@hassangameryt/freeflow 0.7.3 → 0.9.0

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 (426) hide show
  1. package/.agents/plugins/marketplace.json +2 -2
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/.claude-plugin/plugin.json +2 -2
  4. package/.codex-plugin/plugin.json +3 -3
  5. package/.cursor-plugin/plugin.json +1 -1
  6. package/NOTICE +14 -0
  7. package/README.md +101 -159
  8. package/capabilities/cognitive-routing/SKILL.md +47 -210
  9. package/capabilities/cognitive-routing/references/coordinator.md +163 -0
  10. package/capabilities/cognitive-routing/references/worker.md +38 -0
  11. package/capabilities/compaction/SKILL.md +49 -0
  12. package/capabilities/compaction/references/summary-format.md +250 -0
  13. package/capabilities/messaging/SKILL.md +49 -0
  14. package/capabilities/task-memory/SKILL.md +87 -0
  15. package/command-surface.json +8 -52
  16. package/gemini-extension.json +1 -1
  17. package/hooks/claude/hooks.json +13 -3
  18. package/hooks/codex/hooks.json +2 -1
  19. package/hooks/shared/runtime-context.mjs +73 -83
  20. package/licenses/Apache-2.0.txt +55 -0
  21. package/package.json +42 -12
  22. package/pi-extension/README.md +41 -0
  23. package/pi-extension/dist/ask-user/ask.js +108 -0
  24. package/pi-extension/dist/ask-user/form.js +250 -0
  25. package/pi-extension/dist/ask-user/questions.js +66 -0
  26. package/pi-extension/dist/ask-user/tool.js +124 -0
  27. package/pi-extension/dist/cognitive-routing/assembler.js +417 -0
  28. package/pi-extension/dist/cognitive-routing/bootstrap.js +90 -0
  29. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/config.js +8 -6
  30. package/pi-extension/dist/cognitive-routing/economics.js +45 -0
  31. package/pi-extension/dist/cognitive-routing/event-schema.js +388 -0
  32. package/pi-extension/dist/{session-sources/events.js → cognitive-routing/event-store.js} +107 -41
  33. package/pi-extension/dist/cognitive-routing/gate.js +256 -0
  34. package/pi-extension/dist/cognitive-routing/handlers.js +901 -0
  35. package/pi-extension/dist/cognitive-routing/handoffs.js +350 -0
  36. package/pi-extension/dist/cognitive-routing/model-control.js +476 -0
  37. package/pi-extension/dist/cognitive-routing/projection.js +520 -0
  38. package/pi-extension/dist/cognitive-routing/provenance.js +83 -0
  39. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/render.js +15 -15
  40. package/pi-extension/dist/cognitive-routing/runtime.js +398 -0
  41. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/schemas.js +47 -11
  42. package/pi-extension/dist/cognitive-routing/session.js +223 -0
  43. package/pi-extension/dist/{session-sources → cognitive-routing}/sources.js +126 -87
  44. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/state.js +55 -386
  45. package/pi-extension/dist/cognitive-routing/status.js +81 -0
  46. package/pi-extension/dist/cognitive-routing/tools.js +74 -0
  47. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/types.js +14 -11
  48. package/pi-extension/dist/compaction/carry.js +205 -0
  49. package/pi-extension/dist/compaction/config.js +24 -0
  50. package/pi-extension/dist/compaction/controller.js +494 -0
  51. package/pi-extension/dist/compaction/harness.js +93 -0
  52. package/pi-extension/dist/compaction/results.js +159 -0
  53. package/pi-extension/dist/compaction/thresholds.js +35 -0
  54. package/pi-extension/dist/compaction/tool.js +57 -0
  55. package/pi-extension/dist/host/branch.js +13 -0
  56. package/pi-extension/dist/host/canonical.js +12 -0
  57. package/pi-extension/dist/host/catalog.js +62 -0
  58. package/pi-extension/dist/host/config-validation.js +233 -0
  59. package/pi-extension/dist/host/config.js +361 -0
  60. package/pi-extension/dist/host/inbound.js +142 -0
  61. package/pi-extension/dist/host/projection-tags.js +60 -0
  62. package/pi-extension/dist/host/prompts.js +93 -0
  63. package/pi-extension/dist/{session-sources → host}/read-only-session.js +117 -1
  64. package/pi-extension/dist/{runtime → host}/request-history.js +125 -39
  65. package/pi-extension/dist/host/rows.js +25 -0
  66. package/pi-extension/dist/host/runtime-state.js +204 -0
  67. package/pi-extension/dist/host/section-keeper.js +85 -0
  68. package/pi-extension/dist/host/settings/freeflow-command.js +2323 -0
  69. package/pi-extension/dist/{settings/settings-tui.js → host/settings/settings-view.js} +205 -73
  70. package/pi-extension/dist/host/staging.js +28 -0
  71. package/pi-extension/dist/host/status.js +115 -0
  72. package/pi-extension/dist/index.js +1004 -188
  73. package/pi-extension/dist/messaging/config.js +27 -0
  74. package/pi-extension/dist/messaging/messaging.js +398 -0
  75. package/pi-extension/dist/messaging/registry.js +57 -0
  76. package/pi-extension/dist/messaging/render.js +90 -0
  77. package/pi-extension/dist/messaging/tools.js +109 -0
  78. package/pi-extension/dist/messaging/transport.js +101 -0
  79. package/pi-extension/dist/provider-support/cache/anchor.js +21 -0
  80. package/pi-extension/dist/provider-support/cache/anthropic.js +102 -0
  81. package/pi-extension/dist/provider-support/cache/health.js +73 -0
  82. package/pi-extension/dist/provider-support/cache/index.js +58 -0
  83. package/pi-extension/dist/provider-support/cache/keepalive.js +222 -0
  84. package/pi-extension/dist/provider-support/cache/monitor.js +17 -0
  85. package/pi-extension/dist/provider-support/cache/openai-responses.js +48 -0
  86. package/pi-extension/dist/provider-support/effort.js +13 -0
  87. package/pi-extension/dist/provider-support/index.js +44 -3
  88. package/pi-extension/dist/provider-support/{astra → openai}/adapter.js +46 -29
  89. package/pi-extension/dist/provider-support/{astra → openai}/history.js +10 -8
  90. package/pi-extension/dist/provider-support/{astra → openai}/index.js +8 -4
  91. package/pi-extension/dist/provider-support/{astra → openai}/session-state.js +29 -38
  92. package/pi-extension/dist/provider-support/routes.js +17 -0
  93. package/pi-extension/dist/task-memory/config.js +49 -0
  94. package/pi-extension/dist/task-memory/registry.js +119 -0
  95. package/pi-extension/dist/task-memory/render.js +107 -0
  96. package/pi-extension/dist/task-memory/runtime.js +994 -0
  97. package/pi-extension/dist/task-memory/tool.js +233 -0
  98. package/pi-extension/dist/tool-execution/apply-patch/grammar.js +23 -0
  99. package/pi-extension/dist/tool-execution/apply-patch/match.js +38 -0
  100. package/pi-extension/dist/tool-execution/apply-patch/parser.js +177 -0
  101. package/pi-extension/dist/tool-execution/apply-patch/plan.js +201 -0
  102. package/pi-extension/dist/tool-execution/apply-patch/tool.js +84 -0
  103. package/pi-extension/dist/tool-execution/background.js +430 -0
  104. package/pi-extension/dist/tool-execution/bash-guard.js +23 -0
  105. package/pi-extension/dist/tool-execution/config.js +33 -0
  106. package/pi-extension/dist/tool-execution/edit-messages.js +120 -0
  107. package/pi-extension/dist/tool-execution/file-state.js +138 -0
  108. package/pi-extension/dist/tool-execution/file-tracking.js +163 -0
  109. package/pi-extension/dist/tool-execution/guidance-notices.js +124 -0
  110. package/pi-extension/dist/tool-execution/prompt.js +54 -0
  111. package/pi-extension/dist/tool-execution/skill-reads.js +143 -0
  112. package/pi-extension/dist/tool-execution/tools.js +16 -0
  113. package/pi-extension/freeflow/README.md +9 -0
  114. package/runtime/prompts/cognitive-routing.md +4 -4
  115. package/runtime/prompts/core.md +29 -72
  116. package/runtime/prompts/interaction-contract.md +18 -8
  117. package/runtime/prompts/tool-execution.md +25 -0
  118. package/runtime/prompts/working-method.md +25 -0
  119. package/skills/deliver-work/SKILL.md +76 -0
  120. package/skills/deliver-work/references/branch-closeout.md +134 -0
  121. package/skills/deliver-work/references/commit.md +83 -0
  122. package/skills/deliver-work/references/launch.md +94 -0
  123. package/skills/deliver-work/references/release.md +85 -0
  124. package/skills/deliver-work/scripts/commit-state.mjs +139 -0
  125. package/skills/deliver-work/scripts/delivery-state.mjs +107 -0
  126. package/skills/deliver-work/scripts/lib/git-state.mjs +178 -0
  127. package/skills/deliver-work/scripts/push-route.mjs +122 -0
  128. package/skills/deliver-work/scripts/release-preflight.mjs +177 -0
  129. package/skills/discuss-work/SKILL.md +148 -0
  130. package/skills/{discuss → discuss-work}/references/discussion-continuity.md +13 -50
  131. package/skills/discuss-work/references/learning-action.md +36 -0
  132. package/skills/discuss-work/scripts/choices.mjs +101 -0
  133. package/skills/discuss-work/scripts/lib/choices.mjs +159 -0
  134. package/skills/evaluate-behavior/SKILL.md +107 -0
  135. package/skills/evaluate-behavior/references/authoring.md +381 -0
  136. package/skills/evaluate-behavior/references/coding-tasks.md +145 -0
  137. package/skills/evaluate-behavior/references/conversations-pipelines-judges.md +177 -0
  138. package/skills/evaluate-behavior/references/design-and-measurement.md +273 -0
  139. package/skills/evaluate-behavior/references/running-and-evidence.md +245 -0
  140. package/skills/evaluate-behavior/scripts/claude-guard.mjs +76 -0
  141. package/skills/evaluate-behavior/scripts/guard-rules.mjs +309 -0
  142. package/skills/evaluate-behavior/scripts/lib/agreement.mjs +90 -0
  143. package/skills/evaluate-behavior/scripts/lib/arms.mjs +55 -0
  144. package/skills/evaluate-behavior/scripts/lib/budget.mjs +87 -0
  145. package/skills/evaluate-behavior/scripts/lib/build-source.mjs +287 -0
  146. package/skills/evaluate-behavior/scripts/lib/clear.mjs +74 -0
  147. package/skills/evaluate-behavior/scripts/lib/container.mjs +395 -0
  148. package/skills/evaluate-behavior/scripts/lib/decision.mjs +418 -0
  149. package/skills/evaluate-behavior/scripts/lib/definitions.mjs +1072 -0
  150. package/skills/evaluate-behavior/scripts/lib/freeflow.mjs +103 -0
  151. package/skills/evaluate-behavior/scripts/lib/grade-command.mjs +591 -0
  152. package/skills/evaluate-behavior/scripts/lib/grade-comparison.mjs +90 -0
  153. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-interaction.mjs +19 -18
  154. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-support.mjs +32 -5
  155. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-workspace.mjs +28 -12
  156. package/skills/evaluate-behavior/scripts/lib/grade.mjs +101 -0
  157. package/skills/evaluate-behavior/scripts/lib/hooks.mjs +98 -0
  158. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/confinement.mjs +196 -0
  159. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/constraints.mjs +111 -0
  160. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/index.mjs +48 -0
  161. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/isolation.mjs +74 -0
  162. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/launch.mjs +123 -0
  163. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/model-call.mjs +73 -0
  164. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/recorder.mjs +178 -0
  165. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/session.mjs +494 -0
  166. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/skills.mjs +81 -0
  167. package/skills/evaluate-behavior/scripts/lib/hosts/index.mjs +31 -0
  168. package/skills/evaluate-behavior/scripts/lib/hosts/names.mjs +3 -0
  169. package/skills/evaluate-behavior/scripts/lib/hosts/pi/confinement.mjs +173 -0
  170. package/skills/evaluate-behavior/scripts/lib/hosts/pi/host.mjs +148 -0
  171. package/skills/evaluate-behavior/scripts/lib/hosts/pi/index.mjs +70 -0
  172. package/skills/evaluate-behavior/scripts/lib/hosts/pi/isolation.mjs +81 -0
  173. package/skills/evaluate-behavior/scripts/lib/hosts/pi/model-call.mjs +79 -0
  174. package/skills/evaluate-behavior/scripts/lib/hosts/pi/process.mjs +241 -0
  175. package/skills/{evaluate-skill/scripts/lib → evaluate-behavior/scripts/lib/hosts/pi}/rpc.mjs +144 -26
  176. package/skills/evaluate-behavior/scripts/lib/identity.mjs +82 -0
  177. package/skills/evaluate-behavior/scripts/lib/judge.mjs +688 -0
  178. package/skills/evaluate-behavior/scripts/lib/metrics.mjs +332 -0
  179. package/skills/evaluate-behavior/scripts/lib/model-call.mjs +17 -0
  180. package/skills/evaluate-behavior/scripts/lib/participants.mjs +616 -0
  181. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/process.mjs +22 -0
  182. package/skills/evaluate-behavior/scripts/lib/queue.mjs +54 -0
  183. package/skills/evaluate-behavior/scripts/lib/reference.mjs +343 -0
  184. package/skills/evaluate-behavior/scripts/lib/reuse.mjs +277 -0
  185. package/skills/evaluate-behavior/scripts/lib/review.mjs +933 -0
  186. package/skills/evaluate-behavior/scripts/lib/runner.mjs +732 -0
  187. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/sandbox.mjs +121 -14
  188. package/skills/evaluate-behavior/scripts/lib/scan-shell.mjs +457 -0
  189. package/skills/evaluate-behavior/scripts/lib/scan.mjs +479 -0
  190. package/skills/evaluate-behavior/scripts/lib/seal.mjs +91 -0
  191. package/skills/evaluate-behavior/scripts/lib/shell.mjs +560 -0
  192. package/skills/evaluate-behavior/scripts/lib/source-override.mjs +64 -0
  193. package/skills/evaluate-behavior/scripts/lib/subject-file.mjs +88 -0
  194. package/skills/{evaluate-skill/scripts/lib/pi.mjs → evaluate-behavior/scripts/lib/subject.mjs} +239 -262
  195. package/skills/evaluate-behavior/scripts/lib/task-copy.mjs +124 -0
  196. package/skills/evaluate-behavior/scripts/lib/trials.mjs +524 -0
  197. package/skills/evaluate-behavior/scripts/lib/validity.mjs +68 -0
  198. package/skills/evaluate-behavior/scripts/lib/view-html.mjs +454 -0
  199. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/view.mjs +218 -11
  200. package/skills/evaluate-behavior/scripts/pi-command-tool.mjs +159 -0
  201. package/skills/evaluate-behavior/scripts/pi-container-route.mjs +23 -0
  202. package/skills/evaluate-behavior/scripts/pi-guard.mjs +77 -0
  203. package/skills/evaluate-behavior/scripts/pi-login-refresh.mjs +31 -0
  204. package/skills/evaluate-behavior/scripts/skill-eval.mjs +586 -0
  205. package/skills/execute-work/SKILL.md +96 -72
  206. package/skills/execute-work/references/code-practices.md +27 -49
  207. package/skills/execute-work/references/design.md +271 -0
  208. package/skills/execute-work/references/diagnose.md +117 -0
  209. package/skills/execute-work/references/migration.md +108 -0
  210. package/skills/execute-work/references/simplify.md +65 -0
  211. package/skills/execute-work/scripts/self-review.mjs +422 -0
  212. package/skills/execute-work/scripts/touch-map.mjs +290 -0
  213. package/skills/review-work/SKILL.md +94 -64
  214. package/skills/review-work/references/adjudication.md +94 -0
  215. package/skills/review-work/references/artifact.md +198 -0
  216. package/skills/review-work/references/evals-and-judges.md +66 -0
  217. package/skills/review-work/references/work.md +177 -0
  218. package/skills/review-work/scripts/check-brief.mjs +128 -0
  219. package/skills/review-work/scripts/review-packet.mjs +233 -0
  220. package/skills/setup-freeflow/SKILL.md +69 -16
  221. package/skills/track-work/SKILL.md +135 -151
  222. package/skills/track-work/references/handoff.md +190 -0
  223. package/skills/track-work/references/projects.md +51 -0
  224. package/skills/track-work/references/working-record-format.md +201 -344
  225. package/skills/track-work/scripts/lib/document.mjs +79 -19
  226. package/skills/track-work/scripts/lib/format.mjs +18 -1
  227. package/skills/track-work/scripts/lib/recover.mjs +254 -0
  228. package/skills/track-work/scripts/lib/registry.mjs +656 -0
  229. package/skills/track-work/scripts/lib/search.mjs +40 -0
  230. package/skills/track-work/scripts/lib/store.mjs +53 -21
  231. package/skills/track-work/scripts/lib/transitions.mjs +79 -4
  232. package/skills/track-work/scripts/lib/views.mjs +50 -1
  233. package/skills/track-work/scripts/working-record.mjs +263 -22
  234. package/skills/verify-work/SKILL.md +64 -47
  235. package/skills/verify-work/references/feature-map.md +120 -0
  236. package/skills/verify-work/references/runtime-evidence.md +203 -0
  237. package/skills/verify-work/references/test-design.md +27 -6
  238. package/skills/verify-work/scripts/test-changes.mjs +246 -0
  239. package/skills/write-docs/SKILL.md +171 -0
  240. package/skills/write-docs/references/documentation-shapes.md +184 -0
  241. package/skills/write-docs/references/spec-and-plan-shapes.md +308 -0
  242. package/skills/write-docs/scripts/artifact-check.mjs +148 -0
  243. package/skills/write-docs/scripts/docs-check.mjs +229 -0
  244. package/skills/write-docs/scripts/plan-lint.mjs +123 -0
  245. package/skills/write-skill/SKILL.md +165 -165
  246. package/skills/write-skill/references/activation-and-wording.md +143 -0
  247. package/skills/write-skill/references/placement-and-dependencies.md +154 -0
  248. package/skills/write-skill/scripts/lib/compare.mjs +701 -0
  249. package/skills/write-skill/scripts/lib/similarity.mjs +56 -0
  250. package/skills/write-skill/scripts/lib/skill-author.mjs +197 -3
  251. package/skills/write-skill/scripts/skill-author.mjs +67 -8
  252. package/capabilities/context-virtualization/SKILL.md +0 -103
  253. package/capabilities/conversation-history/SKILL.md +0 -53
  254. package/hooks/tests/check-host-adapters.test.mjs +0 -82
  255. package/hooks/tests/check-runtime-context-hook.sh +0 -212
  256. package/pi-extension/dist/cognitive-routing-v2/projection.js +0 -330
  257. package/pi-extension/dist/cognitive-routing-v2/runtime.js +0 -2181
  258. package/pi-extension/dist/cognitive-routing-v2/tools.js +0 -60
  259. package/pi-extension/dist/context-virtualization/commands.js +0 -89
  260. package/pi-extension/dist/context-virtualization/projector.js +0 -42
  261. package/pi-extension/dist/context-virtualization/runtime.js +0 -378
  262. package/pi-extension/dist/context-virtualization/state.js +0 -57
  263. package/pi-extension/dist/context-virtualization/types.js +0 -10
  264. package/pi-extension/dist/conversation-history/passages.js +0 -66
  265. package/pi-extension/dist/conversation-history/ranking.js +0 -105
  266. package/pi-extension/dist/conversation-history/runtime.js +0 -226
  267. package/pi-extension/dist/conversation-history/search.js +0 -56
  268. package/pi-extension/dist/conversation-history/types.js +0 -1
  269. package/pi-extension/dist/freeflow-context/resolver.js +0 -120
  270. package/pi-extension/dist/freeflow-context/runtime.js +0 -80
  271. package/pi-extension/dist/freeflow-context/source-projector.js +0 -95
  272. package/pi-extension/dist/freeflow-context/tool.js +0 -314
  273. package/pi-extension/dist/freeflow-context/types.js +0 -12
  274. package/pi-extension/dist/freeflow-context/visibility.js +0 -28
  275. package/pi-extension/dist/integrations/mcp-config.js +0 -29
  276. package/pi-extension/dist/runtime/runtime-context.js +0 -754
  277. package/pi-extension/dist/runtime/runtime-identity.js +0 -5
  278. package/pi-extension/dist/session-sources/provenance.js +0 -32
  279. package/pi-extension/dist/settings/settings-ui.js +0 -1360
  280. package/pi-extension/dist/ui/text-component.js +0 -57
  281. package/pi-extension/src/cognitive-routing-v2/budget.ts +0 -42
  282. package/pi-extension/src/cognitive-routing-v2/config.ts +0 -173
  283. package/pi-extension/src/cognitive-routing-v2/projection.ts +0 -375
  284. package/pi-extension/src/cognitive-routing-v2/render.ts +0 -277
  285. package/pi-extension/src/cognitive-routing-v2/runtime.ts +0 -2241
  286. package/pi-extension/src/cognitive-routing-v2/schemas.ts +0 -180
  287. package/pi-extension/src/cognitive-routing-v2/state.ts +0 -839
  288. package/pi-extension/src/cognitive-routing-v2/tools.ts +0 -62
  289. package/pi-extension/src/cognitive-routing-v2/types.ts +0 -254
  290. package/pi-extension/src/context-virtualization/commands.ts +0 -111
  291. package/pi-extension/src/context-virtualization/projector.ts +0 -62
  292. package/pi-extension/src/context-virtualization/runtime.ts +0 -428
  293. package/pi-extension/src/context-virtualization/state.ts +0 -79
  294. package/pi-extension/src/context-virtualization/types.ts +0 -92
  295. package/pi-extension/src/conversation-history/passages.ts +0 -81
  296. package/pi-extension/src/conversation-history/ranking.ts +0 -155
  297. package/pi-extension/src/conversation-history/runtime.ts +0 -250
  298. package/pi-extension/src/conversation-history/search.ts +0 -79
  299. package/pi-extension/src/conversation-history/types.ts +0 -31
  300. package/pi-extension/src/freeflow-context/resolver.ts +0 -139
  301. package/pi-extension/src/freeflow-context/runtime.ts +0 -100
  302. package/pi-extension/src/freeflow-context/source-projector.ts +0 -106
  303. package/pi-extension/src/freeflow-context/tool.ts +0 -366
  304. package/pi-extension/src/freeflow-context/types.ts +0 -70
  305. package/pi-extension/src/freeflow-context/visibility.ts +0 -53
  306. package/pi-extension/src/index.ts +0 -390
  307. package/pi-extension/src/integrations/mcp-config.ts +0 -32
  308. package/pi-extension/src/provider-support/astra/adapter.ts +0 -108
  309. package/pi-extension/src/provider-support/astra/history.ts +0 -145
  310. package/pi-extension/src/provider-support/astra/index.ts +0 -12
  311. package/pi-extension/src/provider-support/astra/session-state.ts +0 -113
  312. package/pi-extension/src/provider-support/index.ts +0 -5
  313. package/pi-extension/src/runtime/request-history.ts +0 -243
  314. package/pi-extension/src/runtime/runtime-context.ts +0 -860
  315. package/pi-extension/src/runtime/runtime-identity.ts +0 -8
  316. package/pi-extension/src/session-sources/events.ts +0 -230
  317. package/pi-extension/src/session-sources/provenance.ts +0 -39
  318. package/pi-extension/src/session-sources/read-only-session.ts +0 -170
  319. package/pi-extension/src/session-sources/sources.ts +0 -334
  320. package/pi-extension/src/settings/settings-tui.ts +0 -501
  321. package/pi-extension/src/settings/settings-ui.ts +0 -1652
  322. package/pi-extension/src/ui/text-component.ts +0 -66
  323. package/pi-extension/tests/cache-reuse/history.test.js +0 -117
  324. package/pi-extension/tests/cache-reuse/native.test.js +0 -91
  325. package/pi-extension/tests/cache-reuse/settings.test.js +0 -211
  326. package/pi-extension/tests/cognitive-routing-v2/communication.test.js +0 -577
  327. package/pi-extension/tests/cognitive-routing-v2/compaction-input.test.js +0 -183
  328. package/pi-extension/tests/cognitive-routing-v2/delegation.test.js +0 -557
  329. package/pi-extension/tests/cognitive-routing-v2/native.test.js +0 -474
  330. package/pi-extension/tests/cognitive-routing-v2/performance.test.js +0 -87
  331. package/pi-extension/tests/cognitive-routing-v2/persistence.test.js +0 -300
  332. package/pi-extension/tests/cognitive-routing-v2/projection.test.js +0 -241
  333. package/pi-extension/tests/cognitive-routing-v2/recovery.test.js +0 -1034
  334. package/pi-extension/tests/cognitive-routing-v2/render.test.js +0 -244
  335. package/pi-extension/tests/cognitive-routing-v2/runtime.test.js +0 -423
  336. package/pi-extension/tests/cognitive-routing-v2/stabilization.test.js +0 -521
  337. package/pi-extension/tests/cognitive-routing-v2/state.test.js +0 -586
  338. package/pi-extension/tests/context-virtualization/extension.test.js +0 -775
  339. package/pi-extension/tests/context-virtualization/projector.test.js +0 -110
  340. package/pi-extension/tests/context-virtualization/runtime.test.js +0 -230
  341. package/pi-extension/tests/conversation-history/runtime.test.js +0 -98
  342. package/pi-extension/tests/conversation-history/search.test.js +0 -97
  343. package/pi-extension/tests/fixtures/pi-host.js +0 -4
  344. package/pi-extension/tests/fixtures/routing-native.js +0 -191
  345. package/pi-extension/tests/integration/mode-free-core.test.js +0 -220
  346. package/pi-extension/tests/integration/pi-extension.test.js +0 -1447
  347. package/pi-extension/tests/integration/prompt-architecture.test.js +0 -447
  348. package/pi-extension/tests/integration/unaffected-regressions.test.js +0 -478
  349. package/pi-extension/tests/provider-support/astra-boundaries.test.js +0 -75
  350. package/pi-extension/tests/provider-support/astra.test.js +0 -306
  351. package/pi-extension/tests/provider-support/cli.test.js +0 -92
  352. package/pi-extension/tests/provider-support/native.test.js +0 -183
  353. package/pi-extension/tests/settings/settings-tui.test.js +0 -243
  354. package/pi-extension/tsconfig.json +0 -16
  355. package/plugin.json +0 -33
  356. package/runtime/prompts/context-virtualization.md +0 -3
  357. package/runtime/prompts/conversation-history.md +0 -3
  358. package/skills/action-selection/SKILL.md +0 -100
  359. package/skills/action-selection/references/trajectory-stalls.md +0 -71
  360. package/skills/bypass/SKILL.md +0 -153
  361. package/skills/commit-work/SKILL.md +0 -145
  362. package/skills/commit-work/references/git-state-edges.md +0 -94
  363. package/skills/commit-work/references/simple-push.md +0 -92
  364. package/skills/commit-work/references/staging-decisions.md +0 -106
  365. package/skills/decision-gate/SKILL.md +0 -106
  366. package/skills/design-for-depth/SKILL.md +0 -117
  367. package/skills/design-for-depth/references/design-pressure-signals.md +0 -182
  368. package/skills/design-for-depth/references/implementation-decisions.md +0 -76
  369. package/skills/design-for-depth/references/interface-design-loop.md +0 -136
  370. package/skills/design-for-depth/references/module-and-dependency-design.md +0 -147
  371. package/skills/design-for-depth/references/software-design-philosophy.md +0 -202
  372. package/skills/design-for-depth/references/state-and-failure-boundaries.md +0 -136
  373. package/skills/diagnose-failure/SKILL.md +0 -125
  374. package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +0 -48
  375. package/skills/diagnose-failure/references/flaky-and-performance-diagnosis.md +0 -51
  376. package/skills/discuss/SKILL.md +0 -116
  377. package/skills/evaluate-skill/SKILL.md +0 -219
  378. package/skills/evaluate-skill/references/evaluation-definition-schema.md +0 -385
  379. package/skills/evaluate-skill/references/evaluation-design.md +0 -112
  380. package/skills/evaluate-skill/references/execution-and-evidence.md +0 -90
  381. package/skills/evaluate-skill/references/review-and-revision.md +0 -92
  382. package/skills/evaluate-skill/scripts/lib/definitions.mjs +0 -407
  383. package/skills/evaluate-skill/scripts/lib/grade-comparison.mjs +0 -60
  384. package/skills/evaluate-skill/scripts/lib/grade.mjs +0 -64
  385. package/skills/evaluate-skill/scripts/lib/runner.mjs +0 -368
  386. package/skills/evaluate-skill/scripts/pi-guard.mjs +0 -164
  387. package/skills/evaluate-skill/scripts/skill-eval.mjs +0 -102
  388. package/skills/execute-work/references/execute-work-edges.md +0 -68
  389. package/skills/finish-branch/SKILL.md +0 -117
  390. package/skills/finish-branch/references/integration-options.md +0 -80
  391. package/skills/handoff/SKILL.md +0 -82
  392. package/skills/handoff/references/handoff-templates.md +0 -150
  393. package/skills/launch-work/SKILL.md +0 -116
  394. package/skills/launch-work/references/launch-readiness.md +0 -85
  395. package/skills/migration-work/SKILL.md +0 -115
  396. package/skills/migration-work/references/migration-lifecycle.md +0 -82
  397. package/skills/release-work/SKILL.md +0 -118
  398. package/skills/release-work/references/release-evidence.md +0 -78
  399. package/skills/review-artifact/SKILL.md +0 -142
  400. package/skills/review-artifact/references/adjudicate-artifact-review.md +0 -101
  401. package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +0 -159
  402. package/skills/review-work/references/adjudicate-work-review.md +0 -97
  403. package/skills/review-work/references/independent-work-reviewer-contract.md +0 -139
  404. package/skills/review-work/references/security-risk-lens.md +0 -69
  405. package/skills/setup-freeflow/references/activation-contract.md +0 -109
  406. package/skills/setup-freeflow/references/host-setup.md +0 -67
  407. package/skills/simplify-code/SKILL.md +0 -85
  408. package/skills/simplify-code/references/simplification-patterns.md +0 -70
  409. package/skills/verify-work/references/browser-runtime-evidence.md +0 -55
  410. package/skills/verify-work/references/integration-evidence.md +0 -47
  411. package/skills/verify-work/references/performance-evidence.md +0 -57
  412. package/skills/workflow/SKILL.md +0 -127
  413. package/skills/workflow/references/domain-skill-composition.md +0 -43
  414. package/skills/write-plan/SKILL.md +0 -92
  415. package/skills/write-plan/references/plan-shapes.md +0 -156
  416. package/skills/write-skill/references/activation-boundaries.md +0 -104
  417. package/skills/write-skill/references/agent-first-instructions.md +0 -121
  418. package/skills/write-skill/references/progressive-disclosure.md +0 -127
  419. package/skills/write-skill/references/skill-dependency-graphs.md +0 -190
  420. package/skills/write-spec/SKILL.md +0 -92
  421. package/skills/write-spec/references/artifact-standards.md +0 -86
  422. package/skills/write-spec/references/decision-records.md +0 -78
  423. package/skills/write-spec/references/spec-shapes.md +0 -143
  424. /package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/budget.js +0 -0
  425. /package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/evidence.mjs +0 -0
  426. /package/skills/{evaluate-skill → evaluate-behavior}/scripts/pi-observer.mjs +0 -0
