harnery 0.36.0 → 0.37.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 (311) hide show
  1. package/dist/commander.js +4 -0
  2. package/dist/commands/agents.d.ts.map +1 -1
  3. package/dist/commands/agents.js +87 -46
  4. package/dist/commands/artifacts.d.ts.map +1 -1
  5. package/dist/commands/artifacts.js +26 -1
  6. package/dist/commands/browse.d.ts.map +1 -1
  7. package/dist/commands/browse.js +11 -0
  8. package/dist/commands/diagnostics.d.ts +4 -0
  9. package/dist/commands/diagnostics.d.ts.map +1 -0
  10. package/dist/commands/diagnostics.js +229 -0
  11. package/dist/commands/files.d.ts +12 -0
  12. package/dist/commands/files.d.ts.map +1 -1
  13. package/dist/commands/files.js +54 -1
  14. package/dist/commands/governor.d.ts.map +1 -1
  15. package/dist/commands/governor.js +4 -0
  16. package/dist/commands/ledger-v3.d.ts.map +1 -1
  17. package/dist/commands/ledger-v3.js +71 -2
  18. package/dist/commands/qa-run.d.ts +4 -0
  19. package/dist/commands/qa-run.d.ts.map +1 -0
  20. package/dist/commands/qa-run.js +141 -0
  21. package/dist/commands/resources.d.ts +4 -0
  22. package/dist/commands/resources.d.ts.map +1 -0
  23. package/dist/commands/resources.js +29 -0
  24. package/dist/commands/supervisor.d.ts +4 -0
  25. package/dist/commands/supervisor.d.ts.map +1 -0
  26. package/dist/commands/supervisor.js +101 -0
  27. package/dist/commands/web.d.ts.map +1 -1
  28. package/dist/commands/web.js +17 -0
  29. package/dist/commands/workflow.d.ts.map +1 -1
  30. package/dist/commands/workflow.js +4 -0
  31. package/dist/core/agents/cli.js +7 -3
  32. package/dist/core/agents/health.d.ts +17 -0
  33. package/dist/core/agents/health.d.ts.map +1 -0
  34. package/dist/core/agents/health.js +109 -0
  35. package/dist/core/agents/mailbox.d.ts +92 -0
  36. package/dist/core/agents/mailbox.d.ts.map +1 -0
  37. package/dist/core/agents/mailbox.js +325 -0
  38. package/dist/core/agents/reconcile-coordination-v3.d.ts +44 -0
  39. package/dist/core/agents/reconcile-coordination-v3.d.ts.map +1 -0
  40. package/dist/core/agents/reconcile-coordination-v3.js +58 -0
  41. package/dist/core/agents/render/prompt-context.d.ts +5 -0
  42. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  43. package/dist/core/agents/render/prompt-context.js +34 -13
  44. package/dist/core/agents/render/session-context.d.ts +8 -0
  45. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  46. package/dist/core/agents/render/session-context.js +34 -3
  47. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  48. package/dist/core/agents/rules/commit-conflict.js +50 -1
  49. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  50. package/dist/core/agents/rules/stop-hook.js +6 -10
  51. package/dist/core/agents/session-finalizer-v3.js +4 -1
  52. package/dist/core/artifacts/index.d.ts +26 -1
  53. package/dist/core/artifacts/index.d.ts.map +1 -1
  54. package/dist/core/artifacts/index.js +146 -6
  55. package/dist/core/config.d.ts +12 -0
  56. package/dist/core/config.d.ts.map +1 -1
  57. package/dist/core/config.js +43 -0
  58. package/dist/core/diagnostics/advice.d.ts +9 -0
  59. package/dist/core/diagnostics/advice.d.ts.map +1 -0
  60. package/dist/core/diagnostics/advice.js +112 -0
  61. package/dist/core/diagnostics/bundle.d.ts +35 -0
  62. package/dist/core/diagnostics/bundle.d.ts.map +1 -0
  63. package/dist/core/diagnostics/bundle.js +874 -0
  64. package/dist/core/diagnostics/comparison.d.ts +5 -0
  65. package/dist/core/diagnostics/comparison.d.ts.map +1 -0
  66. package/dist/core/diagnostics/comparison.js +444 -0
  67. package/dist/core/diagnostics/contract.d.ts +245 -0
  68. package/dist/core/diagnostics/contract.d.ts.map +1 -0
  69. package/dist/core/diagnostics/contract.js +18 -0
  70. package/dist/core/diagnostics/identity.d.ts +3 -0
  71. package/dist/core/diagnostics/identity.d.ts.map +1 -0
  72. package/dist/core/diagnostics/identity.js +10 -0
  73. package/dist/core/diagnostics/index.d.ts +8 -0
  74. package/dist/core/diagnostics/index.d.ts.map +1 -0
  75. package/dist/core/diagnostics/index.js +7 -0
  76. package/dist/core/diagnostics/replay.d.ts +8 -0
  77. package/dist/core/diagnostics/replay.d.ts.map +1 -0
  78. package/dist/core/diagnostics/replay.js +213 -0
  79. package/dist/core/diagnostics/sanitize.d.ts +9 -0
  80. package/dist/core/diagnostics/sanitize.d.ts.map +1 -0
  81. package/dist/core/diagnostics/sanitize.js +84 -0
  82. package/dist/core/events/legacy-storage/compression.d.ts +13 -0
  83. package/dist/core/events/legacy-storage/compression.d.ts.map +1 -0
  84. package/dist/core/events/legacy-storage/compression.js +107 -0
  85. package/dist/core/events/legacy-storage/index.d.ts +1 -0
  86. package/dist/core/events/legacy-storage/index.d.ts.map +1 -1
  87. package/dist/core/events/legacy-storage/index.js +1 -0
  88. package/dist/core/events/v3/archive-retention.d.ts +33 -0
  89. package/dist/core/events/v3/archive-retention.d.ts.map +1 -0
  90. package/dist/core/events/v3/archive-retention.js +195 -0
  91. package/dist/core/events/v3/capabilities.d.ts +1 -1
  92. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  93. package/dist/core/events/v3/capabilities.js +1 -0
  94. package/dist/core/events/v3/index.d.ts +1 -0
  95. package/dist/core/events/v3/index.d.ts.map +1 -1
  96. package/dist/core/events/v3/index.js +1 -0
  97. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  98. package/dist/core/events/v3/live-routing.js +1 -0
  99. package/dist/core/events/v3/producers/hook-base.d.ts +1 -1
  100. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  101. package/dist/core/events/v3/producers/hook-base.js +13 -2
  102. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  103. package/dist/core/events/v3/producers/intake.js +1 -0
  104. package/dist/core/events/v3/producers/recorder.d.ts +16 -0
  105. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  106. package/dist/core/events/v3/producers/recorder.js +88 -1
  107. package/dist/core/hooks/adapter/output.d.ts +8 -0
  108. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  109. package/dist/core/hooks/adapter/output.js +11 -1
  110. package/dist/core/hooks/cli.js +183 -192
  111. package/dist/core/hooks/health.d.ts +59 -0
  112. package/dist/core/hooks/health.d.ts.map +1 -0
  113. package/dist/core/hooks/health.js +84 -0
  114. package/dist/core/resources/contract.d.ts +90 -0
  115. package/dist/core/resources/contract.d.ts.map +1 -0
  116. package/dist/core/resources/contract.js +2 -0
  117. package/dist/core/resources/index.d.ts +6 -0
  118. package/dist/core/resources/index.d.ts.map +1 -0
  119. package/dist/core/resources/index.js +5 -0
  120. package/dist/core/resources/sampler.d.ts +27 -0
  121. package/dist/core/resources/sampler.d.ts.map +1 -0
  122. package/dist/core/resources/sampler.js +357 -0
  123. package/dist/core/resources/service-status.d.ts +3 -0
  124. package/dist/core/resources/service-status.d.ts.map +1 -0
  125. package/dist/core/resources/service-status.js +48 -0
  126. package/dist/core/resources/service.d.ts +26 -0
  127. package/dist/core/resources/service.d.ts.map +1 -0
  128. package/dist/core/resources/service.js +292 -0
  129. package/dist/core/resources/storage.d.ts +13 -0
  130. package/dist/core/resources/storage.d.ts.map +1 -0
  131. package/dist/core/resources/storage.js +30 -0
  132. package/dist/core/storage/atomic-json.d.ts +3 -0
  133. package/dist/core/storage/atomic-json.d.ts.map +1 -0
  134. package/dist/core/storage/atomic-json.js +15 -0
  135. package/dist/core/storage/builtins.d.ts.map +1 -1
  136. package/dist/core/storage/builtins.js +45 -6
  137. package/dist/core/storage/logger.d.ts +2 -0
  138. package/dist/core/storage/logger.d.ts.map +1 -1
  139. package/dist/core/storage/logger.js +2 -0
  140. package/dist/core/storage/query.d.ts +14 -0
  141. package/dist/core/storage/query.d.ts.map +1 -1
  142. package/dist/core/storage/query.js +51 -0
  143. package/dist/core/supervisor/activity.d.ts +4 -0
  144. package/dist/core/supervisor/activity.d.ts.map +1 -0
  145. package/dist/core/supervisor/activity.js +141 -0
  146. package/dist/core/supervisor/contract.d.ts +268 -0
  147. package/dist/core/supervisor/contract.d.ts.map +1 -0
  148. package/dist/core/supervisor/contract.js +35 -0
  149. package/dist/core/supervisor/explanations.d.ts +4 -0
  150. package/dist/core/supervisor/explanations.d.ts.map +1 -0
  151. package/dist/core/supervisor/explanations.js +71 -0
  152. package/dist/core/supervisor/findings.d.ts +20 -0
  153. package/dist/core/supervisor/findings.d.ts.map +1 -0
  154. package/dist/core/supervisor/findings.js +399 -0
  155. package/dist/core/supervisor/history.d.ts +9 -0
  156. package/dist/core/supervisor/history.d.ts.map +1 -0
  157. package/dist/core/supervisor/history.js +46 -0
  158. package/dist/core/supervisor/hook-health-alerts.d.ts +14 -0
  159. package/dist/core/supervisor/hook-health-alerts.d.ts.map +1 -0
  160. package/dist/core/supervisor/hook-health-alerts.js +70 -0
  161. package/dist/core/supervisor/hook-health-storage.d.ts +5 -0
  162. package/dist/core/supervisor/hook-health-storage.d.ts.map +1 -0
  163. package/dist/core/supervisor/hook-health-storage.js +24 -0
  164. package/dist/core/supervisor/hook-health.d.ts +72 -0
  165. package/dist/core/supervisor/hook-health.d.ts.map +1 -0
  166. package/dist/core/supervisor/hook-health.js +203 -0
  167. package/dist/core/supervisor/hooks.d.ts +10 -0
  168. package/dist/core/supervisor/hooks.d.ts.map +1 -0
  169. package/dist/core/supervisor/hooks.js +28 -0
  170. package/dist/core/supervisor/index.d.ts +15 -0
  171. package/dist/core/supervisor/index.d.ts.map +1 -0
  172. package/dist/core/supervisor/index.js +14 -0
  173. package/dist/core/supervisor/log-feed.d.ts +9 -0
  174. package/dist/core/supervisor/log-feed.d.ts.map +1 -0
  175. package/dist/core/supervisor/log-feed.js +103 -0
  176. package/dist/core/supervisor/service.d.ts +29 -0
  177. package/dist/core/supervisor/service.d.ts.map +1 -0
  178. package/dist/core/supervisor/service.js +450 -0
  179. package/dist/core/supervisor/services.d.ts +11 -0
  180. package/dist/core/supervisor/services.d.ts.map +1 -0
  181. package/dist/core/supervisor/services.js +155 -0
  182. package/dist/core/supervisor/status.d.ts +3 -0
  183. package/dist/core/supervisor/status.d.ts.map +1 -0
  184. package/dist/core/supervisor/status.js +48 -0
  185. package/dist/core/supervisor/storage.d.ts +30 -0
  186. package/dist/core/supervisor/storage.d.ts.map +1 -0
  187. package/dist/core/supervisor/storage.js +73 -0
  188. package/dist/core/supervisor/timeline.d.ts +3 -0
  189. package/dist/core/supervisor/timeline.d.ts.map +1 -0
  190. package/dist/core/supervisor/timeline.js +87 -0
  191. package/dist/core/workflow/admission.d.ts +23 -0
  192. package/dist/core/workflow/admission.d.ts.map +1 -0
  193. package/dist/core/workflow/admission.js +136 -0
  194. package/dist/core/workflow/engine.d.ts.map +1 -1
  195. package/dist/core/workflow/engine.js +77 -2
  196. package/dist/core/workflow/index.d.ts +3 -2
  197. package/dist/core/workflow/index.d.ts.map +1 -1
  198. package/dist/core/workflow/index.js +2 -1
  199. package/dist/core/workflow/proof.d.ts +2 -1
  200. package/dist/core/workflow/proof.d.ts.map +1 -1
  201. package/dist/core/workflow/proof.js +39 -1
  202. package/dist/core/workflow/run-state.d.ts +3 -2
  203. package/dist/core/workflow/run-state.d.ts.map +1 -1
  204. package/dist/core/workflow/run-state.js +8 -1
  205. package/dist/core/workflow/types.d.ts +33 -1
  206. package/dist/core/workflow/types.d.ts.map +1 -1
  207. package/dist/core/workflow/types.js +2 -1
  208. package/dist/lib/browser/client.d.ts +5 -0
  209. package/dist/lib/browser/client.d.ts.map +1 -1
  210. package/dist/lib/browser/client.js +1 -0
  211. package/dist/lib/browser/index.d.ts +2 -0
  212. package/dist/lib/browser/index.d.ts.map +1 -1
  213. package/dist/lib/browser/index.js +2 -0
  214. package/dist/lib/browser/qa-run-contracts.d.ts +173 -0
  215. package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -0
  216. package/dist/lib/browser/qa-run-contracts.js +226 -0
  217. package/dist/lib/browser/qa-run.d.ts +51 -0
  218. package/dist/lib/browser/qa-run.d.ts.map +1 -0
  219. package/dist/lib/browser/qa-run.js +684 -0
  220. package/dist/lib/coord-root-id.d.ts +9 -0
  221. package/dist/lib/coord-root-id.d.ts.map +1 -0
  222. package/dist/lib/coord-root-id.js +17 -0
  223. package/dist/lib/instructions/apply.d.ts +3 -1
  224. package/dist/lib/instructions/apply.d.ts.map +1 -1
  225. package/dist/lib/instructions/apply.js +74 -3
  226. package/dist/lib/instructions/templates.d.ts.map +1 -1
  227. package/dist/lib/instructions/templates.js +6 -0
  228. package/package.json +12 -1
  229. package/src/commander.ts +26 -0
  230. package/src/commands/agents.ts +102 -49
  231. package/src/commands/artifacts.ts +40 -2
  232. package/src/commands/browse.ts +15 -0
  233. package/src/commands/diagnostics.ts +271 -0
  234. package/src/commands/files.ts +102 -2
  235. package/src/commands/governor.ts +8 -0
  236. package/src/commands/ledger-v3.ts +82 -0
  237. package/src/commands/qa-run.ts +184 -0
  238. package/src/commands/resources.ts +38 -0
  239. package/src/commands/supervisor.ts +141 -0
  240. package/src/commands/web.ts +19 -0
  241. package/src/commands/workflow.ts +8 -0
  242. package/src/core/agents/cli.ts +7 -3
  243. package/src/core/agents/health.ts +142 -0
  244. package/src/core/agents/mailbox.ts +373 -0
  245. package/src/core/agents/reconcile-coordination-v3.ts +77 -0
  246. package/src/core/agents/render/prompt-context.ts +42 -12
  247. package/src/core/agents/render/session-context.ts +37 -3
  248. package/src/core/agents/rules/commit-conflict.ts +58 -1
  249. package/src/core/agents/rules/stop-hook.ts +6 -12
  250. package/src/core/agents/session-finalizer-v3.ts +4 -1
  251. package/src/core/artifacts/index.ts +196 -10
  252. package/src/core/config.ts +111 -2
  253. package/src/core/diagnostics/advice.ts +147 -0
  254. package/src/core/diagnostics/bundle.ts +1142 -0
  255. package/src/core/diagnostics/comparison.ts +565 -0
  256. package/src/core/diagnostics/contract.ts +311 -0
  257. package/src/core/diagnostics/identity.ts +11 -0
  258. package/src/core/diagnostics/index.ts +7 -0
  259. package/src/core/diagnostics/replay.ts +314 -0
  260. package/src/core/diagnostics/sanitize.ts +97 -0
  261. package/src/core/events/legacy-storage/compression.ts +130 -0
  262. package/src/core/events/legacy-storage/index.ts +1 -0
  263. package/src/core/events/v3/archive-retention.ts +251 -0
  264. package/src/core/events/v3/capabilities.ts +2 -0
  265. package/src/core/events/v3/index.ts +9 -0
  266. package/src/core/events/v3/live-routing.ts +1 -0
  267. package/src/core/events/v3/producers/hook-base.ts +14 -2
  268. package/src/core/events/v3/producers/intake.ts +1 -0
  269. package/src/core/events/v3/producers/recorder.ts +110 -1
  270. package/src/core/hooks/adapter/output.ts +12 -1
  271. package/src/core/hooks/cli.ts +192 -215
  272. package/src/core/hooks/health.ts +146 -0
  273. package/src/core/resources/contract.ts +98 -0
  274. package/src/core/resources/index.ts +5 -0
  275. package/src/core/resources/sampler.ts +458 -0
  276. package/src/core/resources/service-status.ts +62 -0
  277. package/src/core/resources/service.ts +337 -0
  278. package/src/core/resources/storage.ts +44 -0
  279. package/src/core/storage/atomic-json.ts +15 -0
  280. package/src/core/storage/builtins.ts +62 -6
  281. package/src/core/storage/logger.ts +2 -0
  282. package/src/core/storage/query.ts +58 -0
  283. package/src/core/supervisor/activity.ts +193 -0
  284. package/src/core/supervisor/contract.ts +312 -0
  285. package/src/core/supervisor/explanations.ts +104 -0
  286. package/src/core/supervisor/findings.ts +788 -0
  287. package/src/core/supervisor/history.ts +61 -0
  288. package/src/core/supervisor/hook-health-alerts.ts +108 -0
  289. package/src/core/supervisor/hook-health-storage.ts +25 -0
  290. package/src/core/supervisor/hook-health.ts +301 -0
  291. package/src/core/supervisor/hooks.ts +35 -0
  292. package/src/core/supervisor/index.ts +14 -0
  293. package/src/core/supervisor/log-feed.ts +131 -0
  294. package/src/core/supervisor/service.ts +511 -0
  295. package/src/core/supervisor/services.ts +203 -0
  296. package/src/core/supervisor/status.ts +59 -0
  297. package/src/core/supervisor/storage.ts +126 -0
  298. package/src/core/supervisor/timeline.ts +133 -0
  299. package/src/core/workflow/admission.ts +215 -0
  300. package/src/core/workflow/engine.ts +93 -1
  301. package/src/core/workflow/index.ts +10 -0
  302. package/src/core/workflow/proof.ts +54 -1
  303. package/src/core/workflow/run-state.ts +13 -1
  304. package/src/core/workflow/types.ts +39 -1
  305. package/src/lib/browser/client.ts +6 -0
  306. package/src/lib/browser/index.ts +29 -0
  307. package/src/lib/browser/qa-run-contracts.ts +380 -0
  308. package/src/lib/browser/qa-run.ts +784 -0
  309. package/src/lib/coord-root-id.ts +23 -0
  310. package/src/lib/instructions/apply.ts +81 -2
  311. package/src/lib/instructions/templates.ts +6 -0
