react-state-basis 0.5.1 → 0.6.1

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/index.js CHANGED
@@ -91,24 +91,176 @@ var calculateCosineSimilarity = (A, B) => {
91
91
  return magA === 0 || magB === 0 ? 0 : dot / (Math.sqrt(magA) * Math.sqrt(magB));
92
92
  };
93
93
 
94
+ // src/core/graph.ts
95
+ var calculateSpectralInfluence = (graph, maxIterations = 20, tolerance = 1e-3) => {
96
+ const nodes = Array.from(/* @__PURE__ */ new Set([...graph.keys(), ...Array.from(graph.values()).flatMap((m) => [...m.keys()])]));
97
+ if (nodes.length === 0) return /* @__PURE__ */ new Map();
98
+ let scores = /* @__PURE__ */ new Map();
99
+ nodes.forEach((n) => scores.set(n, 1 / nodes.length));
100
+ for (let i = 0; i < maxIterations; i++) {
101
+ const nextScores = /* @__PURE__ */ new Map();
102
+ let totalWeight = 0;
103
+ nodes.forEach((source) => {
104
+ let influence = 0;
105
+ const outgoing = graph.get(source);
106
+ if (outgoing) {
107
+ outgoing.forEach((weight, target) => {
108
+ if (source !== target) {
109
+ influence += (scores.get(target) || 0) * weight;
110
+ }
111
+ });
112
+ }
113
+ nextScores.set(source, influence + 0.01);
114
+ totalWeight += influence + 0.01;
115
+ });
116
+ let delta = 0;
117
+ nextScores.forEach((val, key) => {
118
+ const normalized = val / totalWeight;
119
+ const diff = normalized - (scores.get(key) || 0);
120
+ delta += diff * diff;
121
+ nextScores.set(key, normalized);
122
+ });
123
+ scores = nextScores;
124
+ if (Math.sqrt(delta) < tolerance) break;
125
+ }
126
+ return scores;
127
+ };
128
+
129
+ // src/core/ranker.ts
130
+ var parseLabel = (label) => {
131
+ const parts = label.split(" -> ");
132
+ return { file: parts[0] || "Unknown", name: parts[1] || label };
133
+ };
134
+ var identifyTopIssues = (graph, history2, redundantLabels2, violationMap) => {
135
+ const results = [];
136
+ const influence = calculateSpectralInfluence(graph);
137
+ const isEffect = (label) => label.includes("effect_L") || label.includes("useLayoutEffect") || label.includes("useInsertionEffect");
138
+ const isEvent = (label) => label.startsWith("Event_Tick_");
139
+ const eventSignatures = /* @__PURE__ */ new Map();
140
+ const drivers = Array.from(graph.entries()).filter(([label, targets]) => {
141
+ if (targets.size === 0) return false;
142
+ if (isEvent(label)) {
143
+ const validTargets = Array.from(targets.keys()).filter((t) => {
144
+ const meta2 = history2.get(t);
145
+ return meta2 && meta2.role !== "context" /* CONTEXT */;
146
+ });
147
+ if (validTargets.length > 1) {
148
+ const signature = validTargets.sort().join("|");
149
+ const existing = eventSignatures.get(signature);
150
+ if (existing) {
151
+ existing.count++;
152
+ existing.score = Math.max(existing.score, influence.get(label) || 0);
153
+ } else {
154
+ eventSignatures.set(signature, {
155
+ count: 1,
156
+ score: influence.get(label) || 0,
157
+ targets: validTargets
158
+ });
159
+ }
160
+ }
161
+ return false;
162
+ }
163
+ const meta = history2.get(label);
164
+ if (meta?.role === "context" /* CONTEXT */) return false;
165
+ if (meta?.role === "proj" /* PROJECTION */) return false;
166
+ const score = influence.get(label) || 0;
167
+ if (isEffect(label) && targets.size > 0) return true;
168
+ if (targets.size < 2 && score < 0.05) return false;
169
+ return true;
170
+ }).sort((a, b) => {
171
+ const scoreA = influence.get(a[0]) || 0;
172
+ const scoreB = influence.get(b[0]) || 0;
173
+ return scoreB - scoreA;
174
+ });
175
+ const sortedEvents = Array.from(eventSignatures.entries()).sort((a, b) => b[1].targets.length - a[1].targets.length);
176
+ sortedEvents.slice(0, 2).forEach(([sig, data]) => {
177
+ const primaryVictim = parseLabel(data.targets[0]);
178
+ const smartLabel = `${primaryVictim.file} -> Global Event (${primaryVictim.name})`;
179
+ results.push({
180
+ label: smartLabel,
181
+ metric: "influence",
182
+ score: 1,
183
+ reason: `Global Sync Event: An external trigger is updating ${data.targets.length} roots simultaneously. Occurred ${data.count} times.`,
184
+ violations: data.targets.map((t) => ({
185
+ type: "causal_leak",
186
+ target: t
187
+ }))
188
+ });
189
+ });
190
+ drivers.slice(0, 3 - results.length).forEach(([label, targets]) => {
191
+ const targetNames = Array.from(targets.keys());
192
+ if (isEffect(label)) {
193
+ results.push({
194
+ label,
195
+ metric: "influence",
196
+ score: influence.get(label) || 0,
197
+ reason: `Side-Effect Driver: Hook writes to state during render.`,
198
+ violations: targetNames.map((t) => ({ type: "causal_leak", target: t }))
199
+ });
200
+ return;
201
+ }
202
+ results.push({
203
+ label,
204
+ metric: "influence",
205
+ score: influence.get(label) || targets.size,
206
+ reason: `Sync Driver: Acts as a "Prime Mover" for ${targets.size} downstream signals.`,
207
+ violations: targetNames.map((t) => ({ type: "causal_leak", target: t }))
208
+ });
209
+ });
210
+ if (results.length === 0) {
211
+ const sortedDensity = Array.from(history2.entries()).filter(
212
+ ([label, meta]) => meta.role === "local" /* LOCAL */ && !redundantLabels2.has(label) && meta.density > 25
213
+ ).sort((a, b) => b[1].density - a[1].density);
214
+ sortedDensity.slice(0, 3).forEach(([label, meta]) => {
215
+ results.push({
216
+ label,
217
+ metric: "density",
218
+ score: meta.density,
219
+ reason: `High Frequency: potential main-thread saturation.`,
220
+ violations: []
221
+ });
222
+ });
223
+ }
224
+ return results;
225
+ };
226
+
94
227
  // src/core/logger.ts
