@nghyane/arcane 0.1.13 → 0.1.15
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 +28 -0
- package/package.json +21 -70
- package/scripts/format-prompts.ts +1 -3
- package/src/cli/args.ts +2 -7
- package/src/cli/config-cli.ts +1 -1
- package/src/cli/plugin-cli.ts +1 -1
- package/src/cli/setup-cli.ts +1 -1
- package/src/cli/update-cli.ts +1 -1
- package/src/cli/web-search-cli.ts +1 -1
- package/src/cli.ts +0 -1
- package/src/commands/config.ts +1 -1
- package/src/commands/grep.ts +1 -1
- package/src/commands/jupyter.ts +1 -1
- package/src/commands/plugin.ts +1 -1
- package/src/commands/setup.ts +1 -1
- package/src/commands/shell.ts +1 -1
- package/src/commands/ssh.ts +1 -1
- package/src/commands/stats.ts +1 -1
- package/src/commands/update.ts +1 -1
- package/src/config/model-registry.ts +3 -4
- package/src/config/model-resolver.ts +36 -9
- package/src/config/prompt-templates.ts +1 -9
- package/src/config/settings-schema.ts +32 -88
- package/src/config/settings.ts +3 -4
- package/src/debug/index.ts +1 -1
- package/src/debug/log-formatting.ts +1 -1
- package/src/debug/log-viewer.ts +2 -2
- package/src/discovery/helpers.ts +13 -3
- package/src/exa/index.ts +1 -35
- package/src/exa/render.ts +30 -190
- package/src/export/html/index.ts +1 -1
- package/src/extensibility/custom-tools/loader.ts +1 -1
- package/src/extensibility/custom-tools/types.ts +5 -1
- package/src/extensibility/custom-tools/wrapper.ts +1 -1
- package/src/extensibility/extensions/runner.ts +1 -1
- package/src/extensibility/extensions/types.ts +1 -1
- package/src/extensibility/extensions/wrapper.ts +7 -15
- package/src/extensibility/hooks/runner.ts +1 -1
- package/src/extensibility/hooks/types.ts +1 -1
- package/src/extensibility/plugins/doctor.ts +1 -1
- package/src/index.ts +13 -13
- package/src/lsp/index.ts +77 -24
- package/src/lsp/render.ts +34 -583
- package/src/lsp/types.ts +3 -3
- package/src/lsp/utils.ts +1 -1
- package/src/main.ts +1 -1
- package/src/mcp/tool-bridge.ts +1 -24
- package/src/modes/components/assistant-message.ts +7 -7
- package/src/modes/components/bash-execution.ts +50 -112
- package/src/modes/components/bordered-loader.ts +1 -1
- package/src/modes/components/branch-summary-message.ts +16 -10
- package/src/modes/components/compaction-summary-message.ts +20 -12
- package/src/modes/components/context-group.ts +106 -0
- package/src/modes/components/custom-message.ts +4 -5
- package/src/modes/components/diff.ts +2 -2
- package/src/modes/components/dynamic-border.ts +1 -1
- package/src/modes/components/extensions/extension-dashboard.ts +1 -1
- package/src/modes/components/extensions/extension-list.ts +1 -1
- package/src/modes/components/extensions/inspector-panel.ts +1 -1
- package/src/modes/components/footer.ts +2 -2
- package/src/modes/components/history-search.ts +1 -1
- package/src/modes/components/hook-editor.ts +1 -1
- package/src/modes/components/hook-input.ts +1 -1
- package/src/modes/components/hook-message.ts +4 -5
- package/src/modes/components/hook-selector.ts +1 -1
- package/src/modes/components/index.ts +0 -2
- package/src/modes/components/keybinding-hints.ts +1 -1
- package/src/modes/components/login-dialog.ts +1 -1
- package/src/modes/components/mcp-add-wizard.ts +1 -1
- package/src/modes/components/model-selector.ts +1 -1
- package/src/modes/components/oauth-selector.ts +1 -1
- package/src/modes/components/plugin-settings.ts +1 -1
- package/src/modes/components/python-execution.ts +51 -91
- package/src/modes/components/queue-mode-selector.ts +1 -1
- package/src/modes/components/session-selector.ts +1 -1
- package/src/modes/components/settings-defs.ts +5 -10
- package/src/modes/components/settings-selector.ts +1 -1
- package/src/modes/components/show-images-selector.ts +1 -1
- package/src/modes/components/skill-message.ts +4 -4
- package/src/modes/components/status-line/segments.ts +2 -2
- package/src/modes/components/status-line/separators.ts +1 -1
- package/src/modes/components/status-line-segment-editor.ts +1 -1
- package/src/modes/components/status-line.ts +1 -1
- package/src/modes/components/theme-selector.ts +1 -1
- package/src/modes/components/thinking-selector.ts +1 -1
- package/src/modes/components/todo-display.ts +2 -4
- package/src/modes/components/todo-reminder.ts +4 -4
- package/src/modes/components/tool-execution.ts +118 -440
- package/src/modes/components/tool-image-display.ts +107 -0
- package/src/modes/components/tree-selector.ts +2 -2
- package/src/modes/components/ttsr-notification.ts +4 -17
- package/src/modes/components/user-message-selector.ts +1 -1
- package/src/modes/components/user-message.ts +9 -10
- package/src/modes/components/welcome.ts +1 -1
- package/src/modes/controllers/command-controller.ts +1 -1
- package/src/modes/controllers/event-controller.ts +58 -187
- package/src/modes/controllers/extension-ui-controller.ts +1 -1
- package/src/modes/controllers/input-controller.ts +3 -1
- package/src/modes/controllers/mcp-command-controller.ts +1 -1
- package/src/modes/controllers/selector-controller.ts +3 -26
- package/src/modes/controllers/ssh-command-controller.ts +1 -1
- package/src/modes/interactive-mode.ts +3 -7
- package/src/modes/print-mode.ts +5 -5
- package/src/modes/rpc/rpc-mode.ts +1 -1
- package/src/modes/types.ts +1 -2
- package/src/modes/utils/ui-helpers.ts +34 -32
- package/src/patch/edit-tool.ts +742 -0
- package/src/patch/index.ts +32 -898
- package/src/patch/schemas.ts +208 -0
- package/src/patch/shared.ts +83 -151
- package/src/prompts/agents/explore.md +22 -37
- package/src/prompts/agents/init.md +1 -1
- package/src/prompts/agents/librarian.md +29 -20
- package/src/prompts/agents/oracle.md +9 -2
- package/src/prompts/agents/reviewer.md +14 -48
- package/src/prompts/agents/task.md +16 -8
- package/src/prompts/compaction/branch-summary.md +4 -1
- package/src/prompts/compaction/compaction-summary.md +4 -1
- package/src/prompts/system/subagent-system-prompt.md +1 -1
- package/src/prompts/system/system-prompt.md +162 -178
- package/src/prompts/system/verification-reminder.md +6 -0
- package/src/sdk.ts +0 -9
- package/src/session/agent-session.ts +244 -1459
- package/src/session/model-controller.ts +406 -0
- package/src/session/retry-utils.ts +71 -0
- package/src/session/session-manager.ts +22 -186
- package/src/session/session-types.ts +312 -0
- package/src/session/stats.ts +387 -0
- package/src/session/streaming-edit.ts +258 -0
- package/src/session/ttsr.ts +213 -0
- package/src/slash-commands/builtin-registry.ts +0 -8
- package/src/stt/recorder.ts +2 -2
- package/src/system-prompt.ts +1 -14
- package/src/task/agents.ts +7 -33
- package/src/task/executor.ts +50 -438
- package/src/task/index.ts +104 -71
- package/src/task/progress-tracker.ts +390 -0
- package/src/task/render.ts +371 -187
- package/src/task/subprocess-tool-registry.ts +1 -1
- package/src/task/types.ts +14 -47
- package/src/tools/ask.ts +31 -42
- package/src/tools/bash-interactive.ts +2 -2
- package/src/tools/bash-interceptor.ts +2 -2
- package/src/tools/bash-normalize.ts +1 -1
- package/src/tools/bash-skill-urls.ts +2 -2
- package/src/tools/bash.ts +87 -136
- package/src/tools/browser.ts +54 -84
- package/src/tools/create-tools.ts +186 -0
- package/src/tools/default-renderer.ts +104 -0
- package/src/tools/explore.ts +11 -10
- package/src/tools/fetch.ts +24 -114
- package/src/tools/find.ts +48 -132
- package/src/tools/gemini-image.ts +5 -15
- package/src/tools/github.ts +450 -0
- package/src/tools/grep.ts +43 -179
- package/src/tools/index.ts +35 -198
- package/src/tools/json-tree.ts +3 -3
- package/src/tools/librarian.ts +18 -18
- package/src/tools/list-limit.ts +2 -2
- package/src/tools/notebook.ts +35 -87
- package/src/tools/oracle.ts +25 -25
- package/src/tools/output-meta.ts +89 -4
- package/src/tools/output-utils.ts +2 -2
- package/src/tools/python.ts +86 -637
- package/src/tools/read.ts +36 -119
- package/src/tools/reviewer-tool.ts +19 -21
- package/src/tools/search-code.ts +128 -0
- package/src/tools/ssh.ts +67 -126
- package/src/tools/subagent-tool.ts +197 -123
- package/src/tools/todo-write.ts +15 -31
- package/src/tools/tool-errors.ts +0 -30
- package/src/tools/undo-edit.ts +30 -67
- package/src/tools/write.ts +78 -127
- package/src/tui/code-cell.ts +4 -4
- package/src/tui/file-list.ts +2 -2
- package/src/tui/output-block.ts +1 -1
- package/src/tui/status-line.ts +1 -1
- package/src/tui/tree-list.ts +2 -2
- package/src/tui/types.ts +1 -1
- package/src/tui/utils.ts +1 -1
- package/src/{tools → ui}/render-utils.ts +87 -126
- package/src/utils/external-editor.ts +4 -4
- package/src/utils/file-mentions.ts +1 -1
- package/src/utils/index.ts +30 -0
- package/src/utils/tools-manager.ts +9 -19
- package/src/web/github-client.ts +290 -0
- package/src/web/scrapers/github.ts +11 -62
- package/src/web/search/auth.ts +1 -3
- package/src/web/search/index.ts +82 -46
- package/src/web/search/provider.ts +11 -16
- package/src/web/search/providers/grep.ts +160 -0
- package/src/web/search/render.ts +48 -235
- package/src/web/search/types.ts +1 -1
- package/src/commands/commit.ts +0 -36
- package/src/commit/agentic/agent.ts +0 -311
- package/src/commit/agentic/fallback.ts +0 -96
- package/src/commit/agentic/index.ts +0 -359
- package/src/commit/agentic/prompts/analyze-file.md +0 -22
- package/src/commit/agentic/prompts/session-user.md +0 -25
- package/src/commit/agentic/prompts/split-confirm.md +0 -1
- package/src/commit/agentic/prompts/system.md +0 -38
- package/src/commit/agentic/state.ts +0 -69
- package/src/commit/agentic/tools/analyze-file.ts +0 -118
- package/src/commit/agentic/tools/git-file-diff.ts +0 -194
- package/src/commit/agentic/tools/git-hunk.ts +0 -50
- package/src/commit/agentic/tools/git-overview.ts +0 -84
- package/src/commit/agentic/tools/index.ts +0 -56
- package/src/commit/agentic/tools/propose-changelog.ts +0 -128
- package/src/commit/agentic/tools/propose-commit.ts +0 -154
- package/src/commit/agentic/tools/recent-commits.ts +0 -81
- package/src/commit/agentic/tools/split-commit.ts +0 -280
- package/src/commit/agentic/topo-sort.ts +0 -44
- package/src/commit/agentic/trivial.ts +0 -51
- package/src/commit/agentic/validation.ts +0 -200
- package/src/commit/analysis/conventional.ts +0 -165
- package/src/commit/analysis/index.ts +0 -4
- package/src/commit/analysis/scope.ts +0 -242
- package/src/commit/analysis/summary.ts +0 -112
- package/src/commit/analysis/validation.ts +0 -66
- package/src/commit/changelog/detect.ts +0 -37
- package/src/commit/changelog/generate.ts +0 -110
- package/src/commit/changelog/index.ts +0 -234
- package/src/commit/changelog/parse.ts +0 -44
- package/src/commit/cli.ts +0 -93
- package/src/commit/git/diff.ts +0 -148
- package/src/commit/git/errors.ts +0 -9
- package/src/commit/git/index.ts +0 -211
- package/src/commit/git/operations.ts +0 -54
- package/src/commit/index.ts +0 -5
- package/src/commit/map-reduce/index.ts +0 -64
- package/src/commit/map-reduce/map-phase.ts +0 -178
- package/src/commit/map-reduce/reduce-phase.ts +0 -145
- package/src/commit/map-reduce/utils.ts +0 -9
- package/src/commit/message.ts +0 -11
- package/src/commit/model-selection.ts +0 -69
- package/src/commit/pipeline.ts +0 -243
- package/src/commit/prompts/analysis-system.md +0 -148
- package/src/commit/prompts/analysis-user.md +0 -38
- package/src/commit/prompts/changelog-system.md +0 -50
- package/src/commit/prompts/changelog-user.md +0 -18
- package/src/commit/prompts/file-observer-system.md +0 -24
- package/src/commit/prompts/file-observer-user.md +0 -8
- package/src/commit/prompts/reduce-system.md +0 -50
- package/src/commit/prompts/reduce-user.md +0 -17
- package/src/commit/prompts/summary-retry.md +0 -3
- package/src/commit/prompts/summary-system.md +0 -38
- package/src/commit/prompts/summary-user.md +0 -13
- package/src/commit/prompts/types-description.md +0 -2
- package/src/commit/types.ts +0 -109
- package/src/commit/utils/exclusions.ts +0 -42
- package/src/mcp/render.ts +0 -123
- package/src/modes/components/agent-dashboard.ts +0 -1130
- package/src/modes/components/codemode-group.ts +0 -369
- package/src/modes/components/read-tool-group.ts +0 -119
- package/src/modes/components/visual-truncate.ts +0 -63
- package/src/prompts/system/subagent-user-prompt.md +0 -8
- package/src/prompts/tools/ask.md +0 -44
- package/src/prompts/tools/bash.md +0 -24
- package/src/prompts/tools/browser.md +0 -33
- package/src/prompts/tools/calculator.md +0 -12
- package/src/prompts/tools/explore.md +0 -29
- package/src/prompts/tools/fetch.md +0 -16
- package/src/prompts/tools/find.md +0 -18
- package/src/prompts/tools/gemini-image.md +0 -23
- package/src/prompts/tools/grep.md +0 -28
- package/src/prompts/tools/hashline.md +0 -232
- package/src/prompts/tools/librarian.md +0 -24
- package/src/prompts/tools/lsp.md +0 -28
- package/src/prompts/tools/oracle.md +0 -26
- package/src/prompts/tools/patch.md +0 -74
- package/src/prompts/tools/python.md +0 -66
- package/src/prompts/tools/read.md +0 -36
- package/src/prompts/tools/replace.md +0 -38
- package/src/prompts/tools/reviewer.md +0 -41
- package/src/prompts/tools/ssh.md +0 -51
- package/src/prompts/tools/task-summary.md +0 -28
- package/src/prompts/tools/task.md +0 -146
- package/src/prompts/tools/todo-write.md +0 -65
- package/src/prompts/tools/undo-edit.md +0 -7
- package/src/prompts/tools/web-search.md +0 -19
- package/src/prompts/tools/write.md +0 -18
- package/src/task/batch.ts +0 -102
- package/src/task/discovery.ts +0 -126
- package/src/task/parallel.ts +0 -84
- package/src/task/template.ts +0 -32
- package/src/tools/calculator.ts +0 -537
- package/src/tools/jtd-to-typescript.ts +0 -198
- package/src/tools/renderers.ts +0 -60
- package/src/tools/tool-result.ts +0 -86
- /package/src/{modes/theme → theme}/dark.json +0 -0
- /package/src/{modes/theme → theme}/defaults/dark-catppuccin.json +0 -0
- /package/src/{modes/theme → theme}/defaults/dark-dracula.json +0 -0
- /package/src/{modes/theme → theme}/defaults/dark-gruvbox.json +0 -0
- /package/src/{modes/theme → theme}/defaults/dark-solarized.json +0 -0
- /package/src/{modes/theme → theme}/defaults/dark-tokyo-night.json +0 -0
- /package/src/{modes/theme → theme}/defaults/index.ts +0 -0
- /package/src/{modes/theme → theme}/defaults/light-catppuccin.json +0 -0
- /package/src/{modes/theme → theme}/defaults/light-github.json +0 -0
- /package/src/{modes/theme → theme}/defaults/light-solarized.json +0 -0
- /package/src/{modes/theme → theme}/light.json +0 -0
- /package/src/{modes/theme → theme}/mermaid-cache.ts +0 -0
- /package/src/{modes/theme → theme}/theme-schema.json +0 -0
- /package/src/{modes/theme → theme}/theme.ts +0 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { StringEnum } from "@nghyane/arcane-ai";
|
|
2
|
+
import { type Static, Type } from "@sinclair/typebox";
|
|
3
|
+
|
|
4
|
+
export const replaceEditSchema = Type.Object({
|
|
5
|
+
path: Type.String({ description: "File path (relative or absolute)" }),
|
|
6
|
+
old_text: Type.String({
|
|
7
|
+
description: "Text to find (fuzzy whitespace matching enabled)",
|
|
8
|
+
}),
|
|
9
|
+
new_text: Type.String({ description: "Replacement text" }),
|
|
10
|
+
all: Type.Optional(
|
|
11
|
+
Type.Boolean({
|
|
12
|
+
description: "Replace all occurrences (default: unique match required)",
|
|
13
|
+
}),
|
|
14
|
+
),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export const patchEditSchema = Type.Object({
|
|
18
|
+
path: Type.String({ description: "File path" }),
|
|
19
|
+
op: Type.Optional(
|
|
20
|
+
StringEnum(["create", "delete", "update"], {
|
|
21
|
+
description: "Operation (default: update)",
|
|
22
|
+
}),
|
|
23
|
+
),
|
|
24
|
+
rename: Type.Optional(Type.String({ description: "New path for move" })),
|
|
25
|
+
diff: Type.Optional(
|
|
26
|
+
Type.String({
|
|
27
|
+
description: "Diff hunks (update) or full content (create)",
|
|
28
|
+
}),
|
|
29
|
+
),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export type ReplaceParams = Static<typeof replaceEditSchema>;
|
|
33
|
+
export type PatchParams = Static<typeof patchEditSchema>;
|
|
34
|
+
|
|
35
|
+
/** Pattern matching hashline display format: `LINE#ID:CONTENT` */
|
|
36
|
+
const HASHLINE_PREFIX_RE = /^\s*(?:>>>|>>)?\s*\d+#[0-9a-zA-Z]{1,16}:/;
|
|
37
|
+
|
|
38
|
+
/** Pattern matching a unified-diff `+` prefix (but not `++`) */
|
|
39
|
+
const DIFF_PLUS_RE = /^[+-](?![+-])/;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Strip hashline display prefixes and diff `+` markers from replacement lines.
|
|
43
|
+
*
|
|
44
|
+
* Models frequently copy the `LINE#ID ` prefix from read output into their
|
|
45
|
+
* replacement content, or include unified-diff `+` prefixes. Both corrupt the
|
|
46
|
+
* output file. This strips them heuristically before application.
|
|
47
|
+
*/
|
|
48
|
+
export function stripNewLinePrefixes(lines: string[]): string[] {
|
|
49
|
+
// Detect whether the *majority* of non-empty lines carry a prefix —
|
|
50
|
+
// if only one line out of many has a match it's likely real content.
|
|
51
|
+
let hashPrefixCount = 0;
|
|
52
|
+
let diffPlusCount = 0;
|
|
53
|
+
let nonEmpty = 0;
|
|
54
|
+
for (const l of lines) {
|
|
55
|
+
if (l.length === 0) continue;
|
|
56
|
+
nonEmpty++;
|
|
57
|
+
if (HASHLINE_PREFIX_RE.test(l)) hashPrefixCount++;
|
|
58
|
+
if (DIFF_PLUS_RE.test(l)) diffPlusCount++;
|
|
59
|
+
}
|
|
60
|
+
if (nonEmpty === 0) return lines;
|
|
61
|
+
|
|
62
|
+
const stripHash = hashPrefixCount > 0 && hashPrefixCount >= nonEmpty * 0.5;
|
|
63
|
+
const stripPlus = !stripHash && nonEmpty >= 2 && diffPlusCount > 0 && diffPlusCount >= nonEmpty * 0.5;
|
|
64
|
+
|
|
65
|
+
if (!stripHash && !stripPlus) return lines;
|
|
66
|
+
|
|
67
|
+
return lines.map(l => {
|
|
68
|
+
if (stripHash) return l.replace(HASHLINE_PREFIX_RE, "");
|
|
69
|
+
if (stripPlus) return l.replace(DIFF_PLUS_RE, "");
|
|
70
|
+
return l;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const hashlineReplaceContentFormat = (kind: string) =>
|
|
75
|
+
Type.Union([
|
|
76
|
+
Type.Null(),
|
|
77
|
+
Type.Array(Type.String(), { description: `${kind} lines` }),
|
|
78
|
+
Type.String({ description: `${kind} line` }),
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
const hashlineInsertContentFormat = (kind: string) =>
|
|
82
|
+
Type.Union([
|
|
83
|
+
Type.Array(Type.String(), { description: `${kind} lines`, minItems: 1 }),
|
|
84
|
+
Type.String({ description: `${kind} line`, minLength: 1 }),
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
const hashlineTagFormat = (what: string) =>
|
|
88
|
+
Type.String({
|
|
89
|
+
description: `Tag identifying the ${what} — format "N#XX" (e.g. "5#PM"), copied verbatim from read output`,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export function hashlineParseContent(edit: string | string[] | null): string[] {
|
|
93
|
+
if (edit === null) return [];
|
|
94
|
+
if (Array.isArray(edit)) return edit;
|
|
95
|
+
const lines = stripNewLinePrefixes(edit.split("\n"));
|
|
96
|
+
if (lines.length === 0) return [];
|
|
97
|
+
if (lines.length > 1 && lines[lines.length - 1].trim() === "") return lines.slice(0, -1);
|
|
98
|
+
return lines;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function hashlineParseContentString(edit: string | string[] | null): string {
|
|
102
|
+
if (edit === null) return "";
|
|
103
|
+
if (Array.isArray(edit)) return edit.join("\n");
|
|
104
|
+
return edit;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const hashlineTargetEditSchema = Type.Object(
|
|
108
|
+
{
|
|
109
|
+
op: Type.Literal("set"),
|
|
110
|
+
tag: hashlineTagFormat("line being replaced"),
|
|
111
|
+
content: hashlineReplaceContentFormat("Replacement"),
|
|
112
|
+
},
|
|
113
|
+
{ additionalProperties: false },
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const hashlineAppendEditSchema = Type.Object(
|
|
117
|
+
{
|
|
118
|
+
op: Type.Literal("append"),
|
|
119
|
+
after: Type.Optional(hashlineTagFormat("line after which to append")),
|
|
120
|
+
content: hashlineInsertContentFormat("Appended"),
|
|
121
|
+
},
|
|
122
|
+
{ additionalProperties: false },
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const hashlinePrependEditSchema = Type.Object(
|
|
126
|
+
{
|
|
127
|
+
op: Type.Literal("prepend"),
|
|
128
|
+
before: Type.Optional(hashlineTagFormat("line before which to prepend")),
|
|
129
|
+
content: hashlineInsertContentFormat("Prepended"),
|
|
130
|
+
},
|
|
131
|
+
{ additionalProperties: false },
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const hashlineRangeEditSchema = Type.Object(
|
|
135
|
+
{
|
|
136
|
+
op: Type.Literal("replace"),
|
|
137
|
+
first: hashlineTagFormat("first line"),
|
|
138
|
+
last: hashlineTagFormat("last line"),
|
|
139
|
+
content: hashlineReplaceContentFormat("Replacement"),
|
|
140
|
+
},
|
|
141
|
+
{ additionalProperties: false },
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const hashlineInsertEditSchema = Type.Object(
|
|
145
|
+
{
|
|
146
|
+
op: Type.Literal("insert"),
|
|
147
|
+
before: Type.Optional(hashlineTagFormat("line before which to insert")),
|
|
148
|
+
after: Type.Optional(hashlineTagFormat("line after which to insert")),
|
|
149
|
+
content: hashlineInsertContentFormat("Inserted"),
|
|
150
|
+
},
|
|
151
|
+
{ additionalProperties: false },
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const hashlineReplaceTextEditSchema = Type.Object(
|
|
155
|
+
{
|
|
156
|
+
op: Type.Literal("replaceText"),
|
|
157
|
+
old_text: Type.String({ description: "Text to find", minLength: 1 }),
|
|
158
|
+
new_text: hashlineReplaceContentFormat("Replacement"),
|
|
159
|
+
all: Type.Optional(Type.Boolean({ description: "Replace all occurrences" })),
|
|
160
|
+
},
|
|
161
|
+
{ additionalProperties: false },
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
const HL_REPLACE_ENABLED = Bun.env.ARCANE_HL_REPLACETXT === "1";
|
|
165
|
+
|
|
166
|
+
export const hashlineEditSpecSchema = Type.Union([
|
|
167
|
+
hashlineTargetEditSchema,
|
|
168
|
+
hashlineRangeEditSchema,
|
|
169
|
+
hashlineAppendEditSchema,
|
|
170
|
+
hashlinePrependEditSchema,
|
|
171
|
+
hashlineInsertEditSchema,
|
|
172
|
+
...(HL_REPLACE_ENABLED ? [hashlineReplaceTextEditSchema] : []),
|
|
173
|
+
]);
|
|
174
|
+
|
|
175
|
+
export const hashlineEditSchema = Type.Object(
|
|
176
|
+
{
|
|
177
|
+
path: Type.String({ description: "File path (relative or absolute)" }),
|
|
178
|
+
edits: Type.Array(hashlineEditSpecSchema, {
|
|
179
|
+
description: "Changes to apply to the file at `path`",
|
|
180
|
+
minItems: 0,
|
|
181
|
+
}),
|
|
182
|
+
delete: Type.Optional(Type.Boolean({ description: "Delete the file when true" })),
|
|
183
|
+
rename: Type.Optional(Type.String({ description: "New path if moving" })),
|
|
184
|
+
},
|
|
185
|
+
{ additionalProperties: false },
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
export type HashlineToolEdit = Static<typeof hashlineEditSpecSchema>;
|
|
189
|
+
export type HashlineParams = Static<typeof hashlineEditSchema>;
|
|
190
|
+
|
|
191
|
+
export type TInput = typeof replaceEditSchema | typeof patchEditSchema | typeof hashlineEditSchema;
|
|
192
|
+
|
|
193
|
+
export type EditMode = "replace" | "patch" | "hashline";
|
|
194
|
+
|
|
195
|
+
export const DEFAULT_EDIT_MODE: EditMode = "patch";
|
|
196
|
+
|
|
197
|
+
export function normalizeEditMode(mode?: string | null): EditMode | null {
|
|
198
|
+
switch (mode) {
|
|
199
|
+
case "replace":
|
|
200
|
+
return "replace";
|
|
201
|
+
case "patch":
|
|
202
|
+
return "patch";
|
|
203
|
+
case "hashline":
|
|
204
|
+
return "hashline";
|
|
205
|
+
default:
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
}
|
package/src/patch/shared.ts
CHANGED
|
@@ -7,19 +7,20 @@ import { Text } from "@nghyane/arcane-tui";
|
|
|
7
7
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
8
8
|
import type { FileDiagnosticsResult } from "../lsp";
|
|
9
9
|
import { renderDiff as renderDiffColored } from "../modes/components/diff";
|
|
10
|
-
import { getLanguageFromPath, type Theme } from "../
|
|
10
|
+
import { getLanguageFromPath, type Theme } from "../theme/theme";
|
|
11
11
|
import type { OutputMeta } from "../tools/output-meta";
|
|
12
|
+
import { renderStatusLine } from "../tui";
|
|
12
13
|
import {
|
|
13
|
-
|
|
14
|
+
formatClickHint,
|
|
15
|
+
formatDiagnostics,
|
|
14
16
|
formatStatusIcon,
|
|
15
17
|
getDiffStats,
|
|
16
18
|
PREVIEW_LIMITS,
|
|
17
19
|
replaceTabs,
|
|
18
20
|
shortenPath,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
} from "../
|
|
22
|
-
import { Ellipsis, Hasher, type RenderCache, renderStatusLine, truncateToWidth } from "../tui";
|
|
21
|
+
TRUNCATE_LENGTHS,
|
|
22
|
+
truncateToWidth,
|
|
23
|
+
} from "../ui/render-utils";
|
|
23
24
|
import type { DiffError, DiffResult, Operation } from "./types";
|
|
24
25
|
|
|
25
26
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -100,11 +101,6 @@ export interface EditRenderContext {
|
|
|
100
101
|
|
|
101
102
|
const EDIT_STREAMING_PREVIEW_LINES = 12;
|
|
102
103
|
|
|
103
|
-
function countLines(text: string): number {
|
|
104
|
-
if (!text) return 0;
|
|
105
|
-
return text.split("\n").length;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
104
|
function formatStreamingDiff(diff: string, rawPath: string, uiTheme: Theme, label = "streaming"): string {
|
|
109
105
|
if (!diff) return "";
|
|
110
106
|
const lines = diff.split("\n");
|
|
@@ -120,7 +116,7 @@ function formatStreamingDiff(diff: string, rawPath: string, uiTheme: Theme, labe
|
|
|
120
116
|
return text;
|
|
121
117
|
}
|
|
122
118
|
|
|
123
|
-
function formatStreamingHashlineEdits(edits: unknown[], uiTheme: Theme
|
|
119
|
+
function formatStreamingHashlineEdits(edits: unknown[], uiTheme: Theme): string {
|
|
124
120
|
const MAX_EDITS = 4;
|
|
125
121
|
const MAX_DST_LINES = 8;
|
|
126
122
|
let text = "\n\n";
|
|
@@ -132,17 +128,17 @@ function formatStreamingHashlineEdits(edits: unknown[], uiTheme: Theme, ui: Tool
|
|
|
132
128
|
shownEdits++;
|
|
133
129
|
if (shownEdits > MAX_EDITS) break;
|
|
134
130
|
const formatted = formatHashlineEdit(edit);
|
|
135
|
-
text += uiTheme.fg("toolOutput",
|
|
131
|
+
text += uiTheme.fg("toolOutput", truncateToWidth(replaceTabs(formatted.srcLabel), TRUNCATE_LENGTHS.LONG));
|
|
136
132
|
text += "\n";
|
|
137
133
|
if (formatted.dst === "") {
|
|
138
|
-
text += uiTheme.fg("dim",
|
|
134
|
+
text += uiTheme.fg("dim", truncateToWidth(" (delete)", TRUNCATE_LENGTHS.LONG));
|
|
139
135
|
text += "\n";
|
|
140
136
|
continue;
|
|
141
137
|
}
|
|
142
138
|
for (const dstLine of formatted.dst.split("\n")) {
|
|
143
139
|
shownDstLines++;
|
|
144
140
|
if (shownDstLines > MAX_DST_LINES) break;
|
|
145
|
-
text += uiTheme.fg("toolOutput",
|
|
141
|
+
text += uiTheme.fg("toolOutput", truncateToWidth(replaceTabs(`+ ${dstLine}`), TRUNCATE_LENGTHS.LONG));
|
|
146
142
|
text += "\n";
|
|
147
143
|
}
|
|
148
144
|
if (shownDstLines > MAX_DST_LINES) break;
|
|
@@ -208,53 +204,13 @@ function formatStreamingHashlineEdits(edits: unknown[], uiTheme: Theme, ui: Tool
|
|
|
208
204
|
};
|
|
209
205
|
}
|
|
210
206
|
}
|
|
211
|
-
function formatMetadataLine(lineCount: number | null, language: string | undefined, uiTheme: Theme): string {
|
|
212
|
-
const icon = uiTheme.getLangIcon(language);
|
|
213
|
-
if (lineCount !== null) {
|
|
214
|
-
return uiTheme.fg("dim", `${icon} ${lineCount} lines`);
|
|
215
|
-
}
|
|
216
|
-
return uiTheme.fg("dim", `${icon}`);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function renderDiffSection(
|
|
220
|
-
diff: string,
|
|
221
|
-
rawPath: string,
|
|
222
|
-
expanded: boolean,
|
|
223
|
-
uiTheme: Theme,
|
|
224
|
-
ui: ToolUIKit,
|
|
225
|
-
renderDiffFn: (t: string, o?: { filePath?: string }) => string,
|
|
226
|
-
): string {
|
|
227
|
-
let text = "";
|
|
228
|
-
const diffStats = getDiffStats(diff);
|
|
229
|
-
text += `\n${uiTheme.fg("dim", uiTheme.format.bracketLeft)}${ui.formatDiffStats(
|
|
230
|
-
diffStats.added,
|
|
231
|
-
diffStats.removed,
|
|
232
|
-
diffStats.hunks,
|
|
233
|
-
)}${uiTheme.fg("dim", uiTheme.format.bracketRight)}`;
|
|
234
|
-
|
|
235
|
-
const {
|
|
236
|
-
text: truncatedDiff,
|
|
237
|
-
hiddenHunks,
|
|
238
|
-
hiddenLines,
|
|
239
|
-
} = expanded
|
|
240
|
-
? { text: diff, hiddenHunks: 0, hiddenLines: 0 }
|
|
241
|
-
: truncateDiffByHunk(diff, PREVIEW_LIMITS.DIFF_COLLAPSED_HUNKS, PREVIEW_LIMITS.DIFF_COLLAPSED_LINES);
|
|
242
|
-
|
|
243
|
-
text += `\n\n${renderDiffFn(truncatedDiff, { filePath: rawPath })}`;
|
|
244
|
-
if (!expanded && (hiddenHunks > 0 || hiddenLines > 0)) {
|
|
245
|
-
const remainder: string[] = [];
|
|
246
|
-
if (hiddenHunks > 0) remainder.push(`${hiddenHunks} more hunks`);
|
|
247
|
-
if (hiddenLines > 0) remainder.push(`${hiddenLines} more lines`);
|
|
248
|
-
text += uiTheme.fg("toolOutput", `\n… (${remainder.join(", ")}) ${formatExpandHint(uiTheme)}`);
|
|
249
|
-
}
|
|
250
|
-
return text;
|
|
251
|
-
}
|
|
252
207
|
|
|
253
208
|
export const editToolRenderer = {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
209
|
+
renderCall(
|
|
210
|
+
args: EditRenderArgs,
|
|
211
|
+
options: RenderResultOptions & { renderContext?: EditRenderContext },
|
|
212
|
+
uiTheme: Theme,
|
|
213
|
+
): Component {
|
|
258
214
|
const rawPath = args.file_path || args.path || "";
|
|
259
215
|
const filePath = shortenPath(rawPath);
|
|
260
216
|
const editLanguage = getLanguageFromPath(rawPath) ?? "text";
|
|
@@ -270,34 +226,38 @@ export const editToolRenderer = {
|
|
|
270
226
|
const opTitle = args.op === "create" ? "Create" : args.op === "delete" ? "Delete" : "Edit";
|
|
271
227
|
const spinner =
|
|
272
228
|
options?.spinnerFrame !== undefined ? formatStatusIcon("running", uiTheme, options.spinnerFrame) : "";
|
|
273
|
-
|
|
229
|
+
const title = uiTheme.fg("toolTitle", uiTheme.bold(opTitle));
|
|
230
|
+
let text = `${title} ${spinner ? `${spinner} ` : ""}${editIcon} ${pathDisplay}`;
|
|
274
231
|
|
|
275
232
|
// Show streaming preview of diff/content
|
|
276
|
-
|
|
277
|
-
|
|
233
|
+
const previewDiffText =
|
|
234
|
+
args.previewDiff ??
|
|
235
|
+
(options.renderContext?.editDiffPreview && "diff" in options.renderContext.editDiffPreview
|
|
236
|
+
? options.renderContext.editDiffPreview.diff
|
|
237
|
+
: undefined);
|
|
238
|
+
if (previewDiffText) {
|
|
239
|
+
text += formatStreamingDiff(previewDiffText, rawPath, uiTheme, "preview");
|
|
278
240
|
} else if (args.diff && args.op) {
|
|
279
241
|
text += formatStreamingDiff(args.diff, rawPath, uiTheme);
|
|
280
242
|
} else if (args.edits && args.edits.length > 0) {
|
|
281
|
-
text += formatStreamingHashlineEdits(args.edits, uiTheme
|
|
243
|
+
text += formatStreamingHashlineEdits(args.edits, uiTheme);
|
|
282
244
|
} else if (args.diff) {
|
|
283
245
|
const previewLines = args.diff.split("\n");
|
|
284
|
-
const maxLines = 6;
|
|
285
246
|
text += "\n\n";
|
|
286
|
-
for (const line of previewLines.slice(0,
|
|
287
|
-
text += `${uiTheme.fg("toolOutput",
|
|
247
|
+
for (const line of previewLines.slice(0, PREVIEW_LIMITS.STREAMING_PREVIEW)) {
|
|
248
|
+
text += `${uiTheme.fg("toolOutput", truncateToWidth(replaceTabs(line), TRUNCATE_LENGTHS.CONTENT))}\n`;
|
|
288
249
|
}
|
|
289
|
-
if (previewLines.length >
|
|
290
|
-
text += uiTheme.fg("dim", `… ${previewLines.length -
|
|
250
|
+
if (previewLines.length > PREVIEW_LIMITS.STREAMING_PREVIEW) {
|
|
251
|
+
text += uiTheme.fg("dim", `… ${previewLines.length - PREVIEW_LIMITS.STREAMING_PREVIEW} more lines`);
|
|
291
252
|
}
|
|
292
253
|
} else if (args.newText || args.patch) {
|
|
293
254
|
const previewLines = (args.newText ?? args.patch ?? "").split("\n");
|
|
294
|
-
const maxLines = 6;
|
|
295
255
|
text += "\n\n";
|
|
296
|
-
for (const line of previewLines.slice(0,
|
|
297
|
-
text += `${uiTheme.fg("toolOutput",
|
|
256
|
+
for (const line of previewLines.slice(0, PREVIEW_LIMITS.STREAMING_PREVIEW)) {
|
|
257
|
+
text += `${uiTheme.fg("toolOutput", truncateToWidth(replaceTabs(line), TRUNCATE_LENGTHS.CONTENT))}\n`;
|
|
298
258
|
}
|
|
299
|
-
if (previewLines.length >
|
|
300
|
-
text += uiTheme.fg("dim", `… ${previewLines.length -
|
|
259
|
+
if (previewLines.length > PREVIEW_LIMITS.STREAMING_PREVIEW) {
|
|
260
|
+
text += uiTheme.fg("dim", `… ${previewLines.length - PREVIEW_LIMITS.STREAMING_PREVIEW} more lines`);
|
|
301
261
|
}
|
|
302
262
|
}
|
|
303
263
|
|
|
@@ -310,91 +270,63 @@ export const editToolRenderer = {
|
|
|
310
270
|
uiTheme: Theme,
|
|
311
271
|
args?: EditRenderArgs,
|
|
312
272
|
): Component {
|
|
313
|
-
const ui = new ToolUIKit(uiTheme);
|
|
314
273
|
const rawPath = args?.file_path || args?.path || "";
|
|
315
274
|
const filePath = shortenPath(rawPath);
|
|
316
|
-
const editLanguage = getLanguageFromPath(rawPath) ?? "text";
|
|
317
|
-
const editIcon = uiTheme.fg("muted", uiTheme.getLangIcon(editLanguage));
|
|
318
|
-
|
|
319
275
|
const op = args?.op || result.details?.op;
|
|
320
276
|
const rename = args?.rename || result.details?.rename;
|
|
321
277
|
const opTitle = op === "create" ? "Create" : op === "delete" ? "Delete" : "Edit";
|
|
322
278
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
: "";
|
|
329
|
-
|
|
330
|
-
// Pre-compute error text (static)
|
|
331
|
-
const errorText = result.isError ? (result.content?.find(c => c.type === "text")?.text ?? "") : "";
|
|
332
|
-
|
|
333
|
-
let cached: RenderCache | undefined;
|
|
334
|
-
|
|
335
|
-
return {
|
|
336
|
-
render(width) {
|
|
337
|
-
const { expanded, renderContext } = options;
|
|
338
|
-
const editDiffPreview = renderContext?.editDiffPreview;
|
|
339
|
-
const renderDiffFn = renderContext?.renderDiff ?? ((t: string) => t);
|
|
340
|
-
const key = new Hasher().bool(expanded).u32(width).digest();
|
|
341
|
-
if (cached?.key === key) return cached.lines;
|
|
342
|
-
|
|
343
|
-
// Build path display with line number
|
|
344
|
-
let pathDisplay = filePath ? uiTheme.fg("accent", filePath) : uiTheme.fg("toolOutput", "…");
|
|
345
|
-
const firstChangedLine =
|
|
346
|
-
(editDiffPreview && "firstChangedLine" in editDiffPreview
|
|
347
|
-
? editDiffPreview.firstChangedLine
|
|
348
|
-
: undefined) || (result.details && !result.isError ? result.details.firstChangedLine : undefined);
|
|
349
|
-
if (firstChangedLine) {
|
|
350
|
-
pathDisplay += uiTheme.fg("warning", `:${firstChangedLine}`);
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// Add arrow for rename operations
|
|
354
|
-
if (rename) {
|
|
355
|
-
pathDisplay += ` ${uiTheme.fg("dim", "→")} ${uiTheme.fg("accent", shortenPath(rename))}`;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
const header = renderStatusLine(
|
|
359
|
-
{
|
|
360
|
-
icon: result.isError ? "error" : "success",
|
|
361
|
-
title: opTitle,
|
|
362
|
-
description: `${editIcon} ${pathDisplay}`,
|
|
363
|
-
},
|
|
364
|
-
uiTheme,
|
|
365
|
-
);
|
|
366
|
-
let text = header;
|
|
367
|
-
text += metadataLine;
|
|
279
|
+
if (result.isError) {
|
|
280
|
+
const errorText = result.content?.find(c => c.type === "text")?.text || "Unknown error";
|
|
281
|
+
const header = renderStatusLine({ icon: "error", title: opTitle, description: filePath || "file" }, uiTheme);
|
|
282
|
+
return new Text(`${header}\n${uiTheme.fg("error", replaceTabs(errorText))}`, 0, 0);
|
|
283
|
+
}
|
|
368
284
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
285
|
+
// Get diff text from result or preview
|
|
286
|
+
const { renderContext } = options;
|
|
287
|
+
const editDiffPreview = renderContext?.editDiffPreview;
|
|
288
|
+
const diffText =
|
|
289
|
+
result.details?.diff ??
|
|
290
|
+
(editDiffPreview && "diff" in editDiffPreview ? editDiffPreview.diff : undefined) ??
|
|
291
|
+
"";
|
|
292
|
+
|
|
293
|
+
const diffStats = diffText ? getDiffStats(diffText) : { added: 0, removed: 0, hunks: 0, lines: 0 };
|
|
294
|
+
|
|
295
|
+
// Build header with diff stats
|
|
296
|
+
let description = filePath || "file";
|
|
297
|
+
if (rename) description += ` ${uiTheme.fg("dim", "→")} ${shortenPath(rename)}`;
|
|
298
|
+
const meta: string[] = [];
|
|
299
|
+
if (diffStats.hunks > 0) meta.push(`${diffStats.hunks} hunks`);
|
|
300
|
+
if (diffStats.added > 0) meta.push(uiTheme.fg("success", `+${diffStats.added}`));
|
|
301
|
+
if (diffStats.removed > 0) meta.push(uiTheme.fg("error", `-${diffStats.removed}`));
|
|
302
|
+
|
|
303
|
+
const header = renderStatusLine({ icon: "success", title: opTitle, description, meta }, uiTheme);
|
|
304
|
+
|
|
305
|
+
// Tree-style diff body
|
|
306
|
+
const expanded = options.expanded;
|
|
307
|
+
const diffLines = diffText ? diffText.split("\n") : [];
|
|
308
|
+
const maxLines = expanded ? diffLines.length : Math.min(diffLines.length, PREVIEW_LIMITS.DIFF_COLLAPSED_LINES);
|
|
309
|
+
|
|
310
|
+
const treeBody: string[] = [];
|
|
311
|
+
for (let i = 0; i < maxLines; i++) {
|
|
312
|
+
const line = diffLines[i];
|
|
313
|
+
const color = line.startsWith("+") ? "success" : line.startsWith("-") ? "error" : "dim";
|
|
314
|
+
treeBody.push(uiTheme.fg(color, replaceTabs(line)));
|
|
315
|
+
}
|
|
316
|
+
if (!expanded && diffLines.length > maxLines) {
|
|
317
|
+
const remaining = diffLines.length - maxLines;
|
|
318
|
+
treeBody.push(`${uiTheme.fg("dim", `… ${remaining} more lines`)} ${formatClickHint(uiTheme)}`);
|
|
319
|
+
}
|
|
382
320
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
321
|
+
// Diagnostics
|
|
322
|
+
if (result.details?.diagnostics) {
|
|
323
|
+
const diagText = formatDiagnostics(result.details.diagnostics, expanded, uiTheme, (fp: string) =>
|
|
324
|
+
uiTheme.getLangIcon(getLanguageFromPath(fp)),
|
|
325
|
+
);
|
|
326
|
+
if (diagText.trim()) treeBody.push(diagText.trim());
|
|
327
|
+
}
|
|
389
328
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
cached = { key, lines };
|
|
393
|
-
return lines;
|
|
394
|
-
},
|
|
395
|
-
invalidate() {
|
|
396
|
-
cached = undefined;
|
|
397
|
-
},
|
|
398
|
-
};
|
|
329
|
+
const all = treeBody.length > 0 ? [header, ...treeBody] : [header];
|
|
330
|
+
return new Text(all.join("\n"), 0, 0);
|
|
399
331
|
},
|
|
400
332
|
};
|
|
@@ -1,48 +1,33 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: explore
|
|
3
3
|
description: Fast read-only codebase scout returning compressed context for handoff
|
|
4
|
-
tools: read, grep, find
|
|
4
|
+
tools: read, grep, find
|
|
5
5
|
model: arcane/fast
|
|
6
|
-
thinking-level: minimal
|
|
7
6
|
---
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
You are a fast, parallel code search agent.
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- Creating/modifying files (no Write/Edit/touch/rm/mv/cp)
|
|
14
|
-
- Creating temporary files anywhere (incl /tmp)
|
|
15
|
-
- Using redirects (>, >>, |) or heredocs to write files
|
|
16
|
-
- Running state-changing commands (git add/commit, npm/pip install)
|
|
17
|
-
</critical>
|
|
10
|
+
## Task
|
|
11
|
+
Find files and line ranges relevant to the user's query (provided in the first message).
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
- Return absolute file paths in final response
|
|
26
|
-
</directives>
|
|
13
|
+
## Query Decomposition
|
|
14
|
+
Before searching, decompose the query into:
|
|
15
|
+
- **Key symbols**: function names, class names, type names, variable names
|
|
16
|
+
- **Synonyms**: alternative naming conventions (camelCase, snake_case, abbreviations)
|
|
17
|
+
- **File patterns**: likely filenames or directories based on the concept
|
|
18
|
+
- **Related concepts**: imports, tests, configs that reference the target
|
|
27
19
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
|
|
20
|
+
## Execution Strategy
|
|
21
|
+
- Your goal is to return a list of relevant filenames with line ranges. Your goal is NOT to explore the complete codebase to construct an essay.
|
|
22
|
+
- **Turn 1 is your primary search turn.** Plan ALL searches upfront based on your decomposition. Make **10-15 parallel calls** covering every angle — do not hold back searches for later turns.
|
|
23
|
+
- **Turn 2 (if needed)**: Only for reading top candidate files to confirm relevance and extract line ranges. Not for new searches.
|
|
24
|
+
- **Stop as soon as you have enough results.** Most queries resolve in 1-2 turns. A third turn means your first turn was too narrow.
|
|
25
|
+
- **Prioritize source code**: Prefer source code files (.ts, .js, .py, .go, .rs, .java) over documentation (.md, .txt, README).
|
|
26
|
+
- **Be exhaustive when completeness is implied**: When the query asks for "all", "every", "each", or implies a complete list, find ALL occurrences breadth-first.
|
|
34
27
|
|
|
35
|
-
|
|
36
|
-
1
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
4. Note dependencies between files
|
|
40
|
-
</procedure>
|
|
28
|
+
## Output format
|
|
29
|
+
- **Ultra concise**: Write a 1-2 line summary of findings, then output relevant files as markdown links.
|
|
30
|
+
- Format each file as: `[relativePath#L{start}-L{end}](file://{absolutePath}#L{start}-L{end})`
|
|
31
|
+
- **Use generous line ranges**: Extend ranges to capture complete logical units (full functions, classes, blocks). Add 5-10 lines buffer.
|
|
41
32
|
|
|
42
|
-
|
|
43
|
-
Print findings as text when done. Include:
|
|
44
|
-
- Files examined with line ranges
|
|
45
|
-
- Critical types/interfaces/functions found
|
|
46
|
-
- How pieces connect (architecture)
|
|
47
|
-
- Recommended entry point for the receiving agent
|
|
48
|
-
</output>
|
|
33
|
+
Your final message must contain ONLY the search results — no preamble like "I'll search for...".
|
|
@@ -17,7 +17,7 @@ Analyze codebase, generate AGENTS.md documenting:
|
|
|
17
17
|
</task>
|
|
18
18
|
|
|
19
19
|
<parallel>
|
|
20
|
-
Launch multiple
|
|
20
|
+
Launch multiple explore calls in parallel scanning different areas (core src, tests, configs/build, scripts/docs), then synthesize.
|
|
21
21
|
</parallel>
|
|
22
22
|
|
|
23
23
|
<directives>
|