@@ -0,0 +1,229 @@
1
+ import { monorepoRoot, resolveOwner } from "../core/agents/index.js";
2
+ import { readLiveCoordinationRow } from "../core/agents/state/live-coordination-view.js";
3
+ import { buildDiagnosticAdvice, captureDiagnosticBundle, compareDiagnosticBundles, DIAGNOSTIC_COMMAND_SCHEMA_VERSION, listDiagnosticBundles, renderDiagnosticBundleComparison, replayDiagnosticBundle, showDiagnosticBundle, } from "../core/diagnostics/index.js";
4
+ import { buildSupervisorTimeline, explainSupervisorFinding, readSupervisorExplanation, readSupervisorFindings, readSupervisorStatus, readSupervisorTimeline, } from "../core/supervisor/index.js";
5
+ export function registerDiagnosticsCommand(program, emit, context) {
6
+ const root = program
7
+ .command("diagnostics")
8
+ .description("Capture, inspect, and replay sanitized local diagnostic bundles.");
9
+ root
10
+ .command("list")
11
+ .description("List live findings and managed diagnostic bundles.")
12
+ .action(() => {
13
+ run(emit, () => {
14
+ const repoRoot = requireRepoRoot(context);
15
+ const report = readSupervisorFindings(repoRoot);
16
+ const findings = mergeFindings(report?.active ?? [], report?.transitions ?? []);
17
+ const bundles = listDiagnosticBundles(repoRoot);
18
+ const capability = liveFindingsCapability(repoRoot, report !== undefined);
19
+ emit.data({
20
+ schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
21
+ kind: "diagnostic_list",
22
+ findings,
23
+ bundles,
24
+ capability,
25
+ total_findings: findings.length,
26
+ total_bundles: bundles.length,
27
+ });
28
+ });
29
+ });
30
+ root
31
+ .command("show <ref>")
32
+ .description("Show one finding or validate one diagnostic bundle.")
33
+ .action((ref) => {
34
+ run(emit, () => {
35
+ const repoRoot = requireRepoRoot(context);
36
+ const finding = findFinding(repoRoot, ref);
37
+ if (finding) {
38
+ emit.data({
39
+ schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
40
+ kind: "diagnostic_finding",
41
+ finding,
42
+ timeline: readSupervisorTimeline(repoRoot, finding.id) ?? buildSupervisorTimeline(finding),
43
+ explanation: readSupervisorExplanation(repoRoot, finding.id) ?? explainSupervisorFinding(finding),
44
+ });
45
+ return;
46
+ }
47
+ const bundle = showDiagnosticBundle(repoRoot, ref);
48
+ emit.data({
49
+ schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
50
+ kind: "diagnostic_bundle",
51
+ bundle: {
52
+ path: bundle.path,
53
+ manifest: bundle.manifest,
54
+ summary: bundle.summary,
55
+ },
56
+ });
57
+ });
58
+ });
59
+ root
60
+ .command("explain")
61
+ .description("Report bounded local pressure advice without taking action.")
62
+ .option("--bundle <artifact-ref>", "Use a frozen diagnostic bundle instead of live state")
63
+ .option("--json", "Emit structured JSON")
64
+ .action((opts) => {
65
+ run(emit, () => {
66
+ if (opts.json)
67
+ emit.config({ format: "json" });
68
+ const repoRoot = requireRepoRoot(context);
69
+ if (opts.bundle) {
70
+ const bundle = showDiagnosticBundle(repoRoot, opts.bundle);
71
+ emit.data({
72
+ schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
73
+ kind: "diagnostic_advice",
74
+ source: {
75
+ mode: "frozen",
76
+ artifact_id: bundle.manifest.artifact_id,
77
+ captured_at: bundle.manifest.captured_at,
78
+ },
79
+ advice: bundle.expected.advice,
80
+ });
81
+ return;
82
+ }
83
+ const report = readSupervisorFindings(repoRoot);
84
+ const findings = mergeFindings(report?.active ?? [], report?.transitions ?? []);
85
+ const sourceCapability = liveFindingsCapability(repoRoot, report !== undefined);
86
+ emit.data({
87
+ schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
88
+ kind: "diagnostic_advice",
89
+ source: { mode: "live" },
90
+ advice: buildDiagnosticAdvice({
91
+ findings,
92
+ sourceCapability,
93
+ evaluatedAt: new Date().toISOString(),
94
+ }),
95
+ });
96
+ });
97
+ });
98
+ root
99
+ .command("capture")
100
+ .description("Capture sanitized supervisor inputs into a frozen managed bundle.")
101
+ .option("--finding <id>", "Capture the time range for one finding")
102
+ .option("--from <timestamp>", "Capture observations from this ISO timestamp")
103
+ .option("--to <timestamp>", "Capture observations through this ISO timestamp")
104
+ .option("--days <n>", "Managed artifact retention in days")
105
+ .action((opts) => {
106
+ run(emit, () => {
107
+ const repoRoot = requireRepoRoot(context);
108
+ const captured = captureDiagnosticBundle(repoRoot, {
109
+ findingId: opts.finding,
110
+ startAt: opts.from,
111
+ endAt: opts.to,
112
+ retentionDays: opts.days === undefined ? undefined : parseDays(opts.days),
113
+ actor: currentActor(repoRoot),
114
+ });
115
+ emit.data({
116
+ schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
117
+ kind: "diagnostic_bundle_capture",
118
+ bundle: {
119
+ path: captured.path,
120
+ artifact_id: captured.manifest.artifact_id,
121
+ captured_at: captured.manifest.captured_at,
122
+ finding_id: captured.manifest.finding_id,
123
+ summary: captured.summary,
124
+ },
125
+ });
126
+ });
127
+ });
128
+ root
129
+ .command("replay <artifact-ref>")
130
+ .description("Replay a frozen bundle without reading live supervisor state.")
131
+ .action((ref) => {
132
+ run(emit, () => {
133
+ emit.data({
134
+ schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
135
+ kind: "diagnostic_bundle_replay",
136
+ replay: replayDiagnosticBundle(requireRepoRoot(context), ref),
137
+ });
138
+ });
139
+ });
140
+ root
141
+ .command("compare <before> <after>")
142
+ .description("Compare two frozen bundles without reading live supervisor state.")
143
+ .option("--json", "Emit structured JSON")
144
+ .action((before, after, opts) => {
145
+ run(emit, () => {
146
+ const comparison = compareDiagnosticBundles(requireRepoRoot(context), before, after);
147
+ if (opts.json) {
148
+ emit.config({ format: "json" });
149
+ emit.data({
150
+ schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
151
+ kind: "diagnostic_bundle_comparison",
152
+ comparison,
153
+ });
154
+ return;
155
+ }
156
+ emit.text(renderDiagnosticBundleComparison(comparison));
157
+ });
158
+ });
159
+ }
160
+ function liveFindingsCapability(repoRoot, reportPresent) {
161
+ if (!reportPresent) {
162
+ return {
163
+ source_kind: "supervisor.findings",
164
+ state: "unsupported",
165
+ reason_code: "source_missing",
166
+ };
167
+ }
168
+ const status = readSupervisorStatus(repoRoot);
169
+ if (status.running)
170
+ return { source_kind: "supervisor.findings", state: "supported" };
171
+ return {
172
+ source_kind: "supervisor.findings",
173
+ state: "expired",
174
+ reason_code: status.stale
175
+ ? "supervisor_status_stale"
176
+ : status.record
177
+ ? "supervisor_not_running"
178
+ : "supervisor_status_missing",
179
+ };
180
+ }
181
+ function findFinding(repoRoot, id) {
182
+ const report = readSupervisorFindings(repoRoot);
183
+ return mergeFindings(report?.active ?? [], report?.transitions ?? []).find((finding) => finding.id === id);
184
+ }
185
+ function mergeFindings(active, transitions) {
186
+ const byId = new Map();
187
+ for (const finding of transitions)
188
+ byId.set(finding.id, finding);
189
+ for (const finding of active)
190
+ byId.set(finding.id, finding);
191
+ return [...byId.values()].sort((left, right) => Date.parse(right.observed_at) - Date.parse(left.observed_at) ||
192
+ left.id.localeCompare(right.id));
193
+ }
194
+ function currentActor(repoRoot) {
195
+ const instanceId = resolveOwner();
196
+ if (!instanceId)
197
+ return undefined;
198
+ const heartbeat = readLiveCoordinationRow(repoRoot, instanceId);
199
+ return {
200
+ instance_id: instanceId,
201
+ session_id: heartbeat?.session_id,
202
+ name: heartbeat?.name,
203
+ };
204
+ }
205
+ function requireRepoRoot(context) {
206
+ const root = context?.repoRoot ?? monorepoRoot();
207
+ if (!root)
208
+ throw new Error("not inside a Git repository");
209
+ return root;
210
+ }
211
+ function parseDays(value) {
212
+ const parsed = Number(value);
213
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > 3_650) {
214
+ throw new Error("--days must be between 1 and 3650");
215
+ }
216
+ return parsed;
217
+ }
218
+ function run(emit, fn) {
219
+ try {
220
+ fn();
221
+ }
222
+ catch (error) {
223
+ emit.error({
224
+ code: "diagnostics_failed",
225
+ message: error instanceof Error ? error.message : String(error),
226
+ });
227
+ emit.setExitCode(1);
228
+ }
229
+ }
@@ -12,6 +12,18 @@ export interface LocalFileUrl {
12
12
  relPath: string;
13
13
  mode: Exclude<LocalFileUrlMode, "auto">;
14
14
  }