95
228
  var isWeb = typeof window !== "undefined" && typeof window.document !== "undefined";
96
229
  var LAST_LOG_TIMES = /* @__PURE__ */ new Map();
97
230
  var LOG_COOLDOWN = 3e3;
231
+ var THEME = {
232
+ identity: "#6C5CE7",
233
+ // Purple (Brand)
234
+ problem: "#D63031",
235
+ // Red (Bugs)
236
+ solution: "#FBC531",
237
+ // Yellow (Fixes)
238
+ context: "#0984E3",
239
+ // Blue (Locations)
240
+ muted: "#9AA0A6",
241
+ // Gray (Metadata)
242
+ border: "#2E2E35",
243
+ success: "#00b894"
244
+ // Green (Good Score)
245
+ };
98
246
  var STYLES = {
99
- basis: "background: #6c5ce7; color: white; font-weight: bold; padding: 2px 6px; border-radius: 3px;",
100
- version: "background: #a29bfe; color: #2d3436; padding: 2px 6px; border-radius: 3px; margin-left: -4px;",
101
- headerRed: "background: #d63031; color: white; font-weight: bold; padding: 4px 8px; border-radius: 4px;",
102
- headerBlue: "background: #0984e3; color: white; font-weight: bold; padding: 4px 8px; border-radius: 4px;",
103
- headerGreen: "background: #00b894; color: white; font-weight: bold; padding: 4px 8px; border-radius: 4px;",
104
- label: "background: #dfe6e9; color: #2d3436; padding: 0 4px; border-radius: 3px; font-family: monospace; font-weight: bold; border: 1px solid #b2bec3;",
105
- location: "color: #0984e3; font-family: monospace; font-weight: bold;",
106
- subText: "color: #636e72; font-size: 11px;",
247
+ // Structure
248
+ basis: `background: ${THEME.identity}; color: white; font-weight: bold; padding: 2px 6px; border-radius: 3px;`,
249
+ headerIdentity: `background: ${THEME.identity}; color: white; font-weight: bold; padding: 4px 8px; border-radius: 4px;`,
250
+ headerProblem: `background: ${THEME.problem}; color: white; font-weight: bold; padding: 4px 8px; border-radius: 4px;`,
251
+ version: `background: #a29bfe; color: #2d3436; padding: 2px 6px; border-radius: 3px; margin-left: -4px;`,
252
+ // Actions
253
+ actionLabel: `color: ${THEME.solution}; font-weight: bold;`,
254
+ actionPill: `color: ${THEME.solution}; font-weight: bold; border: 1px solid ${THEME.solution}; padding: 0 4px; border-radius: 3px;`,
255
+ // Context
256
+ impactLabel: `color: ${THEME.context}; font-weight: bold;`,
257
+ location: `color: ${THEME.context}; font-family: monospace; font-weight: bold;`,
258
+ // Text
259
+ subText: `color: ${THEME.muted}; font-size: 11px;`,
107
260
  bold: "font-weight: bold;",
108
- action: "color: #00b894; font-weight: bold; border: 1px solid #00b894; padding: 0 4px; border-radius: 3px;",
109
- warning: "color: #d63031; font-weight: bold; border: 1px solid #d63031; padding: 0 4px; border-radius: 3px;"
261
+ label: "background: #dfe6e9; color: #2d3436; padding: 0 4px; border-radius: 3px; font-family: monospace; font-weight: bold; border: 1px solid #b2bec3;"
110
262
  };
111
- var parseLabel = (label) => {
263
+ var parseLabel2 = (label) => {
112
264
  const parts = label.split(" -> ");
113
265
  return { file: parts[0] || "Unknown", name: parts[1] || label };
114
266
  };
@@ -121,57 +273,103 @@ var shouldLog = (key) => {
121
273
  }
122
274
  return false;
123
275
  };
