@oh-my-pi/pi-coding-agent 16.1.22 → 16.2.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 +99 -1
- package/dist/cli.js +4387 -4164
- package/dist/types/advisor/__tests__/emission-guard.test.d.ts +1 -0
- package/dist/types/advisor/emission-guard.d.ts +73 -0
- package/dist/types/advisor/index.d.ts +1 -0
- package/dist/types/advisor/runtime.d.ts +7 -0
- package/dist/types/advisor/watchdog.d.ts +2 -0
- package/dist/types/cli/flag-tables.d.ts +1 -0
- package/dist/types/cli/gallery-fixtures/search.d.ts +1 -1
- package/dist/types/cli/gc-cli.d.ts +58 -0
- package/dist/types/collab/display-name.d.ts +3 -0
- package/dist/types/collab/host.d.ts +0 -2
- package/dist/types/commands/gc.d.ts +37 -0
- package/dist/types/commands/worktree.d.ts +0 -3
- package/dist/types/config/inline-tool-descriptors-mode.d.ts +13 -0
- package/dist/types/config/model-discovery.d.ts +6 -1
- package/dist/types/config/model-registry.d.ts +6 -2
- package/dist/types/config/model-resolver.d.ts +12 -0
- package/dist/types/config/models-config-schema.d.ts +29 -2
- package/dist/types/config/models-config.d.ts +22 -1
- package/dist/types/config/settings-schema.d.ts +145 -21
- package/dist/types/config/settings.d.ts +13 -0
- package/dist/types/dap/config.d.ts +1 -1
- package/dist/types/edit/hashline/filesystem.d.ts +4 -2
- package/dist/types/edit/renderer.d.ts +4 -0
- package/dist/types/extensibility/extensions/types.d.ts +17 -17
- package/dist/types/extensibility/hooks/types.d.ts +10 -10
- package/dist/types/extensibility/plugins/marketplace/types.d.ts +1 -0
- package/dist/types/internal-urls/__tests__/ssh-protocol.test.d.ts +1 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/registry-helpers.d.ts +2 -0
- package/dist/types/internal-urls/router.d.ts +1 -1
- package/dist/types/internal-urls/ssh-protocol.d.ts +10 -0
- package/dist/types/internal-urls/types.d.ts +19 -2
- package/dist/types/irc/bus.d.ts +6 -0
- package/dist/types/mcp/transports/stdio.d.ts +25 -1
- package/dist/types/modes/components/__tests__/move-overlay.test.d.ts +1 -0
- package/dist/types/modes/components/custom-editor.d.ts +7 -0
- package/dist/types/modes/components/move-overlay.d.ts +23 -0
- package/dist/types/modes/components/plugin-selector.d.ts +2 -1
- package/dist/types/modes/components/queue-mode-selector.d.ts +2 -1
- package/dist/types/modes/components/select-list-mouse-routing.d.ts +2 -0
- package/dist/types/modes/components/settings-defs.d.ts +4 -1
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/components/show-images-selector.d.ts +2 -1
- package/dist/types/modes/components/status-line/component.d.ts +2 -0
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/theme-selector.d.ts +2 -1
- package/dist/types/modes/components/thinking-selector.d.ts +2 -1
- package/dist/types/modes/controllers/command-controller.d.ts +10 -1
- package/dist/types/modes/controllers/streaming-reveal.d.ts +6 -0
- package/dist/types/modes/interactive-mode.d.ts +10 -1
- package/dist/types/modes/internal-url-autocomplete.d.ts +1 -1
- package/dist/types/modes/running-subagent-badge.d.ts +6 -0
- package/dist/types/modes/theme/mermaid-rendering.test.d.ts +1 -0
- package/dist/types/modes/theme/theme.d.ts +2 -1
- package/dist/types/modes/types.d.ts +9 -1
- package/dist/types/sdk.d.ts +2 -2
- package/dist/types/session/agent-session.d.ts +2 -1
- package/dist/types/session/session-listing.d.ts +10 -1
- package/dist/types/session/session-manager.d.ts +13 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +1 -1
- package/dist/types/ssh/__tests__/connection-manager-args.test.d.ts +1 -0
- package/dist/types/ssh/__tests__/file-transfer-posix-guard.test.d.ts +1 -0
- package/dist/types/ssh/connection-manager.d.ts +2 -0
- package/dist/types/ssh/file-transfer.d.ts +79 -0
- package/dist/types/ssh/utils.d.ts +6 -0
- package/dist/types/system-prompt.d.ts +5 -0
- package/dist/types/task/executor.d.ts +16 -0
- package/dist/types/tiny/text.d.ts +1 -1
- package/dist/types/tools/builtin-names.d.ts +5 -1
- package/dist/types/tools/{find.d.ts → glob.d.ts} +15 -15
- package/dist/types/tools/{search.d.ts → grep.d.ts} +14 -14
- package/dist/types/tools/index.d.ts +3 -3
- package/dist/types/tools/path-utils.d.ts +29 -0
- package/dist/types/tools/plan-mode-guard.d.ts +7 -0
- package/dist/types/tools/read.d.ts +2 -2
- package/dist/types/tools/render-utils.d.ts +8 -0
- package/dist/types/tools/renderers.d.ts +11 -0
- package/dist/types/tools/ssh.d.ts +2 -0
- package/dist/types/tools/todo.d.ts +0 -16
- package/dist/types/tools/write.d.ts +2 -2
- package/dist/types/utils/active-repo-context.d.ts +8 -0
- package/dist/types/utils/image-resize.d.ts +1 -0
- package/dist/types/utils/markit-cache.d.ts +23 -0
- package/dist/types/utils/markit.d.ts +5 -1
- package/dist/types/utils/prompt-path.d.ts +1 -0
- package/dist/types/web/search/providers/duckduckgo.d.ts +14 -0
- package/dist/types/web/search/providers/firecrawl.d.ts +28 -0
- package/dist/types/web/search/providers/tinyfish.d.ts +29 -0
- package/dist/types/web/search/providers/xai.d.ts +13 -0
- package/dist/types/web/search/types.d.ts +18 -2
- package/package.json +30 -15
- package/scripts/bench-guard.ts +1 -1
- package/scripts/build-binary.ts +9 -9
- package/scripts/bundle-dist.ts +2 -2
- package/src/advisor/__tests__/advisor.test.ts +40 -4
- package/src/advisor/__tests__/emission-guard.test.ts +147 -0
- package/src/advisor/advise-tool.ts +1 -1
- package/src/advisor/emission-guard.ts +172 -0
- package/src/advisor/index.ts +1 -0
- package/src/advisor/runtime.ts +11 -0
- package/src/advisor/watchdog.ts +12 -1
- package/src/cli/args.ts +5 -2
- package/src/cli/auth-broker-cli.ts +17 -0
- package/src/cli/config-cli.ts +4 -0
- package/src/cli/flag-tables.ts +7 -4
- package/src/cli/gallery-cli.ts +14 -2
- package/src/cli/gallery-fixtures/edit.ts +60 -0
- package/src/cli/gallery-fixtures/fs.ts +17 -17
- package/src/cli/gallery-fixtures/search.ts +4 -4
- package/src/cli/gc-cli.ts +939 -0
- package/src/cli/usage-cli.ts +20 -1
- package/src/cli/web-search-cli.ts +1 -1
- package/src/cli-commands.ts +1 -0
- package/src/collab/display-name.ts +13 -0
- package/src/collab/guest.ts +5 -1
- package/src/collab/host.ts +2 -13
- package/src/commands/gc.ts +46 -0
- package/src/commands/worktree.ts +6 -0
- package/src/config/inline-tool-descriptors-mode.ts +27 -0
- package/src/config/model-discovery.ts +77 -8
- package/src/config/model-registry.ts +89 -11
- package/src/config/model-resolver.ts +39 -1
- package/src/config/models-config-schema.ts +41 -5
- package/src/config/models-config.ts +4 -1
- package/src/config/settings-schema.ts +130 -27
- package/src/config/settings.ts +216 -7
- package/src/cursor.ts +1 -1
- package/src/dap/config.ts +152 -8
- package/src/dap/session.ts +1 -1
- package/src/discovery/helpers.ts +3 -1
- package/src/edit/hashline/diff.ts +14 -3
- package/src/edit/hashline/execute.ts +42 -6
- package/src/edit/hashline/filesystem.ts +49 -8
- package/src/edit/index.ts +1 -0
- package/src/edit/modes/patch.ts +11 -1
- package/src/edit/renderer.ts +140 -13
- package/src/eval/__tests__/agent-bridge.test.ts +101 -0
- package/src/eval/__tests__/julia-prelude.test.ts +18 -0
- package/src/eval/agent-bridge.ts +26 -3
- package/src/eval/jl/runner.jl +7 -1
- package/src/eval/js/tool-bridge.ts +2 -2
- package/src/export/html/index.ts +1 -1
- package/src/export/html/template.js +3 -1
- package/src/export/html/tool-views.generated.js +20 -20
- package/src/extensibility/extensions/types.ts +22 -22
- package/src/extensibility/hooks/types.ts +11 -11
- package/src/extensibility/plugins/legacy-pi-bundled-keys.ts +10 -3
- package/src/extensibility/plugins/legacy-pi-bundled-registry.ts +31 -10
- package/src/extensibility/plugins/marketplace/manager.ts +22 -0
- package/src/extensibility/plugins/marketplace/types.ts +1 -0
- package/src/internal-urls/__tests__/ssh-protocol.test.ts +331 -0
- package/src/internal-urls/docs-index.generated.txt +2 -2
- package/src/internal-urls/docs-index.ts +2 -3
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/registry-helpers.ts +19 -4
- package/src/internal-urls/router.ts +5 -3
- package/src/internal-urls/ssh-protocol.ts +367 -0
- package/src/internal-urls/types.ts +19 -2
- package/src/irc/bus.ts +11 -3
- package/src/lsp/index.ts +8 -1
- package/src/mcp/oauth-discovery.ts +20 -20
- package/src/mcp/tool-bridge.ts +32 -2
- package/src/mcp/transports/stdio.test.ts +20 -3
- package/src/mcp/transports/stdio.ts +45 -14
- package/src/memories/index.ts +1 -1
- package/src/modes/acp/acp-event-mapper.ts +2 -2
- package/src/modes/components/__tests__/move-overlay.test.ts +166 -0
- package/src/modes/components/agent-hub.ts +3 -0
- package/src/modes/components/agent-transcript-viewer.ts +9 -7
- package/src/modes/components/custom-editor.ts +90 -5
- package/src/modes/components/move-overlay.ts +282 -0
- package/src/modes/components/plan-review-overlay.ts +35 -35
- package/src/modes/components/plugin-selector.ts +6 -1
- package/src/modes/components/queue-mode-selector.ts +6 -1
- package/src/modes/components/select-list-mouse-routing.ts +35 -0
- package/src/modes/components/session-selector.ts +11 -10
- package/src/modes/components/settings-defs.ts +14 -1
- package/src/modes/components/settings-selector.ts +196 -29
- package/src/modes/components/show-images-selector.ts +6 -1
- package/src/modes/components/status-line/component.ts +108 -28
- package/src/modes/components/status-line/segments.ts +5 -1
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/theme-selector.ts +6 -1
- package/src/modes/components/thinking-selector.ts +6 -1
- package/src/modes/components/tool-execution.ts +25 -9
- package/src/modes/components/tree-selector.ts +5 -5
- package/src/modes/controllers/command-controller.ts +140 -47
- package/src/modes/controllers/event-controller.ts +59 -3
- package/src/modes/controllers/input-controller.ts +70 -4
- package/src/modes/controllers/selector-controller.ts +15 -2
- package/src/modes/controllers/streaming-reveal.ts +17 -0
- package/src/modes/controllers/tool-args-reveal.ts +1 -1
- package/src/modes/interactive-mode.ts +142 -59
- package/src/modes/internal-url-autocomplete.ts +17 -2
- package/src/modes/prompt-action-autocomplete.ts +3 -1
- package/src/modes/running-subagent-badge.ts +13 -0
- package/src/modes/setup-wizard/scenes/glyph.ts +2 -13
- package/src/modes/setup-wizard/scenes/providers.ts +2 -1
- package/src/modes/setup-wizard/scenes/theme.ts +6 -12
- package/src/modes/setup-wizard/scenes/web-search.ts +8 -13
- package/src/modes/setup-wizard/wizard-overlay.ts +6 -5
- package/src/modes/theme/mermaid-rendering.test.ts +53 -0
- package/src/modes/theme/theme.ts +42 -15
- package/src/modes/types.ts +9 -1
- package/src/modes/utils/interactive-context-helpers.ts +1 -1
- package/src/priority.json +15 -0
- package/src/prompts/advisor/active-repo-watchdog.md +6 -0
- package/src/prompts/advisor/system.md +21 -7
- package/src/prompts/agents/designer.md +1 -1
- package/src/prompts/agents/explore.md +1 -1
- package/src/prompts/agents/librarian.md +2 -2
- package/src/prompts/agents/plan.md +2 -2
- package/src/prompts/agents/reviewer.md +1 -1
- package/src/prompts/agents/task.md +2 -2
- package/src/prompts/system/active-repo-context.md +4 -0
- package/src/prompts/system/gemini-tool-call-reminder.md +9 -0
- package/src/prompts/system/plan-mode-active.md +12 -3
- package/src/prompts/system/project-prompt.md +2 -2
- package/src/prompts/system/system-prompt.md +8 -6
- package/src/prompts/tools/bash.md +2 -2
- package/src/prompts/tools/checkpoint.md +1 -1
- package/src/prompts/tools/{find.md → glob.md} +1 -1
- package/src/prompts/tools/{search.md → grep.md} +3 -3
- package/src/prompts/tools/read.md +4 -2
- package/src/sdk.ts +98 -29
- package/src/session/agent-session.ts +828 -191
- package/src/session/session-history-format.ts +2 -2
- package/src/session/session-listing.ts +35 -2
- package/src/session/session-manager.ts +46 -0
- package/src/slash-commands/builtin-registry.ts +158 -22
- package/src/slash-commands/helpers/usage-report.ts +23 -2
- package/src/ssh/__tests__/connection-manager-args.test.ts +69 -0
- package/src/ssh/__tests__/file-transfer-posix-guard.test.ts +68 -0
- package/src/ssh/connection-manager.ts +12 -15
- package/src/ssh/file-transfer.ts +209 -0
- package/src/ssh/utils.ts +24 -0
- package/src/system-prompt.ts +60 -28
- package/src/task/executor.ts +96 -36
- package/src/task/index.ts +3 -3
- package/src/task/render.ts +14 -13
- package/src/task/worktree.ts +38 -1
- package/src/tiny/text.ts +49 -4
- package/src/tiny/worker.ts +3 -3
- package/src/tools/acp-bridge.ts +6 -1
- package/src/tools/bash.ts +2 -2
- package/src/tools/builtin-names.ts +26 -2
- package/src/tools/{find.ts → glob.ts} +48 -42
- package/src/tools/{search.ts → grep.ts} +311 -129
- package/src/tools/index.ts +13 -14
- package/src/tools/irc.ts +6 -2
- package/src/tools/path-utils.ts +64 -1
- package/src/tools/plan-mode-guard.ts +26 -13
- package/src/tools/read.ts +35 -6
- package/src/tools/render-utils.ts +14 -0
- package/src/tools/renderers.ts +15 -4
- package/src/tools/ssh.ts +17 -2
- package/src/tools/todo.ts +4 -26
- package/src/tools/write.ts +25 -9
- package/src/utils/active-repo-context.ts +143 -0
- package/src/utils/edit-mode.ts +19 -2
- package/src/utils/image-resize.ts +88 -7
- package/src/utils/lang-from-path.ts +3 -3
- package/src/utils/markit-cache.ts +166 -0
- package/src/utils/markit.ts +86 -18
- package/src/utils/prompt-path.ts +3 -0
- package/src/utils/shell-snapshot.ts +1 -1
- package/src/utils/title-generator.ts +1 -1
- package/src/web/search/provider.ts +54 -34
- package/src/web/search/providers/duckduckgo.ts +140 -0
- package/src/web/search/providers/firecrawl.ts +144 -0
- package/src/web/search/providers/tinyfish.ts +159 -0
- package/src/web/search/providers/xai.ts +292 -0
- package/src/web/search/providers/zai.ts +142 -56
- package/src/web/search/types.ts +6 -2
package/src/dap/config.ts
CHANGED
|
@@ -1,11 +1,38 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
1
3
|
import * as path from "node:path";
|
|
2
|
-
import { isRecord } from "@oh-my-pi/pi-utils";
|
|
4
|
+
import { isRecord, logger } from "@oh-my-pi/pi-utils";
|
|
5
|
+
import { YAML } from "bun";
|
|
6
|
+
import { getConfigDirPaths } from "../config";
|
|
7
|
+
import { getPreloadedPluginRoots } from "../discovery/helpers";
|
|
3
8
|
import { hasRootMarkers, resolveCommand } from "../lsp/config";
|
|
4
9
|
import DEFAULTS from "./defaults.json" with { type: "json" };
|
|
5
10
|
import type { DapAdapterConfig, DapResolvedAdapter } from "./types";
|
|
6
11
|
|
|
7
12
|
const EXTENSIONLESS_DEBUGGER_ORDER = ["gdb", "lldb-dap"] as const;
|
|
8
13
|
|
|
14
|
+
interface NormalizedConfig {
|
|
15
|
+
adapters: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface ConfigSource {
|
|
19
|
+
read(): NormalizedConfig | null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function parseConfigContent(content: string, filePath: string): unknown {
|
|
23
|
+
const extension = path.extname(filePath).toLowerCase();
|
|
24
|
+
if (extension === ".yaml" || extension === ".yml") {
|
|
25
|
+
return YAML.parse(content) as unknown;
|
|
26
|
+
}
|
|
27
|
+
return JSON.parse(content) as unknown;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function normalizeConfig(value: unknown): NormalizedConfig | null {
|
|
31
|
+
if (!isRecord(value)) return null;
|
|
32
|
+
if (isRecord(value.adapters)) return { adapters: value.adapters };
|
|
33
|
+
return { adapters: value };
|
|
34
|
+
}
|
|
35
|
+
|
|
9
36
|
function normalizeStringArray(value: unknown): string[] {
|
|
10
37
|
if (!Array.isArray(value)) return [];
|
|
11
38
|
return value.filter((entry): entry is string => typeof entry === "string" && entry.length > 0);
|
|
@@ -32,6 +59,15 @@ function normalizeAdapterConfig(config: unknown): DapAdapterConfig | null {
|
|
|
32
59
|
};
|
|
33
60
|
}
|
|
34
61
|
|
|
62
|
+
function readConfigFile(filePath: string): NormalizedConfig | null {
|
|
63
|
+
try {
|
|
64
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
65
|
+
return normalizeConfig(parseConfigContent(content, filePath));
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
35
71
|
function getDefaults(): Record<string, DapAdapterConfig> {
|
|
36
72
|
const adapters: Record<string, DapAdapterConfig> = {};
|
|
37
73
|
for (const [name, config] of Object.entries(DEFAULTS)) {
|
|
@@ -45,14 +81,117 @@ function getDefaults(): Record<string, DapAdapterConfig> {
|
|
|
45
81
|
|
|
46
82
|
const DEFAULT_ADAPTERS = getDefaults();
|
|
47
83
|
|
|
48
|
-
|
|
49
|
-
|
|
84
|
+
function mergeAdapters(
|
|
85
|
+
base: Record<string, DapAdapterConfig>,
|
|
86
|
+
overrides: Record<string, unknown>,
|
|
87
|
+
): Record<string, DapAdapterConfig> {
|
|
88
|
+
const merged: Record<string, DapAdapterConfig> = { ...base };
|
|
89
|
+
for (const [name, config] of Object.entries(overrides)) {
|
|
90
|
+
const existing = merged[name];
|
|
91
|
+
const candidate =
|
|
92
|
+
isRecord(existing) && isRecord(config)
|
|
93
|
+
? {
|
|
94
|
+
...existing,
|
|
95
|
+
...config,
|
|
96
|
+
launchDefaults:
|
|
97
|
+
isRecord(existing.launchDefaults) || isRecord(config.launchDefaults)
|
|
98
|
+
? { ...existing.launchDefaults, ...normalizeObject(config.launchDefaults) }
|
|
99
|
+
: undefined,
|
|
100
|
+
attachDefaults:
|
|
101
|
+
isRecord(existing.attachDefaults) || isRecord(config.attachDefaults)
|
|
102
|
+
? { ...existing.attachDefaults, ...normalizeObject(config.attachDefaults) }
|
|
103
|
+
: undefined,
|
|
104
|
+
}
|
|
105
|
+
: config;
|
|
106
|
+
const normalized = normalizeAdapterConfig(candidate);
|
|
107
|
+
if (normalized) {
|
|
108
|
+
merged[name] = normalized;
|
|
109
|
+
} else if (merged[name]) {
|
|
110
|
+
logger.warn("Ignoring invalid DAP adapter override (keeping previous config).", { name });
|
|
111
|
+
} else {
|
|
112
|
+
logger.warn("Ignoring invalid DAP adapter config.", { name });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return merged;
|
|
50
116
|
}
|
|
51
117
|
|
|
52
|
-
|
|
53
|
-
|
|
118
|
+
function fileConfigSource(filePath: string): ConfigSource {
|
|
119
|
+
return {
|
|
120
|
+
read: () => readConfigFile(filePath),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function getConfigSources(cwd: string): ConfigSource[] {
|
|
125
|
+
const filenames = ["dap.json", ".dap.json", "dap.yaml", ".dap.yaml", "dap.yml", ".dap.yml"];
|
|
126
|
+
const sources: ConfigSource[] = [];
|
|
127
|
+
|
|
128
|
+
for (const filename of filenames) {
|
|
129
|
+
sources.push(fileConfigSource(path.join(cwd, filename)));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const projectDirs = getConfigDirPaths("", { user: false, project: true, cwd });
|
|
133
|
+
for (const dir of projectDirs) {
|
|
134
|
+
for (const filename of filenames) {
|
|
135
|
+
sources.push(fileConfigSource(path.join(dir, filename)));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const userDirs = getConfigDirPaths("", { user: true, project: false });
|
|
140
|
+
for (const dir of userDirs) {
|
|
141
|
+
for (const filename of filenames) {
|
|
142
|
+
sources.push(fileConfigSource(path.join(dir, filename)));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const pluginRoots = getPreloadedPluginRoots();
|
|
147
|
+
for (const root of pluginRoots) {
|
|
148
|
+
for (const filename of filenames) {
|
|
149
|
+
sources.push(fileConfigSource(path.join(root.path, filename)));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
for (const filename of filenames) {
|
|
154
|
+
sources.push(fileConfigSource(path.join(os.homedir(), filename)));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return sources;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function loadAdapterConfigs(cwd: string): Record<string, DapAdapterConfig> {
|
|
161
|
+
let adapters = { ...DEFAULT_ADAPTERS };
|
|
162
|
+
for (const source of getConfigSources(cwd).reverse()) {
|
|
163
|
+
const parsed = source.read();
|
|
164
|
+
if (!parsed) continue;
|
|
165
|
+
adapters = mergeAdapters(adapters, parsed.adapters);
|
|
166
|
+
}
|
|
167
|
+
return adapters;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function getAdapterConfigs(cwd?: string): Record<string, DapAdapterConfig> {
|
|
171
|
+
return cwd ? loadAdapterConfigs(cwd) : { ...DEFAULT_ADAPTERS };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function normalizeCommandForCwd(command: string, cwd: string): string {
|
|
175
|
+
if (path.isAbsolute(command)) return command;
|
|
176
|
+
if (
|
|
177
|
+
command.startsWith("./") ||
|
|
178
|
+
command.startsWith("../") ||
|
|
179
|
+
command.startsWith(".\\") ||
|
|
180
|
+
command.startsWith("..\\")
|
|
181
|
+
) {
|
|
182
|
+
return path.resolve(cwd, command);
|
|
183
|
+
}
|
|
184
|
+
return command;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function resolveAdapterFromConfig(
|
|
188
|
+
adapterName: string,
|
|
189
|
+
configs: Record<string, DapAdapterConfig>,
|
|
190
|
+
cwd: string,
|
|
191
|
+
): DapResolvedAdapter | null {
|
|
192
|
+
const config = configs[adapterName];
|
|
54
193
|
if (!config) return null;
|
|
55
|
-
const resolvedCommand = resolveCommand(config.command, cwd);
|
|
194
|
+
const resolvedCommand = resolveCommand(normalizeCommandForCwd(config.command, cwd), cwd);
|
|
56
195
|
if (!resolvedCommand) return null;
|
|
57
196
|
return {
|
|
58
197
|
name: adapterName,
|
|
@@ -69,9 +208,14 @@ export function resolveAdapter(adapterName: string, cwd: string): DapResolvedAda
|
|
|
69
208
|
};
|
|
70
209
|
}
|
|
71
210
|
|
|
211
|
+
export function resolveAdapter(adapterName: string, cwd: string): DapResolvedAdapter | null {
|
|
212
|
+
return resolveAdapterFromConfig(adapterName, getAdapterConfigs(cwd), cwd);
|
|
213
|
+
}
|
|
214
|
+
|
|
72
215
|
export function getAvailableAdapters(cwd: string): DapResolvedAdapter[] {
|
|
73
|
-
|
|
74
|
-
|
|
216
|
+
const configs = getAdapterConfigs(cwd);
|
|
217
|
+
return Object.keys(configs)
|
|
218
|
+
.map(name => resolveAdapterFromConfig(name, configs, cwd))
|
|
75
219
|
.filter((adapter): adapter is DapResolvedAdapter => adapter !== null);
|
|
76
220
|
}
|
|
77
221
|
|
package/src/dap/session.ts
CHANGED
|
@@ -289,7 +289,7 @@ export class DapSessionManager {
|
|
|
289
289
|
...(options.extraLaunchArguments ?? {}),
|
|
290
290
|
program: options.program,
|
|
291
291
|
cwd: options.cwd,
|
|
292
|
-
args: options.args,
|
|
292
|
+
...(options.args !== undefined ? { args: options.args } : {}),
|
|
293
293
|
};
|
|
294
294
|
// Subscribe to stop events BEFORE launching so we don't miss
|
|
295
295
|
// stopOnEntry events that arrive before we start listening.
|
package/src/discovery/helpers.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { parseRuleConditionAndScope, type Rule, type RuleFrontmatter } from "../
|
|
|
18
18
|
import type { Skill, SkillFrontmatter } from "../capability/skill";
|
|
19
19
|
import type { LoadContext, LoadResult, SourceMeta } from "../capability/types";
|
|
20
20
|
import { parseThinkingLevel } from "../thinking";
|
|
21
|
+
import { normalizeToolNames } from "../tools/builtin-names";
|
|
21
22
|
|
|
22
23
|
import { buildPluginDirRoot } from "./plugin-dir-roots";
|
|
23
24
|
|
|
@@ -246,7 +247,8 @@ export function parseAgentFields(frontmatter: Record<string, unknown>): ParsedAg
|
|
|
246
247
|
return null;
|
|
247
248
|
}
|
|
248
249
|
|
|
249
|
-
let tools = parseArrayOrCSV(frontmatter.tools)
|
|
250
|
+
let tools = parseArrayOrCSV(frontmatter.tools);
|
|
251
|
+
if (tools) tools = normalizeToolNames(tools);
|
|
250
252
|
|
|
251
253
|
// Subagents with explicit tool lists always need yield
|
|
252
254
|
if (tools && !tools.includes("yield")) {
|
|
@@ -199,9 +199,15 @@ function buildStreamingSectionDiff(
|
|
|
199
199
|
section: PatchSection,
|
|
200
200
|
normalized: string,
|
|
201
201
|
): { diff: string; firstChangedLine: number | undefined } | { error: string } {
|
|
202
|
-
const { edits } = parsePatchStreaming(section.diff);
|
|
202
|
+
const { edits, fileOp } = parsePatchStreaming(section.diff);
|
|
203
203
|
const resolved = resolveBlockEdits(edits, normalized, section.path, nativeBlockResolver, { onUnresolved: "drop" });
|
|
204
|
-
if (resolved.length === 0)
|
|
204
|
+
if (resolved.length === 0) {
|
|
205
|
+
// A whole-file op (REM / MV) carries no line edits: the change is the
|
|
206
|
+
// delete/move itself, conveyed by the result header, so emit an empty
|
|
207
|
+
// diff rather than a misleading "No changes" error.
|
|
208
|
+
if (fileOp) return { diff: "", firstChangedLine: undefined };
|
|
209
|
+
return { error: `No changes would be made to ${section.path}.` };
|
|
210
|
+
}
|
|
205
211
|
|
|
206
212
|
const fileLines = normalized.split("\n");
|
|
207
213
|
const rows: string[] = [];
|
|
@@ -264,7 +270,12 @@ export async function computeHashlineSectionDiff(
|
|
|
264
270
|
// (`streaming` unset) falls through to the real Myers diff below.
|
|
265
271
|
if (options.streaming) return buildStreamingSectionDiff(section, normalized);
|
|
266
272
|
const result = applyPreviewEdits({ section, absolutePath, normalized, snapshots, options });
|
|
267
|
-
if (normalized === result.text)
|
|
273
|
+
if (normalized === result.text) {
|
|
274
|
+
// REM/MV-only sections change no text; the header conveys the
|
|
275
|
+
// delete/move, so don't surface a "No changes" error.
|
|
276
|
+
if (section.fileOp) return { diff: "", firstChangedLine: undefined };
|
|
277
|
+
return { error: `No changes would be made to ${section.path}.` };
|
|
278
|
+
}
|
|
268
279
|
return generateDiffString(normalized, result.text, undefined, { path: section.path });
|
|
269
280
|
} catch (err) {
|
|
270
281
|
return { error: err instanceof Error ? err.message : String(err) };
|
|
@@ -106,7 +106,28 @@ function formatBlockResolution(resolution: BlockResolution): string {
|
|
|
106
106
|
return `${op} ${resolution.anchorLine} → resolved ${span} (${lines} line${lines === 1 ? "" : "s"})${suffix}`;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
function renderSection(
|
|
109
|
+
function renderSection(
|
|
110
|
+
result: PatchSectionResult,
|
|
111
|
+
diagnostics: FileDiagnosticsResult | undefined,
|
|
112
|
+
sourcePath: string,
|
|
113
|
+
): RenderedSection {
|
|
114
|
+
if (result.op === "delete") {
|
|
115
|
+
const toolResult: AgentToolResult<EditToolDetails, typeof hashlineEditParamsSchema> = {
|
|
116
|
+
content: [{ type: "text", text: `Deleted ${result.path}` }],
|
|
117
|
+
details: {
|
|
118
|
+
diff: "",
|
|
119
|
+
op: "delete",
|
|
120
|
+
path: result.path,
|
|
121
|
+
oldText: result.before,
|
|
122
|
+
meta: outputMeta().get(),
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
return {
|
|
126
|
+
toolResult,
|
|
127
|
+
perFileResult: { path: result.path, diff: "", op: "delete", oldText: result.before },
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
110
131
|
if (result.op === "noop") {
|
|
111
132
|
const toolResult: AgentToolResult<EditToolDetails, typeof hashlineEditParamsSchema> = {
|
|
112
133
|
content: [{ type: "text", text: noChangeDiagnostic(result.path) }],
|
|
@@ -130,24 +151,39 @@ function renderSection(result: PatchSectionResult, diagnostics: FileDiagnosticsR
|
|
|
130
151
|
result.blockResolutions && result.blockResolutions.length > 0
|
|
131
152
|
? `\n${result.blockResolutions.map(formatBlockResolution).join("\n")}`
|
|
132
153
|
: "";
|
|
154
|
+
const moveBlock = result.moveDest ? `\nMoved to ${result.moveDest}` : "";
|
|
133
155
|
const firstChangedLine = result.firstChangedLine ?? diff.firstChangedLine;
|
|
134
156
|
return {
|
|
135
157
|
toolResult: {
|
|
136
|
-
content: [
|
|
158
|
+
content: [
|
|
159
|
+
{
|
|
160
|
+
type: "text",
|
|
161
|
+
text: `${result.header}${blockBlock}${moveBlock}${previewBlock}${warningsBlock}`,
|
|
162
|
+
},
|
|
163
|
+
],
|
|
137
164
|
details: {
|
|
138
165
|
diff: diff.diff,
|
|
139
166
|
firstChangedLine,
|
|
140
167
|
diagnostics,
|
|
141
168
|
op: result.op,
|
|
169
|
+
move: result.moveDest,
|
|
170
|
+
path: result.moveDest ?? result.path,
|
|
171
|
+
sourcePath: result.moveDest ? sourcePath : undefined,
|
|
172
|
+
oldText: result.before,
|
|
173
|
+
newText: result.after,
|
|
142
174
|
meta,
|
|
143
175
|
},
|
|
144
176
|
},
|
|
145
177
|
perFileResult: {
|
|
146
|
-
path: result.path,
|
|
178
|
+
path: result.moveDest ?? result.path,
|
|
147
179
|
diff: diff.diff,
|
|
148
180
|
firstChangedLine,
|
|
149
181
|
diagnostics,
|
|
150
182
|
op: result.op,
|
|
183
|
+
move: result.moveDest,
|
|
184
|
+
sourcePath: result.moveDest ? sourcePath : undefined,
|
|
185
|
+
oldText: result.before,
|
|
186
|
+
newText: result.after,
|
|
151
187
|
},
|
|
152
188
|
};
|
|
153
189
|
}
|
|
@@ -181,10 +217,10 @@ export async function executeHashlineSingle(
|
|
|
181
217
|
if (escalate) {
|
|
182
218
|
throw new ToolError(noChangeLoopDiagnostic(sectionResult.path, count));
|
|
183
219
|
}
|
|
184
|
-
return renderSection(sectionResult, undefined).toolResult;
|
|
220
|
+
return renderSection(sectionResult, undefined, prepared.section.path).toolResult;
|
|
185
221
|
}
|
|
186
222
|
resetNoopEdit(options.session, sectionResult.canonicalPath);
|
|
187
|
-
return renderSection(sectionResult, fs.consumeDiagnostics(sectionResult.path)).toolResult;
|
|
223
|
+
return renderSection(sectionResult, fs.consumeDiagnostics(sectionResult.path), prepared.section.path).toolResult;
|
|
188
224
|
}
|
|
189
225
|
|
|
190
226
|
// Multi-section: prepare every section up front so we fail fast before
|
|
@@ -215,7 +251,7 @@ export async function executeHashlineSingle(
|
|
|
215
251
|
: new ToolError(noChangeDiagnostic(sectionResult.path));
|
|
216
252
|
}
|
|
217
253
|
resetNoopEdit(options.session, sectionResult.canonicalPath);
|
|
218
|
-
rendered.push(renderSection(sectionResult, fs.consumeDiagnostics(sectionResult.path)));
|
|
254
|
+
rendered.push(renderSection(sectionResult, fs.consumeDiagnostics(sectionResult.path), prepared[i].section.path));
|
|
219
255
|
}
|
|
220
256
|
|
|
221
257
|
return {
|
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
* (batch request, diagnostics) lives on the instance and isn't safe to
|
|
17
17
|
* share across concurrent edit tools.
|
|
18
18
|
*/
|
|
19
|
+
import * as fs from "node:fs/promises";
|
|
19
20
|
import * as path from "node:path";
|
|
20
|
-
import { Filesystem, NotFoundError, type WriteResult } from "@oh-my-pi/hashline";
|
|
21
|
+
import { Filesystem, NotFoundError, type PreflightWriteOptions, type WriteResult } from "@oh-my-pi/hashline";
|
|
21
22
|
import { isEnoent } from "@oh-my-pi/pi-utils";
|
|
22
23
|
import type { FileDiagnosticsResult, WritethroughCallback, WritethroughDeferredHandle } from "../../lsp";
|
|
23
24
|
import type { ToolSession } from "../../tools";
|
|
@@ -25,7 +26,7 @@ import { routeWriteThroughBridge } from "../../tools/acp-bridge";
|
|
|
25
26
|
import { assertEditableFileContent } from "../../tools/auto-generated-guard";
|
|
26
27
|
import { invalidateFsScanAfterWrite } from "../../tools/fs-cache-invalidation";
|
|
27
28
|
import { isInternalUrlPath } from "../../tools/path-utils";
|
|
28
|
-
import { enforcePlanModeWrite, resolvePlanPath } from "../../tools/plan-mode-guard";
|
|
29
|
+
import { enforcePlanModeWrite, resolvePlanPath, targetsLocalSandbox } from "../../tools/plan-mode-guard";
|
|
29
30
|
import { canonicalSnapshotKey } from "../file-snapshot-store";
|
|
30
31
|
import { readEditFileText, serializeEditFileText } from "../read-file";
|
|
31
32
|
import type { LspBatchRequest } from "../renderer";
|
|
@@ -92,12 +93,17 @@ export class HashlineFilesystem extends Filesystem {
|
|
|
92
93
|
// Internal-URL authored targets (`local://`, `vault://`, …) are approved
|
|
93
94
|
// at the lower "read" privilege; never let one redirect onto a "write".
|
|
94
95
|
if (isInternalUrlPath(authoredPath)) return false;
|
|
95
|
-
// Recovery
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
//
|
|
96
|
+
// Recovery rebinds a bare/mis-typed authored path onto the file its
|
|
97
|
+
// snapshot tag uniquely names. Confine the redirect to locations a plain
|
|
98
|
+
// "write" may legitimately target:
|
|
99
|
+
// 1. the working tree (the model dropped the directory), or
|
|
100
|
+
// 2. the session `local://` sandbox where plan/scratch artifacts live —
|
|
101
|
+
// the snapshot tag proves the model wrote/read that exact file this
|
|
102
|
+
// session, so a bare `plan.md#tag` should land on `local://plan.md`.
|
|
103
|
+
// The secret vault and any other out-of-tree path stay refused.
|
|
99
104
|
const root = canonicalSnapshotKey(this.session.cwd);
|
|
100
|
-
|
|
105
|
+
if (resolvedPath === root || resolvedPath.startsWith(`${root}${path.sep}`)) return true;
|
|
106
|
+
return targetsLocalSandbox(this.session, resolvedPath);
|
|
101
107
|
}
|
|
102
108
|
|
|
103
109
|
async readText(relativePath: string): Promise<string> {
|
|
@@ -117,10 +123,45 @@ export class HashlineFilesystem extends Filesystem {
|
|
|
117
123
|
return content;
|
|
118
124
|
}
|
|
119
125
|
|
|
120
|
-
async preflightWrite(relativePath: string): Promise<void> {
|
|
126
|
+
async preflightWrite(relativePath: string, options?: PreflightWriteOptions): Promise<void> {
|
|
127
|
+
const fileOp = options?.fileOp;
|
|
128
|
+
if (fileOp?.kind === "rem") {
|
|
129
|
+
enforcePlanModeWrite(this.session, relativePath, { op: "delete" });
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (fileOp?.kind === "move") {
|
|
133
|
+
enforcePlanModeWrite(this.session, relativePath, { op: "update", move: fileOp.dest });
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
121
136
|
enforcePlanModeWrite(this.session, relativePath, { op: "update" });
|
|
122
137
|
}
|
|
123
138
|
|
|
139
|
+
async delete(relativePath: string): Promise<void> {
|
|
140
|
+
enforcePlanModeWrite(this.session, relativePath, { op: "delete" });
|
|
141
|
+
const absolutePath = this.resolveAbsolute(relativePath);
|
|
142
|
+
try {
|
|
143
|
+
await fs.rm(absolutePath);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
if (isEnoent(error)) throw new NotFoundError(relativePath, error);
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
invalidateFsScanAfterWrite(absolutePath);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async move(fromRelative: string, toRelative: string, content?: string): Promise<void> {
|
|
152
|
+
enforcePlanModeWrite(this.session, fromRelative, { op: "update", move: toRelative });
|
|
153
|
+
const fromAbsolute = this.resolveAbsolute(fromRelative);
|
|
154
|
+
const toAbsolute = this.resolveAbsolute(toRelative);
|
|
155
|
+
if (content !== undefined) {
|
|
156
|
+
await Bun.write(toAbsolute, content);
|
|
157
|
+
await fs.rm(fromAbsolute);
|
|
158
|
+
} else {
|
|
159
|
+
await fs.rename(fromAbsolute, toAbsolute);
|
|
160
|
+
}
|
|
161
|
+
invalidateFsScanAfterWrite(fromAbsolute);
|
|
162
|
+
invalidateFsScanAfterWrite(toAbsolute);
|
|
163
|
+
}
|
|
164
|
+
|
|
124
165
|
async writeText(relativePath: string, content: string): Promise<WriteResult> {
|
|
125
166
|
await this.preflightWrite(relativePath);
|
|
126
167
|
const absolutePath = this.resolveAbsolute(relativePath);
|
package/src/edit/index.ts
CHANGED
package/src/edit/modes/patch.ts
CHANGED
|
@@ -1849,12 +1849,21 @@ export async function executePatchSingle(
|
|
|
1849
1849
|
diff: "",
|
|
1850
1850
|
firstChangedLine: undefined,
|
|
1851
1851
|
};
|
|
1852
|
-
if (
|
|
1852
|
+
if (
|
|
1853
|
+
result.change.type === "update" &&
|
|
1854
|
+
result.change.oldContent !== undefined &&
|
|
1855
|
+
result.change.newContent !== undefined
|
|
1856
|
+
) {
|
|
1853
1857
|
const normalizedOld = normalizeToLF(stripBom(result.change.oldContent).text);
|
|
1854
1858
|
const normalizedNew = normalizeToLF(stripBom(result.change.newContent).text);
|
|
1855
1859
|
diffResult = generateUnifiedDiffString(normalizedOld, normalizedNew, undefined, {
|
|
1856
1860
|
path: result.change.newPath ?? result.change.path,
|
|
1857
1861
|
});
|
|
1862
|
+
} else if (result.change.type === "create" && result.change.newContent !== undefined) {
|
|
1863
|
+
// The result is authoritative for rendering, so emit the added-content
|
|
1864
|
+
// diff here rather than relying on the call-phase streaming preview.
|
|
1865
|
+
const normalizedNew = normalizeToLF(stripBom(result.change.newContent).text);
|
|
1866
|
+
diffResult = generateUnifiedDiffString("", normalizedNew, undefined, { path: result.change.path });
|
|
1858
1867
|
}
|
|
1859
1868
|
|
|
1860
1869
|
let resultText: string;
|
|
@@ -1896,6 +1905,7 @@ export async function executePatchSingle(
|
|
|
1896
1905
|
diagnostics: mergedDiagnostics,
|
|
1897
1906
|
op,
|
|
1898
1907
|
move: effectiveRename,
|
|
1908
|
+
sourcePath: result.change.newPath ? resolvedPath : undefined,
|
|
1899
1909
|
meta,
|
|
1900
1910
|
oldText,
|
|
1901
1911
|
newText,
|