pi-readseek 0.10.6 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -4
- package/dist/index.ts +1538 -1943
- package/package.json +3 -3
- package/prompts/{edit.md → edit_text.md} +2 -2
- package/prompts/{def.md → find_definitions.md} +1 -1
- package/prompts/{search.md → find_nodes.md} +12 -1
- package/prompts/{extract.md → show_assets.md} +1 -1
- package/prompts/{inspect.md → show_content.md} +1 -1
- /package/prompts/{refs.md → find_references.md} +0 -0
- /package/prompts/{grep.md → find_text.md} +0 -0
- /package/prompts/{rename.md → rename_symbol.md} +0 -0
- /package/prompts/{write.md → write_file.md} +0 -0
package/dist/index.ts
CHANGED
|
@@ -6,14 +6,6 @@ import { Type as Type3 } from "@sinclair/typebox";
|
|
|
6
6
|
import { Text as Text3 } from "@earendil-works/pi-tui";
|
|
7
7
|
|
|
8
8
|
// ../readseek-api/src/contract.ts
|
|
9
|
-
var INSPECT_FACETS = [
|
|
10
|
-
"metadata",
|
|
11
|
-
"content",
|
|
12
|
-
"map",
|
|
13
|
-
"diagnostics",
|
|
14
|
-
"identity"
|
|
15
|
-
];
|
|
16
|
-
var VISION_MODES = ["none", "all", "ocr", "caption", "objects"];
|
|
17
9
|
var VISION_LEVELS = ["low", "medium", "high"];
|
|
18
10
|
var EDIT_VARIANTS = [
|
|
19
11
|
"set_line",
|
|
@@ -24,15 +16,22 @@ var EDIT_VARIANTS = [
|
|
|
24
16
|
];
|
|
25
17
|
var GIT_SCOPES = ["tracked", "untracked", "ignored", "all"];
|
|
26
18
|
var TOOL_NAMES = [
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
19
|
+
"show_content",
|
|
20
|
+
"show_structure",
|
|
21
|
+
"show_metadata",
|
|
22
|
+
"show_assets",
|
|
23
|
+
"check_syntax",
|
|
24
|
+
"check_rules",
|
|
25
|
+
"generate_caption",
|
|
26
|
+
"detect_objects",
|
|
27
|
+
"recognize_text",
|
|
28
|
+
"find_nodes",
|
|
29
|
+
"find_text",
|
|
30
|
+
"find_definitions",
|
|
31
|
+
"find_references",
|
|
32
|
+
"edit_text",
|
|
33
|
+
"rename_symbol",
|
|
34
|
+
"write_file"
|
|
36
35
|
];
|
|
37
36
|
var PARAM_DESCRIPTIONS = {
|
|
38
37
|
path: "Absolute or relative file path",
|
|
@@ -43,31 +42,30 @@ var PARAM_DESCRIPTIONS = {
|
|
|
43
42
|
languageOverride: "Language override",
|
|
44
43
|
languageSymbol: "Language override for symbol replacement",
|
|
45
44
|
pattern: "AST pattern (ast-grep style), such as console.log($$$ARGS)",
|
|
45
|
+
patternContext: "Surrounding code context for sub-statement patterns",
|
|
46
|
+
selector: "Target AST node kind to extract from pattern context",
|
|
46
47
|
grepPattern: "Regex pattern; set literal for exact text",
|
|
47
48
|
name: "Qualified or unqualified symbol name",
|
|
48
49
|
refsName: "Identifier to find references for",
|
|
49
|
-
scope: "Restrict results to the binding at the cursor",
|
|
50
|
-
line: "One-based cursor line; required with scope",
|
|
51
|
-
renameLine: "One-based cursor line of the symbol to rename",
|
|
52
|
-
column: "One-based cursor byte column for disambiguation",
|
|
53
50
|
gitScope: "In a Git repository, which files to search: tracked, untracked, ignored (untracked plus ignored), or all. Defaults to tracked plus untracked.",
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
query: "KDL selection query, @path, or '-' for standard input",
|
|
51
|
+
at: "Location selector: line:N[:COLUMN], hash:H[:COLUMN], symbol:NAME, page:N, node:ID, or asset:ID",
|
|
52
|
+
assetAt: "Document selector: page:N, node:ID, or asset:ID",
|
|
53
|
+
rule: "KDL node selection rule, @path, or '-' for standard input",
|
|
54
|
+
rules: "KDL structural checks, @path, or '-' for standard input",
|
|
59
55
|
stdinName: "File name hint when the target is '-'",
|
|
60
56
|
end: "Last line to include",
|
|
61
57
|
limit: "Maximum number of lines to include",
|
|
62
|
-
|
|
58
|
+
depth: "Maximum structural depth for structure output; defaults to 1 in agent tools",
|
|
63
59
|
offset: "One-based starting line",
|
|
64
60
|
readLimit: "Maximum lines to return",
|
|
65
61
|
symbolRead: "Symbol name to read",
|
|
66
62
|
bundle: "Include related symbols from the same file; requires symbol",
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
level: "Explicit inference level: low (default), medium, or high",
|
|
64
|
+
include: "Additional caption tasks: text and/or objects",
|
|
65
|
+
kind: "Restrict structure to this node kind",
|
|
66
|
+
outline: "Return a symbol outline",
|
|
67
|
+
noAnchors: "Omit source line anchors",
|
|
68
|
+
text: "Literal native text query; adapter find_text also supports regex via pattern",
|
|
71
69
|
edits: "Use set_line, replace_lines, insert_after, replace_symbol, or replace",
|
|
72
70
|
editVariant: "Exactly one nested edit variant",
|
|
73
71
|
setLine: 'Replace one line: {"set_line":{"anchor":"LINE:HASH","new_text":"..."}}',
|
|
@@ -104,15 +102,22 @@ var PARAM_DESCRIPTIONS = {
|
|
|
104
102
|
scopeContext: "Context lines within each symbol"
|
|
105
103
|
};
|
|
106
104
|
var TOOL_DESCRIPTIONS = {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
105
|
+
show_content: "Read source, document content, or image descriptors without inference. Obtain fresh `LINE:HASH` anchors before edits; use at with a column for cursor context. Document results include typed nodes and cached asset paths.",
|
|
106
|
+
show_structure: "Show parsed source or document hierarchy. Use shallow depth for file overviews.",
|
|
107
|
+
show_metadata: "Show format, source identity, language, dimensions, or page count without decoding image content or inference.",
|
|
108
|
+
show_assets: "Return selected document asset descriptors with usable cached paths. Adapters attach images from those paths.",
|
|
109
|
+
check_syntax: "Check parser syntax diagnostics. Exit 0 is clean, 1 has findings, 2 is failure; this is not type checking.",
|
|
110
|
+
check_rules: "Evaluate KDL structural assertions. Exit 0 is clean, 1 has findings, 2 is failure.",
|
|
111
|
+
generate_caption: "Explicitly infer a caption using an installed model. Include text and objects to request OCR and detection too; never downloads models automatically.",
|
|
112
|
+
detect_objects: "Explicitly infer object labels and bounding boxes using an installed model.",
|
|
113
|
+
recognize_text: "Explicitly recognize text from pixels using an installed model; reading never silently invokes OCR.",
|
|
114
|
+
find_nodes: "Find AST nodes by pattern or KDL selection rule. Returns edit-ready anchors. Use `find_text` for text and regex.",
|
|
115
|
+
find_text: "Search text or regex and return edit-ready `LINE:HASH` anchors. Native CLI text is literal; adapters preserve regex, glob, context, summary, and symbol grouping.",
|
|
116
|
+
find_definitions: "Find a symbol definition or declaration by qualified or unqualified name.",
|
|
117
|
+
find_references: "Find identifier-name matches with name, or binding-scoped references with at. Use before renaming or deleting a symbol.",
|
|
118
|
+
edit_text: "Edit existing files with fresh `LINE:HASH` anchors. Each edits item contains exactly one set_line, replace_lines, insert_after, replace_symbol, or replace object. Preview before applying a verified plan.",
|
|
119
|
+
rename_symbol: "Rename a symbol at a line or hash cursor with binding-aware edits and stale-plan protection.",
|
|
120
|
+
write_file: "Create or replace a complete text file and return `LINE:HASH` anchors. Use `edit_text` for small changes."
|
|
116
121
|
};
|
|
117
122
|
function renderToolDescription(name, aliases = {}) {
|
|
118
123
|
const desc = TOOL_DESCRIPTIONS[name];
|
|
@@ -188,244 +193,84 @@ var editItemSchema = {
|
|
|
188
193
|
},
|
|
189
194
|
description: PARAM_DESCRIPTIONS.editVariant
|
|
190
195
|
};
|
|
196
|
+
var string = (description) => ({ type: "string", description });
|
|
197
|
+
var integer = (description, minimum = 1) => ({ type: "integer", minimum, description });
|
|
198
|
+
var path = { path: string(PARAM_DESCRIPTIONS.path) };
|
|
199
|
+
var at = { at: string(PARAM_DESCRIPTIONS.at) };
|
|
200
|
+
var lang = { language: string(PARAM_DESCRIPTIONS.language) };
|
|
201
|
+
var stdin = { stdinName: string(PARAM_DESCRIPTIONS.stdinName) };
|
|
202
|
+
var noAnchors = { noAnchors: { type: "boolean", description: PARAM_DESCRIPTIONS.noAnchors } };
|
|
203
|
+
var level = { level: { type: "string", enum: VISION_LEVELS, description: PARAM_DESCRIPTIONS.level } };
|
|
204
|
+
var limit = { limit: integer(PARAM_DESCRIPTIONS.matchLimit) };
|
|
205
|
+
var apply = { apply: { type: "boolean", description: PARAM_DESCRIPTIONS.apply }, planHash: string(PARAM_DESCRIPTIONS.planHash) };
|
|
206
|
+
function tool(name, title, properties, required) {
|
|
207
|
+
return { name, title, description: TOOL_DESCRIPTIONS[name], inputSchema: { type: "object", properties, required, additionalProperties: false } };
|
|
208
|
+
}
|
|
191
209
|
var TOOL_CONTRACTS = [
|
|
192
|
-
{
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
type: "string",
|
|
209
|
-
enum: [...VISION_MODES],
|
|
210
|
-
description: PARAM_DESCRIPTIONS.visionModeInspect
|
|
211
|
-
},
|
|
212
|
-
visionLevel: {
|
|
213
|
-
type: "string",
|
|
214
|
-
enum: [...VISION_LEVELS],
|
|
215
|
-
description: PARAM_DESCRIPTIONS.visionLevel
|
|
216
|
-
},
|
|
217
|
-
stdinName: { type: "string", description: PARAM_DESCRIPTIONS.stdinName }
|
|
218
|
-
},
|
|
219
|
-
required: ["path"],
|
|
220
|
-
additionalProperties: false
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
name: "edit",
|
|
225
|
-
title: "Hash-verified edit",
|
|
226
|
-
description: TOOL_DESCRIPTIONS.edit,
|
|
227
|
-
inputSchema: {
|
|
228
|
-
type: "object",
|
|
229
|
-
properties: {
|
|
230
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.path },
|
|
231
|
-
edits: {
|
|
232
|
-
type: "array",
|
|
233
|
-
minItems: 1,
|
|
234
|
-
description: PARAM_DESCRIPTIONS.edits,
|
|
235
|
-
items: editItemSchema
|
|
236
|
-
},
|
|
237
|
-
language: { type: "string", description: PARAM_DESCRIPTIONS.languageSymbol },
|
|
238
|
-
apply: { type: "boolean", description: PARAM_DESCRIPTIONS.apply },
|
|
239
|
-
planHash: { type: "string", description: PARAM_DESCRIPTIONS.planHash },
|
|
240
|
-
postEditVerify: { type: "boolean", description: PARAM_DESCRIPTIONS.postEditVerify }
|
|
241
|
-
},
|
|
242
|
-
required: ["path", "edits"],
|
|
243
|
-
additionalProperties: false
|
|
244
|
-
}
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
name: "write",
|
|
248
|
-
title: "Write file",
|
|
249
|
-
description: TOOL_DESCRIPTIONS.write,
|
|
250
|
-
inputSchema: {
|
|
251
|
-
type: "object",
|
|
252
|
-
properties: {
|
|
253
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.path },
|
|
254
|
-
content: { type: "string", description: PARAM_DESCRIPTIONS.content }
|
|
255
|
-
},
|
|
256
|
-
required: ["path", "content"],
|
|
257
|
-
additionalProperties: false
|
|
258
|
-
}
|
|
259
|
-
},
|
|
260
|
-
{
|
|
261
|
-
name: "grep",
|
|
262
|
-
title: "Text search",
|
|
263
|
-
description: TOOL_DESCRIPTIONS.grep,
|
|
264
|
-
inputSchema: {
|
|
265
|
-
type: "object",
|
|
266
|
-
properties: {
|
|
267
|
-
pattern: { type: "string", description: PARAM_DESCRIPTIONS.grepPattern },
|
|
268
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.searchPath },
|
|
269
|
-
glob: { type: "string", description: PARAM_DESCRIPTIONS.glob },
|
|
270
|
-
ignoreCase: { type: "boolean", description: PARAM_DESCRIPTIONS.ignoreCase },
|
|
271
|
-
literal: { type: "boolean", description: PARAM_DESCRIPTIONS.literal },
|
|
272
|
-
context: { type: "integer", minimum: 0, description: PARAM_DESCRIPTIONS.context },
|
|
273
|
-
limit: { type: "integer", minimum: 1, description: PARAM_DESCRIPTIONS.matchLimit },
|
|
274
|
-
summary: { type: "boolean", description: PARAM_DESCRIPTIONS.summary },
|
|
275
|
-
scope: {
|
|
276
|
-
type: "string",
|
|
277
|
-
enum: ["symbol"],
|
|
278
|
-
description: PARAM_DESCRIPTIONS.grepScope
|
|
279
|
-
},
|
|
280
|
-
scopeContext: {
|
|
281
|
-
type: "integer",
|
|
282
|
-
minimum: 0,
|
|
283
|
-
description: PARAM_DESCRIPTIONS.scopeContext
|
|
284
|
-
}
|
|
285
|
-
},
|
|
286
|
-
required: ["pattern"],
|
|
287
|
-
additionalProperties: false
|
|
288
|
-
}
|
|
289
|
-
},
|
|
290
|
-
{
|
|
291
|
-
name: "extract",
|
|
292
|
-
title: "Extract asset",
|
|
293
|
-
description: TOOL_DESCRIPTIONS.extract,
|
|
294
|
-
inputSchema: {
|
|
295
|
-
type: "object",
|
|
296
|
-
properties: {
|
|
297
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.path },
|
|
298
|
-
selector: {
|
|
299
|
-
type: "string",
|
|
300
|
-
pattern: "^asset:.+",
|
|
301
|
-
description: PARAM_DESCRIPTIONS.assetSelector
|
|
302
|
-
},
|
|
303
|
-
output: {
|
|
304
|
-
type: "string",
|
|
305
|
-
minLength: 1,
|
|
306
|
-
pattern: "^(?!-$).+",
|
|
307
|
-
description: PARAM_DESCRIPTIONS.output
|
|
308
|
-
},
|
|
309
|
-
stdinName: { type: "string", description: PARAM_DESCRIPTIONS.stdinName }
|
|
310
|
-
},
|
|
311
|
-
required: ["path", "selector", "output"],
|
|
312
|
-
additionalProperties: false
|
|
313
|
-
}
|
|
314
|
-
},
|
|
315
|
-
{
|
|
316
|
-
name: "search",
|
|
317
|
-
title: "AST search",
|
|
318
|
-
description: TOOL_DESCRIPTIONS.search,
|
|
319
|
-
inputSchema: {
|
|
320
|
-
type: "object",
|
|
321
|
-
properties: {
|
|
322
|
-
pattern: { type: "string", description: PARAM_DESCRIPTIONS.pattern },
|
|
323
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.searchPath },
|
|
324
|
-
language: { type: "string", description: PARAM_DESCRIPTIONS.language },
|
|
325
|
-
limit: { type: "integer", minimum: 1, description: PARAM_DESCRIPTIONS.matchLimit },
|
|
326
|
-
...gitScopeSchema
|
|
327
|
-
},
|
|
328
|
-
required: ["pattern"],
|
|
329
|
-
additionalProperties: false
|
|
330
|
-
}
|
|
331
|
-
},
|
|
332
|
-
{
|
|
333
|
-
name: "def",
|
|
334
|
-
title: "Find definition",
|
|
335
|
-
description: TOOL_DESCRIPTIONS.def,
|
|
336
|
-
inputSchema: {
|
|
337
|
-
type: "object",
|
|
338
|
-
properties: {
|
|
339
|
-
name: { type: "string", description: PARAM_DESCRIPTIONS.name },
|
|
340
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.searchPath },
|
|
341
|
-
language: { type: "string", description: PARAM_DESCRIPTIONS.language },
|
|
342
|
-
...gitScopeSchema
|
|
343
|
-
},
|
|
344
|
-
required: ["name"],
|
|
345
|
-
additionalProperties: false
|
|
346
|
-
}
|
|
347
|
-
},
|
|
348
|
-
{
|
|
349
|
-
name: "refs",
|
|
350
|
-
title: "Find references",
|
|
351
|
-
description: TOOL_DESCRIPTIONS.refs,
|
|
352
|
-
inputSchema: {
|
|
353
|
-
type: "object",
|
|
354
|
-
properties: {
|
|
355
|
-
name: { type: "string", description: PARAM_DESCRIPTIONS.refsName },
|
|
356
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.searchPath },
|
|
357
|
-
language: { type: "string", description: PARAM_DESCRIPTIONS.language },
|
|
358
|
-
scope: { type: "boolean", description: PARAM_DESCRIPTIONS.scope },
|
|
359
|
-
line: { type: "integer", minimum: 1, description: PARAM_DESCRIPTIONS.line },
|
|
360
|
-
column: { type: "integer", minimum: 1, description: PARAM_DESCRIPTIONS.column },
|
|
361
|
-
...gitScopeSchema
|
|
362
|
-
},
|
|
363
|
-
additionalProperties: false
|
|
364
|
-
}
|
|
365
|
-
},
|
|
366
|
-
{
|
|
367
|
-
name: "rename",
|
|
368
|
-
title: "Rename symbol",
|
|
369
|
-
description: TOOL_DESCRIPTIONS.rename,
|
|
370
|
-
inputSchema: {
|
|
371
|
-
type: "object",
|
|
372
|
-
properties: {
|
|
373
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.path },
|
|
374
|
-
line: { type: "integer", minimum: 1, description: PARAM_DESCRIPTIONS.renameLine },
|
|
375
|
-
column: { type: "integer", minimum: 1, description: PARAM_DESCRIPTIONS.column },
|
|
376
|
-
to: { type: "string", description: PARAM_DESCRIPTIONS.to },
|
|
377
|
-
workspace: { type: "boolean", description: PARAM_DESCRIPTIONS.workspace },
|
|
378
|
-
apply: { type: "boolean", description: PARAM_DESCRIPTIONS.apply },
|
|
379
|
-
planHash: { type: "string", description: PARAM_DESCRIPTIONS.planHash },
|
|
380
|
-
language: { type: "string", description: PARAM_DESCRIPTIONS.language },
|
|
381
|
-
...gitScopeSchema
|
|
382
|
-
},
|
|
383
|
-
required: ["path", "line", "to"],
|
|
384
|
-
additionalProperties: false
|
|
385
|
-
}
|
|
386
|
-
}
|
|
210
|
+
tool("show_content", "Show content", { ...path, ...at, ...lang, ...stdin, ...noAnchors, end: integer(PARAM_DESCRIPTIONS.end), limit: integer(PARAM_DESCRIPTIONS.limit) }, ["path"]),
|
|
211
|
+
tool("show_structure", "Show structure", { ...path, ...at, ...lang, ...stdin, depth: integer(PARAM_DESCRIPTIONS.depth, 0), kind: string(PARAM_DESCRIPTIONS.kind), outline: { type: "boolean", description: PARAM_DESCRIPTIONS.outline } }, ["path"]),
|
|
212
|
+
tool("show_metadata", "Show metadata", { ...path, ...lang, ...stdin }, ["path"]),
|
|
213
|
+
tool("show_assets", "Show assets", { ...path, at: string(PARAM_DESCRIPTIONS.assetAt), ...stdin }, ["path"]),
|
|
214
|
+
tool("check_syntax", "Check syntax", { ...path, ...lang, ...stdin }, ["path"]),
|
|
215
|
+
tool("check_rules", "Check rules", { ...path, ...gitScopeSchema, rules: string(PARAM_DESCRIPTIONS.rules) }, ["rules"]),
|
|
216
|
+
tool("generate_caption", "Generate caption", { ...path, ...at, ...stdin, ...level, include: { type: "array", items: { type: "string", enum: ["text", "objects"] }, minItems: 1, uniqueItems: true, description: PARAM_DESCRIPTIONS.include } }, ["path"]),
|
|
217
|
+
tool("detect_objects", "Detect objects", { ...path, ...at, ...stdin, ...level }, ["path"]),
|
|
218
|
+
tool("recognize_text", "Recognize text", { ...path, ...at, ...stdin, ...level }, ["path"]),
|
|
219
|
+
tool("find_nodes", "Find nodes", { ...path, ...lang, ...stdin, ...limit, ...gitScopeSchema, ...noAnchors, pattern: string(PARAM_DESCRIPTIONS.pattern), context: string(PARAM_DESCRIPTIONS.patternContext), selector: string(PARAM_DESCRIPTIONS.selector), rule: string(PARAM_DESCRIPTIONS.rule) }, []),
|
|
220
|
+
tool("find_text", "Find text", { ...path, ...limit, ...gitScopeSchema, text: string(PARAM_DESCRIPTIONS.text), pattern: string(PARAM_DESCRIPTIONS.grepPattern), glob: string(PARAM_DESCRIPTIONS.glob), ignoreCase: { type: "boolean", description: PARAM_DESCRIPTIONS.ignoreCase }, literal: { type: "boolean", description: PARAM_DESCRIPTIONS.literal }, context: integer(PARAM_DESCRIPTIONS.context, 0), summary: { type: "boolean", description: PARAM_DESCRIPTIONS.summary }, scope: { type: "string", enum: ["symbol"], description: PARAM_DESCRIPTIONS.grepScope }, scopeContext: integer(PARAM_DESCRIPTIONS.scopeContext, 0) }, []),
|
|
221
|
+
tool("find_definitions", "Find definitions", { ...path, ...lang, ...gitScopeSchema, ...noAnchors, name: string(PARAM_DESCRIPTIONS.name) }, ["name"]),
|
|
222
|
+
tool("find_references", "Find references", { ...path, ...at, ...lang, ...gitScopeSchema, ...noAnchors, name: string(PARAM_DESCRIPTIONS.refsName) }, []),
|
|
223
|
+
tool("edit_text", "Hash-verified edit", { ...path, ...lang, ...gitScopeSchema, ...apply, edits: { type: "array", minItems: 1, items: editItemSchema, description: PARAM_DESCRIPTIONS.edits }, postEditVerify: { type: "boolean", description: PARAM_DESCRIPTIONS.postEditVerify } }, ["path", "edits"]),
|
|
224
|
+
tool("rename_symbol", "Rename symbol", { ...path, ...at, ...lang, ...gitScopeSchema, ...apply, to: string(PARAM_DESCRIPTIONS.to), workspace: { type: "boolean", description: PARAM_DESCRIPTIONS.workspace } }, ["path", "at", "to"]),
|
|
225
|
+
tool("write_file", "Write file", { ...path, content: string(PARAM_DESCRIPTIONS.content) }, ["path", "content"])
|
|
387
226
|
];
|
|
227
|
+
function getToolContract(name) {
|
|
228
|
+
const contract = TOOL_CONTRACTS.find((entry) => entry.name === name);
|
|
229
|
+
if (!contract)
|
|
230
|
+
throw new Error(`missing tool contract: ${name}`);
|
|
231
|
+
return contract;
|
|
232
|
+
}
|
|
388
233
|
// ../readseek-api/src/policy.ts
|
|
389
234
|
var REPLACEABLE_TOOLS = [
|
|
390
235
|
{
|
|
391
|
-
tool: "
|
|
236
|
+
tool: "show_content",
|
|
392
237
|
builtIn: "read",
|
|
393
238
|
benefit: "it returns LINE:HASH anchors for safe edits."
|
|
394
239
|
},
|
|
395
240
|
{
|
|
396
|
-
tool: "
|
|
241
|
+
tool: "edit_text",
|
|
397
242
|
builtIn: "edit",
|
|
398
243
|
benefit: "it verifies fresh LINE:HASH anchors."
|
|
399
244
|
},
|
|
400
245
|
{
|
|
401
|
-
tool: "
|
|
246
|
+
tool: "find_text",
|
|
402
247
|
builtIn: "grep",
|
|
403
248
|
benefit: "it returns LINE:HASH anchors."
|
|
404
249
|
},
|
|
405
250
|
{
|
|
406
|
-
tool: "
|
|
251
|
+
tool: "write_file",
|
|
407
252
|
builtIn: "write",
|
|
408
253
|
benefit: "it returns LINE:HASH anchors."
|
|
409
254
|
}
|
|
410
255
|
];
|
|
411
256
|
var TOOL_COMPACT_GUIDELINES = {
|
|
412
|
-
|
|
413
|
-
"Use `
|
|
257
|
+
show_content: [
|
|
258
|
+
"Use `show_structure` for shallow overviews and `check_syntax` for diagnostics; use `find_definitions`, `find_references`, or `find_nodes` for targeted symbol questions."
|
|
414
259
|
],
|
|
415
|
-
|
|
260
|
+
edit_text: [
|
|
416
261
|
"Prefer set_line, replace_lines, and insert_after; use replace only when anchors are impractical."
|
|
417
262
|
],
|
|
418
|
-
|
|
419
|
-
"Use `
|
|
263
|
+
find_text: [
|
|
264
|
+
"Use `find_text` with summary first for broad searches, then narrow by path, glob, or pattern."
|
|
420
265
|
],
|
|
421
|
-
|
|
422
|
-
"Use anchored edits rather than `
|
|
266
|
+
write_file: [
|
|
267
|
+
"Use anchored edits rather than `write_file` for small changes or appends."
|
|
423
268
|
],
|
|
424
|
-
|
|
425
|
-
"Use `
|
|
269
|
+
find_nodes: [
|
|
270
|
+
"Use `find_nodes` for AST patterns; use `find_text` for plain text."
|
|
426
271
|
],
|
|
427
|
-
|
|
428
|
-
"Use `
|
|
272
|
+
find_references: [
|
|
273
|
+
"Use `find_references` before changing a symbol; use at with line:N:C to follow one binding."
|
|
429
274
|
]
|
|
430
275
|
};
|
|
431
276
|
function resolveToolName(name, aliases = {}) {
|
|
@@ -439,20 +284,20 @@ function renderCompactGuidelines(name, aliases = {}) {
|
|
|
439
284
|
}
|
|
440
285
|
function renderToolRoutingPolicy(options = {}) {
|
|
441
286
|
const aliases = options.aliases ?? {};
|
|
442
|
-
const
|
|
443
|
-
const
|
|
444
|
-
const
|
|
445
|
-
const
|
|
446
|
-
const
|
|
447
|
-
const
|
|
448
|
-
const
|
|
449
|
-
const
|
|
450
|
-
const
|
|
287
|
+
const show_content = resolveToolName("show_content", aliases);
|
|
288
|
+
const edit_text = resolveToolName("edit_text", aliases);
|
|
289
|
+
const write_file = resolveToolName("write_file", aliases);
|
|
290
|
+
const find_text = resolveToolName("find_text", aliases);
|
|
291
|
+
const find_nodes = resolveToolName("find_nodes", aliases);
|
|
292
|
+
const find_definitions = resolveToolName("find_definitions", aliases);
|
|
293
|
+
const find_references = resolveToolName("find_references", aliases);
|
|
294
|
+
const rename_symbol = resolveToolName("rename_symbol", aliases);
|
|
295
|
+
const show_assets = resolveToolName("show_assets", aliases);
|
|
451
296
|
if (options.style === "server") {
|
|
452
297
|
return [
|
|
453
298
|
"Structural code navigation, document inspection, and hash-verified edits with readseek.",
|
|
454
|
-
"For structural questions, prefer these tools to text Grep/Bash: targeted definitions, references, and AST
|
|
455
|
-
`Use ${
|
|
299
|
+
"For structural questions, prefer these tools to text Grep/Bash: targeted definitions, references, and AST patterns; shallow show_structure views; check_syntax diagnostics and show_content cursor context; and document inspection.",
|
|
300
|
+
`Use ${edit_text} for LINE:HASH-anchored mutations (preview with apply=false; apply defaults to true and re-checks plan_hash).`,
|
|
456
301
|
"Paths resolve against CLAUDE_PROJECT_DIR. Native Read/Grep/Edit hooks provide passive context;",
|
|
457
302
|
"call MCP tools for active navigation, document questions, or anchored edits."
|
|
458
303
|
].join(" ");
|
|
@@ -462,7 +307,7 @@ function renderToolRoutingPolicy(options = {}) {
|
|
|
462
307
|
if (options.preferOverBuiltIns) {
|
|
463
308
|
bullets.push("- Prefer ReadSeek tools over built-ins when they can do the job.");
|
|
464
309
|
}
|
|
465
|
-
bullets.push(`- Read with ${
|
|
310
|
+
bullets.push(`- Read with ${show_content} first; ${edit_text} needs fresh LINE:HASH anchors.`, `- Use ${find_text} for text/regex, ${find_nodes} for AST patterns, ${find_definitions}/${find_references} for targeted symbols, and shallow ${resolveToolName("show_structure", aliases)} structures only for file overviews.`, `- Use ${edit_text} for existing files, ${write_file} for whole-file creation or replacement, and ${rename_symbol} for symbol renames.`, `- Use ${resolveToolName("show_structure", aliases)} for document structure; run ${resolveToolName("check_syntax", aliases)} after source edits for a quick syntax check.`, `- Use ${show_assets} to materialize selected document assets and read their returned paths.`);
|
|
466
311
|
if (options.demoteBuiltIns && options.demoteBuiltIns.length > 0) {
|
|
467
312
|
bullets.push(`- Do not use built-in ${options.demoteBuiltIns.join(", ")} when a ReadSeek tool can do the job.`);
|
|
468
313
|
}
|
|
@@ -489,25 +334,9 @@ function tryParseLineAnchor(anchor) {
|
|
|
489
334
|
}
|
|
490
335
|
|
|
491
336
|
// ../readseek-api/src/validation.ts
|
|
492
|
-
function
|
|
493
|
-
if (input.
|
|
494
|
-
|
|
495
|
-
return { ok: false, error: "scope requires line" };
|
|
496
|
-
}
|
|
497
|
-
return { ok: true };
|
|
498
|
-
}
|
|
499
|
-
if (input.line !== undefined || input.column !== undefined) {
|
|
500
|
-
return { ok: false, error: "line/column require scope=true" };
|
|
501
|
-
}
|
|
502
|
-
if (typeof input.name !== "string" || input.name.length === 0) {
|
|
503
|
-
return { ok: false, error: "name is required when scope is not set" };
|
|
504
|
-
}
|
|
505
|
-
return { ok: true };
|
|
506
|
-
}
|
|
507
|
-
function validateVisionLevelVsMode(input) {
|
|
508
|
-
if (input.visionLevel !== undefined && !["all", "ocr", "caption", "objects"].includes(input.visionMode ?? "")) {
|
|
509
|
-
return { ok: false, error: "visionLevel requires an analysis visionMode" };
|
|
510
|
-
}
|
|
337
|
+
function validateReferencesSelection(input) {
|
|
338
|
+
if (Boolean(input.name) === Boolean(input.at))
|
|
339
|
+
return { ok: false, error: "exactly one of name or at is required" };
|
|
511
340
|
return { ok: true };
|
|
512
341
|
}
|
|
513
342
|
var VARIANT_FIELDS = {
|
|
@@ -577,51 +406,8 @@ function validateExactlyOneEditVariant(edits) {
|
|
|
577
406
|
}
|
|
578
407
|
var MIN_SAFE_INTEGER = BigInt(Number.MIN_SAFE_INTEGER);
|
|
579
408
|
var MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
|
|
580
|
-
// ../readseek-api/src/edit-plan.ts
|
|
581
|
-
import { Document, Node, format } from "@bgotink/kdl";
|
|
582
|
-
function node(name, properties, children = []) {
|
|
583
|
-
const result = Node.create(name);
|
|
584
|
-
for (const [key, value] of Object.entries(properties))
|
|
585
|
-
result.setProperty(key, value);
|
|
586
|
-
if (children.length > 0)
|
|
587
|
-
result.children = new Document(children);
|
|
588
|
-
return result;
|
|
589
|
-
}
|
|
590
|
-
function editNode(edit) {
|
|
591
|
-
if ("set_line" in edit) {
|
|
592
|
-
const value = edit.set_line;
|
|
593
|
-
return node("set-line", { anchor: value.anchor, text: value.new_text });
|
|
594
|
-
}
|
|
595
|
-
if ("replace_lines" in edit) {
|
|
596
|
-
const value = edit.replace_lines;
|
|
597
|
-
return node("replace-lines", { start: value.start_anchor, end: value.end_anchor, text: value.new_text });
|
|
598
|
-
}
|
|
599
|
-
if ("insert_after" in edit) {
|
|
600
|
-
const value = edit.insert_after;
|
|
601
|
-
return node("insert-after", { anchor: value.anchor, text: value.new_text });
|
|
602
|
-
}
|
|
603
|
-
if ("replace_symbol" in edit) {
|
|
604
|
-
const value = edit.replace_symbol;
|
|
605
|
-
return node("replace-symbol", { symbol: value.symbol, body: value.new_body });
|
|
606
|
-
}
|
|
607
|
-
const value = edit.replace;
|
|
608
|
-
return node("replace", {
|
|
609
|
-
old: value.old_text,
|
|
610
|
-
new: value.new_text,
|
|
611
|
-
...value.all === undefined ? {} : { all: value.all }
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
|
-
function serializeEditPlan(edits) {
|
|
615
|
-
const validation = validateExactlyOneEditVariant(edits);
|
|
616
|
-
if (!validation.ok)
|
|
617
|
-
throw new Error(validation.error);
|
|
618
|
-
return format(new Document([node("plan", {}, validation.edits.map(editNode))]));
|
|
619
|
-
}
|
|
620
409
|
// ../readseek-api/src/argv.ts
|
|
621
|
-
var
|
|
622
|
-
function buildLineLocation(line, column) {
|
|
623
|
-
return column === undefined ? `line:${line}` : `line:${line}:${column}`;
|
|
624
|
-
}
|
|
410
|
+
var DEFAULT_STRUCTURE_DEPTH = 1;
|
|
625
411
|
function appendGitScopeArgs(args, input) {
|
|
626
412
|
if (input.gitScope !== undefined)
|
|
627
413
|
args.push("--git-scope", input.gitScope);
|
|
@@ -648,30 +434,6 @@ function appendApplyAndPlanHash(args, input) {
|
|
|
648
434
|
pushOptionalString(args, "--plan-hash", input.planHash);
|
|
649
435
|
return args;
|
|
650
436
|
}
|
|
651
|
-
function selectArg(select) {
|
|
652
|
-
if (select === undefined)
|
|
653
|
-
return;
|
|
654
|
-
return Array.isArray(select) ? select.join(",") : select;
|
|
655
|
-
}
|
|
656
|
-
function selectedInspectFacets(select) {
|
|
657
|
-
const facets = (selectArg(select) ?? "content").split(",").map((facet) => facet.trim());
|
|
658
|
-
for (const facet of facets) {
|
|
659
|
-
if (!INSPECT_FACETS.includes(facet)) {
|
|
660
|
-
throw new Error(`unknown inspect facet: ${facet}`);
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
return facets;
|
|
664
|
-
}
|
|
665
|
-
function hasInspectFacet(facets, facet) {
|
|
666
|
-
return facets.includes(facet);
|
|
667
|
-
}
|
|
668
|
-
function validateTarget(command, target, stdinName) {
|
|
669
|
-
if (target.length === 0)
|
|
670
|
-
throw new Error(`${command} requires a target file path or '-'`);
|
|
671
|
-
if (stdinName !== undefined && stdinName.length > 0 && target !== "-") {
|
|
672
|
-
throw new Error("stdinName requires '-' as the target");
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
437
|
function validatePositiveInteger(value, name) {
|
|
676
438
|
if (!Number.isSafeInteger(value) || value < 1) {
|
|
677
439
|
throw new Error(`${name} must be a positive integer`);
|
|
@@ -717,1226 +479,1300 @@ function parseSelector(text) {
|
|
|
717
479
|
}
|
|
718
480
|
return { kind, value };
|
|
719
481
|
}
|
|
720
|
-
function
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
482
|
+
function start(verb, object, input) {
|
|
483
|
+
if (!input.path)
|
|
484
|
+
throw new Error(`${verb} ${object} requires a path`);
|
|
485
|
+
if (input.stdinName !== undefined && input.path !== "-")
|
|
486
|
+
throw new Error("stdinName requires '-' as the target");
|
|
487
|
+
const args = [];
|
|
488
|
+
pushOptionalString(args, "--readseek-dir", input.readseekDir);
|
|
489
|
+
args.push(verb, object, input.path);
|
|
490
|
+
pushOptionalString(args, "--stdin-name", input.stdinName);
|
|
491
|
+
return args;
|
|
492
|
+
}
|
|
493
|
+
function at2(args, value) {
|
|
494
|
+
if (value !== undefined) {
|
|
495
|
+
parseSelector(value);
|
|
496
|
+
args.push("--at", value);
|
|
724
497
|
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
498
|
+
}
|
|
499
|
+
function finish(args) {
|
|
500
|
+
args.push("--kdl");
|
|
501
|
+
return args;
|
|
502
|
+
}
|
|
503
|
+
function language(args, input) {
|
|
504
|
+
pushOptionalString(args, "--language", input.language);
|
|
505
|
+
}
|
|
506
|
+
function limit2(args, value) {
|
|
507
|
+
if (value !== undefined)
|
|
508
|
+
validatePositiveInteger(value, "limit");
|
|
509
|
+
pushOptionalNumber(args, "--limit", value);
|
|
510
|
+
}
|
|
511
|
+
function anchors(args, input) {
|
|
512
|
+
if (input.noAnchors)
|
|
513
|
+
args.push("--no-anchors");
|
|
514
|
+
}
|
|
515
|
+
function buildShowContentArgs(input) {
|
|
736
516
|
if (input.end !== undefined)
|
|
737
517
|
validatePositiveInteger(input.end, "end");
|
|
738
|
-
if (input.limit !== undefined)
|
|
739
|
-
validatePositiveInteger(input.limit, "limit");
|
|
740
|
-
if (input.end !== undefined && input.limit !== undefined) {
|
|
518
|
+
if (input.end !== undefined && input.limit !== undefined)
|
|
741
519
|
throw new Error("cannot combine end with limit");
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
if (!Number.isSafeInteger(input.depth) || input.depth < 0) {
|
|
745
|
-
throw new Error("depth must be a non-negative integer");
|
|
746
|
-
}
|
|
747
|
-
if (!hasMap)
|
|
748
|
-
throw new Error("depth requires the map facet");
|
|
749
|
-
}
|
|
750
|
-
if (input.selector !== undefined && input.query !== undefined) {
|
|
751
|
-
throw new Error("cannot combine selector with query");
|
|
752
|
-
}
|
|
753
|
-
if (!hasContent && (input.end !== undefined || input.limit !== undefined || input.query !== undefined)) {
|
|
754
|
-
throw new Error("ranges and queries require the content facet");
|
|
755
|
-
}
|
|
756
|
-
if (hasIdentity && input.selector === undefined) {
|
|
757
|
-
throw new Error("the identity facet requires a selector");
|
|
758
|
-
}
|
|
759
|
-
if (input.selector !== undefined && !hasContent && !hasIdentity) {
|
|
760
|
-
throw new Error("selectors require the content or identity facet");
|
|
761
|
-
}
|
|
762
|
-
if (input.selector !== undefined) {
|
|
763
|
-
const selector = parseSelector(input.selector);
|
|
764
|
-
if (selector.kind === "symbol" && hasIdentity) {
|
|
765
|
-
throw new Error("the identity facet does not accept symbol selectors");
|
|
766
|
-
}
|
|
767
|
-
if (selector.column !== undefined && !hasIdentity) {
|
|
768
|
-
throw new Error("selector columns require the identity facet");
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
const hasVision = input.visionMode !== undefined || input.visionLevel !== undefined;
|
|
772
|
-
if (hasVision && !hasContent) {
|
|
773
|
-
throw new Error("vision options require the content facet");
|
|
774
|
-
}
|
|
775
|
-
if (hasVision && hasSourceFacet) {
|
|
776
|
-
throw new Error("vision options cannot be combined with source facets");
|
|
777
|
-
}
|
|
778
|
-
const args = [];
|
|
779
|
-
if (input.readseekDir !== undefined)
|
|
780
|
-
args.push("--readseek-dir", input.readseekDir);
|
|
781
|
-
args.push("inspect", input.path);
|
|
782
|
-
if (input.selector !== undefined)
|
|
783
|
-
args.push(input.selector);
|
|
784
|
-
const select = selectArg(input.select);
|
|
785
|
-
if (select !== undefined)
|
|
786
|
-
args.push("--select", select);
|
|
787
|
-
pushOptionalString(args, "--query", input.query);
|
|
520
|
+
const args = start("show", "content", input);
|
|
521
|
+
at2(args, input.at);
|
|
788
522
|
pushOptionalNumber(args, "--end", input.end);
|
|
789
|
-
|
|
523
|
+
limit2(args, input.limit);
|
|
524
|
+
language(args, input);
|
|
525
|
+
anchors(args, input);
|
|
526
|
+
return finish(args);
|
|
527
|
+
}
|
|
528
|
+
function buildShowStructureArgs(input) {
|
|
529
|
+
if (input.depth !== undefined && (!Number.isSafeInteger(input.depth) || input.depth < 0))
|
|
530
|
+
throw new Error("depth must be a non-negative integer");
|
|
531
|
+
const args = start("show", "structure", input);
|
|
532
|
+
at2(args, input.at);
|
|
790
533
|
pushOptionalNumber(args, "--depth", input.depth);
|
|
791
|
-
pushOptionalString(args, "--
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
args
|
|
534
|
+
pushOptionalString(args, "--kind", input.kind);
|
|
535
|
+
language(args, input);
|
|
536
|
+
if (input.outline)
|
|
537
|
+
args.push("--outline");
|
|
538
|
+
return finish(args);
|
|
539
|
+
}
|
|
540
|
+
function buildShowMetadataArgs(input) {
|
|
541
|
+
const args = start("show", "metadata", input);
|
|
542
|
+
language(args, input);
|
|
543
|
+
return finish(args);
|
|
544
|
+
}
|
|
545
|
+
function buildShowAssetsArgs(input) {
|
|
546
|
+
if (input.at !== undefined && !["page", "node", "asset"].includes(parseSelector(input.at).kind))
|
|
547
|
+
throw new Error("assets requires a page, node, or asset selector");
|
|
548
|
+
const args = start("show", "assets", input);
|
|
549
|
+
at2(args, input.at);
|
|
550
|
+
return finish(args);
|
|
551
|
+
}
|
|
552
|
+
function buildCheckSyntaxArgs(input) {
|
|
553
|
+
const args = start("check", "syntax", input);
|
|
554
|
+
language(args, input);
|
|
555
|
+
return finish(args);
|
|
556
|
+
}
|
|
557
|
+
function visionArgs(verb, object, input) {
|
|
558
|
+
if (input.level !== undefined && !VISION_LEVELS.includes(input.level))
|
|
559
|
+
throw new Error("invalid vision level");
|
|
560
|
+
if (input.at !== undefined && !["page", "node", "asset"].includes(parseSelector(input.at).kind))
|
|
561
|
+
throw new Error("vision requires a document selector");
|
|
562
|
+
const args = start(verb, object, input);
|
|
563
|
+
at2(args, input.at);
|
|
564
|
+
pushOptionalString(args, "--level", input.level);
|
|
796
565
|
return args;
|
|
797
566
|
}
|
|
798
|
-
function
|
|
799
|
-
|
|
800
|
-
if (input.
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
567
|
+
function buildGenerateCaptionArgs(input) {
|
|
568
|
+
const args = visionArgs("generate", "caption", input);
|
|
569
|
+
if (input.include !== undefined) {
|
|
570
|
+
if (input.include.length === 0 || input.include.some((task) => task !== "text" && task !== "objects"))
|
|
571
|
+
throw new Error("include requires text or objects");
|
|
572
|
+
args.push("--include", input.include.join(","));
|
|
573
|
+
}
|
|
574
|
+
return finish(args);
|
|
575
|
+
}
|
|
576
|
+
function buildDetectObjectsArgs(input) {
|
|
577
|
+
return finish(visionArgs("detect", "objects", input));
|
|
578
|
+
}
|
|
579
|
+
function buildRecognizeTextArgs(input) {
|
|
580
|
+
return finish(visionArgs("recognize", "text", input));
|
|
581
|
+
}
|
|
582
|
+
function buildFindNodesArgs(input) {
|
|
583
|
+
const hasPattern = Boolean(input.pattern);
|
|
584
|
+
const hasRule = Boolean(input.rule);
|
|
585
|
+
const hasContext = Boolean(input.context);
|
|
586
|
+
if (hasRule) {
|
|
587
|
+
if (hasPattern || hasContext || input.selector)
|
|
588
|
+
throw new Error("rule cannot be combined with pattern, context, or selector");
|
|
589
|
+
} else if (!hasPattern && !hasContext) {
|
|
590
|
+
throw new Error("find nodes requires pattern, context, or rule");
|
|
591
|
+
}
|
|
592
|
+
if (hasContext && !input.selector) {
|
|
593
|
+
throw new Error("context requires selector");
|
|
594
|
+
}
|
|
595
|
+
if (hasPattern && hasContext) {
|
|
596
|
+
throw new Error("pattern and context cannot be combined");
|
|
597
|
+
}
|
|
598
|
+
const args = start("find", "nodes", input);
|
|
599
|
+
pushOptionalString(args, "--pattern", input.pattern);
|
|
600
|
+
pushOptionalString(args, "--context", input.context);
|
|
601
|
+
pushOptionalString(args, "--selector", input.selector);
|
|
602
|
+
pushOptionalString(args, "--rule", input.rule);
|
|
603
|
+
language(args, input);
|
|
604
|
+
limit2(args, input.limit);
|
|
605
|
+
appendGitScopeArgs(args, input);
|
|
606
|
+
anchors(args, input);
|
|
607
|
+
return finish(args);
|
|
814
608
|
}
|
|
815
|
-
function
|
|
816
|
-
const args =
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
pushOptionalNumber(args, "--limit", input.limit);
|
|
609
|
+
function buildFindTextArgs(input) {
|
|
610
|
+
const args = start("find", "text", input);
|
|
611
|
+
args.push("--text", input.text);
|
|
612
|
+
limit2(args, input.limit);
|
|
820
613
|
appendGitScopeArgs(args, input);
|
|
821
|
-
args
|
|
822
|
-
return args;
|
|
614
|
+
return finish(args);
|
|
823
615
|
}
|
|
824
|
-
function
|
|
825
|
-
const args =
|
|
826
|
-
|
|
827
|
-
|
|
616
|
+
function buildFindDefinitionsArgs(input) {
|
|
617
|
+
const args = start("find", "definitions", input);
|
|
618
|
+
args.push("--name", input.name);
|
|
619
|
+
language(args, input);
|
|
828
620
|
appendGitScopeArgs(args, input);
|
|
829
|
-
args
|
|
830
|
-
return args;
|
|
621
|
+
anchors(args, input);
|
|
622
|
+
return finish(args);
|
|
831
623
|
}
|
|
832
|
-
function
|
|
833
|
-
const validated =
|
|
624
|
+
function buildFindReferencesArgs(input) {
|
|
625
|
+
const validated = validateReferencesSelection(input);
|
|
834
626
|
if (!validated.ok)
|
|
835
627
|
throw new Error(validated.error);
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
pushOptionalString(args, "--
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
pushOptionalNumber(args, "--line", input.line);
|
|
843
|
-
pushOptionalNumber(args, "--column", input.column);
|
|
844
|
-
}
|
|
845
|
-
pushOptionalString(args, "--language", input.language);
|
|
628
|
+
if (input.at !== undefined && !["line", "hash"].includes(parseSelector(input.at).kind))
|
|
629
|
+
throw new Error("references requires a line or hash selector");
|
|
630
|
+
const args = start("find", "references", input);
|
|
631
|
+
pushOptionalString(args, "--name", input.name);
|
|
632
|
+
at2(args, input.at);
|
|
633
|
+
language(args, input);
|
|
846
634
|
appendGitScopeArgs(args, input);
|
|
847
|
-
args
|
|
848
|
-
return args;
|
|
635
|
+
anchors(args, input);
|
|
636
|
+
return finish(args);
|
|
849
637
|
}
|
|
850
|
-
function
|
|
851
|
-
const args =
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
638
|
+
function buildCheckRulesArgs(input) {
|
|
639
|
+
const args = start("check", "rules", input);
|
|
640
|
+
args.push("--rules", input.rules);
|
|
641
|
+
appendGitScopeArgs(args, input);
|
|
642
|
+
return finish(args);
|
|
643
|
+
}
|
|
644
|
+
function buildEditTextArgs(input) {
|
|
645
|
+
const args = start("edit", "text", input);
|
|
646
|
+
appendApplyAndPlanHash(args, input);
|
|
647
|
+
language(args, input);
|
|
648
|
+
appendGitScopeArgs(args, input);
|
|
858
649
|
if (input.requestFromStdin)
|
|
859
650
|
args.push("--edits", "-");
|
|
860
|
-
args
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
651
|
+
return finish(args);
|
|
652
|
+
}
|
|
653
|
+
function buildRenameSymbolArgs(input) {
|
|
654
|
+
if (!["line", "hash"].includes(parseSelector(input.at).kind))
|
|
655
|
+
throw new Error("rename requires a line or hash selector");
|
|
656
|
+
const args = start("rename", "symbol", input);
|
|
657
|
+
at2(args, input.at);
|
|
658
|
+
args.push("--to", input.to);
|
|
865
659
|
if (input.workspace !== undefined)
|
|
866
660
|
args.push(`--workspace=${input.workspace}`);
|
|
867
|
-
appendApplyAndPlanHash(args, {
|
|
868
|
-
|
|
869
|
-
planHash: input.planHash,
|
|
870
|
-
flagOrder: input.flagOrder ?? "plan-hash-first"
|
|
871
|
-
});
|
|
872
|
-
pushOptionalString(args, "--language", input.language);
|
|
661
|
+
appendApplyAndPlanHash(args, { ...input, flagOrder: input.flagOrder ?? "plan-hash-first" });
|
|
662
|
+
language(args, input);
|
|
873
663
|
appendGitScopeArgs(args, input);
|
|
874
|
-
args
|
|
875
|
-
return args;
|
|
876
|
-
}
|
|
877
|
-
// ../readseek-api/src/platform.ts
|
|
878
|
-
import { accessSync, constants as fsConstants, existsSync, statSync } from "node:fs";
|
|
879
|
-
import { createRequire } from "node:module";
|
|
880
|
-
import path from "node:path";
|
|
881
|
-
var READSEEK_BINARY_ENV = "READSEEK_BINARY";
|
|
882
|
-
var READSEEK_PLATFORM_PACKAGES = {
|
|
883
|
-
"darwin-arm64": "@jarkkojs/readseek-darwin-arm64",
|
|
884
|
-
"linux-arm64": "@jarkkojs/readseek-linux-arm64",
|
|
885
|
-
"linux-x64": "@jarkkojs/readseek-linux-x64",
|
|
886
|
-
"win32-x64": "@jarkkojs/readseek-win32-x64"
|
|
887
|
-
};
|
|
888
|
-
var resolveFromPackage = createRequire(import.meta.url).resolve;
|
|
889
|
-
function readSeekBinaryName(platform = process.platform) {
|
|
890
|
-
if (platform === "linux")
|
|
891
|
-
return "readseek.AppImage";
|
|
892
|
-
return platform === "win32" ? "readseek.exe" : "readseek";
|
|
664
|
+
return finish(args);
|
|
893
665
|
}
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
if (binaryPath === undefined)
|
|
900
|
-
return null;
|
|
901
|
-
if (!path.isAbsolute(binaryPath)) {
|
|
902
|
-
throw new Error(`${READSEEK_BINARY_ENV} must be an absolute path to the readseek executable`);
|
|
903
|
-
}
|
|
666
|
+
// ../readseek-api/src/client-output.ts
|
|
667
|
+
import { Type } from "@sinclair/typebox";
|
|
668
|
+
import { AssertError, Value } from "@sinclair/typebox/value";
|
|
669
|
+
var OPERATIONS = ["Clone", "Clean", "Default", "Assert"];
|
|
670
|
+
function parse(schema, value, what) {
|
|
904
671
|
try {
|
|
905
|
-
|
|
906
|
-
throw new Error("not a regular file");
|
|
907
|
-
accessSync(binaryPath, fsConstants.X_OK);
|
|
672
|
+
return Value.Parse(OPERATIONS, schema, value);
|
|
908
673
|
} catch (error) {
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
return binaryPath;
|
|
914
|
-
}
|
|
915
|
-
function resolveReadSeekBinaryFromPackages(resolver = resolveFromPackage, options = {}) {
|
|
916
|
-
const resolve = typeof resolver === "function" ? resolver : resolver.resolve.bind(resolver);
|
|
917
|
-
const platform = options.platform ?? process.platform;
|
|
918
|
-
const arch = options.arch ?? process.arch;
|
|
919
|
-
const key = readSeekPlatformKey(platform, arch);
|
|
920
|
-
const platformPackage = READSEEK_PLATFORM_PACKAGES[key];
|
|
921
|
-
if (!platformPackage) {
|
|
922
|
-
const supported = Object.keys(READSEEK_PLATFORM_PACKAGES).join(", ");
|
|
923
|
-
throw new Error(`@jarkkojs/readseek ships no binary for ${key}; it supports ${supported}`);
|
|
924
|
-
}
|
|
925
|
-
const metaPackage = options.metaPackage ?? "@jarkkojs/readseek";
|
|
926
|
-
let packageJsonPath;
|
|
927
|
-
try {
|
|
928
|
-
const metaPackageJson = resolve(`${metaPackage}/package.json`);
|
|
929
|
-
const metaPackageDir = path.dirname(metaPackageJson);
|
|
930
|
-
packageJsonPath = resolve(`${platformPackage}/package.json`, {
|
|
931
|
-
paths: [metaPackageDir]
|
|
932
|
-
});
|
|
933
|
-
} catch {
|
|
934
|
-
packageJsonPath = resolve(`${platformPackage}/package.json`);
|
|
674
|
+
if (!(error instanceof AssertError))
|
|
675
|
+
throw error;
|
|
676
|
+
const detail = error.error;
|
|
677
|
+
throw new Error(`invalid readseek ${what}${detail?.path ?? ""}: ${detail?.message ?? "invalid value"}`);
|
|
935
678
|
}
|
|
936
|
-
const binaryPath = path.join(path.dirname(packageJsonPath), "bin", readSeekBinaryName(platform));
|
|
937
|
-
accessSync(binaryPath, fsConstants.X_OK);
|
|
938
|
-
return binaryPath;
|
|
939
679
|
}
|
|
940
|
-
|
|
941
|
-
var
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
680
|
+
var Int = Type.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: Number.MAX_SAFE_INTEGER });
|
|
681
|
+
var Str = Type.String();
|
|
682
|
+
var Bool = Type.Boolean();
|
|
683
|
+
var OptStr = Type.Optional(Str);
|
|
684
|
+
var OptInt = Type.Optional(Int);
|
|
685
|
+
var Hashline = Type.Object({ line: Int, hash: Str, text: Str });
|
|
686
|
+
var Hashlines = Type.Array(Hashline);
|
|
687
|
+
var ReadOutput = Type.Object({
|
|
688
|
+
file: Str,
|
|
689
|
+
language: Str,
|
|
690
|
+
line_count: Int,
|
|
691
|
+
file_hash: Str,
|
|
692
|
+
start_line: Int,
|
|
693
|
+
end_line: Int,
|
|
694
|
+
hashlines: Hashlines,
|
|
695
|
+
truncated: Type.Optional(Bool)
|
|
696
|
+
});
|
|
697
|
+
var SymbolOutput = Type.Object({
|
|
698
|
+
kind: Str,
|
|
699
|
+
name: Str,
|
|
700
|
+
qualified_name: OptStr,
|
|
701
|
+
start_line: Int,
|
|
702
|
+
end_line: Int,
|
|
703
|
+
start_hash: OptStr,
|
|
704
|
+
end_hash: OptStr,
|
|
705
|
+
start_anchor: OptStr,
|
|
706
|
+
end_anchor: OptStr
|
|
707
|
+
});
|
|
708
|
+
function mapNodeShape(child) {
|
|
709
|
+
return Type.Object({
|
|
710
|
+
kind: Str,
|
|
711
|
+
name: Str,
|
|
712
|
+
start_line: Int,
|
|
713
|
+
end_line: Int,
|
|
714
|
+
start_anchor: Str,
|
|
715
|
+
end_anchor: Str,
|
|
716
|
+
children: Type.Array(child)
|
|
717
|
+
});
|
|
978
718
|
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
function properties(node) {
|
|
982
|
-
return Object.fromEntries(node.properties);
|
|
719
|
+
function recursiveStructureNode() {
|
|
720
|
+
return Type.Recursive((self) => mapNodeShape(self));
|
|
983
721
|
}
|
|
984
|
-
function
|
|
985
|
-
|
|
722
|
+
var StructureNode = typeof Type.Recursive === "function" ? recursiveStructureNode() : Type.Cyclic({ StructureNode: mapNodeShape(Type.Ref("StructureNode")) }, "StructureNode");
|
|
723
|
+
var StructureOutput = Type.Object({
|
|
724
|
+
file: Str,
|
|
725
|
+
language: Str,
|
|
726
|
+
line_count: Int,
|
|
727
|
+
file_hash: Str,
|
|
728
|
+
root: Type.Optional(StructureNode),
|
|
729
|
+
symbols: Type.Array(SymbolOutput)
|
|
730
|
+
});
|
|
731
|
+
var SearchSpan = {
|
|
732
|
+
start_byte: OptInt,
|
|
733
|
+
end_byte: OptInt,
|
|
734
|
+
text: OptStr,
|
|
735
|
+
start_line: Int,
|
|
736
|
+
end_line: Int,
|
|
737
|
+
start_hash: Str,
|
|
738
|
+
end_hash: Str,
|
|
739
|
+
hashlines: Hashlines
|
|
740
|
+
};
|
|
741
|
+
var SearchCapture = Type.Object({ name: Str, ...SearchSpan });
|
|
742
|
+
var SearchMatch = Type.Object({
|
|
743
|
+
pattern_index: Type.Integer({ default: 0 }),
|
|
744
|
+
...SearchSpan,
|
|
745
|
+
captures: Type.Array(SearchCapture)
|
|
746
|
+
});
|
|
747
|
+
var SearchFileOutput = Type.Object({
|
|
748
|
+
file: Str,
|
|
749
|
+
language: Str,
|
|
750
|
+
file_hash: Str,
|
|
751
|
+
matches: Type.Array(SearchMatch)
|
|
752
|
+
});
|
|
753
|
+
var SearchEnvelope = Type.Object({
|
|
754
|
+
results: Type.Array(SearchFileOutput),
|
|
755
|
+
returned_matches: OptInt,
|
|
756
|
+
truncated: Type.Optional(Bool),
|
|
757
|
+
byte_basis: OptStr
|
|
758
|
+
});
|
|
759
|
+
var RefsEnvelope = Type.Object({
|
|
760
|
+
references: Type.Array(Type.Object({
|
|
761
|
+
file: Str,
|
|
762
|
+
line: Int,
|
|
763
|
+
column: Int,
|
|
764
|
+
line_hash: Str,
|
|
765
|
+
text: Str,
|
|
766
|
+
symbol: Type.Optional(Type.Object({ qualified_name: OptStr }))
|
|
767
|
+
}))
|
|
768
|
+
});
|
|
769
|
+
var Diagnostic = Type.Object({
|
|
770
|
+
kind: Type.Union([Type.Literal("error"), Type.Literal("missing")]),
|
|
771
|
+
start_line: Int,
|
|
772
|
+
end_line: Int
|
|
773
|
+
});
|
|
774
|
+
var CheckEnvelope = Type.Object({
|
|
775
|
+
file_hash: OptStr,
|
|
776
|
+
error_count: Int,
|
|
777
|
+
missing_count: Int,
|
|
778
|
+
diagnostics: Type.Array(Diagnostic)
|
|
779
|
+
});
|
|
780
|
+
var DetectedObject = Type.Object({
|
|
781
|
+
label: Str,
|
|
782
|
+
bbox: Type.Tuple([Int, Int, Int, Int])
|
|
783
|
+
});
|
|
784
|
+
var SourceDetection = Type.Object({
|
|
785
|
+
kind: Type.Literal("source"),
|
|
786
|
+
type: Str,
|
|
787
|
+
file: Str,
|
|
788
|
+
language: Str,
|
|
789
|
+
engine: OptStr,
|
|
790
|
+
supported: Bool,
|
|
791
|
+
mime: OptStr,
|
|
792
|
+
syntax: OptStr
|
|
793
|
+
});
|
|
794
|
+
var ImageDetection = Type.Object({
|
|
795
|
+
kind: Type.Literal("image"),
|
|
796
|
+
type: Str,
|
|
797
|
+
file: Str,
|
|
798
|
+
mime: OptStr,
|
|
799
|
+
format: Str,
|
|
800
|
+
width: Int,
|
|
801
|
+
height: Int,
|
|
802
|
+
animated: Bool,
|
|
803
|
+
ocr: OptStr,
|
|
804
|
+
caption: OptStr,
|
|
805
|
+
objects: Type.Optional(Type.Array(DetectedObject))
|
|
806
|
+
});
|
|
807
|
+
var TextDetection = Type.Object({
|
|
808
|
+
kind: Type.Literal("text"),
|
|
809
|
+
type: Str,
|
|
810
|
+
file: Str,
|
|
811
|
+
mime: OptStr
|
|
812
|
+
});
|
|
813
|
+
var PdfDetection = Type.Object({
|
|
814
|
+
kind: Type.Literal("pdf"),
|
|
815
|
+
type: Type.Literal("application/pdf"),
|
|
816
|
+
file: Str,
|
|
817
|
+
mime: OptStr,
|
|
818
|
+
format: Type.Literal("pdf"),
|
|
819
|
+
pages: Int
|
|
820
|
+
});
|
|
821
|
+
var Detection = Type.Union([SourceDetection, ImageDetection, TextDetection, PdfDetection]);
|
|
822
|
+
var SourceDetectionInput = Type.Omit(SourceDetection, ["kind"]);
|
|
823
|
+
var ImageDetectionInput = Type.Omit(ImageDetection, ["kind"]);
|
|
824
|
+
var TextDetectionInput = Type.Omit(TextDetection, ["kind"]);
|
|
825
|
+
var PdfDetectionInput = Type.Omit(PdfDetection, ["kind"]);
|
|
826
|
+
var UnspannedContent = Type.Omit(ReadOutput, ["start_line", "end_line"]);
|
|
827
|
+
var PdfMetadata = Type.Object({ source: Str, format: Type.Literal("pdf"), pages: Int });
|
|
828
|
+
var DocumentCache = Type.Object({
|
|
829
|
+
content_hash: Str,
|
|
830
|
+
state: Type.Union([Type.Literal("built"), Type.Literal("reused")])
|
|
831
|
+
});
|
|
832
|
+
var Identifier = Type.Object({
|
|
833
|
+
text: Str,
|
|
834
|
+
start_column: Int,
|
|
835
|
+
end_column: Int,
|
|
836
|
+
start_byte: Int,
|
|
837
|
+
end_byte: Int
|
|
838
|
+
});
|
|
839
|
+
var CursorEnvelope = Type.Object({
|
|
840
|
+
file: Str,
|
|
841
|
+
language: Str,
|
|
842
|
+
engine: OptStr,
|
|
843
|
+
line_count: Int,
|
|
844
|
+
file_hash: Str,
|
|
845
|
+
line: Int,
|
|
846
|
+
column: Int,
|
|
847
|
+
line_hash: Str,
|
|
848
|
+
identifier: Type.Optional(Identifier),
|
|
849
|
+
symbol: Type.Optional(Type.Object({
|
|
850
|
+
name: Str,
|
|
851
|
+
kind: Str,
|
|
852
|
+
qualified_name: Str,
|
|
853
|
+
start_line: Int,
|
|
854
|
+
end_line: Int
|
|
855
|
+
}))
|
|
856
|
+
});
|
|
857
|
+
var EditOutputSchema = Type.Object({
|
|
858
|
+
file: Str,
|
|
859
|
+
before_hash: Str,
|
|
860
|
+
file_hash: Str,
|
|
861
|
+
plan_hash: Str,
|
|
862
|
+
applied: Bool,
|
|
863
|
+
changed: Bool,
|
|
864
|
+
edit_count: Int,
|
|
865
|
+
before_content: OptStr,
|
|
866
|
+
content: OptStr
|
|
867
|
+
});
|
|
868
|
+
var RenameConflictSchema = Type.Object({ line: Int, column: Int, reason: Str });
|
|
869
|
+
var RenameEditSchema = Type.Object({
|
|
870
|
+
line: Int,
|
|
871
|
+
start_column: Int,
|
|
872
|
+
end_column: Int,
|
|
873
|
+
start_byte: Int,
|
|
874
|
+
end_byte: Int,
|
|
875
|
+
occurrence: Str,
|
|
876
|
+
line_hash: Str,
|
|
877
|
+
text: Str
|
|
878
|
+
});
|
|
879
|
+
var Conflicts = Type.Array(RenameConflictSchema, { default: [] });
|
|
880
|
+
var Edits = Type.Array(RenameEditSchema, { default: [] });
|
|
881
|
+
var RenameFileOutputSchema = Type.Object({
|
|
882
|
+
file: Str,
|
|
883
|
+
language: Str,
|
|
884
|
+
engine: OptStr,
|
|
885
|
+
file_hash: Str,
|
|
886
|
+
conflicts: Conflicts,
|
|
887
|
+
edits: Edits
|
|
888
|
+
});
|
|
889
|
+
var RenameOutputSchema = Type.Object({
|
|
890
|
+
file: Str,
|
|
891
|
+
language: Str,
|
|
892
|
+
engine: OptStr,
|
|
893
|
+
file_hash: Str,
|
|
894
|
+
old_name: Str,
|
|
895
|
+
new_name: Str,
|
|
896
|
+
plan_hash: Str,
|
|
897
|
+
applied: Bool,
|
|
898
|
+
conflicts: Conflicts,
|
|
899
|
+
edits: Edits,
|
|
900
|
+
others: Type.Array(RenameFileOutputSchema, { default: [] })
|
|
901
|
+
});
|
|
902
|
+
var DefEnvelope = Type.Object({
|
|
903
|
+
locations: Type.Array(Type.Object({
|
|
904
|
+
file: Str,
|
|
905
|
+
line: Int,
|
|
906
|
+
column: Int,
|
|
907
|
+
line_hash: Str,
|
|
908
|
+
text: Str,
|
|
909
|
+
kind: OptStr,
|
|
910
|
+
name: OptStr,
|
|
911
|
+
qualified_name: OptStr
|
|
912
|
+
}))
|
|
913
|
+
});
|
|
914
|
+
function parseReadOutput(value) {
|
|
915
|
+
return parse(ReadOutput, value, "read output");
|
|
986
916
|
}
|
|
987
|
-
function
|
|
988
|
-
return
|
|
917
|
+
function parseStructureOutput(value) {
|
|
918
|
+
return parse(StructureOutput, value, "structure output");
|
|
989
919
|
}
|
|
990
|
-
function
|
|
991
|
-
const
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
920
|
+
function parseSearchOutput(value) {
|
|
921
|
+
const envelope = parse(SearchEnvelope, value, "search output");
|
|
922
|
+
const results = envelope.results;
|
|
923
|
+
if (envelope.returned_matches !== undefined)
|
|
924
|
+
results.returned_matches = envelope.returned_matches;
|
|
925
|
+
if (envelope.truncated !== undefined)
|
|
926
|
+
results.truncated = envelope.truncated;
|
|
927
|
+
if (envelope.byte_basis !== undefined)
|
|
928
|
+
results.byte_basis = envelope.byte_basis;
|
|
929
|
+
return results;
|
|
995
930
|
}
|
|
996
|
-
function
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
}
|
|
1002
|
-
const match = /^(\d+):([0-9a-f]+)$/.exec(anchor);
|
|
1003
|
-
if (!match)
|
|
1004
|
-
throw new Error(`invalid readseek KDL line anchor: ${anchor}`);
|
|
1005
|
-
return {
|
|
1006
|
-
line: Number(match[1]),
|
|
1007
|
-
hash: match[2],
|
|
1008
|
-
text: content
|
|
1009
|
-
};
|
|
931
|
+
function parseRefsOutput(value) {
|
|
932
|
+
return parse(RefsEnvelope, value, "refs output").references.map(({ symbol, ...reference }) => ({
|
|
933
|
+
...reference,
|
|
934
|
+
enclosingSymbol: symbol?.qualified_name
|
|
935
|
+
}));
|
|
1010
936
|
}
|
|
1011
|
-
function
|
|
937
|
+
function parseCheckOutput(value) {
|
|
938
|
+
const output = parse(CheckEnvelope, value, "check output");
|
|
1012
939
|
return {
|
|
1013
|
-
|
|
1014
|
-
|
|
940
|
+
file_hash: output.file_hash,
|
|
941
|
+
errorCount: output.error_count,
|
|
942
|
+
missingCount: output.missing_count,
|
|
943
|
+
diagnostics: output.diagnostics
|
|
1015
944
|
};
|
|
1016
945
|
}
|
|
1017
|
-
function
|
|
1018
|
-
const
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
if (objects.length > 0) {
|
|
1022
|
-
result.objects = objects.map((object) => ({
|
|
1023
|
-
label: requireProperty(object, "label"),
|
|
1024
|
-
bbox: [
|
|
1025
|
-
requireProperty(object, "xmin"),
|
|
1026
|
-
requireProperty(object, "ymin"),
|
|
1027
|
-
requireProperty(object, "xmax"),
|
|
1028
|
-
requireProperty(object, "ymax")
|
|
1029
|
-
]
|
|
1030
|
-
}));
|
|
946
|
+
function parseDetectOutput(value) {
|
|
947
|
+
const output = value ?? {};
|
|
948
|
+
if (output.type === "application/pdf") {
|
|
949
|
+
return { kind: "pdf", ...parse(PdfDetectionInput, value, "detect output") };
|
|
1031
950
|
}
|
|
1032
|
-
|
|
951
|
+
if (output.width !== undefined || output.height !== undefined) {
|
|
952
|
+
return { kind: "image", ...parse(ImageDetectionInput, value, "detect output") };
|
|
953
|
+
}
|
|
954
|
+
if (output.language !== undefined) {
|
|
955
|
+
return { kind: "source", ...parse(SourceDetectionInput, value, "detect output") };
|
|
956
|
+
}
|
|
957
|
+
return { kind: "text", ...parse(TextDetectionInput, value, "detect output") };
|
|
1033
958
|
}
|
|
1034
|
-
function
|
|
1035
|
-
const
|
|
959
|
+
function parseTextContent(value) {
|
|
960
|
+
const output = value ?? {};
|
|
961
|
+
if (output.hashlines === undefined || output.start_line !== undefined)
|
|
962
|
+
return parseReadOutput(value);
|
|
963
|
+
const spanned = parse(UnspannedContent, value, "content");
|
|
1036
964
|
return {
|
|
1037
|
-
...
|
|
1038
|
-
|
|
1039
|
-
|
|
965
|
+
...spanned,
|
|
966
|
+
start_line: spanned.hashlines[0]?.line ?? 1,
|
|
967
|
+
end_line: spanned.hashlines[spanned.hashlines.length - 1]?.line ?? 0
|
|
1040
968
|
};
|
|
1041
969
|
}
|
|
1042
|
-
function
|
|
970
|
+
function parseCursorOutput(value) {
|
|
971
|
+
return parse(CursorEnvelope, value, "cursor output");
|
|
972
|
+
}
|
|
973
|
+
function parsePdfMetadata(value) {
|
|
974
|
+
if (!value || typeof value !== "object")
|
|
975
|
+
return;
|
|
976
|
+
if (value.format !== "pdf")
|
|
977
|
+
return;
|
|
978
|
+
const document = parse(PdfMetadata, value, "inspect metadata");
|
|
979
|
+
return { kind: "pdf", type: "application/pdf", file: document.source, format: "pdf", pages: document.pages };
|
|
980
|
+
}
|
|
981
|
+
function parseEditOutput(value) {
|
|
982
|
+
return parse(EditOutputSchema, value, "edit output");
|
|
983
|
+
}
|
|
984
|
+
function parseRenameOutput(value) {
|
|
985
|
+
return parse(RenameOutputSchema, value, "rename output");
|
|
986
|
+
}
|
|
987
|
+
function parseDefOutput(value) {
|
|
988
|
+
return parse(DefEnvelope, value, "def output").locations;
|
|
989
|
+
}
|
|
990
|
+
var Bbox = Type.Object({ x: Type.Number(), y: Type.Number(), width: Type.Number(), height: Type.Number() });
|
|
991
|
+
var Position = { page: OptInt, destination: OptStr, bbox: Type.Optional(Bbox) };
|
|
992
|
+
var Provenance = { inferred: Type.Optional(Bool), model: OptStr, level: OptStr, task: OptStr };
|
|
993
|
+
var ImageDescriptor = Type.Object({
|
|
994
|
+
id: OptStr,
|
|
995
|
+
kind: Type.Optional(Type.Literal("image")),
|
|
996
|
+
content_identity: OptStr,
|
|
997
|
+
path: Str,
|
|
998
|
+
mime: Str,
|
|
999
|
+
width: Int,
|
|
1000
|
+
height: Int,
|
|
1001
|
+
caption: OptStr,
|
|
1002
|
+
ocr: OptStr,
|
|
1003
|
+
objects: Type.Optional(Type.Array(DetectedObject)),
|
|
1004
|
+
...Provenance
|
|
1005
|
+
});
|
|
1006
|
+
var DocumentNode = Type.Object({
|
|
1007
|
+
id: Str,
|
|
1008
|
+
kind: Str,
|
|
1009
|
+
parent_id: OptStr,
|
|
1010
|
+
title: OptStr,
|
|
1011
|
+
level: OptInt,
|
|
1012
|
+
column: OptInt,
|
|
1013
|
+
text: OptStr,
|
|
1014
|
+
...Position
|
|
1015
|
+
});
|
|
1016
|
+
var DocumentAsset = Type.Object({
|
|
1017
|
+
id: Str,
|
|
1018
|
+
kind: Str,
|
|
1019
|
+
mime: Str,
|
|
1020
|
+
path: OptStr,
|
|
1021
|
+
content_identity: OptStr,
|
|
1022
|
+
bytes: OptInt,
|
|
1023
|
+
...Position
|
|
1024
|
+
});
|
|
1025
|
+
var DocumentVision = Type.Object({
|
|
1026
|
+
asset_id: Str,
|
|
1027
|
+
mode: OptStr,
|
|
1028
|
+
caption: OptStr,
|
|
1029
|
+
ocr: OptStr,
|
|
1030
|
+
objects: Type.Optional(Type.Array(DetectedObject)),
|
|
1031
|
+
caption_requested: Type.Optional(Bool),
|
|
1032
|
+
objects_requested: Type.Optional(Bool),
|
|
1033
|
+
ocr_requested: Type.Optional(Bool),
|
|
1034
|
+
...Provenance
|
|
1035
|
+
});
|
|
1036
|
+
var DocumentOutput = Type.Object({
|
|
1037
|
+
id: OptStr,
|
|
1038
|
+
format: Str,
|
|
1039
|
+
source: Str,
|
|
1040
|
+
title: OptStr,
|
|
1041
|
+
pages: Int,
|
|
1042
|
+
nodes: Type.Array(DocumentNode, { default: [] }),
|
|
1043
|
+
assets: Type.Array(DocumentAsset, { default: [] }),
|
|
1044
|
+
vision: Type.Array(DocumentVision, { default: [] })
|
|
1045
|
+
});
|
|
1046
|
+
var TextHit = Type.Object({
|
|
1047
|
+
line: Int,
|
|
1048
|
+
column: Int,
|
|
1049
|
+
text: Str,
|
|
1050
|
+
start_line: Int,
|
|
1051
|
+
end_line: Int,
|
|
1052
|
+
start_byte: Int,
|
|
1053
|
+
end_byte: Int,
|
|
1054
|
+
hashlines: Hashlines
|
|
1055
|
+
});
|
|
1056
|
+
var DocumentHit = Type.Object({ node_id: Str, kind: Str, snippet: Str, page: OptInt });
|
|
1057
|
+
var TextSearchOutput = Type.Object({
|
|
1058
|
+
text: Str,
|
|
1059
|
+
mode: Type.Literal("literal"),
|
|
1060
|
+
total_matches: Int,
|
|
1061
|
+
returned_matches: Int,
|
|
1062
|
+
truncated: Bool,
|
|
1063
|
+
results: Type.Array(Type.Object({ file: Str, file_hash: Str, matches: Type.Array(TextHit) })),
|
|
1064
|
+
documents: Type.Array(Type.Object({ file: Str, content_hash: Str, hits: Type.Array(DocumentHit) }))
|
|
1065
|
+
});
|
|
1066
|
+
var RuleFinding = Type.Object({
|
|
1067
|
+
name: Str,
|
|
1068
|
+
message: Str,
|
|
1069
|
+
path: Str,
|
|
1070
|
+
language: Str,
|
|
1071
|
+
start_byte: Int,
|
|
1072
|
+
end_byte: Int,
|
|
1073
|
+
line: Int,
|
|
1074
|
+
column: Int,
|
|
1075
|
+
end_line: Int,
|
|
1076
|
+
end_column: Int
|
|
1077
|
+
});
|
|
1078
|
+
var RulesOutput = Type.Object({
|
|
1079
|
+
complete: Bool,
|
|
1080
|
+
check_count: Int,
|
|
1081
|
+
file_count: Int,
|
|
1082
|
+
violation_count: Int,
|
|
1083
|
+
diagnostics: Type.Array(RuleFinding)
|
|
1084
|
+
});
|
|
1085
|
+
function parseDocumentOutput(value) {
|
|
1086
|
+
return parse(DocumentOutput, value, "document output");
|
|
1087
|
+
}
|
|
1088
|
+
function parseContentOutput(value) {
|
|
1089
|
+
const output = value;
|
|
1090
|
+
if (output?.format !== undefined)
|
|
1091
|
+
return parseDocumentOutput(value);
|
|
1092
|
+
if (!output || output.metadata === undefined || output.content === undefined)
|
|
1093
|
+
throw new Error("invalid readseek content: missing metadata or content");
|
|
1094
|
+
const metadata = parseDetectOutput(output.metadata);
|
|
1043
1095
|
return {
|
|
1044
|
-
|
|
1045
|
-
|
|
1096
|
+
metadata,
|
|
1097
|
+
content: metadata.kind === "image" ? parse(ImageDescriptor, output.content, "image descriptor") : parseTextContent(output.content),
|
|
1098
|
+
...output.cursor !== undefined ? { cursor: parseCursorOutput(output.cursor) } : {}
|
|
1046
1099
|
};
|
|
1047
1100
|
}
|
|
1048
|
-
function
|
|
1049
|
-
const
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
if (
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1101
|
+
function parseStructureEnvelope(value) {
|
|
1102
|
+
const output = value;
|
|
1103
|
+
if (output?.format !== undefined)
|
|
1104
|
+
return parseDocumentOutput(value);
|
|
1105
|
+
if (!output || output.structure === undefined)
|
|
1106
|
+
throw new Error("invalid readseek structure: missing structure");
|
|
1107
|
+
return { ...output.metadata !== undefined ? { metadata: parseDetectOutput(output.metadata) } : {}, structure: parseStructureOutput(output.structure) };
|
|
1108
|
+
}
|
|
1109
|
+
function parseTextSearchOutput(value) {
|
|
1110
|
+
return parse(TextSearchOutput, value, "text search output");
|
|
1111
|
+
}
|
|
1112
|
+
function parseRulesOutput(value) {
|
|
1113
|
+
return parse(RulesOutput, value, "rules output");
|
|
1114
|
+
}
|
|
1115
|
+
var SourceAssetsOutput = Type.Object({ file: OptStr, metadata: Type.Optional(Detection), assets: Type.Array(DocumentAsset, { default: [] }) });
|
|
1116
|
+
function parseAssetsOutput(value) {
|
|
1117
|
+
const raw = value;
|
|
1118
|
+
if (raw?.format !== undefined)
|
|
1119
|
+
return parseDocumentOutput(value);
|
|
1120
|
+
if (!raw || raw.file === undefined && raw.metadata === undefined)
|
|
1121
|
+
throw new Error("invalid readseek assets output: missing file or metadata");
|
|
1122
|
+
return parse(SourceAssetsOutput, { ...raw, ...raw.metadata !== undefined ? { metadata: parseDetectOutput(raw.metadata) } : {} }, "assets output");
|
|
1057
1123
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
const
|
|
1063
|
-
const
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
result.metadata = properties(metadata);
|
|
1068
|
-
if (cache)
|
|
1069
|
-
result.cache = properties(cache);
|
|
1070
|
-
if (content)
|
|
1071
|
-
result.content = sourceContent(content);
|
|
1072
|
-
if (map)
|
|
1073
|
-
result.map = sourceMap(map);
|
|
1074
|
-
if (diagnosticOutput)
|
|
1075
|
-
result.diagnostics = diagnostics(diagnosticOutput);
|
|
1076
|
-
if (identityOutput)
|
|
1077
|
-
result.identity = identity(identityOutput);
|
|
1124
|
+
|
|
1125
|
+
// ../readseek-api/src/edit-plan.ts
|
|
1126
|
+
import { Document, Node, format } from "@bgotink/kdl";
|
|
1127
|
+
function node(name, properties, children = []) {
|
|
1128
|
+
const result = Node.create(name);
|
|
1129
|
+
for (const [key, value] of Object.entries(properties))
|
|
1130
|
+
result.setProperty(key, value);
|
|
1131
|
+
if (children.length > 0)
|
|
1132
|
+
result.children = new Document(children);
|
|
1078
1133
|
return result;
|
|
1079
1134
|
}
|
|
1080
|
-
function
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
})
|
|
1088
|
-
}
|
|
1135
|
+
function editNode(edit) {
|
|
1136
|
+
if ("set_line" in edit) {
|
|
1137
|
+
const value = edit.set_line;
|
|
1138
|
+
return node("set-line", { anchor: value.anchor, text: value.new_text });
|
|
1139
|
+
}
|
|
1140
|
+
if ("replace_lines" in edit) {
|
|
1141
|
+
const value = edit.replace_lines;
|
|
1142
|
+
return node("replace-lines", { start: value.start_anchor, end: value.end_anchor, text: value.new_text });
|
|
1143
|
+
}
|
|
1144
|
+
if ("insert_after" in edit) {
|
|
1145
|
+
const value = edit.insert_after;
|
|
1146
|
+
return node("insert-after", { anchor: value.anchor, text: value.new_text });
|
|
1147
|
+
}
|
|
1148
|
+
if ("replace_symbol" in edit) {
|
|
1149
|
+
const value = edit.replace_symbol;
|
|
1150
|
+
return node("replace-symbol", { symbol: value.symbol, body: value.new_body });
|
|
1151
|
+
}
|
|
1152
|
+
const value = edit.replace;
|
|
1153
|
+
return node("replace", {
|
|
1154
|
+
old: value.old_text,
|
|
1155
|
+
new: value.new_text,
|
|
1156
|
+
...value.all === undefined ? {} : { all: value.all }
|
|
1157
|
+
});
|
|
1089
1158
|
}
|
|
1090
|
-
function
|
|
1159
|
+
function serializeEditPlan(edits) {
|
|
1160
|
+
const validation = validateExactlyOneEditVariant(edits);
|
|
1161
|
+
if (!validation.ok)
|
|
1162
|
+
throw new Error(validation.error);
|
|
1163
|
+
return format(new Document([node("plan", {}, validation.edits.map(editNode))]));
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// ../readseek-api/src/client.ts
|
|
1167
|
+
function classifyReadSeekFailure(err) {
|
|
1168
|
+
const failure = err;
|
|
1169
|
+
const message = String(failure?.message ?? err);
|
|
1170
|
+
const missing = failure?.code === "ENOENT" || /Cannot find package|Cannot find module|no such file/i.test(message);
|
|
1171
|
+
if (missing) {
|
|
1172
|
+
return { code: "readseek-not-installed", message, hint: "Run npm install to install @jarkkojs/readseek." };
|
|
1173
|
+
}
|
|
1174
|
+
return { code: "readseek-execution-error", message };
|
|
1175
|
+
}
|
|
1176
|
+
function runOptions(options, vision = false) {
|
|
1091
1177
|
return {
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
}
|
|
1097
|
-
documents: children(root, "document").map((documentNode) => ({
|
|
1098
|
-
...properties(documentNode),
|
|
1099
|
-
hits: children(documentNode, "hit").map(properties)
|
|
1100
|
-
}))
|
|
1178
|
+
signal: options.signal,
|
|
1179
|
+
stdin: options.stdin,
|
|
1180
|
+
timeoutMs: options.timeoutMs,
|
|
1181
|
+
cancelable: options.cancelable,
|
|
1182
|
+
...vision ? { vision: true } : {}
|
|
1101
1183
|
};
|
|
1102
1184
|
}
|
|
1103
|
-
function
|
|
1104
|
-
const parsed = children(root, "reference").map((reference) => {
|
|
1105
|
-
const sourceLine = child(reference, "line");
|
|
1106
|
-
if (!sourceLine)
|
|
1107
|
-
throw new Error("invalid readseek KDL reference: missing line");
|
|
1108
|
-
const parsedLine = line(sourceLine);
|
|
1109
|
-
const symbol = child(reference, "symbol");
|
|
1110
|
-
return {
|
|
1111
|
-
...properties(reference),
|
|
1112
|
-
line_hash: parsedLine.hash,
|
|
1113
|
-
text: parsedLine.text,
|
|
1114
|
-
...symbol ? { symbol: properties(symbol) } : {}
|
|
1115
|
-
};
|
|
1116
|
-
});
|
|
1185
|
+
function createReadSeekClient(runner) {
|
|
1117
1186
|
return {
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
})
|
|
1187
|
+
async showContent(path, options = {}) {
|
|
1188
|
+
const value = await runner.kdl(buildShowContentArgs({ ...options, path }), runOptions(options));
|
|
1189
|
+
return parseContentOutput(value);
|
|
1190
|
+
},
|
|
1191
|
+
async showStructure(path, options = {}) {
|
|
1192
|
+
const value = await runner.kdl(buildShowStructureArgs({ ...options, path }), runOptions(options));
|
|
1193
|
+
return parseStructureEnvelope(value);
|
|
1194
|
+
},
|
|
1195
|
+
async showMetadata(path, options = {}) {
|
|
1196
|
+
const value = await runner.kdl(buildShowMetadataArgs({ ...options, path }), runOptions(options));
|
|
1197
|
+
return parsePdfMetadata(value) ?? parseDetectOutput(value?.metadata);
|
|
1198
|
+
},
|
|
1199
|
+
async showAssets(path, options = {}) {
|
|
1200
|
+
const value = await runner.kdl(buildShowAssetsArgs({ ...options, path }), runOptions(options));
|
|
1201
|
+
return parseAssetsOutput(value);
|
|
1202
|
+
},
|
|
1203
|
+
async checkSyntax(path, options = {}) {
|
|
1204
|
+
const value = await runner.kdl(buildCheckSyntaxArgs({ ...options, path }), runOptions(options));
|
|
1205
|
+
return parseCheckOutput(value?.diagnostics ?? value);
|
|
1206
|
+
},
|
|
1207
|
+
async checkRules(path, options) {
|
|
1208
|
+
const value = await runner.kdl(buildCheckRulesArgs({ ...options, path }), runOptions(options));
|
|
1209
|
+
return parseRulesOutput(value);
|
|
1210
|
+
},
|
|
1211
|
+
async generateCaption(path, options = {}) {
|
|
1212
|
+
const value = await runner.kdl(buildGenerateCaptionArgs({ ...options, path }), runOptions(options, true));
|
|
1213
|
+
return parseContentOutput(value);
|
|
1214
|
+
},
|
|
1215
|
+
async detectObjects(path, options = {}) {
|
|
1216
|
+
const value = await runner.kdl(buildDetectObjectsArgs({ ...options, path }), runOptions(options, true));
|
|
1217
|
+
return parseContentOutput(value);
|
|
1218
|
+
},
|
|
1219
|
+
async recognizeText(path, options = {}) {
|
|
1220
|
+
const value = await runner.kdl(buildRecognizeTextArgs({ ...options, path }), runOptions(options, true));
|
|
1221
|
+
return parseContentOutput(value);
|
|
1222
|
+
},
|
|
1223
|
+
async findNodes(path, options) {
|
|
1224
|
+
const value = await runner.kdl(buildFindNodesArgs({ ...options, path }), runOptions(options));
|
|
1225
|
+
return parseSearchOutput(value);
|
|
1226
|
+
},
|
|
1227
|
+
async findText(path, options) {
|
|
1228
|
+
const value = await runner.kdl(buildFindTextArgs({ ...options, path }), runOptions(options));
|
|
1229
|
+
return parseTextSearchOutput(value);
|
|
1230
|
+
},
|
|
1231
|
+
async findDefinitions(path, options) {
|
|
1232
|
+
const value = await runner.kdl(buildFindDefinitionsArgs({ ...options, path }), runOptions(options));
|
|
1233
|
+
return parseDefOutput(value);
|
|
1234
|
+
},
|
|
1235
|
+
async findReferences(path, options) {
|
|
1236
|
+
const value = await runner.kdl(buildFindReferencesArgs({ ...options, path }), runOptions(options));
|
|
1237
|
+
return parseRefsOutput(value);
|
|
1238
|
+
},
|
|
1239
|
+
async editText(path, edits, options = {}) {
|
|
1240
|
+
const stdin = serializeEditPlan(edits);
|
|
1241
|
+
return parseEditOutput(await runner.kdl(buildEditTextArgs({ ...options, path, requestFromStdin: true }), runOptions({ ...options, stdin })));
|
|
1242
|
+
},
|
|
1243
|
+
async renameSymbol(path, options) {
|
|
1244
|
+
const value = await runner.kdl(buildRenameSymbolArgs({ ...options, path }), runOptions(options));
|
|
1245
|
+
return parseRenameOutput(value);
|
|
1246
|
+
}
|
|
1123
1247
|
};
|
|
1124
1248
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
} else if (typeof nameByte === "number" && typeof startByte === "number") {
|
|
1142
|
-
column = nameByte - startByte + 1;
|
|
1143
|
-
}
|
|
1144
|
-
return {
|
|
1145
|
-
file: requireProperty(definition, "file"),
|
|
1146
|
-
line: parsedLine.line,
|
|
1147
|
-
column,
|
|
1148
|
-
line_hash: parsedLine.hash,
|
|
1149
|
-
text: parsedLine.text,
|
|
1150
|
-
kind: symbolProperties.kind,
|
|
1151
|
-
name: symbolProperties.name,
|
|
1152
|
-
qualified_name: symbolProperties.qualified_name
|
|
1153
|
-
};
|
|
1154
|
-
})
|
|
1155
|
-
};
|
|
1249
|
+
// ../readseek-api/src/platform.ts
|
|
1250
|
+
import { accessSync, constants as fsConstants, existsSync, statSync } from "node:fs";
|
|
1251
|
+
import { createRequire } from "node:module";
|
|
1252
|
+
import path2 from "node:path";
|
|
1253
|
+
var READSEEK_BINARY_ENV = "READSEEK_BINARY";
|
|
1254
|
+
var READSEEK_PLATFORM_PACKAGES = {
|
|
1255
|
+
"darwin-arm64": "@jarkkojs/readseek-darwin-arm64",
|
|
1256
|
+
"linux-arm64": "@jarkkojs/readseek-linux-arm64",
|
|
1257
|
+
"linux-x64": "@jarkkojs/readseek-linux-x64",
|
|
1258
|
+
"win32-x64": "@jarkkojs/readseek-win32-x64"
|
|
1259
|
+
};
|
|
1260
|
+
var resolveFromPackage = createRequire(import.meta.url).resolve;
|
|
1261
|
+
function readSeekBinaryName(platform = process.platform) {
|
|
1262
|
+
if (platform === "linux")
|
|
1263
|
+
return "readseek.AppImage";
|
|
1264
|
+
return platform === "win32" ? "readseek.exe" : "readseek";
|
|
1156
1265
|
}
|
|
1157
|
-
function
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1266
|
+
function readSeekPlatformKey(platform = process.platform, arch = process.arch) {
|
|
1267
|
+
return `${platform}-${arch}`;
|
|
1268
|
+
}
|
|
1269
|
+
function resolveReadSeekBinaryOverride(environment = process.env) {
|
|
1270
|
+
const binaryPath = environment[READSEEK_BINARY_ENV];
|
|
1271
|
+
if (binaryPath === undefined)
|
|
1272
|
+
return null;
|
|
1273
|
+
if (!path2.isAbsolute(binaryPath)) {
|
|
1274
|
+
throw new Error(`${READSEEK_BINARY_ENV} must be an absolute path to the readseek executable`);
|
|
1163
1275
|
}
|
|
1164
|
-
|
|
1276
|
+
try {
|
|
1277
|
+
if (!statSync(binaryPath).isFile())
|
|
1278
|
+
throw new Error("not a regular file");
|
|
1279
|
+
accessSync(binaryPath, fsConstants.X_OK);
|
|
1280
|
+
} catch (error) {
|
|
1281
|
+
throw new Error(`${READSEEK_BINARY_ENV} does not point to an executable file: ${binaryPath}`, {
|
|
1282
|
+
cause: error
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
return binaryPath;
|
|
1165
1286
|
}
|
|
1166
|
-
function
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
|
|
1287
|
+
function resolveReadSeekBinaryFromPackages(resolver = resolveFromPackage, options = {}) {
|
|
1288
|
+
const resolve = typeof resolver === "function" ? resolver : resolver.resolve.bind(resolver);
|
|
1289
|
+
const platform = options.platform ?? process.platform;
|
|
1290
|
+
const arch = options.arch ?? process.arch;
|
|
1291
|
+
const key = readSeekPlatformKey(platform, arch);
|
|
1292
|
+
const platformPackage = READSEEK_PLATFORM_PACKAGES[key];
|
|
1293
|
+
if (!platformPackage) {
|
|
1294
|
+
const supported = Object.keys(READSEEK_PLATFORM_PACKAGES).join(", ");
|
|
1295
|
+
throw new Error(`@jarkkojs/readseek ships no binary for ${key}; it supports ${supported}`);
|
|
1296
|
+
}
|
|
1297
|
+
const metaPackage = options.metaPackage ?? "@jarkkojs/readseek";
|
|
1298
|
+
let packageJsonPath;
|
|
1299
|
+
try {
|
|
1300
|
+
const metaPackageJson = resolve(`${metaPackage}/package.json`);
|
|
1301
|
+
const metaPackageDir = path2.dirname(metaPackageJson);
|
|
1302
|
+
packageJsonPath = resolve(`${platformPackage}/package.json`, {
|
|
1303
|
+
paths: [metaPackageDir]
|
|
1304
|
+
});
|
|
1305
|
+
} catch {
|
|
1306
|
+
packageJsonPath = resolve(`${platformPackage}/package.json`);
|
|
1307
|
+
}
|
|
1308
|
+
const binaryPath = path2.join(path2.dirname(packageJsonPath), "bin", readSeekBinaryName(platform));
|
|
1309
|
+
accessSync(binaryPath, fsConstants.X_OK);
|
|
1310
|
+
return binaryPath;
|
|
1311
|
+
}
|
|
1312
|
+
// ../readseek-api/src/error.ts
|
|
1313
|
+
var READSEEK_USAGE_HINT = /(?:^|\n)\s*Run readseek(?: [\w-]+)* --help for more information\.?\s*$/;
|
|
1314
|
+
function cleanReadSeekErrorText(stderr) {
|
|
1315
|
+
return stderr.replace(READSEEK_USAGE_HINT, "").replace(/^error:\s*/i, "").replace(/\s*\n\s*/g, " ").trim();
|
|
1316
|
+
}
|
|
1317
|
+
// ../readseek-api/src/kdl.ts
|
|
1318
|
+
import { parse as parse2 } from "@bgotink/kdl";
|
|
1319
|
+
function convertNode(node) {
|
|
1320
|
+
if (node.getTag() !== null)
|
|
1321
|
+
throw new Error("KDL node annotations are not supported");
|
|
1322
|
+
const properties = new Map;
|
|
1323
|
+
for (const entry of node.entries) {
|
|
1324
|
+
const name = entry.getName();
|
|
1325
|
+
if (name === null)
|
|
1326
|
+
throw new Error("KDL positional arguments are not supported");
|
|
1327
|
+
if (properties.has(name))
|
|
1328
|
+
throw new Error(`KDL duplicate property '${name}'`);
|
|
1329
|
+
if (entry.getTag() !== null)
|
|
1330
|
+
throw new Error("KDL value annotations are not supported");
|
|
1331
|
+
const value = entry.getValue();
|
|
1332
|
+
if (value === null)
|
|
1333
|
+
throw new Error("KDL null values are not supported");
|
|
1334
|
+
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
1335
|
+
throw new Error("KDL number out of range");
|
|
1336
|
+
}
|
|
1337
|
+
properties.set(name, value);
|
|
1338
|
+
}
|
|
1170
1339
|
return {
|
|
1171
|
-
|
|
1172
|
-
|
|
1340
|
+
name: node.getName(),
|
|
1341
|
+
properties,
|
|
1342
|
+
children: node.children?.nodes.map(convertNode) ?? []
|
|
1173
1343
|
};
|
|
1174
1344
|
}
|
|
1175
|
-
function
|
|
1345
|
+
function parseKdlDocument(text) {
|
|
1346
|
+
const document = parse2(text);
|
|
1347
|
+
if (document.nodes.length !== 1)
|
|
1348
|
+
throw new Error("KDL document must contain exactly one root node");
|
|
1349
|
+
return convertNode(document.nodes[0]);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// ../readseek-api/src/output-kdl.ts
|
|
1353
|
+
function properties(node) {
|
|
1354
|
+
return Object.fromEntries(node.properties);
|
|
1355
|
+
}
|
|
1356
|
+
function children(node, name) {
|
|
1357
|
+
return node.children.filter((child) => child.name === name);
|
|
1358
|
+
}
|
|
1359
|
+
function child(node, name) {
|
|
1360
|
+
return node.children.find((candidate) => candidate.name === name);
|
|
1361
|
+
}
|
|
1362
|
+
function requireProperty(node, name) {
|
|
1363
|
+
const value = node.properties.get(name);
|
|
1364
|
+
if (value === undefined)
|
|
1365
|
+
throw new Error(`invalid readseek KDL: ${node.name} is missing '${name}'`);
|
|
1366
|
+
return value;
|
|
1367
|
+
}
|
|
1368
|
+
function line(node) {
|
|
1369
|
+
const anchor = requireProperty(node, "anchor");
|
|
1370
|
+
const content = requireProperty(node, "content");
|
|
1371
|
+
if (typeof anchor !== "string" || typeof content !== "string") {
|
|
1372
|
+
throw new Error("invalid readseek KDL line");
|
|
1373
|
+
}
|
|
1374
|
+
const match = /^(\d+):([0-9a-f]+)$/.exec(anchor);
|
|
1375
|
+
if (!match)
|
|
1376
|
+
throw new Error(`invalid readseek KDL line anchor: ${anchor}`);
|
|
1176
1377
|
return {
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1378
|
+
line: Number(match[1]),
|
|
1379
|
+
hash: match[2],
|
|
1380
|
+
text: content
|
|
1180
1381
|
};
|
|
1181
1382
|
}
|
|
1182
|
-
function
|
|
1383
|
+
function mapNode(node) {
|
|
1183
1384
|
return {
|
|
1184
|
-
...
|
|
1185
|
-
|
|
1385
|
+
...properties(node),
|
|
1386
|
+
children: children(node, "node").map(mapNode)
|
|
1186
1387
|
};
|
|
1187
1388
|
}
|
|
1188
|
-
function
|
|
1389
|
+
function sourceContent(node) {
|
|
1189
1390
|
const result = properties(node);
|
|
1190
|
-
|
|
1191
|
-
const bbox = child(node, "bbox");
|
|
1192
|
-
if (textNode)
|
|
1193
|
-
result.text = requireProperty(textNode, "content");
|
|
1194
|
-
if (bbox)
|
|
1195
|
-
result.bbox = properties(bbox);
|
|
1391
|
+
result.hashlines = children(node, "line").map(line);
|
|
1196
1392
|
const objects = children(node, "object");
|
|
1197
|
-
if (objects.length > 0)
|
|
1198
|
-
result.objects = objects.map(
|
|
1393
|
+
if (objects.length > 0) {
|
|
1394
|
+
result.objects = objects.map((object) => ({
|
|
1395
|
+
label: requireProperty(object, "label"),
|
|
1396
|
+
bbox: [
|
|
1397
|
+
requireProperty(object, "xmin"),
|
|
1398
|
+
requireProperty(object, "ymin"),
|
|
1399
|
+
requireProperty(object, "xmax"),
|
|
1400
|
+
requireProperty(object, "ymax")
|
|
1401
|
+
]
|
|
1402
|
+
}));
|
|
1403
|
+
}
|
|
1199
1404
|
return result;
|
|
1200
1405
|
}
|
|
1201
|
-
function
|
|
1406
|
+
function sourceMap(node) {
|
|
1407
|
+
const root = child(node, "node");
|
|
1202
1408
|
return {
|
|
1203
|
-
...properties(
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
vision: children(root, "vision").map(genericNode)
|
|
1409
|
+
...properties(node),
|
|
1410
|
+
...root ? { root: mapNode(root) } : {},
|
|
1411
|
+
symbols: children(node, "symbol").map(properties)
|
|
1207
1412
|
};
|
|
1208
1413
|
}
|
|
1209
|
-
function
|
|
1210
|
-
const root = parseKdlDocument(text);
|
|
1211
|
-
switch (root.name) {
|
|
1212
|
-
case "document":
|
|
1213
|
-
return root.properties.has("format") ? pdfDocument(root) : sourceDocument(root);
|
|
1214
|
-
case "search":
|
|
1215
|
-
return search(root);
|
|
1216
|
-
case "check":
|
|
1217
|
-
return diagnostics(root);
|
|
1218
|
-
case "refs":
|
|
1219
|
-
return references(root);
|
|
1220
|
-
case "def":
|
|
1221
|
-
return definitions(root);
|
|
1222
|
-
case "edit":
|
|
1223
|
-
return edit(root);
|
|
1224
|
-
case "edit-batch":
|
|
1225
|
-
return { ...properties(root), files: children(root, "file").map(edit) };
|
|
1226
|
-
case "rename":
|
|
1227
|
-
return rename(root);
|
|
1228
|
-
default:
|
|
1229
|
-
throw new Error(`unsupported readseek KDL root: ${root.name}`);
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
1232
|
-
// ../readseek-api/src/process.ts
|
|
1233
|
-
var DEFAULT_READSEEK_TIMEOUT_MS = 120000;
|
|
1234
|
-
var DEFAULT_MAX_OUTPUT_BYTES = 32 * 1024 * 1024;
|
|
1235
|
-
function readSeekProcessEnvironment() {
|
|
1236
|
-
return process.platform === "linux" ? { ...process.env, APPIMAGE_EXTRACT_AND_RUN: "1" } : process.env;
|
|
1237
|
-
}
|
|
1238
|
-
function resolveProcessLimits(options = {}) {
|
|
1414
|
+
function diagnostics(node) {
|
|
1239
1415
|
return {
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
cancelable: options.cancelable !== false
|
|
1416
|
+
...properties(node),
|
|
1417
|
+
diagnostics: children(node, "diagnostic").map(properties)
|
|
1243
1418
|
};
|
|
1244
1419
|
}
|
|
1245
|
-
function
|
|
1246
|
-
const
|
|
1247
|
-
|
|
1420
|
+
function identity(node) {
|
|
1421
|
+
const result = properties(node);
|
|
1422
|
+
const identifier = child(node, "identifier");
|
|
1423
|
+
const symbol = child(node, "symbol");
|
|
1424
|
+
if (identifier)
|
|
1425
|
+
result.identifier = properties(identifier);
|
|
1426
|
+
if (symbol)
|
|
1427
|
+
result.symbol = properties(symbol);
|
|
1428
|
+
return result;
|
|
1248
1429
|
}
|
|
1249
|
-
function
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
const
|
|
1257
|
-
if (
|
|
1258
|
-
|
|
1259
|
-
if (
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
if (
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
let overflowed = false;
|
|
1276
|
-
stream.on("data", (chunk) => {
|
|
1277
|
-
if (overflowed)
|
|
1278
|
-
return;
|
|
1279
|
-
const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
1280
|
-
bytes += buffer.length;
|
|
1281
|
-
if (bytes > maxOutputBytes) {
|
|
1282
|
-
overflowed = true;
|
|
1283
|
-
onOverflow();
|
|
1284
|
-
return;
|
|
1285
|
-
}
|
|
1286
|
-
text += decoder.write(buffer);
|
|
1287
|
-
});
|
|
1288
|
-
return {
|
|
1289
|
-
text: () => text + decoder.end()
|
|
1290
|
-
};
|
|
1291
|
-
}
|
|
1292
|
-
async function runReadSeekNode(binaryPath, args, options = {}) {
|
|
1293
|
-
const limits = resolveProcessLimits(options);
|
|
1294
|
-
if (limits.cancelable && options.signal?.aborted) {
|
|
1295
|
-
throw readSeekCancellationError(options.signal);
|
|
1296
|
-
}
|
|
1297
|
-
return await new Promise((resolve, reject) => {
|
|
1298
|
-
let settled = false;
|
|
1299
|
-
let child;
|
|
1300
|
-
let timer;
|
|
1301
|
-
const finish = (result) => {
|
|
1302
|
-
if (settled)
|
|
1303
|
-
return;
|
|
1304
|
-
settled = true;
|
|
1305
|
-
if (timer !== undefined)
|
|
1306
|
-
clearTimeout(timer);
|
|
1307
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
1308
|
-
resolve(result);
|
|
1309
|
-
};
|
|
1310
|
-
const fail = (error) => {
|
|
1311
|
-
if (settled)
|
|
1312
|
-
return;
|
|
1313
|
-
settled = true;
|
|
1314
|
-
if (timer !== undefined)
|
|
1315
|
-
clearTimeout(timer);
|
|
1316
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
1317
|
-
reject(error instanceof Error ? error : new Error(String(error)));
|
|
1318
|
-
};
|
|
1319
|
-
const terminate = (error) => {
|
|
1320
|
-
if (settled)
|
|
1321
|
-
return;
|
|
1322
|
-
fail(error);
|
|
1323
|
-
try {
|
|
1324
|
-
child.kill("SIGKILL");
|
|
1325
|
-
} catch {}
|
|
1326
|
-
};
|
|
1327
|
-
const onAbort = () => {
|
|
1328
|
-
terminate(readSeekCancellationError(options.signal));
|
|
1329
|
-
};
|
|
1330
|
-
try {
|
|
1331
|
-
child = spawn(binaryPath, [...args], {
|
|
1332
|
-
cwd: options.cwd,
|
|
1333
|
-
env: readSeekProcessEnvironment(),
|
|
1334
|
-
shell: false,
|
|
1335
|
-
stdio: [options.stdin === undefined ? "ignore" : "pipe", "pipe", "pipe"],
|
|
1336
|
-
windowsHide: true
|
|
1337
|
-
});
|
|
1338
|
-
} catch (error) {
|
|
1339
|
-
fail(error);
|
|
1340
|
-
return;
|
|
1341
|
-
}
|
|
1342
|
-
const stdout = attachBoundedStream(child.stdout, limits.maxOutputBytes, () => {
|
|
1343
|
-
terminate(failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { overflow: "stdout", maxOutputBytes: limits.maxOutputBytes }));
|
|
1344
|
-
});
|
|
1345
|
-
const stderr = attachBoundedStream(child.stderr, limits.maxOutputBytes, () => {
|
|
1346
|
-
terminate(failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { overflow: "stderr", maxOutputBytes: limits.maxOutputBytes }));
|
|
1347
|
-
});
|
|
1348
|
-
timer = setTimeout(() => {
|
|
1349
|
-
terminate(failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { timedOut: true, timeoutMs: limits.timeoutMs }));
|
|
1350
|
-
}, limits.timeoutMs);
|
|
1351
|
-
timer.unref?.();
|
|
1352
|
-
if (limits.cancelable && options.signal) {
|
|
1353
|
-
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
1354
|
-
}
|
|
1355
|
-
if (options.stdin !== undefined) {
|
|
1356
|
-
child.stdin.on("error", (error) => {
|
|
1357
|
-
if (error.code !== "EPIPE")
|
|
1358
|
-
fail(error);
|
|
1359
|
-
});
|
|
1360
|
-
child.stdin.end(options.stdin, "utf8");
|
|
1361
|
-
}
|
|
1362
|
-
child.on("error", fail);
|
|
1363
|
-
child.on("close", (code, signal) => {
|
|
1364
|
-
finish({
|
|
1365
|
-
stdout: stdout.text(),
|
|
1366
|
-
stderr: stderr.text(),
|
|
1367
|
-
exitCode: code,
|
|
1368
|
-
signal
|
|
1369
|
-
});
|
|
1370
|
-
});
|
|
1371
|
-
});
|
|
1372
|
-
}
|
|
1373
|
-
async function runReadSeekNodeText(binaryPath, args, options = {}) {
|
|
1374
|
-
return ensureSuccessfulStdout(await runReadSeekNode(binaryPath, args, options));
|
|
1375
|
-
}
|
|
1376
|
-
// ../readseek-api/src/client-output.ts
|
|
1377
|
-
import { Type } from "@sinclair/typebox";
|
|
1378
|
-
import { AssertError, Value } from "@sinclair/typebox/value";
|
|
1379
|
-
var OPERATIONS = ["Clone", "Clean", "Default", "Assert"];
|
|
1380
|
-
function parse2(schema, value, what) {
|
|
1381
|
-
try {
|
|
1382
|
-
return Value.Parse(OPERATIONS, schema, value);
|
|
1383
|
-
} catch (error) {
|
|
1384
|
-
if (!(error instanceof AssertError))
|
|
1385
|
-
throw error;
|
|
1386
|
-
const detail = error.error;
|
|
1387
|
-
throw new Error(`invalid readseek ${what}${detail?.path ?? ""}: ${detail?.message ?? "invalid value"}`);
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
var Int = Type.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: Number.MAX_SAFE_INTEGER });
|
|
1391
|
-
var Str = Type.String();
|
|
1392
|
-
var Bool = Type.Boolean();
|
|
1393
|
-
var OptStr = Type.Optional(Str);
|
|
1394
|
-
var OptInt = Type.Optional(Int);
|
|
1395
|
-
var Hashline = Type.Object({ line: Int, hash: Str, text: Str });
|
|
1396
|
-
var Hashlines = Type.Array(Hashline);
|
|
1397
|
-
var ReadOutput = Type.Object({
|
|
1398
|
-
file: Str,
|
|
1399
|
-
language: Str,
|
|
1400
|
-
line_count: Int,
|
|
1401
|
-
file_hash: Str,
|
|
1402
|
-
start_line: Int,
|
|
1403
|
-
end_line: Int,
|
|
1404
|
-
hashlines: Hashlines
|
|
1405
|
-
});
|
|
1406
|
-
var SymbolOutput = Type.Object({
|
|
1407
|
-
kind: Str,
|
|
1408
|
-
name: Str,
|
|
1409
|
-
qualified_name: OptStr,
|
|
1410
|
-
start_line: Int,
|
|
1411
|
-
end_line: Int,
|
|
1412
|
-
start_hash: OptStr,
|
|
1413
|
-
end_hash: OptStr,
|
|
1414
|
-
start_anchor: OptStr,
|
|
1415
|
-
end_anchor: OptStr
|
|
1416
|
-
});
|
|
1417
|
-
function mapNodeShape(child) {
|
|
1418
|
-
return Type.Object({
|
|
1419
|
-
kind: Str,
|
|
1420
|
-
name: Str,
|
|
1421
|
-
start_line: Int,
|
|
1422
|
-
end_line: Int,
|
|
1423
|
-
start_anchor: Str,
|
|
1424
|
-
end_anchor: Str,
|
|
1425
|
-
children: Type.Array(child)
|
|
1426
|
-
});
|
|
1427
|
-
}
|
|
1428
|
-
function recursiveMapNode() {
|
|
1429
|
-
return Type.Recursive((self) => mapNodeShape(self));
|
|
1430
|
-
}
|
|
1431
|
-
var MapNode = typeof Type.Recursive === "function" ? recursiveMapNode() : Type.Cyclic({ MapNode: mapNodeShape(Type.Ref("MapNode")) }, "MapNode");
|
|
1432
|
-
var MapOutput = Type.Object({
|
|
1433
|
-
file: Str,
|
|
1434
|
-
language: Str,
|
|
1435
|
-
line_count: Int,
|
|
1436
|
-
file_hash: Str,
|
|
1437
|
-
root: Type.Optional(MapNode),
|
|
1438
|
-
symbols: Type.Array(SymbolOutput)
|
|
1439
|
-
});
|
|
1440
|
-
var SearchSpan = {
|
|
1441
|
-
start_byte: OptInt,
|
|
1442
|
-
end_byte: OptInt,
|
|
1443
|
-
text: OptStr,
|
|
1444
|
-
start_line: Int,
|
|
1445
|
-
end_line: Int,
|
|
1446
|
-
start_hash: Str,
|
|
1447
|
-
end_hash: Str,
|
|
1448
|
-
hashlines: Hashlines
|
|
1449
|
-
};
|
|
1450
|
-
var SearchCapture = Type.Object({ name: Str, ...SearchSpan });
|
|
1451
|
-
var SearchMatch = Type.Object({
|
|
1452
|
-
pattern_index: Type.Integer({ default: 0 }),
|
|
1453
|
-
...SearchSpan,
|
|
1454
|
-
captures: Type.Array(SearchCapture)
|
|
1455
|
-
});
|
|
1456
|
-
var SearchFileOutput = Type.Object({
|
|
1457
|
-
file: Str,
|
|
1458
|
-
language: Str,
|
|
1459
|
-
file_hash: Str,
|
|
1460
|
-
matches: Type.Array(SearchMatch)
|
|
1461
|
-
});
|
|
1462
|
-
var SearchEnvelope = Type.Object({
|
|
1463
|
-
results: Type.Array(SearchFileOutput),
|
|
1464
|
-
returned_matches: OptInt,
|
|
1465
|
-
truncated: Type.Optional(Bool),
|
|
1466
|
-
byte_basis: OptStr
|
|
1467
|
-
});
|
|
1468
|
-
var RefsEnvelope = Type.Object({
|
|
1469
|
-
references: Type.Array(Type.Object({
|
|
1470
|
-
file: Str,
|
|
1471
|
-
line: Int,
|
|
1472
|
-
column: Int,
|
|
1473
|
-
line_hash: Str,
|
|
1474
|
-
text: Str,
|
|
1475
|
-
symbol: Type.Optional(Type.Object({ qualified_name: OptStr }))
|
|
1476
|
-
}))
|
|
1477
|
-
});
|
|
1478
|
-
var Diagnostic = Type.Object({
|
|
1479
|
-
kind: Type.Union([Type.Literal("error"), Type.Literal("missing")]),
|
|
1480
|
-
start_line: Int,
|
|
1481
|
-
end_line: Int
|
|
1482
|
-
});
|
|
1483
|
-
var CheckEnvelope = Type.Object({
|
|
1484
|
-
file_hash: OptStr,
|
|
1485
|
-
error_count: Int,
|
|
1486
|
-
missing_count: Int,
|
|
1487
|
-
diagnostics: Type.Array(Diagnostic)
|
|
1488
|
-
});
|
|
1489
|
-
var DetectedObject = Type.Object({
|
|
1490
|
-
label: Str,
|
|
1491
|
-
bbox: Type.Tuple([Int, Int, Int, Int])
|
|
1492
|
-
});
|
|
1493
|
-
var PreparedImage = Type.Object({
|
|
1494
|
-
mime: Str,
|
|
1495
|
-
encoding: Type.Literal("base64"),
|
|
1496
|
-
data: Str
|
|
1497
|
-
});
|
|
1498
|
-
var SourceDetection = Type.Object({
|
|
1499
|
-
kind: Type.Literal("source"),
|
|
1500
|
-
type: Str,
|
|
1501
|
-
file: Str,
|
|
1502
|
-
language: Str,
|
|
1503
|
-
engine: OptStr,
|
|
1504
|
-
supported: Bool,
|
|
1505
|
-
mime: OptStr,
|
|
1506
|
-
syntax: OptStr
|
|
1507
|
-
});
|
|
1508
|
-
var ImageDetection = Type.Object({
|
|
1509
|
-
kind: Type.Literal("image"),
|
|
1510
|
-
type: Str,
|
|
1511
|
-
file: Str,
|
|
1512
|
-
mime: OptStr,
|
|
1513
|
-
format: Str,
|
|
1514
|
-
width: Int,
|
|
1515
|
-
height: Int,
|
|
1516
|
-
animated: Bool,
|
|
1517
|
-
encoding: Type.Optional(Type.Literal("base64")),
|
|
1518
|
-
data: OptStr,
|
|
1519
|
-
ocr: OptStr,
|
|
1520
|
-
caption: OptStr,
|
|
1521
|
-
objects: Type.Optional(Type.Array(DetectedObject))
|
|
1522
|
-
});
|
|
1523
|
-
var TextDetection = Type.Object({
|
|
1524
|
-
kind: Type.Literal("text"),
|
|
1525
|
-
type: Str,
|
|
1526
|
-
file: Str,
|
|
1527
|
-
mime: OptStr
|
|
1528
|
-
});
|
|
1529
|
-
var PdfDetection = Type.Object({
|
|
1530
|
-
kind: Type.Literal("pdf"),
|
|
1531
|
-
type: Type.Literal("application/pdf"),
|
|
1532
|
-
file: Str,
|
|
1533
|
-
mime: OptStr,
|
|
1534
|
-
format: Type.Literal("pdf"),
|
|
1535
|
-
pages: Int
|
|
1536
|
-
});
|
|
1537
|
-
var Detection = Type.Union([SourceDetection, ImageDetection, TextDetection, PdfDetection]);
|
|
1538
|
-
var SourceDetectionInput = Type.Omit(SourceDetection, ["kind"]);
|
|
1539
|
-
var ImageDetectionInput = Type.Omit(ImageDetection, ["kind"]);
|
|
1540
|
-
var TextDetectionInput = Type.Omit(TextDetection, ["kind"]);
|
|
1541
|
-
var PdfDetectionInput = Type.Omit(PdfDetection, ["kind"]);
|
|
1542
|
-
var UnspannedContent = Type.Omit(ReadOutput, ["start_line", "end_line"]);
|
|
1543
|
-
var PdfInspectMetadata = Type.Object({ source: Str, format: Type.Literal("pdf"), pages: Int });
|
|
1544
|
-
var DocumentCache = Type.Object({
|
|
1545
|
-
content_hash: Str,
|
|
1546
|
-
state: Type.Union([Type.Literal("built"), Type.Literal("reused")])
|
|
1547
|
-
});
|
|
1548
|
-
var Identifier = Type.Object({
|
|
1549
|
-
text: Str,
|
|
1550
|
-
start_column: Int,
|
|
1551
|
-
end_column: Int,
|
|
1552
|
-
start_byte: Int,
|
|
1553
|
-
end_byte: Int
|
|
1554
|
-
});
|
|
1555
|
-
var IdentifyEnvelope = Type.Object({
|
|
1556
|
-
file: Str,
|
|
1557
|
-
language: Str,
|
|
1558
|
-
engine: OptStr,
|
|
1559
|
-
line_count: Int,
|
|
1560
|
-
file_hash: Str,
|
|
1561
|
-
line: Int,
|
|
1562
|
-
column: Int,
|
|
1563
|
-
line_hash: Str,
|
|
1564
|
-
identifier: Type.Optional(Identifier),
|
|
1565
|
-
symbol: Type.Optional(Type.Object({
|
|
1566
|
-
name: Str,
|
|
1567
|
-
kind: Str,
|
|
1568
|
-
qualified_name: Str,
|
|
1569
|
-
start_line: Int,
|
|
1570
|
-
end_line: Int
|
|
1571
|
-
}))
|
|
1572
|
-
});
|
|
1573
|
-
var EditOutputSchema = Type.Object({
|
|
1574
|
-
file: Str,
|
|
1575
|
-
before_hash: Str,
|
|
1576
|
-
file_hash: Str,
|
|
1577
|
-
plan_hash: Str,
|
|
1578
|
-
applied: Bool,
|
|
1579
|
-
changed: Bool,
|
|
1580
|
-
edit_count: Int,
|
|
1581
|
-
before_content: OptStr,
|
|
1582
|
-
content: OptStr
|
|
1583
|
-
});
|
|
1584
|
-
var RenameConflictSchema = Type.Object({ line: Int, column: Int, reason: Str });
|
|
1585
|
-
var RenameEditSchema = Type.Object({
|
|
1586
|
-
line: Int,
|
|
1587
|
-
start_column: Int,
|
|
1588
|
-
end_column: Int,
|
|
1589
|
-
start_byte: Int,
|
|
1590
|
-
end_byte: Int,
|
|
1591
|
-
occurrence: Str,
|
|
1592
|
-
line_hash: Str,
|
|
1593
|
-
text: Str
|
|
1594
|
-
});
|
|
1595
|
-
var Conflicts = Type.Array(RenameConflictSchema, { default: [] });
|
|
1596
|
-
var Edits = Type.Array(RenameEditSchema, { default: [] });
|
|
1597
|
-
var RenameFileOutputSchema = Type.Object({
|
|
1598
|
-
file: Str,
|
|
1599
|
-
language: Str,
|
|
1600
|
-
engine: OptStr,
|
|
1601
|
-
file_hash: Str,
|
|
1602
|
-
conflicts: Conflicts,
|
|
1603
|
-
edits: Edits
|
|
1604
|
-
});
|
|
1605
|
-
var RenameOutputSchema = Type.Object({
|
|
1606
|
-
file: Str,
|
|
1607
|
-
language: Str,
|
|
1608
|
-
engine: OptStr,
|
|
1609
|
-
file_hash: Str,
|
|
1610
|
-
old_name: Str,
|
|
1611
|
-
new_name: Str,
|
|
1612
|
-
plan_hash: Str,
|
|
1613
|
-
applied: Bool,
|
|
1614
|
-
conflicts: Conflicts,
|
|
1615
|
-
edits: Edits,
|
|
1616
|
-
others: Type.Array(RenameFileOutputSchema, { default: [] })
|
|
1617
|
-
});
|
|
1618
|
-
var DefEnvelope = Type.Object({
|
|
1619
|
-
locations: Type.Array(Type.Object({
|
|
1620
|
-
file: Str,
|
|
1621
|
-
line: Int,
|
|
1622
|
-
column: Int,
|
|
1623
|
-
line_hash: Str,
|
|
1624
|
-
text: Str,
|
|
1625
|
-
kind: OptStr,
|
|
1626
|
-
name: OptStr,
|
|
1627
|
-
qualified_name: OptStr
|
|
1628
|
-
}))
|
|
1629
|
-
});
|
|
1630
|
-
function parseReadOutput(value) {
|
|
1631
|
-
return parse2(ReadOutput, value, "read output");
|
|
1430
|
+
function sourceDocument(root) {
|
|
1431
|
+
const result = {};
|
|
1432
|
+
const metadata = child(root, "metadata");
|
|
1433
|
+
const cache = child(root, "cache");
|
|
1434
|
+
const content = child(root, "content");
|
|
1435
|
+
const structure = child(root, "structure");
|
|
1436
|
+
const diagnosticOutput = child(root, "diagnostics");
|
|
1437
|
+
const identityOutput = child(root, "cursor");
|
|
1438
|
+
if (metadata)
|
|
1439
|
+
result.metadata = properties(metadata);
|
|
1440
|
+
if (!metadata && !content && !structure && !diagnosticOutput && !identityOutput && root.properties.has("file"))
|
|
1441
|
+
result.file = root.properties.get("file");
|
|
1442
|
+
const assets = children(root, "asset");
|
|
1443
|
+
if (assets.length > 0)
|
|
1444
|
+
result.assets = assets.map(genericNode);
|
|
1445
|
+
if (cache)
|
|
1446
|
+
result.cache = properties(cache);
|
|
1447
|
+
if (content)
|
|
1448
|
+
result.content = sourceContent(content);
|
|
1449
|
+
if (structure)
|
|
1450
|
+
result.structure = sourceMap(structure);
|
|
1451
|
+
if (diagnosticOutput)
|
|
1452
|
+
result.diagnostics = diagnostics(diagnosticOutput);
|
|
1453
|
+
if (identityOutput)
|
|
1454
|
+
result.cursor = identity(identityOutput);
|
|
1455
|
+
return result;
|
|
1632
1456
|
}
|
|
1633
|
-
function
|
|
1634
|
-
return
|
|
1457
|
+
function hit(node) {
|
|
1458
|
+
return {
|
|
1459
|
+
...properties(node),
|
|
1460
|
+
hashlines: children(node, "line").map(line),
|
|
1461
|
+
captures: children(node, "capture").map((capture) => ({
|
|
1462
|
+
...properties(capture),
|
|
1463
|
+
hashlines: children(capture, "line").map(line)
|
|
1464
|
+
}))
|
|
1465
|
+
};
|
|
1635
1466
|
}
|
|
1636
|
-
function
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1467
|
+
function search(root) {
|
|
1468
|
+
return {
|
|
1469
|
+
...properties(root),
|
|
1470
|
+
results: children(root, "match").map((match) => ({
|
|
1471
|
+
...properties(match),
|
|
1472
|
+
matches: children(match, "hit").map(hit)
|
|
1473
|
+
})),
|
|
1474
|
+
documents: children(root, "document").map((documentNode) => ({
|
|
1475
|
+
...properties(documentNode),
|
|
1476
|
+
hits: children(documentNode, "hit").map(properties)
|
|
1477
|
+
}))
|
|
1478
|
+
};
|
|
1646
1479
|
}
|
|
1647
|
-
function
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1480
|
+
function references(root) {
|
|
1481
|
+
const parsed = children(root, "reference").map((reference) => {
|
|
1482
|
+
const sourceLine = child(reference, "line");
|
|
1483
|
+
if (!sourceLine)
|
|
1484
|
+
throw new Error("invalid readseek KDL reference: missing line");
|
|
1485
|
+
const parsedLine = line(sourceLine);
|
|
1486
|
+
const symbol = child(reference, "symbol");
|
|
1487
|
+
return {
|
|
1488
|
+
...properties(reference),
|
|
1489
|
+
line_hash: parsedLine.hash,
|
|
1490
|
+
text: parsedLine.text,
|
|
1491
|
+
...symbol ? { symbol: properties(symbol) } : {}
|
|
1492
|
+
};
|
|
1493
|
+
});
|
|
1494
|
+
return {
|
|
1495
|
+
references: parsed,
|
|
1496
|
+
locations: parsed.map((reference) => {
|
|
1497
|
+
const { symbol, ...location } = reference;
|
|
1498
|
+
return symbol && typeof symbol === "object" ? { ...location, ...symbol } : location;
|
|
1499
|
+
})
|
|
1500
|
+
};
|
|
1652
1501
|
}
|
|
1653
|
-
function
|
|
1654
|
-
const output = parse2(CheckEnvelope, value, "check output");
|
|
1502
|
+
function definitions(root) {
|
|
1655
1503
|
return {
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1504
|
+
locations: children(root, "definition").map((definition) => {
|
|
1505
|
+
const symbol = child(definition, "symbol");
|
|
1506
|
+
const sourceLine = child(definition, "line");
|
|
1507
|
+
if (!symbol || !sourceLine) {
|
|
1508
|
+
throw new Error("invalid readseek KDL definition: missing symbol or line");
|
|
1509
|
+
}
|
|
1510
|
+
const symbolProperties = properties(symbol);
|
|
1511
|
+
const parsedLine = line(sourceLine);
|
|
1512
|
+
const definitionColumn = definition.properties.get("column");
|
|
1513
|
+
const nameByte = symbol.properties.get("name_byte");
|
|
1514
|
+
const startByte = symbol.properties.get("start_byte");
|
|
1515
|
+
let column = 1;
|
|
1516
|
+
if (typeof definitionColumn === "number") {
|
|
1517
|
+
column = definitionColumn;
|
|
1518
|
+
} else if (typeof nameByte === "number" && typeof startByte === "number") {
|
|
1519
|
+
column = nameByte - startByte + 1;
|
|
1520
|
+
}
|
|
1521
|
+
return {
|
|
1522
|
+
file: requireProperty(definition, "file"),
|
|
1523
|
+
line: parsedLine.line,
|
|
1524
|
+
column,
|
|
1525
|
+
line_hash: parsedLine.hash,
|
|
1526
|
+
text: parsedLine.text,
|
|
1527
|
+
kind: symbolProperties.kind,
|
|
1528
|
+
name: symbolProperties.name,
|
|
1529
|
+
qualified_name: symbolProperties.qualified_name
|
|
1530
|
+
};
|
|
1531
|
+
})
|
|
1660
1532
|
};
|
|
1661
1533
|
}
|
|
1662
|
-
function
|
|
1663
|
-
const
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
return { kind: "image", ...parse2(ImageDetectionInput, value, "detect output") };
|
|
1669
|
-
}
|
|
1670
|
-
if (output.language !== undefined) {
|
|
1671
|
-
return { kind: "source", ...parse2(SourceDetectionInput, value, "detect output") };
|
|
1534
|
+
function edit(root) {
|
|
1535
|
+
const result = properties(root);
|
|
1536
|
+
for (const name of ["before_content", "content"]) {
|
|
1537
|
+
const contentNode = child(root, name);
|
|
1538
|
+
if (contentNode)
|
|
1539
|
+
result[name] = requireProperty(contentNode, "content");
|
|
1672
1540
|
}
|
|
1673
|
-
return
|
|
1541
|
+
return result;
|
|
1542
|
+
}
|
|
1543
|
+
function renameEdit(node) {
|
|
1544
|
+
const sourceLine = child(node, "line");
|
|
1545
|
+
if (!sourceLine)
|
|
1546
|
+
throw new Error("invalid readseek KDL rename edit: missing line");
|
|
1547
|
+
return {
|
|
1548
|
+
...properties(node),
|
|
1549
|
+
text: requireProperty(sourceLine, "content")
|
|
1550
|
+
};
|
|
1674
1551
|
}
|
|
1675
|
-
function
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1552
|
+
function renameFile(node) {
|
|
1553
|
+
return {
|
|
1554
|
+
...properties(node),
|
|
1555
|
+
edits: children(node, "edit").map(renameEdit),
|
|
1556
|
+
conflicts: children(node, "conflict").map(properties)
|
|
1557
|
+
};
|
|
1680
1558
|
}
|
|
1681
|
-
function
|
|
1682
|
-
const output = value ?? {};
|
|
1683
|
-
if (output.hashlines === undefined || output.start_line !== undefined)
|
|
1684
|
-
return parseReadOutput(value);
|
|
1685
|
-
const spanned = parse2(UnspannedContent, value, "content");
|
|
1559
|
+
function rename(root) {
|
|
1686
1560
|
return {
|
|
1687
|
-
...
|
|
1688
|
-
|
|
1689
|
-
end_line: spanned.hashlines[spanned.hashlines.length - 1]?.line ?? 0
|
|
1561
|
+
...renameFile(root),
|
|
1562
|
+
others: children(root, "other").map(renameFile)
|
|
1690
1563
|
};
|
|
1691
1564
|
}
|
|
1692
|
-
function
|
|
1693
|
-
|
|
1565
|
+
function genericNode(node) {
|
|
1566
|
+
const result = properties(node);
|
|
1567
|
+
const textNode = child(node, "text");
|
|
1568
|
+
const bbox = child(node, "bbox");
|
|
1569
|
+
if (textNode)
|
|
1570
|
+
result.text = requireProperty(textNode, "content");
|
|
1571
|
+
if (bbox)
|
|
1572
|
+
result.bbox = properties(bbox);
|
|
1573
|
+
const objects = children(node, "object");
|
|
1574
|
+
if (objects.length > 0)
|
|
1575
|
+
result.objects = objects.map((object) => ({
|
|
1576
|
+
label: requireProperty(object, "label"),
|
|
1577
|
+
bbox: [requireProperty(object, "x0"), requireProperty(object, "y0"), requireProperty(object, "x1"), requireProperty(object, "y1")]
|
|
1578
|
+
}));
|
|
1579
|
+
return result;
|
|
1694
1580
|
}
|
|
1695
|
-
function
|
|
1696
|
-
return
|
|
1581
|
+
function pdfDocument(root) {
|
|
1582
|
+
return {
|
|
1583
|
+
...properties(root),
|
|
1584
|
+
nodes: children(root, "node").map(genericNode),
|
|
1585
|
+
assets: children(root, "asset").map(genericNode),
|
|
1586
|
+
vision: children(root, "vision").map(genericNode)
|
|
1587
|
+
};
|
|
1697
1588
|
}
|
|
1698
|
-
function
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1589
|
+
function parseReadSeekKdl(text) {
|
|
1590
|
+
const root = parseKdlDocument(text);
|
|
1591
|
+
switch (root.name) {
|
|
1592
|
+
case "document":
|
|
1593
|
+
return root.properties.has("format") ? pdfDocument(root) : sourceDocument(root);
|
|
1594
|
+
case "search":
|
|
1595
|
+
return search(root);
|
|
1596
|
+
case "check":
|
|
1597
|
+
return diagnostics(root);
|
|
1598
|
+
case "refs":
|
|
1599
|
+
return references(root);
|
|
1600
|
+
case "def":
|
|
1601
|
+
return definitions(root);
|
|
1602
|
+
case "edit":
|
|
1603
|
+
return edit(root);
|
|
1604
|
+
case "edit-batch":
|
|
1605
|
+
return { ...properties(root), files: children(root, "file").map(edit) };
|
|
1606
|
+
case "rename":
|
|
1607
|
+
return rename(root);
|
|
1608
|
+
default:
|
|
1609
|
+
throw new Error(`unsupported readseek KDL root: ${root.name}`);
|
|
1610
|
+
}
|
|
1705
1611
|
}
|
|
1706
|
-
|
|
1707
|
-
|
|
1612
|
+
// ../readseek-api/src/process.ts
|
|
1613
|
+
var DEFAULT_READSEEK_TIMEOUT_MS = 120000;
|
|
1614
|
+
var DEFAULT_MAX_OUTPUT_BYTES = 32 * 1024 * 1024;
|
|
1615
|
+
function readSeekProcessEnvironment() {
|
|
1616
|
+
return process.platform === "linux" ? { ...process.env, APPIMAGE_EXTRACT_AND_RUN: "1" } : process.env;
|
|
1708
1617
|
}
|
|
1709
|
-
function
|
|
1710
|
-
return
|
|
1618
|
+
function resolveProcessLimits(options = {}) {
|
|
1619
|
+
return {
|
|
1620
|
+
timeoutMs: options.timeoutMs ?? DEFAULT_READSEEK_TIMEOUT_MS,
|
|
1621
|
+
maxOutputBytes: options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES,
|
|
1622
|
+
cancelable: options.cancelable !== false
|
|
1623
|
+
};
|
|
1711
1624
|
}
|
|
1712
|
-
function
|
|
1713
|
-
|
|
1625
|
+
function readSeekCancellationError(signal) {
|
|
1626
|
+
const reason = signal?.reason;
|
|
1627
|
+
return reason instanceof Error && reason.name !== "AbortError" ? reason : new Error("readseek cancelled");
|
|
1714
1628
|
}
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
const failure = err;
|
|
1719
|
-
const message = String(failure?.message ?? err);
|
|
1720
|
-
const missing = failure?.code === "ENOENT" || /Cannot find package|Cannot find module|no such file/i.test(message);
|
|
1721
|
-
if (missing) {
|
|
1722
|
-
return { code: "readseek-not-installed", message, hint: "Run npm install to install @jarkkojs/readseek." };
|
|
1629
|
+
function failureFromProcessResult(result, options = {}) {
|
|
1630
|
+
if (options.overflow) {
|
|
1631
|
+
return new Error(`readseek ${options.overflow} exceeded the ${options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES}-byte output limit`);
|
|
1723
1632
|
}
|
|
1724
|
-
|
|
1633
|
+
if (options.timedOut) {
|
|
1634
|
+
return new Error(`readseek timed out after ${options.timeoutMs ?? DEFAULT_READSEEK_TIMEOUT_MS} ms`);
|
|
1635
|
+
}
|
|
1636
|
+
const cleaned = cleanReadSeekErrorText(result.stderr);
|
|
1637
|
+
if (cleaned)
|
|
1638
|
+
return new Error(cleaned);
|
|
1639
|
+
if (result.signal)
|
|
1640
|
+
return new Error(`readseek killed by signal ${result.signal}`);
|
|
1641
|
+
return new Error(`readseek exited with status ${result.exitCode}`);
|
|
1725
1642
|
}
|
|
1726
|
-
function
|
|
1727
|
-
if (
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1643
|
+
function acceptsReadSeekExitCode(args, exitCode) {
|
|
1644
|
+
if (exitCode === 0)
|
|
1645
|
+
return true;
|
|
1646
|
+
if (exitCode !== 1)
|
|
1647
|
+
return false;
|
|
1648
|
+
let index = 0;
|
|
1649
|
+
const valued = new Set(["-C", "--directory", "--output", "--readseek-dir"]);
|
|
1650
|
+
while (index < args.length) {
|
|
1651
|
+
const arg = args[index];
|
|
1652
|
+
if (valued.has(arg)) {
|
|
1653
|
+
index += 2;
|
|
1654
|
+
continue;
|
|
1655
|
+
}
|
|
1656
|
+
if ([...valued].some((flag) => arg.startsWith(`${flag}=`)) || arg === "--kdl") {
|
|
1657
|
+
index++;
|
|
1658
|
+
continue;
|
|
1659
|
+
}
|
|
1660
|
+
return arg === "find" || arg === "check";
|
|
1661
|
+
}
|
|
1662
|
+
return false;
|
|
1744
1663
|
}
|
|
1745
|
-
function
|
|
1746
|
-
|
|
1747
|
-
return
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1664
|
+
function ensureSuccessfulStdout(result, args = []) {
|
|
1665
|
+
if (!result.signal && acceptsReadSeekExitCode(args, result.exitCode))
|
|
1666
|
+
return result.stdout;
|
|
1667
|
+
throw failureFromProcessResult(result);
|
|
1668
|
+
}
|
|
1669
|
+
// ../readseek-api/src/process-node.ts
|
|
1670
|
+
import { spawn } from "node:child_process";
|
|
1671
|
+
import { StringDecoder } from "node:string_decoder";
|
|
1672
|
+
function attachBoundedStream(stream, maxOutputBytes, onOverflow) {
|
|
1673
|
+
const decoder = new StringDecoder("utf8");
|
|
1674
|
+
let text = "";
|
|
1675
|
+
let bytes = 0;
|
|
1676
|
+
let overflowed = false;
|
|
1677
|
+
stream.on("data", (chunk) => {
|
|
1678
|
+
if (overflowed)
|
|
1679
|
+
return;
|
|
1680
|
+
const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
1681
|
+
bytes += buffer.length;
|
|
1682
|
+
if (bytes > maxOutputBytes) {
|
|
1683
|
+
overflowed = true;
|
|
1684
|
+
onOverflow();
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
text += decoder.write(buffer);
|
|
1688
|
+
});
|
|
1689
|
+
return {
|
|
1690
|
+
text: () => text + decoder.end()
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
async function runReadSeekNode(binaryPath, args, options = {}) {
|
|
1694
|
+
const limits = resolveProcessLimits(options);
|
|
1695
|
+
if (limits.cancelable && options.signal?.aborted) {
|
|
1696
|
+
throw readSeekCancellationError(options.signal);
|
|
1760
1697
|
}
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1698
|
+
return await new Promise((resolve, reject) => {
|
|
1699
|
+
let settled = false;
|
|
1700
|
+
let child;
|
|
1701
|
+
let timer;
|
|
1702
|
+
const finish = (result) => {
|
|
1703
|
+
if (settled)
|
|
1704
|
+
return;
|
|
1705
|
+
settled = true;
|
|
1706
|
+
if (timer !== undefined)
|
|
1707
|
+
clearTimeout(timer);
|
|
1708
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
1709
|
+
resolve(result);
|
|
1767
1710
|
};
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1711
|
+
const fail = (error) => {
|
|
1712
|
+
if (settled)
|
|
1713
|
+
return;
|
|
1714
|
+
settled = true;
|
|
1715
|
+
if (timer !== undefined)
|
|
1716
|
+
clearTimeout(timer);
|
|
1717
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
1718
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
1719
|
+
};
|
|
1720
|
+
const terminate = (error) => {
|
|
1721
|
+
if (settled)
|
|
1722
|
+
return;
|
|
1723
|
+
fail(error);
|
|
1724
|
+
try {
|
|
1725
|
+
child.kill("SIGKILL");
|
|
1726
|
+
} catch {}
|
|
1727
|
+
};
|
|
1728
|
+
const onAbort = () => {
|
|
1729
|
+
terminate(readSeekCancellationError(options.signal));
|
|
1730
|
+
};
|
|
1731
|
+
try {
|
|
1732
|
+
child = spawn(binaryPath, [...args], {
|
|
1733
|
+
cwd: options.cwd,
|
|
1734
|
+
env: readSeekProcessEnvironment(),
|
|
1735
|
+
shell: false,
|
|
1736
|
+
stdio: [options.stdin === undefined ? "ignore" : "pipe", "pipe", "pipe"],
|
|
1737
|
+
windowsHide: true
|
|
1738
|
+
});
|
|
1739
|
+
} catch (error) {
|
|
1740
|
+
fail(error);
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
const stdout = attachBoundedStream(child.stdout, limits.maxOutputBytes, () => {
|
|
1744
|
+
terminate(failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { overflow: "stdout", maxOutputBytes: limits.maxOutputBytes }));
|
|
1745
|
+
});
|
|
1746
|
+
const stderr = attachBoundedStream(child.stderr, limits.maxOutputBytes, () => {
|
|
1747
|
+
terminate(failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { overflow: "stderr", maxOutputBytes: limits.maxOutputBytes }));
|
|
1796
1748
|
});
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
if (metadata.kind === "image") {
|
|
1804
|
-
return { metadata, image: parseImageContent(content) };
|
|
1749
|
+
timer = setTimeout(() => {
|
|
1750
|
+
terminate(failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { timedOut: true, timeoutMs: limits.timeoutMs }));
|
|
1751
|
+
}, limits.timeoutMs);
|
|
1752
|
+
timer.unref?.();
|
|
1753
|
+
if (limits.cancelable && options.signal) {
|
|
1754
|
+
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
1805
1755
|
}
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
inspectText,
|
|
1811
|
-
inspectContent,
|
|
1812
|
-
async extract(target, selector, output, options = {}) {
|
|
1813
|
-
await runner.text(buildExtractArgs({
|
|
1814
|
-
path: target,
|
|
1815
|
-
selector,
|
|
1816
|
-
output,
|
|
1817
|
-
stdinName: options.stdinName
|
|
1818
|
-
}), {
|
|
1819
|
-
signal: options.signal,
|
|
1820
|
-
stdin: options.stdin,
|
|
1821
|
-
timeoutMs: options.timeoutMs,
|
|
1822
|
-
cancelable: options.cancelable
|
|
1823
|
-
});
|
|
1824
|
-
},
|
|
1825
|
-
async image(filePath, modes, options = {}) {
|
|
1826
|
-
if (modes.length === 0)
|
|
1827
|
-
throw new Error(`readseek returned no image analysis for ${filePath}`);
|
|
1828
|
-
const inspected = await inspectContent(filePath, {
|
|
1829
|
-
visionMode: modes.length > 1 ? "all" : modes[0],
|
|
1830
|
-
signal: options.signal,
|
|
1831
|
-
vision: true
|
|
1832
|
-
});
|
|
1833
|
-
if (!inspected.image)
|
|
1834
|
-
throw new Error(`readseek returned no image analysis for ${filePath}`);
|
|
1835
|
-
return inspected.image;
|
|
1836
|
-
},
|
|
1837
|
-
async preparedImage(filePath, options = {}) {
|
|
1838
|
-
const inspected = await inspectContent(filePath, {
|
|
1839
|
-
visionMode: "none",
|
|
1840
|
-
signal: options.signal
|
|
1841
|
-
});
|
|
1842
|
-
const output = inspected.image;
|
|
1843
|
-
if (!output || output.encoding !== "base64" || output.data === undefined || output.mime === undefined) {
|
|
1844
|
-
throw new Error(`readseek returned no prepared image for ${filePath}`);
|
|
1845
|
-
}
|
|
1846
|
-
return { mime: output.mime, encoding: output.encoding, data: output.data };
|
|
1847
|
-
},
|
|
1848
|
-
async search(target, pattern, options = {}) {
|
|
1849
|
-
const args = buildSearchArgs({
|
|
1850
|
-
path: target,
|
|
1851
|
-
pattern,
|
|
1852
|
-
language: options.language,
|
|
1853
|
-
limit: options.limit,
|
|
1854
|
-
gitScope: options.gitScope
|
|
1855
|
-
});
|
|
1856
|
-
return parseSearchOutput(await runner.kdl(args, { signal: options.signal }));
|
|
1857
|
-
},
|
|
1858
|
-
async refs(target, options = {}) {
|
|
1859
|
-
const args = buildRefsArgs({
|
|
1860
|
-
path: target,
|
|
1861
|
-
name: options.name,
|
|
1862
|
-
scope: options.scope,
|
|
1863
|
-
line: options.line,
|
|
1864
|
-
column: options.column,
|
|
1865
|
-
language: options.language,
|
|
1866
|
-
gitScope: options.gitScope
|
|
1867
|
-
});
|
|
1868
|
-
return parseRefsOutput(await runner.kdl(args, { signal: options.signal }));
|
|
1869
|
-
},
|
|
1870
|
-
async def(target, options) {
|
|
1871
|
-
const args = buildDefArgs({
|
|
1872
|
-
path: target,
|
|
1873
|
-
name: options.name,
|
|
1874
|
-
language: options.language,
|
|
1875
|
-
gitScope: options.gitScope
|
|
1876
|
-
});
|
|
1877
|
-
return parseDefOutput(await runner.kdl(args, { signal: options.signal }));
|
|
1878
|
-
},
|
|
1879
|
-
async check(filePath, content, options = {}) {
|
|
1880
|
-
const envelope = await inspectSource("-", {
|
|
1881
|
-
select: "diagnostics",
|
|
1882
|
-
stdin: content,
|
|
1883
|
-
stdinName: filePath,
|
|
1884
|
-
signal: options.signal
|
|
1885
|
-
});
|
|
1886
|
-
if (!envelope.diagnostics)
|
|
1887
|
-
throw new Error("invalid readseek diagnostics: missing diagnostics facet");
|
|
1888
|
-
return envelope.diagnostics;
|
|
1889
|
-
},
|
|
1890
|
-
async identify(filePath, content, options) {
|
|
1891
|
-
const envelope = await inspectSource("-", {
|
|
1892
|
-
select: "identity",
|
|
1893
|
-
stdin: content,
|
|
1894
|
-
stdinName: filePath,
|
|
1895
|
-
selector: buildLineLocation(options.line, options.column),
|
|
1896
|
-
language: options.language,
|
|
1897
|
-
signal: options.signal
|
|
1898
|
-
});
|
|
1899
|
-
if (!envelope.identity)
|
|
1900
|
-
throw new Error("invalid readseek identity: missing identity facet");
|
|
1901
|
-
return envelope.identity;
|
|
1902
|
-
},
|
|
1903
|
-
async detect(filePath, options = {}) {
|
|
1904
|
-
const inspected = await inspect(filePath, { select: "metadata", signal: options.signal });
|
|
1905
|
-
const pdf = parsePdfInspectMetadata(inspected);
|
|
1906
|
-
if (pdf)
|
|
1907
|
-
return pdf;
|
|
1908
|
-
return requireInspectMetadata(parseSourceInspectEnvelope(inspected), "metadata");
|
|
1909
|
-
},
|
|
1910
|
-
async edit(filePath, edits, options = {}) {
|
|
1911
|
-
const args = buildEditArgs({
|
|
1912
|
-
path: filePath,
|
|
1913
|
-
apply: options.apply,
|
|
1914
|
-
planHash: options.planHash,
|
|
1915
|
-
language: options.language,
|
|
1916
|
-
requestFromStdin: true
|
|
1917
|
-
});
|
|
1918
|
-
return parseEditOutput(await runner.kdl(args, {
|
|
1919
|
-
signal: options.signal,
|
|
1920
|
-
stdin: serializeEditPlan(edits),
|
|
1921
|
-
timeoutMs: options.timeoutMs,
|
|
1922
|
-
cancelable: options.cancelable
|
|
1923
|
-
}));
|
|
1924
|
-
},
|
|
1925
|
-
async rename(filePath, options) {
|
|
1926
|
-
const args = buildRenameArgs({
|
|
1927
|
-
path: filePath,
|
|
1928
|
-
to: options.to,
|
|
1929
|
-
line: options.line,
|
|
1930
|
-
column: options.column,
|
|
1931
|
-
workspace: options.workspace,
|
|
1932
|
-
apply: options.apply,
|
|
1933
|
-
planHash: options.planHash,
|
|
1934
|
-
language: options.language,
|
|
1935
|
-
gitScope: options.gitScope
|
|
1756
|
+
if (options.stdin !== undefined) {
|
|
1757
|
+
child.stdin.on("error", (error) => {
|
|
1758
|
+
if (error.code !== "EPIPE")
|
|
1759
|
+
fail(error);
|
|
1936
1760
|
});
|
|
1937
|
-
|
|
1761
|
+
child.stdin.end(options.stdin, "utf8");
|
|
1938
1762
|
}
|
|
1939
|
-
|
|
1763
|
+
child.on("error", fail);
|
|
1764
|
+
child.on("close", (code, signal) => {
|
|
1765
|
+
finish({
|
|
1766
|
+
stdout: stdout.text(),
|
|
1767
|
+
stderr: stderr.text(),
|
|
1768
|
+
exitCode: code,
|
|
1769
|
+
signal
|
|
1770
|
+
});
|
|
1771
|
+
});
|
|
1772
|
+
});
|
|
1773
|
+
}
|
|
1774
|
+
async function runReadSeekNodeText(binaryPath, args, options = {}) {
|
|
1775
|
+
return ensureSuccessfulStdout(await runReadSeekNode(binaryPath, args, options), args);
|
|
1940
1776
|
}
|
|
1941
1777
|
// src/tool-prompt-metadata.ts
|
|
1942
1778
|
var REPLACEABLE_BY_TOOL = new Map(REPLACEABLE_TOOLS.map((entry) => [entry.tool, entry]));
|
|
@@ -2415,7 +2251,7 @@ function formatReplaceHint(edits, noopEdits) {
|
|
|
2415
2251
|
return;
|
|
2416
2252
|
if (counts.replace !== counts.total)
|
|
2417
2253
|
return;
|
|
2418
|
-
return "[info: this edit used replace (unverified). For safer future edits, prefer set_line/replace_lines with an anchor from
|
|
2254
|
+
return "[info: this edit used replace (unverified). For safer future edits, prefer set_line/replace_lines with an anchor from readSeek_show_content/readSeek_find_text/readSeek_find_nodes.]";
|
|
2419
2255
|
}
|
|
2420
2256
|
function buildEditOutput(input) {
|
|
2421
2257
|
const summary = `Updated ${input.displayPath}`;
|
|
@@ -2508,17 +2344,17 @@ function classifyEdit(oldContent, newContent) {
|
|
|
2508
2344
|
import { existsSync as existsSync2, statSync as statSync3 } from "node:fs";
|
|
2509
2345
|
import { createRequire as createRequire2 } from "node:module";
|
|
2510
2346
|
import { homedir as homedir2 } from "node:os";
|
|
2511
|
-
import
|
|
2347
|
+
import path3 from "node:path";
|
|
2512
2348
|
|
|
2513
2349
|
// src/readseek-settings.ts
|
|
2514
2350
|
import { readFileSync, statSync as statSync2 } from "node:fs";
|
|
2515
2351
|
import { homedir } from "node:os";
|
|
2516
2352
|
import { join } from "node:path";
|
|
2517
2353
|
var READSEEK_TOOL_REPLACEMENTS = {
|
|
2518
|
-
read: "
|
|
2519
|
-
edit: "
|
|
2520
|
-
grep: "
|
|
2521
|
-
write: "
|
|
2354
|
+
read: "readSeek_show_content",
|
|
2355
|
+
edit: "readSeek_edit_text",
|
|
2356
|
+
grep: "readSeek_find_text",
|
|
2357
|
+
write: "readSeek_write_file"
|
|
2522
2358
|
};
|
|
2523
2359
|
var READSEEK_KEYS = ["overrideTools", "imageMode", "syntaxValidation", "timeoutMs", "grep", "display"];
|
|
2524
2360
|
var READSEEK_GREP_KEYS = ["maxLines", "maxBytes"];
|
|
@@ -2735,7 +2571,7 @@ function readSeekBinaryAvailability() {
|
|
|
2735
2571
|
var defaultReadSeekDirInit;
|
|
2736
2572
|
function defaultReadSeekDir() {
|
|
2737
2573
|
const home = homedir2();
|
|
2738
|
-
return home ?
|
|
2574
|
+
return home ? path3.join(home, ".pi", "readseek") : null;
|
|
2739
2575
|
}
|
|
2740
2576
|
function directoryExists(dir) {
|
|
2741
2577
|
try {
|
|
@@ -2754,24 +2590,39 @@ async function ensureDefaultReadSeekDir() {
|
|
|
2754
2590
|
return null;
|
|
2755
2591
|
if (directoryExists(dir))
|
|
2756
2592
|
return dir;
|
|
2757
|
-
defaultReadSeekDirInit ??= runReadSeekNodeText(readSeekBinaryPath(), ["--readseek-dir", dir, "
|
|
2593
|
+
defaultReadSeekDirInit ??= runReadSeekNodeText(readSeekBinaryPath(), ["--readseek-dir", dir, "initialize", "index"], { timeoutMs: readSeekTimeoutMs() }).then(() => directoryExists(dir) ? dir : null).catch(() => null).finally(() => {
|
|
2758
2594
|
defaultReadSeekDirInit = undefined;
|
|
2759
2595
|
});
|
|
2760
2596
|
return defaultReadSeekDirInit;
|
|
2761
2597
|
}
|
|
2762
2598
|
function hasProjectReadSeekDir(cwd = process.cwd()) {
|
|
2763
|
-
let dir =
|
|
2599
|
+
let dir = path3.resolve(cwd);
|
|
2764
2600
|
while (true) {
|
|
2765
|
-
if (existsSync2(
|
|
2601
|
+
if (existsSync2(path3.join(dir, ".readseek")))
|
|
2766
2602
|
return true;
|
|
2767
|
-
const parent =
|
|
2603
|
+
const parent = path3.dirname(dir);
|
|
2768
2604
|
if (parent === dir)
|
|
2769
2605
|
return false;
|
|
2770
2606
|
dir = parent;
|
|
2771
2607
|
}
|
|
2772
2608
|
}
|
|
2609
|
+
function supportsReadSeekDir(args) {
|
|
2610
|
+
const first = args[0];
|
|
2611
|
+
const second = args[1];
|
|
2612
|
+
if (first === "initialize" && second === "index")
|
|
2613
|
+
return true;
|
|
2614
|
+
if (first === "show" && (second === "content" || second === "assets"))
|
|
2615
|
+
return true;
|
|
2616
|
+
if (first === "generate" && second === "caption")
|
|
2617
|
+
return true;
|
|
2618
|
+
if (first === "detect" && second === "objects")
|
|
2619
|
+
return true;
|
|
2620
|
+
if (first === "recognize" && second === "text")
|
|
2621
|
+
return true;
|
|
2622
|
+
return false;
|
|
2623
|
+
}
|
|
2773
2624
|
async function readSeekInvocationArgs(args) {
|
|
2774
|
-
if (hasProjectReadSeekDir())
|
|
2625
|
+
if (!supportsReadSeekDir(args) || hasProjectReadSeekDir())
|
|
2775
2626
|
return [...args];
|
|
2776
2627
|
const readSeekDir = await ensureDefaultReadSeekDir();
|
|
2777
2628
|
return readSeekDir ? ["--readseek-dir", readSeekDir, ...args] : [...args];
|
|
@@ -2825,22 +2676,24 @@ var runner = {
|
|
|
2825
2676
|
}),
|
|
2826
2677
|
kdl: async (args, options = {}) => parseReadSeekKdl(await runner.text(args, options))
|
|
2827
2678
|
};
|
|
2828
|
-
var
|
|
2829
|
-
var
|
|
2830
|
-
var
|
|
2831
|
-
var
|
|
2832
|
-
var
|
|
2833
|
-
var
|
|
2834
|
-
var
|
|
2835
|
-
var
|
|
2836
|
-
var
|
|
2679
|
+
var client2 = createReadSeekClient(runner);
|
|
2680
|
+
var readSeekShowContent = client2.showContent;
|
|
2681
|
+
var readSeekShowStructure = client2.showStructure;
|
|
2682
|
+
var readSeekShowMetadata = client2.showMetadata;
|
|
2683
|
+
var readSeekShowAssets = client2.showAssets;
|
|
2684
|
+
var readSeekGenerateCaption = client2.generateCaption;
|
|
2685
|
+
var readSeekDetectObjects = client2.detectObjects;
|
|
2686
|
+
var readSeekRecognizeText = client2.recognizeText;
|
|
2687
|
+
var readSeekFindNodes = client2.findNodes;
|
|
2688
|
+
var readSeekFindReferences = client2.findReferences;
|
|
2689
|
+
var readSeekFindDefinitions = client2.findDefinitions;
|
|
2690
|
+
var readSeekCheckSyntax = client2.checkSyntax;
|
|
2691
|
+
var readSeekCheckRules = client2.checkRules;
|
|
2692
|
+
var readSeekEditText = client2.editText;
|
|
2693
|
+
var readSeekRenameSymbol = client2.renameSymbol;
|
|
2837
2694
|
async function readSeekMap(filePath, options = {}) {
|
|
2838
|
-
const envelope = await
|
|
2839
|
-
|
|
2840
|
-
depth: DEFAULT_INSPECT_MAP_DEPTH,
|
|
2841
|
-
signal: options.signal
|
|
2842
|
-
});
|
|
2843
|
-
const map = envelope.map;
|
|
2695
|
+
const envelope = await client2.showStructure(filePath, { depth: DEFAULT_STRUCTURE_DEPTH, signal: options.signal });
|
|
2696
|
+
const map = "structure" in envelope ? envelope.structure : undefined;
|
|
2844
2697
|
if (!map || map.language === "unknown" && map.symbols.length === 0)
|
|
2845
2698
|
return null;
|
|
2846
2699
|
return map;
|
|
@@ -2865,8 +2718,8 @@ async function validateSyntaxRegression(input, options = {}) {
|
|
|
2865
2718
|
let before;
|
|
2866
2719
|
let after;
|
|
2867
2720
|
try {
|
|
2868
|
-
before = input.before === undefined ? EMPTY : await
|
|
2869
|
-
after = await
|
|
2721
|
+
before = input.before === undefined ? EMPTY : await readSeekCheckSyntax("-", { stdinName: input.filePath, stdin: input.before, signal: options.signal });
|
|
2722
|
+
after = await readSeekCheckSyntax("-", { stdinName: input.filePath, stdin: input.after, signal: options.signal });
|
|
2870
2723
|
} catch {
|
|
2871
2724
|
return null;
|
|
2872
2725
|
}
|
|
@@ -3552,7 +3405,7 @@ async function executeEdit(opts) {
|
|
|
3552
3405
|
return await withFileMutationQueue(absolutePath, async () => {
|
|
3553
3406
|
throwIfAborted(signal);
|
|
3554
3407
|
if (wasReadInSession && !wasReadInSession(absolutePath)) {
|
|
3555
|
-
const hint = `Call
|
|
3408
|
+
const hint = `Call readSeek_show_content(${JSON.stringify(rawPath)}) first, or use readSeek_find_text, readSeek_find_nodes, or readSeek_write_file to produce fresh anchors for this file.`;
|
|
3556
3409
|
return buildEditError(absolutePath, "file-not-read", `You must get fresh anchors for ${absolutePath} before editing it. ${hint}`, hint);
|
|
3557
3410
|
}
|
|
3558
3411
|
const parsedEdits = validateExactlyOneEditVariant(parsed.edits ?? []);
|
|
@@ -3562,7 +3415,7 @@ async function executeEdit(opts) {
|
|
|
3562
3415
|
const edits = parsedEdits.edits;
|
|
3563
3416
|
let plan;
|
|
3564
3417
|
try {
|
|
3565
|
-
plan = await
|
|
3418
|
+
plan = await readSeekEditText(absolutePath, edits, { signal, language: parsed.language });
|
|
3566
3419
|
} catch (err) {
|
|
3567
3420
|
throwIfAborted(signal);
|
|
3568
3421
|
const failure = classifyReadSeekFailure(err);
|
|
@@ -3598,7 +3451,7 @@ async function executeEdit(opts) {
|
|
|
3598
3451
|
throwIfAborted(signal);
|
|
3599
3452
|
let applied;
|
|
3600
3453
|
try {
|
|
3601
|
-
applied = await
|
|
3454
|
+
applied = await readSeekEditText(absolutePath, edits, {
|
|
3602
3455
|
apply: true,
|
|
3603
3456
|
planHash: plan.plan_hash,
|
|
3604
3457
|
language: parsed.language,
|
|
@@ -3666,9 +3519,9 @@ async function executeEdit(opts) {
|
|
|
3666
3519
|
}
|
|
3667
3520
|
}
|
|
3668
3521
|
function registerEditTool(pi, options = {}) {
|
|
3669
|
-
const name = options.name ?? "
|
|
3522
|
+
const name = options.name ?? "readSeek_edit_text";
|
|
3670
3523
|
const promptMetadata = defineToolPromptMetadata({
|
|
3671
|
-
promptUrl: new URL("../prompts/
|
|
3524
|
+
promptUrl: new URL("../prompts/edit_text.md", import.meta.url),
|
|
3672
3525
|
promptSnippet: "Edit existing files with fresh LINE:HASH anchors",
|
|
3673
3526
|
registeredName: name,
|
|
3674
3527
|
toolAliases: options.toolAliases
|
|
@@ -3765,7 +3618,7 @@ ${theme.fg("error", info.errorText)}`;
|
|
|
3765
3618
|
|
|
3766
3619
|
// src/grep.ts
|
|
3767
3620
|
import { readFile as fsReadFile2, stat as fsStat } from "node:fs/promises";
|
|
3768
|
-
import
|
|
3621
|
+
import path4 from "node:path";
|
|
3769
3622
|
import { createGrepTool } from "@earendil-works/pi-coding-agent";
|
|
3770
3623
|
import { Type as Type5 } from "@sinclair/typebox";
|
|
3771
3624
|
import { Text as Text4 } from "@earendil-works/pi-tui";
|
|
@@ -4135,7 +3988,7 @@ function formatGrepResultText(input) {
|
|
|
4135
3988
|
|
|
4136
3989
|
// src/coerce-obvious-int.ts
|
|
4137
3990
|
import {
|
|
4138
|
-
coerceObviousBase10Int
|
|
3991
|
+
coerceObviousBase10Int
|
|
4139
3992
|
} from "@jarkkojs/readseek-api";
|
|
4140
3993
|
|
|
4141
3994
|
// src/tui-source-render.ts
|
|
@@ -4255,21 +4108,21 @@ async function executeGrep(opts) {
|
|
|
4255
4108
|
const { toolCallId, params, signal, onUpdate, cwd, onFileAnchored } = opts;
|
|
4256
4109
|
await ensureHashInit();
|
|
4257
4110
|
const rawParams = params;
|
|
4258
|
-
const context =
|
|
4111
|
+
const context = coerceObviousBase10Int(rawParams.context, "context");
|
|
4259
4112
|
if (!context.ok) {
|
|
4260
4113
|
return buildToolErrorResult("grep", "invalid-params-combo", context.message);
|
|
4261
4114
|
}
|
|
4262
4115
|
if (context.value !== undefined && context.value < 0) {
|
|
4263
4116
|
return buildToolErrorResult("grep", "invalid-params-combo", `Invalid context: expected a non-negative integer, received ${context.value}.`);
|
|
4264
4117
|
}
|
|
4265
|
-
const limit =
|
|
4118
|
+
const limit = coerceObviousBase10Int(rawParams.limit, "limit");
|
|
4266
4119
|
if (!limit.ok) {
|
|
4267
4120
|
return buildToolErrorResult("grep", "invalid-limit", limit.message);
|
|
4268
4121
|
}
|
|
4269
4122
|
if (limit.value !== undefined && limit.value < 1) {
|
|
4270
4123
|
return buildToolErrorResult("grep", "invalid-limit", `Invalid limit: expected a positive integer, received ${limit.value}.`);
|
|
4271
4124
|
}
|
|
4272
|
-
const scopeContext =
|
|
4125
|
+
const scopeContext = coerceObviousBase10Int(rawParams.scopeContext, "scopeContext");
|
|
4273
4126
|
if (!scopeContext.ok) {
|
|
4274
4127
|
return buildToolErrorResult("grep", "invalid-params-combo", scopeContext.message);
|
|
4275
4128
|
}
|
|
@@ -4351,7 +4204,7 @@ async function executeGrep(opts) {
|
|
|
4351
4204
|
};
|
|
4352
4205
|
const toAbsolutePath = (displayPath) => {
|
|
4353
4206
|
if (searchPathIsDirectory)
|
|
4354
|
-
return
|
|
4207
|
+
return path4.resolve(searchPath, displayPath);
|
|
4355
4208
|
return searchPath;
|
|
4356
4209
|
};
|
|
4357
4210
|
const groupsByPath = new Map;
|
|
@@ -4539,9 +4392,9 @@ ${warning}` } : item),
|
|
|
4539
4392
|
};
|
|
4540
4393
|
}
|
|
4541
4394
|
function registerGrepTool(pi, options = {}) {
|
|
4542
|
-
const name = options.name ?? "
|
|
4395
|
+
const name = options.name ?? "readSeek_find_text";
|
|
4543
4396
|
const promptMetadata = defineToolPromptMetadata({
|
|
4544
|
-
promptUrl: new URL("../prompts/
|
|
4397
|
+
promptUrl: new URL("../prompts/find_text.md", import.meta.url),
|
|
4545
4398
|
promptSnippet: "Search text or regex with edit-ready LINE:HASH anchors",
|
|
4546
4399
|
registeredName: name
|
|
4547
4400
|
});
|
|
@@ -4628,7 +4481,7 @@ function registerGrepTool(pi, options = {}) {
|
|
|
4628
4481
|
}
|
|
4629
4482
|
|
|
4630
4483
|
// src/search.ts
|
|
4631
|
-
import
|
|
4484
|
+
import path5 from "node:path";
|
|
4632
4485
|
import { Type as Type6 } from "@sinclair/typebox";
|
|
4633
4486
|
|
|
4634
4487
|
// src/stat-search-path.ts
|
|
@@ -4687,7 +4540,7 @@ function mergeRanges(ranges) {
|
|
|
4687
4540
|
return merged;
|
|
4688
4541
|
}
|
|
4689
4542
|
var SEARCH_PROMPT_METADATA = defineToolPromptMetadata({
|
|
4690
|
-
promptUrl: new URL("../prompts/
|
|
4543
|
+
promptUrl: new URL("../prompts/find_nodes.md", import.meta.url),
|
|
4691
4544
|
promptSnippet: "Search code by AST structure using ast-grep-style patterns"
|
|
4692
4545
|
});
|
|
4693
4546
|
function linesFromSearchResult(result, ranges) {
|
|
@@ -4713,7 +4566,7 @@ function linesFromSearchResult(result, ranges) {
|
|
|
4713
4566
|
return lines;
|
|
4714
4567
|
}
|
|
4715
4568
|
function readSeekLanguageForPath(language, searchPath, isFile) {
|
|
4716
|
-
if (language === "typescript" && isFile &&
|
|
4569
|
+
if (language === "typescript" && isFile && path5.extname(searchPath).toLowerCase() === ".tsx")
|
|
4717
4570
|
return "tsx";
|
|
4718
4571
|
return language;
|
|
4719
4572
|
}
|
|
@@ -4727,13 +4580,18 @@ async function executeSearch(opts) {
|
|
|
4727
4580
|
const searchPathIsFile = statResult.stats.isFile();
|
|
4728
4581
|
try {
|
|
4729
4582
|
const effectiveLang = readSeekLanguageForPath(p.language, searchPath, searchPathIsFile);
|
|
4730
|
-
const results = await
|
|
4583
|
+
const results = await readSeekFindNodes(searchPath, {
|
|
4584
|
+
pattern: p.pattern,
|
|
4585
|
+
context: p.context,
|
|
4586
|
+
selector: p.selector,
|
|
4587
|
+
rule: p.rule,
|
|
4588
|
+
limit: p.limit,
|
|
4731
4589
|
language: effectiveLang,
|
|
4732
4590
|
gitScope: p.gitScope,
|
|
4733
4591
|
signal
|
|
4734
4592
|
});
|
|
4735
4593
|
if (results.length === 0) {
|
|
4736
|
-
const emptyOutput = buildSearchOutput({ pattern: p.pattern, files: [] });
|
|
4594
|
+
const emptyOutput = buildSearchOutput({ pattern: p.pattern ?? p.context ?? p.rule ?? "", files: [] });
|
|
4737
4595
|
return {
|
|
4738
4596
|
content: [{ type: "text", text: emptyOutput.text }],
|
|
4739
4597
|
details: {
|
|
@@ -4743,8 +4601,8 @@ async function executeSearch(opts) {
|
|
|
4743
4601
|
}
|
|
4744
4602
|
const readSeekFiles = [];
|
|
4745
4603
|
for (const result of results) {
|
|
4746
|
-
const abs =
|
|
4747
|
-
const display =
|
|
4604
|
+
const abs = path5.isAbsolute(result.file) ? result.file : path5.resolve(cwd, result.file);
|
|
4605
|
+
const display = path5.relative(cwd, abs) || abs;
|
|
4748
4606
|
const ranges = result.matches.map((match) => ({ startLine: match.start_line, endLine: match.end_line }));
|
|
4749
4607
|
const mergedRanges = mergeRanges(ranges);
|
|
4750
4608
|
const lines = linesFromSearchResult(result, mergedRanges);
|
|
@@ -4758,7 +4616,7 @@ async function executeSearch(opts) {
|
|
|
4758
4616
|
});
|
|
4759
4617
|
}
|
|
4760
4618
|
if (readSeekFiles.length === 0) {
|
|
4761
|
-
const emptyOutput = buildSearchOutput({ pattern: p.pattern, files: [] });
|
|
4619
|
+
const emptyOutput = buildSearchOutput({ pattern: p.pattern ?? p.rule ?? "", files: [] });
|
|
4762
4620
|
return {
|
|
4763
4621
|
content: [{ type: "text", text: emptyOutput.text }],
|
|
4764
4622
|
details: {
|
|
@@ -4767,7 +4625,7 @@ async function executeSearch(opts) {
|
|
|
4767
4625
|
};
|
|
4768
4626
|
}
|
|
4769
4627
|
const builtOutput = buildSearchOutput({
|
|
4770
|
-
pattern: p.pattern,
|
|
4628
|
+
pattern: p.pattern ?? p.rule ?? "",
|
|
4771
4629
|
files: readSeekFiles
|
|
4772
4630
|
});
|
|
4773
4631
|
for (const readSeekFile of readSeekFiles) {
|
|
@@ -4786,14 +4644,18 @@ async function executeSearch(opts) {
|
|
|
4786
4644
|
}
|
|
4787
4645
|
function registerSearchTool(pi, options = {}) {
|
|
4788
4646
|
const tool = registerReadSeekTool(pi, {
|
|
4789
|
-
name: "
|
|
4647
|
+
name: "readSeek_find_nodes",
|
|
4790
4648
|
label: "Structural Search",
|
|
4791
4649
|
description: SEARCH_PROMPT_METADATA.description,
|
|
4792
4650
|
promptSnippet: SEARCH_PROMPT_METADATA.promptSnippet,
|
|
4793
4651
|
promptGuidelines: SEARCH_PROMPT_METADATA.promptGuidelines,
|
|
4794
4652
|
parameters: Type6.Object({
|
|
4795
|
-
pattern: Type6.String({ description: PARAM_DESCRIPTIONS.pattern }),
|
|
4653
|
+
pattern: Type6.Optional(Type6.String({ description: PARAM_DESCRIPTIONS.pattern })),
|
|
4654
|
+
context: Type6.Optional(Type6.String({ description: PARAM_DESCRIPTIONS.patternContext })),
|
|
4655
|
+
selector: Type6.Optional(Type6.String({ description: PARAM_DESCRIPTIONS.selector })),
|
|
4796
4656
|
language: languageParam(),
|
|
4657
|
+
rule: Type6.Optional(Type6.String({ description: PARAM_DESCRIPTIONS.rule })),
|
|
4658
|
+
limit: Type6.Optional(Type6.Integer({ minimum: 1 })),
|
|
4797
4659
|
path: searchPathParam(),
|
|
4798
4660
|
...readSeekGitSearchParams()
|
|
4799
4661
|
}),
|
|
@@ -4803,7 +4665,7 @@ function registerSearchTool(pi, options = {}) {
|
|
|
4803
4665
|
renderCall(args, theme, ...rest) {
|
|
4804
4666
|
return renderReadSeekSearchCall(args, theme, rest, {
|
|
4805
4667
|
label: "search",
|
|
4806
|
-
accent: `/${args.pattern}/`,
|
|
4668
|
+
accent: `/${args.pattern ?? args.context ?? args.rule}/`,
|
|
4807
4669
|
flags: [args.gitScope && `git-scope=${args.gitScope}`]
|
|
4808
4670
|
});
|
|
4809
4671
|
},
|
|
@@ -4821,15 +4683,14 @@ function registerSearchTool(pi, options = {}) {
|
|
|
4821
4683
|
|
|
4822
4684
|
// src/refs.ts
|
|
4823
4685
|
import { Type as Type7 } from "@sinclair/typebox";
|
|
4824
|
-
import
|
|
4686
|
+
import path6 from "node:path";
|
|
4825
4687
|
|
|
4826
4688
|
// src/refs-output.ts
|
|
4827
4689
|
function refsQueryLabel(input) {
|
|
4828
4690
|
if (input.name)
|
|
4829
4691
|
return input.name;
|
|
4830
|
-
if (input.
|
|
4831
|
-
return input.
|
|
4832
|
-
}
|
|
4692
|
+
if (input.at)
|
|
4693
|
+
return input.at;
|
|
4833
4694
|
return "?";
|
|
4834
4695
|
}
|
|
4835
4696
|
function buildRefsOutput(input) {
|
|
@@ -4853,7 +4714,7 @@ function buildRefsOutput(input) {
|
|
|
4853
4714
|
|
|
4854
4715
|
// src/refs.ts
|
|
4855
4716
|
var REFS_PROMPT_METADATA = defineToolPromptMetadata({
|
|
4856
|
-
promptUrl: new URL("../prompts/
|
|
4717
|
+
promptUrl: new URL("../prompts/find_references.md", import.meta.url),
|
|
4857
4718
|
promptSnippet: "Find references by identifier name or cursor binding"
|
|
4858
4719
|
});
|
|
4859
4720
|
function refsLine(reference) {
|
|
@@ -4866,14 +4727,14 @@ function groupReferences(references, cwd) {
|
|
|
4866
4727
|
const files = new Map;
|
|
4867
4728
|
const seen = new Set;
|
|
4868
4729
|
for (const reference of references) {
|
|
4869
|
-
const abs =
|
|
4730
|
+
const abs = path6.isAbsolute(reference.file) ? reference.file : path6.resolve(cwd, reference.file);
|
|
4870
4731
|
const dedupeKey = `${abs}:${reference.line}:${reference.column}`;
|
|
4871
4732
|
if (seen.has(dedupeKey))
|
|
4872
4733
|
continue;
|
|
4873
4734
|
seen.add(dedupeKey);
|
|
4874
4735
|
let file = files.get(abs);
|
|
4875
4736
|
if (!file) {
|
|
4876
|
-
file = { displayPath:
|
|
4737
|
+
file = { displayPath: path6.relative(cwd, abs) || abs, path: abs, lines: [] };
|
|
4877
4738
|
files.set(abs, file);
|
|
4878
4739
|
}
|
|
4879
4740
|
file.lines.push(refsLine(reference));
|
|
@@ -4886,7 +4747,7 @@ function isReadSeekCursorValidationFailure(message) {
|
|
|
4886
4747
|
async function executeRefs(opts) {
|
|
4887
4748
|
const { params, signal, cwd, onFileAnchored } = opts;
|
|
4888
4749
|
const p = params;
|
|
4889
|
-
const scopeError =
|
|
4750
|
+
const scopeError = validateReferencesSelection(p);
|
|
4890
4751
|
if (!scopeError.ok) {
|
|
4891
4752
|
return buildToolErrorResult("refs", "invalid-parameter", `refs parameter: ${scopeError.error}`);
|
|
4892
4753
|
}
|
|
@@ -4895,11 +4756,9 @@ async function executeRefs(opts) {
|
|
|
4895
4756
|
if (!statResult.ok)
|
|
4896
4757
|
return statResult.error;
|
|
4897
4758
|
try {
|
|
4898
|
-
const references = await
|
|
4759
|
+
const references = await readSeekFindReferences(searchPath, {
|
|
4899
4760
|
name: p.name,
|
|
4900
|
-
|
|
4901
|
-
line: p.line,
|
|
4902
|
-
column: p.column,
|
|
4761
|
+
at: p.at,
|
|
4903
4762
|
language: p.language,
|
|
4904
4763
|
gitScope: p.gitScope,
|
|
4905
4764
|
signal
|
|
@@ -4907,9 +4766,7 @@ async function executeRefs(opts) {
|
|
|
4907
4766
|
const files = groupReferences(references, cwd);
|
|
4908
4767
|
const builtOutput = buildRefsOutput({
|
|
4909
4768
|
name: p.name,
|
|
4910
|
-
|
|
4911
|
-
line: p.line,
|
|
4912
|
-
column: p.column,
|
|
4769
|
+
at: p.at,
|
|
4913
4770
|
files
|
|
4914
4771
|
});
|
|
4915
4772
|
for (const file of files) {
|
|
@@ -4921,7 +4778,7 @@ async function executeRefs(opts) {
|
|
|
4921
4778
|
};
|
|
4922
4779
|
} catch (err) {
|
|
4923
4780
|
const failure = classifyReadSeekFailure(err);
|
|
4924
|
-
if (p.
|
|
4781
|
+
if (p.at && isReadSeekCursorValidationFailure(failure.message)) {
|
|
4925
4782
|
return buildToolErrorResult("refs", "invalid-parameter", failure.message);
|
|
4926
4783
|
}
|
|
4927
4784
|
return buildToolErrorResult("refs", failure.code, failure.message, failure.hint ? { hint: failure.hint } : {});
|
|
@@ -4929,7 +4786,7 @@ async function executeRefs(opts) {
|
|
|
4929
4786
|
}
|
|
4930
4787
|
function registerRefsTool(pi, options = {}) {
|
|
4931
4788
|
const tool = registerReadSeekTool(pi, {
|
|
4932
|
-
name: "
|
|
4789
|
+
name: "readSeek_find_references",
|
|
4933
4790
|
label: "References",
|
|
4934
4791
|
description: REFS_PROMPT_METADATA.description,
|
|
4935
4792
|
promptSnippet: REFS_PROMPT_METADATA.promptSnippet,
|
|
@@ -4938,20 +4795,18 @@ function registerRefsTool(pi, options = {}) {
|
|
|
4938
4795
|
name: Type7.Optional(Type7.String({ description: PARAM_DESCRIPTIONS.refsName })),
|
|
4939
4796
|
path: searchPathParam(),
|
|
4940
4797
|
language: languageParam(),
|
|
4941
|
-
|
|
4942
|
-
line: Type7.Optional(Type7.Number({ description: PARAM_DESCRIPTIONS.line })),
|
|
4943
|
-
column: Type7.Optional(Type7.Number({ description: PARAM_DESCRIPTIONS.column })),
|
|
4798
|
+
at: Type7.Optional(Type7.String({ description: PARAM_DESCRIPTIONS.at })),
|
|
4944
4799
|
...readSeekGitSearchParams()
|
|
4945
4800
|
}),
|
|
4946
4801
|
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
4947
4802
|
return executeRefs({ params, signal, cwd: ctx.cwd, onFileAnchored: options.onFileAnchored });
|
|
4948
4803
|
},
|
|
4949
4804
|
renderCall(args, theme, ...rest) {
|
|
4950
|
-
const accent = args.name ??
|
|
4805
|
+
const accent = args.name ?? args.at ?? "?";
|
|
4951
4806
|
return renderReadSeekSearchCall(args, theme, rest, {
|
|
4952
4807
|
label: "refs",
|
|
4953
4808
|
accent,
|
|
4954
|
-
flags: [args.
|
|
4809
|
+
flags: [args.at && "binding", args.gitScope && `git-scope=${args.gitScope}`]
|
|
4955
4810
|
});
|
|
4956
4811
|
},
|
|
4957
4812
|
renderResult(result, options, theme, ...rest) {
|
|
@@ -4968,16 +4823,15 @@ function registerRefsTool(pi, options = {}) {
|
|
|
4968
4823
|
|
|
4969
4824
|
// src/rename.ts
|
|
4970
4825
|
import { Type as Type8 } from "@sinclair/typebox";
|
|
4971
|
-
import
|
|
4826
|
+
import path7 from "node:path";
|
|
4972
4827
|
import { Text as Text5 } from "@earendil-works/pi-tui";
|
|
4973
4828
|
var RENAME_PROMPT_METADATA = defineToolPromptMetadata({
|
|
4974
|
-
promptUrl: new URL("../prompts/
|
|
4829
|
+
promptUrl: new URL("../prompts/rename_symbol.md", import.meta.url),
|
|
4975
4830
|
promptSnippet: "Rename a symbol at a source location with verified edits"
|
|
4976
4831
|
});
|
|
4977
4832
|
var renameSchema = Type8.Object({
|
|
4978
4833
|
path: filePathParam(),
|
|
4979
|
-
|
|
4980
|
-
column: Type8.Optional(Type8.Integer({ minimum: 1, description: PARAM_DESCRIPTIONS.column })),
|
|
4834
|
+
at: Type8.String({ description: PARAM_DESCRIPTIONS.at }),
|
|
4981
4835
|
to: Type8.String({ description: PARAM_DESCRIPTIONS.to }),
|
|
4982
4836
|
workspace: Type8.Optional(Type8.Boolean({ description: PARAM_DESCRIPTIONS.workspace })),
|
|
4983
4837
|
apply: Type8.Optional(Type8.Boolean({ description: PARAM_DESCRIPTIONS.applyDefaultTrue }))
|
|
@@ -4988,18 +4842,14 @@ async function executeRename(opts) {
|
|
|
4988
4842
|
if (!p.to.trim()) {
|
|
4989
4843
|
return buildToolErrorResult("rename", "invalid-parameter", "rename parameter 'to' must not be empty");
|
|
4990
4844
|
}
|
|
4991
|
-
if (
|
|
4992
|
-
return buildToolErrorResult("
|
|
4993
|
-
}
|
|
4994
|
-
if (p.column !== undefined && (!Number.isSafeInteger(p.column) || p.column < 1)) {
|
|
4995
|
-
return buildToolErrorResult("rename", "invalid-parameter", "rename parameter 'column' must be a positive integer");
|
|
4845
|
+
if (typeof p.at !== "string" || !/^(line:[1-9][0-9]*|hash:[0-9a-fA-F]+)(:[1-9][0-9]*)?$/.test(p.at)) {
|
|
4846
|
+
return buildToolErrorResult("rename_symbol", "invalid-parameter", "at must be a line or hash location with an optional positive column");
|
|
4996
4847
|
}
|
|
4997
4848
|
const filePath = resolveToCwd2(p.path, cwd);
|
|
4998
4849
|
try {
|
|
4999
|
-
const output = await
|
|
4850
|
+
const output = await readSeekRenameSymbol(filePath, {
|
|
5000
4851
|
to: p.to,
|
|
5001
|
-
|
|
5002
|
-
column: p.column,
|
|
4852
|
+
at: p.at,
|
|
5003
4853
|
workspace: p.workspace ? cwd : undefined,
|
|
5004
4854
|
apply: p.apply ?? true,
|
|
5005
4855
|
signal
|
|
@@ -5008,14 +4858,14 @@ async function executeRename(opts) {
|
|
|
5008
4858
|
for (const file of [output, ...output.others]) {
|
|
5009
4859
|
if (file.edits.length === 0)
|
|
5010
4860
|
continue;
|
|
5011
|
-
const absoluteFile =
|
|
4861
|
+
const absoluteFile = path7.isAbsolute(file.file) ? file.file : path7.resolve(cwd, file.file);
|
|
5012
4862
|
onFileMutated?.(absoluteFile);
|
|
5013
4863
|
}
|
|
5014
4864
|
}
|
|
5015
|
-
const primaryAbs =
|
|
4865
|
+
const primaryAbs = path7.isAbsolute(output.file) ? output.file : path7.resolve(cwd, output.file);
|
|
5016
4866
|
const files = [primaryAbs];
|
|
5017
4867
|
for (const other of output.others) {
|
|
5018
|
-
const abs =
|
|
4868
|
+
const abs = path7.isAbsolute(other.file) ? other.file : path7.resolve(cwd, other.file);
|
|
5019
4869
|
if (!files.includes(abs))
|
|
5020
4870
|
files.push(abs);
|
|
5021
4871
|
}
|
|
@@ -5054,7 +4904,7 @@ First conflict at ${firstConflict.line}:${firstConflict.column}: ${firstConflict
|
|
|
5054
4904
|
}
|
|
5055
4905
|
function registerRenameTool(pi, options = {}) {
|
|
5056
4906
|
registerReadSeekTool(pi, {
|
|
5057
|
-
name: "
|
|
4907
|
+
name: "readSeek_rename_symbol",
|
|
5058
4908
|
label: "Rename",
|
|
5059
4909
|
description: RENAME_PROMPT_METADATA.description,
|
|
5060
4910
|
promptSnippet: RENAME_PROMPT_METADATA.promptSnippet,
|
|
@@ -5097,7 +4947,7 @@ function registerRenameTool(pi, options = {}) {
|
|
|
5097
4947
|
});
|
|
5098
4948
|
if (expanded && output) {
|
|
5099
4949
|
for (const file of outputs) {
|
|
5100
|
-
const display =
|
|
4950
|
+
const display = path7.relative(cwd, file.file) || file.file;
|
|
5101
4951
|
text += `
|
|
5102
4952
|
${linkedPathLine(theme, file.file, display, cwd, ` (${file.edits.length} edits)`, width)}`;
|
|
5103
4953
|
}
|
|
@@ -5320,7 +5170,7 @@ async function executeWrite(opts) {
|
|
|
5320
5170
|
const warnings = [];
|
|
5321
5171
|
const readSeekWarnings = [];
|
|
5322
5172
|
if (hasBareCarriageReturn(content)) {
|
|
5323
|
-
const message = "File content contains bare CR (\\r) line endings;
|
|
5173
|
+
const message = "File content contains bare CR (\\r) line endings; readSeek_write_file refuses to emit anchors that readSeek_show_content/readSeek_edit_text would normalize differently.";
|
|
5324
5174
|
warnings.push(message);
|
|
5325
5175
|
readSeekWarnings.push(buildReadSeekWarning("bare-cr", message));
|
|
5326
5176
|
return buildToolErrorResult("write", "bare-cr", `Cannot write ${filePath}
|
|
@@ -5399,9 +5249,9 @@ async function executeWrite(opts) {
|
|
|
5399
5249
|
};
|
|
5400
5250
|
}
|
|
5401
5251
|
function registerWriteTool(pi, options = {}) {
|
|
5402
|
-
const name = options.name ?? "
|
|
5252
|
+
const name = options.name ?? "readSeek_write_file";
|
|
5403
5253
|
const promptMetadata = defineToolPromptMetadata({
|
|
5404
|
-
promptUrl: new URL("../prompts/
|
|
5254
|
+
promptUrl: new URL("../prompts/write_file.md", import.meta.url),
|
|
5405
5255
|
promptSnippet: "Create or replace a complete file with LINE:HASH anchors",
|
|
5406
5256
|
registeredName: name
|
|
5407
5257
|
});
|
|
@@ -5513,23 +5363,23 @@ function registerWriteTool(pi, options = {}) {
|
|
|
5513
5363
|
|
|
5514
5364
|
// src/def.ts
|
|
5515
5365
|
import { Type as Type10 } from "@sinclair/typebox";
|
|
5516
|
-
import
|
|
5366
|
+
import path8 from "node:path";
|
|
5517
5367
|
var DEF_PROMPT_METADATA = defineToolPromptMetadata({
|
|
5518
|
-
promptUrl: new URL("../prompts/
|
|
5368
|
+
promptUrl: new URL("../prompts/find_definitions.md", import.meta.url),
|
|
5519
5369
|
promptSnippet: "Go to a symbol definition or declaration by name"
|
|
5520
5370
|
});
|
|
5521
5371
|
async function executeDef(opts) {
|
|
5522
5372
|
const { params, signal, cwd, onFileAnchored } = opts;
|
|
5523
5373
|
const p = params;
|
|
5524
5374
|
if (!p.name || !p.name.trim()) {
|
|
5525
|
-
return buildToolErrorResult("def", "invalid-parameter", "
|
|
5375
|
+
return buildToolErrorResult("def", "invalid-parameter", "readSeek_find_definitions requires 'name'");
|
|
5526
5376
|
}
|
|
5527
5377
|
const searchPath = resolveToCwd2(p.path ?? ".", cwd);
|
|
5528
5378
|
const statResult = await statSearchPathOrError("def", p.path, searchPath);
|
|
5529
5379
|
if (!statResult.ok)
|
|
5530
5380
|
return statResult.error;
|
|
5531
5381
|
try {
|
|
5532
|
-
const definitions = await
|
|
5382
|
+
const definitions = await readSeekFindDefinitions(searchPath, {
|
|
5533
5383
|
name: p.name,
|
|
5534
5384
|
language: p.language,
|
|
5535
5385
|
gitScope: p.gitScope,
|
|
@@ -5545,10 +5395,10 @@ async function executeDef(opts) {
|
|
|
5545
5395
|
}
|
|
5546
5396
|
const files = new Map;
|
|
5547
5397
|
for (const def of definitions) {
|
|
5548
|
-
const abs =
|
|
5398
|
+
const abs = path8.isAbsolute(def.file) ? def.file : path8.resolve(cwd, def.file);
|
|
5549
5399
|
let file = files.get(abs);
|
|
5550
5400
|
if (!file) {
|
|
5551
|
-
file = { displayPath:
|
|
5401
|
+
file = { displayPath: path8.relative(cwd, abs) || abs, path: abs, lines: [] };
|
|
5552
5402
|
files.set(abs, file);
|
|
5553
5403
|
}
|
|
5554
5404
|
file.lines.push(buildReadSeekLineWithHash(def.line, def.line_hash, def.text));
|
|
@@ -5578,7 +5428,7 @@ async function executeDef(opts) {
|
|
|
5578
5428
|
}
|
|
5579
5429
|
function registerDefTool(pi, options = {}) {
|
|
5580
5430
|
registerReadSeekTool(pi, {
|
|
5581
|
-
name: "
|
|
5431
|
+
name: "readSeek_find_definitions",
|
|
5582
5432
|
label: "Definition",
|
|
5583
5433
|
description: DEF_PROMPT_METADATA.description,
|
|
5584
5434
|
promptSnippet: DEF_PROMPT_METADATA.promptSnippet,
|
|
@@ -5610,379 +5460,120 @@ function registerDefTool(pi, options = {}) {
|
|
|
5610
5460
|
});
|
|
5611
5461
|
}
|
|
5612
5462
|
|
|
5613
|
-
// src/
|
|
5463
|
+
// src/access.ts
|
|
5614
5464
|
import { Text as Text7 } from "@earendil-works/pi-tui";
|
|
5615
5465
|
import { Type as Type11 } from "@sinclair/typebox";
|
|
5616
|
-
|
|
5617
|
-
var
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
language: Type11.Optional(Type11.String({ description: PARAM_DESCRIPTIONS.languageOverride })),
|
|
5630
|
-
visionMode: Type11.Optional(Type11.Union(VISION_MODES.map((mode) => Type11.Literal(mode)), { description: PARAM_DESCRIPTIONS.visionModeInspect })),
|
|
5631
|
-
visionLevel: Type11.Optional(Type11.Union(VISION_LEVELS.map((level) => Type11.Literal(level)), { description: PARAM_DESCRIPTIONS.visionLevel }))
|
|
5632
|
-
});
|
|
5633
|
-
function hasInspectAnchors(value) {
|
|
5466
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
5467
|
+
var operations = {
|
|
5468
|
+
show_content: readSeekShowContent,
|
|
5469
|
+
show_structure: readSeekShowStructure,
|
|
5470
|
+
show_metadata: readSeekShowMetadata,
|
|
5471
|
+
show_assets: readSeekShowAssets,
|
|
5472
|
+
check_syntax: readSeekCheckSyntax,
|
|
5473
|
+
check_rules: readSeekCheckRules,
|
|
5474
|
+
generate_caption: readSeekGenerateCaption,
|
|
5475
|
+
detect_objects: readSeekDetectObjects,
|
|
5476
|
+
recognize_text: readSeekRecognizeText
|
|
5477
|
+
};
|
|
5478
|
+
function hasAnchors(value) {
|
|
5634
5479
|
if (!value || typeof value !== "object")
|
|
5635
5480
|
return false;
|
|
5636
5481
|
const record = value;
|
|
5637
5482
|
if (Array.isArray(record.hashlines) && record.hashlines.length > 0)
|
|
5638
5483
|
return true;
|
|
5639
|
-
return Object.values(record).some(
|
|
5640
|
-
}
|
|
5641
|
-
function parseSelect(select) {
|
|
5642
|
-
if (select === undefined)
|
|
5643
|
-
return;
|
|
5644
|
-
if (Array.isArray(select)) {
|
|
5645
|
-
const facets = select;
|
|
5646
|
-
if (facets.length === 0)
|
|
5647
|
-
throw new Error("select must include at least one facet");
|
|
5648
|
-
for (const facet of facets) {
|
|
5649
|
-
if (!INSPECT_FACETS.includes(facet)) {
|
|
5650
|
-
throw new Error(`unknown inspect facet \`${facet}\`; expected ${INSPECT_FACETS.join(", ")}`);
|
|
5651
|
-
}
|
|
5652
|
-
}
|
|
5653
|
-
return facets;
|
|
5654
|
-
}
|
|
5655
|
-
if (typeof select !== "string") {
|
|
5656
|
-
throw new Error("select must be a facet, facet list, or comma-separated facets");
|
|
5657
|
-
}
|
|
5658
|
-
if (INSPECT_FACETS.includes(select)) {
|
|
5659
|
-
return select;
|
|
5660
|
-
}
|
|
5661
|
-
const parts = select.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
|
|
5662
|
-
if (parts.length === 0)
|
|
5663
|
-
throw new Error("select must include at least one facet");
|
|
5664
|
-
for (const part of parts) {
|
|
5665
|
-
if (!INSPECT_FACETS.includes(part)) {
|
|
5666
|
-
throw new Error(`unknown inspect facet \`${part}\`; expected ${INSPECT_FACETS.join(", ")}`);
|
|
5667
|
-
}
|
|
5668
|
-
}
|
|
5669
|
-
return parts;
|
|
5670
|
-
}
|
|
5671
|
-
function selectedFacets(select) {
|
|
5672
|
-
if (select === undefined)
|
|
5673
|
-
return ["content"];
|
|
5674
|
-
return Array.isArray(select) ? select : [select];
|
|
5675
|
-
}
|
|
5676
|
-
function summarizeEnvelope(envelope, facets) {
|
|
5677
|
-
if (!envelope || typeof envelope !== "object")
|
|
5678
|
-
return `inspected ${facets.join(",")}`;
|
|
5679
|
-
const record = envelope;
|
|
5680
|
-
const parts = [];
|
|
5681
|
-
for (const facet of facets) {
|
|
5682
|
-
if (facet === "metadata" || record[facet] !== undefined)
|
|
5683
|
-
parts.push(facet);
|
|
5684
|
-
}
|
|
5685
|
-
if (record.metadata !== undefined && !parts.includes("metadata"))
|
|
5686
|
-
parts.unshift("metadata");
|
|
5687
|
-
return `inspected ${parts.join(",") || "metadata"}`;
|
|
5688
|
-
}
|
|
5689
|
-
function parseImageEnvelope(envelope) {
|
|
5690
|
-
if (!envelope || typeof envelope !== "object")
|
|
5691
|
-
return;
|
|
5692
|
-
const record = envelope;
|
|
5693
|
-
if (!record.metadata || typeof record.metadata !== "object")
|
|
5694
|
-
return;
|
|
5695
|
-
const metadata = record.metadata;
|
|
5696
|
-
if (typeof metadata.type !== "string" || !metadata.type.startsWith("image/"))
|
|
5697
|
-
return;
|
|
5698
|
-
if (!record.content || typeof record.content !== "object")
|
|
5699
|
-
return { metadata };
|
|
5700
|
-
const content = record.content;
|
|
5701
|
-
const mime = content.mime ?? content.type ?? metadata.mime ?? metadata.type;
|
|
5702
|
-
const prepared = content.encoding === "base64" && typeof content.data === "string" && typeof mime === "string" ? { data: content.data, mimeType: mime } : undefined;
|
|
5703
|
-
return { metadata, prepared };
|
|
5704
|
-
}
|
|
5705
|
-
function buildInspectSuccess(filePath, facets, envelope, content = [{ type: "text", text: JSON.stringify(envelope) }]) {
|
|
5706
|
-
return {
|
|
5707
|
-
content,
|
|
5708
|
-
details: {
|
|
5709
|
-
readSeekValue: {
|
|
5710
|
-
tool: "inspect",
|
|
5711
|
-
ok: true,
|
|
5712
|
-
path: filePath,
|
|
5713
|
-
select: facets,
|
|
5714
|
-
envelope
|
|
5715
|
-
}
|
|
5716
|
-
}
|
|
5717
|
-
};
|
|
5484
|
+
return Object.values(record).some(hasAnchors);
|
|
5718
5485
|
}
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
}
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
const
|
|
5746
|
-
if (!depth.ok || depth.value !== undefined && depth.value < 0) {
|
|
5747
|
-
const message = depth.ok ? `Invalid depth: expected a non-negative integer, received ${depth.value}.` : depth.message;
|
|
5748
|
-
return buildToolErrorResult("inspect", "invalid-parameter", message, { path: p.path });
|
|
5749
|
-
}
|
|
5750
|
-
if (depth.value !== undefined && !facets.includes("map")) {
|
|
5751
|
-
return buildToolErrorResult("inspect", "invalid-parameter", "depth requires the map facet.", { path: p.path });
|
|
5752
|
-
}
|
|
5753
|
-
const selector = typeof p.selector === "string" ? p.selector.trim() : undefined;
|
|
5754
|
-
if (p.selector !== undefined && !selector) {
|
|
5755
|
-
return buildToolErrorResult("inspect", "invalid-parameter", "Invalid selector: expected a non-empty selector.", { path: p.path });
|
|
5756
|
-
}
|
|
5757
|
-
const query = typeof p.query === "string" ? p.query.trim() : undefined;
|
|
5758
|
-
if (p.query !== undefined && !query) {
|
|
5759
|
-
return buildToolErrorResult("inspect", "invalid-parameter", "Invalid query: expected a non-empty query.", { path: p.path });
|
|
5760
|
-
}
|
|
5761
|
-
if (selector !== undefined && query !== undefined) {
|
|
5762
|
-
return buildToolErrorResult("inspect", "invalid-params-combo", "selector and query cannot be combined.", { path: p.path });
|
|
5763
|
-
}
|
|
5764
|
-
if (facets.includes("identity") && selector === undefined) {
|
|
5765
|
-
return buildToolErrorResult("inspect", "invalid-params-combo", "the identity facet requires a selector.", { path: p.path });
|
|
5766
|
-
}
|
|
5767
|
-
if (p.visionLevel !== undefined && (p.visionMode === undefined || p.visionMode === "none") && !appliesImagePolicy) {
|
|
5768
|
-
return buildToolErrorResult("inspect", "invalid-params-combo", "visionLevel requires an analysis visionMode.", { path: p.path });
|
|
5769
|
-
}
|
|
5770
|
-
const filePath = resolveToCwd2(p.path, cwd);
|
|
5771
|
-
const commonOptions = {
|
|
5772
|
-
select,
|
|
5773
|
-
signal,
|
|
5774
|
-
depth: depth.value ?? (facets.includes("map") ? DEFAULT_INSPECT_MAP_DEPTH : undefined)
|
|
5775
|
-
};
|
|
5776
|
-
const selectionOptions = {
|
|
5777
|
-
...commonOptions,
|
|
5778
|
-
selector,
|
|
5779
|
-
query,
|
|
5780
|
-
end: end.value,
|
|
5781
|
-
limit: limit.value,
|
|
5782
|
-
language: p.language
|
|
5783
|
-
};
|
|
5784
|
-
const probeOptions = {
|
|
5785
|
-
...commonOptions,
|
|
5786
|
-
select: [...new Set(["metadata", ...facets])].filter((facet) => facet !== "identity")
|
|
5787
|
-
};
|
|
5788
|
-
const hasSelectionOptions = selector !== undefined || query !== undefined || end.value !== undefined || limit.value !== undefined || p.language !== undefined;
|
|
5789
|
-
const hasVisionOptions = p.visionMode !== undefined || p.visionLevel !== undefined;
|
|
5790
|
-
const initialVisionMode = appliesImagePolicy ? undefined : p.visionMode;
|
|
5791
|
-
const initialVisionLevel = appliesImagePolicy ? undefined : p.visionLevel;
|
|
5486
|
+
function imagePaths(value, paths = new Map) {
|
|
5487
|
+
if (!value || typeof value !== "object")
|
|
5488
|
+
return paths;
|
|
5489
|
+
const record = value;
|
|
5490
|
+
if (typeof record.path === "string" && typeof record.mime === "string" && record.mime.startsWith("image/")) {
|
|
5491
|
+
paths.set(record.path, record.mime);
|
|
5492
|
+
}
|
|
5493
|
+
for (const child of Object.values(record))
|
|
5494
|
+
imagePaths(child, paths);
|
|
5495
|
+
return paths;
|
|
5496
|
+
}
|
|
5497
|
+
async function executeAccess(opts) {
|
|
5498
|
+
if (!opts.params || typeof opts.params !== "object" || Array.isArray(opts.params)) {
|
|
5499
|
+
return buildToolErrorResult(opts.tool, "invalid-parameter", "Expected an object");
|
|
5500
|
+
}
|
|
5501
|
+
const p = opts.params;
|
|
5502
|
+
const contract = getToolContract(opts.tool);
|
|
5503
|
+
for (const key of Object.keys(p)) {
|
|
5504
|
+
if (key === "stdinName" || !Object.hasOwn(contract.inputSchema.properties, key))
|
|
5505
|
+
return buildToolErrorResult(opts.tool, "invalid-parameter", `Unknown parameter: ${key}`);
|
|
5506
|
+
}
|
|
5507
|
+
const path = p.path === undefined && opts.tool === "check_rules" ? "." : p.path;
|
|
5508
|
+
if (typeof path !== "string" || !path.trim())
|
|
5509
|
+
return buildToolErrorResult(opts.tool, "invalid-parameter", "path is required");
|
|
5510
|
+
if (path === "-")
|
|
5511
|
+
return buildToolErrorResult(opts.tool, "invalid-parameter", "Agent tools require a file path; stdin is available through the CLI or API");
|
|
5512
|
+
const filePath = resolveToCwd2(path, opts.cwd);
|
|
5792
5513
|
try {
|
|
5793
|
-
const
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
if (
|
|
5801
|
-
const
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
return buildInspectSuccess(filePath, facets, imageDetails, [
|
|
5809
|
-
{ type: "image", data: image.prepared.data, mimeType: image.prepared.mimeType }
|
|
5810
|
-
]);
|
|
5514
|
+
const { path: _path, ...options } = p;
|
|
5515
|
+
const envelope = await operations[opts.tool](filePath, { ...options, signal: opts.signal });
|
|
5516
|
+
if (hasAnchors(envelope))
|
|
5517
|
+
opts.onFileAnchored?.(filePath);
|
|
5518
|
+
const content = [
|
|
5519
|
+
{ type: "text", text: JSON.stringify(envelope) }
|
|
5520
|
+
];
|
|
5521
|
+
if (opts.tool === "show_content" || opts.tool === "show_assets") {
|
|
5522
|
+
for (const [imagePath, mimeType] of imagePaths(envelope)) {
|
|
5523
|
+
if (opts.imageMode === "off")
|
|
5524
|
+
content.push({ type: "text", text: `Image available at ${imagePath}; image attachments are disabled by readseek.imageMode.` });
|
|
5525
|
+
else if (opts.modelSupportsImages)
|
|
5526
|
+
content.push({ type: "image", data: (await readFile2(imagePath)).toString("base64"), mimeType });
|
|
5527
|
+
else
|
|
5528
|
+
content.push({ type: "text", text: `Image available at ${imagePath}; this host model does not support image attachments.` });
|
|
5811
5529
|
}
|
|
5812
|
-
const visionMode = p.visionMode && p.visionMode !== "none" ? p.visionMode : "all";
|
|
5813
|
-
const analyzedEnvelope = await readSeekInspect(filePath, {
|
|
5814
|
-
...commonOptions,
|
|
5815
|
-
visionMode,
|
|
5816
|
-
visionLevel: p.visionLevel,
|
|
5817
|
-
vision: true
|
|
5818
|
-
});
|
|
5819
|
-
return buildInspectSuccess(filePath, facets, analyzedEnvelope);
|
|
5820
|
-
}
|
|
5821
|
-
if (p.visionLevel !== undefined && (p.visionMode === undefined || p.visionMode === "none")) {
|
|
5822
|
-
return buildToolErrorResult("inspect", "invalid-params-combo", "visionLevel requires an analysis visionMode.", {
|
|
5823
|
-
path: p.path
|
|
5824
|
-
});
|
|
5825
5530
|
}
|
|
5826
|
-
|
|
5827
|
-
...selectionOptions,
|
|
5828
|
-
visionMode: p.visionMode,
|
|
5829
|
-
visionLevel: p.visionLevel,
|
|
5830
|
-
vision: p.visionMode !== undefined && p.visionMode !== "none"
|
|
5831
|
-
}) : envelope;
|
|
5832
|
-
if (hasInspectAnchors(selectedEnvelope))
|
|
5833
|
-
onFileAnchored?.(filePath);
|
|
5834
|
-
return buildInspectSuccess(filePath, facets, selectedEnvelope);
|
|
5531
|
+
return { content, details: { readSeekValue: { tool: opts.tool, ok: true, path: filePath, envelope } } };
|
|
5835
5532
|
} catch (err) {
|
|
5836
5533
|
const failure = classifyReadSeekFailure(err);
|
|
5837
|
-
return buildToolErrorResult(
|
|
5838
|
-
}
|
|
5839
|
-
}
|
|
5840
|
-
function
|
|
5841
|
-
const
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
cwd: ctx.cwd,
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
}
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
}
|
|
5875
|
-
if (typeof args?.selector === "string" && args.selector)
|
|
5876
|
-
text += theme.fg("dim", ` @ ${args.selector}`);
|
|
5877
|
-
return new Text7(clampLineToWidth(text, context.width), 0, 0);
|
|
5878
|
-
},
|
|
5879
|
-
renderResult(result, options, theme, ...rest) {
|
|
5880
|
-
const { isPartial, isError, expanded, width } = resolveRenderResultContext(options, rest);
|
|
5881
|
-
if (isPartial)
|
|
5882
|
-
return renderPendingResult("pending inspect", width, theme);
|
|
5883
|
-
const textContent = result.content?.[0]?.type === "text" ? result.content[0].text : "";
|
|
5884
|
-
if (isError || result.isError) {
|
|
5885
|
-
return renderErrorResult(textContent, { expanded, width, fallback: "inspect failed", theme });
|
|
5886
|
-
}
|
|
5887
|
-
const value = result.details?.readSeekValue;
|
|
5888
|
-
const facets = Array.isArray(value?.select) ? value.select : ["content"];
|
|
5889
|
-
const label = summarizeEnvelope(value?.envelope, facets);
|
|
5890
|
-
let text = summaryLine(label, { hidden: !!textContent && !expanded, theme, style: "success" });
|
|
5891
|
-
if (expanded && textContent)
|
|
5892
|
-
text += `
|
|
5893
|
-
${textContent}`;
|
|
5894
|
-
return new Text7(clampLinesToWidth(text.split(`
|
|
5534
|
+
return buildToolErrorResult(opts.tool, failure.code, failure.message, failure.hint ? { hint: failure.hint } : {});
|
|
5535
|
+
}
|
|
5536
|
+
}
|
|
5537
|
+
function registerAccessTools(pi, options = {}) {
|
|
5538
|
+
for (const name of Object.keys(operations)) {
|
|
5539
|
+
const registeredName = name === "show_content" ? options.name ?? `readSeek_${name}` : `readSeek_${name}`;
|
|
5540
|
+
const contract = getToolContract(name);
|
|
5541
|
+
const metadata = defineToolPromptMetadata({
|
|
5542
|
+
promptUrl: new URL(`../prompts/${name}.md`, import.meta.url),
|
|
5543
|
+
promptSnippet: contract.title,
|
|
5544
|
+
registeredName,
|
|
5545
|
+
toolAliases: options.toolAliases
|
|
5546
|
+
});
|
|
5547
|
+
registerReadSeekTool(pi, {
|
|
5548
|
+
name: registeredName,
|
|
5549
|
+
label: contract.title,
|
|
5550
|
+
...metadata,
|
|
5551
|
+
parameters: Type11.Unsafe({
|
|
5552
|
+
...contract.inputSchema,
|
|
5553
|
+
properties: Object.fromEntries(Object.entries(contract.inputSchema.properties).filter(([key]) => key !== "stdinName"))
|
|
5554
|
+
}),
|
|
5555
|
+
async execute(_id, params, signal, _update, ctx) {
|
|
5556
|
+
return executeAccess({ tool: name, params, signal, cwd: ctx.cwd, onFileAnchored: options.onFileAnchored, imageMode: options.imageMode, modelSupportsImages: ctx.model?.input.includes("image") ?? false });
|
|
5557
|
+
},
|
|
5558
|
+
renderCall(args) {
|
|
5559
|
+
return new Text7(`${name} ${args.path ?? ""}${args.at ? ` @ ${args.at}` : ""}`, 0, 0);
|
|
5560
|
+
},
|
|
5561
|
+
renderResult(result, renderOptions, theme, ...rest) {
|
|
5562
|
+
const { isPartial, isError, expanded, width } = resolveRenderResultContext(renderOptions, rest);
|
|
5563
|
+
if (isPartial)
|
|
5564
|
+
return renderPendingResult(`pending ${name}`, width, theme);
|
|
5565
|
+
const text = result.content?.find((item) => item.type === "text")?.text ?? "";
|
|
5566
|
+
if (isError || result.isError)
|
|
5567
|
+
return renderErrorResult(text, { expanded, width, fallback: `${name} failed`, theme });
|
|
5568
|
+
const summary = summaryLine(contract.title, { hidden: !!text && !expanded, theme, style: "success" });
|
|
5569
|
+
return new Text7(clampLinesToWidth((expanded ? `${summary}
|
|
5570
|
+
${text}` : summary).split(`
|
|
5895
5571
|
`), width).join(`
|
|
5896
5572
|
`), 0, 0);
|
|
5897
|
-
}
|
|
5898
|
-
});
|
|
5899
|
-
}
|
|
5900
|
-
|
|
5901
|
-
// src/extract.ts
|
|
5902
|
-
import { Text as Text8 } from "@earendil-works/pi-tui";
|
|
5903
|
-
import { Type as Type12 } from "@sinclair/typebox";
|
|
5904
|
-
var EXTRACT_PROMPT_METADATA = defineToolPromptMetadata({
|
|
5905
|
-
promptUrl: new URL("../prompts/extract.md", import.meta.url),
|
|
5906
|
-
promptSnippet: "Extract a selected document asset to a file"
|
|
5907
|
-
});
|
|
5908
|
-
async function executeExtract(opts) {
|
|
5909
|
-
const { signal, cwd, onFileMutated } = opts;
|
|
5910
|
-
const input = opts.params;
|
|
5911
|
-
const selector = typeof input.selector === "string" ? input.selector.trim() : "";
|
|
5912
|
-
if (!selector.startsWith("asset:") || selector === "asset:") {
|
|
5913
|
-
return buildToolErrorResult("extract", "invalid-selector", "selector must identify an asset as asset:ID.", {
|
|
5914
|
-
path: input.path
|
|
5915
|
-
});
|
|
5916
|
-
}
|
|
5917
|
-
const output = typeof input.output === "string" ? input.output.trim() : "";
|
|
5918
|
-
if (!output || output === "-") {
|
|
5919
|
-
return buildToolErrorResult("extract", "invalid-output", "output must be a file path, not stdout.", {
|
|
5920
|
-
path: input.path
|
|
5921
|
-
});
|
|
5922
|
-
}
|
|
5923
|
-
const filePath = resolveToCwd2(input.path, cwd);
|
|
5924
|
-
const outputPath = resolveToCwd2(output, cwd);
|
|
5925
|
-
try {
|
|
5926
|
-
await readSeekExtract(filePath, selector, outputPath, { signal, cancelable: false });
|
|
5927
|
-
onFileMutated?.(outputPath);
|
|
5928
|
-
return {
|
|
5929
|
-
content: [{ type: "text", text: `Extracted ${selector} to ${outputPath}` }],
|
|
5930
|
-
details: {
|
|
5931
|
-
readSeekValue: {
|
|
5932
|
-
tool: "extract",
|
|
5933
|
-
ok: true,
|
|
5934
|
-
path: filePath,
|
|
5935
|
-
selector,
|
|
5936
|
-
output: outputPath
|
|
5937
|
-
}
|
|
5938
5573
|
}
|
|
5939
|
-
};
|
|
5940
|
-
} catch (error) {
|
|
5941
|
-
const failure = classifyReadSeekFailure(error);
|
|
5942
|
-
return buildToolErrorResult("extract", failure.code, failure.message, failure.hint ? { hint: failure.hint } : {});
|
|
5574
|
+
});
|
|
5943
5575
|
}
|
|
5944
5576
|
}
|
|
5945
|
-
function registerExtractTool(pi, options = {}) {
|
|
5946
|
-
return registerReadSeekTool(pi, {
|
|
5947
|
-
name: "readSeek_extract",
|
|
5948
|
-
label: "Extract",
|
|
5949
|
-
...EXTRACT_PROMPT_METADATA,
|
|
5950
|
-
parameters: Type12.Object({
|
|
5951
|
-
path: filePathParam(),
|
|
5952
|
-
selector: Type12.String({ pattern: "^asset:.+", description: PARAM_DESCRIPTIONS.assetSelector }),
|
|
5953
|
-
output: Type12.String({ minLength: 1, pattern: "^(?!-$).+", description: PARAM_DESCRIPTIONS.output })
|
|
5954
|
-
}),
|
|
5955
|
-
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
5956
|
-
return executeExtract({
|
|
5957
|
-
params,
|
|
5958
|
-
signal,
|
|
5959
|
-
cwd: ctx.cwd,
|
|
5960
|
-
onFileMutated: options.onFileMutated
|
|
5961
|
-
});
|
|
5962
|
-
},
|
|
5963
|
-
renderCall(args, theme, ...rest) {
|
|
5964
|
-
const context = rest[0] ?? {};
|
|
5965
|
-
const cwd = context.cwd ?? process.cwd();
|
|
5966
|
-
const displayPath = typeof args?.path === "string" ? args.path : "?";
|
|
5967
|
-
const output = typeof args?.output === "string" ? args.output : "?";
|
|
5968
|
-
let text = `${theme.fg("toolTitle", theme.bold("extract"))} ${linkToolPath(theme.fg("accent", displayPath), displayPath, cwd)}`;
|
|
5969
|
-
if (typeof args?.selector === "string")
|
|
5970
|
-
text += theme.fg("dim", ` ${args.selector}`);
|
|
5971
|
-
text += theme.fg("dim", ` → ${output}`);
|
|
5972
|
-
return new Text8(clampLineToWidth(text, context.width), 0, 0);
|
|
5973
|
-
},
|
|
5974
|
-
renderResult(result, options, theme, ...rest) {
|
|
5975
|
-
const { isPartial, isError, width } = resolveRenderResultContext(options, rest);
|
|
5976
|
-
if (isPartial)
|
|
5977
|
-
return renderPendingResult("pending extract", width, theme);
|
|
5978
|
-
const textContent = result.content?.[0]?.type === "text" ? result.content[0].text : "";
|
|
5979
|
-
if (isError || result.isError) {
|
|
5980
|
-
return renderErrorResult(textContent, { expanded: false, width, fallback: "extract failed", theme });
|
|
5981
|
-
}
|
|
5982
|
-
return new Text8(clampLineToWidth(summaryLine(textContent || "asset extracted", { theme, style: "success" }), width), 0, 0);
|
|
5983
|
-
}
|
|
5984
|
-
});
|
|
5985
|
-
}
|
|
5986
5577
|
|
|
5987
5578
|
// src/session-anchors.ts
|
|
5988
5579
|
class SessionAnchors {
|
|
@@ -6003,30 +5594,37 @@ class SessionAnchors {
|
|
|
6003
5594
|
|
|
6004
5595
|
// index.ts
|
|
6005
5596
|
var READSEEK_TOOL_ENTRIES = [
|
|
6006
|
-
{ builtIn: "edit", readSeekName: "
|
|
6007
|
-
{ builtIn: "grep", readSeekName: "
|
|
6008
|
-
{ builtIn: null, readSeekName: "
|
|
6009
|
-
{ builtIn: null, readSeekName: "
|
|
6010
|
-
{ builtIn: null, readSeekName: "
|
|
6011
|
-
{ builtIn: "write", readSeekName: "
|
|
6012
|
-
{ builtIn: null, readSeekName: "
|
|
6013
|
-
{ builtIn: "read", readSeekName: "
|
|
6014
|
-
{ builtIn: null, readSeekName: "
|
|
5597
|
+
{ builtIn: "edit", readSeekName: "readSeek_edit_text" },
|
|
5598
|
+
{ builtIn: "grep", readSeekName: "readSeek_find_text" },
|
|
5599
|
+
{ builtIn: null, readSeekName: "readSeek_find_nodes" },
|
|
5600
|
+
{ builtIn: null, readSeekName: "readSeek_find_references" },
|
|
5601
|
+
{ builtIn: null, readSeekName: "readSeek_rename_symbol" },
|
|
5602
|
+
{ builtIn: "write", readSeekName: "readSeek_write_file" },
|
|
5603
|
+
{ builtIn: null, readSeekName: "readSeek_find_definitions" },
|
|
5604
|
+
{ builtIn: "read", readSeekName: "readSeek_show_content" },
|
|
5605
|
+
{ builtIn: null, readSeekName: "readSeek_show_structure" },
|
|
5606
|
+
{ builtIn: null, readSeekName: "readSeek_show_metadata" },
|
|
5607
|
+
{ builtIn: null, readSeekName: "readSeek_show_assets" },
|
|
5608
|
+
{ builtIn: null, readSeekName: "readSeek_check_syntax" },
|
|
5609
|
+
{ builtIn: null, readSeekName: "readSeek_check_rules" },
|
|
5610
|
+
{ builtIn: null, readSeekName: "readSeek_generate_caption" },
|
|
5611
|
+
{ builtIn: null, readSeekName: "readSeek_detect_objects" },
|
|
5612
|
+
{ builtIn: null, readSeekName: "readSeek_recognize_text" }
|
|
6015
5613
|
];
|
|
6016
5614
|
function piReadSeekExtension(pi) {
|
|
6017
5615
|
const sessionAnchors = new SessionAnchors;
|
|
6018
5616
|
const { settings } = resolveReadSeekJsonSettings();
|
|
6019
5617
|
const replacedBuiltIns = new Set(settings.overrideTools ?? []);
|
|
6020
5618
|
const swap = (builtIn, readSeekName) => replacedBuiltIns.has(builtIn) ? builtIn : readSeekName;
|
|
6021
|
-
const readName = swap("read", "
|
|
6022
|
-
const editName = swap("edit", "
|
|
6023
|
-
const writeName = swap("write", "
|
|
6024
|
-
const grepName = swap("grep", "
|
|
5619
|
+
const readName = swap("read", "readSeek_show_content");
|
|
5620
|
+
const editName = swap("edit", "readSeek_edit_text");
|
|
5621
|
+
const writeName = swap("write", "readSeek_write_file");
|
|
5622
|
+
const grepName = swap("grep", "readSeek_find_text");
|
|
6025
5623
|
const toolAliases = {
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
5624
|
+
readSeek_show_content: readName,
|
|
5625
|
+
readSeek_edit_text: editName,
|
|
5626
|
+
readSeek_find_text: grepName,
|
|
5627
|
+
readSeek_write_file: writeName
|
|
6030
5628
|
};
|
|
6031
5629
|
const policyAliases = Object.fromEntries(TOOL_NAMES.map((name) => {
|
|
6032
5630
|
const readSeekName = `readSeek_${name}`;
|
|
@@ -6046,15 +5644,12 @@ function piReadSeekExtension(pi) {
|
|
|
6046
5644
|
registerRefsTool(pi, { onFileAnchored: (absolutePath) => sessionAnchors.markAnchored(absolutePath) });
|
|
6047
5645
|
registerRenameTool(pi, { onFileMutated: (absolutePath) => sessionAnchors.forget(absolutePath) });
|
|
6048
5646
|
registerDefTool(pi, { onFileAnchored: (absolutePath) => sessionAnchors.markAnchored(absolutePath) });
|
|
6049
|
-
|
|
5647
|
+
registerAccessTools(pi, {
|
|
6050
5648
|
onFileAnchored: (absolutePath) => sessionAnchors.markAnchored(absolutePath),
|
|
6051
5649
|
name: readName,
|
|
6052
5650
|
toolAliases,
|
|
6053
5651
|
imageMode: replacedBuiltIns.has("read") ? resolveReadSeekImageMode() : undefined
|
|
6054
5652
|
});
|
|
6055
|
-
registerExtractTool(pi, {
|
|
6056
|
-
onFileMutated: (absolutePath) => sessionAnchors.forget(absolutePath)
|
|
6057
|
-
});
|
|
6058
5653
|
registerWriteTool(pi, {
|
|
6059
5654
|
onFileAnchored: (absolutePath) => sessionAnchors.markAnchored(absolutePath),
|
|
6060
5655
|
name: writeName
|