pi-ui-extend 0.1.1

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 (420) hide show
  1. package/README.md +307 -0
  2. package/bin/pix.mjs +219 -0
  3. package/dist/app/app.d.ts +96 -0
  4. package/dist/app/app.js +871 -0
  5. package/dist/app/blink-controller.d.ts +23 -0
  6. package/dist/app/blink-controller.js +82 -0
  7. package/dist/app/cli.d.ts +8 -0
  8. package/dist/app/cli.js +83 -0
  9. package/dist/app/clipboard.d.ts +1 -0
  10. package/dist/app/clipboard.js +24 -0
  11. package/dist/app/command-controller.d.ts +18 -0
  12. package/dist/app/command-controller.js +58 -0
  13. package/dist/app/command-host.d.ts +44 -0
  14. package/dist/app/command-host.js +1 -0
  15. package/dist/app/command-model-actions.d.ts +12 -0
  16. package/dist/app/command-model-actions.js +176 -0
  17. package/dist/app/command-navigation-actions.d.ts +19 -0
  18. package/dist/app/command-navigation-actions.js +267 -0
  19. package/dist/app/command-registry.d.ts +32 -0
  20. package/dist/app/command-registry.js +225 -0
  21. package/dist/app/command-runtime.d.ts +5 -0
  22. package/dist/app/command-runtime.js +32 -0
  23. package/dist/app/command-session-actions.d.ts +20 -0
  24. package/dist/app/command-session-actions.js +295 -0
  25. package/dist/app/constants.d.ts +52 -0
  26. package/dist/app/constants.js +103 -0
  27. package/dist/app/conversation-entry-renderer.d.ts +21 -0
  28. package/dist/app/conversation-entry-renderer.js +81 -0
  29. package/dist/app/conversation-shell-renderer.d.ts +5 -0
  30. package/dist/app/conversation-shell-renderer.js +43 -0
  31. package/dist/app/conversation-tool-renderer.d.ts +16 -0
  32. package/dist/app/conversation-tool-renderer.js +216 -0
  33. package/dist/app/conversation-viewport.d.ts +55 -0
  34. package/dist/app/conversation-viewport.js +252 -0
  35. package/dist/app/dcp-stats.d.ts +2 -0
  36. package/dist/app/dcp-stats.js +116 -0
  37. package/dist/app/editor-layout-renderer.d.ts +31 -0
  38. package/dist/app/editor-layout-renderer.js +211 -0
  39. package/dist/app/editor-panels.d.ts +4 -0
  40. package/dist/app/editor-panels.js +130 -0
  41. package/dist/app/extension-actions-controller.d.ts +22 -0
  42. package/dist/app/extension-actions-controller.js +60 -0
  43. package/dist/app/extension-event-bus.d.ts +3 -0
  44. package/dist/app/extension-event-bus.js +23 -0
  45. package/dist/app/extension-ui-controller.d.ts +57 -0
  46. package/dist/app/extension-ui-controller.js +532 -0
  47. package/dist/app/file-link-opener.d.ts +2 -0
  48. package/dist/app/file-link-opener.js +66 -0
  49. package/dist/app/file-links.d.ts +10 -0
  50. package/dist/app/file-links.js +117 -0
  51. package/dist/app/guards.d.ts +3 -0
  52. package/dist/app/guards.js +9 -0
  53. package/dist/app/icons.d.ts +37 -0
  54. package/dist/app/icons.js +97 -0
  55. package/dist/app/id.d.ts +1 -0
  56. package/dist/app/id.js +4 -0
  57. package/dist/app/image-click-targets.d.ts +5 -0
  58. package/dist/app/image-click-targets.js +32 -0
  59. package/dist/app/image-opener.d.ts +2 -0
  60. package/dist/app/image-opener.js +64 -0
  61. package/dist/app/input-action-controller.d.ts +47 -0
  62. package/dist/app/input-action-controller.js +209 -0
  63. package/dist/app/input-controller.d.ts +60 -0
  64. package/dist/app/input-controller.js +425 -0
  65. package/dist/app/input-paste-handler.d.ts +27 -0
  66. package/dist/app/input-paste-handler.js +146 -0
  67. package/dist/app/menu-items-controller.d.ts +32 -0
  68. package/dist/app/menu-items-controller.js +182 -0
  69. package/dist/app/message-content.d.ts +8 -0
  70. package/dist/app/message-content.js +115 -0
  71. package/dist/app/model-ref.d.ts +13 -0
  72. package/dist/app/model-ref.js +50 -0
  73. package/dist/app/model-usage-controller.d.ts +35 -0
  74. package/dist/app/model-usage-controller.js +99 -0
  75. package/dist/app/model-usage-status.d.ts +125 -0
  76. package/dist/app/model-usage-status.js +749 -0
  77. package/dist/app/mouse-controller.d.ts +182 -0
  78. package/dist/app/mouse-controller.js +968 -0
  79. package/dist/app/native-modifiers.d.ts +3 -0
  80. package/dist/app/native-modifiers.js +60 -0
  81. package/dist/app/nerd-font-controller.d.ts +11 -0
  82. package/dist/app/nerd-font-controller.js +90 -0
  83. package/dist/app/popup-action-controller.d.ts +44 -0
  84. package/dist/app/popup-action-controller.js +278 -0
  85. package/dist/app/popup-menu-controller.d.ts +183 -0
  86. package/dist/app/popup-menu-controller.js +1070 -0
  87. package/dist/app/prompt-enhancer-controller.d.ts +40 -0
  88. package/dist/app/prompt-enhancer-controller.js +215 -0
  89. package/dist/app/queued-message-controller.d.ts +62 -0
  90. package/dist/app/queued-message-controller.js +377 -0
  91. package/dist/app/render-controller.d.ts +41 -0
  92. package/dist/app/render-controller.js +378 -0
  93. package/dist/app/render-text.d.ts +19 -0
  94. package/dist/app/render-text.js +67 -0
  95. package/dist/app/request-history.d.ts +23 -0
  96. package/dist/app/request-history.js +131 -0
  97. package/dist/app/runtime.d.ts +39 -0
  98. package/dist/app/runtime.js +195 -0
  99. package/dist/app/screen-selection.d.ts +6 -0
  100. package/dist/app/screen-selection.js +9 -0
  101. package/dist/app/screen-styler.d.ts +34 -0
  102. package/dist/app/screen-styler.js +168 -0
  103. package/dist/app/scroll-controller.d.ts +51 -0
  104. package/dist/app/scroll-controller.js +207 -0
  105. package/dist/app/session-event-controller.d.ts +69 -0
  106. package/dist/app/session-event-controller.js +338 -0
  107. package/dist/app/session-history.d.ts +23 -0
  108. package/dist/app/session-history.js +164 -0
  109. package/dist/app/session-lifecycle-controller.d.ts +55 -0
  110. package/dist/app/session-lifecycle-controller.js +116 -0
  111. package/dist/app/session-search.d.ts +24 -0
  112. package/dist/app/session-search.js +215 -0
  113. package/dist/app/shell-command.d.ts +27 -0
  114. package/dist/app/shell-command.js +176 -0
  115. package/dist/app/shell-controller.d.ts +28 -0
  116. package/dist/app/shell-controller.js +124 -0
  117. package/dist/app/slash-commands.d.ts +6 -0
  118. package/dist/app/slash-commands.js +75 -0
  119. package/dist/app/startup-checks.d.ts +8 -0
  120. package/dist/app/startup-checks.js +59 -0
  121. package/dist/app/startup-info.d.ts +3 -0
  122. package/dist/app/startup-info.js +176 -0
  123. package/dist/app/status-controller.d.ts +35 -0
  124. package/dist/app/status-controller.js +105 -0
  125. package/dist/app/status-line-renderer.d.ts +68 -0
  126. package/dist/app/status-line-renderer.js +453 -0
  127. package/dist/app/subagents-files.d.ts +10 -0
  128. package/dist/app/subagents-files.js +193 -0
  129. package/dist/app/subagents-model.d.ts +23 -0
  130. package/dist/app/subagents-model.js +224 -0
  131. package/dist/app/subagents-widget-controller.d.ts +43 -0
  132. package/dist/app/subagents-widget-controller.js +311 -0
  133. package/dist/app/tab-line-renderer.d.ts +26 -0
  134. package/dist/app/tab-line-renderer.js +222 -0
  135. package/dist/app/tabs-controller.d.ts +100 -0
  136. package/dist/app/tabs-controller.js +885 -0
  137. package/dist/app/terminal-controller.d.ts +40 -0
  138. package/dist/app/terminal-controller.js +135 -0
  139. package/dist/app/terminal-edit-shortcuts.d.ts +23 -0
  140. package/dist/app/terminal-edit-shortcuts.js +138 -0
  141. package/dist/app/terminal-output-buffer.d.ts +20 -0
  142. package/dist/app/terminal-output-buffer.js +52 -0
  143. package/dist/app/toast-controller.d.ts +13 -0
  144. package/dist/app/toast-controller.js +40 -0
  145. package/dist/app/toast-renderer.d.ts +9 -0
  146. package/dist/app/toast-renderer.js +79 -0
  147. package/dist/app/todo-model.d.ts +22 -0
  148. package/dist/app/todo-model.js +179 -0
  149. package/dist/app/todo-widget-controller.d.ts +21 -0
  150. package/dist/app/todo-widget-controller.js +59 -0
  151. package/dist/app/tool-block-renderer.d.ts +26 -0
  152. package/dist/app/tool-block-renderer.js +439 -0
  153. package/dist/app/types.d.ts +550 -0
  154. package/dist/app/types.js +1 -0
  155. package/dist/app/update.d.ts +36 -0
  156. package/dist/app/update.js +315 -0
  157. package/dist/app/voice-controller.d.ts +52 -0
  158. package/dist/app/voice-controller.js +600 -0
  159. package/dist/app/workspace-actions-controller.d.ts +40 -0
  160. package/dist/app/workspace-actions-controller.js +215 -0
  161. package/dist/app/workspace-undo.d.ts +44 -0
  162. package/dist/app/workspace-undo.js +215 -0
  163. package/dist/config.d.ts +62 -0
  164. package/dist/config.js +527 -0
  165. package/dist/context-progress-bar.d.ts +17 -0
  166. package/dist/context-progress-bar.js +48 -0
  167. package/dist/default-pix-config.d.ts +1 -0
  168. package/dist/default-pix-config.js +375 -0
  169. package/dist/fuzzy.d.ts +23 -0
  170. package/dist/fuzzy.js +165 -0
  171. package/dist/input-editor-files.d.ts +15 -0
  172. package/dist/input-editor-files.js +62 -0
  173. package/dist/input-editor.d.ts +186 -0
  174. package/dist/input-editor.js +835 -0
  175. package/dist/main.d.ts +1 -0
  176. package/dist/main.js +12 -0
  177. package/dist/markdown-format.d.ts +22 -0
  178. package/dist/markdown-format.js +542 -0
  179. package/dist/sdk.d.ts +3 -0
  180. package/dist/sdk.js +1 -0
  181. package/dist/syntax-highlight.d.ts +22 -0
  182. package/dist/syntax-highlight.js +528 -0
  183. package/dist/terminal-width.d.ts +6 -0
  184. package/dist/terminal-width.js +245 -0
  185. package/dist/theme.d.ts +56 -0
  186. package/dist/theme.js +118 -0
  187. package/dist/tool-renderers/apply-patch.d.ts +2 -0
  188. package/dist/tool-renderers/apply-patch.js +36 -0
  189. package/dist/tool-renderers/ast.d.ts +2 -0
  190. package/dist/tool-renderers/ast.js +5 -0
  191. package/dist/tool-renderers/compress.d.ts +2 -0
  192. package/dist/tool-renderers/compress.js +126 -0
  193. package/dist/tool-renderers/index.d.ts +3 -0
  194. package/dist/tool-renderers/index.js +44 -0
  195. package/dist/tool-renderers/question.d.ts +2 -0
  196. package/dist/tool-renderers/question.js +88 -0
  197. package/dist/tool-renderers/read.d.ts +2 -0
  198. package/dist/tool-renderers/read.js +36 -0
  199. package/dist/tool-renderers/repo.d.ts +2 -0
  200. package/dist/tool-renderers/repo.js +13 -0
  201. package/dist/tool-renderers/shell.d.ts +3 -0
  202. package/dist/tool-renderers/shell.js +27 -0
  203. package/dist/tool-renderers/skill.d.ts +2 -0
  204. package/dist/tool-renderers/skill.js +132 -0
  205. package/dist/tool-renderers/subagents.d.ts +2 -0
  206. package/dist/tool-renderers/subagents.js +51 -0
  207. package/dist/tool-renderers/todo.d.ts +2 -0
  208. package/dist/tool-renderers/todo.js +9 -0
  209. package/dist/tool-renderers/types.d.ts +42 -0
  210. package/dist/tool-renderers/types.js +1 -0
  211. package/dist/tool-renderers/utils.d.ts +31 -0
  212. package/dist/tool-renderers/utils.js +230 -0
  213. package/dist/tool-renderers/web.d.ts +3 -0
  214. package/dist/tool-renderers/web.js +9 -0
  215. package/dist/tool-renderers/write.d.ts +2 -0
  216. package/dist/tool-renderers/write.js +42 -0
  217. package/dist/ui.d.ts +56 -0
  218. package/dist/ui.js +94 -0
  219. package/docs/release.md +81 -0
  220. package/extensions/question/contract.ts +100 -0
  221. package/extensions/question/index.ts +34 -0
  222. package/extensions/question/render.ts +28 -0
  223. package/extensions/question/result.ts +86 -0
  224. package/extensions/question/tool-description.ts +11 -0
  225. package/extensions/question/tui.ts +629 -0
  226. package/extensions/question/types.ts +123 -0
  227. package/extensions/session-title/config.ts +169 -0
  228. package/extensions/session-title/index.ts +459 -0
  229. package/extensions/terminal-bell/index.ts +315 -0
  230. package/external/pi-tools-suite/README.md +242 -0
  231. package/external/pi-tools-suite/index.ts +1 -0
  232. package/external/pi-tools-suite/licenses/ollama-pi-web-search.MIT +21 -0
  233. package/external/pi-tools-suite/licenses/opencode-mystatus-MIT.txt +21 -0
  234. package/external/pi-tools-suite/package.json +53 -0
  235. package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +194 -0
  236. package/external/pi-tools-suite/src/antigravity-auth/commands.ts +80 -0
  237. package/external/pi-tools-suite/src/antigravity-auth/constants.ts +26 -0
  238. package/external/pi-tools-suite/src/antigravity-auth/headers.ts +20 -0
  239. package/external/pi-tools-suite/src/antigravity-auth/index.ts +104 -0
  240. package/external/pi-tools-suite/src/antigravity-auth/models.ts +86 -0
  241. package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +305 -0
  242. package/external/pi-tools-suite/src/antigravity-auth/payload.ts +423 -0
  243. package/external/pi-tools-suite/src/antigravity-auth/status.ts +78 -0
  244. package/external/pi-tools-suite/src/antigravity-auth/stream.ts +302 -0
  245. package/external/pi-tools-suite/src/antigravity-auth/types.ts +113 -0
  246. package/external/pi-tools-suite/src/ast-grep/index.ts +6 -0
  247. package/external/pi-tools-suite/src/ast-grep/render.ts +70 -0
  248. package/external/pi-tools-suite/src/ast-grep/schema.ts +109 -0
  249. package/external/pi-tools-suite/src/ast-grep/tool.ts +345 -0
  250. package/external/pi-tools-suite/src/ast-grep/types.ts +55 -0
  251. package/external/pi-tools-suite/src/ast-grep/utils.ts +65 -0
  252. package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +222 -0
  253. package/external/pi-tools-suite/src/async-subagents/commands.ts +518 -0
  254. package/external/pi-tools-suite/src/async-subagents/constants.ts +11 -0
  255. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +74 -0
  256. package/external/pi-tools-suite/src/async-subagents/core/attachment-bridge.ts +133 -0
  257. package/external/pi-tools-suite/src/async-subagents/core/cleanup.ts +66 -0
  258. package/external/pi-tools-suite/src/async-subagents/core/concurrency.ts +90 -0
  259. package/external/pi-tools-suite/src/async-subagents/core/config.ts +819 -0
  260. package/external/pi-tools-suite/src/async-subagents/core/log-limits.ts +166 -0
  261. package/external/pi-tools-suite/src/async-subagents/core/model-fallback.ts +133 -0
  262. package/external/pi-tools-suite/src/async-subagents/core/paths.ts +47 -0
  263. package/external/pi-tools-suite/src/async-subagents/core/pi-invocation.ts +35 -0
  264. package/external/pi-tools-suite/src/async-subagents/core/presets.ts +67 -0
  265. package/external/pi-tools-suite/src/async-subagents/core/process.ts +15 -0
  266. package/external/pi-tools-suite/src/async-subagents/core/prompt.ts +66 -0
  267. package/external/pi-tools-suite/src/async-subagents/core/registry.ts +224 -0
  268. package/external/pi-tools-suite/src/async-subagents/core/retry.ts +191 -0
  269. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +259 -0
  270. package/external/pi-tools-suite/src/async-subagents/core/sessions.ts +138 -0
  271. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +688 -0
  272. package/external/pi-tools-suite/src/async-subagents/core/state.ts +281 -0
  273. package/external/pi-tools-suite/src/async-subagents/core/stop.ts +131 -0
  274. package/external/pi-tools-suite/src/async-subagents/core/structured-result.ts +237 -0
  275. package/external/pi-tools-suite/src/async-subagents/core/tool-guard.ts +34 -0
  276. package/external/pi-tools-suite/src/async-subagents/core/types.ts +150 -0
  277. package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +184 -0
  278. package/external/pi-tools-suite/src/async-subagents/core/utils.ts +11 -0
  279. package/external/pi-tools-suite/src/async-subagents/format.ts +41 -0
  280. package/external/pi-tools-suite/src/async-subagents/index.ts +422 -0
  281. package/external/pi-tools-suite/src/async-subagents/lib.ts +88 -0
  282. package/external/pi-tools-suite/src/async-subagents/live.ts +10 -0
  283. package/external/pi-tools-suite/src/async-subagents/polling.ts +83 -0
  284. package/external/pi-tools-suite/src/async-subagents/render.ts +230 -0
  285. package/external/pi-tools-suite/src/async-subagents/subagent-overlay.ts +77 -0
  286. package/external/pi-tools-suite/src/async-subagents/tasks.ts +120 -0
  287. package/external/pi-tools-suite/src/async-subagents/tools/cleanup.ts +99 -0
  288. package/external/pi-tools-suite/src/async-subagents/tools/result.ts +179 -0
  289. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +372 -0
  290. package/external/pi-tools-suite/src/async-subagents/tools/status.ts +60 -0
  291. package/external/pi-tools-suite/src/async-subagents/tools/stop.ts +79 -0
  292. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +152 -0
  293. package/external/pi-tools-suite/src/async-subagents/tools/wait.ts +67 -0
  294. package/external/pi-tools-suite/src/async-subagents/types.ts +45 -0
  295. package/external/pi-tools-suite/src/async-subagents/ui.ts +5 -0
  296. package/external/pi-tools-suite/src/compress/commands.ts +440 -0
  297. package/external/pi-tools-suite/src/compress/compress-tool.ts +368 -0
  298. package/external/pi-tools-suite/src/compress/compression-blocks.ts +524 -0
  299. package/external/pi-tools-suite/src/compress/config.ts +310 -0
  300. package/external/pi-tools-suite/src/compress/dcp-tui-filter.ts +498 -0
  301. package/external/pi-tools-suite/src/compress/index.ts +397 -0
  302. package/external/pi-tools-suite/src/compress/prompts.ts +269 -0
  303. package/external/pi-tools-suite/src/compress/pruner-candidates.ts +176 -0
  304. package/external/pi-tools-suite/src/compress/pruner-compression-blocks.ts +260 -0
  305. package/external/pi-tools-suite/src/compress/pruner-message-ids.ts +147 -0
  306. package/external/pi-tools-suite/src/compress/pruner-metadata.ts +268 -0
  307. package/external/pi-tools-suite/src/compress/pruner-nudge.ts +315 -0
  308. package/external/pi-tools-suite/src/compress/pruner-tools.ts +263 -0
  309. package/external/pi-tools-suite/src/compress/pruner-types.ts +25 -0
  310. package/external/pi-tools-suite/src/compress/pruner.ts +92 -0
  311. package/external/pi-tools-suite/src/compress/state.ts +486 -0
  312. package/external/pi-tools-suite/src/compress/ui.ts +308 -0
  313. package/external/pi-tools-suite/src/config.ts +176 -0
  314. package/external/pi-tools-suite/src/context-usage.ts +31 -0
  315. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +355 -0
  316. package/external/pi-tools-suite/src/index.ts +46 -0
  317. package/external/pi-tools-suite/src/lib/lsp.ts +62 -0
  318. package/external/pi-tools-suite/src/lib/project.ts +42 -0
  319. package/external/pi-tools-suite/src/lib/tool-args.ts +137 -0
  320. package/external/pi-tools-suite/src/lsp/_shared/config.ts +156 -0
  321. package/external/pi-tools-suite/src/lsp/_shared/glob.ts +60 -0
  322. package/external/pi-tools-suite/src/lsp/_shared/output.ts +102 -0
  323. package/external/pi-tools-suite/src/lsp/_shared/paths.ts +138 -0
  324. package/external/pi-tools-suite/src/lsp/_shared/runner.ts +64 -0
  325. package/external/pi-tools-suite/src/lsp/_shared/template.ts +23 -0
  326. package/external/pi-tools-suite/src/lsp/_shared/trust.ts +116 -0
  327. package/external/pi-tools-suite/src/lsp/_shared/types.ts +98 -0
  328. package/external/pi-tools-suite/src/lsp/async.ts +29 -0
  329. package/external/pi-tools-suite/src/lsp/child-process.ts +81 -0
  330. package/external/pi-tools-suite/src/lsp/client.ts +340 -0
  331. package/external/pi-tools-suite/src/lsp/constants.ts +9 -0
  332. package/external/pi-tools-suite/src/lsp/diagnostics-store.ts +64 -0
  333. package/external/pi-tools-suite/src/lsp/documents.ts +24 -0
  334. package/external/pi-tools-suite/src/lsp/index.ts +31 -0
  335. package/external/pi-tools-suite/src/lsp/lsp-utils.ts +37 -0
  336. package/external/pi-tools-suite/src/lsp/manager.ts +190 -0
  337. package/external/pi-tools-suite/src/lsp/mutation-events.ts +78 -0
  338. package/external/pi-tools-suite/src/lsp/renderer.ts +1 -0
  339. package/external/pi-tools-suite/src/lsp/tool-result.ts +6 -0
  340. package/external/pi-tools-suite/src/lsp/tsserver.ts +107 -0
  341. package/external/pi-tools-suite/src/lsp/types.ts +15 -0
  342. package/external/pi-tools-suite/src/model-tools/apply-patch.ts +590 -0
  343. package/external/pi-tools-suite/src/model-tools/index.ts +430 -0
  344. package/external/pi-tools-suite/src/model-tools/path-utils.ts +6 -0
  345. package/external/pi-tools-suite/src/model-tools/tool-args.ts +11 -0
  346. package/external/pi-tools-suite/src/prompt-commands/index.ts +349 -0
  347. package/external/pi-tools-suite/src/repo-discovery/index.ts +384 -0
  348. package/external/pi-tools-suite/src/repo-discovery/project.ts +7 -0
  349. package/external/pi-tools-suite/src/startup-section.ts +13 -0
  350. package/external/pi-tools-suite/src/terminal-bell/index.ts +309 -0
  351. package/external/pi-tools-suite/src/todo/index.ts +201 -0
  352. package/external/pi-tools-suite/src/todo/state/auto-clear.ts +13 -0
  353. package/external/pi-tools-suite/src/todo/state/invariants.ts +21 -0
  354. package/external/pi-tools-suite/src/todo/state/persistence.ts +94 -0
  355. package/external/pi-tools-suite/src/todo/state/replay.ts +38 -0
  356. package/external/pi-tools-suite/src/todo/state/selectors.ts +49 -0
  357. package/external/pi-tools-suite/src/todo/state/state-reducer.ts +362 -0
  358. package/external/pi-tools-suite/src/todo/state/state.ts +18 -0
  359. package/external/pi-tools-suite/src/todo/state/store.ts +52 -0
  360. package/external/pi-tools-suite/src/todo/state/task-graph.ts +57 -0
  361. package/external/pi-tools-suite/src/todo/todo.ts +487 -0
  362. package/external/pi-tools-suite/src/todo/tool/response-envelope.ts +143 -0
  363. package/external/pi-tools-suite/src/todo/tool/types.ts +188 -0
  364. package/external/pi-tools-suite/src/todo/view/format.ts +18 -0
  365. package/external/pi-tools-suite/src/todo/view/labels.ts +13 -0
  366. package/external/pi-tools-suite/src/tool-descriptions.ts +369 -0
  367. package/external/pi-tools-suite/src/usage/index.ts +152 -0
  368. package/external/pi-tools-suite/src/usage/lib/copilot.ts +535 -0
  369. package/external/pi-tools-suite/src/usage/lib/google.ts +478 -0
  370. package/external/pi-tools-suite/src/usage/lib/openai.ts +268 -0
  371. package/external/pi-tools-suite/src/usage/lib/types.ts +114 -0
  372. package/external/pi-tools-suite/src/usage/lib/utils.ts +134 -0
  373. package/external/pi-tools-suite/src/usage/lib/zhipu.ts +228 -0
  374. package/external/pi-tools-suite/src/web-search/index.ts +397 -0
  375. package/package.json +89 -0
  376. package/skills/context7/SKILL.md +69 -0
  377. package/skills/context7/scripts/context7.sh +73 -0
  378. package/skills/handoff/SKILL.md +15 -0
  379. package/skills/pdf/LICENSE.txt +30 -0
  380. package/skills/pdf/SKILL.md +314 -0
  381. package/skills/pdf/forms.md +294 -0
  382. package/skills/pdf/reference.md +612 -0
  383. package/skills/pdf/scripts/check_bounding_boxes.py +65 -0
  384. package/skills/pdf/scripts/check_fillable_fields.py +11 -0
  385. package/skills/pdf/scripts/convert_pdf_to_images.py +33 -0
  386. package/skills/pdf/scripts/create_validation_image.py +37 -0
  387. package/skills/pdf/scripts/extract_form_field_info.py +122 -0
  388. package/skills/pdf/scripts/extract_form_structure.py +115 -0
  389. package/skills/pdf/scripts/fill_fillable_fields.py +98 -0
  390. package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
  391. package/skills/playwright-cli/SKILL.md +388 -0
  392. package/skills/playwright-cli/references/element-attributes.md +23 -0
  393. package/skills/playwright-cli/references/playwright-tests.md +39 -0
  394. package/skills/playwright-cli/references/request-mocking.md +87 -0
  395. package/skills/playwright-cli/references/running-code.md +241 -0
  396. package/skills/playwright-cli/references/session-management.md +225 -0
  397. package/skills/playwright-cli/references/spec-driven-testing.md +305 -0
  398. package/skills/playwright-cli/references/storage-state.md +275 -0
  399. package/skills/playwright-cli/references/test-generation.md +134 -0
  400. package/skills/playwright-cli/references/tracing.md +139 -0
  401. package/skills/playwright-cli/references/video-recording.md +143 -0
  402. package/skills/simplify/SKILL.md +51 -0
  403. package/skills/skill-creator/LICENSE.txt +202 -0
  404. package/skills/skill-creator/SKILL.md +485 -0
  405. package/skills/skill-creator/agents/analyzer.md +274 -0
  406. package/skills/skill-creator/agents/comparator.md +202 -0
  407. package/skills/skill-creator/agents/grader.md +223 -0
  408. package/skills/skill-creator/assets/eval_review.html +146 -0
  409. package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  410. package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  411. package/skills/skill-creator/references/schemas.md +430 -0
  412. package/skills/skill-creator/scripts/__init__.py +0 -0
  413. package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  414. package/skills/skill-creator/scripts/generate_report.py +326 -0
  415. package/skills/skill-creator/scripts/improve_description.py +247 -0
  416. package/skills/skill-creator/scripts/package_skill.py +136 -0
  417. package/skills/skill-creator/scripts/quick_validate.py +103 -0
  418. package/skills/skill-creator/scripts/run_eval.py +310 -0
  419. package/skills/skill-creator/scripts/run_loop.py +328 -0
  420. package/skills/skill-creator/scripts/utils.py +47 -0
