@oh-my-pi/pi-coding-agent 16.1.22 → 16.2.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 (276) hide show
  1. package/CHANGELOG.md +99 -1
  2. package/dist/cli.js +4387 -4164
  3. package/dist/types/advisor/__tests__/emission-guard.test.d.ts +1 -0
  4. package/dist/types/advisor/emission-guard.d.ts +73 -0
  5. package/dist/types/advisor/index.d.ts +1 -0
  6. package/dist/types/advisor/runtime.d.ts +7 -0
  7. package/dist/types/advisor/watchdog.d.ts +2 -0
  8. package/dist/types/cli/flag-tables.d.ts +1 -0
  9. package/dist/types/cli/gallery-fixtures/search.d.ts +1 -1
  10. package/dist/types/cli/gc-cli.d.ts +58 -0
  11. package/dist/types/collab/display-name.d.ts +3 -0
  12. package/dist/types/collab/host.d.ts +0 -2
  13. package/dist/types/commands/gc.d.ts +37 -0
  14. package/dist/types/commands/worktree.d.ts +0 -3
  15. package/dist/types/config/inline-tool-descriptors-mode.d.ts +13 -0
  16. package/dist/types/config/model-discovery.d.ts +6 -1
  17. package/dist/types/config/model-registry.d.ts +6 -2
  18. package/dist/types/config/model-resolver.d.ts +12 -0
  19. package/dist/types/config/models-config-schema.d.ts +29 -2
  20. package/dist/types/config/models-config.d.ts +22 -1
  21. package/dist/types/config/settings-schema.d.ts +145 -21
  22. package/dist/types/config/settings.d.ts +13 -0
  23. package/dist/types/dap/config.d.ts +1 -1
  24. package/dist/types/edit/hashline/filesystem.d.ts +4 -2
  25. package/dist/types/edit/renderer.d.ts +4 -0
  26. package/dist/types/extensibility/extensions/types.d.ts +17 -17
  27. package/dist/types/extensibility/hooks/types.d.ts +10 -10
  28. package/dist/types/extensibility/plugins/marketplace/types.d.ts +1 -0
  29. package/dist/types/internal-urls/__tests__/ssh-protocol.test.d.ts +1 -0
  30. package/dist/types/internal-urls/index.d.ts +1 -0
  31. package/dist/types/internal-urls/registry-helpers.d.ts +2 -0
  32. package/dist/types/internal-urls/router.d.ts +1 -1
  33. package/dist/types/internal-urls/ssh-protocol.d.ts +10 -0
  34. package/dist/types/internal-urls/types.d.ts +19 -2
  35. package/dist/types/irc/bus.d.ts +6 -0
  36. package/dist/types/mcp/transports/stdio.d.ts +25 -1
  37. package/dist/types/modes/components/__tests__/move-overlay.test.d.ts +1 -0
  38. package/dist/types/modes/components/custom-editor.d.ts +7 -0
  39. package/dist/types/modes/components/move-overlay.d.ts +23 -0
  40. package/dist/types/modes/components/plugin-selector.d.ts +2 -1
  41. package/dist/types/modes/components/queue-mode-selector.d.ts +2 -1
  42. package/dist/types/modes/components/select-list-mouse-routing.d.ts +2 -0
  43. package/dist/types/modes/components/settings-defs.d.ts +4 -1
  44. package/dist/types/modes/components/settings-selector.d.ts +2 -0
  45. package/dist/types/modes/components/show-images-selector.d.ts +2 -1
  46. package/dist/types/modes/components/status-line/component.d.ts +2 -0
  47. package/dist/types/modes/components/status-line/types.d.ts +2 -0
  48. package/dist/types/modes/components/theme-selector.d.ts +2 -1
  49. package/dist/types/modes/components/thinking-selector.d.ts +2 -1
  50. package/dist/types/modes/controllers/command-controller.d.ts +10 -1
  51. package/dist/types/modes/controllers/streaming-reveal.d.ts +6 -0
  52. package/dist/types/modes/interactive-mode.d.ts +10 -1
  53. package/dist/types/modes/internal-url-autocomplete.d.ts +1 -1
  54. package/dist/types/modes/running-subagent-badge.d.ts +6 -0
  55. package/dist/types/modes/theme/mermaid-rendering.test.d.ts +1 -0
  56. package/dist/types/modes/theme/theme.d.ts +2 -1
  57. package/dist/types/modes/types.d.ts +9 -1
  58. package/dist/types/sdk.d.ts +2 -2
  59. package/dist/types/session/agent-session.d.ts +2 -1
  60. package/dist/types/session/session-listing.d.ts +10 -1
  61. package/dist/types/session/session-manager.d.ts +13 -0
  62. package/dist/types/slash-commands/builtin-registry.d.ts +1 -1
  63. package/dist/types/ssh/__tests__/connection-manager-args.test.d.ts +1 -0
  64. package/dist/types/ssh/__tests__/file-transfer-posix-guard.test.d.ts +1 -0
  65. package/dist/types/ssh/connection-manager.d.ts +2 -0
  66. package/dist/types/ssh/file-transfer.d.ts +79 -0
  67. package/dist/types/ssh/utils.d.ts +6 -0
  68. package/dist/types/system-prompt.d.ts +5 -0
  69. package/dist/types/task/executor.d.ts +16 -0
  70. package/dist/types/tiny/text.d.ts +1 -1
  71. package/dist/types/tools/builtin-names.d.ts +5 -1
  72. package/dist/types/tools/{find.d.ts → glob.d.ts} +15 -15
  73. package/dist/types/tools/{search.d.ts → grep.d.ts} +14 -14
  74. package/dist/types/tools/index.d.ts +3 -3
  75. package/dist/types/tools/path-utils.d.ts +29 -0
  76. package/dist/types/tools/plan-mode-guard.d.ts +7 -0
  77. package/dist/types/tools/read.d.ts +2 -2
  78. package/dist/types/tools/render-utils.d.ts +8 -0
  79. package/dist/types/tools/renderers.d.ts +11 -0
  80. package/dist/types/tools/ssh.d.ts +2 -0
  81. package/dist/types/tools/todo.d.ts +0 -16
  82. package/dist/types/tools/write.d.ts +2 -2
  83. package/dist/types/utils/active-repo-context.d.ts +8 -0
  84. package/dist/types/utils/image-resize.d.ts +1 -0
  85. package/dist/types/utils/markit-cache.d.ts +23 -0
  86. package/dist/types/utils/markit.d.ts +5 -1
  87. package/dist/types/utils/prompt-path.d.ts +1 -0
  88. package/dist/types/web/search/providers/duckduckgo.d.ts +14 -0
  89. package/dist/types/web/search/providers/firecrawl.d.ts +28 -0
  90. package/dist/types/web/search/providers/tinyfish.d.ts +29 -0
  91. package/dist/types/web/search/providers/xai.d.ts +13 -0
  92. package/dist/types/web/search/types.d.ts +18 -2
  93. package/package.json +30 -15
  94. package/scripts/bench-guard.ts +1 -1
  95. package/scripts/build-binary.ts +9 -9
  96. package/scripts/bundle-dist.ts +2 -2
  97. package/src/advisor/__tests__/advisor.test.ts +40 -4
  98. package/src/advisor/__tests__/emission-guard.test.ts +147 -0
  99. package/src/advisor/advise-tool.ts +1 -1
  100. package/src/advisor/emission-guard.ts +172 -0
  101. package/src/advisor/index.ts +1 -0
  102. package/src/advisor/runtime.ts +11 -0
  103. package/src/advisor/watchdog.ts +12 -1
  104. package/src/cli/args.ts +5 -2
  105. package/src/cli/auth-broker-cli.ts +17 -0
  106. package/src/cli/config-cli.ts +4 -0
  107. package/src/cli/flag-tables.ts +7 -4
  108. package/src/cli/gallery-cli.ts +14 -2
  109. package/src/cli/gallery-fixtures/edit.ts +60 -0
  110. package/src/cli/gallery-fixtures/fs.ts +17 -17
  111. package/src/cli/gallery-fixtures/search.ts +4 -4
  112. package/src/cli/gc-cli.ts +939 -0
  113. package/src/cli/usage-cli.ts +20 -1
  114. package/src/cli/web-search-cli.ts +1 -1
  115. package/src/cli-commands.ts +1 -0
  116. package/src/collab/display-name.ts +13 -0
  117. package/src/collab/guest.ts +5 -1
  118. package/src/collab/host.ts +2 -13
  119. package/src/commands/gc.ts +46 -0
  120. package/src/commands/worktree.ts +6 -0
  121. package/src/config/inline-tool-descriptors-mode.ts +27 -0
  122. package/src/config/model-discovery.ts +77 -8
  123. package/src/config/model-registry.ts +89 -11
  124. package/src/config/model-resolver.ts +39 -1
  125. package/src/config/models-config-schema.ts +41 -5
  126. package/src/config/models-config.ts +4 -1
  127. package/src/config/settings-schema.ts +130 -27
  128. package/src/config/settings.ts +216 -7
  129. package/src/cursor.ts +1 -1
  130. package/src/dap/config.ts +152 -8
  131. package/src/dap/session.ts +1 -1
  132. package/src/discovery/helpers.ts +3 -1
  133. package/src/edit/hashline/diff.ts +14 -3
  134. package/src/edit/hashline/execute.ts +42 -6
  135. package/src/edit/hashline/filesystem.ts +49 -8
  136. package/src/edit/index.ts +1 -0
  137. package/src/edit/modes/patch.ts +11 -1
  138. package/src/edit/renderer.ts +140 -13
  139. package/src/eval/__tests__/agent-bridge.test.ts +101 -0
  140. package/src/eval/__tests__/julia-prelude.test.ts +18 -0
  141. package/src/eval/agent-bridge.ts +26 -3
  142. package/src/eval/jl/runner.jl +7 -1
  143. package/src/eval/js/tool-bridge.ts +2 -2
  144. package/src/export/html/index.ts +1 -1
  145. package/src/export/html/template.js +3 -1
  146. package/src/export/html/tool-views.generated.js +20 -20
  147. package/src/extensibility/extensions/types.ts +22 -22
  148. package/src/extensibility/hooks/types.ts +11 -11
  149. package/src/extensibility/plugins/legacy-pi-bundled-keys.ts +10 -3
  150. package/src/extensibility/plugins/legacy-pi-bundled-registry.ts +31 -10
  151. package/src/extensibility/plugins/marketplace/manager.ts +22 -0
  152. package/src/extensibility/plugins/marketplace/types.ts +1 -0
  153. package/src/internal-urls/__tests__/ssh-protocol.test.ts +331 -0
  154. package/src/internal-urls/docs-index.generated.txt +2 -2
  155. package/src/internal-urls/docs-index.ts +2 -3
  156. package/src/internal-urls/index.ts +1 -0
  157. package/src/internal-urls/registry-helpers.ts +19 -4
  158. package/src/internal-urls/router.ts +5 -3
  159. package/src/internal-urls/ssh-protocol.ts +367 -0
  160. package/src/internal-urls/types.ts +19 -2
  161. package/src/irc/bus.ts +11 -3
  162. package/src/lsp/index.ts +8 -1
  163. package/src/mcp/oauth-discovery.ts +20 -20
  164. package/src/mcp/tool-bridge.ts +32 -2
  165. package/src/mcp/transports/stdio.test.ts +20 -3
  166. package/src/mcp/transports/stdio.ts +45 -14
  167. package/src/memories/index.ts +1 -1
  168. package/src/modes/acp/acp-event-mapper.ts +2 -2
  169. package/src/modes/components/__tests__/move-overlay.test.ts +166 -0
  170. package/src/modes/components/agent-hub.ts +3 -0
  171. package/src/modes/components/agent-transcript-viewer.ts +9 -7
  172. package/src/modes/components/custom-editor.ts +90 -5
  173. package/src/modes/components/move-overlay.ts +282 -0
  174. package/src/modes/components/plan-review-overlay.ts +35 -35
  175. package/src/modes/components/plugin-selector.ts +6 -1
  176. package/src/modes/components/queue-mode-selector.ts +6 -1
  177. package/src/modes/components/select-list-mouse-routing.ts +35 -0
  178. package/src/modes/components/session-selector.ts +11 -10
  179. package/src/modes/components/settings-defs.ts +14 -1
  180. package/src/modes/components/settings-selector.ts +196 -29
  181. package/src/modes/components/show-images-selector.ts +6 -1
  182. package/src/modes/components/status-line/component.ts +108 -28
  183. package/src/modes/components/status-line/segments.ts +5 -1
  184. package/src/modes/components/status-line/types.ts +2 -0
  185. package/src/modes/components/theme-selector.ts +6 -1
  186. package/src/modes/components/thinking-selector.ts +6 -1
  187. package/src/modes/components/tool-execution.ts +25 -9
  188. package/src/modes/components/tree-selector.ts +5 -5
  189. package/src/modes/controllers/command-controller.ts +140 -47
  190. package/src/modes/controllers/event-controller.ts +59 -3
  191. package/src/modes/controllers/input-controller.ts +70 -4
  192. package/src/modes/controllers/selector-controller.ts +15 -2
  193. package/src/modes/controllers/streaming-reveal.ts +17 -0
  194. package/src/modes/controllers/tool-args-reveal.ts +1 -1
  195. package/src/modes/interactive-mode.ts +142 -59
  196. package/src/modes/internal-url-autocomplete.ts +17 -2
  197. package/src/modes/prompt-action-autocomplete.ts +3 -1
  198. package/src/modes/running-subagent-badge.ts +13 -0
  199. package/src/modes/setup-wizard/scenes/glyph.ts +2 -13
  200. package/src/modes/setup-wizard/scenes/providers.ts +2 -1
  201. package/src/modes/setup-wizard/scenes/theme.ts +6 -12
  202. package/src/modes/setup-wizard/scenes/web-search.ts +8 -13
  203. package/src/modes/setup-wizard/wizard-overlay.ts +6 -5
  204. package/src/modes/theme/mermaid-rendering.test.ts +53 -0
  205. package/src/modes/theme/theme.ts +42 -15
  206. package/src/modes/types.ts +9 -1
  207. package/src/modes/utils/interactive-context-helpers.ts +1 -1
  208. package/src/priority.json +15 -0
  209. package/src/prompts/advisor/active-repo-watchdog.md +6 -0
  210. package/src/prompts/advisor/system.md +21 -7
  211. package/src/prompts/agents/designer.md +1 -1
  212. package/src/prompts/agents/explore.md +1 -1
  213. package/src/prompts/agents/librarian.md +2 -2
  214. package/src/prompts/agents/plan.md +2 -2
  215. package/src/prompts/agents/reviewer.md +1 -1
  216. package/src/prompts/agents/task.md +2 -2
  217. package/src/prompts/system/active-repo-context.md +4 -0
  218. package/src/prompts/system/gemini-tool-call-reminder.md +9 -0
  219. package/src/prompts/system/plan-mode-active.md +12 -3
  220. package/src/prompts/system/project-prompt.md +2 -2
  221. package/src/prompts/system/system-prompt.md +8 -6
  222. package/src/prompts/tools/bash.md +2 -2
  223. package/src/prompts/tools/checkpoint.md +1 -1
  224. package/src/prompts/tools/{find.md → glob.md} +1 -1
  225. package/src/prompts/tools/{search.md → grep.md} +3 -3
  226. package/src/prompts/tools/read.md +4 -2
  227. package/src/sdk.ts +98 -29
  228. package/src/session/agent-session.ts +828 -191
  229. package/src/session/session-history-format.ts +2 -2
  230. package/src/session/session-listing.ts +35 -2
  231. package/src/session/session-manager.ts +46 -0
  232. package/src/slash-commands/builtin-registry.ts +158 -22
  233. package/src/slash-commands/helpers/usage-report.ts +23 -2
  234. package/src/ssh/__tests__/connection-manager-args.test.ts +69 -0
  235. package/src/ssh/__tests__/file-transfer-posix-guard.test.ts +68 -0
  236. package/src/ssh/connection-manager.ts +12 -15
  237. package/src/ssh/file-transfer.ts +209 -0
  238. package/src/ssh/utils.ts +24 -0
  239. package/src/system-prompt.ts +60 -28
  240. package/src/task/executor.ts +96 -36
  241. package/src/task/index.ts +3 -3
  242. package/src/task/render.ts +14 -13
  243. package/src/task/worktree.ts +38 -1
  244. package/src/tiny/text.ts +49 -4
  245. package/src/tiny/worker.ts +3 -3
  246. package/src/tools/acp-bridge.ts +6 -1
  247. package/src/tools/bash.ts +2 -2
  248. package/src/tools/builtin-names.ts +26 -2
  249. package/src/tools/{find.ts → glob.ts} +48 -42
  250. package/src/tools/{search.ts → grep.ts} +311 -129
  251. package/src/tools/index.ts +13 -14
  252. package/src/tools/irc.ts +6 -2
  253. package/src/tools/path-utils.ts +64 -1
  254. package/src/tools/plan-mode-guard.ts +26 -13
  255. package/src/tools/read.ts +35 -6
  256. package/src/tools/render-utils.ts +14 -0
  257. package/src/tools/renderers.ts +15 -4
  258. package/src/tools/ssh.ts +17 -2
  259. package/src/tools/todo.ts +4 -26
  260. package/src/tools/write.ts +25 -9
  261. package/src/utils/active-repo-context.ts +143 -0
  262. package/src/utils/edit-mode.ts +19 -2
  263. package/src/utils/image-resize.ts +88 -7
  264. package/src/utils/lang-from-path.ts +3 -3
  265. package/src/utils/markit-cache.ts +166 -0
  266. package/src/utils/markit.ts +86 -18
  267. package/src/utils/prompt-path.ts +3 -0
  268. package/src/utils/shell-snapshot.ts +1 -1
  269. package/src/utils/title-generator.ts +1 -1
  270. package/src/web/search/provider.ts +54 -34
  271. package/src/web/search/providers/duckduckgo.ts +140 -0
  272. package/src/web/search/providers/firecrawl.ts +144 -0
  273. package/src/web/search/providers/tinyfish.ts +159 -0
  274. package/src/web/search/providers/xai.ts +292 -0
  275. package/src/web/search/providers/zai.ts +142 -56
  276. package/src/web/search/types.ts +6 -2
