@esso0428/pi-subagents 0.17.16 → 0.17.17

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 (359) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/ROADMAP.md +87 -0
  3. package/docs/post-0.17.6-agents-roster-viewer-spec.md +42 -0
  4. package/docs/post-0.17.6-durable-history-spec.md +41 -0
  5. package/docs/post-0.17.6-feature-specs.md +50 -0
  6. package/docs/post-0.17.6-nested-agents-spec.md +38 -0
  7. package/docs/post-0.17.6-recovery-shutdown-spec.md +46 -0
  8. package/docs/post-0.17.6-ui-latency-baseline-spec.md +46 -0
  9. package/docs/post-0.17.6-workflow-rpc-lifecycle-spec.md +54 -0
  10. package/package.json +1 -1
  11. package/src/agent-history.ts +2 -54
  12. package/src/agent-manager.ts +406 -1288
  13. package/src/agent-runner.ts +27 -251
  14. package/src/agent-types.ts +32 -188
  15. package/src/cross-extension-rpc.ts +20 -96
  16. package/src/custom-agents.ts +13 -170
  17. package/src/index.ts +480 -1920
  18. package/src/invocation-config.ts +3 -118
  19. package/src/model-resolver.ts +0 -18
  20. package/src/output-file.ts +6 -61
  21. package/src/prompts.ts +2 -45
  22. package/src/schedule.ts +14 -35
  23. package/src/settings.ts +2 -301
  24. package/src/status-note.ts +1 -66
  25. package/src/types.ts +10 -177
  26. package/src/ui/agent-widget.ts +57 -278
  27. package/src/ui/conversation-blocks.ts +0 -6
  28. package/src/ui/conversation-timeline.ts +25 -139
  29. package/src/ui/conversation-viewer.ts +48 -212
  30. package/src/ui/schedule-menu.ts +8 -9
  31. package/src/usage.ts +2 -109
  32. package/src/worktree.ts +55 -69
  33. package/dist/abortable.d.ts +0 -13
  34. package/dist/abortable.d.ts.map +0 -1
  35. package/dist/abortable.js +0 -43
  36. package/dist/abortable.js.map +0 -1
  37. package/dist/agent-color.d.ts +0 -36
  38. package/dist/agent-color.d.ts.map +0 -1
  39. package/dist/agent-color.js +0 -124
  40. package/dist/agent-color.js.map +0 -1
  41. package/dist/agent-file-toggle.d.ts +0 -126
  42. package/dist/agent-file-toggle.d.ts.map +0 -1
  43. package/dist/agent-file-toggle.js +0 -259
  44. package/dist/agent-file-toggle.js.map +0 -1
  45. package/dist/agent-history-list.d.ts +0 -19
  46. package/dist/agent-history-list.d.ts.map +0 -1
  47. package/dist/agent-history-list.js +0 -69
  48. package/dist/agent-history-list.js.map +0 -1
  49. package/dist/agent-history.d.ts +0 -35
  50. package/dist/agent-history.d.ts.map +0 -1
  51. package/dist/agent-history.js +0 -188
  52. package/dist/agent-history.js.map +0 -1
  53. package/dist/agent-manager.d.ts +0 -503
  54. package/dist/agent-manager.d.ts.map +0 -1
  55. package/dist/agent-manager.js +0 -1572
  56. package/dist/agent-manager.js.map +0 -1
  57. package/dist/agent-recovery.d.ts +0 -37
  58. package/dist/agent-recovery.d.ts.map +0 -1
  59. package/dist/agent-recovery.js +0 -171
  60. package/dist/agent-recovery.js.map +0 -1
  61. package/dist/agent-runner.d.ts +0 -303
  62. package/dist/agent-runner.d.ts.map +0 -1
  63. package/dist/agent-runner.js +0 -1003
  64. package/dist/agent-runner.js.map +0 -1
  65. package/dist/agent-types.d.ts +0 -120
  66. package/dist/agent-types.d.ts.map +0 -1
  67. package/dist/agent-types.js +0 -301
  68. package/dist/agent-types.js.map +0 -1
  69. package/dist/child-context.d.ts +0 -3
  70. package/dist/child-context.d.ts.map +0 -1
  71. package/dist/child-context.js +0 -13
  72. package/dist/child-context.js.map +0 -1
  73. package/dist/context.d.ts +0 -13
  74. package/dist/context.d.ts.map +0 -1
  75. package/dist/context.js +0 -57
  76. package/dist/context.js.map +0 -1
  77. package/dist/cross-extension-rpc.d.ts +0 -67
  78. package/dist/cross-extension-rpc.d.ts.map +0 -1
  79. package/dist/cross-extension-rpc.js +0 -139
  80. package/dist/cross-extension-rpc.js.map +0 -1
  81. package/dist/custom-agents.d.ts +0 -55
  82. package/dist/custom-agents.d.ts.map +0 -1
  83. package/dist/custom-agents.js +0 -309
  84. package/dist/custom-agents.js.map +0 -1
  85. package/dist/default-agents.d.ts +0 -8
  86. package/dist/default-agents.d.ts.map +0 -1
  87. package/dist/default-agents.js +0 -123
  88. package/dist/default-agents.js.map +0 -1
  89. package/dist/enabled-models.d.ts +0 -50
  90. package/dist/enabled-models.d.ts.map +0 -1
  91. package/dist/enabled-models.js +0 -146
  92. package/dist/enabled-models.js.map +0 -1
  93. package/dist/env.d.ts +0 -7
  94. package/dist/env.d.ts.map +0 -1
  95. package/dist/env.js +0 -29
  96. package/dist/env.js.map +0 -1
  97. package/dist/group-join.d.ts +0 -33
  98. package/dist/group-join.d.ts.map +0 -1
  99. package/dist/group-join.js +0 -117
  100. package/dist/group-join.js.map +0 -1
  101. package/dist/index.d.ts +0 -51
  102. package/dist/index.d.ts.map +0 -1
  103. package/dist/index.js +0 -3687
  104. package/dist/index.js.map +0 -1
  105. package/dist/invocation-config.d.ts +0 -108
  106. package/dist/invocation-config.d.ts.map +0 -1
  107. package/dist/invocation-config.js +0 -84
  108. package/dist/invocation-config.js.map +0 -1
  109. package/dist/memory.d.ts +0 -54
  110. package/dist/memory.d.ts.map +0 -1
  111. package/dist/memory.js +0 -166
  112. package/dist/memory.js.map +0 -1
  113. package/dist/mention-clone.d.ts +0 -88
  114. package/dist/mention-clone.d.ts.map +0 -1
  115. package/dist/mention-clone.js +0 -154
  116. package/dist/mention-clone.js.map +0 -1
  117. package/dist/mention.d.ts +0 -82
  118. package/dist/mention.d.ts.map +0 -1
  119. package/dist/mention.js +0 -132
  120. package/dist/mention.js.map +0 -1
  121. package/dist/model-resolver.d.ts +0 -37
  122. package/dist/model-resolver.d.ts.map +0 -1
  123. package/dist/model-resolver.js +0 -96
  124. package/dist/model-resolver.js.map +0 -1
  125. package/dist/model-scope.d.ts +0 -50
  126. package/dist/model-scope.d.ts.map +0 -1
  127. package/dist/model-scope.js +0 -49
  128. package/dist/model-scope.js.map +0 -1
  129. package/dist/nested-tools.d.ts +0 -57
  130. package/dist/nested-tools.d.ts.map +0 -1
  131. package/dist/nested-tools.js +0 -301
  132. package/dist/nested-tools.js.map +0 -1
  133. package/dist/nico-overrides.d.ts +0 -54
  134. package/dist/nico-overrides.d.ts.map +0 -1
  135. package/dist/nico-overrides.js +0 -170
  136. package/dist/nico-overrides.js.map +0 -1
  137. package/dist/output-file.d.ts +0 -44
  138. package/dist/output-file.d.ts.map +0 -1
  139. package/dist/output-file.js +0 -156
  140. package/dist/output-file.js.map +0 -1
  141. package/dist/prompts.d.ts +0 -56
  142. package/dist/prompts.d.ts.map +0 -1
  143. package/dist/prompts.js +0 -92
  144. package/dist/prompts.js.map +0 -1
  145. package/dist/schedule-store.d.ts +0 -39
  146. package/dist/schedule-store.d.ts.map +0 -1
  147. package/dist/schedule-store.js +0 -156
  148. package/dist/schedule-store.js.map +0 -1
  149. package/dist/schedule.d.ts +0 -110
  150. package/dist/schedule.d.ts.map +0 -1
  151. package/dist/schedule.js +0 -360
  152. package/dist/schedule.js.map +0 -1
  153. package/dist/settings.d.ts +0 -354
  154. package/dist/settings.d.ts.map +0 -1
  155. package/dist/settings.js +0 -247
  156. package/dist/settings.js.map +0 -1
  157. package/dist/skill-loader.d.ts +0 -25
  158. package/dist/skill-loader.d.ts.map +0 -1
  159. package/dist/skill-loader.js +0 -94
  160. package/dist/skill-loader.js.map +0 -1
  161. package/dist/status-note.d.ts +0 -62
  162. package/dist/status-note.d.ts.map +0 -1
  163. package/dist/status-note.js +0 -86
  164. package/dist/status-note.js.map +0 -1
  165. package/dist/structured-output.d.ts +0 -62
  166. package/dist/structured-output.d.ts.map +0 -1
  167. package/dist/structured-output.js +0 -113
  168. package/dist/structured-output.js.map +0 -1
  169. package/dist/types.d.ts +0 -372
  170. package/dist/types.d.ts.map +0 -1
  171. package/dist/types.js +0 -6
  172. package/dist/types.js.map +0 -1
  173. package/dist/ui/agent-mention.d.ts +0 -83
  174. package/dist/ui/agent-mention.d.ts.map +0 -1
  175. package/dist/ui/agent-mention.js +0 -188
  176. package/dist/ui/agent-mention.js.map +0 -1
  177. package/dist/ui/agent-widget.d.ts +0 -241
  178. package/dist/ui/agent-widget.d.ts.map +0 -1
  179. package/dist/ui/agent-widget.js +0 -992
  180. package/dist/ui/agent-widget.js.map +0 -1
  181. package/dist/ui/ccstyle/diff/ansi-utils.d.ts +0 -11
  182. package/dist/ui/ccstyle/diff/ansi-utils.d.ts.map +0 -1
  183. package/dist/ui/ccstyle/diff/ansi-utils.js +0 -145
  184. package/dist/ui/ccstyle/diff/ansi-utils.js.map +0 -1
  185. package/dist/ui/ccstyle/diff/diff-presentation.d.ts +0 -12
  186. package/dist/ui/ccstyle/diff/diff-presentation.d.ts.map +0 -1
  187. package/dist/ui/ccstyle/diff/diff-presentation.js +0 -48
  188. package/dist/ui/ccstyle/diff/diff-presentation.js.map +0 -1
  189. package/dist/ui/ccstyle/diff/diff-renderer.d.ts +0 -46
  190. package/dist/ui/ccstyle/diff/diff-renderer.d.ts.map +0 -1
  191. package/dist/ui/ccstyle/diff/diff-renderer.js +0 -2049
  192. package/dist/ui/ccstyle/diff/diff-renderer.js.map +0 -1
  193. package/dist/ui/ccstyle/diff/line-width-safety.d.ts +0 -12
  194. package/dist/ui/ccstyle/diff/line-width-safety.d.ts.map +0 -1
  195. package/dist/ui/ccstyle/diff/line-width-safety.js +0 -58
  196. package/dist/ui/ccstyle/diff/line-width-safety.js.map +0 -1
  197. package/dist/ui/ccstyle/diff/render-utils.d.ts +0 -6
  198. package/dist/ui/ccstyle/diff/render-utils.d.ts.map +0 -1
  199. package/dist/ui/ccstyle/diff/render-utils.js +0 -25
  200. package/dist/ui/ccstyle/diff/render-utils.js.map +0 -1
  201. package/dist/ui/ccstyle/diff/shiki-highlight.d.ts +0 -19
  202. package/dist/ui/ccstyle/diff/shiki-highlight.d.ts.map +0 -1
  203. package/dist/ui/ccstyle/diff/shiki-highlight.js +0 -85
  204. package/dist/ui/ccstyle/diff/shiki-highlight.js.map +0 -1
  205. package/dist/ui/ccstyle/diff/types.d.ts +0 -22
  206. package/dist/ui/ccstyle/diff/types.d.ts.map +0 -1
  207. package/dist/ui/ccstyle/diff/types.js +0 -10
  208. package/dist/ui/ccstyle/diff/types.js.map +0 -1
  209. package/dist/ui/ccstyle/diff/write-display-utils.d.ts +0 -2
  210. package/dist/ui/ccstyle/diff/write-display-utils.d.ts.map +0 -1
  211. package/dist/ui/ccstyle/diff/write-display-utils.js +0 -12
  212. package/dist/ui/ccstyle/diff/write-display-utils.js.map +0 -1
  213. package/dist/ui/ccstyle/tool-renderer.d.ts +0 -17
  214. package/dist/ui/ccstyle/tool-renderer.d.ts.map +0 -1
  215. package/dist/ui/ccstyle/tool-renderer.js +0 -74
  216. package/dist/ui/ccstyle/tool-renderer.js.map +0 -1
  217. package/dist/ui/ccstyle/tool-result.d.ts +0 -44
  218. package/dist/ui/ccstyle/tool-result.d.ts.map +0 -1
  219. package/dist/ui/ccstyle/tool-result.js +0 -423
  220. package/dist/ui/ccstyle/tool-result.js.map +0 -1
  221. package/dist/ui/conversation-blocks.d.ts +0 -46
  222. package/dist/ui/conversation-blocks.d.ts.map +0 -1
  223. package/dist/ui/conversation-blocks.js +0 -313
  224. package/dist/ui/conversation-blocks.js.map +0 -1
  225. package/dist/ui/conversation-nvim.d.ts +0 -8
  226. package/dist/ui/conversation-nvim.d.ts.map +0 -1
  227. package/dist/ui/conversation-nvim.js +0 -117
  228. package/dist/ui/conversation-nvim.js.map +0 -1
  229. package/dist/ui/conversation-role.d.ts +0 -13
  230. package/dist/ui/conversation-role.d.ts.map +0 -1
  231. package/dist/ui/conversation-role.js +0 -39
  232. package/dist/ui/conversation-role.js.map +0 -1
  233. package/dist/ui/conversation-search.d.ts +0 -39
  234. package/dist/ui/conversation-search.d.ts.map +0 -1
  235. package/dist/ui/conversation-search.js +0 -124
  236. package/dist/ui/conversation-search.js.map +0 -1
  237. package/dist/ui/conversation-timeline.d.ts +0 -102
  238. package/dist/ui/conversation-timeline.d.ts.map +0 -1
  239. package/dist/ui/conversation-timeline.js +0 -555
  240. package/dist/ui/conversation-timeline.js.map +0 -1
  241. package/dist/ui/conversation-viewer.d.ts +0 -138
  242. package/dist/ui/conversation-viewer.d.ts.map +0 -1
  243. package/dist/ui/conversation-viewer.js +0 -1175
  244. package/dist/ui/conversation-viewer.js.map +0 -1
  245. package/dist/ui/schedule-menu.d.ts +0 -17
  246. package/dist/ui/schedule-menu.d.ts.map +0 -1
  247. package/dist/ui/schedule-menu.js +0 -95
  248. package/dist/ui/schedule-menu.js.map +0 -1
  249. package/dist/ui/select-item.d.ts +0 -28
  250. package/dist/ui/select-item.d.ts.map +0 -1
  251. package/dist/ui/select-item.js +0 -35
  252. package/dist/ui/select-item.js.map +0 -1
  253. package/dist/ui/viewer-keys.d.ts +0 -21
  254. package/dist/ui/viewer-keys.d.ts.map +0 -1
  255. package/dist/ui/viewer-keys.js +0 -18
  256. package/dist/ui/viewer-keys.js.map +0 -1
  257. package/dist/ui/workflow-card.d.ts +0 -176
  258. package/dist/ui/workflow-card.d.ts.map +0 -1
  259. package/dist/ui/workflow-card.js +0 -333
  260. package/dist/ui/workflow-card.js.map +0 -1
  261. package/dist/ui/workflow-dialog.d.ts +0 -306
  262. package/dist/ui/workflow-dialog.d.ts.map +0 -1
  263. package/dist/ui/workflow-dialog.js +0 -844
  264. package/dist/ui/workflow-dialog.js.map +0 -1
  265. package/dist/ui/workflow-menu.d.ts +0 -42
  266. package/dist/ui/workflow-menu.d.ts.map +0 -1
  267. package/dist/ui/workflow-menu.js +0 -127
  268. package/dist/ui/workflow-menu.js.map +0 -1
  269. package/dist/usage.d.ts +0 -136
  270. package/dist/usage.d.ts.map +0 -1
  271. package/dist/usage.js +0 -121
  272. package/dist/usage.js.map +0 -1
  273. package/dist/workflow/collisions.d.ts +0 -96
  274. package/dist/workflow/collisions.d.ts.map +0 -1
  275. package/dist/workflow/collisions.js +0 -89
  276. package/dist/workflow/collisions.js.map +0 -1
  277. package/dist/workflow/entry.d.ts +0 -33
  278. package/dist/workflow/entry.d.ts.map +0 -1
  279. package/dist/workflow/entry.js +0 -30
  280. package/dist/workflow/entry.js.map +0 -1
  281. package/dist/workflow/host.d.ts +0 -63
  282. package/dist/workflow/host.d.ts.map +0 -1
  283. package/dist/workflow/host.js +0 -363
  284. package/dist/workflow/host.js.map +0 -1
  285. package/dist/workflow/journal.d.ts +0 -98
  286. package/dist/workflow/journal.d.ts.map +0 -1
  287. package/dist/workflow/journal.js +0 -121
  288. package/dist/workflow/journal.js.map +0 -1
  289. package/dist/workflow/json-schema.d.ts +0 -52
  290. package/dist/workflow/json-schema.d.ts.map +0 -1
  291. package/dist/workflow/json-schema.js +0 -112
  292. package/dist/workflow/json-schema.js.map +0 -1
  293. package/dist/workflow/meta.d.ts +0 -68
  294. package/dist/workflow/meta.d.ts.map +0 -1
  295. package/dist/workflow/meta.js +0 -318
  296. package/dist/workflow/meta.js.map +0 -1
  297. package/dist/workflow/progress.d.ts +0 -225
  298. package/dist/workflow/progress.d.ts.map +0 -1
  299. package/dist/workflow/progress.js +0 -362
  300. package/dist/workflow/progress.js.map +0 -1
  301. package/dist/workflow/runtime.d.ts +0 -335
  302. package/dist/workflow/runtime.d.ts.map +0 -1
  303. package/dist/workflow/runtime.js +0 -831
  304. package/dist/workflow/runtime.js.map +0 -1
  305. package/dist/workflow/saved.d.ts +0 -91
  306. package/dist/workflow/saved.d.ts.map +0 -1
  307. package/dist/workflow/saved.js +0 -204
  308. package/dist/workflow/saved.js.map +0 -1
  309. package/dist/workflow/task.d.ts +0 -137
  310. package/dist/workflow/task.d.ts.map +0 -1
  311. package/dist/workflow/task.js +0 -208
  312. package/dist/workflow/task.js.map +0 -1
  313. package/dist/workflow/tool-description.d.ts +0 -39
  314. package/dist/workflow/tool-description.d.ts.map +0 -1
  315. package/dist/workflow/tool-description.js +0 -200
  316. package/dist/workflow/tool-description.js.map +0 -1
  317. package/dist/workflow/worker-source.d.ts +0 -48
  318. package/dist/workflow/worker-source.d.ts.map +0 -1
  319. package/dist/workflow/worker-source.js +0 -779
  320. package/dist/workflow/worker-source.js.map +0 -1
  321. package/dist/worktree.d.ts +0 -53
  322. package/dist/worktree.d.ts.map +0 -1
  323. package/dist/worktree.js +0 -165
  324. package/dist/worktree.js.map +0 -1
  325. package/dist/write-execution.d.ts +0 -42
  326. package/dist/write-execution.d.ts.map +0 -1
  327. package/dist/write-execution.js +0 -138
  328. package/dist/write-execution.js.map +0 -1
  329. package/dist/xml.d.ts +0 -11
  330. package/dist/xml.d.ts.map +0 -1
  331. package/dist/xml.js +0 -13
  332. package/dist/xml.js.map +0 -1
  333. package/src/abortable.ts +0 -43
  334. package/src/agent-color.ts +0 -161
  335. package/src/agent-file-toggle.ts +0 -269
  336. package/src/child-context.ts +0 -15
  337. package/src/mention-clone.ts +0 -196
  338. package/src/mention.ts +0 -141
  339. package/src/model-scope.ts +0 -70
  340. package/src/nested-tools.ts +0 -424
  341. package/src/structured-output.ts +0 -130
  342. package/src/ui/agent-mention.ts +0 -216
  343. package/src/ui/select-item.ts +0 -45
  344. package/src/ui/workflow-card.ts +0 -470
  345. package/src/ui/workflow-dialog.ts +0 -1115
  346. package/src/ui/workflow-menu.ts +0 -166
  347. package/src/workflow/collisions.ts +0 -123
  348. package/src/workflow/entry.ts +0 -47
  349. package/src/workflow/host.ts +0 -403
  350. package/src/workflow/journal.ts +0 -164
  351. package/src/workflow/json-schema.ts +0 -128
  352. package/src/workflow/meta.ts +0 -325
  353. package/src/workflow/progress.ts +0 -550
  354. package/src/workflow/runtime.ts +0 -1219
  355. package/src/workflow/saved.ts +0 -217
  356. package/src/workflow/task.ts +0 -302
  357. package/src/workflow/tool-description.ts +0 -200
  358. package/src/workflow/worker-source.ts +0 -781
  359. package/src/xml.ts +0 -13
