@selesai/code 0.9.11 → 0.9.13

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 (580) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/config.d.ts +4 -6
  3. package/dist/config.js +10 -14
  4. package/dist/core/agent-session.d.ts +0 -1
  5. package/dist/core/agent-session.js +3 -49
  6. package/dist/core/extensions/types.d.ts +0 -2
  7. package/dist/core/settings-manager.d.ts +0 -2
  8. package/dist/core/settings-manager.js +0 -3
  9. package/dist/core/tools/index.d.ts +0 -1
  10. package/dist/core/tools/index.js +0 -1
  11. package/dist/defaults/settings.json +2 -3
  12. package/dist/extensions/model-prompt-injector/index.test.ts +0 -10
  13. package/dist/extensions/model-prompt-injector/index.ts +0 -3
  14. package/dist/extensions/pi-intercom/CHANGELOG.md +53 -16
  15. package/dist/extensions/pi-intercom/README.md +41 -8
  16. package/dist/extensions/pi-intercom/banner.png +0 -0
  17. package/dist/extensions/pi-intercom/broker/broker.ts +498 -215
  18. package/dist/extensions/pi-intercom/broker/client.ts +39 -12
  19. package/dist/extensions/pi-intercom/broker/extension.test.ts +102 -3
  20. package/dist/extensions/pi-intercom/broker/paths.test.ts +2 -2
  21. package/dist/extensions/pi-intercom/broker/protocol.ts +26 -0
  22. package/dist/extensions/pi-intercom/broker/spawn.test.ts +5 -20
  23. package/dist/extensions/pi-intercom/config.test.ts +41 -0
  24. package/dist/extensions/pi-intercom/config.ts +21 -0
  25. package/dist/extensions/pi-intercom/extension-api.ts +40 -0
  26. package/dist/extensions/pi-intercom/index.ts +362 -26
  27. package/dist/extensions/pi-intercom/intercom.integration.test.ts +819 -13
  28. package/dist/extensions/pi-intercom/package.json +1 -1
  29. package/dist/extensions/pi-intercom/project-agent.ts +2 -2
  30. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +8 -110
  31. package/dist/extensions/pi-intercom/types.ts +32 -5
  32. package/dist/extensions/pi-intercom/ui/inline-message.ts +6 -0
  33. package/dist/extensions/pi-subagents/.github/assets/subagent-fleet-inspector.png +0 -0
  34. package/dist/extensions/pi-subagents/.github/workflows/release.yml +28 -0
  35. package/dist/extensions/pi-subagents/.github/workflows/test.yml +51 -0
  36. package/dist/extensions/pi-subagents/.greptile/config.json +33 -0
  37. package/dist/extensions/pi-subagents/.greptile/files.json +8 -0
  38. package/dist/extensions/pi-subagents/.greptile/rules.md +16 -0
  39. package/dist/extensions/pi-subagents/CHANGELOG.md +309 -87
  40. package/dist/extensions/pi-subagents/README.md +15 -17
  41. package/dist/extensions/pi-subagents/agents/oracle.md +3 -1
  42. package/dist/extensions/pi-subagents/agents/researcher.md +32 -13
  43. package/dist/extensions/pi-subagents/agents/reviewer.md +13 -2
  44. package/dist/extensions/pi-subagents/agents/scout.md +2 -2
  45. package/dist/extensions/pi-subagents/agents/worker.md +2 -1
  46. package/dist/extensions/pi-subagents/async-retention-discovery-worker.mjs +180 -0
  47. package/dist/extensions/pi-subagents/docs/configuration.md +106 -27
  48. package/dist/extensions/pi-subagents/docs/extension-api.md +85 -21
  49. package/dist/extensions/pi-subagents/docs/missions.md +41 -4
  50. package/dist/extensions/pi-subagents/docs/models.md +52 -9
  51. package/dist/extensions/pi-subagents/docs/observability.md +103 -16
  52. package/dist/extensions/pi-subagents/docs/tool-reference.md +60 -45
  53. package/dist/extensions/pi-subagents/docs/watchdog.md +60 -3
  54. package/dist/extensions/pi-subagents/docs/workflows.md +181 -7
  55. package/dist/extensions/pi-subagents/index.ts +10 -1
  56. package/dist/extensions/pi-subagents/install.mjs +4 -4
  57. package/dist/extensions/pi-subagents/package-lock.json +1483 -1470
  58. package/dist/extensions/pi-subagents/package.json +6 -3
  59. package/dist/extensions/pi-subagents/prompts/council.md +60 -0
  60. package/dist/extensions/pi-subagents/prompts/parallel-review.md +5 -1
  61. package/dist/extensions/pi-subagents/prompts/review-loop.md +9 -5
  62. package/dist/extensions/pi-subagents/skills/council-mode/SKILL.md +254 -0
  63. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +18 -17
  64. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +31 -9
  65. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +107 -140
  66. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +9 -12
  67. package/dist/extensions/pi-subagents/skills/pi-subagents/references/multi-lane-orchestration.md +39 -0
  68. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +44 -92
  69. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +261 -368
  70. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +6 -2
  71. package/dist/extensions/pi-subagents/src/agents/agents.ts +388 -85
  72. package/dist/extensions/pi-subagents/src/agents/builtin-names.ts +14 -0
  73. package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +418 -0
  74. package/dist/extensions/pi-subagents/src/agents/skills.ts +1 -1
  75. package/dist/extensions/pi-subagents/src/api/agents.ts +7 -0
  76. package/dist/extensions/pi-subagents/src/api/external-job-provider.ts +195 -0
  77. package/dist/extensions/pi-subagents/src/api/preflight.ts +88 -27
  78. package/dist/extensions/pi-subagents/src/api/project-panes.ts +2 -0
  79. package/dist/extensions/pi-subagents/src/api/shared-types.ts +2 -0
  80. package/dist/extensions/pi-subagents/src/extension/config.ts +20 -11
  81. package/dist/extensions/pi-subagents/src/extension/doctor.ts +14 -6
  82. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +5 -4
  83. package/dist/extensions/pi-subagents/src/extension/index.ts +270 -187
  84. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +65 -28
  85. package/dist/extensions/pi-subagents/src/extension/rpc.ts +120 -11
  86. package/dist/extensions/pi-subagents/src/extension/schemas.ts +46 -64
  87. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +51 -37
  88. package/dist/extensions/pi-subagents/src/extension/tool-result.ts +19 -0
  89. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +2 -2
  90. package/dist/extensions/pi-subagents/src/inspectors/herdr/client.ts +3 -3
  91. package/dist/extensions/pi-subagents/src/inspectors/herdr/focus.ts +55 -0
  92. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +2 -1
  93. package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +230 -46
  94. package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +26 -4
  95. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +32 -10
  96. package/dist/extensions/pi-subagents/src/missions/lifecycle.ts +6 -1
  97. package/dist/extensions/pi-subagents/src/missions/store.ts +4 -9
  98. package/dist/extensions/pi-subagents/src/missions/workflow-state.ts +2 -2
  99. package/dist/extensions/pi-subagents/src/policy/authority.ts +2 -0
  100. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +3 -1
  101. package/dist/extensions/pi-subagents/src/runs/background/active-run-index.ts +31 -8
  102. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +210 -52
  103. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +63 -33
  104. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +71 -17
  105. package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +886 -0
  106. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +14 -5
  107. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +49 -56
  108. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +1 -0
  109. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +3 -33
  110. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +5 -0
  111. package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +5 -1
  112. package/dist/extensions/pi-subagents/src/runs/background/completion-replay.ts +22 -12
  113. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +105 -71
  114. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +68 -19
  115. package/dist/extensions/pi-subagents/src/runs/background/index-segment.ts +59 -0
  116. package/dist/extensions/pi-subagents/src/runs/background/inspect-rpc.ts +443 -0
  117. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +94 -10
  118. package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +158 -90
  119. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +141 -53
  120. package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +8 -5
  121. package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +14 -4
  122. package/dist/extensions/pi-subagents/src/runs/background/run-id-query.ts +7 -0
  123. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +13 -14
  124. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +46 -25
  125. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +823 -0
  126. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +9 -3
  127. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +11 -1
  128. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +594 -216
  129. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +17 -13
  130. package/dist/extensions/pi-subagents/src/runs/background/terminal-run-index.ts +138 -0
  131. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +23 -4
  132. package/dist/extensions/pi-subagents/src/runs/background/wait-subscriptions.ts +82 -4
  133. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +5 -3
  134. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +21 -14
  135. package/dist/extensions/pi-subagents/src/runs/foreground/async-stop-action.ts +23 -2
  136. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +153 -58
  137. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +7 -9
  138. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1283 -1657
  139. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +274 -0
  140. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-foreground-steering.ts +6 -5
  141. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +59 -10
  142. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +1 -1
  143. package/dist/extensions/pi-subagents/src/runs/shared/chain-outputs.ts +1 -3
  144. package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +36 -0
  145. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +52 -2
  146. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
  147. package/dist/extensions/pi-subagents/src/runs/shared/extension-bindings.ts +78 -0
  148. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +2 -0
  149. package/dist/extensions/pi-subagents/src/runs/shared/external-job-bridge.ts +460 -0
  150. package/dist/extensions/pi-subagents/src/runs/shared/external-job-runner.ts +389 -0
  151. package/dist/extensions/pi-subagents/src/runs/shared/fast-mode-extension.ts +10 -0
  152. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +14 -0
  153. package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +243 -0
  154. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +201 -85
  155. package/dist/extensions/pi-subagents/src/runs/shared/model-scope.ts +106 -39
  156. package/dist/extensions/pi-subagents/src/runs/shared/mutation-evidence.ts +145 -0
  157. package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +150 -27
  158. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +46 -4
  159. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +19 -15
  160. package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +5 -1
  161. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +86 -2
  162. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +9 -9
  163. package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +0 -6
  164. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +18 -4
  165. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +51 -7
  166. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +62 -21
  167. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +1 -3
  168. package/dist/extensions/pi-subagents/src/runs/shared/tool-timeout.ts +1 -3
  169. package/dist/extensions/pi-subagents/src/runs/shared/workflow-graph.ts +1 -23
  170. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +14 -2
  171. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +2 -2
  172. package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +22 -2
  173. package/dist/extensions/pi-subagents/src/shared/capacity-resilient-json.ts +102 -0
  174. package/dist/extensions/pi-subagents/src/shared/completion-owner.ts +14 -0
  175. package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +49 -1
  176. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +59 -1
  177. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +12 -5
  178. package/dist/extensions/pi-subagents/src/shared/model-info.ts +20 -0
  179. package/dist/extensions/pi-subagents/src/shared/prompt-resources.ts +0 -40
  180. package/dist/extensions/pi-subagents/src/shared/settings.ts +11 -30
  181. package/dist/extensions/pi-subagents/src/shared/thinking-ceiling.ts +52 -0
  182. package/dist/extensions/pi-subagents/src/shared/types.ts +228 -49
  183. package/dist/extensions/pi-subagents/src/shared/utils.ts +11 -3
  184. package/dist/extensions/pi-subagents/src/shared/watch-strategy.ts +10 -0
  185. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +0 -162
  186. package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +2 -5
  187. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +105 -13
  188. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +6 -36
  189. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +829 -0
  190. package/dist/extensions/pi-subagents/src/tui/fleet.ts +1415 -0
  191. package/dist/extensions/pi-subagents/src/tui/render.ts +78 -7
  192. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +1 -1
  193. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +1 -0
  194. package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +59 -51
  195. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +8 -2
  196. package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +2 -1
  197. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +4 -4
  198. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +471 -86
  199. package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +140 -0
  200. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
  201. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/bun/cli.d.ts +3 -0
  202. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/bun/register-bedrock.d.ts +2 -0
  203. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/bun/restore-sandbox-env.d.ts +17 -0
  204. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/args.d.ts +57 -0
  205. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/config-selector.d.ts +16 -0
  206. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/file-processor.d.ts +15 -0
  207. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/initial-message.d.ts +18 -0
  208. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/list-models.d.ts +9 -0
  209. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/project-trust.d.ts +10 -0
  210. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/session-picker.d.ts +10 -0
  211. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli/startup-ui.d.ts +20 -0
  212. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/cli.d.ts +3 -0
  213. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/config.d.ts +96 -0
  214. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/agent-session-runtime.d.ts +119 -0
  215. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/agent-session-services.d.ts +85 -0
  216. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/agent-session.d.ts +620 -0
  217. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/auth-guidance.d.ts +5 -0
  218. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/auth-storage.d.ts +56 -0
  219. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/bash-executor.d.ts +32 -0
  220. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/cache-stats.d.ts +49 -0
  221. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/branch-summarization.d.ts +93 -0
  222. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/compaction.d.ts +128 -0
  223. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/index.d.ts +7 -0
  224. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/compaction/utils.d.ts +38 -0
  225. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/defaults.d.ts +3 -0
  226. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/diagnostics.d.ts +15 -0
  227. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/event-bus.d.ts +9 -0
  228. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/exec.d.ts +29 -0
  229. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/experimental.d.ts +2 -0
  230. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/export-html/ansi-to-html.d.ts +22 -0
  231. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/export-html/index.d.ts +37 -0
  232. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/export-html/tool-renderer.d.ts +34 -0
  233. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/index.d.ts +12 -0
  234. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/loader.d.ts +23 -0
  235. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/runner.d.ts +171 -0
  236. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/types.d.ts +1261 -0
  237. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/wrapper.d.ts +20 -0
  238. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/footer-data-provider.d.ts +54 -0
  239. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/http-dispatcher.d.ts +22 -0
  240. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/index.d.ts +13 -0
  241. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/keybindings.d.ts +358 -0
  242. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/messages.d.ts +77 -0
  243. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-config.d.ts +512 -0
  244. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-registry.d.ts +43 -0
  245. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-resolver.d.ts +121 -0
  246. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/model-runtime.d.ts +82 -0
  247. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/models-store.d.ts +17 -0
  248. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/output-guard.d.ts +7 -0
  249. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/package-manager.d.ts +210 -0
  250. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/project-trust.d.ts +15 -0
  251. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/prompt-templates.d.ts +54 -0
  252. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/provider-attribution.d.ts +4 -0
  253. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/provider-composer.d.ts +55 -0
  254. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/radius.d.ts +2 -0
  255. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/remote-catalog-provider.d.ts +5 -0
  256. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/resolve-config-value.d.ts +30 -0
  257. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/resource-loader.d.ts +206 -0
  258. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/runtime-credentials.d.ts +15 -0
  259. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/sdk.d.ts +106 -0
  260. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/session-cwd.d.ts +19 -0
  261. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/session-manager.d.ts +356 -0
  262. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/settings-manager.d.ts +297 -0
  263. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/skills.d.ts +60 -0
  264. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/slash-commands.d.ts +15 -0
  265. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/source-info.d.ts +18 -0
  266. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/system-prompt.d.ts +28 -0
  267. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/telemetry.d.ts +3 -0
  268. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/timings.d.ts +10 -0
  269. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/bash.d.ts +68 -0
  270. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/edit-diff.d.ts +106 -0
  271. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/edit.d.ts +51 -0
  272. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/file-mutation-queue.d.ts +6 -0
  273. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/find.d.ts +35 -0
  274. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/grep.d.ts +37 -0
  275. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/index.d.ts +40 -0
  276. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/ls.d.ts +37 -0
  277. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/output-accumulator.d.ts +52 -0
  278. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/path-utils.d.ts +10 -0
  279. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/read.d.ts +35 -0
  280. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/render-utils.d.ts +24 -0
  281. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/tool-definition-wrapper.d.ts +14 -0
  282. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/truncate.d.ts +70 -0
  283. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/tools/write.d.ts +26 -0
  284. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/trust-manager.d.ts +36 -0
  285. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/usage-totals.d.ts +19 -0
  286. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/index.d.ts +3 -0
  287. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/client.d.ts +61 -0
  288. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/huggingface.d.ts +23 -0
  289. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/index.d.ts +3 -0
  290. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/provider.d.ts +10 -0
  291. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/extensions/llama/ui.d.ts +42 -0
  292. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/index.d.ts +35 -0
  293. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/main.d.ts +12 -0
  294. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/migrations.d.ts +33 -0
  295. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/index.d.ts +9 -0
  296. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/armin.d.ts +34 -0
  297. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/assistant-message.d.ts +22 -0
  298. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/bash-execution.d.ts +34 -0
  299. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/bordered-loader.d.ts +16 -0
  300. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/branch-summary-message.d.ts +16 -0
  301. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/compaction-summary-message.d.ts +16 -0
  302. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/config-selector.d.ts +102 -0
  303. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/countdown-timer.d.ts +14 -0
  304. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/custom-editor.d.ts +21 -0
  305. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/custom-entry.d.ts +19 -0
  306. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/custom-message.d.ts +20 -0
  307. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/daxnuts.d.ts +23 -0
  308. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/diff.d.ts +12 -0
  309. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/dynamic-border.d.ts +15 -0
  310. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/earendil-announcement.d.ts +5 -0
  311. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/extension-editor.d.ts +22 -0
  312. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/extension-input.d.ts +23 -0
  313. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/extension-selector.d.ts +26 -0
  314. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/first-time-setup.d.ts +25 -0
  315. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/footer.d.ts +32 -0
  316. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/index.d.ts +34 -0
  317. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/keybinding-hints.d.ts +13 -0
  318. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/login-dialog.d.ts +52 -0
  319. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/model-selector.d.ts +54 -0
  320. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/oauth-selector.d.ts +33 -0
  321. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/scoped-models-selector.d.ts +42 -0
  322. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/session-selector-search.d.ts +23 -0
  323. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/session-selector.d.ts +95 -0
  324. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/settings-selector.d.ts +77 -0
  325. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/show-images-selector.d.ts +10 -0
  326. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/skill-invocation-message.d.ts +17 -0
  327. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/status-indicator.d.ts +28 -0
  328. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/theme-selector.d.ts +11 -0
  329. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/thinking-selector.d.ts +11 -0
  330. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/tool-execution.d.ts +63 -0
  331. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/tree-selector.d.ts +94 -0
  332. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/trust-selector.d.ts +23 -0
  333. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/user-message-selector.d.ts +30 -0
  334. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/user-message.d.ts +14 -0
  335. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/components/visual-truncate.d.ts +24 -0
  336. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/interactive-mode.d.ts +394 -0
  337. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/model-search.d.ts +12 -0
  338. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/theme/theme-controller.d.ts +29 -0
  339. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/interactive/theme/theme.d.ts +120 -0
  340. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/print-mode.d.ts +28 -0
  341. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/jsonl.d.ts +17 -0
  342. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/rpc-client.d.ts +246 -0
  343. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/rpc-mode.d.ts +20 -0
  344. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/modes/rpc/rpc-types.d.ts +457 -0
  345. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/package-manager-cli.d.ts +8 -0
  346. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/rpc-entry.d.ts +3 -0
  347. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/ansi.d.ts +2 -0
  348. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/changelog.d.ts +22 -0
  349. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/child-process.d.ts +18 -0
  350. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/clipboard-image.d.ts +11 -0
  351. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/clipboard-native.d.ts +11 -0
  352. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/clipboard.d.ts +4 -0
  353. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/deprecation.d.ts +4 -0
  354. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/exif-orientation.d.ts +5 -0
  355. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/frontmatter.d.ts +8 -0
  356. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/fs-watch.d.ts +5 -0
  357. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/git.d.ts +26 -0
  358. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/html.d.ts +7 -0
  359. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-convert.d.ts +10 -0
  360. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-process.d.ts +18 -0
  361. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-resize-core.d.ts +30 -0
  362. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-resize-worker.d.ts +2 -0
  363. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/image-resize.d.ts +16 -0
  364. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/json.d.ts +3 -0
  365. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/mime.d.ts +3 -0
  366. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/open-browser.d.ts +9 -0
  367. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/paths.d.ts +31 -0
  368. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/photon.d.ts +21 -0
  369. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/pi-user-agent.d.ts +2 -0
  370. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/shell.d.ts +31 -0
  371. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/sleep.d.ts +5 -0
  372. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/syntax-highlight.d.ts +12 -0
  373. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/tools-manager.d.ts +3 -0
  374. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/version-check.d.ts +15 -0
  375. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/utils/windows-self-update.d.ts +3 -0
  376. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/index.mjs +1 -1
  377. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +0 -54
  378. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1053 -414
  379. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +194 -4
  380. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +59 -4
  381. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +0 -77
  382. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +107 -6
  383. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +211 -897
  384. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +265 -375
  385. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +77 -7
  386. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +1 -1
  387. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +10 -10
  388. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +547 -30
  389. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +2112 -310
  390. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +274 -34
  391. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +1 -1
  392. package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +20 -3
  393. package/dist/extensions/pi-subagents/test/support/isolated-temp-root.mjs +9 -0
  394. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +30 -5
  395. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +2 -0
  396. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +4 -2
  397. package/dist/extensions/pi-subagents/test/support/register-loader.mjs +1 -0
  398. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +197 -0
  399. package/dist/extensions/pi-subagents/test/unit/agent-contract.test.ts +14 -0
  400. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +1 -1
  401. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +204 -27
  402. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +444 -145
  403. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +256 -4
  404. package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +9 -7
  405. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +152 -22
  406. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +29 -0
  407. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +205 -23
  408. package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +579 -0
  409. package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +24 -0
  410. package/dist/extensions/pi-subagents/test/unit/authority-policy.test.ts +1 -0
  411. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +3 -3
  412. package/dist/extensions/pi-subagents/test/unit/capacity-resilient-json.test.ts +155 -0
  413. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +2 -2
  414. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +7 -0
  415. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +123 -0
  416. package/dist/extensions/pi-subagents/test/unit/completion-replay.test.ts +81 -3
  417. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +109 -7
  418. package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +2 -2
  419. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +5 -2
  420. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -2
  421. package/dist/extensions/pi-subagents/test/unit/extension-bindings.test.ts +79 -0
  422. package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +22 -0
  423. package/dist/extensions/pi-subagents/test/unit/external-job-runner.test.ts +961 -0
  424. package/dist/extensions/pi-subagents/test/unit/file-system-retry.test.ts +64 -0
  425. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +1110 -0
  426. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +1664 -0
  427. package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +81 -1
  428. package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +138 -11
  429. package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +41 -2
  430. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +210 -79
  431. package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +95 -0
  432. package/dist/extensions/pi-subagents/test/unit/inspect-rpc.test.ts +596 -0
  433. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +10 -1
  434. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +3 -5
  435. package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +167 -0
  436. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +319 -18
  437. package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +78 -0
  438. package/dist/extensions/pi-subagents/test/unit/model-scope-settings.test.ts +19 -5
  439. package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +44 -0
  440. package/dist/extensions/pi-subagents/test/unit/mutation-evidence.test.ts +129 -0
  441. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +231 -2
  442. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +28 -1
  443. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +106 -2
  444. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +204 -7
  445. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +59 -4
  446. package/dist/extensions/pi-subagents/test/unit/path-handling.test.ts +2 -6
  447. package/dist/extensions/pi-subagents/test/unit/pi-args-permission-system.test.ts +34 -2
  448. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +116 -6
  449. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +12 -3
  450. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +56 -61
  451. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +416 -1
  452. package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +9 -2
  453. package/dist/extensions/pi-subagents/test/unit/project-panes-public-api.test.ts +42 -0
  454. package/dist/extensions/pi-subagents/test/unit/prompt-workflows.test.ts +21 -30
  455. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +86 -11
  456. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +49 -1
  457. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +233 -5
  458. package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +28 -5
  459. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +323 -20
  460. package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +66 -10
  461. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +68 -5
  462. package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +174 -0
  463. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +679 -0
  464. package/dist/extensions/pi-subagents/test/unit/scheduled-store-root.test.ts +67 -0
  465. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +55 -44
  466. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +399 -84
  467. package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +13 -0
  468. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  469. package/dist/extensions/pi-subagents/test/unit/slash-bridge.test.ts +15 -10
  470. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +11 -7
  471. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -0
  472. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +40 -1
  473. package/dist/extensions/pi-subagents/test/unit/subagent-action-recovery.test.ts +10 -2
  474. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +38 -3
  475. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +110 -12
  476. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +204 -19
  477. package/dist/extensions/pi-subagents/test/unit/temp-paths.test.ts +25 -0
  478. package/dist/extensions/pi-subagents/test/unit/thinking-ceiling.test.ts +73 -0
  479. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +90 -50
  480. package/dist/extensions/pi-subagents/test/unit/tool-timeout.test.ts +1 -2
  481. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +234 -7
  482. package/dist/extensions/pi-subagents/test/unit/watch-strategy.test.ts +24 -0
  483. package/dist/extensions/pi-subagents/test/unit/watchdog-permission-arbiter.test.ts +36 -0
  484. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +37 -9
  485. package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +302 -0
  486. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +167 -7
  487. package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +113 -0
  488. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +6 -6
  489. package/dist/extensions/ponytail/index.js +31 -25
  490. package/dist/extensions/ponytail/ponytail-config.cjs +34 -7
  491. package/dist/extensions/ponytail/ponytail-instructions.cjs +7 -9
  492. package/dist/extensions/ponytail/test/extension.test.js +7 -8
  493. package/dist/extensions/ponytail/test/helpers.test.js +1 -1
  494. package/dist/skills/brandkit/SKILL.md +799 -0
  495. package/dist/skills/design-taste-frontend/SKILL.md +1207 -0
  496. package/dist/skills/design-taste-frontend-v1/SKILL.md +227 -0
  497. package/dist/skills/full-output-enforcement/SKILL.md +50 -0
  498. package/dist/skills/gpt-taste/SKILL.md +75 -0
  499. package/dist/skills/high-end-visual-design/SKILL.md +99 -0
  500. package/dist/skills/image-to-code/SKILL.md +1229 -0
  501. package/dist/skills/imagegen-frontend-mobile/SKILL.md +1466 -0
  502. package/dist/skills/imagegen-frontend-web/SKILL.md +988 -0
  503. package/dist/skills/industrial-brutalist-ui/SKILL.md +93 -0
  504. package/dist/skills/minimalist-ui/SKILL.md +86 -0
  505. package/dist/skills/pi-subagents/SKILL.md +18 -17
  506. package/dist/skills/pi-subagents/references/constraints-and-recipes.md +31 -9
  507. package/dist/skills/pi-subagents/references/execution-controls.md +95 -143
  508. package/dist/skills/pi-subagents/references/management-authoring-rpc.md +9 -12
  509. package/dist/skills/pi-subagents/references/multi-lane-orchestration.md +39 -0
  510. package/dist/skills/pi-subagents/references/prompting-and-roles.md +45 -94
  511. package/dist/skills/ponytail/SKILL.md +12 -8
  512. package/dist/skills/ponytail-audit/SKILL.md +0 -1
  513. package/dist/skills/ponytail-debt/SKILL.md +0 -1
  514. package/dist/skills/ponytail-gain/SKILL.md +0 -1
  515. package/dist/skills/ponytail-help/SKILL.md +4 -3
  516. package/dist/skills/ponytail-review/SKILL.md +0 -1
  517. package/dist/skills/redesign-existing-projects/SKILL.md +179 -0
  518. package/dist/skills/stitch-design-taste/SKILL.md +185 -0
  519. package/dist/skills/unlazy/CHANGELOG.md +100 -0
  520. package/dist/skills/unlazy/CONTRIBUTING.md +66 -0
  521. package/dist/skills/unlazy/LICENSE +21 -0
  522. package/dist/skills/unlazy/README.md +242 -0
  523. package/dist/skills/unlazy/SECURITY.md +70 -0
  524. package/dist/skills/unlazy/SKILL.md +100 -0
  525. package/dist/skills/unlazy/package.json +13 -0
  526. package/dist/skills/unlazy/references/dispatch.md +82 -0
  527. package/dist/skills/unlazy/references/gates.md +132 -0
  528. package/dist/skills/unlazy/references/method.md +49 -0
  529. package/dist/skills/unlazy/references/orchestration.md +99 -0
  530. package/dist/skills/unlazy/references/parallel.md +123 -0
  531. package/dist/skills/unlazy/references/token-economy.md +39 -0
  532. package/dist/skills/unlazy/research/validation-protocol.md +81 -0
  533. package/dist/skills/unlazy/scripts/dispatch-check.mjs +108 -0
  534. package/dist/skills/unlazy/scripts/gate-check.mjs +894 -0
  535. package/dist/skills/unlazy/scripts/gate-lint.mjs +178 -0
  536. package/dist/skills/unlazy/scripts/install-hooks.mjs +206 -0
  537. package/dist/skills/unlazy/scripts/lib/check-supervisor.mjs +46 -0
  538. package/dist/skills/unlazy/scripts/lib/dispatch.mjs +283 -0
  539. package/dist/skills/unlazy/scripts/lib/gates.mjs +629 -0
  540. package/dist/skills/unlazy/scripts/lib/process-tree.mjs +161 -0
  541. package/dist/skills/unlazy/scripts/lib/regex-worker.mjs +9 -0
  542. package/dist/skills/unlazy/scripts/stop-hook.mjs +174 -0
  543. package/dist/skills/unlazy/templates/PLAN.md +65 -0
  544. package/dist/skills/unlazy/templates/gates-leaf.md +51 -0
  545. package/dist/skills/unlazy/templates/gates-node.md +50 -0
  546. package/dist/skills/unlazy/tests/contract-tests.mjs +127 -0
  547. package/dist/skills/unlazy/tests/dispatch-tests.mjs +481 -0
  548. package/dist/skills/unlazy/tests/hardening-tests.mjs +903 -0
  549. package/dist/skills/unlazy/tests/lint-tests.mjs +242 -0
  550. package/dist/skills/unlazy/tests/run-tests.mjs +554 -0
  551. package/dist/skills/unlazy/tests/self-check.mjs +165 -0
  552. package/dist/skills/unlazy/tests/stress-tests.mjs +356 -0
  553. package/dist/skills/web-design-guidelines/SKILL.md +40 -0
  554. package/docs/settings.md +0 -5
  555. package/package.json +1 -1
  556. package/dist/core/tools/schema-prune.d.ts +0 -16
  557. package/dist/core/tools/schema-prune.js +0 -39
  558. package/dist/core/tools/schema-prune.test.d.ts +0 -1
  559. package/dist/core/tools/schema-prune.test.js +0 -111
  560. package/dist/extensions/pi-subagents/UPSTREAM-V0.50-MAPPING.md +0 -172
  561. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +0 -55
  562. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +0 -61
  563. package/dist/extensions/pi-subagents/src/agents/task-aware-routing.ts +0 -132
  564. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +0 -181
  565. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +0 -1354
  566. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +0 -1581
  567. package/dist/extensions/pi-subagents/src/shared/env.ts +0 -16
  568. package/dist/extensions/pi-subagents/src/shared/session-lineage.ts +0 -71
  569. package/dist/extensions/pi-subagents/src/slash/inline-subagents.ts +0 -136
  570. package/dist/extensions/pi-subagents/src/workflows/workflow-auto-relaunch.ts +0 -41
  571. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +0 -466
  572. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +0 -1859
  573. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +0 -733
  574. package/dist/extensions/pi-subagents/test/unit/builtin-agent-documentation.test.ts +0 -63
  575. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +0 -326
  576. package/dist/extensions/pi-subagents/test/unit/handoff-adoption.test.ts +0 -103
  577. package/dist/extensions/pi-subagents/test/unit/inline-subagents.test.ts +0 -127
  578. package/dist/extensions/pi-subagents/test/unit/session-lineage.test.ts +0 -73
  579. package/dist/extensions/pi-subagents/test/unit/task-aware-routing.test.ts +0 -213
  580. package/dist/extensions/pi-subagents/test/unit/workflow-auto-relaunch.test.ts +0 -65
