@mjasnikovs/pi-task 0.38.28 → 0.38.30

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 (370) hide show
  1. package/dist/config/config.d.ts +70 -70
  2. package/dist/config/config.js +26 -35
  3. package/dist/config/extension-list.d.ts +6 -5
  4. package/dist/config/extension-list.js +3 -2
  5. package/dist/config/reasoning-args.d.ts +9 -7
  6. package/dist/config/reasoning-args.js +12 -10
  7. package/dist/config/reasoning.d.ts +44 -105
  8. package/dist/config/reasoning.js +27 -704
  9. package/dist/config/register.d.ts +34 -48
  10. package/dist/config/register.js +41 -51
  11. package/dist/config/tool-list.d.ts +16 -16
  12. package/dist/config/tool-list.js +1 -1
  13. package/dist/remote/bridge.d.ts +19 -10
  14. package/dist/remote/bridge.js +3 -2
  15. package/dist/remote/broadcast.js +3 -1
  16. package/dist/remote/events.js +12 -11
  17. package/dist/remote/history.d.ts +1 -1
  18. package/dist/remote/protocol.d.ts +6 -3
  19. package/dist/remote/protocol.js +2 -1
  20. package/dist/remote/push.d.ts +16 -16
  21. package/dist/remote/push.js +27 -27
  22. package/dist/remote/register.d.ts +3 -3
  23. package/dist/remote/register.js +17 -19
  24. package/dist/remote/server.d.ts +9 -8
  25. package/dist/remote/server.js +15 -14
  26. package/dist/remote/session-state.d.ts +5 -4
  27. package/dist/remote/session-state.js +8 -5
  28. package/dist/remote/sw.d.ts +7 -6
  29. package/dist/remote/sw.js +7 -6
  30. package/dist/remote/tailscale.d.ts +4 -2
  31. package/dist/remote/tailscale.js +4 -2
  32. package/dist/remote/ui-highlight.js +6 -5
  33. package/dist/remote/ui-render.js +4 -4
  34. package/dist/remote/ui-script.js +24 -24
  35. package/dist/remote/ui-styles.d.ts +1 -1
  36. package/dist/remote/ui-styles.js +10 -13
  37. package/dist/remote/ui-tools.js +9 -6
  38. package/dist/shared/child-extensions.d.ts +29 -17
  39. package/dist/shared/child-extensions.js +29 -17
  40. package/dist/shared/child-output.d.ts +30 -24
  41. package/dist/shared/child-output.js +25 -17
  42. package/dist/shared/child-process.d.ts +47 -40
  43. package/dist/shared/child-process.js +50 -59
  44. package/dist/shared/command-watchdog.d.ts +22 -16
  45. package/dist/shared/command-watchdog.js +28 -21
  46. package/dist/shared/fs-text.d.ts +16 -10
  47. package/dist/shared/fs-text.js +16 -10
  48. package/dist/shared/git-runner.d.ts +25 -25
  49. package/dist/shared/git-runner.js +25 -25
  50. package/dist/shared/leaked-tool-call.d.ts +17 -11
  51. package/dist/shared/leaked-tool-call.js +23 -15
  52. package/dist/shared/model-endpoint.d.ts +29 -16
  53. package/dist/shared/model-endpoint.js +33 -21
  54. package/dist/shared/pi-invocation.d.ts +7 -4
  55. package/dist/shared/pi-invocation.js +12 -7
  56. package/dist/shared/pkg-version.d.ts +13 -5
  57. package/dist/shared/pkg-version.js +13 -5
  58. package/dist/shared/reasoning-capability.d.ts +35 -24
  59. package/dist/shared/reasoning-capability.js +35 -24
  60. package/dist/shared/stream-watchdog.d.ts +60 -44
  61. package/dist/shared/stream-watchdog.js +62 -45
  62. package/dist/task/accept-debt.d.ts +41 -43
  63. package/dist/task/accept-debt.js +73 -65
  64. package/dist/task/api-synthesis.d.ts +24 -21
  65. package/dist/task/api-synthesis.js +32 -26
  66. package/dist/task/apis-contract.d.ts +32 -64
  67. package/dist/task/apis-contract.js +32 -64
  68. package/dist/task/artifact-closure.d.ts +27 -13
  69. package/dist/task/artifact-closure.js +95 -67
  70. package/dist/task/auto-commit.d.ts +46 -35
  71. package/dist/task/auto-commit.js +51 -38
  72. package/dist/task/auto-io.d.ts +45 -25
  73. package/dist/task/auto-io.js +57 -29
  74. package/dist/task/auto-orchestrator.d.ts +26 -24
  75. package/dist/task/auto-orchestrator.js +178 -162
  76. package/dist/task/auto-prompts.d.ts +36 -24
  77. package/dist/task/auto-prompts.js +40 -26
  78. package/dist/task/autofix-ledger.d.ts +27 -25
  79. package/dist/task/autofix-ledger.js +29 -26
  80. package/dist/task/batch-test-task.d.ts +20 -12
  81. package/dist/task/batch-test-task.js +67 -60
  82. package/dist/task/boot-probe.d.ts +60 -44
  83. package/dist/task/boot-probe.js +91 -72
  84. package/dist/task/cancel-input.d.ts +30 -16
  85. package/dist/task/cancel-input.js +20 -11
  86. package/dist/task/cancel-points.d.ts +27 -20
  87. package/dist/task/cancel-points.js +30 -22
  88. package/dist/task/child-runner.d.ts +46 -51
  89. package/dist/task/child-runner.js +48 -49
  90. package/dist/task/child-status.d.ts +23 -16
  91. package/dist/task/child-status.js +23 -16
  92. package/dist/task/clamp-output.js +12 -5
  93. package/dist/task/command-run.d.ts +31 -28
  94. package/dist/task/command-run.js +44 -35
  95. package/dist/task/command-shrink.d.ts +25 -18
  96. package/dist/task/command-shrink.js +37 -31
  97. package/dist/task/command-watchdog.d.ts +9 -6
  98. package/dist/task/command-watchdog.js +21 -15
  99. package/dist/task/context-attribution.d.ts +34 -26
  100. package/dist/task/context-attribution.js +34 -26
  101. package/dist/task/context-silence.d.ts +39 -29
  102. package/dist/task/context-silence.js +35 -25
  103. package/dist/task/context-usage.d.ts +25 -7
  104. package/dist/task/context-usage.js +21 -6
  105. package/dist/task/contracts.d.ts +8 -4
  106. package/dist/task/contracts.js +25 -17
  107. package/dist/task/coverage-loop.d.ts +22 -18
  108. package/dist/task/coverage-loop.js +35 -30
  109. package/dist/task/critique-probes.d.ts +13 -14
  110. package/dist/task/critique-probes.js +50 -39
  111. package/dist/task/debug-log.d.ts +13 -5
  112. package/dist/task/debug-log.js +32 -20
  113. package/dist/task/decompose-fidelity.d.ts +11 -9
  114. package/dist/task/decompose-fidelity.js +38 -33
  115. package/dist/task/decompose-granularity.d.ts +41 -38
  116. package/dist/task/decompose-granularity.js +41 -38
  117. package/dist/task/deep-render-check.d.ts +22 -14
  118. package/dist/task/deep-render-check.js +40 -31
  119. package/dist/task/dropped-input.d.ts +12 -7
  120. package/dist/task/dropped-input.js +5 -2
  121. package/dist/task/enforce-attribution.d.ts +38 -47
  122. package/dist/task/enforce-attribution.js +46 -52
  123. package/dist/task/enforce-guidelines.d.ts +31 -20
  124. package/dist/task/enforce-guidelines.js +32 -21
  125. package/dist/task/enrichment.d.ts +7 -2
  126. package/dist/task/enrichment.js +26 -14
  127. package/dist/task/env-notes.d.ts +16 -7
  128. package/dist/task/env-notes.js +48 -31
  129. package/dist/task/env-template-closure.d.ts +4 -4
  130. package/dist/task/env-template-closure.js +42 -34
  131. package/dist/task/external-context.d.ts +28 -21
  132. package/dist/task/external-context.js +17 -12
  133. package/dist/task/failure-classifier.d.ts +4 -5
  134. package/dist/task/failure-classifier.js +6 -7
  135. package/dist/task/file-inventory.d.ts +15 -11
  136. package/dist/task/file-inventory.js +25 -22
  137. package/dist/task/final-gate-fix.d.ts +74 -86
  138. package/dist/task/final-gate-fix.js +97 -116
  139. package/dist/task/final-gate-progress.d.ts +29 -46
  140. package/dist/task/final-gate-progress.js +40 -51
  141. package/dist/task/final-gate.d.ts +64 -97
  142. package/dist/task/final-gate.js +192 -199
  143. package/dist/task/fix-child.d.ts +21 -27
  144. package/dist/task/fix-child.js +21 -27
  145. package/dist/task/foreign-path.d.ts +6 -5
  146. package/dist/task/foreign-path.js +0 -0
  147. package/dist/task/frozen-conflict.d.ts +9 -10
  148. package/dist/task/frozen-conflict.js +61 -64
  149. package/dist/task/frozen-path-guard.d.ts +35 -14
  150. package/dist/task/frozen-path-guard.js +56 -39
  151. package/dist/task/gate-child.d.ts +27 -28
  152. package/dist/task/gate-child.js +37 -35
  153. package/dist/task/gate-deps.d.ts +34 -27
  154. package/dist/task/gate-deps.js +169 -159
  155. package/dist/task/gate-tally.d.ts +77 -80
  156. package/dist/task/gate-tally.js +65 -68
  157. package/dist/task/git-state-guard.d.ts +15 -11
  158. package/dist/task/git-state-guard.js +76 -66
  159. package/dist/task/impl-widget.d.ts +25 -16
  160. package/dist/task/impl-widget.js +27 -17
  161. package/dist/task/implementation-thinking.d.ts +33 -31
  162. package/dist/task/implementation-thinking.js +5 -6
  163. package/dist/task/implementation-turn.d.ts +34 -31
  164. package/dist/task/implementation-turn.js +29 -27
  165. package/dist/task/inline-markdown.d.ts +20 -7
  166. package/dist/task/inline-markdown.js +15 -6
  167. package/dist/task/launch-config-gap.js +25 -39
  168. package/dist/task/launch-contract.d.ts +18 -21
  169. package/dist/task/launch-contract.js +28 -30
  170. package/dist/task/launch-manifest.d.ts +6 -2
  171. package/dist/task/launch-manifest.js +35 -34
  172. package/dist/task/ledger.js +16 -14
  173. package/dist/task/lint-fix.d.ts +6 -8
  174. package/dist/task/lint-fix.js +67 -69
  175. package/dist/task/loop-detector.d.ts +9 -8
  176. package/dist/task/loop-detector.js +16 -12
  177. package/dist/task/mid-run-input.d.ts +17 -15
  178. package/dist/task/mid-run-input.js +17 -15
  179. package/dist/task/orchestrator.d.ts +24 -28
  180. package/dist/task/orchestrator.js +62 -64
  181. package/dist/task/orientation.d.ts +18 -23
  182. package/dist/task/orientation.js +24 -31
  183. package/dist/task/owned-freeze-conflict.d.ts +21 -20
  184. package/dist/task/owned-freeze-conflict.js +52 -85
  185. package/dist/task/owned-freeze-reassign.d.ts +40 -60
  186. package/dist/task/owned-freeze-reassign.js +41 -61
  187. package/dist/task/parsers.d.ts +4 -2
  188. package/dist/task/parsers.js +4 -4
  189. package/dist/task/phases.d.ts +41 -48
  190. package/dist/task/phases.js +180 -248
  191. package/dist/task/plan-io.d.ts +6 -7
  192. package/dist/task/plan-io.js +6 -7
  193. package/dist/task/plan-orchestrator.d.ts +10 -8
  194. package/dist/task/plan-orchestrator.js +14 -10
  195. package/dist/task/plan-prompts.d.ts +6 -5
  196. package/dist/task/plan-prompts.js +6 -5
  197. package/dist/task/plan-readonly.d.ts +4 -5
  198. package/dist/task/plan-readonly.js +4 -5
  199. package/dist/task/plan-rounds.d.ts +17 -29
  200. package/dist/task/plan-rounds.js +21 -34
  201. package/dist/task/plan-session.d.ts +58 -72
  202. package/dist/task/plan-session.js +61 -83
  203. package/dist/task/probe-gaming.d.ts +28 -27
  204. package/dist/task/probe-gaming.js +0 -0
  205. package/dist/task/prohibition-probe.d.ts +14 -16
  206. package/dist/task/prompts.d.ts +3 -4
  207. package/dist/task/prompts.js +17 -26
  208. package/dist/task/qa-transcript.d.ts +15 -22
  209. package/dist/task/qa-transcript.js +15 -21
  210. package/dist/task/question-box.d.ts +17 -13
  211. package/dist/task/question-box.js +19 -15
  212. package/dist/task/question-dedup.d.ts +6 -7
  213. package/dist/task/question-dedup.js +13 -14
  214. package/dist/task/question-dialog.d.ts +22 -32
  215. package/dist/task/question-dialog.js +22 -32
  216. package/dist/task/question-source.d.ts +18 -44
  217. package/dist/task/question-source.js +22 -51
  218. package/dist/task/refuted-constraint.d.ts +11 -31
  219. package/dist/task/refuted-constraint.js +27 -51
  220. package/dist/task/regenerable-artifacts.d.ts +12 -31
  221. package/dist/task/regenerable-artifacts.js +12 -31
  222. package/dist/task/render-check.d.ts +11 -22
  223. package/dist/task/render-check.js +33 -46
  224. package/dist/task/repo-health-check.d.ts +10 -14
  225. package/dist/task/repo-health-check.js +17 -23
  226. package/dist/task/requirements.d.ts +38 -71
  227. package/dist/task/requirements.js +78 -126
  228. package/dist/task/research-fanout-budget.d.ts +51 -88
  229. package/dist/task/research-fanout-budget.js +51 -88
  230. package/dist/task/research-worker.d.ts +33 -36
  231. package/dist/task/research-worker.js +39 -61
  232. package/dist/task/resume-gap.d.ts +14 -15
  233. package/dist/task/root-cause-repair.d.ts +9 -9
  234. package/dist/task/root-cause-repair.js +28 -40
  235. package/dist/task/run-bracket.d.ts +10 -13
  236. package/dist/task/run-end.d.ts +12 -22
  237. package/dist/task/run-end.js +8 -16
  238. package/dist/task/run-final-gate.d.ts +19 -21
  239. package/dist/task/run-final-gate.js +62 -80
  240. package/dist/task/runner-globs.d.ts +12 -13
  241. package/dist/task/runner-globs.js +12 -13
  242. package/dist/task/runner-resolve.d.ts +9 -9
  243. package/dist/task/runner-resolve.js +22 -23
  244. package/dist/task/script-escape.d.ts +10 -12
  245. package/dist/task/script-escape.js +13 -14
  246. package/dist/task/serve-entry.d.ts +1 -1
  247. package/dist/task/serve-entry.js +22 -25
  248. package/dist/task/service-blocks.js +4 -2
  249. package/dist/task/shipped-source.d.ts +11 -29
  250. package/dist/task/shipped-source.js +11 -29
  251. package/dist/task/skip-escape.js +10 -14
  252. package/dist/task/spec-urls.d.ts +26 -65
  253. package/dist/task/spec-urls.js +26 -65
  254. package/dist/task/spec-validation.d.ts +17 -20
  255. package/dist/task/spec-validation.js +17 -20
  256. package/dist/task/stall-detector.d.ts +23 -30
  257. package/dist/task/stall-detector.js +23 -30
  258. package/dist/task/stream-watchdog.d.ts +14 -12
  259. package/dist/task/stream-watchdog.js +14 -12
  260. package/dist/task/substitution-probe.d.ts +17 -20
  261. package/dist/task/substitution-probe.js +17 -20
  262. package/dist/task/task-gates.d.ts +36 -41
  263. package/dist/task/task-gates.js +95 -106
  264. package/dist/task/task-io.d.ts +4 -4
  265. package/dist/task/task-io.js +4 -4
  266. package/dist/task/task-parsers.js +4 -3
  267. package/dist/task/task-provenance.d.ts +2 -2
  268. package/dist/task/task-provenance.js +11 -13
  269. package/dist/task/task-types.d.ts +4 -3
  270. package/dist/task/terminal-outcome.d.ts +14 -16
  271. package/dist/task/terminal-outcome.js +12 -14
  272. package/dist/task/test-assembly.d.ts +13 -20
  273. package/dist/task/test-assembly.js +13 -20
  274. package/dist/task/timings.d.ts +5 -3
  275. package/dist/task/timings.js +5 -3
  276. package/dist/task/title-label.d.ts +9 -4
  277. package/dist/task/title-label.js +9 -4
  278. package/dist/task/type-only-answer.d.ts +44 -52
  279. package/dist/task/type-only-answer.js +44 -52
  280. package/dist/task/unfailable-command.d.ts +18 -24
  281. package/dist/task/unfailable-command.js +21 -27
  282. package/dist/task/unknown-routing.d.ts +10 -4
  283. package/dist/task/unknown-routing.js +10 -4
  284. package/dist/task/user-directives.d.ts +5 -8
  285. package/dist/task/user-directives.js +5 -8
  286. package/dist/task/verify-quality.d.ts +18 -22
  287. package/dist/task/verify-quality.js +45 -46
  288. package/dist/task/verify-reconcile.d.ts +15 -10
  289. package/dist/task/verify-reconcile.js +45 -43
  290. package/dist/task/verify-resolution.d.ts +24 -20
  291. package/dist/task/verify-resolution.js +51 -50
  292. package/dist/task/verify-work.d.ts +59 -66
  293. package/dist/task/verify-work.js +101 -138
  294. package/dist/task/widget.d.ts +15 -14
  295. package/dist/task/widget.js +22 -17
  296. package/dist/task/wiring-claims.d.ts +25 -32
  297. package/dist/task/wiring-claims.js +30 -35
  298. package/dist/task/write-guard.d.ts +39 -39
  299. package/dist/task/write-guard.js +48 -51
  300. package/dist/task/yolo.d.ts +34 -30
  301. package/dist/task/yolo.js +42 -37
  302. package/dist/workers/abstention.d.ts +21 -41
  303. package/dist/workers/abstention.js +27 -48
  304. package/dist/workers/brave-search.d.ts +4 -3
  305. package/dist/workers/brave-search.js +5 -2
  306. package/dist/workers/brave-warning.d.ts +7 -4
  307. package/dist/workers/brave-warning.js +19 -7
  308. package/dist/workers/ddg-search.d.ts +6 -6
  309. package/dist/workers/ddg-search.js +18 -12
  310. package/dist/workers/docs-cache.js +5 -2
  311. package/dist/workers/docs-chunk.d.ts +30 -37
  312. package/dist/workers/docs-chunk.js +37 -41
  313. package/dist/workers/docs-core.d.ts +28 -44
  314. package/dist/workers/docs-core.js +25 -44
  315. package/dist/workers/docs-index.js +4 -3
  316. package/dist/workers/docs-lookup.d.ts +15 -22
  317. package/dist/workers/docs-lookup.js +12 -21
  318. package/dist/workers/docs-project.d.ts +15 -9
  319. package/dist/workers/docs-project.js +17 -10
  320. package/dist/workers/docs-resolve.d.ts +19 -20
  321. package/dist/workers/docs-resolve.js +35 -32
  322. package/dist/workers/docs-retrieve.d.ts +5 -6
  323. package/dist/workers/docs-retrieve.js +18 -15
  324. package/dist/workers/exa-search.d.ts +9 -6
  325. package/dist/workers/exa-search.js +23 -12
  326. package/dist/workers/fetch-core.d.ts +13 -16
  327. package/dist/workers/fetch-core.js +23 -23
  328. package/dist/workers/focused-extractor.d.ts +12 -12
  329. package/dist/workers/focused-extractor.js +16 -19
  330. package/dist/workers/html-clean.js +24 -14
  331. package/dist/workers/http-request.d.ts +28 -20
  332. package/dist/workers/http-request.js +22 -17
  333. package/dist/workers/npm-version.d.ts +28 -11
  334. package/dist/workers/npm-version.js +24 -15
  335. package/dist/workers/phantom-imports.d.ts +15 -12
  336. package/dist/workers/phantom-imports.js +30 -24
  337. package/dist/workers/pi-worker-core.d.ts +86 -54
  338. package/dist/workers/pi-worker-core.js +112 -112
  339. package/dist/workers/pi-worker-docs.d.ts +24 -19
  340. package/dist/workers/pi-worker-docs.js +67 -76
  341. package/dist/workers/pi-worker-fetch.d.ts +7 -3
  342. package/dist/workers/pi-worker-fetch.js +27 -19
  343. package/dist/workers/pi-worker-search.js +12 -8
  344. package/dist/workers/pi-worker.d.ts +9 -4
  345. package/dist/workers/pi-worker.js +23 -10
  346. package/dist/workers/reasoning-warning.d.ts +18 -17
  347. package/dist/workers/reasoning-warning.js +22 -20
  348. package/dist/workers/research-cache.js +50 -78
  349. package/dist/workers/search-core.js +7 -5
  350. package/dist/workers/search-types.d.ts +10 -9
  351. package/dist/workers/search-types.js +9 -8
  352. package/dist/workers/session-hint.d.ts +13 -14
  353. package/dist/workers/session-hint.js +8 -9
  354. package/dist/workers/shared.d.ts +21 -25
  355. package/dist/workers/shared.js +0 -0
  356. package/dist/workers/single-read-extension.d.ts +14 -7
  357. package/dist/workers/single-read-extension.js +14 -7
  358. package/dist/workers/single-read-guard.d.ts +25 -28
  359. package/dist/workers/single-read-guard.js +32 -32
  360. package/dist/workers/typeonly-log.d.ts +12 -9
  361. package/dist/workers/typeonly-log.js +29 -33
  362. package/dist/workers/worker-channels.d.ts +15 -23
  363. package/dist/workers/worker-channels.js +15 -23
  364. package/dist/workers/worker-failure.d.ts +38 -46
  365. package/dist/workers/worker-failure.js +31 -39
  366. package/dist/workers/worker-kill.d.ts +25 -26
  367. package/dist/workers/worker-kill.js +16 -19
  368. package/dist/workers/worker-profiles.d.ts +43 -53
  369. package/dist/workers/worker-profiles.js +30 -38
  370. package/package.json +10 -8
