canon-ai 3.1.0 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canon-ai",
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "type": "module",
5
5
  "description": "A spec-first, multi-agent coding pipeline you drop into any repo. The law your agents work under.",
6
6
  "engines": {
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: canon-inline-review
3
3
  description: Use when the human wants an independent cross-review of below-pipeline work - uncommitted changes, one commit, or a whole branch before a PR. Triggers on "/canon-inline-review", "review my uncommitted changes", "codex review this", "cross-review before I commit", "review the last commit", and "review my branch". Not for spec compliance (use canon run / --reroute) or the pipeline's own code_review phase.
4
- allowed-tools: Bash(git status *) Bash(git log *) Bash(git rev-parse *) Bash(git symbolic-ref *) Bash(codex review *) Bash(codex exec review *)
4
+ allowed-tools: Read Bash(git status *) Bash(git log *) Bash(git rev-parse *) Bash(git symbolic-ref *) Bash(mktemp) Bash(mktemp *) Bash(codex review *) Bash(codex exec review *)
5
5
  effort: medium
6
6
  ---
7
7
 
@@ -49,20 +49,20 @@ The practical consequence: **the only target you can steer is the uncommitted tr
49
49
 
50
50
  `codex review` is the shorthand for `codex exec review`. Use the shorthand when you want the concise form; treat `codex exec review` as the documented form.
51
51
 
52
- Run non-interactively with the chosen selector:
52
+ Run non-interactively with the chosen selector, and always add `-o <path>` (a fresh path from `mktemp`) to capture the agent's final response in isolation. Raw stdout is the full exec transcript — a session banner, config block, and every shell command the review itself runs, with the actual review text buried somewhere inside — not just the final message. `-o` writes only that final message, cleanly:
53
53
 
54
- - `codex exec review --uncommitted`
55
- - `codex exec review --commit <SHA>`
56
- - `codex exec review --base <branch>`
57
- - `codex exec review "<PROMPT>"` to steer an uncommitted review (prompt-only; do not add `--uncommitted`)
54
+ - `codex exec review --uncommitted -o <path>`
55
+ - `codex exec review --commit <SHA> -o <path>`
56
+ - `codex exec review --base <branch> -o <path>`
57
+ - `codex exec review "<PROMPT>" -o <path>` to steer an uncommitted review (prompt-only; do not add `--uncommitted`)
58
58
 
59
- Do not pipe stdin into the command. The `review` subcommand already runs non-interactively.
59
+ Do not pipe stdin into the command. The `review` subcommand already runs non-interactively. A successful review always produces text in the `-o` file — even a clean result is a summary sentence, never nothing. Treat an empty or missing `-o` file as a failed invocation, regardless of exit code: check exit status and stderr for the cause, surface the failure, and stop. Never read empty output as "no findings."
60
60
 
61
61
  ## Reporting findings
62
62
 
63
- Summarize the review output concisely. Group findings by severity, then stop. Do not dump raw output into the session.
63
+ Only proceed here if `<path>` (the `-o` file) is non-empty. Read it for the review content. Do not grep, parse, or otherwise inspect raw stdout — it's the full transcript, not the result, and findings can be anywhere inside it. Summarize the file's content concisely. Group findings by severity, then stop. Do not dump raw output into the session.
64
64
 
65
- - Stdout is already formatted prose, not JSON: a summary line, then each finding as `Review comment: - [P0]`-`[P3] <title> — <file>:<line>` with its body below. Relay the existing `[P0]`-`[P3]` tags and summary line as-is — don't re-derive severity from wording.
65
+ - The `-o` file is already formatted prose, not JSON: a summary line, then each finding as `Review comment: - [P0]`-`[P3] <title> — <file>:<line>` with its body below. Relay the existing `[P0]`-`[P3]` tags and summary line as-is — don't re-derive severity from wording.
66
66
  - If there are findings, report the important ones first and keep the summary short.
67
67
  - If there are no findings, say so in one line.
68
68
 
@@ -70,7 +70,7 @@ Every orchestrator exit writes a final `■ orchestrator exit code=<N> [reason=<
70
70
 
71
71
  ### `canon stop <id>`
72
72
 
73
- Gracefully terminate a detached run. Sends SIGTERM then SIGKILL if needed. Self-heals stale `.canon-pid` / `.heartbeat.json` when the orchestrator is already dead.
73
+ Gracefully terminate a detached run. Sends SIGTERM then SIGKILL if needed. Self-heals stale `.canon-pid` / `.heartbeat.json` when the orchestrator is already dead. The orchestrator forwards the signal to its agent process groups, waits up to three seconds, then sends SIGKILL to surviving groups and allows up to one second for reaping before removing runtime markers and exiting. Phase completion is suppressed during shutdown so it cannot interrupt this cleanup.
74
74
 
75
75
  ---
76
76
 
@@ -119,7 +119,7 @@ canon task <subcommand> [args]
119
119
  | `accept` | `<id...> <phase> [--reason "<text>"] [--force]` | Operator accept supports `implement`, `spec_review`, and `code_review`. For `implement`, it is the escape hatch for already-committed work: it marks implement done and sets `operator_accepted` so post-implement auto-commit is skipped when the recorded HEAD still matches. For `spec_review` and `code_review`, `--reason` is required; accept writes a `sanctioned` verdict for non-advancing review verdicts, preserves already-advancing verdicts in a blocked bundle, records `operator_accepted*`, and appends the audit reason to `notes.md`. Review accept intentionally skips the implement-only diff/handoff guards. |
120
120
  | `set` | `<id> <field> <value>` | Set flat task metadata with validation. Metadata fields `title`, `task_size`, and `delicate` remain settable whenever the task is reachable. Topology fields `worktree` and `base_branch` are only settable before `status.branch` is recorded; once branched, `set` rejects them and points operators at recreating the task or migrating `status.json` manually. Redirected: `full_send` → `canon run --full-send`; `human_spec_gate` → re-run `canon run`; `status` → `canon task phase`; `branch` → git identity, not `canon task set`; `phases`/`sessions`/`canon`/`escalations` → their owning canon task commands. Immutable: `id`, `created`, `updated`, and `_`-prefixed inline-doc keys. Writes warn after dispatch has started because metadata changes take effect on the next `canon run`. |
121
121
  | `reset-spec-review` | `<id>` | Clear router-relevant state for a fresh spec-review pass after an auto-block. Zeroes iterations, clears verdict, archives the prior `spec-review.md`, and drops the stored `sessions.claude_spec` ID so the next pass runs against a fresh Claude spec session. |
122
- | `reset-code-review` | `<id>` | Clear router-relevant state for a fresh code-review pass after an auto-block. Zeroes the loop-local review counters, clears verdict, archives the prior `review.md`, and drops the stored `sessions.claude_review` ID so the next pass runs against a fresh Claude review session. |
122
+ | `reset-code-review` | `<id>` | Clear router-relevant state for a fresh code-review pass after an auto-block. Zeroes the loop-local review counters, clears verdict, archives the prior `review.md` and re-scaffolds a fresh one from the task templates, and drops the stored `sessions.claude_review` ID so the next pass runs against a fresh Claude review session. |
123
123
  | `post-merge-sync` | `[<branch>]` | After a squash-merge PR, reconcile local branch with origin. Hard-resets if the only divergence is pipeline telemetry; refuses if real new work exists. |
124
124
 
125
125
  ### Common patterns
@@ -467,7 +467,7 @@ Full-tier reroute (any S/M/L/XL task or any `delicate` task) re-enters at the sa
467
467
 
468
468
  Rerouting from `code_review` or a `qa` `pending`/`in_progress` entry happens before the QA-end commit, so task artifacts may still be uncommitted in the worktree. `--reroute` performs no git operation itself, so nothing is destroyed by the reroute. Do not run a manual git command that can discard uncommitted state (`reset --hard`, `checkout HEAD~N`, `stash drop`, or equivalent) in that window.
469
469
 
470
- Reroute archives each named task's `review.md` to `review-prior-<n>.md` in the active task directory, where `<n>` is one greater than the highest archive number already present (or 1 when none exist). It archives every task before changing any task's `status.json`; if an archive fails, reroute aborts without mutating any member's status, while any already-completed rename remains safely preserved on disk. A `review.md` that is still the pristine unfilled template is left in place and produces no archive. Reroute also drops the stored `sessions.claude_review` ID, so post-reroute code review starts a genuine round 1 rather than resuming a session that remembers prior rounds. Archived findings remain binding; exempt-sibling prompts point at the archived file instead of the now-absent `review.md`.
470
+ Reroute archives each named task's `review.md` to `review-prior-<n>.md` in the active task directory, where `<n>` is one greater than the highest archive number already present (or 1 when none exist). It archives every task before changing any task's `status.json`; if an archive fails, reroute aborts without mutating any member's status, while any already-completed rename remains safely preserved on disk. A `review.md` that is still the pristine scaffold is left in place and produces no archive. After archiving a filled review, reroute writes a fresh `review.md` scaffold into the task directory — from the project's `review.md` override under `tasks/_templates/` if it keeps one, otherwise from `.canon/templates/review.md` — so the code-review foreman fills the same template structure a new task starts with. If neither template exists, reroute warns and continues; the foreman then writes the file from scratch. Reroute also drops the stored `sessions.claude_review` ID, so post-reroute code review starts a genuine round 1 rather than resuming a session that remembers prior rounds. Archived findings remain binding; exempt-sibling prompts point at the archived file instead of the now-absent `review.md`.
471
471
 
472
472
  If Codex returns `changes_requested` on a full-tier reroute amendment, the pipeline blocks to the human instead of routing to pipeline-Claude spec revision. The block names the rejected task's `spec.md` and `spec-review.md`; revise the amendment in `spec.md`, then re-run the normal command:
473
473
 
@@ -472,13 +472,13 @@ function parseCanonOwnedArray(source) {
472
472
  // drift, so the hedge is honest; the suffix is stripped before path
473
473
  // validation either way, so accepting it costs the check nothing.
474
474
  function isLineCitationTarget(target) {
475
- return /(?::~?\d+(?:[-–—]~?\d+)?)$/.test(target) || /#L\d+(?:[-–—]L\d+)?$/.test(target);
475
+ return stripLineCitation(target) !== target;
476
476
  }
477
477
 
478
478
  function stripLineCitation(target) {
479
479
  return target
480
- .replace(/:~?\d+(?:[-–—]~?\d+)?(?:,~?\d+(?:[-–—]~?\d+)?)*$/, '')
481
- .replace(/#L\d+(?:[-–—]L?\d+)?(?:,L?\d+(?:[-–—]L?\d+)?)*$/, '');
480
+ .replace(/:~?\d+(?:[-–—]~?\d+)?(?:,[ \t]*~?\d+(?:[-–—]~?\d+)?)*$/, '')
481
+ .replace(/#L\d+(?:[-–—]L?\d+)?(?:,[ \t]*L?\d+(?:[-–—]L?\d+)?)*$/, '');
482
482
  }
483
483
 
484
484
  // `templates/` markdown is intentionally scanned — those files ship to