@sayknow-cli/coding-agent 0.4.6 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (428) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/dist/types/capability/index.d.ts +10 -20
  3. package/dist/types/capability/types.d.ts +3 -0
  4. package/dist/types/cli/args.d.ts +0 -2
  5. package/dist/types/cli/read-cli.d.ts +1 -0
  6. package/dist/types/cli.d.ts +9 -1
  7. package/dist/types/commands/daemon.d.ts +2 -2
  8. package/dist/types/commands/deep-interview.d.ts +9 -0
  9. package/dist/types/commands/harness.d.ts +22 -0
  10. package/dist/types/commands/read.d.ts +6 -0
  11. package/dist/types/commands/sdk.d.ts +20 -2
  12. package/dist/types/config/keybindings.d.ts +34 -4
  13. package/dist/types/config/model-profile-contract.d.ts +40 -0
  14. package/dist/types/config/model-profiles.d.ts +2 -3
  15. package/dist/types/config/model-registry.d.ts +5 -0
  16. package/dist/types/config/provider-auth-health.d.ts +14 -0
  17. package/dist/types/config/provider-ranking.d.ts +59 -0
  18. package/dist/types/config/settings-schema.d.ts +156 -10
  19. package/dist/types/config/settings.d.ts +3 -0
  20. package/dist/types/edit/modes/patch.d.ts +13 -0
  21. package/dist/types/edit/path-mutation-lock.d.ts +15 -0
  22. package/dist/types/eval/py/executor.d.ts +1 -1
  23. package/dist/types/eval/py/runner-artifact.d.ts +8 -0
  24. package/dist/types/eval/py/tool-bridge.d.ts +1 -2
  25. package/dist/types/extensibility/extensions/types.d.ts +43 -2
  26. package/dist/types/extensibility/shared-events.d.ts +6 -0
  27. package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
  28. package/dist/types/main.d.ts +33 -2
  29. package/dist/types/memories/index.d.ts +2 -0
  30. package/dist/types/modes/acp/acp-agent.d.ts +22 -9
  31. package/dist/types/modes/components/assistant-message.d.ts +3 -1
  32. package/dist/types/modes/components/btw-panel.d.ts +1 -0
  33. package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
  34. package/dist/types/modes/components/queue-pane.d.ts +8 -0
  35. package/dist/types/modes/components/queued-message-selector.d.ts +6 -0
  36. package/dist/types/modes/components/read-tool-group.d.ts +4 -4
  37. package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +2 -1
  38. package/dist/types/modes/components/session-observer-overlay.d.ts +4 -0
  39. package/dist/types/modes/components/settings-selector.d.ts +2 -0
  40. package/dist/types/modes/components/tool-execution.d.ts +8 -0
  41. package/dist/types/modes/components/tool-status-header.d.ts +4 -2
  42. package/dist/types/modes/components/welcome.d.ts +5 -0
  43. package/dist/types/modes/controllers/btw-controller.d.ts +5 -0
  44. package/dist/types/modes/controllers/command-controller.d.ts +2 -0
  45. package/dist/types/modes/controllers/event-controller.d.ts +3 -0
  46. package/dist/types/modes/interactive-mode.d.ts +13 -2
  47. package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
  48. package/dist/types/modes/prompt-action-autocomplete.d.ts +6 -1
  49. package/dist/types/modes/prompt-suggestion-controller.d.ts +35 -0
  50. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +2 -2
  51. package/dist/types/modes/types.d.ts +6 -0
  52. package/dist/types/modes/utils/hotkeys-markdown.d.ts +2 -1
  53. package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
  54. package/dist/types/runtime/memory-domain.d.ts +9 -0
  55. package/dist/types/runtime/memory-guard-contract.d.ts +71 -0
  56. package/dist/types/runtime/memory-guard.d.ts +39 -0
  57. package/dist/types/runtime/memory-limit.d.ts +11 -0
  58. package/dist/types/runtime-mcp/content-limits.d.ts +7 -0
  59. package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +1 -1
  60. package/dist/types/runtime-mcp/manager.d.ts +9 -1
  61. package/dist/types/runtime-mcp/oauth-flow.d.ts +0 -5
  62. package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +14 -0
  63. package/dist/types/runtime-mcp/redaction.d.ts +2 -0
  64. package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
  65. package/dist/types/sdk/acp/final-text.d.ts +19 -0
  66. package/dist/types/sdk/acp/mcp.d.ts +23 -0
  67. package/dist/types/sdk/broker/broker.d.ts +2 -0
  68. package/dist/types/sdk/broker/lifecycle.d.ts +13 -0
  69. package/dist/types/sdk/bus/chat-daemon-control.d.ts +9 -1
  70. package/dist/types/sdk/bus/config-commands.d.ts +2 -2
  71. package/dist/types/sdk/bus/config.d.ts +2 -0
  72. package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
  73. package/dist/types/sdk/bus/conversation-store.d.ts +1 -0
  74. package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
  75. package/dist/types/sdk/bus/index.d.ts +52 -4
  76. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +37 -0
  77. package/dist/types/sdk/bus/lifecycle-commands.d.ts +5 -4
  78. package/dist/types/sdk/bus/notification-orchestration.d.ts +1 -0
  79. package/dist/types/sdk/bus/notification-service.d.ts +34 -0
  80. package/dist/types/sdk/bus/operator-runtime.d.ts +1 -0
  81. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +106 -0
  82. package/dist/types/sdk/bus/rate-limit-pool.d.ts +2 -0
  83. package/dist/types/sdk/bus/reconciliation-store.d.ts +65 -0
  84. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +33 -9
  85. package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -1
  86. package/dist/types/sdk/bus/telegram-daemon.d.ts +286 -12
  87. package/dist/types/sdk/bus/telegram-reference.d.ts +2 -0
  88. package/dist/types/sdk/bus/topic-registry.d.ts +88 -2
  89. package/dist/types/sdk/client/discovery.d.ts +2 -0
  90. package/dist/types/sdk/client/liveness.d.ts +7 -0
  91. package/dist/types/sdk/host/control/operations.d.ts +3 -2
  92. package/dist/types/sdk/host/host.d.ts +3 -1
  93. package/dist/types/sdk/host/query/handlers.d.ts +14 -0
  94. package/dist/types/sdk/index.d.ts +2 -0
  95. package/dist/types/sdk/lifecycle-session.d.ts +10 -1
  96. package/dist/types/sdk/prompt-status.d.ts +88 -0
  97. package/dist/types/sdk/session-directory.d.ts +1 -1
  98. package/dist/types/sdk/session.d.ts +7 -0
  99. package/dist/types/sdk/startup-capability.d.ts +9 -0
  100. package/dist/types/sdk/transport/auth-preface.d.ts +9 -0
  101. package/dist/types/sdk/transport/index.d.ts +12 -0
  102. package/dist/types/sdk/transport/relay.d.ts +43 -0
  103. package/dist/types/sdk/transport/serve-cli.d.ts +4 -0
  104. package/dist/types/sdk/transport/socket.d.ts +7 -0
  105. package/dist/types/sdk/transport/stdio.d.ts +3 -0
  106. package/dist/types/session/agent-session.d.ts +83 -24
  107. package/dist/types/session/btw-contract.d.ts +16 -0
  108. package/dist/types/session/fallback-chain-controller.d.ts +18 -2
  109. package/dist/types/session/internal/managed-session-scope.d.ts +70 -10
  110. package/dist/types/session/internal/managed-session-storage.d.ts +34 -12
  111. package/dist/types/session/internal/native-publish-outcome.d.ts +48 -0
  112. package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
  113. package/dist/types/session/session-manager.d.ts +89 -18
  114. package/dist/types/session/session-storage.d.ts +31 -0
  115. package/dist/types/session/streaming-output.d.ts +60 -5
  116. package/dist/types/setup/credential-import.d.ts +5 -1
  117. package/dist/types/setup/provider-onboarding.d.ts +2 -0
  118. package/dist/types/skc-runtime/deep-interview-runtime.d.ts +1 -1
  119. package/dist/types/skc-runtime/deep-interview-stage.d.ts +37 -0
  120. package/dist/types/skc-runtime/gc-runtime.d.ts +1 -1
  121. package/dist/types/skc-runtime/linux-proc.d.ts +22 -14
  122. package/dist/types/skc-runtime/memory-guard-owner-claims.d.ts +47 -0
  123. package/dist/types/skc-runtime/ralplan-runtime.d.ts +112 -1
  124. package/dist/types/skc-runtime/repository-binding.d.ts +63 -0
  125. package/dist/types/skc-runtime/state-runtime.d.ts +3 -1
  126. package/dist/types/skc-runtime/state-writer.d.ts +5 -1
  127. package/dist/types/skc-runtime/team-launch.d.ts +1 -1
  128. package/dist/types/skc-runtime/team-runtime.d.ts +9 -2
  129. package/dist/types/skc-runtime/team-store.d.ts +12 -0
  130. package/dist/types/skc-runtime/team-worker-memory-guard.d.ts +92 -0
  131. package/dist/types/skc-runtime/tmux-owner-isolation.d.ts +7 -0
  132. package/dist/types/skc-runtime/ultragoal-guard.d.ts +6 -5
  133. package/dist/types/skc-runtime/ultragoal-receipt-freshness.d.ts +28 -0
  134. package/dist/types/skc-runtime/ultragoal-runtime.d.ts +43 -5
  135. package/dist/types/skill-state/workflow-hud.d.ts +3 -0
  136. package/dist/types/ssh/utils.d.ts +1 -0
  137. package/dist/types/task/discovery.d.ts +3 -1
  138. package/dist/types/task/executor.d.ts +6 -0
  139. package/dist/types/task/index.d.ts +3 -1
  140. package/dist/types/task/provider-retry-status.d.ts +13 -0
  141. package/dist/types/task/receipt.d.ts +2 -0
  142. package/dist/types/task/types.d.ts +133 -0
  143. package/dist/types/task/ultragoal-redteam-activation.d.ts +33 -0
  144. package/dist/types/tools/browser/launch.d.ts +7 -0
  145. package/dist/types/tools/fetch.d.ts +22 -9
  146. package/dist/types/tools/image-gen.d.ts +63 -1
  147. package/dist/types/tools/index.d.ts +7 -1
  148. package/dist/types/tools/output-meta.d.ts +21 -1
  149. package/dist/types/tools/read-internals.d.ts +12 -0
  150. package/dist/types/tools/read.d.ts +45 -1
  151. package/dist/types/tools/resource-gc.d.ts +23 -0
  152. package/dist/types/tools/skill-discovery.d.ts +7 -0
  153. package/dist/types/tools/sqlite-reader.d.ts +7 -0
  154. package/dist/types/tools/tool-result.d.ts +7 -1
  155. package/dist/types/utils/prompt-suggestion.d.ts +33 -0
  156. package/dist/types/utils/shell-snapshot.d.ts +12 -0
  157. package/dist/types/web/insane/bridge.d.ts +1 -0
  158. package/dist/types/web/insane/url-guard.d.ts +17 -0
  159. package/package.json +8 -12
  160. package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
  161. package/scripts/capture-platform-shortcut-labels-showcase.ts +342 -0
  162. package/scripts/capture-sticky-viewport-showcase.ts +292 -0
  163. package/scripts/compile-args.ts +0 -1
  164. package/scripts/dogfood-repository-binding.ts +209 -0
  165. package/scripts/generate-docs-index.ts +4 -1
  166. package/scripts/generate-sdk-operation-inventory.ts +9 -0
  167. package/scripts/run-test-manifest.ts +6 -4
  168. package/scripts/verify-skc-sdk-canonicalization.ts +122 -18
  169. package/scripts/verify-sticky-viewport-showcase.ts +611 -0
  170. package/src/capability/index.ts +58 -42
  171. package/src/capability/types.ts +3 -0
  172. package/src/cli/args.ts +16 -100
  173. package/src/cli/fast-help.ts +1 -1
  174. package/src/cli/mcp-cli.ts +4 -21
  175. package/src/cli/notify-cli.ts +6 -38
  176. package/src/cli/read-cli.ts +2 -1
  177. package/src/cli/setup-cli.ts +10 -4
  178. package/src/cli.ts +133 -11
  179. package/src/commands/daemon.ts +22 -5
  180. package/src/commands/deep-interview.ts +26 -1
  181. package/src/commands/harness.ts +35 -12
  182. package/src/commands/read.ts +11 -2
  183. package/src/commands/sdk.ts +134 -17
  184. package/src/commands/team.ts +1 -1
  185. package/src/commit/agentic/index.ts +3 -3
  186. package/src/commit/map-reduce/index.ts +2 -2
  187. package/src/config/keybindings.ts +158 -25
  188. package/src/config/model-profile-contract.ts +174 -0
  189. package/src/config/model-profiles.ts +51 -10
  190. package/src/config/model-registry.ts +24 -4
  191. package/src/config/model-resolver.ts +2 -2
  192. package/src/config/provider-auth-health.ts +42 -0
  193. package/src/config/provider-ranking.ts +119 -0
  194. package/src/config/settings-schema.ts +157 -10
  195. package/src/config/settings.ts +254 -108
  196. package/src/coordinator-mcp/model-preset.ts +21 -74
  197. package/src/defaults/skc/skills/deep-interview/SKILL.md +147 -24
  198. package/src/defaults/skc/skills/ralplan/SKILL.md +91 -34
  199. package/src/defaults/skc/skills/team/SKILL.md +1 -1
  200. package/src/defaults/skc/skills/ultragoal/SKILL.md +68 -17
  201. package/src/discovery/ssh.ts +12 -1
  202. package/src/edit/index.ts +3 -6
  203. package/src/edit/modes/patch.ts +38 -1
  204. package/src/edit/modes/replace.ts +42 -0
  205. package/src/edit/path-mutation-lock.ts +112 -0
  206. package/src/eval/js/tool-bridge.ts +1 -1
  207. package/src/eval/py/executor.ts +37 -13
  208. package/src/eval/py/kernel.ts +1 -21
  209. package/src/eval/py/prelude.py +2 -2
  210. package/src/eval/py/runner-artifact.ts +84 -0
  211. package/src/eval/py/tool-bridge.ts +34 -18
  212. package/src/extensibility/extensions/runner.ts +4 -0
  213. package/src/extensibility/extensions/types.ts +42 -4
  214. package/src/extensibility/plugins/marketplace/fetcher.ts +191 -7
  215. package/src/extensibility/shared-events.ts +5 -0
  216. package/src/extensibility/skc-plugins/runtime-adapters.ts +2 -1
  217. package/src/hooks/native-skill-hook.ts +17 -4
  218. package/src/internal-urls/docs-index.generated.ts +17 -16
  219. package/src/internal-urls/local-protocol.ts +87 -25
  220. package/src/internal-urls/local-root-gc.ts +127 -0
  221. package/src/internal-urls/mcp-protocol.ts +73 -11
  222. package/src/main.ts +120 -42
  223. package/src/memories/index.ts +10 -0
  224. package/src/modes/DESIGN.md +52 -0
  225. package/src/modes/acp/acp-agent.ts +647 -83
  226. package/src/modes/acp/acp-event-mapper.ts +106 -12
  227. package/src/modes/acp/acp-mode.ts +39 -3
  228. package/src/modes/action-registry.ts +1 -1
  229. package/src/modes/components/assistant-message.ts +123 -22
  230. package/src/modes/components/btw-panel.ts +82 -16
  231. package/src/modes/components/irc-sidebar.ts +176 -62
  232. package/src/modes/components/model-selector.ts +61 -4
  233. package/src/modes/components/notifications-settings-editor.ts +1 -1
  234. package/src/modes/components/oauth-selector.ts +42 -12
  235. package/src/modes/components/plan-preview-overlay.ts +1 -1
  236. package/src/modes/components/queue-pane.ts +55 -9
  237. package/src/modes/components/queued-message-selector.ts +53 -10
  238. package/src/modes/components/read-tool-group.ts +82 -14
  239. package/src/modes/components/runtime-mcp-add-wizard.ts +5 -0
  240. package/src/modes/components/sayknow-pet-widget.ts +27 -8
  241. package/src/modes/components/session-observer-overlay.ts +187 -32
  242. package/src/modes/components/settings-selector.ts +60 -18
  243. package/src/modes/components/tool-execution.ts +138 -27
  244. package/src/modes/components/tool-status-header.ts +26 -8
  245. package/src/modes/components/welcome.ts +50 -23
  246. package/src/modes/controllers/btw-controller.ts +119 -36
  247. package/src/modes/controllers/command-controller.ts +101 -54
  248. package/src/modes/controllers/event-controller.ts +119 -27
  249. package/src/modes/controllers/extension-ui-controller.ts +23 -12
  250. package/src/modes/controllers/input-controller.ts +100 -8
  251. package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -6
  252. package/src/modes/controllers/selector-controller.ts +4 -1
  253. package/src/modes/interactive-mode.ts +201 -60
  254. package/src/modes/irc-observation-ledger.ts +71 -15
  255. package/src/modes/prompt-action-autocomplete.ts +32 -13
  256. package/src/modes/prompt-suggestion-controller.ts +96 -0
  257. package/src/modes/runtime-init.ts +20 -2
  258. package/src/modes/shared/agent-wire/command-dispatch.ts +3 -3
  259. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +2 -2
  260. package/src/modes/types.ts +6 -0
  261. package/src/modes/utils/hotkeys-markdown.ts +64 -36
  262. package/src/modes/utils/ui-helpers.ts +99 -4
  263. package/src/prompts/agent-fragments/restricted-bash.md +1 -1
  264. package/src/prompts/agents/architect.md +17 -3
  265. package/src/prompts/agents/critic.md +17 -2
  266. package/src/prompts/agents/executor.md +1 -1
  267. package/src/prompts/agents/planner.md +8 -1
  268. package/src/prompts/system/btw-user.md +3 -8
  269. package/src/prompts/system/prompt-suggestion-system.md +32 -0
  270. package/src/prompts/system/system-prompt.md +6 -3
  271. package/src/prompts/tools/cron.md +3 -1
  272. package/src/prompts/tools/read.md +4 -2
  273. package/src/prompts/tools/skill-discovery.md +1 -0
  274. package/src/runtime/memory-domain.ts +66 -0
  275. package/src/runtime/memory-guard-contract.ts +73 -0
  276. package/src/runtime/memory-guard.ts +292 -0
  277. package/src/runtime/memory-limit.ts +50 -0
  278. package/src/runtime-mcp/client.ts +41 -55
  279. package/src/runtime-mcp/content-limits.ts +71 -0
  280. package/src/runtime-mcp/discoverable-tool-metadata.ts +1 -1
  281. package/src/runtime-mcp/json-rpc.ts +28 -11
  282. package/src/runtime-mcp/manager.ts +77 -59
  283. package/src/runtime-mcp/oauth-flow.ts +0 -72
  284. package/src/runtime-mcp/plugin-network-boundary.ts +101 -0
  285. package/src/runtime-mcp/redaction.ts +30 -0
  286. package/src/runtime-mcp/smithery-auth.ts +17 -2
  287. package/src/runtime-mcp/smithery-connect.ts +11 -1
  288. package/src/runtime-mcp/transports/http.ts +63 -22
  289. package/src/sdk/acp/adapter.ts +8 -1
  290. package/src/sdk/acp/final-text.ts +40 -0
  291. package/src/sdk/acp/mcp.ts +26 -0
  292. package/src/sdk/broker/broker.ts +34 -20
  293. package/src/sdk/broker/identity.ts +22 -12
  294. package/src/sdk/broker/lifecycle.ts +293 -43
  295. package/src/sdk/broker/session-index.ts +11 -1
  296. package/src/sdk/bus/chat-daemon-cli.ts +2 -2
  297. package/src/sdk/bus/chat-daemon-control.ts +22 -5
  298. package/src/sdk/bus/config-commands.ts +2 -2
  299. package/src/sdk/bus/config.ts +10 -2
  300. package/src/sdk/bus/control-drain-lease.ts +104 -0
  301. package/src/sdk/bus/conversation-store.ts +40 -6
  302. package/src/sdk/bus/daemon-paths.ts +2 -0
  303. package/src/sdk/bus/index.ts +793 -121
  304. package/src/sdk/bus/kind-aware-reconciliation.ts +242 -0
  305. package/src/sdk/bus/lifecycle-commands.ts +63 -10
  306. package/src/sdk/bus/lifecycle-control-runtime.ts +11 -2
  307. package/src/sdk/bus/lifecycle-orchestrator.ts +32 -1
  308. package/src/sdk/bus/notification-orchestration.ts +12 -0
  309. package/src/sdk/bus/notification-service.ts +87 -25
  310. package/src/sdk/bus/operator-runtime.ts +31 -5
  311. package/src/sdk/bus/prompt-reconciliation.ts +240 -0
  312. package/src/sdk/bus/rate-limit-pool.ts +8 -0
  313. package/src/sdk/bus/recent-activity.ts +90 -26
  314. package/src/sdk/bus/reconciliation-store.ts +224 -0
  315. package/src/sdk/bus/telegram-cli.ts +6 -13
  316. package/src/sdk/bus/telegram-daemon-cli.ts +8 -3
  317. package/src/sdk/bus/telegram-daemon-contract.ts +34 -9
  318. package/src/sdk/bus/telegram-daemon-control.ts +161 -40
  319. package/src/sdk/bus/telegram-daemon.ts +3649 -593
  320. package/src/sdk/bus/telegram-reference.ts +20 -2
  321. package/src/sdk/bus/topic-registry.ts +451 -12
  322. package/src/sdk/cli/session-cli.ts +15 -2
  323. package/src/sdk/client/discovery.ts +19 -3
  324. package/src/sdk/client/liveness.ts +49 -0
  325. package/src/sdk/host/control/dispatch.ts +8 -2
  326. package/src/sdk/host/control/operations.ts +3 -2
  327. package/src/sdk/host/host.ts +27 -9
  328. package/src/sdk/host/query/handlers.ts +125 -5
  329. package/src/sdk/index.ts +12 -0
  330. package/src/sdk/lifecycle-session.ts +19 -3
  331. package/src/sdk/mcp/server.ts +46 -18
  332. package/src/sdk/prompt-status.ts +97 -0
  333. package/src/sdk/protocol/operation-inventory.generated.json +145 -0
  334. package/src/sdk/protocol/operation-registry.ts +24 -4
  335. package/src/sdk/session-directory.ts +5 -1
  336. package/src/sdk/session.ts +69 -8
  337. package/src/sdk/startup-capability.ts +15 -1
  338. package/src/sdk/transport/auth-preface.ts +82 -0
  339. package/src/sdk/transport/index.ts +18 -0
  340. package/src/sdk/transport/relay.ts +252 -0
  341. package/src/sdk/transport/serve-cli.ts +105 -0
  342. package/src/sdk/transport/socket.ts +197 -0
  343. package/src/sdk/transport/stdio.ts +17 -0
  344. package/src/session/agent-session.ts +1112 -314
  345. package/src/session/blob-store.ts +25 -7
  346. package/src/session/btw-contract.ts +59 -0
  347. package/src/session/fallback-chain-controller.ts +47 -8
  348. package/src/session/internal/managed-session-scope.ts +1426 -259
  349. package/src/session/internal/managed-session-storage.ts +414 -238
  350. package/src/session/internal/native-publish-outcome.ts +271 -0
  351. package/src/session/memory-guard-checkpoint-participant.ts +131 -0
  352. package/src/session/session-manager.ts +2079 -469
  353. package/src/session/session-storage.ts +151 -11
  354. package/src/session/streaming-output.ts +262 -43
  355. package/src/setup/credential-import.ts +28 -3
  356. package/src/setup/provider-onboarding.ts +49 -5
  357. package/src/setup/provider-presets.json +2 -1
  358. package/src/skc-runtime/deep-interview-runtime.ts +303 -36
  359. package/src/skc-runtime/deep-interview-stage.ts +1016 -0
  360. package/src/skc-runtime/deep-interview-state.ts +8 -5
  361. package/src/skc-runtime/gc-render.ts +1 -0
  362. package/src/skc-runtime/gc-runtime.ts +11 -1
  363. package/src/skc-runtime/linux-proc.ts +70 -36
  364. package/src/skc-runtime/managed-owner-supervisor.ts +83 -4
  365. package/src/skc-runtime/memory-guard-owner-claims.ts +389 -0
  366. package/src/skc-runtime/ralplan-runtime.ts +1057 -75
  367. package/src/skc-runtime/repository-binding.ts +267 -0
  368. package/src/skc-runtime/session-state-sidecar.ts +25 -9
  369. package/src/skc-runtime/state-runtime.ts +50 -12
  370. package/src/skc-runtime/state-writer.ts +68 -56
  371. package/src/skc-runtime/team-launch.ts +34 -5
  372. package/src/skc-runtime/team-runtime.ts +41 -1
  373. package/src/skc-runtime/team-store.ts +32 -0
  374. package/src/skc-runtime/team-worker-memory-guard.ts +363 -0
  375. package/src/skc-runtime/team-workers.ts +1 -0
  376. package/src/skc-runtime/tmux-common.ts +13 -2
  377. package/src/skc-runtime/tmux-owner-isolation.ts +20 -1
  378. package/src/skc-runtime/tmux-sessions.ts +45 -6
  379. package/src/skc-runtime/ultragoal-guard.ts +93 -15
  380. package/src/skc-runtime/ultragoal-receipt-freshness.ts +123 -0
  381. package/src/skc-runtime/ultragoal-runtime.ts +469 -38
  382. package/src/skc-runtime/workflow-manifest.generated.json +195 -5
  383. package/src/skc-runtime/workflow-manifest.ts +67 -3
  384. package/src/skill-state/workflow-hud.ts +25 -2
  385. package/src/skill-state/workflow-mutation-guard.ts +104 -12
  386. package/src/slash-commands/builtin-registry.ts +1 -1
  387. package/src/ssh/utils.ts +14 -0
  388. package/src/task/discovery.ts +8 -2
  389. package/src/task/executor.ts +165 -47
  390. package/src/task/index.ts +123 -15
  391. package/src/task/provider-retry-status.ts +88 -0
  392. package/src/task/receipt.ts +3 -0
  393. package/src/task/render.ts +45 -26
  394. package/src/task/skc-command.ts +2 -2
  395. package/src/task/types.ts +55 -10
  396. package/src/task/ultragoal-redteam-activation.ts +75 -0
  397. package/src/tools/ask.ts +1 -1
  398. package/src/tools/ast-edit.ts +2 -2
  399. package/src/tools/bash-allowed-prefixes.ts +45 -1
  400. package/src/tools/bash-pty-selection.ts +2 -2
  401. package/src/tools/browser/launch.ts +41 -6
  402. package/src/tools/browser/screenshot-format.ts +6 -1
  403. package/src/tools/cron.ts +1 -1
  404. package/src/tools/fetch.ts +127 -154
  405. package/src/tools/image-gen.ts +476 -23
  406. package/src/tools/index.ts +7 -1
  407. package/src/tools/output-meta.ts +176 -9
  408. package/src/tools/path-utils.ts +5 -1
  409. package/src/tools/read-internals.ts +44 -0
  410. package/src/tools/read.ts +1544 -310
  411. package/src/tools/resource-gc.ts +665 -125
  412. package/src/tools/skill-discovery.ts +39 -3
  413. package/src/tools/sqlite-reader.ts +63 -5
  414. package/src/tools/subagent-render.ts +74 -16
  415. package/src/tools/subagent.ts +2 -0
  416. package/src/tools/tool-result.ts +14 -1
  417. package/src/utils/edit-mode.ts +2 -2
  418. package/src/utils/pasted-image-path.ts +15 -6
  419. package/src/utils/prompt-suggestion.ts +265 -0
  420. package/src/utils/shell-snapshot.ts +173 -63
  421. package/src/utils/sixel.ts +3 -3
  422. package/src/web/insane/bridge.ts +5 -1
  423. package/src/web/insane/url-guard.ts +140 -27
  424. package/src/web/scrapers/docs-rs.ts +30 -5
  425. package/src/web/scrapers/types.ts +19 -49
  426. package/src/web/scrapers/utils.ts +12 -26
  427. package/src/web/search/providers/codex.ts +1 -1
  428. package/src/workflow/workflow-intent-diff.ts +4 -1
