@erclx/canon 5.27.0 → 5.29.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.
Files changed (177) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/draft-ready/SKILL.md +3 -1
  3. package/claude/skills/git-pr/references/evidence.md +1 -1
  4. package/claude/skills/review-address/REQUIREMENT.md +4 -2
  5. package/claude/skills/review-address/SKILL.md +16 -7
  6. package/claude/skills/review-address/references/rebase-conflicts.md +4 -2
  7. package/claude/skills/review-craft/references/ui.md +4 -4
  8. package/claude/skills/review-ui/REQUIREMENT.md +2 -2
  9. package/claude/skills/review-ui/SKILL.md +13 -11
  10. package/claude/skills/review-ui/references/driving.md +8 -8
  11. package/claude/skills/review-ui/references/post.md +19 -7
  12. package/claude/skills/review-ui/references/tick.md +22 -0
  13. package/claude/skills/role-orchestrator/REQUIREMENT.md +15 -15
  14. package/claude/skills/role-orchestrator/SKILL.md +24 -26
  15. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +18 -16
  16. package/claude/skills/role-orchestrator/references/orchestrator-handback.md +12 -2
  17. package/claude/skills/role-orchestrator/references/orchestrator-inbound.md +1 -1
  18. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +1 -1
  19. package/claude/skills/role-orchestrator/references/orchestrator-output.md +4 -4
  20. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +5 -5
  21. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +11 -2
  22. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +6 -6
  23. package/claude/skills/role-orchestrator/references/orchestrator-sweep.md +2 -2
  24. package/claude/skills/role-orchestrator/scripts/poll.ts +304 -10
  25. package/claude/skills/role-planner/REQUIREMENT.md +1 -1
  26. package/claude/skills/role-planner/SKILL.md +2 -2
  27. package/claude/skills/role-reviewer/SKILL.md +1 -1
  28. package/claude/skills/role-worker/SKILL.md +3 -2
  29. package/claude/skills/ui-checklist/SKILL.md +1 -1
  30. package/docs/agents/canvas.md +12 -4
  31. package/docs/agents/gate.md +3 -1
  32. package/docs/agents/index.md +2 -1
  33. package/docs/agents/pr-evidence.md +15 -14
  34. package/docs/agents/pr-tick.md +72 -0
  35. package/docs/agents/sandbox.md +2 -2
  36. package/docs/agents/tasks-plans.md +1 -1
  37. package/docs/agents/tasks-validate.md +18 -18
  38. package/docs/agents/tasks.md +1 -1
  39. package/docs/workflow/operating-model.md +10 -15
  40. package/docs/workflow/parallel-features.md +7 -7
  41. package/package.json +1 -1
  42. package/src/audits/baseline.ts +1 -1
  43. package/src/audits/run.ts +1 -1
  44. package/src/canvas/capture.ts +1 -1
  45. package/src/canvas/client/app.tsx +105 -4
  46. package/src/canvas/client/inspector/field.tsx +61 -2
  47. package/src/canvas/client/inspector/fields.css +78 -0
  48. package/src/canvas/client/inspector/token-select.tsx +109 -0
  49. package/src/canvas/client/inspector/values.ts +74 -2
  50. package/src/canvas/client/inspector.tsx +134 -15
  51. package/src/canvas/client/keys.ts +71 -0
  52. package/src/canvas/client/pages-panel.tsx +5 -1
  53. package/src/canvas/client/panel-handle.tsx +90 -0
  54. package/src/canvas/client/selection.tsx +3 -1
  55. package/src/canvas/client/shell.css +194 -4
  56. package/src/canvas/client/state.ts +255 -11
  57. package/src/canvas/client/surface.tsx +231 -18
  58. package/src/canvas/client/tools.tsx +153 -0
  59. package/src/canvas/content.ts +66 -1
  60. package/src/canvas/edit.ts +207 -25
  61. package/src/canvas/history.ts +116 -0
  62. package/src/canvas/server.ts +119 -13
  63. package/src/canvas/tokens.ts +1 -1
  64. package/src/claude/seeds.ts +2 -2
  65. package/src/claude/skills-reach.ts +1 -1
  66. package/src/{exec.ts → cli/exec.ts} +2 -2
  67. package/src/{help.ts → cli/help.ts} +1 -1
  68. package/src/cli.ts +1 -1
  69. package/src/commands/audits.ts +9 -1
  70. package/src/commands/autoship.ts +1 -1
  71. package/src/commands/canvas.ts +2 -2
  72. package/src/commands/capture.ts +1 -1
  73. package/src/commands/census.ts +1 -1
  74. package/src/commands/claude.ts +5 -5
  75. package/src/commands/comments.ts +1 -1
  76. package/src/commands/context.ts +1 -1
  77. package/src/commands/demo.ts +9 -1
  78. package/src/commands/deps.ts +1 -1
  79. package/src/commands/design.ts +12 -4
  80. package/src/commands/docs.ts +2 -2
  81. package/src/commands/driver.ts +9 -1
  82. package/src/commands/feedback.ts +3 -3
  83. package/src/commands/gate.ts +10 -3
  84. package/src/commands/gov.ts +3 -3
  85. package/src/commands/indexes.ts +1 -1
  86. package/src/commands/init.ts +11 -3
  87. package/src/commands/intake.ts +1 -1
  88. package/src/commands/inventory.ts +9 -1
  89. package/src/commands/labels.ts +1 -1
  90. package/src/commands/markdown.ts +1 -1
  91. package/src/commands/migrate.ts +2 -2
  92. package/src/commands/pr.ts +324 -9
  93. package/src/commands/records.ts +1 -1
  94. package/src/commands/repo.ts +1 -1
  95. package/src/commands/sandbox.ts +11 -14
  96. package/src/commands/secrets.ts +9 -1
  97. package/src/commands/sessions.ts +1 -1
  98. package/src/commands/slides.ts +2 -2
  99. package/src/commands/standards.ts +1 -1
  100. package/src/commands/sync.ts +3 -3
  101. package/src/commands/targets.ts +1 -1
  102. package/src/commands/tasks.ts +20 -3
  103. package/src/commands/teach.ts +1 -1
  104. package/src/commands/tooling.ts +2 -2
  105. package/src/commands/transcripts.ts +2 -2
  106. package/src/commands/upgrade.ts +2 -2
  107. package/src/commands/wiki.ts +2 -2
  108. package/src/commands/worktrees.ts +1 -1
  109. package/src/context/architecture.ts +1 -1
  110. package/src/context/citations.ts +2 -2
  111. package/src/context/classify/extract.ts +1 -1
  112. package/src/context/folders.ts +2 -2
  113. package/src/context/requirements.ts +1 -1
  114. package/src/docs/read.ts +1 -1
  115. package/src/feedback/github.ts +1 -1
  116. package/src/gate/measures.ts +2 -2
  117. package/src/gate/sequencer.ts +55 -3
  118. package/src/gate/stages.ts +8 -0
  119. package/src/gate/suite-lock.ts +214 -0
  120. package/src/init/run.ts +1 -1
  121. package/src/intake/folder.ts +1 -1
  122. package/src/labels/map.ts +1 -1
  123. package/src/labels/phase.ts +3 -3
  124. package/src/migrate/record-layout.ts +1 -1
  125. package/src/migrate/records.ts +11 -11
  126. package/src/migrate/rename.ts +1 -1
  127. package/src/migrate/scratch-evidence.ts +1 -1
  128. package/src/migrate/surface-roots.ts +6 -6
  129. package/src/pr/evidence.ts +188 -16
  130. package/src/pr/tick.ts +56 -0
  131. package/src/process/harness.ts +1 -1
  132. package/src/records/backup.ts +1 -1
  133. package/src/records/ordinal.ts +1 -1
  134. package/src/records/prune.ts +1 -1
  135. package/src/records/size.ts +1 -1
  136. package/src/records/stale-canonical.ts +1 -1
  137. package/src/records/stale.ts +1 -1
  138. package/src/records/validate.ts +2 -2
  139. package/src/{project-root.ts → roots/project.ts} +2 -2
  140. package/src/{record-root.ts → roots/record.ts} +1 -1
  141. package/src/sandbox/coverage.ts +11 -12
  142. package/src/sandbox/equivalence.ts +57 -26
  143. package/src/sandbox/headless/run.ts +1 -1
  144. package/src/sandbox/hooks.ts +1 -1
  145. package/src/sandbox/provision.ts +79 -29
  146. package/src/sandbox/scenario.ts +588 -0
  147. package/src/serve/report.ts +1 -1
  148. package/src/sessions/live.ts +4 -1
  149. package/src/sessions/transfer/bundle.ts +1 -1
  150. package/src/slides/decks.ts +1 -1
  151. package/src/standards/read.ts +1 -1
  152. package/src/sync/engine.ts +2 -2
  153. package/src/sync/git.ts +1 -1
  154. package/src/sync/layout.ts +2 -2
  155. package/src/sync/stamp.ts +1 -1
  156. package/src/sync/workflow.ts +1 -1
  157. package/src/targets/validate.ts +2 -2
  158. package/src/tasks/answers.ts +1 -1
  159. package/src/tasks/archive.ts +1 -1
  160. package/src/tasks/label.ts +1 -1
  161. package/src/tasks/reach.ts +1 -1
  162. package/src/tasks/validate.ts +38 -14
  163. package/src/teach/nav.ts +1 -1
  164. package/src/teach/workspace.ts +1 -1
  165. package/src/tooling/inject.ts +2 -2
  166. package/src/tooling/read.ts +1 -1
  167. package/src/tooling/scan.ts +1 -1
  168. package/src/tooling/verify-stack.ts +1 -1
  169. package/src/version/installed.ts +1 -1
  170. package/src/version/skew.ts +1 -1
  171. package/standards/board.md +3 -3
  172. package/standards/plan.md +13 -7
  173. package/tsconfig.json +1 -1
  174. /package/src/{cli-run.ts → cli/run.ts} +0 -0
  175. /package/src/{ui.ts → cli/ui.ts} +0 -0
  176. /package/src/{legacy-path.ts → roots/legacy.ts} +0 -0
  177. /package/src/{surface-root.ts → roots/surface.ts} +0 -0
