pi-mega-compact 0.20.27 → 0.20.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/config/vector-cortex-vc9b.js +29 -0
  2. package/dist/config/vector-cortex-vc9c.js +34 -0
  3. package/dist/config/vector-cortex.js +3 -3
  4. package/dist/config.js +1 -1
  5. package/dist/extensions/dashboard-server/api-contracts/endpoints/registry-ext.js +13 -0
  6. package/dist/extensions/dashboard-server/api-contracts/setup-cortex.js +6 -5
  7. package/dist/extensions/dashboard-server/route-dispatch.js +5 -1
  8. package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +2 -0
  9. package/dist/extensions/dashboard-server/routes-setup-cortex-actions.js +116 -0
  10. package/dist/extensions/dashboard-server/routes.js +1 -0
  11. package/dist/extensions/dashboard-server/setup-cortex-actions.js +213 -0
  12. package/dist/extensions/dashboard-server/setup-cortex-blockers.js +17 -0
  13. package/dist/src/config/vector-cortex-vc9b.js +29 -0
  14. package/dist/src/config/vector-cortex-vc9c.js +34 -0
  15. package/dist/src/config/vector-cortex.js +3 -3
  16. package/dist/src/config.js +1 -1
  17. package/extensions/dashboard-client/dist/assets/{AreaChart-Bl8FQm-w.js → AreaChart-DIKsPqLG.js} +2 -2
  18. package/extensions/dashboard-client/dist/assets/{AreaChart-Bl8FQm-w.js.map → AreaChart-DIKsPqLG.js.map} +1 -1
  19. package/extensions/dashboard-client/dist/assets/{BarChart-BXn1a_v9.js → BarChart-DeqN74Hn.js} +2 -2
  20. package/extensions/dashboard-client/dist/assets/{BarChart-BXn1a_v9.js.map → BarChart-DeqN74Hn.js.map} +1 -1
  21. package/extensions/dashboard-client/dist/assets/{CacheTab-DzZpIHkZ.js → CacheTab-x1YU4tYc.js} +2 -2
  22. package/extensions/dashboard-client/dist/assets/{CacheTab-DzZpIHkZ.js.map → CacheTab-x1YU4tYc.js.map} +1 -1
  23. package/extensions/dashboard-client/dist/assets/{EventsTab-rn_Ncwk0.js → EventsTab-6BuEbd8Y.js} +2 -2
  24. package/extensions/dashboard-client/dist/assets/{EventsTab-rn_Ncwk0.js.map → EventsTab-6BuEbd8Y.js.map} +1 -1
  25. package/extensions/dashboard-client/dist/assets/{HealthTab-D4d20PFh.js → HealthTab-B71Ft1ac.js} +2 -2
  26. package/extensions/dashboard-client/dist/assets/{HealthTab-D4d20PFh.js.map → HealthTab-B71Ft1ac.js.map} +1 -1
  27. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-44lwue_H.js → MaintenanceTab-dysyJtHk.js} +2 -2
  28. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-44lwue_H.js.map → MaintenanceTab-dysyJtHk.js.map} +1 -1
  29. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BPCPyPqp.js → MemoryMapTab-B3dKRb_4.js} +2 -2
  30. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BPCPyPqp.js.map → MemoryMapTab-B3dKRb_4.js.map} +1 -1
  31. package/extensions/dashboard-client/dist/assets/{MetricsTab-B1is6D7F.js → MetricsTab-COn4GoUK.js} +2 -2
  32. package/extensions/dashboard-client/dist/assets/{MetricsTab-B1is6D7F.js.map → MetricsTab-COn4GoUK.js.map} +1 -1
  33. package/extensions/dashboard-client/dist/assets/{OverviewTab-DIC_cUjS.js → OverviewTab-Cd9qAEB3.js} +2 -2
  34. package/extensions/dashboard-client/dist/assets/{OverviewTab-DIC_cUjS.js.map → OverviewTab-Cd9qAEB3.js.map} +1 -1
  35. package/extensions/dashboard-client/dist/assets/{ReposTab-KhTQqt5Z.js → ReposTab-DpiP1-Vv.js} +2 -2
  36. package/extensions/dashboard-client/dist/assets/{ReposTab-KhTQqt5Z.js.map → ReposTab-DpiP1-Vv.js.map} +1 -1
  37. package/extensions/dashboard-client/dist/assets/{SessionsTab-CeOUPRIM.js → SessionsTab-BwRUeGZM.js} +2 -2
  38. package/extensions/dashboard-client/dist/assets/{SessionsTab-CeOUPRIM.js.map → SessionsTab-BwRUeGZM.js.map} +1 -1
  39. package/extensions/dashboard-client/dist/assets/SetupTab-CJFDD2_v.js +3 -0
  40. package/extensions/dashboard-client/dist/assets/SetupTab-CJFDD2_v.js.map +1 -0
  41. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CXmxE5_8.js → TimeSavedCard-_XsdjQ7Z.js} +2 -2
  42. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CXmxE5_8.js.map → TimeSavedCard-_XsdjQ7Z.js.map} +1 -1
  43. package/extensions/dashboard-client/dist/assets/{TurnsTab-Dbx9pZPX.js → TurnsTab-CWPscPLL.js} +2 -2
  44. package/extensions/dashboard-client/dist/assets/{TurnsTab-Dbx9pZPX.js.map → TurnsTab-CWPscPLL.js.map} +1 -1
  45. package/extensions/dashboard-client/dist/assets/VcStatusBadge-Cx56rAIM.js +2 -0
  46. package/extensions/dashboard-client/dist/assets/VcStatusBadge-Cx56rAIM.js.map +1 -0
  47. package/extensions/dashboard-client/dist/assets/VectorCortexTab-B5ElUM7S.js +2 -0
  48. package/extensions/dashboard-client/dist/assets/VectorCortexTab-B5ElUM7S.js.map +1 -0
  49. package/extensions/dashboard-client/dist/assets/{WikiTab-B1mKp1SA.js → WikiTab-uZ5Mq3XG.js} +2 -2
  50. package/extensions/dashboard-client/dist/assets/{WikiTab-B1mKp1SA.js.map → WikiTab-uZ5Mq3XG.js.map} +1 -1
  51. package/extensions/dashboard-client/dist/assets/{button-BFHPDVb1.js → button-Kc18bYFz.js} +2 -2
  52. package/extensions/dashboard-client/dist/assets/{button-BFHPDVb1.js.map → button-Kc18bYFz.js.map} +1 -1
  53. package/extensions/dashboard-client/dist/assets/{card-XrbSJiOF.js → card-COJZoG08.js} +2 -2
  54. package/extensions/dashboard-client/dist/assets/{card-XrbSJiOF.js.map → card-COJZoG08.js.map} +1 -1
  55. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B9Ba91Tu.js → generateCategoricalChart-ChEYo017.js} +2 -2
  56. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B9Ba91Tu.js.map → generateCategoricalChart-ChEYo017.js.map} +1 -1
  57. package/extensions/dashboard-client/dist/assets/{index-P13AO5ni.js → index-CB7Rn5FP.js} +14 -14
  58. package/extensions/dashboard-client/dist/assets/index-CB7Rn5FP.js.map +1 -0
  59. package/extensions/dashboard-client/dist/assets/index-DbuGwYD7.css +1 -0
  60. package/extensions/dashboard-client/dist/assets/{switch-jnYDePmb.js → switch-BFhl_tNh.js} +2 -2
  61. package/extensions/dashboard-client/dist/assets/{switch-jnYDePmb.js.map → switch-BFhl_tNh.js.map} +1 -1
  62. package/extensions/dashboard-client/dist/assets/{toggle-JO-vvubb.js → toggle-DJ68kATc.js} +2 -2
  63. package/extensions/dashboard-client/dist/assets/{toggle-JO-vvubb.js.map → toggle-DJ68kATc.js.map} +1 -1
  64. package/extensions/dashboard-client/dist/assets/{useSSE-DAkXqUOy.js → useSSE-CXWh42xX.js} +2 -2
  65. package/extensions/dashboard-client/dist/assets/{useSSE-DAkXqUOy.js.map → useSSE-CXWh42xX.js.map} +1 -1
  66. package/extensions/dashboard-client/dist/index.html +2 -2
  67. package/extensions/dashboard-client/src/api/setup-cortex.ts +62 -0
  68. package/extensions/dashboard-client/src/tabs/SetupTab/CortexActionsCard.tsx +221 -0
  69. package/extensions/dashboard-client/src/tabs/SetupTab/CortexBlockersCard.tsx +74 -0
  70. package/extensions/dashboard-client/src/tabs/SetupTab/CortexEncoderCard.tsx +113 -0
  71. package/extensions/dashboard-client/src/tabs/SetupTab/CortexSetup.tsx +53 -0
  72. package/extensions/dashboard-client/src/tabs/SetupTab/CortexSetupStyles.ts +98 -0
  73. package/extensions/dashboard-client/src/tabs/SetupTab.tsx +22 -6
  74. package/extensions/dashboard-client/src/tabs/useSetupCortexPoll.ts +64 -0
  75. package/extensions/dashboard-client/src/types/setup-cortex.ts +118 -0
  76. package/extensions/dashboard-server/api-contracts/endpoints/registry-ext.ts +34 -1
  77. package/extensions/dashboard-server/api-contracts/setup-cortex.ts +63 -5
  78. package/extensions/dashboard-server/route-dispatch.ts +4 -0
  79. package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +12 -0
  80. package/extensions/dashboard-server/routes-setup-cortex-actions.ts +133 -0
  81. package/extensions/dashboard-server/routes.ts +4 -0
  82. package/extensions/dashboard-server/setup-cortex-actions.ts +242 -0
  83. package/extensions/dashboard-server/setup-cortex-blockers.ts +25 -0
  84. package/package.json +1 -1
  85. package/src/config/vector-cortex-vc9b.ts +31 -0
  86. package/src/config/vector-cortex-vc9c.ts +36 -0
  87. package/src/config/vector-cortex.ts +3 -3
  88. package/src/config.ts +2 -0
  89. package/extensions/dashboard-client/dist/assets/SetupTab-DnN0mX0J.js +0 -2
  90. package/extensions/dashboard-client/dist/assets/SetupTab-DnN0mX0J.js.map +0 -1
  91. package/extensions/dashboard-client/dist/assets/VectorCortexTab-MzqdB6zI.js +0 -2
  92. package/extensions/dashboard-client/dist/assets/VectorCortexTab-MzqdB6zI.js.map +0 -1
  93. package/extensions/dashboard-client/dist/assets/index-Difwoltx.css +0 -1
  94. package/extensions/dashboard-client/dist/assets/index-P13AO5ni.js.map +0 -1
