@sayknow-cli/coding-agent 0.3.6 → 0.3.8

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 (1264) hide show
  1. package/README.md +76 -0
  2. package/dist/types/append-only-mode.d.ts +31 -0
  3. package/dist/types/async/index.d.ts +2 -0
  4. package/dist/types/async/job-manager.d.ts +328 -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 +47 -0
  25. package/dist/types/capability/prompt.d.ts +15 -0
  26. package/dist/types/capability/rule.d.ts +69 -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/completion-cli.d.ts +41 -0
  41. package/dist/types/cli/config-cli.d.ts +23 -0
  42. package/dist/types/cli/daemon-cli.d.ts +25 -0
  43. package/dist/types/cli/fast-help.d.ts +1 -0
  44. package/dist/types/cli/file-processor.d.ts +11 -0
  45. package/dist/types/cli/fixture-report.d.ts +20 -0
  46. package/dist/types/cli/fixture-report.test.d.ts +1 -0
  47. package/dist/types/cli/grep-cli.d.ts +17 -0
  48. package/dist/types/cli/initial-message.d.ts +17 -0
  49. package/dist/types/cli/list-models.d.ts +36 -0
  50. package/dist/types/cli/local-provider-smoke.d.ts +59 -0
  51. package/dist/types/cli/mcp-cli.d.ts +25 -0
  52. package/dist/types/cli/migrate-cli.d.ts +20 -0
  53. package/dist/types/cli/nofile-limit.d.ts +11 -0
  54. package/dist/types/cli/notify-cli.d.ts +32 -0
  55. package/dist/types/cli/plugin-cli.d.ts +34 -0
  56. package/dist/types/cli/read-cli.d.ts +4 -0
  57. package/dist/types/cli/session-picker.d.ts +3 -0
  58. package/dist/types/cli/setup-cli.d.ts +73 -0
  59. package/dist/types/cli/shell-cli.d.ts +8 -0
  60. package/dist/types/cli/skills-cli.d.ts +9 -0
  61. package/dist/types/cli/ssh-cli.d.ts +21 -0
  62. package/dist/types/cli/stats-cli.d.ts +17 -0
  63. package/dist/types/cli/telegram-cli.d.ts +13 -0
  64. package/dist/types/cli/update-cli.d.ts +89 -0
  65. package/dist/types/cli/web-search-cli.d.ts +32 -0
  66. package/dist/types/cli/worktree-cli.d.ts +26 -0
  67. package/dist/types/cli.d.ts +132 -0
  68. package/dist/types/commands/acp.d.ts +12 -0
  69. package/dist/types/commands/agents.d.ts +34 -0
  70. package/dist/types/commands/auth-broker.d.ts +54 -0
  71. package/dist/types/commands/auth-gateway.d.ts +32 -0
  72. package/dist/types/commands/codex-native-hook.d.ts +6 -0
  73. package/dist/types/commands/commit.d.ts +27 -0
  74. package/dist/types/commands/completion.d.ts +29 -0
  75. package/dist/types/commands/config.d.ts +33 -0
  76. package/dist/types/commands/contribution-prep.d.ts +18 -0
  77. package/dist/types/commands/coordinator.d.ts +19 -0
  78. package/dist/types/commands/daemon.d.ts +41 -0
  79. package/dist/types/commands/deep-interview.d.ts +54 -0
  80. package/dist/types/commands/gc.d.ts +26 -0
  81. package/dist/types/commands/grep.d.ts +42 -0
  82. package/dist/types/commands/harness.d.ts +43 -0
  83. package/dist/types/commands/launch.d.ts +127 -0
  84. package/dist/types/commands/local-provider.d.ts +34 -0
  85. package/dist/types/commands/mcp-serve.d.ts +24 -0
  86. package/dist/types/commands/mcp.d.ts +70 -0
  87. package/dist/types/commands/migrate.d.ts +33 -0
  88. package/dist/types/commands/notify.d.ts +41 -0
  89. package/dist/types/commands/plugin.d.ts +58 -0
  90. package/dist/types/commands/ralplan.d.ts +7 -0
  91. package/dist/types/commands/read.d.ts +15 -0
  92. package/dist/types/commands/rlm.d.ts +10 -0
  93. package/dist/types/commands/session.d.ts +30 -0
  94. package/dist/types/commands/setup.d.ts +105 -0
  95. package/dist/types/commands/shell.d.ts +21 -0
  96. package/dist/types/commands/skills.d.ts +26 -0
  97. package/dist/types/commands/ssh.d.ts +48 -0
  98. package/dist/types/commands/state.d.ts +7 -0
  99. package/dist/types/commands/stats.d.ts +25 -0
  100. package/dist/types/commands/team.d.ts +24 -0
  101. package/dist/types/commands/telegram.d.ts +22 -0
  102. package/dist/types/commands/ultragoal.d.ts +8 -0
  103. package/dist/types/commands/update.d.ts +20 -0
  104. package/dist/types/commands/web-search.d.ts +87 -0
  105. package/dist/types/commands/worktree.d.ts +34 -0
  106. package/dist/types/commit/agentic/agent.d.ts +31 -0
  107. package/dist/types/commit/agentic/fallback.d.ts +5 -0
  108. package/dist/types/commit/agentic/index.d.ts +2 -0
  109. package/dist/types/commit/agentic/state.d.ts +58 -0
  110. package/dist/types/commit/agentic/tools/analyze-file.d.ts +19 -0
  111. package/dist/types/commit/agentic/tools/git-file-diff.d.ts +10 -0
  112. package/dist/types/commit/agentic/tools/git-hunk.d.ts +9 -0
  113. package/dist/types/commit/agentic/tools/git-overview.d.ts +9 -0
  114. package/dist/types/commit/agentic/tools/index.d.ts +16 -0
  115. package/dist/types/commit/agentic/tools/propose-changelog.d.ts +28 -0
  116. package/dist/types/commit/agentic/tools/propose-commit.d.ts +36 -0
  117. package/dist/types/commit/agentic/tools/recent-commits.d.ts +7 -0
  118. package/dist/types/commit/agentic/tools/schemas.d.ts +27 -0
  119. package/dist/types/commit/agentic/tools/split-commit.d.ts +53 -0
  120. package/dist/types/commit/agentic/topo-sort.d.ts +4 -0
  121. package/dist/types/commit/agentic/trivial.d.ts +7 -0
  122. package/dist/types/commit/agentic/validation.d.ts +20 -0
  123. package/dist/types/commit/analysis/conventional.d.ts +22 -0
  124. package/dist/types/commit/analysis/index.d.ts +4 -0
  125. package/dist/types/commit/analysis/scope.d.ts +6 -0
  126. package/dist/types/commit/analysis/summary.d.ts +19 -0
  127. package/dist/types/commit/analysis/validation.d.ts +8 -0
  128. package/dist/types/commit/changelog/detect.d.ts +2 -0
  129. package/dist/types/commit/changelog/generate.d.ts +30 -0
  130. package/dist/types/commit/changelog/index.d.ts +30 -0
  131. package/dist/types/commit/changelog/parse.d.ts +2 -0
  132. package/dist/types/commit/cli.d.ts +3 -0
  133. package/dist/types/commit/git/diff.d.ts +5 -0
  134. package/dist/types/commit/index.d.ts +4 -0
  135. package/dist/types/commit/map-reduce/index.d.ts +28 -0
  136. package/dist/types/commit/map-reduce/map-phase.d.ts +17 -0
  137. package/dist/types/commit/map-reduce/reduce-phase.d.ts +13 -0
  138. package/dist/types/commit/map-reduce/utils.d.ts +2 -0
  139. package/dist/types/commit/message.d.ts +2 -0
  140. package/dist/types/commit/model-selection.d.ts +15 -0
  141. package/dist/types/commit/pipeline.d.ts +5 -0
  142. package/dist/types/commit/shared-llm.d.ts +54 -0
  143. package/dist/types/commit/types.d.ts +78 -0
  144. package/dist/types/commit/utils/exclusions.d.ts +4 -0
  145. package/dist/types/commit/utils.d.ts +20 -0
  146. package/dist/types/config/config-file.d.ts +58 -0
  147. package/dist/types/config/file-lock-gc.d.ts +5 -0
  148. package/dist/types/config/file-lock.d.ts +36 -0
  149. package/dist/types/config/keybindings.d.ts +359 -0
  150. package/dist/types/config/model-equivalence.d.ts +24 -0
  151. package/dist/types/config/model-profile-activation.d.ts +64 -0
  152. package/dist/types/config/model-profiles.d.ts +39 -0
  153. package/dist/types/config/model-registry.d.ts +465 -0
  154. package/dist/types/config/model-resolver.d.ts +217 -0
  155. package/dist/types/config/models-config-schema.d.ts +700 -0
  156. package/dist/types/config/prompt-templates.d.ts +32 -0
  157. package/dist/types/config/resolve-config-value.d.ts +17 -0
  158. package/dist/types/config/settings-schema.d.ts +4169 -0
  159. package/dist/types/config/settings.d.ts +149 -0
  160. package/dist/types/config/skill-settings-defaults.d.ts +14 -0
  161. package/dist/types/config/telegram-autostart.d.ts +14 -0
  162. package/dist/types/config/telegram-env-bridge.d.ts +18 -0
  163. package/dist/types/config.d.ts +66 -0
  164. package/dist/types/coordinator/contract.d.ts +4 -0
  165. package/dist/types/coordinator-mcp/policy.d.ts +24 -0
  166. package/dist/types/coordinator-mcp/safety.d.ts +26 -0
  167. package/dist/types/coordinator-mcp/server.d.ts +66 -0
  168. package/dist/types/cursor.d.ts +24 -0
  169. package/dist/types/daemon/builtin.d.ts +20 -0
  170. package/dist/types/daemon/control-types.d.ts +57 -0
  171. package/dist/types/daemon/runtime.d.ts +25 -0
  172. package/dist/types/dap/client.d.ts +39 -0
  173. package/dist/types/dap/config.d.ts +6 -0
  174. package/dist/types/dap/index.d.ts +4 -0
  175. package/dist/types/dap/session.d.ts +108 -0
  176. package/dist/types/dap/types.d.ts +524 -0
  177. package/dist/types/debug/crash-diagnostics.d.ts +45 -0
  178. package/dist/types/debug/index.d.ts +15 -0
  179. package/dist/types/debug/log-formatting.d.ts +4 -0
  180. package/dist/types/debug/log-viewer.d.ts +68 -0
  181. package/dist/types/debug/profiler.d.ts +24 -0
  182. package/dist/types/debug/raw-sse-buffer.d.ts +44 -0
  183. package/dist/types/debug/raw-sse.d.ts +16 -0
  184. package/dist/types/debug/report-bundle.d.ts +55 -0
  185. package/dist/types/debug/runtime-gauges.d.ts +6 -0
  186. package/dist/types/debug/system-info.d.ts +26 -0
  187. package/dist/types/deep-interview/plaintext-gate-guard.d.ts +11 -0
  188. package/dist/types/deep-interview/render-middleware.d.ts +6 -0
  189. package/dist/types/defaults/skc/extensions/grok-build/index.d.ts +1 -0
  190. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/index.d.ts +1 -0
  191. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/models/catalog.d.ts +25 -0
  192. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/payload/sanitize.d.ts +27 -0
  193. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/provider/billing.d.ts +8 -0
  194. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/provider/register.d.ts +5 -0
  195. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/provider/stream.d.ts +10 -0
  196. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/provider/usage.d.ts +2 -0
  197. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/shared/base-url.d.ts +2 -0
  198. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/shared/errors.d.ts +38 -0
  199. package/dist/types/defaults/skc-defaults.d.ts +64 -0
  200. package/dist/types/defaults/skc-grok-cli.d.ts +5 -0
  201. package/dist/types/discovery/agents-md.d.ts +1 -0
  202. package/dist/types/discovery/agents.d.ts +12 -0
  203. package/dist/types/discovery/builtin.d.ts +1 -0
  204. package/dist/types/discovery/claude-plugins.d.ts +1 -0
  205. package/dist/types/discovery/claude.d.ts +1 -0
  206. package/dist/types/discovery/cline.d.ts +1 -0
  207. package/dist/types/discovery/codex.d.ts +1 -0
  208. package/dist/types/discovery/cursor.d.ts +19 -0
  209. package/dist/types/discovery/gemini.d.ts +1 -0
  210. package/dist/types/discovery/github.d.ts +1 -0
  211. package/dist/types/discovery/helpers.d.ts +271 -0
  212. package/dist/types/discovery/index.d.ts +48 -0
  213. package/dist/types/discovery/mcp-json.d.ts +1 -0
  214. package/dist/types/discovery/opencode.d.ts +1 -0
  215. package/dist/types/discovery/plugin-dir-roots.d.ts +15 -0
  216. package/dist/types/discovery/ssh.d.ts +1 -0
  217. package/dist/types/discovery/substitute-plugin-root.d.ts +5 -0
  218. package/dist/types/discovery/vscode.d.ts +1 -0
  219. package/dist/types/discovery/windsurf.d.ts +15 -0
  220. package/dist/types/edit/apply-patch/index.d.ts +35 -0
  221. package/dist/types/edit/apply-patch/parser.d.ts +34 -0
  222. package/dist/types/edit/diff.d.ts +75 -0
  223. package/dist/types/edit/file-read-cache.d.ts +25 -0
  224. package/dist/types/edit/index.d.ts +58 -0
  225. package/dist/types/edit/modes/apply-patch.d.ts +24 -0
  226. package/dist/types/edit/modes/patch.d.ts +99 -0
  227. package/dist/types/edit/modes/replace.d.ts +149 -0
  228. package/dist/types/edit/normalize.d.ts +43 -0
  229. package/dist/types/edit/notebook.d.ts +26 -0
  230. package/dist/types/edit/read-file.d.ts +8 -0
  231. package/dist/types/edit/renderer.d.ts +110 -0
  232. package/dist/types/edit/streaming.d.ts +66 -0
  233. package/dist/types/eval/backend.d.ts +40 -0
  234. package/dist/types/eval/index.d.ts +4 -0
  235. package/dist/types/eval/js/context-manager.d.ts +27 -0
  236. package/dist/types/eval/js/executor.d.ts +29 -0
  237. package/dist/types/eval/js/index.d.ts +10 -0
  238. package/dist/types/eval/js/shared/helpers.d.ts +38 -0
  239. package/dist/types/eval/js/shared/indirect-eval.d.ts +14 -0
  240. package/dist/types/eval/js/shared/prelude.d.ts +1 -0
  241. package/dist/types/eval/js/shared/rewrite-imports.d.ts +6 -0
  242. package/dist/types/eval/js/shared/runtime.d.ts +47 -0
  243. package/dist/types/eval/js/shared/types.d.ts +24 -0
  244. package/dist/types/eval/js/tool-bridge.d.ts +18 -0
  245. package/dist/types/eval/js/worker-core.d.ts +5 -0
  246. package/dist/types/eval/js/worker-entry.d.ts +1 -0
  247. package/dist/types/eval/js/worker-protocol.d.ts +77 -0
  248. package/dist/types/eval/py/display.d.ts +25 -0
  249. package/dist/types/eval/py/executor.d.ts +88 -0
  250. package/dist/types/eval/py/index.d.ts +10 -0
  251. package/dist/types/eval/py/kernel.d.ts +65 -0
  252. package/dist/types/eval/py/prelude.d.ts +1 -0
  253. package/dist/types/eval/py/runtime.d.ts +29 -0
  254. package/dist/types/eval/py/tool-bridge.d.ts +20 -0
  255. package/dist/types/eval/types.d.ts +52 -0
  256. package/dist/types/exa/factory.d.ts +13 -0
  257. package/dist/types/exa/index.d.ts +20 -0
  258. package/dist/types/exa/mcp-client.d.ts +45 -0
  259. package/dist/types/exa/render.d.ts +19 -0
  260. package/dist/types/exa/researcher.d.ts +9 -0
  261. package/dist/types/exa/search.d.ts +9 -0
  262. package/dist/types/exa/types.d.ts +155 -0
  263. package/dist/types/exa/websets.d.ts +9 -0
  264. package/dist/types/exec/bash-executor.d.ts +64 -0
  265. package/dist/types/exec/exec.d.ts +25 -0
  266. package/dist/types/exec/idle-timeout-watchdog.d.ts +18 -0
  267. package/dist/types/exec/non-interactive-env.d.ts +1 -0
  268. package/dist/types/export/custom-share.d.ts +20 -0
  269. package/dist/types/export/html/index.d.ts +10 -0
  270. package/dist/types/export/html/template.generated.d.ts +1 -0
  271. package/dist/types/export/html/template.macro.d.ts +5 -0
  272. package/dist/types/export/ttsr.d.ts +55 -0
  273. package/dist/types/extensibility/custom-commands/bundled/ci-green/index.d.ts +9 -0
  274. package/dist/types/extensibility/custom-commands/index.d.ts +2 -0
  275. package/dist/types/extensibility/custom-commands/loader.d.ts +29 -0
  276. package/dist/types/extensibility/custom-commands/types.d.ts +106 -0
  277. package/dist/types/extensibility/custom-tools/index.d.ts +6 -0
  278. package/dist/types/extensibility/custom-tools/loader.d.ts +69 -0
  279. package/dist/types/extensibility/custom-tools/types.d.ts +229 -0
  280. package/dist/types/extensibility/custom-tools/wrapper.d.ts +24 -0
  281. package/dist/types/extensibility/extensions/compact-handler.d.ts +26 -0
  282. package/dist/types/extensibility/extensions/get-commands-handler.d.ts +29 -0
  283. package/dist/types/extensibility/extensions/index.d.ts +9 -0
  284. package/dist/types/extensibility/extensions/loader.d.ts +43 -0
  285. package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +35 -0
  286. package/dist/types/extensibility/extensions/runner.d.ts +135 -0
  287. package/dist/types/extensibility/extensions/types.d.ts +918 -0
  288. package/dist/types/extensibility/extensions/wrapper.d.ts +55 -0
  289. package/dist/types/extensibility/hooks/index.d.ts +5 -0
  290. package/dist/types/extensibility/hooks/loader.d.ts +89 -0
  291. package/dist/types/extensibility/hooks/runner.d.ts +126 -0
  292. package/dist/types/extensibility/hooks/tool-wrapper.d.ts +25 -0
  293. package/dist/types/extensibility/hooks/types.d.ts +431 -0
  294. package/dist/types/extensibility/plugins/doctor.d.ts +3 -0
  295. package/dist/types/extensibility/plugins/git-url.d.ts +34 -0
  296. package/dist/types/extensibility/plugins/index.d.ts +8 -0
  297. package/dist/types/extensibility/plugins/installer.d.ts +5 -0
  298. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
  299. package/dist/types/extensibility/plugins/loader.d.ts +31 -0
  300. package/dist/types/extensibility/plugins/manager.d.ts +65 -0
  301. package/dist/types/extensibility/plugins/marketplace/cache.d.ts +41 -0
  302. package/dist/types/extensibility/plugins/marketplace/fetcher.d.ts +48 -0
  303. package/dist/types/extensibility/plugins/marketplace/index.d.ts +6 -0
  304. package/dist/types/extensibility/plugins/marketplace/manager.d.ts +57 -0
  305. package/dist/types/extensibility/plugins/marketplace/registry.d.ts +34 -0
  306. package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +28 -0
  307. package/dist/types/extensibility/plugins/marketplace/types.d.ts +130 -0
  308. package/dist/types/extensibility/plugins/parser.d.ts +52 -0
  309. package/dist/types/extensibility/plugins/security-scanner.d.ts +31 -0
  310. package/dist/types/extensibility/plugins/types.d.ts +149 -0
  311. package/dist/types/extensibility/shared-events.d.ts +281 -0
  312. package/dist/types/extensibility/skc-plugins/activation.d.ts +14 -0
  313. package/dist/types/extensibility/skc-plugins/compiler.d.ts +19 -0
  314. package/dist/types/extensibility/skc-plugins/constrained-hooks.d.ts +29 -0
  315. package/dist/types/extensibility/skc-plugins/index.d.ts +18 -0
  316. package/dist/types/extensibility/skc-plugins/injection.d.ts +40 -0
  317. package/dist/types/extensibility/skc-plugins/installer.d.ts +13 -0
  318. package/dist/types/extensibility/skc-plugins/loader.d.ts +3 -0
  319. package/dist/types/extensibility/skc-plugins/mcp-policy.d.ts +26 -0
  320. package/dist/types/extensibility/skc-plugins/observability.d.ts +27 -0
  321. package/dist/types/extensibility/skc-plugins/paths.d.ts +8 -0
  322. package/dist/types/extensibility/skc-plugins/prompt-appendix.d.ts +16 -0
  323. package/dist/types/extensibility/skc-plugins/registry.d.ts +32 -0
  324. package/dist/types/extensibility/skc-plugins/runtime-adapters.d.ts +64 -0
  325. package/dist/types/extensibility/skc-plugins/schema.d.ts +3 -0
  326. package/dist/types/extensibility/skc-plugins/session-validation.d.ts +42 -0
  327. package/dist/types/extensibility/skc-plugins/state.d.ts +9 -0
  328. package/dist/types/extensibility/skc-plugins/tools.d.ts +8 -0
  329. package/dist/types/extensibility/skc-plugins/types.d.ts +220 -0
  330. package/dist/types/extensibility/skc-plugins/validation.d.ts +11 -0
  331. package/dist/types/extensibility/skills.d.ts +82 -0
  332. package/dist/types/extensibility/slash-commands.d.ts +48 -0
  333. package/dist/types/extensibility/tool-proxy.d.ts +4 -0
  334. package/dist/types/extensibility/typebox.d.ts +155 -0
  335. package/dist/types/extensibility/utils.d.ts +12 -0
  336. package/dist/types/goals/index.d.ts +3 -0
  337. package/dist/types/goals/runtime.d.ts +63 -0
  338. package/dist/types/goals/state.d.ts +32 -0
  339. package/dist/types/goals/tools/goal-tool.d.ts +62 -0
  340. package/dist/types/harness-control-plane/classifier.d.ts +13 -0
  341. package/dist/types/harness-control-plane/control-endpoint.d.ts +31 -0
  342. package/dist/types/harness-control-plane/finalize.d.ts +60 -0
  343. package/dist/types/harness-control-plane/gc-adapter.d.ts +3 -0
  344. package/dist/types/harness-control-plane/operate.d.ts +35 -0
  345. package/dist/types/harness-control-plane/owner.d.ts +53 -0
  346. package/dist/types/harness-control-plane/phase-rollup.d.ts +23 -0
  347. package/dist/types/harness-control-plane/preserve.d.ts +19 -0
  348. package/dist/types/harness-control-plane/receipt-ingest.d.ts +19 -0
  349. package/dist/types/harness-control-plane/receipt-spool.d.ts +19 -0
  350. package/dist/types/harness-control-plane/receipts.d.ts +149 -0
  351. package/dist/types/harness-control-plane/rpc-adapter.d.ts +69 -0
  352. package/dist/types/harness-control-plane/seams.d.ts +21 -0
  353. package/dist/types/harness-control-plane/session-lease.d.ts +65 -0
  354. package/dist/types/harness-control-plane/state-machine.d.ts +24 -0
  355. package/dist/types/harness-control-plane/storage.d.ts +81 -0
  356. package/dist/types/harness-control-plane/types.d.ts +187 -0
  357. package/dist/types/hashline/anchors.d.ts +20 -0
  358. package/dist/types/hashline/apply.d.ts +14 -0
  359. package/dist/types/hashline/constants.d.ts +19 -0
  360. package/dist/types/hashline/diff-preview.d.ts +2 -0
  361. package/dist/types/hashline/diff.d.ts +17 -0
  362. package/dist/types/hashline/execute.d.ts +4 -0
  363. package/dist/types/hashline/hash.d.ts +123 -0
  364. package/dist/types/hashline/index.d.ts +13 -0
  365. package/dist/types/hashline/input.d.ts +11 -0
  366. package/dist/types/hashline/parser.d.ts +7 -0
  367. package/dist/types/hashline/prefixes.d.ts +7 -0
  368. package/dist/types/hashline/recovery.d.ts +27 -0
  369. package/dist/types/hashline/stream.d.ts +2 -0
  370. package/dist/types/hashline/types.d.ts +77 -0
  371. package/dist/types/hindsight/backend.d.ts +13 -0
  372. package/dist/types/hindsight/bank.d.ts +54 -0
  373. package/dist/types/hindsight/client.d.ts +224 -0
  374. package/dist/types/hindsight/config.d.ts +51 -0
  375. package/dist/types/hindsight/content.d.ts +70 -0
  376. package/dist/types/hindsight/index.d.ts +8 -0
  377. package/dist/types/hindsight/mental-models.d.ts +125 -0
  378. package/dist/types/hindsight/state.d.ts +99 -0
  379. package/dist/types/hindsight/transcript.d.ts +28 -0
  380. package/dist/types/hooks/codex-native-hooks-config.d.ts +29 -0
  381. package/dist/types/hooks/native-skill-hook.d.ts +28 -0
  382. package/dist/types/hooks/skill-keywords.d.ts +18 -0
  383. package/dist/types/hooks/skill-state.d.ts +93 -0
  384. package/dist/types/i18n/index.d.ts +38 -0
  385. package/dist/types/i18n/messages/de.d.ts +2 -0
  386. package/dist/types/i18n/messages/de.messages.d.ts +1 -0
  387. package/dist/types/i18n/messages/de.settings.d.ts +1 -0
  388. package/dist/types/i18n/messages/en.d.ts +81 -0
  389. package/dist/types/i18n/messages/es.d.ts +2 -0
  390. package/dist/types/i18n/messages/es.messages.d.ts +1 -0
  391. package/dist/types/i18n/messages/es.settings.d.ts +1 -0
  392. package/dist/types/i18n/messages/fr.d.ts +2 -0
  393. package/dist/types/i18n/messages/fr.messages.d.ts +1 -0
  394. package/dist/types/i18n/messages/fr.settings.d.ts +1 -0
  395. package/dist/types/i18n/messages/ja.d.ts +2 -0
  396. package/dist/types/i18n/messages/ja.messages.d.ts +1 -0
  397. package/dist/types/i18n/messages/ja.settings.d.ts +1 -0
  398. package/dist/types/i18n/messages/ko.d.ts +2 -0
  399. package/dist/types/i18n/messages/ko.messages.d.ts +1 -0
  400. package/dist/types/i18n/messages/ko.settings.d.ts +1 -0
  401. package/dist/types/i18n/messages/zh.d.ts +2 -0
  402. package/dist/types/i18n/messages/zh.messages.d.ts +1 -0
  403. package/dist/types/i18n/messages/zh.settings.d.ts +1 -0
  404. package/dist/types/index.d.ts +33 -0
  405. package/dist/types/internal-urls/agent-protocol.d.ts +12 -0
  406. package/dist/types/internal-urls/artifact-protocol.d.ts +6 -0
  407. package/dist/types/internal-urls/docs-index.generated.d.ts +2 -0
  408. package/dist/types/internal-urls/index.d.ts +20 -0
  409. package/dist/types/internal-urls/issue-pr-protocol.d.ts +17 -0
  410. package/dist/types/internal-urls/json-query.d.ts +30 -0
  411. package/dist/types/internal-urls/local-protocol.d.ts +39 -0
  412. package/dist/types/internal-urls/mcp-protocol.d.ts +12 -0
  413. package/dist/types/internal-urls/memory-protocol.d.ts +23 -0
  414. package/dist/types/internal-urls/parse.d.ts +19 -0
  415. package/dist/types/internal-urls/registry-helpers.d.ts +11 -0
  416. package/dist/types/internal-urls/router.d.ts +14 -0
  417. package/dist/types/internal-urls/rule-protocol.d.ts +6 -0
  418. package/dist/types/internal-urls/skc-protocol.d.ts +12 -0
  419. package/dist/types/internal-urls/skill-protocol.d.ts +13 -0
  420. package/dist/types/internal-urls/types.d.ts +109 -0
  421. package/dist/types/lsp/client.d.ts +66 -0
  422. package/dist/types/lsp/clients/biome-client.d.ts +16 -0
  423. package/dist/types/lsp/clients/index.d.ts +19 -0
  424. package/dist/types/lsp/clients/lsp-linter-client.d.ts +16 -0
  425. package/dist/types/lsp/clients/swiftlint-client.d.ts +20 -0
  426. package/dist/types/lsp/config.d.ts +65 -0
  427. package/dist/types/lsp/edits.d.ts +23 -0
  428. package/dist/types/lsp/index.d.ts +130 -0
  429. package/dist/types/lsp/lspmux.d.ts +58 -0
  430. package/dist/types/lsp/render.d.ts +32 -0
  431. package/dist/types/lsp/startup-events.d.ts +12 -0
  432. package/dist/types/lsp/types.d.ts +306 -0
  433. package/dist/types/lsp/utils.d.ts +108 -0
  434. package/dist/types/main.d.ts +75 -0
  435. package/dist/types/memories/index.d.ts +28 -0
  436. package/dist/types/memories/storage.d.ts +110 -0
  437. package/dist/types/memory-backend/index.d.ts +4 -0
  438. package/dist/types/memory-backend/local-backend.d.ts +9 -0
  439. package/dist/types/memory-backend/off-backend.d.ts +7 -0
  440. package/dist/types/memory-backend/resolve.d.ts +15 -0
  441. package/dist/types/memory-backend/types.d.ts +61 -0
  442. package/dist/types/migrate/action-planner.d.ts +11 -0
  443. package/dist/types/migrate/adapters/claude-code.d.ts +2 -0
  444. package/dist/types/migrate/adapters/codex.d.ts +5 -0
  445. package/dist/types/migrate/adapters/index.d.ts +45 -0
  446. package/dist/types/migrate/adapters/opencode.d.ts +2 -0
  447. package/dist/types/migrate/executor.d.ts +2 -0
  448. package/dist/types/migrate/mcp-mapper.d.ts +20 -0
  449. package/dist/types/migrate/report.d.ts +18 -0
  450. package/dist/types/migrate/skill-normalizer.d.ts +27 -0
  451. package/dist/types/migrate/types.d.ts +126 -0
  452. package/dist/types/modes/acp/acp-agent.d.ts +61 -0
  453. package/dist/types/modes/acp/acp-client-bridge.d.ts +9 -0
  454. package/dist/types/modes/acp/acp-event-mapper.d.ts +34 -0
  455. package/dist/types/modes/acp/acp-mode.d.ts +5 -0
  456. package/dist/types/modes/acp/index.d.ts +2 -0
  457. package/dist/types/modes/acp/terminal-auth.d.ts +6 -0
  458. package/dist/types/modes/bridge/auth.d.ts +12 -0
  459. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +9 -0
  460. package/dist/types/modes/bridge/bridge-mode.d.ts +47 -0
  461. package/dist/types/modes/bridge/bridge-ui-context.d.ts +88 -0
  462. package/dist/types/modes/bridge/event-stream.d.ts +8 -0
  463. package/dist/types/modes/components/agent-dashboard.d.ts +21 -0
  464. package/dist/types/modes/components/assistant-message.d.ts +20 -0
  465. package/dist/types/modes/components/bash-execution.d.ts +29 -0
  466. package/dist/types/modes/components/bordered-loader.d.ts +11 -0
  467. package/dist/types/modes/components/branch-summary-message.d.ts +13 -0
  468. package/dist/types/modes/components/btw-panel.d.ts +16 -0
  469. package/dist/types/modes/components/compaction-summary-message.d.ts +13 -0
  470. package/dist/types/modes/components/countdown-timer.d.ts +14 -0
  471. package/dist/types/modes/components/custom-editor.d.ts +67 -0
  472. package/dist/types/modes/components/custom-message.d.ts +15 -0
  473. package/dist/types/modes/components/custom-model-preset-wizard.d.ts +12 -0
  474. package/dist/types/modes/components/custom-provider-wizard.d.ts +10 -0
  475. package/dist/types/modes/components/diff.d.ts +11 -0
  476. package/dist/types/modes/components/dynamic-border.d.ts +14 -0
  477. package/dist/types/modes/components/eval-execution.d.ts +23 -0
  478. package/dist/types/modes/components/execution-shared.d.ts +46 -0
  479. package/dist/types/modes/components/extensions/extension-dashboard.d.ts +26 -0
  480. package/dist/types/modes/components/extensions/extension-list.d.ts +39 -0
  481. package/dist/types/modes/components/extensions/index.d.ts +8 -0
  482. package/dist/types/modes/components/extensions/inspector-panel.d.ts +8 -0
  483. package/dist/types/modes/components/extensions/state-manager.d.ts +50 -0
  484. package/dist/types/modes/components/extensions/types.d.ts +151 -0
  485. package/dist/types/modes/components/footer.d.ts +30 -0
  486. package/dist/types/modes/components/history-search.d.ts +7 -0
  487. package/dist/types/modes/components/hook-editor.d.ts +18 -0
  488. package/dist/types/modes/components/hook-input.d.ts +15 -0
  489. package/dist/types/modes/components/hook-message.d.ts +15 -0
  490. package/dist/types/modes/components/hook-selector.d.ts +53 -0
  491. package/dist/types/modes/components/index.d.ts +35 -0
  492. package/dist/types/modes/components/jobs-overlay-model.d.ts +31 -0
  493. package/dist/types/modes/components/jobs-overlay.d.ts +30 -0
  494. package/dist/types/modes/components/keybinding-hints.d.ts +40 -0
  495. package/dist/types/modes/components/login-dialog.d.ts +32 -0
  496. package/dist/types/modes/components/message-frame.d.ts +42 -0
  497. package/dist/types/modes/components/model-selector.d.ts +60 -0
  498. package/dist/types/modes/components/oauth-selector.d.ts +17 -0
  499. package/dist/types/modes/components/plugin-selector.d.ts +26 -0
  500. package/dist/types/modes/components/plugin-settings.d.ts +66 -0
  501. package/dist/types/modes/components/provider-onboarding-selector.d.ts +7 -0
  502. package/dist/types/modes/components/queue-mode-selector.d.ts +9 -0
  503. package/dist/types/modes/components/queued-message-selector.d.ts +12 -0
  504. package/dist/types/modes/components/read-tool-group.d.ts +30 -0
  505. package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +26 -0
  506. package/dist/types/modes/components/session-observer-overlay.d.ts +11 -0
  507. package/dist/types/modes/components/session-selector.d.ts +30 -0
  508. package/dist/types/modes/components/settings-defs.d.ts +50 -0
  509. package/dist/types/modes/components/settings-selector.d.ts +62 -0
  510. package/dist/types/modes/components/show-images-selector.d.ts +9 -0
  511. package/dist/types/modes/components/skill-hud/render.d.ts +2 -0
  512. package/dist/types/modes/components/skill-message.d.ts +10 -0
  513. package/dist/types/modes/components/status-line/context-thresholds.d.ts +4 -0
  514. package/dist/types/modes/components/status-line/git-utils.d.ts +28 -0
  515. package/dist/types/modes/components/status-line/index.d.ts +4 -0
  516. package/dist/types/modes/components/status-line/presets.d.ts +3 -0
  517. package/dist/types/modes/components/status-line/segments.d.ts +5 -0
  518. package/dist/types/modes/components/status-line/separators.d.ts +3 -0
  519. package/dist/types/modes/components/status-line/token-rate.d.ts +10 -0
  520. package/dist/types/modes/components/status-line/types.d.ts +77 -0
  521. package/dist/types/modes/components/status-line.d.ts +103 -0
  522. package/dist/types/modes/components/theme-selector.d.ts +10 -0
  523. package/dist/types/modes/components/thinking-selector.d.ts +10 -0
  524. package/dist/types/modes/components/todo-reminder.d.ts +13 -0
  525. package/dist/types/modes/components/tool-execution.d.ts +54 -0
  526. package/dist/types/modes/components/tree-selector.d.ts +31 -0
  527. package/dist/types/modes/components/ttsr-notification.d.ts +13 -0
  528. package/dist/types/modes/components/two-column-body.d.ts +9 -0
  529. package/dist/types/modes/components/user-message-selector.d.ts +28 -0
  530. package/dist/types/modes/components/user-message.d.ts +7 -0
  531. package/dist/types/modes/components/visual-truncate.d.ts +19 -0
  532. package/dist/types/modes/components/welcome.d.ts +45 -0
  533. package/dist/types/modes/controllers/btw-controller.d.ts +10 -0
  534. package/dist/types/modes/controllers/command-controller-shared.d.ts +47 -0
  535. package/dist/types/modes/controllers/command-controller.d.ts +40 -0
  536. package/dist/types/modes/controllers/event-controller.d.ts +17 -0
  537. package/dist/types/modes/controllers/extension-ui-controller.d.ts +80 -0
  538. package/dist/types/modes/controllers/input-controller.d.ts +42 -0
  539. package/dist/types/modes/controllers/runtime-mcp-command-controller.d.ts +10 -0
  540. package/dist/types/modes/controllers/selector-controller.d.ts +66 -0
  541. package/dist/types/modes/controllers/ssh-command-controller.d.ts +10 -0
  542. package/dist/types/modes/controllers/todo-command-controller.d.ts +7 -0
  543. package/dist/types/modes/emoji-autocomplete.d.ts +16 -0
  544. package/dist/types/modes/index.d.ts +10 -0
  545. package/dist/types/modes/interactive-mode.d.ts +273 -0
  546. package/dist/types/modes/jobs-observer.d.ts +57 -0
  547. package/dist/types/modes/oauth-manual-input.d.ts +8 -0
  548. package/dist/types/modes/print-mode.d.ts +45 -0
  549. package/dist/types/modes/prompt-action-autocomplete.d.ts +50 -0
  550. package/dist/types/modes/rpc/host-tools.d.ts +1 -0
  551. package/dist/types/modes/rpc/host-uris.d.ts +1 -0
  552. package/dist/types/modes/rpc/rpc-client.d.ts +288 -0
  553. package/dist/types/modes/rpc/rpc-mode.d.ts +87 -0
  554. package/dist/types/modes/rpc/rpc-socket-security.d.ts +7 -0
  555. package/dist/types/modes/rpc/rpc-types.d.ts +794 -0
  556. package/dist/types/modes/runtime-init.d.ts +21 -0
  557. package/dist/types/modes/session-observer-registry.d.ts +26 -0
  558. package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +57 -0
  559. package/dist/types/modes/shared/agent-wire/command-contract.d.ts +18 -0
  560. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +37 -0
  561. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +2 -0
  562. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +94 -0
  563. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +103 -0
  564. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +60 -0
  565. package/dist/types/modes/shared/agent-wire/event-observation.d.ts +37 -0
  566. package/dist/types/modes/shared/agent-wire/handshake.d.ts +56 -0
  567. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +16 -0
  568. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +17 -0
  569. package/dist/types/modes/shared/agent-wire/protocol.d.ts +25 -0
  570. package/dist/types/modes/shared/agent-wire/responses.d.ts +4 -0
  571. package/dist/types/modes/shared/agent-wire/scopes.d.ts +18 -0
  572. package/dist/types/modes/shared/agent-wire/session-registry.d.ts +25 -0
  573. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +42 -0
  574. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +27 -0
  575. package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +29 -0
  576. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +68 -0
  577. package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +161 -0
  578. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +82 -0
  579. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +114 -0
  580. package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +39 -0
  581. package/dist/types/modes/shared.d.ts +15 -0
  582. package/dist/types/modes/slash-command-visibility.d.ts +1 -0
  583. package/dist/types/modes/theme/defaults/index.d.ts +652 -0
  584. package/dist/types/modes/theme/mermaid-cache.d.ts +9 -0
  585. package/dist/types/modes/theme/shimmer.d.ts +38 -0
  586. package/dist/types/modes/theme/theme.d.ts +275 -0
  587. package/dist/types/modes/tmux-scroll.d.ts +18 -0
  588. package/dist/types/modes/types.d.ts +289 -0
  589. package/dist/types/modes/utils/abort-message.d.ts +4 -0
  590. package/dist/types/modes/utils/context-usage.d.ts +51 -0
  591. package/dist/types/modes/utils/hotkeys-markdown.d.ts +5 -0
  592. package/dist/types/modes/utils/keybinding-matchers.d.ts +10 -0
  593. package/dist/types/modes/utils/terminal-bell.d.ts +3 -0
  594. package/dist/types/modes/utils/tools-markdown.d.ts +5 -0
  595. package/dist/types/modes/utils/ui-helpers.d.ts +54 -0
  596. package/dist/types/notifications/attachment-registry.d.ts +17 -0
  597. package/dist/types/notifications/chat-adapters.d.ts +9 -0
  598. package/dist/types/notifications/config-commands.d.ts +26 -0
  599. package/dist/types/notifications/config.d.ts +82 -0
  600. package/dist/types/notifications/daemon-paths.d.ts +10 -0
  601. package/dist/types/notifications/engine.d.ts +59 -0
  602. package/dist/types/notifications/helpers.d.ts +55 -0
  603. package/dist/types/notifications/html-format.d.ts +75 -0
  604. package/dist/types/notifications/index.d.ts +179 -0
  605. package/dist/types/notifications/lifecycle-commands.d.ts +68 -0
  606. package/dist/types/notifications/lifecycle-control-runtime.d.ts +98 -0
  607. package/dist/types/notifications/lifecycle-orchestrator.d.ts +144 -0
  608. package/dist/types/notifications/managed-daemon.d.ts +48 -0
  609. package/dist/types/notifications/operator-runtime.d.ts +52 -0
  610. package/dist/types/notifications/rate-limit-pool.d.ts +95 -0
  611. package/dist/types/notifications/recent-activity.d.ts +39 -0
  612. package/dist/types/notifications/telegram-cli.d.ts +19 -0
  613. package/dist/types/notifications/telegram-daemon-cli.d.ts +28 -0
  614. package/dist/types/notifications/telegram-daemon-control.d.ts +64 -0
  615. package/dist/types/notifications/telegram-daemon.d.ts +407 -0
  616. package/dist/types/notifications/telegram-reference.d.ts +112 -0
  617. package/dist/types/notifications/threaded-inbound.d.ts +77 -0
  618. package/dist/types/notifications/threaded-render.d.ts +78 -0
  619. package/dist/types/notifications/topic-registry.d.ts +70 -0
  620. package/dist/types/plan-mode/approved-plan.d.ts +49 -0
  621. package/dist/types/plan-mode/state.d.ts +6 -0
  622. package/dist/types/registry/agent-registry.d.ts +62 -0
  623. package/dist/types/reminders/star-reminder.d.ts +115 -0
  624. package/dist/types/research-plan/index.d.ts +1 -0
  625. package/dist/types/research-plan/ledger.d.ts +33 -0
  626. package/dist/types/rlm/artifacts.d.ts +9 -0
  627. package/dist/types/rlm/complete-research-tool.d.ts +35 -0
  628. package/dist/types/rlm/data-context.d.ts +6 -0
  629. package/dist/types/rlm/index.d.ts +47 -0
  630. package/dist/types/rlm/notebook.d.ts +12 -0
  631. package/dist/types/rlm/preset.d.ts +23 -0
  632. package/dist/types/rlm/python-tool.d.ts +16 -0
  633. package/dist/types/rlm/report.d.ts +14 -0
  634. package/dist/types/rlm/types.d.ts +37 -0
  635. package/dist/types/runtime/process-lifecycle.d.ts +108 -0
  636. package/dist/types/runtime-api-key.d.ts +7 -0
  637. package/dist/types/runtime-mcp/client.d.ts +74 -0
  638. package/dist/types/runtime-mcp/config-writer.d.ts +88 -0
  639. package/dist/types/runtime-mcp/config.d.ts +77 -0
  640. package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +7 -0
  641. package/dist/types/runtime-mcp/index.d.ts +18 -0
  642. package/dist/types/runtime-mcp/json-rpc.d.ts +22 -0
  643. package/dist/types/runtime-mcp/loader.d.ts +45 -0
  644. package/dist/types/runtime-mcp/manager.d.ts +195 -0
  645. package/dist/types/runtime-mcp/oauth-discovery.d.ts +40 -0
  646. package/dist/types/runtime-mcp/oauth-flow.d.ts +59 -0
  647. package/dist/types/runtime-mcp/render.d.ts +25 -0
  648. package/dist/types/runtime-mcp/smithery-auth.d.ts +16 -0
  649. package/dist/types/runtime-mcp/smithery-connect.d.ts +38 -0
  650. package/dist/types/runtime-mcp/smithery-registry.d.ts +51 -0
  651. package/dist/types/runtime-mcp/tool-bridge.d.ts +86 -0
  652. package/dist/types/runtime-mcp/tool-cache.d.ts +8 -0
  653. package/dist/types/runtime-mcp/transports/http.d.ts +36 -0
  654. package/dist/types/runtime-mcp/transports/index.d.ts +5 -0
  655. package/dist/types/runtime-mcp/transports/stdio.d.ts +29 -0
  656. package/dist/types/runtime-mcp/types.d.ts +348 -0
  657. package/dist/types/sdk.d.ts +248 -0
  658. package/dist/types/secrets/index.d.ts +9 -0
  659. package/dist/types/secrets/obfuscator.d.ts +23 -0
  660. package/dist/types/secrets/regex.d.ts +2 -0
  661. package/dist/types/session/agent-session.d.ts +1182 -0
  662. package/dist/types/session/agent-storage.d.ts +101 -0
  663. package/dist/types/session/artifacts.d.ts +64 -0
  664. package/dist/types/session/auth-broker-config.d.ts +13 -0
  665. package/dist/types/session/auth-storage.d.ts +6 -0
  666. package/dist/types/session/blob-store.d.ts +160 -0
  667. package/dist/types/session/client-bridge.d.ts +88 -0
  668. package/dist/types/session/contribution-prep.d.ts +47 -0
  669. package/dist/types/session/file-mention-pruning.d.ts +8 -0
  670. package/dist/types/session/history-storage.d.ts +16 -0
  671. package/dist/types/session/messages.d.ts +169 -0
  672. package/dist/types/session/session-dump-format.d.ts +22 -0
  673. package/dist/types/session/session-manager.d.ts +660 -0
  674. package/dist/types/session/session-storage.d.ts +88 -0
  675. package/dist/types/session/streaming-output.d.ts +209 -0
  676. package/dist/types/session/tool-choice-queue.d.ts +84 -0
  677. package/dist/types/session/yield-queue.d.ts +24 -0
  678. package/dist/types/setup/credential-auto-import.d.ts +63 -0
  679. package/dist/types/setup/credential-import.d.ts +82 -0
  680. package/dist/types/setup/hermes-setup.d.ts +78 -0
  681. package/dist/types/setup/host-plugin-setup.d.ts +39 -0
  682. package/dist/types/setup/model-onboarding-guidance.d.ts +9 -0
  683. package/dist/types/setup/provider-onboarding.d.ts +52 -0
  684. package/dist/types/skc-runtime/cli-write-receipt.d.ts +24 -0
  685. package/dist/types/skc-runtime/deep-interview-ambiguity.d.ts +39 -0
  686. package/dist/types/skc-runtime/deep-interview-recorder.d.ts +114 -0
  687. package/dist/types/skc-runtime/deep-interview-runtime.d.ts +36 -0
  688. package/dist/types/skc-runtime/deep-interview-state.d.ts +127 -0
  689. package/dist/types/skc-runtime/gc-render.d.ts +6 -0
  690. package/dist/types/skc-runtime/gc-runtime.d.ts +134 -0
  691. package/dist/types/skc-runtime/goal-mode-request.d.ts +53 -0
  692. package/dist/types/skc-runtime/launch-tmux.d.ts +78 -0
  693. package/dist/types/skc-runtime/launch-worktree.d.ts +46 -0
  694. package/dist/types/skc-runtime/ledger-event-renderer.d.ts +68 -0
  695. package/dist/types/skc-runtime/psmux-detect.d.ts +78 -0
  696. package/dist/types/skc-runtime/ralplan-runtime.d.ts +26 -0
  697. package/dist/types/skc-runtime/restricted-role-agent-bash.d.ts +3 -0
  698. package/dist/types/skc-runtime/session-layout.d.ts +59 -0
  699. package/dist/types/skc-runtime/session-resolution.d.ts +47 -0
  700. package/dist/types/skc-runtime/session-state-sidecar.d.ts +39 -0
  701. package/dist/types/skc-runtime/state-graph.d.ts +4 -0
  702. package/dist/types/skc-runtime/state-migrations.d.ts +33 -0
  703. package/dist/types/skc-runtime/state-renderer.d.ts +70 -0
  704. package/dist/types/skc-runtime/state-runtime.d.ts +38 -0
  705. package/dist/types/skc-runtime/state-schema.d.ts +319 -0
  706. package/dist/types/skc-runtime/state-validation.d.ts +6 -0
  707. package/dist/types/skc-runtime/state-writer.d.ts +244 -0
  708. package/dist/types/skc-runtime/team-gc.d.ts +7 -0
  709. package/dist/types/skc-runtime/team-runtime.d.ts +355 -0
  710. package/dist/types/skc-runtime/tmux-common.d.ts +104 -0
  711. package/dist/types/skc-runtime/tmux-gc.d.ts +7 -0
  712. package/dist/types/skc-runtime/tmux-sessions.d.ts +62 -0
  713. package/dist/types/skc-runtime/ultragoal-guard.d.ts +93 -0
  714. package/dist/types/skc-runtime/ultragoal-receipt-freshness.d.ts +42 -0
  715. package/dist/types/skc-runtime/ultragoal-runtime.d.ts +410 -0
  716. package/dist/types/skc-runtime/workflow-command-ref.d.ts +43 -0
  717. package/dist/types/skc-runtime/workflow-manifest.d.ts +54 -0
  718. package/dist/types/skill-state/active-state.d.ts +126 -0
  719. package/dist/types/skill-state/canonical-skills.d.ts +3 -0
  720. package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +38 -0
  721. package/dist/types/skill-state/initial-phase.d.ts +12 -0
  722. package/dist/types/skill-state/workflow-hud.d.ts +83 -0
  723. package/dist/types/skill-state/workflow-state-contract.d.ts +57 -0
  724. package/dist/types/skill-state/workflow-state-version.d.ts +3 -0
  725. package/dist/types/slash-commands/acp-builtins.d.ts +18 -0
  726. package/dist/types/slash-commands/builtin-registry.d.ts +24 -0
  727. package/dist/types/slash-commands/helpers/context-report.d.ts +7 -0
  728. package/dist/types/slash-commands/helpers/fast-status-report.d.ts +82 -0
  729. package/dist/types/slash-commands/helpers/format.d.ts +10 -0
  730. package/dist/types/slash-commands/helpers/mcp.d.ts +3 -0
  731. package/dist/types/slash-commands/helpers/parse.d.ts +33 -0
  732. package/dist/types/slash-commands/helpers/ssh.d.ts +3 -0
  733. package/dist/types/slash-commands/helpers/todo.d.ts +3 -0
  734. package/dist/types/slash-commands/helpers/usage-report.d.ts +7 -0
  735. package/dist/types/slash-commands/types.d.ts +120 -0
  736. package/dist/types/ssh/config-writer.d.ts +49 -0
  737. package/dist/types/ssh/connection-manager.d.ts +33 -0
  738. package/dist/types/ssh/ssh-executor.d.ts +37 -0
  739. package/dist/types/ssh/sshfs-mount.d.ts +6 -0
  740. package/dist/types/ssh/utils.d.ts +2 -0
  741. package/dist/types/stt/downloader.d.ts +9 -0
  742. package/dist/types/stt/index.d.ts +3 -0
  743. package/dist/types/stt/recorder.d.ts +13 -0
  744. package/dist/types/stt/setup.d.ts +18 -0
  745. package/dist/types/stt/stt-controller.d.ts +16 -0
  746. package/dist/types/stt/transcriber.d.ts +16 -0
  747. package/dist/types/system-prompt.d.ts +118 -0
  748. package/dist/types/task/agents.d.ts +28 -0
  749. package/dist/types/task/commands.d.ts +35 -0
  750. package/dist/types/task/discovery.d.ts +19 -0
  751. package/dist/types/task/executor.d.ts +124 -0
  752. package/dist/types/task/fork-context-advisory.d.ts +13 -0
  753. package/dist/types/task/fork-context-budget.d.ts +7 -0
  754. package/dist/types/task/id.d.ts +7 -0
  755. package/dist/types/task/index.d.ts +43 -0
  756. package/dist/types/task/name-generator.d.ts +16 -0
  757. package/dist/types/task/output-manager.d.ts +36 -0
  758. package/dist/types/task/parallel.d.ts +34 -0
  759. package/dist/types/task/receipt.d.ts +87 -0
  760. package/dist/types/task/render.d.ts +28 -0
  761. package/dist/types/task/roi-reconciliation.d.ts +27 -0
  762. package/dist/types/task/simple-mode.d.ts +8 -0
  763. package/dist/types/task/skc-command.d.ts +7 -0
  764. package/dist/types/task/spawn-gate.d.ts +29 -0
  765. package/dist/types/task/subprocess-tool-registry.d.ts +72 -0
  766. package/dist/types/task/token-log.d.ts +30 -0
  767. package/dist/types/task/token-log.test.d.ts +1 -0
  768. package/dist/types/task/types.d.ts +508 -0
  769. package/dist/types/task/worktree.d.ts +94 -0
  770. package/dist/types/thinking-metadata.d.ts +16 -0
  771. package/dist/types/thinking.d.ts +22 -0
  772. package/dist/types/tool-discovery/tool-index.d.ts +112 -0
  773. package/dist/types/tools/archive-reader.d.ts +40 -0
  774. package/dist/types/tools/ask-answer-registry.d.ts +13 -0
  775. package/dist/types/tools/ask.d.ts +123 -0
  776. package/dist/types/tools/ast-edit.d.ts +77 -0
  777. package/dist/types/tools/ast-grep.d.ts +69 -0
  778. package/dist/types/tools/auto-generated-guard.d.ts +17 -0
  779. package/dist/types/tools/bash-allowed-prefixes.d.ts +10 -0
  780. package/dist/types/tools/bash-command-fixup.d.ts +11 -0
  781. package/dist/types/tools/bash-interactive.d.ts +16 -0
  782. package/dist/types/tools/bash-interceptor.d.ts +24 -0
  783. package/dist/types/tools/bash-pty-selection.d.ts +7 -0
  784. package/dist/types/tools/bash-skill-urls.d.ts +31 -0
  785. package/dist/types/tools/bash.d.ts +157 -0
  786. package/dist/types/tools/bisect.d.ts +81 -0
  787. package/dist/types/tools/browser/actions.d.ts +54 -0
  788. package/dist/types/tools/browser/attach.d.ts +50 -0
  789. package/dist/types/tools/browser/launch.d.ts +62 -0
  790. package/dist/types/tools/browser/readable.d.ts +17 -0
  791. package/dist/types/tools/browser/registry.d.ts +57 -0
  792. package/dist/types/tools/browser/render.d.ts +53 -0
  793. package/dist/types/tools/browser/tab-protocol.d.ts +144 -0
  794. package/dist/types/tools/browser/tab-supervisor.d.ts +103 -0
  795. package/dist/types/tools/browser/tab-worker-entry.d.ts +1 -0
  796. package/dist/types/tools/browser/tab-worker.d.ts +19 -0
  797. package/dist/types/tools/browser.d.ts +211 -0
  798. package/dist/types/tools/calculator.d.ts +76 -0
  799. package/dist/types/tools/checkpoint.d.ts +63 -0
  800. package/dist/types/tools/composer-bash-policy.d.ts +14 -0
  801. package/dist/types/tools/computer/render.d.ts +17 -0
  802. package/dist/types/tools/computer-gc.d.ts +23 -0
  803. package/dist/types/tools/computer.d.ts +465 -0
  804. package/dist/types/tools/conflict-detect.d.ts +205 -0
  805. package/dist/types/tools/context.d.ts +19 -0
  806. package/dist/types/tools/cron.d.ts +91 -0
  807. package/dist/types/tools/debug.d.ts +209 -0
  808. package/dist/types/tools/eval.d.ts +108 -0
  809. package/dist/types/tools/fetch.d.ts +84 -0
  810. package/dist/types/tools/file-recorder.d.ts +13 -0
  811. package/dist/types/tools/find.d.ts +95 -0
  812. package/dist/types/tools/fs-cache-invalidation.d.ts +15 -0
  813. package/dist/types/tools/gh-format.d.ts +6 -0
  814. package/dist/types/tools/gh-renderer.d.ts +25 -0
  815. package/dist/types/tools/gh.d.ts +356 -0
  816. package/dist/types/tools/github-cache.d.ts +103 -0
  817. package/dist/types/tools/grouped-file-output.d.ts +36 -0
  818. package/dist/types/tools/hindsight-recall.d.ts +21 -0
  819. package/dist/types/tools/hindsight-reflect.d.ts +23 -0
  820. package/dist/types/tools/hindsight-retain.d.ts +27 -0
  821. package/dist/types/tools/image-gen.d.ts +79 -0
  822. package/dist/types/tools/index.d.ts +318 -0
  823. package/dist/types/tools/irc.d.ts +79 -0
  824. package/dist/types/tools/job.d.ts +78 -0
  825. package/dist/types/tools/json-tree.d.ts +23 -0
  826. package/dist/types/tools/jtd-to-json-schema.d.ts +29 -0
  827. package/dist/types/tools/jtd-to-typescript.d.ts +26 -0
  828. package/dist/types/tools/jtd-utils.d.ts +42 -0
  829. package/dist/types/tools/list-limit.d.ts +12 -0
  830. package/dist/types/tools/match-line-format.d.ts +11 -0
  831. package/dist/types/tools/monitor.d.ts +54 -0
  832. package/dist/types/tools/output-meta.d.ts +204 -0
  833. package/dist/types/tools/path-utils.d.ts +147 -0
  834. package/dist/types/tools/plan-mode-guard.d.ts +18 -0
  835. package/dist/types/tools/read.d.ts +85 -0
  836. package/dist/types/tools/recipe/index.d.ts +45 -0
  837. package/dist/types/tools/recipe/render.d.ts +36 -0
  838. package/dist/types/tools/recipe/runner.d.ts +60 -0
  839. package/dist/types/tools/recipe/runners/cargo.d.ts +16 -0
  840. package/dist/types/tools/recipe/runners/index.d.ts +2 -0
  841. package/dist/types/tools/recipe/runners/just.d.ts +2 -0
  842. package/dist/types/tools/recipe/runners/make.d.ts +2 -0
  843. package/dist/types/tools/recipe/runners/pkg.d.ts +2 -0
  844. package/dist/types/tools/recipe/runners/task.d.ts +2 -0
  845. package/dist/types/tools/render-mermaid.d.ts +37 -0
  846. package/dist/types/tools/render-utils.d.ts +158 -0
  847. package/dist/types/tools/renderers.d.ts +26 -0
  848. package/dist/types/tools/resolve.d.ts +80 -0
  849. package/dist/types/tools/resource-gc.d.ts +54 -0
  850. package/dist/types/tools/review.d.ts +63 -0
  851. package/dist/types/tools/search-tool-bm25.d.ts +65 -0
  852. package/dist/types/tools/search.d.ts +93 -0
  853. package/dist/types/tools/skill.d.ts +47 -0
  854. package/dist/types/tools/sqlite-reader.d.ts +94 -0
  855. package/dist/types/tools/ssh.d.ts +67 -0
  856. package/dist/types/tools/subagent-render.d.ts +31 -0
  857. package/dist/types/tools/subagent.d.ts +117 -0
  858. package/dist/types/tools/telegram-send.d.ts +32 -0
  859. package/dist/types/tools/todo-write.d.ts +120 -0
  860. package/dist/types/tools/tool-errors.d.ts +33 -0
  861. package/dist/types/tools/tool-result.d.ts +30 -0
  862. package/dist/types/tools/tool-timeouts.d.ts +56 -0
  863. package/dist/types/tools/ultragoal-ask-guard.d.ts +12 -0
  864. package/dist/types/tools/vim.d.ts +58 -0
  865. package/dist/types/tools/write.d.ts +59 -0
  866. package/dist/types/tools/yield.d.ts +25 -0
  867. package/dist/types/tui/code-cell.d.ts +32 -0
  868. package/dist/types/tui/file-list.d.ts +22 -0
  869. package/dist/types/tui/hyperlink.d.ts +42 -0
  870. package/dist/types/tui/index.d.ts +11 -0
  871. package/dist/types/tui/output-block.d.ts +28 -0
  872. package/dist/types/tui/status-line.d.ts +18 -0
  873. package/dist/types/tui/tree-list.d.ts +19 -0
  874. package/dist/types/tui/types.d.ts +13 -0
  875. package/dist/types/tui/utils.d.ts +36 -0
  876. package/dist/types/utils/changelog.d.ts +37 -0
  877. package/dist/types/utils/clipboard.d.ts +22 -0
  878. package/dist/types/utils/cmux-workspace.d.ts +52 -0
  879. package/dist/types/utils/command-args.d.ts +9 -0
  880. package/dist/types/utils/commit-message-generator.d.ts +7 -0
  881. package/dist/types/utils/edit-mode.d.ts +13 -0
  882. package/dist/types/utils/event-bus.d.ts +6 -0
  883. package/dist/types/utils/external-editor.d.ts +17 -0
  884. package/dist/types/utils/file-display-mode.d.ts +27 -0
  885. package/dist/types/utils/file-mentions.d.ts +25 -0
  886. package/dist/types/utils/git.d.ts +393 -0
  887. package/dist/types/utils/image-loading.d.ts +26 -0
  888. package/dist/types/utils/image-resize.d.ts +39 -0
  889. package/dist/types/utils/lang-from-path.d.ts +8 -0
  890. package/dist/types/utils/markit.d.ts +7 -0
  891. package/dist/types/utils/open.d.ts +2 -0
  892. package/dist/types/utils/session-color.d.ts +10 -0
  893. package/dist/types/utils/shell-snapshot.d.ts +5 -0
  894. package/dist/types/utils/sixel.d.ts +21 -0
  895. package/dist/types/utils/title-generator.d.ts +31 -0
  896. package/dist/types/utils/tool-choice.d.ts +20 -0
  897. package/dist/types/utils/tools-manager.d.ts +9 -0
  898. package/dist/types/vim/buffer.d.ts +41 -0
  899. package/dist/types/vim/commands.d.ts +6 -0
  900. package/dist/types/vim/engine.d.ts +47 -0
  901. package/dist/types/vim/parser.d.ts +3 -0
  902. package/dist/types/vim/render.d.ts +25 -0
  903. package/dist/types/vim/types.d.ts +182 -0
  904. package/dist/types/web/insane/bridge.d.ts +103 -0
  905. package/dist/types/web/insane/url-guard.d.ts +25 -0
  906. package/dist/types/web/kagi.d.ts +23 -0
  907. package/dist/types/web/parallel.d.ts +58 -0
  908. package/dist/types/web/scrapers/artifacthub.d.ts +6 -0
  909. package/dist/types/web/scrapers/arxiv.d.ts +5 -0
  910. package/dist/types/web/scrapers/aur.d.ts +5 -0
  911. package/dist/types/web/scrapers/biorxiv.d.ts +5 -0
  912. package/dist/types/web/scrapers/bluesky.d.ts +5 -0
  913. package/dist/types/web/scrapers/brew.d.ts +5 -0
  914. package/dist/types/web/scrapers/cheatsh.d.ts +8 -0
  915. package/dist/types/web/scrapers/chocolatey.d.ts +5 -0
  916. package/dist/types/web/scrapers/choosealicense.d.ts +2 -0
  917. package/dist/types/web/scrapers/cisa-kev.d.ts +5 -0
  918. package/dist/types/web/scrapers/clojars.d.ts +5 -0
  919. package/dist/types/web/scrapers/coingecko.d.ts +5 -0
  920. package/dist/types/web/scrapers/crates-io.d.ts +5 -0
  921. package/dist/types/web/scrapers/crossref.d.ts +2 -0
  922. package/dist/types/web/scrapers/devto.d.ts +5 -0
  923. package/dist/types/web/scrapers/discogs.d.ts +8 -0
  924. package/dist/types/web/scrapers/discourse.d.ts +5 -0
  925. package/dist/types/web/scrapers/dockerhub.d.ts +5 -0
  926. package/dist/types/web/scrapers/docs-rs.d.ts +2 -0
  927. package/dist/types/web/scrapers/fdroid.d.ts +5 -0
  928. package/dist/types/web/scrapers/firefox-addons.d.ts +2 -0
  929. package/dist/types/web/scrapers/flathub.d.ts +2 -0
  930. package/dist/types/web/scrapers/github-gist.d.ts +5 -0
  931. package/dist/types/web/scrapers/github.d.ts +12 -0
  932. package/dist/types/web/scrapers/gitlab.d.ts +5 -0
  933. package/dist/types/web/scrapers/go-pkg.d.ts +5 -0
  934. package/dist/types/web/scrapers/hackage.d.ts +5 -0
  935. package/dist/types/web/scrapers/hackernews.d.ts +2 -0
  936. package/dist/types/web/scrapers/hex.d.ts +5 -0
  937. package/dist/types/web/scrapers/huggingface.d.ts +2 -0
  938. package/dist/types/web/scrapers/iacr.d.ts +5 -0
  939. package/dist/types/web/scrapers/index.d.ts +84 -0
  940. package/dist/types/web/scrapers/jetbrains-marketplace.d.ts +2 -0
  941. package/dist/types/web/scrapers/lemmy.d.ts +2 -0
  942. package/dist/types/web/scrapers/lobsters.d.ts +5 -0
  943. package/dist/types/web/scrapers/mastodon.d.ts +5 -0
  944. package/dist/types/web/scrapers/maven.d.ts +6 -0
  945. package/dist/types/web/scrapers/mdn.d.ts +2 -0
  946. package/dist/types/web/scrapers/metacpan.d.ts +5 -0
  947. package/dist/types/web/scrapers/musicbrainz.d.ts +5 -0
  948. package/dist/types/web/scrapers/npm.d.ts +5 -0
  949. package/dist/types/web/scrapers/nuget.d.ts +5 -0
  950. package/dist/types/web/scrapers/nvd.d.ts +5 -0
  951. package/dist/types/web/scrapers/ollama.d.ts +2 -0
  952. package/dist/types/web/scrapers/open-vsx.d.ts +5 -0
  953. package/dist/types/web/scrapers/opencorporates.d.ts +5 -0
  954. package/dist/types/web/scrapers/openlibrary.d.ts +5 -0
  955. package/dist/types/web/scrapers/orcid.d.ts +5 -0
  956. package/dist/types/web/scrapers/osv.d.ts +5 -0
  957. package/dist/types/web/scrapers/packagist.d.ts +5 -0
  958. package/dist/types/web/scrapers/pub-dev.d.ts +5 -0
  959. package/dist/types/web/scrapers/pubmed.d.ts +5 -0
  960. package/dist/types/web/scrapers/pypi.d.ts +5 -0
  961. package/dist/types/web/scrapers/rawg.d.ts +2 -0
  962. package/dist/types/web/scrapers/readthedocs.d.ts +2 -0
  963. package/dist/types/web/scrapers/reddit.d.ts +5 -0
  964. package/dist/types/web/scrapers/repology.d.ts +5 -0
  965. package/dist/types/web/scrapers/rfc.d.ts +5 -0
  966. package/dist/types/web/scrapers/rubygems.d.ts +5 -0
  967. package/dist/types/web/scrapers/searchcode.d.ts +2 -0
  968. package/dist/types/web/scrapers/sec-edgar.d.ts +5 -0
  969. package/dist/types/web/scrapers/semantic-scholar.d.ts +2 -0
  970. package/dist/types/web/scrapers/snapcraft.d.ts +2 -0
  971. package/dist/types/web/scrapers/sourcegraph.d.ts +2 -0
  972. package/dist/types/web/scrapers/spdx.d.ts +5 -0
  973. package/dist/types/web/scrapers/spotify.d.ts +8 -0
  974. package/dist/types/web/scrapers/stackoverflow.d.ts +6 -0
  975. package/dist/types/web/scrapers/terraform.d.ts +5 -0
  976. package/dist/types/web/scrapers/tldr.d.ts +7 -0
  977. package/dist/types/web/scrapers/twitter.d.ts +5 -0
  978. package/dist/types/web/scrapers/types.d.ts +83 -0
  979. package/dist/types/web/scrapers/utils.d.ts +32 -0
  980. package/dist/types/web/scrapers/vimeo.d.ts +5 -0
  981. package/dist/types/web/scrapers/vscode-marketplace.d.ts +5 -0
  982. package/dist/types/web/scrapers/w3c.d.ts +2 -0
  983. package/dist/types/web/scrapers/wikidata.d.ts +5 -0
  984. package/dist/types/web/scrapers/wikipedia.d.ts +5 -0
  985. package/dist/types/web/scrapers/youtube.d.ts +13 -0
  986. package/dist/types/web/search/index.d.ts +118 -0
  987. package/dist/types/web/search/provider.d.ts +55 -0
  988. package/dist/types/web/search/providers/anthropic.d.ts +32 -0
  989. package/dist/types/web/search/providers/base.d.ts +90 -0
  990. package/dist/types/web/search/providers/brave.d.ts +27 -0
  991. package/dist/types/web/search/providers/codex.d.ts +35 -0
  992. package/dist/types/web/search/providers/duckduckgo.d.ts +57 -0
  993. package/dist/types/web/search/providers/exa.d.ts +52 -0
  994. package/dist/types/web/search/providers/gemini.d.ts +57 -0
  995. package/dist/types/web/search/providers/insane.d.ts +53 -0
  996. package/dist/types/web/search/providers/jina.d.ts +26 -0
  997. package/dist/types/web/search/providers/kagi.d.ts +24 -0
  998. package/dist/types/web/search/providers/kimi.d.ts +27 -0
  999. package/dist/types/web/search/providers/openai-compatible.d.ts +9 -0
  1000. package/dist/types/web/search/providers/parallel.d.ts +15 -0
  1001. package/dist/types/web/search/providers/perplexity.d.ts +38 -0
  1002. package/dist/types/web/search/providers/searxng.d.ts +44 -0
  1003. package/dist/types/web/search/providers/synthetic.d.ts +21 -0
  1004. package/dist/types/web/search/providers/tavily.d.ts +29 -0
  1005. package/dist/types/web/search/providers/text-citations.d.ts +23 -0
  1006. package/dist/types/web/search/providers/utils.d.ts +88 -0
  1007. package/dist/types/web/search/providers/xai.d.ts +64 -0
  1008. package/dist/types/web/search/providers/zai.d.ts +28 -0
  1009. package/dist/types/web/search/render.d.ts +36 -0
  1010. package/dist/types/web/search/types.d.ts +372 -0
  1011. package/dist/types/web/search/utils.d.ts +4 -0
  1012. package/dist/types/workflow/workflow-intent-diff.d.ts +25 -0
  1013. package/dist/types/workflow/workflow-intent-report-consumer.d.ts +50 -0
  1014. package/dist/types/workflow/workflow-intent-report-schema.d.ts +2 -0
  1015. package/dist/types/workflow/workflow-intent-report.d.ts +48 -0
  1016. package/dist/types/workspace-tree.d.ts +42 -0
  1017. package/package.json +118 -117
  1018. package/scripts/build-binary.ts +3 -0
  1019. package/src/append-only-mode.ts +58 -0
  1020. package/src/autoresearch/prompt.md +1 -1
  1021. package/src/autoresearch/tools/log-experiment.ts +1 -1
  1022. package/src/capability/mcp.ts +2 -0
  1023. package/src/capability/rule.ts +9 -0
  1024. package/src/cli/completion-cli.ts +234 -0
  1025. package/src/cli/config-cli.ts +61 -9
  1026. package/src/cli/fast-help.ts +1 -0
  1027. package/src/cli/fixture-report.test.ts +230 -0
  1028. package/src/cli/fixture-report.ts +171 -0
  1029. package/src/cli/nofile-limit.ts +48 -0
  1030. package/src/cli/notify-cli.ts +92 -8
  1031. package/src/cli/telegram-cli.ts +156 -0
  1032. package/src/cli/update-cli.ts +109 -9
  1033. package/src/cli/web-search-cli.ts +5 -7
  1034. package/src/cli.ts +31 -2
  1035. package/src/commands/completion.ts +84 -0
  1036. package/src/commands/config.ts +2 -0
  1037. package/src/commands/contribution-prep.ts +1 -1
  1038. package/src/commands/deep-interview.ts +2 -1
  1039. package/src/commands/launch.ts +1 -1
  1040. package/src/commands/ralplan.ts +1 -0
  1041. package/src/commands/telegram.ts +47 -0
  1042. package/src/config/file-lock.ts +73 -34
  1043. package/src/config/keybindings.ts +17 -8
  1044. package/src/config/mcp-schema.json +4 -0
  1045. package/src/config/model-profile-activation.ts +65 -0
  1046. package/src/config/model-profiles.ts +31 -2
  1047. package/src/config/settings-schema.ts +279 -7
  1048. package/src/config/settings.ts +22 -0
  1049. package/src/config/telegram-autostart.ts +107 -0
  1050. package/src/config/telegram-env-bridge.ts +92 -0
  1051. package/src/defaults/skc/skills/ralplan/SKILL.md +29 -20
  1052. package/src/defaults/skc/skills/team/SKILL.md +17 -14
  1053. package/src/defaults/skc/skills/ultragoal/SKILL.md +95 -115
  1054. package/src/defaults/skc/skills/ultragoal/pipeline-validation-contracts.md +30 -0
  1055. package/src/defaults/skc-defaults.ts +25 -0
  1056. package/src/discovery/builtin.ts +12 -0
  1057. package/src/discovery/cursor.ts +5 -84
  1058. package/src/discovery/gemini.ts +3 -89
  1059. package/src/discovery/helpers.ts +10 -0
  1060. package/src/discovery/index.ts +5 -1
  1061. package/src/discovery/mcp-json.ts +11 -0
  1062. package/src/discovery/opencode.ts +5 -122
  1063. package/src/discovery/windsurf.ts +4 -82
  1064. package/src/edit/read-file.ts +9 -1
  1065. package/src/export/html/template.generated.ts +1 -1
  1066. package/src/export/html/template.js +60 -2
  1067. package/src/export/ttsr.ts +96 -18
  1068. package/src/extensibility/extensions/runner.ts +185 -220
  1069. package/src/extensibility/extensions/types.ts +20 -0
  1070. package/src/extensibility/skc-plugins/runtime-adapters.ts +156 -44
  1071. package/src/extensibility/skills.ts +30 -2
  1072. package/src/goals/runtime.ts +10 -2
  1073. package/src/hindsight/backend.ts +1 -3
  1074. package/src/hooks/native-skill-hook.ts +124 -4
  1075. package/src/hooks/skill-state.ts +33 -73
  1076. package/src/i18n/messages/de.ts +1 -0
  1077. package/src/i18n/messages/en.ts +1 -0
  1078. package/src/i18n/messages/es.ts +1 -0
  1079. package/src/i18n/messages/fr.ts +1 -0
  1080. package/src/i18n/messages/ja.settings.ts +28 -0
  1081. package/src/i18n/messages/ja.ts +1 -0
  1082. package/src/i18n/messages/ko.settings.ts +28 -0
  1083. package/src/i18n/messages/ko.ts +1 -0
  1084. package/src/i18n/messages/zh.settings.ts +28 -0
  1085. package/src/i18n/messages/zh.ts +1 -0
  1086. package/src/internal-urls/docs-index.generated.ts +21 -8
  1087. package/src/main.ts +100 -45
  1088. package/src/memories/index.ts +12 -1
  1089. package/src/migrate/executor.ts +23 -6
  1090. package/src/modes/acp/acp-agent.ts +7 -6
  1091. package/src/modes/components/agent-dashboard.ts +1 -34
  1092. package/src/modes/components/assistant-message.ts +241 -82
  1093. package/src/modes/components/custom-editor.ts +27 -0
  1094. package/src/modes/components/extensions/extension-dashboard.ts +2 -48
  1095. package/src/modes/components/hook-selector.ts +21 -3
  1096. package/src/modes/components/model-selector.ts +118 -15
  1097. package/src/modes/components/queued-message-selector.ts +92 -0
  1098. package/src/modes/components/session-selector.ts +19 -9
  1099. package/src/modes/components/settings-selector.ts +64 -5
  1100. package/src/modes/components/skill-message.ts +18 -10
  1101. package/src/modes/components/status-line/presets.ts +11 -0
  1102. package/src/modes/components/status-line/segments.ts +10 -2
  1103. package/src/modes/components/status-line.ts +341 -99
  1104. package/src/modes/components/tool-execution.ts +44 -19
  1105. package/src/modes/components/tree-selector.ts +28 -8
  1106. package/src/modes/components/two-column-body.ts +36 -0
  1107. package/src/modes/components/welcome.ts +335 -63
  1108. package/src/modes/controllers/command-controller.ts +66 -6
  1109. package/src/modes/controllers/event-controller.ts +70 -47
  1110. package/src/modes/controllers/extension-ui-controller.ts +22 -12
  1111. package/src/modes/controllers/input-controller.ts +367 -53
  1112. package/src/modes/controllers/selector-controller.ts +152 -52
  1113. package/src/modes/interactive-mode.ts +80 -39
  1114. package/src/modes/print-mode.ts +43 -4
  1115. package/src/modes/prompt-action-autocomplete.ts +47 -14
  1116. package/src/modes/rpc/rpc-mode.ts +29 -3
  1117. package/src/modes/rpc/rpc-types.ts +10 -0
  1118. package/src/modes/shared/agent-wire/command-validation.ts +4 -0
  1119. package/src/modes/shared/agent-wire/deep-interview-gate.ts +72 -15
  1120. package/src/modes/shared/agent-wire/event-contract.ts +22 -0
  1121. package/src/modes/shared/agent-wire/event-envelope.ts +82 -0
  1122. package/src/modes/shared/agent-wire/scopes.ts +1 -0
  1123. package/src/modes/shared/agent-wire/workflow-gate-schema.ts +20 -0
  1124. package/src/modes/slash-command-visibility.ts +9 -0
  1125. package/src/modes/theme/theme.ts +5 -1
  1126. package/src/modes/types.ts +9 -1
  1127. package/src/modes/utils/hotkeys-markdown.ts +6 -2
  1128. package/src/modes/utils/ui-helpers.ts +95 -9
  1129. package/src/notifications/config.ts +25 -5
  1130. package/src/notifications/daemon-paths.ts +2 -0
  1131. package/src/notifications/html-format.ts +75 -1
  1132. package/src/notifications/index.ts +149 -16
  1133. package/src/notifications/lifecycle-commands.ts +37 -7
  1134. package/src/notifications/lifecycle-control-runtime.ts +12 -3
  1135. package/src/notifications/lifecycle-orchestrator.ts +19 -6
  1136. package/src/notifications/recent-activity.ts +32 -8
  1137. package/src/notifications/telegram-daemon-cli.ts +13 -4
  1138. package/src/notifications/telegram-daemon-control.ts +14 -3
  1139. package/src/notifications/telegram-daemon.ts +382 -93
  1140. package/src/notifications/telegram-reference.ts +36 -30
  1141. package/src/notifications/threaded-render.ts +31 -7
  1142. package/src/prompts/agents/architect.md +24 -12
  1143. package/src/prompts/agents/critic.md +27 -20
  1144. package/src/prompts/agents/executor.md +14 -11
  1145. package/src/prompts/agents/planner.md +24 -14
  1146. package/src/prompts/ci-green-request.md +3 -8
  1147. package/src/prompts/goals/goal-continuation.md +0 -5
  1148. package/src/prompts/goals/goal-mode-active.md +0 -5
  1149. package/src/prompts/system/agent-creation-architect.md +2 -2
  1150. package/src/prompts/system/plan-mode-active.md +1 -1
  1151. package/src/prompts/system/plan-mode-subagent.md +3 -3
  1152. package/src/prompts/system/project-prompt.md +0 -13
  1153. package/src/prompts/system/subagent-system-prompt.md +3 -2
  1154. package/src/prompts/system/system-prompt.md +42 -12
  1155. package/src/prompts/system/volatile-project-context.md +10 -0
  1156. package/src/prompts/system/web-search.md +4 -7
  1157. package/src/prompts/tools/apply-patch.md +6 -0
  1158. package/src/prompts/tools/ast-edit.md +1 -0
  1159. package/src/prompts/tools/bash.md +2 -2
  1160. package/src/prompts/tools/bisect.md +22 -0
  1161. package/src/prompts/tools/browser.md +1 -1
  1162. package/src/prompts/tools/computer.md +2 -2
  1163. package/src/prompts/tools/cron.md +0 -2
  1164. package/src/prompts/tools/eval.md +2 -2
  1165. package/src/prompts/tools/find.md +1 -1
  1166. package/src/prompts/tools/github.md +6 -6
  1167. package/src/prompts/tools/goal.md +1 -3
  1168. package/src/prompts/tools/image-gen.md +12 -5
  1169. package/src/prompts/tools/irc.md +5 -4
  1170. package/src/prompts/tools/job.md +2 -2
  1171. package/src/prompts/tools/lsp.md +1 -1
  1172. package/src/prompts/tools/monitor.md +2 -2
  1173. package/src/prompts/tools/patch.md +2 -2
  1174. package/src/prompts/tools/replace.md +2 -21
  1175. package/src/prompts/tools/rewind.md +1 -1
  1176. package/src/prompts/tools/search-tool-bm25.md +1 -11
  1177. package/src/prompts/tools/search.md +1 -1
  1178. package/src/prompts/tools/skill.md +3 -2
  1179. package/src/prompts/tools/ssh.md +2 -1
  1180. package/src/prompts/tools/subagent.md +2 -2
  1181. package/src/prompts/tools/task.md +4 -5
  1182. package/src/prompts/tools/todo-write.md +1 -1
  1183. package/src/prompts/tools/vim.md +1 -0
  1184. package/src/prompts/tools/web-search.md +2 -0
  1185. package/src/prompts/tools/write.md +8 -2
  1186. package/src/runtime-api-key.ts +16 -0
  1187. package/src/runtime-mcp/config-writer.ts +28 -0
  1188. package/src/runtime-mcp/config.ts +7 -0
  1189. package/src/runtime-mcp/loader.ts +3 -0
  1190. package/src/runtime-mcp/manager.ts +3 -0
  1191. package/src/runtime-mcp/types.ts +6 -0
  1192. package/src/sdk.ts +62 -39
  1193. package/src/session/agent-session.ts +1041 -150
  1194. package/src/session/agent-storage.ts +4 -0
  1195. package/src/session/file-mention-pruning.ts +64 -0
  1196. package/src/session/messages.ts +4 -0
  1197. package/src/session/session-manager.ts +161 -22
  1198. package/src/skc-runtime/deep-interview-ambiguity.ts +206 -0
  1199. package/src/skc-runtime/deep-interview-recorder.ts +62 -8
  1200. package/src/skc-runtime/deep-interview-state.ts +44 -2
  1201. package/src/skc-runtime/ralplan-runtime.ts +22 -6
  1202. package/src/skc-runtime/restricted-role-agent-bash.ts +1 -0
  1203. package/src/skc-runtime/session-state-sidecar.ts +413 -27
  1204. package/src/skc-runtime/state-runtime.ts +20 -7
  1205. package/src/skc-runtime/state-writer.ts +20 -5
  1206. package/src/skc-runtime/ultragoal-guard.ts +205 -90
  1207. package/src/skc-runtime/ultragoal-receipt-freshness.ts +315 -0
  1208. package/src/skc-runtime/ultragoal-runtime.ts +1671 -275
  1209. package/src/skc-runtime/workflow-manifest.generated.json +108 -5
  1210. package/src/skc-runtime/workflow-manifest.ts +74 -2
  1211. package/src/skill-state/active-state.ts +141 -5
  1212. package/src/skill-state/deep-interview-mutation-guard.ts +67 -3
  1213. package/src/slash-commands/builtin-registry.ts +248 -81
  1214. package/src/slash-commands/types.ts +2 -0
  1215. package/src/system-prompt.ts +64 -15
  1216. package/src/task/executor.ts +137 -24
  1217. package/src/task/fork-context-advisory.ts +2 -7
  1218. package/src/task/fork-context-budget.ts +9 -0
  1219. package/src/task/index.ts +13 -6
  1220. package/src/task/output-manager.ts +20 -8
  1221. package/src/task/receipt.ts +26 -7
  1222. package/src/task/token-log.test.ts +188 -0
  1223. package/src/task/token-log.ts +179 -0
  1224. package/src/tools/ast-grep.ts +10 -7
  1225. package/src/tools/bash.ts +39 -14
  1226. package/src/tools/bisect.ts +367 -0
  1227. package/src/tools/computer.ts +246 -43
  1228. package/src/tools/index.ts +11 -1
  1229. package/src/tools/output-meta.ts +116 -4
  1230. package/src/tools/search.ts +8 -2
  1231. package/src/tools/skill.ts +16 -1
  1232. package/src/tools/telegram-send.ts +6 -0
  1233. package/src/tools/ultragoal-ask-guard.ts +39 -5
  1234. package/src/utils/cmux-workspace.ts +233 -0
  1235. package/src/utils/file-mentions.ts +39 -7
  1236. package/src/utils/git.ts +73 -0
  1237. package/src/utils/title-generator.ts +2 -0
  1238. package/src/web/kagi.ts +1 -1
  1239. package/src/web/parallel.ts +2 -2
  1240. package/src/web/scrapers/youtube.ts +24 -12
  1241. package/src/web/search/index.ts +137 -52
  1242. package/src/web/search/provider.ts +80 -0
  1243. package/src/web/search/providers/anthropic.ts +1 -1
  1244. package/src/web/search/providers/brave.ts +1 -1
  1245. package/src/web/search/providers/codex.ts +1 -1
  1246. package/src/web/search/providers/duckduckgo.ts +1 -1
  1247. package/src/web/search/providers/exa.ts +1 -1
  1248. package/src/web/search/providers/gemini.ts +7 -3
  1249. package/src/web/search/providers/jina.ts +1 -1
  1250. package/src/web/search/providers/kimi.ts +6 -1
  1251. package/src/web/search/providers/openai-compatible.ts +1 -1
  1252. package/src/web/search/providers/parallel.ts +1 -1
  1253. package/src/web/search/providers/perplexity.ts +2 -2
  1254. package/src/web/search/providers/searxng.ts +1 -1
  1255. package/src/web/search/providers/synthetic.ts +1 -1
  1256. package/src/web/search/providers/tavily.ts +1 -1
  1257. package/src/web/search/providers/utils.ts +67 -17
  1258. package/src/web/search/providers/xai.ts +1 -1
  1259. package/src/web/search/providers/zai.ts +1 -1
  1260. package/src/web/search/render.ts +3 -0
  1261. package/src/workflow/workflow-intent-diff.ts +222 -0
  1262. package/src/workflow/workflow-intent-report-consumer.ts +221 -0
  1263. package/src/workflow/workflow-intent-report-schema.ts +129 -0
  1264. package/src/workflow/workflow-intent-report.ts +135 -0
