@ashx-j/lunr 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/builtin-extensions/lunr-todos.d.ts +7 -6
  2. package/dist/builtin-extensions/lunr-todos.d.ts.map +1 -1
  3. package/dist/builtin-extensions/lunr-todos.js +24 -11
  4. package/dist/builtin-extensions/lunr-todos.js.map +1 -1
  5. package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.d.ts.map +1 -1
  6. package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.js +9 -5
  7. package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.js.map +1 -1
  8. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.d.ts.map +1 -1
  9. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js +31 -3
  10. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js.map +1 -1
  11. package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.d.ts +1 -0
  12. package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.d.ts.map +1 -1
  13. package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.js +14 -4
  14. package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.js.map +1 -1
  15. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  16. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +4 -3
  17. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  18. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
  19. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +12 -1
  20. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
  21. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +3 -0
  22. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
  23. package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
  24. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +8 -0
  25. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  26. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +22 -2
  27. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  28. package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
  29. package/dist/builtin-extensions/pi-web-access/index.js +38 -230
  30. package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
  31. package/dist/builtin-extensions/pi-web-access/render-search-chrome.d.ts +35 -0
  32. package/dist/builtin-extensions/pi-web-access/render-search-chrome.d.ts.map +1 -0
  33. package/dist/builtin-extensions/pi-web-access/render-search-chrome.js +93 -0
  34. package/dist/builtin-extensions/pi-web-access/render-search-chrome.js.map +1 -0
  35. package/dist/catalog/models.json +1 -1
  36. package/dist/catalog/providers/cloudflare-workers-ai.json +1 -1
  37. package/dist/catalog/providers/huggingface.json +1 -1
  38. package/dist/catalog/providers/opencode-go.json +1 -1
  39. package/dist/catalog/providers/openrouter.json +1 -1
  40. package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
  41. package/dist/catalog/publication.json +3 -3
  42. package/dist/core/context-breakdown.d.ts +21 -1
  43. package/dist/core/context-breakdown.d.ts.map +1 -1
  44. package/dist/core/context-breakdown.js +58 -2
  45. package/dist/core/context-breakdown.js.map +1 -1
  46. package/dist/core/permission-mode-control.d.ts +27 -0
  47. package/dist/core/permission-mode-control.d.ts.map +1 -0
  48. package/dist/core/permission-mode-control.js +39 -0
  49. package/dist/core/permission-mode-control.js.map +1 -0
  50. package/dist/core/settings-manager.d.ts.map +1 -1
  51. package/dist/core/settings-manager.js.map +1 -1
  52. package/dist/core/slash-commands.d.ts.map +1 -1
  53. package/dist/core/slash-commands.js +0 -1
  54. package/dist/core/slash-commands.js.map +1 -1
  55. package/dist/core/tools/read.d.ts.map +1 -1
  56. package/dist/core/tools/read.js +14 -20
  57. package/dist/core/tools/read.js.map +1 -1
  58. package/dist/core/tools/render-utils.d.ts +2 -0
  59. package/dist/core/tools/render-utils.d.ts.map +1 -1
  60. package/dist/core/tools/render-utils.js +10 -0
  61. package/dist/core/tools/render-utils.js.map +1 -1
  62. package/dist/modes/interactive/components/assistant-message.d.ts +1 -0
  63. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  64. package/dist/modes/interactive/components/assistant-message.js +1 -0
  65. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  66. package/dist/modes/interactive/components/context-view.d.ts.map +1 -1
  67. package/dist/modes/interactive/components/context-view.js +3 -1
  68. package/dist/modes/interactive/components/context-view.js.map +1 -1
  69. package/dist/modes/interactive/components/plan-message.d.ts +17 -0
  70. package/dist/modes/interactive/components/plan-message.d.ts.map +1 -0
  71. package/dist/modes/interactive/components/plan-message.js +43 -0
  72. package/dist/modes/interactive/components/plan-message.js.map +1 -0
  73. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  74. package/dist/modes/interactive/components/settings-selector.js +1 -1
  75. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  76. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  77. package/dist/modes/interactive/components/tool-execution.js +3 -1
  78. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  79. package/dist/modes/interactive/components/usage-view.d.ts +4 -25
  80. package/dist/modes/interactive/components/usage-view.d.ts.map +1 -1
  81. package/dist/modes/interactive/components/usage-view.js +17 -69
  82. package/dist/modes/interactive/components/usage-view.js.map +1 -1
  83. package/dist/modes/interactive/components/user-message.d.ts +1 -0
  84. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  85. package/dist/modes/interactive/components/user-message.js +1 -0
  86. package/dist/modes/interactive/components/user-message.js.map +1 -1
  87. package/dist/modes/interactive/interactive-mode.d.ts +17 -6
  88. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  89. package/dist/modes/interactive/interactive-mode.js +196 -114
  90. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  91. package/dist/modes/interactive/smooth-streaming.d.ts +39 -6
  92. package/dist/modes/interactive/smooth-streaming.d.ts.map +1 -1
  93. package/dist/modes/interactive/smooth-streaming.js +160 -73
  94. package/dist/modes/interactive/smooth-streaming.js.map +1 -1
  95. package/dist/utils/clipboard-image.d.ts.map +1 -1
  96. package/dist/utils/clipboard-image.js +7 -3
  97. package/dist/utils/clipboard-image.js.map +1 -1
  98. package/docs/terminal-setup.md +13 -0
  99. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  100. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  101. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  102. package/examples/extensions/gondolin/package-lock.json +2 -2
  103. package/examples/extensions/gondolin/package.json +1 -1
  104. package/examples/extensions/sandbox/package-lock.json +2 -2
  105. package/examples/extensions/sandbox/package.json +1 -1
  106. package/examples/extensions/with-deps/package-lock.json +2 -2
  107. package/examples/extensions/with-deps/package.json +1 -1
  108. package/package.json +4 -4