@@ -0,0 +1,242 @@
1
+ /**
2
+ * dashboard-server/setup-cortex-actions.ts — VC9B action driver (actor surface).
3
+ *
4
+ * Implements the actual mechanics behind POST /api/setup-cortex-action and
5
+ * GET /api/setup-cortex-action-log: locating + spawning ONLY the committed local
6
+ * vc2-model-prep scripts (fetch-model.sh, bench-onnx.mjs), capturing their
7
+ * output to <stateDir>/logs/vc9b/<action>-<ts>.log, re-running the committed
8
+ * encoder asset verification seam for verify-asset (NO subprocess), and serving
9
+ * a bounded + redacted log tail.
10
+ *
11
+ * This module is the ONLY place that touches the filesystem for VC9B actions.
12
+ * The route file (routes-setup-cortex-actions.ts) carries NO path/script/blocker
13
+ * string literals — it delegates here. Guardrails: the spawned scripts are the
14
+ * existing committed local developer-tooling scripts (never fetched, no network,
15
+ * PREVENT-PI-004); the log tail is bounded at 8 KiB and redacted (digest
16
+ * prefixes + codes only, never payload bytes — EVAL-REDACT-002); PREVENT-011
17
+ * (no `any`).
18
+ */
19
+
20
+ import { spawnSync } from "node:child_process"; // guardrails-allow PREVENT-PI-004: local subprocess spawn of committed repo script (loopback)
21
+ import {
22
+ mkdirSync,
23
+ readFileSync,
24
+ writeFileSync,
25
+ existsSync,
26
+ readdirSync,
27
+ } from "node:fs";
28
+ import { join, dirname, basename } from "node:path";
29
+ import { fileURLToPath } from "node:url";
30
+ import type {
31
+ SetupCortexActionKind,
32
+ SetupCortexActionResult,
33
+ } from "./api-contracts/setup-cortex.js";
34
+ import {
35
+ readEncoderManifest,
36
+ verifyEncoderAsset,
37
+ detectPlatform,
38
+ } from "../../src/vector-cortex/encoder/asset.js";
39
+
40
+ /** Cap applied to every log tail served by the action-log route. */
41
+ export const ACTION_LOG_TAIL_BYTES = 8192;
42
+
43
+ /** Locate the commit's vc2-model-prep directory by walking up to the repo root. */
44
+ function vc2ScriptDir(): string | null {
45
+ let dir = dirname(fileURLToPath(import.meta.url));
46
+ const rel = join("scripts", "vc2-model-prep");
47
+ for (let i = 0; i < 8; i++) {
48
+ const candidate = join(dir, rel);
49
+ if (existsSync(join(candidate, "fetch-model.sh"))) return candidate;
50
+ const next = dirname(dir);
51
+ if (next === dir) break;
52
+ dir = next;
53
+ }
54
+ return null;
55
+ }
56
+
57
+ /** Absolute dir holding this repo's <stateDir>/logs/vc9b/ action logs. */
58
+ export function vc9bLogDir(stateDir: string): string {
59
+ return join(stateDir, "logs", "vc9b");
60
+ }
61
+
62
+ /** Ensure the vc9b log dir exists and return its absolute path. */
63
+ function ensureLogDir(stateDir: string): string {
64
+ const dir = vc9bLogDir(stateDir);
65
+ // guardrails-allow PREVENT-PI-004: local state-dir filesystem write (loopback)
66
+ mkdirSync(dir, { recursive: true });
67
+ return dir;
68
+ }
69
+
70
+ /** Safe log basename: non-empty, no separators, not a dot/double-dot segment. */
71
+ export function isSafeLogName(name: string): boolean {
72
+ if (!name || name.length === 0) return false;
73
+ if (name.includes("/") || name.includes("\\")) return false;
74
+ if (name === "." || name === "..") return false;
75
+ // Must match our own file naming: <action>-<ts>.log where ts is digits.
76
+ return /^[a-z-]+-\d+\.log$/.test(name);
77
+ }
78
+
79
+ /**
80
+ * Redact a fragment of action-log output: bound long digests to their prefix and
81
+ * collapse long base64-looking tokens, so the served tail carries digest prefixes
82
+ * + codes only — never arbitrary payload bytes. Returns the redacted text.
83
+ */
84
+ export function redactLog(text: string): string {
85
+ let out = text;
86
+ // SHA-256 (64 hex) or any long hex digest -> keep the first 12 chars.
87
+ out = out.replace(/\b[0-9a-fA-F]{32,}\b/g, (m) => `sha256:${m.slice(0, 12)}`);
88
+ // Long base64-ish tokens (26+ chars from the base64 alphabet) -> collapse.
89
+ out = out.replace(/[A-Za-z0-9+/=]{26,}/g, (m) => `<redacted:${m.length}>`);
90
+ return out;
91
+ }
92
+
93
+ /** Read + bound + redact the tail of one vc9b log file. */
94
+ export function readActionLogTail(
95
+ stateDir: string,
96
+ name: string,
97
+ ): { name: string; tail: string; complete: boolean } | null {
98
+ if (!isSafeLogName(name)) return null;
99
+ const dir = vc9bLogDir(stateDir);
100
+ const full = join(dir, name);
101
+ if (basename(full) !== name) return null; // belt-and-suspenders: no traversal
102
+ if (!existsSync(full)) return null;
103
+ let raw: string;
104
+ try {
105
+ // guardrails-allow PREVENT-PI-004: local state-dir filesystem read (loopback)
106
+ raw = readFileSync(full, "utf8");
107
+ } catch {
108
+ return null;
109
+ }
110
+ const bounded = raw.length > ACTION_LOG_TAIL_BYTES
111
+ ? raw.slice(-ACTION_LOG_TAIL_BYTES)
112
+ : raw;
113
+ return {
114
+ name,
115
+ tail: redactLog(bounded),
116
+ complete: raw.length <= ACTION_LOG_TAIL_BYTES,
117
+ };
118
+ }
119
+
120
+ /** Run a vc2-model-prep subprocess and capture its output to a vc9b log file. */
121
+ function runSpawnedAction(
122
+ action: Extract<SetupCortexActionKind, "fetch-model" | "bench">,
123
+ stateDir: string,
124
+ ): SetupCortexActionResult {
125
+ const dir = vc2ScriptDir();
126
+ const { name, logPath } = writeLogName(action, stateDir);
127
+ if (dir === null) {
128
+ writeLog(logPath, "vc2-model-prep scripts not found in this checkout\n");
129
+ return { action, ok: false, exitCode: null, logPath, logName: name, spawned: true };
130
+ }
131
+ let result;
132
+ if (action === "fetch-model") {
133
+ // guardrails-allow PREVENT-PI-004: local subprocess spawn of committed repo script (loopback)
134
+ result = spawnSync("bash", [join(dir, "fetch-model.sh"), join(stateDir, "vc2-model-prep")], {
135
+ encoding: "utf8",
136
+ timeout: 60_000,
137
+ });
138
+ } else {
139
+ // guardrails-allow PREVENT-PI-004: local subprocess spawn of committed repo script (loopback)
140
+ result = spawnSync(process.execPath, [join(dir, "bench-onnx.mjs")], {
141
+ encoding: "utf8",
142
+ timeout: 60_000,
143
+ });
144
+ }
145
+ const out = `${result.stdout ?? ""}${result.stderr ?? ""}`;
146
+ writeLog(logPath, out || "(no output)\n");
147
+ return {
148
+ action,
149
+ ok: result.status === 0,
150
+ exitCode: result.status === null ? null : result.status,
151
+ logPath,
152
+ logName: name,
153
+ spawned: true,
154
+ };
155
+ }
156
+
157
+ /**
158
+ * Re-run the committed encoder asset verification seam (readEncoderManifest +
159
+ * verifyEncoderAsset + detectPlatform) WITHOUT any subprocess, and log a
160
+ * redacted summary (mode + digest prefix + verdict/code only). Uses the same
161
+ * repo-root walk the VC9A status route uses to find assets/vector-cortex.
162
+ */
163
+ function runVerifyAsset(stateDir: string): SetupCortexActionResult {
164
+ const { name, logPath } = writeLogName("verify-asset", stateDir);
165
+ const body = buildVerifySummary();
166
+ writeLog(logPath, body);
167
+ return {
168
+ action: "verify-asset",
169
+ ok: body.includes("verdict=qualified"),
170
+ exitCode: null,
171
+ logPath,
172
+ logName: name,
173
+ spawned: false,
174
+ };
175
+ }
176
+
177
+ /** Compute the redacted verify-asset summary lines (digests + codes only). */
178
+ function buildVerifySummary(): string {
179
+ const dir = encoderAssetDir();
180
+ if (dir === null) {
181
+ return "mode=C verdict=unavailable reason=asset_missing\n";
182
+ }
183
+ const manifest = readEncoderManifest(dir);
184
+ if (manifest === null) {
185
+ return "mode=B verdict=demoted reason=ENC_MANIFEST_INVALID\n";
186
+ }
187
+ const platform = detectPlatform();
188
+ const verify = verifyEncoderAsset(dir, manifest, platform);
189
+ if (verify.ok) {
190
+ const prefix = verify.onnxDigest.slice(0, 12);
191
+ return `mode=A verdict=qualified onnx_digest_prefix=${prefix} embedded_bytes=${verify.embeddedBytes}\n`;
192
+ }
193
+ return `mode=B verdict=demoted reason=${verify.code}\n`;
194
+ }
195
+
196
+ /** Walk up to the committed encoder-v1 asset dir (mirrors routes-setup-cortex.ts). */
197
+ function encoderAssetDir(): string | null {
198
+ let dir = dirname(fileURLToPath(import.meta.url));
199
+ const rel = join("assets", "vector-cortex", "encoder-v1");
200
+ for (let i = 0; i < 8; i++) {
201
+ const candidate = join(dir, rel);
202
+ // guardrails-allow PREVENT-PI-004: local asset filesystem read (loopback)
203
+ if (existsSync(join(candidate, "manifest.json"))) return candidate;
204
+ const next = dirname(dir);
205
+ if (next === dir) break;
206
+ dir = next;
207
+ }
208
+ return null;
209
+ }
210
+
211
+ interface LogFileRef {
212
+ name: string;
213
+ logPath: string;
214
+ }
215
+
216
+ /** Unique <action>-<ts>.log name + absolute path under the vc9b log dir. */
217
+ function writeLogName(action: SetupCortexActionKind, stateDir: string): LogFileRef {
218
+ let ts = Date.now();
219
+ const existing = new Set(readdirSync(ensureLogDir(stateDir)));
220
+ while (existing.has(`${action}-${ts}.log`)) ts++;
221
+ const name = `${action}-${ts}.log`;
222
+ return { name, logPath: join(vc9bLogDir(stateDir), name) };
223
+ }
224
+
225
+ function writeLog(logPath: string, body: string): void {
226
+ // guardrails-allow PREVENT-PI-004: local state-dir filesystem write (loopback)
227
+ writeFileSync(logPath, body, "utf8");
228
+ }
229
+
230
+ /**
231
+ * Run one Setup Cortex action against the given stateDir. Returns the action
232
+ * result on success; throws nothing — every failure is surfaced as a result with
233
+ * ok=false so the route can shape the HTTP response. Never touches the network;
234
+ * the subprocesses it may spawn are the committed local vc2-model-prep scripts.
235
+ */
236
+ export function runSetupCortexAction(
237
+ action: SetupCortexActionKind,
238
+ stateDir: string,
239
+ ): SetupCortexActionResult {
240
+ if (action === "verify-asset") return runVerifyAsset(stateDir);
241
+ return runSpawnedAction(action, stateDir);
242
+ }
@@ -71,3 +71,28 @@ export const SETUP_CORTEX_BLOCKERS: readonly SetupCortexBlockerV1[] = [
71
71
  export function setupCortexBlocker(id: string): SetupCortexBlockerV1 | undefined {
72
72
  return SETUP_CORTEX_BLOCKERS.find((b) => b.id === id);
73
73
  }
74
+
75
+ // ─── VC9B action gating ─────────────────────────────────────────────────────
76
+
77
+ /** The VC9B action kinds the drivers know how to run. */
78
+ export type SetupCortexActionKind = "fetch-model" | "bench" | "verify-asset";
79
+
80
+ /**
81
+ * The open hard-gate ids that BLOCK a given action. fetch-model and bench are
82
+ * gated by HG-1 (five-head training open) and HG-3 (install budget open) per the
83
+ * VC9 workstream plan; verify-asset is a pure re-read of committed assets and is
84
+ * NOT gated. When a gated action is requested, the route returns
85
+ * action_blocked_by_open_item with these ids and does NOT spawn. The ids are
86
+ * always drawn from SETUP_CORTEX_BLOCKERS (each exists — verified by test).
87
+ */
88
+ export function setupCortexActionBlockers(
89
+ action: SetupCortexActionKind,
90
+ ): readonly string[] {
91
+ switch (action) {
92
+ case "fetch-model":
93
+ case "bench":
94
+ return ["HG-1", "HG-3"];
95
+ case "verify-asset":
96
+ return [];
97
+ }
98
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-mega-compact",
3
- "version": "0.20.27",
3
+ "version": "0.20.28",
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-vc9b.ts — VC9B setup-cortex action-drivers 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 was. This is the
6
+ * SETUP-DASHBOARD action flag (the dashboard Setup tab fetch/bench/verify action
7
+ * drivers). vector-cortex.ts re-exports it below and root src/config.ts
8
+ * re-exports it, so no consumer import path changes.
9
+ *
10
+ * The split is purely mechanical: VC9B_ENABLED is byte-identical in name,
11
+ * semantics, and default to the definition it replaces, and vector-cortex.ts
12
+ * re-exports it so every existing `from "./config/vector-cortex.js"` import
13
+ * keeps resolving unchanged.
14
+ *
15
+ * Pi-agnostic, dependency-free (PREVENT-PI-004 / PREVENT-011).
16
+ */
17
+
18
+ import { sprintFlag } from "./vector-cortex-flag.js";
19
+
20
+ /**
21
+ * VC9B — Setup Cortex action drivers (POST /api/setup-cortex-action +
22
+ * GET /api/setup-cortex-action-log). Default ON. `MEGACOMPACT_VC9B=0` disables
23
+ * and is byte-identical to the predecessor (VC9A-era): the action POST returns
24
+ * the disabled shape (404/disabled) and flag-off bytes are unchanged. The
25
+ * actions only spawn the existing committed local scripts
26
+ * (scripts/vc2-model-prep/fetch-model.sh / bench-onnx.mjs) or re-read the
27
+ * committed encoder assets — never payload bytes, no network (PREVENT-PI-004).
28
+ * This flag MUST also be a dashboard SETTINGS toggle (visible in config UI,
29
+ * never in EXCLUDED_SETTINGS), mirroring VC9A.
30
+ */
31
+ export const VC9B_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC9B");
@@ -0,0 +1,36 @@
1
+ /**
2
+ * config/vector-cortex-vc9c.ts — VC9C SetupTab Cortex sub-tab 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 and
6
+ * vector-cortex-vc9b.ts were. This is the SETUP-DASHBOARD UI flag (the Cortex
7
+ * sub-tab inside SetupTab). vector-cortex.ts re-exports it below and root
8
+ * src/config.ts re-exports it, so no consumer import path changes.
9
+ *
10
+ * The split is purely mechanical: VC9C_ENABLED is byte-identical in name,
11
+ * semantics, and default to the definition it replaces, and vector-cortex.ts
12
+ * re-exports it so every existing `from "./config/vector-cortex.js"` import
13
+ * keeps resolving unchanged.
14
+ *
15
+ * The client gates the Cortex sub-tab's visible state on the flag via the
16
+ * VC0E honest-status pattern: when the VC9A status payload reports the
17
+ * off/disabled shape (or VC9C is off), the sub-tab is filtered from
18
+ * SUB_TABS. Flag-off is byte-identical to the predecessor (VC9B-era).
19
+ *
20
+ * Pi-agnostic, dependency-free (PREVENT-PI-004 / PREVENT-011).
21
+ */
22
+
23
+ import { sprintFlag } from "./vector-cortex-flag.js";
24
+
25
+ /**
26
+ * VC9C — SetupTab Cortex sub-tab (client UI). Default ON. `MEGACOMPACT_VC9C=0`
27
+ * disables and is byte-identical to the predecessor (VC9B-era): the Cortex
28
+ * sub-tab is filtered from SUB_TABS and the Setup tab renders exactly as it
29
+ * did before this sprint. The sub-tab is a pure consumer of the VC9A status
30
+ * endpoint (GET /api/setup-cortex-status) + VC9B action endpoints (POST
31
+ * /api/setup-cortex-action, GET /api/setup-cortex-action-log); it adds NO
32
+ * server logic and never surfaces payload bytes/prompts/ledger. This flag MUST
33
+ * also be a dashboard SETTINGS toggle (visible in config UI, never in
34
+ * EXCLUDED_SETTINGS), mirroring VC9A/VC9B.
35
+ */
36
+ export const VC9C_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC9C");
@@ -275,10 +275,10 @@ 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.
278
+ // VC9A/VC9B/VC9C split to vector-cortex-vc9{a,b,c}.ts to stay under the 300-line soft limit.
281
279
  export { VC9A_ENABLED } from "./vector-cortex-vc9a.js";
280
+ export { VC9B_ENABLED } from "./vector-cortex-vc9b.js";
281
+ export { VC9C_ENABLED } from "./vector-cortex-vc9c.js";
282
282
 
283
283
  // Breaker state machine constants (TRIAD_RESILIENCE.md §breaker) extracted to
284
284
  // vector-cortex-breakers.ts to keep this file under the 300-line soft limit.
package/src/config.ts CHANGED
@@ -179,6 +179,8 @@ export {
179
179
  VC8B_ENABLED,
180
180
  VC8C_ENABLED,
181
181
  VC9A_ENABLED,
182
+ VC9B_ENABLED,
183
+ VC9C_ENABLED,
182
184
  BREAKER_WINDOW_MS,
183
185
  BREAKER_MIN_ATTEMPTS,
184
186
  BREAKER_PERF_FAILURES,
@@ -1,2 +0,0 @@
1
- import{r as n,j as e,h as L,i as W,k as F,p as q,l as X,m as K,C as Y,n as J,o as Q,q as Z,s as ee,t as te,v as se,w as ne,x as ae,y as re}from"./index-P13AO5ni.js";import{S as le}from"./switch-jnYDePmb.js";import{T as ie}from"./toggle-JO-vvubb.js";function oe(t){try{return new Date(t*1e3).toLocaleString()}catch{return"—"}}function G({achievements:t}){const i=n.useRef(0),[s,u]=n.useState(null),l=t.reduce((a,o)=>Math.max(a,o.unlocked_at??0),0),m=i.current;n.useEffect(()=>{l>i.current&&(i.current=l)},[l]),n.useEffect(()=>{if(m>0&&l>m){const a=t.filter(o=>o.unlocked_at!=null&&(o.unlocked_at??0)>m);if(a.length>0){const o=a.map(c=>`${c.icon??""} ${c.title}`.trim()).join(", ")+" unlocked!";u(o);const f=setTimeout(()=>u(null),4e3);return()=>clearTimeout(f)}}},[t,l,m]);const h=t.filter(a=>!(a.hidden===1&&a.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:[h.length===0&&e.jsx("span",{className:"repo-none",children:"no achievements yet"}),h.map(a=>{if(a.unlocked_at!=null){const o=m>0&&(a.unlocked_at??0)>m;return e.jsxs("div",{className:`ach-tile unlocked${o?" just-unlocked":""}`,children:[a.icon??""," ",a.title,e.jsxs("span",{className:"ach-detail",children:["unlocked ",oe(a.unlocked_at)]})]},a.id)}return e.jsxs("div",{className:"ach-tile locked",children:["??? ",a.title]},a.id)})]})]})}function I(t){return(Math.round(t*10)/10).toString()+"%"}function O(t){return t!=null?new Date(t).toLocaleString():"—"}function z(t){return t&&typeof t=="object"?t:{}}function ce(t){return t.split("/").pop()||t}function _({title:t,rows:i,badge:s,renderValue:u}){return e.jsxs("div",{className:"lb-card",children:[e.jsxs("h3",{children:[t,s]}),i.length===0?e.jsx("div",{className:"lb-empty",children:"—"}):e.jsx("table",{children:e.jsx("tbody",{children:i.map((l,m)=>e.jsxs("tr",{children:[e.jsx("td",{title:l.repo_root,children:ce(l.repo_root)}),e.jsx("td",{className:"num",children:u(l)})]},`${l.repo_root}-${m}`))})})]})}function de(){const[t,i]=n.useState({}),[s,u]=n.useState(0),[l,m]=n.useState([]),[h,a]=n.useState(!1),[o,f]=n.useState(!0),[c,x]=n.useState(null),r=n.useRef(0),g=n.useCallback(async()=>{try{const[b,y,p,w,E,V]=await Promise.all([L({metric:"cache",limit:25}),L({metric:"dedupe",limit:25}),L({metric:"turns",limit:25}),L({metric:"mega_cache",limit:25}),L({metric:"repos",limit:1}),W()]),U=w.find(P=>P.ts>r.current&&P.value>100);r.current>0&&U&&(x(`oopsie! cache went to ${Math.round(U.value)}% — MEGA CACHE 🥧`),setTimeout(()=>x(null),4e3)),w.length>0&&(r.current=Math.max(...w.map(P=>P.ts))),i({cache:b,dedupe:y,turns:p,mega_cache:w}),u(E[0]?.value??0),m(V)}catch{}finally{f(!1)}},[]);n.useEffect(()=>{let b=!0;const y=async()=>{b&&await g()};y();const p=setInterval(()=>void y(),15e3);return()=>{b=!1,clearInterval(p)}},[g]),n.useEffect(()=>{let b=!0;const y=async()=>{try{const w=await F();b&&(a(!!w.game_mode_on),w.theme&&(document.documentElement.dataset.theme=w.theme))}catch{}};y();const p=setInterval(()=>void y(),15e3);return()=>{b=!1,clearInterval(p)}},[]);const S=t.mega_cache??[];let v=null,N=null;for(const b of S){(v==null||b.value>v)&&(v=b.value);const y=z(b.meta),p=y.firstSeenTs??y.firstSeen??b.ts;(N==null||p<N)&&(N=p)}const M=v!=null&&v>100,j=t.turns??[],k=j.reduce((b,y)=>Math.max(b,y.value),0),D=Math.floor(Math.log2(k+1))+1,R=(t.cache?.length??0)>0||(t.dedupe?.length??0)>0||j.length>0||S.length>0||s>0;return e.jsxs("div",{className:`game-tab${h?" game-mode-on":""}`,children:[c!=null&&e.jsx("div",{className:"mega-cache-toast show",children:c}),M&&e.jsxs("div",{className:"mega-cache-banner",children:["🥧"," MEGA CACHE! peak ",I(v)," — first reached ",O(N)]}),M&&e.jsxs("div",{className:"achievement-tile unlocked",children:["🏆"," Opie's Wild Ride",e.jsxs("span",{className:"ach-detail",children:["best ",I(v)," · first ",O(N)]})]}),e.jsx("h2",{children:"High Scores"}),!R&&!o&&e.jsx("div",{className:"game-empty",children:"No scores yet — run a session with game mode on."}),R&&e.jsxs("div",{className:"game-leaderboards",children:[e.jsx(_,{title:"Cache %",rows:t.cache??[],renderValue:b=>I(b.value)}),e.jsx(_,{title:"Dedupe (collapsed)",rows:t.dedupe??[],renderValue:b=>b.value.toLocaleString()}),e.jsx(_,{title:"Turns",rows:j,badge:j.length>0?e.jsxs("span",{className:"lvl-badge",children:["LVL ",D]}):void 0,renderValue:b=>b.value.toLocaleString()}),e.jsx(_,{title:"MEGA CACHE trophies",rows:S,renderValue:b=>e.jsxs(e.Fragment,{children:[I(b.value),e.jsx("span",{className:"lb-meta",children:O(z(b.meta).firstSeenTs??z(b.meta).firstSeen??b.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(G,{achievements:l})]})}function me(){const[t,i]=n.useState([]),[s,u]=n.useState(!0),[l,m]=n.useState(null),h=n.useCallback(async()=>{try{const a=await W();i(a),m(null)}catch(a){m(a instanceof Error?a:new Error(String(a)))}finally{u(!1)}},[]);return n.useEffect(()=>{let a=!0;const o=async()=>{a&&await h()};o();const f=setInterval(()=>void o(),15e3);return()=>{a=!1,clearInterval(f)}},[h]),s&&t.length===0?e.jsx("div",{className:"tab-stub",children:"Loading achievements…"}):l&&t.length===0?e.jsxs("div",{className:"tab-stub",children:["Error: ",l.message]}):e.jsxs("div",{className:"achievements-tab",children:[e.jsx("h2",{children:"Achievements"}),e.jsx(G,{achievements:t})]})}const H=[{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"}}],$=H.map(t=>t.id),T={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 ue(t,i,s){let u=t.toLocaleString();return i!=null&&s>0&&(u+=` (${Math.round(i*100)}% of ${s.toLocaleString()})`),u}function he(t){return`${Math.round((t||0)*100)}%`}function fe(){const[t,i]=n.useState(null),[s,u]=n.useState(null),[l,m]=n.useState(!1);n.useEffect(()=>{let r=!0;const g=async()=>{try{const v=await X();r&&i(v)}catch{}};g();const S=setInterval(()=>void g(),5e3);return()=>{r=!1,clearInterval(S)}},[]),n.useEffect(()=>{let r=!0;const g=async()=>{try{const v=await F();r&&(u(v),v.theme&&(document.documentElement.dataset.theme=v.theme))}catch{}};g();const S=setInterval(()=>void g(),5e3);return()=>{r=!1,clearInterval(S)}},[]);const h=n.useCallback(async r=>{m(!0);try{const g=await q(r);u(g),g.theme&&(document.documentElement.dataset.theme=g.theme)}catch{}m(!1)},[]),a=s?.game_mode_on??!1,o=s?.theme??"transparent",f=s?.tui_display_mode??"full",c=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:T.gameMode,children:[e.jsx("input",{type:"checkbox",checked:a,onChange:r=>h({game_mode_on:r.currentTarget.checked}),disabled:l}),"Game Mode"]})}),e.jsx("div",{className:"settings-row",children:e.jsxs("label",{title:T.theme,children:["Theme",e.jsx("select",{value:o,onChange:r=>h({theme:r.currentTarget.value}),disabled:l,children:H.map(r=>e.jsx("option",{value:r.id,children:r.label},r.id))}),e.jsx("button",{type:"button",disabled:l,className:"theme-cycle-btn",title:"Cycle to the next theme (P3)",onClick:()=>{const r=$.indexOf(o),g=$[(r<0?0:r+1)%$.length];g&&h({theme:g})},children:"Next theme →"})]})}),e.jsx("div",{className:"settings-row",children:e.jsxs("label",{title:T.tuiMode,children:["TUI Mode",e.jsxs("select",{value:f,onChange:r=>h({tui_display_mode:r.currentTarget.value}),disabled:l,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:T.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:T.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:T.pressure,children:"Pressure"}),e.jsx("span",{className:"config-value",children:t?he(t.pressure):"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:T.threshold,children:"Threshold"}),e.jsx("span",{className:"config-value",children:c?ue(c.thresholdTokens,c.tierPct,x):"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:T.fastGate,children:"Fast Gate"}),e.jsx("span",{className:"config-value",children:c?`${c.fastGatePct}%`:"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",children:"Auto"}),e.jsx("span",{className:"config-value",children:c?c.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:c?.anchorUserMessages??"—"})]})]})]})]})}const C={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 xe(){const[t,i]=n.useState(null),[s,u]=n.useState(null),l=n.useCallback(()=>{K().then(i).catch(f=>u(f instanceof Error?f.message:String(f)))},[]);n.useEffect(()=>{l()},[l]),n.useEffect(()=>{const f=setInterval(l,3e4);return()=>clearInterval(f)},[l]);const m=t?.status==="ok",h=t?.status==="ok"?"Working":t?.status==="unreachable"?"Unreachable":"Error",a=m?"#4caf50":"#f44336",o=m?"✓":"✗";return e.jsxs("div",{style:C.section,children:[e.jsx("h3",{style:C.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:C.row,children:[e.jsxs("span",{style:{...C.label,color:`${a}`},children:[o," ",h,":"]}),e.jsxs("span",{style:C.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:C.row,children:[e.jsx("span",{style:C.label,children:"Endpoint:"}),e.jsx("span",{style:C.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 ge({title:t,children:i}){const[s,u]=n.useState(!0),l=`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:()=>u(m=>!m),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":l,children:[e.jsx("span",{children:t}),e.jsx(Y,{className:J("h-4 w-4 text-muted-foreground transition-transform",s&&"rotate-180"),"aria-hidden":"true"})]}),s&&e.jsx("div",{id:l,className:"divide-y divide-border px-4 py-1",children:i})]})}const pe="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 be(){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 je({setting:t,id:i,llmActive:s,saving:u,onUpdate:l}){const[m,h]=n.useState(null),a=t.requiresLlm&&!s,o=n.useRef(null);n.useEffect(()=>()=>{o.current&&clearTimeout(o.current)},[]);const f=n.useCallback(r=>{l(t.key,r).then(g=>h(g)).catch(g=>h(g instanceof Error?g.message:String(g)))},[l,t.key]),c=n.useCallback(r=>{o.current&&clearTimeout(o.current),o.current=setTimeout(()=>f(r),500)},[f]),x=u||a;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:`${i}-input`,className:"cursor-pointer",children:t.label}),t.requiresLlm&&!s&&e.jsx(be,{})]}),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(le,{id:`${i}-input`,checked:!!t.value,disabled:x||a,onCheckedChange:r=>f(String(r)),"aria-label":t.label}):e.jsxs(e.Fragment,{children:[e.jsx("input",{id:`${i}-input`,type:t.type==="number"?"number":"text",defaultValue:String(t.value??""),min:t.min,max:t.max,disabled:x,onChange:r=>c(r.target.value),className:`${pe} ${t.type==="number"?"w-24":"w-56"}`}),t.unit&&e.jsx("span",{className:"text-xs text-muted-foreground",children:t.unit})]})})]}),m&&e.jsxs("p",{className:"mt-1 text-xs text-danger",children:["Error: ",m]})]})}function ve(){const[t,i]=n.useState(null),[s,u]=n.useState(null),[l,m]=n.useState(!1),[h,a]=n.useState(null),o=n.useCallback(()=>{Q().then(i).catch(c=>u(c instanceof Error?c.message:String(c)))},[]);n.useEffect(()=>{o()},[o]);const f=n.useCallback(async(c,x)=>{m(!0);try{const r=await Z({key:c,value:x});return a(r.restartRequired?"Saved — restart pi to apply changes.":"Saved."),o(),null}catch(r){return r instanceof Error?r.message:String(r)}finally{m(!1)}},[o]);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(c=>e.jsx(ge,{title:c.name,children:c.settings.map(x=>e.jsx(je,{setting:x,id:`${c.name.replace(/[^a-z0-9]+/gi,"-")}-${x.key}`,llmActive:t.llmActive,saving:l,onUpdate:f},x.key))},c.name)),h&&e.jsx("div",{className:"mt-1 rounded-md border border-warning/40 bg-warning/10 p-2 text-xs text-warning",role:"status",children:h})]})}const d={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 ye({customUrl:t,setCustomUrl:i,applyEmbedder:s,configuring:u}){return e.jsxs("div",{style:d.section,children:[e.jsx("h3",{style:d.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:l=>i(l.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:{...d.button,opacity:t?1:.4},onClick:()=>s("custom",t),disabled:!t||u!==null,children:u==="custom"?"Writing...":"Use Custom URL"})]}),e.jsxs("div",{style:d.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 Se(){const[t,i]=n.useState(null),[s,u]=n.useState(null),[l,m]=n.useState(null),[h,a]=n.useState(null),[o,f]=n.useState(!1),[c,x]=n.useState(null),[r,g]=n.useState(null),[S,v]=n.useState(null),[N,M]=n.useState(""),j=n.useCallback(()=>{ee().then(i).catch(p=>m(p instanceof Error?p.message:String(p)))},[]),k=n.useCallback((p,w)=>{x(p),v(null),g(null),te({embedder:p,url:w}).then(E=>{g(E),x(null),j()}).catch(E=>{v(E instanceof Error?E.message:String(E)),x(null)})},[j]),D=n.useCallback(()=>{f(!0),a(null),se().then(p=>{u(p),f(!1)}).catch(p=>{a(p instanceof Error?p.message:String(p)),f(!1)})},[]);n.useEffect(()=>{j()},[j]),n.useEffect(()=>{const p=setInterval(j,3e4);return()=>clearInterval(p)},[j]);const R=p=>{switch(p){case"trigram":return"TrigramEmbedder (heuristic, default)";case"http":return"HTTP Embedder (BYO localhost)";case"minilm":return"MiniLM (experimental)";default:return"Unknown"}},b=t?.currentEmbedder==="trigram"&&e.jsxs("div",{style:d.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."]}),y=p=>{const w=p?"#1a5a1a":"#3a1a1a",E=p?"#4caf50":"#f44336";return e.jsx("span",{style:{...d.badge,background:w,color:E},children:p?"Detected":"Not found"})};return e.jsxs("div",{style:d.container,children:[e.jsx("h2",{style:{fontSize:"1.3rem",marginTop:0,marginBottom:"1rem"},children:"Embedder Setup"}),e.jsx(xe,{}),e.jsxs("div",{style:d.section,children:[e.jsx("h3",{style:d.sectionTitle,children:"Current Embedder Configuration"}),l&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",l]}),t&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:d.row,children:[e.jsx("span",{style:d.label,children:"Active Embedder:"}),e.jsx("span",{style:d.value,children:R(t.currentEmbedder)})]}),"configuredEmbedder"in t&&t.configuredEmbedder!==t.currentEmbedder&&e.jsxs("div",{style:d.warning,children:[e.jsx("strong",{children:"Configured but not active:"})," ",R(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:{...d.row,color:"#ff9800"},children:[e.jsx("span",{style:d.label,children:"Status:"}),e.jsx("span",{style:d.value,children:"Restart required to activate the configured embedder"})]}),e.jsxs("div",{style:d.row,children:[e.jsx("span",{style:d.label,children:"Embedding URL:"}),e.jsx("span",{style:d.value,children:t.embeddingUrl??e.jsx("span",{style:{color:"#888"},children:"not set"})})]}),e.jsxs("div",{style:d.row,children:[e.jsx("span",{style:d.label,children:"Embed Cache:"}),e.jsx("span",{style:d.value,children:t.embedCache??e.jsx("span",{style:{color:"#888"},children:"not set"})})]}),e.jsxs("div",{style:d.row,children:[e.jsx("span",{style:d.label,children:"MiniLM:"}),e.jsx("span",{style:d.value,children:t.minilm?"enabled":"disabled"})]}),b]}),!t&&!l&&e.jsx("p",{style:{color:"#888",fontSize:"0.85rem"},children:"Loading configuration..."})]}),e.jsxs("div",{style:d.section,children:[e.jsx("h3",{style:d.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:d.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"Ollama"})}),s.ollama!==null?e.jsxs("span",{children:[y(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:d.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"llama.cpp"})}),s.llamaCpp!==null?e.jsxs("span",{children:[y(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:d.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"ONNX Runtime"})}),s.onnx!==null?e.jsxs("span",{children:[y(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]})]}),h&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",h]}),e.jsxs("div",{style:{marginTop:"1rem"},children:[e.jsx("button",{style:d.button,onClick:D,disabled:o,children:o?"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:{...d.button,opacity:s.ollama?.installed?1:.4},onClick:()=>k("ollama"),disabled:!s.ollama?.installed||c!==null,children:c==="ollama"?"Writing...":"Use Ollama"}),e.jsx("button",{style:{...d.button,opacity:s.llamaCpp?.installed?1:.4},onClick:()=>k("llama"),disabled:!s.llamaCpp?.installed||c!==null,children:c==="llama"?"Writing...":"Use llama.cpp"}),e.jsx("button",{style:{...d.button,opacity:s.onnx?.installed?1:.4},onClick:()=>k("onnx"),disabled:!s.onnx?.installed||c!==null,children:c==="onnx"?"Writing...":"Use ONNX"}),e.jsx("button",{style:{...d.button,background:"#444"},onClick:()=>k("trigram"),disabled:c!==null,children:c==="trigram"?"Writing...":"Use Trigram (default)"})]}),r&&e.jsx("div",{style:d.warning,children:r.alreadyActive?"Already active — no restart needed.":`Configured ${r.embedder}. Restart pi to activate (config written to ${r.envPath}).`}),S&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem",marginTop:"0.5rem"},children:["Configure error: ",S]})]})]}),e.jsx(ye,{customUrl:N,setCustomUrl:M,applyEmbedder:k,configuring:c}),e.jsxs("div",{style:d.section,children:[e.jsx("h3",{style:d.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:d.section,children:[e.jsx("h3",{style:d.sectionTitle,children:"Settings"}),e.jsx(ve,{})]})]})}function A(t){return t>=1e6?`${(t/1e6).toFixed(2)}M`:t>=1e3?`${Math.round(t/1e3)}K`:String(t)}function we(t,i,s){if(t<=0)return"—";const l=(i>0?i:Math.ceil(t*.1))+Math.ceil(t*(s/100)),m=t-l;return m<=0?"0 (at risk)":`${A(m)} tokens`}function B({label:t,value:i,min:s,max:u,step:l=1,onChange:m,warning:h}){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 ${h?"text-warning":"text-fg"}`,title:h,children:[i,"%"]})]}),e.jsx("input",{type:"range",min:s,max:u,step:l,value:i,onChange:a=>m(Number(a.target.value)),className:"threshold-slider w-full"}),h&&e.jsxs("p",{className:"text-[10px] text-warning",children:["⚠ ",h]})]})}function Ne({model:t,defaults:i,safetyRange:s,fireRange:u,onSave:l,onReset:m,saving:h}){const[a,o]=n.useState(t.threshold.safetyMarginPct),[f,c]=n.useState(t.threshold.firePointPct),[x,r]=n.useState(!1),[g,S]=n.useState(null);n.useEffect(()=>{o(t.threshold.safetyMarginPct),c(t.threshold.firePointPct),r(!1)},[t.threshold.safetyMarginPct,t.threshold.firePointPct]);const v=a<5?'Low safety margin — risks "conversation too long" errors when a single turn injects a large tool output between gate fires.':void 0,N=f>85?"High fire point — compaction may trigger close to the window cap; a single large turn can overshoot before the gate fires.":void 0,M=n.useCallback(async()=>{S(null);try{await l(t.modelId,a,f),r(!1)}catch(j){S(j instanceof Error?j.message:String(j))}},[t.modelId,a,f,l]);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," · ",A(t.contextWindow)," window ·"," ",A(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:we(t.contextWindow,t.maxTokens,a)})]}),e.jsxs("div",{children:["Compaction fires at:"," ",e.jsx("span",{className:"font-mono text-fg",children:A(Math.ceil(t.contextWindow*(f/100)))})]})]})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsx(B,{label:"Safety margin",value:a,min:s[0],max:s[1],onChange:j=>{o(j),r(!0)},warning:v}),e.jsx(B,{label:"Fire point",value:f,min:u[0],max:u[1],onChange:j=>{c(j),r(!0)},warning:N})]}),e.jsxs("div",{className:"mt-2 flex items-center gap-2",children:[e.jsx("button",{type:"button",onClick:M,disabled:!x||h,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:()=>m(t.modelId),disabled:h,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 (",i.safetyMarginPct,"% /"," ",i.firePointPct,"%)"]}),g&&e.jsx("span",{className:"text-[11px] text-error",children:g})]})]})}function Ee(){const[t,i]=n.useState(null),[s,u]=n.useState(!0),[l,m]=n.useState(null),[h,a]=n.useState(!1),o=n.useCallback(async()=>{try{m(null),i(await ne())}catch(x){m(x instanceof Error?x.message:String(x))}finally{u(!1)}},[]);n.useEffect(()=>{o()},[o]);const f=n.useCallback(async(x,r,g)=>{a(!0);try{await ae({modelId:x,safetyMarginPct:r,firePointPct:g}),await o()}finally{a(!1)}},[o]),c=n.useCallback(async x=>{a(!0);try{await re(x),await o()}finally{a(!1)}},[o]);return s?e.jsx("div",{className:"p-4 text-sm text-fg-muted",children:"Loading thresholds…"}):l?e.jsxs("div",{className:"p-4 text-sm text-error",children:["Error: ",l]}):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(Ne,{model:x,defaults:t.defaults,safetyRange:t.defaults.safetyMarginRange,fireRange:t.defaults.firePointRange,onSave:f,onReset:c,saving:h},x.modelId))})]}):e.jsx("div",{className:"p-4 text-sm text-fg-muted",children:"No data."})}const Te=[{id:"embedder",label:"Embedder"},{id:"thresholds",label:"Thresholds"},{id:"config",label:"Config"},{id:"game",label:"Game Mode"},{id:"achievements",label:"Achievements"}];function Re(){const[t,i]=n.useState("embedder");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:Te.map(s=>e.jsx(ie,{pressed:t===s.id,onClick:()=>i(s.id),children:s.label},s.id))}),t==="embedder"&&e.jsx(Se,{}),t==="thresholds"&&e.jsx(Ee,{}),t==="config"&&e.jsx(fe,{}),t==="game"&&e.jsx(de,{}),t==="achievements"&&e.jsx(me,{})]})}export{Re as default};
2
- //# sourceMappingURL=SetupTab-DnN0mX0J.js.map