@@ -4,13 +4,21 @@ import {
4
4
  copyFileSync,
5
5
  existsSync,
6
6
  mkdirSync,
7
- readdirSync,
8
7
  rmSync,
9
- statSync,
10
8
  writeFileSync,
11
9
  } from 'node:fs'
12
10
  import { basename, dirname, join, relative } from 'node:path'
13
11
  import { probeScenario, stageScenario } from '@/sandbox/hooks'
12
+ import {
13
+ FIXTURE_SUFFIX,
14
+ FIXTURES_DIR,
15
+ listFixtureFiles,
16
+ loadScenario,
17
+ resolveScenarioFile,
18
+ type ScenarioDefinition,
19
+ scenarioExports,
20
+ stageScenarioInProcess,
21
+ } from '@/sandbox/scenario'
14
22
  import { assertSandboxDirSafe, sandboxRoots, sandboxTree } from '@/sandbox/tree'
15
23
  import {
16
24
  intro,
@@ -22,20 +30,20 @@ import {
22
30
  outro,
23
31
  palette,
24
32
  select,
25
- } from '@/ui'
33
+ } from '@/cli/ui'
26
34
 
27
35
  /**
28
36
  * Provisions one scenario into the sandbox tree, and resets or cleans that tree.
29
- * Each scenario's hooks run in bash through `sandbox-hook.sh`, and everything
30
- * between them runs here, in the order the retired bash dispatcher held.
37
+ * A bash scenario's hooks run through `sandbox-hook.sh` and a TypeScript one's
38
+ * arm runs in process through `scenario.ts`, and everything between them runs
39
+ * here, in the order the retired bash dispatcher held.
31
40
  *
32
41
  * Narration is part of the contract. `canon sandbox equivalence` compares the
33
42
  * log line for line against the bash harness, so every message, its frame
34
43
  * glyph, and its position in the order stays as that harness wrote it.
35
44
  */