@@ -2,14 +2,27 @@ import * as crypto from "node:crypto";
2
2
  import * as os from "node:os";
3
3
  import * as path from "node:path";
4
4
  import { inflateSync } from "node:zlib";
5
- import { normalizeGoal } from "../goals/state";
6
- import { buildSessionContext, loadEntriesFromFile, type SessionEntry } from "../session/session-manager";
7
5
  import type { WorkflowHudSummary } from "../skill-state/active-state";
8
6
  import { buildUltragoalHudSummary as buildWorkflowUltragoalHudSummary } from "../skill-state/workflow-hud";
9
7
  import { renderCliWriteReceipt } from "./cli-write-receipt";
10
- import { DEFAULT_ULTRAGOAL_OBJECTIVE, SKC_SESSION_FILE_ENV } from "./goal-mode-request";
8
+ import { DEFAULT_ULTRAGOAL_OBJECTIVE } from "./goal-mode-request";
9
+ import {
10
+ computeUltragoalPlanGeneration,
11
+ findFreshBatchCloseReceipt,
12
+ requiredUltragoalGoals,
13
+ validateDeferredMemberReceiptFresh,
14
+ validateReceiptFreshBase,
15
+ } from "./ultragoal-receipt-freshness";
16
+
17
+ export { computeUltragoalPlanGeneration, receiptRelevantGoals } from "./ultragoal-receipt-freshness";
18
+
11
19
  import { sessionUltragoalDir, skcRoot } from "./session-layout";
