pi-mega-compact 0.20.21 → 0.20.23

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 (95) hide show
  1. package/dist/extensions/dashboard-server/resolve-snapshot.js +42 -28
  2. package/dist/extensions/dashboard-server/routes-setup.js +4 -1
  3. package/dist/extensions/dashboard-server/routes-vector-cortex-crystals.js +11 -3
  4. package/dist/extensions/dashboard-server/routes-vector-cortex-diagnostics.js +7 -2
  5. package/dist/extensions/dashboard-server/routes-vector-cortex-economics.js +1 -0
  6. package/dist/extensions/dashboard-server/routes-vector-cortex-heal.js +18 -6
  7. package/dist/extensions/dashboard-server/routes-vector-cortex-policy.js +1 -0
  8. package/dist/extensions/dashboard-server/routes-vector-cortex-reconstruct.js +10 -3
  9. package/dist/extensions/dashboard-server/routes-vector-cortex-repair.js +13 -5
  10. package/dist/extensions/dashboard-server/routes-vector-cortex-shards.js +12 -4
  11. package/dist/extensions/dashboard-server/vc-event-counts.js +63 -0
  12. package/dist/extensions/mega-events/context-handler/afterCompact.js +34 -0
  13. package/dist/extensions/mega-events/context-handler/pipelineRun.js +33 -0
  14. package/dist/extensions/mega-runtime/dashboard-snapshot.js +9 -6
  15. package/dist/extensions/mega-runtime/runtime-snapshot.js +2 -0
  16. package/dist/extensions/mega-runtime/vc-observer.js +98 -0
  17. package/dist/src/vector-cortex/platform/_cross-language-fixture.js +57 -0
  18. package/dist/vector-cortex/platform/_cross-language-fixture.js +57 -0
  19. package/extensions/dashboard-client/dist/assets/{AreaChart-BkfB-LSQ.js → AreaChart-BzEedilo.js} +2 -2
  20. package/extensions/dashboard-client/dist/assets/{AreaChart-BkfB-LSQ.js.map → AreaChart-BzEedilo.js.map} +1 -1
  21. package/extensions/dashboard-client/dist/assets/{BarChart-Cs1kogko.js → BarChart-CzAVg1_J.js} +2 -2
  22. package/extensions/dashboard-client/dist/assets/{BarChart-Cs1kogko.js.map → BarChart-CzAVg1_J.js.map} +1 -1
  23. package/extensions/dashboard-client/dist/assets/{CacheTab-BZgaguGr.js → CacheTab-D2-rzTuX.js} +2 -2
  24. package/extensions/dashboard-client/dist/assets/{CacheTab-BZgaguGr.js.map → CacheTab-D2-rzTuX.js.map} +1 -1
  25. package/extensions/dashboard-client/dist/assets/{EventsTab-BFbkI_MO.js → EventsTab-DB7g1Szy.js} +2 -2
  26. package/extensions/dashboard-client/dist/assets/{EventsTab-BFbkI_MO.js.map → EventsTab-DB7g1Szy.js.map} +1 -1
  27. package/extensions/dashboard-client/dist/assets/{HealthTab-CvlOENCX.js → HealthTab-Cvkmi-R3.js} +2 -2
  28. package/extensions/dashboard-client/dist/assets/{HealthTab-CvlOENCX.js.map → HealthTab-Cvkmi-R3.js.map} +1 -1
  29. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-CtBuz2qL.js → MaintenanceTab-g_udcOO7.js} +2 -2
  30. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-CtBuz2qL.js.map → MaintenanceTab-g_udcOO7.js.map} +1 -1
  31. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-K4775S4d.js → MemoryMapTab-DAjBaf8P.js} +2 -2
  32. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-K4775S4d.js.map → MemoryMapTab-DAjBaf8P.js.map} +1 -1
  33. package/extensions/dashboard-client/dist/assets/{MetricsTab-DVGcFInz.js → MetricsTab-13dYYocB.js} +2 -2
  34. package/extensions/dashboard-client/dist/assets/{MetricsTab-DVGcFInz.js.map → MetricsTab-13dYYocB.js.map} +1 -1
  35. package/extensions/dashboard-client/dist/assets/{OverviewTab-4LmW5ZCl.js → OverviewTab-CLpCyLvx.js} +2 -2
  36. package/extensions/dashboard-client/dist/assets/{OverviewTab-4LmW5ZCl.js.map → OverviewTab-CLpCyLvx.js.map} +1 -1
  37. package/extensions/dashboard-client/dist/assets/{ReposTab-StebchgQ.js → ReposTab-EdAqUrwG.js} +2 -2
  38. package/extensions/dashboard-client/dist/assets/{ReposTab-StebchgQ.js.map → ReposTab-EdAqUrwG.js.map} +1 -1
  39. package/extensions/dashboard-client/dist/assets/{SessionsTab-C3D_XAkX.js → SessionsTab-C21ZuOL_.js} +2 -2
  40. package/extensions/dashboard-client/dist/assets/{SessionsTab-C3D_XAkX.js.map → SessionsTab-C21ZuOL_.js.map} +1 -1
  41. package/extensions/dashboard-client/dist/assets/SetupTab-CP7lE3L_.js +2 -0
  42. package/extensions/dashboard-client/dist/assets/SetupTab-CP7lE3L_.js.map +1 -0
  43. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CTPi_AAW.js → TimeSavedCard-DZ3QR8qt.js} +2 -2
  44. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CTPi_AAW.js.map → TimeSavedCard-DZ3QR8qt.js.map} +1 -1
  45. package/extensions/dashboard-client/dist/assets/{TurnsTab-DSOGcY5Q.js → TurnsTab-CNchE5rD.js} +2 -2
  46. package/extensions/dashboard-client/dist/assets/{TurnsTab-DSOGcY5Q.js.map → TurnsTab-CNchE5rD.js.map} +1 -1
  47. package/extensions/dashboard-client/dist/assets/{VectorCortexTab-OMW8_RFf.js → VectorCortexTab-B3WuPeyn.js} +2 -2
  48. package/extensions/dashboard-client/dist/assets/{VectorCortexTab-OMW8_RFf.js.map → VectorCortexTab-B3WuPeyn.js.map} +1 -1
  49. package/extensions/dashboard-client/dist/assets/{WikiTab-Db-qFDdg.js → WikiTab-BIe5Z9Nc.js} +2 -2
  50. package/extensions/dashboard-client/dist/assets/{WikiTab-Db-qFDdg.js.map → WikiTab-BIe5Z9Nc.js.map} +1 -1
  51. package/extensions/dashboard-client/dist/assets/{button-BF4UgBAD.js → button-BrVreSt5.js} +2 -2
  52. package/extensions/dashboard-client/dist/assets/{button-BF4UgBAD.js.map → button-BrVreSt5.js.map} +1 -1
  53. package/extensions/dashboard-client/dist/assets/{card-XmXoYQqB.js → card-D9F4wbqs.js} +2 -2
  54. package/extensions/dashboard-client/dist/assets/{card-XmXoYQqB.js.map → card-D9F4wbqs.js.map} +1 -1
  55. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-Be8hM1aU.js → generateCategoricalChart-mkdzCnMP.js} +2 -2
  56. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-Be8hM1aU.js.map → generateCategoricalChart-mkdzCnMP.js.map} +1 -1
  57. package/extensions/dashboard-client/dist/assets/{index-NXDgILxv.js → index-CtlmOlj1.js} +3 -3
  58. package/extensions/dashboard-client/dist/assets/{index-NXDgILxv.js.map → index-CtlmOlj1.js.map} +1 -1
  59. package/extensions/dashboard-client/dist/assets/{switch-kUZCrbia.js → switch-BXmp5iwA.js} +2 -2
  60. package/extensions/dashboard-client/dist/assets/{switch-kUZCrbia.js.map → switch-BXmp5iwA.js.map} +1 -1
  61. package/extensions/dashboard-client/dist/assets/{toggle-DEe5mCwF.js → toggle-BgawNwW9.js} +2 -2
  62. package/extensions/dashboard-client/dist/assets/{toggle-DEe5mCwF.js.map → toggle-BgawNwW9.js.map} +1 -1
  63. package/extensions/dashboard-client/dist/assets/{useSSE-BlCyLqge.js → useSSE-DZKX73Ea.js} +2 -2
  64. package/extensions/dashboard-client/dist/assets/{useSSE-BlCyLqge.js.map → useSSE-DZKX73Ea.js.map} +1 -1
  65. package/extensions/dashboard-client/dist/index.html +1 -1
  66. package/extensions/dashboard-client/src/tabs/SetupTab/CustomEndpointSection.tsx +65 -0
  67. package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetup.tsx +19 -108
  68. package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetupStyles.ts +69 -0
  69. package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +5 -3
  70. package/extensions/dashboard-server/api-contracts/setup.ts +4 -3
  71. package/extensions/dashboard-server/api-contracts/vector-cortex-cache.ts +5 -0
  72. package/extensions/dashboard-server/api-contracts/vector-cortex-diagnostics.ts +2 -0
  73. package/extensions/dashboard-server/api-contracts/vector-cortex-economics.ts +2 -0
  74. package/extensions/dashboard-server/api-contracts/vector-cortex-policy.ts +2 -0
  75. package/extensions/dashboard-server/resolve-snapshot.ts +42 -28
  76. package/extensions/dashboard-server/routes-setup.ts +3 -1
  77. package/extensions/dashboard-server/routes-vector-cortex-crystals.ts +12 -3
  78. package/extensions/dashboard-server/routes-vector-cortex-diagnostics.ts +8 -2
  79. package/extensions/dashboard-server/routes-vector-cortex-economics.ts +1 -0
  80. package/extensions/dashboard-server/routes-vector-cortex-heal.ts +19 -6
  81. package/extensions/dashboard-server/routes-vector-cortex-policy.ts +1 -0
  82. package/extensions/dashboard-server/routes-vector-cortex-reconstruct.ts +11 -3
  83. package/extensions/dashboard-server/routes-vector-cortex-repair.ts +14 -5
  84. package/extensions/dashboard-server/routes-vector-cortex-shards.ts +13 -4
  85. package/extensions/dashboard-server/vc-event-counts.ts +67 -0
  86. package/extensions/mega-dashboard.ts +2 -0
  87. package/extensions/mega-events/context-handler/afterCompact.ts +46 -0
  88. package/extensions/mega-events/context-handler/pipelineRun.ts +39 -0
  89. package/extensions/mega-runtime/dashboard-snapshot.ts +12 -6
  90. package/extensions/mega-runtime/runtime-snapshot.ts +6 -0
  91. package/extensions/mega-runtime/vc-observer.ts +120 -0
  92. package/package.json +1 -1
  93. package/src/vector-cortex/platform/_cross-language-fixture.ts +83 -0
  94. package/extensions/dashboard-client/dist/assets/SetupTab-BTBGyppF.js +0 -2
  95. package/extensions/dashboard-client/dist/assets/SetupTab-BTBGyppF.js.map +0 -1