124
- var displayRedundancyAlert = (labelA, metaA, labelB, metaB, sim) => {
125
- if (!isWeb || !shouldLog(`redundant-${labelA}-${labelB}`)) return;
126
- const infoA = parseLabel(labelA);
127
- const infoB = parseLabel(labelB);
128
- const isContextMirror = metaA.role === "local" && metaB.role === "context" || metaB.role === "local" && metaA.role === "context";
129
- const local = metaA.role === "local" ? infoA : infoB;
130
- const context = metaA.role === "context" ? infoA : infoB;
131
- console.group(`%c \u264A BASIS | ${isContextMirror ? "CONTEXT MIRRORING" : "DUPLICATE STATE"} `, STYLES.headerRed);
132
- console.log(`%c\u{1F4CD} Location: %c${infoA.file}`, STYLES.bold, STYLES.location);
133
- if (isContextMirror) {
134
- console.log(
135
- `%cIssue:%c Local variable %c${local.name}%c is just a copy of Global Context %c${context.name}%c.
136
- %cConfidence: ${(sim * 100).toFixed(0)}%`,
137
- STYLES.bold,
138
- "",
139
- STYLES.label,
140
- "",
141
- STYLES.label,
142
- "",
143
- STYLES.subText
144
- );
145
- console.log(`%cFix:%c Use the context value directly to avoid state drift.`, STYLES.bold, STYLES.warning);
146
- } else {
147
- console.log(
148
- `%cIssue:%c %c${infoA.name}%c and %c${infoB.name}%c are synchronized (${(sim * 100).toFixed(0)}% correlation).`,
149
- STYLES.bold,
150
- "",
151
- STYLES.label,
152
- "",
153
- STYLES.label,
154
- ""
155
- );
156
- console.log(
157
- `%cFix:%c Merge states or calculate %c${infoB.name}%c from %c${infoA.name}%c via %cuseMemo%c.`,
158
- STYLES.bold,
159
- "",
160
- STYLES.label,
161
- "",
162
- STYLES.label,
163
- "",
164
- STYLES.action,
165
- ""
166
- );
276
+ var isBooleanLike = (name) => /^(is|has|can|should|did|will|show|hide)(?=[A-Z_])/.test(name);
277
+ var getSuggestedFix = (issue, info) => {
278
+ if (issue.label.includes("Global Event")) {
279
+ return `These variables update together but live in different hooks/files. Consolidate them into a single %cuseReducer%c or atomic store update.`;
167
280
  }
168
- console.groupEnd();
281
+ const violations = issue.violations || [];
282
+ const leaks = violations.filter((v) => v.type === "causal_leak");
283
+ const mirrors = violations.filter((v) => v.type === "context_mirror");
284
+ const duplicates = violations.filter((v) => v.type === "duplicate_state");
285
+ if (mirrors.length > 0) {
286
+ return `Local state is 'shadowing' Global Context. This creates two sources of truth. Delete the local state and consume the %cContext%c value directly.`;
287
+ }
288
+ if (leaks.length > 0) {
289
+ const targetName = parseLabel2(leaks[0].target).name;
290
+ if (issue.label.includes("effect")) {
291
+ return `This Effect triggers a synchronous re-render of ${targetName}. Calculate ${targetName} during the render phase (Derived State) or wrap in %cuseMemo%c if expensive.`;
292
+ }
293
+ return `State cascading detected. ${info.name} triggers ${targetName} in a separate frame. Merge them into one object to update simultaneously.`;
294
+ }
295
+ if (duplicates.length > 0) {
296
+ if (isBooleanLike(info.name)) {
297
+ return `Boolean Explosion detected. Multiple flags are toggling in sync. Replace impossible states with a single %cstatus%c string ('idle' | 'loading' | 'success').`;
298
+ }
299
+ return `Redundant State detected. This variable carries no unique information. Derive it from the source variable during render, or use %cuseMemo%c to cache the result.`;
300
+ }
301
+ if (issue.metric === "density") {
302
+ return `High-Frequency Update. This variable updates faster than the frame rate. Apply %cdebounce%c or move to a Ref to unblock the main thread.`;
303
+ }
304
+ return `Check the dependency chain of ${info.name}.`;
169
305
  };
170
- var displayHealthReport = (history2, threshold) => {
306
+ var displayHealthReport = (history2, threshold, violationMap) => {
171
307
  if (!isWeb) return;
172
308
  const entries = Array.from(history2.entries());
173
- const totalVars = entries.length;
174
- if (totalVars === 0) return;
309
+ if (entries.length === 0) return;
310
+ const topIssues = identifyTopIssues(instance.graph, history2, instance.redundantLabels, violationMap);
311
+ console.group(`%c \u{1F4CA} BASIS | ARCHITECTURAL HEALTH REPORT `, STYLES.headerIdentity);
312
+ if (topIssues.length > 0) {
313
+ console.log(
314
+ `%c\u{1F3AF} REFACTOR PRIORITIES %c(PRIME MOVERS)`,
315
+ `font-weight: bold; color: ${THEME.identity}; margin-top: 10px;`,
316
+ `font-weight: normal; color: ${THEME.muted}; font-style: italic;`
317
+ );
318
+ topIssues.forEach((issue, idx) => {
319
+ const info = parseLabel2(issue.label);
320
+ const icon = issue.metric === "influence" ? "\u26A1" : "\u{1F4C8}";
321
+ const pColor = idx === 0 ? THEME.problem : idx === 1 ? THEME.solution : THEME.identity;
322
+ let displayName = info.name;
323
+ let displayFile = info.file;
324
+ if (issue.label.includes("Global Event")) {
325
+ displayName = info.name;
326
+ displayFile = info.file;
327
+ }
328
+ console.group(
329
+ ` %c${idx + 1}%c ${icon} ${displayName} %c(${displayFile})`,
330
+ `background: ${pColor}; color: ${idx === 1 ? "black" : "white"}; border-radius: 50%; padding: 0 5px;`,
331
+ "font-family: monospace; font-weight: 700;",
332
+ `color: ${THEME.muted}; font-size: 10px; font-weight: normal; font-style: italic;`
333
+ );
334
+ console.log(`%c${issue.reason}`, `color: ${THEME.muted}; font-style: italic;`);
335
+ if (issue.violations.length > 0) {
336
+ const byFile = /* @__PURE__ */ new Map();
337
+ issue.violations.forEach((v) => {
338
+ if (issue.label.includes("Global Event") && v.type === "context_mirror") return;
339
+ const { file, name } = parseLabel2(v.target);
340
+ if (!byFile.has(file)) byFile.set(file, []);
341
+ byFile.get(file).push(name);
342
+ });
343
+ const impactParts = [];
344
+ byFile.forEach((vars, file) => {
345
+ const varList = vars.join(", ");
346
+ impactParts.push(`${file} (${varList})`);
347
+ });
348
+ if (impactParts.length > 0) {
349
+ console.log(`%cImpacts: %c${impactParts.join(" + ")}`, STYLES.impactLabel, "");
350
+ }
351
+ }
352
+ const fix = getSuggestedFix(issue, info);
353
+ const fixParts = fix.split("%c");
354
+ if (fixParts.length === 3) {
355
+ console.log(
356
+ `%cSolution: %c${fixParts[0]}%c${fixParts[1]}%c${fixParts[2]}`,
357
+ STYLES.actionLabel,
358
+ "",
359
+ STYLES.actionPill,
360
+ ""
361
+ );
362
+ } else {
363
+ console.log(
364
+ `%cSolution: %c${fix}`,
365
+ STYLES.actionLabel,
366
+ ""
367
+ );
368
+ }
369
+ console.groupEnd();
370
+ });
371
+ console.log("\n");
372
+ }
175
373
  const clusters = [];
176
374
  const processed = /* @__PURE__ */ new Set();
177
375
  let independentCount = 0;
@@ -181,9 +379,8 @@ var displayHealthReport = (history2, threshold) => {
181
379
  processed.add(labelA);
182
380
  entries.forEach(([labelB, metaB]) => {
183
381
  if (labelA === labelB || processed.has(labelB)) return;
184
- const sim = calculateCosineSimilarity(metaA.buffer, metaB.buffer);
185
- if (sim > threshold) {
186
- if (metaA.role === "context" && metaB.role === "context") return;
382
+ if (calculateCosineSimilarity(metaA.buffer, metaB.buffer) > threshold) {
383
+ if (metaA.role === "context" /* CONTEXT */ && metaB.role === "context" /* CONTEXT */) return;
187
384
  currentCluster.push(labelB);
188
385
  processed.add(labelB);
189
386
  }
@@ -191,73 +388,159 @@ var displayHealthReport = (history2, threshold) => {
191
388
  if (currentCluster.length > 1) clusters.push(currentCluster);
192
389
  else independentCount++;
193
390
  });
194
- const systemRank = independentCount + clusters.length;
195
- const healthScore = systemRank / totalVars * 100;
196
- console.group(`%c \u{1F4CA} BASIS | ARCHITECTURAL HEALTH REPORT `, STYLES.headerGreen);
391
+ const totalVars = entries.length;
392
+ const redundancyScore = (independentCount + clusters.length) / totalVars * 100;
393
+ let internalEdges = 0;
394
+ instance.graph.forEach((targets, source) => {
395
+ if (source.startsWith("Event_Tick_")) return;
396
+ internalEdges += targets.size;
397
+ });
398
+ const causalPenalty = internalEdges / totalVars * 100;
399
+ let healthScore = redundancyScore - causalPenalty;
400
+ if (healthScore < 0) healthScore = 0;
401
+ const scoreColor = healthScore > 85 ? THEME.success : THEME.problem;
197
402
  console.log(
198
- `%cEfficiency: %c${healthScore.toFixed(1)}% %c(${systemRank}/${totalVars} Sources of Truth)`,
403
+ `%cSystem Efficiency: %c${healthScore.toFixed(1)}%`,
199
404
  STYLES.bold,
200
- `color: ${healthScore > 85 ? "#00b894" : "#d63031"}; font-weight: bold;`,
201
- STYLES.subText
405
+ `color: ${scoreColor}; font-weight: bold;`
202
406
  );
407
+ console.log(`%cSources of Truth: ${independentCount + clusters.length}/${totalVars} | Causal Leaks: ${internalEdges}`, STYLES.subText);
203
408
  if (clusters.length > 0) {
204
- console.log(`%cDetected ${clusters.length} Sync Issues:`, "font-weight: bold; color: #e17055; margin-top: 10px;");
409
+ console.log(`%cDetected ${clusters.length} Sync Issues:`, `font-weight: bold; color: ${THEME.problem}; margin-top: 10px;`);
205
410
  clusters.forEach((cluster, idx) => {
206
- const clusterMetas = cluster.map((l) => ({ label: l, meta: history2.get(l), info: parseLabel(l) }));
207
- const contexts = clusterMetas.filter((c) => c.meta.role === "context");
208
- const locals = clusterMetas.filter((c) => c.meta.role === "local");
209
- const names = clusterMetas.map((c) => `${c.meta.role === "context" ? "\u03A9 " : ""}${c.info.name}`).join(" \u27F7 ");
210
- console.group(` %c${idx + 1}%c ${names}`, "background: #e17055; color: white; border-radius: 50%; padding: 0 5px;", "font-family: monospace; font-weight: bold;");
211
- if (contexts.length > 0) {
212
- const ctxNames = contexts.map((c) => c.info.name).join(", ");
213
- console.log(`%cDiagnosis:%c Context Mirroring. Variables are copying from %c${ctxNames}%c.`, STYLES.bold, "", STYLES.label, "");
214
- console.log(`%cSolution:%c Use the context directly to avoid state drift.`, STYLES.bold, STYLES.action);
411
+ const clusterMetas = cluster.map((l) => ({
412
+ label: l,
413
+ meta: history2.get(l),
414
+ name: parseLabel2(l).name
415
+ }));
416
+ const hasCtx = clusterMetas.some(
417
+ (c) => c.meta.role === "context" /* CONTEXT */ || c.meta.role === "store" /* STORE */
418
+ );
419
+ const names = clusterMetas.map((c) => {
420
+ const prefix = c.meta.role === "store" /* STORE */ ? "\u03A3 " : c.meta.role === "context" /* CONTEXT */ ? "\u03A9 " : "";
421
+ return `${prefix}${c.name}`;
422
+ }).join(" \u27F7 ");
423
+ console.group(` %c${idx + 1}%c ${names}`, `background: ${THEME.problem}; color: white; border-radius: 50%; padding: 0 5px;`, "font-family: monospace; font-weight: bold;");
424
+ if (hasCtx) {
425
+ const hasStore = clusterMetas.some((c) => c.meta.role === "store" /* STORE */);
426
+ const sourceType = hasStore ? "External Store" : "global context";
427
+ console.log(`%cDiagnosis: ${hasStore ? "Store" : "Context"} Mirroring. Local state is shadowing ${sourceType}.`, `color: ${THEME.problem};`);
428
+ console.log(`%cSolution: Use ${sourceType} directly to avoid state drift.`, STYLES.actionLabel);
215
429
  } else {
216
- const isExplosion = locals.length > 2;
217
- if (isExplosion) {
218
- console.log(`%cDiagnosis:%c Boolean Explosion. Multiple states updating in sync.`, STYLES.bold, "");
219
- console.log(`%cSolution:%c Combine into a single %cstatus%c string or a %creducer%c.`, STYLES.bold, "", STYLES.label, "", STYLES.label, "");
430
+ const boolKeywords = ["is", "has", "can", "should", "loading", "success", "error", "active", "enabled", "open", "visible"];
431
+ const boolCount = clusterMetas.filter(
432
+ (c) => boolKeywords.some((kw) => c.name.toLowerCase().startsWith(kw))
433
+ ).length;
434
+ const isBoolExplosion = cluster.length > 2 && boolCount / cluster.length > 0.5;
435
+ if (isBoolExplosion) {
436
+ console.log(`%cDiagnosis:%c Boolean Explosion. Multiple booleans updating in sync.`, STYLES.bold, "");
437
+ console.log(`%cSolution:%c Combine into a single %cstatus%c string or a %creducer%c.`, STYLES.actionLabel, "", STYLES.actionPill, "", STYLES.actionPill, "");
438
+ } else if (cluster.length > 2) {
439
+ console.log(`%cDiagnosis:%c Sibling Updates. These states respond to the same event.`, STYLES.bold, "");
440
+ console.log(`%cSolution:%c This may be intentional. If not, consolidate into a %creducer%c.`, STYLES.actionLabel, "", STYLES.actionPill, "");
220
441
  } else {
221
442
  console.log(`%cDiagnosis:%c Redundant State. Variables always change together.`, STYLES.bold, "");
222
- console.log(`%cSolution:%c Derive one from the other via %cuseMemo%c.`, STYLES.bold, "", STYLES.label, "");
443
+ console.log(`%cSolution:%c Derive one from the other via %cuseMemo%c.`, STYLES.actionLabel, "", STYLES.actionPill, "");
223
444
  }
224
445
  }
225
446
  console.groupEnd();
226
447
  });
227
448
  } else {
228
- console.log("%c\u2728 Your architecture is clean. No redundant state detected.", "color: #00b894; font-weight: bold;");
449
+ console.log("%c\u2728 Your architecture is clean. No redundant state detected.", `color: ${THEME.success}; font-weight: bold;`);
450
+ }
451
+ console.groupEnd();
452
+ };
453
+ var displayRedundancyAlert = (labelA, metaA, labelB, metaB, sim) => {
454
+ if (!isWeb || !shouldLog(`redundant-${labelA}-${labelB}`)) return;
455
+ const infoA = parseLabel2(labelA);
456
+ const infoB = parseLabel2(labelB);
457
+ const isContextMirror = metaA.role === "local" /* LOCAL */ && metaB.role === "context" /* CONTEXT */ || metaB.role === "local" /* LOCAL */ && metaA.role === "context" /* CONTEXT */;
458
+ const isStoreMirror = metaA.role === "local" /* LOCAL */ && metaB.role === "store" /* STORE */ || metaB.role === "local" /* LOCAL */ && metaA.role === "store" /* STORE */;
459
+ const alertType = isContextMirror ? "CONTEXT MIRRORING" : isStoreMirror ? "STORE MIRRORING" : "DUPLICATE STATE";
460
+ console.group(`%c \u264A BASIS | ${alertType} `, STYLES.headerProblem);
461
+ console.log(`%c\u{1F4CD} Location: %c${infoA.file}`, STYLES.bold, STYLES.location);
462
+ console.log(`%cIssue:%c ${infoA.name} and ${infoB.name} are synchronized (${(sim * 100).toFixed(0)}%).`, STYLES.bold, "");
463
+ if (isContextMirror || isStoreMirror) {
464
+ const sourceType = isStoreMirror ? "External Store" : "Global Context";
465
+ console.log(
466
+ `%cFix:%c Local state is 'shadowing' ${sourceType}. Delete the local state and consume the %c${sourceType}%c value directly.`,
467
+ STYLES.bold,
468
+ "",
469
+ STYLES.actionPill,
470
+ ""
471
+ );
472
+ } else {
473
+ if (isBooleanLike(infoA.name) || isBooleanLike(infoB.name)) {
474
+ console.log(
475
+ `%cFix:%c Boolean Explosion detected. Merge flags into a single %cstatus%c string or %cuseReducer%c.`,
476
+ STYLES.bold,
477
+ "",
478
+ STYLES.actionPill,
479
+ "",
480
+ STYLES.actionPill,
481
+ ""
482
+ );
483
+ } else {
484
+ console.log(
485
+ `%cFix:%c Redundant State detected. Derive %c${infoB.name}%c from %c${infoA.name}%c during render, or use %cuseMemo%c.`,
486
+ STYLES.bold,
487
+ "",
488
+ STYLES.label,
489
+ "",
490
+ STYLES.label,
491
+ "",
492
+ STYLES.actionPill,
493
+ ""
494
+ );
495
+ }
229
496
  }
230
497
  console.groupEnd();
231
498
  };
232
499
  var displayCausalHint = (targetLabel, targetMeta, sourceLabel, sourceMeta) => {
233
500
  if (!isWeb || !shouldLog(`causal-${sourceLabel}-${targetLabel}`)) return;
234
- const target = parseLabel(targetLabel);
235
- const source = parseLabel(sourceLabel);
236
- const isContextTrigger = sourceMeta.role === "context";
237
- console.groupCollapsed(`%c \u26A1 BASIS | ${isContextTrigger ? "CONTEXT SYNC LEAK" : "DOUBLE RENDER"} `, STYLES.headerBlue);
501
+ const target = parseLabel2(targetLabel);
502
+ const source = parseLabel2(sourceLabel);
503
+ const headerType = sourceMeta.role === "context" /* CONTEXT */ ? "CONTEXT SYNC LEAK" : sourceMeta.role === "store" /* STORE */ ? "STORE SYNC LEAK" : "DOUBLE RENDER";
504
+ const isEffect = sourceLabel.includes("effect") || sourceLabel.includes("useLayoutEffect");
505
+ console.groupCollapsed(`%c \u26A1 BASIS | ${headerType} `, STYLES.headerProblem);
238
506
  console.log(`%c\u{1F4CD} Location: %c${target.file}`, STYLES.bold, STYLES.location);
239
- if (isContextTrigger) {
240
- console.log(`%cIssue:%c Context %c${source.name}%c updated, then local %c${target.name}%c followed 1 frame later.`, STYLES.bold, "", STYLES.label, "", STYLES.label, "");
241
- console.log(`%cImpact: This forces React to render the component twice for every change.`, STYLES.subText);
507
+ console.log(`%cIssue:%c ${source.name} triggers ${target.name} in separate frames.`, STYLES.bold, "");
508
+ if (isEffect) {
509
+ console.log(
510
+ `%cFix:%c Derive %c${target.name}%c during the render phase (remove effect) or wrap in %cuseMemo%c.`,
511
+ STYLES.bold,
512
+ "",
513
+ STYLES.label,
514
+ "",
515
+ STYLES.actionPill,
516
+ ""
517
+ );
242
518
  } else {
243
- console.log(`%cIssue:%c %c${source.name}%c triggers %c${target.name}%c in a separate frame.`, STYLES.bold, "", STYLES.label, "", STYLES.label, "");
519
+ console.log(
520
+ `%cFix:%c Merge %c${target.name}%c with %c${source.name}%c into a single state update.`,
521
+ STYLES.bold,
522
+ "",
523
+ STYLES.label,
524
+ "",
525
+ STYLES.label,
526
+ ""
527
+ );
244
528
  }
245
- console.log(`%cFix:%c Derive %c${target.name}%c during the first render.`, STYLES.bold, STYLES.action, STYLES.label, "");
246
529
  console.groupEnd();
247
530
  };
248
531
  var displayViolentBreaker = (label, count, threshold) => {
249
532
  if (!isWeb) return;
250
533
  const parts = label.split(" -> ");
251
- console.group(`%c \u{1F6D1} BASIS CRITICAL | CIRCUIT BREAKER `, "background: #dc2626; color: white; font-weight: bold; padding: 8px 16px;");
534
+ console.group(`%c \u{1F6D1} BASIS CRITICAL | CIRCUIT BREAKER `, STYLES.headerProblem);
252
535
  console.error(`INFINITE LOOP DETECTED
253
536
  Variable: ${parts[1] || label}
254
537
  Frequency: ${count} updates/sec`);
255
- console.log(`%cACTION: Update BLOCKED to prevent browser freeze.`, "color: #dc2626; font-weight: bold;");
538
+ console.log(`%cACTION: Update BLOCKED to prevent browser freeze.`, `color: ${THEME.problem}; font-weight: bold;`);
256
539
  console.groupEnd();
257
540
  };
258
541
  var displayBootLog = (windowSize) => {
259
542
  if (!isWeb) return;
260
- console.log(`%cBasis%cAuditor%c | v0.5.x Architectural Forensics Active (Window: ${windowSize})`, STYLES.basis, STYLES.version, "color: #636e72; font-style: italic; margin-left: 8px;");
543
+ console.log(`%cBasis%cAuditor%c "Graph Era" (Window: ${windowSize})`, STYLES.basis, STYLES.version, `color: ${THEME.muted}; font-style: italic; margin-left: 8px;`);
261
544
  };
262
545
 
263
546
  // src/core/constants.ts
@@ -267,10 +550,37 @@ var LOOP_THRESHOLD = 150;
267
550
  var VOLATILITY_THRESHOLD = 25;
268
551
 
269
552
  // src/core/analysis.ts
553
+ var CAUSAL_MARGIN = 0.05;
554
+ var isEventDriven = (label, graph) => {
555
+ for (const [parent, targets] of graph.entries()) {
556
+ if (parent.startsWith("Event_Tick_") && targets.has(label)) {
557
+ return true;
558
+ }
559
+ }
560
+ return false;
561
+ };
270
562
  var calculateAllSimilarities = (entryA, entryB) => {
271
- const sync = calculateSimilarityCircular(entryA.meta.buffer, entryA.meta.head, entryB.meta.buffer, entryB.meta.head, 0);
272
- const bA = calculateSimilarityCircular(entryA.meta.buffer, entryA.meta.head, entryB.meta.buffer, entryB.meta.head, 1);
273
- const aB = calculateSimilarityCircular(entryA.meta.buffer, entryA.meta.head, entryB.meta.buffer, entryB.meta.head, -1);
563
+ const sync = calculateSimilarityCircular(
564
+ entryA.meta.buffer,
565
+ entryA.meta.head,
566
+ entryB.meta.buffer,
567
+ entryB.meta.head,
568
+ 0
569
+ );
570
+ const bA = calculateSimilarityCircular(
571
+ entryA.meta.buffer,
572
+ entryA.meta.head,
573
+ entryB.meta.buffer,
574
+ entryB.meta.head,
575
+ 1
576
+ );
577
+ const aB = calculateSimilarityCircular(
578
+ entryA.meta.buffer,
579
+ entryA.meta.head,
580
+ entryB.meta.buffer,
581
+ entryB.meta.head,
582
+ -1
583
+ );
274
584
  return { sync, bA, aB, max: Math.max(sync, bA, aB) };
275
585
  };
276
586
  var shouldSkipComparison = (entryA, entryB, dirtyLabels2) => {
@@ -278,49 +588,79 @@ var shouldSkipComparison = (entryA, entryB, dirtyLabels2) => {
278
588
  if (dirtyLabels2.has(entryB.label) && entryA.label > entryB.label) return true;
279
589
  return false;
280
590
  };
281
- var detectRedundancy = (entryA, entryB, similarities, redundantSet) => {
591
+ var pushViolation = (map, source, detail) => {
592
+ if (!map.has(source)) {
593
+ map.set(source, []);
594
+ }
595
+ const list = map.get(source);
596
+ const exists = list.some(
597
+ (v) => v.type === detail.type && v.target === detail.target
598
+ );
599
+ if (!exists) {
600
+ list.push(detail);
601
+ }
602
+ };
603
+ var isGlobalSource = (role) => role === "context" /* CONTEXT */ || role === "store" /* STORE */;
604
+ var detectRedundancy = (entryA, entryB, similarities, redundantSet, violationMap) => {
282
605
  const roleA = entryA.meta.role;
283
606
  const roleB = entryB.meta.role;
284
- if (roleA === "context" /* CONTEXT */ && roleB === "context" /* CONTEXT */) return;
607
+ if (isGlobalSource(roleA) && isGlobalSource(roleB)) return;
285
608
  if (entryA.meta.density < 2 || entryB.meta.density < 2) return;
286
- if (roleA === "local" /* LOCAL */ && roleB === "context" /* CONTEXT */) {
609
+ if (roleA === "local" /* LOCAL */ && isGlobalSource(roleB)) {
287
610
  redundantSet.add(entryA.label);
611
+ pushViolation(violationMap, entryB.label, { type: "context_mirror", target: entryA.label, similarity: similarities.max });
288
612
  displayRedundancyAlert(entryA.label, entryA.meta, entryB.label, entryB.meta, similarities.max);
289
- } else if (roleA === "context" /* CONTEXT */ && roleB === "local" /* LOCAL */) {
613
+ } else if (isGlobalSource(roleA) && roleB === "local" /* LOCAL */) {
290
614
  redundantSet.add(entryB.label);
615
+ pushViolation(violationMap, entryA.label, { type: "context_mirror", target: entryB.label, similarity: similarities.max });
291
616
  displayRedundancyAlert(entryB.label, entryB.meta, entryA.label, entryA.meta, similarities.max);
292
617
  } else if (roleA === "local" /* LOCAL */ && roleB === "local" /* LOCAL */) {
293
618
  redundantSet.add(entryA.label);
294
619
  redundantSet.add(entryB.label);
620
+ pushViolation(violationMap, entryA.label, { type: "duplicate_state", target: entryB.label, similarity: similarities.max });
621
+ pushViolation(violationMap, entryB.label, { type: "duplicate_state", target: entryA.label, similarity: similarities.max });
295
622
  displayRedundancyAlert(entryA.label, entryA.meta, entryB.label, entryB.meta, similarities.max);
296
623
  }
297
624
  };
298
- var detectCausalLeak = (entryA, entryB, similarities) => {
625
+ var detectCausalLeak = (entryA, entryB, similarities, violationMap, graph) => {
299
626
  if (entryA.isVolatile || entryB.isVolatile) return;
627
+ if (similarities.max - similarities.sync < CAUSAL_MARGIN) return;
628
+ const addLeak = (source, target) => {
629
+ if (isEventDriven(target, graph)) return;
630
+ if (!violationMap.has(source)) {
631
+ violationMap.set(source, []);
632
+ }
633
+ violationMap.get(source).push({ type: "causal_leak", target });
634
+ const sourceEntry = source === entryA.label ? entryA : entryB;
635
+ const targetEntry = source === entryA.label ? entryB : entryA;
636
+ displayCausalHint(target, targetEntry.meta, source, sourceEntry.meta);
637
+ };
300
638
  if (similarities.bA === similarities.max) {
301
- displayCausalHint(entryB.label, entryB.meta, entryA.label, entryA.meta);
639
+ addLeak(entryA.label, entryB.label);
302
640
  } else if (similarities.aB === similarities.max) {
303
- displayCausalHint(entryA.label, entryA.meta, entryB.label, entryB.meta);
641
+ addLeak(entryB.label, entryA.label);
304
642
  }
305
643
  };
306
- var detectSubspaceOverlap = (dirtyEntries, allEntries, redundantSet, dirtyLabels2) => {
644
+ var detectSubspaceOverlap = (dirtyEntries, allEntries, redundantSet, dirtyLabels2, graph) => {
307
645
  let compCount = 0;
646
+ const violationMap = /* @__PURE__ */ new Map();
308
647
  for (const entryA of dirtyEntries) {
309
648
  for (const entryB of allEntries) {
310
649
  if (shouldSkipComparison(entryA, entryB, dirtyLabels2)) continue;
311
650
  compCount++;
312
651
  const similarities = calculateAllSimilarities(entryA, entryB);
313
652
  if (similarities.max > SIMILARITY_THRESHOLD) {
314
- detectRedundancy(entryA, entryB, similarities, redundantSet);
315
- detectCausalLeak(entryA, entryB, similarities);
653
+ detectRedundancy(entryA, entryB, similarities, redundantSet, violationMap);
654
+ detectCausalLeak(entryA, entryB, similarities, violationMap, graph);
316
655
  }
317
656
  }
318
657
  }
319
- return compCount;
658
+ return { compCount, violationMap };
320
659
  };
321
660
 
322
661
  // src/engine.ts
323
662
  var BASIS_INSTANCE_KEY = /* @__PURE__ */ Symbol.for("__basis_engine_instance__");
663
+ var EVENT_TTL = 1e4;
324
664
  var NULL_SIGNAL = {
325
665
  role: "proj" /* PROJECTION */,
326
666
  buffer: new Uint8Array(0),
@@ -328,6 +668,28 @@ var NULL_SIGNAL = {
328
668
  density: 0,
329
669
  options: {}
330
670
  };
671
+ var activeEventId = null;
672
+ var pruneGraph = () => {
673
+ const now = Date.now();
674
+ for (const source of instance.graph.keys()) {
675
+ if (source.startsWith("Event_Tick_")) {
676
+ const parts = source.split("_");
677
+ const timestamp = parseInt(parts[2], 10);
678
+ if (now - timestamp > EVENT_TTL) {
679
+ instance.graph.delete(source);
680
+ }
681
+ }
682
+ }
683
+ };
684
+ var getEventId = () => {
685
+ if (!activeEventId) {
686
+ activeEventId = `Event_Tick_${Date.now()}_${Math.random().toString(36).substr(2, 5)}`;
687
+ requestAnimationFrame(() => {
688
+ activeEventId = null;
689
+ });
690
+ }
691
+ return activeEventId;
692
+ };
331
693
  var getGlobalInstance = () => {
332
694
  const root = globalThis;
333
695
  if (!root[BASIS_INSTANCE_KEY]) {
@@ -340,7 +702,10 @@ var getGlobalInstance = () => {
340
702
  tick: 0,
341
703
  isBatching: false,
342
704
  currentEffectSource: null,
705
+ lastStateUpdate: null,
343
706
  pausedVariables: /* @__PURE__ */ new Set(),
707
+ graph: /* @__PURE__ */ new Map(),
708
+ violationMap: /* @__PURE__ */ new Map(),
344
709
  metrics: {
345
710
  lastAnalysisTimeMs: 0,
346
711
  comparisonCount: 0,
@@ -370,6 +735,14 @@ var calculateTickEntropy = (tickIdx) => {
370
735
  });
371
736
  return 1 - activeCount / total;
372
737
  };
738
+ var recordEdge = (source, target) => {
739
+ if (!source || !target || source === target) return;
740
+ if (!instance.graph.has(source)) {
741
+ instance.graph.set(source, /* @__PURE__ */ new Map());
742
+ }
743
+ const targets = instance.graph.get(source);
744
+ targets.set(target, (targets.get(target) || 0) + 1);
745
+ };
373
746
  var analyzeBasis = () => {
374
747
  if (!instance.config.debug || dirtyLabels.size === 0) {
375
748
  return;
@@ -400,16 +773,33 @@ var analyzeBasis = () => {
400
773
  nextRedundant.add(l);
401
774
  }
402
775
  });
403
- const compCount = detectSubspaceOverlap(
776
+ const { compCount, violationMap } = detectSubspaceOverlap(
404
777
  dirtyEntries,
405
778
  allEntries,
406
779
  nextRedundant,
407
- snapshot
780
+ snapshot,
781
+ instance.graph
408
782
  );
409
783
  instance.redundantLabels.clear();
410
784
  nextRedundant.forEach((l) => {
411
785
  instance.redundantLabels.add(l);
412
786
  });
787
+ violationMap.forEach((newList, label) => {
788
+ const existing = instance.violationMap.get(label) || [];
789
+ newList.forEach((detail) => {
790
+ const alreadyExists = existing.some(
791
+ (v) => v.type === detail.type && v.target === detail.target
792
+ );
793
+ if (!alreadyExists) {
794
+ existing.push(detail);
795
+ }
796
+ });
797
+ instance.violationMap.set(label, existing);
798
+ });
799
+ if (instance.violationMap.size > 500) {
800
+ const keys = Array.from(instance.violationMap.keys()).slice(0, 200);
801
+ keys.forEach((k) => instance.violationMap.delete(k));
802
+ }
413
803
  instance.metrics.lastAnalysisTimeMs = performance.now() - analysisStart;
414
804
  instance.metrics.comparisonCount = compCount;
415
805
  instance.metrics.lastAnalysisTimestamp = Date.now();
@@ -431,6 +821,7 @@ var processHeartbeat = () => {
431
821
  instance.currentTickBatch.clear();
432
822
  currentTickRegistry = {};
433
823
  instance.isBatching = false;
824
+ instance.lastStateUpdate = null;
434
825
  if (dirtyLabels.size > 0) {
435
826
  analyzeBasis();
436
827
  }
@@ -442,6 +833,7 @@ var recordUpdate = (label) => {
442
833
  if (now - instance.lastCleanup > 1e3) {
443
834
  instance.loopCounters.clear();
444
835
  instance.lastCleanup = now;
836
+ pruneGraph();
445
837
  }
446
838
  const count = (instance.loopCounters.get(label) || 0) + 1;
447
839
  instance.loopCounters.set(label, count);
@@ -450,17 +842,25 @@ var recordUpdate = (label) => {
450
842
  instance.pausedVariables.add(label);
451
843
  return false;
452
844
  }
453
- if (instance.currentEffectSource && instance.currentEffectSource !== label) {
454
- const targetMeta = instance.history.get(label);
455
- const sourceMeta = instance.history.get(instance.currentEffectSource);
456
- if (targetMeta) {
457
- const sourceDensity = sourceMeta?.density || 0;
458
- const isVolatile = targetMeta.density > VOLATILITY_THRESHOLD || sourceDensity > VOLATILITY_THRESHOLD;
459
- if (!isVolatile) {
460
- displayCausalHint(label, targetMeta, instance.currentEffectSource, sourceMeta || NULL_SIGNAL);
845
+ const meta = instance.history.get(label);
846
+ let edgeSource = null;
847
+ if (instance.currentEffectSource) {
848
+ edgeSource = instance.currentEffectSource;
849
+ } else {
850
+ edgeSource = getEventId();
851
+ }
852
+ if (edgeSource && edgeSource !== label) {
853
+ recordEdge(edgeSource, label);
854
+ if (instance.currentEffectSource && instance.currentEffectSource !== label) {
855
+ const sourceMeta = instance.history.get(instance.currentEffectSource) || NULL_SIGNAL;
856
+ if (meta && sourceMeta && meta.density < VOLATILITY_THRESHOLD && sourceMeta.density < VOLATILITY_THRESHOLD) {
857
+ displayCausalHint(label, meta, instance.currentEffectSource, sourceMeta);
461
858
  }
462
859
  }
463
860
  }
861
+ if (meta && meta.role === "local" /* LOCAL */ && !instance.currentEffectSource) {
862
+ instance.lastStateUpdate = label;
863
+ }
464
864
  if (currentTickRegistry[label]) return true;
465
865
  currentTickRegistry[label] = true;
466
866
  instance.currentTickBatch.add(label);
@@ -479,7 +879,7 @@ var configureBasis = (c) => {
479
879
  }
480
880
  };
481
881
  var registerVariable = (l, o = {}) => {
482
- if (!instance.config.debug || o.suppressAll) return;
882
+ if (o.suppressAll) return;
483
883
  if (!instance.history.has(l)) {
484
884
  instance.history.set(l, {
485
885
  buffer: new Uint8Array(WINDOW_SIZE),
@@ -504,10 +904,10 @@ var endEffectTracking = () => {
504
904
  };
505
905
  var printBasisHealthReport = (threshold = 0.5) => {
506
906
  if (!instance.config.debug) return;
507
- displayHealthReport(instance.history, threshold);
907
+ displayHealthReport(instance.history, threshold, instance.violationMap);
508
908
  };
509
909
  var getBasisMetrics = () => ({
510
- engine: "v0.5.x",
910
+ engine: "v0.6.x",
511
911
  hooks: instance.history.size,
512
912
  analysis_ms: instance.metrics.lastAnalysisTimeMs.toFixed(3),
513
913
  entropy: instance.metrics.systemEntropy.toFixed(3)
@@ -721,7 +1121,14 @@ var BasisHUD = () => {
721
1121
  if (!canvas) return;
722
1122
  const ctx = canvas.getContext("2d");
723
1123
  if (!ctx) return;
724
- const entries = Array.from(history.entries());
1124
+ const entries = Array.from(history.entries()).sort((a, b) => {
1125
+ const roleOrder = (role) => {
1126
+ if (role === "context") return 0;
1127
+ if (role === "store") return 1;
1128
+ return 2;
1129
+ };
1130
+ return roleOrder(a[1].role) - roleOrder(b[1].role);
1131
+ });
725
1132
  const dpr = window.devicePixelRatio || 1;
726
1133
  const rawWidth = HUD_DIMENSIONS.WINDOW_SIZE * HUD_DIMENSIONS.COL_WIDTH + HUD_DIMENSIONS.LABEL_WIDTH + HUD_DIMENSIONS.PADDING * 2;
727
1134
  const rawHeight = Math.max(entries.length * HUD_DIMENSIONS.ROW_HEIGHT + HUD_DIMENSIONS.PADDING * 2, 80);
@@ -777,7 +1184,7 @@ function renderMatrix(ctx, entries) {
777
1184
  let rowIndex = 0;
778
1185
  for (const [label, meta] of entries) {
779
1186
  const y = rowIndex * rowH + pad;
780
- const isContext = meta.role === "context";
1187
+ const isContext = meta.role === "context" || meta.role === "store";
781
1188
  const isRedundant = !isContext && redundantLabels.has(label);
782
1189
  const { buffer, head } = meta;
783
1190
  let uiPos = 0;
@@ -796,7 +1203,8 @@ function renderMatrix(ctx, entries) {
796
1203
  const stateName = label.split(" -> ")[1] || label;
797
1204
  const textX = L * colW + pad + 10;
798
1205
  ctx.fillStyle = isContext ? HUD_THEME.header : isRedundant ? HUD_THEME.error : HUD_THEME.text;
799
- ctx.fillText((isContext ? "\u03A9 " : isRedundant ? "! " : "") + stateName, textX, y + 9);
1206
+ const prefix = meta.role === "store" ? "\u03A3 " : isContext ? "\u03A9 " : isRedundant ? "! " : "";
1207
+ ctx.fillText(prefix + stateName, textX, y + 9);
800
1208
  rowIndex++;
801
1209
  }
802
1210
  ctx.fillStyle = HUD_THEME.grid;
@@ -825,7 +1233,7 @@ var HUDHeader = ({ isExpanded }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)
825
1233
  },
826
1234
  children: [
827
1235
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: isExpanded ? "STATE BASIS MATRIX" : "\u{1F4D0} BASIS ACTIVE" }),
828
- isExpanded && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { opacity: 0.8, fontSize: "9px" }, children: "v0.5.x" })
1236
+ isExpanded && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { opacity: 0.8, fontSize: "9px" }, children: "v0.6.x" })
829
1237
  ]
830
1238
  }
831
1239
  );