@@ -326,7 +326,26 @@ function formatAccountHeader(
326
326
  const planType = report.metadata?.planType;
327
327
  if (typeof planType === "string" && planType) header += chalk.dim(` · plan: ${planType}`);
328
328
  const savedResets = report.resetCredits?.availableCount ?? 0;
329
- if (savedResets > 0) header += chalk.cyan(` · ✦ ${savedResets} saved reset${savedResets === 1 ? "" : "s"}`);
329
+ if (savedResets > 0) {
330
+ header += chalk.cyan(` · ✦ ${savedResets} saved reset${savedResets === 1 ? "" : "s"}`);
331
+ const credits = report.resetCredits?.credits;
332
+ if (credits) {
333
+ const expiries = credits
334
+ .filter(c => c.expiresAt)
335
+ .map(c => ({ date: c.expiresAt!, ms: Date.parse(c.expiresAt!) }))
336
+ .filter(c => !Number.isNaN(c.ms))
337
+ .sort((a, b) => a.ms - b.ms);
338
+ const upcoming = expiries.find(c => c.ms > nowMs);
339
+ if (upcoming) {
340
+ header += chalk.dim(
341
+ ` · soonest expires in ${formatDuration(upcoming.ms - nowMs)} (${upcoming.date.slice(0, 10)})`,
342
+ );
343
+ } else {
344
+ const lastExpired = expiries.at(-1);
345
+ if (lastExpired) header += chalk.dim(` · expired (${lastExpired.date.slice(0, 10)})`);
346
+ }
347
+ }
348
+ }
330
349
  if (report.fetchedAt && nowMs - report.fetchedAt > 90_000) {
331
350
  header += chalk.dim(` · fetched ${formatDuration(nowMs - report.fetchedAt)} ago`);
332
351
  }
@@ -120,7 +120,7 @@ ${chalk.bold("Arguments:")}
120
120
 
121
121
  ${chalk.bold("Options:")}
122
122
  --provider <name> Provider: ${PROVIDERS.join(", ")}
123
- --recency <value> Recency filter (Brave/Perplexity): ${RECENCY_OPTIONS.join(", ")}
123
+ --recency <value> Recency filter (when supported): ${RECENCY_OPTIONS.join(", ")}
124
124
  -l, --limit <n> Max results to return
125
125
  --compact Render condensed output
126
126
  -h, --help Show this help
@@ -23,6 +23,7 @@ export const commands: CommandEntry[] = [
23
23
  { name: "__complete", load: () => import("./commands/complete").then(m => m.default) },
24
24
  { name: "config", load: () => import("./commands/config").then(m => m.default) },
25
25
  { name: "dry-balance", load: () => import("./commands/dry-balance").then(m => m.default) },
26
+ { name: "gc", load: () => import("./commands/gc").then(m => m.default) },
26
27
  { name: "grep", load: () => import("./commands/grep").then(m => m.default) },
27
28
  { name: "gallery", load: () => import("./commands/gallery").then(m => m.default) },
28
29
  { name: "grievances", load: () => import("./commands/grievances").then(m => m.default) },
@@ -0,0 +1,13 @@
1
+ import * as os from "node:os";
2
+ import type { InteractiveModeContext } from "../modes/types";
3
+
4
+ /** Display name for this process's user in collab sessions. */
5
+ export function collabDisplayName(ctx: InteractiveModeContext): string {
6
+ const configured = (ctx.settings.get("collab.displayName") ?? "").trim();
7
+ if (configured) return configured;
8
+ try {
9
+ return os.userInfo().username;
10
+ } catch {
11
+ return "anonymous";
12
+ }
13
+ }
@@ -24,7 +24,7 @@ import type { SessionEntry } from "../session/session-entries";
24
24
  import { shouldDisableReasoning, toReasoningEffort } from "../thinking";
25
25
  import { setSessionTerminalTitle } from "../utils/title-generator";
26
26
  import { importRoomKey } from "./crypto";
27
- import { collabDisplayName } from "./host";
27
+ import { collabDisplayName } from "./display-name";
28
28
  import {
29
29
  type AgentSnapshot,
30
30
  COLLAB_PROTO,
@@ -276,6 +276,7 @@ export class CollabGuestLink {
276
276
  }
277
277
 
278
278
  this.#ctx.collabGuest = this;
279
+ this.#ctx.syncRunningSubagentBadge();
279
280
  }
280
281
 
281
282
  /** User-initiated leave (or post-disconnect cleanup): restore the previous session. */
@@ -357,6 +358,7 @@ export class CollabGuestLink {
357
358
  this.#applyHostState(pending.state);
358
359
  this.#ctx.resetObserverRegistry();
359
360
  this.#applyAgentSnapshots(pending.agents);
361
+ this.#ctx.syncRunningSubagentBadge();
360
362
  this.#assistantStreamSynced = false;
361
363
  setSessionTerminalTitle(pending.state.sessionName ?? pending.header.title, pending.state.cwd);
362
364
  this.#ctx.chatContainer.clear();
@@ -440,6 +442,7 @@ export class CollabGuestLink {
440
442
  break;
441
443
  case "agents":
442
444
  this.#applyAgentSnapshots(frame.agents);
445
+ this.#ctx.syncRunningSubagentBadge();
443
446
  break;
444
447
  case "transcript": {
445
448
  const resolve = this.#pendingTranscripts.get(frame.reqId);
@@ -573,6 +576,7 @@ export class CollabGuestLink {
573
576
  this.#ctx.statusLine.setCollabStatus(null);
574
577
  this.#flushPendingTranscripts();
575
578
  this.#clearAgentMirror();
579
+ this.#ctx.syncRunningSubagentBadge();
576
580
  this.#ctx.resetObserverRegistry();
577
581
  this.#clearTransientUi();
578
582
  // Replica file stays on disk: it is a valid session file outside the
@@ -11,7 +11,6 @@
11
11
 
12
12
  import { timingSafeEqual } from "node:crypto";
13
13
  import * as fs from "node:fs/promises";
14
- import * as os from "node:os";
15
14
  import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai";
16
15
  import { logger } from "@oh-my-pi/pi-utils";
17
16
  import type { BusChannel, AgentEvent as WireAgentEvent, SessionEntry as WireSessionEntry } from "@oh-my-pi/pi-wire";
@@ -21,8 +20,9 @@ import { type AgentRef, AgentRegistry } from "../registry/agent-registry";
21
20
  import type { AgentSessionEvent } from "../session/agent-session";
22
21
  import { stripImagesFromMessage, USER_INTERRUPT_LABEL } from "../session/messages";
23
22
  import type { SessionEntry as StoredSessionEntry } from "../session/session-entries";
24
- import { TASK_SUBAGENT_LIFECYCLE_CHANNEL, TASK_SUBAGENT_PROGRESS_CHANNEL } from "../task";
23
+ import { TASK_SUBAGENT_LIFECYCLE_CHANNEL, TASK_SUBAGENT_PROGRESS_CHANNEL } from "../task/types";
25
24
  import { generateRoomKey, generateWriteToken, importRoomKey } from "./crypto";
25
+ import { collabDisplayName } from "./display-name";
26
26
  import {
27
27
  type AgentSnapshot,
28
28
  COLLAB_PROMPT_MESSAGE_TYPE,
@@ -102,17 +102,6 @@ const TRANSCRIPT_READ_CAP = 4 * 1024 * 1024;
102
102
  */
103
103
  const SNAPSHOT_CHUNK_BYTES = 512 * 1024;
104
104
 
105
- /** Display name for this process's user in collab sessions. */
106
- export function collabDisplayName(ctx: InteractiveModeContext): string {
107
- const configured = (ctx.settings.get("collab.displayName") ?? "").trim();
108
- if (configured) return configured;
109
- try {
110
- return os.userInfo().username;
111
- } catch {
112
- return "anonymous";
113
- }
114
- }
115
-
116
105
  export class CollabHost {
117
106
  #ctx: InteractiveModeContext;
118
107
  #socket: CollabSocket | null = null;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Run on-disk storage maintenance.
3
+ */
4
+ import { Command, Flags } from "@oh-my-pi/pi-utils/cli";
5
+ import { collectGcErrors, type GcCommandArgs, runGcCommand } from "../cli/gc-cli";
6
+
7
+ export default class Gc extends Command {
8
+ static description = "Run storage garbage collection";
9
+
10
+ static flags = {
11
+ apply: Flags.boolean({ description: "Apply changes (default is dry-run)" }),
12
+ json: Flags.boolean({ description: "Output JSON" }),
13
+ "agent-dir": Flags.string({ description: "Agent directory to maintain" }),
14
+ blobs: Flags.boolean({ description: "Sweep unreferenced blobs" }),
15
+ archive: Flags.boolean({ description: "Archive cold sessions" }),
16
+ wal: Flags.boolean({ description: "Checkpoint history/model database WAL files" }),
17
+ "cold-archive-after-days": Flags.integer({ description: "Minimum session age before archiving" }),
18
+ "retain-newest-global": Flags.integer({ description: "Always keep this many newest sessions active" }),
19
+ "retain-newest-per-cwd": Flags.integer({ description: "Always keep this many newest sessions per cwd active" }),
20
+ };
21
+
22
+ async run(): Promise<void> {
23
+ const { flags } = await this.parse(Gc);
24
+ const cmd: GcCommandArgs = {
25
+ flags: {
26
+ apply: flags.apply,
27
+ json: flags.json,
28
+ agentDir: flags["agent-dir"],
29
+ blobs: flags.blobs,
30
+ archive: flags.archive,
31
+ wal: flags.wal,
32
+ coldArchiveAfterDays: flags["cold-archive-after-days"],
33
+ retainNewestGlobal: flags["retain-newest-global"],
34
+ retainNewestPerCwd: flags["retain-newest-per-cwd"],
35
+ },
36
+ };
37
+ const result = await runGcCommand(cmd);
38
+ const errors = collectGcErrors(result);
39
+ if (errors.length > 0) {
40
+ process.stderr.write(
41
+ `GC completed with ${errors.length} error${errors.length === 1 ? "" : "s"}:\n${errors.map(error => `- ${error}`).join("\n")}\n`,
42
+ );
43
+ process.exitCode = 1;
44
+ }
45
+ }
46
+ }
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * List and clean up agent-managed git worktrees under `~/.omp/wt`.
3
3
  */
4
+ import { getProjectDir } from "@oh-my-pi/pi-utils";
4
5
  import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
5
6
  import { clearWorktrees, listWorktrees } from "../cli/worktree-cli";
7
+ import { Settings } from "../config/settings";
6
8
 
7
9
  export default class Worktree extends Command {
8
10
  static description = "List or clear agent-managed git worktrees (~/.omp/wt)";
@@ -43,6 +45,10 @@ export default class Worktree extends Command {
43
45
 
44
46
  async run(): Promise<void> {
45
47
  const { args, flags } = await this.parse(Worktree);
48
+ // Load settings so the `worktree.base` override is applied before we scan
49
+ // — otherwise this command would inspect ~/.omp/wt while the agent created
50
+ // its worktrees under the configured base.
51
+ await Settings.init({ cwd: getProjectDir() });
46
52
  if (args.action === "clear") {
47
53
  await clearWorktrees({
48
54
  all: flags.all ?? false,
@@ -0,0 +1,27 @@
1
+ import { modelFamilyToken } from "@oh-my-pi/pi-catalog/identity";
2
+
3
+ /**
4
+ * Resolves whether full tool descriptors should be inlined into the system
5
+ * prompt (and stripped from provider tool schemas) for a given model and
6
+ * setting.
7
+ *
8
+ * `auto` enforces a per-model policy: inline for Gemini models, off otherwise.
9
+ * Gemini benefits from descriptors in-prompt; other providers keep them in the
10
+ * tool schemas. `on`/`off` are explicit user overrides.
11
+ *
12
+ * @param modelId Canonical model id (e.g. `gemini-3-pro`); resolve aliases via
13
+ * `ModelRegistry.getCanonicalId` before calling so `auto` classifies correctly.
14
+ */
15
+ export function shouldInlineToolDescriptors(
16
+ setting: "auto" | "on" | "off" | undefined,
17
+ modelId: string | undefined,
18
+ ): boolean {
19
+ switch (setting ?? "auto") {
20
+ case "on":
21
+ return true;
22
+ case "off":
23
+ return false;
24
+ default:
25
+ return modelId !== undefined && modelFamilyToken(modelId) === "gemini";
26
+ }
27
+ }
@@ -6,14 +6,19 @@
6
6
  * discovery lives in pi-catalog's provider-models.
7
7
  */
8
8
  import { type ApiKey, type FetchImpl, withAuth } from "@oh-my-pi/pi-ai";
9
- import type { Api, Model } from "@oh-my-pi/pi-ai/types";
9
+ import type { Api, Model, RemoteCompactionConfig } from "@oh-my-pi/pi-ai/types";
10
10
  import { buildModel } from "@oh-my-pi/pi-catalog/build";
11
11
  import {
12
12
  getBundledModelReferenceIndex,
13
13
  resolveModelReference,
14
14
  stripBracketedModelIdAffixes,
15
15
  } from "@oh-my-pi/pi-catalog/identity";
16
- import { fetchLmStudioNativeModelMetadata } from "@oh-my-pi/pi-catalog/provider-models/openai-compat";
16
+ import {
17
+ fetchLiteLLMRichModels,
18
+ fetchLmStudioNativeModelMetadata,
19
+ OPENAI_COMPAT_DISCOVERY_DEFAULT_CONTEXT_WINDOW,
20
+ OPENAI_COMPAT_DISCOVERY_DEFAULT_MAX_TOKENS,
21
+ } from "@oh-my-pi/pi-catalog/provider-models/openai-compat";
17
22
  import type { ModelSpec } from "@oh-my-pi/pi-catalog/types";
18
23
  import { isRecord } from "@oh-my-pi/pi-utils";
19
24
  import type { ProviderDiscovery } from "./models-config-schema";
@@ -27,7 +32,8 @@ import type { ProviderDiscovery } from "./models-config-schema";
27
32
  // mid-stream when models hit the cap on legitimate large tool calls (see
28
33
  // issue #1528: `write` payloads >~5KB on deepseek-v4-pro surfaced as
29
34
  // "socket connection was closed unexpectedly").
30
- export const DISCOVERY_DEFAULT_MAX_TOKENS = 32_768;
35
+ export const DISCOVERY_DEFAULT_CONTEXT_WINDOW = OPENAI_COMPAT_DISCOVERY_DEFAULT_CONTEXT_WINDOW;
36
+ export const DISCOVERY_DEFAULT_MAX_TOKENS = OPENAI_COMPAT_DISCOVERY_DEFAULT_MAX_TOKENS;
31
37
 
32
38
  const DEFAULT_OLLAMA_BASE_URL = "http://127.0.0.1:11434";
33
39
  const OLLAMA_HOST_DEFAULT_PORT = "11434";
@@ -89,6 +95,7 @@ export interface DiscoveryProviderConfig {
89
95
  baseUrl?: string;
90
96
  headers?: Record<string, string>;
91
97
  compat?: ModelSpec<Api>["compat"];
98
+ remoteCompaction?: RemoteCompactionConfig<Api>;
92
99
  discovery: ProviderDiscovery;
93
100
  optional?: boolean;
94
101
  }
@@ -209,6 +216,8 @@ export function discoverModelsByProviderType(
209
216
  return discoverOpenAIModelsList(providerConfig, ctx);
210
217
  case "proxy":
211
218
  return discoverProxyModels(providerConfig, ctx);
219
+ case "litellm":
220
+ return discoverLiteLLMModels(providerConfig, ctx);
212
221
  }
213
222
  }
214
223
 
@@ -302,7 +311,7 @@ export async function discoverOllamaModels(
302
311
  input: metadata?.input ?? ["text"],
303
312
  imageInputDecoder: "stb",
304
313
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
305
- contextWindow: metadata?.contextWindow ?? 128000,
314
+ contextWindow: metadata?.contextWindow ?? DISCOVERY_DEFAULT_CONTEXT_WINDOW,
306
315
  maxTokens: Math.min(metadata?.contextWindow ?? Number.POSITIVE_INFINITY, DISCOVERY_DEFAULT_MAX_TOKENS),
307
316
  headers: providerConfig.headers,
308
317
  } as ModelSpec<Api>);
@@ -369,7 +378,7 @@ export async function discoverLlamaCppModels(
369
378
  for (const item of models) {
370
379
  const { id } = item;
371
380
  if (!id) continue;
372
- const contextWindow = item.contextWindow ?? serverMetadata?.contextWindow ?? 128000;
381
+ const contextWindow = item.contextWindow ?? serverMetadata?.contextWindow ?? DISCOVERY_DEFAULT_CONTEXT_WINDOW;
373
382
  discovered.push(
374
383
  buildModel({
375
384
  id,
@@ -467,7 +476,7 @@ export async function discoverOpenAIModelsList(
467
476
  toPositiveNumberOrUndefined(item.max_model_len) ??
468
477
  toPositiveNumberOrUndefined(item.context_length) ??
469
478
  nativeMetadataForModel?.contextWindow ??
470
- 128000;
479
+ DISCOVERY_DEFAULT_CONTEXT_WINDOW;
471
480
  discovered.push(
472
481
  buildModel({
473
482
  id,
@@ -493,6 +502,59 @@ export async function discoverOpenAIModelsList(
493
502
  return discovered;
494
503
  }
495
504
 
505
+ export async function discoverLiteLLMModels(
506
+ providerConfig: DiscoveryProviderConfig,
507
+ ctx: DiscoveryContext,
508
+ ): Promise<Model<Api>[]> {
509
+ const baseUrl = normalizeLiteLLMDiscoveryBaseUrl(providerConfig.baseUrl);
510
+ const references = getBundledModelReferenceIndex();
511
+ const resolveReference = (id: string) => resolveModelReference(id, references) as ModelSpec<Api> | undefined;
512
+ const baseHeaders: Record<string, string> = { ...(providerConfig.headers ?? {}) };
513
+ let headers = baseHeaders;
514
+ const attempt = async (h: Record<string, string>) => {
515
+ headers = h;
516
+ let authError: (Error & { status: number }) | undefined;
517
+ const authAwareFetch: FetchImpl = async (input, init) => {
518
+ const response = await ctx.fetch(input, init);
519
+ if (response.status === 401) {
520
+ authError = new Error(`HTTP ${response.status} from ${String(input)}`) as Error & { status: number };
521
+ authError.status = response.status;
522
+ }
523
+ return response;
524
+ };
525
+ const models = await fetchLiteLLMRichModels({
526
+ api: providerConfig.api,
527
+ provider: providerConfig.provider,
528
+ baseUrl,
529
+ headers: h,
530
+ fetch: authAwareFetch,
531
+ referenceResolver: resolveReference,
532
+ signal: AbortSignal.timeout(10_000),
533
+ });
534
+ if (authError && models === null) {
535
+ throw authError;
536
+ }
537
+ return models;
538
+ };
539
+ const apiKey = await ctx.getBearerApiKeyResolver(providerConfig.provider);
540
+ let richModels: ModelSpec<Api>[] | null;
541
+ try {
542
+ richModels = apiKey
543
+ ? await withAuth(apiKey, key => attempt({ ...baseHeaders, Authorization: `Bearer ${key}` }))
544
+ : await attempt(baseHeaders);
545
+ } catch (error) {
546
+ const status = typeof error === "object" && error !== null && "status" in error ? error.status : undefined;
547
+ if (status !== 401) {
548
+ throw error;
549
+ }
550
+ richModels = null;
551
+ }
552
+ if (!richModels || richModels.length === 0) {
553
+ return discoverOpenAIModelsList({ ...providerConfig, baseUrl }, ctx);
554
+ }
555
+ return richModels.map(spec => buildModel({ ...spec, headers }));
556
+ }
557
+
496
558
  /**
497
559
  * Discover models from an Anthropic+OpenAI-compatible reseller proxy that
498
560
  * exposes both `/v1/messages` and `/v1/chat/completions`, advertising each
@@ -571,7 +633,10 @@ export async function discoverProxyModels(
571
633
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
572
634
  // Prefer the context_length the API reports for this model; fall
573
635
  // back to the bundled reference, then a sane default.
574
- contextWindow: toPositiveNumberOrUndefined(item.context_length) ?? reference?.contextWindow ?? 128000,
636
+ contextWindow:
637
+ toPositiveNumberOrUndefined(item.context_length) ??
638
+ reference?.contextWindow ??
639
+ DISCOVERY_DEFAULT_CONTEXT_WINDOW,
575
640
  maxTokens: reference?.maxTokens ?? discoveryDefaultMaxTokens(api),
576
641
  headers,
577
642
  // OpenAI-compat fields are no-ops on anthropic models; the
@@ -616,7 +681,11 @@ function toLlamaCppNativeBaseUrl(baseUrl: string): string {
616
681
  }
617
682
  }
618
683
 
619
- function normalizeOpenAIModelsListBaseUrl(baseUrl?: string): string {
684
+ export function normalizeLiteLLMDiscoveryBaseUrl(baseUrl?: string): string {
685
+ return normalizeOpenAIModelsListBaseUrl(baseUrl ?? "http://localhost:4000/v1");
686
+ }
687
+
688
+ export function normalizeOpenAIModelsListBaseUrl(baseUrl?: string): string {
620
689
  const defaultBaseUrl = "http://127.0.0.1:1234/v1";
621
690
  const raw = baseUrl || defaultBaseUrl;
622
691
  try {