@@ -0,0 +1,250 @@
1
+ import { Input, Key, matchesKey, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
2
+ const OWN_ANSWER = "Type my own answer";
3
+ export class QuestionForm {
4
+ questions;
5
+ theme;
6
+ done;
7
+ requestRender;
8
+ options;
9
+ tab = 0;
10
+ cursor;
11
+ picked;
12
+ written = new Map();
13
+ notes = new Map();
14
+ answered = new Set();
15
+ mode = "choose";
16
+ input = new Input();
17
+ cache;
18
+ focusedValue = false;
19
+ constructor(questions, theme, done, requestRender = () => {}, options = {}) {
20
+ this.questions = questions;
21
+ this.theme = theme;
22
+ this.done = done;
23
+ this.requestRender = requestRender;
24
+ this.options = options;
25
+ this.cursor = questions.map(() => 0);
26
+ this.picked = questions.map(() => new Set());
27
+ this.input.onSubmit = (value) => this.submitInput(value);
28
+ this.input.onEscape = () => this.leaveInput();
29
+ }
30
+ get focused() {
31
+ return this.focusedValue;
32
+ }
33
+ set focused(value) {
34
+ this.focusedValue = value;
35
+ this.input.focused = value && this.mode !== "choose";
36
+ }
37
+ get many() {
38
+ return this.questions.length > 1;
39
+ }
40
+ get onSubmitTab() {
41
+ return this.many && this.tab === this.questions.length;
42
+ }
43
+ get ownAnswer() {
44
+ return this.options.ownAnswer !== false;
45
+ }
46
+ rows(index) {
47
+ return this.questions[index].options.length + (this.ownAnswer ? 1 : 0);
48
+ }
49
+ refresh() {
50
+ this.cache = undefined;
51
+ this.requestRender();
52
+ }
53
+ finish() {
54
+ const answers = this.questions.map((question, index) => {
55
+ const note = this.notes.get(index);
56
+ const text = this.written.get(index);
57
+ return {
58
+ header: question.header,
59
+ question: question.question,
60
+ selected:
61
+ text === undefined
62
+ ? [...this.picked[index]].sort((a, b) => a - b).map((at) => question.options[at].label)
63
+ : [],
64
+ ...(text === undefined ? {} : { text }),
65
+ ...(note ? { note } : {}),
66
+ };
67
+ });
68
+ this.done({ status: "answered", answers });
69
+ }
70
+ /** After a question is answered: the next unanswered question, the Submit tab, or done for a single question. */
71
+ advance() {
72
+ this.answered.add(this.tab);
73
+ if (!this.many) return this.finish();
74
+ const next = this.questions.findIndex((_, index) => !this.answered.has(index));
75
+ this.tab = next === -1 ? this.questions.length : next;
76
+ this.refresh();
77
+ }
78
+ submitInput(value) {
79
+ const text = value.trim();
80
+ if (this.mode === "own") {
81
+ if (!text) return;
82
+ this.written.set(this.tab, text);
83
+ this.picked[this.tab].clear();
84
+ this.leaveInput(false);
85
+ this.advance();
86
+ return;
87
+ }
88
+ if (text) this.notes.set(this.tab, text);
89
+ else this.notes.delete(this.tab);
90
+ this.leaveInput();
91
+ }
92
+ leaveInput(render = true) {
93
+ this.mode = "choose";
94
+ this.input.setValue("");
95
+ this.input.focused = false;
96
+ if (render) this.refresh();
97
+ }
98
+ enterInput(mode) {
99
+ this.mode = mode;
100
+ this.input.setValue(mode === "note" ? (this.notes.get(this.tab) ?? "") : (this.written.get(this.tab) ?? ""));
101
+ this.input.focused = this.focusedValue;
102
+ this.refresh();
103
+ }
104
+ handleInput(data) {
105
+ if (this.mode !== "choose") {
106
+ this.input.handleInput(data);
107
+ this.refresh();
108
+ return;
109
+ }
110
+ if (matchesKey(data, Key.escape)) return this.done({ status: "dismissed" });
111
+ if (this.many && (matchesKey(data, Key.tab) || matchesKey(data, Key.right))) {
112
+ this.tab = (this.tab + 1) % (this.questions.length + 1);
113
+ return this.refresh();
114
+ }
115
+ if (this.many && (matchesKey(data, Key.shift("tab")) || matchesKey(data, Key.left))) {
116
+ this.tab = (this.tab + this.questions.length) % (this.questions.length + 1);
117
+ return this.refresh();
118
+ }
119
+ if (this.onSubmitTab) {
120
+ if (matchesKey(data, Key.enter) && this.answered.size === this.questions.length) this.finish();
121
+ return;
122
+ }
123
+ const question = this.questions[this.tab];
124
+ const at = this.cursor[this.tab];
125
+ const own = at === question.options.length;
126
+ if (matchesKey(data, Key.up)) {
127
+ this.cursor[this.tab] = Math.max(0, at - 1);
128
+ return this.refresh();
129
+ }
130
+ if (matchesKey(data, Key.down)) {
131
+ this.cursor[this.tab] = Math.min(this.rows(this.tab) - 1, at + 1);
132
+ return this.refresh();
133
+ }
134
+ if (data === "n" && this.options.notes !== false) return this.enterInput("note");
135
+ if (question.multiSelect && data === " " && !own) {
136
+ const picked = this.picked[this.tab];
137
+ if (picked.has(at)) picked.delete(at);
138
+ else picked.add(at);
139
+ this.written.delete(this.tab);
140
+ this.answered.delete(this.tab);
141
+ return this.refresh();
142
+ }
143
+ if (matchesKey(data, Key.enter)) {
144
+ if (own) return this.enterInput("own");
145
+ const picked = this.picked[this.tab];
146
+ if (!question.multiSelect) {
147
+ picked.clear();
148
+ picked.add(at);
149
+ } else if (picked.size === 0) picked.add(at);
150
+ this.written.delete(this.tab);
151
+ this.advance();
152
+ }
153
+ }
154
+ invalidate() {
155
+ this.cache = undefined;
156
+ }
157
+ render(width) {
158
+ if (this.cache) return this.cache;
159
+ const t = this.theme;
160
+ const w = Math.max(1, width);
161
+ const lines = [];
162
+ const wrap = (prefix, text) => {
163
+ const indent = visibleWidth(prefix);
164
+ const body = wrapTextWithAnsi(text, Math.max(1, w - indent));
165
+ body.forEach((line, i) => lines.push(`${i === 0 ? prefix : " ".repeat(indent)}${line}`));
166
+ };
167
+ lines.push(t.fg("accent", "─".repeat(w)));
168
+ if (this.many) {
169
+ const tabs = this.questions.map((question, index) => {
170
+ const label = ` ${this.answered.has(index) ? "■" : "□"} ${question.header} `;
171
+ return index === this.tab
172
+ ? t.bold(t.fg("accent", label))
173
+ : t.fg(this.answered.has(index) ? "success" : "muted", label);
174
+ });
175
+ const ready = this.answered.size === this.questions.length;
176
+ const submit = " ✓ Submit ";
177
+ tabs.push(this.onSubmitTab ? t.bold(t.fg("accent", submit)) : t.fg(ready ? "success" : "dim", submit));
178
+ wrap(" ", tabs.join(" "));
179
+ lines.push("");
180
+ }
181
+ if (this.onSubmitTab) {
182
+ wrap(" ", t.bold("Your answers"));
183
+ lines.push("");
184
+ this.questions.forEach((question, index) => {
185
+ const text = this.written.get(index);
186
+ const chosen = [...this.picked[index]].map((at) => question.options[at].label).join(", ");
187
+ const answer =
188
+ text !== undefined ? `"${text}"` : this.answered.has(index) ? chosen : t.fg("warning", "not answered");
189
+ wrap(" ", `${t.fg("muted", `${question.header}:`)} ${answer}`);
190
+ const note = this.notes.get(index);
191
+ if (note) wrap(" ", t.fg("dim", `note: ${note}`));
192
+ });
193
+ lines.push("");
194
+ wrap(
195
+ " ",
196
+ this.answered.size === this.questions.length
197
+ ? t.fg("success", "Enter to submit")
198
+ : t.fg("warning", "Answer every question to submit"),
199
+ );
200
+ } else {
201
+ const index = this.tab;
202
+ const question = this.questions[index];
203
+ wrap(" ", `${t.fg("muted", `${question.header} ·`)} ${t.bold(question.question)}`);
204
+ lines.push("");
205
+ const rows = [...question.options, ...(this.ownAnswer ? [{ label: OWN_ANSWER }] : [])];
206
+ rows.forEach((option, at) => {
207
+ const own = at === question.options.length;
208
+ const here = at === this.cursor[index] && this.mode === "choose";
209
+ const mark = question.multiSelect && !own ? (this.picked[index].has(at) ? "[x] " : "[ ] ") : "";
210
+ const chosen = !question.multiSelect && !own && this.answered.has(index) && this.picked[index].has(at);
211
+ const label = `${at + 1}. ${mark}${option.label}${chosen ? " ✓" : ""}`;
212
+ wrap(here ? t.fg("accent", "› ") : " ", here ? t.fg("accent", label) : label);
213
+ const description = own ? this.written.get(index) : option.description;
214
+ if (description) wrap(" ", t.fg("muted", own ? `"${description}"` : description));
215
+ });
216
+ const note = this.notes.get(index);
217
+ if (note && this.mode !== "note") {
218
+ lines.push("");
219
+ wrap(" ", t.fg("dim", `Note: ${note}`));
220
+ }
221
+ if (this.mode !== "choose") {
222
+ lines.push("");
223
+ wrap(" ", t.fg("muted", this.mode === "own" ? "Your answer:" : "Note for this question:"));
224
+ for (const line of this.input.render(Math.max(1, w - 2))) lines.push(` ${line}`);
225
+ }
226
+ }
227
+ lines.push("");
228
+ if (this.options.deadline !== undefined) {
229
+ const left = Math.max(0, Math.ceil((this.options.deadline - Date.now()) / 1000));
230
+ wrap(
231
+ " ",
232
+ t.fg("dim", `Closes in ${Math.floor(left / 60)}:${String(left % 60).padStart(2, "0")} without an answer`),
233
+ );
234
+ }
235
+ const help =
236
+ this.mode !== "choose"
237
+ ? "Enter to save · Esc to go back"
238
+ : [
239
+ "↑↓ move",
240
+ this.questions[this.tab]?.multiSelect ? "Space toggle · Enter confirm" : "Enter choose",
241
+ ...(this.options.notes !== false ? ["n note"] : []),
242
+ ...(this.many ? ["Tab next"] : []),
243
+ "Esc close without answering",
244
+ ].join(" · ");
245
+ wrap(" ", t.fg("dim", help));
246
+ lines.push(t.fg("accent", "─".repeat(w)));
247
+ this.cache = lines;
248
+ return lines;
249
+ }
250
+ }
@@ -0,0 +1,66 @@
1
+ /*
2
+ * The questions ask_user puts to the user, and the answers it returns: Claude Code's AskUserQuestion shape (1-4
3
+ * questions, a short header each, 2-4 options with descriptions, multi-select), since models know it. Every question
4
+ * also accepts the user's own words and a note; the dialog adds those, the model never lists them.
5
+ */
6
+ export const MAX_QUESTIONS = 4;
7
+ export const MIN_OPTIONS = 2;
8
+ export const MAX_OPTIONS = 4;
9
+ export const MAX_HEADER = 12;
10
+ const text = (value) => (typeof value === "string" ? value.trim() : "");
11
+ /** The questions as given, or the first reason they cannot be asked. */
12
+ export function validateQuestions(value) {
13
+ if (!Array.isArray(value) || value.length < 1 || value.length > MAX_QUESTIONS)
14
+ return { error: `Ask 1 to ${MAX_QUESTIONS} questions.` };
15
+ const questions = [];
16
+ const headers = new Set();
17
+ for (const [index, raw] of value.entries()) {
18
+ const at = `Question ${index + 1}`;
19
+ const question = text(raw?.question);
20
+ const header = text(raw?.header);
21
+ if (!question) return { error: `${at} has no question text.` };
22
+ if (!header || header.length > MAX_HEADER)
23
+ return { error: `${at} needs a header of 1 to ${MAX_HEADER} characters.` };
24
+ if (headers.has(header)) return { error: `${at} repeats the header "${header}".` };
25
+ headers.add(header);
26
+ const options = Array.isArray(raw?.options) ? raw.options : [];
27
+ if (options.length < MIN_OPTIONS || options.length > MAX_OPTIONS)
28
+ return { error: `${at} needs ${MIN_OPTIONS} to ${MAX_OPTIONS} options.` };
29
+ const labels = new Set();
30
+ const normalized = [];
31
+ for (const option of options) {
32
+ const label = text(option?.label);
33
+ if (!label) return { error: `${at} has an option with no label.` };
34
+ if (/^other\b/i.test(label))
35
+ return { error: `${at} lists "${label}": the dialog adds the user's own answer itself; remove it.` };
36
+ if (labels.has(label)) return { error: `${at} repeats the option "${label}".` };
37
+ labels.add(label);
38
+ const description = text(option?.description);
39
+ normalized.push(description ? { label, description } : { label });
40
+ }
41
+ questions.push({
42
+ question,
43
+ header,
44
+ options: normalized,
45
+ ...(raw?.multiSelect === true ? { multiSelect: true } : {}),
46
+ });
47
+ }
48
+ return { questions };
49
+ }
50
+ /** What the model reads after the dialog. */
51
+ export function outcomeText(outcome) {
52
+ if (outcome.status === "unavailable") return `${outcome.reason} Ask in your reply and end your turn.`;
53
+ if (outcome.status === "dismissed")
54
+ return "The user closed the dialog without answering. Do not act on the choice: ask in your reply, or continue only with work that does not depend on it.";
55
+ const lines = ["The user answered in a dialog:"];
56
+ for (const answer of outcome.answers) {
57
+ lines.push(`- ${answer.header}: ${answer.question}`);
58
+ if (answer.text !== undefined) lines.push(` Answer, in their words: ${answer.text}`);
59
+ else lines.push(` Answer: ${answer.selected.join("; ")}`);
60
+ if (answer.note) lines.push(` Note: ${answer.note}`);
61
+ }
62
+ lines.push(
63
+ "Each answer decides only its question. A note or written answer that asks something, sets a condition or asks for more information is not a decision: respond to it before acting.",
64
+ );
65
+ return lines.join("\n");
66
+ }
@@ -0,0 +1,124 @@
1
+ import { Text } from "@earendil-works/pi-tui";
2
+ import { firstLine, foldRow, paint } from "../host/rows.js";
3
+ import { askUser } from "./ask.js";
4
+ import { MAX_HEADER, MAX_OPTIONS, MAX_QUESTIONS, MIN_OPTIONS, outcomeText, validateQuestions } from "./questions.js";
5
+ export const ASK_USER = "ask_user";
6
+ const DESCRIPTION = [
7
+ "Ask the user in a dialog when a choice is theirs to make: what to do, which direction to take, whether to go beyond what they asked. The call waits for their answer.",
8
+ `Ask 1 to ${MAX_QUESTIONS} questions. Each has a full-sentence question, a header of at most ${MAX_HEADER} characters, and ${MIN_OPTIONS} to ${MAX_OPTIONS} options: a label of a few words and a description of what choosing it means. Put your recommended option first and end its label with "(Recommended)". Use multiSelect when the options are not exclusive. The dialog adds a field for the user's own answer and a note, so never list an "Other" option.`,
9
+ "Several questions in one call only when each is the user's and none depends on another's answer. Say any context the choice needs in your reply before calling: the dialog shows only the questions and options.",
10
+ "If the user closes the dialog or no one can answer it, the result says so: then ask in your reply.",
11
+ ].join("\n\n");
12
+ // Pi adds a tool's guidelines to the system prompt's rules while the tool is active.
13
+ const GUIDELINE =
14
+ "Use ask_user for a choice that is the user's to make, with the options that matter and your recommendation first; never for facts you can look up or work out.";
15
+ const textOf = (result) =>
16
+ (result?.content ?? [])
17
+ .filter((part) => part?.type === "text")
18
+ .map((part) => part.text ?? "")
19
+ .join("\n");
20
+ /** Registered once, declared only while Freeflow is effective outside subagents. */
21
+ export function registerAskUserTool(pi, host) {
22
+ pi.registerTool({
23
+ name: ASK_USER,
24
+ label: "Question",
25
+ description: DESCRIPTION,
26
+ promptGuidelines: [GUIDELINE],
27
+ parameters: {
28
+ type: "object",
29
+ additionalProperties: false,
30
+ properties: {
31
+ questions: {
32
+ type: "array",
33
+ minItems: 1,
34
+ maxItems: MAX_QUESTIONS,
35
+ items: {
36
+ type: "object",
37
+ additionalProperties: false,
38
+ properties: {
39
+ question: { type: "string", description: "The full question, ending with a question mark." },
40
+ header: {
41
+ type: "string",
42
+ description: `A label of at most ${MAX_HEADER} characters, such as "Default".`,
43
+ },
44
+ options: {
45
+ type: "array",
46
+ minItems: MIN_OPTIONS,
47
+ maxItems: MAX_OPTIONS,
48
+ items: {
49
+ type: "object",
50
+ additionalProperties: false,
51
+ properties: {
52
+ label: { type: "string", description: "A few words; the recommended one first." },
53
+ description: { type: "string", description: "What choosing it means, and its tradeoff." },
54
+ },
55
+ required: ["label", "description"],
56
+ },
57
+ },
58
+ multiSelect: { type: "boolean", description: "True when the user may choose more than one." },
59
+ },
60
+ required: ["question", "header", "options"],
61
+ },
62
+ },
63
+ },
64
+ required: ["questions"],
65
+ },
66
+ // It asks the user, so scripts must not call it, and its transcript views apply (see task_memory).
67
+ exposure: "model-only",
68
+ defaultActive: false,
69
+ executionMode: "sequential",
70
+ // One line each for what was asked and what the user answered; options and notes when expanded or short.
71
+ renderCall: (args, theme, context) => {
72
+ const questions = (Array.isArray(args?.questions) ? args.questions : []).filter((q) => q?.question);
73
+ const title = paint(theme, "toolTitle", "Question");
74
+ if (!questions.length) return new Text(title, 0, 0);
75
+ const head =
76
+ questions.length === 1
77
+ ? `${title} · ${paint(theme, "accent", String(questions[0].header ?? ""))}: ${firstLine(questions[0].question, 120)}`
78
+ : `${title} · ${questions.map((q) => paint(theme, "accent", String(q.header ?? ""))).join(", ")}`;
79
+ const body = questions.flatMap((q) => [
80
+ ...(questions.length > 1 ? [`${q.header}: ${q.question}`] : q.question.length > 120 ? [q.question] : []),
81
+ ...(Array.isArray(q.options) ? q.options : []).map(
82
+ (o) => `${questions.length > 1 ? " " : ""}- ${o.label}${o.description ? ` — ${o.description}` : ""}`,
83
+ ),
84
+ ]);
85
+ return foldRow(head, context?.expanded === true ? body : [], context?.expanded === true, theme);
86
+ },
87
+ renderResult: (result, options, theme) => {
88
+ const outcome = result?.details?.outcome;
89
+ if (outcome?.status === "answered") {
90
+ const lines = outcome.answers.map(
91
+ (answer) =>
92
+ `${answer.header}: ${answer.text !== undefined ? `"${answer.text}"` : answer.selected.join(", ")}${answer.note ? ` (note: ${answer.note})` : ""}`,
93
+ );
94
+ const head = paint(theme, "success", lines.length === 1 ? `Answered · ${lines[0]}` : "Answered");
95
+ return foldRow(head, lines.length === 1 ? [] : lines, options?.expanded === true, theme);
96
+ }
97
+ if (outcome?.status === "dismissed")
98
+ return new Text(paint(theme, "warning", "Closed without answering (Esc)"), 0, 0);
99
+ return new Text(paint(theme, "warning", firstLine(textOf(result)) || "Not asked"), 0, 0);
100
+ },
101
+ async execute(_id, params, signal, _update, ctx) {
102
+ const refused = host.refusal(ctx);
103
+ const checked = validateQuestions(params?.questions);
104
+ let outcome;
105
+ if (refused) outcome = { status: "unavailable", reason: refused };
106
+ else if ("error" in checked)
107
+ return { content: [{ type: "text", text: checked.error }], details: {}, isError: true };
108
+ else outcome = await askUser(ctx, checked.questions, signal);
109
+ return {
110
+ content: [{ type: "text", text: refused ? refused : outcomeText(outcome) }],
111
+ details: { outcome },
112
+ ...(outcome.status === "answered" ? {} : { isError: true }),
113
+ };
114
+ },
115
+ });
116
+ }
117
+ /** Declare or withdraw ask_user, keeping other tools in place. */
118
+ export function applyAskUserTool(pi, effective) {
119
+ if (typeof pi.getActiveTools !== "function" || typeof pi.setActiveTools !== "function") return;
120
+ const current = pi.getActiveTools();
121
+ const present = current.includes(ASK_USER);
122
+ if (effective && !present) pi.setActiveTools([...current, ASK_USER]);
123
+ if (!effective && present) pi.setActiveTools(current.filter((name) => name !== ASK_USER));
124
+ }