@pi-unipi/unipi 3.0.0-alpha.2 → 3.0.0-alpha.21

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 +292 -0
  2. package/README.md +8 -11
  3. package/docs/prefix-cache-architecture.md +14 -0
  4. package/package.json +22 -24
  5. package/packages/ask-user/README.md +55 -107
  6. package/packages/ask-user/ask-ui.ts +306 -732
  7. package/packages/ask-user/clipboard.ts +50 -0
  8. package/packages/ask-user/config.ts +74 -78
  9. package/packages/ask-user/package.json +2 -2
  10. package/packages/ask-user/questions.ts +151 -0
  11. package/packages/ask-user/skills/ask-user/SKILL.md +59 -133
  12. package/packages/ask-user/tools.ts +198 -432
  13. package/packages/autocomplete/package.json +1 -1
  14. package/packages/autocomplete/src/constants.ts +38 -43
  15. package/packages/autocomplete/src/sorting.ts +8 -0
  16. package/packages/background-tasks/package.json +2 -2
  17. package/packages/background-tasks/src/config.ts +0 -73
  18. package/packages/background-tasks/src/index.ts +20 -16
  19. package/packages/background-tasks/src/registry.ts +1 -171
  20. package/packages/background-tasks/src/types.ts +0 -32
  21. package/packages/btw/README.md +13 -56
  22. package/packages/btw/extensions/btw.ts +403 -1796
  23. package/packages/btw/package.json +5 -2
  24. package/packages/btw/skills/btw/SKILL.md +7 -143
  25. package/packages/compactor/README.md +56 -287
  26. package/packages/compactor/package.json +5 -9
  27. package/packages/compactor/skills/compactor/SKILL.md +13 -20
  28. package/packages/compactor/src/card.ts +90 -0
  29. package/packages/compactor/src/commands/index.ts +73 -130
  30. package/packages/compactor/src/compaction/compact-args.ts +5 -3
  31. package/packages/compactor/src/compaction/filter-noise.ts +1 -1
  32. package/packages/compactor/src/compaction/hooks.ts +487 -311
  33. package/packages/compactor/src/compaction/source.ts +178 -0
  34. package/packages/compactor/src/compaction/summarize.ts +586 -52
  35. package/packages/compactor/src/config/manager.ts +130 -127
  36. package/packages/compactor/src/config/schema.ts +32 -48
  37. package/packages/compactor/src/index.ts +40 -431
  38. package/packages/compactor/src/info-screen.ts +44 -190
  39. package/packages/compactor/src/session/recall-blocks.ts +1 -1
  40. package/packages/compactor/src/stats.ts +76 -0
  41. package/packages/compactor/src/tools/context-budget.ts +17 -34
  42. package/packages/compactor/src/tools/ctx-doctor.ts +45 -36
  43. package/packages/compactor/src/tools/register.ts +29 -269
  44. package/packages/compactor/src/types.ts +47 -186
  45. package/packages/core/README.md +25 -0
  46. package/packages/core/child-agent.ts +1 -0
  47. package/packages/core/command-echo.ts +63 -0
  48. package/packages/core/compaction-context.ts +41 -0
  49. package/packages/core/constants.ts +8 -38
  50. package/packages/core/events.ts +0 -53
  51. package/packages/core/fusion-status.ts +4 -0
  52. package/packages/core/global.d.ts +10 -0
  53. package/packages/core/harness-messages.ts +392 -0
  54. package/packages/core/index.ts +14 -0
  55. package/packages/core/kanboard-status.ts +49 -0
  56. package/packages/core/long-horizon-owner-status.ts +46 -0
  57. package/packages/core/model-cache.ts +81 -7
  58. package/packages/core/package.json +6 -3
  59. package/packages/core/src/attach/detect.ts +163 -0
  60. package/packages/core/src/child-agent/child-args.ts +31 -0
  61. package/packages/core/src/child-agent/delivery.ts +41 -0
  62. package/packages/core/src/child-agent/index.ts +5 -0
  63. package/packages/core/src/child-agent/readers.ts +203 -0
  64. package/packages/core/src/child-agent/runtime.ts +584 -0
  65. package/packages/core/src/evidence.ts +78 -0
  66. package/packages/core/src/hints/browser.ts +278 -0
  67. package/packages/core/src/hints/crab-data.ts +19 -0
  68. package/packages/core/src/hints/index.ts +865 -0
  69. package/packages/core/src/hints/lines.ts +607 -0
  70. package/packages/core/src/hints/store.ts +120 -0
  71. package/packages/core/src/jev/chatter.ts +24 -0
  72. package/packages/core/src/jev/settings.ts +177 -14
  73. package/packages/core/src/package-colors.ts +2 -0
  74. package/packages/core/src/settings/catalog.ts +39 -15
  75. package/packages/core/src/settings/engine.ts +48 -2
  76. package/packages/core/src/settings/hub.ts +83 -20
  77. package/packages/core/src/settings/open.ts +49 -0
  78. package/packages/core/src/settings/schema.ts +27 -7
  79. package/packages/core/src/tui/hub-kit.ts +18 -5
  80. package/packages/core/src/tui/kit.ts +198 -0
  81. package/packages/core/src/tui/progress.ts +73 -0
  82. package/packages/core/src/turn/arbiter.ts +290 -0
  83. package/packages/footer/README.md +4 -6
  84. package/packages/footer/package.json +3 -3
  85. package/packages/footer/src/glance-editor.ts +19 -11
  86. package/packages/footer/src/help.ts +1 -1
  87. package/packages/footer/src/index.ts +36 -3
  88. package/packages/footer/src/presets.ts +3 -4
  89. package/packages/footer/src/rendering/icons.ts +0 -20
  90. package/packages/footer/src/segments/compactor.ts +52 -142
  91. package/packages/footer/src/segments/status-ext.ts +0 -1
  92. package/packages/fusion/README.md +14 -4
  93. package/packages/fusion/package.json +4 -3
  94. package/packages/fusion/src/child-args.ts +1 -0
  95. package/packages/fusion/src/index.ts +161 -8
  96. package/packages/fusion/src/pi-settings.ts +57 -0
  97. package/packages/fusion/src/picker.ts +186 -51
  98. package/packages/fusion/src/preset.ts +56 -2
  99. package/packages/fusion/src/prompts.ts +1 -1
  100. package/packages/fusion/src/sidekick-runtime.ts +1 -420
  101. package/packages/fusion/src/tools.ts +107 -128
  102. package/packages/fusion/src/transcript.ts +27 -85
  103. package/packages/info-screen/package.json +2 -2
  104. package/packages/input-shortcuts/README.md +18 -30
  105. package/packages/input-shortcuts/package.json +2 -2
  106. package/packages/input-shortcuts/src/burst.ts +88 -0
  107. package/packages/input-shortcuts/src/chord-overlay.ts +20 -70
  108. package/packages/input-shortcuts/src/cleared-input.ts +97 -0
  109. package/packages/input-shortcuts/src/index.ts +99 -193
  110. package/packages/input-shortcuts/src/last-response.ts +40 -0
  111. package/packages/input-shortcuts/src/registers.ts +8 -23
  112. package/packages/input-shortcuts/src/types.ts +4 -16
  113. package/packages/input-shortcuts/src/undo-redo.ts +59 -47
  114. package/packages/kanboard/README.md +51 -47
  115. package/packages/kanboard/index.ts +293 -55
  116. package/packages/kanboard/package.json +8 -8
  117. package/packages/kanboard/skills/kanboard/SKILL.md +61 -27
  118. package/packages/kanboard/src/badges.ts +93 -0
  119. package/packages/kanboard/src/bin.ts +4 -2
  120. package/packages/kanboard/src/commands.ts +218 -84
  121. package/packages/kanboard/src/debug.ts +20 -0
  122. package/packages/kanboard/src/guard.ts +267 -109
  123. package/packages/kanboard/src/monitor.ts +330 -0
  124. package/packages/kanboard/src/notice-buffer.ts +74 -0
  125. package/packages/kanboard/src/progress.ts +27 -0
  126. package/packages/kanboard/src/reminders.ts +234 -0
  127. package/packages/kanboard/src/settings.ts +69 -15
  128. package/packages/kanboard/src/shapes.ts +5 -0
  129. package/packages/long-horizon/index.ts +190 -13
  130. package/packages/long-horizon/package.json +3 -3
  131. package/packages/long-horizon/src/commands.ts +103 -7
  132. package/packages/long-horizon/src/compaction-brief.ts +35 -0
  133. package/packages/long-horizon/src/engine/continuation.ts +84 -15
  134. package/packages/long-horizon/src/engine/goal-state.ts +64 -13
  135. package/packages/long-horizon/src/engine/nudge-stash.ts +71 -0
  136. package/packages/long-horizon/src/engine/ralph.ts +3 -2
  137. package/packages/long-horizon/src/engine/runaway.ts +68 -11
  138. package/packages/long-horizon/src/engine/verifier.ts +19 -0
  139. package/packages/long-horizon/src/gate.ts +37 -12
  140. package/packages/long-horizon/src/judge/resolve.ts +1 -0
  141. package/packages/long-horizon/src/owner.ts +35 -2
  142. package/packages/long-horizon/src/progress.ts +87 -0
  143. package/packages/long-horizon/src/prompts/goal.ts +1 -1
  144. package/packages/long-horizon/src/runtime.ts +172 -18
  145. package/packages/long-horizon/src/settings.ts +54 -39
  146. package/packages/long-horizon/src/tools/goal.ts +6 -0
  147. package/packages/long-horizon/src/tools/graph.ts +1 -1
  148. package/packages/long-horizon/src/tools/swarm.ts +3 -3
  149. package/packages/mcp/package.json +2 -2
  150. package/packages/memory/commands.ts +7 -2
  151. package/packages/memory/index.ts +210 -32
  152. package/packages/memory/package.json +3 -3
  153. package/packages/memory/save-session.ts +264 -0
  154. package/packages/memory/settings.ts +17 -0
  155. package/packages/memory/tools.ts +253 -203
  156. package/packages/notify/package.json +2 -2
  157. package/packages/skill-registry/README.md +53 -16
  158. package/packages/skill-registry/index.ts +230 -0
  159. package/packages/skill-registry/package.json +19 -8
  160. package/packages/skill-registry/src/editor.ts +206 -0
  161. package/packages/skill-registry/src/judge.ts +289 -0
  162. package/packages/skill-registry/src/registry.ts +87 -0
  163. package/packages/skill-registry/src/settings.ts +259 -0
  164. package/packages/skill-registry/src/vault.ts +80 -0
  165. package/packages/subagents/README.md +39 -119
  166. package/packages/subagents/package.json +6 -13
  167. package/packages/subagents/skills/subagents/SKILL.md +18 -42
  168. package/packages/subagents/src/agents.ts +213 -0
  169. package/packages/subagents/src/cards.ts +182 -0
  170. package/packages/subagents/src/index.ts +609 -1084
  171. package/packages/subagents/src/manager.ts +429 -0
  172. package/packages/subagents/src/profiles.ts +130 -0
  173. package/packages/subagents/src/transcript.ts +154 -0
  174. package/packages/subagents/src/ui.ts +389 -0
  175. package/packages/unipi/bundled.js +39756 -45569
  176. package/packages/unipi/index.ts +55 -10
  177. package/packages/updater/package.json +2 -2
  178. package/packages/utility/README.md +76 -69
  179. package/packages/utility/package.json +2 -2
  180. package/packages/utility/skills/image/SKILL.md +37 -0
  181. package/packages/utility/skills/utility/SKILL.md +17 -60
  182. package/packages/utility/src/answer/extract.ts +128 -0
  183. package/packages/utility/src/answer/index.ts +213 -0
  184. package/packages/utility/src/answer/reply.ts +133 -0
  185. package/packages/utility/src/answer/web.ts +167 -0
  186. package/packages/utility/src/attach/index.ts +205 -0
  187. package/packages/utility/src/commands.ts +38 -142
  188. package/packages/utility/src/diagnostics/engine.ts +50 -5
  189. package/packages/utility/src/image/index.ts +33 -0
  190. package/packages/utility/src/image/models.ts +221 -0
  191. package/packages/{image/src → utility/src/image}/recognize.ts +2 -2
  192. package/packages/utility/src/image/settings.ts +178 -0
  193. package/packages/{image/src/image-source.ts → utility/src/image/source.ts} +1 -1
  194. package/packages/utility/src/image/tools.ts +168 -0
  195. package/packages/utility/src/image/transports.ts +186 -0
  196. package/packages/utility/src/index.ts +68 -389
  197. package/packages/utility/src/lifecycle/cleanup.ts +116 -311
  198. package/packages/utility/src/rename/gate.ts +102 -0
  199. package/packages/utility/src/rename/index.ts +191 -0
  200. package/packages/utility/src/rename/session.ts +170 -0
  201. package/packages/utility/src/render/delegated.ts +285 -0
  202. package/packages/utility/src/render/harness.ts +683 -0
  203. package/packages/utility/src/render/parse.ts +156 -0
  204. package/packages/utility/src/render/pi-settings.ts +38 -0
  205. package/packages/utility/src/render/reply-bg.ts +307 -0
  206. package/packages/utility/src/render/simple.ts +724 -0
  207. package/packages/utility/src/render/spacing.ts +235 -0
  208. package/packages/utility/src/render/styled.ts +251 -0
  209. package/packages/utility/src/render/tools.ts +353 -0
  210. package/packages/utility/src/settings.ts +166 -233
  211. package/packages/utility/src/types.ts +1 -222
  212. package/packages/watchdog/index.ts +17 -6
  213. package/packages/watchdog/package.json +3 -3
  214. package/packages/watchdog/src/config.ts +3 -2
  215. package/packages/web-api/package.json +2 -2
  216. package/packages/workflow/README.md +3 -0
  217. package/packages/workflow/index.ts +0 -2
  218. package/packages/workflow/package.json +2 -2
  219. package/packages/workflow/src/permission/decide.ts +6 -4
  220. package/packages/workflow/src/permission/index.ts +17 -7
  221. package/packages/workflow/src/permission/settings.ts +39 -4
  222. package/packages/workflow/src/plan/index.ts +19 -4
  223. package/packages/background-tasks/extensions/delegate-child.ts +0 -1
  224. package/packages/background-tasks/src/context-parent-snapshot.ts +0 -142
  225. package/packages/background-tasks/src/context-token-budget.ts +0 -903
  226. package/packages/background-tasks/src/context-visible-conversation-v2.ts +0 -551
  227. package/packages/background-tasks/src/delegate/artifacts.ts +0 -487
  228. package/packages/background-tasks/src/delegate/budget.ts +0 -415
  229. package/packages/background-tasks/src/delegate/hook-contract-evidence.json +0 -18
  230. package/packages/background-tasks/src/delegate/hook-contract.ts +0 -154
  231. package/packages/background-tasks/src/delegate/launch.ts +0 -484
  232. package/packages/background-tasks/src/delegate/result-package.ts +0 -459
  233. package/packages/background-tasks/src/delegate/runner.ts +0 -430
  234. package/packages/background-tasks/src/delegate/seed.ts +0 -423
  235. package/packages/background-tasks/src/delegate/types.ts +0 -323
  236. package/packages/background-tasks/src/delegate-child-extension.ts +0 -978
  237. package/packages/background-tasks/src/delegate-extension.ts +0 -654
  238. package/packages/background-tasks/src/fixtures/delegate-context-incident.json +0 -17
  239. package/packages/compactor/skills/compactor-detail/SKILL.md +0 -116
  240. package/packages/compactor/skills/compactor-doctor/SKILL.md +0 -71
  241. package/packages/compactor/skills/compactor-stats/SKILL.md +0 -51
  242. package/packages/compactor/src/compaction/build-sections.ts +0 -76
  243. package/packages/compactor/src/compaction/extract/goals.ts +0 -36
  244. package/packages/compactor/src/compaction/extract/preferences.ts +0 -40
  245. package/packages/compactor/src/compaction/format.ts +0 -53
  246. package/packages/compactor/src/compaction/merge.ts +0 -143
  247. package/packages/compactor/src/config/presets.ts +0 -160
  248. package/packages/compactor/src/executor/executor.ts +0 -233
  249. package/packages/compactor/src/executor/runtime.ts +0 -115
  250. package/packages/compactor/src/security/evaluator.ts +0 -89
  251. package/packages/compactor/src/security/policy.ts +0 -96
  252. package/packages/compactor/src/security/scanner.ts +0 -65
  253. package/packages/compactor/src/session/auto-inject.ts +0 -60
  254. package/packages/compactor/src/session/db.ts +0 -325
  255. package/packages/compactor/src/session/extract.ts +0 -144
  256. package/packages/compactor/src/session/resume-inject.ts +0 -64
  257. package/packages/compactor/src/session/snapshot.ts +0 -327
  258. package/packages/compactor/src/tools/ctx-batch-execute.ts +0 -41
  259. package/packages/compactor/src/tools/ctx-execute-file.ts +0 -23
  260. package/packages/compactor/src/tools/ctx-execute.ts +0 -23
  261. package/packages/compactor/src/tools/ctx-stats.ts +0 -96
  262. package/packages/image/README.md +0 -99
  263. package/packages/image/package.json +0 -61
  264. package/packages/image/skills/image/SKILL.md +0 -76
  265. package/packages/image/src/generate.ts +0 -256
  266. package/packages/image/src/index.ts +0 -135
  267. package/packages/image/src/models.ts +0 -519
  268. package/packages/image/src/openai-images-api.ts +0 -282
  269. package/packages/image/src/register-providers.ts +0 -209
  270. package/packages/image/src/settings.ts +0 -173
  271. package/packages/image/src/tools.ts +0 -326
  272. package/packages/input-shortcuts/src/clipboard.ts +0 -119
  273. package/packages/kanboard/src/runner.ts +0 -817
  274. package/packages/skill-registry/skills/auto/SKILL.md +0 -465
  275. package/packages/skill-registry/skills/brainstorm/SKILL.md +0 -219
  276. package/packages/skill-registry/skills/chore-create/SKILL.md +0 -315
  277. package/packages/skill-registry/skills/chore-execute/SKILL.md +0 -314
  278. package/packages/skill-registry/skills/consolidate/SKILL.md +0 -142
  279. package/packages/skill-registry/skills/consultant/SKILL.md +0 -97
  280. package/packages/skill-registry/skills/debug/SKILL.md +0 -228
  281. package/packages/skill-registry/skills/document/SKILL.md +0 -120
  282. package/packages/skill-registry/skills/fix/SKILL.md +0 -212
  283. package/packages/skill-registry/skills/gather-context/SKILL.md +0 -145
  284. package/packages/skill-registry/skills/plan/SKILL.md +0 -231
  285. package/packages/skill-registry/skills/quick-fix/SKILL.md +0 -135
  286. package/packages/skill-registry/skills/quick-work/SKILL.md +0 -110
  287. package/packages/skill-registry/skills/research/SKILL.md +0 -251
  288. package/packages/skill-registry/skills/review-work/SKILL.md +0 -187
  289. package/packages/skill-registry/skills/scan-issues/SKILL.md +0 -195
  290. package/packages/skill-registry/skills/work/SKILL.md +0 -218
  291. package/packages/skill-registry/skills/worktree-create/SKILL.md +0 -69
  292. package/packages/skill-registry/skills/worktree-list/SKILL.md +0 -78
  293. package/packages/skill-registry/skills/worktree-merge/SKILL.md +0 -89
  294. package/packages/subagents/agents/delegate.md +0 -14
  295. package/packages/subagents/agents/oracle.md +0 -78
  296. package/packages/subagents/agents/researcher.md +0 -52
  297. package/packages/subagents/agents/reviewer.md +0 -80
  298. package/packages/subagents/agents/scout.md +0 -50
  299. package/packages/subagents/agents/worker.md +0 -59
  300. package/packages/subagents/prompts/council.md +0 -48
  301. package/packages/subagents/prompts/gather-context-and-clarify.md +0 -13
  302. package/packages/subagents/prompts/parallel-cleanup.md +0 -59
  303. package/packages/subagents/prompts/parallel-research.md +0 -50
  304. package/packages/subagents/prompts/parallel-review.md +0 -54
  305. package/packages/subagents/prompts/review-loop.md +0 -43
  306. package/packages/subagents/skills/council-mode/SKILL.md +0 -230
  307. package/packages/subagents/skills/subagents/references/constraints-and-recipes.md +0 -259
  308. package/packages/subagents/skills/subagents/references/execution-controls.md +0 -454
  309. package/packages/subagents/skills/subagents/references/management-authoring-rpc.md +0 -161
  310. package/packages/subagents/skills/subagents/references/multi-lane-orchestration.md +0 -39
  311. package/packages/subagents/skills/subagents/references/prompting-and-roles.md +0 -267
  312. package/packages/subagents/src/acceptance.ts +0 -331
  313. package/packages/subagents/src/agent-manager.ts +0 -405
  314. package/packages/subagents/src/agent-memory.ts +0 -300
  315. package/packages/subagents/src/agent-overrides.ts +0 -183
  316. package/packages/subagents/src/agent-runner.ts +0 -271
  317. package/packages/subagents/src/async-runner.ts +0 -422
  318. package/packages/subagents/src/authority-policy.ts +0 -47
  319. package/packages/subagents/src/budgets.ts +0 -285
  320. package/packages/subagents/src/child-safety.ts +0 -140
  321. package/packages/subagents/src/config.ts +0 -249
  322. package/packages/subagents/src/conversation-viewer.ts +0 -281
  323. package/packages/subagents/src/core-compat.ts +0 -94
  324. package/packages/subagents/src/custom-agents.ts +0 -343
  325. package/packages/subagents/src/file-system-retry.ts +0 -50
  326. package/packages/subagents/src/fleet-data.ts +0 -105
  327. package/packages/subagents/src/fleet-view.ts +0 -322
  328. package/packages/subagents/src/foreground-detach.ts +0 -59
  329. package/packages/subagents/src/fork-context.ts +0 -285
  330. package/packages/subagents/src/global.d.ts +0 -7
  331. package/packages/subagents/src/guide.ts +0 -129
  332. package/packages/subagents/src/mission-state.ts +0 -133
  333. package/packages/subagents/src/mission-store.ts +0 -436
  334. package/packages/subagents/src/output-limits.ts +0 -142
  335. package/packages/subagents/src/parity-types.ts +0 -315
  336. package/packages/subagents/src/pi-args.ts +0 -167
  337. package/packages/subagents/src/result-files.ts +0 -232
  338. package/packages/subagents/src/result-watcher.ts +0 -221
  339. package/packages/subagents/src/retained-children.ts +0 -176
  340. package/packages/subagents/src/run-fanout-budget.ts +0 -356
  341. package/packages/subagents/src/scheduled-runs.ts +0 -349
  342. package/packages/subagents/src/schemas.ts +0 -263
  343. package/packages/subagents/src/slash-commands.ts +0 -80
  344. package/packages/subagents/src/supervisor-channel.ts +0 -249
  345. package/packages/subagents/src/tool-handler.ts +0 -1144
  346. package/packages/subagents/src/types.ts +0 -238
  347. package/packages/subagents/src/widget.ts +0 -457
  348. package/packages/subagents/src/workflow-script.ts +0 -737
  349. package/packages/subagents/src/workflow-worker.ts +0 -384
  350. package/packages/subagents/src/worktree.ts +0 -614
  351. package/packages/utility/src/analytics/collector.ts +0 -293
  352. package/packages/utility/src/info-screen.ts +0 -80
  353. package/packages/utility/src/lifecycle/process.ts +0 -162
  354. package/packages/utility/src/prefix-cache.ts +0 -263
  355. package/packages/utility/src/skill-discovery.ts +0 -542
  356. package/packages/utility/src/tools/env.ts +0 -113
  357. package/packages/utility/src/tui/name-badge-state.ts +0 -315
  358. package/packages/utility/src/tui/name-badge.ts +0 -109
  359. /package/packages/{subagents/src → core/src/child-agent}/pi-spawn.ts +0 -0