@@ -13,7 +13,7 @@ import { fetchAllContent } from "./extract.js";
13
13
  import { normalizeFetchContentParams } from "./fetch-params.js";
14
14
  import { clearCloneCache } from "./github-extract.js";
15
15
  import { search } from "./gemini-search.js";
16
- import { formatSeconds, getWebSearchConfigDir, getWebSearchConfigPath } from "./utils.js";
16
+ import { getWebSearchConfigDir, getWebSearchConfigPath } from "./utils.js";
17
17
  import { clearResults, deleteResult, generateId, getAllResults, getResult, restoreFromSession, storeResult, } from "./storage.js";
18
18
  import { activityMonitor } from "./activity.js";
19
19
  import { startCuratorServer } from "./curator-server.js";
@@ -34,6 +34,7 @@ import { isOpenAISearchAvailable } from "./openai-search.js";
34
34
  import { isParallelAvailable } from "./parallel.js";
35
35
  import { isTavilyAvailable } from "./tavily.js";
36
36
  import { buildSearchErrorPlan } from "./render-search-error.js";
37
+ import { collectFetchUrls, collectSearchQueries, formatFetchCallTitle, formatFetchChrome, formatSearchCallTitle, formatSearchChrome, } from "./render-search-chrome.js";
37
38
  import { loadEnabledModelPatterns, modelMatchesEnabledPatterns } from "./summary-model-scope.js";
38
39
  const WEB_SEARCH_CONFIG_PATH = getWebSearchConfigPath();
