@ashx-j/lunr 0.2.11 → 0.2.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 (342) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +211 -236
  3. package/dist/builtin-extensions/ashxj-tui.d.ts +3 -0
  4. package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
  5. package/dist/builtin-extensions/ashxj-tui.js +28 -11
  6. package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
  7. package/dist/builtin-extensions/index.d.ts.map +1 -1
  8. package/dist/builtin-extensions/index.js +0 -2
  9. package/dist/builtin-extensions/index.js.map +1 -1
  10. package/dist/builtin-extensions/lunr-cron.d.ts +1 -1
  11. package/dist/builtin-extensions/lunr-cron.d.ts.map +1 -1
  12. package/dist/builtin-extensions/lunr-cron.js +1 -1
  13. package/dist/builtin-extensions/lunr-cron.js.map +1 -1
  14. package/dist/builtin-extensions/pi-subagents/src/extension/chain-validation.d.ts.map +1 -1
  15. package/dist/builtin-extensions/pi-subagents/src/extension/chain-validation.js +3 -3
  16. package/dist/builtin-extensions/pi-subagents/src/extension/chain-validation.js.map +1 -1
  17. package/dist/builtin-extensions/pi-subagents/src/extension/doctor.d.ts +0 -2
  18. package/dist/builtin-extensions/pi-subagents/src/extension/doctor.d.ts.map +1 -1
  19. package/dist/builtin-extensions/pi-subagents/src/extension/doctor.js +1 -23
  20. package/dist/builtin-extensions/pi-subagents/src/extension/doctor.js.map +1 -1
  21. package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.d.ts.map +1 -1
  22. package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.js +6 -7
  23. package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.js.map +1 -1
  24. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +1 -1
  25. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  26. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +7 -14
  27. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  28. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts +12 -9
  29. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
  30. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +38 -34
  31. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
  32. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +3 -3
  33. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
  34. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +32 -47
  35. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
  36. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.d.ts +2 -2
  37. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.d.ts.map +1 -1
  38. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.js.map +1 -1
  39. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts +7 -10
  40. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts.map +1 -1
  41. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js +90 -109
  42. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js.map +1 -1
  43. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts +3 -2
  44. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts.map +1 -1
  45. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js +37 -50
  46. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js.map +1 -1
  47. package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.d.ts.map +1 -1
  48. package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js +1 -1
  49. package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js.map +1 -1
  50. package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.d.ts +4 -0
  51. package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.d.ts.map +1 -1
  52. package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.js +5 -5
  53. package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.js.map +1 -1
  54. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts.map +1 -1
  55. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js +31 -13
  56. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js.map +1 -1
  57. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.d.ts +2 -2
  58. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.d.ts.map +1 -1
  59. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.js.map +1 -1
  60. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts +4 -3
  61. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
  62. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +48 -20
  63. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
  64. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts +2 -2
  65. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
  66. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +90 -64
  67. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
  68. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts +6 -8
  69. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  70. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +262 -161
  71. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
  72. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts +2 -1
  73. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts.map +1 -1
  74. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js +24 -33
  75. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js.map +1 -1
  76. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts +25 -0
  77. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts.map +1 -0
  78. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js +51 -0
  79. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js.map +1 -0
  80. package/dist/builtin-extensions/pi-subagents/src/runs/shared/dynamic-fanout.d.ts.map +1 -1
  81. package/dist/builtin-extensions/pi-subagents/src/runs/shared/dynamic-fanout.js +20 -3
  82. package/dist/builtin-extensions/pi-subagents/src/runs/shared/dynamic-fanout.js.map +1 -1
  83. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +4 -1
  84. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
  85. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
  86. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts +5 -0
  87. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts.map +1 -1
  88. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js +9 -3
  89. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js.map +1 -1
  90. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  91. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js +2 -2
  92. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  93. package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.d.ts +2 -2
  94. package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.d.ts.map +1 -1
  95. package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.js +20 -17
  96. package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.js.map +1 -1
  97. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts +70 -0
  98. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts.map +1 -0
  99. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js +153 -0
  100. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js.map +1 -0
  101. package/dist/builtin-extensions/pi-subagents/src/shared/settings.d.ts +13 -8
  102. package/dist/builtin-extensions/pi-subagents/src/shared/settings.d.ts.map +1 -1
  103. package/dist/builtin-extensions/pi-subagents/src/shared/settings.js +20 -51
  104. package/dist/builtin-extensions/pi-subagents/src/shared/settings.js.map +1 -1
  105. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +80 -20
  106. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
  107. package/dist/builtin-extensions/pi-subagents/src/shared/types.js +10 -2
  108. package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
  109. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts +2 -2
  110. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts.map +1 -1
  111. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js +20 -32
  112. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js.map +1 -1
  113. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +2 -1
  114. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
  115. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +23 -449
  116. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
  117. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +2 -1
  118. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  119. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +13 -11
  120. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  121. package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.d.ts +2 -1
  122. package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.d.ts.map +1 -1
  123. package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.js +18 -17
  124. package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.js.map +1 -1
  125. package/dist/builtin-extensions/simple-pi-memory.d.ts +2 -2
  126. package/dist/builtin-extensions/simple-pi-memory.d.ts.map +1 -1
  127. package/dist/builtin-extensions/simple-pi-memory.js +41 -17
  128. package/dist/builtin-extensions/simple-pi-memory.js.map +1 -1
  129. package/dist/catalog/models.json +1 -1
  130. package/dist/catalog/providers/amazon-bedrock.json +1 -1
  131. package/dist/catalog/providers/azure-openai-responses.json +1 -1
  132. package/dist/catalog/providers/cloudflare-ai-gateway.json +1 -1
  133. package/dist/catalog/providers/cloudflare-workers-ai.json +1 -1
  134. package/dist/catalog/providers/fireworks.json +1 -1
  135. package/dist/catalog/providers/github-copilot.json +1 -1
  136. package/dist/catalog/providers/huggingface.json +1 -1
  137. package/dist/catalog/providers/minimax-cn.json +1 -1
  138. package/dist/catalog/providers/minimax.json +1 -1
  139. package/dist/catalog/providers/mistral.json +1 -1
  140. package/dist/catalog/providers/nvidia.json +1 -1
  141. package/dist/catalog/providers/openai.json +1 -1
  142. package/dist/catalog/providers/opencode-go.json +1 -1
  143. package/dist/catalog/providers/opencode.json +1 -1
  144. package/dist/catalog/providers/openrouter.json +1 -1
  145. package/dist/catalog/providers/qwen-cloud-cn.json +1 -1
  146. package/dist/catalog/providers/qwen-cloud.json +1 -1
  147. package/dist/catalog/providers/qwen-token-plan-cn.json +1 -1
  148. package/dist/catalog/providers/qwen-token-plan.json +1 -1
  149. package/dist/catalog/providers/together.json +1 -1
  150. package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
  151. package/dist/catalog/providers/zai-coding-cn.json +1 -1
  152. package/dist/catalog/providers/zai.json +1 -1
  153. package/dist/catalog/publication.json +3 -3
  154. package/dist/core/agent-session.d.ts +7 -1
  155. package/dist/core/agent-session.d.ts.map +1 -1
  156. package/dist/core/agent-session.js +34 -4
  157. package/dist/core/agent-session.js.map +1 -1
  158. package/dist/core/context-breakdown.d.ts +3 -1
  159. package/dist/core/context-breakdown.d.ts.map +1 -1
  160. package/dist/core/context-breakdown.js +5 -2
  161. package/dist/core/context-breakdown.js.map +1 -1
  162. package/dist/core/customize.d.ts +2 -0
  163. package/dist/core/customize.d.ts.map +1 -1
  164. package/dist/core/customize.js +6 -0
  165. package/dist/core/customize.js.map +1 -1
  166. package/dist/core/memory-cap.d.ts +4 -8
  167. package/dist/core/memory-cap.d.ts.map +1 -1
  168. package/dist/core/memory-cap.js +8 -8
  169. package/dist/core/memory-cap.js.map +1 -1
  170. package/dist/core/permissions.d.ts +2 -0
  171. package/dist/core/permissions.d.ts.map +1 -1
  172. package/dist/core/permissions.js +30 -14
  173. package/dist/core/permissions.js.map +1 -1
  174. package/dist/core/plan-mode.d.ts.map +1 -1
  175. package/dist/core/plan-mode.js +1 -9
  176. package/dist/core/plan-mode.js.map +1 -1
  177. package/dist/core/rollback.d.ts.map +1 -1
  178. package/dist/core/rollback.js +1 -1
  179. package/dist/core/rollback.js.map +1 -1
  180. package/dist/core/settings-manager.d.ts +16 -5
  181. package/dist/core/settings-manager.d.ts.map +1 -1
  182. package/dist/core/settings-manager.js +37 -10
  183. package/dist/core/settings-manager.js.map +1 -1
  184. package/dist/core/slash-commands.d.ts.map +1 -1
  185. package/dist/core/slash-commands.js +1 -5
  186. package/dist/core/slash-commands.js.map +1 -1
  187. package/dist/core/subagent-permission-inherit.d.ts +34 -22
  188. package/dist/core/subagent-permission-inherit.d.ts.map +1 -1
  189. package/dist/core/subagent-permission-inherit.js +37 -80
  190. package/dist/core/subagent-permission-inherit.js.map +1 -1
  191. package/dist/core/swarm.d.ts.map +1 -1
  192. package/dist/core/swarm.js +13 -7
  193. package/dist/core/swarm.js.map +1 -1
  194. package/dist/core/system-prompt.d.ts +6 -4
  195. package/dist/core/system-prompt.d.ts.map +1 -1
  196. package/dist/core/system-prompt.js +38 -48
  197. package/dist/core/system-prompt.js.map +1 -1
  198. package/dist/core/usage-adapters/openai-codex.d.ts +1 -1
  199. package/dist/core/usage-adapters/openai-codex.d.ts.map +1 -1
  200. package/dist/core/usage-adapters/openai-codex.js +22 -17
  201. package/dist/core/usage-adapters/openai-codex.js.map +1 -1
  202. package/dist/core/usage-service.d.ts +10 -1
  203. package/dist/core/usage-service.d.ts.map +1 -1
  204. package/dist/core/usage-service.js +17 -6
  205. package/dist/core/usage-service.js.map +1 -1
  206. package/dist/gateway/agent-bridge.d.ts.map +1 -1
  207. package/dist/gateway/agent-bridge.js +1 -4
  208. package/dist/gateway/agent-bridge.js.map +1 -1
  209. package/dist/gateway/cron.d.ts.map +1 -1
  210. package/dist/gateway/cron.js +1 -4
  211. package/dist/gateway/cron.js.map +1 -1
  212. package/dist/index.d.ts +1 -1
  213. package/dist/index.d.ts.map +1 -1
  214. package/dist/index.js.map +1 -1
  215. package/dist/main.d.ts.map +1 -1
  216. package/dist/main.js +0 -5
  217. package/dist/main.js.map +1 -1
  218. package/dist/migrations.d.ts +2 -0
  219. package/dist/migrations.d.ts.map +1 -1
  220. package/dist/migrations.js +21 -0
  221. package/dist/migrations.js.map +1 -1
  222. package/dist/modes/interactive/components/settings-selector.d.ts +7 -4
  223. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  224. package/dist/modes/interactive/components/settings-selector.js +122 -162
  225. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  226. package/dist/modes/interactive/components/usage-view.d.ts +1 -1
  227. package/dist/modes/interactive/components/usage-view.d.ts.map +1 -1
  228. package/dist/modes/interactive/components/usage-view.js +7 -4
  229. package/dist/modes/interactive/components/usage-view.js.map +1 -1
  230. package/dist/modes/interactive/interactive-mode.d.ts +1 -2
  231. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  232. package/dist/modes/interactive/interactive-mode.js +55 -96
  233. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  234. package/dist/modes/interactive/skill-tag-autocomplete.d.ts +13 -0
  235. package/dist/modes/interactive/skill-tag-autocomplete.d.ts.map +1 -0
  236. package/dist/modes/interactive/skill-tag-autocomplete.js +72 -0
  237. package/dist/modes/interactive/skill-tag-autocomplete.js.map +1 -0
  238. package/docs/compaction.md +23 -23
  239. package/docs/containerization.md +24 -24
  240. package/docs/custom-provider.md +18 -18
  241. package/docs/development.md +16 -15
  242. package/docs/docs.json +6 -2
  243. package/docs/extensions.md +82 -80
  244. package/docs/features.md +102 -0
  245. package/docs/index.md +25 -19
  246. package/docs/json.md +7 -7
  247. package/docs/keybindings.md +4 -4
  248. package/docs/models.md +2 -2
  249. package/docs/packages.md +38 -42
  250. package/docs/prompt-templates.md +4 -4
  251. package/docs/providers.md +22 -10
  252. package/docs/quickstart.md +81 -46
  253. package/docs/rpc.md +7 -13
  254. package/docs/sdk.md +43 -41
  255. package/docs/security.md +18 -18
  256. package/docs/session-format.md +9 -9
  257. package/docs/sessions.md +13 -12
  258. package/docs/settings.md +63 -24
  259. package/docs/shell-aliases.md +2 -2
  260. package/docs/skills.md +21 -11
  261. package/docs/terminal-setup.md +5 -5
  262. package/docs/termux.md +7 -7
  263. package/docs/themes.md +12 -14
  264. package/docs/tmux.md +4 -4
  265. package/docs/tui.md +23 -23
  266. package/docs/usage.md +112 -87
  267. package/docs/windows.md +10 -2
  268. package/examples/README.md +3 -1
  269. package/examples/extensions/README.md +6 -6
  270. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  271. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  272. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  273. package/examples/extensions/doom-overlay/README.md +2 -2
  274. package/examples/extensions/gondolin/package-lock.json +2 -2
  275. package/examples/extensions/gondolin/package.json +1 -1
  276. package/examples/extensions/plan-mode/README.md +3 -1
  277. package/examples/extensions/sandbox/package-lock.json +2 -2
  278. package/examples/extensions/sandbox/package.json +1 -1
  279. package/examples/extensions/subagent/README.md +13 -11
  280. package/examples/extensions/todo.ts +2 -1
  281. package/examples/extensions/with-deps/package-lock.json +2 -2
  282. package/examples/extensions/with-deps/package.json +1 -1
  283. package/examples/sdk/README.md +9 -5
  284. package/package.json +6 -7
  285. package/dist/builtin-extensions/lunr-behavior.d.ts +0 -44
  286. package/dist/builtin-extensions/lunr-behavior.d.ts.map +0 -1
  287. package/dist/builtin-extensions/lunr-behavior.js +0 -213
  288. package/dist/builtin-extensions/lunr-behavior.js.map +0 -1
  289. package/dist/builtin-extensions/pi-subagents/agents/context-builder.md +0 -46
  290. package/dist/builtin-extensions/pi-subagents/agents/deep-researcher.md +0 -36
  291. package/dist/builtin-extensions/pi-subagents/agents/delegate.md +0 -12
  292. package/dist/builtin-extensions/pi-subagents/agents/oracle.md +0 -73
  293. package/dist/builtin-extensions/pi-subagents/agents/planner.md +0 -55
  294. package/dist/builtin-extensions/pi-subagents/agents/research-writer.md +0 -37
  295. package/dist/builtin-extensions/pi-subagents/agents/researcher.md +0 -52
  296. package/dist/builtin-extensions/pi-subagents/agents/reviewer.md +0 -79
  297. package/dist/builtin-extensions/pi-subagents/agents/scout.md +0 -50
  298. package/dist/builtin-extensions/pi-subagents/agents/worker.md +0 -55
  299. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.d.ts +0 -20
  300. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.d.ts.map +0 -1
  301. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.js +0 -1273
  302. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.js.map +0 -1
  303. package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.d.ts +0 -49
  304. package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.d.ts.map +0 -1
  305. package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.js +0 -252
  306. package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.js.map +0 -1
  307. package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.d.ts +0 -3
  308. package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.d.ts.map +0 -1
  309. package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.js +0 -6
  310. package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.js.map +0 -1
  311. package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.d.ts +0 -3
  312. package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.d.ts.map +0 -1
  313. package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.js +0 -23
  314. package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.js.map +0 -1
  315. package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.d.ts +0 -8
  316. package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.d.ts.map +0 -1
  317. package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.js +0 -143
  318. package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.js.map +0 -1
  319. package/dist/builtin-extensions/pi-subagents/src/agents/agents.d.ts +0 -176
  320. package/dist/builtin-extensions/pi-subagents/src/agents/agents.d.ts.map +0 -1
  321. package/dist/builtin-extensions/pi-subagents/src/agents/agents.js +0 -1326
  322. package/dist/builtin-extensions/pi-subagents/src/agents/agents.js.map +0 -1
  323. package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.d.ts +0 -7
  324. package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.d.ts.map +0 -1
  325. package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.js +0 -307
  326. package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.js.map +0 -1
  327. package/dist/builtin-extensions/pi-subagents/src/agents/identity.d.ts +0 -8
  328. package/dist/builtin-extensions/pi-subagents/src/agents/identity.d.ts.map +0 -1
  329. package/dist/builtin-extensions/pi-subagents/src/agents/identity.js +0 -30
  330. package/dist/builtin-extensions/pi-subagents/src/agents/identity.js.map +0 -1
  331. package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.d.ts +0 -35
  332. package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.d.ts.map +0 -1
  333. package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.js +0 -151
  334. package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.js.map +0 -1
  335. package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.d.ts +0 -131
  336. package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.d.ts.map +0 -1
  337. package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.js +0 -491
  338. package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.js.map +0 -1
  339. package/dist/core/behavior-preset.d.ts +0 -60
  340. package/dist/core/behavior-preset.d.ts.map +0 -1
  341. package/dist/core/behavior-preset.js +0 -257
  342. package/dist/core/behavior-preset.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builtin-extensions/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAoB,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAuBrF,yFAAyF;AACzF,eAAO,MAAM,sBAAsB,EAAE,eAAe,EAWnD,CAAC;AAiBF,eAAO,MAAM,gCAAgC,UAAsD,CAAC;AAEpG,6FAA6F;AAC7F,eAAO,MAAM,sBAAsB,yBAA0B,CAAC;AAE9D,6EAA6E;AAC7E,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAQhF;AAED,yFAAyF;AACzF,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAE3E;AAED,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,EAAE,eAAe,EAA2B,CAAC","sourcesContent":["/**\n * Built-in extensions for lunR.\n *\n * Light factories stay on the first-paint graph. Heavy factories are imported\n * only when attachDeferredBuiltinExtensions() runs after the TUI is up, or\n * immediately for print/RPC/gateway where there is no first-paint window.\n */\n\nimport type { ExtensionFactory, InlineExtension } from \"../core/extensions/types.ts\";\n\nimport simplePiMemory from \"./simple-pi-memory.ts\";\nimport piTps from \"./pi-tps.ts\";\nimport ashxjTui from \"./ashxj-tui.ts\";\nimport ashxjSpinners from \"./ashxj-spinners.ts\";\nimport ashxjThinking from \"./ashxj-thinking.ts\";\nimport lunrLocalProviders from \"./lunr-local-providers/index.ts\";\nimport lunrTodos from \"./lunr-todos.ts\";\nimport lunrPlanTools from \"./lunr-plan-tools.ts\";\nimport lunrBehavior from \"./lunr-behavior.ts\";\nimport lunrSkillCreator from \"./lunr-skill-creator/index.ts\";\n\n/**\n * Wrap a raw factory function as a named InlineExtension.\n * The cast bridges the gap between the source-level ExtensionFactory type\n * (used here) and the dist-level type that extensions import via the package\n * name. The underlying function signatures are structurally identical.\n */\nfunction ext(name: string, factory: unknown): InlineExtension {\n\treturn { name, factory: factory as ExtensionFactory };\n}\n\n/** UI, local providers, and small lunR-native factories. Safe to import at CLI start. */\nexport const lightBuiltinExtensions: InlineExtension[] = [\n\text(\"simple-pi-memory\", simplePiMemory),\n\text(\"pi-tps\", piTps),\n\text(\"ashxj-tui\", ashxjTui),\n\text(\"ashxj-spinners\", ashxjSpinners),\n\text(\"ashxj-thinking\", ashxjThinking),\n\text(\"lunr-local-providers\", lunrLocalProviders),\n\text(\"lunr-todos\", lunrTodos),\n\text(\"lunr-plan-tools\", lunrPlanTools),\n\text(\"lunr-behavior\", lunrBehavior),\n\text(\"lunr-skill-creator\", lunrSkillCreator),\n];\n\nconst DEFERRED_BUILTIN_LOADERS: Array<{\n\tname: string;\n\tload: () => Promise<{ default: unknown }>;\n}> = [\n\t{ name: \"pi-ollama-cloud\", load: () => import(\"./pi-ollama-cloud/index.ts\") },\n\t{ name: \"narumiruna-pi-goal\", load: () => import(\"./narumiruna-pi-goal/src/goal.ts\") },\n\t{ name: \"lunr-cron\", load: () => import(\"./lunr-cron.ts\") },\n\t{ name: \"pi-intercom\", load: () => import(\"./pi-intercom/index.ts\") },\n\t{ name: \"pi-prompt-template-model\", load: () => import(\"./pi-prompt-template-model/index.ts\") },\n\t{ name: \"pi-subagents\", load: () => import(\"./pi-subagents/index.ts\") },\n\t{ name: \"pi-web-access\", load: () => import(\"./pi-web-access/index.ts\") },\n\t{ name: \"pi-lsp-extension\", load: () => import(\"./pi-lsp-extension/src/index.ts\") },\n\t{ name: \"pi-mcp-adapter\", load: () => import(\"./pi-mcp-adapter/index.ts\") },\n];\n\nexport const DEFERRED_BUILTIN_EXTENSION_NAMES = DEFERRED_BUILTIN_LOADERS.map((entry) => entry.name);\n\n/** Flags registered only after deferred builtins attach. Do not fail CLI parse for these. */\nexport const DEFERRED_BUILTIN_FLAGS = [\"mcp-config\"] as const;\n\n/** Import MCP / LSP / web-access / intercom / subagents only when needed. */\nexport async function loadDeferredBuiltinExtensions(): Promise<InlineExtension[]> {\n\tconst loaded = await Promise.all(\n\t\tDEFERRED_BUILTIN_LOADERS.map(async ({ name, load }) => {\n\t\t\tconst module = await load();\n\t\t\treturn ext(name, module.default);\n\t\t}),\n\t);\n\treturn loaded;\n}\n\n/** Full roster. Print / RPC / gateway still need every factory before the first turn. */\nexport async function loadAllBuiltinExtensions(): Promise<InlineExtension[]> {\n\treturn [...lightBuiltinExtensions, ...(await loadDeferredBuiltinExtensions())];\n}\n\n/** Eager full roster. Prefer loadAllBuiltinExtensions() so CLI start stays light. */\nexport const builtinExtensions: InlineExtension[] = lightBuiltinExtensions;\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builtin-extensions/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAoB,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAsBrF,yFAAyF;AACzF,eAAO,MAAM,sBAAsB,EAAE,eAAe,EAUnD,CAAC;AAiBF,eAAO,MAAM,gCAAgC,UAAsD,CAAC;AAEpG,6FAA6F;AAC7F,eAAO,MAAM,sBAAsB,yBAA0B,CAAC;AAE9D,6EAA6E;AAC7E,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAQhF;AAED,yFAAyF;AACzF,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAE3E;AAED,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,EAAE,eAAe,EAA2B,CAAC","sourcesContent":["/**\n * Built-in extensions for lunR.\n *\n * Light factories stay on the first-paint graph. Heavy factories are imported\n * only when attachDeferredBuiltinExtensions() runs after the TUI is up, or\n * immediately for print/RPC/gateway where there is no first-paint window.\n */\n\nimport type { ExtensionFactory, InlineExtension } from \"../core/extensions/types.ts\";\n\nimport simplePiMemory from \"./simple-pi-memory.ts\";\nimport piTps from \"./pi-tps.ts\";\nimport ashxjTui from \"./ashxj-tui.ts\";\nimport ashxjSpinners from \"./ashxj-spinners.ts\";\nimport ashxjThinking from \"./ashxj-thinking.ts\";\nimport lunrLocalProviders from \"./lunr-local-providers/index.ts\";\nimport lunrTodos from \"./lunr-todos.ts\";\nimport lunrPlanTools from \"./lunr-plan-tools.ts\";\nimport lunrSkillCreator from \"./lunr-skill-creator/index.ts\";\n\n/**\n * Wrap a raw factory function as a named InlineExtension.\n * The cast bridges the gap between the source-level ExtensionFactory type\n * (used here) and the dist-level type that extensions import via the package\n * name. The underlying function signatures are structurally identical.\n */\nfunction ext(name: string, factory: unknown): InlineExtension {\n\treturn { name, factory: factory as ExtensionFactory };\n}\n\n/** UI, local providers, and small lunR-native factories. Safe to import at CLI start. */\nexport const lightBuiltinExtensions: InlineExtension[] = [\n\text(\"simple-pi-memory\", simplePiMemory),\n\text(\"pi-tps\", piTps),\n\text(\"ashxj-tui\", ashxjTui),\n\text(\"ashxj-spinners\", ashxjSpinners),\n\text(\"ashxj-thinking\", ashxjThinking),\n\text(\"lunr-local-providers\", lunrLocalProviders),\n\text(\"lunr-todos\", lunrTodos),\n\text(\"lunr-plan-tools\", lunrPlanTools),\n\text(\"lunr-skill-creator\", lunrSkillCreator),\n];\n\nconst DEFERRED_BUILTIN_LOADERS: Array<{\n\tname: string;\n\tload: () => Promise<{ default: unknown }>;\n}> = [\n\t{ name: \"pi-ollama-cloud\", load: () => import(\"./pi-ollama-cloud/index.ts\") },\n\t{ name: \"narumiruna-pi-goal\", load: () => import(\"./narumiruna-pi-goal/src/goal.ts\") },\n\t{ name: \"lunr-cron\", load: () => import(\"./lunr-cron.ts\") },\n\t{ name: \"pi-intercom\", load: () => import(\"./pi-intercom/index.ts\") },\n\t{ name: \"pi-prompt-template-model\", load: () => import(\"./pi-prompt-template-model/index.ts\") },\n\t{ name: \"pi-subagents\", load: () => import(\"./pi-subagents/index.ts\") },\n\t{ name: \"pi-web-access\", load: () => import(\"./pi-web-access/index.ts\") },\n\t{ name: \"pi-lsp-extension\", load: () => import(\"./pi-lsp-extension/src/index.ts\") },\n\t{ name: \"pi-mcp-adapter\", load: () => import(\"./pi-mcp-adapter/index.ts\") },\n];\n\nexport const DEFERRED_BUILTIN_EXTENSION_NAMES = DEFERRED_BUILTIN_LOADERS.map((entry) => entry.name);\n\n/** Flags registered only after deferred builtins attach. Do not fail CLI parse for these. */\nexport const DEFERRED_BUILTIN_FLAGS = [\"mcp-config\"] as const;\n\n/** Import MCP / LSP / web-access / intercom / subagents only when needed. */\nexport async function loadDeferredBuiltinExtensions(): Promise<InlineExtension[]> {\n\tconst loaded = await Promise.all(\n\t\tDEFERRED_BUILTIN_LOADERS.map(async ({ name, load }) => {\n\t\t\tconst module = await load();\n\t\t\treturn ext(name, module.default);\n\t\t}),\n\t);\n\treturn loaded;\n}\n\n/** Full roster. Print / RPC / gateway still need every factory before the first turn. */\nexport async function loadAllBuiltinExtensions(): Promise<InlineExtension[]> {\n\treturn [...lightBuiltinExtensions, ...(await loadDeferredBuiltinExtensions())];\n}\n\n/** Eager full roster. Prefer loadAllBuiltinExtensions() so CLI start stays light. */\nexport const builtinExtensions: InlineExtension[] = lightBuiltinExtensions;\n"]}
