diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2bf6b68 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + build-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + # Must stay >= 1.26.5: GO-2026-5856 (Encrypted Client Hello privacy + # leak in crypto/tls) is fixed in the toolchain, not in our code. + go-version: '1.26.5' + check-latest: true + + - name: Build + run: go build ./... + + - name: Vet + run: go vet ./... + + - name: Test + run: go test ./... + + - name: Govulncheck + run: | + go install golang.org/x/vuln/cmd/govulncheck@latest + govulncheck ./... diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c4cf709 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,36 @@ +name: Release + +on: + push: + tags: ['v*'] + +permissions: + contents: write + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + # goreleaser derives the changelog and version from tag history. + fetch-depth: 0 + + - uses: actions/setup-go@v5 + with: + # Keep in step with ci.yml — see the note there about GO-2026-5856. + go-version: '1.26.5' + check-latest: true + + - name: Verify before publishing + run: | + go build ./... + go vet ./... + go test ./... + + - uses: goreleaser/goreleaser-action@v6 + with: + version: '~> v2' + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index f57df4d..17efac9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,13 @@ coverage.* # OS .DS_Store + +# Internal session handoff — kept locally, mirrored to ~/.claude/handoffs/ +# Carries operational detail (hosts, account structure, local paths) that +# does not belong in a public repo. +HANDOFF.md + +# One-off generator/verification reports — internal tooling output +dogfood-results.json +apify-actor-audit-report.json +workflow-verify-report.json diff --git a/.goreleaser.yaml b/.goreleaser.yaml index c63b9e9..e0b7917 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -9,7 +9,7 @@ builds: env: - CGO_ENABLED=0 ldflags: - - -s -w -X canvas-pp-cli/internal/cli.version={{ .Version }} + - -s -w -X github.com/johnnyrobot/canvas-pp-cli/internal/cli.version={{ .Version }} targets: - darwin_amd64 - darwin_arm64 @@ -41,6 +41,10 @@ checksum: name_template: checksums.txt brews: - name: canvas-pp-cli + # Disabled until github.com/johnnyrobot/homebrew-tap exists — goreleaser + # fails the entire release if it cannot push the formula. Create that repo, + # then remove this line to start publishing the formula. + skip_upload: true repository: owner: johnnyrobot name: homebrew-tap diff --git a/CHANGELOG.md b/CHANGELOG.md index e75331a..ddc02f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ # Changelog -This file is maintained by printing-press-library release automation. Do not hand-edit release sections in normal PRs. +Release notes for canvas-pp-cli. Versions follow the git tags on this repository; release artifacts are published by goreleaser. diff --git a/HANDOFF.md b/HANDOFF.md deleted file mode 100644 index 0278b67..0000000 --- a/HANDOFF.md +++ /dev/null @@ -1,255 +0,0 @@ -# canvas-pp-cli — Session Handoff - -> Comprehensive context for the next session. Last updated: **2026-08-07**. -> This is a hand-authored doc (not generated) — it survives `generate --force`. -> **This file is the canonical handoff.** Mirror at `~/.claude/handoffs/canvas-pp-cli-handoff.md`. -> Any copy under `$TMPDIR` / `/var/folders/…/T/` is stale — macOS wipes it on reboot. Edit this file. - -## TL;DR — current status - -`canvas-pp-cli` is a **complete, working Go CLI for the full Canvas LMS REST API** (1,042 endpoints / 122 resource groups) plus **6 hand-written "transcendence" commands** that join data no single Canvas endpoint returns. It was generated by the Printing Press (`/printing-press`) from the Instructure developer docs. - -- ✅ Built, on `$PATH`, credentials configured, **live-verified** against `https://canvas.johnnyrobot.ai`. -- ✅ Quality: shipcheck 7/7 PASS, scorecard **92/100 (Grade A)**, verify 100%. -- ✅ All 6 transcendence commands execute correctly live; `audit-enrollments` already found 2 real config issues. -- ⚠️ **One open validation gap:** the test instance (`canvas.johnnyrobot.ai`, account "Project-CLU") has **zero students** in any course, so the student-grade paths (scores in `roster`, `at-risk`, `to-grade`, `standings`) couldn't be exercised with real data. They're logically sound but unproven on populated data. -- ⏸️ **Not published** to the public Printing Press library (held by user's choice until tested). The local library copy is publish-ready. - -**As of 2026-08-07** (see [Session log](#session-log--2026-08-07) at the end): four PRs merged to `main` @ `f5e126f`; build/vet/test all green; three upstream issues filed. Publication status unchanged — **still not published, and verified so**: `mvanhorn/printing-press-library` has no `library/productivity/canvas` entry, no `canvas-current` release tag, and no match for `canvas-pp-cli` anywhere. Every install path in `README.md` 404s today. - -## Where everything lives - -| What | Path | -|---|---| -| **Working repo (use this)** | `/Users/laccd/code/cli-tools/canvas-pp-cli/` ← **moved 2026-08-06**, no longer at `~/code/canvas-pp-cli` | -| **Private GitHub repo** | `https://github.com/johnnyrobot/canvas-pp-cli` (PRIVATE) | -| **PATH symlink** | `~/.local/bin/canvas-pp-cli` → working repo's built binary | -| **Printing Press library copy** | `~/printing-press/library/canvas/` (publish/polish/reprint operate here) | -| **Manuscripts (research+proofs)** | `~/printing-press/manuscripts/canvas/20260622-151431-06e611a5/` | -| **Internal spec (source of truth)** | `~/printing-press/.runstate/code-0c13d8b6/runs/20260622-151431-06e611a5/research/canvas-spec.yaml` | -| **Docs→spec converter** | `~/printing-press/.runstate/code-0c13d8b6/runs/20260622-151431-06e611a5/pipeline/convert.py` | -| **Token (credentials)** | `~/.local/share/canvas-pp-cli/credentials.toml` (mode 0600) | -| **Config (base_url)** | `~/.config/canvas-pp-cli/config.toml` | -| **Local SQLite store** | `~/.local/share/canvas-pp-cli/data.db` (empty until `sync`) | - -Three copies exist, all on the `-pp-cli` naming convention: working repo, private GitHub repo, and the Printing Press library copy. The working repo + GitHub repo are the user's; the library copy is the Printing Press artifact used for publish/polish/reprint. - -## What it is - -- **API:** Canvas LMS REST (`/api/v1/...`), generated from the user-provided `developerdocs.instructure.com` `llms-full` export. -- **Auth:** Bearer token, **per-instance base URL** (each institution has its own host). Env vars `CANVAS_API_TOKEN` / `CANVAS_ACCESS_TOKEN`; `CANVAS_BASE_URL` overrides the host. -- **MCP:** thin `canvas_search` + `canvas_execute` orchestration pair (stdio+http), so agents reach all 1,042 endpoints without loading 1,042 tools. MCP binary: `canvas-mcp` (built via `go build ./cmd/canvas-pp-mcp`). -- **Agent-native:** every command supports `--json/--agent/--select/--compact/--csv/--dry-run`. Framework commands: `sync`, `search` (offline FTS), `sql`, `stale`, `doctor`, `tail`, `import`, `agent-context`, `which`. - -## How it was built (provenance) - -1. Input was `~/Desktop/canvas-rest-api-llms-full.md` — page 0 of a paginated `llms-full` export (A–E only). The full export was crawled from `developerdocs.instructure.com/llms-full.txt` + `/llms-full.txt/1` (pages 2–5 are other Instructure products, no `/api/v1`). -2. `convert.py` (see path above) parses the markdown into the internal YAML spec. **Two non-obvious converter fixes were required** (both retro candidates for the Printing Press): - - **Fenced-code-block tracking** — `#`-prefixed comments inside ```` ```js ```` examples were being read as resource headers, creating junk resources. - - **Shared param-table siblings** — Canvas documents some operations with multiple `#### METHOD path` lines sharing one param table (e.g. course- vs section-scoped "Enroll a user"). The converter originally gave the table only to the last sibling, leaving ~170 endpoints without typed body flags. Fixed by grouping siblings and sharing the table. This is why `enrollments create` has `--enrollment-user-id` etc. -3. Generated with `cli-printing-press generate --spec canvas-spec.yaml --category productivity --max-endpoints-per-resource 100`. Reserved-name collisions remapped in the spec: `search`→`search_resource`, `analytics`→`analytics_resource`, `history`→`history_resource`. PATCH (4 endpoints) mapped to PUT (generator supports GET/POST/PUT/DELETE only). - -## Code map - -Standard generated Go CLI. Packages under `internal/`: `cli`, `client`, `store`, `config`, `cliutil`, `mcp`, `mcp/cobratree`. - -> **Changed 2026-08-07:** `internal/cache` and `internal/types` were **deleted** in PR #4 (dead code). Don't be surprised by their absence. -> `internal/cli` is **one Go package**, 1,181 files, ~171k lines. Never enumerate it — use `doctor` / `which` / `--help`. - -**The only hand-written code (everything else is generator-emitted)** lives in `internal/cli/`: - -| File | Command | What it does | -|---|---|---| -| `novel_canvas.go` | (shared) | `canvasObj` JSON accessors, bounded paginator `canvasFetchList`, `anonLabel`, `teacherCourses`, `emitNovel`, `verifyEmpty` | -| `roster.go` | `roster ` | enrollments + user + sections + grades → one row/student | -| `at_risk.go` | `at-risk [--course\|--all-my-courses] --since` | missing/late aggregation across courses, ranked | -| `to_grade.go` | `to-grade [--course\|--all-my-courses] --sort` | ungraded-submission queue, oldest-first | -| `since.go` | `since [--course]` | new submissions/announcements/enrollments digest | -| `standings.go` | `standings --term [--account] [--by]` | grade distribution + pass/DFW rollup | -| `audit_enrollments.go` | `audit-enrollments --account [--orphans] [--ghost-teachers]` | account anomaly sweep | -| `*_test.go` (6) + `novel_canvas_test.go` | — | real table-driven unit tests for the logic | - -Hand-written-command conventions (already followed; preserve them): verify-friendly RunE (`dryRunOK`, help-only branch, `usageErr` on missing input), `verifyEmpty` short-circuit so they never dial out under `PRINTING_PRESS_VERIFY=1`, `--anonymize` (FERPA-safe), bounded `--max-scan-pages`/`--max-courses`, `IsDogfoodEnv` curtailment, `// pp:data-source live` + `validateDataSourceStrategy(flags,"live")`, and `pp:read-only`/`pp:happy-args`/`pp:no-error-path-probe` annotations. - -## Credentials & access - -- **Canvas token:** stored via `canvas-pp-cli auth set-token` → `~/.local/share/canvas-pp-cli/credentials.toml`. **Do not put the token value in any file in the repo or in this doc.** -- **Base URL:** `https://canvas.johnnyrobot.ai` set in `~/.config/canvas-pp-cli/config.toml` (`base_url = '...'`). No env vars needed at runtime; credentials persist in config. -- **The token is user-scoped** — the CLI can only do what the Canvas account can. The account (`johnnyrobot`) is an **admin** of accounts 1 (Project-CLU / root) and 2 (Site Admin). Teacher/admin scope is required for `at-risk`, `to-grade` (all-students submissions) and the account commands. -- **GitHub:** `gh` is authed as `johnnyrobot` (HTTPS, `repo`+`workflow` scopes). A second account `johnnyphung-laccd` is in the keyring with a **broken/expired token** (harmless; `gh auth refresh` or remove to clear the error). `git config user.name=johnnyrobot`, `user.email=174211481+johnnyrobot@users.noreply.github.com` (no real PII). -- **⚠️ Security:** the Canvas token was pasted into the chat that set this up — if that transcript is retained/shared, **rotate the token** (Canvas → Account → Settings → regenerate) and re-run `canvas-pp-cli auth set-token `. - -## Validation status - -| Layer | Status | -|---|---| -| Build / vet / unit tests | ✅ PASS | -| Shipcheck (7 legs) | ✅ PASS, scorecard 92/100 | -| Live auth + reachability | ✅ token works, `courses index` returns 10 courses | -| `roster` join (live) | ✅ section resolved, fields populated, teacher correctly scoreless | -| `audit-enrollments` (live) | ✅ found 2 ghost-teacher courses (ids **34**, **36**, unpublished) | -| `at-risk`/`to-grade`/`since`/`standings` (live) | ✅ execute correctly, valid JSON, honest empty-state notes | -| **Student-grade math** | ⚠️ **UNPROVEN** — instance has no students, so scores/missing-work/distribution paths had no data | - -**To close the gap:** run against a course with real student enrollments + submissions — either add test students to a Project-CLU course, or point at a populated instance (e.g. `CANVAS_BASE_URL=https://canvas.project-remedy.com CANVAS_API_TOKEN= canvas-pp-cli roster --anonymize --agent`). Watch for field-mapping issues in the join logic; if a command returns empty/wrong-shaped data on a populated course, that's a real bug to fix in the corresponding `internal/cli/*.go`. - -## Known issues & caveats - -1. **`generate --force` can clobber the 6 novel command files.** The generator re-emits scaffolds from `research.json`'s `novel_features`, overwriting same-named hand-written files. During this build it preserved them on one regen and clobbered them on another. **Before any reprint/regen, back up `internal/cli/{roster,at_risk,to_grade,since,standings,audit_enrollments,novel_canvas}{,_test}.go` and restore after.** (A backup from this session is at `~/printing-press/.runstate/code-0c13d8b6/runs/20260622-151431-06e611a5/novel-backup-postpolish/`.) -2. **`printer_name` generator gap.** The generator's `resolvePrinterNameForNew` would not populate `printer_name`/`creator.name` even with `git config user.name` set. They were hand-set to `johnnyrobot` in the **library copy's** `.printing-press.json` (`creator.name` + `printer_name`) to pass `publish validate`. A reprint would null them again → re-set by hand. -3. **`.gitignore` + rename trap.** When renaming the binary, the old binary name stops being ignored and `git add -A` will commit it (26 MB). Already cleaned; just be aware. -4. **Publish live-test gate.** `/printing-press-publish canvas` reruns **live** dogfood; with the token configured it should pass, but if you want to skip it use `/printing-press-publish canvas --skip-live-test=auth-unavailable`. -5. **Two retro candidates** worth filing via `/printing-press-retro`: the converter shared-param-table bug and the `printer_name` resolution gap (both described above). - -## Common tasks - -```bash -cd /Users/laccd/code/canvas-pp-cli - -# Rebuild (PATH symlink auto-reflects this) -go build -o canvas-pp-cli ./cmd/canvas-pp-cli -go build -o canvas-pp-mcp ./cmd/canvas-pp-mcp # MCP server - -# Run (credentials persisted in config; no env vars needed) -canvas-pp-cli doctor -canvas-pp-cli courses index --agent -canvas-pp-cli roster --anonymize --agent -canvas-pp-cli audit-enrollments --account 1 --ghost-teachers --agent - -# Test -go test ./internal/cli/ - -# Iterate: edit internal/cli/*.go → rebuild → git commit → git push -``` - -## The Printing Press relationship - -This CLI was made by `/printing-press` and the **library copy** (`~/printing-press/library/canvas/`) is still wired to that ecosystem: - -- `/printing-press-polish canvas` — diagnostic-fix loop to push past 92/100 (operates on the library copy). -- `/printing-press-publish canvas` — opens a PR to the **public** `mvanhorn/printing-press-library` (currently held; library copy is validated + publish-ready). -- `/printing-press-reprint canvas` — regenerate from scratch under a newer Printing Press, carrying prior research + novel features (⚠️ see caveat #1 about novel-file preservation). -- `/printing-press-retro` — file the 2 retro candidates above. - -The user's **working repo** (`/Users/laccd/code/canvas-pp-cli`) has diverged from the library copy only by the addition of this `HANDOFF.md` and the `.gitignore`; the code is identical. If the user hand-edits the working repo and later wants those changes published, the changes must be ported to the library copy (or the working repo promoted) before `/printing-press-publish`. - -## Immediate next steps (suggested) - -1. Validate the student-grade paths on a populated course (the one real open item — see [Release readiness](#release-readiness--assessed-2026-08-07)). -2. Decide whether to publish to the public library (or keep private). -3. Rotate the Canvas token if the setup transcript is retained/shared. -4. Optionally `/printing-press-retro` to file the remaining generator gaps. - ---- - -# Session log — 2026-08-07 - -State at end of session: `main` @ `f5e126f`, clean tree, four PRs merged, full suite green. - -## Merged PRs — read the PRs, don't re-derive - -| PR | What | -|---|---| -| [#1](https://github.com/johnnyrobot/canvas-pp-cli/pull/1) | fetch → analyze → render seam across all six novel commands; two ordering bugs fixed | -| [#2](https://github.com/johnnyrobot/canvas-pp-cli/pull/2) | `version: "2"` in `.golangci.yml` — `make lint` was erroring before it linted anything | -| [#3](https://github.com/johnnyrobot/canvas-pp-cli/pull/3) | `docs/agents/*` — issue tracker, triage labels, domain-doc layout | -| [#4](https://github.com/johnnyrobot/canvas-pp-cli/pull/4) | six architecture-review candidates: `which`, MCP bounding, ID dedup, credential tests, mirror warnings, dead-code removal | - -Design decisions behind #1 are **not** in a doc — they came from a 20-question grilling session. The commit messages carry the reasoning; `.printing-press-patches/canvas-novel-command-analyze-seam.json` carries the intent. - -## Filed upstream (mvanhorn/cli-printing-press) - -- **[#4016](https://github.com/mvanhorn/cli-printing-press/issues/4016)** — three `which.go.tmpl` scoring defects, verified against v4.30.1. -- **[#3370](https://github.com/mvanhorn/cli-printing-press/issues/3370)** — commented with the hidden-area-group traversal detail; a naive tree walk finds 52 commands instead of ~1,000. -- **[#4025](https://github.com/mvanhorn/cli-printing-press/issues/4025)** — `AuthHeader()` duplicate unreachable `AccessToken` guard. `config.go.tmpl:728-750` (per_call env-var range) collides with `:775-786` (trailing minted-token block) because `resolveEnvVarField("CANVAS_ACCESS_TOKEN")` aliases onto the reserved `AccessToken` field. -- **[#3778](https://github.com/mvanhorn/cli-printing-press/issues/3778)** — commented with our reprint reproduction. **It is the inverse of the filed mechanism:** theirs is preserved old *callers* + overwritten *definer*; ours is preserved old *definer* + fresh new *callers*. -- **[#4033](https://github.com/mvanhorn/cli-printing-press/issues/4033)** — `doctor` collects a failure reason and discards it at render time. Two sections: cache (`error` set at `doctor.go.tmpl:1265`/`:1273`, never rendered by `renderCacheReport:1348`) and paths (`detail` set at `:991`, never rendered by `renderPathsReport:1049` — which also skips `status`, so a paths failure prints the bare header ` Paths:` and nothing else). - -## The reprint decision — RESOLVED: deferred - -A reprint at 4.30.1 was attempted in a sandbox and **does not build**: - -``` -Force regen merged 39 preserved files / 1 AddCommand calls -Error: go build ./... failed - undefined: resolveReadWithStrategyAndResponsePath (523 call sites, 523 files) -``` - -4.30.1 **introduces** that helper in `data_source.go:145`; it does not exist in our 4.25.0 tree. regen-merge preserved our `data_source.go` (PR #4's mirror fix made it drift) while regenerating the 523 callers fresh. Live reproduction of upstream #3778. - -Scale: **1,197 files differ**, 49 new in 4.30.1, 32 only in ours. Whole-tree replacement, not a merge. A clean 4.30.1 baseline **does** build — regenerate a sandbox with: - -```bash -cli-printing-press generate --spec spec.yaml --output /tmp/fresh-430 -``` - -### What 4.30.1 already fixes vs. what we still carry - -| Fix | 4.30.1 | On reconcile | -|---|---|---| -| MCP response bounding | ✅ `bound.EndpointResponse` | drop ours, take upstream | -| `which` WhyItMatters unscored | ❌ | re-apply | -| `which` group substring match | ❌ | re-apply | -| `which` command-tree fallback | ❌ | re-apply | -| ID extraction duplicated store↔cli | ❌ | re-apply | -| Mirror errors swallowed | ❌ | re-apply | -| `AuthHeader` unreachable branch | ❌ (filed #4025) | re-apply unless fixed upstream | -| `internal/config` tests | additive | keep | - -If a reprint is revisited, re-verify this table against the then-current version rather than trusting it. - -## Release readiness — assessed 2026-08-07 - -Verdict: **not ready**, but the gap is distribution, not code quality. - -Green: `go build` exit 0 · `go vet` clean · `go test ./...` all 7 packages pass · all six novel commands have tests · `CGO_ENABLED=0` cross-build to `linux/amd64` succeeds (pure-Go `modernc.org/sqlite`, so the goreleaser config is sound) · Apache-2.0 LICENSE + NOTICE present · no secrets or student PII in tracked files · binary smoke-tests clean. - -Blockers: - -1. **Never published.** Every `README.md` install path 404s. The library is public and active; this CLI just hasn't gone through `printing-press-publish`. -2. **`govulncheck`: GO-2026-5856** — Encrypted Client Hello privacy leak in `crypto/tls`, 4 live call traces including the MCP server's TLS `Start`. Fixed in **go1.26.5**; local toolchain is 1.26.4 and 1.26.5 is released. Build release binaries on ≥1.26.5. -3. **No CI.** No `.github/` at all — nothing runs the suite on push. -4. **`make lint` exits 1** — 739 real findings (126 shown; caps hide ~83%). Reviewed: **no correctness bugs**. 257 are `SA9003: empty branch` from a vestigial `if !stdinBody {}` in generated write commands (real body-building `if/else` is further down); rest is style, `noctx` in test/generated code, and dead pagination helpers. Both `internal/store` findings are benign (`sql.ErrNoRows` returns unwrapped; `hint` is overwritten in both branches). -5. **Student-grade math still UNPROVEN** — carried over from 2026-06-23 and unchanged. This is the core value proposition and remains unvalidated against real student data. - -## `doctor` swallows its own diagnosis — filed as #4033 - -`doctor` prints `FAIL Cache: error` with no reason. `collectCacheReport` sets `report["error"]`; `renderCacheReport` renders `db_path`, `schema_version`, `db_bytes`, `stale_after`, `oldest_age`, `resources`, `hint` — and **never `error`**. `--agent` JSON *does* carry it, so only humans get the undiagnosable failure, in the command whose whole job is human diagnosis. - -The paths section has the same shape and is worse: `collectPathsReport` sets `status`+`detail` on failure, and `renderPathsReport` reads neither, so a path-resolution failure prints the bare header ` Paths:` with no failure indicator at all. Both confirmed still present in the 4.30.1 template; `doctor.go` is `DO NOT EDIT`, so this affects every printed CLI with a local store. - -Locally the swallowed message is `database schema version 9 is newer than supported version 4; upgrade the CLI binary` — the on-disk DB was written by a newer build on this machine. That part is an environment artifact, not a product defect. - -## Gotchas that cost real time - -**`.printing-press-patches/` is write-only.** The generated `AGENTS.md` claims recording a patch means "a regen carries the intent forward". It does not — `regenmerge/*.go` has zero references to patches (upstream #3955). What actually preserves work is regen-merge's per-file verdicts: `NOVEL` files survive cleanly; hand-edits to generated files become `TEMPLATED-BODY-DRIFT`, which preserves the **whole old file** — that is what broke the reprint. A three-line local fix silently pinned an entire generated file at 4.25.0. - -**golangci-lint default caps hide ~83% of findings.** `max-issues-per-linter: 50` / `max-same-issues: 3`. Repo reports 126; the real number is 739. Truncation also makes findings *appear to move between files* as unrelated code shifts, which reads as a regression. When comparing branches, run with both caps set to 0. - -**zsh does not word-split unquoted parameter expansions.** `for c in "roster 12345"; do cmd $c; done` passes one argument, not two. Bit us twice; both times it looked like a product failure. - -**Piping masks exit codes.** `golangci-lint run | tail` reported exit 0 while the linter had errored on config version and never ran. Capture to a file and check `$?`. - -**Six other Claude sessions run on this machine.** One moved the repo mid-session. If paths break, check `~/code/cli-tools/` and siblings before assuming deletion. - -## Working conventions — please keep - -**Mutation-test every rule.** After writing a test, break the rule it covers and confirm it goes red, then revert. This caught four tests that passed and proved nothing — two where the fixture let a different code path answer first, one where a "whole-query" bonus was a substring test in disguise. Green tests are why both shipped bugs went unnoticed; don't trust a green test you haven't broken. - -**Verify inherited numbers.** Three figures inherited from the prior handoff were wrong: "1,042 call sites" was 523 (the 1,042 is the *endpoint* count from this doc's TL;DR — same digits, unrelated quantity); "48 new files" was 49; and the `AuthHeader` defect was described from the template but only reproduces in generated output. Re-run the decisive command before quoting a number in a PR or public issue. - -**Verify subagent claims.** Explorer agents overstated twice — a "byte-identical" block that differed on 21 of 134 lines, and call-site counts from a buggy grep. - -**Check upstream before filing.** Two of three "live bugs" found in an earlier session were already fixed in the current generator. Templates are in the module cache at `~/go/pkg/mod/github.com/mvanhorn/cli-printing-press/v4@v4.30.1/internal/generator/templates/`. - -**Prove equivalence before deleting a duplicate.** The ID-dedup in #4 ran both implementations over 250 combinations first; the corpus survives as `internal/store/extract_resource_id_test.go`. - -**ADHD output mode is ON** for this user (`/i-have-adhd`) — lead with the next action, number multi-step work, restate state each turn, concrete time estimates, no preamble or closers. Persists until they say "stop adhd mode". - -## Suggested skills - -- **`superpowers:verification-before-completion`** — evidence before assertions; never claim green without showing output. -- **`mattpocock-skills:diagnosing-bugs`** — for any remaining review candidate or reprint failure. -- **`mattpocock-skills:grilling`** — before committing to a reprint; a 1,197-file change deserves the treatment PR #1 got. -- **`printing-press-publish`** — the actual path to public release. -- Avoid `printing-press-amend` — disabled for model invocation in this user's `skillOverrides`; the user must run it. diff --git a/README.md b/README.md index 4f0bfca..e105aeb 100644 --- a/README.md +++ b/README.md @@ -8,99 +8,58 @@ Created by [@johnnyrobot](https://github.com/johnnyrobot). ## Install -The recommended path installs both the `canvas-pp-cli` binary and the `pp-canvas` agent skill (Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, and other agents supported by the upstream [`skills`](https://github.com/vercel-labs/skills) CLI) in one shot: +### Go install -```bash -npx -y @mvanhorn/printing-press-library install canvas -``` - -For CLI only (no skill): - -```bash -npx -y @mvanhorn/printing-press-library install canvas --cli-only -``` - -For skill only — installs the skill into the same agents as the default command above, but skips the CLI binary (use this to update or reinstall just the skill): - -```bash -npx -y @mvanhorn/printing-press-library install canvas --skill-only -``` - -To constrain the skill install to one or more specific agents (repeatable — agent names match the [`skills`](https://github.com/vercel-labs/skills) CLI): +Requires Go 1.26.5 or newer: ```bash -npx -y @mvanhorn/printing-press-library install canvas --agent claude-code -npx -y @mvanhorn/printing-press-library install canvas --agent claude-code --agent codex +go install github.com/johnnyrobot/canvas-pp-cli/cmd/canvas-pp-cli@latest ``` -### Without Node (Go fallback) - -If `npx` isn't available (no Node, offline), install the CLI directly via Go (requires Go 1.26.5 or newer): +To also install the MCP server binary: ```bash -go install github.com/mvanhorn/printing-press-library/library/productivity/canvas/cmd/canvas-pp-cli@latest +go install github.com/johnnyrobot/canvas-pp-cli/cmd/canvas-pp-mcp@latest ``` -This installs the CLI only — no skill. - ### Pre-built binary -Download a pre-built binary for your platform from the [latest release](https://github.com/mvanhorn/printing-press-library/releases/tag/canvas-current). On macOS, clear the Gatekeeper quarantine: `xattr -d com.apple.quarantine `. On Unix, mark it executable: `chmod +x `. - - -## Install for Hermes +Download a binary for your platform from the [latest release](https://github.com/johnnyrobot/canvas-pp-cli/releases/latest). Builds are published for macOS, Linux and Windows on both amd64 and arm64. -Install the CLI binary first. The installer writes binaries to a per-user managed bin directory by default: `$HOME/.local/bin` on macOS/Linux and `%LOCALAPPDATA%\Programs\PrintingPress\bin` on Windows. +On macOS, clear the Gatekeeper quarantine after downloading: ```bash -npx -y @mvanhorn/printing-press-library install canvas --cli-only +xattr -d com.apple.quarantine canvas-pp-cli ``` -Then install the focused Hermes skill. - -From the Hermes CLI: +On Unix, mark it executable: ```bash -hermes skills install mvanhorn/printing-press-library/cli-skills/pp-canvas --force +chmod +x canvas-pp-cli ``` -Inside a Hermes chat session: +### From source ```bash -/skills install mvanhorn/printing-press-library/cli-skills/pp-canvas --force +git clone https://github.com/johnnyrobot/canvas-pp-cli.git +cd canvas-pp-cli +make build # or: go build ./cmd/canvas-pp-cli +make build-all # CLI + MCP server ``` -Restart the Hermes session or gateway if the newly installed skill is not visible immediately. +### Agent skill -## Install for OpenClaw -Install both the CLI binary and the focused OpenClaw skill. The installer defaults binaries to a per-user bin directory (`$HOME/.local/bin` on macOS/Linux, `%LOCALAPPDATA%\Programs\PrintingPress\bin` on Windows): - -```bash -npx -y @mvanhorn/printing-press-library install canvas --agent openclaw -``` - -Restart the OpenClaw session or gateway if the newly installed skill is not visible immediately. +`SKILL.md` in this repo is a ready-to-use agent skill describing the CLI's commands and recipes. Point your agent at it directly, or copy it into your agent's skills directory. ## Use with Claude Desktop -This CLI ships an [MCPB](https://github.com/modelcontextprotocol/mcpb) bundle — Claude Desktop's standard format for one-click MCP extension installs (no JSON config required). - -To install: - -1. Download the `.mcpb` for your platform from the [latest release](https://github.com/mvanhorn/printing-press-library/releases/tag/canvas-current). -2. Double-click the `.mcpb` file. Claude Desktop opens and walks you through the install. -3. Fill in `CANVAS_API_TOKEN` when Claude Desktop prompts you. - -Requires Claude Desktop 1.0.0 or later. Pre-built bundles ship for macOS Apple Silicon (`darwin-arm64`) and Windows (`amd64`, `arm64`); for other platforms, use the manual config below. - -
-Manual JSON config (advanced) +The MCP server (`canvas-pp-mcp`) exposes the whole Canvas surface to Claude Desktop through a `canvas_search` + `canvas_execute` pair, so an agent reaches every endpoint without loading a tool per endpoint. -If you can't use the MCPB bundle (older Claude Desktop, unsupported platform), install the MCP binary and configure it manually. +Install the MCP binary, then add it to your Claude Desktop config. ```bash -go install github.com/mvanhorn/printing-press-library/library/productivity/canvas/cmd/canvas-pp-mcp@latest +go install github.com/johnnyrobot/canvas-pp-cli/cmd/canvas-pp-mcp@latest ``` Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`): @@ -118,7 +77,6 @@ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_ } ``` -
## Authentication diff --git a/apify-actor-audit-report.json b/apify-actor-audit-report.json deleted file mode 100644 index 3da9312..0000000 --- a/apify-actor-audit-report.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "dir": "\u003ccli-dir\u003e/canvas-pp-cli", - "research_dir": "\u003ccli-dir\u003e/20260622-151431-06e611a5", - "verdict": "pass", - "actors": null, - "issues": [ - "no Apify actor references found, skipping" - ] -} \ No newline at end of file diff --git a/cmd/canvas-pp-cli/main.go b/cmd/canvas-pp-cli/main.go index 288d03e..94eb721 100644 --- a/cmd/canvas-pp-cli/main.go +++ b/cmd/canvas-pp-cli/main.go @@ -6,7 +6,7 @@ package main import ( "os" - "canvas-pp-cli/internal/cli" + "github.com/johnnyrobot/canvas-pp-cli/internal/cli" ) func main() { diff --git a/cmd/canvas-pp-mcp/main.go b/cmd/canvas-pp-mcp/main.go index e98ca22..ae3a42b 100644 --- a/cmd/canvas-pp-mcp/main.go +++ b/cmd/canvas-pp-mcp/main.go @@ -9,7 +9,7 @@ import ( "os" "strings" - mcptools "canvas-pp-cli/internal/mcp" + mcptools "github.com/johnnyrobot/canvas-pp-cli/internal/mcp" "github.com/mark3labs/mcp-go/server" ) diff --git a/dogfood-results.json b/dogfood-results.json deleted file mode 100644 index 16f74f8..0000000 --- a/dogfood-results.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "dir": "\u003ccli-dir\u003e/canvas-pp-cli", - "spec_path": "\u003ccli-dir\u003e/spec.yaml", - "spec_source": "bundled", - "verdict": "PASS", - "path_check": { - "tested": 0, - "valid": 0, - "valid_pct": 0, - "skipped": true, - "detail": "internal-yaml spec: paths validated at parse time" - }, - "auth_check": { - "spec_scheme": "bearer token format (expects \"Bearer \" prefix)", - "generated_format": "Bearer ", - "match": true, - "detail": "spec and generated client both use \"Bearer\"" - }, - "browser_session_check": { - "required": false, - "pass": true, - "detail": "browser-session auth not required" - }, - "oauth_scope_coverage_check": { - "checked": 0, - "covered": 0, - "skipped": true, - "detail": "no OAuth-scoped endpoints in spec" - }, - "dead_flags": { - "total": 22, - "dead": 0 - }, - "dead_functions": { - "total": 72, - "dead": 0 - }, - "pipeline_check": { - "sync_calls_domain": true, - "search_calls_domain": false, - "domain_tables": 1, - "sync_file_emitted": true, - "sync_resources_present": true, - "detail": "sync uses domain-specific Upsert methods; search uses generic Search only; 1 domain tables found" - }, - "example_check": { - "tested": 10, - "with_examples": 10, - "valid_examples": 10, - "detail": "10/10 commands have examples" - }, - "wiring_check": { - "command_tree": { - "defined": 1176, - "registered": 1176 - }, - "config_consistency": { - "consistent": true - }, - "workflow_completeness": { - "skipped": true, - "total_steps": 0, - "mapped_steps": 0, - "detail": "no workflow_verify.yaml found" - } - }, - "novel_features_check": { - "planned": 6, - "found": 6 - }, - "mcp_surface_parity": { - "state": "runtime_walking", - "pass": true, - "detail": "MCP surface mirrors the Cobra tree at runtime" - }, - "reimplementation_check": { - "checked": 6, - "exempted_via_store": 0 - }, - "source_client_check": { - "checked": 0, - "skipped": true - }, - "print_json_filtered_check": { - "checked": 1170 - }, - "test_presence": { - "checked": 0 - }, - "naming_check": { - "checked": 1170 - }, - "sync_param_drop_check": { - "checked": 0, - "skipped": true - }, - "issues": null -} \ No newline at end of file diff --git a/go.mod b/go.mod index 1d90aaa..25ee269 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module canvas-pp-cli +module github.com/johnnyrobot/canvas-pp-cli go 1.26 diff --git a/internal/cli/agent_context.go b/internal/cli/agent_context.go index 6b7f1db..a583cde 100644 --- a/internal/cli/agent_context.go +++ b/internal/cli/agent_context.go @@ -8,7 +8,7 @@ import ( "os" "sort" - "canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" "github.com/spf13/cobra" "github.com/spf13/pflag" ) diff --git a/internal/cli/analytics.go b/internal/cli/analytics.go index 7dabd9b..3caf5e1 100644 --- a/internal/cli/analytics.go +++ b/internal/cli/analytics.go @@ -10,7 +10,7 @@ import ( "sort" "strings" - "canvas-pp-cli/internal/store" + "github.com/johnnyrobot/canvas-pp-cli/internal/store" "github.com/spf13/cobra" ) diff --git a/internal/cli/at_risk.go b/internal/cli/at_risk.go index 4df56ad..750f191 100644 --- a/internal/cli/at_risk.go +++ b/internal/cli/at_risk.go @@ -13,8 +13,8 @@ import ( "github.com/spf13/cobra" - "canvas-pp-cli/internal/client" - "canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/client" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" ) type atRiskItem struct { diff --git a/internal/cli/auth.go b/internal/cli/auth.go index 333b2f2..6022a65 100644 --- a/internal/cli/auth.go +++ b/internal/cli/auth.go @@ -7,8 +7,8 @@ import ( "fmt" "os" - "canvas-pp-cli/internal/cliutil" - "canvas-pp-cli/internal/config" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/config" "github.com/spf13/cobra" ) diff --git a/internal/cli/channel_workflow.go b/internal/cli/channel_workflow.go index 438e928..7d5ab0a 100644 --- a/internal/cli/channel_workflow.go +++ b/internal/cli/channel_workflow.go @@ -8,7 +8,7 @@ import ( "fmt" "time" - "canvas-pp-cli/internal/store" + "github.com/johnnyrobot/canvas-pp-cli/internal/store" "github.com/spf13/cobra" ) diff --git a/internal/cli/data_source.go b/internal/cli/data_source.go index 8803383..5c80c49 100644 --- a/internal/cli/data_source.go +++ b/internal/cli/data_source.go @@ -18,8 +18,8 @@ import ( "sync" "time" - "canvas-pp-cli/internal/client" - "canvas-pp-cli/internal/store" + "github.com/johnnyrobot/canvas-pp-cli/internal/client" + "github.com/johnnyrobot/canvas-pp-cli/internal/store" ) const networkFallbackReason = "api_unreachable" diff --git a/internal/cli/doctor.go b/internal/cli/doctor.go index 7d26468..e5d1573 100644 --- a/internal/cli/doctor.go +++ b/internal/cli/doctor.go @@ -13,10 +13,10 @@ import ( "strings" "time" - "canvas-pp-cli/internal/client" - "canvas-pp-cli/internal/cliutil" - "canvas-pp-cli/internal/config" - "canvas-pp-cli/internal/store" + "github.com/johnnyrobot/canvas-pp-cli/internal/client" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/config" + "github.com/johnnyrobot/canvas-pp-cli/internal/store" "github.com/spf13/cobra" ) diff --git a/internal/cli/feedback.go b/internal/cli/feedback.go index a520306..8997453 100644 --- a/internal/cli/feedback.go +++ b/internal/cli/feedback.go @@ -14,7 +14,7 @@ import ( "strings" "time" - "canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" "github.com/spf13/cobra" ) diff --git a/internal/cli/helpers.go b/internal/cli/helpers.go index 65c4b37..365261d 100644 --- a/internal/cli/helpers.go +++ b/internal/cli/helpers.go @@ -5,8 +5,8 @@ package cli import ( "bytes" - "canvas-pp-cli/internal/client" - "canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/client" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" "context" "encoding/json" "errors" diff --git a/internal/cli/novel_canvas.go b/internal/cli/novel_canvas.go index f568dda..022eb02 100644 --- a/internal/cli/novel_canvas.go +++ b/internal/cli/novel_canvas.go @@ -25,8 +25,8 @@ import ( "github.com/spf13/cobra" - "canvas-pp-cli/internal/client" - "canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/client" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" ) // canvasObj is a decoded Canvas JSON object kept as raw values for lazy, diff --git a/internal/cli/profile.go b/internal/cli/profile.go index 6729188..901b97b 100644 --- a/internal/cli/profile.go +++ b/internal/cli/profile.go @@ -11,7 +11,7 @@ import ( "sort" "strings" - "canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" "github.com/spf13/cobra" "github.com/spf13/pflag" ) diff --git a/internal/cli/root.go b/internal/cli/root.go index 97dc86f..4ffa542 100644 --- a/internal/cli/root.go +++ b/internal/cli/root.go @@ -12,9 +12,9 @@ import ( "text/tabwriter" "time" - "canvas-pp-cli/internal/client" - "canvas-pp-cli/internal/cliutil" - "canvas-pp-cli/internal/config" + "github.com/johnnyrobot/canvas-pp-cli/internal/client" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/config" "github.com/spf13/cobra" ) diff --git a/internal/cli/search.go b/internal/cli/search.go index c7b9187..ea468d3 100644 --- a/internal/cli/search.go +++ b/internal/cli/search.go @@ -8,7 +8,7 @@ import ( "fmt" "strings" - "canvas-pp-cli/internal/store" + "github.com/johnnyrobot/canvas-pp-cli/internal/store" "github.com/spf13/cobra" ) diff --git a/internal/cli/since.go b/internal/cli/since.go index 67195c3..218073a 100644 --- a/internal/cli/since.go +++ b/internal/cli/since.go @@ -12,7 +12,7 @@ import ( "github.com/spf13/cobra" - "canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" ) type sinceChange struct { diff --git a/internal/cli/sync.go b/internal/cli/sync.go index 67e9d0e..c48bac0 100644 --- a/internal/cli/sync.go +++ b/internal/cli/sync.go @@ -4,9 +4,9 @@ package cli import ( - "canvas-pp-cli/internal/client" - "canvas-pp-cli/internal/cliutil" - "canvas-pp-cli/internal/store" + "github.com/johnnyrobot/canvas-pp-cli/internal/client" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/store" "context" "encoding/json" "errors" diff --git a/internal/cli/sync_hint.go b/internal/cli/sync_hint.go index aa70b6b..bed18dd 100644 --- a/internal/cli/sync_hint.go +++ b/internal/cli/sync_hint.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "canvas-pp-cli/internal/store" + "github.com/johnnyrobot/canvas-pp-cli/internal/store" "github.com/spf13/cobra" ) diff --git a/internal/cli/sync_hint_test.go b/internal/cli/sync_hint_test.go index 7cac0bf..047255a 100644 --- a/internal/cli/sync_hint_test.go +++ b/internal/cli/sync_hint_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - "canvas-pp-cli/internal/store" + "github.com/johnnyrobot/canvas-pp-cli/internal/store" "github.com/spf13/cobra" ) diff --git a/internal/cli/sync_numeric_id_test.go b/internal/cli/sync_numeric_id_test.go index 78f2989..7db886b 100644 --- a/internal/cli/sync_numeric_id_test.go +++ b/internal/cli/sync_numeric_id_test.go @@ -8,7 +8,7 @@ import ( "path/filepath" "testing" - "canvas-pp-cli/internal/store" + "github.com/johnnyrobot/canvas-pp-cli/internal/store" ) func TestSyncSingleObject_PreservesLargeIntegerResourceIDs(t *testing.T) { diff --git a/internal/cli/tail.go b/internal/cli/tail.go index 68e3ba5..4d6148c 100644 --- a/internal/cli/tail.go +++ b/internal/cli/tail.go @@ -12,7 +12,7 @@ import ( "syscall" "time" - "canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" "github.com/spf13/cobra" ) diff --git a/internal/client/client.go b/internal/client/client.go index 5a0570f..82a3672 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -5,8 +5,8 @@ package client import ( "bytes" - "canvas-pp-cli/internal/cliutil" - "canvas-pp-cli/internal/config" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/config" "context" "crypto/sha256" "encoding/base64" diff --git a/internal/client/client_verify_short_circuit_test.go b/internal/client/client_verify_short_circuit_test.go index 580398f..8759b92 100644 --- a/internal/client/client_verify_short_circuit_test.go +++ b/internal/client/client_verify_short_circuit_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "canvas-pp-cli/internal/config" + "github.com/johnnyrobot/canvas-pp-cli/internal/config" ) // recordingRoundTripper counts how many times its RoundTrip method is diff --git a/internal/cliutil/credentials_test.go b/internal/cliutil/credentials_test.go index 1988ebb..052f0c6 100644 --- a/internal/cliutil/credentials_test.go +++ b/internal/cliutil/credentials_test.go @@ -13,8 +13,8 @@ import ( "testing" "time" - "canvas-pp-cli/internal/cliutil" - "canvas-pp-cli/internal/config" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/config" ) func resetCredentialEnv(t *testing.T) (home, configPath string) { diff --git a/internal/config/config.go b/internal/config/config.go index 513704d..bb9869c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" "github.com/pelletier/go-toml/v2" ) diff --git a/internal/mcp/tools.go b/internal/mcp/tools.go index 8615d07..0f21412 100644 --- a/internal/mcp/tools.go +++ b/internal/mcp/tools.go @@ -13,12 +13,12 @@ import ( "strings" "time" - "canvas-pp-cli/internal/cli" - "canvas-pp-cli/internal/client" - "canvas-pp-cli/internal/cliutil" - "canvas-pp-cli/internal/config" - "canvas-pp-cli/internal/mcp/cobratree" - "canvas-pp-cli/internal/store" + "github.com/johnnyrobot/canvas-pp-cli/internal/cli" + "github.com/johnnyrobot/canvas-pp-cli/internal/client" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/config" + "github.com/johnnyrobot/canvas-pp-cli/internal/mcp/cobratree" + "github.com/johnnyrobot/canvas-pp-cli/internal/store" mcplib "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" ) diff --git a/internal/mcp/tools_test.go b/internal/mcp/tools_test.go index 29097e5..744a7c3 100644 --- a/internal/mcp/tools_test.go +++ b/internal/mcp/tools_test.go @@ -9,7 +9,7 @@ import ( "strings" "testing" - "canvas-pp-cli/internal/cliutil" + "github.com/johnnyrobot/canvas-pp-cli/internal/cliutil" mcplib "github.com/mark3labs/mcp-go/mcp" ) diff --git a/workflow-verify-report.json b/workflow-verify-report.json deleted file mode 100644 index 34ca0e5..0000000 --- a/workflow-verify-report.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "dir": "\u003ccli-dir\u003e/canvas-pp-cli", - "workflows": null, - "verdict": "workflow-pass", - "issues": [ - "no workflow manifest found, skipping" - ] -} \ No newline at end of file