@@ -0,0 +1,302 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { calculateCost, createAssistantMessageEventStream, type AssistantMessage, type AssistantMessageEventStream, type Context, type SimpleStreamOptions, type ToolCall } from "@earendil-works/pi-ai";
3
+ import { ALL_ACCOUNTS_EXHAUSTED_MARKER, API_ID, ENDPOINT_PROD, PROVIDER_ID, STREAM_ENDPOINTS } from "./constants";
4
+ import { clampAccountIndex, decodeApiKey, getPiAuthPath, getStoredAccounts, readJsonFile } from "./auth-store";
5
+ import { getAntigravityHeaders, getModelHeaderStyle } from "./headers";
6
+ import { refreshNextFailoverCredential } from "./oauth";
7
+ import { buildPayload, extraHeadersForPayload, partThoughtSignature } from "./payload";
8
+ import { emitAntigravityStatus } from "./status";
9
+ import type { AntigravityChunk, AntigravityModel, PiAuthData } from "./types";
10
+
11
+ function baseUsage(): NonNullable<AssistantMessage["usage"]> {
12
+ return {
13
+ input: 0,
14
+ output: 0,
15
+ cacheRead: 0,
16
+ cacheWrite: 0,
17
+ totalTokens: 0,
18
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
19
+ };
20
+ }
21
+
22
+ function mapStopReason(reason?: string): "stop" | "length" | "error" {
23
+ switch (reason) {
24
+ case "STOP":
25
+ return "stop";
26
+ case "MAX_TOKENS":
27
+ return "length";
28
+ default:
29
+ return "error";
30
+ }
31
+ }
32
+
33
+ function isFailoverCandidate(status: number | undefined, body: string): boolean {
34
+ if (isLimitFailoverCandidate(status, body)) return true;
35
+ const lower = body.toLowerCase();
36
+ if (lower.includes("model_capacity_exhausted") || lower.includes("server busy") || lower.includes("overloaded") || lower.includes("capacity")) {
37
+ return true;
38
+ }
39
+ return [500, 502, 503, 504].includes(status ?? 0) && (lower.includes("unavailable") || lower.includes("try again") || lower.includes("busy"));
40
+ }
41
+
42
+ function isLimitFailoverCandidate(status: number | undefined, body: string): boolean {
43
+ if (status === 429) return true;
44
+ const lower = body.toLowerCase();
45
+ return lower.includes("quota_exhausted")
46
+ || lower.includes("quota exhausted")
47
+ || lower.includes("quota exceeded")
48
+ || lower.includes("resource_exhausted")
49
+ || lower.includes("resource exhausted")
50
+ || lower.includes("rate limit")
51
+ || lower.includes("rate_limit");
52
+ }
53
+
54
+ function shouldTryNextEndpoint(status: number | undefined, body: string): boolean {
55
+ if (isFailoverCandidate(status, body)) return false;
56
+ return [404, 500, 502, 503, 504].includes(status ?? 0);
57
+ }
58
+
59
+ async function sendAntigravityRequest(
60
+ payload: Record<string, unknown>,
61
+ apiKey: string,
62
+ requestHeaders: Record<string, string>,
63
+ model: AntigravityModel,
64
+ options?: SimpleStreamOptions,
65
+ ): Promise<{ response: Response; lastError: string }> {
66
+ let response: Response | undefined;
67
+ let lastError = "";
68
+ const headerStyle = getModelHeaderStyle(model);
69
+ const endpoints = headerStyle === "gemini-cli" ? [ENDPOINT_PROD] : STREAM_ENDPOINTS;
70
+ for (const endpoint of endpoints) {
71
+ response = await fetch(`${endpoint}/v1internal:streamGenerateContent?alt=sse`, {
72
+ method: "POST",
73
+ signal: options?.signal,
74
+ headers: {
75
+ Authorization: `Bearer ${apiKey}`,
76
+ "Content-Type": "application/json",
77
+ Accept: "text/event-stream",
78
+ ...getAntigravityHeaders(headerStyle),
79
+ ...requestHeaders,
80
+ ...(options?.headers ?? {}),
81
+ },
82
+ body: JSON.stringify(payload),
83
+ });
84
+ await options?.onResponse?.({ status: response.status, headers: Object.fromEntries(response.headers.entries()) }, model);
85
+ if (response.ok) break;
86
+ lastError = await response.text().catch(() => response?.statusText ?? "");
87
+ if (!shouldTryNextEndpoint(response.status, lastError)) break;
88
+ }
89
+ if (!response) throw new Error("Antigravity request failed: no response");
90
+ return { response, lastError };
91
+ }
92
+
93
+ function updateUsage(output: AssistantMessage, model: AntigravityModel, metadata: NonNullable<AntigravityChunk["response"]>["usageMetadata"]): void {
94
+ if (!metadata) return;
95
+ const cacheRead = metadata.cachedContentTokenCount ?? 0;
96
+ output.usage = {
97
+ input: Math.max(0, (metadata.promptTokenCount ?? 0) - cacheRead),
98
+ output: (metadata.candidatesTokenCount ?? 0) + (metadata.thoughtsTokenCount ?? 0),
99
+ cacheRead,
100
+ cacheWrite: 0,
101
+ totalTokens: metadata.totalTokenCount ?? 0,
102
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
103
+ };
104
+ calculateCost(model, output.usage);
105
+ }
106
+
107
+ export function streamAntigravity(model: AntigravityModel, context: Context, options?: SimpleStreamOptions): AssistantMessageEventStream {
108
+ const stream = createAssistantMessageEventStream();
109
+ (async () => {
110
+ const output: AssistantMessage = {
111
+ role: "assistant",
112
+ content: [],
113
+ api: API_ID,
114
+ provider: model.provider,
115
+ model: model.id,
116
+ usage: baseUsage(),
117
+ stopReason: "stop",
118
+ timestamp: Date.now(),
119
+ };
120
+
121
+ let openTextIndex: number | undefined;
122
+ let openThinkingIndex: number | undefined;
123
+ const closeOpenText = () => {
124
+ if (openTextIndex === undefined) return;
125
+ const block = output.content[openTextIndex];
126
+ if (block?.type === "text") stream.push({ type: "text_end", contentIndex: openTextIndex, content: block.text, partial: output });
127
+ openTextIndex = undefined;
128
+ };
129
+ const closeOpenThinking = () => {
130
+ if (openThinkingIndex === undefined) return;
131
+ const block = output.content[openThinkingIndex];
132
+ if (block?.type === "thinking") stream.push({ type: "thinking_end", contentIndex: openThinkingIndex, content: block.thinking, partial: output });
133
+ openThinkingIndex = undefined;
134
+ };
135
+
136
+ try {
137
+ const attemptedAccountIndices = new Set<number>();
138
+ const auth = await readJsonFile<PiAuthData>(getPiAuthPath(), {});
139
+ const storedCredential = auth[PROVIDER_ID];
140
+ const apiKey = storedCredential?.type === "oauth" && storedCredential.access && (storedCredential.expires ?? 0) > Date.now()
141
+ ? storedCredential.access
142
+ : options?.apiKey;
143
+ if (!apiKey) throw new Error("Not authenticated with Antigravity. Run /login antigravity first.");
144
+ const decodedApiKey = decodeApiKey(apiKey);
145
+ const authAccounts = getStoredAccounts(auth[PROVIDER_ID]);
146
+ if (authAccounts.length > 0) attemptedAccountIndices.add(clampAccountIndex(auth[PROVIDER_ID]?.activeIndex, authAccounts.length));
147
+
148
+ let payload = buildPayload(model, context, options);
149
+ if (decodedApiKey.projectId) payload.project = decodedApiKey.projectId;
150
+ const replacedPayload = await options?.onPayload?.(payload, model);
151
+ if (replacedPayload !== undefined) payload = replacedPayload as Record<string, unknown>;
152
+
153
+ stream.push({ type: "start", partial: output });
154
+ const requestHeaders = extraHeadersForPayload(payload);
155
+ let requestApiKey = decodedApiKey.access;
156
+ let response: Response | undefined;
157
+ let lastError = "";
158
+ let allAccountsExhausted = false;
159
+ while (true) {
160
+ const result = await sendAntigravityRequest(payload, requestApiKey, requestHeaders, model, options);
161
+ response = result.response;
162
+ lastError = result.lastError;
163
+ if (response.ok) break;
164
+ if (!isFailoverCandidate(response.status, lastError) || options?.signal?.aborted) break;
165
+ const nextCredential = await refreshNextFailoverCredential(attemptedAccountIndices);
166
+ if (!nextCredential) {
167
+ allAccountsExhausted = isLimitFailoverCandidate(response.status, lastError);
168
+ break;
169
+ }
170
+ const decodedNext = decodeApiKey(nextCredential.apiKey);
171
+ requestApiKey = decodedNext.access;
172
+ payload = { ...payload, project: decodedNext.projectId || nextCredential.projectId };
173
+ emitAntigravityStatus({
174
+ kind: "switch",
175
+ email: nextCredential.email,
176
+ accountIndex: nextCredential.accountIndex,
177
+ accountCount: nextCredential.accountCount,
178
+ projectId: decodedNext.projectId || nextCredential.projectId,
179
+ status: response.status,
180
+ });
181
+ }
182
+ if (!response?.ok) {
183
+ const status = response?.status ?? "no response";
184
+ if (allAccountsExhausted) {
185
+ throw new Error(`${ALL_ACCOUNTS_EXHAUSTED_MARKER} model=${model.id} status=${status}: all configured Antigravity accounts are exhausted for this model: ${lastError}`);
186
+ }
187
+ throw new Error(`Antigravity request failed (${status}): ${lastError}`);
188
+ }
189
+ if (!response.body) throw new Error("Antigravity response did not include a stream body");
190
+
191
+ for await (const chunk of readSse(response.body, options?.signal)) {
192
+ if (chunk.error) throw new Error(chunk.error.message ?? JSON.stringify(chunk.error));
193
+ const inner = chunk.response;
194
+ if (!inner) continue;
195
+ output.responseId ||= inner.responseId;
196
+ output.responseModel ||= inner.modelVersion;
197
+ updateUsage(output, model, inner.usageMetadata);
198
+ const candidate = inner.candidates?.[0];
199
+ const parts = candidate?.content?.parts ?? [];
200
+ for (const part of parts) {
201
+ const thoughtSignature = partThoughtSignature(part);
202
+ if (typeof part.text === "string") {
203
+ if (part.thought === true) {
204
+ closeOpenText();
205
+ if (openThinkingIndex === undefined) {
206
+ output.content.push({ type: "thinking", thinking: "", thinkingSignature: thoughtSignature });
207
+ openThinkingIndex = output.content.length - 1;
208
+ stream.push({ type: "thinking_start", contentIndex: openThinkingIndex, partial: output });
209
+ }
210
+ const block = output.content[openThinkingIndex];
211
+ if (block?.type === "thinking") {
212
+ block.thinking += part.text;
213
+ block.thinkingSignature ||= thoughtSignature;
214
+ stream.push({ type: "thinking_delta", contentIndex: openThinkingIndex, delta: part.text, partial: output });
215
+ }
216
+ } else {
217
+ closeOpenThinking();
218
+ if (openTextIndex === undefined) {
219
+ output.content.push({ type: "text", text: "", textSignature: thoughtSignature });
220
+ openTextIndex = output.content.length - 1;
221
+ stream.push({ type: "text_start", contentIndex: openTextIndex, partial: output });
222
+ }
223
+ const block = output.content[openTextIndex];
224
+ if (block?.type === "text") {
225
+ block.text += part.text;
226
+ block.textSignature ||= thoughtSignature;
227
+ stream.push({ type: "text_delta", contentIndex: openTextIndex, delta: part.text, partial: output });
228
+ }
229
+ }
230
+ }
231
+ if (part.functionCall) {
232
+ closeOpenText();
233
+ closeOpenThinking();
234
+ const toolCall: ToolCall = {
235
+ type: "toolCall",
236
+ id: part.functionCall.id || `${part.functionCall.name ?? "tool"}_${randomUUID()}`,
237
+ name: part.functionCall.name ?? "",
238
+ arguments: part.functionCall.args ?? {},
239
+ ...(thoughtSignature ? { thoughtSignature } : {}),
240
+ };
241
+ output.content.push(toolCall);
242
+ const contentIndex = output.content.length - 1;
243
+ stream.push({ type: "toolcall_start", contentIndex, partial: output });
244
+ stream.push({ type: "toolcall_delta", contentIndex, delta: JSON.stringify(toolCall.arguments), partial: output });
245
+ stream.push({ type: "toolcall_end", contentIndex, toolCall, partial: output });
246
+ }
247
+ }
248
+ if (candidate?.finishReason) output.stopReason = mapStopReason(candidate.finishReason);
249
+ if (output.content.some((block) => block.type === "toolCall")) output.stopReason = "toolUse";
250
+ }
251
+ closeOpenText();
252
+ closeOpenThinking();
253
+ if (options?.signal?.aborted) throw new Error("Request was aborted");
254
+ if (output.stopReason === "error" || output.stopReason === "aborted") throw new Error("Antigravity stopped with an error finish reason");
255
+ stream.push({ type: "done", reason: output.stopReason, message: output });
256
+ stream.end();
257
+ } catch (error) {
258
+ closeOpenText();
259
+ closeOpenThinking();
260
+ output.stopReason = options?.signal?.aborted ? "aborted" : "error";
261
+ output.errorMessage = error instanceof Error ? error.message : String(error);
262
+ stream.push({ type: "error", reason: output.stopReason, error: output });
263
+ stream.end();
264
+ }
265
+ })();
266
+ return stream;
267
+ }
268
+
269
+ async function* readSse(body: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<AntigravityChunk> {
270
+ const reader = body.getReader();
271
+ const decoder = new TextDecoder();
272
+ let buffer = "";
273
+ try {
274
+ while (true) {
275
+ if (signal?.aborted) throw new Error("Request was aborted");
276
+ const { value, done } = await reader.read();
277
+ if (done) break;
278
+ buffer += decoder.decode(value, { stream: true });
279
+ let boundary = buffer.match(/\r?\n\r?\n/);
280
+ while (boundary?.index !== undefined) {
281
+ const raw = buffer.slice(0, boundary.index);
282
+ buffer = buffer.slice(boundary.index + boundary[0].length);
283
+ const data = raw
284
+ .split(/\r?\n/)
285
+ .filter((line) => line.startsWith("data:"))
286
+ .map((line) => line.slice(5).trim())
287
+ .join("\n");
288
+ if (!data || data === "[DONE]") continue;
289
+ yield JSON.parse(data) as AntigravityChunk;
290
+ boundary = buffer.match(/\r?\n\r?\n/);
291
+ }
292
+ }
293
+ buffer += decoder.decode();
294
+ for (const line of buffer.split(/\r?\n/)) {
295
+ if (!line.startsWith("data:")) continue;
296
+ const data = line.slice(5).trim();
297
+ if (data && data !== "[DONE]") yield JSON.parse(data) as AntigravityChunk;
298
+ }
299
+ } finally {
300
+ reader.releaseLock();
301
+ }
302
+ }
@@ -0,0 +1,113 @@
1
+ import type { Model, OAuthCredentials, OAuthLoginCallbacks } from "@earendil-works/pi-ai";
2
+
3
+ export type HeaderStyle = "antigravity" | "gemini-cli";
4
+ export type AntigravityModel = Model<"antigravity-unified-gateway"> & { antigravityProjectId?: string; antigravityHeaderStyle?: HeaderStyle };
5
+
6
+ export type AntigravityPart = {
7
+ text?: string;
8
+ thought?: boolean;
9
+ thoughtSignature?: string;
10
+ thought_signature?: string;
11
+ inlineData?: { mimeType: string; data: string };
12
+ functionCall?: { id?: string; name?: string; args?: Record<string, unknown> };
13
+ functionResponse?: { id?: string; name?: string; response?: Record<string, unknown> };
14
+ };
15
+
16
+ export type AntigravityContent = {
17
+ role: "user" | "model";
18
+ parts: AntigravityPart[];
19
+ };
20
+
21
+ export type AntigravityChunk = {
22
+ response?: {
23
+ candidates?: Array<{
24
+ content?: { role?: string; parts?: AntigravityPart[] };
25
+ finishReason?: string;
26
+ }>;
27
+ usageMetadata?: {
28
+ promptTokenCount?: number;
29
+ candidatesTokenCount?: number;
30
+ cachedContentTokenCount?: number;
31
+ thoughtsTokenCount?: number;
32
+ totalTokenCount?: number;
33
+ };
34
+ modelVersion?: string;
35
+ responseId?: string;
36
+ };
37
+ error?: { code?: number; message?: string; status?: string };
38
+ };
39
+
40
+ export type OpencodeAntigravityAccount = {
41
+ email?: string;
42
+ refreshToken?: string;
43
+ projectId?: string;
44
+ managedProjectId?: string;
45
+ enabled?: boolean;
46
+ };
47
+
48
+ export type OpencodeAntigravityStorage = {
49
+ version?: number;
50
+ accounts?: OpencodeAntigravityAccount[];
51
+ activeIndex?: number;
52
+ };
53
+
54
+ export type PiAuthCredential = {
55
+ type?: string;
56
+ refresh?: string;
57
+ access?: string;
58
+ expires?: number;
59
+ email?: string;
60
+ accounts?: OpencodeAntigravityAccount[];
61
+ activeIndex?: number;
62
+ [key: string]: unknown;
63
+ };
64
+
65
+ export type PiAuthData = Record<string, PiAuthCredential>;
66
+
67
+ export type RefreshedAntigravityAccount = {
68
+ account: OpencodeAntigravityAccount;
69
+ credentials: OAuthCredentials & PiAuthCredential;
70
+ projectId: string;
71
+ };
72
+
73
+ export type AntigravityFailoverCredential = {
74
+ apiKey: string;
75
+ projectId: string;
76
+ email?: string;
77
+ accountIndex: number;
78
+ accountCount: number;
79
+ };
80
+
81
+ export type AntigravityStatusDetails = {
82
+ kind: "status" | "switch";
83
+ email?: string;
84
+ accountIndex?: number;
85
+ accountCount?: number;
86
+ projectId?: string;
87
+ status?: number;
88
+ expires?: number;
89
+ };
90
+
91
+ export type AntigravityLoginCallbacks = Pick<OAuthLoginCallbacks, "onAuth" | "onPrompt">;
92
+
93
+ export type OpencodeAntigravityImportResult = {
94
+ imported: boolean;
95
+ reason?: string;
96
+ sourcePath: string;
97
+ authPath: string;
98
+ email?: string;
99
+ accountIndex?: number;
100
+ accountCount?: number;
101
+ overwroteExisting?: boolean;
102
+ };
103
+
104
+ export type AntigravityAddAccountResult = {
105
+ added: boolean;
106
+ updatedExisting?: boolean;
107
+ activated: boolean;
108
+ authPath: string;
109
+ email?: string;
110
+ accountIndex: number;
111
+ accountCount: number;
112
+ projectId?: string;
113
+ };
@@ -0,0 +1,6 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { registerAstGrepTool } from "./tool";
3
+
4
+ export default function astGrepExtension(pi: ExtensionAPI) {
5
+ registerAstGrepTool(pi);
6
+ }
@@ -0,0 +1,70 @@
1
+ import { Text } from "@earendil-works/pi-tui";
2
+ import type { AstGrepDetails, AstGrepParamsType } from "./types";
3
+ import { shellQuoteForDisplay } from "./utils";
4
+
5
+ type RenderTheme = {
6
+ fg(name: string, text: string): string;
7
+ bold(text: string): string;
8
+ };
9
+
10
+ type AstGrepRenderResult = {
11
+ content: unknown[];
12
+ details?: unknown;
13
+ };
14
+
15
+ type RenderResultOptions = {
16
+ expanded?: boolean;
17
+ isPartial?: boolean;
18
+ };
19
+
20
+ function renderAstGrepCallWithName(args: Partial<AstGrepParamsType>, theme: RenderTheme, toolName: string) {
21
+ let text = theme.fg("toolTitle", theme.bold(`${toolName} `));
22
+ text += theme.fg("accent", args.command === "scan" ? "scan" : JSON.stringify(args.pattern ?? ""));
23
+ if (args.lang) text += theme.fg("muted", ` --lang ${args.lang}`);
24
+ if (args.updateAll) text += theme.fg("warning", " update-all");
25
+ else if (args.rewrite) text += theme.fg("warning", " rewrite-preview");
26
+ const paths = Array.isArray(args.paths) ? args.paths : [];
27
+ if (paths.length > 0) text += theme.fg("dim", ` in ${paths.join(", ")}`);
28
+ return new Text(text, 0, 0);
29
+ }
30
+
31
+ export function renderAstGrepCall(args: Partial<AstGrepParamsType>, theme: RenderTheme) {
32
+ return renderAstGrepCallWithName(args, theme, "ast_grep");
33
+ }
34
+
35
+ export function renderAstApplyCall(args: Partial<AstGrepParamsType>, theme: RenderTheme) {
36
+ return renderAstGrepCallWithName({ ...args, updateAll: true }, theme, "ast_apply");
37
+ }
38
+
39
+ export function renderAstGrepResult(
40
+ result: AstGrepRenderResult,
41
+ { expanded, isPartial }: RenderResultOptions,
42
+ theme: RenderTheme,
43
+ ) {
44
+ const details = result.details as AstGrepDetails | undefined;
45
+ if (isPartial) return new Text(theme.fg("warning", "Searching AST..."), 0, 0);
46
+ if (!details) return new Text(theme.fg("dim", "ast-grep finished"), 0, 0);
47
+
48
+ let text = details.matchCount === 0
49
+ ? theme.fg("dim", "No matches")
50
+ : theme.fg("success", `${details.matchCount} match${details.matchCount === 1 ? "" : "es"}`);
51
+ if (details.mutated) text += theme.fg("warning", " (applied)");
52
+ if (details.changedFiles?.length) {
53
+ text += theme.fg("dim", ` ${details.changedFiles.length} file${details.changedFiles.length === 1 ? "" : "s"}`);
54
+ }
55
+ if (details.rewritePreview) text += theme.fg("warning", " (rewrite preview)");
56
+ if (details.truncation?.truncated) text += theme.fg("warning", " (truncated)");
57
+ if (details.fullOutputPath) text += theme.fg("dim", ` full: ${details.fullOutputPath}`);
58
+
59
+ if (expanded) {
60
+ text += `\n${theme.fg("dim", shellQuoteForDisplay(details.command))}`;
61
+ const content = result.content[0] as { type?: unknown; text?: unknown } | undefined;
62
+ if (content?.type === "text" && typeof content.text === "string" && content.text.trim()) {
63
+ for (const line of content.text.split("\n").slice(0, 30)) {
64
+ text += `\n${theme.fg("dim", line)}`;
65
+ }
66
+ }
67
+ }
68
+
69
+ return new Text(text, 0, 0);
70
+ }
@@ -0,0 +1,109 @@
1
+ import { StringEnum } from "@earendil-works/pi-ai";
2
+ import { Type } from "typebox";
3
+
4
+ const AstGrepParamProperties = {
5
+ command: Type.Optional(
6
+ StringEnum(["run", "scan"] as const, {
7
+ description: "ast-grep subcommand. run searches/rewrites by pattern; scan uses sgconfig/rule YAML. Default: run.",
8
+ }),
9
+ ),
10
+ pattern: Type.Optional(
11
+ Type.String({
12
+ description: "AST pattern to match for command=run, e.g. 'console.log($A)'",
13
+ }),
14
+ ),
15
+ paths: Type.Optional(
16
+ Type.Array(Type.String(), {
17
+ description: "Files/directories to search. Defaults to ['.'].",
18
+ }),
19
+ ),
20
+ lang: Type.Optional(
21
+ Type.String({
22
+ description: "Language of the pattern, e.g. ts, tsx, js, python, rust, go.",
23
+ }),
24
+ ),
25
+ rewrite: Type.Optional(
26
+ Type.String({
27
+ description:
28
+ "Optional rewrite template/fix. ast_grep previews rewrites only; use ast_apply to apply changes.",
29
+ }),
30
+ ),
31
+ selector: Type.Optional(
32
+ Type.String({
33
+ description: "Optional AST node kind selector to extract the sub-node of the pattern to match.",
34
+ }),
35
+ ),
36
+ strictness: Type.Optional(
37
+ StringEnum(["cst", "smart", "ast", "relaxed", "signature", "template"] as const, {
38
+ description: "Pattern strictness. ast-grep default is smart.",
39
+ }),
40
+ ),
41
+ debugQuery: Type.Optional(
42
+ StringEnum(["pattern", "ast", "cst", "sexp"] as const, {
43
+ description: "Print query pattern's tree-sitter AST. Requires lang be set explicitly.",
44
+ }),
45
+ ),
46
+ config: Type.Optional(Type.String({ description: "Path to ast-grep root config, default is sgconfig.yml." })),
47
+ globs: Type.Optional(
48
+ Type.Array(Type.String(), {
49
+ description: "Include/exclude globs. Repeatable ast-grep --globs values; use !pattern to exclude.",
50
+ }),
51
+ ),
52
+ threads: Type.Optional(Type.Number({ description: "Approximate number of threads to use. 0 lets ast-grep choose." })),
53
+ inspect: Type.Optional(
54
+ StringEnum(["nothing", "summary", "entity"] as const, {
55
+ description: "Inspect information for file/rule discovery and scanning.",
56
+ }),
57
+ ),
58
+ maxResults: Type.Optional(Type.Number({ description: "For command=scan, show at most N results and stop once the limit is reached." })),
59
+ context: Type.Optional(Type.Number({ description: "Show N context lines around each match." })),
60
+ before: Type.Optional(Type.Number({ description: "Show N lines before each match." })),
61
+ after: Type.Optional(Type.Number({ description: "Show N lines after each match." })),
62
+ filesWithMatches: Type.Optional(
63
+ Type.Boolean({ description: "Only print paths with at least one match. Conflicts with rewrite and json." }),
64
+ ),
65
+ json: Type.Optional(Type.Boolean({ description: "Return ast-grep matches as JSON." })),
66
+ jsonStyle: Type.Optional(
67
+ StringEnum(["pretty", "stream", "compact"] as const, {
68
+ description: "JSON output style. Default: pretty.",
69
+ }),
70
+ ),
71
+ follow: Type.Optional(Type.Boolean({ description: "Follow symbolic links while traversing directories." })),
72
+ noIgnore: Type.Optional(
73
+ Type.Array(StringEnum(["hidden", "dot", "exclude", "global", "parent", "vcs"] as const), {
74
+ description: "Ignore-file suppression modes passed as repeated --no-ignore values.",
75
+ }),
76
+ ),
77
+ rule: Type.Optional(Type.String({ description: "For command=scan, scan with a single rule file." })),
78
+ inlineRules: Type.Optional(
79
+ Type.String({ description: "For command=scan, rule YAML text. Separate multiple rules with --- . Conflicts with rule." }),
80
+ ),
81
+ format: Type.Optional(
82
+ StringEnum(["github", "sarif"] as const, {
83
+ description: "For command=scan, output warning/error messages in a machine-readable format.",
84
+ }),
85
+ ),
86
+ reportStyle: Type.Optional(
87
+ StringEnum(["rich", "medium", "short"] as const, {
88
+ description: "For command=scan, diagnostic report style. Default: rich.",
89
+ }),
90
+ ),
91
+ includeMetadata: Type.Optional(Type.Boolean({ description: "For command=scan with json=true, include rule metadata." })),
92
+ filter: Type.Optional(Type.String({ description: "For command=scan, regex for rule ids to run. Conflicts with rule." })),
93
+ error: Type.Optional(Type.Array(Type.String(), { description: "For command=scan, set specified rule ids to error. Use [''] for bare --error." })),
94
+ warning: Type.Optional(Type.Array(Type.String(), { description: "For command=scan, set specified rule ids to warning. Use [''] for bare --warning." })),
95
+ info: Type.Optional(Type.Array(Type.String(), { description: "For command=scan, set specified rule ids to info. Use [''] for bare --info." })),
96
+ hint: Type.Optional(Type.Array(Type.String(), { description: "For command=scan, set specified rule ids to hint. Use [''] for bare --hint." })),
97
+ off: Type.Optional(Type.Array(Type.String(), { description: "For command=scan, turn off specified rule ids. Use [''] for bare --off." })),
98
+ };
99
+
100
+ export const AstGrepParams = Type.Object(AstGrepParamProperties);
101
+
102
+ export const AstApplyParams = Type.Object({
103
+ ...AstGrepParamProperties,
104
+ rewrite: Type.Optional(
105
+ Type.String({
106
+ description: "Rewrite template/fix for command=run. ast_apply applies changes with ast-grep --update-all.",
107
+ }),
108
+ ),
109
+ });