@sayknow-cli/coding-agent 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2036) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +37 -0
  3. package/dist/types/async/index.d.ts +2 -0
  4. package/dist/types/async/job-manager.d.ts +326 -0
  5. package/dist/types/async/support.d.ts +2 -0
  6. package/dist/types/autoresearch/dashboard.d.ts +4 -0
  7. package/dist/types/autoresearch/git.d.ts +36 -0
  8. package/dist/types/autoresearch/helpers.d.ts +24 -0
  9. package/dist/types/autoresearch/index.d.ts +2 -0
  10. package/dist/types/autoresearch/state.d.ts +17 -0
  11. package/dist/types/autoresearch/storage.d.ts +142 -0
  12. package/dist/types/autoresearch/tools/init-experiment.d.ts +31 -0
  13. package/dist/types/autoresearch/tools/log-experiment.d.ts +23 -0
  14. package/dist/types/autoresearch/tools/run-experiment.d.ts +8 -0
  15. package/dist/types/autoresearch/tools/update-notes.d.ts +12 -0
  16. package/dist/types/autoresearch/types.d.ts +154 -0
  17. package/dist/types/capability/context-file.d.ts +17 -0
  18. package/dist/types/capability/extension-module.d.ts +15 -0
  19. package/dist/types/capability/extension.d.ts +28 -0
  20. package/dist/types/capability/fs.d.ts +20 -0
  21. package/dist/types/capability/hook.d.ts +19 -0
  22. package/dist/types/capability/index.d.ts +80 -0
  23. package/dist/types/capability/instruction.d.ts +17 -0
  24. package/dist/types/capability/mcp.d.ts +45 -0
  25. package/dist/types/capability/prompt.d.ts +15 -0
  26. package/dist/types/capability/rule.d.ts +61 -0
  27. package/dist/types/capability/settings.d.ts +15 -0
  28. package/dist/types/capability/skill.d.ts +36 -0
  29. package/dist/types/capability/slash-command.d.ts +17 -0
  30. package/dist/types/capability/ssh.d.ts +23 -0
  31. package/dist/types/capability/system-prompt.d.ts +15 -0
  32. package/dist/types/capability/tool.d.ts +19 -0
  33. package/dist/types/capability/types.d.ts +154 -0
  34. package/dist/types/cli/agents-cli.d.ts +12 -0
  35. package/dist/types/cli/args.d.ts +56 -0
  36. package/dist/types/cli/auth-broker-cli.d.ts +25 -0
  37. package/dist/types/cli/auth-gateway-cli.d.ts +18 -0
  38. package/dist/types/cli/classify-install-target.d.ts +18 -0
  39. package/dist/types/cli/commands/init-xdg.d.ts +1 -0
  40. package/dist/types/cli/config-cli.d.ts +22 -0
  41. package/dist/types/cli/fast-help.d.ts +1 -0
  42. package/dist/types/cli/file-processor.d.ts +11 -0
  43. package/dist/types/cli/grep-cli.d.ts +17 -0
  44. package/dist/types/cli/initial-message.d.ts +17 -0
  45. package/dist/types/cli/list-models.d.ts +36 -0
  46. package/dist/types/cli/plugin-cli.d.ts +32 -0
  47. package/dist/types/cli/read-cli.d.ts +4 -0
  48. package/dist/types/cli/session-picker.d.ts +3 -0
  49. package/dist/types/cli/setup-cli.d.ts +54 -0
  50. package/dist/types/cli/shell-cli.d.ts +8 -0
  51. package/dist/types/cli/skills-cli.d.ts +9 -0
  52. package/dist/types/cli/ssh-cli.d.ts +21 -0
  53. package/dist/types/cli/stats-cli.d.ts +17 -0
  54. package/dist/types/cli/update-cli.d.ts +41 -0
  55. package/dist/types/cli/web-search-cli.d.ts +32 -0
  56. package/dist/types/cli/worktree-cli.d.ts +26 -0
  57. package/dist/types/cli.d.ts +3 -0
  58. package/dist/types/commands/acp.d.ts +12 -0
  59. package/dist/types/commands/agents.d.ts +34 -0
  60. package/dist/types/commands/auth-broker.d.ts +54 -0
  61. package/dist/types/commands/auth-gateway.d.ts +32 -0
  62. package/dist/types/commands/codex-native-hook.d.ts +6 -0
  63. package/dist/types/commands/commit.d.ts +27 -0
  64. package/dist/types/commands/config.d.ts +30 -0
  65. package/dist/types/commands/contribution-prep.d.ts +18 -0
  66. package/dist/types/commands/coordinator.d.ts +19 -0
  67. package/dist/types/commands/deep-interview.d.ts +51 -0
  68. package/dist/types/commands/gc.d.ts +26 -0
  69. package/dist/types/commands/grep.d.ts +42 -0
  70. package/dist/types/commands/harness.d.ts +43 -0
  71. package/dist/types/commands/launch.d.ts +127 -0
  72. package/dist/types/commands/mcp-serve.d.ts +24 -0
  73. package/dist/types/commands/plugin.d.ts +52 -0
  74. package/dist/types/commands/ralplan.d.ts +7 -0
  75. package/dist/types/commands/read.d.ts +15 -0
  76. package/dist/types/commands/rlm.d.ts +10 -0
  77. package/dist/types/commands/session.d.ts +24 -0
  78. package/dist/types/commands/setup.d.ts +105 -0
  79. package/dist/types/commands/shell.d.ts +21 -0
  80. package/dist/types/commands/skills.d.ts +26 -0
  81. package/dist/types/commands/ssh.d.ts +48 -0
  82. package/dist/types/commands/state.d.ts +7 -0
  83. package/dist/types/commands/stats.d.ts +25 -0
  84. package/dist/types/commands/team.d.ts +24 -0
  85. package/dist/types/commands/ultragoal.d.ts +8 -0
  86. package/dist/types/commands/update.d.ts +20 -0
  87. package/dist/types/commands/web-search.d.ts +87 -0
  88. package/dist/types/commands/worktree.d.ts +34 -0
  89. package/dist/types/commit/agentic/agent.d.ts +31 -0
  90. package/dist/types/commit/agentic/fallback.d.ts +5 -0
  91. package/dist/types/commit/agentic/index.d.ts +2 -0
  92. package/dist/types/commit/agentic/state.d.ts +58 -0
  93. package/dist/types/commit/agentic/tools/analyze-file.d.ts +19 -0
  94. package/dist/types/commit/agentic/tools/git-file-diff.d.ts +10 -0
  95. package/dist/types/commit/agentic/tools/git-hunk.d.ts +9 -0
  96. package/dist/types/commit/agentic/tools/git-overview.d.ts +9 -0
  97. package/dist/types/commit/agentic/tools/index.d.ts +16 -0
  98. package/dist/types/commit/agentic/tools/propose-changelog.d.ts +28 -0
  99. package/dist/types/commit/agentic/tools/propose-commit.d.ts +36 -0
  100. package/dist/types/commit/agentic/tools/recent-commits.d.ts +7 -0
  101. package/dist/types/commit/agentic/tools/schemas.d.ts +27 -0
  102. package/dist/types/commit/agentic/tools/split-commit.d.ts +53 -0
  103. package/dist/types/commit/agentic/topo-sort.d.ts +4 -0
  104. package/dist/types/commit/agentic/trivial.d.ts +7 -0
  105. package/dist/types/commit/agentic/validation.d.ts +20 -0
  106. package/dist/types/commit/analysis/conventional.d.ts +22 -0
  107. package/dist/types/commit/analysis/index.d.ts +4 -0
  108. package/dist/types/commit/analysis/scope.d.ts +6 -0
  109. package/dist/types/commit/analysis/summary.d.ts +19 -0
  110. package/dist/types/commit/analysis/validation.d.ts +8 -0
  111. package/dist/types/commit/changelog/detect.d.ts +2 -0
  112. package/dist/types/commit/changelog/generate.d.ts +30 -0
  113. package/dist/types/commit/changelog/index.d.ts +30 -0
  114. package/dist/types/commit/changelog/parse.d.ts +2 -0
  115. package/dist/types/commit/cli.d.ts +3 -0
  116. package/dist/types/commit/git/diff.d.ts +5 -0
  117. package/dist/types/commit/index.d.ts +4 -0
  118. package/dist/types/commit/map-reduce/index.d.ts +28 -0
  119. package/dist/types/commit/map-reduce/map-phase.d.ts +17 -0
  120. package/dist/types/commit/map-reduce/reduce-phase.d.ts +13 -0
  121. package/dist/types/commit/map-reduce/utils.d.ts +2 -0
  122. package/dist/types/commit/message.d.ts +2 -0
  123. package/dist/types/commit/model-selection.d.ts +15 -0
  124. package/dist/types/commit/pipeline.d.ts +5 -0
  125. package/dist/types/commit/shared-llm.d.ts +54 -0
  126. package/dist/types/commit/types.d.ts +78 -0
  127. package/dist/types/commit/utils/exclusions.d.ts +4 -0
  128. package/dist/types/commit/utils.d.ts +20 -0
  129. package/dist/types/config/config-file.d.ts +58 -0
  130. package/dist/types/config/file-lock-gc.d.ts +5 -0
  131. package/dist/types/config/file-lock.d.ts +35 -0
  132. package/dist/types/config/keybindings.d.ts +349 -0
  133. package/dist/types/config/model-equivalence.d.ts +24 -0
  134. package/dist/types/config/model-profile-activation.d.ts +39 -0
  135. package/dist/types/config/model-profiles.d.ts +37 -0
  136. package/dist/types/config/model-registry.d.ts +457 -0
  137. package/dist/types/config/model-resolver.d.ts +217 -0
  138. package/dist/types/config/models-config-schema.d.ts +690 -0
  139. package/dist/types/config/prompt-templates.d.ts +32 -0
  140. package/dist/types/config/resolve-config-value.d.ts +17 -0
  141. package/dist/types/config/settings-schema.d.ts +3581 -0
  142. package/dist/types/config/settings.d.ts +134 -0
  143. package/dist/types/config/skill-settings-defaults.d.ts +14 -0
  144. package/dist/types/config.d.ts +66 -0
  145. package/dist/types/coordinator/contract.d.ts +4 -0
  146. package/dist/types/coordinator-mcp/policy.d.ts +24 -0
  147. package/dist/types/coordinator-mcp/safety.d.ts +26 -0
  148. package/dist/types/coordinator-mcp/server.d.ts +58 -0
  149. package/dist/types/cursor.d.ts +24 -0
  150. package/dist/types/dap/client.d.ts +39 -0
  151. package/dist/types/dap/config.d.ts +6 -0
  152. package/dist/types/dap/index.d.ts +4 -0
  153. package/dist/types/dap/session.d.ts +108 -0
  154. package/dist/types/dap/types.d.ts +524 -0
  155. package/dist/types/debug/crash-diagnostics.d.ts +45 -0
  156. package/dist/types/debug/index.d.ts +15 -0
  157. package/dist/types/debug/log-formatting.d.ts +4 -0
  158. package/dist/types/debug/log-viewer.d.ts +68 -0
  159. package/dist/types/debug/profiler.d.ts +24 -0
  160. package/dist/types/debug/raw-sse-buffer.d.ts +44 -0
  161. package/dist/types/debug/raw-sse.d.ts +16 -0
  162. package/dist/types/debug/report-bundle.d.ts +55 -0
  163. package/dist/types/debug/runtime-gauges.d.ts +6 -0
  164. package/dist/types/debug/system-info.d.ts +26 -0
  165. package/dist/types/deep-interview/render-middleware.d.ts +6 -0
  166. package/dist/types/defaults/skc/extensions/grok-build/index.d.ts +1 -0
  167. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/index.d.ts +1 -0
  168. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/models/catalog.d.ts +25 -0
  169. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/payload/sanitize.d.ts +27 -0
  170. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/provider/billing.d.ts +8 -0
  171. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/provider/register.d.ts +5 -0
  172. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/provider/stream.d.ts +10 -0
  173. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/provider/usage.d.ts +2 -0
  174. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/shared/base-url.d.ts +2 -0
  175. package/dist/types/defaults/skc/extensions/grok-cli-vendor/src/shared/errors.d.ts +38 -0
  176. package/dist/types/defaults/skc-defaults.d.ts +57 -0
  177. package/dist/types/defaults/skc-grok-cli.d.ts +5 -0
  178. package/dist/types/discovery/agents-md.d.ts +1 -0
  179. package/dist/types/discovery/agents.d.ts +12 -0
  180. package/dist/types/discovery/builtin.d.ts +1 -0
  181. package/dist/types/discovery/claude-plugins.d.ts +1 -0
  182. package/dist/types/discovery/claude.d.ts +1 -0
  183. package/dist/types/discovery/cline.d.ts +1 -0
  184. package/dist/types/discovery/codex.d.ts +1 -0
  185. package/dist/types/discovery/cursor.d.ts +16 -0
  186. package/dist/types/discovery/gemini.d.ts +1 -0
  187. package/dist/types/discovery/github.d.ts +1 -0
  188. package/dist/types/discovery/helpers.d.ts +271 -0
  189. package/dist/types/discovery/index.d.ts +48 -0
  190. package/dist/types/discovery/mcp-json.d.ts +1 -0
  191. package/dist/types/discovery/opencode.d.ts +1 -0
  192. package/dist/types/discovery/plugin-dir-roots.d.ts +15 -0
  193. package/dist/types/discovery/ssh.d.ts +1 -0
  194. package/dist/types/discovery/substitute-plugin-root.d.ts +5 -0
  195. package/dist/types/discovery/vscode.d.ts +1 -0
  196. package/dist/types/discovery/windsurf.d.ts +13 -0
  197. package/dist/types/edit/apply-patch/index.d.ts +35 -0
  198. package/dist/types/edit/apply-patch/parser.d.ts +34 -0
  199. package/dist/types/edit/diff.d.ts +75 -0
  200. package/dist/types/edit/file-read-cache.d.ts +25 -0
  201. package/dist/types/edit/index.d.ts +58 -0
  202. package/dist/types/edit/modes/apply-patch.d.ts +24 -0
  203. package/dist/types/edit/modes/patch.d.ts +99 -0
  204. package/dist/types/edit/modes/replace.d.ts +149 -0
  205. package/dist/types/edit/normalize.d.ts +43 -0
  206. package/dist/types/edit/notebook.d.ts +26 -0
  207. package/dist/types/edit/read-file.d.ts +8 -0
  208. package/dist/types/edit/renderer.d.ts +110 -0
  209. package/dist/types/edit/streaming.d.ts +66 -0
  210. package/dist/types/eval/backend.d.ts +40 -0
  211. package/dist/types/eval/index.d.ts +4 -0
  212. package/dist/types/eval/js/context-manager.d.ts +27 -0
  213. package/dist/types/eval/js/executor.d.ts +29 -0
  214. package/dist/types/eval/js/index.d.ts +10 -0
  215. package/dist/types/eval/js/shared/helpers.d.ts +38 -0
  216. package/dist/types/eval/js/shared/indirect-eval.d.ts +14 -0
  217. package/dist/types/eval/js/shared/prelude.d.ts +1 -0
  218. package/dist/types/eval/js/shared/rewrite-imports.d.ts +6 -0
  219. package/dist/types/eval/js/shared/runtime.d.ts +47 -0
  220. package/dist/types/eval/js/shared/types.d.ts +24 -0
  221. package/dist/types/eval/js/tool-bridge.d.ts +18 -0
  222. package/dist/types/eval/js/worker-core.d.ts +5 -0
  223. package/dist/types/eval/js/worker-entry.d.ts +1 -0
  224. package/dist/types/eval/js/worker-protocol.d.ts +77 -0
  225. package/dist/types/eval/py/display.d.ts +25 -0
  226. package/dist/types/eval/py/executor.d.ts +88 -0
  227. package/dist/types/eval/py/index.d.ts +10 -0
  228. package/dist/types/eval/py/kernel.d.ts +65 -0
  229. package/dist/types/eval/py/prelude.d.ts +1 -0
  230. package/dist/types/eval/py/runtime.d.ts +29 -0
  231. package/dist/types/eval/py/tool-bridge.d.ts +20 -0
  232. package/dist/types/eval/types.d.ts +52 -0
  233. package/dist/types/exa/factory.d.ts +13 -0
  234. package/dist/types/exa/index.d.ts +20 -0
  235. package/dist/types/exa/mcp-client.d.ts +45 -0
  236. package/dist/types/exa/render.d.ts +19 -0
  237. package/dist/types/exa/researcher.d.ts +9 -0
  238. package/dist/types/exa/search.d.ts +9 -0
  239. package/dist/types/exa/types.d.ts +155 -0
  240. package/dist/types/exa/websets.d.ts +9 -0
  241. package/dist/types/exec/bash-executor.d.ts +64 -0
  242. package/dist/types/exec/exec.d.ts +25 -0
  243. package/dist/types/exec/idle-timeout-watchdog.d.ts +18 -0
  244. package/dist/types/exec/non-interactive-env.d.ts +1 -0
  245. package/dist/types/export/custom-share.d.ts +20 -0
  246. package/dist/types/export/html/index.d.ts +10 -0
  247. package/dist/types/export/html/template.generated.d.ts +1 -0
  248. package/dist/types/export/html/template.macro.d.ts +5 -0
  249. package/dist/types/export/ttsr.d.ts +44 -0
  250. package/dist/types/extensibility/custom-commands/bundled/ci-green/index.d.ts +9 -0
  251. package/dist/types/extensibility/custom-commands/bundled/review/index.d.ts +10 -0
  252. package/dist/types/extensibility/custom-commands/index.d.ts +2 -0
  253. package/dist/types/extensibility/custom-commands/loader.d.ts +29 -0
  254. package/dist/types/extensibility/custom-commands/types.d.ts +106 -0
  255. package/dist/types/extensibility/custom-tools/index.d.ts +6 -0
  256. package/dist/types/extensibility/custom-tools/loader.d.ts +69 -0
  257. package/dist/types/extensibility/custom-tools/types.d.ts +229 -0
  258. package/dist/types/extensibility/custom-tools/wrapper.d.ts +24 -0
  259. package/dist/types/extensibility/extensions/compact-handler.d.ts +26 -0
  260. package/dist/types/extensibility/extensions/get-commands-handler.d.ts +29 -0
  261. package/dist/types/extensibility/extensions/index.d.ts +9 -0
  262. package/dist/types/extensibility/extensions/loader.d.ts +43 -0
  263. package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +35 -0
  264. package/dist/types/extensibility/extensions/runner.d.ts +134 -0
  265. package/dist/types/extensibility/extensions/types.d.ts +891 -0
  266. package/dist/types/extensibility/extensions/wrapper.d.ts +55 -0
  267. package/dist/types/extensibility/hooks/index.d.ts +5 -0
  268. package/dist/types/extensibility/hooks/loader.d.ts +89 -0
  269. package/dist/types/extensibility/hooks/runner.d.ts +126 -0
  270. package/dist/types/extensibility/hooks/tool-wrapper.d.ts +25 -0
  271. package/dist/types/extensibility/hooks/types.d.ts +431 -0
  272. package/dist/types/extensibility/plugins/doctor.d.ts +3 -0
  273. package/dist/types/extensibility/plugins/git-url.d.ts +34 -0
  274. package/dist/types/extensibility/plugins/index.d.ts +7 -0
  275. package/dist/types/extensibility/plugins/installer.d.ts +5 -0
  276. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
  277. package/dist/types/extensibility/plugins/loader.d.ts +31 -0
  278. package/dist/types/extensibility/plugins/manager.d.ts +65 -0
  279. package/dist/types/extensibility/plugins/marketplace/cache.d.ts +41 -0
  280. package/dist/types/extensibility/plugins/marketplace/fetcher.d.ts +48 -0
  281. package/dist/types/extensibility/plugins/marketplace/index.d.ts +6 -0
  282. package/dist/types/extensibility/plugins/marketplace/manager.d.ts +57 -0
  283. package/dist/types/extensibility/plugins/marketplace/registry.d.ts +34 -0
  284. package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +28 -0
  285. package/dist/types/extensibility/plugins/marketplace/types.d.ts +130 -0
  286. package/dist/types/extensibility/plugins/parser.d.ts +52 -0
  287. package/dist/types/extensibility/plugins/types.d.ts +149 -0
  288. package/dist/types/extensibility/shared-events.d.ts +280 -0
  289. package/dist/types/extensibility/skc-plugins/activation.d.ts +14 -0
  290. package/dist/types/extensibility/skc-plugins/index.d.ts +9 -0
  291. package/dist/types/extensibility/skc-plugins/injection.d.ts +31 -0
  292. package/dist/types/extensibility/skc-plugins/loader.d.ts +3 -0
  293. package/dist/types/extensibility/skc-plugins/paths.d.ts +8 -0
  294. package/dist/types/extensibility/skc-plugins/schema.d.ts +3 -0
  295. package/dist/types/extensibility/skc-plugins/state.d.ts +9 -0
  296. package/dist/types/extensibility/skc-plugins/tools.d.ts +8 -0
  297. package/dist/types/extensibility/skc-plugins/types.d.ts +64 -0
  298. package/dist/types/extensibility/skc-plugins/validation.d.ts +4 -0
  299. package/dist/types/extensibility/skills.d.ts +82 -0
  300. package/dist/types/extensibility/slash-commands.d.ts +48 -0
  301. package/dist/types/extensibility/tool-proxy.d.ts +4 -0
  302. package/dist/types/extensibility/typebox.d.ts +155 -0
  303. package/dist/types/extensibility/utils.d.ts +12 -0
  304. package/dist/types/goals/index.d.ts +3 -0
  305. package/dist/types/goals/runtime.d.ts +62 -0
  306. package/dist/types/goals/state.d.ts +32 -0
  307. package/dist/types/goals/tools/goal-tool.d.ts +62 -0
  308. package/dist/types/harness-control-plane/classifier.d.ts +13 -0
  309. package/dist/types/harness-control-plane/control-endpoint.d.ts +31 -0
  310. package/dist/types/harness-control-plane/finalize.d.ts +60 -0
  311. package/dist/types/harness-control-plane/gc-adapter.d.ts +3 -0
  312. package/dist/types/harness-control-plane/operate.d.ts +35 -0
  313. package/dist/types/harness-control-plane/owner.d.ts +53 -0
  314. package/dist/types/harness-control-plane/phase-rollup.d.ts +23 -0
  315. package/dist/types/harness-control-plane/preserve.d.ts +19 -0
  316. package/dist/types/harness-control-plane/receipt-ingest.d.ts +19 -0
  317. package/dist/types/harness-control-plane/receipt-spool.d.ts +19 -0
  318. package/dist/types/harness-control-plane/receipts.d.ts +149 -0
  319. package/dist/types/harness-control-plane/rpc-adapter.d.ts +69 -0
  320. package/dist/types/harness-control-plane/seams.d.ts +21 -0
  321. package/dist/types/harness-control-plane/session-lease.d.ts +65 -0
  322. package/dist/types/harness-control-plane/state-machine.d.ts +24 -0
  323. package/dist/types/harness-control-plane/storage.d.ts +80 -0
  324. package/dist/types/harness-control-plane/types.d.ts +187 -0
  325. package/dist/types/hashline/anchors.d.ts +20 -0
  326. package/dist/types/hashline/apply.d.ts +14 -0
  327. package/dist/types/hashline/constants.d.ts +19 -0
  328. package/dist/types/hashline/diff-preview.d.ts +2 -0
  329. package/dist/types/hashline/diff.d.ts +17 -0
  330. package/dist/types/hashline/execute.d.ts +4 -0
  331. package/dist/types/hashline/hash.d.ts +123 -0
  332. package/dist/types/hashline/index.d.ts +13 -0
  333. package/dist/types/hashline/input.d.ts +11 -0
  334. package/dist/types/hashline/parser.d.ts +7 -0
  335. package/dist/types/hashline/prefixes.d.ts +7 -0
  336. package/dist/types/hashline/recovery.d.ts +27 -0
  337. package/dist/types/hashline/stream.d.ts +2 -0
  338. package/dist/types/hashline/types.d.ts +77 -0
  339. package/dist/types/hindsight/backend.d.ts +13 -0
  340. package/dist/types/hindsight/bank.d.ts +54 -0
  341. package/dist/types/hindsight/client.d.ts +224 -0
  342. package/dist/types/hindsight/config.d.ts +51 -0
  343. package/dist/types/hindsight/content.d.ts +70 -0
  344. package/dist/types/hindsight/index.d.ts +8 -0
  345. package/dist/types/hindsight/mental-models.d.ts +125 -0
  346. package/dist/types/hindsight/state.d.ts +99 -0
  347. package/dist/types/hindsight/transcript.d.ts +28 -0
  348. package/dist/types/hooks/codex-native-hooks-config.d.ts +29 -0
  349. package/dist/types/hooks/native-skill-hook.d.ts +16 -0
  350. package/dist/types/hooks/skill-keywords.d.ts +18 -0
  351. package/dist/types/hooks/skill-state.d.ts +85 -0
  352. package/dist/types/i18n/index.d.ts +38 -0
  353. package/dist/types/i18n/messages/de.d.ts +2 -0
  354. package/dist/types/i18n/messages/de.messages.d.ts +1 -0
  355. package/dist/types/i18n/messages/de.settings.d.ts +1 -0
  356. package/dist/types/i18n/messages/en.d.ts +66 -0
  357. package/dist/types/i18n/messages/es.d.ts +2 -0
  358. package/dist/types/i18n/messages/es.messages.d.ts +1 -0
  359. package/dist/types/i18n/messages/es.settings.d.ts +1 -0
  360. package/dist/types/i18n/messages/fr.d.ts +2 -0
  361. package/dist/types/i18n/messages/fr.messages.d.ts +1 -0
  362. package/dist/types/i18n/messages/fr.settings.d.ts +1 -0
  363. package/dist/types/i18n/messages/ja.d.ts +2 -0
  364. package/dist/types/i18n/messages/ja.messages.d.ts +1 -0
  365. package/dist/types/i18n/messages/ja.settings.d.ts +1 -0
  366. package/dist/types/i18n/messages/ko.d.ts +2 -0
  367. package/dist/types/i18n/messages/ko.messages.d.ts +1 -0
  368. package/dist/types/i18n/messages/ko.settings.d.ts +1 -0
  369. package/dist/types/i18n/messages/zh.d.ts +2 -0
  370. package/dist/types/i18n/messages/zh.messages.d.ts +1 -0
  371. package/dist/types/i18n/messages/zh.settings.d.ts +1 -0
  372. package/dist/types/index.d.ts +33 -0
  373. package/dist/types/internal-urls/agent-protocol.d.ts +12 -0
  374. package/dist/types/internal-urls/artifact-protocol.d.ts +6 -0
  375. package/dist/types/internal-urls/docs-index.generated.d.ts +2 -0
  376. package/dist/types/internal-urls/index.d.ts +20 -0
  377. package/dist/types/internal-urls/issue-pr-protocol.d.ts +17 -0
  378. package/dist/types/internal-urls/json-query.d.ts +30 -0
  379. package/dist/types/internal-urls/local-protocol.d.ts +39 -0
  380. package/dist/types/internal-urls/mcp-protocol.d.ts +12 -0
  381. package/dist/types/internal-urls/memory-protocol.d.ts +23 -0
  382. package/dist/types/internal-urls/parse.d.ts +19 -0
  383. package/dist/types/internal-urls/registry-helpers.d.ts +11 -0
  384. package/dist/types/internal-urls/router.d.ts +14 -0
  385. package/dist/types/internal-urls/rule-protocol.d.ts +6 -0
  386. package/dist/types/internal-urls/skc-protocol.d.ts +12 -0
  387. package/dist/types/internal-urls/skill-protocol.d.ts +13 -0
  388. package/dist/types/internal-urls/types.d.ts +109 -0
  389. package/dist/types/lsp/client.d.ts +66 -0
  390. package/dist/types/lsp/clients/biome-client.d.ts +16 -0
  391. package/dist/types/lsp/clients/index.d.ts +19 -0
  392. package/dist/types/lsp/clients/lsp-linter-client.d.ts +16 -0
  393. package/dist/types/lsp/clients/swiftlint-client.d.ts +20 -0
  394. package/dist/types/lsp/config.d.ts +65 -0
  395. package/dist/types/lsp/edits.d.ts +23 -0
  396. package/dist/types/lsp/index.d.ts +130 -0
  397. package/dist/types/lsp/lspmux.d.ts +58 -0
  398. package/dist/types/lsp/render.d.ts +32 -0
  399. package/dist/types/lsp/startup-events.d.ts +11 -0
  400. package/dist/types/lsp/types.d.ts +304 -0
  401. package/dist/types/lsp/utils.d.ts +108 -0
  402. package/dist/types/main.d.ts +70 -0
  403. package/dist/types/memories/index.d.ts +28 -0
  404. package/dist/types/memories/storage.d.ts +110 -0
  405. package/dist/types/memory-backend/index.d.ts +4 -0
  406. package/dist/types/memory-backend/local-backend.d.ts +9 -0
  407. package/dist/types/memory-backend/off-backend.d.ts +7 -0
  408. package/dist/types/memory-backend/resolve.d.ts +15 -0
  409. package/dist/types/memory-backend/types.d.ts +61 -0
  410. package/dist/types/modes/acp/acp-agent.d.ts +61 -0
  411. package/dist/types/modes/acp/acp-client-bridge.d.ts +9 -0
  412. package/dist/types/modes/acp/acp-event-mapper.d.ts +34 -0
  413. package/dist/types/modes/acp/acp-mode.d.ts +5 -0
  414. package/dist/types/modes/acp/index.d.ts +2 -0
  415. package/dist/types/modes/acp/terminal-auth.d.ts +6 -0
  416. package/dist/types/modes/bridge/auth.d.ts +12 -0
  417. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +9 -0
  418. package/dist/types/modes/bridge/bridge-mode.d.ts +47 -0
  419. package/dist/types/modes/bridge/bridge-ui-context.d.ts +88 -0
  420. package/dist/types/modes/bridge/event-stream.d.ts +8 -0
  421. package/dist/types/modes/components/agent-dashboard.d.ts +21 -0
  422. package/dist/types/modes/components/assistant-message.d.ts +16 -0
  423. package/dist/types/modes/components/bash-execution.d.ts +29 -0
  424. package/dist/types/modes/components/bordered-loader.d.ts +11 -0
  425. package/dist/types/modes/components/branch-summary-message.d.ts +13 -0
  426. package/dist/types/modes/components/btw-panel.d.ts +16 -0
  427. package/dist/types/modes/components/compaction-summary-message.d.ts +13 -0
  428. package/dist/types/modes/components/countdown-timer.d.ts +14 -0
  429. package/dist/types/modes/components/custom-editor.d.ts +62 -0
  430. package/dist/types/modes/components/custom-message.d.ts +15 -0
  431. package/dist/types/modes/components/custom-model-preset-wizard.d.ts +12 -0
  432. package/dist/types/modes/components/custom-provider-wizard.d.ts +10 -0
  433. package/dist/types/modes/components/diff.d.ts +11 -0
  434. package/dist/types/modes/components/dynamic-border.d.ts +14 -0
  435. package/dist/types/modes/components/eval-execution.d.ts +23 -0
  436. package/dist/types/modes/components/execution-shared.d.ts +46 -0
  437. package/dist/types/modes/components/extensions/extension-dashboard.d.ts +26 -0
  438. package/dist/types/modes/components/extensions/extension-list.d.ts +39 -0
  439. package/dist/types/modes/components/extensions/index.d.ts +8 -0
  440. package/dist/types/modes/components/extensions/inspector-panel.d.ts +8 -0
  441. package/dist/types/modes/components/extensions/state-manager.d.ts +50 -0
  442. package/dist/types/modes/components/extensions/types.d.ts +151 -0
  443. package/dist/types/modes/components/footer.d.ts +30 -0
  444. package/dist/types/modes/components/history-search.d.ts +7 -0
  445. package/dist/types/modes/components/hook-editor.d.ts +18 -0
  446. package/dist/types/modes/components/hook-input.d.ts +15 -0
  447. package/dist/types/modes/components/hook-message.d.ts +15 -0
  448. package/dist/types/modes/components/hook-selector.d.ts +48 -0
  449. package/dist/types/modes/components/index.d.ts +35 -0
  450. package/dist/types/modes/components/jobs-overlay-model.d.ts +31 -0
  451. package/dist/types/modes/components/jobs-overlay.d.ts +30 -0
  452. package/dist/types/modes/components/keybinding-hints.d.ts +40 -0
  453. package/dist/types/modes/components/login-dialog.d.ts +32 -0
  454. package/dist/types/modes/components/message-frame.d.ts +42 -0
  455. package/dist/types/modes/components/model-selector.d.ts +46 -0
  456. package/dist/types/modes/components/oauth-selector.d.ts +15 -0
  457. package/dist/types/modes/components/plugin-selector.d.ts +26 -0
  458. package/dist/types/modes/components/plugin-settings.d.ts +66 -0
  459. package/dist/types/modes/components/provider-onboarding-selector.d.ts +7 -0
  460. package/dist/types/modes/components/queue-mode-selector.d.ts +9 -0
  461. package/dist/types/modes/components/read-tool-group.d.ts +30 -0
  462. package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +26 -0
  463. package/dist/types/modes/components/session-observer-overlay.d.ts +11 -0
  464. package/dist/types/modes/components/session-selector.d.ts +30 -0
  465. package/dist/types/modes/components/settings-defs.d.ts +50 -0
  466. package/dist/types/modes/components/settings-selector.d.ts +56 -0
  467. package/dist/types/modes/components/show-images-selector.d.ts +9 -0
  468. package/dist/types/modes/components/skill-hud/render.d.ts +2 -0
  469. package/dist/types/modes/components/skill-message.d.ts +9 -0
  470. package/dist/types/modes/components/status-line/context-thresholds.d.ts +4 -0
  471. package/dist/types/modes/components/status-line/git-utils.d.ts +22 -0
  472. package/dist/types/modes/components/status-line/index.d.ts +4 -0
  473. package/dist/types/modes/components/status-line/presets.d.ts +3 -0
  474. package/dist/types/modes/components/status-line/segments.d.ts +5 -0
  475. package/dist/types/modes/components/status-line/separators.d.ts +3 -0
  476. package/dist/types/modes/components/status-line/token-rate.d.ts +10 -0
  477. package/dist/types/modes/components/status-line/types.d.ts +79 -0
  478. package/dist/types/modes/components/status-line.d.ts +82 -0
  479. package/dist/types/modes/components/theme-selector.d.ts +10 -0
  480. package/dist/types/modes/components/thinking-selector.d.ts +10 -0
  481. package/dist/types/modes/components/todo-reminder.d.ts +13 -0
  482. package/dist/types/modes/components/tool-execution.d.ts +54 -0
  483. package/dist/types/modes/components/tree-selector.d.ts +31 -0
  484. package/dist/types/modes/components/ttsr-notification.d.ts +13 -0
  485. package/dist/types/modes/components/user-message-selector.d.ts +28 -0
  486. package/dist/types/modes/components/user-message.d.ts +7 -0
  487. package/dist/types/modes/components/visual-truncate.d.ts +19 -0
  488. package/dist/types/modes/components/welcome.d.ts +35 -0
  489. package/dist/types/modes/controllers/btw-controller.d.ts +10 -0
  490. package/dist/types/modes/controllers/command-controller-shared.d.ts +47 -0
  491. package/dist/types/modes/controllers/command-controller.d.ts +38 -0
  492. package/dist/types/modes/controllers/event-controller.d.ts +12 -0
  493. package/dist/types/modes/controllers/extension-ui-controller.d.ts +80 -0
  494. package/dist/types/modes/controllers/input-controller.d.ts +39 -0
  495. package/dist/types/modes/controllers/runtime-mcp-command-controller.d.ts +10 -0
  496. package/dist/types/modes/controllers/selector-controller.d.ts +57 -0
  497. package/dist/types/modes/controllers/ssh-command-controller.d.ts +10 -0
  498. package/dist/types/modes/controllers/todo-command-controller.d.ts +7 -0
  499. package/dist/types/modes/emoji-autocomplete.d.ts +16 -0
  500. package/dist/types/modes/index.d.ts +10 -0
  501. package/dist/types/modes/interactive-mode.d.ts +266 -0
  502. package/dist/types/modes/jobs-observer.d.ts +57 -0
  503. package/dist/types/modes/oauth-manual-input.d.ts +8 -0
  504. package/dist/types/modes/print-mode.d.ts +33 -0
  505. package/dist/types/modes/prompt-action-autocomplete.d.ts +46 -0
  506. package/dist/types/modes/rpc/host-tools.d.ts +1 -0
  507. package/dist/types/modes/rpc/host-uris.d.ts +1 -0
  508. package/dist/types/modes/rpc/rpc-client.d.ts +288 -0
  509. package/dist/types/modes/rpc/rpc-mode.d.ts +87 -0
  510. package/dist/types/modes/rpc/rpc-socket-security.d.ts +7 -0
  511. package/dist/types/modes/rpc/rpc-types.d.ts +779 -0
  512. package/dist/types/modes/runtime-init.d.ts +21 -0
  513. package/dist/types/modes/session-observer-registry.d.ts +26 -0
  514. package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +57 -0
  515. package/dist/types/modes/shared/agent-wire/command-contract.d.ts +18 -0
  516. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +37 -0
  517. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +2 -0
  518. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +60 -0
  519. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +84 -0
  520. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +38 -0
  521. package/dist/types/modes/shared/agent-wire/event-observation.d.ts +37 -0
  522. package/dist/types/modes/shared/agent-wire/handshake.d.ts +56 -0
  523. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +16 -0
  524. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +17 -0
  525. package/dist/types/modes/shared/agent-wire/protocol.d.ts +25 -0
  526. package/dist/types/modes/shared/agent-wire/responses.d.ts +4 -0
  527. package/dist/types/modes/shared/agent-wire/scopes.d.ts +18 -0
  528. package/dist/types/modes/shared/agent-wire/session-registry.d.ts +25 -0
  529. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +42 -0
  530. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +27 -0
  531. package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +29 -0
  532. package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +68 -0
  533. package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +161 -0
  534. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +72 -0
  535. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +114 -0
  536. package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +39 -0
  537. package/dist/types/modes/shared.d.ts +15 -0
  538. package/dist/types/modes/theme/defaults/index.d.ts +553 -0
  539. package/dist/types/modes/theme/mermaid-cache.d.ts +9 -0
  540. package/dist/types/modes/theme/shimmer.d.ts +38 -0
  541. package/dist/types/modes/theme/theme.d.ts +275 -0
  542. package/dist/types/modes/types.d.ts +278 -0
  543. package/dist/types/modes/utils/abort-message.d.ts +4 -0
  544. package/dist/types/modes/utils/context-usage.d.ts +51 -0
  545. package/dist/types/modes/utils/hotkeys-markdown.d.ts +5 -0
  546. package/dist/types/modes/utils/keybinding-matchers.d.ts +10 -0
  547. package/dist/types/modes/utils/tools-markdown.d.ts +5 -0
  548. package/dist/types/modes/utils/ui-helpers.d.ts +53 -0
  549. package/dist/types/plan-mode/approved-plan.d.ts +49 -0
  550. package/dist/types/plan-mode/state.d.ts +6 -0
  551. package/dist/types/registry/agent-registry.d.ts +62 -0
  552. package/dist/types/reminders/star-reminder.d.ts +115 -0
  553. package/dist/types/rlm/artifacts.d.ts +9 -0
  554. package/dist/types/rlm/complete-research-tool.d.ts +35 -0
  555. package/dist/types/rlm/data-context.d.ts +6 -0
  556. package/dist/types/rlm/index.d.ts +35 -0
  557. package/dist/types/rlm/notebook.d.ts +12 -0
  558. package/dist/types/rlm/preset.d.ts +23 -0
  559. package/dist/types/rlm/python-tool.d.ts +16 -0
  560. package/dist/types/rlm/report.d.ts +14 -0
  561. package/dist/types/rlm/types.d.ts +37 -0
  562. package/dist/types/runtime/process-lifecycle.d.ts +108 -0
  563. package/dist/types/runtime-mcp/client.d.ts +74 -0
  564. package/dist/types/runtime-mcp/config-writer.d.ts +53 -0
  565. package/dist/types/runtime-mcp/config.d.ts +75 -0
  566. package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +7 -0
  567. package/dist/types/runtime-mcp/index.d.ts +18 -0
  568. package/dist/types/runtime-mcp/json-rpc.d.ts +22 -0
  569. package/dist/types/runtime-mcp/loader.d.ts +43 -0
  570. package/dist/types/runtime-mcp/manager.d.ts +193 -0
  571. package/dist/types/runtime-mcp/oauth-discovery.d.ts +40 -0
  572. package/dist/types/runtime-mcp/oauth-flow.d.ts +59 -0
  573. package/dist/types/runtime-mcp/render.d.ts +25 -0
  574. package/dist/types/runtime-mcp/smithery-auth.d.ts +16 -0
  575. package/dist/types/runtime-mcp/smithery-connect.d.ts +38 -0
  576. package/dist/types/runtime-mcp/smithery-registry.d.ts +51 -0
  577. package/dist/types/runtime-mcp/tool-bridge.d.ts +86 -0
  578. package/dist/types/runtime-mcp/tool-cache.d.ts +8 -0
  579. package/dist/types/runtime-mcp/transports/http.d.ts +36 -0
  580. package/dist/types/runtime-mcp/transports/index.d.ts +5 -0
  581. package/dist/types/runtime-mcp/transports/stdio.d.ts +29 -0
  582. package/dist/types/runtime-mcp/types.d.ts +335 -0
  583. package/dist/types/sdk.d.ts +243 -0
  584. package/dist/types/secrets/index.d.ts +9 -0
  585. package/dist/types/secrets/obfuscator.d.ts +23 -0
  586. package/dist/types/secrets/regex.d.ts +2 -0
  587. package/dist/types/session/agent-session.d.ts +1078 -0
  588. package/dist/types/session/agent-storage.d.ts +100 -0
  589. package/dist/types/session/artifacts.d.ts +64 -0
  590. package/dist/types/session/auth-broker-config.d.ts +13 -0
  591. package/dist/types/session/auth-storage.d.ts +6 -0
  592. package/dist/types/session/blob-store.d.ts +135 -0
  593. package/dist/types/session/client-bridge.d.ts +88 -0
  594. package/dist/types/session/contribution-prep.d.ts +47 -0
  595. package/dist/types/session/history-storage.d.ts +16 -0
  596. package/dist/types/session/messages.d.ts +165 -0
  597. package/dist/types/session/session-dump-format.d.ts +22 -0
  598. package/dist/types/session/session-manager.d.ts +587 -0
  599. package/dist/types/session/session-storage.d.ts +88 -0
  600. package/dist/types/session/streaming-output.d.ts +209 -0
  601. package/dist/types/session/tool-choice-queue.d.ts +84 -0
  602. package/dist/types/session/yield-queue.d.ts +24 -0
  603. package/dist/types/setup/credential-import.d.ts +79 -0
  604. package/dist/types/setup/hermes-setup.d.ts +78 -0
  605. package/dist/types/setup/model-onboarding-guidance.d.ts +9 -0
  606. package/dist/types/setup/provider-onboarding.d.ts +52 -0
  607. package/dist/types/skc-runtime/cli-write-receipt.d.ts +24 -0
  608. package/dist/types/skc-runtime/deep-interview-recorder.d.ts +103 -0
  609. package/dist/types/skc-runtime/deep-interview-runtime.d.ts +36 -0
  610. package/dist/types/skc-runtime/deep-interview-state.d.ts +112 -0
  611. package/dist/types/skc-runtime/gc-render.d.ts +6 -0
  612. package/dist/types/skc-runtime/gc-runtime.d.ts +134 -0
  613. package/dist/types/skc-runtime/goal-mode-request.d.ts +53 -0
  614. package/dist/types/skc-runtime/launch-tmux.d.ts +76 -0
  615. package/dist/types/skc-runtime/launch-worktree.d.ts +46 -0
  616. package/dist/types/skc-runtime/ledger-event-renderer.d.ts +68 -0
  617. package/dist/types/skc-runtime/ralplan-runtime.d.ts +25 -0
  618. package/dist/types/skc-runtime/restricted-role-agent-bash.d.ts +2 -0
  619. package/dist/types/skc-runtime/session-state-sidecar.d.ts +27 -0
  620. package/dist/types/skc-runtime/state-graph.d.ts +4 -0
  621. package/dist/types/skc-runtime/state-migrations.d.ts +33 -0
  622. package/dist/types/skc-runtime/state-renderer.d.ts +65 -0
  623. package/dist/types/skc-runtime/state-runtime.d.ts +37 -0
  624. package/dist/types/skc-runtime/state-schema.d.ts +317 -0
  625. package/dist/types/skc-runtime/state-validation.d.ts +6 -0
  626. package/dist/types/skc-runtime/state-writer.d.ts +209 -0
  627. package/dist/types/skc-runtime/team-gc.d.ts +7 -0
  628. package/dist/types/skc-runtime/team-runtime.d.ts +353 -0
  629. package/dist/types/skc-runtime/tmux-common.d.ts +61 -0
  630. package/dist/types/skc-runtime/tmux-gc.d.ts +7 -0
  631. package/dist/types/skc-runtime/tmux-sessions.d.ts +40 -0
  632. package/dist/types/skc-runtime/ultragoal-guard.d.ts +36 -0
  633. package/dist/types/skc-runtime/ultragoal-runtime.d.ts +210 -0
  634. package/dist/types/skc-runtime/workflow-command-ref.d.ts +43 -0
  635. package/dist/types/skc-runtime/workflow-manifest.d.ts +54 -0
  636. package/dist/types/skill-state/active-state.d.ts +114 -0
  637. package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +33 -0
  638. package/dist/types/skill-state/initial-phase.d.ts +12 -0
  639. package/dist/types/skill-state/workflow-hud.d.ts +81 -0
  640. package/dist/types/skill-state/workflow-state-contract.d.ts +57 -0
  641. package/dist/types/skill-state/workflow-state-version.d.ts +3 -0
  642. package/dist/types/slash-commands/acp-builtins.d.ts +18 -0
  643. package/dist/types/slash-commands/builtin-registry.d.ts +24 -0
  644. package/dist/types/slash-commands/helpers/context-report.d.ts +7 -0
  645. package/dist/types/slash-commands/helpers/fast-status-report.d.ts +76 -0
  646. package/dist/types/slash-commands/helpers/format.d.ts +10 -0
  647. package/dist/types/slash-commands/helpers/mcp.d.ts +3 -0
  648. package/dist/types/slash-commands/helpers/parse.d.ts +33 -0
  649. package/dist/types/slash-commands/helpers/ssh.d.ts +3 -0
  650. package/dist/types/slash-commands/helpers/todo.d.ts +3 -0
  651. package/dist/types/slash-commands/helpers/usage-report.d.ts +7 -0
  652. package/dist/types/slash-commands/types.d.ts +118 -0
  653. package/dist/types/ssh/config-writer.d.ts +49 -0
  654. package/dist/types/ssh/connection-manager.d.ts +33 -0
  655. package/dist/types/ssh/ssh-executor.d.ts +37 -0
  656. package/dist/types/ssh/sshfs-mount.d.ts +6 -0
  657. package/dist/types/ssh/utils.d.ts +2 -0
  658. package/dist/types/stt/downloader.d.ts +9 -0
  659. package/dist/types/stt/index.d.ts +3 -0
  660. package/dist/types/stt/recorder.d.ts +13 -0
  661. package/dist/types/stt/setup.d.ts +18 -0
  662. package/dist/types/stt/stt-controller.d.ts +16 -0
  663. package/dist/types/stt/transcriber.d.ts +16 -0
  664. package/dist/types/system-prompt.d.ts +93 -0
  665. package/dist/types/task/agents.d.ts +28 -0
  666. package/dist/types/task/commands.d.ts +35 -0
  667. package/dist/types/task/discovery.d.ts +19 -0
  668. package/dist/types/task/executor.d.ts +113 -0
  669. package/dist/types/task/fork-context-advisory.d.ts +13 -0
  670. package/dist/types/task/id.d.ts +7 -0
  671. package/dist/types/task/index.d.ts +43 -0
  672. package/dist/types/task/name-generator.d.ts +16 -0
  673. package/dist/types/task/output-manager.d.ts +36 -0
  674. package/dist/types/task/parallel.d.ts +34 -0
  675. package/dist/types/task/receipt.d.ts +87 -0
  676. package/dist/types/task/render.d.ts +28 -0
  677. package/dist/types/task/roi-reconciliation.d.ts +27 -0
  678. package/dist/types/task/simple-mode.d.ts +8 -0
  679. package/dist/types/task/skc-command.d.ts +7 -0
  680. package/dist/types/task/spawn-gate.d.ts +38 -0
  681. package/dist/types/task/subprocess-tool-registry.d.ts +72 -0
  682. package/dist/types/task/types.d.ts +508 -0
  683. package/dist/types/task/worktree.d.ts +94 -0
  684. package/dist/types/thinking-metadata.d.ts +16 -0
  685. package/dist/types/thinking.d.ts +22 -0
  686. package/dist/types/tool-discovery/tool-index.d.ts +112 -0
  687. package/dist/types/tools/archive-reader.d.ts +40 -0
  688. package/dist/types/tools/ask.d.ts +123 -0
  689. package/dist/types/tools/ast-edit.d.ts +77 -0
  690. package/dist/types/tools/ast-grep.d.ts +69 -0
  691. package/dist/types/tools/auto-generated-guard.d.ts +17 -0
  692. package/dist/types/tools/bash-allowed-prefixes.d.ts +10 -0
  693. package/dist/types/tools/bash-command-fixup.d.ts +11 -0
  694. package/dist/types/tools/bash-interactive.d.ts +16 -0
  695. package/dist/types/tools/bash-interceptor.d.ts +24 -0
  696. package/dist/types/tools/bash-pty-selection.d.ts +7 -0
  697. package/dist/types/tools/bash-skill-urls.d.ts +31 -0
  698. package/dist/types/tools/bash.d.ts +157 -0
  699. package/dist/types/tools/browser/actions.d.ts +54 -0
  700. package/dist/types/tools/browser/attach.d.ts +50 -0
  701. package/dist/types/tools/browser/launch.d.ts +62 -0
  702. package/dist/types/tools/browser/readable.d.ts +17 -0
  703. package/dist/types/tools/browser/registry.d.ts +57 -0
  704. package/dist/types/tools/browser/render.d.ts +53 -0
  705. package/dist/types/tools/browser/tab-protocol.d.ts +144 -0
  706. package/dist/types/tools/browser/tab-supervisor.d.ts +72 -0
  707. package/dist/types/tools/browser/tab-worker-entry.d.ts +1 -0
  708. package/dist/types/tools/browser/tab-worker.d.ts +19 -0
  709. package/dist/types/tools/browser.d.ts +211 -0
  710. package/dist/types/tools/calculator.d.ts +76 -0
  711. package/dist/types/tools/checkpoint.d.ts +63 -0
  712. package/dist/types/tools/computer/render.d.ts +17 -0
  713. package/dist/types/tools/computer.d.ts +465 -0
  714. package/dist/types/tools/conflict-detect.d.ts +205 -0
  715. package/dist/types/tools/context.d.ts +19 -0
  716. package/dist/types/tools/cron.d.ts +116 -0
  717. package/dist/types/tools/debug.d.ts +209 -0
  718. package/dist/types/tools/eval.d.ts +108 -0
  719. package/dist/types/tools/fetch.d.ts +61 -0
  720. package/dist/types/tools/file-recorder.d.ts +13 -0
  721. package/dist/types/tools/find.d.ts +95 -0
  722. package/dist/types/tools/fs-cache-invalidation.d.ts +15 -0
  723. package/dist/types/tools/gh-format.d.ts +6 -0
  724. package/dist/types/tools/gh-renderer.d.ts +25 -0
  725. package/dist/types/tools/gh.d.ts +356 -0
  726. package/dist/types/tools/github-cache.d.ts +103 -0
  727. package/dist/types/tools/grouped-file-output.d.ts +36 -0
  728. package/dist/types/tools/hindsight-recall.d.ts +21 -0
  729. package/dist/types/tools/hindsight-reflect.d.ts +23 -0
  730. package/dist/types/tools/hindsight-retain.d.ts +27 -0
  731. package/dist/types/tools/image-gen.d.ts +79 -0
  732. package/dist/types/tools/index.d.ts +297 -0
  733. package/dist/types/tools/inspect-image-renderer.d.ts +26 -0
  734. package/dist/types/tools/inspect-image.d.ts +31 -0
  735. package/dist/types/tools/irc.d.ts +79 -0
  736. package/dist/types/tools/job.d.ts +78 -0
  737. package/dist/types/tools/json-tree.d.ts +23 -0
  738. package/dist/types/tools/jtd-to-json-schema.d.ts +29 -0
  739. package/dist/types/tools/jtd-to-typescript.d.ts +26 -0
  740. package/dist/types/tools/jtd-utils.d.ts +42 -0
  741. package/dist/types/tools/list-limit.d.ts +12 -0
  742. package/dist/types/tools/match-line-format.d.ts +11 -0
  743. package/dist/types/tools/monitor.d.ts +54 -0
  744. package/dist/types/tools/output-meta.d.ts +204 -0
  745. package/dist/types/tools/path-utils.d.ts +147 -0
  746. package/dist/types/tools/plan-mode-guard.d.ts +18 -0
  747. package/dist/types/tools/read.d.ts +85 -0
  748. package/dist/types/tools/recipe/index.d.ts +45 -0
  749. package/dist/types/tools/recipe/render.d.ts +36 -0
  750. package/dist/types/tools/recipe/runner.d.ts +60 -0
  751. package/dist/types/tools/recipe/runners/cargo.d.ts +16 -0
  752. package/dist/types/tools/recipe/runners/index.d.ts +2 -0
  753. package/dist/types/tools/recipe/runners/just.d.ts +2 -0
  754. package/dist/types/tools/recipe/runners/make.d.ts +2 -0
  755. package/dist/types/tools/recipe/runners/pkg.d.ts +2 -0
  756. package/dist/types/tools/recipe/runners/task.d.ts +2 -0
  757. package/dist/types/tools/render-mermaid.d.ts +37 -0
  758. package/dist/types/tools/render-utils.d.ts +158 -0
  759. package/dist/types/tools/renderers.d.ts +26 -0
  760. package/dist/types/tools/resolve.d.ts +80 -0
  761. package/dist/types/tools/review.d.ts +63 -0
  762. package/dist/types/tools/search-tool-bm25.d.ts +65 -0
  763. package/dist/types/tools/search.d.ts +93 -0
  764. package/dist/types/tools/skill.d.ts +47 -0
  765. package/dist/types/tools/sqlite-reader.d.ts +94 -0
  766. package/dist/types/tools/ssh.d.ts +67 -0
  767. package/dist/types/tools/subagent-render.d.ts +31 -0
  768. package/dist/types/tools/subagent.d.ts +114 -0
  769. package/dist/types/tools/todo-write.d.ts +120 -0
  770. package/dist/types/tools/tool-errors.d.ts +33 -0
  771. package/dist/types/tools/tool-result.d.ts +30 -0
  772. package/dist/types/tools/tool-timeouts.d.ts +56 -0
  773. package/dist/types/tools/ultragoal-ask-guard.d.ts +5 -0
  774. package/dist/types/tools/vim.d.ts +58 -0
  775. package/dist/types/tools/write.d.ts +59 -0
  776. package/dist/types/tools/yield.d.ts +25 -0
  777. package/dist/types/tui/code-cell.d.ts +32 -0
  778. package/dist/types/tui/file-list.d.ts +22 -0
  779. package/dist/types/tui/hyperlink.d.ts +42 -0
  780. package/dist/types/tui/index.d.ts +11 -0
  781. package/dist/types/tui/output-block.d.ts +28 -0
  782. package/dist/types/tui/status-line.d.ts +18 -0
  783. package/dist/types/tui/tree-list.d.ts +19 -0
  784. package/dist/types/tui/types.d.ts +13 -0
  785. package/dist/types/tui/utils.d.ts +36 -0
  786. package/dist/types/utils/changelog.d.ts +36 -0
  787. package/dist/types/utils/clipboard.d.ts +22 -0
  788. package/dist/types/utils/command-args.d.ts +9 -0
  789. package/dist/types/utils/commit-message-generator.d.ts +7 -0
  790. package/dist/types/utils/edit-mode.d.ts +13 -0
  791. package/dist/types/utils/event-bus.d.ts +6 -0
  792. package/dist/types/utils/external-editor.d.ts +17 -0
  793. package/dist/types/utils/file-display-mode.d.ts +27 -0
  794. package/dist/types/utils/file-mentions.d.ts +11 -0
  795. package/dist/types/utils/git.d.ts +361 -0
  796. package/dist/types/utils/image-loading.d.ts +26 -0
  797. package/dist/types/utils/image-resize.d.ts +39 -0
  798. package/dist/types/utils/lang-from-path.d.ts +8 -0
  799. package/dist/types/utils/markit.d.ts +7 -0
  800. package/dist/types/utils/open.d.ts +2 -0
  801. package/dist/types/utils/session-color.d.ts +10 -0
  802. package/dist/types/utils/shell-snapshot.d.ts +5 -0
  803. package/dist/types/utils/sixel.d.ts +21 -0
  804. package/dist/types/utils/title-generator.d.ts +31 -0
  805. package/dist/types/utils/tool-choice.d.ts +20 -0
  806. package/dist/types/utils/tools-manager.d.ts +9 -0
  807. package/dist/types/vim/buffer.d.ts +41 -0
  808. package/dist/types/vim/commands.d.ts +6 -0
  809. package/dist/types/vim/engine.d.ts +47 -0
  810. package/dist/types/vim/parser.d.ts +3 -0
  811. package/dist/types/vim/render.d.ts +25 -0
  812. package/dist/types/vim/types.d.ts +182 -0
  813. package/dist/types/web/kagi.d.ts +23 -0
  814. package/dist/types/web/parallel.d.ts +58 -0
  815. package/dist/types/web/scrapers/artifacthub.d.ts +6 -0
  816. package/dist/types/web/scrapers/arxiv.d.ts +5 -0
  817. package/dist/types/web/scrapers/aur.d.ts +5 -0
  818. package/dist/types/web/scrapers/biorxiv.d.ts +5 -0
  819. package/dist/types/web/scrapers/bluesky.d.ts +5 -0
  820. package/dist/types/web/scrapers/brew.d.ts +5 -0
  821. package/dist/types/web/scrapers/cheatsh.d.ts +8 -0
  822. package/dist/types/web/scrapers/chocolatey.d.ts +5 -0
  823. package/dist/types/web/scrapers/choosealicense.d.ts +2 -0
  824. package/dist/types/web/scrapers/cisa-kev.d.ts +5 -0
  825. package/dist/types/web/scrapers/clojars.d.ts +5 -0
  826. package/dist/types/web/scrapers/coingecko.d.ts +5 -0
  827. package/dist/types/web/scrapers/crates-io.d.ts +5 -0
  828. package/dist/types/web/scrapers/crossref.d.ts +2 -0
  829. package/dist/types/web/scrapers/devto.d.ts +5 -0
  830. package/dist/types/web/scrapers/discogs.d.ts +8 -0
  831. package/dist/types/web/scrapers/discourse.d.ts +5 -0
  832. package/dist/types/web/scrapers/dockerhub.d.ts +5 -0
  833. package/dist/types/web/scrapers/docs-rs.d.ts +2 -0
  834. package/dist/types/web/scrapers/fdroid.d.ts +5 -0
  835. package/dist/types/web/scrapers/firefox-addons.d.ts +2 -0
  836. package/dist/types/web/scrapers/flathub.d.ts +2 -0
  837. package/dist/types/web/scrapers/github-gist.d.ts +5 -0
  838. package/dist/types/web/scrapers/github.d.ts +12 -0
  839. package/dist/types/web/scrapers/gitlab.d.ts +5 -0
  840. package/dist/types/web/scrapers/go-pkg.d.ts +5 -0
  841. package/dist/types/web/scrapers/hackage.d.ts +5 -0
  842. package/dist/types/web/scrapers/hackernews.d.ts +2 -0
  843. package/dist/types/web/scrapers/hex.d.ts +5 -0
  844. package/dist/types/web/scrapers/huggingface.d.ts +2 -0
  845. package/dist/types/web/scrapers/iacr.d.ts +5 -0
  846. package/dist/types/web/scrapers/index.d.ts +84 -0
  847. package/dist/types/web/scrapers/jetbrains-marketplace.d.ts +2 -0
  848. package/dist/types/web/scrapers/lemmy.d.ts +2 -0
  849. package/dist/types/web/scrapers/lobsters.d.ts +5 -0
  850. package/dist/types/web/scrapers/mastodon.d.ts +5 -0
  851. package/dist/types/web/scrapers/maven.d.ts +6 -0
  852. package/dist/types/web/scrapers/mdn.d.ts +2 -0
  853. package/dist/types/web/scrapers/metacpan.d.ts +5 -0
  854. package/dist/types/web/scrapers/musicbrainz.d.ts +5 -0
  855. package/dist/types/web/scrapers/npm.d.ts +5 -0
  856. package/dist/types/web/scrapers/nuget.d.ts +5 -0
  857. package/dist/types/web/scrapers/nvd.d.ts +5 -0
  858. package/dist/types/web/scrapers/ollama.d.ts +2 -0
  859. package/dist/types/web/scrapers/open-vsx.d.ts +5 -0
  860. package/dist/types/web/scrapers/opencorporates.d.ts +5 -0
  861. package/dist/types/web/scrapers/openlibrary.d.ts +5 -0
  862. package/dist/types/web/scrapers/orcid.d.ts +5 -0
  863. package/dist/types/web/scrapers/osv.d.ts +5 -0
  864. package/dist/types/web/scrapers/packagist.d.ts +5 -0
  865. package/dist/types/web/scrapers/pub-dev.d.ts +5 -0
  866. package/dist/types/web/scrapers/pubmed.d.ts +5 -0
  867. package/dist/types/web/scrapers/pypi.d.ts +5 -0
  868. package/dist/types/web/scrapers/rawg.d.ts +2 -0
  869. package/dist/types/web/scrapers/readthedocs.d.ts +2 -0
  870. package/dist/types/web/scrapers/reddit.d.ts +5 -0
  871. package/dist/types/web/scrapers/repology.d.ts +5 -0
  872. package/dist/types/web/scrapers/rfc.d.ts +5 -0
  873. package/dist/types/web/scrapers/rubygems.d.ts +5 -0
  874. package/dist/types/web/scrapers/searchcode.d.ts +2 -0
  875. package/dist/types/web/scrapers/sec-edgar.d.ts +5 -0
  876. package/dist/types/web/scrapers/semantic-scholar.d.ts +2 -0
  877. package/dist/types/web/scrapers/snapcraft.d.ts +2 -0
  878. package/dist/types/web/scrapers/sourcegraph.d.ts +2 -0
  879. package/dist/types/web/scrapers/spdx.d.ts +5 -0
  880. package/dist/types/web/scrapers/spotify.d.ts +8 -0
  881. package/dist/types/web/scrapers/stackoverflow.d.ts +6 -0
  882. package/dist/types/web/scrapers/terraform.d.ts +5 -0
  883. package/dist/types/web/scrapers/tldr.d.ts +7 -0
  884. package/dist/types/web/scrapers/twitter.d.ts +5 -0
  885. package/dist/types/web/scrapers/types.d.ts +78 -0
  886. package/dist/types/web/scrapers/utils.d.ts +26 -0
  887. package/dist/types/web/scrapers/vimeo.d.ts +5 -0
  888. package/dist/types/web/scrapers/vscode-marketplace.d.ts +5 -0
  889. package/dist/types/web/scrapers/w3c.d.ts +2 -0
  890. package/dist/types/web/scrapers/wikidata.d.ts +5 -0
  891. package/dist/types/web/scrapers/wikipedia.d.ts +5 -0
  892. package/dist/types/web/scrapers/youtube.d.ts +5 -0
  893. package/dist/types/web/search/index.d.ts +115 -0
  894. package/dist/types/web/search/provider.d.ts +24 -0
  895. package/dist/types/web/search/providers/anthropic.d.ts +32 -0
  896. package/dist/types/web/search/providers/base.d.ts +90 -0
  897. package/dist/types/web/search/providers/brave.d.ts +27 -0
  898. package/dist/types/web/search/providers/codex.d.ts +35 -0
  899. package/dist/types/web/search/providers/duckduckgo.d.ts +57 -0
  900. package/dist/types/web/search/providers/exa.d.ts +52 -0
  901. package/dist/types/web/search/providers/gemini.d.ts +57 -0
  902. package/dist/types/web/search/providers/jina.d.ts +26 -0
  903. package/dist/types/web/search/providers/kagi.d.ts +24 -0
  904. package/dist/types/web/search/providers/kimi.d.ts +27 -0
  905. package/dist/types/web/search/providers/openai-compatible.d.ts +9 -0
  906. package/dist/types/web/search/providers/parallel.d.ts +15 -0
  907. package/dist/types/web/search/providers/perplexity.d.ts +38 -0
  908. package/dist/types/web/search/providers/searxng.d.ts +44 -0
  909. package/dist/types/web/search/providers/synthetic.d.ts +21 -0
  910. package/dist/types/web/search/providers/tavily.d.ts +29 -0
  911. package/dist/types/web/search/providers/utils.d.ts +52 -0
  912. package/dist/types/web/search/providers/xai.d.ts +64 -0
  913. package/dist/types/web/search/providers/zai.d.ts +28 -0
  914. package/dist/types/web/search/render.d.ts +35 -0
  915. package/dist/types/web/search/types.d.ts +364 -0
  916. package/dist/types/web/search/utils.d.ts +4 -0
  917. package/dist/types/workspace-tree.d.ts +42 -0
  918. package/examples/README.md +21 -0
  919. package/examples/custom-tools/README.md +104 -0
  920. package/examples/custom-tools/hello/index.ts +20 -0
  921. package/examples/extensions/README.md +120 -0
  922. package/examples/extensions/api-demo.ts +79 -0
  923. package/examples/extensions/chalk-logger.ts +25 -0
  924. package/examples/extensions/hello.ts +31 -0
  925. package/examples/extensions/pirate.ts +43 -0
  926. package/examples/extensions/plan-mode.ts +549 -0
  927. package/examples/extensions/reload-runtime.ts +38 -0
  928. package/examples/extensions/tools.ts +144 -0
  929. package/examples/extensions/with-deps/index.ts +36 -0
  930. package/examples/extensions/with-deps/package-lock.json +31 -0
  931. package/examples/extensions/with-deps/package.json +16 -0
  932. package/examples/hooks/README.md +56 -0
  933. package/examples/hooks/auto-commit-on-exit.ts +48 -0
  934. package/examples/hooks/confirm-destructive.ts +58 -0
  935. package/examples/hooks/custom-compaction.ts +115 -0
  936. package/examples/hooks/dirty-repo-guard.ts +51 -0
  937. package/examples/hooks/file-trigger.ts +40 -0
  938. package/examples/hooks/git-checkpoint.ts +52 -0
  939. package/examples/hooks/handoff.ts +149 -0
  940. package/examples/hooks/permission-gate.ts +33 -0
  941. package/examples/hooks/protected-paths.ts +29 -0
  942. package/examples/hooks/qna.ts +118 -0
  943. package/examples/hooks/status-line.ts +39 -0
  944. package/examples/sdk/01-minimal.ts +21 -0
  945. package/examples/sdk/02-custom-model.ts +49 -0
  946. package/examples/sdk/03-custom-prompt.ts +46 -0
  947. package/examples/sdk/04-skills.ts +43 -0
  948. package/examples/sdk/06-extensions.ts +82 -0
  949. package/examples/sdk/06-hooks.ts +61 -0
  950. package/examples/sdk/07-context-files.ts +35 -0
  951. package/examples/sdk/08-prompt-templates.ts +41 -0
  952. package/examples/sdk/08-slash-commands.ts +46 -0
  953. package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
  954. package/examples/sdk/11-sessions.ts +47 -0
  955. package/examples/sdk/README.md +172 -0
  956. package/package.json +540 -0
  957. package/scripts/build-binary.ts +95 -0
  958. package/scripts/format-prompts.ts +68 -0
  959. package/scripts/generate-docs-index.ts +71 -0
  960. package/scripts/generate-template.ts +33 -0
  961. package/src/async/index.ts +2 -0
  962. package/src/async/job-manager.ts +1489 -0
  963. package/src/async/support.ts +6 -0
  964. package/src/autoresearch/command-resume.md +14 -0
  965. package/src/autoresearch/dashboard.ts +446 -0
  966. package/src/autoresearch/git.ts +319 -0
  967. package/src/autoresearch/helpers.ts +218 -0
  968. package/src/autoresearch/index.ts +536 -0
  969. package/src/autoresearch/prompt-setup.md +43 -0
  970. package/src/autoresearch/prompt.md +103 -0
  971. package/src/autoresearch/resume-message.md +10 -0
  972. package/src/autoresearch/state.ts +273 -0
  973. package/src/autoresearch/storage.ts +699 -0
  974. package/src/autoresearch/tools/init-experiment.ts +272 -0
  975. package/src/autoresearch/tools/log-experiment.ts +524 -0
  976. package/src/autoresearch/tools/run-experiment.ts +475 -0
  977. package/src/autoresearch/tools/update-notes.ts +109 -0
  978. package/src/autoresearch/types.ts +168 -0
  979. package/src/bun-imports.d.ts +28 -0
  980. package/src/capability/context-file.ts +44 -0
  981. package/src/capability/extension-module.ts +34 -0
  982. package/src/capability/extension.ts +47 -0
  983. package/src/capability/fs.ts +107 -0
  984. package/src/capability/hook.ts +40 -0
  985. package/src/capability/index.ts +436 -0
  986. package/src/capability/instruction.ts +37 -0
  987. package/src/capability/mcp.ts +74 -0
  988. package/src/capability/prompt.ts +35 -0
  989. package/src/capability/rule.ts +244 -0
  990. package/src/capability/settings.ts +34 -0
  991. package/src/capability/skill.ts +56 -0
  992. package/src/capability/slash-command.ts +40 -0
  993. package/src/capability/ssh.ts +41 -0
  994. package/src/capability/system-prompt.ts +34 -0
  995. package/src/capability/tool.ts +38 -0
  996. package/src/capability/types.ts +168 -0
  997. package/src/cli/agents-cli.ts +141 -0
  998. package/src/cli/args.ts +306 -0
  999. package/src/cli/auth-broker-cli.ts +748 -0
  1000. package/src/cli/auth-gateway-cli.ts +411 -0
  1001. package/src/cli/classify-install-target.ts +50 -0
  1002. package/src/cli/commands/init-xdg.ts +27 -0
  1003. package/src/cli/config-cli.ts +426 -0
  1004. package/src/cli/fast-help.ts +82 -0
  1005. package/src/cli/file-processor.ts +123 -0
  1006. package/src/cli/grep-cli.ts +160 -0
  1007. package/src/cli/initial-message.ts +58 -0
  1008. package/src/cli/list-models.ts +206 -0
  1009. package/src/cli/plugin-cli.ts +942 -0
  1010. package/src/cli/read-cli.ts +57 -0
  1011. package/src/cli/session-picker.ts +52 -0
  1012. package/src/cli/setup-cli.ts +675 -0
  1013. package/src/cli/shell-cli.ts +176 -0
  1014. package/src/cli/skills-cli.ts +88 -0
  1015. package/src/cli/ssh-cli.ts +179 -0
  1016. package/src/cli/stats-cli.ts +238 -0
  1017. package/src/cli/update-cli.ts +459 -0
  1018. package/src/cli/web-search-cli.ts +248 -0
  1019. package/src/cli/worktree-cli.ts +291 -0
  1020. package/src/cli.ts +225 -0
  1021. package/src/commands/acp.ts +24 -0
  1022. package/src/commands/agents.ts +57 -0
  1023. package/src/commands/auth-broker.ts +96 -0
  1024. package/src/commands/auth-gateway.ts +63 -0
  1025. package/src/commands/codex-native-hook.ts +11 -0
  1026. package/src/commands/commit.ts +46 -0
  1027. package/src/commands/config.ts +51 -0
  1028. package/src/commands/contribution-prep.ts +41 -0
  1029. package/src/commands/coordinator.ts +113 -0
  1030. package/src/commands/deep-interview.ts +39 -0
  1031. package/src/commands/gc.ts +22 -0
  1032. package/src/commands/grep.ts +48 -0
  1033. package/src/commands/harness.ts +1207 -0
  1034. package/src/commands/launch.ts +178 -0
  1035. package/src/commands/mcp-serve.ts +63 -0
  1036. package/src/commands/plugin.ts +78 -0
  1037. package/src/commands/ralplan.ts +19 -0
  1038. package/src/commands/read.ts +35 -0
  1039. package/src/commands/rlm.ts +19 -0
  1040. package/src/commands/session.ts +152 -0
  1041. package/src/commands/setup.ts +91 -0
  1042. package/src/commands/shell.ts +29 -0
  1043. package/src/commands/skills.ts +48 -0
  1044. package/src/commands/ssh.ts +60 -0
  1045. package/src/commands/state.ts +24 -0
  1046. package/src/commands/stats.ts +29 -0
  1047. package/src/commands/team.ts +216 -0
  1048. package/src/commands/ultragoal.ts +41 -0
  1049. package/src/commands/update.ts +21 -0
  1050. package/src/commands/web-search.ts +108 -0
  1051. package/src/commands/worktree.ts +56 -0
  1052. package/src/commit/agentic/agent.ts +316 -0
  1053. package/src/commit/agentic/fallback.ts +96 -0
  1054. package/src/commit/agentic/index.ts +356 -0
  1055. package/src/commit/agentic/prompts/analyze-file.md +22 -0
  1056. package/src/commit/agentic/prompts/session-user.md +25 -0
  1057. package/src/commit/agentic/prompts/split-confirm.md +1 -0
  1058. package/src/commit/agentic/prompts/system.md +38 -0
  1059. package/src/commit/agentic/state.ts +60 -0
  1060. package/src/commit/agentic/tools/analyze-file.ts +127 -0
  1061. package/src/commit/agentic/tools/git-file-diff.ts +191 -0
  1062. package/src/commit/agentic/tools/git-hunk.ts +50 -0
  1063. package/src/commit/agentic/tools/git-overview.ts +81 -0
  1064. package/src/commit/agentic/tools/index.ts +54 -0
  1065. package/src/commit/agentic/tools/propose-changelog.ts +144 -0
  1066. package/src/commit/agentic/tools/propose-commit.ts +109 -0
  1067. package/src/commit/agentic/tools/recent-commits.ts +81 -0
  1068. package/src/commit/agentic/tools/schemas.ts +23 -0
  1069. package/src/commit/agentic/tools/split-commit.ts +238 -0
  1070. package/src/commit/agentic/topo-sort.ts +44 -0
  1071. package/src/commit/agentic/trivial.ts +51 -0
  1072. package/src/commit/agentic/validation.ts +183 -0
  1073. package/src/commit/analysis/conventional.ts +64 -0
  1074. package/src/commit/analysis/index.ts +4 -0
  1075. package/src/commit/analysis/scope.ts +242 -0
  1076. package/src/commit/analysis/summary.ts +105 -0
  1077. package/src/commit/analysis/validation.ts +66 -0
  1078. package/src/commit/changelog/detect.ts +40 -0
  1079. package/src/commit/changelog/generate.ts +97 -0
  1080. package/src/commit/changelog/index.ts +234 -0
  1081. package/src/commit/changelog/parse.ts +44 -0
  1082. package/src/commit/cli.ts +85 -0
  1083. package/src/commit/git/diff.ts +148 -0
  1084. package/src/commit/index.ts +5 -0
  1085. package/src/commit/map-reduce/index.ts +69 -0
  1086. package/src/commit/map-reduce/map-phase.ts +193 -0
  1087. package/src/commit/map-reduce/reduce-phase.ts +49 -0
  1088. package/src/commit/map-reduce/utils.ts +9 -0
  1089. package/src/commit/message.ts +11 -0
  1090. package/src/commit/model-selection.ts +51 -0
  1091. package/src/commit/pipeline.ts +244 -0
  1092. package/src/commit/prompts/analysis-system.md +148 -0
  1093. package/src/commit/prompts/analysis-user.md +38 -0
  1094. package/src/commit/prompts/changelog-system.md +50 -0
  1095. package/src/commit/prompts/changelog-user.md +18 -0
  1096. package/src/commit/prompts/file-observer-system.md +24 -0
  1097. package/src/commit/prompts/file-observer-user.md +8 -0
  1098. package/src/commit/prompts/reduce-system.md +50 -0
  1099. package/src/commit/prompts/reduce-user.md +17 -0
  1100. package/src/commit/prompts/summary-retry.md +3 -0
  1101. package/src/commit/prompts/summary-system.md +38 -0
  1102. package/src/commit/prompts/summary-user.md +13 -0
  1103. package/src/commit/prompts/types-description.md +2 -0
  1104. package/src/commit/shared-llm.ts +77 -0
  1105. package/src/commit/types.ts +118 -0
  1106. package/src/commit/utils/exclusions.ts +42 -0
  1107. package/src/commit/utils.ts +58 -0
  1108. package/src/config/config-file.ts +232 -0
  1109. package/src/config/file-lock-gc.ts +193 -0
  1110. package/src/config/file-lock.ts +185 -0
  1111. package/src/config/keybindings.ts +510 -0
  1112. package/src/config/mcp-schema.json +230 -0
  1113. package/src/config/model-equivalence.ts +811 -0
  1114. package/src/config/model-profile-activation.ts +249 -0
  1115. package/src/config/model-profiles.ts +396 -0
  1116. package/src/config/model-registry.ts +2816 -0
  1117. package/src/config/model-resolver.ts +1336 -0
  1118. package/src/config/models-config-schema.ts +258 -0
  1119. package/src/config/prompt-templates.ts +310 -0
  1120. package/src/config/resolve-config-value.ts +94 -0
  1121. package/src/config/settings-schema.ts +3183 -0
  1122. package/src/config/settings.ts +967 -0
  1123. package/src/config/skill-settings-defaults.ts +27 -0
  1124. package/src/config.ts +212 -0
  1125. package/src/coordinator/contract.ts +22 -0
  1126. package/src/coordinator-mcp/policy.ts +160 -0
  1127. package/src/coordinator-mcp/safety.ts +80 -0
  1128. package/src/coordinator-mcp/server.ts +2006 -0
  1129. package/src/cursor.ts +392 -0
  1130. package/src/dap/client.ts +730 -0
  1131. package/src/dap/config.ts +150 -0
  1132. package/src/dap/defaults.json +211 -0
  1133. package/src/dap/index.ts +4 -0
  1134. package/src/dap/session.ts +1343 -0
  1135. package/src/dap/types.ts +600 -0
  1136. package/src/debug/crash-diagnostics.ts +223 -0
  1137. package/src/debug/index.ts +459 -0
  1138. package/src/debug/log-formatting.ts +58 -0
  1139. package/src/debug/log-viewer.ts +908 -0
  1140. package/src/debug/profiler.ts +162 -0
  1141. package/src/debug/raw-sse-buffer.ts +270 -0
  1142. package/src/debug/raw-sse.ts +213 -0
  1143. package/src/debug/report-bundle.ts +365 -0
  1144. package/src/debug/runtime-gauges.ts +20 -0
  1145. package/src/debug/system-info.ts +111 -0
  1146. package/src/deep-interview/render-middleware.ts +372 -0
  1147. package/src/defaults/skc/agent.models.grok-cli.yml +36 -0
  1148. package/src/defaults/skc/extensions/grok-build/index.ts +1 -0
  1149. package/src/defaults/skc/extensions/grok-build/package.json +7 -0
  1150. package/src/defaults/skc/extensions/grok-cli-vendor/biome.json +39 -0
  1151. package/src/defaults/skc/extensions/grok-cli-vendor/package.json +8 -0
  1152. package/src/defaults/skc/extensions/grok-cli-vendor/src/index.ts +1 -0
  1153. package/src/defaults/skc/extensions/grok-cli-vendor/src/models/catalog.ts +155 -0
  1154. package/src/defaults/skc/extensions/grok-cli-vendor/src/payload/sanitize.ts +361 -0
  1155. package/src/defaults/skc/extensions/grok-cli-vendor/src/provider/billing.ts +57 -0
  1156. package/src/defaults/skc/extensions/grok-cli-vendor/src/provider/register.ts +99 -0
  1157. package/src/defaults/skc/extensions/grok-cli-vendor/src/provider/stream.ts +50 -0
  1158. package/src/defaults/skc/extensions/grok-cli-vendor/src/provider/usage.ts +56 -0
  1159. package/src/defaults/skc/extensions/grok-cli-vendor/src/shared/base-url.ts +36 -0
  1160. package/src/defaults/skc/extensions/grok-cli-vendor/src/shared/errors.ts +44 -0
  1161. package/src/defaults/skc/skills/deep-interview/SKILL.md +879 -0
  1162. package/src/defaults/skc/skills/deep-interview/auto-answer-uncertain.md +37 -0
  1163. package/src/defaults/skc/skills/deep-interview/auto-research-greenfield.md +42 -0
  1164. package/src/defaults/skc/skills/deep-interview/lateral-review-panel.md +49 -0
  1165. package/src/defaults/skc/skills/ralplan/SKILL.md +191 -0
  1166. package/src/defaults/skc/skills/team/SKILL.md +442 -0
  1167. package/src/defaults/skc/skills/ultragoal/SKILL.md +349 -0
  1168. package/src/defaults/skc/skills/ultragoal/ai-slop-cleaner.md +61 -0
  1169. package/src/defaults/skc-defaults.ts +217 -0
  1170. package/src/defaults/skc-grok-cli.ts +22 -0
  1171. package/src/discovery/agents-md.ts +67 -0
  1172. package/src/discovery/agents.ts +230 -0
  1173. package/src/discovery/builtin.ts +932 -0
  1174. package/src/discovery/claude-plugins.ts +407 -0
  1175. package/src/discovery/claude.ts +313 -0
  1176. package/src/discovery/cline.ts +83 -0
  1177. package/src/discovery/codex.ts +330 -0
  1178. package/src/discovery/cursor.ts +220 -0
  1179. package/src/discovery/gemini.ts +383 -0
  1180. package/src/discovery/github.ts +118 -0
  1181. package/src/discovery/helpers.ts +992 -0
  1182. package/src/discovery/index.ts +76 -0
  1183. package/src/discovery/mcp-json.ts +171 -0
  1184. package/src/discovery/opencode.ts +398 -0
  1185. package/src/discovery/plugin-dir-roots.ts +28 -0
  1186. package/src/discovery/ssh.ts +153 -0
  1187. package/src/discovery/substitute-plugin-root.ts +29 -0
  1188. package/src/discovery/vscode.ts +105 -0
  1189. package/src/discovery/windsurf.ts +147 -0
  1190. package/src/edit/apply-patch/index.ts +87 -0
  1191. package/src/edit/apply-patch/parser.ts +174 -0
  1192. package/src/edit/diff.ts +873 -0
  1193. package/src/edit/file-read-cache.ts +95 -0
  1194. package/src/edit/index.ts +528 -0
  1195. package/src/edit/modes/apply-patch.lark +19 -0
  1196. package/src/edit/modes/apply-patch.ts +53 -0
  1197. package/src/edit/modes/patch.ts +1835 -0
  1198. package/src/edit/modes/replace.ts +1161 -0
  1199. package/src/edit/normalize.ts +375 -0
  1200. package/src/edit/notebook.ts +226 -0
  1201. package/src/edit/read-file.ts +43 -0
  1202. package/src/edit/renderer.ts +683 -0
  1203. package/src/edit/streaming.ts +561 -0
  1204. package/src/eval/backend.ts +43 -0
  1205. package/src/eval/index.ts +4 -0
  1206. package/src/eval/js/context-manager.ts +577 -0
  1207. package/src/eval/js/executor.ts +136 -0
  1208. package/src/eval/js/index.ts +47 -0
  1209. package/src/eval/js/shared/helpers.ts +237 -0
  1210. package/src/eval/js/shared/indirect-eval.ts +30 -0
  1211. package/src/eval/js/shared/prelude.ts +2 -0
  1212. package/src/eval/js/shared/prelude.txt +70 -0
  1213. package/src/eval/js/shared/rewrite-imports.ts +415 -0
  1214. package/src/eval/js/shared/runtime.ts +301 -0
  1215. package/src/eval/js/shared/types.ts +18 -0
  1216. package/src/eval/js/tool-bridge.ts +144 -0
  1217. package/src/eval/js/worker-core.ts +150 -0
  1218. package/src/eval/js/worker-entry.ts +24 -0
  1219. package/src/eval/js/worker-protocol.ts +41 -0
  1220. package/src/eval/py/display.ts +71 -0
  1221. package/src/eval/py/executor.ts +678 -0
  1222. package/src/eval/py/index.ts +58 -0
  1223. package/src/eval/py/kernel.ts +712 -0
  1224. package/src/eval/py/prelude.py +462 -0
  1225. package/src/eval/py/prelude.ts +3 -0
  1226. package/src/eval/py/runner.py +964 -0
  1227. package/src/eval/py/runtime.ts +331 -0
  1228. package/src/eval/py/tool-bridge.ts +137 -0
  1229. package/src/eval/types.ts +48 -0
  1230. package/src/exa/factory.ts +60 -0
  1231. package/src/exa/index.ts +27 -0
  1232. package/src/exa/mcp-client.ts +364 -0
  1233. package/src/exa/render.ts +244 -0
  1234. package/src/exa/researcher.ts +36 -0
  1235. package/src/exa/search.ts +47 -0
  1236. package/src/exa/types.ts +166 -0
  1237. package/src/exa/websets.ts +248 -0
  1238. package/src/exec/bash-executor.ts +403 -0
  1239. package/src/exec/exec.ts +53 -0
  1240. package/src/exec/idle-timeout-watchdog.ts +126 -0
  1241. package/src/exec/non-interactive-env.ts +48 -0
  1242. package/src/export/custom-share.ts +65 -0
  1243. package/src/export/html/index.ts +168 -0
  1244. package/src/export/html/template.css +1060 -0
  1245. package/src/export/html/template.generated.ts +2 -0
  1246. package/src/export/html/template.html +47 -0
  1247. package/src/export/html/template.js +2268 -0
  1248. package/src/export/html/template.macro.ts +25 -0
  1249. package/src/export/html/vendor/highlight.min.js +1213 -0
  1250. package/src/export/html/vendor/marked.min.js +6 -0
  1251. package/src/export/ttsr.ts +434 -0
  1252. package/src/extensibility/custom-commands/bundled/ci-green/index.ts +25 -0
  1253. package/src/extensibility/custom-commands/bundled/review/index.ts +456 -0
  1254. package/src/extensibility/custom-commands/index.ts +2 -0
  1255. package/src/extensibility/custom-commands/loader.ts +238 -0
  1256. package/src/extensibility/custom-commands/types.ts +113 -0
  1257. package/src/extensibility/custom-tools/index.ts +7 -0
  1258. package/src/extensibility/custom-tools/loader.ts +245 -0
  1259. package/src/extensibility/custom-tools/types.ts +257 -0
  1260. package/src/extensibility/custom-tools/wrapper.ts +49 -0
  1261. package/src/extensibility/extensions/compact-handler.ts +40 -0
  1262. package/src/extensibility/extensions/get-commands-handler.ts +80 -0
  1263. package/src/extensibility/extensions/index.ts +16 -0
  1264. package/src/extensibility/extensions/loader.ts +551 -0
  1265. package/src/extensibility/extensions/prefix-command-bridge.ts +128 -0
  1266. package/src/extensibility/extensions/runner.ts +900 -0
  1267. package/src/extensibility/extensions/types.ts +1286 -0
  1268. package/src/extensibility/extensions/wrapper.ts +190 -0
  1269. package/src/extensibility/hooks/index.ts +5 -0
  1270. package/src/extensibility/hooks/loader.ts +257 -0
  1271. package/src/extensibility/hooks/runner.ts +425 -0
  1272. package/src/extensibility/hooks/tool-wrapper.ts +107 -0
  1273. package/src/extensibility/hooks/types.ts +599 -0
  1274. package/src/extensibility/plugins/doctor.ts +66 -0
  1275. package/src/extensibility/plugins/git-url.ts +281 -0
  1276. package/src/extensibility/plugins/index.ts +9 -0
  1277. package/src/extensibility/plugins/installer.ts +192 -0
  1278. package/src/extensibility/plugins/legacy-pi-compat.ts +336 -0
  1279. package/src/extensibility/plugins/loader.ts +288 -0
  1280. package/src/extensibility/plugins/manager.ts +731 -0
  1281. package/src/extensibility/plugins/marketplace/cache.ts +136 -0
  1282. package/src/extensibility/plugins/marketplace/fetcher.ts +317 -0
  1283. package/src/extensibility/plugins/marketplace/index.ts +6 -0
  1284. package/src/extensibility/plugins/marketplace/manager.ts +770 -0
  1285. package/src/extensibility/plugins/marketplace/registry.ts +196 -0
  1286. package/src/extensibility/plugins/marketplace/source-resolver.ts +147 -0
  1287. package/src/extensibility/plugins/marketplace/types.ts +191 -0
  1288. package/src/extensibility/plugins/parser.ts +105 -0
  1289. package/src/extensibility/plugins/types.ts +194 -0
  1290. package/src/extensibility/shared-events.ts +344 -0
  1291. package/src/extensibility/skc-plugins/activation.ts +87 -0
  1292. package/src/extensibility/skc-plugins/index.ts +9 -0
  1293. package/src/extensibility/skc-plugins/injection.ts +114 -0
  1294. package/src/extensibility/skc-plugins/loader.ts +131 -0
  1295. package/src/extensibility/skc-plugins/paths.ts +66 -0
  1296. package/src/extensibility/skc-plugins/schema.ts +79 -0
  1297. package/src/extensibility/skc-plugins/state.ts +29 -0
  1298. package/src/extensibility/skc-plugins/tools.ts +47 -0
  1299. package/src/extensibility/skc-plugins/types.ts +97 -0
  1300. package/src/extensibility/skc-plugins/validation.ts +76 -0
  1301. package/src/extensibility/skills.ts +423 -0
  1302. package/src/extensibility/slash-commands.ts +236 -0
  1303. package/src/extensibility/tool-proxy.ts +25 -0
  1304. package/src/extensibility/typebox.ts +418 -0
  1305. package/src/extensibility/utils.ts +44 -0
  1306. package/src/goals/index.ts +3 -0
  1307. package/src/goals/runtime.ts +419 -0
  1308. package/src/goals/state.ts +66 -0
  1309. package/src/goals/tools/goal-tool.ts +237 -0
  1310. package/src/harness-control-plane/classifier.ts +128 -0
  1311. package/src/harness-control-plane/control-endpoint.ts +148 -0
  1312. package/src/harness-control-plane/finalize.ts +340 -0
  1313. package/src/harness-control-plane/gc-adapter.ts +184 -0
  1314. package/src/harness-control-plane/operate.ts +225 -0
  1315. package/src/harness-control-plane/owner.ts +684 -0
  1316. package/src/harness-control-plane/phase-rollup.ts +96 -0
  1317. package/src/harness-control-plane/preserve.ts +102 -0
  1318. package/src/harness-control-plane/receipt-ingest.ts +127 -0
  1319. package/src/harness-control-plane/receipt-spool.ts +128 -0
  1320. package/src/harness-control-plane/receipts.ts +482 -0
  1321. package/src/harness-control-plane/rpc-adapter.ts +290 -0
  1322. package/src/harness-control-plane/seams.ts +39 -0
  1323. package/src/harness-control-plane/session-lease.ts +388 -0
  1324. package/src/harness-control-plane/state-machine.ts +119 -0
  1325. package/src/harness-control-plane/storage.ts +492 -0
  1326. package/src/harness-control-plane/types.ts +267 -0
  1327. package/src/hashline/anchors.ts +113 -0
  1328. package/src/hashline/apply.ts +737 -0
  1329. package/src/hashline/bigrams.json +649 -0
  1330. package/src/hashline/constants.ts +25 -0
  1331. package/src/hashline/diff-preview.ts +43 -0
  1332. package/src/hashline/diff.ts +56 -0
  1333. package/src/hashline/execute.ts +267 -0
  1334. package/src/hashline/grammar.lark +21 -0
  1335. package/src/hashline/hash.ts +196 -0
  1336. package/src/hashline/index.ts +13 -0
  1337. package/src/hashline/input.ts +130 -0
  1338. package/src/hashline/parser.ts +246 -0
  1339. package/src/hashline/prefixes.ts +101 -0
  1340. package/src/hashline/recovery.ts +113 -0
  1341. package/src/hashline/stream.ts +123 -0
  1342. package/src/hashline/types.ts +68 -0
  1343. package/src/hindsight/backend.ts +205 -0
  1344. package/src/hindsight/bank.ts +131 -0
  1345. package/src/hindsight/client.ts +598 -0
  1346. package/src/hindsight/config.ts +175 -0
  1347. package/src/hindsight/content.ts +210 -0
  1348. package/src/hindsight/index.ts +8 -0
  1349. package/src/hindsight/mental-models.ts +383 -0
  1350. package/src/hindsight/seeds.json +32 -0
  1351. package/src/hindsight/state.ts +469 -0
  1352. package/src/hindsight/transcript.ts +71 -0
  1353. package/src/hooks/codex-native-hooks-config.ts +143 -0
  1354. package/src/hooks/native-skill-hook.ts +305 -0
  1355. package/src/hooks/skill-keywords.ts +88 -0
  1356. package/src/hooks/skill-state.ts +753 -0
  1357. package/src/i18n/index.ts +188 -0
  1358. package/src/i18n/messages/de.messages.ts +308 -0
  1359. package/src/i18n/messages/de.settings.ts +805 -0
  1360. package/src/i18n/messages/de.ts +65 -0
  1361. package/src/i18n/messages/en.ts +86 -0
  1362. package/src/i18n/messages/es.messages.ts +314 -0
  1363. package/src/i18n/messages/es.settings.ts +798 -0
  1364. package/src/i18n/messages/es.ts +65 -0
  1365. package/src/i18n/messages/fr.messages.ts +312 -0
  1366. package/src/i18n/messages/fr.settings.ts +771 -0
  1367. package/src/i18n/messages/fr.ts +65 -0
  1368. package/src/i18n/messages/ja.messages.ts +314 -0
  1369. package/src/i18n/messages/ja.settings.ts +809 -0
  1370. package/src/i18n/messages/ja.ts +69 -0
  1371. package/src/i18n/messages/ko.messages.ts +312 -0
  1372. package/src/i18n/messages/ko.settings.ts +798 -0
  1373. package/src/i18n/messages/ko.ts +69 -0
  1374. package/src/i18n/messages/zh.messages.ts +298 -0
  1375. package/src/i18n/messages/zh.settings.ts +779 -0
  1376. package/src/i18n/messages/zh.ts +69 -0
  1377. package/src/index.ts +56 -0
  1378. package/src/internal-urls/agent-protocol.ts +176 -0
  1379. package/src/internal-urls/artifact-protocol.ts +84 -0
  1380. package/src/internal-urls/docs-index.generated.ts +106 -0
  1381. package/src/internal-urls/index.ts +21 -0
  1382. package/src/internal-urls/issue-pr-protocol.ts +577 -0
  1383. package/src/internal-urls/json-query.ts +126 -0
  1384. package/src/internal-urls/local-protocol.ts +249 -0
  1385. package/src/internal-urls/mcp-protocol.ts +151 -0
  1386. package/src/internal-urls/memory-protocol.ts +165 -0
  1387. package/src/internal-urls/parse.ts +72 -0
  1388. package/src/internal-urls/registry-helpers.ts +28 -0
  1389. package/src/internal-urls/router.ts +78 -0
  1390. package/src/internal-urls/rule-protocol.ts +38 -0
  1391. package/src/internal-urls/skc-protocol.ts +83 -0
  1392. package/src/internal-urls/skill-protocol.ts +103 -0
  1393. package/src/internal-urls/types.ts +114 -0
  1394. package/src/lsp/client.ts +1012 -0
  1395. package/src/lsp/clients/biome-client.ts +202 -0
  1396. package/src/lsp/clients/index.ts +50 -0
  1397. package/src/lsp/clients/lsp-linter-client.ts +93 -0
  1398. package/src/lsp/clients/swiftlint-client.ts +120 -0
  1399. package/src/lsp/config.ts +492 -0
  1400. package/src/lsp/defaults.json +494 -0
  1401. package/src/lsp/edits.ts +166 -0
  1402. package/src/lsp/index.ts +2283 -0
  1403. package/src/lsp/lspmux.ts +257 -0
  1404. package/src/lsp/render.ts +692 -0
  1405. package/src/lsp/startup-events.ts +13 -0
  1406. package/src/lsp/types.ts +445 -0
  1407. package/src/lsp/utils.ts +678 -0
  1408. package/src/main.ts +1080 -0
  1409. package/src/memories/index.ts +1137 -0
  1410. package/src/memories/storage.ts +577 -0
  1411. package/src/memory-backend/index.ts +4 -0
  1412. package/src/memory-backend/local-backend.ts +38 -0
  1413. package/src/memory-backend/off-backend.ts +16 -0
  1414. package/src/memory-backend/resolve.ts +24 -0
  1415. package/src/memory-backend/types.ts +79 -0
  1416. package/src/modes/acp/acp-agent.ts +2203 -0
  1417. package/src/modes/acp/acp-client-bridge.ts +154 -0
  1418. package/src/modes/acp/acp-event-mapper.ts +911 -0
  1419. package/src/modes/acp/acp-mode.ts +23 -0
  1420. package/src/modes/acp/index.ts +2 -0
  1421. package/src/modes/acp/terminal-auth.ts +37 -0
  1422. package/src/modes/bridge/auth.ts +41 -0
  1423. package/src/modes/bridge/bridge-client-bridge.ts +47 -0
  1424. package/src/modes/bridge/bridge-mode.ts +664 -0
  1425. package/src/modes/bridge/bridge-ui-context.ts +200 -0
  1426. package/src/modes/bridge/event-stream.ts +70 -0
  1427. package/src/modes/components/agent-dashboard.ts +1120 -0
  1428. package/src/modes/components/assistant-message.ts +255 -0
  1429. package/src/modes/components/bash-execution.ts +232 -0
  1430. package/src/modes/components/bordered-loader.ts +41 -0
  1431. package/src/modes/components/branch-summary-message.ts +45 -0
  1432. package/src/modes/components/btw-panel.ts +104 -0
  1433. package/src/modes/components/compaction-summary-message.ts +51 -0
  1434. package/src/modes/components/countdown-timer.ts +75 -0
  1435. package/src/modes/components/custom-editor.ts +363 -0
  1436. package/src/modes/components/custom-message.ts +65 -0
  1437. package/src/modes/components/custom-model-preset-wizard.ts +293 -0
  1438. package/src/modes/components/custom-provider-wizard.ts +318 -0
  1439. package/src/modes/components/diff.ts +363 -0
  1440. package/src/modes/components/dynamic-border.ts +25 -0
  1441. package/src/modes/components/eval-execution.ts +168 -0
  1442. package/src/modes/components/execution-shared.ts +102 -0
  1443. package/src/modes/components/extensions/extension-dashboard.ts +350 -0
  1444. package/src/modes/components/extensions/extension-list.ts +492 -0
  1445. package/src/modes/components/extensions/index.ts +9 -0
  1446. package/src/modes/components/extensions/inspector-panel.ts +317 -0
  1447. package/src/modes/components/extensions/state-manager.ts +628 -0
  1448. package/src/modes/components/extensions/types.ts +191 -0
  1449. package/src/modes/components/footer.ts +270 -0
  1450. package/src/modes/components/history-search.ts +162 -0
  1451. package/src/modes/components/hook-editor.ts +151 -0
  1452. package/src/modes/components/hook-input.ts +79 -0
  1453. package/src/modes/components/hook-message.ts +68 -0
  1454. package/src/modes/components/hook-selector.ts +582 -0
  1455. package/src/modes/components/index.ts +36 -0
  1456. package/src/modes/components/jobs-overlay-model.ts +109 -0
  1457. package/src/modes/components/jobs-overlay.ts +172 -0
  1458. package/src/modes/components/keybinding-hints.ts +65 -0
  1459. package/src/modes/components/login-dialog.ts +164 -0
  1460. package/src/modes/components/message-frame.ts +88 -0
  1461. package/src/modes/components/model-selector.ts +1477 -0
  1462. package/src/modes/components/oauth-selector.ts +253 -0
  1463. package/src/modes/components/plugin-selector.ts +95 -0
  1464. package/src/modes/components/plugin-settings.ts +488 -0
  1465. package/src/modes/components/provider-onboarding-selector.ts +98 -0
  1466. package/src/modes/components/queue-mode-selector.ts +56 -0
  1467. package/src/modes/components/read-tool-group.ts +267 -0
  1468. package/src/modes/components/runtime-mcp-add-wizard.ts +1392 -0
  1469. package/src/modes/components/session-observer-overlay.ts +839 -0
  1470. package/src/modes/components/session-selector.ts +343 -0
  1471. package/src/modes/components/settings-defs.ts +175 -0
  1472. package/src/modes/components/settings-selector.ts +662 -0
  1473. package/src/modes/components/show-images-selector.ts +45 -0
  1474. package/src/modes/components/skill-hud/render.ts +83 -0
  1475. package/src/modes/components/skill-message.ts +152 -0
  1476. package/src/modes/components/status-line/context-thresholds.ts +68 -0
  1477. package/src/modes/components/status-line/git-utils.ts +42 -0
  1478. package/src/modes/components/status-line/index.ts +4 -0
  1479. package/src/modes/components/status-line/presets.ts +119 -0
  1480. package/src/modes/components/status-line/segments.ts +590 -0
  1481. package/src/modes/components/status-line/separators.ts +55 -0
  1482. package/src/modes/components/status-line/token-rate.ts +66 -0
  1483. package/src/modes/components/status-line/types.ts +92 -0
  1484. package/src/modes/components/status-line.ts +853 -0
  1485. package/src/modes/components/theme-selector.ts +63 -0
  1486. package/src/modes/components/thinking-selector.ts +52 -0
  1487. package/src/modes/components/todo-reminder.ts +40 -0
  1488. package/src/modes/components/tool-execution.ts +853 -0
  1489. package/src/modes/components/tree-selector.ts +930 -0
  1490. package/src/modes/components/ttsr-notification.ts +80 -0
  1491. package/src/modes/components/user-message-selector.ts +141 -0
  1492. package/src/modes/components/user-message.ts +51 -0
  1493. package/src/modes/components/visual-truncate.ts +63 -0
  1494. package/src/modes/components/welcome.ts +409 -0
  1495. package/src/modes/controllers/btw-controller.ts +105 -0
  1496. package/src/modes/controllers/command-controller-shared.ts +108 -0
  1497. package/src/modes/controllers/command-controller.ts +1672 -0
  1498. package/src/modes/controllers/event-controller.ts +852 -0
  1499. package/src/modes/controllers/extension-ui-controller.ts +1017 -0
  1500. package/src/modes/controllers/input-controller.ts +1047 -0
  1501. package/src/modes/controllers/runtime-mcp-command-controller.ts +1934 -0
  1502. package/src/modes/controllers/selector-controller.ts +1407 -0
  1503. package/src/modes/controllers/ssh-command-controller.ts +384 -0
  1504. package/src/modes/controllers/todo-command-controller.ts +485 -0
  1505. package/src/modes/data/emojis.json +1 -0
  1506. package/src/modes/emoji-autocomplete.ts +285 -0
  1507. package/src/modes/index.ts +35 -0
  1508. package/src/modes/interactive-mode.ts +2677 -0
  1509. package/src/modes/jobs-observer.ts +204 -0
  1510. package/src/modes/oauth-manual-input.ts +42 -0
  1511. package/src/modes/print-mode.ts +131 -0
  1512. package/src/modes/prompt-action-autocomplete.ts +409 -0
  1513. package/src/modes/rpc/host-tools.ts +1 -0
  1514. package/src/modes/rpc/host-uris.ts +1 -0
  1515. package/src/modes/rpc/rpc-client.ts +1085 -0
  1516. package/src/modes/rpc/rpc-mode.ts +808 -0
  1517. package/src/modes/rpc/rpc-socket-security.ts +103 -0
  1518. package/src/modes/rpc/rpc-types.ts +613 -0
  1519. package/src/modes/runtime-init.ts +116 -0
  1520. package/src/modes/session-observer-registry.ts +146 -0
  1521. package/src/modes/shared/agent-wire/approval-gate.ts +151 -0
  1522. package/src/modes/shared/agent-wire/command-contract.ts +18 -0
  1523. package/src/modes/shared/agent-wire/command-dispatch.ts +466 -0
  1524. package/src/modes/shared/agent-wire/command-validation.ts +167 -0
  1525. package/src/modes/shared/agent-wire/deep-interview-gate.ts +251 -0
  1526. package/src/modes/shared/agent-wire/event-contract.ts +147 -0
  1527. package/src/modes/shared/agent-wire/event-envelope.ts +140 -0
  1528. package/src/modes/shared/agent-wire/event-observation.ts +397 -0
  1529. package/src/modes/shared/agent-wire/handshake.ts +157 -0
  1530. package/src/modes/shared/agent-wire/host-tool-bridge.ts +197 -0
  1531. package/src/modes/shared/agent-wire/host-uri-bridge.ts +236 -0
  1532. package/src/modes/shared/agent-wire/protocol.ts +46 -0
  1533. package/src/modes/shared/agent-wire/responses.ts +17 -0
  1534. package/src/modes/shared/agent-wire/scopes.ts +92 -0
  1535. package/src/modes/shared/agent-wire/session-registry.ts +109 -0
  1536. package/src/modes/shared/agent-wire/ui-request-broker.ts +150 -0
  1537. package/src/modes/shared/agent-wire/ui-result.ts +48 -0
  1538. package/src/modes/shared/agent-wire/unattended-action-policy.ts +365 -0
  1539. package/src/modes/shared/agent-wire/unattended-audit.ts +175 -0
  1540. package/src/modes/shared/agent-wire/unattended-run-controller.ts +426 -0
  1541. package/src/modes/shared/agent-wire/unattended-session.ts +219 -0
  1542. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +324 -0
  1543. package/src/modes/shared/agent-wire/workflow-gate-schema.ts +331 -0
  1544. package/src/modes/shared.ts +55 -0
  1545. package/src/modes/theme/defaults/blue-octopus.json +126 -0
  1546. package/src/modes/theme/defaults/claude-code.json +100 -0
  1547. package/src/modes/theme/defaults/codex.json +100 -0
  1548. package/src/modes/theme/defaults/index.ts +13 -0
  1549. package/src/modes/theme/defaults/opencode.json +102 -0
  1550. package/src/modes/theme/defaults/red-octopus.json +123 -0
  1551. package/src/modes/theme/mermaid-cache.ts +29 -0
  1552. package/src/modes/theme/shimmer.ts +219 -0
  1553. package/src/modes/theme/theme-schema.json +429 -0
  1554. package/src/modes/theme/theme.ts +2452 -0
  1555. package/src/modes/types.ts +313 -0
  1556. package/src/modes/utils/abort-message.ts +41 -0
  1557. package/src/modes/utils/context-usage.ts +391 -0
  1558. package/src/modes/utils/hotkeys-markdown.ts +61 -0
  1559. package/src/modes/utils/keybinding-matchers.ts +30 -0
  1560. package/src/modes/utils/tools-markdown.ts +27 -0
  1561. package/src/modes/utils/ui-helpers.ts +749 -0
  1562. package/src/plan-mode/approved-plan.ts +163 -0
  1563. package/src/plan-mode/state.ts +6 -0
  1564. package/src/prompts/agents/architect.md +92 -0
  1565. package/src/prompts/agents/critic.md +65 -0
  1566. package/src/prompts/agents/executor.md +63 -0
  1567. package/src/prompts/agents/explore.md +58 -0
  1568. package/src/prompts/agents/frontmatter.md +14 -0
  1569. package/src/prompts/agents/init.md +34 -0
  1570. package/src/prompts/agents/plan.md +49 -0
  1571. package/src/prompts/agents/planner.md +60 -0
  1572. package/src/prompts/agents/reviewer.md +141 -0
  1573. package/src/prompts/agents/task.md +16 -0
  1574. package/src/prompts/ci-green-request.md +36 -0
  1575. package/src/prompts/goals/goal-continuation.md +26 -0
  1576. package/src/prompts/goals/goal-mode-active.md +22 -0
  1577. package/src/prompts/memories/consolidation.md +30 -0
  1578. package/src/prompts/memories/read-path.md +10 -0
  1579. package/src/prompts/memories/stage_one_input.md +6 -0
  1580. package/src/prompts/memories/stage_one_system.md +21 -0
  1581. package/src/prompts/memories/unavailable.md +9 -0
  1582. package/src/prompts/review-request.md +70 -0
  1583. package/src/prompts/system/agent-creation-architect.md +75 -0
  1584. package/src/prompts/system/agent-creation-user.md +6 -0
  1585. package/src/prompts/system/auto-continue.md +1 -0
  1586. package/src/prompts/system/btw-user.md +8 -0
  1587. package/src/prompts/system/commit-message-system.md +2 -0
  1588. package/src/prompts/system/custom-system-prompt.md +64 -0
  1589. package/src/prompts/system/eager-todo.md +13 -0
  1590. package/src/prompts/system/irc-incoming.md +8 -0
  1591. package/src/prompts/system/plan-mode-active.md +116 -0
  1592. package/src/prompts/system/plan-mode-approved.md +28 -0
  1593. package/src/prompts/system/plan-mode-compact-instructions.md +16 -0
  1594. package/src/prompts/system/plan-mode-reference.md +14 -0
  1595. package/src/prompts/system/plan-mode-subagent.md +34 -0
  1596. package/src/prompts/system/plan-mode-tool-decision-reminder.md +9 -0
  1597. package/src/prompts/system/project-prompt.md +46 -0
  1598. package/src/prompts/system/rlm-report-command.md +1 -0
  1599. package/src/prompts/system/rlm-research.md +23 -0
  1600. package/src/prompts/system/subagent-system-prompt.md +60 -0
  1601. package/src/prompts/system/subagent-user-prompt.md +3 -0
  1602. package/src/prompts/system/subagent-yield-reminder.md +12 -0
  1603. package/src/prompts/system/system-prompt.md +275 -0
  1604. package/src/prompts/system/title-system.md +2 -0
  1605. package/src/prompts/system/ttsr-interrupt.md +7 -0
  1606. package/src/prompts/system/ttsr-tool-reminder.md +5 -0
  1607. package/src/prompts/system/web-search.md +25 -0
  1608. package/src/prompts/tools/apply-patch.md +65 -0
  1609. package/src/prompts/tools/ask.md +29 -0
  1610. package/src/prompts/tools/ast-edit.md +39 -0
  1611. package/src/prompts/tools/ast-grep.md +42 -0
  1612. package/src/prompts/tools/async-result.md +8 -0
  1613. package/src/prompts/tools/bash.md +69 -0
  1614. package/src/prompts/tools/browser.md +75 -0
  1615. package/src/prompts/tools/calculator.md +10 -0
  1616. package/src/prompts/tools/checkpoint.md +16 -0
  1617. package/src/prompts/tools/computer.md +74 -0
  1618. package/src/prompts/tools/cron.md +25 -0
  1619. package/src/prompts/tools/debug.md +33 -0
  1620. package/src/prompts/tools/eval.md +75 -0
  1621. package/src/prompts/tools/find.md +34 -0
  1622. package/src/prompts/tools/github.md +20 -0
  1623. package/src/prompts/tools/goal.md +21 -0
  1624. package/src/prompts/tools/hashline.md +130 -0
  1625. package/src/prompts/tools/image-gen.md +7 -0
  1626. package/src/prompts/tools/inspect-image-system.md +20 -0
  1627. package/src/prompts/tools/inspect-image.md +32 -0
  1628. package/src/prompts/tools/irc.md +49 -0
  1629. package/src/prompts/tools/job.md +27 -0
  1630. package/src/prompts/tools/lsp.md +42 -0
  1631. package/src/prompts/tools/monitor.md +30 -0
  1632. package/src/prompts/tools/patch.md +70 -0
  1633. package/src/prompts/tools/read.md +82 -0
  1634. package/src/prompts/tools/recall.md +6 -0
  1635. package/src/prompts/tools/recipe.md +16 -0
  1636. package/src/prompts/tools/reflect.md +6 -0
  1637. package/src/prompts/tools/render-mermaid.md +9 -0
  1638. package/src/prompts/tools/replace.md +36 -0
  1639. package/src/prompts/tools/resolve.md +9 -0
  1640. package/src/prompts/tools/retain.md +7 -0
  1641. package/src/prompts/tools/rewind.md +13 -0
  1642. package/src/prompts/tools/search-tool-bm25.md +33 -0
  1643. package/src/prompts/tools/search.md +25 -0
  1644. package/src/prompts/tools/skill.md +28 -0
  1645. package/src/prompts/tools/ssh.md +35 -0
  1646. package/src/prompts/tools/subagent.md +56 -0
  1647. package/src/prompts/tools/task-summary.md +22 -0
  1648. package/src/prompts/tools/task.md +86 -0
  1649. package/src/prompts/tools/todo-write.md +50 -0
  1650. package/src/prompts/tools/vim.md +98 -0
  1651. package/src/prompts/tools/web-search.md +17 -0
  1652. package/src/prompts/tools/write.md +14 -0
  1653. package/src/registry/agent-registry.ts +140 -0
  1654. package/src/reminders/star-reminder.ts +420 -0
  1655. package/src/rlm/artifacts.ts +60 -0
  1656. package/src/rlm/complete-research-tool.ts +163 -0
  1657. package/src/rlm/data-context.ts +26 -0
  1658. package/src/rlm/index.ts +339 -0
  1659. package/src/rlm/notebook.ts +108 -0
  1660. package/src/rlm/preset.ts +76 -0
  1661. package/src/rlm/python-tool.ts +68 -0
  1662. package/src/rlm/report.ts +70 -0
  1663. package/src/rlm/types.ts +40 -0
  1664. package/src/runtime/process-lifecycle.ts +400 -0
  1665. package/src/runtime-mcp/client.ts +485 -0
  1666. package/src/runtime-mcp/config-writer.ts +225 -0
  1667. package/src/runtime-mcp/config.ts +365 -0
  1668. package/src/runtime-mcp/discoverable-tool-metadata.ts +25 -0
  1669. package/src/runtime-mcp/index.ts +29 -0
  1670. package/src/runtime-mcp/json-rpc.ts +84 -0
  1671. package/src/runtime-mcp/loader.ts +124 -0
  1672. package/src/runtime-mcp/manager.ts +1331 -0
  1673. package/src/runtime-mcp/oauth-discovery.ts +349 -0
  1674. package/src/runtime-mcp/oauth-flow.ts +409 -0
  1675. package/src/runtime-mcp/render.ts +123 -0
  1676. package/src/runtime-mcp/smithery-auth.ts +104 -0
  1677. package/src/runtime-mcp/smithery-connect.ts +145 -0
  1678. package/src/runtime-mcp/smithery-registry.ts +477 -0
  1679. package/src/runtime-mcp/tool-bridge.ts +416 -0
  1680. package/src/runtime-mcp/tool-cache.ts +117 -0
  1681. package/src/runtime-mcp/transports/http.ts +504 -0
  1682. package/src/runtime-mcp/transports/index.ts +6 -0
  1683. package/src/runtime-mcp/transports/stdio.ts +352 -0
  1684. package/src/runtime-mcp/types.ts +426 -0
  1685. package/src/sdk.ts +2290 -0
  1686. package/src/secrets/index.ts +116 -0
  1687. package/src/secrets/obfuscator.ts +352 -0
  1688. package/src/secrets/regex.ts +21 -0
  1689. package/src/session/agent-session.ts +10226 -0
  1690. package/src/session/agent-storage.ts +466 -0
  1691. package/src/session/artifacts.ts +150 -0
  1692. package/src/session/auth-broker-config.ts +102 -0
  1693. package/src/session/auth-storage.ts +23 -0
  1694. package/src/session/blob-store.ts +428 -0
  1695. package/src/session/client-bridge.ts +85 -0
  1696. package/src/session/contribution-prep.ts +320 -0
  1697. package/src/session/history-storage.ts +332 -0
  1698. package/src/session/messages.ts +406 -0
  1699. package/src/session/session-dump-format.ts +209 -0
  1700. package/src/session/session-manager.ts +4049 -0
  1701. package/src/session/session-storage.ts +415 -0
  1702. package/src/session/streaming-output.ts +1269 -0
  1703. package/src/session/tool-choice-queue.ts +236 -0
  1704. package/src/session/yield-queue.ts +155 -0
  1705. package/src/setup/credential-import.ts +429 -0
  1706. package/src/setup/hermes/templates/operator-instructions.v1.md +36 -0
  1707. package/src/setup/hermes-setup.ts +484 -0
  1708. package/src/setup/model-onboarding-guidance.ts +48 -0
  1709. package/src/setup/provider-onboarding.ts +358 -0
  1710. package/src/skc-runtime/cli-write-receipt.ts +31 -0
  1711. package/src/skc-runtime/deep-interview-recorder.ts +457 -0
  1712. package/src/skc-runtime/deep-interview-runtime.ts +639 -0
  1713. package/src/skc-runtime/deep-interview-state.ts +324 -0
  1714. package/src/skc-runtime/gc-render.ts +70 -0
  1715. package/src/skc-runtime/gc-runtime.ts +403 -0
  1716. package/src/skc-runtime/goal-mode-request.ts +223 -0
  1717. package/src/skc-runtime/launch-tmux.ts +423 -0
  1718. package/src/skc-runtime/launch-worktree.ts +302 -0
  1719. package/src/skc-runtime/ledger-event-renderer.ts +164 -0
  1720. package/src/skc-runtime/ralplan-runtime.ts +877 -0
  1721. package/src/skc-runtime/restricted-role-agent-bash.ts +5 -0
  1722. package/src/skc-runtime/session-state-sidecar.ts +177 -0
  1723. package/src/skc-runtime/state-graph.ts +86 -0
  1724. package/src/skc-runtime/state-migrations.ts +179 -0
  1725. package/src/skc-runtime/state-renderer.ts +354 -0
  1726. package/src/skc-runtime/state-runtime.ts +2023 -0
  1727. package/src/skc-runtime/state-schema.ts +192 -0
  1728. package/src/skc-runtime/state-validation.ts +49 -0
  1729. package/src/skc-runtime/state-writer.ts +1012 -0
  1730. package/src/skc-runtime/team-gc.ts +49 -0
  1731. package/src/skc-runtime/team-runtime.ts +4355 -0
  1732. package/src/skc-runtime/tmux-common.ts +172 -0
  1733. package/src/skc-runtime/tmux-gc.ts +239 -0
  1734. package/src/skc-runtime/tmux-sessions.ts +271 -0
  1735. package/src/skc-runtime/ultragoal-guard.ts +455 -0
  1736. package/src/skc-runtime/ultragoal-runtime.ts +3684 -0
  1737. package/src/skc-runtime/workflow-command-ref.ts +239 -0
  1738. package/src/skc-runtime/workflow-manifest.generated.json +1676 -0
  1739. package/src/skc-runtime/workflow-manifest.ts +454 -0
  1740. package/src/skill-state/active-state.ts +839 -0
  1741. package/src/skill-state/deep-interview-mutation-guard.ts +452 -0
  1742. package/src/skill-state/initial-phase.ts +19 -0
  1743. package/src/skill-state/workflow-hud.ts +274 -0
  1744. package/src/skill-state/workflow-state-contract.ts +150 -0
  1745. package/src/skill-state/workflow-state-version.ts +3 -0
  1746. package/src/slash-commands/acp-builtins.ts +55 -0
  1747. package/src/slash-commands/builtin-registry.ts +1206 -0
  1748. package/src/slash-commands/helpers/context-report.ts +149 -0
  1749. package/src/slash-commands/helpers/fast-status-report.ts +111 -0
  1750. package/src/slash-commands/helpers/format.ts +46 -0
  1751. package/src/slash-commands/helpers/mcp.ts +532 -0
  1752. package/src/slash-commands/helpers/parse.ts +85 -0
  1753. package/src/slash-commands/helpers/ssh.ts +195 -0
  1754. package/src/slash-commands/helpers/todo.ts +279 -0
  1755. package/src/slash-commands/helpers/usage-report.ts +91 -0
  1756. package/src/slash-commands/types.ts +125 -0
  1757. package/src/ssh/config-writer.ts +183 -0
  1758. package/src/ssh/connection-manager.ts +482 -0
  1759. package/src/ssh/ssh-executor.ts +133 -0
  1760. package/src/ssh/sshfs-mount.ts +140 -0
  1761. package/src/ssh/utils.ts +8 -0
  1762. package/src/stt/downloader.ts +71 -0
  1763. package/src/stt/index.ts +3 -0
  1764. package/src/stt/recorder.ts +351 -0
  1765. package/src/stt/setup.ts +52 -0
  1766. package/src/stt/stt-controller.ts +160 -0
  1767. package/src/stt/transcribe.py +70 -0
  1768. package/src/stt/transcriber.ts +91 -0
  1769. package/src/system-prompt.ts +581 -0
  1770. package/src/task/agents.ts +164 -0
  1771. package/src/task/commands.ts +131 -0
  1772. package/src/task/discovery.ts +136 -0
  1773. package/src/task/executor.ts +1733 -0
  1774. package/src/task/fork-context-advisory.ts +99 -0
  1775. package/src/task/id.ts +33 -0
  1776. package/src/task/index.ts +1788 -0
  1777. package/src/task/name-generator.ts +1577 -0
  1778. package/src/task/output-manager.ts +108 -0
  1779. package/src/task/parallel.ts +116 -0
  1780. package/src/task/receipt.ts +304 -0
  1781. package/src/task/render.ts +1101 -0
  1782. package/src/task/roi-reconciliation.ts +90 -0
  1783. package/src/task/simple-mode.ts +27 -0
  1784. package/src/task/skc-command.ts +26 -0
  1785. package/src/task/spawn-gate.ts +132 -0
  1786. package/src/task/subprocess-tool-registry.ts +88 -0
  1787. package/src/task/types.ts +431 -0
  1788. package/src/task/worktree.ts +506 -0
  1789. package/src/thinking-metadata.ts +51 -0
  1790. package/src/thinking.ts +73 -0
  1791. package/src/tool-discovery/tool-index.ts +400 -0
  1792. package/src/tools/archive-reader.ts +330 -0
  1793. package/src/tools/ask.ts +998 -0
  1794. package/src/tools/ast-edit.ts +550 -0
  1795. package/src/tools/ast-grep.ts +424 -0
  1796. package/src/tools/auto-generated-guard.ts +305 -0
  1797. package/src/tools/bash-allowed-prefixes.ts +252 -0
  1798. package/src/tools/bash-command-fixup.ts +37 -0
  1799. package/src/tools/bash-interactive.ts +388 -0
  1800. package/src/tools/bash-interceptor.ts +67 -0
  1801. package/src/tools/bash-pty-selection.ts +14 -0
  1802. package/src/tools/bash-skill-urls.ts +248 -0
  1803. package/src/tools/bash.ts +1302 -0
  1804. package/src/tools/browser/actions.ts +189 -0
  1805. package/src/tools/browser/attach.ts +275 -0
  1806. package/src/tools/browser/launch.ts +651 -0
  1807. package/src/tools/browser/readable.ts +95 -0
  1808. package/src/tools/browser/registry.ts +384 -0
  1809. package/src/tools/browser/render.ts +220 -0
  1810. package/src/tools/browser/tab-protocol.ts +105 -0
  1811. package/src/tools/browser/tab-supervisor.ts +599 -0
  1812. package/src/tools/browser/tab-worker-entry.ts +21 -0
  1813. package/src/tools/browser/tab-worker.ts +1054 -0
  1814. package/src/tools/browser.ts +458 -0
  1815. package/src/tools/calculator.ts +540 -0
  1816. package/src/tools/checkpoint.ts +134 -0
  1817. package/src/tools/computer/render.ts +78 -0
  1818. package/src/tools/computer.ts +640 -0
  1819. package/src/tools/conflict-detect.ts +672 -0
  1820. package/src/tools/context.ts +39 -0
  1821. package/src/tools/cron.ts +709 -0
  1822. package/src/tools/debug.ts +1014 -0
  1823. package/src/tools/eval.ts +1101 -0
  1824. package/src/tools/fetch.ts +1482 -0
  1825. package/src/tools/file-recorder.ts +35 -0
  1826. package/src/tools/find.ts +543 -0
  1827. package/src/tools/fs-cache-invalidation.ts +28 -0
  1828. package/src/tools/gh-format.ts +12 -0
  1829. package/src/tools/gh-renderer.ts +428 -0
  1830. package/src/tools/gh.ts +3737 -0
  1831. package/src/tools/github-cache.ts +548 -0
  1832. package/src/tools/grouped-file-output.ts +96 -0
  1833. package/src/tools/hindsight-recall.ts +66 -0
  1834. package/src/tools/hindsight-reflect.ts +55 -0
  1835. package/src/tools/hindsight-retain.ts +54 -0
  1836. package/src/tools/image-gen.ts +1284 -0
  1837. package/src/tools/index.ts +595 -0
  1838. package/src/tools/inspect-image-renderer.ts +103 -0
  1839. package/src/tools/inspect-image.ts +167 -0
  1840. package/src/tools/irc.ts +239 -0
  1841. package/src/tools/job.ts +614 -0
  1842. package/src/tools/json-tree.ts +256 -0
  1843. package/src/tools/jtd-to-json-schema.ts +219 -0
  1844. package/src/tools/jtd-to-typescript.ts +136 -0
  1845. package/src/tools/jtd-utils.ts +102 -0
  1846. package/src/tools/list-limit.ts +40 -0
  1847. package/src/tools/match-line-format.ts +22 -0
  1848. package/src/tools/monitor.ts +252 -0
  1849. package/src/tools/output-meta.ts +754 -0
  1850. package/src/tools/path-utils.ts +741 -0
  1851. package/src/tools/plan-mode-guard.ts +68 -0
  1852. package/src/tools/puppeteer/00_stealth_tampering.txt +63 -0
  1853. package/src/tools/puppeteer/01_stealth_activity.txt +20 -0
  1854. package/src/tools/puppeteer/02_stealth_hairline.txt +11 -0
  1855. package/src/tools/puppeteer/03_stealth_botd.txt +384 -0
  1856. package/src/tools/puppeteer/04_stealth_iframe.txt +81 -0
  1857. package/src/tools/puppeteer/05_stealth_webgl.txt +75 -0
  1858. package/src/tools/puppeteer/06_stealth_screen.txt +72 -0
  1859. package/src/tools/puppeteer/07_stealth_fonts.txt +97 -0
  1860. package/src/tools/puppeteer/08_stealth_audio.txt +51 -0
  1861. package/src/tools/puppeteer/09_stealth_locale.txt +46 -0
  1862. package/src/tools/puppeteer/10_stealth_plugins.txt +206 -0
  1863. package/src/tools/puppeteer/11_stealth_hardware.txt +8 -0
  1864. package/src/tools/puppeteer/12_stealth_codecs.txt +40 -0
  1865. package/src/tools/puppeteer/13_stealth_worker.txt +74 -0
  1866. package/src/tools/read.ts +2332 -0
  1867. package/src/tools/recipe/index.ts +80 -0
  1868. package/src/tools/recipe/render.ts +19 -0
  1869. package/src/tools/recipe/runner.ts +219 -0
  1870. package/src/tools/recipe/runners/cargo.ts +131 -0
  1871. package/src/tools/recipe/runners/index.ts +8 -0
  1872. package/src/tools/recipe/runners/just.ts +73 -0
  1873. package/src/tools/recipe/runners/make.ts +101 -0
  1874. package/src/tools/recipe/runners/pkg.ts +167 -0
  1875. package/src/tools/recipe/runners/task.ts +72 -0
  1876. package/src/tools/render-mermaid.ts +68 -0
  1877. package/src/tools/render-utils.ts +774 -0
  1878. package/src/tools/renderers.ts +79 -0
  1879. package/src/tools/resolve.ts +333 -0
  1880. package/src/tools/review.ts +252 -0
  1881. package/src/tools/search-tool-bm25.ts +360 -0
  1882. package/src/tools/search.ts +787 -0
  1883. package/src/tools/skill.ts +170 -0
  1884. package/src/tools/sqlite-reader.ts +750 -0
  1885. package/src/tools/ssh.ts +310 -0
  1886. package/src/tools/subagent-render.ts +268 -0
  1887. package/src/tools/subagent.ts +862 -0
  1888. package/src/tools/todo-write.ts +695 -0
  1889. package/src/tools/tool-errors.ts +62 -0
  1890. package/src/tools/tool-result.ts +86 -0
  1891. package/src/tools/tool-timeouts.ts +31 -0
  1892. package/src/tools/ultragoal-ask-guard.ts +39 -0
  1893. package/src/tools/vim.ts +949 -0
  1894. package/src/tools/write.ts +953 -0
  1895. package/src/tools/yield.ts +268 -0
  1896. package/src/tui/code-cell.ts +201 -0
  1897. package/src/tui/file-list.ts +55 -0
  1898. package/src/tui/hyperlink.ts +126 -0
  1899. package/src/tui/index.ts +12 -0
  1900. package/src/tui/output-block.ts +150 -0
  1901. package/src/tui/status-line.ts +39 -0
  1902. package/src/tui/tree-list.ts +84 -0
  1903. package/src/tui/types.ts +15 -0
  1904. package/src/tui/utils.ts +103 -0
  1905. package/src/utils/changelog.ts +121 -0
  1906. package/src/utils/clipboard.ts +156 -0
  1907. package/src/utils/command-args.ts +76 -0
  1908. package/src/utils/commit-message-generator.ts +135 -0
  1909. package/src/utils/edit-mode.ts +42 -0
  1910. package/src/utils/event-bus.ts +33 -0
  1911. package/src/utils/external-editor.ts +65 -0
  1912. package/src/utils/file-display-mode.ts +45 -0
  1913. package/src/utils/file-mentions.ts +376 -0
  1914. package/src/utils/git.ts +1536 -0
  1915. package/src/utils/image-loading.ts +102 -0
  1916. package/src/utils/image-resize.ts +309 -0
  1917. package/src/utils/lang-from-path.ts +239 -0
  1918. package/src/utils/markit.ts +89 -0
  1919. package/src/utils/open.ts +20 -0
  1920. package/src/utils/session-color.ts +43 -0
  1921. package/src/utils/shell-snapshot.ts +187 -0
  1922. package/src/utils/sixel.ts +69 -0
  1923. package/src/utils/title-generator.ts +237 -0
  1924. package/src/utils/tool-choice.ts +62 -0
  1925. package/src/utils/tools-manager.ts +363 -0
  1926. package/src/vim/buffer.ts +309 -0
  1927. package/src/vim/commands.ts +382 -0
  1928. package/src/vim/engine.ts +2409 -0
  1929. package/src/vim/parser.ts +134 -0
  1930. package/src/vim/render.ts +252 -0
  1931. package/src/vim/types.ts +197 -0
  1932. package/src/web/kagi.ts +183 -0
  1933. package/src/web/parallel.ts +349 -0
  1934. package/src/web/scrapers/artifacthub.ts +207 -0
  1935. package/src/web/scrapers/arxiv.ts +83 -0
  1936. package/src/web/scrapers/aur.ts +162 -0
  1937. package/src/web/scrapers/biorxiv.ts +133 -0
  1938. package/src/web/scrapers/bluesky.ts +262 -0
  1939. package/src/web/scrapers/brew.ts +172 -0
  1940. package/src/web/scrapers/cheatsh.ts +68 -0
  1941. package/src/web/scrapers/chocolatey.ts +196 -0
  1942. package/src/web/scrapers/choosealicense.ts +95 -0
  1943. package/src/web/scrapers/cisa-kev.ts +87 -0
  1944. package/src/web/scrapers/clojars.ts +154 -0
  1945. package/src/web/scrapers/coingecko.ts +177 -0
  1946. package/src/web/scrapers/crates-io.ts +97 -0
  1947. package/src/web/scrapers/crossref.ts +136 -0
  1948. package/src/web/scrapers/devto.ts +147 -0
  1949. package/src/web/scrapers/discogs.ts +306 -0
  1950. package/src/web/scrapers/discourse.ts +197 -0
  1951. package/src/web/scrapers/dockerhub.ts +138 -0
  1952. package/src/web/scrapers/docs-rs.ts +653 -0
  1953. package/src/web/scrapers/fdroid.ts +134 -0
  1954. package/src/web/scrapers/firefox-addons.ts +191 -0
  1955. package/src/web/scrapers/flathub.ts +223 -0
  1956. package/src/web/scrapers/github-gist.ts +58 -0
  1957. package/src/web/scrapers/github.ts +452 -0
  1958. package/src/web/scrapers/gitlab.ts +401 -0
  1959. package/src/web/scrapers/go-pkg.ts +266 -0
  1960. package/src/web/scrapers/hackage.ts +140 -0
  1961. package/src/web/scrapers/hackernews.ts +189 -0
  1962. package/src/web/scrapers/hex.ts +105 -0
  1963. package/src/web/scrapers/huggingface.ts +321 -0
  1964. package/src/web/scrapers/iacr.ts +89 -0
  1965. package/src/web/scrapers/index.ts +252 -0
  1966. package/src/web/scrapers/jetbrains-marketplace.ts +159 -0
  1967. package/src/web/scrapers/lemmy.ts +203 -0
  1968. package/src/web/scrapers/lobsters.ts +175 -0
  1969. package/src/web/scrapers/mastodon.ts +292 -0
  1970. package/src/web/scrapers/maven.ts +138 -0
  1971. package/src/web/scrapers/mdn.ts +173 -0
  1972. package/src/web/scrapers/metacpan.ts +222 -0
  1973. package/src/web/scrapers/musicbrainz.ts +250 -0
  1974. package/src/web/scrapers/npm.ts +98 -0
  1975. package/src/web/scrapers/nuget.ts +183 -0
  1976. package/src/web/scrapers/nvd.ts +222 -0
  1977. package/src/web/scrapers/ollama.ts +239 -0
  1978. package/src/web/scrapers/open-vsx.ts +106 -0
  1979. package/src/web/scrapers/opencorporates.ts +292 -0
  1980. package/src/web/scrapers/openlibrary.ts +336 -0
  1981. package/src/web/scrapers/orcid.ts +286 -0
  1982. package/src/web/scrapers/osv.ts +176 -0
  1983. package/src/web/scrapers/packagist.ts +160 -0
  1984. package/src/web/scrapers/pub-dev.ts +143 -0
  1985. package/src/web/scrapers/pubmed.ts +211 -0
  1986. package/src/web/scrapers/pypi.ts +112 -0
  1987. package/src/web/scrapers/rawg.ts +110 -0
  1988. package/src/web/scrapers/readthedocs.ts +120 -0
  1989. package/src/web/scrapers/reddit.ts +95 -0
  1990. package/src/web/scrapers/repology.ts +251 -0
  1991. package/src/web/scrapers/rfc.ts +201 -0
  1992. package/src/web/scrapers/rubygems.ts +103 -0
  1993. package/src/web/scrapers/searchcode.ts +189 -0
  1994. package/src/web/scrapers/sec-edgar.ts +261 -0
  1995. package/src/web/scrapers/semantic-scholar.ts +171 -0
  1996. package/src/web/scrapers/snapcraft.ts +187 -0
  1997. package/src/web/scrapers/sourcegraph.ts +336 -0
  1998. package/src/web/scrapers/spdx.ts +108 -0
  1999. package/src/web/scrapers/spotify.ts +198 -0
  2000. package/src/web/scrapers/stackoverflow.ts +120 -0
  2001. package/src/web/scrapers/terraform.ts +277 -0
  2002. package/src/web/scrapers/tldr.ts +47 -0
  2003. package/src/web/scrapers/twitter.ts +93 -0
  2004. package/src/web/scrapers/types.ts +318 -0
  2005. package/src/web/scrapers/utils.ts +109 -0
  2006. package/src/web/scrapers/vimeo.ts +133 -0
  2007. package/src/web/scrapers/vscode-marketplace.ts +187 -0
  2008. package/src/web/scrapers/w3c.ts +156 -0
  2009. package/src/web/scrapers/wikidata.ts +344 -0
  2010. package/src/web/scrapers/wikipedia.ts +84 -0
  2011. package/src/web/scrapers/youtube.ts +319 -0
  2012. package/src/web/search/index.ts +326 -0
  2013. package/src/web/search/provider.ts +324 -0
  2014. package/src/web/search/providers/anthropic.ts +302 -0
  2015. package/src/web/search/providers/base.ts +94 -0
  2016. package/src/web/search/providers/brave.ts +149 -0
  2017. package/src/web/search/providers/codex.ts +557 -0
  2018. package/src/web/search/providers/duckduckgo.ts +279 -0
  2019. package/src/web/search/providers/exa.ts +197 -0
  2020. package/src/web/search/providers/gemini.ts +455 -0
  2021. package/src/web/search/providers/jina.ts +101 -0
  2022. package/src/web/search/providers/kagi.ts +75 -0
  2023. package/src/web/search/providers/kimi.ts +171 -0
  2024. package/src/web/search/providers/openai-compatible.ts +151 -0
  2025. package/src/web/search/providers/parallel.ts +210 -0
  2026. package/src/web/search/providers/perplexity.ts +575 -0
  2027. package/src/web/search/providers/searxng.ts +309 -0
  2028. package/src/web/search/providers/synthetic.ts +108 -0
  2029. package/src/web/search/providers/tavily.ts +173 -0
  2030. package/src/web/search/providers/utils.ts +128 -0
  2031. package/src/web/search/providers/xai.ts +511 -0
  2032. package/src/web/search/providers/zai.ts +320 -0
  2033. package/src/web/search/render.ts +306 -0
  2034. package/src/web/search/types.ts +473 -0
  2035. package/src/web/search/utils.ts +17 -0
  2036. package/src/workspace-tree.ts +286 -0
@@ -0,0 +1,4355 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import * as fs from "node:fs/promises";
3
+ import * as path from "node:path";
4
+ import type { WorkflowHudSummary } from "../skill-state/active-state";
5
+ import { buildTeamHudSummary as buildWorkflowTeamHudSummary } from "../skill-state/workflow-hud";
6
+ import { WORKFLOW_STATE_VERSION } from "../skill-state/workflow-state-contract";
7
+ import type { GcPidProbe, GcRecord } from "./gc-runtime";
8
+
9
+ import { applySkcTmuxProfile, SKC_TMUX_LAUNCHED_ENV } from "./launch-tmux";
10
+ import {
11
+ AlreadyExistsError,
12
+ appendJsonl as appendJsonlAudited,
13
+ appendText,
14
+ createJsonNoClobber,
15
+ deleteIfOwned,
16
+ removeFileAudited,
17
+ writeJsonAtomic,
18
+ writeReport,
19
+ writeWorkflowEnvelopeAtomic,
20
+ } from "./state-writer";
21
+ import {
22
+ buildSkcTmuxExactOptionTarget,
23
+ buildSkcTmuxUntaggedSessionHint,
24
+ resolveSkcTmuxCommand,
25
+ SKC_TMUX_PROFILE_OPTION,
26
+ SKC_TMUX_PROFILE_VALUE,
27
+ } from "./tmux-common";
28
+
29
+ export type SkcTeamPhase = "starting" | "running" | "awaiting_integration" | "complete" | "failed" | "cancelled";
30
+ export type SkcTeamTaskStatus = "pending" | "blocked" | "in_progress" | "completed" | "failed";
31
+ export type SkcWorkerStatusState = "idle" | "working" | "blocked" | "done" | "failed" | "draining" | "unknown";
32
+ export type SkcTeamWorkerLifecycleState =
33
+ | "starting"
34
+ | "ready"
35
+ | "working"
36
+ | "draining"
37
+ | "stopped"
38
+ | "failed"
39
+ | "unknown";
40
+ export type SkcTeamShutdownMode = "graceful" | "force" | "abort";
41
+
42
+ export const SKC_TEAM_DEFAULT_WORKERS = 3;
43
+ export const SKC_TEAM_MAX_WORKERS = 20;
44
+ const SKC_TEAM_WORKER_CLI_ENV = "SKC_TEAM_WORKER_CLI";
45
+ const SKC_TEAM_WORKER_CLI_MAP_ENV = "SKC_TEAM_WORKER_CLI_MAP";
46
+
47
+ export type SkcTeamWorkerCli = "skc";
48
+ type SkcTeamWorkerCliMode = "auto" | SkcTeamWorkerCli;
49
+
50
+ export interface SkcTeamLeader {
51
+ session_id: string;
52
+ pane_id: string;
53
+ cwd: string;
54
+ }
55
+
56
+ export interface SkcTeamWorker {
57
+ id: string;
58
+ name: string;
59
+ index: number;
60
+ agent_type: string;
61
+ role: string;
62
+ pane_id?: string;
63
+ status: "starting" | "idle" | "busy" | "stopped";
64
+ last_heartbeat: string;
65
+ assigned_tasks: string[];
66
+ worktree_repo_root?: string;
67
+ worktree_path?: string;
68
+ worktree_branch?: string | null;
69
+ worktree_detached?: boolean;
70
+ worktree_created?: boolean;
71
+ worktree_base_ref?: string;
72
+ team_state_root?: string;
73
+ }
74
+
75
+ export interface SkcTeamTaskClaim {
76
+ owner: string;
77
+ token: string;
78
+ leased_until: string;
79
+ }
80
+ export type SkcTeamTaskCompletionEvidenceKind = "command" | "inspection" | "artifact";
81
+ export type SkcTeamTaskCompletionEvidenceStatus = "passed" | "failed" | "not_run" | "verified" | "rejected";
82
+
83
+ export interface SkcTeamTaskCompletionEvidenceItem {
84
+ kind: SkcTeamTaskCompletionEvidenceKind;
85
+ status: SkcTeamTaskCompletionEvidenceStatus;
86
+ summary: string;
87
+ command?: string;
88
+ artifact?: string;
89
+ location?: string;
90
+ output?: string;
91
+ }
92
+
93
+ export interface SkcTeamTaskCompletionEvidence {
94
+ summary: string;
95
+ items: SkcTeamTaskCompletionEvidenceItem[];
96
+ files?: string[];
97
+ notes?: string;
98
+ recorded_by: string;
99
+ recorded_at: string;
100
+ }
101
+
102
+ export interface SkcTeamTask {
103
+ id: string;
104
+ subject: string;
105
+ description: string;
106
+ title: string;
107
+ objective: string;
108
+ status: SkcTeamTaskStatus;
109
+ assignee?: string;
110
+ owner?: string;
111
+ result?: string;
112
+ completion_evidence?: SkcTeamTaskCompletionEvidence;
113
+ error?: string;
114
+ blocked_by?: string[];
115
+ depends_on?: string[];
116
+ lane?: string;
117
+ required_role?: string;
118
+ allowed_roles?: string[];
119
+ version: number;
120
+ claim?: SkcTeamTaskClaim;
121
+ created_at: string;
122
+ updated_at: string;
123
+ completed_at?: string;
124
+ }
125
+
126
+ export type SkcTeamWorktreeMode =
127
+ | { enabled: false }
128
+ | { enabled: true; detached: true; name: null }
129
+ | { enabled: true; detached: false; name: string };
130
+
131
+ export interface SkcTeamConfig {
132
+ team_name: string;
133
+ display_name: string;
134
+ requested_name: string;
135
+ task: string;
136
+ agent_type: string;
137
+ worker_count: number;
138
+ max_workers: number;
139
+ state_root: string;
140
+ worker_command: string;
141
+ worker_cli_plan: SkcTeamWorkerCli[];
142
+ tmux_command: string;
143
+ tmux_session: string;
144
+ tmux_session_name: string;
145
+ tmux_target: string;
146
+ workspace_mode: "direct" | "worktree";
147
+ dry_run: boolean;
148
+ leader: SkcTeamLeader;
149
+ leader_cwd: string;
150
+ team_state_root: string;
151
+ workers: SkcTeamWorker[];
152
+ created_at: string;
153
+ updated_at: string;
154
+ }
155
+
156
+ export type SkcTeamIntegrationStatus =
157
+ | "idle"
158
+ | "integrated"
159
+ | "integration_failed"
160
+ | "merge_conflict"
161
+ | "cherry_pick_conflict"
162
+ | "rebase_conflict";
163
+
164
+ export interface SkcTeamWorkerIntegrationState {
165
+ last_seen_head?: string;
166
+ last_integrated_head?: string;
167
+ last_leader_head?: string;
168
+ last_rebased_leader_head?: string;
169
+ status?: SkcTeamIntegrationStatus;
170
+ conflict_commit?: string;
171
+ conflict_files?: string[];
172
+ updated_at?: string;
173
+ }
174
+
175
+ export interface SkcTeamMonitorSnapshot {
176
+ integration_by_worker: Record<string, SkcTeamWorkerIntegrationState>;
177
+ updated_at: string;
178
+ }
179
+ export interface SkcTeamWorkerLifecycle {
180
+ worker: string;
181
+ lifecycle_state: SkcTeamWorkerLifecycleState;
182
+ worker_status_state: SkcWorkerStatusState;
183
+ pane_id?: string;
184
+ pid?: number;
185
+ started_at?: string;
186
+ updated_at: string;
187
+ stopped_at?: string;
188
+ stop_reason?: string;
189
+ shutdown_request_id?: string;
190
+ shutdown_requested_at?: string;
191
+ shutdown_acknowledged_at?: string;
192
+ shutdown_ack_status?: string;
193
+ shutdown_mode?: SkcTeamShutdownMode;
194
+ }
195
+
196
+ export type SkcTeamNotificationDeliveryState =
197
+ | "pending"
198
+ | "sent"
199
+ | "queued"
200
+ | "deferred"
201
+ | "failed"
202
+ | "delivered"
203
+ | "acknowledged";
204
+
205
+ export type SkcTeamPaneAttemptResult = "sent" | "queued" | "deferred" | "failed";
206
+
207
+ export interface SkcTeamNotification {
208
+ id: string;
209
+ kind: "mailbox_message" | "worker_lifecycle" | "invalid_attempt";
210
+ team_name: string;
211
+ recipient: string;
212
+ source: { type: "message" | "task" | "worker" | "event"; id: string };
213
+ idempotency_key?: string;
214
+ delivery_state: SkcTeamNotificationDeliveryState;
215
+ pane_attempt_result?: SkcTeamPaneAttemptResult;
216
+ pane_attempt_reason?: string;
217
+ pane_attempt_at?: string;
218
+ created_at: string;
219
+ updated_at: string;
220
+ replay_count: number;
221
+ }
222
+
223
+ export interface SkcTeamNotificationSummary {
224
+ total: number;
225
+ replay_eligible: number;
226
+ by_state: Record<SkcTeamNotificationDeliveryState, number>;
227
+ }
228
+
229
+ export interface SkcTeamSnapshot {
230
+ team_name: string;
231
+ display_name: string;
232
+ phase: SkcTeamPhase;
233
+ state_dir: string;
234
+ tmux_session: string;
235
+ tmux_session_name: string;
236
+ tmux_target: string;
237
+ task_total: number;
238
+ task_counts: Record<SkcTeamTaskStatus, number>;
239
+ workers: SkcTeamWorker[];
240
+ integration_by_worker?: Record<string, SkcTeamWorkerIntegrationState>;
241
+ worker_lifecycle_by_id: Record<string, SkcTeamWorkerLifecycle>;
242
+ notification_summary: SkcTeamNotificationSummary;
243
+ updated_at: string;
244
+ }
245
+ export interface SkcTeamSnapshotOptions {
246
+ reconcileNotifications?: boolean;
247
+ }
248
+
249
+ export interface SkcTeamStartOptions {
250
+ workerCount: number;
251
+ agentType: string;
252
+ task: string;
253
+ teamName?: string;
254
+ worktreeMode?: SkcTeamWorktreeMode;
255
+ cwd?: string;
256
+ env?: NodeJS.ProcessEnv;
257
+ dryRun?: boolean;
258
+ }
259
+
260
+ export interface SkcTeamApiClaimResult {
261
+ ok: boolean;
262
+ task?: SkcTeamTask;
263
+ worker_id?: string;
264
+ claim_token?: string;
265
+ reason?: string;
266
+ }
267
+ export type SkcTeamLivenessRecoveryReason =
268
+ | "claim_expired"
269
+ | "stale_heartbeat"
270
+ | "missing_pane"
271
+ | "worker_lifecycle_failed"
272
+ | "worker_lifecycle_stopped";
273
+
274
+ export interface SkcTeamRecoveredClaim {
275
+ task_id: string;
276
+ worker: string;
277
+ reasons: SkcTeamLivenessRecoveryReason[];
278
+ }
279
+
280
+ export interface SkcTeamLivenessRecoveryResult {
281
+ recovered_claims: SkcTeamRecoveredClaim[];
282
+ stale_workers: Record<string, SkcTeamLivenessRecoveryReason[]>;
283
+ }
284
+
285
+ export interface SkcTeamMailboxMessage {
286
+ message_id: string;
287
+ from_worker: string;
288
+ to_worker: string;
289
+ body: string;
290
+ created_at: string;
291
+ delivered_at?: string;
292
+ notified_at?: string;
293
+ idempotency_key?: string;
294
+ }
295
+
296
+ function taskReceiptFields(teamName: string, task: SkcTeamTask): Record<string, unknown> {
297
+ return {
298
+ team_name: teamName,
299
+ task_id: task.id,
300
+ status: task.status,
301
+ owner: task.owner,
302
+ worker_id: task.claim?.owner ?? task.owner ?? task.assignee,
303
+ };
304
+ }
305
+
306
+ function mailboxMessageReceiptFields(teamName: string, message: SkcTeamMailboxMessage): Record<string, unknown> {
307
+ return {
308
+ team_name: teamName,
309
+ message_id: message.message_id,
310
+ from_worker: message.from_worker,
311
+ to_worker: message.to_worker,
312
+ delivered: Boolean(message.delivered_at),
313
+ notified: Boolean(message.notified_at),
314
+ delivered_at: message.delivered_at,
315
+ notified_at: message.notified_at,
316
+ };
317
+ }
318
+
319
+ function notificationReceiptFields(notification: SkcTeamNotification): Record<string, unknown> {
320
+ return {
321
+ team_name: notification.team_name,
322
+ notification_id: notification.id,
323
+ recipient: notification.recipient,
324
+ source_type: notification.source.type,
325
+ source_id: notification.source.id,
326
+ delivery_state: notification.delivery_state,
327
+ pane_attempt_result: notification.pane_attempt_result,
328
+ pane_attempt_reason: notification.pane_attempt_reason,
329
+ replay_count: notification.replay_count,
330
+ };
331
+ }
332
+
333
+ function notificationSummaryReceipt(
334
+ teamName: string,
335
+ result: { notifications: SkcTeamNotification[]; summary: SkcTeamNotificationSummary },
336
+ ): Record<string, unknown> {
337
+ return {
338
+ team_name: teamName,
339
+ notification_ids: result.notifications.map(notification => notification.id),
340
+ delivery_states: result.notifications.map(notification => notification.delivery_state),
341
+ summary: result.summary,
342
+ };
343
+ }
344
+
345
+ interface FsError {
346
+ code?: string;
347
+ }
348
+
349
+ function normalizeSkcTeamWorkerCliMode(
350
+ raw: string | undefined,
351
+ sourceEnv = SKC_TEAM_WORKER_CLI_ENV,
352
+ ): SkcTeamWorkerCliMode {
353
+ const normalized = String(raw ?? "auto")
354
+ .trim()
355
+ .toLowerCase();
356
+ if (normalized === "" || normalized === "auto") return "auto";
357
+ if (normalized === "skc") return "skc";
358
+ if (normalized === "codex" || normalized === "claude" || normalized === "gemini") {
359
+ throw new Error(`Unsupported ${sourceEnv} value "${raw}". SKC team launches SKC teammate sessions only.`);
360
+ }
361
+ throw new Error(`Invalid ${sourceEnv} value "${raw}". Expected: auto or skc`);
362
+ }
363
+
364
+ export function resolveSkcTeamWorkerCli(env: NodeJS.ProcessEnv = process.env): SkcTeamWorkerCli {
365
+ const mode = normalizeSkcTeamWorkerCliMode(env[SKC_TEAM_WORKER_CLI_ENV]);
366
+ return mode === "auto" ? "skc" : mode;
367
+ }
368
+
369
+ export function resolveSkcTeamWorkerCliPlan(
370
+ workerCount: number,
371
+ env: NodeJS.ProcessEnv = process.env,
372
+ ): SkcTeamWorkerCli[] {
373
+ if (!Number.isInteger(workerCount) || workerCount < 1) {
374
+ throw new Error(`workerCount must be >= 1 (got ${workerCount})`);
375
+ }
376
+ normalizeSkcTeamWorkerCliMode(env[SKC_TEAM_WORKER_CLI_ENV]);
377
+ const rawMap = String(env[SKC_TEAM_WORKER_CLI_MAP_ENV] ?? "").trim();
378
+ if (rawMap === "") {
379
+ const cli = resolveSkcTeamWorkerCli(env);
380
+ return Array.from({ length: workerCount }, () => cli);
381
+ }
382
+ const entries = rawMap.split(",").map(entry => entry.trim());
383
+ if (entries.length === 0 || entries.every(entry => entry.length === 0)) {
384
+ throw new Error(
385
+ `Invalid ${SKC_TEAM_WORKER_CLI_MAP_ENV} value "${env[SKC_TEAM_WORKER_CLI_MAP_ENV]}". Expected: auto or skc`,
386
+ );
387
+ }
388
+ if (entries.some(entry => entry.length === 0)) {
389
+ throw new Error(
390
+ `Invalid ${SKC_TEAM_WORKER_CLI_MAP_ENV} value "${env[SKC_TEAM_WORKER_CLI_MAP_ENV]}". Empty entries are not allowed.`,
391
+ );
392
+ }
393
+ if (entries.length !== 1 && entries.length !== workerCount) {
394
+ throw new Error(
395
+ `Invalid ${SKC_TEAM_WORKER_CLI_MAP_ENV} length ${entries.length}; expected 1 or ${workerCount} comma-separated values.`,
396
+ );
397
+ }
398
+ const expanded = entries.length === 1 ? Array.from({ length: workerCount }, () => entries[0] ?? "") : entries;
399
+ return expanded.map(entry => {
400
+ const mode = normalizeSkcTeamWorkerCliMode(entry, SKC_TEAM_WORKER_CLI_MAP_ENV);
401
+ return mode === "auto" ? "skc" : mode;
402
+ });
403
+ }
404
+
405
+ export function translateSkcWorkerLaunchArgsForCli(workerCli: SkcTeamWorkerCli, args: string[]): string[] {
406
+ if (workerCli !== "skc") {
407
+ throw new Error(`Unsupported team worker CLI "${workerCli}". SKC team launches SKC teammate sessions only.`);
408
+ }
409
+ return [...args];
410
+ }
411
+
412
+ interface SkcTmuxLeaderContext {
413
+ sessionName: string;
414
+ windowIndex: string;
415
+ leaderPaneId: string;
416
+ target: string;
417
+ }
418
+ export interface SkcTeamEvent {
419
+ event_id: string;
420
+ ts: string;
421
+ type: string;
422
+ worker?: string;
423
+ task_id?: string;
424
+ message?: string;
425
+ data?: Record<string, unknown>;
426
+ }
427
+ export interface SkcTeamTraceEvent {
428
+ schema_version: 1;
429
+ trace_id: string;
430
+ span_id: string;
431
+ source_event_id: string;
432
+ event_type: string;
433
+ ts: string;
434
+ worker?: string;
435
+ task_id?: string;
436
+ message?: string;
437
+ evidence_refs?: string[];
438
+ data?: Record<string, unknown>;
439
+ }
440
+ interface WorkerStatusFile {
441
+ state: SkcWorkerStatusState;
442
+ current_task_id?: string;
443
+ reason?: string;
444
+ updated_at: string;
445
+ }
446
+ interface WorkerHeartbeatFile {
447
+ pid: number;
448
+ last_turn_at: string;
449
+ turn_count: number;
450
+ alive: boolean;
451
+ }
452
+ interface GitResult {
453
+ ok: boolean;
454
+ stdout: string;
455
+ stderr: string;
456
+ }
457
+ interface SkcTeamCommitHygieneEntry {
458
+ recorded_at: string;
459
+ operation:
460
+ | "auto_checkpoint"
461
+ | "leader_integration_attempt"
462
+ | "integration_merge"
463
+ | "integration_cherry_pick"
464
+ | "cross_rebase";
465
+ worker_name: string;
466
+ task_id?: string;
467
+ status: "applied" | "skipped" | "conflict" | "failed";
468
+ operational_commit?: string | null;
469
+ source_commit?: string;
470
+ leader_head_before?: string;
471
+ leader_head_after?: string | null;
472
+ worker_head_before?: string | null;
473
+ worker_head_after?: string | null;
474
+ worktree_path?: string;
475
+ detail: string;
476
+ }
477
+
478
+ interface SkcWorkerIntegrationDedupeState {
479
+ last_requested_fingerprint?: string;
480
+ last_requested_head?: string | null;
481
+ last_requested_status?: SkcWorkerCheckpointClassification["kind"];
482
+ last_requested_at?: string;
483
+ }
484
+
485
+ export interface SkcWorkerIntegrationAttemptRequestResult {
486
+ requested: boolean;
487
+ reason: "requested" | "not_worker" | "missing_worktree" | "no_changes" | "deduped" | "git_error";
488
+ worker?: string;
489
+ team_name?: string;
490
+ fingerprint?: string;
491
+ head?: string | null;
492
+ status?: SkcWorkerCheckpointClassification["kind"];
493
+ }
494
+
495
+ function isSkcTeamTaskStatus(value: string): value is SkcTeamTaskStatus {
496
+ return ["pending", "blocked", "in_progress", "completed", "failed"].includes(value);
497
+ }
498
+
499
+ function parseSkcTeamTaskStatus(value: unknown, allowLegacyComplete = false): SkcTeamTaskStatus {
500
+ const raw = typeof value === "string" ? value.trim() : "";
501
+ if (allowLegacyComplete && raw === "complete") return "completed";
502
+ if (isSkcTeamTaskStatus(raw)) return raw;
503
+ throw new Error(`invalid_task_status:${raw}`);
504
+ }
505
+
506
+ export const SKC_TEAM_API_OPERATIONS = [
507
+ "send-message",
508
+ "broadcast",
509
+ "mailbox-list",
510
+ "mailbox-mark-delivered",
511
+ "mailbox-mark-notified",
512
+ "notification-list",
513
+ "notification-read",
514
+ "notification-replay",
515
+ "notification-mark-pane-attempt",
516
+ "worker-startup-ack",
517
+ "create-task",
518
+ "read-task",
519
+ "list-tasks",
520
+ "update-task",
521
+ "claim-task",
522
+ "transition-task-status",
523
+ "transition-task",
524
+ "release-task-claim",
525
+ "read-config",
526
+ "read-manifest",
527
+ "read-worker-status",
528
+ "update-worker-status",
529
+ "read-worker-heartbeat",
530
+ "recover-stale-claims",
531
+ "update-worker-heartbeat",
532
+ "write-worker-inbox",
533
+ "write-worker-identity",
534
+ "append-event",
535
+ "read-events",
536
+ "read-traces",
537
+ "await-event",
538
+ "write-shutdown-request",
539
+ "read-shutdown-ack",
540
+ "read-monitor-snapshot",
541
+ "write-monitor-snapshot",
542
+ "read-task-approval",
543
+ "write-task-approval",
544
+ ] as const;
545
+
546
+ function now(): string {
547
+ return new Date().toISOString();
548
+ }
549
+ function isEnoent(error: unknown): error is FsError {
550
+ return typeof error === "object" && error !== null && "code" in error && (error as FsError).code === "ENOENT";
551
+ }
552
+ function stateWriterOptions(filePath: string, category: "state" | "ledger" | "report" | "prune", verb: string) {
553
+ const resolved = path.resolve(filePath);
554
+ const marker = `${path.sep}.skc${path.sep}`;
555
+ const markerIndex = resolved.indexOf(marker);
556
+ const cwd = markerIndex >= 0 ? resolved.slice(0, markerIndex) : process.cwd();
557
+ return { cwd, audit: { category, verb, owner: "skc-runtime" as const } };
558
+ }
559
+
560
+ function sanitizeName(value: string): string {
561
+ const sanitized = value
562
+ .toLowerCase()
563
+ .replace(/[^a-z0-9]+/g, "-")
564
+ .replace(/-+/g, "-")
565
+ .replace(/^-|-$/g, "")
566
+ .slice(0, 40)
567
+ .replace(/-$/, "");
568
+ return sanitized || "team";
569
+ }
570
+ function shortHash(value: string): string {
571
+ return Bun.hash(value).toString(16).slice(0, 8).padStart(8, "0");
572
+ }
573
+
574
+ function stableHash(value: string): string {
575
+ return createHash("sha256").update(value).digest("hex").slice(0, 24);
576
+ }
577
+ function makeTeamName(task: string, env: NodeJS.ProcessEnv): string {
578
+ const basis = [task, env.SKC_SESSION_ID, env.CODEX_SESSION_ID, env.TMUX_PANE, env.TMUX, now()]
579
+ .filter(Boolean)
580
+ .join(":");
581
+ const prefix = sanitizeName(task).slice(0, 30).replace(/-$/, "") || "team";
582
+ return `${prefix}-${shortHash(basis)}`;
583
+ }
584
+ function teamDir(stateRoot: string, teamName: string): string {
585
+ return path.join(stateRoot, sanitizeName(teamName));
586
+ }
587
+ function shellQuote(value: string): string {
588
+ return `'${value.replace(/'/g, "'\\''")}'`;
589
+ }
590
+ function safePathSegment(kind: string, value: string): string {
591
+ assertSafeId(kind, value);
592
+ return value;
593
+ }
594
+ function taskPath(dir: string, taskId: string): string {
595
+ return path.join(dir, "tasks", `${safePathSegment("task_id", taskId)}.json`);
596
+ }
597
+ function mailboxPath(dir: string, worker: string): string {
598
+ return path.join(dir, "mailbox", `${safePathSegment("worker_id", worker)}.json`);
599
+ }
600
+ function mailboxDirPath(dir: string, worker: string): string {
601
+ return path.join(dir, "mailbox", safePathSegment("worker_id", worker));
602
+ }
603
+ function mailboxMessagePath(dir: string, worker: string, messageId: string): string {
604
+ return path.join(mailboxDirPath(dir, worker), `${safePathSegment("message_id", messageId)}.json`);
605
+ }
606
+ function notificationPath(dir: string, notificationId: string): string {
607
+ return path.join(dir, "notifications", `${safePathSegment("notification_id", notificationId)}.json`);
608
+ }
609
+ function workerDir(dir: string, worker: string): string {
610
+ return path.join(dir, "workers", safePathSegment("worker_id", worker));
611
+ }
612
+ function workerLifecyclePath(dir: string, worker: string): string {
613
+ return path.join(workerDir(dir, worker), "lifecycle.json");
614
+ }
615
+
616
+ function tracePath(dir: string): string {
617
+ return path.join(dir, "trace.jsonl");
618
+ }
619
+
620
+ function traceErrorPath(dir: string): string {
621
+ return path.join(dir, "trace-errors.jsonl");
622
+ }
623
+ function isSafeId(value: string): boolean {
624
+ return (
625
+ /^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/.test(value) &&
626
+ !value.includes("..") &&
627
+ !value.includes("/") &&
628
+ !value.includes("\\")
629
+ );
630
+ }
631
+ function assertSafeId(kind: string, value: string): void {
632
+ if (!isSafeId(value)) throw new Error(`invalid_${kind}:${value}`);
633
+ }
634
+ function isLeaderRecipient(value: string): boolean {
635
+ return value === "leader-fixed";
636
+ }
637
+ function assertKnownWorker(config: SkcTeamConfig, worker: string, allowLeader = false): void {
638
+ assertSafeId("worker_id", worker);
639
+ if (allowLeader && isLeaderRecipient(worker)) return;
640
+ if (!config.workers.some(candidate => candidate.id === worker)) throw new Error(`unknown_worker:${worker}`);
641
+ }
642
+ function findKnownWorker(config: SkcTeamConfig, worker: string): SkcTeamWorker {
643
+ assertKnownWorker(config, worker);
644
+ const found = config.workers.find(candidate => candidate.id === worker);
645
+ if (!found) throw new Error(`unknown_worker:${worker}`);
646
+ return found;
647
+ }
648
+ function assertKnownParticipant(config: SkcTeamConfig, worker: string): void {
649
+ assertKnownWorker(config, worker, true);
650
+ }
651
+ function messageNotificationId(teamName: string, recipient: string, messageId: string): string {
652
+ return `ntf-${stableHash(["mailbox_message", teamName, recipient, messageId].join(":"))}`;
653
+ }
654
+ function messageIdFor(input: {
655
+ teamName: string;
656
+ fromWorker: string;
657
+ toWorker: string;
658
+ body: string;
659
+ idempotencyKey?: string;
660
+ createdKey: string;
661
+ }): string {
662
+ return `msg-${stableHash([input.teamName, input.fromWorker, input.toWorker, input.idempotencyKey ?? input.body, input.createdKey].join(":"))}`;
663
+ }
664
+ function workerIntegrationDedupePath(dir: string, worker: string): string {
665
+ return path.join(workerDir(dir, worker), "posttooluse-dedupe.json");
666
+ }
667
+
668
+ export function resolveSkcTeamStateRoot(cwd = process.cwd(), env: NodeJS.ProcessEnv = process.env): string {
669
+ const explicit = env.SKC_TEAM_STATE_ROOT?.trim();
670
+ if (explicit) return path.resolve(cwd, explicit);
671
+ return path.join(cwd, ".skc", "state", "team");
672
+ }
673
+
674
+ async function readJsonFile<T>(filePath: string): Promise<T | null> {
675
+ try {
676
+ return (await Bun.file(filePath).json()) as T;
677
+ } catch (error) {
678
+ if (isEnoent(error)) return null;
679
+ throw error;
680
+ }
681
+ }
682
+ function isPositivePid(value: unknown): value is number {
683
+ return typeof value === "number" && Number.isInteger(value) && value > 0;
684
+ }
685
+
686
+ function collectTeamGcWorkerPids(
687
+ heartbeat: WorkerHeartbeatFile | null,
688
+ lifecycle: SkcTeamWorkerLifecycle | null,
689
+ ): number[] {
690
+ const pids: number[] = [];
691
+ if (isPositivePid(heartbeat?.pid)) pids.push(heartbeat.pid);
692
+ if (isPositivePid(lifecycle?.pid) && !pids.includes(lifecycle.pid)) pids.push(lifecycle.pid);
693
+ return pids;
694
+ }
695
+
696
+ interface TeamGcPidClassification {
697
+ removable: boolean;
698
+ pidStatus: "dead" | "alive" | "eperm" | "unknown" | "none";
699
+ pid?: number;
700
+ }
701
+
702
+ /**
703
+ * Liveness-only, fail-closed: a worker is removable ONLY when it has at least
704
+ * one authoritative pid and EVERY candidate pid probes dead (ESRCH). Any alive,
705
+ * EPERM, or unknown candidate (heartbeat OR lifecycle) keeps the worker, so a
706
+ * dead heartbeat pid can never override a live lifecycle pid.
707
+ */
708
+ function classifyTeamGcWorkerPids(pids: number[], probe: GcPidProbe): TeamGcPidClassification {
709
+ if (pids.length === 0) return { removable: false, pidStatus: "none" };
710
+ const statuses = pids.map(pid => ({ pid, status: gcProbeStatus(probe, pid) }));
711
+ const kept = statuses.find(entry => entry.status !== "dead");
712
+ if (kept) return { removable: false, pidStatus: kept.status, pid: kept.pid };
713
+ return { removable: true, pidStatus: "dead", pid: statuses[0]?.pid };
714
+ }
715
+
716
+ function gcProbeStatus(probe: GcPidProbe, pid: number): "dead" | "alive" | "eperm" | "unknown" {
717
+ const result = probe(pid);
718
+ if (result.status === "dead") return "dead";
719
+ return result.reason ?? "unknown";
720
+ }
721
+
722
+ function teamGcRecordDetail(heartbeat: WorkerHeartbeatFile | null, lifecycle: SkcTeamWorkerLifecycle | null): string {
723
+ return [
724
+ `heartbeat=${heartbeat ? "present" : "missing"}`,
725
+ ...(heartbeat ? [`heartbeat_alive=${heartbeat.alive}`, `last_turn_at=${heartbeat.last_turn_at}`] : []),
726
+ `lifecycle=${lifecycle?.lifecycle_state ?? "missing"}`,
727
+ ...(lifecycle?.pane_id ? [`pane_id=${lifecycle.pane_id}`] : []),
728
+ ...(lifecycle?.stop_reason ? [`stop_reason=${lifecycle.stop_reason}`] : []),
729
+ ].join(" ");
730
+ }
731
+
732
+ /** @internal */
733
+ export async function listTeamWorkerGcRecords(teamRoot: string, probe: GcPidProbe): Promise<GcRecord[]> {
734
+ const teamEntries = await fs.readdir(teamRoot, { withFileTypes: true });
735
+ const records: GcRecord[] = [];
736
+ for (const teamEntry of teamEntries) {
737
+ if (!teamEntry.isDirectory()) continue;
738
+ const teamName = teamEntry.name;
739
+ const teamDirPath = path.join(teamRoot, teamName);
740
+ let workerEntries: import("node:fs").Dirent[];
741
+ try {
742
+ workerEntries = await fs.readdir(path.join(teamDirPath, "workers"), { withFileTypes: true });
743
+ } catch (error) {
744
+ if (isEnoent(error)) continue;
745
+ throw error;
746
+ }
747
+
748
+ for (const workerEntry of workerEntries) {
749
+ if (!workerEntry.isDirectory()) continue;
750
+ const workerId = workerEntry.name;
751
+ const dir = path.join(teamDirPath, "workers", workerId);
752
+ let heartbeat: WorkerHeartbeatFile | null = null;
753
+ let lifecycle: SkcTeamWorkerLifecycle | null = null;
754
+ try {
755
+ heartbeat = await readJsonFile<WorkerHeartbeatFile>(path.join(dir, "heartbeat.json"));
756
+ lifecycle = await readJsonFile<SkcTeamWorkerLifecycle>(path.join(dir, "lifecycle.json"));
757
+ } catch (error) {
758
+ records.push({
759
+ store: "team_workers",
760
+ id: `${teamName}/${workerId}`,
761
+ root: teamRoot,
762
+ path: dir,
763
+ pid_status: "none",
764
+ status: "malformed",
765
+ stale: false,
766
+ removable: false,
767
+ action: "none",
768
+ reason: "worker_state_malformed_kept",
769
+ error: error instanceof Error ? error.message : String(error),
770
+ });
771
+ continue;
772
+ }
773
+ const pids = collectTeamGcWorkerPids(heartbeat, lifecycle);
774
+ const { removable, pidStatus, pid } = classifyTeamGcWorkerPids(pids, probe);
775
+ const terminalLifecycle = lifecycle?.lifecycle_state === "failed" || lifecycle?.lifecycle_state === "stopped";
776
+ const status = removable
777
+ ? "dead"
778
+ : pidStatus === "none" && terminalLifecycle
779
+ ? "terminal_lifecycle"
780
+ : pidStatus === "none"
781
+ ? "no_pid"
782
+ : pidStatus;
783
+ records.push({
784
+ store: "team_workers",
785
+ id: `${teamName}/${workerId}`,
786
+ root: teamRoot,
787
+ path: dir,
788
+ pid,
789
+ pid_status: pidStatus,
790
+ status,
791
+ stale: removable,
792
+ removable,
793
+ action: "none",
794
+ reason: removable
795
+ ? "worker_all_pids_dead"
796
+ : pidStatus === "none" && terminalLifecycle
797
+ ? "terminal_lifecycle_without_pid_kept"
798
+ : pidStatus === "none"
799
+ ? "worker_pid_missing_kept"
800
+ : `worker_pid_${pidStatus}_kept`,
801
+ detail: teamGcRecordDetail(heartbeat, lifecycle),
802
+ });
803
+ }
804
+ }
805
+ return records;
806
+ }
807
+
808
+ /** @internal */
809
+ export async function pruneTeamWorkerGcRecord(record: GcRecord, probe: GcPidProbe): Promise<boolean> {
810
+ if (!record.path || !record.id.includes("/")) return false;
811
+ const [teamName, workerId] = record.id.split("/", 2);
812
+ if (!teamName || !workerId) return false;
813
+ const teamDirPath = path.dirname(path.dirname(record.path));
814
+ const heartbeat = await readJsonFile<WorkerHeartbeatFile>(path.join(record.path, "heartbeat.json"));
815
+ const lifecycle = await readJsonFile<SkcTeamWorkerLifecycle>(path.join(record.path, "lifecycle.json"));
816
+ const pids = collectTeamGcWorkerPids(heartbeat, lifecycle);
817
+ if (!classifyTeamGcWorkerPids(pids, probe).removable) return false;
818
+
819
+ const claimDir = path.join(teamDirPath, "claims");
820
+ try {
821
+ for (const entry of await fs.readdir(claimDir, { withFileTypes: true })) {
822
+ if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
823
+ const claimPath = path.join(claimDir, entry.name);
824
+ const claim = readClaimRecord(await readJsonFile<unknown>(claimPath));
825
+ if (claim?.owner !== workerId) continue;
826
+ await removeFileAudited(claimPath, stateWriterOptions(claimPath, "prune", "gc-team-worker"));
827
+ }
828
+ } catch (error) {
829
+ if (!isEnoent(error)) throw error;
830
+ }
831
+
832
+ for (const task of await readTasks(teamDirPath)) {
833
+ if (task.claim?.owner !== workerId && task.assignee !== workerId) continue;
834
+ if (task.status === "completed" || task.status === "failed") continue;
835
+ await writeTask(teamDirPath, {
836
+ ...task,
837
+ status: "pending",
838
+ assignee: undefined,
839
+ claim: undefined,
840
+ version: task.version + 1,
841
+ updated_at: now(),
842
+ });
843
+ }
844
+
845
+ // Remove the stale worker record dir itself so a removable record always
846
+ // results in an observable removal, even when it owns no claims/tasks.
847
+ await fs.rm(record.path, { recursive: true, force: true });
848
+ return true;
849
+ }
850
+ function stateCategoryForJsonPath(filePath: string): "state" | "ledger" {
851
+ return filePath.endsWith(".jsonl") || filePath.includes(`${path.sep}telemetry${path.sep}`) ? "ledger" : "state";
852
+ }
853
+
854
+ async function writeJsonFile(filePath: string, value: unknown): Promise<void> {
855
+ await writeJsonAtomic(filePath, value, stateWriterOptions(filePath, stateCategoryForJsonPath(filePath), "write"));
856
+ }
857
+ async function writeJsonFileNoClobber(filePath: string, value: unknown): Promise<boolean> {
858
+ try {
859
+ await createJsonNoClobber(
860
+ filePath,
861
+ value,
862
+ stateWriterOptions(filePath, stateCategoryForJsonPath(filePath), "create"),
863
+ );
864
+ return true;
865
+ } catch (error) {
866
+ if (error instanceof AlreadyExistsError) return false;
867
+ throw error;
868
+ }
869
+ }
870
+ async function appendJsonl(filePath: string, value: unknown): Promise<void> {
871
+ await appendJsonlAudited(filePath, value, stateWriterOptions(filePath, "ledger", "append"));
872
+ }
873
+ function traceIdForTeam(dir: string): string {
874
+ return `trace-${stableHash(path.basename(dir))}`;
875
+ }
876
+
877
+ function evidenceRefsForEvent(event: SkcTeamEvent): string[] | undefined {
878
+ const refs: string[] = [];
879
+ if (event.task_id && event.type === "task_transitioned" && event.data && "completion_evidence" in event.data)
880
+ refs.push(`task:${event.task_id}:completion_evidence`);
881
+ if (event.task_id && event.type === "task_claim_recovered") refs.push(`task:${event.task_id}:claim_recovery`);
882
+ if (event.worker && event.type.startsWith("worker_")) refs.push(`worker:${event.worker}`);
883
+ return refs.length > 0 ? refs : undefined;
884
+ }
885
+ function pickString(value: unknown): string | undefined {
886
+ return typeof value === "string" ? value : undefined;
887
+ }
888
+ function pickNumber(value: unknown): number | undefined {
889
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
890
+ }
891
+ function pickBoolean(value: unknown): boolean | undefined {
892
+ return typeof value === "boolean" ? value : undefined;
893
+ }
894
+ function pickStringArray(value: unknown): string[] | undefined {
895
+ return Array.isArray(value) && value.every(item => typeof item === "string") ? value : undefined;
896
+ }
897
+ function setIfDefined(record: Record<string, unknown>, key: string, value: unknown): void {
898
+ if (value !== undefined) record[key] = value;
899
+ }
900
+ function messageBodyTraceProjection(body: string | undefined): Record<string, unknown> {
901
+ if (body === undefined) return {};
902
+ return {
903
+ body_byte_length: Buffer.byteLength(body, "utf8"),
904
+ body_sha256: createHash("sha256").update(body).digest("hex"),
905
+ };
906
+ }
907
+ function traceDataForEvent(event: SkcTeamEvent): Record<string, unknown> | undefined {
908
+ const source = event.data ?? {};
909
+ const data: Record<string, unknown> = {};
910
+ switch (event.type) {
911
+ case "message_sent": {
912
+ setIfDefined(data, "to_worker", pickString(source.to_worker));
913
+ setIfDefined(data, "message_id", pickString(source.message_id));
914
+ Object.assign(data, messageBodyTraceProjection(pickString(event.message)));
915
+ break;
916
+ }
917
+ case "message_acknowledged":
918
+ case "message_notified": {
919
+ setIfDefined(data, "message_id", pickString(event.message));
920
+ break;
921
+ }
922
+ case "team_started": {
923
+ setIfDefined(data, "worker_count", pickNumber(source.worker_count));
924
+ setIfDefined(data, "agent_type", pickString(source.agent_type));
925
+ setIfDefined(data, "workspace_mode", pickString(source.workspace_mode));
926
+ setIfDefined(data, "dry_run", pickBoolean(source.dry_run));
927
+ break;
928
+ }
929
+ case "task_claim_recovered": {
930
+ setIfDefined(data, "reasons", pickStringArray(source.reasons));
931
+ break;
932
+ }
933
+ case "task_transitioned": {
934
+ setIfDefined(data, "status", pickString(source.status));
935
+ const evidence = source.completion_evidence;
936
+ if (typeof evidence === "object" && evidence !== null) {
937
+ const evidenceRecord = evidence as Record<string, unknown>;
938
+ data.completion_evidence = {
939
+ recorded_by: pickString(evidenceRecord.recorded_by),
940
+ item_count: pickNumber(evidenceRecord.item_count),
941
+ verified_item_count: pickNumber(evidenceRecord.verified_item_count),
942
+ };
943
+ }
944
+ break;
945
+ }
946
+ case "worker_integration_attempt_requested": {
947
+ setIfDefined(data, "worker_name", pickString(source.worker_name));
948
+ setIfDefined(data, "worker_head", pickString(source.worker_head));
949
+ setIfDefined(data, "status", pickString(source.status));
950
+ if (Array.isArray(source.files)) data.file_count = source.files.length;
951
+ break;
952
+ }
953
+ case "worker_lifecycle_nudge": {
954
+ setIfDefined(data, "condition", pickString(source.condition));
955
+ setIfDefined(data, "severity", pickString(source.severity));
956
+ setIfDefined(data, "fingerprint", pickString(source.fingerprint));
957
+ setIfDefined(data, "auto_action_taken", pickBoolean(source.auto_action_taken));
958
+ break;
959
+ }
960
+ case "team_shutdown": {
961
+ setIfDefined(data, "phase", pickString(source.phase));
962
+ setIfDefined(data, "shutdown_request_id", pickString(source.shutdown_request_id));
963
+ setIfDefined(data, "graceful_shutdown_complete", pickBoolean(source.graceful_shutdown_complete));
964
+ if (Array.isArray(source.evidence_failures)) data.evidence_failure_count = source.evidence_failures.length;
965
+ break;
966
+ }
967
+ case "worker_status_updated": {
968
+ setIfDefined(data, "status", pickString(source.status));
969
+ setIfDefined(data, "current_task_id", pickString(source.current_task_id));
970
+ break;
971
+ }
972
+ case "worker_shutdown_requested": {
973
+ setIfDefined(data, "requested_by", pickString(source.requested_by));
974
+ setIfDefined(data, "request_id", pickString(source.request_id));
975
+ setIfDefined(data, "mode", pickString(source.mode));
976
+ break;
977
+ }
978
+ }
979
+ return Object.keys(data).length > 0 ? data : undefined;
980
+ }
981
+
982
+ async function appendTraceForEvent(dir: string, event: SkcTeamEvent): Promise<void> {
983
+ const evidenceRefs = evidenceRefsForEvent(event);
984
+ const traceData = traceDataForEvent(event);
985
+ const trace: SkcTeamTraceEvent = {
986
+ schema_version: 1,
987
+ trace_id: traceIdForTeam(dir),
988
+ span_id: `span-${stableHash(event.event_id)}`,
989
+ source_event_id: event.event_id,
990
+ event_type: event.type,
991
+ ts: event.ts,
992
+ ...(event.worker ? { worker: event.worker } : {}),
993
+ ...(event.task_id ? { task_id: event.task_id } : {}),
994
+ ...(traceData ? { data: traceData } : {}),
995
+ ...(evidenceRefs ? { evidence_refs: evidenceRefs } : {}),
996
+ };
997
+ try {
998
+ await appendJsonl(tracePath(dir), trace);
999
+ } catch (error) {
1000
+ try {
1001
+ await appendJsonl(traceErrorPath(dir), {
1002
+ ts: now(),
1003
+ source_event_id: event.event_id,
1004
+ error: error instanceof Error ? error.message : String(error),
1005
+ });
1006
+ } catch {
1007
+ // Trace append failure must not break legacy events.jsonl compatibility.
1008
+ }
1009
+ }
1010
+ }
1011
+ async function appendEvent(dir: string, event: Omit<SkcTeamEvent, "ts" | "event_id">): Promise<SkcTeamEvent> {
1012
+ const full = { event_id: `evt-${Date.now()}-${Math.random().toString(16).slice(2)}`, ts: now(), ...event };
1013
+ await appendJsonl(path.join(dir, "events.jsonl"), full);
1014
+ await appendTraceForEvent(dir, full);
1015
+ return full;
1016
+ }
1017
+ async function appendTelemetry(
1018
+ dir: string,
1019
+ event: { type: string; message: string; data?: Record<string, unknown> },
1020
+ ): Promise<void> {
1021
+ await appendJsonl(path.join(dir, "telemetry.jsonl"), { ts: now(), ...event });
1022
+ }
1023
+ async function readConfig(dir: string): Promise<SkcTeamConfig> {
1024
+ const config = await readJsonFile<SkcTeamConfig>(path.join(dir, "config.json"));
1025
+ if (!config) throw new Error(`team_config_not_found:${dir}`);
1026
+ const tmuxSessionName = config.tmux_session_name ?? config.tmux_session?.split(":")[0] ?? "";
1027
+ return {
1028
+ ...config,
1029
+ max_workers: config.max_workers ?? SKC_TEAM_MAX_WORKERS,
1030
+ tmux_command: config.tmux_command ?? resolveSkcTmuxCommand(),
1031
+ tmux_session: tmuxSessionName,
1032
+ tmux_session_name: tmuxSessionName,
1033
+ tmux_target: config.tmux_target ?? config.tmux_session ?? tmuxSessionName,
1034
+ dry_run: config.dry_run ?? config.tmux_session_name === "dry-run",
1035
+ leader_cwd: config.leader_cwd ?? config.leader.cwd,
1036
+ team_state_root: config.team_state_root ?? config.state_root,
1037
+ worker_cli_plan: config.worker_cli_plan ?? Array.from({ length: config.worker_count }, () => "skc"),
1038
+ };
1039
+ }
1040
+ async function readPhase(dir: string): Promise<SkcTeamPhase> {
1041
+ const phase = await readJsonFile<{ current_phase?: SkcTeamPhase }>(path.join(dir, "phase.json"));
1042
+ return phase?.current_phase ?? "running";
1043
+ }
1044
+ async function writePhase(dir: string, phase: SkcTeamPhase): Promise<void> {
1045
+ await writeJsonFile(path.join(dir, "phase.json"), { current_phase: phase, updated_at: now() });
1046
+ }
1047
+ function isSkcWorkerStatusState(value: string): value is SkcWorkerStatusState {
1048
+ return ["idle", "working", "blocked", "done", "failed", "draining", "unknown"].includes(value);
1049
+ }
1050
+
1051
+ function parseSkcWorkerStatusState(value: unknown): SkcWorkerStatusState {
1052
+ return typeof value === "string" && isSkcWorkerStatusState(value) ? value : "unknown";
1053
+ }
1054
+ function parseRequiredSkcWorkerStatusState(value: unknown): SkcWorkerStatusState {
1055
+ const raw = typeof value === "string" ? value.trim() : "";
1056
+ if (isSkcWorkerStatusState(raw)) return raw;
1057
+ throw new Error(`invalid_worker_status:${raw}`);
1058
+ }
1059
+
1060
+ function lifecycleStateForWorkerStatus(status: SkcWorkerStatusState): SkcTeamWorkerLifecycleState {
1061
+ switch (status) {
1062
+ case "working":
1063
+ return "working";
1064
+ case "draining":
1065
+ return "draining";
1066
+ case "failed":
1067
+ return "failed";
1068
+ case "unknown":
1069
+ return "unknown";
1070
+ case "idle":
1071
+ case "blocked":
1072
+ case "done":
1073
+ return "ready";
1074
+ }
1075
+ }
1076
+
1077
+ function parseSkcTeamShutdownMode(value: unknown): SkcTeamShutdownMode {
1078
+ const raw = typeof value === "string" ? value.trim() : "graceful";
1079
+ if (raw === "graceful" || raw === "force" || raw === "abort") return raw;
1080
+ throw new Error(`invalid_shutdown_mode:${raw}`);
1081
+ }
1082
+
1083
+ function isSkcTeamWorkerLifecycleState(value: string): value is SkcTeamWorkerLifecycleState {
1084
+ return ["starting", "ready", "working", "draining", "stopped", "failed", "unknown"].includes(value);
1085
+ }
1086
+
1087
+ function parseSkcTeamWorkerLifecycleState(value: unknown): SkcTeamWorkerLifecycleState {
1088
+ return typeof value === "string" && isSkcTeamWorkerLifecycleState(value) ? value : "unknown";
1089
+ }
1090
+
1091
+ async function readWorkerStatusFile(dir: string, worker: string): Promise<WorkerStatusFile> {
1092
+ return (
1093
+ (await readJsonFile<WorkerStatusFile>(path.join(workerDir(dir, worker), "status.json"))) ?? {
1094
+ state: "unknown",
1095
+ updated_at: now(),
1096
+ }
1097
+ );
1098
+ }
1099
+
1100
+ async function readWorkerLifecycleRecord(dir: string, worker: SkcTeamWorker): Promise<SkcTeamWorkerLifecycle> {
1101
+ const workerStatus = await readWorkerStatusFile(dir, worker.id);
1102
+ const heartbeat = await readJsonFile<WorkerHeartbeatFile>(path.join(workerDir(dir, worker.id), "heartbeat.json"));
1103
+ const rawLifecycle = await readJsonFile<Partial<SkcTeamWorkerLifecycle>>(workerLifecyclePath(dir, worker.id));
1104
+ const shutdownAck = await readJsonFile<Record<string, unknown>>(
1105
+ path.join(workerDir(dir, worker.id), "shutdown-ack.json"),
1106
+ );
1107
+ const lifecycle: SkcTeamWorkerLifecycle = {
1108
+ worker: worker.id,
1109
+ lifecycle_state: parseSkcTeamWorkerLifecycleState(rawLifecycle?.lifecycle_state),
1110
+ worker_status_state: parseSkcWorkerStatusState(workerStatus.state),
1111
+ pane_id: worker.pane_id ?? rawLifecycle?.pane_id,
1112
+ updated_at: rawLifecycle?.updated_at ?? workerStatus.updated_at ?? now(),
1113
+ };
1114
+ if (typeof rawLifecycle?.pid === "number") lifecycle.pid = rawLifecycle.pid;
1115
+ else if (typeof heartbeat?.pid === "number") lifecycle.pid = heartbeat.pid;
1116
+ if (rawLifecycle?.started_at) lifecycle.started_at = rawLifecycle.started_at;
1117
+ if (rawLifecycle?.stopped_at) lifecycle.stopped_at = rawLifecycle.stopped_at;
1118
+ if (rawLifecycle?.stop_reason) lifecycle.stop_reason = rawLifecycle.stop_reason;
1119
+ if (rawLifecycle?.shutdown_request_id) lifecycle.shutdown_request_id = rawLifecycle.shutdown_request_id;
1120
+ if (rawLifecycle?.shutdown_requested_at) lifecycle.shutdown_requested_at = rawLifecycle.shutdown_requested_at;
1121
+ if (
1122
+ rawLifecycle?.shutdown_mode === "graceful" ||
1123
+ rawLifecycle?.shutdown_mode === "force" ||
1124
+ rawLifecycle?.shutdown_mode === "abort"
1125
+ )
1126
+ lifecycle.shutdown_mode = rawLifecycle.shutdown_mode;
1127
+ if (typeof shutdownAck?.acknowledged_at === "string")
1128
+ lifecycle.shutdown_acknowledged_at = shutdownAck.acknowledged_at;
1129
+ if (typeof shutdownAck?.status === "string") lifecycle.shutdown_ack_status = shutdownAck.status;
1130
+ return lifecycle;
1131
+ }
1132
+
1133
+ async function readWorkerLifecycleById(
1134
+ dir: string,
1135
+ config: SkcTeamConfig,
1136
+ ): Promise<Record<string, SkcTeamWorkerLifecycle>> {
1137
+ const entries = await Promise.all(config.workers.map(worker => readWorkerLifecycleRecord(dir, worker)));
1138
+ return Object.fromEntries(entries.map(entry => [entry.worker, entry]));
1139
+ }
1140
+
1141
+ async function writeWorkerLifecycleRecord(
1142
+ dir: string,
1143
+ worker: SkcTeamWorker,
1144
+ lifecycleState: SkcTeamWorkerLifecycleState,
1145
+ updates: Partial<SkcTeamWorkerLifecycle> = {},
1146
+ ): Promise<SkcTeamWorkerLifecycle> {
1147
+ const current = await readWorkerLifecycleRecord(dir, worker);
1148
+ const next: SkcTeamWorkerLifecycle = {
1149
+ ...current,
1150
+ ...updates,
1151
+ worker: worker.id,
1152
+ lifecycle_state: lifecycleState,
1153
+ worker_status_state: current.worker_status_state,
1154
+ pane_id: updates.pane_id ?? worker.pane_id ?? current.pane_id,
1155
+ updated_at: now(),
1156
+ };
1157
+ await writeJsonFile(workerLifecyclePath(dir, worker.id), next);
1158
+ return next;
1159
+ }
1160
+
1161
+ async function writeWorkerLifecycleForConfig(
1162
+ dir: string,
1163
+ config: SkcTeamConfig,
1164
+ lifecycleState: SkcTeamWorkerLifecycleState,
1165
+ updatesFor: (worker: SkcTeamWorker) => Partial<SkcTeamWorkerLifecycle> = () => ({}),
1166
+ ): Promise<Record<string, SkcTeamWorkerLifecycle>> {
1167
+ const entries = await Promise.all(
1168
+ config.workers.map(worker => writeWorkerLifecycleRecord(dir, worker, lifecycleState, updatesFor(worker))),
1169
+ );
1170
+ return Object.fromEntries(entries.map(entry => [entry.worker, entry]));
1171
+ }
1172
+
1173
+ function teamModeStatePath(): string {
1174
+ return path.join(".skc", "state", "team-state.json");
1175
+ }
1176
+
1177
+ export async function persistSkcTeamModeStateSummary(snapshot: SkcTeamSnapshot, cwd = process.cwd()): Promise<void> {
1178
+ const active = snapshot.phase !== "complete" && snapshot.phase !== "cancelled";
1179
+ const updatedAt = now();
1180
+ await writeWorkflowEnvelopeAtomic(
1181
+ teamModeStatePath(),
1182
+ {
1183
+ skill: "team",
1184
+ version: WORKFLOW_STATE_VERSION,
1185
+ active,
1186
+ current_phase: snapshot.phase,
1187
+ team_name: snapshot.team_name,
1188
+ task_counts: snapshot.task_counts,
1189
+ updated_at: updatedAt,
1190
+ },
1191
+ {
1192
+ cwd,
1193
+ receipt: {
1194
+ cwd,
1195
+ skill: "team",
1196
+ owner: "skc-runtime",
1197
+ command: "skc team sync-team-summary",
1198
+ nowIso: updatedAt,
1199
+ },
1200
+ audit: { category: "state", verb: "sync-team-summary", owner: "skc-runtime", skill: "team" },
1201
+ },
1202
+ );
1203
+ }
1204
+
1205
+ function appendLivenessRecoveryReason(
1206
+ reasons: SkcTeamLivenessRecoveryReason[],
1207
+ reason: SkcTeamLivenessRecoveryReason,
1208
+ ): void {
1209
+ if (!reasons.includes(reason)) reasons.push(reason);
1210
+ }
1211
+
1212
+ function isPastTimestamp(value: string | undefined): boolean {
1213
+ if (!value) return false;
1214
+ const timestamp = Date.parse(value);
1215
+ return Number.isFinite(timestamp) && timestamp <= Date.now();
1216
+ }
1217
+
1218
+ function readClaimRecord(value: unknown): SkcTeamTaskClaim | undefined {
1219
+ if (!isRecord(value)) return undefined;
1220
+ const owner = typeof value.owner === "string" ? value.owner : "";
1221
+ const token = typeof value.token === "string" ? value.token : "";
1222
+ const leasedUntil = typeof value.leased_until === "string" ? value.leased_until : "";
1223
+ if (!owner || !token || !leasedUntil) return undefined;
1224
+ return { owner, token, leased_until: leasedUntil };
1225
+ }
1226
+
1227
+ function isWorkerHeartbeatStale(
1228
+ worker: SkcTeamWorker,
1229
+ heartbeat: WorkerHeartbeatFile | null,
1230
+ env: NodeJS.ProcessEnv,
1231
+ ): boolean {
1232
+ const thresholdMs = parseDurationEnv(env, "SKC_TEAM_HEARTBEAT_STALE_MS", 120_000);
1233
+ if (thresholdMs <= 0) return false;
1234
+ const heartbeatAt = Date.parse(heartbeat?.last_turn_at ?? worker.last_heartbeat);
1235
+ return Number.isFinite(heartbeatAt) && Date.now() - heartbeatAt >= thresholdMs;
1236
+ }
1237
+
1238
+ async function detectSkcTeamWorkerLivenessReasons(
1239
+ dir: string,
1240
+ config: SkcTeamConfig,
1241
+ worker: SkcTeamWorker,
1242
+ env: NodeJS.ProcessEnv,
1243
+ ): Promise<SkcTeamLivenessRecoveryReason[]> {
1244
+ const reasons: SkcTeamLivenessRecoveryReason[] = [];
1245
+ const lifecycle = await readWorkerLifecycleRecord(dir, worker);
1246
+ const heartbeat = await readJsonFile<WorkerHeartbeatFile>(path.join(workerDir(dir, worker.id), "heartbeat.json"));
1247
+ if (lifecycle.lifecycle_state === "failed") appendLivenessRecoveryReason(reasons, "worker_lifecycle_failed");
1248
+ if (lifecycle.lifecycle_state === "stopped") appendLivenessRecoveryReason(reasons, "worker_lifecycle_stopped");
1249
+ if (isWorkerHeartbeatStale(worker, heartbeat, env)) appendLivenessRecoveryReason(reasons, "stale_heartbeat");
1250
+ if (!config.dry_run && (!worker.pane_id?.startsWith("%") || !paneBelongsToTeamTarget(config, worker.pane_id)))
1251
+ appendLivenessRecoveryReason(reasons, "missing_pane");
1252
+ return reasons;
1253
+ }
1254
+
1255
+ async function reconcileSkcTeamStaleClaims(
1256
+ teamName: string,
1257
+ dir: string,
1258
+ config: SkcTeamConfig,
1259
+ env: NodeJS.ProcessEnv,
1260
+ ): Promise<SkcTeamLivenessRecoveryResult> {
1261
+ const staleWorkers: Record<string, SkcTeamLivenessRecoveryReason[]> = {};
1262
+ for (const worker of config.workers) {
1263
+ const reasons = await detectSkcTeamWorkerLivenessReasons(dir, config, worker, env);
1264
+ if (reasons.length === 0) continue;
1265
+ staleWorkers[worker.id] = reasons;
1266
+ if (reasons.includes("missing_pane") && reasons.includes("worker_lifecycle_stopped") === false) {
1267
+ await writeWorkerLifecycleRecord(dir, worker, "failed", { stop_reason: "pane_missing" });
1268
+ }
1269
+ }
1270
+
1271
+ const recoveredClaims: SkcTeamRecoveredClaim[] = [];
1272
+ for (const task of await readTasks(dir)) {
1273
+ if (task.status === "completed" || task.status === "failed") continue;
1274
+ const claimPath = path.join(dir, "claims", `${task.id}.json`);
1275
+ const diskClaim = readClaimRecord(await readJsonFile<unknown>(claimPath));
1276
+ const claim = task.claim ?? diskClaim;
1277
+ if (!claim) continue;
1278
+
1279
+ const reasons = [...(staleWorkers[claim.owner] ?? [])];
1280
+ if (isPastTimestamp(claim.leased_until)) appendLivenessRecoveryReason(reasons, "claim_expired");
1281
+ if (reasons.length === 0) continue;
1282
+
1283
+ await fs.rm(claimPath, { force: true });
1284
+ recoveredClaims.push({ task_id: task.id, worker: claim.owner, reasons });
1285
+ if (task.status !== "in_progress") {
1286
+ await appendEvent(dir, {
1287
+ type: "task_claim_recovered",
1288
+ task_id: task.id,
1289
+ worker: claim.owner,
1290
+ message: "Removed stale task claim file",
1291
+ data: { reasons },
1292
+ });
1293
+ continue;
1294
+ }
1295
+
1296
+ const recoveredTask = normalizeTask({
1297
+ ...task,
1298
+ status: "pending",
1299
+ assignee: undefined,
1300
+ claim: undefined,
1301
+ version: task.version + 1,
1302
+ updated_at: now(),
1303
+ });
1304
+ await writeTask(dir, recoveredTask);
1305
+ await appendEvent(dir, {
1306
+ type: "task_claim_recovered",
1307
+ task_id: task.id,
1308
+ worker: claim.owner,
1309
+ message: "Recovered task from stale worker claim",
1310
+ data: { reasons },
1311
+ });
1312
+ }
1313
+
1314
+ if (recoveredClaims.length > 0)
1315
+ await appendTelemetry(dir, {
1316
+ type: "team_liveness_recovery",
1317
+ message: `Recovered ${recoveredClaims.length} stale team task claim(s)`,
1318
+ data: { team_name: teamName, recovered_claims: recoveredClaims },
1319
+ });
1320
+
1321
+ return { recovered_claims: recoveredClaims, stale_workers: staleWorkers };
1322
+ }
1323
+
1324
+ export async function recoverSkcTeamStaleClaims(
1325
+ teamName: string,
1326
+ cwd = process.cwd(),
1327
+ env: NodeJS.ProcessEnv = process.env,
1328
+ ): Promise<SkcTeamLivenessRecoveryResult> {
1329
+ const dir = await findTeamDir(teamName, cwd, env);
1330
+ const config = await readConfig(dir);
1331
+ return reconcileSkcTeamStaleClaims(teamName, dir, config, env);
1332
+ }
1333
+ function normalizeOptionalTaskString(value: unknown): string | undefined {
1334
+ if (typeof value !== "string") return undefined;
1335
+ const trimmed = value.trim();
1336
+ return trimmed || undefined;
1337
+ }
1338
+
1339
+ function normalizeOptionalTaskStringArray(value: unknown): string[] | undefined {
1340
+ if (!Array.isArray(value)) return undefined;
1341
+ const items = Array.from(
1342
+ new Set(value.map(item => (typeof item === "string" ? item.trim() : "")).filter(item => item.length > 0)),
1343
+ ).sort();
1344
+ return items.length > 0 ? items : undefined;
1345
+ }
1346
+ type SkcTeamTaskMetadataInput = Partial<
1347
+ Pick<SkcTeamTask, "owner" | "lane" | "required_role" | "allowed_roles" | "depends_on" | "blocked_by">
1348
+ >;
1349
+
1350
+ function taskMetadataFromInput(input: Record<string, unknown>, includeOwner = false): SkcTeamTaskMetadataInput {
1351
+ const metadata: SkcTeamTaskMetadataInput = {};
1352
+ const owner = normalizeOptionalTaskString(input.owner);
1353
+ const lane = normalizeOptionalTaskString(input.lane);
1354
+ const requiredRole = normalizeOptionalTaskString(input.required_role ?? input.requiredRole);
1355
+ const allowedRoles = normalizeOptionalTaskStringArray(input.allowed_roles ?? input.allowedRoles);
1356
+ const dependsOn = normalizeOptionalTaskStringArray(input.depends_on ?? input.dependsOn);
1357
+ const blockedBy = normalizeOptionalTaskStringArray(input.blocked_by ?? input.blockedBy);
1358
+ if (includeOwner && owner) metadata.owner = owner;
1359
+ if (lane) metadata.lane = lane;
1360
+ if (requiredRole) metadata.required_role = requiredRole;
1361
+ if (allowedRoles) metadata.allowed_roles = allowedRoles;
1362
+ if (dependsOn) metadata.depends_on = dependsOn;
1363
+ if (blockedBy) metadata.blocked_by = blockedBy;
1364
+ return metadata;
1365
+ }
1366
+
1367
+ function normalizeTask(raw: SkcTeamTask): SkcTeamTask {
1368
+ const status = raw.status === ("complete" as SkcTeamTaskStatus) ? "completed" : raw.status;
1369
+ return {
1370
+ ...raw,
1371
+ status,
1372
+ subject: raw.subject ?? raw.title,
1373
+ description: raw.description ?? raw.objective,
1374
+ title: raw.title ?? raw.subject,
1375
+ objective: raw.objective ?? raw.description,
1376
+ version: raw.version ?? 1,
1377
+ lane: normalizeOptionalTaskString(raw.lane),
1378
+ required_role: normalizeOptionalTaskString(raw.required_role),
1379
+ allowed_roles: normalizeOptionalTaskStringArray(raw.allowed_roles),
1380
+ };
1381
+ }
1382
+
1383
+ const SKC_TEAM_INTEGRATION_ATTENTION_STATUSES = new Set<SkcTeamIntegrationStatus>([
1384
+ "integration_failed",
1385
+ "merge_conflict",
1386
+ "cherry_pick_conflict",
1387
+ "rebase_conflict",
1388
+ ]);
1389
+ const SKC_TEAM_INTEGRATION_SETTLED_STATUSES = new Set<SkcTeamIntegrationStatus>(["idle", "integrated"]);
1390
+
1391
+ async function hasPendingSkcTeamIntegration(
1392
+ dir: string,
1393
+ config: SkcTeamConfig,
1394
+ monitor: SkcTeamMonitorSnapshot | null,
1395
+ ): Promise<boolean> {
1396
+ for (const worker of config.workers) {
1397
+ const integration = monitor?.integration_by_worker?.[worker.id];
1398
+ if (integration?.status && SKC_TEAM_INTEGRATION_ATTENTION_STATUSES.has(integration.status)) return true;
1399
+
1400
+ const request = await readJsonFile<SkcWorkerIntegrationDedupeState>(workerIntegrationDedupePath(dir, worker.id));
1401
+ if (!request?.last_requested_at) continue;
1402
+ if (!integration?.status || !integration.updated_at) return true;
1403
+ if (SKC_TEAM_INTEGRATION_ATTENTION_STATUSES.has(integration.status)) return true;
1404
+ if (
1405
+ SKC_TEAM_INTEGRATION_SETTLED_STATUSES.has(integration.status) &&
1406
+ integration.updated_at >= request.last_requested_at
1407
+ ) {
1408
+ continue;
1409
+ }
1410
+ return true;
1411
+ }
1412
+ return false;
1413
+ }
1414
+
1415
+ async function resolveSkcTeamSnapshotPhase(
1416
+ dir: string,
1417
+ config: SkcTeamConfig,
1418
+ storedPhase: SkcTeamPhase,
1419
+ tasks: SkcTeamTask[],
1420
+ monitor: SkcTeamMonitorSnapshot | null,
1421
+ ): Promise<SkcTeamPhase> {
1422
+ if (storedPhase !== "running") return storedPhase;
1423
+ if (tasks.length === 0 || !tasks.every(isSkcTeamTaskCompletionVerified)) return storedPhase;
1424
+ return (await hasPendingSkcTeamIntegration(dir, config, monitor)) ? "awaiting_integration" : storedPhase;
1425
+ }
1426
+
1427
+ function isRecord(value: unknown): value is Record<string, unknown> {
1428
+ return typeof value === "object" && value != null;
1429
+ }
1430
+ const SKC_TEAM_COMPLETION_EVIDENCE_SUMMARY_MAX = 4_000;
1431
+ const SKC_TEAM_COMPLETION_EVIDENCE_OUTPUT_MAX = 8_000;
1432
+ const SKC_TEAM_COMMAND_EVIDENCE_STATUSES = new Set<SkcTeamTaskCompletionEvidenceStatus>([
1433
+ "passed",
1434
+ "failed",
1435
+ "not_run",
1436
+ ]);
1437
+ const SKC_TEAM_VERIFICATION_EVIDENCE_STATUSES = new Set<SkcTeamTaskCompletionEvidenceStatus>(["verified", "rejected"]);
1438
+
1439
+ function completionEvidenceError(taskId: string, field: string): Error {
1440
+ return new Error(`invalid_completion_evidence:${taskId}:${field}`);
1441
+ }
1442
+
1443
+ function trimRequiredCompletionEvidenceString(
1444
+ taskId: string,
1445
+ field: string,
1446
+ value: unknown,
1447
+ maxLength = SKC_TEAM_COMPLETION_EVIDENCE_SUMMARY_MAX,
1448
+ ): string {
1449
+ if (typeof value !== "string") throw completionEvidenceError(taskId, field);
1450
+ const trimmed = value.trim();
1451
+ if (!trimmed || trimmed.length > maxLength) throw completionEvidenceError(taskId, field);
1452
+ return trimmed;
1453
+ }
1454
+
1455
+ function trimOptionalCompletionEvidenceString(
1456
+ taskId: string,
1457
+ field: string,
1458
+ value: unknown,
1459
+ maxLength = SKC_TEAM_COMPLETION_EVIDENCE_OUTPUT_MAX,
1460
+ ): string | undefined {
1461
+ if (value == null) return undefined;
1462
+ if (typeof value !== "string") throw completionEvidenceError(taskId, field);
1463
+ const trimmed = value.trim();
1464
+ if (!trimmed) return undefined;
1465
+ if (trimmed.length > maxLength) throw completionEvidenceError(taskId, field);
1466
+ return trimmed;
1467
+ }
1468
+
1469
+ function normalizeSkcTeamCompletionEvidenceStatus(
1470
+ taskId: string,
1471
+ kind: SkcTeamTaskCompletionEvidenceKind,
1472
+ value: unknown,
1473
+ ): SkcTeamTaskCompletionEvidenceStatus {
1474
+ const status = trimRequiredCompletionEvidenceString(taskId, "items.status", value);
1475
+ const allowed = kind === "command" ? SKC_TEAM_COMMAND_EVIDENCE_STATUSES : SKC_TEAM_VERIFICATION_EVIDENCE_STATUSES;
1476
+ if (!allowed.has(status as SkcTeamTaskCompletionEvidenceStatus))
1477
+ throw completionEvidenceError(taskId, "items.status");
1478
+ return status as SkcTeamTaskCompletionEvidenceStatus;
1479
+ }
1480
+
1481
+ function normalizeSkcTeamCompletionEvidenceItem(taskId: string, value: unknown): SkcTeamTaskCompletionEvidenceItem {
1482
+ if (!isRecord(value) || Array.isArray(value)) throw completionEvidenceError(taskId, "items");
1483
+ const kind = trimRequiredCompletionEvidenceString(taskId, "items.kind", value.kind);
1484
+ if (kind !== "command" && kind !== "inspection" && kind !== "artifact")
1485
+ throw completionEvidenceError(taskId, "items.kind");
1486
+ const status = normalizeSkcTeamCompletionEvidenceStatus(taskId, kind, value.status);
1487
+ const item: SkcTeamTaskCompletionEvidenceItem = {
1488
+ kind,
1489
+ status,
1490
+ summary: trimRequiredCompletionEvidenceString(taskId, "items.summary", value.summary),
1491
+ };
1492
+ const command = trimOptionalCompletionEvidenceString(taskId, "items.command", value.command);
1493
+ const artifact = trimOptionalCompletionEvidenceString(taskId, "items.artifact", value.artifact);
1494
+ const location = trimOptionalCompletionEvidenceString(taskId, "items.location", value.location);
1495
+ const output = trimOptionalCompletionEvidenceString(taskId, "items.output", value.output);
1496
+ if (kind === "command" && !command) throw completionEvidenceError(taskId, "items.command");
1497
+ if (command) item.command = command;
1498
+ if (artifact) item.artifact = artifact;
1499
+ if (location) item.location = location;
1500
+ if (output) item.output = output;
1501
+ return item;
1502
+ }
1503
+
1504
+ function normalizeSkcTeamCompletionEvidenceFiles(taskId: string, value: unknown): string[] | undefined {
1505
+ if (value == null) return undefined;
1506
+ if (!Array.isArray(value)) throw completionEvidenceError(taskId, "files");
1507
+ const files = new Set<string>();
1508
+ for (const entry of value) {
1509
+ if (typeof entry !== "string") throw completionEvidenceError(taskId, "files");
1510
+ const filePath = entry.trim().replace(/\\/g, "/");
1511
+ if (!filePath || filePath.includes("\0") || path.isAbsolute(filePath) || filePath.split("/").includes("..")) {
1512
+ throw completionEvidenceError(taskId, "files");
1513
+ }
1514
+ files.add(filePath);
1515
+ }
1516
+ return files.size > 0 ? [...files].sort() : undefined;
1517
+ }
1518
+
1519
+ function isSkcTeamCompletionEvidenceItemVerified(item: SkcTeamTaskCompletionEvidenceItem): boolean {
1520
+ return (
1521
+ (item.kind === "command" && item.status === "passed") ||
1522
+ ((item.kind === "inspection" || item.kind === "artifact") && item.status === "verified")
1523
+ );
1524
+ }
1525
+
1526
+ function normalizeSkcTeamTaskCompletionEvidence(
1527
+ taskId: string,
1528
+ owner: string,
1529
+ input: unknown,
1530
+ recordedAt = now(),
1531
+ ): SkcTeamTaskCompletionEvidence {
1532
+ if (!isRecord(input) || Array.isArray(input)) throw new Error(`completion_evidence_required:${taskId}`);
1533
+ const itemsValue = input.items;
1534
+ if (!Array.isArray(itemsValue) || itemsValue.length === 0) throw completionEvidenceError(taskId, "items");
1535
+ const items = itemsValue.map(item => normalizeSkcTeamCompletionEvidenceItem(taskId, item));
1536
+ if (!items.some(isSkcTeamCompletionEvidenceItemVerified))
1537
+ throw new Error(`completion_evidence_no_verified_item:${taskId}`);
1538
+ const evidence: SkcTeamTaskCompletionEvidence = {
1539
+ summary: trimRequiredCompletionEvidenceString(taskId, "summary", input.summary),
1540
+ items,
1541
+ recorded_by: owner,
1542
+ recorded_at: recordedAt,
1543
+ };
1544
+ const files = normalizeSkcTeamCompletionEvidenceFiles(taskId, input.files);
1545
+ const notes = trimOptionalCompletionEvidenceString(taskId, "notes", input.notes);
1546
+ if (files) evidence.files = files;
1547
+ if (notes) evidence.notes = notes;
1548
+ return evidence;
1549
+ }
1550
+
1551
+ function getSkcTeamTaskCompletionEvidenceFailure(task: SkcTeamTask): string | null {
1552
+ if (task.status !== "completed") return `task_not_completed:${task.id}`;
1553
+ const evidence = task.completion_evidence;
1554
+ if (!isRecord(evidence) || Array.isArray(evidence)) return `completion_evidence_required:${task.id}`;
1555
+ if (typeof evidence.recorded_by !== "string" || evidence.recorded_by.trim().length === 0)
1556
+ return `invalid_completion_evidence:${task.id}:recorded_by`;
1557
+ if (typeof evidence.recorded_at !== "string" || evidence.recorded_at.trim().length === 0)
1558
+ return `invalid_completion_evidence:${task.id}:recorded_at`;
1559
+ try {
1560
+ normalizeSkcTeamTaskCompletionEvidence(task.id, evidence.recorded_by.trim(), evidence, evidence.recorded_at);
1561
+ return null;
1562
+ } catch (error) {
1563
+ return error instanceof Error ? error.message : `invalid_completion_evidence:${task.id}:unknown`;
1564
+ }
1565
+ }
1566
+
1567
+ function isSkcTeamTaskCompletionVerified(task: SkcTeamTask): boolean {
1568
+ return getSkcTeamTaskCompletionEvidenceFailure(task) == null;
1569
+ }
1570
+ function roleValuesForWorker(worker: SkcTeamWorker): Set<string> {
1571
+ return new Set([worker.role, worker.agent_type].map(value => value.trim()).filter(value => value.length > 0));
1572
+ }
1573
+
1574
+ function getSkcTeamTaskClaimEligibilityReason(
1575
+ task: SkcTeamTask,
1576
+ worker: SkcTeamWorker,
1577
+ tasks: SkcTeamTask[],
1578
+ ): string | null {
1579
+ if (task.status !== "pending") return `task_not_pending:${task.id}`;
1580
+ if (task.owner && task.owner !== worker.id) return `task_owner_mismatch:${task.id}:${task.owner}`;
1581
+ if (task.assignee && task.assignee !== worker.id) return `task_assignee_mismatch:${task.id}:${task.assignee}`;
1582
+
1583
+ const workerRoles = roleValuesForWorker(worker);
1584
+ if (task.required_role && !workerRoles.has(task.required_role))
1585
+ return `task_role_mismatch:${task.id}:${task.required_role}`;
1586
+ if (task.allowed_roles?.length && !task.allowed_roles.some(role => workerRoles.has(role)))
1587
+ return `task_role_mismatch:${task.id}:${task.allowed_roles.join(",")}`;
1588
+
1589
+ if (task.blocked_by?.length) return `task_blocked:${task.id}:${task.blocked_by.join(",")}`;
1590
+ for (const dependencyId of task.depends_on ?? []) {
1591
+ const dependency = tasks.find(candidate => candidate.id === dependencyId);
1592
+ if (!dependency || !isSkcTeamTaskCompletionVerified(dependency))
1593
+ return `task_dependency_incomplete:${task.id}:${dependencyId}`;
1594
+ }
1595
+
1596
+ return null;
1597
+ }
1598
+
1599
+ async function getActiveClaimReason(dir: string, task: SkcTeamTask): Promise<string | null> {
1600
+ const claimPath = path.join(dir, "claims", `${task.id}.json`);
1601
+ const diskClaim = readClaimRecord(await readJsonFile<unknown>(claimPath));
1602
+ const claim = task.claim ?? diskClaim;
1603
+ if (!claim || isPastTimestamp(claim.leased_until)) return null;
1604
+ return `task_already_claimed:${task.id}`;
1605
+ }
1606
+ function isSkcTeamTaskRecord(value: unknown): value is SkcTeamTask {
1607
+ return (
1608
+ isRecord(value) &&
1609
+ typeof value.id === "string" &&
1610
+ typeof value.status === "string" &&
1611
+ (isSkcTeamTaskStatus(value.status) || value.status === "complete") &&
1612
+ (typeof value.subject === "string" || typeof value.title === "string") &&
1613
+ (typeof value.description === "string" || typeof value.objective === "string")
1614
+ );
1615
+ }
1616
+ function isSkcTeamTaskFile(entry: { isFile(): boolean; name: string }): boolean {
1617
+ return entry.isFile() && entry.name.endsWith(".json") && !entry.name.endsWith(".evidence.json");
1618
+ }
1619
+
1620
+ async function readTasks(dir: string): Promise<SkcTeamTask[]> {
1621
+ try {
1622
+ const entries = await fs.readdir(path.join(dir, "tasks"), { withFileTypes: true });
1623
+ const tasks = await Promise.all(
1624
+ entries.filter(isSkcTeamTaskFile).map(entry => readJsonFile<unknown>(path.join(dir, "tasks", entry.name))),
1625
+ );
1626
+ return tasks
1627
+ .filter(isSkcTeamTaskRecord)
1628
+ .map(normalizeTask)
1629
+ .sort((a, b) => a.id.localeCompare(b.id));
1630
+ } catch (error) {
1631
+ if (isEnoent(error)) return [];
1632
+ throw error;
1633
+ }
1634
+ }
1635
+ async function writeTask(dir: string, task: SkcTeamTask): Promise<void> {
1636
+ await writeJsonFile(taskPath(dir, task.id), normalizeTask(task));
1637
+ }
1638
+
1639
+ async function findTeamDir(
1640
+ teamName: string,
1641
+ cwd = process.cwd(),
1642
+ env: NodeJS.ProcessEnv = process.env,
1643
+ ): Promise<string> {
1644
+ const root = resolveSkcTeamStateRoot(cwd, env);
1645
+ const exact = teamDir(root, teamName);
1646
+ if (await readJsonFile<SkcTeamConfig>(path.join(exact, "config.json"))) return exact;
1647
+ const candidates = await listSkcTeams(cwd, env);
1648
+ const input = sanitizeName(teamName);
1649
+ const matches = candidates.filter(
1650
+ candidate => candidate.team_name === input || sanitizeName(candidate.display_name) === input,
1651
+ );
1652
+ if (matches.length === 1) return matches[0].state_dir;
1653
+ if (matches.length > 1)
1654
+ throw new Error(`ambiguous_team_name:${teamName}:${matches.map(match => match.team_name).join(",")}`);
1655
+ throw new Error(`team_not_found:${teamName}`);
1656
+ }
1657
+ function buildWorkers(count: number, agentType: string, stateRoot?: string): SkcTeamWorker[] {
1658
+ return Array.from({ length: count }, (_, index) => {
1659
+ const id = `worker-${index + 1}`;
1660
+ return {
1661
+ id,
1662
+ name: id,
1663
+ index: index + 1,
1664
+ agent_type: agentType,
1665
+ role: agentType,
1666
+ status: "starting",
1667
+ last_heartbeat: now(),
1668
+ assigned_tasks: [],
1669
+ team_state_root: stateRoot,
1670
+ };
1671
+ });
1672
+ }
1673
+ function sanitizePathToken(value: string): string {
1674
+ return sanitizeName(value) || "default";
1675
+ }
1676
+ function runGitResult(cwd: string, args: string[]): GitResult {
1677
+ const result = Bun.spawnSync(["git", ...args], { cwd, stdout: "pipe", stderr: "pipe" });
1678
+ return {
1679
+ ok: result.exitCode === 0,
1680
+ stdout: result.stdout.toString().trim(),
1681
+ stderr: result.stderr.toString().trim(),
1682
+ };
1683
+ }
1684
+ function runGit(cwd: string, args: string[]): string {
1685
+ const result = runGitResult(cwd, args);
1686
+ if (result.ok) return result.stdout;
1687
+ throw new Error(result.stderr || `git ${args.join(" ")} failed`);
1688
+ }
1689
+ function tryRunGit(cwd: string, args: string[]): string | null {
1690
+ const result = runGitResult(cwd, args);
1691
+ return result.ok ? result.stdout : null;
1692
+ }
1693
+ function isGitRepository(cwd: string): boolean {
1694
+ return tryRunGit(cwd, ["rev-parse", "--show-toplevel"]) != null;
1695
+ }
1696
+
1697
+ function parseWorktreeMode(args: string[]): { mode: SkcTeamWorktreeMode; remainingArgs: string[] } {
1698
+ let mode: SkcTeamWorktreeMode = { enabled: false };
1699
+ const remainingArgs: string[] = [];
1700
+ for (let index = 0; index < args.length; index += 1) {
1701
+ const arg = args[index] ?? "";
1702
+ if (arg === "--worktree" || arg === "-w") {
1703
+ const next = args[index + 1];
1704
+ if (typeof next === "string" && next.length > 0 && !next.startsWith("-") && !next.includes(":")) {
1705
+ mode = { enabled: true, detached: false, name: next };
1706
+ index += 1;
1707
+ } else mode = { enabled: true, detached: true, name: null };
1708
+ continue;
1709
+ }
1710
+ if (arg.startsWith("--worktree=")) {
1711
+ const name = arg.slice("--worktree=".length).trim();
1712
+ mode = name ? { enabled: true, detached: false, name } : { enabled: true, detached: true, name: null };
1713
+ continue;
1714
+ }
1715
+ if (arg.startsWith("-w=") || (arg.startsWith("-w") && arg.length > 2)) {
1716
+ const name = arg.startsWith("-w=") ? arg.slice("-w=".length).trim() : arg.slice(2).trim();
1717
+ mode = name ? { enabled: true, detached: false, name } : { enabled: true, detached: true, name: null };
1718
+ continue;
1719
+ }
1720
+ remainingArgs.push(arg);
1721
+ }
1722
+ return { mode, remainingArgs };
1723
+ }
1724
+ function resolveDefaultWorktreeMode(mode?: SkcTeamWorktreeMode): SkcTeamWorktreeMode {
1725
+ return mode?.enabled ? mode : { enabled: true, detached: true, name: null };
1726
+ }
1727
+ function branchExists(repoRoot: string, branchName: string): boolean {
1728
+ return (
1729
+ Bun.spawnSync(["git", "show-ref", "--verify", "--quiet", `refs/heads/${branchName}`], {
1730
+ cwd: repoRoot,
1731
+ stdout: "ignore",
1732
+ stderr: "ignore",
1733
+ }).exitCode === 0
1734
+ );
1735
+ }
1736
+ function worktreeIsDirty(worktreePath: string): boolean {
1737
+ return runGit(worktreePath, ["status", "--porcelain"]).trim().length > 0;
1738
+ }
1739
+ function worktreeHead(worktreePath: string): string {
1740
+ return runGit(worktreePath, ["rev-parse", "HEAD"]);
1741
+ }
1742
+ async function pathExists(filePath: string): Promise<boolean> {
1743
+ try {
1744
+ await fs.access(filePath);
1745
+ return true;
1746
+ } catch (error) {
1747
+ if (isEnoent(error)) return false;
1748
+ throw error;
1749
+ }
1750
+ }
1751
+ function findWorktreePath(repoRoot: string, worktreePath: string): string | null {
1752
+ const raw = runGit(repoRoot, ["worktree", "list", "--porcelain"]);
1753
+ const resolved = path.resolve(worktreePath);
1754
+ for (const line of raw.split(/\r?\n/))
1755
+ if (line.startsWith("worktree ") && path.resolve(line.slice("worktree ".length)) === resolved) return resolved;
1756
+ return null;
1757
+ }
1758
+ async function ensureWorkerWorktree(
1759
+ cwd: string,
1760
+ dir: string,
1761
+ teamName: string,
1762
+ worker: SkcTeamWorker,
1763
+ mode: SkcTeamWorktreeMode,
1764
+ ): Promise<SkcTeamWorker> {
1765
+ if (!mode.enabled) return worker;
1766
+ if (!isGitRepository(cwd)) throw new Error(`team_worktree_requires_git_repo:${cwd}`);
1767
+ const repoRoot = runGit(cwd, ["rev-parse", "--show-toplevel"]);
1768
+ const baseRef = runGit(repoRoot, ["rev-parse", "HEAD"]);
1769
+ const worktreePath = path.join(dir, "worktrees", worker.id);
1770
+ const existing = findWorktreePath(repoRoot, worktreePath);
1771
+ let created = false;
1772
+ const branchName = mode.detached
1773
+ ? null
1774
+ : `${mode.name}/${sanitizePathToken(teamName)}/${sanitizePathToken(worker.id)}`;
1775
+ if (existing) {
1776
+ if (worktreeIsDirty(worktreePath)) throw new Error(`worktree_dirty:${worktreePath}`);
1777
+ if (mode.detached && worktreeHead(worktreePath) !== baseRef) throw new Error(`worktree_stale:${worktreePath}`);
1778
+ } else {
1779
+ if (await pathExists(worktreePath)) throw new Error(`worktree_path_conflict:${worktreePath}`);
1780
+ await fs.mkdir(path.dirname(worktreePath), { recursive: true });
1781
+ const args = mode.detached
1782
+ ? ["worktree", "add", "--detach", worktreePath, baseRef]
1783
+ : branchExists(repoRoot, branchName ?? "")
1784
+ ? ["worktree", "add", worktreePath, branchName ?? ""]
1785
+ : ["worktree", "add", "-b", branchName ?? "", worktreePath, baseRef];
1786
+ runGit(repoRoot, args);
1787
+ created = true;
1788
+ }
1789
+ return {
1790
+ ...worker,
1791
+ worktree_repo_root: repoRoot,
1792
+ worktree_path: path.resolve(worktreePath),
1793
+ worktree_branch: branchName,
1794
+ worktree_detached: mode.detached,
1795
+ worktree_created: created,
1796
+ worktree_base_ref: baseRef,
1797
+ };
1798
+ }
1799
+
1800
+ function buildTeamTmuxLeaderRequirementMessage(detail?: string): string {
1801
+ const suffix = detail?.trim() ? `:${detail.trim()}` : "";
1802
+ return `skc_team_requires_tmux_leader: run \`skc --tmux\` first, then run \`skc team ...\` inside that tmux-backed leader session, or use \`skc team --dry-run\` for state-only smoke tests${suffix}`;
1803
+ }
1804
+ function readSkcTmuxProfileValue(tmuxCommand: string, sessionName: string): string {
1805
+ const result = Bun.spawnSync(
1806
+ [tmuxCommand, "show-options", "-qv", "-t", buildSkcTmuxExactOptionTarget(sessionName), SKC_TMUX_PROFILE_OPTION],
1807
+ {
1808
+ stdout: "pipe",
1809
+ stderr: "pipe",
1810
+ },
1811
+ );
1812
+ if (result.exitCode !== 0) return "";
1813
+ return result.stdout.toString().trim();
1814
+ }
1815
+
1816
+ function retagSkcLaunchedTmuxSession(tmuxCommand: string, sessionName: string): boolean {
1817
+ const result = Bun.spawnSync(
1818
+ [
1819
+ tmuxCommand,
1820
+ "set-option",
1821
+ "-t",
1822
+ buildSkcTmuxExactOptionTarget(sessionName),
1823
+ SKC_TMUX_PROFILE_OPTION,
1824
+ SKC_TMUX_PROFILE_VALUE,
1825
+ ],
1826
+ {
1827
+ stdout: "pipe",
1828
+ stderr: "pipe",
1829
+ },
1830
+ );
1831
+ return result.exitCode === 0;
1832
+ }
1833
+
1834
+ function readCurrentTmuxLeaderContext(tmuxCommand: string, env: NodeJS.ProcessEnv): SkcTmuxLeaderContext {
1835
+ const paneTarget = env.TMUX_PANE?.trim();
1836
+ const args = paneTarget
1837
+ ? ["display-message", "-p", "-t", paneTarget, "#S:#I #{pane_id}"]
1838
+ : ["display-message", "-p", "#S:#I #{pane_id}"];
1839
+ const result = Bun.spawnSync([tmuxCommand, ...args], { stdout: "pipe", stderr: "pipe" });
1840
+ if (result.exitCode !== 0) throw new Error(buildTeamTmuxLeaderRequirementMessage(result.stderr.toString()));
1841
+ const [sessionAndWindow = "", leaderPaneId = ""] = result.stdout.toString().trim().split(/\s+/);
1842
+ const [sessionName = "", windowIndex = ""] = sessionAndWindow.split(":");
1843
+ if (!sessionName || !windowIndex || !leaderPaneId.startsWith("%"))
1844
+ throw new Error(buildTeamTmuxLeaderRequirementMessage(`invalid_tmux_context:${result.stdout.toString().trim()}`));
1845
+ if (readSkcTmuxProfileValue(tmuxCommand, sessionName) !== SKC_TMUX_PROFILE_VALUE) {
1846
+ // Self-heal: a pane launched through `skc --tmux` exports
1847
+ // SKC_TMUX_LAUNCHED=1, but the session can lose (or never receive) the
1848
+ // @skc-profile user-option tag when startup attach fails mid-way or the
1849
+ // registry write races. That stranded-but-genuinely-SKC leader pane
1850
+ // previously hard-failed as unmanaged_tmux_session; re-tag it instead.
1851
+ const launchedBySkc = env[SKC_TMUX_LAUNCHED_ENV] === "1";
1852
+ const retagged = launchedBySkc && retagSkcLaunchedTmuxSession(tmuxCommand, sessionName);
1853
+ if (!retagged || readSkcTmuxProfileValue(tmuxCommand, sessionName) !== SKC_TMUX_PROFILE_VALUE)
1854
+ throw new Error(
1855
+ buildTeamTmuxLeaderRequirementMessage(
1856
+ `unmanaged_tmux_session:${sessionName} — ${buildSkcTmuxUntaggedSessionHint(tmuxCommand)}`,
1857
+ ),
1858
+ );
1859
+ }
1860
+ return { sessionName, windowIndex, leaderPaneId, target: `${sessionName}:${windowIndex}` };
1861
+ }
1862
+ export function resolveSkcWorkerCommand(cwd = process.cwd(), env: NodeJS.ProcessEnv = process.env): string {
1863
+ const explicit = env.SKC_TEAM_WORKER_COMMAND?.trim();
1864
+ if (explicit) return explicit;
1865
+ const entrypoint = process.argv[1];
1866
+ if (entrypoint?.endsWith(".ts"))
1867
+ return `${shellQuote(process.execPath)} ${shellQuote(path.resolve(cwd, entrypoint))}`;
1868
+ if (entrypoint && path.basename(entrypoint).startsWith("skc")) return shellQuote(path.resolve(cwd, entrypoint));
1869
+ return "skc";
1870
+ }
1871
+ function buildWorkerCommand(config: SkcTeamConfig, worker: SkcTeamWorker): string {
1872
+ const workspace = worker.worktree_path
1873
+ ? `Worker worktree: ${worker.worktree_path}.`
1874
+ : `Worker cwd: ${config.leader.cwd}.`;
1875
+ const prompt = [
1876
+ `You are ${worker.id} in skc team ${config.team_name}.`,
1877
+ `Team state root: ${config.state_root}.`,
1878
+ workspace,
1879
+ `Team brief (context only): ${config.task}`,
1880
+ "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.",
1881
+ `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.`,
1882
+ `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.`,
1883
+ ].join("\n");
1884
+ const env = [
1885
+ `SKC_TEAM_WORKER=${shellQuote(`${config.team_name}/${worker.id}`)}`,
1886
+ `SKC_TEAM_INTERNAL_WORKER=${shellQuote(`${config.team_name}/${worker.id}`)}`,
1887
+ `SKC_TEAM_NAME=${shellQuote(config.team_name)}`,
1888
+ `SKC_TEAM_WORKER_ID=${shellQuote(worker.id)}`,
1889
+ `SKC_TEAM_STATE_ROOT=${shellQuote(config.state_root)}`,
1890
+ `SKC_TEAM_LEADER_CWD=${shellQuote(config.leader.cwd)}`,
1891
+ `SKC_TEAM_DISPLAY_NAME=${shellQuote(config.display_name)}`,
1892
+ ...(worker.worktree_path ? [`SKC_TEAM_WORKTREE_PATH=${shellQuote(worker.worktree_path)}`] : []),
1893
+ ];
1894
+ return `${env.join(" ")} ${config.worker_command} ${shellQuote(prompt)}`;
1895
+ }
1896
+ interface SkcTeamInitialLane {
1897
+ label: string;
1898
+ title: string;
1899
+ body: string;
1900
+ }
1901
+
1902
+ function normalizeLaneId(label: string): string {
1903
+ return `lane-${sanitizeName(label).toLowerCase() || stableHash(label).slice(0, 8)}`;
1904
+ }
1905
+
1906
+ function parseExplicitTeamLanes(task: string): SkcTeamInitialLane[] {
1907
+ const lines = task.split(/\r?\n/);
1908
+ const lanes: SkcTeamInitialLane[] = [];
1909
+ let current: { label: string; title: string; body: string[] } | null = null;
1910
+ const laneHeading = /^#{2,6}\s+Lane\s+([A-Za-z0-9]+)\s*(?:[—–-]\s*(.+))?\s*$/;
1911
+ const boundaryHeading = /^#{1,6}\s+(?:Integration Owner|Verification Plan|ADR|Approval State)\b/i;
1912
+
1913
+ for (const line of lines) {
1914
+ const match = line.match(laneHeading);
1915
+ if (match) {
1916
+ if (current) lanes.push({ ...current, body: current.body.join("\n").trim() });
1917
+ current = {
1918
+ label: match[1] ?? `${lanes.length + 1}`,
1919
+ title: (match[2] ?? `Lane ${match[1] ?? lanes.length + 1}`).trim(),
1920
+ body: [],
1921
+ };
1922
+ continue;
1923
+ }
1924
+ if (current && boundaryHeading.test(line)) {
1925
+ lanes.push({ ...current, body: current.body.join("\n").trim() });
1926
+ current = null;
1927
+ continue;
1928
+ }
1929
+ if (current) current.body.push(line);
1930
+ }
1931
+ if (current) lanes.push({ ...current, body: current.body.join("\n").trim() });
1932
+ return lanes.filter(lane => lane.body.length > 0 || lane.title.length > 0);
1933
+ }
1934
+
1935
+ function hasAmbiguousLaneSplitIntent(task: string): boolean {
1936
+ return (
1937
+ /\bsplit\s+lanes?\s*:/i.test(task) || /\blanes?\s*:\s*[A-Z]\b/i.test(task) || /\bLane\s+[A-Z]\s*[—–-]/.test(task)
1938
+ );
1939
+ }
1940
+
1941
+ function buildInitialTasks(task: string, workers: SkcTeamWorker[]): SkcTeamTask[] {
1942
+ const lanes = parseExplicitTeamLanes(task);
1943
+ if (lanes.length > 0)
1944
+ return lanes.map((lane, index) => {
1945
+ const worker = workers[index % workers.length];
1946
+ if (!worker) throw new Error("team_lane_requires_worker");
1947
+ const laneTitle = `Lane ${lane.label} — ${lane.title}`;
1948
+ const objective = [`${laneTitle}`, lane.body].filter(part => part.trim().length > 0).join("\n\n");
1949
+ return {
1950
+ id: `task-${index + 1}`,
1951
+ subject: laneTitle,
1952
+ description: objective,
1953
+ title: laneTitle,
1954
+ objective,
1955
+ status: "pending",
1956
+ owner: worker.id,
1957
+ lane: normalizeLaneId(lane.label),
1958
+ required_role: worker.role,
1959
+ version: 1,
1960
+ created_at: now(),
1961
+ updated_at: now(),
1962
+ };
1963
+ });
1964
+
1965
+ if (workers.length > 1 && hasAmbiguousLaneSplitIntent(task))
1966
+ throw new Error(
1967
+ "ambiguous_team_lane_split: multi-worker team launch mentions lanes but does not provide explicit markdown lane sections such as `### Lane A — Title`",
1968
+ );
1969
+
1970
+ return workers.map(worker => ({
1971
+ id: `task-${worker.index}`,
1972
+ subject: `Execute team brief (${worker.id})`,
1973
+ description: task,
1974
+ title: `Execute team brief (${worker.id})`,
1975
+ objective: task,
1976
+ status: "pending",
1977
+ owner: worker.id,
1978
+ version: 1,
1979
+ created_at: now(),
1980
+ updated_at: now(),
1981
+ }));
1982
+ }
1983
+
1984
+ async function startTmuxSession(
1985
+ config: SkcTeamConfig,
1986
+ dir: string,
1987
+ dryRun: boolean,
1988
+ env: NodeJS.ProcessEnv = process.env,
1989
+ ): Promise<SkcTeamWorker[]> {
1990
+ if (dryRun) return config.workers.map(worker => ({ ...worker, pane_id: `%dry-run-${worker.id}` }));
1991
+ const rollbackPaneIds: string[] = [];
1992
+ try {
1993
+ const workers: SkcTeamWorker[] = [];
1994
+ let rightStackRootPaneId: string | null = null;
1995
+ for (const worker of config.workers) {
1996
+ const splitDirection: string = worker.index === 1 ? "-h" : "-v";
1997
+ const splitTarget: string =
1998
+ worker.index === 1 ? config.leader.pane_id : (rightStackRootPaneId ?? config.leader.pane_id);
1999
+ const split: Bun.SyncSubprocess<"pipe", "pipe"> = Bun.spawnSync(
2000
+ [
2001
+ config.tmux_command,
2002
+ "split-window",
2003
+ splitDirection,
2004
+ "-t",
2005
+ splitTarget,
2006
+ "-d",
2007
+ "-P",
2008
+ "-F",
2009
+ "#{pane_id}",
2010
+ "-c",
2011
+ worker.worktree_path ?? config.leader.cwd,
2012
+ buildWorkerCommand(config, worker),
2013
+ ],
2014
+ { stdout: "pipe", stderr: "pipe" },
2015
+ );
2016
+ if (split.exitCode !== 0)
2017
+ throw new Error(split.stderr.toString().trim() || `tmux_split_failed:${config.tmux_target}:${worker.id}`);
2018
+ const paneId: string = split.stdout.toString().trim().split(/\r?\n/)[0]?.trim() ?? "";
2019
+ if (!paneId.startsWith("%")) throw new Error(`tmux_split_missing_pane:${config.tmux_target}:${worker.id}`);
2020
+ rollbackPaneIds.push(paneId);
2021
+ if (worker.index === 1) rightStackRootPaneId = paneId;
2022
+ workers.push({ ...worker, pane_id: paneId });
2023
+ }
2024
+ Bun.spawnSync([config.tmux_command, "select-layout", "-t", config.tmux_target, "main-vertical"], {
2025
+ stdout: "ignore",
2026
+ stderr: "ignore",
2027
+ });
2028
+ const widthResult = Bun.spawnSync(
2029
+ [config.tmux_command, "display-message", "-p", "-t", config.tmux_target, "#{window_width}"],
2030
+ { stdout: "pipe", stderr: "ignore" },
2031
+ );
2032
+ const width = Number.parseInt(widthResult.stdout.toString().trim(), 10);
2033
+ if (Number.isFinite(width) && width >= 40) {
2034
+ Bun.spawnSync(
2035
+ [
2036
+ config.tmux_command,
2037
+ "set-window-option",
2038
+ "-t",
2039
+ config.tmux_target,
2040
+ "main-pane-width",
2041
+ String(Math.floor(width / 2)),
2042
+ ],
2043
+ { stdout: "ignore", stderr: "ignore" },
2044
+ );
2045
+ Bun.spawnSync([config.tmux_command, "select-layout", "-t", config.tmux_target, "main-vertical"], {
2046
+ stdout: "ignore",
2047
+ stderr: "ignore",
2048
+ });
2049
+ }
2050
+ const profileResult = applySkcTmuxProfile({
2051
+ tmuxCommand: config.tmux_command,
2052
+ target: config.tmux_target,
2053
+ cwd: config.leader.cwd,
2054
+ env,
2055
+ });
2056
+ await appendTelemetry(dir, {
2057
+ type: "tmux_profile_applied",
2058
+ message: profileResult.skipped
2059
+ ? "Skipped SKC scoped tmux profile"
2060
+ : "Applied SKC scoped tmux profile to team tmux target",
2061
+ data: {
2062
+ tmux_target: config.tmux_target,
2063
+ command_count: profileResult.commands.length,
2064
+ failure_count: profileResult.failures.length,
2065
+ },
2066
+ });
2067
+ await appendTelemetry(dir, {
2068
+ type: "tmux_started",
2069
+ message: "Started skc team worker panes in current tmux window",
2070
+ data: { tmux_target: config.tmux_target, panes: workers.map(worker => worker.pane_id).filter(Boolean) },
2071
+ });
2072
+ return workers;
2073
+ } catch (error) {
2074
+ for (const paneId of rollbackPaneIds)
2075
+ Bun.spawnSync([config.tmux_command, "kill-pane", "-t", paneId], { stdout: "ignore", stderr: "ignore" });
2076
+ throw error;
2077
+ }
2078
+ }
2079
+ function paneBelongsToTeamTarget(config: SkcTeamConfig, paneId: string): boolean {
2080
+ if (paneId === config.leader.pane_id) return false;
2081
+ const result = Bun.spawnSync([config.tmux_command, "display-message", "-p", "-t", paneId, "#S:#I #{pane_id}"], {
2082
+ stdout: "pipe",
2083
+ stderr: "ignore",
2084
+ });
2085
+ if (result.exitCode !== 0) return false;
2086
+ const [target = "", detectedPaneId = ""] = result.stdout.toString().trim().split(/\s+/);
2087
+ return target === config.tmux_target && detectedPaneId === paneId;
2088
+ }
2089
+ function killWorkerPanes(config: SkcTeamConfig): void {
2090
+ for (const worker of config.workers)
2091
+ if (worker.pane_id?.startsWith("%") && paneBelongsToTeamTarget(config, worker.pane_id))
2092
+ Bun.spawnSync([config.tmux_command, "kill-pane", "-t", worker.pane_id], {
2093
+ stdout: "ignore",
2094
+ stderr: "ignore",
2095
+ });
2096
+ }
2097
+ async function rollbackCreatedWorktrees(workers: SkcTeamWorker[]): Promise<void> {
2098
+ for (const worker of workers.filter(worker => worker.worktree_created).reverse())
2099
+ if (worker.worktree_repo_root && worker.worktree_path)
2100
+ Bun.spawnSync(["git", "worktree", "remove", "--force", worker.worktree_path], {
2101
+ cwd: worker.worktree_repo_root,
2102
+ stdout: "ignore",
2103
+ stderr: "ignore",
2104
+ });
2105
+ }
2106
+ async function removeCleanCreatedWorktrees(workers: SkcTeamWorker[]): Promise<void> {
2107
+ for (const worker of workers.filter(worker => worker.worktree_created).reverse())
2108
+ if (worker.worktree_repo_root && worker.worktree_path && !worktreeIsDirty(worker.worktree_path))
2109
+ Bun.spawnSync(["git", "worktree", "remove", worker.worktree_path], {
2110
+ cwd: worker.worktree_repo_root,
2111
+ stdout: "ignore",
2112
+ stderr: "ignore",
2113
+ });
2114
+ }
2115
+
2116
+ function monitorSnapshotPath(dir: string): string {
2117
+ return path.join(dir, "monitor-snapshot.json");
2118
+ }
2119
+ function integrationReportPath(dir: string): string {
2120
+ return path.join(dir, "integration-report.md");
2121
+ }
2122
+ function commitHygieneLedgerPath(config: SkcTeamConfig): string {
2123
+ return path.join(config.leader_cwd, ".skc", "reports", "team-commit-hygiene", `${config.team_name}.ledger.json`);
2124
+ }
2125
+ function integrationNowState(
2126
+ status: SkcTeamIntegrationStatus,
2127
+ ): Pick<SkcTeamWorkerIntegrationState, "status" | "updated_at"> {
2128
+ return { status, updated_at: now() };
2129
+ }
2130
+ async function appendIntegrationReport(
2131
+ dir: string,
2132
+ entry: { worker: string; operation: "merge" | "cherry-pick" | "rebase"; files: string[]; detail: string },
2133
+ ): Promise<void> {
2134
+ const line = `- [${now()}] ${entry.worker}: ${entry.operation}; files=${entry.files.join(",") || "unknown"}; ${entry.detail}\n`;
2135
+ if (await pathExists(integrationReportPath(dir)))
2136
+ await appendText(
2137
+ integrationReportPath(dir),
2138
+ line,
2139
+ stateWriterOptions(integrationReportPath(dir), "report", "append"),
2140
+ );
2141
+ else
2142
+ await writeReport(
2143
+ integrationReportPath(dir),
2144
+ `# Integration Report\n\n${line}`,
2145
+ stateWriterOptions(integrationReportPath(dir), "report", "write"),
2146
+ );
2147
+ }
2148
+ async function appendCommitHygieneEntries(config: SkcTeamConfig, entries: SkcTeamCommitHygieneEntry[]): Promise<void> {
2149
+ if (entries.length === 0) return;
2150
+ const ledgerPath = commitHygieneLedgerPath(config);
2151
+ const existing = (await readJsonFile<{ version: number; entries: SkcTeamCommitHygieneEntry[] }>(ledgerPath)) ?? {
2152
+ version: 1,
2153
+ entries: [],
2154
+ };
2155
+ await writeJsonFile(ledgerPath, { version: 1, entries: [...existing.entries, ...entries] });
2156
+ }
2157
+ function resolveHead(cwd: string): string | null {
2158
+ return tryRunGit(cwd, ["rev-parse", "HEAD"]);
2159
+ }
2160
+ function isAncestor(cwd: string, ancestor: string, descendant: string): boolean {
2161
+ return runGitResult(cwd, ["merge-base", "--is-ancestor", ancestor, descendant]).ok;
2162
+ }
2163
+ function listCommitRange(cwd: string, baseRef: string, headRef: string): string[] {
2164
+ const result = runGitResult(cwd, ["rev-list", "--reverse", `${baseRef}..${headRef}`]);
2165
+ if (!result.ok || !result.stdout) return [];
2166
+ return result.stdout
2167
+ .split(/\r?\n/)
2168
+ .map(line => line.trim())
2169
+ .filter(Boolean);
2170
+ }
2171
+ function listConflictFiles(cwd: string): string[] {
2172
+ const result = runGitResult(cwd, ["diff", "--name-only", "--diff-filter=U"]);
2173
+ if (!result.ok || !result.stdout) return [];
2174
+ return result.stdout
2175
+ .split(/\r?\n/)
2176
+ .map(line => line.trim())
2177
+ .filter(Boolean);
2178
+ }
2179
+
2180
+ export type SkcWorkerCheckpointClassification =
2181
+ | { kind: "clean"; files: string[] }
2182
+ | { kind: "eligible"; files: string[] }
2183
+ | { kind: "protected_only"; files: string[] }
2184
+ | { kind: "conflicted"; files: string[] }
2185
+ | { kind: "git_error"; files: string[]; detail: string };
2186
+
2187
+ const UNMERGED_GIT_STATUS_CODES = new Set(["DD", "AU", "UD", "UA", "DU", "AA", "UU"]);
2188
+ const PROTECTED_WORKER_CHECKPOINT_PREFIXES = [
2189
+ ".skc/state/",
2190
+ ".skc/logs/",
2191
+ ".skc/reports/",
2192
+ ".skc/tmp/",
2193
+ ".skc/ultragoal/",
2194
+ ];
2195
+
2196
+ function parsePorcelainStatusFiles(stdout: string): string[] {
2197
+ return stdout
2198
+ .split(/\r?\n/)
2199
+ .map(line => line.trimEnd())
2200
+ .filter(Boolean)
2201
+ .map(line => line.slice(3).trim())
2202
+ .filter(Boolean);
2203
+ }
2204
+
2205
+ function normalizeGitStatusPath(filePath: string): string {
2206
+ return (filePath.split(" -> ").at(-1) ?? filePath).replace(/\\/g, "/").replace(/^\.\//, "");
2207
+ }
2208
+
2209
+ export function classifySkcTeamCheckpointFiles(files: string[]): { eligible: string[]; protected: string[] } {
2210
+ const eligible: string[] = [];
2211
+ const protectedFiles: string[] = [];
2212
+ for (const file of files) {
2213
+ const normalized = normalizeGitStatusPath(file);
2214
+ if (
2215
+ PROTECTED_WORKER_CHECKPOINT_PREFIXES.some(
2216
+ prefix => normalized === prefix.slice(0, -1) || normalized.startsWith(prefix),
2217
+ )
2218
+ )
2219
+ protectedFiles.push(file);
2220
+ else eligible.push(file);
2221
+ }
2222
+ return { eligible, protected: protectedFiles };
2223
+ }
2224
+
2225
+ export function classifyWorkerCheckpointStatus(cwd: string): SkcWorkerCheckpointClassification {
2226
+ const status = runGitResult(cwd, ["status", "--porcelain", "-uall"]);
2227
+ if (!status.ok) {
2228
+ return { kind: "git_error", files: [], detail: status.stderr || status.stdout || "git status failed" };
2229
+ }
2230
+ if (!status.stdout.trim()) return { kind: "clean", files: [] };
2231
+ const files = parsePorcelainStatusFiles(status.stdout);
2232
+ const hasUnmergedStatus = status.stdout
2233
+ .split(/\r?\n/)
2234
+ .filter(Boolean)
2235
+ .some(line => UNMERGED_GIT_STATUS_CODES.has(line.slice(0, 2)));
2236
+ const conflictFiles = listConflictFiles(cwd);
2237
+ if (hasUnmergedStatus || conflictFiles.length > 0) {
2238
+ return { kind: "conflicted", files: conflictFiles.length > 0 ? conflictFiles : files };
2239
+ }
2240
+ const classified = classifySkcTeamCheckpointFiles(files);
2241
+ if (classified.eligible.length === 0 && classified.protected.length > 0)
2242
+ return { kind: "protected_only", files: classified.protected };
2243
+ return { kind: "eligible", files: classified.eligible };
2244
+ }
2245
+ async function appendIntegrationEvent(
2246
+ dir: string,
2247
+ type: string,
2248
+ worker: SkcTeamWorker,
2249
+ data: Record<string, unknown>,
2250
+ ): Promise<void> {
2251
+ await appendEvent(dir, {
2252
+ type,
2253
+ worker: worker.id,
2254
+ task_id: worker.assigned_tasks[0],
2255
+ message: typeof data.summary === "string" ? data.summary : type,
2256
+ data,
2257
+ });
2258
+ }
2259
+ async function notifyLeader(
2260
+ config: SkcTeamConfig,
2261
+ worker: SkcTeamWorker,
2262
+ body: string,
2263
+ cwd: string,
2264
+ env: NodeJS.ProcessEnv,
2265
+ ): Promise<void> {
2266
+ await sendSkcTeamMessage(config.team_name, worker.id, "leader-fixed", body, cwd, env).catch(() => undefined);
2267
+ }
2268
+ async function notifyWorker(
2269
+ config: SkcTeamConfig,
2270
+ worker: SkcTeamWorker,
2271
+ body: string,
2272
+ cwd: string,
2273
+ env: NodeJS.ProcessEnv,
2274
+ ): Promise<void> {
2275
+ await sendSkcTeamMessage(config.team_name, "leader-fixed", worker.id, body, cwd, env).catch(() => undefined);
2276
+ }
2277
+ async function notifyIntegrationConflict(
2278
+ config: SkcTeamConfig,
2279
+ worker: SkcTeamWorker,
2280
+ body: string,
2281
+ cwd: string,
2282
+ env: NodeJS.ProcessEnv,
2283
+ ): Promise<void> {
2284
+ await Promise.all([notifyLeader(config, worker, body, cwd, env), notifyWorker(config, worker, body, cwd, env)]);
2285
+ }
2286
+ function autoCommitDirtyWorker(worker: SkcTeamWorker): {
2287
+ committed: boolean;
2288
+ commit: string | null;
2289
+ classification: SkcWorkerCheckpointClassification | null;
2290
+ } {
2291
+ const empty = { committed: false, commit: null, classification: null };
2292
+ if (!worker.worktree_path) return empty;
2293
+ const classification = classifyWorkerCheckpointStatus(worker.worktree_path);
2294
+ if (classification.kind !== "eligible") return { ...empty, classification };
2295
+ if (!runGitResult(worker.worktree_path, ["add", "--", ...classification.files]).ok)
2296
+ return { ...empty, classification };
2297
+ const message = `skc(team): auto-checkpoint ${worker.id} [${worker.assigned_tasks[0] ?? "unknown"}]`;
2298
+ if (!runGitResult(worker.worktree_path, ["commit", "--no-verify", "-m", message]).ok)
2299
+ return { ...empty, classification };
2300
+ return { committed: true, commit: resolveHead(worker.worktree_path), classification };
2301
+ }
2302
+ function workerMergeRef(worker: SkcTeamWorker, workerHead: string): string {
2303
+ if (!worker.worktree_path) return workerHead;
2304
+ const branch = tryRunGit(worker.worktree_path, ["rev-parse", "--abbrev-ref", "HEAD"]);
2305
+ return !branch || branch === "HEAD" ? workerHead : branch;
2306
+ }
2307
+ async function integrateSkcWorkerCommits(
2308
+ config: SkcTeamConfig,
2309
+ dir: string,
2310
+ previous: SkcTeamMonitorSnapshot | null,
2311
+ cwd: string,
2312
+ env: NodeJS.ProcessEnv,
2313
+ ): Promise<Record<string, SkcTeamWorkerIntegrationState>> {
2314
+ const integrationByWorker: Record<string, SkcTeamWorkerIntegrationState> = {
2315
+ ...(previous?.integration_by_worker ?? {}),
2316
+ };
2317
+ const hygieneEntries: SkcTeamCommitHygieneEntry[] = [];
2318
+ const leaderCwd = config.leader_cwd || cwd;
2319
+ const cycleLeaderHead = resolveHead(leaderCwd);
2320
+ for (const worker of config.workers) {
2321
+ if (!worker.worktree_path || !worker.worktree_repo_root || !(await pathExists(worker.worktree_path))) continue;
2322
+ const { committed, commit } = autoCommitDirtyWorker(worker);
2323
+ if (!committed) continue;
2324
+ await appendIntegrationEvent(dir, "worker_auto_commit", worker, {
2325
+ worker_name: worker.id,
2326
+ commit_hash: commit,
2327
+ worktree_path: worker.worktree_path,
2328
+ summary: `auto-committed dirty worktree for ${worker.id}`,
2329
+ });
2330
+ hygieneEntries.push({
2331
+ recorded_at: now(),
2332
+ operation: "auto_checkpoint",
2333
+ worker_name: worker.id,
2334
+ task_id: worker.assigned_tasks[0],
2335
+ status: "applied",
2336
+ operational_commit: commit,
2337
+ worktree_path: worker.worktree_path,
2338
+ detail: "Dirty worker worktree checkpointed before integration.",
2339
+ });
2340
+ }
2341
+
2342
+ for (const worker of config.workers) {
2343
+ if (!worker.worktree_path || !worker.worktree_repo_root || !(await pathExists(worker.worktree_path))) continue;
2344
+ const leaderHead = resolveHead(leaderCwd);
2345
+ const workerHead = resolveHead(worker.worktree_path);
2346
+ const state: SkcTeamWorkerIntegrationState = {
2347
+ ...(integrationByWorker[worker.id] ?? {}),
2348
+ last_leader_head: leaderHead ?? integrationByWorker[worker.id]?.last_leader_head,
2349
+ };
2350
+ if (!leaderHead || !workerHead) {
2351
+ integrationByWorker[worker.id] = state;
2352
+ continue;
2353
+ }
2354
+ state.last_seen_head = workerHead;
2355
+ if (isAncestor(leaderCwd, workerHead, "HEAD")) {
2356
+ integrationByWorker[worker.id] = {
2357
+ ...state,
2358
+ last_integrated_head: workerHead,
2359
+ ...integrationNowState("idle"),
2360
+ };
2361
+ continue;
2362
+ }
2363
+ if (isAncestor(worker.worktree_path, leaderHead, workerHead)) {
2364
+ const mergeRef = workerMergeRef(worker, workerHead);
2365
+ const merge = runGitResult(leaderCwd, ["merge", "--no-ff", "-m", `skc(team): merge ${worker.id}`, mergeRef]);
2366
+ if (merge.ok) {
2367
+ const newLeaderHead = resolveHead(leaderCwd);
2368
+ if (newLeaderHead && newLeaderHead !== leaderHead && isAncestor(leaderCwd, workerHead, "HEAD")) {
2369
+ integrationByWorker[worker.id] = {
2370
+ ...state,
2371
+ last_integrated_head: workerHead,
2372
+ last_leader_head: newLeaderHead,
2373
+ conflict_commit: undefined,
2374
+ conflict_files: undefined,
2375
+ ...integrationNowState("integrated"),
2376
+ };
2377
+ await appendIntegrationEvent(dir, "worker_merge_applied", worker, {
2378
+ worker_name: worker.id,
2379
+ worker_head: workerHead,
2380
+ leader_head_before: leaderHead,
2381
+ leader_head_after: newLeaderHead,
2382
+ worktree_path: worker.worktree_path,
2383
+ summary: `merged ${worker.id} into leader`,
2384
+ });
2385
+ await notifyLeader(
2386
+ config,
2387
+ worker,
2388
+ `INTEGRATED: merged ${worker.id} ${workerHead.slice(0, 12)} into leader.`,
2389
+ cwd,
2390
+ env,
2391
+ );
2392
+ hygieneEntries.push({
2393
+ recorded_at: now(),
2394
+ operation: "integration_merge",
2395
+ worker_name: worker.id,
2396
+ task_id: worker.assigned_tasks[0],
2397
+ status: "applied",
2398
+ operational_commit: newLeaderHead,
2399
+ source_commit: workerHead,
2400
+ leader_head_before: leaderHead,
2401
+ leader_head_after: newLeaderHead,
2402
+ worktree_path: worker.worktree_path,
2403
+ detail: "Leader created a runtime merge commit to integrate worker history.",
2404
+ });
2405
+ } else {
2406
+ integrationByWorker[worker.id] = { ...state, ...integrationNowState("integration_failed") };
2407
+ hygieneEntries.push({
2408
+ recorded_at: now(),
2409
+ operation: "integration_merge",
2410
+ worker_name: worker.id,
2411
+ task_id: worker.assigned_tasks[0],
2412
+ status: "failed",
2413
+ source_commit: workerHead,
2414
+ leader_head_before: leaderHead,
2415
+ leader_head_after: newLeaderHead,
2416
+ worktree_path: worker.worktree_path,
2417
+ detail: "Runtime merge succeeded but did not advance the leader head.",
2418
+ });
2419
+ await notifyLeader(
2420
+ config,
2421
+ worker,
2422
+ `INTEGRATION FAILED: merge for ${worker.id} did not advance leader HEAD.`,
2423
+ cwd,
2424
+ env,
2425
+ );
2426
+ }
2427
+ } else {
2428
+ const conflictFiles = listConflictFiles(leaderCwd);
2429
+ runGitResult(leaderCwd, ["merge", "--abort"]);
2430
+ integrationByWorker[worker.id] = {
2431
+ ...state,
2432
+ conflict_commit: workerHead,
2433
+ conflict_files: conflictFiles,
2434
+ ...integrationNowState("merge_conflict"),
2435
+ };
2436
+ await appendIntegrationEvent(dir, "worker_merge_conflict", worker, {
2437
+ worker_name: worker.id,
2438
+ worker_head: workerHead,
2439
+ conflict_files: conflictFiles,
2440
+ stderr: merge.stderr || merge.stdout,
2441
+ summary: `merge conflict for ${worker.id}`,
2442
+ });
2443
+ await appendIntegrationReport(dir, {
2444
+ worker: worker.id,
2445
+ operation: "merge",
2446
+ files: conflictFiles,
2447
+ detail: `merge --no-ff failed and was aborted: ${(merge.stderr || merge.stdout).slice(0, 200)}`,
2448
+ });
2449
+ await notifyIntegrationConflict(
2450
+ config,
2451
+ worker,
2452
+ `CONFLICT: merge failed for ${worker.id}; files: ${conflictFiles.join(",") || "unknown"}. Manual resolution required; runtime aborted the merge and did not auto-resolve.`,
2453
+ cwd,
2454
+ env,
2455
+ );
2456
+ hygieneEntries.push({
2457
+ recorded_at: now(),
2458
+ operation: "integration_merge",
2459
+ worker_name: worker.id,
2460
+ task_id: worker.assigned_tasks[0],
2461
+ status: "conflict",
2462
+ source_commit: workerHead,
2463
+ leader_head_before: leaderHead,
2464
+ leader_head_after: resolveHead(leaderCwd),
2465
+ worktree_path: worker.worktree_path,
2466
+ detail: `Runtime merge failed and was aborted: ${(merge.stderr || merge.stdout).slice(0, 200)}`,
2467
+ });
2468
+ }
2469
+ continue;
2470
+ }
2471
+
2472
+ const baseline =
2473
+ state.last_integrated_head &&
2474
+ tryRunGit(worker.worktree_path, ["rev-parse", "--verify", state.last_integrated_head])
2475
+ ? state.last_integrated_head
2476
+ : leaderHead;
2477
+ const commits = listCommitRange(worker.worktree_path, baseline, workerHead);
2478
+ for (const commit of commits) {
2479
+ const pick = runGitResult(leaderCwd, ["cherry-pick", "--allow-empty", commit]);
2480
+ if (!pick.ok) {
2481
+ const conflictFiles = listConflictFiles(leaderCwd);
2482
+ runGitResult(leaderCwd, ["cherry-pick", "--abort"]);
2483
+ integrationByWorker[worker.id] = {
2484
+ ...state,
2485
+ conflict_commit: commit,
2486
+ conflict_files: conflictFiles,
2487
+ ...integrationNowState("cherry_pick_conflict"),
2488
+ };
2489
+ await appendIntegrationEvent(dir, "worker_cherry_pick_conflict", worker, {
2490
+ worker_name: worker.id,
2491
+ commit,
2492
+ conflict_files: conflictFiles,
2493
+ stderr: pick.stderr || pick.stdout,
2494
+ summary: `cherry-pick conflict for ${worker.id}`,
2495
+ });
2496
+ await appendIntegrationReport(dir, {
2497
+ worker: worker.id,
2498
+ operation: "cherry-pick",
2499
+ files: conflictFiles,
2500
+ detail: `cherry-pick failed and was aborted: ${(pick.stderr || pick.stdout).slice(0, 200)}`,
2501
+ });
2502
+ await notifyIntegrationConflict(
2503
+ config,
2504
+ worker,
2505
+ `CONFLICT: cherry-pick failed for ${worker.id}; files: ${conflictFiles.join(",") || "unknown"}. Manual resolution required; runtime aborted the cherry-pick and did not auto-resolve.`,
2506
+ cwd,
2507
+ env,
2508
+ );
2509
+ hygieneEntries.push({
2510
+ recorded_at: now(),
2511
+ operation: "integration_cherry_pick",
2512
+ worker_name: worker.id,
2513
+ task_id: worker.assigned_tasks[0],
2514
+ status: "conflict",
2515
+ source_commit: commit,
2516
+ leader_head_before: leaderHead,
2517
+ leader_head_after: resolveHead(leaderCwd),
2518
+ worktree_path: worker.worktree_path,
2519
+ detail: `Runtime cherry-pick failed and was aborted: ${(pick.stderr || pick.stdout).slice(0, 200)}`,
2520
+ });
2521
+ break;
2522
+ }
2523
+ const newLeaderHead = resolveHead(leaderCwd);
2524
+ if (!newLeaderHead || newLeaderHead === leaderHead) {
2525
+ integrationByWorker[worker.id] = { ...state, ...integrationNowState("integration_failed") };
2526
+ hygieneEntries.push({
2527
+ recorded_at: now(),
2528
+ operation: "integration_cherry_pick",
2529
+ worker_name: worker.id,
2530
+ task_id: worker.assigned_tasks[0],
2531
+ status: "failed",
2532
+ source_commit: commit,
2533
+ leader_head_before: leaderHead,
2534
+ leader_head_after: newLeaderHead,
2535
+ worktree_path: worker.worktree_path,
2536
+ detail: "Runtime cherry-pick did not advance the leader head.",
2537
+ });
2538
+ break;
2539
+ }
2540
+ integrationByWorker[worker.id] = {
2541
+ ...state,
2542
+ last_integrated_head: commit,
2543
+ last_leader_head: newLeaderHead,
2544
+ conflict_commit: undefined,
2545
+ conflict_files: undefined,
2546
+ ...integrationNowState("integrated"),
2547
+ };
2548
+ await appendIntegrationEvent(dir, "worker_cherry_pick_applied", worker, {
2549
+ worker_name: worker.id,
2550
+ commit,
2551
+ leader_head_before: leaderHead,
2552
+ leader_head_after: newLeaderHead,
2553
+ worktree_path: worker.worktree_path,
2554
+ summary: `cherry-picked ${commit.slice(0, 12)} from ${worker.id}`,
2555
+ });
2556
+ await notifyLeader(
2557
+ config,
2558
+ worker,
2559
+ `INTEGRATED: cherry-picked ${commit.slice(0, 12)} from ${worker.id}.`,
2560
+ cwd,
2561
+ env,
2562
+ );
2563
+ hygieneEntries.push({
2564
+ recorded_at: now(),
2565
+ operation: "integration_cherry_pick",
2566
+ worker_name: worker.id,
2567
+ task_id: worker.assigned_tasks[0],
2568
+ status: "applied",
2569
+ operational_commit: newLeaderHead,
2570
+ source_commit: commit,
2571
+ leader_head_before: leaderHead,
2572
+ leader_head_after: newLeaderHead,
2573
+ worktree_path: worker.worktree_path,
2574
+ detail: "Leader cherry-picked diverged worker history.",
2575
+ });
2576
+ }
2577
+ }
2578
+
2579
+ const newLeaderHead = resolveHead(leaderCwd);
2580
+ if (cycleLeaderHead && newLeaderHead && cycleLeaderHead !== newLeaderHead) {
2581
+ for (const worker of config.workers) {
2582
+ if (!worker.worktree_path || !(await pathExists(worker.worktree_path))) continue;
2583
+ const status = await readSkcWorkerStatus(config.team_name, worker.id, cwd, env);
2584
+ if (!["idle", "done", "failed"].includes(status.state)) {
2585
+ await appendIntegrationEvent(dir, "worker_cross_rebase_skipped", worker, {
2586
+ worker_name: worker.id,
2587
+ worker_state: status.state,
2588
+ leader_head: newLeaderHead,
2589
+ summary: `skipped cross-rebase for ${worker.id}`,
2590
+ });
2591
+ hygieneEntries.push({
2592
+ recorded_at: now(),
2593
+ operation: "cross_rebase",
2594
+ worker_name: worker.id,
2595
+ task_id: worker.assigned_tasks[0],
2596
+ status: "skipped",
2597
+ leader_head_after: newLeaderHead,
2598
+ worktree_path: worker.worktree_path,
2599
+ detail: `Worker state ${status.state} is not eligible for automatic cross-rebase.`,
2600
+ });
2601
+ continue;
2602
+ }
2603
+ if (worktreeIsDirty(worker.worktree_path)) {
2604
+ hygieneEntries.push({
2605
+ recorded_at: now(),
2606
+ operation: "cross_rebase",
2607
+ worker_name: worker.id,
2608
+ task_id: worker.assigned_tasks[0],
2609
+ status: "skipped",
2610
+ leader_head_after: newLeaderHead,
2611
+ worktree_path: worker.worktree_path,
2612
+ detail: "Worker worktree is dirty after integration; automatic cross-rebase skipped.",
2613
+ });
2614
+ continue;
2615
+ }
2616
+ const before = resolveHead(worker.worktree_path);
2617
+ const rebase = runGitResult(worker.worktree_path, ["rebase", newLeaderHead]);
2618
+ if (rebase.ok) {
2619
+ const after = resolveHead(worker.worktree_path);
2620
+ integrationByWorker[worker.id] = {
2621
+ ...(integrationByWorker[worker.id] ?? {}),
2622
+ last_rebased_leader_head: newLeaderHead,
2623
+ conflict_commit: undefined,
2624
+ conflict_files: undefined,
2625
+ ...integrationNowState("idle"),
2626
+ };
2627
+ await appendIntegrationEvent(dir, "worker_cross_rebase_applied", worker, {
2628
+ worker_name: worker.id,
2629
+ leader_head: newLeaderHead,
2630
+ worktree_path: worker.worktree_path,
2631
+ summary: `cross-rebased ${worker.id}`,
2632
+ });
2633
+ hygieneEntries.push({
2634
+ recorded_at: now(),
2635
+ operation: "cross_rebase",
2636
+ worker_name: worker.id,
2637
+ task_id: worker.assigned_tasks[0],
2638
+ status: "applied",
2639
+ operational_commit: after,
2640
+ leader_head_after: newLeaderHead,
2641
+ worker_head_before: before,
2642
+ worker_head_after: after,
2643
+ worktree_path: worker.worktree_path,
2644
+ detail: "Runtime rebase moved worker history onto updated leader head.",
2645
+ });
2646
+ } else {
2647
+ const conflictFiles = listConflictFiles(worker.worktree_path);
2648
+ runGitResult(worker.worktree_path, ["rebase", "--abort"]);
2649
+ integrationByWorker[worker.id] = {
2650
+ ...(integrationByWorker[worker.id] ?? {}),
2651
+ conflict_commit: before ?? newLeaderHead,
2652
+ conflict_files: conflictFiles,
2653
+ ...integrationNowState("rebase_conflict"),
2654
+ };
2655
+ await appendIntegrationEvent(dir, "worker_cross_rebase_conflict", worker, {
2656
+ worker_name: worker.id,
2657
+ leader_head: newLeaderHead,
2658
+ conflict_files: conflictFiles,
2659
+ stderr: rebase.stderr || rebase.stdout,
2660
+ summary: `cross-rebase conflict for ${worker.id}`,
2661
+ });
2662
+ await appendIntegrationReport(dir, {
2663
+ worker: worker.id,
2664
+ operation: "rebase",
2665
+ files: conflictFiles,
2666
+ detail: `rebase failed and was aborted: ${(rebase.stderr || rebase.stdout).slice(0, 200)}`,
2667
+ });
2668
+ await notifyIntegrationConflict(
2669
+ config,
2670
+ worker,
2671
+ `CONFLICT: cross-rebase failed for ${worker.id}; files: ${conflictFiles.join(",") || "unknown"}. Manual resolution required; runtime aborted the rebase and did not auto-resolve.`,
2672
+ cwd,
2673
+ env,
2674
+ );
2675
+ hygieneEntries.push({
2676
+ recorded_at: now(),
2677
+ operation: "cross_rebase",
2678
+ worker_name: worker.id,
2679
+ task_id: worker.assigned_tasks[0],
2680
+ status: "conflict",
2681
+ leader_head_after: newLeaderHead,
2682
+ worker_head_before: before,
2683
+ worker_head_after: resolveHead(worker.worktree_path),
2684
+ worktree_path: worker.worktree_path,
2685
+ detail: `Runtime cross-rebase failed and was aborted: ${(rebase.stderr || rebase.stdout).slice(0, 200)}`,
2686
+ });
2687
+ }
2688
+ }
2689
+ }
2690
+ await appendCommitHygieneEntries(config, hygieneEntries);
2691
+ return integrationByWorker;
2692
+ }
2693
+
2694
+ async function initializeStateDirs(dir: string, workers: SkcTeamWorker[]): Promise<void> {
2695
+ // Empty mailbox directories are runtime state, so they must exist before messages arrive.
2696
+ await fs.mkdir(path.join(dir, "mailbox"), { recursive: true });
2697
+ for (const worker of workers) {
2698
+ await fs.mkdir(mailboxDirPath(dir, worker.id), { recursive: true });
2699
+ await writeJsonFile(mailboxPath(dir, worker.id), { messages: [] });
2700
+ await writeJsonFile(path.join(workerDir(dir, worker.id), "status.json"), { state: "idle", updated_at: now() });
2701
+ await writeJsonFile(workerLifecyclePath(dir, worker.id), {
2702
+ worker: worker.id,
2703
+ lifecycle_state: "starting",
2704
+ worker_status_state: "idle",
2705
+ updated_at: now(),
2706
+ } satisfies SkcTeamWorkerLifecycle);
2707
+ await writeJsonFile(path.join(workerDir(dir, worker.id), "heartbeat.json"), {
2708
+ pid: 0,
2709
+ last_turn_at: now(),
2710
+ turn_count: 0,
2711
+ alive: true,
2712
+ });
2713
+ }
2714
+ // Empty leader mailbox directory is runtime state, so it must exist before messages arrive.
2715
+ await fs.mkdir(mailboxDirPath(dir, "leader-fixed"), { recursive: true });
2716
+ await writeJsonFile(mailboxPath(dir, "leader-fixed"), { messages: [] });
2717
+ }
2718
+
2719
+ export async function startSkcTeam(options: SkcTeamStartOptions): Promise<SkcTeamSnapshot> {
2720
+ const cwd = options.cwd ?? process.cwd();
2721
+ const env = options.env ?? process.env;
2722
+ if (!Number.isInteger(options.workerCount) || options.workerCount < 1 || options.workerCount > SKC_TEAM_MAX_WORKERS)
2723
+ throw new Error(`invalid_team_worker_count:${options.workerCount}:expected_1_${SKC_TEAM_MAX_WORKERS}`);
2724
+ const workerCliPlan = resolveSkcTeamWorkerCliPlan(options.workerCount, env);
2725
+ const stateRoot = resolveSkcTeamStateRoot(cwd, env);
2726
+ const teamName = sanitizeName(options.teamName ?? makeTeamName(options.task, env));
2727
+ const displayName = sanitizeName(options.teamName ?? options.task).slice(0, 30) || teamName;
2728
+ const dir = teamDir(stateRoot, teamName);
2729
+ const createdAt = now();
2730
+ const worktreeMode = resolveDefaultWorktreeMode(options.worktreeMode);
2731
+ const tmuxCommand = resolveSkcTmuxCommand(env);
2732
+ const tmuxContext = options.dryRun
2733
+ ? { sessionName: "dry-run", windowIndex: "0", leaderPaneId: "%dry-run-leader", target: "dry-run:0" }
2734
+ : readCurrentTmuxLeaderContext(tmuxCommand, env);
2735
+ const initialWorkers = buildWorkers(options.workerCount, options.agentType, stateRoot);
2736
+ const initialTasks = buildInitialTasks(options.task, initialWorkers);
2737
+ const workers: SkcTeamWorker[] = [];
2738
+ try {
2739
+ for (const worker of initialWorkers)
2740
+ workers.push(options.dryRun ? worker : await ensureWorkerWorktree(cwd, dir, teamName, worker, worktreeMode));
2741
+ } catch (error) {
2742
+ await rollbackCreatedWorktrees(workers);
2743
+ throw error;
2744
+ }
2745
+ const config: SkcTeamConfig = {
2746
+ team_name: teamName,
2747
+ display_name: displayName,
2748
+ requested_name: options.teamName ?? displayName,
2749
+ task: options.task,
2750
+ agent_type: options.agentType,
2751
+ worker_count: options.workerCount,
2752
+ max_workers: SKC_TEAM_MAX_WORKERS,
2753
+ state_root: stateRoot,
2754
+ worker_command: resolveSkcWorkerCommand(cwd, env),
2755
+ worker_cli_plan: workerCliPlan,
2756
+ tmux_command: tmuxCommand,
2757
+ tmux_session: tmuxContext.sessionName,
2758
+ tmux_session_name: tmuxContext.sessionName,
2759
+ tmux_target: tmuxContext.target,
2760
+ workspace_mode: worktreeMode.enabled ? "worktree" : "direct",
2761
+ dry_run: options.dryRun ?? false,
2762
+ leader: { session_id: env.SKC_SESSION_ID ?? env.CODEX_SESSION_ID ?? "", pane_id: tmuxContext.leaderPaneId, cwd },
2763
+ leader_cwd: cwd,
2764
+ team_state_root: stateRoot,
2765
+ workers,
2766
+ created_at: createdAt,
2767
+ updated_at: createdAt,
2768
+ };
2769
+ await initializeStateDirs(dir, config.workers);
2770
+ await writeJsonFile(path.join(dir, "config.json"), config);
2771
+ await writeJsonFile(path.join(dir, "manifest.v2.json"), {
2772
+ version: 2,
2773
+ team_name: config.team_name,
2774
+ display_name: config.display_name,
2775
+ requested_name: config.requested_name,
2776
+ tmux_session: config.tmux_session,
2777
+ tmux_session_name: config.tmux_session_name,
2778
+ tmux_target: config.tmux_target,
2779
+ worker_command: config.worker_command,
2780
+ worker_cli_plan: config.worker_cli_plan,
2781
+ tmux_command: config.tmux_command,
2782
+ leader: config.leader,
2783
+ workers: config.workers,
2784
+ workspace_mode: config.workspace_mode,
2785
+ dry_run: config.dry_run,
2786
+ created_at: createdAt,
2787
+ updated_at: createdAt,
2788
+ });
2789
+ await writePhase(dir, "starting");
2790
+ for (const task of initialTasks) await writeTask(dir, task);
2791
+ await appendEvent(dir, {
2792
+ type: "team_started",
2793
+ message: options.dryRun
2794
+ ? "Created native skc team dry-run state without starting tmux workers"
2795
+ : "Started native skc team runtime",
2796
+ data: {
2797
+ worker_count: options.workerCount,
2798
+ agent_type: options.agentType,
2799
+ workspace_mode: config.workspace_mode,
2800
+ dry_run: config.dry_run,
2801
+ },
2802
+ });
2803
+ await appendTelemetry(dir, {
2804
+ type: "team_runtime",
2805
+ message: options.dryRun ? "Native skc team dry-run state initialized" : "Native skc team runtime initialized",
2806
+ data: {
2807
+ state_root: stateRoot,
2808
+ worker_command: config.worker_command,
2809
+ worker_cli_plan: workerCliPlan,
2810
+ workspace_mode: config.workspace_mode,
2811
+ dry_run: config.dry_run,
2812
+ },
2813
+ });
2814
+ let tmuxWorkers: SkcTeamWorker[];
2815
+ try {
2816
+ tmuxWorkers = await startTmuxSession(config, dir, options.dryRun ?? false, env);
2817
+ } catch (error) {
2818
+ await writePhase(dir, "failed");
2819
+ await appendEvent(dir, {
2820
+ type: "team_start_failed",
2821
+ message: error instanceof Error ? error.message : String(error),
2822
+ });
2823
+ killWorkerPanes(config);
2824
+ await rollbackCreatedWorktrees(config.workers);
2825
+ throw error;
2826
+ }
2827
+ const runningConfig = {
2828
+ ...config,
2829
+ workers: tmuxWorkers.map(worker => ({ ...worker, status: "idle" as const, last_heartbeat: now() })),
2830
+ updated_at: now(),
2831
+ };
2832
+ await writeJsonFile(path.join(dir, "config.json"), runningConfig);
2833
+ await writeWorkerLifecycleForConfig(dir, runningConfig, "starting", worker => ({
2834
+ pane_id: worker.pane_id,
2835
+ started_at: runningConfig.created_at,
2836
+ }));
2837
+ await writePhase(dir, "running");
2838
+ return readSkcTeamSnapshot(teamName, cwd, env);
2839
+ }
2840
+
2841
+ export async function readSkcTeamSnapshot(
2842
+ teamName: string,
2843
+ cwd = process.cwd(),
2844
+ env: NodeJS.ProcessEnv = process.env,
2845
+ options: SkcTeamSnapshotOptions = {},
2846
+ ): Promise<SkcTeamSnapshot> {
2847
+ const dir = await findTeamDir(teamName, cwd, env);
2848
+ const config = await readConfig(dir);
2849
+ const storedPhase = await readPhase(dir);
2850
+ const tasks = await readTasks(dir);
2851
+ const taskCounts: Record<SkcTeamTaskStatus, number> = {
2852
+ pending: 0,
2853
+ blocked: 0,
2854
+ in_progress: 0,
2855
+ completed: 0,
2856
+ failed: 0,
2857
+ };
2858
+ for (const task of tasks) taskCounts[task.status] += 1;
2859
+ const monitor = await readJsonFile<SkcTeamMonitorSnapshot>(monitorSnapshotPath(dir));
2860
+ const workerLifecycleById = await readWorkerLifecycleById(dir, config);
2861
+ const notificationSummary =
2862
+ options.reconcileNotifications === true
2863
+ ? await reconcileTeamNotifications(dir, config)
2864
+ : summarizeNotifications(await listNotificationRecords(dir));
2865
+ const phase = await resolveSkcTeamSnapshotPhase(dir, config, storedPhase, tasks, monitor);
2866
+ return {
2867
+ team_name: config.team_name,
2868
+ display_name: config.display_name,
2869
+ phase,
2870
+ state_dir: dir,
2871
+ tmux_session: config.tmux_session,
2872
+ tmux_session_name: config.tmux_session_name,
2873
+ tmux_target: config.tmux_target,
2874
+ task_total: tasks.length,
2875
+ task_counts: taskCounts,
2876
+ workers: config.workers,
2877
+ integration_by_worker: monitor?.integration_by_worker,
2878
+ worker_lifecycle_by_id: workerLifecycleById,
2879
+ notification_summary: notificationSummary,
2880
+ updated_at: config.updated_at,
2881
+ };
2882
+ }
2883
+ export async function monitorSkcTeamSnapshot(
2884
+ teamName: string,
2885
+ cwd = process.cwd(),
2886
+ env: NodeJS.ProcessEnv = process.env,
2887
+ ): Promise<SkcTeamSnapshot> {
2888
+ const snapshot = await monitorSkcTeam(teamName, cwd, env);
2889
+ return snapshot;
2890
+ }
2891
+ function workerIntegrationFingerprint(head: string | null, classification: SkcWorkerCheckpointClassification): string {
2892
+ return `${head ?? "no-head"}:${classification.kind}:${classification.files.join("\0")}`;
2893
+ }
2894
+
2895
+ export async function requestSkcWorkerIntegrationAttempt(
2896
+ cwd = process.cwd(),
2897
+ env: NodeJS.ProcessEnv = process.env,
2898
+ ): Promise<SkcWorkerIntegrationAttemptRequestResult> {
2899
+ const teamName = env.SKC_TEAM_NAME?.trim();
2900
+ const worker = env.SKC_TEAM_WORKER_ID?.trim() || env.SKC_TEAM_INTERNAL_WORKER?.split("/").pop()?.trim();
2901
+ if (!teamName || !worker) return { requested: false, reason: "not_worker" };
2902
+ const dir = await findTeamDir(teamName, cwd, env);
2903
+ const config = await readConfig(dir);
2904
+ const configuredWorker = config.workers.find(candidate => candidate.id === worker);
2905
+ const worktreePath = env.SKC_TEAM_WORKTREE_PATH?.trim() || configuredWorker?.worktree_path;
2906
+ if (!worktreePath || !(await pathExists(worktreePath)))
2907
+ return { requested: false, reason: "missing_worktree", worker, team_name: teamName };
2908
+ const classification = classifyWorkerCheckpointStatus(worktreePath);
2909
+ const head = resolveHead(worktreePath);
2910
+ if (classification.kind === "git_error") {
2911
+ return { requested: false, reason: "git_error", worker, team_name: teamName, head, status: classification.kind };
2912
+ }
2913
+ if (classification.kind === "protected_only") {
2914
+ return { requested: false, reason: "no_changes", worker, team_name: teamName, head, status: classification.kind };
2915
+ }
2916
+ if (classification.kind === "clean" && configuredWorker?.worktree_base_ref === head) {
2917
+ return { requested: false, reason: "no_changes", worker, team_name: teamName, head, status: classification.kind };
2918
+ }
2919
+ const fingerprint = workerIntegrationFingerprint(head, classification);
2920
+ const dedupePath = workerIntegrationDedupePath(dir, worker);
2921
+ const dedupe = (await readJsonFile<SkcWorkerIntegrationDedupeState>(dedupePath)) ?? {};
2922
+ if (dedupe.last_requested_fingerprint === fingerprint) {
2923
+ return {
2924
+ requested: false,
2925
+ reason: "deduped",
2926
+ worker,
2927
+ team_name: teamName,
2928
+ fingerprint,
2929
+ head,
2930
+ status: classification.kind,
2931
+ };
2932
+ }
2933
+ await writeJsonFile(dedupePath, {
2934
+ last_requested_fingerprint: fingerprint,
2935
+ last_requested_head: head,
2936
+ last_requested_status: classification.kind,
2937
+ last_requested_at: now(),
2938
+ } satisfies SkcWorkerIntegrationDedupeState);
2939
+ await appendEvent(dir, {
2940
+ type: "worker_integration_attempt_requested",
2941
+ worker,
2942
+ message: `Worker ${worker} requested leader integration attempt`,
2943
+ data: { worker_name: worker, worker_head: head, status: classification.kind, files: classification.files },
2944
+ });
2945
+ await sendSkcTeamMessage(
2946
+ teamName,
2947
+ worker,
2948
+ "leader-fixed",
2949
+ `INTEGRATION REQUESTED: ${worker} has ${classification.kind} git changes at ${head?.slice(0, 12) ?? "unknown-head"}.`,
2950
+ cwd,
2951
+ env,
2952
+ ).catch(() => undefined);
2953
+ await appendCommitHygieneEntries(config, [
2954
+ {
2955
+ recorded_at: now(),
2956
+ operation: "leader_integration_attempt",
2957
+ worker_name: worker,
2958
+ task_id: configuredWorker?.assigned_tasks[0],
2959
+ status: "applied",
2960
+ source_commit: head ?? undefined,
2961
+ worker_head_after: head,
2962
+ worktree_path: worktreePath,
2963
+ detail: "Worker turn-end requested a leader integration attempt for semantic git changes.",
2964
+ },
2965
+ ]);
2966
+ return {
2967
+ requested: true,
2968
+ reason: "requested",
2969
+ worker,
2970
+ team_name: teamName,
2971
+ fingerprint,
2972
+ head,
2973
+ status: classification.kind,
2974
+ };
2975
+ }
2976
+
2977
+ export async function buildTeamHudSummary(
2978
+ snapshot: SkcTeamSnapshot,
2979
+ latestEvent?: SkcTeamEvent,
2980
+ latestMessage?: SkcTeamMailboxMessage,
2981
+ ): Promise<WorkflowHudSummary> {
2982
+ return buildWorkflowTeamHudSummary({
2983
+ phase: snapshot.phase,
2984
+ task_total: snapshot.task_total,
2985
+ task_counts: snapshot.task_counts,
2986
+ workers: snapshot.workers,
2987
+ updated_at: snapshot.updated_at,
2988
+ latestEvent,
2989
+ latestMessage,
2990
+ });
2991
+ }
2992
+
2993
+ export async function monitorSkcTeam(
2994
+ teamName: string,
2995
+ cwd = process.cwd(),
2996
+ env: NodeJS.ProcessEnv = process.env,
2997
+ ): Promise<SkcTeamSnapshot> {
2998
+ const dir = await findTeamDir(teamName, cwd, env);
2999
+ const config = await readConfig(dir);
3000
+ const previous = await readJsonFile<SkcTeamMonitorSnapshot>(monitorSnapshotPath(dir));
3001
+ await reconcileSkcTeamStaleClaims(teamName, dir, config, env);
3002
+ const integrationByWorker = await integrateSkcWorkerCommits(config, dir, previous, cwd, env);
3003
+ await writeJsonFile(monitorSnapshotPath(dir), { integration_by_worker: integrationByWorker, updated_at: now() });
3004
+ await replaySkcTeamNotifications(teamName, cwd, env);
3005
+ await computeLifecycleNudges(config, dir, cwd, env);
3006
+ return readSkcTeamSnapshot(teamName, cwd, env);
3007
+ }
3008
+ export async function listSkcTeams(
3009
+ cwd = process.cwd(),
3010
+ env: NodeJS.ProcessEnv = process.env,
3011
+ ): Promise<SkcTeamSnapshot[]> {
3012
+ const root = resolveSkcTeamStateRoot(cwd, env);
3013
+ try {
3014
+ const entries = await fs.readdir(root, { withFileTypes: true });
3015
+ const snapshots = await Promise.all(
3016
+ entries
3017
+ .filter(entry => entry.isDirectory())
3018
+ .map(entry => readSkcTeamSnapshot(entry.name, cwd, env).catch(() => null)),
3019
+ );
3020
+ return snapshots.filter((snapshot): snapshot is SkcTeamSnapshot => snapshot != null);
3021
+ } catch (error) {
3022
+ if (isEnoent(error)) return [];
3023
+ throw error;
3024
+ }
3025
+ }
3026
+
3027
+ function parsePaneAttemptResult(value: string): SkcTeamPaneAttemptResult {
3028
+ if (value === "sent" || value === "queued" || value === "deferred" || value === "failed") return value;
3029
+ throw new Error(`invalid_pane_attempt_result:${value}`);
3030
+ }
3031
+ async function writeSkcWorkerStartupAck(
3032
+ teamName: string,
3033
+ worker: string,
3034
+ cwd: string,
3035
+ env: NodeJS.ProcessEnv,
3036
+ input: Record<string, unknown>,
3037
+ ): Promise<Record<string, unknown>> {
3038
+ const dir = await findTeamDir(teamName, cwd, env);
3039
+ const config = await readConfig(dir);
3040
+ const teamWorker = findKnownWorker(config, worker);
3041
+ const ack = {
3042
+ worker,
3043
+ pid: typeof input.pid === "number" ? input.pid : undefined,
3044
+ session: typeof input.session === "string" ? input.session : undefined,
3045
+ protocol_version: String(input.protocol_version ?? "1"),
3046
+ ack_at: now(),
3047
+ };
3048
+ await writeJsonFile(path.join(workerDir(dir, worker), "startup-ack.json"), ack);
3049
+ await writeWorkerLifecycleRecord(dir, teamWorker, "ready", {
3050
+ pane_id: teamWorker.pane_id,
3051
+ pid: typeof input.pid === "number" ? input.pid : undefined,
3052
+ started_at: ack.ack_at,
3053
+ });
3054
+ await appendEvent(dir, { type: "worker_startup_ack", worker, message: `Worker ${worker} acknowledged startup` });
3055
+ return ack;
3056
+ }
3057
+ function parseDurationEnv(env: NodeJS.ProcessEnv, name: string, fallbackMs: number): number {
3058
+ const raw = env[name]?.trim();
3059
+ if (!raw) return fallbackMs;
3060
+ const parsed = Number(raw);
3061
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallbackMs;
3062
+ }
3063
+ async function writeLifecycleNudge(
3064
+ dir: string,
3065
+ worker: string,
3066
+ condition: string,
3067
+ severity: "warning" | "error",
3068
+ suggestedAction: string,
3069
+ env: NodeJS.ProcessEnv,
3070
+ ): Promise<void> {
3071
+ const fingerprint = `nudge-${stableHash([worker, condition].join(":"))}`;
3072
+ const nudgePath = path.join(workerDir(dir, worker), "nudges", `${fingerprint}.json`);
3073
+ const existing = await readJsonFile<Record<string, unknown>>(nudgePath);
3074
+ const nowMs = Date.now();
3075
+ const cooldownMs = parseDurationEnv(env, "SKC_TEAM_NUDGE_COOLDOWN_MS", 30_000);
3076
+ const cooldownUntil = typeof existing?.cooldown_until === "string" ? Date.parse(existing.cooldown_until) : 0;
3077
+ if (existing && Number.isFinite(cooldownUntil) && cooldownUntil > nowMs) return;
3078
+ const firstSeen = typeof existing?.first_seen_at === "string" ? existing.first_seen_at : now();
3079
+ const count = typeof existing?.count === "number" ? existing.count + 1 : 1;
3080
+ const record = {
3081
+ fingerprint,
3082
+ worker,
3083
+ condition,
3084
+ severity,
3085
+ first_seen_at: firstSeen,
3086
+ last_seen_at: now(),
3087
+ cooldown_until: new Date(nowMs + cooldownMs).toISOString(),
3088
+ count,
3089
+ suggested_action: suggestedAction,
3090
+ auto_action_taken: false,
3091
+ };
3092
+ await writeJsonFile(nudgePath, record);
3093
+ await appendEvent(dir, {
3094
+ type: "worker_lifecycle_nudge",
3095
+ worker,
3096
+ message: suggestedAction,
3097
+ data: { condition, severity, fingerprint, auto_action_taken: false },
3098
+ });
3099
+ await writeNotificationRecord(dir, {
3100
+ id: `ntf-${stableHash(["worker_lifecycle", worker, condition].join(":"))}`,
3101
+ kind: "worker_lifecycle",
3102
+ team_name: path.basename(dir),
3103
+ recipient: "leader-fixed",
3104
+ source: { type: "worker", id: worker },
3105
+ delivery_state: "pending",
3106
+ created_at: firstSeen,
3107
+ updated_at: now(),
3108
+ replay_count: 0,
3109
+ });
3110
+ }
3111
+ async function computeLifecycleNudges(
3112
+ config: SkcTeamConfig,
3113
+ dir: string,
3114
+ _cwd: string,
3115
+ env: NodeJS.ProcessEnv,
3116
+ ): Promise<void> {
3117
+ const startupGraceMs = parseDurationEnv(env, "SKC_TEAM_STARTUP_GRACE_MS", 30_000);
3118
+ const heartbeatStaleMs = parseDurationEnv(env, "SKC_TEAM_HEARTBEAT_STALE_MS", 120_000);
3119
+ const createdAt = Date.parse(config.created_at);
3120
+ const ageMs = Date.now() - (Number.isFinite(createdAt) ? createdAt : Date.now());
3121
+ for (const worker of config.workers) {
3122
+ const ack = await readJsonFile<Record<string, unknown>>(path.join(workerDir(dir, worker.id), "startup-ack.json"));
3123
+ if (!ack && ageMs >= startupGraceMs) {
3124
+ await writeLifecycleNudge(
3125
+ dir,
3126
+ worker.id,
3127
+ "missing_startup_ack",
3128
+ "warning",
3129
+ `Worker ${worker.id} has not sent startup ACK; leader may inspect or relaunch manually.`,
3130
+ env,
3131
+ );
3132
+ }
3133
+ const heartbeat = await readSkcWorkerHeartbeat(config.team_name, worker.id, config.leader.cwd, {
3134
+ ...env,
3135
+ SKC_TEAM_STATE_ROOT: config.state_root,
3136
+ });
3137
+ const heartbeatAt = Date.parse(heartbeat?.last_turn_at ?? worker.last_heartbeat);
3138
+ if (Number.isFinite(heartbeatAt) && Date.now() - heartbeatAt >= heartbeatStaleMs) {
3139
+ await writeLifecycleNudge(
3140
+ dir,
3141
+ worker.id,
3142
+ "stale_heartbeat",
3143
+ "warning",
3144
+ `Worker ${worker.id} heartbeat is stale; leader may inspect or relaunch manually.`,
3145
+ env,
3146
+ );
3147
+ }
3148
+ if (worker.status === "stopped") {
3149
+ await writeLifecycleNudge(
3150
+ dir,
3151
+ worker.id,
3152
+ "worker_stopped",
3153
+ "error",
3154
+ `Worker ${worker.id} is stopped before team completion; leader action is required.`,
3155
+ env,
3156
+ );
3157
+ }
3158
+ }
3159
+ }
3160
+
3161
+ export async function shutdownSkcTeam(
3162
+ teamName: string,
3163
+ cwd = process.cwd(),
3164
+ env: NodeJS.ProcessEnv = process.env,
3165
+ ): Promise<SkcTeamSnapshot> {
3166
+ const dir = await findTeamDir(teamName, cwd, env);
3167
+ const config = await readConfig(dir);
3168
+ const tasks = await readTasks(dir);
3169
+ const evidenceFailures = tasks
3170
+ .map(task => {
3171
+ const reason = task.status === "completed" ? getSkcTeamTaskCompletionEvidenceFailure(task) : null;
3172
+ return reason ? { task_id: task.id, reason } : null;
3173
+ })
3174
+ .filter((failure): failure is { task_id: string; reason: string } => failure != null);
3175
+ const shutdownRequestId = `shutdown-${stableHash([config.team_name, now(), randomUUID()].join(":"))}`;
3176
+ const shutdownRequestedAt = now();
3177
+ await Promise.all(
3178
+ config.workers.map(worker =>
3179
+ writeSkcShutdownRequest(
3180
+ teamName,
3181
+ worker.id,
3182
+ "leader-fixed",
3183
+ cwd,
3184
+ env,
3185
+ shutdownRequestId,
3186
+ "graceful",
3187
+ shutdownRequestedAt,
3188
+ ),
3189
+ ),
3190
+ );
3191
+ const monitor = await readJsonFile<SkcTeamMonitorSnapshot>(monitorSnapshotPath(dir));
3192
+ const completionVerified = tasks.length === 0 || tasks.every(isSkcTeamTaskCompletionVerified);
3193
+ const pendingIntegration = completionVerified ? await hasPendingSkcTeamIntegration(dir, config, monitor) : false;
3194
+ killWorkerPanes(config);
3195
+ await removeCleanCreatedWorktrees(config.workers);
3196
+ const stopped = {
3197
+ ...config,
3198
+ workers: config.workers.map(worker => ({ ...worker, status: "stopped" as const, last_heartbeat: now() })),
3199
+ updated_at: now(),
3200
+ };
3201
+ await writeJsonFile(path.join(dir, "config.json"), stopped);
3202
+ await writeWorkerLifecycleForConfig(dir, stopped, "stopped", worker => ({
3203
+ pane_id: worker.pane_id,
3204
+ stopped_at: stopped.updated_at,
3205
+ stop_reason: "graceful_shutdown",
3206
+ shutdown_request_id: shutdownRequestId,
3207
+ shutdown_requested_at: shutdownRequestedAt,
3208
+ shutdown_mode: "graceful",
3209
+ }));
3210
+ const workerLifecycleById = await readWorkerLifecycleById(dir, stopped);
3211
+ const gracefulShutdownComplete = stopped.workers.every(worker => {
3212
+ const lifecycle = workerLifecycleById[worker.id];
3213
+ return (
3214
+ lifecycle?.lifecycle_state === "stopped" &&
3215
+ lifecycle.shutdown_request_id === shutdownRequestId &&
3216
+ lifecycle.shutdown_mode === "graceful"
3217
+ );
3218
+ });
3219
+ const shutdownPhase: SkcTeamPhase =
3220
+ completionVerified && gracefulShutdownComplete
3221
+ ? pendingIntegration
3222
+ ? "awaiting_integration"
3223
+ : "complete"
3224
+ : evidenceFailures.length > 0 || tasks.some(task => task.status === "failed" || task.status === "blocked")
3225
+ ? "failed"
3226
+ : "cancelled";
3227
+ await writePhase(dir, shutdownPhase);
3228
+ const shutdownData: Record<string, unknown> = {
3229
+ phase: shutdownPhase,
3230
+ shutdown_request_id: shutdownRequestId,
3231
+ graceful_shutdown_complete: gracefulShutdownComplete,
3232
+ };
3233
+ if (evidenceFailures.length > 0) shutdownData.evidence_failures = evidenceFailures;
3234
+ await appendEvent(dir, {
3235
+ type: "team_shutdown",
3236
+ message:
3237
+ shutdownPhase === "complete"
3238
+ ? "Shut down native skc team runtime after completed tasks"
3239
+ : "Shut down native skc team runtime with incomplete tasks",
3240
+ data: shutdownData,
3241
+ });
3242
+ await appendTelemetry(dir, {
3243
+ type: "team_shutdown",
3244
+ message: `Native skc team runtime stopped with phase ${shutdownPhase}`,
3245
+ data: { shutdown_request_id: shutdownRequestId, graceful_shutdown_complete: gracefulShutdownComplete },
3246
+ });
3247
+ return readSkcTeamSnapshot(config.team_name, cwd, env);
3248
+ }
3249
+
3250
+ export async function listSkcTeamTasks(
3251
+ teamName: string,
3252
+ cwd = process.cwd(),
3253
+ env: NodeJS.ProcessEnv = process.env,
3254
+ ): Promise<SkcTeamTask[]> {
3255
+ return readTasks(await findTeamDir(teamName, cwd, env));
3256
+ }
3257
+ export async function readSkcTeamTask(
3258
+ teamName: string,
3259
+ taskId: string,
3260
+ cwd = process.cwd(),
3261
+ env: NodeJS.ProcessEnv = process.env,
3262
+ ): Promise<SkcTeamTask> {
3263
+ const task = (await listSkcTeamTasks(teamName, cwd, env)).find(candidate => candidate.id === taskId);
3264
+ if (!task) throw new Error(`task_not_found:${taskId}`);
3265
+ return task;
3266
+ }
3267
+ export async function createSkcTeamTask(
3268
+ teamName: string,
3269
+ subject: string,
3270
+ description: string,
3271
+ cwd = process.cwd(),
3272
+ env: NodeJS.ProcessEnv = process.env,
3273
+ taskOptions: SkcTeamTaskMetadataInput = {},
3274
+ ): Promise<SkcTeamTask> {
3275
+ const dir = await findTeamDir(teamName, cwd, env);
3276
+ const config = await readConfig(dir);
3277
+ if (taskOptions.owner) assertKnownWorker(config, taskOptions.owner);
3278
+ const tasks = await readTasks(dir);
3279
+ const next = tasks.length + 1;
3280
+ const task: SkcTeamTask = {
3281
+ id: `task-${next}`,
3282
+ subject,
3283
+ description,
3284
+ title: subject,
3285
+ objective: description,
3286
+ status: "pending",
3287
+ ...(taskOptions.owner ? { owner: taskOptions.owner } : {}),
3288
+ ...(taskOptions.lane ? { lane: taskOptions.lane } : {}),
3289
+ ...(taskOptions.required_role ? { required_role: taskOptions.required_role } : {}),
3290
+ ...(taskOptions.allowed_roles ? { allowed_roles: taskOptions.allowed_roles } : {}),
3291
+ ...(taskOptions.depends_on ? { depends_on: taskOptions.depends_on } : {}),
3292
+ ...(taskOptions.blocked_by ? { blocked_by: taskOptions.blocked_by } : {}),
3293
+ version: 1,
3294
+ created_at: now(),
3295
+ updated_at: now(),
3296
+ };
3297
+ await writeTask(dir, task);
3298
+ config.updated_at = now();
3299
+ await writeJsonFile(path.join(dir, "config.json"), config);
3300
+ await appendEvent(dir, { type: "task_created", task_id: task.id, message: subject });
3301
+ return task;
3302
+ }
3303
+ export async function updateSkcTeamTask(
3304
+ teamName: string,
3305
+ taskId: string,
3306
+ updates: Partial<
3307
+ Pick<
3308
+ SkcTeamTask,
3309
+ "subject" | "description" | "blocked_by" | "depends_on" | "lane" | "required_role" | "allowed_roles"
3310
+ >
3311
+ >,
3312
+ cwd = process.cwd(),
3313
+ env: NodeJS.ProcessEnv = process.env,
3314
+ ): Promise<SkcTeamTask> {
3315
+ const dir = await findTeamDir(teamName, cwd, env);
3316
+ const task = await readSkcTeamTask(teamName, taskId, cwd, env);
3317
+ const updated = normalizeTask({
3318
+ ...task,
3319
+ ...updates,
3320
+ title: updates.subject ?? task.title,
3321
+ objective: updates.description ?? task.objective,
3322
+ version: task.version + 1,
3323
+ updated_at: now(),
3324
+ });
3325
+ await writeTask(dir, updated);
3326
+ await appendEvent(dir, { type: "task_updated", task_id: taskId, message: updated.subject });
3327
+ return updated;
3328
+ }
3329
+ export async function claimSkcTeamTask(
3330
+ teamName: string,
3331
+ workerId: string,
3332
+ cwd = process.cwd(),
3333
+ env: NodeJS.ProcessEnv = process.env,
3334
+ taskId?: string,
3335
+ ): Promise<SkcTeamApiClaimResult> {
3336
+ const dir = await findTeamDir(teamName, cwd, env);
3337
+ const config = await readConfig(dir);
3338
+ const teamWorker = findKnownWorker(config, workerId);
3339
+ const livenessRecovery = await reconcileSkcTeamStaleClaims(teamName, dir, config, env);
3340
+ const staleWorkerReasons = livenessRecovery.stale_workers[workerId];
3341
+ if (staleWorkerReasons?.length)
3342
+ return { ok: false, reason: `worker_not_live:${workerId}:${staleWorkerReasons.join(",")}` };
3343
+ const tasks = await readTasks(dir);
3344
+ const task = taskId
3345
+ ? tasks.find(candidate => candidate.id === taskId)
3346
+ : tasks.find(candidate => getSkcTeamTaskClaimEligibilityReason(candidate, teamWorker, tasks) == null);
3347
+ if (!task) return { ok: false, reason: taskId ? `task_not_found:${taskId}` : "no_pending_task" };
3348
+ const eligibilityReason = getSkcTeamTaskClaimEligibilityReason(task, teamWorker, tasks);
3349
+ if (eligibilityReason) return { ok: false, reason: eligibilityReason };
3350
+ const activeClaimReason = await getActiveClaimReason(dir, task);
3351
+ if (activeClaimReason) return { ok: false, reason: activeClaimReason };
3352
+ const token = randomUUID();
3353
+ const claim: SkcTeamTaskClaim = {
3354
+ owner: workerId,
3355
+ token,
3356
+ leased_until: new Date(Date.now() + 30 * 60_000).toISOString(),
3357
+ };
3358
+ const claimPath = path.join(dir, "claims", `${task.id}.json`);
3359
+ const created = await writeJsonFileNoClobber(claimPath, claim);
3360
+ if (!created) return { ok: false, reason: `task_already_claimed:${task.id}` };
3361
+ const current = await readSkcTeamTask(teamName, task.id, cwd, env);
3362
+ const currentEligibilityReason = getSkcTeamTaskClaimEligibilityReason(current, teamWorker, await readTasks(dir));
3363
+ if (currentEligibilityReason) {
3364
+ await fs.rm(claimPath, { force: true });
3365
+ return { ok: false, reason: currentEligibilityReason };
3366
+ }
3367
+ if (current.status !== "pending") {
3368
+ await deleteIfOwned(claimPath, {
3369
+ ...stateWriterOptions(claimPath, "prune", "rollback"),
3370
+ predicate: current => (current as SkcTeamTaskClaim).token === token,
3371
+ });
3372
+ return { ok: false, reason: `task_not_pending:${task.id}` };
3373
+ }
3374
+ const updated: SkcTeamTask = {
3375
+ ...current,
3376
+ status: "in_progress",
3377
+ assignee: workerId,
3378
+ owner: workerId,
3379
+ claim,
3380
+ version: current.version + 1,
3381
+ updated_at: now(),
3382
+ };
3383
+ try {
3384
+ await writeTask(dir, updated);
3385
+ } catch (error) {
3386
+ await deleteIfOwned(claimPath, {
3387
+ ...stateWriterOptions(claimPath, "prune", "rollback"),
3388
+ predicate: current => (current as SkcTeamTaskClaim).token === token,
3389
+ });
3390
+ throw error;
3391
+ }
3392
+ await appendEvent(dir, {
3393
+ type: "task_claimed",
3394
+ task_id: updated.id,
3395
+ worker: workerId,
3396
+ message: "Worker claimed task",
3397
+ });
3398
+ return { ok: true, task: updated, worker_id: workerId, claim_token: token };
3399
+ }
3400
+ export async function transitionSkcTeamTaskStatus(
3401
+ teamName: string,
3402
+ taskId: string,
3403
+ status: SkcTeamTaskStatus,
3404
+ cwd = process.cwd(),
3405
+ env: NodeJS.ProcessEnv = process.env,
3406
+ claimToken?: string,
3407
+ workerId?: string,
3408
+ completionEvidenceInput?: unknown,
3409
+ ): Promise<SkcTeamTask> {
3410
+ const dir = await findTeamDir(teamName, cwd, env);
3411
+ const config = await readConfig(dir);
3412
+ const task = await readSkcTeamTask(teamName, taskId, cwd, env);
3413
+ if (workerId) assertKnownWorker(config, workerId);
3414
+ if (status === "pending") throw new Error(`invalid_task_transition:${taskId}:pending_requires_release`);
3415
+ if (task.status === "completed" || task.status === "failed") throw new Error(`task_terminal:${taskId}`);
3416
+ if (!task.claim) throw new Error(`claim_token_required:${taskId}`);
3417
+ if (!claimToken) throw new Error(`claim_token_required:${taskId}`);
3418
+ if (task.claim.token !== claimToken) throw new Error(`claim_token_mismatch:${taskId}`);
3419
+ if (workerId && task.claim.owner !== workerId) throw new Error(`claim_owner_mismatch:${taskId}`);
3420
+ const terminal = status === "completed" || status === "failed";
3421
+ const transitionedAt = now();
3422
+ const completionEvidence =
3423
+ status === "completed"
3424
+ ? normalizeSkcTeamTaskCompletionEvidence(taskId, task.claim.owner, completionEvidenceInput, transitionedAt)
3425
+ : undefined;
3426
+ const updated: SkcTeamTask = {
3427
+ ...task,
3428
+ status,
3429
+ claim: terminal ? undefined : task.claim,
3430
+ version: task.version + 1,
3431
+ updated_at: transitionedAt,
3432
+ ...(terminal ? { completed_at: transitionedAt } : {}),
3433
+ ...(completionEvidence ? { completion_evidence: completionEvidence } : {}),
3434
+ };
3435
+ await writeTask(dir, updated);
3436
+ if (terminal) {
3437
+ const claimPath = path.join(dir, "claims", `${taskId}.json`);
3438
+ await removeFileAudited(claimPath, stateWriterOptions(claimPath, "prune", "terminal"));
3439
+ }
3440
+ const eventData: Record<string, unknown> = { status };
3441
+ if (completionEvidence) {
3442
+ eventData.completion_evidence = {
3443
+ recorded_by: completionEvidence.recorded_by,
3444
+ item_count: completionEvidence.items.length,
3445
+ verified_item_count: completionEvidence.items.filter(isSkcTeamCompletionEvidenceItemVerified).length,
3446
+ files_count: completionEvidence.files?.length ?? 0,
3447
+ };
3448
+ }
3449
+ await appendEvent(dir, {
3450
+ type: "task_transitioned",
3451
+ task_id: taskId,
3452
+ message: "Task status changed",
3453
+ data: eventData,
3454
+ });
3455
+ return updated;
3456
+ }
3457
+ export async function transitionSkcTeamTask(
3458
+ teamName: string,
3459
+ taskId: string,
3460
+ status: SkcTeamTaskStatus | "complete",
3461
+ cwd = process.cwd(),
3462
+ env: NodeJS.ProcessEnv = process.env,
3463
+ claimToken?: string,
3464
+ completionEvidenceInput?: unknown,
3465
+ ): Promise<SkcTeamTask> {
3466
+ return transitionSkcTeamTaskStatus(
3467
+ teamName,
3468
+ taskId,
3469
+ parseSkcTeamTaskStatus(status, true),
3470
+ cwd,
3471
+ env,
3472
+ claimToken,
3473
+ undefined,
3474
+ completionEvidenceInput,
3475
+ );
3476
+ }
3477
+ export async function releaseSkcTeamTaskClaim(
3478
+ teamName: string,
3479
+ taskId: string,
3480
+ claimToken: string,
3481
+ workerId: string,
3482
+ cwd = process.cwd(),
3483
+ env: NodeJS.ProcessEnv = process.env,
3484
+ ): Promise<SkcTeamTask> {
3485
+ const dir = await findTeamDir(teamName, cwd, env);
3486
+ const task = await readSkcTeamTask(teamName, taskId, cwd, env);
3487
+ if (!task.claim || task.claim.token !== claimToken || task.claim.owner !== workerId)
3488
+ throw new Error(`claim_token_mismatch:${taskId}`);
3489
+ const updated: SkcTeamTask = {
3490
+ ...task,
3491
+ status: "pending",
3492
+ assignee: undefined,
3493
+ claim: undefined,
3494
+ version: task.version + 1,
3495
+ updated_at: now(),
3496
+ };
3497
+ await writeTask(dir, updated);
3498
+ const claimPath = path.join(dir, "claims", `${taskId}.json`);
3499
+ await deleteIfOwned(claimPath, {
3500
+ ...stateWriterOptions(claimPath, "prune", "release"),
3501
+ predicate: current => (current as SkcTeamTaskClaim).token === claimToken,
3502
+ });
3503
+ await appendEvent(dir, {
3504
+ type: "task_claim_released",
3505
+ task_id: taskId,
3506
+ worker: workerId,
3507
+ message: "Task claim released",
3508
+ });
3509
+ return updated;
3510
+ }
3511
+
3512
+ function emptyNotificationSummary(): SkcTeamNotificationSummary {
3513
+ return {
3514
+ total: 0,
3515
+ replay_eligible: 0,
3516
+ by_state: {
3517
+ pending: 0,
3518
+ sent: 0,
3519
+ queued: 0,
3520
+ deferred: 0,
3521
+ failed: 0,
3522
+ delivered: 0,
3523
+ acknowledged: 0,
3524
+ },
3525
+ };
3526
+ }
3527
+ function isReplayEligibleNotification(state: SkcTeamNotificationDeliveryState): boolean {
3528
+ return state === "pending" || state === "queued" || state === "deferred" || state === "failed";
3529
+ }
3530
+ function summarizeNotifications(notifications: SkcTeamNotification[]): SkcTeamNotificationSummary {
3531
+ const summary = emptyNotificationSummary();
3532
+ for (const notification of notifications) {
3533
+ summary.total += 1;
3534
+ summary.by_state[notification.delivery_state] += 1;
3535
+ if (isReplayEligibleNotification(notification.delivery_state)) summary.replay_eligible += 1;
3536
+ }
3537
+ return summary;
3538
+ }
3539
+ async function listNotificationRecords(dir: string): Promise<SkcTeamNotification[]> {
3540
+ const notificationsDir = path.join(dir, "notifications");
3541
+ try {
3542
+ const entries = await fs.readdir(notificationsDir, { withFileTypes: true });
3543
+ const records = await Promise.all(
3544
+ entries
3545
+ .filter(entry => entry.isFile() && entry.name.endsWith(".json"))
3546
+ .map(entry => readJsonFile<SkcTeamNotification>(path.join(notificationsDir, entry.name))),
3547
+ );
3548
+ return records
3549
+ .filter((record): record is SkcTeamNotification => record != null)
3550
+ .sort((a, b) => a.id.localeCompare(b.id));
3551
+ } catch (error) {
3552
+ if (isEnoent(error)) return [];
3553
+ throw error;
3554
+ }
3555
+ }
3556
+ async function readNotificationRecord(dir: string, notificationId: string): Promise<SkcTeamNotification> {
3557
+ assertSafeId("notification_id", notificationId);
3558
+ const notification = await readJsonFile<SkcTeamNotification>(notificationPath(dir, notificationId));
3559
+ if (!notification) throw new Error(`notification_not_found:${notificationId}`);
3560
+ return notification;
3561
+ }
3562
+ function mergeNotificationState(
3563
+ current: SkcTeamNotificationDeliveryState,
3564
+ next: SkcTeamNotificationDeliveryState,
3565
+ ): SkcTeamNotificationDeliveryState {
3566
+ const rank: Record<SkcTeamNotificationDeliveryState, number> = {
3567
+ pending: 0,
3568
+ queued: 1,
3569
+ deferred: 1,
3570
+ failed: 1,
3571
+ sent: 2,
3572
+ delivered: 3,
3573
+ acknowledged: 4,
3574
+ };
3575
+ return rank[next] >= rank[current] ? next : current;
3576
+ }
3577
+ async function writeNotificationRecord(dir: string, notification: SkcTeamNotification): Promise<SkcTeamNotification> {
3578
+ const existing = await readJsonFile<SkcTeamNotification>(notificationPath(dir, notification.id));
3579
+ const merged: SkcTeamNotification = existing
3580
+ ? {
3581
+ ...existing,
3582
+ ...notification,
3583
+ delivery_state: mergeNotificationState(existing.delivery_state, notification.delivery_state),
3584
+ created_at: existing.created_at,
3585
+ replay_count: Math.max(existing.replay_count ?? 0, notification.replay_count ?? 0),
3586
+ updated_at: now(),
3587
+ }
3588
+ : notification;
3589
+ await writeJsonFile(notificationPath(dir, merged.id), merged);
3590
+ return merged;
3591
+ }
3592
+ async function createMessageNotification(
3593
+ dir: string,
3594
+ teamName: string,
3595
+ message: SkcTeamMailboxMessage,
3596
+ state: SkcTeamNotificationDeliveryState = "pending",
3597
+ ): Promise<SkcTeamNotification> {
3598
+ const id = messageNotificationId(teamName, message.to_worker, message.message_id);
3599
+ return writeNotificationRecord(dir, {
3600
+ id,
3601
+ kind: "mailbox_message",
3602
+ team_name: teamName,
3603
+ recipient: message.to_worker,
3604
+ source: { type: "message", id: message.message_id },
3605
+ idempotency_key: message.idempotency_key,
3606
+ delivery_state: state,
3607
+ created_at: message.created_at,
3608
+ updated_at: now(),
3609
+ replay_count: 0,
3610
+ });
3611
+ }
3612
+ async function readLegacyMailbox(dir: string, worker: string): Promise<{ messages: SkcTeamMailboxMessage[] }> {
3613
+ return (await readJsonFile<{ messages: SkcTeamMailboxMessage[] }>(mailboxPath(dir, worker))) ?? { messages: [] };
3614
+ }
3615
+ async function readMailbox(dir: string, worker: string): Promise<{ messages: SkcTeamMailboxMessage[] }> {
3616
+ assertSafeId("worker_id", worker);
3617
+ const byId = new Map<string, SkcTeamMailboxMessage>();
3618
+ for (const message of (await readLegacyMailbox(dir, worker)).messages ?? []) byId.set(message.message_id, message);
3619
+ try {
3620
+ const entries = await fs.readdir(mailboxDirPath(dir, worker), { withFileTypes: true });
3621
+ const records = await Promise.all(
3622
+ entries
3623
+ .filter(entry => entry.isFile() && entry.name.endsWith(".json"))
3624
+ .map(entry => readJsonFile<SkcTeamMailboxMessage>(path.join(mailboxDirPath(dir, worker), entry.name))),
3625
+ );
3626
+ for (const message of records) if (message) byId.set(message.message_id, message);
3627
+ } catch (error) {
3628
+ if (!isEnoent(error)) throw error;
3629
+ }
3630
+ return { messages: [...byId.values()].sort((a, b) => a.created_at.localeCompare(b.created_at)) };
3631
+ }
3632
+ async function writeLegacyMailboxView(dir: string, worker: string): Promise<void> {
3633
+ const current = await readMailbox(dir, worker);
3634
+ await writeJsonFile(mailboxPath(dir, worker), current);
3635
+ }
3636
+ async function writeMailboxMessage(
3637
+ dir: string,
3638
+ worker: string,
3639
+ message: SkcTeamMailboxMessage,
3640
+ ): Promise<SkcTeamMailboxMessage> {
3641
+ assertSafeId("message_id", message.message_id);
3642
+ const filePath = mailboxMessagePath(dir, worker, message.message_id);
3643
+ const existing = await readJsonFile<SkcTeamMailboxMessage>(filePath);
3644
+ if (existing) {
3645
+ if (
3646
+ existing.from_worker !== message.from_worker ||
3647
+ existing.to_worker !== message.to_worker ||
3648
+ existing.body !== message.body
3649
+ ) {
3650
+ throw new Error(`message_id_conflict:${message.message_id}`);
3651
+ }
3652
+ const merged = {
3653
+ ...existing,
3654
+ ...message,
3655
+ notified_at: existing.notified_at ?? message.notified_at,
3656
+ delivered_at: existing.delivered_at ?? message.delivered_at,
3657
+ };
3658
+ await writeJsonFile(filePath, merged);
3659
+ await writeLegacyMailboxView(dir, worker);
3660
+ return merged;
3661
+ }
3662
+ const created = await writeJsonFileNoClobber(filePath, message);
3663
+ if (!created) return writeMailboxMessage(dir, worker, message);
3664
+ await writeLegacyMailboxView(dir, worker);
3665
+ return message;
3666
+ }
3667
+ async function reconcileTeamNotifications(dir: string, config: SkcTeamConfig): Promise<SkcTeamNotificationSummary> {
3668
+ for (const recipient of ["leader-fixed", ...config.workers.map(worker => worker.id)]) {
3669
+ const mailbox = await readMailbox(dir, recipient);
3670
+ for (const message of mailbox.messages) {
3671
+ const state = message.delivered_at ? "acknowledged" : message.notified_at ? "delivered" : "pending";
3672
+ await createMessageNotification(dir, config.team_name, message, state);
3673
+ }
3674
+ }
3675
+ return summarizeNotifications(await listNotificationRecords(dir));
3676
+ }
3677
+ async function attemptPaneNotification(
3678
+ dir: string,
3679
+ config: SkcTeamConfig,
3680
+ notification: SkcTeamNotification,
3681
+ env: NodeJS.ProcessEnv,
3682
+ ): Promise<SkcTeamNotification> {
3683
+ const paneId =
3684
+ notification.recipient === "leader-fixed"
3685
+ ? config.leader.pane_id
3686
+ : config.workers.find(worker => worker.id === notification.recipient)?.pane_id;
3687
+ let result: SkcTeamPaneAttemptResult = "deferred";
3688
+ let reason = "pane_missing";
3689
+ if (paneId) {
3690
+ if (config.tmux_session === "dry-run" || env.SKC_TEAM_FAKE_PANE_ATTEMPT === "sent") {
3691
+ result = "sent";
3692
+ reason = "dry_run_or_fake_tmux";
3693
+ } else {
3694
+ result = "queued";
3695
+ reason = "tmux_delivery_recorded_without_injection";
3696
+ }
3697
+ }
3698
+ return writeNotificationRecord(dir, {
3699
+ ...notification,
3700
+ delivery_state: result,
3701
+ pane_attempt_result: result,
3702
+ pane_attempt_reason: reason,
3703
+ pane_attempt_at: now(),
3704
+ updated_at: now(),
3705
+ });
3706
+ }
3707
+ export async function replaySkcTeamNotifications(
3708
+ teamName: string,
3709
+ cwd = process.cwd(),
3710
+ env: NodeJS.ProcessEnv = process.env,
3711
+ ): Promise<{ notifications: SkcTeamNotification[]; summary: SkcTeamNotificationSummary }> {
3712
+ const dir = await findTeamDir(teamName, cwd, env);
3713
+ const config = await readConfig(dir);
3714
+ await reconcileTeamNotifications(dir, config);
3715
+ const next: SkcTeamNotification[] = [];
3716
+ for (const notification of await listNotificationRecords(dir)) {
3717
+ if (!isReplayEligibleNotification(notification.delivery_state)) {
3718
+ next.push(notification);
3719
+ continue;
3720
+ }
3721
+ const attempted = await attemptPaneNotification(
3722
+ dir,
3723
+ config,
3724
+ {
3725
+ ...notification,
3726
+ replay_count: (notification.replay_count ?? 0) + 1,
3727
+ },
3728
+ env,
3729
+ );
3730
+ next.push(attempted);
3731
+ }
3732
+ return { notifications: next, summary: summarizeNotifications(next) };
3733
+ }
3734
+ export async function sendSkcTeamMessage(
3735
+ teamName: string,
3736
+ fromWorker: string,
3737
+ toWorker: string,
3738
+ body: string,
3739
+ cwd = process.cwd(),
3740
+ env: NodeJS.ProcessEnv = process.env,
3741
+ idempotencyKey?: string,
3742
+ ): Promise<SkcTeamMailboxMessage> {
3743
+ const dir = await findTeamDir(teamName, cwd, env);
3744
+ const config = await readConfig(dir);
3745
+ assertKnownParticipant(config, fromWorker);
3746
+ assertKnownParticipant(config, toWorker);
3747
+ const createdKey = idempotencyKey ?? randomUUID();
3748
+ const message: SkcTeamMailboxMessage = {
3749
+ message_id: messageIdFor({ teamName: config.team_name, fromWorker, toWorker, body, idempotencyKey, createdKey }),
3750
+ from_worker: fromWorker,
3751
+ to_worker: toWorker,
3752
+ body,
3753
+ created_at: now(),
3754
+ ...(idempotencyKey ? { idempotency_key: idempotencyKey } : {}),
3755
+ };
3756
+ const written = await writeMailboxMessage(dir, toWorker, message);
3757
+ const notification = await createMessageNotification(dir, config.team_name, written);
3758
+ await attemptPaneNotification(dir, config, notification, env);
3759
+ await appendEvent(dir, {
3760
+ type: "message_sent",
3761
+ worker: fromWorker,
3762
+ message: body,
3763
+ data: { to_worker: toWorker, message_id: written.message_id },
3764
+ });
3765
+ return written;
3766
+ }
3767
+ export async function broadcastSkcTeamMessage(
3768
+ teamName: string,
3769
+ fromWorker: string,
3770
+ body: string,
3771
+ cwd = process.cwd(),
3772
+ env: NodeJS.ProcessEnv = process.env,
3773
+ idempotencyKey?: string,
3774
+ ): Promise<SkcTeamMailboxMessage[]> {
3775
+ const config = await readConfig(await findTeamDir(teamName, cwd, env));
3776
+ return Promise.all(
3777
+ config.workers.map(worker =>
3778
+ sendSkcTeamMessage(
3779
+ teamName,
3780
+ fromWorker,
3781
+ worker.id,
3782
+ body,
3783
+ cwd,
3784
+ env,
3785
+ idempotencyKey ? `${idempotencyKey}:${worker.id}` : undefined,
3786
+ ),
3787
+ ),
3788
+ );
3789
+ }
3790
+ export async function listSkcTeamMailbox(
3791
+ teamName: string,
3792
+ worker: string,
3793
+ cwd = process.cwd(),
3794
+ env: NodeJS.ProcessEnv = process.env,
3795
+ ): Promise<SkcTeamMailboxMessage[]> {
3796
+ const dir = await findTeamDir(teamName, cwd, env);
3797
+ const config = await readConfig(dir);
3798
+ assertKnownParticipant(config, worker);
3799
+ return (await readMailbox(dir, worker)).messages;
3800
+ }
3801
+ export async function markSkcTeamMailboxMessage(
3802
+ teamName: string,
3803
+ worker: string,
3804
+ messageId: string,
3805
+ field: "delivered_at" | "notified_at",
3806
+ cwd = process.cwd(),
3807
+ env: NodeJS.ProcessEnv = process.env,
3808
+ ): Promise<SkcTeamMailboxMessage> {
3809
+ assertSafeId("message_id", messageId);
3810
+ const dir = await findTeamDir(teamName, cwd, env);
3811
+ const config = await readConfig(dir);
3812
+ assertKnownParticipant(config, worker);
3813
+ const mailbox = await readMailbox(dir, worker);
3814
+ const message = mailbox.messages.find(candidate => candidate.message_id === messageId);
3815
+ if (!message) throw new Error(`message_not_found:${messageId}`);
3816
+ const updated = { ...message, [field]: message[field] ?? now() };
3817
+ const written = await writeMailboxMessage(dir, worker, updated);
3818
+ const notificationId = messageNotificationId(config.team_name, worker, messageId);
3819
+ const existing =
3820
+ (await readJsonFile<SkcTeamNotification>(notificationPath(dir, notificationId))) ??
3821
+ (await createMessageNotification(dir, config.team_name, written));
3822
+ const nextState: SkcTeamNotificationDeliveryState = field === "delivered_at" ? "acknowledged" : "delivered";
3823
+ const before = existing.delivery_state;
3824
+ await writeNotificationRecord(dir, { ...existing, delivery_state: nextState, updated_at: now() });
3825
+ if (mergeNotificationState(before, nextState) !== before)
3826
+ await appendEvent(dir, {
3827
+ type: `message_${field === "delivered_at" ? "acknowledged" : "notified"}`,
3828
+ worker,
3829
+ message: messageId,
3830
+ });
3831
+ return written;
3832
+ }
3833
+ export async function readSkcWorkerStatus(
3834
+ teamName: string,
3835
+ worker: string,
3836
+ cwd = process.cwd(),
3837
+ env: NodeJS.ProcessEnv = process.env,
3838
+ ): Promise<WorkerStatusFile> {
3839
+ const dir = await findTeamDir(teamName, cwd, env);
3840
+ const config = await readConfig(dir);
3841
+ assertKnownWorker(config, worker);
3842
+ return readWorkerStatusFile(dir, worker);
3843
+ }
3844
+ export async function updateSkcWorkerStatus(
3845
+ teamName: string,
3846
+ worker: string,
3847
+ status: SkcWorkerStatusState,
3848
+ cwd = process.cwd(),
3849
+ env: NodeJS.ProcessEnv = process.env,
3850
+ currentTaskId?: string,
3851
+ reason?: string,
3852
+ ): Promise<WorkerStatusFile> {
3853
+ const dir = await findTeamDir(teamName, cwd, env);
3854
+ const config = await readConfig(dir);
3855
+ const teamWorker = findKnownWorker(config, worker);
3856
+ if (currentTaskId) assertSafeId("task_id", currentTaskId);
3857
+ const trimmedReason = reason?.trim();
3858
+ const value: WorkerStatusFile = {
3859
+ state: status,
3860
+ ...(currentTaskId ? { current_task_id: currentTaskId } : {}),
3861
+ ...(trimmedReason ? { reason: trimmedReason } : {}),
3862
+ updated_at: now(),
3863
+ };
3864
+ await writeJsonFile(path.join(workerDir(dir, worker), "status.json"), value);
3865
+ const currentLifecycle = await readWorkerLifecycleRecord(dir, teamWorker);
3866
+ const lifecycleState =
3867
+ currentLifecycle.lifecycle_state === "stopped" ? "stopped" : lifecycleStateForWorkerStatus(status);
3868
+ await writeWorkerLifecycleRecord(dir, teamWorker, lifecycleState);
3869
+ await appendEvent(dir, {
3870
+ type: "worker_status_updated",
3871
+ worker,
3872
+ message: `Worker ${worker} reported ${status}`,
3873
+ data: {
3874
+ status,
3875
+ current_task_id: currentTaskId,
3876
+ },
3877
+ });
3878
+ return value;
3879
+ }
3880
+ export async function readSkcWorkerHeartbeat(
3881
+ teamName: string,
3882
+ worker: string,
3883
+ cwd = process.cwd(),
3884
+ env: NodeJS.ProcessEnv = process.env,
3885
+ ): Promise<WorkerHeartbeatFile | null> {
3886
+ const dir = await findTeamDir(teamName, cwd, env);
3887
+ const config = await readConfig(dir);
3888
+ assertKnownWorker(config, worker);
3889
+ return readJsonFile<WorkerHeartbeatFile>(path.join(workerDir(dir, worker), "heartbeat.json"));
3890
+ }
3891
+ export async function updateSkcWorkerHeartbeat(
3892
+ teamName: string,
3893
+ worker: string,
3894
+ heartbeat: WorkerHeartbeatFile,
3895
+ cwd = process.cwd(),
3896
+ env: NodeJS.ProcessEnv = process.env,
3897
+ ): Promise<WorkerHeartbeatFile> {
3898
+ const dir = await findTeamDir(teamName, cwd, env);
3899
+ const config = await readConfig(dir);
3900
+ assertKnownWorker(config, worker);
3901
+ const value = { ...heartbeat, last_turn_at: heartbeat.last_turn_at || now() };
3902
+ await writeJsonFile(path.join(workerDir(dir, worker), "heartbeat.json"), value);
3903
+ return value;
3904
+ }
3905
+ export async function writeSkcWorkerInbox(
3906
+ teamName: string,
3907
+ worker: string,
3908
+ content: string,
3909
+ cwd = process.cwd(),
3910
+ env: NodeJS.ProcessEnv = process.env,
3911
+ ): Promise<{ path: string }> {
3912
+ const dir = await findTeamDir(teamName, cwd, env);
3913
+ const config = await readConfig(dir);
3914
+ assertKnownWorker(config, worker);
3915
+ const filePath = path.join(workerDir(dir, worker), "inbox.md");
3916
+ await writeReport(filePath, content, stateWriterOptions(filePath, "report", "write"));
3917
+ return { path: filePath };
3918
+ }
3919
+ export async function writeSkcWorkerIdentity(
3920
+ teamName: string,
3921
+ worker: SkcTeamWorker,
3922
+ cwd = process.cwd(),
3923
+ env: NodeJS.ProcessEnv = process.env,
3924
+ ): Promise<SkcTeamWorker> {
3925
+ const dir = await findTeamDir(teamName, cwd, env);
3926
+ const config = await readConfig(dir);
3927
+ assertKnownWorker(config, worker.id);
3928
+ await writeJsonFile(path.join(workerDir(dir, worker.id), "identity.json"), worker);
3929
+ return worker;
3930
+ }
3931
+ export async function readSkcTeamEvents(
3932
+ teamName: string,
3933
+ cwd = process.cwd(),
3934
+ env: NodeJS.ProcessEnv = process.env,
3935
+ ): Promise<SkcTeamEvent[]> {
3936
+ const dir = await findTeamDir(teamName, cwd, env);
3937
+ try {
3938
+ const text = await Bun.file(path.join(dir, "events.jsonl")).text();
3939
+ return text
3940
+ .split(/\r?\n/)
3941
+ .filter(Boolean)
3942
+ .map(line => JSON.parse(line) as SkcTeamEvent);
3943
+ } catch (error) {
3944
+ if (isEnoent(error)) return [];
3945
+ throw error;
3946
+ }
3947
+ }
3948
+ export async function readSkcTeamTraces(
3949
+ teamName: string,
3950
+ cwd = process.cwd(),
3951
+ env: NodeJS.ProcessEnv = process.env,
3952
+ ): Promise<SkcTeamTraceEvent[]> {
3953
+ const dir = await findTeamDir(teamName, cwd, env);
3954
+ try {
3955
+ const text = await Bun.file(tracePath(dir)).text();
3956
+ return text
3957
+ .split(/\r?\n/)
3958
+ .filter(Boolean)
3959
+ .map(line => JSON.parse(line) as SkcTeamTraceEvent);
3960
+ } catch (error) {
3961
+ if (isEnoent(error)) return [];
3962
+ throw error;
3963
+ }
3964
+ }
3965
+ export async function appendSkcTeamEvent(
3966
+ teamName: string,
3967
+ type: string,
3968
+ worker = "leader-fixed",
3969
+ cwd = process.cwd(),
3970
+ env: NodeJS.ProcessEnv = process.env,
3971
+ ): Promise<SkcTeamEvent> {
3972
+ return appendEvent(await findTeamDir(teamName, cwd, env), { type, worker });
3973
+ }
3974
+ export async function awaitSkcTeamEvent(
3975
+ teamName: string,
3976
+ _timeoutMs = 0,
3977
+ cwd = process.cwd(),
3978
+ env: NodeJS.ProcessEnv = process.env,
3979
+ ): Promise<{ status: "event" | "timeout"; event?: SkcTeamEvent }> {
3980
+ const events = await readSkcTeamEvents(teamName, cwd, env);
3981
+ const event = events.at(-1);
3982
+ return event ? { status: "event", event } : { status: "timeout" };
3983
+ }
3984
+ export async function writeSkcMonitorSnapshot(
3985
+ teamName: string,
3986
+ snapshot: unknown,
3987
+ cwd = process.cwd(),
3988
+ env: NodeJS.ProcessEnv = process.env,
3989
+ ): Promise<unknown> {
3990
+ await writeJsonFile(monitorSnapshotPath(await findTeamDir(teamName, cwd, env)), snapshot);
3991
+ return snapshot;
3992
+ }
3993
+ export async function readSkcMonitorSnapshot(
3994
+ teamName: string,
3995
+ cwd = process.cwd(),
3996
+ env: NodeJS.ProcessEnv = process.env,
3997
+ ): Promise<unknown> {
3998
+ return readJsonFile<unknown>(monitorSnapshotPath(await findTeamDir(teamName, cwd, env)));
3999
+ }
4000
+ export async function writeSkcTaskApproval(
4001
+ teamName: string,
4002
+ taskId: string,
4003
+ approval: Record<string, unknown>,
4004
+ cwd = process.cwd(),
4005
+ env: NodeJS.ProcessEnv = process.env,
4006
+ ): Promise<Record<string, unknown>> {
4007
+ assertSafeId("task_id", taskId);
4008
+ await writeJsonFile(path.join(await findTeamDir(teamName, cwd, env), "approvals", `${taskId}.json`), approval);
4009
+ return approval;
4010
+ }
4011
+ export async function readSkcTaskApproval(
4012
+ teamName: string,
4013
+ taskId: string,
4014
+ cwd = process.cwd(),
4015
+ env: NodeJS.ProcessEnv = process.env,
4016
+ ): Promise<Record<string, unknown> | null> {
4017
+ assertSafeId("task_id", taskId);
4018
+ return readJsonFile<Record<string, unknown>>(
4019
+ path.join(await findTeamDir(teamName, cwd, env), "approvals", `${taskId}.json`),
4020
+ );
4021
+ }
4022
+ export async function writeSkcShutdownRequest(
4023
+ teamName: string,
4024
+ worker: string,
4025
+ requestedBy: string,
4026
+ cwd = process.cwd(),
4027
+ env: NodeJS.ProcessEnv = process.env,
4028
+ requestId = `shutdown-${stableHash([teamName, worker, now(), randomUUID()].join(":"))}`,
4029
+ mode: SkcTeamShutdownMode = "graceful",
4030
+ requestedAt = now(),
4031
+ ): Promise<Record<string, unknown>> {
4032
+ const dir = await findTeamDir(teamName, cwd, env);
4033
+ const config = await readConfig(dir);
4034
+ const teamWorker = findKnownWorker(config, worker);
4035
+ assertKnownParticipant(config, requestedBy);
4036
+ const value = { worker, requested_by: requestedBy, request_id: requestId, mode, requested_at: requestedAt };
4037
+ await writeJsonFile(path.join(workerDir(dir, worker), "shutdown-request.json"), value);
4038
+ await writeWorkerLifecycleRecord(dir, teamWorker, "draining", {
4039
+ shutdown_request_id: requestId,
4040
+ shutdown_requested_at: requestedAt,
4041
+ shutdown_mode: mode,
4042
+ });
4043
+ await appendEvent(dir, {
4044
+ type: "worker_shutdown_requested",
4045
+ worker,
4046
+ message: `Worker ${worker} shutdown requested`,
4047
+ data: { requested_by: requestedBy, request_id: requestId, mode },
4048
+ });
4049
+ return value;
4050
+ }
4051
+ export async function readSkcShutdownAck(
4052
+ teamName: string,
4053
+ worker: string,
4054
+ cwd = process.cwd(),
4055
+ env: NodeJS.ProcessEnv = process.env,
4056
+ ): Promise<Record<string, unknown> | null> {
4057
+ const dir = await findTeamDir(teamName, cwd, env);
4058
+ const config = await readConfig(dir);
4059
+ assertKnownWorker(config, worker);
4060
+ return readJsonFile<Record<string, unknown>>(path.join(workerDir(dir, worker), "shutdown-ack.json"));
4061
+ }
4062
+
4063
+ export async function executeSkcTeamApiOperation(
4064
+ operation: string,
4065
+ input: Record<string, unknown>,
4066
+ cwd = process.cwd(),
4067
+ env: NodeJS.ProcessEnv = process.env,
4068
+ ): Promise<unknown> {
4069
+ const teamName = String(input.team_name ?? input.teamName ?? "").trim();
4070
+ if (!teamName) throw new Error("missing_team_name");
4071
+ const workerInput = input.worker ?? input.worker_id ?? input.workerId;
4072
+ const worker = String(workerInput ?? "worker-1");
4073
+ const explicitWorker = workerInput == null ? undefined : String(workerInput);
4074
+ switch (operation) {
4075
+ case "list-tasks":
4076
+ return { tasks: await listSkcTeamTasks(teamName, cwd, env) };
4077
+ case "read-task":
4078
+ return { task: await readSkcTeamTask(teamName, String(input.task_id ?? input.taskId), cwd, env) };
4079
+ case "create-task": {
4080
+ const task = await createSkcTeamTask(
4081
+ teamName,
4082
+ String(input.subject ?? "Task"),
4083
+ String(input.description ?? ""),
4084
+ cwd,
4085
+ env,
4086
+ taskMetadataFromInput(input, true),
4087
+ );
4088
+ return { ok: true, ...taskReceiptFields(teamName, task) };
4089
+ }
4090
+ case "update-task": {
4091
+ const task = await updateSkcTeamTask(
4092
+ teamName,
4093
+ String(input.task_id ?? input.taskId),
4094
+ {
4095
+ subject: typeof input.subject === "string" ? input.subject : undefined,
4096
+ description: typeof input.description === "string" ? input.description : undefined,
4097
+ ...taskMetadataFromInput(input),
4098
+ },
4099
+ cwd,
4100
+ env,
4101
+ );
4102
+ return { ok: true, ...taskReceiptFields(teamName, task) };
4103
+ }
4104
+ case "claim-task": {
4105
+ const requestedTaskId = input.task_id ?? input.taskId;
4106
+ const result = await claimSkcTeamTask(
4107
+ teamName,
4108
+ worker,
4109
+ cwd,
4110
+ env,
4111
+ typeof requestedTaskId === "string" ? requestedTaskId : undefined,
4112
+ );
4113
+ return {
4114
+ ok: result.ok,
4115
+ reason: result.reason,
4116
+ team_name: teamName,
4117
+ worker_id: result.worker_id ?? worker,
4118
+ ...(result.task ? taskReceiptFields(teamName, result.task) : {}),
4119
+ claim_token: result.claim_token,
4120
+ };
4121
+ }
4122
+ case "transition-task":
4123
+ case "transition-task-status": {
4124
+ const task = await transitionSkcTeamTaskStatus(
4125
+ teamName,
4126
+ String(input.task_id ?? input.taskId),
4127
+ parseSkcTeamTaskStatus(input.to ?? input.status),
4128
+ cwd,
4129
+ env,
4130
+ typeof input.claim_token === "string" ? input.claim_token : undefined,
4131
+ explicitWorker,
4132
+ input.completion_evidence ?? input.completionEvidence,
4133
+ );
4134
+ return {
4135
+ ok: true,
4136
+ ...taskReceiptFields(teamName, task),
4137
+ worker_id: explicitWorker ?? task.owner ?? task.assignee,
4138
+ };
4139
+ }
4140
+ case "release-task-claim": {
4141
+ const task = await releaseSkcTeamTaskClaim(
4142
+ teamName,
4143
+ String(input.task_id),
4144
+ String(input.claim_token),
4145
+ worker,
4146
+ cwd,
4147
+ env,
4148
+ );
4149
+ return { ok: true, ...taskReceiptFields(teamName, task), worker_id: worker };
4150
+ }
4151
+ case "send-message": {
4152
+ const message = await sendSkcTeamMessage(
4153
+ teamName,
4154
+ String(input.from_worker),
4155
+ String(input.to_worker),
4156
+ String(input.body),
4157
+ cwd,
4158
+ env,
4159
+ typeof input.idempotency_key === "string" ? input.idempotency_key : undefined,
4160
+ );
4161
+ return { ok: true, ...mailboxMessageReceiptFields(teamName, message) };
4162
+ }
4163
+ case "broadcast": {
4164
+ const messages = await broadcastSkcTeamMessage(
4165
+ teamName,
4166
+ String(input.from_worker),
4167
+ String(input.body),
4168
+ cwd,
4169
+ env,
4170
+ typeof input.idempotency_key === "string" ? input.idempotency_key : undefined,
4171
+ );
4172
+ return {
4173
+ ok: true,
4174
+ team_name: teamName,
4175
+ message_ids: messages.map(message => message.message_id),
4176
+ delivery_states: messages.map(message => ({
4177
+ message_id: message.message_id,
4178
+ to_worker: message.to_worker,
4179
+ delivered: Boolean(message.delivered_at),
4180
+ notified: Boolean(message.notified_at),
4181
+ })),
4182
+ };
4183
+ }
4184
+ case "mailbox-list":
4185
+ return { messages: await listSkcTeamMailbox(teamName, worker, cwd, env) };
4186
+ case "mailbox-mark-delivered": {
4187
+ const message = await markSkcTeamMailboxMessage(
4188
+ teamName,
4189
+ worker,
4190
+ String(input.message_id),
4191
+ "delivered_at",
4192
+ cwd,
4193
+ env,
4194
+ );
4195
+ return { ok: true, ...mailboxMessageReceiptFields(teamName, message) };
4196
+ }
4197
+ case "mailbox-mark-notified": {
4198
+ const message = await markSkcTeamMailboxMessage(
4199
+ teamName,
4200
+ worker,
4201
+ String(input.message_id),
4202
+ "notified_at",
4203
+ cwd,
4204
+ env,
4205
+ );
4206
+ return { ok: true, ...mailboxMessageReceiptFields(teamName, message) };
4207
+ }
4208
+ case "notification-list": {
4209
+ const dir = await findTeamDir(teamName, cwd, env);
4210
+ const config = await readConfig(dir);
4211
+ await reconcileTeamNotifications(dir, config);
4212
+ const notifications = await listNotificationRecords(dir);
4213
+ const result = { notifications, summary: summarizeNotifications(notifications) };
4214
+ return notificationSummaryReceipt(teamName, result);
4215
+ }
4216
+ case "notification-read":
4217
+ return {
4218
+ notification: await readNotificationRecord(
4219
+ await findTeamDir(teamName, cwd, env),
4220
+ String(input.notification_id),
4221
+ ),
4222
+ };
4223
+ case "notification-replay":
4224
+ return notificationSummaryReceipt(teamName, await replaySkcTeamNotifications(teamName, cwd, env));
4225
+ case "notification-mark-pane-attempt": {
4226
+ const dir = await findTeamDir(teamName, cwd, env);
4227
+ const notification = await readNotificationRecord(dir, String(input.notification_id));
4228
+ const updated = await writeNotificationRecord(dir, {
4229
+ ...notification,
4230
+ delivery_state: parsePaneAttemptResult(String(input.result ?? "failed")),
4231
+ pane_attempt_result: parsePaneAttemptResult(String(input.result ?? "failed")),
4232
+ pane_attempt_reason: String(input.reason ?? "manual_api"),
4233
+ pane_attempt_at: now(),
4234
+ updated_at: now(),
4235
+ });
4236
+ return { ok: true, ...notificationReceiptFields(updated) };
4237
+ }
4238
+ case "worker-startup-ack":
4239
+ return writeSkcWorkerStartupAck(teamName, worker, cwd, env, input);
4240
+ case "read-config":
4241
+ return await readConfig(await findTeamDir(teamName, cwd, env));
4242
+ case "read-manifest":
4243
+ return readJsonFile(path.join(await findTeamDir(teamName, cwd, env), "manifest.v2.json"));
4244
+ case "read-worker-status":
4245
+ return readSkcWorkerStatus(teamName, worker, cwd, env);
4246
+ case "update-worker-status": {
4247
+ const currentTaskIdInput = input.current_task_id ?? input.currentTaskId;
4248
+ return updateSkcWorkerStatus(
4249
+ teamName,
4250
+ worker,
4251
+ parseRequiredSkcWorkerStatusState(input.status ?? input.state),
4252
+ cwd,
4253
+ env,
4254
+ typeof currentTaskIdInput === "string" ? currentTaskIdInput : undefined,
4255
+ typeof input.reason === "string" ? input.reason : undefined,
4256
+ );
4257
+ }
4258
+ case "read-worker-heartbeat":
4259
+ return readSkcWorkerHeartbeat(teamName, worker, cwd, env);
4260
+ case "recover-stale-claims":
4261
+ return recoverSkcTeamStaleClaims(teamName, cwd, env);
4262
+ case "update-worker-heartbeat":
4263
+ return updateSkcWorkerHeartbeat(
4264
+ teamName,
4265
+ worker,
4266
+ {
4267
+ pid: Number(input.pid ?? 0),
4268
+ last_turn_at: now(),
4269
+ turn_count: Number(input.turn_count ?? 0),
4270
+ alive: Boolean(input.alive ?? true),
4271
+ },
4272
+ cwd,
4273
+ env,
4274
+ );
4275
+ case "write-worker-inbox":
4276
+ return writeSkcWorkerInbox(teamName, worker, String(input.content ?? ""), cwd, env);
4277
+ case "write-worker-identity":
4278
+ return writeSkcWorkerIdentity(
4279
+ teamName,
4280
+ {
4281
+ id: worker,
4282
+ name: worker,
4283
+ index: Number(input.index ?? 1),
4284
+ agent_type: String(input.role ?? "executor"),
4285
+ role: String(input.role ?? "executor"),
4286
+ status: "idle",
4287
+ last_heartbeat: now(),
4288
+ assigned_tasks: Array.isArray(input.assigned_tasks) ? input.assigned_tasks.map(String) : [],
4289
+ },
4290
+ cwd,
4291
+ env,
4292
+ );
4293
+ case "append-event":
4294
+ return appendSkcTeamEvent(teamName, String(input.type ?? "event"), worker, cwd, env);
4295
+ case "read-events":
4296
+ return { events: await readSkcTeamEvents(teamName, cwd, env) };
4297
+ case "read-traces":
4298
+ return { traces: await readSkcTeamTraces(teamName, cwd, env) };
4299
+ case "await-event":
4300
+ return awaitSkcTeamEvent(teamName, Number(input.timeout_ms ?? 0), cwd, env);
4301
+ case "write-monitor-snapshot":
4302
+ return writeSkcMonitorSnapshot(teamName, input.snapshot ?? {}, cwd, env);
4303
+ case "read-monitor-snapshot":
4304
+ return readSkcMonitorSnapshot(teamName, cwd, env);
4305
+ case "write-task-approval":
4306
+ return writeSkcTaskApproval(teamName, String(input.task_id), input, cwd, env);
4307
+ case "read-task-approval":
4308
+ return readSkcTaskApproval(teamName, String(input.task_id), cwd, env);
4309
+ case "write-shutdown-request": {
4310
+ const shutdownRequestIdInput = input.request_id ?? input.requestId;
4311
+ return writeSkcShutdownRequest(
4312
+ teamName,
4313
+ worker,
4314
+ String(input.requested_by ?? input.requestedBy ?? "leader-fixed"),
4315
+ cwd,
4316
+ env,
4317
+ typeof shutdownRequestIdInput === "string" ? shutdownRequestIdInput : undefined,
4318
+ parseSkcTeamShutdownMode(input.mode),
4319
+ );
4320
+ }
4321
+ case "read-shutdown-ack":
4322
+ return readSkcShutdownAck(teamName, worker, cwd, env);
4323
+ default:
4324
+ throw new Error(`unknown_team_api_operation:${operation}`);
4325
+ }
4326
+ }
4327
+
4328
+ export function parseTeamLaunchArgs(argv: string[]): SkcTeamStartOptions {
4329
+ const parsedWorktree = parseWorktreeMode(argv);
4330
+ const positionals = parsedWorktree.remainingArgs.filter(arg => !arg.startsWith("--"));
4331
+ const dryRun = argv.includes("--dry-run");
4332
+ let workerCount = SKC_TEAM_DEFAULT_WORKERS;
4333
+ let agentType = "executor";
4334
+ let taskStartIndex = 0;
4335
+ const first = positionals[0] ?? "";
4336
+ const countRole = first.match(/^(\d+):([a-zA-Z][a-zA-Z0-9_-]*)$/);
4337
+ const countOnly = first.match(/^(\d+)$/);
4338
+ const roleOnly = first.match(/^([a-zA-Z][a-zA-Z0-9_-]*)$/);
4339
+ if (countRole) {
4340
+ workerCount = Number.parseInt(countRole[1] ?? "", 10);
4341
+ agentType = countRole[2] ?? "executor";
4342
+ taskStartIndex = 1;
4343
+ } else if (countOnly) {
4344
+ workerCount = Number.parseInt(countOnly[1] ?? "", 10);
4345
+ taskStartIndex = 1;
4346
+ } else if (roleOnly && positionals.length > 1) {
4347
+ agentType = roleOnly[1] ?? "executor";
4348
+ taskStartIndex = 1;
4349
+ }
4350
+ const task = positionals.slice(taskStartIndex).join(" ").trim();
4351
+ if (!task) throw new Error("missing_team_task");
4352
+ if (!Number.isInteger(workerCount) || workerCount < 1 || workerCount > SKC_TEAM_MAX_WORKERS)
4353
+ throw new Error(`invalid_team_worker_count:${workerCount}:expected_1_${SKC_TEAM_MAX_WORKERS}`);
4354
+ return { workerCount, agentType, task, dryRun, worktreeMode: resolveDefaultWorktreeMode(parsedWorktree.mode) };
4355
+ }