@@ -14,69 +14,8 @@ import type { SetupStatusResponse, SetupDetectResponse, SetupConfigureResponse }
14
14
  import { fetchSetupStatus, fetchSetupDetect, configureEmbedder } from "../../api/client";
15
15
  import EmbedderHealthCard from "./EmbedderHealthCard";
16
16
  import SettingsPanel from "./SettingsPanel";
17
-
18
- const styles: Record<string, React.CSSProperties> = {
19
- container: {
20
- padding: "1rem",
21
- maxWidth: "720px",
22
- margin: "0 auto",
23
- fontFamily: "system-ui, sans-serif",
24
- color: "#e0e0e0",
25
- },
26
- section: {
27
- background: "#1a1a2e",
28
- borderRadius: "8px",
29
- padding: "1rem",
30
- marginBottom: "1rem",
31
- border: "1px solid #2a2a4e",
32
- },
33
- sectionTitle: {
34
- fontSize: "1.1rem",
35
- fontWeight: 700,
36
- marginTop: 0,
37
- marginBottom: "0.75rem",
38
- color: "#e0e0e0",
39
- borderBottom: "1px solid #333",
40
- paddingBottom: "0.5rem",
41
- },
42
- label: { fontWeight: 600, color: "#a0a0c0", marginRight: "0.5rem" },
43
- value: { color: "#e0e0e0" },
44
- row: { marginBottom: "0.4rem", fontSize: "0.9rem" },
45
- warning: {
46
- background: "#3a2a00",
47
- border: "1px solid #665500",
48
- borderRadius: "8px",
49
- padding: "0.75rem",
50
- marginTop: "0.5rem",
51
- color: "#ffcc00",
52
- fontSize: "0.85rem",
53
- },
54
- badge: {
55
- display: "inline-block",
56
- padding: "0.15rem 0.5rem",
57
- borderRadius: "4px",
58
- fontSize: "0.8rem",
59
- fontWeight: 600,
60
- marginLeft: "0.5rem",
61
- },
62
- detectRow: {
63
- display: "flex",
64
- justifyContent: "space-between",
65
- alignItems: "center",
66
- padding: "0.5rem 0",
67
- borderBottom: "1px solid #2a2a4e",
68
- },
69
- button: {
70
- background: "#3a5a9f",
71
- color: "#fff",
72
- border: "none",
73
- borderRadius: "6px",
74
- padding: "0.5rem 1rem",
75
- cursor: "pointer",
76
- fontSize: "0.9rem",
77
- fontWeight: 600,
78
- },
79
- };
17
+ import CustomEndpointSection from "./CustomEndpointSection";
18
+ import { styles } from "./EmbedderSetupStyles";
80
19
 
