@danypops/pi-lector 0.13.1 → 0.13.6
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/extension/src/code-intelligence/operations.ts +2 -1
- package/extension/src/index.ts +51 -31
- package/extension/src/tool-output-bounds.ts +36 -0
- package/extension/src/workspace-cache/caching-overlay.ts +7 -4
- package/extension/src/workspace-cache/caching-widget.ts +13 -1
- package/extension/src/workspace-cache/operations.ts +2 -1
- package/package.json +3 -3
|
@@ -52,7 +52,7 @@ export interface CodeIntelligenceOperations {
|
|
|
52
52
|
workspaceMap(path: string, maxNodes: number, maxEdges: number, maxEntries: number, maxBytes: number): Promise<OperationOutputs["workspace.map"]>;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
export function createLectorCodeIntelligenceOperations(): CodeIntelligenceOperations {
|
|
55
|
+
export function createLectorCodeIntelligenceOperations(ownerId?: string): CodeIntelligenceOperations {
|
|
56
56
|
return {
|
|
57
57
|
async goToDefinition(path, line, character) {
|
|
58
58
|
return withWorkspace(
|
|
@@ -144,6 +144,7 @@ export function createLectorCodeIntelligenceOperations(): CodeIntelligenceOperat
|
|
|
144
144
|
operation: "workspace.populateSymbolGraph",
|
|
145
145
|
input: { workspaceId, maxFiles, maxSymbolsPerFile },
|
|
146
146
|
waitMs,
|
|
147
|
+
...(ownerId ? { ownerId } : {}),
|
|
147
148
|
});
|
|
148
149
|
return job;
|
|
149
150
|
},
|
package/extension/src/index.ts
CHANGED
|
@@ -38,10 +38,11 @@ import {
|
|
|
38
38
|
createWriteToolDefinition,
|
|
39
39
|
type ExtensionAPI,
|
|
40
40
|
type ExtensionCommandContext,
|
|
41
|
+
type ToolDefinition,
|
|
41
42
|
} from "@earendil-works/pi-coding-agent";
|
|
42
43
|
import { Text, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
43
44
|
import { renderBoundedTable, type TextMeasure } from "malevich-tui-components";
|
|
44
|
-
import { Type } from "typebox";
|
|
45
|
+
import { type TSchema, Type } from "typebox";
|
|
45
46
|
|
|
46
47
|
/** Real ANSI-aware measurement for Table -- Malevich's own default is ASCII-only, unsafe against theme-styled cell/header text. */
|
|
47
48
|
const tableMeasure: TextMeasure = { visibleWidth, truncateToWidth };
|
|
@@ -128,6 +129,7 @@ import { createLectorSearchOperations } from "./search/operations.ts";
|
|
|
128
129
|
import { formatSearchCall, formatSearchResult } from "./search/rendering.ts";
|
|
129
130
|
import { type AnnotationAnchorInput, createLectorSymbolAnnotationOperations } from "./symbol-annotation/operations.ts";
|
|
130
131
|
import { formatAnnotationDetail, formatAnnotationListSummary, formatAnnotationSummary } from "./symbol-annotation/rendering.ts";
|
|
132
|
+
import { boundLectorToolText } from "./tool-output-bounds.ts";
|
|
131
133
|
import type { LectorVehicleCall } from "./vehicle-client.ts";
|
|
132
134
|
import { CachingOverlay } from "./workspace-cache/caching-overlay.ts";
|
|
133
135
|
import {
|
|
@@ -168,7 +170,23 @@ function renderIntelligenceSource(body: string, provenance: IntelligenceProvenan
|
|
|
168
170
|
* "start it with `lector serve`" error if none is reachable.
|
|
169
171
|
*/
|
|
170
172
|
export default function (pi: ExtensionAPI) {
|
|
171
|
-
|
|
173
|
+
let cacheOperations = createWorkspaceCacheOperations();
|
|
174
|
+
// Registration is the ownership boundary: every custom Lector tool enters this set
|
|
175
|
+
// automatically, so future tools cannot silently bypass the final model-content cap.
|
|
176
|
+
// Built-in-compatible read/write/edit stay on Pi's own definitions and truncation path.
|
|
177
|
+
const customToolNames = new Set<string>();
|
|
178
|
+
function registerLectorTool<TParams extends TSchema, TDetails = unknown, TState = unknown>(tool: ToolDefinition<TParams, TDetails, TState>): void {
|
|
179
|
+
customToolNames.add(tool.name);
|
|
180
|
+
pi.registerTool(tool);
|
|
181
|
+
}
|
|
182
|
+
pi.on("tool_result", (event) => {
|
|
183
|
+
if (!customToolNames.has(event.toolName)) return;
|
|
184
|
+
const textBlocks = event.content.filter((block): block is Extract<(typeof event.content)[number], { type: "text" }> => block.type === "text");
|
|
185
|
+
if (textBlocks.length === 0) return;
|
|
186
|
+
const bounded = boundLectorToolText(textBlocks.map((block) => block.text).join("\n"));
|
|
187
|
+
if (!bounded.truncation) return;
|
|
188
|
+
return { content: [{ type: "text", text: bounded.text }, ...event.content.filter((block) => block.type !== "text")] };
|
|
189
|
+
});
|
|
172
190
|
// One generation counter shared by every root's monitor loop, not per-root -- a new session
|
|
173
191
|
// (or shutdown) invalidates every previous session's in-flight monitor regardless of which
|
|
174
192
|
// root it tracked, and there is exactly one "current session" at a time.
|
|
@@ -292,6 +310,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
292
310
|
|
|
293
311
|
pi.on("session_start", (_event, ctx) => {
|
|
294
312
|
const { cwd } = ctx;
|
|
313
|
+
const ownerId = ctx.sessionManager.getSessionId();
|
|
314
|
+
cacheOperations = createWorkspaceCacheOperations(ownerId);
|
|
295
315
|
sessionGeneration++;
|
|
296
316
|
cacheStatesByRoot.clear();
|
|
297
317
|
monitoringRoots.clear();
|
|
@@ -299,9 +319,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
299
319
|
uiContext = ctx;
|
|
300
320
|
setNewWorkspaceObserver((root) => startMonitoringRoot(root, ctx));
|
|
301
321
|
if (ctx.hasUI) {
|
|
302
|
-
// The persistent widget counterpart to the single-line "lector-cache" status above
|
|
303
|
-
//
|
|
304
|
-
cachingOverlay
|
|
322
|
+
// The persistent widget counterpart to the single-line "lector-cache" status above.
|
|
323
|
+
// Ownership is the Pi session, not cwd: one session may legitimately touch several roots.
|
|
324
|
+
cachingOverlay = new CachingOverlay(undefined, ownerId);
|
|
305
325
|
cachingOverlay.setUI(ctx.ui);
|
|
306
326
|
void cachingOverlay.refresh();
|
|
307
327
|
cachingOverlay.startPolling();
|
|
@@ -323,7 +343,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
323
343
|
pi.registerTool(createEditToolDefinition(cwd, { operations: createLectorEditOperations() }));
|
|
324
344
|
|
|
325
345
|
const findSymbolsOperations = createLectorFindSymbolsOperations();
|
|
326
|
-
|
|
346
|
+
registerLectorTool({
|
|
327
347
|
name: "find_symbols",
|
|
328
348
|
label: "Find Symbols",
|
|
329
349
|
description:
|
|
@@ -385,7 +405,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
385
405
|
},
|
|
386
406
|
});
|
|
387
407
|
|
|
388
|
-
const codeIntelligenceOperations = createLectorCodeIntelligenceOperations();
|
|
408
|
+
const codeIntelligenceOperations = createLectorCodeIntelligenceOperations(ownerId);
|
|
389
409
|
|
|
390
410
|
const editorOverlayOptions = { overlay: true, overlayOptions: { width: "100%", maxHeight: "100%", anchor: "center" } } as const;
|
|
391
411
|
|
|
@@ -451,7 +471,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
451
471
|
character: Type.Number({ description: "1-indexed character offset within the line" }),
|
|
452
472
|
};
|
|
453
473
|
|
|
454
|
-
|
|
474
|
+
registerLectorTool({
|
|
455
475
|
name: "go_to_definition",
|
|
456
476
|
label: "Go to Definition",
|
|
457
477
|
description: "Find where the symbol at an exact file position is actually declared, across files, through re-exports and aliasing.",
|
|
@@ -485,7 +505,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
485
505
|
},
|
|
486
506
|
});
|
|
487
507
|
|
|
488
|
-
|
|
508
|
+
registerLectorTool({
|
|
489
509
|
name: "go_to_implementation",
|
|
490
510
|
label: "Go to Implementation",
|
|
491
511
|
description:
|
|
@@ -523,7 +543,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
523
543
|
},
|
|
524
544
|
});
|
|
525
545
|
|
|
526
|
-
|
|
546
|
+
registerLectorTool({
|
|
527
547
|
name: "find_references",
|
|
528
548
|
label: "Find References",
|
|
529
549
|
description: "Find every project-wide usage of the symbol at an exact file position.",
|
|
@@ -568,7 +588,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
568
588
|
},
|
|
569
589
|
});
|
|
570
590
|
|
|
571
|
-
|
|
591
|
+
registerLectorTool({
|
|
572
592
|
name: "hover",
|
|
573
593
|
label: "Hover",
|
|
574
594
|
description: "Get type and documentation information for the symbol at an exact file position.",
|
|
@@ -608,7 +628,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
608
628
|
},
|
|
609
629
|
});
|
|
610
630
|
|
|
611
|
-
|
|
631
|
+
registerLectorTool({
|
|
612
632
|
name: "document_symbols",
|
|
613
633
|
label: "Document Symbols",
|
|
614
634
|
description: "List every symbol declared in one file, hierarchically -- an outline of its classes, functions, and their members.",
|
|
@@ -642,7 +662,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
642
662
|
},
|
|
643
663
|
});
|
|
644
664
|
|
|
645
|
-
|
|
665
|
+
registerLectorTool({
|
|
646
666
|
name: "diagnostics",
|
|
647
667
|
label: "Diagnostics",
|
|
648
668
|
description: "List every error and warning a language server currently knows about for one file, as of its last analysis.",
|
|
@@ -679,7 +699,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
679
699
|
},
|
|
680
700
|
});
|
|
681
701
|
|
|
682
|
-
|
|
702
|
+
registerLectorTool({
|
|
683
703
|
name: "call_hierarchy",
|
|
684
704
|
label: "Call Hierarchy",
|
|
685
705
|
description:
|
|
@@ -745,7 +765,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
745
765
|
},
|
|
746
766
|
});
|
|
747
767
|
|
|
748
|
-
|
|
768
|
+
registerLectorTool({
|
|
749
769
|
name: "reference_based_rename",
|
|
750
770
|
label: "Reference-Based Rename",
|
|
751
771
|
description:
|
|
@@ -808,7 +828,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
808
828
|
applied?: OperationOutputs["workspace.rename"];
|
|
809
829
|
}
|
|
810
830
|
|
|
811
|
-
|
|
831
|
+
registerLectorTool({
|
|
812
832
|
name: "rename",
|
|
813
833
|
label: "Rename",
|
|
814
834
|
description:
|
|
@@ -877,7 +897,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
877
897
|
uncontained?: boolean;
|
|
878
898
|
}
|
|
879
899
|
|
|
880
|
-
|
|
900
|
+
registerLectorTool({
|
|
881
901
|
name: "symbol_annotations",
|
|
882
902
|
label: "Symbol Annotations",
|
|
883
903
|
description:
|
|
@@ -1056,7 +1076,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1056
1076
|
},
|
|
1057
1077
|
});
|
|
1058
1078
|
|
|
1059
|
-
|
|
1079
|
+
registerLectorTool({
|
|
1060
1080
|
name: "reachable_from",
|
|
1061
1081
|
label: "Reachable From",
|
|
1062
1082
|
description:
|
|
@@ -1105,7 +1125,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1105
1125
|
},
|
|
1106
1126
|
});
|
|
1107
1127
|
|
|
1108
|
-
|
|
1128
|
+
registerLectorTool({
|
|
1109
1129
|
name: "workspace_map",
|
|
1110
1130
|
label: "Workspace Map",
|
|
1111
1131
|
description:
|
|
@@ -1162,7 +1182,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1162
1182
|
readonly job?: JobSnapshot<PopulateSymbolGraphResult>;
|
|
1163
1183
|
}
|
|
1164
1184
|
|
|
1165
|
-
|
|
1185
|
+
registerLectorTool({
|
|
1166
1186
|
name: "workspace_cache",
|
|
1167
1187
|
label: "Workspace Cache",
|
|
1168
1188
|
description:
|
|
@@ -1253,7 +1273,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1253
1273
|
});
|
|
1254
1274
|
|
|
1255
1275
|
const gitOperations = createLectorGitOperations();
|
|
1256
|
-
|
|
1276
|
+
registerLectorTool({
|
|
1257
1277
|
name: "git",
|
|
1258
1278
|
label: "Git",
|
|
1259
1279
|
description:
|
|
@@ -1396,7 +1416,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1396
1416
|
});
|
|
1397
1417
|
|
|
1398
1418
|
const searchOperations = createLectorSearchOperations();
|
|
1399
|
-
|
|
1419
|
+
registerLectorTool({
|
|
1400
1420
|
name: "search_code",
|
|
1401
1421
|
label: "Search Code",
|
|
1402
1422
|
description:
|
|
@@ -1437,7 +1457,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1437
1457
|
});
|
|
1438
1458
|
|
|
1439
1459
|
const findFilesOperations = createLectorFindFilesOperations();
|
|
1440
|
-
|
|
1460
|
+
registerLectorTool({
|
|
1441
1461
|
name: "find_files",
|
|
1442
1462
|
label: "Find Files",
|
|
1443
1463
|
description:
|
|
@@ -1483,7 +1503,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1483
1503
|
});
|
|
1484
1504
|
|
|
1485
1505
|
const lineEditOperations = createLectorLineEditOperations();
|
|
1486
|
-
|
|
1506
|
+
registerLectorTool({
|
|
1487
1507
|
name: "line_edit",
|
|
1488
1508
|
label: "Line Edit",
|
|
1489
1509
|
description:
|
|
@@ -1554,7 +1574,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1554
1574
|
});
|
|
1555
1575
|
|
|
1556
1576
|
const applyPatchOperations = createLectorApplyPatchOperations();
|
|
1557
|
-
|
|
1577
|
+
registerLectorTool({
|
|
1558
1578
|
name: "apply_patch",
|
|
1559
1579
|
label: "Apply Patch",
|
|
1560
1580
|
description:
|
|
@@ -1605,7 +1625,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1605
1625
|
| { readonly action: "revert"; readonly reverted: { readonly path: string; readonly newHash: string | null } };
|
|
1606
1626
|
|
|
1607
1627
|
const mutationHistoryOperations = createMutationHistoryOperations();
|
|
1608
|
-
|
|
1628
|
+
registerLectorTool({
|
|
1609
1629
|
name: "mutation_history",
|
|
1610
1630
|
label: "Mutation History",
|
|
1611
1631
|
description:
|
|
@@ -1690,7 +1710,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1690
1710
|
}
|
|
1691
1711
|
|
|
1692
1712
|
const packageSourceOperations = createLectorPackageSourceOperations();
|
|
1693
|
-
|
|
1713
|
+
registerLectorTool({
|
|
1694
1714
|
name: "package_source",
|
|
1695
1715
|
label: "Package Source",
|
|
1696
1716
|
description:
|
|
@@ -1796,7 +1816,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1796
1816
|
const repoFetchOperations = createLectorRepoFetchOperations();
|
|
1797
1817
|
const repoCacheListOperations = createRepoCacheListOperations();
|
|
1798
1818
|
const repoCacheEvictOperations = createRepoCacheEvictOperations();
|
|
1799
|
-
|
|
1819
|
+
registerLectorTool({
|
|
1800
1820
|
name: "repo_cache",
|
|
1801
1821
|
label: "Repo Cache",
|
|
1802
1822
|
description:
|
|
@@ -1899,7 +1919,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1899
1919
|
| { readonly action: "sourcegraph_code"; readonly result: { candidates: readonly SourcegraphCodeCandidate[] } };
|
|
1900
1920
|
|
|
1901
1921
|
const externalSearchOperations = createExternalSearchOperations();
|
|
1902
|
-
|
|
1922
|
+
registerLectorTool({
|
|
1903
1923
|
name: "external_search",
|
|
1904
1924
|
label: "External Search",
|
|
1905
1925
|
description:
|
|
@@ -1956,7 +1976,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1956
1976
|
});
|
|
1957
1977
|
|
|
1958
1978
|
const crossWorkspaceSearchOperations = createLectorCrossWorkspaceSearchOperations();
|
|
1959
|
-
|
|
1979
|
+
registerLectorTool({
|
|
1960
1980
|
name: "find_symbols_across_projects",
|
|
1961
1981
|
label: "Find Symbols Across Projects",
|
|
1962
1982
|
description:
|
|
@@ -1996,7 +2016,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1996
2016
|
},
|
|
1997
2017
|
});
|
|
1998
2018
|
|
|
1999
|
-
|
|
2019
|
+
registerLectorTool({
|
|
2000
2020
|
name: "search_code_across_projects",
|
|
2001
2021
|
label: "Search Code Across Projects",
|
|
2002
2022
|
description:
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult, truncateHead } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
export interface BoundedLectorToolText {
|
|
4
|
+
readonly text: string;
|
|
5
|
+
readonly truncation: TruncationResult | undefined;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function noticeFor(truncation: TruncationResult): string {
|
|
9
|
+
return (
|
|
10
|
+
`[Lector tool output truncated: ${truncation.totalLines} lines total, ${formatSize(truncation.totalBytes)} total; ` +
|
|
11
|
+
`showing ${truncation.outputLines} lines and ${formatSize(truncation.outputBytes)}. Refine the query or lower its scope.]`
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Applies Pi's process-level custom-tool output contract independently of Lector's domain bounds.
|
|
17
|
+
* Domain maxBytes values intentionally describe DTO payload fields, not the final serialized tool
|
|
18
|
+
* message; this final guard accounts for separators, provenance, JSON framing, and caller-selected
|
|
19
|
+
* bounds before content enters model context.
|
|
20
|
+
*/
|
|
21
|
+
export function boundLectorToolText(text: string): BoundedLectorToolText {
|
|
22
|
+
const initial = truncateHead(text);
|
|
23
|
+
if (!initial.truncated) return { text, truncation: undefined };
|
|
24
|
+
|
|
25
|
+
let bounded = initial;
|
|
26
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
27
|
+
const notice = noticeFor(bounded);
|
|
28
|
+
const noticeBytes = Buffer.byteLength(`\n\n${notice}`, "utf8");
|
|
29
|
+
bounded = truncateHead(text, {
|
|
30
|
+
maxLines: Math.max(1, DEFAULT_MAX_LINES - 2),
|
|
31
|
+
maxBytes: Math.max(1, DEFAULT_MAX_BYTES - noticeBytes),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const notice = noticeFor(bounded);
|
|
35
|
+
return { text: bounded.content ? `${bounded.content}\n\n${notice}` : notice, truncation: bounded };
|
|
36
|
+
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* DoctorOverlay: factory-form ctx.ui.setWidget registration, requestRender on refresh, hides the
|
|
5
5
|
* widget entirely (setWidget(key, undefined)) rather than an empty box once nothing is caching.
|
|
6
6
|
*
|
|
7
|
-
* workspace.activeCachingJobs
|
|
8
|
-
*
|
|
7
|
+
* workspace.activeCachingJobs is filtered by the owning Pi session, while its omitted-owner
|
|
8
|
+
* daemon contract remains available for global administration -- see cache-query-handlers.ts.
|
|
9
9
|
*/
|
|
10
10
|
import type { ExtensionUIContext, Theme } from "@earendil-works/pi-coding-agent";
|
|
11
11
|
import type { TUI } from "@earendil-works/pi-tui";
|
|
@@ -39,7 +39,10 @@ export class CachingOverlay {
|
|
|
39
39
|
intervalMs: CACHING_WIDGET_ROTATION_INTERVAL_MS,
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
-
constructor(
|
|
42
|
+
constructor(
|
|
43
|
+
private readonly connect: () => Promise<RetryingLectorClient> = lectorClient,
|
|
44
|
+
private readonly ownerId?: string,
|
|
45
|
+
) {}
|
|
43
46
|
|
|
44
47
|
setUI(ctx: ExtensionUIContext): void {
|
|
45
48
|
if (ctx !== this.uiCtx) {
|
|
@@ -55,7 +58,7 @@ export class CachingOverlay {
|
|
|
55
58
|
async refresh(): Promise<void> {
|
|
56
59
|
try {
|
|
57
60
|
const client = await this.connect();
|
|
58
|
-
const result = await client.call("workspace.activeCachingJobs", {});
|
|
61
|
+
const result = await client.call("workspace.activeCachingJobs", this.ownerId ? { ownerId: this.ownerId } : {});
|
|
59
62
|
this.projection = buildCachingWidgetProjection(result.jobs);
|
|
60
63
|
} catch {
|
|
61
64
|
this.projection = EMPTY_PROJECTION;
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* unit-testable without a real daemon or terminal. See caching-overlay.ts for the stateful
|
|
6
6
|
* ctx.ui.setWidget-registered class that drives these from a live poll.
|
|
7
7
|
*/
|
|
8
|
+
|
|
9
|
+
import { basename } from "node:path";
|
|
8
10
|
import { vehicleWidgetTitle } from "@danypops/vehicle-client-pi/widget-header";
|
|
9
11
|
import { truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
10
12
|
import { type AutoRotatingWindow, renderCardRow, type TextMeasure } from "malevich-tui-components";
|
|
@@ -20,6 +22,10 @@ export const LECTOR_CACHING_WIDGET_VISIBLE_ROWS = 5;
|
|
|
20
22
|
export interface CachingWidgetRow {
|
|
21
23
|
workspaceId: string;
|
|
22
24
|
status: "queued" | "running" | "waiting-for-resources";
|
|
25
|
+
/** Absent for an already-unregistered workspace -- falls back to the bare workspaceId for display. */
|
|
26
|
+
rootPath?: string;
|
|
27
|
+
/** Absent until the first file of this run completes, or while still queued -- nothing walked yet. */
|
|
28
|
+
progress?: { filesProcessed: number; filesTotal: number };
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
export interface CachingWidgetProjection {
|
|
@@ -31,6 +37,11 @@ export function buildCachingWidgetProjection(jobs: readonly CachingWidgetRow[]):
|
|
|
31
37
|
return { rows: [...jobs], total: jobs.length };
|
|
32
38
|
}
|
|
33
39
|
|
|
40
|
+
/** The project directory's own basename when a path is known ("lector", not the full absolute path a narrow card has no room for) -- falls back to the bare workspaceId hash for a row with no rootPath at all. */
|
|
41
|
+
function cachingRowLabel(row: CachingWidgetRow): string {
|
|
42
|
+
return row.rootPath ? basename(row.rootPath) : row.workspaceId;
|
|
43
|
+
}
|
|
44
|
+
|
|
34
45
|
function cachingRowLine(theme: { fg(color: string, text: string): string }, row: CachingWidgetRow, width: number): string {
|
|
35
46
|
const glyph =
|
|
36
47
|
row.status === "waiting-for-resources"
|
|
@@ -38,7 +49,8 @@ function cachingRowLine(theme: { fg(color: string, text: string): string }, row:
|
|
|
38
49
|
: row.status === "queued"
|
|
39
50
|
? theme.fg("muted", "\u2022")
|
|
40
51
|
: theme.fg("accent", "\u25b6");
|
|
41
|
-
|
|
52
|
+
const progressSuffix = row.progress ? theme.fg("muted", ` (${row.progress.filesProcessed}/${row.progress.filesTotal})`) : "";
|
|
53
|
+
return truncateToWidth(`${glyph} ${cachingRowLabel(row)}${progressSuffix}`, width, "\u2026");
|
|
42
54
|
}
|
|
43
55
|
|
|
44
56
|
/** "Lector · Caching · <N>", plus a "page/total ⟳" suffix once genuinely paging. */
|
|
@@ -39,7 +39,7 @@ export interface WorkspaceCacheOperations {
|
|
|
39
39
|
watchJob?(jobId: string, onJob: (job: JobSnapshot<PopulateSymbolGraphResult>) => void): Promise<JobWatchOutcome>;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
export function createWorkspaceCacheOperations(): WorkspaceCacheOperations {
|
|
42
|
+
export function createWorkspaceCacheOperations(ownerId?: string): WorkspaceCacheOperations {
|
|
43
43
|
return {
|
|
44
44
|
status(directory, maxFiles, maxSymbolsPerFile) {
|
|
45
45
|
return withWorkspace(
|
|
@@ -59,6 +59,7 @@ export function createWorkspaceCacheOperations(): WorkspaceCacheOperations {
|
|
|
59
59
|
operation: "workspace.populateSymbolGraph",
|
|
60
60
|
input: { workspaceId, maxFiles, maxSymbolsPerFile, retryTimeBudgetMs },
|
|
61
61
|
waitMs,
|
|
62
|
+
...(ownerId ? { ownerId } : {}),
|
|
62
63
|
});
|
|
63
64
|
return job;
|
|
64
65
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danypops/pi-lector",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.6",
|
|
4
4
|
"description": "Pi host adapter for Lector: overrides read/write/edit with a daemon-backed, hash-guarded filesystem",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"@earendil-works/pi-coding-agent": "*",
|
|
20
20
|
"@earendil-works/pi-tui": "*",
|
|
21
21
|
"typebox": "*",
|
|
22
|
-
"@danypops/vehicle-client-pi": "^0.
|
|
22
|
+
"@danypops/vehicle-client-pi": "^0.45.0"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@danypops/lector": "^0.19.9",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"picomatch": "^4.0.5"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@danypops/vehicle-client-pi": "^0.
|
|
32
|
+
"@danypops/vehicle-client-pi": "^0.45.0",
|
|
33
33
|
"@danypops/vehicle-conformance": "^0.4.0",
|
|
34
34
|
"@danypops/pi-extension-harness": "^0.2.0",
|
|
35
35
|
"@danypops/pi-tui-harness": "^0.0.1",
|