@oh-my-pi/pi-coding-agent 17.2.4 → 17.2.5

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 (319) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/{CHANGELOG-bpmhv26t.md → CHANGELOG-q2w43aw3.md} +51 -0
  3. package/dist/cli.js +4148 -3717
  4. package/dist/{template-8vdv6xb4.js → template-c2hyaytt.js} +8 -26
  5. package/dist/types/cli/args.d.ts +4 -1
  6. package/dist/types/cli/browser-relay-cli.d.ts +15 -0
  7. package/dist/types/cli/command-help.d.ts +99 -0
  8. package/dist/types/cli/help-extra.d.ts +2 -0
  9. package/dist/types/cli/thinking-levels.d.ts +5 -0
  10. package/dist/types/cli/update-cli.d.ts +13 -0
  11. package/dist/types/commands/browser-relay.d.ts +38 -0
  12. package/dist/types/commands/commit.d.ts +3 -0
  13. package/dist/types/commands/complete.d.ts +1 -1
  14. package/dist/types/commands/completions.d.ts +6 -0
  15. package/dist/types/commands/grep.d.ts +3 -0
  16. package/dist/types/commands/join.d.ts +4 -0
  17. package/dist/types/commands/launch-help.d.ts +171 -0
  18. package/dist/types/commands/launch.d.ts +5 -1
  19. package/dist/types/commands/models.d.ts +3 -0
  20. package/dist/types/commands/say.d.ts +10 -0
  21. package/dist/types/commands/worktree.d.ts +3 -0
  22. package/dist/types/config/keybindings.d.ts +5 -0
  23. package/dist/types/config/model-discovery.d.ts +2 -2
  24. package/dist/types/config/models-config-schema-bundle.d.ts +3 -0
  25. package/dist/types/config/models-config-schema.d.ts +2 -0
  26. package/dist/types/config/models-config.d.ts +1 -0
  27. package/dist/types/config/service-tier.d.ts +2 -0
  28. package/dist/types/config/settings-schema.d.ts +69 -21
  29. package/dist/types/cursor-bridge-tools.d.ts +1 -1
  30. package/dist/types/cursor.d.ts +7 -4
  31. package/dist/types/edit/index.d.ts +3 -3
  32. package/dist/types/edit/modes/replace.d.ts +22 -15
  33. package/dist/types/edit/renderer.d.ts +1 -1
  34. package/dist/types/eval/py/kernel.d.ts +3 -1
  35. package/dist/types/eval/py/spawn-options.d.ts +12 -16
  36. package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +8 -1
  37. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -1
  38. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
  39. package/dist/types/launch/broker.d.ts +1 -1
  40. package/dist/types/launch/client.d.ts +6 -3
  41. package/dist/types/launch/ensure.d.ts +8 -0
  42. package/dist/types/launch/paths.d.ts +1 -1
  43. package/dist/types/launch/protocol.d.ts +2 -2
  44. package/dist/types/lsp/client.d.ts +2 -0
  45. package/dist/types/lsp/mux/daemon.d.ts +15 -0
  46. package/dist/types/lsp/mux/protocol.d.ts +57 -0
  47. package/dist/types/lsp/mux/server.d.ts +18 -0
  48. package/dist/types/lsp/types.d.ts +22 -2
  49. package/dist/types/main.d.ts +2 -0
  50. package/dist/types/mnemopi/embed-client.d.ts +1 -1
  51. package/dist/types/mnemopi/state.d.ts +0 -23
  52. package/dist/types/modes/components/assistant-message.d.ts +2 -0
  53. package/dist/types/modes/components/custom-editor.d.ts +2 -1
  54. package/dist/types/modes/components/read-tool-group.d.ts +2 -0
  55. package/dist/types/modes/components/stripped-tool-calls-placeholder.d.ts +12 -0
  56. package/dist/types/modes/components/tool-execution.d.ts +2 -0
  57. package/dist/types/modes/controllers/input-controller.d.ts +1 -0
  58. package/dist/types/modes/interactive-mode.d.ts +1 -0
  59. package/dist/types/modes/types.d.ts +1 -0
  60. package/dist/types/modes/workflow.d.ts +2 -1
  61. package/dist/types/sdk.d.ts +3 -1
  62. package/dist/types/secrets/index.d.ts +1 -1
  63. package/dist/types/session/agent-session-types.d.ts +3 -1
  64. package/dist/types/session/indexed-session-storage.d.ts +1 -0
  65. package/dist/types/session/session-advisors.d.ts +1 -1
  66. package/dist/types/session/session-context.d.ts +2 -1
  67. package/dist/types/session/session-maintenance.d.ts +1 -0
  68. package/dist/types/session/session-manager.d.ts +16 -11
  69. package/dist/types/session/session-stats.d.ts +10 -0
  70. package/dist/types/session/session-storage.d.ts +15 -3
  71. package/dist/types/system-prompt.d.ts +4 -1
  72. package/dist/types/task/index.d.ts +2 -1
  73. package/dist/types/task/spawn-policy.d.ts +5 -0
  74. package/dist/types/thinking.d.ts +1 -7
  75. package/dist/types/tools/ast-grep.d.ts +1 -1
  76. package/dist/types/tools/browser/registry.d.ts +2 -1
  77. package/dist/types/tools/browser/relay/bridge.d.ts +35 -0
  78. package/dist/types/tools/browser/relay/daemon.d.ts +16 -0
  79. package/dist/types/tools/browser/relay/kind.d.ts +19 -0
  80. package/dist/types/tools/browser/relay/protocol.d.ts +97 -0
  81. package/dist/types/tools/browser/relay/server.d.ts +35 -0
  82. package/dist/types/tools/browser/render.d.ts +1 -0
  83. package/dist/types/tools/browser.d.ts +3 -0
  84. package/dist/types/tools/computer/exposure.d.ts +9 -7
  85. package/dist/types/tools/computer/protocol.d.ts +70 -17
  86. package/dist/types/tools/computer/supervisor.d.ts +23 -10
  87. package/dist/types/tools/computer/worker-entry.d.ts +1 -0
  88. package/dist/types/tools/computer/worker.d.ts +42 -7
  89. package/dist/types/tools/computer-renderer.d.ts +7 -5
  90. package/dist/types/tools/computer.d.ts +25 -44
  91. package/dist/types/tools/context.d.ts +3 -0
  92. package/dist/types/tools/glob.d.ts +1 -1
  93. package/dist/types/tools/grep.d.ts +1 -1
  94. package/dist/types/tools/render-utils.d.ts +2 -0
  95. package/dist/types/tools/{browser/run-cancellation.d.ts → run-scope.d.ts} +8 -8
  96. package/dist/types/tools/tool-timeouts.d.ts +5 -0
  97. package/dist/types/tools/xdev.d.ts +8 -0
  98. package/dist/types/utils/clipboard.d.ts +2 -2
  99. package/dist/types/web/kagi.d.ts +1 -0
  100. package/dist/types/web/search/index.d.ts +1 -1
  101. package/dist/types/web/search/providers/anthropic.d.ts +1 -0
  102. package/dist/types/web/search/providers/base.d.ts +2 -0
  103. package/dist/types/web/search/providers/brave.d.ts +1 -0
  104. package/dist/types/web/search/providers/browser-page.d.ts +1 -0
  105. package/dist/types/web/search/providers/codex.d.ts +1 -0
  106. package/dist/types/web/search/providers/exa.d.ts +1 -0
  107. package/dist/types/web/search/providers/firecrawl.d.ts +1 -0
  108. package/dist/types/web/search/providers/gemini.d.ts +1 -0
  109. package/dist/types/web/search/providers/jina.d.ts +1 -0
  110. package/dist/types/web/search/providers/kagi.d.ts +1 -0
  111. package/dist/types/web/search/providers/kimi.d.ts +1 -0
  112. package/dist/types/web/search/providers/parallel.d.ts +1 -0
  113. package/dist/types/web/search/providers/perplexity.d.ts +1 -0
  114. package/dist/types/web/search/providers/searxng.d.ts +1 -0
  115. package/dist/types/web/search/providers/tavily.d.ts +1 -0
  116. package/dist/types/web/search/providers/tinyfish.d.ts +1 -0
  117. package/dist/types/web/search/providers/utils.d.ts +6 -9
  118. package/dist/types/web/search/providers/zai.d.ts +1 -0
  119. package/dist/types/web/search/types.d.ts +4 -0
  120. package/package.json +12 -12
  121. package/src/cli/args.ts +7 -87
  122. package/src/cli/browser-relay-cli.ts +119 -0
  123. package/src/cli/command-help.ts +103 -0
  124. package/src/cli/completion-gen.ts +5 -5
  125. package/src/cli/flag-tables.ts +9 -0
  126. package/src/cli/help-extra.ts +89 -0
  127. package/src/cli/setup-cli.ts +13 -21
  128. package/src/cli/thinking-levels.ts +7 -0
  129. package/src/cli/update-cli.ts +26 -7
  130. package/src/cli-commands.ts +170 -33
  131. package/src/cli.ts +17 -5
  132. package/src/commands/acp.ts +3 -1
  133. package/src/commands/agents.ts +3 -2
  134. package/src/commands/auth-broker.ts +3 -2
  135. package/src/commands/auth-gateway.ts +3 -2
  136. package/src/commands/bench.ts +2 -3
  137. package/src/commands/browser-relay.ts +53 -0
  138. package/src/commands/cleanse.ts +2 -2
  139. package/src/commands/commit.ts +3 -2
  140. package/src/commands/complete.ts +2 -1
  141. package/src/commands/completions.ts +3 -2
  142. package/src/commands/config.ts +3 -2
  143. package/src/commands/dry-balance.ts +2 -2
  144. package/src/commands/gallery.ts +3 -2
  145. package/src/commands/gc.ts +3 -2
  146. package/src/commands/grep.ts +3 -2
  147. package/src/commands/grievances.ts +3 -2
  148. package/src/commands/install.ts +2 -2
  149. package/src/commands/join.ts +3 -2
  150. package/src/commands/launch-help.ts +116 -0
  151. package/src/commands/launch.ts +7 -191
  152. package/src/commands/models.ts +3 -2
  153. package/src/commands/plugin.ts +3 -2
  154. package/src/commands/read.ts +3 -2
  155. package/src/commands/say.ts +3 -2
  156. package/src/commands/setup.ts +3 -2
  157. package/src/commands/shell.ts +3 -2
  158. package/src/commands/ssh.ts +3 -2
  159. package/src/commands/stats.ts +3 -2
  160. package/src/commands/tiny-models.ts +2 -2
  161. package/src/commands/token.ts +2 -2
  162. package/src/commands/ttsr.ts +2 -2
  163. package/src/commands/update.ts +3 -2
  164. package/src/commands/usage.ts +3 -2
  165. package/src/commands/web-search.ts +3 -2
  166. package/src/commands/worktree.ts +3 -2
  167. package/src/config/keybindings.ts +5 -0
  168. package/src/config/model-discovery.ts +30 -13
  169. package/src/config/model-registry.ts +9 -5
  170. package/src/config/models-config-schema-bundle.ts +9 -0
  171. package/src/config/resolve-config-value.ts +2 -1
  172. package/src/config/service-tier.ts +5 -0
  173. package/src/config/settings-schema.ts +72 -20
  174. package/src/cursor-bridge-tools.ts +1 -1
  175. package/src/cursor.ts +10 -14
  176. package/src/edit/diff.ts +17 -8
  177. package/src/edit/index.ts +20 -7
  178. package/src/edit/modes/replace.ts +93 -40
  179. package/src/edit/renderer.ts +1 -1
  180. package/src/edit/streaming.ts +14 -17
  181. package/src/eval/py/kernel.ts +2 -1
  182. package/src/eval/py/spawn-options.ts +24 -29
  183. package/src/export/html/template.js +8 -26
  184. package/src/extensibility/extensions/wrapper.ts +1 -0
  185. package/src/extensibility/legacy-pi-ai-shim.ts +22 -1
  186. package/src/extensibility/legacy-pi-coding-agent-shim.ts +7 -6
  187. package/src/extensibility/plugins/legacy-pi-compat.ts +124 -57
  188. package/src/extensibility/skills.ts +11 -0
  189. package/src/extensibility/utils.ts +10 -2
  190. package/src/launch/broker.ts +1 -1
  191. package/src/launch/client.ts +32 -13
  192. package/src/launch/ensure.ts +73 -0
  193. package/src/launch/paths.ts +1 -1
  194. package/src/launch/protocol.ts +2 -2
  195. package/src/lsp/client.ts +23 -2
  196. package/src/lsp/index.ts +8 -0
  197. package/src/lsp/mux/daemon.ts +348 -0
  198. package/src/lsp/mux/protocol.ts +96 -0
  199. package/src/lsp/mux/server.ts +797 -0
  200. package/src/lsp/types.ts +28 -2
  201. package/src/main.ts +7 -2
  202. package/src/mcp/oauth-flow.ts +11 -1
  203. package/src/mnemopi/embed-client.ts +49 -2
  204. package/src/mnemopi/state.ts +57 -23
  205. package/src/modes/components/assistant-message.ts +11 -0
  206. package/src/modes/components/chat-transcript-builder.ts +4 -0
  207. package/src/modes/components/custom-editor.ts +9 -0
  208. package/src/modes/components/read-tool-group.ts +10 -0
  209. package/src/modes/components/status-line/component.ts +1 -1
  210. package/src/modes/components/stripped-tool-calls-placeholder.ts +35 -0
  211. package/src/modes/components/tool-execution.ts +8 -0
  212. package/src/modes/components/tree-selector.ts +46 -48
  213. package/src/modes/controllers/event-controller.ts +17 -0
  214. package/src/modes/controllers/input-controller.ts +39 -1
  215. package/src/modes/controllers/mcp-command-controller.ts +11 -5
  216. package/src/modes/controllers/selector-controller.ts +20 -0
  217. package/src/modes/interactive-mode.ts +2 -0
  218. package/src/modes/types.ts +1 -0
  219. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  220. package/src/modes/utils/interactive-context-helpers.ts +1 -0
  221. package/src/modes/utils/ui-helpers.ts +6 -10
  222. package/src/modes/workflow.ts +8 -2
  223. package/src/prompts/agents/init.md +1 -1
  224. package/src/prompts/system/plan-mode-active.md +2 -2
  225. package/src/prompts/system/system-prompt.md +26 -52
  226. package/src/prompts/system/workflow-notice.md +3 -3
  227. package/src/prompts/tools/ast-grep.md +1 -1
  228. package/src/prompts/tools/bash.md +1 -1
  229. package/src/prompts/tools/browser.md +1 -0
  230. package/src/prompts/tools/computer.md +21 -21
  231. package/src/prompts/tools/glob.md +1 -1
  232. package/src/prompts/tools/grep.md +1 -1
  233. package/src/prompts/tools/replace.md +5 -4
  234. package/src/prompts/tools/task.md +4 -4
  235. package/src/sdk.ts +34 -6
  236. package/src/secrets/index.ts +1 -1
  237. package/src/session/agent-session-types.ts +3 -1
  238. package/src/session/agent-session.ts +13 -1
  239. package/src/session/indexed-session-storage.ts +9 -0
  240. package/src/session/prewalk.ts +24 -2
  241. package/src/session/session-advisors.ts +2 -2
  242. package/src/session/session-context.ts +16 -12
  243. package/src/session/session-dump-format.ts +1 -1
  244. package/src/session/session-maintenance.ts +38 -4
  245. package/src/session/session-manager.ts +102 -67
  246. package/src/session/session-paths.ts +118 -55
  247. package/src/session/session-stats.ts +48 -3
  248. package/src/session/session-storage.ts +30 -22
  249. package/src/session/stream-guards.ts +1 -1
  250. package/src/slash-commands/builtin-registry.ts +27 -24
  251. package/src/system-prompt.ts +8 -3
  252. package/src/task/index.ts +23 -8
  253. package/src/task/spawn-policy.ts +14 -0
  254. package/src/thinking.ts +2 -8
  255. package/src/tools/ast-grep.ts +10 -4
  256. package/src/tools/browser/cmux/cmux-tab.ts +5 -10
  257. package/src/tools/browser/cmux/rpc.ts +2 -8
  258. package/src/tools/browser/registry.ts +53 -2
  259. package/src/tools/browser/relay/bridge.ts +945 -0
  260. package/src/tools/browser/relay/daemon.ts +117 -0
  261. package/src/tools/browser/relay/extension-assets/background.js.txt +242 -0
  262. package/src/tools/browser/relay/extension-assets/manifest.json.txt +14 -0
  263. package/src/tools/browser/relay/extension-assets/options.html.txt +53 -0
  264. package/src/tools/browser/relay/extension-assets/options.js.txt +23 -0
  265. package/src/tools/browser/relay/kind.ts +41 -0
  266. package/src/tools/browser/relay/protocol.ts +54 -0
  267. package/src/tools/browser/relay/server.ts +141 -0
  268. package/src/tools/browser/render.ts +4 -1
  269. package/src/tools/browser/shared-daemon.ts +7 -58
  270. package/src/tools/browser/tab-supervisor.ts +5 -4
  271. package/src/tools/browser/tab-worker.ts +33 -12
  272. package/src/tools/browser.ts +26 -1
  273. package/src/tools/computer/exposure.ts +11 -35
  274. package/src/tools/computer/protocol.ts +51 -10
  275. package/src/tools/computer/supervisor.ts +227 -124
  276. package/src/tools/computer/worker-entry.ts +11 -6
  277. package/src/tools/computer/worker.ts +695 -81
  278. package/src/tools/computer-renderer.ts +104 -65
  279. package/src/tools/computer.ts +134 -428
  280. package/src/tools/context.ts +3 -0
  281. package/src/tools/glob.ts +9 -2
  282. package/src/tools/grep.ts +12 -6
  283. package/src/tools/inspect-image.ts +32 -6
  284. package/src/tools/render-utils.ts +2 -0
  285. package/src/tools/{browser/run-cancellation.ts → run-scope.ts} +11 -11
  286. package/src/tools/tool-timeouts.ts +1 -0
  287. package/src/tools/xdev.ts +29 -2
  288. package/src/utils/clipboard.ts +40 -14
  289. package/src/utils/command-args.ts +26 -28
  290. package/src/utils/tool-choice.ts +0 -13
  291. package/src/web/kagi.ts +2 -1
  292. package/src/web/search/index.ts +18 -2
  293. package/src/web/search/providers/anthropic.ts +4 -1
  294. package/src/web/search/providers/base.ts +2 -0
  295. package/src/web/search/providers/brave.ts +3 -1
  296. package/src/web/search/providers/browser-page.ts +6 -4
  297. package/src/web/search/providers/codex.ts +4 -1
  298. package/src/web/search/providers/duckduckgo.ts +2 -1
  299. package/src/web/search/providers/ecosia.ts +2 -1
  300. package/src/web/search/providers/exa.ts +4 -2
  301. package/src/web/search/providers/firecrawl.ts +3 -1
  302. package/src/web/search/providers/gemini.ts +8 -2
  303. package/src/web/search/providers/google.ts +2 -1
  304. package/src/web/search/providers/jina.ts +12 -2
  305. package/src/web/search/providers/kagi.ts +3 -0
  306. package/src/web/search/providers/kimi.ts +5 -1
  307. package/src/web/search/providers/mojeek.ts +2 -1
  308. package/src/web/search/providers/parallel.ts +5 -1
  309. package/src/web/search/providers/perplexity.ts +6 -3
  310. package/src/web/search/providers/public.ts +1 -1
  311. package/src/web/search/providers/searxng.ts +11 -5
  312. package/src/web/search/providers/startpage.ts +10 -4
  313. package/src/web/search/providers/synthetic.ts +11 -5
  314. package/src/web/search/providers/tavily.ts +3 -1
  315. package/src/web/search/providers/tinyfish.ts +3 -1
  316. package/src/web/search/providers/utils.ts +12 -10
  317. package/src/web/search/providers/xai.ts +2 -2
  318. package/src/web/search/providers/zai.ts +18 -3
  319. package/src/web/search/types.ts +6 -0