@@ -4,14 +4,13 @@
4
4
  * tool_call → TurnActivity accumulation (bash commands, edit/write
5
5
  * files, call count)
6
6
  * agent_end → extract recent tail + token totals, run continuation
7
- * settlement, deliver the next message
8
- * continuation.send → pi.sendUserMessage (a follow-up user turn: the gate
9
- * re-resolves, the owner wins, the loop continues)
7
+ * settlement, fill the arbiter's nudge stash (delivered by
8
+ * the single agent_before_settle nudge, long-horizon/index.ts)
10
9
  * verifier → modelRegistry.complete on the session model (or the
11
10
  * configured verifier model)
12
11
  *
13
- * The loop closes here: agent_end → settle → sendUserMessage → next turn →
14
- * agent_end … bounded by maxTurns / stall cap / token budget.
12
+ * The loop closes here: agent_end → settle → stash → before_settle nudge →
13
+ * next turn → agent_end … bounded by maxTurns / stall cap / token budget.
15
14
  */
16
15
 
17
16
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
@@ -24,6 +23,9 @@ import type { RalphLoop } from "./engine/ralph.js";
24
23
  import type { LongHorizonSettings } from "./settings.js";
25
24
  import { loadSettings } from "./settings.js";
26
25
  import { RunawayGuard } from "./engine/runaway.js";
