pi-readseek 0.11.0 → 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.
Files changed (3) hide show
  1. package/README.md +5 -0
  2. package/dist/index.ts +277 -25
  3. 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("edit"));
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("pending edit", width, theme);
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, "grep")} ${theme.fg("accent", `/${pattern}/`)}`;
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("pending grep", width, theme);
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: "search",
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 search",
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: "refs",
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 refs",
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("rename"));
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 rename", width, theme);
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: "rename failed", theme });
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, "write");
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("pending write", width, theme);
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: "write failed", theme });
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";
@@ -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: "def",
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 def",
5669
+ pendingLabel: "pending readSeek_find_definitions",
5455
5670
  emptyLabel: "no definitions",
5456
5671
  unitSingular: "definition",
5457
5672
  unitPlural: "definitions"
@@ -5475,6 +5690,25 @@ 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
+ }
5478
5712
  function hasAnchors(value) {
5479
5713
  if (!value || typeof value !== "object")
5480
5714
  return false;
@@ -5515,8 +5749,9 @@ async function executeAccess(opts) {
5515
5749
  const envelope = await operations[opts.tool](filePath, { ...options, signal: opts.signal });
5516
5750
  if (hasAnchors(envelope))
5517
5751
  opts.onFileAnchored?.(filePath);
5752
+ const presentation = isShowTool(opts.tool) ? presentShowResult(opts.tool, envelope, p) : undefined;
5518
5753
  const content = [
5519
- { type: "text", text: JSON.stringify(envelope) }
5754
+ { type: "text", text: presentation ? formatShowResult(presentation) : JSON.stringify(envelope) }
5520
5755
  ];
5521
5756
  if (opts.tool === "show_content" || opts.tool === "show_assets") {
5522
5757
  for (const [imagePath, mimeType] of imagePaths(envelope)) {
@@ -5528,7 +5763,7 @@ async function executeAccess(opts) {
5528
5763
  content.push({ type: "text", text: `Image available at ${imagePath}; this host model does not support image attachments.` });
5529
5764
  }
5530
5765
  }
5531
- return { content, details: { readSeekValue: { tool: opts.tool, ok: true, path: filePath, envelope } } };
5766
+ return { content, details: { readSeekValue: { tool: opts.tool, ok: true, path: filePath, envelope, presentation } } };
5532
5767
  } catch (err) {
5533
5768
  const failure = classifyReadSeekFailure(err);
5534
5769
  return buildToolErrorResult(opts.tool, failure.code, failure.message, failure.hint ? { hint: failure.hint } : {});
@@ -5555,19 +5790,36 @@ function registerAccessTools(pi, options = {}) {
5555
5790
  async execute(_id, params, signal, _update, ctx) {
5556
5791
  return executeAccess({ tool: name, params, signal, cwd: ctx.cwd, onFileAnchored: options.onFileAnchored, imageMode: options.imageMode, modelSupportsImages: ctx.model?.input.includes("image") ?? false });
5557
5792
  },
5558
- renderCall(args) {
5559
- return new Text7(`${name} ${args.path ?? ""}${args.at ? ` @ ${args.at}` : ""}`, 0, 0);
5793
+ renderCall(args, theme, ...rest) {
5794
+ const context = rest[0] ?? {};
5795
+ const cwd = context.cwd ?? process.cwd();
5796
+ const label = renderToolLabel(theme, registeredName);
5797
+ const filePath = typeof args?.path === "string" ? args.path : args?.path ? String(args.path) : "";
5798
+ const renderedPath = filePath ? linkToolPath(theme?.fg ? theme.fg("accent", filePath) : filePath, filePath, cwd) : "";
5799
+ const atBadge = args?.at ? theme?.fg ? theme.fg("dim", ` @ ${args.at}`) : ` @ ${args.at}` : "";
5800
+ const text = clampLineToWidth([label, renderedPath, atBadge].filter(Boolean).join(" "), context.width);
5801
+ return upsertTextComponent(context.lastComponent, text);
5560
5802
  },
5561
5803
  renderResult(result, renderOptions, theme, ...rest) {
5562
5804
  const { isPartial, isError, expanded, width } = resolveRenderResultContext(renderOptions, rest);
5563
5805
  if (isPartial)
5564
- return renderPendingResult(`pending ${name}`, width, theme);
5806
+ return renderPendingResult(`pending ${registeredName}`, width, theme);
5565
5807
  const text = result.content?.find((item) => item.type === "text")?.text ?? "";
5566
5808
  if (isError || result.isError)
5567
- return renderErrorResult(text, { expanded, width, fallback: `${name} failed`, theme });
5568
- const summary = summaryLine(contract.title, { hidden: !!text && !expanded, theme, style: "success" });
5569
- return new Text7(clampLinesToWidth((expanded ? `${summary}
5570
- ${text}` : summary).split(`
5809
+ return renderErrorResult(text, { expanded, width, fallback: `${registeredName} failed`, theme });
5810
+ const presentation = result.details?.readSeekValue?.presentation;
5811
+ if (presentation) {
5812
+ const summary = summaryLine(presentation.summary, { hidden: !!presentation.body && !expanded, theme, style: presentation.notices.length > 0 ? "warning" : "success" });
5813
+ const notes = presentation.notices.map((notice) => `Note: ${notice}`);
5814
+ const attachments = result.content?.filter((item) => item.type === "text").slice(1).map((item) => item.text) ?? [];
5815
+ return new Text7([summary, ...expanded ? [presentation.body] : [], ...notes, ...attachments].filter(Boolean).join(`
5816
+
5817
+ `), 0, 0);
5818
+ }
5819
+ const envelope = result.details?.readSeekValue?.envelope;
5820
+ const nonShowSummary = resolveNonShowSummary(name, envelope);
5821
+ const summary = summaryLine(nonShowSummary, { hidden: !!text && !expanded, theme, style: "success" });
5822
+ return new Text7(clampLinesToWidth((expanded ? `${summary}\\n${text}` : summary).split(`
5571
5823
  `), width).join(`
5572
5824
  `), 0, 0);
5573
5825
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-readseek",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
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.0",
43
- "@jarkkojs/readseek-api": "^0.11.0",
42
+ "@jarkkojs/readseek": "^0.11.1",
43
+ "@jarkkojs/readseek-api": "^0.11.1",
44
44
  "diff": "^9.0.0",
45
45
  "xxhash-wasm": "^1.1.0"
46
46
  },