pi-readseek 0.3.1 → 0.3.3
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/README.md +24 -18
- package/index.ts +16 -144
- package/package.json +1 -1
- package/src/edit-output.ts +1 -7
- package/src/edit.ts +3 -14
- package/src/grep-output.ts +0 -26
- package/src/grep.ts +1 -13
- package/src/read-output.ts +1 -27
- package/src/read.ts +1 -10
- package/src/readseek-client.ts +1 -12
- package/src/sg-output.ts +0 -30
- package/src/sg.ts +14 -22
- package/src/write.ts +1 -13
- package/src/context-application.ts +0 -70
- package/src/context-hygiene.ts +0 -512
- package/src/doom-loop-suggestions.ts +0 -42
- package/src/doom-loop.ts +0 -216
- package/src/find.ts +0 -613
- package/src/ls.ts +0 -293
- package/src/readseek-command.ts +0 -170
- package/src/readseek-repo.ts +0 -50
package/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
`pi-readseek` is a pi extension for readseek-backed file reading, hash-anchored
|
|
4
4
|
editing, anchored grep, structural maps, symbol lookup, and structural search.
|
|
5
|
-
It
|
|
6
|
-
|
|
5
|
+
It resolves conflicts between overlapping pi file-operation tools by exposing
|
|
6
|
+
one consistent readseek-centered surface.
|
|
7
7
|
|
|
8
8
|
## Installation
|
|
9
9
|
|
|
@@ -11,25 +11,31 @@ exposing one consistent readseek-centered surface.
|
|
|
11
11
|
pi install npm:pi-readseek
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
+
The structural search and map features require the `@jarkkojs/readseek` native
|
|
15
|
+
binary. The extension auto-installs the correct platform package, or you can
|
|
16
|
+
install it manually:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Auto-installed by the extension on supported platforms.
|
|
20
|
+
# Manual install (if needed):
|
|
21
|
+
npm install --save-dev @jarkkojs/readseek
|
|
22
|
+
```
|
|
23
|
+
|
|
14
24
|
## Tools
|
|
15
25
|
|
|
16
|
-
-
|
|
17
|
-
images are returned as attachments.
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
`search`, or `write`.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- `grep` — searches text and returns edit-ready `LINE:HASH` anchors without a
|
|
26
|
+
- **read** — reads text files with `LINE:HASH` anchors for later `edit` calls;
|
|
27
|
+
images are returned as attachments. Supports `symbol`, `map`, and `bundle`
|
|
28
|
+
options powered by `@jarkkojs/readseek`.
|
|
29
|
+
- **edit** — changes existing text files using fresh anchors from `read`,
|
|
30
|
+
`grep`, `search`, or `write`. Variants: `set_line`, `replace_lines`,
|
|
31
|
+
`insert_after`, `replace_symbol`, `replace`. Set `new_text` to `""` to
|
|
32
|
+
delete a line.
|
|
33
|
+
- **grep** — searches text and returns edit-ready `LINE:HASH` anchors without a
|
|
25
34
|
follow-up `read`.
|
|
26
|
-
-
|
|
27
|
-
matches
|
|
28
|
-
-
|
|
29
|
-
follow-up edits.
|
|
30
|
-
to edit.
|
|
31
|
-
- `ls` — lists one directory.
|
|
32
|
-
- `find` — recursively discovers files and directories.
|
|
35
|
+
- **search** — searches code by structural pattern (AST) and returns anchored
|
|
36
|
+
matches. Use when syntax matters more than raw text.
|
|
37
|
+
- **write** — creates or overwrites whole files and returns anchors for
|
|
38
|
+
immediate follow-up edits.
|
|
33
39
|
|
|
34
40
|
## Licensing
|
|
35
41
|
|
package/index.ts
CHANGED
|
@@ -4,149 +4,21 @@ import { registerEditTool } from "./src/edit.js";
|
|
|
4
4
|
import { registerGrepTool } from "./src/grep.js";
|
|
5
5
|
import { registerSgTool, isSgAvailable } from "./src/sg.js";
|
|
6
6
|
import { registerWriteTool } from "./src/write.js";
|
|
7
|
-
import { registerLsTool } from "./src/ls.js";
|
|
8
|
-
import { registerFindTool } from "./src/find.js";
|
|
9
|
-
import { registerReadseekCommand } from "./src/readseek-command.js";
|
|
10
|
-
import { hasReadseekDir } from "./src/readseek-repo.js";
|
|
11
|
-
import { readseekUpdate } from "./src/readseek-client.js";
|
|
12
|
-
import { applyContextHygieneStaleContext } from "./src/context-application.js";
|
|
13
|
-
import {
|
|
14
|
-
createContextHygieneTracker,
|
|
15
|
-
normalizePathForContextHygiene,
|
|
16
|
-
type ContextHygieneEvent,
|
|
17
|
-
type ContextHygieneMetadata,
|
|
18
|
-
type ContextHygieneReport,
|
|
19
|
-
type ContextHygieneResource,
|
|
20
|
-
type ContextHygieneTracker,
|
|
21
|
-
} from "./src/context-hygiene.js";
|
|
22
|
-
import {
|
|
23
|
-
consumeDoomLoopWarning,
|
|
24
|
-
createDoomLoopState,
|
|
25
|
-
formatDoomLoopMessage,
|
|
26
|
-
recordToolCall,
|
|
27
|
-
} from "./src/doom-loop.js";
|
|
28
|
-
|
|
29
|
-
function isContextHygieneResource(value: unknown): value is ContextHygieneResource {
|
|
30
|
-
if (!value || typeof value !== "object") return false;
|
|
31
|
-
const resource = value as { kind?: unknown; key?: unknown };
|
|
32
|
-
return (resource.kind === "file" || resource.kind === "symbol") && typeof resource.key === "string";
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function isContextHygieneMetadata(value: unknown): value is ContextHygieneMetadata {
|
|
36
|
-
if (!value || typeof value !== "object") return false;
|
|
37
|
-
const metadata = value as Partial<ContextHygieneMetadata>;
|
|
38
|
-
return (
|
|
39
|
-
metadata.schemaVersion === 1 &&
|
|
40
|
-
typeof metadata.tool === "string" &&
|
|
41
|
-
(metadata.classification === "read-context" ||
|
|
42
|
-
metadata.classification === "search-context" ||
|
|
43
|
-
metadata.classification === "mutation") &&
|
|
44
|
-
Array.isArray(metadata.resources) &&
|
|
45
|
-
metadata.resources.every(isContextHygieneResource)
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function contextHygieneFromDetails(details: unknown): ContextHygieneMetadata | undefined {
|
|
50
|
-
if (!details || typeof details !== "object") return undefined;
|
|
51
|
-
const metadata = (details as { contextHygiene?: unknown }).contextHygiene;
|
|
52
|
-
return isContextHygieneMetadata(metadata) ? metadata : undefined;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function recordContextHygiene(
|
|
56
|
-
tracker: ContextHygieneTracker,
|
|
57
|
-
metadata: ContextHygieneMetadata,
|
|
58
|
-
toolCallId: unknown,
|
|
59
|
-
): ContextHygieneEvent {
|
|
60
|
-
return tracker.record(metadata, {
|
|
61
|
-
resultId: typeof toolCallId === "string" ? toolCallId : undefined,
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
7
|
export default function piReadseekExtension(pi: ExtensionAPI): void {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
: "Use grep summary for counts; install @jarkkojs/readseek to enable search.";
|
|
83
|
-
|
|
84
|
-
registerGrepTool(pi, { searchGuideline, onFileAnchored: noteRead });
|
|
85
|
-
registerSgTool(pi, { onFileAnchored: noteRead });
|
|
86
|
-
registerWriteTool(pi, { onFileAnchored: noteRead });
|
|
87
|
-
registerLsTool(pi);
|
|
88
|
-
registerFindTool(pi);
|
|
89
|
-
registerReadseekCommand(pi);
|
|
90
|
-
|
|
91
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
92
|
-
if (hasReadseekDir(ctx.cwd)) {
|
|
93
|
-
readseekUpdate(ctx.cwd).catch(() => {});
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
pi.on("tool_call", (event: any) => {
|
|
98
|
-
recordToolCall(
|
|
99
|
-
doomLoopState,
|
|
100
|
-
event.toolName,
|
|
101
|
-
event.toolCallId,
|
|
102
|
-
(event.input ?? {}) as Record<string, unknown>,
|
|
103
|
-
);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
const expireStaleReadTurns = (report: ContextHygieneReport) => {
|
|
107
|
-
if (readTurns.size === 0) return;
|
|
108
|
-
for (const candidate of report.staleCandidates) {
|
|
109
|
-
if (!candidate.resourceKey.startsWith("file:")) continue;
|
|
110
|
-
const resourcePath = readTurnKey(candidate.resourceKey.slice("file:".length));
|
|
111
|
-
const recordedEventId = readTurns.get(resourcePath);
|
|
112
|
-
if (recordedEventId === undefined) continue;
|
|
113
|
-
if (recordedEventId < candidate.mutationEventId) {
|
|
114
|
-
readTurns.delete(resourcePath);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
pi.on("context", (event: any): any => {
|
|
120
|
-
if (!Array.isArray(event.messages)) return undefined;
|
|
121
|
-
const report = contextHygieneTracker.generateReport();
|
|
122
|
-
const messages = applyContextHygieneStaleContext(event.messages, report);
|
|
123
|
-
expireStaleReadTurns(report);
|
|
124
|
-
return { messages };
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
pi.on("tool_result", (event: any) => {
|
|
128
|
-
const contextHygiene = contextHygieneFromDetails(event.details);
|
|
129
|
-
if (contextHygiene) recordContextHygiene(contextHygieneTracker, contextHygiene, event.toolCallId);
|
|
130
|
-
|
|
131
|
-
const doomLoop = consumeDoomLoopWarning(doomLoopState, event.toolCallId);
|
|
132
|
-
if (!doomLoop || !Array.isArray(event.content)) return undefined;
|
|
133
|
-
|
|
134
|
-
const content = [...event.content];
|
|
135
|
-
const prefix = `${formatDoomLoopMessage(doomLoop)}\n\n---\n`;
|
|
136
|
-
const textIndex = content.findIndex((item) => {
|
|
137
|
-
const maybeText = item as { type?: unknown; text?: unknown };
|
|
138
|
-
return maybeText.type === "text" && typeof maybeText.text === "string";
|
|
139
|
-
});
|
|
140
|
-
if (textIndex >= 0) {
|
|
141
|
-
const item = content[textIndex] as { type: "text"; text: string };
|
|
142
|
-
content[textIndex] = { ...item, text: `${prefix}${item.text}` };
|
|
143
|
-
} else {
|
|
144
|
-
content.unshift({ type: "text" as const, text: prefix });
|
|
145
|
-
}
|
|
146
|
-
return {
|
|
147
|
-
content,
|
|
148
|
-
details: event.details,
|
|
149
|
-
isError: event.isError,
|
|
150
|
-
};
|
|
151
|
-
});
|
|
8
|
+
const readPaths = new Set<string>();
|
|
9
|
+
const noteRead = (absolutePath: string) => {
|
|
10
|
+
readPaths.add(absolutePath);
|
|
11
|
+
};
|
|
12
|
+
const wasReadInSession = (absolutePath: string) => readPaths.has(absolutePath);
|
|
13
|
+
|
|
14
|
+
registerReadTool(pi, { onSuccessfulRead: noteRead });
|
|
15
|
+
registerEditTool(pi, { wasReadInSession });
|
|
16
|
+
const sgAvailable = isSgAvailable();
|
|
17
|
+
const searchGuideline = sgAvailable
|
|
18
|
+
? "Use grep summary for counts; use search for structural code patterns."
|
|
19
|
+
: "Use grep summary for counts; install @jarkkojs/readseek to enable search.";
|
|
20
|
+
|
|
21
|
+
registerGrepTool(pi, { searchGuideline, onFileAnchored: noteRead });
|
|
22
|
+
registerSgTool(pi, { onFileAnchored: noteRead });
|
|
23
|
+
registerWriteTool(pi, { onFileAnchored: noteRead });
|
|
152
24
|
}
|
package/package.json
CHANGED
package/src/edit-output.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { countEditTypes, parseDiffStats } from "./edit-render-helpers.js";
|
|
2
2
|
import { buildReadseekEditResult, type SemanticSummary } from "./readseek-value.js";
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import type { DiffData } from "./diff-data.js";
|
|
5
5
|
export interface BuildEditOutputInput {
|
|
6
6
|
path: string;
|
|
@@ -18,7 +18,6 @@ export interface EditOutputResult {
|
|
|
18
18
|
text: string;
|
|
19
19
|
patch: string;
|
|
20
20
|
readseekValue: ReturnType<typeof buildReadseekEditResult>;
|
|
21
|
-
contextHygiene: ContextHygieneMetadata;
|
|
22
21
|
}
|
|
23
22
|
function getVisibleDiffStats(diff: string): { added: number; removed: number } {
|
|
24
23
|
const stats = parseDiffStats(diff);
|
|
@@ -98,10 +97,5 @@ export function buildEditOutput(input: BuildEditOutputInput): EditOutputResult {
|
|
|
98
97
|
noopEdits: input.noopEdits,
|
|
99
98
|
...(input.semanticSummary ? { semanticSummary: input.semanticSummary } : {}),
|
|
100
99
|
}),
|
|
101
|
-
contextHygiene: buildContextHygieneMetadata({
|
|
102
|
-
tool: "edit",
|
|
103
|
-
classification: "mutation",
|
|
104
|
-
resources: [buildFileResource(input.path)],
|
|
105
|
-
}),
|
|
106
100
|
};
|
|
107
101
|
}
|
package/src/edit.ts
CHANGED
|
@@ -21,7 +21,7 @@ import { buildEditPreviewKey, buildPendingEditPreviewData, resolvePendingDiffPre
|
|
|
21
21
|
import { buildDiffData, type DiffBlockRange } from "./diff-data.js";
|
|
22
22
|
import { clampLineToWidth, clampLinesToWidth, isRendererExpanded, linkToolPath, summaryLine } from "./tui-render-utils.js";
|
|
23
23
|
import { DiffPreviewComponent } from "./tui-diff-component.js";
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
import { resolveEditDiffDisplay } from "./readseek-settings.js";
|
|
26
26
|
|
|
27
27
|
const EDIT_PENDING_PREVIEW_STATE_KEY = "hashline-edit-pending-preview";
|
|
@@ -100,11 +100,10 @@ function buildEditError(
|
|
|
100
100
|
message: string,
|
|
101
101
|
hint?: string,
|
|
102
102
|
errorDetails?: Record<string, unknown>,
|
|
103
|
-
contextHygiene?: ContextHygieneMetadata,
|
|
104
103
|
): {
|
|
105
104
|
content: [{ type: "text"; text: string }];
|
|
106
105
|
isError: true;
|
|
107
|
-
details: EditToolDetails & { readseekValue: any
|
|
106
|
+
details: EditToolDetails & { readseekValue: any };
|
|
108
107
|
} {
|
|
109
108
|
return {
|
|
110
109
|
content: [{ type: "text", text: message }],
|
|
@@ -119,8 +118,7 @@ function buildEditError(
|
|
|
119
118
|
path,
|
|
120
119
|
error: buildReadseekError(code, message, hint, errorDetails),
|
|
121
120
|
},
|
|
122
|
-
|
|
123
|
-
} as EditToolDetails & { readseekValue: any; contextHygiene?: ContextHygieneMetadata },
|
|
121
|
+
} as EditToolDetails & { readseekValue: any },
|
|
124
122
|
};
|
|
125
123
|
}
|
|
126
124
|
|
|
@@ -491,11 +489,6 @@ export function registerEditTool(pi: ExtensionAPI, options: EditToolOptions = {}
|
|
|
491
489
|
}
|
|
492
490
|
|
|
493
491
|
if (input.postEditVerify === true) {
|
|
494
|
-
const postWriteMutationContextHygiene = buildContextHygieneMetadata({
|
|
495
|
-
tool: "edit",
|
|
496
|
-
classification: "mutation",
|
|
497
|
-
resources: [buildFileResource(absolutePath)],
|
|
498
|
-
});
|
|
499
492
|
let verifiedContent: string;
|
|
500
493
|
try {
|
|
501
494
|
const verified = await fsReadFile(absolutePath, "utf-8");
|
|
@@ -506,7 +499,6 @@ export function registerEditTool(pi: ExtensionAPI, options: EditToolOptions = {}
|
|
|
506
499
|
fsCode: err?.code,
|
|
507
500
|
fsMessage: err?.message,
|
|
508
501
|
},
|
|
509
|
-
postWriteMutationContextHygiene,
|
|
510
502
|
);
|
|
511
503
|
}
|
|
512
504
|
if (verifiedContent !== writeContent) {
|
|
@@ -515,7 +507,6 @@ export function registerEditTool(pi: ExtensionAPI, options: EditToolOptions = {}
|
|
|
515
507
|
expectedLength: writeContent.length,
|
|
516
508
|
actualLength: verifiedContent.length,
|
|
517
509
|
},
|
|
518
|
-
postWriteMutationContextHygiene,
|
|
519
510
|
);
|
|
520
511
|
}
|
|
521
512
|
}
|
|
@@ -580,7 +571,6 @@ export function registerEditTool(pi: ExtensionAPI, options: EditToolOptions = {}
|
|
|
580
571
|
diffData,
|
|
581
572
|
firstChangedLine: anchorResult.firstChangedLine ?? diffResult.firstChangedLine,
|
|
582
573
|
readseekValue: builtOutput.readseekValue,
|
|
583
|
-
contextHygiene: builtOutput.contextHygiene,
|
|
584
574
|
} as EditToolDetails & {
|
|
585
575
|
diffData: typeof diffData;
|
|
586
576
|
readseekValue: {
|
|
@@ -594,7 +584,6 @@ export function registerEditTool(pi: ExtensionAPI, options: EditToolOptions = {}
|
|
|
594
584
|
warnings: string[];
|
|
595
585
|
noopEdits: unknown[];
|
|
596
586
|
};
|
|
597
|
-
contextHygiene: ContextHygieneMetadata;
|
|
598
587
|
},
|
|
599
588
|
};
|
|
600
589
|
});
|
package/src/grep-output.ts
CHANGED
|
@@ -4,14 +4,6 @@ import {
|
|
|
4
4
|
truncateHead,
|
|
5
5
|
} from "@earendil-works/pi-coding-agent";
|
|
6
6
|
import { resolveGrepOutputBudget } from "./grep-budget.js";
|
|
7
|
-
import {
|
|
8
|
-
buildContextHygieneMetadata,
|
|
9
|
-
buildFileResource,
|
|
10
|
-
buildSymbolResource,
|
|
11
|
-
type ContextHygieneMetadata,
|
|
12
|
-
type ContextHygieneRehydrateDescriptor,
|
|
13
|
-
type ContextHygieneResource,
|
|
14
|
-
} from "./context-hygiene.js";
|
|
15
7
|
|
|
16
8
|
export interface GrepOutputRecord extends ReadseekLine {
|
|
17
9
|
path: string;
|
|
@@ -64,7 +56,6 @@ export interface BuildGrepOutputInput {
|
|
|
64
56
|
scopeMode?: "symbol";
|
|
65
57
|
scopeWarnings?: GrepScopeWarning[];
|
|
66
58
|
passthroughLines?: string[];
|
|
67
|
-
rehydrate?: ContextHygieneRehydrateDescriptor | null;
|
|
68
59
|
}
|
|
69
60
|
|
|
70
61
|
export interface GrepOutputResult {
|
|
@@ -87,7 +78,6 @@ export interface GrepOutputResult {
|
|
|
87
78
|
warnings: GrepScopeWarning[];
|
|
88
79
|
};
|
|
89
80
|
};
|
|
90
|
-
contextHygiene: ContextHygieneMetadata;
|
|
91
81
|
}
|
|
92
82
|
|
|
93
83
|
function renderEntry(displayPath: string, entry: GrepOutputEntry): string {
|
|
@@ -174,24 +164,8 @@ export function buildGrepOutput(input: BuildGrepOutputInput): GrepOutputResult {
|
|
|
174
164
|
readseekValue.scopes = buildScopeMetadata(input.groups, input.scopeWarnings ?? []);
|
|
175
165
|
}
|
|
176
166
|
|
|
177
|
-
const contextHygieneResources: ContextHygieneResource[] = [];
|
|
178
|
-
for (const record of input.records) {
|
|
179
|
-
contextHygieneResources.push(buildFileResource(record.path));
|
|
180
|
-
}
|
|
181
|
-
for (const group of input.groups) {
|
|
182
|
-
if (!group.scope) continue;
|
|
183
|
-
contextHygieneResources.push(buildFileResource(group.absolutePath));
|
|
184
|
-
contextHygieneResources.push(buildSymbolResource(group.absolutePath, group.scope.symbol.name, group.scope.symbol.kind));
|
|
185
|
-
}
|
|
186
|
-
const contextHygiene = buildContextHygieneMetadata({
|
|
187
|
-
tool: "grep",
|
|
188
|
-
classification: "search-context",
|
|
189
|
-
resources: contextHygieneResources,
|
|
190
|
-
rehydrate: input.rehydrate ?? undefined,
|
|
191
|
-
});
|
|
192
167
|
return {
|
|
193
168
|
text,
|
|
194
169
|
readseekValue,
|
|
195
|
-
contextHygiene,
|
|
196
170
|
};
|
|
197
171
|
}
|
package/src/grep.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { looksLikeBinary } from "./binary-detect.js";
|
|
|
9
9
|
import { ensureHashInit, formatHashlineDisplay, escapeControlCharsForDisplay } from "./hashline.js";
|
|
10
10
|
import { buildReadseekError, buildReadseekLine } from "./readseek-value.js";
|
|
11
11
|
import { buildGrepOutput } from "./grep-output.js";
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
import { getOrGenerateMap } from "./map-cache.js";
|
|
14
14
|
import { scopeGrepGroupsToSymbols } from "./grep-symbol-scope.js";
|
|
15
15
|
import { resolveToCwd } from "./path-utils.js";
|
|
@@ -672,17 +672,6 @@ if (p.scope === "symbol" && !summary) {
|
|
|
672
672
|
scopeMode: p.scope === "symbol" && !summary ? "symbol" : undefined,
|
|
673
673
|
scopeWarnings,
|
|
674
674
|
passthroughLines,
|
|
675
|
-
rehydrate: buildGrepRehydrateDescriptor({
|
|
676
|
-
pattern: p.pattern,
|
|
677
|
-
path: p.path,
|
|
678
|
-
glob: p.glob,
|
|
679
|
-
literal: p.literal,
|
|
680
|
-
ignoreCase: p.ignoreCase,
|
|
681
|
-
context: p.context,
|
|
682
|
-
summary: p.summary,
|
|
683
|
-
scope: p.scope,
|
|
684
|
-
scopeContext: p.scopeContext,
|
|
685
|
-
}),
|
|
686
675
|
});
|
|
687
676
|
|
|
688
677
|
if (!summary && readseekRecords.length > 0) {
|
|
@@ -705,7 +694,6 @@ if (p.scope === "symbol" && !summary) {
|
|
|
705
694
|
details: {
|
|
706
695
|
...compactDetails,
|
|
707
696
|
readseekValue: builtOutput.readseekValue,
|
|
708
|
-
contextHygiene: builtOutput.contextHygiene,
|
|
709
697
|
},
|
|
710
698
|
};
|
|
711
699
|
},
|
package/src/read-output.ts
CHANGED
|
@@ -5,14 +5,7 @@ import {
|
|
|
5
5
|
truncateHead,
|
|
6
6
|
} from "@earendil-works/pi-coding-agent";
|
|
7
7
|
import { buildReadseekLines, renderReadseekLines, type ReadseekLine, type ReadseekWarning } from "./readseek-value.js";
|
|
8
|
-
|
|
9
|
-
buildContextHygieneMetadata,
|
|
10
|
-
buildFileResource,
|
|
11
|
-
buildSymbolResource,
|
|
12
|
-
type ContextHygieneMetadata,
|
|
13
|
-
type ContextHygieneRehydrateDescriptor,
|
|
14
|
-
type ContextHygieneResource,
|
|
15
|
-
} from "./context-hygiene.js";
|
|
8
|
+
|
|
16
9
|
|
|
17
10
|
export interface ReadSymbolMetadata {
|
|
18
11
|
query: string;
|
|
@@ -65,7 +58,6 @@ export interface ReadOutputInput {
|
|
|
65
58
|
symbol?: ReadSymbolMetadata | null;
|
|
66
59
|
map?: ReadMapMetadata;
|
|
67
60
|
bundle?: ReadBundleMetadata | null;
|
|
68
|
-
rehydrate?: ContextHygieneRehydrateDescriptor | null;
|
|
69
61
|
}
|
|
70
62
|
|
|
71
63
|
export interface ReadOutputResult {
|
|
@@ -101,7 +93,6 @@ export interface ReadOutputResult {
|
|
|
101
93
|
warnings: ReadseekWarning[];
|
|
102
94
|
};
|
|
103
95
|
};
|
|
104
|
-
contextHygiene: ContextHygieneMetadata;
|
|
105
96
|
}
|
|
106
97
|
|
|
107
98
|
export function buildReadOutput(input: ReadOutputInput): ReadOutputResult {
|
|
@@ -187,26 +178,9 @@ export function buildReadOutput(input: ReadOutputInput): ReadOutputResult {
|
|
|
187
178
|
};
|
|
188
179
|
}
|
|
189
180
|
|
|
190
|
-
const contextHygieneResources: ContextHygieneResource[] = [buildFileResource(input.path)];
|
|
191
|
-
if (input.symbol) {
|
|
192
|
-
contextHygieneResources.push(buildSymbolResource(input.path, input.symbol.name, input.symbol.kind));
|
|
193
|
-
}
|
|
194
|
-
if (input.bundle?.applied) {
|
|
195
|
-
for (const support of input.bundle.localSupport) {
|
|
196
|
-
contextHygieneResources.push(buildSymbolResource(input.path, support.symbol.name, support.symbol.kind));
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
const contextHygiene = buildContextHygieneMetadata({
|
|
200
|
-
tool: "read",
|
|
201
|
-
classification: "read-context",
|
|
202
|
-
resources: contextHygieneResources,
|
|
203
|
-
rehydrate: input.rehydrate ?? undefined,
|
|
204
|
-
});
|
|
205
|
-
|
|
206
181
|
return {
|
|
207
182
|
text,
|
|
208
183
|
lines,
|
|
209
184
|
readseekValue,
|
|
210
|
-
contextHygiene,
|
|
211
185
|
};
|
|
212
186
|
}
|
package/src/read.ts
CHANGED
|
@@ -20,7 +20,7 @@ import { formatFileMapWithBudget } from "./readseek/formatter.js";
|
|
|
20
20
|
import { findSymbol, type SymbolMatch } from "./readseek/symbol-lookup.js";
|
|
21
21
|
import { formatAmbiguous, formatNotFound } from "./readseek/symbol-error-format.js";
|
|
22
22
|
import { buildReadOutput } from "./read-output.js";
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
import { buildLocalBundle } from "./read-local-bundle.js";
|
|
25
25
|
import { coerceObviousBase10Int } from "./coerce-obvious-int.js";
|
|
26
26
|
import { readseekRead } from "./readseek-client.js";
|
|
@@ -681,14 +681,6 @@ export function registerReadTool(pi: ExtensionAPI, options: ReadToolOptions = {}
|
|
|
681
681
|
text: mapText,
|
|
682
682
|
},
|
|
683
683
|
...(bundleMetadata ? { bundle: bundleMetadata } : {}),
|
|
684
|
-
rehydrate: buildReadRehydrateDescriptor({
|
|
685
|
-
path: p.path,
|
|
686
|
-
offset: p.offset,
|
|
687
|
-
limit: p.limit,
|
|
688
|
-
symbol: p.symbol,
|
|
689
|
-
map: p.map,
|
|
690
|
-
bundle: p.bundle,
|
|
691
|
-
}),
|
|
692
684
|
});
|
|
693
685
|
|
|
694
686
|
return succeed({
|
|
@@ -696,7 +688,6 @@ export function registerReadTool(pi: ExtensionAPI, options: ReadToolOptions = {}
|
|
|
696
688
|
details: {
|
|
697
689
|
truncation: truncation.truncated ? truncation : undefined,
|
|
698
690
|
readseekValue: readOutput.readseekValue,
|
|
699
|
-
contextHygiene: readOutput.contextHygiene,
|
|
700
691
|
},
|
|
701
692
|
});
|
|
702
693
|
},
|
package/src/readseek-client.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { DetailLevel } from "./readseek/enums.js";
|
|
|
6
6
|
import type { FileMap, FileSymbol } from "./readseek/types.js";
|
|
7
7
|
import { SymbolKind } from "./readseek/enums.js";
|
|
8
8
|
|
|
9
|
-
interface ReadseekHashline {
|
|
9
|
+
export interface ReadseekHashline {
|
|
10
10
|
line: number;
|
|
11
11
|
hash: string;
|
|
12
12
|
text: string;
|
|
@@ -389,14 +389,3 @@ export async function readseekMapContent(
|
|
|
389
389
|
);
|
|
390
390
|
return fileMapFromReadseekOutput(output, filePath, Buffer.byteLength(content, "utf8"));
|
|
391
391
|
}
|
|
392
|
-
|
|
393
|
-
export interface ReadseekUpdateStats {
|
|
394
|
-
created: number;
|
|
395
|
-
removed: number;
|
|
396
|
-
unchanged: number;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
export async function readseekUpdate(cwd: string): Promise<ReadseekUpdateStats> {
|
|
400
|
-
const stdout = await runReadseekRaw(["update", cwd]);
|
|
401
|
-
return JSON.parse(stdout) as ReadseekUpdateStats;
|
|
402
|
-
}
|
package/src/sg-output.ts
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
import type { ReadseekLine, ReadseekRange } from "./readseek-value.js";
|
|
2
|
-
import {
|
|
3
|
-
buildContextHygieneMetadata,
|
|
4
|
-
buildFileResource,
|
|
5
|
-
buildSymbolResource,
|
|
6
|
-
type ContextHygieneMetadata,
|
|
7
|
-
type ContextHygieneRehydrateDescriptor,
|
|
8
|
-
type ContextHygieneResource,
|
|
9
|
-
} from "./context-hygiene.js";
|
|
10
2
|
|
|
11
3
|
export interface SgOutputFile {
|
|
12
4
|
displayPath: string;
|
|
@@ -19,7 +11,6 @@ export interface SgOutputFile {
|
|
|
19
11
|
export interface BuildSgOutputInput {
|
|
20
12
|
pattern: string;
|
|
21
13
|
files: SgOutputFile[];
|
|
22
|
-
rehydrate?: ContextHygieneRehydrateDescriptor | null;
|
|
23
14
|
}
|
|
24
15
|
|
|
25
16
|
export interface SgOutputResult {
|
|
@@ -32,7 +23,6 @@ export interface SgOutputResult {
|
|
|
32
23
|
lines: ReadseekLine[];
|
|
33
24
|
}>;
|
|
34
25
|
};
|
|
35
|
-
contextHygiene: ContextHygieneMetadata;
|
|
36
26
|
}
|
|
37
27
|
|
|
38
28
|
export function buildSgOutput(input: BuildSgOutputInput): SgOutputResult {
|
|
@@ -43,12 +33,6 @@ export function buildSgOutput(input: BuildSgOutputInput): SgOutputResult {
|
|
|
43
33
|
tool: "search",
|
|
44
34
|
files: [],
|
|
45
35
|
},
|
|
46
|
-
contextHygiene: buildContextHygieneMetadata({
|
|
47
|
-
tool: "search",
|
|
48
|
-
classification: "search-context",
|
|
49
|
-
resources: [],
|
|
50
|
-
rehydrate: input.rehydrate ?? undefined,
|
|
51
|
-
}),
|
|
52
36
|
};
|
|
53
37
|
}
|
|
54
38
|
|
|
@@ -60,14 +44,6 @@ export function buildSgOutput(input: BuildSgOutputInput): SgOutputResult {
|
|
|
60
44
|
}
|
|
61
45
|
}
|
|
62
46
|
|
|
63
|
-
const contextHygieneResources: ContextHygieneResource[] = [];
|
|
64
|
-
for (const file of input.files) {
|
|
65
|
-
contextHygieneResources.push(buildFileResource(file.path));
|
|
66
|
-
for (const symbol of file.symbols ?? []) {
|
|
67
|
-
contextHygieneResources.push(buildSymbolResource(file.path, symbol.name, symbol.kind));
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
47
|
return {
|
|
72
48
|
text: blocks.join("\n"),
|
|
73
49
|
readseekValue: {
|
|
@@ -78,11 +54,5 @@ export function buildSgOutput(input: BuildSgOutputInput): SgOutputResult {
|
|
|
78
54
|
lines: file.lines.map((line) => ({ ...line })),
|
|
79
55
|
})),
|
|
80
56
|
},
|
|
81
|
-
contextHygiene: buildContextHygieneMetadata({
|
|
82
|
-
tool: "search",
|
|
83
|
-
classification: "search-context",
|
|
84
|
-
resources: contextHygieneResources,
|
|
85
|
-
rehydrate: input.rehydrate ?? undefined,
|
|
86
|
-
}),
|
|
87
57
|
};
|
|
88
58
|
}
|