26
+ import { appendProgress, registerProgressRenderer, sendHarnessUserMessage, UNIPI_EVENTS } from "@pi-unipi/core";
27
+ import { goalEstimatePrompt, goalProgressData, parseEstimate, type GoalEvidence } from "./progress.js";
28
+ import { TERMINAL_GOAL_STATUSES } from "./engine/goal-state.js";
27
29
 
28
30
  /** Extract command/file signals from a tool call for the activity record. */
29
31
  export function classifyToolCall(
@@ -88,7 +90,9 @@ export function extractTail(
88
90
  .filter((entry) => entry.text.length > 0);
89
91
  }
90
92
 
91
- /** Best-effort cumulative token count from assistant usage fields. */
93
+ /** Best-effort cumulative token count from assistant usage fields. Accepts
94
+ * both shapes pi providers emit: {input, output, cacheRead, cacheWrite,
95
+ * totalTokens} and {inputTokens, outputTokens}. */
92
96
  export function sumUsageTokens(messages: readonly unknown[]): number | undefined {
93
97
  let total = 0;
94
98
  let seen = false;
@@ -102,8 +106,16 @@ export function sumUsageTokens(messages: readonly unknown[]): number | undefined
102
106
  seen = true;
103
107
  continue;
104
108
  }
105
- const input = typeof record.inputTokens === "number" ? record.inputTokens : 0;
106
- const output = typeof record.outputTokens === "number" ? record.outputTokens : 0;
109
+ const input = typeof record.input === "number"
110
+ ? record.input
111
+ : typeof record.inputTokens === "number"
112
+ ? record.inputTokens
113
+ : 0;
114
+ const output = typeof record.output === "number"
115
+ ? record.output
116
+ : typeof record.outputTokens === "number"
117
+ ? record.outputTokens
118
+ : 0;
107
119
  if (input + output > 0) {
108
120
  total += input + output;
109
121
  seen = true;
@@ -112,6 +124,58 @@ export function sumUsageTokens(messages: readonly unknown[]): number | undefined
112
124
  return seen ? total : undefined;
113
125
  }
114
126
 
127
+ /**
128
+ * Char-based token estimate (ceil(chars/4)) over a turn's assistant text,
129
+ * thinking, tool-call args, and toolResult text. Used when a provider reports
130
+ * no usable usage so the budget still bounds the loop.
131
+ */
132
+ export function estimateTokens(messages: readonly unknown[]): number {
133
+ let chars = 0;
134
+ const countText = (value: unknown): void => {
135
+ if (typeof value === "string") chars += value.length;
136
+ };
137
+ for (const message of messages) {
138
+ if (typeof message !== "object" || message === null) continue;
139
+ const record = message as Record<string, unknown>;
140
+ const role = typeof record.role === "string" ? record.role : undefined;
141
+ const content = record.content;
142
+ if (role === "assistant") {
143
+ if (typeof content === "string") {
144
+ chars += content.length;
145
+ } else if (Array.isArray(content)) {
146
+ for (const part of content) {
147
+ if (typeof part !== "object" || part === null) continue;
148
+ const block = part as Record<string, unknown>;
149
+ if (block.type === "text") countText(block.text);
150
+ else if (block.type === "thinking") countText(block.thinking);
151
+ else if (block.type === "toolCall" || block.type === "tool_call" || block.type === "toolUse" || block.type === "tool_use") {
152
+ const args = block.arguments !== undefined ? block.arguments : block.input;
153
+ if (typeof args === "string") {
154
+ chars += args.length;
155
+ } else if (args !== undefined && args !== null) {
156
+ try {
157
+ chars += JSON.stringify(args).length;
158
+ } catch {
159
+ // Unserializable args just don't count.
160
+ }
161
+ }
162
+ }
163
+ }
164
+ }
165
+ } else if (role === "toolResult" || role === "tool_result") {
166
+ if (typeof content === "string") chars += content.length;
167
+ else if (Array.isArray(content)) {
168
+ for (const part of content) {
169
+ if (typeof part === "object" && part !== null && (part as Record<string, unknown>).type === "text") {
170
+ countText((part as Record<string, unknown>).text);
171
+ }
172
+ }
173
+ }
174
+ }
175
+ }
176
+ return Math.ceil(chars / 4);
177
+ }
178
+
115
179
  export interface RuntimeDeps {
116
180
  readonly machine: GoalMachine;
117
181
  readonly toolset: GoalToolset;
@@ -126,8 +190,14 @@ interface EvalContext {
126
190
  model: ExtensionContext["model"];
127
191
  }
128
192
 
129
- export function wireRuntime(pi: ExtensionAPI, deps: RuntimeDeps): void {
193
+ export interface RuntimeHandle {
194
+ /** Estimate goal progress now and post it (user-only). */
195
+ estimateGoal(ctx?: ExtensionContext): Promise<"ok" | "none" | "failed">;
196
+ }
197
+
198
+ export function wireRuntime(pi: ExtensionAPI, deps: RuntimeDeps): RuntimeHandle {
130
199
  const settings = deps.loadSettings ?? loadSettings;
200
+ registerProgressRenderer(pi);
131
201
 
132
202
  // ── per-turn activity accumulator ───────────────────────────────────
133
203
  let toolCalls = 0;
@@ -151,12 +221,31 @@ export function wireRuntime(pi: ExtensionAPI, deps: RuntimeDeps): void {
151
221
  // ── runaway guard: feed steps, steer once per turn ─────────────────
152
222
  const runaway = new RunawayGuard({
153
223
  steer: (text) => {
154
- void pi.sendUserMessage(text, { deliverAs: "steer" });
224
+ sendHarnessUserMessage(
225
+ pi,
226
+ text,
227
+ { source: "Progress guard", title: "No-progress guard", synopsis: "Repeated work detected", severity: "warning" },
228
+ { deliverAs: "steer" },
229
+ );
155
230
  },
156
231
  });
232
+ // pi's tool_execution_end carries no input — capture args per call at
233
+ // execution start and join them at the end, so "identical arguments" keys
234
+ // on real arguments instead of collapsing to one hash for the whole tool.
235
+ const argsByCallId = new Map<string, unknown>();
236
+ pi.on("tool_execution_start", (event) => {
237
+ try {
238
+ const startEvent = event as { toolCallId?: string; args?: unknown };
239
+ if (typeof startEvent.toolCallId === "string") {
240
+ argsByCallId.set(startEvent.toolCallId, startEvent.args);
241
+ }
242
+ } catch {
243
+ // Detector instrumentation must never abort a turn.
244
+ }
245
+ });
157
246
  pi.on("tool_execution_end", (event) => {
158
247
  try {
159
- const toolEvent = event as { toolName?: string; result?: unknown; isError?: boolean };
248
+ const toolEvent = event as { toolCallId?: string; toolName?: string; result?: unknown; isError?: boolean; input?: unknown };
160
249
  if (typeof toolEvent.toolName !== "string") return;
161
250
  const resultText =
162
251
  typeof toolEvent.result === "string"
@@ -168,9 +257,12 @@ export function wireRuntime(pi: ExtensionAPI, deps: RuntimeDeps): void {
168
257
  return String(toolEvent.result ?? "");
169
258
  }
170
259
  })();
260
+ const callId = typeof toolEvent.toolCallId === "string" ? toolEvent.toolCallId : undefined;
261
+ const input = callId !== undefined ? argsByCallId.get(callId) : undefined;
262
+ if (callId !== undefined) argsByCallId.delete(callId);
171
263
  runaway.feed({
172
264
  tool: toolEvent.toolName,
173
- input: (event as { input?: unknown }).input,
265
+ input: input ?? (event as { input?: unknown }).input,
174
266
  resultText: resultText.slice(0, 400),
175
267
  isError: toolEvent.isError === true,
176
268
  });
@@ -202,21 +294,75 @@ export function wireRuntime(pi: ExtensionAPI, deps: RuntimeDeps): void {
202
294
  const tokens = sumUsageTokens(messages);
203
295
  // Only update when this turn actually reported usage — a usage-less turn
204
296
  // keeps the last known counter (and never erases an injected one).
205
- if (tokens !== undefined) deps.continuation.setTokenCounter(() => tokens);
297
+ if (tokens !== undefined) {
298
+ deps.continuation.setTokenCounter(() => tokens);
299
+ deps.continuation.setTokensEstimated(false);
300
+ } else if (messages.length > 0) {
301
+ // Messages exist but carry no usable usage: estimate from their sizes so
302
+ // the budget still bounds the loop (flagged as estimated everywhere).
303
+ const estimated = estimateTokens(messages);
304
+ deps.continuation.setTokenCounter(() => estimated);
305
+ deps.continuation.setTokensEstimated(true);
306
+ }
307
+ deps.continuation.setNotify((text, level) => {
308
+ try {
309
+ (ctx as { ui?: { notify?: (t: string, l?: string) => void } }).ui?.notify?.(text, level ?? "warning");
310
+ } catch {
311
+ // Notification must never break settlement.
312
+ }
313
+ });
314
+ if (deps.machine.get()) lastEvidence = activity;
206
315
  await deps.continuation.onTurnEnd(activity);
316
+ // Per-loop goal progress: fire-and-forget, never delays the next turn.
317
+ if (settings().goalProgress === "loop") void estimateGoal(ctx, true);
207
318
  } catch {
208
319
  // Settlement failures must never surface as turn aborts.
209
320
  }
210
321
  });
211
322
 
212
- // ── verifier evaluate → modelRegistry.complete ──────────────────────
213
- const evaluate: VerifierEvaluate = async (prompt, signal) => {
214
- const context = evalContext;
323
+ // ── goal progress estimate (one-off side call, never in context) ─────
324
+ let lastEvidence: GoalEvidence | undefined;
325
+ let lastPercent: number | undefined;
326
+ let lastGoalKey: string | undefined;
327
+ let estimating = false;
328
+
329
+ async function estimateGoal(ctx?: ExtensionContext, fromLoop = false): Promise<"ok" | "none" | "failed"> {
330
+ try {
331
+ const goal = deps.machine.get();
332
+ if (!goal || deps.ralph?.get()?.status === "active") return "none"; // ralph has its own bar
333
+ const key = `${goal.goalId}:${goal.status}`;
334
+ const terminal = TERMINAL_GOAL_STATUSES.has(goal.status);
335
+ // A loop posts once per goal turn; a finished goal posts its last bar once.
336
+ if (fromLoop && (goal.status === "paused" || (terminal && key === lastGoalKey))) return "none";
337
+ if (goal.goalId !== lastGoalKey?.split(":")[0]) lastPercent = undefined;
338
+ lastGoalKey = key;
339
+ if (goal.status === "complete") {
340
+ appendProgress(pi, goalProgressData(goal, 100, "Objective met."));
341
+ return "ok";
342
+ }
343
+ if (estimating) return "ok";
344
+ estimating = true;
345
+ const s = settings();
346
+ const text = await complete(s.progressModel || s.verifierModel, goalEstimatePrompt(goal, lastEvidence, lastPercent), undefined, ctx);
347
+ const est = parseEstimate(text);
348
+ if (!est) return "failed";
349
+ lastPercent = est.percent;
350
+ appendProgress(pi, goalProgressData(deps.machine.get() ?? goal, est.percent, est.summary));
351
+ return "ok";
352
+ } catch {
353
+ return "failed";
354
+ } finally {
355
+ estimating = false;
356
+ }
357
+ }
358
+
359
+ // ── one-shot completions (verifier, progress) → modelRegistry.complete ─
360
+ async function complete(configured: string, prompt: string, signal?: AbortSignal, ctx?: ExtensionContext): Promise<string> {
361
+ const context = ctx ? { registry: ctx.modelRegistry, model: ctx.model } : evalContext;
215
362
  if (!context?.model || !context.registry) {
216
363
  throw new Error("verifier: no model context available yet");
217
364
  }
218
365
  let model = context.model;
219
- const configured = settings().verifierModel;
220
366
  if (configured) {
221
367
  const slash = configured.indexOf("/");
222
368
  if (slash > 0) {
@@ -243,7 +389,8 @@ export function wireRuntime(pi: ExtensionAPI, deps: RuntimeDeps): void {
243
389
  : "";
244
390
  if (!text) throw new Error("verifier: empty completion");
245
391
  return text;
246
- };
392
+ }
393
+ const evaluate: VerifierEvaluate = (prompt, signal) => complete(settings().verifierModel, prompt, signal);
247
394
  deps.continuation.setEvaluate(evaluate);
248
395
  if (deps.ralph) deps.ralph.setEvaluate(evaluate);
249
396
 
@@ -251,4 +398,11 @@ export function wireRuntime(pi: ExtensionAPI, deps: RuntimeDeps): void {
251
398
  pi.on("session_compact", () => {
252
399
  deps.continuation.armRecovery();
253
400
  });
401
+ // Boundary compactions (compactor's percentage trigger) don't fire
402
+ // session_compact; the compactor announces them on the event bus.
403
+ pi.events?.on?.(UNIPI_EVENTS.COMPACTOR_COMPACTED, () => {
404
+ deps.continuation.armRecovery();
405
+ });
406
+
407
+ return { estimateGoal: (ctx) => estimateGoal(ctx) };
254
408
  }
@@ -12,7 +12,7 @@
12
12
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
13
13
  import { dirname, join } from "node:path";
14
14
  import { homedir } from "node:os";
15
- import { getSettings, registerSettings, setSettings } from "@pi-unipi/core";
15
+ import { decisionModelSection, DEFAULT_DECISION_OVERRIDE, getSettings, registerSettings, resolveDecisionModel, setSettings } from "@pi-unipi/core";
16
16
  import type { LhMode } from "./modes.js";
17
17
 
18
18
  export interface JudgeSettings {
@@ -52,6 +52,14 @@ export interface LongHorizonSettings {
52
52
  defaultMode: LhMode;
53
53
  /** Model used for goal-completion verification (empty = session model). */
54
54
  verifierModel: string;
55
+ /**
56
+ * User-only goal progress estimate (a one-off model call, never in context):
57
+ * "loop" = after every goal turn and on /unipi:goal status; "status" = only
58
+ * on status; "off" = never.
59
+ */
60
+ goalProgress: "loop" | "status" | "off";
61
+ /** Model for the estimate (empty = verifier model, else session model). */
62
+ progressModel: string;
55
63
  }
56
64
 
57
65
  export const DEFAULT_SETTINGS: LongHorizonSettings = {
@@ -62,12 +70,14 @@ export const DEFAULT_SETTINGS: LongHorizonSettings = {
62
70
  // openrouter/custom ride the decisions endpoint → the hosted jev id.
63
71
  model: "typesafe/jev-1.13",
64
72
  baseUrl: "",
65
- threshold: 0.6,
73
+ threshold: 0.8,
66
74
  timeoutMs: 0,
67
75
  apiKey: "",
68
76
  },
69
- defaultMode: "goal",
77
+ defaultMode: "none",
70
78
  verifierModel: "",
79
+ goalProgress: "loop",
80
+ progressModel: "",
71
81
  };
72
82
 
73
83
  const settingsPath = (): string => join(homedir(), ".pi", "agent", "settings.json");
@@ -134,6 +144,8 @@ function mergeSettings(stored: unknown): LongHorizonSettings {
134
144
  ? (stored.defaultMode as LhMode)
135
145
  : DEFAULT_SETTINGS.defaultMode,
136
146
  verifierModel: typeof stored.verifierModel === "string" ? stored.verifierModel : "",
147
+ goalProgress: stored.goalProgress === "status" || stored.goalProgress === "off" ? stored.goalProgress : "loop",
148
+ progressModel: typeof stored.progressModel === "string" ? stored.progressModel : "",
137
149
  };
138
150
  }
139
151
 
@@ -145,50 +157,18 @@ let cache: LongHorizonSettings | null = null;
145
157
  registerSettings({
146
158
  namespace: "long-horizon",
147
159
  label: "Long-Horizon",
148
- defaults: DEFAULT_SETTINGS as unknown as Record<string, unknown>,
160
+ defaults: { ...DEFAULT_SETTINGS, decisionModel: DEFAULT_DECISION_OVERRIDE } as unknown as Record<string, unknown>,
149
161
  projectOverrides: true,
150
162
  schema: [
151
163
  {
152
164
  title: "Judge",
153
- description: "Prompt → mode routing — the transport derives from the model",
165
+ description: "Prompt → mode routing with the Decision Model (shared settings: /unipi:settings → Decision Model)",
154
166
  fields: [
155
167
  { key: "judge.enabled", type: "boolean", label: "Judge enabled", description: "Route new prompts automatically; off = always defaultMode" },
156
- {
157
- key: "judge.provider",
158
- type: "enum",
159
- label: "Provider",
160
- options: [
161
- { value: "typesafe", label: "typesafe (native systemone)" },
162
- { value: "openrouter", label: "openrouter (decisions endpoint)" },
163
- { value: "custom", label: "custom (Base URL + API key)" },
164
- ],
165
- description: "typesafe = native systemone · openrouter = decisions/chat · custom = your own gateway",
166
- },
167
- { key: "judge.baseUrl", type: "string", label: "Base URL", description: "required when provider=custom · oino proxy = https://router.oino.dev/v1", emptyLabel: "provider default" },
168
- { key: "judge.apiKey", type: "secret", label: "API key", description: "Stored key wins over env (works in tmux/ssh-c/systemd)", emptyLabel: "env / bridge fallback" },
169
- {
170
- key: "judge.model",
171
- type: "model",
172
- label: "Decision model",
173
- description: "decision (classifier) model — jev; custom… for others",
174
- providerKey: "judge.provider",
175
- presetsByProvider: {
176
- typesafe: ["jev-latest"],
177
- openrouter: ["typesafe/jev-1.13"],
178
- custom: ["typesafe/jev-1.13"],
179
- },
180
- },
181
168
  { key: "judge.threshold", type: "number", label: "Confidence threshold", description: "Below this the judge abstains (0-1)", min: 0.01, max: 1 },
182
169
  ],
183
170
  },
184
- {
185
- title: "Judge — Advanced",
186
- advanced: true,
187
- description: "Rarely needed — zero means the provider default",
188
- fields: [
189
- { key: "judge.timeoutMs", type: "number", label: "Timeout ms", min: 0, zeroLabel: "auto (1s native / 6s chat)" },
190
- ],
191
- },
171
+ decisionModelSection({ title: "Judge — Decision model" }),
192
172
  {
193
173
  title: "Modes",
194
174
  fields: [
@@ -202,6 +182,24 @@ registerSettings({
202
182
  { key: "verifierModel", type: "model", label: "Verifier model", description: "Goal completion verification", emptyLabel: "inherit (session model)", capability: "text", emptyOption: "inherit (session model)" },
203
183
  ],
204
184
  },
185
+ {
186
+ title: "Progress",
187
+ description: "Progress bars shown only to you — never sent to the model",
188
+ fields: [
189
+ {
190
+ key: "goalProgress",
191
+ type: "enum",
192
+ label: "Goal progress estimate",
193
+ options: [
194
+ { value: "loop", label: "every loop + /goal status" },
195
+ { value: "status", label: "only on /goal status" },
196
+ { value: "off", label: "off" },
197
+ ],
198
+ description: "A one-off side call estimates % done and summarizes the work so far",
199
+ },
200
+ { key: "progressModel", type: "model", label: "Estimate model", description: "Cheaper is fine; runs once per goal turn", emptyLabel: "inherit (verifier → session model)", capability: "text", emptyOption: "inherit (verifier → session model)" },
201
+ ],
202
+ },
205
203
  ],
206
204
  });
207
205
 
@@ -209,10 +207,27 @@ export function loadSettings(force = false): LongHorizonSettings {
209
207
  if (cache && !force) return cache;
210
208
  const raw = getSettings("long-horizon", process.cwd());
211
209
  // The engine stores validated shapes; re-validate defensively anyway.
212
- cache = mergeSettings(raw);
210
+ cache = withDecisionModel(mergeSettings(raw), process.cwd());
213
211
  return cache;
214
212
  }
215
213
 
214
+ /**
215
+ * The judge's transport (provider/model/baseUrl/key/timeout) is the Decision
216
+ * Model — shared, or this module's custom override. `enabled` and
217
+ * `threshold` stay long-horizon's own.
218
+ */
219
+ function withDecisionModel(settings: LongHorizonSettings, cwd: string): LongHorizonSettings {
220
+ try {
221
+ const dm = resolveDecisionModel(cwd, "long-horizon");
222
+ return {
223
+ ...settings,
224
+ judge: { ...settings.judge, provider: dm.provider, model: dm.model, baseUrl: dm.baseUrl, apiKey: dm.apiKey, timeoutMs: dm.timeoutMs ?? 0 },
225
+ };
226
+ } catch {
227
+ return settings;
228
+ }
229
+ }
230
+
216
231
  export function saveSettings(update: Partial<LongHorizonSettings>): LongHorizonSettings {
217
232
  const current = mergeSettings(getSettings("long-horizon", process.cwd()));
218
233
  const next = mergeSettings({ ...current, ...update, judge: { ...current.judge, ...(update.judge ?? {}) } });
@@ -59,6 +59,11 @@ export class GoalToolset {
59
59
  return this.pending;
60
60
  }
61
61
 
62
+ /** Drop any pending proposal unverified (user stop/clear); get_goal stops advertising it. */
63
+ discardProposal(): void {
64
+ this.pending = null;
65
+ }
66
+
62
67
  register(pi: ExtensionAPI): void {
63
68
  // ── create_goal ───────────────────────────────────────────────────
64
69
  pi.registerTool({
@@ -219,6 +224,7 @@ export class GoalToolset {
219
224
  stall_cap: goal.stallCap,
220
225
  token_budget: goal.tokenBudget,
221
226
  tokens_used: goal.tokensBaselinePending ? null : goal.tokensNow - goal.tokensAtStart,
227
+ tokens_estimated: goal.tokensEstimated === true,
222
228
  expected_goal_id: goal.goalId,
223
229
  expected_updated_at: goal.updatedAt,
224
230
  updated_at: goal.updatedAt,
@@ -51,7 +51,7 @@ export const GRAPH_ORCHESTRATION_PROMPT = `<long-horizon-graph>
51
51
  Graph Mode is active. You are the supervisor of a dependent work graph.
52
52
 
53
53
  - Declare the graph first with update_agent_graph: items with explicit dependsOn (an item's inputs are the COMMITTED results of its dependencies). Cycles are refused.
54
- - Dispatch every currently-ready item with spawn_helper or bg_delegate. Do not dispatch an item before its dependencies complete.
54
+ - Dispatch every currently-ready item with run_subagent (is_background:true for parallel items). Do not dispatch an item before its dependencies complete.
55
55
  - After dispatching a wave, call swarm_yield. Do not poll; background notifications wake you.
56
56
  - On wake, record outcomes with graph_output. Recording a completion hands you the next ready items together with their input frontiers (the dependency summaries) — pass those inputs into the child instructions instead of restating conclusions.
57
57
  - A failed item can be re-dispatched after its failure is recorded; downstream items stay blocked until it completes or is aborted.
@@ -2,12 +2,12 @@
2
2
  * Swarm — Maka's fan-out prescription over unipi's delegation tools.
3
3
  *
4
4
  * The ledger is the durable schedule: declared items with reported outcomes.
5
- * The MODEL dispatches via spawn_helper/bg_delegate (full surface in swarm
5
+ * The MODEL dispatches via run_subagent (full surface in swarm
6
6
  * mode); swarm_report records outcomes idempotently; swarm_status projects
7
7
  * running | needs_attention | settled; swarm_yield ends the supervisor turn
8
8
  * (wakes arrive via background-task notifications — user-first by design).
9
9
  *
10
- * v1 seam honesty: spawn_helper dispatch is opaque to extensions, so
10
+ * v1 seam honesty: run_subagent dispatch is opaque to extensions, so
11
11
  * claim-before-dispatch is enforced by the orchestration prompt (one dispatch
12
12
  * per item) plus report idempotency (duplicate terminal reports refused
13
13
  * unless the item was failed and is being replaced). Harness-level claims
@@ -45,7 +45,7 @@ Swarm Mode is active. Treat parallel delegation as the preferred execution strat
45
45
 
46
46
  - Before acting, decide whether parallel delegation would materially improve speed, quality, coverage, or independent verification. If the work cannot be usefully divided into at least two meaningful independent items, continue directly.
47
47
  - Make every item bounded and self-contained: explicit scope, expected output, constraints. Avoid overlapping writes; prefer read-only investigation.
48
- - Dispatch each item exactly once with spawn_helper or bg_delegate (run_in_background). Do not re-dispatch an item unless you reported it failed and are replacing it.
48
+ - Dispatch each item exactly once with run_subagent (is_background:true for parallel items). Do not re-dispatch an item unless you reported it failed and are replacing it.
49
49
  - After dispatching all items, call swarm_yield. Do not poll, sleep, watch task logs, or wait synchronously; background-task notifications will wake you when work settles.
50
50
  - On wake, call swarm_status for compact statuses. Read full results only for completed items you will synthesize or failed items you must diagnose.
51
51
  - Record every outcome with swarm_report. Replace failed work by re-dispatching a corrected item and reporting it under the same id.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/mcp",
3
- "version": "3.0.0-alpha.2",
3
+ "version": "3.0.0-alpha.21",
4
4
  "description": "MCP server management extension for Pi coding agent — browse, add, configure, and use MCP servers",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -30,7 +30,7 @@
30
30
  "test": "npx tsx --test tests/**/*.test.ts"
31
31
  },
32
32
  "dependencies": {
33
- "@pi-unipi/core": "3.0.0-alpha.2"
33
+ "@pi-unipi/core": "3.0.0-alpha.21"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -11,6 +11,7 @@
11
11
  import * as fs from "node:fs";
12
12
  import * as path from "node:path";
13
13
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
14
+ import { sendHarnessUserMessage } from "@pi-unipi/core";
14
15
  import type { SessionBackend } from "./session.js";
15
16
  import { MEMORY_TOOLS } from "./tools.js";
16
17
  import { readMemoryConfig } from "./settings.js";
@@ -226,8 +227,10 @@ export function registerMemoryCommands(
226
227
  return;
227
228
  }
228
229
  ctx.ui.notify("Analyzing text for memories... Use memory_store tool to save.", "info");
229
- pi.sendUserMessage(
230
+ sendHarnessUserMessage(
231
+ pi,
230
232
  `Analyze the following text and extract any memory-worthy items (user preferences, project decisions, code patterns, conversation summaries). For each item found, use the memory_store tool to save it.\n\nText to analyze:\n${args}`,
233
+ { source: "Memory", title: "Extract memories", synopsis: "Generated from /unipi:memory-process" },
231
234
  { deliverAs: "followUp" },
232
235
  );
233
236
  },
@@ -237,7 +240,8 @@ export function registerMemoryCommands(
237
240
  description: "Consolidate current session into memory",
238
241
  handler: async (_args, ctx) => {
239
242
  ctx.ui.notify("Consolidating session into memory... Use memory_store tool to save insights.", "info");
240
- pi.sendUserMessage(
243
+ sendHarnessUserMessage(
244
+ pi,
241
245
  `Review the current session and identify any memory-worthy items:
242
246
  - User preferences discovered
243
247
  - Project decisions made
@@ -245,6 +249,7 @@ export function registerMemoryCommands(
245
249
  - Important context to remember
246
250
 
247
251
  For each item, use the memory_store tool to save it with an appropriate title and type.`,
252
+ { source: "Memory", title: "Consolidate session", synopsis: "Generated from /unipi:memory-consolidate" },
248
253
  { deliverAs: "followUp" },
249
254
  );
250
255
  },