81
20
  export default function EmbedderSetup(): React.ReactElement {
82
21
  const [status, setStatus] = useState<SetupStatusResponse | null>(null);
@@ -97,7 +36,7 @@ export default function EmbedderSetup(): React.ReactElement {
97
36
  );
98
37
  }, []);
99
38
 
100
- const applyEmbedder = useCallback((embedder: "ollama" | "llama" | "trigram" | "custom", url?: string) => {
39
+ const applyEmbedder = useCallback((embedder: "ollama" | "llama" | "trigram" | "custom" | "onnx", url?: string) => {
101
40
  setConfiguring(embedder);
102
41
  setConfigError(null);
103
42
  setConfigResult(null);
@@ -368,6 +307,13 @@ export default function EmbedderSetup(): React.ReactElement {
368
307
  >
369
308
  {configuring === "llama" ? "Writing..." : "Use llama.cpp"}
370
309
  </button>
310
+ <button
311
+ style={{ ...styles.button, opacity: detect.onnx?.installed ? 1 : 0.4 }}
312
+ onClick={() => applyEmbedder("onnx")}
313
+ disabled={!detect.onnx?.installed || configuring !== null}
314
+ >
315
+ {configuring === "onnx" ? "Writing..." : "Use ONNX"}
316
+ </button>
371
317
  <button
372
318
  style={{ ...styles.button, background: "#444" }}
373
319
  onClick={() => applyEmbedder("trigram")}
@@ -393,47 +339,12 @@ export default function EmbedderSetup(): React.ReactElement {
393
339
  </div>
394
340
 
395
341
  {/* Custom (remote) embedder — third-party / hosted endpoint */}
396
- <div style={styles.section}>
397
- <h3 style={styles.sectionTitle}>Custom Endpoint (remote / third-party)</h3>
398
- <p style={{ fontSize: "0.85rem", color: "#a0a0c0", marginTop: 0 }}>
399
- Point at any OpenAI-compatible embeddings API or hosted endpoint.
400
- This opts in to a non-loopback connection (sets{" "}
401
- <code>MEGACOMPACT_ALLOW_REMOTE_EMBEDDER=1</code>) — your prompts'
402
- embedding requests will be sent to the URL you enter. Default is
403
- loopback-only.
404
- </p>
405
- <div style={{ display: "flex", gap: "0.5rem", flexWrap: "wrap", alignItems: "center" }}>
406
- <input
407
- type="url"
408
- placeholder="https://api.example.com/v1/embeddings"
409
- value={customUrl}
410
- onChange={(e) => setCustomUrl(e.target.value)}
411
- style={{
412
- flex: "1 1 300px",
413
- background: "#12122a",
414
- color: "#e0e0e0",
415
- border: "1px solid #2a2a4e",
416
- borderRadius: "6px",
417
- padding: "0.4rem 0.6rem",
418
- fontSize: "0.85rem",
419
- fontFamily: "monospace",
420
- }}
421
- />
422
- <button
423
- style={{ ...styles.button, opacity: customUrl ? 1 : 0.4 }}
424
- onClick={() => applyEmbedder("custom", customUrl)}
425
- disabled={!customUrl || configuring !== null}
426
- >
427
- {configuring === "custom" ? "Writing..." : "Use Custom URL"}
428
- </button>
429
- </div>
430
- <div style={styles.warning}>
431
- <strong>Heads up:</strong> a remote endpoint receives the text you embed
432
- (it does NOT receive your full conversation — only the strings passed to
433
- <code> embed()</code> for recall/dedup). Verify the endpoint's privacy
434
- policy before use.
435
- </div>
436
- </div>
342
+ <CustomEndpointSection
343
+ customUrl={customUrl}
344
+ setCustomUrl={setCustomUrl}
345
+ applyEmbedder={applyEmbedder}
346
+ configuring={configuring}
347
+ />
437
348
 
438
349
  {/* Help Section */}
439
350
  <div style={styles.section}>
@@ -458,9 +369,9 @@ export default function EmbedderSetup(): React.ReactElement {
458
369
  the URL accordingly.
459
370
  </li>
460
371
  <li>
461
- <strong>ONNX Runtime:</strong> Install{" "}
462
- <code>onnxruntime-node</code> in the project root. Not yet
463
- integrated see docs for manual setup.
372
+ <strong>ONNX Runtime:</strong> Run a local text-embeddings
373
+ server (e.g. TEI) and click <strong>Use ONNX</strong> above.
374
+ Default URL: <code>http://localhost:8081/v1/embeddings</code>.
464
375
  </li>
465
376
  </ul>
466
377
  </div>
@@ -0,0 +1,69 @@
1
+ /**
2
+ * SetupTab/EmbedderSetupStyles.ts — extracted styles for EmbedderSetup.
3
+ *
4
+ * Split from EmbedderSetup.tsx to respect the extensions/ 400-line soft limit.
5
+ */
6
+ import type React from "react";
7
+
8
+ export const styles: Record<string, React.CSSProperties> = {
9
+ container: {
10
+ padding: "1rem",
11
+ maxWidth: "720px",
12
+ margin: "0 auto",
13
+ fontFamily: "system-ui, sans-serif",
14
+ color: "#e0e0e0",
15
+ },
16
+ section: {
17
+ background: "#1a1a2e",
18
+ borderRadius: "8px",
19
+ padding: "1rem",
20
+ marginBottom: "1rem",
21
+ border: "1px solid #2a2a4e",
22
+ },
23
+ sectionTitle: {
24
+ fontSize: "1.1rem",
25
+ fontWeight: 700,
26
+ marginTop: 0,
27
+ marginBottom: "0.75rem",
28
+ color: "#e0e0e0",
29
+ borderBottom: "1px solid #333",
30
+ paddingBottom: "0.5rem",
31
+ },
32
+ label: { fontWeight: 600, color: "#a0a0c0", marginRight: "0.5rem" },
33
+ value: { color: "#e0e0e0" },
34
+ row: { marginBottom: "0.4rem", fontSize: "0.9rem" },
35
+ warning: {
36
+ background: "#3a2a00",
37
+ border: "1px solid #665500",
38
+ borderRadius: "8px",
39
+ padding: "0.75rem",
40
+ marginTop: "0.5rem",
41
+ color: "#ffcc00",
42
+ fontSize: "0.85rem",
43
+ },
44
+ badge: {
45
+ display: "inline-block",
46
+ padding: "0.15rem 0.5rem",
47
+ borderRadius: "4px",
48
+ fontSize: "0.8rem",
49
+ fontWeight: 600,
50
+ marginLeft: "0.5rem",
51
+ },
52
+ detectRow: {
53
+ display: "flex",
54
+ justifyContent: "space-between",
55
+ alignItems: "center",
56
+ padding: "0.5rem 0",
57
+ borderBottom: "1px solid #2a2a4e",
58
+ },
59
+ button: {
60
+ background: "#3a5a9f",
61
+ color: "#fff",
62
+ border: "none",
63
+ borderRadius: "6px",
64
+ padding: "0.5rem 1rem",
65
+ cursor: "pointer",
66
+ fontSize: "0.9rem",
67
+ fontWeight: 600,
68
+ },
69
+ };
@@ -77,10 +77,12 @@ export default function VectorCortexTab(): React.ReactElement {
77
77
  <div className="flex flex-col gap-4">
78
78
  <div className="flex items-center gap-2">
79
79
  <h2 className="text-lg font-semibold">Vector Cortex Evaluation</h2>
80
- {data.enabled ? (
81
- <Badge variant="warning">OBSERVER PENDING (A)</Badge>
82
- ) : (
80
+ {!data.enabled ? (
83
81
  <Badge variant="danger">MODE C (OFF)</Badge>
82
+ ) : data.samples === 0 ? (
83
+ <Badge variant="warning">OBSERVER (A) — NO SAMPLES YET</Badge>
84
+ ) : (
85
+ <Badge variant="success">OBSERVER (A) — {data.samples} SAMPLES</Badge>
84
86
  )}
85
87
  </div>
86
88
 
@@ -67,9 +67,10 @@ export interface SetupDetectResponse {
67
67
  export interface SetupConfigureRequest {
68
68
  /** Which embedder to configure. "trigram" clears the URL (uses built-in).
69
69
  * "custom" writes a user-supplied URL and opts in to non-loopback endpoints
70
- * (sets MEGACOMPACT_ALLOW_REMOTE_EMBEDDER=1) for third-party / hosted APIs. */
71
- readonly embedder: "ollama" | "llama" | "trigram" | "custom";
72
- /** Override URL (required for "custom"; optional default for ollama/llama). */
70
+ * (sets MEGACOMPACT_ALLOW_REMOTE_EMBEDDER=1) for third-party / hosted APIs.
71
+ * "onnx" points at a local ONNX text-embeddings-inference server. */
72
+ readonly embedder: "ollama" | "llama" | "trigram" | "custom" | "onnx";
73
+ /** Override URL (required for "custom"; optional defaults for ollama/llama/onnx). */
73
74
  readonly url?: string;
74
75
  }
75
76
 
@@ -50,4 +50,9 @@ export interface VectorCortexCrystalsView {
50
50
  readonly lastFailure: string | null;
51
51
  /** ISO timestamp of the snapshot. */
52
52
  readonly updatedAt: string;
53
+ /**
54
+ * Present when the underlying subsystem is not fully wired yet, explaining
55
+ * why emit-only counters are reported instead of live cache-serve integration.
56
+ */
57
+ readonly deferredReason?: string;
53
58
  }
@@ -69,6 +69,8 @@ export interface VectorCortexDiagnosticsView {
69
69
  readonly serveBlocked: number;
70
70
  /** Observable cache-breaker state (a state name, not a payload). */
71
71
  readonly breakerState: string;
72
+ /** Present when the miss-classifier is not yet wired, with a reason. */
73
+ readonly deferredReason?: string;
72
74
  /** Last diagnostics rejection reason (a CACHE or M5 code), or null. */
73
75
  readonly lastFailure: string | null;
74
76
  /** ISO timestamp of the snapshot. */
@@ -44,4 +44,6 @@ export interface VectorCortexEconomicsView {
44
44
  readonly lastFailure: string | null;
45
45
  /** ISO timestamp of the snapshot. */
46
46
  readonly updatedAt: string;
47
+ /** Present when the economic aggregate is not yet computed, with a reason. */
48
+ readonly deferredReason?: string;
47
49
  }
@@ -33,4 +33,6 @@ export interface VectorCortexPolicyView {
33
33
  readonly lastFailure: string | null;
34
34
  /** ISO timestamp of the snapshot. */
35
35
  readonly updatedAt: string;
36
+ /** Present when the shadow controller is not yet instantiated, with a reason. */
37
+ readonly deferredReason?: string;
36
38
  }
@@ -8,16 +8,14 @@
8
8
  * Resolution order (the launch dir is the OWNer of this dashboard):
9
9
  * 1. The launch stateDir's OWN dashboard.json — the pi process that launched
10
10
  * this dashboard server is the session you are coding in, so its snapshot
11
- * is "this session" by definition. This must win over any other repo
12
- * regardless of last_seen freshness; otherwise a more-recently-active
13
- * OTHER repo steals the "this session" slot and your actual session gets
14
- * demoted to an "other" gauge, producing the exact duplicate-gauge bug
15
- * (this session + pi-<launchrepo> both showing the same active session
16
- * split across two boxes).
17
- * 2. Most recently seen OTHER repo (by last_seen in repo_registry) whose
18
- * dashboard.json exists and has a non-null updatedAt — fallback for when
19
- * the launch dir has no live snapshot yet (e.g. dashboard launched before
20
- * any compaction wrote dashboard.json).
11
+ * is "this session" by definition. It must be fresh (updatedAt within
12
+ * STALE_MS) to win; otherwise the launch dir's pi process has exited or
13
+ * stopped snapshotting, and showing its stale data as "this session" is
14
+ * misleading. When stale, fall through to the most-recently-active repo.
15
+ * 2. Most recently seen repo (by last_seen in repo_registry) whose
16
+ * dashboard.json exists and has a non-null updatedAt — this includes the
17
+ * launch dir via the registry, so an exited-but-recent launch session
18
+ * still appears.
21
19
  * 3. The static launch stateDir's dashboard.json (original behavior).
22
20
  */
23
21
 
@@ -34,6 +32,19 @@ export interface ResolvedSnapshot {
34
32
  stateDir: string;
35
33
  }
36
34
 
35
+ /** Snapshots older than this are stale — the owning pi session has exited or
36
+ * stopped snapshotting. 5 minutes covers the slowest possible context event
37
+ * cadence + debounce + snapshot throttle. */
38
+ const STALE_MS = 5 * 60 * 1000;
39
+
40
+ /** Age of a snapshot's updatedAt in ms. Returns Infinity for invalid dates. */
41
+ function snapshotAgeMs(updatedAt: string | null | undefined): number {
42
+ if (!updatedAt) return Infinity;
43
+ const t = Date.parse(updatedAt);
44
+ if (Number.isNaN(t)) return Infinity;
45
+ return Date.now() - t;
46
+ }
47
+
37
48
  const require = createRequire(import.meta.url);
38
49
 
39
50
  interface RepoRegistryRow {
@@ -42,12 +53,14 @@ interface RepoRegistryRow {
42
53
  }
43
54
 
44
55
  /**
45
- * Find the most recently active OTHER repo's stateDir (excluding the launch
46
- * dir, which is handled by the caller) by scanning the repo registry for the
47
- * repo with the highest last_seen whose dashboard.json exists and has a
48
- * non-null updatedAt. Returns null if no suitable repo is found.
56
+ * Find the most recently active repo's stateDir by scanning the repo registry
57
+ * for the repo with the highest last_seen whose dashboard.json exists and has
58
+ * a non-null updatedAt. Unlike the old `mostRecentOtherRepoStateDir`, this
59
+ * does NOT exclude the launch dir when the launch dir's snapshot is stale
60
+ * but its registry entry has a recent last_seen (e.g. session just exited),
61
+ * it should still be eligible.
49
62
  */
50
- function mostRecentOtherRepoStateDir(launchStateDir: string): string | null {
63
+ function mostRecentActiveRepoStateDir(_launchStateDir: string): string | null {
51
64
  const indexPath = join(getIndexDir(), "index.sqlite");
52
65
  if (!existsSync(indexPath)) return null;
53
66
  let db;
@@ -59,10 +72,9 @@ function mostRecentOtherRepoStateDir(launchStateDir: string): string | null {
59
72
  .prepare(
60
73
  `SELECT state_dir, last_seen FROM repo_registry
61
74
  WHERE state_dir IS NOT NULL AND last_seen IS NOT NULL
62
- AND state_dir != @launch
63
75
  ORDER BY last_seen DESC`,
64
76
  )
65
- .all({ launch: launchStateDir }) as unknown as RepoRegistryRow[];
77
+ .all() as unknown as RepoRegistryRow[];
66
78
  for (const r of rows) {
67
79
  const dashPath = join(r.state_dir, "dashboard.json");
68
80
  if (!existsSync(dashPath)) continue;
@@ -84,27 +96,29 @@ function mostRecentOtherRepoStateDir(launchStateDir: string): string | null {
84
96
  }
85
97
 
86
98
  /**
87
- * Resolve the best snapshot to serve. Tries the most recently active repo's
88
- * dashboard.json first, then falls back to the static launch path.
99
+ * Resolve the best snapshot to serve. The launch dir wins when its snapshot is
100
+ * fresh; when stale (or missing) the most recently active repo wins instead.
89
101
  */
90
102
  export function resolveSnapshot(
91
103
  staticSnapshotPath: string,
92
104
  staticStateDir: string,
93
105
  ): ResolvedSnapshot {
94
- // 1. The launch dir's OWN snapshot is "this session" — the pi process that
95
- // launched this dashboard is the session you are coding in. It wins over
96
- // any other repo regardless of last_seen, so a more-recently-active OTHER
97
- // repo can't steal the "this session" slot and demote your actual session
98
- // to a duplicate "other" gauge.
106
+ // 1. The launch dir's OWN snapshot is "this session" — but only when it's
107
+ // fresh (updated within STALE_MS). A stale launch-dir snapshot means
108
+ // the pi process that owned it has exited or stopped snapshotting; serving
109
+ // its frozen data as "this session" is misleading. Fall through to the
110
+ // most-recently-active repo so the user sees the session that is actually
111
+ // running.
99
112
  if (existsSync(staticSnapshotPath)) {
100
113
  const launchSnap = readSnapshot(staticSnapshotPath);
101
- if (launchSnap.updatedAt) {
114
+ if (launchSnap.updatedAt && snapshotAgeMs(launchSnap.updatedAt) < STALE_MS) {
102
115
  return { snapshot: launchSnap, stateDir: staticStateDir };
103
116
  }
104
117
  }
105
- // 2. Fall back to the most recently active OTHER repo (launch dir had no
106
- // live snapshot yet).
107
- const activeDir = mostRecentOtherRepoStateDir(staticStateDir);
118
+ // 2. Fall back to the most recently active OTHER repo (launch dir stale or
119
+ // had no live snapshot yet). The registry includes the launch dir too,
120
+ // so a recently-exited launch session can still appear.
121
+ const activeDir = mostRecentActiveRepoStateDir(staticStateDir);
108
122
  if (activeDir) {
109
123
  const activePath = join(activeDir, "dashboard.json");
110
124
  const snap = readSnapshot(activePath);
@@ -214,6 +214,7 @@ export function handleSetupDetect(
214
214
 
215
215
  const OLLAMA_DEFAULT_URL = "http://localhost:11434/api/embeddings"; // guardrails-allow PREVENT-PI-004: localhost-only config string, not a runtime fetch
216
216
  const LLAMA_DEFAULT_URL = "http://localhost:8080/v1/embeddings"; // guardrails-allow PREVENT-PI-004: localhost-only config string, not a runtime fetch
217
+ const ONNX_DEFAULT_URL = "http://localhost:8081/v1/embeddings"; // guardrails-allow PREVENT-PI-004: localhost-only config string, not a runtime fetch — TEI / ONNX embedding server
217
218
 
218
219
  function readJsonBody(
219
220
  req: IncomingMessage,
@@ -265,7 +266,7 @@ export function handleSetupConfigure(
265
266
  }
266
267
  const body = parsed.value as unknown as SetupConfigureRequest;
267
268
  const embedder = body.embedder;
268
- if (embedder !== "ollama" && embedder !== "llama" && embedder !== "trigram" && embedder !== "custom") {
269
+ if (embedder !== "ollama" && embedder !== "llama" && embedder !== "trigram" && embedder !== "custom" && embedder !== "onnx") {
269
270
  res.writeHead(400, { "Content-Type": "application/json" });
270
271
  res.end(JSON.stringify({ error: "invalid_embedder" }));
271
272
  return;
@@ -275,6 +276,7 @@ export function handleSetupConfigure(
275
276
  let allowRemote = false;
276
277
  if (embedder === "ollama") resolvedUrl = typeof url === "string" && url ? url : OLLAMA_DEFAULT_URL;
277
278
  else if (embedder === "llama") resolvedUrl = typeof url === "string" && url ? url : LLAMA_DEFAULT_URL;
279
+ else if (embedder === "onnx") resolvedUrl = typeof url === "string" && url ? url : ONNX_DEFAULT_URL;
278
280
  else if (embedder === "custom") {
279
281
  // Third-party / remote endpoint. Requires a URL; opts in to the
280
282
  // non-loopback allowlist so embeddingConfigFromEnv() accepts it.
@@ -28,8 +28,15 @@ import type { IncomingMessage, ServerResponse } from "node:http";
28
28
  import type { RouteContext } from "./routes-core.js";
29
29
  import { VC7A_ENABLED } from "../../src/config.js";
30
30
  import { sendJson } from "./routes-vector-cortex-shared.js";
31
+ import { countVcEvents, vcCount } from "./vc-event-counts.js";
31
32
  import type { VectorCortexCrystalsView } from "./api-contracts/vector-cortex-cache.js";
32
33
 
34
+ // Actual events emitted by src/vector-cortex/cache/crystal-emit.ts.
35
+ const CRYSTAL_EVENTS = [
36
+ "vector_cortex_crystal_written",
37
+ "vector_cortex_crystal_collision",
38
+ ] as const;
39
+
33
40
  /**
34
41
  * Reader-only GET /api/vector-cortex/cache-crystals (VC7A).
35
42
  *
@@ -39,7 +46,7 @@ import type { VectorCortexCrystalsView } from "./api-contracts/vector-cortex-cac
39
46
  export function handleVectorCortexCrystals(
40
47
  req: IncomingMessage,
41
48
  res: ServerResponse,
42
- _ctx: RouteContext,
49
+ ctx: RouteContext,
43
50
  ): boolean {
44
51
  const url = req.url ?? "";
45
52
  const path = url.split("?")[0] ?? url;
@@ -50,6 +57,7 @@ export function handleVectorCortexCrystals(
50
57
  }
51
58
 
52
59
  const enabled = VC7A_ENABLED();
60
+ const counts = countVcEvents(ctx.stateDir, CRYSTAL_EVENTS);
53
61
  // Flag-off routes to mode C: with VC7A off nothing is served from the crystal
54
62
  // cache, which is exactly the spec's "cache bypass" outcome. Reporting A (hit)
55
63
  // or B (fresh render forced by a miss) would imply a cache path that is not
@@ -58,16 +66,17 @@ export function handleVectorCortexCrystals(
58
66
  const body: VectorCortexCrystalsView = {
59
67
  enabled,
60
68
  mode,
61
- crystalCount: 0,
69
+ crystalCount: vcCount(counts, "vector_cortex_crystal_written"),
62
70
  totalBytes: 0,
63
71
  hits: 0,
64
72
  misses: 0,
65
73
  hitBytes: 0,
66
74
  writes: 0,
67
75
  duplicateWrites: 0,
68
- collisions: 0,
76
+ collisions: vcCount(counts, "vector_cortex_crystal_collision"),
69
77
  lastFailure: null,
70
78
  updatedAt: new Date().toISOString(),
79
+ deferredReason: "crystal_store_not_instantiated_v0_20_23",
71
80
  };
72
81
  sendJson(res, 200, body);
73
82
  return true;
@@ -30,8 +30,12 @@ import type { IncomingMessage, ServerResponse } from "node:http";
30
30
  import type { RouteContext } from "./routes-core.js";
31
31
  import { VC7C_ENABLED } from "../../src/config.js";
32
32
  import { sendJson } from "./routes-vector-cortex-shared.js";
33
+ import { countVcEvents, vcCount } from "./vc-event-counts.js";
33
34
  import type { VectorCortexDiagnosticsView } from "./api-contracts/vector-cortex-diagnostics.js";
34
35
 
36
+ // Actual events emitted by src/vector-cortex/cache/diagnostics-emit.ts.
37
+ const DIAGNOSTICS_EVENTS = ["vector_cortex_cache_serve_blocked"] as const;
38
+
35
39
  /**
36
40
  * Reader-only GET /api/vector-cortex/cache-diagnostics (VC7C).
37
41
  *
@@ -41,7 +45,7 @@ import type { VectorCortexDiagnosticsView } from "./api-contracts/vector-cortex-
41
45
  export function handleVectorCortexDiagnostics(
42
46
  req: IncomingMessage,
43
47
  res: ServerResponse,
44
- _ctx: RouteContext,
48
+ ctx: RouteContext,
45
49
  ): boolean {
46
50
  const url = req.url ?? "";
47
51
  const path = url.split("?")[0] ?? url;
@@ -52,6 +56,7 @@ export function handleVectorCortexDiagnostics(
52
56
  }
53
57
 
54
58
  const enabled = VC7C_ENABLED();
59
+ const counts = countVcEvents(ctx.stateDir, DIAGNOSTICS_EVENTS);
55
60
  // Flag-off routes to mode C: with VC7C off the diagnostics/breaker reporter is
56
61
  // suppressed, so no cache serve is attested here and the surface reports the
57
62
  // all-cache bypass outcome. Reporting A (crystal served) or B (fresh render
@@ -67,10 +72,11 @@ export function handleVectorCortexDiagnostics(
67
72
  requestMisses: 0,
68
73
  generationMisses: 0,
69
74
  unknownMisses: 0,
70
- serveBlocked: 0,
75
+ serveBlocked: vcCount(counts, "vector_cortex_cache_serve_blocked"),
71
76
  breakerState: "closed",
72
77
  lastFailure: null,
73
78
  updatedAt: new Date().toISOString(),
79
+ deferredReason: "cache_classifier_not_wired_v0_20_23",
74
80
  };
75
81
  sendJson(res, 200, body);
76
82
  return true;
@@ -62,6 +62,7 @@ export function handleVectorCortexEconomics(
62
62
  unprovenExclusions: 0,
63
63
  lastFailure: null,
64
64
  updatedAt: new Date().toISOString(),
65
+ deferredReason: "economics_not_computed_v0_20_23",
65
66
  };
66
67
  sendJson(res, 200, body);
67
68
  return true;
@@ -24,16 +24,27 @@ import type { IncomingMessage, ServerResponse } from "node:http";
24
24
  import type { RouteContext } from "./routes-core.js";
25
25
  import { VC6A_ENABLED, VC6B_ENABLED } from "../../src/config.js";
26
26
  import { sendJson } from "./routes-vector-cortex-shared.js";
27
+ import { countVcEvents, vcCount } from "./vc-event-counts.js";
27
28
  import type {
28
29
  VectorCortexClosureProofView,
29
30
  VectorCortexRestoreView,
30
31
  } from "./api-contracts/vector-cortex.js";
31
32
 
33
+ // Actual event names emitted by src/vector-cortex/heal/emit.ts + restore-emit.ts.
34
+ const CLOSURE_EVENTS = [
35
+ "vector_cortex_closure_optimized",
36
+ "vector_cortex_closure_proof_rejected",
37
+ ] as const;
38
+ const RESTORE_EVENTS = [
39
+ "vector_cortex_source_restored",
40
+ "vector_cortex_restore_digest_rejected",
41
+ ] as const;
42
+
32
43
  /** Reader-only GET /api/vector-cortex/closure-proof (VC6A). */
33
44
  export function handleVectorCortexClosureProof(
34
45
  req: IncomingMessage,
35
46
  res: ServerResponse,
36
- _ctx: RouteContext,
47
+ ctx: RouteContext,
37
48
  ): boolean {
38
49
  const url = req.url ?? "";
39
50
  const path = url.split("?")[0] ?? url;
@@ -44,13 +55,14 @@ export function handleVectorCortexClosureProof(
44
55
  }
45
56
 
46
57
  const enabled = VC6A_ENABLED();
58
+ const counts = countVcEvents(ctx.stateDir, CLOSURE_EVENTS);
47
59
  // Flag-off routes to mode B (conservative closure, no reduction) per spec.
48
60
  const mode: "A" | "B" | "C" = enabled ? "A" : "B";
49
61
  const body: VectorCortexClosureProofView = {
50
62
  enabled,
51
63
  mode,
52
- optimizations: 0,
53
- proofRejections: 0,
64
+ optimizations: vcCount(counts, "vector_cortex_closure_optimized"),
65
+ proofRejections: vcCount(counts, "vector_cortex_closure_proof_rejected"),
54
66
  retainedEdgeTotal: 0,
55
67
  removedEdgeTotal: 0,
56
68
  conservativeTraversalTotal: 0,
@@ -72,7 +84,7 @@ export function handleVectorCortexClosureProof(
72
84
  export function handleVectorCortexRestore(
73
85
  req: IncomingMessage,
74
86
  res: ServerResponse,
75
- _ctx: RouteContext,
87
+ ctx: RouteContext,
76
88
  ): boolean {
77
89
  const url = req.url ?? "";
78
90
  const path = url.split("?")[0] ?? url;
@@ -83,6 +95,7 @@ export function handleVectorCortexRestore(
83
95
  }
84
96
 
85
97
  const enabled = VC6B_ENABLED();
98
+ const counts = countVcEvents(ctx.stateDir, RESTORE_EVENTS);
86
99
  // Flag-off routes to mode C: with VC6B off there is no exact-restoration path
87
100
  // at all, so the honest OFF view is the disclose-loss mode (old context is
88
101
  // omitted rather than inferred) — mirroring how VC6A's OFF view reports the
@@ -91,10 +104,10 @@ export function handleVectorCortexRestore(
91
104
  const body: VectorCortexRestoreView = {
92
105
  enabled,
93
106
  mode,
94
- restoreAttempts: 0,
107
+ restoreAttempts: vcCount(counts, "vector_cortex_source_restored"),
95
108
  restoredCount: 0,
96
109
  missingCount: 0,
97
- digestRejections: 0,
110
+ digestRejections: vcCount(counts, "vector_cortex_restore_digest_rejected"),
98
111
  lastRejection: null,
99
112
  updatedAt: new Date().toISOString(),
100
113
  };
@@ -49,6 +49,7 @@ export function handleVectorCortexPolicy(
49
49
  pressureVersion: 1,
50
50
  lastFailure: null,
51
51
  updatedAt: new Date().toISOString(),
52
+ deferredReason: "shadow_controller_not_instantiated_v0_20_23",
52
53
  };
53
54
  sendJson(res, 200, body);
54
55
  return true;