39
40
  /** Shared collapsed/expanded renderer for an error/cancel plan produced by
@@ -124,15 +125,7 @@ function resolveWorkflow(input, hasUI) {
124
125
  return "summary-review";
125
126
  }
126
127
  function normalizeQueryList(queryList) {
127
- const normalized = [];
128
- for (const query of queryList) {
129
- if (typeof query !== "string")
130
- continue;
131
- const trimmed = query.trim();
132
- if (trimmed.length > 0)
133
- normalized.push(trimmed);
134
- }
135
- return normalized;
128
+ return collectSearchQueries({ queries: queryList });
136
129
  }
137
130
  function getCuratorTimeoutSeconds() {
138
131
  const source = loadConfig();
@@ -1377,12 +1370,10 @@ export default function (pi) {
1377
1370
  });
1378
1371
  },
1379
1372
  renderCall(args, theme) {
1380
- const input = args;
1381
- const rawQueryList = Array.isArray(input.queries)
1382
- ? input.queries
1383
- : (input.query !== undefined ? [input.query] : []);
1384
- const queryList = normalizeQueryList(rawQueryList);
1385
- if (queryList.length === 0) {
1373
+ // lunr: collapsed header is title-only. Query list lives in expanded renderResult.
1374
+ const queryList = collectSearchQueries(args);
1375
+ const call = formatSearchCallTitle(queryList);
1376
+ if (call.empty) {
1386
1377
  return new Text(theme.fg("toolTitle", theme.bold("search ")) + theme.fg("error", "(no query)"), 0, 0);
1387
1378
  }
1388
1379
  if (queryList.length === 1) {
@@ -1390,17 +1381,9 @@ export default function (pi) {
1390
1381
  const display = q.length > 60 ? q.slice(0, 57) + "..." : q;
1391
1382
  return new Text(theme.fg("toolTitle", theme.bold("search ")) + theme.fg("accent", `"${display}"`), 0, 0);
1392
1383
  }
1393
- const lines = [theme.fg("toolTitle", theme.bold("search ")) + theme.fg("accent", `${queryList.length} queries`)];
1394
- for (const q of queryList.slice(0, 5)) {
1395
- const display = q.length > 50 ? q.slice(0, 47) + "..." : q;
1396
- lines.push(theme.fg("muted", ` "${display}"`));
1397
- }
1398
- if (queryList.length > 5) {
1399
- lines.push(theme.fg("muted", ` ... and ${queryList.length - 5} more`));
1400
- }
1401
- return new Text(lines.join("\n"), 0, 0);
1384
+ return new Text(theme.fg("toolTitle", theme.bold("search ")) + theme.fg("accent", `${queryList.length} queries`), 0, 0);
1402
1385
  },
1403
- renderResult(result, { expanded, isPartial }, theme) {
1386
+ renderResult(result, { expanded, isPartial }, theme, context) {
1404
1387
  const details = result.details;
1405
1388
  if (isPartial) {
1406
1389
  if (details?.phase === "curator-fallback") {
@@ -1453,137 +1436,16 @@ export default function (pi) {
1453
1436
  return renderSearchErrorPlan(plan, expanded, theme);
1454
1437
  return new Text(theme.fg("error", `Error: ${details.error}`), 0, 0);
1455
1438
  }
1456
- let statusLine;
1457
- const queryInfo = details?.queryCount === 1 ? "" : `${details?.successfulQueries}/${details?.queryCount} queries, `;
1458
- statusLine = theme.fg("success", `${queryInfo}${details?.totalResults ?? 0} sources`);
1459
- if (details?.curated && details?.curatedFrom) {
1460
- statusLine += theme.fg("muted", ` (${details.queryCount}/${details.curatedFrom} queries curated)`);
1461
- }
1462
- if (details?.fetchId && details?.fetchUrls) {
1463
- statusLine += theme.fg("muted", ` (fetching ${details.fetchUrls.length} URLs)`);
1464
- }
1465
- else if (details?.fetchId) {
1466
- statusLine += theme.fg("muted", " (content ready)");
1467
- }
1468
- // Build expanded lines first so collapsed view can reference total count
1469
- const lines = [statusLine];
1470
- if (details?.summary?.text) {
1471
- lines.push("");
1472
- lines.push(theme.fg("accent", `── Summary (${details.summary.workflow}) ` + "─".repeat(32)));
1473
- lines.push("");
1474
- for (const line of details.summary.text.split("\n")) {
1475
- lines.push(` ${line}`);
1476
- }
1477
- lines.push("");
1478
- const metaParts = [
1479
- details.summary.model ? `model=${details.summary.model}` : "model=deterministic",
1480
- `duration=${details.summary.durationMs}ms`,
1481
- `tokens~${details.summary.tokenEstimate}`,
1482
- details.summary.fallbackUsed ? "fallback=true" : "fallback=false",
1483
- details.summary.edited ? "edited=true" : "edited=false",
1484
- ];
1485
- if (details.summary.fallbackReason) {
1486
- metaParts.push(`reason=${details.summary.fallbackReason}`);
1487
- }
1488
- lines.push(theme.fg("dim", " " + metaParts.join(" · ")));
1489
- }
1490
- const queryDetails = details?.curatedQueries;
1491
- if (queryDetails?.length) {
1492
- const kept = queryDetails.length;
1493
- const from = details?.curatedFrom ?? kept;
1494
- lines.push("");
1495
- lines.push(theme.fg("accent", `\u2500\u2500 Curated Results (${kept} of ${from} queries kept) ` + "\u2500".repeat(24)));
1496
- for (const cq of queryDetails) {
1497
- lines.push("");
1498
- const dq = cq.query.length > 65 ? cq.query.slice(0, 62) + "..." : cq.query;
1499
- const providerLabel = cq.provider ? ` (${cq.provider})` : "";
1500
- lines.push(theme.fg("accent", ` "${dq}"${providerLabel}`));
1501
- if (cq.error) {
1502
- lines.push(theme.fg("error", ` ${cq.error}`));
1503
- }
1504
- else if (cq.answer) {
1505
- lines.push("");
1506
- for (const line of cq.answer.split("\n")) {
1507
- lines.push(` ${line}`);
1508
- }
1509
- }
1510
- if (cq.sources.length > 0) {
1511
- lines.push("");
1512
- for (const s of cq.sources) {
1513
- const domain = s.url.replace(/^https?:\/\//, "").replace(/\/.*$/, "");
1514
- const title = s.title.length > 50 ? s.title.slice(0, 47) + "..." : s.title;
1515
- lines.push(theme.fg("muted", ` \u25b8 ${title}`) + theme.fg("dim", ` \u00b7 ${domain}`));
1516
- }
1517
- }
1518
- }
1519
- lines.push("");
1520
- }
1521
- else {
1522
- const textContent = result.content.find((c) => c.type === "text")?.text || "";
1523
- const preview = textContent.length > 500 ? textContent.slice(0, 500) + "..." : textContent;
1524
- for (const line of preview.split("\n")) {
1525
- lines.push(theme.fg("dim", line));
1526
- }
1527
- }
1528
- if (details?.fetchUrls && details.fetchUrls.length > 0) {
1529
- if (details.curated) {
1530
- lines.push(theme.fg("muted", `Fetching ${details.fetchUrls.length} URLs in background`));
1531
- }
1532
- else {
1533
- lines.push(theme.fg("muted", "Fetching:"));
1534
- for (const u of details.fetchUrls.slice(0, 5)) {
1535
- const display = u.length > 60 ? u.slice(0, 57) + "..." : u;
1536
- lines.push(theme.fg("dim", " " + display));
1537
- }
1538
- if (details.fetchUrls.length > 5) {
1539
- lines.push(theme.fg("dim", ` ... and ${details.fetchUrls.length - 5} more`));
1540
- }
1541
- }
1542
- }
1543
- const totalLines = lines.length;
1544
- if (!expanded) {
1545
- const box = new Box(1, 0, (t) => theme.bg("toolSuccessBg", t));
1546
- box.addChild(new Text(statusLine, 0, 0));
1547
- let collapsedLines = 1; // statusLine
1548
- const summaryPreview = details?.summary?.text?.trim() || "";
1549
- if (summaryPreview) {
1550
- const preview = summaryPreview.length > 120 ? summaryPreview.slice(0, 117) + "..." : summaryPreview;
1551
- box.addChild(new Text(theme.fg("dim", preview), 0, 0));
1552
- collapsedLines++;
1553
- }
1554
- else if (details?.curatedQueries?.length) {
1555
- for (const cq of details.curatedQueries.slice(0, 3)) {
1556
- const dq = cq.query.length > 55 ? cq.query.slice(0, 52) + "..." : cq.query;
1557
- const srcCount = cq.sources?.length ?? 0;
1558
- const suffix = cq.error ? theme.fg("error", " (error)") : theme.fg("dim", ` · ${srcCount} sources`);
1559
- box.addChild(new Text(theme.fg("accent", ` "${dq}"`) + suffix, 0, 0));
1560
- collapsedLines++;
1561
- }
1562
- if (details.curatedQueries.length > 3) {
1563
- box.addChild(new Text(theme.fg("dim", ` ... and ${details.curatedQueries.length - 3} more`), 0, 0));
1564
- collapsedLines++;
1565
- }
1566
- }
1567
- else {
1568
- const textContent = result.content.find((c) => c.type === "text")?.text || "";
1569
- const firstContentLine = textContent.split("\n").find(l => {
1570
- const t = l.trim();
1571
- return t && !t.startsWith("[") && !t.startsWith("#") && !t.startsWith("---");
1572
- });
1573
- const fallbackLine = (firstContentLine?.trim() || "").replace(/\*\*/g, "");
1574
- if (fallbackLine) {
1575
- const preview = fallbackLine.length > 120 ? fallbackLine.slice(0, 117) + "..." : fallbackLine;
1576
- box.addChild(new Text(theme.fg("dim", preview), 0, 0));
1577
- collapsedLines++;
1578
- }
1579
- }
1580
- const moreLines = Math.max(0, totalLines - collapsedLines);
1581
- if (moreLines > 0) {
1582
- box.addChild(new Text(theme.fg("muted", `\n... (${moreLines} more lines, ${totalLines} total, ctrl+o to expand)`), 0, 0));
1583
- }
1584
- return box;
1585
- }
1586
- return new Text(lines.join("\n"), 0, 0);
1439
+ // lunr: collapsed = status/count only. Expanded = query list, no answers/sources/summary.
1440
+ const queryList = collectSearchQueries(context?.args);
1441
+ const fallbackQueries = (details?.curatedQueries ?? []).map((cq) => cq.query).filter(Boolean);
1442
+ const chrome = formatSearchChrome({
1443
+ queries: queryList.length > 0 ? queryList : fallbackQueries,
1444
+ details,
1445
+ expanded,
1446
+ });
1447
+ const statusColor = expanded ? "accent" : "success";
1448
+ return new Text(chrome.result.map((line) => theme.fg(statusColor, line)).join("\n"), 0, 0);
1587
1449
  },
