@jarkkojs/readseek-api 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.
package/README.md CHANGED
@@ -43,6 +43,12 @@ separate extraction step or destination argument. Cache population is an interna
43
43
  write; reading never invokes inference. Syntax checks return diagnostics even
44
44
  when the native process exits 1 (findings); exit 2 is a failure.
45
45
 
46
+ `presentShowResult()` and `formatShowResult()` provide shared readable output for
47
+ `show_content`, `show_structure`, `show_metadata`, and `show_assets`. Summaries
48
+ identify selections and counts; bodies contain anchored lines, document sections,
49
+ structure trees, fields, or asset paths. Notices identify omitted source ranges
50
+ and how to continue. Formatting never mutates the decoded result.
51
+
46
52
  This is a breaking contract: legacy `inspect`/`extract` methods, selectable facets,
47
53
  and old command names are removed, not aliased.
48
54
 
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export * from "./argv.ts";
5
5
  export * from "./client.ts";
6
6
  export { serializeEditPlan } from "./edit-plan.ts";
7
7
  export * from "./hashline.ts";
8
+ export * from "./show-presentation.ts";
8
9
  export { READSEEK_BINARY_ENV, READSEEK_PLATFORM_PACKAGES, readSeekBinaryName, readSeekPlatformKey, resolveReadSeekBinaryFromPackages, resolveReadSeekBinaryOverride, resolveReadSeekCacheDir, type ModuleResolver, type ReadSeekCacheOptions, } from "./platform.ts";
9
10
  export { canonicalPathKey, expandUserPath, isSubPath, resolveScopedPath, resolveToCwd, } from "./path.ts";
10
11
  export { cleanReadSeekErrorText } from "./error.ts";
package/dist/index.js CHANGED
@@ -1347,6 +1347,221 @@ function createReadSeekClient(runner) {
1347
1347
  }
1348
1348
  };
1349
1349
  }
1350
+ // src/show-presentation.ts
1351
+ function isShowTool(name) {
1352
+ return name === "show_content" || name === "show_structure" || name === "show_metadata" || name === "show_assets";
1353
+ }
1354
+ function record(value) {
1355
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
1356
+ }
1357
+ function records(value) {
1358
+ return Array.isArray(value) ? value.map(record) : [];
1359
+ }
1360
+ function text(value) {
1361
+ return typeof value === "string" ? value : "";
1362
+ }
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")}`;
1373
+ });
1374
+ }
1375
+ function inline(value) {
1376
+ return safe(text(value)).replaceAll(`
1377
+ `, "\\n");
1378
+ }
1379
+ function plural(n, unit) {
1380
+ return `${n} ${unit}${n === 1 ? "" : "s"}`;
1381
+ }
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
+ `);
1390
+ }
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
+ `);
1442
+ }
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
+ `);
1456
+ }
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";
1558
+ return result;
1559
+ }
1560
+ function formatShowResult(presentation) {
1561
+ return [presentation.summary, presentation.body, ...presentation.notices.map((notice) => `Note: ${notice}`)].filter(Boolean).join(`
1562
+
1563
+ `);
1564
+ }
1350
1565
  // src/platform.ts
1351
1566
  import { accessSync, constants as fsConstants, existsSync, statSync } from "node:fs";
1352
1567
  import { createRequire } from "node:module";
@@ -2113,13 +2328,16 @@ export {
2113
2328
  expandUserPath,
2114
2329
  failureFromProcessResult,
2115
2330
  fallbackToolDescriptionMap,
2331
+ formatShowResult,
2116
2332
  getToolContract,
2333
+ isShowTool,
2117
2334
  isSubPath,
2118
2335
  parseLineAnchor,
2119
2336
  parseReadSeekKdl,
2120
2337
  parseSelector,
2121
2338
  parseSuccessfulKdl,
2122
2339
  preferredToolDescriptionMap,
2340
+ presentShowResult,
2123
2341
  readSeekBinaryName,
2124
2342
  readSeekPlatformKey,
2125
2343
  readSeekProcessEnvironment,
@@ -0,0 +1,15 @@
1
+ export type ShowTool = "show_content" | "show_structure" | "show_metadata" | "show_assets";
2
+ export interface ShowPresentation {
3
+ summary: string;
4
+ body: string;
5
+ notices: string[];
6
+ metadata: Record<string, number>;
7
+ }
8
+ export interface ShowPresentationOptions {
9
+ path?: string;
10
+ at?: string;
11
+ noAnchors?: boolean;
12
+ }
13
+ export declare function isShowTool(name: string): name is ShowTool;
14
+ export declare function presentShowResult(tool: ShowTool, value: unknown, options?: ShowPresentationOptions): ShowPresentation;
15
+ export declare function formatShowResult(presentation: ShowPresentation): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jarkkojs/readseek-api",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "Shared ReadSeek CLI contract, validation, argv builders, and bounded process runners",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -51,7 +51,7 @@
51
51
  "vitest": "^4.1.0"
52
52
  },
53
53
  "dependencies": {
54
- "@jarkkojs/readseek": "^0.11.0",
54
+ "@jarkkojs/readseek": "^0.11.1",
55
55
  "@bgotink/kdl": "0.4.0",
56
56
  "@sinclair/typebox": "0.34.52"
57
57
  }