@@ -0,0 +1,823 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import * as fs from "node:fs";
3
+ import * as path from "node:path";
4
+ import type { AgentToolResult } from "@earendil-works/pi-agent-core";
5
+ import type { ExtensionContext } from "@selesai/code";
6
+ import { getProjectSubagentsDir } from "../../shared/artifacts.ts";
7
+ import { writePrivateAtomicJson } from "../../shared/atomic-json.ts";
8
+ import { shortenPath } from "../../shared/formatters.ts";
9
+ import type { AsyncStatus, Details, ExtensionConfig } from "../../shared/types.ts";
10
+ import type { SubagentParamsLike } from "../foreground/subagent-executor.ts";
11
+ import { validateExecutionAcceptance } from "../shared/acceptance.ts";
12
+ import type { ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
13
+ import { previewSimpleWorkflowRun } from "../../workflows/scripted-workflow.ts";
14
+
15
+ export const SCHEDULED_RUN_ACTIONS = [
16
+ "schedule.create",
17
+ "schedule.list",
18
+ "schedule.show",
19
+ "schedule.history",
20
+ "schedule.pause",
21
+ "schedule.resume",
22
+ "schedule.run",
23
+ "schedule.run-due",
24
+ "schedule.delete",
25
+ ] as const;
26
+
27
+ const MAX_TIMER_DELAY_MS = 2_147_483_647;
28
+ const DEFAULT_MAX_PENDING = 20;
29
+ const MAX_HISTORY = 100;
30
+ const STALE_LAUNCH_CLAIM_MS = 5 * 60_000;
31
+ const SCHEDULE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
32
+
33
+ type ScheduledRunTimers = Pick<typeof globalThis, "setTimeout" | "clearTimeout">;
34
+ export type ScheduledRunAction = typeof SCHEDULED_RUN_ACTIONS[number];
35
+ export type ScheduleRunState = "running" | "skipped" | "missed" | "completed" | "failed_launch" | "failed_run";
36
+ export type ScheduleTrigger =
37
+ | { kind: "once"; at: string; nextRunAt?: string }
38
+ | { kind: "interval"; every: string; everyMs: number; anchorAt: string; nextRunAt: string };
39
+ export type ScheduleTarget = { workflowScript: string };
40
+
41
+ export interface ScheduleRecord {
42
+ schemaVersion: 1;
43
+ id: string;
44
+ name: string;
45
+ cwd: string;
46
+ trigger: ScheduleTrigger;
47
+ target: ScheduleTarget;
48
+ overlap: "skip";
49
+ catchUp: "none" | "latest";
50
+ timeoutMs?: number;
51
+ paused: boolean;
52
+ createdAt: string;
53
+ updatedAt: string;
54
+ activeRunId?: string;
55
+ lastRunId?: string;
56
+ }
57
+
58
+ export interface ScheduleRunRecord {
59
+ schemaVersion: 1;
60
+ id: string;
61
+ scheduleId: string;
62
+ plannedAt: string;
63
+ dueReason: "timer" | "run-due" | "manual";
64
+ state: ScheduleRunState;
65
+ startedAt?: string;
66
+ completedAt?: string;
67
+ asyncId?: string;
68
+ asyncDir?: string;
69
+ error?: string;
70
+ }
71
+
72
+ type ScheduledRunManagerDeps = {
73
+ config: ExtensionConfig;
74
+ launch(params: SubagentParamsLike, ctx: ExtensionContext, signal: AbortSignal): Promise<AgentToolResult<Details>>;
75
+ storeRoot?: string;
76
+ now?: () => number;
77
+ randomId?: () => string;
78
+ resolveCapabilityCeiling?: (sessionId: string) => ResolvedSubagentCapabilityCeiling | undefined;
79
+ timers?: ScheduledRunTimers;
80
+ };
81
+
82
+ export function isScheduledRunAction(action: unknown): action is ScheduledRunAction {
83
+ return typeof action === "string" && (SCHEDULED_RUN_ACTIONS as readonly string[]).includes(action);
84
+ }
85
+
86
+ export function scheduledRunsEnabled(config: ExtensionConfig): boolean {
87
+ return config.scheduledRuns?.enabled !== false;
88
+ }
89
+
90
+ export function scheduledRunStorePath(cwd: string, _sessionId?: string, root?: string): string {
91
+ if (!root) return path.join(getProjectSubagentsDir(path.resolve(cwd)), "schedules");
92
+ const projectKey = createHash("sha256").update(path.resolve(cwd)).digest("hex").slice(0, 20);
93
+ return path.join(root, projectKey);
94
+ }
95
+
96
+ export function parseScheduledRunTime(at: string, now = Date.now()): number {
97
+ const trimmed = at.trim();
98
+ const relative = trimmed.match(/^\+(\d+)(s|m|h|d)$/);
99
+ if (relative) {
100
+ const amount = Number(relative[1]);
101
+ if (!Number.isSafeInteger(amount) || amount < 1) throw new Error(`Invalid at value "${at}". Relative delays must be positive, such as "+10m".`);
102
+ const unitMs = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000 }[relative[2] as "s" | "m" | "h" | "d"];
103
+ const result = now + amount * unitMs;
104
+ if (!Number.isSafeInteger(result)) throw new Error(`Invalid at value "${at}". Relative delay is too large.`);
105
+ return result;
106
+ }
107
+ const iso = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.\d{1,3})?)?(Z|[+-]\d{2}:\d{2})$/);
108
+ if (!iso) throw new Error(`Invalid at value "${at}". Use a one-shot delay such as "+10m" or an ISO timestamp with timezone.`);
109
+ const year = Number(iso[1]);
110
+ const month = Number(iso[2]);
111
+ const day = Number(iso[3]);
112
+ const hour = Number(iso[4]);
113
+ const minute = Number(iso[5]);
114
+ const second = iso[6] === undefined ? 0 : Number(iso[6]);
115
+ const zone = iso[7]!;
116
+ const offsetHour = zone === "Z" ? 0 : Number(zone.slice(1, 3));
117
+ const offsetMinute = zone === "Z" ? 0 : Number(zone.slice(4, 6));
118
+ const daysInMonth = month >= 1 && month <= 12 ? new Date(Date.UTC(year, month, 0)).getUTCDate() : 0;
119
+ const parsed = Date.parse(trimmed);
120
+ if (month < 1 || month > 12 || day < 1 || day > daysInMonth || hour > 23 || minute > 59 || second > 59 || offsetHour > 23 || offsetMinute > 59 || !Number.isFinite(parsed)) throw new Error(`Invalid at value "${at}". Use a valid ISO timestamp.`);
121
+ if (parsed <= now) throw new Error(`Scheduled time ${new Date(parsed).toISOString()} is in the past.`);
122
+ return parsed;
123
+ }
124
+
125
+ export function parseScheduleInterval(every: string): number {
126
+ const match = every.trim().match(/^(\d+)(m|h|d|w)$/);
127
+ if (!match) throw new Error(`Invalid every value "${every}". This first recurring slice supports fixed intervals such as "30m", "6h", "2d", or "2w".`);
128
+ const amount = Number(match[1]);
129
+ if (!Number.isSafeInteger(amount) || amount < 1) throw new Error(`Invalid every value "${every}". Interval must be positive.`);
130
+ const unitMs = { m: 60_000, h: 3_600_000, d: 86_400_000, w: 604_800_000 }[match[2] as "m" | "h" | "d" | "w"];
131
+ const result = amount * unitMs;
132
+ if (!Number.isSafeInteger(result)) throw new Error(`Invalid every value "${every}". Interval is too large.`);
133
+ return result;
134
+ }
135
+
136
+ function timestamp(value: number): string {
137
+ return new Date(value).toISOString();
138
+ }
139
+
140
+ function validateScheduleId(id: string): string {
141
+ if (!SCHEDULE_ID.test(id)) throw new Error("Schedule id must be 1-64 characters and contain only letters, numbers, '.', '_', or '-'.");
142
+ return id;
143
+ }
144
+
145
+ function pathWithin(root: string, candidate: string): boolean {
146
+ const relative = path.relative(root, candidate);
147
+ return relative === "" || (relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));
148
+ }
149
+
150
+ function assertScheduleRoot(root: string, projectCwd: string | undefined, create: boolean): void {
151
+ if (!projectCwd) {
152
+ if (create) fs.mkdirSync(root, { recursive: true, mode: 0o700 });
153
+ return;
154
+ }
155
+ let projectPath: string;
156
+ try {
157
+ projectPath = fs.realpathSync(projectCwd);
158
+ } catch (error) {
159
+ if (!create && (error as NodeJS.ErrnoException).code === "ENOENT") return;
160
+ throw error;
161
+ }
162
+ let existing = root;
163
+ while (!fs.existsSync(existing)) {
164
+ const parent = path.dirname(existing);
165
+ if (parent === existing) break;
166
+ existing = parent;
167
+ }
168
+ if (!pathWithin(projectPath, fs.realpathSync(existing))) throw new Error(`Project schedule root '${root}' resolves outside the real project.`);
169
+ if (!create) return;
170
+ fs.mkdirSync(root, { recursive: true, mode: 0o700 });
171
+ if (!pathWithin(projectPath, fs.realpathSync(root))) throw new Error(`Project schedule root '${root}' resolves outside the real project.`);
172
+ }
173
+
174
+ function scheduleDir(root: string, id: string, create = false, projectCwd?: string): string {
175
+ assertScheduleRoot(root, projectCwd, create);
176
+ const dir = path.join(root, validateScheduleId(id));
177
+ try {
178
+ const stat = fs.lstatSync(dir);
179
+ if (stat.isSymbolicLink() || !stat.isDirectory()) throw new Error(`Schedule path '${dir}' must be a real directory.`);
180
+ } catch (error) {
181
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
182
+ if (!create) return dir;
183
+ fs.mkdirSync(dir, { mode: 0o700 });
184
+ }
185
+ const rootPath = fs.realpathSync(root);
186
+ const dirPath = fs.realpathSync(dir);
187
+ if (dirPath !== path.join(rootPath, id)) throw new Error(`Schedule path '${dir}' escapes the project schedule root.`);
188
+ return dir;
189
+ }
190
+
191
+ function readJson(file: string, label: string): unknown {
192
+ try {
193
+ return JSON.parse(fs.readFileSync(file, "utf-8"));
194
+ } catch (error) {
195
+ throw new Error(`Failed to read ${label} '${file}': ${error instanceof Error ? error.message : String(error)}`, { cause: error instanceof Error ? error : undefined });
196
+ }
197
+ }
198
+
199
+ function parseScheduleTarget(value: unknown, file: string): ScheduleTarget {
200
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`Schedule record '${file}' has invalid trigger or target.`);
201
+ const target = value as { workflowScript?: unknown; agent?: unknown; task?: unknown };
202
+ if (typeof target.workflowScript === "string" && target.workflowScript.trim()) return { workflowScript: target.workflowScript.trim() };
203
+ if (target.agent !== undefined || target.task !== undefined) throw new Error(`Schedule record '${file}' uses a removed legacy agent target; recreate it with target.workflowScript.`);
204
+ throw new Error(`Schedule record '${file}' requires a workflowScript target.`);
205
+ }
206
+
207
+ function parseSchedule(value: unknown, file: string): ScheduleRecord {
208
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`Schedule record '${file}' must be a JSON object.`);
209
+ const record = value as Partial<ScheduleRecord>;
210
+ if (record.schemaVersion !== 1 || typeof record.id !== "string" || typeof record.name !== "string" || typeof record.cwd !== "string" || typeof record.createdAt !== "string" || typeof record.updatedAt !== "string" || typeof record.paused !== "boolean") throw new Error(`Schedule record '${file}' has invalid required fields.`);
211
+ validateScheduleId(record.id);
212
+ if (!record.trigger || typeof record.trigger !== "object" || !record.target || typeof record.target !== "object") throw new Error(`Schedule record '${file}' has invalid trigger or target.`);
213
+ if (record.overlap !== "skip" || (record.catchUp !== "none" && record.catchUp !== "latest")) throw new Error(`Schedule record '${file}' has unsupported policy fields.`);
214
+ if (record.trigger.kind === "once") {
215
+ if (typeof record.trigger.at !== "string" || (record.trigger.nextRunAt !== undefined && typeof record.trigger.nextRunAt !== "string")) throw new Error(`Schedule record '${file}' has an invalid one-shot trigger.`);
216
+ } else if (record.trigger.kind === "interval") {
217
+ if (typeof record.trigger.every !== "string" || typeof record.trigger.everyMs !== "number" || typeof record.trigger.anchorAt !== "string" || typeof record.trigger.nextRunAt !== "string") throw new Error(`Schedule record '${file}' has an invalid interval trigger.`);
218
+ } else throw new Error(`Schedule record '${file}' has an unsupported trigger.`);
219
+ return { ...record, target: parseScheduleTarget(record.target, file) } as ScheduleRecord;
220
+ }
221
+
222
+ class ScheduleStore {
223
+ readonly root: string;
224
+ private readonly projectCwd?: string;
225
+
226
+ constructor(root: string, projectCwd?: string) {
227
+ this.root = root;
228
+ this.projectCwd = projectCwd;
229
+ }
230
+
231
+ directory(id: string, create = false): string {
232
+ return scheduleDir(this.root, id, create, this.projectCwd);
233
+ }
234
+
235
+ ids(): string[] {
236
+ assertScheduleRoot(this.root, this.projectCwd, false);
237
+ if (!fs.existsSync(this.root)) return [];
238
+ return fs.readdirSync(this.root, { withFileTypes: true })
239
+ .filter((entry) => entry.isDirectory() && SCHEDULE_ID.test(entry.name))
240
+ .map((entry) => entry.name);
241
+ }
242
+
243
+ list(): ScheduleRecord[] {
244
+ return this.ids().map((id) => this.find(id)).filter((record): record is ScheduleRecord => record !== undefined);
245
+ }
246
+
247
+ get(id: string): ScheduleRecord {
248
+ const record = this.find(id);
249
+ if (!record) throw new Error(`Schedule '${id}' not found.`);
250
+ return record;
251
+ }
252
+
253
+ /** Like {@link get}, but returns undefined when the schedule no longer exists. */
254
+ find(id: string): ScheduleRecord | undefined {
255
+ const file = path.join(scheduleDir(this.root, id, false, this.projectCwd), "schedule.json");
256
+ if (!fs.existsSync(file)) return undefined;
257
+ return parseSchedule(readJson(file, "schedule record"), file);
258
+ }
259
+
260
+ write(record: ScheduleRecord): void {
261
+ writePrivateAtomicJson(path.join(scheduleDir(this.root, record.id, true, this.projectCwd), "schedule.json"), record);
262
+ }
263
+
264
+ delete(id: string): void {
265
+ fs.rmSync(scheduleDir(this.root, id, false, this.projectCwd), { recursive: true, force: true });
266
+ }
267
+
268
+ history(id: string): ScheduleRunRecord[] {
269
+ const file = path.join(scheduleDir(this.root, id, false, this.projectCwd), "history.json");
270
+ if (!fs.existsSync(file)) return [];
271
+ const value = readJson(file, "schedule history") as { schemaVersion?: unknown; runs?: unknown };
272
+ if (value?.schemaVersion !== 1 || !Array.isArray(value.runs)) throw new Error(`Schedule history '${file}' has invalid fields.`);
273
+ return value.runs as ScheduleRunRecord[];
274
+ }
275
+
276
+ writeRun(schedule: ScheduleRecord, run: ScheduleRunRecord, event: string): void {
277
+ const dir = scheduleDir(this.root, schedule.id, true, this.projectCwd);
278
+ writePrivateAtomicJson(path.join(dir, "runs", `${run.id}.json`), run);
279
+ const runs = [run, ...this.history(schedule.id).filter((item) => item.id !== run.id)].slice(0, MAX_HISTORY);
280
+ writePrivateAtomicJson(path.join(dir, "history.json"), { schemaVersion: 1, runs });
281
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
282
+ fs.appendFileSync(path.join(dir, "events.jsonl"), `${JSON.stringify({ schemaVersion: 1, timestamp: new Date().toISOString(), event, scheduleId: schedule.id, runId: run.id, state: run.state })}\n`, { encoding: "utf-8", mode: 0o600 });
283
+ }
284
+
285
+ appendEvent(schedule: ScheduleRecord, event: string): void {
286
+ const dir = scheduleDir(this.root, schedule.id, true, this.projectCwd);
287
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
288
+ fs.appendFileSync(path.join(dir, "events.jsonl"), `${JSON.stringify({ schemaVersion: 1, timestamp: new Date().toISOString(), event, scheduleId: schedule.id })}\n`, { encoding: "utf-8", mode: 0o600 });
289
+ }
290
+ }
291
+
292
+ function resolveMaxPending(config: ExtensionConfig): number {
293
+ const value = config.scheduledRuns?.maxPending;
294
+ return typeof value === "number" && Number.isInteger(value) && value >= 1 ? value : DEFAULT_MAX_PENDING;
295
+ }
296
+
297
+ function nextAfter(trigger: ScheduleTrigger, plannedAt: number, now: number): string | undefined {
298
+ if (trigger.kind === "once") return undefined;
299
+ let next = plannedAt + trigger.everyMs;
300
+ while (next <= now) next += trigger.everyMs;
301
+ return timestamp(next);
302
+ }
303
+
304
+ function nextRunAt(schedule: ScheduleRecord): number | undefined {
305
+ const value = schedule.trigger.nextRunAt;
306
+ if (!value) return undefined;
307
+ const parsed = Date.parse(value);
308
+ if (!Number.isFinite(parsed)) throw new Error(`Schedule '${schedule.id}' has invalid nextRunAt.`);
309
+ return parsed;
310
+ }
311
+
312
+ function duePlannedAt(schedule: ScheduleRecord, now: number): number | undefined {
313
+ const next = nextRunAt(schedule);
314
+ if (next === undefined || next > now || schedule.catchUp !== "latest" || schedule.trigger.kind !== "interval") return next;
315
+ return next + Math.floor((now - next) / schedule.trigger.everyMs) * schedule.trigger.everyMs;
316
+ }
317
+
318
+ function textResult(text: string, schedules?: ScheduleRecord[], runs?: ScheduleRunRecord[], isError = false): AgentToolResult<Details> {
319
+ return {
320
+ content: [{ type: "text", text }],
321
+ ...(isError ? { isError: true } : {}),
322
+ details: { mode: "management", results: [], schedules: { ...(schedules ? { records: schedules } : {}), ...(runs ? { runs } : {}) } },
323
+ };
324
+ }
325
+
326
+ function targetLabel(target: ScheduleTarget): string {
327
+ const preview = previewSimpleWorkflowRun(target.workflowScript);
328
+ return preview?.agent ? `workflowScript -> agent ${preview.agent}` : "workflowScript (dynamic)";
329
+ }
330
+
331
+ function sanitizeTarget(params: SubagentParamsLike): { target?: ScheduleTarget; error?: string } {
332
+ if (params.tasks || params.chain) return { error: "Recurring schedules require workflowScript; legacy tasks and chain inputs are unsupported." };
333
+ if (params.agent !== undefined || params.task !== undefined) return { error: "schedule.create requires workflowScript. Use workflowScript: \"return runs.run('main', { agent, task })\"." };
334
+ if (typeof params.workflowScript !== "string" || !params.workflowScript.trim()) return { error: "schedule.create requires a non-empty workflowScript." };
335
+ if (params.context === "fork") return { error: "Scheduled runs require fresh context." };
336
+ if (params.async === false) return { error: "Scheduled runs are always async." };
337
+ const acceptanceErrors = validateExecutionAcceptance(params as Parameters<typeof validateExecutionAcceptance>[0]);
338
+ if (acceptanceErrors.length) return { error: acceptanceErrors.join(" ") };
339
+ return { target: { workflowScript: params.workflowScript.trim() } };
340
+ }
341
+
342
+ function executionParams(schedule: ScheduleRecord): SubagentParamsLike {
343
+ return {
344
+ ...schedule.target,
345
+ async: true,
346
+ context: "fresh",
347
+ cwd: schedule.cwd,
348
+ mission: false,
349
+ // Scheduled fires have no operator watching, so completions must name the origin.
350
+ scheduleOrigin: { id: schedule.id, ...(schedule.name ? { name: schedule.name } : {}) },
351
+ ...(schedule.timeoutMs === undefined ? {} : { timeoutMs: schedule.timeoutMs }),
352
+ };
353
+ }
354
+
355
+ function snapshotContext(ctx: ExtensionContext, cwd: string): ExtensionContext {
356
+ const source = ctx.sessionManager;
357
+ const sessionId = source.getSessionId();
358
+ const sessionFile = source.getSessionFile();
359
+ const sessionManager = new Proxy(source, {
360
+ get(target, property) {
361
+ if (property === "getSessionId") return () => sessionId;
362
+ if (property === "getSessionFile") return () => sessionFile;
363
+ const value = Reflect.get(target, property, target) as unknown;
364
+ return typeof value === "function" ? value.bind(target) : value;
365
+ },
366
+ });
367
+ return { ...ctx, cwd, sessionManager };
368
+ }
369
+
370
+ export function listScheduledRunSummaries(cwd: string, root?: string): ScheduleRecord[] {
371
+ return new ScheduleStore(scheduledRunStorePath(cwd, undefined, root), root === undefined ? path.resolve(cwd) : undefined).list();
372
+ }
373
+
374
+ export class ScheduledRunManager {
375
+ private store?: ScheduleStore;
376
+ private readonly stores = new Map<string, ScheduleStore>();
377
+ private readonly contexts = new Map<string, ExtensionContext>();
378
+ private readonly timers = new Map<string, ReturnType<typeof setTimeout>>();
379
+ private readonly observedAsyncIds = new Set<string>();
380
+ private readonly now: () => number;
381
+ private readonly randomId: () => string;
382
+ private readonly timersApi: ScheduledRunTimers;
383
+ private readonly deps: ScheduledRunManagerDeps;
384
+
385
+ constructor(deps: ScheduledRunManagerDeps) {
386
+ this.deps = deps;
387
+ this.now = deps.now ?? Date.now;
388
+ this.randomId = deps.randomId ?? (() => randomUUID().slice(0, 8));
389
+ this.timersApi = deps.timers ?? globalThis;
390
+ }
391
+
392
+ bindSession(ctx: ExtensionContext): void {
393
+ if (!scheduledRunsEnabled(this.deps.config)) return;
394
+ this.selectProject(ctx.cwd, ctx);
395
+ }
396
+
397
+ stop(): void {
398
+ this.stopTimers();
399
+ this.store = undefined;
400
+ this.stores.clear();
401
+ this.contexts.clear();
402
+ this.observedAsyncIds.clear();
403
+ }
404
+
405
+ async handleToolCall(params: SubagentParamsLike, ctx: ExtensionContext): Promise<AgentToolResult<Details>> {
406
+ try {
407
+ if (!scheduledRunsEnabled(this.deps.config)) return textResult("Scheduled runs are disabled by scheduledRuns.enabled=false.", undefined, undefined, true);
408
+ this.selectProject(params.cwd ?? ctx.cwd, ctx);
409
+ switch (params.action) {
410
+ case "schedule.create": return this.create(params, ctx);
411
+ case "schedule.list": return this.list();
412
+ case "schedule.show": return this.show(params);
413
+ case "schedule.history": return this.history(params);
414
+ case "schedule.pause": return this.pause(params, true);
415
+ case "schedule.resume": return this.pause(params, false);
416
+ case "schedule.run": return await this.runManual(params);
417
+ case "schedule.run-due": return await this.runDue();
418
+ case "schedule.delete": return this.remove(params);
419
+ default: return textResult(`Unknown schedule action: ${params.action}`, undefined, undefined, true);
420
+ }
421
+ } catch (error) {
422
+ return textResult(error instanceof Error ? error.message : String(error), undefined, undefined, true);
423
+ }
424
+ }
425
+
426
+ observedCompletionRunIds(): Set<string> {
427
+ return new Set(this.observedAsyncIds);
428
+ }
429
+
430
+ referencedAsyncRunIds(): Set<string> {
431
+ const runIds = new Set(this.observedAsyncIds);
432
+ for (const store of this.stores.values()) {
433
+ for (const scheduleId of store.ids()) {
434
+ for (const run of store.history(scheduleId)) {
435
+ if (run.asyncId) runIds.add(run.asyncId);
436
+ }
437
+ }
438
+ }
439
+ return runIds;
440
+ }
441
+
442
+ handleAsyncCompletion(payload: unknown): void {
443
+ if (!payload || typeof payload !== "object") return;
444
+ const data = payload as { id?: unknown; runId?: unknown; success?: unknown; state?: unknown; summary?: unknown };
445
+ const asyncId = typeof data.runId === "string" ? data.runId : typeof data.id === "string" ? data.id : undefined;
446
+ if (!asyncId) return;
447
+ for (const store of this.stores.values()) {
448
+ let ids: string[];
449
+ try {
450
+ ids = store.ids();
451
+ } catch (error) {
452
+ console.error(`Failed to inspect schedule store '${store.root}' during async completion:`, error);
453
+ continue;
454
+ }
455
+ for (const id of ids) {
456
+ try {
457
+ const schedule = store.get(id);
458
+ const run = store.history(id).find((item) => item.asyncId === asyncId && item.state === "running");
459
+ if (!run) continue;
460
+ this.finishRun(store, schedule, run, data.success === true, typeof data.summary === "string" ? data.summary : undefined);
461
+ return;
462
+ } catch (error) {
463
+ console.error(`Failed to inspect schedule '${id}' in '${store.root}' during async completion:`, error);
464
+ }
465
+ }
466
+ }
467
+ }
468
+
469
+ private create(params: SubagentParamsLike, ctx: ExtensionContext): AgentToolResult<Details> {
470
+ const store = this.requireStore();
471
+ const target = sanitizeTarget(params);
472
+ if (target.error) return textResult(target.error, undefined, undefined, true);
473
+ const at = params.at?.trim();
474
+ const every = params.every?.trim();
475
+ if (Boolean(at) === Boolean(every)) return textResult("schedule.create requires exactly one trigger: at or every.", undefined, undefined, true);
476
+ if (params.overlap !== undefined && params.overlap !== "skip") return textResult("This first recurring slice supports overlap='skip' only.", undefined, undefined, true);
477
+ if (params.catchUp !== undefined && params.catchUp !== "none" && params.catchUp !== "latest") return textResult("catchUp must be 'none' or 'latest'.", undefined, undefined, true);
478
+ if (params.missionId !== undefined || params.mission !== undefined || params.missionUpdate !== undefined || params.missionStatus !== undefined || params.missionScope !== undefined) return textResult("Mission attachment is deferred from this first schedule slice.", undefined, undefined, true);
479
+ if (params.on !== undefined || params.timezone !== undefined || every === "day" || every === "week" || every === "month" || every === "year") return textResult("Calendar schedules are deferred from this first safe slice. Use a fixed interval such as every:'24h' or every:'7d'.", undefined, undefined, true);
480
+ const sessionId = ctx.sessionManager.getSessionId() ?? "unknown";
481
+ if (this.deps.resolveCapabilityCeiling?.(sessionId)) return textResult("Cannot persist a schedule while a capability ceiling is active.", undefined, undefined, true);
482
+ if (store.list().length >= resolveMaxPending(this.deps.config)) return textResult(`Schedule limit reached (${resolveMaxPending(this.deps.config)}).`, undefined, undefined, true);
483
+ const id = validateScheduleId((params.id?.trim() || this.randomId()));
484
+ if (store.ids().includes(id)) return textResult(`Schedule '${id}' already exists.`, undefined, undefined, true);
485
+ const now = this.now();
486
+ let trigger: ScheduleTrigger;
487
+ if (at) {
488
+ const planned = parseScheduledRunTime(at, now);
489
+ trigger = { kind: "once", at, nextRunAt: timestamp(planned) };
490
+ } else {
491
+ const everyMs = parseScheduleInterval(every!);
492
+ trigger = { kind: "interval", every: every!, everyMs, anchorAt: timestamp(now), nextRunAt: timestamp(now + everyMs) };
493
+ }
494
+ const schedule: ScheduleRecord = {
495
+ schemaVersion: 1,
496
+ id,
497
+ name: params.name?.trim() || targetLabel(target.target!),
498
+ cwd: path.resolve(params.cwd ?? ctx.cwd),
499
+ trigger,
500
+ target: target.target!,
501
+ overlap: "skip",
502
+ catchUp: params.catchUp ?? "latest",
503
+ ...(params.timeoutMs === undefined ? {} : { timeoutMs: params.timeoutMs }),
504
+ paused: false,
505
+ createdAt: timestamp(now),
506
+ updatedAt: timestamp(now),
507
+ };
508
+ store.write(schedule);
509
+ store.appendEvent(schedule, "schedule.created");
510
+ this.arm(schedule, store);
511
+ return textResult(`Created schedule ${id}.\nName: ${schedule.name}\nTrigger: ${at ? `at ${at}` : `every ${every}`}\nNext: ${schedule.trigger.nextRunAt}\nTarget: ${targetLabel(schedule.target)}`, [schedule]);
512
+ }
513
+
514
+ private list(): AgentToolResult<Details> {
515
+ const schedules = this.requireStore().list().sort((a, b) => (a.trigger.nextRunAt ?? "").localeCompare(b.trigger.nextRunAt ?? ""));
516
+ if (!schedules.length) return textResult("No project schedules.", []);
517
+ return textResult([`Project schedules: ${schedules.length}`, ...schedules.map((item) => `- ${item.id} | ${item.paused ? "paused" : item.activeRunId ? "running" : "scheduled"} | ${item.trigger.nextRunAt ?? "no next run"} | ${item.name}`)].join("\n"), schedules);
518
+ }
519
+
520
+ private show(params: SubagentParamsLike): AgentToolResult<Details> {
521
+ const schedule = this.resolve(params);
522
+ return textResult([`Schedule: ${schedule.id}`, `Name: ${schedule.name}`, `State: ${schedule.paused ? "paused" : schedule.activeRunId ? "running" : "scheduled"}`, `Target: ${targetLabel(schedule.target)}`, `CWD: ${shortenPath(schedule.cwd)}`, `Next: ${schedule.trigger.nextRunAt ?? "none"}`, `Catch up: ${schedule.catchUp}`, schedule.activeRunId ? `Active run: ${schedule.activeRunId}` : undefined].filter(Boolean).join("\n"), [schedule]);
523
+ }
524
+
525
+ private history(params: SubagentParamsLike): AgentToolResult<Details> {
526
+ const schedule = this.resolve(params);
527
+ const runs = this.requireStore().history(schedule.id);
528
+ return textResult(runs.length ? [`Schedule history: ${schedule.id}`, ...runs.map((run) => `- ${run.id} | ${run.state} | ${run.plannedAt}${run.asyncId ? ` | async ${run.asyncId}` : ""}`)].join("\n") : `No runs recorded for schedule ${schedule.id}.`, [schedule], runs);
529
+ }
530
+
531
+ private pause(params: SubagentParamsLike, paused: boolean): AgentToolResult<Details> {
532
+ const schedule = this.resolve(params);
533
+ if (schedule.paused === paused) return textResult(`Schedule ${schedule.id} is already ${paused ? "paused" : "active"}.`, [schedule]);
534
+ schedule.paused = paused;
535
+ schedule.updatedAt = timestamp(this.now());
536
+ this.requireStore().write(schedule);
537
+ this.requireStore().appendEvent(schedule, paused ? "schedule.paused" : "schedule.resumed");
538
+ const store = this.requireStore();
539
+ if (paused) this.clearTimer(store, schedule.id); else this.restoreOne(store, schedule);
540
+ return textResult(`${paused ? "Paused" : "Resumed"} schedule ${schedule.id}.`, [schedule]);
541
+ }
542
+
543
+ private async runManual(params: SubagentParamsLike): Promise<AgentToolResult<Details>> {
544
+ const store = this.requireStore();
545
+ const schedule = this.resolve(params);
546
+ const run = await this.launch(store, schedule, this.now(), "manual", false);
547
+ return textResult(`Manual schedule run ${run.id}: ${run.state}${run.asyncId ? ` (async ${run.asyncId})` : ""}.`, [store.get(schedule.id)], [run], run.state === "failed_launch");
548
+ }
549
+
550
+ private async runDue(): Promise<AgentToolResult<Details>> {
551
+ const store = this.requireStore();
552
+ const due = store.list().filter((schedule) => !schedule.paused && nextRunAt(schedule) !== undefined && nextRunAt(schedule)! <= this.now());
553
+ const runs: ScheduleRunRecord[] = [];
554
+ for (const schedule of due) {
555
+ const planned = duePlannedAt(schedule, this.now())!;
556
+ if (!schedule.activeRunId && schedule.catchUp === "none" && planned < this.now()) runs.push(this.recordMissed(store, schedule, planned, "run-due"));
557
+ else runs.push(await this.launch(store, schedule, planned, "run-due", true));
558
+ }
559
+ return textResult(runs.length ? `Processed ${runs.length} due schedule(s).` : "No schedules are due.", store.list(), runs);
560
+ }
561
+
562
+ private remove(params: SubagentParamsLike): AgentToolResult<Details> {
563
+ const schedule = this.resolve(params);
564
+ if (schedule.activeRunId) return textResult(`Schedule ${schedule.id} has active run ${schedule.activeRunId}; stop that run before deleting the schedule.`, [schedule], undefined, true);
565
+ const store = this.requireStore();
566
+ this.clearTimer(store, schedule.id);
567
+ store.appendEvent(schedule, "schedule.deleted");
568
+ store.delete(schedule.id);
569
+ return textResult(`Deleted schedule ${schedule.id}.`);
570
+ }
571
+
572
+ private restore(store: ScheduleStore): void {
573
+ for (const schedule of store.list()) this.restoreOne(store, schedule);
574
+ }
575
+
576
+ private restoreOne(store: ScheduleStore, schedule: ScheduleRecord, notBefore?: number, rearm = true): void {
577
+ if (schedule.activeRunId) {
578
+ const run = store.history(schedule.id).find((item) => item.id === schedule.activeRunId);
579
+ if (run?.state === "running" && run.asyncId) this.observedAsyncIds.add(run.asyncId);
580
+ const startedAt = run?.startedAt ? Date.parse(run.startedAt) : Number.NaN;
581
+ if (run?.state === "running" && run.asyncDir) {
582
+ try {
583
+ const status = readJson(path.join(run.asyncDir, "status.json"), "async status") as Partial<AsyncStatus>;
584
+ if (["complete", "failed", "stopped", "rejected"].includes(String(status.state))) this.finishRun(store, schedule, run, status.state === "complete", typeof status.error === "string" ? status.error : undefined);
585
+ } catch (error) {
586
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT" && !(error instanceof Error && /ENOENT/.test(error.message))) throw error;
587
+ }
588
+ }
589
+ if (schedule.activeRunId && (!run || run.state !== "running" || (!run.asyncId && Number.isFinite(startedAt) && startedAt + STALE_LAUNCH_CLAIM_MS <= this.now()))) {
590
+ if (run?.state === "running") {
591
+ run.state = "failed_launch";
592
+ run.completedAt = timestamp(this.now());
593
+ run.error = "Recovered a stale launch claim before an async run was attached.";
594
+ store.writeRun(schedule, run, "schedule.run.failed");
595
+ }
596
+ schedule.activeRunId = undefined;
597
+ schedule.updatedAt = timestamp(this.now());
598
+ store.write(schedule);
599
+ fs.rmSync(path.join(store.directory(schedule.id), "active.lock"), { force: true });
600
+ }
601
+ }
602
+ if (!rearm || schedule.paused) return;
603
+ const next = nextRunAt(schedule);
604
+ if (next === undefined) return;
605
+ if (!schedule.activeRunId && next < this.now() && schedule.catchUp === "none") {
606
+ try {
607
+ this.recordMissed(store, schedule, next, "timer");
608
+ } catch (error) {
609
+ if (notBefore !== undefined) this.arm(schedule, store, notBefore);
610
+ throw error;
611
+ }
612
+ }
613
+ this.arm(schedule, store, notBefore);
614
+ }
615
+
616
+ private arm(schedule: ScheduleRecord, store: ScheduleStore, notBefore?: number): void {
617
+ this.clearTimer(store, schedule.id);
618
+ if (schedule.paused) return;
619
+ const next = nextRunAt(schedule);
620
+ if (next === undefined) return;
621
+ const timer = this.timersApi.setTimeout(() => {
622
+ // A timer callback is outside every caller's try/catch, so an escaping
623
+ // rejection here reaches the process as an uncaught exception and exits
624
+ // Pi. Contain every failure to this one schedule.
625
+ void this.fire(store, schedule.id).catch((error) => {
626
+ console.warn(`[pi-subagents] Scheduled run '${schedule.id}' failed to fire: ${error instanceof Error ? error.message : String(error)}`);
627
+ this.restoreAfterFireError(store, schedule.id);
628
+ });
629
+ }, Math.min(Math.max(0, next - this.now(), (notBefore ?? 0) - this.now()), MAX_TIMER_DELAY_MS));
630
+ timer.unref?.();
631
+ this.timers.set(this.timerKey(store, schedule.id), timer);
632
+ }
633
+
634
+ private restoreAfterFireError(store: ScheduleStore, id: string): void {
635
+ try {
636
+ const schedule = store.find(id);
637
+ if (!schedule) return;
638
+ const now = this.now();
639
+ const planned = schedule.trigger.kind === "interval" ? duePlannedAt(schedule, now) : undefined;
640
+ const notBefore = planned !== undefined && planned <= now ? Date.parse(nextAfter(schedule.trigger, planned, now)!) : undefined;
641
+ this.restoreOne(store, schedule, notBefore, schedule.trigger.kind === "interval");
642
+ } catch (error) {
643
+ console.warn(`[pi-subagents] Scheduled run '${id}' could not be restored after fire failure: ${error instanceof Error ? error.message : String(error)}`);
644
+ }
645
+ }
646
+
647
+ private async fire(store: ScheduleStore, id: string): Promise<void> {
648
+ this.clearTimer(store, id);
649
+ // Schedules are project-scoped and shared, and `delete` only clears the
650
+ // timer inside the deleting process. Another session can therefore remove
651
+ // a schedule while this process still holds an armed timer for it; there
652
+ // is then nothing to run and nothing to re-arm.
653
+ const schedule = store.find(id);
654
+ if (!schedule) return;
655
+ const planned = duePlannedAt(schedule, this.now());
656
+ if (planned === undefined || schedule.paused) return;
657
+ if (planned > this.now()) return this.arm(schedule, store);
658
+ await this.launch(store, schedule, planned, "timer", true);
659
+ }
660
+
661
+ private async launch(store: ScheduleStore, schedule: ScheduleRecord, planned: number, dueReason: ScheduleRunRecord["dueReason"], advance: boolean): Promise<ScheduleRunRecord> {
662
+ const now = this.now();
663
+ const run: ScheduleRunRecord = { schemaVersion: 1, id: this.randomId(), scheduleId: schedule.id, plannedAt: timestamp(planned), dueReason, state: "running", startedAt: timestamp(now) };
664
+ if (schedule.activeRunId) {
665
+ run.state = "skipped";
666
+ run.completedAt = timestamp(now);
667
+ if (advance) {
668
+ schedule.trigger.nextRunAt = nextAfter(schedule.trigger, planned, now);
669
+ schedule.updatedAt = timestamp(now);
670
+ store.write(schedule);
671
+ }
672
+ store.writeRun(schedule, run, "schedule.skipped_overlap");
673
+ this.arm(schedule, store);
674
+ return run;
675
+ }
676
+ const lockPath = path.join(store.directory(schedule.id, true), "active.lock");
677
+ fs.mkdirSync(path.dirname(lockPath), { recursive: true, mode: 0o700 });
678
+ let lock: number;
679
+ try {
680
+ lock = fs.openSync(lockPath, "wx", 0o600);
681
+ fs.writeFileSync(lock, run.id, "utf-8");
682
+ fs.closeSync(lock);
683
+ } catch (error) {
684
+ if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
685
+ run.state = "skipped";
686
+ run.completedAt = timestamp(now);
687
+ if (advance) {
688
+ schedule.trigger.nextRunAt = nextAfter(schedule.trigger, planned, now);
689
+ schedule.updatedAt = timestamp(now);
690
+ store.write(schedule);
691
+ }
692
+ store.writeRun(schedule, run, "schedule.skipped_overlap");
693
+ this.arm(schedule, store);
694
+ return run;
695
+ }
696
+ schedule.activeRunId = run.id;
697
+ schedule.lastRunId = run.id;
698
+ if (advance) schedule.trigger.nextRunAt = nextAfter(schedule.trigger, planned, now);
699
+ schedule.updatedAt = timestamp(now);
700
+ store.write(schedule);
701
+ store.writeRun(schedule, run, "schedule.run.started");
702
+ try {
703
+ const result = await this.deps.launch(executionParams(schedule), this.requireContext(store), new AbortController().signal);
704
+ const asyncId = result.details?.asyncId ?? result.details?.runId;
705
+ if (result.isError || !asyncId) throw new Error(result.content.find((item) => item.type === "text")?.text ?? "Scheduled launch failed.");
706
+ run.asyncId = asyncId;
707
+ run.asyncDir = result.details?.asyncDir;
708
+ this.observedAsyncIds.add(asyncId);
709
+ store.writeRun(schedule, run, "schedule.run.attached_async");
710
+ this.arm(schedule, store);
711
+ return run;
712
+ } catch (error) {
713
+ run.state = "failed_launch";
714
+ run.completedAt = timestamp(this.now());
715
+ run.error = error instanceof Error ? error.message : String(error);
716
+ schedule.activeRunId = undefined;
717
+ schedule.updatedAt = timestamp(this.now());
718
+ store.write(schedule);
719
+ store.writeRun(schedule, run, "schedule.run.failed");
720
+ fs.rmSync(lockPath, { force: true });
721
+ this.arm(schedule, store);
722
+ return run;
723
+ }
724
+ }
725
+
726
+ private finishRun(store: ScheduleStore, schedule: ScheduleRecord, run: ScheduleRunRecord, success: boolean, error?: string): void {
727
+ const now = this.now();
728
+ const next = nextRunAt(schedule);
729
+ if (next !== undefined && next <= now) {
730
+ const planned = duePlannedAt(schedule, now)!;
731
+ const skipped: ScheduleRunRecord = {
732
+ schemaVersion: 1,
733
+ id: this.randomId(),
734
+ scheduleId: schedule.id,
735
+ plannedAt: timestamp(planned),
736
+ dueReason: "timer",
737
+ state: "skipped",
738
+ completedAt: timestamp(now),
739
+ };
740
+ schedule.trigger.nextRunAt = nextAfter(schedule.trigger, planned, now);
741
+ store.writeRun(schedule, skipped, "schedule.skipped_overlap");
742
+ }
743
+ if (run.asyncId) this.observedAsyncIds.delete(run.asyncId);
744
+ run.state = success ? "completed" : "failed_run";
745
+ run.completedAt = timestamp(now);
746
+ if (!success && error) run.error = error;
747
+ schedule.activeRunId = undefined;
748
+ schedule.updatedAt = timestamp(now);
749
+ store.write(schedule);
750
+ fs.rmSync(path.join(store.directory(schedule.id), "active.lock"), { force: true });
751
+ store.writeRun(schedule, run, success ? "schedule.run.completed" : "schedule.run.failed");
752
+ this.arm(schedule, store);
753
+ }
754
+
755
+ private recordMissed(store: ScheduleStore, schedule: ScheduleRecord, planned: number, dueReason: ScheduleRunRecord["dueReason"]): ScheduleRunRecord {
756
+ const run: ScheduleRunRecord = {
757
+ schemaVersion: 1,
758
+ id: this.randomId(),
759
+ scheduleId: schedule.id,
760
+ plannedAt: timestamp(planned),
761
+ dueReason,
762
+ state: "missed",
763
+ completedAt: timestamp(this.now()),
764
+ };
765
+ schedule.trigger.nextRunAt = nextAfter(schedule.trigger, planned, this.now());
766
+ schedule.updatedAt = timestamp(this.now());
767
+ store.write(schedule);
768
+ store.writeRun(schedule, run, "schedule.missed");
769
+ return run;
770
+ }
771
+
772
+ private selectProject(cwd: string, ctx: ExtensionContext): void {
773
+ const projectCwd = path.resolve(cwd);
774
+ const root = scheduledRunStorePath(projectCwd, undefined, this.deps.storeRoot);
775
+ if (path.resolve(ctx.cwd) === projectCwd) this.contexts.set(root, snapshotContext(ctx, projectCwd));
776
+ else if (!this.contexts.has(root)) throw new Error(`Cannot use project '${projectCwd}' until that project has been opened in this runtime.`);
777
+ let store = this.stores.get(root);
778
+ if (!store) {
779
+ store = new ScheduleStore(root, this.deps.storeRoot === undefined ? projectCwd : undefined);
780
+ this.stores.set(root, store);
781
+ this.restore(store);
782
+ }
783
+ this.store = store;
784
+ }
785
+
786
+ private resolve(params: SubagentParamsLike): ScheduleRecord {
787
+ const id = params.id?.trim();
788
+ if (!id) throw new Error(`${params.action} requires id.`);
789
+ return this.requireStore().get(id);
790
+ }
791
+
792
+ private requireStore(): ScheduleStore {
793
+ if (!this.store) throw new Error("Schedule store is unavailable.");
794
+ return this.store;
795
+ }
796
+
797
+ private requireContext(store: ScheduleStore): ExtensionContext {
798
+ const ctx = this.contexts.get(store.root);
799
+ if (!ctx) throw new Error("Schedule runtime context is unavailable.");
800
+ return ctx;
801
+ }
802
+
803
+ private timerKey(store: ScheduleStore, id: string): string {
804
+ return `${store.root}\0${id}`;
805
+ }
806
+
807
+ private clearTimer(store: ScheduleStore, id: string): void {
808
+ const key = this.timerKey(store, id);
809
+ const timer = this.timers.get(key);
810
+ if (!timer) return;
811
+ this.timersApi.clearTimeout(timer);
812
+ this.timers.delete(key);
813
+ }
814
+
815
+ private stopTimers(): void {
816
+ for (const timer of this.timers.values()) this.timersApi.clearTimeout(timer);
817
+ this.timers.clear();
818
+ }
819
+ }
820
+
821
+ export function createScheduledRunManager(deps: ScheduledRunManagerDeps): ScheduledRunManager {
822
+ return new ScheduledRunManager(deps);
823
+ }