@@ -4,10 +4,10 @@
4
4
  * Handles `omp setup` for onboarding and `omp setup <component>` for optional dependencies.
5
5
  */
6
6
  import * as path from "node:path";
7
- import { $which, APP_NAME, getProjectDir, getPythonEnvDir } from "@oh-my-pi/pi-utils";
8
- import { $ } from "bun";
7
+ import { APP_NAME, getProjectDir, getPythonEnvDir } from "@oh-my-pi/pi-utils";
9
8
  import chalk from "chalk";
10
9
  import { Settings, settings } from "../config/settings";
10
+ import { checkPythonKernelAvailability } from "../eval/py/kernel";
11
11
  import { theme } from "../modes/theme/theme";
12
12
  import { downloadSttModel, isSttModelCached } from "../stt/downloader";
13
13
  import { isSttModelKey, STT_MODEL_OPTIONS } from "../stt/models";
@@ -82,25 +82,14 @@ function managedPythonPath(): string {
82
82
  /**
83
83
  * Check Python environment and kernel dependencies.
84
84
  */
85
- async function checkPythonSetup(): Promise<PythonCheckResult> {
86
- const result: PythonCheckResult = {
87
- available: false,
85
+ async function checkPythonSetup(cwd: string, interpreter?: string): Promise<PythonCheckResult> {
86
+ const availability = await checkPythonKernelAvailability(cwd, interpreter, { forceProbe: true });
87
+ return {
88
+ available: availability.ok,
89
+ pythonPath: availability.pythonPath,
90
+ usingManagedEnv: availability.pythonPath === managedPythonPath(),
88
91
  managedEnvPath: MANAGED_PYTHON_ENV,
89
92
  };
90
-
91
- const systemPythonPath = $which("python") ?? $which("python3");
92
- const managedPath = managedPythonPath();
93
- const hasManagedEnv = await Bun.file(managedPath).exists();
94
-
95
- const pythonPath = systemPythonPath ?? (hasManagedEnv ? managedPath : undefined);
96
- if (!pythonPath) {
97
- return result;
98
- }
99
- const probe = await $`${pythonPath} -c "import sys;sys.exit(0)"`.quiet().nothrow();
100
- result.pythonPath = pythonPath;
101
- result.available = probe.exitCode === 0;
102
- result.usingManagedEnv = pythonPath === managedPath;
103
- return result;
104
93
  }
105
94
 
106
95
  /**
@@ -126,7 +115,10 @@ export async function runSetupCommand(cmd: SetupCommandArgs): Promise<void> {
126
115
  }
127
116
 
128
117
  async function handlePythonSetup(flags: { json?: boolean; check?: boolean }): Promise<void> {
129
- const check = await checkPythonSetup();
118
+ const cwd = getProjectDir();
119
+ const projectSettings = await Settings.init({ cwd });
120
+ const interpreter = projectSettings.get("python.interpreter")?.trim() || undefined;
121
+ const check = await checkPythonSetup(cwd, interpreter);
130
122
 
131
123
  if (flags.json) {
132
124
  console.log(JSON.stringify(check, null, 2));
@@ -136,7 +128,7 @@ async function handlePythonSetup(flags: { json?: boolean; check?: boolean }): Pr
136
128
 
137
129
  if (!check.pythonPath) {
138
130
  console.error(chalk.red(`${theme.status.error} Python not found`));
139
- console.error(chalk.dim("Install Python 3.8+ and ensure it's in your PATH"));
131
+ console.error(chalk.dim("Install Python 3.8+ or set python.interpreter to its executable path"));
140
132
  process.exit(1);
141
133
  }
142
134
 
@@ -0,0 +1,7 @@
1
+ import { THINKING_EFFORTS } from "@oh-my-pi/pi-catalog/effort";
2
+
3
+ /**
4
+ * Thinking selectors accepted by the `--thinking` CLI flag, in display order.
5
+ * Shared by help metadata, shell completions, and validation warnings.
6
+ */
7
+ export const CLI_THINKING_LEVELS: readonly string[] = ["off", ...THINKING_EFFORTS, "auto"];
@@ -765,14 +765,33 @@ async function pruneBunCacheAfterGlobalInstall(): Promise<BunInstallCachePruneRe
765
765
  /**
766
766
  * Detect a musl-libc Linux host (Alpine, Void-musl) so self-update replaces a
767
767
  * musl binary with the musl release asset instead of the glibc build, which
768
- * would fail to start on the next run. Mirrors the detection in
769
- * scripts/install.sh.
768
+ * would fail to start on the next run. The loader file alone is not sufficient:
769
+ * glibc hosts may have musl installed for cross-compilation.
770
770
  */
771
- function isMuslLinux(): boolean {
772
- if (process.platform !== "linux") return false;
773
- if (fs.existsSync("/etc/alpine-release")) return true;
774
- const loaderArch = process.arch === "arm64" ? "aarch64" : "x86_64";
775
- return fs.existsSync(`/lib/ld-musl-${loaderArch}.so.1`);
771
+ interface MuslDetectionOptions {
772
+ platform?: NodeJS.Platform;
773
+ alpineRelease?: boolean;
774
+ lddOutput?: string;
775
+ }
776
+
777
+ function detectLddOutput(): string | undefined {
778
+ try {
779
+ const result = Bun.spawnSync(["ldd", "--version"], { stdout: "pipe", stderr: "pipe" });
780
+ return `${result.stdout.toString("utf-8")}\n${result.stderr.toString("utf-8")}`;
781
+ } catch {
782
+ return undefined;
783
+ }
784
+ }
785
+
786
+ function isMuslLinux(options: MuslDetectionOptions = {}): boolean {
787
+ if ((options.platform ?? process.platform) !== "linux") return false;
788
+ if (options.alpineRelease ?? fs.existsSync("/etc/alpine-release")) return true;
789
+ return /\bmusl\b/i.test(options.lddOutput ?? detectLddOutput() ?? "");
790
+ }
791
+
792
+ /** Test seam for libc detection. */
793
+ export function isMuslLinuxForTest(options: Required<MuslDetectionOptions>): boolean {
794
+ return isMuslLinux(options);
776
795
  }
777
796
 
778
797
  /**
@@ -9,42 +9,179 @@
9
9
  * regression that motivated the split.
10
10
  */
11
11
  import type { CommandEntry } from "@oh-my-pi/pi-utils/cli";
12
+ import * as commandHelp from "./cli/command-help";
12
13
  import { flagConsumesValue } from "./cli/flag-tables";
14
+ import { launchHelp } from "./commands/launch-help";
13
15
 
14
16
  export const commands: CommandEntry[] = [
15
- { name: "launch", load: () => import("./commands/launch").then(m => m.default) },
16
- { name: "acp", load: () => import("./commands/acp").then(m => m.default) },
17
- { name: "auth-broker", load: () => import("./commands/auth-broker").then(m => m.default) },
18
- { name: "auth-gateway", load: () => import("./commands/auth-gateway").then(m => m.default) },
19
- { name: "agents", load: () => import("./commands/agents").then(m => m.default) },
20
- { name: "bench", load: () => import("./commands/bench").then(m => m.default) },
21
- { name: "cleanse", load: () => import("./commands/cleanse").then(m => m.default) },
22
- { name: "commit", load: () => import("./commands/commit").then(m => m.default) },
23
- { name: "completions", load: () => import("./commands/completions").then(m => m.default) },
24
- { name: "__complete", load: () => import("./commands/complete").then(m => m.default) },
25
- { name: "config", load: () => import("./commands/config").then(m => m.default) },
26
- { name: "dry-balance", load: () => import("./commands/dry-balance").then(m => m.default) },
27
- { name: "gc", load: () => import("./commands/gc").then(m => m.default) },
28
- { name: "grep", load: () => import("./commands/grep").then(m => m.default) },
29
- { name: "gallery", load: () => import("./commands/gallery").then(m => m.default) },
30
- { name: "grievances", load: () => import("./commands/grievances").then(m => m.default) },
31
- { name: "install", load: () => import("./commands/install").then(m => m.default) },
32
- { name: "join", load: () => import("./commands/join").then(m => m.default) },
33
- { name: "models", load: () => import("./commands/models").then(m => m.default) },
34
- { name: "plugin", load: () => import("./commands/plugin").then(m => m.default) },
35
- { name: "say", load: () => import("./commands/say").then(m => m.default) },
36
- { name: "setup", load: () => import("./commands/setup").then(m => m.default) },
37
- { name: "shell", load: () => import("./commands/shell").then(m => m.default) },
38
- { name: "read", load: () => import("./commands/read").then(m => m.default) },
39
- { name: "ssh", load: () => import("./commands/ssh").then(m => m.default) },
40
- { name: "stats", load: () => import("./commands/stats").then(m => m.default) },
41
- { name: "update", load: () => import("./commands/update").then(m => m.default) },
42
- { name: "usage", load: () => import("./commands/usage").then(m => m.default) },
43
- { name: "tiny-models", load: () => import("./commands/tiny-models").then(m => m.default) },
44
- { name: "token", load: () => import("./commands/token").then(m => m.default) },
45
- { name: "ttsr", load: () => import("./commands/ttsr").then(m => m.default) },
46
- { name: "worktree", load: () => import("./commands/worktree").then(m => m.default), aliases: ["wt"] },
47
- { name: "search", load: () => import("./commands/web-search").then(m => m.default), aliases: ["q"] },
17
+ { name: "launch", load: () => import("./commands/launch").then(m => m.default), help: launchHelp },
18
+ {
19
+ name: "acp",
20
+ load: () => import("./commands/acp").then(m => m.default),
21
+ help: commandHelp.acpHelp,
22
+ },
23
+ {
24
+ name: "auth-broker",
25
+ load: () => import("./commands/auth-broker").then(m => m.default),
26
+ help: commandHelp.authBrokerHelp,
27
+ },
28
+ {
29
+ name: "auth-gateway",
30
+ load: () => import("./commands/auth-gateway").then(m => m.default),
31
+ help: commandHelp.authGatewayHelp,
32
+ },
33
+ {
34
+ name: "agents",
35
+ load: () => import("./commands/agents").then(m => m.default),
36
+ help: commandHelp.agentsHelp,
37
+ },
38
+ {
39
+ name: "bench",
40
+ load: () => import("./commands/bench").then(m => m.default),
41
+ help: commandHelp.benchHelp,
42
+ },
43
+ {
44
+ name: "browser-relay",
45
+ load: () => import("./commands/browser-relay").then(m => m.default),
46
+ help: commandHelp.browserRelayHelp,
47
+ },
48
+ {
49
+ name: "cleanse",
50
+ load: () => import("./commands/cleanse").then(m => m.default),
51
+ help: commandHelp.cleanseHelp,
52
+ },
53
+ {
54
+ name: "commit",
55
+ load: () => import("./commands/commit").then(m => m.default),
56
+ help: commandHelp.commitHelp,
57
+ },
58
+ {
59
+ name: "completions",
60
+ load: () => import("./commands/completions").then(m => m.default),
61
+ help: commandHelp.completionsHelp,
62
+ },
63
+ {
64
+ name: "__complete",
65
+ load: () => import("./commands/complete").then(m => m.default),
66
+ help: commandHelp.completeHelp,
67
+ },
68
+ {
69
+ name: "config",
70
+ load: () => import("./commands/config").then(m => m.default),
71
+ help: commandHelp.configHelp,
72
+ },
73
+ {
74
+ name: "dry-balance",
75
+ load: () => import("./commands/dry-balance").then(m => m.default),
76
+ help: commandHelp.dryBalanceHelp,
77
+ },
78
+ {
79
+ name: "gc",
80
+ load: () => import("./commands/gc").then(m => m.default),
81
+ help: commandHelp.gcHelp,
82
+ },
83
+ {
84
+ name: "grep",
85
+ load: () => import("./commands/grep").then(m => m.default),
86
+ help: commandHelp.grepHelp,
87
+ },
88
+ {
89
+ name: "gallery",
90
+ load: () => import("./commands/gallery").then(m => m.default),
91
+ help: commandHelp.galleryHelp,
92
+ },
93
+ {
94
+ name: "grievances",
95
+ load: () => import("./commands/grievances").then(m => m.default),
96
+ help: commandHelp.grievancesHelp,
97
+ },
98
+ {
99
+ name: "install",
100
+ load: () => import("./commands/install").then(m => m.default),
101
+ help: commandHelp.installHelp,
102
+ },
103
+ {
104
+ name: "join",
105
+ load: () => import("./commands/join").then(m => m.default),
106
+ help: commandHelp.joinHelp,
107
+ },
108
+ {
109
+ name: "models",
110
+ load: () => import("./commands/models").then(m => m.default),
111
+ help: commandHelp.modelsHelp,
112
+ },
113
+ {
114
+ name: "plugin",
115
+ load: () => import("./commands/plugin").then(m => m.default),
116
+ help: commandHelp.pluginHelp,
117
+ },
118
+ {
119
+ name: "say",
120
+ load: () => import("./commands/say").then(m => m.default),
121
+ help: commandHelp.sayHelp,
122
+ },
123
+ {
124
+ name: "setup",
125
+ load: () => import("./commands/setup").then(m => m.default),
126
+ help: commandHelp.setupHelp,
127
+ },
128
+ {
129
+ name: "shell",
130
+ load: () => import("./commands/shell").then(m => m.default),
131
+ help: commandHelp.shellHelp,
132
+ },
133
+ {
134
+ name: "read",
135
+ load: () => import("./commands/read").then(m => m.default),
136
+ help: commandHelp.readHelp,
137
+ },
138
+ {
139
+ name: "ssh",
140
+ load: () => import("./commands/ssh").then(m => m.default),
141
+ help: commandHelp.sshHelp,
142
+ },
143
+ {
144
+ name: "stats",
145
+ load: () => import("./commands/stats").then(m => m.default),
146
+ help: commandHelp.statsHelp,
147
+ },
148
+ {
149
+ name: "update",
150
+ load: () => import("./commands/update").then(m => m.default),
151
+ help: commandHelp.updateHelp,
152
+ },
153
+ {
154
+ name: "usage",
155
+ load: () => import("./commands/usage").then(m => m.default),
156
+ help: commandHelp.usageHelp,
157
+ },
158
+ {
159
+ name: "tiny-models",
160
+ load: () => import("./commands/tiny-models").then(m => m.default),
161
+ help: commandHelp.tinyModelsHelp,
162
+ },
163
+ {
164
+ name: "token",
165
+ load: () => import("./commands/token").then(m => m.default),
166
+ help: commandHelp.tokenHelp,
167
+ },
168
+ {
169
+ name: "ttsr",
170
+ load: () => import("./commands/ttsr").then(m => m.default),
171
+ help: commandHelp.ttsrHelp,
172
+ },
173
+ {
174
+ name: "worktree",
175
+ load: () => import("./commands/worktree").then(m => m.default),
176
+ aliases: ["wt"],
177
+ help: commandHelp.worktreeHelp,
178
+ },
179
+ {
180
+ name: "search",
181
+ load: () => import("./commands/web-search").then(m => m.default),
182
+ aliases: ["q"],
183
+ help: commandHelp.searchHelp,
184
+ },
48
185
  ];
49
186
 
50
187
  // Documented-looking plugin/marketplace verbs that are NOT registered top-level
package/src/cli.ts CHANGED
@@ -15,7 +15,7 @@ try {
15
15
  * lightweight CLI runner from pi-utils.
16
16
  */
17
17
  import { parentPort } from "node:worker_threads";
18
- import type { CliConfig } from "@oh-my-pi/pi-utils/cli";
18
+ import type { CliConfig, CommandMetadata } from "@oh-my-pi/pi-utils/cli";
19
19
  import {
20
20
  APP_NAME,
21
21
  getActiveProfile,
@@ -33,6 +33,7 @@ import { startJsEvalProcess } from "./eval/js/process-entry";
33
33
  import type { WorkerInbound as JsWorkerInbound, WorkerOutbound as JsWorkerOutbound } from "./eval/js/worker-protocol";
34
34
  import { DAEMON_BROKER_WORKER_ARG } from "./launch/protocol";
35
35
  import { TERMINAL_OUTPUT_WORKER_ARG } from "./launch/terminal-output-worker-protocol";
36
+ import { LSP_MUX_WORKER_ARG } from "./lsp/mux/protocol";
36
37
  import { COMPUTER_WORKER_ARG } from "./tools/computer/protocol";
37
38
  import { smokeTestComputerWorker } from "./tools/computer/supervisor";
38
39
  import { startComputerWorker } from "./tools/computer/worker-entry";
@@ -60,9 +61,13 @@ const isProcessEntry = import.meta.main || process.env.PI_COMPILED === "true";
60
61
  // `@oh-my-pi/pi-utils/env` eagerly loads `.env` from the agent directory at
61
62
  // import time, so it must not be imported before `setProfile` runs.
62
63
 
63
- async function showHelp(config: CliConfig): Promise<void> {
64
- const { renderRootHelp } = await import("@oh-my-pi/pi-utils/cli");
65
- const { getExtraHelpText } = await import("./cli/args");
64
+ async function showHelp(config: CliConfig<CommandMetadata>): Promise<void> {
65
+ // Root help historically loads the selected profile's environment. The
66
+ // lazily loaded help module imports it statically after profile bootstrap.
67
+ const [{ renderRootHelp }, { getExtraHelpText }] = await Promise.all([
68
+ import("@oh-my-pi/pi-utils/cli"),
69
+ import("./cli/help-extra"),
70
+ ]);
66
71
  renderRootHelp(config);
67
72
  const extra = getExtraHelpText();
68
73
  if (extra.trim().length > 0) {
@@ -89,6 +94,7 @@ async function runSmokeTest(): Promise<void> {
89
94
  const { smokeTestJsEvalWorker } = await import("./eval/js/context-manager");
90
95
  // Other smoke dependencies stay lazy so normal CLI startup does not load their worker clients.
91
96
  const { smokeTestDaemonBroker } = await import("./launch/client");
97
+ const { smokeTestLspMux } = await import("./lsp/mux/daemon");
92
98
  const { smokeTestTerminalOutputWorker } = await import("./launch/terminal-output-worker-client");
93
99
  await smokeTestSyncWorker();
94
100
 
@@ -111,6 +117,7 @@ async function runSmokeTest(): Promise<void> {
111
117
  await smokeTestTtsWorker();
112
118
  await smokeTestMnemopiEmbedWorker();
113
119
  await smokeTestDaemonBroker();
120
+ await smokeTestLspMux();
114
121
  await smokeTestTerminalOutputWorker();
115
122
  process.stdout.write("smoke-test: ok\n");
116
123
  }
@@ -210,6 +217,11 @@ async function runWorkerEntrypoint(arg: string | undefined): Promise<boolean> {
210
217
  await startDaemonBrokerFromEnvironment();
211
218
  return true;
212
219
  }
220
+ if (arg === LSP_MUX_WORKER_ARG) {
221
+ const { startLspMuxFromEnvironment } = await import("./lsp/mux/server");
222
+ await startLspMuxFromEnvironment();
223
+ return true;
224
+ }
213
225
  return false;
214
226
  }
215
227
 
@@ -397,7 +409,7 @@ export async function runCli(argv: string[]): Promise<void> {
397
409
  process.exitCode = 1;
398
410
  return;
399
411
  }
400
- return run({ bin: APP_NAME, version: VERSION, argv: resolved.argv, commands, help: showHelp });
412
+ return run({ bin: APP_NAME, version: VERSION, argv: resolved.argv, commands, metadataHelp: showHelp });
401
413
  }
402
414
 
403
415
  // Floating call instead of top-level await: TLA forces `--bytecode` (CJS
@@ -4,13 +4,15 @@
4
4
  * Thin wrapper around the launch flow that forces `mode: "acp"` unless the
5
5
  * ACP terminal-auth flag asks the same command to open the interactive TUI.
6
6
  */
7
+
7
8
  import { Command } from "@oh-my-pi/pi-utils/cli";
8
9
  import { type Args as ParsedArgs, parseArgs, reportCliUsageError } from "../cli/args";
10
+ import { acpHelp as commandHelp } from "../cli/command-help";
9
11
  import { runRootCommand } from "../main";
10
12
  import { prepareAcpTerminalAuthArgs } from "../modes/acp/terminal-auth";
11
13
 
12
14
  export default class Acp extends Command {
13
- static description = "Run Oh My Pi as an ACP (Agent Client Protocol) server over stdio";
15
+ static description = commandHelp.description;
14
16
  static strict = false;
15
17
 
16
18
  async run(): Promise<void> {
@@ -1,15 +1,16 @@
1
1
  /**
2
2
  * Manage bundled task agents.
3
3
  */
4
+
4
5
  import { Args, Command, Flags, renderCommandHelp } from "@oh-my-pi/pi-utils/cli";
5
6
  import { type AgentsAction, type AgentsCommandArgs, runAgentsCommand } from "../cli/agents-cli";
7
+ import { agentsHelp as commandHelp } from "../cli/command-help";
6
8
  import { initTheme } from "../modes/theme/theme";
7
9
 
8
10
  const ACTIONS: AgentsAction[] = ["unpack"];
9
11
 
10
12
  export default class Agents extends Command {
11
- static description = "Manage bundled task agents";
12
-
13
+ static description = commandHelp.description;
13
14
  static args = {
14
15
  action: Args.string({
15
16
  description: "Agents action",
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * `omp auth-broker` — manage the omp credential vault.
3
3
  */
4
+
4
5
  import { Args, Command, Flags, renderCommandHelp } from "@oh-my-pi/pi-utils/cli";
5
6
  import {
6
7
  AUTH_BROKER_ACTIONS,
@@ -8,11 +9,11 @@ import {
8
9
  type AuthBrokerCommandArgs,
9
10
  runAuthBrokerCommand,
10
11
  } from "../cli/auth-broker-cli";
12
+ import { authBrokerHelp as commandHelp } from "../cli/command-help";
11
13
  import { initTheme } from "../modes/theme/theme";
12
14
 
13
15
  export default class AuthBroker extends Command {
14
- static description = "Manage the omp auth-broker (credential vault)";
15
-
16
+ static description = commandHelp.description;
16
17
  static args = {
17
18
  action: Args.string({
18
19
  description: "Sub-command",
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * `omp auth-gateway` — run a forward proxy that injects auth from the broker.
3
3
  */
4
+
4
5
  import { Args, Command, Flags, renderCommandHelp } from "@oh-my-pi/pi-utils/cli";
5
6
  import {
6
7
  AUTH_GATEWAY_ACTIONS,
@@ -8,11 +9,11 @@ import {
8
9
  type AuthGatewayCommandArgs,
9
10
  runAuthGatewayCommand,
10
11
  } from "../cli/auth-gateway-cli";
12
+ import { authGatewayHelp as commandHelp } from "../cli/command-help";
11
13
  import { initTheme } from "../modes/theme/theme";
12
14
 
13
15
  export default class AuthGateway extends Command {
14
- static description = "Run an auth-gateway forward proxy backed by the configured broker";
15
-
16
+ static description = commandHelp.description;
16
17
  static args = {
17
18
  action: Args.string({
18
19
  description: "Sub-command",
@@ -1,11 +1,10 @@
1
1
  import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
2
2
  import { runBenchCommand } from "../cli/bench-cli";
3
+ import { benchHelp as commandHelp } from "../cli/command-help";
3
4
  import { SERVICE_TIER_OPENAI_VALUES } from "../config/service-tier";
4
5
 
5
6
  export default class Bench extends Command {
6
- static description =
7
- "Benchmark models with the same prompt: time-to-first-token and generation throughput (tokens/s)";
8
-
7
+ static description = commandHelp.description;
9
8
  static args = {
10
9
  models: Args.string({
11
10
  description: "Model selectors (provider/model or fuzzy id, e.g. opus)",
@@ -0,0 +1,53 @@
1
+ /**
2
+ * `omp browser-relay` — drive the user's own Chrome tabs.
3
+ */
4
+ import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
5
+ import {
6
+ BROWSER_RELAY_ACTIONS,
7
+ type BrowserRelayAction,
8
+ DEFAULT_RELAY_PORT,
9
+ runBrowserRelayCommand,
10
+ } from "../cli/browser-relay-cli";
11
+
12
+ export default class BrowserRelay extends Command {
13
+ static description = "Run the local CDP relay that lets the browser tool drive your own Chrome tabs";
14
+
15
+ static args = {
16
+ action: Args.string({
17
+ description: `Action: ${BROWSER_RELAY_ACTIONS.join(" | ")} (default serve)`,
18
+ options: [...BROWSER_RELAY_ACTIONS],
19
+ required: false,
20
+ }),
21
+ };
22
+
23
+ static flags = {
24
+ port: Flags.integer({ char: "p", description: "Port to listen on", default: DEFAULT_RELAY_PORT }),
25
+ token: Flags.string({ description: "Require the extension to present this token" }),
26
+ dir: Flags.string({
27
+ description: "Extension install directory (install; default ~/.omp/browser-relay/extension)",
28
+ }),
29
+ "no-group": Flags.boolean({
30
+ description: "Don't gather controllable tabs into an 'omp' tab group",
31
+ default: false,
32
+ }),
33
+ verbose: Flags.boolean({ char: "v", description: "Log relay traffic summaries to stderr", default: false }),
34
+ };
35
+
36
+ static examples = [
37
+ "omp browser-relay install # write the Chrome extension to disk + setup steps",
38
+ "omp browser-relay # serve the relay on the default port",
39
+ "omp browser-relay -p 9333 --token s3cret",
40
+ ];
41
+
42
+ async run(): Promise<void> {
43
+ const { args, flags } = await this.parse(BrowserRelay);
44
+ await runBrowserRelayCommand({
45
+ action: (args.action as BrowserRelayAction | undefined) ?? "serve",
46
+ port: flags.port,
47
+ token: flags.token,
48
+ dir: flags.dir,
49
+ group: !flags["no-group"],
50
+ verbose: flags.verbose,
51
+ });
52
+ }
53
+ }
@@ -1,11 +1,11 @@
1
1
  import { postmortem } from "@oh-my-pi/pi-utils";
2
2
  import { Command, Flags } from "@oh-my-pi/pi-utils/cli";
3
3
  import { runCleanseCommand } from "../cleanse";
4
+ import { cleanseHelp as commandHelp } from "../cli/command-help";
4
5
  import { CliUsageError } from "../cli/usage-error";
5
6
 
6
7
  export default class Cleanse extends Command {
7
- static description = "Detect and fix project diagnostics with weighted parallel subagents";
8
-
8
+ static description = commandHelp.description;
9
9
  static flags = {
10
10
  agents: Flags.integer({
11
11
  char: "n",
@@ -1,15 +1,16 @@
1
1
  /**
2
2
  * Generate and optionally push a commit with changelog updates.
3
3
  */
4
+
4
5
  import { postmortem } from "@oh-my-pi/pi-utils";
5
6
  import { Command, Flags } from "@oh-my-pi/pi-utils/cli";
7
+ import { commitHelp as commandHelp } from "../cli/command-help";
6
8
  import { runCommitCommand } from "../commit";
7
9
  import type { CommitCommandArgs } from "../commit/types";
8
10
  import { initTheme } from "../modes/theme/theme";
9
11
 
10
12
  export default class Commit extends Command {
11
- static description = "Generate a commit message and update changelogs";
12
-
13
+ static description = commandHelp.description;
13
14
  static flags = {
14
15
  push: Flags.boolean({ description: "Push after committing" }),
15
16
  "dry-run": Flags.boolean({ description: "Preview without committing" }),
@@ -10,10 +10,11 @@
10
10
  */
11
11
  import { type GeneratedProvider, getBundledModels, getBundledProviders } from "@oh-my-pi/pi-catalog/models";
12
12
  import { Command } from "@oh-my-pi/pi-utils/cli";
13
+ import { completeHelp as commandHelp } from "../cli/command-help";
13
14
  import { SessionManager } from "../session/session-manager";
14
15
 
15
16
  export default class Complete extends Command {
16
- static hidden = true;
17
+ static hidden = commandHelp.hidden;
17
18
  static strict = false;
18
19
 
19
20
  async run(): Promise<void> {
@@ -4,8 +4,10 @@
4
4
  * The script is derived entirely from the declarative command/flag metadata
5
5
  * (see `cli/completion-gen.ts`), so it never drifts from the actual CLI surface.
6
6
  */
7
+
7
8
  import { APP_NAME, VERSION } from "@oh-my-pi/pi-utils";
8
9
  import { Args, type CliConfig, Command, type CommandCtor } from "@oh-my-pi/pi-utils/cli";
10
+ import { completionsHelp as commandHelp } from "../cli/command-help";
9
11
  import { buildSpec, generateCompletion, type Shell } from "../cli/completion-gen";
10
12
  import { commands } from "../cli-commands";
11
13
 
@@ -14,8 +16,7 @@ const ROOT_COMMAND = "launch";
14
16
  const SHELLS = ["bash", "zsh", "fish"] as const;
15
17
 
16
18
  export default class Completions extends Command {
17
- static description = "Print a shell completion script (bash, zsh, or fish)";
18
-
19
+ static description = commandHelp.description;
19
20
  static args = {
20
21
  shell: Args.string({
21
22
  description: "Target shell",
@@ -1,15 +1,16 @@
1
1
  /**
2
2
  * Manage configuration settings.
3
3
  */
4
+
4
5
  import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
6
+ import { configHelp as commandHelp } from "../cli/command-help";
5
7
  import { type ConfigAction, type ConfigCommandArgs, runConfigCommand } from "../cli/config-cli";
6
8
  import { initTheme } from "../modes/theme/theme";
7
9
 
8
10
  const ACTIONS: ConfigAction[] = ["list", "get", "set", "reset", "path", "init-xdg"];
9
11
 
10
12
  export default class Config extends Command {
11
- static description = "Manage configuration settings";
12
-
13
+ static description = commandHelp.description;
13
14
  static args = {
14
15
  action: Args.string({
15
16
  description: "Config action",
@@ -1,9 +1,9 @@
1
1
  import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
2
+ import { dryBalanceHelp as commandHelp } from "../cli/command-help";
2
3
  import { runDryBalanceCommand } from "../cli/dry-balance-cli";
3
4
 
4
5
  export default class DryBalance extends Command {
5
- static description = "Dry-run OAuth account balancing across random session ids";
6
-
6
+ static description = commandHelp.description;
7
7
  static args = {
8
8
  model: Args.string({
9
9
  description: "Model selector (provider/model or fuzzy id). Defaults to the configured default model.",