@@ -1,20 +1,49 @@
1
1
  import * as crypto from "node:crypto";
2
- import * as os from "node:os";
3
2
  import * as path from "node:path";
3
+ import { getConfigRootDir } from "@sayknow-cli/utils";
4
4
  import type { WorkflowHudSummary } from "../skill-state/active-state";
5
5
  import { buildUltragoalHudSummary as buildWorkflowUltragoalHudSummary } from "../skill-state/workflow-hud";
6
6
  import { renderCliWriteReceipt } from "./cli-write-receipt";
7
7
  import { DEFAULT_ULTRAGOAL_OBJECTIVE } from "./goal-mode-request";
8
8
  import {
9
+ assertCwdMatchesRepositoryBinding,
10
+ captureRepositoryBinding,
11
+ parseRepositoryBinding,
12
+ type RepositoryBinding,
13
+ } from "./repository-binding";
14
+ import {
15
+ CRITIC_GATE_HARD_STOP_EVENT,
16
+ CRITIC_GATE_OVERRIDE_EVENT,
17
+ CRITIC_VERDICT_EVENT,
18
+ type CriticVerdict,
19
+ computeCriticVerdictPlanGeneration,
9
20
  computeUltragoalPlanGeneration,
21
+ countNonOkayTerminalCriticVerdicts,
22
+ finalAggregateReceiptMissingCriticOkay,
10
23
  findFreshBatchCloseReceipt,
11
24
  findLedgerReceiptEvent,
25
+ isCleanPauseCriticVerdictShape,
12
26
  requiredUltragoalGoals,
27
+ TERMINAL_CRITIC_CEILING,
28
+ terminalCriticCeilingReached,
29
+ terminalCriticGateOverridden,
30
+ terminalCriticHardStopReached,
13
31
  validateDeferredMemberReceiptFresh,
14
32
  validateReceiptFreshBase,
15
33
  } from "./ultragoal-receipt-freshness";
