@oh-my-pi/pi-coding-agent 17.0.9 → 17.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +1 -1
  3. package/dist/cli.js +4659 -4261
  4. package/dist/types/async/job-manager.d.ts +37 -1
  5. package/dist/types/cli/args.d.ts +2 -0
  6. package/dist/types/cli/bench-cli.d.ts +41 -0
  7. package/dist/types/commands/bench.d.ts +15 -3
  8. package/dist/types/commands/launch.d.ts +4 -0
  9. package/dist/types/config/model-registry.d.ts +3 -1
  10. package/dist/types/config/models-config-schema.d.ts +18 -6
  11. package/dist/types/config/models-config.d.ts +14 -5
  12. package/dist/types/config/provider-globals.d.ts +2 -2
  13. package/dist/types/config/service-tier.d.ts +5 -1
  14. package/dist/types/config/settings-schema.d.ts +316 -47
  15. package/dist/types/config/settings.d.ts +7 -0
  16. package/dist/types/dap/client.d.ts +20 -0
  17. package/dist/types/exec/bash-executor.d.ts +38 -0
  18. package/dist/types/exec/direnv.d.ts +33 -0
  19. package/dist/types/export/html/args.d.ts +15 -0
  20. package/dist/types/export/html/index.d.ts +11 -26
  21. package/dist/types/export/html/web-palette.d.ts +55 -116
  22. package/dist/types/extensibility/extensions/loader.d.ts +3 -0
  23. package/dist/types/extensibility/extensions/types.d.ts +17 -2
  24. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +13 -0
  25. package/dist/types/live/controller.d.ts +40 -0
  26. package/dist/types/live/protocol.d.ts +85 -0
  27. package/dist/types/live/protocol.test.d.ts +1 -0
  28. package/dist/types/live/transport.d.ts +48 -0
  29. package/dist/types/live/visualizer.d.ts +33 -0
  30. package/dist/types/lsp/client.d.ts +16 -1
  31. package/dist/types/mcp/config-writer.test.d.ts +1 -0
  32. package/dist/types/mcp/oauth-discovery.d.ts +2 -0
  33. package/dist/types/mcp/smithery-auth.d.ts +1 -1
  34. package/dist/types/mcp/smithery-auth.test.d.ts +1 -0
  35. package/dist/types/memory-backend/tool-names.d.ts +2 -0
  36. package/dist/types/modes/components/login-dialog.d.ts +2 -2
  37. package/dist/types/modes/components/plan-review-overlay.d.ts +26 -0
  38. package/dist/types/modes/components/settings-defs.d.ts +7 -1
  39. package/dist/types/modes/components/status-line/component.jj-cache.test.d.ts +1 -0
  40. package/dist/types/modes/components/tool-execution.d.ts +9 -1
  41. package/dist/types/modes/controllers/command-controller.d.ts +1 -1
  42. package/dist/types/modes/controllers/event-controller.d.ts +6 -1
  43. package/dist/types/modes/controllers/live-command-controller.d.ts +14 -0
  44. package/dist/types/modes/interactive-mode.d.ts +5 -0
  45. package/dist/types/modes/theme/theme.d.ts +1 -1
  46. package/dist/types/modes/types.d.ts +3 -1
  47. package/dist/types/modes/utils/context-usage.d.ts +12 -2
  48. package/dist/types/plan-mode/plan-files.d.ts +10 -0
  49. package/dist/types/registry/agent-lifecycle.d.ts +21 -9
  50. package/dist/types/registry/agent-registry.d.ts +11 -4
  51. package/dist/types/sdk.d.ts +15 -1
  52. package/dist/types/secrets/index.d.ts +15 -2
  53. package/dist/types/secrets/obfuscator.d.ts +113 -15
  54. package/dist/types/session/acp-permission-gate.d.ts +19 -0
  55. package/dist/types/session/agent-session-events.d.ts +84 -0
  56. package/dist/types/session/agent-session-types.d.ts +314 -0
  57. package/dist/types/session/agent-session.d.ts +118 -755
  58. package/dist/types/session/async-job-delivery.d.ts +28 -0
  59. package/dist/types/session/bash-runner.d.ts +75 -0
  60. package/dist/types/session/blob-store.d.ts +11 -1
  61. package/dist/types/session/blob-store.test.d.ts +1 -0
  62. package/dist/types/session/checkpoint-entries.d.ts +28 -0
  63. package/dist/types/session/eval-runner.d.ts +49 -0
  64. package/dist/types/session/irc-bridge.d.ts +46 -0
  65. package/dist/types/session/messages.d.ts +22 -0
  66. package/dist/types/session/model-controls.d.ts +180 -0
  67. package/dist/types/session/prewalk.d.ts +46 -0
  68. package/dist/types/session/queued-messages.d.ts +22 -0
  69. package/dist/types/session/redis-session-storage.d.ts +1 -0
  70. package/dist/types/session/retry-fallback-chains.d.ts +74 -0
  71. package/dist/types/session/role-models.d.ts +15 -0
  72. package/dist/types/session/session-advisors.d.ts +228 -0
  73. package/dist/types/session/session-entries.d.ts +8 -0
  74. package/dist/types/session/session-handoff.d.ts +70 -0
  75. package/dist/types/session/session-history-format.d.ts +6 -1
  76. package/dist/types/session/session-maintenance.d.ts +246 -0
  77. package/dist/types/session/session-manager.d.ts +41 -0
  78. package/dist/types/session/session-memory.d.ts +56 -0
  79. package/dist/types/session/session-provider-boundary.d.ts +62 -0
  80. package/dist/types/session/session-stats.d.ts +48 -0
  81. package/dist/types/session/session-tools.d.ts +143 -0
  82. package/dist/types/session/session-workspace.d.ts +32 -0
  83. package/dist/types/session/stream-guards.d.ts +44 -0
  84. package/dist/types/session/todo-tracker.d.ts +56 -0
  85. package/dist/types/session/ttsr-coordinator.d.ts +51 -0
  86. package/dist/types/session/turn-recovery.d.ts +225 -0
  87. package/dist/types/system-prompt.d.ts +2 -0
  88. package/dist/types/task/executor.d.ts +4 -1
  89. package/dist/types/task/output-manager.d.ts +3 -1
  90. package/dist/types/tools/approval.d.ts +1 -0
  91. package/dist/types/tools/browser/launch.d.ts +5 -0
  92. package/dist/types/tools/image-gen.d.ts +4 -4
  93. package/dist/types/tools/image-providers.d.ts +38 -0
  94. package/dist/types/tools/index.d.ts +5 -0
  95. package/dist/types/tools/path-utils.d.ts +8 -0
  96. package/dist/types/tools/todo.d.ts +10 -4
  97. package/dist/types/tools/xdev.d.ts +5 -1
  98. package/dist/types/tts/streaming-player.d.ts +14 -0
  99. package/dist/types/tts/vocalizer.d.ts +5 -0
  100. package/dist/types/utils/jj.d.ts +29 -0
  101. package/dist/types/utils/lang-from-path.d.ts +1 -0
  102. package/dist/types/utils/title-generator.d.ts +30 -0
  103. package/dist/types/vibe/runtime.d.ts +36 -8
  104. package/dist/types/web/search/index.d.ts +1 -1
  105. package/dist/types/web/search/provider.d.ts +15 -5
  106. package/dist/types/web/search/types.d.ts +94 -0
  107. package/package.json +12 -12
  108. package/scripts/generate-share-viewer.ts +4 -6
  109. package/src/advisor/__tests__/advisor.test.ts +643 -0
  110. package/src/advisor/runtime.ts +144 -43
  111. package/src/async/job-manager.ts +90 -2
  112. package/src/cli/args.ts +2 -0
  113. package/src/cli/auth-gateway-cli.ts +18 -3
  114. package/src/cli/bench-cli.ts +395 -29
  115. package/src/cli/flag-tables.ts +3 -0
  116. package/src/cli/gc-cli.ts +2 -2
  117. package/src/cli/usage-cli.ts +10 -1
  118. package/src/collab/host.ts +3 -2
  119. package/src/commands/bench.ts +18 -4
  120. package/src/commands/launch.ts +4 -0
  121. package/src/config/model-registry.ts +10 -2
  122. package/src/config/models-config-schema.ts +15 -4
  123. package/src/config/provider-globals.ts +9 -9
  124. package/src/config/service-tier.ts +26 -1
  125. package/src/config/settings-schema.ts +209 -51
  126. package/src/config/settings.ts +81 -2
  127. package/src/dap/client.ts +37 -4
  128. package/src/edit/index.ts +49 -12
  129. package/src/eval/py/executor.ts +103 -33
  130. package/src/exec/bash-executor.ts +89 -6
  131. package/src/exec/direnv.ts +145 -0
  132. package/src/export/html/args.ts +20 -0
  133. package/src/export/html/index.ts +45 -47
  134. package/src/export/html/template.css +19 -1
  135. package/src/export/html/template.html +6 -0
  136. package/src/export/html/template.js +21 -0
  137. package/src/export/html/tool-views.generated.js +31 -31
  138. package/src/export/html/web-palette.ts +116 -132
  139. package/src/export/share.ts +249 -49
  140. package/src/extensibility/extensions/loader.ts +29 -1
  141. package/src/extensibility/extensions/runner.ts +6 -0
  142. package/src/extensibility/extensions/types.ts +33 -2
  143. package/src/extensibility/plugins/legacy-pi-compat.ts +19 -1
  144. package/src/hindsight/state.ts +64 -6
  145. package/src/internal-urls/local-protocol.ts +2 -1
  146. package/src/internal-urls/memory-protocol.ts +2 -2
  147. package/src/internal-urls/skill-protocol.ts +2 -2
  148. package/src/internal-urls/ssh-protocol.ts +2 -1
  149. package/src/internal-urls/vault-protocol.ts +2 -1
  150. package/src/live/audio-worklet.txt +59 -0
  151. package/src/live/browser-runtime.txt +221 -0
  152. package/src/live/controller.ts +464 -0
  153. package/src/live/prompts/agent-final-message.md +3 -0
  154. package/src/live/prompts/live-instructions.md +23 -0
  155. package/src/live/protocol.test.ts +140 -0
  156. package/src/live/protocol.ts +233 -0
  157. package/src/live/transport.ts +490 -0
  158. package/src/live/visualizer.ts +234 -0
  159. package/src/lsp/client.ts +29 -9
  160. package/src/lsp/index.ts +19 -4
  161. package/src/main.ts +8 -1
  162. package/src/mcp/config-writer.test.ts +43 -0
  163. package/src/mcp/config-writer.ts +109 -82
  164. package/src/mcp/oauth-discovery.ts +10 -2
  165. package/src/mcp/smithery-auth.test.ts +29 -0
  166. package/src/mcp/smithery-auth.ts +3 -2
  167. package/src/memories/index.ts +40 -20
  168. package/src/memory-backend/tool-names.ts +2 -0
  169. package/src/mnemopi/backend.ts +24 -7
  170. package/src/modes/acp/acp-agent.ts +56 -10
  171. package/src/modes/acp/acp-event-mapper.ts +8 -1
  172. package/src/modes/components/agent-hub.ts +1 -1
  173. package/src/modes/components/login-dialog.ts +14 -4
  174. package/src/modes/components/plan-review-overlay.ts +350 -35
  175. package/src/modes/components/settings-defs.ts +23 -1
  176. package/src/modes/components/settings-selector.ts +169 -1
  177. package/src/modes/components/status-line/component.jj-cache.test.ts +229 -0
  178. package/src/modes/components/status-line/component.ts +123 -2
  179. package/src/modes/components/tool-execution.ts +11 -2
  180. package/src/modes/controllers/command-controller.ts +56 -15
  181. package/src/modes/controllers/event-controller.ts +111 -16
  182. package/src/modes/controllers/extension-ui-controller.test.ts +1 -0
  183. package/src/modes/controllers/extension-ui-controller.ts +20 -4
  184. package/src/modes/controllers/live-command-controller.ts +178 -0
  185. package/src/modes/controllers/mcp-command-controller.ts +10 -1
  186. package/src/modes/controllers/omfg-controller.ts +44 -40
  187. package/src/modes/controllers/selector-controller.ts +18 -10
  188. package/src/modes/controllers/session-focus-controller.ts +6 -1
  189. package/src/modes/interactive-mode.ts +157 -38
  190. package/src/modes/runtime-init.ts +2 -0
  191. package/src/modes/setup-wizard/scenes/web-search.ts +17 -9
  192. package/src/modes/theme/theme.ts +1 -1
  193. package/src/modes/types.ts +3 -1
  194. package/src/modes/utils/context-usage.ts +23 -7
  195. package/src/modes/utils/ui-helpers.ts +10 -5
  196. package/src/plan-mode/plan-files.ts +40 -0
  197. package/src/prompts/bench/cache-prefix-chunk.md +1 -0
  198. package/src/prompts/bench/cache-prefix.md +3 -0
  199. package/src/prompts/bench/cache-suffix.md +1 -0
  200. package/src/prompts/system/custom-system-prompt.md +1 -1
  201. package/src/prompts/system/project-prompt.md +8 -1
  202. package/src/prompts/system/subagent-async-pending.md +6 -0
  203. package/src/prompts/system/system-prompt.md +1 -1
  204. package/src/prompts/system/workflow-notice.md +48 -40
  205. package/src/prompts/system/xdev-mount-notice.md +4 -0
  206. package/src/prompts/tools/todo.md +3 -1
  207. package/src/registry/agent-lifecycle.ts +116 -46
  208. package/src/registry/agent-registry.ts +35 -8
  209. package/src/registry/persisted-agents.ts +26 -2
  210. package/src/sdk.ts +210 -136
  211. package/src/secrets/index.ts +127 -4
  212. package/src/secrets/obfuscator.ts +2328 -105
  213. package/src/session/acp-permission-gate.ts +165 -0
  214. package/src/session/agent-session-error-log.test.ts +1 -1
  215. package/src/session/agent-session-events.ts +66 -0
  216. package/src/session/agent-session-types.ts +334 -0
  217. package/src/session/agent-session.ts +1892 -12226
  218. package/src/session/artifacts.ts +6 -5
  219. package/src/session/async-job-delivery.ts +74 -0
  220. package/src/session/bash-runner.ts +326 -0
  221. package/src/session/blob-store.test.ts +56 -0
  222. package/src/session/blob-store.ts +18 -2
  223. package/src/session/checkpoint-entries.ts +81 -0
  224. package/src/session/eval-runner.ts +212 -0
  225. package/src/session/indexed-session-storage.ts +9 -2
  226. package/src/session/irc-bridge.ts +203 -0
  227. package/src/session/messages.ts +263 -1
  228. package/src/session/model-controls.ts +714 -0
  229. package/src/session/prewalk.ts +252 -0
  230. package/src/session/queued-messages.ts +93 -0
  231. package/src/session/redis-session-storage.ts +51 -11
  232. package/src/session/retry-fallback-chains.ts +455 -0
  233. package/src/session/role-models.ts +85 -0
  234. package/src/session/session-advisors.ts +1679 -0
  235. package/src/session/session-context.ts +6 -3
  236. package/src/session/session-entries.ts +8 -0
  237. package/src/session/session-handoff.ts +308 -0
  238. package/src/session/session-history-format.ts +20 -9
  239. package/src/session/session-loader.ts +0 -46
  240. package/src/session/session-maintenance.ts +2983 -0
  241. package/src/session/session-manager.ts +390 -30
  242. package/src/session/session-memory.ts +222 -0
  243. package/src/session/session-provider-boundary.ts +307 -0
  244. package/src/session/session-stats.ts +293 -0
  245. package/src/session/session-tools.ts +943 -0
  246. package/src/session/session-workspace.ts +53 -0
  247. package/src/session/stream-guards.ts +417 -0
  248. package/src/session/todo-tracker.ts +380 -0
  249. package/src/session/ttsr-coordinator.ts +496 -0
  250. package/src/session/turn-recovery.ts +1629 -0
  251. package/src/slash-commands/builtin-registry.ts +92 -11
  252. package/src/slash-commands/helpers/usage-report.ts +22 -3
  253. package/src/system-prompt.ts +41 -17
  254. package/src/task/executor.ts +285 -70
  255. package/src/task/index.ts +98 -105
  256. package/src/task/output-manager.ts +25 -3
  257. package/src/task/persisted-revive.ts +4 -3
  258. package/src/task/structured-subagent.ts +1 -0
  259. package/src/tools/approval.ts +55 -10
  260. package/src/tools/bash-interactive.ts +26 -0
  261. package/src/tools/bash-skill-urls.ts +28 -2
  262. package/src/tools/bash.ts +339 -123
  263. package/src/tools/browser/launch.ts +9 -1
  264. package/src/tools/browser/tab-supervisor.ts +8 -5
  265. package/src/tools/browser.ts +94 -47
  266. package/src/tools/image-gen.ts +20 -28
  267. package/src/tools/image-providers.ts +50 -0
  268. package/src/tools/index.ts +9 -0
  269. package/src/tools/path-utils.ts +49 -2
  270. package/src/tools/read.ts +156 -88
  271. package/src/tools/renderers.ts +7 -1
  272. package/src/tools/todo.ts +101 -11
  273. package/src/tools/vibe.ts +1 -2
  274. package/src/tools/write.ts +51 -1
  275. package/src/tools/xdev.ts +67 -3
  276. package/src/tts/streaming-player.ts +62 -4
  277. package/src/tts/vocalizer.ts +18 -1
  278. package/src/utils/jj.ts +125 -4
  279. package/src/utils/lang-from-path.ts +7 -0
  280. package/src/utils/title-generator.ts +137 -1
  281. package/src/vibe/runtime.ts +852 -72
  282. package/src/web/search/index.ts +3 -6
  283. package/src/web/search/provider.ts +31 -16
  284. package/src/web/search/providers/xai.ts +7 -1
  285. package/src/web/search/types.ts +3 -0