15
+ export type DashboardRootErrorCode = "dashboard_unreachable" | "dashboard_identity_unavailable" | "dashboard_root_mismatch";
16
+ export declare class DashboardRootError extends Error {
17
+ readonly code: DashboardRootErrorCode;
18
+ readonly hint: string;
19
+ constructor(code: DashboardRootErrorCode, message: string, hint: string);
20
+ }
21
+ export type DashboardRootFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
22
+ /**
23
+ * Prove that the dashboard on the selected port serves the same canonical
24
+ * coordination root used to mint the file URL.
25
+ */
26
+ export declare function verifyDashboardRoot(coordRoot: string, port: number, fetchImpl?: DashboardRootFetch): Promise<void>;
15
27
  /**
16
28
  * Mint the local browser URL for a file under the dashboard's coord root.
17
29
  * HTML defaults to the isolated files origin so scripts and relative assets
@@ -1 +1 @@
1
- {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/commands/files.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAK1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;CACzC;AAuCD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAS1F;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CA6DN"}
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/commands/files.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAM1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;CACzC;AAED,MAAM,MAAM,sBAAsB,GAC9B,uBAAuB,GACvB,gCAAgC,GAChC,yBAAyB,CAAC;AAE9B,qBAAa,kBAAmB,SAAQ,KAAK;IAEzC,QAAQ,CAAC,IAAI,EAAE,sBAAsB;IAErC,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAFZ,IAAI,EAAE,sBAAsB,EACrC,OAAO,EAAE,MAAM,EACN,IAAI,EAAE,MAAM;CAKxB;AAMD,MAAM,MAAM,kBAAkB,GAAG,CAC/B,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAC7B,IAAI,CAAC,EAAE,WAAW,KACf,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEvB;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,kBAA0B,GACpC,OAAO,CAAC,IAAI,CAAC,CAmDf;AAuCD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAS1F;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CA0EN"}
@@ -2,8 +2,53 @@ import { realpathSync, statSync } from "node:fs";
2
2
  import path from "node:path";
3
3
  import { resolveCoordRoot } from "../core/agents/coord-client.js";
4
4
  import { DEFAULT_WEB_PORT, resolveWebPort } from "../core/config.js";
5
+ import { coordRootId, localCoordRootIdUrl } from "../lib/coord-root-id.js";
5
6
  import { localFilesOriginUrl, localFileViewerUrl } from "../lib/local-file-url.js";
6
7
  export { FILES_ORIGIN_HOST } from "../lib/local-file-url.js";
8
+ export class DashboardRootError extends Error {
9
+ code;
10
+ hint;
11
+ constructor(code, message, hint) {
12
+ super(message);
13
+ this.code = code;
14
+ this.hint = hint;
15
+ this.name = "DashboardRootError";
16
+ }
17
+ }
18
+ /**
19
+ * Prove that the dashboard on the selected port serves the same canonical
20
+ * coordination root used to mint the file URL.
21
+ */
22
+ export async function verifyDashboardRoot(coordRoot, port, fetchImpl = fetch) {
23
+ const url = localCoordRootIdUrl(port);
24
+ let response;
25
+ try {
26
+ response = await fetchImpl(url, {
27
+ headers: { accept: "application/json" },
28
+ signal: AbortSignal.timeout(5_000),
29
+ });
30
+ }
31
+ catch {
32
+ throw new DashboardRootError("dashboard_unreachable", `dashboard is not reachable at http://localhost:${port}`, "Start the dashboard for this repository, then retry.");
33
+ }
34
+ if (!response.ok) {
35
+ throw new DashboardRootError("dashboard_identity_unavailable", `dashboard at http://localhost:${port} cannot report its repository identity (HTTP ${response.status})`, "Update and restart the dashboard, then retry.");
36
+ }
37
+ let payload;
38
+ try {
39
+ payload = (await response.json());
40
+ }
41
+ catch {
42
+ throw new DashboardRootError("dashboard_identity_unavailable", `dashboard at http://localhost:${port} returned an invalid repository identity`, "Update and restart the dashboard, then retry.");
43
+ }
44
+ if (typeof payload.root_id !== "string") {
45
+ throw new DashboardRootError("dashboard_identity_unavailable", `dashboard at http://localhost:${port} returned an invalid repository identity`, "Update and restart the dashboard, then retry.");
46
+ }
47
+ const expected = coordRootId(coordRoot);
48
+ if (payload.root_id !== expected) {
49
+ throw new DashboardRootError("dashboard_root_mismatch", `dashboard at http://localhost:${port} serves a different repository`, "Stop that dashboard and start this repository's dashboard, then retry.");
50
+ }
51
+ }
7
52
  function isOutsideRoot(relPath) {
8
53
  return relPath === "" || relPath === ".." || relPath.startsWith(`..${path.sep}`);
9
54
  }