16
34
 
17
- export { computeUltragoalPlanGeneration, receiptRelevantGoals } from "./ultragoal-receipt-freshness";
35
+ export {
36
+ CRITIC_GATE_HARD_STOP_EVENT,
37
+ CRITIC_GATE_OVERRIDE_EVENT,
38
+ CRITIC_VERDICT_EVENT,
39
+ type CriticVerdict,
40
+ computeUltragoalPlanGeneration,
41
+ countTerminalCriticVerdicts,
42
+ receiptRelevantGoals,
43
+ TERMINAL_CRITIC_CEILING,
44
+ terminalCriticCeilingReached,
45
+ terminalCriticGateOverridden,
46
+ } from "./ultragoal-receipt-freshness";
18
47
 
19
48
  import { sessionUltragoalDir, skcRoot } from "./session-layout";
20
49
  import {
@@ -170,6 +199,8 @@ export interface UltragoalPlan {
170
199
  skcObjective: string;
171
200
  skcObjectiveAliases?: string[];
172
201
  goals: UltragoalGoal[];
202
+ /** Authoritative repository identity for multi-repo fail-closed spawn (#2901). */
203
+ repositoryBinding?: RepositoryBinding;
173
204
  createdAt: string;
174
205
  updatedAt: string;
175
206
  [key: string]: unknown;
@@ -427,7 +458,6 @@ export const DEFAULT_ULTRAGOAL_NUDGE_BUDGET = 10;
427
458
  export function countUltragoalNudges(ledger: readonly UltragoalLedgerEvent[], goalId: string): number {
428
459
  return ledger.filter(event => event.event === "nudge" && event.goalId === goalId).length;
429
460
  }
430
-
431
461
  function parseNudgeBudgetValue(value: unknown): number | null {
432
462
  return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value >= 0 ? value : null;
433
463
  }
@@ -461,8 +491,7 @@ export async function resolveUltragoalNudgeBudget(cwd: string): Promise<{ budget
461
491
  const projectPath = path.join(skcRoot(cwd), "settings.json");
462
492
  const project = await readSettingsNudgeBudget(projectPath);
463
493
  if (project !== null) return { budget: project, source: projectPath };
464
- const userDir = process.env.SKC_CONFIG_DIR?.trim() || path.join(os.homedir(), ".skc");
465
- const userPath = path.join(userDir, "settings.json");
494
+ const userPath = path.join(getConfigRootDir(), "settings.json");
466
495
  const user = await readSettingsNudgeBudget(userPath);
467
496
  if (user !== null) return { budget: user, source: userPath };
468
497
  return { budget: DEFAULT_ULTRAGOAL_NUDGE_BUDGET, source: "default" };
@@ -1328,6 +1357,10 @@ function normalizePlan(raw: unknown): UltragoalPlan {
1328
1357
  (value): value is string => typeof value === "string" && value.trim().length > 0,
1329
1358
  )
1330
1359
  : undefined;
1360
+ let repositoryBinding: RepositoryBinding | undefined;
1361
+ if (record.repositoryBinding !== undefined) {
1362
+ repositoryBinding = parseRepositoryBinding(record.repositoryBinding);
1363
+ }
1331
1364
  return {
1332
1365
  version: 1,
1333
1366
  brief,
@@ -1337,6 +1370,7 @@ function normalizePlan(raw: unknown): UltragoalPlan {
1337
1370
  goals,
1338
1371
  createdAt,
1339
1372
  updatedAt,
1373
+ ...(repositoryBinding ? { repositoryBinding } : {}),
1340
1374
  ...(typeof record.state_revision === "number" && Number.isFinite(record.state_revision)
1341
1375
  ? { state_revision: record.state_revision }
1342
1376
  : {}),
@@ -1537,12 +1571,16 @@ export async function createUltragoalPlan(input: {
1537
1571
  goal.validationBatch = validationBatchByGoalId.get(goal.id);
1538
1572
  validateValidationBatchPipelineExclusion(goal);
1539
1573
  }
1574
+ const repositoryBinding = await captureRepositoryBinding(input.cwd, {
1575
+ displayPath: input.cwd,
1576
+ });
1540
1577
  const plan: UltragoalPlan = {
1541
1578
  version: 1,
1542
1579
  brief,
1543
1580
  skcGoalMode: input.skcGoalMode ?? "aggregate",
1544
1581
  skcObjective: DEFAULT_ULTRAGOAL_OBJECTIVE,
1545
1582
  goals,
1583
+ repositoryBinding,
1546
1584
  createdAt: now,
1547
1585
  updatedAt: now,
1548
1586
  };
@@ -1618,6 +1656,50 @@ export function getUltragoalRunCompletionState(
1618
1656
  };
1619
1657
  }
1620
1658
 
1659
+ /**
1660
+ * Discriminated next-action for `complete-goals` handoff (#2903).
1661
+ * `none` is reserved for genuine completion; `execute-goal` always carries a goal.
1662
+ */
1663
+ export type UltragoalCompleteNextActionKind =
1664
+ | "none"
1665
+ | "execute-goal"
1666
+ | "retry-failed"
1667
+ | "resolve-blockers"
1668
+ | "final-aggregate-receipt";
1669
+
1670
+ export type UltragoalCompleteNextAction = {
1671
+ kind: UltragoalCompleteNextActionKind;
1672
+ goal?: UltragoalGoal;
1673
+ blockedGoals?: UltragoalGoal[];
1674
+ failedGoals?: UltragoalGoal[];
1675
+ };
1676
+
1677
+ /**
1678
+ * Resolve the actionable next step after scheduling / complete-goals.
1679
+ * Blocked and review_blocked goals remain unschedulable; they surface as
1680
+ * `resolve-blockers` instead of a contradictory `execute-goal` without goal_id.
1681
+ */
1682
+ export function resolveUltragoalCompleteNextAction(
1683
+ plan: UltragoalPlan,
1684
+ options: { retryFailed?: boolean; selectedGoal?: UltragoalGoal } = {},
1685
+ ): UltragoalCompleteNextAction {
1686
+ const state = getUltragoalRunCompletionState(plan, { retryFailed: options.retryFailed });
1687
+ // Genuine completion keeps next_action=`none` (historical complete-goals contract).
1688
+ // final-aggregate-receipt is reserved for a future dedicated handoff; do not remap
1689
+ // allComplete here so aggregate runs still finish with `none` / complete text.
1690
+ if (state.allComplete) return { kind: "none" };
1691
+ const goal = options.selectedGoal ?? state.nextGoal;
1692
+ if (goal) return { kind: "execute-goal", goal };
1693
+ const blockedGoals = state.incompleteGoals.filter(
1694
+ item => item.status === "blocked" || item.status === "review_blocked",
1695
+ );
1696
+ if (blockedGoals.length > 0) return { kind: "resolve-blockers", blockedGoals };
1697
+ const failedGoals = state.incompleteGoals.filter(item => item.status === "failed");
1698
+ if (failedGoals.length > 0) return { kind: "retry-failed", failedGoals };
1699
+ // Incomplete but not schedulable (unexpected statuses): still actionable, not "none".
1700
+ return { kind: "resolve-blockers", blockedGoals: state.incompleteGoals };
1701
+ }
1702
+
1621
1703
  export async function startNextUltragoalGoal(input: {
1622
1704
  cwd: string;
1623
1705
  retryFailed?: boolean;
@@ -1626,11 +1708,27 @@ export async function startNextUltragoalGoal(input: {
1626
1708
  plan: UltragoalPlan;
1627
1709
  goal?: UltragoalGoal;
1628
1710
  allComplete: boolean;
1711
+ nextAction: UltragoalCompleteNextAction;
1629
1712
  }> {
1630
1713
  const plan = await readUltragoalPlan(input.cwd, input.sessionId);
1631
1714
  if (!plan) throw new Error("No ultragoal plan found. Run `skc ultragoal create-goals --brief ...` first.");
1632
- const goal = chooseNextGoal(plan, input.retryFailed === true);
1633
- if (!goal) return { plan, allComplete: getUltragoalRunCompletionState(plan).allComplete };
1715
+ // Fail closed: delegated execution requires stamped repository authority (#2901).
1716
+ if (!plan.repositoryBinding) {
1717
+ throw new Error(
1718
+ "Ultragoal plan is missing repositoryBinding; recreate goals so the plan is bound to an authoritative repository identity.",
1719
+ );
1720
+ }
1721
+ await assertCwdMatchesRepositoryBinding(input.cwd, plan.repositoryBinding);
1722
+ const retryFailed = input.retryFailed === true;
1723
+ const goal = chooseNextGoal(plan, retryFailed);
1724
+ if (!goal) {
1725
+ const state = getUltragoalRunCompletionState(plan, { retryFailed });
1726
+ return {
1727
+ plan,
1728
+ allComplete: state.allComplete,
1729
+ nextAction: resolveUltragoalCompleteNextAction(plan, { retryFailed }),
1730
+ };
1731
+ }
1634
1732
  if (goal.status !== "active") {
1635
1733
  const now = new Date().toISOString();
1636
1734
  goal.status = "active";
@@ -1640,7 +1738,12 @@ export async function startNextUltragoalGoal(input: {
1640
1738
  await writePlan(input.cwd, plan, input.sessionId);
1641
1739
  await appendLedger(input.cwd, { event: "goal_started", goalId: goal.id }, input.sessionId);
1642
1740
  }
1643
- return { plan, goal, allComplete: false };
1741
+ return {
1742
+ plan,
1743
+ goal,
1744
+ allComplete: false,
1745
+ nextAction: { kind: "execute-goal", goal },
1746
+ };
1644
1747
  }
1645
1748
 
1646
1749
  async function readStructuredValue(cwd: string, value: string): Promise<unknown> {
@@ -2514,12 +2617,23 @@ async function validateCompletionQualityGate(
2514
2617
  } = {},
2515
2618
  ): Promise<void> {
2516
2619
  const batchMode = options.goal?.validationBatch;
2620
+ const receiptKind =
2621
+ options.plan && options.goal && options.ledger
2622
+ ? chooseReceiptKind(options.plan, options.ledger, options.goal, "complete")
2623
+ : undefined;
2624
+ const isFinalAggregate = receiptKind === "final-aggregate";
2517
2625
  if (batchMode && options.goal && options.goal.id !== batchMode.finalGoalId) {
2518
2626
  validateDeferredCompletionQualityGate(gate, options.goal, batchMode, options.changeSet);
2519
2627
  return;
2520
2628
  }
2521
2629
  if (batchMode && options.goal && options.goal.id === batchMode.finalGoalId) {
2522
- const allowedKeys = new Set(["architectReview", "executorQa", "iteration", "validationBatchClose"]);
2630
+ const allowedKeys = new Set([
2631
+ "architectReview",
2632
+ "executorQa",
2633
+ "iteration",
2634
+ "validationBatchClose",
2635
+ "criticReview",
2636
+ ]);
2523
2637
  const unsupportedKeys = Object.keys(gate).filter(key => !allowedKeys.has(key));
2524
2638
  if (unsupportedKeys.length > 0)
2525
2639
  throw new Error(`qualityGate contains unsupported keys: ${unsupportedKeys.join(", ")}`);
@@ -2534,8 +2648,8 @@ async function validateCompletionQualityGate(
2534
2648
  }
2535
2649
  const allowedKeys = new Set(
2536
2650
  batchMode
2537
- ? ["architectReview", "executorQa", "iteration", "validationBatchClose"]
2538
- : ["architectReview", "executorQa", "iteration"],
2651
+ ? ["architectReview", "executorQa", "iteration", "validationBatchClose", "criticReview"]
2652
+ : ["architectReview", "executorQa", "iteration", "criticReview"],
2539
2653
  );
2540
2654
  const unsupportedKeys = Object.keys(gate).filter(key => !allowedKeys.has(key));
2541
2655
  if (unsupportedKeys.length > 0) {
@@ -2547,6 +2661,25 @@ async function validateCompletionQualityGate(
2547
2661
  if (!architectReview || !executorQa || !iteration) {
2548
2662
  throw new Error("qualityGate requires architectReview, executorQa, and iteration objects");
2549
2663
  }
2664
+ if (isFinalAggregate) {
2665
+ if (
2666
+ options.ledger &&
2667
+ terminalCriticCeilingReached(options.ledger) &&
2668
+ !terminalCriticGateOverridden(options.ledger)
2669
+ ) {
2670
+ throw new Error(
2671
+ "checkpoint --status complete blocked: terminal-critic ceiling reached; requires human/leader skc ultragoal record-critic-gate-override before completion",
2672
+ );
2673
+ }
2674
+ const criticReview = qualityGateObject(gate.criticReview);
2675
+ if (criticReview?.verdict !== "OKAY") {
2676
+ throw new Error(
2677
+ "checkpoint --status complete (final aggregate) requires criticReview with verdict OKAY, non-empty evidence, and empty blockers",
2678
+ );
2679
+ }
2680
+ requireNonEmptyString(criticReview.evidence, "criticReview.evidence");
2681
+ requireEmptyBlockers(criticReview.blockers, "criticReview.blockers");
2682
+ }
2550
2683
  if (
2551
2684
  architectReview.architectureStatus !== CLEAN_ARCHITECT_STATUS ||
2552
2685
  architectReview.productStatus !== CLEAN_ARCHITECT_STATUS ||
@@ -2958,8 +3091,13 @@ export async function checkpointUltragoalGoal(input: {
2958
3091
  // receipt, the replay is a genuine re-verification: it must run the full
2959
3092
  // quality gate and mint a fresh receipt, otherwise a completed goal with a
2960
3093
  // context-staled receipt can never be repaired (different evidence is
2961
- // rejected on complete goals by design). A mutated goal row keeps the
2962
- // fail-loud tamper handling in the idempotent branch below.
3094
+ // rejected on complete goals by design). A final-aggregate receipt whose
3095
+ // recorded checkpoint gate lacks a clean criticReview OKAY is likewise
3096
+ // repair-eligible: it is not "stale", but the completion guard rejects it
3097
+ // forever (active_missing_critic_verdict), so a no-op replay would leave
3098
+ // the run permanently unable to complete even after the terminal critic
3099
+ // records OKAY. A mutated goal row keeps the fail-loud tamper handling in
3100
+ // the idempotent branch below.
2963
3101
  const staleCompleteReceiptReplay =
2964
3102
  input.status === "complete" &&
2965
3103
  goal.status === "complete" &&
@@ -2967,13 +3105,14 @@ export async function checkpointUltragoalGoal(input: {
2967
3105
  Boolean(matchingIdempotentEvent) &&
2968
3106
  (!goal.completionVerification ||
2969
3107
  (goal.completionVerification.verifiedAt === goal.updatedAt &&
2970
- validateReceiptFreshBase({
3108
+ (validateReceiptFreshBase({
2971
3109
  plan,
2972
3110
  ledger: ledgerBefore,
2973
3111
  goal,
2974
3112
  receipt: goal.completionVerification,
2975
3113
  receiptKind: goal.completionVerification.receiptKind,
2976
- }) !== null));
3114
+ }) !== null ||
3115
+ finalAggregateReceiptMissingCriticOkay(ledgerBefore, goal.completionVerification))));
2977
3116
  if (
2978
3117
  goal.status === input.status &&
2979
3118
  goal.evidence === evidence &&
@@ -3550,10 +3689,10 @@ export async function recordUltragoalReviewBlockers(input: {
3550
3689
  export type UltragoalBlockerClassification = "human_blocked" | "resolvable";
3551
3690
 
3552
3691
  /**
3553
- * Record an audited blocker triage classification in the durable ledger. A
3554
- * `human_blocked` classification is the only thing that authorizes
3555
- * `goal({"op":"pause"})` while an Ultragoal run is active; `resolvable` is an
3556
- * audit note and never unblocks pause.
3692
+ * Record an audited blocker triage classification in the durable ledger. Pause
3693
+ * requires the latest `blocker_classified` event to be `human_blocked` and a
3694
+ * later clean pause terminal critic verdict bound to that classification; `resolvable`
3695
+ * is an audit note and never unblocks pause.
3557
3696
  */
3558
3697
  export async function recordUltragoalBlockerClassification(input: {
3559
3698
  cwd: string;
@@ -3574,6 +3713,130 @@ export async function recordUltragoalBlockerClassification(input: {
3574
3713
  });
3575
3714
  }
3576
3715
 
3716
+ export async function recordUltragoalCriticVerdict(input: {
3717
+ cwd: string;
3718
+ terminus: "completion" | "pause";
3719
+ verdict: CriticVerdict;
3720
+ evidence: string;
3721
+ blockers?: string[];
3722
+ goalId?: string;
3723
+ classificationEventId?: string;
3724
+ }): Promise<UltragoalLedgerEvent> {
3725
+ const evidence = input.evidence.trim();
3726
+ if (!evidence) throw new Error("record-critic-verdict --evidence is required");
3727
+ if (input.terminus !== "completion" && input.terminus !== "pause") {
3728
+ throw new Error('record-critic-verdict --terminus must be "completion" or "pause"');
3729
+ }
3730
+ if (input.verdict !== "OKAY" && input.verdict !== "ITERATE" && input.verdict !== "REJECT") {
3731
+ throw new Error("record-critic-verdict --verdict must be OKAY, ITERATE, or REJECT");
3732
+ }
3733
+ const blockers = stringArray(input.blockers ?? []);
3734
+ if (!blockers) throw new Error("record-critic-verdict --blockers-json must be a JSON string array");
3735
+ if (input.terminus === "completion" && input.verdict === "OKAY" && blockers.length > 0) {
3736
+ throw new Error("OKAY critic verdict must have empty blockers");
3737
+ }
3738
+ const classificationEventId = input.classificationEventId?.trim();
3739
+ if (input.terminus === "pause" && !classificationEventId) {
3740
+ throw new Error("record-critic-verdict --classification-event-id is required for pause verdicts");
3741
+ }
3742
+ const resolvedSessionId = resolveSkcSessionForWrite(input.cwd, {
3743
+ envSessionId: process.env.SKC_SESSION_ID,
3744
+ }).skcSessionId;
3745
+ const paths = getUltragoalPaths(input.cwd, resolvedSessionId);
3746
+ return withWorkflowStateLock(
3747
+ paths.ledgerPath,
3748
+ async () => {
3749
+ const plan = await readUltragoalPlan(input.cwd, resolvedSessionId);
3750
+ if (!plan) throw new Error("record-critic-verdict requires an active ultragoal plan");
3751
+ const ledger = await readUltragoalLedger(input.cwd, resolvedSessionId);
3752
+ if (input.terminus === "pause") {
3753
+ const latestClassification = [...ledger].reverse().find(event => event.event === "blocker_classified");
3754
+ if (
3755
+ latestClassification?.classification !== "human_blocked" ||
3756
+ latestClassification.eventId !== classificationEventId
3757
+ ) {
3758
+ throw new Error(
3759
+ "record-critic-verdict pause requires --classification-event-id to name the latest human_blocked classification",
3760
+ );
3761
+ }
3762
+ }
3763
+ const planGeneration = computeCriticVerdictPlanGeneration(plan);
3764
+ if (
3765
+ input.terminus === "pause" &&
3766
+ input.verdict === "OKAY" &&
3767
+ !isCleanPauseCriticVerdictShape(
3768
+ {
3769
+ event: CRITIC_VERDICT_EVENT,
3770
+ terminus: input.terminus,
3771
+ verdict: input.verdict,
3772
+ evidence,
3773
+ blockers,
3774
+ planGeneration,
3775
+ classificationEventId,
3776
+ },
3777
+ planGeneration,
3778
+ classificationEventId!,
3779
+ )
3780
+ ) {
3781
+ throw new Error("OKAY critic verdict must have empty blockers");
3782
+ }
3783
+ const criticVerdict = await appendLedger(
3784
+ input.cwd,
3785
+ {
3786
+ event: CRITIC_VERDICT_EVENT,
3787
+ terminus: input.terminus,
3788
+ verdict: input.verdict,
3789
+ evidence,
3790
+ blockers,
3791
+ planGeneration,
3792
+ ...(classificationEventId ? { classificationEventId } : {}),
3793
+ ...(input.goalId?.trim() ? { goalId: input.goalId.trim() } : {}),
3794
+ },
3795
+ resolvedSessionId,
3796
+ );
3797
+ const updatedLedger = [...ledger, criticVerdict];
3798
+ const count = countNonOkayTerminalCriticVerdicts(updatedLedger);
3799
+ if (count >= TERMINAL_CRITIC_CEILING && !terminalCriticHardStopReached(updatedLedger)) {
3800
+ await appendLedger(
3801
+ input.cwd,
3802
+ {
3803
+ event: CRITIC_GATE_HARD_STOP_EVENT,
3804
+ planGeneration,
3805
+ reason: "Terminal critic verdict ceiling reached.",
3806
+ count,
3807
+ },
3808
+ resolvedSessionId,
3809
+ );
3810
+ }
3811
+ return criticVerdict;
3812
+ },
3813
+ { cwd: input.cwd },
3814
+ );
3815
+ }
3816
+
3817
+ export async function recordUltragoalCriticGateOverride(input: {
3818
+ cwd: string;
3819
+ evidence: string;
3820
+ }): Promise<UltragoalLedgerEvent> {
3821
+ const evidence = input.evidence.trim();
3822
+ if (!evidence) throw new Error("record-critic-gate-override --evidence is required");
3823
+ const resolvedSessionId = resolveSkcSessionForWrite(input.cwd, {
3824
+ envSessionId: process.env.SKC_SESSION_ID,
3825
+ }).skcSessionId;
3826
+ const paths = getUltragoalPaths(input.cwd, resolvedSessionId);
3827
+ return withWorkflowStateLock(
3828
+ paths.ledgerPath,
3829
+ async () => {
3830
+ const ledger = await readUltragoalLedger(input.cwd, resolvedSessionId);
3831
+ if (!terminalCriticHardStopReached(ledger)) {
3832
+ throw new Error("record-critic-gate-override requires a durably recorded terminal critic hard stop");
3833
+ }
3834
+ return appendLedger(input.cwd, { event: CRITIC_GATE_OVERRIDE_EVENT, evidence }, resolvedSessionId);
3835
+ },
3836
+ { cwd: input.cwd },
3837
+ );
3838
+ }
3839
+
3577
3840
  type UltragoalReviewMode = "review-only" | "review-start";
3578
3841
  type UltragoalReviewContractStrength = "strong" | "thin-derived";
3579
3842
 
@@ -3972,7 +4235,7 @@ function renderUltragoalHelp(args: readonly string[]): string | null {
3972
4235
  " $ skc ultragoal classify-blocker --classification <human_blocked|resolvable> --evidence <text> [FLAGS]",
3973
4236
  "",
3974
4237
  "FLAGS",
3975
- " --classification=<value> Required. human_blocked authorizes pause only as the latest ledger event; resolvable never authorizes pause",
4238
+ " --classification=<value> Required. human_blocked must be the latest blocker_classified event; pause also requires a later bound clean pause terminal critic OKAY verdict; resolvable never authorizes pause",
3976
4239
  " --evidence=<value> Required. Specific blocker evidence; must name the human-only dependency for human_blocked",
3977
4240
  " --goal-id=<value> Optional durable .skc/ultragoal goal id, e.g. G001",
3978
4241
  " --json Output a machine-readable receipt",
@@ -3983,6 +4246,44 @@ function renderUltragoalHelp(args: readonly string[]): string | null {
3983
4246
  "",
3984
4247
  ].join("\n");
3985
4248
  }
4249
+ if (subject === "record-critic-verdict") {
4250
+ return [
4251
+ "Run native SKC Ultragoal workflow commands",
4252
+ "",
4253
+ "USAGE",
4254
+ " $ skc ultragoal record-critic-verdict --terminus <completion|pause> --verdict <OKAY|ITERATE|REJECT> --evidence <text> [--blockers-json <json>] [--goal-id <id>] [--classification-event-id <id>]",
4255
+ "",
4256
+ "FLAGS",
4257
+ " --terminus=<value> Required. completion or pause",
4258
+ " --verdict=<value> Required. OKAY, ITERATE, or REJECT",
4259
+ " --evidence=<value> Required. Specific evidence supporting the verdict",
4260
+ " --blockers-json=<value> Optional JSON string array of blockers",
4261
+ " --goal-id=<value> Optional durable .skc/ultragoal goal id, e.g. G001",
4262
+ " --classification-event-id=<id> Required for pause verdicts; binds the human_blocked classification",
4263
+ " --json Output a machine-readable receipt",
4264
+ "",
4265
+ "EXAMPLES",
4266
+ ' $ skc ultragoal record-critic-verdict --terminus completion --verdict OKAY --evidence "all final-aggregate checkpoint evidence is current"',
4267
+ "",
4268
+ ].join("\n");
4269
+ }
4270
+ if (subject === "record-critic-gate-override") {
4271
+ return [
4272
+ "Run native SKC Ultragoal workflow commands",
4273
+ "",
4274
+ "USAGE",
4275
+ " $ skc ultragoal record-critic-gate-override --evidence <text> [--json]",
4276
+ "",
4277
+ "FLAGS",
4278
+ " --evidence=<value> Required. Human/leader authorization evidence for the terminal-critic ceiling override",
4279
+ " --json Output a machine-readable receipt",
4280
+ "",
4281
+ "EXAMPLES",
4282
+ ' $ skc ultragoal record-critic-gate-override --evidence "leader approved another terminal attempt after reviewing all five findings"',
4283
+ "",
4284
+ ].join("\n");
4285
+ }
4286
+
3986
4287
  return [
3987
4288
  "Run native SKC Ultragoal workflow commands",
3988
4289
  "",
@@ -3998,11 +4299,14 @@ function renderUltragoalHelp(args: readonly string[]): string | null {
3998
4299
  " steer",
3999
4300
  " record-review-blockers",
4000
4301
  " classify-blocker",
4302
+ " record-critic-verdict",
4303
+ " record-critic-gate-override",
4304
+
4001
4305
  " start-pipeline-overlap",
4002
4306
  " join-pipeline-overlap",
4003
4307
  " rebaseline-pipeline-overlap",
4004
4308
  "",
4005
- "Run `skc ultragoal checkpoint --help`, `skc ultragoal review --help`, or `skc ultragoal classify-blocker --help` for command-specific requirements.",
4309
+ "Run `skc ultragoal checkpoint --help`, `skc ultragoal review --help`, `skc ultragoal classify-blocker --help`, `skc ultragoal record-critic-verdict --help`, or `skc ultragoal record-critic-gate-override --help` for command-specific requirements.",
4006
4310
  "",
4007
4311
  ].join("\n");
4008
4312
  }
@@ -4021,31 +4325,111 @@ function renderStatus(summary: UltragoalStatusSummary, json: boolean): string {
4021
4325
  return renderUltragoalStatusMarkdown(summary);
4022
4326
  }
4023
4327
 
4328
+ function summarizeBlockedGoalForHandoff(goal: UltragoalGoal): {
4329
+ id: string;
4330
+ status: UltragoalGoalStatus;
4331
+ evidence?: string;
4332
+ } {
4333
+ const evidence = typeof goal.evidence === "string" && goal.evidence.trim() ? goal.evidence.trim() : undefined;
4334
+ return {
4335
+ id: goal.id,
4336
+ status: goal.status,
4337
+ ...(evidence ? { evidence } : {}),
4338
+ };
4339
+ }
4340
+
4024
4341
  function renderCompleteHandoff(
4025
- result: { plan: UltragoalPlan; goal?: UltragoalGoal; allComplete: boolean },
4342
+ result: {
4343
+ plan: UltragoalPlan;
4344
+ goal?: UltragoalGoal;
4345
+ allComplete: boolean;
4346
+ nextAction?: UltragoalCompleteNextAction;
4347
+ },
4026
4348
  json: boolean,
4027
4349
  cwd: string,
4028
4350
  ): string {
4351
+ const nextAction =
4352
+ result.nextAction ??
4353
+ resolveUltragoalCompleteNextAction(result.plan, {
4354
+ selectedGoal: result.goal,
4355
+ });
4356
+ const goalsPath = getUltragoalPaths(cwd, currentUltragoalSessionId(cwd)).goalsPath;
4357
+
4029
4358
  if (json) {
4030
- return renderCliWriteReceipt({
4359
+ const receipt: Record<string, unknown> = {
4031
4360
  ok: true,
4032
4361
  all_complete: result.allComplete,
4033
- next_action: result.allComplete ? "none" : "execute-goal",
4034
- goal_id: result.goal?.id,
4035
- goal_status: result.goal?.status,
4362
+ next_action: nextAction.kind,
4036
4363
  skc_objective: result.plan.skcObjective,
4037
- goals_path: getUltragoalPaths(cwd, currentUltragoalSessionId(cwd)).goalsPath,
4038
- });
4364
+ goals_path: goalsPath,
4365
+ };
4366
+ if (nextAction.kind === "execute-goal" && nextAction.goal) {
4367
+ receipt.goal_id = nextAction.goal.id;
4368
+ receipt.goal_status = nextAction.goal.status;
4369
+ }
4370
+ if (nextAction.kind === "resolve-blockers" && nextAction.blockedGoals) {
4371
+ receipt.blocked_goals = nextAction.blockedGoals.map(summarizeBlockedGoalForHandoff);
4372
+ receipt.blocked_goal_ids = nextAction.blockedGoals.map(goal => goal.id);
4373
+ receipt.recovery_hints = [
4374
+ "skc ultragoal classify-blocker --help",
4375
+ "skc ultragoal record-review-blockers --help",
4376
+ "skc ultragoal steer --kind add_subgoal --help",
4377
+ "skc ultragoal steer --kind mark_blocked_superseded --help",
4378
+ ];
4379
+ }
4380
+ if (nextAction.kind === "retry-failed" && nextAction.failedGoals) {
4381
+ receipt.failed_goal_ids = nextAction.failedGoals.map(goal => goal.id);
4382
+ receipt.recovery_hints = ["skc ultragoal complete-goals --retry-failed"];
4383
+ }
4384
+ if (nextAction.kind === "final-aggregate-receipt") {
4385
+ receipt.recovery_hints = [
4386
+ "Finalize the aggregate completion receipt before treating the ultragoal run as closed.",
4387
+ ];
4388
+ }
4389
+ return renderCliWriteReceipt(receipt);
4039
4390
  }
4040
- if (result.allComplete) return "ultragoal complete all=true\n";
4041
- if (!result.goal) return "ultragoal next-action=none\n";
4042
- return [
4043
- `ultragoal next-action=execute-goal goal-id=${result.goal.id}`,
4044
- `objective=${result.goal.objective}`,
4045
- `skc-objective=${result.plan.skcObjective}`,
4046
- "checkpoint requires=architectReview:CLEAR+APPROVE,executorQa:passed",
4047
- "",
4048
- ].join("\n");
4391
+
4392
+ if (nextAction.kind === "none" || (result.allComplete && nextAction.kind !== "final-aggregate-receipt")) {
4393
+ return "ultragoal complete all=true\n";
4394
+ }
4395
+ if (nextAction.kind === "final-aggregate-receipt") {
4396
+ return [
4397
+ "ultragoal next-action=final-aggregate-receipt",
4398
+ "hint=finalize the aggregate completion receipt before treating the run as closed",
4399
+ "",
4400
+ ].join("\n");
4401
+ }
4402
+ if (nextAction.kind === "execute-goal" && nextAction.goal) {
4403
+ return [
4404
+ `ultragoal next-action=execute-goal goal-id=${nextAction.goal.id}`,
4405
+ `objective=${nextAction.goal.objective}`,
4406
+ `skc-objective=${result.plan.skcObjective}`,
4407
+ "checkpoint requires=architectReview:CLEAR+APPROVE,executorQa:passed",
4408
+ "",
4409
+ ].join("\n");
4410
+ }
4411
+ if (nextAction.kind === "resolve-blockers" && nextAction.blockedGoals && nextAction.blockedGoals.length > 0) {
4412
+ const ids = nextAction.blockedGoals.map(goal => goal.id).join(",");
4413
+ const statuses = nextAction.blockedGoals.map(goal => `${goal.id}:${goal.status}`).join(",");
4414
+ return [
4415
+ "ultragoal next-action=resolve-blockers",
4416
+ `blocked-goal-ids=${ids}`,
4417
+ `blocked-statuses=${statuses}`,
4418
+ "hint=resolve blockers via classify-blocker / record-review-blockers / steer --kind add_subgoal (or audited mark_blocked_superseded); blocked goals stay unschedulable",
4419
+ "",
4420
+ ].join("\n");
4421
+ }
4422
+ if (nextAction.kind === "retry-failed" && nextAction.failedGoals && nextAction.failedGoals.length > 0) {
4423
+ const ids = nextAction.failedGoals.map(goal => goal.id).join(",");
4424
+ return [
4425
+ "ultragoal next-action=retry-failed",
4426
+ `failed-goal-ids=${ids}`,
4427
+ "hint=run `skc ultragoal complete-goals --retry-failed` after the failure is addressed",
4428
+ "",
4429
+ ].join("\n");
4430
+ }
4431
+ // Fail closed: never claim complete or execute-goal without a goal id.
4432
+ return "ultragoal next-action=resolve-blockers\nhint=no schedulable goal; inspect goals.json and ledger\n";
4049
4433
  }
4050
4434
  function renderCheckpointContinuation(
4051
4435
  result: UltragoalCheckpointContinuation,
@@ -4354,8 +4738,53 @@ async function dispatchUltragoalCommand(args: string[], cwd: string): Promise<Ul
4354
4738
  ok: true,
4355
4739
  event: "blocker_classified",
4356
4740
  classification: event.classification,
4741
+ event_id: event.eventId,
4742
+ })
4743
+ : `Recorded blocker classification: ${String(event.classification)} event-id=${String(event.eventId)}.\n`,
4744
+ };
4745
+ }
4746
+ case "record-critic-verdict": {
4747
+ const blockersJson = flagValue(args, "--blockers-json");
4748
+ const blockers =
4749
+ blockersJson === undefined ? undefined : stringArray(await readStructuredValue(cwd, blockersJson));
4750
+ if (blockersJson !== undefined && !blockers) {
4751
+ throw new Error("record-critic-verdict --blockers-json must be a JSON string array");
4752
+ }
4753
+ const event = await recordUltragoalCriticVerdict({
4754
+ cwd,
4755
+ terminus: (flagValue(args, "--terminus") ?? "") as "completion" | "pause",
4756
+ verdict: (flagValue(args, "--verdict") ?? "") as CriticVerdict,
4757
+ evidence: flagValue(args, "--evidence") ?? "",
4758
+ blockers: blockers ?? undefined,
4759
+ goalId: flagValue(args, "--goal-id"),
4760
+ classificationEventId: flagValue(args, "--classification-event-id"),
4761
+ });
4762
+ return {
4763
+ status: 0,
4764
+ stdout: json
4765
+ ? renderCliWriteReceipt({
4766
+ ok: true,
4767
+ event: CRITIC_VERDICT_EVENT,
4768
+ terminus: event.terminus,
4769
+ verdict: event.verdict,
4770
+ })
4771
+ : `Recorded critic verdict: ${String(event.verdict)} (${String(event.terminus)}).\n`,
4772
+ };
4773
+ }
4774
+ case "record-critic-gate-override": {
4775
+ const event = await recordUltragoalCriticGateOverride({
4776
+ cwd,
4777
+ evidence: flagValue(args, "--evidence") ?? "",
4778
+ });
4779
+ return {
4780
+ status: 0,
4781
+ stdout: json
4782
+ ? renderCliWriteReceipt({
4783
+ ok: true,
4784
+ event: CRITIC_GATE_OVERRIDE_EVENT,
4785
+ event_id: event.eventId,
4357
4786
  })
4358
- : `Recorded blocker classification: ${String(event.classification)}.\n`,
4787
+ : `Recorded terminal critic gate override event-id=${String(event.eventId)}.\n`,
4359
4788
  };
4360
4789
  }
4361
4790
  case "start-pipeline-overlap": {
@@ -4435,6 +4864,8 @@ const RECONCILE_COMMANDS = new Set([
4435
4864
  "record-review-blockers",
4436
4865
  "review",
4437
4866
  "classify-blocker",
4867
+ "record-critic-verdict",
4868
+ "record-critic-gate-override",
4438
4869
  "start-pipeline-overlap",
4439
4870
  "join-pipeline-overlap",
4440
4871
  "rebaseline-pipeline-overlap",