@oh-my-pi/pi-coding-agent 13.19.0 → 14.0.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 +266 -1
- package/package.json +86 -20
- package/scripts/format-prompts.ts +2 -2
- package/src/autoresearch/apply-contract-to-state.ts +24 -0
- package/src/autoresearch/contract.ts +0 -44
- package/src/autoresearch/dashboard.ts +1 -2
- package/src/autoresearch/git.ts +91 -0
- package/src/autoresearch/helpers.ts +49 -0
- package/src/autoresearch/index.ts +28 -187
- package/src/autoresearch/prompt.md +26 -9
- package/src/autoresearch/state.ts +0 -6
- package/src/autoresearch/tools/init-experiment.ts +202 -117
- package/src/autoresearch/tools/log-experiment.ts +83 -125
- package/src/autoresearch/tools/run-experiment.ts +48 -10
- package/src/autoresearch/types.ts +2 -2
- package/src/capability/index.ts +4 -2
- package/src/cli/file-processor.ts +3 -3
- package/src/cli/grep-cli.ts +8 -8
- package/src/cli/grievances-cli.ts +78 -0
- package/src/cli/read-cli.ts +67 -0
- package/src/cli/setup-cli.ts +4 -4
- package/src/cli/update-cli.ts +3 -3
- package/src/cli.ts +2 -0
- package/src/commands/grep.ts +6 -1
- package/src/commands/grievances.ts +20 -0
- package/src/commands/read.ts +33 -0
- package/src/commit/agentic/agent.ts +5 -5
- package/src/commit/agentic/index.ts +3 -4
- package/src/commit/agentic/tools/analyze-file.ts +3 -3
- package/src/commit/agentic/validation.ts +1 -1
- package/src/commit/analysis/conventional.ts +4 -4
- package/src/commit/analysis/summary.ts +3 -3
- package/src/commit/changelog/generate.ts +4 -4
- package/src/commit/map-reduce/map-phase.ts +4 -4
- package/src/commit/map-reduce/reduce-phase.ts +4 -4
- package/src/commit/pipeline.ts +3 -4
- package/src/config/prompt-templates.ts +44 -226
- package/src/config/resolve-config-value.ts +4 -2
- package/src/config/settings-schema.ts +54 -2
- package/src/config/settings.ts +25 -26
- package/src/dap/client.ts +674 -0
- package/src/dap/config.ts +150 -0
- package/src/dap/defaults.json +211 -0
- package/src/dap/index.ts +4 -0
- package/src/dap/session.ts +1255 -0
- package/src/dap/types.ts +600 -0
- package/src/debug/log-viewer.ts +3 -2
- package/src/discovery/builtin.ts +1 -2
- package/src/discovery/codex.ts +2 -2
- package/src/discovery/github.ts +2 -1
- package/src/discovery/helpers.ts +2 -2
- package/src/discovery/opencode.ts +2 -2
- package/src/edit/diff.ts +818 -0
- package/src/edit/index.ts +309 -0
- package/src/edit/line-hash.ts +67 -0
- package/src/edit/modes/chunk.ts +454 -0
- package/src/{patch → edit/modes}/hashline.ts +741 -361
- package/src/{patch/applicator.ts → edit/modes/patch.ts} +420 -117
- package/src/{patch/fuzzy.ts → edit/modes/replace.ts} +519 -197
- package/src/{patch → edit}/normalize.ts +97 -76
- package/src/{patch/shared.ts → edit/renderer.ts} +181 -108
- package/src/exec/bash-executor.ts +4 -2
- package/src/exec/idle-timeout-watchdog.ts +126 -0
- package/src/exec/non-interactive-env.ts +5 -0
- package/src/extensibility/custom-commands/bundled/ci-green/index.ts +2 -2
- package/src/extensibility/custom-commands/bundled/review/index.ts +2 -2
- package/src/extensibility/custom-commands/loader.ts +1 -2
- package/src/extensibility/custom-tools/loader.ts +34 -11
- package/src/extensibility/extensions/loader.ts +9 -4
- package/src/extensibility/extensions/runner.ts +24 -1
- package/src/extensibility/extensions/types.ts +1 -1
- package/src/extensibility/hooks/loader.ts +5 -6
- package/src/extensibility/hooks/types.ts +1 -1
- package/src/extensibility/plugins/doctor.ts +2 -1
- package/src/extensibility/slash-commands.ts +3 -7
- package/src/index.ts +2 -1
- package/src/internal-urls/docs-index.generated.ts +11 -11
- package/src/ipy/executor.ts +58 -17
- package/src/ipy/gateway-coordinator.ts +6 -4
- package/src/ipy/kernel.ts +45 -22
- package/src/ipy/runtime.ts +2 -2
- package/src/lsp/client.ts +7 -4
- package/src/lsp/clients/lsp-linter-client.ts +4 -4
- package/src/lsp/config.ts +2 -2
- package/src/lsp/defaults.json +688 -154
- package/src/lsp/index.ts +234 -45
- package/src/lsp/lspmux.ts +2 -2
- package/src/lsp/startup-events.ts +13 -0
- package/src/lsp/types.ts +12 -1
- package/src/lsp/utils.ts +8 -1
- package/src/main.ts +102 -46
- package/src/memories/index.ts +4 -5
- package/src/modes/acp/acp-agent.ts +563 -163
- package/src/modes/acp/acp-event-mapper.ts +9 -1
- package/src/modes/acp/acp-mode.ts +4 -2
- package/src/modes/components/agent-dashboard.ts +3 -4
- package/src/modes/components/diff.ts +6 -7
- package/src/modes/components/read-tool-group.ts +6 -12
- package/src/modes/components/settings-defs.ts +5 -0
- package/src/modes/components/tool-execution.ts +1 -1
- package/src/modes/components/welcome.ts +1 -1
- package/src/modes/controllers/btw-controller.ts +2 -2
- package/src/modes/controllers/command-controller.ts +3 -2
- package/src/modes/controllers/input-controller.ts +12 -8
- package/src/modes/index.ts +20 -2
- package/src/modes/interactive-mode.ts +94 -37
- package/src/modes/rpc/host-tools.ts +186 -0
- package/src/modes/rpc/rpc-client.ts +178 -13
- package/src/modes/rpc/rpc-mode.ts +73 -3
- package/src/modes/rpc/rpc-types.ts +53 -1
- package/src/modes/theme/theme.ts +80 -8
- package/src/modes/types.ts +2 -2
- package/src/prompts/system/system-prompt.md +2 -1
- package/src/prompts/tools/chunk-edit.md +219 -0
- package/src/prompts/tools/debug.md +43 -0
- package/src/prompts/tools/grep.md +3 -0
- package/src/prompts/tools/lsp.md +5 -5
- package/src/prompts/tools/read-chunk.md +17 -0
- package/src/prompts/tools/read.md +19 -5
- package/src/sdk.ts +190 -154
- package/src/secrets/obfuscator.ts +1 -1
- package/src/session/agent-session.ts +306 -256
- package/src/session/agent-storage.ts +12 -12
- package/src/session/compaction/branch-summarization.ts +3 -3
- package/src/session/compaction/compaction.ts +5 -6
- package/src/session/compaction/utils.ts +3 -3
- package/src/session/history-storage.ts +62 -19
- package/src/session/messages.ts +3 -3
- package/src/session/session-dump-format.ts +203 -0
- package/src/session/session-storage.ts +4 -2
- package/src/session/streaming-output.ts +1 -1
- package/src/session/tool-choice-queue.ts +213 -0
- package/src/slash-commands/builtin-registry.ts +56 -8
- package/src/ssh/connection-manager.ts +2 -2
- package/src/ssh/sshfs-mount.ts +5 -5
- package/src/stt/downloader.ts +4 -4
- package/src/stt/recorder.ts +4 -4
- package/src/stt/transcriber.ts +2 -2
- package/src/system-prompt.ts +21 -13
- package/src/task/agents.ts +5 -6
- package/src/task/commands.ts +2 -5
- package/src/task/executor.ts +4 -4
- package/src/task/index.ts +3 -4
- package/src/task/template.ts +2 -2
- package/src/task/worktree.ts +4 -4
- package/src/tools/ask.ts +2 -3
- package/src/tools/ast-edit.ts +7 -7
- package/src/tools/ast-grep.ts +7 -7
- package/src/tools/auto-generated-guard.ts +36 -41
- package/src/tools/await-tool.ts +2 -2
- package/src/tools/bash.ts +5 -23
- package/src/tools/browser.ts +4 -5
- package/src/tools/calculator.ts +2 -3
- package/src/tools/cancel-job.ts +2 -2
- package/src/tools/checkpoint.ts +3 -3
- package/src/tools/debug.ts +1007 -0
- package/src/tools/exit-plan-mode.ts +2 -3
- package/src/tools/fetch.ts +67 -3
- package/src/tools/find.ts +4 -5
- package/src/tools/fs-cache-invalidation.ts +5 -0
- package/src/tools/gemini-image.ts +13 -5
- package/src/tools/gh.ts +10 -11
- package/src/tools/grep.ts +57 -9
- package/src/tools/index.ts +44 -22
- package/src/tools/inspect-image.ts +4 -4
- package/src/tools/output-meta.ts +1 -1
- package/src/tools/python.ts +19 -6
- package/src/tools/read.ts +198 -67
- package/src/tools/render-mermaid.ts +2 -3
- package/src/tools/render-utils.ts +20 -6
- package/src/tools/renderers.ts +3 -1
- package/src/tools/report-tool-issue.ts +80 -0
- package/src/tools/resolve.ts +70 -39
- package/src/tools/search-tool-bm25.ts +2 -2
- package/src/tools/ssh.ts +2 -2
- package/src/tools/todo-write.ts +2 -2
- package/src/tools/tool-timeouts.ts +1 -0
- package/src/tools/write.ts +5 -6
- package/src/tui/tree-list.ts +3 -1
- package/src/utils/clipboard.ts +80 -0
- package/src/utils/commit-message-generator.ts +2 -3
- package/src/utils/edit-mode.ts +49 -0
- package/src/utils/file-display-mode.ts +6 -5
- package/src/utils/file-mentions.ts +8 -7
- package/src/utils/git.ts +4 -4
- package/src/utils/image-loading.ts +98 -0
- package/src/utils/title-generator.ts +2 -3
- package/src/utils/tools-manager.ts +6 -6
- package/src/web/scrapers/choosealicense.ts +1 -1
- package/src/web/search/index.ts +3 -3
- package/src/autoresearch/command-initialize.md +0 -34
- package/src/patch/diff.ts +0 -433
- package/src/patch/index.ts +0 -888
- package/src/patch/parser.ts +0 -532
- package/src/patch/types.ts +0 -292
- package/src/prompts/agents/oracle.md +0 -77
- package/src/tools/pending-action.ts +0 -49
- package/src/utils/child-process.ts +0 -88
- package/src/utils/frontmatter.ts +0 -117
- package/src/utils/image-input.ts +0 -274
- package/src/utils/mime.ts +0 -53
- package/src/utils/prompt-format.ts +0 -170
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import { prompt } from "@oh-my-pi/pi-utils";
|
|
3
|
+
import {
|
|
4
|
+
createLspWritethrough,
|
|
5
|
+
type FileDiagnosticsResult,
|
|
6
|
+
type WritethroughCallback,
|
|
7
|
+
type WritethroughDeferredHandle,
|
|
8
|
+
writethroughNoop,
|
|
9
|
+
} from "../lsp";
|
|
10
|
+
import chunkEditDescription from "../prompts/tools/chunk-edit.md" with { type: "text" };
|
|
11
|
+
import hashlineDescription from "../prompts/tools/hashline.md" with { type: "text" };
|
|
12
|
+
import patchDescription from "../prompts/tools/patch.md" with { type: "text" };
|
|
13
|
+
import replaceDescription from "../prompts/tools/replace.md" with { type: "text" };
|
|
14
|
+
import type { ToolSession } from "../tools";
|
|
15
|
+
import { type EditMode, normalizeEditMode, resolveEditMode } from "../utils/edit-mode";
|
|
16
|
+
import {
|
|
17
|
+
type ChunkParams,
|
|
18
|
+
chunkEditParamsSchema,
|
|
19
|
+
executeChunkMode,
|
|
20
|
+
isChunkParams,
|
|
21
|
+
resolveAnchorStyle,
|
|
22
|
+
} from "./modes/chunk";
|
|
23
|
+
import { executeHashlineMode, type HashlineParams, hashlineEditParamsSchema, isHashlineParams } from "./modes/hashline";
|
|
24
|
+
import { executePatchMode, isPatchParams, type PatchParams, patchEditSchema } from "./modes/patch";
|
|
25
|
+
import { executeReplaceMode, isReplaceParams, type ReplaceParams, replaceEditSchema } from "./modes/replace";
|
|
26
|
+
import { type EditToolDetails, getLspBatchRequest, type LspBatchRequest } from "./renderer";
|
|
27
|
+
|
|
28
|
+
export { DEFAULT_EDIT_MODE, type EditMode, normalizeEditMode } from "../utils/edit-mode";
|
|
29
|
+
export * from "./diff";
|
|
30
|
+
export * from "./line-hash";
|
|
31
|
+
export * from "./modes/chunk";
|
|
32
|
+
export * from "./modes/hashline";
|
|
33
|
+
export * from "./modes/patch";
|
|
34
|
+
export * from "./modes/replace";
|
|
35
|
+
export * from "./normalize";
|
|
36
|
+
export * from "./renderer";
|
|
37
|
+
|
|
38
|
+
type TInput =
|
|
39
|
+
| typeof replaceEditSchema
|
|
40
|
+
| typeof patchEditSchema
|
|
41
|
+
| typeof hashlineEditParamsSchema
|
|
42
|
+
| typeof chunkEditParamsSchema;
|
|
43
|
+
|
|
44
|
+
type EditParams = ReplaceParams | PatchParams | HashlineParams | ChunkParams;
|
|
45
|
+
|
|
46
|
+
type ModeExecutionArgs = {
|
|
47
|
+
params: EditParams;
|
|
48
|
+
signal: AbortSignal | undefined;
|
|
49
|
+
batchRequest: LspBatchRequest | undefined;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
type EditModeDefinition = {
|
|
53
|
+
description: (session: ToolSession) => string;
|
|
54
|
+
parameters: TInput;
|
|
55
|
+
invalidParamsMessage: string;
|
|
56
|
+
validate: (params: EditParams) => boolean;
|
|
57
|
+
execute: (tool: EditTool, args: ModeExecutionArgs) => Promise<AgentToolResult<EditToolDetails, TInput>>;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
function resolveConfiguredEditMode(rawEditMode: string): EditMode | undefined {
|
|
61
|
+
if (!rawEditMode || rawEditMode === "auto") {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const editMode = normalizeEditMode(rawEditMode);
|
|
66
|
+
if (!editMode) {
|
|
67
|
+
throw new Error(`Invalid PI_EDIT_VARIANT: ${rawEditMode}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return editMode;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function resolveAllowFuzzy(session: ToolSession, rawValue: string): boolean {
|
|
74
|
+
switch (rawValue) {
|
|
75
|
+
case "true":
|
|
76
|
+
case "1":
|
|
77
|
+
return true;
|
|
78
|
+
case "false":
|
|
79
|
+
case "0":
|
|
80
|
+
return false;
|
|
81
|
+
case "auto":
|
|
82
|
+
return session.settings.get("edit.fuzzyMatch");
|
|
83
|
+
default:
|
|
84
|
+
throw new Error(`Invalid PI_EDIT_FUZZY: ${rawValue}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function resolveFuzzyThreshold(session: ToolSession, rawValue: string): number {
|
|
89
|
+
if (rawValue === "auto") {
|
|
90
|
+
return session.settings.get("edit.fuzzyThreshold");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const threshold = Number.parseFloat(rawValue);
|
|
94
|
+
if (Number.isNaN(threshold) || threshold < 0 || threshold > 1) {
|
|
95
|
+
throw new Error(`Invalid PI_EDIT_FUZZY_THRESHOLD: ${rawValue}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return threshold;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function createEditWritethrough(session: ToolSession): WritethroughCallback {
|
|
102
|
+
const enableLsp = session.enableLsp ?? true;
|
|
103
|
+
const enableDiagnostics = enableLsp && session.settings.get("lsp.diagnosticsOnEdit");
|
|
104
|
+
const enableFormat = enableLsp && session.settings.get("lsp.formatOnWrite");
|
|
105
|
+
return enableLsp ? createLspWritethrough(session.cwd, { enableFormat, enableDiagnostics }) : writethroughNoop;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export class EditTool implements AgentTool<TInput> {
|
|
109
|
+
readonly name = "edit";
|
|
110
|
+
readonly label = "Edit";
|
|
111
|
+
readonly nonAbortable = true;
|
|
112
|
+
readonly concurrency = "exclusive";
|
|
113
|
+
readonly strict = true;
|
|
114
|
+
|
|
115
|
+
readonly #allowFuzzy: boolean;
|
|
116
|
+
readonly #fuzzyThreshold: number;
|
|
117
|
+
readonly #writethrough: WritethroughCallback;
|
|
118
|
+
readonly #editMode?: EditMode;
|
|
119
|
+
readonly #pendingDeferredFetches = new Map<string, AbortController>();
|
|
120
|
+
|
|
121
|
+
constructor(private readonly session: ToolSession) {
|
|
122
|
+
const {
|
|
123
|
+
PI_EDIT_FUZZY: editFuzzy = "auto",
|
|
124
|
+
PI_EDIT_FUZZY_THRESHOLD: editFuzzyThreshold = "auto",
|
|
125
|
+
PI_EDIT_VARIANT: envEditVariant = "auto",
|
|
126
|
+
} = Bun.env;
|
|
127
|
+
|
|
128
|
+
this.#editMode = resolveConfiguredEditMode(envEditVariant);
|
|
129
|
+
this.#allowFuzzy = resolveAllowFuzzy(session, editFuzzy);
|
|
130
|
+
this.#fuzzyThreshold = resolveFuzzyThreshold(session, editFuzzyThreshold);
|
|
131
|
+
this.#writethrough = createEditWritethrough(session);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
get mode(): EditMode {
|
|
135
|
+
if (this.#editMode) return this.#editMode;
|
|
136
|
+
return resolveEditMode(this.session);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
get description(): string {
|
|
140
|
+
return this.#getModeDefinition().description(this.session);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
get parameters(): TInput {
|
|
144
|
+
return this.#getModeDefinition().parameters;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async execute(
|
|
148
|
+
_toolCallId: string,
|
|
149
|
+
params: ReplaceParams,
|
|
150
|
+
signal?: AbortSignal,
|
|
151
|
+
_onUpdate?: AgentToolUpdateCallback<EditToolDetails, TInput>,
|
|
152
|
+
context?: AgentToolContext,
|
|
153
|
+
): Promise<AgentToolResult<EditToolDetails, TInput>>;
|
|
154
|
+
async execute(
|
|
155
|
+
_toolCallId: string,
|
|
156
|
+
params: PatchParams,
|
|
157
|
+
signal?: AbortSignal,
|
|
158
|
+
_onUpdate?: AgentToolUpdateCallback<EditToolDetails, TInput>,
|
|
159
|
+
context?: AgentToolContext,
|
|
160
|
+
): Promise<AgentToolResult<EditToolDetails, TInput>>;
|
|
161
|
+
async execute(
|
|
162
|
+
_toolCallId: string,
|
|
163
|
+
params: HashlineParams,
|
|
164
|
+
signal?: AbortSignal,
|
|
165
|
+
_onUpdate?: AgentToolUpdateCallback<EditToolDetails, TInput>,
|
|
166
|
+
context?: AgentToolContext,
|
|
167
|
+
): Promise<AgentToolResult<EditToolDetails, TInput>>;
|
|
168
|
+
async execute(
|
|
169
|
+
_toolCallId: string,
|
|
170
|
+
params: ChunkParams,
|
|
171
|
+
signal?: AbortSignal,
|
|
172
|
+
_onUpdate?: AgentToolUpdateCallback<EditToolDetails, TInput>,
|
|
173
|
+
context?: AgentToolContext,
|
|
174
|
+
): Promise<AgentToolResult<EditToolDetails, TInput>>;
|
|
175
|
+
async execute(
|
|
176
|
+
_toolCallId: string,
|
|
177
|
+
params: EditParams,
|
|
178
|
+
signal?: AbortSignal,
|
|
179
|
+
_onUpdate?: AgentToolUpdateCallback<EditToolDetails, TInput>,
|
|
180
|
+
context?: AgentToolContext,
|
|
181
|
+
): Promise<AgentToolResult<EditToolDetails, TInput>> {
|
|
182
|
+
const modeDefinition = this.#getModeDefinition();
|
|
183
|
+
if (!modeDefinition.validate(params)) {
|
|
184
|
+
throw new Error(modeDefinition.invalidParamsMessage);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return modeDefinition.execute(this, {
|
|
188
|
+
params,
|
|
189
|
+
signal,
|
|
190
|
+
batchRequest: getLspBatchRequest(context?.toolCall),
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
#getModeDefinition(): EditModeDefinition {
|
|
195
|
+
return {
|
|
196
|
+
chunk: {
|
|
197
|
+
description: (session: ToolSession) =>
|
|
198
|
+
prompt.render(chunkEditDescription, {
|
|
199
|
+
anchorStyle: resolveAnchorStyle(session.settings),
|
|
200
|
+
}),
|
|
201
|
+
parameters: chunkEditParamsSchema,
|
|
202
|
+
invalidParamsMessage: "Invalid edit parameters for chunk mode.",
|
|
203
|
+
validate: isChunkParams,
|
|
204
|
+
async execute(tool: EditTool, args: ModeExecutionArgs) {
|
|
205
|
+
return executeChunkMode({
|
|
206
|
+
session: tool.session,
|
|
207
|
+
params: args.params as ChunkParams,
|
|
208
|
+
signal: args.signal,
|
|
209
|
+
batchRequest: args.batchRequest,
|
|
210
|
+
writethrough: tool.#writethrough,
|
|
211
|
+
beginDeferredDiagnosticsForPath: path => tool.#beginDeferredDiagnosticsForPath(path),
|
|
212
|
+
});
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
patch: {
|
|
216
|
+
description: () => prompt.render(patchDescription),
|
|
217
|
+
parameters: patchEditSchema,
|
|
218
|
+
invalidParamsMessage: "Invalid edit parameters for patch mode.",
|
|
219
|
+
validate: isPatchParams,
|
|
220
|
+
async execute(tool: EditTool, args: ModeExecutionArgs) {
|
|
221
|
+
return executePatchMode({
|
|
222
|
+
session: tool.session,
|
|
223
|
+
params: args.params as PatchParams,
|
|
224
|
+
signal: args.signal,
|
|
225
|
+
batchRequest: args.batchRequest,
|
|
226
|
+
allowFuzzy: tool.#allowFuzzy,
|
|
227
|
+
fuzzyThreshold: tool.#fuzzyThreshold,
|
|
228
|
+
writethrough: tool.#writethrough,
|
|
229
|
+
beginDeferredDiagnosticsForPath: path => tool.#beginDeferredDiagnosticsForPath(path),
|
|
230
|
+
});
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
hashline: {
|
|
234
|
+
description: () => prompt.render(hashlineDescription),
|
|
235
|
+
parameters: hashlineEditParamsSchema,
|
|
236
|
+
invalidParamsMessage: "Invalid edit parameters for hashline mode.",
|
|
237
|
+
validate: isHashlineParams,
|
|
238
|
+
async execute(tool: EditTool, args: ModeExecutionArgs) {
|
|
239
|
+
return executeHashlineMode({
|
|
240
|
+
session: tool.session,
|
|
241
|
+
params: args.params as HashlineParams,
|
|
242
|
+
signal: args.signal,
|
|
243
|
+
batchRequest: args.batchRequest,
|
|
244
|
+
writethrough: tool.#writethrough,
|
|
245
|
+
beginDeferredDiagnosticsForPath: path => tool.#beginDeferredDiagnosticsForPath(path),
|
|
246
|
+
});
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
replace: {
|
|
250
|
+
description: () => prompt.render(replaceDescription),
|
|
251
|
+
parameters: replaceEditSchema,
|
|
252
|
+
invalidParamsMessage: "Invalid edit parameters for replace mode.",
|
|
253
|
+
validate: isReplaceParams,
|
|
254
|
+
async execute(tool: EditTool, args: ModeExecutionArgs) {
|
|
255
|
+
return executeReplaceMode({
|
|
256
|
+
session: tool.session,
|
|
257
|
+
params: args.params as ReplaceParams,
|
|
258
|
+
signal: args.signal,
|
|
259
|
+
batchRequest: args.batchRequest,
|
|
260
|
+
allowFuzzy: tool.#allowFuzzy,
|
|
261
|
+
fuzzyThreshold: tool.#fuzzyThreshold,
|
|
262
|
+
writethrough: tool.#writethrough,
|
|
263
|
+
beginDeferredDiagnosticsForPath: path => tool.#beginDeferredDiagnosticsForPath(path),
|
|
264
|
+
});
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
}[this.mode];
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
#beginDeferredDiagnosticsForPath(path: string): WritethroughDeferredHandle {
|
|
271
|
+
const existingDeferred = this.#pendingDeferredFetches.get(path);
|
|
272
|
+
if (existingDeferred) {
|
|
273
|
+
existingDeferred.abort();
|
|
274
|
+
this.#pendingDeferredFetches.delete(path);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const deferredController = new AbortController();
|
|
278
|
+
return {
|
|
279
|
+
onDeferredDiagnostics: (lateDiagnostics: FileDiagnosticsResult) => {
|
|
280
|
+
this.#pendingDeferredFetches.delete(path);
|
|
281
|
+
this.#injectLateDiagnostics(path, lateDiagnostics);
|
|
282
|
+
},
|
|
283
|
+
signal: deferredController.signal,
|
|
284
|
+
finalize: (diagnostics: FileDiagnosticsResult | undefined) => {
|
|
285
|
+
if (!diagnostics) {
|
|
286
|
+
this.#pendingDeferredFetches.set(path, deferredController);
|
|
287
|
+
} else {
|
|
288
|
+
deferredController.abort();
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
#injectLateDiagnostics(path: string, diagnostics: FileDiagnosticsResult): void {
|
|
295
|
+
const summary = diagnostics.summary ?? "";
|
|
296
|
+
const lines = diagnostics.messages ?? [];
|
|
297
|
+
const body = [`Late LSP diagnostics for ${path} (arrived after the edit tool returned):`, summary, ...lines]
|
|
298
|
+
.filter(Boolean)
|
|
299
|
+
.join("\n");
|
|
300
|
+
|
|
301
|
+
this.session.queueDeferredMessage?.({
|
|
302
|
+
role: "custom",
|
|
303
|
+
customType: "lsp-late-diagnostic",
|
|
304
|
+
content: body,
|
|
305
|
+
display: false,
|
|
306
|
+
timestamp: Date.now(),
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight line-hash utilities extracted from hashline.ts to avoid
|
|
3
|
+
* circular dependencies (prompt-templates → hashline → tools → edit).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** 16-char nibble alphabet (no digits); shared with chunk checksum suffixes. */
|
|
7
|
+
export const HASHLINE_NIBBLE_ALPHABET = "ZPMQVRWSNKTXJBYH";
|
|
8
|
+
|
|
9
|
+
const NIBBLE_STR = HASHLINE_NIBBLE_ALPHABET;
|
|
10
|
+
|
|
11
|
+
const DICT = Array.from({ length: 256 }, (_, i) => {
|
|
12
|
+
const h = i >>> 4;
|
|
13
|
+
const l = i & 0x0f;
|
|
14
|
+
return `${NIBBLE_STR[h]}${NIBBLE_STR[l]}`;
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const RE_SIGNIFICANT = /[\p{L}\p{N}]/u;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Compute a short hexadecimal hash of a single line.
|
|
21
|
+
*
|
|
22
|
+
* Uses xxHash32 on a trailing-whitespace-trimmed, CR-stripped line, truncated to 2 chars from
|
|
23
|
+
* {@link NIBBLE_STR}. For lines containing no alphanumeric characters (only
|
|
24
|
+
* punctuation/symbols/whitespace), the line number is mixed in to reduce hash collisions.
|
|
25
|
+
* The line input should not include a trailing newline.
|
|
26
|
+
*/
|
|
27
|
+
export function computeLineHash(idx: number, line: string): string {
|
|
28
|
+
line = line.replace(/\r/g, "").trimEnd();
|
|
29
|
+
|
|
30
|
+
let seed = 0;
|
|
31
|
+
if (!RE_SIGNIFICANT.test(line)) {
|
|
32
|
+
seed = idx;
|
|
33
|
+
}
|
|
34
|
+
return DICT[Bun.hash.xxHash32(line, seed) & 0xff];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Formats a hash given the line number and text.
|
|
39
|
+
*/
|
|
40
|
+
export function formatLineHash(line: number, lines: string): string {
|
|
41
|
+
return `${line}#${computeLineHash(line, lines)}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Format file text with hashline prefixes for display.
|
|
46
|
+
*
|
|
47
|
+
* Each line becomes `LINENUM#HASH:TEXT` where LINENUM is 1-indexed.
|
|
48
|
+
*
|
|
49
|
+
* @param text - Raw file text string
|
|
50
|
+
* @param startLine - First line number (1-indexed, defaults to 1)
|
|
51
|
+
* @returns Formatted string with one hashline-prefixed line per input line
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```
|
|
55
|
+
* formatHashLines("function hi() {\n return;\n}")
|
|
56
|
+
* // "1#HH:function hi() {\n2#HH: return;\n3#HH:}"
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function formatHashLines(text: string, startLine = 1): string {
|
|
60
|
+
const lines = text.split("\n");
|
|
61
|
+
return lines
|
|
62
|
+
.map((line, i) => {
|
|
63
|
+
const num = startLine + i;
|
|
64
|
+
return `${formatLineHash(num, line)}:${line}`;
|
|
65
|
+
})
|
|
66
|
+
.join("\n");
|
|
67
|
+
}
|