@jarkkojs/readseek-api 0.10.7 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -5
- package/dist/argv.d.ts +74 -39
- package/dist/client-output.d.ts +273 -20
- package/dist/client.d.ts +39 -128
- package/dist/contract.d.ts +30 -30
- package/dist/index.d.ts +8 -7
- package/dist/index.js +1718 -1662
- package/dist/process.d.ts +3 -2
- package/dist/show-presentation.d.ts +15 -0
- package/dist/validation.d.ts +3 -10
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
// src/contract.ts
|
|
2
|
-
var INSPECT_FACETS = [
|
|
3
|
-
"metadata",
|
|
4
|
-
"content",
|
|
5
|
-
"map",
|
|
6
|
-
"diagnostics",
|
|
7
|
-
"identity"
|
|
8
|
-
];
|
|
9
|
-
var VISION_MODES = ["none", "all", "ocr", "caption", "objects"];
|
|
10
|
-
var VISION_ANALYSIS_MODES = ["all", "ocr", "caption", "objects"];
|
|
11
2
|
var VISION_LEVELS = ["low", "medium", "high"];
|
|
12
3
|
var EDIT_VARIANTS = [
|
|
13
4
|
"set_line",
|
|
@@ -18,15 +9,22 @@ var EDIT_VARIANTS = [
|
|
|
18
9
|
];
|
|
19
10
|
var GIT_SCOPES = ["tracked", "untracked", "ignored", "all"];
|
|
20
11
|
var TOOL_NAMES = [
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
12
|
+
"show_content",
|
|
13
|
+
"show_structure",
|
|
14
|
+
"show_metadata",
|
|
15
|
+
"show_assets",
|
|
16
|
+
"check_syntax",
|
|
17
|
+
"check_rules",
|
|
18
|
+
"generate_caption",
|
|
19
|
+
"detect_objects",
|
|
20
|
+
"recognize_text",
|
|
21
|
+
"find_nodes",
|
|
22
|
+
"find_text",
|
|
23
|
+
"find_definitions",
|
|
24
|
+
"find_references",
|
|
25
|
+
"edit_text",
|
|
26
|
+
"rename_symbol",
|
|
27
|
+
"write_file"
|
|
30
28
|
];
|
|
31
29
|
var PARAM_DESCRIPTIONS = {
|
|
32
30
|
path: "Absolute or relative file path",
|
|
@@ -37,31 +35,30 @@ var PARAM_DESCRIPTIONS = {
|
|
|
37
35
|
languageOverride: "Language override",
|
|
38
36
|
languageSymbol: "Language override for symbol replacement",
|
|
39
37
|
pattern: "AST pattern (ast-grep style), such as console.log($$$ARGS)",
|
|
38
|
+
patternContext: "Surrounding code context for sub-statement patterns",
|
|
39
|
+
selector: "Target AST node kind to extract from pattern context",
|
|
40
40
|
grepPattern: "Regex pattern; set literal for exact text",
|
|
41
41
|
name: "Qualified or unqualified symbol name",
|
|
42
42
|
refsName: "Identifier to find references for",
|
|
43
|
-
scope: "Restrict results to the binding at the cursor",
|
|
44
|
-
line: "One-based cursor line; required with scope",
|
|
45
|
-
renameLine: "One-based cursor line of the symbol to rename",
|
|
46
|
-
column: "One-based cursor byte column for disambiguation",
|
|
47
43
|
gitScope: "In a Git repository, which files to search: tracked, untracked, ignored (untracked plus ignored), or all. Defaults to tracked plus untracked.",
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
query: "KDL selection query, @path, or '-' for standard input",
|
|
44
|
+
at: "Location selector: line:N[:COLUMN], hash:H[:COLUMN], symbol:NAME, page:N, node:ID, or asset:ID",
|
|
45
|
+
assetAt: "Document selector: page:N, node:ID, or asset:ID",
|
|
46
|
+
rule: "KDL node selection rule, @path, or '-' for standard input",
|
|
47
|
+
rules: "KDL structural checks, @path, or '-' for standard input",
|
|
53
48
|
stdinName: "File name hint when the target is '-'",
|
|
54
49
|
end: "Last line to include",
|
|
55
50
|
limit: "Maximum number of lines to include",
|
|
56
|
-
|
|
51
|
+
depth: "Maximum structural depth for structure output; defaults to 1 in agent tools",
|
|
57
52
|
offset: "One-based starting line",
|
|
58
53
|
readLimit: "Maximum lines to return",
|
|
59
54
|
symbolRead: "Symbol name to read",
|
|
60
55
|
bundle: "Include related symbols from the same file; requires symbol",
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
level: "Explicit inference level: low (default), medium, or high",
|
|
57
|
+
include: "Additional caption tasks: text and/or objects",
|
|
58
|
+
kind: "Restrict structure to this node kind",
|
|
59
|
+
outline: "Return a symbol outline",
|
|
60
|
+
noAnchors: "Omit source line anchors",
|
|
61
|
+
text: "Literal native text query; adapter find_text also supports regex via pattern",
|
|
65
62
|
edits: "Use set_line, replace_lines, insert_after, replace_symbol, or replace",
|
|
66
63
|
editVariant: "Exactly one nested edit variant",
|
|
67
64
|
setLine: 'Replace one line: {"set_line":{"anchor":"LINE:HASH","new_text":"..."}}',
|
|
@@ -98,15 +95,22 @@ var PARAM_DESCRIPTIONS = {
|
|
|
98
95
|
scopeContext: "Context lines within each symbol"
|
|
99
96
|
};
|
|
100
97
|
var TOOL_DESCRIPTIONS = {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
98
|
+
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.",
|
|
99
|
+
show_structure: "Show parsed source or document hierarchy. Use shallow depth for file overviews.",
|
|
100
|
+
show_metadata: "Show format, source identity, language, dimensions, or page count without decoding image content or inference.",
|
|
101
|
+
show_assets: "Return selected document asset descriptors with usable cached paths. Adapters attach images from those paths.",
|
|
102
|
+
check_syntax: "Check parser syntax diagnostics. Exit 0 is clean, 1 has findings, 2 is failure; this is not type checking.",
|
|
103
|
+
check_rules: "Evaluate KDL structural assertions. Exit 0 is clean, 1 has findings, 2 is failure.",
|
|
104
|
+
generate_caption: "Explicitly infer a caption using an installed model. Include text and objects to request OCR and detection too; never downloads models automatically.",
|
|
105
|
+
detect_objects: "Explicitly infer object labels and bounding boxes using an installed model.",
|
|
106
|
+
recognize_text: "Explicitly recognize text from pixels using an installed model; reading never silently invokes OCR.",
|
|
107
|
+
find_nodes: "Find AST nodes by pattern or KDL selection rule. Returns edit-ready anchors. Use `find_text` for text and regex.",
|
|
108
|
+
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.",
|
|
109
|
+
find_definitions: "Find a symbol definition or declaration by qualified or unqualified name.",
|
|
110
|
+
find_references: "Find identifier-name matches with name, or binding-scoped references with at. Use before renaming or deleting a symbol.",
|
|
111
|
+
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.",
|
|
112
|
+
rename_symbol: "Rename a symbol at a line or hash cursor with binding-aware edits and stale-plan protection.",
|
|
113
|
+
write_file: "Create or replace a complete text file and return `LINE:HASH` anchors. Use `edit_text` for small changes."
|
|
110
114
|
};
|
|
111
115
|
function renderToolDescription(name, aliases = {}) {
|
|
112
116
|
const desc = TOOL_DESCRIPTIONS[name];
|
|
@@ -182,202 +186,36 @@ var editItemSchema = {
|
|
|
182
186
|
},
|
|
183
187
|
description: PARAM_DESCRIPTIONS.editVariant
|
|
184
188
|
};
|
|
189
|
+
var string = (description) => ({ type: "string", description });
|
|
190
|
+
var integer = (description, minimum = 1) => ({ type: "integer", minimum, description });
|
|
191
|
+
var path = { path: string(PARAM_DESCRIPTIONS.path) };
|
|
192
|
+
var at = { at: string(PARAM_DESCRIPTIONS.at) };
|
|
193
|
+
var lang = { language: string(PARAM_DESCRIPTIONS.language) };
|
|
194
|
+
var stdin = { stdinName: string(PARAM_DESCRIPTIONS.stdinName) };
|
|
195
|
+
var noAnchors = { noAnchors: { type: "boolean", description: PARAM_DESCRIPTIONS.noAnchors } };
|
|
196
|
+
var level = { level: { type: "string", enum: VISION_LEVELS, description: PARAM_DESCRIPTIONS.level } };
|
|
197
|
+
var limit = { limit: integer(PARAM_DESCRIPTIONS.matchLimit) };
|
|
198
|
+
var apply = { apply: { type: "boolean", description: PARAM_DESCRIPTIONS.apply }, planHash: string(PARAM_DESCRIPTIONS.planHash) };
|
|
199
|
+
function tool(name, title, properties, required) {
|
|
200
|
+
return { name, title, description: TOOL_DESCRIPTIONS[name], inputSchema: { type: "object", properties, required, additionalProperties: false } };
|
|
201
|
+
}
|
|
185
202
|
var TOOL_CONTRACTS = [
|
|
186
|
-
{
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
type: "string",
|
|
203
|
-
enum: [...VISION_MODES],
|
|
204
|
-
description: PARAM_DESCRIPTIONS.visionModeInspect
|
|
205
|
-
},
|
|
206
|
-
visionLevel: {
|
|
207
|
-
type: "string",
|
|
208
|
-
enum: [...VISION_LEVELS],
|
|
209
|
-
description: PARAM_DESCRIPTIONS.visionLevel
|
|
210
|
-
},
|
|
211
|
-
stdinName: { type: "string", description: PARAM_DESCRIPTIONS.stdinName }
|
|
212
|
-
},
|
|
213
|
-
required: ["path"],
|
|
214
|
-
additionalProperties: false
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
name: "edit",
|
|
219
|
-
title: "Hash-verified edit",
|
|
220
|
-
description: TOOL_DESCRIPTIONS.edit,
|
|
221
|
-
inputSchema: {
|
|
222
|
-
type: "object",
|
|
223
|
-
properties: {
|
|
224
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.path },
|
|
225
|
-
edits: {
|
|
226
|
-
type: "array",
|
|
227
|
-
minItems: 1,
|
|
228
|
-
description: PARAM_DESCRIPTIONS.edits,
|
|
229
|
-
items: editItemSchema
|
|
230
|
-
},
|
|
231
|
-
language: { type: "string", description: PARAM_DESCRIPTIONS.languageSymbol },
|
|
232
|
-
apply: { type: "boolean", description: PARAM_DESCRIPTIONS.apply },
|
|
233
|
-
planHash: { type: "string", description: PARAM_DESCRIPTIONS.planHash },
|
|
234
|
-
postEditVerify: { type: "boolean", description: PARAM_DESCRIPTIONS.postEditVerify }
|
|
235
|
-
},
|
|
236
|
-
required: ["path", "edits"],
|
|
237
|
-
additionalProperties: false
|
|
238
|
-
}
|
|
239
|
-
},
|
|
240
|
-
{
|
|
241
|
-
name: "write",
|
|
242
|
-
title: "Write file",
|
|
243
|
-
description: TOOL_DESCRIPTIONS.write,
|
|
244
|
-
inputSchema: {
|
|
245
|
-
type: "object",
|
|
246
|
-
properties: {
|
|
247
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.path },
|
|
248
|
-
content: { type: "string", description: PARAM_DESCRIPTIONS.content }
|
|
249
|
-
},
|
|
250
|
-
required: ["path", "content"],
|
|
251
|
-
additionalProperties: false
|
|
252
|
-
}
|
|
253
|
-
},
|
|
254
|
-
{
|
|
255
|
-
name: "grep",
|
|
256
|
-
title: "Text search",
|
|
257
|
-
description: TOOL_DESCRIPTIONS.grep,
|
|
258
|
-
inputSchema: {
|
|
259
|
-
type: "object",
|
|
260
|
-
properties: {
|
|
261
|
-
pattern: { type: "string", description: PARAM_DESCRIPTIONS.grepPattern },
|
|
262
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.searchPath },
|
|
263
|
-
glob: { type: "string", description: PARAM_DESCRIPTIONS.glob },
|
|
264
|
-
ignoreCase: { type: "boolean", description: PARAM_DESCRIPTIONS.ignoreCase },
|
|
265
|
-
literal: { type: "boolean", description: PARAM_DESCRIPTIONS.literal },
|
|
266
|
-
context: { type: "integer", minimum: 0, description: PARAM_DESCRIPTIONS.context },
|
|
267
|
-
limit: { type: "integer", minimum: 1, description: PARAM_DESCRIPTIONS.matchLimit },
|
|
268
|
-
summary: { type: "boolean", description: PARAM_DESCRIPTIONS.summary },
|
|
269
|
-
scope: {
|
|
270
|
-
type: "string",
|
|
271
|
-
enum: ["symbol"],
|
|
272
|
-
description: PARAM_DESCRIPTIONS.grepScope
|
|
273
|
-
},
|
|
274
|
-
scopeContext: {
|
|
275
|
-
type: "integer",
|
|
276
|
-
minimum: 0,
|
|
277
|
-
description: PARAM_DESCRIPTIONS.scopeContext
|
|
278
|
-
}
|
|
279
|
-
},
|
|
280
|
-
required: ["pattern"],
|
|
281
|
-
additionalProperties: false
|
|
282
|
-
}
|
|
283
|
-
},
|
|
284
|
-
{
|
|
285
|
-
name: "extract",
|
|
286
|
-
title: "Extract asset",
|
|
287
|
-
description: TOOL_DESCRIPTIONS.extract,
|
|
288
|
-
inputSchema: {
|
|
289
|
-
type: "object",
|
|
290
|
-
properties: {
|
|
291
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.path },
|
|
292
|
-
selector: {
|
|
293
|
-
type: "string",
|
|
294
|
-
pattern: "^asset:.+",
|
|
295
|
-
description: PARAM_DESCRIPTIONS.assetSelector
|
|
296
|
-
},
|
|
297
|
-
output: {
|
|
298
|
-
type: "string",
|
|
299
|
-
minLength: 1,
|
|
300
|
-
pattern: "^(?!-$).+",
|
|
301
|
-
description: PARAM_DESCRIPTIONS.output
|
|
302
|
-
},
|
|
303
|
-
stdinName: { type: "string", description: PARAM_DESCRIPTIONS.stdinName }
|
|
304
|
-
},
|
|
305
|
-
required: ["path", "selector", "output"],
|
|
306
|
-
additionalProperties: false
|
|
307
|
-
}
|
|
308
|
-
},
|
|
309
|
-
{
|
|
310
|
-
name: "search",
|
|
311
|
-
title: "AST search",
|
|
312
|
-
description: TOOL_DESCRIPTIONS.search,
|
|
313
|
-
inputSchema: {
|
|
314
|
-
type: "object",
|
|
315
|
-
properties: {
|
|
316
|
-
pattern: { type: "string", description: PARAM_DESCRIPTIONS.pattern },
|
|
317
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.searchPath },
|
|
318
|
-
language: { type: "string", description: PARAM_DESCRIPTIONS.language },
|
|
319
|
-
limit: { type: "integer", minimum: 1, description: PARAM_DESCRIPTIONS.matchLimit },
|
|
320
|
-
...gitScopeSchema
|
|
321
|
-
},
|
|
322
|
-
required: ["pattern"],
|
|
323
|
-
additionalProperties: false
|
|
324
|
-
}
|
|
325
|
-
},
|
|
326
|
-
{
|
|
327
|
-
name: "def",
|
|
328
|
-
title: "Find definition",
|
|
329
|
-
description: TOOL_DESCRIPTIONS.def,
|
|
330
|
-
inputSchema: {
|
|
331
|
-
type: "object",
|
|
332
|
-
properties: {
|
|
333
|
-
name: { type: "string", description: PARAM_DESCRIPTIONS.name },
|
|
334
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.searchPath },
|
|
335
|
-
language: { type: "string", description: PARAM_DESCRIPTIONS.language },
|
|
336
|
-
...gitScopeSchema
|
|
337
|
-
},
|
|
338
|
-
required: ["name"],
|
|
339
|
-
additionalProperties: false
|
|
340
|
-
}
|
|
341
|
-
},
|
|
342
|
-
{
|
|
343
|
-
name: "refs",
|
|
344
|
-
title: "Find references",
|
|
345
|
-
description: TOOL_DESCRIPTIONS.refs,
|
|
346
|
-
inputSchema: {
|
|
347
|
-
type: "object",
|
|
348
|
-
properties: {
|
|
349
|
-
name: { type: "string", description: PARAM_DESCRIPTIONS.refsName },
|
|
350
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.searchPath },
|
|
351
|
-
language: { type: "string", description: PARAM_DESCRIPTIONS.language },
|
|
352
|
-
scope: { type: "boolean", description: PARAM_DESCRIPTIONS.scope },
|
|
353
|
-
line: { type: "integer", minimum: 1, description: PARAM_DESCRIPTIONS.line },
|
|
354
|
-
column: { type: "integer", minimum: 1, description: PARAM_DESCRIPTIONS.column },
|
|
355
|
-
...gitScopeSchema
|
|
356
|
-
},
|
|
357
|
-
additionalProperties: false
|
|
358
|
-
}
|
|
359
|
-
},
|
|
360
|
-
{
|
|
361
|
-
name: "rename",
|
|
362
|
-
title: "Rename symbol",
|
|
363
|
-
description: TOOL_DESCRIPTIONS.rename,
|
|
364
|
-
inputSchema: {
|
|
365
|
-
type: "object",
|
|
366
|
-
properties: {
|
|
367
|
-
path: { type: "string", description: PARAM_DESCRIPTIONS.path },
|
|
368
|
-
line: { type: "integer", minimum: 1, description: PARAM_DESCRIPTIONS.renameLine },
|
|
369
|
-
column: { type: "integer", minimum: 1, description: PARAM_DESCRIPTIONS.column },
|
|
370
|
-
to: { type: "string", description: PARAM_DESCRIPTIONS.to },
|
|
371
|
-
workspace: { type: "boolean", description: PARAM_DESCRIPTIONS.workspace },
|
|
372
|
-
apply: { type: "boolean", description: PARAM_DESCRIPTIONS.apply },
|
|
373
|
-
planHash: { type: "string", description: PARAM_DESCRIPTIONS.planHash },
|
|
374
|
-
language: { type: "string", description: PARAM_DESCRIPTIONS.language },
|
|
375
|
-
...gitScopeSchema
|
|
376
|
-
},
|
|
377
|
-
required: ["path", "line", "to"],
|
|
378
|
-
additionalProperties: false
|
|
379
|
-
}
|
|
380
|
-
}
|
|
203
|
+
tool("show_content", "Show content", { ...path, ...at, ...lang, ...stdin, ...noAnchors, end: integer(PARAM_DESCRIPTIONS.end), limit: integer(PARAM_DESCRIPTIONS.limit) }, ["path"]),
|
|
204
|
+
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"]),
|
|
205
|
+
tool("show_metadata", "Show metadata", { ...path, ...lang, ...stdin }, ["path"]),
|
|
206
|
+
tool("show_assets", "Show assets", { ...path, at: string(PARAM_DESCRIPTIONS.assetAt), ...stdin }, ["path"]),
|
|
207
|
+
tool("check_syntax", "Check syntax", { ...path, ...lang, ...stdin }, ["path"]),
|
|
208
|
+
tool("check_rules", "Check rules", { ...path, ...gitScopeSchema, rules: string(PARAM_DESCRIPTIONS.rules) }, ["rules"]),
|
|
209
|
+
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"]),
|
|
210
|
+
tool("detect_objects", "Detect objects", { ...path, ...at, ...stdin, ...level }, ["path"]),
|
|
211
|
+
tool("recognize_text", "Recognize text", { ...path, ...at, ...stdin, ...level }, ["path"]),
|
|
212
|
+
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) }, []),
|
|
213
|
+
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) }, []),
|
|
214
|
+
tool("find_definitions", "Find definitions", { ...path, ...lang, ...gitScopeSchema, ...noAnchors, name: string(PARAM_DESCRIPTIONS.name) }, ["name"]),
|
|
215
|
+
tool("find_references", "Find references", { ...path, ...at, ...lang, ...gitScopeSchema, ...noAnchors, name: string(PARAM_DESCRIPTIONS.refsName) }, []),
|
|
216
|
+
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"]),
|
|
217
|
+
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"]),
|
|
218
|
+
tool("write_file", "Write file", { ...path, content: string(PARAM_DESCRIPTIONS.content) }, ["path", "content"])
|
|
381
219
|
];
|
|
382
220
|
function getToolContract(name) {
|
|
383
221
|
const contract = TOOL_CONTRACTS.find((entry) => entry.name === name);
|
|
@@ -388,70 +226,70 @@ function getToolContract(name) {
|
|
|
388
226
|
// src/policy.ts
|
|
389
227
|
var REPLACEABLE_TOOLS = [
|
|
390
228
|
{
|
|
391
|
-
tool: "
|
|
229
|
+
tool: "show_content",
|
|
392
230
|
builtIn: "read",
|
|
393
231
|
benefit: "it returns LINE:HASH anchors for safe edits."
|
|
394
232
|
},
|
|
395
233
|
{
|
|
396
|
-
tool: "
|
|
234
|
+
tool: "edit_text",
|
|
397
235
|
builtIn: "edit",
|
|
398
236
|
benefit: "it verifies fresh LINE:HASH anchors."
|
|
399
237
|
},
|
|
400
238
|
{
|
|
401
|
-
tool: "
|
|
239
|
+
tool: "find_text",
|
|
402
240
|
builtIn: "grep",
|
|
403
241
|
benefit: "it returns LINE:HASH anchors."
|
|
404
242
|
},
|
|
405
243
|
{
|
|
406
|
-
tool: "
|
|
244
|
+
tool: "write_file",
|
|
407
245
|
builtIn: "write",
|
|
408
246
|
benefit: "it returns LINE:HASH anchors."
|
|
409
247
|
}
|
|
410
248
|
];
|
|
411
249
|
var TOOL_COMPACT_GUIDELINES = {
|
|
412
|
-
|
|
413
|
-
"Use `
|
|
250
|
+
show_content: [
|
|
251
|
+
"Use `show_structure` for shallow overviews and `check_syntax` for diagnostics; use `find_definitions`, `find_references`, or `find_nodes` for targeted symbol questions."
|
|
414
252
|
],
|
|
415
|
-
|
|
253
|
+
edit_text: [
|
|
416
254
|
"Prefer set_line, replace_lines, and insert_after; use replace only when anchors are impractical."
|
|
417
255
|
],
|
|
418
|
-
|
|
419
|
-
"Use `
|
|
256
|
+
find_text: [
|
|
257
|
+
"Use `find_text` with summary first for broad searches, then narrow by path, glob, or pattern."
|
|
420
258
|
],
|
|
421
|
-
|
|
422
|
-
"Use anchored edits rather than `
|
|
259
|
+
write_file: [
|
|
260
|
+
"Use anchored edits rather than `write_file` for small changes or appends."
|
|
423
261
|
],
|
|
424
|
-
|
|
425
|
-
"Use `
|
|
262
|
+
find_nodes: [
|
|
263
|
+
"Use `find_nodes` for AST patterns; use `find_text` for plain text."
|
|
426
264
|
],
|
|
427
|
-
|
|
428
|
-
"Use `
|
|
265
|
+
find_references: [
|
|
266
|
+
"Use `find_references` before changing a symbol; use at with line:N:C to follow one binding."
|
|
429
267
|
]
|
|
430
268
|
};
|
|
431
269
|
var BUILTIN_FALLBACKS = {
|
|
432
|
-
read: "
|
|
433
|
-
edit: "
|
|
434
|
-
write: "
|
|
435
|
-
grep: "
|
|
436
|
-
apply_patch: "
|
|
270
|
+
read: "show_content",
|
|
271
|
+
edit: "edit_text",
|
|
272
|
+
write: "write_file",
|
|
273
|
+
grep: "find_text",
|
|
274
|
+
apply_patch: "edit_text"
|
|
437
275
|
};
|
|
438
276
|
var PREFERENCE_LEADS = {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
277
|
+
show_content: "Preferred for reading source with anchors.",
|
|
278
|
+
edit_text: "Preferred for editing existing text files with fresh LINE:HASH anchors.",
|
|
279
|
+
write_file: "Preferred for creating or replacing a complete text file; returns LINE:HASH anchors.",
|
|
280
|
+
find_text: "Preferred text/regex find_nodes; returns edit_text-ready LINE:HASH anchors.",
|
|
281
|
+
find_nodes: "Preferred for AST or structural code find_nodes with ast-find_text-style patterns.",
|
|
282
|
+
find_definitions: "Preferred for go-to-definition or declaration lookup by name.",
|
|
283
|
+
find_references: "Preferred for finding identifier-name matches or binding-specific references before rename_symbol or delete.",
|
|
284
|
+
rename_symbol: "Preferred for renaming a symbol with binding-aware, verified edits.",
|
|
285
|
+
show_assets: "Preferred for saving a selected document asset to a file."
|
|
448
286
|
};
|
|
449
287
|
var FALLBACK_TEMPLATES = {
|
|
450
|
-
read: "Prefer `
|
|
451
|
-
edit: "Prefer `
|
|
452
|
-
write: "Prefer `
|
|
453
|
-
grep: "Prefer `
|
|
454
|
-
apply_patch: "Prefer `
|
|
288
|
+
read: "Prefer `show_content` with fresh LINE:HASH anchors.",
|
|
289
|
+
edit: "Prefer `edit_text` with fresh LINE:HASH anchors.",
|
|
290
|
+
write: "Prefer `write_file` so the result returns LINE:HASH anchors.",
|
|
291
|
+
grep: "Prefer `find_text` for text/regex search with edit-ready anchors.",
|
|
292
|
+
apply_patch: "Prefer `edit_text` for existing text files."
|
|
455
293
|
};
|
|
456
294
|
function resolveToolName(name, aliases = {}) {
|
|
457
295
|
return aliases[name] ?? name;
|
|
@@ -463,7 +301,7 @@ function renderCompactGuidelines(name, aliases = {}) {
|
|
|
463
301
|
return (TOOL_COMPACT_GUIDELINES[name] ?? []).map((guideline) => rewriteBacktickedToolNames(guideline, aliases));
|
|
464
302
|
}
|
|
465
303
|
function renderPreferredToolDescription(name, aliases = {}) {
|
|
466
|
-
return rewriteBacktickedToolNames(PREFERENCE_LEADS[name], aliases);
|
|
304
|
+
return rewriteBacktickedToolNames(PREFERENCE_LEADS[name] ?? `Preferred for ${name.replaceAll("_", " ")} with ReadSeek.`, aliases);
|
|
467
305
|
}
|
|
468
306
|
function renderFallbackToolDescription(builtIn, aliases = {}) {
|
|
469
307
|
const template = FALLBACK_TEMPLATES[builtIn];
|
|
@@ -473,20 +311,20 @@ function renderFallbackToolDescription(builtIn, aliases = {}) {
|
|
|
473
311
|
}
|
|
474
312
|
function renderToolRoutingPolicy(options = {}) {
|
|
475
313
|
const aliases = options.aliases ?? {};
|
|
476
|
-
const
|
|
477
|
-
const
|
|
478
|
-
const
|
|
479
|
-
const
|
|
480
|
-
const
|
|
481
|
-
const
|
|
482
|
-
const
|
|
483
|
-
const
|
|
484
|
-
const
|
|
314
|
+
const show_content = resolveToolName("show_content", aliases);
|
|
315
|
+
const edit_text = resolveToolName("edit_text", aliases);
|
|
316
|
+
const write_file = resolveToolName("write_file", aliases);
|
|
317
|
+
const find_text = resolveToolName("find_text", aliases);
|
|
318
|
+
const find_nodes = resolveToolName("find_nodes", aliases);
|
|
319
|
+
const find_definitions = resolveToolName("find_definitions", aliases);
|
|
320
|
+
const find_references = resolveToolName("find_references", aliases);
|
|
321
|
+
const rename_symbol = resolveToolName("rename_symbol", aliases);
|
|
322
|
+
const show_assets = resolveToolName("show_assets", aliases);
|
|
485
323
|
if (options.style === "server") {
|
|
486
324
|
return [
|
|
487
325
|
"Structural code navigation, document inspection, and hash-verified edits with readseek.",
|
|
488
|
-
"For structural questions, prefer these tools to text Grep/Bash: targeted definitions, references, and AST
|
|
489
|
-
`Use ${
|
|
326
|
+
"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.",
|
|
327
|
+
`Use ${edit_text} for LINE:HASH-anchored mutations (preview with apply=false; apply defaults to true and re-checks plan_hash).`,
|
|
490
328
|
"Paths resolve against CLAUDE_PROJECT_DIR. Native Read/Grep/Edit hooks provide passive context;",
|
|
491
329
|
"call MCP tools for active navigation, document questions, or anchored edits."
|
|
492
330
|
].join(" ");
|
|
@@ -496,7 +334,7 @@ function renderToolRoutingPolicy(options = {}) {
|
|
|
496
334
|
if (options.preferOverBuiltIns) {
|
|
497
335
|
bullets.push("- Prefer ReadSeek tools over built-ins when they can do the job.");
|
|
498
336
|
}
|
|
499
|
-
bullets.push(`- Read with ${
|
|
337
|
+
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.`);
|
|
500
338
|
if (options.demoteBuiltIns && options.demoteBuiltIns.length > 0) {
|
|
501
339
|
bullets.push(`- Do not use built-in ${options.demoteBuiltIns.join(", ")} when a ReadSeek tool can do the job.`);
|
|
502
340
|
}
|
|
@@ -538,25 +376,9 @@ function parseLineAnchor(anchor) {
|
|
|
538
376
|
}
|
|
539
377
|
|
|
540
378
|
// src/validation.ts
|
|
541
|
-
function
|
|
542
|
-
if (input.
|
|
543
|
-
|
|
544
|
-
return { ok: false, error: "scope requires line" };
|
|
545
|
-
}
|
|
546
|
-
return { ok: true };
|
|
547
|
-
}
|
|
548
|
-
if (input.line !== undefined || input.column !== undefined) {
|
|
549
|
-
return { ok: false, error: "line/column require scope=true" };
|
|
550
|
-
}
|
|
551
|
-
if (typeof input.name !== "string" || input.name.length === 0) {
|
|
552
|
-
return { ok: false, error: "name is required when scope is not set" };
|
|
553
|
-
}
|
|
554
|
-
return { ok: true };
|
|
555
|
-
}
|
|
556
|
-
function validateVisionLevelVsMode(input) {
|
|
557
|
-
if (input.visionLevel !== undefined && !["all", "ocr", "caption", "objects"].includes(input.visionMode ?? "")) {
|
|
558
|
-
return { ok: false, error: "visionLevel requires an analysis visionMode" };
|
|
559
|
-
}
|
|
379
|
+
function validateReferencesSelection(input) {
|
|
380
|
+
if (Boolean(input.name) === Boolean(input.at))
|
|
381
|
+
return { ok: false, error: "exactly one of name or at is required" };
|
|
560
382
|
return { ok: true };
|
|
561
383
|
}
|
|
562
384
|
var VARIANT_FIELDS = {
|
|
@@ -682,48 +504,8 @@ function coerceNonNegativeInt(value) {
|
|
|
682
504
|
}
|
|
683
505
|
return;
|
|
684
506
|
}
|
|
685
|
-
// src/edit-plan.ts
|
|
686
|
-
import { Document, Node, format } from "@bgotink/kdl";
|
|
687
|
-
function node(name, properties, children = []) {
|
|
688
|
-
const result = Node.create(name);
|
|
689
|
-
for (const [key, value] of Object.entries(properties))
|
|
690
|
-
result.setProperty(key, value);
|
|
691
|
-
if (children.length > 0)
|
|
692
|
-
result.children = new Document(children);
|
|
693
|
-
return result;
|
|
694
|
-
}
|
|
695
|
-
function editNode(edit) {
|
|
696
|
-
if ("set_line" in edit) {
|
|
697
|
-
const value = edit.set_line;
|
|
698
|
-
return node("set-line", { anchor: value.anchor, text: value.new_text });
|
|
699
|
-
}
|
|
700
|
-
if ("replace_lines" in edit) {
|
|
701
|
-
const value = edit.replace_lines;
|
|
702
|
-
return node("replace-lines", { start: value.start_anchor, end: value.end_anchor, text: value.new_text });
|
|
703
|
-
}
|
|
704
|
-
if ("insert_after" in edit) {
|
|
705
|
-
const value = edit.insert_after;
|
|
706
|
-
return node("insert-after", { anchor: value.anchor, text: value.new_text });
|
|
707
|
-
}
|
|
708
|
-
if ("replace_symbol" in edit) {
|
|
709
|
-
const value = edit.replace_symbol;
|
|
710
|
-
return node("replace-symbol", { symbol: value.symbol, body: value.new_body });
|
|
711
|
-
}
|
|
712
|
-
const value = edit.replace;
|
|
713
|
-
return node("replace", {
|
|
714
|
-
old: value.old_text,
|
|
715
|
-
new: value.new_text,
|
|
716
|
-
...value.all === undefined ? {} : { all: value.all }
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
function serializeEditPlan(edits) {
|
|
720
|
-
const validation = validateExactlyOneEditVariant(edits);
|
|
721
|
-
if (!validation.ok)
|
|
722
|
-
throw new Error(validation.error);
|
|
723
|
-
return format(new Document([node("plan", {}, validation.edits.map(editNode))]));
|
|
724
|
-
}
|
|
725
507
|
// src/argv.ts
|
|
726
|
-
var
|
|
508
|
+
var DEFAULT_STRUCTURE_DEPTH = 1;
|
|
727
509
|
function buildLineLocation(line, column) {
|
|
728
510
|
return column === undefined ? `line:${line}` : `line:${line}:${column}`;
|
|
729
511
|
}
|
|
@@ -753,30 +535,6 @@ function appendApplyAndPlanHash(args, input) {
|
|
|
753
535
|
pushOptionalString(args, "--plan-hash", input.planHash);
|
|
754
536
|
return args;
|
|
755
537
|
}
|
|
756
|
-
function selectArg(select) {
|
|
757
|
-
if (select === undefined)
|
|
758
|
-
return;
|
|
759
|
-
return Array.isArray(select) ? select.join(",") : select;
|
|
760
|
-
}
|
|
761
|
-
function selectedInspectFacets(select) {
|
|
762
|
-
const facets = (selectArg(select) ?? "content").split(",").map((facet) => facet.trim());
|
|
763
|
-
for (const facet of facets) {
|
|
764
|
-
if (!INSPECT_FACETS.includes(facet)) {
|
|
765
|
-
throw new Error(`unknown inspect facet: ${facet}`);
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
return facets;
|
|
769
|
-
}
|
|
770
|
-
function hasInspectFacet(facets, facet) {
|
|
771
|
-
return facets.includes(facet);
|
|
772
|
-
}
|
|
773
|
-
function validateTarget(command, target, stdinName) {
|
|
774
|
-
if (target.length === 0)
|
|
775
|
-
throw new Error(`${command} requires a target file path or '-'`);
|
|
776
|
-
if (stdinName !== undefined && stdinName.length > 0 && target !== "-") {
|
|
777
|
-
throw new Error("stdinName requires '-' as the target");
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
538
|
function validatePositiveInteger(value, name) {
|
|
781
539
|
if (!Number.isSafeInteger(value) || value < 1) {
|
|
782
540
|
throw new Error(`${name} must be a positive integer`);
|
|
@@ -822,1425 +580,1713 @@ function parseSelector(text) {
|
|
|
822
580
|
}
|
|
823
581
|
return { kind, value };
|
|
824
582
|
}
|
|
825
|
-
function
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
583
|
+
function start(verb, object, input) {
|
|
584
|
+
if (!input.path)
|
|
585
|
+
throw new Error(`${verb} ${object} requires a path`);
|
|
586
|
+
if (input.stdinName !== undefined && input.path !== "-")
|
|
587
|
+
throw new Error("stdinName requires '-' as the target");
|
|
588
|
+
const args = [];
|
|
589
|
+
pushOptionalString(args, "--readseek-dir", input.readseekDir);
|
|
590
|
+
args.push(verb, object, input.path);
|
|
591
|
+
pushOptionalString(args, "--stdin-name", input.stdinName);
|
|
592
|
+
return args;
|
|
593
|
+
}
|
|
594
|
+
function at2(args, value) {
|
|
595
|
+
if (value !== undefined) {
|
|
596
|
+
parseSelector(value);
|
|
597
|
+
args.push("--at", value);
|
|
829
598
|
}
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
599
|
+
}
|
|
600
|
+
function finish(args) {
|
|
601
|
+
args.push("--kdl");
|
|
602
|
+
return args;
|
|
603
|
+
}
|
|
604
|
+
function language(args, input) {
|
|
605
|
+
pushOptionalString(args, "--language", input.language);
|
|
606
|
+
}
|
|
607
|
+
function limit2(args, value) {
|
|
608
|
+
if (value !== undefined)
|
|
609
|
+
validatePositiveInteger(value, "limit");
|
|
610
|
+
pushOptionalNumber(args, "--limit", value);
|
|
611
|
+
}
|
|
612
|
+
function anchors(args, input) {
|
|
613
|
+
if (input.noAnchors)
|
|
614
|
+
args.push("--no-anchors");
|
|
615
|
+
}
|
|
616
|
+
function buildShowContentArgs(input) {
|
|
841
617
|
if (input.end !== undefined)
|
|
842
618
|
validatePositiveInteger(input.end, "end");
|
|
843
|
-
if (input.limit !== undefined)
|
|
844
|
-
validatePositiveInteger(input.limit, "limit");
|
|
845
|
-
if (input.end !== undefined && input.limit !== undefined) {
|
|
619
|
+
if (input.end !== undefined && input.limit !== undefined)
|
|
846
620
|
throw new Error("cannot combine end with limit");
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
if (!Number.isSafeInteger(input.depth) || input.depth < 0) {
|
|
850
|
-
throw new Error("depth must be a non-negative integer");
|
|
851
|
-
}
|
|
852
|
-
if (!hasMap)
|
|
853
|
-
throw new Error("depth requires the map facet");
|
|
854
|
-
}
|
|
855
|
-
if (input.selector !== undefined && input.query !== undefined) {
|
|
856
|
-
throw new Error("cannot combine selector with query");
|
|
857
|
-
}
|
|
858
|
-
if (!hasContent && (input.end !== undefined || input.limit !== undefined || input.query !== undefined)) {
|
|
859
|
-
throw new Error("ranges and queries require the content facet");
|
|
860
|
-
}
|
|
861
|
-
if (hasIdentity && input.selector === undefined) {
|
|
862
|
-
throw new Error("the identity facet requires a selector");
|
|
863
|
-
}
|
|
864
|
-
if (input.selector !== undefined && !hasContent && !hasIdentity) {
|
|
865
|
-
throw new Error("selectors require the content or identity facet");
|
|
866
|
-
}
|
|
867
|
-
if (input.selector !== undefined) {
|
|
868
|
-
const selector = parseSelector(input.selector);
|
|
869
|
-
if (selector.kind === "symbol" && hasIdentity) {
|
|
870
|
-
throw new Error("the identity facet does not accept symbol selectors");
|
|
871
|
-
}
|
|
872
|
-
if (selector.column !== undefined && !hasIdentity) {
|
|
873
|
-
throw new Error("selector columns require the identity facet");
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
const hasVision = input.visionMode !== undefined || input.visionLevel !== undefined;
|
|
877
|
-
if (hasVision && !hasContent) {
|
|
878
|
-
throw new Error("vision options require the content facet");
|
|
879
|
-
}
|
|
880
|
-
if (hasVision && hasSourceFacet) {
|
|
881
|
-
throw new Error("vision options cannot be combined with source facets");
|
|
882
|
-
}
|
|
883
|
-
const args = [];
|
|
884
|
-
if (input.readseekDir !== undefined)
|
|
885
|
-
args.push("--readseek-dir", input.readseekDir);
|
|
886
|
-
args.push("inspect", input.path);
|
|
887
|
-
if (input.selector !== undefined)
|
|
888
|
-
args.push(input.selector);
|
|
889
|
-
const select = selectArg(input.select);
|
|
890
|
-
if (select !== undefined)
|
|
891
|
-
args.push("--select", select);
|
|
892
|
-
pushOptionalString(args, "--query", input.query);
|
|
621
|
+
const args = start("show", "content", input);
|
|
622
|
+
at2(args, input.at);
|
|
893
623
|
pushOptionalNumber(args, "--end", input.end);
|
|
894
|
-
|
|
624
|
+
limit2(args, input.limit);
|
|
625
|
+
language(args, input);
|
|
626
|
+
anchors(args, input);
|
|
627
|
+
return finish(args);
|
|
628
|
+
}
|
|
629
|
+
function buildShowStructureArgs(input) {
|
|
630
|
+
if (input.depth !== undefined && (!Number.isSafeInteger(input.depth) || input.depth < 0))
|
|
631
|
+
throw new Error("depth must be a non-negative integer");
|
|
632
|
+
const args = start("show", "structure", input);
|
|
633
|
+
at2(args, input.at);
|
|
895
634
|
pushOptionalNumber(args, "--depth", input.depth);
|
|
896
|
-
pushOptionalString(args, "--
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
args
|
|
635
|
+
pushOptionalString(args, "--kind", input.kind);
|
|
636
|
+
language(args, input);
|
|
637
|
+
if (input.outline)
|
|
638
|
+
args.push("--outline");
|
|
639
|
+
return finish(args);
|
|
640
|
+
}
|
|
641
|
+
function buildShowMetadataArgs(input) {
|
|
642
|
+
const args = start("show", "metadata", input);
|
|
643
|
+
language(args, input);
|
|
644
|
+
return finish(args);
|
|
645
|
+
}
|
|
646
|
+
function buildShowAssetsArgs(input) {
|
|
647
|
+
if (input.at !== undefined && !["page", "node", "asset"].includes(parseSelector(input.at).kind))
|
|
648
|
+
throw new Error("assets requires a page, node, or asset selector");
|
|
649
|
+
const args = start("show", "assets", input);
|
|
650
|
+
at2(args, input.at);
|
|
651
|
+
return finish(args);
|
|
652
|
+
}
|
|
653
|
+
function buildCheckSyntaxArgs(input) {
|
|
654
|
+
const args = start("check", "syntax", input);
|
|
655
|
+
language(args, input);
|
|
656
|
+
return finish(args);
|
|
657
|
+
}
|
|
658
|
+
function visionArgs(verb, object, input) {
|
|
659
|
+
if (input.level !== undefined && !VISION_LEVELS.includes(input.level))
|
|
660
|
+
throw new Error("invalid vision level");
|
|
661
|
+
if (input.at !== undefined && !["page", "node", "asset"].includes(parseSelector(input.at).kind))
|
|
662
|
+
throw new Error("vision requires a document selector");
|
|
663
|
+
const args = start(verb, object, input);
|
|
664
|
+
at2(args, input.at);
|
|
665
|
+
pushOptionalString(args, "--level", input.level);
|
|
901
666
|
return args;
|
|
902
667
|
}
|
|
903
|
-
function
|
|
904
|
-
|
|
905
|
-
if (input.
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
668
|
+
function buildGenerateCaptionArgs(input) {
|
|
669
|
+
const args = visionArgs("generate", "caption", input);
|
|
670
|
+
if (input.include !== undefined) {
|
|
671
|
+
if (input.include.length === 0 || input.include.some((task) => task !== "text" && task !== "objects"))
|
|
672
|
+
throw new Error("include requires text or objects");
|
|
673
|
+
args.push("--include", input.include.join(","));
|
|
674
|
+
}
|
|
675
|
+
return finish(args);
|
|
676
|
+
}
|
|
677
|
+
function buildDetectObjectsArgs(input) {
|
|
678
|
+
return finish(visionArgs("detect", "objects", input));
|
|
679
|
+
}
|
|
680
|
+
function buildRecognizeTextArgs(input) {
|
|
681
|
+
return finish(visionArgs("recognize", "text", input));
|
|
682
|
+
}
|
|
683
|
+
function buildFindNodesArgs(input) {
|
|
684
|
+
const hasPattern = Boolean(input.pattern);
|
|
685
|
+
const hasRule = Boolean(input.rule);
|
|
686
|
+
const hasContext = Boolean(input.context);
|
|
687
|
+
if (hasRule) {
|
|
688
|
+
if (hasPattern || hasContext || input.selector)
|
|
689
|
+
throw new Error("rule cannot be combined with pattern, context, or selector");
|
|
690
|
+
} else if (!hasPattern && !hasContext) {
|
|
691
|
+
throw new Error("find nodes requires pattern, context, or rule");
|
|
692
|
+
}
|
|
693
|
+
if (hasContext && !input.selector) {
|
|
694
|
+
throw new Error("context requires selector");
|
|
695
|
+
}
|
|
696
|
+
if (hasPattern && hasContext) {
|
|
697
|
+
throw new Error("pattern and context cannot be combined");
|
|
698
|
+
}
|
|
699
|
+
const args = start("find", "nodes", input);
|
|
700
|
+
pushOptionalString(args, "--pattern", input.pattern);
|
|
701
|
+
pushOptionalString(args, "--context", input.context);
|
|
702
|
+
pushOptionalString(args, "--selector", input.selector);
|
|
703
|
+
pushOptionalString(args, "--rule", input.rule);
|
|
704
|
+
language(args, input);
|
|
705
|
+
limit2(args, input.limit);
|
|
706
|
+
appendGitScopeArgs(args, input);
|
|
707
|
+
anchors(args, input);
|
|
708
|
+
return finish(args);
|
|
919
709
|
}
|
|
920
|
-
function
|
|
921
|
-
const args =
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
pushOptionalNumber(args, "--limit", input.limit);
|
|
710
|
+
function buildFindTextArgs(input) {
|
|
711
|
+
const args = start("find", "text", input);
|
|
712
|
+
args.push("--text", input.text);
|
|
713
|
+
limit2(args, input.limit);
|
|
925
714
|
appendGitScopeArgs(args, input);
|
|
926
|
-
args
|
|
927
|
-
return args;
|
|
715
|
+
return finish(args);
|
|
928
716
|
}
|
|
929
|
-
function
|
|
930
|
-
const args =
|
|
931
|
-
|
|
932
|
-
|
|
717
|
+
function buildFindDefinitionsArgs(input) {
|
|
718
|
+
const args = start("find", "definitions", input);
|
|
719
|
+
args.push("--name", input.name);
|
|
720
|
+
language(args, input);
|
|
933
721
|
appendGitScopeArgs(args, input);
|
|
934
|
-
args
|
|
935
|
-
return args;
|
|
722
|
+
anchors(args, input);
|
|
723
|
+
return finish(args);
|
|
936
724
|
}
|
|
937
|
-
function
|
|
938
|
-
const validated =
|
|
725
|
+
function buildFindReferencesArgs(input) {
|
|
726
|
+
const validated = validateReferencesSelection(input);
|
|
939
727
|
if (!validated.ok)
|
|
940
728
|
throw new Error(validated.error);
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
pushOptionalString(args, "--
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
pushOptionalNumber(args, "--line", input.line);
|
|
948
|
-
pushOptionalNumber(args, "--column", input.column);
|
|
949
|
-
}
|
|
950
|
-
pushOptionalString(args, "--language", input.language);
|
|
729
|
+
if (input.at !== undefined && !["line", "hash"].includes(parseSelector(input.at).kind))
|
|
730
|
+
throw new Error("references requires a line or hash selector");
|
|
731
|
+
const args = start("find", "references", input);
|
|
732
|
+
pushOptionalString(args, "--name", input.name);
|
|
733
|
+
at2(args, input.at);
|
|
734
|
+
language(args, input);
|
|
951
735
|
appendGitScopeArgs(args, input);
|
|
952
|
-
args
|
|
953
|
-
return args;
|
|
736
|
+
anchors(args, input);
|
|
737
|
+
return finish(args);
|
|
954
738
|
}
|
|
955
|
-
function
|
|
956
|
-
const args =
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
739
|
+
function buildCheckRulesArgs(input) {
|
|
740
|
+
const args = start("check", "rules", input);
|
|
741
|
+
args.push("--rules", input.rules);
|
|
742
|
+
appendGitScopeArgs(args, input);
|
|
743
|
+
return finish(args);
|
|
744
|
+
}
|
|
745
|
+
function buildEditTextArgs(input) {
|
|
746
|
+
const args = start("edit", "text", input);
|
|
747
|
+
appendApplyAndPlanHash(args, input);
|
|
748
|
+
language(args, input);
|
|
749
|
+
appendGitScopeArgs(args, input);
|
|
963
750
|
if (input.requestFromStdin)
|
|
964
751
|
args.push("--edits", "-");
|
|
965
|
-
args
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
752
|
+
return finish(args);
|
|
753
|
+
}
|
|
754
|
+
function buildRenameSymbolArgs(input) {
|
|
755
|
+
if (!["line", "hash"].includes(parseSelector(input.at).kind))
|
|
756
|
+
throw new Error("rename requires a line or hash selector");
|
|
757
|
+
const args = start("rename", "symbol", input);
|
|
758
|
+
at2(args, input.at);
|
|
759
|
+
args.push("--to", input.to);
|
|
970
760
|
if (input.workspace !== undefined)
|
|
971
761
|
args.push(`--workspace=${input.workspace}`);
|
|
972
|
-
appendApplyAndPlanHash(args, {
|
|
973
|
-
|
|
974
|
-
planHash: input.planHash,
|
|
975
|
-
flagOrder: input.flagOrder ?? "plan-hash-first"
|
|
976
|
-
});
|
|
977
|
-
pushOptionalString(args, "--language", input.language);
|
|
762
|
+
appendApplyAndPlanHash(args, { ...input, flagOrder: input.flagOrder ?? "plan-hash-first" });
|
|
763
|
+
language(args, input);
|
|
978
764
|
appendGitScopeArgs(args, input);
|
|
979
|
-
args
|
|
980
|
-
return args;
|
|
981
|
-
}
|
|
982
|
-
// src/platform.ts
|
|
983
|
-
import { accessSync, constants as fsConstants, existsSync, statSync } from "node:fs";
|
|
984
|
-
import { createRequire } from "node:module";
|
|
985
|
-
import { homedir } from "node:os";
|
|
986
|
-
import path from "node:path";
|
|
987
|
-
var READSEEK_BINARY_ENV = "READSEEK_BINARY";
|
|
988
|
-
var READSEEK_PLATFORM_PACKAGES = {
|
|
989
|
-
"darwin-arm64": "@jarkkojs/readseek-darwin-arm64",
|
|
990
|
-
"linux-arm64": "@jarkkojs/readseek-linux-arm64",
|
|
991
|
-
"linux-x64": "@jarkkojs/readseek-linux-x64",
|
|
992
|
-
"win32-x64": "@jarkkojs/readseek-win32-x64"
|
|
993
|
-
};
|
|
994
|
-
var resolveFromPackage = createRequire(import.meta.url).resolve;
|
|
995
|
-
function readSeekBinaryName(platform = process.platform) {
|
|
996
|
-
if (platform === "linux")
|
|
997
|
-
return "readseek.AppImage";
|
|
998
|
-
return platform === "win32" ? "readseek.exe" : "readseek";
|
|
765
|
+
return finish(args);
|
|
999
766
|
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
if (binaryPath === undefined)
|
|
1006
|
-
return null;
|
|
1007
|
-
if (!path.isAbsolute(binaryPath)) {
|
|
1008
|
-
throw new Error(`${READSEEK_BINARY_ENV} must be an absolute path to the readseek executable`);
|
|
1009
|
-
}
|
|
767
|
+
// src/client-output.ts
|
|
768
|
+
import { Type } from "@sinclair/typebox";
|
|
769
|
+
import { AssertError, Value } from "@sinclair/typebox/value";
|
|
770
|
+
var OPERATIONS = ["Clone", "Clean", "Default", "Assert"];
|
|
771
|
+
function parse(schema, value, what) {
|
|
1010
772
|
try {
|
|
1011
|
-
|
|
1012
|
-
throw new Error("not a regular file");
|
|
1013
|
-
accessSync(binaryPath, fsConstants.X_OK);
|
|
773
|
+
return Value.Parse(OPERATIONS, schema, value);
|
|
1014
774
|
} catch (error) {
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
return binaryPath;
|
|
1020
|
-
}
|
|
1021
|
-
function resolveReadSeekBinaryFromPackages(resolver = resolveFromPackage, options = {}) {
|
|
1022
|
-
const resolve = typeof resolver === "function" ? resolver : resolver.resolve.bind(resolver);
|
|
1023
|
-
const platform = options.platform ?? process.platform;
|
|
1024
|
-
const arch = options.arch ?? process.arch;
|
|
1025
|
-
const key = readSeekPlatformKey(platform, arch);
|
|
1026
|
-
const platformPackage = READSEEK_PLATFORM_PACKAGES[key];
|
|
1027
|
-
if (!platformPackage) {
|
|
1028
|
-
const supported = Object.keys(READSEEK_PLATFORM_PACKAGES).join(", ");
|
|
1029
|
-
throw new Error(`@jarkkojs/readseek ships no binary for ${key}; it supports ${supported}`);
|
|
1030
|
-
}
|
|
1031
|
-
const metaPackage = options.metaPackage ?? "@jarkkojs/readseek";
|
|
1032
|
-
let packageJsonPath;
|
|
1033
|
-
try {
|
|
1034
|
-
const metaPackageJson = resolve(`${metaPackage}/package.json`);
|
|
1035
|
-
const metaPackageDir = path.dirname(metaPackageJson);
|
|
1036
|
-
packageJsonPath = resolve(`${platformPackage}/package.json`, {
|
|
1037
|
-
paths: [metaPackageDir]
|
|
1038
|
-
});
|
|
1039
|
-
} catch {
|
|
1040
|
-
packageJsonPath = resolve(`${platformPackage}/package.json`);
|
|
775
|
+
if (!(error instanceof AssertError))
|
|
776
|
+
throw error;
|
|
777
|
+
const detail = error.error;
|
|
778
|
+
throw new Error(`invalid readseek ${what}${detail?.path ?? ""}: ${detail?.message ?? "invalid value"}`);
|
|
1041
779
|
}
|
|
1042
|
-
const binaryPath = path.join(path.dirname(packageJsonPath), "bin", readSeekBinaryName(platform));
|
|
1043
|
-
accessSync(binaryPath, fsConstants.X_OK);
|
|
1044
|
-
return binaryPath;
|
|
1045
780
|
}
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
781
|
+
var Int = Type.Integer({ minimum: Number.MIN_SAFE_INTEGER, maximum: Number.MAX_SAFE_INTEGER });
|
|
782
|
+
var Str = Type.String();
|
|
783
|
+
var Bool = Type.Boolean();
|
|
784
|
+
var OptStr = Type.Optional(Str);
|
|
785
|
+
var OptInt = Type.Optional(Int);
|
|
786
|
+
var Hashline = Type.Object({ line: Int, hash: Str, text: Str });
|
|
787
|
+
var Hashlines = Type.Array(Hashline);
|
|
788
|
+
var ReadOutput = Type.Object({
|
|
789
|
+
file: Str,
|
|
790
|
+
language: Str,
|
|
791
|
+
line_count: Int,
|
|
792
|
+
file_hash: Str,
|
|
793
|
+
start_line: Int,
|
|
794
|
+
end_line: Int,
|
|
795
|
+
hashlines: Hashlines,
|
|
796
|
+
truncated: Type.Optional(Bool)
|
|
797
|
+
});
|
|
798
|
+
var SymbolOutput = Type.Object({
|
|
799
|
+
kind: Str,
|
|
800
|
+
name: Str,
|
|
801
|
+
qualified_name: OptStr,
|
|
802
|
+
start_line: Int,
|
|
803
|
+
end_line: Int,
|
|
804
|
+
start_hash: OptStr,
|
|
805
|
+
end_hash: OptStr,
|
|
806
|
+
start_anchor: OptStr,
|
|
807
|
+
end_anchor: OptStr
|
|
808
|
+
});
|
|
809
|
+
function mapNodeShape(child) {
|
|
810
|
+
return Type.Object({
|
|
811
|
+
kind: Str,
|
|
812
|
+
name: Str,
|
|
813
|
+
start_line: Int,
|
|
814
|
+
end_line: Int,
|
|
815
|
+
start_anchor: Str,
|
|
816
|
+
end_anchor: Str,
|
|
817
|
+
children: Type.Array(child)
|
|
818
|
+
});
|
|
1070
819
|
}
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
import { homedir as homedir2 } from "node:os";
|
|
1074
|
-
import path2 from "node:path";
|
|
1075
|
-
var UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
1076
|
-
function canonicalPathKey(cwd, filePath) {
|
|
1077
|
-
const resolved = path2.resolve(cwd, filePath);
|
|
1078
|
-
try {
|
|
1079
|
-
return realpathSync.native(resolved);
|
|
1080
|
-
} catch {
|
|
1081
|
-
return resolved;
|
|
1082
|
-
}
|
|
820
|
+
function recursiveStructureNode() {
|
|
821
|
+
return Type.Recursive((self) => mapNodeShape(self));
|
|
1083
822
|
}
|
|
1084
|
-
function
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
823
|
+
var StructureNode = typeof Type.Recursive === "function" ? recursiveStructureNode() : Type.Cyclic({ StructureNode: mapNodeShape(Type.Ref("StructureNode")) }, "StructureNode");
|
|
824
|
+
var StructureOutput = Type.Object({
|
|
825
|
+
file: Str,
|
|
826
|
+
language: Str,
|
|
827
|
+
line_count: Int,
|
|
828
|
+
file_hash: Str,
|
|
829
|
+
root: Type.Optional(StructureNode),
|
|
830
|
+
symbols: Type.Array(SymbolOutput)
|
|
831
|
+
});
|
|
832
|
+
var SearchSpan = {
|
|
833
|
+
start_byte: OptInt,
|
|
834
|
+
end_byte: OptInt,
|
|
835
|
+
text: OptStr,
|
|
836
|
+
start_line: Int,
|
|
837
|
+
end_line: Int,
|
|
838
|
+
start_hash: Str,
|
|
839
|
+
end_hash: Str,
|
|
840
|
+
hashlines: Hashlines
|
|
841
|
+
};
|
|
842
|
+
var SearchCapture = Type.Object({ name: Str, ...SearchSpan });
|
|
843
|
+
var SearchMatch = Type.Object({
|
|
844
|
+
pattern_index: Type.Integer({ default: 0 }),
|
|
845
|
+
...SearchSpan,
|
|
846
|
+
captures: Type.Array(SearchCapture)
|
|
847
|
+
});
|
|
848
|
+
var SearchFileOutput = Type.Object({
|
|
849
|
+
file: Str,
|
|
850
|
+
language: Str,
|
|
851
|
+
file_hash: Str,
|
|
852
|
+
matches: Type.Array(SearchMatch)
|
|
853
|
+
});
|
|
854
|
+
var SearchEnvelope = Type.Object({
|
|
855
|
+
results: Type.Array(SearchFileOutput),
|
|
856
|
+
returned_matches: OptInt,
|
|
857
|
+
truncated: Type.Optional(Bool),
|
|
858
|
+
byte_basis: OptStr
|
|
859
|
+
});
|
|
860
|
+
var RefsEnvelope = Type.Object({
|
|
861
|
+
references: Type.Array(Type.Object({
|
|
862
|
+
file: Str,
|
|
863
|
+
line: Int,
|
|
864
|
+
column: Int,
|
|
865
|
+
line_hash: Str,
|
|
866
|
+
text: Str,
|
|
867
|
+
symbol: Type.Optional(Type.Object({ qualified_name: OptStr }))
|
|
868
|
+
}))
|
|
869
|
+
});
|
|
870
|
+
var Diagnostic = Type.Object({
|
|
871
|
+
kind: Type.Union([Type.Literal("error"), Type.Literal("missing")]),
|
|
872
|
+
start_line: Int,
|
|
873
|
+
end_line: Int
|
|
874
|
+
});
|
|
875
|
+
var CheckEnvelope = Type.Object({
|
|
876
|
+
file_hash: OptStr,
|
|
877
|
+
error_count: Int,
|
|
878
|
+
missing_count: Int,
|
|
879
|
+
diagnostics: Type.Array(Diagnostic)
|
|
880
|
+
});
|
|
881
|
+
var DetectedObject = Type.Object({
|
|
882
|
+
label: Str,
|
|
883
|
+
bbox: Type.Tuple([Int, Int, Int, Int])
|
|
884
|
+
});
|
|
885
|
+
var SourceDetection = Type.Object({
|
|
886
|
+
kind: Type.Literal("source"),
|
|
887
|
+
type: Str,
|
|
888
|
+
file: Str,
|
|
889
|
+
language: Str,
|
|
890
|
+
engine: OptStr,
|
|
891
|
+
supported: Bool,
|
|
892
|
+
mime: OptStr,
|
|
893
|
+
syntax: OptStr
|
|
894
|
+
});
|
|
895
|
+
var ImageDetection = Type.Object({
|
|
896
|
+
kind: Type.Literal("image"),
|
|
897
|
+
type: Str,
|
|
898
|
+
file: Str,
|
|
899
|
+
mime: OptStr,
|
|
900
|
+
format: Str,
|
|
901
|
+
width: Int,
|
|
902
|
+
height: Int,
|
|
903
|
+
animated: Bool,
|
|
904
|
+
ocr: OptStr,
|
|
905
|
+
caption: OptStr,
|
|
906
|
+
objects: Type.Optional(Type.Array(DetectedObject))
|
|
907
|
+
});
|
|
908
|
+
var TextDetection = Type.Object({
|
|
909
|
+
kind: Type.Literal("text"),
|
|
910
|
+
type: Str,
|
|
911
|
+
file: Str,
|
|
912
|
+
mime: OptStr
|
|
913
|
+
});
|
|
914
|
+
var PdfDetection = Type.Object({
|
|
915
|
+
kind: Type.Literal("pdf"),
|
|
916
|
+
type: Type.Literal("application/pdf"),
|
|
917
|
+
file: Str,
|
|
918
|
+
mime: OptStr,
|
|
919
|
+
format: Type.Literal("pdf"),
|
|
920
|
+
pages: Int
|
|
921
|
+
});
|
|
922
|
+
var Detection = Type.Union([SourceDetection, ImageDetection, TextDetection, PdfDetection]);
|
|
923
|
+
var SourceDetectionInput = Type.Omit(SourceDetection, ["kind"]);
|
|
924
|
+
var ImageDetectionInput = Type.Omit(ImageDetection, ["kind"]);
|
|
925
|
+
var TextDetectionInput = Type.Omit(TextDetection, ["kind"]);
|
|
926
|
+
var PdfDetectionInput = Type.Omit(PdfDetection, ["kind"]);
|
|
927
|
+
var UnspannedContent = Type.Omit(ReadOutput, ["start_line", "end_line"]);
|
|
928
|
+
var PdfMetadata = Type.Object({ source: Str, format: Type.Literal("pdf"), pages: Int });
|
|
929
|
+
var DocumentCache = Type.Object({
|
|
930
|
+
content_hash: Str,
|
|
931
|
+
state: Type.Union([Type.Literal("built"), Type.Literal("reused")])
|
|
932
|
+
});
|
|
933
|
+
var Identifier = Type.Object({
|
|
934
|
+
text: Str,
|
|
935
|
+
start_column: Int,
|
|
936
|
+
end_column: Int,
|
|
937
|
+
start_byte: Int,
|
|
938
|
+
end_byte: Int
|
|
939
|
+
});
|
|
940
|
+
var CursorEnvelope = Type.Object({
|
|
941
|
+
file: Str,
|
|
942
|
+
language: Str,
|
|
943
|
+
engine: OptStr,
|
|
944
|
+
line_count: Int,
|
|
945
|
+
file_hash: Str,
|
|
946
|
+
line: Int,
|
|
947
|
+
column: Int,
|
|
948
|
+
line_hash: Str,
|
|
949
|
+
identifier: Type.Optional(Identifier),
|
|
950
|
+
symbol: Type.Optional(Type.Object({
|
|
951
|
+
name: Str,
|
|
952
|
+
kind: Str,
|
|
953
|
+
qualified_name: Str,
|
|
954
|
+
start_line: Int,
|
|
955
|
+
end_line: Int
|
|
956
|
+
}))
|
|
957
|
+
});
|
|
958
|
+
var EditOutputSchema = Type.Object({
|
|
959
|
+
file: Str,
|
|
960
|
+
before_hash: Str,
|
|
961
|
+
file_hash: Str,
|
|
962
|
+
plan_hash: Str,
|
|
963
|
+
applied: Bool,
|
|
964
|
+
changed: Bool,
|
|
965
|
+
edit_count: Int,
|
|
966
|
+
before_content: OptStr,
|
|
967
|
+
content: OptStr
|
|
968
|
+
});
|
|
969
|
+
var RenameConflictSchema = Type.Object({ line: Int, column: Int, reason: Str });
|
|
970
|
+
var RenameEditSchema = Type.Object({
|
|
971
|
+
line: Int,
|
|
972
|
+
start_column: Int,
|
|
973
|
+
end_column: Int,
|
|
974
|
+
start_byte: Int,
|
|
975
|
+
end_byte: Int,
|
|
976
|
+
occurrence: Str,
|
|
977
|
+
line_hash: Str,
|
|
978
|
+
text: Str
|
|
979
|
+
});
|
|
980
|
+
var Conflicts = Type.Array(RenameConflictSchema, { default: [] });
|
|
981
|
+
var Edits = Type.Array(RenameEditSchema, { default: [] });
|
|
982
|
+
var RenameFileOutputSchema = Type.Object({
|
|
983
|
+
file: Str,
|
|
984
|
+
language: Str,
|
|
985
|
+
engine: OptStr,
|
|
986
|
+
file_hash: Str,
|
|
987
|
+
conflicts: Conflicts,
|
|
988
|
+
edits: Edits
|
|
989
|
+
});
|
|
990
|
+
var RenameOutputSchema = Type.Object({
|
|
991
|
+
file: Str,
|
|
992
|
+
language: Str,
|
|
993
|
+
engine: OptStr,
|
|
994
|
+
file_hash: Str,
|
|
995
|
+
old_name: Str,
|
|
996
|
+
new_name: Str,
|
|
997
|
+
plan_hash: Str,
|
|
998
|
+
applied: Bool,
|
|
999
|
+
conflicts: Conflicts,
|
|
1000
|
+
edits: Edits,
|
|
1001
|
+
others: Type.Array(RenameFileOutputSchema, { default: [] })
|
|
1002
|
+
});
|
|
1003
|
+
var DefEnvelope = Type.Object({
|
|
1004
|
+
locations: Type.Array(Type.Object({
|
|
1005
|
+
file: Str,
|
|
1006
|
+
line: Int,
|
|
1007
|
+
column: Int,
|
|
1008
|
+
line_hash: Str,
|
|
1009
|
+
text: Str,
|
|
1010
|
+
kind: OptStr,
|
|
1011
|
+
name: OptStr,
|
|
1012
|
+
qualified_name: OptStr
|
|
1013
|
+
}))
|
|
1014
|
+
});
|
|
1015
|
+
function parseReadOutput(value) {
|
|
1016
|
+
return parse(ReadOutput, value, "read output");
|
|
1092
1017
|
}
|
|
1093
|
-
function
|
|
1094
|
-
|
|
1095
|
-
return path2.isAbsolute(expanded) ? expanded : path2.resolve(cwd, expanded);
|
|
1018
|
+
function parseStructureOutput(value) {
|
|
1019
|
+
return parse(StructureOutput, value, "structure output");
|
|
1096
1020
|
}
|
|
1097
|
-
function
|
|
1098
|
-
const
|
|
1099
|
-
|
|
1021
|
+
function parseSearchOutput(value) {
|
|
1022
|
+
const envelope = parse(SearchEnvelope, value, "search output");
|
|
1023
|
+
const results = envelope.results;
|
|
1024
|
+
if (envelope.returned_matches !== undefined)
|
|
1025
|
+
results.returned_matches = envelope.returned_matches;
|
|
1026
|
+
if (envelope.truncated !== undefined)
|
|
1027
|
+
results.truncated = envelope.truncated;
|
|
1028
|
+
if (envelope.byte_basis !== undefined)
|
|
1029
|
+
results.byte_basis = envelope.byte_basis;
|
|
1030
|
+
return results;
|
|
1100
1031
|
}
|
|
1101
|
-
function
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
lstatSync(ancestor);
|
|
1107
|
-
} catch (error) {
|
|
1108
|
-
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT")
|
|
1109
|
-
throw error;
|
|
1110
|
-
const parent = path2.dirname(ancestor);
|
|
1111
|
-
if (parent === ancestor)
|
|
1112
|
-
throw error;
|
|
1113
|
-
missing.push(path2.basename(ancestor));
|
|
1114
|
-
ancestor = parent;
|
|
1115
|
-
continue;
|
|
1116
|
-
}
|
|
1117
|
-
return path2.join(realpathSync.native(ancestor), ...missing.reverse());
|
|
1118
|
-
}
|
|
1032
|
+
function parseRefsOutput(value) {
|
|
1033
|
+
return parse(RefsEnvelope, value, "refs output").references.map(({ symbol, ...reference }) => ({
|
|
1034
|
+
...reference,
|
|
1035
|
+
enclosingSymbol: symbol?.qualified_name
|
|
1036
|
+
}));
|
|
1119
1037
|
}
|
|
1120
|
-
function
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1038
|
+
function parseCheckOutput(value) {
|
|
1039
|
+
const output = parse(CheckEnvelope, value, "check output");
|
|
1040
|
+
return {
|
|
1041
|
+
file_hash: output.file_hash,
|
|
1042
|
+
errorCount: output.error_count,
|
|
1043
|
+
missingCount: output.missing_count,
|
|
1044
|
+
diagnostics: output.diagnostics
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
function parseDetectOutput(value) {
|
|
1048
|
+
const output = value ?? {};
|
|
1049
|
+
if (output.type === "application/pdf") {
|
|
1050
|
+
return { kind: "pdf", ...parse(PdfDetectionInput, value, "detect output") };
|
|
1129
1051
|
}
|
|
1130
|
-
if (
|
|
1131
|
-
return {
|
|
1052
|
+
if (output.width !== undefined || output.height !== undefined) {
|
|
1053
|
+
return { kind: "image", ...parse(ImageDetectionInput, value, "detect output") };
|
|
1132
1054
|
}
|
|
1133
|
-
|
|
1134
|
-
}
|
|
1135
|
-
// src/error.ts
|
|
1136
|
-
var READSEEK_USAGE_HINT = /(?:^|\n)\s*Run readseek(?: [\w-]+)* --help for more information\.?\s*$/;
|
|
1137
|
-
function cleanReadSeekErrorText(stderr) {
|
|
1138
|
-
return stderr.replace(READSEEK_USAGE_HINT, "").replace(/^error:\s*/i, "").replace(/\s*\n\s*/g, " ").trim();
|
|
1139
|
-
}
|
|
1140
|
-
// src/kdl.ts
|
|
1141
|
-
import { parse } from "@bgotink/kdl";
|
|
1142
|
-
function convertNode(node) {
|
|
1143
|
-
if (node.getTag() !== null)
|
|
1144
|
-
throw new Error("KDL node annotations are not supported");
|
|
1145
|
-
const properties = new Map;
|
|
1146
|
-
for (const entry of node.entries) {
|
|
1147
|
-
const name = entry.getName();
|
|
1148
|
-
if (name === null)
|
|
1149
|
-
throw new Error("KDL positional arguments are not supported");
|
|
1150
|
-
if (properties.has(name))
|
|
1151
|
-
throw new Error(`KDL duplicate property '${name}'`);
|
|
1152
|
-
if (entry.getTag() !== null)
|
|
1153
|
-
throw new Error("KDL value annotations are not supported");
|
|
1154
|
-
const value = entry.getValue();
|
|
1155
|
-
if (value === null)
|
|
1156
|
-
throw new Error("KDL null values are not supported");
|
|
1157
|
-
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
1158
|
-
throw new Error("KDL number out of range");
|
|
1159
|
-
}
|
|
1160
|
-
properties.set(name, value);
|
|
1055
|
+
if (output.language !== undefined) {
|
|
1056
|
+
return { kind: "source", ...parse(SourceDetectionInput, value, "detect output") };
|
|
1161
1057
|
}
|
|
1058
|
+
return { kind: "text", ...parse(TextDetectionInput, value, "detect output") };
|
|
1059
|
+
}
|
|
1060
|
+
function parseTextContent(value) {
|
|
1061
|
+
const output = value ?? {};
|
|
1062
|
+
if (output.hashlines === undefined || output.start_line !== undefined)
|
|
1063
|
+
return parseReadOutput(value);
|
|
1064
|
+
const spanned = parse(UnspannedContent, value, "content");
|
|
1162
1065
|
return {
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1066
|
+
...spanned,
|
|
1067
|
+
start_line: spanned.hashlines[0]?.line ?? 1,
|
|
1068
|
+
end_line: spanned.hashlines[spanned.hashlines.length - 1]?.line ?? 0
|
|
1166
1069
|
};
|
|
1167
1070
|
}
|
|
1168
|
-
function
|
|
1169
|
-
|
|
1170
|
-
if (document.nodes.length !== 1)
|
|
1171
|
-
throw new Error("KDL document must contain exactly one root node");
|
|
1172
|
-
return convertNode(document.nodes[0]);
|
|
1071
|
+
function parseCursorOutput(value) {
|
|
1072
|
+
return parse(CursorEnvelope, value, "cursor output");
|
|
1173
1073
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1074
|
+
function parsePdfMetadata(value) {
|
|
1075
|
+
if (!value || typeof value !== "object")
|
|
1076
|
+
return;
|
|
1077
|
+
if (value.format !== "pdf")
|
|
1078
|
+
return;
|
|
1079
|
+
const document = parse(PdfMetadata, value, "inspect metadata");
|
|
1080
|
+
return { kind: "pdf", type: "application/pdf", file: document.source, format: "pdf", pages: document.pages };
|
|
1178
1081
|
}
|
|
1179
|
-
function
|
|
1180
|
-
return
|
|
1082
|
+
function parseEditOutput(value) {
|
|
1083
|
+
return parse(EditOutputSchema, value, "edit output");
|
|
1181
1084
|
}
|
|
1182
|
-
function
|
|
1183
|
-
return
|
|
1085
|
+
function parseRenameOutput(value) {
|
|
1086
|
+
return parse(RenameOutputSchema, value, "rename output");
|
|
1184
1087
|
}
|
|
1185
|
-
function
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1088
|
+
function parseDefOutput(value) {
|
|
1089
|
+
return parse(DefEnvelope, value, "def output").locations;
|
|
1090
|
+
}
|
|
1091
|
+
var Bbox = Type.Object({ x: Type.Number(), y: Type.Number(), width: Type.Number(), height: Type.Number() });
|
|
1092
|
+
var Position = { page: OptInt, destination: OptStr, bbox: Type.Optional(Bbox) };
|
|
1093
|
+
var Provenance = { inferred: Type.Optional(Bool), model: OptStr, level: OptStr, task: OptStr };
|
|
1094
|
+
var ImageDescriptor = Type.Object({
|
|
1095
|
+
id: OptStr,
|
|
1096
|
+
kind: Type.Optional(Type.Literal("image")),
|
|
1097
|
+
content_identity: OptStr,
|
|
1098
|
+
path: Str,
|
|
1099
|
+
mime: Str,
|
|
1100
|
+
width: Int,
|
|
1101
|
+
height: Int,
|
|
1102
|
+
caption: OptStr,
|
|
1103
|
+
ocr: OptStr,
|
|
1104
|
+
objects: Type.Optional(Type.Array(DetectedObject)),
|
|
1105
|
+
...Provenance
|
|
1106
|
+
});
|
|
1107
|
+
var DocumentNode = Type.Object({
|
|
1108
|
+
id: Str,
|
|
1109
|
+
kind: Str,
|
|
1110
|
+
parent_id: OptStr,
|
|
1111
|
+
title: OptStr,
|
|
1112
|
+
level: OptInt,
|
|
1113
|
+
column: OptInt,
|
|
1114
|
+
text: OptStr,
|
|
1115
|
+
...Position
|
|
1116
|
+
});
|
|
1117
|
+
var DocumentAsset = Type.Object({
|
|
1118
|
+
id: Str,
|
|
1119
|
+
kind: Str,
|
|
1120
|
+
mime: Str,
|
|
1121
|
+
path: OptStr,
|
|
1122
|
+
content_identity: OptStr,
|
|
1123
|
+
bytes: OptInt,
|
|
1124
|
+
...Position
|
|
1125
|
+
});
|
|
1126
|
+
var DocumentVision = Type.Object({
|
|
1127
|
+
asset_id: Str,
|
|
1128
|
+
mode: OptStr,
|
|
1129
|
+
caption: OptStr,
|
|
1130
|
+
ocr: OptStr,
|
|
1131
|
+
objects: Type.Optional(Type.Array(DetectedObject)),
|
|
1132
|
+
caption_requested: Type.Optional(Bool),
|
|
1133
|
+
objects_requested: Type.Optional(Bool),
|
|
1134
|
+
ocr_requested: Type.Optional(Bool),
|
|
1135
|
+
...Provenance
|
|
1136
|
+
});
|
|
1137
|
+
var DocumentOutput = Type.Object({
|
|
1138
|
+
id: OptStr,
|
|
1139
|
+
format: Str,
|
|
1140
|
+
source: Str,
|
|
1141
|
+
title: OptStr,
|
|
1142
|
+
pages: Int,
|
|
1143
|
+
nodes: Type.Array(DocumentNode, { default: [] }),
|
|
1144
|
+
assets: Type.Array(DocumentAsset, { default: [] }),
|
|
1145
|
+
vision: Type.Array(DocumentVision, { default: [] })
|
|
1146
|
+
});
|
|
1147
|
+
var TextHit = Type.Object({
|
|
1148
|
+
line: Int,
|
|
1149
|
+
column: Int,
|
|
1150
|
+
text: Str,
|
|
1151
|
+
start_line: Int,
|
|
1152
|
+
end_line: Int,
|
|
1153
|
+
start_byte: Int,
|
|
1154
|
+
end_byte: Int,
|
|
1155
|
+
hashlines: Hashlines
|
|
1156
|
+
});
|
|
1157
|
+
var DocumentHit = Type.Object({ node_id: Str, kind: Str, snippet: Str, page: OptInt });
|
|
1158
|
+
var TextSearchOutput = Type.Object({
|
|
1159
|
+
text: Str,
|
|
1160
|
+
mode: Type.Literal("literal"),
|
|
1161
|
+
total_matches: Int,
|
|
1162
|
+
returned_matches: Int,
|
|
1163
|
+
truncated: Bool,
|
|
1164
|
+
results: Type.Array(Type.Object({ file: Str, file_hash: Str, matches: Type.Array(TextHit) })),
|
|
1165
|
+
documents: Type.Array(Type.Object({ file: Str, content_hash: Str, hits: Type.Array(DocumentHit) }))
|
|
1166
|
+
});
|
|
1167
|
+
var RuleFinding = Type.Object({
|
|
1168
|
+
name: Str,
|
|
1169
|
+
message: Str,
|
|
1170
|
+
path: Str,
|
|
1171
|
+
language: Str,
|
|
1172
|
+
start_byte: Int,
|
|
1173
|
+
end_byte: Int,
|
|
1174
|
+
line: Int,
|
|
1175
|
+
column: Int,
|
|
1176
|
+
end_line: Int,
|
|
1177
|
+
end_column: Int
|
|
1178
|
+
});
|
|
1179
|
+
var RulesOutput = Type.Object({
|
|
1180
|
+
complete: Bool,
|
|
1181
|
+
check_count: Int,
|
|
1182
|
+
file_count: Int,
|
|
1183
|
+
violation_count: Int,
|
|
1184
|
+
diagnostics: Type.Array(RuleFinding)
|
|
1185
|
+
});
|
|
1186
|
+
function parseDocumentOutput(value) {
|
|
1187
|
+
return parse(DocumentOutput, value, "document output");
|
|
1190
1188
|
}
|
|
1191
|
-
function
|
|
1192
|
-
const
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
const
|
|
1198
|
-
if (!match)
|
|
1199
|
-
throw new Error(`invalid readseek KDL line anchor: ${anchor}`);
|
|
1189
|
+
function parseContentOutput(value) {
|
|
1190
|
+
const output = value;
|
|
1191
|
+
if (output?.format !== undefined)
|
|
1192
|
+
return parseDocumentOutput(value);
|
|
1193
|
+
if (!output || output.metadata === undefined || output.content === undefined)
|
|
1194
|
+
throw new Error("invalid readseek content: missing metadata or content");
|
|
1195
|
+
const metadata = parseDetectOutput(output.metadata);
|
|
1200
1196
|
return {
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1197
|
+
metadata,
|
|
1198
|
+
content: metadata.kind === "image" ? parse(ImageDescriptor, output.content, "image descriptor") : parseTextContent(output.content),
|
|
1199
|
+
...output.cursor !== undefined ? { cursor: parseCursorOutput(output.cursor) } : {}
|
|
1204
1200
|
};
|
|
1205
1201
|
}
|
|
1206
|
-
function
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1202
|
+
function parseStructureEnvelope(value) {
|
|
1203
|
+
const output = value;
|
|
1204
|
+
if (output?.format !== undefined)
|
|
1205
|
+
return parseDocumentOutput(value);
|
|
1206
|
+
if (!output || output.structure === undefined)
|
|
1207
|
+
throw new Error("invalid readseek structure: missing structure");
|
|
1208
|
+
return { ...output.metadata !== undefined ? { metadata: parseDetectOutput(output.metadata) } : {}, structure: parseStructureOutput(output.structure) };
|
|
1209
|
+
}
|
|
1210
|
+
function parseTextSearchOutput(value) {
|
|
1211
|
+
return parse(TextSearchOutput, value, "text search output");
|
|
1212
|
+
}
|
|
1213
|
+
function parseRulesOutput(value) {
|
|
1214
|
+
return parse(RulesOutput, value, "rules output");
|
|
1215
|
+
}
|
|
1216
|
+
var SourceAssetsOutput = Type.Object({ file: OptStr, metadata: Type.Optional(Detection), assets: Type.Array(DocumentAsset, { default: [] }) });
|
|
1217
|
+
function parseAssetsOutput(value) {
|
|
1218
|
+
const raw = value;
|
|
1219
|
+
if (raw?.format !== undefined)
|
|
1220
|
+
return parseDocumentOutput(value);
|
|
1221
|
+
if (!raw || raw.file === undefined && raw.metadata === undefined)
|
|
1222
|
+
throw new Error("invalid readseek assets output: missing file or metadata");
|
|
1223
|
+
return parse(SourceAssetsOutput, { ...raw, ...raw.metadata !== undefined ? { metadata: parseDetectOutput(raw.metadata) } : {} }, "assets output");
|
|
1211
1224
|
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
requireProperty(object, "ymin"),
|
|
1222
|
-
requireProperty(object, "xmax"),
|
|
1223
|
-
requireProperty(object, "ymax")
|
|
1224
|
-
]
|
|
1225
|
-
}));
|
|
1226
|
-
}
|
|
1225
|
+
|
|
1226
|
+
// src/edit-plan.ts
|
|
1227
|
+
import { Document, Node, format } from "@bgotink/kdl";
|
|
1228
|
+
function node(name, properties, children = []) {
|
|
1229
|
+
const result = Node.create(name);
|
|
1230
|
+
for (const [key, value] of Object.entries(properties))
|
|
1231
|
+
result.setProperty(key, value);
|
|
1232
|
+
if (children.length > 0)
|
|
1233
|
+
result.children = new Document(children);
|
|
1227
1234
|
return result;
|
|
1228
1235
|
}
|
|
1229
|
-
function
|
|
1230
|
-
|
|
1236
|
+
function editNode(edit) {
|
|
1237
|
+
if ("set_line" in edit) {
|
|
1238
|
+
const value = edit.set_line;
|
|
1239
|
+
return node("set-line", { anchor: value.anchor, text: value.new_text });
|
|
1240
|
+
}
|
|
1241
|
+
if ("replace_lines" in edit) {
|
|
1242
|
+
const value = edit.replace_lines;
|
|
1243
|
+
return node("replace-lines", { start: value.start_anchor, end: value.end_anchor, text: value.new_text });
|
|
1244
|
+
}
|
|
1245
|
+
if ("insert_after" in edit) {
|
|
1246
|
+
const value = edit.insert_after;
|
|
1247
|
+
return node("insert-after", { anchor: value.anchor, text: value.new_text });
|
|
1248
|
+
}
|
|
1249
|
+
if ("replace_symbol" in edit) {
|
|
1250
|
+
const value = edit.replace_symbol;
|
|
1251
|
+
return node("replace-symbol", { symbol: value.symbol, body: value.new_body });
|
|
1252
|
+
}
|
|
1253
|
+
const value = edit.replace;
|
|
1254
|
+
return node("replace", {
|
|
1255
|
+
old: value.old_text,
|
|
1256
|
+
new: value.new_text,
|
|
1257
|
+
...value.all === undefined ? {} : { all: value.all }
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1260
|
+
function serializeEditPlan(edits) {
|
|
1261
|
+
const validation = validateExactlyOneEditVariant(edits);
|
|
1262
|
+
if (!validation.ok)
|
|
1263
|
+
throw new Error(validation.error);
|
|
1264
|
+
return format(new Document([node("plan", {}, validation.edits.map(editNode))]));
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
// src/client.ts
|
|
1268
|
+
function classifyReadSeekFailure(err) {
|
|
1269
|
+
const failure = err;
|
|
1270
|
+
const message = String(failure?.message ?? err);
|
|
1271
|
+
const missing = failure?.code === "ENOENT" || /Cannot find package|Cannot find module|no such file/i.test(message);
|
|
1272
|
+
if (missing) {
|
|
1273
|
+
return { code: "readseek-not-installed", message, hint: "Run npm install to install @jarkkojs/readseek." };
|
|
1274
|
+
}
|
|
1275
|
+
return { code: "readseek-execution-error", message };
|
|
1276
|
+
}
|
|
1277
|
+
function runOptions(options, vision = false) {
|
|
1231
1278
|
return {
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1279
|
+
signal: options.signal,
|
|
1280
|
+
stdin: options.stdin,
|
|
1281
|
+
timeoutMs: options.timeoutMs,
|
|
1282
|
+
cancelable: options.cancelable,
|
|
1283
|
+
...vision ? { vision: true } : {}
|
|
1235
1284
|
};
|
|
1236
1285
|
}
|
|
1237
|
-
function
|
|
1286
|
+
function createReadSeekClient(runner) {
|
|
1238
1287
|
return {
|
|
1239
|
-
|
|
1240
|
-
|
|
1288
|
+
async showContent(path, options = {}) {
|
|
1289
|
+
const value = await runner.kdl(buildShowContentArgs({ ...options, path }), runOptions(options));
|
|
1290
|
+
return parseContentOutput(value);
|
|
1291
|
+
},
|
|
1292
|
+
async showStructure(path, options = {}) {
|
|
1293
|
+
const value = await runner.kdl(buildShowStructureArgs({ ...options, path }), runOptions(options));
|
|
1294
|
+
return parseStructureEnvelope(value);
|
|
1295
|
+
},
|
|
1296
|
+
async showMetadata(path, options = {}) {
|
|
1297
|
+
const value = await runner.kdl(buildShowMetadataArgs({ ...options, path }), runOptions(options));
|
|
1298
|
+
return parsePdfMetadata(value) ?? parseDetectOutput(value?.metadata);
|
|
1299
|
+
},
|
|
1300
|
+
async showAssets(path, options = {}) {
|
|
1301
|
+
const value = await runner.kdl(buildShowAssetsArgs({ ...options, path }), runOptions(options));
|
|
1302
|
+
return parseAssetsOutput(value);
|
|
1303
|
+
},
|
|
1304
|
+
async checkSyntax(path, options = {}) {
|
|
1305
|
+
const value = await runner.kdl(buildCheckSyntaxArgs({ ...options, path }), runOptions(options));
|
|
1306
|
+
return parseCheckOutput(value?.diagnostics ?? value);
|
|
1307
|
+
},
|
|
1308
|
+
async checkRules(path, options) {
|
|
1309
|
+
const value = await runner.kdl(buildCheckRulesArgs({ ...options, path }), runOptions(options));
|
|
1310
|
+
return parseRulesOutput(value);
|
|
1311
|
+
},
|
|
1312
|
+
async generateCaption(path, options = {}) {
|
|
1313
|
+
const value = await runner.kdl(buildGenerateCaptionArgs({ ...options, path }), runOptions(options, true));
|
|
1314
|
+
return parseContentOutput(value);
|
|
1315
|
+
},
|
|
1316
|
+
async detectObjects(path, options = {}) {
|
|
1317
|
+
const value = await runner.kdl(buildDetectObjectsArgs({ ...options, path }), runOptions(options, true));
|
|
1318
|
+
return parseContentOutput(value);
|
|
1319
|
+
},
|
|
1320
|
+
async recognizeText(path, options = {}) {
|
|
1321
|
+
const value = await runner.kdl(buildRecognizeTextArgs({ ...options, path }), runOptions(options, true));
|
|
1322
|
+
return parseContentOutput(value);
|
|
1323
|
+
},
|
|
1324
|
+
async findNodes(path, options) {
|
|
1325
|
+
const value = await runner.kdl(buildFindNodesArgs({ ...options, path }), runOptions(options));
|
|
1326
|
+
return parseSearchOutput(value);
|
|
1327
|
+
},
|
|
1328
|
+
async findText(path, options) {
|
|
1329
|
+
const value = await runner.kdl(buildFindTextArgs({ ...options, path }), runOptions(options));
|
|
1330
|
+
return parseTextSearchOutput(value);
|
|
1331
|
+
},
|
|
1332
|
+
async findDefinitions(path, options) {
|
|
1333
|
+
const value = await runner.kdl(buildFindDefinitionsArgs({ ...options, path }), runOptions(options));
|
|
1334
|
+
return parseDefOutput(value);
|
|
1335
|
+
},
|
|
1336
|
+
async findReferences(path, options) {
|
|
1337
|
+
const value = await runner.kdl(buildFindReferencesArgs({ ...options, path }), runOptions(options));
|
|
1338
|
+
return parseRefsOutput(value);
|
|
1339
|
+
},
|
|
1340
|
+
async editText(path, edits, options = {}) {
|
|
1341
|
+
const stdin = serializeEditPlan(edits);
|
|
1342
|
+
return parseEditOutput(await runner.kdl(buildEditTextArgs({ ...options, path, requestFromStdin: true }), runOptions({ ...options, stdin })));
|
|
1343
|
+
},
|
|
1344
|
+
async renameSymbol(path, options) {
|
|
1345
|
+
const value = await runner.kdl(buildRenameSymbolArgs({ ...options, path }), runOptions(options));
|
|
1346
|
+
return parseRenameOutput(value);
|
|
1347
|
+
}
|
|
1241
1348
|
};
|
|
1242
1349
|
}
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
const symbol = child(node, "symbol");
|
|
1247
|
-
if (identifier)
|
|
1248
|
-
result.identifier = properties(identifier);
|
|
1249
|
-
if (symbol)
|
|
1250
|
-
result.symbol = properties(symbol);
|
|
1251
|
-
return result;
|
|
1350
|
+
// src/show-presentation.ts
|
|
1351
|
+
function isShowTool(name) {
|
|
1352
|
+
return name === "show_content" || name === "show_structure" || name === "show_metadata" || name === "show_assets";
|
|
1252
1353
|
}
|
|
1253
|
-
function
|
|
1254
|
-
|
|
1255
|
-
const metadata = child(root, "metadata");
|
|
1256
|
-
const cache = child(root, "cache");
|
|
1257
|
-
const content = child(root, "content");
|
|
1258
|
-
const map = child(root, "map");
|
|
1259
|
-
const diagnosticOutput = child(root, "diagnostics");
|
|
1260
|
-
const identityOutput = child(root, "identity");
|
|
1261
|
-
if (metadata)
|
|
1262
|
-
result.metadata = properties(metadata);
|
|
1263
|
-
if (cache)
|
|
1264
|
-
result.cache = properties(cache);
|
|
1265
|
-
if (content)
|
|
1266
|
-
result.content = sourceContent(content);
|
|
1267
|
-
if (map)
|
|
1268
|
-
result.map = sourceMap(map);
|
|
1269
|
-
if (diagnosticOutput)
|
|
1270
|
-
result.diagnostics = diagnostics(diagnosticOutput);
|
|
1271
|
-
if (identityOutput)
|
|
1272
|
-
result.identity = identity(identityOutput);
|
|
1273
|
-
return result;
|
|
1354
|
+
function record(value) {
|
|
1355
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
1274
1356
|
}
|
|
1275
|
-
function
|
|
1276
|
-
return
|
|
1277
|
-
...properties(node),
|
|
1278
|
-
hashlines: children(node, "line").map(line),
|
|
1279
|
-
captures: children(node, "capture").map((capture) => ({
|
|
1280
|
-
...properties(capture),
|
|
1281
|
-
hashlines: children(capture, "line").map(line)
|
|
1282
|
-
}))
|
|
1283
|
-
};
|
|
1357
|
+
function records(value) {
|
|
1358
|
+
return Array.isArray(value) ? value.map(record) : [];
|
|
1284
1359
|
}
|
|
1285
|
-
function
|
|
1286
|
-
return
|
|
1287
|
-
...properties(root),
|
|
1288
|
-
results: children(root, "match").map((match) => ({
|
|
1289
|
-
...properties(match),
|
|
1290
|
-
matches: children(match, "hit").map(hit)
|
|
1291
|
-
})),
|
|
1292
|
-
documents: children(root, "document").map((documentNode) => ({
|
|
1293
|
-
...properties(documentNode),
|
|
1294
|
-
hits: children(documentNode, "hit").map(properties)
|
|
1295
|
-
}))
|
|
1296
|
-
};
|
|
1360
|
+
function text(value) {
|
|
1361
|
+
return typeof value === "string" ? value : "";
|
|
1297
1362
|
}
|
|
1298
|
-
function
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
text: parsedLine.text,
|
|
1309
|
-
...symbol ? { symbol: properties(symbol) } : {}
|
|
1310
|
-
};
|
|
1363
|
+
function count(value) {
|
|
1364
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
1365
|
+
}
|
|
1366
|
+
function safe(value) {
|
|
1367
|
+
return value.replace(/[\x00-\x09\x0b-\x1f\x7f-\x9f]/g, (char) => {
|
|
1368
|
+
if (char === "\t")
|
|
1369
|
+
return "\\t";
|
|
1370
|
+
if (char === "\r")
|
|
1371
|
+
return "\\r";
|
|
1372
|
+
return `\\x${char.charCodeAt(0).toString(16).padStart(2, "0")}`;
|
|
1311
1373
|
});
|
|
1312
|
-
return {
|
|
1313
|
-
references: parsed,
|
|
1314
|
-
locations: parsed.map((reference) => {
|
|
1315
|
-
const { symbol, ...location } = reference;
|
|
1316
|
-
return symbol && typeof symbol === "object" ? { ...location, ...symbol } : location;
|
|
1317
|
-
})
|
|
1318
|
-
};
|
|
1319
1374
|
}
|
|
1320
|
-
function
|
|
1321
|
-
return
|
|
1322
|
-
|
|
1323
|
-
const symbol = child(definition, "symbol");
|
|
1324
|
-
const sourceLine = child(definition, "line");
|
|
1325
|
-
if (!symbol || !sourceLine) {
|
|
1326
|
-
throw new Error("invalid readseek KDL definition: missing symbol or line");
|
|
1327
|
-
}
|
|
1328
|
-
const symbolProperties = properties(symbol);
|
|
1329
|
-
const parsedLine = line(sourceLine);
|
|
1330
|
-
const definitionColumn = definition.properties.get("column");
|
|
1331
|
-
const nameByte = symbol.properties.get("name_byte");
|
|
1332
|
-
const startByte = symbol.properties.get("start_byte");
|
|
1333
|
-
let column = 1;
|
|
1334
|
-
if (typeof definitionColumn === "number") {
|
|
1335
|
-
column = definitionColumn;
|
|
1336
|
-
} else if (typeof nameByte === "number" && typeof startByte === "number") {
|
|
1337
|
-
column = nameByte - startByte + 1;
|
|
1338
|
-
}
|
|
1339
|
-
return {
|
|
1340
|
-
file: requireProperty(definition, "file"),
|
|
1341
|
-
line: parsedLine.line,
|
|
1342
|
-
column,
|
|
1343
|
-
line_hash: parsedLine.hash,
|
|
1344
|
-
text: parsedLine.text,
|
|
1345
|
-
kind: symbolProperties.kind,
|
|
1346
|
-
name: symbolProperties.name,
|
|
1347
|
-
qualified_name: symbolProperties.qualified_name
|
|
1348
|
-
};
|
|
1349
|
-
})
|
|
1350
|
-
};
|
|
1375
|
+
function inline(value) {
|
|
1376
|
+
return safe(text(value)).replaceAll(`
|
|
1377
|
+
`, "\\n");
|
|
1351
1378
|
}
|
|
1352
|
-
function
|
|
1353
|
-
|
|
1354
|
-
for (const name of ["before_content", "content"]) {
|
|
1355
|
-
const contentNode = child(root, name);
|
|
1356
|
-
if (contentNode)
|
|
1357
|
-
result[name] = requireProperty(contentNode, "content");
|
|
1358
|
-
}
|
|
1359
|
-
return result;
|
|
1379
|
+
function plural(n, unit) {
|
|
1380
|
+
return `${n} ${unit}${n === 1 ? "" : "s"}`;
|
|
1360
1381
|
}
|
|
1361
|
-
function
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1382
|
+
function fields(value, omit = []) {
|
|
1383
|
+
return Object.entries(value).flatMap(([key, item]) => {
|
|
1384
|
+
if (omit.includes(key) || item === undefined || item === null || typeof item === "object")
|
|
1385
|
+
return [];
|
|
1386
|
+
const label = key.replaceAll("_", " ");
|
|
1387
|
+
return [`${label[0]?.toUpperCase() ?? ""}${label.slice(1)}: ${safe(String(item))}`];
|
|
1388
|
+
}).join(`
|
|
1389
|
+
`);
|
|
1369
1390
|
}
|
|
1370
|
-
function
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1391
|
+
function location(value) {
|
|
1392
|
+
const start = text(value.start_anchor) || (count(value.start_line) !== undefined ? `${value.start_line}${text(value.start_hash) ? `:${value.start_hash}` : ""}` : "");
|
|
1393
|
+
const end = text(value.end_anchor) || (count(value.end_line) !== undefined ? `${value.end_line}${text(value.end_hash) ? `:${value.end_hash}` : ""}` : "");
|
|
1394
|
+
return start ? ` ${inline(start)}${end && end !== start ? ` - ${inline(end)}` : ""}` : "";
|
|
1395
|
+
}
|
|
1396
|
+
function sourceStructure(structure) {
|
|
1397
|
+
const sections = [];
|
|
1398
|
+
if (structure.root) {
|
|
1399
|
+
const lines = [];
|
|
1400
|
+
const stack = [{ node: record(structure.root), depth: 0 }];
|
|
1401
|
+
while (stack.length > 0) {
|
|
1402
|
+
const { node, depth } = stack.pop();
|
|
1403
|
+
lines.push(`${" ".repeat(Math.min(depth, 12))}${inline(node.kind) || "node"}${text(node.name) ? ` ${inline(node.name)}` : ""}${location(node)}`);
|
|
1404
|
+
const children = records(node.children);
|
|
1405
|
+
for (let i = children.length - 1;i >= 0; i--)
|
|
1406
|
+
stack.push({ node: children[i], depth: depth + 1 });
|
|
1407
|
+
}
|
|
1408
|
+
sections.push(`Tree
|
|
1409
|
+
${lines.join(`
|
|
1410
|
+
`)}`);
|
|
1411
|
+
}
|
|
1412
|
+
const symbols = records(structure.symbols);
|
|
1413
|
+
if (symbols.length > 0) {
|
|
1414
|
+
sections.push(`Symbols
|
|
1415
|
+
${symbols.map((symbol) => `${inline(symbol.kind) || "symbol"} ${inline(symbol.qualified_name || symbol.name)}${location(symbol)}`).join(`
|
|
1416
|
+
`)}`);
|
|
1417
|
+
}
|
|
1418
|
+
return sections.join(`
|
|
1419
|
+
|
|
1420
|
+
`) || "No structure found in this selection.";
|
|
1421
|
+
}
|
|
1422
|
+
function documentNodes(nodes, content) {
|
|
1423
|
+
const depths = new Map;
|
|
1424
|
+
return nodes.map((node) => {
|
|
1425
|
+
const depth = Math.min((depths.get(text(node.parent_id)) ?? -1) + 1, 12);
|
|
1426
|
+
depths.set(text(node.id), depth);
|
|
1427
|
+
const indent = " ".repeat(depth);
|
|
1428
|
+
const label = inline(node.title) || inline(node.kind) || "node";
|
|
1429
|
+
const page = count(node.page);
|
|
1430
|
+
const selector = text(node.id) ? `node:${inline(node.id)}` : "";
|
|
1431
|
+
const position = [selector, page !== undefined ? `page:${page}` : ""].filter(Boolean).join(" · ");
|
|
1432
|
+
const heading = `${indent}${label}${position ? ` [${position}]` : ""}`;
|
|
1433
|
+
const body = text(node.text);
|
|
1434
|
+
return content && body ? `${heading}
|
|
1435
|
+
${safe(body).split(`
|
|
1436
|
+
`).map((line) => indent + line).join(`
|
|
1437
|
+
`)}` : heading;
|
|
1438
|
+
}).join(content ? `
|
|
1439
|
+
|
|
1440
|
+
` : `
|
|
1441
|
+
`);
|
|
1376
1442
|
}
|
|
1377
|
-
function
|
|
1378
|
-
return {
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1443
|
+
function assetList(assets) {
|
|
1444
|
+
return assets.map((asset) => {
|
|
1445
|
+
const id = text(asset.id);
|
|
1446
|
+
const page = count(asset.page);
|
|
1447
|
+
const heading = [id ? `asset:${inline(id)}` : inline(asset.kind) || "image", inline(asset.mime), page !== undefined ? `page:${page}` : ""].filter(Boolean).join(" · ");
|
|
1448
|
+
const details = fields(asset, ["id", "kind", "mime", "page", "bbox", "content_identity"]);
|
|
1449
|
+
return `${heading}${details ? `
|
|
1450
|
+
${details.split(`
|
|
1451
|
+
`).map((line) => ` ${line}`).join(`
|
|
1452
|
+
`)}` : ""}`;
|
|
1453
|
+
}).join(`
|
|
1454
|
+
|
|
1455
|
+
`);
|
|
1382
1456
|
}
|
|
1383
|
-
function
|
|
1384
|
-
const
|
|
1385
|
-
const
|
|
1386
|
-
const
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
const
|
|
1392
|
-
|
|
1393
|
-
|
|
1457
|
+
function presentShowResult(tool, value, options = {}) {
|
|
1458
|
+
const output = record(value);
|
|
1459
|
+
const metadata = record(output.metadata);
|
|
1460
|
+
const content = record(output.content);
|
|
1461
|
+
const cursor = record(output.cursor);
|
|
1462
|
+
const structure = record(output.structure);
|
|
1463
|
+
const document = typeof output.format === "string" && (Array.isArray(output.nodes) || typeof output.source === "string");
|
|
1464
|
+
const path = inline(options.path || output.source || output.file || content.file || structure.file || metadata.file || cursor.file) || "(unknown path)";
|
|
1465
|
+
const summary = [];
|
|
1466
|
+
const result = { summary: "", body: "", notices: [], metadata: {} };
|
|
1467
|
+
if (tool === "show_metadata") {
|
|
1468
|
+
const data = Object.keys(metadata).length > 0 ? metadata : output;
|
|
1469
|
+
if (text(data.format || data.language || data.type))
|
|
1470
|
+
summary.push(inline(data.format || data.language || data.type));
|
|
1471
|
+
if (count(data.pages) !== undefined) {
|
|
1472
|
+
result.metadata.pages = data.pages;
|
|
1473
|
+
summary.push(plural(result.metadata.pages, "page"));
|
|
1474
|
+
}
|
|
1475
|
+
result.body = fields(data) || "No metadata available.";
|
|
1476
|
+
} else if (tool === "show_assets") {
|
|
1477
|
+
const assets = records(output.assets);
|
|
1478
|
+
result.metadata.assets = assets.length;
|
|
1479
|
+
summary.push(plural(assets.length, "asset"));
|
|
1480
|
+
result.body = assetList(assets) || "No assets in this selection.";
|
|
1481
|
+
} else if (document) {
|
|
1482
|
+
const nodes = records(output.nodes);
|
|
1483
|
+
const assets = records(output.assets);
|
|
1484
|
+
result.metadata.nodes = nodes.length;
|
|
1485
|
+
if (count(output.pages) !== undefined)
|
|
1486
|
+
result.metadata.pages = output.pages;
|
|
1487
|
+
summary.push(plural(nodes.length, "node"));
|
|
1488
|
+
if (result.metadata.pages !== undefined)
|
|
1489
|
+
summary.push(plural(result.metadata.pages, "page"));
|
|
1490
|
+
const sections = [text(output.title) ? safe(text(output.title)) : "", documentNodes(nodes, tool === "show_content")];
|
|
1491
|
+
if (assets.length > 0) {
|
|
1492
|
+
result.metadata.assets = assets.length;
|
|
1493
|
+
sections.push(`Assets
|
|
1494
|
+
${assetList(assets)}`);
|
|
1495
|
+
}
|
|
1496
|
+
result.body = sections.filter(Boolean).join(`
|
|
1497
|
+
|
|
1498
|
+
`) || "No content in this selection.";
|
|
1499
|
+
} else if (tool === "show_structure") {
|
|
1500
|
+
const symbols = records(structure.symbols);
|
|
1501
|
+
result.metadata.symbols = symbols.length;
|
|
1502
|
+
summary.push(plural(symbols.length, "symbol"));
|
|
1503
|
+
result.body = sourceStructure(structure);
|
|
1504
|
+
} else if (content.kind === "image" || count(content.width) !== undefined && count(content.height) !== undefined || count(metadata.width) !== undefined && count(metadata.height) !== undefined || text(content.mime).startsWith("image/") || text(metadata.mime).startsWith("image/") || text(metadata.type).startsWith("image/")) {
|
|
1505
|
+
const description = Object.keys(content).length > 0 ? content : Object.keys(metadata).length > 0 ? metadata : output;
|
|
1506
|
+
if (count(description.width) !== undefined && count(description.height) !== undefined) {
|
|
1507
|
+
summary.push(`${description.width} × ${description.height}`);
|
|
1508
|
+
} else if (count(metadata.width) !== undefined && count(metadata.height) !== undefined) {
|
|
1509
|
+
summary.push(`${metadata.width} × ${metadata.height}`);
|
|
1510
|
+
}
|
|
1511
|
+
const mime = text(description.mime || metadata.mime || metadata.type);
|
|
1512
|
+
if (mime)
|
|
1513
|
+
summary.push(inline(mime));
|
|
1514
|
+
result.body = fields(description, ["hashlines"]) || fields(metadata) || "No content in this selection.";
|
|
1515
|
+
} else if (Array.isArray(content.hashlines) || Array.isArray(cursor.hashlines)) {
|
|
1516
|
+
const lines = records(content.hashlines ?? cursor.hashlines);
|
|
1517
|
+
const start = count(content.start_line) ?? count(lines[0]?.line);
|
|
1518
|
+
const end = count(content.end_line) ?? count(lines.at(-1)?.line);
|
|
1519
|
+
const total = count(content.line_count) ?? count(cursor.line_count);
|
|
1520
|
+
if (start !== undefined && end !== undefined && start <= end) {
|
|
1521
|
+
result.metadata.start_line = start;
|
|
1522
|
+
result.metadata.end_line = end;
|
|
1523
|
+
summary.push(`lines ${start}-${end}${total !== undefined ? ` of ${total}` : ""}`);
|
|
1524
|
+
} else
|
|
1525
|
+
summary.push(plural(lines.length, "line"));
|
|
1526
|
+
const lang = text(metadata.language || content.language);
|
|
1527
|
+
if (lang)
|
|
1528
|
+
summary.push(inline(lang));
|
|
1529
|
+
const rows = lines.map((line) => `${line.line}${options.noAnchors ? "" : `:${text(line.hash)}`} | ${safe(text(line.text)).replaceAll("\\n", "\\\\n")}`);
|
|
1530
|
+
const identifier = record(cursor.identifier);
|
|
1531
|
+
if (count(cursor.line) !== undefined)
|
|
1532
|
+
result.metadata.line = cursor.line;
|
|
1533
|
+
if (count(cursor.column) !== undefined)
|
|
1534
|
+
result.metadata.column = cursor.column;
|
|
1535
|
+
if (Object.keys(cursor).length > 0) {
|
|
1536
|
+
const symbol = record(cursor.symbol);
|
|
1537
|
+
const description = [text(identifier.text), text(symbol.qualified_name || symbol.name), text(symbol.kind)].filter(Boolean);
|
|
1538
|
+
rows.unshift(`Cursor: ${cursor.line ?? "?"}:${cursor.column ?? "?"}${description.length > 0 ? ` · ${[...new Set(description)].map(inline).join(" · ")}` : ""}`, "");
|
|
1539
|
+
}
|
|
1540
|
+
result.body = rows.join(`
|
|
1541
|
+
`) || "Empty source selection.";
|
|
1542
|
+
if (start !== undefined && start > 1)
|
|
1543
|
+
result.notices.push(`Earlier lines omitted. Read preceding content with at: line:1 and limit: ${start - 1}.`);
|
|
1544
|
+
if (end !== undefined && total !== undefined && end < total) {
|
|
1545
|
+
result.notices.push(`More lines available. Continue with at: line:${end + 1}.`);
|
|
1546
|
+
} else if (content.truncated === true && (end === undefined || total === undefined)) {
|
|
1547
|
+
result.notices.push(`Content is truncated.${end !== undefined ? ` Continue with at: line:${end + 1}.` : " Select a smaller range with at and limit."}`);
|
|
1548
|
+
}
|
|
1549
|
+
} else {
|
|
1550
|
+
const description = Object.keys(content).length > 0 ? content : output;
|
|
1551
|
+
result.body = fields(description) || "No content in this selection.";
|
|
1552
|
+
}
|
|
1553
|
+
if (tool === "show_structure")
|
|
1554
|
+
result.notices.push("Structure is limited to the requested depth, kind, and outline. Use a deeper depth or focus with at to inspect further.");
|
|
1555
|
+
if (text(output.warning))
|
|
1556
|
+
result.notices.push(safe(text(output.warning)));
|
|
1557
|
+
result.summary = summary.join(" · ") || "complete";
|
|
1394
1558
|
return result;
|
|
1395
1559
|
}
|
|
1396
|
-
function
|
|
1397
|
-
return {
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
assets: children(root, "asset").map(genericNode),
|
|
1401
|
-
vision: children(root, "vision").map(genericNode)
|
|
1402
|
-
};
|
|
1403
|
-
}
|
|
1404
|
-
function parseReadSeekKdl(text) {
|
|
1405
|
-
const root = parseKdlDocument(text);
|
|
1406
|
-
switch (root.name) {
|
|
1407
|
-
case "document":
|
|
1408
|
-
return root.properties.has("format") ? pdfDocument(root) : sourceDocument(root);
|
|
1409
|
-
case "search":
|
|
1410
|
-
return search(root);
|
|
1411
|
-
case "check":
|
|
1412
|
-
return diagnostics(root);
|
|
1413
|
-
case "refs":
|
|
1414
|
-
return references(root);
|
|
1415
|
-
case "def":
|
|
1416
|
-
return definitions(root);
|
|
1417
|
-
case "edit":
|
|
1418
|
-
return edit(root);
|
|
1419
|
-
case "edit-batch":
|
|
1420
|
-
return { ...properties(root), files: children(root, "file").map(edit) };
|
|
1421
|
-
case "rename":
|
|
1422
|
-
return rename(root);
|
|
1423
|
-
default:
|
|
1424
|
-
throw new Error(`unsupported readseek KDL root: ${root.name}`);
|
|
1425
|
-
}
|
|
1560
|
+
function formatShowResult(presentation) {
|
|
1561
|
+
return [presentation.summary, presentation.body, ...presentation.notices.map((notice) => `Note: ${notice}`)].filter(Boolean).join(`
|
|
1562
|
+
|
|
1563
|
+
`);
|
|
1426
1564
|
}
|
|
1427
|
-
// src/
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1565
|
+
// src/platform.ts
|
|
1566
|
+
import { accessSync, constants as fsConstants, existsSync, statSync } from "node:fs";
|
|
1567
|
+
import { createRequire } from "node:module";
|
|
1568
|
+
import { homedir } from "node:os";
|
|
1569
|
+
import path2 from "node:path";
|
|
1570
|
+
var READSEEK_BINARY_ENV = "READSEEK_BINARY";
|
|
1571
|
+
var READSEEK_PLATFORM_PACKAGES = {
|
|
1572
|
+
"darwin-arm64": "@jarkkojs/readseek-darwin-arm64",
|
|
1573
|
+
"linux-arm64": "@jarkkojs/readseek-linux-arm64",
|
|
1574
|
+
"linux-x64": "@jarkkojs/readseek-linux-x64",
|
|
1575
|
+
"win32-x64": "@jarkkojs/readseek-win32-x64"
|
|
1576
|
+
};
|
|
1577
|
+
var resolveFromPackage = createRequire(import.meta.url).resolve;
|
|
1578
|
+
function readSeekBinaryName(platform = process.platform) {
|
|
1579
|
+
if (platform === "linux")
|
|
1580
|
+
return "readseek.AppImage";
|
|
1581
|
+
return platform === "win32" ? "readseek.exe" : "readseek";
|
|
1432
1582
|
}
|
|
1433
|
-
function
|
|
1434
|
-
return {
|
|
1435
|
-
timeoutMs: options.timeoutMs ?? DEFAULT_READSEEK_TIMEOUT_MS,
|
|
1436
|
-
maxOutputBytes: options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES,
|
|
1437
|
-
cancelable: options.cancelable !== false
|
|
1438
|
-
};
|
|
1583
|
+
function readSeekPlatformKey(platform = process.platform, arch = process.arch) {
|
|
1584
|
+
return `${platform}-${arch}`;
|
|
1439
1585
|
}
|
|
1440
|
-
function
|
|
1441
|
-
const
|
|
1442
|
-
|
|
1586
|
+
function resolveReadSeekBinaryOverride(environment = process.env) {
|
|
1587
|
+
const binaryPath = environment[READSEEK_BINARY_ENV];
|
|
1588
|
+
if (binaryPath === undefined)
|
|
1589
|
+
return null;
|
|
1590
|
+
if (!path2.isAbsolute(binaryPath)) {
|
|
1591
|
+
throw new Error(`${READSEEK_BINARY_ENV} must be an absolute path to the readseek executable`);
|
|
1592
|
+
}
|
|
1593
|
+
try {
|
|
1594
|
+
if (!statSync(binaryPath).isFile())
|
|
1595
|
+
throw new Error("not a regular file");
|
|
1596
|
+
accessSync(binaryPath, fsConstants.X_OK);
|
|
1597
|
+
} catch (error) {
|
|
1598
|
+
throw new Error(`${READSEEK_BINARY_ENV} does not point to an executable file: ${binaryPath}`, {
|
|
1599
|
+
cause: error
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1602
|
+
return binaryPath;
|
|
1443
1603
|
}
|
|
1444
|
-
function
|
|
1445
|
-
|
|
1446
|
-
|
|
1604
|
+
function resolveReadSeekBinaryFromPackages(resolver = resolveFromPackage, options = {}) {
|
|
1605
|
+
const resolve = typeof resolver === "function" ? resolver : resolver.resolve.bind(resolver);
|
|
1606
|
+
const platform = options.platform ?? process.platform;
|
|
1607
|
+
const arch = options.arch ?? process.arch;
|
|
1608
|
+
const key = readSeekPlatformKey(platform, arch);
|
|
1609
|
+
const platformPackage = READSEEK_PLATFORM_PACKAGES[key];
|
|
1610
|
+
if (!platformPackage) {
|
|
1611
|
+
const supported = Object.keys(READSEEK_PLATFORM_PACKAGES).join(", ");
|
|
1612
|
+
throw new Error(`@jarkkojs/readseek ships no binary for ${key}; it supports ${supported}`);
|
|
1447
1613
|
}
|
|
1448
|
-
|
|
1449
|
-
|
|
1614
|
+
const metaPackage = options.metaPackage ?? "@jarkkojs/readseek";
|
|
1615
|
+
let packageJsonPath;
|
|
1616
|
+
try {
|
|
1617
|
+
const metaPackageJson = resolve(`${metaPackage}/package.json`);
|
|
1618
|
+
const metaPackageDir = path2.dirname(metaPackageJson);
|
|
1619
|
+
packageJsonPath = resolve(`${platformPackage}/package.json`, {
|
|
1620
|
+
paths: [metaPackageDir]
|
|
1621
|
+
});
|
|
1622
|
+
} catch {
|
|
1623
|
+
packageJsonPath = resolve(`${platformPackage}/package.json`);
|
|
1450
1624
|
}
|
|
1451
|
-
const
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
if (result.signal)
|
|
1455
|
-
return new Error(`readseek killed by signal ${result.signal}`);
|
|
1456
|
-
return new Error(`readseek exited with status ${result.exitCode}`);
|
|
1625
|
+
const binaryPath = path2.join(path2.dirname(packageJsonPath), "bin", readSeekBinaryName(platform));
|
|
1626
|
+
accessSync(binaryPath, fsConstants.X_OK);
|
|
1627
|
+
return binaryPath;
|
|
1457
1628
|
}
|
|
1458
|
-
function
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1629
|
+
function resolveReadSeekCacheDir(subPath, options = {}) {
|
|
1630
|
+
const env = options.environment ?? process.env;
|
|
1631
|
+
const platform = options.platform ?? process.platform;
|
|
1632
|
+
const home = options.homedir ? options.homedir() : homedir();
|
|
1633
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1634
|
+
const localDirName = options.localDirName ?? ".readseek";
|
|
1635
|
+
if (localDirName && localDirName.length > 0) {
|
|
1636
|
+
const local = path2.join(cwd, localDirName);
|
|
1637
|
+
if (existsSync(local))
|
|
1638
|
+
return local;
|
|
1639
|
+
}
|
|
1640
|
+
let base;
|
|
1641
|
+
if (platform === "win32") {
|
|
1642
|
+
base = env.LOCALAPPDATA ?? path2.join(home, "AppData", "Local");
|
|
1643
|
+
} else {
|
|
1644
|
+
const xdg = env.XDG_CACHE_HOME?.trim();
|
|
1645
|
+
base = xdg && path2.isAbsolute(xdg) ? xdg : path2.join(home, ".cache");
|
|
1646
|
+
}
|
|
1647
|
+
const pathModule = platform === "win32" ? path2.win32 : path2;
|
|
1648
|
+
if (subPath === undefined) {
|
|
1649
|
+
return pathModule.join(base, "readseek");
|
|
1650
|
+
}
|
|
1651
|
+
const parts = Array.isArray(subPath) ? subPath : [subPath];
|
|
1652
|
+
return pathModule.join(base, ...parts);
|
|
1462
1653
|
}
|
|
1463
|
-
|
|
1464
|
-
|
|
1654
|
+
// src/path.ts
|
|
1655
|
+
import { lstatSync, realpathSync } from "node:fs";
|
|
1656
|
+
import { homedir as homedir2 } from "node:os";
|
|
1657
|
+
import path3 from "node:path";
|
|
1658
|
+
var UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
1659
|
+
function canonicalPathKey(cwd, filePath) {
|
|
1660
|
+
const resolved = path3.resolve(cwd, filePath);
|
|
1661
|
+
try {
|
|
1662
|
+
return realpathSync.native(resolved);
|
|
1663
|
+
} catch {
|
|
1664
|
+
return resolved;
|
|
1665
|
+
}
|
|
1465
1666
|
}
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
stream.on("data", (chunk) => {
|
|
1475
|
-
if (overflowed)
|
|
1476
|
-
return;
|
|
1477
|
-
const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
1478
|
-
bytes += buffer.length;
|
|
1479
|
-
if (bytes > maxOutputBytes) {
|
|
1480
|
-
overflowed = true;
|
|
1481
|
-
onOverflow();
|
|
1482
|
-
return;
|
|
1483
|
-
}
|
|
1484
|
-
text += decoder.write(buffer);
|
|
1485
|
-
});
|
|
1486
|
-
return {
|
|
1487
|
-
text: () => text + decoder.end()
|
|
1488
|
-
};
|
|
1667
|
+
function expandUserPath(filePath, homedirFn = homedir2) {
|
|
1668
|
+
const withoutAt = filePath.startsWith("@") ? filePath.slice(1) : filePath;
|
|
1669
|
+
const normalized = withoutAt.replace(UNICODE_SPACES, " ");
|
|
1670
|
+
if (normalized === "~")
|
|
1671
|
+
return homedirFn();
|
|
1672
|
+
if (normalized.startsWith("~/"))
|
|
1673
|
+
return homedirFn() + normalized.slice(1);
|
|
1674
|
+
return normalized;
|
|
1489
1675
|
}
|
|
1490
|
-
|
|
1491
|
-
const
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
settled = true;
|
|
1503
|
-
if (timer !== undefined)
|
|
1504
|
-
clearTimeout(timer);
|
|
1505
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
1506
|
-
resolve(result);
|
|
1507
|
-
};
|
|
1508
|
-
const fail = (error) => {
|
|
1509
|
-
if (settled)
|
|
1510
|
-
return;
|
|
1511
|
-
settled = true;
|
|
1512
|
-
if (timer !== undefined)
|
|
1513
|
-
clearTimeout(timer);
|
|
1514
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
1515
|
-
reject(error instanceof Error ? error : new Error(String(error)));
|
|
1516
|
-
};
|
|
1517
|
-
const terminate = (error) => {
|
|
1518
|
-
if (settled)
|
|
1519
|
-
return;
|
|
1520
|
-
fail(error);
|
|
1521
|
-
try {
|
|
1522
|
-
child.kill("SIGKILL");
|
|
1523
|
-
} catch {}
|
|
1524
|
-
};
|
|
1525
|
-
const onAbort = () => {
|
|
1526
|
-
terminate(readSeekCancellationError(options.signal));
|
|
1527
|
-
};
|
|
1676
|
+
function resolveToCwd(filePath, cwd, homedirFn = homedir2) {
|
|
1677
|
+
const expanded = expandUserPath(filePath, homedirFn);
|
|
1678
|
+
return path3.isAbsolute(expanded) ? expanded : path3.resolve(cwd, expanded);
|
|
1679
|
+
}
|
|
1680
|
+
function isSubPath(parent, candidate) {
|
|
1681
|
+
const relative = path3.relative(parent, candidate);
|
|
1682
|
+
return relative === "" || !relative.startsWith(`..${path3.sep}`) && relative !== ".." && !path3.isAbsolute(relative);
|
|
1683
|
+
}
|
|
1684
|
+
function resolvePathWithMissingTail(filePath) {
|
|
1685
|
+
let ancestor = filePath;
|
|
1686
|
+
const missing = [];
|
|
1687
|
+
while (true) {
|
|
1528
1688
|
try {
|
|
1529
|
-
|
|
1530
|
-
cwd: options.cwd,
|
|
1531
|
-
env: readSeekProcessEnvironment(),
|
|
1532
|
-
shell: false,
|
|
1533
|
-
stdio: [options.stdin === undefined ? "ignore" : "pipe", "pipe", "pipe"],
|
|
1534
|
-
windowsHide: true
|
|
1535
|
-
});
|
|
1689
|
+
lstatSync(ancestor);
|
|
1536
1690
|
} catch (error) {
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
});
|
|
1546
|
-
timer = setTimeout(() => {
|
|
1547
|
-
terminate(failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { timedOut: true, timeoutMs: limits.timeoutMs }));
|
|
1548
|
-
}, limits.timeoutMs);
|
|
1549
|
-
timer.unref?.();
|
|
1550
|
-
if (limits.cancelable && options.signal) {
|
|
1551
|
-
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
1552
|
-
}
|
|
1553
|
-
if (options.stdin !== undefined) {
|
|
1554
|
-
child.stdin.on("error", (error) => {
|
|
1555
|
-
if (error.code !== "EPIPE")
|
|
1556
|
-
fail(error);
|
|
1557
|
-
});
|
|
1558
|
-
child.stdin.end(options.stdin, "utf8");
|
|
1691
|
+
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT")
|
|
1692
|
+
throw error;
|
|
1693
|
+
const parent = path3.dirname(ancestor);
|
|
1694
|
+
if (parent === ancestor)
|
|
1695
|
+
throw error;
|
|
1696
|
+
missing.push(path3.basename(ancestor));
|
|
1697
|
+
ancestor = parent;
|
|
1698
|
+
continue;
|
|
1559
1699
|
}
|
|
1560
|
-
|
|
1561
|
-
child.on("close", (code, signal) => {
|
|
1562
|
-
finish({
|
|
1563
|
-
stdout: stdout.text(),
|
|
1564
|
-
stderr: stderr.text(),
|
|
1565
|
-
exitCode: code,
|
|
1566
|
-
signal
|
|
1567
|
-
});
|
|
1568
|
-
});
|
|
1569
|
-
});
|
|
1570
|
-
}
|
|
1571
|
-
async function runReadSeekNodeText(binaryPath, args, options = {}) {
|
|
1572
|
-
return ensureSuccessfulStdout(await runReadSeekNode(binaryPath, args, options));
|
|
1573
|
-
}
|
|
1574
|
-
async function runReadSeekNodeKdl(binaryPath, args, options = {}) {
|
|
1575
|
-
return parseSuccessfulKdl(await runReadSeekNode(binaryPath, args, options));
|
|
1576
|
-
}
|
|
1577
|
-
// src/process-bun.ts
|
|
1578
|
-
function getBunSpawn() {
|
|
1579
|
-
const bunGlobal = globalThis;
|
|
1580
|
-
const spawn = bunGlobal.Bun?.spawn;
|
|
1581
|
-
if (typeof spawn !== "function") {
|
|
1582
|
-
throw new Error("Bun.spawn is unavailable in this runtime");
|
|
1700
|
+
return path3.join(realpathSync.native(ancestor), ...missing.reverse());
|
|
1583
1701
|
}
|
|
1584
|
-
return spawn;
|
|
1585
1702
|
}
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
let totalBytes = 0;
|
|
1703
|
+
function resolveScopedPath(root, rawPath, fallback = ".") {
|
|
1704
|
+
let canonicalRoot;
|
|
1705
|
+
let candidate;
|
|
1590
1706
|
try {
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
if (totalBytes > maxOutputBytes) {
|
|
1597
|
-
onOverflow();
|
|
1598
|
-
await reader.cancel().catch(() => {
|
|
1599
|
-
return;
|
|
1600
|
-
});
|
|
1601
|
-
throw failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { overflow: streamName, maxOutputBytes });
|
|
1602
|
-
}
|
|
1603
|
-
chunks.push(value);
|
|
1604
|
-
}
|
|
1605
|
-
} finally {
|
|
1606
|
-
reader.releaseLock();
|
|
1707
|
+
canonicalRoot = realpathSync.native(path3.resolve(root));
|
|
1708
|
+
candidate = resolvePathWithMissingTail(path3.resolve(canonicalRoot, rawPath ?? fallback));
|
|
1709
|
+
} catch (error) {
|
|
1710
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1711
|
+
return { ok: false, error: `cannot resolve project path (${root}): ${rawPath ?? fallback}: ${message}` };
|
|
1607
1712
|
}
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
for (const chunk of chunks) {
|
|
1611
|
-
bytes.set(chunk, offset);
|
|
1612
|
-
offset += chunk.byteLength;
|
|
1713
|
+
if (!isSubPath(canonicalRoot, candidate)) {
|
|
1714
|
+
return { ok: false, error: `path escapes project root (${canonicalRoot}): ${rawPath ?? fallback}` };
|
|
1613
1715
|
}
|
|
1614
|
-
return
|
|
1716
|
+
return { ok: true, path: candidate };
|
|
1615
1717
|
}
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1718
|
+
// src/error.ts
|
|
1719
|
+
var READSEEK_USAGE_HINT = /(?:^|\n)\s*Run readseek(?: [\w-]+)* --help for more information\.?\s*$/;
|
|
1720
|
+
function cleanReadSeekErrorText(stderr) {
|
|
1721
|
+
return stderr.replace(READSEEK_USAGE_HINT, "").replace(/^error:\s*/i, "").replace(/\s*\n\s*/g, " ").trim();
|
|
1722
|
+
}
|
|
1723
|
+
// src/kdl.ts
|
|
1724
|
+
import { parse as parse2 } from "@bgotink/kdl";
|
|
1725
|
+
function convertNode(node) {
|
|
1726
|
+
if (node.getTag() !== null)
|
|
1727
|
+
throw new Error("KDL node annotations are not supported");
|
|
1728
|
+
const properties = new Map;
|
|
1729
|
+
for (const entry of node.entries) {
|
|
1730
|
+
const name = entry.getName();
|
|
1731
|
+
if (name === null)
|
|
1732
|
+
throw new Error("KDL positional arguments are not supported");
|
|
1733
|
+
if (properties.has(name))
|
|
1734
|
+
throw new Error(`KDL duplicate property '${name}'`);
|
|
1735
|
+
if (entry.getTag() !== null)
|
|
1736
|
+
throw new Error("KDL value annotations are not supported");
|
|
1737
|
+
const value = entry.getValue();
|
|
1738
|
+
if (value === null)
|
|
1739
|
+
throw new Error("KDL null values are not supported");
|
|
1740
|
+
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
1741
|
+
throw new Error("KDL number out of range");
|
|
1742
|
+
}
|
|
1743
|
+
properties.set(name, value);
|
|
1620
1744
|
}
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
env: readSeekProcessEnvironment(),
|
|
1626
|
-
stderr: "pipe",
|
|
1627
|
-
stdin,
|
|
1628
|
-
stdout: "pipe"
|
|
1629
|
-
};
|
|
1630
|
-
const child = spawn([binaryPath, ...args], limits.cancelable && options.signal ? { ...spawnOptions, killSignal: "SIGKILL", signal: options.signal } : spawnOptions);
|
|
1631
|
-
const killForOverflow = () => {
|
|
1632
|
-
try {
|
|
1633
|
-
child.kill("SIGKILL");
|
|
1634
|
-
} catch {}
|
|
1745
|
+
return {
|
|
1746
|
+
name: node.getName(),
|
|
1747
|
+
properties,
|
|
1748
|
+
children: node.children?.nodes.map(convertNode) ?? []
|
|
1635
1749
|
};
|
|
1636
|
-
let timeout;
|
|
1637
|
-
const timeoutResult = new Promise((_resolve, reject) => {
|
|
1638
|
-
timeout = setTimeout(() => {
|
|
1639
|
-
try {
|
|
1640
|
-
child.kill("SIGKILL");
|
|
1641
|
-
} catch {}
|
|
1642
|
-
reject(failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { timedOut: true, timeoutMs: limits.timeoutMs }));
|
|
1643
|
-
}, limits.timeoutMs);
|
|
1644
|
-
timeout.unref?.();
|
|
1645
|
-
});
|
|
1646
|
-
const pending = Promise.all([
|
|
1647
|
-
readBoundedText(child.stdout, "stdout", limits.maxOutputBytes, killForOverflow),
|
|
1648
|
-
readBoundedText(child.stderr, "stderr", limits.maxOutputBytes, killForOverflow),
|
|
1649
|
-
child.exited
|
|
1650
|
-
]);
|
|
1651
|
-
try {
|
|
1652
|
-
const [stdout, stderr, exitCode] = await Promise.race([pending, timeoutResult]);
|
|
1653
|
-
if (limits.cancelable && options.signal?.aborted)
|
|
1654
|
-
throw readSeekCancellationError(options.signal);
|
|
1655
|
-
return { stdout, stderr, exitCode, signal: null };
|
|
1656
|
-
} finally {
|
|
1657
|
-
if (timeout !== undefined)
|
|
1658
|
-
clearTimeout(timeout);
|
|
1659
|
-
pending.catch(() => {
|
|
1660
|
-
return;
|
|
1661
|
-
});
|
|
1662
|
-
}
|
|
1663
1750
|
}
|
|
1664
|
-
|
|
1665
|
-
|
|
1751
|
+
function parseKdlDocument(text) {
|
|
1752
|
+
const document = parse2(text);
|
|
1753
|
+
if (document.nodes.length !== 1)
|
|
1754
|
+
throw new Error("KDL document must contain exactly one root node");
|
|
1755
|
+
return convertNode(document.nodes[0]);
|
|
1666
1756
|
}
|
|
1667
|
-
|
|
1668
|
-
|
|
1757
|
+
|
|
1758
|
+
// src/output-kdl.ts
|
|
1759
|
+
function properties(node) {
|
|
1760
|
+
return Object.fromEntries(node.properties);
|
|
1669
1761
|
}
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
import { AssertError, Value } from "@sinclair/typebox/value";
|
|
1673
|
-
var OPERATIONS = ["Clone", "Clean", "Default", "Assert"];
|
|
1674
|
-
function parse2(schema, value, what) {
|
|
1675
|
-
try {
|
|
1676
|
-
return Value.Parse(OPERATIONS, schema, value);
|
|
1677
|
-
} catch (error) {
|
|
1678
|
-
if (!(error instanceof AssertError))
|
|
1679
|
-
throw error;
|
|
1680
|
-
const detail = error.error;
|
|
1681
|
-
throw new Error(`invalid readseek ${what}${detail?.path ?? ""}: ${detail?.message ?? "invalid value"}`);
|
|
1682
|
-
}
|
|
1762
|
+
function children(node, name) {
|
|
1763
|
+
return node.children.filter((child) => child.name === name);
|
|
1683
1764
|
}
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
var Bool = Type.Boolean();
|
|
1687
|
-
var OptStr = Type.Optional(Str);
|
|
1688
|
-
var OptInt = Type.Optional(Int);
|
|
1689
|
-
var Hashline = Type.Object({ line: Int, hash: Str, text: Str });
|
|
1690
|
-
var Hashlines = Type.Array(Hashline);
|
|
1691
|
-
var ReadOutput = Type.Object({
|
|
1692
|
-
file: Str,
|
|
1693
|
-
language: Str,
|
|
1694
|
-
line_count: Int,
|
|
1695
|
-
file_hash: Str,
|
|
1696
|
-
start_line: Int,
|
|
1697
|
-
end_line: Int,
|
|
1698
|
-
hashlines: Hashlines
|
|
1699
|
-
});
|
|
1700
|
-
var SymbolOutput = Type.Object({
|
|
1701
|
-
kind: Str,
|
|
1702
|
-
name: Str,
|
|
1703
|
-
qualified_name: OptStr,
|
|
1704
|
-
start_line: Int,
|
|
1705
|
-
end_line: Int,
|
|
1706
|
-
start_hash: OptStr,
|
|
1707
|
-
end_hash: OptStr,
|
|
1708
|
-
start_anchor: OptStr,
|
|
1709
|
-
end_anchor: OptStr
|
|
1710
|
-
});
|
|
1711
|
-
function mapNodeShape(child) {
|
|
1712
|
-
return Type.Object({
|
|
1713
|
-
kind: Str,
|
|
1714
|
-
name: Str,
|
|
1715
|
-
start_line: Int,
|
|
1716
|
-
end_line: Int,
|
|
1717
|
-
start_anchor: Str,
|
|
1718
|
-
end_anchor: Str,
|
|
1719
|
-
children: Type.Array(child)
|
|
1720
|
-
});
|
|
1765
|
+
function child(node, name) {
|
|
1766
|
+
return node.children.find((candidate) => candidate.name === name);
|
|
1721
1767
|
}
|
|
1722
|
-
function
|
|
1723
|
-
|
|
1768
|
+
function requireProperty(node, name) {
|
|
1769
|
+
const value = node.properties.get(name);
|
|
1770
|
+
if (value === undefined)
|
|
1771
|
+
throw new Error(`invalid readseek KDL: ${node.name} is missing '${name}'`);
|
|
1772
|
+
return value;
|
|
1724
1773
|
}
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
});
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
end_line: Int,
|
|
1740
|
-
start_hash: Str,
|
|
1741
|
-
end_hash: Str,
|
|
1742
|
-
hashlines: Hashlines
|
|
1743
|
-
};
|
|
1744
|
-
var SearchCapture = Type.Object({ name: Str, ...SearchSpan });
|
|
1745
|
-
var SearchMatch = Type.Object({
|
|
1746
|
-
pattern_index: Type.Integer({ default: 0 }),
|
|
1747
|
-
...SearchSpan,
|
|
1748
|
-
captures: Type.Array(SearchCapture)
|
|
1749
|
-
});
|
|
1750
|
-
var SearchFileOutput = Type.Object({
|
|
1751
|
-
file: Str,
|
|
1752
|
-
language: Str,
|
|
1753
|
-
file_hash: Str,
|
|
1754
|
-
matches: Type.Array(SearchMatch)
|
|
1755
|
-
});
|
|
1756
|
-
var SearchEnvelope = Type.Object({
|
|
1757
|
-
results: Type.Array(SearchFileOutput),
|
|
1758
|
-
returned_matches: OptInt,
|
|
1759
|
-
truncated: Type.Optional(Bool),
|
|
1760
|
-
byte_basis: OptStr
|
|
1761
|
-
});
|
|
1762
|
-
var RefsEnvelope = Type.Object({
|
|
1763
|
-
references: Type.Array(Type.Object({
|
|
1764
|
-
file: Str,
|
|
1765
|
-
line: Int,
|
|
1766
|
-
column: Int,
|
|
1767
|
-
line_hash: Str,
|
|
1768
|
-
text: Str,
|
|
1769
|
-
symbol: Type.Optional(Type.Object({ qualified_name: OptStr }))
|
|
1770
|
-
}))
|
|
1771
|
-
});
|
|
1772
|
-
var Diagnostic = Type.Object({
|
|
1773
|
-
kind: Type.Union([Type.Literal("error"), Type.Literal("missing")]),
|
|
1774
|
-
start_line: Int,
|
|
1775
|
-
end_line: Int
|
|
1776
|
-
});
|
|
1777
|
-
var CheckEnvelope = Type.Object({
|
|
1778
|
-
file_hash: OptStr,
|
|
1779
|
-
error_count: Int,
|
|
1780
|
-
missing_count: Int,
|
|
1781
|
-
diagnostics: Type.Array(Diagnostic)
|
|
1782
|
-
});
|
|
1783
|
-
var DetectedObject = Type.Object({
|
|
1784
|
-
label: Str,
|
|
1785
|
-
bbox: Type.Tuple([Int, Int, Int, Int])
|
|
1786
|
-
});
|
|
1787
|
-
var PreparedImage = Type.Object({
|
|
1788
|
-
mime: Str,
|
|
1789
|
-
encoding: Type.Literal("base64"),
|
|
1790
|
-
data: Str
|
|
1791
|
-
});
|
|
1792
|
-
var SourceDetection = Type.Object({
|
|
1793
|
-
kind: Type.Literal("source"),
|
|
1794
|
-
type: Str,
|
|
1795
|
-
file: Str,
|
|
1796
|
-
language: Str,
|
|
1797
|
-
engine: OptStr,
|
|
1798
|
-
supported: Bool,
|
|
1799
|
-
mime: OptStr,
|
|
1800
|
-
syntax: OptStr
|
|
1801
|
-
});
|
|
1802
|
-
var ImageDetection = Type.Object({
|
|
1803
|
-
kind: Type.Literal("image"),
|
|
1804
|
-
type: Str,
|
|
1805
|
-
file: Str,
|
|
1806
|
-
mime: OptStr,
|
|
1807
|
-
format: Str,
|
|
1808
|
-
width: Int,
|
|
1809
|
-
height: Int,
|
|
1810
|
-
animated: Bool,
|
|
1811
|
-
encoding: Type.Optional(Type.Literal("base64")),
|
|
1812
|
-
data: OptStr,
|
|
1813
|
-
ocr: OptStr,
|
|
1814
|
-
caption: OptStr,
|
|
1815
|
-
objects: Type.Optional(Type.Array(DetectedObject))
|
|
1816
|
-
});
|
|
1817
|
-
var TextDetection = Type.Object({
|
|
1818
|
-
kind: Type.Literal("text"),
|
|
1819
|
-
type: Str,
|
|
1820
|
-
file: Str,
|
|
1821
|
-
mime: OptStr
|
|
1822
|
-
});
|
|
1823
|
-
var PdfDetection = Type.Object({
|
|
1824
|
-
kind: Type.Literal("pdf"),
|
|
1825
|
-
type: Type.Literal("application/pdf"),
|
|
1826
|
-
file: Str,
|
|
1827
|
-
mime: OptStr,
|
|
1828
|
-
format: Type.Literal("pdf"),
|
|
1829
|
-
pages: Int
|
|
1830
|
-
});
|
|
1831
|
-
var Detection = Type.Union([SourceDetection, ImageDetection, TextDetection, PdfDetection]);
|
|
1832
|
-
var SourceDetectionInput = Type.Omit(SourceDetection, ["kind"]);
|
|
1833
|
-
var ImageDetectionInput = Type.Omit(ImageDetection, ["kind"]);
|
|
1834
|
-
var TextDetectionInput = Type.Omit(TextDetection, ["kind"]);
|
|
1835
|
-
var PdfDetectionInput = Type.Omit(PdfDetection, ["kind"]);
|
|
1836
|
-
var UnspannedContent = Type.Omit(ReadOutput, ["start_line", "end_line"]);
|
|
1837
|
-
var PdfInspectMetadata = Type.Object({ source: Str, format: Type.Literal("pdf"), pages: Int });
|
|
1838
|
-
var DocumentCache = Type.Object({
|
|
1839
|
-
content_hash: Str,
|
|
1840
|
-
state: Type.Union([Type.Literal("built"), Type.Literal("reused")])
|
|
1841
|
-
});
|
|
1842
|
-
var Identifier = Type.Object({
|
|
1843
|
-
text: Str,
|
|
1844
|
-
start_column: Int,
|
|
1845
|
-
end_column: Int,
|
|
1846
|
-
start_byte: Int,
|
|
1847
|
-
end_byte: Int
|
|
1848
|
-
});
|
|
1849
|
-
var IdentifyEnvelope = Type.Object({
|
|
1850
|
-
file: Str,
|
|
1851
|
-
language: Str,
|
|
1852
|
-
engine: OptStr,
|
|
1853
|
-
line_count: Int,
|
|
1854
|
-
file_hash: Str,
|
|
1855
|
-
line: Int,
|
|
1856
|
-
column: Int,
|
|
1857
|
-
line_hash: Str,
|
|
1858
|
-
identifier: Type.Optional(Identifier),
|
|
1859
|
-
symbol: Type.Optional(Type.Object({
|
|
1860
|
-
name: Str,
|
|
1861
|
-
kind: Str,
|
|
1862
|
-
qualified_name: Str,
|
|
1863
|
-
start_line: Int,
|
|
1864
|
-
end_line: Int
|
|
1865
|
-
}))
|
|
1866
|
-
});
|
|
1867
|
-
var EditOutputSchema = Type.Object({
|
|
1868
|
-
file: Str,
|
|
1869
|
-
before_hash: Str,
|
|
1870
|
-
file_hash: Str,
|
|
1871
|
-
plan_hash: Str,
|
|
1872
|
-
applied: Bool,
|
|
1873
|
-
changed: Bool,
|
|
1874
|
-
edit_count: Int,
|
|
1875
|
-
before_content: OptStr,
|
|
1876
|
-
content: OptStr
|
|
1877
|
-
});
|
|
1878
|
-
var RenameConflictSchema = Type.Object({ line: Int, column: Int, reason: Str });
|
|
1879
|
-
var RenameEditSchema = Type.Object({
|
|
1880
|
-
line: Int,
|
|
1881
|
-
start_column: Int,
|
|
1882
|
-
end_column: Int,
|
|
1883
|
-
start_byte: Int,
|
|
1884
|
-
end_byte: Int,
|
|
1885
|
-
occurrence: Str,
|
|
1886
|
-
line_hash: Str,
|
|
1887
|
-
text: Str
|
|
1888
|
-
});
|
|
1889
|
-
var Conflicts = Type.Array(RenameConflictSchema, { default: [] });
|
|
1890
|
-
var Edits = Type.Array(RenameEditSchema, { default: [] });
|
|
1891
|
-
var RenameFileOutputSchema = Type.Object({
|
|
1892
|
-
file: Str,
|
|
1893
|
-
language: Str,
|
|
1894
|
-
engine: OptStr,
|
|
1895
|
-
file_hash: Str,
|
|
1896
|
-
conflicts: Conflicts,
|
|
1897
|
-
edits: Edits
|
|
1898
|
-
});
|
|
1899
|
-
var RenameOutputSchema = Type.Object({
|
|
1900
|
-
file: Str,
|
|
1901
|
-
language: Str,
|
|
1902
|
-
engine: OptStr,
|
|
1903
|
-
file_hash: Str,
|
|
1904
|
-
old_name: Str,
|
|
1905
|
-
new_name: Str,
|
|
1906
|
-
plan_hash: Str,
|
|
1907
|
-
applied: Bool,
|
|
1908
|
-
conflicts: Conflicts,
|
|
1909
|
-
edits: Edits,
|
|
1910
|
-
others: Type.Array(RenameFileOutputSchema, { default: [] })
|
|
1911
|
-
});
|
|
1912
|
-
var DefEnvelope = Type.Object({
|
|
1913
|
-
locations: Type.Array(Type.Object({
|
|
1914
|
-
file: Str,
|
|
1915
|
-
line: Int,
|
|
1916
|
-
column: Int,
|
|
1917
|
-
line_hash: Str,
|
|
1918
|
-
text: Str,
|
|
1919
|
-
kind: OptStr,
|
|
1920
|
-
name: OptStr,
|
|
1921
|
-
qualified_name: OptStr
|
|
1922
|
-
}))
|
|
1923
|
-
});
|
|
1924
|
-
function parseReadOutput(value) {
|
|
1925
|
-
return parse2(ReadOutput, value, "read output");
|
|
1774
|
+
function line(node) {
|
|
1775
|
+
const anchor = requireProperty(node, "anchor");
|
|
1776
|
+
const content = requireProperty(node, "content");
|
|
1777
|
+
if (typeof anchor !== "string" || typeof content !== "string") {
|
|
1778
|
+
throw new Error("invalid readseek KDL line");
|
|
1779
|
+
}
|
|
1780
|
+
const match = /^(\d+):([0-9a-f]+)$/.exec(anchor);
|
|
1781
|
+
if (!match)
|
|
1782
|
+
throw new Error(`invalid readseek KDL line anchor: ${anchor}`);
|
|
1783
|
+
return {
|
|
1784
|
+
line: Number(match[1]),
|
|
1785
|
+
hash: match[2],
|
|
1786
|
+
text: content
|
|
1787
|
+
};
|
|
1926
1788
|
}
|
|
1927
|
-
function
|
|
1928
|
-
return
|
|
1789
|
+
function mapNode(node) {
|
|
1790
|
+
return {
|
|
1791
|
+
...properties(node),
|
|
1792
|
+
children: children(node, "node").map(mapNode)
|
|
1793
|
+
};
|
|
1929
1794
|
}
|
|
1930
|
-
function
|
|
1931
|
-
const
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1795
|
+
function sourceContent(node) {
|
|
1796
|
+
const result = properties(node);
|
|
1797
|
+
result.hashlines = children(node, "line").map(line);
|
|
1798
|
+
const objects = children(node, "object");
|
|
1799
|
+
if (objects.length > 0) {
|
|
1800
|
+
result.objects = objects.map((object) => ({
|
|
1801
|
+
label: requireProperty(object, "label"),
|
|
1802
|
+
bbox: [
|
|
1803
|
+
requireProperty(object, "xmin"),
|
|
1804
|
+
requireProperty(object, "ymin"),
|
|
1805
|
+
requireProperty(object, "xmax"),
|
|
1806
|
+
requireProperty(object, "ymax")
|
|
1807
|
+
]
|
|
1808
|
+
}));
|
|
1809
|
+
}
|
|
1810
|
+
return result;
|
|
1940
1811
|
}
|
|
1941
|
-
function
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1812
|
+
function sourceMap(node) {
|
|
1813
|
+
const root = child(node, "node");
|
|
1814
|
+
return {
|
|
1815
|
+
...properties(node),
|
|
1816
|
+
...root ? { root: mapNode(root) } : {},
|
|
1817
|
+
symbols: children(node, "symbol").map(properties)
|
|
1818
|
+
};
|
|
1946
1819
|
}
|
|
1947
|
-
function
|
|
1948
|
-
const output = parse2(CheckEnvelope, value, "check output");
|
|
1820
|
+
function diagnostics(node) {
|
|
1949
1821
|
return {
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
missingCount: output.missing_count,
|
|
1953
|
-
diagnostics: output.diagnostics
|
|
1822
|
+
...properties(node),
|
|
1823
|
+
diagnostics: children(node, "diagnostic").map(properties)
|
|
1954
1824
|
};
|
|
1955
1825
|
}
|
|
1956
|
-
function
|
|
1957
|
-
const
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1826
|
+
function identity(node) {
|
|
1827
|
+
const result = properties(node);
|
|
1828
|
+
const identifier = child(node, "identifier");
|
|
1829
|
+
const symbol = child(node, "symbol");
|
|
1830
|
+
if (identifier)
|
|
1831
|
+
result.identifier = properties(identifier);
|
|
1832
|
+
if (symbol)
|
|
1833
|
+
result.symbol = properties(symbol);
|
|
1834
|
+
return result;
|
|
1835
|
+
}
|
|
1836
|
+
function sourceDocument(root) {
|
|
1837
|
+
const result = {};
|
|
1838
|
+
const metadata = child(root, "metadata");
|
|
1839
|
+
const cache = child(root, "cache");
|
|
1840
|
+
const content = child(root, "content");
|
|
1841
|
+
const structure = child(root, "structure");
|
|
1842
|
+
const diagnosticOutput = child(root, "diagnostics");
|
|
1843
|
+
const identityOutput = child(root, "cursor");
|
|
1844
|
+
if (metadata)
|
|
1845
|
+
result.metadata = properties(metadata);
|
|
1846
|
+
if (!metadata && !content && !structure && !diagnosticOutput && !identityOutput && root.properties.has("file"))
|
|
1847
|
+
result.file = root.properties.get("file");
|
|
1848
|
+
const assets = children(root, "asset");
|
|
1849
|
+
if (assets.length > 0)
|
|
1850
|
+
result.assets = assets.map(genericNode);
|
|
1851
|
+
if (cache)
|
|
1852
|
+
result.cache = properties(cache);
|
|
1853
|
+
if (content)
|
|
1854
|
+
result.content = sourceContent(content);
|
|
1855
|
+
if (structure)
|
|
1856
|
+
result.structure = sourceMap(structure);
|
|
1857
|
+
if (diagnosticOutput)
|
|
1858
|
+
result.diagnostics = diagnostics(diagnosticOutput);
|
|
1859
|
+
if (identityOutput)
|
|
1860
|
+
result.cursor = identity(identityOutput);
|
|
1861
|
+
return result;
|
|
1862
|
+
}
|
|
1863
|
+
function hit(node) {
|
|
1864
|
+
return {
|
|
1865
|
+
...properties(node),
|
|
1866
|
+
hashlines: children(node, "line").map(line),
|
|
1867
|
+
captures: children(node, "capture").map((capture) => ({
|
|
1868
|
+
...properties(capture),
|
|
1869
|
+
hashlines: children(capture, "line").map(line)
|
|
1870
|
+
}))
|
|
1871
|
+
};
|
|
1872
|
+
}
|
|
1873
|
+
function search(root) {
|
|
1874
|
+
return {
|
|
1875
|
+
...properties(root),
|
|
1876
|
+
results: children(root, "match").map((match) => ({
|
|
1877
|
+
...properties(match),
|
|
1878
|
+
matches: children(match, "hit").map(hit)
|
|
1879
|
+
})),
|
|
1880
|
+
documents: children(root, "document").map((documentNode) => ({
|
|
1881
|
+
...properties(documentNode),
|
|
1882
|
+
hits: children(documentNode, "hit").map(properties)
|
|
1883
|
+
}))
|
|
1884
|
+
};
|
|
1885
|
+
}
|
|
1886
|
+
function references(root) {
|
|
1887
|
+
const parsed = children(root, "reference").map((reference) => {
|
|
1888
|
+
const sourceLine = child(reference, "line");
|
|
1889
|
+
if (!sourceLine)
|
|
1890
|
+
throw new Error("invalid readseek KDL reference: missing line");
|
|
1891
|
+
const parsedLine = line(sourceLine);
|
|
1892
|
+
const symbol = child(reference, "symbol");
|
|
1893
|
+
return {
|
|
1894
|
+
...properties(reference),
|
|
1895
|
+
line_hash: parsedLine.hash,
|
|
1896
|
+
text: parsedLine.text,
|
|
1897
|
+
...symbol ? { symbol: properties(symbol) } : {}
|
|
1898
|
+
};
|
|
1899
|
+
});
|
|
1900
|
+
return {
|
|
1901
|
+
references: parsed,
|
|
1902
|
+
locations: parsed.map((reference) => {
|
|
1903
|
+
const { symbol, ...location } = reference;
|
|
1904
|
+
return symbol && typeof symbol === "object" ? { ...location, ...symbol } : location;
|
|
1905
|
+
})
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1908
|
+
function definitions(root) {
|
|
1909
|
+
return {
|
|
1910
|
+
locations: children(root, "definition").map((definition) => {
|
|
1911
|
+
const symbol = child(definition, "symbol");
|
|
1912
|
+
const sourceLine = child(definition, "line");
|
|
1913
|
+
if (!symbol || !sourceLine) {
|
|
1914
|
+
throw new Error("invalid readseek KDL definition: missing symbol or line");
|
|
1915
|
+
}
|
|
1916
|
+
const symbolProperties = properties(symbol);
|
|
1917
|
+
const parsedLine = line(sourceLine);
|
|
1918
|
+
const definitionColumn = definition.properties.get("column");
|
|
1919
|
+
const nameByte = symbol.properties.get("name_byte");
|
|
1920
|
+
const startByte = symbol.properties.get("start_byte");
|
|
1921
|
+
let column = 1;
|
|
1922
|
+
if (typeof definitionColumn === "number") {
|
|
1923
|
+
column = definitionColumn;
|
|
1924
|
+
} else if (typeof nameByte === "number" && typeof startByte === "number") {
|
|
1925
|
+
column = nameByte - startByte + 1;
|
|
1926
|
+
}
|
|
1927
|
+
return {
|
|
1928
|
+
file: requireProperty(definition, "file"),
|
|
1929
|
+
line: parsedLine.line,
|
|
1930
|
+
column,
|
|
1931
|
+
line_hash: parsedLine.hash,
|
|
1932
|
+
text: parsedLine.text,
|
|
1933
|
+
kind: symbolProperties.kind,
|
|
1934
|
+
name: symbolProperties.name,
|
|
1935
|
+
qualified_name: symbolProperties.qualified_name
|
|
1936
|
+
};
|
|
1937
|
+
})
|
|
1938
|
+
};
|
|
1939
|
+
}
|
|
1940
|
+
function edit(root) {
|
|
1941
|
+
const result = properties(root);
|
|
1942
|
+
for (const name of ["before_content", "content"]) {
|
|
1943
|
+
const contentNode = child(root, name);
|
|
1944
|
+
if (contentNode)
|
|
1945
|
+
result[name] = requireProperty(contentNode, "content");
|
|
1966
1946
|
}
|
|
1967
|
-
return
|
|
1947
|
+
return result;
|
|
1968
1948
|
}
|
|
1969
|
-
function
|
|
1970
|
-
const
|
|
1971
|
-
if (
|
|
1972
|
-
throw new Error("invalid readseek
|
|
1973
|
-
return
|
|
1949
|
+
function renameEdit(node) {
|
|
1950
|
+
const sourceLine = child(node, "line");
|
|
1951
|
+
if (!sourceLine)
|
|
1952
|
+
throw new Error("invalid readseek KDL rename edit: missing line");
|
|
1953
|
+
return {
|
|
1954
|
+
...properties(node),
|
|
1955
|
+
text: requireProperty(sourceLine, "content")
|
|
1956
|
+
};
|
|
1974
1957
|
}
|
|
1975
|
-
function
|
|
1976
|
-
const output = value ?? {};
|
|
1977
|
-
if (output.hashlines === undefined || output.start_line !== undefined)
|
|
1978
|
-
return parseReadOutput(value);
|
|
1979
|
-
const spanned = parse2(UnspannedContent, value, "content");
|
|
1958
|
+
function renameFile(node) {
|
|
1980
1959
|
return {
|
|
1981
|
-
...
|
|
1982
|
-
|
|
1983
|
-
|
|
1960
|
+
...properties(node),
|
|
1961
|
+
edits: children(node, "edit").map(renameEdit),
|
|
1962
|
+
conflicts: children(node, "conflict").map(properties)
|
|
1984
1963
|
};
|
|
1985
1964
|
}
|
|
1986
|
-
function
|
|
1987
|
-
return
|
|
1965
|
+
function rename(root) {
|
|
1966
|
+
return {
|
|
1967
|
+
...renameFile(root),
|
|
1968
|
+
others: children(root, "other").map(renameFile)
|
|
1969
|
+
};
|
|
1988
1970
|
}
|
|
1989
|
-
function
|
|
1990
|
-
|
|
1971
|
+
function genericNode(node) {
|
|
1972
|
+
const result = properties(node);
|
|
1973
|
+
const textNode = child(node, "text");
|
|
1974
|
+
const bbox = child(node, "bbox");
|
|
1975
|
+
if (textNode)
|
|
1976
|
+
result.text = requireProperty(textNode, "content");
|
|
1977
|
+
if (bbox)
|
|
1978
|
+
result.bbox = properties(bbox);
|
|
1979
|
+
const objects = children(node, "object");
|
|
1980
|
+
if (objects.length > 0)
|
|
1981
|
+
result.objects = objects.map((object) => ({
|
|
1982
|
+
label: requireProperty(object, "label"),
|
|
1983
|
+
bbox: [requireProperty(object, "x0"), requireProperty(object, "y0"), requireProperty(object, "x1"), requireProperty(object, "y1")]
|
|
1984
|
+
}));
|
|
1985
|
+
return result;
|
|
1991
1986
|
}
|
|
1992
|
-
function
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1987
|
+
function pdfDocument(root) {
|
|
1988
|
+
return {
|
|
1989
|
+
...properties(root),
|
|
1990
|
+
nodes: children(root, "node").map(genericNode),
|
|
1991
|
+
assets: children(root, "asset").map(genericNode),
|
|
1992
|
+
vision: children(root, "vision").map(genericNode)
|
|
1993
|
+
};
|
|
1999
1994
|
}
|
|
2000
|
-
function
|
|
2001
|
-
|
|
1995
|
+
function parseReadSeekKdl(text) {
|
|
1996
|
+
const root = parseKdlDocument(text);
|
|
1997
|
+
switch (root.name) {
|
|
1998
|
+
case "document":
|
|
1999
|
+
return root.properties.has("format") ? pdfDocument(root) : sourceDocument(root);
|
|
2000
|
+
case "search":
|
|
2001
|
+
return search(root);
|
|
2002
|
+
case "check":
|
|
2003
|
+
return diagnostics(root);
|
|
2004
|
+
case "refs":
|
|
2005
|
+
return references(root);
|
|
2006
|
+
case "def":
|
|
2007
|
+
return definitions(root);
|
|
2008
|
+
case "edit":
|
|
2009
|
+
return edit(root);
|
|
2010
|
+
case "edit-batch":
|
|
2011
|
+
return { ...properties(root), files: children(root, "file").map(edit) };
|
|
2012
|
+
case "rename":
|
|
2013
|
+
return rename(root);
|
|
2014
|
+
default:
|
|
2015
|
+
throw new Error(`unsupported readseek KDL root: ${root.name}`);
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
// src/process.ts
|
|
2019
|
+
var DEFAULT_READSEEK_TIMEOUT_MS = 120000;
|
|
2020
|
+
var DEFAULT_MAX_OUTPUT_BYTES = 32 * 1024 * 1024;
|
|
2021
|
+
function readSeekProcessEnvironment() {
|
|
2022
|
+
return process.platform === "linux" ? { ...process.env, APPIMAGE_EXTRACT_AND_RUN: "1" } : process.env;
|
|
2023
|
+
}
|
|
2024
|
+
function resolveProcessLimits(options = {}) {
|
|
2025
|
+
return {
|
|
2026
|
+
timeoutMs: options.timeoutMs ?? DEFAULT_READSEEK_TIMEOUT_MS,
|
|
2027
|
+
maxOutputBytes: options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES,
|
|
2028
|
+
cancelable: options.cancelable !== false
|
|
2029
|
+
};
|
|
2002
2030
|
}
|
|
2003
|
-
function
|
|
2004
|
-
|
|
2031
|
+
function readSeekCancellationError(signal) {
|
|
2032
|
+
const reason = signal?.reason;
|
|
2033
|
+
return reason instanceof Error && reason.name !== "AbortError" ? reason : new Error("readseek cancelled");
|
|
2005
2034
|
}
|
|
2006
|
-
function
|
|
2007
|
-
|
|
2035
|
+
function failureFromProcessResult(result, options = {}) {
|
|
2036
|
+
if (options.overflow) {
|
|
2037
|
+
return new Error(`readseek ${options.overflow} exceeded the ${options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES}-byte output limit`);
|
|
2038
|
+
}
|
|
2039
|
+
if (options.timedOut) {
|
|
2040
|
+
return new Error(`readseek timed out after ${options.timeoutMs ?? DEFAULT_READSEEK_TIMEOUT_MS} ms`);
|
|
2041
|
+
}
|
|
2042
|
+
const cleaned = cleanReadSeekErrorText(result.stderr);
|
|
2043
|
+
if (cleaned)
|
|
2044
|
+
return new Error(cleaned);
|
|
2045
|
+
if (result.signal)
|
|
2046
|
+
return new Error(`readseek killed by signal ${result.signal}`);
|
|
2047
|
+
return new Error(`readseek exited with status ${result.exitCode}`);
|
|
2008
2048
|
}
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2049
|
+
function acceptsReadSeekExitCode(args, exitCode) {
|
|
2050
|
+
if (exitCode === 0)
|
|
2051
|
+
return true;
|
|
2052
|
+
if (exitCode !== 1)
|
|
2053
|
+
return false;
|
|
2054
|
+
let index = 0;
|
|
2055
|
+
const valued = new Set(["-C", "--directory", "--output", "--readseek-dir"]);
|
|
2056
|
+
while (index < args.length) {
|
|
2057
|
+
const arg = args[index];
|
|
2058
|
+
if (valued.has(arg)) {
|
|
2059
|
+
index += 2;
|
|
2060
|
+
continue;
|
|
2061
|
+
}
|
|
2062
|
+
if ([...valued].some((flag) => arg.startsWith(`${flag}=`)) || arg === "--kdl") {
|
|
2063
|
+
index++;
|
|
2064
|
+
continue;
|
|
2065
|
+
}
|
|
2066
|
+
return arg === "find" || arg === "check";
|
|
2017
2067
|
}
|
|
2018
|
-
return
|
|
2068
|
+
return false;
|
|
2019
2069
|
}
|
|
2020
|
-
function
|
|
2021
|
-
if (!
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
const result = {};
|
|
2025
|
-
if (output.metadata !== undefined)
|
|
2026
|
-
result.metadata = parseDetectOutput(output.metadata);
|
|
2027
|
-
if (output.cache !== undefined)
|
|
2028
|
-
result.cache = parseDocumentCache(output.cache);
|
|
2029
|
-
if (output.content !== undefined)
|
|
2030
|
-
result.content = output.content;
|
|
2031
|
-
if (output.map !== undefined)
|
|
2032
|
-
result.map = parseMapOutput(output.map);
|
|
2033
|
-
if (output.diagnostics !== undefined)
|
|
2034
|
-
result.diagnostics = parseCheckOutput(output.diagnostics);
|
|
2035
|
-
if (output.identity !== undefined)
|
|
2036
|
-
result.identity = parseIdentifyOutput(output.identity);
|
|
2037
|
-
return result;
|
|
2070
|
+
function ensureSuccessfulStdout(result, args = []) {
|
|
2071
|
+
if (!result.signal && acceptsReadSeekExitCode(args, result.exitCode))
|
|
2072
|
+
return result.stdout;
|
|
2073
|
+
throw failureFromProcessResult(result);
|
|
2038
2074
|
}
|
|
2039
|
-
function
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2075
|
+
function parseSuccessfulKdl(result, args = []) {
|
|
2076
|
+
return parseReadSeekKdl(ensureSuccessfulStdout(result, args));
|
|
2077
|
+
}
|
|
2078
|
+
// src/process-node.ts
|
|
2079
|
+
import { spawn } from "node:child_process";
|
|
2080
|
+
import { StringDecoder } from "node:string_decoder";
|
|
2081
|
+
function attachBoundedStream(stream, maxOutputBytes, onOverflow) {
|
|
2082
|
+
const decoder = new StringDecoder("utf8");
|
|
2083
|
+
let text = "";
|
|
2084
|
+
let bytes = 0;
|
|
2085
|
+
let overflowed = false;
|
|
2086
|
+
stream.on("data", (chunk) => {
|
|
2087
|
+
if (overflowed)
|
|
2088
|
+
return;
|
|
2089
|
+
const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
2090
|
+
bytes += buffer.length;
|
|
2091
|
+
if (bytes > maxOutputBytes) {
|
|
2092
|
+
overflowed = true;
|
|
2093
|
+
onOverflow();
|
|
2094
|
+
return;
|
|
2095
|
+
}
|
|
2096
|
+
text += decoder.write(buffer);
|
|
2097
|
+
});
|
|
2098
|
+
return {
|
|
2099
|
+
text: () => text + decoder.end()
|
|
2100
|
+
};
|
|
2101
|
+
}
|
|
2102
|
+
async function runReadSeekNode(binaryPath, args, options = {}) {
|
|
2103
|
+
const limits = resolveProcessLimits(options);
|
|
2104
|
+
if (limits.cancelable && options.signal?.aborted) {
|
|
2105
|
+
throw readSeekCancellationError(options.signal);
|
|
2054
2106
|
}
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2107
|
+
return await new Promise((resolve, reject) => {
|
|
2108
|
+
let settled = false;
|
|
2109
|
+
let child;
|
|
2110
|
+
let timer;
|
|
2111
|
+
const finish = (result) => {
|
|
2112
|
+
if (settled)
|
|
2113
|
+
return;
|
|
2114
|
+
settled = true;
|
|
2115
|
+
if (timer !== undefined)
|
|
2116
|
+
clearTimeout(timer);
|
|
2117
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
2118
|
+
resolve(result);
|
|
2061
2119
|
};
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2120
|
+
const fail = (error) => {
|
|
2121
|
+
if (settled)
|
|
2122
|
+
return;
|
|
2123
|
+
settled = true;
|
|
2124
|
+
if (timer !== undefined)
|
|
2125
|
+
clearTimeout(timer);
|
|
2126
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
2127
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
2128
|
+
};
|
|
2129
|
+
const terminate = (error) => {
|
|
2130
|
+
if (settled)
|
|
2131
|
+
return;
|
|
2132
|
+
fail(error);
|
|
2133
|
+
try {
|
|
2134
|
+
child.kill("SIGKILL");
|
|
2135
|
+
} catch {}
|
|
2136
|
+
};
|
|
2137
|
+
const onAbort = () => {
|
|
2138
|
+
terminate(readSeekCancellationError(options.signal));
|
|
2139
|
+
};
|
|
2140
|
+
try {
|
|
2141
|
+
child = spawn(binaryPath, [...args], {
|
|
2142
|
+
cwd: options.cwd,
|
|
2143
|
+
env: readSeekProcessEnvironment(),
|
|
2144
|
+
shell: false,
|
|
2145
|
+
stdio: [options.stdin === undefined ? "ignore" : "pipe", "pipe", "pipe"],
|
|
2146
|
+
windowsHide: true
|
|
2147
|
+
});
|
|
2148
|
+
} catch (error) {
|
|
2149
|
+
fail(error);
|
|
2150
|
+
return;
|
|
2151
|
+
}
|
|
2152
|
+
const stdout = attachBoundedStream(child.stdout, limits.maxOutputBytes, () => {
|
|
2153
|
+
terminate(failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { overflow: "stdout", maxOutputBytes: limits.maxOutputBytes }));
|
|
2090
2154
|
});
|
|
2091
|
-
const
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2155
|
+
const stderr = attachBoundedStream(child.stderr, limits.maxOutputBytes, () => {
|
|
2156
|
+
terminate(failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { overflow: "stderr", maxOutputBytes: limits.maxOutputBytes }));
|
|
2157
|
+
});
|
|
2158
|
+
timer = setTimeout(() => {
|
|
2159
|
+
terminate(failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { timedOut: true, timeoutMs: limits.timeoutMs }));
|
|
2160
|
+
}, limits.timeoutMs);
|
|
2161
|
+
timer.unref?.();
|
|
2162
|
+
if (limits.cancelable && options.signal) {
|
|
2163
|
+
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
2099
2164
|
}
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
inspectText,
|
|
2105
|
-
inspectContent,
|
|
2106
|
-
async extract(target, selector, output, options = {}) {
|
|
2107
|
-
await runner.text(buildExtractArgs({
|
|
2108
|
-
path: target,
|
|
2109
|
-
selector,
|
|
2110
|
-
output,
|
|
2111
|
-
stdinName: options.stdinName
|
|
2112
|
-
}), {
|
|
2113
|
-
signal: options.signal,
|
|
2114
|
-
stdin: options.stdin,
|
|
2115
|
-
timeoutMs: options.timeoutMs,
|
|
2116
|
-
cancelable: options.cancelable
|
|
2117
|
-
});
|
|
2118
|
-
},
|
|
2119
|
-
async image(filePath, modes, options = {}) {
|
|
2120
|
-
if (modes.length === 0)
|
|
2121
|
-
throw new Error(`readseek returned no image analysis for ${filePath}`);
|
|
2122
|
-
const inspected = await inspectContent(filePath, {
|
|
2123
|
-
visionMode: modes.length > 1 ? "all" : modes[0],
|
|
2124
|
-
signal: options.signal,
|
|
2125
|
-
vision: true
|
|
2165
|
+
if (options.stdin !== undefined) {
|
|
2166
|
+
child.stdin.on("error", (error) => {
|
|
2167
|
+
if (error.code !== "EPIPE")
|
|
2168
|
+
fail(error);
|
|
2126
2169
|
});
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2170
|
+
child.stdin.end(options.stdin, "utf8");
|
|
2171
|
+
}
|
|
2172
|
+
child.on("error", fail);
|
|
2173
|
+
child.on("close", (code, signal) => {
|
|
2174
|
+
finish({
|
|
2175
|
+
stdout: stdout.text(),
|
|
2176
|
+
stderr: stderr.text(),
|
|
2177
|
+
exitCode: code,
|
|
2178
|
+
signal
|
|
2135
2179
|
});
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2180
|
+
});
|
|
2181
|
+
});
|
|
2182
|
+
}
|
|
2183
|
+
async function runReadSeekNodeText(binaryPath, args, options = {}) {
|
|
2184
|
+
return ensureSuccessfulStdout(await runReadSeekNode(binaryPath, args, options), args);
|
|
2185
|
+
}
|
|
2186
|
+
async function runReadSeekNodeKdl(binaryPath, args, options = {}) {
|
|
2187
|
+
return parseSuccessfulKdl(await runReadSeekNode(binaryPath, args, options), args);
|
|
2188
|
+
}
|
|
2189
|
+
// src/process-bun.ts
|
|
2190
|
+
function getBunSpawn() {
|
|
2191
|
+
const bunGlobal = globalThis;
|
|
2192
|
+
const spawn = bunGlobal.Bun?.spawn;
|
|
2193
|
+
if (typeof spawn !== "function") {
|
|
2194
|
+
throw new Error("Bun.spawn is unavailable in this runtime");
|
|
2195
|
+
}
|
|
2196
|
+
return spawn;
|
|
2197
|
+
}
|
|
2198
|
+
async function readBoundedText(stream, streamName, maxOutputBytes, onOverflow) {
|
|
2199
|
+
const reader = stream.getReader();
|
|
2200
|
+
const chunks = [];
|
|
2201
|
+
let totalBytes = 0;
|
|
2202
|
+
try {
|
|
2203
|
+
while (true) {
|
|
2204
|
+
const { done, value } = await reader.read();
|
|
2205
|
+
if (done)
|
|
2206
|
+
break;
|
|
2207
|
+
totalBytes += value.byteLength;
|
|
2208
|
+
if (totalBytes > maxOutputBytes) {
|
|
2209
|
+
onOverflow();
|
|
2210
|
+
await reader.cancel().catch(() => {
|
|
2211
|
+
return;
|
|
2212
|
+
});
|
|
2213
|
+
throw failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { overflow: streamName, maxOutputBytes });
|
|
2139
2214
|
}
|
|
2140
|
-
|
|
2141
|
-
},
|
|
2142
|
-
async search(target, pattern, options = {}) {
|
|
2143
|
-
const args = buildSearchArgs({
|
|
2144
|
-
path: target,
|
|
2145
|
-
pattern,
|
|
2146
|
-
language: options.language,
|
|
2147
|
-
limit: options.limit,
|
|
2148
|
-
gitScope: options.gitScope
|
|
2149
|
-
});
|
|
2150
|
-
return parseSearchOutput(await runner.kdl(args, { signal: options.signal }));
|
|
2151
|
-
},
|
|
2152
|
-
async refs(target, options = {}) {
|
|
2153
|
-
const args = buildRefsArgs({
|
|
2154
|
-
path: target,
|
|
2155
|
-
name: options.name,
|
|
2156
|
-
scope: options.scope,
|
|
2157
|
-
line: options.line,
|
|
2158
|
-
column: options.column,
|
|
2159
|
-
language: options.language,
|
|
2160
|
-
gitScope: options.gitScope
|
|
2161
|
-
});
|
|
2162
|
-
return parseRefsOutput(await runner.kdl(args, { signal: options.signal }));
|
|
2163
|
-
},
|
|
2164
|
-
async def(target, options) {
|
|
2165
|
-
const args = buildDefArgs({
|
|
2166
|
-
path: target,
|
|
2167
|
-
name: options.name,
|
|
2168
|
-
language: options.language,
|
|
2169
|
-
gitScope: options.gitScope
|
|
2170
|
-
});
|
|
2171
|
-
return parseDefOutput(await runner.kdl(args, { signal: options.signal }));
|
|
2172
|
-
},
|
|
2173
|
-
async check(filePath, content, options = {}) {
|
|
2174
|
-
const envelope = await inspectSource("-", {
|
|
2175
|
-
select: "diagnostics",
|
|
2176
|
-
stdin: content,
|
|
2177
|
-
stdinName: filePath,
|
|
2178
|
-
signal: options.signal
|
|
2179
|
-
});
|
|
2180
|
-
if (!envelope.diagnostics)
|
|
2181
|
-
throw new Error("invalid readseek diagnostics: missing diagnostics facet");
|
|
2182
|
-
return envelope.diagnostics;
|
|
2183
|
-
},
|
|
2184
|
-
async identify(filePath, content, options) {
|
|
2185
|
-
const envelope = await inspectSource("-", {
|
|
2186
|
-
select: "identity",
|
|
2187
|
-
stdin: content,
|
|
2188
|
-
stdinName: filePath,
|
|
2189
|
-
selector: buildLineLocation(options.line, options.column),
|
|
2190
|
-
language: options.language,
|
|
2191
|
-
signal: options.signal
|
|
2192
|
-
});
|
|
2193
|
-
if (!envelope.identity)
|
|
2194
|
-
throw new Error("invalid readseek identity: missing identity facet");
|
|
2195
|
-
return envelope.identity;
|
|
2196
|
-
},
|
|
2197
|
-
async detect(filePath, options = {}) {
|
|
2198
|
-
const inspected = await inspect(filePath, { select: "metadata", signal: options.signal });
|
|
2199
|
-
const pdf = parsePdfInspectMetadata(inspected);
|
|
2200
|
-
if (pdf)
|
|
2201
|
-
return pdf;
|
|
2202
|
-
return requireInspectMetadata(parseSourceInspectEnvelope(inspected), "metadata");
|
|
2203
|
-
},
|
|
2204
|
-
async edit(filePath, edits, options = {}) {
|
|
2205
|
-
const args = buildEditArgs({
|
|
2206
|
-
path: filePath,
|
|
2207
|
-
apply: options.apply,
|
|
2208
|
-
planHash: options.planHash,
|
|
2209
|
-
language: options.language,
|
|
2210
|
-
requestFromStdin: true
|
|
2211
|
-
});
|
|
2212
|
-
return parseEditOutput(await runner.kdl(args, {
|
|
2213
|
-
signal: options.signal,
|
|
2214
|
-
stdin: serializeEditPlan(edits),
|
|
2215
|
-
timeoutMs: options.timeoutMs,
|
|
2216
|
-
cancelable: options.cancelable
|
|
2217
|
-
}));
|
|
2218
|
-
},
|
|
2219
|
-
async rename(filePath, options) {
|
|
2220
|
-
const args = buildRenameArgs({
|
|
2221
|
-
path: filePath,
|
|
2222
|
-
to: options.to,
|
|
2223
|
-
line: options.line,
|
|
2224
|
-
column: options.column,
|
|
2225
|
-
workspace: options.workspace,
|
|
2226
|
-
apply: options.apply,
|
|
2227
|
-
planHash: options.planHash,
|
|
2228
|
-
language: options.language,
|
|
2229
|
-
gitScope: options.gitScope
|
|
2230
|
-
});
|
|
2231
|
-
return parseRenameOutput(await runner.kdl(args, { signal: options.signal }));
|
|
2215
|
+
chunks.push(value);
|
|
2232
2216
|
}
|
|
2217
|
+
} finally {
|
|
2218
|
+
reader.releaseLock();
|
|
2219
|
+
}
|
|
2220
|
+
const bytes = new Uint8Array(totalBytes);
|
|
2221
|
+
let offset = 0;
|
|
2222
|
+
for (const chunk of chunks) {
|
|
2223
|
+
bytes.set(chunk, offset);
|
|
2224
|
+
offset += chunk.byteLength;
|
|
2225
|
+
}
|
|
2226
|
+
return new TextDecoder().decode(bytes);
|
|
2227
|
+
}
|
|
2228
|
+
async function runReadSeekBun(binaryPath, args, options = {}) {
|
|
2229
|
+
const limits = resolveProcessLimits(options);
|
|
2230
|
+
if (limits.cancelable && options.signal?.aborted) {
|
|
2231
|
+
throw readSeekCancellationError(options.signal);
|
|
2232
|
+
}
|
|
2233
|
+
const spawn = getBunSpawn();
|
|
2234
|
+
const stdin = options.stdin === undefined ? undefined : new TextEncoder().encode(options.stdin);
|
|
2235
|
+
const spawnOptions = {
|
|
2236
|
+
cwd: options.cwd,
|
|
2237
|
+
env: readSeekProcessEnvironment(),
|
|
2238
|
+
stderr: "pipe",
|
|
2239
|
+
stdin,
|
|
2240
|
+
stdout: "pipe"
|
|
2241
|
+
};
|
|
2242
|
+
const child = spawn([binaryPath, ...args], limits.cancelable && options.signal ? { ...spawnOptions, killSignal: "SIGKILL", signal: options.signal } : spawnOptions);
|
|
2243
|
+
const killForOverflow = () => {
|
|
2244
|
+
try {
|
|
2245
|
+
child.kill("SIGKILL");
|
|
2246
|
+
} catch {}
|
|
2233
2247
|
};
|
|
2248
|
+
let timeout;
|
|
2249
|
+
const timeoutResult = new Promise((_resolve, reject) => {
|
|
2250
|
+
timeout = setTimeout(() => {
|
|
2251
|
+
try {
|
|
2252
|
+
child.kill("SIGKILL");
|
|
2253
|
+
} catch {}
|
|
2254
|
+
reject(failureFromProcessResult({ stdout: "", stderr: "", exitCode: null, signal: null }, { timedOut: true, timeoutMs: limits.timeoutMs }));
|
|
2255
|
+
}, limits.timeoutMs);
|
|
2256
|
+
timeout.unref?.();
|
|
2257
|
+
});
|
|
2258
|
+
const pending = Promise.all([
|
|
2259
|
+
readBoundedText(child.stdout, "stdout", limits.maxOutputBytes, killForOverflow),
|
|
2260
|
+
readBoundedText(child.stderr, "stderr", limits.maxOutputBytes, killForOverflow),
|
|
2261
|
+
child.exited
|
|
2262
|
+
]);
|
|
2263
|
+
try {
|
|
2264
|
+
const [stdout, stderr, exitCode] = await Promise.race([pending, timeoutResult]);
|
|
2265
|
+
if (limits.cancelable && options.signal?.aborted)
|
|
2266
|
+
throw readSeekCancellationError(options.signal);
|
|
2267
|
+
return { stdout, stderr, exitCode, signal: null };
|
|
2268
|
+
} finally {
|
|
2269
|
+
if (timeout !== undefined)
|
|
2270
|
+
clearTimeout(timeout);
|
|
2271
|
+
pending.catch(() => {
|
|
2272
|
+
return;
|
|
2273
|
+
});
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
async function runReadSeekBunText(binaryPath, args, options = {}) {
|
|
2277
|
+
return ensureSuccessfulStdout(await runReadSeekBun(binaryPath, args, options), args);
|
|
2278
|
+
}
|
|
2279
|
+
async function runReadSeekBunKdl(binaryPath, args, options = {}) {
|
|
2280
|
+
return parseSuccessfulKdl(await runReadSeekBun(binaryPath, args, options), args);
|
|
2234
2281
|
}
|
|
2235
2282
|
export {
|
|
2236
2283
|
BUILTIN_FALLBACKS,
|
|
2237
|
-
DEFAULT_INSPECT_MAP_DEPTH,
|
|
2238
2284
|
DEFAULT_MAX_OUTPUT_BYTES,
|
|
2239
2285
|
DEFAULT_READSEEK_TIMEOUT_MS,
|
|
2286
|
+
DEFAULT_STRUCTURE_DEPTH,
|
|
2240
2287
|
EDIT_VARIANTS,
|
|
2241
2288
|
GIT_SCOPES,
|
|
2242
2289
|
HASH_LEN,
|
|
2243
|
-
INSPECT_FACETS,
|
|
2244
2290
|
PARAM_DESCRIPTIONS,
|
|
2245
2291
|
READSEEK_BINARY_ENV,
|
|
2246
2292
|
READSEEK_PLATFORM_PACKAGES,
|
|
@@ -2249,19 +2295,26 @@ export {
|
|
|
2249
2295
|
TOOL_CONTRACTS,
|
|
2250
2296
|
TOOL_DESCRIPTIONS,
|
|
2251
2297
|
TOOL_NAMES,
|
|
2252
|
-
VISION_ANALYSIS_MODES,
|
|
2253
2298
|
VISION_LEVELS,
|
|
2254
|
-
|
|
2299
|
+
acceptsReadSeekExitCode,
|
|
2255
2300
|
appendApplyAndPlanHash,
|
|
2256
2301
|
appendGitScopeArgs,
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2302
|
+
buildCheckRulesArgs,
|
|
2303
|
+
buildCheckSyntaxArgs,
|
|
2304
|
+
buildDetectObjectsArgs,
|
|
2305
|
+
buildEditTextArgs,
|
|
2306
|
+
buildFindDefinitionsArgs,
|
|
2307
|
+
buildFindNodesArgs,
|
|
2308
|
+
buildFindReferencesArgs,
|
|
2309
|
+
buildFindTextArgs,
|
|
2310
|
+
buildGenerateCaptionArgs,
|
|
2261
2311
|
buildLineLocation,
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2312
|
+
buildRecognizeTextArgs,
|
|
2313
|
+
buildRenameSymbolArgs,
|
|
2314
|
+
buildShowAssetsArgs,
|
|
2315
|
+
buildShowContentArgs,
|
|
2316
|
+
buildShowMetadataArgs,
|
|
2317
|
+
buildShowStructureArgs,
|
|
2265
2318
|
canonicalPathKey,
|
|
2266
2319
|
classifyReadSeekFailure,
|
|
2267
2320
|
cleanReadSeekErrorText,
|
|
@@ -2275,12 +2328,16 @@ export {
|
|
|
2275
2328
|
expandUserPath,
|
|
2276
2329
|
failureFromProcessResult,
|
|
2277
2330
|
fallbackToolDescriptionMap,
|
|
2331
|
+
formatShowResult,
|
|
2278
2332
|
getToolContract,
|
|
2333
|
+
isShowTool,
|
|
2279
2334
|
isSubPath,
|
|
2280
2335
|
parseLineAnchor,
|
|
2281
2336
|
parseReadSeekKdl,
|
|
2337
|
+
parseSelector,
|
|
2282
2338
|
parseSuccessfulKdl,
|
|
2283
2339
|
preferredToolDescriptionMap,
|
|
2340
|
+
presentShowResult,
|
|
2284
2341
|
readSeekBinaryName,
|
|
2285
2342
|
readSeekPlatformKey,
|
|
2286
2343
|
readSeekProcessEnvironment,
|
|
@@ -2306,6 +2363,5 @@ export {
|
|
|
2306
2363
|
serializeEditPlan,
|
|
2307
2364
|
tryParseLineAnchor,
|
|
2308
2365
|
validateExactlyOneEditVariant,
|
|
2309
|
-
|
|
2310
|
-
validateVisionLevelVsMode
|
|
2366
|
+
validateReferencesSelection
|
|
2311
2367
|
};
|