36
45
 
37
- const ANCHOR_FIXTURE_PARTS = ['sandbox', 'fixtures', 'anchor', 'create']
38
- const FIXTURE_SUFFIX = '.fixture'
46
+ const ANCHOR_FIXTURE_PARTS = ['sandbox', FIXTURES_DIR, 'anchor', 'create']
39
47
  const SKILL_PATHSPEC = 'claude/skills/**/SKILL.md'
40
48
 
41
49
  /**
@@ -98,15 +106,6 @@ function finish(message: string): void {
98
106
  process.stderr.write(`\n${GREEN}${message}${NC}\n`)
99
107
  }
100
108
 
101
- function listFixtureFiles(dir: string): string[] {
102
- if (!existsSync(dir)) return []
103
-
104
- return (readdirSync(dir, { recursive: true, encoding: 'utf8' }) as string[])
105
- .map((path) => join(dir, path))
106
- .filter((path) => statSync(path).isFile())
107
- .sort()
108
- }
109
-
110
109
  function stageAnchorTree(
111
110
  root: string,
112
111
  sandbox: string,
@@ -402,12 +401,57 @@ interface Scenario {
402
401
  readonly arm: string | undefined
403
402
  }
404
403
 
405
- function provisionScenario(
404
+ /**
405
+ * Reads what a scenario declares ahead of provisioning: its config exports and
406
+ * whether it stages from the anchor. A bash scenario answers through the probe,
407
+ * and a TypeScript one from its module, which is also what its stage runs.
408
+ */
409
+ function declareScenario(
410
+ root: string,
411
+ scenario: Scenario,
412
+ env: NodeJS.ProcessEnv,
413
+ ):
414
+ | { kind: 'sh'; file: string; isAnchor: boolean }
415
+ | { kind: 'ts'; definition: ScenarioDefinition; isAnchor: boolean } {
416
+ const name = `${scenario.category}/${scenario.command}`
417
+ const resolved = resolveScenarioFile(
418
+ join(root, 'sandbox'),
419
+ scenario.category,
420
+ scenario.command,
421
+ )
422
+ if (!resolved.ok && resolved.reason === 'ambiguous')
423
+ fail(
424
+ `Sandbox script ${name} exists as both .sh and .ts. Delete the one the port replaced.`,
425
+ )
426
+ if (!resolved.ok) fail(`Sandbox script not found: ${name}`)
427
+
428
+ if (resolved.kind === 'sh') {
429
+ const probe = probeScenario(resolved.file, env)
430
+ if (!probe.ok) throw new Halt(probe.status)
431
+ Object.assign(env, probe.exports)
432
+
433
+ return { kind: 'sh', file: resolved.file, isAnchor: probe.isAnchor }
434
+ }
435
+
436
+ let definition: ScenarioDefinition
437
+ try {
438
+ definition = loadScenario(resolved.file)
439
+ } catch (error) {
440
+ fail(
441
+ `Could not load scenario ${name}: ${error instanceof Error ? error.message : String(error)}`,
442
+ )
443
+ }
444
+ Object.assign(env, scenarioExports(definition, root, env))
445
+
446
+ return { kind: 'ts', definition, isAnchor: definition.anchor === true }
447
+ }
448
+
449
+ async function provisionScenario(
406
450
  root: string,
407
451
  sandbox: string,
408
452
  scenario: Scenario,
409
453
  baseEnv: NodeJS.ProcessEnv,
410
- ): void {
454
+ ): Promise<void> {
411
455
  const env: NodeJS.ProcessEnv = { ...baseEnv }
412
456
  if (scenario.arm !== undefined) {
413
457
  env.SANDBOX_SCENARIO = scenario.arm
@@ -415,13 +459,7 @@ function provisionScenario(
415
459
  }
416
460
 
417
461
  const sandboxDir = join(root, 'sandbox')
418
- const file = join(sandboxDir, scenario.category, `${scenario.command}.sh`)
419
- if (!existsSync(file) || !statSync(file).isFile())
420
- fail(`Sandbox script not found: ${scenario.category}/${scenario.command}`)
421
-
422
- const probe = probeScenario(file, env)
423
- if (!probe.ok) throw new Halt(probe.status)
424
- Object.assign(env, probe.exports)
462
+ const declared = declareScenario(root, scenario, env)
425
463
 
426
464
  if (!existsSync(sandboxDir))
427
465
  fail(`Sandbox directory not found at: ${sandboxDir}`)
@@ -435,14 +473,26 @@ function provisionScenario(
435
473
  }
436
474
 
437
475
  logStep(`Provisioning ${scenario.category}:${scenario.command}`)
438
- if (probe.isAnchor) stageAnchorTree(root, sandbox, env)
476
+ if (declared.isAnchor) stageAnchorTree(root, sandbox, env)
439
477
  else initEmptyTree(sandbox, env)
440
478
  configureCredentials(sandbox, env)
441
479
  setupAssets(root, sandbox, env)
442
480
 
443
481
  // A scenario that execs a verb as its last step hands the run to that verb,
444
- // whose own frame is the last one written, so nothing follows it here.
445
- const staged = stageScenario(file, env)
482
+ // whose own frame is the last one written, so nothing follows it here. An
483
+ // in-process arm writes its exports straight into `env`.
484
+ const staged =
485
+ declared.kind === 'sh'
486
+ ? stageScenario(declared.file, env)
487
+ : {
488
+ ...(await stageScenarioInProcess(declared.definition, {
489
+ root,
490
+ dir: sandbox,
491
+ env,
492
+ arm: scenario.arm,
493
+ })),
494
+ exports: {},
495
+ }
446
496
  if (staged.ending === 'replaced') throw new Halt(staged.status, false)
447
497
  if (staged.ending === 'exited') throw new Halt(staged.status)
448
498
  Object.assign(env, staged.exports)
@@ -590,7 +640,7 @@ export async function runSandbox(
590
640
  }
591
641
 
592
642
  const { category, command } = parseTarget(request.target)
593
- provisionScenario(
643
+ await provisionScenario(
594
644
  root,
595
645
  sandbox,
596
646
  { category, command, arm: request.arm },