@@ -1,59 +1,5 @@
1
- import { Type } from "@sinclair/typebox";
2
1
  import type { AgentConfig, IsolationMode, JoinMode, ThinkingLevel } from "./types.js";
3
2
 
4
- /**
5
- * The model-facing `isolation` parameter, shared by the `Agent` tool and the
6
- * nested delegation tool so the two cannot drift.
7
- *
8
- * Shape matters more than wording here. As a single-value optional literal,
9
- * models that fill every optional parameter — the transcript on #231 shows one
10
- * emitting `resume: ""`, `schedule: ""` and `model: "default"` alongside it —
11
- * had only `"worktree"` available to fill it with, and kept spawning worktrees
12
- * across three turns while their own reasoning said to omit the field. Every
13
- * other optional parameter has an inert filler; this one did not. `"off"` is
14
- * listed first and described as the default so the harmless value is the
15
- * obvious one to reach for.
16
- *
17
- * The wording tracks Claude Code's own `isolation` parameter, whose phrasing
18
- * models have the most exposure to: one description on the union rather than
19
- * per-value ones, opening "Isolation mode.", then a sentence per value in
20
- * schema order, each with its caveats in a trailing parenthetical. Two clauses
21
- * are ours, because our shape is not theirs — `"off"` has no counterpart there
22
- * (their enum is `worktree | remote`, so both of their values do something),
23
- * and neither does the uncommitted-work warning, which is the specific trap
24
- * #231 fell into. Deliberately absent is any "only use a worktree when…"
25
- * restriction: Claude Code's `Agent` tool states the capability and stops, and
26
- * a second legal value is what lets a model decline one, not being told to.
27
- */
28
- const isolationParamShape = {
29
- isolation: Type.Optional(
30
- Type.Union([Type.Literal("off"), Type.Literal("worktree")], {
31
- description:
32
- 'Isolation mode. Default "off". "off" runs the agent in the current checkout, the same as omitting the field. "worktree" creates a temporary git worktree so the agent works on an isolated copy of the repo (a copy cannot see uncommitted or staged changes in the main checkout).',
33
- }),
34
- ),
35
- };
36
-
37
- /**
38
- * Build the `isolation` parameter for a tool schema, or nothing when the
39
- * project disabled worktrees (`worktreeIsolation: false`).
40
- *
41
- * Dropping the field beats accepting it and quietly downgrading. The setting is
42
- * for a project whose model passes `"worktree"` on *every* call, so a
43
- * per-result "isolation was disabled" note would be noise on every result and
44
- * would keep raising the salience of a capability that isn't there. With no
45
- * field there is nothing to pass, nothing to drop, and nothing to explain — the
46
- * same trade `scheduleParam` makes for disabled scheduling, at zero LLM-context
47
- * cost. The resolver gate and the `agent-manager` check still cover the paths a
48
- * schema can't reach: agent files, the scheduler, and cross-extension RPC.
49
- *
50
- * Like `scheduleParam`, this is read once at tool registration — flipping the
51
- * setting needs a new pi session for the schema to change.
52
- */
53
- export function isolationParam(enabled: boolean): Partial<typeof isolationParamShape> {
54
- return enabled ? isolationParamShape : {};
55
- }
56
-
57
3
  interface AgentInvocationParams {
58
4
  model?: string;
59
5
  thinking?: string;
@@ -61,42 +7,12 @@ interface AgentInvocationParams {
61
7
  run_in_background?: boolean;
62
8
  inherit_context?: boolean;
63
9
  isolated?: boolean;
64
- /**
65
- * Untyped on purpose. Both tool schemas now build this field conditionally
66
- * and spread it, which erases TypeBox's literal inference to `unknown` (the
67
- * `schedule` param has the same shape). The resolver below narrows by
68
- * comparison rather than trusting the declaration, which also makes it safe
69
- * for the cross-extension RPC path, where options arrive unvalidated.
70
- */
71
- isolation?: unknown;
72
- }
73
-
74
- interface ResolveOptions {
75
- /**
76
- * Whether worktree isolation is permitted at all. False when the project set
77
- * `worktreeIsolation: false`, which drops a requested worktree rather than
78
- * failing the call: the fail-loud precedent covers spawns that *cannot* work,
79
- * while this one is the user opting out, and throwing would break exactly the
80
- * calls the `"off"` value exists to tolerate. Defaults to allowed.
81
- */
82
- worktreeAllowed?: boolean;
83
- /**
84
- * What an unqualified spawn means — neither the call nor the agent file said.
85
- *
86
- * Top-level callers pass the `backgroundByDefault` setting (default `true`,
87
- * following Claude Code). Nested callers pass `false` unconditionally: a
88
- * detached child is killed by `abortOwnedChildren` when its parent settles
89
- * and has no notification path of its own, so backgrounding one loses its
90
- * work. Both call sites pass it explicitly; the `false` fallback only covers
91
- * a caller that supplies no options at all, which in-tree means tests.
92
- */
93
- defaultRunInBackground?: boolean;
10
+ isolation?: IsolationMode;
94
11
  }
95
12
 
96
13
  export function resolveAgentInvocationConfig(
97
14
  agentConfig: AgentConfig | undefined,
98
15
  params: AgentInvocationParams,
99
- opts?: ResolveOptions,
100
16
  ): {
101
17
  modelInput?: string;
102
18
  modelFromParams: boolean;
@@ -106,47 +22,16 @@ export function resolveAgentInvocationConfig(
106
22
  runInBackground: boolean;
107
23
  isolated: boolean;
108
24
  isolation?: IsolationMode;
109
- /**
110
- * Caller parameters an agent file's frontmatter outranked, so the surfaces can
111
- * say "(asked X)" instead of presenting the effective value as the requested
112
- * one (#182). Populated only where both sides named something and they
113
- * disagree — a caller who asked for what they got was still honored.
114
- *
115
- * `max_turns` is deliberately absent: no surface renders a requested-vs-
116
- * effective turn limit, so recording one would be dead data.
117
- */
118
- overridden?: { thinking?: ThinkingLevel; model?: string };
119
25
  } {
120
- // Precedence first, collapse second — reversing these loses the veto, since
121
- // an agent file's "off" only outranks a caller's "worktree" while it is still
122
- // a value. Everything downstream then sees "worktree" or nothing at all.
123
- const requested = agentConfig?.isolation ?? params.isolation;
124
- const isolation = requested === "worktree" && opts?.worktreeAllowed !== false ? "worktree" : undefined;
125
-
126
- const overriddenThinking = agentConfig?.thinking != null && params.thinking != null
127
- && agentConfig.thinking !== params.thinking
128
- ? params.thinking as ThinkingLevel
129
- : undefined;
130
- const overriddenModel = agentConfig?.model != null && params.model != null
131
- && agentConfig.model !== params.model
132
- ? params.model
133
- : undefined;
134
-
135
26
  return {
136
27
  modelInput: agentConfig?.model ?? params.model,
137
28
  modelFromParams: agentConfig?.model == null && params.model != null,
138
29
  thinking: (agentConfig?.thinking ?? params.thinking) as ThinkingLevel | undefined,
139
30
  maxTurns: agentConfig?.maxTurns ?? params.max_turns,
140
31
  inheritContext: agentConfig?.inheritContext ?? params.inherit_context ?? false,
141
- runInBackground: agentConfig?.runInBackground ?? params.run_in_background ?? opts?.defaultRunInBackground ?? false,
32
+ runInBackground: agentConfig?.runInBackground ?? params.run_in_background ?? false,
142
33
  isolated: agentConfig?.isolated ?? params.isolated ?? false,
143
- isolation,
144
- // Undefined rather than an empty object when nothing was overridden: callers
145
- // spread this into the invocation snapshot, and an always-present key would
146
- // put `requestedThinking: undefined` on every record.
147
- overridden: overriddenThinking || overriddenModel
148
- ? { thinking: overriddenThinking, model: overriddenModel }
149
- : undefined,
34
+ isolation: agentConfig?.isolation ?? params.isolation,
150
35
  };
151
36
  }
152
37
 
@@ -14,24 +14,6 @@ export interface ModelRegistry {
14
14
  getAvailable?(): any[];
15
15
  }
16
16
 
17
- /**
18
- * Both display forms of a model. The short one goes on tight rows (the widget,
19
- * the Agent tool result), the canonical one where there is room to disambiguate
20
- * two providers serving a similarly-named model (the conversation viewer).
21
- *
22
- * One function, because `index.ts` labels the model it resolved before the run
23
- * and `agent-manager.ts` relabels it from the live session afterwards — the two
24
- * must agree or the label would visibly change the moment the session starts.
25
- */
26
- export function describeModel(
27
- model: { provider: string; id: string; name?: string },
28
- ): { modelName: string; modelId: string } {
29
- return {
30
- modelName: (model.name ?? model.id).replace(/^Claude\s+/i, "").toLowerCase(),
31
- modelId: `${model.provider}/${model.id}`,
32
- };
33
- }
34
-
35
17
  /**
36
18
  * Resolve a model string to a Model instance.
37
19
  * Tries exact match first ("provider/modelId"), then fuzzy match against all available models.
@@ -10,20 +10,6 @@ import { tmpdir } from "node:os";
10
10
  import { join } from "node:path";
11
11
  import type { AgentSession, AgentSessionEvent } from "@earendil-works/pi-coding-agent";
12
12
 
13
- /**
14
- * Project/global default for writing a subagent's `.output` transcript; a custom
15
- * agent's `output_transcript` overrides it per agent.
16
- *
17
- * State lives here rather than in an index.ts closure because both spawn paths
18
- * need it — the top-level Agent tool and the nested delegation tools. Same
19
- * reason `scopeModels` lives in model-scope.ts: a setting only one path can read
20
- * is a setting the other path silently ignores.
21
- */
22
- let outputTranscriptDefault = true;
23
-
24
- export function getOutputTranscriptDefault(): boolean { return outputTranscriptDefault; }
25
- export function setOutputTranscriptDefault(b: boolean): void { outputTranscriptDefault = b; }
26
-
27
13
  /**
28
14
  * Encode a cwd path as a filesystem-safe directory name. Handles:
29
15
  * - POSIX: "/home/user/project" → "home-user-project"
@@ -37,14 +23,9 @@ export function encodeCwd(cwd: string): string {
37
23
  .replace(/^-+/, ""); // strip leading dashes (POSIX root, UNC)
38
24
  }
39
25
 
40
- /**
41
- * The per-session scratch directory, created if missing.
42
- * Mirrors Claude Code's layout: /tmp/{prefix}-{uid}/{encoded-cwd}/{sessionId}/tasks
43
- *
44
- * Shared with the workflow tool, which persists each invocation's script here so
45
- * iterating on one is edit-file-then-rerun — the same convention, one directory.
46
- */
47
- export function sessionTaskDir(cwd: string, sessionId: string): string {
26
+ /** Create the output file path, ensuring the directory exists.
27
+ * Mirrors Claude Code's layout: /tmp/{prefix}-{uid}/{encoded-cwd}/{sessionId}/tasks/{agentId}.output */
28
+ export function createOutputFilePath(cwd: string, agentId: string, sessionId: string): string {
48
29
  const encoded = encodeCwd(cwd);
49
30
  const root = join(tmpdir(), `pi-subagents-${process.getuid?.() ?? 0}`);
50
31
  mkdirSync(root, { recursive: true, mode: 0o700 });
@@ -57,27 +38,7 @@ export function sessionTaskDir(cwd: string, sessionId: string): string {
57
38
  }
58
39
  const dir = join(root, encoded, sessionId, "tasks");
59
40
  mkdirSync(dir, { recursive: true });
60
- return dir;
61
- }
62
-
63
- /** Create the output file path, ensuring the directory exists. */
64
- export function createOutputFilePath(cwd: string, agentId: string, sessionId: string): string {
65
- return join(sessionTaskDir(cwd, sessionId), `${agentId}.output`);
66
- }
67
-
68
- /**
69
- * Ensure a transcript file exists without disturbing what is already in it.
70
- *
71
- * A resume reuses the agent's existing transcript (same deterministic path), so
72
- * it must never call `writeInitialEntry` — that truncates, discarding turns the
73
- * completion notification still points the user at, and any history the session
74
- * has since compacted away is gone for good. Appending nothing creates the file
75
- * when this is the agent's first transcript and is a no-op when it is not.
76
- */
77
- export function ensureOutputFile(path: string): void {
78
- try {
79
- appendFileSync(path, "", "utf-8");
80
- } catch { /* ignore — streaming writes are best-effort too */ }
41
+ return join(dir, `${agentId}.output`);
81
42
  }
82
43
 
83
44
  /** Write the initial user prompt entry. */
@@ -102,24 +63,9 @@ export function streamToOutputFile(
102
63
  path: string,
103
64
  agentId: string,
104
65
  cwd: string,
105
- startIndexOrHistoryPath?: number | string,
106
66
  historyPath?: string,
107
67
  ): () => void {
108
- // Keep the fork's historical five-argument form (historyPath as the fifth
109
- // argument) while accepting upstream's six-argument resume form
110
- // (startIndex, historyPath). This matters because scheduler/RPC/workflow
111
- // callers use the ordinary spawn form, whereas resume starts after an
112
- // existing in-memory message prefix.
113
- const startIndex = typeof startIndexOrHistoryPath === "number" ? startIndexOrHistoryPath : undefined;
114
- const durableHistoryPath = typeof startIndexOrHistoryPath === "string"
115
- ? startIndexOrHistoryPath
116
- : historyPath;
117
- // Index of the first message this stream is responsible for. A spawn writes
118
- // messages[0] as the initial prompt entry, so it starts at 1. A resume hands
119
- // in the session's length as of just before the run: the session already
120
- // holds every prior turn, and re-emitting those would duplicate history that
121
- // is already in the file.
122
- let writtenCount = startIndex ?? 1;
68
+ let writtenCount = 1; // initial user prompt already written
123
69
 
124
70
  const flush = () => {
125
71
  const messages = session.messages;
@@ -134,8 +80,7 @@ export function streamToOutputFile(
134
80
  cwd,
135
81
  };
136
82
  const entryJson = JSON.stringify(entry) + "\n";
137
- const targets = durableHistoryPath && durableHistoryPath !== path ? [path, durableHistoryPath] : [path];
138
- for (const target of targets) {
83
+ for (const target of historyPath && historyPath !== path ? [path, historyPath] : [path]) {
139
84
  try {
140
85
  appendFileSync(target, entryJson, "utf-8");
141
86
  } catch { /* ignore write errors */ }
package/src/prompts.ts CHANGED
@@ -10,29 +10,6 @@ export interface PromptExtras {
10
10
  memoryBlock?: string;
11
11
  /** Preloaded skill contents to inject. */
12
12
  skillBlocks?: { name: string; content: string }[];
13
- /**
14
- * Parent directory the worktree copy was created from. Set only for
15
- * `isolation: "worktree"` spawns — triggers the block that tells the agent
16
- * to stay in the copy.
17
- */
18
- worktreeBase?: string;
19
- /**
20
- * Set only for a workflow's own children, and only when they have no
21
- * `StructuredOutput` tool to answer through.
22
- *
23
- * A workflow child's final text is not read by a human — it is the value
24
- * `agent()` resolves to, and the script interpolates it straight into the
25
- * next stage's prompt. Without this, children answer the way every other
26
- * subagent does (a report addressed to a reader), and the padding becomes
27
- * input tokens for the stage downstream. Claude Code's `Workflow` tool
28
- * documents this contract to the script-writing model; this is the end of it
29
- * that makes the documentation true.
30
- *
31
- * Deliberately NOT applied to every subagent. In pi an ordinary agent's
32
- * output IS read by a human — through the Agents widget, the conversation
33
- * viewer and `get_subagent_result` — so terse raw data would be wrong there.
34
- */
35
- workflowChild?: boolean;
36
13
  }
37
14
 
38
15
  /**
@@ -66,26 +43,6 @@ Working directory: ${cwd}
66
43
  ${env.isGitRepo ? `Git repository: yes\nBranch: ${env.branch}` : "Not a git repository"}
67
44
  Platform: ${env.platform}`;
68
45
 
69
- // A worktree agent is told its cwd twice: by the env block above (the copy)
70
- // and by whatever names the main checkout — the inherited parent prompt in
71
- // append mode, or the task prompt in either mode. It follows the latter and
72
- // works in the shared tree (#187), so resolve the contradiction explicitly.
73
- const worktreeBlock = extras?.worktreeBase
74
- ? `\n\n<worktree_isolation>
75
- Your working directory is an isolated git worktree copy of ${extras.worktreeBase}.
76
- Work only inside it — never in ${extras.worktreeBase}, even if other instructions name that path as your working directory.
77
- </worktree_isolation>`
78
- : "";
79
-
80
- // The script, not a person, reads what this child returns — see
81
- // `PromptExtras.workflowChild` for why only workflow children get this.
82
- const workflowBlock = extras?.workflowChild
83
- ? `\n\n<workflow_child>
84
- Your final message IS the return value of this task. A workflow script captures it and passes it to the next stage; no person reads it.
85
- Return only the answer, in exactly the shape the prompt asks for — no preamble, no summary of what you did, no offer to continue.
86
- </workflow_child>`
87
- : "";
88
-
89
46
  // Build optional extras suffix
90
47
  const extraSections: string[] = [];
91
48
  if (extras?.memoryBlock) {
@@ -123,7 +80,7 @@ You are operating as a sub-agent invoked to handle a specific task.
123
80
  // placed verbatim (no wrapper tag) so it forms an identical byte prefix
124
81
  // with the parent session, maximising KV cache hits. The <active_agent>
125
82
  // tag and env block vary per call and are placed after the cached prefix.
126
- return identity + "\n\n" + bridge + "\n\n" + activeAgentTag + envBlock + worktreeBlock + workflowBlock + customSection + extrasSuffix;
83
+ return identity + "\n\n" + bridge + "\n\n" + activeAgentTag + envBlock + customSection + extrasSuffix;
127
84
  }
128
85
 
129
86
  // "replace" mode — env header + the config's full system prompt
@@ -132,7 +89,7 @@ You have been invoked to handle a specific task autonomously.
132
89
 
133
90
  ${envBlock}`;
134
91
 
135
- return activeAgentTag + replaceHeader + worktreeBlock + workflowBlock + "\n\n" + config.systemPrompt + extrasSuffix;
92
+ return activeAgentTag + replaceHeader + "\n\n" + config.systemPrompt + extrasSuffix;
136
93
  }
137
94
 
138
95
  /** Fallback base prompt when parent system prompt is unavailable in append mode. */
package/src/schedule.ts CHANGED
@@ -19,8 +19,6 @@ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-a
19
19
  import { Cron } from "croner";
20
20
  import { nanoid } from "nanoid";
21
21
  import type { AgentManager } from "./agent-manager.js";
22
- import { normalizeMaxTurns } from "./agent-runner.js";
23
- import { resolveSpawnType } from "./agent-types.js";
24
22
  import { resolveModel } from "./model-resolver.js";
25
23
  import type { ScheduleStore } from "./schedule-store.js";
26
24
  import type { IsolationMode, ScheduledSubagent, SubagentType, ThinkingLevel } from "./types.js";
@@ -240,15 +238,7 @@ export class SubagentScheduler {
240
238
 
241
239
  let agentId: string;
242
240
  try {
243
- // Re-resolve at fire time against the registry as it stands. This does not
244
- // reload from disk (the scheduler has no reason to rebuild process-global
245
- // state from a timer), so it catches changes that went through /agents or
246
- // an Agent call — not a file deleted directly from a shell. The catch below turns
247
- // this into lastStatus: "error" plus an error event, like any other
248
- // fire-time failure.
249
- const dispatch = resolveSpawnType(job.subagent_type);
250
- if (!dispatch.ok) throw new Error(dispatch.message);
251
- agentId = manager.spawn(pi, ctx, dispatch.type, job.prompt, {
241
+ agentId = manager.spawn(pi, ctx, job.subagent_type, job.prompt, {
252
242
  description: job.description,
253
243
  isBackground: true,
254
244
  bypassQueue: true,
@@ -257,20 +247,6 @@ export class SubagentScheduler {
257
247
  isolated: job.isolated,
258
248
  thinkingLevel: job.thinking,
259
249
  isolation: job.isolation,
260
- // A scheduled run has no tool call to build this, so without it the
261
- // conversation viewer shows nothing about how the job was configured.
262
- // The model is left out on purpose: agent-manager fills in the effective
263
- // one when the session reports it, and naming the pre-session pick here
264
- // would only be right until then.
265
- invocation: {
266
- thinking: job.thinking,
267
- // Normalized like the Agent tool's own snapshot: `0` means unlimited,
268
- // and rendering it as "max turns: 0" would read as a limit of none.
269
- maxTurns: normalizeMaxTurns(job.max_turns),
270
- isolated: job.isolated,
271
- runInBackground: true,
272
- isolation: job.isolation,
273
- },
274
250
  });
275
251
  } catch (err) {
276
252
  const error = err instanceof Error ? err.message : String(err);
@@ -281,6 +257,7 @@ export class SubagentScheduler {
281
257
 
282
258
  this.emit({ type: "fired", jobId: id, agentId, name: job.name });
283
259
 
260
+ const record = manager.getRecord(agentId);
284
261
  const finalize = (status: "success" | "error") => {
285
262
  const next = this.getNextRun(id);
286
263
  const current = store.get(id);
@@ -295,16 +272,18 @@ export class SubagentScheduler {
295
272
  // AgentManager's promise resolves either way (its .catch returns ""), so we
296
273
  // can't infer success/failure from the promise — read record.status instead.
297
274
  // Terminal states: completed/steered = success; error/aborted/stopped = error.
298
- // awaitStartup first: with isolation: "worktree" the run promise only exists
299
- // once the repo copy is made, and a failed copy rejects here.
300
- manager.awaitStartup(agentId)
301
- .then(() => manager.getRecord(agentId)?.promise)
302
- .then(() => {
303
- const r = manager.getRecord(agentId);
304
- const failed = r?.status === "error" || r?.status === "aborted" || r?.status === "stopped";
305
- finalize(failed ? "error" : "success");
306
- })
307
- .catch(() => finalize("error"));
275
+ if (record?.promise) {
276
+ record.promise
277
+ .then(() => {
278
+ const r = manager.getRecord(agentId);
279
+ const failed = r?.status === "error" || r?.status === "aborted" || r?.status === "stopped";
280
+ finalize(failed ? "error" : "success");
281
+ })
282
+ .catch(() => finalize("error"));
283
+ } else {
284
+ // Spawn returned without a promise (defensive — bypassQueue path always sets one).
285
+ finalize("success");
286
+ }
308
287
  }
309
288
 
310
289
  private emit(event: ScheduleChangeEvent): void {