@@ -16,6 +16,7 @@ import {
16
16
  resolveActiveProjectRegistryPath,
17
17
  resolveOrDefaultProjectRegistryPath,
18
18
  } from "../discovery/helpers.js";
19
+ import { parseExportArgs } from "../export/html/args";
19
20
  import { shareSession } from "../export/share";
20
21
  import { PluginManager } from "../extensibility/plugins";
21
22
  import {
@@ -203,6 +204,14 @@ function parseShakeMode(args: string): ShakeMode | { error: string } {
203
204
  return { error: `Unknown /shake mode "${verb}". Use elide or images.` };
204
205
  }
205
206
 
207
+ /** Format the session's workspace directories (cwd + additional) for display. */
208
+ function formatWorkspaceDirectories(runtime: SlashCommandRuntime, note?: string): string {
209
+ const cwd = runtime.sessionManager.getCwd();
210
+ const additional = runtime.sessionManager.getAdditionalDirectories();
211
+ const lines = ["Workspace directories:", ` ${cwd} (working directory)`, ...additional.map(d => ` ${d}`)];
212
+ return note ? `${note}\n${lines.join("\n")}` : lines.join("\n");
213
+ }
214
+
206
215
  const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
207
216
  {
208
217
  name: "settings",
@@ -606,19 +615,15 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
606
615
  {
607
616
  name: "export",
608
617
  description: "Export session to HTML file",
609
- inlineHint: "[path]",
618
+ inlineHint: "[--themes] [path]",
610
619
  allowArgs: true,
611
620
  handle: async (command, runtime) => {
612
- const arg = command.args.trim();
613
- // Match the interactive `/export` behavior: clipboard aliases are not a
614
- // valid export target. Without this, the literal value (`copy`,
615
- // `--copy`, `clipboard`) is passed to `exportToHtml` and becomes the
616
- // output filename.
617
- if (arg === "--copy" || arg === "clipboard" || arg === "copy") {
618
- return usage("Use /dump to copy the session to clipboard.", runtime);
619
- }
620
621
  try {
621
- const filePath = await runtime.session.exportToHtml(arg || undefined);
622
+ const { outputPath, useUserThemes } = parseExportArgs(command.args);
623
+ if (outputPath === "--copy" || outputPath === "clipboard" || outputPath === "copy") {
624
+ return usage("Use /dump to copy the session to clipboard.", runtime);
625
+ }
626
+ const filePath = await runtime.session.exportToHtml(outputPath, useUserThemes);
622
627
  await runtime.output(`Session exported to: ${filePath}`);
623
628
  return commandConsumed();
624
629
  } catch (err) {
@@ -1712,7 +1717,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
1712
1717
  return usage(`Failed to save pending settings: ${errorMessage(err)}`, runtime);
1713
1718
  }
1714
1719
  try {
1715
- await runtime.sessionManager.moveTo(resolvedPath);
1720
+ await runtime.session.moveSession(resolvedPath);
1716
1721
  } catch (err) {
1717
1722
  return usage(`Move failed: ${errorMessage(err)}`, runtime);
1718
1723
  }
@@ -1733,6 +1738,74 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
1733
1738
  await runtime.ctx.handleMoveCommand(command.args || undefined);
1734
1739
  },
1735
1740
  },
1741
+ {
1742
+ name: "add-dir",
1743
+ description: "Add a workspace directory to this session (multi-root)",
1744
+ acpDescription: "Add a workspace directory to this session",
1745
+ inlineHint: "<path>",
1746
+ allowArgs: true,
1747
+ handle: async (command, runtime) => {
1748
+ if (runtime.session.isStreaming) return usage("Cannot add a directory while streaming.", runtime);
1749
+ if (!command.args) return usage(formatWorkspaceDirectories(runtime, "Usage: /add-dir <path>"), runtime);
1750
+ const resolved = resolveToCwd(command.args, runtime.cwd);
1751
+ try {
1752
+ const stat = await fs.stat(resolved);
1753
+ if (!stat.isDirectory()) return usage(`Not a directory: ${resolved}`, runtime);
1754
+ } catch {
1755
+ return usage(`Directory does not exist: ${resolved}`, runtime);
1756
+ }
1757
+ let added: string | null;
1758
+ try {
1759
+ added = await runtime.sessionManager.addWorkspaceDirectory(resolved);
1760
+ } catch (err) {
1761
+ return usage(errorMessage(err), runtime);
1762
+ }
1763
+ if (added === null) {
1764
+ await runtime.output(`Already in the workspace: ${resolved}`);
1765
+ return commandConsumed();
1766
+ }
1767
+ await runtime.session.refreshBaseSystemPrompt();
1768
+ await runtime.output(formatWorkspaceDirectories(runtime, `Added ${added}.`));
1769
+ return commandConsumed();
1770
+ },
1771
+ },
1772
+ {
1773
+ name: "remove-dir",
1774
+ description: "Remove a workspace directory from this session",
1775
+ acpDescription: "Remove a workspace directory from this session",
1776
+ inlineHint: "<path>",
1777
+ allowArgs: true,
1778
+ handle: async (command, runtime) => {
1779
+ if (runtime.session.isStreaming) return usage("Cannot remove a directory while streaming.", runtime);
1780
+ if (!command.args) return usage("Usage: /remove-dir <path>", runtime);
1781
+ const resolved = resolveToCwd(command.args, runtime.cwd);
1782
+ if (resolved === path.resolve(runtime.cwd)) {
1783
+ return usage("Cannot remove the working directory; use /move to change it.", runtime);
1784
+ }
1785
+ let removed: string | null;
1786
+ try {
1787
+ removed = await runtime.sessionManager.removeWorkspaceDirectory(resolved);
1788
+ } catch (err) {
1789
+ return usage(errorMessage(err), runtime);
1790
+ }
1791
+ if (removed === null) {
1792
+ await runtime.output(`Not a workspace directory: ${resolved}`);
1793
+ return commandConsumed();
1794
+ }
1795
+ await runtime.session.refreshBaseSystemPrompt();
1796
+ await runtime.output(formatWorkspaceDirectories(runtime, `Removed ${removed}.`));
1797
+ return commandConsumed();
1798
+ },
1799
+ },
1800
+ {
1801
+ name: "dirs",
1802
+ description: "List this session's workspace directories",
1803
+ acpDescription: "List this session's workspace directories",
1804
+ handle: async (_command, runtime) => {
1805
+ await runtime.output(formatWorkspaceDirectories(runtime));
1806
+ return commandConsumed();
1807
+ },
1808
+ },
1736
1809
  {
1737
1810
  name: "exit",
1738
1811
  description: "Exit the application",
@@ -2317,6 +2390,14 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
2317
2390
  if (prompt) return { prompt };
2318
2391
  },
2319
2392
  },
2393
+ {
2394
+ name: "live",
2395
+ description: "Start Codex-backed realtime voice mode",
2396
+ handleTui: async (_command, runtime) => {
2397
+ runtime.ctx.editor.setText("");
2398
+ await runtime.ctx.handleLiveCommand();
2399
+ },
2400
+ },
2320
2401
  {
2321
2402
  name: "pause",
2322
2403
  description: "Freeze all agents (main, subagents, advisor) until resumed",
@@ -12,6 +12,14 @@ function formatProviderName(provider: string): string {
12
12
  .join(" ");
13
13
  }
14
14
 
15
+ function formatWindowSuffix(label: string, windowLabel: string | undefined): string {
16
+ if (!windowLabel) return "";
17
+ const normalizedLabel = label.toLowerCase();
18
+ const normalizedWindow = windowLabel.toLowerCase();
19
+ if (normalizedWindow === "quota window" || normalizedLabel.includes(normalizedWindow)) return "";
20
+ return ` — ${windowLabel}`;
21
+ }
22
+
15
23
  function formatUsageAmount(limit: UsageLimit): string {
16
24
  const amount = limit.amount;
17
25
  const used = amount.used ?? (amount.usedFraction !== undefined ? amount.usedFraction * 100 : undefined);
@@ -55,6 +63,7 @@ function renderUsageReports(
55
63
  reports: UsageReport[],
56
64
  nowMs: number,
57
65
  resolveActiveAccount?: (provider: string) => OAuthAccountIdentity | undefined,
66
+ usageModelSelectors: readonly string[] = [],
58
67
  ): string {
59
68
  const latestFetchedAt = Math.max(...reports.map(report => report.fetchedAt ?? 0));
60
69
  const lines = [`Usage${latestFetchedAt ? ` (${formatDuration(nowMs - latestFetchedAt)} ago)` : ""}`];
@@ -69,6 +78,11 @@ function renderUsageReports(
69
78
  left.localeCompare(right),
70
79
  )) {
71
80
  lines.push("", formatProviderName(provider));
81
+ const reportingModels = usageModelSelectors.filter(selector => selector.startsWith(`${provider}/`));
82
+ if (reportingModels.length > 0) {
83
+ lines.push(" Models with usage data");
84
+ for (const selector of reportingModels) lines.push(` ${sanitizeText(selector)}`);
85
+ }
72
86
  const activeAccount = resolveActiveAccount?.(provider);
73
87
  // Provider-wide disclaimers render once per provider, not per limit.
74
88
  const providerNotes = [...new Set(providerReports.flatMap(report => report.notes ?? []))];
@@ -118,7 +132,7 @@ function renderUsageReports(
118
132
  limit.scope.tier && !limit.label.toLowerCase().includes(limit.scope.tier.toLowerCase())
119
133
  ? ` (${limit.scope.tier})`
120
134
  : "";
121
- lines.push(`- ${limit.label}${tier}${window ? ` — ${window}` : ""}`);
135
+ lines.push(`- ${limit.label}${tier}${formatWindowSuffix(limit.label, window)}`);
122
136
  lines.push(
123
137
  ` ${formatUsageReportAccount(report, limit, index)}: ${formatUsageAmount(limit)}${inUse ? " ← in use by this session" : ""}`,
124
138
  );
@@ -146,6 +160,7 @@ function renderUsageReports(
146
160
  export async function buildUsageReportText(runtime: SlashCommandRuntime): Promise<string> {
147
161
  const provider = runtime.session as SlashCommandRuntime["session"] & {
148
162
  fetchUsageReports?: () => Promise<UsageReport[] | null>;
163
+ getUsageReportingModelSelectors?: (reports: readonly UsageReport[]) => string[];
149
164
  };
150
165
  if (provider.fetchUsageReports) {
151
166
  const reports = await provider.fetchUsageReports();
@@ -157,8 +172,12 @@ export async function buildUsageReportText(runtime: SlashCommandRuntime): Promis
157
172
  runtime.session.sessionId,
158
173
  )
159
174
  : undefined;
160
- return renderUsageReports(reports, Date.now(), providerId =>
161
- providerId === currentProvider ? activeAccount : undefined,
175
+ const usageModelSelectors = provider.getUsageReportingModelSelectors?.(reports) ?? [];
176
+ return renderUsageReports(
177
+ reports,
178
+ Date.now(),
179
+ providerId => (providerId === currentProvider ? activeAccount : undefined),
180
+ usageModelSelectors,
162
181
  );
163
182
  }
164
183
  }
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import * as os from "node:os";
6
+ import * as path from "node:path";
6
7
  import type { AgentTool } from "@oh-my-pi/pi-agent-core";
7
8
  import type { ToolExample, TSchema } from "@oh-my-pi/pi-ai";
8
9
  import { renderToolInventory } from "@oh-my-pi/pi-ai/dialect";
@@ -466,6 +467,8 @@ export interface BuildSystemPromptOptions {
466
467
  skillsSettings?: SkillsSettings;
467
468
  /** Working directory. Default: getProjectDir() */
468
469
  cwd?: string;
470
+ /** Additional workspace directories beyond cwd (multi-root), absolute. Injected into the project prompt. */
471
+ additionalWorkspaceRoots?: string[];
469
472
  /** Pre-loaded context files (skips discovery if provided). */
470
473
  contextFiles?: Array<{ path: string; content: string; depth?: number }>;
471
474
  /** Skills provided directly to system prompt construction. */
@@ -535,6 +538,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
535
538
  skillsSettings,
536
539
  toolNames: providedToolNames,
537
540
  cwd,
541
+ additionalWorkspaceRoots = [],
538
542
  contextFiles: providedContextFiles,
539
543
  skills: providedSkills,
540
544
  rules,
@@ -619,23 +623,42 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
619
623
  const systemPromptCustomizationPromise: Promise<string | null> = callerControlsCustomPrompt
620
624
  ? Promise.resolve(null)
621
625
  : logger.time("loadSystemPromptFiles", loadSystemPromptFiles, { cwd: resolvedCwd });
622
- const contextFilesPromise = providedContextFiles
623
- ? Promise.resolve(providedContextFiles)
624
- : logger.time("loadProjectContextFiles", loadProjectContextFiles, { cwd: resolvedCwd });
625
- const workspaceTreePromise =
626
- providedWorkspaceTree !== undefined
627
- ? Promise.resolve(providedWorkspaceTree)
628
- : includeWorkspaceTree
629
- ? logger.time("buildWorkspaceTree", () =>
630
- buildWorkspaceTree(resolvedCwd, { timeoutMs: SYSTEM_PROMPT_PREP_TIMEOUT_MS }),
631
- )
632
- : Promise.resolve({
633
- rootPath: resolvedCwd,
634
- rendered: "",
635
- truncated: false,
636
- totalLines: 0,
637
- agentsMdFiles: [],
638
- });
626
+ const contextFilesPromise = (async () => {
627
+ const primary = providedContextFiles
628
+ ? providedContextFiles
629
+ : await logger.time("loadProjectContextFiles", loadProjectContextFiles, { cwd: resolvedCwd });
630
+ // Also discover context files (AGENTS.md, rules, etc.) for each additional workspace root.
631
+ const additionalRoots = additionalWorkspaceRoots.filter(d => path.resolve(d) !== path.resolve(resolvedCwd));
632
+ if (additionalRoots.length === 0) return primary;
633
+ const extra = await Promise.all(
634
+ additionalRoots.map(root => loadProjectContextFiles({ cwd: root }).catch(() => [])),
635
+ );
636
+ return dedupeExactContextFiles([...primary, ...extra.flat()]);
637
+ })();
638
+ const additionalRootsForTree = additionalWorkspaceRoots.filter(d => path.resolve(d) !== path.resolve(resolvedCwd));
639
+ const workspaceTreePromise = (async () => {
640
+ const primary =
641
+ providedWorkspaceTree !== undefined
642
+ ? await Promise.resolve(providedWorkspaceTree)
643
+ : includeWorkspaceTree
644
+ ? await logger.time("buildWorkspaceTree", () =>
645
+ buildWorkspaceTree(resolvedCwd, { timeoutMs: SYSTEM_PROMPT_PREP_TIMEOUT_MS }),
646
+ )
647
+ : { rootPath: resolvedCwd, rendered: "", truncated: false, totalLines: 0, agentsMdFiles: [] };
648
+ if (additionalRootsForTree.length === 0 || !includeWorkspaceTree) return primary;
649
+ const extraTrees = await Promise.all(
650
+ additionalRootsForTree.map(root =>
651
+ buildWorkspaceTree(root, { timeoutMs: SYSTEM_PROMPT_PREP_TIMEOUT_MS }).catch(() => ({
652
+ rootPath: root,
653
+ rendered: "",
654
+ truncated: false,
655
+ totalLines: 0,
656
+ agentsMdFiles: [],
657
+ })),
658
+ ),
659
+ );
660
+ return { ...primary, agentsMdFiles: [...primary.agentsMdFiles, ...extraTrees.flatMap(t => t.agentsMdFiles)] };
661
+ })();
639
662
  const skillsPromise: Promise<readonly Skill[]> =
640
663
  providedSkills !== undefined
641
664
  ? Promise.resolve(providedSkills)
@@ -794,6 +817,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
794
817
  date,
795
818
  dateTime,
796
819
  cwd: promptCwd,
820
+ additionalWorkspaceRoots: additionalWorkspaceRoots.filter(d => path.resolve(d) !== path.resolve(resolvedCwd)),
797
821
  model: includeModelInPrompt ? (model ?? "") : "",
798
822
  useCodexTaskPrompt: usesCodexTaskPrompt(model),
799
823
  personality: personality === "none" ? "" : PERSONALITY_SPECS[personality].trim(),