@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
@@ -1,326 +0,0 @@
1
- /**
2
- * @pi-unipi/image — Agent tool registration
3
- *
4
- * Registers `image_generate` and `image_recognize`. Each tool is registered
5
- * only when enabled in config, so a user who wants just one does not have the
6
- * other consuming context in the system prompt.
7
- */
8
-
9
- import { Type } from "typebox";
10
- import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
11
- import { IMAGE_TOOLS } from "@pi-unipi/core";
12
-
13
- import { generateImage } from "./generate.js";
14
- import { loadImage } from "./image-source.js";
15
- import { registerRegistryImageProviders } from "./register-providers.js";
16
- import {
17
- findProviderBaseUrl,
18
- formatModelRef,
19
- listAllImageGenModels,
20
- resolveImageGenModel,
21
- resolveVisionModel,
22
- type ChatModelRegistry,
23
- type VisionModel,
24
- } from "./models.js";
25
- import { recognizeImage } from "./recognize.js";
26
- import { getOutputDir, loadConfig } from "./settings.js";
27
-
28
- /** Error shape shared by both tools. */
29
- function errorResult(message: string) {
30
- return {
31
- content: [{ type: "text" as const, text: message }],
32
- isError: true,
33
- details: {},
34
- };
35
- }
36
-
37
- function messageOf(error: unknown): string {
38
- return error instanceof Error ? error.message : String(error);
39
- }
40
-
41
- /** Read the chat model registry off the extension context. */
42
- function getRegistry(ctx: ExtensionContext): ChatModelRegistry | undefined {
43
- return (ctx as unknown as { modelRegistry?: ChatModelRegistry }).modelRegistry;
44
- }
45
-
46
- /** Resolve an API key for a provider through pi's auth storage. */
47
- async function resolveApiKey(
48
- registry: ChatModelRegistry | undefined,
49
- provider: string,
50
- ): Promise<string | undefined> {
51
- try {
52
- const key = await registry?.getApiKeyForProvider?.(provider);
53
- if (key) return key;
54
- } catch {
55
- // Fall through to the environment.
56
- }
57
-
58
- const envName = `${provider.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_API_KEY`;
59
- return process.env[envName] || undefined;
60
- }
61
-
62
- /** Look up the full pi-ai model object for a vision model. */
63
- function findChatModel(
64
- registry: ChatModelRegistry,
65
- model: VisionModel,
66
- ): { baseUrl?: string; api?: string } | undefined {
67
- try {
68
- return registry.find(model.provider, model.id) as
69
- | { baseUrl?: string; api?: string }
70
- | undefined;
71
- } catch {
72
- return undefined;
73
- }
74
- }
75
-
76
- export function registerImageTools(pi: ExtensionAPI): void {
77
- const config = loadConfig();
78
-
79
- if (config.generate.enabled) registerGenerateTool(pi);
80
- if (config.recognize.enabled) registerRecognizeTool(pi);
81
- }
82
-
83
- function registerGenerateTool(pi: ExtensionAPI): void {
84
- pi.registerTool({
85
- name: IMAGE_TOOLS.GENERATE,
86
- label: "Generate Image",
87
- description:
88
- "Generate an image from a text prompt, or edit an existing image by " +
89
- "passing `image`. The result is returned inline and, when enabled, saved to disk.",
90
- promptSnippet: "Generate an image from a text prompt.",
91
- promptGuidelines: [
92
- "Use image_generate to create images from a text description.",
93
- "Write a detailed prompt — subject, style, composition and lighting all help.",
94
- "Pass `image` to edit an existing image instead of generating a new one.",
95
- "Editing regenerates the whole image, so unmentioned details may change.",
96
- "Describe what you DO want; negation is unreliable in image models.",
97
- "Omit model to use the one configured in /unipi:settings.",
98
- "Generated images cost money per call; do not regenerate without being asked.",
99
- ],
100
- parameters: Type.Object({
101
- prompt: Type.String({
102
- description: "Description of the image to generate. Be specific.",
103
- }),
104
- image: Type.Optional(
105
- Type.String({
106
- description:
107
- "Source image to edit: a local file path, data: URL, or base64 data. " +
108
- "When set, the model edits this image instead of generating from scratch.",
109
- }),
110
- ),
111
- model: Type.Optional(
112
- Type.String({
113
- description:
114
- 'Image model override, e.g. "flux.2-pro" or ' +
115
- '"openrouter/google/gemini-3-pro-image". Omit to use the configured default.',
116
- }),
117
- ),
118
- }),
119
- async execute(_toolCallId, params, signal, _onUpdate, ctx) {
120
- try {
121
- const config = loadConfig();
122
- const registry = getRegistry(ctx);
123
- // Bridge pi's own providers into pi-ai's images collection so the user
124
- // is not forced onto OpenRouter. Idempotent and best-effort.
125
- await registerRegistryImageProviders(registry);
126
- // Include image models contributed by registered providers, so the
127
- // tool can resolve anything the settings picker offers.
128
- const models = await listAllImageGenModels(registry);
129
-
130
- const requested = params.model?.trim() || config.generate.model;
131
- const maybeResolved = resolveImageGenModel(requested, models);
132
- if (typeof maybeResolved === "string") return errorResult(maybeResolved);
133
-
134
- // A model may arrive without an endpoint — notably a user-typed
135
- // "provider/model-id", accepted at face value. Fill it in from the
136
- // registry so the adapter knows where to POST.
137
- const registryBaseUrl = maybeResolved.baseUrl
138
- ? undefined
139
- : findProviderBaseUrl(registry, maybeResolved.provider);
140
- const resolved = registryBaseUrl
141
- ? { ...maybeResolved, baseUrl: registryBaseUrl }
142
- : maybeResolved;
143
-
144
- // pi-ai resolves image auth from its own credential store; only fall
145
- // back to pi's chat-provider key when that comes up empty.
146
- const fallbackKey = await resolveApiKey(registry, resolved.provider);
147
-
148
- // An input image switches the request into edit mode.
149
- const sourceImage = params.image?.trim()
150
- ? loadImage(params.image, ctx.cwd ?? process.cwd())
151
- : undefined;
152
-
153
- const result = await generateImage({
154
- prompt: params.prompt,
155
- model: resolved,
156
- ...(fallbackKey ? { apiKey: fallbackKey } : {}),
157
- ...(sourceImage ? { inputImage: sourceImage } : {}),
158
- signal,
159
- outputDir: config.generate.saveToDisk ? getOutputDir(config) : undefined,
160
- });
161
-
162
- const saved = result.images
163
- .map((image) => image.path)
164
- .filter((path): path is string => Boolean(path));
165
-
166
- const summary = [
167
- `${sourceImage ? "Edited" : "Generated"} ${result.images.length} ` +
168
- `image${result.images.length === 1 ? "" : "s"} with ${formatModelRef(resolved)}.`,
169
- saved.length > 0 ? `Saved to:\n${saved.map((p) => ` ${p}`).join("\n")}` : "",
170
- config.generate.saveToDisk && saved.length === 0
171
- ? "Could not write to the output directory — returning the image inline only."
172
- : "",
173
- result.text,
174
- ]
175
- .filter(Boolean)
176
- .join("\n");
177
-
178
- return {
179
- content: [
180
- { type: "text" as const, text: summary },
181
- ...result.images.map((image) => ({
182
- type: "image" as const,
183
- data: image.data,
184
- mimeType: image.mimeType,
185
- })),
186
- ],
187
- details: {
188
- model: formatModelRef(resolved),
189
- count: result.images.length,
190
- paths: saved,
191
- },
192
- };
193
- } catch (error) {
194
- return errorResult(`Image generation failed: ${messageOf(error)}`);
195
- }
196
- },
197
- });
198
- }
199
-
200
- function registerRecognizeTool(pi: ExtensionAPI): void {
201
- pi.registerTool({
202
- name: IMAGE_TOOLS.RECOGNIZE,
203
- label: "Recognize Image",
204
- description:
205
- "Analyze an image and answer questions about it using a vision model. " +
206
- "Accepts a local file path, a data: URL, or base64 image data.",
207
- promptSnippet: "Analyze an image and answer questions about it.",
208
- promptGuidelines: [
209
- "Use image_recognize to read screenshots, diagrams, mockups and photos.",
210
- "Pass a local file path whenever possible — it is cheaper than inlining base64.",
211
- "Ask a specific question in `prompt` to focus the analysis.",
212
- "Remote URLs are not fetched; download the image first.",
213
- ],
214
- parameters: Type.Object({
215
- image: Type.String({
216
- description:
217
- "Local file path, data: URL, or base64 image data. " +
218
- "Supported types: PNG, JPEG, GIF, WebP.",
219
- }),
220
- prompt: Type.Optional(
221
- Type.String({
222
- description:
223
- "What to ask about the image. Defaults to a general description.",
224
- }),
225
- ),
226
- model: Type.Optional(
227
- Type.String({
228
- description:
229
- "Vision model override. Must accept image input. " +
230
- "Omit to use the configured default or the current session model.",
231
- }),
232
- ),
233
- systemPrompt: Type.Optional(
234
- Type.String({
235
- description:
236
- "Override the configured system prompt for this call only.",
237
- }),
238
- ),
239
- }),
240
- async execute(_toolCallId, params, signal, _onUpdate, ctx) {
241
- try {
242
- const config = loadConfig();
243
-
244
- const registry = getRegistry(ctx);
245
- if (!registry) {
246
- return errorResult(
247
- "Model registry unavailable — image_recognize needs an active session.",
248
- );
249
- }
250
-
251
- // Precedence: per-call override, configured model, session model.
252
- const requested =
253
- params.model?.trim() ||
254
- config.recognize.model.trim() ||
255
- currentSessionModel(ctx);
256
-
257
- if (!requested) {
258
- return errorResult(
259
- "No vision model configured.\n" +
260
- "→ Choose one with /unipi:settings, or pass `model`.",
261
- );
262
- }
263
-
264
- const resolved = resolveVisionModel(requested, registry);
265
- if (typeof resolved === "string") return errorResult(resolved);
266
-
267
- const image = loadImage(params.image, ctx.cwd ?? process.cwd());
268
-
269
- const chatModel = findChatModel(registry, resolved);
270
- const baseUrl = chatModel?.baseUrl;
271
- if (!baseUrl) {
272
- return errorResult(
273
- `Could not determine the API endpoint for ${formatModelRef(resolved)}.`,
274
- );
275
- }
276
-
277
- const apiKey = await resolveApiKey(registry, resolved.provider);
278
- if (!apiKey) {
279
- return errorResult(
280
- `No API key for provider "${resolved.provider}".\n` +
281
- "→ Sign in with /login, or set the provider's API key environment variable.",
282
- );
283
- }
284
-
285
- const result = await recognizeImage({
286
- image,
287
- prompt: params.prompt?.trim() || "Describe this image in detail.",
288
- systemPrompt: params.systemPrompt?.trim() || config.recognize.systemPrompt,
289
- apiKey,
290
- baseUrl,
291
- api: chatModel?.api ?? "openai-completions",
292
- modelId: resolved.id,
293
- signal,
294
- });
295
-
296
- const origin = image.path ? ` (${image.path})` : "";
297
-
298
- return {
299
- content: [
300
- {
301
- type: "text" as const,
302
- text: `${result.text}\n\n— analyzed with ${formatModelRef(resolved)}${origin}`,
303
- },
304
- ],
305
- details: {
306
- model: formatModelRef(resolved),
307
- mimeType: image.mimeType,
308
- source: image.source,
309
- ...(image.path ? { path: image.path } : {}),
310
- },
311
- };
312
- } catch (error) {
313
- return errorResult(`Image recognition failed: ${messageOf(error)}`);
314
- }
315
- },
316
- });
317
- }
318
-
319
- /** The session's current model as "provider/id", when discoverable. */
320
- function currentSessionModel(ctx: ExtensionContext): string {
321
- const model = (ctx as unknown as { model?: { provider?: string; id?: string } }).model;
322
- if (model?.provider && model?.id) {
323
- return formatModelRef({ provider: model.provider, id: model.id });
324
- }
325
- return "";
326
- }
@@ -1,119 +0,0 @@
1
- /**
2
- * Cross-platform clipboard read/write using child_process.
3
- * Detection order: xclip → xsel → pbcopy/pbpaste → clip/powershell.
4
- * Caches detected command on first use.
5
- */
6
-
7
- import { execSync } from "node:child_process";
8
-
9
- export interface ClipboardResult {
10
- ok: boolean;
11
- text?: string;
12
- reason?: string;
13
- }
14
-
15
- type ClipboardTool = "xclip" | "xsel" | "pbcopy" | "clip" | "powershell" | null;
16
-
17
- let cachedTool: ClipboardTool | undefined; // undefined = not yet detected
18
-
19
- /**
20
- * Detect available clipboard command. Caches result.
21
- */
22
- export function detectClipboard(): ClipboardTool {
23
- if (cachedTool !== undefined) return cachedTool;
24
-
25
- const tools: Array<{ name: ClipboardTool; test: string }> = [
26
- { name: "xclip", test: "xclip -selection clipboard -o" },
27
- { name: "xsel", test: "xsel --clipboard --output" },
28
- { name: "pbcopy", test: "pbpaste" },
29
- { name: "clip", test: "echo test | clip" },
30
- { name: "powershell", test: "powershell -command Get-Clipboard" },
31
- ];
32
-
33
- for (const tool of tools) {
34
- try {
35
- execSync(tool.test, { stdio: "ignore", timeout: 2000 });
36
- cachedTool = tool.name;
37
- return cachedTool;
38
- } catch {
39
- // Try next tool
40
- }
41
- }
42
-
43
- cachedTool = null;
44
- return null;
45
- }
46
-
47
- /**
48
- * Copy text to system clipboard.
49
- */
50
- export function copyToClipboard(text: string): ClipboardResult {
51
- const tool = detectClipboard();
52
- if (!tool) return { ok: false, reason: "clipboard unavailable" };
53
-
54
- try {
55
- switch (tool) {
56
- case "xclip":
57
- execSync("xclip -selection clipboard", { input: text, timeout: 2000 });
58
- break;
59
- case "xsel":
60
- execSync("xsel --clipboard --input", { input: text, timeout: 2000 });
61
- break;
62
- case "pbcopy":
63
- execSync("pbcopy", { input: text, timeout: 2000 });
64
- break;
65
- case "clip":
66
- execSync("clip", { input: text, timeout: 2000 });
67
- break;
68
- case "powershell":
69
- execSync(`powershell -command "Set-Clipboard -Value '${text.replace(/'/g, "''")}'"`, { timeout: 2000 });
70
- break;
71
- }
72
- return { ok: true };
73
- } catch {
74
- return { ok: false, reason: "clipboard write failed" };
75
- }
76
- }
77
-
78
- /**
79
- * Read text from system clipboard.
80
- */
81
- export function pasteFromClipboard(): ClipboardResult {
82
- const tool = detectClipboard();
83
- if (!tool) return { ok: false, reason: "clipboard unavailable" };
84
-
85
- try {
86
- let text: string;
87
- switch (tool) {
88
- case "xclip":
89
- text = execSync("xclip -selection clipboard -o", { encoding: "utf-8", timeout: 2000 }).trimEnd();
90
- break;
91
- case "xsel":
92
- text = execSync("xsel --clipboard --output", { encoding: "utf-8", timeout: 2000 }).trimEnd();
93
- break;
94
- case "pbcopy":
95
- // pbcopy is write-only; use pbpaste for reading
96
- text = execSync("pbpaste", { encoding: "utf-8", timeout: 2000 }).trimEnd();
97
- break;
98
- case "clip":
99
- // clip is write-only on Windows; use powershell for reading
100
- text = execSync("powershell -command Get-Clipboard", { encoding: "utf-8", timeout: 2000 }).trimEnd();
101
- break;
102
- case "powershell":
103
- text = execSync("powershell -command Get-Clipboard", { encoding: "utf-8", timeout: 2000 }).trimEnd();
104
- break;
105
- default:
106
- return { ok: false, reason: "clipboard unavailable" };
107
- }
108
- return { ok: true, text };
109
- } catch {
110
- return { ok: false, reason: "clipboard read failed" };
111
- }
112
- }
113
-
114
- /**
115
- * Reset cached tool detection (for testing).
116
- */
117
- export function resetClipboardCache(): void {
118
- cachedTool = undefined;
119
- }