@oh-my-pi/pi-coding-agent 14.2.0 → 14.3.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 (54) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/package.json +19 -19
  3. package/src/cli/args.ts +10 -1
  4. package/src/cli/shell-cli.ts +15 -3
  5. package/src/config/settings-schema.ts +60 -1
  6. package/src/dap/session.ts +8 -2
  7. package/src/debug/system-info.ts +6 -2
  8. package/src/discovery/claude.ts +58 -36
  9. package/src/discovery/opencode.ts +20 -2
  10. package/src/edit/index.ts +3 -1
  11. package/src/edit/modes/chunk.ts +133 -53
  12. package/src/edit/modes/hashline.ts +36 -11
  13. package/src/edit/renderer.ts +98 -133
  14. package/src/edit/streaming.ts +351 -0
  15. package/src/exec/bash-executor.ts +60 -5
  16. package/src/internal-urls/docs-index.generated.ts +5 -5
  17. package/src/internal-urls/pi-protocol.ts +0 -2
  18. package/src/lsp/client.ts +22 -6
  19. package/src/lsp/defaults.json +2 -1
  20. package/src/lsp/index.ts +53 -10
  21. package/src/lsp/types.ts +2 -0
  22. package/src/modes/acp/acp-agent.ts +76 -2
  23. package/src/modes/components/assistant-message.ts +1 -34
  24. package/src/modes/components/hook-editor.ts +1 -1
  25. package/src/modes/components/tool-execution.ts +111 -101
  26. package/src/modes/controllers/input-controller.ts +1 -1
  27. package/src/modes/interactive-mode.ts +0 -2
  28. package/src/modes/theme/mermaid-cache.ts +13 -52
  29. package/src/modes/theme/theme.ts +2 -2
  30. package/src/prompts/system/system-prompt.md +1 -1
  31. package/src/prompts/tools/ast-grep.md +1 -0
  32. package/src/prompts/tools/browser.md +1 -0
  33. package/src/prompts/tools/chunk-edit.md +25 -22
  34. package/src/prompts/tools/gh-pr-push.md +2 -1
  35. package/src/prompts/tools/grep.md +4 -3
  36. package/src/prompts/tools/lsp.md +6 -0
  37. package/src/prompts/tools/read-chunk.md +46 -7
  38. package/src/prompts/tools/read.md +7 -4
  39. package/src/sdk.ts +8 -5
  40. package/src/session/agent-session.ts +36 -20
  41. package/src/session/session-manager.ts +228 -57
  42. package/src/session/streaming-output.ts +11 -0
  43. package/src/system-prompt.ts +7 -2
  44. package/src/task/executor.ts +1 -0
  45. package/src/tools/ast-edit.ts +37 -2
  46. package/src/tools/bash.ts +75 -12
  47. package/src/tools/find.ts +19 -26
  48. package/src/tools/gh.ts +6 -16
  49. package/src/tools/grep.ts +94 -37
  50. package/src/tools/path-utils.ts +31 -3
  51. package/src/tools/resolve.ts +12 -3
  52. package/src/tools/sqlite-reader.ts +116 -3
  53. package/src/tools/vim.ts +1 -1
  54. package/src/web/search/providers/codex.ts +129 -6
@@ -4,8 +4,8 @@
4
4
  * Uses brush-core via native bindings for shell execution.
5
5
  */
6
6
  import * as fs from "node:fs/promises";
7
- import { executeShell, Shell } from "@oh-my-pi/pi-natives";
8
- import { Settings } from "../config/settings";
7
+ import { executeShell, type MinimizerOptions, Shell } from "@oh-my-pi/pi-natives";
8
+ import { Settings, type ShellMinimizerSettings } from "../config/settings";
9
9
  import { OutputSink } from "../session/streaming-output";
10
10
  import { getOrCreateSnapshot } from "../utils/shell-snapshot";
11
11
  import { NON_INTERACTIVE_ENV } from "./non-interactive-env";
@@ -22,6 +22,17 @@ export interface BashExecutorOptions {
22
22
  /** Artifact path/id for full output storage */
23
23
  artifactPath?: string;
24
24
  artifactId?: string;
25
+ /**
26
+ * Invoked when the native minimizer rewrote the command's output, giving
27
+ * the caller a chance to persist the lossless original capture (typically
28
+ * via the session's `ArtifactManager`). The returned id is spliced into
29
+ * the sink output as `artifact://<id>` so the agent can retrieve the raw
30
+ * bytes. Return `undefined` to skip the footer.
31
+ */
32
+ onMinimizedSave?: (
33
+ originalText: string,
34
+ info: { filter: string; inputBytes: number; outputBytes: number },
35
+ ) => Promise<string | undefined>;
25
36
  }
26
37
 
27
38
  export interface BashResult {
@@ -53,10 +64,24 @@ async function resolveShellCwd(cwd: string | undefined): Promise<string | undefi
53
64
  }
54
65
  }
55
66
 
