pi-mega-compact 0.20.25 → 0.20.27
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/dist/config/vector-cortex-vc9a.js +29 -0
- package/dist/config/vector-cortex.js +4 -0
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/api-contracts/endpoints/registry-ext.js +7 -0
- package/dist/extensions/dashboard-server/api-contracts/setup-cortex.js +12 -0
- package/dist/extensions/dashboard-server/route-dispatch.js +3 -1
- package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +1 -0
- package/dist/extensions/dashboard-server/routes-setup-cortex.js +143 -0
- package/dist/extensions/dashboard-server/routes.js +1 -0
- package/dist/extensions/dashboard-server/server.js +4 -2
- package/dist/extensions/dashboard-server/setup-cortex-blockers.js +53 -0
- package/dist/extensions/mega-dashboard-bounce.js +79 -0
- package/dist/extensions/mega-dashboard-cmds.js +57 -24
- package/dist/src/config/vector-cortex-vc9a.js +29 -0
- package/dist/src/config/vector-cortex.js +4 -0
- package/dist/src/config.js +1 -1
- package/extensions/dashboard-client/dist/assets/{AreaChart-DRErPez1.js → AreaChart-Bl8FQm-w.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-DRErPez1.js.map → AreaChart-Bl8FQm-w.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-Cwxel3M7.js → BarChart-BXn1a_v9.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-Cwxel3M7.js.map → BarChart-BXn1a_v9.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-D4j3vwFu.js → CacheTab-DzZpIHkZ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-D4j3vwFu.js.map → CacheTab-DzZpIHkZ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-BA7t_fsH.js → EventsTab-rn_Ncwk0.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-BA7t_fsH.js.map → EventsTab-rn_Ncwk0.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-Ci9gtYDP.js → HealthTab-D4d20PFh.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-Ci9gtYDP.js.map → HealthTab-D4d20PFh.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-BeqWn-xu.js → MaintenanceTab-44lwue_H.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-BeqWn-xu.js.map → MaintenanceTab-44lwue_H.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BreZegCV.js → MemoryMapTab-BPCPyPqp.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BreZegCV.js.map → MemoryMapTab-BPCPyPqp.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-DLbgfJT2.js → MetricsTab-B1is6D7F.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-DLbgfJT2.js.map → MetricsTab-B1is6D7F.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-BtcXdrnC.js → OverviewTab-DIC_cUjS.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-BtcXdrnC.js.map → OverviewTab-DIC_cUjS.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-DpDLEzV9.js → ReposTab-KhTQqt5Z.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-DpDLEzV9.js.map → ReposTab-KhTQqt5Z.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-CMe5jSrZ.js → SessionsTab-CeOUPRIM.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-CMe5jSrZ.js.map → SessionsTab-CeOUPRIM.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SetupTab-C3OY8mc7.js → SetupTab-DnN0mX0J.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-C3OY8mc7.js.map → SetupTab-DnN0mX0J.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BFPJUQzs.js → TimeSavedCard-CXmxE5_8.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BFPJUQzs.js.map → TimeSavedCard-CXmxE5_8.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-Ujt29pKI.js → TurnsTab-Dbx9pZPX.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-Ujt29pKI.js.map → TurnsTab-Dbx9pZPX.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{VectorCortexTab-CfxZW91A.js → VectorCortexTab-MzqdB6zI.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{VectorCortexTab-CfxZW91A.js.map → VectorCortexTab-MzqdB6zI.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{WikiTab-BiKXVwGT.js → WikiTab-B1mKp1SA.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-BiKXVwGT.js.map → WikiTab-B1mKp1SA.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-DJwGcw0u.js → button-BFHPDVb1.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-DJwGcw0u.js.map → button-BFHPDVb1.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-CgjBf5LZ.js → card-XrbSJiOF.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-CgjBf5LZ.js.map → card-XrbSJiOF.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-CTQIl2qs.js → generateCategoricalChart-B9Ba91Tu.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-CTQIl2qs.js.map → generateCategoricalChart-B9Ba91Tu.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-Bu8CZUMX.js → index-P13AO5ni.js} +4 -4
- package/extensions/dashboard-client/dist/assets/index-P13AO5ni.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{switch-uUiS1Raq.js → switch-jnYDePmb.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-uUiS1Raq.js.map → switch-jnYDePmb.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-Dv3OEscH.js → toggle-JO-vvubb.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-Dv3OEscH.js.map → toggle-JO-vvubb.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-n6ymAic3.js → useSSE-DAkXqUOy.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-n6ymAic3.js.map → useSSE-DAkXqUOy.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-server/api-contracts/endpoints/registry-ext.ts +11 -0
- package/extensions/dashboard-server/api-contracts/setup-cortex.ts +65 -0
- package/extensions/dashboard-server/route-dispatch.ts +2 -0
- package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +6 -0
- package/extensions/dashboard-server/routes-setup-cortex.ts +167 -0
- package/extensions/dashboard-server/routes.ts +1 -0
- package/extensions/dashboard-server/server.ts +4 -2
- package/extensions/dashboard-server/setup-cortex-blockers.ts +73 -0
- package/extensions/mega-dashboard-bounce.ts +97 -0
- package/extensions/mega-dashboard-cmds.ts +63 -24
- package/package.json +1 -1
- package/src/config/vector-cortex-vc9a.ts +31 -0
- package/src/config/vector-cortex.ts +5 -0
- package/src/config.ts +1 -0
- package/extensions/dashboard-client/dist/assets/index-Bu8CZUMX.js.map +0 -1
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-server/routes-setup-cortex.ts — VC9A Setup Cortex status route.
|
|
3
|
+
*
|
|
4
|
+
* GET /api/setup-cortex-status — reader-only aggregate surfacing the
|
|
5
|
+
* vector-cortex encoder gate (mode A/B/C, qualification verdict,
|
|
6
|
+
* blockers, encoder health) for the dashboard Setup tab. Does NOT close
|
|
7
|
+
* the ML gate: the hard-gate blockers are read-only and stay open.
|
|
8
|
+
*
|
|
9
|
+
* Reuses readEncoderManifest / verifyEncoderAsset / detectPlatform
|
|
10
|
+
* (src/vector-cortex/encoder/asset.ts) and deriveVcStatus (vc-status.ts),
|
|
11
|
+
* plus the memoized encoder-facts pattern from routes-vector-cortex-health.ts
|
|
12
|
+
* (manifest bytes + file size/mtime + platform cache key) so the expensive
|
|
13
|
+
* full-asset hashing is skipped on repeat polls.
|
|
14
|
+
*
|
|
15
|
+
* The blocker rows carry NO string literals here — they come from the static
|
|
16
|
+
* manifest module setup-cortex-blockers.ts (single canonical source).
|
|
17
|
+
*
|
|
18
|
+
* Guardrails: PREVENT-PI-004 (local filesystem read only), PREVENT-011 (no
|
|
19
|
+
* `any`), reader-only aggregate (never payloads/prompts/ledger — EVAL-REDACT-002).
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
23
|
+
import { createHash } from "node:crypto";
|
|
24
|
+
import { readFileSync, statSync } from "node:fs";
|
|
25
|
+
import { join, dirname } from "node:path";
|
|
26
|
+
import { fileURLToPath } from "node:url";
|
|
27
|
+
import type { RouteContext } from "./routes-core.js";
|
|
28
|
+
import { VC9A_ENABLED } from "../../src/config.js";
|
|
29
|
+
import { readEncoderManifest, verifyEncoderAsset, detectPlatform } from "../../src/vector-cortex/encoder/asset.js";
|
|
30
|
+
import { sendJson } from "./routes-vector-cortex-shared.js";
|
|
31
|
+
import { deriveVcStatus } from "./vc-status.js";
|
|
32
|
+
import { SETUP_CORTEX_BLOCKERS } from "./setup-cortex-blockers.js";
|
|
33
|
+
import type {
|
|
34
|
+
SetupCortexStatusResponse,
|
|
35
|
+
BlockerV1,
|
|
36
|
+
} from "./api-contracts/setup-cortex.js";
|
|
37
|
+
|
|
38
|
+
/** Resolve the committed encoder-v1 asset dir by walking up to the repo root. */
|
|
39
|
+
function encoderAssetDir(): string | null {
|
|
40
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
41
|
+
const rel = join("assets", "vector-cortex", "encoder-v1");
|
|
42
|
+
for (let i = 0; i < 8; i++) {
|
|
43
|
+
const candidate = join(dir, rel);
|
|
44
|
+
try {
|
|
45
|
+
// guardrails-allow PREVENT-PI-004: local asset filesystem read (loopback)
|
|
46
|
+
readFileSync(join(candidate, "manifest.json"));
|
|
47
|
+
return candidate;
|
|
48
|
+
} catch {
|
|
49
|
+
/* keep walking */
|
|
50
|
+
}
|
|
51
|
+
const next = dirname(dir);
|
|
52
|
+
if (next === dir) break;
|
|
53
|
+
dir = next;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Reader-only encoder health facts: mode + asset digest (+ vertex/verdict). */
|
|
59
|
+
interface SetupCortexFacts {
|
|
60
|
+
mode: "A" | "B" | "C";
|
|
61
|
+
assetDigestPrefix: string | null;
|
|
62
|
+
verdict: "qualified" | "demoted" | "unavailable";
|
|
63
|
+
thresholdFailures: string[];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface SetupCortexFactCache {
|
|
67
|
+
key: string;
|
|
68
|
+
facts: SetupCortexFacts;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let factCache: SetupCortexFactCache | null = null;
|
|
72
|
+
|
|
73
|
+
/** Stable cache key: manifest bytes + (size,mtime) of the asset files + platform. */
|
|
74
|
+
function factCacheKey(dir: string, manifestPath: string): string | null {
|
|
75
|
+
const platform = detectPlatform();
|
|
76
|
+
if (!platform) return null;
|
|
77
|
+
const parts: string[] = [platform];
|
|
78
|
+
try {
|
|
79
|
+
for (const p of [manifestPath, join(dir, "model.onnx"), join(dir, "tokenizer.json")]) {
|
|
80
|
+
const s = statSync(p);
|
|
81
|
+
parts.push(`${s.size}:${s.mtimeMs}`);
|
|
82
|
+
}
|
|
83
|
+
// guardrails-allow PREVENT-PI-004: local manifest filesystem read (loopback)
|
|
84
|
+
parts.push(createHash("sha256").update(readFileSync(manifestPath)).digest("hex"));
|
|
85
|
+
} catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return parts.join("|");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function computeSetupCortexFacts(dir: string): SetupCortexFacts | null {
|
|
92
|
+
const manifest = readEncoderManifest(dir);
|
|
93
|
+
if (manifest === null) {
|
|
94
|
+
return { mode: "C", assetDigestPrefix: null, verdict: "unavailable", thresholdFailures: [] };
|
|
95
|
+
}
|
|
96
|
+
const manifestPath = join(dir, "manifest.json");
|
|
97
|
+
const key = factCacheKey(dir, manifestPath);
|
|
98
|
+
if (key === null) return null;
|
|
99
|
+
if (factCache !== null && factCache.key === key) return factCache.facts;
|
|
100
|
+
let digest: string;
|
|
101
|
+
try {
|
|
102
|
+
// guardrails-allow PREVENT-PI-004: local manifest filesystem read (loopback)
|
|
103
|
+
digest = createHash("sha256").update(readFileSync(manifestPath)).digest("hex");
|
|
104
|
+
} catch {
|
|
105
|
+
const facts: SetupCortexFacts = { mode: "B", assetDigestPrefix: null, verdict: "demoted", thresholdFailures: ["ENC_ASSET_UNREADABLE"] };
|
|
106
|
+
factCache = { key, facts };
|
|
107
|
+
return facts;
|
|
108
|
+
}
|
|
109
|
+
const verify = verifyEncoderAsset(dir, manifest, detectPlatform());
|
|
110
|
+
const prefix = digest.slice(0, 12);
|
|
111
|
+
const facts: SetupCortexFacts = verify.ok
|
|
112
|
+
? { mode: "A", assetDigestPrefix: prefix, verdict: "qualified", thresholdFailures: [] }
|
|
113
|
+
: { mode: "B", assetDigestPrefix: prefix, verdict: "demoted", thresholdFailures: [verify.code] };
|
|
114
|
+
factCache = { key, facts };
|
|
115
|
+
return facts;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function setupCortexFacts(): SetupCortexFacts {
|
|
119
|
+
const dir = encoderAssetDir();
|
|
120
|
+
if (dir === null) {
|
|
121
|
+
return { mode: "C", assetDigestPrefix: null, verdict: "unavailable", thresholdFailures: [] };
|
|
122
|
+
}
|
|
123
|
+
const facts = computeSetupCortexFacts(dir);
|
|
124
|
+
return facts ?? { mode: "C", assetDigestPrefix: null, verdict: "unavailable", thresholdFailures: [] };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Reader-only GET /api/setup-cortex-status (VC9A).
|
|
129
|
+
*
|
|
130
|
+
* Purely read: no mutation, never payloads/prompts/ledger. Flag-off returns the
|
|
131
|
+
* byte-identical VC8C-era shape `{enabled:false, mode:"C", status:"off"}` with
|
|
132
|
+
* the encoder-health mode C and no qualification/blocker detail leaked.
|
|
133
|
+
*/
|
|
134
|
+
export function handleSetupCortexStatus(
|
|
135
|
+
req: IncomingMessage,
|
|
136
|
+
res: ServerResponse,
|
|
137
|
+
_ctx: RouteContext,
|
|
138
|
+
): boolean {
|
|
139
|
+
const url = req.url ?? "";
|
|
140
|
+
if (url !== "/api/setup-cortex-status") return false;
|
|
141
|
+
if (req.method !== "GET") {
|
|
142
|
+
sendJson(res, 405, { error: "method_not_allowed" });
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const enabled = VC9A_ENABLED();
|
|
147
|
+
const facts = enabled ? setupCortexFacts() : null;
|
|
148
|
+
const blocks: BlockerV1[] = enabled ? [...SETUP_CORTEX_BLOCKERS] : [];
|
|
149
|
+
|
|
150
|
+
const body: SetupCortexStatusResponse = {
|
|
151
|
+
enabled,
|
|
152
|
+
flag: "MEGACOMPACT_VC9A",
|
|
153
|
+
mode: facts ? facts.mode : "C",
|
|
154
|
+
assetDigestPrefix: facts ? facts.assetDigestPrefix : null,
|
|
155
|
+
qualification: facts
|
|
156
|
+
? { verdict: facts.verdict, thresholdFailures: facts.thresholdFailures }
|
|
157
|
+
: { verdict: "unavailable", thresholdFailures: [] },
|
|
158
|
+
blockers: blocks,
|
|
159
|
+
encoderHealth: facts
|
|
160
|
+
? { assetDigestPrefix: facts.assetDigestPrefix, mode: facts.mode }
|
|
161
|
+
: { assetDigestPrefix: null, mode: "C" },
|
|
162
|
+
updatedAt: new Date().toISOString(),
|
|
163
|
+
status: deriveVcStatus({ enabled, hasData: !!facts && facts.verdict !== "unavailable", structuralOnly: true }),
|
|
164
|
+
};
|
|
165
|
+
sendJson(res, 200, body);
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
@@ -302,9 +302,11 @@ export async function launchDashboardServer(
|
|
|
302
302
|
v6.listen(port, "::1", () => log("ipv6 loopback bound", { port })); // guardrails-allow PREVENT-PI-004: IPv6 loopback (::1) mirror of the dashboard server
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
-
// Write port.pid
|
|
305
|
+
// Write port.pid (VC0F B2: stamp `version` so the launcher can detect
|
|
306
|
+
// a stale runner by comparing the marker against its own version
|
|
307
|
+
// without an HTTP probe — closes the orphan case for pre-B2 servers).
|
|
306
308
|
try {
|
|
307
|
-
writeFileSync(portFile, JSON.stringify({ port, pid: process.pid }));
|
|
309
|
+
writeFileSync(portFile, JSON.stringify({ port, pid: process.pid, version: SERVER_VERSION }));
|
|
308
310
|
} catch (e) {
|
|
309
311
|
log("could not write port.pid", { error: String(e) });
|
|
310
312
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-server/setup-cortex-blockers.ts — canonical blocker manifest for the
|
|
3
|
+
* dashboard Setup Cortex status read path (VC9A).
|
|
4
|
+
*
|
|
5
|
+
* The hard-gate items enumerated in docs/vector-cortex/vc2-model-prep.md §6
|
|
6
|
+
* (per the 2026-08-05 research update: the opset-14→17 re-export blocker is
|
|
7
|
+
* REMOVED because onnx-community exports are now opset 21). This module is the
|
|
8
|
+
* SINGLE canonical source of those blockers — the route file
|
|
9
|
+
* (routes-setup-cortex.ts) carries NO string literals for them; it reads this
|
|
10
|
+
* static manifest so the UI rows and the spec stay in one place.
|
|
11
|
+
*
|
|
12
|
+
* Reader-only, static: zero network, no writes (PREVENT-PI-004), no `any`
|
|
13
|
+
* (PREVENT-011).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** The open hard-gate items VC9A surfaces (nothing is closed in-workstream). */
|
|
17
|
+
export interface SetupCortexBlockerV1 {
|
|
18
|
+
/** Stable machine id (e.g. HG-1) the client can key rows on. */
|
|
19
|
+
readonly id: string;
|
|
20
|
+
/** Human title shown on the blockers card. */
|
|
21
|
+
readonly title: string;
|
|
22
|
+
/** Severity: blocker | high | medium. */
|
|
23
|
+
readonly severity: "blocker" | "high" | "medium";
|
|
24
|
+
/** Lifecycle state — all OPEN (hard gates are never silently closed). */
|
|
25
|
+
readonly status: "open";
|
|
26
|
+
/** Optional candidate resolution surfaced for the controller / user. */
|
|
27
|
+
readonly resolution?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The four blockers VC9A reports. Enumerates the vc2-model-prep §6 items that
|
|
32
|
+
* remain per the 2026-08-05 research. The opset re-export blocker (formerly
|
|
33
|
+
* §6 #2) is NOT listed: onnx-community exports are opset 21, so it is removed.
|
|
34
|
+
*/
|
|
35
|
+
export const SETUP_CORTEX_BLOCKERS: readonly SetupCortexBlockerV1[] = [
|
|
36
|
+
{
|
|
37
|
+
id: "HG-1",
|
|
38
|
+
title: "Five projection heads do not exist",
|
|
39
|
+
severity: "blocker",
|
|
40
|
+
status: "open",
|
|
41
|
+
resolution:
|
|
42
|
+
"Supervision transfer onto a frozen bge-small-en-v1.5 trunk (contradiction distilled from cross-encoder/nli-deberta-v3-small; dependency NLI-assisted; cache-stability deterministic; payload-routing small MLP) — VC2B training + export.",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "HG-3",
|
|
46
|
+
title: "onnxruntime-node install exceeds the 80 MiB asset budget",
|
|
47
|
+
severity: "blocker",
|
|
48
|
+
status: "open",
|
|
49
|
+
resolution:
|
|
50
|
+
"onnxruntime-node bundles ~258 MiB across all platforms. Candidate: transformers.js v4.2.0 (9.5 MiB shell, pure-Node via onnxruntime-web WASM) measured against budget + p95 gate before committing.",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "HG-4",
|
|
54
|
+
title: "No darwin-x64 binary in onnxruntime-node",
|
|
55
|
+
severity: "high",
|
|
56
|
+
status: "open",
|
|
57
|
+
resolution:
|
|
58
|
+
"Intel-Mac mode-A users demote to the WASM path (if HG-3 resolves that way) or mode B.",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: "HG-5",
|
|
62
|
+
title: "RSS margin at 512 tokens is ~0.5%",
|
|
63
|
+
severity: "medium",
|
|
64
|
+
status: "open",
|
|
65
|
+
resolution:
|
|
66
|
+
"149.2 MiB vs 150 MiB cap with run-to-run variance 119-149 MiB; considers capping mode A at 384 tokens or using the marginal-footprint accounting runtime.ts already implements.",
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
/** Look up one blocker by id; undefined when unknown (defensive). */
|
|
71
|
+
export function setupCortexBlocker(id: string): SetupCortexBlockerV1 | undefined {
|
|
72
|
+
return SETUP_CORTEX_BLOCKERS.find((b) => b.id === id);
|
|
73
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mega-dashboard-bounce.ts — VC0F stale-runner detection + bounce.
|
|
3
|
+
*
|
|
4
|
+
* Delegate of `mega-dashboard-cmds.ts` (kept under the extensions/ soft limit):
|
|
5
|
+
* owns the once-per-process staleness gate and the pure
|
|
6
|
+
* `bounceStaleRunnerIfAny` decision, which is the durable restart-on-upgrade
|
|
7
|
+
* seam — after `pi update --extensions` replaces the on-disk package, the next
|
|
8
|
+
* `session_start` probes the running dashboard, sees the version mismatch, and
|
|
9
|
+
* kills + respawns the stale runner so it serves the current code.
|
|
10
|
+
*
|
|
11
|
+
* The function is dependency-injected so unit tests (VC0F C1–C3) can stub every
|
|
12
|
+
* primitive; the production wiring (live discovery / version / kill) lives in
|
|
13
|
+
* `mega-dashboard-cmds.ts` and is passed in. No network here — the localhost
|
|
14
|
+
* HTTP probes live behind the injected `isServerRunning`/`serverVersion` deps
|
|
15
|
+
* (already audited PREVENT-PI-004 in the parent file).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Once-per-process staleness gate (VC0F A2). After the FIRST successful probe
|
|
20
|
+
* we skip re-probing on later /mega-dashboard invocations or session-start
|
|
21
|
+
* events within the same extension process — the probe is cheap but the
|
|
22
|
+
* kill+respawn it triggers is disruptive. Set regardless of outcome.
|
|
23
|
+
*/
|
|
24
|
+
let stalenessCheckedThisProcess = false;
|
|
25
|
+
|
|
26
|
+
/** Test-only seam: clear the once-per-process gate between unit tests. */
|
|
27
|
+
export function resetStalenessGateForTests(): void {
|
|
28
|
+
stalenessCheckedThisProcess = false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Injectables `bounceStaleRunnerIfAny` needs from the current repo's dashboard
|
|
32
|
+
* lifecycle. Injected so the unit tests (VC0F C1–C3) can stub each primitive
|
|
33
|
+
* independently. */
|
|
34
|
+
export interface BounceStaleDeps {
|
|
35
|
+
/** Discover a live dashboard server for the current repo, or null. */
|
|
36
|
+
isServerRunning(): Promise<{ port: number; url: string; hasPidFile: boolean } | null>;
|
|
37
|
+
/** Version the running server reports via HTTP (/api/version), or null. */
|
|
38
|
+
serverVersion(port: number): Promise<string | null>;
|
|
39
|
+
/** Version stamped in the current repo's port.pid marker, or null. */
|
|
40
|
+
markerVersion(): string | null;
|
|
41
|
+
/** Version of THIS extension package (from its own package.json). */
|
|
42
|
+
ownVersion(): string | null;
|
|
43
|
+
/** Kill the server on `port` and clear its marker (best-effort). */
|
|
44
|
+
killServerOnPort(port: number): void;
|
|
45
|
+
/** User notification; a no-op on the silent session-start path (VC0F A3). */
|
|
46
|
+
notify(message: string): void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Detect + replace a STALE dashboard runner for the current repo (VC0F A1).
|
|
51
|
+
*
|
|
52
|
+
* A runner is stale when it is an orphan (live but missing its port.pid
|
|
53
|
+
* marker), when its marker's stamped `version` differs from this extension's
|
|
54
|
+
* own version (VC0F B2 — avoids the HTTP probe), or when the version it
|
|
55
|
+
* reports over HTTP differs from our own (fallback for pre-B2 servers whose
|
|
56
|
+
* marker has no `version` field). A stale runner is killed so the next launch
|
|
57
|
+
* serves the current on-disk code.
|
|
58
|
+
*
|
|
59
|
+
* Best-effort and non-fatal (Goal 4): any failure returns `{bounced:false}`
|
|
60
|
+
* and never throws. Runs at most once per extension process (A2).
|
|
61
|
+
*/
|
|
62
|
+
export async function bounceStaleRunnerIfAny(deps: BounceStaleDeps): Promise<{ bounced: boolean }> {
|
|
63
|
+
if (stalenessCheckedThisProcess) return { bounced: false };
|
|
64
|
+
try {
|
|
65
|
+
stalenessCheckedThisProcess = true; // once per process, regardless of outcome
|
|
66
|
+
const info = await deps.isServerRunning();
|
|
67
|
+
if (!info) return { bounced: false };
|
|
68
|
+
const orphan = !info.hasPidFile;
|
|
69
|
+
const want = deps.ownVersion();
|
|
70
|
+
const marker = deps.markerVersion();
|
|
71
|
+
let stale: boolean;
|
|
72
|
+
let from: string | null = null;
|
|
73
|
+
if (orphan) {
|
|
74
|
+
stale = true; // live server with no marker → orphan by definition
|
|
75
|
+
} else if (want != null && marker != null) {
|
|
76
|
+
stale = marker !== want; // B2: compare the stamped marker, skip the HTTP probe
|
|
77
|
+
from = marker;
|
|
78
|
+
} else {
|
|
79
|
+
const running = await deps.serverVersion(info.port);
|
|
80
|
+
from = running;
|
|
81
|
+
stale = want != null && running != null && running !== want;
|
|
82
|
+
}
|
|
83
|
+
if (stale) {
|
|
84
|
+
deps.notify(
|
|
85
|
+
orphan
|
|
86
|
+
? "[mega-compact] replacing orphaned dashboard server…"
|
|
87
|
+
: `[mega-compact] replacing stale dashboard (${from ?? "?"} → ${want ?? "?"})…`,
|
|
88
|
+
);
|
|
89
|
+
deps.killServerOnPort(info.port);
|
|
90
|
+
return { bounced: true };
|
|
91
|
+
}
|
|
92
|
+
return { bounced: false };
|
|
93
|
+
} catch {
|
|
94
|
+
// Best-effort, non-fatal — a failed probe/kill never breaks the caller.
|
|
95
|
+
return { bounced: false };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -12,6 +12,15 @@ import { fileURLToPath } from "node:url";
|
|
|
12
12
|
import { existsSync, writeFileSync, readFileSync, unlinkSync, openSync, closeSync } from "node:fs";
|
|
13
13
|
import { spawn, execSync } from "node:child_process"; // guardrails-allow PREVENT-PI-004: spawns the optional, user-triggered localhost dashboard server only
|
|
14
14
|
import type { MegaRuntime } from "./mega-runtime.js";
|
|
15
|
+
import {
|
|
16
|
+
bounceStaleRunnerIfAny,
|
|
17
|
+
type BounceStaleDeps,
|
|
18
|
+
} from "./mega-dashboard-bounce.js";
|
|
19
|
+
|
|
20
|
+
// Re-export the VC0F bounce seam for the unit tests, which import the parent
|
|
21
|
+
// module. The implementation + once-per-process gate live in the sibling
|
|
22
|
+
// delegate file to keep this module under the extensions/ soft limit (400).
|
|
23
|
+
export { bounceStaleRunnerIfAny, resetStalenessGateForTests, type BounceStaleDeps } from "./mega-dashboard-bounce.js";
|
|
15
24
|
|
|
16
25
|
/** Register the dashboard server lifecycle commands. */
|
|
17
26
|
export function registerDashboardCommands(pi: ExtensionAPI, runtime: MegaRuntime): void {
|
|
@@ -111,6 +120,28 @@ export function registerDashboardCommands(pi: ExtensionAPI, runtime: MegaRuntime
|
|
|
111
120
|
try { unlinkSync(portFile()); } catch { /* ignore */ }
|
|
112
121
|
}
|
|
113
122
|
|
|
123
|
+
/** Version stamped in the current repo's port.pid marker (VC0F B2), or null
|
|
124
|
+
* when the marker is absent or predates the stamped `version` field. */
|
|
125
|
+
function markerVersion(): string | null {
|
|
126
|
+
try {
|
|
127
|
+
const info = JSON.parse(readFileSync(portFile(), "utf-8")) as { version?: unknown };
|
|
128
|
+
return typeof info.version === "string" ? info.version : null;
|
|
129
|
+
} catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Build the dependency set `bounceStaleRunnerIfAny` needs for the CURRENT
|
|
136
|
+
* repo's dashboard lifecycle (port.pid / runner / launch-log all resolve via
|
|
137
|
+
* `runtime.currentStateDir`, so a repo switch re-targets the bounce).
|
|
138
|
+
* `notify` is threaded here so the interactive /mega-dashboard path surfaces
|
|
139
|
+
* the replace messages while the silent session-start path is a no-op.
|
|
140
|
+
*/
|
|
141
|
+
function staleBounceDeps(notify: (msg: string) => void): BounceStaleDeps {
|
|
142
|
+
return { isServerRunning, serverVersion, markerVersion, ownVersion, killServerOnPort, notify };
|
|
143
|
+
}
|
|
144
|
+
|
|
114
145
|
/**
|
|
115
146
|
* Resolve the launchable dashboard-server module.
|
|
116
147
|
*
|
|
@@ -148,9 +179,14 @@ export function registerDashboardCommands(pi: ExtensionAPI, runtime: MegaRuntime
|
|
|
148
179
|
const resolved = resolveDashboardEntry();
|
|
149
180
|
if (!resolved) return false;
|
|
150
181
|
dashboardNeedsStrip = resolved.needsStripTypes;
|
|
182
|
+
// VC0F B1: stamp the extension version in the generated script at WRITE time
|
|
183
|
+
// so a future probe can compare it against ownVersion() without a live HTTP
|
|
184
|
+
// round-trip (useful when the server is hung and /api/version times out).
|
|
185
|
+
const stampedVersion = ownVersion() ?? "0.0.0";
|
|
151
186
|
const script = [
|
|
152
187
|
`import { appendFileSync } from "node:fs";`,
|
|
153
188
|
`const __log = ${JSON.stringify(launchLog())};`,
|
|
189
|
+
`const __VERSION = ${JSON.stringify(stampedVersion)}; // mega-compact bundle version stamped at write time (VC0F B1)`,
|
|
154
190
|
`function __fail(err) {`,
|
|
155
191
|
` const msg = "[mega-compact] dashboard failed: " + (err && err.stack ? err.stack : String(err));`,
|
|
156
192
|
` try { appendFileSync(__log, msg + "\\n"); } catch { /* ignore */ }`,
|
|
@@ -181,32 +217,18 @@ export function registerDashboardCommands(pi: ExtensionAPI, runtime: MegaRuntime
|
|
|
181
217
|
description: "Start the local web dashboard and optionally open it in the default browser.",
|
|
182
218
|
handler: async (_args: string, ctx: ExtensionContext) => {
|
|
183
219
|
runtime.bindRepo(ctx.cwd);
|
|
184
|
-
|
|
220
|
+
// VC0F A1: lift the stale-replace decision out of the handler. Interactive
|
|
221
|
+
// path is unchanged — the user is still notified before a stale runner is
|
|
222
|
+
// killed. When a stale server is bounced, we fall straight through to a
|
|
223
|
+
// fresh spawn; otherwise reuse the live current server if there is one.
|
|
224
|
+
const { bounced } = await bounceStaleRunnerIfAny(staleBounceDeps((msg) => ctx.ui.notify(msg)));
|
|
225
|
+
const info = bounced ? null : await isServerRunning();
|
|
185
226
|
|
|
186
227
|
if (info) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
// build). A live server WITH a matching pid file and version is reused.
|
|
192
|
-
const orphan = !info.hasPidFile;
|
|
193
|
-
const running = await serverVersion(info.port);
|
|
194
|
-
const want = ownVersion();
|
|
195
|
-
const stale = orphan || (want != null && running != null && running !== want);
|
|
196
|
-
if (stale) {
|
|
197
|
-
ctx.ui.notify(
|
|
198
|
-
orphan
|
|
199
|
-
? "[mega-compact] replacing orphaned dashboard server…"
|
|
200
|
-
: `[mega-compact] replacing stale dashboard (${running} → ${want})…`,
|
|
201
|
-
);
|
|
202
|
-
killServerOnPort(info.port);
|
|
203
|
-
info = null;
|
|
204
|
-
} else {
|
|
205
|
-
ctx.ui.notify(`[mega-compact] dashboard already running at ${info.url}`);
|
|
206
|
-
const open = await ctx.ui.confirm("mega-compact dashboard", `Open ${info.url} in browser?`);
|
|
207
|
-
if (open) openBrowser(info.url);
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
228
|
+
ctx.ui.notify(`[mega-compact] dashboard already running at ${info.url}`);
|
|
229
|
+
const open = await ctx.ui.confirm("mega-compact dashboard", `Open ${info.url} in browser?`);
|
|
230
|
+
if (open) openBrowser(info.url);
|
|
231
|
+
return;
|
|
210
232
|
}
|
|
211
233
|
|
|
212
234
|
// Start the server
|
|
@@ -310,4 +332,21 @@ export function registerDashboardCommands(pi: ExtensionAPI, runtime: MegaRuntime
|
|
|
310
332
|
}
|
|
311
333
|
},
|
|
312
334
|
});
|
|
335
|
+
|
|
336
|
+
// VC0F A3 — durable restart-on-upgrade: after `pi update --extensions`
|
|
337
|
+
// replaces the on-disk package, the next pi session probes the running
|
|
338
|
+
// dashboard, sees the version mismatch, and kills + respawns the stale runner
|
|
339
|
+
// automatically. SILENT — no ctx.ui.notify on this session-start path (unlike
|
|
340
|
+
// the explicit /mega-dashboard path). Best-effort and non-fatal: a probe or
|
|
341
|
+
// kill failure here never breaks session startup.
|
|
342
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
343
|
+
runtime.bindRepo(ctx.cwd);
|
|
344
|
+
try {
|
|
345
|
+
await bounceStaleRunnerIfAny(
|
|
346
|
+
staleBounceDeps(() => { /* session-start path stays silent (VC0F A3) */ }),
|
|
347
|
+
);
|
|
348
|
+
} catch {
|
|
349
|
+
/* best-effort — never break the session */
|
|
350
|
+
}
|
|
351
|
+
});
|
|
313
352
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-mega-compact",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.27",
|
|
4
4
|
"description": "Layered, local, vector-backed context compressor for pi — supersede/collapse/cluster compaction with deduped inline recall.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config/vector-cortex-vc9a.ts — VC9A setup-cortex status-read-path sprint flag.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from vector-cortex.ts so that file stays under the 300-line soft
|
|
5
|
+
* limit (soft-as-hard gate), exactly as vector-cortex-vc8c.ts,
|
|
6
|
+
* vector-cortex-breakers.ts and vector-cortex-early.ts were. This is the
|
|
7
|
+
* SETUP-DASHBOARD reader flag (the dashboard Setup tab cortex status endpoint).
|
|
8
|
+
* vector-cortex.ts re-exports it below and root src/config.ts re-exports it, so
|
|
9
|
+
* no consumer import path changes.
|
|
10
|
+
*
|
|
11
|
+
* The split is purely mechanical: VC9A_ENABLED is byte-identical in name,
|
|
12
|
+
* semantics, and default to the definition it replaces, and vector-cortex.ts
|
|
13
|
+
* re-exports it so every existing `from "./config/vector-cortex.js"` import
|
|
14
|
+
* keeps resolving unchanged.
|
|
15
|
+
*
|
|
16
|
+
* Pi-agnostic, dependency-free (PREVENT-PI-004 / PREVENT-011).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { sprintFlag } from "./vector-cortex-flag.js";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* VC9A — Setup Cortex status read path (GET /api/setup-cortex-status).
|
|
23
|
+
* Default ON. `MEGACOMPACT_VC9A=0` disables and is byte-identical to the
|
|
24
|
+
* predecessor (VC8C-era shape): the endpoint returns `{enabled:false,
|
|
25
|
+
* mode:"C", status:"off"}` and surfaces no qualification/blocker/health detail —
|
|
26
|
+
* a pure reader-only projection, never a mutation. This flag MUST also be a
|
|
27
|
+
* dashboard SETTINGS toggle (visible in config UI, never in EXCLUDED_SETTINGS),
|
|
28
|
+
* mirroring VC4A..VC8C. The dashboard reader itself performs only local
|
|
29
|
+
* filesystem reads (no network, PREVENT-PI-004).
|
|
30
|
+
*/
|
|
31
|
+
export const VC9A_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC9A");
|
|
@@ -275,6 +275,11 @@ export const VC8B_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC8B");
|
|
|
275
275
|
// import keeps resolving unchanged.
|
|
276
276
|
export { VC8C_ENABLED } from "./vector-cortex-vc8c.js";
|
|
277
277
|
|
|
278
|
+
// VC9A (setup-cortex status read path) extracted to vector-cortex-vc9a.ts to
|
|
279
|
+
// keep this file under the 300-line soft limit. Re-exported here so every
|
|
280
|
+
// existing `from "./config/vector-cortex.js"` import keeps resolving unchanged.
|
|
281
|
+
export { VC9A_ENABLED } from "./vector-cortex-vc9a.js";
|
|
282
|
+
|
|
278
283
|
// Breaker state machine constants (TRIAD_RESILIENCE.md §breaker) extracted to
|
|
279
284
|
// vector-cortex-breakers.ts to keep this file under the 300-line soft limit.
|
|
280
285
|
export {
|