1588
1450
  });
1589
1451
  pi.registerTool({
@@ -1703,42 +1565,19 @@ export default function (pi) {
1703
1565
  };
1704
1566
  },
1705
1567
  renderCall(args, theme) {
1706
- const { url, urls, prompt, timestamp, frames, model } = args;
1707
- const urlList = urls ?? (url ? [url] : []);
1708
- if (urlList.length === 0) {
1568
+ // lunr: collapsed header is title-only. URL list lives in expanded renderResult.
1569
+ const urlList = collectFetchUrls(args);
1570
+ const call = formatFetchCallTitle(urlList);
1571
+ if (call.empty) {
1709
1572
  return new Text(theme.fg("toolTitle", theme.bold("fetch ")) + theme.fg("error", "(no URL)"), 0, 0);
1710
1573
  }
1711
- const lines = [];
1712
1574
  if (urlList.length === 1) {
1713
1575
  const display = urlList[0].length > 60 ? urlList[0].slice(0, 57) + "..." : urlList[0];
1714
- lines.push(theme.fg("toolTitle", theme.bold("fetch ")) + theme.fg("accent", display));
1715
- }
1716
- else {
1717
- lines.push(theme.fg("toolTitle", theme.bold("fetch ")) + theme.fg("accent", `${urlList.length} URLs`));
1718
- for (const u of urlList.slice(0, 5)) {
1719
- const display = u.length > 60 ? u.slice(0, 57) + "..." : u;
1720
- lines.push(theme.fg("muted", " " + display));
1721
- }
1722
- if (urlList.length > 5) {
1723
- lines.push(theme.fg("muted", ` ... and ${urlList.length - 5} more`));
1724
- }
1725
- }
1726
- if (timestamp) {
1727
- lines.push(theme.fg("dim", " timestamp: ") + theme.fg("warning", timestamp));
1728
- }
1729
- if (typeof frames === "number") {
1730
- lines.push(theme.fg("dim", " frames: ") + theme.fg("warning", String(frames)));
1731
- }
1732
- if (prompt) {
1733
- const display = prompt.length > 250 ? prompt.slice(0, 247) + "..." : prompt;
1734
- lines.push(theme.fg("dim", " prompt: ") + theme.fg("muted", `"${display}"`));
1735
- }
1736
- if (model) {
1737
- lines.push(theme.fg("dim", " model: ") + theme.fg("warning", model));
1576
+ return new Text(theme.fg("toolTitle", theme.bold("fetch ")) + theme.fg("accent", display), 0, 0);
1738
1577
  }
1739
- return new Text(lines.join("\n"), 0, 0);
1578
+ return new Text(theme.fg("toolTitle", theme.bold("fetch ")) + theme.fg("accent", `${urlList.length} URLs`), 0, 0);
1740
1579
  },
1741
- renderResult(result, { expanded, isPartial }, theme) {
1580
+ renderResult(result, { expanded, isPartial }, theme, context) {
1742
1581
  const details = result.details;
1743
1582
  if (isPartial) {
1744
1583
  const progress = details?.progress ?? 0;
@@ -1764,49 +1603,18 @@ export default function (pi) {
1764
1603
  return renderSearchErrorPlan(plan, expanded, theme);
1765
1604
  return new Text(theme.fg("error", `Error: ${details.error}`), 0, 0);
1766
1605
  }
1767
- if (details?.urlCount === 1) {
1768
- const title = details?.title || "Untitled";
1769
- const imgCount = details?.imageCount ?? (details?.hasImage ? 1 : 0);
1770
- const imageBadge = imgCount > 1
1771
- ? theme.fg("accent", ` [${imgCount} images]`)
1772
- : imgCount === 1
1773
- ? theme.fg("accent", " [image]")
1774
- : "";
1775
- let statusLine = theme.fg("success", title) + theme.fg("muted", ` (${details?.totalChars ?? 0} chars)`) + imageBadge;
1776
- if (details?.truncated) {
1777
- statusLine += theme.fg("warning", " [truncated]");
1778
- }
1779
- if (typeof details?.duration === "number") {
1780
- statusLine += theme.fg("muted", ` | ${formatSeconds(Math.floor(details.duration))} total`);
1781
- }
1782
- const textContent = result.content.find((c) => c.type === "text")?.text || "";
1783
- if (!expanded) {
1784
- const brief = textContent.length > 200 ? textContent.slice(0, 200) + "..." : textContent;
1785
- return new Text(statusLine + "\n" + theme.fg("dim", brief), 0, 0);
1786
- }
1787
- const lines = [statusLine];
1788
- if (details?.prompt) {
1789
- const display = details.prompt.length > 250 ? details.prompt.slice(0, 247) + "..." : details.prompt;
1790
- lines.push(theme.fg("dim", ` prompt: "${display}"`));
1791
- }
1792
- if (details?.timestamp) {
1793
- lines.push(theme.fg("dim", ` timestamp: ${details.timestamp}`));
1794
- }
1795
- if (typeof details?.frames === "number") {
1796
- lines.push(theme.fg("dim", ` frames: ${details.frames}`));
1797
- }
1798
- const preview = textContent.length > 500 ? textContent.slice(0, 500) + "..." : textContent;
1799
- lines.push(theme.fg("dim", preview));
1800
- return new Text(lines.join("\n"), 0, 0);
1801
- }
1802
- const countColor = (details?.successful ?? 0) > 0 ? "success" : "error";
1803
- const statusLine = theme.fg(countColor, `${details?.successful}/${details?.urlCount} URLs`) + theme.fg("muted", " (content stored)");
1804
- if (!expanded) {
1805
- return new Text(statusLine, 0, 0);
1806
- }
1807
- const textContent = result.content.find((c) => c.type === "text")?.text || "";
1808
- const preview = textContent.length > 500 ? textContent.slice(0, 500) + "..." : textContent;
1809
- return new Text(statusLine + "\n" + theme.fg("dim", preview), 0, 0);
1606
+ // lunr: collapsed = count/status only. Expanded = URL list, no markdown/prompt/frames.
1607
+ const urlList = collectFetchUrls(context?.args);
1608
+ const fallbackUrls = Array.isArray(details?.urls)
1609
+ ? details.urls
1610
+ : [];
1611
+ const chrome = formatFetchChrome({
1612
+ urls: urlList.length > 0 ? urlList : fallbackUrls,
1613
+ details,
1614
+ expanded,
1615
+ });
1616
+ const statusColor = expanded ? "accent" : ((details?.successful ?? 0) > 0 || details?.urlCount === 1 ? "success" : "error");
1617
+ return new Text(chrome.result.map((line) => theme.fg(statusColor, line)).join("\n"), 0, 0);
1810
1618
  },
1811
1619
  });
1812
1620
  pi.registerTool({