@sayknow-cli/coding-agent 0.2.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.
Files changed (2036) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +37 -0
  3. package/dist/types/async/index.d.ts +2 -0
  4. package/dist/types/async/job-manager.d.ts +326 -0
  5. package/dist/types/async/support.d.ts +2 -0
  6. package/dist/types/autoresearch/dashboard.d.ts +4 -0
  7. package/dist/types/autoresearch/git.d.ts +36 -0
  8. package/dist/types/autoresearch/helpers.d.ts +24 -0
  9. package/dist/types/autoresearch/index.d.ts +2 -0
  10. package/dist/types/autoresearch/state.d.ts +17 -0
  11. package/dist/types/autoresearch/storage.d.ts +142 -0
  12. package/dist/types/autoresearch/tools/init-experiment.d.ts +31 -0
  13. package/dist/types/autoresearch/tools/log-experiment.d.ts +23 -0
  14. package/dist/types/autoresearch/tools/run-experiment.d.ts +8 -0
  15. package/dist/types/autoresearch/tools/update-notes.d.ts +12 -0
  16. package/dist/types/autoresearch/types.d.ts +154 -0
  17. package/dist/types/capability/context-file.d.ts +17 -0
  18. package/dist/types/capability/extension-module.d.ts +15 -0
  19. package/dist/types/capability/extension.d.ts +28 -0
  20. package/dist/types/capability/fs.d.ts +20 -0
  21. package/dist/types/capability/hook.d.ts +19 -0
  22. package/dist/types/capability/index.d.ts +80 -0
  23. package/dist/types/capability/instruction.d.ts +17 -0
  24. package/dist/types/capability/mcp.d.ts +45 -0
  25. package/dist/types/capability/prompt.d.ts +15 -0
  26. package/dist/types/capability/rule.d.ts +61 -0
  27. package/dist/types/capability/settings.d.ts +15 -0
  28. package/dist/types/capability/skill.d.ts +36 -0
  29. package/dist/types/capability/slash-command.d.ts +17 -0
  30. package/dist/types/capability/ssh.d.ts +23 -0
  31. package/dist/types/capability/system-prompt.d.ts +15 -0
  32. package/dist/types/capability/tool.d.ts +19 -0
  33. package/dist/types/capability/types.d.ts +154 -0
  34. package/dist/types/cli/agents-cli.d.ts +12 -0
  35. package/dist/types/cli/args.d.ts +56 -0
  36. package/dist/types/cli/auth-broker-cli.d.ts +25 -0
  37. package/dist/types/cli/auth-gateway-cli.d.ts +18 -0
  38. package/dist/types/cli/classify-install-target.d.ts +18 -0
  39. package/dist/types/cli/commands/init-xdg.d.ts +1 -0
  40. package/dist/types/cli/config-cli.d.ts +22 -0
  41. package/dist/types/cli/fast-help.d.ts +1 -0
  42. package/dist/types/cli/file-processor.d.ts +11 -0
  43. package/dist/types/cli/grep-cli.d.ts +17 -0
  44. package/dist/types/cli/initial-message.d.ts +17 -0
  45. package/dist/types/cli/list-models.d.ts +36 -0
  46. package/dist/types/cli/plugin-cli.d.ts +32 -0
  47. package/dist/types/cli/read-cli.d.ts +4 -0
  48. package/dist/types/cli/session-picker.d.ts +3 -0
  49. package/dist/types/cli/setup-cli.d.ts +54 -0
  50. package/dist/types/cli/shell-cli.d.ts +8 -0
  51. package/dist/types/cli/skills-cli.d.ts +9 -0
  52. package/dist/types/cli/ssh-cli.d.ts +21 -0
  53. package/dist/types/cli/stats-cli.d.ts +17 -0
  54. package/dist/types/cli/update-cli.d.ts +41 -0
  55. package/dist/types/cli/web-search-cli.d.ts +32 -0
  56. package/dist/types/cli/worktree-cli.d.ts +26 -0
  57. package/dist/types/cli.d.ts +3 -0
  58. package/dist/types/commands/acp.d.ts +12 -0
  59. package/dist/types/commands/agents.d.ts +34 -0
  60. package/dist/types/commands/auth-broker.d.ts +54 -0
  61. package/dist/types/commands/auth-gateway.d.ts +32 -0
  62. package/dist/types/commands/codex-native-hook.d.ts +6 -0
  63. package/dist/types/commands/commit.d.ts +27 -0
  64. package/dist/types/commands/config.d.ts +30 -0
  65. package/dist/types/commands/contribution-prep.d.ts +18 -0
  66. package/dist/types/commands/coordinator.d.ts +19 -0
  67. package/dist/types/commands/deep-interview.d.ts +51 -0
  68. package/dist/types/commands/gc.d.ts +26 -0
  69. package/dist/types/commands/grep.d.ts +42 -0
  70. package/dist/types/commands/harness.d.ts +43 -0
  71. package/dist/types/commands/launch.d.ts +127 -0
  72. package/dist/types/commands/mcp-serve.d.ts +24 -0
  73. package/dist/types/commands/plugin.d.ts +52 -0
  74. package/dist/types/commands/ralplan.d.ts +7 -0
  75. package/dist/types/commands/read.d.ts +15 -0
  76. package/dist/types/commands/rlm.d.ts +10 -0
  77. package/dist/types/commands/session.d.ts +24 -0
  78. package/dist/types/commands/setup.d.ts +105 -0
  79. package/dist/types/commands/shell.d.ts +21 -0
  80. package/dist/types/commands/skills.d.ts +26 -0
  81. package/dist/types/commands/ssh.d.ts +48 -0
  82. package/dist/types/commands/state.d.ts +7 -0
  83. package/dist/types/commands/stats.d.ts +25 -0
  84. package/dist/types/commands/team.d.ts +24 -0
  85. package/dist/types/commands/ultragoal.d.ts +8 -0
  86. package/dist/types/commands/update.d.ts +20 -0
  87. package/dist/types/commands/web-search.d.ts +87 -0
  88. package/dist/types/commands/worktree.d.ts +34 -0
  89. package/dist/types/commit/agentic/agent.d.ts +31 -0
  90. package/dist/types/commit/agentic/fallback.d.ts +5 -0
  91. package/dist/types/commit/agentic/index.d.ts +2 -0
  92. package/dist/types/commit/agentic/state.d.ts +58 -0
  93. package/dist/types/commit/agentic/tools/analyze-file.d.ts +19 -0
  94. package/dist/types/commit/agentic/tools/git-file-diff.d.ts +10 -0
  95. package/dist/types/commit/agentic/tools/git-hunk.d.ts +9 -0
  96. package/dist/types/commit/agentic/tools/git-overview.d.ts +9 -0
  97. package/dist/types/commit/agentic/tools/index.d.ts +16 -0
  98. package/dist/types/commit/agentic/tools/propose-changelog.d.ts +28 -0
  99. package/dist/types/commit/agentic/tools/propose-commit.d.ts +36 -0
  100. package/dist/types/commit/agentic/tools/recent-commits.d.ts +7 -0
  101. package/dist/types/commit/agentic/tools/schemas.d.ts +27 -0
  102. package/dist/types/commit/agentic/tools/split-commit.d.ts +53 -0
  103. package/dist/types/commit/agentic/topo-sort.d.ts +4 -0
  104. package/dist/types/commit/agentic/trivial.d.ts +7 -0
  105. package/dist/types/commit/agentic/validation.d.ts +20 -0
  106. package/dist/types/commit/analysis/conventional.d.ts +22 -0
  107. package/dist/types/commit/analysis/index.d.ts +4 -0
  108. package/dist/types/commit/analysis/scope.d.ts +6 -0
  109. package/dist/types/commit/analysis/summary.d.ts +19 -0
  110. package/dist/types/commit/analysis/validation.d.ts +8 -0
  111. package/dist/types/commit/changelog/detect.d.ts +2 -0
  112. package/dist/types/commit/changelog/generate.d.ts +30 -0
  113. package/dist/types/commit/changelog/index.d.ts +30 -0
  114. package/dist/types/commit/changelog/parse.d.ts +2 -0
  115. package/dist/types/commit/cli.d.ts +3 -0
  116. package/dist/types/commit/git/diff.d.ts +5 -0
  117. package/dist/types/commit/index.d.ts +4 -0
  118. package/dist/types/commit/map-reduce/index.d.ts +28 -0
  119. package/dist/types/commit/map-reduce/map-phase.d.ts +17 -0
  120. package/dist/types/commit/map-reduce/reduce-phase.d.ts +13 -0
  121. package/dist/types/commit/map-reduce/utils.d.ts +2 -0
  122. package/dist/types/commit/message.d.ts +2 -0
  123. package/dist/types/commit/model-selection.d.ts +15 -0
  124. package/dist/types/commit/pipeline.d.ts +5 -0
  125. package/dist/types/commit/shared-llm.d.ts +54 -0
  126. package/dist/types/commit/types.d.ts +78 -0
  127. package/dist/types/commit/utils/exclusions.d.ts +4 -0
  128. package/dist/types/commit/utils.d.ts +20 -0
  129. package/dist/types/config/config-file.d.ts +58 -0
  130. package/dist/types/config/file-lock-gc.d.ts +5 -0
  131. package/dist/types/config/file-lock.d.ts +35 -0
  132. package/dist/types/config/keybindings.d.ts +349 -0
  133. package/dist/types/config/model-equivalence.d.ts +24 -0
  134. package/dist/types/config/model-profile-activation.d.ts +39 -0
  135. package/dist/types/config/model-profiles.d.ts +37 -0
  136. package/dist/types/config/model-registry.d.ts +457 -0
  137. package/dist/types/config/model-resolver.d.ts +217 -0
  138. package/dist/types/config/models-config-schema.d.ts +690 -0
  139. package/dist/types/config/prompt-templates.d.ts +32 -0
  140. package/dist/types/config/resolve-config-value.d.ts +17 -0
  141. package/dist/types/config/settings-schema.d.ts +3581 -0
  142. package/dist/types/config/settings.d.ts +134 -0
  143. package/dist/types/config/skill-settings-defaults.d.ts +14 -0
  144. package/dist/types/config.d.ts +66 -0
  145. package/dist/types/coordinator/contract.d.ts +4 -0
  146. package/dist/types/coordinator-mcp/policy.d.ts +24 -0
  147. package/dist/types/coordinator-mcp/safety.d.ts +26 -0
  148. package/dist/types/coordinator-mcp/server.d.ts +58 -0
  149. package/dist/types/cursor.d.ts +24 -0
  150. package/dist/types/dap/client.d.ts +39 -0
  151. package/dist/types/dap/config.d.ts +6 -0
  152. package/dist/types/dap/index.d.ts +4 -0
  153. package/dist/types/dap/session.d.ts +108 -0
  154. package/dist/types/dap/types.d.ts +524 -0
  155. package/dist/types/debug/crash-diagnostics.d.ts +45 -0
  156. package/dist/types/debug/index.d.ts +15 -0
  157. package/dist/types/debug/log-formatting.d.ts +4 -0
  158. package/dist/types/debug/log-viewer.d.ts +68 -0
  159. package/dist/types/debug/profiler.d.ts +24 -0
  160. package/dist/types/debug/raw-sse-buffer.d.ts +44 -0
  161. package/dist/types/debug/raw-sse.d.ts +16 -0
  162. package/dist/types/debug/report-bundle.d.ts +55 -0
  163. package/dist/types/debug/runtime-gauges.d.ts +6 -0
  164. package/dist/types/debug/system-info.d.ts +26 -0
  165. package/dist/types/deep-interview/render-middleware.d.ts +6 -0
  166. package/dist/types/defaults/skc/extensions/grok-build/index.d.ts +1 -0
  167. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/index.d.ts +1 -0
  168. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/models/catalog.d.ts +25 -0
  169. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/payload/sanitize.d.ts +27 -0
  170. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/provider/billing.d.ts +8 -0
  171. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/provider/register.d.ts +5 -0
  172. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/provider/stream.d.ts +10 -0
  173. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/provider/usage.d.ts +2 -0
  174. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/shared/base-url.d.ts +2 -0
  175. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/shared/errors.d.ts +38 -0
  176. package/dist/types/defaults/skc-defaults.d.ts +57 -0
  177. package/dist/types/defaults/skc-grok-cli.d.ts +5 -0
  178. package/dist/types/discovery/agents-md.d.ts +1 -0
  179. package/dist/types/discovery/agents.d.ts +12 -0
  180. package/dist/types/discovery/builtin.d.ts +1 -0
  181. package/dist/types/discovery/claude-plugins.d.ts +1 -0
  182. package/dist/types/discovery/claude.d.ts +1 -0
  183. package/dist/types/discovery/cline.d.ts +1 -0
  184. package/dist/types/discovery/codex.d.ts +1 -0
  185. package/dist/types/discovery/cursor.d.ts +16 -0
  186. package/dist/types/discovery/gemini.d.ts +1 -0
  187. package/dist/types/discovery/github.d.ts +1 -0
  188. package/dist/types/discovery/helpers.d.ts +271 -0
  189. package/dist/types/discovery/index.d.ts +48 -0
  190. package/dist/types/discovery/mcp-json.d.ts +1 -0
  191. package/dist/types/discovery/opencode.d.ts +1 -0
  192. package/dist/types/discovery/plugin-dir-roots.d.ts +15 -0
  193. package/dist/types/discovery/ssh.d.ts +1 -0
  194. package/dist/types/discovery/substitute-plugin-root.d.ts +5 -0
  195. package/dist/types/discovery/vscode.d.ts +1 -0
  196. package/dist/types/discovery/windsurf.d.ts +13 -0
  197. package/dist/types/edit/apply-patch/index.d.ts +35 -0
  198. package/dist/types/edit/apply-patch/parser.d.ts +34 -0
  199. package/dist/types/edit/diff.d.ts +75 -0
  200. package/dist/types/edit/file-read-cache.d.ts +25 -0
  201. package/dist/types/edit/index.d.ts +58 -0
  202. package/dist/types/edit/modes/apply-patch.d.ts +24 -0
  203. package/dist/types/edit/modes/patch.d.ts +99 -0
  204. package/dist/types/edit/modes/replace.d.ts +149 -0
  205. package/dist/types/edit/normalize.d.ts +43 -0
  206. package/dist/types/edit/notebook.d.ts +26 -0
  207. package/dist/types/edit/read-file.d.ts +8 -0
  208. package/dist/types/edit/renderer.d.ts +110 -0
  209. package/dist/types/edit/streaming.d.ts +66 -0
  210. package/dist/types/eval/backend.d.ts +40 -0
  211. package/dist/types/eval/index.d.ts +4 -0
  212. package/dist/types/eval/js/context-manager.d.ts +27 -0
  213. package/dist/types/eval/js/executor.d.ts +29 -0
  214. package/dist/types/eval/js/index.d.ts +10 -0
  215. package/dist/types/eval/js/shared/helpers.d.ts +38 -0
  216. package/dist/types/eval/js/shared/indirect-eval.d.ts +14 -0
  217. package/dist/types/eval/js/shared/prelude.d.ts +1 -0
  218. package/dist/types/eval/js/shared/rewrite-imports.d.ts +6 -0
  219. package/dist/types/eval/js/shared/runtime.d.ts +47 -0
  220. package/dist/types/eval/js/shared/types.d.ts +24 -0
  221. package/dist/types/eval/js/tool-bridge.d.ts +18 -0
  222. package/dist/types/eval/js/worker-core.d.ts +5 -0
  223. package/dist/types/eval/js/worker-entry.d.ts +1 -0
  224. package/dist/types/eval/js/worker-protocol.d.ts +77 -0
  225. package/dist/types/eval/py/display.d.ts +25 -0
  226. package/dist/types/eval/py/executor.d.ts +88 -0
  227. package/dist/types/eval/py/index.d.ts +10 -0
  228. package/dist/types/eval/py/kernel.d.ts +65 -0
  229. package/dist/types/eval/py/prelude.d.ts +1 -0
  230. package/dist/types/eval/py/runtime.d.ts +29 -0
  231. package/dist/types/eval/py/tool-bridge.d.ts +20 -0
  232. package/dist/types/eval/types.d.ts +52 -0
  233. package/dist/types/exa/factory.d.ts +13 -0
  234. package/dist/types/exa/index.d.ts +20 -0
  235. package/dist/types/exa/mcp-client.d.ts +45 -0
  236. package/dist/types/exa/render.d.ts +19 -0
  237. package/dist/types/exa/researcher.d.ts +9 -0
  238. package/dist/types/exa/search.d.ts +9 -0
  239. package/dist/types/exa/types.d.ts +155 -0
  240. package/dist/types/exa/websets.d.ts +9 -0
  241. package/dist/types/exec/bash-executor.d.ts +64 -0
  242. package/dist/types/exec/exec.d.ts +25 -0
  243. package/dist/types/exec/idle-timeout-watchdog.d.ts +18 -0
  244. package/dist/types/exec/non-interactive-env.d.ts +1 -0
  245. package/dist/types/export/custom-share.d.ts +20 -0
  246. package/dist/types/export/html/index.d.ts +10 -0
  247. package/dist/types/export/html/template.generated.d.ts +1 -0
  248. package/dist/types/export/html/template.macro.d.ts +5 -0
  249. package/dist/types/export/ttsr.d.ts +44 -0
  250. package/dist/types/extensibility/custom-commands/bundled/ci-green/index.d.ts +9 -0
  251. package/dist/types/extensibility/custom-commands/bundled/review/index.d.ts +10 -0
  252. package/dist/types/extensibility/custom-commands/index.d.ts +2 -0
  253. package/dist/types/extensibility/custom-commands/loader.d.ts +29 -0
  254. package/dist/types/extensibility/custom-commands/types.d.ts +106 -0
  255. package/dist/types/extensibility/custom-tools/index.d.ts +6 -0
  256. package/dist/types/extensibility/custom-tools/loader.d.ts +69 -0
  257. package/dist/types/extensibility/custom-tools/types.d.ts +229 -0
  258. package/dist/types/extensibility/custom-tools/wrapper.d.ts +24 -0
  259. package/dist/types/extensibility/extensions/compact-handler.d.ts +26 -0
  260. package/dist/types/extensibility/extensions/get-commands-handler.d.ts +29 -0
  261. package/dist/types/extensibility/extensions/index.d.ts +9 -0
  262. package/dist/types/extensibility/extensions/loader.d.ts +43 -0
  263. package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +35 -0
  264. package/dist/types/extensibility/extensions/runner.d.ts +134 -0
  265. package/dist/types/extensibility/extensions/types.d.ts +891 -0
  266. package/dist/types/extensibility/extensions/wrapper.d.ts +55 -0
  267. package/dist/types/extensibility/hooks/index.d.ts +5 -0
  268. package/dist/types/extensibility/hooks/loader.d.ts +89 -0
  269. package/dist/types/extensibility/hooks/runner.d.ts +126 -0
  270. package/dist/types/extensibility/hooks/tool-wrapper.d.ts +25 -0
  271. package/dist/types/extensibility/hooks/types.d.ts +431 -0
  272. package/dist/types/extensibility/plugins/doctor.d.ts +3 -0
  273. package/dist/types/extensibility/plugins/git-url.d.ts +34 -0
  274. package/dist/types/extensibility/plugins/index.d.ts +7 -0
  275. package/dist/types/extensibility/plugins/installer.d.ts +5 -0
  276. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
  277. package/dist/types/extensibility/plugins/loader.d.ts +31 -0
  278. package/dist/types/extensibility/plugins/manager.d.ts +65 -0
  279. package/dist/types/extensibility/plugins/marketplace/cache.d.ts +41 -0
  280. package/dist/types/extensibility/plugins/marketplace/fetcher.d.ts +48 -0
  281. package/dist/types/extensibility/plugins/marketplace/index.d.ts +6 -0
  282. package/dist/types/extensibility/plugins/marketplace/manager.d.ts +57 -0
  283. package/dist/types/extensibility/plugins/marketplace/registry.d.ts +34 -0
  284. package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +28 -0
  285. package/dist/types/extensibility/plugins/marketplace/types.d.ts +130 -0
  286. package/dist/types/extensibility/plugins/parser.d.ts +52 -0
  287. package/dist/types/extensibility/plugins/types.d.ts +149 -0
  288. package/dist/types/extensibility/shared-events.d.ts +280 -0
  289. package/dist/types/extensibility/skc-plugins/activation.d.ts +14 -0
  290. package/dist/types/extensibility/skc-plugins/index.d.ts +9 -0
  291. package/dist/types/extensibility/skc-plugins/injection.d.ts +31 -0
  292. package/dist/types/extensibility/skc-plugins/loader.d.ts +3 -0
  293. package/dist/types/extensibility/skc-plugins/paths.d.ts +8 -0
  294. package/dist/types/extensibility/skc-plugins/schema.d.ts +3 -0
  295. package/dist/types/extensibility/skc-plugins/state.d.ts +9 -0
  296. package/dist/types/extensibility/skc-plugins/tools.d.ts +8 -0
  297. package/dist/types/extensibility/skc-plugins/types.d.ts +64 -0
  298. package/dist/types/extensibility/skc-plugins/validation.d.ts +4 -0
  299. package/dist/types/extensibility/skills.d.ts +82 -0
  300. package/dist/types/extensibility/slash-commands.d.ts +48 -0
  301. package/dist/types/extensibility/tool-proxy.d.ts +4 -0
  302. package/dist/types/extensibility/typebox.d.ts +155 -0
  303. package/dist/types/extensibility/utils.d.ts +12 -0
  304. package/dist/types/goals/index.d.ts +3 -0
  305. package/dist/types/goals/runtime.d.ts +62 -0
  306. package/dist/types/goals/state.d.ts +32 -0
  307. package/dist/types/goals/tools/goal-tool.d.ts +62 -0
  308. package/dist/types/harness-control-plane/classifier.d.ts +13 -0
  309. package/dist/types/harness-control-plane/control-endpoint.d.ts +31 -0
  310. package/dist/types/harness-control-plane/finalize.d.ts +60 -0
  311. package/dist/types/harness-control-plane/gc-adapter.d.ts +3 -0
  312. package/dist/types/harness-control-plane/operate.d.ts +35 -0
  313. package/dist/types/harness-control-plane/owner.d.ts +53 -0
  314. package/dist/types/harness-control-plane/phase-rollup.d.ts +23 -0
  315. package/dist/types/harness-control-plane/preserve.d.ts +19 -0
  316. package/dist/types/harness-control-plane/receipt-ingest.d.ts +19 -0
  317. package/dist/types/harness-control-plane/receipt-spool.d.ts +19 -0
  318. package/dist/types/harness-control-plane/receipts.d.ts +149 -0
  319. package/dist/types/harness-control-plane/rpc-adapter.d.ts +69 -0
  320. package/dist/types/harness-control-plane/seams.d.ts +21 -0
  321. package/dist/types/harness-control-plane/session-lease.d.ts +65 -0
  322. package/dist/types/harness-control-plane/state-machine.d.ts +24 -0
  323. package/dist/types/harness-control-plane/storage.d.ts +80 -0
  324. package/dist/types/harness-control-plane/types.d.ts +187 -0
  325. package/dist/types/hashline/anchors.d.ts +20 -0
  326. package/dist/types/hashline/apply.d.ts +14 -0
  327. package/dist/types/hashline/constants.d.ts +19 -0
  328. package/dist/types/hashline/diff-preview.d.ts +2 -0
  329. package/dist/types/hashline/diff.d.ts +17 -0
  330. package/dist/types/hashline/execute.d.ts +4 -0
  331. package/dist/types/hashline/hash.d.ts +123 -0
  332. package/dist/types/hashline/index.d.ts +13 -0
  333. package/dist/types/hashline/input.d.ts +11 -0
  334. package/dist/types/hashline/parser.d.ts +7 -0
  335. package/dist/types/hashline/prefixes.d.ts +7 -0
  336. package/dist/types/hashline/recovery.d.ts +27 -0
  337. package/dist/types/hashline/stream.d.ts +2 -0
  338. package/dist/types/hashline/types.d.ts +77 -0
  339. package/dist/types/hindsight/backend.d.ts +13 -0
  340. package/dist/types/hindsight/bank.d.ts +54 -0
  341. package/dist/types/hindsight/client.d.ts +224 -0
  342. package/dist/types/hindsight/config.d.ts +51 -0
  343. package/dist/types/hindsight/content.d.ts +70 -0
  344. package/dist/types/hindsight/index.d.ts +8 -0
  345. package/dist/types/hindsight/mental-models.d.ts +125 -0
  346. package/dist/types/hindsight/state.d.ts +99 -0
  347. package/dist/types/hindsight/transcript.d.ts +28 -0
  348. package/dist/types/hooks/codex-native-hooks-config.d.ts +29 -0
  349. package/dist/types/hooks/native-skill-hook.d.ts +16 -0
  350. package/dist/types/hooks/skill-keywords.d.ts +18 -0
  351. package/dist/types/hooks/skill-state.d.ts +85 -0
  352. package/dist/types/i18n/index.d.ts +38 -0
  353. package/dist/types/i18n/messages/de.d.ts +2 -0
  354. package/dist/types/i18n/messages/de.messages.d.ts +1 -0
  355. package/dist/types/i18n/messages/de.settings.d.ts +1 -0
  356. package/dist/types/i18n/messages/en.d.ts +66 -0
  357. package/dist/types/i18n/messages/es.d.ts +2 -0
  358. package/dist/types/i18n/messages/es.messages.d.ts +1 -0
  359. package/dist/types/i18n/messages/es.settings.d.ts +1 -0
  360. package/dist/types/i18n/messages/fr.d.ts +2 -0
  361. package/dist/types/i18n/messages/fr.messages.d.ts +1 -0
  362. package/dist/types/i18n/messages/fr.settings.d.ts +1 -0
  363. package/dist/types/i18n/messages/ja.d.ts +2 -0
  364. package/dist/types/i18n/messages/ja.messages.d.ts +1 -0
  365. package/dist/types/i18n/messages/ja.settings.d.ts +1 -0
  366. package/dist/types/i18n/messages/ko.d.ts +2 -0
  367. package/dist/types/i18n/messages/ko.messages.d.ts +1 -0
  368. package/dist/types/i18n/messages/ko.settings.d.ts +1 -0
  369. package/dist/types/i18n/messages/zh.d.ts +2 -0
  370. package/dist/types/i18n/messages/zh.messages.d.ts +1 -0
  371. package/dist/types/i18n/messages/zh.settings.d.ts +1 -0
  372. package/dist/types/index.d.ts +33 -0
  373. package/dist/types/internal-urls/agent-protocol.d.ts +12 -0
  374. package/dist/types/internal-urls/artifact-protocol.d.ts +6 -0
  375. package/dist/types/internal-urls/docs-index.generated.d.ts +2 -0
  376. package/dist/types/internal-urls/index.d.ts +20 -0
  377. package/dist/types/internal-urls/issue-pr-protocol.d.ts +17 -0
  378. package/dist/types/internal-urls/json-query.d.ts +30 -0
  379. package/dist/types/internal-urls/local-protocol.d.ts +39 -0
  380. package/dist/types/internal-urls/mcp-protocol.d.ts +12 -0
  381. package/dist/types/internal-urls/memory-protocol.d.ts +23 -0
  382. package/dist/types/internal-urls/parse.d.ts +19 -0
  383. package/dist/types/internal-urls/registry-helpers.d.ts +11 -0
  384. package/dist/types/internal-urls/router.d.ts +14 -0
  385. package/dist/types/internal-urls/rule-protocol.d.ts +6 -0
  386. package/dist/types/internal-urls/skc-protocol.d.ts +12 -0
  387. package/dist/types/internal-urls/skill-protocol.d.ts +13 -0
  388. package/dist/types/internal-urls/types.d.ts +109 -0
  389. package/dist/types/lsp/client.d.ts +66 -0
  390. package/dist/types/lsp/clients/biome-client.d.ts +16 -0
  391. package/dist/types/lsp/clients/index.d.ts +19 -0
  392. package/dist/types/lsp/clients/lsp-linter-client.d.ts +16 -0
  393. package/dist/types/lsp/clients/swiftlint-client.d.ts +20 -0
  394. package/dist/types/lsp/config.d.ts +65 -0
  395. package/dist/types/lsp/edits.d.ts +23 -0
  396. package/dist/types/lsp/index.d.ts +130 -0
  397. package/dist/types/lsp/lspmux.d.ts +58 -0
  398. package/dist/types/lsp/render.d.ts +32 -0
  399. package/dist/types/lsp/startup-events.d.ts +11 -0
  400. package/dist/types/lsp/types.d.ts +304 -0
  401. package/dist/types/lsp/utils.d.ts +108 -0
  402. package/dist/types/main.d.ts +70 -0
  403. package/dist/types/memories/index.d.ts +28 -0
  404. package/dist/types/memories/storage.d.ts +110 -0
  405. package/dist/types/memory-backend/index.d.ts +4 -0
  406. package/dist/types/memory-backend/local-backend.d.ts +9 -0
  407. package/dist/types/memory-backend/off-backend.d.ts +7 -0
  408. package/dist/types/memory-backend/resolve.d.ts +15 -0
  409. package/dist/types/memory-backend/types.d.ts +61 -0
  410. package/dist/types/modes/acp/acp-agent.d.ts +61 -0
  411. package/dist/types/modes/acp/acp-client-bridge.d.ts +9 -0
  412. package/dist/types/modes/acp/acp-event-mapper.d.ts +34 -0
  413. package/dist/types/modes/acp/acp-mode.d.ts +5 -0
  414. package/dist/types/modes/acp/index.d.ts +2 -0
  415. package/dist/types/modes/acp/terminal-auth.d.ts +6 -0
  416. package/dist/types/modes/bridge/auth.d.ts +12 -0
  417. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +9 -0
  418. package/dist/types/modes/bridge/bridge-mode.d.ts +47 -0
  419. package/dist/types/modes/bridge/bridge-ui-context.d.ts +88 -0
  420. package/dist/types/modes/bridge/event-stream.d.ts +8 -0
  421. package/dist/types/modes/components/agent-dashboard.d.ts +21 -0
  422. package/dist/types/modes/components/assistant-message.d.ts +16 -0
  423. package/dist/types/modes/components/bash-execution.d.ts +29 -0
  424. package/dist/types/modes/components/bordered-loader.d.ts +11 -0
  425. package/dist/types/modes/components/branch-summary-message.d.ts +13 -0
  426. package/dist/types/modes/components/btw-panel.d.ts +16 -0
  427. package/dist/types/modes/components/compaction-summary-message.d.ts +13 -0
  428. package/dist/types/modes/components/countdown-timer.d.ts +14 -0
  429. package/dist/types/modes/components/custom-editor.d.ts +62 -0
  430. package/dist/types/modes/components/custom-message.d.ts +15 -0
  431. package/dist/types/modes/components/custom-model-preset-wizard.d.ts +12 -0
  432. package/dist/types/modes/components/custom-provider-wizard.d.ts +10 -0
  433. package/dist/types/modes/components/diff.d.ts +11 -0
  434. package/dist/types/modes/components/dynamic-border.d.ts +14 -0
  435. package/dist/types/modes/components/eval-execution.d.ts +23 -0
  436. package/dist/types/modes/components/execution-shared.d.ts +46 -0
  437. package/dist/types/modes/components/extensions/extension-dashboard.d.ts +26 -0
  438. package/dist/types/modes/components/extensions/extension-list.d.ts +39 -0
  439. package/dist/types/modes/components/extensions/index.d.ts +8 -0
  440. package/dist/types/modes/components/extensions/inspector-panel.d.ts +8 -0
  441. package/dist/types/modes/components/extensions/state-manager.d.ts +50 -0
  442. package/dist/types/modes/components/extensions/types.d.ts +151 -0
  443. package/dist/types/modes/components/footer.d.ts +30 -0
  444. package/dist/types/modes/components/history-search.d.ts +7 -0
  445. package/dist/types/modes/components/hook-editor.d.ts +18 -0
  446. package/dist/types/modes/components/hook-input.d.ts +15 -0
  447. package/dist/types/modes/components/hook-message.d.ts +15 -0
  448. package/dist/types/modes/components/hook-selector.d.ts +48 -0
  449. package/dist/types/modes/components/index.d.ts +35 -0
  450. package/dist/types/modes/components/jobs-overlay-model.d.ts +31 -0
  451. package/dist/types/modes/components/jobs-overlay.d.ts +30 -0
  452. package/dist/types/modes/components/keybinding-hints.d.ts +40 -0
  453. package/dist/types/modes/components/login-dialog.d.ts +32 -0
  454. package/dist/types/modes/components/message-frame.d.ts +42 -0
  455. package/dist/types/modes/components/model-selector.d.ts +46 -0
  456. package/dist/types/modes/components/oauth-selector.d.ts +15 -0
  457. package/dist/types/modes/components/plugin-selector.d.ts +26 -0
  458. package/dist/types/modes/components/plugin-settings.d.ts +66 -0
  459. package/dist/types/modes/components/provider-onboarding-selector.d.ts +7 -0
  460. package/dist/types/modes/components/queue-mode-selector.d.ts +9 -0
  461. package/dist/types/modes/components/read-tool-group.d.ts +30 -0
  462. package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +26 -0
  463. package/dist/types/modes/components/session-observer-overlay.d.ts +11 -0
  464. package/dist/types/modes/components/session-selector.d.ts +30 -0
  465. package/dist/types/modes/components/settings-defs.d.ts +50 -0
  466. package/dist/types/modes/components/settings-selector.d.ts +56 -0
  467. package/dist/types/modes/components/show-images-selector.d.ts +9 -0
  468. package/dist/types/modes/components/skill-hud/render.d.ts +2 -0
  469. package/dist/types/modes/components/skill-message.d.ts +9 -0
  470. package/dist/types/modes/components/status-line/context-thresholds.d.ts +4 -0
  471. package/dist/types/modes/components/status-line/git-utils.d.ts +22 -0
  472. package/dist/types/modes/components/status-line/index.d.ts +4 -0
  473. package/dist/types/modes/components/status-line/presets.d.ts +3 -0
  474. package/dist/types/modes/components/status-line/segments.d.ts +5 -0
  475. package/dist/types/modes/components/status-line/separators.d.ts +3 -0
  476. package/dist/types/modes/components/status-line/token-rate.d.ts +10 -0
  477. package/dist/types/modes/components/status-line/types.d.ts +79 -0
  478. package/dist/types/modes/components/status-line.d.ts +82 -0
  479. package/dist/types/modes/components/theme-selector.d.ts +10 -0
  480. package/dist/types/modes/components/thinking-selector.d.ts +10 -0
  481. package/dist/types/modes/components/todo-reminder.d.ts +13 -0
  482. package/dist/types/modes/components/tool-execution.d.ts +54 -0
  483. package/dist/types/modes/components/tree-selector.d.ts +31 -0
  484. package/dist/types/modes/components/ttsr-notification.d.ts +13 -0
  485. package/dist/types/modes/components/user-message-selector.d.ts +28 -0
  486. package/dist/types/modes/components/user-message.d.ts +7 -0
  487. package/dist/types/modes/components/visual-truncate.d.ts +19 -0
  488. package/dist/types/modes/components/welcome.d.ts +35 -0
  489. package/dist/types/modes/controllers/btw-controller.d.ts +10 -0
  490. package/dist/types/modes/controllers/command-controller-shared.d.ts +47 -0
  491. package/dist/types/modes/controllers/command-controller.d.ts +38 -0
  492. package/dist/types/modes/controllers/event-controller.d.ts +12 -0
  493. package/dist/types/modes/controllers/extension-ui-controller.d.ts +80 -0
  494. package/dist/types/modes/controllers/input-controller.d.ts +39 -0
  495. package/dist/types/modes/controllers/runtime-mcp-command-controller.d.ts +10 -0
  496. package/dist/types/modes/controllers/selector-controller.d.ts +57 -0
  497. package/dist/types/modes/controllers/ssh-command-controller.d.ts +10 -0
  498. package/dist/types/modes/controllers/todo-command-controller.d.ts +7 -0
  499. package/dist/types/modes/emoji-autocomplete.d.ts +16 -0
  500. package/dist/types/modes/index.d.ts +10 -0
  501. package/dist/types/modes/interactive-mode.d.ts +266 -0
  502. package/dist/types/modes/jobs-observer.d.ts +57 -0
  503. package/dist/types/modes/oauth-manual-input.d.ts +8 -0
  504. package/dist/types/modes/print-mode.d.ts +33 -0
  505. package/dist/types/modes/prompt-action-autocomplete.d.ts +46 -0
  506. package/dist/types/modes/rpc/host-tools.d.ts +1 -0
  507. package/dist/types/modes/rpc/host-uris.d.ts +1 -0
  508. package/dist/types/modes/rpc/rpc-client.d.ts +288 -0
  509. package/dist/types/modes/rpc/rpc-mode.d.ts +87 -0
  510. package/dist/types/modes/rpc/rpc-socket-security.d.ts +7 -0
  511. package/dist/types/modes/rpc/rpc-types.d.ts +779 -0
  512. package/dist/types/modes/runtime-init.d.ts +21 -0
  513. package/dist/types/modes/session-observer-registry.d.ts +26 -0
  514. package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +57 -0
  515. package/dist/types/modes/shared/agent-wire/command-contract.d.ts +18 -0
  516. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +37 -0
  517. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +2 -0
  518. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +60 -0
  519. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +84 -0
  520. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +38 -0
  521. package/dist/types/modes/shared/agent-wire/event-observation.d.ts +37 -0
  522. package/dist/types/modes/shared/agent-wire/handshake.d.ts +56 -0
  523. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +16 -0
  524. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +17 -0
  525. package/dist/types/modes/shared/agent-wire/protocol.d.ts +25 -0
  526. package/dist/types/modes/shared/agent-wire/responses.d.ts +4 -0
  527. package/dist/types/modes/shared/agent-wire/scopes.d.ts +18 -0
  528. package/dist/types/modes/shared/agent-wire/session-registry.d.ts +25 -0
  529. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +42 -0
  530. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +27 -0
  531. package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +29 -0
  532. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +68 -0
  533. package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +161 -0
  534. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +72 -0
  535. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +114 -0
  536. package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +39 -0
  537. package/dist/types/modes/shared.d.ts +15 -0
  538. package/dist/types/modes/theme/defaults/index.d.ts +553 -0
  539. package/dist/types/modes/theme/mermaid-cache.d.ts +9 -0
  540. package/dist/types/modes/theme/shimmer.d.ts +38 -0
  541. package/dist/types/modes/theme/theme.d.ts +275 -0
  542. package/dist/types/modes/types.d.ts +278 -0
  543. package/dist/types/modes/utils/abort-message.d.ts +4 -0
  544. package/dist/types/modes/utils/context-usage.d.ts +51 -0
  545. package/dist/types/modes/utils/hotkeys-markdown.d.ts +5 -0
  546. package/dist/types/modes/utils/keybinding-matchers.d.ts +10 -0
  547. package/dist/types/modes/utils/tools-markdown.d.ts +5 -0
  548. package/dist/types/modes/utils/ui-helpers.d.ts +53 -0
  549. package/dist/types/plan-mode/approved-plan.d.ts +49 -0
  550. package/dist/types/plan-mode/state.d.ts +6 -0
  551. package/dist/types/registry/agent-registry.d.ts +62 -0
  552. package/dist/types/reminders/star-reminder.d.ts +115 -0
  553. package/dist/types/rlm/artifacts.d.ts +9 -0
  554. package/dist/types/rlm/complete-research-tool.d.ts +35 -0
  555. package/dist/types/rlm/data-context.d.ts +6 -0
  556. package/dist/types/rlm/index.d.ts +35 -0
  557. package/dist/types/rlm/notebook.d.ts +12 -0
  558. package/dist/types/rlm/preset.d.ts +23 -0
  559. package/dist/types/rlm/python-tool.d.ts +16 -0
  560. package/dist/types/rlm/report.d.ts +14 -0
  561. package/dist/types/rlm/types.d.ts +37 -0
  562. package/dist/types/runtime/process-lifecycle.d.ts +108 -0
  563. package/dist/types/runtime-mcp/client.d.ts +74 -0
  564. package/dist/types/runtime-mcp/config-writer.d.ts +53 -0
  565. package/dist/types/runtime-mcp/config.d.ts +75 -0
  566. package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +7 -0
  567. package/dist/types/runtime-mcp/index.d.ts +18 -0
  568. package/dist/types/runtime-mcp/json-rpc.d.ts +22 -0
  569. package/dist/types/runtime-mcp/loader.d.ts +43 -0
  570. package/dist/types/runtime-mcp/manager.d.ts +193 -0
  571. package/dist/types/runtime-mcp/oauth-discovery.d.ts +40 -0
  572. package/dist/types/runtime-mcp/oauth-flow.d.ts +59 -0
  573. package/dist/types/runtime-mcp/render.d.ts +25 -0
  574. package/dist/types/runtime-mcp/smithery-auth.d.ts +16 -0
  575. package/dist/types/runtime-mcp/smithery-connect.d.ts +38 -0
  576. package/dist/types/runtime-mcp/smithery-registry.d.ts +51 -0
  577. package/dist/types/runtime-mcp/tool-bridge.d.ts +86 -0
  578. package/dist/types/runtime-mcp/tool-cache.d.ts +8 -0
  579. package/dist/types/runtime-mcp/transports/http.d.ts +36 -0
  580. package/dist/types/runtime-mcp/transports/index.d.ts +5 -0
  581. package/dist/types/runtime-mcp/transports/stdio.d.ts +29 -0
  582. package/dist/types/runtime-mcp/types.d.ts +335 -0
  583. package/dist/types/sdk.d.ts +243 -0
  584. package/dist/types/secrets/index.d.ts +9 -0
  585. package/dist/types/secrets/obfuscator.d.ts +23 -0
  586. package/dist/types/secrets/regex.d.ts +2 -0
  587. package/dist/types/session/agent-session.d.ts +1078 -0
  588. package/dist/types/session/agent-storage.d.ts +100 -0
  589. package/dist/types/session/artifacts.d.ts +64 -0
  590. package/dist/types/session/auth-broker-config.d.ts +13 -0
  591. package/dist/types/session/auth-storage.d.ts +6 -0
  592. package/dist/types/session/blob-store.d.ts +135 -0
  593. package/dist/types/session/client-bridge.d.ts +88 -0
  594. package/dist/types/session/contribution-prep.d.ts +47 -0
  595. package/dist/types/session/history-storage.d.ts +16 -0
  596. package/dist/types/session/messages.d.ts +165 -0
  597. package/dist/types/session/session-dump-format.d.ts +22 -0
  598. package/dist/types/session/session-manager.d.ts +587 -0
  599. package/dist/types/session/session-storage.d.ts +88 -0
  600. package/dist/types/session/streaming-output.d.ts +209 -0
  601. package/dist/types/session/tool-choice-queue.d.ts +84 -0
  602. package/dist/types/session/yield-queue.d.ts +24 -0
  603. package/dist/types/setup/credential-import.d.ts +79 -0
  604. package/dist/types/setup/hermes-setup.d.ts +78 -0
  605. package/dist/types/setup/model-onboarding-guidance.d.ts +9 -0
  606. package/dist/types/setup/provider-onboarding.d.ts +52 -0
  607. package/dist/types/skc-runtime/cli-write-receipt.d.ts +24 -0
  608. package/dist/types/skc-runtime/deep-interview-recorder.d.ts +103 -0
  609. package/dist/types/skc-runtime/deep-interview-runtime.d.ts +36 -0
  610. package/dist/types/skc-runtime/deep-interview-state.d.ts +112 -0
  611. package/dist/types/skc-runtime/gc-render.d.ts +6 -0
  612. package/dist/types/skc-runtime/gc-runtime.d.ts +134 -0
  613. package/dist/types/skc-runtime/goal-mode-request.d.ts +53 -0
  614. package/dist/types/skc-runtime/launch-tmux.d.ts +76 -0
  615. package/dist/types/skc-runtime/launch-worktree.d.ts +46 -0
  616. package/dist/types/skc-runtime/ledger-event-renderer.d.ts +68 -0
  617. package/dist/types/skc-runtime/ralplan-runtime.d.ts +25 -0
  618. package/dist/types/skc-runtime/restricted-role-agent-bash.d.ts +2 -0
  619. package/dist/types/skc-runtime/session-state-sidecar.d.ts +27 -0
  620. package/dist/types/skc-runtime/state-graph.d.ts +4 -0
  621. package/dist/types/skc-runtime/state-migrations.d.ts +33 -0
  622. package/dist/types/skc-runtime/state-renderer.d.ts +65 -0
  623. package/dist/types/skc-runtime/state-runtime.d.ts +37 -0
  624. package/dist/types/skc-runtime/state-schema.d.ts +317 -0
  625. package/dist/types/skc-runtime/state-validation.d.ts +6 -0
  626. package/dist/types/skc-runtime/state-writer.d.ts +209 -0
  627. package/dist/types/skc-runtime/team-gc.d.ts +7 -0
  628. package/dist/types/skc-runtime/team-runtime.d.ts +353 -0
  629. package/dist/types/skc-runtime/tmux-common.d.ts +61 -0
  630. package/dist/types/skc-runtime/tmux-gc.d.ts +7 -0
  631. package/dist/types/skc-runtime/tmux-sessions.d.ts +40 -0
  632. package/dist/types/skc-runtime/ultragoal-guard.d.ts +36 -0
  633. package/dist/types/skc-runtime/ultragoal-runtime.d.ts +210 -0
  634. package/dist/types/skc-runtime/workflow-command-ref.d.ts +43 -0
  635. package/dist/types/skc-runtime/workflow-manifest.d.ts +54 -0
  636. package/dist/types/skill-state/active-state.d.ts +114 -0
  637. package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +33 -0
  638. package/dist/types/skill-state/initial-phase.d.ts +12 -0
  639. package/dist/types/skill-state/workflow-hud.d.ts +81 -0
  640. package/dist/types/skill-state/workflow-state-contract.d.ts +57 -0
  641. package/dist/types/skill-state/workflow-state-version.d.ts +3 -0
  642. package/dist/types/slash-commands/acp-builtins.d.ts +18 -0
  643. package/dist/types/slash-commands/builtin-registry.d.ts +24 -0
  644. package/dist/types/slash-commands/helpers/context-report.d.ts +7 -0
  645. package/dist/types/slash-commands/helpers/fast-status-report.d.ts +76 -0
  646. package/dist/types/slash-commands/helpers/format.d.ts +10 -0
  647. package/dist/types/slash-commands/helpers/mcp.d.ts +3 -0
  648. package/dist/types/slash-commands/helpers/parse.d.ts +33 -0
  649. package/dist/types/slash-commands/helpers/ssh.d.ts +3 -0
  650. package/dist/types/slash-commands/helpers/todo.d.ts +3 -0
  651. package/dist/types/slash-commands/helpers/usage-report.d.ts +7 -0
  652. package/dist/types/slash-commands/types.d.ts +118 -0
  653. package/dist/types/ssh/config-writer.d.ts +49 -0
  654. package/dist/types/ssh/connection-manager.d.ts +33 -0
  655. package/dist/types/ssh/ssh-executor.d.ts +37 -0
  656. package/dist/types/ssh/sshfs-mount.d.ts +6 -0
  657. package/dist/types/ssh/utils.d.ts +2 -0
  658. package/dist/types/stt/downloader.d.ts +9 -0
  659. package/dist/types/stt/index.d.ts +3 -0
  660. package/dist/types/stt/recorder.d.ts +13 -0
  661. package/dist/types/stt/setup.d.ts +18 -0
  662. package/dist/types/stt/stt-controller.d.ts +16 -0
  663. package/dist/types/stt/transcriber.d.ts +16 -0
  664. package/dist/types/system-prompt.d.ts +93 -0
  665. package/dist/types/task/agents.d.ts +28 -0
  666. package/dist/types/task/commands.d.ts +35 -0
  667. package/dist/types/task/discovery.d.ts +19 -0
  668. package/dist/types/task/executor.d.ts +113 -0
  669. package/dist/types/task/fork-context-advisory.d.ts +13 -0
  670. package/dist/types/task/id.d.ts +7 -0
  671. package/dist/types/task/index.d.ts +43 -0
  672. package/dist/types/task/name-generator.d.ts +16 -0
  673. package/dist/types/task/output-manager.d.ts +36 -0
  674. package/dist/types/task/parallel.d.ts +34 -0
  675. package/dist/types/task/receipt.d.ts +87 -0
  676. package/dist/types/task/render.d.ts +28 -0
  677. package/dist/types/task/roi-reconciliation.d.ts +27 -0
  678. package/dist/types/task/simple-mode.d.ts +8 -0
  679. package/dist/types/task/skc-command.d.ts +7 -0
  680. package/dist/types/task/spawn-gate.d.ts +38 -0
  681. package/dist/types/task/subprocess-tool-registry.d.ts +72 -0
  682. package/dist/types/task/types.d.ts +508 -0
  683. package/dist/types/task/worktree.d.ts +94 -0
  684. package/dist/types/thinking-metadata.d.ts +16 -0
  685. package/dist/types/thinking.d.ts +22 -0
  686. package/dist/types/tool-discovery/tool-index.d.ts +112 -0
  687. package/dist/types/tools/archive-reader.d.ts +40 -0
  688. package/dist/types/tools/ask.d.ts +123 -0
  689. package/dist/types/tools/ast-edit.d.ts +77 -0
  690. package/dist/types/tools/ast-grep.d.ts +69 -0
  691. package/dist/types/tools/auto-generated-guard.d.ts +17 -0
  692. package/dist/types/tools/bash-allowed-prefixes.d.ts +10 -0
  693. package/dist/types/tools/bash-command-fixup.d.ts +11 -0
  694. package/dist/types/tools/bash-interactive.d.ts +16 -0
  695. package/dist/types/tools/bash-interceptor.d.ts +24 -0
  696. package/dist/types/tools/bash-pty-selection.d.ts +7 -0
  697. package/dist/types/tools/bash-skill-urls.d.ts +31 -0
  698. package/dist/types/tools/bash.d.ts +157 -0
  699. package/dist/types/tools/browser/actions.d.ts +54 -0
  700. package/dist/types/tools/browser/attach.d.ts +50 -0
  701. package/dist/types/tools/browser/launch.d.ts +62 -0
  702. package/dist/types/tools/browser/readable.d.ts +17 -0
  703. package/dist/types/tools/browser/registry.d.ts +57 -0
  704. package/dist/types/tools/browser/render.d.ts +53 -0
  705. package/dist/types/tools/browser/tab-protocol.d.ts +144 -0
  706. package/dist/types/tools/browser/tab-supervisor.d.ts +72 -0
  707. package/dist/types/tools/browser/tab-worker-entry.d.ts +1 -0
  708. package/dist/types/tools/browser/tab-worker.d.ts +19 -0
  709. package/dist/types/tools/browser.d.ts +211 -0
  710. package/dist/types/tools/calculator.d.ts +76 -0
  711. package/dist/types/tools/checkpoint.d.ts +63 -0
  712. package/dist/types/tools/computer/render.d.ts +17 -0
  713. package/dist/types/tools/computer.d.ts +465 -0
  714. package/dist/types/tools/conflict-detect.d.ts +205 -0
  715. package/dist/types/tools/context.d.ts +19 -0
  716. package/dist/types/tools/cron.d.ts +116 -0
  717. package/dist/types/tools/debug.d.ts +209 -0
  718. package/dist/types/tools/eval.d.ts +108 -0
  719. package/dist/types/tools/fetch.d.ts +61 -0
  720. package/dist/types/tools/file-recorder.d.ts +13 -0
  721. package/dist/types/tools/find.d.ts +95 -0
  722. package/dist/types/tools/fs-cache-invalidation.d.ts +15 -0
  723. package/dist/types/tools/gh-format.d.ts +6 -0
  724. package/dist/types/tools/gh-renderer.d.ts +25 -0
  725. package/dist/types/tools/gh.d.ts +356 -0
  726. package/dist/types/tools/github-cache.d.ts +103 -0
  727. package/dist/types/tools/grouped-file-output.d.ts +36 -0
  728. package/dist/types/tools/hindsight-recall.d.ts +21 -0
  729. package/dist/types/tools/hindsight-reflect.d.ts +23 -0
  730. package/dist/types/tools/hindsight-retain.d.ts +27 -0
  731. package/dist/types/tools/image-gen.d.ts +79 -0
  732. package/dist/types/tools/index.d.ts +297 -0
  733. package/dist/types/tools/inspect-image-renderer.d.ts +26 -0
  734. package/dist/types/tools/inspect-image.d.ts +31 -0
  735. package/dist/types/tools/irc.d.ts +79 -0
  736. package/dist/types/tools/job.d.ts +78 -0
  737. package/dist/types/tools/json-tree.d.ts +23 -0
  738. package/dist/types/tools/jtd-to-json-schema.d.ts +29 -0
  739. package/dist/types/tools/jtd-to-typescript.d.ts +26 -0
  740. package/dist/types/tools/jtd-utils.d.ts +42 -0
  741. package/dist/types/tools/list-limit.d.ts +12 -0
  742. package/dist/types/tools/match-line-format.d.ts +11 -0
  743. package/dist/types/tools/monitor.d.ts +54 -0
  744. package/dist/types/tools/output-meta.d.ts +204 -0
  745. package/dist/types/tools/path-utils.d.ts +147 -0
  746. package/dist/types/tools/plan-mode-guard.d.ts +18 -0
  747. package/dist/types/tools/read.d.ts +85 -0
  748. package/dist/types/tools/recipe/index.d.ts +45 -0
  749. package/dist/types/tools/recipe/render.d.ts +36 -0
  750. package/dist/types/tools/recipe/runner.d.ts +60 -0
  751. package/dist/types/tools/recipe/runners/cargo.d.ts +16 -0
  752. package/dist/types/tools/recipe/runners/index.d.ts +2 -0
  753. package/dist/types/tools/recipe/runners/just.d.ts +2 -0
  754. package/dist/types/tools/recipe/runners/make.d.ts +2 -0
  755. package/dist/types/tools/recipe/runners/pkg.d.ts +2 -0
  756. package/dist/types/tools/recipe/runners/task.d.ts +2 -0
  757. package/dist/types/tools/render-mermaid.d.ts +37 -0
  758. package/dist/types/tools/render-utils.d.ts +158 -0
  759. package/dist/types/tools/renderers.d.ts +26 -0
  760. package/dist/types/tools/resolve.d.ts +80 -0
  761. package/dist/types/tools/review.d.ts +63 -0
  762. package/dist/types/tools/search-tool-bm25.d.ts +65 -0
  763. package/dist/types/tools/search.d.ts +93 -0
  764. package/dist/types/tools/skill.d.ts +47 -0
  765. package/dist/types/tools/sqlite-reader.d.ts +94 -0
  766. package/dist/types/tools/ssh.d.ts +67 -0
  767. package/dist/types/tools/subagent-render.d.ts +31 -0
  768. package/dist/types/tools/subagent.d.ts +114 -0
  769. package/dist/types/tools/todo-write.d.ts +120 -0
  770. package/dist/types/tools/tool-errors.d.ts +33 -0
  771. package/dist/types/tools/tool-result.d.ts +30 -0
  772. package/dist/types/tools/tool-timeouts.d.ts +56 -0
  773. package/dist/types/tools/ultragoal-ask-guard.d.ts +5 -0
  774. package/dist/types/tools/vim.d.ts +58 -0
  775. package/dist/types/tools/write.d.ts +59 -0
  776. package/dist/types/tools/yield.d.ts +25 -0
  777. package/dist/types/tui/code-cell.d.ts +32 -0
  778. package/dist/types/tui/file-list.d.ts +22 -0
  779. package/dist/types/tui/hyperlink.d.ts +42 -0
  780. package/dist/types/tui/index.d.ts +11 -0
  781. package/dist/types/tui/output-block.d.ts +28 -0
  782. package/dist/types/tui/status-line.d.ts +18 -0
  783. package/dist/types/tui/tree-list.d.ts +19 -0
  784. package/dist/types/tui/types.d.ts +13 -0
  785. package/dist/types/tui/utils.d.ts +36 -0
  786. package/dist/types/utils/changelog.d.ts +36 -0
  787. package/dist/types/utils/clipboard.d.ts +22 -0
  788. package/dist/types/utils/command-args.d.ts +9 -0
  789. package/dist/types/utils/commit-message-generator.d.ts +7 -0
  790. package/dist/types/utils/edit-mode.d.ts +13 -0
  791. package/dist/types/utils/event-bus.d.ts +6 -0
  792. package/dist/types/utils/external-editor.d.ts +17 -0
  793. package/dist/types/utils/file-display-mode.d.ts +27 -0
  794. package/dist/types/utils/file-mentions.d.ts +11 -0
  795. package/dist/types/utils/git.d.ts +361 -0
  796. package/dist/types/utils/image-loading.d.ts +26 -0
  797. package/dist/types/utils/image-resize.d.ts +39 -0
  798. package/dist/types/utils/lang-from-path.d.ts +8 -0
  799. package/dist/types/utils/markit.d.ts +7 -0
  800. package/dist/types/utils/open.d.ts +2 -0
  801. package/dist/types/utils/session-color.d.ts +10 -0
  802. package/dist/types/utils/shell-snapshot.d.ts +5 -0
  803. package/dist/types/utils/sixel.d.ts +21 -0
  804. package/dist/types/utils/title-generator.d.ts +31 -0
  805. package/dist/types/utils/tool-choice.d.ts +20 -0
  806. package/dist/types/utils/tools-manager.d.ts +9 -0
  807. package/dist/types/vim/buffer.d.ts +41 -0
  808. package/dist/types/vim/commands.d.ts +6 -0
  809. package/dist/types/vim/engine.d.ts +47 -0
  810. package/dist/types/vim/parser.d.ts +3 -0
  811. package/dist/types/vim/render.d.ts +25 -0
  812. package/dist/types/vim/types.d.ts +182 -0
  813. package/dist/types/web/kagi.d.ts +23 -0
  814. package/dist/types/web/parallel.d.ts +58 -0
  815. package/dist/types/web/scrapers/artifacthub.d.ts +6 -0
  816. package/dist/types/web/scrapers/arxiv.d.ts +5 -0
  817. package/dist/types/web/scrapers/aur.d.ts +5 -0
  818. package/dist/types/web/scrapers/biorxiv.d.ts +5 -0
  819. package/dist/types/web/scrapers/bluesky.d.ts +5 -0
  820. package/dist/types/web/scrapers/brew.d.ts +5 -0
  821. package/dist/types/web/scrapers/cheatsh.d.ts +8 -0
  822. package/dist/types/web/scrapers/chocolatey.d.ts +5 -0
  823. package/dist/types/web/scrapers/choosealicense.d.ts +2 -0
  824. package/dist/types/web/scrapers/cisa-kev.d.ts +5 -0
  825. package/dist/types/web/scrapers/clojars.d.ts +5 -0
  826. package/dist/types/web/scrapers/coingecko.d.ts +5 -0
  827. package/dist/types/web/scrapers/crates-io.d.ts +5 -0
  828. package/dist/types/web/scrapers/crossref.d.ts +2 -0
  829. package/dist/types/web/scrapers/devto.d.ts +5 -0
  830. package/dist/types/web/scrapers/discogs.d.ts +8 -0
  831. package/dist/types/web/scrapers/discourse.d.ts +5 -0
  832. package/dist/types/web/scrapers/dockerhub.d.ts +5 -0
  833. package/dist/types/web/scrapers/docs-rs.d.ts +2 -0
  834. package/dist/types/web/scrapers/fdroid.d.ts +5 -0
  835. package/dist/types/web/scrapers/firefox-addons.d.ts +2 -0
  836. package/dist/types/web/scrapers/flathub.d.ts +2 -0
  837. package/dist/types/web/scrapers/github-gist.d.ts +5 -0
  838. package/dist/types/web/scrapers/github.d.ts +12 -0
  839. package/dist/types/web/scrapers/gitlab.d.ts +5 -0
  840. package/dist/types/web/scrapers/go-pkg.d.ts +5 -0
  841. package/dist/types/web/scrapers/hackage.d.ts +5 -0
  842. package/dist/types/web/scrapers/hackernews.d.ts +2 -0
  843. package/dist/types/web/scrapers/hex.d.ts +5 -0
  844. package/dist/types/web/scrapers/huggingface.d.ts +2 -0
  845. package/dist/types/web/scrapers/iacr.d.ts +5 -0
  846. package/dist/types/web/scrapers/index.d.ts +84 -0
  847. package/dist/types/web/scrapers/jetbrains-marketplace.d.ts +2 -0
  848. package/dist/types/web/scrapers/lemmy.d.ts +2 -0
  849. package/dist/types/web/scrapers/lobsters.d.ts +5 -0
  850. package/dist/types/web/scrapers/mastodon.d.ts +5 -0
  851. package/dist/types/web/scrapers/maven.d.ts +6 -0
  852. package/dist/types/web/scrapers/mdn.d.ts +2 -0
  853. package/dist/types/web/scrapers/metacpan.d.ts +5 -0
  854. package/dist/types/web/scrapers/musicbrainz.d.ts +5 -0
  855. package/dist/types/web/scrapers/npm.d.ts +5 -0
  856. package/dist/types/web/scrapers/nuget.d.ts +5 -0
  857. package/dist/types/web/scrapers/nvd.d.ts +5 -0
  858. package/dist/types/web/scrapers/ollama.d.ts +2 -0
  859. package/dist/types/web/scrapers/open-vsx.d.ts +5 -0
  860. package/dist/types/web/scrapers/opencorporates.d.ts +5 -0
  861. package/dist/types/web/scrapers/openlibrary.d.ts +5 -0
  862. package/dist/types/web/scrapers/orcid.d.ts +5 -0
  863. package/dist/types/web/scrapers/osv.d.ts +5 -0
  864. package/dist/types/web/scrapers/packagist.d.ts +5 -0
  865. package/dist/types/web/scrapers/pub-dev.d.ts +5 -0
  866. package/dist/types/web/scrapers/pubmed.d.ts +5 -0
  867. package/dist/types/web/scrapers/pypi.d.ts +5 -0
  868. package/dist/types/web/scrapers/rawg.d.ts +2 -0
  869. package/dist/types/web/scrapers/readthedocs.d.ts +2 -0
  870. package/dist/types/web/scrapers/reddit.d.ts +5 -0
  871. package/dist/types/web/scrapers/repology.d.ts +5 -0
  872. package/dist/types/web/scrapers/rfc.d.ts +5 -0
  873. package/dist/types/web/scrapers/rubygems.d.ts +5 -0
  874. package/dist/types/web/scrapers/searchcode.d.ts +2 -0
  875. package/dist/types/web/scrapers/sec-edgar.d.ts +5 -0
  876. package/dist/types/web/scrapers/semantic-scholar.d.ts +2 -0
  877. package/dist/types/web/scrapers/snapcraft.d.ts +2 -0
  878. package/dist/types/web/scrapers/sourcegraph.d.ts +2 -0
  879. package/dist/types/web/scrapers/spdx.d.ts +5 -0
  880. package/dist/types/web/scrapers/spotify.d.ts +8 -0
  881. package/dist/types/web/scrapers/stackoverflow.d.ts +6 -0
  882. package/dist/types/web/scrapers/terraform.d.ts +5 -0
  883. package/dist/types/web/scrapers/tldr.d.ts +7 -0
  884. package/dist/types/web/scrapers/twitter.d.ts +5 -0
  885. package/dist/types/web/scrapers/types.d.ts +78 -0
  886. package/dist/types/web/scrapers/utils.d.ts +26 -0
  887. package/dist/types/web/scrapers/vimeo.d.ts +5 -0
  888. package/dist/types/web/scrapers/vscode-marketplace.d.ts +5 -0
  889. package/dist/types/web/scrapers/w3c.d.ts +2 -0
  890. package/dist/types/web/scrapers/wikidata.d.ts +5 -0
  891. package/dist/types/web/scrapers/wikipedia.d.ts +5 -0
  892. package/dist/types/web/scrapers/youtube.d.ts +5 -0
  893. package/dist/types/web/search/index.d.ts +115 -0
  894. package/dist/types/web/search/provider.d.ts +24 -0
  895. package/dist/types/web/search/providers/anthropic.d.ts +32 -0
  896. package/dist/types/web/search/providers/base.d.ts +90 -0
  897. package/dist/types/web/search/providers/brave.d.ts +27 -0
  898. package/dist/types/web/search/providers/codex.d.ts +35 -0
  899. package/dist/types/web/search/providers/duckduckgo.d.ts +57 -0
  900. package/dist/types/web/search/providers/exa.d.ts +52 -0
  901. package/dist/types/web/search/providers/gemini.d.ts +57 -0
  902. package/dist/types/web/search/providers/jina.d.ts +26 -0
  903. package/dist/types/web/search/providers/kagi.d.ts +24 -0
  904. package/dist/types/web/search/providers/kimi.d.ts +27 -0
  905. package/dist/types/web/search/providers/openai-compatible.d.ts +9 -0
  906. package/dist/types/web/search/providers/parallel.d.ts +15 -0
  907. package/dist/types/web/search/providers/perplexity.d.ts +38 -0
  908. package/dist/types/web/search/providers/searxng.d.ts +44 -0
  909. package/dist/types/web/search/providers/synthetic.d.ts +21 -0
  910. package/dist/types/web/search/providers/tavily.d.ts +29 -0
  911. package/dist/types/web/search/providers/utils.d.ts +52 -0
  912. package/dist/types/web/search/providers/xai.d.ts +64 -0
  913. package/dist/types/web/search/providers/zai.d.ts +28 -0
  914. package/dist/types/web/search/render.d.ts +35 -0
  915. package/dist/types/web/search/types.d.ts +364 -0
  916. package/dist/types/web/search/utils.d.ts +4 -0
  917. package/dist/types/workspace-tree.d.ts +42 -0
  918. package/examples/README.md +21 -0
  919. package/examples/custom-tools/README.md +104 -0
  920. package/examples/custom-tools/hello/index.ts +20 -0
  921. package/examples/extensions/README.md +120 -0
  922. package/examples/extensions/api-demo.ts +79 -0
  923. package/examples/extensions/chalk-logger.ts +25 -0
  924. package/examples/extensions/hello.ts +31 -0
  925. package/examples/extensions/pirate.ts +43 -0
  926. package/examples/extensions/plan-mode.ts +549 -0
  927. package/examples/extensions/reload-runtime.ts +38 -0
  928. package/examples/extensions/tools.ts +144 -0
  929. package/examples/extensions/with-deps/index.ts +36 -0
  930. package/examples/extensions/with-deps/package-lock.json +31 -0
  931. package/examples/extensions/with-deps/package.json +16 -0
  932. package/examples/hooks/README.md +56 -0
  933. package/examples/hooks/auto-commit-on-exit.ts +48 -0
  934. package/examples/hooks/confirm-destructive.ts +58 -0
  935. package/examples/hooks/custom-compaction.ts +115 -0
  936. package/examples/hooks/dirty-repo-guard.ts +51 -0
  937. package/examples/hooks/file-trigger.ts +40 -0
  938. package/examples/hooks/git-checkpoint.ts +52 -0
  939. package/examples/hooks/handoff.ts +149 -0
  940. package/examples/hooks/permission-gate.ts +33 -0
  941. package/examples/hooks/protected-paths.ts +29 -0
  942. package/examples/hooks/qna.ts +118 -0
  943. package/examples/hooks/status-line.ts +39 -0
  944. package/examples/sdk/01-minimal.ts +21 -0
  945. package/examples/sdk/02-custom-model.ts +49 -0
  946. package/examples/sdk/03-custom-prompt.ts +46 -0
  947. package/examples/sdk/04-skills.ts +43 -0
  948. package/examples/sdk/06-extensions.ts +82 -0
  949. package/examples/sdk/06-hooks.ts +61 -0
  950. package/examples/sdk/07-context-files.ts +35 -0
  951. package/examples/sdk/08-prompt-templates.ts +41 -0
  952. package/examples/sdk/08-slash-commands.ts +46 -0
  953. package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
  954. package/examples/sdk/11-sessions.ts +47 -0
  955. package/examples/sdk/README.md +172 -0
  956. package/package.json +540 -0
  957. package/scripts/build-binary.ts +95 -0
  958. package/scripts/format-prompts.ts +68 -0
  959. package/scripts/generate-docs-index.ts +71 -0
  960. package/scripts/generate-template.ts +33 -0
  961. package/src/async/index.ts +2 -0
  962. package/src/async/job-manager.ts +1489 -0
  963. package/src/async/support.ts +6 -0
  964. package/src/autoresearch/command-resume.md +14 -0
  965. package/src/autoresearch/dashboard.ts +446 -0
  966. package/src/autoresearch/git.ts +319 -0
  967. package/src/autoresearch/helpers.ts +218 -0
  968. package/src/autoresearch/index.ts +536 -0
  969. package/src/autoresearch/prompt-setup.md +43 -0
  970. package/src/autoresearch/prompt.md +103 -0
  971. package/src/autoresearch/resume-message.md +10 -0
  972. package/src/autoresearch/state.ts +273 -0
  973. package/src/autoresearch/storage.ts +699 -0
  974. package/src/autoresearch/tools/init-experiment.ts +272 -0
  975. package/src/autoresearch/tools/log-experiment.ts +524 -0
  976. package/src/autoresearch/tools/run-experiment.ts +475 -0
  977. package/src/autoresearch/tools/update-notes.ts +109 -0
  978. package/src/autoresearch/types.ts +168 -0
  979. package/src/bun-imports.d.ts +28 -0
  980. package/src/capability/context-file.ts +44 -0
  981. package/src/capability/extension-module.ts +34 -0
  982. package/src/capability/extension.ts +47 -0
  983. package/src/capability/fs.ts +107 -0
  984. package/src/capability/hook.ts +40 -0
  985. package/src/capability/index.ts +436 -0
  986. package/src/capability/instruction.ts +37 -0
  987. package/src/capability/mcp.ts +74 -0
  988. package/src/capability/prompt.ts +35 -0
  989. package/src/capability/rule.ts +244 -0
  990. package/src/capability/settings.ts +34 -0
  991. package/src/capability/skill.ts +56 -0
  992. package/src/capability/slash-command.ts +40 -0
  993. package/src/capability/ssh.ts +41 -0
  994. package/src/capability/system-prompt.ts +34 -0
  995. package/src/capability/tool.ts +38 -0
  996. package/src/capability/types.ts +168 -0
  997. package/src/cli/agents-cli.ts +141 -0
  998. package/src/cli/args.ts +306 -0
  999. package/src/cli/auth-broker-cli.ts +748 -0
  1000. package/src/cli/auth-gateway-cli.ts +411 -0
  1001. package/src/cli/classify-install-target.ts +50 -0
  1002. package/src/cli/commands/init-xdg.ts +27 -0
  1003. package/src/cli/config-cli.ts +426 -0
  1004. package/src/cli/fast-help.ts +82 -0
  1005. package/src/cli/file-processor.ts +123 -0
  1006. package/src/cli/grep-cli.ts +160 -0
  1007. package/src/cli/initial-message.ts +58 -0
  1008. package/src/cli/list-models.ts +206 -0
  1009. package/src/cli/plugin-cli.ts +942 -0
  1010. package/src/cli/read-cli.ts +57 -0
  1011. package/src/cli/session-picker.ts +52 -0
  1012. package/src/cli/setup-cli.ts +675 -0
  1013. package/src/cli/shell-cli.ts +176 -0
  1014. package/src/cli/skills-cli.ts +88 -0
  1015. package/src/cli/ssh-cli.ts +179 -0
  1016. package/src/cli/stats-cli.ts +238 -0
  1017. package/src/cli/update-cli.ts +459 -0
  1018. package/src/cli/web-search-cli.ts +248 -0
  1019. package/src/cli/worktree-cli.ts +291 -0
  1020. package/src/cli.ts +225 -0
  1021. package/src/commands/acp.ts +24 -0
  1022. package/src/commands/agents.ts +57 -0
  1023. package/src/commands/auth-broker.ts +96 -0
  1024. package/src/commands/auth-gateway.ts +63 -0
  1025. package/src/commands/codex-native-hook.ts +11 -0
  1026. package/src/commands/commit.ts +46 -0
  1027. package/src/commands/config.ts +51 -0
  1028. package/src/commands/contribution-prep.ts +41 -0
  1029. package/src/commands/coordinator.ts +113 -0
  1030. package/src/commands/deep-interview.ts +39 -0
  1031. package/src/commands/gc.ts +22 -0
  1032. package/src/commands/grep.ts +48 -0
  1033. package/src/commands/harness.ts +1207 -0
  1034. package/src/commands/launch.ts +178 -0
  1035. package/src/commands/mcp-serve.ts +63 -0
  1036. package/src/commands/plugin.ts +78 -0
  1037. package/src/commands/ralplan.ts +19 -0
  1038. package/src/commands/read.ts +35 -0
  1039. package/src/commands/rlm.ts +19 -0
  1040. package/src/commands/session.ts +152 -0
  1041. package/src/commands/setup.ts +91 -0
  1042. package/src/commands/shell.ts +29 -0
  1043. package/src/commands/skills.ts +48 -0
  1044. package/src/commands/ssh.ts +60 -0
  1045. package/src/commands/state.ts +24 -0
  1046. package/src/commands/stats.ts +29 -0
  1047. package/src/commands/team.ts +216 -0
  1048. package/src/commands/ultragoal.ts +41 -0
  1049. package/src/commands/update.ts +21 -0
  1050. package/src/commands/web-search.ts +108 -0
  1051. package/src/commands/worktree.ts +56 -0
  1052. package/src/commit/agentic/agent.ts +316 -0
  1053. package/src/commit/agentic/fallback.ts +96 -0
  1054. package/src/commit/agentic/index.ts +356 -0
  1055. package/src/commit/agentic/prompts/analyze-file.md +22 -0
  1056. package/src/commit/agentic/prompts/session-user.md +25 -0
  1057. package/src/commit/agentic/prompts/split-confirm.md +1 -0
  1058. package/src/commit/agentic/prompts/system.md +38 -0
  1059. package/src/commit/agentic/state.ts +60 -0
  1060. package/src/commit/agentic/tools/analyze-file.ts +127 -0
  1061. package/src/commit/agentic/tools/git-file-diff.ts +191 -0
  1062. package/src/commit/agentic/tools/git-hunk.ts +50 -0
  1063. package/src/commit/agentic/tools/git-overview.ts +81 -0
  1064. package/src/commit/agentic/tools/index.ts +54 -0
  1065. package/src/commit/agentic/tools/propose-changelog.ts +144 -0
  1066. package/src/commit/agentic/tools/propose-commit.ts +109 -0
  1067. package/src/commit/agentic/tools/recent-commits.ts +81 -0
  1068. package/src/commit/agentic/tools/schemas.ts +23 -0
  1069. package/src/commit/agentic/tools/split-commit.ts +238 -0
  1070. package/src/commit/agentic/topo-sort.ts +44 -0
  1071. package/src/commit/agentic/trivial.ts +51 -0
  1072. package/src/commit/agentic/validation.ts +183 -0
  1073. package/src/commit/analysis/conventional.ts +64 -0
  1074. package/src/commit/analysis/index.ts +4 -0
  1075. package/src/commit/analysis/scope.ts +242 -0
  1076. package/src/commit/analysis/summary.ts +105 -0
  1077. package/src/commit/analysis/validation.ts +66 -0
  1078. package/src/commit/changelog/detect.ts +40 -0
  1079. package/src/commit/changelog/generate.ts +97 -0
  1080. package/src/commit/changelog/index.ts +234 -0
  1081. package/src/commit/changelog/parse.ts +44 -0
  1082. package/src/commit/cli.ts +85 -0
  1083. package/src/commit/git/diff.ts +148 -0
  1084. package/src/commit/index.ts +5 -0
  1085. package/src/commit/map-reduce/index.ts +69 -0
  1086. package/src/commit/map-reduce/map-phase.ts +193 -0
  1087. package/src/commit/map-reduce/reduce-phase.ts +49 -0
  1088. package/src/commit/map-reduce/utils.ts +9 -0
  1089. package/src/commit/message.ts +11 -0
  1090. package/src/commit/model-selection.ts +51 -0
  1091. package/src/commit/pipeline.ts +244 -0
  1092. package/src/commit/prompts/analysis-system.md +148 -0
  1093. package/src/commit/prompts/analysis-user.md +38 -0
  1094. package/src/commit/prompts/changelog-system.md +50 -0
  1095. package/src/commit/prompts/changelog-user.md +18 -0
  1096. package/src/commit/prompts/file-observer-system.md +24 -0
  1097. package/src/commit/prompts/file-observer-user.md +8 -0
  1098. package/src/commit/prompts/reduce-system.md +50 -0
  1099. package/src/commit/prompts/reduce-user.md +17 -0
  1100. package/src/commit/prompts/summary-retry.md +3 -0
  1101. package/src/commit/prompts/summary-system.md +38 -0
  1102. package/src/commit/prompts/summary-user.md +13 -0
  1103. package/src/commit/prompts/types-description.md +2 -0
  1104. package/src/commit/shared-llm.ts +77 -0
  1105. package/src/commit/types.ts +118 -0
  1106. package/src/commit/utils/exclusions.ts +42 -0
  1107. package/src/commit/utils.ts +58 -0
  1108. package/src/config/config-file.ts +232 -0
  1109. package/src/config/file-lock-gc.ts +193 -0
  1110. package/src/config/file-lock.ts +185 -0
  1111. package/src/config/keybindings.ts +510 -0
  1112. package/src/config/mcp-schema.json +230 -0
  1113. package/src/config/model-equivalence.ts +811 -0
  1114. package/src/config/model-profile-activation.ts +249 -0
  1115. package/src/config/model-profiles.ts +396 -0
  1116. package/src/config/model-registry.ts +2816 -0
  1117. package/src/config/model-resolver.ts +1336 -0
  1118. package/src/config/models-config-schema.ts +258 -0
  1119. package/src/config/prompt-templates.ts +310 -0
  1120. package/src/config/resolve-config-value.ts +94 -0
  1121. package/src/config/settings-schema.ts +3183 -0
  1122. package/src/config/settings.ts +967 -0
  1123. package/src/config/skill-settings-defaults.ts +27 -0
  1124. package/src/config.ts +212 -0
  1125. package/src/coordinator/contract.ts +22 -0
  1126. package/src/coordinator-mcp/policy.ts +160 -0
  1127. package/src/coordinator-mcp/safety.ts +80 -0
  1128. package/src/coordinator-mcp/server.ts +2006 -0
  1129. package/src/cursor.ts +392 -0
  1130. package/src/dap/client.ts +730 -0
  1131. package/src/dap/config.ts +150 -0
  1132. package/src/dap/defaults.json +211 -0
  1133. package/src/dap/index.ts +4 -0
  1134. package/src/dap/session.ts +1343 -0
  1135. package/src/dap/types.ts +600 -0
  1136. package/src/debug/crash-diagnostics.ts +223 -0
  1137. package/src/debug/index.ts +459 -0
  1138. package/src/debug/log-formatting.ts +58 -0
  1139. package/src/debug/log-viewer.ts +908 -0
  1140. package/src/debug/profiler.ts +162 -0
  1141. package/src/debug/raw-sse-buffer.ts +270 -0
  1142. package/src/debug/raw-sse.ts +213 -0
  1143. package/src/debug/report-bundle.ts +365 -0
  1144. package/src/debug/runtime-gauges.ts +20 -0
  1145. package/src/debug/system-info.ts +111 -0
  1146. package/src/deep-interview/render-middleware.ts +372 -0
  1147. package/src/defaults/skc/agent.models.grok-cli.yml +36 -0
  1148. package/src/defaults/skc/extensions/grok-build/index.ts +1 -0
  1149. package/src/defaults/skc/extensions/grok-build/package.json +7 -0
  1150. package/src/defaults/skc/extensions/grok-cli-vendor/biome.json +39 -0
  1151. package/src/defaults/skc/extensions/grok-cli-vendor/package.json +8 -0
  1152. package/src/defaults/skc/extensions/grok-cli-vendor/src/index.ts +1 -0
  1153. package/src/defaults/skc/extensions/grok-cli-vendor/src/models/catalog.ts +155 -0
  1154. package/src/defaults/skc/extensions/grok-cli-vendor/src/payload/sanitize.ts +361 -0
  1155. package/src/defaults/skc/extensions/grok-cli-vendor/src/provider/billing.ts +57 -0
  1156. package/src/defaults/skc/extensions/grok-cli-vendor/src/provider/register.ts +99 -0
  1157. package/src/defaults/skc/extensions/grok-cli-vendor/src/provider/stream.ts +50 -0
  1158. package/src/defaults/skc/extensions/grok-cli-vendor/src/provider/usage.ts +56 -0
  1159. package/src/defaults/skc/extensions/grok-cli-vendor/src/shared/base-url.ts +36 -0
  1160. package/src/defaults/skc/extensions/grok-cli-vendor/src/shared/errors.ts +44 -0
  1161. package/src/defaults/skc/skills/deep-interview/SKILL.md +879 -0
  1162. package/src/defaults/skc/skills/deep-interview/auto-answer-uncertain.md +37 -0
  1163. package/src/defaults/skc/skills/deep-interview/auto-research-greenfield.md +42 -0
  1164. package/src/defaults/skc/skills/deep-interview/lateral-review-panel.md +49 -0
  1165. package/src/defaults/skc/skills/ralplan/SKILL.md +191 -0
  1166. package/src/defaults/skc/skills/team/SKILL.md +442 -0
  1167. package/src/defaults/skc/skills/ultragoal/SKILL.md +349 -0
  1168. package/src/defaults/skc/skills/ultragoal/ai-slop-cleaner.md +61 -0
  1169. package/src/defaults/skc-defaults.ts +217 -0
  1170. package/src/defaults/skc-grok-cli.ts +22 -0
  1171. package/src/discovery/agents-md.ts +67 -0
  1172. package/src/discovery/agents.ts +230 -0
  1173. package/src/discovery/builtin.ts +932 -0
  1174. package/src/discovery/claude-plugins.ts +407 -0
  1175. package/src/discovery/claude.ts +313 -0
  1176. package/src/discovery/cline.ts +83 -0
  1177. package/src/discovery/codex.ts +330 -0
  1178. package/src/discovery/cursor.ts +220 -0
  1179. package/src/discovery/gemini.ts +383 -0
  1180. package/src/discovery/github.ts +118 -0
  1181. package/src/discovery/helpers.ts +992 -0
  1182. package/src/discovery/index.ts +76 -0
  1183. package/src/discovery/mcp-json.ts +171 -0
  1184. package/src/discovery/opencode.ts +398 -0
  1185. package/src/discovery/plugin-dir-roots.ts +28 -0
  1186. package/src/discovery/ssh.ts +153 -0
  1187. package/src/discovery/substitute-plugin-root.ts +29 -0
  1188. package/src/discovery/vscode.ts +105 -0
  1189. package/src/discovery/windsurf.ts +147 -0
  1190. package/src/edit/apply-patch/index.ts +87 -0
  1191. package/src/edit/apply-patch/parser.ts +174 -0
  1192. package/src/edit/diff.ts +873 -0
  1193. package/src/edit/file-read-cache.ts +95 -0
  1194. package/src/edit/index.ts +528 -0
  1195. package/src/edit/modes/apply-patch.lark +19 -0
  1196. package/src/edit/modes/apply-patch.ts +53 -0
  1197. package/src/edit/modes/patch.ts +1835 -0
  1198. package/src/edit/modes/replace.ts +1161 -0
  1199. package/src/edit/normalize.ts +375 -0
  1200. package/src/edit/notebook.ts +226 -0
  1201. package/src/edit/read-file.ts +43 -0
  1202. package/src/edit/renderer.ts +683 -0
  1203. package/src/edit/streaming.ts +561 -0
  1204. package/src/eval/backend.ts +43 -0
  1205. package/src/eval/index.ts +4 -0
  1206. package/src/eval/js/context-manager.ts +577 -0
  1207. package/src/eval/js/executor.ts +136 -0
  1208. package/src/eval/js/index.ts +47 -0
  1209. package/src/eval/js/shared/helpers.ts +237 -0
  1210. package/src/eval/js/shared/indirect-eval.ts +30 -0
  1211. package/src/eval/js/shared/prelude.ts +2 -0
  1212. package/src/eval/js/shared/prelude.txt +70 -0
  1213. package/src/eval/js/shared/rewrite-imports.ts +415 -0
  1214. package/src/eval/js/shared/runtime.ts +301 -0
  1215. package/src/eval/js/shared/types.ts +18 -0
  1216. package/src/eval/js/tool-bridge.ts +144 -0
  1217. package/src/eval/js/worker-core.ts +150 -0
  1218. package/src/eval/js/worker-entry.ts +24 -0
  1219. package/src/eval/js/worker-protocol.ts +41 -0
  1220. package/src/eval/py/display.ts +71 -0
  1221. package/src/eval/py/executor.ts +678 -0
  1222. package/src/eval/py/index.ts +58 -0
  1223. package/src/eval/py/kernel.ts +712 -0
  1224. package/src/eval/py/prelude.py +462 -0
  1225. package/src/eval/py/prelude.ts +3 -0
  1226. package/src/eval/py/runner.py +964 -0
  1227. package/src/eval/py/runtime.ts +331 -0
  1228. package/src/eval/py/tool-bridge.ts +137 -0
  1229. package/src/eval/types.ts +48 -0
  1230. package/src/exa/factory.ts +60 -0
  1231. package/src/exa/index.ts +27 -0
  1232. package/src/exa/mcp-client.ts +364 -0
  1233. package/src/exa/render.ts +244 -0
  1234. package/src/exa/researcher.ts +36 -0
  1235. package/src/exa/search.ts +47 -0
  1236. package/src/exa/types.ts +166 -0
  1237. package/src/exa/websets.ts +248 -0
  1238. package/src/exec/bash-executor.ts +403 -0
  1239. package/src/exec/exec.ts +53 -0
  1240. package/src/exec/idle-timeout-watchdog.ts +126 -0
  1241. package/src/exec/non-interactive-env.ts +48 -0
  1242. package/src/export/custom-share.ts +65 -0
  1243. package/src/export/html/index.ts +168 -0
  1244. package/src/export/html/template.css +1060 -0
  1245. package/src/export/html/template.generated.ts +2 -0
  1246. package/src/export/html/template.html +47 -0
  1247. package/src/export/html/template.js +2268 -0
  1248. package/src/export/html/template.macro.ts +25 -0
  1249. package/src/export/html/vendor/highlight.min.js +1213 -0
  1250. package/src/export/html/vendor/marked.min.js +6 -0
  1251. package/src/export/ttsr.ts +434 -0
  1252. package/src/extensibility/custom-commands/bundled/ci-green/index.ts +25 -0
  1253. package/src/extensibility/custom-commands/bundled/review/index.ts +456 -0
  1254. package/src/extensibility/custom-commands/index.ts +2 -0
  1255. package/src/extensibility/custom-commands/loader.ts +238 -0
  1256. package/src/extensibility/custom-commands/types.ts +113 -0
  1257. package/src/extensibility/custom-tools/index.ts +7 -0
  1258. package/src/extensibility/custom-tools/loader.ts +245 -0
  1259. package/src/extensibility/custom-tools/types.ts +257 -0
  1260. package/src/extensibility/custom-tools/wrapper.ts +49 -0
  1261. package/src/extensibility/extensions/compact-handler.ts +40 -0
  1262. package/src/extensibility/extensions/get-commands-handler.ts +80 -0
  1263. package/src/extensibility/extensions/index.ts +16 -0
  1264. package/src/extensibility/extensions/loader.ts +551 -0
  1265. package/src/extensibility/extensions/prefix-command-bridge.ts +128 -0
  1266. package/src/extensibility/extensions/runner.ts +900 -0
  1267. package/src/extensibility/extensions/types.ts +1286 -0
  1268. package/src/extensibility/extensions/wrapper.ts +190 -0
  1269. package/src/extensibility/hooks/index.ts +5 -0
  1270. package/src/extensibility/hooks/loader.ts +257 -0
  1271. package/src/extensibility/hooks/runner.ts +425 -0
  1272. package/src/extensibility/hooks/tool-wrapper.ts +107 -0
  1273. package/src/extensibility/hooks/types.ts +599 -0
  1274. package/src/extensibility/plugins/doctor.ts +66 -0
  1275. package/src/extensibility/plugins/git-url.ts +281 -0
  1276. package/src/extensibility/plugins/index.ts +9 -0
  1277. package/src/extensibility/plugins/installer.ts +192 -0
  1278. package/src/extensibility/plugins/legacy-pi-compat.ts +336 -0
  1279. package/src/extensibility/plugins/loader.ts +288 -0
  1280. package/src/extensibility/plugins/manager.ts +731 -0
  1281. package/src/extensibility/plugins/marketplace/cache.ts +136 -0
  1282. package/src/extensibility/plugins/marketplace/fetcher.ts +317 -0
  1283. package/src/extensibility/plugins/marketplace/index.ts +6 -0
  1284. package/src/extensibility/plugins/marketplace/manager.ts +770 -0
  1285. package/src/extensibility/plugins/marketplace/registry.ts +196 -0
  1286. package/src/extensibility/plugins/marketplace/source-resolver.ts +147 -0
  1287. package/src/extensibility/plugins/marketplace/types.ts +191 -0
  1288. package/src/extensibility/plugins/parser.ts +105 -0
  1289. package/src/extensibility/plugins/types.ts +194 -0
  1290. package/src/extensibility/shared-events.ts +344 -0
  1291. package/src/extensibility/skc-plugins/activation.ts +87 -0
  1292. package/src/extensibility/skc-plugins/index.ts +9 -0
  1293. package/src/extensibility/skc-plugins/injection.ts +114 -0
  1294. package/src/extensibility/skc-plugins/loader.ts +131 -0
  1295. package/src/extensibility/skc-plugins/paths.ts +66 -0
  1296. package/src/extensibility/skc-plugins/schema.ts +79 -0
  1297. package/src/extensibility/skc-plugins/state.ts +29 -0
  1298. package/src/extensibility/skc-plugins/tools.ts +47 -0
  1299. package/src/extensibility/skc-plugins/types.ts +97 -0
  1300. package/src/extensibility/skc-plugins/validation.ts +76 -0
  1301. package/src/extensibility/skills.ts +423 -0
  1302. package/src/extensibility/slash-commands.ts +236 -0
  1303. package/src/extensibility/tool-proxy.ts +25 -0
  1304. package/src/extensibility/typebox.ts +418 -0
  1305. package/src/extensibility/utils.ts +44 -0
  1306. package/src/goals/index.ts +3 -0
  1307. package/src/goals/runtime.ts +419 -0
  1308. package/src/goals/state.ts +66 -0
  1309. package/src/goals/tools/goal-tool.ts +237 -0
  1310. package/src/harness-control-plane/classifier.ts +128 -0
  1311. package/src/harness-control-plane/control-endpoint.ts +148 -0
  1312. package/src/harness-control-plane/finalize.ts +340 -0
  1313. package/src/harness-control-plane/gc-adapter.ts +184 -0
  1314. package/src/harness-control-plane/operate.ts +225 -0
  1315. package/src/harness-control-plane/owner.ts +684 -0
  1316. package/src/harness-control-plane/phase-rollup.ts +96 -0
  1317. package/src/harness-control-plane/preserve.ts +102 -0
  1318. package/src/harness-control-plane/receipt-ingest.ts +127 -0
  1319. package/src/harness-control-plane/receipt-spool.ts +128 -0
  1320. package/src/harness-control-plane/receipts.ts +482 -0
  1321. package/src/harness-control-plane/rpc-adapter.ts +290 -0
  1322. package/src/harness-control-plane/seams.ts +39 -0
  1323. package/src/harness-control-plane/session-lease.ts +388 -0
  1324. package/src/harness-control-plane/state-machine.ts +119 -0
  1325. package/src/harness-control-plane/storage.ts +492 -0
  1326. package/src/harness-control-plane/types.ts +267 -0
  1327. package/src/hashline/anchors.ts +113 -0
  1328. package/src/hashline/apply.ts +737 -0
  1329. package/src/hashline/bigrams.json +649 -0
  1330. package/src/hashline/constants.ts +25 -0
  1331. package/src/hashline/diff-preview.ts +43 -0
  1332. package/src/hashline/diff.ts +56 -0
  1333. package/src/hashline/execute.ts +267 -0
  1334. package/src/hashline/grammar.lark +21 -0
  1335. package/src/hashline/hash.ts +196 -0
  1336. package/src/hashline/index.ts +13 -0
  1337. package/src/hashline/input.ts +130 -0
  1338. package/src/hashline/parser.ts +246 -0
  1339. package/src/hashline/prefixes.ts +101 -0
  1340. package/src/hashline/recovery.ts +113 -0
  1341. package/src/hashline/stream.ts +123 -0
  1342. package/src/hashline/types.ts +68 -0
  1343. package/src/hindsight/backend.ts +205 -0
  1344. package/src/hindsight/bank.ts +131 -0
  1345. package/src/hindsight/client.ts +598 -0
  1346. package/src/hindsight/config.ts +175 -0
  1347. package/src/hindsight/content.ts +210 -0
  1348. package/src/hindsight/index.ts +8 -0
  1349. package/src/hindsight/mental-models.ts +383 -0
  1350. package/src/hindsight/seeds.json +32 -0
  1351. package/src/hindsight/state.ts +469 -0
  1352. package/src/hindsight/transcript.ts +71 -0
  1353. package/src/hooks/codex-native-hooks-config.ts +143 -0
  1354. package/src/hooks/native-skill-hook.ts +305 -0
  1355. package/src/hooks/skill-keywords.ts +88 -0
  1356. package/src/hooks/skill-state.ts +753 -0
  1357. package/src/i18n/index.ts +188 -0
  1358. package/src/i18n/messages/de.messages.ts +308 -0
  1359. package/src/i18n/messages/de.settings.ts +805 -0
  1360. package/src/i18n/messages/de.ts +65 -0
  1361. package/src/i18n/messages/en.ts +86 -0
  1362. package/src/i18n/messages/es.messages.ts +314 -0
  1363. package/src/i18n/messages/es.settings.ts +798 -0
  1364. package/src/i18n/messages/es.ts +65 -0
  1365. package/src/i18n/messages/fr.messages.ts +312 -0
  1366. package/src/i18n/messages/fr.settings.ts +771 -0
  1367. package/src/i18n/messages/fr.ts +65 -0
  1368. package/src/i18n/messages/ja.messages.ts +314 -0
  1369. package/src/i18n/messages/ja.settings.ts +809 -0
  1370. package/src/i18n/messages/ja.ts +69 -0
  1371. package/src/i18n/messages/ko.messages.ts +312 -0
  1372. package/src/i18n/messages/ko.settings.ts +798 -0
  1373. package/src/i18n/messages/ko.ts +69 -0
  1374. package/src/i18n/messages/zh.messages.ts +298 -0
  1375. package/src/i18n/messages/zh.settings.ts +779 -0
  1376. package/src/i18n/messages/zh.ts +69 -0
  1377. package/src/index.ts +56 -0
  1378. package/src/internal-urls/agent-protocol.ts +176 -0
  1379. package/src/internal-urls/artifact-protocol.ts +84 -0
  1380. package/src/internal-urls/docs-index.generated.ts +106 -0
  1381. package/src/internal-urls/index.ts +21 -0
  1382. package/src/internal-urls/issue-pr-protocol.ts +577 -0
  1383. package/src/internal-urls/json-query.ts +126 -0
  1384. package/src/internal-urls/local-protocol.ts +249 -0
  1385. package/src/internal-urls/mcp-protocol.ts +151 -0
  1386. package/src/internal-urls/memory-protocol.ts +165 -0
  1387. package/src/internal-urls/parse.ts +72 -0
  1388. package/src/internal-urls/registry-helpers.ts +28 -0
  1389. package/src/internal-urls/router.ts +78 -0
  1390. package/src/internal-urls/rule-protocol.ts +38 -0
  1391. package/src/internal-urls/skc-protocol.ts +83 -0
  1392. package/src/internal-urls/skill-protocol.ts +103 -0
  1393. package/src/internal-urls/types.ts +114 -0
  1394. package/src/lsp/client.ts +1012 -0
  1395. package/src/lsp/clients/biome-client.ts +202 -0
  1396. package/src/lsp/clients/index.ts +50 -0
  1397. package/src/lsp/clients/lsp-linter-client.ts +93 -0
  1398. package/src/lsp/clients/swiftlint-client.ts +120 -0
  1399. package/src/lsp/config.ts +492 -0
  1400. package/src/lsp/defaults.json +494 -0
  1401. package/src/lsp/edits.ts +166 -0
  1402. package/src/lsp/index.ts +2283 -0
  1403. package/src/lsp/lspmux.ts +257 -0
  1404. package/src/lsp/render.ts +692 -0
  1405. package/src/lsp/startup-events.ts +13 -0
  1406. package/src/lsp/types.ts +445 -0
  1407. package/src/lsp/utils.ts +678 -0
  1408. package/src/main.ts +1080 -0
  1409. package/src/memories/index.ts +1137 -0
  1410. package/src/memories/storage.ts +577 -0
  1411. package/src/memory-backend/index.ts +4 -0
  1412. package/src/memory-backend/local-backend.ts +38 -0
  1413. package/src/memory-backend/off-backend.ts +16 -0
  1414. package/src/memory-backend/resolve.ts +24 -0
  1415. package/src/memory-backend/types.ts +79 -0
  1416. package/src/modes/acp/acp-agent.ts +2203 -0
  1417. package/src/modes/acp/acp-client-bridge.ts +154 -0
  1418. package/src/modes/acp/acp-event-mapper.ts +911 -0
  1419. package/src/modes/acp/acp-mode.ts +23 -0
  1420. package/src/modes/acp/index.ts +2 -0
  1421. package/src/modes/acp/terminal-auth.ts +37 -0
  1422. package/src/modes/bridge/auth.ts +41 -0
  1423. package/src/modes/bridge/bridge-client-bridge.ts +47 -0
  1424. package/src/modes/bridge/bridge-mode.ts +664 -0
  1425. package/src/modes/bridge/bridge-ui-context.ts +200 -0
  1426. package/src/modes/bridge/event-stream.ts +70 -0
  1427. package/src/modes/components/agent-dashboard.ts +1120 -0
  1428. package/src/modes/components/assistant-message.ts +255 -0
  1429. package/src/modes/components/bash-execution.ts +232 -0
  1430. package/src/modes/components/bordered-loader.ts +41 -0
  1431. package/src/modes/components/branch-summary-message.ts +45 -0
  1432. package/src/modes/components/btw-panel.ts +104 -0
  1433. package/src/modes/components/compaction-summary-message.ts +51 -0
  1434. package/src/modes/components/countdown-timer.ts +75 -0
  1435. package/src/modes/components/custom-editor.ts +363 -0
  1436. package/src/modes/components/custom-message.ts +65 -0
  1437. package/src/modes/components/custom-model-preset-wizard.ts +293 -0
  1438. package/src/modes/components/custom-provider-wizard.ts +318 -0
  1439. package/src/modes/components/diff.ts +363 -0
  1440. package/src/modes/components/dynamic-border.ts +25 -0
  1441. package/src/modes/components/eval-execution.ts +168 -0
  1442. package/src/modes/components/execution-shared.ts +102 -0
  1443. package/src/modes/components/extensions/extension-dashboard.ts +350 -0
  1444. package/src/modes/components/extensions/extension-list.ts +492 -0
  1445. package/src/modes/components/extensions/index.ts +9 -0
  1446. package/src/modes/components/extensions/inspector-panel.ts +317 -0
  1447. package/src/modes/components/extensions/state-manager.ts +628 -0
  1448. package/src/modes/components/extensions/types.ts +191 -0
  1449. package/src/modes/components/footer.ts +270 -0
  1450. package/src/modes/components/history-search.ts +162 -0
  1451. package/src/modes/components/hook-editor.ts +151 -0
  1452. package/src/modes/components/hook-input.ts +79 -0
  1453. package/src/modes/components/hook-message.ts +68 -0
  1454. package/src/modes/components/hook-selector.ts +582 -0
  1455. package/src/modes/components/index.ts +36 -0
  1456. package/src/modes/components/jobs-overlay-model.ts +109 -0
  1457. package/src/modes/components/jobs-overlay.ts +172 -0
  1458. package/src/modes/components/keybinding-hints.ts +65 -0
  1459. package/src/modes/components/login-dialog.ts +164 -0
  1460. package/src/modes/components/message-frame.ts +88 -0
  1461. package/src/modes/components/model-selector.ts +1477 -0
  1462. package/src/modes/components/oauth-selector.ts +253 -0
  1463. package/src/modes/components/plugin-selector.ts +95 -0
  1464. package/src/modes/components/plugin-settings.ts +488 -0
  1465. package/src/modes/components/provider-onboarding-selector.ts +98 -0
  1466. package/src/modes/components/queue-mode-selector.ts +56 -0
  1467. package/src/modes/components/read-tool-group.ts +267 -0
  1468. package/src/modes/components/runtime-mcp-add-wizard.ts +1392 -0
  1469. package/src/modes/components/session-observer-overlay.ts +839 -0
  1470. package/src/modes/components/session-selector.ts +343 -0
  1471. package/src/modes/components/settings-defs.ts +175 -0
  1472. package/src/modes/components/settings-selector.ts +662 -0
  1473. package/src/modes/components/show-images-selector.ts +45 -0
  1474. package/src/modes/components/skill-hud/render.ts +83 -0
  1475. package/src/modes/components/skill-message.ts +152 -0
  1476. package/src/modes/components/status-line/context-thresholds.ts +68 -0
  1477. package/src/modes/components/status-line/git-utils.ts +42 -0
  1478. package/src/modes/components/status-line/index.ts +4 -0
  1479. package/src/modes/components/status-line/presets.ts +119 -0
  1480. package/src/modes/components/status-line/segments.ts +590 -0
  1481. package/src/modes/components/status-line/separators.ts +55 -0
  1482. package/src/modes/components/status-line/token-rate.ts +66 -0
  1483. package/src/modes/components/status-line/types.ts +92 -0
  1484. package/src/modes/components/status-line.ts +853 -0
  1485. package/src/modes/components/theme-selector.ts +63 -0
  1486. package/src/modes/components/thinking-selector.ts +52 -0
  1487. package/src/modes/components/todo-reminder.ts +40 -0
  1488. package/src/modes/components/tool-execution.ts +853 -0
  1489. package/src/modes/components/tree-selector.ts +930 -0
  1490. package/src/modes/components/ttsr-notification.ts +80 -0
  1491. package/src/modes/components/user-message-selector.ts +141 -0
  1492. package/src/modes/components/user-message.ts +51 -0
  1493. package/src/modes/components/visual-truncate.ts +63 -0
  1494. package/src/modes/components/welcome.ts +409 -0
  1495. package/src/modes/controllers/btw-controller.ts +105 -0
  1496. package/src/modes/controllers/command-controller-shared.ts +108 -0
  1497. package/src/modes/controllers/command-controller.ts +1672 -0
  1498. package/src/modes/controllers/event-controller.ts +852 -0
  1499. package/src/modes/controllers/extension-ui-controller.ts +1017 -0
  1500. package/src/modes/controllers/input-controller.ts +1047 -0
  1501. package/src/modes/controllers/runtime-mcp-command-controller.ts +1934 -0
  1502. package/src/modes/controllers/selector-controller.ts +1407 -0
  1503. package/src/modes/controllers/ssh-command-controller.ts +384 -0
  1504. package/src/modes/controllers/todo-command-controller.ts +485 -0
  1505. package/src/modes/data/emojis.json +1 -0
  1506. package/src/modes/emoji-autocomplete.ts +285 -0
  1507. package/src/modes/index.ts +35 -0
  1508. package/src/modes/interactive-mode.ts +2677 -0
  1509. package/src/modes/jobs-observer.ts +204 -0
  1510. package/src/modes/oauth-manual-input.ts +42 -0
  1511. package/src/modes/print-mode.ts +131 -0
  1512. package/src/modes/prompt-action-autocomplete.ts +409 -0
  1513. package/src/modes/rpc/host-tools.ts +1 -0
  1514. package/src/modes/rpc/host-uris.ts +1 -0
  1515. package/src/modes/rpc/rpc-client.ts +1085 -0
  1516. package/src/modes/rpc/rpc-mode.ts +808 -0
  1517. package/src/modes/rpc/rpc-socket-security.ts +103 -0
  1518. package/src/modes/rpc/rpc-types.ts +613 -0
  1519. package/src/modes/runtime-init.ts +116 -0
  1520. package/src/modes/session-observer-registry.ts +146 -0
  1521. package/src/modes/shared/agent-wire/approval-gate.ts +151 -0
  1522. package/src/modes/shared/agent-wire/command-contract.ts +18 -0
  1523. package/src/modes/shared/agent-wire/command-dispatch.ts +466 -0
  1524. package/src/modes/shared/agent-wire/command-validation.ts +167 -0
  1525. package/src/modes/shared/agent-wire/deep-interview-gate.ts +251 -0
  1526. package/src/modes/shared/agent-wire/event-contract.ts +147 -0
  1527. package/src/modes/shared/agent-wire/event-envelope.ts +140 -0
  1528. package/src/modes/shared/agent-wire/event-observation.ts +397 -0
  1529. package/src/modes/shared/agent-wire/handshake.ts +157 -0
  1530. package/src/modes/shared/agent-wire/host-tool-bridge.ts +197 -0
  1531. package/src/modes/shared/agent-wire/host-uri-bridge.ts +236 -0
  1532. package/src/modes/shared/agent-wire/protocol.ts +46 -0
  1533. package/src/modes/shared/agent-wire/responses.ts +17 -0
  1534. package/src/modes/shared/agent-wire/scopes.ts +92 -0
  1535. package/src/modes/shared/agent-wire/session-registry.ts +109 -0
  1536. package/src/modes/shared/agent-wire/ui-request-broker.ts +150 -0
  1537. package/src/modes/shared/agent-wire/ui-result.ts +48 -0
  1538. package/src/modes/shared/agent-wire/unattended-action-policy.ts +365 -0
  1539. package/src/modes/shared/agent-wire/unattended-audit.ts +175 -0
  1540. package/src/modes/shared/agent-wire/unattended-run-controller.ts +426 -0
  1541. package/src/modes/shared/agent-wire/unattended-session.ts +219 -0
  1542. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +324 -0
  1543. package/src/modes/shared/agent-wire/workflow-gate-schema.ts +331 -0
  1544. package/src/modes/shared.ts +55 -0
  1545. package/src/modes/theme/defaults/blue-octopus.json +126 -0
  1546. package/src/modes/theme/defaults/claude-code.json +100 -0
  1547. package/src/modes/theme/defaults/codex.json +100 -0
  1548. package/src/modes/theme/defaults/index.ts +13 -0
  1549. package/src/modes/theme/defaults/opencode.json +102 -0
  1550. package/src/modes/theme/defaults/red-octopus.json +123 -0
  1551. package/src/modes/theme/mermaid-cache.ts +29 -0
  1552. package/src/modes/theme/shimmer.ts +219 -0
  1553. package/src/modes/theme/theme-schema.json +429 -0
  1554. package/src/modes/theme/theme.ts +2452 -0
  1555. package/src/modes/types.ts +313 -0
  1556. package/src/modes/utils/abort-message.ts +41 -0
  1557. package/src/modes/utils/context-usage.ts +391 -0
  1558. package/src/modes/utils/hotkeys-markdown.ts +61 -0
  1559. package/src/modes/utils/keybinding-matchers.ts +30 -0
  1560. package/src/modes/utils/tools-markdown.ts +27 -0
  1561. package/src/modes/utils/ui-helpers.ts +749 -0
  1562. package/src/plan-mode/approved-plan.ts +163 -0
  1563. package/src/plan-mode/state.ts +6 -0
  1564. package/src/prompts/agents/architect.md +92 -0
  1565. package/src/prompts/agents/critic.md +65 -0
  1566. package/src/prompts/agents/executor.md +63 -0
  1567. package/src/prompts/agents/explore.md +58 -0
  1568. package/src/prompts/agents/frontmatter.md +14 -0
  1569. package/src/prompts/agents/init.md +34 -0
  1570. package/src/prompts/agents/plan.md +49 -0
  1571. package/src/prompts/agents/planner.md +60 -0
  1572. package/src/prompts/agents/reviewer.md +141 -0
  1573. package/src/prompts/agents/task.md +16 -0
  1574. package/src/prompts/ci-green-request.md +36 -0
  1575. package/src/prompts/goals/goal-continuation.md +26 -0
  1576. package/src/prompts/goals/goal-mode-active.md +22 -0
  1577. package/src/prompts/memories/consolidation.md +30 -0
  1578. package/src/prompts/memories/read-path.md +10 -0
  1579. package/src/prompts/memories/stage_one_input.md +6 -0
  1580. package/src/prompts/memories/stage_one_system.md +21 -0
  1581. package/src/prompts/memories/unavailable.md +9 -0
  1582. package/src/prompts/review-request.md +70 -0
  1583. package/src/prompts/system/agent-creation-architect.md +75 -0
  1584. package/src/prompts/system/agent-creation-user.md +6 -0
  1585. package/src/prompts/system/auto-continue.md +1 -0
  1586. package/src/prompts/system/btw-user.md +8 -0
  1587. package/src/prompts/system/commit-message-system.md +2 -0
  1588. package/src/prompts/system/custom-system-prompt.md +64 -0
  1589. package/src/prompts/system/eager-todo.md +13 -0
  1590. package/src/prompts/system/irc-incoming.md +8 -0
  1591. package/src/prompts/system/plan-mode-active.md +116 -0
  1592. package/src/prompts/system/plan-mode-approved.md +28 -0
  1593. package/src/prompts/system/plan-mode-compact-instructions.md +16 -0
  1594. package/src/prompts/system/plan-mode-reference.md +14 -0
  1595. package/src/prompts/system/plan-mode-subagent.md +34 -0
  1596. package/src/prompts/system/plan-mode-tool-decision-reminder.md +9 -0
  1597. package/src/prompts/system/project-prompt.md +46 -0
  1598. package/src/prompts/system/rlm-report-command.md +1 -0
  1599. package/src/prompts/system/rlm-research.md +23 -0
  1600. package/src/prompts/system/subagent-system-prompt.md +60 -0
  1601. package/src/prompts/system/subagent-user-prompt.md +3 -0
  1602. package/src/prompts/system/subagent-yield-reminder.md +12 -0
  1603. package/src/prompts/system/system-prompt.md +275 -0
  1604. package/src/prompts/system/title-system.md +2 -0
  1605. package/src/prompts/system/ttsr-interrupt.md +7 -0
  1606. package/src/prompts/system/ttsr-tool-reminder.md +5 -0
  1607. package/src/prompts/system/web-search.md +25 -0
  1608. package/src/prompts/tools/apply-patch.md +65 -0
  1609. package/src/prompts/tools/ask.md +29 -0
  1610. package/src/prompts/tools/ast-edit.md +39 -0
  1611. package/src/prompts/tools/ast-grep.md +42 -0
  1612. package/src/prompts/tools/async-result.md +8 -0
  1613. package/src/prompts/tools/bash.md +69 -0
  1614. package/src/prompts/tools/browser.md +75 -0
  1615. package/src/prompts/tools/calculator.md +10 -0
  1616. package/src/prompts/tools/checkpoint.md +16 -0
  1617. package/src/prompts/tools/computer.md +74 -0
  1618. package/src/prompts/tools/cron.md +25 -0
  1619. package/src/prompts/tools/debug.md +33 -0
  1620. package/src/prompts/tools/eval.md +75 -0
  1621. package/src/prompts/tools/find.md +34 -0
  1622. package/src/prompts/tools/github.md +20 -0
  1623. package/src/prompts/tools/goal.md +21 -0
  1624. package/src/prompts/tools/hashline.md +130 -0
  1625. package/src/prompts/tools/image-gen.md +7 -0
  1626. package/src/prompts/tools/inspect-image-system.md +20 -0
  1627. package/src/prompts/tools/inspect-image.md +32 -0
  1628. package/src/prompts/tools/irc.md +49 -0
  1629. package/src/prompts/tools/job.md +27 -0
  1630. package/src/prompts/tools/lsp.md +42 -0
  1631. package/src/prompts/tools/monitor.md +30 -0
  1632. package/src/prompts/tools/patch.md +70 -0
  1633. package/src/prompts/tools/read.md +82 -0
  1634. package/src/prompts/tools/recall.md +6 -0
  1635. package/src/prompts/tools/recipe.md +16 -0
  1636. package/src/prompts/tools/reflect.md +6 -0
  1637. package/src/prompts/tools/render-mermaid.md +9 -0
  1638. package/src/prompts/tools/replace.md +36 -0
  1639. package/src/prompts/tools/resolve.md +9 -0
  1640. package/src/prompts/tools/retain.md +7 -0
  1641. package/src/prompts/tools/rewind.md +13 -0
  1642. package/src/prompts/tools/search-tool-bm25.md +33 -0
  1643. package/src/prompts/tools/search.md +25 -0
  1644. package/src/prompts/tools/skill.md +28 -0
  1645. package/src/prompts/tools/ssh.md +35 -0
  1646. package/src/prompts/tools/subagent.md +56 -0
  1647. package/src/prompts/tools/task-summary.md +22 -0
  1648. package/src/prompts/tools/task.md +86 -0
  1649. package/src/prompts/tools/todo-write.md +50 -0
  1650. package/src/prompts/tools/vim.md +98 -0
  1651. package/src/prompts/tools/web-search.md +17 -0
  1652. package/src/prompts/tools/write.md +14 -0
  1653. package/src/registry/agent-registry.ts +140 -0
  1654. package/src/reminders/star-reminder.ts +420 -0
  1655. package/src/rlm/artifacts.ts +60 -0
  1656. package/src/rlm/complete-research-tool.ts +163 -0
  1657. package/src/rlm/data-context.ts +26 -0
  1658. package/src/rlm/index.ts +339 -0
  1659. package/src/rlm/notebook.ts +108 -0
  1660. package/src/rlm/preset.ts +76 -0
  1661. package/src/rlm/python-tool.ts +68 -0
  1662. package/src/rlm/report.ts +70 -0
  1663. package/src/rlm/types.ts +40 -0
  1664. package/src/runtime/process-lifecycle.ts +400 -0
  1665. package/src/runtime-mcp/client.ts +485 -0
  1666. package/src/runtime-mcp/config-writer.ts +225 -0
  1667. package/src/runtime-mcp/config.ts +365 -0
  1668. package/src/runtime-mcp/discoverable-tool-metadata.ts +25 -0
  1669. package/src/runtime-mcp/index.ts +29 -0
  1670. package/src/runtime-mcp/json-rpc.ts +84 -0
  1671. package/src/runtime-mcp/loader.ts +124 -0
  1672. package/src/runtime-mcp/manager.ts +1331 -0
  1673. package/src/runtime-mcp/oauth-discovery.ts +349 -0
  1674. package/src/runtime-mcp/oauth-flow.ts +409 -0
  1675. package/src/runtime-mcp/render.ts +123 -0
  1676. package/src/runtime-mcp/smithery-auth.ts +104 -0
  1677. package/src/runtime-mcp/smithery-connect.ts +145 -0
  1678. package/src/runtime-mcp/smithery-registry.ts +477 -0
  1679. package/src/runtime-mcp/tool-bridge.ts +416 -0
  1680. package/src/runtime-mcp/tool-cache.ts +117 -0
  1681. package/src/runtime-mcp/transports/http.ts +504 -0
  1682. package/src/runtime-mcp/transports/index.ts +6 -0
  1683. package/src/runtime-mcp/transports/stdio.ts +352 -0
  1684. package/src/runtime-mcp/types.ts +426 -0
  1685. package/src/sdk.ts +2290 -0
  1686. package/src/secrets/index.ts +116 -0
  1687. package/src/secrets/obfuscator.ts +352 -0
  1688. package/src/secrets/regex.ts +21 -0
  1689. package/src/session/agent-session.ts +10226 -0
  1690. package/src/session/agent-storage.ts +466 -0
  1691. package/src/session/artifacts.ts +150 -0
  1692. package/src/session/auth-broker-config.ts +102 -0
  1693. package/src/session/auth-storage.ts +23 -0
  1694. package/src/session/blob-store.ts +428 -0
  1695. package/src/session/client-bridge.ts +85 -0
  1696. package/src/session/contribution-prep.ts +320 -0
  1697. package/src/session/history-storage.ts +332 -0
  1698. package/src/session/messages.ts +406 -0
  1699. package/src/session/session-dump-format.ts +209 -0
  1700. package/src/session/session-manager.ts +4049 -0
  1701. package/src/session/session-storage.ts +415 -0
  1702. package/src/session/streaming-output.ts +1269 -0
  1703. package/src/session/tool-choice-queue.ts +236 -0
  1704. package/src/session/yield-queue.ts +155 -0
  1705. package/src/setup/credential-import.ts +429 -0
  1706. package/src/setup/hermes/templates/operator-instructions.v1.md +36 -0
  1707. package/src/setup/hermes-setup.ts +484 -0
  1708. package/src/setup/model-onboarding-guidance.ts +48 -0
  1709. package/src/setup/provider-onboarding.ts +358 -0
  1710. package/src/skc-runtime/cli-write-receipt.ts +31 -0
  1711. package/src/skc-runtime/deep-interview-recorder.ts +457 -0
  1712. package/src/skc-runtime/deep-interview-runtime.ts +639 -0
  1713. package/src/skc-runtime/deep-interview-state.ts +324 -0
  1714. package/src/skc-runtime/gc-render.ts +70 -0
  1715. package/src/skc-runtime/gc-runtime.ts +403 -0
  1716. package/src/skc-runtime/goal-mode-request.ts +223 -0
  1717. package/src/skc-runtime/launch-tmux.ts +423 -0
  1718. package/src/skc-runtime/launch-worktree.ts +302 -0
  1719. package/src/skc-runtime/ledger-event-renderer.ts +164 -0
  1720. package/src/skc-runtime/ralplan-runtime.ts +877 -0
  1721. package/src/skc-runtime/restricted-role-agent-bash.ts +5 -0
  1722. package/src/skc-runtime/session-state-sidecar.ts +177 -0
  1723. package/src/skc-runtime/state-graph.ts +86 -0
  1724. package/src/skc-runtime/state-migrations.ts +179 -0
  1725. package/src/skc-runtime/state-renderer.ts +354 -0
  1726. package/src/skc-runtime/state-runtime.ts +2023 -0
  1727. package/src/skc-runtime/state-schema.ts +192 -0
  1728. package/src/skc-runtime/state-validation.ts +49 -0
  1729. package/src/skc-runtime/state-writer.ts +1012 -0
  1730. package/src/skc-runtime/team-gc.ts +49 -0
  1731. package/src/skc-runtime/team-runtime.ts +4355 -0
  1732. package/src/skc-runtime/tmux-common.ts +172 -0
  1733. package/src/skc-runtime/tmux-gc.ts +239 -0
  1734. package/src/skc-runtime/tmux-sessions.ts +271 -0
  1735. package/src/skc-runtime/ultragoal-guard.ts +455 -0
  1736. package/src/skc-runtime/ultragoal-runtime.ts +3684 -0
  1737. package/src/skc-runtime/workflow-command-ref.ts +239 -0
  1738. package/src/skc-runtime/workflow-manifest.generated.json +1676 -0
  1739. package/src/skc-runtime/workflow-manifest.ts +454 -0
  1740. package/src/skill-state/active-state.ts +839 -0
  1741. package/src/skill-state/deep-interview-mutation-guard.ts +452 -0
  1742. package/src/skill-state/initial-phase.ts +19 -0
  1743. package/src/skill-state/workflow-hud.ts +274 -0
  1744. package/src/skill-state/workflow-state-contract.ts +150 -0
  1745. package/src/skill-state/workflow-state-version.ts +3 -0
  1746. package/src/slash-commands/acp-builtins.ts +55 -0
  1747. package/src/slash-commands/builtin-registry.ts +1206 -0
  1748. package/src/slash-commands/helpers/context-report.ts +149 -0
  1749. package/src/slash-commands/helpers/fast-status-report.ts +111 -0
  1750. package/src/slash-commands/helpers/format.ts +46 -0
  1751. package/src/slash-commands/helpers/mcp.ts +532 -0
  1752. package/src/slash-commands/helpers/parse.ts +85 -0
  1753. package/src/slash-commands/helpers/ssh.ts +195 -0
  1754. package/src/slash-commands/helpers/todo.ts +279 -0
  1755. package/src/slash-commands/helpers/usage-report.ts +91 -0
  1756. package/src/slash-commands/types.ts +125 -0
  1757. package/src/ssh/config-writer.ts +183 -0
  1758. package/src/ssh/connection-manager.ts +482 -0
  1759. package/src/ssh/ssh-executor.ts +133 -0
  1760. package/src/ssh/sshfs-mount.ts +140 -0
  1761. package/src/ssh/utils.ts +8 -0
  1762. package/src/stt/downloader.ts +71 -0
  1763. package/src/stt/index.ts +3 -0
  1764. package/src/stt/recorder.ts +351 -0
  1765. package/src/stt/setup.ts +52 -0
  1766. package/src/stt/stt-controller.ts +160 -0
  1767. package/src/stt/transcribe.py +70 -0
  1768. package/src/stt/transcriber.ts +91 -0
  1769. package/src/system-prompt.ts +581 -0
  1770. package/src/task/agents.ts +164 -0
  1771. package/src/task/commands.ts +131 -0
  1772. package/src/task/discovery.ts +136 -0
  1773. package/src/task/executor.ts +1733 -0
  1774. package/src/task/fork-context-advisory.ts +99 -0
  1775. package/src/task/id.ts +33 -0
  1776. package/src/task/index.ts +1788 -0
  1777. package/src/task/name-generator.ts +1577 -0
  1778. package/src/task/output-manager.ts +108 -0
  1779. package/src/task/parallel.ts +116 -0
  1780. package/src/task/receipt.ts +304 -0
  1781. package/src/task/render.ts +1101 -0
  1782. package/src/task/roi-reconciliation.ts +90 -0
  1783. package/src/task/simple-mode.ts +27 -0
  1784. package/src/task/skc-command.ts +26 -0
  1785. package/src/task/spawn-gate.ts +132 -0
  1786. package/src/task/subprocess-tool-registry.ts +88 -0
  1787. package/src/task/types.ts +431 -0
  1788. package/src/task/worktree.ts +506 -0
  1789. package/src/thinking-metadata.ts +51 -0
  1790. package/src/thinking.ts +73 -0
  1791. package/src/tool-discovery/tool-index.ts +400 -0
  1792. package/src/tools/archive-reader.ts +330 -0
  1793. package/src/tools/ask.ts +998 -0
  1794. package/src/tools/ast-edit.ts +550 -0
  1795. package/src/tools/ast-grep.ts +424 -0
  1796. package/src/tools/auto-generated-guard.ts +305 -0
  1797. package/src/tools/bash-allowed-prefixes.ts +252 -0
  1798. package/src/tools/bash-command-fixup.ts +37 -0
  1799. package/src/tools/bash-interactive.ts +388 -0
  1800. package/src/tools/bash-interceptor.ts +67 -0
  1801. package/src/tools/bash-pty-selection.ts +14 -0
  1802. package/src/tools/bash-skill-urls.ts +248 -0
  1803. package/src/tools/bash.ts +1302 -0
  1804. package/src/tools/browser/actions.ts +189 -0
  1805. package/src/tools/browser/attach.ts +275 -0
  1806. package/src/tools/browser/launch.ts +651 -0
  1807. package/src/tools/browser/readable.ts +95 -0
  1808. package/src/tools/browser/registry.ts +384 -0
  1809. package/src/tools/browser/render.ts +220 -0
  1810. package/src/tools/browser/tab-protocol.ts +105 -0
  1811. package/src/tools/browser/tab-supervisor.ts +599 -0
  1812. package/src/tools/browser/tab-worker-entry.ts +21 -0
  1813. package/src/tools/browser/tab-worker.ts +1054 -0
  1814. package/src/tools/browser.ts +458 -0
  1815. package/src/tools/calculator.ts +540 -0
  1816. package/src/tools/checkpoint.ts +134 -0
  1817. package/src/tools/computer/render.ts +78 -0
  1818. package/src/tools/computer.ts +640 -0
  1819. package/src/tools/conflict-detect.ts +672 -0
  1820. package/src/tools/context.ts +39 -0
  1821. package/src/tools/cron.ts +709 -0
  1822. package/src/tools/debug.ts +1014 -0
  1823. package/src/tools/eval.ts +1101 -0
  1824. package/src/tools/fetch.ts +1482 -0
  1825. package/src/tools/file-recorder.ts +35 -0
  1826. package/src/tools/find.ts +543 -0
  1827. package/src/tools/fs-cache-invalidation.ts +28 -0
  1828. package/src/tools/gh-format.ts +12 -0
  1829. package/src/tools/gh-renderer.ts +428 -0
  1830. package/src/tools/gh.ts +3737 -0
  1831. package/src/tools/github-cache.ts +548 -0
  1832. package/src/tools/grouped-file-output.ts +96 -0
  1833. package/src/tools/hindsight-recall.ts +66 -0
  1834. package/src/tools/hindsight-reflect.ts +55 -0
  1835. package/src/tools/hindsight-retain.ts +54 -0
  1836. package/src/tools/image-gen.ts +1284 -0
  1837. package/src/tools/index.ts +595 -0
  1838. package/src/tools/inspect-image-renderer.ts +103 -0
  1839. package/src/tools/inspect-image.ts +167 -0
  1840. package/src/tools/irc.ts +239 -0
  1841. package/src/tools/job.ts +614 -0
  1842. package/src/tools/json-tree.ts +256 -0
  1843. package/src/tools/jtd-to-json-schema.ts +219 -0
  1844. package/src/tools/jtd-to-typescript.ts +136 -0
  1845. package/src/tools/jtd-utils.ts +102 -0
  1846. package/src/tools/list-limit.ts +40 -0
  1847. package/src/tools/match-line-format.ts +22 -0
  1848. package/src/tools/monitor.ts +252 -0
  1849. package/src/tools/output-meta.ts +754 -0
  1850. package/src/tools/path-utils.ts +741 -0
  1851. package/src/tools/plan-mode-guard.ts +68 -0
  1852. package/src/tools/puppeteer/00_stealth_tampering.txt +63 -0
  1853. package/src/tools/puppeteer/01_stealth_activity.txt +20 -0
  1854. package/src/tools/puppeteer/02_stealth_hairline.txt +11 -0
  1855. package/src/tools/puppeteer/03_stealth_botd.txt +384 -0
  1856. package/src/tools/puppeteer/04_stealth_iframe.txt +81 -0
  1857. package/src/tools/puppeteer/05_stealth_webgl.txt +75 -0
  1858. package/src/tools/puppeteer/06_stealth_screen.txt +72 -0
  1859. package/src/tools/puppeteer/07_stealth_fonts.txt +97 -0
  1860. package/src/tools/puppeteer/08_stealth_audio.txt +51 -0
  1861. package/src/tools/puppeteer/09_stealth_locale.txt +46 -0
  1862. package/src/tools/puppeteer/10_stealth_plugins.txt +206 -0
  1863. package/src/tools/puppeteer/11_stealth_hardware.txt +8 -0
  1864. package/src/tools/puppeteer/12_stealth_codecs.txt +40 -0
  1865. package/src/tools/puppeteer/13_stealth_worker.txt +74 -0
  1866. package/src/tools/read.ts +2332 -0
  1867. package/src/tools/recipe/index.ts +80 -0
  1868. package/src/tools/recipe/render.ts +19 -0
  1869. package/src/tools/recipe/runner.ts +219 -0
  1870. package/src/tools/recipe/runners/cargo.ts +131 -0
  1871. package/src/tools/recipe/runners/index.ts +8 -0
  1872. package/src/tools/recipe/runners/just.ts +73 -0
  1873. package/src/tools/recipe/runners/make.ts +101 -0
  1874. package/src/tools/recipe/runners/pkg.ts +167 -0
  1875. package/src/tools/recipe/runners/task.ts +72 -0
  1876. package/src/tools/render-mermaid.ts +68 -0
  1877. package/src/tools/render-utils.ts +774 -0
  1878. package/src/tools/renderers.ts +79 -0
  1879. package/src/tools/resolve.ts +333 -0
  1880. package/src/tools/review.ts +252 -0
  1881. package/src/tools/search-tool-bm25.ts +360 -0
  1882. package/src/tools/search.ts +787 -0
  1883. package/src/tools/skill.ts +170 -0
  1884. package/src/tools/sqlite-reader.ts +750 -0
  1885. package/src/tools/ssh.ts +310 -0
  1886. package/src/tools/subagent-render.ts +268 -0
  1887. package/src/tools/subagent.ts +862 -0
  1888. package/src/tools/todo-write.ts +695 -0
  1889. package/src/tools/tool-errors.ts +62 -0
  1890. package/src/tools/tool-result.ts +86 -0
  1891. package/src/tools/tool-timeouts.ts +31 -0
  1892. package/src/tools/ultragoal-ask-guard.ts +39 -0
  1893. package/src/tools/vim.ts +949 -0
  1894. package/src/tools/write.ts +953 -0
  1895. package/src/tools/yield.ts +268 -0
  1896. package/src/tui/code-cell.ts +201 -0
  1897. package/src/tui/file-list.ts +55 -0
  1898. package/src/tui/hyperlink.ts +126 -0
  1899. package/src/tui/index.ts +12 -0
  1900. package/src/tui/output-block.ts +150 -0
  1901. package/src/tui/status-line.ts +39 -0
  1902. package/src/tui/tree-list.ts +84 -0
  1903. package/src/tui/types.ts +15 -0
  1904. package/src/tui/utils.ts +103 -0
  1905. package/src/utils/changelog.ts +121 -0
  1906. package/src/utils/clipboard.ts +156 -0
  1907. package/src/utils/command-args.ts +76 -0
  1908. package/src/utils/commit-message-generator.ts +135 -0
  1909. package/src/utils/edit-mode.ts +42 -0
  1910. package/src/utils/event-bus.ts +33 -0
  1911. package/src/utils/external-editor.ts +65 -0
  1912. package/src/utils/file-display-mode.ts +45 -0
  1913. package/src/utils/file-mentions.ts +376 -0
  1914. package/src/utils/git.ts +1536 -0
  1915. package/src/utils/image-loading.ts +102 -0
  1916. package/src/utils/image-resize.ts +309 -0
  1917. package/src/utils/lang-from-path.ts +239 -0
  1918. package/src/utils/markit.ts +89 -0
  1919. package/src/utils/open.ts +20 -0
  1920. package/src/utils/session-color.ts +43 -0
  1921. package/src/utils/shell-snapshot.ts +187 -0
  1922. package/src/utils/sixel.ts +69 -0
  1923. package/src/utils/title-generator.ts +237 -0
  1924. package/src/utils/tool-choice.ts +62 -0
  1925. package/src/utils/tools-manager.ts +363 -0
  1926. package/src/vim/buffer.ts +309 -0
  1927. package/src/vim/commands.ts +382 -0
  1928. package/src/vim/engine.ts +2409 -0
  1929. package/src/vim/parser.ts +134 -0
  1930. package/src/vim/render.ts +252 -0
  1931. package/src/vim/types.ts +197 -0
  1932. package/src/web/kagi.ts +183 -0
  1933. package/src/web/parallel.ts +349 -0
  1934. package/src/web/scrapers/artifacthub.ts +207 -0
  1935. package/src/web/scrapers/arxiv.ts +83 -0
  1936. package/src/web/scrapers/aur.ts +162 -0
  1937. package/src/web/scrapers/biorxiv.ts +133 -0
  1938. package/src/web/scrapers/bluesky.ts +262 -0
  1939. package/src/web/scrapers/brew.ts +172 -0
  1940. package/src/web/scrapers/cheatsh.ts +68 -0
  1941. package/src/web/scrapers/chocolatey.ts +196 -0
  1942. package/src/web/scrapers/choosealicense.ts +95 -0
  1943. package/src/web/scrapers/cisa-kev.ts +87 -0
  1944. package/src/web/scrapers/clojars.ts +154 -0
  1945. package/src/web/scrapers/coingecko.ts +177 -0
  1946. package/src/web/scrapers/crates-io.ts +97 -0
  1947. package/src/web/scrapers/crossref.ts +136 -0
  1948. package/src/web/scrapers/devto.ts +147 -0
  1949. package/src/web/scrapers/discogs.ts +306 -0
  1950. package/src/web/scrapers/discourse.ts +197 -0
  1951. package/src/web/scrapers/dockerhub.ts +138 -0
  1952. package/src/web/scrapers/docs-rs.ts +653 -0
  1953. package/src/web/scrapers/fdroid.ts +134 -0
  1954. package/src/web/scrapers/firefox-addons.ts +191 -0
  1955. package/src/web/scrapers/flathub.ts +223 -0
  1956. package/src/web/scrapers/github-gist.ts +58 -0
  1957. package/src/web/scrapers/github.ts +452 -0
  1958. package/src/web/scrapers/gitlab.ts +401 -0
  1959. package/src/web/scrapers/go-pkg.ts +266 -0
  1960. package/src/web/scrapers/hackage.ts +140 -0
  1961. package/src/web/scrapers/hackernews.ts +189 -0
  1962. package/src/web/scrapers/hex.ts +105 -0
  1963. package/src/web/scrapers/huggingface.ts +321 -0
  1964. package/src/web/scrapers/iacr.ts +89 -0
  1965. package/src/web/scrapers/index.ts +252 -0
  1966. package/src/web/scrapers/jetbrains-marketplace.ts +159 -0
  1967. package/src/web/scrapers/lemmy.ts +203 -0
  1968. package/src/web/scrapers/lobsters.ts +175 -0
  1969. package/src/web/scrapers/mastodon.ts +292 -0
  1970. package/src/web/scrapers/maven.ts +138 -0
  1971. package/src/web/scrapers/mdn.ts +173 -0
  1972. package/src/web/scrapers/metacpan.ts +222 -0
  1973. package/src/web/scrapers/musicbrainz.ts +250 -0
  1974. package/src/web/scrapers/npm.ts +98 -0
  1975. package/src/web/scrapers/nuget.ts +183 -0
  1976. package/src/web/scrapers/nvd.ts +222 -0
  1977. package/src/web/scrapers/ollama.ts +239 -0
  1978. package/src/web/scrapers/open-vsx.ts +106 -0
  1979. package/src/web/scrapers/opencorporates.ts +292 -0
  1980. package/src/web/scrapers/openlibrary.ts +336 -0
  1981. package/src/web/scrapers/orcid.ts +286 -0
  1982. package/src/web/scrapers/osv.ts +176 -0
  1983. package/src/web/scrapers/packagist.ts +160 -0
  1984. package/src/web/scrapers/pub-dev.ts +143 -0
  1985. package/src/web/scrapers/pubmed.ts +211 -0
  1986. package/src/web/scrapers/pypi.ts +112 -0
  1987. package/src/web/scrapers/rawg.ts +110 -0
  1988. package/src/web/scrapers/readthedocs.ts +120 -0
  1989. package/src/web/scrapers/reddit.ts +95 -0
  1990. package/src/web/scrapers/repology.ts +251 -0
  1991. package/src/web/scrapers/rfc.ts +201 -0
  1992. package/src/web/scrapers/rubygems.ts +103 -0
  1993. package/src/web/scrapers/searchcode.ts +189 -0
  1994. package/src/web/scrapers/sec-edgar.ts +261 -0
  1995. package/src/web/scrapers/semantic-scholar.ts +171 -0
  1996. package/src/web/scrapers/snapcraft.ts +187 -0
  1997. package/src/web/scrapers/sourcegraph.ts +336 -0
  1998. package/src/web/scrapers/spdx.ts +108 -0
  1999. package/src/web/scrapers/spotify.ts +198 -0
  2000. package/src/web/scrapers/stackoverflow.ts +120 -0
  2001. package/src/web/scrapers/terraform.ts +277 -0
  2002. package/src/web/scrapers/tldr.ts +47 -0
  2003. package/src/web/scrapers/twitter.ts +93 -0
  2004. package/src/web/scrapers/types.ts +318 -0
  2005. package/src/web/scrapers/utils.ts +109 -0
  2006. package/src/web/scrapers/vimeo.ts +133 -0
  2007. package/src/web/scrapers/vscode-marketplace.ts +187 -0
  2008. package/src/web/scrapers/w3c.ts +156 -0
  2009. package/src/web/scrapers/wikidata.ts +344 -0
  2010. package/src/web/scrapers/wikipedia.ts +84 -0
  2011. package/src/web/scrapers/youtube.ts +319 -0
  2012. package/src/web/search/index.ts +326 -0
  2013. package/src/web/search/provider.ts +324 -0
  2014. package/src/web/search/providers/anthropic.ts +302 -0
  2015. package/src/web/search/providers/base.ts +94 -0
  2016. package/src/web/search/providers/brave.ts +149 -0
  2017. package/src/web/search/providers/codex.ts +557 -0
  2018. package/src/web/search/providers/duckduckgo.ts +279 -0
  2019. package/src/web/search/providers/exa.ts +197 -0
  2020. package/src/web/search/providers/gemini.ts +455 -0
  2021. package/src/web/search/providers/jina.ts +101 -0
  2022. package/src/web/search/providers/kagi.ts +75 -0
  2023. package/src/web/search/providers/kimi.ts +171 -0
  2024. package/src/web/search/providers/openai-compatible.ts +151 -0
  2025. package/src/web/search/providers/parallel.ts +210 -0
  2026. package/src/web/search/providers/perplexity.ts +575 -0
  2027. package/src/web/search/providers/searxng.ts +309 -0
  2028. package/src/web/search/providers/synthetic.ts +108 -0
  2029. package/src/web/search/providers/tavily.ts +173 -0
  2030. package/src/web/search/providers/utils.ts +128 -0
  2031. package/src/web/search/providers/xai.ts +511 -0
  2032. package/src/web/search/providers/zai.ts +320 -0
  2033. package/src/web/search/render.ts +306 -0
  2034. package/src/web/search/types.ts +473 -0
  2035. package/src/web/search/utils.ts +17 -0
  2036. package/src/workspace-tree.ts +286 -0
@@ -0,0 +1,3684 @@
1
+ import * as crypto from "node:crypto";
2
+ import * as path from "node:path";
3
+ import { inflateSync } from "node:zlib";
4
+
5
+ import type { WorkflowHudSummary } from "../skill-state/active-state";
6
+ import { buildUltragoalHudSummary as buildWorkflowUltragoalHudSummary } from "../skill-state/workflow-hud";
7
+ import { renderCliWriteReceipt } from "./cli-write-receipt";
8
+ import { DEFAULT_ULTRAGOAL_OBJECTIVE } from "./goal-mode-request";
9
+ import { latestUltragoalLedgerEventFromText } from "./ledger-event-renderer";
10
+ import { renderUltragoalStatusMarkdown } from "./state-renderer";
11
+ import { reconcileWorkflowSkillState } from "./state-runtime";
12
+ import { appendJsonl, writeArtifact, writeJsonAtomic } from "./state-writer";
13
+
14
+ export type UltragoalSkcGoalMode = "aggregate" | "per-story";
15
+ export type UltragoalGoalStatus =
16
+ | "pending"
17
+ | "active"
18
+ | "complete"
19
+ | "failed"
20
+ | "blocked"
21
+ | "review_blocked"
22
+ | "superseded";
23
+
24
+ export interface UltragoalGoal {
25
+ id: string;
26
+ title: string;
27
+ objective: string;
28
+ status: UltragoalGoalStatus;
29
+ createdAt: string;
30
+ updatedAt: string;
31
+ startedAt?: string;
32
+ completedAt?: string;
33
+ evidence?: string;
34
+ steering?: Record<string, unknown>;
35
+ completionVerification?: UltragoalCompletionVerification;
36
+ }
37
+
38
+ export interface UltragoalPlan {
39
+ version: 1;
40
+ brief: string;
41
+ skcGoalMode: UltragoalSkcGoalMode;
42
+ skcObjective: string;
43
+ skcObjectiveAliases?: string[];
44
+ goals: UltragoalGoal[];
45
+ createdAt: string;
46
+ updatedAt: string;
47
+ }
48
+
49
+ export type UltragoalReceiptKind = "per-goal" | "final-aggregate";
50
+
51
+ export interface UltragoalCompletionVerification {
52
+ schemaVersion: 1;
53
+ receiptId: string;
54
+ verifiedAt: string;
55
+ goalId: string;
56
+ receiptKind: UltragoalReceiptKind;
57
+ goalStatusBeforeCheckpoint: UltragoalGoalStatus;
58
+ skcGoalMode: UltragoalSkcGoalMode;
59
+ skcObjective: string;
60
+ qualityGateHash: string;
61
+ skcGoalSnapshotHash: string;
62
+ planGeneration: string;
63
+ basis: {
64
+ planHashBeforeCheckpoint: string;
65
+ latestRelevantLedgerEventIdBeforeCheckpoint: string | null;
66
+ goalUpdatedAtBeforeCheckpoint: string;
67
+ relevantGoalIdsBeforeCheckpoint: string[];
68
+ requiredGoalSetHashBeforeCheckpoint: string;
69
+ };
70
+ checkpointLedgerEventId: string;
71
+ }
72
+
73
+ export interface UltragoalLedgerEvent extends JsonObject {
74
+ eventId?: string;
75
+ event?: string;
76
+ goalId?: string;
77
+ timestamp?: string;
78
+ }
79
+
80
+ export interface UltragoalPaths {
81
+ dir: string;
82
+ briefPath: string;
83
+ goalsPath: string;
84
+ ledgerPath: string;
85
+ }
86
+
87
+ export interface UltragoalStatusSummary {
88
+ exists: boolean;
89
+ status: "missing" | "pending" | "active" | "complete" | "blocked" | "failed";
90
+ paths: UltragoalPaths;
91
+ skcObjective?: string;
92
+ currentGoal?: UltragoalGoal;
93
+ counts: Record<UltragoalGoalStatus, number>;
94
+ goals: UltragoalGoal[];
95
+ }
96
+
97
+ export interface UltragoalCommandResult {
98
+ reviewBlockerGoalIds?: string[];
99
+ createdReviewPlan?: boolean;
100
+ status: number;
101
+ stdout?: string;
102
+ stderr?: string;
103
+ createdPlan?: boolean;
104
+ }
105
+
106
+ interface JsonObject {
107
+ [key: string]: unknown;
108
+ }
109
+
110
+ const TERMINAL_OR_SKIPPED_STATUSES = new Set<UltragoalGoalStatus>(["complete", "superseded"]);
111
+ const CLEAN_ARCHITECT_STATUS = "CLEAR";
112
+ const APPROVE_RECOMMENDATION = "APPROVE";
113
+ const PASSED_STATUS = "passed";
114
+ const NOT_APPLICABLE_STATUS = "not_applicable";
115
+ const COVERED_STATUS = "covered";
116
+ const ACCEPTED_PROOF_STATUSES = new Set([COVERED_STATUS, "passed", "verified"]);
117
+ const MIN_SUBSTANTIVE_EVIDENCE_WORDS = 5;
118
+ const MIN_SUBSTANTIVE_EVIDENCE_CHARS = 32;
119
+
120
+ const SKC_GOAL_SNAPSHOT_MAX_AGE_MILLISECONDS = 10 * 60 * 1000;
121
+ const SKC_GOAL_SNAPSHOT_MAX_FUTURE_SKEW_MILLISECONDS = 60 * 1000;
122
+
123
+ const SCHEDULABLE_STATUSES = new Set<UltragoalGoalStatus>(["pending", "active", "failed"]);
124
+ const NATIVE_STEERING_KINDS = [
125
+ "add_subgoal",
126
+ "split_subgoal",
127
+ "reorder_pending",
128
+ "revise_pending_wording",
129
+ "annotate_ledger",
130
+ "mark_blocked_superseded",
131
+ ] as const;
132
+ type UltragoalSteeringKind = (typeof NATIVE_STEERING_KINDS)[number];
133
+ const NATIVE_STEERING_KIND_SET = new Set<string>(NATIVE_STEERING_KINDS);
134
+
135
+ interface ReplacementSpec {
136
+ title: string;
137
+ objective: string;
138
+ }
139
+
140
+ interface SteeringCommandResult {
141
+ kind: UltragoalSteeringKind;
142
+ message: string;
143
+ receipt: JsonObject;
144
+ }
145
+
146
+ function stableStructuredValue(value: unknown): unknown {
147
+ if (Array.isArray(value)) return value.map(item => stableStructuredValue(item));
148
+ if (typeof value !== "object" || value === null) return value;
149
+ const record = value as Record<string, unknown>;
150
+ const sorted: Record<string, unknown> = {};
151
+ for (const key of Object.keys(record).sort()) {
152
+ const item = record[key];
153
+ if (item !== undefined) sorted[key] = stableStructuredValue(item);
154
+ }
155
+ return sorted;
156
+ }
157
+
158
+ export function hashStructuredValue(value: unknown): string {
159
+ return crypto
160
+ .createHash("sha256")
161
+ .update(JSON.stringify(stableStructuredValue(value)))
162
+ .digest("hex");
163
+ }
164
+
165
+ export function getUltragoalPaths(cwd: string): UltragoalPaths {
166
+ const dir = path.join(cwd, ".skc", "ultragoal");
167
+ return {
168
+ dir,
169
+ briefPath: path.join(dir, "brief.md"),
170
+ goalsPath: path.join(dir, "goals.json"),
171
+ ledgerPath: path.join(dir, "ledger.jsonl"),
172
+ };
173
+ }
174
+
175
+ function isEnoent(error: unknown): boolean {
176
+ return (
177
+ typeof error === "object" && error !== null && "code" in error && (error as { code?: unknown }).code === "ENOENT"
178
+ );
179
+ }
180
+
181
+ async function appendLedger(cwd: string, event: JsonObject): Promise<UltragoalLedgerEvent> {
182
+ const paths = getUltragoalPaths(cwd);
183
+ const entry: UltragoalLedgerEvent = {
184
+ eventId: typeof event.eventId === "string" ? event.eventId : crypto.randomUUID(),
185
+ ...event,
186
+ timestamp: new Date().toISOString(),
187
+ };
188
+ await appendJsonl(paths.ledgerPath, entry, {
189
+ cwd,
190
+ audit: { category: "ledger", verb: "append", owner: "skc-runtime" },
191
+ });
192
+ return entry;
193
+ }
194
+
195
+ export async function readUltragoalLedger(cwd: string): Promise<UltragoalLedgerEvent[]> {
196
+ try {
197
+ const raw = await Bun.file(getUltragoalPaths(cwd).ledgerPath).text();
198
+ return raw
199
+ .split(/\r?\n/)
200
+ .map(line => line.trim())
201
+ .filter(line => line.length > 0)
202
+ .map(line => JSON.parse(line) as UltragoalLedgerEvent);
203
+ } catch (error) {
204
+ if (isEnoent(error)) return [];
205
+ throw error;
206
+ }
207
+ }
208
+
209
+ async function writePlan(cwd: string, plan: UltragoalPlan): Promise<void> {
210
+ const paths = getUltragoalPaths(cwd);
211
+ await writeArtifact(paths.briefPath, `${plan.brief.trim()}\n`, {
212
+ cwd,
213
+ audit: { category: "artifact", verb: "write", owner: "skc-runtime" },
214
+ });
215
+ await writeJsonAtomic(paths.goalsPath, plan, {
216
+ cwd,
217
+ audit: { category: "state", verb: "write", owner: "skc-runtime" },
218
+ });
219
+ }
220
+
221
+ function requiredUltragoalGoals(plan: UltragoalPlan): UltragoalGoal[] {
222
+ return plan.goals.filter(goal => goal.status !== "superseded");
223
+ }
224
+
225
+ function receiptRelevantGoals(
226
+ plan: UltragoalPlan,
227
+ goal: UltragoalGoal,
228
+ receiptKind: UltragoalReceiptKind,
229
+ ): UltragoalGoal[] {
230
+ return receiptKind === "final-aggregate" ? requiredUltragoalGoals(plan) : [goal];
231
+ }
232
+
233
+ function ledgerEventId(event: UltragoalLedgerEvent): string | null {
234
+ return typeof event.eventId === "string" && event.eventId.trim().length > 0 ? event.eventId : null;
235
+ }
236
+
237
+ function latestRelevantLedgerEventId(
238
+ ledger: readonly UltragoalLedgerEvent[],
239
+ relevantGoalIds: readonly string[],
240
+ excludeEventId?: string,
241
+ ): string | null {
242
+ const relevant = new Set(relevantGoalIds);
243
+ for (const event of [...ledger].reverse()) {
244
+ const eventId = ledgerEventId(event);
245
+ if (eventId && eventId === excludeEventId) continue;
246
+ const goalId = typeof event.goalId === "string" ? event.goalId : null;
247
+ if (!goalId || relevant.has(goalId)) return eventId;
248
+ }
249
+ return null;
250
+ }
251
+
252
+ function planSnapshotForReceipt(input: {
253
+ plan: UltragoalPlan;
254
+ goal: UltragoalGoal;
255
+ beforeStatus: UltragoalGoalStatus;
256
+ targetGoalUpdatedAt: string;
257
+ receiptKind: UltragoalReceiptKind;
258
+ }): unknown {
259
+ const targetGoalSnapshot = {
260
+ ...input.goal,
261
+ status: input.beforeStatus,
262
+ updatedAt: input.targetGoalUpdatedAt,
263
+ evidence: undefined,
264
+ completedAt: undefined,
265
+ completionVerification: undefined,
266
+ };
267
+ const goals =
268
+ input.receiptKind === "final-aggregate"
269
+ ? input.plan.goals.map(goal => ({
270
+ ...goal,
271
+ status: goal.id === input.goal.id ? input.beforeStatus : goal.status,
272
+ updatedAt: goal.id === input.goal.id ? input.targetGoalUpdatedAt : goal.updatedAt,
273
+ evidence: goal.id === input.goal.id ? undefined : goal.evidence,
274
+ completedAt: goal.id === input.goal.id ? undefined : goal.completedAt,
275
+ completionVerification: undefined,
276
+ }))
277
+ : [targetGoalSnapshot];
278
+ return {
279
+ version: input.plan.version,
280
+ brief: input.plan.brief,
281
+ skcGoalMode: input.plan.skcGoalMode,
282
+ skcObjective: input.plan.skcObjective,
283
+ skcObjectiveAliases: input.plan.skcObjectiveAliases,
284
+ createdAt: input.plan.createdAt,
285
+ goals,
286
+ };
287
+ }
288
+
289
+ export function computeUltragoalPlanGeneration(input: {
290
+ plan: UltragoalPlan;
291
+ ledger: readonly UltragoalLedgerEvent[];
292
+ goal: UltragoalGoal;
293
+ receiptKind: UltragoalReceiptKind;
294
+ beforeStatus: UltragoalGoalStatus;
295
+ excludeEventId?: string;
296
+ targetGoalUpdatedAt?: string;
297
+ }): {
298
+ planGeneration: string;
299
+ basis: UltragoalCompletionVerification["basis"];
300
+ } {
301
+ const relevantGoals = receiptRelevantGoals(input.plan, input.goal, input.receiptKind);
302
+ const relevantGoalIds = relevantGoals.map(goal => goal.id);
303
+ const targetGoalUpdatedAt = input.targetGoalUpdatedAt ?? input.goal.updatedAt;
304
+ const planHashBeforeCheckpoint = hashStructuredValue(
305
+ planSnapshotForReceipt({
306
+ plan: input.plan,
307
+ goal: input.goal,
308
+ beforeStatus: input.beforeStatus,
309
+ targetGoalUpdatedAt,
310
+ receiptKind: input.receiptKind,
311
+ }),
312
+ );
313
+ const requiredGoalSetHashBeforeCheckpoint = hashStructuredValue(
314
+ relevantGoals.map(goal => ({
315
+ id: goal.id,
316
+ status: goal.id === input.goal.id ? input.beforeStatus : goal.status,
317
+ updatedAt: goal.id === input.goal.id ? targetGoalUpdatedAt : goal.updatedAt,
318
+ })),
319
+ );
320
+ const basis: UltragoalCompletionVerification["basis"] = {
321
+ planHashBeforeCheckpoint,
322
+ latestRelevantLedgerEventIdBeforeCheckpoint: latestRelevantLedgerEventId(
323
+ input.ledger,
324
+ relevantGoalIds,
325
+ input.excludeEventId,
326
+ ),
327
+ goalUpdatedAtBeforeCheckpoint: targetGoalUpdatedAt,
328
+ relevantGoalIdsBeforeCheckpoint: relevantGoalIds,
329
+ requiredGoalSetHashBeforeCheckpoint,
330
+ };
331
+ return { planGeneration: hashStructuredValue(basis), basis };
332
+ }
333
+
334
+ function chooseReceiptKind(
335
+ plan: UltragoalPlan,
336
+ goal: UltragoalGoal,
337
+ status: UltragoalGoalStatus,
338
+ ): UltragoalReceiptKind {
339
+ if (plan.skcGoalMode === "per-story") return "per-goal";
340
+ if (status !== "complete") return "per-goal";
341
+ const unfinishedRequiredGoals = requiredUltragoalGoals(plan).filter(
342
+ item => item.id !== goal.id && !TERMINAL_OR_SKIPPED_STATUSES.has(item.status),
343
+ );
344
+ return unfinishedRequiredGoals.length === 0 ? "final-aggregate" : "per-goal";
345
+ }
346
+
347
+ function buildCompletionReceipt(input: {
348
+ plan: UltragoalPlan;
349
+ ledger: readonly UltragoalLedgerEvent[];
350
+ goal: UltragoalGoal;
351
+ receiptKind: UltragoalReceiptKind;
352
+ beforeStatus: UltragoalGoalStatus;
353
+ qualityGateJson: JsonObject;
354
+ skcGoalJson: JsonObject;
355
+ now: string;
356
+ checkpointLedgerEventId: string;
357
+ }): UltragoalCompletionVerification {
358
+ const generation = computeUltragoalPlanGeneration({
359
+ plan: input.plan,
360
+ ledger: input.ledger,
361
+ goal: input.goal,
362
+ receiptKind: input.receiptKind,
363
+ beforeStatus: input.beforeStatus,
364
+ targetGoalUpdatedAt: input.now,
365
+ excludeEventId: input.checkpointLedgerEventId,
366
+ });
367
+ return {
368
+ schemaVersion: 1,
369
+ receiptId: crypto.randomUUID(),
370
+ verifiedAt: input.now,
371
+ goalId: input.goal.id,
372
+ receiptKind: input.receiptKind,
373
+ goalStatusBeforeCheckpoint: input.beforeStatus,
374
+ skcGoalMode: input.plan.skcGoalMode,
375
+ skcObjective: input.plan.skcObjective,
376
+ qualityGateHash: hashStructuredValue(input.qualityGateJson),
377
+ skcGoalSnapshotHash: hashStructuredValue(input.skcGoalJson),
378
+ planGeneration: generation.planGeneration,
379
+ basis: generation.basis,
380
+ checkpointLedgerEventId: input.checkpointLedgerEventId,
381
+ };
382
+ }
383
+
384
+ function nonEmptyString(value: unknown): string | null {
385
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
386
+ }
387
+
388
+ function normalizeGoalStatus(value: unknown): UltragoalGoalStatus {
389
+ switch (value) {
390
+ case "pending":
391
+ case "active":
392
+ case "complete":
393
+ case "failed":
394
+ case "blocked":
395
+ case "review_blocked":
396
+ case "superseded":
397
+ return value;
398
+ default:
399
+ return "pending";
400
+ }
401
+ }
402
+
403
+ function parseGoalStatus(value: unknown): UltragoalGoalStatus {
404
+ const status = normalizeGoalStatus(value);
405
+ if (status === "pending" && value !== "pending") {
406
+ throw new Error(
407
+ "checkpoint --status must be pending, active, complete, failed, blocked, review_blocked, or superseded",
408
+ );
409
+ }
410
+ return status;
411
+ }
412
+
413
+ function normalizePlan(raw: unknown): UltragoalPlan {
414
+ if (typeof raw !== "object" || raw === null) throw new Error("Invalid ultragoal plan: expected object");
415
+ const record = raw as JsonObject;
416
+ const brief = nonEmptyString(record.brief) ?? "";
417
+ const createdAt = nonEmptyString(record.createdAt) ?? new Date().toISOString();
418
+ const updatedAt = nonEmptyString(record.updatedAt) ?? createdAt;
419
+ const skcGoalMode = record.skcGoalMode === "per-story" ? "per-story" : "aggregate";
420
+ const skcObjective = nonEmptyString(record.skcObjective) ?? DEFAULT_ULTRAGOAL_OBJECTIVE;
421
+ const rawGoals = Array.isArray(record.goals) ? record.goals : [];
422
+ const goals: UltragoalGoal[] = rawGoals.map((item, index) => {
423
+ const goalRecord = typeof item === "object" && item !== null ? (item as JsonObject) : {};
424
+ const id = nonEmptyString(goalRecord.id) ?? `G${String(index + 1).padStart(3, "0")}`;
425
+ const title = nonEmptyString(goalRecord.title) ?? id;
426
+ const objective = nonEmptyString(goalRecord.objective) ?? title;
427
+ const goalCreatedAt = nonEmptyString(goalRecord.createdAt) ?? createdAt;
428
+ return {
429
+ id,
430
+ title,
431
+ objective,
432
+ status: normalizeGoalStatus(goalRecord.status),
433
+ createdAt: goalCreatedAt,
434
+ updatedAt: nonEmptyString(goalRecord.updatedAt) ?? goalCreatedAt,
435
+ startedAt: nonEmptyString(goalRecord.startedAt) ?? undefined,
436
+ completedAt: nonEmptyString(goalRecord.completedAt) ?? undefined,
437
+ evidence: nonEmptyString(goalRecord.evidence) ?? undefined,
438
+ steering:
439
+ typeof goalRecord.steering === "object" && goalRecord.steering !== null
440
+ ? (goalRecord.steering as Record<string, unknown>)
441
+ : undefined,
442
+ completionVerification:
443
+ typeof goalRecord.completionVerification === "object" && goalRecord.completionVerification !== null
444
+ ? (goalRecord.completionVerification as UltragoalCompletionVerification)
445
+ : undefined,
446
+ };
447
+ });
448
+ const aliases = Array.isArray(record.skcObjectiveAliases)
449
+ ? record.skcObjectiveAliases.filter(
450
+ (value): value is string => typeof value === "string" && value.trim().length > 0,
451
+ )
452
+ : undefined;
453
+ return {
454
+ version: 1,
455
+ brief,
456
+ skcGoalMode,
457
+ skcObjective,
458
+ skcObjectiveAliases: aliases,
459
+ goals,
460
+ createdAt,
461
+ updatedAt,
462
+ };
463
+ }
464
+
465
+ export async function readUltragoalPlan(cwd: string): Promise<UltragoalPlan | null> {
466
+ try {
467
+ return normalizePlan(await Bun.file(getUltragoalPaths(cwd).goalsPath).json());
468
+ } catch (error) {
469
+ if (isEnoent(error)) return null;
470
+ throw error;
471
+ }
472
+ }
473
+
474
+ function emptyCounts(): Record<UltragoalGoalStatus, number> {
475
+ return {
476
+ pending: 0,
477
+ active: 0,
478
+ complete: 0,
479
+ failed: 0,
480
+ blocked: 0,
481
+ review_blocked: 0,
482
+ superseded: 0,
483
+ };
484
+ }
485
+
486
+ export async function getUltragoalStatus(cwd: string): Promise<UltragoalStatusSummary> {
487
+ const paths = getUltragoalPaths(cwd);
488
+ const plan = await readUltragoalPlan(cwd);
489
+ const counts = emptyCounts();
490
+ if (!plan) return { exists: false, status: "missing", paths, counts, goals: [] };
491
+ for (const goal of plan.goals) counts[goal.status] += 1;
492
+ const currentGoal = plan.goals.find(goal => SCHEDULABLE_STATUSES.has(goal.status));
493
+ let status: UltragoalStatusSummary["status"] = "pending";
494
+ if (plan.goals.length > 0 && plan.goals.every(goal => TERMINAL_OR_SKIPPED_STATUSES.has(goal.status)))
495
+ status = "complete";
496
+ else if (counts.active > 0) status = "active";
497
+ else if (counts.failed > 0) status = "failed";
498
+ else if (counts.blocked > 0 || counts.review_blocked > 0) status = "blocked";
499
+ return {
500
+ exists: true,
501
+ status,
502
+ paths,
503
+ skcObjective: plan.skcObjective,
504
+ currentGoal,
505
+ counts,
506
+ goals: plan.goals,
507
+ };
508
+ }
509
+ export function buildUltragoalHudSummary(
510
+ summary: UltragoalStatusSummary,
511
+ latestLedger?: UltragoalLedgerEvent,
512
+ ): WorkflowHudSummary {
513
+ return buildWorkflowUltragoalHudSummary({
514
+ status: summary.status,
515
+ currentGoal: summary.currentGoal,
516
+ counts: summary.counts,
517
+ goals: summary.goals,
518
+ latestLedgerEvent: latestLedger,
519
+ updatedAt: new Date().toISOString(),
520
+ });
521
+ }
522
+ function clampTitle(title: string): string {
523
+ return title.length > 80 ? `${title.slice(0, 77)}...` : title;
524
+ }
525
+
526
+ function firstNonEmptyLine(text: string): string | undefined {
527
+ return text
528
+ .split(/\r?\n/)
529
+ .map(line => line.trim())
530
+ .find(line => line.length > 0);
531
+ }
532
+
533
+ function titleFromBrief(brief: string): string {
534
+ const firstLine = firstNonEmptyLine(brief);
535
+ if (!firstLine) return "Complete ultragoal brief";
536
+ return clampTitle(firstLine);
537
+ }
538
+
539
+ // A reserved, column-0 (unindented) `@goal` line opens a story. The character
540
+ // right after `@goal` must be `:`, an ASCII space or tab, or end-of-line, so
541
+ // `@goalish`, `@goals:`, `@goal-foo`, `@goal.foo`, `@goal/foo`, a non-breaking
542
+ // space, and indented or mid-line `@goal:` are all ordinary objective text and
543
+ // never delimiters.
544
+ const GOAL_DELIMITER = /^@goal(?::|[ \t]+|$)[ \t]*(.*)$/;
545
+
546
+ interface ParsedGoal {
547
+ title: string;
548
+ objective: string;
549
+ }
550
+
551
+ function parseGoalsFromBrief(brief: string): ParsedGoal[] {
552
+ const sections: { title: string; body: string[] }[] = [];
553
+ let current: { title: string; body: string[] } | undefined;
554
+ for (const line of brief.split(/\r?\n/)) {
555
+ const match = GOAL_DELIMITER.exec(line);
556
+ if (match) {
557
+ current = { title: match[1].trim(), body: [] };
558
+ sections.push(current);
559
+ continue;
560
+ }
561
+ current?.body.push(line);
562
+ }
563
+ if (sections.length === 0) {
564
+ return [{ title: titleFromBrief(brief), objective: brief.trim() }];
565
+ }
566
+ return sections.map((section, index) => {
567
+ const body = section.body.join("\n").trim();
568
+ const title = section.title || firstNonEmptyLine(body) || "";
569
+ if (!title && !body) {
570
+ throw new Error(`ultragoal @goal block ${index + 1} has no title or objective`);
571
+ }
572
+ return { title: clampTitle(title), objective: body || title };
573
+ });
574
+ }
575
+
576
+ export async function createUltragoalPlan(input: {
577
+ cwd: string;
578
+ brief: string;
579
+ skcGoalMode?: UltragoalSkcGoalMode;
580
+ }): Promise<UltragoalPlan> {
581
+ const brief = input.brief.trim();
582
+ if (!brief) throw new Error("ultragoal brief is required");
583
+ const now = new Date().toISOString();
584
+ // Parse the untrimmed brief so the raw-line delimiter contract holds: a
585
+ // leading-indented `@goal` on the first line must stay objective text rather
586
+ // than being promoted to column 0 by trimming.
587
+ const goals: UltragoalGoal[] = parseGoalsFromBrief(input.brief).map((goal, index) => ({
588
+ id: `G${String(index + 1).padStart(3, "0")}`,
589
+ title: goal.title,
590
+ objective: goal.objective,
591
+ status: "pending",
592
+ createdAt: now,
593
+ updatedAt: now,
594
+ }));
595
+ const plan: UltragoalPlan = {
596
+ version: 1,
597
+ brief,
598
+ skcGoalMode: input.skcGoalMode ?? "aggregate",
599
+ skcObjective: DEFAULT_ULTRAGOAL_OBJECTIVE,
600
+ goals,
601
+ createdAt: now,
602
+ updatedAt: now,
603
+ };
604
+ await writePlan(input.cwd, plan);
605
+ await appendLedger(input.cwd, { event: "plan_created", goalIds: plan.goals.map(goal => goal.id) });
606
+ return plan;
607
+ }
608
+
609
+ function chooseNextGoal(plan: UltragoalPlan, retryFailed: boolean): UltragoalGoal | undefined {
610
+ return (
611
+ plan.goals.find(goal => goal.status === "active") ??
612
+ plan.goals.find(goal => goal.status === "pending") ??
613
+ (retryFailed ? plan.goals.find(goal => goal.status === "failed") : undefined)
614
+ );
615
+ }
616
+ export interface UltragoalRunCompletionState {
617
+ requiredGoals: UltragoalGoal[];
618
+ incompleteGoals: UltragoalGoal[];
619
+ nextGoal?: UltragoalGoal;
620
+ allComplete: boolean;
621
+ hasBlockers: boolean;
622
+ needsFinalAggregateReceipt: boolean;
623
+ }
624
+
625
+ export function getUltragoalRunCompletionState(
626
+ plan: UltragoalPlan,
627
+ options: { retryFailed?: boolean } = {},
628
+ ): UltragoalRunCompletionState {
629
+ const requiredGoals = requiredUltragoalGoals(plan);
630
+ const incompleteGoals = requiredGoals.filter(goal => !TERMINAL_OR_SKIPPED_STATUSES.has(goal.status));
631
+ const nextGoal = chooseNextGoal(plan, options.retryFailed === true);
632
+ return {
633
+ requiredGoals,
634
+ incompleteGoals,
635
+ nextGoal,
636
+ allComplete: requiredGoals.length > 0 && incompleteGoals.length === 0,
637
+ hasBlockers: incompleteGoals.some(goal => goal.status === "blocked" || goal.status === "review_blocked"),
638
+ needsFinalAggregateReceipt: plan.skcGoalMode === "aggregate" && incompleteGoals.length === 0,
639
+ };
640
+ }
641
+
642
+ export async function startNextUltragoalGoal(input: { cwd: string; retryFailed?: boolean }): Promise<{
643
+ plan: UltragoalPlan;
644
+ goal?: UltragoalGoal;
645
+ allComplete: boolean;
646
+ }> {
647
+ const plan = await readUltragoalPlan(input.cwd);
648
+ if (!plan) throw new Error("No ultragoal plan found. Run `skc ultragoal create-goals --brief ...` first.");
649
+ const goal = chooseNextGoal(plan, input.retryFailed === true);
650
+ if (!goal) return { plan, allComplete: getUltragoalRunCompletionState(plan).allComplete };
651
+ if (goal.status !== "active") {
652
+ const now = new Date().toISOString();
653
+ goal.status = "active";
654
+ goal.startedAt = goal.startedAt ?? now;
655
+ goal.updatedAt = now;
656
+ plan.updatedAt = now;
657
+ await writePlan(input.cwd, plan);
658
+ await appendLedger(input.cwd, { event: "goal_started", goalId: goal.id });
659
+ }
660
+ return { plan, goal, allComplete: false };
661
+ }
662
+
663
+ async function readStructuredValue(cwd: string, value: string): Promise<unknown> {
664
+ const trimmed = value.trim();
665
+ if (!trimmed) return "";
666
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) return JSON.parse(trimmed) as unknown;
667
+ try {
668
+ return await Bun.file(path.resolve(cwd, trimmed)).json();
669
+ } catch (error) {
670
+ if (isEnoent(error)) return value;
671
+ throw error;
672
+ }
673
+ }
674
+ function qualityGateObject(value: unknown): JsonObject | null {
675
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? (value as JsonObject) : null;
676
+ }
677
+
678
+ function nonEmptyStringArray(value: unknown): string[] | null {
679
+ if (!Array.isArray(value)) return null;
680
+ const strings = value.filter(item => typeof item === "string" && item.trim().length > 0);
681
+ return strings.length === value.length && strings.length > 0 ? strings : null;
682
+ }
683
+
684
+ function requireNonEmptyString(value: unknown, fieldName: string): void {
685
+ if (typeof value !== "string" || value.trim().length === 0) {
686
+ throw new Error(`qualityGate ${fieldName} must be a non-empty string`);
687
+ }
688
+ }
689
+
690
+ function requireEmptyBlockers(value: unknown, fieldName: string): void {
691
+ if (!Array.isArray(value) || value.length !== 0) {
692
+ throw new Error(`qualityGate ${fieldName} must be an empty blockers array`);
693
+ }
694
+ }
695
+ function requireQualityGateObject(value: unknown, fieldName: string): JsonObject {
696
+ const object = qualityGateObject(value);
697
+ if (!object) throw new Error(`qualityGate ${fieldName} must be an object`);
698
+ return object;
699
+ }
700
+
701
+ function requireObjectArray(value: unknown, fieldName: string): JsonObject[] {
702
+ if (!Array.isArray(value) || value.length === 0) {
703
+ throw new Error(`qualityGate ${fieldName} must be a non-empty object array`);
704
+ }
705
+ return value.map((item, index) => requireQualityGateObject(item, `${fieldName}[${index}]`));
706
+ }
707
+
708
+ function requiredStringField(row: JsonObject, key: string, fieldName: string): string {
709
+ const value = row[key];
710
+ if (typeof value !== "string" || value.trim().length === 0) {
711
+ const hint =
712
+ key === "obligation" && typeof row.description === "string" && row.description.trim().length > 0
713
+ ? "; found description, but complete-checkpoint contractCoverage rows require obligation"
714
+ : "";
715
+ throw new Error(`qualityGate ${fieldName}.${key} must be a non-empty string${hint}`);
716
+ }
717
+ return value.trim();
718
+ }
719
+
720
+ function optionalStatusField(row: JsonObject, fieldName: string): string | null {
721
+ if (row.status === undefined) return null;
722
+ const status = requiredStringField(row, "status", fieldName).toLowerCase();
723
+ if (status === "todo") throw new Error(`qualityGate ${fieldName}.status must not be todo`);
724
+ return status;
725
+ }
726
+
727
+ function requireProofStatus(status: string, fieldName: string): void {
728
+ if (!ACCEPTED_PROOF_STATUSES.has(status) && status !== NOT_APPLICABLE_STATUS) {
729
+ throw new Error(`qualityGate ${fieldName}.status must be covered, passed, verified, or not_applicable`);
730
+ }
731
+ }
732
+ function requireSuccessStatus(status: string, fieldName: string): void {
733
+ requireProofStatus(status, fieldName);
734
+ if (status === NOT_APPLICABLE_STATUS) {
735
+ throw new Error(`qualityGate ${fieldName}.status must be covered, passed, or verified`);
736
+ }
737
+ }
738
+
739
+ function rowOutcomeStatuses(row: JsonObject, fieldName: string): string[] {
740
+ const statuses: string[] = [];
741
+ const status = optionalStatusField(row, fieldName);
742
+ if (status) statuses.push(status);
743
+ const verdict = row.verdict;
744
+ if (typeof verdict === "string" && verdict.trim().length > 0) statuses.push(verdict.trim().toLowerCase());
745
+ const result = row.result;
746
+ if (typeof result === "string" && result.trim().length > 0) statuses.push(result.trim().toLowerCase());
747
+ if (statuses.length === 0) throw new Error(`qualityGate ${fieldName}.verdict must be a non-empty string`);
748
+ return statuses;
749
+ }
750
+
751
+ function requireSuccessfulRowOutcome(row: JsonObject, fieldName: string): void {
752
+ for (const status of rowOutcomeStatuses(row, fieldName)) {
753
+ requireSuccessStatus(status, fieldName);
754
+ }
755
+ }
756
+
757
+ function requireStringLinks(value: unknown, fieldName: string): string[] {
758
+ const strings = nonEmptyStringArray(value);
759
+ if (!strings) throw new Error(`qualityGate ${fieldName} must be a non-empty string array`);
760
+ return strings.map(item => item.trim());
761
+ }
762
+
763
+ function optionalStringLinks(row: JsonObject, key: string, fieldName: string): string[] | null {
764
+ if (row[key] === undefined) return null;
765
+ return requireStringLinks(row[key], `${fieldName}.${key}`);
766
+ }
767
+
768
+ function buildRowIdMap(rows: JsonObject[], fieldName: string): Map<string, JsonObject> {
769
+ const ids = new Map<string, JsonObject>();
770
+ for (const [index, row] of rows.entries()) {
771
+ const id = requiredStringField(row, "id", `${fieldName}[${index}]`);
772
+ if (ids.has(id)) throw new Error(`qualityGate ${fieldName} contains duplicate id ${id}`);
773
+ ids.set(id, row);
774
+ }
775
+ return ids;
776
+ }
777
+
778
+ function requireResolvedLinks(ids: string[], map: Map<string, JsonObject>, fieldName: string): void {
779
+ for (const id of ids) {
780
+ if (!map.has(id)) throw new Error(`qualityGate ${fieldName} references unknown id ${id}`);
781
+ }
782
+ }
783
+ function successfulLinkedRows(ids: string[], map: Map<string, JsonObject>, fieldName: string): JsonObject[] {
784
+ const rows: JsonObject[] = [];
785
+ for (const id of ids) {
786
+ const row = map.get(id);
787
+ if (!row) throw new Error(`qualityGate ${fieldName} references unknown id ${id}`);
788
+ requireSuccessfulRowOutcome(row, `${fieldName}.${id}`);
789
+ rows.push(row);
790
+ }
791
+ return rows;
792
+ }
793
+
794
+ function normalizedEvidenceKind(row: JsonObject): string {
795
+ return requiredStringField(row, "kind", "executorQa.artifactRefs[]").toLowerCase().replaceAll("_", "-");
796
+ }
797
+
798
+ function evidenceKindMatches(kind: string, words: string[]): boolean {
799
+ return words.some(word => kind.includes(word));
800
+ }
801
+
802
+ type SurfaceFamily = "web" | "cli" | "native" | "api-package" | "algorithm-math" | "unknown";
803
+
804
+ type UltragoalChangeStatus = "added" | "modified" | "deleted" | "renamed" | "copied" | "unknown";
805
+ type UltragoalChangeCategory =
806
+ | "code"
807
+ | "generated-binding"
808
+ | "tool"
809
+ | "settings-registry"
810
+ | "prompt-doc-behavior"
811
+ | "docs-static"
812
+ | "other";
813
+ interface UltragoalChangeSetPath extends JsonObject {
814
+ path: string;
815
+ status: UltragoalChangeStatus;
816
+ oldPath?: string;
817
+ category?: UltragoalChangeCategory;
818
+ }
819
+ interface UltragoalChangeSet extends JsonObject {
820
+ source: "checkpoint-git" | "review-pr" | "review-branch" | "review-worktree" | "review-spec";
821
+ baseRef?: string;
822
+ headRef?: string;
823
+ mergeBase?: string;
824
+ paths: UltragoalChangeSetPath[];
825
+ rawDiffStat?: string;
826
+ trusted: true;
827
+ }
828
+
829
+ const MANDATORY_COMPUTER_CASE_IDS = [
830
+ "kill-switch-bypass",
831
+ "suspended-enforcement",
832
+ "permission-revoked",
833
+ "display-stale",
834
+ "out-of-bounds-drift",
835
+ "runaway-loop-halt",
836
+ "blast-radius",
837
+ ] as const;
838
+
839
+ function normalizeRepoPath(value: string): string {
840
+ return value.replaceAll("\\\\", "/").replace(/^\.\//, "");
841
+ }
842
+
843
+ function categorizeComputerChangePath(value: string): UltragoalChangeCategory {
844
+ const normalized = normalizeRepoPath(value);
845
+ if (normalized.startsWith("crates/pi-natives/src/computer/")) return "code";
846
+ if (/^packages\/natives\/native\/index\.(?:d\.ts|js)$/.test(normalized)) return "generated-binding";
847
+ if (
848
+ normalized === "packages/coding-agent/src/tools/computer.ts" ||
849
+ normalized.startsWith("packages/coding-agent/src/tools/computer/")
850
+ )
851
+ return "tool";
852
+ if (
853
+ normalized === "packages/coding-agent/src/tools/index.ts" ||
854
+ normalized === "packages/coding-agent/src/tools/renderers.ts" ||
855
+ normalized === "packages/coding-agent/src/config/settings-schema.ts"
856
+ )
857
+ return "settings-registry";
858
+ if (
859
+ normalized === "packages/coding-agent/src/prompts/tools/computer.md" ||
860
+ normalized === "packages/coding-agent/src/defaults/skc/skills/ultragoal/SKILL.md" ||
861
+ normalized === "packages/coding-agent/src/prompts/agents/executor.md"
862
+ )
863
+ return "prompt-doc-behavior";
864
+ if (normalized === "docs/tools/computer.md" || normalized === "docs/computer-use/README.md") return "docs-static";
865
+ return "other";
866
+ }
867
+
868
+ function isComputerChangePath(row: UltragoalChangeSetPath): boolean {
869
+ return (
870
+ categorizeComputerChangePath(row.path) !== "other" ||
871
+ (row.oldPath ? categorizeComputerChangePath(row.oldPath) !== "other" : false)
872
+ );
873
+ }
874
+
875
+ function isDocsOnlyStaticComputerChangeSet(changeSet: UltragoalChangeSet | undefined): boolean {
876
+ if (!changeSet || changeSet.paths.length === 0) return false;
877
+ return changeSet.paths.every(row => {
878
+ const category = row.category ?? categorizeComputerChangePath(row.path);
879
+ const oldCategory = row.oldPath ? categorizeComputerChangePath(row.oldPath) : category;
880
+ return category === "docs-static" && oldCategory === "docs-static";
881
+ });
882
+ }
883
+
884
+ function trustedChangeSetRequiresComputerSuite(changeSet: UltragoalChangeSet | undefined): boolean {
885
+ if (!changeSet?.trusted) return false;
886
+ if (isDocsOnlyStaticComputerChangeSet(changeSet)) return false;
887
+ return changeSet.paths.some(isComputerChangePath);
888
+ }
889
+
890
+ function requiresComputerRedTeamSuite(executorQa: JsonObject, changeSet: UltragoalChangeSet | undefined): boolean {
891
+ if (trustedChangeSetRequiresComputerSuite(changeSet)) return true;
892
+ const declaredPaths = Array.isArray(executorQa.changedPaths) ? executorQa.changedPaths : [];
893
+ return declaredPaths.some(value => typeof value === "string" && categorizeComputerChangePath(value) !== "other");
894
+ }
895
+
896
+ function normalizeAdversarialCaseId(value: string): string {
897
+ return normalizeSurfaceToken(value).replace(/\s+/g, "-");
898
+ }
899
+
900
+ export function normalizeSurfaceToken(value: string): string {
901
+ return value.toLowerCase().replaceAll("_", "-").trim();
902
+ }
903
+
904
+ export function surfaceFamily(value: string): SurfaceFamily {
905
+ const normalized = normalizeSurfaceToken(value);
906
+ if (
907
+ ["computer", "computer-use", "desktop-input", "native-input", "native", "desktop", "tui"].some(word =>
908
+ normalized.includes(word),
909
+ )
910
+ )
911
+ return "native";
912
+ if (["gui", "web", "browser", "ui", "visual"].some(word => normalized.includes(word))) return "web";
913
+ if (["cli", "terminal", "command"].some(word => normalized.includes(word))) return "cli";
914
+ if (["api", "package", "library", "sdk"].some(word => normalized.includes(word))) return "api-package";
915
+ if (["algorithm", "math", "mathematical", "equation"].some(word => normalized.includes(word))) {
916
+ return "algorithm-math";
917
+ }
918
+ return "unknown";
919
+ }
920
+
921
+ function isLiveSurfaceFamily(family: SurfaceFamily): boolean {
922
+ return family === "web" || family === "cli" || family === "native";
923
+ }
924
+
925
+ function validateSurfaceArtifactCompatibility(
926
+ surface: string,
927
+ artifactIds: string[],
928
+ artifactRefs: Map<string, JsonObject>,
929
+ fieldName: string,
930
+ ): void {
931
+ const family = surfaceFamily(surface);
932
+ const kinds = artifactIds.map(id => normalizedEvidenceKind(artifactRefs.get(id)!));
933
+ if (family === "web") {
934
+ const hasBrowser = kinds.some(kind =>
935
+ evidenceKindMatches(kind, ["browser", "playwright", "pandawright", "automation"]),
936
+ );
937
+ const hasVisual = kinds.some(kind => evidenceKindMatches(kind, ["screenshot", "image", "visual"]));
938
+ if (!hasBrowser || !hasVisual) {
939
+ throw new Error(
940
+ `qualityGate ${fieldName} for GUI/web surfaces must reference browser automation plus screenshot or image-verdict artifacts`,
941
+ );
942
+ }
943
+ return;
944
+ }
945
+ const surfaceFamilies: Record<Exclude<SurfaceFamily, "web" | "unknown">, { evidence: string[]; label: string }> = {
946
+ cli: {
947
+ evidence: ["cli", "log", "transcript", "terminal", "command", "test-report"],
948
+ label: "CLI",
949
+ },
950
+ native: {
951
+ evidence: ["native", "desktop", "tui", "terminal", "pty", "transcript", "screenshot", "image", "automation"],
952
+ label: "native",
953
+ },
954
+ "api-package": {
955
+ evidence: ["api", "package", "consumer", "black-box", "test-report"],
956
+ label: "API/package",
957
+ },
958
+ "algorithm-math": {
959
+ evidence: ["property", "boundary", "edge", "adversarial", "failure", "math", "algorithm", "test-report"],
960
+ label: "algorithm/math",
961
+ },
962
+ };
963
+ if (family !== "unknown") {
964
+ const expected = surfaceFamilies[family];
965
+ if (!kinds.some(kind => evidenceKindMatches(kind, expected.evidence))) {
966
+ throw new Error(
967
+ `qualityGate ${fieldName} for ${expected.label} surfaces must reference compatible artifact kinds`,
968
+ );
969
+ }
970
+ }
971
+ }
972
+
973
+ function isSubstantiveEvidence(value: unknown): boolean {
974
+ if (typeof value !== "string") return false;
975
+ const trimmed = value.trim();
976
+ if (trimmed.length < MIN_SUBSTANTIVE_EVIDENCE_CHARS) return false;
977
+ const words = trimmed.split(/\s+/).filter(word => /[a-z0-9]/i.test(word));
978
+ if (words.length < MIN_SUBSTANTIVE_EVIDENCE_WORDS) return false;
979
+ const normalized = trimmed.toLowerCase();
980
+ return !["todo", "tbd", "n/a", "na", "none", "placeholder", "empty", "stub"].includes(normalized);
981
+ }
982
+
983
+ function hasTypedVerifiedReceipt(value: unknown): boolean {
984
+ const receipt = qualityGateObject(value);
985
+ if (!receipt) return false;
986
+ const type = nonEmptyString(receipt.type) ?? nonEmptyString(receipt.kind) ?? nonEmptyString(receipt.receiptType);
987
+ const id = nonEmptyString(receipt.id) ?? nonEmptyString(receipt.receiptId) ?? nonEmptyString(receipt.ref);
988
+ const status = (nonEmptyString(receipt.status) ?? nonEmptyString(receipt.verdict) ?? "").toLowerCase();
989
+ return Boolean(type && id && (status === "verified" || status === "passed"));
990
+ }
991
+
992
+ async function hasExistingNonEmptyArtifact(cwd: string, value: unknown): Promise<boolean> {
993
+ const artifactPath = nonEmptyString(value);
994
+ if (!artifactPath) return false;
995
+ const resolved = path.resolve(cwd, artifactPath);
996
+ try {
997
+ const file = Bun.file(resolved);
998
+ return (await file.exists()) && file.size > 0;
999
+ } catch (error) {
1000
+ if (isEnoent(error)) return false;
1001
+ throw error;
1002
+ }
1003
+ }
1004
+
1005
+ async function readArtifactBytes(cwd: string, row: JsonObject, fieldName: string): Promise<Buffer | null> {
1006
+ const artifactPath = nonEmptyString(row.path);
1007
+ if (!artifactPath) return null;
1008
+ const resolved = path.resolve(cwd, artifactPath);
1009
+ try {
1010
+ const file = Bun.file(resolved);
1011
+ if (!(await file.exists())) return null;
1012
+ return Buffer.from(await file.arrayBuffer());
1013
+ } catch (error) {
1014
+ if (isEnoent(error)) return null;
1015
+ throw new Error(`qualityGate ${fieldName} artifact could not be read: ${String(error)}`);
1016
+ }
1017
+ }
1018
+
1019
+ const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
1020
+ const JPEG_START_OF_IMAGE = 0xd8;
1021
+ const JPEG_END_OF_IMAGE = 0xd9;
1022
+ const JPEG_START_OF_SCAN = 0xda;
1023
+ const JPEG_STANDALONE_MARKERS = new Set([0x01, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7]);
1024
+ const PNG_CRC_TABLE = new Uint32Array(256).map((_, index) => {
1025
+ let crc = index;
1026
+ for (let bit = 0; bit < 8; bit++) crc = crc & 1 ? 0xedb88320 ^ (crc >>> 1) : crc >>> 1;
1027
+ return crc >>> 0;
1028
+ });
1029
+
1030
+ function pngCrc32(bytes: Buffer): number {
1031
+ let crc = 0xffffffff;
1032
+ for (const byte of bytes) crc = PNG_CRC_TABLE[(crc ^ byte) & 0xff]! ^ (crc >>> 8);
1033
+ return (crc ^ 0xffffffff) >>> 0;
1034
+ }
1035
+
1036
+ function parsePngDimensions(
1037
+ bytes: Buffer,
1038
+ ): { width: number; height: number; headerBytes: number; sampleBytes?: Buffer } | null {
1039
+ if (bytes.length < 45) return null;
1040
+ if (!bytes.subarray(0, 8).equals(PNG_SIGNATURE)) return null;
1041
+ let offset = 8;
1042
+ let width = 0;
1043
+ let height = 0;
1044
+ let sawIhdr = false;
1045
+ let sawIdat = false;
1046
+ const idatChunks: Buffer[] = [];
1047
+ while (offset + 12 <= bytes.length) {
1048
+ const chunkStart = offset;
1049
+ const length = bytes.readUInt32BE(offset);
1050
+ offset += 4;
1051
+ const type = bytes.toString("ascii", offset, offset + 4);
1052
+ offset += 4;
1053
+ if (offset + length + 4 > bytes.length) return null;
1054
+ const data = bytes.subarray(offset, offset + length);
1055
+ offset += length;
1056
+ const expectedCrc = bytes.readUInt32BE(offset);
1057
+ offset += 4;
1058
+ if (pngCrc32(bytes.subarray(chunkStart + 4, offset - 4)) !== expectedCrc) return null;
1059
+ if (!sawIhdr) {
1060
+ if (type !== "IHDR" || length !== 13) return null;
1061
+ width = data.readUInt32BE(0);
1062
+ height = data.readUInt32BE(4);
1063
+ if (
1064
+ width === 0 ||
1065
+ height === 0 ||
1066
+ data[8] !== 8 ||
1067
+ ![2, 6].includes(data[9]!) ||
1068
+ data[10] !== 0 ||
1069
+ data[11] !== 0 ||
1070
+ data[12] !== 0
1071
+ )
1072
+ return null;
1073
+ sawIhdr = true;
1074
+ } else if (type === "IHDR") return null;
1075
+ if (type === "IDAT") {
1076
+ if (!sawIhdr || length === 0) return null;
1077
+ sawIdat = true;
1078
+ idatChunks.push(data);
1079
+ }
1080
+ if (type === "IEND") {
1081
+ if (length !== 0 || !sawIhdr || !sawIdat || offset !== bytes.length) return null;
1082
+ try {
1083
+ return { width, height, headerBytes: 8, sampleBytes: inflateSync(Buffer.concat(idatChunks)) };
1084
+ } catch {
1085
+ return null;
1086
+ }
1087
+ }
1088
+ }
1089
+ return null;
1090
+ }
1091
+
1092
+ function parseJpegDimensions(
1093
+ bytes: Buffer,
1094
+ ): { width: number; height: number; headerBytes: number; sampleBytes?: Buffer } | null {
1095
+ if (bytes.length < 8 || bytes[0] !== 0xff || bytes[1] !== JPEG_START_OF_IMAGE) return null;
1096
+ let offset = 2;
1097
+ let dimensions: { width: number; height: number; headerBytes: number } | null = null;
1098
+ let sawStartOfScan = false;
1099
+ let scanStart = -1;
1100
+ while (offset < bytes.length) {
1101
+ if (bytes[offset] !== 0xff) return null;
1102
+ while (offset < bytes.length && bytes[offset] === 0xff) offset++;
1103
+ if (offset >= bytes.length) return null;
1104
+ const marker = bytes[offset++];
1105
+ if (marker === 0x00) return null;
1106
+ if (marker === JPEG_END_OF_IMAGE) return null;
1107
+ if (JPEG_STANDALONE_MARKERS.has(marker)) continue;
1108
+ if (offset + 2 > bytes.length) return null;
1109
+ const segmentLength = bytes.readUInt16BE(offset);
1110
+ if (segmentLength < 2 || offset + segmentLength > bytes.length) return null;
1111
+ const segmentDataEnd = offset + segmentLength;
1112
+ if (marker === 0xc0 || marker === 0xc1 || marker === 0xc2) {
1113
+ if (segmentLength < 8) return null;
1114
+ dimensions = {
1115
+ width: bytes.readUInt16BE(offset + 5),
1116
+ height: bytes.readUInt16BE(offset + 3),
1117
+ headerBytes: offset + segmentLength,
1118
+ };
1119
+ }
1120
+ if (marker === JPEG_START_OF_SCAN) {
1121
+ if (!dimensions || segmentDataEnd >= bytes.length) return null;
1122
+ sawStartOfScan = true;
1123
+ scanStart = segmentDataEnd;
1124
+ break;
1125
+ }
1126
+ offset += segmentLength;
1127
+ }
1128
+ if (!dimensions || !sawStartOfScan || scanStart < 0) return null;
1129
+ let scanOffset = scanStart;
1130
+ let entropyBytes = 0;
1131
+ while (scanOffset < bytes.length) {
1132
+ const byte = bytes[scanOffset++]!;
1133
+ if (byte !== 0xff) {
1134
+ entropyBytes++;
1135
+ continue;
1136
+ }
1137
+ if (scanOffset >= bytes.length) return null;
1138
+ const marker = bytes[scanOffset++]!;
1139
+ if (marker === 0x00) {
1140
+ entropyBytes++;
1141
+ continue;
1142
+ }
1143
+ if (JPEG_STANDALONE_MARKERS.has(marker)) continue;
1144
+ if (marker === JPEG_END_OF_IMAGE) {
1145
+ if (scanOffset !== bytes.length || entropyBytes < 32) return null;
1146
+ return { ...dimensions, sampleBytes: bytes.subarray(scanStart, scanOffset - 2) };
1147
+ }
1148
+ return null;
1149
+ }
1150
+ return null;
1151
+ }
1152
+
1153
+ function unsupportedScreenshotFormat(bytes: Buffer): string | null {
1154
+ if (bytes.toString("ascii", 0, 6) === "GIF87a" || bytes.toString("ascii", 0, 6) === "GIF89a") return "GIF";
1155
+ if (bytes.toString("ascii", 0, 2) === "BM") return "BMP";
1156
+ if (bytes.length >= 12 && bytes.toString("ascii", 0, 4) === "RIFF" && bytes.toString("ascii", 8, 12) === "WEBP")
1157
+ return "WebP";
1158
+ return null;
1159
+ }
1160
+
1161
+ function parseImageDimensions(
1162
+ bytes: Buffer,
1163
+ ): { width: number; height: number; headerBytes: number; sampleBytes?: Buffer } | null {
1164
+ return parsePngDimensions(bytes) ?? parseJpegDimensions(bytes);
1165
+ }
1166
+
1167
+ function hasNonUniformImageBytes(bytes: Buffer, headerBytes: number, sampleBytes?: Buffer): boolean {
1168
+ const source = sampleBytes ?? bytes;
1169
+ const sampleStart = sampleBytes ? 0 : Math.min(Math.max(headerBytes, 0), source.length);
1170
+ const sampleLength = source.length - sampleStart;
1171
+ if (sampleLength < 32) return false;
1172
+ const windows: Buffer[] = [];
1173
+ for (let index = 0; index < 64; index++) {
1174
+ const offset = sampleStart + Math.floor(((sampleLength - 32) * index) / 63);
1175
+ windows.push(source.subarray(offset, offset + 32));
1176
+ }
1177
+ const byteCounts = new Map<number, number>();
1178
+ let total = 0;
1179
+ for (const window of windows) {
1180
+ for (const byte of window) {
1181
+ byteCounts.set(byte, (byteCounts.get(byte) ?? 0) + 1);
1182
+ total++;
1183
+ }
1184
+ }
1185
+ const first = windows[0]!;
1186
+ const differingWindows = windows.slice(1).filter(window => !window.equals(first)).length;
1187
+ const maxCount = Math.max(...byteCounts.values());
1188
+ return byteCounts.size >= 16 && differingWindows >= 8 && maxCount / total <= 0.95;
1189
+ }
1190
+
1191
+ async function validateScreenshotArtifact(cwd: string, row: JsonObject, fieldName: string): Promise<boolean> {
1192
+ const bytes = await readArtifactBytes(cwd, row, fieldName);
1193
+ if (!bytes) throw new Error(`qualityGate ${fieldName} screenshot artifact path must resolve to an existing file`);
1194
+ if (bytes.length < 4096) throw new Error(`qualityGate ${fieldName} screenshot artifact must be at least 4096 bytes`);
1195
+ const unsupportedFormat = unsupportedScreenshotFormat(bytes);
1196
+ if (unsupportedFormat) {
1197
+ throw new Error(
1198
+ `qualityGate ${fieldName} unsupported/undecodable screenshot format ${unsupportedFormat}; use PNG or fully marker-validated JPEG`,
1199
+ );
1200
+ }
1201
+ const dimensions = parseImageDimensions(bytes);
1202
+ if (!dimensions)
1203
+ throw new Error(`qualityGate ${fieldName} screenshot artifact must be a decodable PNG or JPEG image`);
1204
+ if (dimensions.width < 320 || dimensions.height < 180) {
1205
+ throw new Error(`qualityGate ${fieldName} screenshot artifact must be at least 320x180 pixels`);
1206
+ }
1207
+ if (!hasNonUniformImageBytes(bytes, dimensions.headerBytes, dimensions.sampleBytes)) {
1208
+ throw new Error(
1209
+ `qualityGate ${fieldName} screenshot artifact must be non-uniform, not blank, solid, tiny, or placeholder imagery`,
1210
+ );
1211
+ }
1212
+ return true;
1213
+ }
1214
+
1215
+ function normalizeTranscriptTimestamp(value: unknown): number | null {
1216
+ if (typeof value === "number" && Number.isFinite(value)) return value;
1217
+ if (typeof value !== "string" || value.trim().length === 0) return null;
1218
+ const numeric = Number(value);
1219
+ if (Number.isFinite(numeric)) return numeric;
1220
+ const parsed = Date.parse(value);
1221
+ return Number.isFinite(parsed) ? parsed : null;
1222
+ }
1223
+
1224
+ function transcriptSurfaceCompatible(value: unknown, family: SurfaceFamily): boolean {
1225
+ const surface = nonEmptyString(value);
1226
+ return !surface || family === "unknown" || surfaceFamily(surface) === family;
1227
+ }
1228
+
1229
+ function actionSelectorRequired(type: string): boolean {
1230
+ return ["click", "fill", "press", "assert", "screenshot", "observe"].includes(type);
1231
+ }
1232
+
1233
+ async function validateAutomationTranscriptArtifact(
1234
+ cwd: string,
1235
+ row: JsonObject,
1236
+ fieldName: string,
1237
+ options: { surfaceFamily: SurfaceFamily },
1238
+ ): Promise<boolean> {
1239
+ const bytes = await readArtifactBytes(cwd, row, fieldName);
1240
+ if (!bytes) throw new Error(`qualityGate ${fieldName} automation transcript path must resolve to an existing file`);
1241
+ let transcript: JsonObject;
1242
+ try {
1243
+ const parsed = JSON.parse(bytes.toString("utf8"));
1244
+ transcript = requireQualityGateObject(parsed, `${fieldName}.transcript`);
1245
+ } catch (error) {
1246
+ throw new Error(`qualityGate ${fieldName} automation transcript must be valid JSON: ${String(error)}`);
1247
+ }
1248
+ if (transcript.schemaVersion !== 1)
1249
+ throw new Error(`qualityGate ${fieldName} automation transcript schemaVersion must be 1`);
1250
+ if (!transcriptSurfaceCompatible(transcript.surface, options.surfaceFamily)) {
1251
+ throw new Error(
1252
+ `qualityGate ${fieldName} automation transcript surface is not compatible with ${options.surfaceFamily}`,
1253
+ );
1254
+ }
1255
+ if (!nonEmptyString(transcript.tool))
1256
+ throw new Error(`qualityGate ${fieldName} automation transcript tool must be non-empty`);
1257
+ const actions = requireObjectArray(transcript.actions, `${fieldName}.actions`);
1258
+ if (actions.length < 1) throw new Error(`qualityGate ${fieldName} automation transcript actions must be non-empty`);
1259
+ const assertionsValue = transcript.assertions;
1260
+ const assertions =
1261
+ assertionsValue === undefined ? [] : requireObjectArray(assertionsValue, `${fieldName}.assertions`);
1262
+ const timestamps: number[] = [];
1263
+ let hasSelectorBearingEntry = false;
1264
+ for (const [index, action] of actions.entries()) {
1265
+ const actionField = `${fieldName}.actions[${index}]`;
1266
+ const type = requiredStringField(action, "type", actionField).toLowerCase();
1267
+ const timestamp = normalizeTranscriptTimestamp(action.timestamp);
1268
+ if (timestamp === null) throw new Error(`qualityGate ${actionField}.timestamp must be present and parseable`);
1269
+ timestamps.push(timestamp);
1270
+ const selector = nonEmptyString(action.selector);
1271
+ if (actionSelectorRequired(type) && !selector)
1272
+ throw new Error(`qualityGate ${actionField}.selector must be non-empty`);
1273
+ if (type === "goto" && !nonEmptyString(action.url))
1274
+ throw new Error(`qualityGate ${actionField}.url must be non-empty`);
1275
+ if (type === "custom" && !selector && !nonEmptyString(action.target)) {
1276
+ throw new Error(`qualityGate ${actionField}.selector or target must be non-empty`);
1277
+ }
1278
+ if (selector) hasSelectorBearingEntry = true;
1279
+ }
1280
+ for (const [index, assertion] of assertions.entries()) {
1281
+ const assertionField = `${fieldName}.assertions[${index}]`;
1282
+ const timestamp = normalizeTranscriptTimestamp(assertion.timestamp);
1283
+ if (timestamp === null) throw new Error(`qualityGate ${assertionField}.timestamp must be present and parseable`);
1284
+ timestamps.push(timestamp);
1285
+ if (nonEmptyString(assertion.status)?.toLowerCase() !== PASSED_STATUS) {
1286
+ throw new Error(`qualityGate ${assertionField}.status must be passed`);
1287
+ }
1288
+ if (nonEmptyString(assertion.selector)) hasSelectorBearingEntry = true;
1289
+ }
1290
+ for (let index = 1; index < timestamps.length; index++) {
1291
+ if (timestamps[index]! < timestamps[index - 1]!) {
1292
+ throw new Error(`qualityGate ${fieldName} automation transcript timestamps must be monotonic non-decreasing`);
1293
+ }
1294
+ }
1295
+ if (!hasSelectorBearingEntry) {
1296
+ throw new Error(
1297
+ `qualityGate ${fieldName} automation transcript must include at least one selector-bearing action or assertion`,
1298
+ );
1299
+ }
1300
+ return true;
1301
+ }
1302
+
1303
+ async function validatePtyCaptureArtifact(cwd: string, row: JsonObject, fieldName: string): Promise<boolean> {
1304
+ const bytes = await readArtifactBytes(cwd, row, fieldName);
1305
+ if (!bytes) throw new Error(`qualityGate ${fieldName} PTY capture path must resolve to an existing file`);
1306
+ if (bytes.length < 512) throw new Error(`qualityGate ${fieldName} PTY capture must be at least 512 bytes`);
1307
+ const text = bytes.toString("utf8");
1308
+ const hasCsi = /\x1b\[[0-?]*[ -/]*[@-~]/.test(text);
1309
+ const hasOsc = /\x1b\][^\x07]*(?:\x07|\x1b\\)/.test(text);
1310
+ const hasAltOrCursor = /\x1b\[\?1049[hl]|\x1b\[H|\x1b\[2J/.test(text);
1311
+ const hasRedraw = /[\r\b]/.test(text) && hasCsi;
1312
+ if (!hasCsi && !hasOsc && !hasAltOrCursor && !hasRedraw) {
1313
+ throw new Error(`qualityGate ${fieldName} PTY capture must contain terminal control sequences`);
1314
+ }
1315
+ if (!/[\x20-\x7e]{10,}/.test(text)) {
1316
+ throw new Error(
1317
+ `qualityGate ${fieldName} PTY capture must contain a printable text run of at least 10 characters`,
1318
+ );
1319
+ }
1320
+ return true;
1321
+ }
1322
+
1323
+ function structuralArtifactKind(row: JsonObject): "screenshot" | "automation" | "pty" | null {
1324
+ const kind = normalizedEvidenceKind(row);
1325
+ if (evidenceKindMatches(kind, ["screenshot", "image", "visual"])) return "screenshot";
1326
+ if (evidenceKindMatches(kind, ["browser", "playwright", "pandawright", "automation", "app-automation"]))
1327
+ return "automation";
1328
+ if (evidenceKindMatches(kind, ["pty", "tui", "terminal-capture"])) return "pty";
1329
+ return null;
1330
+ }
1331
+
1332
+ async function validateStructuralArtifact(
1333
+ cwd: string,
1334
+ row: JsonObject,
1335
+ fieldName: string,
1336
+ options: { surfaceFamily: SurfaceFamily; live: boolean },
1337
+ ): Promise<boolean> {
1338
+ void options.live;
1339
+ const kind = structuralArtifactKind(row);
1340
+ if (!kind) return false;
1341
+ if (kind === "screenshot") return validateScreenshotArtifact(cwd, row, fieldName);
1342
+ if (kind === "automation") return validateAutomationTranscriptArtifact(cwd, row, fieldName, options);
1343
+ if (kind === "pty") return validatePtyCaptureArtifact(cwd, row, fieldName);
1344
+ return false;
1345
+ }
1346
+
1347
+ const CLI_REPLAY_MAX_OUTPUT_BYTES = 1024 * 1024;
1348
+ const CLI_REPLAY_DEFAULT_TIMEOUT_MS = 10_000;
1349
+ const CLI_REPLAY_MIN_TIMEOUT_MS = 1_000;
1350
+ const CLI_REPLAY_MAX_TIMEOUT_MS = 30_000;
1351
+ const CLI_REPLAY_EXEMPT_REASON_CODES = [
1352
+ "unsafe_side_effect",
1353
+ "requires_credentials",
1354
+ "requires_network",
1355
+ "non_deterministic_external",
1356
+ "destructive",
1357
+ "interactive_only",
1358
+ "platform_unavailable",
1359
+ ] as const;
1360
+ const CLI_REPLAY_EXEMPT_REASON_CODE_SET = new Set<string>(CLI_REPLAY_EXEMPT_REASON_CODES);
1361
+ const CLI_REPLAY_ENV_BASE: Record<string, string> = { CI: "1", NO_COLOR: "1", SKC_ULTRAGOAL_REPLAY: "1" };
1362
+ const CLI_REPLAY_EXEMPT_REASON_CODE_LIST = CLI_REPLAY_EXEMPT_REASON_CODES.join(", ");
1363
+ const CLI_REPLAY_SAFE_ENV_NAMES = new Set(["LANG", "LC_ALL", "LC_CTYPE", "TZ"]);
1364
+ const CLI_REPLAY_DANGEROUS_ENV_NAME_PATTERN =
1365
+ /^(?:NODE_OPTIONS|GIT_EXTERNAL_DIFF|GIT_SSH|GIT_SSH_COMMAND|GIT_PAGER|PATH|LD_PRELOAD|LD_LIBRARY_PATH)$|^(?:GIT_CONFIG|DYLD_|BUN_|NPM_CONFIG_)|(?:^|_)OPTIONS$|PRELOAD$/;
1366
+ const ANSI_ESCAPE_PATTERN = /\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1b\\)|[@-Z\\-_])/g;
1367
+
1368
+ function clampCliReplayTimeout(value: unknown): number {
1369
+ if (value === undefined) return CLI_REPLAY_DEFAULT_TIMEOUT_MS;
1370
+ if (typeof value !== "number" || !Number.isFinite(value)) {
1371
+ throw new Error("qualityGate CLI replay timeoutMs must be a finite number");
1372
+ }
1373
+ return Math.min(CLI_REPLAY_MAX_TIMEOUT_MS, Math.max(CLI_REPLAY_MIN_TIMEOUT_MS, Math.trunc(value)));
1374
+ }
1375
+
1376
+ function basenameCommand(value: string): string {
1377
+ return path.basename(value).toLowerCase();
1378
+ }
1379
+
1380
+ function isDeterministicConsoleLogReplay(code: string): boolean {
1381
+ let remaining = code.trim();
1382
+ if (remaining.length === 0) return false;
1383
+ let matched = false;
1384
+ while (remaining.length > 0) {
1385
+ const match =
1386
+ /^console\.log\(\s*("(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\])*'|`(?:\\[\s\S]|[^`\\$])*`)\s*\)\s*;?\s*/.exec(
1387
+ remaining,
1388
+ );
1389
+ if (!match) return false;
1390
+ const statement = match[0]!;
1391
+ const literal = match[1]!;
1392
+ if (literal.startsWith("`") && literal.includes("${")) return false;
1393
+ matched = true;
1394
+ remaining = remaining.slice(statement.length);
1395
+ }
1396
+ return matched;
1397
+ }
1398
+
1399
+ function hasShellRedirectionToken(value: string): boolean {
1400
+ return /^(?:[<>]|\d?[<>]|\d?>&\d|\|\|?|&&|;)$/.test(value) || /(?:^|[^\w])-?>/.test(value);
1401
+ }
1402
+
1403
+ function isSafeRefOrPathspec(value: string): boolean {
1404
+ return value.length > 0 && !value.startsWith("-") && !/[\0\n\r]/.test(value) && !hasShellRedirectionToken(value);
1405
+ }
1406
+
1407
+ function isAllowedGitReplayCommand(args: readonly string[]): boolean {
1408
+ const subcommand = args[0];
1409
+ const rest = args.slice(1);
1410
+ if (subcommand === "status") return rest.every(arg => ["--short", "--porcelain", "--branch"].includes(arg));
1411
+ if (subcommand === "rev-parse" || subcommand === "merge-base")
1412
+ return rest.length > 0 && rest.every(isSafeRefOrPathspec);
1413
+ if (subcommand !== "diff" && subcommand !== "show" && subcommand !== "log") return false;
1414
+ let pathspecMode = false;
1415
+ for (const arg of rest) {
1416
+ if (arg === "--") {
1417
+ pathspecMode = true;
1418
+ continue;
1419
+ }
1420
+ if (pathspecMode) {
1421
+ if (!isSafeRefOrPathspec(arg)) return false;
1422
+ continue;
1423
+ }
1424
+ if (["--stat", "--name-only", "--oneline", "--no-ext-diff"].includes(arg)) continue;
1425
+ if (!isSafeRefOrPathspec(arg)) return false;
1426
+ }
1427
+ return true;
1428
+ }
1429
+
1430
+ function isBareExecutableName(value: string): boolean {
1431
+ // The allowlist is keyed on the basename, but the raw command[0] is what gets spawned.
1432
+ // Reject path-qualified or case-spoofed executables (e.g. ./git, /tmp/npm, scripts/node, GIT)
1433
+ // so an attacker-controlled binary cannot impersonate a trusted tool.
1434
+ return (
1435
+ value.length > 0 &&
1436
+ !value.includes("/") &&
1437
+ !value.includes("\\") &&
1438
+ value === path.basename(value) &&
1439
+ value === value.toLowerCase()
1440
+ );
1441
+ }
1442
+
1443
+ function isAllowedCliReplayCommand(command: readonly string[]): boolean {
1444
+ if (
1445
+ command.length === 0 ||
1446
+ command.some(arg => arg.trim() !== arg || arg.length === 0 || hasShellRedirectionToken(arg))
1447
+ )
1448
+ return false;
1449
+ if (!isBareExecutableName(command[0]!)) return false;
1450
+ const executable = basenameCommand(command[0]!);
1451
+ const args = command.slice(1);
1452
+ if (executable === "bun" || executable === "node") {
1453
+ if (args.length === 1 && args[0] === "--version") return true;
1454
+ return args.length === 2 && args[0] === "-e" && isDeterministicConsoleLogReplay(args[1]!);
1455
+ }
1456
+ if (executable === "npm" || executable === "pnpm" || executable === "yarn") {
1457
+ return (args.length === 1 && args[0] === "--version") || (args.length === 1 && args[0] === "list");
1458
+ }
1459
+ if (executable === "git") return isAllowedGitReplayCommand(args);
1460
+ if (executable === "skc") return args.length === 1 && ["read", "status"].includes(args[0] ?? "");
1461
+ return false;
1462
+ }
1463
+
1464
+ function resolveCliReplayCommand(command: string[]): string[] {
1465
+ if (basenameCommand(command[0]!) === "bun") return [process.execPath, ...command.slice(1)];
1466
+ return command;
1467
+ }
1468
+
1469
+ function resolveUnderCwd(cwd: string, replayCwd: unknown, fieldName: string): string {
1470
+ const relative = replayCwd === undefined ? "." : nonEmptyString(replayCwd);
1471
+ if (!relative) throw new Error(`qualityGate ${fieldName}.cwd must be a non-empty string when provided`);
1472
+ const root = path.resolve(cwd);
1473
+ const resolved = path.resolve(root, relative);
1474
+ const relativeToRoot = path.relative(root, resolved);
1475
+ if (relativeToRoot === ".." || relativeToRoot.startsWith(`..${path.sep}`) || path.isAbsolute(relativeToRoot)) {
1476
+ throw new Error(`qualityGate ${fieldName}.cwd must resolve under the repository cwd`);
1477
+ }
1478
+ return resolved;
1479
+ }
1480
+
1481
+ function buildCliReplayEnv(value: unknown, fieldName: string): Record<string, string> {
1482
+ const env: Record<string, string> = { ...CLI_REPLAY_ENV_BASE };
1483
+ if (value === undefined) return env;
1484
+ const object = requireQualityGateObject(value, `${fieldName}.env`);
1485
+ for (const [key, envValue] of Object.entries(object)) {
1486
+ if (!/^[A-Z_][A-Z0-9_]*$/.test(key))
1487
+ throw new Error(`qualityGate ${fieldName}.env.${key} must be an uppercase environment key`);
1488
+ if (CLI_REPLAY_DANGEROUS_ENV_NAME_PATTERN.test(key) || !CLI_REPLAY_SAFE_ENV_NAMES.has(key)) {
1489
+ throw new Error(`qualityGate ${fieldName}.env.${key} is not in the CLI replay safe environment allowlist`);
1490
+ }
1491
+ if (typeof envValue !== "string") throw new Error(`qualityGate ${fieldName}.env.${key} must be a string`);
1492
+ env[key] = envValue;
1493
+ }
1494
+ return env;
1495
+ }
1496
+
1497
+ function normalizeCliReplayOutput(value: string, cwd: string): string {
1498
+ let normalized = value.replace(ANSI_ESCAPE_PATTERN, "").replace(/\r\n?/g, "\n");
1499
+ const home = process.env.HOME;
1500
+ const replacements: Array<[RegExp, string]> = [
1501
+ [/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z\b/g, "<TIMESTAMP>"],
1502
+ [/\b[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\b/gi, "<UUID>"],
1503
+ [/\b[0-9a-f]{7,}\b/gi, "<HASH>"],
1504
+ [/(?:\/private)?\/var\/folders\/[^\s"']+|\/tmp\/[^\s"']+|\/var\/tmp\/[^\s"']+/g, "<TMP>"],
1505
+ ];
1506
+ for (const candidate of [path.resolve(cwd), home]) {
1507
+ if (!candidate) continue;
1508
+ const escaped = candidate.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1509
+ normalized = normalized.replace(new RegExp(escaped, "g"), candidate === home ? "<HOME>" : "<CWD>");
1510
+ }
1511
+ for (const [pattern, replacement] of replacements) normalized = normalized.replace(pattern, replacement);
1512
+ const lines = normalized.split("\n").map(line => line.replace(/[ \t]+$/g, ""));
1513
+ while (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
1514
+ return lines.join("\n");
1515
+ }
1516
+
1517
+ async function readCliReplayRecord(cwd: string, row: JsonObject, fieldName: string): Promise<JsonObject | null> {
1518
+ const inline = qualityGateObject(row.replay) ?? (row.kind === "cli-replay" ? row : null);
1519
+ if (inline) return inline;
1520
+ if (!evidenceKindMatches(normalizedEvidenceKind(row), ["cli-replay", "command-replay"])) return null;
1521
+ const bytes = await readArtifactBytes(cwd, row, fieldName);
1522
+ if (!bytes) return null;
1523
+ try {
1524
+ return requireQualityGateObject(JSON.parse(bytes.toString("utf8")), `${fieldName}.replay`);
1525
+ } catch (error) {
1526
+ throw new Error(`qualityGate ${fieldName} CLI replay artifact must be valid JSON: ${String(error)}`);
1527
+ }
1528
+ }
1529
+
1530
+ function parseCliReplayRecord(
1531
+ record: JsonObject,
1532
+ fieldName: string,
1533
+ ): {
1534
+ command: string[];
1535
+ replayCwd: unknown;
1536
+ env: Record<string, string>;
1537
+ timeoutMs: number;
1538
+ expectedExitCode: number;
1539
+ recordedStdout: string;
1540
+ invariants: JsonObject[];
1541
+ } {
1542
+ if (record.schemaVersion !== 1) throw new Error(`qualityGate ${fieldName}.schemaVersion must be 1`);
1543
+ if (record.kind !== "cli-replay") throw new Error(`qualityGate ${fieldName}.kind must be cli-replay`);
1544
+ if (record.command !== undefined && typeof record.command === "string") {
1545
+ throw new Error(`qualityGate ${fieldName}.command must be an argv string array, not a shell string`);
1546
+ }
1547
+ const command = nonEmptyStringArray(record.command);
1548
+ if (!command) throw new Error(`qualityGate ${fieldName}.command must be a non-empty string array`);
1549
+ if (record.replaySafe !== true)
1550
+ throw new Error(`qualityGate ${fieldName}.replaySafe must be true before CLI replay executes`);
1551
+ if (!isAllowedCliReplayCommand(command))
1552
+ throw new Error(`qualityGate ${fieldName}.command is not in the conservative CLI replay allowlist`);
1553
+ if (record.normalization !== undefined && record.normalization !== "default") {
1554
+ throw new Error(`qualityGate ${fieldName}.normalization must be default when provided`);
1555
+ }
1556
+ if (typeof record.recordedStdout !== "string")
1557
+ throw new Error(`qualityGate ${fieldName}.recordedStdout must be a string`);
1558
+ if (record.recordedStderr !== undefined && typeof record.recordedStderr !== "string") {
1559
+ throw new Error(`qualityGate ${fieldName}.recordedStderr must be a string when provided`);
1560
+ }
1561
+ const expectedExitCode = record.expectedExitCode === undefined ? 0 : record.expectedExitCode;
1562
+ if (typeof expectedExitCode !== "number" || !Number.isInteger(expectedExitCode)) {
1563
+ throw new Error(`qualityGate ${fieldName}.expectedExitCode must be an integer`);
1564
+ }
1565
+ const invariants =
1566
+ record.invariants === undefined ? [] : requireObjectArray(record.invariants, `${fieldName}.invariants`);
1567
+ return {
1568
+ command: command.map(item => item.trim()),
1569
+ replayCwd: record.cwd,
1570
+ env: buildCliReplayEnv(record.env, fieldName),
1571
+ timeoutMs: clampCliReplayTimeout(record.timeoutMs),
1572
+ expectedExitCode,
1573
+ recordedStdout: record.recordedStdout,
1574
+ invariants,
1575
+ };
1576
+ }
1577
+
1578
+ function validateCliReplayInvariants(invariants: JsonObject[], stdout: string, fieldName: string): void {
1579
+ for (const [index, invariant] of invariants.entries()) {
1580
+ const invariantField = `${fieldName}.invariants[${index}]`;
1581
+ const type = requiredStringField(invariant, "type", invariantField);
1582
+ const value = requiredStringField(invariant, "value", invariantField);
1583
+ if (type === "substring" && !stdout.includes(value))
1584
+ throw new Error(`qualityGate ${invariantField} substring invariant did not match stdout`);
1585
+ else if (type === "not_substring" && stdout.includes(value))
1586
+ throw new Error(`qualityGate ${invariantField} not_substring invariant matched stdout`);
1587
+ else if (type === "regex") {
1588
+ const flags = invariant.flags === undefined ? "" : requiredStringField(invariant, "flags", invariantField);
1589
+ if (!/^[im]*$/.test(flags)) throw new Error(`qualityGate ${invariantField}.flags may only contain i and m`);
1590
+ if (!new RegExp(value, flags).test(stdout))
1591
+ throw new Error(`qualityGate ${invariantField} regex invariant did not match stdout`);
1592
+ } else if (type !== "substring" && type !== "not_substring") {
1593
+ throw new Error(`qualityGate ${invariantField}.type must be substring, regex, or not_substring`);
1594
+ }
1595
+ }
1596
+ }
1597
+
1598
+ async function collectCliReplayOutput(
1599
+ stream: ReadableStream<Uint8Array> | null,
1600
+ ): Promise<{ text: string; truncated: boolean }> {
1601
+ if (!stream) return { text: "", truncated: false };
1602
+ const reader = stream.getReader();
1603
+ const chunks: Buffer[] = [];
1604
+ let size = 0;
1605
+ let truncated = false;
1606
+ try {
1607
+ while (true) {
1608
+ const { done, value } = await reader.read();
1609
+ if (done) break;
1610
+ if (size < CLI_REPLAY_MAX_OUTPUT_BYTES) {
1611
+ const remaining = CLI_REPLAY_MAX_OUTPUT_BYTES - size;
1612
+ const chunk = Buffer.from(value.subarray(0, remaining));
1613
+ chunks.push(chunk);
1614
+ size += chunk.length;
1615
+ }
1616
+ if (value.length > 0 && size >= CLI_REPLAY_MAX_OUTPUT_BYTES) {
1617
+ truncated = true;
1618
+ await reader.cancel().catch(() => undefined);
1619
+ break;
1620
+ }
1621
+ }
1622
+ } finally {
1623
+ reader.releaseLock();
1624
+ }
1625
+ return { text: Buffer.concat(chunks).toString("utf8"), truncated };
1626
+ }
1627
+
1628
+ export interface ReplayProcessHandle {
1629
+ readonly exited: Promise<number>;
1630
+ kill(signal?: number | NodeJS.Signals): void;
1631
+ }
1632
+
1633
+ export async function waitForReplayProcessWithTimeout(
1634
+ process: ReplayProcessHandle,
1635
+ timeoutMs: number,
1636
+ graceMs = 2000,
1637
+ ): Promise<number> {
1638
+ let timeoutTimer: NodeJS.Timeout | undefined;
1639
+ let graceTimer: NodeJS.Timeout | undefined;
1640
+ const timedOut = Symbol("timedOut");
1641
+ const timeout = new Promise<typeof timedOut>(resolve => {
1642
+ timeoutTimer = setTimeout(() => resolve(timedOut), timeoutMs);
1643
+ });
1644
+ const first = await Promise.race([process.exited, timeout]);
1645
+ if (first !== timedOut) {
1646
+ if (timeoutTimer) clearTimeout(timeoutTimer);
1647
+ return first;
1648
+ }
1649
+ process.kill("SIGTERM");
1650
+ const killed = Symbol("killed");
1651
+ const grace = new Promise<typeof killed>(resolve => {
1652
+ graceTimer = setTimeout(() => {
1653
+ process.kill("SIGKILL");
1654
+ resolve(killed);
1655
+ }, graceMs);
1656
+ });
1657
+ await Promise.race([process.exited, grace]);
1658
+ await process.exited.catch(() => undefined);
1659
+ if (timeoutTimer) clearTimeout(timeoutTimer);
1660
+ if (graceTimer) clearTimeout(graceTimer);
1661
+ throw new Error("timeout");
1662
+ }
1663
+
1664
+ async function validateReplayExemptFallback(
1665
+ cwd: string,
1666
+ record: JsonObject,
1667
+ fieldName: string,
1668
+ artifactRefs: Map<string, JsonObject>,
1669
+ options: { surfaceFamily: SurfaceFamily; live: boolean },
1670
+ ): Promise<boolean> {
1671
+ const exempt = qualityGateObject(record.replayExempt);
1672
+ if (!exempt) return false;
1673
+ const reasonCode = requiredStringField(exempt, "reasonCode", `${fieldName}.replayExempt`);
1674
+ if (!CLI_REPLAY_EXEMPT_REASON_CODE_SET.has(reasonCode))
1675
+ throw new Error(
1676
+ `qualityGate ${fieldName}.replayExempt.reasonCode must be one of: ${CLI_REPLAY_EXEMPT_REASON_CODE_LIST}`,
1677
+ );
1678
+ const reason = requiredStringField(exempt, "reason", `${fieldName}.replayExempt`);
1679
+ if (!isSubstantiveEvidence(reason) || reason.length < 30)
1680
+ throw new Error(`qualityGate ${fieldName}.replayExempt.reason must be audited and substantive`);
1681
+ requiredStringField(exempt, "approvedBy", `${fieldName}.replayExempt`);
1682
+ const fallbackRefs = requireStringLinks(
1683
+ exempt.fallbackArtifactRefs,
1684
+ `${fieldName}.replayExempt.fallbackArtifactRefs`,
1685
+ );
1686
+ requireResolvedLinks(fallbackRefs, artifactRefs, `${fieldName}.replayExempt.fallbackArtifactRefs`);
1687
+ let validFallback = false;
1688
+ for (const fallbackRef of fallbackRefs) {
1689
+ if (fallbackRef === requiredStringField(record, "id", fieldName)) {
1690
+ throw new Error(`qualityGate ${fieldName}.replayExempt fallback must not reference the replay record itself`);
1691
+ }
1692
+ const fallback = artifactRefs.get(fallbackRef)!;
1693
+ if (await validateStructuralArtifact(cwd, fallback, `executorQa.artifactRefs.${fallbackRef}`, options))
1694
+ validFallback = true;
1695
+ }
1696
+ if (!validFallback)
1697
+ throw new Error(
1698
+ `qualityGate ${fieldName}.replayExempt requires at least one structurally-valid fallback artifact`,
1699
+ );
1700
+ return true;
1701
+ }
1702
+ async function validateCliReplay(
1703
+ cwd: string,
1704
+ row: JsonObject,
1705
+ fieldName: string,
1706
+ options: { live: boolean },
1707
+ ): Promise<boolean> {
1708
+ const record = await readCliReplayRecord(cwd, row, fieldName);
1709
+ if (!record) return false;
1710
+ if (record.replayExempt !== undefined) {
1711
+ throw new Error(
1712
+ `qualityGate ${fieldName}.replayExempt can only be validated from surfaceEvidence with fallback context`,
1713
+ );
1714
+ }
1715
+ void options.live;
1716
+ const replay = parseCliReplayRecord(record, fieldName);
1717
+ const replayCwd = resolveUnderCwd(cwd, replay.replayCwd, fieldName);
1718
+ const process = Bun.spawn(resolveCliReplayCommand(replay.command), {
1719
+ cwd: replayCwd,
1720
+ env: replay.env,
1721
+ stdout: "pipe",
1722
+ stderr: "pipe",
1723
+ });
1724
+ try {
1725
+ const [stdout, stderr, exitCode] = await Promise.all([
1726
+ collectCliReplayOutput(process.stdout),
1727
+ collectCliReplayOutput(process.stderr),
1728
+ waitForReplayProcessWithTimeout(process, replay.timeoutMs),
1729
+ ]);
1730
+ if (stdout.truncated || stderr.truncated)
1731
+ throw new Error(`qualityGate ${fieldName} CLI replay output exceeded 1 MiB buffer cap`);
1732
+ if (exitCode !== replay.expectedExitCode) {
1733
+ throw new Error(
1734
+ `qualityGate ${fieldName} CLI replay exit code ${exitCode} did not match expected ${replay.expectedExitCode}`,
1735
+ );
1736
+ }
1737
+ const actualStdout = normalizeCliReplayOutput(stdout.text, cwd);
1738
+ const recordedStdout = normalizeCliReplayOutput(replay.recordedStdout, cwd);
1739
+ if (replay.invariants.length > 0) {
1740
+ validateCliReplayInvariants(replay.invariants, actualStdout, fieldName);
1741
+ } else if (actualStdout !== recordedStdout) {
1742
+ throw new Error(`qualityGate ${fieldName} CLI replay stdout did not match recordedStdout after normalization`);
1743
+ }
1744
+ return true;
1745
+ } catch (error) {
1746
+ if (error instanceof Error && error.message === "timeout") {
1747
+ throw new Error(`qualityGate ${fieldName} CLI replay timed out after ${replay.timeoutMs}ms`);
1748
+ }
1749
+ throw error;
1750
+ }
1751
+ }
1752
+
1753
+ async function hasLiveProofPresence(
1754
+ cwd: string,
1755
+ row: JsonObject,
1756
+ fieldName: string,
1757
+ family: SurfaceFamily,
1758
+ ): Promise<boolean> {
1759
+ if (await hasExistingNonEmptyArtifact(cwd, row.path)) return true;
1760
+ if (family === "cli") {
1761
+ const record = await readCliReplayRecord(cwd, row, fieldName);
1762
+ if (record) return true;
1763
+ }
1764
+ return false;
1765
+ }
1766
+
1767
+ async function validateLiveSurfaceProofPresence(
1768
+ cwd: string,
1769
+ family: SurfaceFamily,
1770
+ artifactIds: string[],
1771
+ artifactRefs: Map<string, JsonObject>,
1772
+ ): Promise<void> {
1773
+ if (!isLiveSurfaceFamily(family)) return;
1774
+ for (const artifactId of artifactIds) {
1775
+ if (
1776
+ await hasLiveProofPresence(cwd, artifactRefs.get(artifactId)!, `executorQa.artifactRefs.${artifactId}`, family)
1777
+ )
1778
+ return;
1779
+ }
1780
+ throw new Error(
1781
+ `qualityGate ${artifactIds.map(id => `executorQa.artifactRefs.${id}`).join(", ")} must reference a live proof artifact, structural capture, or CLI replay; inlineEvidence and typed verifiedReceipt do not prove live surfaces`,
1782
+ );
1783
+ }
1784
+ async function validateSurfaceStructuralRequirement(
1785
+ cwd: string,
1786
+ family: SurfaceFamily,
1787
+ artifactIds: string[],
1788
+ artifactRefs: Map<string, JsonObject>,
1789
+ fieldName: string,
1790
+ ): Promise<void> {
1791
+ if (family !== "web" && family !== "native") return;
1792
+ let hasScreenshot = false;
1793
+ let hasAutomation = false;
1794
+ let hasPty = false;
1795
+ for (const artifactId of artifactIds) {
1796
+ const artifact = artifactRefs.get(artifactId)!;
1797
+ const kind = structuralArtifactKind(artifact);
1798
+ if (!kind) continue;
1799
+ const valid = await validateStructuralArtifact(cwd, artifact, `executorQa.artifactRefs.${artifactId}`, {
1800
+ surfaceFamily: family,
1801
+ live: true,
1802
+ });
1803
+ if (kind === "screenshot" && valid) hasScreenshot = true;
1804
+ if (kind === "automation" && valid) hasAutomation = true;
1805
+ if (kind === "pty" && valid) hasPty = true;
1806
+ }
1807
+ if (family === "web" && (!hasScreenshot || !hasAutomation)) {
1808
+ throw new Error(
1809
+ `qualityGate ${fieldName} for GUI/web surfaces must include a valid automation transcript and non-uniform screenshot`,
1810
+ );
1811
+ }
1812
+ if (family === "native" && !hasScreenshot && !hasAutomation && !hasPty) {
1813
+ throw new Error(
1814
+ `qualityGate ${fieldName} for native surfaces must include a valid screenshot, PTY capture, or app-automation transcript`,
1815
+ );
1816
+ }
1817
+ }
1818
+
1819
+ async function validateArtifactProof(
1820
+ cwd: string,
1821
+ row: JsonObject,
1822
+ fieldName: string,
1823
+ options: { surfaceFamily: SurfaceFamily; live: boolean },
1824
+ ): Promise<void> {
1825
+ if (await hasExistingNonEmptyArtifact(cwd, row.path)) return;
1826
+ if (await validateStructuralArtifact(cwd, row, fieldName, options)) return;
1827
+ if (options.surfaceFamily === "cli" && (await validateCliReplay(cwd, row, fieldName, { live: options.live })))
1828
+ return;
1829
+ if (!options.live && (hasTypedVerifiedReceipt(row.verifiedReceipt) || hasTypedVerifiedReceipt(row.receipt))) return;
1830
+ const proofLabel = options.live
1831
+ ? "a live proof artifact, structural capture, or CLI replay; inlineEvidence and typed verifiedReceipt do not prove live surfaces"
1832
+ : "an existing non-empty artifact path or a typed verifiedReceipt; inlineEvidence alone is not sufficient";
1833
+ throw new Error(`qualityGate ${fieldName} must reference ${proofLabel}`);
1834
+ }
1835
+
1836
+ async function validateArtifactRefs(cwd: string, executorQa: JsonObject): Promise<Map<string, JsonObject>> {
1837
+ void cwd;
1838
+ const rows = requireObjectArray(executorQa.artifactRefs, "executorQa.artifactRefs");
1839
+ const idMap = buildRowIdMap(rows, "executorQa.artifactRefs");
1840
+ for (const [index, row] of rows.entries()) {
1841
+ const fieldName = `executorQa.artifactRefs[${index}]`;
1842
+ requiredStringField(row, "kind", fieldName);
1843
+ requiredStringField(row, "description", fieldName);
1844
+ }
1845
+ return idMap;
1846
+ }
1847
+
1848
+ async function validateSurfaceEvidence(
1849
+ cwd: string,
1850
+ executorQa: JsonObject,
1851
+ artifactRefs: Map<string, JsonObject>,
1852
+ ): Promise<Map<string, JsonObject>> {
1853
+ const rows = requireObjectArray(executorQa.surfaceEvidence, "executorQa.surfaceEvidence");
1854
+ const idMap = buildRowIdMap(rows, "executorQa.surfaceEvidence");
1855
+ for (const [index, row] of rows.entries()) {
1856
+ const fieldName = `executorQa.surfaceEvidence[${index}]`;
1857
+ const status = optionalStatusField(row, fieldName);
1858
+ requiredStringField(row, "contractRef", fieldName);
1859
+ if (status === NOT_APPLICABLE_STATUS) {
1860
+ requiredStringField(row, "reason", fieldName);
1861
+ continue;
1862
+ }
1863
+ const surface = requiredStringField(row, "surface", fieldName);
1864
+ const family = surfaceFamily(surface);
1865
+ requireSuccessfulRowOutcome(row, fieldName);
1866
+ requiredStringField(row, "invocation", fieldName);
1867
+ if (typeof row.verdict !== "string" || row.verdict.trim().length === 0) {
1868
+ requiredStringField(row, "result", fieldName);
1869
+ }
1870
+ const artifactIds = requireStringLinks(row.artifactRefs, `${fieldName}.artifactRefs`);
1871
+ requireResolvedLinks(artifactIds, artifactRefs, `${fieldName}.artifactRefs`);
1872
+ await validateLiveSurfaceProofPresence(cwd, family, artifactIds, artifactRefs);
1873
+ validateSurfaceArtifactCompatibility(surface, artifactIds, artifactRefs, `${fieldName}.artifactRefs`);
1874
+ await validateSurfaceStructuralRequirement(cwd, family, artifactIds, artifactRefs, `${fieldName}.artifactRefs`);
1875
+ if (family === "cli") {
1876
+ let hasPassingReplay = false;
1877
+ for (const artifactId of artifactIds) {
1878
+ const artifact = artifactRefs.get(artifactId)!;
1879
+ const artifactField = `executorQa.artifactRefs.${artifactId}`;
1880
+ const record = await readCliReplayRecord(cwd, artifact, artifactField);
1881
+ if (!record) continue;
1882
+ if (record.replayExempt !== undefined) {
1883
+ if (
1884
+ await validateReplayExemptFallback(cwd, { ...record, id: artifactId }, artifactField, artifactRefs, {
1885
+ surfaceFamily: family,
1886
+ live: true,
1887
+ })
1888
+ ) {
1889
+ hasPassingReplay = true;
1890
+ }
1891
+ } else if (await validateCliReplay(cwd, artifact, artifactField, { live: true })) {
1892
+ hasPassingReplay = true;
1893
+ }
1894
+ }
1895
+ if (!hasPassingReplay) {
1896
+ throw new Error(
1897
+ `qualityGate ${fieldName} for CLI surfaces must include a passing argv CLI replay or valid replayExempt fallback`,
1898
+ );
1899
+ }
1900
+ }
1901
+ for (const artifactId of artifactIds) {
1902
+ if (family === "cli") {
1903
+ const record = await readCliReplayRecord(
1904
+ cwd,
1905
+ artifactRefs.get(artifactId)!,
1906
+ `executorQa.artifactRefs.${artifactId}`,
1907
+ );
1908
+ if (record?.replayExempt !== undefined) continue;
1909
+ }
1910
+ await validateArtifactProof(cwd, artifactRefs.get(artifactId)!, `executorQa.artifactRefs.${artifactId}`, {
1911
+ surfaceFamily: family,
1912
+ live: isLiveSurfaceFamily(family),
1913
+ });
1914
+ }
1915
+ }
1916
+ return idMap;
1917
+ }
1918
+
1919
+ function validateAdversarialCases(
1920
+ executorQa: JsonObject,
1921
+ artifactRefs: Map<string, JsonObject>,
1922
+ ): Map<string, JsonObject> {
1923
+ const rows = requireObjectArray(executorQa.adversarialCases, "executorQa.adversarialCases");
1924
+ const idMap = buildRowIdMap(rows, "executorQa.adversarialCases");
1925
+ for (const [index, row] of rows.entries()) {
1926
+ const fieldName = `executorQa.adversarialCases[${index}]`;
1927
+ const status = optionalStatusField(row, fieldName);
1928
+ if (status === NOT_APPLICABLE_STATUS) {
1929
+ throw new Error(`qualityGate ${fieldName}.status must not be not_applicable`);
1930
+ }
1931
+ requireSuccessfulRowOutcome(row, fieldName);
1932
+ requiredStringField(row, "contractRef", fieldName);
1933
+ requiredStringField(row, "scenario", fieldName);
1934
+ requiredStringField(row, "expectedBehavior", fieldName);
1935
+ if (typeof row.verdict !== "string" || row.verdict.trim().length === 0) {
1936
+ requiredStringField(row, "result", fieldName);
1937
+ }
1938
+ const artifactIds = requireStringLinks(row.artifactRefs, `${fieldName}.artifactRefs`);
1939
+ requireResolvedLinks(artifactIds, artifactRefs, `${fieldName}.artifactRefs`);
1940
+ }
1941
+ return idMap;
1942
+ }
1943
+
1944
+ async function validateMandatoryComputerAdversarialCases(
1945
+ cwd: string,
1946
+ contractCoverage: JsonObject[],
1947
+ adversarialCases: Map<string, JsonObject>,
1948
+ artifactRefs: Map<string, JsonObject>,
1949
+ ): Promise<void> {
1950
+ const linkedCaseIds = new Set<string>();
1951
+ for (const [index, row] of contractCoverage.entries()) {
1952
+ const ids = optionalStringLinks(row, "adversarialCaseRefs", `executorQa.contractCoverage[${index}]`);
1953
+ for (const id of ids ?? []) linkedCaseIds.add(normalizeAdversarialCaseId(id));
1954
+ }
1955
+ for (const caseId of MANDATORY_COMPUTER_CASE_IDS) {
1956
+ const row = adversarialCases.get(caseId);
1957
+ if (!row)
1958
+ throw new Error(
1959
+ `COMPUTER_REDTEAM_CASE_MISSING: qualityGate executorQa.adversarialCases must include ${caseId}`,
1960
+ );
1961
+ if (optionalStatusField(row, `executorQa.adversarialCases.${caseId}`) === NOT_APPLICABLE_STATUS) {
1962
+ throw new Error(
1963
+ `COMPUTER_REDTEAM_CASE_NOT_APPLICABLE: mandatory computer adversarial case ${caseId} must not be not_applicable`,
1964
+ );
1965
+ }
1966
+ if (!linkedCaseIds.has(caseId)) {
1967
+ throw new Error(
1968
+ `COMPUTER_REDTEAM_CASE_UNLINKED: mandatory computer adversarial case ${caseId} must be linked from contractCoverage.adversarialCaseRefs`,
1969
+ );
1970
+ }
1971
+ const artifactIds = requireStringLinks(row.artifactRefs, `executorQa.adversarialCases.${caseId}.artifactRefs`);
1972
+ let hasValidLiveNativeProof = false;
1973
+ let sawInlineOnly = false;
1974
+ let sawReceiptOnly = false;
1975
+ let sawMetadataOnly = false;
1976
+ for (const artifactId of artifactIds) {
1977
+ const artifact = artifactRefs.get(artifactId);
1978
+ if (!artifact)
1979
+ throw new Error(
1980
+ `qualityGate executorQa.adversarialCases.${caseId}.artifactRefs references unknown id ${artifactId}`,
1981
+ );
1982
+ const fieldName = `executorQa.artifactRefs.${artifactId}`;
1983
+ if (artifact.inlineEvidence !== undefined && !nonEmptyString(artifact.path)) sawInlineOnly = true;
1984
+ if (
1985
+ (artifact.verifiedReceipt !== undefined || artifact.receipt !== undefined) &&
1986
+ !nonEmptyString(artifact.path)
1987
+ )
1988
+ sawReceiptOnly = true;
1989
+ if (
1990
+ !nonEmptyString(artifact.path) &&
1991
+ artifact.inlineEvidence === undefined &&
1992
+ artifact.verifiedReceipt === undefined &&
1993
+ artifact.receipt === undefined
1994
+ )
1995
+ sawMetadataOnly = true;
1996
+ try {
1997
+ await validateArtifactProof(cwd, artifact, fieldName, { surfaceFamily: "native", live: true });
1998
+ if (await validateStructuralArtifact(cwd, artifact, fieldName, { surfaceFamily: "native", live: true }))
1999
+ hasValidLiveNativeProof = true;
2000
+ } catch {
2001
+ // Preserve the explicit computer red-team error taxonomy below.
2002
+ }
2003
+ }
2004
+ if (!hasValidLiveNativeProof) {
2005
+ if (sawInlineOnly)
2006
+ throw new Error(
2007
+ `COMPUTER_REDTEAM_INLINE_ONLY: mandatory computer adversarial case ${caseId} requires live structural native proof`,
2008
+ );
2009
+ if (sawReceiptOnly)
2010
+ throw new Error(
2011
+ `COMPUTER_REDTEAM_RECEIPT_ONLY: mandatory computer adversarial case ${caseId} requires live structural native proof`,
2012
+ );
2013
+ if (sawMetadataOnly)
2014
+ throw new Error(
2015
+ `COMPUTER_REDTEAM_ARTIFACT_METADATA_ONLY: mandatory computer adversarial case ${caseId} requires durable live structural native proof`,
2016
+ );
2017
+ throw new Error(
2018
+ `COMPUTER_REDTEAM_ARTIFACT_MISSING: mandatory computer adversarial case ${caseId} requires at least one valid live structural native proof artifact`,
2019
+ );
2020
+ }
2021
+ }
2022
+ }
2023
+
2024
+ function validateContractCoverage(
2025
+ executorQa: JsonObject,
2026
+ surfaceEvidence: Map<string, JsonObject>,
2027
+ adversarialCases: Map<string, JsonObject>,
2028
+ artifactRefs: Map<string, JsonObject>,
2029
+ ): JsonObject[] {
2030
+ const rows = requireObjectArray(executorQa.contractCoverage, "executorQa.contractCoverage");
2031
+ buildRowIdMap(rows, "executorQa.contractCoverage");
2032
+ let hasSuccessfulContractCoverage = false;
2033
+ for (const [index, row] of rows.entries()) {
2034
+ const fieldName = `executorQa.contractCoverage[${index}]`;
2035
+ requiredStringField(row, "contractRef", fieldName);
2036
+ const status = optionalStatusField(row, fieldName);
2037
+ if (status === NOT_APPLICABLE_STATUS) {
2038
+ requiredStringField(row, "reason", fieldName);
2039
+ continue;
2040
+ }
2041
+ requiredStringField(row, "obligation", fieldName);
2042
+ if (!status) throw new Error(`qualityGate ${fieldName}.status must be a non-empty string`);
2043
+ requireSuccessStatus(status, fieldName);
2044
+ hasSuccessfulContractCoverage = true;
2045
+ const surfaceIds = optionalStringLinks(row, "surfaceEvidenceRefs", fieldName);
2046
+ const adversarialIds = optionalStringLinks(row, "adversarialCaseRefs", fieldName);
2047
+ const artifactIds = optionalStringLinks(row, "artifactRefs", fieldName);
2048
+ if (!surfaceIds && !adversarialIds && !artifactIds) {
2049
+ throw new Error(
2050
+ `qualityGate ${fieldName} must link to surfaceEvidenceRefs, adversarialCaseRefs, or artifactRefs`,
2051
+ );
2052
+ }
2053
+ let successfulProofLinks = 0;
2054
+ if (surfaceIds)
2055
+ successfulProofLinks += successfulLinkedRows(
2056
+ surfaceIds,
2057
+ surfaceEvidence,
2058
+ `${fieldName}.surfaceEvidenceRefs`,
2059
+ ).length;
2060
+ if (adversarialIds) {
2061
+ successfulProofLinks += successfulLinkedRows(
2062
+ adversarialIds,
2063
+ adversarialCases,
2064
+ `${fieldName}.adversarialCaseRefs`,
2065
+ ).length;
2066
+ }
2067
+ if (artifactIds) {
2068
+ requireResolvedLinks(artifactIds, artifactRefs, `${fieldName}.artifactRefs`);
2069
+ successfulProofLinks += artifactIds.length;
2070
+ }
2071
+ if (successfulProofLinks === 0) {
2072
+ throw new Error(`qualityGate ${fieldName} must link to at least one successful proof row or artifact`);
2073
+ }
2074
+ }
2075
+ if (!hasSuccessfulContractCoverage) {
2076
+ throw new Error(
2077
+ "qualityGate executorQa.contractCoverage must include at least one row with status covered, passed, or verified",
2078
+ );
2079
+ }
2080
+ return rows;
2081
+ }
2082
+
2083
+ async function validateExecutorQaRedTeamEvidenceInternal(
2084
+ cwd: string,
2085
+ executorQa: JsonObject,
2086
+ options: { mode?: "checkpoint" | "review"; changeSet?: UltragoalChangeSet } = {},
2087
+ ): Promise<void> {
2088
+ const artifactRefs = await validateArtifactRefs(cwd, executorQa);
2089
+ const surfaceEvidence = await validateSurfaceEvidence(cwd, executorQa, artifactRefs);
2090
+ const adversarialCases = validateAdversarialCases(executorQa, artifactRefs);
2091
+ const contractCoverage = validateContractCoverage(executorQa, surfaceEvidence, adversarialCases, artifactRefs);
2092
+ if (requiresComputerRedTeamSuite(executorQa, options.changeSet)) {
2093
+ await validateMandatoryComputerAdversarialCases(cwd, contractCoverage, adversarialCases, artifactRefs);
2094
+ }
2095
+ }
2096
+
2097
+ async function validateExecutorQaRedTeamEvidence(
2098
+ cwd: string,
2099
+ executorQa: JsonObject,
2100
+ options: { changeSet?: UltragoalChangeSet } = {},
2101
+ ): Promise<void> {
2102
+ await validateExecutorQaRedTeamEvidenceInternal(cwd, executorQa, {
2103
+ mode: "checkpoint",
2104
+ changeSet: options.changeSet,
2105
+ });
2106
+ }
2107
+
2108
+ export async function validateExecutorQaRedTeamEvidenceForReview(
2109
+ cwd: string,
2110
+ executorQa: Record<string, unknown>,
2111
+ options: { mode?: "review"; changeSet?: UltragoalChangeSet } = {},
2112
+ ): Promise<void> {
2113
+ await validateExecutorQaRedTeamEvidenceInternal(cwd, executorQa as JsonObject, options);
2114
+ }
2115
+
2116
+ async function validateCompletionQualityGate(
2117
+ cwd: string,
2118
+ gate: JsonObject,
2119
+ options: { changeSet?: UltragoalChangeSet } = {},
2120
+ ): Promise<void> {
2121
+ const codeReview = qualityGateObject(gate.codeReview);
2122
+ if (codeReview) {
2123
+ throw new Error(
2124
+ "checkpoint --status complete requires architect review approval through architectReview, executorQa, and iteration quality-gate evidence; legacy codeReview-only gates are not sufficient",
2125
+ );
2126
+ }
2127
+ const allowedKeys = new Set(["architectReview", "executorQa", "iteration"]);
2128
+ const unsupportedKeys = Object.keys(gate).filter(key => !allowedKeys.has(key));
2129
+ if (unsupportedKeys.length > 0) {
2130
+ throw new Error(`qualityGate contains unsupported keys: ${unsupportedKeys.join(", ")}`);
2131
+ }
2132
+ const architectReview = qualityGateObject(gate.architectReview);
2133
+ const executorQa = qualityGateObject(gate.executorQa);
2134
+ const iteration = qualityGateObject(gate.iteration);
2135
+ if (!architectReview || !executorQa || !iteration) {
2136
+ throw new Error("qualityGate requires architectReview, executorQa, and iteration objects");
2137
+ }
2138
+ if (
2139
+ architectReview.architectureStatus !== CLEAN_ARCHITECT_STATUS ||
2140
+ architectReview.productStatus !== CLEAN_ARCHITECT_STATUS ||
2141
+ architectReview.codeStatus !== CLEAN_ARCHITECT_STATUS ||
2142
+ architectReview.recommendation !== APPROVE_RECOMMENDATION
2143
+ ) {
2144
+ throw new Error(
2145
+ "checkpoint --status complete requires architect review approval: architectReview architecture/product/code must be CLEAR and recommendation must be APPROVE",
2146
+ );
2147
+ }
2148
+ if (!nonEmptyStringArray(architectReview.commands)) {
2149
+ throw new Error("qualityGate architectReview.commands must be a non-empty string array");
2150
+ }
2151
+ requireNonEmptyString(architectReview.evidence, "architectReview.evidence");
2152
+ requireEmptyBlockers(architectReview.blockers, "architectReview.blockers");
2153
+ if (
2154
+ executorQa.status !== PASSED_STATUS ||
2155
+ executorQa.e2eStatus !== PASSED_STATUS ||
2156
+ executorQa.redTeamStatus !== PASSED_STATUS
2157
+ ) {
2158
+ throw new Error("qualityGate executorQa status, e2eStatus, and redTeamStatus must be passed");
2159
+ }
2160
+ if (!nonEmptyStringArray(executorQa.e2eCommands) || !nonEmptyStringArray(executorQa.redTeamCommands)) {
2161
+ throw new Error("qualityGate executorQa e2eCommands and redTeamCommands must be non-empty string arrays");
2162
+ }
2163
+ requireNonEmptyString(executorQa.evidence, "executorQa.evidence");
2164
+ requireEmptyBlockers(executorQa.blockers, "executorQa.blockers");
2165
+ await validateExecutorQaRedTeamEvidence(cwd, executorQa, { changeSet: options.changeSet });
2166
+ if (iteration.status !== PASSED_STATUS || iteration.fullRerun !== true) {
2167
+ throw new Error("qualityGate iteration must be passed with fullRerun true");
2168
+ }
2169
+ if (!nonEmptyStringArray(iteration.rerunCommands)) {
2170
+ throw new Error("qualityGate iteration.rerunCommands must be a non-empty string array");
2171
+ }
2172
+ requireNonEmptyString(iteration.evidence, "iteration.evidence");
2173
+ requireEmptyBlockers(iteration.blockers, "iteration.blockers");
2174
+ }
2175
+
2176
+ async function readRequiredCompletionQualityGate(
2177
+ cwd: string,
2178
+ value: string | undefined,
2179
+ options: { changeSet?: UltragoalChangeSet } = {},
2180
+ ): Promise<unknown> {
2181
+ if (!value?.trim()) {
2182
+ throw new Error(
2183
+ "complete checkpoints require --quality-gate-json with architectReview, executorQa, and iteration evidence",
2184
+ );
2185
+ }
2186
+ const gate = await readStructuredValue(cwd, value);
2187
+ const gateObject = qualityGateObject(gate);
2188
+ if (!gateObject) throw new Error("qualityGate must be a JSON object");
2189
+ await validateCompletionQualityGate(cwd, gateObject, { changeSet: options.changeSet });
2190
+ return gate;
2191
+ }
2192
+
2193
+ function snapshotUpdatedAtMilliseconds(value: unknown): number | null {
2194
+ if (typeof value === "number" && Number.isFinite(value)) return value;
2195
+ if (typeof value !== "string" || value.trim().length === 0) return null;
2196
+ const trimmed = value.trim();
2197
+ if (/^\d+$/.test(trimmed)) {
2198
+ const parsed = Number.parseInt(trimmed, 10);
2199
+ return Number.isFinite(parsed) ? parsed : null;
2200
+ }
2201
+ const parsed = Date.parse(trimmed);
2202
+ return Number.isFinite(parsed) ? parsed : null;
2203
+ }
2204
+ async function readSkcGoalSnapshot(input: {
2205
+ cwd: string;
2206
+ value: string | undefined;
2207
+ plan: UltragoalPlan;
2208
+ goal?: UltragoalGoal;
2209
+ required: boolean;
2210
+ errorPrefix: string;
2211
+ allowCompletedLegacyBlocker?: boolean;
2212
+ }): Promise<unknown> {
2213
+ if (!input.value?.trim()) {
2214
+ if (!input.required) return undefined;
2215
+ throw new Error(
2216
+ `${input.errorPrefix} require --skc-goal-json from a fresh active goal({"op":"get"}) snapshot; this is the SKC goal-mode receipt, not the .skc/ultragoal/goals.json goal record`,
2217
+ );
2218
+ }
2219
+ const snapshot = await readStructuredValue(input.cwd, input.value);
2220
+ const snapshotObject = qualityGateObject(snapshot);
2221
+ const detailsObject = qualityGateObject(snapshotObject?.details);
2222
+ const goalObject = qualityGateObject(snapshotObject?.goal) ?? qualityGateObject(detailsObject?.goal);
2223
+ if (!goalObject)
2224
+ throw new Error(
2225
+ `${input.errorPrefix} require --skc-goal-json with a goal object from goal({"op":"get"}); pass the active SKC goal-mode snapshot, not the .skc/ultragoal/goals.json goal record`,
2226
+ );
2227
+ const updatedAt = snapshotUpdatedAtMilliseconds(goalObject.updatedAt);
2228
+ if (!updatedAt)
2229
+ throw new Error(
2230
+ `${input.errorPrefix} require --skc-goal-json goal.updatedAt as epoch milliseconds or an ISO timestamp from goal({"op":"get"}); pass the active SKC goal-mode snapshot, not the .skc/ultragoal/goals.json goal record`,
2231
+ );
2232
+ const nowMilliseconds = Date.now();
2233
+ if (updatedAt < nowMilliseconds - SKC_GOAL_SNAPSHOT_MAX_AGE_MILLISECONDS) {
2234
+ throw new Error(`${input.errorPrefix} require a fresh --skc-goal-json snapshot`);
2235
+ }
2236
+ if (updatedAt > nowMilliseconds + SKC_GOAL_SNAPSHOT_MAX_FUTURE_SKEW_MILLISECONDS) {
2237
+ throw new Error(`${input.errorPrefix} require --skc-goal-json goal.updatedAt that is not from the future`);
2238
+ }
2239
+ const objective = typeof goalObject.objective === "string" ? goalObject.objective : "";
2240
+ const expectedObjectives = new Set([input.plan.skcObjective, ...(input.plan.skcObjectiveAliases ?? [])]);
2241
+ if (input.plan.skcGoalMode === "per-story" && input.goal?.objective) {
2242
+ expectedObjectives.add(input.goal.objective);
2243
+ }
2244
+ if (input.allowCompletedLegacyBlocker && goalObject.status === "complete" && !expectedObjectives.has(objective)) {
2245
+ return snapshot;
2246
+ }
2247
+ if (!expectedObjectives.has(objective)) {
2248
+ throw new Error(
2249
+ `${input.errorPrefix} require --skc-goal-json objective to match the active SKC goal-mode objective from goal({"op":"get"}), not the .skc/ultragoal/goals.json goal ${input.goal?.id ?? "record"}`,
2250
+ );
2251
+ }
2252
+ if (goalObject.status !== "active") {
2253
+ throw new Error(`${input.errorPrefix} require --skc-goal-json goal.status to be active`);
2254
+ }
2255
+ return snapshot;
2256
+ }
2257
+
2258
+ export async function checkpointUltragoalGoal(input: {
2259
+ cwd: string;
2260
+ goalId: string;
2261
+ status: UltragoalGoalStatus;
2262
+ evidence: string;
2263
+ skcGoalJson?: string;
2264
+ qualityGateJson?: string;
2265
+ }): Promise<UltragoalPlan> {
2266
+ const plan = await readUltragoalPlan(input.cwd);
2267
+ if (!plan) throw new Error("No ultragoal plan found. Run `skc ultragoal create-goals --brief ...` first.");
2268
+ const goal = plan.goals.find(item => item.id === input.goalId);
2269
+ if (!goal) throw new Error(`No ultragoal goal found for ${input.goalId}.`);
2270
+ const evidence = input.evidence.trim();
2271
+ if (!evidence) throw new Error("checkpoint evidence is required");
2272
+ const ledgerBefore = await readUltragoalLedger(input.cwd);
2273
+ if (
2274
+ goal.status === input.status &&
2275
+ goal.evidence === evidence &&
2276
+ ledgerBefore.some(
2277
+ event =>
2278
+ event.event === "goal_checkpointed" &&
2279
+ event.goalId === goal.id &&
2280
+ event.status === input.status &&
2281
+ event.evidence === evidence,
2282
+ )
2283
+ ) {
2284
+ // Idempotent re-checkpoint: this goal is already recorded in the target status with the same
2285
+ // evidence, so skip the plan rewrite and ledger append to avoid duplicate goal_checkpointed
2286
+ // events. The ledger is the dedup source of truth because it is exactly what a duplicate write
2287
+ // would corrupt (mirrors the ralplan #638 guard). Requiring a matching ledger row means an
2288
+ // interrupted prior write (plan persisted, ledger append lost) still re-appends the event
2289
+ // instead of silently dropping it.
2290
+ return plan;
2291
+ }
2292
+ const changeSet = input.status === "complete" ? await computeCheckpointChangeSet(input.cwd) : undefined;
2293
+ const qualityGateJson =
2294
+ input.status === "complete"
2295
+ ? await readRequiredCompletionQualityGate(input.cwd, input.qualityGateJson, { changeSet })
2296
+ : input.qualityGateJson
2297
+ ? await readStructuredValue(input.cwd, input.qualityGateJson)
2298
+ : undefined;
2299
+ const now = new Date().toISOString();
2300
+ const beforeStatus = goal.status;
2301
+ if (input.status === "complete") {
2302
+ const blockedGoalId =
2303
+ typeof goal.steering?.kind === "string" && goal.steering.kind === "review_blocker"
2304
+ ? nonEmptyString(goal.steering.blockedGoalId)
2305
+ : null;
2306
+ const blockedGoal = blockedGoalId ? plan.goals.find(item => item.id === blockedGoalId) : undefined;
2307
+ if (blockedGoal?.status === "review_blocked") {
2308
+ blockedGoal.status = "superseded";
2309
+ blockedGoal.evidence = `Resolved by verification blocker story ${goal.id}: ${evidence}`;
2310
+ blockedGoal.updatedAt = now;
2311
+ }
2312
+ }
2313
+ const receiptKind = input.status === "complete" ? chooseReceiptKind(plan, goal, input.status) : null;
2314
+ const skcGoalJson =
2315
+ input.status === "complete"
2316
+ ? await readSkcGoalSnapshot({
2317
+ cwd: input.cwd,
2318
+ value: input.skcGoalJson,
2319
+ plan,
2320
+ goal,
2321
+ required: true,
2322
+ errorPrefix: "complete checkpoints",
2323
+ })
2324
+ : await readSkcGoalSnapshot({
2325
+ cwd: input.cwd,
2326
+ value: input.skcGoalJson,
2327
+ plan,
2328
+ goal,
2329
+ required: false,
2330
+ errorPrefix: `${input.status} checkpoints`,
2331
+ allowCompletedLegacyBlocker: input.status === "blocked",
2332
+ });
2333
+ const pendingCheckpointEventId = crypto.randomUUID();
2334
+ if (input.status === "complete" && receiptKind && qualityGateJson && !Array.isArray(qualityGateJson)) {
2335
+ goal.completionVerification = buildCompletionReceipt({
2336
+ plan,
2337
+ ledger: ledgerBefore,
2338
+ goal,
2339
+ receiptKind,
2340
+ beforeStatus,
2341
+ qualityGateJson: qualityGateJson as JsonObject,
2342
+ skcGoalJson: skcGoalJson as JsonObject,
2343
+ now,
2344
+ checkpointLedgerEventId: pendingCheckpointEventId,
2345
+ });
2346
+ }
2347
+ goal.status = input.status;
2348
+ goal.evidence = evidence;
2349
+ goal.updatedAt = now;
2350
+ if (input.status === "complete") goal.completedAt = now;
2351
+ plan.updatedAt = now;
2352
+ await writePlan(input.cwd, plan);
2353
+ await appendLedger(input.cwd, {
2354
+ eventId: pendingCheckpointEventId,
2355
+ event: "goal_checkpointed",
2356
+ goalId: goal.id,
2357
+ status: input.status,
2358
+ evidence,
2359
+ skcGoalJson,
2360
+ qualityGateJson,
2361
+ completionVerification: goal.completionVerification,
2362
+ });
2363
+ return plan;
2364
+ }
2365
+ export interface UltragoalCheckpointContinuation {
2366
+ plan: UltragoalPlan;
2367
+ checkpointedGoal: UltragoalGoal;
2368
+ nextGoal?: UltragoalGoal;
2369
+ startedNext: boolean;
2370
+ allComplete: boolean;
2371
+ incompleteGoals: UltragoalGoal[];
2372
+ }
2373
+
2374
+ export async function checkpointAndContinueUltragoalGoal(input: {
2375
+ cwd: string;
2376
+ goalId: string;
2377
+ status: UltragoalGoalStatus;
2378
+ evidence: string;
2379
+ skcGoalJson?: string;
2380
+ qualityGateJson?: string;
2381
+ advanceNext?: boolean;
2382
+ retryFailed?: boolean;
2383
+ }): Promise<UltragoalCheckpointContinuation> {
2384
+ let plan = await checkpointUltragoalGoal(input);
2385
+ const checkpointedGoal = plan.goals.find(goal => goal.id === input.goalId);
2386
+ if (!checkpointedGoal) throw new Error(`No ultragoal goal found for ${input.goalId}.`);
2387
+ if (input.status === "complete" && input.advanceNext === true) {
2388
+ const beforeAdvance = getUltragoalRunCompletionState(plan, { retryFailed: input.retryFailed });
2389
+ if (beforeAdvance.nextGoal && beforeAdvance.nextGoal.status !== "active") {
2390
+ const started = await startNextUltragoalGoal({ cwd: input.cwd, retryFailed: input.retryFailed });
2391
+ plan = started.plan;
2392
+ const afterAdvance = getUltragoalRunCompletionState(plan, { retryFailed: input.retryFailed });
2393
+ return {
2394
+ plan,
2395
+ checkpointedGoal,
2396
+ nextGoal: started.goal,
2397
+ startedNext: Boolean(started.goal),
2398
+ allComplete: afterAdvance.allComplete,
2399
+ incompleteGoals: afterAdvance.incompleteGoals,
2400
+ };
2401
+ }
2402
+ }
2403
+ const state = getUltragoalRunCompletionState(plan, { retryFailed: input.retryFailed });
2404
+ return {
2405
+ plan,
2406
+ checkpointedGoal,
2407
+ nextGoal: state.nextGoal,
2408
+ startedNext: false,
2409
+ allComplete: state.allComplete,
2410
+ incompleteGoals: state.incompleteGoals,
2411
+ };
2412
+ }
2413
+
2414
+ function nextUltragoalGoalId(plan: UltragoalPlan, offset = 1): string {
2415
+ return `G${String(plan.goals.length + offset).padStart(3, "0")}`;
2416
+ }
2417
+
2418
+ function requireSteeringText(value: string, label: string, kind: UltragoalSteeringKind): string {
2419
+ const trimmed = value.trim();
2420
+ if (!trimmed) throw new Error(`steer --${label} is required for ${kind}`);
2421
+ return trimmed;
2422
+ }
2423
+
2424
+ function requireSteeringEvidence(input: { kind: UltragoalSteeringKind; evidence: string; rationale: string }): {
2425
+ evidence: string;
2426
+ rationale: string;
2427
+ } {
2428
+ return {
2429
+ evidence: requireSteeringText(input.evidence, "evidence", input.kind),
2430
+ rationale: requireSteeringText(input.rationale, "rationale", input.kind),
2431
+ };
2432
+ }
2433
+
2434
+ function findGoalOrThrow(plan: UltragoalPlan, goalId: string, kind: UltragoalSteeringKind): UltragoalGoal {
2435
+ const id = goalId.trim();
2436
+ if (!id) throw new Error(`steer --goal-id is required for ${kind}`);
2437
+ const goal = plan.goals.find(item => item.id === id);
2438
+ if (!goal) throw new Error(`No ultragoal goal found for ${id}.`);
2439
+ return goal;
2440
+ }
2441
+
2442
+ function requireGoalStatus(
2443
+ goal: UltragoalGoal,
2444
+ allowed: readonly UltragoalGoalStatus[],
2445
+ kind: UltragoalSteeringKind,
2446
+ ): void {
2447
+ if (!allowed.includes(goal.status)) {
2448
+ throw new Error(`steer ${kind} requires goal ${goal.id} status ${allowed.join(" or ")}; found ${goal.status}`);
2449
+ }
2450
+ }
2451
+
2452
+ function parseJsonFlag(value: string, label: string, kind: UltragoalSteeringKind): unknown {
2453
+ const trimmed = requireSteeringText(value, label, kind);
2454
+ try {
2455
+ return JSON.parse(trimmed) as unknown;
2456
+ } catch (error) {
2457
+ const message = error instanceof Error ? error.message : String(error);
2458
+ throw new Error(`steer --${label} must be valid JSON for ${kind}: ${message}`);
2459
+ }
2460
+ }
2461
+
2462
+ function parseReplacementSpecs(value: string, kind: UltragoalSteeringKind): ReplacementSpec[] {
2463
+ const raw = parseJsonFlag(value, "replacements-json", kind);
2464
+ if (!Array.isArray(raw) || raw.length < 2) {
2465
+ throw new Error("steer --replacements-json must be an array with at least two replacements");
2466
+ }
2467
+ const seen = new Set<string>();
2468
+ return raw.map((item, index) => {
2469
+ if (typeof item !== "object" || item === null || Array.isArray(item)) {
2470
+ throw new Error(`steer --replacements-json[${index}] must be an object`);
2471
+ }
2472
+ const record = item as Record<string, unknown>;
2473
+ const title = typeof record.title === "string" ? record.title.trim() : "";
2474
+ const objective = typeof record.objective === "string" ? record.objective.trim() : "";
2475
+ if (!title || !objective) {
2476
+ throw new Error(`steer --replacements-json[${index}] requires non-empty title and objective`);
2477
+ }
2478
+ const key = `${title}\u0000${objective}`;
2479
+ if (seen.has(key)) throw new Error(`steer --replacements-json[${index}] duplicates an earlier replacement`);
2480
+ seen.add(key);
2481
+ return { title, objective };
2482
+ });
2483
+ }
2484
+
2485
+ function parsePendingOrder(value: string, kind: UltragoalSteeringKind): string[] {
2486
+ const raw = parseJsonFlag(value, "order-json", kind);
2487
+ if (!Array.isArray(raw) || raw.length === 0) {
2488
+ throw new Error("steer --order-json must be a non-empty array of goal ids");
2489
+ }
2490
+ const seen = new Set<string>();
2491
+ return raw.map((item, index) => {
2492
+ if (typeof item !== "string" || item.trim().length === 0) {
2493
+ throw new Error(`steer --order-json[${index}] must be a non-empty goal id string`);
2494
+ }
2495
+ const id = item.trim();
2496
+ if (seen.has(id)) throw new Error(`steer --order-json contains duplicate goal id ${id}`);
2497
+ seen.add(id);
2498
+ return id;
2499
+ });
2500
+ }
2501
+
2502
+ async function appendSteeringRejected(input: {
2503
+ cwd: string;
2504
+ kind: UltragoalSteeringKind;
2505
+ reason: string;
2506
+ goalId?: string;
2507
+ evidence?: string;
2508
+ rationale?: string;
2509
+ payload?: JsonObject;
2510
+ }): Promise<void> {
2511
+ await appendLedger(input.cwd, {
2512
+ event: "steering_rejected",
2513
+ kind: input.kind,
2514
+ goalId: input.goalId?.trim() || undefined,
2515
+ reason: input.reason,
2516
+ evidence: input.evidence?.trim() || undefined,
2517
+ rationale: input.rationale?.trim() || undefined,
2518
+ payload: input.payload,
2519
+ });
2520
+ }
2521
+
2522
+ function steeringPayloadSummary(args: readonly string[]): JsonObject {
2523
+ return {
2524
+ goalId: flagValue(args, "--goal-id"),
2525
+ title: flagValue(args, "--title"),
2526
+ objective: flagValue(args, "--objective"),
2527
+ replacementsJson: flagValue(args, "--replacements-json"),
2528
+ orderJson: flagValue(args, "--order-json"),
2529
+ };
2530
+ }
2531
+
2532
+ function parseNativeSteeringKind(value: string | undefined): UltragoalSteeringKind {
2533
+ if (typeof value === "string" && NATIVE_STEERING_KIND_SET.has(value)) return value as UltragoalSteeringKind;
2534
+ throw new Error(`native steering currently supports --kind ${NATIVE_STEERING_KINDS.join(", ")}`);
2535
+ }
2536
+
2537
+ async function addUltragoalSubgoalToPlan(input: {
2538
+ cwd: string;
2539
+ plan: UltragoalPlan;
2540
+ title: string;
2541
+ objective: string;
2542
+ evidence: string;
2543
+ rationale: string;
2544
+ }): Promise<{ plan: UltragoalPlan; goalId: string }> {
2545
+ const kind = "add_subgoal";
2546
+ const title = requireSteeringText(input.title, "title", kind);
2547
+ const objective = requireSteeringText(input.objective, "objective", kind);
2548
+ const { evidence, rationale } = requireSteeringEvidence({
2549
+ kind,
2550
+ evidence: input.evidence,
2551
+ rationale: input.rationale,
2552
+ });
2553
+ const now = new Date().toISOString();
2554
+ const nextId = nextUltragoalGoalId(input.plan);
2555
+ input.plan.goals.push({
2556
+ id: nextId,
2557
+ title,
2558
+ objective,
2559
+ status: "pending",
2560
+ createdAt: now,
2561
+ updatedAt: now,
2562
+ steering: { kind, evidence, rationale },
2563
+ });
2564
+ input.plan.updatedAt = now;
2565
+ await writePlan(input.cwd, input.plan);
2566
+ await appendLedger(input.cwd, {
2567
+ event: "steering_accepted",
2568
+ kind,
2569
+ goalId: nextId,
2570
+ evidence,
2571
+ rationale,
2572
+ });
2573
+ return { plan: input.plan, goalId: nextId };
2574
+ }
2575
+
2576
+ export async function addUltragoalSubgoal(input: {
2577
+ cwd: string;
2578
+ title: string;
2579
+ objective: string;
2580
+ evidence: string;
2581
+ rationale: string;
2582
+ }): Promise<UltragoalPlan> {
2583
+ const plan = await readUltragoalPlan(input.cwd);
2584
+ if (!plan) throw new Error("No ultragoal plan found. Run `skc ultragoal create-goals --brief ...` first.");
2585
+ return (await addUltragoalSubgoalToPlan({ ...input, plan })).plan;
2586
+ }
2587
+
2588
+ async function splitUltragoalSubgoal(input: {
2589
+ cwd: string;
2590
+ plan: UltragoalPlan;
2591
+ goalId: string;
2592
+ replacementsJson: string;
2593
+ evidence: string;
2594
+ rationale: string;
2595
+ }): Promise<{ plan: UltragoalPlan; goalId: string; replacementGoalIds: string[] }> {
2596
+ const kind = "split_subgoal";
2597
+ const { evidence, rationale } = requireSteeringEvidence({
2598
+ kind,
2599
+ evidence: input.evidence,
2600
+ rationale: input.rationale,
2601
+ });
2602
+ const target = findGoalOrThrow(input.plan, input.goalId, kind);
2603
+ requireGoalStatus(target, ["pending"], kind);
2604
+ const replacements = parseReplacementSpecs(input.replacementsJson, kind);
2605
+ const now = new Date().toISOString();
2606
+ const replacementGoalIds = replacements.map((_, index) => nextUltragoalGoalId(input.plan, index + 1));
2607
+ target.status = "superseded";
2608
+ target.evidence = evidence;
2609
+ target.updatedAt = now;
2610
+ target.steering = { kind, evidence, rationale, replacementGoalIds };
2611
+ const replacementGoals = replacements.map(
2612
+ (replacement, index): UltragoalGoal => ({
2613
+ id: replacementGoalIds[index]!,
2614
+ title: replacement.title,
2615
+ objective: replacement.objective,
2616
+ status: "pending",
2617
+ createdAt: now,
2618
+ updatedAt: now,
2619
+ steering: { kind: "split_replacement", sourceGoalId: target.id, evidence, rationale },
2620
+ }),
2621
+ );
2622
+ const targetIndex = input.plan.goals.findIndex(goal => goal.id === target.id);
2623
+ input.plan.goals.splice(targetIndex + 1, 0, ...replacementGoals);
2624
+ input.plan.updatedAt = now;
2625
+ await writePlan(input.cwd, input.plan);
2626
+ await appendLedger(input.cwd, {
2627
+ event: "steering_accepted",
2628
+ kind,
2629
+ goalId: target.id,
2630
+ replacementGoalIds,
2631
+ evidence,
2632
+ rationale,
2633
+ });
2634
+ return { plan: input.plan, goalId: target.id, replacementGoalIds };
2635
+ }
2636
+
2637
+ async function reorderPendingUltragoalGoals(input: {
2638
+ cwd: string;
2639
+ plan: UltragoalPlan;
2640
+ orderJson: string;
2641
+ evidence: string;
2642
+ rationale: string;
2643
+ }): Promise<{ plan: UltragoalPlan; pendingGoalIds: string[] }> {
2644
+ const kind = "reorder_pending";
2645
+ const { evidence, rationale } = requireSteeringEvidence({
2646
+ kind,
2647
+ evidence: input.evidence,
2648
+ rationale: input.rationale,
2649
+ });
2650
+ const pendingGoalIds = input.plan.goals.filter(goal => goal.status === "pending").map(goal => goal.id);
2651
+ const requestedOrder = parsePendingOrder(input.orderJson, kind);
2652
+ const pendingSet = new Set(pendingGoalIds);
2653
+ for (const id of requestedOrder) {
2654
+ const goal = input.plan.goals.find(item => item.id === id);
2655
+ if (!goal) throw new Error(`steer --order-json references unknown goal id ${id}`);
2656
+ if (goal.status !== "pending") throw new Error(`steer --order-json references non-pending goal id ${id}`);
2657
+ }
2658
+ const missing = pendingGoalIds.filter(id => !requestedOrder.includes(id));
2659
+ if (missing.length > 0) throw new Error(`steer --order-json missing pending goal id(s): ${missing.join(", ")}`);
2660
+ if (requestedOrder.length !== pendingSet.size)
2661
+ throw new Error("steer --order-json must include every pending goal exactly once");
2662
+ const pendingById = new Map(input.plan.goals.map(goal => [goal.id, goal]));
2663
+ const remaining = [...requestedOrder];
2664
+ input.plan.goals = input.plan.goals.map(goal =>
2665
+ goal.status === "pending" ? pendingById.get(remaining.shift()!)! : goal,
2666
+ );
2667
+ input.plan.updatedAt = new Date().toISOString();
2668
+ await writePlan(input.cwd, input.plan);
2669
+ await appendLedger(input.cwd, {
2670
+ event: "steering_accepted",
2671
+ kind,
2672
+ previousPendingGoalIds: pendingGoalIds,
2673
+ pendingGoalIds: requestedOrder,
2674
+ evidence,
2675
+ rationale,
2676
+ });
2677
+ return { plan: input.plan, pendingGoalIds: requestedOrder };
2678
+ }
2679
+
2680
+ async function revisePendingUltragoalWording(input: {
2681
+ cwd: string;
2682
+ plan: UltragoalPlan;
2683
+ goalId: string;
2684
+ title?: string;
2685
+ objective?: string;
2686
+ evidence: string;
2687
+ rationale: string;
2688
+ }): Promise<{ plan: UltragoalPlan; goalId: string; changedFields: string[] }> {
2689
+ const kind = "revise_pending_wording";
2690
+ const { evidence, rationale } = requireSteeringEvidence({
2691
+ kind,
2692
+ evidence: input.evidence,
2693
+ rationale: input.rationale,
2694
+ });
2695
+ const goal = findGoalOrThrow(input.plan, input.goalId, kind);
2696
+ requireGoalStatus(goal, ["pending"], kind);
2697
+ const title = input.title === undefined ? undefined : input.title.trim();
2698
+ const objective = input.objective === undefined ? undefined : input.objective.trim();
2699
+ if (input.title !== undefined && !title)
2700
+ throw new Error("steer --title must be non-empty for revise_pending_wording");
2701
+ if (input.objective !== undefined && !objective)
2702
+ throw new Error("steer --objective must be non-empty for revise_pending_wording");
2703
+ if (!title && !objective) throw new Error("revise_pending_wording requires --title and/or --objective");
2704
+ const changedFields: string[] = [];
2705
+ if (title !== undefined) {
2706
+ goal.title = title;
2707
+ changedFields.push("title");
2708
+ }
2709
+ if (objective !== undefined) {
2710
+ goal.objective = objective;
2711
+ changedFields.push("objective");
2712
+ }
2713
+ const now = new Date().toISOString();
2714
+ goal.updatedAt = now;
2715
+ goal.steering = { kind, evidence, rationale, changedFields };
2716
+ input.plan.updatedAt = now;
2717
+ await writePlan(input.cwd, input.plan);
2718
+ await appendLedger(input.cwd, {
2719
+ event: "steering_accepted",
2720
+ kind,
2721
+ goalId: goal.id,
2722
+ changedFields,
2723
+ evidence,
2724
+ rationale,
2725
+ });
2726
+ return { plan: input.plan, goalId: goal.id, changedFields };
2727
+ }
2728
+
2729
+ async function annotateUltragoalLedger(input: {
2730
+ cwd: string;
2731
+ plan: UltragoalPlan;
2732
+ evidence: string;
2733
+ rationale: string;
2734
+ }): Promise<{ plan: UltragoalPlan }> {
2735
+ const kind = "annotate_ledger";
2736
+ const { evidence, rationale } = requireSteeringEvidence({
2737
+ kind,
2738
+ evidence: input.evidence,
2739
+ rationale: input.rationale,
2740
+ });
2741
+ await appendLedger(input.cwd, { event: "steering_accepted", kind, evidence, rationale });
2742
+ return { plan: input.plan };
2743
+ }
2744
+
2745
+ async function markBlockedUltragoalSuperseded(input: {
2746
+ cwd: string;
2747
+ plan: UltragoalPlan;
2748
+ goalId: string;
2749
+ evidence: string;
2750
+ rationale: string;
2751
+ }): Promise<{ plan: UltragoalPlan; goalId: string }> {
2752
+ const kind = "mark_blocked_superseded";
2753
+ const { evidence, rationale } = requireSteeringEvidence({
2754
+ kind,
2755
+ evidence: input.evidence,
2756
+ rationale: input.rationale,
2757
+ });
2758
+ const goal = findGoalOrThrow(input.plan, input.goalId, kind);
2759
+ requireGoalStatus(goal, ["blocked", "review_blocked"], kind);
2760
+ const remainingRequiredGoals = requiredUltragoalGoals(input.plan).filter(item => item.id !== goal.id);
2761
+ if (remainingRequiredGoals.length === 0) {
2762
+ throw new Error(`steer ${kind} cannot supersede ${goal.id} because it is the only remaining required goal`);
2763
+ }
2764
+ const now = new Date().toISOString();
2765
+ goal.status = "superseded";
2766
+ goal.evidence = evidence;
2767
+ goal.updatedAt = now;
2768
+ goal.steering = { kind, evidence, rationale, noReplacementRequired: true };
2769
+ input.plan.updatedAt = now;
2770
+ await writePlan(input.cwd, input.plan);
2771
+ await appendLedger(input.cwd, {
2772
+ event: "steering_accepted",
2773
+ kind,
2774
+ goalId: goal.id,
2775
+ noReplacementRequired: true,
2776
+ evidence,
2777
+ rationale,
2778
+ });
2779
+ return { plan: input.plan, goalId: goal.id };
2780
+ }
2781
+
2782
+ export async function recordUltragoalReviewBlockers(input: {
2783
+ cwd: string;
2784
+ goalId: string;
2785
+ title: string;
2786
+ objective: string;
2787
+ evidence: string;
2788
+ skcGoalJson?: string;
2789
+ }): Promise<UltragoalPlan> {
2790
+ const objective = input.objective.trim();
2791
+ if (!objective) throw new Error("record-review-blockers --objective is required");
2792
+ if (!input.skcGoalJson?.trim()) {
2793
+ throw new Error('record-review-blockers require --skc-goal-json from a fresh active goal({"op":"get"}) snapshot');
2794
+ }
2795
+ const plan = await checkpointUltragoalGoal({
2796
+ cwd: input.cwd,
2797
+ goalId: input.goalId,
2798
+ status: "review_blocked",
2799
+ evidence: input.evidence,
2800
+ skcGoalJson: input.skcGoalJson,
2801
+ });
2802
+ const now = new Date().toISOString();
2803
+ const nextId = `G${String(plan.goals.length + 1).padStart(3, "0")}`;
2804
+ plan.goals.push({
2805
+ id: nextId,
2806
+ title: input.title.trim() || "Resolve final code-review blockers",
2807
+ objective,
2808
+ status: "pending",
2809
+ createdAt: now,
2810
+ updatedAt: now,
2811
+ steering: { kind: "review_blocker", blockedGoalId: input.goalId },
2812
+ });
2813
+ plan.updatedAt = now;
2814
+ await writePlan(input.cwd, plan);
2815
+ await appendLedger(input.cwd, { event: "review_blockers_recorded", goalId: input.goalId, blockerGoalId: nextId });
2816
+ return plan;
2817
+ }
2818
+
2819
+ type UltragoalReviewMode = "review-only" | "review-start";
2820
+ type UltragoalReviewContractStrength = "strong" | "thin-derived";
2821
+
2822
+ interface UltragoalReviewFinding extends JsonObject {
2823
+ severity: "blocker";
2824
+ message: string;
2825
+ }
2826
+
2827
+ interface UltragoalReviewResult extends JsonObject {
2828
+ verdict: "pass" | "fail" | "inconclusive: weak-contract";
2829
+ contractStrength: UltragoalReviewContractStrength;
2830
+ cleanPassEligible: boolean;
2831
+ source: JsonObject;
2832
+ findings: UltragoalReviewFinding[];
2833
+ artifactValidationSummary: JsonObject;
2834
+ weakContractCapApplied: boolean;
2835
+ blockerGoalIds?: string[];
2836
+ }
2837
+
2838
+ function parseReviewMode(value: string | undefined): UltragoalReviewMode {
2839
+ if (value === undefined || value === "review-only") return "review-only";
2840
+ if (value === "review-start") return "review-start";
2841
+ throw new Error("review --mode must be review-only or review-start");
2842
+ }
2843
+
2844
+ async function readOptionalExecutorQa(cwd: string, value: string | undefined): Promise<JsonObject> {
2845
+ if (!value) {
2846
+ return {
2847
+ status: "passed",
2848
+ e2eStatus: "passed",
2849
+ redTeamStatus: "passed",
2850
+ evidence: "review evidence bundle was not supplied; runtime reports this as a finding",
2851
+ e2eCommands: ["skc ultragoal review"],
2852
+ redTeamCommands: ["skc ultragoal review"],
2853
+ artifactRefs: [],
2854
+ contractCoverage: [],
2855
+ surfaceEvidence: [],
2856
+ adversarialCases: [],
2857
+ blockers: [],
2858
+ };
2859
+ }
2860
+ const structured = await readStructuredValue(cwd, value);
2861
+ if (typeof structured !== "object" || structured === null || Array.isArray(structured)) {
2862
+ throw new Error("review --executor-qa-json must resolve to an executorQa object");
2863
+ }
2864
+ return structured as JsonObject;
2865
+ }
2866
+
2867
+ async function spawnText(
2868
+ command: string[],
2869
+ options: { cwd: string; timeoutMs?: number },
2870
+ ): Promise<{ ok: boolean; stdout: string; stderr: string }> {
2871
+ try {
2872
+ const proc = Bun.spawn(command, { cwd: options.cwd, stdout: "pipe", stderr: "pipe" });
2873
+ const timeout = setTimeout(() => proc.kill(), options.timeoutMs ?? 5000);
2874
+ const [stdout, stderr, exitCode] = await Promise.all([
2875
+ new Response(proc.stdout).text(),
2876
+ new Response(proc.stderr).text(),
2877
+ proc.exited,
2878
+ ]);
2879
+ clearTimeout(timeout);
2880
+ return { ok: exitCode === 0, stdout, stderr };
2881
+ } catch (error) {
2882
+ return { ok: false, stdout: "", stderr: error instanceof Error ? error.message : String(error) };
2883
+ }
2884
+ }
2885
+
2886
+ async function resolveGitBase(cwd: string, branch?: string): Promise<string> {
2887
+ const candidates = branch ? [branch] : ["origin/main", "origin/master", "main", "master"];
2888
+ for (const candidate of candidates) {
2889
+ const exists = await spawnText(["git", "rev-parse", "--verify", candidate], { cwd, timeoutMs: 3000 });
2890
+ if (exists.ok) return candidate;
2891
+ }
2892
+ const mergeBase = await spawnText(["git", "merge-base", "HEAD", "origin/main"], { cwd, timeoutMs: 3000 });
2893
+ if (mergeBase.ok && mergeBase.stdout.trim()) return mergeBase.stdout.trim();
2894
+ return "HEAD~1";
2895
+ }
2896
+
2897
+ function parseGitNameStatus(output: string): UltragoalChangeSetPath[] {
2898
+ const rows: UltragoalChangeSetPath[] = [];
2899
+ for (const line of output.split("\n")) {
2900
+ const trimmed = line.trim();
2901
+ if (!trimmed) continue;
2902
+ const parts = trimmed.split(/\s+/);
2903
+ const statusCode = parts[0] ?? "";
2904
+ let status: UltragoalChangeStatus = "unknown";
2905
+ if (statusCode.startsWith("A")) status = "added";
2906
+ else if (statusCode.startsWith("M")) status = "modified";
2907
+ else if (statusCode.startsWith("D")) status = "deleted";
2908
+ else if (statusCode.startsWith("R")) status = "renamed";
2909
+ else if (statusCode.startsWith("C")) status = "copied";
2910
+ const pathValue = status === "renamed" || status === "copied" ? parts[2] : parts[1];
2911
+ if (!pathValue) continue;
2912
+ const oldPath = status === "renamed" || status === "copied" ? parts[1] : undefined;
2913
+ rows.push({
2914
+ path: normalizeRepoPath(pathValue),
2915
+ oldPath: oldPath ? normalizeRepoPath(oldPath) : undefined,
2916
+ status,
2917
+ category: categorizeComputerChangePath(pathValue),
2918
+ });
2919
+ }
2920
+ return rows;
2921
+ }
2922
+
2923
+ function mergeChangeSetPaths(groups: UltragoalChangeSetPath[][]): UltragoalChangeSetPath[] {
2924
+ const byKey = new Map<string, UltragoalChangeSetPath>();
2925
+ for (const row of groups.flat()) byKey.set(`${row.oldPath ?? ""}\u0000${row.path}`, row);
2926
+ return [...byKey.values()];
2927
+ }
2928
+
2929
+ async function computeCheckpointChangeSet(cwd: string): Promise<UltragoalChangeSet | undefined> {
2930
+ const inGit = await spawnText(["git", "rev-parse", "--is-inside-work-tree"], { cwd, timeoutMs: 3000 });
2931
+ if (!inGit.ok || inGit.stdout.trim() !== "true") return undefined;
2932
+ if (!(await Bun.file(path.join(cwd, ".git")).exists())) return undefined;
2933
+ const baseRef = await resolveGitBase(cwd);
2934
+ const base = baseRef;
2935
+ const mergeBase = await spawnText(["git", "merge-base", "HEAD", baseRef], { cwd, timeoutMs: 3000 });
2936
+ const [committed, unstaged, staged, stat] = await Promise.all([
2937
+ spawnText(["git", "diff", "--name-status", `${base}...HEAD`], { cwd, timeoutMs: 5000 }),
2938
+ spawnText(["git", "diff", "--name-status"], { cwd, timeoutMs: 5000 }),
2939
+ spawnText(["git", "diff", "--cached", "--name-status"], { cwd, timeoutMs: 5000 }),
2940
+ spawnText(["git", "diff", "--stat", `${base}...HEAD`], { cwd, timeoutMs: 5000 }),
2941
+ ]);
2942
+ if (!committed.ok && !unstaged.ok && !staged.ok) return undefined;
2943
+ return {
2944
+ source: "checkpoint-git",
2945
+ baseRef,
2946
+ mergeBase: mergeBase.ok && mergeBase.stdout.trim() ? mergeBase.stdout.trim() : undefined,
2947
+ headRef: "HEAD",
2948
+ paths: mergeChangeSetPaths([
2949
+ parseGitNameStatus(committed.stdout),
2950
+ parseGitNameStatus(unstaged.stdout),
2951
+ parseGitNameStatus(staged.stdout),
2952
+ ]),
2953
+ rawDiffStat: stat.stdout,
2954
+ trusted: true,
2955
+ };
2956
+ }
2957
+
2958
+ function parseUnifiedDiffPaths(diff: string): UltragoalChangeSetPath[] {
2959
+ const paths: UltragoalChangeSetPath[] = [];
2960
+ for (const line of diff.split("\n")) {
2961
+ if (!line.startsWith("diff --git ")) continue;
2962
+ const match = /^diff --git a\/(.+?) b\/(.+)$/.exec(line);
2963
+ if (!match) continue;
2964
+ const oldPath = normalizeRepoPath(match[1]!);
2965
+ const newPath = normalizeRepoPath(match[2]!);
2966
+ paths.push({
2967
+ path: newPath,
2968
+ oldPath: oldPath === newPath ? undefined : oldPath,
2969
+ status: oldPath === newPath ? "modified" : "renamed",
2970
+ category: categorizeComputerChangePath(newPath),
2971
+ });
2972
+ }
2973
+ return paths;
2974
+ }
2975
+
2976
+ function changeSetFromReviewSource(source: JsonObject): UltragoalChangeSet | undefined {
2977
+ const kind = nonEmptyString(source.kind);
2978
+ if (kind === "spec") return { source: "review-spec", paths: [], trusted: true };
2979
+ if (kind === "pr" && typeof source.diff === "string")
2980
+ return {
2981
+ source: "review-pr",
2982
+ paths: parseUnifiedDiffPaths(source.diff),
2983
+ rawDiffStat: source.diff,
2984
+ trusted: true,
2985
+ };
2986
+ const local = qualityGateObject(source.local);
2987
+ if (kind === "pr" && local) return changeSetFromReviewSource(local);
2988
+ if (kind === "worktree")
2989
+ return {
2990
+ source: "review-worktree",
2991
+ paths: parseGitNameStatus(String(source.nameStatus ?? source.status ?? "")),
2992
+ rawDiffStat: String(source.diffStat ?? ""),
2993
+ trusted: true,
2994
+ };
2995
+ if (kind === "branch" || kind === "pr-fallback")
2996
+ return {
2997
+ source: "review-branch",
2998
+ baseRef: nonEmptyString(source.base) ?? undefined,
2999
+ headRef: "HEAD",
3000
+ paths: parseGitNameStatus(String(source.nameStatus ?? "")),
3001
+ rawDiffStat: String(source.diffStat ?? ""),
3002
+ trusted: true,
3003
+ };
3004
+ return undefined;
3005
+ }
3006
+
3007
+ async function localDiffSource(cwd: string, sourceKind: string, branch?: string): Promise<JsonObject> {
3008
+ if (sourceKind === "worktree") {
3009
+ const [status, diff, unstaged, staged] = await Promise.all([
3010
+ spawnText(["git", "status", "--short"], { cwd, timeoutMs: 5000 }),
3011
+ spawnText(["git", "diff", "--stat"], { cwd, timeoutMs: 5000 }),
3012
+ spawnText(["git", "diff", "--name-status"], { cwd, timeoutMs: 5000 }),
3013
+ spawnText(["git", "diff", "--cached", "--name-status"], { cwd, timeoutMs: 5000 }),
3014
+ ]);
3015
+ return {
3016
+ kind: "worktree",
3017
+ status: status.stdout,
3018
+ diffStat: diff.stdout,
3019
+ nameStatus: `${unstaged.stdout}\n${staged.stdout}`,
3020
+ };
3021
+ }
3022
+ const base = await resolveGitBase(cwd, branch);
3023
+ const [diff, nameStatus] = await Promise.all([
3024
+ spawnText(["git", "diff", "--stat", `${base}...HEAD`], { cwd, timeoutMs: 5000 }),
3025
+ spawnText(["git", "diff", "--name-status", `${base}...HEAD`], { cwd, timeoutMs: 5000 }),
3026
+ ]);
3027
+ return { kind: sourceKind, base, branch, diffStat: diff.stdout, nameStatus: nameStatus.stdout };
3028
+ }
3029
+
3030
+ async function resolveReviewSource(
3031
+ cwd: string,
3032
+ args: readonly string[],
3033
+ specPath: string | undefined,
3034
+ ): Promise<{ contractStrength: UltragoalReviewContractStrength; source: JsonObject }> {
3035
+ if (specPath) {
3036
+ const absolute = path.resolve(cwd, specPath);
3037
+ return {
3038
+ contractStrength: "strong",
3039
+ source: { kind: "spec", path: specPath, contract: await Bun.file(absolute).text() },
3040
+ };
3041
+ }
3042
+ const pr = flagValue(args, "--pr");
3043
+ if (pr) {
3044
+ const [view, diff] = await Promise.all([
3045
+ spawnText(["gh", "pr", "view", pr, "--json", "title,body,baseRefName"], { cwd, timeoutMs: 5000 }),
3046
+ spawnText(["gh", "pr", "diff", pr], { cwd, timeoutMs: 5000 }),
3047
+ ]);
3048
+ if (view.ok && diff.ok)
3049
+ return {
3050
+ contractStrength: "thin-derived",
3051
+ source: { kind: "pr", pr, prSource: "gh", metadata: view.stdout, diff: diff.stdout },
3052
+ };
3053
+ return {
3054
+ contractStrength: "thin-derived",
3055
+ source: {
3056
+ kind: "pr",
3057
+ pr,
3058
+ prSource: "gh-unavailable",
3059
+ ghError: `${view.stderr}${diff.stderr}`.trim(),
3060
+ local: await localDiffSource(cwd, "pr-fallback"),
3061
+ },
3062
+ };
3063
+ }
3064
+ const branch = flagValue(args, "--branch");
3065
+ if (branch) return { contractStrength: "thin-derived", source: await localDiffSource(cwd, "branch", branch) };
3066
+ return { contractStrength: "thin-derived", source: await localDiffSource(cwd, "worktree") };
3067
+ }
3068
+
3069
+ function findingFromError(error: unknown): UltragoalReviewFinding {
3070
+ return { severity: "blocker", message: error instanceof Error ? error.message : String(error) };
3071
+ }
3072
+
3073
+ function executorQaBlockers(executorQa: JsonObject): UltragoalReviewFinding[] {
3074
+ const blockers = nonEmptyStringArray(executorQa.blockers);
3075
+ return (blockers ?? []).map(message => ({ severity: "blocker", message: `executorQa.blockers: ${message}` }));
3076
+ }
3077
+
3078
+ const RESOLVED_REVIEW_BLOCKER_STATUSES = new Set<UltragoalGoalStatus>(["complete", "superseded"]);
3079
+
3080
+ function findOpenReviewBlockerGoal(plan: UltragoalPlan, message: string): UltragoalGoal | undefined {
3081
+ const objective = message.trim();
3082
+ return plan.goals.find(
3083
+ goal =>
3084
+ goal.steering?.kind === "review_blocker" &&
3085
+ goal.objective.trim() === objective &&
3086
+ !RESOLVED_REVIEW_BLOCKER_STATUSES.has(goal.status),
3087
+ );
3088
+ }
3089
+
3090
+ async function recordReviewFindingGoals(cwd: string, findings: readonly UltragoalReviewFinding[]): Promise<string[]> {
3091
+ let plan = await readUltragoalPlan(cwd);
3092
+ const now = new Date().toISOString();
3093
+ if (!plan) {
3094
+ plan = {
3095
+ version: 1,
3096
+ skcObjective: DEFAULT_ULTRAGOAL_OBJECTIVE,
3097
+ brief: "Ultragoal review-start findings",
3098
+ skcGoalMode: "aggregate",
3099
+ createdAt: now,
3100
+ updatedAt: now,
3101
+ goals: [],
3102
+ };
3103
+ }
3104
+ const blockerGoalIds: string[] = [];
3105
+ const createdGoalIds: string[] = [];
3106
+ for (const finding of findings) {
3107
+ const existing = findOpenReviewBlockerGoal(plan, finding.message);
3108
+ if (existing) {
3109
+ if (!blockerGoalIds.includes(existing.id)) blockerGoalIds.push(existing.id);
3110
+ continue;
3111
+ }
3112
+ const id = nextUltragoalGoalId(plan);
3113
+ plan.goals.push({
3114
+ id,
3115
+ title: "Resolve ultragoal review finding",
3116
+ objective: finding.message,
3117
+ status: "pending",
3118
+ createdAt: now,
3119
+ updatedAt: now,
3120
+ steering: { kind: "review_blocker" },
3121
+ });
3122
+ blockerGoalIds.push(id);
3123
+ createdGoalIds.push(id);
3124
+ }
3125
+ if (createdGoalIds.length > 0) {
3126
+ plan.updatedAt = now;
3127
+ await writePlan(cwd, plan);
3128
+ await appendLedger(cwd, {
3129
+ event: "review_blockers_recorded",
3130
+ blockerGoalIds: createdGoalIds,
3131
+ findings: findings.map(finding => finding.message),
3132
+ });
3133
+ }
3134
+ return blockerGoalIds;
3135
+ }
3136
+
3137
+ export async function runUltragoalReview(cwd: string, args: readonly string[]): Promise<UltragoalReviewResult> {
3138
+ const mode = parseReviewMode(flagValue(args, "--mode"));
3139
+ const specPath = flagValue(args, "--spec");
3140
+ const { contractStrength, source } = await resolveReviewSource(cwd, args, specPath);
3141
+ const changeSet = changeSetFromReviewSource(source);
3142
+ const executorQa = await readOptionalExecutorQa(
3143
+ cwd,
3144
+ flagValue(args, "--executor-qa-json") ?? flagValue(args, "--executor-qa"),
3145
+ );
3146
+ const findings: UltragoalReviewFinding[] = [];
3147
+ try {
3148
+ await validateExecutorQaRedTeamEvidenceForReview(cwd, executorQa, { mode: "review", changeSet });
3149
+ } catch (error) {
3150
+ findings.push(findingFromError(error));
3151
+ }
3152
+ findings.push(...executorQaBlockers(executorQa));
3153
+ const weakContractCapApplied = contractStrength === "thin-derived";
3154
+ const cleanPassEligible = contractStrength === "strong" && findings.length === 0;
3155
+ const result: UltragoalReviewResult = {
3156
+ verdict: cleanPassEligible
3157
+ ? "pass"
3158
+ : weakContractCapApplied && findings.length === 0
3159
+ ? "inconclusive: weak-contract"
3160
+ : "fail",
3161
+ contractStrength,
3162
+ cleanPassEligible,
3163
+ source,
3164
+ findings,
3165
+ artifactValidationSummary: {
3166
+ validator: "validateExecutorQaRedTeamEvidenceForReview",
3167
+ mode: "review",
3168
+ passed: findings.length === 0,
3169
+ findingCount: findings.length,
3170
+ },
3171
+ weakContractCapApplied,
3172
+ };
3173
+ if (mode === "review-start" && findings.length > 0)
3174
+ result.blockerGoalIds = await recordReviewFindingGoals(cwd, findings);
3175
+ return result;
3176
+ }
3177
+
3178
+ function flagValue(args: readonly string[], flag: string): string | undefined {
3179
+ const index = args.indexOf(flag);
3180
+ if (index < 0) return undefined;
3181
+ return args[index + 1];
3182
+ }
3183
+
3184
+ function hasFlag(args: readonly string[], flag: string): boolean {
3185
+ return args.includes(flag);
3186
+ }
3187
+
3188
+ const HELP_FLAGS = new Set(["--help", "-h"]);
3189
+
3190
+ const FLAGS_WITH_VALUES = new Set([
3191
+ "--brief",
3192
+ "--brief-file",
3193
+ "--skc-goal-mode",
3194
+ "--goal-id",
3195
+ "--status",
3196
+ "--evidence",
3197
+ "--skc-goal-json",
3198
+ "--quality-gate-json",
3199
+ "--executor-qa-json",
3200
+ "--executor-qa",
3201
+ "--pr",
3202
+ "--branch",
3203
+ "--spec",
3204
+ "--mode",
3205
+ "--kind",
3206
+ "--title",
3207
+ "--objective",
3208
+ "--rationale",
3209
+ "--replacements-json",
3210
+ "--order-json",
3211
+ ]);
3212
+
3213
+ function isHelpArg(arg: string): boolean {
3214
+ return HELP_FLAGS.has(arg);
3215
+ }
3216
+
3217
+ function commandName(args: readonly string[]): string {
3218
+ let skipNext = false;
3219
+ for (const arg of args) {
3220
+ if (skipNext) {
3221
+ skipNext = false;
3222
+ continue;
3223
+ }
3224
+ if (FLAGS_WITH_VALUES.has(arg)) {
3225
+ skipNext = true;
3226
+ continue;
3227
+ }
3228
+ if (isHelpArg(arg)) continue;
3229
+ if (!arg.startsWith("-")) return arg;
3230
+ }
3231
+ return "status";
3232
+ }
3233
+
3234
+ function renderUltragoalHelp(args: readonly string[]): string | null {
3235
+ if (!args.some(isHelpArg) && args[0] !== "help") return null;
3236
+ const subject =
3237
+ args[0] === "help" ? args.find((arg, index) => index > 0 && !arg.startsWith("-")) : commandName(args);
3238
+ if (subject === "checkpoint") {
3239
+ return [
3240
+ "Run native SKC Ultragoal workflow commands",
3241
+ "",
3242
+ "USAGE",
3243
+ " $ skc ultragoal checkpoint --goal-id <id> --status <status> --evidence <text> [FLAGS]",
3244
+ "",
3245
+ "FLAGS",
3246
+ " --goal-id=<value> Durable .skc/ultragoal goal id, e.g. G001",
3247
+ " --status=<value> pending|active|complete|failed|blocked|review_blocked|superseded",
3248
+ " --evidence=<value> Completion or checkpoint evidence text",
3249
+ " --quality-gate-json=<value> JSON string or path for complete checkpoints",
3250
+ ' --skc-goal-json=<value> JSON string or path containing the current goal({"op":"get"}) snapshot',
3251
+ " --json Output a machine-readable receipt",
3252
+ "",
3253
+ "COMPLETE CHECKPOINT RECEIPTS",
3254
+ " --quality-gate-json must be an object with architectReview, executorQa, and iteration.",
3255
+ " executorQa.contractCoverage[] rows require an obligation field; description is not a substitute.",
3256
+ ' --skc-goal-json must contain the active SKC goal-mode snapshot from goal({"op":"get"}), not the .skc/ultragoal/goals.json goal record.',
3257
+ " goal.updatedAt may be epoch milliseconds or an ISO timestamp and must be fresh.",
3258
+ "",
3259
+ "EXAMPLES",
3260
+ ' $ skc ultragoal checkpoint --goal-id G001 --status blocked --evidence "waiting on review"',
3261
+ ' $ skc ultragoal checkpoint --goal-id G001 --status complete --evidence "tests passed" --skc-goal-json ./goal.json --quality-gate-json ./quality-gate.json --json',
3262
+ "",
3263
+ ].join("\n");
3264
+ }
3265
+ if (subject === "review") {
3266
+ return [
3267
+ "Run native SKC Ultragoal workflow commands",
3268
+ "",
3269
+ "USAGE",
3270
+ " $ skc ultragoal review [--pr <n> | --branch <ref>] [--spec <path>] [--executor-qa-json <json-or-path>] [FLAGS]",
3271
+ "",
3272
+ "FLAGS",
3273
+ " --pr=<value> Review a GitHub PR; falls back to local diff when gh is unavailable",
3274
+ " --branch=<value> Review the current branch against a base ref",
3275
+ " --spec=<value> Contract/spec override; enables strong-contract clean PASS eligibility",
3276
+ " --executor-qa-json=<value> executorQa JSON string or path using checkpoint qualityGate.executorQa shape",
3277
+ " --mode=<value> review-only|review-start (default review-only)",
3278
+ " --json Output the machine-readable verdict report",
3279
+ "",
3280
+ "OUTPUT",
3281
+ " JSON includes verdict, contractStrength, cleanPassEligible, source, findings, artifactValidationSummary, and weakContractCapApplied.",
3282
+ "",
3283
+ ].join("\n");
3284
+ }
3285
+ return [
3286
+ "Run native SKC Ultragoal workflow commands",
3287
+ "",
3288
+ "USAGE",
3289
+ " $ skc ultragoal <command> [FLAGS]",
3290
+ "",
3291
+ "COMMANDS",
3292
+ " status",
3293
+ " create-goals",
3294
+ " complete-goals",
3295
+ " checkpoint",
3296
+ " review",
3297
+ " steer",
3298
+ " record-review-blockers",
3299
+ "",
3300
+ "Run `skc ultragoal checkpoint --help` or `skc ultragoal review --help` for command-specific requirements.",
3301
+ "",
3302
+ ].join("\n");
3303
+ }
3304
+
3305
+ async function readBrief(cwd: string, args: readonly string[]): Promise<string> {
3306
+ const inline = flagValue(args, "--brief");
3307
+ if (inline !== undefined) return inline;
3308
+ const briefFile = flagValue(args, "--brief-file");
3309
+ if (briefFile !== undefined) return await Bun.file(path.resolve(cwd, briefFile)).text();
3310
+ if (hasFlag(args, "--from-stdin")) return await Bun.stdin.text();
3311
+ throw new Error("create-goals requires --brief, --brief-file, or --from-stdin");
3312
+ }
3313
+
3314
+ function renderStatus(summary: UltragoalStatusSummary, json: boolean): string {
3315
+ if (json) return `${JSON.stringify(summary, null, 2)}\n`;
3316
+ return renderUltragoalStatusMarkdown(summary);
3317
+ }
3318
+
3319
+ function renderCompleteHandoff(
3320
+ result: { plan: UltragoalPlan; goal?: UltragoalGoal; allComplete: boolean },
3321
+ json: boolean,
3322
+ cwd: string,
3323
+ ): string {
3324
+ if (json) {
3325
+ return renderCliWriteReceipt({
3326
+ ok: true,
3327
+ all_complete: result.allComplete,
3328
+ next_action: result.allComplete ? "none" : "execute-goal",
3329
+ goal_id: result.goal?.id,
3330
+ goal_status: result.goal?.status,
3331
+ skc_objective: result.plan.skcObjective,
3332
+ goals_path: getUltragoalPaths(cwd).goalsPath,
3333
+ });
3334
+ }
3335
+ if (result.allComplete) return "ultragoal complete all=true\n";
3336
+ if (!result.goal) return "ultragoal next-action=none\n";
3337
+ return [
3338
+ `ultragoal next-action=execute-goal goal-id=${result.goal.id}`,
3339
+ `objective=${result.goal.objective}`,
3340
+ `skc-objective=${result.plan.skcObjective}`,
3341
+ "checkpoint requires=architectReview:CLEAR+APPROVE,executorQa:passed",
3342
+ "",
3343
+ ].join("\n");
3344
+ }
3345
+ function renderCheckpointContinuation(
3346
+ result: UltragoalCheckpointContinuation,
3347
+ status: UltragoalGoalStatus,
3348
+ json: boolean,
3349
+ cwd: string,
3350
+ ): string {
3351
+ if (json)
3352
+ return renderCliWriteReceipt({
3353
+ ok: true,
3354
+ goal_id: result.checkpointedGoal.id,
3355
+ status,
3356
+ goals_path: getUltragoalPaths(cwd).goalsPath,
3357
+ completion_receipt_kind: result.checkpointedGoal.completionVerification?.receiptKind,
3358
+ quality_gate_hash: result.checkpointedGoal.completionVerification?.qualityGateHash,
3359
+ all_complete: result.allComplete,
3360
+ next_goal_id: result.nextGoal?.id,
3361
+ next_goal_status: result.nextGoal?.status,
3362
+ started_next: result.startedNext,
3363
+ incomplete_goal_ids: result.incompleteGoals.map(goal => goal.id),
3364
+ });
3365
+ const lines = [`Checkpointed ${result.checkpointedGoal.id} as ${status}.`];
3366
+ if (status === "complete") {
3367
+ if (result.allComplete) {
3368
+ lines.push("All ultragoal goals are complete.");
3369
+ } else if (result.nextGoal) {
3370
+ lines.push(`Next ultragoal goal: ${result.nextGoal.id} — ${result.nextGoal.title}`);
3371
+ lines.push(`Objective: ${result.nextGoal.objective}`);
3372
+ lines.push(`SKC objective: ${result.plan.skcObjective}`);
3373
+ lines.push(
3374
+ result.startedNext
3375
+ ? "The next ultragoal goal is active; continue the current aggregate SKC goal and checkpoint this story when verified."
3376
+ : "Run `skc ultragoal complete-goals` to activate the next ultragoal story.",
3377
+ );
3378
+ }
3379
+ } else if (status === "failed") {
3380
+ lines.push("Resume failed goals with `skc ultragoal complete-goals --retry-failed` after the blocker is fixed.");
3381
+ } else if (status === "blocked" || status === "review_blocked") {
3382
+ lines.push(
3383
+ "Blocked ultragoal work must be resolved with explicit blocker work or steering before final completion.",
3384
+ );
3385
+ }
3386
+ lines.push("");
3387
+ return lines.join("\n");
3388
+ }
3389
+
3390
+ async function executeUltragoalSteeringCommand(args: readonly string[], cwd: string): Promise<SteeringCommandResult> {
3391
+ const kind = parseNativeSteeringKind(flagValue(args, "--kind"));
3392
+ const plan = await readUltragoalPlan(cwd);
3393
+ if (!plan) throw new Error("No ultragoal plan found. Run `skc ultragoal create-goals --brief ...` first.");
3394
+ const evidence = flagValue(args, "--evidence") ?? "";
3395
+ const rationale = flagValue(args, "--rationale") ?? "";
3396
+ try {
3397
+ switch (kind) {
3398
+ case "add_subgoal": {
3399
+ const result = await addUltragoalSubgoalToPlan({
3400
+ cwd,
3401
+ plan,
3402
+ title: flagValue(args, "--title") ?? "",
3403
+ objective: flagValue(args, "--objective") ?? "",
3404
+ evidence,
3405
+ rationale,
3406
+ });
3407
+ return {
3408
+ kind,
3409
+ message: "Accepted add_subgoal steering.\n",
3410
+ receipt: { ok: true, kind, goal_id: result.goalId, goals_path: getUltragoalPaths(cwd).goalsPath },
3411
+ };
3412
+ }
3413
+ case "split_subgoal": {
3414
+ const result = await splitUltragoalSubgoal({
3415
+ cwd,
3416
+ plan,
3417
+ goalId: flagValue(args, "--goal-id") ?? "",
3418
+ replacementsJson: flagValue(args, "--replacements-json") ?? "",
3419
+ evidence,
3420
+ rationale,
3421
+ });
3422
+ return {
3423
+ kind,
3424
+ message: "Accepted split_subgoal steering.\n",
3425
+ receipt: {
3426
+ ok: true,
3427
+ kind,
3428
+ goal_id: result.goalId,
3429
+ replacement_goal_ids: result.replacementGoalIds,
3430
+ goals_path: getUltragoalPaths(cwd).goalsPath,
3431
+ },
3432
+ };
3433
+ }
3434
+ case "reorder_pending": {
3435
+ const result = await reorderPendingUltragoalGoals({
3436
+ cwd,
3437
+ plan,
3438
+ orderJson: flagValue(args, "--order-json") ?? "",
3439
+ evidence,
3440
+ rationale,
3441
+ });
3442
+ return {
3443
+ kind,
3444
+ message: "Accepted reorder_pending steering.\n",
3445
+ receipt: {
3446
+ ok: true,
3447
+ kind,
3448
+ pending_goal_ids: result.pendingGoalIds,
3449
+ goals_path: getUltragoalPaths(cwd).goalsPath,
3450
+ },
3451
+ };
3452
+ }
3453
+ case "revise_pending_wording": {
3454
+ const result = await revisePendingUltragoalWording({
3455
+ cwd,
3456
+ plan,
3457
+ goalId: flagValue(args, "--goal-id") ?? "",
3458
+ title: flagValue(args, "--title"),
3459
+ objective: flagValue(args, "--objective"),
3460
+ evidence,
3461
+ rationale,
3462
+ });
3463
+ return {
3464
+ kind,
3465
+ message: "Accepted revise_pending_wording steering.\n",
3466
+ receipt: {
3467
+ ok: true,
3468
+ kind,
3469
+ goal_id: result.goalId,
3470
+ changed_fields: result.changedFields,
3471
+ goals_path: getUltragoalPaths(cwd).goalsPath,
3472
+ },
3473
+ };
3474
+ }
3475
+ case "annotate_ledger": {
3476
+ await annotateUltragoalLedger({ cwd, plan, evidence, rationale });
3477
+ return {
3478
+ kind,
3479
+ message: "Accepted annotate_ledger steering.\n",
3480
+ receipt: { ok: true, kind, ledger_path: getUltragoalPaths(cwd).ledgerPath },
3481
+ };
3482
+ }
3483
+ case "mark_blocked_superseded": {
3484
+ const result = await markBlockedUltragoalSuperseded({
3485
+ cwd,
3486
+ plan,
3487
+ goalId: flagValue(args, "--goal-id") ?? "",
3488
+ evidence,
3489
+ rationale,
3490
+ });
3491
+ return {
3492
+ kind,
3493
+ message: "Accepted mark_blocked_superseded steering.\n",
3494
+ receipt: {
3495
+ ok: true,
3496
+ kind,
3497
+ goal_id: result.goalId,
3498
+ no_replacement_required: true,
3499
+ goals_path: getUltragoalPaths(cwd).goalsPath,
3500
+ },
3501
+ };
3502
+ }
3503
+ }
3504
+ } catch (error) {
3505
+ const reason = error instanceof Error ? error.message : String(error);
3506
+ await appendSteeringRejected({
3507
+ cwd,
3508
+ kind,
3509
+ reason,
3510
+ goalId: flagValue(args, "--goal-id"),
3511
+ evidence,
3512
+ rationale,
3513
+ payload: steeringPayloadSummary(args),
3514
+ });
3515
+ throw error;
3516
+ }
3517
+ }
3518
+
3519
+ async function dispatchUltragoalCommand(args: string[], cwd: string): Promise<UltragoalCommandResult> {
3520
+ const help = renderUltragoalHelp(args);
3521
+ if (help) return { status: 0, stdout: help };
3522
+ try {
3523
+ const command = commandName(args);
3524
+ const json = hasFlag(args, "--json");
3525
+ switch (command) {
3526
+ case "status":
3527
+ return { status: 0, stdout: renderStatus(await getUltragoalStatus(cwd), json) };
3528
+ case "create":
3529
+ case "create-goals": {
3530
+ const mode = flagValue(args, "--skc-goal-mode") === "per-story" ? "per-story" : "aggregate";
3531
+ const plan = await createUltragoalPlan({ cwd, brief: await readBrief(cwd, args), skcGoalMode: mode });
3532
+ return {
3533
+ status: 0,
3534
+ createdPlan: true,
3535
+ stdout: json
3536
+ ? renderCliWriteReceipt({
3537
+ ok: true,
3538
+ goals_count: plan.goals.length,
3539
+ goal_ids: plan.goals.map(goal => goal.id),
3540
+ goals_path: getUltragoalPaths(cwd).goalsPath,
3541
+ })
3542
+ : `Created ultragoal plan with ${plan.goals.length} goal${plan.goals.length === 1 ? "" : "s"} at ${getUltragoalPaths(cwd).goalsPath}.\n`,
3543
+ };
3544
+ }
3545
+ case "complete-goals":
3546
+ return {
3547
+ status: 0,
3548
+ stdout: renderCompleteHandoff(
3549
+ await startNextUltragoalGoal({ cwd, retryFailed: hasFlag(args, "--retry-failed") }),
3550
+ json,
3551
+ cwd,
3552
+ ),
3553
+ };
3554
+ case "checkpoint": {
3555
+ const goalId = flagValue(args, "--goal-id") ?? "";
3556
+ const status = parseGoalStatus(flagValue(args, "--status"));
3557
+ const evidence = flagValue(args, "--evidence") ?? "";
3558
+ const result = await checkpointAndContinueUltragoalGoal({
3559
+ cwd,
3560
+ goalId,
3561
+ status,
3562
+ evidence,
3563
+ skcGoalJson: flagValue(args, "--skc-goal-json"),
3564
+ qualityGateJson: flagValue(args, "--quality-gate-json"),
3565
+ advanceNext: status === "complete",
3566
+ });
3567
+ return {
3568
+ status: 0,
3569
+ stdout: renderCheckpointContinuation(result, status, json, cwd),
3570
+ };
3571
+ }
3572
+ case "review": {
3573
+ const result = await runUltragoalReview(cwd, args);
3574
+ return {
3575
+ status: 0,
3576
+ stdout: json ? `${JSON.stringify(result, null, 2)}\n` : `${result.verdict}\n`,
3577
+ reviewBlockerGoalIds: result.blockerGoalIds,
3578
+ createdReviewPlan: (result.blockerGoalIds?.length ?? 0) > 0,
3579
+ };
3580
+ }
3581
+ case "steer": {
3582
+ const result = await executeUltragoalSteeringCommand(args, cwd);
3583
+ return {
3584
+ status: 0,
3585
+ stdout: json ? renderCliWriteReceipt(result.receipt) : result.message,
3586
+ };
3587
+ }
3588
+ case "record-review-blockers": {
3589
+ const plan = await recordUltragoalReviewBlockers({
3590
+ cwd,
3591
+ goalId: flagValue(args, "--goal-id") ?? "",
3592
+ title: flagValue(args, "--title") ?? "Resolve final code-review blockers",
3593
+ objective: flagValue(args, "--objective") ?? "",
3594
+ evidence: flagValue(args, "--evidence") ?? "",
3595
+ skcGoalJson: flagValue(args, "--skc-goal-json"),
3596
+ });
3597
+ const goal = plan.goals.at(-1);
3598
+ return {
3599
+ status: 0,
3600
+ stdout: json
3601
+ ? renderCliWriteReceipt({ ok: true, goal_id: goal?.id, goals_path: getUltragoalPaths(cwd).goalsPath })
3602
+ : "Recorded review blockers.\n",
3603
+ };
3604
+ }
3605
+ default:
3606
+ return { status: 1, stderr: `Unknown skc ultragoal command: ${command}\n` };
3607
+ }
3608
+ } catch (error) {
3609
+ return { status: 1, stderr: `${error instanceof Error ? error.message : String(error)}\n` };
3610
+ }
3611
+ }
3612
+
3613
+ const RECONCILE_COMMANDS = new Set([
3614
+ "status",
3615
+ "create",
3616
+ "create-goals",
3617
+ "complete-goals",
3618
+ "checkpoint",
3619
+ "steer",
3620
+ "record-review-blockers",
3621
+ "review",
3622
+ ]);
3623
+
3624
+ /**
3625
+ * Derive a workflow-state payload from the ultragoal plan/ledger and reconcile the
3626
+ * ultragoal mode-state + active-state/HUD so `skc state ultragoal read`, the
3627
+ * skill-tool chain guard, and the HUD chip mirror the plan/ledger. Session scope
3628
+ * follows `skc state` (`SKC_SESSION_ID`). This is a derived repair: it never changes
3629
+ * the triggering command's status/stdout, but a failure is surfaced (stderr + a
3630
+ * `reconcile_failed` ledger audit event) rather than silently swallowed. `status` is
3631
+ * therefore a read PLUS a derived repair; it never mutates goals.json/ledger.jsonl
3632
+ * beyond that reconcile-failure audit event.
3633
+ */
3634
+ async function reconcileUltragoalState(cwd: string): Promise<void> {
3635
+ const sessionId = process.env.SKC_SESSION_ID?.trim() || undefined;
3636
+ try {
3637
+ const summary = await getUltragoalStatus(cwd);
3638
+ const status = summary.status;
3639
+ const active = summary.exists && status !== "complete";
3640
+ const payload: Record<string, unknown> = {
3641
+ skill: "ultragoal",
3642
+ status,
3643
+ current_phase: status,
3644
+ active,
3645
+ goals: summary.goals.map(goal => ({ id: goal.id, title: goal.title, status: goal.status })),
3646
+ counts: summary.counts,
3647
+ active_goal_id: summary.currentGoal?.id ?? null,
3648
+ ledger_path: summary.paths.ledgerPath,
3649
+ brief_path: summary.paths.briefPath,
3650
+ goals_path: summary.paths.goalsPath,
3651
+ };
3652
+ if (summary.skcObjective) payload.skc_objective = summary.skcObjective;
3653
+ const ledgerText = await Bun.file(summary.paths.ledgerPath)
3654
+ .text()
3655
+ .catch(() => "");
3656
+ const latestLedger = latestUltragoalLedgerEventFromText(ledgerText);
3657
+ if (latestLedger) {
3658
+ payload.latestLedgerEvent = {
3659
+ event: latestLedger.event,
3660
+ ...(latestLedger.goalId ? { goalId: latestLedger.goalId } : {}),
3661
+ ...(latestLedger.timestamp ? { timestamp: latestLedger.timestamp } : {}),
3662
+ };
3663
+ }
3664
+ await reconcileWorkflowSkillState({ cwd, mode: "ultragoal", sessionId, active, phase: status, payload });
3665
+ } catch (error) {
3666
+ const message = error instanceof Error ? error.message : String(error);
3667
+ process.stderr.write(`ultragoal state reconciliation failed: ${message}\n`);
3668
+ try {
3669
+ await appendLedger(cwd, { type: "reconcile_failed", error: message });
3670
+ } catch {
3671
+ // Best-effort audit; never let a secondary failure change command semantics.
3672
+ }
3673
+ }
3674
+ }
3675
+
3676
+ export async function runNativeUltragoalCommand(args: string[], cwd = process.cwd()): Promise<UltragoalCommandResult> {
3677
+ const command = commandName(args);
3678
+ const result = await dispatchUltragoalCommand(args, cwd);
3679
+ const isHelp = args.some(isHelpArg) || args[0] === "help";
3680
+ if (!isHelp && result.status === 0 && RECONCILE_COMMANDS.has(command)) {
3681
+ await reconcileUltragoalState(cwd);
3682
+ }
3683
+ return result;
3684
+ }