@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.
- package/CHANGELOG.md +59 -0
- package/package.json +19 -19
- package/src/cli/args.ts +10 -1
- package/src/cli/shell-cli.ts +15 -3
- package/src/config/settings-schema.ts +60 -1
- package/src/dap/session.ts +8 -2
- package/src/debug/system-info.ts +6 -2
- package/src/discovery/claude.ts +58 -36
- package/src/discovery/opencode.ts +20 -2
- package/src/edit/index.ts +3 -1
- package/src/edit/modes/chunk.ts +133 -53
- package/src/edit/modes/hashline.ts +36 -11
- package/src/edit/renderer.ts +98 -133
- package/src/edit/streaming.ts +351 -0
- package/src/exec/bash-executor.ts +60 -5
- package/src/internal-urls/docs-index.generated.ts +5 -5
- package/src/internal-urls/pi-protocol.ts +0 -2
- package/src/lsp/client.ts +22 -6
- package/src/lsp/defaults.json +2 -1
- package/src/lsp/index.ts +53 -10
- package/src/lsp/types.ts +2 -0
- package/src/modes/acp/acp-agent.ts +76 -2
- package/src/modes/components/assistant-message.ts +1 -34
- package/src/modes/components/hook-editor.ts +1 -1
- package/src/modes/components/tool-execution.ts +111 -101
- package/src/modes/controllers/input-controller.ts +1 -1
- package/src/modes/interactive-mode.ts +0 -2
- package/src/modes/theme/mermaid-cache.ts +13 -52
- package/src/modes/theme/theme.ts +2 -2
- package/src/prompts/system/system-prompt.md +1 -1
- package/src/prompts/tools/ast-grep.md +1 -0
- package/src/prompts/tools/browser.md +1 -0
- package/src/prompts/tools/chunk-edit.md +25 -22
- package/src/prompts/tools/gh-pr-push.md +2 -1
- package/src/prompts/tools/grep.md +4 -3
- package/src/prompts/tools/lsp.md +6 -0
- package/src/prompts/tools/read-chunk.md +46 -7
- package/src/prompts/tools/read.md +7 -4
- package/src/sdk.ts +8 -5
- package/src/session/agent-session.ts +36 -20
- package/src/session/session-manager.ts +228 -57
- package/src/session/streaming-output.ts +11 -0
- package/src/system-prompt.ts +7 -2
- package/src/task/executor.ts +1 -0
- package/src/tools/ast-edit.ts +37 -2
- package/src/tools/bash.ts +75 -12
- package/src/tools/find.ts +19 -26
- package/src/tools/gh.ts +6 -16
- package/src/tools/grep.ts +94 -37
- package/src/tools/path-utils.ts +31 -3
- package/src/tools/resolve.ts +12 -3
- package/src/tools/sqlite-reader.ts +116 -3
- package/src/tools/vim.ts +1 -1
- package/src/web/search/providers/codex.ts +129 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,65 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [14.3.0] - 2026-04-25
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added Markdown pipe-table `row_N` chunk selectors for row-level table edits.
|
|
10
|
+
- Added `resolveToolAlias` export so tool names in CLI and session setup are normalized to canonical names, including mapping legacy `read` references to `open`
|
|
11
|
+
- Added new `open` and `open-chunk` tool prompt documentation pages to describe canonical `open` usage for local files/directories, chunk reads, and URLs
|
|
12
|
+
- Added full-output retrieval metadata to minimized shell command output by appending an `artifact://<id>` footer with byte counts, allowing users to open the original unminimized command output
|
|
13
|
+
- Added streaming preview API exports from the package (`resolveEditMode`, `EDIT_MODE_STRATEGIES`, and chunk preview helpers) so editors can reuse mode-aware edit preview logic programmatically
|
|
14
|
+
- Added `shellMinimizer` configuration options (`enabled`, `settingsPath`, `only`, `except`, and `maxCaptureBytes`) so users can control shell output minimization behavior
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Changed the canonical file/URL reader tool from `read` to `open` across default tool lists and routing, including system prompts, plan mode, cursor handlers, and runtime tool registration
|
|
19
|
+
- Changed runtime and UI handling to render and track `open` tool calls as first-class (with `read` accepted as legacy alias), including ACP mapping, session observers, and streaming message groups
|
|
20
|
+
- Changed chunk edit guidance to document parser-specific region behavior, including TypeScript decorator/JSDoc sibling chunks, Python docstrings as body content, Python opaque nested chunks, Markdown whole-chunk fallbacks, ID volatility, and indentation display differences
|
|
21
|
+
- Changed chunk deletion in chunk edit mode to require explicit `delete: true`; `write: null` and bare `{ path }` entries now fail with guidance instead of deleting content.
|
|
22
|
+
- Changed chunk edit validation to reject entries with multiple operation fields instead of choosing one and ignoring the rest.
|
|
23
|
+
- Changed chunk edit validation to reject `write: ""` as an accidental destructive empty replacement; use the open tool for inspection or `delete: true` for deletion.
|
|
24
|
+
- Changed chunk edit responses to warn when appending or prepending to a container without `~`, since that inserts outside the container rather than inside its body.
|
|
25
|
+
- Changed fetch output logging so URL-fetch artifacts now use `.open.log` naming instead of `.read.log`
|
|
26
|
+
- Changed Bash interception guidance and errors to recommend `open` in place of `read` for cat/head/tail-style commands
|
|
27
|
+
- Changed exported SDK tool surface to expose `OpenTool` as canonical and keep `ReadTool` as a compatibility alias
|
|
28
|
+
- Changed session list loading to use parallel workers and fixed-size prefix reads per session file, reducing latency when loading many or large sessions
|
|
29
|
+
- Changed edit call rendering to use mode-aware streaming diff previews, including multi-file chunk edit previews grouped by file path while arguments are still streaming
|
|
30
|
+
- Changed shell execution in both interactive and non-interactive modes to route command output through the configured shell output minimizer
|
|
31
|
+
- Changed default behavior so shell output minimization can now be toggled from settings without code changes
|
|
32
|
+
- Changed shell output minimization to leave compound and piped commands unchanged; only a single eligible whole command is captured and minimized after it exits
|
|
33
|
+
|
|
34
|
+
### Removed
|
|
35
|
+
|
|
36
|
+
- Removed the chunk edit `read: true` operation; use the open tool to inspect chunks without modifying files.
|
|
37
|
+
- Removed the `replace: { old, new }` chunk edit operation. Use `write` or `insert` for chunk edits instead.
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- Fixed startup crashes on Linux systems where Bun's `os.cpus()` fails on non-contiguous CPU numbering ([#779](https://github.com/can1357/oh-my-pi/issues/779))
|
|
42
|
+
- Fixed `gh_pr_push` so branches without `gh_pr_checkout` metadata fail instead of falling back to the tracked merge branch, and updated the GitHub tool setting copy to stop calling the tool group read-only ([#778](https://github.com/can1357/oh-my-pi/issues/778))
|
|
43
|
+
- Fixed session list metadata extraction to better populate session titles and first-user summaries from partial session data when full JSONL parsing is unavailable
|
|
44
|
+
- Fixed shell execution output to replace raw streamed bash output with the minimizer’s rewritten text before final output while still preserving the full original output as artifact metadata
|
|
45
|
+
- Fixed bash command minimization to save the full unminimized output as a `bash-original` artifact during AgentSession shell execution, enabling `artifact://` access to complete command output
|
|
46
|
+
- Fixed streaming chunk previews that could display an incomplete trailing edit as a deletion when partial JSON temporarily converted in-flight values to `null`
|
|
47
|
+
- Fixed edit streaming preview updates to cancel obsolete in-flight computations and avoid rendering stale previews as args change
|
|
48
|
+
- Fixed chunk edits to reject unsafe `^`/`~` writes on code leaf chunks instead of falling back to whole-chunk replacement and risking structural indentation corruption
|
|
49
|
+
- Fixed chunk `replace` operations to dedent multiline replacement snippets before reapplying the matched source indentation, preventing Python nested replacements from compounding indentation on repeated edits.
|
|
50
|
+
- Fixed Go chunk trees to classify `package` clauses separately from imports and to avoid duplicating method receivers in method summaries.
|
|
51
|
+
- Fixed chunk path-not-found guidance so it recommends `sel="?"` without claiming the already-shown listing must be re-read.
|
|
52
|
+
- Fixed Markdown chunk appends to preserve blank-line separators after line-oriented inserts such as table rows
|
|
53
|
+
- Fixed Markdown section region-fallback warnings to call out child chunks that will be replaced by whole-section edits.
|
|
54
|
+
- Fixed rejected chunk-edit errors to distinguish current file content from hypothetical post-edit parse-error previews and to state when a same-file batch was rolled back.
|
|
55
|
+
- Fixed unsafe Python head-region edits by rejecting decorated Python `^` writes and Python `^` deletes that can orphan indented bodies while still parsing.
|
|
56
|
+
- Fixed Markdown table-row appends so row-shaped content lands inside the table block instead of after the trailing blank-line separator.
|
|
57
|
+
- Fixed Markdown root writes to preserve fenced-code indentation verbatim.
|
|
58
|
+
- Fixed Rust enum-variant replacement matching so trailing commas are included consistently with whole-variant writes.
|
|
59
|
+
- Fixed streaming edit call headers to keep showing the target file path while the edit arguments are still arriving
|
|
60
|
+
- Fixed Mermaid fenced markdown rendering in assistant messages on terminals without image protocol support ([#650](https://github.com/can1357/oh-my-pi/issues/650))
|
|
61
|
+
- Fixed chunk edit path parsing so plan-mode edits to section-addressed `local://PLAN.md:<selector>` paths are classified as writes to the plan file
|
|
62
|
+
- Fixed SQLite `read` helper queries to reject `where=` clauses with SQL control syntax that could override the structured selector's pagination; raw SQL remains available through `q=SELECT ...`
|
|
63
|
+
|
|
5
64
|
## [14.2.0] - 2026-04-23
|
|
6
65
|
|
|
7
66
|
### Added
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "14.
|
|
4
|
+
"version": "14.3.0",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/can1357/oh-my-pi",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -44,31 +44,31 @@
|
|
|
44
44
|
"generate-template": "bun scripts/generate-template.ts"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@agentclientprotocol/sdk": "0.
|
|
48
|
-
"@mozilla/readability": "^0.6",
|
|
49
|
-
"@oh-my-pi/omp-stats": "14.
|
|
50
|
-
"@oh-my-pi/pi-agent-core": "14.
|
|
51
|
-
"@oh-my-pi/pi-ai": "14.
|
|
52
|
-
"@oh-my-pi/pi-natives": "14.
|
|
53
|
-
"@oh-my-pi/pi-tui": "14.
|
|
54
|
-
"@oh-my-pi/pi-utils": "14.
|
|
55
|
-
"@sinclair/typebox": "^0.34",
|
|
56
|
-
"@xterm/headless": "^6.0",
|
|
57
|
-
"ajv": "^8.
|
|
58
|
-
"chalk": "^5.6",
|
|
59
|
-
"diff": "^
|
|
47
|
+
"@agentclientprotocol/sdk": "0.20.0",
|
|
48
|
+
"@mozilla/readability": "^0.6.0",
|
|
49
|
+
"@oh-my-pi/omp-stats": "14.3.0",
|
|
50
|
+
"@oh-my-pi/pi-agent-core": "14.3.0",
|
|
51
|
+
"@oh-my-pi/pi-ai": "14.3.0",
|
|
52
|
+
"@oh-my-pi/pi-natives": "14.3.0",
|
|
53
|
+
"@oh-my-pi/pi-tui": "14.3.0",
|
|
54
|
+
"@oh-my-pi/pi-utils": "14.3.0",
|
|
55
|
+
"@sinclair/typebox": "^0.34.49",
|
|
56
|
+
"@xterm/headless": "^6.0.0",
|
|
57
|
+
"ajv": "^8.20.0",
|
|
58
|
+
"chalk": "^5.6.2",
|
|
59
|
+
"diff": "^9.0.0",
|
|
60
60
|
"fflate": "0.8.2",
|
|
61
61
|
"handlebars": "^4.7.9",
|
|
62
|
-
"linkedom": "^0.18",
|
|
63
|
-
"lru-cache": "11.3.
|
|
64
|
-
"markit-ai": "0.5.
|
|
65
|
-
"puppeteer": "^24.
|
|
62
|
+
"linkedom": "^0.18.12",
|
|
63
|
+
"lru-cache": "11.3.5",
|
|
64
|
+
"markit-ai": "0.5.3",
|
|
65
|
+
"puppeteer": "^24.42.0",
|
|
66
66
|
"turndown": "7.2.4",
|
|
67
67
|
"turndown-plugin-gfm": "1.0.2",
|
|
68
68
|
"zod": "4.3.6"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
-
"@types/bun": "^1.3",
|
|
71
|
+
"@types/bun": "^1.3.13",
|
|
72
72
|
"@types/turndown": "5.0.6"
|
|
73
73
|
},
|
|
74
74
|
"engines": {
|
package/src/cli/args.ts
CHANGED
|
@@ -60,7 +60,16 @@ export function parseArgs(args: string[], extensionFlags?: Map<string, { type: "
|
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
for (let i = 0; i < args.length; i++) {
|
|
63
|
-
|
|
63
|
+
let arg = args[i];
|
|
64
|
+
|
|
65
|
+
// Support --flag=value syntax (e.g. --tools=ask,read)
|
|
66
|
+
if (arg.startsWith("--") && arg.includes("=")) {
|
|
67
|
+
const eqIdx = arg.indexOf("=");
|
|
68
|
+
const value = arg.slice(eqIdx + 1);
|
|
69
|
+
arg = arg.slice(0, eqIdx);
|
|
70
|
+
// Insert the value so the existing "args[++i]" logic picks it up
|
|
71
|
+
args.splice(i + 1, 0, value);
|
|
72
|
+
}
|
|
64
73
|
|
|
65
74
|
if (arg === "--help" || arg === "-h") {
|
|
66
75
|
result.help = true;
|
package/src/cli/shell-cli.ts
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import * as path from "node:path";
|
|
7
7
|
import { createInterface } from "node:readline/promises";
|
|
8
|
-
import { Shell } from "@oh-my-pi/pi-natives";
|
|
8
|
+
import { type MinimizerOptions, Shell } from "@oh-my-pi/pi-natives";
|
|
9
9
|
import { APP_NAME, getProjectDir } from "@oh-my-pi/pi-utils";
|
|
10
10
|
import chalk from "chalk";
|
|
11
|
-
import { Settings } from "../config/settings";
|
|
11
|
+
import { Settings, type ShellMinimizerSettings } from "../config/settings";
|
|
12
12
|
import { getOrCreateSnapshot } from "../utils/shell-snapshot";
|
|
13
13
|
|
|
14
14
|
export interface ShellCommandArgs {
|
|
@@ -41,6 +41,17 @@ export function parseShellArgs(args: string[]): ShellCommandArgs | undefined {
|
|
|
41
41
|
return result;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
function buildMinimizerOptions(group: ShellMinimizerSettings): MinimizerOptions | undefined {
|
|
45
|
+
if (!group.enabled) return undefined;
|
|
46
|
+
return {
|
|
47
|
+
enabled: true,
|
|
48
|
+
settingsPath: group.settingsPath || undefined,
|
|
49
|
+
only: group.only.length > 0 ? group.only : undefined,
|
|
50
|
+
except: group.except.length > 0 ? group.except : undefined,
|
|
51
|
+
maxCaptureBytes: group.maxCaptureBytes,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
44
55
|
export async function runShellCommand(cmd: ShellCommandArgs): Promise<void> {
|
|
45
56
|
if (!process.stdin.isTTY) {
|
|
46
57
|
process.stderr.write("Error: shell console requires an interactive TTY.\n");
|
|
@@ -51,7 +62,8 @@ export async function runShellCommand(cmd: ShellCommandArgs): Promise<void> {
|
|
|
51
62
|
const settings = await Settings.init({ cwd });
|
|
52
63
|
const { shell, env: shellEnv } = settings.getShellConfig();
|
|
53
64
|
const snapshotPath = cmd.noSnapshot || !shell.includes("bash") ? null : await getOrCreateSnapshot(shell, shellEnv);
|
|
54
|
-
const
|
|
65
|
+
const minimizer = buildMinimizerOptions(settings.getGroup("shellMinimizer"));
|
|
66
|
+
const shellSession = new Shell({ sessionEnv: shellEnv, snapshotPath: snapshotPath ?? undefined, minimizer });
|
|
55
67
|
|
|
56
68
|
let active = false;
|
|
57
69
|
let lastChar: string | null = null;
|
|
@@ -1123,6 +1123,39 @@ export const SETTINGS_SCHEMA = {
|
|
|
1123
1123
|
},
|
|
1124
1124
|
"bashInterceptor.patterns": { type: "array", default: DEFAULT_BASH_INTERCEPTOR_RULES },
|
|
1125
1125
|
|
|
1126
|
+
// Shell output minimizer
|
|
1127
|
+
"shellMinimizer.enabled": {
|
|
1128
|
+
type: "boolean",
|
|
1129
|
+
default: true,
|
|
1130
|
+
ui: {
|
|
1131
|
+
tab: "editing",
|
|
1132
|
+
label: "Shell Minimizer",
|
|
1133
|
+
description: "Compress verbose shell output (git, npm, cargo, etc.) before returning it to the agent",
|
|
1134
|
+
},
|
|
1135
|
+
},
|
|
1136
|
+
"shellMinimizer.settingsPath": {
|
|
1137
|
+
type: "string",
|
|
1138
|
+
default: undefined,
|
|
1139
|
+
ui: {
|
|
1140
|
+
tab: "editing",
|
|
1141
|
+
label: "Minimizer Settings Path",
|
|
1142
|
+
description: "Optional TOML file with per-command minimizer overrides",
|
|
1143
|
+
submenu: true,
|
|
1144
|
+
},
|
|
1145
|
+
},
|
|
1146
|
+
"shellMinimizer.only": { type: "array", default: EMPTY_STRING_ARRAY },
|
|
1147
|
+
"shellMinimizer.except": { type: "array", default: EMPTY_STRING_ARRAY },
|
|
1148
|
+
"shellMinimizer.maxCaptureBytes": {
|
|
1149
|
+
type: "number",
|
|
1150
|
+
default: 4 * 1024 * 1024,
|
|
1151
|
+
ui: {
|
|
1152
|
+
tab: "editing",
|
|
1153
|
+
label: "Minimizer Capture Limit",
|
|
1154
|
+
description: "Maximum captured output bytes before falling back to raw streaming",
|
|
1155
|
+
submenu: true,
|
|
1156
|
+
},
|
|
1157
|
+
},
|
|
1158
|
+
|
|
1126
1159
|
// Python
|
|
1127
1160
|
"python.toolMode": {
|
|
1128
1161
|
type: "enum",
|
|
@@ -1315,7 +1348,8 @@ export const SETTINGS_SCHEMA = {
|
|
|
1315
1348
|
ui: {
|
|
1316
1349
|
tab: "tools",
|
|
1317
1350
|
label: "GitHub CLI",
|
|
1318
|
-
description:
|
|
1351
|
+
description:
|
|
1352
|
+
"Enable gh_* tools for GitHub repository, issue, pull request, diff, search, checkout, and PR push workflows",
|
|
1319
1353
|
},
|
|
1320
1354
|
},
|
|
1321
1355
|
|
|
@@ -1612,6 +1646,22 @@ export const SETTINGS_SCHEMA = {
|
|
|
1612
1646
|
ui: { tab: "tasks", label: "Claude Project Commands", description: "Load commands from .claude/commands/" },
|
|
1613
1647
|
},
|
|
1614
1648
|
|
|
1649
|
+
"commands.enableOpencodeUser": {
|
|
1650
|
+
type: "boolean",
|
|
1651
|
+
default: true,
|
|
1652
|
+
ui: {
|
|
1653
|
+
tab: "tasks",
|
|
1654
|
+
label: "OpenCode User Commands",
|
|
1655
|
+
description: "Load commands from ~/.config/opencode/commands/",
|
|
1656
|
+
},
|
|
1657
|
+
},
|
|
1658
|
+
|
|
1659
|
+
"commands.enableOpencodeProject": {
|
|
1660
|
+
type: "boolean",
|
|
1661
|
+
default: true,
|
|
1662
|
+
ui: { tab: "tasks", label: "OpenCode Project Commands", description: "Load commands from .opencode/commands/" },
|
|
1663
|
+
},
|
|
1664
|
+
|
|
1615
1665
|
// ────────────────────────────────────────────────────────────────────────
|
|
1616
1666
|
// Providers
|
|
1617
1667
|
// ────────────────────────────────────────────────────────────────────────
|
|
@@ -1956,6 +2006,14 @@ export interface BashInterceptorRule {
|
|
|
1956
2006
|
allowSubcommands?: string[];
|
|
1957
2007
|
}
|
|
1958
2008
|
|
|
2009
|
+
export interface ShellMinimizerSettings {
|
|
2010
|
+
enabled: boolean;
|
|
2011
|
+
settingsPath: string | undefined;
|
|
2012
|
+
only: string[];
|
|
2013
|
+
except: string[];
|
|
2014
|
+
maxCaptureBytes: number;
|
|
2015
|
+
}
|
|
2016
|
+
|
|
1959
2017
|
/** Map group prefix -> typed settings interface */
|
|
1960
2018
|
export interface GroupTypeMap {
|
|
1961
2019
|
compaction: CompactionSettings;
|
|
@@ -1973,6 +2031,7 @@ export interface GroupTypeMap {
|
|
|
1973
2031
|
modelRoles: Record<string, string>;
|
|
1974
2032
|
modelTags: ModelTagsSettings;
|
|
1975
2033
|
cycleOrder: string[];
|
|
2034
|
+
shellMinimizer: ShellMinimizerSettings;
|
|
1976
2035
|
}
|
|
1977
2036
|
|
|
1978
2037
|
export type GroupPrefix = keyof GroupTypeMap;
|
package/src/dap/session.ts
CHANGED
|
@@ -1075,11 +1075,17 @@ export class DapSessionManager {
|
|
|
1075
1075
|
* MUST be called before the command that triggers the event.
|
|
1076
1076
|
*/
|
|
1077
1077
|
#prepareStopOutcome(session: DapSession, signal?: AbortSignal, timeoutMs: number = 30_000): Promise<unknown> {
|
|
1078
|
-
|
|
1078
|
+
const promises = [
|
|
1079
1079
|
session.client.waitForEvent("stopped", undefined, signal, timeoutMs),
|
|
1080
1080
|
session.client.waitForEvent("terminated", undefined, signal, timeoutMs),
|
|
1081
1081
|
session.client.waitForEvent("exited", undefined, signal, timeoutMs),
|
|
1082
|
-
]
|
|
1082
|
+
];
|
|
1083
|
+
// Promise.race leaves the losing waiters pending; their timeouts would
|
|
1084
|
+
// otherwise surface as unhandled rejections once they fire.
|
|
1085
|
+
for (const p of promises) {
|
|
1086
|
+
p.catch(() => {});
|
|
1087
|
+
}
|
|
1088
|
+
return Promise.race(promises);
|
|
1083
1089
|
}
|
|
1084
1090
|
|
|
1085
1091
|
/**
|
package/src/debug/system-info.ts
CHANGED
|
@@ -40,8 +40,12 @@ function macosMarketingName(release: string): string | undefined {
|
|
|
40
40
|
|
|
41
41
|
/** Collect system information */
|
|
42
42
|
export async function collectSystemInfo(): Promise<SystemInfo> {
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
let cpuModel = "Unknown CPU";
|
|
44
|
+
try {
|
|
45
|
+
cpuModel = os.cpus()[0]?.model ?? cpuModel;
|
|
46
|
+
} catch {
|
|
47
|
+
// Keep debug report collection best-effort when CPU probing fails.
|
|
48
|
+
}
|
|
45
49
|
|
|
46
50
|
// Try to get shell from environment
|
|
47
51
|
const shell = Bun.env.SHELL ?? Bun.env.ComSpec ?? "unknown";
|
package/src/discovery/claude.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { type SlashCommand, slashCommandCapability } from "../capability/slash-c
|
|
|
18
18
|
import { type SystemPrompt, systemPromptCapability } from "../capability/system-prompt";
|
|
19
19
|
import { type CustomTool, toolCapability } from "../capability/tool";
|
|
20
20
|
import type { LoadContext, LoadResult } from "../capability/types";
|
|
21
|
+
import { settings } from "../config/settings";
|
|
21
22
|
import {
|
|
22
23
|
calculateDepth,
|
|
23
24
|
createSourceMeta,
|
|
@@ -252,48 +253,69 @@ async function loadExtensionModules(ctx: LoadContext): Promise<LoadResult<Extens
|
|
|
252
253
|
// Slash Commands
|
|
253
254
|
// =============================================================================
|
|
254
255
|
|
|
256
|
+
/**
|
|
257
|
+
* Read the Claude command-loading toggles from settings.
|
|
258
|
+
* Falls back to true (current behavior) when settings are not initialized,
|
|
259
|
+
* e.g. inside discovery unit tests that run without Settings.init().
|
|
260
|
+
*/
|
|
261
|
+
function readClaudeCommandToggles(): { enableUser: boolean; enableProject: boolean } {
|
|
262
|
+
try {
|
|
263
|
+
return {
|
|
264
|
+
enableUser: settings.get("commands.enableClaudeUser") ?? true,
|
|
265
|
+
enableProject: settings.get("commands.enableClaudeProject") ?? true,
|
|
266
|
+
};
|
|
267
|
+
} catch {
|
|
268
|
+
return { enableUser: true, enableProject: true };
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
255
272
|
async function loadSlashCommands(ctx: LoadContext): Promise<LoadResult<SlashCommand>> {
|
|
256
273
|
const items: SlashCommand[] = [];
|
|
257
274
|
const warnings: string[] = [];
|
|
275
|
+
const { enableUser, enableProject } = readClaudeCommandToggles();
|
|
276
|
+
|
|
277
|
+
if (enableUser) {
|
|
278
|
+
const userBase = getUserClaude(ctx);
|
|
279
|
+
const userCommandsDir = path.join(userBase, "commands");
|
|
280
|
+
|
|
281
|
+
const userResult = await loadFilesFromDir<SlashCommand>(ctx, userCommandsDir, PROVIDER_ID, "user", {
|
|
282
|
+
extensions: ["md"],
|
|
283
|
+
transform: (name, content, path, source) => {
|
|
284
|
+
const cmdName = name.replace(/\.md$/, "");
|
|
285
|
+
return {
|
|
286
|
+
name: cmdName,
|
|
287
|
+
path,
|
|
288
|
+
content,
|
|
289
|
+
level: "user",
|
|
290
|
+
_source: source,
|
|
291
|
+
};
|
|
292
|
+
},
|
|
293
|
+
});
|
|
258
294
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const userResult = await loadFilesFromDir<SlashCommand>(ctx, userCommandsDir, PROVIDER_ID, "user", {
|
|
263
|
-
extensions: ["md"],
|
|
264
|
-
transform: (name, content, path, source) => {
|
|
265
|
-
const cmdName = name.replace(/\.md$/, "");
|
|
266
|
-
return {
|
|
267
|
-
name: cmdName,
|
|
268
|
-
path,
|
|
269
|
-
content,
|
|
270
|
-
level: "user",
|
|
271
|
-
_source: source,
|
|
272
|
-
};
|
|
273
|
-
},
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
items.push(...userResult.items);
|
|
277
|
-
if (userResult.warnings) warnings.push(...userResult.warnings);
|
|
278
|
-
|
|
279
|
-
const projectCommandsDir = path.join(ctx.cwd, CONFIG_DIR, "commands");
|
|
295
|
+
items.push(...userResult.items);
|
|
296
|
+
if (userResult.warnings) warnings.push(...userResult.warnings);
|
|
297
|
+
}
|
|
280
298
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
299
|
+
if (enableProject) {
|
|
300
|
+
const projectCommandsDir = path.join(ctx.cwd, CONFIG_DIR, "commands");
|
|
301
|
+
|
|
302
|
+
const projectResult = await loadFilesFromDir<SlashCommand>(ctx, projectCommandsDir, PROVIDER_ID, "project", {
|
|
303
|
+
extensions: ["md"],
|
|
304
|
+
transform: (name, content, path, source) => {
|
|
305
|
+
const cmdName = name.replace(/\.md$/, "");
|
|
306
|
+
return {
|
|
307
|
+
name: cmdName,
|
|
308
|
+
path,
|
|
309
|
+
content,
|
|
310
|
+
level: "project",
|
|
311
|
+
_source: source,
|
|
312
|
+
};
|
|
313
|
+
},
|
|
314
|
+
});
|
|
294
315
|
|
|
295
|
-
|
|
296
|
-
|
|
316
|
+
items.push(...projectResult.items);
|
|
317
|
+
if (projectResult.warnings) warnings.push(...projectResult.warnings);
|
|
318
|
+
}
|
|
297
319
|
|
|
298
320
|
return { items, warnings };
|
|
299
321
|
}
|
|
@@ -26,6 +26,7 @@ import { type Settings, settingsCapability } from "../capability/settings";
|
|
|
26
26
|
import { type Skill, skillCapability } from "../capability/skill";
|
|
27
27
|
import { type SlashCommand, slashCommandCapability } from "../capability/slash-command";
|
|
28
28
|
import type { LoadContext, LoadResult, SourceMeta } from "../capability/types";
|
|
29
|
+
import { settings } from "../config/settings";
|
|
29
30
|
|
|
30
31
|
import {
|
|
31
32
|
buildExtensionModuleItems,
|
|
@@ -236,9 +237,26 @@ async function loadExtensionModules(ctx: LoadContext): Promise<LoadResult<Extens
|
|
|
236
237
|
// Slash Commands (commands/)
|
|
237
238
|
// =============================================================================
|
|
238
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Read the OpenCode command-loading toggles from settings.
|
|
242
|
+
* Falls back to true (current behavior) when settings are not initialized,
|
|
243
|
+
* e.g. inside discovery unit tests that run without Settings.init().
|
|
244
|
+
*/
|
|
245
|
+
function readOpencodeCommandToggles(): { enableUser: boolean; enableProject: boolean } {
|
|
246
|
+
try {
|
|
247
|
+
return {
|
|
248
|
+
enableUser: settings.get("commands.enableOpencodeUser") ?? true,
|
|
249
|
+
enableProject: settings.get("commands.enableOpencodeProject") ?? true,
|
|
250
|
+
};
|
|
251
|
+
} catch {
|
|
252
|
+
return { enableUser: true, enableProject: true };
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
239
256
|
async function loadSlashCommands(ctx: LoadContext): Promise<LoadResult<SlashCommand>> {
|
|
240
|
-
const
|
|
241
|
-
const
|
|
257
|
+
const { enableUser, enableProject } = readOpencodeCommandToggles();
|
|
258
|
+
const userCommandsDir = enableUser ? getUserPath(ctx, "opencode", "commands") : null;
|
|
259
|
+
const projectCommandsDir = enableProject ? getProjectPath(ctx, "opencode", "commands") : null;
|
|
242
260
|
|
|
243
261
|
const transformCommand =
|
|
244
262
|
(level: "user" | "project") => (name: string, content: string, filePath: string, source: SourceMeta) => {
|
package/src/edit/index.ts
CHANGED
|
@@ -68,6 +68,7 @@ export * from "./modes/patch";
|
|
|
68
68
|
export * from "./modes/replace";
|
|
69
69
|
export * from "./normalize";
|
|
70
70
|
export * from "./renderer";
|
|
71
|
+
export * from "./streaming";
|
|
71
72
|
|
|
72
73
|
type TInput =
|
|
73
74
|
| typeof replaceEditSchema
|
|
@@ -322,7 +323,8 @@ export class EditTool implements AgentTool<TInput> {
|
|
|
322
323
|
chunkAutoIndent: resolveChunkAutoIndent(),
|
|
323
324
|
}),
|
|
324
325
|
parameters: chunkEditParamsSchema,
|
|
325
|
-
invalidParamsMessage:
|
|
326
|
+
invalidParamsMessage:
|
|
327
|
+
"Invalid edit parameters for chunk mode. Expected `{ edits: [{ path: 'file:selector', ...op }, ...] }` with at least one edit. Each edit needs a `path`; supply exactly one of `write: 'content'`, `insert: { loc, body }`, or `delete: true`.",
|
|
326
328
|
validate: isChunkParams,
|
|
327
329
|
execute: (
|
|
328
330
|
tool: EditTool,
|