@openeryc/pi-coding-agent 0.75.25 → 0.75.27

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 (314) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cli/config-selector.d.ts +1 -13
  3. package/dist/cli/config-selector.d.ts.map +1 -1
  4. package/dist/cli/config-selector.js +4 -29
  5. package/dist/cli/config-selector.js.map +1 -1
  6. package/dist/cli/list-models.d.ts.map +1 -1
  7. package/dist/cli/list-models.js +1 -1
  8. package/dist/cli/list-models.js.map +1 -1
  9. package/dist/core/agent-session.d.ts +1 -0
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +20 -0
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  14. package/dist/core/export-html/tool-renderer.js.map +1 -1
  15. package/dist/core/extensions/loader.d.ts.map +1 -1
  16. package/dist/core/extensions/loader.js +1 -1
  17. package/dist/core/extensions/loader.js.map +1 -1
  18. package/dist/core/extensions/runner.d.ts +1 -1
  19. package/dist/core/extensions/runner.d.ts.map +1 -1
  20. package/dist/core/extensions/runner.js +1 -1
  21. package/dist/core/extensions/runner.js.map +1 -1
  22. package/dist/core/extensions/types.d.ts +1 -1
  23. package/dist/core/extensions/types.d.ts.map +1 -1
  24. package/dist/core/extensions/types.js.map +1 -1
  25. package/dist/core/keybindings.d.ts +7 -135
  26. package/dist/core/keybindings.d.ts.map +1 -1
  27. package/dist/core/keybindings.js +1 -1
  28. package/dist/core/keybindings.js.map +1 -1
  29. package/dist/core/mcp/client.d.ts +38 -0
  30. package/dist/core/mcp/client.d.ts.map +1 -0
  31. package/dist/core/mcp/client.js +88 -0
  32. package/dist/core/mcp/client.js.map +1 -0
  33. package/dist/core/mcp/index.d.ts +3 -0
  34. package/dist/core/mcp/index.d.ts.map +1 -0
  35. package/dist/core/mcp/index.js +3 -0
  36. package/dist/core/mcp/index.js.map +1 -0
  37. package/dist/core/mcp/manager.d.ts +11 -0
  38. package/dist/core/mcp/manager.d.ts.map +1 -0
  39. package/dist/core/mcp/manager.js +99 -0
  40. package/dist/core/mcp/manager.js.map +1 -0
  41. package/dist/core/settings-manager.d.ts +10 -0
  42. package/dist/core/settings-manager.d.ts.map +1 -1
  43. package/dist/core/settings-manager.js +3 -0
  44. package/dist/core/settings-manager.js.map +1 -1
  45. package/dist/core/tools/bash.d.ts.map +1 -1
  46. package/dist/core/tools/bash.js +1 -1
  47. package/dist/core/tools/bash.js.map +1 -1
  48. package/dist/core/tools/edit.d.ts +1 -1
  49. package/dist/core/tools/edit.d.ts.map +1 -1
  50. package/dist/core/tools/edit.js +1 -1
  51. package/dist/core/tools/edit.js.map +1 -1
  52. package/dist/core/tools/find.d.ts.map +1 -1
  53. package/dist/core/tools/find.js +1 -1
  54. package/dist/core/tools/find.js.map +1 -1
  55. package/dist/core/tools/grep.d.ts.map +1 -1
  56. package/dist/core/tools/grep.js +1 -1
  57. package/dist/core/tools/grep.js.map +1 -1
  58. package/dist/core/tools/index.d.ts +3 -1
  59. package/dist/core/tools/index.d.ts.map +1 -1
  60. package/dist/core/tools/index.js +27 -1
  61. package/dist/core/tools/index.js.map +1 -1
  62. package/dist/core/tools/ls.d.ts.map +1 -1
  63. package/dist/core/tools/ls.js +1 -1
  64. package/dist/core/tools/ls.js.map +1 -1
  65. package/dist/core/tools/read.d.ts.map +1 -1
  66. package/dist/core/tools/read.js +1 -1
  67. package/dist/core/tools/read.js.map +1 -1
  68. package/dist/core/tools/render-utils.d.ts.map +1 -1
  69. package/dist/core/tools/render-utils.js +1 -1
  70. package/dist/core/tools/render-utils.js.map +1 -1
  71. package/dist/core/tools/web-fetch.d.ts +15 -0
  72. package/dist/core/tools/web-fetch.d.ts.map +1 -0
  73. package/dist/core/tools/web-fetch.js +52 -0
  74. package/dist/core/tools/web-fetch.js.map +1 -0
  75. package/dist/core/tools/web-search.d.ts +18 -0
  76. package/dist/core/tools/web-search.d.ts.map +1 -0
  77. package/dist/core/tools/web-search.js +83 -0
  78. package/dist/core/tools/web-search.js.map +1 -0
  79. package/dist/core/tools/write.d.ts.map +1 -1
  80. package/dist/core/tools/write.js +1 -1
  81. package/dist/core/tools/write.js.map +1 -1
  82. package/dist/core/tui-stubs.d.ts +95 -0
  83. package/dist/core/tui-stubs.d.ts.map +1 -0
  84. package/dist/core/tui-stubs.js +90 -0
  85. package/dist/core/tui-stubs.js.map +1 -0
  86. package/dist/index.d.ts +5 -3
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +7 -5
  89. package/dist/index.js.map +1 -1
  90. package/dist/main.d.ts.map +1 -1
  91. package/dist/main.js +14 -106
  92. package/dist/main.js.map +1 -1
  93. package/dist/modes/index.d.ts +0 -4
  94. package/dist/modes/index.d.ts.map +1 -1
  95. package/dist/modes/index.js +0 -4
  96. package/dist/modes/index.js.map +1 -1
  97. package/dist/modes/interactive/components/diff.d.ts +1 -8
  98. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  99. package/dist/modes/interactive/components/diff.js +2 -131
  100. package/dist/modes/interactive/components/diff.js.map +1 -1
  101. package/dist/modes/interactive/components/keybinding-hints.d.ts +2 -12
  102. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  103. package/dist/modes/interactive/components/keybinding-hints.js +4 -33
  104. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  105. package/dist/modes/interactive/components/visual-truncate.d.ts +1 -19
  106. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  107. package/dist/modes/interactive/components/visual-truncate.js +4 -31
  108. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  109. package/dist/modes/interactive/theme/theme.d.ts +27 -89
  110. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  111. package/dist/modes/interactive/theme/theme.js +44 -992
  112. package/dist/modes/interactive/theme/theme.js.map +1 -1
  113. package/dist/package-manager-cli.d.ts.map +1 -1
  114. package/dist/package-manager-cli.js +1 -1
  115. package/dist/package-manager-cli.js.map +1 -1
  116. package/npm-shrinkwrap.json +240 -246
  117. package/package.json +6 -7
  118. package/dist/cli/session-picker.d.ts +0 -9
  119. package/dist/cli/session-picker.d.ts.map +0 -1
  120. package/dist/cli/session-picker.js +0 -35
  121. package/dist/cli/session-picker.js.map +0 -1
  122. package/dist/modes/interactive/assets/clankolas.png +0 -0
  123. package/dist/modes/interactive/components/armin.d.ts +0 -34
  124. package/dist/modes/interactive/components/armin.d.ts.map +0 -1
  125. package/dist/modes/interactive/components/armin.js +0 -333
  126. package/dist/modes/interactive/components/armin.js.map +0 -1
  127. package/dist/modes/interactive/components/assistant-message.d.ts +0 -20
  128. package/dist/modes/interactive/components/assistant-message.d.ts.map +0 -1
  129. package/dist/modes/interactive/components/assistant-message.js +0 -121
  130. package/dist/modes/interactive/components/assistant-message.js.map +0 -1
  131. package/dist/modes/interactive/components/bash-execution.d.ts +0 -34
  132. package/dist/modes/interactive/components/bash-execution.d.ts.map +0 -1
  133. package/dist/modes/interactive/components/bash-execution.js +0 -175
  134. package/dist/modes/interactive/components/bash-execution.js.map +0 -1
  135. package/dist/modes/interactive/components/bordered-loader.d.ts +0 -16
  136. package/dist/modes/interactive/components/bordered-loader.d.ts.map +0 -1
  137. package/dist/modes/interactive/components/bordered-loader.js +0 -54
  138. package/dist/modes/interactive/components/bordered-loader.js.map +0 -1
  139. package/dist/modes/interactive/components/branch-summary-message.d.ts +0 -16
  140. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +0 -1
  141. package/dist/modes/interactive/components/branch-summary-message.js +0 -44
  142. package/dist/modes/interactive/components/branch-summary-message.js.map +0 -1
  143. package/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -16
  144. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +0 -1
  145. package/dist/modes/interactive/components/compaction-summary-message.js +0 -45
  146. package/dist/modes/interactive/components/compaction-summary-message.js.map +0 -1
  147. package/dist/modes/interactive/components/config-selector.d.ts +0 -71
  148. package/dist/modes/interactive/components/config-selector.d.ts.map +0 -1
  149. package/dist/modes/interactive/components/config-selector.js +0 -506
  150. package/dist/modes/interactive/components/config-selector.js.map +0 -1
  151. package/dist/modes/interactive/components/countdown-timer.d.ts +0 -14
  152. package/dist/modes/interactive/components/countdown-timer.d.ts.map +0 -1
  153. package/dist/modes/interactive/components/countdown-timer.js +0 -33
  154. package/dist/modes/interactive/components/countdown-timer.js.map +0 -1
  155. package/dist/modes/interactive/components/custom-editor.d.ts +0 -21
  156. package/dist/modes/interactive/components/custom-editor.d.ts.map +0 -1
  157. package/dist/modes/interactive/components/custom-editor.js +0 -70
  158. package/dist/modes/interactive/components/custom-editor.js.map +0 -1
  159. package/dist/modes/interactive/components/custom-message.d.ts +0 -20
  160. package/dist/modes/interactive/components/custom-message.d.ts.map +0 -1
  161. package/dist/modes/interactive/components/custom-message.js +0 -79
  162. package/dist/modes/interactive/components/custom-message.js.map +0 -1
  163. package/dist/modes/interactive/components/daxnuts.d.ts +0 -23
  164. package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
  165. package/dist/modes/interactive/components/daxnuts.js +0 -140
  166. package/dist/modes/interactive/components/daxnuts.js.map +0 -1
  167. package/dist/modes/interactive/components/dynamic-border.d.ts +0 -15
  168. package/dist/modes/interactive/components/dynamic-border.d.ts.map +0 -1
  169. package/dist/modes/interactive/components/dynamic-border.js +0 -21
  170. package/dist/modes/interactive/components/dynamic-border.js.map +0 -1
  171. package/dist/modes/interactive/components/earendil-announcement.d.ts +0 -5
  172. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +0 -1
  173. package/dist/modes/interactive/components/earendil-announcement.js +0 -40
  174. package/dist/modes/interactive/components/earendil-announcement.js.map +0 -1
  175. package/dist/modes/interactive/components/extension-editor.d.ts +0 -20
  176. package/dist/modes/interactive/components/extension-editor.d.ts.map +0 -1
  177. package/dist/modes/interactive/components/extension-editor.js +0 -119
  178. package/dist/modes/interactive/components/extension-editor.js.map +0 -1
  179. package/dist/modes/interactive/components/extension-input.d.ts +0 -23
  180. package/dist/modes/interactive/components/extension-input.d.ts.map +0 -1
  181. package/dist/modes/interactive/components/extension-input.js +0 -61
  182. package/dist/modes/interactive/components/extension-input.js.map +0 -1
  183. package/dist/modes/interactive/components/extension-selector.d.ts +0 -26
  184. package/dist/modes/interactive/components/extension-selector.d.ts.map +0 -1
  185. package/dist/modes/interactive/components/extension-selector.js +0 -83
  186. package/dist/modes/interactive/components/extension-selector.js.map +0 -1
  187. package/dist/modes/interactive/components/footer.d.ts +0 -27
  188. package/dist/modes/interactive/components/footer.d.ts.map +0 -1
  189. package/dist/modes/interactive/components/footer.js +0 -201
  190. package/dist/modes/interactive/components/footer.js.map +0 -1
  191. package/dist/modes/interactive/components/index.d.ts +0 -32
  192. package/dist/modes/interactive/components/index.d.ts.map +0 -1
  193. package/dist/modes/interactive/components/index.js +0 -33
  194. package/dist/modes/interactive/components/index.js.map +0 -1
  195. package/dist/modes/interactive/components/login-dialog.d.ts +0 -46
  196. package/dist/modes/interactive/components/login-dialog.d.ts.map +0 -1
  197. package/dist/modes/interactive/components/login-dialog.js +0 -160
  198. package/dist/modes/interactive/components/login-dialog.js.map +0 -1
  199. package/dist/modes/interactive/components/model-selector.d.ts +0 -47
  200. package/dist/modes/interactive/components/model-selector.d.ts.map +0 -1
  201. package/dist/modes/interactive/components/model-selector.js +0 -278
  202. package/dist/modes/interactive/components/model-selector.js.map +0 -1
  203. package/dist/modes/interactive/components/oauth-selector.d.ts +0 -31
  204. package/dist/modes/interactive/components/oauth-selector.d.ts.map +0 -1
  205. package/dist/modes/interactive/components/oauth-selector.js +0 -165
  206. package/dist/modes/interactive/components/oauth-selector.js.map +0 -1
  207. package/dist/modes/interactive/components/scoped-models-selector.d.ts +0 -42
  208. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +0 -1
  209. package/dist/modes/interactive/components/scoped-models-selector.js +0 -290
  210. package/dist/modes/interactive/components/scoped-models-selector.js.map +0 -1
  211. package/dist/modes/interactive/components/session-selector-search.d.ts +0 -23
  212. package/dist/modes/interactive/components/session-selector-search.d.ts.map +0 -1
  213. package/dist/modes/interactive/components/session-selector-search.js +0 -155
  214. package/dist/modes/interactive/components/session-selector-search.js.map +0 -1
  215. package/dist/modes/interactive/components/session-selector.d.ts +0 -96
  216. package/dist/modes/interactive/components/session-selector.d.ts.map +0 -1
  217. package/dist/modes/interactive/components/session-selector.js +0 -861
  218. package/dist/modes/interactive/components/session-selector.js.map +0 -1
  219. package/dist/modes/interactive/components/settings-selector.d.ts +0 -69
  220. package/dist/modes/interactive/components/settings-selector.d.ts.map +0 -1
  221. package/dist/modes/interactive/components/settings-selector.js +0 -390
  222. package/dist/modes/interactive/components/settings-selector.js.map +0 -1
  223. package/dist/modes/interactive/components/show-images-selector.d.ts +0 -10
  224. package/dist/modes/interactive/components/show-images-selector.d.ts.map +0 -1
  225. package/dist/modes/interactive/components/show-images-selector.js +0 -39
  226. package/dist/modes/interactive/components/show-images-selector.js.map +0 -1
  227. package/dist/modes/interactive/components/skill-invocation-message.d.ts +0 -17
  228. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +0 -1
  229. package/dist/modes/interactive/components/skill-invocation-message.js +0 -47
  230. package/dist/modes/interactive/components/skill-invocation-message.js.map +0 -1
  231. package/dist/modes/interactive/components/theme-selector.d.ts +0 -11
  232. package/dist/modes/interactive/components/theme-selector.d.ts.map +0 -1
  233. package/dist/modes/interactive/components/theme-selector.js +0 -50
  234. package/dist/modes/interactive/components/theme-selector.js.map +0 -1
  235. package/dist/modes/interactive/components/thinking-selector.d.ts +0 -11
  236. package/dist/modes/interactive/components/thinking-selector.d.ts.map +0 -1
  237. package/dist/modes/interactive/components/thinking-selector.js +0 -51
  238. package/dist/modes/interactive/components/thinking-selector.js.map +0 -1
  239. package/dist/modes/interactive/components/tool-execution.d.ts +0 -63
  240. package/dist/modes/interactive/components/tool-execution.d.ts.map +0 -1
  241. package/dist/modes/interactive/components/tool-execution.js +0 -295
  242. package/dist/modes/interactive/components/tool-execution.js.map +0 -1
  243. package/dist/modes/interactive/components/tree-selector.d.ts +0 -89
  244. package/dist/modes/interactive/components/tree-selector.d.ts.map +0 -1
  245. package/dist/modes/interactive/components/tree-selector.js +0 -1093
  246. package/dist/modes/interactive/components/tree-selector.js.map +0 -1
  247. package/dist/modes/interactive/components/user-message-selector.d.ts +0 -30
  248. package/dist/modes/interactive/components/user-message-selector.d.ts.map +0 -1
  249. package/dist/modes/interactive/components/user-message-selector.js +0 -114
  250. package/dist/modes/interactive/components/user-message-selector.js.map +0 -1
  251. package/dist/modes/interactive/components/user-message.d.ts +0 -10
  252. package/dist/modes/interactive/components/user-message.d.ts.map +0 -1
  253. package/dist/modes/interactive/components/user-message.js +0 -29
  254. package/dist/modes/interactive/components/user-message.js.map +0 -1
  255. package/dist/modes/interactive/interactive-mode.d.ts +0 -375
  256. package/dist/modes/interactive/interactive-mode.d.ts.map +0 -1
  257. package/dist/modes/interactive/interactive-mode.js +0 -4799
  258. package/dist/modes/interactive/interactive-mode.js.map +0 -1
  259. package/dist/modes/interactive/theme/dark.json +0 -86
  260. package/dist/modes/interactive/theme/light.json +0 -85
  261. package/dist/modes/interactive/theme/theme-schema.json +0 -335
  262. package/examples/extensions/border-status-editor.ts +0 -150
  263. package/examples/extensions/built-in-tool-renderer.ts +0 -249
  264. package/examples/extensions/custom-footer.ts +0 -64
  265. package/examples/extensions/custom-header.ts +0 -73
  266. package/examples/extensions/custom-provider-anthropic/index.ts +0 -604
  267. package/examples/extensions/custom-provider-anthropic/package-lock.json +0 -24
  268. package/examples/extensions/custom-provider-anthropic/package.json +0 -19
  269. package/examples/extensions/custom-provider-gitlab-duo/index.ts +0 -349
  270. package/examples/extensions/custom-provider-gitlab-duo/package.json +0 -16
  271. package/examples/extensions/custom-provider-gitlab-duo/test.ts +0 -82
  272. package/examples/extensions/doom-overlay/README.md +0 -46
  273. package/examples/extensions/doom-overlay/doom/build/doom.js +0 -21
  274. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  275. package/examples/extensions/doom-overlay/doom/build.sh +0 -152
  276. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +0 -72
  277. package/examples/extensions/doom-overlay/doom-component.ts +0 -132
  278. package/examples/extensions/doom-overlay/doom-engine.ts +0 -173
  279. package/examples/extensions/doom-overlay/doom-keys.ts +0 -104
  280. package/examples/extensions/doom-overlay/index.ts +0 -74
  281. package/examples/extensions/doom-overlay/wad-finder.ts +0 -51
  282. package/examples/extensions/github-issue-autocomplete.ts +0 -185
  283. package/examples/extensions/handoff.ts +0 -191
  284. package/examples/extensions/interactive-shell.ts +0 -196
  285. package/examples/extensions/message-renderer.ts +0 -59
  286. package/examples/extensions/minimal-mode.ts +0 -426
  287. package/examples/extensions/modal-editor.ts +0 -85
  288. package/examples/extensions/overlay-qa-tests.ts +0 -1379
  289. package/examples/extensions/overlay-test.ts +0 -153
  290. package/examples/extensions/plan-mode/index.ts +0 -340
  291. package/examples/extensions/preset.ts +0 -430
  292. package/examples/extensions/qna.ts +0 -122
  293. package/examples/extensions/question.ts +0 -264
  294. package/examples/extensions/questionnaire.ts +0 -427
  295. package/examples/extensions/rainbow-editor.ts +0 -88
  296. package/examples/extensions/sandbox/index.ts +0 -321
  297. package/examples/extensions/sandbox/package-lock.json +0 -92
  298. package/examples/extensions/sandbox/package.json +0 -19
  299. package/examples/extensions/snake.ts +0 -343
  300. package/examples/extensions/space-invaders.ts +0 -560
  301. package/examples/extensions/ssh.ts +0 -220
  302. package/examples/extensions/status-line.ts +0 -32
  303. package/examples/extensions/structured-output.ts +0 -65
  304. package/examples/extensions/subagent/index.ts +0 -1009
  305. package/examples/extensions/summarize.ts +0 -206
  306. package/examples/extensions/tic-tac-toe.ts +0 -1008
  307. package/examples/extensions/todo.ts +0 -297
  308. package/examples/extensions/tools.ts +0 -141
  309. package/examples/extensions/truncated-tool.ts +0 -195
  310. package/examples/extensions/with-deps/index.ts +0 -32
  311. package/examples/extensions/with-deps/package-lock.json +0 -31
  312. package/examples/extensions/with-deps/package.json +0 -22
  313. package/examples/extensions/working-indicator.ts +0 -123
  314. package/examples/rpc-extension-ui.ts +0 -632
