@oh-my-pi/pi-coding-agent 13.16.0 → 13.16.2
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.
- package/CHANGELOG.md +14 -0
- package/package.json +7 -7
- package/src/commit/agentic/tools/analyze-file.ts +1 -0
- package/src/config/settings-schema.ts +7 -0
- package/src/extensibility/custom-tools/types.ts +3 -0
- package/src/extensibility/extensions/runner.ts +7 -0
- package/src/extensibility/extensions/types.ts +4 -0
- package/src/ipy/cancellation.ts +28 -0
- package/src/ipy/executor.ts +252 -77
- package/src/ipy/kernel.ts +181 -35
- package/src/ipy/modules.ts +39 -4
- package/src/modes/acp/acp-agent.ts +1 -0
- package/src/modes/components/assistant-message.ts +1 -1
- package/src/modes/components/tool-execution.ts +2 -1
- package/src/modes/controllers/extension-ui-controller.ts +3 -0
- package/src/modes/controllers/input-controller.ts +1 -0
- package/src/modes/print-mode.ts +1 -0
- package/src/modes/prompt-action-autocomplete.ts +5 -3
- package/src/modes/rpc/rpc-mode.ts +1 -0
- package/src/prompts/tools/ast-edit.md +1 -1
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/find.md +1 -1
- package/src/prompts/tools/grep.md +2 -2
- package/src/sdk.ts +17 -1
- package/src/session/agent-session.ts +6 -0
- package/src/task/executor.ts +4 -0
- package/src/task/index.ts +2 -0
- package/src/tools/browser.ts +51 -2
- package/src/tools/find.ts +1 -0
- package/src/tools/grep.ts +21 -17
- package/src/tools/index.ts +3 -0
- package/src/tools/python.ts +3 -2
package/src/sdk.ts
CHANGED
|
@@ -9,8 +9,17 @@ import {
|
|
|
9
9
|
import type { Message, Model } from "@oh-my-pi/pi-ai";
|
|
10
10
|
|
|
11
11
|
import { prewarmOpenAICodexResponses } from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
12
|
+
import { SearchDb } from "@oh-my-pi/pi-natives";
|
|
12
13
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
13
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
$env,
|
|
16
|
+
getAgentDbPath,
|
|
17
|
+
getAgentDir,
|
|
18
|
+
getProjectDir,
|
|
19
|
+
getSearchDbDir,
|
|
20
|
+
logger,
|
|
21
|
+
postmortem,
|
|
22
|
+
} from "@oh-my-pi/pi-utils";
|
|
14
23
|
import chalk from "chalk";
|
|
15
24
|
import { AsyncJobManager } from "./async";
|
|
16
25
|
import { createAutoresearchExtension } from "./autoresearch";
|
|
@@ -131,6 +140,8 @@ export interface CreateAgentSessionOptions {
|
|
|
131
140
|
authStorage?: AuthStorage;
|
|
132
141
|
/** Model registry. Default: discoverModels(authStorage, agentDir) */
|
|
133
142
|
modelRegistry?: ModelRegistry;
|
|
143
|
+
/** Shared native search DB for grep/glob/fuzzyFind-backed workflows. */
|
|
144
|
+
searchDb?: SearchDb;
|
|
134
145
|
|
|
135
146
|
/** Model to use. Default: from settings, else first available */
|
|
136
147
|
model?: Model;
|
|
@@ -381,6 +392,7 @@ function createCustomToolContext(ctx: ExtensionContext): CustomToolContext {
|
|
|
381
392
|
sessionManager: ctx.sessionManager,
|
|
382
393
|
modelRegistry: ctx.modelRegistry,
|
|
383
394
|
model: ctx.model,
|
|
395
|
+
searchDb: ctx.searchDb,
|
|
384
396
|
isIdle: ctx.isIdle,
|
|
385
397
|
hasQueuedMessages: ctx.hasPendingMessages,
|
|
386
398
|
abort: ctx.abort,
|
|
@@ -862,6 +874,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
862
874
|
})
|
|
863
875
|
: undefined;
|
|
864
876
|
|
|
877
|
+
const searchDb = options.searchDb ?? new SearchDb(getSearchDbDir(agentDir));
|
|
865
878
|
const pendingActionStore = new PendingActionStore();
|
|
866
879
|
const toolSession: ToolSession = {
|
|
867
880
|
cwd,
|
|
@@ -911,6 +924,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
911
924
|
modelRegistry,
|
|
912
925
|
asyncJobManager,
|
|
913
926
|
pendingActionStore,
|
|
927
|
+
searchDb,
|
|
914
928
|
};
|
|
915
929
|
|
|
916
930
|
// Initialize internal URL router for internal protocols (agent://, artifact://, memory://, skill://, rule://, mcp://, local://)
|
|
@@ -1173,6 +1187,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1173
1187
|
sessionManager,
|
|
1174
1188
|
modelRegistry,
|
|
1175
1189
|
model: agent?.state.model,
|
|
1190
|
+
searchDb,
|
|
1176
1191
|
isIdle: () => !session?.isStreaming,
|
|
1177
1192
|
hasQueuedMessages: () => (session?.queuedMessageCount ?? 0) > 0,
|
|
1178
1193
|
abort: () => session?.abort(),
|
|
@@ -1539,6 +1554,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1539
1554
|
obfuscator,
|
|
1540
1555
|
asyncJobManager,
|
|
1541
1556
|
pendingActionStore,
|
|
1557
|
+
searchDb,
|
|
1542
1558
|
});
|
|
1543
1559
|
|
|
1544
1560
|
if (model?.api === "openai-codex-responses") {
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
modelsAreEqual,
|
|
51
51
|
parseRateLimitReason,
|
|
52
52
|
} from "@oh-my-pi/pi-ai";
|
|
53
|
+
import type { SearchDb } from "@oh-my-pi/pi-natives";
|
|
53
54
|
import { abortableSleep, getAgentDbPath, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
54
55
|
import type { AsyncJob, AsyncJobManager } from "../async";
|
|
55
56
|
import type { Rule } from "../capability/rule";
|
|
@@ -237,6 +238,8 @@ export interface AgentSessionConfig {
|
|
|
237
238
|
obfuscator?: SecretObfuscator;
|
|
238
239
|
/** Pending action store for preview/apply workflows */
|
|
239
240
|
pendingActionStore?: PendingActionStore;
|
|
241
|
+
/** Shared native search DB for grep/glob/fuzzyFind-backed workflows. */
|
|
242
|
+
searchDb?: SearchDb;
|
|
240
243
|
}
|
|
241
244
|
|
|
242
245
|
/** Options for AgentSession.prompt() */
|
|
@@ -348,6 +351,7 @@ export class AgentSession {
|
|
|
348
351
|
readonly agent: Agent;
|
|
349
352
|
readonly sessionManager: SessionManager;
|
|
350
353
|
readonly settings: Settings;
|
|
354
|
+
readonly searchDb: SearchDb | undefined;
|
|
351
355
|
|
|
352
356
|
#asyncJobManager: AsyncJobManager | undefined = undefined;
|
|
353
357
|
#scopedModels: Array<{ model: Model; thinkingLevel?: ThinkingLevel }>;
|
|
@@ -462,6 +466,7 @@ export class AgentSession {
|
|
|
462
466
|
this.agent = config.agent;
|
|
463
467
|
this.sessionManager = config.sessionManager;
|
|
464
468
|
this.settings = config.settings;
|
|
469
|
+
this.searchDb = config.searchDb;
|
|
465
470
|
this.#asyncJobManager = config.asyncJobManager;
|
|
466
471
|
this.#scopedModels = config.scopedModels ?? [];
|
|
467
472
|
this.#thinkingLevel = config.thinkingLevel;
|
|
@@ -1888,6 +1893,7 @@ export class AgentSession {
|
|
|
1888
1893
|
sessionManager: this.sessionManager,
|
|
1889
1894
|
modelRegistry: this.#modelRegistry,
|
|
1890
1895
|
model: this.model,
|
|
1896
|
+
searchDb: this.searchDb,
|
|
1891
1897
|
isIdle: () => !this.isStreaming,
|
|
1892
1898
|
hasQueuedMessages: () => this.queuedMessageCount > 0,
|
|
1893
1899
|
abort: () => {
|
package/src/task/executor.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import type { AgentEvent, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
8
|
+
import type { SearchDb } from "@oh-my-pi/pi-natives";
|
|
8
9
|
import { logger, untilAborted } from "@oh-my-pi/pi-utils";
|
|
9
10
|
import type { TSchema } from "@sinclair/typebox";
|
|
10
11
|
import Ajv, { type ValidateFunction } from "ajv";
|
|
@@ -147,6 +148,7 @@ export interface ExecutorOptions {
|
|
|
147
148
|
mcpManager?: MCPManager;
|
|
148
149
|
authStorage?: AuthStorage;
|
|
149
150
|
modelRegistry?: ModelRegistry;
|
|
151
|
+
searchDb?: SearchDb;
|
|
150
152
|
settings?: Settings;
|
|
151
153
|
}
|
|
152
154
|
|
|
@@ -950,6 +952,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
950
952
|
cwd: worktree ?? cwd,
|
|
951
953
|
authStorage,
|
|
952
954
|
modelRegistry,
|
|
955
|
+
searchDb: options.searchDb,
|
|
953
956
|
settings: subagentSettings,
|
|
954
957
|
model,
|
|
955
958
|
thinkingLevel: effectiveThinkingLevel,
|
|
@@ -1042,6 +1045,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
1042
1045
|
},
|
|
1043
1046
|
{
|
|
1044
1047
|
getModel: () => session.model,
|
|
1048
|
+
getSearchDb: () => session.searchDb,
|
|
1045
1049
|
isIdle: () => !session.isStreaming,
|
|
1046
1050
|
abort: () => session.abort(),
|
|
1047
1051
|
hasPendingMessages: () => session.queuedMessageCount > 0,
|
package/src/task/index.ts
CHANGED
|
@@ -775,6 +775,7 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
|
|
775
775
|
},
|
|
776
776
|
authStorage: this.session.authStorage,
|
|
777
777
|
modelRegistry: this.session.modelRegistry,
|
|
778
|
+
searchDb: this.session.searchDb,
|
|
778
779
|
settings: this.session.settings,
|
|
779
780
|
mcpManager: this.session.mcpManager,
|
|
780
781
|
contextFiles,
|
|
@@ -828,6 +829,7 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
|
|
828
829
|
},
|
|
829
830
|
authStorage: this.session.authStorage,
|
|
830
831
|
modelRegistry: this.session.modelRegistry,
|
|
832
|
+
searchDb: this.session.searchDb,
|
|
831
833
|
settings: this.session.settings,
|
|
832
834
|
mcpManager: this.session.mcpManager,
|
|
833
835
|
contextFiles,
|
package/src/tools/browser.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as fs from "node:fs
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { Readability } from "@mozilla/readability";
|
|
@@ -61,6 +61,54 @@ async function loadPuppeteer(): Promise<typeof Puppeteer> {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* On NixOS, Puppeteer's bundled Chromium is a dynamically-linked FHS binary and
|
|
66
|
+
* cannot run as-is. Detect the platform and resolve a system-installed Chromium
|
|
67
|
+
* so `puppeteer.launch()` can use it instead of the bundled one.
|
|
68
|
+
*
|
|
69
|
+
* Detection order:
|
|
70
|
+
* 1. `chromium` on PATH
|
|
71
|
+
* 2. `chromium-browser` on PATH
|
|
72
|
+
* 3. ~/.nix-profile/bin/chromium (user profile)
|
|
73
|
+
* 4. /run/current-system/sw/bin/chromium (system profile)
|
|
74
|
+
*
|
|
75
|
+
* Returns `undefined` on non-NixOS systems or when no binary is found, which
|
|
76
|
+
* causes Puppeteer to fall back to its default resolution.
|
|
77
|
+
*/
|
|
78
|
+
let _resolvedChromium: string | null | undefined; // undefined = unchecked; null = not found
|
|
79
|
+
function resolveSystemChromium(): string | undefined {
|
|
80
|
+
if (_resolvedChromium !== undefined) return _resolvedChromium ?? undefined;
|
|
81
|
+
try {
|
|
82
|
+
if (!fs.existsSync("/etc/NIXOS")) {
|
|
83
|
+
_resolvedChromium = null;
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
_resolvedChromium = null;
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
const candidates = [
|
|
91
|
+
Bun.which("chromium"),
|
|
92
|
+
Bun.which("chromium-browser"),
|
|
93
|
+
path.join(os.homedir(), ".nix-profile/bin/chromium"),
|
|
94
|
+
"/run/current-system/sw/bin/chromium",
|
|
95
|
+
];
|
|
96
|
+
for (const candidate of candidates) {
|
|
97
|
+
if (candidate) {
|
|
98
|
+
try {
|
|
99
|
+
if (fs.existsSync(candidate)) {
|
|
100
|
+
_resolvedChromium = candidate;
|
|
101
|
+
logger.debug("NixOS: using system Chromium", { path: candidate });
|
|
102
|
+
return candidate;
|
|
103
|
+
}
|
|
104
|
+
} catch {}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
_resolvedChromium = null;
|
|
108
|
+
logger.debug("NixOS detected but no Chromium binary found; Puppeteer may fail to launch");
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
64
112
|
const DEFAULT_VIEWPORT = { width: 1365, height: 768, deviceScaleFactor: 1.25 };
|
|
65
113
|
const STEALTH_IGNORE_DEFAULT_ARGS = [
|
|
66
114
|
"--disable-extensions",
|
|
@@ -548,6 +596,7 @@ export class BrowserTool implements AgentTool<typeof browserSchema, BrowserToolD
|
|
|
548
596
|
this.#browser = await puppeteer.launch({
|
|
549
597
|
headless: this.#currentHeadless,
|
|
550
598
|
defaultViewport: this.#currentHeadless ? initialViewport : null,
|
|
599
|
+
executablePath: resolveSystemChromium(),
|
|
551
600
|
args: launchArgs,
|
|
552
601
|
ignoreDefaultArgs: [...STEALTH_IGNORE_DEFAULT_ARGS],
|
|
553
602
|
});
|
|
@@ -1382,7 +1431,7 @@ export class BrowserTool implements AgentTool<typeof browserSchema, BrowserToolD
|
|
|
1382
1431
|
} else {
|
|
1383
1432
|
dest = path.join(os.tmpdir(), `omp-sshots-${Snowflake.next()}.png`);
|
|
1384
1433
|
}
|
|
1385
|
-
await fs.mkdir(path.dirname(dest), { recursive: true });
|
|
1434
|
+
await fs.promises.mkdir(path.dirname(dest), { recursive: true });
|
|
1386
1435
|
// Full-res buffer when saving to a user-defined location; resized (API copy) for temp-only.
|
|
1387
1436
|
const saveFullRes = !!(paramPath || screenshotDir);
|
|
1388
1437
|
const savedBuffer = saveFullRes ? buffer : resized.buffer;
|
package/src/tools/find.ts
CHANGED
package/src/tools/grep.ts
CHANGED
|
@@ -169,23 +169,27 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
169
169
|
// Run grep
|
|
170
170
|
let result: GrepResult;
|
|
171
171
|
try {
|
|
172
|
-
result = await grep(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
172
|
+
result = await grep(
|
|
173
|
+
{
|
|
174
|
+
pattern: normalizedPattern,
|
|
175
|
+
path: searchPath,
|
|
176
|
+
glob: globFilter,
|
|
177
|
+
type: type?.trim() || undefined,
|
|
178
|
+
ignoreCase,
|
|
179
|
+
multiline: effectiveMultiline,
|
|
180
|
+
hidden: true,
|
|
181
|
+
gitignore: useGitignore,
|
|
182
|
+
cache: false,
|
|
183
|
+
maxCount: internalLimit,
|
|
184
|
+
offset: normalizedOffset > 0 ? normalizedOffset : undefined,
|
|
185
|
+
contextBefore: normalizedContextBefore,
|
|
186
|
+
contextAfter: normalizedContextAfter,
|
|
187
|
+
maxColumns: DEFAULT_MAX_COLUMN,
|
|
188
|
+
mode: effectiveOutputMode,
|
|
189
|
+
},
|
|
190
|
+
undefined,
|
|
191
|
+
this.session.searchDb,
|
|
192
|
+
);
|
|
189
193
|
} catch (err) {
|
|
190
194
|
if (err instanceof Error && err.message.startsWith("regex parse error")) {
|
|
191
195
|
throw new ToolError(err.message);
|
package/src/tools/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import type { SearchDb } from "@oh-my-pi/pi-natives";
|
|
2
3
|
import { $env, logger } from "@oh-my-pi/pi-utils";
|
|
3
4
|
import type { AsyncJobManager } from "../async";
|
|
4
5
|
import type { PromptTemplate } from "../config/prompt-templates";
|
|
@@ -144,6 +145,8 @@ export interface ToolSession {
|
|
|
144
145
|
asyncJobManager?: AsyncJobManager;
|
|
145
146
|
/** Settings instance for passing to subagents */
|
|
146
147
|
settings: Settings;
|
|
148
|
+
/** Shared native search DB for grep/glob/fuzzyFind-backed workflows. */
|
|
149
|
+
searchDb?: SearchDb;
|
|
147
150
|
/** Plan mode state (if active) */
|
|
148
151
|
getPlanModeState?: () => PlanModeState | undefined;
|
|
149
152
|
/** Get compact conversation context for subagents (excludes tool results, system prompts) */
|
package/src/tools/python.ts
CHANGED
|
@@ -180,7 +180,8 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
|
180
180
|
// Clamp to reasonable range: 1s - 600s (10 min)
|
|
181
181
|
const timeoutSec = clampTimeout("python", rawTimeout);
|
|
182
182
|
const timeoutMs = timeoutSec * 1000;
|
|
183
|
-
const
|
|
183
|
+
const deadlineMs = Date.now() + timeoutMs;
|
|
184
|
+
const timeoutSignal = AbortSignal.timeout(Math.max(0, deadlineMs - Date.now()));
|
|
184
185
|
const combinedSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
|
|
185
186
|
let outputSink: OutputSink | undefined;
|
|
186
187
|
let outputSummary: OutputSummary | undefined;
|
|
@@ -267,7 +268,7 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
|
267
268
|
const sessionId = sessionFile ? `session:${sessionFile}:cwd:${commandCwd}` : `cwd:${commandCwd}`;
|
|
268
269
|
const baseExecutorOptions: Omit<PythonExecutorOptions, "reset"> = {
|
|
269
270
|
cwd: commandCwd,
|
|
270
|
-
|
|
271
|
+
deadlineMs,
|
|
271
272
|
signal: combinedSignal,
|
|
272
273
|
sessionId,
|
|
273
274
|
kernelMode: this.session.settings.get("python.kernelMode"),
|