67
+ function buildMinimizerOptions(group: ShellMinimizerSettings): MinimizerOptions | undefined {
68
+ if (!group.enabled) return undefined;
69
+ return {
70
+ enabled: true,
71
+ settingsPath: group.settingsPath || undefined,
72
+ only: group.only.length > 0 ? group.only : undefined,
73
+ except: group.except.length > 0 ? group.except : undefined,
74
+ maxCaptureBytes: group.maxCaptureBytes,
75
+ };
76
+ }
77
+
56
78
  export async function executeBash(command: string, options?: BashExecutorOptions): Promise<BashResult> {
57
79
  const settings = await Settings.init();
58
80
  const { shell, env: shellEnv, prefix } = settings.getShellConfig();
59
81
  const snapshotPath = shell.includes("bash") ? await getOrCreateSnapshot(shell, shellEnv) : null;
82
+
83
+ const minimizer = buildMinimizerOptions(settings.getGroup("shellMinimizer"));
84
+
60
85
  const commandCwd = await resolveShellCwd(options?.cwd);
61
86
  const commandEnv = options?.env ? { ...NON_INTERACTIVE_ENV, ...options.env } : NON_INTERACTIVE_ENV;
62
87
 
@@ -89,7 +114,7 @@ export async function executeBash(command: string, options?: BashExecutorOptions
89
114
  };
90
115
  }
91
116
 
92
- const sessionKey = buildSessionKey(shell, prefix, snapshotPath, shellEnv, options?.sessionKey);
117
+ const sessionKey = buildSessionKey(shell, prefix, snapshotPath, shellEnv, options?.sessionKey, minimizer);
93
118
  const persistentSessionBroken = brokenShellSessions.has(sessionKey);
94
119
  if (persistentSessionBroken) {
95
120
  shellSessions.delete(sessionKey);
@@ -97,7 +122,11 @@ export async function executeBash(command: string, options?: BashExecutorOptions
97
122
 
98
123
  let shellSession = persistentSessionBroken ? undefined : shellSessions.get(sessionKey);
99
124
  if (!shellSession && !persistentSessionBroken) {
100
- shellSession = new Shell({ sessionEnv: shellEnv, snapshotPath: snapshotPath ?? undefined });
125
+ shellSession = new Shell({
126
+ sessionEnv: shellEnv,
127
+ snapshotPath: snapshotPath ?? undefined,
128
+ minimizer,
129
+ });
101
130
  shellSessions.set(sessionKey, shellSession);
102
131
  }
103
132
  const userSignal = options?.signal;
@@ -152,6 +181,7 @@ export async function executeBash(command: string, options?: BashExecutorOptions
152
181
  env: commandEnv,
153
182
  sessionEnv: shellEnv,
154
183
  snapshotPath: snapshotPath ?? undefined,
184
+ minimizer,
155
185
  timeoutMs: options?.timeout,
156
186
  signal: runAbortController.signal,
157
187
  },
@@ -204,6 +234,27 @@ export async function executeBash(command: string, options?: BashExecutorOptions
204
234
  };
205
235
  }
206
236
 
237
+ // When the native minimizer rewrote the output, swap the sink's accumulated
238
+ // raw stream for the minimized text, persist the original as a session
239
+ // artifact, and splice an `artifact://<id>` footer into the visible text so
240
+ // the agent can retrieve the raw bytes losslessly.
241
+ const minimized = winner.result.minimized;
242
+ if (minimized) {
243
+ sink.replace(minimized.text);
244
+ if (options?.onMinimizedSave) {
245
+ const artifactId = await options.onMinimizedSave(minimized.originalText, {
246
+ filter: minimized.filter,
247
+ inputBytes: minimized.inputBytes,
248
+ outputBytes: minimized.outputBytes,
249
+ });
250
+ if (artifactId) {
251
+ sink.push(
252
+ `\n… full output: artifact://${artifactId} (${minimized.inputBytes} → ${minimized.outputBytes} bytes)\n`,
253
+ );
254
+ }
255
+ }
256
+ }
257
+
207
258
  // Normal completion
208
259
  return {
209
260
  exitCode: winner.result.exitCode,
@@ -232,9 +283,13 @@ function buildSessionKey(
232
283
  snapshotPath: string | null,
233
284
  env: Record<string, string>,
234
285
  agentSessionKey?: string,
286
+ minimizer?: MinimizerOptions,
235
287
  ): string {
236
288
  const entries = Object.entries(env);
237
289
  entries.sort(([a], [b]) => a.localeCompare(b));
238
290
  const envSerialized = entries.map(([key, value]) => `${key}=${value}`).join("\n");
239
- return [agentSessionKey ?? "", shell, prefix ?? "", snapshotPath ?? "", envSerialized].join("\n");
291
+ const minimizerSerialized = minimizer ? JSON.stringify(minimizer) : "";
292
+ return [agentSessionKey ?? "", shell, prefix ?? "", snapshotPath ?? "", envSerialized, minimizerSerialized].join(
293
+ "\n",
294
+ );
240
295
  }