@oh-my-pi/pi-coding-agent 9.2.0 → 9.2.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 +54 -0
- package/package.json +7 -7
- package/src/cli/stats-cli.ts +1 -0
- package/src/commit/agentic/agent.ts +4 -0
- package/src/commit/agentic/index.ts +5 -1
- package/src/commit/git/operations.ts +1 -0
- package/src/debug/index.ts +1 -1
- package/src/extensibility/plugins/installer.ts +2 -0
- package/src/extensibility/plugins/manager.ts +3 -0
- package/src/ipy/gateway-coordinator.ts +1 -0
- package/src/lsp/clients/biome-client.ts +1 -0
- package/src/lsp/index.ts +1 -0
- package/src/lsp/lspmux.ts +1 -0
- package/src/session/auth-storage.ts +26 -5
- package/src/utils/clipboard.ts +13 -5
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,60 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [9.2.2] - 2026-01-31
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Added grep CLI subcommand (`omp grep`) for testing pattern matching
|
|
9
|
+
- Added fuzzy matching for model resolution with scoring and ranking fallback
|
|
10
|
+
- Added 'Open: artifact folder' menu option to debug selector for quick access to session artifacts
|
|
11
|
+
- Added Kimi API format setting for selecting between OpenAI and Anthropic formats
|
|
12
|
+
- Added Codex and Gemini web search providers with OAuth and grounding support
|
|
13
|
+
- Added /debug command with interactive menu for profiling, heap snapshots, session dumps, and diagnostics
|
|
14
|
+
- Added configurable ask timeout and notification settings
|
|
15
|
+
- Added gitignore-aware project tree scanning with ripgrep integration
|
|
16
|
+
- Added project tree visualization to system prompts with configurable depth and entry limits
|
|
17
|
+
- Added reset() method to CountdownTimer with integration into HookSelectorComponent
|
|
18
|
+
- Added custom message support to AgentSession via promptCustomMessage() method
|
|
19
|
+
- Added skill message component for rendering /skill command messages as compact entries
|
|
20
|
+
- Added model preference matching system for intelligent model selection based on usage history
|
|
21
|
+
- Added designer agent with UI/UX review and accessibility audit capabilities
|
|
22
|
+
- Added model-specific edit variant configuration for patch/replace modes
|
|
23
|
+
- Added automatic browser opening when stats dashboard starts
|
|
24
|
+
- Added model statistics table and TTFT/throughput metrics to stats dashboard
|
|
25
|
+
- Added artifact allocation for truncated fetch responses to preserve full content
|
|
26
|
+
- Added 30-second timeout to ask tool with auto-selection of recommended option
|
|
27
|
+
- Added recommended parameter (0-indexed) to ask tool for specifying default option
|
|
28
|
+
- Added JTD to TypeScript converter for rendering schemas in system prompts
|
|
29
|
+
- Added tools list to system prompt for better agent awareness
|
|
30
|
+
- Added synthetic message flag for system-injected prompts
|
|
31
|
+
- Added session compaction enhancements with auto-continue, tool pruning, and remote endpoint support
|
|
32
|
+
- Added detection and rendering of missing complete tool warning in subagent output
|
|
33
|
+
- Added outline UI components for bordered list containers
|
|
34
|
+
- Added macOS NFD normalization and curly quote variant resolution for file paths
|
|
35
|
+
- Enhanced session compaction with dynamic token ratio adjustment and improved summary preservation
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
- Simplified find tool API by consolidating path and pattern parameters
|
|
39
|
+
- Replaced bulk file loading with streaming for read tool to reduce memory overhead
|
|
40
|
+
- Migrated grep and find tools to WASM-based implementation
|
|
41
|
+
- Replaced ripgrep-based file listing with glob-based file discovery for project scans
|
|
42
|
+
- Updated minimum Bun runtime requirement to >=1.3.7
|
|
43
|
+
- Renamed task parameter from output to schema
|
|
44
|
+
- Renamed complete tool to submit_result for clarity and consistency
|
|
45
|
+
- Improved output preview logic: shows full output for ≤30 lines, truncates to 10 lines for larger output
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
- Enhanced error reporting with debug stack trace when DEBUG env is set
|
|
49
|
+
- Improved OAuth token refresh error handling to distinguish transient vs definitive failures
|
|
50
|
+
- Added windowsHide option to child process spawn calls to prevent console windows on Windows
|
|
51
|
+
- External edits to config.yml are now preserved when omp reloads or saves settings
|
|
52
|
+
- Exposed LSP server startup errors in session display and logs
|
|
53
|
+
- Improved error handling and security in agent storage initialization with restrictive file permissions
|
|
54
|
+
- Fixed LSP server display showing unknown when server warmup fails
|
|
55
|
+
- Preserved null timeout when user disables ask timeout setting
|
|
56
|
+
- Removed incorrect timeout unit conversion logic in cursor, fetch, gemini-image, and ssh tools
|
|
57
|
+
- Blocked /fork command while streaming to prevent split session logs
|
|
58
|
+
|
|
5
59
|
## [9.0.0] - 2026-01-29
|
|
6
60
|
|
|
7
61
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
3
|
-
"version": "9.2.
|
|
3
|
+
"version": "9.2.2",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"ompConfig": {
|
|
@@ -79,12 +79,12 @@
|
|
|
79
79
|
"test": "bun test"
|
|
80
80
|
},
|
|
81
81
|
"dependencies": {
|
|
82
|
-
"@oh-my-pi/omp-stats": "9.2.
|
|
83
|
-
"@oh-my-pi/pi-agent-core": "9.2.
|
|
84
|
-
"@oh-my-pi/pi-ai": "9.2.
|
|
85
|
-
"@oh-my-pi/pi-natives": "9.2.
|
|
86
|
-
"@oh-my-pi/pi-tui": "9.2.
|
|
87
|
-
"@oh-my-pi/pi-utils": "9.2.
|
|
82
|
+
"@oh-my-pi/omp-stats": "9.2.2",
|
|
83
|
+
"@oh-my-pi/pi-agent-core": "9.2.2",
|
|
84
|
+
"@oh-my-pi/pi-ai": "9.2.2",
|
|
85
|
+
"@oh-my-pi/pi-natives": "9.2.2",
|
|
86
|
+
"@oh-my-pi/pi-tui": "9.2.2",
|
|
87
|
+
"@oh-my-pi/pi-utils": "9.2.2",
|
|
88
88
|
"@openai/agents": "^0.4.4",
|
|
89
89
|
"@sinclair/typebox": "^0.34.48",
|
|
90
90
|
"ajv": "^8.17.1",
|
package/src/cli/stats-cli.ts
CHANGED
|
@@ -114,6 +114,7 @@ export async function runStatsCommand(cmd: StatsCommandArgs): Promise<void> {
|
|
|
114
114
|
Bun.spawn(openCommand === "cmd" ? ["cmd", "/c", "start", url] : [openCommand, url], {
|
|
115
115
|
stdout: "ignore",
|
|
116
116
|
stderr: "ignore",
|
|
117
|
+
windowsHide: true,
|
|
117
118
|
}).unref();
|
|
118
119
|
|
|
119
120
|
console.log("Press Ctrl+C to stop\n");
|
|
@@ -113,6 +113,10 @@ export async function runCommitAgentSession(input: CommitAgentInput): Promise<Co
|
|
|
113
113
|
messageCount += 1;
|
|
114
114
|
isThinking = false;
|
|
115
115
|
clearThinkingLine();
|
|
116
|
+
const assistantMessage = event.message as { stopReason?: string; errorMessage?: string };
|
|
117
|
+
if (assistantMessage.stopReason === "error" && assistantMessage.errorMessage) {
|
|
118
|
+
writeStdout(`● Error: ${assistantMessage.errorMessage}`);
|
|
119
|
+
}
|
|
116
120
|
const messageText = extractMessageText(event.message?.content ?? []);
|
|
117
121
|
if (messageText) {
|
|
118
122
|
writeAssistantMessage(messageText);
|
|
@@ -134,7 +134,11 @@ export async function runAgenticCommit(args: CommitCommandArgs): Promise<void> {
|
|
|
134
134
|
existingChangelogEntries,
|
|
135
135
|
});
|
|
136
136
|
} catch (error) {
|
|
137
|
-
|
|
137
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
138
|
+
writeStderr(`Agent error: ${errorMessage}`);
|
|
139
|
+
if (error instanceof Error && error.stack && process.env.DEBUG) {
|
|
140
|
+
writeStderr(error.stack);
|
|
141
|
+
}
|
|
138
142
|
writeStdout("● Using fallback commit generation...");
|
|
139
143
|
commitState = { proposal: generateFallbackProposal(numstat) };
|
|
140
144
|
usedFallback = true;
|
package/src/debug/index.ts
CHANGED
|
@@ -310,7 +310,7 @@ export class DebugSelectorComponent extends Container {
|
|
|
310
310
|
const [cmd, ...args] = openArgs;
|
|
311
311
|
|
|
312
312
|
try {
|
|
313
|
-
Bun.spawn([cmd, ...args], { stdout: "ignore", stderr: "ignore" }).unref();
|
|
313
|
+
Bun.spawn([cmd, ...args], { stdout: "ignore", stderr: "ignore", windowsHide: true }).unref();
|
|
314
314
|
this.ctx.showStatus(`Opened: ${artifactsDir}`);
|
|
315
315
|
} catch (err) {
|
|
316
316
|
this.ctx.showError(`Failed to open artifact folder: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -50,6 +50,7 @@ export async function installPlugin(packageName: string): Promise<InstalledPlugi
|
|
|
50
50
|
stdin: "ignore",
|
|
51
51
|
stdout: "pipe",
|
|
52
52
|
stderr: "pipe",
|
|
53
|
+
windowsHide: true,
|
|
53
54
|
});
|
|
54
55
|
|
|
55
56
|
const exitCode = await proc.exited;
|
|
@@ -91,6 +92,7 @@ export async function uninstallPlugin(name: string): Promise<void> {
|
|
|
91
92
|
stdin: "ignore",
|
|
92
93
|
stdout: "pipe",
|
|
93
94
|
stderr: "pipe",
|
|
95
|
+
windowsHide: true,
|
|
94
96
|
});
|
|
95
97
|
|
|
96
98
|
const exitCode = await proc.exited;
|
|
@@ -159,6 +159,7 @@ export class PluginManager {
|
|
|
159
159
|
stdin: "ignore",
|
|
160
160
|
stdout: "pipe",
|
|
161
161
|
stderr: "pipe",
|
|
162
|
+
windowsHide: true,
|
|
162
163
|
});
|
|
163
164
|
|
|
164
165
|
const exitCode = await proc.exited;
|
|
@@ -239,6 +240,7 @@ export class PluginManager {
|
|
|
239
240
|
stdin: "ignore",
|
|
240
241
|
stdout: "pipe",
|
|
241
242
|
stderr: "pipe",
|
|
243
|
+
windowsHide: true,
|
|
242
244
|
});
|
|
243
245
|
|
|
244
246
|
const exitCode = await proc.exited;
|
|
@@ -621,6 +623,7 @@ export class PluginManager {
|
|
|
621
623
|
stdin: "ignore",
|
|
622
624
|
stdout: "pipe",
|
|
623
625
|
stderr: "pipe",
|
|
626
|
+
windowsHide: true,
|
|
624
627
|
});
|
|
625
628
|
return (await proc.exited) === 0;
|
|
626
629
|
} catch {
|
package/src/lsp/index.ts
CHANGED
package/src/lsp/lspmux.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
loginGitHubCopilot,
|
|
20
20
|
loginKimi,
|
|
21
21
|
loginOpenAICodex,
|
|
22
|
+
loginOpenCode,
|
|
22
23
|
type OAuthController,
|
|
23
24
|
type OAuthCredentials,
|
|
24
25
|
type OAuthProvider,
|
|
@@ -782,6 +783,11 @@ export class AuthStorage {
|
|
|
782
783
|
ctrl.onProgress ? () => ctrl.onProgress?.("Waiting for browser authentication...") : undefined,
|
|
783
784
|
);
|
|
784
785
|
break;
|
|
786
|
+
case "opencode": {
|
|
787
|
+
const apiKey = await loginOpenCode(ctrl);
|
|
788
|
+
credentials = { access: apiKey, refresh: apiKey, expires: Number.MAX_SAFE_INTEGER };
|
|
789
|
+
break;
|
|
790
|
+
}
|
|
785
791
|
default:
|
|
786
792
|
throw new Error(`Unknown OAuth provider: ${provider}`);
|
|
787
793
|
}
|
|
@@ -1281,14 +1287,29 @@ export class AuthStorage {
|
|
|
1281
1287
|
this.recordSessionCredential(provider, sessionId, "oauth", selection.index);
|
|
1282
1288
|
return result.apiKey;
|
|
1283
1289
|
} catch (error) {
|
|
1284
|
-
|
|
1290
|
+
const errorMsg = String(error);
|
|
1291
|
+
// Only remove credentials for definitive auth failures
|
|
1292
|
+
// Keep credentials for transient errors (network, 5xx) and block temporarily
|
|
1293
|
+
const isDefinitiveFailure =
|
|
1294
|
+
/invalid_grant|invalid_token|revoked|unauthorized|expired.*refresh|refresh.*expired/i.test(errorMsg) ||
|
|
1295
|
+
(/401|403/.test(errorMsg) && !/timeout|network|fetch failed|ECONNREFUSED/i.test(errorMsg));
|
|
1296
|
+
|
|
1297
|
+
logger.warn("OAuth token refresh failed", {
|
|
1285
1298
|
provider,
|
|
1286
1299
|
index: selection.index,
|
|
1287
|
-
error:
|
|
1300
|
+
error: errorMsg,
|
|
1301
|
+
isDefinitiveFailure,
|
|
1288
1302
|
});
|
|
1289
|
-
|
|
1290
|
-
if (
|
|
1291
|
-
|
|
1303
|
+
|
|
1304
|
+
if (isDefinitiveFailure) {
|
|
1305
|
+
// Permanently remove invalid credentials
|
|
1306
|
+
this.removeCredentialAt(provider, selection.index);
|
|
1307
|
+
if (this.getCredentialsForProvider(provider).some(credential => credential.type === "oauth")) {
|
|
1308
|
+
return this.getApiKey(provider, sessionId, options);
|
|
1309
|
+
}
|
|
1310
|
+
} else {
|
|
1311
|
+
// Block temporarily for transient failures (5 minutes)
|
|
1312
|
+
this.markCredentialBlocked(providerKey, selection.index, this.usageNow() + 5 * 60 * 1000);
|
|
1292
1313
|
}
|
|
1293
1314
|
}
|
|
1294
1315
|
|
package/src/utils/clipboard.ts
CHANGED
|
@@ -37,25 +37,33 @@ export async function copyToClipboard(text: string): Promise<void> {
|
|
|
37
37
|
|
|
38
38
|
try {
|
|
39
39
|
if (p === "darwin") {
|
|
40
|
-
await Bun.spawn(["pbcopy"], { stdin: Buffer.from(text), timeout }).exited;
|
|
40
|
+
await Bun.spawn(["pbcopy"], { stdin: Buffer.from(text), timeout, windowsHide: true }).exited;
|
|
41
41
|
} else if (p === "win32") {
|
|
42
|
-
await Bun.spawn(["clip"], { stdin: Buffer.from(text), timeout }).exited;
|
|
42
|
+
await Bun.spawn(["clip"], { stdin: Buffer.from(text), timeout, windowsHide: true }).exited;
|
|
43
43
|
} else {
|
|
44
44
|
const wayland = isWaylandSession();
|
|
45
45
|
if (wayland) {
|
|
46
46
|
const wlCopyPath = Bun.which("wl-copy");
|
|
47
47
|
if (wlCopyPath) {
|
|
48
48
|
// Fire-and-forget: wl-copy may not exit promptly, so we unref to avoid blocking
|
|
49
|
-
void Bun.spawn([wlCopyPath], { stdin: Buffer.from(text), timeout }).unref();
|
|
49
|
+
void Bun.spawn([wlCopyPath], { stdin: Buffer.from(text), timeout, windowsHide: true }).unref();
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
// Linux - try xclip first, fall back to xsel
|
|
55
55
|
try {
|
|
56
|
-
await Bun.spawn(["xclip", "-selection", "clipboard"], {
|
|
56
|
+
await Bun.spawn(["xclip", "-selection", "clipboard"], {
|
|
57
|
+
stdin: Buffer.from(text),
|
|
58
|
+
timeout,
|
|
59
|
+
windowsHide: true,
|
|
60
|
+
}).exited;
|
|
57
61
|
} catch {
|
|
58
|
-
await Bun.spawn(["xsel", "--clipboard", "--input"], {
|
|
62
|
+
await Bun.spawn(["xsel", "--clipboard", "--input"], {
|
|
63
|
+
stdin: Buffer.from(text),
|
|
64
|
+
timeout,
|
|
65
|
+
windowsHide: true,
|
|
66
|
+
}).exited;
|
|
59
67
|
}
|
|
60
68
|
}
|
|
61
69
|
} catch (error) {
|