@@ -13,7 +13,6 @@ import ashxjThinking from "./ashxj-thinking.js";
13
13
  import lunrLocalProviders from "./lunr-local-providers/index.js";
14
14
  import lunrTodos from "./lunr-todos.js";
15
15
  import lunrPlanTools from "./lunr-plan-tools.js";
16
- import lunrBehavior from "./lunr-behavior.js";
17
16
  import lunrSkillCreator from "./lunr-skill-creator/index.js";
18
17
  /**
19
18
  * Wrap a raw factory function as a named InlineExtension.
@@ -34,7 +33,6 @@ export const lightBuiltinExtensions = [
34
33
  ext("lunr-local-providers", lunrLocalProviders),
35
34
  ext("lunr-todos", lunrTodos),
36
35
  ext("lunr-plan-tools", lunrPlanTools),
37
- ext("lunr-behavior", lunrBehavior),
38
36
  ext("lunr-skill-creator", lunrSkillCreator),
39
37
  ];
40
38
  const DEFERRED_BUILTIN_LOADERS = [
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/builtin-extensions/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Built-in extensions for lunR.\n *\n * Light factories stay on the first-paint graph. Heavy factories are imported\n * only when attachDeferredBuiltinExtensions() runs after the TUI is up, or\n * immediately for print/RPC/gateway where there is no first-paint window.\n */\n\nimport type { ExtensionFactory, InlineExtension } from \"../core/extensions/types.ts\";\n\nimport simplePiMemory from \"./simple-pi-memory.ts\";\nimport piTps from \"./pi-tps.ts\";\nimport ashxjTui from \"./ashxj-tui.ts\";\nimport ashxjSpinners from \"./ashxj-spinners.ts\";\nimport ashxjThinking from \"./ashxj-thinking.ts\";\nimport lunrLocalProviders from \"./lunr-local-providers/index.ts\";\nimport lunrTodos from \"./lunr-todos.ts\";\nimport lunrPlanTools from \"./lunr-plan-tools.ts\";\nimport lunrBehavior from \"./lunr-behavior.ts\";\nimport lunrSkillCreator from \"./lunr-skill-creator/index.ts\";\n\n/**\n * Wrap a raw factory function as a named InlineExtension.\n * The cast bridges the gap between the source-level ExtensionFactory type\n * (used here) and the dist-level type that extensions import via the package\n * name. The underlying function signatures are structurally identical.\n */\nfunction ext(name: string, factory: unknown): InlineExtension {\n\treturn { name, factory: factory as ExtensionFactory };\n}\n\n/** UI, local providers, and small lunR-native factories. Safe to import at CLI start. */\nexport const lightBuiltinExtensions: InlineExtension[] = [\n\text(\"simple-pi-memory\", simplePiMemory),\n\text(\"pi-tps\", piTps),\n\text(\"ashxj-tui\", ashxjTui),\n\text(\"ashxj-spinners\", ashxjSpinners),\n\text(\"ashxj-thinking\", ashxjThinking),\n\text(\"lunr-local-providers\", lunrLocalProviders),\n\text(\"lunr-todos\", lunrTodos),\n\text(\"lunr-plan-tools\", lunrPlanTools),\n\text(\"lunr-behavior\", lunrBehavior),\n\text(\"lunr-skill-creator\", lunrSkillCreator),\n];\n\nconst DEFERRED_BUILTIN_LOADERS: Array<{\n\tname: string;\n\tload: () => Promise<{ default: unknown }>;\n}> = [\n\t{ name: \"pi-ollama-cloud\", load: () => import(\"./pi-ollama-cloud/index.ts\") },\n\t{ name: \"narumiruna-pi-goal\", load: () => import(\"./narumiruna-pi-goal/src/goal.ts\") },\n\t{ name: \"lunr-cron\", load: () => import(\"./lunr-cron.ts\") },\n\t{ name: \"pi-intercom\", load: () => import(\"./pi-intercom/index.ts\") },\n\t{ name: \"pi-prompt-template-model\", load: () => import(\"./pi-prompt-template-model/index.ts\") },\n\t{ name: \"pi-subagents\", load: () => import(\"./pi-subagents/index.ts\") },\n\t{ name: \"pi-web-access\", load: () => import(\"./pi-web-access/index.ts\") },\n\t{ name: \"pi-lsp-extension\", load: () => import(\"./pi-lsp-extension/src/index.ts\") },\n\t{ name: \"pi-mcp-adapter\", load: () => import(\"./pi-mcp-adapter/index.ts\") },\n];\n\nexport const DEFERRED_BUILTIN_EXTENSION_NAMES = DEFERRED_BUILTIN_LOADERS.map((entry) => entry.name);\n\n/** Flags registered only after deferred builtins attach. Do not fail CLI parse for these. */\nexport const DEFERRED_BUILTIN_FLAGS = [\"mcp-config\"] as const;\n\n/** Import MCP / LSP / web-access / intercom / subagents only when needed. */\nexport async function loadDeferredBuiltinExtensions(): Promise<InlineExtension[]> {\n\tconst loaded = await Promise.all(\n\t\tDEFERRED_BUILTIN_LOADERS.map(async ({ name, load }) => {\n\t\t\tconst module = await load();\n\t\t\treturn ext(name, module.default);\n\t\t}),\n\t);\n\treturn loaded;\n}\n\n/** Full roster. Print / RPC / gateway still need every factory before the first turn. */\nexport async function loadAllBuiltinExtensions(): Promise<InlineExtension[]> {\n\treturn [...lightBuiltinExtensions, ...(await loadDeferredBuiltinExtensions())];\n}\n\n/** Eager full roster. Prefer loadAllBuiltinExtensions() so CLI start stays light. */\nexport const builtinExtensions: InlineExtension[] = lightBuiltinExtensions;\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/builtin-extensions/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Built-in extensions for lunR.\n *\n * Light factories stay on the first-paint graph. Heavy factories are imported\n * only when attachDeferredBuiltinExtensions() runs after the TUI is up, or\n * immediately for print/RPC/gateway where there is no first-paint window.\n */\n\nimport type { ExtensionFactory, InlineExtension } from \"../core/extensions/types.ts\";\n\nimport simplePiMemory from \"./simple-pi-memory.ts\";\nimport piTps from \"./pi-tps.ts\";\nimport ashxjTui from \"./ashxj-tui.ts\";\nimport ashxjSpinners from \"./ashxj-spinners.ts\";\nimport ashxjThinking from \"./ashxj-thinking.ts\";\nimport lunrLocalProviders from \"./lunr-local-providers/index.ts\";\nimport lunrTodos from \"./lunr-todos.ts\";\nimport lunrPlanTools from \"./lunr-plan-tools.ts\";\nimport lunrSkillCreator from \"./lunr-skill-creator/index.ts\";\n\n/**\n * Wrap a raw factory function as a named InlineExtension.\n * The cast bridges the gap between the source-level ExtensionFactory type\n * (used here) and the dist-level type that extensions import via the package\n * name. The underlying function signatures are structurally identical.\n */\nfunction ext(name: string, factory: unknown): InlineExtension {\n\treturn { name, factory: factory as ExtensionFactory };\n}\n\n/** UI, local providers, and small lunR-native factories. Safe to import at CLI start. */\nexport const lightBuiltinExtensions: InlineExtension[] = [\n\text(\"simple-pi-memory\", simplePiMemory),\n\text(\"pi-tps\", piTps),\n\text(\"ashxj-tui\", ashxjTui),\n\text(\"ashxj-spinners\", ashxjSpinners),\n\text(\"ashxj-thinking\", ashxjThinking),\n\text(\"lunr-local-providers\", lunrLocalProviders),\n\text(\"lunr-todos\", lunrTodos),\n\text(\"lunr-plan-tools\", lunrPlanTools),\n\text(\"lunr-skill-creator\", lunrSkillCreator),\n];\n\nconst DEFERRED_BUILTIN_LOADERS: Array<{\n\tname: string;\n\tload: () => Promise<{ default: unknown }>;\n}> = [\n\t{ name: \"pi-ollama-cloud\", load: () => import(\"./pi-ollama-cloud/index.ts\") },\n\t{ name: \"narumiruna-pi-goal\", load: () => import(\"./narumiruna-pi-goal/src/goal.ts\") },\n\t{ name: \"lunr-cron\", load: () => import(\"./lunr-cron.ts\") },\n\t{ name: \"pi-intercom\", load: () => import(\"./pi-intercom/index.ts\") },\n\t{ name: \"pi-prompt-template-model\", load: () => import(\"./pi-prompt-template-model/index.ts\") },\n\t{ name: \"pi-subagents\", load: () => import(\"./pi-subagents/index.ts\") },\n\t{ name: \"pi-web-access\", load: () => import(\"./pi-web-access/index.ts\") },\n\t{ name: \"pi-lsp-extension\", load: () => import(\"./pi-lsp-extension/src/index.ts\") },\n\t{ name: \"pi-mcp-adapter\", load: () => import(\"./pi-mcp-adapter/index.ts\") },\n];\n\nexport const DEFERRED_BUILTIN_EXTENSION_NAMES = DEFERRED_BUILTIN_LOADERS.map((entry) => entry.name);\n\n/** Flags registered only after deferred builtins attach. Do not fail CLI parse for these. */\nexport const DEFERRED_BUILTIN_FLAGS = [\"mcp-config\"] as const;\n\n/** Import MCP / LSP / web-access / intercom / subagents only when needed. */\nexport async function loadDeferredBuiltinExtensions(): Promise<InlineExtension[]> {\n\tconst loaded = await Promise.all(\n\t\tDEFERRED_BUILTIN_LOADERS.map(async ({ name, load }) => {\n\t\t\tconst module = await load();\n\t\t\treturn ext(name, module.default);\n\t\t}),\n\t);\n\treturn loaded;\n}\n\n/** Full roster. Print / RPC / gateway still need every factory before the first turn. */\nexport async function loadAllBuiltinExtensions(): Promise<InlineExtension[]> {\n\treturn [...lightBuiltinExtensions, ...(await loadDeferredBuiltinExtensions())];\n}\n\n/** Eager full roster. Prefer loadAllBuiltinExtensions() so CLI start stays light. */\nexport const builtinExtensions: InlineExtension[] = lightBuiltinExtensions;\n"]}
@@ -18,7 +18,7 @@
18
18
  * (registered here as the local notify; the Phase 4 gateway replaces
19
19
  * it — core/cron/scheduler.ts never touches the bridge itself).
20
20
  *
21
- * `// @ts-nocheck` matches the builtin-extension convention (see lunr-behavior).
21
+ * `// @ts-nocheck` matches the builtin-extension convention.
22
22
  * Runtime imports stay on concrete core modules — never the package barrel.
23
23
  */
24
24
  import type { ExtensionAPI } from "@ashx-j/lunr";
