pi-readseek 0.11.0 → 0.11.2
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 +5 -0
- package/dist/index.ts +333 -28
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -27,6 +27,11 @@ attachments without a separate extraction call. Reading never runs local inferen
|
|
|
27
27
|
captioning, detection, and OCR require their explicit tools. Legacy tool names and
|
|
28
28
|
selectable inspection facets are removed.
|
|
29
29
|
|
|
30
|
+
The four `show` tools display readable summaries and grouped details rather than
|
|
31
|
+
JSON dumps. Expand with Ctrl+O to reveal content; long lines wrap on resize.
|
|
32
|
+
Source anchors, selected document nodes, asset paths, and continuation notices
|
|
33
|
+
remain visible. Native results are retained in tool-result details.
|
|
34
|
+
|
|
30
35
|
## Settings
|
|
31
36
|
|
|
32
37
|
Add `readseek` to `~/.pi/agent/settings.json` or `.pi/settings.json`:
|
package/dist/index.ts
CHANGED
|
@@ -1246,6 +1246,221 @@ function createReadSeekClient(runner) {
|
|
|
1246
1246
|
}
|
|
1247
1247
|
};
|
|
1248
1248
|
}
|
|
1249
|
+
// ../readseek-api/src/show-presentation.ts
|
|
1250
|
+
function isShowTool(name) {
|
|
1251
|
+
return name === "show_content" || name === "show_structure" || name === "show_metadata" || name === "show_assets";
|
|
1252
|
+
}
|
|
1253
|
+
function record(value) {
|
|
1254
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
1255
|
+
}
|
|
1256
|
+
function records(value) {
|
|
1257
|
+
return Array.isArray(value) ? value.map(record) : [];
|
|
1258
|
+
}
|
|
1259
|
+
function text(value) {
|
|
1260
|
+
return typeof value === "string" ? value : "";
|
|
1261
|
+
}
|
|
1262
|
+
function count(value) {
|
|
1263
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
1264
|
+
}
|
|
1265
|
+
function safe(value) {
|
|
1266
|
+
return value.replace(/[\x00-\x09\x0b-\x1f\x7f-\x9f]/g, (char) => {
|
|
1267
|
+
if (char === "\t")
|
|
1268
|
+
return "\\t";
|
|
1269
|
+
if (char === "\r")
|
|
1270
|
+
return "\\r";
|
|
1271
|
+
return `\\x${char.charCodeAt(0).toString(16).padStart(2, "0")}`;
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1274
|
+
function inline(value) {
|
|
1275
|
+
return safe(text(value)).replaceAll(`
|
|
1276
|
+
`, "\\n");
|
|
1277
|
+
}
|
|
1278
|
+
function plural(n, unit) {
|
|
1279
|
+
return `${n} ${unit}${n === 1 ? "" : "s"}`;
|
|
1280
|
+
}
|
|
1281
|
+
function fields(value, omit = []) {
|
|
1282
|
+
return Object.entries(value).flatMap(([key, item]) => {
|
|
1283
|
+
if (omit.includes(key) || item === undefined || item === null || typeof item === "object")
|
|
1284
|
+
return [];
|
|
1285
|
+
const label = key.replaceAll("_", " ");
|
|
1286
|
+
return [`${label[0]?.toUpperCase() ?? ""}${label.slice(1)}: ${safe(String(item))}`];
|
|
1287
|
+
}).join(`
|
|
1288
|
+
`);
|
|
1289
|
+
}
|
|
1290
|
+
function location(value) {
|
|
1291
|
+
const start = text(value.start_anchor) || (count(value.start_line) !== undefined ? `${value.start_line}${text(value.start_hash) ? `:${value.start_hash}` : ""}` : "");
|
|
1292
|
+
const end = text(value.end_anchor) || (count(value.end_line) !== undefined ? `${value.end_line}${text(value.end_hash) ? `:${value.end_hash}` : ""}` : "");
|
|
1293
|
+
return start ? ` ${inline(start)}${end && end !== start ? ` - ${inline(end)}` : ""}` : "";
|
|
1294
|
+
}
|
|
1295
|
+
function sourceStructure(structure) {
|
|
1296
|
+
const sections = [];
|
|
1297
|
+
if (structure.root) {
|
|
1298
|
+
const lines = [];
|
|
1299
|
+
const stack = [{ node: record(structure.root), depth: 0 }];
|
|
1300
|
+
while (stack.length > 0) {
|
|
1301
|
+
const { node, depth } = stack.pop();
|
|
1302
|
+
lines.push(`${" ".repeat(Math.min(depth, 12))}${inline(node.kind) || "node"}${text(node.name) ? ` ${inline(node.name)}` : ""}${location(node)}`);
|
|
1303
|
+
const children = records(node.children);
|
|
1304
|
+
for (let i = children.length - 1;i >= 0; i--)
|
|
1305
|
+
stack.push({ node: children[i], depth: depth + 1 });
|
|
1306
|
+
}
|
|
1307
|
+
sections.push(`Tree
|
|
1308
|
+
${lines.join(`
|
|
1309
|
+
`)}`);
|
|
1310
|
+
}
|
|
1311
|
+
const symbols = records(structure.symbols);
|
|
1312
|
+
if (symbols.length > 0) {
|
|
1313
|
+
sections.push(`Symbols
|
|
1314
|
+
${symbols.map((symbol) => `${inline(symbol.kind) || "symbol"} ${inline(symbol.qualified_name || symbol.name)}${location(symbol)}`).join(`
|
|
1315
|
+
`)}`);
|
|
1316
|
+
}
|
|
1317
|
+
return sections.join(`
|
|
1318
|
+
|
|
1319
|
+
`) || "No structure found in this selection.";
|
|
1320
|
+
}
|
|
1321
|
+
function documentNodes(nodes, content) {
|
|
1322
|
+
const depths = new Map;
|
|
1323
|
+
return nodes.map((node) => {
|
|
1324
|
+
const depth = Math.min((depths.get(text(node.parent_id)) ?? -1) + 1, 12);
|
|
1325
|
+
depths.set(text(node.id), depth);
|
|
1326
|
+
const indent = " ".repeat(depth);
|
|
1327
|
+
const label = inline(node.title) || inline(node.kind) || "node";
|
|
1328
|
+
const page = count(node.page);
|
|
1329
|
+
const selector = text(node.id) ? `node:${inline(node.id)}` : "";
|
|
1330
|
+
const position = [selector, page !== undefined ? `page:${page}` : ""].filter(Boolean).join(" · ");
|
|
1331
|
+
const heading = `${indent}${label}${position ? ` [${position}]` : ""}`;
|
|
1332
|
+
const body = text(node.text);
|
|
1333
|
+
return content && body ? `${heading}
|
|
1334
|
+
${safe(body).split(`
|
|
1335
|
+
`).map((line) => indent + line).join(`
|
|
1336
|
+
`)}` : heading;
|
|
1337
|
+
}).join(content ? `
|
|
1338
|
+
|
|
1339
|
+
` : `
|
|
1340
|
+
`);
|
|
1341
|
+
}
|
|
1342
|
+
function assetList(assets) {
|
|
1343
|
+
return assets.map((asset) => {
|
|
1344
|
+
const id = text(asset.id);
|
|
1345
|
+
const page = count(asset.page);
|
|
1346
|
+
const heading = [id ? `asset:${inline(id)}` : inline(asset.kind) || "image", inline(asset.mime), page !== undefined ? `page:${page}` : ""].filter(Boolean).join(" · ");
|
|
1347
|
+
const details = fields(asset, ["id", "kind", "mime", "page", "bbox", "content_identity"]);
|
|
1348
|
+
return `${heading}${details ? `
|
|
1349
|
+
${details.split(`
|
|
1350
|
+
`).map((line) => ` ${line}`).join(`
|
|
1351
|
+
`)}` : ""}`;
|
|
1352
|
+
}).join(`
|
|
1353
|
+
|
|
1354
|
+
`);
|
|
1355
|
+
}
|
|
1356
|
+
function presentShowResult(tool, value, options = {}) {
|
|
1357
|
+
const output = record(value);
|
|
1358
|
+
const metadata = record(output.metadata);
|
|
1359
|
+
const content = record(output.content);
|
|
1360
|
+
const cursor = record(output.cursor);
|
|
1361
|
+
const structure = record(output.structure);
|
|
1362
|
+
const document = typeof output.format === "string" && (Array.isArray(output.nodes) || typeof output.source === "string");
|
|
1363
|
+
const path = inline(options.path || output.source || output.file || content.file || structure.file || metadata.file || cursor.file) || "(unknown path)";
|
|
1364
|
+
const summary = [];
|
|
1365
|
+
const result = { summary: "", body: "", notices: [], metadata: {} };
|
|
1366
|
+
if (tool === "show_metadata") {
|
|
1367
|
+
const data = Object.keys(metadata).length > 0 ? metadata : output;
|
|
1368
|
+
if (text(data.format || data.language || data.type))
|
|
1369
|
+
summary.push(inline(data.format || data.language || data.type));
|
|
1370
|
+
if (count(data.pages) !== undefined) {
|
|
1371
|
+
result.metadata.pages = data.pages;
|
|
1372
|
+
summary.push(plural(result.metadata.pages, "page"));
|
|
1373
|
+
}
|
|
1374
|
+
result.body = fields(data) || "No metadata available.";
|
|
1375
|
+
} else if (tool === "show_assets") {
|
|
1376
|
+
const assets = records(output.assets);
|
|
1377
|
+
result.metadata.assets = assets.length;
|
|
1378
|
+
summary.push(plural(assets.length, "asset"));
|
|
1379
|
+
result.body = assetList(assets) || "No assets in this selection.";
|
|
1380
|
+
} else if (document) {
|
|
1381
|
+
const nodes = records(output.nodes);
|
|
1382
|
+
const assets = records(output.assets);
|
|
1383
|
+
result.metadata.nodes = nodes.length;
|
|
1384
|
+
if (count(output.pages) !== undefined)
|
|
1385
|
+
result.metadata.pages = output.pages;
|
|
1386
|
+
summary.push(plural(nodes.length, "node"));
|
|
1387
|
+
if (result.metadata.pages !== undefined)
|
|
1388
|
+
summary.push(plural(result.metadata.pages, "page"));
|
|
1389
|
+
const sections = [text(output.title) ? safe(text(output.title)) : "", documentNodes(nodes, tool === "show_content")];
|
|
1390
|
+
if (assets.length > 0) {
|
|
1391
|
+
result.metadata.assets = assets.length;
|
|
1392
|
+
sections.push(`Assets
|
|
1393
|
+
${assetList(assets)}`);
|
|
1394
|
+
}
|
|
1395
|
+
result.body = sections.filter(Boolean).join(`
|
|
1396
|
+
|
|
1397
|
+
`) || "No content in this selection.";
|
|
1398
|
+
} else if (tool === "show_structure") {
|
|
1399
|
+
const symbols = records(structure.symbols);
|
|
1400
|
+
result.metadata.symbols = symbols.length;
|
|
1401
|
+
summary.push(plural(symbols.length, "symbol"));
|
|
1402
|
+
result.body = sourceStructure(structure);
|
|
1403
|
+
} 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/")) {
|
|
1404
|
+
const description = Object.keys(content).length > 0 ? content : Object.keys(metadata).length > 0 ? metadata : output;
|
|
1405
|
+
if (count(description.width) !== undefined && count(description.height) !== undefined) {
|
|
1406
|
+
summary.push(`${description.width} × ${description.height}`);
|
|
1407
|
+
} else if (count(metadata.width) !== undefined && count(metadata.height) !== undefined) {
|
|
1408
|
+
summary.push(`${metadata.width} × ${metadata.height}`);
|
|
1409
|
+
}
|
|
1410
|
+
const mime = text(description.mime || metadata.mime || metadata.type);
|
|
1411
|
+
if (mime)
|
|
1412
|
+
summary.push(inline(mime));
|
|
1413
|
+
result.body = fields(description, ["hashlines"]) || fields(metadata) || "No content in this selection.";
|
|
1414
|
+
} else if (Array.isArray(content.hashlines) || Array.isArray(cursor.hashlines)) {
|
|
1415
|
+
const lines = records(content.hashlines ?? cursor.hashlines);
|
|
1416
|
+
const start = count(content.start_line) ?? count(lines[0]?.line);
|
|
1417
|
+
const end = count(content.end_line) ?? count(lines.at(-1)?.line);
|
|
1418
|
+
const total = count(content.line_count) ?? count(cursor.line_count);
|
|
1419
|
+
if (start !== undefined && end !== undefined && start <= end) {
|
|
1420
|
+
result.metadata.start_line = start;
|
|
1421
|
+
result.metadata.end_line = end;
|
|
1422
|
+
summary.push(`lines ${start}-${end}${total !== undefined ? ` of ${total}` : ""}`);
|
|
1423
|
+
} else
|
|
1424
|
+
summary.push(plural(lines.length, "line"));
|
|
1425
|
+
const lang = text(metadata.language || content.language);
|
|
1426
|
+
if (lang)
|
|
1427
|
+
summary.push(inline(lang));
|
|
1428
|
+
const rows = lines.map((line) => `${line.line}${options.noAnchors ? "" : `:${text(line.hash)}`} | ${safe(text(line.text)).replaceAll("\\n", "\\\\n")}`);
|
|
1429
|
+
const identifier = record(cursor.identifier);
|
|
1430
|
+
if (count(cursor.line) !== undefined)
|
|
1431
|
+
result.metadata.line = cursor.line;
|
|
1432
|
+
if (count(cursor.column) !== undefined)
|
|
1433
|
+
result.metadata.column = cursor.column;
|
|
1434
|
+
if (Object.keys(cursor).length > 0) {
|
|
1435
|
+
const symbol = record(cursor.symbol);
|
|
1436
|
+
const description = [text(identifier.text), text(symbol.qualified_name || symbol.name), text(symbol.kind)].filter(Boolean);
|
|
1437
|
+
rows.unshift(`Cursor: ${cursor.line ?? "?"}:${cursor.column ?? "?"}${description.length > 0 ? ` · ${[...new Set(description)].map(inline).join(" · ")}` : ""}`, "");
|
|
1438
|
+
}
|
|
1439
|
+
result.body = rows.join(`
|
|
1440
|
+
`) || "Empty source selection.";
|
|
1441
|
+
if (start !== undefined && start > 1)
|
|
1442
|
+
result.notices.push(`Earlier lines omitted. Read preceding content with at: line:1 and limit: ${start - 1}.`);
|
|
1443
|
+
if (end !== undefined && total !== undefined && end < total) {
|
|
1444
|
+
result.notices.push(`More lines available. Continue with at: line:${end + 1}.`);
|
|
1445
|
+
} else if (content.truncated === true && (end === undefined || total === undefined)) {
|
|
1446
|
+
result.notices.push(`Content is truncated.${end !== undefined ? ` Continue with at: line:${end + 1}.` : " Select a smaller range with at and limit."}`);
|
|
1447
|
+
}
|
|
1448
|
+
} else {
|
|
1449
|
+
const description = Object.keys(content).length > 0 ? content : output;
|
|
1450
|
+
result.body = fields(description) || "No content in this selection.";
|
|
1451
|
+
}
|
|
1452
|
+
if (tool === "show_structure")
|
|
1453
|
+
result.notices.push("Structure is limited to the requested depth, kind, and outline. Use a deeper depth or focus with at to inspect further.");
|
|
1454
|
+
if (text(output.warning))
|
|
1455
|
+
result.notices.push(safe(text(output.warning)));
|
|
1456
|
+
result.summary = summary.join(" · ") || "complete";
|
|
1457
|
+
return result;
|
|
1458
|
+
}
|
|
1459
|
+
function formatShowResult(presentation) {
|
|
1460
|
+
return [presentation.summary, presentation.body, ...presentation.notices.map((notice) => `Note: ${notice}`)].filter(Boolean).join(`
|
|
1461
|
+
|
|
1462
|
+
`);
|
|
1463
|
+
}
|
|
1249
1464
|
// ../readseek-api/src/platform.ts
|
|
1250
1465
|
import { accessSync, constants as fsConstants, existsSync, statSync } from "node:fs";
|
|
1251
1466
|
import { createRequire } from "node:module";
|
|
@@ -3549,7 +3764,7 @@ function registerEditTool(pi, options = {}) {
|
|
|
3549
3764
|
const cwd = context.cwd ?? process.cwd();
|
|
3550
3765
|
const argsComplete = context.argsComplete ?? false;
|
|
3551
3766
|
const { path: filePath, suffix } = formatEditCallText(args, argsComplete);
|
|
3552
|
-
let text = theme.fg("toolTitle", theme.bold(
|
|
3767
|
+
let text = theme.fg("toolTitle", theme.bold(name));
|
|
3553
3768
|
if (filePath)
|
|
3554
3769
|
text += ` ${linkToolPath(theme.fg("accent", filePath), filePath, cwd)}`;
|
|
3555
3770
|
else
|
|
@@ -3566,7 +3781,7 @@ function registerEditTool(pi, options = {}) {
|
|
|
3566
3781
|
renderResult(result, options, theme, ...rest) {
|
|
3567
3782
|
const { isPartial, isError, expanded, width, context } = resolveRenderResultContext(options, rest, resolveReadSeekToolDisplayMode("edit") === "expanded");
|
|
3568
3783
|
if (isPartial) {
|
|
3569
|
-
return renderPendingResult(
|
|
3784
|
+
return renderPendingResult(`pending ${name}`, width, theme);
|
|
3570
3785
|
}
|
|
3571
3786
|
const textContent = result.content?.filter((c) => c.type === "text").map((c) => c.text || "").join(`
|
|
3572
3787
|
`) ?? "";
|
|
@@ -4421,7 +4636,7 @@ function registerGrepTool(pi, options = {}) {
|
|
|
4421
4636
|
const { pattern, suffix } = formatGrepCallText(args);
|
|
4422
4637
|
const rawPath = typeof args?.path === "string" && args.path !== "." ? args.path : undefined;
|
|
4423
4638
|
const glob = typeof args?.glob === "string" ? args.glob : undefined;
|
|
4424
|
-
let text = `${renderToolLabel(theme,
|
|
4639
|
+
let text = `${renderToolLabel(theme, name)} ${theme.fg("accent", `/${pattern}/`)}`;
|
|
4425
4640
|
if (suffix) {
|
|
4426
4641
|
if (rawPath) {
|
|
4427
4642
|
text += theme.fg("dim", " in ");
|
|
@@ -4437,7 +4652,7 @@ function registerGrepTool(pi, options = {}) {
|
|
|
4437
4652
|
renderResult(result, options, theme, ...rest) {
|
|
4438
4653
|
const { isPartial, isError, expanded, cwd, width } = resolveRenderResultContext(options, rest, resolveReadSeekToolDisplayMode("grep") === "expanded");
|
|
4439
4654
|
if (isPartial)
|
|
4440
|
-
return renderPendingResult(
|
|
4655
|
+
return renderPendingResult(`pending ${name}`, width, theme);
|
|
4441
4656
|
const content = result.content?.[0];
|
|
4442
4657
|
const textContent = content?.type === "text" ? content.text : "";
|
|
4443
4658
|
if (isError || result.isError)
|
|
@@ -4664,14 +4879,14 @@ function registerSearchTool(pi, options = {}) {
|
|
|
4664
4879
|
},
|
|
4665
4880
|
renderCall(args, theme, ...rest) {
|
|
4666
4881
|
return renderReadSeekSearchCall(args, theme, rest, {
|
|
4667
|
-
label: "
|
|
4882
|
+
label: "readSeek_find_nodes",
|
|
4668
4883
|
accent: `/${args.pattern ?? args.context ?? args.rule}/`,
|
|
4669
4884
|
flags: [args.gitScope && `git-scope=${args.gitScope}`]
|
|
4670
4885
|
});
|
|
4671
4886
|
},
|
|
4672
4887
|
renderResult(result, options, theme, ...rest) {
|
|
4673
4888
|
return renderAnchoredFilesResult(result, options, theme, rest, {
|
|
4674
|
-
pendingLabel: "pending
|
|
4889
|
+
pendingLabel: "pending readSeek_find_nodes",
|
|
4675
4890
|
emptyLabel: "no matches",
|
|
4676
4891
|
unitSingular: "match",
|
|
4677
4892
|
unitPlural: "matches"
|
|
@@ -4804,14 +5019,14 @@ function registerRefsTool(pi, options = {}) {
|
|
|
4804
5019
|
renderCall(args, theme, ...rest) {
|
|
4805
5020
|
const accent = args.name ?? args.at ?? "?";
|
|
4806
5021
|
return renderReadSeekSearchCall(args, theme, rest, {
|
|
4807
|
-
label: "
|
|
5022
|
+
label: "readSeek_find_references",
|
|
4808
5023
|
accent,
|
|
4809
5024
|
flags: [args.at && "binding", args.gitScope && `git-scope=${args.gitScope}`]
|
|
4810
5025
|
});
|
|
4811
5026
|
},
|
|
4812
5027
|
renderResult(result, options, theme, ...rest) {
|
|
4813
5028
|
return renderAnchoredFilesResult(result, options, theme, rest, {
|
|
4814
|
-
pendingLabel: "pending
|
|
5029
|
+
pendingLabel: "pending readSeek_find_references",
|
|
4815
5030
|
emptyLabel: "no references",
|
|
4816
5031
|
unitSingular: "reference",
|
|
4817
5032
|
unitPlural: "references"
|
|
@@ -4917,7 +5132,7 @@ function registerRenameTool(pi, options = {}) {
|
|
|
4917
5132
|
const context = rest[0] ?? {};
|
|
4918
5133
|
const cwd = context.cwd ?? process.cwd();
|
|
4919
5134
|
const displayPath = typeof args?.path === "string" ? args.path : "?";
|
|
4920
|
-
let text = theme.fg("toolTitle", theme.bold("
|
|
5135
|
+
let text = theme.fg("toolTitle", theme.bold("readSeek_rename_symbol"));
|
|
4921
5136
|
text += ` ${linkToolPath(theme.fg("accent", displayPath), displayPath, cwd)}`;
|
|
4922
5137
|
if (args?.to)
|
|
4923
5138
|
text += theme.fg("dim", ` → ${args.to}`);
|
|
@@ -4926,13 +5141,13 @@ function registerRenameTool(pi, options = {}) {
|
|
|
4926
5141
|
renderResult(result, options, theme, ...rest) {
|
|
4927
5142
|
const { isPartial, isError, expanded, cwd, width } = resolveRenderResultContext(options, rest);
|
|
4928
5143
|
if (isPartial)
|
|
4929
|
-
return renderPendingResult("pending
|
|
5144
|
+
return renderPendingResult("pending readSeek_rename_symbol", width, theme);
|
|
4930
5145
|
const content = result.content?.[0];
|
|
4931
5146
|
const textContent = content?.type === "text" ? content.text : "";
|
|
4932
5147
|
const readSeekValue = result.details?.readSeekValue;
|
|
4933
5148
|
const output = readSeekValue?.output;
|
|
4934
5149
|
if (isError || result.isError) {
|
|
4935
|
-
return renderErrorResult(textContent, { expanded, width, fallback: "
|
|
5150
|
+
return renderErrorResult(textContent, { expanded, width, fallback: "readSeek_rename_symbol failed", theme });
|
|
4936
5151
|
}
|
|
4937
5152
|
const outputs = output ? [output, ...output.others] : [];
|
|
4938
5153
|
const editCount = outputs.reduce((total, file) => total + file.edits.length, 0);
|
|
@@ -5303,7 +5518,7 @@ function registerWriteTool(pi, options = {}) {
|
|
|
5303
5518
|
renderCall(args, theme, context = {}) {
|
|
5304
5519
|
const { path, content } = args;
|
|
5305
5520
|
const cwd = context.cwd ?? process.cwd();
|
|
5306
|
-
const label = renderToolLabel(theme,
|
|
5521
|
+
const label = renderToolLabel(theme, name);
|
|
5307
5522
|
const lineCount = typeof content === "string" ? content.split(`
|
|
5308
5523
|
`).length : 0;
|
|
5309
5524
|
const bytes = typeof content === "string" ? Buffer.byteLength(content, "utf8") : 0;
|
|
@@ -5325,11 +5540,11 @@ function registerWriteTool(pi, options = {}) {
|
|
|
5325
5540
|
renderResult(result, options, theme, ...rest) {
|
|
5326
5541
|
const { isPartial, expanded, width, context } = resolveRenderResultContext(options, rest, resolveReadSeekToolDisplayMode("write") === "expanded");
|
|
5327
5542
|
if (isPartial)
|
|
5328
|
-
return renderPendingResult(
|
|
5543
|
+
return renderPendingResult(`pending ${name}`, width, theme);
|
|
5329
5544
|
const details = result.details ?? {};
|
|
5330
5545
|
const output = result.content?.[0]?.type === "text" ? result.content[0].text : "";
|
|
5331
5546
|
if (result.isError || details.readSeekValue?.ok === false) {
|
|
5332
|
-
return renderErrorResult(output, { expanded, width, fallback:
|
|
5547
|
+
return renderErrorResult(output, { expanded, width, fallback: `${name} failed`, theme });
|
|
5333
5548
|
}
|
|
5334
5549
|
const diffData = details.diffData;
|
|
5335
5550
|
const state = details.writeState === "overwritten" ? "overwritten" : "created";
|
|
@@ -5389,7 +5604,7 @@ async function executeDef(opts) {
|
|
|
5389
5604
|
return {
|
|
5390
5605
|
content: [{ type: "text", text: "no definitions found" }],
|
|
5391
5606
|
details: {
|
|
5392
|
-
readSeekValue: { tool: "def", ok: true, path: searchPath, definitions: [] }
|
|
5607
|
+
readSeekValue: { tool: "def", ok: true, path: searchPath, definitions: [], files: [] }
|
|
5393
5608
|
}
|
|
5394
5609
|
};
|
|
5395
5610
|
}
|
|
@@ -5418,7 +5633,7 @@ async function executeDef(opts) {
|
|
|
5418
5633
|
content: [{ type: "text", text: textParts.join(`
|
|
5419
5634
|
`) }],
|
|
5420
5635
|
details: {
|
|
5421
|
-
readSeekValue: { tool: "def", ok: true, path: searchPath, definitions }
|
|
5636
|
+
readSeekValue: { tool: "def", ok: true, path: searchPath, definitions, files: fileList }
|
|
5422
5637
|
}
|
|
5423
5638
|
};
|
|
5424
5639
|
} catch (err) {
|
|
@@ -5444,14 +5659,14 @@ function registerDefTool(pi, options = {}) {
|
|
|
5444
5659
|
},
|
|
5445
5660
|
renderCall(args, theme, ...rest) {
|
|
5446
5661
|
return renderReadSeekSearchCall(args, theme, rest, {
|
|
5447
|
-
label: "
|
|
5662
|
+
label: "readSeek_find_definitions",
|
|
5448
5663
|
accent: args.name,
|
|
5449
5664
|
flags: [args.gitScope && `git-scope=${args.gitScope}`]
|
|
5450
5665
|
});
|
|
5451
5666
|
},
|
|
5452
5667
|
renderResult(result, options, theme, ...rest) {
|
|
5453
5668
|
return renderAnchoredFilesResult(result, options, theme, rest, {
|
|
5454
|
-
pendingLabel: "pending
|
|
5669
|
+
pendingLabel: "pending readSeek_find_definitions",
|
|
5455
5670
|
emptyLabel: "no definitions",
|
|
5456
5671
|
unitSingular: "definition",
|
|
5457
5672
|
unitPlural: "definitions"
|
|
@@ -5461,7 +5676,7 @@ function registerDefTool(pi, options = {}) {
|
|
|
5461
5676
|
}
|
|
5462
5677
|
|
|
5463
5678
|
// src/access.ts
|
|
5464
|
-
import { Text as Text7 } from "@earendil-works/pi-tui";
|
|
5679
|
+
import { Text as Text7, wrapTextWithAnsi as wrapTextWithAnsi2 } from "@earendil-works/pi-tui";
|
|
5465
5680
|
import { Type as Type11 } from "@sinclair/typebox";
|
|
5466
5681
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
5467
5682
|
var operations = {
|
|
@@ -5475,6 +5690,67 @@ var operations = {
|
|
|
5475
5690
|
detect_objects: readSeekDetectObjects,
|
|
5476
5691
|
recognize_text: readSeekRecognizeText
|
|
5477
5692
|
};
|
|
5693
|
+
function resolveNonShowSummary(tool, envelope) {
|
|
5694
|
+
if (tool === "check_syntax") {
|
|
5695
|
+
const errorCount = envelope?.diagnostics?.error_count ?? 0;
|
|
5696
|
+
return errorCount === 0 ? "clean" : `${errorCount} syntax error${errorCount === 1 ? "" : "s"}`;
|
|
5697
|
+
}
|
|
5698
|
+
if (tool === "check_rules") {
|
|
5699
|
+
const violations = Array.isArray(envelope?.violations) ? envelope.violations.length : 0;
|
|
5700
|
+
return violations === 0 ? "clean" : `${violations} rule violation${violations === 1 ? "" : "s"}`;
|
|
5701
|
+
}
|
|
5702
|
+
if (tool === "detect_objects") {
|
|
5703
|
+
const objects = Array.isArray(envelope?.objects) ? envelope.objects.length : 0;
|
|
5704
|
+
return `${objects} object${objects === 1 ? "" : "s"}`;
|
|
5705
|
+
}
|
|
5706
|
+
if (tool === "generate_caption")
|
|
5707
|
+
return "caption generated";
|
|
5708
|
+
if (tool === "recognize_text")
|
|
5709
|
+
return "text recognized";
|
|
5710
|
+
return "complete";
|
|
5711
|
+
}
|
|
5712
|
+
var SOURCE_ROW_RE = /^(\d+)(:[0-9a-fA-F]+)? \| (.*)$/;
|
|
5713
|
+
function renderShowPresentation(summary, body, extras, expanded, theme, fallbackWidth) {
|
|
5714
|
+
const fg = typeof theme?.fg === "function" ? (style, value) => theme.fg(style, value) : (_style, value) => value;
|
|
5715
|
+
const rawBodyLines = expanded && body ? body.split(`
|
|
5716
|
+
`) : [];
|
|
5717
|
+
let maxDigits = 0;
|
|
5718
|
+
for (const line of rawBodyLines) {
|
|
5719
|
+
const match = line.match(SOURCE_ROW_RE);
|
|
5720
|
+
if (match && match[1].length > maxDigits)
|
|
5721
|
+
maxDigits = match[1].length;
|
|
5722
|
+
}
|
|
5723
|
+
return {
|
|
5724
|
+
invalidate() {},
|
|
5725
|
+
render(renderWidth) {
|
|
5726
|
+
const normalized = normalizeWidth(renderWidth, fallbackWidth ?? 80);
|
|
5727
|
+
const out = [...wrapTextWithAnsi2(summary, normalized)];
|
|
5728
|
+
if (!expanded)
|
|
5729
|
+
return out;
|
|
5730
|
+
for (const line of rawBodyLines) {
|
|
5731
|
+
if (!line && maxDigits > 0)
|
|
5732
|
+
continue;
|
|
5733
|
+
const match = line.match(SOURCE_ROW_RE);
|
|
5734
|
+
if (match) {
|
|
5735
|
+
const anchor = `${match[1].padStart(maxDigits, " ")}${match[2] ?? ""}`;
|
|
5736
|
+
const prefix = ` ${fg("dim", `${anchor} | `)}`;
|
|
5737
|
+
out.push(...wrapWithHangingIndent(prefix, match[3] ?? "", normalized));
|
|
5738
|
+
} else if (line.startsWith("Cursor: ")) {
|
|
5739
|
+
out.push(...wrapWithHangingIndent(" ", fg("dim", line), normalized));
|
|
5740
|
+
} else {
|
|
5741
|
+
out.push(...wrapTextWithAnsi2(line, normalized));
|
|
5742
|
+
}
|
|
5743
|
+
}
|
|
5744
|
+
for (const extra of extras) {
|
|
5745
|
+
for (const line of extra.split(`
|
|
5746
|
+
`)) {
|
|
5747
|
+
out.push(...wrapTextWithAnsi2(fg("warning", line), normalized));
|
|
5748
|
+
}
|
|
5749
|
+
}
|
|
5750
|
+
return out;
|
|
5751
|
+
}
|
|
5752
|
+
};
|
|
5753
|
+
}
|
|
5478
5754
|
function hasAnchors(value) {
|
|
5479
5755
|
if (!value || typeof value !== "object")
|
|
5480
5756
|
return false;
|
|
@@ -5515,8 +5791,9 @@ async function executeAccess(opts) {
|
|
|
5515
5791
|
const envelope = await operations[opts.tool](filePath, { ...options, signal: opts.signal });
|
|
5516
5792
|
if (hasAnchors(envelope))
|
|
5517
5793
|
opts.onFileAnchored?.(filePath);
|
|
5794
|
+
const presentation = isShowTool(opts.tool) ? presentShowResult(opts.tool, envelope, p) : undefined;
|
|
5518
5795
|
const content = [
|
|
5519
|
-
{ type: "text", text: JSON.stringify(envelope) }
|
|
5796
|
+
{ type: "text", text: presentation ? formatShowResult(presentation) : JSON.stringify(envelope) }
|
|
5520
5797
|
];
|
|
5521
5798
|
if (opts.tool === "show_content" || opts.tool === "show_assets") {
|
|
5522
5799
|
for (const [imagePath, mimeType] of imagePaths(envelope)) {
|
|
@@ -5528,7 +5805,7 @@ async function executeAccess(opts) {
|
|
|
5528
5805
|
content.push({ type: "text", text: `Image available at ${imagePath}; this host model does not support image attachments.` });
|
|
5529
5806
|
}
|
|
5530
5807
|
}
|
|
5531
|
-
return { content, details: { readSeekValue: { tool: opts.tool, ok: true, path: filePath, envelope } } };
|
|
5808
|
+
return { content, details: { readSeekValue: { tool: opts.tool, ok: true, path: filePath, envelope, presentation } } };
|
|
5532
5809
|
} catch (err) {
|
|
5533
5810
|
const failure = classifyReadSeekFailure(err);
|
|
5534
5811
|
return buildToolErrorResult(opts.tool, failure.code, failure.message, failure.hint ? { hint: failure.hint } : {});
|
|
@@ -5555,19 +5832,47 @@ function registerAccessTools(pi, options = {}) {
|
|
|
5555
5832
|
async execute(_id, params, signal, _update, ctx) {
|
|
5556
5833
|
return executeAccess({ tool: name, params, signal, cwd: ctx.cwd, onFileAnchored: options.onFileAnchored, imageMode: options.imageMode, modelSupportsImages: ctx.model?.input.includes("image") ?? false });
|
|
5557
5834
|
},
|
|
5558
|
-
renderCall(args) {
|
|
5559
|
-
|
|
5835
|
+
renderCall(args, theme, ...rest) {
|
|
5836
|
+
const context = rest[0] ?? {};
|
|
5837
|
+
const cwd = context.cwd ?? process.cwd();
|
|
5838
|
+
const label = renderToolLabel(theme, registeredName);
|
|
5839
|
+
const filePath = typeof args?.path === "string" ? args.path : args?.path ? String(args.path) : "";
|
|
5840
|
+
const renderedPath = filePath ? linkToolPath(theme?.fg ? theme.fg("accent", filePath) : filePath, filePath, cwd) : "";
|
|
5841
|
+
const atBadge = args?.at ? theme?.fg ? theme.fg("dim", `@ ${args.at}`) : `@ ${args.at}` : "";
|
|
5842
|
+
const flags = [
|
|
5843
|
+
args?.limit !== undefined && `limit=${args.limit}`,
|
|
5844
|
+
args?.end !== undefined && `end=${args.end}`,
|
|
5845
|
+
args?.depth !== undefined && `depth=${args.depth}`,
|
|
5846
|
+
args?.kind && `kind=${args.kind}`,
|
|
5847
|
+
args?.outline && "outline",
|
|
5848
|
+
args?.noAnchors && "no-anchors",
|
|
5849
|
+
args?.level && `level=${args.level}`
|
|
5850
|
+
].filter(Boolean);
|
|
5851
|
+
const flagsBadge = flags.length > 0 ? theme?.fg ? theme.fg("dim", `[${flags.join(",")}]`) : `[${flags.join(",")}]` : "";
|
|
5852
|
+
const text = clampLineToWidth([label, renderedPath, atBadge, flagsBadge].filter(Boolean).join(" "), context.width);
|
|
5853
|
+
return upsertTextComponent(context.lastComponent, text);
|
|
5560
5854
|
},
|
|
5561
5855
|
renderResult(result, renderOptions, theme, ...rest) {
|
|
5562
5856
|
const { isPartial, isError, expanded, width } = resolveRenderResultContext(renderOptions, rest);
|
|
5563
5857
|
if (isPartial)
|
|
5564
|
-
return renderPendingResult(`pending ${
|
|
5858
|
+
return renderPendingResult(`pending ${registeredName}`, width, theme);
|
|
5565
5859
|
const text = result.content?.find((item) => item.type === "text")?.text ?? "";
|
|
5566
5860
|
if (isError || result.isError)
|
|
5567
|
-
return renderErrorResult(text, { expanded, width, fallback: `${
|
|
5568
|
-
const
|
|
5569
|
-
|
|
5570
|
-
|
|
5861
|
+
return renderErrorResult(text, { expanded, width, fallback: `${registeredName} failed`, theme });
|
|
5862
|
+
const presentation = result.details?.readSeekValue?.presentation;
|
|
5863
|
+
const envelope = result.details?.readSeekValue?.envelope;
|
|
5864
|
+
if (presentation) {
|
|
5865
|
+
const warning = typeof envelope?.warning === "string" && envelope.warning ? presentation.notices.at(-1) : undefined;
|
|
5866
|
+
const attachments = result.content?.filter((item) => item.type === "text").slice(1).map((item) => item.text) ?? [];
|
|
5867
|
+
const extras = [...warning ? [`Note: ${warning}`] : [], ...attachments];
|
|
5868
|
+
const hasWarning = extras.length > 0;
|
|
5869
|
+
const hasExpandable = Boolean(presentation.body) || hasWarning;
|
|
5870
|
+
const summary = summaryLine(presentation.summary, { hidden: hasExpandable && !expanded, theme, style: hasWarning ? "warning" : "success" });
|
|
5871
|
+
return renderShowPresentation(summary, presentation.body, extras, expanded, theme, width);
|
|
5872
|
+
}
|
|
5873
|
+
const nonShowSummary = resolveNonShowSummary(name, envelope);
|
|
5874
|
+
const summary = summaryLine(nonShowSummary, { hidden: !!text && !expanded, theme, style: "success" });
|
|
5875
|
+
return new Text7(clampLinesToWidth((expanded ? `${summary}\\n${text}` : summary).split(`
|
|
5571
5876
|
`), width).join(`
|
|
5572
5877
|
`), 0, 0);
|
|
5573
5878
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-readseek",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.2",
|
|
4
4
|
"description": "Pi extension for LINE:HASH-anchored file operations and structural code navigation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"node": ">=20.0.0"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@jarkkojs/readseek": "^0.11.
|
|
43
|
-
"@jarkkojs/readseek-api": "^0.11.
|
|
42
|
+
"@jarkkojs/readseek": "^0.11.2",
|
|
43
|
+
"@jarkkojs/readseek-api": "^0.11.2",
|
|
44
44
|
"diff": "^9.0.0",
|
|
45
45
|
"xxhash-wasm": "^1.1.0"
|
|
46
46
|
},
|