@@ -44,15 +44,8 @@ declare class BorderedBox implements Component {
44
44
  * One /task-config setting, and BOTH directions of its value.
45
45
  *
46
46
  * `format` renders the stored value for the panel; `apply` parses the chosen
47
- * label back into it. They are per-row because the two used to be hand-written
48
- * ladders a `displayValue` arm to format, a matching `onChange` arm to parse,
49
- * and three different idioms for the same parse across the four enum settings.
50
- * Adding one enum setting meant four coordinated edits (row, format arm, parse
51
- * arm, sanitizer) and NONE of them failed to compile if you forgot it: a missed
52
- * format arm rendered `String(cfg[id])`, and a missed parse arm let the generic
53
- * `else` write the boolean `newValue === 'on'` into an enum field. The comment
54
- * that used to sit in that `else` — explaining why `debugLogs` must not fall
55
- * into it — was the interface saying it was too shallow.
47
+ * label back into it. Both live on the row so adding an enum setting is ONE
48
+ * edit, and a row that renders but cannot parse is impossible to write.
56
49
  *
57
50
  * With both directions on the row, `format(apply(cfg, v)) === v` is a property
58
51
  * over the whole table, and the panel and the non-TUI listing cannot disagree
@@ -64,18 +57,16 @@ export interface ConfigItem {
64
57
  * string (`reason:`, `tool:`, `ext:`) for a DISCOVERED one.
65
58
  *
66
59
  * It is `string`, not `keyof PiTaskConfig`, and that is what lets the three
67
- * dynamic families BE rows instead of bypassing them. While the id was
68
- * narrow, each family re-invented both directions by hand a builder, an
69
- * apply function, and an arm in a four-way prefix ladder 300 lines away —
70
- * and the round-trip property `config-items.test.ts` runs over `ITEMS`
71
- * covered none of them.
60
+ * dynamic families BE rows instead of bypassing them so the round-trip
61
+ * property in `config-items.test.ts` covers them through the same row type
62
+ * as the fixed settings.
72
63
  */
73
64
  id: string;
74
65
  /**
75
- * Which titled block of the menu this row sits under. Rows are grouped by
76
- * section in {@link panelItems}, in the order the sections first appear in
77
- * {@link ITEMS} so moving a row between sections is a one-word edit and
78
- * the header follows it.
66
+ * Which titled block of the menu this row sits under. {@link renderRows}
67
+ * walks {@link SECTIONS} and collects the rows claiming each key, so the
68
+ * block order is SECTIONS' order and moving a row between blocks is a
69
+ * one-word edit here.
79
70
  */
80
71
  section: Section;
81
72
  label: string;
@@ -95,12 +86,11 @@ export interface ConfigItem {
95
86
  /**
96
87
  * The titled blocks the settings menu is divided into.
97
88
  *
98
- * A flat list of ~30 rows — twelve settings, seven reasoning groups, one row per
99
- * live tool and one per installed extension — reads as a wall, and the rows that
100
- * belong together (a mode and the seven groups it controls; a timeout and the
101
- * per-tool exemptions from it) end up separated by rows that have nothing to do
102
- * with them. The headers are inert rows: no `values`, so Enter does nothing on
103
- * them.
89
+ * One flat list the fixed settings, one row per reasoning group, one per live
90
+ * tool and one per installed extension — reads as a wall, and the rows that
91
+ * belong together (a mode and the groups it controls; a timeout and the per-tool
92
+ * exemptions from it) end up separated by rows that have nothing to do with
93
+ * them. The headers are inert rows: no `values`, so Enter does nothing on them.
104
94
  */
105
95
  export type Section = 'session' | 'checks' | 'research' | 'reasoning' | 'timeouts' | 'unattended' | 'logging' | 'extensions';
106
96
  /** Section order, and the label each header renders. */
@@ -113,9 +103,8 @@ export declare const SECTION_ID_PREFIX = "section:";
113
103
  /**
114
104
  * Every setting rendered by /task-config, in display order.
115
105
  *
116
- * Exported so the round-trip property below can be asserted over the WHOLE table
117
- * rather than per setting — the check that would have caught a forgotten arm in
118
- * either of the two ladders this replaced.
106
+ * Exported so the round-trip property in `config-items.test.ts` can be asserted
107
+ * over the WHOLE table rather than per setting.
119
108
  */
120
109
  export declare const ITEMS: ConfigItem[];
121
110
  export declare function extensionItems(extensions: InstalledExtension[]): ConfigItem[];
@@ -134,10 +123,10 @@ export declare function applyToolToggle(exempt: readonly string[], toolName: str
134
123
  * parent is also a row.
135
124
  *
136
125
  * So a child is drawn as a tree branch under its parent and loses the repeated
137
- * `think: research:` prefix, which is 15 columns of the same text on four
138
- * consecutive lines. `└─` on the last child, `├─` on the rest, decided from the
139
- * group's position in {@link REASONING_GROUPS} rather than a hand-kept list —
140
- * adding a fifth worker moves the corner on its own.
126
+ * `think: research:` prefix, the same text at the head of four consecutive
127
+ * lines. `└─` on the last child, `├─` on the rest, decided from the group's
128
+ * position in {@link REASONING_GROUPS} rather than a hand-kept list — adding a
129
+ * fifth worker moves the corner on its own.
141
130
  *
142
131
  * Leading spaces survive: SettingsList pads the label right, never trims it.
143
132
  */
@@ -150,8 +139,8 @@ export declare function reasoningItems(): ConfigItem[];
150
139
  * a per-group choice. The seeding step is what stops that from being a trap: on
151
140
  * the way out of `default`/`on`/`off` every OTHER group is first pinned to the
152
141
  * level it was already running at, so changing one row changes one row. Without
153
- * it, nudging `research` while in `off` would silently return the other six to
154
- * whatever the stored table happened to hold.
142
+ * it, nudging `research` while in `off` would silently return every other group
143
+ * to whatever the stored table happened to hold.
155
144
  */
156
145
  export declare function applyReasoningLevel(cfg: PiTaskConfig, group: ReasoningGroup, chosen: string): void;
157
146
  /**
@@ -192,10 +181,10 @@ export declare function createSettingsPanel(items: PanelItem[], theme: Theme,
192
181
  * Called with the row's id, its new value, and the LIST ITSELF.
193
182
  *
194
183
  * The list is handed back because some rows change what OTHER rows display:
195
- * flipping `reasoning` to off means all seven `think:` rows now run at off,
196
- * and a row's `currentValue` is a snapshot taken when the panel was built.
197
- * Without a way to write the others back, the menu shows `reasoning off`
198
- * beside seven rows still claiming `inherit` — which is what it did.
184
+ * flipping `reasoning` to off means every `think:` row now runs at off, and
185
+ * a row's `currentValue` is a snapshot taken when the panel was built.
186
+ * Without a way to write the others back, the menu would show
187
+ * `reasoning off` beside rows still claiming `inherit`.
199
188
  */
200
189
  onChange: (id: string, newValue: string, list: SettingsList) => void, onCancel: () => void): BorderedBox;
201
190
  /**
@@ -204,10 +193,10 @@ onChange: (id: string, newValue: string, list: SettingsList) => void, onCancel:
204
193
  * One list of `ConfigItem`s — so a row's display, its write-back and its section
205
194
  * are one object, the dispatch is a lookup by id, and the round-trip properties
206
195
  * in `config-items.test.ts` cover the reasoning, tool and extension families
207
- * that used to bypass the row type entirely.
196
+ * through the same row type as everything else.
208
197
  *
209
- * Fixed rows come before discovered ones within a section, which is the order
210
- * the hand-written `extra` map produced.
198
+ * Fixed rows come before discovered ones within a section, so a freshly
199
+ * installed extension appends rather than reshuffling the menu.
211
200
  */
212
201
  export declare function configRows(installed: InstalledExtension[], tools?: readonly GuardableTool[]): ConfigItem[];
213
202
  /** Render `rows` for the current config, grouped under their section headers. */
@@ -219,15 +208,12 @@ export declare function panelItems(cfg: PiTaskConfig, installed: InstalledExtens
219
208
  *
220
209
  * A row's `currentValue` in the live list is a snapshot taken when the panel was
221
210
  * built, and rows describe each other: cycling `reasoning` to `off` changes what
222
- * all seven `think:` rows run at, and cycling one group row flips the mode,
223
- * which changes the other six.
211
+ * every `think:` row runs at, and cycling one group row flips the mode, which
212
+ * changes all the others.
224
213
  *
225
- * This runs after ANY change, over EVERY row. Its predecessor,
226
- * `refreshReasoningRows`, ran after any change too but hard-coded the seven
227
- * reasoning ids plus `reasoningMode` and touched none of the other ~30 rows, so
228
- * the next cross-row dependency would have needed a fifth function. Re-reading a
229
- * `format` costs nothing, which is why there is still no list of "changes that
230
- * need a refresh" to keep correct.
214
+ * This runs after ANY change, over EVERY row. Re-reading a `format` costs
215
+ * nothing, which is why there is no list of "changes that need a refresh" to
216
+ * keep correct.
231
217
  */
232
218
  export declare function syncRows(cfg: PiTaskConfig, rows: readonly ConfigItem[], list: SettingsList): void;
233
219
  export declare function registerConfig(pi: ExtensionAPI): void;
@@ -78,8 +78,7 @@ export const SECTIONS = [
78
78
  { key: 'logging', title: 'logging' },
79
79
  { key: 'extensions', title: 'child extensions' },
80
80
  // Last on purpose. It is the longest block (a fixed timeout plus one row
81
- // per live tool, so it grows with the host) and the least often changed
82
- // in front of `unattended` it pushed every short section off the screen.
81
+ // per live tool, so it grows with the host) and the least often changed.
83
82
  { key: 'timeouts', title: 'timeouts' }
84
83
  ];
85
84
  /** Marks a header row, so onChange can ignore one and tests can find them. */
@@ -88,9 +87,8 @@ export const SECTION_ID_PREFIX = 'section:';
88
87
  * An inert titled row. No `values` ⇒ SettingsList's Enter handler no-ops on it,
89
88
  * and {@link SkipInertRows} steps the cursor straight over it.
90
89
  *
91
- * Upper case, and styled muted by {@link makeTheme}, because the dashed
92
- * lower-case form it replaces was the same case, colour and weight as the
93
- * setting labels underneath it — eight headings that read as nine more rows.
90
+ * Upper case, and styled muted by {@link makeTheme}, so a heading does not read
91
+ * as one more setting row.
94
92
  */
95
93
  function sectionHeader(title) {
96
94
  return {
@@ -132,9 +130,8 @@ function booleanItem(section, id, label, description) {
132
130
  /**
133
131
  * Every setting rendered by /task-config, in display order.
134
132
  *
135
- * Exported so the round-trip property below can be asserted over the WHOLE table
136
- * rather than per setting — the check that would have caught a forgotten arm in
137
- * either of the two ladders this replaced.
133
+ * Exported so the round-trip property in `config-items.test.ts` can be asserted
134
+ * over the WHOLE table rather than per setting.
138
135
  */
139
136
  export const ITEMS = [
140
137
  booleanItem('session', 'remote', 'remote control', 'Serve the task UI on your local network so you can follow and steer a run from '
@@ -317,13 +314,13 @@ export function applyToolToggle(exempt, toolName, watched) {
317
314
  *
318
315
  * SHOWN IN EVERY MODE, not only `custom`. Two reasons, and the second is the
319
316
  * real one:
320
- * - `SettingsList` fixes the overlay's body height from the descriptions it was
321
- * constructed with (see createSettingsPanel), so rows that appear and vanish
322
- * would leave the box sized for the wrong list.
317
+ * - {@link createSettingsPanel} pads the box to a height computed from the
318
+ * descriptions it was handed, so rows that appear and vanish would leave the
319
+ * box sized for the wrong list.
323
320
  * - The value displayed is what the group ACTUALLY runs at — resolveReasoning,
324
- * not the stored custom table. That makes the measured `default` table
325
- * readable from the menu instead of hidden in a source file, which is the
326
- * whole point of having measured it.
321
+ * not the stored custom table. In mode `off` every row reads `off` even
322
+ * though the custom table underneath is untouched, which is the honest
323
+ * answer to "what will my next child do".
327
324
  */
328
325
  const REASON_ID_PREFIX = 'reason:';
329
326
  /**
@@ -336,10 +333,10 @@ const REASON_ID_PREFIX = 'reason:';
336
333
  * parent is also a row.
337
334
  *
338
335
  * So a child is drawn as a tree branch under its parent and loses the repeated
339
- * `think: research:` prefix, which is 15 columns of the same text on four
340
- * consecutive lines. `└─` on the last child, `├─` on the rest, decided from the
341
- * group's position in {@link REASONING_GROUPS} rather than a hand-kept list —
342
- * adding a fifth worker moves the corner on its own.
336
+ * `think: research:` prefix, the same text at the head of four consecutive
337
+ * lines. `└─` on the last child, `├─` on the rest, decided from the group's
338
+ * position in {@link REASONING_GROUPS} rather than a hand-kept list — adding a
339
+ * fifth worker moves the corner on its own.
343
340
  *
344
341
  * Leading spaces survive: SettingsList pads the label right, never trims it.
345
342
  */
@@ -374,15 +371,15 @@ export function reasoningItems() {
374
371
  * a per-group choice. The seeding step is what stops that from being a trap: on
375
372
  * the way out of `default`/`on`/`off` every OTHER group is first pinned to the
376
373
  * level it was already running at, so changing one row changes one row. Without
377
- * it, nudging `research` while in `off` would silently return the other six to
378
- * whatever the stored table happened to hold.
374
+ * it, nudging `research` while in `off` would silently return every other group
375
+ * to whatever the stored table happened to hold.
379
376
  */
380
377
  export function applyReasoningLevel(cfg, group, chosen) {
381
378
  if (!REASONING_SETTINGS.includes(chosen))
382
379
  return;
383
380
  if (cfg.reasoningMode !== 'custom') {
384
381
  // Freeze the table exactly as it runs today, then switch to custom, so
385
- // opening one row cannot silently move the other six.
382
+ // opening one row cannot silently move the rest.
386
383
  cfg.reasoningLevels = effectiveReasoning(cfg);
387
384
  cfg.reasoningMode = 'custom';
388
385
  }
@@ -438,10 +435,9 @@ const DOWN_KEY = '\x1b[B';
438
435
  * Moves the cursor over the section headers and the blank rows between them.
439
436
  *
440
437
  * Those rows are decoration: they carry no `values`, so Enter already does
441
- * nothing on them. Without this they were still stops on the way down — with a
442
- * heading AND a blank line per section that is sixteen dead keypresses in a
443
- * thirty-row menu, and the panel opens with the cursor parked on a heading that
444
- * has no description to show.
438
+ * nothing on them. Without this they were still stops on the way down — a
439
+ * heading AND a blank line for every section and the panel opens with the
440
+ * cursor parked on a heading that has no description to show.
445
441
  *
446
442
  * It drives the list through its own public `handleInput` — pressing the very
447
443
  * key the user pressed, N times — rather than reaching for the private
@@ -506,10 +502,10 @@ export function createSettingsPanel(items, theme,
506
502
  * Called with the row's id, its new value, and the LIST ITSELF.
507
503
  *
508
504
  * The list is handed back because some rows change what OTHER rows display:
509
- * flipping `reasoning` to off means all seven `think:` rows now run at off,
510
- * and a row's `currentValue` is a snapshot taken when the panel was built.
511
- * Without a way to write the others back, the menu shows `reasoning off`
512
- * beside seven rows still claiming `inherit` — which is what it did.
505
+ * flipping `reasoning` to off means every `think:` row now runs at off, and
506
+ * a row's `currentValue` is a snapshot taken when the panel was built.
507
+ * Without a way to write the others back, the menu would show
508
+ * `reasoning off` beside rows still claiming `inherit`.
513
509
  */
514
510
  onChange, onCancel) {
515
511
  // A row with no `values` is a header or the blank line above one.
@@ -523,10 +519,10 @@ onChange, onCancel) {
523
519
  * One list of `ConfigItem`s — so a row's display, its write-back and its section
524
520
  * are one object, the dispatch is a lookup by id, and the round-trip properties
525
521
  * in `config-items.test.ts` cover the reasoning, tool and extension families
526
- * that used to bypass the row type entirely.
522
+ * through the same row type as everything else.
527
523
  *
528
- * Fixed rows come before discovered ones within a section, which is the order
529
- * the hand-written `extra` map produced.
524
+ * Fixed rows come before discovered ones within a section, so a freshly
525
+ * installed extension appends rather than reshuffling the menu.
530
526
  */
531
527
  export function configRows(installed, tools = []) {
532
528
  // The discovered rows carry a section like every other row — the per-tool
@@ -567,15 +563,12 @@ export function panelItems(cfg, installed, tools = []) {
567
563
  *
568
564
  * A row's `currentValue` in the live list is a snapshot taken when the panel was
569
565
  * built, and rows describe each other: cycling `reasoning` to `off` changes what
570
- * all seven `think:` rows run at, and cycling one group row flips the mode,
571
- * which changes the other six.
566
+ * every `think:` row runs at, and cycling one group row flips the mode, which
567
+ * changes all the others.
572
568
  *
573
- * This runs after ANY change, over EVERY row. Its predecessor,
574
- * `refreshReasoningRows`, ran after any change too but hard-coded the seven
575
- * reasoning ids plus `reasoningMode` and touched none of the other ~30 rows, so
576
- * the next cross-row dependency would have needed a fifth function. Re-reading a
577
- * `format` costs nothing, which is why there is still no list of "changes that
578
- * need a refresh" to keep correct.
569
+ * This runs after ANY change, over EVERY row. Re-reading a `format` costs
570
+ * nothing, which is why there is no list of "changes that need a refresh" to
571
+ * keep correct.
579
572
  */
580
573
  export function syncRows(cfg, rows, list) {
581
574
  for (const row of rows)
@@ -600,11 +593,10 @@ async function handleTaskConfig(_args, ctx, getTools = () => []) {
600
593
  // it can only be read here, when the menu opens, never at registration.
601
594
  const tools = getTools();
602
595
  if (ctx.mode !== 'tui') {
603
- // Reads the SAME `format` the panel does, so the two renderings cannot
604
- // disagree about what a setting currently says.
605
- // Built from panelItems, not a second hand-written walk of the same
606
- // tables: the two renderings used to be able to disagree about what a
607
- // setting said, and a headless run is the one place nobody would notice.
596
+ // Built from panelItems and reading the SAME `format` the panel does,
597
+ // so the two renderings cannot disagree about what a setting says. A
598
+ // second walk of the same tables is the one place nobody would notice
599
+ // them drifting, because a headless run has no panel to compare against.
608
600
  const lines = panelItems(cfg, installed, tools)
609
601
  // The blank rows between sections are there to give the TUI air.
610
602
  // One line of `|`-joined text has none to give, and an empty label
@@ -621,12 +613,10 @@ async function handleTaskConfig(_args, ctx, getTools = () => []) {
621
613
  const rows = configRows(installed, tools);
622
614
  await ctx.ui.custom((_tui, theme, _kb, done) => createSettingsPanel(renderRows(cfg, rows), theme, (id, newValue, list) => {
623
615
  // Every row parses its own value. There is no generic
624
- // fallback and no prefix ladder: the ladder this replaces
625
- // ended in one that wrote `newValue === 'on'` into whatever
626
- // field it was handed, so a new enum setting silently became
627
- // a boolean until someone noticed. A header row carries no
628
- // `values`, so SettingsList never cycles it and it matches
629
- // no row here anyway.
616
+ // fallback and no prefix ladder, so a row that forgets to
617
+ // parse cannot fall through to something that guesses. A
618
+ // header row carries no `values`, so SettingsList never
619
+ // cycles it and it matches no row here anyway.
630
620
  rows.find(row => row.id === id)?.apply(cfg, newValue);
631
621
  syncRows(cfg, rows, list);
632
622
  saveConfig(cfg).catch(() => { });
@@ -4,28 +4,28 @@ import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
4
4
  * the live session rather than named by hand.
5
5
  *
6
6
  * WHY DISCOVERY AND NOT A HAND-EDITED NAME LIST: the watchdog arms on ANY tool
7
- * (see task/command-watchdog.ts), which is correct for `bash` — pi's bash takes
8
- * an OPTIONAL `timeout` with no default, so an unbounded command runs forever —
9
- * but wrong for an extension tool that already owns a longer, bounded contract
10
- * of its own. Those tools get aborted mid-transaction at the generic ceiling.
11
- * The operator has to be able to say "not this one", and the only identity that
12
- * survives a rename or an uninstall is the one pi itself reports.
7
+ * (see task/command-watchdog.ts), which is correct for `bash` — its `timeout`
8
+ * is optional and has no default (`resolveTimeoutMs` returns undefined when it
9
+ * is omitted), so an unbounded command runs forever but wrong for an
10
+ * extension tool that already owns a longer, bounded contract of its own. Those
11
+ * tools get aborted mid-transaction at the generic ceiling. The operator has to
12
+ * be able to say "not this one", and the only identity that survives a rename
13
+ * or an uninstall is the one pi itself reports.
13
14
  *
14
- * MEASURED against pi 0.83.0 (`pi.getAllTools()`), not assumed:
15
- * - built-ins report `source: "builtin"`, `path: "<builtin:bash>"`
16
- * - extension tools report the extension's real entry-point path — the SAME
15
+ * What `pi.getAllTools()` reports:
16
+ * - built-ins carry `source: "builtin"` and a synthetic `<builtin:name>` path
17
+ * - extension tools carry the extension's real entry-point path — the SAME
17
18
  * identity `extensionWhitelist` keys on (see extension-list.ts)
18
- * - `getAllTools()` THROWS during extension loading ("Extension runtime not
19
- * initialized"); it is only callable from `session_start` onward, which is
20
- * why this is read when the menu opens and never at registration.
21
- * - `getActiveTools()` is a strict SUBSET (4 of 7 built-ins in a plain
22
- * session), so it is the wrong source: a tool the model isn't currently
23
- * offered is still a tool the watchdog would arm on if it ran.
19
+ * - it THROWS during extension loading ("Extension runtime not initialized"),
20
+ * so this is read when the menu opens and never at registration
21
+ * - `getActiveTools()` returns only what the model is currently offered, which
22
+ * is the wrong source: a tool that is not offered right now is still a tool
23
+ * the watchdog would arm on if it ran.
24
24
  */
25
25
  export interface GuardableTool {
26
26
  /** Exact tool name — the watchdog's key, and what the config stores. */
27
27
  name: string;
28
- /** Provenance shown in the menu, e.g. "built in" or "npm:pi-fable". */
28
+ /** Provenance shown in the menu, e.g. "built in" or "npm:pi-fable (/path)". */
29
29
  origin: string;
30
30
  }
31
31
  /**
@@ -1,4 +1,4 @@
1
- /** `source` values pi reports for its own tools rather than an extension's. */
1
+ /** The `source` pi reports for its own tools rather than an extension's. */
2
2
  const BUILTIN_SOURCE = 'builtin';
3
3
  /**
4
4
  * Human provenance for a tool's source metadata. `source` is pi's own word for
@@ -25,14 +25,20 @@ export interface AskSpec {
25
25
  displayQuestion?: string;
26
26
  /** Plain question text for the browser card. */
27
27
  question: string;
28
- /** Primary recommended option, prefilled in the local TUI. */
28
+ /**
29
+ * Primary recommended option. It is the remote card's "✓ Accept" answer.
30
+ * Locally it is handed to `ctx.ui.input` as the placeholder argument, which
31
+ * pi's interactive input component takes and never reads — so with no
32
+ * `options` the local box opens empty.
33
+ */
29
34
  recommended?: string;
30
35
  /**
31
- * Placeholder for the local TUI text input when there is NO recommended
32
- * option. Local-only: the remote card must not see it, or it would render as
33
- * an acceptable recommendation ("✓ Accept" answering with placeholder text).
34
- * Used by the steer prompt, whose hint ("type guidance, or leave empty…") is
35
- * instructional copy, not an answer.
36
+ * Instructional copy for the local TUI text input when there is NO
37
+ * recommended option. Local-only, and deliberately absent from the
38
+ * PromptMessage below: on the remote it would render as an acceptable
39
+ * recommendation (" Accept" answering with instructional text). Its one
40
+ * producer is the steer prompt. Like `recommended` it reaches pi as the
41
+ * `input` placeholder, which pi's input component ignores.
36
42
  */
37
43
  localPlaceholder?: string;
38
44
  /** Secondary recommended option shown as a second button on the remote. */
@@ -44,8 +50,10 @@ export interface AskSpec {
44
50
  * a bare text input — one option per line, arrow-key navigable. Each entry's
45
51
  * `label` is what the picker displays; its `value` is what ask() resolves to
46
52
  * when chosen. A built-in "type a different answer" entry is appended that
47
- * falls back to a text input, preserving the free-text override. Used for the
48
- * binary A/B grill/clarify fork. Remote browsers ignore this and keep
53
+ * falls back to a text input, preserving the free-text override. Produced by
54
+ * the two-option grill/clarify fork, whose cards are labelled `A:` and `B:`
55
+ * (buildOptionCards), and by /task-plan's picker. The PromptMessage built in
56
+ * ask() carries no `options` field, so remote browsers never see it and keep
49
57
  * rendering recommended/recommended2 as buttons.
50
58
  */
51
59
  options?: {
@@ -69,8 +77,9 @@ export interface AskSpec {
69
77
  * which the remote already covers with the recommended/recommended2 buttons —
70
78
  * these are ACTIONS that mean something other than "here is my answer", so
71
79
  * the remote cannot express them by any existing field. /task-plan's "ask the
72
- * model" and "proceed to execution" are the only producers; every other call
73
- * site omits this and the card is byte-for-byte what it was.
80
+ * model" and "proceed to execution" are the only producers; for every other
81
+ * prompt the list is empty, and the browser's makeActionBtns then appends
82
+ * nothing to the card.
74
83
  */
75
84
  actions?: {
76
85
  label: string;
@@ -62,8 +62,9 @@ export class SessionUI {
62
62
  // service worker drops the banner if a window is visible+focused (sw.ts),
63
63
  // so we always push and let delivery-time visibility decide.
64
64
  void pushNotify('pi needs your input', spec.question, 'pi-prompt').catch(() => { });
65
- // Local: resolves to a value/undefined, or undefined on abort. Swallow
66
- // the rejection some implementations throw on abort so it never leaks.
65
+ // Local: resolves to a value, or to undefined on cancel or abort. The
66
+ // catch is belt-and-braces a rejection here would surface as an
67
+ // unhandled one rather than as a lost race.
67
68
  const local = this.ctx.hasUI ?
68
69
  this.askLocal(spec, ac.signal).catch(() => undefined)
69
70
  : new Promise(() => { });
@@ -1,4 +1,6 @@
1
- // globalThis persists across jiti module re-evaluations on session switches
1
+ // pi loads an extension through `createJiti(..., {moduleCache: false})`, so a
2
+ // reload re-evaluates this module and resets its module-level state. globalThis
3
+ // survives that, which is why the client set lives there.
2
4
  const g = globalThis;
3
5
  if (!g.__piRemoteClients)
4
6
  g.__piRemoteClients = new Set();
@@ -25,11 +25,11 @@ export function setupEvents(pi) {
25
25
  if (errorMessage || ae.reason === 'error') {
26
26
  const message = errorMessage || 'Request failed';
27
27
  addError(message);
28
- // No push here: pi-task only notifies for the two cases the user
29
- // cares about — needing their input (the grill/clarify dialog, see
30
- // bridge.ask) and a top-level /task or /task-auto run finishing
31
- // (orchestrator/auto-orchestrator). A push on every host agent
32
- // error — most of them outside any task — is just noise.
28
+ // No push here: every pushNotify call site in src/ is one of
29
+ // two things — needing the user's input (bridge.ask) or a
30
+ // top-level run finishing (runSingleTask under `notifyFinish`,
31
+ // and run-bracket's announceTerminal). A push on every host
32
+ // agent error — most of them outside any task — is just noise.
33
33
  }
34
34
  }
35
35
  });
@@ -47,12 +47,13 @@ export function setupEvents(pi) {
47
47
  });
48
48
  pi.on('agent_end', (_event, ctx) => {
49
49
  agentEnd(ctx.getContextUsage(), ctx.model?.name);
50
- // Deliberately no push: agent_end fires on EVERY host turn — every chat
51
- // reply, every internal phase turn inside /task, and every internal /task
52
- // run inside /task-auto — so a "Task finished" push here floods the device.
53
- // The real "a run finished" push is fired from the top-level command
54
- // handlers instead (orchestrator handleTask/handleTaskResume, and
55
- // auto-orchestrator's runAutoLoop), which never fire for internal runs.
50
+ // Deliberately no push: agent_end fires on EVERY host-session turn —
51
+ // every chat reply, and the implementation turn of every task, including
52
+ // each task inside a /task-auto run — so a "Task finished" push here
53
+ // floods the device. (Phase children are spawned pi processes running
54
+ // --no-extensions, so they never reach this handler at all.) The real
55
+ // "a run finished" push is gated on `notifyFinish`, which only the
56
+ // top-level command handlers pass.
56
57
  });
57
58
  pi.on('input', (event, _ctx) => {
58
59
  if (event.source === 'interactive' && typeof event.text === 'string') {
@@ -25,7 +25,7 @@ export interface Turn {
25
25
  role: 'user' | 'assistant' | 'system';
26
26
  /** User text, error text, or a system note. Assistant content lives in `parts`. */
27
27
  text?: string;
28
- /** Ordered assistant content (text + tools). */
28
+ /** Ordered assistant content text, thinking and tool parts, interleaved. */
29
29
  parts?: Part[];
30
30
  error?: boolean;
31
31
  /** Epoch ms when the turn was committed — the client renders a dim HH:MM. */
@@ -7,7 +7,8 @@ export interface PromptMessage {
7
7
  /**
8
8
  * Buttons that answer with their own `value` instead of with an answer to the
9
9
  * question — /task-plan's "ask the model" and "proceed to execution". Absent
10
- * on every other prompt, so an older card renders exactly as before.
10
+ * on every other prompt, and the browser's makeActionBtns then appends
11
+ * nothing to the card.
11
12
  */
12
13
  actions?: {
13
14
  label: string;
@@ -67,8 +68,10 @@ export interface ContextUsage {
67
68
  contextWindow?: number;
68
69
  percent?: number;
69
70
  }
70
- /** Seeds the context-usage bar for a freshly-connected client (the live value is
71
- * otherwise only carried on agent_end). */
71
+ /** A standalone context-usage update. The browser handles it, but nothing in
72
+ * `src/` sends one: a connecting client is seeded from the snapshot's `context`
73
+ * field, and the live value rides on `agent_end`. The only caller of
74
+ * `setContext`, which emits this, is the test suite. */
72
75
  export interface ContextMessage {
73
76
  type: 'context';
74
77
  contextUsage: ContextUsage;
@@ -1,5 +1,6 @@
1
1
  // Wire format shared by the WS server and the inline browser app.
2
- // Keep these shapes in sync with the hand-written switch in ui.ts.
2
+ // Keep these shapes in sync with the hand-written `switch (msg.type)` in
3
+ // ui-script.ts, which is where the browser decodes them.
3
4
  export function isClientMessage(x) {
4
5
  if (typeof x !== 'object' || x === null)
5
6
  return false;
@@ -11,27 +11,27 @@ export interface VapidKeys {
11
11
  publicKey: string;
12
12
  privateKey: string;
13
13
  }
14
- /** Where the VAPID keypair is persisted losing these keys invalidates every
15
- * existing browser subscription. */
14
+ /** Where the VAPID keypair is persisted. The browser subscribes with this
15
+ * public key as its applicationServerKey (see ui-script.ts), so the pair has to
16
+ * outlive the process that created it. */
16
17
  export declare function vapidStorePath(): string;
17
18
  /** Where browser push subscriptions are mirrored to disk (next to vapid.json).
18
- * Without this, a server restart e.g. after a rebuild silently drops every
19
- * device: the in-memory store is empty, and a backgrounded/suspended PWA won't
20
- * re-register until the user next foregrounds it, which is exactly when the push
21
- * is no longer useful. The in-memory store stays authoritative within a process;
22
- * this is its durable mirror. */
19
+ * Without this a server restart starts with an empty store and reaches nobody
20
+ * until every device happens to re-register. The in-memory store stays
21
+ * authoritative within a process; this is its durable mirror. */
23
22
  export declare function subscriptionsStorePath(): string;
24
23
  /** Diagnostic log file. Defaults to /tmp for easy tailing; override with
25
24
  * PI_REMOTE_PUSH_LOG. (The VAPID key stays in its durable XDG location.) */
26
25
  export declare function pushLogPath(): string;
27
- /** VAPID JWT `sub` claim. Apple (unlike Chrome/FCM) validates this and rejects
28
- * tokens with an unroutable subject like `mailto:...@localhost` as BadJwtToken,
29
- * so the default is a real https URL. Override with PI_REMOTE_PUSH_SUBJECT
30
- * (e.g. your own `mailto:you@domain.com`). */
26
+ /** VAPID JWT `sub` claim. web-push's validateSubject requires a parseable URL
27
+ * whose protocol is `https:` or `mailto:` and throws otherwise, so the default
28
+ * is a real https URL. Override with PI_REMOTE_PUSH_SUBJECT (e.g. your own
29
+ * `mailto:you@domain.com`). */
31
30
  export declare function pushSubject(): string;
32
31
  /** Append a timestamped diagnostic line — but only when PI_REMOTE_PUSH_DEBUG is
33
- * set, so it stays silent (and test-safe) by default. Push failures are
34
- * otherwise swallowed, so this is the way to see Apple's HTTP status codes. */
32
+ * set, so it stays silent (and test-safe) by default. deliver() swallows every
33
+ * send failure, so this is the only way to see the push service's status
34
+ * codes. */
35
35
  export declare function logPush(line: string): void;
36
36
  /** Load the persisted VAPID keypair, generating and saving one on first use or
37
37
  * if the stored file is missing/corrupt. Stable across restarts. */
@@ -54,8 +54,8 @@ export declare function deliver(targets: PushSubscriptionJSON[], payload: string
54
54
  }>;
55
55
  /** The VAPID public key the browser needs as its applicationServerKey. */
56
56
  export declare function publicKey(): string;
57
- /** Send a notification to all subscribed devices. Best-effort: delivery is
58
- * server→push-service→device, so it reaches a suspended iOS PWA that the
59
- * in-page Notification API never could. */
57
+ /** Send a notification to all subscribed devices. Best-effort, and the route is
58
+ * server→push-service→device, so it does not need the page to be open the way
59
+ * the in-page Notification API does. */
60
60
  export declare function pushNotify(title: string, body: string, tag?: string): Promise<void>;
61
61
  export {};