@@ -1 +1 @@
1
- {"version":3,"file":"lunr-cron.d.ts","sourceRoot":"","sources":["../../src/builtin-extensions/lunr-cron.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,iCAAiC,CAAC;AAyFtF,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,GAAG,IAAI,CA6P/C","sourcesContent":["// @ts-nocheck\n/**\n * lunr-cron — lunR-native scheduled jobs (Phase 1: local TUI delivery;\n * Phase 4: gateway delivery + origin stamping).\n *\n * lunR: this file is lunR-native (not an absorbed upstream extension). It wires\n * core/cron (jobs store + scheduler) into the interactive session:\n *\n * - `/cron list|create|pause|resume|run|remove|status` command.\n * - One `cron` tool (TypeBox) so the agent can manage jobs. The shared\n * core/cron/fire-guard depth counter refuses the tool while a cron-fired\n * turn is in flight — TUI-fired OR gateway-fired (jobs cannot schedule\n * jobs).\n * - Jobs created inside a gateway chat turn are stamped with that chat as\n * their origin and default deliver to \"origin\" (core/cron/origin-context).\n * - Scheduler starts on session_start only in \"tui\" mode, stops on\n * session_shutdown. runJob = sendUserMessage + wait for agent_end;\n * deliverResult reads the `@lunr/cron-delivery` bridge on globalThis\n * (registered here as the local notify; the Phase 4 gateway replaces\n * it — core/cron/scheduler.ts never touches the bridge itself).\n *\n * `// @ts-nocheck` matches the builtin-extension convention (see lunr-behavior).\n * Runtime imports stay on concrete core modules — never the package barrel.\n */\n\nimport type { ExtensionAPI, ExtensionContext } from \"@ashx-j/lunr\";\nimport { Type } from \"@sinclair/typebox\";\nimport { beginCronFire, endCronFire, isCronFire } from \"../core/cron/fire-guard.ts\";\nimport {\n\tcreateJob,\n\tgetJob,\n\tlistJobs,\n\tparseSchedule,\n\tpauseJob,\n\tremoveJob,\n\tresumeJob,\n\tsetCronDeliverValidator,\n\tupdateJob,\n} from \"../core/cron/jobs.ts\";\nimport { currentOrigin } from \"../core/cron/origin-context.ts\";\nimport { executeJob, startScheduler } from \"../core/cron/scheduler.ts\";\nimport { loadGatewayConfig } from \"../gateway/config.ts\";\nimport { createDeliverValidator } from \"../gateway/cron.ts\";\n\n// ---------------------------------------------------------------------------\n// Module state\n// ---------------------------------------------------------------------------\n/** The cron-fired turn currently waiting for agent_end. */\nlet pendingRun: { resolve: (text: string) => void; reject: (err: Error) => void } | null = null;\nlet scheduler: { stop(): void } | null = null;\nlet lastCtx: ExtensionContext | null = null;\n\nconst DELIVERY_BRIDGE_SYMBOL = Symbol.for(\"@lunr/cron-delivery\");\n\n// ---------------------------------------------------------------------------\n// Turn plumbing\n// ---------------------------------------------------------------------------\n\n/** Final assistant text from an agent_end messages array (last assistant message, text blocks only). */\nfunction extractAssistantText(messages: unknown[]): string {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst msg = messages[i] as any;\n\t\tif (msg?.role !== \"assistant\") continue;\n\t\tconst parts = Array.isArray(msg.content) ? msg.content : [];\n\t\tconst text = parts\n\t\t\t.filter((p: any) => p?.type === \"text\")\n\t\t\t.map((p: any) => String(p.text ?? \"\"))\n\t\t\t.join(\"\")\n\t\t\t.trim();\n\t\tif (text) return text;\n\t}\n\treturn \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Formatting helpers\n// ---------------------------------------------------------------------------\n\nfunction fmtTime(iso: string | null): string {\n\tif (!iso) return \"-\";\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return \"-\";\n\tconst p = (n: number) => String(n).padStart(2, \"0\");\n\t// Stored timestamps are UTC ISO; render in local time so users read wall-clock.\n\treturn `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;\n}\n\nfunction formatJobList(): string {\n\tconst jobs = listJobs();\n\tif (jobs.length === 0) return \"No cron jobs. Create one with /cron create <schedule> <prompt>.\";\n\tconst lines = jobs.map(\n\t\t(j) =>\n\t\t\t`${j.id} ${j.state}${j.enabled ? \"\" : \" (disabled)\"} ${j.scheduleDisplay} next=${fmtTime(j.nextRunAt)} last=${j.lastStatus ?? \"-\"}${j.lastError ? ` (${j.lastError})` : \"\"} ${j.name}`,\n\t);\n\treturn `Cron jobs (${jobs.length}):\\n${lines.join(\"\\n\")}`;\n}\n\nfunction formatStatus(): string {\n\tconst jobs = listJobs();\n\tconst count = (s: string) => jobs.filter((j) => j.state === s).length;\n\tconst next = jobs\n\t\t.filter((j) => j.enabled && j.state === \"scheduled\" && j.nextRunAt)\n\t\t.sort((a, b) => String(a.nextRunAt).localeCompare(String(b.nextRunAt)))[0];\n\treturn (\n\t\t`Cron: scheduler ${scheduler ? \"running\" : \"stopped\"}; ${jobs.length} job(s) — ` +\n\t\t`${count(\"scheduled\")} scheduled, ${count(\"paused\")} paused, ${count(\"completed\")} completed, ${count(\"error\")} error.` +\n\t\t(next ? ` Next: '${next.name}' at ${fmtTime(next.nextRunAt)}.` : \"\")\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Extension\n// ---------------------------------------------------------------------------\n\nexport default function (pi: ExtensionAPI): void {\n\t// Same allowlist the gateway uses, so a TUI session cannot persist a job\n\t// that later posts to a chat the bot can reach but is not allowed.\n\tsetCronDeliverValidator(createDeliverValidator(loadGatewayConfig()));\n\n\t// --- Local delivery bridge (Phase 4 gateway replaces this) ---\n\t(globalThis as Record<symbol, unknown>)[DELIVERY_BRIDGE_SYMBOL] = async (job: { name: string }, _content: string) => {\n\t\ttry {\n\t\t\tlastCtx?.ui.notify(`Cron job '${job.name}' finished`, \"info\");\n\t\t\treturn null;\n\t\t} catch (err) {\n\t\t\treturn String((err as Error)?.message ?? err);\n\t\t}\n\t};\n\n\t// --- Scheduler deps (TUI) ---\n\tconst runJob = (prompt: string, _job: unknown): Promise<string> => {\n\t\tif (pendingRun) return Promise.reject(new Error(\"another cron job turn is already in flight\"));\n\t\treturn new Promise<string>((resolve, reject) => {\n\t\t\tbeginCronFire();\n\t\t\tpendingRun = { resolve, reject };\n\t\t\ttry {\n\t\t\t\tpi.sendUserMessage(prompt);\n\t\t\t} catch (err) {\n\t\t\t\tpendingRun = null;\n\t\t\t\tendCronFire();\n\t\t\t\treject(err as Error);\n\t\t\t}\n\t\t});\n\t};\n\n\tconst deliverResult = async (job: any, content: string): Promise<void> => {\n\t\tconst bridge = (globalThis as Record<symbol, unknown>)[DELIVERY_BRIDGE_SYMBOL] as\n\t\t\t| ((job: unknown, content: string) => Promise<string | null>)\n\t\t\t| undefined;\n\t\tif (!bridge) throw new Error(\"no cron delivery bridge registered\");\n\t\tconst err = await bridge(job, content);\n\t\tif (err) throw new Error(String(err));\n\t};\n\n\tconst schedulerDeps = { runJob, deliverResult };\n\n\t/** Manual trigger: run inline when idle, otherwise make the job due for the next tick. */\n\tconst triggerRun = async (job: any, ctx: ExtensionContext): Promise<string> => {\n\t\tif (ctx.isIdle()) {\n\t\t\ttry {\n\t\t\t\tawait executeJob(getJob(job.id), schedulerDeps);\n\t\t\t\treturn `Cron job '${job.name}' (${job.id}) finished.`;\n\t\t\t} catch (err) {\n\t\t\t\treturn `Cron job '${job.name}' (${job.id}) failed: ${String((err as Error)?.message ?? err)}`;\n\t\t\t}\n\t\t}\n\t\tawait updateJob(job.id, { nextRunAt: new Date().toISOString() });\n\t\treturn `Cron job '${job.name}' (${job.id}) queued for the next scheduler tick.`;\n\t};\n\n\t// --- Resolve the cron-fired turn when the agent turn ends ---\n\tpi.on(\"agent_end\", (event) => {\n\t\tif (!pendingRun) return;\n\t\tconst pending = pendingRun;\n\t\tpendingRun = null;\n\t\tendCronFire();\n\t\tpending.resolve(extractAssistantText(event.messages ?? []));\n\t});\n\n\t// --- Scheduler lifecycle: TUI sessions only ---\n\tpi.on(\"session_start\", (_event, ctx) => {\n\t\tlastCtx = ctx;\n\t\tif (ctx.mode !== \"tui\") return;\n\t\tscheduler?.stop();\n\t\tscheduler = startScheduler(schedulerDeps);\n\t});\n\n\tpi.on(\"session_shutdown\", () => {\n\t\tscheduler?.stop();\n\t\tscheduler = null;\n\t});\n\n\t// --- /cron command ---\n\tpi.registerCommand(\"cron\", {\n\t\tdescription: \"Manage cron jobs: /cron list | create <schedule> <prompt> | pause|resume|run|remove <id-or-name> | status\",\n\t\tgetArgumentCompletions: (prefix: string) => {\n\t\t\tconst subs = [\"list\", \"create\", \"pause\", \"resume\", \"run\", \"remove\", \"status\"];\n\t\t\tconst lower = prefix.toLowerCase();\n\t\t\treturn subs\n\t\t\t\t.filter((s) => s.startsWith(lower))\n\t\t\t\t.map((s) => ({ value: s, label: s, description: `/cron ${s}` }));\n\t\t},\n\t\thandler: async (args, ctx) => {\n\t\t\tlastCtx = ctx;\n\t\t\tconst tokens = args.trim().split(/\\s+/).filter(Boolean);\n\t\t\tconst sub = (tokens.shift() ?? \"list\").toLowerCase();\n\t\t\ttry {\n\t\t\t\tswitch (sub) {\n\t\t\t\t\tcase \"list\": {\n\t\t\t\t\t\tctx.ui.notify(formatJobList(), \"info\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"status\": {\n\t\t\t\t\t\tctx.ui.notify(formatStatus(), \"info\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"create\": {\n\t\t\t\t\t\t// Greedy: the schedule is the shortest leading token run that parses.\n\t\t\t\t\t\tlet used = 0;\n\t\t\t\t\t\tfor (let k = 1; k <= Math.min(6, tokens.length); k++) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tparseSchedule(tokens.slice(0, k).join(\" \"));\n\t\t\t\t\t\t\t\tused = k;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// keep extending\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst prompt = tokens.slice(used).join(\" \").trim();\n\t\t\t\t\t\tif (!used || !prompt) {\n\t\t\t\t\t\t\tctx.ui.notify(\"Usage: /cron create <schedule> <prompt> — e.g. /cron create every 30m check the deploy\", \"error\");\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst job = await createJob({ prompt, schedule: tokens.slice(0, used).join(\" \") });\n\t\t\t\t\t\tctx.ui.notify(`Created cron job '${job.name}' (${job.id}) — ${job.scheduleDisplay}, next run ${fmtTime(job.nextRunAt)}.`, \"info\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"pause\":\n\t\t\t\t\tcase \"resume\":\n\t\t\t\t\tcase \"remove\":\n\t\t\t\t\tcase \"run\": {\n\t\t\t\t\t\tconst idOrName = tokens.join(\" \").trim();\n\t\t\t\t\t\tif (!idOrName) {\n\t\t\t\t\t\t\tctx.ui.notify(`Usage: /cron ${sub} <id-or-name>`, \"error\");\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (sub === \"pause\") {\n\t\t\t\t\t\t\tconst job = await pauseJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(`Paused cron job '${job.name}' (${job.id}).`, \"info\");\n\t\t\t\t\t\t} else if (sub === \"resume\") {\n\t\t\t\t\t\t\tconst job = await resumeJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(`Resumed cron job '${job.name}' (${job.id}) — next run ${fmtTime(job.nextRunAt)}.`, \"info\");\n\t\t\t\t\t\t} else if (sub === \"remove\") {\n\t\t\t\t\t\t\tconst job = await removeJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(`Removed cron job '${job.name}' (${job.id}).`, \"info\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst job = getJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(await triggerRun(job, ctx), \"info\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tctx.ui.notify(\"Usage: /cron list | create <schedule> <prompt> | pause|resume|run|remove <id-or-name> | status\", \"error\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tctx.ui.notify(String((err as Error)?.message ?? err), \"error\");\n\t\t\t}\n\t\t},\n\t});\n\n\t// --- cron tool (agent-facing) ---\n\tpi.registerTool({\n\t\tname: \"cron\",\n\t\tlabel: \"Cron\",\n\t\tdescription: [\n\t\t\t\"Manage scheduled cron jobs that run prompts unattended in this session.\",\n\t\t\t\"Actions: create (needs prompt + schedule), list, update (id + fields), pause, resume, remove, run (trigger now).\",\n\t\t\t\"Schedule formats: 'every 30m' / 'every 2h' / 'every 1d' (recurring), '30m'/'2h' or an ISO timestamp (one-shot), or a 5-field cron expression.\",\n\t\t\t\"Job output is delivered automatically; the job's prompt can answer [SILENT] to suppress delivery.\",\n\t\t].join(\"\\n\"),\n\t\tparameters: Type.Object({\n\t\t\taction: Type.Union([\n\t\t\t\tType.Literal(\"create\"),\n\t\t\t\tType.Literal(\"list\"),\n\t\t\t\tType.Literal(\"update\"),\n\t\t\t\tType.Literal(\"pause\"),\n\t\t\t\tType.Literal(\"resume\"),\n\t\t\t\tType.Literal(\"remove\"),\n\t\t\t\tType.Literal(\"run\"),\n\t\t\t]),\n\t\t\tid: Type.Optional(Type.String({ description: \"Job id or unique name (all actions except create/list).\" })),\n\t\t\tname: Type.Optional(Type.String({ description: \"Display name (<=50 chars); derived from the prompt when omitted.\" })),\n\t\t\tprompt: Type.Optional(Type.String({ description: \"The prompt the job runs (create/update).\" })),\n\t\t\tschedule: Type.Optional(Type.String({ description: \"Schedule input (create/update).\" })),\n\t\t\tdeliver: Type.Optional(\n\t\t\t\tType.String({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Delivery target(s), comma-separated: 'local' (output file only), 'origin' (the chat that created the job), 'telegram'/'discord' (platform home channel), or 'telegram:<chatId>[:<threadId>]' / 'discord:<chatId>[:<threadId>]'. Defaults to 'origin' when created from a gateway chat, else 'local'.\",\n\t\t\t\t}),\n\t\t\t),\n\t\t}),\n\t\tasync execute(_toolCallId, params, _signal, _onUpdate, ctx) {\n\t\t\tconst text = (t: string) => ({ content: [{ type: \"text\" as const, text: t }] });\n\t\t\tif (isCronFire()) {\n\t\t\t\treturn text(\"cron: unavailable while a cron-fired turn is running (cron jobs cannot schedule cron jobs).\");\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tswitch (params.action) {\n\t\t\t\t\tcase \"create\": {\n\t\t\t\t\t\tif (!params.prompt?.trim() || !params.schedule?.trim()) {\n\t\t\t\t\t\t\treturn text(\"cron create: prompt and schedule are required.\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Inside a gateway chat turn, stamp the chat as the delivery\n\t\t\t\t\t\t// origin and default deliver to \"origin\" (Phase 4); outside\n\t\t\t\t\t\t// any origin context the default stays \"local\".\n\t\t\t\t\t\tconst origin = currentOrigin();\n\t\t\t\t\t\tconst job = await createJob({\n\t\t\t\t\t\t\tprompt: params.prompt,\n\t\t\t\t\t\t\tschedule: params.schedule,\n\t\t\t\t\t\t\tname: params.name,\n\t\t\t\t\t\t\tdeliver: params.deliver ?? (origin ? \"origin\" : undefined),\n\t\t\t\t\t\t\torigin: origin ? { ...origin } : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn text(`Created cron job '${job.name}' (${job.id}) — ${job.scheduleDisplay}, next run ${fmtTime(job.nextRunAt)}.`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"list\": {\n\t\t\t\t\t\treturn text(formatJobList());\n\t\t\t\t\t}\n\t\t\t\t\tcase \"update\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron update: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await updateJob(params.id, {\n\t\t\t\t\t\t\tname: params.name,\n\t\t\t\t\t\t\tprompt: params.prompt,\n\t\t\t\t\t\t\tschedule: params.schedule,\n\t\t\t\t\t\t\tdeliver: params.deliver,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn text(`Updated cron job '${job.name}' (${job.id}) — ${job.scheduleDisplay}, next run ${fmtTime(job.nextRunAt)}.`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"pause\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron pause: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await pauseJob(params.id);\n\t\t\t\t\t\treturn text(`Paused cron job '${job.name}' (${job.id}).`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"resume\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron resume: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await resumeJob(params.id);\n\t\t\t\t\t\treturn text(`Resumed cron job '${job.name}' (${job.id}) — next run ${fmtTime(job.nextRunAt)}.`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"remove\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron remove: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await removeJob(params.id);\n\t\t\t\t\t\treturn text(`Removed cron job '${job.name}' (${job.id}).`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"run\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron run: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = getJob(params.id);\n\t\t\t\t\t\treturn text(await triggerRun(job, ctx));\n\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn text(`cron: unknown action \"${String(params.action)}\".`);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\treturn text(`cron: ${String((err as Error)?.message ?? err)}`);\n\t\t\t}\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"lunr-cron.d.ts","sourceRoot":"","sources":["../../src/builtin-extensions/lunr-cron.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,iCAAiC,CAAC;AAyFtF,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,GAAG,IAAI,CA6P/C","sourcesContent":["// @ts-nocheck\n/**\n * lunr-cron — lunR-native scheduled jobs (Phase 1: local TUI delivery;\n * Phase 4: gateway delivery + origin stamping).\n *\n * lunR: this file is lunR-native (not an absorbed upstream extension). It wires\n * core/cron (jobs store + scheduler) into the interactive session:\n *\n * - `/cron list|create|pause|resume|run|remove|status` command.\n * - One `cron` tool (TypeBox) so the agent can manage jobs. The shared\n * core/cron/fire-guard depth counter refuses the tool while a cron-fired\n * turn is in flight — TUI-fired OR gateway-fired (jobs cannot schedule\n * jobs).\n * - Jobs created inside a gateway chat turn are stamped with that chat as\n * their origin and default deliver to \"origin\" (core/cron/origin-context).\n * - Scheduler starts on session_start only in \"tui\" mode, stops on\n * session_shutdown. runJob = sendUserMessage + wait for agent_end;\n * deliverResult reads the `@lunr/cron-delivery` bridge on globalThis\n * (registered here as the local notify; the Phase 4 gateway replaces\n * it — core/cron/scheduler.ts never touches the bridge itself).\n *\n * `// @ts-nocheck` matches the builtin-extension convention.\n * Runtime imports stay on concrete core modules — never the package barrel.\n */\n\nimport type { ExtensionAPI, ExtensionContext } from \"@ashx-j/lunr\";\nimport { Type } from \"@sinclair/typebox\";\nimport { beginCronFire, endCronFire, isCronFire } from \"../core/cron/fire-guard.ts\";\nimport {\n\tcreateJob,\n\tgetJob,\n\tlistJobs,\n\tparseSchedule,\n\tpauseJob,\n\tremoveJob,\n\tresumeJob,\n\tsetCronDeliverValidator,\n\tupdateJob,\n} from \"../core/cron/jobs.ts\";\nimport { currentOrigin } from \"../core/cron/origin-context.ts\";\nimport { executeJob, startScheduler } from \"../core/cron/scheduler.ts\";\nimport { loadGatewayConfig } from \"../gateway/config.ts\";\nimport { createDeliverValidator } from \"../gateway/cron.ts\";\n\n// ---------------------------------------------------------------------------\n// Module state\n// ---------------------------------------------------------------------------\n/** The cron-fired turn currently waiting for agent_end. */\nlet pendingRun: { resolve: (text: string) => void; reject: (err: Error) => void } | null = null;\nlet scheduler: { stop(): void } | null = null;\nlet lastCtx: ExtensionContext | null = null;\n\nconst DELIVERY_BRIDGE_SYMBOL = Symbol.for(\"@lunr/cron-delivery\");\n\n// ---------------------------------------------------------------------------\n// Turn plumbing\n// ---------------------------------------------------------------------------\n\n/** Final assistant text from an agent_end messages array (last assistant message, text blocks only). */\nfunction extractAssistantText(messages: unknown[]): string {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst msg = messages[i] as any;\n\t\tif (msg?.role !== \"assistant\") continue;\n\t\tconst parts = Array.isArray(msg.content) ? msg.content : [];\n\t\tconst text = parts\n\t\t\t.filter((p: any) => p?.type === \"text\")\n\t\t\t.map((p: any) => String(p.text ?? \"\"))\n\t\t\t.join(\"\")\n\t\t\t.trim();\n\t\tif (text) return text;\n\t}\n\treturn \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Formatting helpers\n// ---------------------------------------------------------------------------\n\nfunction fmtTime(iso: string | null): string {\n\tif (!iso) return \"-\";\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return \"-\";\n\tconst p = (n: number) => String(n).padStart(2, \"0\");\n\t// Stored timestamps are UTC ISO; render in local time so users read wall-clock.\n\treturn `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;\n}\n\nfunction formatJobList(): string {\n\tconst jobs = listJobs();\n\tif (jobs.length === 0) return \"No cron jobs. Create one with /cron create <schedule> <prompt>.\";\n\tconst lines = jobs.map(\n\t\t(j) =>\n\t\t\t`${j.id} ${j.state}${j.enabled ? \"\" : \" (disabled)\"} ${j.scheduleDisplay} next=${fmtTime(j.nextRunAt)} last=${j.lastStatus ?? \"-\"}${j.lastError ? ` (${j.lastError})` : \"\"} ${j.name}`,\n\t);\n\treturn `Cron jobs (${jobs.length}):\\n${lines.join(\"\\n\")}`;\n}\n\nfunction formatStatus(): string {\n\tconst jobs = listJobs();\n\tconst count = (s: string) => jobs.filter((j) => j.state === s).length;\n\tconst next = jobs\n\t\t.filter((j) => j.enabled && j.state === \"scheduled\" && j.nextRunAt)\n\t\t.sort((a, b) => String(a.nextRunAt).localeCompare(String(b.nextRunAt)))[0];\n\treturn (\n\t\t`Cron: scheduler ${scheduler ? \"running\" : \"stopped\"}; ${jobs.length} job(s) — ` +\n\t\t`${count(\"scheduled\")} scheduled, ${count(\"paused\")} paused, ${count(\"completed\")} completed, ${count(\"error\")} error.` +\n\t\t(next ? ` Next: '${next.name}' at ${fmtTime(next.nextRunAt)}.` : \"\")\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Extension\n// ---------------------------------------------------------------------------\n\nexport default function (pi: ExtensionAPI): void {\n\t// Same allowlist the gateway uses, so a TUI session cannot persist a job\n\t// that later posts to a chat the bot can reach but is not allowed.\n\tsetCronDeliverValidator(createDeliverValidator(loadGatewayConfig()));\n\n\t// --- Local delivery bridge (Phase 4 gateway replaces this) ---\n\t(globalThis as Record<symbol, unknown>)[DELIVERY_BRIDGE_SYMBOL] = async (job: { name: string }, _content: string) => {\n\t\ttry {\n\t\t\tlastCtx?.ui.notify(`Cron job '${job.name}' finished`, \"info\");\n\t\t\treturn null;\n\t\t} catch (err) {\n\t\t\treturn String((err as Error)?.message ?? err);\n\t\t}\n\t};\n\n\t// --- Scheduler deps (TUI) ---\n\tconst runJob = (prompt: string, _job: unknown): Promise<string> => {\n\t\tif (pendingRun) return Promise.reject(new Error(\"another cron job turn is already in flight\"));\n\t\treturn new Promise<string>((resolve, reject) => {\n\t\t\tbeginCronFire();\n\t\t\tpendingRun = { resolve, reject };\n\t\t\ttry {\n\t\t\t\tpi.sendUserMessage(prompt);\n\t\t\t} catch (err) {\n\t\t\t\tpendingRun = null;\n\t\t\t\tendCronFire();\n\t\t\t\treject(err as Error);\n\t\t\t}\n\t\t});\n\t};\n\n\tconst deliverResult = async (job: any, content: string): Promise<void> => {\n\t\tconst bridge = (globalThis as Record<symbol, unknown>)[DELIVERY_BRIDGE_SYMBOL] as\n\t\t\t| ((job: unknown, content: string) => Promise<string | null>)\n\t\t\t| undefined;\n\t\tif (!bridge) throw new Error(\"no cron delivery bridge registered\");\n\t\tconst err = await bridge(job, content);\n\t\tif (err) throw new Error(String(err));\n\t};\n\n\tconst schedulerDeps = { runJob, deliverResult };\n\n\t/** Manual trigger: run inline when idle, otherwise make the job due for the next tick. */\n\tconst triggerRun = async (job: any, ctx: ExtensionContext): Promise<string> => {\n\t\tif (ctx.isIdle()) {\n\t\t\ttry {\n\t\t\t\tawait executeJob(getJob(job.id), schedulerDeps);\n\t\t\t\treturn `Cron job '${job.name}' (${job.id}) finished.`;\n\t\t\t} catch (err) {\n\t\t\t\treturn `Cron job '${job.name}' (${job.id}) failed: ${String((err as Error)?.message ?? err)}`;\n\t\t\t}\n\t\t}\n\t\tawait updateJob(job.id, { nextRunAt: new Date().toISOString() });\n\t\treturn `Cron job '${job.name}' (${job.id}) queued for the next scheduler tick.`;\n\t};\n\n\t// --- Resolve the cron-fired turn when the agent turn ends ---\n\tpi.on(\"agent_end\", (event) => {\n\t\tif (!pendingRun) return;\n\t\tconst pending = pendingRun;\n\t\tpendingRun = null;\n\t\tendCronFire();\n\t\tpending.resolve(extractAssistantText(event.messages ?? []));\n\t});\n\n\t// --- Scheduler lifecycle: TUI sessions only ---\n\tpi.on(\"session_start\", (_event, ctx) => {\n\t\tlastCtx = ctx;\n\t\tif (ctx.mode !== \"tui\") return;\n\t\tscheduler?.stop();\n\t\tscheduler = startScheduler(schedulerDeps);\n\t});\n\n\tpi.on(\"session_shutdown\", () => {\n\t\tscheduler?.stop();\n\t\tscheduler = null;\n\t});\n\n\t// --- /cron command ---\n\tpi.registerCommand(\"cron\", {\n\t\tdescription: \"Manage cron jobs: /cron list | create <schedule> <prompt> | pause|resume|run|remove <id-or-name> | status\",\n\t\tgetArgumentCompletions: (prefix: string) => {\n\t\t\tconst subs = [\"list\", \"create\", \"pause\", \"resume\", \"run\", \"remove\", \"status\"];\n\t\t\tconst lower = prefix.toLowerCase();\n\t\t\treturn subs\n\t\t\t\t.filter((s) => s.startsWith(lower))\n\t\t\t\t.map((s) => ({ value: s, label: s, description: `/cron ${s}` }));\n\t\t},\n\t\thandler: async (args, ctx) => {\n\t\t\tlastCtx = ctx;\n\t\t\tconst tokens = args.trim().split(/\\s+/).filter(Boolean);\n\t\t\tconst sub = (tokens.shift() ?? \"list\").toLowerCase();\n\t\t\ttry {\n\t\t\t\tswitch (sub) {\n\t\t\t\t\tcase \"list\": {\n\t\t\t\t\t\tctx.ui.notify(formatJobList(), \"info\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"status\": {\n\t\t\t\t\t\tctx.ui.notify(formatStatus(), \"info\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"create\": {\n\t\t\t\t\t\t// Greedy: the schedule is the shortest leading token run that parses.\n\t\t\t\t\t\tlet used = 0;\n\t\t\t\t\t\tfor (let k = 1; k <= Math.min(6, tokens.length); k++) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tparseSchedule(tokens.slice(0, k).join(\" \"));\n\t\t\t\t\t\t\t\tused = k;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// keep extending\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst prompt = tokens.slice(used).join(\" \").trim();\n\t\t\t\t\t\tif (!used || !prompt) {\n\t\t\t\t\t\t\tctx.ui.notify(\"Usage: /cron create <schedule> <prompt> — e.g. /cron create every 30m check the deploy\", \"error\");\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst job = await createJob({ prompt, schedule: tokens.slice(0, used).join(\" \") });\n\t\t\t\t\t\tctx.ui.notify(`Created cron job '${job.name}' (${job.id}) — ${job.scheduleDisplay}, next run ${fmtTime(job.nextRunAt)}.`, \"info\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"pause\":\n\t\t\t\t\tcase \"resume\":\n\t\t\t\t\tcase \"remove\":\n\t\t\t\t\tcase \"run\": {\n\t\t\t\t\t\tconst idOrName = tokens.join(\" \").trim();\n\t\t\t\t\t\tif (!idOrName) {\n\t\t\t\t\t\t\tctx.ui.notify(`Usage: /cron ${sub} <id-or-name>`, \"error\");\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (sub === \"pause\") {\n\t\t\t\t\t\t\tconst job = await pauseJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(`Paused cron job '${job.name}' (${job.id}).`, \"info\");\n\t\t\t\t\t\t} else if (sub === \"resume\") {\n\t\t\t\t\t\t\tconst job = await resumeJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(`Resumed cron job '${job.name}' (${job.id}) — next run ${fmtTime(job.nextRunAt)}.`, \"info\");\n\t\t\t\t\t\t} else if (sub === \"remove\") {\n\t\t\t\t\t\t\tconst job = await removeJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(`Removed cron job '${job.name}' (${job.id}).`, \"info\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst job = getJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(await triggerRun(job, ctx), \"info\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tctx.ui.notify(\"Usage: /cron list | create <schedule> <prompt> | pause|resume|run|remove <id-or-name> | status\", \"error\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tctx.ui.notify(String((err as Error)?.message ?? err), \"error\");\n\t\t\t}\n\t\t},\n\t});\n\n\t// --- cron tool (agent-facing) ---\n\tpi.registerTool({\n\t\tname: \"cron\",\n\t\tlabel: \"Cron\",\n\t\tdescription: [\n\t\t\t\"Manage scheduled cron jobs that run prompts unattended in this session.\",\n\t\t\t\"Actions: create (needs prompt + schedule), list, update (id + fields), pause, resume, remove, run (trigger now).\",\n\t\t\t\"Schedule formats: 'every 30m' / 'every 2h' / 'every 1d' (recurring), '30m'/'2h' or an ISO timestamp (one-shot), or a 5-field cron expression.\",\n\t\t\t\"Job output is delivered automatically; the job's prompt can answer [SILENT] to suppress delivery.\",\n\t\t].join(\"\\n\"),\n\t\tparameters: Type.Object({\n\t\t\taction: Type.Union([\n\t\t\t\tType.Literal(\"create\"),\n\t\t\t\tType.Literal(\"list\"),\n\t\t\t\tType.Literal(\"update\"),\n\t\t\t\tType.Literal(\"pause\"),\n\t\t\t\tType.Literal(\"resume\"),\n\t\t\t\tType.Literal(\"remove\"),\n\t\t\t\tType.Literal(\"run\"),\n\t\t\t]),\n\t\t\tid: Type.Optional(Type.String({ description: \"Job id or unique name (all actions except create/list).\" })),\n\t\t\tname: Type.Optional(Type.String({ description: \"Display name (<=50 chars); derived from the prompt when omitted.\" })),\n\t\t\tprompt: Type.Optional(Type.String({ description: \"The prompt the job runs (create/update).\" })),\n\t\t\tschedule: Type.Optional(Type.String({ description: \"Schedule input (create/update).\" })),\n\t\t\tdeliver: Type.Optional(\n\t\t\t\tType.String({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Delivery target(s), comma-separated: 'local' (output file only), 'origin' (the chat that created the job), 'telegram'/'discord' (platform home channel), or 'telegram:<chatId>[:<threadId>]' / 'discord:<chatId>[:<threadId>]'. Defaults to 'origin' when created from a gateway chat, else 'local'.\",\n\t\t\t\t}),\n\t\t\t),\n\t\t}),\n\t\tasync execute(_toolCallId, params, _signal, _onUpdate, ctx) {\n\t\t\tconst text = (t: string) => ({ content: [{ type: \"text\" as const, text: t }] });\n\t\t\tif (isCronFire()) {\n\t\t\t\treturn text(\"cron: unavailable while a cron-fired turn is running (cron jobs cannot schedule cron jobs).\");\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tswitch (params.action) {\n\t\t\t\t\tcase \"create\": {\n\t\t\t\t\t\tif (!params.prompt?.trim() || !params.schedule?.trim()) {\n\t\t\t\t\t\t\treturn text(\"cron create: prompt and schedule are required.\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Inside a gateway chat turn, stamp the chat as the delivery\n\t\t\t\t\t\t// origin and default deliver to \"origin\" (Phase 4); outside\n\t\t\t\t\t\t// any origin context the default stays \"local\".\n\t\t\t\t\t\tconst origin = currentOrigin();\n\t\t\t\t\t\tconst job = await createJob({\n\t\t\t\t\t\t\tprompt: params.prompt,\n\t\t\t\t\t\t\tschedule: params.schedule,\n\t\t\t\t\t\t\tname: params.name,\n\t\t\t\t\t\t\tdeliver: params.deliver ?? (origin ? \"origin\" : undefined),\n\t\t\t\t\t\t\torigin: origin ? { ...origin } : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn text(`Created cron job '${job.name}' (${job.id}) — ${job.scheduleDisplay}, next run ${fmtTime(job.nextRunAt)}.`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"list\": {\n\t\t\t\t\t\treturn text(formatJobList());\n\t\t\t\t\t}\n\t\t\t\t\tcase \"update\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron update: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await updateJob(params.id, {\n\t\t\t\t\t\t\tname: params.name,\n\t\t\t\t\t\t\tprompt: params.prompt,\n\t\t\t\t\t\t\tschedule: params.schedule,\n\t\t\t\t\t\t\tdeliver: params.deliver,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn text(`Updated cron job '${job.name}' (${job.id}) — ${job.scheduleDisplay}, next run ${fmtTime(job.nextRunAt)}.`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"pause\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron pause: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await pauseJob(params.id);\n\t\t\t\t\t\treturn text(`Paused cron job '${job.name}' (${job.id}).`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"resume\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron resume: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await resumeJob(params.id);\n\t\t\t\t\t\treturn text(`Resumed cron job '${job.name}' (${job.id}) — next run ${fmtTime(job.nextRunAt)}.`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"remove\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron remove: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await removeJob(params.id);\n\t\t\t\t\t\treturn text(`Removed cron job '${job.name}' (${job.id}).`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"run\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron run: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = getJob(params.id);\n\t\t\t\t\t\treturn text(await triggerRun(job, ctx));\n\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn text(`cron: unknown action \"${String(params.action)}\".`);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\treturn text(`cron: ${String((err as Error)?.message ?? err)}`);\n\t\t\t}\n\t\t},\n\t});\n}\n"]}
@@ -19,7 +19,7 @@
19
19
  * (registered here as the local notify; the Phase 4 gateway replaces
20
20
  * it — core/cron/scheduler.ts never touches the bridge itself).
21
21
  *
22
- * `// @ts-nocheck` matches the builtin-extension convention (see lunr-behavior).
22
+ * `// @ts-nocheck` matches the builtin-extension convention.
23
23
  * Runtime imports stay on concrete core modules — never the package barrel.
24
24
  */
25
25
  import { Type } from "@sinclair/typebox";
@@ -1 +1 @@
1
- {"version":3,"file":"lunr-cron.js","sourceRoot":"","sources":["../../src/builtin-extensions/lunr-cron.ts"],"names":[],"mappings":"AAAA,cAAc;AACd;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACpF,OAAO,EACN,SAAS,EACT,MAAM,EACN,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,SAAS,EACT,SAAS,EACT,uBAAuB,EACvB,SAAS,GACT,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAC9E,2DAA2D;AAC3D,IAAI,UAAU,GAA6E,IAAI,CAAC;AAChG,IAAI,SAAS,GAA4B,IAAI,CAAC;AAC9C,IAAI,OAAO,GAA4B,IAAI,CAAC;AAE5C,MAAM,sBAAsB,GAAG,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;AAEjE,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,wGAAwG;AACxG,SAAS,oBAAoB,CAAC,QAAmB,EAAU;IAC1D,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAQ,CAAC;QAC/B,IAAI,GAAG,EAAE,IAAI,KAAK,WAAW;YAAE,SAAS;QACxC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,GAAG,KAAK;aAChB,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,MAAM,CAAC;aACtC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;aACrC,IAAI,CAAC,EAAE,CAAC;aACR,IAAI,EAAE,CAAC;QACT,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;IACvB,CAAC;IACD,OAAO,EAAE,CAAC;AAAA,CACV;AAED,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,SAAS,OAAO,CAAC,GAAkB,EAAU;IAC5C,IAAI,CAAC,GAAG;QAAE,OAAO,GAAG,CAAC;IACrB,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QAAE,OAAO,GAAG,CAAC;IAC1C,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACpD,gFAAgF;IAChF,OAAO,GAAG,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;AAAA,CAC7G;AAED,SAAS,aAAa,GAAW;IAChC,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;IACxB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,iEAAiE,CAAC;IAChG,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACrB,CAAC,CAAC,EAAE,EAAE,CACL,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,eAAe,UAAU,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,UAAU,IAAI,GAAG,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAC5L,CAAC;IACF,OAAO,cAAc,IAAI,CAAC,MAAM,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAAA,CAC1D;AAED,SAAS,YAAY,GAAW;IAC/B,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;IACxB,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IACtE,MAAM,IAAI,GAAG,IAAI;SACf,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,KAAK,WAAW,IAAI,CAAC,CAAC,SAAS,CAAC;SAClE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,OAAO,CACN,mBAAmB,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,MAAM,cAAY;QAChF,GAAG,KAAK,CAAC,WAAW,CAAC,eAAe,KAAK,CAAC,QAAQ,CAAC,YAAY,KAAK,CAAC,WAAW,CAAC,eAAe,KAAK,CAAC,OAAO,CAAC,SAAS;QACvH,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,IAAI,QAAQ,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CACpE,CAAC;AAAA,CACF;AAED,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,MAAM,CAAC,OAAO,WAAW,EAAgB,EAAQ;IAChD,yEAAyE;IACzE,mEAAmE;IACnE,uBAAuB,CAAC,sBAAsB,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC;IAErE,gEAAgE;IAC/D,UAAsC,CAAC,sBAAsB,CAAC,GAAG,KAAK,EAAE,GAAqB,EAAE,QAAgB,EAAE,EAAE,CAAC;QACpH,IAAI,CAAC;YACJ,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,GAAG,CAAC,IAAI,YAAY,EAAE,MAAM,CAAC,CAAC;YAC9D,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,OAAO,MAAM,CAAE,GAAa,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC;QAC/C,CAAC;IAAA,CACD,CAAC;IAEF,+BAA+B;IAC/B,MAAM,MAAM,GAAG,CAAC,MAAc,EAAE,IAAa,EAAmB,EAAE,CAAC;QAClE,IAAI,UAAU;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC,CAAC;QAC/F,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;YAC/C,aAAa,EAAE,CAAC;YAChB,UAAU,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;YACjC,IAAI,CAAC;gBACJ,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,UAAU,GAAG,IAAI,CAAC;gBAClB,WAAW,EAAE,CAAC;gBACd,MAAM,CAAC,GAAY,CAAC,CAAC;YACtB,CAAC;QAAA,CACD,CAAC,CAAC;IAAA,CACH,CAAC;IAEF,MAAM,aAAa,GAAG,KAAK,EAAE,GAAQ,EAAE,OAAe,EAAiB,EAAE,CAAC;QACzE,MAAM,MAAM,GAAI,UAAsC,CAAC,sBAAsB,CAEjE,CAAC;QACb,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACnE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACvC,IAAI,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAAA,CACtC,CAAC;IAEF,MAAM,aAAa,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAEhD,0FAA0F;IAC1F,MAAM,UAAU,GAAG,KAAK,EAAE,GAAQ,EAAE,GAAqB,EAAmB,EAAE,CAAC;QAC9E,IAAI,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;YAClB,IAAI,CAAC;gBACJ,MAAM,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,CAAC;gBAChD,OAAO,aAAa,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,aAAa,CAAC;YACvD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,OAAO,aAAa,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,aAAa,MAAM,CAAE,GAAa,EAAE,OAAO,IAAI,GAAG,CAAC,EAAE,CAAC;YAC/F,CAAC;QACF,CAAC;QACD,MAAM,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACjE,OAAO,aAAa,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,uCAAuC,CAAC;IAAA,CAChF,CAAC;IAEF,+DAA+D;IAC/D,EAAE,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC;QAC7B,IAAI,CAAC,UAAU;YAAE,OAAO;QACxB,MAAM,OAAO,GAAG,UAAU,CAAC;QAC3B,UAAU,GAAG,IAAI,CAAC;QAClB,WAAW,EAAE,CAAC;QACd,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;IAAA,CAC5D,CAAC,CAAC;IAEH,iDAAiD;IACjD,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;QACvC,OAAO,GAAG,GAAG,CAAC;QACd,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK;YAAE,OAAO;QAC/B,SAAS,EAAE,IAAI,EAAE,CAAC;QAClB,SAAS,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;IAAA,CAC1C,CAAC,CAAC;IAEH,EAAE,CAAC,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC;QAC/B,SAAS,EAAE,IAAI,EAAE,CAAC;QAClB,SAAS,GAAG,IAAI,CAAC;IAAA,CACjB,CAAC,CAAC;IAEH,wBAAwB;IACxB,EAAE,CAAC,eAAe,CAAC,MAAM,EAAE;QAC1B,WAAW,EAAE,2GAA2G;QACxH,sBAAsB,EAAE,CAAC,MAAc,EAAE,EAAE,CAAC;YAC3C,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC9E,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;YACnC,OAAO,IAAI;iBACT,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;iBAClC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAAA,CAClE;QACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;YAC7B,OAAO,GAAG,GAAG,CAAC;YACd,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACxD,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;YACrD,IAAI,CAAC;gBACJ,QAAQ,GAAG,EAAE,CAAC;oBACb,KAAK,MAAM,EAAE,CAAC;wBACb,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,MAAM,CAAC,CAAC;wBACvC,OAAO;oBACR,CAAC;oBACD,KAAK,QAAQ,EAAE,CAAC;wBACf,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,MAAM,CAAC,CAAC;wBACtC,OAAO;oBACR,CAAC;oBACD,KAAK,QAAQ,EAAE,CAAC;wBACf,sEAAsE;wBACtE,IAAI,IAAI,GAAG,CAAC,CAAC;wBACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;4BACtD,IAAI,CAAC;gCACJ,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;gCAC5C,IAAI,GAAG,CAAC,CAAC;gCACT,MAAM;4BACP,CAAC;4BAAC,MAAM,CAAC;gCACR,iBAAiB;4BAClB,CAAC;wBACF,CAAC;wBACD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;wBACnD,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;4BACtB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,0FAAwF,EAAE,OAAO,CAAC,CAAC;4BACjH,OAAO;wBACR,CAAC;wBACD,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;wBACnF,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,qBAAqB,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,SAAO,GAAG,CAAC,eAAe,cAAc,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;wBAClI,OAAO;oBACR,CAAC;oBACD,KAAK,OAAO,CAAC;oBACb,KAAK,QAAQ,CAAC;oBACd,KAAK,QAAQ,CAAC;oBACd,KAAK,KAAK,EAAE,CAAC;wBACZ,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;wBACzC,IAAI,CAAC,QAAQ,EAAE,CAAC;4BACf,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,gBAAgB,GAAG,eAAe,EAAE,OAAO,CAAC,CAAC;4BAC3D,OAAO;wBACR,CAAC;wBACD,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;4BACrB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;4BACrC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,oBAAoB,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;wBACrE,CAAC;6BAAM,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;4BAC7B,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;4BACtC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,qBAAqB,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,kBAAgB,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;wBAC3G,CAAC;6BAAM,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;4BAC7B,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;4BACtC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,qBAAqB,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;wBACtE,CAAC;6BAAM,CAAC;4BACP,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;4BAC7B,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;wBACnD,CAAC;wBACD,OAAO;oBACR,CAAC;oBACD,SAAS,CAAC;wBACT,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,gGAAgG,EAAE,OAAO,CAAC,CAAC;oBAC1H,CAAC;gBACF,CAAC;YACF,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAE,GAAa,EAAE,OAAO,IAAI,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;YAChE,CAAC;QAAA,CACD;KACD,CAAC,CAAC;IAEH,mCAAmC;IACnC,EAAE,CAAC,YAAY,CAAC;QACf,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,MAAM;QACb,WAAW,EAAE;YACZ,yEAAyE;YACzE,kHAAkH;YAClH,+IAA+I;YAC/I,mGAAmG;SACnG,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;YACvB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC;gBAClB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACtB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;gBACpB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACtB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;gBACrB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACtB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACtB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;aACnB,CAAC;YACF,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,yDAAyD,EAAE,CAAC,CAAC;YAC1G,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,kEAAkE,EAAE,CAAC,CAAC;YACrH,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,0CAA0C,EAAE,CAAC,CAAC;YAC/F,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,iCAAiC,EAAE,CAAC,CAAC;YACxF,OAAO,EAAE,IAAI,CAAC,QAAQ,CACrB,IAAI,CAAC,MAAM,CAAC;gBACX,WAAW,EACV,sSAAsS;aACvS,CAAC,CACF;SACD,CAAC;QACF,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE;YAC3D,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YAChF,IAAI,UAAU,EAAE,EAAE,CAAC;gBAClB,OAAO,IAAI,CAAC,6FAA6F,CAAC,CAAC;YAC5G,CAAC;YACD,IAAI,CAAC;gBACJ,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;oBACvB,KAAK,QAAQ,EAAE,CAAC;wBACf,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;4BACxD,OAAO,IAAI,CAAC,gDAAgD,CAAC,CAAC;wBAC/D,CAAC;wBACD,6DAA6D;wBAC7D,4DAA4D;wBAC5D,gDAAgD;wBAChD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;wBAC/B,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC;4BAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;4BACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;4BACzB,IAAI,EAAE,MAAM,CAAC,IAAI;4BACjB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;4BAC1D,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS;yBAC1C,CAAC,CAAC;wBACH,OAAO,IAAI,CAAC,qBAAqB,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,SAAO,GAAG,CAAC,eAAe,cAAc,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACzH,CAAC;oBACD,KAAK,MAAM,EAAE,CAAC;wBACb,OAAO,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;oBAC9B,CAAC;oBACD,KAAK,QAAQ,EAAE,CAAC;wBACf,IAAI,CAAC,MAAM,CAAC,EAAE;4BAAE,OAAO,IAAI,CAAC,+CAA+C,CAAC,CAAC;wBAC7E,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,EAAE,EAAE;4BACtC,IAAI,EAAE,MAAM,CAAC,IAAI;4BACjB,MAAM,EAAE,MAAM,CAAC,MAAM;4BACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;4BACzB,OAAO,EAAE,MAAM,CAAC,OAAO;yBACvB,CAAC,CAAC;wBACH,OAAO,IAAI,CAAC,qBAAqB,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,SAAO,GAAG,CAAC,eAAe,cAAc,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACzH,CAAC;oBACD,KAAK,OAAO,EAAE,CAAC;wBACd,IAAI,CAAC,MAAM,CAAC,EAAE;4BAAE,OAAO,IAAI,CAAC,8CAA8C,CAAC,CAAC;wBAC5E,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;wBACtC,OAAO,IAAI,CAAC,oBAAoB,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;oBAC3D,CAAC;oBACD,KAAK,QAAQ,EAAE,CAAC;wBACf,IAAI,CAAC,MAAM,CAAC,EAAE;4BAAE,OAAO,IAAI,CAAC,+CAA+C,CAAC,CAAC;wBAC7E,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;wBACvC,OAAO,IAAI,CAAC,qBAAqB,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,kBAAgB,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACjG,CAAC;oBACD,KAAK,QAAQ,EAAE,CAAC;wBACf,IAAI,CAAC,MAAM,CAAC,EAAE;4BAAE,OAAO,IAAI,CAAC,+CAA+C,CAAC,CAAC;wBAC7E,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;wBACvC,OAAO,IAAI,CAAC,qBAAqB,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;oBAC5D,CAAC;oBACD,KAAK,KAAK,EAAE,CAAC;wBACZ,IAAI,CAAC,MAAM,CAAC,EAAE;4BAAE,OAAO,IAAI,CAAC,4CAA4C,CAAC,CAAC;wBAC1E,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;wBAC9B,OAAO,IAAI,CAAC,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;oBACzC,CAAC;oBACD;wBACC,OAAO,IAAI,CAAC,yBAAyB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAClE,CAAC;YACF,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,OAAO,IAAI,CAAC,SAAS,MAAM,CAAE,GAAa,EAAE,OAAO,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC;YAChE,CAAC;QAAA,CACD;KACD,CAAC,CAAC;AAAA,CACH","sourcesContent":["// @ts-nocheck\n/**\n * lunr-cron — lunR-native scheduled jobs (Phase 1: local TUI delivery;\n * Phase 4: gateway delivery + origin stamping).\n *\n * lunR: this file is lunR-native (not an absorbed upstream extension). It wires\n * core/cron (jobs store + scheduler) into the interactive session:\n *\n * - `/cron list|create|pause|resume|run|remove|status` command.\n * - One `cron` tool (TypeBox) so the agent can manage jobs. The shared\n * core/cron/fire-guard depth counter refuses the tool while a cron-fired\n * turn is in flight — TUI-fired OR gateway-fired (jobs cannot schedule\n * jobs).\n * - Jobs created inside a gateway chat turn are stamped with that chat as\n * their origin and default deliver to \"origin\" (core/cron/origin-context).\n * - Scheduler starts on session_start only in \"tui\" mode, stops on\n * session_shutdown. runJob = sendUserMessage + wait for agent_end;\n * deliverResult reads the `@lunr/cron-delivery` bridge on globalThis\n * (registered here as the local notify; the Phase 4 gateway replaces\n * it — core/cron/scheduler.ts never touches the bridge itself).\n *\n * `// @ts-nocheck` matches the builtin-extension convention (see lunr-behavior).\n * Runtime imports stay on concrete core modules — never the package barrel.\n */\n\nimport type { ExtensionAPI, ExtensionContext } from \"@ashx-j/lunr\";\nimport { Type } from \"@sinclair/typebox\";\nimport { beginCronFire, endCronFire, isCronFire } from \"../core/cron/fire-guard.ts\";\nimport {\n\tcreateJob,\n\tgetJob,\n\tlistJobs,\n\tparseSchedule,\n\tpauseJob,\n\tremoveJob,\n\tresumeJob,\n\tsetCronDeliverValidator,\n\tupdateJob,\n} from \"../core/cron/jobs.ts\";\nimport { currentOrigin } from \"../core/cron/origin-context.ts\";\nimport { executeJob, startScheduler } from \"../core/cron/scheduler.ts\";\nimport { loadGatewayConfig } from \"../gateway/config.ts\";\nimport { createDeliverValidator } from \"../gateway/cron.ts\";\n\n// ---------------------------------------------------------------------------\n// Module state\n// ---------------------------------------------------------------------------\n/** The cron-fired turn currently waiting for agent_end. */\nlet pendingRun: { resolve: (text: string) => void; reject: (err: Error) => void } | null = null;\nlet scheduler: { stop(): void } | null = null;\nlet lastCtx: ExtensionContext | null = null;\n\nconst DELIVERY_BRIDGE_SYMBOL = Symbol.for(\"@lunr/cron-delivery\");\n\n// ---------------------------------------------------------------------------\n// Turn plumbing\n// ---------------------------------------------------------------------------\n\n/** Final assistant text from an agent_end messages array (last assistant message, text blocks only). */\nfunction extractAssistantText(messages: unknown[]): string {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst msg = messages[i] as any;\n\t\tif (msg?.role !== \"assistant\") continue;\n\t\tconst parts = Array.isArray(msg.content) ? msg.content : [];\n\t\tconst text = parts\n\t\t\t.filter((p: any) => p?.type === \"text\")\n\t\t\t.map((p: any) => String(p.text ?? \"\"))\n\t\t\t.join(\"\")\n\t\t\t.trim();\n\t\tif (text) return text;\n\t}\n\treturn \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Formatting helpers\n// ---------------------------------------------------------------------------\n\nfunction fmtTime(iso: string | null): string {\n\tif (!iso) return \"-\";\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return \"-\";\n\tconst p = (n: number) => String(n).padStart(2, \"0\");\n\t// Stored timestamps are UTC ISO; render in local time so users read wall-clock.\n\treturn `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;\n}\n\nfunction formatJobList(): string {\n\tconst jobs = listJobs();\n\tif (jobs.length === 0) return \"No cron jobs. Create one with /cron create <schedule> <prompt>.\";\n\tconst lines = jobs.map(\n\t\t(j) =>\n\t\t\t`${j.id} ${j.state}${j.enabled ? \"\" : \" (disabled)\"} ${j.scheduleDisplay} next=${fmtTime(j.nextRunAt)} last=${j.lastStatus ?? \"-\"}${j.lastError ? ` (${j.lastError})` : \"\"} ${j.name}`,\n\t);\n\treturn `Cron jobs (${jobs.length}):\\n${lines.join(\"\\n\")}`;\n}\n\nfunction formatStatus(): string {\n\tconst jobs = listJobs();\n\tconst count = (s: string) => jobs.filter((j) => j.state === s).length;\n\tconst next = jobs\n\t\t.filter((j) => j.enabled && j.state === \"scheduled\" && j.nextRunAt)\n\t\t.sort((a, b) => String(a.nextRunAt).localeCompare(String(b.nextRunAt)))[0];\n\treturn (\n\t\t`Cron: scheduler ${scheduler ? \"running\" : \"stopped\"}; ${jobs.length} job(s) — ` +\n\t\t`${count(\"scheduled\")} scheduled, ${count(\"paused\")} paused, ${count(\"completed\")} completed, ${count(\"error\")} error.` +\n\t\t(next ? ` Next: '${next.name}' at ${fmtTime(next.nextRunAt)}.` : \"\")\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Extension\n// ---------------------------------------------------------------------------\n\nexport default function (pi: ExtensionAPI): void {\n\t// Same allowlist the gateway uses, so a TUI session cannot persist a job\n\t// that later posts to a chat the bot can reach but is not allowed.\n\tsetCronDeliverValidator(createDeliverValidator(loadGatewayConfig()));\n\n\t// --- Local delivery bridge (Phase 4 gateway replaces this) ---\n\t(globalThis as Record<symbol, unknown>)[DELIVERY_BRIDGE_SYMBOL] = async (job: { name: string }, _content: string) => {\n\t\ttry {\n\t\t\tlastCtx?.ui.notify(`Cron job '${job.name}' finished`, \"info\");\n\t\t\treturn null;\n\t\t} catch (err) {\n\t\t\treturn String((err as Error)?.message ?? err);\n\t\t}\n\t};\n\n\t// --- Scheduler deps (TUI) ---\n\tconst runJob = (prompt: string, _job: unknown): Promise<string> => {\n\t\tif (pendingRun) return Promise.reject(new Error(\"another cron job turn is already in flight\"));\n\t\treturn new Promise<string>((resolve, reject) => {\n\t\t\tbeginCronFire();\n\t\t\tpendingRun = { resolve, reject };\n\t\t\ttry {\n\t\t\t\tpi.sendUserMessage(prompt);\n\t\t\t} catch (err) {\n\t\t\t\tpendingRun = null;\n\t\t\t\tendCronFire();\n\t\t\t\treject(err as Error);\n\t\t\t}\n\t\t});\n\t};\n\n\tconst deliverResult = async (job: any, content: string): Promise<void> => {\n\t\tconst bridge = (globalThis as Record<symbol, unknown>)[DELIVERY_BRIDGE_SYMBOL] as\n\t\t\t| ((job: unknown, content: string) => Promise<string | null>)\n\t\t\t| undefined;\n\t\tif (!bridge) throw new Error(\"no cron delivery bridge registered\");\n\t\tconst err = await bridge(job, content);\n\t\tif (err) throw new Error(String(err));\n\t};\n\n\tconst schedulerDeps = { runJob, deliverResult };\n\n\t/** Manual trigger: run inline when idle, otherwise make the job due for the next tick. */\n\tconst triggerRun = async (job: any, ctx: ExtensionContext): Promise<string> => {\n\t\tif (ctx.isIdle()) {\n\t\t\ttry {\n\t\t\t\tawait executeJob(getJob(job.id), schedulerDeps);\n\t\t\t\treturn `Cron job '${job.name}' (${job.id}) finished.`;\n\t\t\t} catch (err) {\n\t\t\t\treturn `Cron job '${job.name}' (${job.id}) failed: ${String((err as Error)?.message ?? err)}`;\n\t\t\t}\n\t\t}\n\t\tawait updateJob(job.id, { nextRunAt: new Date().toISOString() });\n\t\treturn `Cron job '${job.name}' (${job.id}) queued for the next scheduler tick.`;\n\t};\n\n\t// --- Resolve the cron-fired turn when the agent turn ends ---\n\tpi.on(\"agent_end\", (event) => {\n\t\tif (!pendingRun) return;\n\t\tconst pending = pendingRun;\n\t\tpendingRun = null;\n\t\tendCronFire();\n\t\tpending.resolve(extractAssistantText(event.messages ?? []));\n\t});\n\n\t// --- Scheduler lifecycle: TUI sessions only ---\n\tpi.on(\"session_start\", (_event, ctx) => {\n\t\tlastCtx = ctx;\n\t\tif (ctx.mode !== \"tui\") return;\n\t\tscheduler?.stop();\n\t\tscheduler = startScheduler(schedulerDeps);\n\t});\n\n\tpi.on(\"session_shutdown\", () => {\n\t\tscheduler?.stop();\n\t\tscheduler = null;\n\t});\n\n\t// --- /cron command ---\n\tpi.registerCommand(\"cron\", {\n\t\tdescription: \"Manage cron jobs: /cron list | create <schedule> <prompt> | pause|resume|run|remove <id-or-name> | status\",\n\t\tgetArgumentCompletions: (prefix: string) => {\n\t\t\tconst subs = [\"list\", \"create\", \"pause\", \"resume\", \"run\", \"remove\", \"status\"];\n\t\t\tconst lower = prefix.toLowerCase();\n\t\t\treturn subs\n\t\t\t\t.filter((s) => s.startsWith(lower))\n\t\t\t\t.map((s) => ({ value: s, label: s, description: `/cron ${s}` }));\n\t\t},\n\t\thandler: async (args, ctx) => {\n\t\t\tlastCtx = ctx;\n\t\t\tconst tokens = args.trim().split(/\\s+/).filter(Boolean);\n\t\t\tconst sub = (tokens.shift() ?? \"list\").toLowerCase();\n\t\t\ttry {\n\t\t\t\tswitch (sub) {\n\t\t\t\t\tcase \"list\": {\n\t\t\t\t\t\tctx.ui.notify(formatJobList(), \"info\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"status\": {\n\t\t\t\t\t\tctx.ui.notify(formatStatus(), \"info\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"create\": {\n\t\t\t\t\t\t// Greedy: the schedule is the shortest leading token run that parses.\n\t\t\t\t\t\tlet used = 0;\n\t\t\t\t\t\tfor (let k = 1; k <= Math.min(6, tokens.length); k++) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tparseSchedule(tokens.slice(0, k).join(\" \"));\n\t\t\t\t\t\t\t\tused = k;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// keep extending\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst prompt = tokens.slice(used).join(\" \").trim();\n\t\t\t\t\t\tif (!used || !prompt) {\n\t\t\t\t\t\t\tctx.ui.notify(\"Usage: /cron create <schedule> <prompt> — e.g. /cron create every 30m check the deploy\", \"error\");\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst job = await createJob({ prompt, schedule: tokens.slice(0, used).join(\" \") });\n\t\t\t\t\t\tctx.ui.notify(`Created cron job '${job.name}' (${job.id}) — ${job.scheduleDisplay}, next run ${fmtTime(job.nextRunAt)}.`, \"info\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"pause\":\n\t\t\t\t\tcase \"resume\":\n\t\t\t\t\tcase \"remove\":\n\t\t\t\t\tcase \"run\": {\n\t\t\t\t\t\tconst idOrName = tokens.join(\" \").trim();\n\t\t\t\t\t\tif (!idOrName) {\n\t\t\t\t\t\t\tctx.ui.notify(`Usage: /cron ${sub} <id-or-name>`, \"error\");\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (sub === \"pause\") {\n\t\t\t\t\t\t\tconst job = await pauseJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(`Paused cron job '${job.name}' (${job.id}).`, \"info\");\n\t\t\t\t\t\t} else if (sub === \"resume\") {\n\t\t\t\t\t\t\tconst job = await resumeJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(`Resumed cron job '${job.name}' (${job.id}) — next run ${fmtTime(job.nextRunAt)}.`, \"info\");\n\t\t\t\t\t\t} else if (sub === \"remove\") {\n\t\t\t\t\t\t\tconst job = await removeJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(`Removed cron job '${job.name}' (${job.id}).`, \"info\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst job = getJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(await triggerRun(job, ctx), \"info\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tctx.ui.notify(\"Usage: /cron list | create <schedule> <prompt> | pause|resume|run|remove <id-or-name> | status\", \"error\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tctx.ui.notify(String((err as Error)?.message ?? err), \"error\");\n\t\t\t}\n\t\t},\n\t});\n\n\t// --- cron tool (agent-facing) ---\n\tpi.registerTool({\n\t\tname: \"cron\",\n\t\tlabel: \"Cron\",\n\t\tdescription: [\n\t\t\t\"Manage scheduled cron jobs that run prompts unattended in this session.\",\n\t\t\t\"Actions: create (needs prompt + schedule), list, update (id + fields), pause, resume, remove, run (trigger now).\",\n\t\t\t\"Schedule formats: 'every 30m' / 'every 2h' / 'every 1d' (recurring), '30m'/'2h' or an ISO timestamp (one-shot), or a 5-field cron expression.\",\n\t\t\t\"Job output is delivered automatically; the job's prompt can answer [SILENT] to suppress delivery.\",\n\t\t].join(\"\\n\"),\n\t\tparameters: Type.Object({\n\t\t\taction: Type.Union([\n\t\t\t\tType.Literal(\"create\"),\n\t\t\t\tType.Literal(\"list\"),\n\t\t\t\tType.Literal(\"update\"),\n\t\t\t\tType.Literal(\"pause\"),\n\t\t\t\tType.Literal(\"resume\"),\n\t\t\t\tType.Literal(\"remove\"),\n\t\t\t\tType.Literal(\"run\"),\n\t\t\t]),\n\t\t\tid: Type.Optional(Type.String({ description: \"Job id or unique name (all actions except create/list).\" })),\n\t\t\tname: Type.Optional(Type.String({ description: \"Display name (<=50 chars); derived from the prompt when omitted.\" })),\n\t\t\tprompt: Type.Optional(Type.String({ description: \"The prompt the job runs (create/update).\" })),\n\t\t\tschedule: Type.Optional(Type.String({ description: \"Schedule input (create/update).\" })),\n\t\t\tdeliver: Type.Optional(\n\t\t\t\tType.String({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Delivery target(s), comma-separated: 'local' (output file only), 'origin' (the chat that created the job), 'telegram'/'discord' (platform home channel), or 'telegram:<chatId>[:<threadId>]' / 'discord:<chatId>[:<threadId>]'. Defaults to 'origin' when created from a gateway chat, else 'local'.\",\n\t\t\t\t}),\n\t\t\t),\n\t\t}),\n\t\tasync execute(_toolCallId, params, _signal, _onUpdate, ctx) {\n\t\t\tconst text = (t: string) => ({ content: [{ type: \"text\" as const, text: t }] });\n\t\t\tif (isCronFire()) {\n\t\t\t\treturn text(\"cron: unavailable while a cron-fired turn is running (cron jobs cannot schedule cron jobs).\");\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tswitch (params.action) {\n\t\t\t\t\tcase \"create\": {\n\t\t\t\t\t\tif (!params.prompt?.trim() || !params.schedule?.trim()) {\n\t\t\t\t\t\t\treturn text(\"cron create: prompt and schedule are required.\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Inside a gateway chat turn, stamp the chat as the delivery\n\t\t\t\t\t\t// origin and default deliver to \"origin\" (Phase 4); outside\n\t\t\t\t\t\t// any origin context the default stays \"local\".\n\t\t\t\t\t\tconst origin = currentOrigin();\n\t\t\t\t\t\tconst job = await createJob({\n\t\t\t\t\t\t\tprompt: params.prompt,\n\t\t\t\t\t\t\tschedule: params.schedule,\n\t\t\t\t\t\t\tname: params.name,\n\t\t\t\t\t\t\tdeliver: params.deliver ?? (origin ? \"origin\" : undefined),\n\t\t\t\t\t\t\torigin: origin ? { ...origin } : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn text(`Created cron job '${job.name}' (${job.id}) — ${job.scheduleDisplay}, next run ${fmtTime(job.nextRunAt)}.`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"list\": {\n\t\t\t\t\t\treturn text(formatJobList());\n\t\t\t\t\t}\n\t\t\t\t\tcase \"update\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron update: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await updateJob(params.id, {\n\t\t\t\t\t\t\tname: params.name,\n\t\t\t\t\t\t\tprompt: params.prompt,\n\t\t\t\t\t\t\tschedule: params.schedule,\n\t\t\t\t\t\t\tdeliver: params.deliver,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn text(`Updated cron job '${job.name}' (${job.id}) — ${job.scheduleDisplay}, next run ${fmtTime(job.nextRunAt)}.`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"pause\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron pause: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await pauseJob(params.id);\n\t\t\t\t\t\treturn text(`Paused cron job '${job.name}' (${job.id}).`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"resume\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron resume: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await resumeJob(params.id);\n\t\t\t\t\t\treturn text(`Resumed cron job '${job.name}' (${job.id}) — next run ${fmtTime(job.nextRunAt)}.`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"remove\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron remove: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await removeJob(params.id);\n\t\t\t\t\t\treturn text(`Removed cron job '${job.name}' (${job.id}).`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"run\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron run: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = getJob(params.id);\n\t\t\t\t\t\treturn text(await triggerRun(job, ctx));\n\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn text(`cron: unknown action \"${String(params.action)}\".`);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\treturn text(`cron: ${String((err as Error)?.message ?? err)}`);\n\t\t\t}\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"lunr-cron.js","sourceRoot":"","sources":["../../src/builtin-extensions/lunr-cron.ts"],"names":[],"mappings":"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","sourcesContent":["// @ts-nocheck\n/**\n * lunr-cron — lunR-native scheduled jobs (Phase 1: local TUI delivery;\n * Phase 4: gateway delivery + origin stamping).\n *\n * lunR: this file is lunR-native (not an absorbed upstream extension). It wires\n * core/cron (jobs store + scheduler) into the interactive session:\n *\n * - `/cron list|create|pause|resume|run|remove|status` command.\n * - One `cron` tool (TypeBox) so the agent can manage jobs. The shared\n * core/cron/fire-guard depth counter refuses the tool while a cron-fired\n * turn is in flight — TUI-fired OR gateway-fired (jobs cannot schedule\n * jobs).\n * - Jobs created inside a gateway chat turn are stamped with that chat as\n * their origin and default deliver to \"origin\" (core/cron/origin-context).\n * - Scheduler starts on session_start only in \"tui\" mode, stops on\n * session_shutdown. runJob = sendUserMessage + wait for agent_end;\n * deliverResult reads the `@lunr/cron-delivery` bridge on globalThis\n * (registered here as the local notify; the Phase 4 gateway replaces\n * it — core/cron/scheduler.ts never touches the bridge itself).\n *\n * `// @ts-nocheck` matches the builtin-extension convention.\n * Runtime imports stay on concrete core modules — never the package barrel.\n */\n\nimport type { ExtensionAPI, ExtensionContext } from \"@ashx-j/lunr\";\nimport { Type } from \"@sinclair/typebox\";\nimport { beginCronFire, endCronFire, isCronFire } from \"../core/cron/fire-guard.ts\";\nimport {\n\tcreateJob,\n\tgetJob,\n\tlistJobs,\n\tparseSchedule,\n\tpauseJob,\n\tremoveJob,\n\tresumeJob,\n\tsetCronDeliverValidator,\n\tupdateJob,\n} from \"../core/cron/jobs.ts\";\nimport { currentOrigin } from \"../core/cron/origin-context.ts\";\nimport { executeJob, startScheduler } from \"../core/cron/scheduler.ts\";\nimport { loadGatewayConfig } from \"../gateway/config.ts\";\nimport { createDeliverValidator } from \"../gateway/cron.ts\";\n\n// ---------------------------------------------------------------------------\n// Module state\n// ---------------------------------------------------------------------------\n/** The cron-fired turn currently waiting for agent_end. */\nlet pendingRun: { resolve: (text: string) => void; reject: (err: Error) => void } | null = null;\nlet scheduler: { stop(): void } | null = null;\nlet lastCtx: ExtensionContext | null = null;\n\nconst DELIVERY_BRIDGE_SYMBOL = Symbol.for(\"@lunr/cron-delivery\");\n\n// ---------------------------------------------------------------------------\n// Turn plumbing\n// ---------------------------------------------------------------------------\n\n/** Final assistant text from an agent_end messages array (last assistant message, text blocks only). */\nfunction extractAssistantText(messages: unknown[]): string {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst msg = messages[i] as any;\n\t\tif (msg?.role !== \"assistant\") continue;\n\t\tconst parts = Array.isArray(msg.content) ? msg.content : [];\n\t\tconst text = parts\n\t\t\t.filter((p: any) => p?.type === \"text\")\n\t\t\t.map((p: any) => String(p.text ?? \"\"))\n\t\t\t.join(\"\")\n\t\t\t.trim();\n\t\tif (text) return text;\n\t}\n\treturn \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Formatting helpers\n// ---------------------------------------------------------------------------\n\nfunction fmtTime(iso: string | null): string {\n\tif (!iso) return \"-\";\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return \"-\";\n\tconst p = (n: number) => String(n).padStart(2, \"0\");\n\t// Stored timestamps are UTC ISO; render in local time so users read wall-clock.\n\treturn `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;\n}\n\nfunction formatJobList(): string {\n\tconst jobs = listJobs();\n\tif (jobs.length === 0) return \"No cron jobs. Create one with /cron create <schedule> <prompt>.\";\n\tconst lines = jobs.map(\n\t\t(j) =>\n\t\t\t`${j.id} ${j.state}${j.enabled ? \"\" : \" (disabled)\"} ${j.scheduleDisplay} next=${fmtTime(j.nextRunAt)} last=${j.lastStatus ?? \"-\"}${j.lastError ? ` (${j.lastError})` : \"\"} ${j.name}`,\n\t);\n\treturn `Cron jobs (${jobs.length}):\\n${lines.join(\"\\n\")}`;\n}\n\nfunction formatStatus(): string {\n\tconst jobs = listJobs();\n\tconst count = (s: string) => jobs.filter((j) => j.state === s).length;\n\tconst next = jobs\n\t\t.filter((j) => j.enabled && j.state === \"scheduled\" && j.nextRunAt)\n\t\t.sort((a, b) => String(a.nextRunAt).localeCompare(String(b.nextRunAt)))[0];\n\treturn (\n\t\t`Cron: scheduler ${scheduler ? \"running\" : \"stopped\"}; ${jobs.length} job(s) — ` +\n\t\t`${count(\"scheduled\")} scheduled, ${count(\"paused\")} paused, ${count(\"completed\")} completed, ${count(\"error\")} error.` +\n\t\t(next ? ` Next: '${next.name}' at ${fmtTime(next.nextRunAt)}.` : \"\")\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Extension\n// ---------------------------------------------------------------------------\n\nexport default function (pi: ExtensionAPI): void {\n\t// Same allowlist the gateway uses, so a TUI session cannot persist a job\n\t// that later posts to a chat the bot can reach but is not allowed.\n\tsetCronDeliverValidator(createDeliverValidator(loadGatewayConfig()));\n\n\t// --- Local delivery bridge (Phase 4 gateway replaces this) ---\n\t(globalThis as Record<symbol, unknown>)[DELIVERY_BRIDGE_SYMBOL] = async (job: { name: string }, _content: string) => {\n\t\ttry {\n\t\t\tlastCtx?.ui.notify(`Cron job '${job.name}' finished`, \"info\");\n\t\t\treturn null;\n\t\t} catch (err) {\n\t\t\treturn String((err as Error)?.message ?? err);\n\t\t}\n\t};\n\n\t// --- Scheduler deps (TUI) ---\n\tconst runJob = (prompt: string, _job: unknown): Promise<string> => {\n\t\tif (pendingRun) return Promise.reject(new Error(\"another cron job turn is already in flight\"));\n\t\treturn new Promise<string>((resolve, reject) => {\n\t\t\tbeginCronFire();\n\t\t\tpendingRun = { resolve, reject };\n\t\t\ttry {\n\t\t\t\tpi.sendUserMessage(prompt);\n\t\t\t} catch (err) {\n\t\t\t\tpendingRun = null;\n\t\t\t\tendCronFire();\n\t\t\t\treject(err as Error);\n\t\t\t}\n\t\t});\n\t};\n\n\tconst deliverResult = async (job: any, content: string): Promise<void> => {\n\t\tconst bridge = (globalThis as Record<symbol, unknown>)[DELIVERY_BRIDGE_SYMBOL] as\n\t\t\t| ((job: unknown, content: string) => Promise<string | null>)\n\t\t\t| undefined;\n\t\tif (!bridge) throw new Error(\"no cron delivery bridge registered\");\n\t\tconst err = await bridge(job, content);\n\t\tif (err) throw new Error(String(err));\n\t};\n\n\tconst schedulerDeps = { runJob, deliverResult };\n\n\t/** Manual trigger: run inline when idle, otherwise make the job due for the next tick. */\n\tconst triggerRun = async (job: any, ctx: ExtensionContext): Promise<string> => {\n\t\tif (ctx.isIdle()) {\n\t\t\ttry {\n\t\t\t\tawait executeJob(getJob(job.id), schedulerDeps);\n\t\t\t\treturn `Cron job '${job.name}' (${job.id}) finished.`;\n\t\t\t} catch (err) {\n\t\t\t\treturn `Cron job '${job.name}' (${job.id}) failed: ${String((err as Error)?.message ?? err)}`;\n\t\t\t}\n\t\t}\n\t\tawait updateJob(job.id, { nextRunAt: new Date().toISOString() });\n\t\treturn `Cron job '${job.name}' (${job.id}) queued for the next scheduler tick.`;\n\t};\n\n\t// --- Resolve the cron-fired turn when the agent turn ends ---\n\tpi.on(\"agent_end\", (event) => {\n\t\tif (!pendingRun) return;\n\t\tconst pending = pendingRun;\n\t\tpendingRun = null;\n\t\tendCronFire();\n\t\tpending.resolve(extractAssistantText(event.messages ?? []));\n\t});\n\n\t// --- Scheduler lifecycle: TUI sessions only ---\n\tpi.on(\"session_start\", (_event, ctx) => {\n\t\tlastCtx = ctx;\n\t\tif (ctx.mode !== \"tui\") return;\n\t\tscheduler?.stop();\n\t\tscheduler = startScheduler(schedulerDeps);\n\t});\n\n\tpi.on(\"session_shutdown\", () => {\n\t\tscheduler?.stop();\n\t\tscheduler = null;\n\t});\n\n\t// --- /cron command ---\n\tpi.registerCommand(\"cron\", {\n\t\tdescription: \"Manage cron jobs: /cron list | create <schedule> <prompt> | pause|resume|run|remove <id-or-name> | status\",\n\t\tgetArgumentCompletions: (prefix: string) => {\n\t\t\tconst subs = [\"list\", \"create\", \"pause\", \"resume\", \"run\", \"remove\", \"status\"];\n\t\t\tconst lower = prefix.toLowerCase();\n\t\t\treturn subs\n\t\t\t\t.filter((s) => s.startsWith(lower))\n\t\t\t\t.map((s) => ({ value: s, label: s, description: `/cron ${s}` }));\n\t\t},\n\t\thandler: async (args, ctx) => {\n\t\t\tlastCtx = ctx;\n\t\t\tconst tokens = args.trim().split(/\\s+/).filter(Boolean);\n\t\t\tconst sub = (tokens.shift() ?? \"list\").toLowerCase();\n\t\t\ttry {\n\t\t\t\tswitch (sub) {\n\t\t\t\t\tcase \"list\": {\n\t\t\t\t\t\tctx.ui.notify(formatJobList(), \"info\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"status\": {\n\t\t\t\t\t\tctx.ui.notify(formatStatus(), \"info\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"create\": {\n\t\t\t\t\t\t// Greedy: the schedule is the shortest leading token run that parses.\n\t\t\t\t\t\tlet used = 0;\n\t\t\t\t\t\tfor (let k = 1; k <= Math.min(6, tokens.length); k++) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tparseSchedule(tokens.slice(0, k).join(\" \"));\n\t\t\t\t\t\t\t\tused = k;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// keep extending\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst prompt = tokens.slice(used).join(\" \").trim();\n\t\t\t\t\t\tif (!used || !prompt) {\n\t\t\t\t\t\t\tctx.ui.notify(\"Usage: /cron create <schedule> <prompt> — e.g. /cron create every 30m check the deploy\", \"error\");\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst job = await createJob({ prompt, schedule: tokens.slice(0, used).join(\" \") });\n\t\t\t\t\t\tctx.ui.notify(`Created cron job '${job.name}' (${job.id}) — ${job.scheduleDisplay}, next run ${fmtTime(job.nextRunAt)}.`, \"info\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"pause\":\n\t\t\t\t\tcase \"resume\":\n\t\t\t\t\tcase \"remove\":\n\t\t\t\t\tcase \"run\": {\n\t\t\t\t\t\tconst idOrName = tokens.join(\" \").trim();\n\t\t\t\t\t\tif (!idOrName) {\n\t\t\t\t\t\t\tctx.ui.notify(`Usage: /cron ${sub} <id-or-name>`, \"error\");\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (sub === \"pause\") {\n\t\t\t\t\t\t\tconst job = await pauseJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(`Paused cron job '${job.name}' (${job.id}).`, \"info\");\n\t\t\t\t\t\t} else if (sub === \"resume\") {\n\t\t\t\t\t\t\tconst job = await resumeJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(`Resumed cron job '${job.name}' (${job.id}) — next run ${fmtTime(job.nextRunAt)}.`, \"info\");\n\t\t\t\t\t\t} else if (sub === \"remove\") {\n\t\t\t\t\t\t\tconst job = await removeJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(`Removed cron job '${job.name}' (${job.id}).`, \"info\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst job = getJob(idOrName);\n\t\t\t\t\t\t\tctx.ui.notify(await triggerRun(job, ctx), \"info\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tctx.ui.notify(\"Usage: /cron list | create <schedule> <prompt> | pause|resume|run|remove <id-or-name> | status\", \"error\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tctx.ui.notify(String((err as Error)?.message ?? err), \"error\");\n\t\t\t}\n\t\t},\n\t});\n\n\t// --- cron tool (agent-facing) ---\n\tpi.registerTool({\n\t\tname: \"cron\",\n\t\tlabel: \"Cron\",\n\t\tdescription: [\n\t\t\t\"Manage scheduled cron jobs that run prompts unattended in this session.\",\n\t\t\t\"Actions: create (needs prompt + schedule), list, update (id + fields), pause, resume, remove, run (trigger now).\",\n\t\t\t\"Schedule formats: 'every 30m' / 'every 2h' / 'every 1d' (recurring), '30m'/'2h' or an ISO timestamp (one-shot), or a 5-field cron expression.\",\n\t\t\t\"Job output is delivered automatically; the job's prompt can answer [SILENT] to suppress delivery.\",\n\t\t].join(\"\\n\"),\n\t\tparameters: Type.Object({\n\t\t\taction: Type.Union([\n\t\t\t\tType.Literal(\"create\"),\n\t\t\t\tType.Literal(\"list\"),\n\t\t\t\tType.Literal(\"update\"),\n\t\t\t\tType.Literal(\"pause\"),\n\t\t\t\tType.Literal(\"resume\"),\n\t\t\t\tType.Literal(\"remove\"),\n\t\t\t\tType.Literal(\"run\"),\n\t\t\t]),\n\t\t\tid: Type.Optional(Type.String({ description: \"Job id or unique name (all actions except create/list).\" })),\n\t\t\tname: Type.Optional(Type.String({ description: \"Display name (<=50 chars); derived from the prompt when omitted.\" })),\n\t\t\tprompt: Type.Optional(Type.String({ description: \"The prompt the job runs (create/update).\" })),\n\t\t\tschedule: Type.Optional(Type.String({ description: \"Schedule input (create/update).\" })),\n\t\t\tdeliver: Type.Optional(\n\t\t\t\tType.String({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Delivery target(s), comma-separated: 'local' (output file only), 'origin' (the chat that created the job), 'telegram'/'discord' (platform home channel), or 'telegram:<chatId>[:<threadId>]' / 'discord:<chatId>[:<threadId>]'. Defaults to 'origin' when created from a gateway chat, else 'local'.\",\n\t\t\t\t}),\n\t\t\t),\n\t\t}),\n\t\tasync execute(_toolCallId, params, _signal, _onUpdate, ctx) {\n\t\t\tconst text = (t: string) => ({ content: [{ type: \"text\" as const, text: t }] });\n\t\t\tif (isCronFire()) {\n\t\t\t\treturn text(\"cron: unavailable while a cron-fired turn is running (cron jobs cannot schedule cron jobs).\");\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tswitch (params.action) {\n\t\t\t\t\tcase \"create\": {\n\t\t\t\t\t\tif (!params.prompt?.trim() || !params.schedule?.trim()) {\n\t\t\t\t\t\t\treturn text(\"cron create: prompt and schedule are required.\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Inside a gateway chat turn, stamp the chat as the delivery\n\t\t\t\t\t\t// origin and default deliver to \"origin\" (Phase 4); outside\n\t\t\t\t\t\t// any origin context the default stays \"local\".\n\t\t\t\t\t\tconst origin = currentOrigin();\n\t\t\t\t\t\tconst job = await createJob({\n\t\t\t\t\t\t\tprompt: params.prompt,\n\t\t\t\t\t\t\tschedule: params.schedule,\n\t\t\t\t\t\t\tname: params.name,\n\t\t\t\t\t\t\tdeliver: params.deliver ?? (origin ? \"origin\" : undefined),\n\t\t\t\t\t\t\torigin: origin ? { ...origin } : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn text(`Created cron job '${job.name}' (${job.id}) — ${job.scheduleDisplay}, next run ${fmtTime(job.nextRunAt)}.`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"list\": {\n\t\t\t\t\t\treturn text(formatJobList());\n\t\t\t\t\t}\n\t\t\t\t\tcase \"update\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron update: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await updateJob(params.id, {\n\t\t\t\t\t\t\tname: params.name,\n\t\t\t\t\t\t\tprompt: params.prompt,\n\t\t\t\t\t\t\tschedule: params.schedule,\n\t\t\t\t\t\t\tdeliver: params.deliver,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn text(`Updated cron job '${job.name}' (${job.id}) — ${job.scheduleDisplay}, next run ${fmtTime(job.nextRunAt)}.`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"pause\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron pause: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await pauseJob(params.id);\n\t\t\t\t\t\treturn text(`Paused cron job '${job.name}' (${job.id}).`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"resume\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron resume: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await resumeJob(params.id);\n\t\t\t\t\t\treturn text(`Resumed cron job '${job.name}' (${job.id}) — next run ${fmtTime(job.nextRunAt)}.`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"remove\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron remove: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = await removeJob(params.id);\n\t\t\t\t\t\treturn text(`Removed cron job '${job.name}' (${job.id}).`);\n\t\t\t\t\t}\n\t\t\t\t\tcase \"run\": {\n\t\t\t\t\t\tif (!params.id) return text(\"cron run: id (or unique name) is required.\");\n\t\t\t\t\t\tconst job = getJob(params.id);\n\t\t\t\t\t\treturn text(await triggerRun(job, ctx));\n\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn text(`cron: unknown action \"${String(params.action)}\".`);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\treturn text(`cron: ${String((err as Error)?.message ?? err)}`);\n\t\t\t}\n\t\t},\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"chain-validation.d.ts","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-subagents/src/extension/chain-validation.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;GAiBG;AAqBH,eAAO,MAAM,eAAe,UAA2B,CAAC;AACxD,eAAO,MAAM,kBAAkB,UAAoC,CAAC;AACpE,eAAO,MAAM,qBAAqB,UAA+C,CAAC;AAClF,eAAO,MAAM,WAAW,UAAqC,CAAC;AAC9D,eAAO,MAAM,gBAAgB,UAAkC,CAAC;AAChE,eAAO,MAAM,YAAY,UAAsC,CAAC;AA8DhE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAmDtD","sourcesContent":["// @ts-nocheck\n/**\n * Friendly chain parameter validation.\n *\n * The runtime (pi-ai) validates tool arguments against the TypeBox schema before\n * the tool's `execute` runs. When a chain step has an extra property, the model\n * receives a raw TypeBox message such as `chain.1: must not have additional\n * properties` — which does not name the offending property, list the allowed\n * ones, or show the expected shape. Agents then iteratively guess the format and\n * waste several turns before getting it right.\n *\n * `validateChainInput` runs from the tool's `prepareArguments` shim (and the RPC\n * bridge) *before* schema validation. It throws a rich, actionable error for the\n * common chain-shape failures, so the model sees which property is disallowed,\n * what is allowed, and a valid example — instead of a raw TypeBox diagnostic.\n *\n * Allowed property names and additional-property strictness are derived directly\n * from the schema objects in `schemas.ts` so this stays aligned with TypeBox.\n */\n\nimport {\n\tChainItem,\n\tParallelTaskSchema,\n\tDynamicParallelTemplateSchema,\n\tDynamicExpandSchema,\n\tDynamicCollectSchema,\n} from \"./schemas.ts\";\n\ntype ObjectSchema = {\n\tproperties?: Record<string, unknown>;\n\tadditionalProperties?: unknown;\n};\n\nfunction allowedKeysOf(schema: ObjectSchema | undefined): string[] {\n\treturn schema?.properties ? Object.keys(schema.properties) : [];\n}\n\nconst ExpandFromSchema = (DynamicExpandSchema.properties?.from ?? {}) as ObjectSchema;\n\nexport const CHAIN_STEP_KEYS = allowedKeysOf(ChainItem);\nexport const PARALLEL_TASK_KEYS = allowedKeysOf(ParallelTaskSchema);\nexport const DYNAMIC_TEMPLATE_KEYS = allowedKeysOf(DynamicParallelTemplateSchema);\nexport const EXPAND_KEYS = allowedKeysOf(DynamicExpandSchema);\nexport const EXPAND_FROM_KEYS = allowedKeysOf(ExpandFromSchema);\nexport const COLLECT_KEYS = allowedKeysOf(DynamicCollectSchema);\n\nconst CHAIN_STEP_EXAMPLE = '{\"agent\": \"worker\", \"task\": \"do X\"}';\nconst PARALLEL_TASK_EXAMPLE = '{\"agent\": \"worker\", \"task\": \"do X\"}';\nconst DYNAMIC_TEMPLATE_EXAMPLE = '{\"agent\": \"worker\", \"task\": \"Review {item.path}\"}';\nconst EXPAND_EXAMPLE = '{\"from\": {\"output\": \"targets\", \"path\": \"/items\"}, \"maxItems\": 4}';\nconst EXPAND_FROM_EXAMPLE = '{\"output\": \"targets\", \"path\": \"/items\"}';\nconst COLLECT_EXAMPLE = '{\"as\": \"reviews\"}';\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction disallowedKeys(value: Record<string, unknown>, allowed: readonly string[]): string[] {\n\treturn Object.keys(value).filter((key) => !allowed.includes(key));\n}\n\nfunction typeName(value: unknown): string {\n\tif (Array.isArray(value)) return \"array\";\n\treturn typeof value;\n}\n\nfunction quoteList(keys: string[]): string {\n\treturn keys.map((key) => `\"${key}\"`).join(\", \");\n}\n\nfunction disallowedMessage(\n\tpath: string,\n\tkeys: string[],\n\tallowed: readonly string[],\n\texample?: string,\n): string {\n\tconst subject = keys.length === 1\n\t\t? `property \"${keys[0]}\" is not allowed`\n\t\t: `properties ${quoteList(keys)} are not allowed`;\n\tconst examplePart = example ? `\\n\\nExample: ${example}` : \"\";\n\treturn `subagent ${path}: ${subject}.\\nAllowed properties: ${allowed.join(\", \")}.${examplePart}`;\n}\n\nfunction expectObject(value: unknown, path: string, allowed: readonly string[], example?: string): asserts value is Record<string, unknown> {\n\tif (!isPlainObject(value)) {\n\t\tconst examplePart = example ? `\\n\\nExample: ${example}` : \"\";\n\t\tthrow new Error(\n\t\t\t`subagent ${path}: expected an object, received ${typeName(value)}.\\nAllowed properties: ${allowed.join(\", \")}.${examplePart}`,\n\t\t);\n\t}\n}\n\nfunction checkNoExtraKeys(\n\tvalue: Record<string, unknown>,\n\tpath: string,\n\tschema: ObjectSchema,\n\tallowed: readonly string[],\n\texample?: string,\n): void {\n\tif (schema.additionalProperties !== false) return;\n\tconst extra = disallowedKeys(value, allowed);\n\tif (extra.length > 0) {\n\t\tthrow new Error(disallowedMessage(path, extra, allowed, example));\n\t}\n}\n\n/**\n * Validates the `chain` array on a raw subagent tool-call argument object and\n * throws a friendly, actionable error when a chain step (or a nested\n * `parallel`/`expand`/`collect` object) has a disallowed property or wrong shape.\n *\n * No-op when `chain` is absent or not an array, so management/control/single/\n * parallel calls are unaffected.\n */\nexport function validateChainInput(args: unknown): void {\n\tif (!isPlainObject(args)) return;\n\tconst chain = (args as Record<string, unknown>).chain;\n\tif (!Array.isArray(chain)) return;\n\n\tchain.forEach((step, index) => {\n\t\tconst stepPath = `chain step validation failed at chain[${index}]`;\n\t\texpectObject(step, stepPath, CHAIN_STEP_KEYS, CHAIN_STEP_EXAMPLE);\n\t\tcheckNoExtraKeys(step, stepPath, ChainItem, CHAIN_STEP_KEYS, CHAIN_STEP_EXAMPLE);\n\n\t\tif (step.expand !== undefined) {\n\t\t\tconst expandPath = `${stepPath}.expand`;\n\t\t\texpectObject(step.expand, expandPath, EXPAND_KEYS, EXPAND_EXAMPLE);\n\t\t\tcheckNoExtraKeys(step.expand, expandPath, DynamicExpandSchema, EXPAND_KEYS, EXPAND_EXAMPLE);\n\n\t\t\tconst from = (step.expand as Record<string, unknown>).from;\n\t\t\tif (from !== undefined) {\n\t\t\t\tconst fromPath = `${expandPath}.from`;\n\t\t\t\texpectObject(from, fromPath, EXPAND_FROM_KEYS, EXPAND_FROM_EXAMPLE);\n\t\t\t\tcheckNoExtraKeys(from, fromPath, ExpandFromSchema, EXPAND_FROM_KEYS, EXPAND_FROM_EXAMPLE);\n\t\t\t}\n\t\t}\n\n\t\tif (step.collect !== undefined) {\n\t\t\tconst collectPath = `${stepPath}.collect`;\n\t\t\texpectObject(step.collect, collectPath, COLLECT_KEYS, COLLECT_EXAMPLE);\n\t\t\tcheckNoExtraKeys(step.collect, collectPath, DynamicCollectSchema, COLLECT_KEYS, COLLECT_EXAMPLE);\n\t\t}\n\n\t\tconst parallel = step.parallel;\n\t\tif (parallel === undefined) return;\n\n\t\tif (Array.isArray(parallel)) {\n\t\t\tparallel.forEach((task, pIndex) => {\n\t\t\t\tconst taskPath = `${stepPath}.parallel[${pIndex}]`;\n\t\t\t\texpectObject(task, taskPath, PARALLEL_TASK_KEYS, PARALLEL_TASK_EXAMPLE);\n\t\t\t\tcheckNoExtraKeys(task, taskPath, ParallelTaskSchema, PARALLEL_TASK_KEYS, PARALLEL_TASK_EXAMPLE);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (isPlainObject(parallel)) {\n\t\t\tconst templatePath = `${stepPath}.parallel (dynamic fanout template)`;\n\t\t\tcheckNoExtraKeys(parallel, templatePath, DynamicParallelTemplateSchema, DYNAMIC_TEMPLATE_KEYS, DYNAMIC_TEMPLATE_EXAMPLE);\n\t\t\treturn;\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t`subagent ${stepPath}.parallel: expected an array of task objects or a dynamic fanout template object, received ${typeName(parallel)}.\\n\\nExample static: [${PARALLEL_TASK_EXAMPLE}]\\nExample dynamic: ${DYNAMIC_TEMPLATE_EXAMPLE}`,\n\t\t);\n\t});\n}"]}
1
+ {"version":3,"file":"chain-validation.d.ts","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-subagents/src/extension/chain-validation.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;GAiBG;AAqBH,eAAO,MAAM,eAAe,UAA2B,CAAC;AACxD,eAAO,MAAM,kBAAkB,UAAoC,CAAC;AACpE,eAAO,MAAM,qBAAqB,UAA+C,CAAC;AAClF,eAAO,MAAM,WAAW,UAAqC,CAAC;AAC9D,eAAO,MAAM,gBAAgB,UAAkC,CAAC;AAChE,eAAO,MAAM,YAAY,UAAsC,CAAC;AA8DhE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAmDtD","sourcesContent":["// @ts-nocheck\n/**\n * Friendly chain parameter validation.\n *\n * The runtime (pi-ai) validates tool arguments against the TypeBox schema before\n * the tool's `execute` runs. When a chain step has an extra property, the model\n * receives a raw TypeBox message such as `chain.1: must not have additional\n * properties` — which does not name the offending property, list the allowed\n * ones, or show the expected shape. Agents then iteratively guess the format and\n * waste several turns before getting it right.\n *\n * `validateChainInput` runs from the tool's `prepareArguments` shim (and the RPC\n * bridge) *before* schema validation. It throws a rich, actionable error for the\n * common chain-shape failures, so the model sees which property is disallowed,\n * what is allowed, and a valid example — instead of a raw TypeBox diagnostic.\n *\n * Allowed property names and additional-property strictness are derived directly\n * from the schema objects in `schemas.ts` so this stays aligned with TypeBox.\n */\n\nimport {\n\tChainItem,\n\tParallelTaskSchema,\n\tDynamicParallelTemplateSchema,\n\tDynamicExpandSchema,\n\tDynamicCollectSchema,\n} from \"./schemas.ts\";\n\ntype ObjectSchema = {\n\tproperties?: Record<string, unknown>;\n\tadditionalProperties?: unknown;\n};\n\nfunction allowedKeysOf(schema: ObjectSchema | undefined): string[] {\n\treturn schema?.properties ? Object.keys(schema.properties) : [];\n}\n\nconst ExpandFromSchema = (DynamicExpandSchema.properties?.from ?? {}) as ObjectSchema;\n\nexport const CHAIN_STEP_KEYS = allowedKeysOf(ChainItem);\nexport const PARALLEL_TASK_KEYS = allowedKeysOf(ParallelTaskSchema);\nexport const DYNAMIC_TEMPLATE_KEYS = allowedKeysOf(DynamicParallelTemplateSchema);\nexport const EXPAND_KEYS = allowedKeysOf(DynamicExpandSchema);\nexport const EXPAND_FROM_KEYS = allowedKeysOf(ExpandFromSchema);\nexport const COLLECT_KEYS = allowedKeysOf(DynamicCollectSchema);\n\nconst CHAIN_STEP_EXAMPLE = '{\"task\": \"do X\", \"description\": \"Do X\", \"permissions\": \"read-only\"}';\nconst PARALLEL_TASK_EXAMPLE = '{\"task\": \"do X\", \"description\": \"Do X\", \"permissions\": \"read-only\"}';\nconst DYNAMIC_TEMPLATE_EXAMPLE = '{\"task\": \"Review {item.path}\", \"description\": \"Review {item.path}\", \"permissions\": \"read-only\"}';\nconst EXPAND_EXAMPLE = '{\"from\": {\"output\": \"targets\", \"path\": \"/items\"}, \"maxItems\": 4}';\nconst EXPAND_FROM_EXAMPLE = '{\"output\": \"targets\", \"path\": \"/items\"}';\nconst COLLECT_EXAMPLE = '{\"as\": \"reviews\"}';\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction disallowedKeys(value: Record<string, unknown>, allowed: readonly string[]): string[] {\n\treturn Object.keys(value).filter((key) => !allowed.includes(key));\n}\n\nfunction typeName(value: unknown): string {\n\tif (Array.isArray(value)) return \"array\";\n\treturn typeof value;\n}\n\nfunction quoteList(keys: string[]): string {\n\treturn keys.map((key) => `\"${key}\"`).join(\", \");\n}\n\nfunction disallowedMessage(\n\tpath: string,\n\tkeys: string[],\n\tallowed: readonly string[],\n\texample?: string,\n): string {\n\tconst subject = keys.length === 1\n\t\t? `property \"${keys[0]}\" is not allowed`\n\t\t: `properties ${quoteList(keys)} are not allowed`;\n\tconst examplePart = example ? `\\n\\nExample: ${example}` : \"\";\n\treturn `subagent ${path}: ${subject}.\\nAllowed properties: ${allowed.join(\", \")}.${examplePart}`;\n}\n\nfunction expectObject(value: unknown, path: string, allowed: readonly string[], example?: string): asserts value is Record<string, unknown> {\n\tif (!isPlainObject(value)) {\n\t\tconst examplePart = example ? `\\n\\nExample: ${example}` : \"\";\n\t\tthrow new Error(\n\t\t\t`subagent ${path}: expected an object, received ${typeName(value)}.\\nAllowed properties: ${allowed.join(\", \")}.${examplePart}`,\n\t\t);\n\t}\n}\n\nfunction checkNoExtraKeys(\n\tvalue: Record<string, unknown>,\n\tpath: string,\n\tschema: ObjectSchema,\n\tallowed: readonly string[],\n\texample?: string,\n): void {\n\tif (schema.additionalProperties !== false) return;\n\tconst extra = disallowedKeys(value, allowed);\n\tif (extra.length > 0) {\n\t\tthrow new Error(disallowedMessage(path, extra, allowed, example));\n\t}\n}\n\n/**\n * Validates the `chain` array on a raw subagent tool-call argument object and\n * throws a friendly, actionable error when a chain step (or a nested\n * `parallel`/`expand`/`collect` object) has a disallowed property or wrong shape.\n *\n * No-op when `chain` is absent or not an array, so management/control/single/\n * parallel calls are unaffected.\n */\nexport function validateChainInput(args: unknown): void {\n\tif (!isPlainObject(args)) return;\n\tconst chain = (args as Record<string, unknown>).chain;\n\tif (!Array.isArray(chain)) return;\n\n\tchain.forEach((step, index) => {\n\t\tconst stepPath = `chain step validation failed at chain[${index}]`;\n\t\texpectObject(step, stepPath, CHAIN_STEP_KEYS, CHAIN_STEP_EXAMPLE);\n\t\tcheckNoExtraKeys(step, stepPath, ChainItem, CHAIN_STEP_KEYS, CHAIN_STEP_EXAMPLE);\n\n\t\tif (step.expand !== undefined) {\n\t\t\tconst expandPath = `${stepPath}.expand`;\n\t\t\texpectObject(step.expand, expandPath, EXPAND_KEYS, EXPAND_EXAMPLE);\n\t\t\tcheckNoExtraKeys(step.expand, expandPath, DynamicExpandSchema, EXPAND_KEYS, EXPAND_EXAMPLE);\n\n\t\t\tconst from = (step.expand as Record<string, unknown>).from;\n\t\t\tif (from !== undefined) {\n\t\t\t\tconst fromPath = `${expandPath}.from`;\n\t\t\t\texpectObject(from, fromPath, EXPAND_FROM_KEYS, EXPAND_FROM_EXAMPLE);\n\t\t\t\tcheckNoExtraKeys(from, fromPath, ExpandFromSchema, EXPAND_FROM_KEYS, EXPAND_FROM_EXAMPLE);\n\t\t\t}\n\t\t}\n\n\t\tif (step.collect !== undefined) {\n\t\t\tconst collectPath = `${stepPath}.collect`;\n\t\t\texpectObject(step.collect, collectPath, COLLECT_KEYS, COLLECT_EXAMPLE);\n\t\t\tcheckNoExtraKeys(step.collect, collectPath, DynamicCollectSchema, COLLECT_KEYS, COLLECT_EXAMPLE);\n\t\t}\n\n\t\tconst parallel = step.parallel;\n\t\tif (parallel === undefined) return;\n\n\t\tif (Array.isArray(parallel)) {\n\t\t\tparallel.forEach((task, pIndex) => {\n\t\t\t\tconst taskPath = `${stepPath}.parallel[${pIndex}]`;\n\t\t\t\texpectObject(task, taskPath, PARALLEL_TASK_KEYS, PARALLEL_TASK_EXAMPLE);\n\t\t\t\tcheckNoExtraKeys(task, taskPath, ParallelTaskSchema, PARALLEL_TASK_KEYS, PARALLEL_TASK_EXAMPLE);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (isPlainObject(parallel)) {\n\t\t\tconst templatePath = `${stepPath}.parallel (dynamic fanout template)`;\n\t\t\tcheckNoExtraKeys(parallel, templatePath, DynamicParallelTemplateSchema, DYNAMIC_TEMPLATE_KEYS, DYNAMIC_TEMPLATE_EXAMPLE);\n\t\t\treturn;\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t`subagent ${stepPath}.parallel: expected an array of task objects or a dynamic fanout template object, received ${typeName(parallel)}.\\n\\nExample static: [${PARALLEL_TASK_EXAMPLE}]\\nExample dynamic: ${DYNAMIC_TEMPLATE_EXAMPLE}`,\n\t\t);\n\t});\n}"]}
@@ -28,9 +28,9 @@ export const DYNAMIC_TEMPLATE_KEYS = allowedKeysOf(DynamicParallelTemplateSchema
28
28
  export const EXPAND_KEYS = allowedKeysOf(DynamicExpandSchema);
29
29
  export const EXPAND_FROM_KEYS = allowedKeysOf(ExpandFromSchema);
30
30
  export const COLLECT_KEYS = allowedKeysOf(DynamicCollectSchema);
31
- const CHAIN_STEP_EXAMPLE = '{"agent": "worker", "task": "do X"}';
32
- const PARALLEL_TASK_EXAMPLE = '{"agent": "worker", "task": "do X"}';
33
- const DYNAMIC_TEMPLATE_EXAMPLE = '{"agent": "worker", "task": "Review {item.path}"}';
31
+ const CHAIN_STEP_EXAMPLE = '{"task": "do X", "description": "Do X", "permissions": "read-only"}';
32
+ const PARALLEL_TASK_EXAMPLE = '{"task": "do X", "description": "Do X", "permissions": "read-only"}';
33
+ const DYNAMIC_TEMPLATE_EXAMPLE = '{"task": "Review {item.path}", "description": "Review {item.path}", "permissions": "read-only"}';
34
34
  const EXPAND_EXAMPLE = '{"from": {"output": "targets", "path": "/items"}, "maxItems": 4}';
35
35
  const EXPAND_FROM_EXAMPLE = '{"output": "targets", "path": "/items"}';
36
36
  const COLLECT_EXAMPLE = '{"as": "reviews"}';
@@ -1 +1 @@
1
- {"version":3,"file":"chain-validation.js","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-subagents/src/extension/chain-validation.ts"],"names":[],"mappings":"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","sourcesContent":["// @ts-nocheck\n/**\n * Friendly chain parameter validation.\n *\n * The runtime (pi-ai) validates tool arguments against the TypeBox schema before\n * the tool's `execute` runs. When a chain step has an extra property, the model\n * receives a raw TypeBox message such as `chain.1: must not have additional\n * properties` — which does not name the offending property, list the allowed\n * ones, or show the expected shape. Agents then iteratively guess the format and\n * waste several turns before getting it right.\n *\n * `validateChainInput` runs from the tool's `prepareArguments` shim (and the RPC\n * bridge) *before* schema validation. It throws a rich, actionable error for the\n * common chain-shape failures, so the model sees which property is disallowed,\n * what is allowed, and a valid example — instead of a raw TypeBox diagnostic.\n *\n * Allowed property names and additional-property strictness are derived directly\n * from the schema objects in `schemas.ts` so this stays aligned with TypeBox.\n */\n\nimport {\n\tChainItem,\n\tParallelTaskSchema,\n\tDynamicParallelTemplateSchema,\n\tDynamicExpandSchema,\n\tDynamicCollectSchema,\n} from \"./schemas.ts\";\n\ntype ObjectSchema = {\n\tproperties?: Record<string, unknown>;\n\tadditionalProperties?: unknown;\n};\n\nfunction allowedKeysOf(schema: ObjectSchema | undefined): string[] {\n\treturn schema?.properties ? Object.keys(schema.properties) : [];\n}\n\nconst ExpandFromSchema = (DynamicExpandSchema.properties?.from ?? {}) as ObjectSchema;\n\nexport const CHAIN_STEP_KEYS = allowedKeysOf(ChainItem);\nexport const PARALLEL_TASK_KEYS = allowedKeysOf(ParallelTaskSchema);\nexport const DYNAMIC_TEMPLATE_KEYS = allowedKeysOf(DynamicParallelTemplateSchema);\nexport const EXPAND_KEYS = allowedKeysOf(DynamicExpandSchema);\nexport const EXPAND_FROM_KEYS = allowedKeysOf(ExpandFromSchema);\nexport const COLLECT_KEYS = allowedKeysOf(DynamicCollectSchema);\n\nconst CHAIN_STEP_EXAMPLE = '{\"agent\": \"worker\", \"task\": \"do X\"}';\nconst PARALLEL_TASK_EXAMPLE = '{\"agent\": \"worker\", \"task\": \"do X\"}';\nconst DYNAMIC_TEMPLATE_EXAMPLE = '{\"agent\": \"worker\", \"task\": \"Review {item.path}\"}';\nconst EXPAND_EXAMPLE = '{\"from\": {\"output\": \"targets\", \"path\": \"/items\"}, \"maxItems\": 4}';\nconst EXPAND_FROM_EXAMPLE = '{\"output\": \"targets\", \"path\": \"/items\"}';\nconst COLLECT_EXAMPLE = '{\"as\": \"reviews\"}';\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction disallowedKeys(value: Record<string, unknown>, allowed: readonly string[]): string[] {\n\treturn Object.keys(value).filter((key) => !allowed.includes(key));\n}\n\nfunction typeName(value: unknown): string {\n\tif (Array.isArray(value)) return \"array\";\n\treturn typeof value;\n}\n\nfunction quoteList(keys: string[]): string {\n\treturn keys.map((key) => `\"${key}\"`).join(\", \");\n}\n\nfunction disallowedMessage(\n\tpath: string,\n\tkeys: string[],\n\tallowed: readonly string[],\n\texample?: string,\n): string {\n\tconst subject = keys.length === 1\n\t\t? `property \"${keys[0]}\" is not allowed`\n\t\t: `properties ${quoteList(keys)} are not allowed`;\n\tconst examplePart = example ? `\\n\\nExample: ${example}` : \"\";\n\treturn `subagent ${path}: ${subject}.\\nAllowed properties: ${allowed.join(\", \")}.${examplePart}`;\n}\n\nfunction expectObject(value: unknown, path: string, allowed: readonly string[], example?: string): asserts value is Record<string, unknown> {\n\tif (!isPlainObject(value)) {\n\t\tconst examplePart = example ? `\\n\\nExample: ${example}` : \"\";\n\t\tthrow new Error(\n\t\t\t`subagent ${path}: expected an object, received ${typeName(value)}.\\nAllowed properties: ${allowed.join(\", \")}.${examplePart}`,\n\t\t);\n\t}\n}\n\nfunction checkNoExtraKeys(\n\tvalue: Record<string, unknown>,\n\tpath: string,\n\tschema: ObjectSchema,\n\tallowed: readonly string[],\n\texample?: string,\n): void {\n\tif (schema.additionalProperties !== false) return;\n\tconst extra = disallowedKeys(value, allowed);\n\tif (extra.length > 0) {\n\t\tthrow new Error(disallowedMessage(path, extra, allowed, example));\n\t}\n}\n\n/**\n * Validates the `chain` array on a raw subagent tool-call argument object and\n * throws a friendly, actionable error when a chain step (or a nested\n * `parallel`/`expand`/`collect` object) has a disallowed property or wrong shape.\n *\n * No-op when `chain` is absent or not an array, so management/control/single/\n * parallel calls are unaffected.\n */\nexport function validateChainInput(args: unknown): void {\n\tif (!isPlainObject(args)) return;\n\tconst chain = (args as Record<string, unknown>).chain;\n\tif (!Array.isArray(chain)) return;\n\n\tchain.forEach((step, index) => {\n\t\tconst stepPath = `chain step validation failed at chain[${index}]`;\n\t\texpectObject(step, stepPath, CHAIN_STEP_KEYS, CHAIN_STEP_EXAMPLE);\n\t\tcheckNoExtraKeys(step, stepPath, ChainItem, CHAIN_STEP_KEYS, CHAIN_STEP_EXAMPLE);\n\n\t\tif (step.expand !== undefined) {\n\t\t\tconst expandPath = `${stepPath}.expand`;\n\t\t\texpectObject(step.expand, expandPath, EXPAND_KEYS, EXPAND_EXAMPLE);\n\t\t\tcheckNoExtraKeys(step.expand, expandPath, DynamicExpandSchema, EXPAND_KEYS, EXPAND_EXAMPLE);\n\n\t\t\tconst from = (step.expand as Record<string, unknown>).from;\n\t\t\tif (from !== undefined) {\n\t\t\t\tconst fromPath = `${expandPath}.from`;\n\t\t\t\texpectObject(from, fromPath, EXPAND_FROM_KEYS, EXPAND_FROM_EXAMPLE);\n\t\t\t\tcheckNoExtraKeys(from, fromPath, ExpandFromSchema, EXPAND_FROM_KEYS, EXPAND_FROM_EXAMPLE);\n\t\t\t}\n\t\t}\n\n\t\tif (step.collect !== undefined) {\n\t\t\tconst collectPath = `${stepPath}.collect`;\n\t\t\texpectObject(step.collect, collectPath, COLLECT_KEYS, COLLECT_EXAMPLE);\n\t\t\tcheckNoExtraKeys(step.collect, collectPath, DynamicCollectSchema, COLLECT_KEYS, COLLECT_EXAMPLE);\n\t\t}\n\n\t\tconst parallel = step.parallel;\n\t\tif (parallel === undefined) return;\n\n\t\tif (Array.isArray(parallel)) {\n\t\t\tparallel.forEach((task, pIndex) => {\n\t\t\t\tconst taskPath = `${stepPath}.parallel[${pIndex}]`;\n\t\t\t\texpectObject(task, taskPath, PARALLEL_TASK_KEYS, PARALLEL_TASK_EXAMPLE);\n\t\t\t\tcheckNoExtraKeys(task, taskPath, ParallelTaskSchema, PARALLEL_TASK_KEYS, PARALLEL_TASK_EXAMPLE);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (isPlainObject(parallel)) {\n\t\t\tconst templatePath = `${stepPath}.parallel (dynamic fanout template)`;\n\t\t\tcheckNoExtraKeys(parallel, templatePath, DynamicParallelTemplateSchema, DYNAMIC_TEMPLATE_KEYS, DYNAMIC_TEMPLATE_EXAMPLE);\n\t\t\treturn;\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t`subagent ${stepPath}.parallel: expected an array of task objects or a dynamic fanout template object, received ${typeName(parallel)}.\\n\\nExample static: [${PARALLEL_TASK_EXAMPLE}]\\nExample dynamic: ${DYNAMIC_TEMPLATE_EXAMPLE}`,\n\t\t);\n\t});\n}"]}
1
+ {"version":3,"file":"chain-validation.js","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-subagents/src/extension/chain-validation.ts"],"names":[],"mappings":"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","sourcesContent":["// @ts-nocheck\n/**\n * Friendly chain parameter validation.\n *\n * The runtime (pi-ai) validates tool arguments against the TypeBox schema before\n * the tool's `execute` runs. When a chain step has an extra property, the model\n * receives a raw TypeBox message such as `chain.1: must not have additional\n * properties` — which does not name the offending property, list the allowed\n * ones, or show the expected shape. Agents then iteratively guess the format and\n * waste several turns before getting it right.\n *\n * `validateChainInput` runs from the tool's `prepareArguments` shim (and the RPC\n * bridge) *before* schema validation. It throws a rich, actionable error for the\n * common chain-shape failures, so the model sees which property is disallowed,\n * what is allowed, and a valid example — instead of a raw TypeBox diagnostic.\n *\n * Allowed property names and additional-property strictness are derived directly\n * from the schema objects in `schemas.ts` so this stays aligned with TypeBox.\n */\n\nimport {\n\tChainItem,\n\tParallelTaskSchema,\n\tDynamicParallelTemplateSchema,\n\tDynamicExpandSchema,\n\tDynamicCollectSchema,\n} from \"./schemas.ts\";\n\ntype ObjectSchema = {\n\tproperties?: Record<string, unknown>;\n\tadditionalProperties?: unknown;\n};\n\nfunction allowedKeysOf(schema: ObjectSchema | undefined): string[] {\n\treturn schema?.properties ? Object.keys(schema.properties) : [];\n}\n\nconst ExpandFromSchema = (DynamicExpandSchema.properties?.from ?? {}) as ObjectSchema;\n\nexport const CHAIN_STEP_KEYS = allowedKeysOf(ChainItem);\nexport const PARALLEL_TASK_KEYS = allowedKeysOf(ParallelTaskSchema);\nexport const DYNAMIC_TEMPLATE_KEYS = allowedKeysOf(DynamicParallelTemplateSchema);\nexport const EXPAND_KEYS = allowedKeysOf(DynamicExpandSchema);\nexport const EXPAND_FROM_KEYS = allowedKeysOf(ExpandFromSchema);\nexport const COLLECT_KEYS = allowedKeysOf(DynamicCollectSchema);\n\nconst CHAIN_STEP_EXAMPLE = '{\"task\": \"do X\", \"description\": \"Do X\", \"permissions\": \"read-only\"}';\nconst PARALLEL_TASK_EXAMPLE = '{\"task\": \"do X\", \"description\": \"Do X\", \"permissions\": \"read-only\"}';\nconst DYNAMIC_TEMPLATE_EXAMPLE = '{\"task\": \"Review {item.path}\", \"description\": \"Review {item.path}\", \"permissions\": \"read-only\"}';\nconst EXPAND_EXAMPLE = '{\"from\": {\"output\": \"targets\", \"path\": \"/items\"}, \"maxItems\": 4}';\nconst EXPAND_FROM_EXAMPLE = '{\"output\": \"targets\", \"path\": \"/items\"}';\nconst COLLECT_EXAMPLE = '{\"as\": \"reviews\"}';\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction disallowedKeys(value: Record<string, unknown>, allowed: readonly string[]): string[] {\n\treturn Object.keys(value).filter((key) => !allowed.includes(key));\n}\n\nfunction typeName(value: unknown): string {\n\tif (Array.isArray(value)) return \"array\";\n\treturn typeof value;\n}\n\nfunction quoteList(keys: string[]): string {\n\treturn keys.map((key) => `\"${key}\"`).join(\", \");\n}\n\nfunction disallowedMessage(\n\tpath: string,\n\tkeys: string[],\n\tallowed: readonly string[],\n\texample?: string,\n): string {\n\tconst subject = keys.length === 1\n\t\t? `property \"${keys[0]}\" is not allowed`\n\t\t: `properties ${quoteList(keys)} are not allowed`;\n\tconst examplePart = example ? `\\n\\nExample: ${example}` : \"\";\n\treturn `subagent ${path}: ${subject}.\\nAllowed properties: ${allowed.join(\", \")}.${examplePart}`;\n}\n\nfunction expectObject(value: unknown, path: string, allowed: readonly string[], example?: string): asserts value is Record<string, unknown> {\n\tif (!isPlainObject(value)) {\n\t\tconst examplePart = example ? `\\n\\nExample: ${example}` : \"\";\n\t\tthrow new Error(\n\t\t\t`subagent ${path}: expected an object, received ${typeName(value)}.\\nAllowed properties: ${allowed.join(\", \")}.${examplePart}`,\n\t\t);\n\t}\n}\n\nfunction checkNoExtraKeys(\n\tvalue: Record<string, unknown>,\n\tpath: string,\n\tschema: ObjectSchema,\n\tallowed: readonly string[],\n\texample?: string,\n): void {\n\tif (schema.additionalProperties !== false) return;\n\tconst extra = disallowedKeys(value, allowed);\n\tif (extra.length > 0) {\n\t\tthrow new Error(disallowedMessage(path, extra, allowed, example));\n\t}\n}\n\n/**\n * Validates the `chain` array on a raw subagent tool-call argument object and\n * throws a friendly, actionable error when a chain step (or a nested\n * `parallel`/`expand`/`collect` object) has a disallowed property or wrong shape.\n *\n * No-op when `chain` is absent or not an array, so management/control/single/\n * parallel calls are unaffected.\n */\nexport function validateChainInput(args: unknown): void {\n\tif (!isPlainObject(args)) return;\n\tconst chain = (args as Record<string, unknown>).chain;\n\tif (!Array.isArray(chain)) return;\n\n\tchain.forEach((step, index) => {\n\t\tconst stepPath = `chain step validation failed at chain[${index}]`;\n\t\texpectObject(step, stepPath, CHAIN_STEP_KEYS, CHAIN_STEP_EXAMPLE);\n\t\tcheckNoExtraKeys(step, stepPath, ChainItem, CHAIN_STEP_KEYS, CHAIN_STEP_EXAMPLE);\n\n\t\tif (step.expand !== undefined) {\n\t\t\tconst expandPath = `${stepPath}.expand`;\n\t\t\texpectObject(step.expand, expandPath, EXPAND_KEYS, EXPAND_EXAMPLE);\n\t\t\tcheckNoExtraKeys(step.expand, expandPath, DynamicExpandSchema, EXPAND_KEYS, EXPAND_EXAMPLE);\n\n\t\t\tconst from = (step.expand as Record<string, unknown>).from;\n\t\t\tif (from !== undefined) {\n\t\t\t\tconst fromPath = `${expandPath}.from`;\n\t\t\t\texpectObject(from, fromPath, EXPAND_FROM_KEYS, EXPAND_FROM_EXAMPLE);\n\t\t\t\tcheckNoExtraKeys(from, fromPath, ExpandFromSchema, EXPAND_FROM_KEYS, EXPAND_FROM_EXAMPLE);\n\t\t\t}\n\t\t}\n\n\t\tif (step.collect !== undefined) {\n\t\t\tconst collectPath = `${stepPath}.collect`;\n\t\t\texpectObject(step.collect, collectPath, COLLECT_KEYS, COLLECT_EXAMPLE);\n\t\t\tcheckNoExtraKeys(step.collect, collectPath, DynamicCollectSchema, COLLECT_KEYS, COLLECT_EXAMPLE);\n\t\t}\n\n\t\tconst parallel = step.parallel;\n\t\tif (parallel === undefined) return;\n\n\t\tif (Array.isArray(parallel)) {\n\t\t\tparallel.forEach((task, pIndex) => {\n\t\t\t\tconst taskPath = `${stepPath}.parallel[${pIndex}]`;\n\t\t\t\texpectObject(task, taskPath, PARALLEL_TASK_KEYS, PARALLEL_TASK_EXAMPLE);\n\t\t\t\tcheckNoExtraKeys(task, taskPath, ParallelTaskSchema, PARALLEL_TASK_KEYS, PARALLEL_TASK_EXAMPLE);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (isPlainObject(parallel)) {\n\t\t\tconst templatePath = `${stepPath}.parallel (dynamic fanout template)`;\n\t\t\tcheckNoExtraKeys(parallel, templatePath, DynamicParallelTemplateSchema, DYNAMIC_TEMPLATE_KEYS, DYNAMIC_TEMPLATE_EXAMPLE);\n\t\t\treturn;\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t`subagent ${stepPath}.parallel: expected an array of task objects or a dynamic fanout template object, received ${typeName(parallel)}.\\n\\nExample static: [${PARALLEL_TASK_EXAMPLE}]\\nExample dynamic: ${DYNAMIC_TEMPLATE_EXAMPLE}`,\n\t\t);\n\t});\n}"]}
@@ -1,4 +1,3 @@
1
- import { discoverAgentsAll } from "../agents/agents.ts";
2
1
  import { diagnoseIntercomBridge } from "../intercom/intercom-bridge.ts";
3
2
  import { discoverAvailableSkills } from "../agents/skills.ts";
4
3
  import { type ExtensionConfig, type SubagentState } from "../shared/types.ts";
@@ -10,7 +9,6 @@ interface DoctorPaths {
10
9
  }
11
10
  interface DoctorDeps {
12
11
  isAsyncAvailable: () => boolean;
13
- discoverAgentsAll: typeof discoverAgentsAll;
14
12
  discoverAvailableSkills: typeof discoverAvailableSkills;
15
13
  diagnoseIntercomBridge: typeof diagnoseIntercomBridge;
16
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-subagents/src/extension/doctor.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAoB,MAAM,qBAAqB,CAAC;AAE1E,OAAO,EAAE,sBAAsB,EAAiC,MAAM,gCAAgC,CAAC;AACvG,OAAO,EAAE,uBAAuB,EAAoB,MAAM,qBAAqB,CAAC;AAChF,OAAO,EAKN,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,MAAM,oBAAoB,CAAC;AAE5B,UAAU,WAAW;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,UAAU;IACnB,gBAAgB,EAAE,MAAM,OAAO,CAAC;IAChC,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;CACtD;AAED,UAAU,iBAAiB;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;CAC3B;AA2ID,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAgClE","sourcesContent":["// @ts-nocheck\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { discoverAgentsAll, type AgentSource } from \"../agents/agents.ts\";\nimport { isAsyncAvailable } from \"../runs/background/async-execution.ts\";\nimport { diagnoseIntercomBridge, type IntercomBridgeDiagnostic } from \"../intercom/intercom-bridge.ts\";\nimport { discoverAvailableSkills, type SkillSource } from \"../agents/skills.ts\";\nimport {\n\tASYNC_DIR,\n\tCHAIN_RUNS_DIR,\n\tRESULTS_DIR,\n\tTEMP_ROOT_DIR,\n\ttype ExtensionConfig,\n\ttype SubagentState,\n} from \"../shared/types.ts\";\n\ninterface DoctorPaths {\n\ttempRootDir: string;\n\tasyncDir: string;\n\tresultsDir: string;\n\tchainRunsDir: string;\n}\n\ninterface DoctorDeps {\n\tisAsyncAvailable: () => boolean;\n\tdiscoverAgentsAll: typeof discoverAgentsAll;\n\tdiscoverAvailableSkills: typeof discoverAvailableSkills;\n\tdiagnoseIntercomBridge: typeof diagnoseIntercomBridge;\n}\n\ninterface DoctorReportInput {\n\tcwd: string;\n\tconfig: ExtensionConfig;\n\tstate: SubagentState;\n\tcontext?: \"fresh\" | \"fork\";\n\trequestedSessionDir?: string;\n\tcurrentSessionFile?: string | null;\n\tcurrentSessionId?: string | null;\n\torchestratorTarget?: string;\n\tsessionError?: string;\n\texpandTilde?: (value: string) => string;\n\tpaths?: DoctorPaths;\n\tdeps?: Partial<DoctorDeps>;\n}\n\nconst DEFAULT_PATHS: DoctorPaths = {\n\ttempRootDir: TEMP_ROOT_DIR,\n\tasyncDir: ASYNC_DIR,\n\tresultsDir: RESULTS_DIR,\n\tchainRunsDir: CHAIN_RUNS_DIR,\n};\n\nconst DEFAULT_DEPS: DoctorDeps = {\n\tisAsyncAvailable,\n\tdiscoverAgentsAll,\n\tdiscoverAvailableSkills,\n\tdiagnoseIntercomBridge,\n};\n\nfunction errorText(error: unknown): string {\n\treturn error instanceof Error ? `${error.name}: ${error.message}` : String(error);\n}\n\nfunction lineFromCheck(label: string, check: () => string): string {\n\ttry {\n\t\treturn check();\n\t} catch (error) {\n\t\treturn `- ${label}: failed — ${errorText(error)}`;\n\t}\n}\n\nfunction formatExistingDirectory(label: string, dirPath: string): string {\n\ttry {\n\t\tif (!fs.existsSync(dirPath)) return `- ${label}: missing (${dirPath})`;\n\t\tconst stats = fs.statSync(dirPath);\n\t\tif (!stats.isDirectory()) throw new Error(`not a directory: ${dirPath}`);\n\t\tfs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);\n\t\treturn `- ${label}: ok (${dirPath})`;\n\t} catch (error) {\n\t\treturn `- ${label}: failed (${dirPath}) — ${errorText(error)}`;\n\t}\n}\n\nfunction formatSourceCounts(counts: Record<AgentSource, number>): string {\n\treturn `builtin ${counts.builtin}, package ${counts.package}, user ${counts.user}, project ${counts.project}`;\n}\n\nfunction formatSkillSourceCounts(skills: Array<{ source: SkillSource }>): string {\n\tconst counts = new Map<SkillSource, number>();\n\tfor (const skill of skills) counts.set(skill.source, (counts.get(skill.source) ?? 0) + 1);\n\tconst ordered: SkillSource[] = [\n\t\t\"project\",\n\t\t\"project-settings\",\n\t\t\"project-package\",\n\t\t\"user\",\n\t\t\"user-settings\",\n\t\t\"user-package\",\n\t\t\"extension\",\n\t\t\"builtin\",\n\t\t\"unknown\",\n\t];\n\tconst parts = ordered\n\t\t.map((source) => `${source} ${counts.get(source) ?? 0}`)\n\t\t.filter((part) => !part.endsWith(\" 0\"));\n\treturn parts.length > 0 ? parts.join(\", \") : \"none\";\n}\n\nfunction formatConfiguredSessionDir(input: DoctorReportInput): string {\n\tif (input.requestedSessionDir) {\n\t\treturn path.resolve(input.expandTilde?.(input.requestedSessionDir) ?? input.requestedSessionDir);\n\t}\n\tif (input.config.defaultSessionDir) {\n\t\treturn path.resolve(input.expandTilde?.(input.config.defaultSessionDir) ?? input.config.defaultSessionDir);\n\t}\n\treturn \"not configured\";\n}\n\nfunction formatSessionLines(input: DoctorReportInput): string[] {\n\tconst sessionFile = input.currentSessionFile ?? null;\n\tconst lines = [\n\t\tlineFromCheck(\"configured session dir\", () => `- configured session dir: ${formatConfiguredSessionDir(input)}`),\n\t\t`- current session file: ${sessionFile ?? \"not available\"}`,\n\t\t`- current session dir: ${sessionFile ? path.dirname(sessionFile) : \"not available\"}`,\n\t\t`- current session id: ${input.currentSessionId ?? input.state.currentSessionId ?? \"not available\"}`,\n\t];\n\tif (input.sessionError) lines.push(`- session manager: failed — ${input.sessionError}`);\n\treturn lines;\n}\n\nfunction formatDiscovery(input: DoctorReportInput, deps: DoctorDeps): string[] {\n\treturn [\n\t\tlineFromCheck(\"agents/chains\", () => {\n\t\t\tconst discovered = deps.discoverAgentsAll(input.cwd);\n\t\t\tconst agentCounts = {\n\t\t\t\tbuiltin: discovered.builtin.length,\n\t\t\t\tpackage: discovered.package?.length ?? 0,\n\t\t\t\tuser: discovered.user.length,\n\t\t\t\tproject: discovered.project.length,\n\t\t\t};\n\t\t\tconst chainCounts = discovered.chains.reduce<Record<AgentSource, number>>((counts, chain) => {\n\t\t\t\tcounts[chain.source] += 1;\n\t\t\t\treturn counts;\n\t\t\t}, { builtin: 0, package: 0, user: 0, project: 0 });\n\t\t\treturn [\n\t\t\t\t`- agents: total ${agentCounts.builtin + agentCounts.package + agentCounts.user + agentCounts.project} (${formatSourceCounts(agentCounts)})`,\n\t\t\t\t`- chains: total ${discovered.chains.length} (${formatSourceCounts(chainCounts)})`,\n\t\t\t].join(\"\\n\");\n\t\t}),\n\t\tlineFromCheck(\"skills\", () => {\n\t\t\tconst skills = deps.discoverAvailableSkills(input.cwd);\n\t\t\treturn `- skills: total ${skills.length} (${formatSkillSourceCounts(skills)})`;\n\t\t}),\n\t];\n}\n\nfunction formatIntercomDiagnostic(diagnostic: IntercomBridgeDiagnostic, context: \"fresh\" | \"fork\" | undefined): string[] {\n\tconst lines = [\n\t\t`- bridge: ${diagnostic.active ? \"active\" : \"inactive\"}${diagnostic.reason ? ` (${diagnostic.reason})` : \"\"}`,\n\t\t`- mode: ${diagnostic.mode}; context: ${context ?? \"unspecified\"}`,\n\t\t`- orchestrator target: ${diagnostic.orchestratorTarget ?? \"not available\"}`,\n\t\t`- supervisor channel: ${diagnostic.supervisorChannelAvailable ? \"available\" : \"unavailable\"} (${diagnostic.extensionDir})`,\n\t];\n\treturn lines;\n}\n\nfunction formatPermissionSystemSection(): string[] {\n\tconst lines: string[] = [];\n\tconst parentSession = process.env[\"PI_SUBAGENT_PARENT_SESSION\"] ?? \"\";\n\tconst trimmed = parentSession.trim();\n\tif (trimmed) {\n\t\tlines.push(`- parent session: set (${trimmed})`);\n\t} else {\n\t\tlines.push(\"- parent session: not set — ask forwarding from subprocess children will not reach a parent UI\");\n\t}\n\tconst isChild = process.env[\"PI_SUBAGENT_CHILD\"] === \"1\";\n\tlines.push(`- subagent process: ${isChild ? \"yes (PI_SUBAGENT_CHILD=1)\" : \"no\"}`);\n\t// Whether pi-permission-system is installed and where it stores config is\n\t// outside pi-subagents' control, so we only report the forwarding signal we\n\t// own. Run `pi list` to confirm the permission extension is installed.\n\treturn lines;\n}\n\nexport function buildDoctorReport(input: DoctorReportInput): string {\n\tconst paths = input.paths ?? DEFAULT_PATHS;\n\tconst deps = { ...DEFAULT_DEPS, ...input.deps };\n\tconst lines = [\n\t\t\"Subagents doctor report\",\n\t\t\"\",\n\t\t\"Runtime\",\n\t\t`- cwd: ${input.cwd}`,\n\t\tlineFromCheck(\"async support\", () => `- async support: ${deps.isAsyncAvailable() ? \"available\" : \"unavailable\"}`),\n\t\t...formatSessionLines(input),\n\t\t\"\",\n\t\t\"Filesystem\",\n\t\tformatExistingDirectory(\"temp root\", paths.tempRootDir),\n\t\tformatExistingDirectory(\"async runs\", paths.asyncDir),\n\t\tformatExistingDirectory(\"results\", paths.resultsDir),\n\t\tformatExistingDirectory(\"chain runs\", paths.chainRunsDir),\n\t\t\"\",\n\t\t\"Discovery\",\n\t\t...formatDiscovery(input, deps),\n\t\t\"\",\n\t\t\"Permission system\",\n\t\t...formatPermissionSystemSection(),\n\t\t\"\",\n\t\t\"Intercom bridge\",\n\t\t...lineFromCheck(\"intercom bridge\", () => formatIntercomDiagnostic(deps.diagnoseIntercomBridge({\n\t\t\tconfig: input.config.intercomBridge,\n\t\t\tcontext: input.context,\n\t\t\torchestratorTarget: input.orchestratorTarget,\n\t\t\tcwd: input.cwd,\n\t\t}), input.context).join(\"\\n\")).split(\"\\n\"),\n\t];\n\treturn lines.join(\"\\n\");\n}\n"]}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-subagents/src/extension/doctor.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,sBAAsB,EAAiC,MAAM,gCAAgC,CAAC;AACvG,OAAO,EAAE,uBAAuB,EAAoB,MAAM,qBAAqB,CAAC;AAChF,OAAO,EAKN,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,MAAM,oBAAoB,CAAC;AAE5B,UAAU,WAAW;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,UAAU;IACnB,gBAAgB,EAAE,MAAM,OAAO,CAAC;IAChC,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;CACtD;AAED,UAAU,iBAAiB;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;CAC3B;AAqHD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAgClE","sourcesContent":["// @ts-nocheck\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { isAsyncAvailable } from \"../runs/background/async-execution.ts\";\nimport { diagnoseIntercomBridge, type IntercomBridgeDiagnostic } from \"../intercom/intercom-bridge.ts\";\nimport { discoverAvailableSkills, type SkillSource } from \"../agents/skills.ts\";\nimport {\n\tASYNC_DIR,\n\tCHAIN_RUNS_DIR,\n\tRESULTS_DIR,\n\tTEMP_ROOT_DIR,\n\ttype ExtensionConfig,\n\ttype SubagentState,\n} from \"../shared/types.ts\";\n\ninterface DoctorPaths {\n\ttempRootDir: string;\n\tasyncDir: string;\n\tresultsDir: string;\n\tchainRunsDir: string;\n}\n\ninterface DoctorDeps {\n\tisAsyncAvailable: () => boolean;\n\tdiscoverAvailableSkills: typeof discoverAvailableSkills;\n\tdiagnoseIntercomBridge: typeof diagnoseIntercomBridge;\n}\n\ninterface DoctorReportInput {\n\tcwd: string;\n\tconfig: ExtensionConfig;\n\tstate: SubagentState;\n\tcontext?: \"fresh\" | \"fork\";\n\trequestedSessionDir?: string;\n\tcurrentSessionFile?: string | null;\n\tcurrentSessionId?: string | null;\n\torchestratorTarget?: string;\n\tsessionError?: string;\n\texpandTilde?: (value: string) => string;\n\tpaths?: DoctorPaths;\n\tdeps?: Partial<DoctorDeps>;\n}\n\nconst DEFAULT_PATHS: DoctorPaths = {\n\ttempRootDir: TEMP_ROOT_DIR,\n\tasyncDir: ASYNC_DIR,\n\tresultsDir: RESULTS_DIR,\n\tchainRunsDir: CHAIN_RUNS_DIR,\n};\n\nconst DEFAULT_DEPS: DoctorDeps = {\n\tisAsyncAvailable,\n\tdiscoverAvailableSkills,\n\tdiagnoseIntercomBridge,\n};\n\nfunction errorText(error: unknown): string {\n\treturn error instanceof Error ? `${error.name}: ${error.message}` : String(error);\n}\n\nfunction lineFromCheck(label: string, check: () => string): string {\n\ttry {\n\t\treturn check();\n\t} catch (error) {\n\t\treturn `- ${label}: failed — ${errorText(error)}`;\n\t}\n}\n\nfunction formatExistingDirectory(label: string, dirPath: string): string {\n\ttry {\n\t\tif (!fs.existsSync(dirPath)) return `- ${label}: missing (${dirPath})`;\n\t\tconst stats = fs.statSync(dirPath);\n\t\tif (!stats.isDirectory()) throw new Error(`not a directory: ${dirPath}`);\n\t\tfs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);\n\t\treturn `- ${label}: ok (${dirPath})`;\n\t} catch (error) {\n\t\treturn `- ${label}: failed (${dirPath}) — ${errorText(error)}`;\n\t}\n}\n\nfunction formatSkillSourceCounts(skills: Array<{ source: SkillSource }>): string {\n\tconst counts = new Map<SkillSource, number>();\n\tfor (const skill of skills) counts.set(skill.source, (counts.get(skill.source) ?? 0) + 1);\n\tconst ordered: SkillSource[] = [\n\t\t\"project\",\n\t\t\"project-settings\",\n\t\t\"project-package\",\n\t\t\"user\",\n\t\t\"user-settings\",\n\t\t\"user-package\",\n\t\t\"extension\",\n\t\t\"builtin\",\n\t\t\"unknown\",\n\t];\n\tconst parts = ordered\n\t\t.map((source) => `${source} ${counts.get(source) ?? 0}`)\n\t\t.filter((part) => !part.endsWith(\" 0\"));\n\treturn parts.length > 0 ? parts.join(\", \") : \"none\";\n}\n\nfunction formatConfiguredSessionDir(input: DoctorReportInput): string {\n\tif (input.requestedSessionDir) {\n\t\treturn path.resolve(input.expandTilde?.(input.requestedSessionDir) ?? input.requestedSessionDir);\n\t}\n\tif (input.config.defaultSessionDir) {\n\t\treturn path.resolve(input.expandTilde?.(input.config.defaultSessionDir) ?? input.config.defaultSessionDir);\n\t}\n\treturn \"not configured\";\n}\n\nfunction formatSessionLines(input: DoctorReportInput): string[] {\n\tconst sessionFile = input.currentSessionFile ?? null;\n\tconst lines = [\n\t\tlineFromCheck(\"configured session dir\", () => `- configured session dir: ${formatConfiguredSessionDir(input)}`),\n\t\t`- current session file: ${sessionFile ?? \"not available\"}`,\n\t\t`- current session dir: ${sessionFile ? path.dirname(sessionFile) : \"not available\"}`,\n\t\t`- current session id: ${input.currentSessionId ?? input.state.currentSessionId ?? \"not available\"}`,\n\t];\n\tif (input.sessionError) lines.push(`- session manager: failed — ${input.sessionError}`);\n\treturn lines;\n}\n\nfunction formatDiscovery(input: DoctorReportInput, deps: DoctorDeps): string[] {\n\treturn [\n\t\tlineFromCheck(\"skills\", () => {\n\t\t\tconst skills = deps.discoverAvailableSkills(input.cwd);\n\t\t\treturn `- skills: total ${skills.length} (${formatSkillSourceCounts(skills)})`;\n\t\t}),\n\t];\n}\n\nfunction formatIntercomDiagnostic(diagnostic: IntercomBridgeDiagnostic, context: \"fresh\" | \"fork\" | undefined): string[] {\n\tconst lines = [\n\t\t`- bridge: ${diagnostic.active ? \"active\" : \"inactive\"}${diagnostic.reason ? ` (${diagnostic.reason})` : \"\"}`,\n\t\t`- mode: ${diagnostic.mode}; context: ${context ?? \"unspecified\"}`,\n\t\t`- orchestrator target: ${diagnostic.orchestratorTarget ?? \"not available\"}`,\n\t\t`- supervisor channel: ${diagnostic.supervisorChannelAvailable ? \"available\" : \"unavailable\"} (${diagnostic.extensionDir})`,\n\t];\n\treturn lines;\n}\n\nfunction formatPermissionSystemSection(): string[] {\n\tconst lines: string[] = [];\n\tconst parentSession = process.env[\"PI_SUBAGENT_PARENT_SESSION\"] ?? \"\";\n\tconst trimmed = parentSession.trim();\n\tif (trimmed) {\n\t\tlines.push(`- parent session: set (${trimmed})`);\n\t} else {\n\t\tlines.push(\"- parent session: not set — ask forwarding from subprocess children will not reach a parent UI\");\n\t}\n\tconst isChild = process.env[\"PI_SUBAGENT_CHILD\"] === \"1\";\n\tlines.push(`- subagent process: ${isChild ? \"yes (PI_SUBAGENT_CHILD=1)\" : \"no\"}`);\n\t// Whether pi-permission-system is installed and where it stores config is\n\t// outside pi-subagents' control, so we only report the forwarding signal we\n\t// own. Run `pi list` to confirm the permission extension is installed.\n\treturn lines;\n}\n\nexport function buildDoctorReport(input: DoctorReportInput): string {\n\tconst paths = input.paths ?? DEFAULT_PATHS;\n\tconst deps = { ...DEFAULT_DEPS, ...input.deps };\n\tconst lines = [\n\t\t\"Subagents doctor report\",\n\t\t\"\",\n\t\t\"Runtime\",\n\t\t`- cwd: ${input.cwd}`,\n\t\tlineFromCheck(\"async support\", () => `- async support: ${deps.isAsyncAvailable() ? \"available\" : \"unavailable\"}`),\n\t\t...formatSessionLines(input),\n\t\t\"\",\n\t\t\"Filesystem\",\n\t\tformatExistingDirectory(\"temp root\", paths.tempRootDir),\n\t\tformatExistingDirectory(\"async runs\", paths.asyncDir),\n\t\tformatExistingDirectory(\"results\", paths.resultsDir),\n\t\tformatExistingDirectory(\"chain runs\", paths.chainRunsDir),\n\t\t\"\",\n\t\t\"Capabilities\",\n\t\t...formatDiscovery(input, deps),\n\t\t\"\",\n\t\t\"Permission system\",\n\t\t...formatPermissionSystemSection(),\n\t\t\"\",\n\t\t\"Intercom bridge\",\n\t\t...lineFromCheck(\"intercom bridge\", () => formatIntercomDiagnostic(deps.diagnoseIntercomBridge({\n\t\t\tconfig: input.config.intercomBridge,\n\t\t\tcontext: input.context,\n\t\t\torchestratorTarget: input.orchestratorTarget,\n\t\t\tcwd: input.cwd,\n\t\t}), input.context).join(\"\\n\")).split(\"\\n\"),\n\t];\n\treturn lines.join(\"\\n\");\n}\n"]}
@@ -1,7 +1,6 @@
1
1
  // @ts-nocheck
2
2
  import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
- import { discoverAgentsAll } from "../agents/agents.js";
5
4
  import { isAsyncAvailable } from "../runs/background/async-execution.js";
6
5
  import { diagnoseIntercomBridge } from "../intercom/intercom-bridge.js";
7
6
  import { discoverAvailableSkills } from "../agents/skills.js";
@@ -14,7 +13,6 @@ const DEFAULT_PATHS = {
14
13
  };
15
14
  const DEFAULT_DEPS = {
16
15
  isAsyncAvailable,
17
- discoverAgentsAll,
18
16
  discoverAvailableSkills,
19
17
  diagnoseIntercomBridge,
20
18
  };
@@ -43,9 +41,6 @@ function formatExistingDirectory(label, dirPath) {
43
41
  return `- ${label}: failed (${dirPath}) — ${errorText(error)}`;
44
42
  }
45
43
  }
46
- function formatSourceCounts(counts) {
47
- return `builtin ${counts.builtin}, package ${counts.package}, user ${counts.user}, project ${counts.project}`;
48
- }
49
44
  function formatSkillSourceCounts(skills) {
50
45
  const counts = new Map();
51
46
  for (const skill of skills)
@@ -89,23 +84,6 @@ function formatSessionLines(input) {
89
84
  }
90
85
  function formatDiscovery(input, deps) {
91
86
  return [
92
- lineFromCheck("agents/chains", () => {
93
- const discovered = deps.discoverAgentsAll(input.cwd);
94
- const agentCounts = {
95
- builtin: discovered.builtin.length,
96
- package: discovered.package?.length ?? 0,
97
- user: discovered.user.length,
98
- project: discovered.project.length,
99
- };
100
- const chainCounts = discovered.chains.reduce((counts, chain) => {
101
- counts[chain.source] += 1;
102
- return counts;
103
- }, { builtin: 0, package: 0, user: 0, project: 0 });
104
- return [
105
- `- agents: total ${agentCounts.builtin + agentCounts.package + agentCounts.user + agentCounts.project} (${formatSourceCounts(agentCounts)})`,
106
- `- chains: total ${discovered.chains.length} (${formatSourceCounts(chainCounts)})`,
107
- ].join("\n");
108
- }),
109
87
  lineFromCheck("skills", () => {
110
88
  const skills = deps.discoverAvailableSkills(input.cwd);
111
89
  return `- skills: total ${skills.length} (${formatSkillSourceCounts(skills)})`;
@@ -155,7 +133,7 @@ export function buildDoctorReport(input) {
155
133
  formatExistingDirectory("results", paths.resultsDir),
156
134
  formatExistingDirectory("chain runs", paths.chainRunsDir),
157
135
  "",
158
- "Discovery",
136
+ "Capabilities",
159
137
  ...formatDiscovery(input, deps),
160
138
  "",
161
139
  "Permission system",