pi-mega-compact 0.20.28 → 0.20.30
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-vc9d.js +32 -0
- package/dist/config/vector-cortex.js +2 -1
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +1 -0
- package/dist/extensions/dashboard-server/routes-setup-detect-cache.js +201 -0
- package/dist/extensions/dashboard-server/routes-setup.js +11 -83
- package/dist/src/config/vector-cortex-vc9d.js +32 -0
- package/dist/src/config/vector-cortex.js +2 -1
- package/dist/src/config.js +1 -1
- package/extensions/dashboard-client/dist/assets/{AreaChart-DIKsPqLG.js → AreaChart-EL8l2Fcj.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-DIKsPqLG.js.map → AreaChart-EL8l2Fcj.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-DeqN74Hn.js → BarChart-TrwfSh0w.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-DeqN74Hn.js.map → BarChart-TrwfSh0w.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-x1YU4tYc.js → CacheTab-C3KWDFDm.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-x1YU4tYc.js.map → CacheTab-C3KWDFDm.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-6BuEbd8Y.js → EventsTab-CNrT-b7t.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-6BuEbd8Y.js.map → EventsTab-CNrT-b7t.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-B71Ft1ac.js → HealthTab-CkBCFPk6.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-B71Ft1ac.js.map → HealthTab-CkBCFPk6.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-dysyJtHk.js → MaintenanceTab-CcbKszwx.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-dysyJtHk.js.map → MaintenanceTab-CcbKszwx.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-B3dKRb_4.js → MemoryMapTab-B2LvwScj.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-B3dKRb_4.js.map → MemoryMapTab-B2LvwScj.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-COn4GoUK.js → MetricsTab-Dv_xZtOG.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-COn4GoUK.js.map → MetricsTab-Dv_xZtOG.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-Cd9qAEB3.js → OverviewTab-D7xwhpOl.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-Cd9qAEB3.js.map → OverviewTab-D7xwhpOl.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-DpiP1-Vv.js → ReposTab-BfhiPXdA.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-DpiP1-Vv.js.map → ReposTab-BfhiPXdA.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-BwRUeGZM.js → SessionsTab-tQM0TQLp.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-BwRUeGZM.js.map → SessionsTab-tQM0TQLp.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-G-MkdQiR.js +3 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-G-MkdQiR.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-_XsdjQ7Z.js → TimeSavedCard-CYltysD3.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-_XsdjQ7Z.js.map → TimeSavedCard-CYltysD3.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-CWPscPLL.js → TurnsTab-1Y_Lpxx-.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-CWPscPLL.js.map → TurnsTab-1Y_Lpxx-.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{VcStatusBadge-Cx56rAIM.js → VcStatusBadge-BNHVeTG7.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{VcStatusBadge-Cx56rAIM.js.map → VcStatusBadge-BNHVeTG7.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{VectorCortexTab-B5ElUM7S.js → VectorCortexTab-goacPxL1.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{VectorCortexTab-B5ElUM7S.js.map → VectorCortexTab-goacPxL1.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{WikiTab-uZ5Mq3XG.js → WikiTab-DTOemYtE.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-uZ5Mq3XG.js.map → WikiTab-DTOemYtE.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-Kc18bYFz.js → button-B_4j_PVR.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-Kc18bYFz.js.map → button-B_4j_PVR.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-COJZoG08.js → card-Ce58rSXG.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-COJZoG08.js.map → card-Ce58rSXG.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-ChEYo017.js → generateCategoricalChart-DtNoJ6fZ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-ChEYo017.js.map → generateCategoricalChart-DtNoJ6fZ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-CB7Rn5FP.js → index-eoCm0uxj.js} +3 -3
- package/extensions/dashboard-client/dist/assets/{index-CB7Rn5FP.js.map → index-eoCm0uxj.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{switch-BFhl_tNh.js → switch-B9kM0N7R.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-BFhl_tNh.js.map → switch-B9kM0N7R.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-DJ68kATc.js → toggle-BwoHYpMa.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-DJ68kATc.js.map → toggle-BwoHYpMa.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-CXWh42xX.js → useSSE-DohG5AGv.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-CXWh42xX.js.map → useSSE-DohG5AGv.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetup.tsx +14 -2
- package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +6 -0
- package/extensions/dashboard-server/routes-setup-detect-cache.ts +224 -0
- package/extensions/dashboard-server/routes-setup.ts +19 -79
- package/package.json +1 -1
- package/src/config/vector-cortex-vc9d.ts +34 -0
- package/src/config/vector-cortex.ts +2 -1
- package/src/config.ts +1 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-CJFDD2_v.js +0 -3
- package/extensions/dashboard-client/dist/assets/SetupTab-CJFDD2_v.js.map +0 -1
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-server/routes-setup-detect-cache.ts — memoized embedder-barrier
|
|
3
|
+
* detection (VC9D).
|
|
4
|
+
*
|
|
5
|
+
* The three raw fresh detectors (`detectOllama` / `detectLlamaCpp` /
|
|
6
|
+
* `detectOnnx`) moved verbatim out of routes-setup.ts — they are the source of
|
|
7
|
+
* truth for "is this embedder backend present". Each also has a memoized
|
|
8
|
+
* sibling (`memoizedDetectOllama` / `memoizedDetectLlamaCpp` /
|
|
9
|
+
* `memoizedDetectOnnx`) that runs the expensive spawn ONLY when its mutable
|
|
10
|
+
* input changes, matching the `healthFactCacheKey` invalidation semantics from
|
|
11
|
+
* routes-vector-cortex-health.ts:71-122: the cache key is the resolved binary
|
|
12
|
+
* path + its size/mtime (onnx: resolved module path + package mtime), so an
|
|
13
|
+
* install/upgrade on PATH or in node_modules naturally invalidates the entry,
|
|
14
|
+
* while a steady environment reuses the result instead of re-spawning.
|
|
15
|
+
*
|
|
16
|
+
* A single module-level slot per target is shared across every
|
|
17
|
+
* /api/setup-detect request, so consecutive polls reuse the result.
|
|
18
|
+
*
|
|
19
|
+
* Guardrails: PREVENT-PI-004 (local subprocess + filesystem reads only, no
|
|
20
|
+
* network), PREVENT-011 (no `any`). Each decoration line carries a
|
|
21
|
+
* guardrails-allow annotation.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { spawnSync } from "node:child_process"; // guardrails-allow PREVENT-PI-004: local subprocess detection only
|
|
25
|
+
import { createRequire } from "node:module";
|
|
26
|
+
import { statSync } from "node:fs";
|
|
27
|
+
import type { DetectResult, OllamaDetectResult } from "./api-contracts/setup.js";
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Raw fresh detectors (moved verbatim from routes-setup.ts — single source).
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
export function detectOllama(): OllamaDetectResult | null {
|
|
34
|
+
try {
|
|
35
|
+
const version = spawnSync("ollama", ["--version"], {
|
|
36
|
+
timeout: 5000,
|
|
37
|
+
encoding: "utf-8",
|
|
38
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
39
|
+
});
|
|
40
|
+
if (version.status !== 0) {
|
|
41
|
+
return { installed: false, models: [], running: false, detail: version.stderr?.trim() || "not found" };
|
|
42
|
+
}
|
|
43
|
+
// Check for running server
|
|
44
|
+
let running = false;
|
|
45
|
+
let models: string[] = [];
|
|
46
|
+
try {
|
|
47
|
+
const listResult = spawnSync("ollama", ["list"], {
|
|
48
|
+
timeout: 5000,
|
|
49
|
+
encoding: "utf-8",
|
|
50
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
51
|
+
});
|
|
52
|
+
if (listResult.status === 0) {
|
|
53
|
+
running = true;
|
|
54
|
+
// Parse lines: NAME ID SIZE MODIFIED
|
|
55
|
+
const lines = listResult.stdout?.split("\n") ?? [];
|
|
56
|
+
for (const line of lines) {
|
|
57
|
+
const name = line.split(/\s+/)[0];
|
|
58
|
+
if (name && name !== "NAME") models.push(name);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
// ollama list failed — server may not be running
|
|
63
|
+
running = false;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
installed: true,
|
|
67
|
+
models,
|
|
68
|
+
running,
|
|
69
|
+
detail: version.stdout?.trim() || null,
|
|
70
|
+
};
|
|
71
|
+
} catch {
|
|
72
|
+
return { installed: false, models: [], running: false, detail: "detection error" };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function detectLlamaCpp(): DetectResult | null {
|
|
77
|
+
try {
|
|
78
|
+
const which = spawnSync("which", ["llama-server", "llama.cpp"], {
|
|
79
|
+
timeout: 3000,
|
|
80
|
+
encoding: "utf-8",
|
|
81
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
82
|
+
});
|
|
83
|
+
const installed = which.status === 0 && which.stdout.trim().length > 0;
|
|
84
|
+
return {
|
|
85
|
+
installed,
|
|
86
|
+
detail: installed ? which.stdout.trim() : null,
|
|
87
|
+
};
|
|
88
|
+
} catch {
|
|
89
|
+
return { installed: false, detail: "detection error" };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function detectOnnx(): DetectResult | null {
|
|
94
|
+
try {
|
|
95
|
+
// Check for onnxruntime-node in a parent node_modules
|
|
96
|
+
const req = createRequire(import.meta.url);
|
|
97
|
+
try {
|
|
98
|
+
req.resolve("onnxruntime-node");
|
|
99
|
+
return { installed: true, detail: "onnxruntime-node found in node_modules" };
|
|
100
|
+
} catch {
|
|
101
|
+
return { installed: false, detail: "onnxruntime-node not found in node_modules" };
|
|
102
|
+
}
|
|
103
|
+
} catch {
|
|
104
|
+
return { installed: false, detail: "detection error" };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
// Detect memo slot — generic, deterministic, unit-testable.
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
export interface DetectMemoSlot<V> {
|
|
113
|
+
/** Return the stored value when `key` matches the cached key, else null. */
|
|
114
|
+
get(key: string): V | null;
|
|
115
|
+
/** Store a value under a key. */
|
|
116
|
+
set(key: string, value: V): void;
|
|
117
|
+
/** Drop the cached entry. */
|
|
118
|
+
clear(): void;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** A single memo slot. `value` is never null for a detect result (objects only). */
|
|
122
|
+
export function createDetectMemo<V>(): DetectMemoSlot<V> {
|
|
123
|
+
let key: string | null = null;
|
|
124
|
+
let value: V | null = null;
|
|
125
|
+
return {
|
|
126
|
+
get(k: string): V | null {
|
|
127
|
+
return key !== null && key === k ? value : null;
|
|
128
|
+
},
|
|
129
|
+
set(k: string, v: V): void {
|
|
130
|
+
key = k;
|
|
131
|
+
value = v;
|
|
132
|
+
},
|
|
133
|
+
clear(): void {
|
|
134
|
+
key = null;
|
|
135
|
+
value = null;
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Run `compute` only when the derived key changes; a null key (inputs not
|
|
142
|
+
* resolvable — e.g. the binary is absent) is never cached, so every call runs
|
|
143
|
+
* the (cheap, fast-failing) detect fresh. This ordering is what the
|
|
144
|
+
* SETUP-CORTEX-030/031 fixtures pin: an unchanged key returns the stored value
|
|
145
|
+
* without re-running compute; a key mutation forces a recompute.
|
|
146
|
+
*/
|
|
147
|
+
export function withDetectMemo<V>(
|
|
148
|
+
slot: DetectMemoSlot<V>,
|
|
149
|
+
deriveKey: () => string | null,
|
|
150
|
+
compute: () => V,
|
|
151
|
+
): V {
|
|
152
|
+
const key = deriveKey();
|
|
153
|
+
const cached = key !== null ? slot.get(key) : null;
|
|
154
|
+
if (cached !== null) return cached;
|
|
155
|
+
const value = compute();
|
|
156
|
+
if (key !== null) slot.set(key, value);
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
// Mutable-input cache-key derivations.
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
|
|
164
|
+
/** Resolve the first PATH entry for a binary, or null when absent. */
|
|
165
|
+
function whichBin(bin: string): string | null {
|
|
166
|
+
const r = spawnSync("which", [bin], {
|
|
167
|
+
timeout: 3000,
|
|
168
|
+
encoding: "utf-8",
|
|
169
|
+
// guardrails-allow PREVENT-PI-004: local which lookup only
|
|
170
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
171
|
+
});
|
|
172
|
+
if (r.status !== 0 || !r.stdout) return null;
|
|
173
|
+
const first = r.stdout.trim().split("\n")[0]?.trim();
|
|
174
|
+
return first && first.length > 0 ? first : null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Key = resolved path + size + mtimeMs, so an install/upgrade invalidates. */
|
|
178
|
+
function fileKey(p: string | null): string | null {
|
|
179
|
+
if (p === null || p.length === 0) return null;
|
|
180
|
+
try {
|
|
181
|
+
const s = statSync(p);
|
|
182
|
+
return `${p}:${s.size}:${s.mtimeMs}`;
|
|
183
|
+
} catch {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Key = resolved module path + its package.json mtime (node_modules rebuild). */
|
|
189
|
+
function moduleKey(packageName: string): string | null {
|
|
190
|
+
try {
|
|
191
|
+
const req = createRequire(import.meta.url);
|
|
192
|
+
const resolved = req.resolve(packageName + "/package.json");
|
|
193
|
+
return fileKey(resolved);
|
|
194
|
+
} catch {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
// Memoized wrappers (shared module-level slots across requests).
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
|
|
203
|
+
const ollamaSlot = createDetectMemo<OllamaDetectResult | null>();
|
|
204
|
+
const llamaSlot = createDetectMemo<DetectResult | null>();
|
|
205
|
+
const onnxSlot = createDetectMemo<DetectResult | null>();
|
|
206
|
+
|
|
207
|
+
const ollamaKey = (): string | null => fileKey(whichBin("ollama"));
|
|
208
|
+
const llamaKey = (): string | null => fileKey(whichBin("llama-server") ?? whichBin("llama.cpp"));
|
|
209
|
+
const onnxKey = (): string | null => moduleKey("onnxruntime-node");
|
|
210
|
+
|
|
211
|
+
export function memoizedDetectOllama(): OllamaDetectResult | null {
|
|
212
|
+
// guardrails-allow PREVENT-PI-004: local subprocess detection only
|
|
213
|
+
return withDetectMemo(ollamaSlot, ollamaKey, detectOllama);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function memoizedDetectLlamaCpp(): DetectResult | null {
|
|
217
|
+
// guardrails-allow PREVENT-PI-004: local subprocess detection only
|
|
218
|
+
return withDetectMemo(llamaSlot, llamaKey, detectLlamaCpp);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function memoizedDetectOnnx(): DetectResult | null {
|
|
222
|
+
// guardrails-allow PREVENT-PI-004: local module resolution only
|
|
223
|
+
return withDetectMemo(onnxSlot, onnxKey, detectOnnx);
|
|
224
|
+
}
|
|
@@ -9,12 +9,19 @@
|
|
|
9
9
|
* Each decoration line carries a guardrails-allow annotation.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { spawnSync } from "node:child_process"; // guardrails-allow PREVENT-PI-004: local subprocess detection only
|
|
13
|
-
import { createRequire } from "node:module";
|
|
14
12
|
import { writeFileSync, mkdirSync, readFileSync, existsSync } from "node:fs";
|
|
15
13
|
import { join } from "node:path";
|
|
16
14
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
17
15
|
import type { RouteContext } from "./routes-core.js";
|
|
16
|
+
import { VC9D_ENABLED } from "../../src/config.js";
|
|
17
|
+
import {
|
|
18
|
+
detectOllama,
|
|
19
|
+
detectLlamaCpp,
|
|
20
|
+
detectOnnx,
|
|
21
|
+
memoizedDetectOllama,
|
|
22
|
+
memoizedDetectLlamaCpp,
|
|
23
|
+
memoizedDetectOnnx,
|
|
24
|
+
} from "./routes-setup-detect-cache.js";
|
|
18
25
|
import type {
|
|
19
26
|
SetupStatusResponse,
|
|
20
27
|
SetupDetectResponse,
|
|
@@ -91,80 +98,10 @@ export function handleSetupStatus(
|
|
|
91
98
|
// handleSetupDetect — "/api/setup-detect"
|
|
92
99
|
// ---------------------------------------------------------------------------
|
|
93
100
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
encoding: "utf-8",
|
|
99
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
100
|
-
});
|
|
101
|
-
if (version.status !== 0) {
|
|
102
|
-
return { installed: false, models: [], running: false, detail: version.stderr?.trim() || "not found" };
|
|
103
|
-
}
|
|
104
|
-
// Check for running server
|
|
105
|
-
let running = false;
|
|
106
|
-
let models: string[] = [];
|
|
107
|
-
try {
|
|
108
|
-
const listResult = spawnSync("ollama", ["list"], {
|
|
109
|
-
timeout: 5000,
|
|
110
|
-
encoding: "utf-8",
|
|
111
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
112
|
-
});
|
|
113
|
-
if (listResult.status === 0) {
|
|
114
|
-
running = true;
|
|
115
|
-
// Parse lines: NAME ID SIZE MODIFIED
|
|
116
|
-
const lines = listResult.stdout?.split("\n") ?? [];
|
|
117
|
-
for (const line of lines) {
|
|
118
|
-
const name = line.split(/\s+/)[0];
|
|
119
|
-
if (name && name !== "NAME") models.push(name);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
} catch {
|
|
123
|
-
// ollama list failed — server may not be running
|
|
124
|
-
running = false;
|
|
125
|
-
}
|
|
126
|
-
return {
|
|
127
|
-
installed: true,
|
|
128
|
-
models,
|
|
129
|
-
running,
|
|
130
|
-
detail: version.stdout?.trim() || null,
|
|
131
|
-
};
|
|
132
|
-
} catch {
|
|
133
|
-
return { installed: false, models: [], running: false, detail: "detection error" };
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function detectLlamaCpp(): DetectResult | null {
|
|
138
|
-
try {
|
|
139
|
-
const which = spawnSync("which", ["llama-server", "llama.cpp"], {
|
|
140
|
-
timeout: 3000,
|
|
141
|
-
encoding: "utf-8",
|
|
142
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
143
|
-
});
|
|
144
|
-
const installed = which.status === 0 && which.stdout.trim().length > 0;
|
|
145
|
-
return {
|
|
146
|
-
installed,
|
|
147
|
-
detail: installed ? which.stdout.trim() : null,
|
|
148
|
-
};
|
|
149
|
-
} catch {
|
|
150
|
-
return { installed: false, detail: "detection error" };
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function detectOnnx(): DetectResult | null {
|
|
155
|
-
try {
|
|
156
|
-
// Check for onnxruntime-node in a parent node_modules
|
|
157
|
-
const req = createRequire(import.meta.url);
|
|
158
|
-
try {
|
|
159
|
-
req.resolve("onnxruntime-node");
|
|
160
|
-
return { installed: true, detail: "onnxruntime-node found in node_modules" };
|
|
161
|
-
} catch {
|
|
162
|
-
return { installed: false, detail: "onnxruntime-node not found in node_modules" };
|
|
163
|
-
}
|
|
164
|
-
} catch {
|
|
165
|
-
return { installed: false, detail: "detection error" };
|
|
166
|
-
}
|
|
167
|
-
}
|
|
101
|
+
// Detection bodies live in routes-setup-detect-cache.ts (single source). When
|
|
102
|
+
// MEGACOMPACT_VC9D is ON the memoized wrappers reuse the result across requests
|
|
103
|
+
// (keyed by the mutable input: resolved binary path + mtime); when OFF we call
|
|
104
|
+
// the raw fresh detectors — byte-identical to the VC9C-era per-request spawn.
|
|
168
105
|
|
|
169
106
|
export function handleSetupDetect(
|
|
170
107
|
req: IncomingMessage,
|
|
@@ -183,20 +120,23 @@ export function handleSetupDetect(
|
|
|
183
120
|
let llamaCpp: DetectResult | null = null;
|
|
184
121
|
let onnx: DetectResult | null = null;
|
|
185
122
|
|
|
123
|
+
// guardrails-allow PREVENT-PI-004: local subprocess detection only (memoized or fresh)
|
|
124
|
+
const cached = VC9D_ENABLED();
|
|
125
|
+
|
|
186
126
|
try {
|
|
187
|
-
ollama = detectOllama();
|
|
127
|
+
ollama = cached ? memoizedDetectOllama() : detectOllama();
|
|
188
128
|
} catch (e) {
|
|
189
129
|
error = `ollama detection failed: ${e instanceof Error ? e.message : String(e)}`;
|
|
190
130
|
}
|
|
191
131
|
|
|
192
132
|
try {
|
|
193
|
-
llamaCpp = detectLlamaCpp();
|
|
133
|
+
llamaCpp = cached ? memoizedDetectLlamaCpp() : detectLlamaCpp();
|
|
194
134
|
} catch (e) {
|
|
195
135
|
error = error ?? `llama.cpp detection failed: ${e instanceof Error ? e.message : String(e)}`;
|
|
196
136
|
}
|
|
197
137
|
|
|
198
138
|
try {
|
|
199
|
-
onnx = detectOnnx();
|
|
139
|
+
onnx = cached ? memoizedDetectOnnx() : detectOnnx();
|
|
200
140
|
} catch (e) {
|
|
201
141
|
error = error ?? `onnx detection failed: ${e instanceof Error ? e.message : String(e)}`;
|
|
202
142
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-mega-compact",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.30",
|
|
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,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config/vector-cortex-vc9d.ts — VC9D embedder-detect consolidation 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-vc9a.ts..vector-cortex-vc9c.ts
|
|
6
|
+
* were. This is the SETUP-DASHBOARD consolidation flag (the embedder-detect
|
|
7
|
+
* memoization + the shared 5s embedder poll). vector-cortex.ts re-exports it
|
|
8
|
+
* below and root src/config.ts re-exports it, so no consumer import path
|
|
9
|
+
* changes.
|
|
10
|
+
*
|
|
11
|
+
* The split is purely mechanical: VC9D_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
|
+
* VC9D — embedder detect consolidation + conformance roll-up. Default ON.
|
|
23
|
+
* `MEGACOMPACT_VC9D=0` disables and is byte-identical to the predecessor
|
|
24
|
+
* (VC9C-era): /api/setup-detect spawns its detectors fresh per request (no
|
|
25
|
+
* memoization) and the embedder sub-tab keeps its previous poll cadence. When
|
|
26
|
+
* ON, the detect path is memoized against the mutable input (resolved binary
|
|
27
|
+
* path + mtime) so consecutive requests reuse the result without re-spawning,
|
|
28
|
+
* and the embedder + cortex sub-tabs share the 5s poll contract. Detection is
|
|
29
|
+
* READ-ONLY — local binary spawns + filesystem stat only, no network
|
|
30
|
+
* (PREVENT-PI-004), never payload bytes/prompts/ledger (EVAL-REDACT-002). This
|
|
31
|
+
* flag MUST also be a dashboard SETTINGS toggle (visible in config UI, never in
|
|
32
|
+
* EXCLUDED_SETTINGS), mirroring VC9A/VC9B/VC9C.
|
|
33
|
+
*/
|
|
34
|
+
export const VC9D_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC9D");
|
|
@@ -275,10 +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/VC9B/VC9C split to vector-cortex-vc9{a,b,c}.ts to stay under the 300-line soft limit.
|
|
278
|
+
// VC9A/VC9B/VC9C/VC9D split to vector-cortex-vc9{a,b,c,d}.ts to stay under the 300-line soft limit.
|
|
279
279
|
export { VC9A_ENABLED } from "./vector-cortex-vc9a.js";
|
|
280
280
|
export { VC9B_ENABLED } from "./vector-cortex-vc9b.js";
|
|
281
281
|
export { VC9C_ENABLED } from "./vector-cortex-vc9c.js";
|
|
282
|
+
export { VC9D_ENABLED } from "./vector-cortex-vc9d.js";
|
|
282
283
|
|
|
283
284
|
// Breaker state machine constants (TRIAD_RESILIENCE.md §breaker) extracted to
|
|
284
285
|
// vector-cortex-breakers.ts to keep this file under the 300-line soft limit.
|
package/src/config.ts
CHANGED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{r as n,j as e,h as z,i as F,k as G,p as K,l as Q,m as J,C as Y,n as Z,o as ee,q as te,s as se,t as ne,v as re,w as ae,x as le,y as oe}from"./index-CB7Rn5FP.js";import{S as ie}from"./switch-BFhl_tNh.js";import{V as ce}from"./VcStatusBadge-Cx56rAIM.js";import{T as de}from"./toggle-DJ68kATc.js";function me(t){try{return new Date(t*1e3).toLocaleString()}catch{return"—"}}function H({achievements:t}){const r=n.useRef(0),[s,l]=n.useState(null),a=t.reduce((o,d)=>Math.max(o,d.unlocked_at??0),0),c=r.current;n.useEffect(()=>{a>r.current&&(r.current=a)},[a]),n.useEffect(()=>{if(c>0&&a>c){const o=t.filter(d=>d.unlocked_at!=null&&(d.unlocked_at??0)>c);if(o.length>0){const d=o.map(m=>`${m.icon??""} ${m.title}`.trim()).join(", ")+" unlocked!";l(d);const g=setTimeout(()=>l(null),4e3);return()=>clearTimeout(g)}}},[t,a,c]);const f=t.filter(o=>!(o.hidden===1&&o.unlocked_at==null));return e.jsxs("div",{className:"ach-section",children:[s!=null&&e.jsx("div",{className:"ach-toast show",children:s}),e.jsxs("div",{className:"ach-tiles",children:[f.length===0&&e.jsx("span",{className:"repo-none",children:"no achievements yet"}),f.map(o=>{if(o.unlocked_at!=null){const d=c>0&&(o.unlocked_at??0)>c;return e.jsxs("div",{className:`ach-tile unlocked${d?" just-unlocked":""}`,children:[o.icon??""," ",o.title,e.jsxs("span",{className:"ach-detail",children:["unlocked ",me(o.unlocked_at)]})]},o.id)}return e.jsxs("div",{className:"ach-tile locked",children:["??? ",o.title]},o.id)})]})]})}function B(t){return(Math.round(t*10)/10).toString()+"%"}function O(t){return t!=null?new Date(t).toLocaleString():"—"}function D(t){return t&&typeof t=="object"?t:{}}function ue(t){return t.split("/").pop()||t}function I({title:t,rows:r,badge:s,renderValue:l}){return e.jsxs("div",{className:"lb-card",children:[e.jsxs("h3",{children:[t,s]}),r.length===0?e.jsx("div",{className:"lb-empty",children:"—"}):e.jsx("table",{children:e.jsx("tbody",{children:r.map((a,c)=>e.jsxs("tr",{children:[e.jsx("td",{title:a.repo_root,children:ue(a.repo_root)}),e.jsx("td",{className:"num",children:l(a)})]},`${a.repo_root}-${c}`))})})]})}function he(){const[t,r]=n.useState({}),[s,l]=n.useState(0),[a,c]=n.useState([]),[f,o]=n.useState(!1),[d,g]=n.useState(!0),[m,x]=n.useState(null),i=n.useRef(0),u=n.useCallback(async()=>{try{const[y,w,p,k,T,X]=await Promise.all([z({metric:"cache",limit:25}),z({metric:"dedupe",limit:25}),z({metric:"turns",limit:25}),z({metric:"mega_cache",limit:25}),z({metric:"repos",limit:1}),F()]),W=k.find(A=>A.ts>i.current&&A.value>100);i.current>0&&W&&(x(`oopsie! cache went to ${Math.round(W.value)}% — MEGA CACHE 🥧`),setTimeout(()=>x(null),4e3)),k.length>0&&(i.current=Math.max(...k.map(A=>A.ts))),r({cache:y,dedupe:w,turns:p,mega_cache:k}),l(T[0]?.value??0),c(X)}catch{}finally{g(!1)}},[]);n.useEffect(()=>{let y=!0;const w=async()=>{y&&await u()};w();const p=setInterval(()=>void w(),15e3);return()=>{y=!1,clearInterval(p)}},[u]),n.useEffect(()=>{let y=!0;const w=async()=>{try{const k=await G();y&&(o(!!k.game_mode_on),k.theme&&(document.documentElement.dataset.theme=k.theme))}catch{}};w();const p=setInterval(()=>void w(),15e3);return()=>{y=!1,clearInterval(p)}},[]);const j=t.mega_cache??[];let v=null,N=null;for(const y of j){(v==null||y.value>v)&&(v=y.value);const w=D(y.meta),p=w.firstSeenTs??w.firstSeen??y.ts;(N==null||p<N)&&(N=p)}const C=v!=null&&v>100,S=t.turns??[],M=S.reduce((y,w)=>Math.max(y,w.value),0),_=Math.floor(Math.log2(M+1))+1,L=(t.cache?.length??0)>0||(t.dedupe?.length??0)>0||S.length>0||j.length>0||s>0;return e.jsxs("div",{className:`game-tab${f?" game-mode-on":""}`,children:[m!=null&&e.jsx("div",{className:"mega-cache-toast show",children:m}),C&&e.jsxs("div",{className:"mega-cache-banner",children:["🥧"," MEGA CACHE! peak ",B(v)," — first reached ",O(N)]}),C&&e.jsxs("div",{className:"achievement-tile unlocked",children:["🏆"," Opie's Wild Ride",e.jsxs("span",{className:"ach-detail",children:["best ",B(v)," · first ",O(N)]})]}),e.jsx("h2",{children:"High Scores"}),!L&&!d&&e.jsx("div",{className:"game-empty",children:"No scores yet — run a session with game mode on."}),L&&e.jsxs("div",{className:"game-leaderboards",children:[e.jsx(I,{title:"Cache %",rows:t.cache??[],renderValue:y=>B(y.value)}),e.jsx(I,{title:"Dedupe (collapsed)",rows:t.dedupe??[],renderValue:y=>y.value.toLocaleString()}),e.jsx(I,{title:"Turns",rows:S,badge:S.length>0?e.jsxs("span",{className:"lvl-badge",children:["LVL ",_]}):void 0,renderValue:y=>y.value.toLocaleString()}),e.jsx(I,{title:"MEGA CACHE trophies",rows:j,renderValue:y=>e.jsxs(e.Fragment,{children:[B(y.value),e.jsx("span",{className:"lb-meta",children:O(D(y.meta).firstSeenTs??D(y.meta).firstSeen??y.ts)})]})})]}),s>0&&e.jsx("div",{className:"repos-badge-line",children:e.jsxs("span",{className:"repos-badge",children:[s," repos"]})}),e.jsx("h3",{children:"Achievements"}),e.jsx(H,{achievements:a})]})}function fe(){const[t,r]=n.useState([]),[s,l]=n.useState(!0),[a,c]=n.useState(null),f=n.useCallback(async()=>{try{const o=await F();r(o),c(null)}catch(o){c(o instanceof Error?o:new Error(String(o)))}finally{l(!1)}},[]);return n.useEffect(()=>{let o=!0;const d=async()=>{o&&await f()};d();const g=setInterval(()=>void d(),15e3);return()=>{o=!1,clearInterval(g)}},[f]),s&&t.length===0?e.jsx("div",{className:"tab-stub",children:"Loading achievements…"}):a&&t.length===0?e.jsxs("div",{className:"tab-stub",children:["Error: ",a.message]}):e.jsxs("div",{className:"achievements-tab",children:[e.jsx("h2",{children:"Achievements"}),e.jsx(H,{achievements:t})]})}const q=[{id:"transparent",label:"Transparent (accents only)",css:{bg:null,fg:"#c9d1d9",accent:"#3fb950",mega:"#f0883e"},ansi:{bg:null,fg:"39",accent:"32",mega:"33"}},{id:"retro",label:"Retro 8-bit green",css:{bg:"#003300",fg:"#33ff33",accent:"#00ff41",mega:"#39ff14"},ansi:{bg:"40",fg:"92",accent:"92",mega:"1;92"}},{id:"orange-bold",label:"Orange bold",css:{bg:"#1a0f00",fg:"#ff8c00",accent:"#ff6b00",mega:"#ff4500"},ansi:{bg:"48;5;52",fg:"38;5;208",accent:"38;5;208",mega:"1;38;5;202"}},{id:"cyan-neon",label:"Cyan neon",css:{bg:"#001a1a",fg:"#00ffff",accent:"#22d3ee",mega:"#7df9ff"},ansi:{bg:"48;5;23",fg:"38;5;51",accent:"38;5;51",mega:"1;38;5;51"}},{id:"amber-mono",label:"Amber phosphor",css:{bg:"#1a1200",fg:"#ffb000",accent:"#ff8c00",mega:"#ff5500"},ansi:{bg:"48;5;58",fg:"38;5;214",accent:"38;5;214",mega:"1;38;5;208"}},{id:"grayscale",label:"Grayscale minimal",css:{bg:"#161616",fg:"#b0b0b0",accent:"#8b949e",mega:"#e6edf3"},ansi:{bg:"48;5;235",fg:"38;5;249",accent:"38;5;249",mega:"1;38;5;255"}}],$=q.map(t=>t.id),E={gameMode:"Turn game mode on/off (themes the widget + dashboard)",theme:"Visual theme (applies instantly)",tuiMode:"TUI widget display density",tier:"Live pressure band — climbs low→mega as context fills the window.",preset:"The env-resolved base compaction preset (low/medium/high/ultra/mega) that set the token threshold.",pressure:"Live pressure = currentTokens / threshold — % of the model context window (threshold fires at the tier's % of window).",threshold:"Compaction threshold = tierPct × model context window — mega-compact trims BELOW pi's native ~80% auto-compact for any model size.",fastGate:"Fast-gate arming floor — the live trim arms once context passes this % of the window."};function ge(t,r,s){let l=t.toLocaleString();return r!=null&&s>0&&(l+=` (${Math.round(r*100)}% of ${s.toLocaleString()})`),l}function xe(t){return`${Math.round((t||0)*100)}%`}function pe(){const[t,r]=n.useState(null),[s,l]=n.useState(null),[a,c]=n.useState(!1);n.useEffect(()=>{let i=!0;const u=async()=>{try{const v=await Q();i&&r(v)}catch{}};u();const j=setInterval(()=>void u(),5e3);return()=>{i=!1,clearInterval(j)}},[]),n.useEffect(()=>{let i=!0;const u=async()=>{try{const v=await G();i&&(l(v),v.theme&&(document.documentElement.dataset.theme=v.theme))}catch{}};u();const j=setInterval(()=>void u(),5e3);return()=>{i=!1,clearInterval(j)}},[]);const f=n.useCallback(async i=>{c(!0);try{const u=await K(i);l(u),u.theme&&(document.documentElement.dataset.theme=u.theme)}catch{}c(!1)},[]),o=s?.game_mode_on??!1,d=s?.theme??"transparent",g=s?.tui_display_mode??"full",m=t?.config,x=t?.context.contextWindow??0;return e.jsxs("div",{className:"config-tab",children:[e.jsxs("section",{className:"config-settings",children:[e.jsx("h3",{children:"Settings"}),e.jsx("div",{className:"settings-row",children:e.jsxs("label",{title:E.gameMode,children:[e.jsx("input",{type:"checkbox",checked:o,onChange:i=>f({game_mode_on:i.currentTarget.checked}),disabled:a}),"Game Mode"]})}),e.jsx("div",{className:"settings-row",children:e.jsxs("label",{title:E.theme,children:["Theme",e.jsx("select",{value:d,onChange:i=>f({theme:i.currentTarget.value}),disabled:a,children:q.map(i=>e.jsx("option",{value:i.id,children:i.label},i.id))}),e.jsx("button",{type:"button",disabled:a,className:"theme-cycle-btn",title:"Cycle to the next theme (P3)",onClick:()=>{const i=$.indexOf(d),u=$[(i<0?0:i+1)%$.length];u&&f({theme:u})},children:"Next theme →"})]})}),e.jsx("div",{className:"settings-row",children:e.jsxs("label",{title:E.tuiMode,children:["TUI Mode",e.jsxs("select",{value:g,onChange:i=>f({tui_display_mode:i.currentTarget.value}),disabled:a,children:[e.jsx("option",{value:"full",children:"Full"}),e.jsx("option",{value:"minimal",children:"Minimal"})]})," ",e.jsx("span",{className:"tui-mode-hint",children:"(affects the in-app TUI widget; not shown here)"})]})})]}),e.jsxs("section",{className:"config-display",children:[e.jsx("h3",{children:"Configuration"}),e.jsxs("div",{className:"config-grid",children:[e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:E.tier,children:"Tier"}),e.jsx("span",{className:"config-value",children:t?`${t.tier} (live)`:"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:E.preset,children:"Preset"}),e.jsx("span",{className:"config-value",children:t?.presetTier??"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:E.pressure,children:"Pressure"}),e.jsx("span",{className:"config-value",children:t?xe(t.pressure):"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:E.threshold,children:"Threshold"}),e.jsx("span",{className:"config-value",children:m?ge(m.thresholdTokens,m.tierPct,x):"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:E.fastGate,children:"Fast Gate"}),e.jsx("span",{className:"config-value",children:m?`${m.fastGatePct}%`:"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",children:"Auto"}),e.jsx("span",{className:"config-value",children:m?m.auto?"enabled":"disabled":"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",children:"Anchor"}),e.jsx("span",{className:"config-value",children:m?.anchorUserMessages??"—"})]})]})]})]})}const R={section:{background:"#1a1a2e",borderRadius:"8px",padding:"1rem",marginBottom:"1rem",border:"1px solid #2a2a4e"},sectionTitle:{fontSize:"1.1rem",fontWeight:700,marginTop:0,marginBottom:"0.75rem",color:"#e0e0e0",borderBottom:"1px solid #333",paddingBottom:"0.5rem"},label:{fontWeight:600,color:"#a0a0c0",marginRight:"0.5rem"},value:{color:"#e0e0e0"},row:{marginBottom:"0.4rem",fontSize:"0.9rem"}};function be(){const[t,r]=n.useState(null),[s,l]=n.useState(null),a=n.useCallback(()=>{J().then(r).catch(g=>l(g instanceof Error?g.message:String(g)))},[]);n.useEffect(()=>{a()},[a]),n.useEffect(()=>{const g=setInterval(a,3e4);return()=>clearInterval(g)},[a]);const c=t?.status==="ok",f=t?.status==="ok"?"Working":t?.status==="unreachable"?"Unreachable":"Error",o=c?"#4caf50":"#f44336",d=c?"✓":"✗";return e.jsxs("div",{style:R.section,children:[e.jsx("h3",{style:R.sectionTitle,children:"Embedder Health"}),s&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",s]}),!t&&!s&&e.jsx("p",{style:{color:"#888",fontSize:"0.85rem"},children:"Probing embedder..."}),t&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:R.row,children:[e.jsxs("span",{style:{...R.label,color:`${o}`},children:[d," ",f,":"]}),e.jsxs("span",{style:R.value,children:[t.dim," dims"]}),t.latencyMs!==void 0&&e.jsxs("span",{style:{color:"#a0a0c0",marginLeft:"0.5rem"},children:["(",t.latencyMs.toFixed(1)," ms)"]})]}),e.jsxs("div",{style:R.row,children:[e.jsx("span",{style:R.label,children:"Endpoint:"}),e.jsx("span",{style:R.value,children:t.url??e.jsx("span",{style:{color:"#888"},children:"built-in (no URL)"})})]}),t.error&&e.jsx("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:t.error})]})]})}function je({title:t,children:r}){const[s,l]=n.useState(!0),a=`settings-${t.toLowerCase().replace(/[^a-z0-9]+/g,"-")}`;return e.jsxs("section",{className:"overflow-hidden rounded-xl border border-border bg-bg-elevated/40",children:[e.jsxs("button",{type:"button",onClick:()=>l(c=>!c),className:"flex w-full items-center justify-between rounded-t-xl bg-bg-elevated/60 px-4 py-3 text-left text-sm font-semibold text-foreground transition-colors hover:bg-bg-elevated","aria-expanded":s,"aria-controls":a,children:[e.jsx("span",{children:t}),e.jsx(Y,{className:Z("h-4 w-4 text-muted-foreground transition-transform",s&&"rotate-180"),"aria-hidden":"true"})]}),s&&e.jsx("div",{id:a,className:"divide-y divide-border px-4 py-1",children:r})]})}const ye="rounded-md border border-border bg-bg-elevated/50 px-2 py-1 text-sm outline-none transition-colors focus:border-primary disabled:cursor-not-allowed disabled:opacity-50";function ve(){return e.jsx("span",{className:"ml-2 inline-flex items-center rounded-md border border-warning/40 bg-warning/15 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-warning",title:"Requires an LLM embedder (Ollama/HTTP) to be effective",children:"LLM"})}function Se({setting:t,id:r,llmActive:s,saving:l,onUpdate:a}){const[c,f]=n.useState(null),o=t.requiresLlm&&!s,d=n.useRef(null);n.useEffect(()=>()=>{d.current&&clearTimeout(d.current)},[]);const g=n.useCallback(i=>{a(t.key,i).then(u=>f(u)).catch(u=>f(u instanceof Error?u.message:String(u)))},[a,t.key]),m=n.useCallback(i=>{d.current&&clearTimeout(d.current),d.current=setTimeout(()=>g(i),500)},[g]),x=l||o;return e.jsxs("div",{className:"py-2.5",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center text-sm font-semibold text-foreground",children:[e.jsx("label",{htmlFor:`${r}-input`,className:"cursor-pointer",children:t.label}),t.requiresLlm&&!s&&e.jsx(ve,{})]}),e.jsx("div",{className:"mt-0.5 text-xs text-muted-foreground",children:t.description})]}),e.jsx("div",{className:"flex shrink-0 items-center gap-2",children:t.type==="boolean"?e.jsx(ie,{id:`${r}-input`,checked:!!t.value,disabled:x||o,onCheckedChange:i=>g(String(i)),"aria-label":t.label}):e.jsxs(e.Fragment,{children:[e.jsx("input",{id:`${r}-input`,type:t.type==="number"?"number":"text",defaultValue:String(t.value??""),min:t.min,max:t.max,disabled:x,onChange:i=>m(i.target.value),className:`${ye} ${t.type==="number"?"w-24":"w-56"}`}),t.unit&&e.jsx("span",{className:"text-xs text-muted-foreground",children:t.unit})]})})]}),c&&e.jsxs("p",{className:"mt-1 text-xs text-danger",children:["Error: ",c]})]})}function we(){const[t,r]=n.useState(null),[s,l]=n.useState(null),[a,c]=n.useState(!1),[f,o]=n.useState(null),d=n.useCallback(()=>{ee().then(r).catch(m=>l(m instanceof Error?m.message:String(m)))},[]);n.useEffect(()=>{d()},[d]);const g=n.useCallback(async(m,x)=>{c(!0);try{const i=await te({key:m,value:x});return o(i.restartRequired?"Saved — restart pi to apply changes.":"Saved."),d(),null}catch(i){return i instanceof Error?i.message:String(i)}finally{c(!1)}},[d]);return e.jsxs("div",{className:"flex flex-col gap-3",children:[s&&e.jsxs("p",{className:"text-sm text-danger",children:["Error: ",s]}),!t&&!s&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading settings..."}),t?.categories.map(m=>e.jsx(je,{title:m.name,children:m.settings.map(x=>e.jsx(Se,{setting:x,id:`${m.name.replace(/[^a-z0-9]+/gi,"-")}-${x.key}`,llmActive:t.llmActive,saving:a,onUpdate:g},x.key))},m.name)),f&&e.jsx("div",{className:"mt-1 rounded-md border border-warning/40 bg-warning/10 p-2 text-xs text-warning",role:"status",children:f})]})}const h={container:{padding:"1rem",maxWidth:"720px",margin:"0 auto",fontFamily:"system-ui, sans-serif",color:"#e0e0e0"},section:{background:"#1a1a2e",borderRadius:"8px",padding:"1rem",marginBottom:"1rem",border:"1px solid #2a2a4e"},sectionTitle:{fontSize:"1.1rem",fontWeight:700,marginTop:0,marginBottom:"0.75rem",color:"#e0e0e0",borderBottom:"1px solid #333",paddingBottom:"0.5rem"},label:{fontWeight:600,color:"#a0a0c0",marginRight:"0.5rem"},value:{color:"#e0e0e0"},row:{marginBottom:"0.4rem",fontSize:"0.9rem"},warning:{background:"#3a2a00",border:"1px solid #665500",borderRadius:"8px",padding:"0.75rem",marginTop:"0.5rem",color:"#ffcc00",fontSize:"0.85rem"},badge:{display:"inline-block",padding:"0.15rem 0.5rem",borderRadius:"4px",fontSize:"0.8rem",fontWeight:600,marginLeft:"0.5rem"},detectRow:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"0.5rem 0",borderBottom:"1px solid #2a2a4e"},button:{background:"#3a5a9f",color:"#fff",border:"none",borderRadius:"6px",padding:"0.5rem 1rem",cursor:"pointer",fontSize:"0.9rem",fontWeight:600}};function Ne({customUrl:t,setCustomUrl:r,applyEmbedder:s,configuring:l}){return e.jsxs("div",{style:h.section,children:[e.jsx("h3",{style:h.sectionTitle,children:"Custom Endpoint (remote / third-party)"}),e.jsxs("p",{style:{fontSize:"0.85rem",color:"#a0a0c0",marginTop:0},children:["Point at any OpenAI-compatible embeddings API or hosted endpoint. This opts in to a non-loopback connection (sets"," ",e.jsx("code",{children:"MEGACOMPACT_ALLOW_REMOTE_EMBEDDER=1"}),") — your prompts' embedding requests will be sent to the URL you enter. Default is loopback-only."]}),e.jsxs("div",{style:{display:"flex",gap:"0.5rem",flexWrap:"wrap",alignItems:"center"},children:[e.jsx("input",{type:"url",placeholder:"https://api.example.com/v1/embeddings",value:t,onChange:a=>r(a.target.value),style:{flex:"1 1 300px",background:"#12122a",color:"#e0e0e0",border:"1px solid #2a2a4e",borderRadius:"6px",padding:"0.4rem 0.6rem",fontSize:"0.85rem",fontFamily:"monospace"}}),e.jsx("button",{style:{...h.button,opacity:t?1:.4},onClick:()=>s("custom",t),disabled:!t||l!==null,children:l==="custom"?"Writing...":"Use Custom URL"})]}),e.jsxs("div",{style:h.warning,children:[e.jsx("strong",{children:"Heads up:"})," a remote endpoint receives the text you embed (it does NOT receive your full conversation — only the strings passed to",e.jsx("code",{children:" embed()"})," for recall/dedup). Verify the endpoint's privacy policy before use."]})]})}function ke(){const[t,r]=n.useState(null),[s,l]=n.useState(null),[a,c]=n.useState(null),[f,o]=n.useState(null),[d,g]=n.useState(!1),[m,x]=n.useState(null),[i,u]=n.useState(null),[j,v]=n.useState(null),[N,C]=n.useState(""),S=n.useCallback(()=>{se().then(r).catch(p=>c(p instanceof Error?p.message:String(p)))},[]),M=n.useCallback((p,k)=>{x(p),v(null),u(null),ne({embedder:p,url:k}).then(T=>{u(T),x(null),S()}).catch(T=>{v(T instanceof Error?T.message:String(T)),x(null)})},[S]),_=n.useCallback(()=>{g(!0),o(null),re().then(p=>{l(p),g(!1)}).catch(p=>{o(p instanceof Error?p.message:String(p)),g(!1)})},[]);n.useEffect(()=>{S()},[S]),n.useEffect(()=>{const p=setInterval(S,3e4);return()=>clearInterval(p)},[S]);const L=p=>{switch(p){case"trigram":return"TrigramEmbedder (heuristic, default)";case"http":return"HTTP Embedder (BYO localhost)";case"minilm":return"MiniLM (experimental)";default:return"Unknown"}},y=t?.currentEmbedder==="trigram"&&e.jsxs("div",{style:h.warning,children:[e.jsx("strong",{children:"Note:"})," TrigramEmbedder is a heuristic-strength default embedder. It works without any setup but recall quality may be lower than a dedicated embedding backend. If you notice poor recall results, consider installing Ollama and running the"," ",e.jsx("code",{children:"/megasetup"})," command, or set"," ",e.jsx("code",{children:"MEGACOMPACT_EMBEDDING_URL"})," to point at your own localhost embedding server."]}),w=p=>{const k=p?"#1a5a1a":"#3a1a1a",T=p?"#4caf50":"#f44336";return e.jsx("span",{style:{...h.badge,background:k,color:T},children:p?"Detected":"Not found"})};return e.jsxs("div",{style:h.container,children:[e.jsx("h2",{style:{fontSize:"1.3rem",marginTop:0,marginBottom:"1rem"},children:"Embedder Setup"}),e.jsx(be,{}),e.jsxs("div",{style:h.section,children:[e.jsx("h3",{style:h.sectionTitle,children:"Current Embedder Configuration"}),a&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",a]}),t&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:h.row,children:[e.jsx("span",{style:h.label,children:"Active Embedder:"}),e.jsx("span",{style:h.value,children:L(t.currentEmbedder)})]}),"configuredEmbedder"in t&&t.configuredEmbedder!==t.currentEmbedder&&e.jsxs("div",{style:h.warning,children:[e.jsx("strong",{children:"Configured but not active:"})," ",L(t.configuredEmbedder)," is configured in .mega-compact.env but not yet loaded."," ",e.jsx("strong",{children:"Restart pi"})," to activate it.",t.configuredUrl&&e.jsxs(e.Fragment,{children:[" (",t.configuredUrl,")"]})]}),"restartRequired"in t&&t.restartRequired&&e.jsxs("div",{style:{...h.row,color:"#ff9800"},children:[e.jsx("span",{style:h.label,children:"Status:"}),e.jsx("span",{style:h.value,children:"Restart required to activate the configured embedder"})]}),e.jsxs("div",{style:h.row,children:[e.jsx("span",{style:h.label,children:"Embedding URL:"}),e.jsx("span",{style:h.value,children:t.embeddingUrl??e.jsx("span",{style:{color:"#888"},children:"not set"})})]}),e.jsxs("div",{style:h.row,children:[e.jsx("span",{style:h.label,children:"Embed Cache:"}),e.jsx("span",{style:h.value,children:t.embedCache??e.jsx("span",{style:{color:"#888"},children:"not set"})})]}),e.jsxs("div",{style:h.row,children:[e.jsx("span",{style:h.label,children:"MiniLM:"}),e.jsx("span",{style:h.value,children:t.minilm?"enabled":"disabled"})]}),y]}),!t&&!a&&e.jsx("p",{style:{color:"#888",fontSize:"0.85rem"},children:"Loading configuration..."})]}),e.jsxs("div",{style:h.section,children:[e.jsx("h3",{style:h.sectionTitle,children:"Local Embedder Detection"}),e.jsx("p",{style:{fontSize:"0.85rem",color:"#a0a0c0",marginTop:0},children:"Detect which local embedding backends are available on this machine. No software is installed — detection only."}),s&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:h.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"Ollama"})}),s.ollama!==null?e.jsxs("span",{children:[w(s.ollama.installed),s.ollama.installed&&e.jsx("span",{style:{fontSize:"0.8rem",color:"#a0a0c0",marginLeft:"0.5rem"},children:s.ollama.running?`server running, ${s.ollama.models.length} model(s)`:"server not running"})]}):e.jsx("span",{style:{color:"#888",fontSize:"0.85rem"},children:"not checked"})]}),e.jsxs("div",{style:h.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"llama.cpp"})}),s.llamaCpp!==null?e.jsxs("span",{children:[w(s.llamaCpp.installed),s.llamaCpp.installed&&s.llamaCpp.detail&&e.jsx("span",{style:{fontSize:"0.8rem",color:"#a0a0c0",marginLeft:"0.5rem"},children:s.llamaCpp.detail})]}):e.jsx("span",{style:{color:"#888",fontSize:"0.85rem"},children:"not checked"})]}),e.jsxs("div",{style:h.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"ONNX Runtime"})}),s.onnx!==null?e.jsxs("span",{children:[w(s.onnx.installed),s.onnx.installed&&s.onnx.detail&&e.jsx("span",{style:{fontSize:"0.8rem",color:"#a0a0c0",marginLeft:"0.5rem"},children:s.onnx.detail})]}):e.jsx("span",{style:{color:"#888",fontSize:"0.85rem"},children:"not checked"})]}),s.error&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.8rem",marginTop:"0.5rem"},children:["Detection error: ",s.error]})]}),f&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",f]}),e.jsxs("div",{style:{marginTop:"1rem"},children:[e.jsx("button",{style:h.button,onClick:_,disabled:d,children:d?"Detecting...":"Run Detection"}),e.jsxs("span",{style:{fontSize:"0.8rem",color:"#888",marginLeft:"0.75rem"},children:["Or run ",e.jsx("code",{children:"/megasetup"})," in the chat for an interactive wizard."]})]}),s&&e.jsxs("div",{style:{marginTop:"1rem",paddingTop:"0.75rem",borderTop:"1px solid #2a2a4e"},children:[e.jsx("div",{style:{fontSize:"0.9rem",fontWeight:600,marginBottom:"0.5rem"},children:"Configure"}),e.jsxs("div",{style:{display:"flex",gap:"0.5rem",flexWrap:"wrap"},children:[e.jsx("button",{style:{...h.button,opacity:s.ollama?.installed?1:.4},onClick:()=>M("ollama"),disabled:!s.ollama?.installed||m!==null,children:m==="ollama"?"Writing...":"Use Ollama"}),e.jsx("button",{style:{...h.button,opacity:s.llamaCpp?.installed?1:.4},onClick:()=>M("llama"),disabled:!s.llamaCpp?.installed||m!==null,children:m==="llama"?"Writing...":"Use llama.cpp"}),e.jsx("button",{style:{...h.button,opacity:s.onnx?.installed?1:.4},onClick:()=>M("onnx"),disabled:!s.onnx?.installed||m!==null,children:m==="onnx"?"Writing...":"Use ONNX"}),e.jsx("button",{style:{...h.button,background:"#444"},onClick:()=>M("trigram"),disabled:m!==null,children:m==="trigram"?"Writing...":"Use Trigram (default)"})]}),i&&e.jsx("div",{style:h.warning,children:i.alreadyActive?"Already active — no restart needed.":`Configured ${i.embedder}. Restart pi to activate (config written to ${i.envPath}).`}),j&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem",marginTop:"0.5rem"},children:["Configure error: ",j]})]})]}),e.jsx(Ne,{customUrl:N,setCustomUrl:C,applyEmbedder:M,configuring:m}),e.jsxs("div",{style:h.section,children:[e.jsx("h3",{style:h.sectionTitle,children:"How to Upgrade"}),e.jsxs("ul",{style:{fontSize:"0.85rem",lineHeight:1.6,paddingLeft:"1.25rem"},children:[e.jsxs("li",{children:[e.jsx("strong",{children:"Ollama:"})," Install from"," ",e.jsx("a",{href:"https://ollama.com",style:{color:"#6a9fff"},target:"_blank",rel:"noopener noreferrer",children:"ollama.com"}),", then ",e.jsx("code",{children:"ollama pull nomic-embed-text"})," and restart pi. Set ",e.jsx("code",{children:"MEGACOMPACT_EMBEDDING_URL=http://localhost:11434/api/embeddings"}),"."]}),e.jsxs("li",{children:[e.jsx("strong",{children:"llama.cpp:"})," Build or install llama.cpp, run"," ",e.jsx("code",{children:"llama-server"})," with an embedding model, and set the URL accordingly."]}),e.jsxs("li",{children:[e.jsx("strong",{children:"ONNX Runtime:"})," Run a local text-embeddings server (e.g. TEI) and click ",e.jsx("strong",{children:"Use ONNX"})," above. Default URL: ",e.jsx("code",{children:"http://localhost:8081/v1/embeddings"}),"."]})]})]}),e.jsxs("div",{style:h.section,children:[e.jsx("h3",{style:h.sectionTitle,children:"Settings"}),e.jsx(we,{})]})]})}function P(t){return t>=1e6?`${(t/1e6).toFixed(2)}M`:t>=1e3?`${Math.round(t/1e3)}K`:String(t)}function Ce(t,r,s){if(t<=0)return"—";const a=(r>0?r:Math.ceil(t*.1))+Math.ceil(t*(s/100)),c=t-a;return c<=0?"0 (at risk)":`${P(c)} tokens`}function U({label:t,value:r,min:s,max:l,step:a=1,onChange:c,warning:f}){return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex items-center justify-between text-xs",children:[e.jsx("span",{className:"font-medium text-fg-muted",children:t}),e.jsxs("span",{className:`font-mono ${f?"text-warning":"text-fg"}`,title:f,children:[r,"%"]})]}),e.jsx("input",{type:"range",min:s,max:l,step:a,value:r,onChange:o=>c(Number(o.target.value)),className:"threshold-slider w-full"}),f&&e.jsxs("p",{className:"text-[10px] text-warning",children:["⚠ ",f]})]})}function Te({model:t,defaults:r,safetyRange:s,fireRange:l,onSave:a,onReset:c,saving:f}){const[o,d]=n.useState(t.threshold.safetyMarginPct),[g,m]=n.useState(t.threshold.firePointPct),[x,i]=n.useState(!1),[u,j]=n.useState(null);n.useEffect(()=>{d(t.threshold.safetyMarginPct),m(t.threshold.firePointPct),i(!1)},[t.threshold.safetyMarginPct,t.threshold.firePointPct]);const v=o<5?'Low safety margin — risks "conversation too long" errors when a single turn injects a large tool output between gate fires.':void 0,N=g>85?"High fire point — compaction may trigger close to the window cap; a single large turn can overshoot before the gate fires.":void 0,C=n.useCallback(async()=>{j(null);try{await a(t.modelId,o,g),i(!1)}catch(S){j(S instanceof Error?S.message:String(S))}},[t.modelId,o,g,a]);return e.jsxs("div",{className:"rounded-md border border-border bg-bg-elevated/30 p-3",children:[e.jsxs("div",{className:"mb-2 flex items-start justify-between",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm font-semibold text-fg",children:t.modelName??t.modelId}),t.threshold.isOverride&&e.jsx("span",{className:"rounded border border-primary/40 bg-primary/15 px-1.5 py-0.5 text-[10px] font-semibold uppercase text-primary",title:"This model has a custom override (not the default)",children:"Override"})]}),e.jsxs("div",{className:"text-[11px] text-fg-muted",children:[t.provider," · ",P(t.contextWindow)," window ·"," ",P(t.maxTokens)," output"]})]}),e.jsxs("div",{className:"text-right text-[11px] text-fg-muted",children:[e.jsxs("div",{children:["Usable tail:"," ",e.jsx("span",{className:"font-mono text-fg",children:Ce(t.contextWindow,t.maxTokens,o)})]}),e.jsxs("div",{children:["Compaction fires at:"," ",e.jsx("span",{className:"font-mono text-fg",children:P(Math.ceil(t.contextWindow*(g/100)))})]})]})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsx(U,{label:"Safety margin",value:o,min:s[0],max:s[1],onChange:S=>{d(S),i(!0)},warning:v}),e.jsx(U,{label:"Fire point",value:g,min:l[0],max:l[1],onChange:S=>{m(S),i(!0)},warning:N})]}),e.jsxs("div",{className:"mt-2 flex items-center gap-2",children:[e.jsx("button",{type:"button",onClick:C,disabled:!x||f,className:"rounded-md bg-primary px-2.5 py-1 text-xs font-semibold text-primary-fg disabled:cursor-not-allowed disabled:opacity-50",children:x?"Save override":"Saved"}),t.threshold.isOverride&&e.jsxs("button",{type:"button",onClick:()=>c(t.modelId),disabled:f,className:"rounded-md border border-border px-2.5 py-1 text-xs text-fg-muted disabled:cursor-not-allowed disabled:opacity-50",children:["Reset to default (",r.safetyMarginPct,"% /"," ",r.firePointPct,"%)"]}),u&&e.jsx("span",{className:"text-[11px] text-error",children:u})]})]})}function Ee(){const[t,r]=n.useState(null),[s,l]=n.useState(!0),[a,c]=n.useState(null),[f,o]=n.useState(!1),d=n.useCallback(async()=>{try{c(null),r(await ae())}catch(x){c(x instanceof Error?x.message:String(x))}finally{l(!1)}},[]);n.useEffect(()=>{d()},[d]);const g=n.useCallback(async(x,i,u)=>{o(!0);try{await le({modelId:x,safetyMarginPct:i,firePointPct:u}),await d()}finally{o(!1)}},[d]),m=n.useCallback(async x=>{o(!0);try{await oe(x),await d()}finally{o(!1)}},[d]);return s?e.jsx("div",{className:"p-4 text-sm text-fg-muted",children:"Loading thresholds…"}):a?e.jsxs("div",{className:"p-4 text-sm text-error",children:["Error: ",a]}):t?e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"rounded-md border border-border bg-bg-elevated/20 p-3",children:[e.jsx("h3",{className:"text-sm font-semibold",children:"Per-Model Compaction Thresholds"}),e.jsxs("p",{className:"mt-1 text-[11px] text-fg-muted",children:["Tune when compaction fires + how much safety margin to reserve,",e.jsx("strong",{children:" per model"}),". Different providers' models range from 8K to 1M+ context — one global % is wrong. Defaults:"," ",e.jsxs("span",{className:"font-mono",children:[t.defaults.safetyMarginPct,"% safety"]})," ","/"," ",e.jsxs("span",{className:"font-mono",children:[t.defaults.firePointPct,"% fire"]}),". Values outside the safe band show warnings."]})]}),t.models.length===0?e.jsx("div",{className:"rounded-md border border-border p-4 text-sm text-fg-muted",children:"No models captured yet. Start a pi session in any repo to populate model snapshots, then return here to tune per-model thresholds."}):e.jsx("div",{className:"flex flex-col gap-3",children:t.models.map(x=>e.jsx(Te,{model:x,defaults:t.defaults,safetyRange:t.defaults.safetyMarginRange,fireRange:t.defaults.firePointRange,onSave:g,onReset:m,saving:f},x.modelId))})]}):e.jsx("div",{className:"p-4 text-sm text-fg-muted",children:"No data."})}async function Re(){const t=await fetch("/api/setup-cortex-status");if(!t.ok)throw new Error(`setup-cortex status: ${t.status}`);return t.json()}async function Me(t){const r=await fetch("/api/setup-cortex-action",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(r.ok)return{ok:!0,result:await r.json()};let s;try{s=await r.json()}catch{s={error:"disabled"}}return{ok:!1,status:r.status,error:s}}async function Le(t){const r=await fetch(`/api/setup-cortex-action-log?name=${encodeURIComponent(t)}`);if(!r.ok)throw new Error(`setup-cortex action-log: ${r.status}`);return r.json()}function ze(t){return t===null?!0:t.enabled&&t.status!=="off"}function V(){const[t,r]=n.useState({loading:!0,error:null,data:null}),s=n.useCallback(()=>{r(l=>({...l,loading:!0})),Re().then(l=>r(a=>({...a,data:l,loading:!1,error:null}))).catch(l=>r(a=>({...a,loading:!1,error:l instanceof Error?l.message:String(l)})))},[]);return n.useEffect(()=>{s();const l=setInterval(s,5e3);return()=>clearInterval(l)},[s]),[t,s]}const b={container:{padding:"1rem",maxWidth:"720px",margin:"0 auto",fontFamily:"system-ui, sans-serif",color:"#e0e0e0"},section:{background:"#1a1a2e",borderRadius:"8px",padding:"1rem",marginBottom:"1rem",border:"1px solid #2a2a4e"},sectionTitle:{fontSize:"1.1rem",fontWeight:700,marginTop:0,marginBottom:"0.75rem",color:"#e0e0e0",borderBottom:"1px solid #333",paddingBottom:"0.5rem"},label:{fontWeight:600,color:"#a0a0c0",marginRight:"0.5rem"},value:{color:"#e0e0e0"},row:{marginBottom:"0.4rem",fontSize:"0.9rem"},warning:{background:"#3a2a00",border:"1px solid #665500",borderRadius:"8px",padding:"0.75rem",marginTop:"0.5rem",color:"#ffcc00",fontSize:"0.85rem"},blocked:{background:"#3a1a1a",border:"1px solid #662222",borderRadius:"8px",padding:"0.75rem",marginTop:"0.5rem",color:"#ff6666",fontSize:"0.85rem"},badge:{display:"inline-block",padding:"0.15rem 0.5rem",borderRadius:"4px",fontSize:"0.8rem",fontWeight:600,marginLeft:"0.5rem"},button:{background:"#3a5a9f",color:"#fff",border:"none",borderRadius:"6px",padding:"0.5rem 1rem",cursor:"pointer",fontSize:"0.9rem",fontWeight:600},buttonDanger:{background:"#6a2a2a",color:"#ffb3b3",border:"1px solid #662222",borderRadius:"6px",padding:"0.5rem 1rem",cursor:"pointer",fontSize:"0.9rem",fontWeight:600},blockerRow:{display:"flex",justifyContent:"space-between",alignItems:"center",gap:"0.5rem",padding:"0.5rem 0.6rem",borderRadius:"6px",marginBottom:"0.35rem",fontSize:"0.85rem"},blockerRowHighlighted:{background:"#3a1a1a",border:"1px solid #662222"},mono:{fontFamily:"ui-monospace, monospace",fontSize:"0.8rem"}};function Ae(t){switch(t){case"A":return"A — qualified learned encoder asset";case"B":return"B — demoted (heuristic/trigram)";case"C":return"C — absent (asset not verified)";default:return"—"}}function Be(t){const r=t==="qualified"?"#1a5a1a":t==="demoted"?"#3a3a1a":"#3a1a1a",s=t==="qualified"?"#4caf50":t==="demoted"?"#ffcc00":"#f44336";return e.jsx("span",{style:{...b.badge,background:r,color:s},children:t??"unknown"})}function Ie({data:t,error:r}){return e.jsxs("div",{style:b.section,children:[e.jsxs("h3",{style:b.sectionTitle,children:[e.jsx("span",{style:{marginRight:"0.5rem"},children:"Cortex Encoder"}),e.jsx(ce,{status:t?.status})]}),r&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",r]}),!t&&!r&&e.jsx("p",{style:{color:"#888",fontSize:"0.85rem"},children:"Loading cortex status..."}),!t?.enabled&&e.jsx("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:"Cortex status disabled (VC9A off)."}),e.jsxs("div",{style:b.row,children:[e.jsx("span",{style:b.label,children:"Mode:"}),e.jsx("span",{style:b.value,children:Ae(t?.encoderHealth.mode)})]}),e.jsxs("div",{style:b.row,children:[e.jsx("span",{style:b.label,children:"Asset digest prefix:"}),e.jsx("span",{style:{...b.value,...b.mono},children:t?.assetDigestPrefix??e.jsx("span",{style:{color:"#888"},children:"not available"})})]}),e.jsxs("div",{style:b.row,children:[e.jsx("span",{style:b.label,children:"Qualification:"}),Be(t?.qualification.verdict)]}),(t?.qualification.thresholdFailures.length??0)>0&&e.jsxs("div",{style:b.warning,children:[e.jsx("strong",{children:"Threshold failure(s):"})," ",t?.qualification.thresholdFailures.join(", ")]}),t?.status==="awaiting_data"&&e.jsx("p",{style:{color:"#a0a0c0",fontSize:"0.85rem"},children:"Awaiting encoder data. Qualification will appear once an asset is present."}),t?.status==="deferred"&&e.jsx("p",{style:{color:"#a0a0c0",fontSize:"0.85rem"},children:"Encoder status deferred."})]})}function Pe(t){switch(t){case"blocker":return"#f44336";case"high":return"#ff9800";default:return"#a0a0c0"}}function _e({blockers:t,highlight:r}){const s=r??[];return e.jsxs("div",{style:b.section,children:[e.jsxs("h3",{style:b.sectionTitle,children:["Open Hard-Gate Blockers",e.jsx("span",{style:{...b.badge,background:"#3a1a1a",color:"#f44336"},children:t.length})]}),t.length===0&&e.jsx("p",{style:{color:"#4caf50",fontSize:"0.85rem"},children:"No open hard-gate blockers."}),t.map(l=>{const a=s.includes(l.id);return e.jsxs("div",{style:{...b.blockerRow,...a?b.blockerRowHighlighted:{}},children:[e.jsx("span",{style:{...b.mono,fontWeight:700},children:l.id}),e.jsx("span",{style:{flex:1,color:"#e0e0e0"},children:l.title}),e.jsx("span",{style:{color:Pe(l.severity)},children:l.severity}),e.jsx("span",{style:{color:"#a0a0c0",fontStyle:"italic"},children:a?"gates this action":l.status})]},l.id)}),s.length>0&&e.jsxs("div",{style:b.blocked,children:[e.jsx("strong",{children:"Blocked:"})," the requested action is gated by the highlighted open hard-gate item(s). It was not run."]})]})}const Oe=[{key:"fetch-model",label:"Fetch Model",desc:"Fetch the qualified encoder model asset",dangerous:!0,confirm:"Fetch the encoder model asset onto this host? (Gated by any open hard gate.)"},{key:"bench",label:"Bench Encoder",desc:"Benchmark the encoder runtime on this host",dangerous:!0,confirm:"Run an encoder benchmark on this host? (Gated by any open hard gate.)"},{key:"verify-asset",label:"Verify Asset",desc:"Re-verify the committed encoder asset",dangerous:!1,confirm:"Re-verify the committed encoder asset?"}];function De({data:t,onBlocked:r,onAction:s}){const[l,a]=n.useState(null),[c,f]=n.useState(null),[o,d]=n.useState(null),[g,m]=n.useState(!1),x=n.useCallback(async u=>{a(u.key),d(null),f(null),m(!1),r([]);try{const j=await Me({action:u.key,confirm:!0});if(j.ok){const v=j.result;let N=null,C=null;try{const S=await Le(v.logName);N=S.tail,C=S.complete}catch{}f({action:v.action,logName:v.logName,tail:N,complete:C,message:v.ok?`${v.action} completed (spawned: ${v.spawned})`:`${v.action} did not complete cleanly`}),s()}else j.error.error==="action_blocked_by_open_item"?(r(j.error.blockers),d("The action is blocked by an open hard-gate item and was not run.")):j.error.error==="confirmation_required"?d("The server rejected the action: explicit confirmation is required."):(m(!0),d(j.status===404?"Setup Cortex actions are disabled (off).":`Action failed (${j.status}).`))}catch(j){d(j instanceof Error?j.message:String(j))}finally{a(null)}},[r,s]),i=u=>{window.confirm(u.confirm)&&x(u)};return e.jsxs("div",{style:b.section,children:[e.jsx("h3",{style:b.sectionTitle,children:"Cortex Actions"}),Oe.map(u=>{const j=l===u.key;return e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"0.5rem",padding:"0.5rem 0",borderBottom:"1px solid #2a2a4e"},children:[e.jsxs("div",{children:[e.jsx("div",{style:{fontWeight:600},children:u.label}),e.jsx("div",{style:{fontSize:"0.8rem",color:"#a0a0c0"},children:u.desc})]}),e.jsx("button",{style:u.dangerous?b.buttonDanger:b.button,disabled:l!==null,onClick:()=>i(u),children:j?"Running…":"Run"})]},u.key)}),g&&e.jsx("div",{style:b.blocked,children:"Setup Cortex actions are disabled. Enable MEGACOMPACT_VC9B to run them."}),o&&!g&&e.jsx("p",{style:{color:"#f44336",fontSize:"0.85rem",marginTop:"0.5rem"},children:o}),c&&e.jsxs("div",{style:b.warning,"data-testid":"cortex-action-result",children:[e.jsxs("strong",{children:["Result (",c.action,"):"]})," ",c.message,c.logName&&e.jsxs("span",{style:{...b.mono,marginLeft:"0.5rem"},children:["log: ",c.logName]}),c.tail!==null&&e.jsxs("pre",{style:{whiteSpace:"pre-wrap",wordBreak:"break-word",fontSize:"0.75rem",maxHeight:"12rem",overflow:"auto",marginTop:"0.5rem"},children:[c.tail,c.complete===!1&&`
|
|
2
|
-
… (truncated)`]})]}),!t?.enabled&&!g&&e.jsx("p",{style:{color:"#a0a0c0",fontSize:"0.8rem",marginTop:"0.5rem"},children:"Cortex status unavailable — actions may not be schedulable."})]})}function $e(){const[t,r]=V(),[s,l]=n.useState([]),a=n.useCallback(f=>{l(f)},[]),c=n.useCallback(()=>{r()},[r]);return e.jsxs("div",{style:b.container,children:[e.jsx("h2",{style:{fontSize:"1.3rem",marginTop:0,marginBottom:"1rem"},children:"Setup Cortex"}),e.jsx("p",{style:{fontSize:"0.85rem",color:"#a0a0c0",marginTop:0},children:"Vector-cortex encoder gate: mode, qualification, open hard-gate blockers, and the confirmation-gated fetch/bench/verify actions."}),e.jsx(Ie,{data:t.data,error:t.error}),e.jsx(_e,{blockers:t.data?.blockers??[],highlight:s}),e.jsx(De,{data:t.data,onBlocked:a,onAction:c})]})}const We=[{id:"embedder",label:"Embedder"},{id:"thresholds",label:"Thresholds"},{id:"config",label:"Config"},{id:"game",label:"Game Mode"},{id:"achievements",label:"Achievements"}],Ue={id:"cortex",label:"Cortex"};function Ve(){const[t,r]=n.useState("embedder"),[s]=V(),l=n.useMemo(()=>{const a=[...We];return ze(s.data)&&a.push(Ue),a},[s.data]);return e.jsxs("div",{className:"mx-auto flex max-w-3xl flex-col gap-4 p-4",children:[e.jsx("nav",{className:"flex gap-2 border-b border-border pb-2","aria-label":"Setup sections",children:l.map(a=>e.jsx(de,{pressed:t===a.id,onClick:()=>r(a.id),children:a.label},a.id))}),t==="embedder"&&e.jsx(ke,{}),t==="thresholds"&&e.jsx(Ee,{}),t==="config"&&e.jsx(pe,{}),t==="game"&&e.jsx(he,{}),t==="achievements"&&e.jsx(fe,{}),t==="cortex"&&e.jsx($e,{})]})}export{Ve as default};
|
|
3
|
-
//# sourceMappingURL=SetupTab-CJFDD2_v.js.map
|