omp-fabric 1.14.0 → 1.16.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 (83) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +1 -0
  3. package/dist/chunks/{chunk-PV453JOK.js → chunk-3NWBU3K7.js} +2 -2
  4. package/dist/chunks/{chunk-XQCAIIEM.js → chunk-3U5ZVAIX.js} +2 -2
  5. package/dist/chunks/{chunk-R6QAXATY.js → chunk-ARRZTY7E.js} +2 -2
  6. package/dist/chunks/chunk-BSUEBCAM.js +248 -0
  7. package/dist/chunks/chunk-BSUEBCAM.js.map +7 -0
  8. package/dist/chunks/{chunk-KJKO6KGW.js → chunk-D2ET33NE.js} +13 -403
  9. package/dist/chunks/chunk-D2ET33NE.js.map +7 -0
  10. package/dist/chunks/chunk-E4HNDTLM.js +469 -0
  11. package/dist/chunks/chunk-E4HNDTLM.js.map +7 -0
  12. package/dist/chunks/{chunk-DTXCVXXF.js → chunk-N2MMGFMD.js} +8 -6
  13. package/dist/chunks/{chunk-DTXCVXXF.js.map → chunk-N2MMGFMD.js.map} +1 -1
  14. package/dist/chunks/{chunk-GZQVYRM3.js → chunk-NX2G7BRO.js} +6 -2
  15. package/dist/chunks/{chunk-GZQVYRM3.js.map → chunk-NX2G7BRO.js.map} +2 -2
  16. package/dist/chunks/{chunk-M4DQ47WO.js → chunk-QD2B5FUE.js} +1 -2
  17. package/dist/chunks/chunk-SMNOQLKU.js +53 -0
  18. package/dist/chunks/chunk-SMNOQLKU.js.map +7 -0
  19. package/dist/chunks/{chunk-2NTQAH6X.js → chunk-WCV26AOT.js} +12 -7
  20. package/dist/chunks/chunk-WCV26AOT.js.map +7 -0
  21. package/dist/chunks/{chunk-AOXYDBXC.js → chunk-XJMS4223.js} +2 -2
  22. package/dist/commands/fabric.d.ts.map +1 -1
  23. package/dist/compaction/hook.d.ts.map +1 -1
  24. package/dist/compaction/hook.js +2 -2
  25. package/dist/compaction/lcm-doctor.d.ts +60 -0
  26. package/dist/compaction/lcm-doctor.d.ts.map +1 -0
  27. package/dist/compaction/lcm-maintenance.d.ts +3 -0
  28. package/dist/compaction/lcm-maintenance.d.ts.map +1 -1
  29. package/dist/compaction/lcm-model.d.ts +1 -1
  30. package/dist/compaction/lcm-model.d.ts.map +1 -1
  31. package/dist/compaction/lcm-runtime.d.ts +28 -4
  32. package/dist/compaction/lcm-runtime.d.ts.map +1 -1
  33. package/dist/compaction/lcm-runtime.js +509 -101
  34. package/dist/compaction/lcm-runtime.js.map +4 -4
  35. package/dist/fabric-runtime-state.d.ts +13 -0
  36. package/dist/fabric-runtime-state.d.ts.map +1 -1
  37. package/dist/fabric-runtime-state.js +13 -12
  38. package/dist/fabric-runtime-state.js.map +2 -2
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +65 -17
  41. package/dist/index.js.map +2 -2
  42. package/dist/providers/memory-provider.js +2 -2
  43. package/dist/residency/host.js +7 -7
  44. package/dist/residency/omp-entry.js +7 -7
  45. package/dist/storage/lcm-directory.d.ts +16 -0
  46. package/dist/storage/lcm-directory.d.ts.map +1 -0
  47. package/dist/storage/lcm-identity.d.ts +1 -0
  48. package/dist/storage/lcm-identity.d.ts.map +1 -1
  49. package/dist/storage/lcm-ledger.d.ts +11 -0
  50. package/dist/storage/lcm-ledger.d.ts.map +1 -1
  51. package/dist/storage/lcm-migration.d.ts +1 -0
  52. package/dist/storage/lcm-migration.d.ts.map +1 -1
  53. package/dist/ui/controller.d.ts +1 -0
  54. package/dist/ui/controller.d.ts.map +1 -1
  55. package/dist/ui/conversation.js +5 -5
  56. package/dist/ui/dashboard-model.d.ts +1 -1
  57. package/dist/ui/dashboard-model.d.ts.map +1 -1
  58. package/dist/ui/dashboard.d.ts +0 -18
  59. package/dist/ui/dashboard.d.ts.map +1 -1
  60. package/dist/ui/dashboard.js +68 -504
  61. package/dist/ui/dashboard.js.map +4 -4
  62. package/dist/ui/frame.d.ts +7 -0
  63. package/dist/ui/frame.d.ts.map +1 -0
  64. package/dist/ui/lcm-dashboard.d.ts +43 -0
  65. package/dist/ui/lcm-dashboard.d.ts.map +1 -0
  66. package/dist/ui/lcm-dashboard.js +395 -0
  67. package/dist/ui/lcm-dashboard.js.map +7 -0
  68. package/dist/ui/lcm-panel.d.ts +0 -1
  69. package/dist/ui/lcm-panel.d.ts.map +1 -1
  70. package/dist/ui/lcm-panel.js +23 -0
  71. package/dist/ui/lcm-panel.js.map +7 -0
  72. package/docs/compaction.md +20 -1
  73. package/docs/interface.md +1 -0
  74. package/package.json +1 -1
  75. package/dist/chunks/chunk-2NTQAH6X.js.map +0 -7
  76. package/dist/chunks/chunk-KJKO6KGW.js.map +0 -7
  77. package/dist/chunks/chunk-NIWOSO22.js +0 -74
  78. package/dist/chunks/chunk-NIWOSO22.js.map +0 -7
  79. /package/dist/chunks/{chunk-PV453JOK.js.map → chunk-3NWBU3K7.js.map} +0 -0
  80. /package/dist/chunks/{chunk-XQCAIIEM.js.map → chunk-3U5ZVAIX.js.map} +0 -0
  81. /package/dist/chunks/{chunk-R6QAXATY.js.map → chunk-ARRZTY7E.js.map} +0 -0
  82. /package/dist/chunks/{chunk-M4DQ47WO.js.map → chunk-QD2B5FUE.js.map} +0 -0
  83. /package/dist/chunks/{chunk-AOXYDBXC.js.map → chunk-XJMS4223.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.16.0
4
+
5
+ ### Added
6
+
7
+ - `/fabric lcm` opens a dashboard of its own for the LCM ledger, with four tabs: `health` runs a doctor over seven checks and offers a one-key repair for the ones that carry one, `graph` pages the summary nodes and opens the raw entry behind any source, `coverage` draws every stored branch entry as one aggregated cell above the text a compaction would serve, and `jobs` lists maintenance work failure-first with `r` to requeue and `l` to release stuck leases.
8
+ - An automatic repair ladder persisted in the ledger (`repair_ladder`): one repair per turn boundary, a failing check preferred over a warning one, five attempts per fault class with 30-second backoff doubling to 8 minutes, parked and reported once the budget is spent, and cleared after its check has been quiet for half an hour.
9
+ - A ledger directory (`projects.json`) that remembers the key each project path was first filed under, so a project whose directory changes inode keeps its history, plus a daily sweep that removes a ledger only when its project directory is gone and nothing has written it for 30 days.
10
+
11
+ ### Fixed
12
+
13
+ - A session file the host has not written yet is reported as absent rather than as a reconciliation error, so a fresh session no longer opens `degraded` with a fault it cannot act on. Reconciliation re-runs once the file appears.
14
+ - Readback hashes each branch entry and appends only the ones whose payload is not stored yet, which lets it run on every message instead of once a turn; an entry amended in place still gains a revision.
15
+ - The frontier cache is invalidated whenever readback, reconciliation, maintenance, compaction, or a repair changes what it summarises, so coverage can no longer report a stale figure.
16
+ - The jobs page orders failures first in SQL, so a recent failure is visible on a ledger holding more jobs than one page.
17
+ - `BACKUP_MANIFEST_VERSION` moves to 3 because the ledger snapshot now digests the repair table; an older backup is refused with the versioned message instead of a raw SQLite error.
18
+
19
+ ### Changed
20
+
21
+ - The LCM view left the shared `/fabric dashboard`; key `3` is gone and the help screen points at `/fabric lcm`.
22
+
23
+ ## 1.15.0
24
+
25
+ ### Added
26
+
27
+ - Support for compaction custom instructions and preserve items in LCM: `renderAddressedFrontier` and `emergencyReduce` now render a `[Compaction Request]` block when instructions or preserve entries are supplied via `compact.request`, matching the deterministic compactor's policy contract.
28
+ - SQLite indexes on `summary_nodes(project_key, created_at, node_id)`, `maintenance_jobs(project_key, status)`, and `summary_edges(child_id, parent_id)` to eliminate unindexed table scans during node listing, job scheduling, and ancestor edge traversal.
29
+ - Warning logging and UI notifications on compaction hook errors before cancellation, preventing silent context blowups.
30
+
31
+ ### Fixed
32
+
33
+ - Transaction batching during session readback and compaction: `readback()` and `compact()` now wrap raw entry persistence in an explicit ledger transaction, collapsing hundreds of sequential synchronous SQLite fsync operations into a single atomic commit.
34
+ - Dirty flag enforcement in `LcmRuntime`: `syncAndSchedule()` now checks `this.dirty` and active session binding to skip redundant full-branch readbacks on idle turns.
35
+ - Memory allocation in `clipUtf8End`: trailing text slices are now bounded to `maxBytes * 2` before codepoint conversion, eliminating multi-megabyte array allocations when producing emergency excerpts.
36
+
3
37
  ## 1.14.0
4
38
 
5
39
  ### Added
package/README.md CHANGED
@@ -122,6 +122,7 @@ Fabric includes a live activity surface in OMP:
122
122
 
123
123
  - A compact widget above the chat (like `pi-supervisor`) whose header follows the current phase while its rows show active/completed agents, active actors, and their recent nested tool or code-change activity.
124
124
  - `/fabric` (or `/fabric dashboard`): opens the **Activity** and **Topology** views. The user-facing OMP session appears as **Main**. You can queue or steer participants and inspect the project topology.
125
+ - `/fabric lcm`: opens the LCM ledger dashboard with health checks and one-key repairs, the summary node graph, branch coverage, and maintenance jobs.
125
126
  - `/fabric settings`: mirrors OMP's `/settings` and writes changes to `fabric.json`. TUI hosts get the searchable settings component; RPC hosts get the same nested sections, value/input/model pickers, list editors, and project/global save scopes through native dialog primitives.
126
127
  - `Tool display` (`compact` by default, or `full`) is configured under `/fabric settings` → **UI**; compact elevates the declared display intent, hides the outer TypeScript, and applies to the current transcript immediately. OMP's tool-expand keybinding (`ctrl+o` by default) expands a compact card to the full transcript.
127
128
 
@@ -21,7 +21,7 @@ import {
21
21
  import {
22
22
  peerLabelPrefix,
23
23
  writeHandoffSession
24
- } from "./chunk-DTXCVXXF.js";
24
+ } from "./chunk-N2MMGFMD.js";
25
25
  import {
26
26
  DEFAULT_FABRIC_CONFIG,
27
27
  MAX_AGENT_TIMEOUT_MS,
@@ -6635,4 +6635,4 @@ export {
6635
6635
  agentParticipantRecords,
6636
6636
  actorParticipantRecord
6637
6637
  };
6638
- //# sourceMappingURL=chunk-PV453JOK.js.map
6638
+ //# sourceMappingURL=chunk-3NWBU3K7.js.map
@@ -10,7 +10,7 @@ import {
10
10
  lifecycleSourceIdentity,
11
11
  loadModelUsage,
12
12
  useBudgetLedger
13
- } from "./chunk-PV453JOK.js";
13
+ } from "./chunk-3NWBU3K7.js";
14
14
  import {
15
15
  normalizeModelAliases,
16
16
  resolveAvailableOmpModel
@@ -685,4 +685,4 @@ if (isMain) {
685
685
  export {
686
686
  runResidentHostFromConfigPath
687
687
  };
688
- //# sourceMappingURL=chunk-XQCAIIEM.js.map
688
+ //# sourceMappingURL=chunk-3U5ZVAIX.js.map
@@ -12,7 +12,7 @@ import {
12
12
  buildThinkingDigest,
13
13
  snapshotHandoffSession,
14
14
  thinkingTransferPolicy
15
- } from "./chunk-DTXCVXXF.js";
15
+ } from "./chunk-N2MMGFMD.js";
16
16
  import {
17
17
  isFabricThinking
18
18
  } from "./chunk-SKYNDRW5.js";
@@ -2803,4 +2803,4 @@ export {
2803
2803
  resolveFabricIdentity,
2804
2804
  MainAgentController
2805
2805
  };
2806
- //# sourceMappingURL=chunk-R6QAXATY.js.map
2806
+ //# sourceMappingURL=chunk-ARRZTY7E.js.map
@@ -0,0 +1,248 @@
1
+ import {
2
+ formatClock,
3
+ padToWidth,
4
+ safeText,
5
+ wrapPlainText
6
+ } from "./chunk-KIH3KLZU.js";
7
+
8
+ // src/ui/lcm-panel.ts
9
+ import { truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
10
+ var LCM_NODE_PAGE = 200;
11
+ var COVERAGE_COMPLETE_RATIO = 0.95;
12
+ var EMERGENCY_MODEL_HASH = "emergency";
13
+ var readLcmSnapshot = (source, offset) => {
14
+ const nodes = source.nodes(LCM_NODE_PAGE, offset);
15
+ return {
16
+ report: source.report(),
17
+ coverage: source.coverage(),
18
+ preview: source.preview(),
19
+ coverageMap: source.coverageMap(),
20
+ nodes,
21
+ offset,
22
+ hasMore: nodes.length === LCM_NODE_PAGE
23
+ };
24
+ };
25
+ var lcmNodeDetail = (source, nodeId) => {
26
+ const detail = source.node(nodeId);
27
+ if (!detail) return void 0;
28
+ return {
29
+ node: detail.node,
30
+ revisions: [...detail.revisions].sort((left, right) => left.revision - right.revision),
31
+ ancestors: detail.ancestors
32
+ };
33
+ };
34
+ var formatBytes = (bytes) => {
35
+ if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
36
+ if (bytes < 1024) return `${Math.round(bytes)} B`;
37
+ if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} kB`;
38
+ return `${(bytes / 1048576).toFixed(1)} MB`;
39
+ };
40
+ var formatPercent = (value) => value > 0 && value < 1 ? `${value.toFixed(value < 0.1 ? 2 : 1)}%` : `${Math.round(value)}%`;
41
+ var isEmergency = (modelHash) => modelHash === EMERGENCY_MODEL_HASH;
42
+ var originLabel = (modelHash) => isEmergency(modelHash) ? "excerpt" : "model";
43
+ var shortId = (value) => value.length > 10 ? `${value.slice(0, 10)}\u2026` : value;
44
+ var textBytes = (text) => text ? Buffer.byteLength(text, "utf8") : 0;
45
+ var lcmUnavailableLine = () => "LCM ledger unavailable \xB7 set compaction.engine to lcm and start a session to populate it";
46
+ var bandRun = (theme, char, length) => {
47
+ const color = char === "\u2588" ? "success" : char === "\u2593" ? "warning" : "dim";
48
+ return theme.fg(color, char.repeat(length));
49
+ };
50
+ var coverageBand = (theme, map, cells) => {
51
+ if (cells <= 0) return "";
52
+ if (map.length === 0) return theme.fg("dim", "\xB7".repeat(cells));
53
+ let band = "";
54
+ let runChar = "";
55
+ let runLength = 0;
56
+ for (let cell = 0; cell < cells; cell++) {
57
+ const start = Math.min(map.length - 1, Math.floor(cell * map.length / cells));
58
+ const end = Math.min(map.length, Math.max(start + 1, Math.floor((cell + 1) * map.length / cells)));
59
+ let covered = 0;
60
+ for (let index = start; index < end; index++) {
61
+ if (map[index].covered) covered++;
62
+ }
63
+ const char = covered === 0 ? "\u2591" : covered === end - start ? "\u2588" : "\u2593";
64
+ if (char === runChar) {
65
+ runLength++;
66
+ continue;
67
+ }
68
+ if (runLength > 0) band += bandRun(theme, runChar, runLength);
69
+ runChar = char;
70
+ runLength = 1;
71
+ }
72
+ if (runLength > 0) band += bandRun(theme, runChar, runLength);
73
+ return band;
74
+ };
75
+ var renderLcmCoverageLine = (theme, snapshot, width) => {
76
+ const { active, covered } = snapshot.coverage;
77
+ const label = `${covered}/${active} covered ${formatPercent(active > 0 ? covered / active * 100 : 0)}`;
78
+ const cells = Math.max(0, width - visibleWidth(label) - 1);
79
+ const band = coverageBand(theme, snapshot.coverageMap, cells);
80
+ return truncateToWidth(`${band} ${theme.fg("muted", label)}`, width, "");
81
+ };
82
+ var nodeRow = (node) => {
83
+ const indent = " ".repeat(Math.min(node.depth, 8));
84
+ const glyph = node.kind === "condensed" ? "\u25C6" : "\u25C7";
85
+ return safeText(
86
+ `${indent}${glyph} ${node.kind} ${originLabel(node.modelHash)} \xB7 ${node.sources.length} src \xB7 ${node.children.length} ch \xB7 ${formatBytes(textBytes(node.text))} \xB7 ${shortId(node.nodeId)}`
87
+ );
88
+ };
89
+ var renderLcmNodeLines = (theme, snapshot, width, height, selectedIndex) => {
90
+ const available = Math.max(1, height);
91
+ const total = snapshot.nodes.length;
92
+ const heading = `nodes ${total === 0 ? 0 : snapshot.offset + 1}-${snapshot.offset + total}${snapshot.hasMore ? "+" : ""}`;
93
+ const lines = [theme.fg("accent", truncateToWidth(heading, width, ""))];
94
+ if (total === 0) {
95
+ lines.push(theme.fg("dim", " (no summary nodes on the active branch yet)"));
96
+ while (lines.length < available) lines.push("");
97
+ return lines.slice(0, available);
98
+ }
99
+ const rows = Math.max(1, available - 1);
100
+ const start = Math.max(
101
+ 0,
102
+ Math.min(selectedIndex - Math.floor(rows / 2), Math.max(0, total - rows))
103
+ );
104
+ for (let index = start; index < Math.min(total, start + rows); index++) {
105
+ const node = snapshot.nodes[index];
106
+ const emergency = isEmergency(node.modelHash);
107
+ let line = theme.fg(emergency ? "warning" : "muted", nodeRow(node));
108
+ if (index === selectedIndex) line = theme.bg("selectedBg", padToWidth(line, width));
109
+ lines.push(truncateToWidth(line, width, ""));
110
+ }
111
+ while (lines.length < available) lines.push("");
112
+ return lines.slice(0, available);
113
+ };
114
+ var renderLcmPreviewLines = (theme, snapshot, width, height) => {
115
+ const available = Math.max(1, height);
116
+ const preview = snapshot.preview;
117
+ const complete = preview.activeSources > 0 && preview.coveredSources / preview.activeSources >= COVERAGE_COMPLETE_RATIO;
118
+ const ratio = complete && preview.sourceBytes > 0 ? ` \xB7 assembled text is ${formatPercent(preview.summaryBytes / preview.sourceBytes * 100)} of the session payload it replaces` : "";
119
+ const headline = `preview \xB7 frontier holds ${preview.coveredSources}/${preview.activeSources} sources \xB7 ${preview.nodes} nodes assemble to ${formatBytes(preview.summaryBytes)} \xB7 session stored payload ${formatBytes(preview.sourceBytes)}${ratio}`;
120
+ const lines = wrapPlainText(headline, width, 2).map((line) => theme.fg("accent", line));
121
+ const body = wrapPlainText(preview.text, width, Math.max(1, available - lines.length));
122
+ for (const line of body) lines.push(theme.fg("dim", line));
123
+ if (body.length === 0) lines.push(theme.fg("dim", "(the frontier assembles no text yet)"));
124
+ while (lines.length < available) lines.push("");
125
+ return lines.slice(0, available);
126
+ };
127
+ var revisionColumns = (theme, detail, width, rows) => {
128
+ const current = detail.revisions[detail.revisions.length - 1];
129
+ const previous = detail.revisions[detail.revisions.length - 2];
130
+ if (!current) return [];
131
+ if (!previous) {
132
+ const lines2 = [theme.fg("accent", `text \xB7 current revision ${current.revision} \xB7 ${originLabel(current.modelHash)}`)];
133
+ for (const line of wrapPlainText(current.text, width, Math.max(1, rows - 1))) {
134
+ lines2.push(theme.fg("dim", line));
135
+ }
136
+ return lines2;
137
+ }
138
+ const label = (revision, name) => `${name} revision ${revision.revision} \xB7 ${originLabel(revision.modelHash)}`;
139
+ if (width < 60) {
140
+ const lines2 = [theme.fg("accent", label(current, "current"))];
141
+ for (const line of wrapPlainText(current.text, width, Math.max(1, Math.floor((rows - 2) / 2)))) {
142
+ lines2.push(theme.fg("dim", line));
143
+ }
144
+ lines2.push(theme.fg("accent", label(previous, "previous")));
145
+ for (const line of wrapPlainText(previous.text, width, Math.max(1, Math.floor((rows - 2) / 2)))) {
146
+ lines2.push(theme.fg("muted", line));
147
+ }
148
+ return lines2;
149
+ }
150
+ const columnWidth = Math.floor((width - 1) / 2);
151
+ const body = Math.max(1, rows - 1);
152
+ const previousBody = wrapPlainText(previous.text, columnWidth, body);
153
+ const currentBody = wrapPlainText(current.text, columnWidth, body);
154
+ const lines = [
155
+ `${padToWidth(theme.fg("accent", label(previous, "previous")), columnWidth)}${theme.fg("borderMuted", "\u2502")}${theme.fg("accent", label(current, "current"))}`
156
+ ];
157
+ for (let index = 0; index < body; index++) {
158
+ const left = previousBody[index];
159
+ const right = currentBody[index];
160
+ if (left === void 0 && right === void 0) break;
161
+ lines.push(
162
+ `${padToWidth(theme.fg("muted", left ?? ""), columnWidth)}${theme.fg("borderMuted", "\u2502")}${theme.fg("dim", right ?? "")}`
163
+ );
164
+ }
165
+ return lines;
166
+ };
167
+ var renderLcmDetailLines = (theme, detail, sourceIndex, entry, width, height) => {
168
+ const available = Math.max(1, height);
169
+ const node = detail.node;
170
+ const lines = [
171
+ theme.fg(
172
+ isEmergency(node.modelHash) ? "warning" : "accent",
173
+ truncateToWidth(
174
+ safeText(
175
+ `${node.kind} \xB7 ${originLabel(node.modelHash)} \xB7 depth ${node.depth} \xB7 ${node.state} \xB7 ${formatClock(node.createdAt)} \xB7 ${node.nodeId}`
176
+ ),
177
+ width,
178
+ ""
179
+ )
180
+ ),
181
+ theme.fg(
182
+ "dim",
183
+ truncateToWidth(safeText(`model hash ${node.modelHash} \xB7 branch ${node.branch ?? "none"}`), width, "")
184
+ ),
185
+ theme.fg(
186
+ "dim",
187
+ truncateToWidth(
188
+ safeText(`ancestors ${detail.ancestors.length > 0 ? detail.ancestors.join(" \u203A ") : "none"}`),
189
+ width,
190
+ ""
191
+ )
192
+ ),
193
+ theme.fg(
194
+ "dim",
195
+ truncateToWidth(
196
+ safeText(
197
+ `children (${node.children.length}) ${node.children.length > 0 ? node.children.map(shortId).join(" ") : "none"}`
198
+ ),
199
+ width,
200
+ ""
201
+ )
202
+ ),
203
+ theme.fg("accent", truncateToWidth(`sources (${node.sources.length})`, width, ""))
204
+ ];
205
+ const sourceRows = Math.min(node.sources.length, Math.max(1, Math.floor(available / 4)));
206
+ const sourceStart = Math.max(
207
+ 0,
208
+ Math.min(sourceIndex - Math.floor(sourceRows / 2), Math.max(0, node.sources.length - sourceRows))
209
+ );
210
+ for (let index = sourceStart; index < Math.min(node.sources.length, sourceStart + sourceRows); index++) {
211
+ const source = node.sources[index];
212
+ const text = ` ${source.sessionId}/${source.entryId}@${source.revision}`;
213
+ const line = index === sourceIndex ? theme.bg("selectedBg", padToWidth(theme.fg("muted", text), width)) : theme.fg("muted", text);
214
+ lines.push(truncateToWidth(line, width, ""));
215
+ }
216
+ if (node.sources.length === 0) lines.push(theme.fg("dim", " (no sources)"));
217
+ if (entry) {
218
+ lines.push(
219
+ theme.fg(
220
+ "accent",
221
+ truncateToWidth(
222
+ safeText(`raw entry \xB7 ${entry.role} \xB7 ${formatClock(entry.createdAt)} \xB7 ${formatBytes(Buffer.byteLength(entry.payloadJson, "utf8"))} stored`),
223
+ width,
224
+ ""
225
+ )
226
+ )
227
+ );
228
+ for (const line of wrapPlainText(entry.content, width, Math.max(1, Math.floor(available / 4)))) {
229
+ lines.push(theme.fg("dim", line));
230
+ }
231
+ }
232
+ const remaining = Math.max(1, available - lines.length);
233
+ for (const line of revisionColumns(theme, detail, width, remaining)) lines.push(line);
234
+ while (lines.length < available) lines.push("");
235
+ return lines.slice(0, available);
236
+ };
237
+
238
+ export {
239
+ LCM_NODE_PAGE,
240
+ readLcmSnapshot,
241
+ lcmNodeDetail,
242
+ lcmUnavailableLine,
243
+ renderLcmCoverageLine,
244
+ renderLcmNodeLines,
245
+ renderLcmPreviewLines,
246
+ renderLcmDetailLines
247
+ };
248
+ //# sourceMappingURL=chunk-BSUEBCAM.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/ui/lcm-panel.ts"],
4
+ "sourcesContent": ["import type { Theme } from \"@oh-my-pi/pi-coding-agent\";\nimport { truncateToWidth, visibleWidth } from \"@oh-my-pi/pi-tui\";\nimport type { LcmDashboardNode, LcmStatusSource } from \"../fabric-runtime-state.js\";\nimport { lcmStatusLabel } from \"../compaction/lcm-status.js\";\nimport { formatClock, formatCost, padToWidth, safeText, wrapPlainText } from \"./format.js\";\n\nexport const LCM_NODE_PAGE = 200;\n\nconst COVERAGE_COMPLETE_RATIO = 0.95;\nconst EMERGENCY_MODEL_HASH = \"emergency\";\n\nexport interface LcmViewSnapshot {\n report: ReturnType<LcmStatusSource[\"report\"]>;\n coverage: ReturnType<LcmStatusSource[\"coverage\"]>;\n preview: ReturnType<LcmStatusSource[\"preview\"]>;\n coverageMap: ReturnType<LcmStatusSource[\"coverageMap\"]>;\n nodes: LcmDashboardNode[];\n offset: number;\n hasMore: boolean;\n}\n\nexport interface LcmNodeDetail {\n node: LcmDashboardNode;\n revisions: Array<{ revision: number; text: string; modelHash: string; createdAt: number }>;\n ancestors: string[];\n}\n\nexport interface LcmSourceEntry {\n payloadJson: string;\n content: string;\n role: string;\n createdAt: number;\n}\n\n/** Reads every ledger projection the LCM view needs in one pass so rendering never walks the ledger. */\nexport const readLcmSnapshot = (source: LcmStatusSource, offset: number): LcmViewSnapshot => {\n const nodes = source.nodes(LCM_NODE_PAGE, offset);\n return {\n report: source.report(),\n coverage: source.coverage(),\n preview: source.preview(),\n coverageMap: source.coverageMap(),\n nodes,\n offset,\n hasMore: nodes.length === LCM_NODE_PAGE,\n };\n};\n\nexport const lcmNodeDetail = (\n source: LcmStatusSource,\n nodeId: string,\n): LcmNodeDetail | undefined => {\n const detail = source.node(nodeId);\n if (!detail) return undefined;\n return {\n node: detail.node,\n revisions: [...detail.revisions].sort((left, right) => left.revision - right.revision),\n ancestors: detail.ancestors,\n };\n};\n\nconst formatBytes = (bytes: number): string => {\n if (!Number.isFinite(bytes) || bytes <= 0) return \"0 B\";\n if (bytes < 1_024) return `${Math.round(bytes)} B`;\n if (bytes < 1_048_576) return `${(bytes / 1_024).toFixed(1)} kB`;\n return `${(bytes / 1_048_576).toFixed(1)} MB`;\n};\n\nconst formatPercent = (value: number): string =>\n value > 0 && value < 1 ? `${value.toFixed(value < 0.1 ? 2 : 1)}%` : `${Math.round(value)}%`;\n\nconst isEmergency = (modelHash: string): boolean => modelHash === EMERGENCY_MODEL_HASH;\n\nconst originLabel = (modelHash: string): string => (isEmergency(modelHash) ? \"excerpt\" : \"model\");\n\nconst shortId = (value: string): string => (value.length > 10 ? `${value.slice(0, 10)}\u2026` : value);\n\nconst textBytes = (text: string | undefined): number =>\n text ? Buffer.byteLength(text, \"utf8\") : 0;\n\nexport const lcmUnavailableLine = (): string =>\n \"LCM ledger unavailable \u00B7 set compaction.engine to lcm and start a session to populate it\";\n\nconst bandRun = (theme: Theme, char: string, length: number): string => {\n const color = char === \"\u2588\" ? \"success\" : char === \"\u2593\" ? \"warning\" : \"dim\";\n return theme.fg(color, char.repeat(length));\n};\n\nconst coverageBand = (\n theme: Theme,\n map: LcmViewSnapshot[\"coverageMap\"],\n cells: number,\n): string => {\n if (cells <= 0) return \"\";\n if (map.length === 0) return theme.fg(\"dim\", \"\u00B7\".repeat(cells));\n let band = \"\";\n let runChar = \"\";\n let runLength = 0;\n for (let cell = 0; cell < cells; cell++) {\n const start = Math.min(map.length - 1, Math.floor((cell * map.length) / cells));\n const end = Math.min(map.length, Math.max(start + 1, Math.floor(((cell + 1) * map.length) / cells)));\n let covered = 0;\n for (let index = start; index < end; index++) {\n if (map[index]!.covered) covered++;\n }\n const char = covered === 0 ? \"\u2591\" : covered === end - start ? \"\u2588\" : \"\u2593\";\n if (char === runChar) {\n runLength++;\n continue;\n }\n if (runLength > 0) band += bandRun(theme, runChar, runLength);\n runChar = char;\n runLength = 1;\n }\n if (runLength > 0) band += bandRun(theme, runChar, runLength);\n return band;\n};\n\nexport const renderLcmCoverageLine = (\n theme: Theme,\n snapshot: LcmViewSnapshot,\n width: number,\n): string => {\n const { active, covered } = snapshot.coverage;\n const label = `${covered}/${active} covered ${formatPercent(active > 0 ? (covered / active) * 100 : 0)}`;\n const cells = Math.max(0, width - visibleWidth(label) - 1);\n const band = coverageBand(theme, snapshot.coverageMap, cells);\n return truncateToWidth(`${band} ${theme.fg(\"muted\", label)}`, width, \"\");\n};\n\nconst nodeRow = (node: LcmDashboardNode): string => {\n const indent = \" \".repeat(Math.min(node.depth, 8));\n const glyph = node.kind === \"condensed\" ? \"\u25C6\" : \"\u25C7\";\n return safeText(\n `${indent}${glyph} ${node.kind} ${originLabel(node.modelHash)} \u00B7 ${node.sources.length} src \u00B7 ${node.children.length} ch \u00B7 ${formatBytes(textBytes(node.text))} \u00B7 ${shortId(node.nodeId)}`,\n );\n};\n\nexport const renderLcmNodeLines = (\n theme: Theme,\n snapshot: LcmViewSnapshot,\n width: number,\n height: number,\n selectedIndex: number,\n): string[] => {\n const available = Math.max(1, height);\n const total = snapshot.nodes.length;\n const heading = `nodes ${total === 0 ? 0 : snapshot.offset + 1}-${snapshot.offset + total}${snapshot.hasMore ? \"+\" : \"\"}`;\n const lines = [theme.fg(\"accent\", truncateToWidth(heading, width, \"\"))];\n if (total === 0) {\n lines.push(theme.fg(\"dim\", \" (no summary nodes on the active branch yet)\"));\n while (lines.length < available) lines.push(\"\");\n return lines.slice(0, available);\n }\n const rows = Math.max(1, available - 1);\n const start = Math.max(\n 0,\n Math.min(selectedIndex - Math.floor(rows / 2), Math.max(0, total - rows)),\n );\n for (let index = start; index < Math.min(total, start + rows); index++) {\n const node = snapshot.nodes[index]!;\n const emergency = isEmergency(node.modelHash);\n let line = theme.fg(emergency ? \"warning\" : \"muted\", nodeRow(node));\n if (index === selectedIndex) line = theme.bg(\"selectedBg\", padToWidth(line, width));\n lines.push(truncateToWidth(line, width, \"\"));\n }\n while (lines.length < available) lines.push(\"\");\n return lines.slice(0, available);\n};\n\nexport const renderLcmPreviewLines = (\n theme: Theme,\n snapshot: LcmViewSnapshot,\n width: number,\n height: number,\n): string[] => {\n const available = Math.max(1, height);\n const preview = snapshot.preview;\n const complete =\n preview.activeSources > 0 &&\n preview.coveredSources / preview.activeSources >= COVERAGE_COMPLETE_RATIO;\n const ratio =\n complete && preview.sourceBytes > 0\n ? ` \u00B7 assembled text is ${formatPercent((preview.summaryBytes / preview.sourceBytes) * 100)} of the session payload it replaces`\n : \"\";\n const headline = `preview \u00B7 frontier holds ${preview.coveredSources}/${preview.activeSources} sources \u00B7 ${preview.nodes} nodes assemble to ${formatBytes(preview.summaryBytes)} \u00B7 session stored payload ${formatBytes(preview.sourceBytes)}${ratio}`;\n const lines = wrapPlainText(headline, width, 2).map((line) => theme.fg(\"accent\", line));\n const body = wrapPlainText(preview.text, width, Math.max(1, available - lines.length));\n for (const line of body) lines.push(theme.fg(\"dim\", line));\n if (body.length === 0) lines.push(theme.fg(\"dim\", \"(the frontier assembles no text yet)\"));\n while (lines.length < available) lines.push(\"\");\n return lines.slice(0, available);\n};\n\nconst revisionColumns = (\n theme: Theme,\n detail: LcmNodeDetail,\n width: number,\n rows: number,\n): string[] => {\n const current = detail.revisions[detail.revisions.length - 1];\n const previous = detail.revisions[detail.revisions.length - 2];\n if (!current) return [];\n if (!previous) {\n const lines = [theme.fg(\"accent\", `text \u00B7 current revision ${current.revision} \u00B7 ${originLabel(current.modelHash)}`)];\n for (const line of wrapPlainText(current.text, width, Math.max(1, rows - 1))) {\n lines.push(theme.fg(\"dim\", line));\n }\n return lines;\n }\n const label = (revision: { revision: number; modelHash: string }, name: string): string =>\n `${name} revision ${revision.revision} \u00B7 ${originLabel(revision.modelHash)}`;\n if (width < 60) {\n const lines = [theme.fg(\"accent\", label(current, \"current\"))];\n for (const line of wrapPlainText(current.text, width, Math.max(1, Math.floor((rows - 2) / 2)))) {\n lines.push(theme.fg(\"dim\", line));\n }\n lines.push(theme.fg(\"accent\", label(previous, \"previous\")));\n for (const line of wrapPlainText(previous.text, width, Math.max(1, Math.floor((rows - 2) / 2)))) {\n lines.push(theme.fg(\"muted\", line));\n }\n return lines;\n }\n const columnWidth = Math.floor((width - 1) / 2);\n const body = Math.max(1, rows - 1);\n const previousBody = wrapPlainText(previous.text, columnWidth, body);\n const currentBody = wrapPlainText(current.text, columnWidth, body);\n const lines = [\n `${padToWidth(theme.fg(\"accent\", label(previous, \"previous\")), columnWidth)}${theme.fg(\"borderMuted\", \"\u2502\")}${theme.fg(\"accent\", label(current, \"current\"))}`,\n ];\n for (let index = 0; index < body; index++) {\n const left = previousBody[index];\n const right = currentBody[index];\n if (left === undefined && right === undefined) break;\n lines.push(\n `${padToWidth(theme.fg(\"muted\", left ?? \"\"), columnWidth)}${theme.fg(\"borderMuted\", \"\u2502\")}${theme.fg(\"dim\", right ?? \"\")}`,\n );\n }\n return lines;\n};\n\nexport const renderLcmDetailLines = (\n theme: Theme,\n detail: LcmNodeDetail,\n sourceIndex: number,\n entry: LcmSourceEntry | undefined,\n width: number,\n height: number,\n): string[] => {\n const available = Math.max(1, height);\n const node = detail.node;\n const lines: string[] = [\n theme.fg(\n isEmergency(node.modelHash) ? \"warning\" : \"accent\",\n truncateToWidth(\n safeText(\n `${node.kind} \u00B7 ${originLabel(node.modelHash)} \u00B7 depth ${node.depth} \u00B7 ${node.state} \u00B7 ${formatClock(node.createdAt)} \u00B7 ${node.nodeId}`,\n ),\n width,\n \"\",\n ),\n ),\n theme.fg(\n \"dim\",\n truncateToWidth(safeText(`model hash ${node.modelHash} \u00B7 branch ${node.branch ?? \"none\"}`), width, \"\"),\n ),\n theme.fg(\n \"dim\",\n truncateToWidth(\n safeText(`ancestors ${detail.ancestors.length > 0 ? detail.ancestors.join(\" \u203A \") : \"none\"}`),\n width,\n \"\",\n ),\n ),\n theme.fg(\n \"dim\",\n truncateToWidth(\n safeText(\n `children (${node.children.length}) ${node.children.length > 0 ? node.children.map(shortId).join(\" \") : \"none\"}`,\n ),\n width,\n \"\",\n ),\n ),\n theme.fg(\"accent\", truncateToWidth(`sources (${node.sources.length})`, width, \"\")),\n ];\n const sourceRows = Math.min(node.sources.length, Math.max(1, Math.floor(available / 4)));\n const sourceStart = Math.max(\n 0,\n Math.min(sourceIndex - Math.floor(sourceRows / 2), Math.max(0, node.sources.length - sourceRows)),\n );\n for (let index = sourceStart; index < Math.min(node.sources.length, sourceStart + sourceRows); index++) {\n const source = node.sources[index]!;\n const text = ` ${source.sessionId}/${source.entryId}@${source.revision}`;\n const line =\n index === sourceIndex\n ? theme.bg(\"selectedBg\", padToWidth(theme.fg(\"muted\", text), width))\n : theme.fg(\"muted\", text);\n lines.push(truncateToWidth(line, width, \"\"));\n }\n if (node.sources.length === 0) lines.push(theme.fg(\"dim\", \" (no sources)\"));\n if (entry) {\n lines.push(\n theme.fg(\n \"accent\",\n truncateToWidth(\n safeText(`raw entry \u00B7 ${entry.role} \u00B7 ${formatClock(entry.createdAt)} \u00B7 ${formatBytes(Buffer.byteLength(entry.payloadJson, \"utf8\"))} stored`),\n width,\n \"\",\n ),\n ),\n );\n for (const line of wrapPlainText(entry.content, width, Math.max(1, Math.floor(available / 4)))) {\n lines.push(theme.fg(\"dim\", line));\n }\n }\n const remaining = Math.max(1, available - lines.length);\n for (const line of revisionColumns(theme, detail, width, remaining)) lines.push(line);\n while (lines.length < available) lines.push(\"\");\n return lines.slice(0, available);\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["lines"]
7
+ }