@@ -1,297 +0,0 @@
1
- /**
2
- * Todo Extension - Demonstrates state management via session entries
3
- *
4
- * This extension:
5
- * - Registers a `todo` tool for the LLM to manage todos
6
- * - Registers a `/todos` command for users to view the list
7
- *
8
- * State is stored in tool result details (not external files), which allows
9
- * proper branching - when you branch, the todo state is automatically
10
- * correct for that point in history.
11
- */
12
-
13
- import { StringEnum } from "@openeryc/pi-ai";
14
- import type { ExtensionAPI, ExtensionContext, Theme } from "@openeryc/pi-coding-agent";
15
- import { matchesKey, Text, truncateToWidth } from "@openeryc/pi-tui";
16
- import { Type } from "typebox";
17
-
18
- interface Todo {
19
- id: number;
20
- text: string;
21
- done: boolean;
22
- }
23
-
24
- interface TodoDetails {
25
- action: "list" | "add" | "toggle" | "clear";
26
- todos: Todo[];
27
- nextId: number;
28
- error?: string;
29
- }
30
-
31
- const TodoParams = Type.Object({
32
- action: StringEnum(["list", "add", "toggle", "clear"] as const),
33
- text: Type.Optional(Type.String({ description: "Todo text (for add)" })),
34
- id: Type.Optional(Type.Number({ description: "Todo ID (for toggle)" })),
35
- });
36
-
37
- /**
38
- * UI component for the /todos command
39
- */
40
- class TodoListComponent {
41
- private todos: Todo[];
42
- private theme: Theme;
43
- private onClose: () => void;
44
- private cachedWidth?: number;
45
- private cachedLines?: string[];
46
-
47
- constructor(todos: Todo[], theme: Theme, onClose: () => void) {
48
- this.todos = todos;
49
- this.theme = theme;
50
- this.onClose = onClose;
51
- }
52
-
53
- handleInput(data: string): void {
54
- if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
55
- this.onClose();
56
- }
57
- }
58
-
59
- render(width: number): string[] {
60
- if (this.cachedLines && this.cachedWidth === width) {
61
- return this.cachedLines;
62
- }
63
-
64
- const lines: string[] = [];
65
- const th = this.theme;
66
-
67
- lines.push("");
68
- const title = th.fg("accent", " Todos ");
69
- const headerLine =
70
- th.fg("borderMuted", "─".repeat(3)) + title + th.fg("borderMuted", "─".repeat(Math.max(0, width - 10)));
71
- lines.push(truncateToWidth(headerLine, width));
72
- lines.push("");
73
-
74
- if (this.todos.length === 0) {
75
- lines.push(truncateToWidth(` ${th.fg("dim", "No todos yet. Ask the agent to add some!")}`, width));
76
- } else {
77
- const done = this.todos.filter((t) => t.done).length;
78
- const total = this.todos.length;
79
- lines.push(truncateToWidth(` ${th.fg("muted", `${done}/${total} completed`)}`, width));
80
- lines.push("");
81
-
82
- for (const todo of this.todos) {
83
- const check = todo.done ? th.fg("success", "✓") : th.fg("dim", "○");
84
- const id = th.fg("accent", `#${todo.id}`);
85
- const text = todo.done ? th.fg("dim", todo.text) : th.fg("text", todo.text);
86
- lines.push(truncateToWidth(` ${check} ${id} ${text}`, width));
87
- }
88
- }
89
-
90
- lines.push("");
91
- lines.push(truncateToWidth(` ${th.fg("dim", "Press Escape to close")}`, width));
92
- lines.push("");
93
-
94
- this.cachedWidth = width;
95
- this.cachedLines = lines;
96
- return lines;
97
- }
98
-
99
- invalidate(): void {
100
- this.cachedWidth = undefined;
101
- this.cachedLines = undefined;
102
- }
103
- }
104
-
105
- export default function (pi: ExtensionAPI) {
106
- // In-memory state (reconstructed from session on load)
107
- let todos: Todo[] = [];
108
- let nextId = 1;
109
-
110
- /**
111
- * Reconstruct state from session entries.
112
- * Scans tool results for this tool and applies them in order.
113
- */
114
- const reconstructState = (ctx: ExtensionContext) => {
115
- todos = [];
116
- nextId = 1;
117
-
118
- for (const entry of ctx.sessionManager.getBranch()) {
119
- if (entry.type !== "message") continue;
120
- const msg = entry.message;
121
- if (msg.role !== "toolResult" || msg.toolName !== "todo") continue;
122
-
123
- const details = msg.details as TodoDetails | undefined;
124
- if (details) {
125
- todos = details.todos;
126
- nextId = details.nextId;
127
- }
128
- }
129
- };
130
-
131
- // Reconstruct state on session events
132
- pi.on("session_start", async (_event, ctx) => reconstructState(ctx));
133
- pi.on("session_tree", async (_event, ctx) => reconstructState(ctx));
134
-
135
- // Register the todo tool for the LLM
136
- pi.registerTool({
137
- name: "todo",
138
- label: "Todo",
139
- description: "Manage a todo list. Actions: list, add (text), toggle (id), clear",
140
- parameters: TodoParams,
141
-
142
- async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
143
- switch (params.action) {
144
- case "list":
145
- return {
146
- content: [
147
- {
148
- type: "text",
149
- text: todos.length
150
- ? todos.map((t) => `[${t.done ? "x" : " "}] #${t.id}: ${t.text}`).join("\n")
151
- : "No todos",
152
- },
153
- ],
154
- details: { action: "list", todos: [...todos], nextId } as TodoDetails,
155
- };
156
-
157
- case "add": {
158
- if (!params.text) {
159
- return {
160
- content: [{ type: "text", text: "Error: text required for add" }],
161
- details: { action: "add", todos: [...todos], nextId, error: "text required" } as TodoDetails,
162
- };
163
- }
164
- const newTodo: Todo = { id: nextId++, text: params.text, done: false };
165
- todos.push(newTodo);
166
- return {
167
- content: [{ type: "text", text: `Added todo #${newTodo.id}: ${newTodo.text}` }],
168
- details: { action: "add", todos: [...todos], nextId } as TodoDetails,
169
- };
170
- }
171
-
172
- case "toggle": {
173
- if (params.id === undefined) {
174
- return {
175
- content: [{ type: "text", text: "Error: id required for toggle" }],
176
- details: { action: "toggle", todos: [...todos], nextId, error: "id required" } as TodoDetails,
177
- };
178
- }
179
- const todo = todos.find((t) => t.id === params.id);
180
- if (!todo) {
181
- return {
182
- content: [{ type: "text", text: `Todo #${params.id} not found` }],
183
- details: {
184
- action: "toggle",
185
- todos: [...todos],
186
- nextId,
187
- error: `#${params.id} not found`,
188
- } as TodoDetails,
189
- };
190
- }
191
- todo.done = !todo.done;
192
- return {
193
- content: [{ type: "text", text: `Todo #${todo.id} ${todo.done ? "completed" : "uncompleted"}` }],
194
- details: { action: "toggle", todos: [...todos], nextId } as TodoDetails,
195
- };
196
- }
197
-
198
- case "clear": {
199
- const count = todos.length;
200
- todos = [];
201
- nextId = 1;
202
- return {
203
- content: [{ type: "text", text: `Cleared ${count} todos` }],
204
- details: { action: "clear", todos: [], nextId: 1 } as TodoDetails,
205
- };
206
- }
207
-
208
- default:
209
- return {
210
- content: [{ type: "text", text: `Unknown action: ${params.action}` }],
211
- details: {
212
- action: "list",
213
- todos: [...todos],
214
- nextId,
215
- error: `unknown action: ${params.action}`,
216
- } as TodoDetails,
217
- };
218
- }
219
- },
220
-
221
- renderCall(args, theme, _context) {
222
- let text = theme.fg("toolTitle", theme.bold("todo ")) + theme.fg("muted", args.action);
223
- if (args.text) text += ` ${theme.fg("dim", `"${args.text}"`)}`;
224
- if (args.id !== undefined) text += ` ${theme.fg("accent", `#${args.id}`)}`;
225
- return new Text(text, 0, 0);
226
- },
227
-
228
- renderResult(result, { expanded }, theme, _context) {
229
- const details = result.details as TodoDetails | undefined;
230
- if (!details) {
231
- const text = result.content[0];
232
- return new Text(text?.type === "text" ? text.text : "", 0, 0);
233
- }
234
-
235
- if (details.error) {
236
- return new Text(theme.fg("error", `Error: ${details.error}`), 0, 0);
237
- }
238
-
239
- const todoList = details.todos;
240
-
241
- switch (details.action) {
242
- case "list": {
243
- if (todoList.length === 0) {
244
- return new Text(theme.fg("dim", "No todos"), 0, 0);
245
- }
246
- let listText = theme.fg("muted", `${todoList.length} todo(s):`);
247
- const display = expanded ? todoList : todoList.slice(0, 5);
248
- for (const t of display) {
249
- const check = t.done ? theme.fg("success", "✓") : theme.fg("dim", "○");
250
- const itemText = t.done ? theme.fg("dim", t.text) : theme.fg("muted", t.text);
251
- listText += `\n${check} ${theme.fg("accent", `#${t.id}`)} ${itemText}`;
252
- }
253
- if (!expanded && todoList.length > 5) {
254
- listText += `\n${theme.fg("dim", `... ${todoList.length - 5} more`)}`;
255
- }
256
- return new Text(listText, 0, 0);
257
- }
258
-
259
- case "add": {
260
- const added = todoList[todoList.length - 1];
261
- return new Text(
262
- theme.fg("success", "✓ Added ") +
263
- theme.fg("accent", `#${added.id}`) +
264
- " " +
265
- theme.fg("muted", added.text),
266
- 0,
267
- 0,
268
- );
269
- }
270
-
271
- case "toggle": {
272
- const text = result.content[0];
273
- const msg = text?.type === "text" ? text.text : "";
274
- return new Text(theme.fg("success", "✓ ") + theme.fg("muted", msg), 0, 0);
275
- }
276
-
277
- case "clear":
278
- return new Text(theme.fg("success", "✓ ") + theme.fg("muted", "Cleared all todos"), 0, 0);
279
- }
280
- },
281
- });
282
-
283
- // Register the /todos command for users
284
- pi.registerCommand("todos", {
285
- description: "Show all todos on the current branch",
286
- handler: async (_args, ctx) => {
287
- if (!ctx.hasUI) {
288
- ctx.ui.notify("/todos requires interactive mode", "error");
289
- return;
290
- }
291
-
292
- await ctx.ui.custom<void>((_tui, theme, _kb, done) => {
293
- return new TodoListComponent(todos, theme, () => done());
294
- });
295
- },
296
- });
297
- }
@@ -1,141 +0,0 @@
1
- /**
2
- * Tools Extension
3
- *
4
- * Provides a /tools command to enable/disable tools interactively.
5
- * Tool selection persists across session reloads and respects branch navigation.
6
- *
7
- * Usage:
8
- * 1. Copy this file to ~/.pi/agent/extensions/ or your project's .pi/extensions/
9
- * 2. Use /tools to open the tool selector
10
- */
11
-
12
- import type { ExtensionAPI, ExtensionContext, ToolInfo } from "@openeryc/pi-coding-agent";
13
- import { getSettingsListTheme } from "@openeryc/pi-coding-agent";
14
- import { Container, type SettingItem, SettingsList } from "@openeryc/pi-tui";
15
-
16
- // State persisted to session
17
- interface ToolsState {
18
- enabledTools: string[];
19
- }
20
-
21
- export default function toolsExtension(pi: ExtensionAPI) {
22
- // Track enabled tools
23
- let enabledTools: Set<string> = new Set();
24
- let allTools: ToolInfo[] = [];
25
-
26
- // Persist current state
27
- function persistState() {
28
- pi.appendEntry<ToolsState>("tools-config", {
29
- enabledTools: Array.from(enabledTools),
30
- });
31
- }
32
-
33
- // Apply current tool selection
34
- function applyTools() {
35
- pi.setActiveTools(Array.from(enabledTools));
36
- }
37
-
38
- // Find the last tools-config entry in the current branch
39
- function restoreFromBranch(ctx: ExtensionContext) {
40
- allTools = pi.getAllTools();
41
-
42
- // Get entries in current branch only
43
- const branchEntries = ctx.sessionManager.getBranch();
44
- let savedTools: string[] | undefined;
45
-
46
- for (const entry of branchEntries) {
47
- if (entry.type === "custom" && entry.customType === "tools-config") {
48
- const data = entry.data as ToolsState | undefined;
49
- if (data?.enabledTools) {
50
- savedTools = data.enabledTools;
51
- }
52
- }
53
- }
54
-
55
- if (savedTools) {
56
- // Restore saved tool selection (filter to only tools that still exist)
57
- const allToolNames = allTools.map((t) => t.name);
58
- enabledTools = new Set(savedTools.filter((t: string) => allToolNames.includes(t)));
59
- applyTools();
60
- } else {
61
- // No saved state - sync with currently active tools
62
- enabledTools = new Set(pi.getActiveTools());
63
- }
64
- }
65
-
66
- // Register /tools command
67
- pi.registerCommand("tools", {
68
- description: "Enable/disable tools",
69
- handler: async (_args, ctx) => {
70
- // Refresh tool list
71
- allTools = pi.getAllTools();
72
-
73
- await ctx.ui.custom((tui, theme, _kb, done) => {
74
- // Build settings items for each tool
75
- const items: SettingItem[] = allTools.map((tool) => ({
76
- id: tool.name,
77
- label: tool.name,
78
- currentValue: enabledTools.has(tool.name) ? "enabled" : "disabled",
79
- values: ["enabled", "disabled"],
80
- }));
81
-
82
- const container = new Container();
83
- container.addChild(
84
- new (class {
85
- render(_width: number) {
86
- return [theme.fg("accent", theme.bold("Tool Configuration")), ""];
87
- }
88
- invalidate() {}
89
- })(),
90
- );
91
-
92
- const settingsList = new SettingsList(
93
- items,
94
- Math.min(items.length + 2, 15),
95
- getSettingsListTheme(),
96
- (id, newValue) => {
97
- // Update enabled state and apply immediately
98
- if (newValue === "enabled") {
99
- enabledTools.add(id);
100
- } else {
101
- enabledTools.delete(id);
102
- }
103
- applyTools();
104
- persistState();
105
- },
106
- () => {
107
- // Close dialog
108
- done(undefined);
109
- },
110
- );
111
-
112
- container.addChild(settingsList);
113
-
114
- const component = {
115
- render(width: number) {
116
- return container.render(width);
117
- },
118
- invalidate() {
119
- container.invalidate();
120
- },
121
- handleInput(data: string) {
122
- settingsList.handleInput?.(data);
123
- tui.requestRender();
124
- },
125
- };
126
-
127
- return component;
128
- });
129
- },
130
- });
131
-
132
- // Restore state on session start
133
- pi.on("session_start", async (_event, ctx) => {
134
- restoreFromBranch(ctx);
135
- });
136
-
137
- // Restore state when navigating the session tree
138
- pi.on("session_tree", async (_event, ctx) => {
139
- restoreFromBranch(ctx);
140
- });
141
- }
@@ -1,195 +0,0 @@
1
- /**
2
- * Truncated Tool Example - Demonstrates proper output truncation for custom tools
3
- *
4
- * Custom tools MUST truncate their output to avoid overwhelming the LLM context.
5
- * The built-in limit is 50KB (~10k tokens) and 2000 lines, whichever is hit first.
6
- *
7
- * This example shows how to:
8
- * 1. Use the built-in truncation utilities
9
- * 2. Write full output to a temp file when truncated
10
- * 3. Inform the LLM where to find the complete output
11
- * 4. Custom rendering of tool calls and results
12
- *
13
- * The `rg` tool here wraps ripgrep with proper truncation. Compare this to the
14
- * built-in `grep` tool in src/core/tools/grep.ts for a more complete implementation.
15
- */
16
-
17
- import { mkdtemp, writeFile } from "node:fs/promises";
18
- import type { ExtensionAPI } from "@openeryc/pi-coding-agent";
19
- import {
20
- DEFAULT_MAX_BYTES,
21
- DEFAULT_MAX_LINES,
22
- formatSize,
23
- type TruncationResult,
24
- truncateHead,
25
- withFileMutationQueue,
26
- } from "@openeryc/pi-coding-agent";
27
- import { Text } from "@openeryc/pi-tui";
28
- import { execSync } from "child_process";
29
- import { tmpdir } from "os";
30
- import { join } from "path";
31
- import { Type } from "typebox";
32
-
33
- const RgParams = Type.Object({
34
- pattern: Type.String({ description: "Search pattern (regex)" }),
35
- path: Type.Optional(Type.String({ description: "Directory to search (default: current directory)" })),
36
- glob: Type.Optional(Type.String({ description: "File glob pattern, e.g. '*.ts'" })),
37
- });
38
-
39
- interface RgDetails {
40
- pattern: string;
41
- path?: string;
42
- glob?: string;
43
- matchCount: number;
44
- truncation?: TruncationResult;
45
- fullOutputPath?: string;
46
- }
47
-
48
- export default function (pi: ExtensionAPI) {
49
- pi.registerTool({
50
- name: "rg",
51
- label: "ripgrep",
52
- // Document the truncation limits in the tool description so the LLM knows
53
- description: `Search file contents using ripgrep. Output is truncated to ${DEFAULT_MAX_LINES} lines or ${formatSize(DEFAULT_MAX_BYTES)} (whichever is hit first). If truncated, full output is saved to a temp file.`,
54
- parameters: RgParams,
55
-
56
- async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
57
- const { pattern, path: searchPath, glob } = params;
58
-
59
- // Build the ripgrep command
60
- const args = ["rg", "--line-number", "--color=never"];
61
- if (glob) args.push("--glob", glob);
62
- args.push(pattern);
63
- args.push(searchPath || ".");
64
-
65
- let output: string;
66
- try {
67
- output = execSync(args.join(" "), {
68
- cwd: ctx.cwd,
69
- encoding: "utf-8",
70
- maxBuffer: 100 * 1024 * 1024, // 100MB buffer to capture full output
71
- });
72
- } catch (err: any) {
73
- // ripgrep exits with 1 when no matches found
74
- if (err.status === 1) {
75
- return {
76
- content: [{ type: "text", text: "No matches found" }],
77
- details: { pattern, path: searchPath, glob, matchCount: 0 } as RgDetails,
78
- };
79
- }
80
- throw new Error(`ripgrep failed: ${err.message}`);
81
- }
82
-
83
- if (!output.trim()) {
84
- return {
85
- content: [{ type: "text", text: "No matches found" }],
86
- details: { pattern, path: searchPath, glob, matchCount: 0 } as RgDetails,
87
- };
88
- }
89
-
90
- // Apply truncation using built-in utilities
91
- // truncateHead keeps the first N lines/bytes (good for search results)
92
- // truncateTail keeps the last N lines/bytes (good for logs/command output)
93
- const truncation = truncateHead(output, {
94
- maxLines: DEFAULT_MAX_LINES,
95
- maxBytes: DEFAULT_MAX_BYTES,
96
- });
97
-
98
- // Count matches (each non-empty line with a match)
99
- const matchCount = output.split("\n").filter((line) => line.trim()).length;
100
-
101
- const details: RgDetails = {
102
- pattern,
103
- path: searchPath,
104
- glob,
105
- matchCount,
106
- };
107
-
108
- let resultText = truncation.content;
109
-
110
- if (truncation.truncated) {
111
- // Save full output to a temp file so LLM can access it if needed
112
- const tempDir = await mkdtemp(join(tmpdir(), "pi-rg-"));
113
- const tempFile = join(tempDir, "output.txt");
114
- await withFileMutationQueue(tempFile, async () => {
115
- await writeFile(tempFile, output, "utf8");
116
- });
117
-
118
- details.truncation = truncation;
119
- details.fullOutputPath = tempFile;
120
-
121
- // Add truncation notice - this helps the LLM understand the output is incomplete
122
- const truncatedLines = truncation.totalLines - truncation.outputLines;
123
- const truncatedBytes = truncation.totalBytes - truncation.outputBytes;
124
-
125
- resultText += `\n\n[Output truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`;
126
- resultText += ` (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}).`;
127
- resultText += ` ${truncatedLines} lines (${formatSize(truncatedBytes)}) omitted.`;
128
- resultText += ` Full output saved to: ${tempFile}]`;
129
- }
130
-
131
- return {
132
- content: [{ type: "text", text: resultText }],
133
- details,
134
- };
135
- },
136
-
137
- // Custom rendering of the tool call (shown before/during execution)
138
- renderCall(args, theme, _context) {
139
- let text = theme.fg("toolTitle", theme.bold("rg "));
140
- text += theme.fg("accent", `"${args.pattern}"`);
141
- if (args.path) {
142
- text += theme.fg("muted", ` in ${args.path}`);
143
- }
144
- if (args.glob) {
145
- text += theme.fg("dim", ` --glob ${args.glob}`);
146
- }
147
- return new Text(text, 0, 0);
148
- },
149
-
150
- // Custom rendering of the tool result
151
- renderResult(result, { expanded, isPartial }, theme, _context) {
152
- const details = result.details as RgDetails | undefined;
153
-
154
- // Handle streaming/partial results
155
- if (isPartial) {
156
- return new Text(theme.fg("warning", "Searching..."), 0, 0);
157
- }
158
-
159
- // No matches
160
- if (!details || details.matchCount === 0) {
161
- return new Text(theme.fg("dim", "No matches found"), 0, 0);
162
- }
163
-
164
- // Build result display
165
- let text = theme.fg("success", `${details.matchCount} matches`);
166
-
167
- // Show truncation warning if applicable
168
- if (details.truncation?.truncated) {
169
- text += theme.fg("warning", " (truncated)");
170
- }
171
-
172
- // In expanded view, show the actual matches
173
- if (expanded) {
174
- const content = result.content[0];
175
- if (content?.type === "text") {
176
- // Show first 20 lines in expanded view, or all if fewer
177
- const lines = content.text.split("\n").slice(0, 20);
178
- for (const line of lines) {
179
- text += `\n${theme.fg("dim", line)}`;
180
- }
181
- if (content.text.split("\n").length > 20) {
182
- text += `\n${theme.fg("muted", "... (use read tool to see full output)")}`;
183
- }
184
- }
185
-
186
- // Show temp file path if truncated
187
- if (details.fullOutputPath) {
188
- text += `\n${theme.fg("dim", `Full output: ${details.fullOutputPath}`)}`;
189
- }
190
- }
191
-
192
- return new Text(text, 0, 0);
193
- },
194
- });
195
- }
@@ -1,32 +0,0 @@
1
- /**
2
- * Example extension with its own npm dependencies.
3
- * Tests that jiti resolves modules from the extension's own node_modules.
4
- *
5
- * Requires: npm install in this directory
6
- */
7
-
8
- import type { ExtensionAPI } from "@openeryc/pi-coding-agent";
9
- import ms from "ms";
10
- import { Type } from "typebox";
11
-
12
- export default function (pi: ExtensionAPI) {
13
- // Register a tool that uses ms
14
- pi.registerTool({
15
- name: "parse_duration",
16
- label: "Parse Duration",
17
- description: "Parse a human-readable duration string (e.g., '2 days', '1h', '5m') to milliseconds",
18
- parameters: Type.Object({
19
- duration: Type.String({ description: "Duration string like '2 days', '1h', '5m'" }),
20
- }),
21
- execute: async (_toolCallId, params) => {
22
- const result = ms(params.duration as ms.StringValue);
23
- if (result === undefined) {
24
- throw new Error(`Invalid duration: "${params.duration}"`);
25
- }
26
- return {
27
- content: [{ type: "text", text: `${params.duration} = ${result} milliseconds` }],
28
- details: {},
29
- };
30
- },
31
- });
32
- }
@@ -1,31 +0,0 @@
1
- {
2
- "name": "pi-extension-with-deps",
3
- "version": "0.75.25",
4
- "lockfileVersion": 3,
5
- "requires": true,
6
- "packages": {
7
- "": {
8
- "name": "pi-extension-with-deps",
9
- "version": "0.75.25",
10
- "dependencies": {
11
- "ms": "^2.1.3"
12
- },
13
- "devDependencies": {
14
- "@types/ms": "^2.1.0"
15
- }
16
- },
17
- "node_modules/@types/ms": {
18
- "version": "2.1.0",
19
- "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
20
- "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
21
- "dev": true,
22
- "license": "MIT"
23
- },
24
- "node_modules/ms": {
25
- "version": "2.1.3",
26
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
27
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
28
- "license": "MIT"
29
- }
30
- }
31
- }