@@ -66,7 +111,8 @@ export function registerFilesCommand(program, emit, context) {
66
111
  .option("--coord-root <dir>", "Override the coord root")
67
112
  .option("--raw", "Use the isolated files origin, regardless of extension")
68
113
  .option("--viewer", "Use the dashboard file viewer, regardless of extension")
69
- .action((filePath, opts) => {
114
+ .option("--no-verify", "Mint without checking the running dashboard's repository identity")
115
+ .action(async (filePath, opts) => {
70
116
  if (opts.raw && opts.viewer) {
71
117
  emit.error({
72
118
  code: "conflicting_url_modes",
@@ -99,9 +145,16 @@ export function registerFilesCommand(program, emit, context) {
99
145
  port,
100
146
  mode: opts.raw ? "raw" : opts.viewer ? "viewer" : "auto",
101
147
  });
148
+ if (opts.verify !== false)
149
+ await verifyDashboardRoot(coordRoot, port);
102
150
  emit.text(`${result.url}\n`);
103
151
  }
104
152
  catch (error) {
153
+ if (error instanceof DashboardRootError) {
154
+ emit.error({ code: error.code, message: error.message, hint: error.hint });
155
+ emit.setExitCode(1);
156
+ return;
157
+ }
105
158
  emit.error({
106
159
  code: "invalid_local_file",
107
160
  message: error instanceof Error ? error.message : "invalid local file path",
@@ -1 +1 @@
1
- {"version":3,"file":"governor.d.ts","sourceRoot":"","sources":["../../src/commands/governor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AA6EnD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CA6HjF"}
1
+ {"version":3,"file":"governor.d.ts","sourceRoot":"","sources":["../../src/commands/governor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AA8EnD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CA6HjF"}
@@ -302,6 +302,7 @@ function addServiceOptions(command) {
302
302
  .option("--error-backoff-max-ms <n>", "Maximum service-error backoff (default 300000)")
303
303
  .option("--adapter <name>", "Fallback adapter for agent calls without a specialist")
304
304
  .option("--cwd <dir>", "Working directory for child agents")
305
+ .option("--observe-pressure", "Record observer-only local pressure before each workflow's first real child dispatch")
305
306
  .option("--subscription-only", "Require stored adapter-login billing")
306
307
  .option("--allow-api-billing", "Permit API-key override billing")
307
308
  .option("--policy <file>", "Host policy JSON/JSONC")
@@ -431,6 +432,9 @@ function registerRunCommand(governor, mode, registry, emit) {
431
432
  spawners: registry.spawners(),
432
433
  defaultAdapter: opts.adapter,
433
434
  cwd: opts.cwd,
435
+ diagnosticAdmission: opts.observePressure
436
+ ? { schema_version: 1, mode: "shadow" }
437
+ : undefined,
434
438
  subscriptionOnly: opts.subscriptionOnly === true ? true : workflowSubscriptionOnly(coordRoot),
435
439
  allowApiBilling: opts.allowApiBilling,
436
440
  ...adapterProofInputs(registry.list().map((adapter) => adapter.profile), { versionProbe: probeBinaryVersion }),
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-v3.d.ts","sourceRoot":"","sources":["../../src/commands/ledger-v3.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAmC1E,2DAA2D;AAC3D,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CAsWN"}
1
+ {"version":3,"file":"ledger-v3.d.ts","sourceRoot":"","sources":["../../src/commands/ledger-v3.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAsC1E,2DAA2D;AAC3D,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CAiaN"}
@@ -2,8 +2,8 @@ import { spawnSync } from "node:child_process";
2
2
  import { createHash } from "node:crypto";
3
3
  import { existsSync, mkdirSync, readFileSync } from "node:fs";
4
4
  import { resolve } from "node:path";
5
- import { inventoryLegacyV1Segments, streamLegacyV1Rows, verifyLegacyV1HardFence, writeLegacyV1Canary, } from "../core/events/legacy-storage/index.js";
6
- import { initializeEventLedgerV3, readEventV3ControlState, recoverInvalidEventLedgerV3, sha256V3, } from "../core/events/v3/index.js";
5
+ import { compressSealedLegacyV1Segments, inventoryLegacyV1Segments, streamLegacyV1Rows, verifyLegacyV1HardFence, writeLegacyV1Canary, } from "../core/events/legacy-storage/index.js";
6
+ import { cleanEventV3Archives, initializeEventLedgerV3, inventoryEventV3Archives, readEventV3ControlState, recoverInvalidEventLedgerV3, sha256V3, } from "../core/events/v3/index.js";
7
7
  import { authorizeEventV3SupportReplacement, inventoryEventV3Support, planEventV3SupportReplacement, planEventV3SupportTransaction, readEventV3SupportPackManifest, readEventV3SupportTransaction, streamEventV3SupportPackRecords, unpackEventV3SupportPack, verifyEventV3SupportTransactionShadow, writeEventV3SupportTransactionShadow, } from "../core/events/v3/support-storage/index.js";
8
8
  /** Inspect or initialize the universal V3 event ledger. */
9
9
  export function registerLedgerV3Command(program, emit, context) {
@@ -21,6 +21,38 @@ export function registerLedgerV3Command(program, emit, context) {
21
21
  emitFailure(emit, "ledger_v3_status_failed", error);
22
22
  }
23
23
  });
24
+ const archives = command
25
+ .command("archives")
26
+ .description("Inventory and enforce bounded retention for complete closed V3 epochs");
27
+ archives
28
+ .command("list")
29
+ .description("Show closed epochs, retention classifications, and planned actions")
30
+ .option("--root <path>", "Explicit coordination root")
31
+ .action((options) => {
32
+ try {
33
+ const rows = inventoryEventV3Archives(resolve(options.root ?? coordRoot(context)));
34
+ emit.data({ rows, meta: summarizeArchiveRows(rows) });
35
+ }
36
+ catch (error) {
37
+ emitFailure(emit, "ledger_v3_archive_inventory_failed", error);
38
+ }
39
+ });
40
+ archives
41
+ .command("clean")
42
+ .description("Preview closed-epoch deletion; pass --yes to execute the exact current plan")
43
+ .option("--root <path>", "Explicit coordination root")
44
+ .option("--yes", "Delete only epochs still classified expired or over-budget")
45
+ .action((options) => {
46
+ try {
47
+ const rows = cleanEventV3Archives(resolve(options.root ?? coordRoot(context)), {
48
+ yes: options.yes,
49
+ });
50
+ emit.data({ rows, meta: summarizeArchiveRows(rows) });
51
+ }
52
+ catch (error) {
53
+ emitFailure(emit, "ledger_v3_archive_cleanup_failed", error);
54
+ }
55
+ });
24
56
  command
25
57
  .command("initialize")
26
58
  .description("Create V3 control state, or archive and replace the current V3 epoch")
@@ -279,6 +311,29 @@ export function registerLedgerV3Command(program, emit, context) {
279
311
  emitFailure(emit, "ledger_v1_inventory_failed", error);
280
312
  }
281
313
  });
314
+ command
315
+ .command("legacy-compress")
316
+ .description("Preview verified gzip replacement of sealed non-terminal V1 shards")
317
+ .option("--root <path>", "Explicit coordination root")
318
+ .option("--yes", "Replace only unchanged shards after exact logical-row parity")
319
+ .action(async (options) => {
320
+ try {
321
+ const rows = await compressSealedLegacyV1Segments(resolve(options.root ?? coordRoot(context)), { yes: options.yes });
322
+ emit.data({
323
+ rows,
324
+ meta: {
325
+ total: rows.length,
326
+ would_compress: rows.filter((row) => row.action === "would-compress").length,
327
+ compressed: rows.filter((row) => row.action === "compressed").length,
328
+ bytes_before: rows.reduce((sum, row) => sum + row.bytes_before, 0),
329
+ bytes_after: rows.reduce((sum, row) => sum + (row.bytes_after ?? row.bytes_before), 0),
330
+ },
331
+ });
332
+ }
333
+ catch (error) {
334
+ emitFailure(emit, "ledger_v1_compression_failed", error);
335
+ }
336
+ });
282
337
  command
283
338
  .command("verify-legacy")
284
339
  .description("Stream and validate one loose or manifest-bound gzip legacy segment")
@@ -431,6 +486,20 @@ function sameSortedStrings(left, right) {
431
486
  return (leftSorted.length === rightSorted.length &&
432
487
  leftSorted.every((value, index) => value === rightSorted[index]));
433
488
  }
489
+ function summarizeArchiveRows(rows) {
490
+ const classifications = {};
491
+ for (const row of rows) {
492
+ classifications[row.classification] = (classifications[row.classification] ?? 0) + 1;
493
+ }
494
+ return {
495
+ total: rows.length,
496
+ bytes: rows.reduce((sum, row) => sum + (row.bytes ?? 0), 0),
497
+ classifications,
498
+ would_delete: rows.filter((row) => row.action === "would-delete").length,
499
+ would_delete_bytes: rows.reduce((sum, row) => sum + (row.action === "would-delete" ? (row.bytes ?? 0) : 0), 0),
500
+ deleted: rows.filter((row) => row.action === "deleted").length,
501
+ };
502
+ }
434
503
  function emitFailure(emit, code, error) {
435
504
  emit.error({ code, message: error instanceof Error ? error.message : String(error) });
436
505
  throw error;
@@ -0,0 +1,4 @@
1
+ import type { Command } from "commander";
2
+ import type { EmitContext } from "../commander.js";
3
+ export declare function registerQaRunCommand(program: Command, emit: EmitContext): void;
4
+ //# sourceMappingURL=qa-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-run.d.ts","sourceRoot":"","sources":["../../src/commands/qa-run.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAiBnD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CA+J9E"}
@@ -0,0 +1,141 @@
1
+ // `qa-run <target>`: run the whole page-QA matrix (planner, deterministic
2
+ // gates, interactions, critique, snapshot) in one command. The agent's loop
3
+ // collapses to: build the job, run this, read page-qa-result.json.
4
+ import { readFileSync } from "node:fs";
5
+ import { join, resolve } from "node:path";
6
+ import { QA_RUN_RESULT_FILENAME, runQaMatrix } from "../lib/browser/qa-run.js";
7
+ import { QA_RUN_JOB_SCHEMA_VERSION, validateQaRunJob, } from "../lib/browser/qa-run-contracts.js";
8
+ export function registerQaRunCommand(program, emit) {
9
+ program
10
+ .command("qa-run <target>")
11
+ .description("Run the whole page-QA matrix in one command: QA planner, deterministic " +
12
+ "gates per viewport/theme/state through a bounded process pool, serial " +
13
+ "interaction assertions, manifest-required vision critique, and the QA " +
14
+ "snapshot. Writes page-qa-result.json with a fail-closed verdict.")
15
+ .option("--job <file>", "QA job document (JSON). Validated before any browser starts — secret-bearing " +
16
+ "fields are refused, and the job may widen but never narrow the planner's coverage. " +
17
+ "Absent: a minimal implicit job for <target> is used.")
18
+ .option("--mode <mode>", "signoff persists a QA snapshot on a passing run; review never does.", "signoff")
19
+ .option("--concurrency <n>", "Concurrent deterministic captures (1-8; default 2). Interactions and critique " +
20
+ "always run serially.")
21
+ .option("--allow-metered", "Permit the critique provider's metered-API fallback. Default: subscription-backed " +
22
+ "headless harnesses only — exhaustion becomes an incomplete blocker, never a metered call.")
23
+ .option("--out-dir <dir>", "Artifact + result directory (default: .qa-run/<timestamp> under the current directory).")
24
+ .option("--json", "Print the full QaRunResult JSON to stdout.")
25
+ .addHelpText("after", "\nExit codes: 0 verdict passed · 1 usage or job-validation error · " +
26
+ "2 verdict failed · 4 verdict incomplete.")
27
+ .action(async (target, opts, command) => {
28
+ if (opts.mode !== "signoff" && opts.mode !== "review") {
29
+ emit.error({
30
+ code: "qa_run_invalid_mode",
31
+ message: '--mode must be "signoff" or "review"',
32
+ });
33
+ process.exitCode = 1;
34
+ return;
35
+ }
36
+ const modeExplicit = command.getOptionValueSource("mode") === "cli";
37
+ let jobDocument;
38
+ if (opts.job) {
39
+ let rawText;
40
+ try {
41
+ rawText = readFileSync(opts.job, "utf8");
42
+ }
43
+ catch (err) {
44
+ emit.error({
45
+ code: "qa_run_job_unreadable",
46
+ message: `cannot read --job file ${opts.job}: ${err instanceof Error ? err.message : String(err)}`,
47
+ });
48
+ process.exitCode = 1;
49
+ return;
50
+ }
51
+ let parsed;
52
+ try {
53
+ parsed = JSON.parse(rawText);
54
+ }
55
+ catch (err) {
56
+ emit.error({
57
+ code: "qa_run_job_invalid_json",
58
+ message: `--job file ${opts.job} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,
59
+ });
60
+ process.exitCode = 1;
61
+ return;
62
+ }
63
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
64
+ const raw = parsed;
65
+ // The CLI target argument is authoritative; a job file may omit
66
+ // target and mode. An explicit --mode overrides the job's mode.
67
+ jobDocument = {
68
+ ...raw,
69
+ target,
70
+ ...(raw.mode === undefined || modeExplicit ? { mode: opts.mode } : {}),
71
+ };
72
+ }
73
+ else {
74
+ jobDocument = parsed;
75
+ }
76
+ }
77
+ else {
78
+ jobDocument = { schema_version: QA_RUN_JOB_SCHEMA_VERSION, target, mode: opts.mode };
79
+ }
80
+ // All validation errors print at once, before any browser starts.
81
+ const validation = validateQaRunJob(jobDocument);
82
+ if (!validation.ok) {
83
+ for (const message of validation.errors)
84
+ emit.log(`job: ${message}`, "error");
85
+ emit.error({
86
+ code: "qa_run_invalid_job",
87
+ message: `job validation failed with ${validation.errors.length} error${validation.errors.length === 1 ? "" : "s"}`,
88
+ });
89
+ process.exitCode = 1;
90
+ return;
91
+ }
92
+ const policy = { ...validation.job.policy };
93
+ if (opts.concurrency !== undefined) {
94
+ const n = Number.parseInt(opts.concurrency, 10);
95
+ if (!Number.isInteger(n) || n < 1 || n > 8) {
96
+ emit.error({
97
+ code: "qa_run_invalid_concurrency",
98
+ message: "--concurrency must be an integer between 1 and 8",
99
+ });
100
+ process.exitCode = 1;
101
+ return;
102
+ }
103
+ policy.command_concurrency = n;
104
+ }
105
+ if (opts.allowMetered)
106
+ policy.allow_metered_critique = true;
107
+ const job = { ...validation.job, policy };
108
+ const outDir = resolve(opts.outDir ?? join(".qa-run", new Date().toISOString().replace(/[:.]/g, "-")));
109
+ const cliScript = process.argv[1];
110
+ if (!cliScript) {
111
+ emit.error({
112
+ code: "qa_run_no_cli_script",
113
+ message: "cannot resolve the host CLI script path for child browse invocations",
114
+ });
115
+ process.exitCode = 1;
116
+ return;
117
+ }
118
+ // Children run the same host CLI, so they inherit the host's browse
119
+ // wiring (critique provider, cookie jar, profiles) unchanged.
120
+ const browseArgv = [process.execPath, cliScript, "browse"];
121
+ const result = await runQaMatrix({
122
+ job,
123
+ outDir,
124
+ browseArgv,
125
+ onLog: (message) => emit.log(message, "info"),
126
+ });
127
+ if (opts.json)
128
+ emit.data(result);
129
+ const resultPath = join(outDir, QA_RUN_RESULT_FILENAME);
130
+ for (const blocker of result.blockers) {
131
+ emit.log(`blocker [${blocker.stage}${blocker.context_id ? ` ${blocker.context_id}` : ""}]: ${blocker.reason}`, "warn");
132
+ }
133
+ emit.log(`verdict: ${result.verdict} — ${result.contexts.length} context${result.contexts.length === 1 ? "" : "s"}, ` +
134
+ `${result.commands.length} command${result.commands.length === 1 ? "" : "s"}, ` +
135
+ `${result.blockers.length} blocker${result.blockers.length === 1 ? "" : "s"}; result: ${resultPath}`, result.verdict === "passed" ? "info" : "warn");
136
+ if (result.verdict === "failed")
137
+ process.exitCode = 2;
138
+ else if (result.verdict === "incomplete")
139
+ process.exitCode = 4;
140
+ });
141
+ }
@@ -0,0 +1,4 @@
1
+ import type { Command } from "commander";
2
+ import type { EmitContext, HarneryProgramContext } from "../commander.js";
3
+ export declare function registerResourcesCommand(program: Command, emit: EmitContext, context?: HarneryProgramContext): void;
4
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../../src/commands/resources.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAG1E,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CAgBN"}
@@ -0,0 +1,29 @@
1
+ import { resolve } from "node:path";
2
+ import { sampleResources } from "../core/resources/index.js";
3
+ export function registerResourcesCommand(program, emit, context) {
4
+ const resources = program
5
+ .command("resources")
6
+ .description("Observe local CPU and memory pressure by agent and process tree");
7
+ resources
8
+ .command("snapshot")
9
+ .description("Capture one machine and process-resource snapshot")
10
+ .option("--root <path>", "Explicit coordination root")
11
+ .action((options) => {
12
+ try {
13
+ emit.data(sampleResources(resolve(options.root ?? coordRoot(context))).snapshot);
14
+ }
15
+ catch (error) {
16
+ fail(emit, "resource_snapshot_failed", error);
17
+ }
18
+ });
19
+ }
20
+ function coordRoot(context) {
21
+ return context?.resolveCoordRoot?.() ?? context?.repoRoot ?? process.cwd();
22
+ }
23
+ function fail(emit, code, error) {
24
+ emit.error({
25
+ code,
26
+ message: error instanceof Error ? error.message : String(error),
27
+ });
28
+ emit.setExitCode(1);
29
+ }
@@ -0,0 +1,4 @@
1
+ import type { Command } from "commander";
2
+ import type { EmitContext, HarneryProgramContext } from "../commander.js";
3
+ export declare function registerSupervisorCommand(program: Command, emit: EmitContext, context?: HarneryProgramContext): void;
4
+ //# sourceMappingURL=supervisor.d.ts.map