12
- import { resolveSkcSessionForRead, resolveSkcSessionForWrite, writeSessionActivityMarker } from "./session-resolution";
20
+ import {
21
+ resolveSkcSessionForRead,
22
+ resolveSkcSessionForWrite,
23
+ SessionResolutionError,
24
+ writeSessionActivityMarker,
25
+ } from "./session-resolution";
13
26
  import { renderUltragoalStatusMarkdown } from "./state-renderer";
14
27
  import { reconcileWorkflowSkillState } from "./state-runtime";
15
28
  import {
@@ -30,6 +43,96 @@ export type UltragoalGoalStatus =
30
43
  | "review_blocked"
31
44
  | "superseded";
32
45
 
46
+ export type UltragoalPipelineMetadataSource = "original_plan_graph" | "legacy_brief_only" | "steering";
47
+ export type UltragoalPipelineOverlapState =
48
+ | "none"
49
+ | "open"
50
+ | "joined_clean"
51
+ | "blocked_disjoint_continue"
52
+ | "quarantine_required"
53
+ | "rebaseline_complete";
54
+
55
+ export interface UltragoalPipelineTargets extends JsonObject {
56
+ files: string[];
57
+ surfaces: string[];
58
+ }
59
+
60
+ export interface UltragoalPipelineMetadata extends JsonObject {
61
+ schemaVersion: 1;
62
+ goalId: string;
63
+ source: UltragoalPipelineMetadataSource;
64
+ eligible: boolean;
65
+ dependsOn: string[];
66
+ independentOf: string[];
67
+ targets: UltragoalPipelineTargets;
68
+ metadataHash: string;
69
+ overlap: UltragoalPipelineOverlapState;
70
+ overlapId?: string;
71
+ priorGoalId?: string;
72
+ nextGoalId?: string;
73
+ blockerFootprints?: UltragoalPipelineTargets[];
74
+ invalidationReason?: string;
75
+ invalidatedAt?: string;
76
+ }
77
+
78
+ export interface UltragoalGoalMetadataInput {
79
+ schemaVersion: 1;
80
+ goalId: string;
81
+ source: UltragoalPipelineMetadataSource;
82
+ dependsOn?: string[];
83
+ independentOf?: string[];
84
+ targets?: Partial<UltragoalPipelineTargets>;
85
+ }
86
+
87
+ export interface UltragoalValidationBatchMetadata extends JsonObject {
88
+ schemaVersion: 1;
89
+ batchId: string;
90
+ memberIds: string[];
91
+ finalGoalId: string;
92
+ mode: "aggregate-only";
93
+ metadataHash: string;
94
+ }
95
+
96
+ export interface UltragoalValidationBatchInput {
97
+ schemaVersion: 1;
98
+ batchId: string;
99
+ memberIds: string[];
100
+ finalGoalId: string;
101
+ }
102
+
103
+ export interface UltragoalPipelineOverlapHandles extends JsonObject {
104
+ review: JsonObject;
105
+ qa: JsonObject;
106
+ implementation: JsonObject;
107
+ }
108
+
109
+ export interface UltragoalPipelineOverlapReceipt extends JsonObject {
110
+ ok: true;
111
+ event: string;
112
+ overlap_id: string;
113
+ prior_goal_id: string;
114
+ next_goal_id?: string;
115
+ goal_id?: string;
116
+ status?: UltragoalPipelineOverlapState;
117
+ next_goal_status?: UltragoalGoalStatus;
118
+ goals_path: string;
119
+ ledger_path: string;
120
+ }
121
+
122
+ export type UltragoalPipelineLedgerEventName =
123
+ | "pipeline_overlap_started"
124
+ | "pipeline_overlap_joined"
125
+ | "pipeline_overlap_blocked"
126
+ | "pipeline_overlap_quarantined"
127
+ | "pipeline_overlap_rebaselined";
128
+
129
+ export interface UltragoalPipelineLedgerEvent extends UltragoalLedgerEvent {
130
+ event: UltragoalPipelineLedgerEventName;
131
+ schemaVersion: 1;
132
+ overlapId: string;
133
+ priorGoalId: string;
134
+ nextGoalId: string;
135
+ }
33
136
  export interface UltragoalGoal {
34
137
  id: string;
35
138
  title: string;
@@ -42,6 +145,8 @@ export interface UltragoalGoal {
42
145
  evidence?: string;
43
146
  steering?: Record<string, unknown>;
44
147
  completionVerification?: UltragoalCompletionVerification;
148
+ pipelineMetadata?: UltragoalPipelineMetadata;
149
+ validationBatch?: UltragoalValidationBatchMetadata;
45
150
  }
46
151
 
47
152
  export interface UltragoalPlan {
@@ -68,7 +173,6 @@ export interface UltragoalCompletionVerification {
68
173
  skcGoalMode: UltragoalSkcGoalMode;
69
174
  skcObjective: string;
70
175
  qualityGateHash: string;
71
- skcGoalSnapshotHash: string;
72
176
  planGeneration: string;
73
177
  basis: {
74
178
  planHashBeforeCheckpoint: string;
@@ -78,7 +182,36 @@ export interface UltragoalCompletionVerification {
78
182
  requiredGoalSetHashBeforeCheckpoint: string;
79
183
  };
80
184
  checkpointLedgerEventId: string;
81
- }
185
+ validationBatch?:
186
+ | {
187
+ schemaVersion: 1;
188
+ role: "deferred-member";
189
+ batchId: string;
190
+ memberIds: string[];
191
+ finalGoalId: string;
192
+ metadataHash: string;
193
+ changeSetHash: string;
194
+ }
195
+ | {
196
+ schemaVersion: 1;
197
+ role: "batch-close";
198
+ batchId: string;
199
+ memberIds: string[];
200
+ finalGoalId: string;
201
+ memberMetadataHashes: Record<string, string>;
202
+ memberReceiptIds: Record<string, string>;
203
+ memberCheckpointLedgerEventIds: Record<string, string>;
204
+ memberChangeSetHashes: Record<string, string>;
205
+ unionHash: string;
206
+ };
207
+ }
208
+
209
+ type UltragoalDeferredCompletionVerification = UltragoalCompletionVerification & {
210
+ validationBatch: Extract<
211
+ NonNullable<UltragoalCompletionVerification["validationBatch"]>,
212
+ { role: "deferred-member" }
213
+ >;
214
+ };
82
215
 
83
216
  export interface UltragoalLedgerEvent extends JsonObject {
84
217
  eventId?: string;
@@ -145,6 +278,7 @@ export interface UltragoalStatusSummary {
145
278
  nudgeRemaining?: number;
146
279
  nudgeGoalId?: string;
147
280
  nudgeTargetKind?: UltragoalNudgeTargetKind;
281
+ pipelineOverlap?: JsonObject;
148
282
  }
149
283
 
150
284
  export interface UltragoalCommandResult {
@@ -174,10 +308,9 @@ const ACCEPTED_PROOF_STATUSES = new Set([COVERED_STATUS, "passed", "verified"]);
174
308
  const MIN_SUBSTANTIVE_EVIDENCE_WORDS = 5;
175
309
  const MIN_SUBSTANTIVE_EVIDENCE_CHARS = 32;
176
310
 
177
- const SKC_GOAL_SNAPSHOT_MAX_AGE_MILLISECONDS = 10 * 60 * 1000;
178
- const SKC_GOAL_SNAPSHOT_MAX_FUTURE_SKEW_MILLISECONDS = 60 * 1000;
179
-
180
311
  const SCHEDULABLE_STATUSES = new Set<UltragoalGoalStatus>(["pending", "active", "failed"]);
312
+ const COMPLETE_CHECKPOINT_ALLOWED_PRE_STATUSES = new Set<UltragoalGoalStatus>(["active", "failed"]);
313
+
181
314
  const NATIVE_STEERING_KINDS = [
182
315
  "add_subgoal",
183
316
  "split_subgoal",
@@ -437,119 +570,6 @@ async function writePlan(cwd: string, plan: UltragoalPlan, sessionId?: string |
437
570
  await writeSessionActivityMarker(cwd, resolvedSessionId, { writer: "ultragoal-runtime", path: paths.goalsPath });
438
571
  }
439
572
 
440
- function requiredUltragoalGoals(plan: UltragoalPlan): UltragoalGoal[] {
441
- return plan.goals.filter(goal => goal.status !== "superseded");
442
- }
443
-
444
- function receiptRelevantGoals(
445
- plan: UltragoalPlan,
446
- goal: UltragoalGoal,
447
- receiptKind: UltragoalReceiptKind,
448
- ): UltragoalGoal[] {
449
- return receiptKind === "final-aggregate" ? requiredUltragoalGoals(plan) : [goal];
450
- }
451
-
452
- function ledgerEventId(event: UltragoalLedgerEvent): string | null {
453
- return typeof event.eventId === "string" && event.eventId.trim().length > 0 ? event.eventId : null;
454
- }
455
-
456
- function latestRelevantLedgerEventId(
457
- ledger: readonly UltragoalLedgerEvent[],
458
- relevantGoalIds: readonly string[],
459
- excludeEventId?: string,
460
- ): string | null {
461
- const relevant = new Set(relevantGoalIds);
462
- for (const event of [...ledger].reverse()) {
463
- const eventId = ledgerEventId(event);
464
- if (eventId && eventId === excludeEventId) continue;
465
- const goalId = typeof event.goalId === "string" ? event.goalId : null;
466
- if (!goalId || relevant.has(goalId)) return eventId;
467
- }
468
- return null;
469
- }
470
-
471
- function planSnapshotForReceipt(input: {
472
- plan: UltragoalPlan;
473
- goal: UltragoalGoal;
474
- beforeStatus: UltragoalGoalStatus;
475
- targetGoalUpdatedAt: string;
476
- receiptKind: UltragoalReceiptKind;
477
- }): unknown {
478
- const targetGoalSnapshot = {
479
- ...input.goal,
480
- status: input.beforeStatus,
481
- updatedAt: input.targetGoalUpdatedAt,
482
- evidence: undefined,
483
- completedAt: undefined,
484
- completionVerification: undefined,
485
- };
486
- const goals =
487
- input.receiptKind === "final-aggregate"
488
- ? input.plan.goals.map(goal => ({
489
- ...goal,
490
- status: goal.id === input.goal.id ? input.beforeStatus : goal.status,
491
- updatedAt: goal.id === input.goal.id ? input.targetGoalUpdatedAt : goal.updatedAt,
492
- evidence: goal.id === input.goal.id ? undefined : goal.evidence,
493
- completedAt: goal.id === input.goal.id ? undefined : goal.completedAt,
494
- completionVerification: undefined,
495
- }))
496
- : [targetGoalSnapshot];
497
- return {
498
- version: input.plan.version,
499
- brief: input.plan.brief,
500
- skcGoalMode: input.plan.skcGoalMode,
501
- skcObjective: input.plan.skcObjective,
502
- skcObjectiveAliases: input.plan.skcObjectiveAliases,
503
- createdAt: input.plan.createdAt,
504
- goals,
505
- };
506
- }
507
-
508
- export function computeUltragoalPlanGeneration(input: {
509
- plan: UltragoalPlan;
510
- ledger: readonly UltragoalLedgerEvent[];
511
- goal: UltragoalGoal;
512
- receiptKind: UltragoalReceiptKind;
513
- beforeStatus: UltragoalGoalStatus;
514
- excludeEventId?: string;
515
- targetGoalUpdatedAt?: string;
516
- }): {
517
- planGeneration: string;
518
- basis: UltragoalCompletionVerification["basis"];
519
- } {
520
- const relevantGoals = receiptRelevantGoals(input.plan, input.goal, input.receiptKind);
521
- const relevantGoalIds = relevantGoals.map(goal => goal.id);
522
- const targetGoalUpdatedAt = input.targetGoalUpdatedAt ?? input.goal.updatedAt;
523
- const planHashBeforeCheckpoint = hashStructuredValue(
524
- planSnapshotForReceipt({
525
- plan: input.plan,
526
- goal: input.goal,
527
- beforeStatus: input.beforeStatus,
528
- targetGoalUpdatedAt,
529
- receiptKind: input.receiptKind,
530
- }),
531
- );
532
- const requiredGoalSetHashBeforeCheckpoint = hashStructuredValue(
533
- relevantGoals.map(goal => ({
534
- id: goal.id,
535
- status: goal.id === input.goal.id ? input.beforeStatus : goal.status,
536
- updatedAt: goal.id === input.goal.id ? targetGoalUpdatedAt : goal.updatedAt,
537
- })),
538
- );
539
- const basis: UltragoalCompletionVerification["basis"] = {
540
- planHashBeforeCheckpoint,
541
- latestRelevantLedgerEventIdBeforeCheckpoint: latestRelevantLedgerEventId(
542
- input.ledger,
543
- relevantGoalIds,
544
- input.excludeEventId,
545
- ),
546
- goalUpdatedAtBeforeCheckpoint: targetGoalUpdatedAt,
547
- relevantGoalIdsBeforeCheckpoint: relevantGoalIds,
548
- requiredGoalSetHashBeforeCheckpoint,
549
- };
550
- return { planGeneration: hashStructuredValue(basis), basis };
551
- }
552
-
553
573
  function chooseReceiptKind(
554
574
  plan: UltragoalPlan,
555
575
  goal: UltragoalGoal,
@@ -557,7 +577,12 @@ function chooseReceiptKind(
557
577
  ): UltragoalReceiptKind {
558
578
  if (plan.skcGoalMode === "per-story") return "per-goal";
559
579
  if (status !== "complete") return "per-goal";
560
- const unfinishedRequiredGoals = requiredUltragoalGoals(plan).filter(
580
+ const requiredGoals = requiredUltragoalGoals(plan);
581
+ const existingFinalAggregateGoal = requiredGoals.find(
582
+ item => item.id !== goal.id && item.completionVerification?.receiptKind === "final-aggregate",
583
+ );
584
+ if (existingFinalAggregateGoal) return "per-goal";
585
+ const unfinishedRequiredGoals = requiredGoals.filter(
561
586
  item => item.id !== goal.id && !TERMINAL_OR_SKIPPED_STATUSES.has(item.status),
562
587
  );
563
588
  return unfinishedRequiredGoals.length === 0 ? "final-aggregate" : "per-goal";
@@ -570,7 +595,6 @@ function buildCompletionReceipt(input: {
570
595
  receiptKind: UltragoalReceiptKind;
571
596
  beforeStatus: UltragoalGoalStatus;
572
597
  qualityGateJson: JsonObject;
573
- skcGoalJson: JsonObject;
574
598
  now: string;
575
599
  checkpointLedgerEventId: string;
576
600
  }): UltragoalCompletionVerification {
@@ -583,6 +607,54 @@ function buildCompletionReceipt(input: {
583
607
  targetGoalUpdatedAt: input.now,
584
608
  excludeEventId: input.checkpointLedgerEventId,
585
609
  });
610
+ let validationBatch: UltragoalCompletionVerification["validationBatch"];
611
+ if (input.goal.validationBatch) {
612
+ if (input.goal.id !== input.goal.validationBatch.finalGoalId) {
613
+ const deferred = qualityGateObject(input.qualityGateJson.deferredToBatch);
614
+ const changeSet = qualityGateObject(deferred?.changeSet);
615
+ validationBatch = {
616
+ schemaVersion: 1,
617
+ role: "deferred-member",
618
+ batchId: input.goal.validationBatch.batchId,
619
+ memberIds: [...input.goal.validationBatch.memberIds],
620
+ finalGoalId: input.goal.validationBatch.finalGoalId,
621
+ metadataHash: input.goal.validationBatch.metadataHash,
622
+ changeSetHash: String(changeSet?.changeSetHash ?? ""),
623
+ };
624
+ } else {
625
+ const close = qualityGateObject(input.qualityGateJson.validationBatchClose);
626
+ const union = qualityGateObject(close?.unionChangeSet);
627
+ const memberReceiptIds: Record<string, string> = {};
628
+ const memberCheckpointLedgerEventIds: Record<string, string> = {};
629
+ const rows = Array.isArray(close?.memberReceipts) ? close.memberReceipts : [];
630
+ for (const row of rows) {
631
+ if (typeof row === "object" && row !== null && !Array.isArray(row)) {
632
+ const record = row as JsonObject;
633
+ const goalId = nonEmptyString(record.goalId);
634
+ if (goalId) {
635
+ memberReceiptIds[goalId] = String(record.receiptId ?? "");
636
+ memberCheckpointLedgerEventIds[goalId] = String(record.checkpointLedgerEventId ?? "");
637
+ }
638
+ }
639
+ }
640
+ validationBatch = {
641
+ schemaVersion: 1,
642
+ role: "batch-close",
643
+ batchId: input.goal.validationBatch.batchId,
644
+ memberIds: [...input.goal.validationBatch.memberIds],
645
+ finalGoalId: input.goal.validationBatch.finalGoalId,
646
+ memberMetadataHashes: {
647
+ ...(qualityGateObject(close?.memberMetadataHashes) as Record<string, string> | undefined),
648
+ },
649
+ memberReceiptIds,
650
+ memberCheckpointLedgerEventIds,
651
+ memberChangeSetHashes: {
652
+ ...(qualityGateObject(union?.memberChangeSetHashes) as Record<string, string> | undefined),
653
+ },
654
+ unionHash: String(union?.unionHash ?? ""),
655
+ };
656
+ }
657
+ }
586
658
  return {
587
659
  schemaVersion: 1,
588
660
  receiptId: crypto.randomUUID(),
@@ -593,16 +665,564 @@ function buildCompletionReceipt(input: {
593
665
  skcGoalMode: input.plan.skcGoalMode,
594
666
  skcObjective: input.plan.skcObjective,
595
667
  qualityGateHash: hashStructuredValue(input.qualityGateJson),
596
- skcGoalSnapshotHash: hashStructuredValue(input.skcGoalJson),
597
668
  planGeneration: generation.planGeneration,
598
669
  basis: generation.basis,
599
670
  checkpointLedgerEventId: input.checkpointLedgerEventId,
671
+ validationBatch,
600
672
  };
601
673
  }
602
674
 
603
675
  function nonEmptyString(value: unknown): string | null {
604
676
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
605
677
  }
678
+ function stringArray(value: unknown): string[] | null {
679
+ return Array.isArray(value) && value.every(item => typeof item === "string") ? value.map(item => item.trim()) : null;
680
+ }
681
+
682
+ function normalizePipelineStringArray(value: unknown, fieldName: string): string[] {
683
+ const items = stringArray(value) ?? [];
684
+ const filtered = items.filter(item => item.length > 0);
685
+ if (items.length !== filtered.length) throw new Error(`${fieldName} must contain only non-empty strings`);
686
+ return filtered;
687
+ }
688
+
689
+ function normalizePipelinePath(value: string, fieldName: string): string {
690
+ const raw = value.trim();
691
+ if (raw.split(/[\\/]+/).includes("..")) throw new Error(`${fieldName} contains unsafe path ${value}`);
692
+ const normalized = normalizeRepoPath(raw);
693
+ if (
694
+ !normalized ||
695
+ normalized.startsWith("../") ||
696
+ normalized === ".." ||
697
+ path.isAbsolute(normalized) ||
698
+ normalized.includes("\0")
699
+ ) {
700
+ throw new Error(`${fieldName} contains unsafe path ${value}`);
701
+ }
702
+ return normalized;
703
+ }
704
+
705
+ function normalizePipelineTargets(value: unknown, fieldName: string): UltragoalPipelineTargets {
706
+ const record = typeof value === "object" && value !== null && !Array.isArray(value) ? (value as JsonObject) : {};
707
+ const files = normalizePipelineStringArray(record.files, `${fieldName}.files`).map(item =>
708
+ normalizePipelinePath(item, `${fieldName}.files`),
709
+ );
710
+ const surfaces = normalizePipelineStringArray(record.surfaces, `${fieldName}.surfaces`).map(normalizeSurfaceToken);
711
+ if (new Set(files).size !== files.length) throw new Error(`${fieldName}.files contains duplicate normalized paths`);
712
+ if (new Set(surfaces).size !== surfaces.length)
713
+ throw new Error(`${fieldName}.surfaces contains duplicate normalized surfaces`);
714
+ return { files, surfaces };
715
+ }
716
+
717
+ function pipelineMetadataHashBasis(metadata: Omit<UltragoalPipelineMetadata, "metadataHash">): JsonObject {
718
+ return {
719
+ schemaVersion: metadata.schemaVersion,
720
+ goalId: metadata.goalId,
721
+ source: metadata.source,
722
+ dependsOn: metadata.dependsOn,
723
+ independentOf: metadata.independentOf,
724
+ targets: metadata.targets,
725
+ };
726
+ }
727
+
728
+ function hashPipelineMetadata(metadata: Omit<UltragoalPipelineMetadata, "metadataHash">): string {
729
+ return hashStructuredValue(pipelineMetadataHashBasis(metadata));
730
+ }
731
+
732
+ function withPipelineMetadataHash(
733
+ metadata: Omit<UltragoalPipelineMetadata, "metadataHash">,
734
+ ): UltragoalPipelineMetadata {
735
+ return { ...metadata, metadataHash: hashPipelineMetadata(metadata) } as UltragoalPipelineMetadata;
736
+ }
737
+ function validationBatchHashBasis(metadata: Omit<UltragoalValidationBatchMetadata, "metadataHash">): JsonObject {
738
+ return {
739
+ schemaVersion: metadata.schemaVersion,
740
+ batchId: metadata.batchId,
741
+ memberIds: metadata.memberIds,
742
+ finalGoalId: metadata.finalGoalId,
743
+ mode: metadata.mode,
744
+ };
745
+ }
746
+
747
+ function hashValidationBatch(metadata: Omit<UltragoalValidationBatchMetadata, "metadataHash">): string {
748
+ return hashStructuredValue(validationBatchHashBasis(metadata));
749
+ }
750
+
751
+ function withValidationBatchHash(
752
+ metadata: Omit<UltragoalValidationBatchMetadata, "metadataHash">,
753
+ ): UltragoalValidationBatchMetadata {
754
+ return { ...metadata, metadataHash: hashValidationBatch(metadata) } as UltragoalValidationBatchMetadata;
755
+ }
756
+
757
+ function parseValidationBatchInput(
758
+ value: unknown,
759
+ goalIds: ReadonlySet<string>,
760
+ skcGoalMode: UltragoalSkcGoalMode,
761
+ ): UltragoalValidationBatchMetadata[] {
762
+ if (!Array.isArray(value)) throw new Error("validation batch JSON must be an array");
763
+ if (value.length === 0) return [];
764
+ if (skcGoalMode !== "aggregate") throw new Error("validation batches require aggregate ultragoal mode");
765
+ const goalOrder = new Map([...goalIds].map((id, index) => [id, index]));
766
+ const assigned = new Set<string>();
767
+ const batches: UltragoalValidationBatchMetadata[] = [];
768
+ for (const row of value) {
769
+ if (typeof row !== "object" || row === null || Array.isArray(row))
770
+ throw new Error("validation batch rows must be objects");
771
+ const record = row as JsonObject;
772
+ if (record.schemaVersion !== 1) throw new Error("validation batch schemaVersion must be 1");
773
+ const batchId = nonEmptyString(record.batchId);
774
+ if (!batchId) throw new Error("validation batch batchId is required");
775
+ const finalGoalId = nonEmptyString(record.finalGoalId);
776
+ if (!finalGoalId || !goalIds.has(finalGoalId))
777
+ throw new Error(`validation batch ${batchId} references unknown finalGoalId ${finalGoalId ?? ""}`);
778
+ const memberIds = stringArray(record.memberIds);
779
+ if (!memberIds || memberIds.length === 0)
780
+ throw new Error(`validation batch ${batchId} memberIds must be non-empty`);
781
+ if (memberIds.some(id => id.length === 0))
782
+ throw new Error(`validation batch ${batchId} memberIds must contain only non-empty strings`);
783
+ if (new Set(memberIds).size !== memberIds.length)
784
+ throw new Error(`validation batch ${batchId} contains duplicate memberIds`);
785
+ for (const memberId of memberIds) {
786
+ if (!goalIds.has(memberId))
787
+ throw new Error(`validation batch ${batchId} references unknown member ${memberId}`);
788
+ if (assigned.has(memberId)) throw new Error(`Goal ${memberId} belongs to more than one validation batch`);
789
+ }
790
+ if (!memberIds.includes(finalGoalId))
791
+ throw new Error(`validation batch ${batchId} memberIds must contain finalGoalId ${finalGoalId}`);
792
+ for (const memberId of memberIds) assigned.add(memberId);
793
+ const canonicalMemberIds = [...memberIds].sort(
794
+ (left, right) => (goalOrder.get(left) ?? 0) - (goalOrder.get(right) ?? 0),
795
+ );
796
+ batches.push(
797
+ withValidationBatchHash({
798
+ schemaVersion: 1,
799
+ batchId,
800
+ memberIds: canonicalMemberIds,
801
+ finalGoalId,
802
+ mode: "aggregate-only",
803
+ }),
804
+ );
805
+ }
806
+ return batches;
807
+ }
808
+
809
+ function normalizeSavedValidationBatch(record: unknown, id: string): UltragoalValidationBatchMetadata | undefined {
810
+ if (typeof record !== "object" || record === null || Array.isArray(record)) return undefined;
811
+ const value = record as JsonObject;
812
+ if (value.schemaVersion !== 1) throw new Error(`Goal ${id} validation batch schemaVersion must be 1`);
813
+ const batchId = nonEmptyString(value.batchId);
814
+ if (!batchId) throw new Error(`Goal ${id} validation batch batchId is required`);
815
+ const memberIds = stringArray(value.memberIds);
816
+ if (!memberIds || memberIds.length === 0) throw new Error(`Goal ${id} validation batch memberIds must be non-empty`);
817
+ if (new Set(memberIds).size !== memberIds.length || memberIds.some(memberId => memberId.length === 0)) {
818
+ throw new Error(`Goal ${id} validation batch memberIds must be unique non-empty strings`);
819
+ }
820
+ if (!memberIds.includes(id)) throw new Error(`Goal ${id} validation batch must include its goal id`);
821
+ const finalGoalId = nonEmptyString(value.finalGoalId);
822
+ if (!finalGoalId || !memberIds.includes(finalGoalId))
823
+ throw new Error(`Goal ${id} validation batch finalGoalId must be a member`);
824
+ if (value.mode !== "aggregate-only") throw new Error(`Goal ${id} validation batch mode must be aggregate-only`);
825
+ const basis: Omit<UltragoalValidationBatchMetadata, "metadataHash"> = {
826
+ schemaVersion: 1,
827
+ batchId,
828
+ memberIds,
829
+ finalGoalId,
830
+ mode: "aggregate-only",
831
+ };
832
+ const metadataHash = nonEmptyString(value.metadataHash);
833
+ if (!metadataHash) throw new Error(`Goal ${id} validation batch metadataHash is required`);
834
+ const normalized = { ...basis, metadataHash } as UltragoalValidationBatchMetadata;
835
+ if (metadataHash !== hashValidationBatch(basis))
836
+ throw new Error(`Goal ${id} has stale validation batch metadata hash`);
837
+ return normalized;
838
+ }
839
+
840
+ function pipelineMetadataConflictsWithValidationBatch(metadata: UltragoalPipelineMetadata | undefined): boolean {
841
+ return metadata?.eligible === true || metadata?.source === "original_plan_graph" || metadata?.source === "steering";
842
+ }
843
+
844
+ function validateValidationBatchPipelineExclusion(goal: UltragoalGoal): void {
845
+ if (goal.validationBatch && pipelineMetadataConflictsWithValidationBatch(goal.pipelineMetadata)) {
846
+ throw new Error(`Goal ${goal.id} cannot combine validationBatch with eligible pipeline metadata`);
847
+ }
848
+ }
849
+ function requireFreshValidationBatchMetadata(goal: UltragoalGoal): UltragoalValidationBatchMetadata | undefined {
850
+ const metadata = goal.validationBatch;
851
+ if (!metadata) return undefined;
852
+ const { metadataHash, ...basis } = metadata;
853
+ if (metadataHash !== hashValidationBatch(basis))
854
+ throw new Error(`Goal ${goal.id} has stale validation batch metadata hash`);
855
+ validateValidationBatchPipelineExclusion(goal);
856
+ return metadata;
857
+ }
858
+
859
+ function findFreshValidationBatchClose(
860
+ plan: UltragoalPlan,
861
+ metadata: UltragoalValidationBatchMetadata,
862
+ member: UltragoalGoal,
863
+ ledger: readonly UltragoalLedgerEvent[],
864
+ ): UltragoalGoal | undefined {
865
+ const receipt = member.completionVerification;
866
+ if (!receipt) return undefined;
867
+ const finalReceipt = findFreshBatchCloseReceipt({ plan, ledger, deferredGoal: member, deferredReceipt: receipt });
868
+ if (!finalReceipt) return undefined;
869
+ const finalGoal = plan.goals.find(goal => goal.id === metadata.finalGoalId);
870
+ const close = finalReceipt.validationBatch;
871
+ if (!finalGoal || close?.role !== "batch-close") return undefined;
872
+ if (close.batchId !== metadata.batchId || close.finalGoalId !== metadata.finalGoalId) return undefined;
873
+ if (
874
+ close.memberIds.length !== metadata.memberIds.length ||
875
+ close.memberIds.some((id, index) => id !== metadata.memberIds[index])
876
+ )
877
+ return undefined;
878
+ if (close.memberMetadataHashes[member.id] !== metadata.metadataHash) return undefined;
879
+ return finalGoal;
880
+ }
881
+
882
+ function requireDeferredMemberReceiptFresh(
883
+ plan: UltragoalPlan,
884
+ ledger: readonly UltragoalLedgerEvent[],
885
+ member: UltragoalGoal,
886
+ fieldName: string,
887
+ ): UltragoalDeferredCompletionVerification {
888
+ const receipt = member.completionVerification;
889
+ if (!receipt) throw new Error(`${fieldName} requires fresh deferred receipt for ${member.id}`);
890
+ if (receipt.validationBatch?.role !== "deferred-member")
891
+ throw new Error(`${fieldName} requires fresh deferred receipt for ${member.id}`);
892
+ const diagnostic = validateDeferredMemberReceiptFresh({
893
+ plan,
894
+ ledger,
895
+ goal: member,
896
+ receipt,
897
+ receiptKind: "per-goal",
898
+ requireClose: false,
899
+ });
900
+ if (diagnostic.state !== "active_verified_complete")
901
+ throw new Error(`${fieldName}.${member.id} ${diagnostic.message}`);
902
+ return receipt as UltragoalDeferredCompletionVerification;
903
+ }
904
+
905
+ function requireFreshBatchCloseReceiptBasis(
906
+ plan: UltragoalPlan,
907
+ ledger: readonly UltragoalLedgerEvent[],
908
+ goal: UltragoalGoal,
909
+ receipt: UltragoalCompletionVerification,
910
+ event: UltragoalLedgerEvent,
911
+ ): void {
912
+ const batch = receipt.validationBatch;
913
+ if (batch?.role !== "batch-close") return;
914
+ const base = validateReceiptFreshBase({ plan, ledger, goal, receipt, receiptKind: receipt.receiptKind });
915
+ if (base) throw new Error(base.message);
916
+ for (const memberId of batch.memberIds) {
917
+ const member = plan.goals.find(item => item.id === memberId);
918
+ if (
919
+ !member?.validationBatch ||
920
+ member.validationBatch.batchId !== batch.batchId ||
921
+ member.validationBatch.metadataHash !== batch.memberMetadataHashes[memberId]
922
+ ) {
923
+ throw new Error(`Goal ${goal.id} has stale validation batch close receipt for ${batch.batchId}`);
924
+ }
925
+ if (memberId === batch.finalGoalId) continue;
926
+ const memberReceipt = requireDeferredMemberReceiptFresh(
927
+ plan,
928
+ ledger,
929
+ member,
930
+ `Goal ${goal.id} batch-close receipt`,
931
+ );
932
+ if (
933
+ batch.memberReceiptIds[memberId] !== memberReceipt.receiptId ||
934
+ batch.memberCheckpointLedgerEventIds[memberId] !== memberReceipt.checkpointLedgerEventId ||
935
+ batch.memberChangeSetHashes[memberId] !== memberReceipt.validationBatch!.changeSetHash
936
+ ) {
937
+ throw new Error(`Goal ${goal.id} batch-close receipt is stale for deferred member ${memberId}`);
938
+ }
939
+ }
940
+ const close = qualityGateObject(qualityGateObject(event.qualityGateJson)?.validationBatchClose);
941
+ const unionHash = String(qualityGateObject(close?.unionChangeSet)?.unionHash ?? "");
942
+ if (batch.unionHash !== unionHash)
943
+ throw new Error(`Goal ${goal.id} validation batch close receipt union hash is stale`);
944
+ }
945
+
946
+ function clearValidationBatchForBatch(
947
+ plan: UltragoalPlan,
948
+ metadata: UltragoalValidationBatchMetadata | undefined,
949
+ ): void {
950
+ if (!metadata) return;
951
+ for (const member of plan.goals) {
952
+ if (member.validationBatch?.batchId === metadata.batchId) delete member.validationBatch;
953
+ }
954
+ }
955
+
956
+ function freshDeferredValidationBatchBlocker(
957
+ plan: UltragoalPlan,
958
+ metadata: UltragoalValidationBatchMetadata,
959
+ ledger: readonly UltragoalLedgerEvent[],
960
+ ): UltragoalGoal | undefined {
961
+ for (const memberId of metadata.memberIds) {
962
+ const member = plan.goals.find(goal => goal.id === memberId);
963
+ if (!member?.validationBatch || member.status !== "complete") continue;
964
+ try {
965
+ requireDeferredMemberReceiptFresh(plan, ledger, member, "validation batch steering");
966
+ } catch {
967
+ continue;
968
+ }
969
+ if (!findFreshValidationBatchClose(plan, member.validationBatch, member, ledger)) return member;
970
+ }
971
+ return undefined;
972
+ }
973
+
974
+ function requireValidationBatchSteeringAllowed(
975
+ plan: UltragoalPlan,
976
+ goal: UltragoalGoal,
977
+ kind: UltragoalSteeringKind,
978
+ ledger: readonly UltragoalLedgerEvent[],
979
+ ): void {
980
+ const metadata = goal.validationBatch;
981
+ if (!metadata) return;
982
+ const blocker = freshDeferredValidationBatchBlocker(plan, metadata, ledger);
983
+ if (blocker)
984
+ throw new Error(
985
+ `steer ${kind} cannot invalidate validation batch ${metadata.batchId} while member ${blocker.id} has a fresh deferred receipt`,
986
+ );
987
+ }
988
+ function legacyPipelineMetadata(goalId: string): UltragoalPipelineMetadata {
989
+ const basis: Omit<UltragoalPipelineMetadata, "metadataHash"> = {
990
+ schemaVersion: 1,
991
+ goalId,
992
+ source: "legacy_brief_only",
993
+ eligible: false,
994
+ dependsOn: [],
995
+ independentOf: [],
996
+ targets: { files: [], surfaces: [] },
997
+ overlap: "none",
998
+ invalidationReason: "missing_pipeline_metadata",
999
+ };
1000
+ return withPipelineMetadataHash(basis);
1001
+ }
1002
+
1003
+ function normalizePipelineMetadataRecord(value: unknown, goalIds: ReadonlySet<string>): UltragoalPipelineMetadata {
1004
+ if (typeof value !== "object" || value === null || Array.isArray(value))
1005
+ throw new Error("goal metadata rows must be objects");
1006
+ const record = value as JsonObject;
1007
+ if (record.schemaVersion !== 1) throw new Error("goal metadata schemaVersion must be 1");
1008
+ const goalId = nonEmptyString(record.goalId);
1009
+ if (!goalId || !goalIds.has(goalId)) throw new Error(`goal metadata references unknown goal id ${goalId ?? ""}`);
1010
+ const source = record.source;
1011
+ if (source !== "original_plan_graph" && source !== "legacy_brief_only" && source !== "steering") {
1012
+ throw new Error("goal metadata source must be original_plan_graph, legacy_brief_only, or steering");
1013
+ }
1014
+ const dependsOn = normalizePipelineStringArray(record.dependsOn, `metadata ${goalId}.dependsOn`);
1015
+ const independentOf = normalizePipelineStringArray(record.independentOf, `metadata ${goalId}.independentOf`);
1016
+ if (dependsOn.includes(goalId) || independentOf.includes(goalId))
1017
+ throw new Error(`goal metadata ${goalId} cannot reference itself`);
1018
+ for (const id of [...dependsOn, ...independentOf]) {
1019
+ if (!goalIds.has(id)) throw new Error(`goal metadata ${goalId} references unknown goal id ${id}`);
1020
+ }
1021
+ if (dependsOn.some(id => independentOf.includes(id)))
1022
+ throw new Error(`goal metadata ${goalId} has dependency/independence conflict`);
1023
+ const targets = requireNonEmptyPipelineTargets(record.targets, `metadata ${goalId}.targets`);
1024
+ const basis: Omit<UltragoalPipelineMetadata, "metadataHash"> = {
1025
+ schemaVersion: 1,
1026
+ goalId,
1027
+ source,
1028
+ eligible: false,
1029
+ dependsOn,
1030
+ independentOf,
1031
+ targets,
1032
+ overlap: "none",
1033
+ };
1034
+ return withPipelineMetadataHash(basis);
1035
+ }
1036
+
1037
+ function targetsAreDisjoint(left: UltragoalPipelineTargets, right: UltragoalPipelineTargets): boolean {
1038
+ return (
1039
+ left.files.every(file => !right.files.includes(file)) &&
1040
+ left.surfaces.every(surface => !right.surfaces.includes(surface))
1041
+ );
1042
+ }
1043
+
1044
+ function targetsOverlap(left: UltragoalPipelineTargets, right: UltragoalPipelineTargets): boolean {
1045
+ return (
1046
+ left.files.some(file => right.files.includes(file)) ||
1047
+ left.surfaces.some(surface => right.surfaces.includes(surface))
1048
+ );
1049
+ }
1050
+
1051
+ function requireNonEmptyPipelineTargets(value: unknown, fieldName: string): UltragoalPipelineTargets {
1052
+ const targets = normalizePipelineTargets(value, fieldName);
1053
+ if (targets.files.length === 0 && targets.surfaces.length === 0)
1054
+ throw new Error(`${fieldName} requires files or surfaces`);
1055
+ return targets;
1056
+ }
1057
+
1058
+ function collectPipelineBlockerFootprints(result: JsonObject, fieldName: string): UltragoalPipelineTargets[] {
1059
+ const raw = Array.isArray(result.blockers)
1060
+ ? result.blockers
1061
+ : Array.isArray(result.blockerFootprints)
1062
+ ? result.blockerFootprints
1063
+ : [];
1064
+ return raw.map((item, index) => {
1065
+ const record = requireJsonObjectValue(item, `${fieldName}.blockers[${index}]`);
1066
+ const footprint = typeof record.footprint === "object" && record.footprint !== null ? record.footprint : record;
1067
+ return requireNonEmptyPipelineTargets(footprint, `${fieldName}.blockers[${index}].footprint`);
1068
+ });
1069
+ }
1070
+
1071
+ function pipelineTargetsCoverPath(targets: UltragoalPipelineTargets, filePath: string): boolean {
1072
+ const normalized = normalizeRepoPath(filePath);
1073
+ return targets.files.some(target => normalized === target || normalized.startsWith(`${target}/`));
1074
+ }
1075
+
1076
+ function pipelinePeer(plan: UltragoalPlan, metadata: UltragoalPipelineMetadata): UltragoalGoal | undefined {
1077
+ const peerId = metadata.goalId === metadata.priorGoalId ? metadata.nextGoalId : metadata.priorGoalId;
1078
+ return peerId ? plan.goals.find(goal => goal.id === peerId) : undefined;
1079
+ }
1080
+
1081
+ function handleIdsFromValue(value: JsonObject | JsonObject[], fieldName: string): string[] {
1082
+ const records = Array.isArray(value) ? value : [value];
1083
+ const ids = records.map(
1084
+ (record, index) =>
1085
+ nonEmptyString(record.id) ??
1086
+ nonEmptyString(record.handleId) ??
1087
+ nonEmptyString(record.name) ??
1088
+ `${fieldName}-${index}`,
1089
+ );
1090
+ if (ids.some(id => id.length === 0)) throw new Error(`${fieldName} handles require ids`);
1091
+ return ids;
1092
+ }
1093
+
1094
+ function resultHandleIds(value: JsonObject, fieldName: string): string[] {
1095
+ const ids = stringArray(value.handleIds) ?? stringArray(value.handles) ?? [];
1096
+ if (ids.length === 0) throw new Error(`${fieldName} requires handleIds`);
1097
+ return ids;
1098
+ }
1099
+
1100
+ function requireCoveredHandles(expected: readonly string[], actual: readonly string[], fieldName: string): void {
1101
+ const missing = expected.filter(id => !actual.includes(id));
1102
+ if (missing.length > 0) throw new Error(`${fieldName} is missing handle coverage for ${missing.join(", ")}`);
1103
+ }
1104
+
1105
+ function validatePipelineEligibility(metadata: UltragoalPipelineMetadata[]): UltragoalPipelineMetadata[] {
1106
+ const byId = new Map(metadata.map(item => [item.goalId, item]));
1107
+ return metadata.map(item => {
1108
+ const invalidationReasons: string[] = [];
1109
+ if (item.source !== "original_plan_graph") invalidationReasons.push("not_original_plan_graph");
1110
+ if (item.targets.files.length === 0 && item.targets.surfaces.length === 0)
1111
+ invalidationReasons.push("empty_targets");
1112
+ for (const otherId of item.independentOf) {
1113
+ const other = byId.get(otherId);
1114
+ if (!other?.independentOf.includes(item.goalId))
1115
+ invalidationReasons.push(`missing_symmetric_independence:${otherId}`);
1116
+ if (other && !targetsAreDisjoint(item.targets, other.targets))
1117
+ invalidationReasons.push(`shared_targets:${otherId}`);
1118
+ }
1119
+ const eligible = invalidationReasons.length === 0;
1120
+ return {
1121
+ ...item,
1122
+ eligible,
1123
+ ...(eligible ? {} : { invalidationReason: invalidationReasons.join(",") || "ineligible" }),
1124
+ };
1125
+ });
1126
+ }
1127
+
1128
+ function parseGoalMetadataInput(value: unknown, goalIds: ReadonlySet<string>): UltragoalPipelineMetadata[] {
1129
+ if (!Array.isArray(value)) throw new Error("goal metadata JSON must be an array");
1130
+ const seen = new Set<string>();
1131
+ const metadata = value.map(row => {
1132
+ const item = normalizePipelineMetadataRecord(row, goalIds);
1133
+ if (seen.has(item.goalId)) throw new Error(`duplicate goal metadata for ${item.goalId}`);
1134
+ seen.add(item.goalId);
1135
+ return item;
1136
+ });
1137
+ return validatePipelineEligibility(metadata);
1138
+ }
1139
+ function normalizeSavedPipelineMetadata(value: unknown, goalId: string): UltragoalPipelineMetadata | undefined {
1140
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
1141
+ const record = value as JsonObject;
1142
+ const source =
1143
+ record.source === "original_plan_graph" || record.source === "legacy_brief_only" || record.source === "steering"
1144
+ ? record.source
1145
+ : "legacy_brief_only";
1146
+ const overlap =
1147
+ record.overlap === "open" ||
1148
+ record.overlap === "joined_clean" ||
1149
+ record.overlap === "blocked_disjoint_continue" ||
1150
+ record.overlap === "quarantine_required" ||
1151
+ record.overlap === "rebaseline_complete"
1152
+ ? record.overlap
1153
+ : "none";
1154
+ const basis: Omit<UltragoalPipelineMetadata, "metadataHash"> = {
1155
+ schemaVersion: 1,
1156
+ goalId,
1157
+ source,
1158
+ eligible: record.eligible === true,
1159
+ dependsOn: normalizePipelineStringArray(record.dependsOn, `metadata ${goalId}.dependsOn`),
1160
+ independentOf: normalizePipelineStringArray(record.independentOf, `metadata ${goalId}.independentOf`),
1161
+ targets: normalizePipelineTargets(record.targets, `metadata ${goalId}.targets`),
1162
+ overlap,
1163
+ ...(nonEmptyString(record.overlapId) ? { overlapId: nonEmptyString(record.overlapId)! } : {}),
1164
+ ...(nonEmptyString(record.priorGoalId) ? { priorGoalId: nonEmptyString(record.priorGoalId)! } : {}),
1165
+ ...(nonEmptyString(record.nextGoalId) ? { nextGoalId: nonEmptyString(record.nextGoalId)! } : {}),
1166
+ ...(Array.isArray(record.blockerFootprints)
1167
+ ? {
1168
+ blockerFootprints: record.blockerFootprints.map((item, index) =>
1169
+ normalizePipelineTargets(item, `metadata ${goalId}.blockerFootprints[${index}]`),
1170
+ ),
1171
+ }
1172
+ : {}),
1173
+ ...(nonEmptyString(record.invalidationReason)
1174
+ ? { invalidationReason: nonEmptyString(record.invalidationReason)! }
1175
+ : {}),
1176
+ ...(nonEmptyString(record.invalidatedAt) ? { invalidatedAt: nonEmptyString(record.invalidatedAt)! } : {}),
1177
+ };
1178
+ return {
1179
+ ...basis,
1180
+ metadataHash: nonEmptyString(record.metadataHash) ?? hashPipelineMetadata(basis),
1181
+ } as UltragoalPipelineMetadata;
1182
+ }
1183
+
1184
+ function currentPipelineHash(metadata: UltragoalPipelineMetadata): string {
1185
+ return hashPipelineMetadata(metadata);
1186
+ }
1187
+
1188
+ function requireFreshPipelineMetadata(goal: UltragoalGoal): UltragoalPipelineMetadata {
1189
+ const metadata = goal.pipelineMetadata;
1190
+ if (!metadata) throw new Error(`Goal ${goal.id} has no pipeline metadata`);
1191
+ if (metadata.metadataHash !== currentPipelineHash(metadata))
1192
+ throw new Error(`Goal ${goal.id} has stale pipeline metadata hash`);
1193
+ return metadata;
1194
+ }
1195
+
1196
+ function openPipelineOverlap(
1197
+ plan: UltragoalPlan,
1198
+ ): { prior: UltragoalGoal; next: UltragoalGoal; overlapId: string } | null {
1199
+ const openGoals = plan.goals.filter(goal => goal.pipelineMetadata?.overlap === "open");
1200
+ if (openGoals.length === 0) return null;
1201
+ const overlapId = openGoals[0]?.pipelineMetadata?.overlapId;
1202
+ if (!overlapId) return null;
1203
+ const peers = openGoals.filter(goal => goal.pipelineMetadata?.overlapId === overlapId);
1204
+ if (peers.length !== 2) return null;
1205
+ const prior = peers[0];
1206
+ const next = peers[1];
1207
+ if (!prior || !next) return null;
1208
+ return { prior, next, overlapId };
1209
+ }
1210
+
1211
+ function invalidatePipelineMetadata(goal: UltragoalGoal, reason: string, now: string): void {
1212
+ const basis: Omit<UltragoalPipelineMetadata, "metadataHash"> = {
1213
+ schemaVersion: 1,
1214
+ goalId: goal.id,
1215
+ source: goal.pipelineMetadata?.source ?? "steering",
1216
+ eligible: false,
1217
+ dependsOn: goal.pipelineMetadata?.dependsOn ?? [],
1218
+ independentOf: goal.pipelineMetadata?.independentOf ?? [],
1219
+ targets: goal.pipelineMetadata?.targets ?? { files: [], surfaces: [] },
1220
+ overlap: "none",
1221
+ invalidationReason: reason,
1222
+ invalidatedAt: now,
1223
+ };
1224
+ goal.pipelineMetadata = withPipelineMetadataHash(basis);
1225
+ }
606
1226
 
607
1227
  function normalizeGoalStatus(value: unknown): UltragoalGoalStatus {
608
1228
  switch (value) {
@@ -644,6 +1264,8 @@ function normalizePlan(raw: unknown): UltragoalPlan {
644
1264
  const title = nonEmptyString(goalRecord.title) ?? id;
645
1265
  const objective = nonEmptyString(goalRecord.objective) ?? title;
646
1266
  const goalCreatedAt = nonEmptyString(goalRecord.createdAt) ?? createdAt;
1267
+ const pipelineMetadata = normalizeSavedPipelineMetadata(goalRecord.pipelineMetadata, id);
1268
+ const validationBatch = normalizeSavedValidationBatch(goalRecord.validationBatch, id);
647
1269
  return {
648
1270
  ...goalRecord,
649
1271
  id,
@@ -663,6 +1285,8 @@ function normalizePlan(raw: unknown): UltragoalPlan {
663
1285
  typeof goalRecord.completionVerification === "object" && goalRecord.completionVerification !== null
664
1286
  ? (goalRecord.completionVerification as UltragoalCompletionVerification)
665
1287
  : undefined,
1288
+ pipelineMetadata,
1289
+ validationBatch,
666
1290
  };
667
1291
  });
668
1292
  const aliases = Array.isArray(record.skcObjectiveAliases)
@@ -719,6 +1343,7 @@ export async function getUltragoalStatus(cwd: string, sessionId?: string | null)
719
1343
  if (!plan) return { exists: false, status: "missing", paths, counts, goals: [] };
720
1344
  for (const goal of plan.goals) counts[goal.status] += 1;
721
1345
  const currentGoal = plan.goals.find(goal => SCHEDULABLE_STATUSES.has(goal.status));
1346
+ const overlap = openPipelineOverlap(plan);
722
1347
  let status: UltragoalStatusSummary["status"] = "pending";
723
1348
  if (plan.goals.length > 0 && plan.goals.every(goal => TERMINAL_OR_SKIPPED_STATUSES.has(goal.status)))
724
1349
  status = "complete";
@@ -748,6 +1373,16 @@ export async function getUltragoalStatus(cwd: string, sessionId?: string | null)
748
1373
  counts,
749
1374
  goals: plan.goals,
750
1375
  ...nudgeFields,
1376
+ ...(overlap
1377
+ ? {
1378
+ pipelineOverlap: {
1379
+ overlapId: overlap.overlapId,
1380
+ priorGoalId: overlap.prior.id,
1381
+ nextGoalId: overlap.next.id,
1382
+ status: overlap.next.pipelineMetadata?.overlap,
1383
+ },
1384
+ }
1385
+ : {}),
751
1386
  };
752
1387
  }
753
1388
  export function buildUltragoalHudSummary(
@@ -822,6 +1457,10 @@ export async function createUltragoalPlan(input: {
822
1457
  brief: string;
823
1458
  skcGoalMode?: UltragoalSkcGoalMode;
824
1459
  sessionId?: string | null;
1460
+ goalMetadata?: UltragoalGoalMetadataInput[];
1461
+ goalMetadataJson?: string;
1462
+ validationBatches?: UltragoalValidationBatchInput[];
1463
+ validationBatchJson?: string;
825
1464
  }): Promise<UltragoalPlan> {
826
1465
  const brief = input.brief.trim();
827
1466
  if (!brief) throw new Error("ultragoal brief is required");
@@ -837,6 +1476,33 @@ export async function createUltragoalPlan(input: {
837
1476
  createdAt: now,
838
1477
  updatedAt: now,
839
1478
  }));
1479
+ const goalIds = new Set(goals.map(goal => goal.id));
1480
+ const metadataInput = input.goalMetadataJson
1481
+ ? await readStructuredValue(input.cwd, input.goalMetadataJson)
1482
+ : input.goalMetadata;
1483
+ const validationBatchInput = input.validationBatchJson
1484
+ ? await readStructuredValue(input.cwd, input.validationBatchJson)
1485
+ : input.validationBatches;
1486
+ if (metadataInput !== undefined && validationBatchInput !== undefined) {
1487
+ const metadataRows = Array.isArray(metadataInput) ? metadataInput : [];
1488
+ const batchRows = Array.isArray(validationBatchInput) ? validationBatchInput : [];
1489
+ if (metadataRows.length > 0 && batchRows.length > 0)
1490
+ throw new Error("validation-batch-json and goal-metadata-json are mutually exclusive");
1491
+ }
1492
+ const metadata = metadataInput === undefined ? [] : parseGoalMetadataInput(metadataInput, goalIds);
1493
+ const validationBatches =
1494
+ validationBatchInput === undefined
1495
+ ? []
1496
+ : parseValidationBatchInput(validationBatchInput, goalIds, input.skcGoalMode ?? "aggregate");
1497
+ const metadataByGoalId = new Map(metadata.map(item => [item.goalId, item]));
1498
+ const validationBatchByGoalId = new Map<string, UltragoalValidationBatchMetadata>();
1499
+ for (const batch of validationBatches)
1500
+ for (const memberId of batch.memberIds) validationBatchByGoalId.set(memberId, batch);
1501
+ for (const goal of goals) {
1502
+ goal.pipelineMetadata = metadataByGoalId.get(goal.id) ?? legacyPipelineMetadata(goal.id);
1503
+ goal.validationBatch = validationBatchByGoalId.get(goal.id);
1504
+ validateValidationBatchPipelineExclusion(goal);
1505
+ }
840
1506
  const plan: UltragoalPlan = {
841
1507
  version: 1,
842
1508
  brief,
@@ -866,6 +1532,305 @@ export interface UltragoalRunCompletionState {
866
1532
  hasBlockers: boolean;
867
1533
  needsFinalAggregateReceipt: boolean;
868
1534
  }
1535
+ function requireJsonObjectValue(value: unknown, fieldName: string): JsonObject {
1536
+ if (typeof value !== "object" || value === null || Array.isArray(value))
1537
+ throw new Error(`${fieldName} must be an object`);
1538
+ if (Object.keys(value).length === 0) throw new Error(`${fieldName} must be non-empty`);
1539
+ return value as JsonObject;
1540
+ }
1541
+
1542
+ function requireJsonObjectOrArrayValue(value: unknown, fieldName: string): JsonObject | JsonObject[] {
1543
+ if (Array.isArray(value)) {
1544
+ if (value.length === 0) throw new Error(`${fieldName} must be non-empty`);
1545
+ return value.map((item, index) => requireJsonObjectValue(item, `${fieldName}[${index}]`));
1546
+ }
1547
+ return requireJsonObjectValue(value, fieldName);
1548
+ }
1549
+
1550
+ async function readRequiredJsonObject(cwd: string, value: string, fieldName: string): Promise<JsonObject> {
1551
+ return requireJsonObjectValue(await readStructuredValue(cwd, value), fieldName);
1552
+ }
1553
+
1554
+ async function readRequiredJsonObjectOrArray(
1555
+ cwd: string,
1556
+ value: string,
1557
+ fieldName: string,
1558
+ ): Promise<JsonObject | JsonObject[]> {
1559
+ return requireJsonObjectOrArrayValue(await readStructuredValue(cwd, value), fieldName);
1560
+ }
1561
+
1562
+ function requirePipelineStartable(plan: UltragoalPlan, prior: UltragoalGoal, next: UltragoalGoal): void {
1563
+ if (plan.skcGoalMode !== "aggregate")
1564
+ throw new Error("pipeline overlap is supported only for aggregate ultragoal mode");
1565
+ if (openPipelineOverlap(plan))
1566
+ throw new Error("Cannot start pipeline overlap because another overlap is already open");
1567
+ if (prior.status !== "active")
1568
+ throw new Error(`Prior goal ${prior.id} must be active before pipeline overlap starts`);
1569
+ if (next.status !== "pending" && next.status !== "failed")
1570
+ throw new Error(`Next goal ${next.id} must be pending or retryable failed`);
1571
+ validateValidationBatchPipelineExclusion(prior);
1572
+ validateValidationBatchPipelineExclusion(next);
1573
+ if (prior.validationBatch || next.validationBatch)
1574
+ throw new Error("pipeline overlap cannot start for validation batch goals");
1575
+ const priorMetadata = requireFreshPipelineMetadata(prior);
1576
+ const nextMetadata = requireFreshPipelineMetadata(next);
1577
+ if (!priorMetadata.eligible || !nextMetadata.eligible)
1578
+ throw new Error("pipeline overlap requires eligible original-plan metadata on both goals");
1579
+ if (!priorMetadata.independentOf.includes(next.id) || !nextMetadata.independentOf.includes(prior.id)) {
1580
+ throw new Error("pipeline overlap requires symmetric original independence");
1581
+ }
1582
+ if (!targetsAreDisjoint(priorMetadata.targets, nextMetadata.targets))
1583
+ throw new Error("pipeline overlap requires disjoint files and surfaces");
1584
+ }
1585
+
1586
+ function pipelineEventRefs(prior: UltragoalGoal, next: UltragoalGoal): JsonObject {
1587
+ return {
1588
+ priorMetadataHash: prior.pipelineMetadata?.metadataHash,
1589
+ nextMetadataHash: next.pipelineMetadata?.metadataHash,
1590
+ priorTargets: prior.pipelineMetadata?.targets,
1591
+ nextTargets: next.pipelineMetadata?.targets,
1592
+ };
1593
+ }
1594
+
1595
+ function pipelineReceipt(
1596
+ cwd: string,
1597
+ event: string,
1598
+ overlapId: string,
1599
+ prior: UltragoalGoal,
1600
+ next: UltragoalGoal,
1601
+ ): UltragoalPipelineOverlapReceipt {
1602
+ const paths = getUltragoalPaths(cwd, currentUltragoalSessionId(cwd));
1603
+ return {
1604
+ ok: true,
1605
+ event,
1606
+ overlap_id: overlapId,
1607
+ prior_goal_id: prior.id,
1608
+ next_goal_id: next.id,
1609
+ status: next.pipelineMetadata?.overlap,
1610
+ next_goal_status: next.status,
1611
+ goals_path: paths.goalsPath,
1612
+ ledger_path: paths.ledgerPath,
1613
+ };
1614
+ }
1615
+
1616
+ export async function startUltragoalPipelineOverlap(input: {
1617
+ cwd: string;
1618
+ priorGoalId: string;
1619
+ nextGoalId: string;
1620
+ reviewHandles: JsonObject | JsonObject[];
1621
+ qaHandles: JsonObject | JsonObject[];
1622
+ implementationHandle: JsonObject;
1623
+ }): Promise<UltragoalPipelineOverlapReceipt> {
1624
+ const plan = await readUltragoalPlan(input.cwd);
1625
+ if (!plan) throw new Error("No ultragoal plan found. Run `skc ultragoal create-goals --brief ...` first.");
1626
+ const prior = plan.goals.find(goal => goal.id === input.priorGoalId);
1627
+ const next = plan.goals.find(goal => goal.id === input.nextGoalId);
1628
+ if (!prior || !next) throw new Error("start-pipeline-overlap requires existing prior and next goal ids");
1629
+ const reviewHandles = requireJsonObjectOrArrayValue(input.reviewHandles, "review handles");
1630
+ const qaHandles = requireJsonObjectOrArrayValue(input.qaHandles, "QA handles");
1631
+ requireJsonObjectValue(input.implementationHandle, "implementation handle");
1632
+ requirePipelineStartable(plan, prior, next);
1633
+ const now = new Date().toISOString();
1634
+ const overlapId = `pipeline-${crypto.randomUUID()}`;
1635
+ const priorMetadata = requireFreshPipelineMetadata(prior);
1636
+ const nextMetadata = requireFreshPipelineMetadata(next);
1637
+ const priorOpenMetadata = {
1638
+ ...priorMetadata,
1639
+ overlap: "open" as const,
1640
+ overlapId,
1641
+ priorGoalId: prior.id,
1642
+ nextGoalId: next.id,
1643
+ };
1644
+ const nextOpenMetadata = {
1645
+ ...nextMetadata,
1646
+ overlap: "open" as const,
1647
+ overlapId,
1648
+ priorGoalId: prior.id,
1649
+ nextGoalId: next.id,
1650
+ };
1651
+ prior.pipelineMetadata = { ...priorOpenMetadata, metadataHash: hashPipelineMetadata(priorOpenMetadata) };
1652
+ next.pipelineMetadata = { ...nextOpenMetadata, metadataHash: hashPipelineMetadata(nextOpenMetadata) };
1653
+ prior.updatedAt = now;
1654
+ next.updatedAt = now;
1655
+ next.status = "active";
1656
+ next.startedAt = next.startedAt ?? now;
1657
+ plan.updatedAt = now;
1658
+ await writePlan(input.cwd, plan);
1659
+ const refs = pipelineEventRefs(prior, next);
1660
+ const expectedReviewHandleIds = handleIdsFromValue(reviewHandles, "review");
1661
+ const expectedQaHandleIds = handleIdsFromValue(qaHandles, "QA");
1662
+ await appendLedger(input.cwd, {
1663
+ event: "pipeline_overlap_started",
1664
+ eventId: crypto.randomUUID(),
1665
+ timestamp: now,
1666
+ schemaVersion: 1,
1667
+ overlapId,
1668
+ priorGoalId: prior.id,
1669
+ nextGoalId: next.id,
1670
+ reviewHandles,
1671
+ reviewHandleIds: expectedReviewHandleIds,
1672
+ qaHandles,
1673
+ qaHandleIds: expectedQaHandleIds,
1674
+ implementationHandle: input.implementationHandle,
1675
+ ...refs,
1676
+ });
1677
+ await appendLedger(input.cwd, { event: "goal_started", goalId: next.id, pipelineOverlapId: overlapId });
1678
+ return pipelineReceipt(input.cwd, "pipeline_overlap_started", overlapId, prior, next);
1679
+ }
1680
+
1681
+ function resultStatus(value: JsonObject, fieldName: string): string {
1682
+ const status = nonEmptyString(value.status) ?? nonEmptyString(value.verdict) ?? nonEmptyString(value.result);
1683
+ if (!status) throw new Error(`${fieldName} requires status, verdict, or result`);
1684
+ return status.toLowerCase();
1685
+ }
1686
+
1687
+ function requireCleanPipelineResult(result: JsonObject, expectedHandleIds: readonly string[], fieldName: string): void {
1688
+ const status = resultStatus(result, fieldName);
1689
+ if (!["passed", "pass", "approved", "clear"].includes(status)) throw new Error(`${fieldName} did not pass`);
1690
+ const evidence = nonEmptyString(result.evidence);
1691
+ if (!evidence || !isSubstantiveEvidence(evidence)) throw new Error(`${fieldName} requires substantive evidence`);
1692
+ requireCoveredHandles(expectedHandleIds, resultHandleIds(result, fieldName), fieldName);
1693
+ if (collectPipelineBlockerFootprints(result, fieldName).length > 0)
1694
+ throw new Error(`${fieldName} cannot clean-join with blockers`);
1695
+ }
1696
+
1697
+ function pipelineStartEventHandleIds(
1698
+ ledger: UltragoalLedgerEvent[],
1699
+ overlapId: string,
1700
+ ): { review: string[]; qa: string[] } {
1701
+ const event = ledger.find(row => row.event === "pipeline_overlap_started" && row.overlapId === overlapId) as
1702
+ | JsonObject
1703
+ | undefined;
1704
+ if (!event) throw new Error(`No pipeline_overlap_started event found for ${overlapId}`);
1705
+ const review =
1706
+ stringArray(event.reviewHandleIds) ??
1707
+ handleIdsFromValue(requireJsonObjectOrArrayValue(event.reviewHandles, "review handles"), "review");
1708
+ const qa =
1709
+ stringArray(event.qaHandleIds) ??
1710
+ handleIdsFromValue(requireJsonObjectOrArrayValue(event.qaHandles, "QA handles"), "QA");
1711
+ return { review, qa };
1712
+ }
1713
+
1714
+ export async function joinUltragoalPipelineOverlap(input: {
1715
+ cwd: string;
1716
+ overlapId: string;
1717
+ reviewResult: JsonObject;
1718
+ qaResult: JsonObject;
1719
+ }): Promise<UltragoalPipelineOverlapReceipt> {
1720
+ const plan = await readUltragoalPlan(input.cwd);
1721
+ if (!plan) throw new Error("No ultragoal plan found. Run `skc ultragoal create-goals --brief ...` first.");
1722
+ const overlap = openPipelineOverlap(plan);
1723
+ if (!overlap || overlap.overlapId !== input.overlapId)
1724
+ throw new Error(`No open pipeline overlap found for ${input.overlapId}`);
1725
+ const { prior, next, overlapId } = overlap;
1726
+ const nextMetadata = requireFreshPipelineMetadata(next);
1727
+ const ledger = await readUltragoalLedger(input.cwd);
1728
+ const expectedHandles = pipelineStartEventHandleIds(ledger, overlapId);
1729
+ const reviewBlockers = collectPipelineBlockerFootprints(input.reviewResult, "review result");
1730
+ const qaBlockers = collectPipelineBlockerFootprints(input.qaResult, "QA result");
1731
+ const blockerFootprints = [...reviewBlockers, ...qaBlockers];
1732
+ let state: UltragoalPipelineOverlapState;
1733
+ let event: UltragoalPipelineLedgerEventName;
1734
+ if (blockerFootprints.length === 0) {
1735
+ try {
1736
+ requireCleanPipelineResult(input.reviewResult, expectedHandles.review, "review result");
1737
+ requireCleanPipelineResult(input.qaResult, expectedHandles.qa, "QA result");
1738
+ state = "joined_clean";
1739
+ event = "pipeline_overlap_joined";
1740
+ } catch {
1741
+ state = "quarantine_required";
1742
+ event = "pipeline_overlap_quarantined";
1743
+ }
1744
+ } else if (blockerFootprints.every(footprint => !targetsOverlap(footprint, nextMetadata.targets))) {
1745
+ state = "blocked_disjoint_continue";
1746
+ event = "pipeline_overlap_joined";
1747
+ } else {
1748
+ state = "quarantine_required";
1749
+ event = "pipeline_overlap_quarantined";
1750
+ }
1751
+ const now = new Date().toISOString();
1752
+ for (const goal of [prior, next]) {
1753
+ const metadata = requireFreshPipelineMetadata(goal);
1754
+ const joinedMetadata = { ...metadata, overlap: state, blockerFootprints };
1755
+ goal.pipelineMetadata = { ...joinedMetadata, metadataHash: hashPipelineMetadata(joinedMetadata) };
1756
+ goal.updatedAt = now;
1757
+ }
1758
+ if (state === "quarantine_required") next.status = "blocked";
1759
+ plan.updatedAt = now;
1760
+ await writePlan(input.cwd, plan);
1761
+ await appendLedger(input.cwd, {
1762
+ event,
1763
+ eventId: crypto.randomUUID(),
1764
+ timestamp: now,
1765
+ schemaVersion: 1,
1766
+ overlapId,
1767
+ priorGoalId: prior.id,
1768
+ nextGoalId: next.id,
1769
+ status: state,
1770
+ reviewResult: input.reviewResult,
1771
+ qaResult: input.qaResult,
1772
+ blockerFootprints,
1773
+ ...pipelineEventRefs(prior, next),
1774
+ });
1775
+ return pipelineReceipt(input.cwd, event, overlapId, prior, next);
1776
+ }
1777
+
1778
+ export async function rebaselineUltragoalPipelineOverlap(input: {
1779
+ cwd: string;
1780
+ overlapId: string;
1781
+ goalId: string;
1782
+ evidence: string;
1783
+ targetState: JsonObject;
1784
+ }): Promise<UltragoalPipelineOverlapReceipt> {
1785
+ const plan = await readUltragoalPlan(input.cwd);
1786
+ if (!plan) throw new Error("No ultragoal plan found. Run `skc ultragoal create-goals --brief ...` first.");
1787
+ const goal = plan.goals.find(item => item.id === input.goalId);
1788
+ if (!goal) throw new Error(`No ultragoal goal found for ${input.goalId}.`);
1789
+ const evidence = input.evidence.trim();
1790
+ if (!isSubstantiveEvidence(evidence)) throw new Error("rebaseline-pipeline-overlap requires substantive evidence");
1791
+ const targetState = requireNonEmptyPipelineTargets(input.targetState, "target state");
1792
+ const metadata = requireFreshPipelineMetadata(goal);
1793
+ if (metadata.overlap !== "quarantine_required" || metadata.overlapId !== input.overlapId) {
1794
+ throw new Error(`Goal ${goal.id} is not quarantined for overlap ${input.overlapId}`);
1795
+ }
1796
+ for (const footprint of metadata.blockerFootprints ?? []) {
1797
+ if (targetsOverlap(footprint, targetState))
1798
+ throw new Error("rebaseline-pipeline-overlap target state overlaps unresolved blocker footprints");
1799
+ }
1800
+ const now = new Date().toISOString();
1801
+ const rebaselinedMetadata = { ...metadata, overlap: "rebaseline_complete" as const, targets: targetState };
1802
+ goal.pipelineMetadata = { ...rebaselinedMetadata, metadataHash: hashPipelineMetadata(rebaselinedMetadata) };
1803
+ goal.status = "active";
1804
+ goal.evidence = evidence;
1805
+ goal.updatedAt = now;
1806
+ plan.updatedAt = now;
1807
+ await writePlan(input.cwd, plan);
1808
+ const peer = pipelinePeer(plan, metadata);
1809
+ await appendLedger(input.cwd, {
1810
+ event: "pipeline_overlap_rebaselined",
1811
+ eventId: crypto.randomUUID(),
1812
+ timestamp: now,
1813
+ schemaVersion: 1,
1814
+ overlapId: input.overlapId,
1815
+ priorGoalId: metadata.priorGoalId ?? peer?.id ?? "",
1816
+ nextGoalId: metadata.nextGoalId ?? goal.id,
1817
+ goalId: goal.id,
1818
+ evidence,
1819
+ targetState,
1820
+ metadataHash: goal.pipelineMetadata.metadataHash,
1821
+ });
1822
+ const paths = getUltragoalPaths(input.cwd, currentUltragoalSessionId(input.cwd));
1823
+ return {
1824
+ ok: true,
1825
+ event: "pipeline_overlap_rebaselined",
1826
+ overlap_id: input.overlapId,
1827
+ prior_goal_id: metadata.priorGoalId ?? peer?.id ?? "",
1828
+ goal_id: goal.id,
1829
+ status: goal.pipelineMetadata.overlap,
1830
+ goals_path: paths.goalsPath,
1831
+ ledger_path: paths.ledgerPath,
1832
+ };
1833
+ }
869
1834
 
870
1835
  export function getUltragoalRunCompletionState(
871
1836
  plan: UltragoalPlan,
@@ -1080,6 +2045,7 @@ interface UltragoalChangeSet extends JsonObject {
1080
2045
  mergeBase?: string;
1081
2046
  paths: UltragoalChangeSetPath[];
1082
2047
  rawDiffStat?: string;
2048
+ rawDiff?: string;
1083
2049
  trusted: true;
1084
2050
  }
1085
2051
 
@@ -1092,11 +2058,16 @@ const MANDATORY_COMPUTER_CASE_IDS = [
1092
2058
  "runaway-loop-halt",
1093
2059
  "blast-radius",
1094
2060
  ] as const;
2061
+ const TOOLS_INDEX_PATH = "packages/coding-agent/src/tools/index.ts";
1095
2062
 
1096
2063
  function normalizeRepoPath(value: string): string {
1097
2064
  return value.replaceAll("\\\\", "/").replace(/^\.\//, "");
1098
2065
  }
1099
2066
 
2067
+ function isToolsIndexPath(value: string): boolean {
2068
+ return normalizeRepoPath(value) === TOOLS_INDEX_PATH;
2069
+ }
2070
+
1100
2071
  function categorizeComputerChangePath(value: string): UltragoalChangeCategory {
1101
2072
  const normalized = normalizeRepoPath(value);
1102
2073
  if (normalized.startsWith("crates/pi-natives/src/computer/")) return "code";
@@ -1107,7 +2078,6 @@ function categorizeComputerChangePath(value: string): UltragoalChangeCategory {
1107
2078
  )
1108
2079
  return "tool";
1109
2080
  if (
1110
- normalized === "packages/coding-agent/src/tools/index.ts" ||
1111
2081
  normalized === "packages/coding-agent/src/tools/renderers.ts" ||
1112
2082
  normalized === "packages/coding-agent/src/config/settings-schema.ts"
1113
2083
  )
@@ -1125,18 +2095,76 @@ function categorizeComputerChangePath(value: string): UltragoalChangeCategory {
1125
2095
  function isComputerControlSurfaceCategory(category: UltragoalChangeCategory): boolean {
1126
2096
  // The computer-use red-team suite is conditional, not universal (see the
1127
2097
  // ultragoal SKILL): require it only when the change actually touches
1128
- // computer-control source — the computer tool (`tool`), its settings/registry
1129
- // wiring (`settings-registry`), or computer Rust (`code`). A bare regeneration
1130
- // of the SHARED native binding (`generated-binding`: packages/natives/native/
1131
- // index.{d.ts,js}) is NOT by itself a computer-use change: that file is
1132
- // generated from Rust, so any real computer-use behavior change must also
1133
- // touch one of the categories above and will still trigger the suite. Treating
1134
- // the regenerated aggregate binding as a computer surface forced the suite on
1135
- // unrelated features (e.g. notifications), which the SKILL explicitly warns
1136
- // against, so it is excluded here.
2098
+ // computer-control source — the computer tool (`tool`), its behavior-bearing
2099
+ // settings/renderer wiring (`settings-registry`), or computer Rust (`code`).
2100
+ // A bare regeneration of the SHARED native binding (`generated-binding`:
2101
+ // packages/natives/native/index.{d.ts,js}) is NOT by itself a computer-use
2102
+ // change: that file is generated from Rust, so any real computer-use behavior
2103
+ // change must also touch one of the categories above and will still trigger
2104
+ // the suite. Treating aggregate binding or registration files as a computer
2105
+ // surface forced the suite on unrelated changes, which the SKILL explicitly
2106
+ // warns against, so they are excluded here.
1137
2107
  return category === "code" || category === "tool" || category === "settings-registry";
1138
2108
  }
1139
2109
 
2110
+ function isComputerSpecificToolsIndexDiff(diff: string | undefined, targetPath: string): boolean {
2111
+ if (!diff || !isToolsIndexPath(targetPath)) return false;
2112
+ let inTargetFile = false;
2113
+ for (const line of diff.split("\n")) {
2114
+ if (line.startsWith("diff --git ")) {
2115
+ const match = /^diff --git a\/(.+?) b\/(.+)$/.exec(line);
2116
+ inTargetFile = !!match && (isToolsIndexPath(match[1]!) || isToolsIndexPath(match[2]!));
2117
+ continue;
2118
+ }
2119
+ if (!inTargetFile || line.startsWith("+++") || line.startsWith("---")) continue;
2120
+ if (!line.startsWith("+") && !line.startsWith("-")) continue;
2121
+ const changedLine = line.slice(1);
2122
+ if (
2123
+ /\bComputerTool\b/.test(changedLine) ||
2124
+ /\bisComputerCallable\b/.test(changedLine) ||
2125
+ /\bisComputerLoadablePlatform\b/.test(changedLine) ||
2126
+ /["']computer["']/.test(changedLine) ||
2127
+ /["']\.\/computer["']/.test(changedLine) ||
2128
+ /\bcomputer\s*:/.test(changedLine)
2129
+ ) {
2130
+ return true;
2131
+ }
2132
+ }
2133
+ return false;
2134
+ }
2135
+
2136
+ /** Settings registry file that holds ALL settings, most of them unrelated to computer control. */
2137
+ const SETTINGS_SCHEMA_PATH = "packages/coding-agent/src/config/settings-schema.ts";
2138
+
2139
+ function isSettingsSchemaPath(value: string): boolean {
2140
+ return normalizeRepoPath(value) === SETTINGS_SCHEMA_PATH;
2141
+ }
2142
+
2143
+ /**
2144
+ * The settings registry holds every setting (themes, tool output sizes, retry
2145
+ * knobs, …), so a bare `settings-schema.ts` edit is NOT by itself a computer
2146
+ * change. Mirror {@link isComputerSpecificToolsIndexDiff}: only treat it as a
2147
+ * computer-control surface when the diff actually adds/removes a `computer.*`
2148
+ * setting key. When no diff is available, callers fall back to the conservative
2149
+ * (fail-closed) categorization instead of this narrowing.
2150
+ */
2151
+ function isComputerSpecificSettingsDiff(diff: string | undefined, targetPath: string): boolean {
2152
+ if (!diff || !isSettingsSchemaPath(targetPath)) return false;
2153
+ let inTargetFile = false;
2154
+ for (const line of diff.split("\n")) {
2155
+ if (line.startsWith("diff --git ")) {
2156
+ const match = /^diff --git a\/(.+?) b\/(.+)$/.exec(line);
2157
+ inTargetFile = !!match && (isSettingsSchemaPath(match[1]!) || isSettingsSchemaPath(match[2]!));
2158
+ continue;
2159
+ }
2160
+ if (!inTargetFile || line.startsWith("+++") || line.startsWith("---")) continue;
2161
+ if (!line.startsWith("+") && !line.startsWith("-")) continue;
2162
+ const changedLine = line.slice(1);
2163
+ if (/["']computer\./.test(changedLine)) return true;
2164
+ }
2165
+ return false;
2166
+ }
2167
+
1140
2168
  function isComputerControlSurfaceChangePath(row: UltragoalChangeSetPath): boolean {
1141
2169
  const category = row.category ?? categorizeComputerChangePath(row.path);
1142
2170
  const oldCategory = row.oldPath ? categorizeComputerChangePath(row.oldPath) : category;
@@ -1145,7 +2173,26 @@ function isComputerControlSurfaceChangePath(row: UltragoalChangeSetPath): boolea
1145
2173
 
1146
2174
  function trustedChangeSetRequiresComputerSuite(changeSet: UltragoalChangeSet | undefined): boolean {
1147
2175
  if (!changeSet?.trusted) return false;
1148
- return changeSet.paths.some(isComputerControlSurfaceChangePath);
2176
+ return changeSet.paths.some(row => {
2177
+ if (isComputerControlSurfaceChangePath(row)) {
2178
+ // The settings registry mixes computer and non-computer settings. Narrow it
2179
+ // with the diff so unrelated settings edits do not force the computer suite;
2180
+ // fall back to the conservative categorization when no diff is available.
2181
+ const touchesSettingsSchema =
2182
+ isSettingsSchemaPath(row.path) || (row.oldPath ? isSettingsSchemaPath(row.oldPath) : false);
2183
+ if (touchesSettingsSchema && changeSet.rawDiff !== undefined) {
2184
+ return (
2185
+ isComputerSpecificSettingsDiff(changeSet.rawDiff, row.path) ||
2186
+ (row.oldPath ? isComputerSpecificSettingsDiff(changeSet.rawDiff, row.oldPath) : false)
2187
+ );
2188
+ }
2189
+ return true;
2190
+ }
2191
+ return (
2192
+ isComputerSpecificToolsIndexDiff(changeSet.rawDiff, row.path) ||
2193
+ (row.oldPath ? isComputerSpecificToolsIndexDiff(changeSet.rawDiff, row.oldPath) : false)
2194
+ );
2195
+ });
1149
2196
  }
1150
2197
 
1151
2198
  function requiresComputerRedTeamSuite(executorQa: JsonObject, changeSet: UltragoalChangeSet | undefined): boolean {
@@ -2393,18 +3440,141 @@ export async function validateExecutorQaRedTeamEvidenceForReview(
2393
3440
  await validateExecutorQaRedTeamEvidenceInternal(cwd, executorQa as JsonObject, options);
2394
3441
  }
2395
3442
 
3443
+ function canonicalChangeSetRows(value: unknown, fieldName: string): UltragoalChangeSetPath[] {
3444
+ if (!Array.isArray(value)) throw new Error(`${fieldName} must be an array`);
3445
+ return value.map((row, index) => {
3446
+ if (typeof row !== "object" || row === null || Array.isArray(row))
3447
+ throw new Error(`${fieldName}[${index}] must be an object`);
3448
+ const record = row as JsonObject;
3449
+ const pathValue = nonEmptyString(record.path);
3450
+ if (!pathValue) throw new Error(`${fieldName}[${index}].path is required`);
3451
+ if ("goalId" in record) throw new Error(`${fieldName}[${index}] must not contain goalId attribution`);
3452
+ const status = nonEmptyString(record.status);
3453
+ if (!status) throw new Error(`${fieldName}[${index}].status is required`);
3454
+ return { path: normalizeRepoPath(pathValue), status: status as UltragoalChangeStatus };
3455
+ });
3456
+ }
3457
+
3458
+ function changeSetHashForPaths(paths: readonly UltragoalChangeSetPath[]): string {
3459
+ return hashStructuredValue(paths.map(row => ({ path: row.path, status: row.status, oldPath: row.oldPath })));
3460
+ }
3461
+
3462
+ function requireChangeSetCoverage(
3463
+ expected: UltragoalChangeSet | undefined,
3464
+ declared: readonly UltragoalChangeSetPath[],
3465
+ fieldName: string,
3466
+ ): void {
3467
+ if (!expected) return;
3468
+ const declaredExactKeys = new Set(declared.map(row => `${row.oldPath ?? ""}\u0000${row.path}\u0000${row.status}`));
3469
+ const declaredPathKeys = new Set(declared.map(row => `${row.oldPath ?? ""}\u0000${row.path}`));
3470
+ for (const row of expected.paths) {
3471
+ const pathKey = `${row.oldPath ?? ""}\u0000${row.path}`;
3472
+ const exactKey = `${pathKey}\u0000${row.status}`;
3473
+ const covered = row.status === "unknown" ? declaredPathKeys.has(pathKey) : declaredExactKeys.has(exactKey);
3474
+ if (!covered) throw new Error(`${fieldName} does not cover computed checkpoint change-set path ${row.path}`);
3475
+ }
3476
+ }
3477
+
3478
+ function requireValidationBatchTuple(
3479
+ metadata: UltragoalValidationBatchMetadata,
3480
+ record: JsonObject,
3481
+ fieldName: string,
3482
+ ): void {
3483
+ if (record.schemaVersion !== 1) throw new Error(`${fieldName}.schemaVersion must be 1`);
3484
+ if (record.batchId !== metadata.batchId) throw new Error(`${fieldName}.batchId must match durable validationBatch`);
3485
+ if (record.finalGoalId !== metadata.finalGoalId)
3486
+ throw new Error(`${fieldName}.finalGoalId must match durable validationBatch`);
3487
+ if (record.metadataHash !== metadata.metadataHash)
3488
+ throw new Error(`${fieldName}.metadataHash must match durable validationBatch`);
3489
+ const memberIds = stringArray(record.memberIds);
3490
+ if (
3491
+ !memberIds ||
3492
+ memberIds.length !== metadata.memberIds.length ||
3493
+ memberIds.some((id, index) => id !== metadata.memberIds[index])
3494
+ ) {
3495
+ throw new Error(`${fieldName}.memberIds must match durable validationBatch order`);
3496
+ }
3497
+ }
3498
+
3499
+ function validateDeferredCompletionQualityGate(
3500
+ gate: JsonObject,
3501
+ goal: UltragoalGoal,
3502
+ metadata: UltragoalValidationBatchMetadata,
3503
+ changeSet?: UltragoalChangeSet,
3504
+ ): void {
3505
+ const allowedKeys = new Set(["deferredToBatch"]);
3506
+ const unsupportedKeys = Object.keys(gate).filter(key => !allowedKeys.has(key));
3507
+ if (unsupportedKeys.length > 0)
3508
+ throw new Error(`deferred qualityGate contains unsupported keys: ${unsupportedKeys.join(", ")}`);
3509
+ const deferred = qualityGateObject(gate.deferredToBatch);
3510
+ if (!deferred) throw new Error("deferred qualityGate requires deferredToBatch object");
3511
+ if (deferred.kind !== "validation-batch-deferred")
3512
+ throw new Error("deferredToBatch.kind must be validation-batch-deferred");
3513
+ requireValidationBatchTuple(metadata, deferred, "deferredToBatch");
3514
+ if (goal.id === metadata.finalGoalId)
3515
+ throw new Error("final validation batch goal cannot use deferredToBatch quality gate");
3516
+ const deferredLanes = stringArray(deferred.deferredLanes)?.filter(Boolean).sort();
3517
+ if (deferredLanes?.join(",") !== "architectReview,executorQa")
3518
+ throw new Error("deferredToBatch.deferredLanes must be architectReview and executorQa");
3519
+ const targeted = qualityGateObject(deferred.targetedVerification);
3520
+ if (!targeted || targeted.status !== PASSED_STATUS || !nonEmptyStringArray(targeted.commands))
3521
+ throw new Error("deferredToBatch.targetedVerification must pass with non-empty commands");
3522
+ requireNonEmptyString(targeted.evidence, "deferredToBatch.targetedVerification.evidence");
3523
+ const cleaner = qualityGateObject(deferred.aiSlopCleaner);
3524
+ if (!cleaner || cleaner.status !== PASSED_STATUS) throw new Error("deferredToBatch.aiSlopCleaner must pass");
3525
+ requireNonEmptyString(cleaner.evidence, "deferredToBatch.aiSlopCleaner.evidence");
3526
+ const iteration = qualityGateObject(deferred.iteration);
3527
+ if (!iteration || iteration.status !== PASSED_STATUS || iteration.fullRerun !== true)
3528
+ throw new Error("deferredToBatch.iteration must pass with fullRerun true");
3529
+ if (!nonEmptyStringArray(iteration.rerunCommands))
3530
+ throw new Error("deferredToBatch.iteration.rerunCommands must be non-empty");
3531
+ requireNonEmptyString(iteration.evidence, "deferredToBatch.iteration.evidence");
3532
+ requireEmptyBlockers(iteration.blockers, "deferredToBatch.iteration.blockers");
3533
+ const declaredChangeSet = qualityGateObject(deferred.changeSet);
3534
+ if (!declaredChangeSet) throw new Error("deferredToBatch.changeSet is required");
3535
+ if (declaredChangeSet.memberGoalId !== goal.id)
3536
+ throw new Error("deferredToBatch.changeSet.memberGoalId must label the checkpointed goal");
3537
+ if (declaredChangeSet.cumulativeFromBase !== true)
3538
+ throw new Error("deferredToBatch.changeSet.cumulativeFromBase must be true");
3539
+ const paths = canonicalChangeSetRows(declaredChangeSet.paths, "deferredToBatch.changeSet.paths");
3540
+ requireChangeSetCoverage(changeSet, paths, "deferredToBatch.changeSet.paths");
3541
+ if (declaredChangeSet.changeSetHash !== changeSetHashForPaths(paths))
3542
+ throw new Error("deferredToBatch.changeSet.changeSetHash does not match declared paths");
3543
+ }
2396
3544
  async function validateCompletionQualityGate(
2397
3545
  cwd: string,
2398
3546
  gate: JsonObject,
2399
- options: { changeSet?: UltragoalChangeSet } = {},
3547
+ options: {
3548
+ changeSet?: UltragoalChangeSet;
3549
+ plan?: UltragoalPlan;
3550
+ goal?: UltragoalGoal;
3551
+ ledger?: readonly UltragoalLedgerEvent[];
3552
+ } = {},
2400
3553
  ): Promise<void> {
3554
+ const batchMode = options.goal?.validationBatch;
3555
+ if (batchMode && options.goal && options.goal.id !== batchMode.finalGoalId) {
3556
+ validateDeferredCompletionQualityGate(gate, options.goal, batchMode, options.changeSet);
3557
+ return;
3558
+ }
3559
+ if (batchMode && options.goal && options.goal.id === batchMode.finalGoalId) {
3560
+ const allowedKeys = new Set(["architectReview", "executorQa", "iteration", "validationBatchClose"]);
3561
+ const unsupportedKeys = Object.keys(gate).filter(key => !allowedKeys.has(key));
3562
+ if (unsupportedKeys.length > 0)
3563
+ throw new Error(`qualityGate contains unsupported keys: ${unsupportedKeys.join(", ")}`);
3564
+ if (!qualityGateObject(gate.validationBatchClose))
3565
+ throw new Error("final validation batch goal requires validationBatchClose");
3566
+ }
2401
3567
  const codeReview = qualityGateObject(gate.codeReview);
2402
3568
  if (codeReview) {
2403
3569
  throw new Error(
2404
3570
  "checkpoint --status complete requires architect review approval through architectReview, executorQa, and iteration quality-gate evidence; legacy codeReview-only gates are not sufficient",
2405
3571
  );
2406
3572
  }
2407
- const allowedKeys = new Set(["architectReview", "executorQa", "iteration"]);
3573
+ const allowedKeys = new Set(
3574
+ batchMode
3575
+ ? ["architectReview", "executorQa", "iteration", "validationBatchClose"]
3576
+ : ["architectReview", "executorQa", "iteration"],
3577
+ );
2408
3578
  const unsupportedKeys = Object.keys(gate).filter(key => !allowedKeys.has(key));
2409
3579
  if (unsupportedKeys.length > 0) {
2410
3580
  throw new Error(`qualityGate contains unsupported keys: ${unsupportedKeys.join(", ")}`);
@@ -2451,12 +3621,105 @@ async function validateCompletionQualityGate(
2451
3621
  }
2452
3622
  requireNonEmptyString(iteration.evidence, "iteration.evidence");
2453
3623
  requireEmptyBlockers(iteration.blockers, "iteration.blockers");
3624
+ if (batchMode && options.goal && options.plan && options.ledger) {
3625
+ validateBatchCloseQualityGate(gate, options.plan, batchMode, options.ledger, options.changeSet);
3626
+ }
2454
3627
  }
2455
3628
 
3629
+ function validateBatchCloseQualityGate(
3630
+ gate: JsonObject,
3631
+ plan: UltragoalPlan,
3632
+ metadata: UltragoalValidationBatchMetadata,
3633
+ ledger: readonly UltragoalLedgerEvent[],
3634
+ changeSet?: UltragoalChangeSet,
3635
+ ): void {
3636
+ const close = qualityGateObject(gate.validationBatchClose);
3637
+ if (!close) throw new Error("validationBatchClose is required");
3638
+ if (close.schemaVersion !== 1 || close.kind !== "validation-batch-close")
3639
+ throw new Error("validationBatchClose.kind must be validation-batch-close");
3640
+ if (close.batchId !== metadata.batchId || close.finalGoalId !== metadata.finalGoalId)
3641
+ throw new Error("validationBatchClose tuple must match durable validationBatch");
3642
+ const memberIds = stringArray(close.memberIds);
3643
+ if (
3644
+ !memberIds ||
3645
+ memberIds.length !== metadata.memberIds.length ||
3646
+ memberIds.some((id, index) => id !== metadata.memberIds[index])
3647
+ )
3648
+ throw new Error("validationBatchClose.memberIds must match durable validationBatch order");
3649
+ const memberMetadataHashes = qualityGateObject(close.memberMetadataHashes);
3650
+ const memberChangeSetHashes = qualityGateObject(qualityGateObject(close.unionChangeSet)?.memberChangeSetHashes);
3651
+ if (!memberMetadataHashes || !memberChangeSetHashes)
3652
+ throw new Error("validationBatchClose member metadata and change-set hashes are required");
3653
+ const seenReceipts = new Set<string>();
3654
+ const receiptRows = Array.isArray(close.memberReceipts) ? close.memberReceipts : [];
3655
+ const nonFinalIds = metadata.memberIds.filter(memberId => memberId !== metadata.finalGoalId);
3656
+ for (const memberId of metadata.memberIds) {
3657
+ const member = plan.goals.find(item => item.id === memberId);
3658
+ if (!member?.validationBatch) throw new Error(`validationBatchClose references missing batch member ${memberId}`);
3659
+ if (member.validationBatch.metadataHash !== memberMetadataHashes[memberId])
3660
+ throw new Error(`validationBatchClose.memberMetadataHashes.${memberId} does not match durable metadata`);
3661
+ if (memberId !== metadata.finalGoalId && member.status !== "complete")
3662
+ throw new Error(`validationBatchClose cannot close before ${memberId} is complete`);
3663
+ }
3664
+ if (receiptRows.length !== nonFinalIds.length)
3665
+ throw new Error("validationBatchClose.memberReceipts must list every non-final member exactly once");
3666
+ for (const row of receiptRows) {
3667
+ if (typeof row !== "object" || row === null || Array.isArray(row))
3668
+ throw new Error("validationBatchClose.memberReceipts rows must be objects");
3669
+ const record = row as JsonObject;
3670
+ const memberId = nonEmptyString(record.goalId);
3671
+ if (!memberId || !nonFinalIds.includes(memberId))
3672
+ throw new Error("validationBatchClose.memberReceipts contains invalid member goalId");
3673
+ if (seenReceipts.has(memberId))
3674
+ throw new Error(`validationBatchClose.memberReceipts contains duplicate member ${memberId}`);
3675
+ seenReceipts.add(memberId);
3676
+ const member = plan.goals.find(item => item.id === memberId)!;
3677
+ const receipt = requireDeferredMemberReceiptFresh(plan, ledger, member, "validationBatchClose.memberReceipts");
3678
+ if (
3679
+ record.role !== "deferred-member" ||
3680
+ record.receiptId !== receipt.receiptId ||
3681
+ record.qualityGateHash !== receipt.qualityGateHash ||
3682
+ record.changeSetHash !== receipt.validationBatch.changeSetHash ||
3683
+ record.checkpointLedgerEventId !== receipt.checkpointLedgerEventId
3684
+ ) {
3685
+ throw new Error(`validationBatchClose.memberReceipts.${memberId} does not match deferred receipt`);
3686
+ }
3687
+ if (memberChangeSetHashes[memberId] !== receipt.validationBatch.changeSetHash)
3688
+ throw new Error(
3689
+ `validationBatchClose.unionChangeSet.memberChangeSetHashes.${memberId} does not match deferred receipt`,
3690
+ );
3691
+ }
3692
+ if (seenReceipts.size !== nonFinalIds.length)
3693
+ throw new Error("validationBatchClose.memberReceipts is missing a non-final member");
3694
+ const union = qualityGateObject(close.unionChangeSet);
3695
+ if (union?.source !== "validation-batch")
3696
+ throw new Error("validationBatchClose.unionChangeSet.source must be validation-batch");
3697
+ const unionPaths = canonicalChangeSetRows(union.paths, "validationBatchClose.unionChangeSet.paths");
3698
+ requireChangeSetCoverage(changeSet, unionPaths, "validationBatchClose.unionChangeSet.paths");
3699
+ const finalHash = changeSetHashForPaths(unionPaths);
3700
+ if (memberChangeSetHashes[metadata.finalGoalId] !== finalHash)
3701
+ throw new Error(
3702
+ "validationBatchClose.unionChangeSet.memberChangeSetHashes final member hash does not match current change set",
3703
+ );
3704
+ if (
3705
+ union.unionHash !==
3706
+ hashStructuredValue({
3707
+ memberChangeSetHashes,
3708
+ paths: unionPaths.map(row => ({ path: row.path, status: row.status, oldPath: row.oldPath })),
3709
+ })
3710
+ )
3711
+ throw new Error("validationBatchClose.unionChangeSet.unionHash does not match declared union");
3712
+ requireNonEmptyString(close.coverageEvidence, "validationBatchClose.coverageEvidence");
3713
+ }
2456
3714
  async function readRequiredCompletionQualityGate(
2457
3715
  cwd: string,
2458
3716
  value: string | undefined,
2459
- options: { changeSet?: UltragoalChangeSet } = {},
3717
+ options: {
3718
+ changeSet?: UltragoalChangeSet;
3719
+ plan?: UltragoalPlan;
3720
+ goal?: UltragoalGoal;
3721
+ ledger?: readonly UltragoalLedgerEvent[];
3722
+ } = {},
2460
3723
  ): Promise<unknown> {
2461
3724
  if (!value?.trim()) {
2462
3725
  throw new Error(
@@ -2466,97 +3729,73 @@ async function readRequiredCompletionQualityGate(
2466
3729
  const gate = await readStructuredValue(cwd, value);
2467
3730
  const gateObject = qualityGateObject(gate);
2468
3731
  if (!gateObject) throw new Error("qualityGate must be a JSON object");
2469
- await validateCompletionQualityGate(cwd, gateObject, { changeSet: options.changeSet });
3732
+ await validateCompletionQualityGate(cwd, gateObject, {
3733
+ changeSet: options.changeSet,
3734
+ plan: options.plan,
3735
+ goal: options.goal,
3736
+ ledger: options.ledger,
3737
+ });
2470
3738
  return gate;
2471
3739
  }
2472
3740
 
2473
- function snapshotUpdatedAtMilliseconds(value: unknown): number | null {
2474
- if (typeof value === "number" && Number.isFinite(value)) return value;
2475
- if (typeof value !== "string" || value.trim().length === 0) return null;
2476
- const trimmed = value.trim();
2477
- if (/^\d+$/.test(trimmed)) {
2478
- const parsed = Number.parseInt(trimmed, 10);
2479
- return Number.isFinite(parsed) ? parsed : null;
2480
- }
2481
- const parsed = Date.parse(trimmed);
2482
- return Number.isFinite(parsed) ? parsed : null;
2483
- }
2484
-
2485
- function singleSessionLeafId(entries: readonly SessionEntry[]): string | undefined {
2486
- if (entries.length === 0) return undefined;
2487
- const parentIds = new Set(
2488
- entries.map(entry => entry.parentId).filter((parentId): parentId is string => typeof parentId === "string"),
2489
- );
2490
- const leafIds = entries.map(entry => entry.id).filter(id => !parentIds.has(id));
2491
- return leafIds.length === 1 ? leafIds[0] : undefined;
2492
- }
2493
-
2494
- async function readCurrentSessionSkcGoalSnapshot(): Promise<unknown | undefined> {
2495
- const sessionFile = process.env[SKC_SESSION_FILE_ENV]?.trim();
2496
- if (!sessionFile) return undefined;
2497
- const fileEntries = await loadEntriesFromFile(sessionFile);
2498
- const entries = fileEntries.filter((entry): entry is SessionEntry => entry.type !== "session");
2499
- const leafId = singleSessionLeafId(entries);
2500
- if (!leafId) return undefined;
2501
- const context = buildSessionContext(entries, leafId);
2502
- if (context.mode !== "goal" && context.mode !== "goal_paused") return undefined;
2503
- const goal = normalizeGoal(context.modeData?.goal);
2504
- return goal ? { goal } : undefined;
2505
- }
2506
- async function readSkcGoalSnapshot(input: {
2507
- cwd: string;
2508
- value: string | undefined;
2509
- plan: UltragoalPlan;
2510
- goal?: UltragoalGoal;
2511
- required: boolean;
2512
- errorPrefix: string;
2513
- allowCompletedLegacyBlocker?: boolean;
2514
- }): Promise<unknown> {
2515
- const snapshot = input.value?.trim()
2516
- ? await readStructuredValue(input.cwd, input.value)
2517
- : await readCurrentSessionSkcGoalSnapshot();
2518
- if (snapshot === undefined) {
2519
- if (!input.required) return undefined;
3741
+ function validatePipelineCheckpointSafety(
3742
+ plan: UltragoalPlan,
3743
+ goal: UltragoalGoal,
3744
+ changeSet?: UltragoalChangeSet,
3745
+ ): void {
3746
+ const metadata = goal.pipelineMetadata;
3747
+ if (!metadata) return;
3748
+ validateValidationBatchPipelineExclusion(goal);
3749
+ requireFreshPipelineMetadata(goal);
3750
+ if (metadata.overlap === "open") {
2520
3751
  throw new Error(
2521
- `${input.errorPrefix} require an active SKC goal-mode snapshot from the current session or --skc-goal-json; this is the SKC goal-mode receipt, not the .skc/ultragoal/goals.json goal record`,
3752
+ `Cannot complete ${goal.id} while pipeline overlap ${metadata.overlapId ?? ""} is open; join or quarantine first.`,
2522
3753
  );
2523
3754
  }
2524
- const snapshotObject = qualityGateObject(snapshot);
2525
- const detailsObject = qualityGateObject(snapshotObject?.details);
2526
- const goalObject = qualityGateObject(snapshotObject?.goal) ?? qualityGateObject(detailsObject?.goal);
2527
- if (!goalObject)
3755
+ if (metadata.overlap === "quarantine_required") {
2528
3756
  throw new Error(
2529
- `${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`,
3757
+ `Cannot complete ${goal.id} while pipeline overlap ${metadata.overlapId ?? ""} requires rebaseline.`,
2530
3758
  );
2531
- const updatedAt = snapshotUpdatedAtMilliseconds(goalObject.updatedAt);
2532
- if (!updatedAt)
3759
+ }
3760
+ if (metadata.goalId === metadata.priorGoalId && metadata.overlap !== "none" && metadata.overlap !== "joined_clean") {
2533
3761
  throw new Error(
2534
- `${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`,
3762
+ `Cannot complete ${goal.id} without a clean join for pipeline overlap ${metadata.overlapId ?? ""}.`,
2535
3763
  );
2536
- const nowMilliseconds = Date.now();
2537
- if (updatedAt < nowMilliseconds - SKC_GOAL_SNAPSHOT_MAX_AGE_MILLISECONDS) {
2538
- throw new Error(`${input.errorPrefix} require a fresh --skc-goal-json snapshot`);
2539
3764
  }
2540
- if (updatedAt > nowMilliseconds + SKC_GOAL_SNAPSHOT_MAX_FUTURE_SKEW_MILLISECONDS) {
2541
- throw new Error(`${input.errorPrefix} require --skc-goal-json goal.updatedAt that is not from the future`);
2542
- }
2543
- const objective = typeof goalObject.objective === "string" ? goalObject.objective : "";
2544
- const expectedObjectives = new Set([input.plan.skcObjective, ...(input.plan.skcObjectiveAliases ?? [])]);
2545
- if (input.plan.skcGoalMode === "per-story" && input.goal?.objective) {
2546
- expectedObjectives.add(input.goal.objective);
3765
+ const peer = pipelinePeer(plan, metadata);
3766
+ if (changeSet && metadata.overlap !== "none") {
3767
+ const peerTargets = peer?.pipelineMetadata?.targets;
3768
+ for (const row of changeSet.paths) {
3769
+ const ownedByGoal = pipelineTargetsCoverPath(metadata.targets, row.path);
3770
+ const ownedByPeer = peerTargets ? pipelineTargetsCoverPath(peerTargets, row.path) : false;
3771
+ if (ownedByGoal && ownedByPeer)
3772
+ throw new Error(`Cannot complete ${goal.id} with shared pipeline change-set path ${row.path}.`);
3773
+ if (!ownedByGoal && !ownedByPeer)
3774
+ throw new Error(`Cannot complete ${goal.id} with unattributable pipeline change-set path ${row.path}.`);
3775
+ if (!ownedByGoal && ownedByPeer)
3776
+ throw new Error(`Cannot complete ${goal.id} with next-goal pipeline change-set path ${row.path}.`);
3777
+ }
2547
3778
  }
2548
- if (input.allowCompletedLegacyBlocker && goalObject.status === "complete" && !expectedObjectives.has(objective)) {
2549
- return snapshot;
3779
+ }
3780
+
3781
+ function validateCompleteCheckpointTargetGoal(goal: UltragoalGoal): void {
3782
+ if (COMPLETE_CHECKPOINT_ALLOWED_PRE_STATUSES.has(goal.status)) return;
3783
+ if (goal.status === "pending") {
3784
+ throw new Error(
3785
+ `Cannot checkpoint ${goal.id} as complete while its durable goals.json status is pending; start the goal before completing it.`,
3786
+ );
2550
3787
  }
2551
- if (!expectedObjectives.has(objective)) {
3788
+ if (goal.status === "complete") {
2552
3789
  throw new Error(
2553
- `${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"}`,
3790
+ `Cannot checkpoint ${goal.id} as complete with different evidence because its durable goals.json status is already complete.`,
2554
3791
  );
2555
3792
  }
2556
- if (goalObject.status !== "active") {
2557
- throw new Error(`${input.errorPrefix} require --skc-goal-json goal.status to be active`);
3793
+ if (goal.status === "superseded") {
3794
+ throw new Error(`Cannot checkpoint ${goal.id} as complete because its durable goals.json status is superseded.`);
2558
3795
  }
2559
- return snapshot;
3796
+ throw new Error(
3797
+ `Cannot checkpoint ${goal.id} as complete while its durable goals.json status is ${goal.status}; only active or retryable failed goals can be completed.`,
3798
+ );
2560
3799
  }
2561
3800
 
2562
3801
  export async function checkpointUltragoalGoal(input: {
@@ -2564,7 +3803,6 @@ export async function checkpointUltragoalGoal(input: {
2564
3803
  goalId: string;
2565
3804
  status: UltragoalGoalStatus;
2566
3805
  evidence: string;
2567
- skcGoalJson?: string;
2568
3806
  qualityGateJson?: string;
2569
3807
  }): Promise<UltragoalPlan> {
2570
3808
  const plan = await readUltragoalPlan(input.cwd);
@@ -2574,17 +3812,51 @@ export async function checkpointUltragoalGoal(input: {
2574
3812
  const evidence = input.evidence.trim();
2575
3813
  if (!evidence) throw new Error("checkpoint evidence is required");
2576
3814
  const ledgerBefore = await readUltragoalLedger(input.cwd);
2577
- if (
2578
- goal.status === input.status &&
2579
- goal.evidence === evidence &&
2580
- ledgerBefore.some(
2581
- event =>
2582
- event.event === "goal_checkpointed" &&
2583
- event.goalId === goal.id &&
2584
- event.status === input.status &&
2585
- event.evidence === evidence,
2586
- )
2587
- ) {
3815
+ const matchingIdempotentEvent = ledgerBefore.find(
3816
+ event =>
3817
+ event.event === "goal_checkpointed" &&
3818
+ event.goalId === goal.id &&
3819
+ event.status === input.status &&
3820
+ event.evidence === evidence,
3821
+ );
3822
+ const batchMetadata = input.status === "complete" ? requireFreshValidationBatchMetadata(goal) : undefined;
3823
+ if (batchMetadata && goal.completionVerification?.validationBatch) {
3824
+ const receiptBatch = goal.completionVerification.validationBatch;
3825
+ if (receiptBatch.role === "deferred-member" && receiptBatch.metadataHash !== batchMetadata.metadataHash) {
3826
+ throw new Error(`Goal ${goal.id} has stale validation batch completion receipt for ${batchMetadata.batchId}`);
3827
+ }
3828
+ if (
3829
+ receiptBatch.role === "batch-close" &&
3830
+ receiptBatch.memberMetadataHashes[goal.id] !== batchMetadata.metadataHash
3831
+ ) {
3832
+ throw new Error(`Goal ${goal.id} has stale validation batch close receipt for ${batchMetadata.batchId}`);
3833
+ }
3834
+ }
3835
+ if (input.status === "complete" && goal.completionVerification?.validationBatch && !batchMetadata) {
3836
+ throw new Error(`Goal ${goal.id} has stale validation batch completion receipt`);
3837
+ }
3838
+ if (goal.status === input.status && goal.evidence === evidence && matchingIdempotentEvent) {
3839
+ if (batchMetadata) {
3840
+ const receipt = goal.completionVerification;
3841
+ const receiptBatch = receipt?.validationBatch;
3842
+ if (!receipt || !receiptBatch)
3843
+ throw new Error(
3844
+ `Goal ${goal.id} has validation batch ${batchMetadata.batchId} but no matching completion receipt`,
3845
+ );
3846
+ if (receipt.checkpointLedgerEventId !== matchingIdempotentEvent.eventId)
3847
+ throw new Error(`Goal ${goal.id} validation batch receipt does not match prior checkpoint event`);
3848
+ if (hashStructuredValue(matchingIdempotentEvent.qualityGateJson) !== receipt.qualityGateHash)
3849
+ throw new Error(`Goal ${goal.id} validation batch receipt quality gate is stale`);
3850
+ if (receiptBatch.role === "deferred-member" && receiptBatch.metadataHash !== batchMetadata.metadataHash)
3851
+ throw new Error(`Goal ${goal.id} has stale validation batch metadata hash in deferred receipt`);
3852
+ if (receiptBatch.role === "batch-close")
3853
+ requireFreshBatchCloseReceiptBasis(plan, ledgerBefore, goal, receipt, matchingIdempotentEvent);
3854
+ if (
3855
+ receiptBatch.role === "batch-close" &&
3856
+ receiptBatch.memberMetadataHashes[goal.id] !== batchMetadata.metadataHash
3857
+ )
3858
+ throw new Error(`Goal ${goal.id} has stale validation batch metadata hash in close receipt`);
3859
+ }
2588
3860
  // Idempotent re-checkpoint: this goal is already recorded in the target status with the same
2589
3861
  // evidence, so skip the plan rewrite and ledger append to avoid duplicate goal_checkpointed
2590
3862
  // events. The ledger is the dedup source of truth because it is exactly what a duplicate write
@@ -2594,9 +3866,18 @@ export async function checkpointUltragoalGoal(input: {
2594
3866
  return plan;
2595
3867
  }
2596
3868
  const changeSet = input.status === "complete" ? await computeCheckpointChangeSet(input.cwd) : undefined;
3869
+ if (input.status === "complete") {
3870
+ validatePipelineCheckpointSafety(plan, goal, changeSet);
3871
+ validateCompleteCheckpointTargetGoal(goal);
3872
+ }
2597
3873
  const qualityGateJson =
2598
3874
  input.status === "complete"
2599
- ? await readRequiredCompletionQualityGate(input.cwd, input.qualityGateJson, { changeSet })
3875
+ ? await readRequiredCompletionQualityGate(input.cwd, input.qualityGateJson, {
3876
+ changeSet,
3877
+ plan,
3878
+ goal,
3879
+ ledger: ledgerBefore,
3880
+ })
2600
3881
  : input.qualityGateJson
2601
3882
  ? await readStructuredValue(input.cwd, input.qualityGateJson)
2602
3883
  : undefined;
@@ -2615,25 +3896,6 @@ export async function checkpointUltragoalGoal(input: {
2615
3896
  }
2616
3897
  }
2617
3898
  const receiptKind = input.status === "complete" ? chooseReceiptKind(plan, goal, input.status) : null;
2618
- const skcGoalJson =
2619
- input.status === "complete"
2620
- ? await readSkcGoalSnapshot({
2621
- cwd: input.cwd,
2622
- value: input.skcGoalJson,
2623
- plan,
2624
- goal,
2625
- required: true,
2626
- errorPrefix: "complete checkpoints",
2627
- })
2628
- : await readSkcGoalSnapshot({
2629
- cwd: input.cwd,
2630
- value: input.skcGoalJson,
2631
- plan,
2632
- goal,
2633
- required: false,
2634
- errorPrefix: `${input.status} checkpoints`,
2635
- allowCompletedLegacyBlocker: input.status === "blocked",
2636
- });
2637
3899
  const pendingCheckpointEventId = crypto.randomUUID();
2638
3900
  if (input.status === "complete" && receiptKind && qualityGateJson && !Array.isArray(qualityGateJson)) {
2639
3901
  goal.completionVerification = buildCompletionReceipt({
@@ -2643,7 +3905,6 @@ export async function checkpointUltragoalGoal(input: {
2643
3905
  receiptKind,
2644
3906
  beforeStatus,
2645
3907
  qualityGateJson: qualityGateJson as JsonObject,
2646
- skcGoalJson: skcGoalJson as JsonObject,
2647
3908
  now,
2648
3909
  checkpointLedgerEventId: pendingCheckpointEventId,
2649
3910
  });
@@ -2662,7 +3923,6 @@ export async function checkpointUltragoalGoal(input: {
2662
3923
  goalId: goal.id,
2663
3924
  status: input.status,
2664
3925
  evidence,
2665
- skcGoalJson,
2666
3926
  qualityGateJson,
2667
3927
  completionVerification: goal.completionVerification,
2668
3928
  });
@@ -2682,7 +3942,6 @@ export async function checkpointAndContinueUltragoalGoal(input: {
2682
3942
  goalId: string;
2683
3943
  status: UltragoalGoalStatus;
2684
3944
  evidence: string;
2685
- skcGoalJson?: string;
2686
3945
  qualityGateJson?: string;
2687
3946
  advanceNext?: boolean;
2688
3947
  retryFailed?: boolean;
@@ -2866,6 +4125,7 @@ async function addUltragoalSubgoalToPlan(input: {
2866
4125
  createdAt: now,
2867
4126
  updatedAt: now,
2868
4127
  steering: { kind, evidence, rationale },
4128
+ pipelineMetadata: legacyPipelineMetadata(nextId),
2869
4129
  });
2870
4130
  input.plan.updatedAt = now;
2871
4131
  await writePlan(input.cwd, input.plan);
@@ -2907,6 +4167,8 @@ async function splitUltragoalSubgoal(input: {
2907
4167
  });
2908
4168
  const target = findGoalOrThrow(input.plan, input.goalId, kind);
2909
4169
  requireGoalStatus(target, ["pending"], kind);
4170
+ const ledger = await readUltragoalLedger(input.cwd);
4171
+ requireValidationBatchSteeringAllowed(input.plan, target, kind, ledger);
2910
4172
  const replacements = parseReplacementSpecs(input.replacementsJson, kind);
2911
4173
  const now = new Date().toISOString();
2912
4174
  const replacementGoalIds = replacements.map((_, index) => nextUltragoalGoalId(input.plan, index + 1));
@@ -2914,6 +4176,8 @@ async function splitUltragoalSubgoal(input: {
2914
4176
  target.evidence = evidence;
2915
4177
  target.updatedAt = now;
2916
4178
  target.steering = { kind, evidence, rationale, replacementGoalIds };
4179
+ invalidatePipelineMetadata(target, "split_subgoal_superseded", now);
4180
+ clearValidationBatchForBatch(input.plan, target.validationBatch);
2917
4181
  const replacementGoals = replacements.map(
2918
4182
  (replacement, index): UltragoalGoal => ({
2919
4183
  id: replacementGoalIds[index]!,
@@ -2923,6 +4187,7 @@ async function splitUltragoalSubgoal(input: {
2923
4187
  createdAt: now,
2924
4188
  updatedAt: now,
2925
4189
  steering: { kind: "split_replacement", sourceGoalId: target.id, evidence, rationale },
4190
+ pipelineMetadata: legacyPipelineMetadata(replacementGoalIds[index]!),
2926
4191
  }),
2927
4192
  );
2928
4193
  const targetIndex = input.plan.goals.findIndex(goal => goal.id === target.id);
@@ -3000,6 +4265,8 @@ async function revisePendingUltragoalWording(input: {
3000
4265
  });
3001
4266
  const goal = findGoalOrThrow(input.plan, input.goalId, kind);
3002
4267
  requireGoalStatus(goal, ["pending"], kind);
4268
+ const ledger = await readUltragoalLedger(input.cwd);
4269
+ requireValidationBatchSteeringAllowed(input.plan, goal, kind, ledger);
3003
4270
  const title = input.title === undefined ? undefined : input.title.trim();
3004
4271
  const objective = input.objective === undefined ? undefined : input.objective.trim();
3005
4272
  if (input.title !== undefined && !title)
@@ -3019,6 +4286,8 @@ async function revisePendingUltragoalWording(input: {
3019
4286
  const now = new Date().toISOString();
3020
4287
  goal.updatedAt = now;
3021
4288
  goal.steering = { kind, evidence, rationale, changedFields };
4289
+ invalidatePipelineMetadata(goal, "revised_pending_wording", now);
4290
+ clearValidationBatchForBatch(input.plan, goal.validationBatch);
3022
4291
  input.plan.updatedAt = now;
3023
4292
  await writePlan(input.cwd, input.plan);
3024
4293
  await appendLedger(input.cwd, {
@@ -3063,6 +4332,8 @@ async function markBlockedUltragoalSuperseded(input: {
3063
4332
  });
3064
4333
  const goal = findGoalOrThrow(input.plan, input.goalId, kind);
3065
4334
  requireGoalStatus(goal, ["blocked", "review_blocked"], kind);
4335
+ const ledger = await readUltragoalLedger(input.cwd);
4336
+ requireValidationBatchSteeringAllowed(input.plan, goal, kind, ledger);
3066
4337
  const remainingRequiredGoals = requiredUltragoalGoals(input.plan).filter(item => item.id !== goal.id);
3067
4338
  if (remainingRequiredGoals.length === 0) {
3068
4339
  throw new Error(`steer ${kind} cannot supersede ${goal.id} because it is the only remaining required goal`);
@@ -3072,6 +4343,7 @@ async function markBlockedUltragoalSuperseded(input: {
3072
4343
  goal.evidence = evidence;
3073
4344
  goal.updatedAt = now;
3074
4345
  goal.steering = { kind, evidence, rationale, noReplacementRequired: true };
4346
+ clearValidationBatchForBatch(input.plan, goal.validationBatch);
3075
4347
  input.plan.updatedAt = now;
3076
4348
  await writePlan(input.cwd, input.plan);
3077
4349
  await appendLedger(input.cwd, {
@@ -3091,19 +4363,14 @@ export async function recordUltragoalReviewBlockers(input: {
3091
4363
  title: string;
3092
4364
  objective: string;
3093
4365
  evidence: string;
3094
- skcGoalJson?: string;
3095
4366
  }): Promise<UltragoalPlan> {
3096
4367
  const objective = input.objective.trim();
3097
4368
  if (!objective) throw new Error("record-review-blockers --objective is required");
3098
- if (!input.skcGoalJson?.trim()) {
3099
- throw new Error('record-review-blockers require --skc-goal-json from a fresh active goal({"op":"get"}) snapshot');
3100
- }
3101
4369
  const plan = await checkpointUltragoalGoal({
3102
4370
  cwd: input.cwd,
3103
4371
  goalId: input.goalId,
3104
4372
  status: "review_blocked",
3105
4373
  evidence: input.evidence,
3106
- skcGoalJson: input.skcGoalJson,
3107
4374
  });
3108
4375
  const persistedPlan = await readUltragoalPlan(input.cwd);
3109
4376
  if (persistedPlan?.state_revision !== undefined) plan.state_revision = persistedPlan.state_revision;
@@ -3277,6 +4544,20 @@ function parseGitNameStatus(output: string): UltragoalChangeSetPath[] {
3277
4544
  return rows;
3278
4545
  }
3279
4546
 
4547
+ function ciDevChangedPathRows(): UltragoalChangeSetPath[] {
4548
+ const raw = process.env.CI_DEV_CHANGED_PATHS;
4549
+ if (!raw) return [];
4550
+ return raw
4551
+ .split(/\r?\n/)
4552
+ .map(row => row.trim())
4553
+ .filter(Boolean)
4554
+ .map(pathValue => ({
4555
+ path: normalizeRepoPath(pathValue),
4556
+ status: "unknown" as UltragoalChangeStatus,
4557
+ category: categorizeComputerChangePath(pathValue),
4558
+ }));
4559
+ }
4560
+
3280
4561
  function mergeChangeSetPaths(groups: UltragoalChangeSetPath[][]): UltragoalChangeSetPath[] {
3281
4562
  const byKey = new Map<string, UltragoalChangeSetPath>();
3282
4563
  for (const row of groups.flat()) byKey.set(`${row.oldPath ?? ""}\u0000${row.path}`, row);
@@ -3284,30 +4565,39 @@ function mergeChangeSetPaths(groups: UltragoalChangeSetPath[][]): UltragoalChang
3284
4565
  }
3285
4566
 
3286
4567
  async function computeCheckpointChangeSet(cwd: string): Promise<UltragoalChangeSet | undefined> {
4568
+ const ciChangedPaths = ciDevChangedPathRows();
3287
4569
  const inGit = await spawnText(["git", "rev-parse", "--is-inside-work-tree"], { cwd, timeoutMs: 3000 });
3288
- if (!inGit.ok || inGit.stdout.trim() !== "true") return undefined;
3289
- if (!(await Bun.file(path.join(cwd, ".git")).exists())) return undefined;
4570
+ if (!inGit.ok || inGit.stdout.trim() !== "true") {
4571
+ if (ciChangedPaths.length === 0) return undefined;
4572
+ return { source: "checkpoint-git", paths: ciChangedPaths, trusted: true };
4573
+ }
3290
4574
  const baseRef = await resolveGitBase(cwd);
3291
4575
  const base = baseRef;
3292
4576
  const mergeBase = await spawnText(["git", "merge-base", "HEAD", baseRef], { cwd, timeoutMs: 3000 });
3293
- const [committed, unstaged, staged, stat] = await Promise.all([
4577
+ const [committed, unstaged, staged, stat, committedDiff, unstagedDiff, stagedDiff] = await Promise.all([
3294
4578
  spawnText(["git", "diff", "--name-status", `${base}...HEAD`], { cwd, timeoutMs: 5000 }),
3295
4579
  spawnText(["git", "diff", "--name-status"], { cwd, timeoutMs: 5000 }),
3296
4580
  spawnText(["git", "diff", "--cached", "--name-status"], { cwd, timeoutMs: 5000 }),
3297
4581
  spawnText(["git", "diff", "--stat", `${base}...HEAD`], { cwd, timeoutMs: 5000 }),
4582
+ spawnText(["git", "diff", `${base}...HEAD`], { cwd, timeoutMs: 5000 }),
4583
+ spawnText(["git", "diff"], { cwd, timeoutMs: 5000 }),
4584
+ spawnText(["git", "diff", "--cached"], { cwd, timeoutMs: 5000 }),
4585
+ ]);
4586
+ if (!committed.ok && !unstaged.ok && !staged.ok && ciChangedPaths.length === 0) return undefined;
4587
+ const gitPaths = mergeChangeSetPaths([
4588
+ parseGitNameStatus(committed.stdout),
4589
+ parseGitNameStatus(unstaged.stdout),
4590
+ parseGitNameStatus(staged.stdout),
3298
4591
  ]);
3299
- if (!committed.ok && !unstaged.ok && !staged.ok) return undefined;
4592
+ const paths = gitPaths.length > 0 ? gitPaths : ciChangedPaths;
3300
4593
  return {
3301
4594
  source: "checkpoint-git",
3302
4595
  baseRef,
3303
4596
  mergeBase: mergeBase.ok && mergeBase.stdout.trim() ? mergeBase.stdout.trim() : undefined,
3304
4597
  headRef: "HEAD",
3305
- paths: mergeChangeSetPaths([
3306
- parseGitNameStatus(committed.stdout),
3307
- parseGitNameStatus(unstaged.stdout),
3308
- parseGitNameStatus(staged.stdout),
3309
- ]),
4598
+ paths,
3310
4599
  rawDiffStat: stat.stdout,
4600
+ rawDiff: [committedDiff.stdout, unstagedDiff.stdout, stagedDiff.stdout].filter(Boolean).join("\n"),
3311
4601
  trusted: true,
3312
4602
  };
3313
4603
  }
@@ -3338,6 +4628,7 @@ function changeSetFromReviewSource(source: JsonObject): UltragoalChangeSet | und
3338
4628
  source: "review-pr",
3339
4629
  paths: parseUnifiedDiffPaths(source.diff),
3340
4630
  rawDiffStat: source.diff,
4631
+ rawDiff: source.diff,
3341
4632
  trusted: true,
3342
4633
  };
3343
4634
  const local = qualityGateObject(source.local);
@@ -3347,6 +4638,7 @@ function changeSetFromReviewSource(source: JsonObject): UltragoalChangeSet | und
3347
4638
  source: "review-worktree",
3348
4639
  paths: parseGitNameStatus(String(source.nameStatus ?? source.status ?? "")),
3349
4640
  rawDiffStat: String(source.diffStat ?? ""),
4641
+ rawDiff: String(source.diff ?? ""),
3350
4642
  trusted: true,
3351
4643
  };
3352
4644
  if (kind === "branch" || kind === "pr-fallback")
@@ -3356,6 +4648,7 @@ function changeSetFromReviewSource(source: JsonObject): UltragoalChangeSet | und
3356
4648
  headRef: "HEAD",
3357
4649
  paths: parseGitNameStatus(String(source.nameStatus ?? "")),
3358
4650
  rawDiffStat: String(source.diffStat ?? ""),
4651
+ rawDiff: String(source.diff ?? ""),
3359
4652
  trusted: true,
3360
4653
  };
3361
4654
  return undefined;
@@ -3363,25 +4656,36 @@ function changeSetFromReviewSource(source: JsonObject): UltragoalChangeSet | und
3363
4656
 
3364
4657
  async function localDiffSource(cwd: string, sourceKind: string, branch?: string): Promise<JsonObject> {
3365
4658
  if (sourceKind === "worktree") {
3366
- const [status, diff, unstaged, staged] = await Promise.all([
4659
+ const [status, diffStat, unstaged, staged, unstagedDiff, stagedDiff] = await Promise.all([
3367
4660
  spawnText(["git", "status", "--short"], { cwd, timeoutMs: 5000 }),
3368
4661
  spawnText(["git", "diff", "--stat"], { cwd, timeoutMs: 5000 }),
3369
4662
  spawnText(["git", "diff", "--name-status"], { cwd, timeoutMs: 5000 }),
3370
4663
  spawnText(["git", "diff", "--cached", "--name-status"], { cwd, timeoutMs: 5000 }),
4664
+ spawnText(["git", "diff"], { cwd, timeoutMs: 5000 }),
4665
+ spawnText(["git", "diff", "--cached"], { cwd, timeoutMs: 5000 }),
3371
4666
  ]);
3372
4667
  return {
3373
4668
  kind: "worktree",
3374
4669
  status: status.stdout,
3375
- diffStat: diff.stdout,
4670
+ diffStat: diffStat.stdout,
4671
+ diff: [unstagedDiff.stdout, stagedDiff.stdout].filter(Boolean).join("\n"),
3376
4672
  nameStatus: `${unstaged.stdout}\n${staged.stdout}`,
3377
4673
  };
3378
4674
  }
3379
4675
  const base = await resolveGitBase(cwd, branch);
3380
- const [diff, nameStatus] = await Promise.all([
4676
+ const [diffStat, nameStatus, diff] = await Promise.all([
3381
4677
  spawnText(["git", "diff", "--stat", `${base}...HEAD`], { cwd, timeoutMs: 5000 }),
3382
4678
  spawnText(["git", "diff", "--name-status", `${base}...HEAD`], { cwd, timeoutMs: 5000 }),
4679
+ spawnText(["git", "diff", `${base}...HEAD`], { cwd, timeoutMs: 5000 }),
3383
4680
  ]);
3384
- return { kind: sourceKind, base, branch, diffStat: diff.stdout, nameStatus: nameStatus.stdout };
4681
+ return {
4682
+ kind: sourceKind,
4683
+ base,
4684
+ branch,
4685
+ diffStat: diffStat.stdout,
4686
+ diff: diff.stdout,
4687
+ nameStatus: nameStatus.stdout,
4688
+ };
3385
4689
  }
3386
4690
 
3387
4691
  async function resolveReviewSource(
@@ -3551,7 +4855,6 @@ const FLAGS_WITH_VALUES = new Set([
3551
4855
  "--goal-id",
3552
4856
  "--status",
3553
4857
  "--evidence",
3554
- "--skc-goal-json",
3555
4858
  "--quality-gate-json",
3556
4859
  "--executor-qa-json",
3557
4860
  "--executor-qa",
@@ -3566,6 +4869,17 @@ const FLAGS_WITH_VALUES = new Set([
3566
4869
  "--replacements-json",
3567
4870
  "--order-json",
3568
4871
  "--classification",
4872
+ "--goal-metadata-json",
4873
+ "--validation-batch-json",
4874
+ "--prior-goal-id",
4875
+ "--next-goal-id",
4876
+ "--review-handles-json",
4877
+ "--qa-handles-json",
4878
+ "--implementation-handle-json",
4879
+ "--overlap-id",
4880
+ "--review-result-json",
4881
+ "--qa-result-json",
4882
+ "--target-state-json",
3569
4883
  ]);
3570
4884
 
3571
4885
  function isHelpArg(arg: string): boolean {
@@ -3605,15 +4919,12 @@ function renderUltragoalHelp(args: readonly string[]): string | null {
3605
4919
  " --status=<value> pending|active|complete|failed|blocked|review_blocked|superseded",
3606
4920
  " --evidence=<value> Completion or checkpoint evidence text",
3607
4921
  " --quality-gate-json=<value> JSON string or path for complete checkpoints",
3608
- " --skc-goal-json=<value> Optional JSON/path override for current goal snapshot; omitted complete checkpoints read current session goal state",
3609
4922
  " --json Output a machine-readable receipt",
3610
4923
  "",
3611
4924
  "COMPLETE CHECKPOINT RECEIPTS",
3612
4925
  " --quality-gate-json must be an object with architectReview, executorQa, and iteration.",
3613
4926
  " executorQa.contractCoverage[] rows require an obligation field; description is not a substitute.",
3614
- " Complete checkpoints use the current session's active SKC goal-mode snapshot when --skc-goal-json is omitted.",
3615
- " Explicit --skc-goal-json values must contain an active SKC goal-mode snapshot, not the .skc/ultragoal/goals.json goal record.",
3616
- " goal.updatedAt may be epoch milliseconds or an ISO timestamp and must be fresh.",
4927
+ " Complete checkpoints validate the target durable goals.json record before writing a receipt.",
3617
4928
  "",
3618
4929
  "EXAMPLES",
3619
4930
  ' $ skc ultragoal checkpoint --goal-id G001 --status blocked --evidence "waiting on review"',
@@ -3675,6 +4986,9 @@ function renderUltragoalHelp(args: readonly string[]): string | null {
3675
4986
  " steer",
3676
4987
  " record-review-blockers",
3677
4988
  " classify-blocker",
4989
+ " start-pipeline-overlap",
4990
+ " join-pipeline-overlap",
4991
+ " rebaseline-pipeline-overlap",
3678
4992
  "",
3679
4993
  "Run `skc ultragoal checkpoint --help`, `skc ultragoal review --help`, or `skc ultragoal classify-blocker --help` for command-specific requirements.",
3680
4994
  "",
@@ -3905,9 +5219,18 @@ async function executeUltragoalSteeringCommand(args: readonly string[], cwd: str
3905
5219
  }
3906
5220
 
3907
5221
  async function dispatchUltragoalCommand(args: string[], cwd: string): Promise<UltragoalCommandResult> {
3908
- const sessionId = currentUltragoalSessionId(cwd);
5222
+ // Help must not require a resolvable session; render it before session resolution.
3909
5223
  const help = renderUltragoalHelp(args);
3910
5224
  if (help) return { status: 0, stdout: help };
5225
+ let sessionId: string;
5226
+ try {
5227
+ sessionId = currentUltragoalSessionId(cwd);
5228
+ } catch (error) {
5229
+ // A missing/ambiguous session is an operator input error, not a crash:
5230
+ // surface the guidance on stderr instead of an uncaught-exception dump.
5231
+ if (error instanceof SessionResolutionError) return { status: 1, stderr: `${error.message}\n` };
5232
+ throw error;
5233
+ }
3911
5234
  try {
3912
5235
  const command = commandName(args);
3913
5236
  const json = hasFlag(args, "--json");
@@ -3916,8 +5239,20 @@ async function dispatchUltragoalCommand(args: string[], cwd: string): Promise<Ul
3916
5239
  return { status: 0, stdout: renderStatus(await getUltragoalStatus(cwd, sessionId), json) };
3917
5240
  case "create":
3918
5241
  case "create-goals": {
5242
+ if (
5243
+ flagValue(args, "--goal-metadata-json") !== undefined &&
5244
+ flagValue(args, "--validation-batch-json") !== undefined
5245
+ ) {
5246
+ throw new Error("--validation-batch-json and --goal-metadata-json are mutually exclusive");
5247
+ }
3919
5248
  const mode = flagValue(args, "--skc-goal-mode") === "per-story" ? "per-story" : "aggregate";
3920
- const plan = await createUltragoalPlan({ cwd, brief: await readBrief(cwd, args), skcGoalMode: mode });
5249
+ const plan = await createUltragoalPlan({
5250
+ cwd,
5251
+ brief: await readBrief(cwd, args),
5252
+ skcGoalMode: mode,
5253
+ goalMetadataJson: flagValue(args, "--goal-metadata-json"),
5254
+ validationBatchJson: flagValue(args, "--validation-batch-json"),
5255
+ });
3921
5256
  return {
3922
5257
  status: 0,
3923
5258
  createdPlan: true,
@@ -3949,7 +5284,6 @@ async function dispatchUltragoalCommand(args: string[], cwd: string): Promise<Ul
3949
5284
  goalId,
3950
5285
  status,
3951
5286
  evidence,
3952
- skcGoalJson: flagValue(args, "--skc-goal-json"),
3953
5287
  qualityGateJson: flagValue(args, "--quality-gate-json"),
3954
5288
  advanceNext: status === "complete",
3955
5289
  });
@@ -3981,7 +5315,6 @@ async function dispatchUltragoalCommand(args: string[], cwd: string): Promise<Ul
3981
5315
  title: flagValue(args, "--title") ?? "Resolve final code-review blockers",
3982
5316
  objective: flagValue(args, "--objective") ?? "",
3983
5317
  evidence: flagValue(args, "--evidence") ?? "",
3984
- skcGoalJson: flagValue(args, "--skc-goal-json"),
3985
5318
  });
3986
5319
  const goal = plan.goals.at(-1);
3987
5320
  return {
@@ -4013,6 +5346,65 @@ async function dispatchUltragoalCommand(args: string[], cwd: string): Promise<Ul
4013
5346
  : `Recorded blocker classification: ${String(event.classification)}.\n`,
4014
5347
  };
4015
5348
  }
5349
+ case "start-pipeline-overlap": {
5350
+ const receipt = await startUltragoalPipelineOverlap({
5351
+ cwd,
5352
+ priorGoalId: flagValue(args, "--prior-goal-id") ?? "",
5353
+ nextGoalId: flagValue(args, "--next-goal-id") ?? "",
5354
+ reviewHandles: await readRequiredJsonObjectOrArray(
5355
+ cwd,
5356
+ flagValue(args, "--review-handles-json") ?? "",
5357
+ "review handles",
5358
+ ),
5359
+ qaHandles: await readRequiredJsonObjectOrArray(
5360
+ cwd,
5361
+ flagValue(args, "--qa-handles-json") ?? "",
5362
+ "QA handles",
5363
+ ),
5364
+ implementationHandle: await readRequiredJsonObject(
5365
+ cwd,
5366
+ flagValue(args, "--implementation-handle-json") ?? "",
5367
+ "implementation handle",
5368
+ ),
5369
+ });
5370
+ return {
5371
+ status: 0,
5372
+ stdout: json ? renderCliWriteReceipt(receipt) : `Started pipeline overlap ${receipt.overlap_id}.\n`,
5373
+ };
5374
+ }
5375
+ case "join-pipeline-overlap": {
5376
+ const receipt = await joinUltragoalPipelineOverlap({
5377
+ cwd,
5378
+ overlapId: flagValue(args, "--overlap-id") ?? "",
5379
+ reviewResult: await readRequiredJsonObject(
5380
+ cwd,
5381
+ flagValue(args, "--review-result-json") ?? "",
5382
+ "review result",
5383
+ ),
5384
+ qaResult: await readRequiredJsonObject(cwd, flagValue(args, "--qa-result-json") ?? "", "QA result"),
5385
+ });
5386
+ return {
5387
+ status: 0,
5388
+ stdout: json ? renderCliWriteReceipt(receipt) : `Joined pipeline overlap ${receipt.overlap_id}.\n`,
5389
+ };
5390
+ }
5391
+ case "rebaseline-pipeline-overlap": {
5392
+ const receipt = await rebaselineUltragoalPipelineOverlap({
5393
+ cwd,
5394
+ overlapId: flagValue(args, "--overlap-id") ?? "",
5395
+ goalId: flagValue(args, "--goal-id") ?? "",
5396
+ evidence: flagValue(args, "--evidence") ?? "",
5397
+ targetState: await readRequiredJsonObject(
5398
+ cwd,
5399
+ flagValue(args, "--target-state-json") ?? "",
5400
+ "target state",
5401
+ ),
5402
+ });
5403
+ return {
5404
+ status: 0,
5405
+ stdout: json ? renderCliWriteReceipt(receipt) : `Rebaselined pipeline overlap ${receipt.overlap_id}.\n`,
5406
+ };
5407
+ }
4016
5408
  default:
4017
5409
  return { status: 1, stderr: `Unknown skc ultragoal command: ${command}\n` };
4018
5410
  }
@@ -4031,6 +5423,9 @@ const RECONCILE_COMMANDS = new Set([
4031
5423
  "record-review-blockers",
4032
5424
  "review",
4033
5425
  "classify-blocker",
5426
+ "start-pipeline-overlap",
5427
+ "join-pipeline-overlap",
5428
+ "rebaseline-pipeline-overlap",
4034
5429
  ]);
4035
5430
 
4036
5431
  /**
@@ -4067,6 +5462,7 @@ async function reconcileUltragoalState(cwd: string): Promise<void> {
4067
5462
  if (summary.nudgeRemaining !== undefined) payload.nudge_remaining = summary.nudgeRemaining;
4068
5463
  if (summary.nudgeGoalId !== undefined) payload.nudge_goal_id = summary.nudgeGoalId;
4069
5464
  if (summary.nudgeTargetKind !== undefined) payload.nudge_target_kind = summary.nudgeTargetKind;
5465
+ if (summary.pipelineOverlap) payload.pipeline_overlap = summary.pipelineOverlap;
4070
5466
  const ledgerText = await Bun.file(summary.paths.ledgerPath)
4071
5467
  .text()
4072
5468
  .catch(() => "");