canon-ai 3.4.0 → 3.6.0
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/CHANGELOG.md +26 -0
- package/README.md +1 -1
- package/dist/cli/index.js +7 -29
- package/dist/orchestrator/run-task.js +217 -92
- package/package.json +1 -1
- package/templates/.canon/templates/spec.md +2 -0
- package/templates/.claude/agents/code-review-anchored.md +12 -0
- package/templates/.claude/agents/code-review-cold.md +1 -0
- package/templates/.claude/agents/spec-review-lens.md +33 -0
- package/templates/.claude/skills/canon-pipeline/recovery.md +21 -0
- package/templates/.claude/skills/canon-spec/SKILL.md +12 -1
- package/templates/.claude/skills/canon-spec-review/SKILL.md +38 -46
- package/templates/docs/pipeline-orchestrator.md +28 -11
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,32 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [3.6.0] — 2026-10-04
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **`/canon-spec-review` reviewers report every finding they can cite, and the final report does the filtering.** They now use Codex spec review's blocking and nit definitions, so behavior a spec explicitly excludes and verifies as unaffected is a nit at most. The Affected Files check now names the exact heading the pipeline reads, accepts any amendment section, and expects generated or rebuilt outputs to be listed. The reviewers now run as a read-only `spec-review-lens` agent that has no edit tools, can't launch other agents or skills, and is told to use the shell only for reading. Run `canon upgrade`, then start a new Claude Code session to pick it up.
|
|
12
|
+
- **Refactor specs must check that the behavior they preserve is actually correct.** Before a "preserve behavior" criterion, a refactor spec now records in *Problem* whether each preserved behavior is correct today, and gives one outcome for each: correct as-is, fixed deliberately with its own criterion, split into a separate task, or kept as a named quirk. A behavior confirmed correct needs only a one-line record. `/canon-spec`, the spec template, and the pipeline's spec phases all ask for it. Pipeline spec review treats a missing audit as blocking, while `/canon-spec-review` reports it as STRONG. Feature and bug-fix specs are unaffected.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **A task whose base branch can't be diffed now blocks instead of passing scope checks.** If git can't read a task's changes against its base (a stale or mistyped `base_branch`, a deleted base), the unreadable diff used to look like "nothing changed," so scope checks let the work through. Full-send review and the `code_review` pre-flight now block with git's error instead of advancing to QA or looping back to implement. `--pr` and `--push` report that the task's changed files couldn't be computed instead of advising a rebase, and `--force` does not bypass it. Implementation continues, with the full check matrix required.
|
|
17
|
+
|
|
18
|
+
## [3.5.0] — 2026-09-29
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **A reviewer that can't reach a verdict now stops the run for a human.** If a code-review lens returns nothing usable twice, the foreman sets `code_review` to `blocked` instead of being pushed to invent a verdict; recover with `canon task reset-code-review` for each bundle member, then `canon run`.
|
|
23
|
+
- **Plans include a short feasibility check.** Pipeline, reroute, and `/canon-spec` XS plans now confirm the code they rely on exists, trace the real call path and callers, and name the input that makes each new test fail without the fix.
|
|
24
|
+
- **`CLAUDE_MODEL_LIGHT` and `CLAUDE_MODEL_STRONG` override each tier's model.** Existing per-phase pins and `CLAUDE_MODEL` still work and take precedence in that order.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- **Claude defaults are re-baselined for the 5.5 generation.** Spec, plan, and code review run Sonnet `medium` for XS/S, Opus `medium` for M/L, and Opus `high` for XL/delicate; QA runs Sonnet `medium` at every size, and nothing runs at `xhigh`. A model pin now replaces only the model, so a Sonnet pin on M/L review or plan drops from `high` to `medium` effort.
|
|
29
|
+
- **Unattended Claude phases get an explicit unattended-session contract.** Like Codex's headless preamble, it says no one will answer questions, finishing means the artifact is written and the phase command has run, and the phase must not start other phases or reviewers.
|
|
30
|
+
- **The code-review foreman accepts clean lens results and bounds delegation.** A lens's empty result is now valid rather than "a bug in the lens," and the foreman spawns only its two lenses plus one re-spawn.
|
|
31
|
+
- **`/canon-spec-review` no longer requires a task ID.** With no argument it reviews the task under discussion, or asks which one when that's ambiguous.
|
|
32
|
+
|
|
7
33
|
## [3.4.0] — 2026-09-27
|
|
8
34
|
|
|
9
35
|
### Added
|
package/README.md
CHANGED
|
@@ -86,7 +86,7 @@ The pipeline supports two tiers:
|
|
|
86
86
|
- **Fast tier** (XS tasks): spec + plan in one Claude session, skip Codex spec review, human gate replaces it.
|
|
87
87
|
- **Full tier** (S / M / L / XL / delicate tasks): every phase runs separately, Codex reviews specs before they reach the human.
|
|
88
88
|
|
|
89
|
-
`delicate: true` (set in `status.json` at task creation) promotes any task to full tier and upgrades the
|
|
89
|
+
`delicate: true` (set in `status.json` at task creation) promotes any task to full tier and upgrades the model and effort for spec, plan, and code review, plus Codex spec review and implementation; QA and the cold-Codex review lens stay on their regular cells. Use it for sensitive surfaces — auth, payments, persistent storage, anything where a regression has unbounded blast radius.
|
|
90
90
|
|
|
91
91
|
A single command runs a task end-to-end:
|
|
92
92
|
|
package/dist/cli/index.js
CHANGED
|
@@ -555,20 +555,6 @@ import path4 from "path";
|
|
|
555
555
|
import { fileURLToPath } from "url";
|
|
556
556
|
var __filename = fileURLToPath(import.meta.url);
|
|
557
557
|
var __dirname = path4.dirname(__filename);
|
|
558
|
-
function parseMaxReviewLoops(raw) {
|
|
559
|
-
if (!raw) return null;
|
|
560
|
-
const trimmed = raw.trim();
|
|
561
|
-
if (!/^-?\d+$/.test(trimmed)) {
|
|
562
|
-
warn(`Invalid MAX_REVIEW_LOOPS value "${raw}"; using the size-aware default.`);
|
|
563
|
-
return null;
|
|
564
|
-
}
|
|
565
|
-
const parsed = Number(trimmed);
|
|
566
|
-
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
567
|
-
warn(`Invalid MAX_REVIEW_LOOPS value "${raw}"; using the size-aware default.`);
|
|
568
|
-
return null;
|
|
569
|
-
}
|
|
570
|
-
return parsed;
|
|
571
|
-
}
|
|
572
558
|
function resolveRepoRoot() {
|
|
573
559
|
try {
|
|
574
560
|
const result = spawnSync("git", ["rev-parse", "--git-common-dir"], { encoding: "utf8" });
|
|
@@ -601,15 +587,6 @@ function resolveProjectName() {
|
|
|
601
587
|
}
|
|
602
588
|
var config = {
|
|
603
589
|
projectName: resolveProjectName(),
|
|
604
|
-
claudeBudget: process.env.CLAUDE_BUDGET ?? null,
|
|
605
|
-
claudeModelSpec: process.env.CLAUDE_MODEL_SPEC ?? process.env.CLAUDE_MODEL ?? "opus",
|
|
606
|
-
claudeModelPlan: process.env.CLAUDE_MODEL_PLAN ?? process.env.CLAUDE_MODEL ?? "sonnet",
|
|
607
|
-
claudeModelReview: process.env.CLAUDE_MODEL_REVIEW ?? process.env.CLAUDE_MODEL ?? "sonnet",
|
|
608
|
-
claudeModelReviewLarge: process.env.CLAUDE_MODEL_REVIEW_LARGE ?? process.env.CLAUDE_MODEL ?? "opus",
|
|
609
|
-
claudeModelQa: process.env.CLAUDE_MODEL_QA ?? process.env.CLAUDE_MODEL ?? "sonnet",
|
|
610
|
-
codexModelMini: process.env.CODEX_MODEL_MINI ?? process.env.CODEX_MODEL_DEFAULT ?? "gpt-6-luna",
|
|
611
|
-
codexModelFull: process.env.CODEX_MODEL_FULL ?? process.env.CODEX_MODEL_DELICATE ?? "gpt-6-sol",
|
|
612
|
-
maxReviewLoops: parseMaxReviewLoops(process.env.MAX_REVIEW_LOOPS),
|
|
613
590
|
maxContextBytes: Number.parseInt(process.env.MAX_CONTEXT_BYTES ?? String(64 * 1024), 10)
|
|
614
591
|
};
|
|
615
592
|
|
|
@@ -1247,7 +1224,7 @@ function checkTemplates(cwd) {
|
|
|
1247
1224
|
}
|
|
1248
1225
|
function checkCanonVersion(cwd) {
|
|
1249
1226
|
const versionPath = join(cwd, ".canon", "version");
|
|
1250
|
-
const installedVersion = "3.
|
|
1227
|
+
const installedVersion = "3.6.0";
|
|
1251
1228
|
if (!existsSync(versionPath)) {
|
|
1252
1229
|
return { label: ".canon/version", status: "warn", detail: "missing \u2014 run `canon upgrade`" };
|
|
1253
1230
|
}
|
|
@@ -1744,7 +1721,7 @@ function initCmd(_args) {
|
|
|
1744
1721
|
}
|
|
1745
1722
|
function writeCanonVersion(cwd) {
|
|
1746
1723
|
const versionPath = join2(cwd, ".canon", "version");
|
|
1747
|
-
const version = "3.
|
|
1724
|
+
const version = "3.6.0";
|
|
1748
1725
|
mkdirSync(dirname2(versionPath), { recursive: true });
|
|
1749
1726
|
writeFileSync(versionPath, version + "\n");
|
|
1750
1727
|
}
|
|
@@ -2754,7 +2731,7 @@ function isInstalledSourcePath(sourcePath) {
|
|
|
2754
2731
|
return sourcePath.includes("/node_modules/") || sourcePath.includes("\\node_modules\\") || sourcePath.includes("/_npx/") || sourcePath.includes("\\_npx\\");
|
|
2755
2732
|
}
|
|
2756
2733
|
function resolveCanonVersion(explicit) {
|
|
2757
|
-
return explicit ?? "3.
|
|
2734
|
+
return explicit ?? "3.6.0" ?? "dev";
|
|
2758
2735
|
}
|
|
2759
2736
|
function resolveOrchestratorCommit(repoRoot, upstreamCommit, runGitAt) {
|
|
2760
2737
|
const ownToplevel = captureGitOutput(repoRoot, ["rev-parse", "--show-toplevel"], runGitAt);
|
|
@@ -4880,7 +4857,7 @@ function currentPinFromManifest(manifest) {
|
|
|
4880
4857
|
return "unknown";
|
|
4881
4858
|
}
|
|
4882
4859
|
function bakedVersion() {
|
|
4883
|
-
return "3.
|
|
4860
|
+
return "3.6.0";
|
|
4884
4861
|
}
|
|
4885
4862
|
function ownPackageName(pkgDir) {
|
|
4886
4863
|
try {
|
|
@@ -5096,6 +5073,7 @@ var CANON_OWNED = [
|
|
|
5096
5073
|
".claude/skills/canon-sweep/SKILL.md",
|
|
5097
5074
|
".claude/agents/code-review-anchored.md",
|
|
5098
5075
|
".claude/agents/code-review-cold.md",
|
|
5076
|
+
".claude/agents/spec-review-lens.md",
|
|
5099
5077
|
".canon/templates/status.json",
|
|
5100
5078
|
".canon/templates/spec.md",
|
|
5101
5079
|
".canon/templates/plan.md",
|
|
@@ -5356,7 +5334,7 @@ function runUpgrade(cwd, pkgDir, options = {}) {
|
|
|
5356
5334
|
cutoverWarnings.push(docsRefsCheckRel);
|
|
5357
5335
|
}
|
|
5358
5336
|
const versionPath = join5(cwd, ".canon", "version");
|
|
5359
|
-
const newVersion = "3.
|
|
5337
|
+
const newVersion = "3.6.0";
|
|
5360
5338
|
const currentVersion = existsSync5(versionPath) ? readFileSync4(versionPath, "utf8").trim() : null;
|
|
5361
5339
|
if (currentVersion !== newVersion) {
|
|
5362
5340
|
pending.push({ rel: ".canon/version", projectPath: versionPath, content: newVersion + "\n" });
|
|
@@ -5664,7 +5642,7 @@ Global:
|
|
|
5664
5642
|
`);
|
|
5665
5643
|
}
|
|
5666
5644
|
function printVersion() {
|
|
5667
|
-
console.log("3.
|
|
5645
|
+
console.log("3.6.0");
|
|
5668
5646
|
}
|
|
5669
5647
|
switch (command) {
|
|
5670
5648
|
case "doctor":
|