@sayknow-cli/coding-agent 0.4.7 → 0.5.1

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 +122 -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 +20 -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
@@ -96,7 +96,6 @@ export interface GuardedStateWriterOptions extends StateWriterOptions {
96
96
  policy: StateWritePolicy;
97
97
  expectedRevision?: number;
98
98
  sourceRevision?: number;
99
- lockHeld?: boolean;
100
99
  }
101
100
 
102
101
  export type GuardedWriteResult =
@@ -114,6 +113,11 @@ export interface StateWriterOptions {
114
113
  * `withFileLock` defaults.
115
114
  */
116
115
  lock?: FileLockOptions;
116
+ /**
117
+ * Caller already holds the workflow state lock for this target path (via
118
+ * `withWorkflowStateLock`). Skip re-acquisition to avoid self-deadlock.
119
+ */
120
+ lockHeld?: boolean;
117
121
  }
118
122
 
119
123
  export class StateWriteConflictError extends Error {
@@ -681,63 +685,71 @@ export async function writeWorkflowEnvelopeAtomic(
681
685
  options?: StateWriterOptions,
682
686
  ): Promise<string> {
683
687
  const filePath = resolveSkcTarget(targetPath, cwdForOptions(options));
684
- const withReceipt = withWorkflowReceipt(value, buildReceipt(options));
685
- const stamped = stampWorkflowEnvelopeChecksum(withReceipt, filePath);
686
- const parsed = RequiredOnWriteEnvelopeSchema.safeParse(stamped);
687
- if (!parsed.success) {
688
- throw new Error(
689
- `Refusing to write invalid workflow state envelope to ${filePath}: ${parsed.error.issues
690
- .map(issue => `${issue.path.join(".") || "<root>"}: ${issue.message}`)
691
- .join("; ")}`,
692
- );
693
- }
694
- // #658: internal runtime writers (ralplan/ultragoal/deep-interview/team) persist
695
- // envelopes directly, bypassing the `skc state` CLI transition gate (`isValidTransition`,
696
- // historically the sole call site in state-runtime.ts). Re-assert that gate on every
697
- // sanctioned envelope write so internal writes cannot persist invalid state-machine phase
698
- // transitions silently. Forced writes (`skc state ... --force`, reconcile repairs) carry
699
- // `audit.forced` and bypass, mirroring the CLI's `use --force to bypass`.
700
- //
701
- // The gate governs ACTIVE workflow progression only. Deactivation/teardown writes
702
- // (`active: false`, e.g. `skc state clear`, which persists the universal `complete`
703
- // sentinel that is not a per-skill manifest state) leave the transition graph and are
704
- // intentionally exempt.
705
- if (options?.audit?.forced !== true && parsed.data.active === true) {
706
- const toPhase = parsed.data.current_phase.trim();
707
- if (toPhase) {
708
- // Lazy import: workflow-manifest dereferences CANONICAL_SKC_WORKFLOW_SKILLS at
709
- // module load, and active-state -> state-writer -> workflow-manifest -> active-state
710
- // is a load-time cycle. Importing at call time (after init) avoids the TDZ.
711
- const { isKnownWorkflowState, isValidTransition } = await import("./workflow-manifest");
712
- const skill = parsed.data.skill;
713
- // Structural invariant (hard): a `current_phase` absent from the skill's manifest is
714
- // never a legitimate internal write, matching the CLI/reconcile unknown-phase gate.
715
- if (!isKnownWorkflowState(skill, toPhase)) {
716
- throw new Error(
717
- `Refusing to write unknown ${skill} phase "${toPhase}" to ${filePath}: not a known ${skill} manifest state (forced writes bypass via audit.forced)`,
718
- );
719
- }
720
- // Transition invariant (#658, diagnostic-only safety net): resolve the prior phase
721
- // (caller-supplied `audit.fromPhase`, else the active persisted envelope on disk) and
722
- // flag edges the manifest does not define. Intentionally NON-blocking and audit-only
723
- // — the CLI path already hard-fails invalid edges before reaching here, and legitimate
724
- // internal repairs / ralplan short-mode stage skips move between valid states without a
725
- // direct manifest edge. It records an `invalid_transition_detected` audit entry (no
726
- // stderr) so such transitions are non-silent without breaking those flows.
727
- const fromPhase = (options?.audit?.fromPhase ?? (await readPersistedPhase(filePath)))?.trim();
728
- if (
729
- fromPhase &&
730
- fromPhase !== toPhase &&
731
- isKnownWorkflowState(skill, fromPhase) &&
732
- !isValidTransition(skill, fromPhase, toPhase)
733
- ) {
734
- await recordInvalidWorkflowTransition({ filePath, skill, fromPhase, toPhase, options });
688
+ const write = async (): Promise<string> => {
689
+ const withReceipt = withWorkflowReceipt(value, buildReceipt(options));
690
+ const stamped = stampWorkflowEnvelopeChecksum(withReceipt, filePath);
691
+ const parsed = RequiredOnWriteEnvelopeSchema.safeParse(stamped);
692
+ if (!parsed.success) {
693
+ throw new Error(
694
+ `Refusing to write invalid workflow state envelope to ${filePath}: ${parsed.error.issues
695
+ .map(issue => `${issue.path.join(".") || "<root>"}: ${issue.message}`)
696
+ .join("; ")}`,
697
+ );
698
+ }
699
+ // #658: internal runtime writers (ralplan/ultragoal/deep-interview/team) persist
700
+ // envelopes directly, bypassing the `skc state` CLI transition gate (`isValidTransition`,
701
+ // historically the sole call site in state-runtime.ts). Re-assert that gate on every
702
+ // sanctioned envelope write so internal writes cannot persist invalid state-machine phase
703
+ // transitions silently. Forced writes (`skc state ... --force`, reconcile repairs) carry
704
+ // `audit.forced` and bypass, mirroring the CLI's `use --force to bypass`.
705
+ //
706
+ // The gate governs ACTIVE workflow progression only. Deactivation/teardown writes
707
+ // (`active: false`, e.g. `skc state clear`, which persists the universal `complete`
708
+ // sentinel that is not a per-skill manifest state) leave the transition graph and are
709
+ // intentionally exempt.
710
+ if (options?.audit?.forced !== true && parsed.data.active === true) {
711
+ const toPhase = parsed.data.current_phase.trim();
712
+ if (toPhase) {
713
+ // Lazy import: workflow-manifest dereferences CANONICAL_SKC_WORKFLOW_SKILLS at
714
+ // module load, and active-state -> state-writer -> workflow-manifest -> active-state
715
+ // is a load-time cycle. Importing at call time (after init) avoids the TDZ.
716
+ const { isKnownWorkflowState, isValidTransition } = await import("./workflow-manifest");
717
+ const skill = parsed.data.skill;
718
+ // Structural invariant (hard): a `current_phase` absent from the skill's manifest is
719
+ // never a legitimate internal write, matching the CLI/reconcile unknown-phase gate.
720
+ if (!isKnownWorkflowState(skill, toPhase)) {
721
+ throw new Error(
722
+ `Refusing to write unknown ${skill} phase "${toPhase}" to ${filePath}: not a known ${skill} manifest state (forced writes bypass via audit.forced)`,
723
+ );
724
+ }
725
+ // Transition invariant (#658, diagnostic-only safety net): resolve the prior phase
726
+ // (caller-supplied `audit.fromPhase`, else the active persisted envelope on disk) and
727
+ // flag edges the manifest does not define. Intentionally NON-blocking and audit-only
728
+ // — the CLI path already hard-fails invalid edges before reaching here, and legitimate
729
+ // internal repairs / ralplan short-mode stage skips move between valid states without a
730
+ // direct manifest edge. It records an `invalid_transition_detected` audit entry (no
731
+ // stderr) so such transitions are non-silent without breaking those flows.
732
+ const fromPhase = (options?.audit?.fromPhase ?? (await readPersistedPhase(filePath)))?.trim();
733
+ if (
734
+ fromPhase &&
735
+ fromPhase !== toPhase &&
736
+ isKnownWorkflowState(skill, fromPhase) &&
737
+ !isValidTransition(skill, fromPhase, toPhase)
738
+ ) {
739
+ await recordInvalidWorkflowTransition({ filePath, skill, fromPhase, toPhase, options });
740
+ }
735
741
  }
736
742
  }
737
- }
738
- await atomicWrite(filePath, jsonText(stamped));
739
- await maybeAudit(filePath, options);
740
- return filePath;
743
+ await atomicWrite(filePath, jsonText(stamped));
744
+ await maybeAudit(filePath, options);
745
+ return filePath;
746
+ };
747
+ // Serialize with every other writer of the same state path. Without this, a
748
+ // revision-preserving envelope write (seed/spec persistence) can interleave
749
+ // inside a staged apply's check-then-write window and be silently overwritten
750
+ // (#3387 architect finding 1). Callers already inside `withWorkflowStateLock`
751
+ // for this path pass `lockHeld: true`.
752
+ return options?.lockHeld ? write() : lockResolvedWorkflowTarget(filePath, write, options?.lock);
741
753
  }
742
754
 
743
755
  export async function writeTextAtomic(targetPath: string, text: string, options?: StateWriterOptions): Promise<string> {
@@ -12,6 +12,7 @@ import type {
12
12
  SkcTeamWorkerLifecycle,
13
13
  SkcTeamWorktreeMode,
14
14
  } from "./team-runtime";
15
+ import { createInitialSkcTeamWorkerMemoryGuardLedger, workerMemoryGuardLedgerPath } from "./team-worker-memory-guard";
15
16
 
16
17
  /** Launch-specific option wiring kept separate from runtime dispatch. */
17
18
  export function withTeamLaunchTransport(
@@ -34,6 +35,7 @@ export function buildWorkerCommand(
34
35
  config: SkcTeamConfig,
35
36
  worker: SkcTeamWorker,
36
37
  platform: NodeJS.Platform = process.platform,
38
+ promptOverride?: string,
37
39
  ): string {
38
40
  const quote = platform === "win32" ? powershellQuote : shellQuote;
39
41
  const envAssignment = (key: string, value: string): string =>
@@ -41,7 +43,8 @@ export function buildWorkerCommand(
41
43
  const workspace = worker.worktree_path
42
44
  ? `Worker worktree: ${worker.worktree_path}.`
43
45
  : `Worker cwd: ${config.leader.cwd}.`;
44
- const prompt =
46
+ const initialPrompt =
47
+ promptOverride ??
45
48
  [
46
49
  `You are ${worker.id} in skc team ${config.team_name}.`,
47
50
  `Team state root: ${config.state_root}.`,
@@ -50,8 +53,9 @@ export function buildWorkerCommand(
50
53
  "Before implementation, claim your worker-owned task and treat the claimed task record as the source of truth. Do not implement directly from the broad team brief.",
51
54
  `Before claiming work, send startup ACK: skc team api worker-startup-ack --input '{"team_name":"${config.team_name}","worker_id":"${worker.id}","protocol_version":"1"}' --json.`,
52
55
  "Use skc team api update-worker-status to report task-local activity, then claim-task/transition-task-status with this worker id; keep heartbeat current during long work, record completion_evidence (summary plus a passed command or verified inspection/artifact item) before completed, and do not mutate leader-owned goal state.",
53
- ]
54
- .join("\n")
56
+ ].join("\n");
57
+ const prompt =
58
+ initialPrompt
55
59
  .replace(/[\uFEFF\u200B]/g, "")
56
60
  .replace(/\r?\n+/g, " ")
57
61
  .trim() || `Worker ${worker.id} ready.`;
@@ -66,6 +70,10 @@ export function buildWorkerCommand(
66
70
  envAssignment("SKC_TEAM_DISPLAY_NAME", config.display_name),
67
71
  envAssignment(SPAWN_PROVENANCE_ENV, config.leader.session_id.trim() || config.team_name),
68
72
  ...(worker.worktree_path ? [envAssignment("SKC_TEAM_WORKTREE_PATH", worker.worktree_path)] : []),
73
+ envAssignment(
74
+ "SKC_TEAM_WORKER_MEMORY_GUARD_PATH",
75
+ workerMemoryGuardLedgerPath(path.join(config.state_root, config.team_name), worker.id),
76
+ ),
69
77
  ];
70
78
  const joined = envLines.join(" ");
71
79
  const clearInheritedSession = config.skc_session_id
@@ -146,6 +154,7 @@ async function initializeStateDirs(
146
154
  runtime: SkcTeamLaunchRuntime,
147
155
  dir: string,
148
156
  workers: SkcTeamWorker[],
157
+ platform: NodeJS.Platform,
149
158
  ): Promise<void> {
150
159
  await fs.mkdir(path.join(dir, "mailbox"), { recursive: true });
151
160
  for (const worker of workers) {
@@ -167,6 +176,14 @@ async function initializeStateDirs(
167
176
  turn_count: 0,
168
177
  alive: true,
169
178
  });
179
+ await runtime.writeJson(
180
+ workerMemoryGuardLedgerPath(dir, worker.id),
181
+ createInitialSkcTeamWorkerMemoryGuardLedger({
182
+ workerId: worker.id,
183
+ platform,
184
+ now: runtime.now(),
185
+ }),
186
+ );
170
187
  }
171
188
  await fs.mkdir(runtime.mailboxDirPath(dir, "leader-fixed"), { recursive: true });
172
189
  await runtime.writeJson(runtime.mailboxPath(dir, "leader-fixed"), { messages: [] });
@@ -217,6 +234,18 @@ export async function startSkcTeamLaunch(
217
234
  await runtime.rollbackCreatedWorktrees(workers);
218
235
  throw error;
219
236
  }
237
+ const tasksByOwner = new Map<string, string[]>();
238
+ for (const task of initialTasks) {
239
+ const owner = task.owner?.trim();
240
+ if (!owner) continue;
241
+ const assigned = tasksByOwner.get(owner) ?? [];
242
+ assigned.push(task.id);
243
+ tasksByOwner.set(owner, assigned);
244
+ }
245
+ const workersWithAssignments = workers.map(worker => ({
246
+ ...worker,
247
+ assigned_tasks: tasksByOwner.get(worker.id) ?? worker.assigned_tasks,
248
+ }));
220
249
  const config: SkcTeamConfig = {
221
250
  team_name: teamName,
222
251
  display_name: displayName,
@@ -242,11 +271,11 @@ export async function startSkcTeamLaunch(
242
271
  },
243
272
  leader_cwd: cwd,
244
273
  team_state_root: stateRoot,
245
- workers,
274
+ workers: workersWithAssignments,
246
275
  created_at: createdAt,
247
276
  updated_at: createdAt,
248
277
  };
249
- await initializeStateDirs(runtime, dir, config.workers);
278
+ await initializeStateDirs(runtime, dir, config.workers, platform);
250
279
  await runtime.writeJson(path.join(dir, "config.json"), config);
251
280
  await runtime.writeJson(path.join(dir, "manifest.v2.json"), {
252
281
  version: 2,
@@ -455,7 +455,32 @@ export interface WorkerHeartbeatFile {
455
455
  last_turn_at: string;
456
456
  turn_count: number;
457
457
  alive: boolean;
458
+ /** Linux process start time, so a recycled PID cannot impersonate this worker. */
459
+ process_start_time?: string;
458
460
  }
461
+ /**
462
+ * Linux process start time (field 22 of /proc/<pid>/stat), used to pin a heartbeat
463
+ * to one specific process. PIDs are recycled, so without this a reaper can match a
464
+ * stale record against an unrelated process that later took the same PID.
465
+ * Returns undefined off Linux or when the process is gone.
466
+ */
467
+ async function readLinuxProcessStartTime(pid: number): Promise<string | undefined> {
468
+ if (process.platform !== "linux" || !Number.isSafeInteger(pid) || pid <= 0) return undefined;
469
+ try {
470
+ const stat = await Bun.file(`/proc/${pid}/stat`).text();
471
+ const commandEnd = stat.lastIndexOf(")");
472
+ if (commandEnd < 0) return undefined;
473
+ const fields = stat
474
+ .slice(commandEnd + 2)
475
+ .trim()
476
+ .split(/\s+/);
477
+ const startTime = fields[19];
478
+ return startTime && /^\d+$/.test(startTime) ? startTime : undefined;
479
+ } catch {
480
+ return undefined;
481
+ }
482
+ }
483
+
459
484
  interface GitResult {
460
485
  ok: boolean;
461
486
  stdout: string;
@@ -491,7 +516,7 @@ interface SkcWorkerIntegrationDedupeState {
491
516
 
492
517
  export interface SkcWorkerIntegrationAttemptRequestResult {
493
518
  requested: boolean;
494
- reason: "requested" | "not_worker" | "missing_worktree" | "no_changes" | "deduped" | "git_error";
519
+ reason: "requested" | "not_worker" | "missing_worktree" | "no_changes" | "deduped" | "git_error" | "cancelled";
495
520
  worker?: string;
496
521
  team_name?: string;
497
522
  fingerprint?: string;
@@ -499,6 +524,12 @@ export interface SkcWorkerIntegrationAttemptRequestResult {
499
524
  status?: SkcWorkerCheckpointClassification["kind"];
500
525
  }
501
526
 
527
+ /** Caller-supplied controls for a worker integration attempt. */
528
+ export interface SkcWorkerIntegrationAttemptOptions {
529
+ /** Abort the attempt between its blocking git probes. */
530
+ signal?: AbortSignal;
531
+ }
532
+
502
533
  function isSkcTeamTaskStatus(value: string): value is SkcTeamTaskStatus {
503
534
  return ["pending", "blocked", "in_progress", "completed", "failed"].includes(value);
504
535
  }
@@ -2973,7 +3004,13 @@ function workerIntegrationFingerprint(head: string | null, classification: SkcWo
2973
3004
  export async function requestSkcWorkerIntegrationAttempt(
2974
3005
  cwd = process.cwd(),
2975
3006
  env: NodeJS.ProcessEnv = process.env,
3007
+ options: SkcWorkerIntegrationAttemptOptions = {},
2976
3008
  ): Promise<SkcWorkerIntegrationAttemptRequestResult> {
3009
+ // The probes below shell out to git, which can block for a long time on a large
3010
+ // or network-backed worktree. The caller (session shutdown) needs to stop waiting,
3011
+ // so bail at each boundary instead of running to completion regardless.
3012
+ const cancelled = (): SkcWorkerIntegrationAttemptRequestResult => ({ requested: false, reason: "cancelled" });
3013
+ if (options.signal?.aborted) return cancelled();
2977
3014
  const teamName = env.SKC_TEAM_NAME?.trim();
2978
3015
  const worker = env.SKC_TEAM_WORKER_ID?.trim() || env.SKC_TEAM_INTERNAL_WORKER?.split("/").pop()?.trim();
2979
3016
  if (!teamName || !worker) return { requested: false, reason: "not_worker" };
@@ -2983,7 +3020,9 @@ export async function requestSkcWorkerIntegrationAttempt(
2983
3020
  const worktreePath = env.SKC_TEAM_WORKTREE_PATH?.trim() || configuredWorker?.worktree_path;
2984
3021
  if (!worktreePath || !(await pathExists(worktreePath)))
2985
3022
  return { requested: false, reason: "missing_worktree", worker, team_name: teamName };
3023
+ if (options.signal?.aborted) return cancelled();
2986
3024
  const classification = classifyWorkerCheckpointStatus(worktreePath);
3025
+ if (options.signal?.aborted) return cancelled();
2987
3026
  const head = resolveHead(worktreePath);
2988
3027
  if (classification.kind === "git_error") {
2989
3028
  return { requested: false, reason: "git_error", worker, team_name: teamName, head, status: classification.kind };
@@ -4346,6 +4385,7 @@ export async function executeSkcTeamApiOperation(
4346
4385
  last_turn_at: now(),
4347
4386
  turn_count: Number(input.turn_count ?? 0),
4348
4387
  alive: Boolean(input.alive ?? true),
4388
+ process_start_time: await readLinuxProcessStartTime(Number(input.pid ?? 0)),
4349
4389
  },
4350
4390
  cwd,
4351
4391
  env,
@@ -126,6 +126,38 @@ export interface SkcTeamApiClaimResult {
126
126
  claim_token?: string;
127
127
  reason?: string;
128
128
  }
129
+ export type SkcTeamWorkerClaimSelection =
130
+ | { kind: "none" }
131
+ | { kind: "exact"; task: SkcTeamTask; claim: SkcTeamTaskClaim }
132
+ | { kind: "ambiguous"; tasks: SkcTeamTask[] };
133
+
134
+ export function selectCurrentClaimedTaskForWorker(
135
+ tasks: readonly SkcTeamTask[],
136
+ workerId: string,
137
+ ): SkcTeamWorkerClaimSelection {
138
+ const claimed = tasks.filter(
139
+ task =>
140
+ task.status === "in_progress" &&
141
+ task.assignee === workerId &&
142
+ task.claim?.owner === workerId &&
143
+ task.owner === workerId,
144
+ );
145
+ if (claimed.length === 0) return { kind: "none" };
146
+ if (claimed.length === 1) {
147
+ const task = claimed[0]!;
148
+ return { kind: "exact", task, claim: task.claim! };
149
+ }
150
+ return { kind: "ambiguous", tasks: claimed };
151
+ }
152
+ export function findSkcTeamClaimedTaskForWorker(
153
+ tasks: readonly SkcTeamTask[],
154
+ workerId: string,
155
+ ): SkcTeamTask | undefined {
156
+ const active = selectCurrentClaimedTaskForWorker(tasks, workerId);
157
+ if (active.kind === "exact") return active.task;
158
+ if (active.kind === "ambiguous") return undefined;
159
+ return tasks.find(task => task.status === "blocked" && task.assignee === workerId && task.claim?.owner === workerId);
160
+ }
129
161
 
130
162
  type EventAppender = (event: {
131
163
  type: string;