token-pilot 0.29.0 → 0.30.1
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +2 -4
- package/CHANGELOG.md +35 -0
- package/README.md +57 -384
- package/agents/tp-api-surface-tracker.md +1 -1
- package/agents/tp-audit-scanner.md +1 -1
- package/agents/tp-commit-writer.md +1 -1
- package/agents/tp-context-engineer.md +1 -1
- package/agents/tp-dead-code-finder.md +1 -1
- package/agents/tp-debugger.md +1 -1
- package/agents/tp-dep-health.md +1 -1
- package/agents/tp-doc-writer.md +1 -1
- package/agents/tp-history-explorer.md +1 -1
- package/agents/tp-impact-analyzer.md +1 -1
- package/agents/tp-incident-timeline.md +1 -1
- package/agents/tp-incremental-builder.md +1 -1
- package/agents/tp-migration-scout.md +1 -1
- package/agents/tp-onboard.md +1 -1
- package/agents/tp-performance-profiler.md +1 -1
- package/agents/tp-pr-reviewer.md +1 -1
- package/agents/tp-refactor-planner.md +1 -1
- package/agents/tp-review-impact.md +1 -1
- package/agents/tp-run.md +1 -1
- package/agents/tp-session-restorer.md +1 -1
- package/agents/tp-ship-coordinator.md +1 -1
- package/agents/tp-spec-writer.md +1 -1
- package/agents/tp-test-coverage-gapper.md +1 -1
- package/agents/tp-test-triage.md +1 -1
- package/agents/tp-test-writer.md +1 -1
- package/dist/ast-index/client.d.ts +17 -2
- package/dist/ast-index/client.js +233 -107
- package/dist/cli/tool-audit.d.ts +5 -0
- package/dist/cli/tool-audit.js +9 -1
- package/dist/core/edit-prep-state.d.ts +42 -0
- package/dist/core/edit-prep-state.js +108 -0
- package/dist/core/policy-engine.d.ts +1 -5
- package/dist/core/policy-engine.js +9 -24
- package/dist/handlers/explore-area.js +6 -1
- package/dist/handlers/read-for-edit.d.ts +5 -5
- package/dist/handlers/read-for-edit.js +188 -110
- package/dist/hooks/installer.js +18 -0
- package/dist/hooks/pre-bash.d.ts +11 -1
- package/dist/hooks/pre-bash.js +51 -1
- package/dist/hooks/pre-edit.d.ts +69 -0
- package/dist/hooks/pre-edit.js +104 -0
- package/dist/hooks/pre-grep.d.ts +12 -1
- package/dist/hooks/pre-grep.js +39 -1
- package/dist/index.d.ts +30 -0
- package/dist/index.js +87 -22
- package/dist/server/enforcement-mode.d.ts +47 -0
- package/dist/server/enforcement-mode.js +59 -0
- package/dist/server/tool-definitions.d.ts +20 -0
- package/dist/server/tool-definitions.js +127 -12
- package/dist/server/tool-profiles.d.ts +19 -1
- package/dist/server/tool-profiles.js +38 -4
- package/dist/server.d.ts +2 -0
- package/dist/server.js +89 -21
- package/docs/agents.md +82 -0
- package/docs/configuration.md +117 -0
- package/docs/hooks.md +99 -0
- package/docs/installation.md +169 -0
- package/docs/tools.md +61 -0
- package/hooks/hooks.json +18 -0
- package/package.json +2 -2
- package/start.sh +19 -9
package/dist/cli/tool-audit.d.ts
CHANGED
|
@@ -22,6 +22,11 @@ export interface ToolAuditRow {
|
|
|
22
22
|
/** Calls where the recorder claimed NO savings (pass-through) — separate so
|
|
23
23
|
* they don't poison the reduction average. */
|
|
24
24
|
noneCalls: number;
|
|
25
|
+
/** Calls where the MCP response was served from the session cache (the model
|
|
26
|
+
* replayed cached tokens). These contribute to `saved` but the mechanism
|
|
27
|
+
* is token re-use, not structural compression — useful to split out so the
|
|
28
|
+
* "Est.Saved*" column is understood correctly. */
|
|
29
|
+
cacheHitCalls: number;
|
|
25
30
|
/** True when reduction is below the low-value threshold AND we have enough
|
|
26
31
|
* samples (≥5) to make a claim — avoids flagging tools after 1 bad run. */
|
|
27
32
|
lowValue: boolean;
|
package/dist/cli/tool-audit.js
CHANGED
|
@@ -24,12 +24,15 @@ export function aggregateToolCalls(events, lowValueThreshold = 20, minSamples =
|
|
|
24
24
|
tokensReturned: 0,
|
|
25
25
|
tokensWouldBe: 0,
|
|
26
26
|
noneCalls: 0,
|
|
27
|
+
cacheHitCalls: 0,
|
|
27
28
|
};
|
|
28
29
|
row.count++;
|
|
29
30
|
row.tokensReturned += e.tokensReturned;
|
|
30
31
|
row.tokensWouldBe += e.tokensWouldBe;
|
|
31
32
|
if (e.savingsCategory === "none")
|
|
32
33
|
row.noneCalls++;
|
|
34
|
+
if (e.sessionCacheHit)
|
|
35
|
+
row.cacheHitCalls++;
|
|
33
36
|
byTool.set(e.tool, row);
|
|
34
37
|
}
|
|
35
38
|
const rows = [];
|
|
@@ -47,6 +50,7 @@ export function aggregateToolCalls(events, lowValueThreshold = 20, minSamples =
|
|
|
47
50
|
saved,
|
|
48
51
|
reductionPct,
|
|
49
52
|
noneCalls: r.noneCalls,
|
|
53
|
+
cacheHitCalls: r.cacheHitCalls,
|
|
50
54
|
lowValue,
|
|
51
55
|
});
|
|
52
56
|
}
|
|
@@ -74,7 +78,7 @@ Run a few MCP tool calls from your AI client, then re-run \`npx token-pilot tool
|
|
|
74
78
|
lines.push(`Token Pilot — tool audit`);
|
|
75
79
|
lines.push(` ${opts.totalEvents} calls across ${rows.length} tools (cumulative across sessions)`);
|
|
76
80
|
lines.push("");
|
|
77
|
-
lines.push(" Tool Calls
|
|
81
|
+
lines.push(" Tool Calls Est.Saved* Returned Reduction");
|
|
78
82
|
lines.push(" ─────────────────────────────────────────────────────────────────");
|
|
79
83
|
for (const r of rows) {
|
|
80
84
|
const tool = r.tool.padEnd(24);
|
|
@@ -91,6 +95,10 @@ Run a few MCP tool calls from your AI client, then re-run \`npx token-pilot tool
|
|
|
91
95
|
lines.push("Low-value tools flagged above have <20% token reduction across ≥5 calls.");
|
|
92
96
|
lines.push("Consider: check their `none` passthrough count, or whether a cheaper alternative (Grep, Read) would do the job.");
|
|
93
97
|
}
|
|
98
|
+
lines.push("");
|
|
99
|
+
lines.push("* Est.Saved is estimated against a full-file read baseline. Actual prompt");
|
|
100
|
+
lines.push(" savings depend on client caching — use `cacheHitCalls` in --json output");
|
|
101
|
+
lines.push(" to distinguish structural compression from cache re-use.");
|
|
94
102
|
return lines.join("\n");
|
|
95
103
|
}
|
|
96
104
|
export async function runToolAudit(opts) {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared disk state so a PreToolUse:Edit hook subprocess can tell whether
|
|
3
|
+
* the main-thread agent actually called `read_for_edit` before the Edit.
|
|
4
|
+
*
|
|
5
|
+
* Why file-backed: hook subprocesses spawn fresh per-call and see no
|
|
6
|
+
* in-process state from the MCP server. Keyed by a hash of projectRoot so
|
|
7
|
+
* two concurrent projects on the same machine don't cross-contaminate.
|
|
8
|
+
* Entries expire after 30 minutes — long enough to cover a typical edit
|
|
9
|
+
* session, short enough that a stale prep from a previous conversation
|
|
10
|
+
* doesn't let a bad Edit slip through tomorrow.
|
|
11
|
+
*
|
|
12
|
+
* All operations are best-effort: any I/O error is swallowed silently.
|
|
13
|
+
* A broken state file must NEVER block an Edit — it's a soft guardrail,
|
|
14
|
+
* not a file-system invariant. If the prep file is unreadable we act as
|
|
15
|
+
* if "no prep exists" and the hook behaves per its enforcement mode.
|
|
16
|
+
*/
|
|
17
|
+
declare function stateDir(): string;
|
|
18
|
+
declare function stateFile(projectRoot: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Record that `read_for_edit` was just called for `absPath`.
|
|
21
|
+
* Safe to call in any order, from any process — atomically rewrites the
|
|
22
|
+
* state file so a racing read never sees a half-written JSON.
|
|
23
|
+
*/
|
|
24
|
+
export declare function markEditPrepared(projectRoot: string, absPath: string, now?: number): void;
|
|
25
|
+
/**
|
|
26
|
+
* Has `read_for_edit` been called for `absPath` recently enough to
|
|
27
|
+
* authorise a follow-up Edit? Auto-prunes entries older than TTL.
|
|
28
|
+
*/
|
|
29
|
+
export declare function isEditPrepared(projectRoot: string, absPath: string, now?: number, ttlMs?: number): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Clear all prep state for a project root. Intended for tests and for the
|
|
32
|
+
* `doctor` CLI if we ever want an explicit reset button.
|
|
33
|
+
*/
|
|
34
|
+
export declare function clearEditPrep(projectRoot: string): void;
|
|
35
|
+
/** Exposed for tests so they don't need to import tmpdir themselves. */
|
|
36
|
+
export declare const __test__: {
|
|
37
|
+
stateDir: typeof stateDir;
|
|
38
|
+
stateFile: typeof stateFile;
|
|
39
|
+
DEFAULT_TTL_MS: number;
|
|
40
|
+
};
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=edit-prep-state.d.ts.map
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared disk state so a PreToolUse:Edit hook subprocess can tell whether
|
|
3
|
+
* the main-thread agent actually called `read_for_edit` before the Edit.
|
|
4
|
+
*
|
|
5
|
+
* Why file-backed: hook subprocesses spawn fresh per-call and see no
|
|
6
|
+
* in-process state from the MCP server. Keyed by a hash of projectRoot so
|
|
7
|
+
* two concurrent projects on the same machine don't cross-contaminate.
|
|
8
|
+
* Entries expire after 30 minutes — long enough to cover a typical edit
|
|
9
|
+
* session, short enough that a stale prep from a previous conversation
|
|
10
|
+
* doesn't let a bad Edit slip through tomorrow.
|
|
11
|
+
*
|
|
12
|
+
* All operations are best-effort: any I/O error is swallowed silently.
|
|
13
|
+
* A broken state file must NEVER block an Edit — it's a soft guardrail,
|
|
14
|
+
* not a file-system invariant. If the prep file is unreadable we act as
|
|
15
|
+
* if "no prep exists" and the hook behaves per its enforcement mode.
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from "node:fs";
|
|
18
|
+
import { createHash } from "node:crypto";
|
|
19
|
+
import { tmpdir } from "node:os";
|
|
20
|
+
import { join, resolve } from "node:path";
|
|
21
|
+
const STATE_DIR_NAME = "token-pilot-edit-prep";
|
|
22
|
+
const DEFAULT_TTL_MS = 30 * 60 * 1000; // 30 minutes
|
|
23
|
+
function stateDir() {
|
|
24
|
+
return join(tmpdir(), STATE_DIR_NAME);
|
|
25
|
+
}
|
|
26
|
+
function stateFile(projectRoot) {
|
|
27
|
+
const hash = createHash("sha1")
|
|
28
|
+
.update(resolve(projectRoot))
|
|
29
|
+
.digest("hex")
|
|
30
|
+
.slice(0, 16);
|
|
31
|
+
return join(stateDir(), `${hash}.json`);
|
|
32
|
+
}
|
|
33
|
+
function loadState(projectRoot) {
|
|
34
|
+
try {
|
|
35
|
+
const txt = readFileSync(stateFile(projectRoot), "utf-8");
|
|
36
|
+
const parsed = JSON.parse(txt);
|
|
37
|
+
if (parsed &&
|
|
38
|
+
typeof parsed === "object" &&
|
|
39
|
+
"paths" in parsed &&
|
|
40
|
+
typeof parsed.paths === "object") {
|
|
41
|
+
return parsed;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
/* corrupt / missing — fall through */
|
|
46
|
+
}
|
|
47
|
+
return { paths: {} };
|
|
48
|
+
}
|
|
49
|
+
function pruneExpired(state, ttlMs, now) {
|
|
50
|
+
const fresh = {};
|
|
51
|
+
for (const [p, ts] of Object.entries(state.paths)) {
|
|
52
|
+
if (typeof ts === "number" && now - ts < ttlMs) {
|
|
53
|
+
fresh[p] = ts;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { paths: fresh };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Record that `read_for_edit` was just called for `absPath`.
|
|
60
|
+
* Safe to call in any order, from any process — atomically rewrites the
|
|
61
|
+
* state file so a racing read never sees a half-written JSON.
|
|
62
|
+
*/
|
|
63
|
+
export function markEditPrepared(projectRoot, absPath, now = Date.now()) {
|
|
64
|
+
try {
|
|
65
|
+
const dir = stateDir();
|
|
66
|
+
if (!existsSync(dir))
|
|
67
|
+
mkdirSync(dir, { recursive: true });
|
|
68
|
+
const state = pruneExpired(loadState(projectRoot), DEFAULT_TTL_MS, now);
|
|
69
|
+
state.paths[resolve(absPath)] = now;
|
|
70
|
+
const file = stateFile(projectRoot);
|
|
71
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
72
|
+
writeFileSync(tmp, JSON.stringify(state));
|
|
73
|
+
renameSync(tmp, file);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
/* best-effort — see module doc */
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Has `read_for_edit` been called for `absPath` recently enough to
|
|
81
|
+
* authorise a follow-up Edit? Auto-prunes entries older than TTL.
|
|
82
|
+
*/
|
|
83
|
+
export function isEditPrepared(projectRoot, absPath, now = Date.now(), ttlMs = DEFAULT_TTL_MS) {
|
|
84
|
+
const state = pruneExpired(loadState(projectRoot), ttlMs, now);
|
|
85
|
+
return typeof state.paths[resolve(absPath)] === "number";
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Clear all prep state for a project root. Intended for tests and for the
|
|
89
|
+
* `doctor` CLI if we ever want an explicit reset button.
|
|
90
|
+
*/
|
|
91
|
+
export function clearEditPrep(projectRoot) {
|
|
92
|
+
try {
|
|
93
|
+
const file = stateFile(projectRoot);
|
|
94
|
+
if (existsSync(file)) {
|
|
95
|
+
writeFileSync(file, JSON.stringify({ paths: {} }));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
/* best effort */
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Exposed for tests so they don't need to import tmpdir themselves. */
|
|
103
|
+
export const __test__ = {
|
|
104
|
+
stateDir,
|
|
105
|
+
stateFile,
|
|
106
|
+
DEFAULT_TTL_MS,
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=edit-prep-state.js.map
|
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
export interface PolicyConfig {
|
|
7
7
|
/** Advisory hints when an expensive tool is used where a cheaper alternative exists */
|
|
8
8
|
preferCheapReads: boolean;
|
|
9
|
-
/** Track if read_for_edit was called before edit (advisory) */
|
|
10
|
-
requireReadForEditBeforeEdit: boolean;
|
|
11
9
|
/** Always cache project overview in session cache */
|
|
12
10
|
cacheProjectOverview: boolean;
|
|
13
11
|
/** Warn after N full-file reads in a session */
|
|
@@ -25,13 +23,11 @@ export declare const DEFAULT_POLICIES: PolicyConfig;
|
|
|
25
23
|
export interface PolicyCheckContext {
|
|
26
24
|
fullFileReadsCount: number;
|
|
27
25
|
tokensReturned: number;
|
|
28
|
-
readForEditCalled?: Set<string>;
|
|
29
|
-
editTargetPath?: string;
|
|
30
26
|
totalCallCount?: number;
|
|
31
27
|
totalTokensReturned?: number;
|
|
32
28
|
}
|
|
33
29
|
export interface PolicyAdvisory {
|
|
34
|
-
level:
|
|
30
|
+
level: "info" | "warn";
|
|
35
31
|
message: string;
|
|
36
32
|
}
|
|
37
33
|
/**
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export const DEFAULT_POLICIES = {
|
|
7
7
|
preferCheapReads: true,
|
|
8
|
-
requireReadForEditBeforeEdit: true,
|
|
9
8
|
cacheProjectOverview: true,
|
|
10
9
|
maxFullFileReads: 10,
|
|
11
10
|
warnOnLargeReads: true,
|
|
@@ -14,14 +13,11 @@ export const DEFAULT_POLICIES = {
|
|
|
14
13
|
compactionTokenThreshold: 8000,
|
|
15
14
|
};
|
|
16
15
|
/** Full-file read tools that count toward maxFullFileReads */
|
|
17
|
-
const FULL_READ_TOOLS = new Set([
|
|
18
|
-
'smart_read',
|
|
19
|
-
'smart_read_many',
|
|
20
|
-
]);
|
|
16
|
+
const FULL_READ_TOOLS = new Set(["smart_read", "smart_read_many"]);
|
|
21
17
|
/** Tools that indicate a cheaper alternative may exist */
|
|
22
18
|
const EXPENSIVE_TOOLS = {
|
|
23
|
-
smart_read:
|
|
24
|
-
smart_read_many:
|
|
19
|
+
smart_read: "Consider read_symbol() or read_range() for targeted reads",
|
|
20
|
+
smart_read_many: "Consider reading files individually with read_symbol()",
|
|
25
21
|
};
|
|
26
22
|
/**
|
|
27
23
|
* Check policy rules and return advisory messages.
|
|
@@ -33,7 +29,7 @@ export function checkPolicy(policy, tool, context) {
|
|
|
33
29
|
FULL_READ_TOOLS.has(tool) &&
|
|
34
30
|
context.fullFileReadsCount >= policy.maxFullFileReads) {
|
|
35
31
|
return {
|
|
36
|
-
level:
|
|
32
|
+
level: "warn",
|
|
37
33
|
message: `POLICY: ${context.fullFileReadsCount} full-file reads this session (limit: ${policy.maxFullFileReads}). Consider read_symbol() or read_range() for targeted access.`,
|
|
38
34
|
};
|
|
39
35
|
}
|
|
@@ -41,7 +37,7 @@ export function checkPolicy(policy, tool, context) {
|
|
|
41
37
|
if (policy.warnOnLargeReads &&
|
|
42
38
|
context.tokensReturned > policy.largeReadThreshold) {
|
|
43
39
|
return {
|
|
44
|
-
level:
|
|
40
|
+
level: "info",
|
|
45
41
|
message: `POLICY: Large response (~${context.tokensReturned} tokens). Future reads on this file: use read_symbol() or read_range() for targeted access.`,
|
|
46
42
|
};
|
|
47
43
|
}
|
|
@@ -50,29 +46,18 @@ export function checkPolicy(policy, tool, context) {
|
|
|
50
46
|
// Only advise when token count is high enough to matter
|
|
51
47
|
if (context.tokensReturned > 500) {
|
|
52
48
|
return {
|
|
53
|
-
level:
|
|
49
|
+
level: "info",
|
|
54
50
|
message: `POLICY: ${EXPENSIVE_TOOLS[tool]}`,
|
|
55
51
|
};
|
|
56
52
|
}
|
|
57
53
|
}
|
|
58
|
-
// 4.
|
|
59
|
-
if (policy.requireReadForEditBeforeEdit &&
|
|
60
|
-
tool === 'edit' &&
|
|
61
|
-
context.editTargetPath &&
|
|
62
|
-
context.readForEditCalled &&
|
|
63
|
-
!context.readForEditCalled.has(context.editTargetPath)) {
|
|
64
|
-
return {
|
|
65
|
-
level: 'info',
|
|
66
|
-
message: `POLICY: Consider using read_for_edit("${context.editTargetPath}") before editing to get precise edit context.`,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
// 5. Session compaction advisory — by call count
|
|
54
|
+
// 4. Session compaction advisory — by call count
|
|
70
55
|
if (policy.compactionCallThreshold > 0 &&
|
|
71
56
|
context.totalCallCount !== undefined &&
|
|
72
57
|
context.totalCallCount > 0 &&
|
|
73
58
|
context.totalCallCount % policy.compactionCallThreshold === 0) {
|
|
74
59
|
return {
|
|
75
|
-
level:
|
|
60
|
+
level: "info",
|
|
76
61
|
message: `COMPACTION: ${context.totalCallCount} tool calls this session. Consider calling session_snapshot() to capture state, then compact context.`,
|
|
77
62
|
};
|
|
78
63
|
}
|
|
@@ -84,7 +69,7 @@ export function checkPolicy(policy, tool, context) {
|
|
|
84
69
|
context.totalCallCount % 5 === 0 // don't spam every call, check every 5th
|
|
85
70
|
) {
|
|
86
71
|
return {
|
|
87
|
-
level:
|
|
72
|
+
level: "info",
|
|
88
73
|
message: `COMPACTION: ~${context.totalTokensReturned} tokens returned this session. Consider calling session_snapshot() to capture state, then compact context.`,
|
|
89
74
|
};
|
|
90
75
|
}
|
|
@@ -42,7 +42,12 @@ export async function handleExploreArea(args, projectRoot, astIndex) {
|
|
|
42
42
|
absPath = dirname(absPath);
|
|
43
43
|
}
|
|
44
44
|
const relDir = relative(projectRoot, absPath) || ".";
|
|
45
|
-
|
|
45
|
+
// v0.30.0 — narrowed default from all 4 sections to the two cheap ones.
|
|
46
|
+
// Telemetry (docker-local-env, 2026-04-24) showed the all-4 default giving
|
|
47
|
+
// negative token reduction (-7%): `imports` builds a full dep graph and
|
|
48
|
+
// `tests` walks subtrees, both easily outweighing the raw-file baseline.
|
|
49
|
+
// Callers who need imports/tests now opt in explicitly via `include`.
|
|
50
|
+
const include = args.include ?? ["outline", "changes"];
|
|
46
51
|
// Collect code files for import/test analysis
|
|
47
52
|
const codeFiles = await listCodeFiles(absPath);
|
|
48
53
|
// Run all sections in parallel
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { AstIndexClient } from
|
|
2
|
-
import type { SymbolResolver } from
|
|
3
|
-
import type { FileCache } from
|
|
4
|
-
import type { ContextRegistry } from
|
|
1
|
+
import type { AstIndexClient } from "../ast-index/client.js";
|
|
2
|
+
import type { SymbolResolver } from "../core/symbol-resolver.js";
|
|
3
|
+
import type { FileCache } from "../core/file-cache.js";
|
|
4
|
+
import type { ContextRegistry } from "../core/context-registry.js";
|
|
5
5
|
export interface ReadForEditArgs {
|
|
6
6
|
path: string;
|
|
7
7
|
symbol?: string;
|
|
@@ -17,7 +17,7 @@ export declare function handleReadForEdit(args: ReadForEditArgs, projectRoot: st
|
|
|
17
17
|
actionableHints?: boolean;
|
|
18
18
|
}): Promise<{
|
|
19
19
|
content: Array<{
|
|
20
|
-
type:
|
|
20
|
+
type: "text";
|
|
21
21
|
text: string;
|
|
22
22
|
}>;
|
|
23
23
|
}>;
|