aspectcode 0.4.1 → 1.0.0

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 (242) hide show
  1. package/README.md +2 -2
  2. package/dist/agentsMdRenderer.d.ts +16 -0
  3. package/dist/agentsMdRenderer.d.ts.map +1 -0
  4. package/dist/agentsMdRenderer.js +137 -0
  5. package/dist/agentsMdRenderer.js.map +1 -0
  6. package/dist/auth.d.ts +31 -0
  7. package/dist/auth.d.ts.map +1 -0
  8. package/dist/auth.js +385 -0
  9. package/dist/auth.js.map +1 -0
  10. package/dist/autoResolve.d.ts +41 -0
  11. package/dist/autoResolve.d.ts.map +1 -0
  12. package/dist/autoResolve.js +196 -0
  13. package/dist/autoResolve.js.map +1 -0
  14. package/dist/changeEvaluator.d.ts +56 -0
  15. package/dist/changeEvaluator.d.ts.map +1 -0
  16. package/dist/changeEvaluator.js +674 -0
  17. package/dist/changeEvaluator.js.map +1 -0
  18. package/dist/cli.d.ts +3 -1
  19. package/dist/cli.d.ts.map +1 -1
  20. package/dist/cli.js +1 -1
  21. package/dist/cli.js.map +1 -1
  22. package/dist/config.d.ts +37 -17
  23. package/dist/config.d.ts.map +1 -1
  24. package/dist/config.js +50 -2
  25. package/dist/config.js.map +1 -1
  26. package/dist/dreamCycle.d.ts +57 -0
  27. package/dist/dreamCycle.d.ts.map +1 -0
  28. package/dist/dreamCycle.js +334 -0
  29. package/dist/dreamCycle.js.map +1 -0
  30. package/dist/kbBuilder.d.ts +1 -2
  31. package/dist/kbBuilder.d.ts.map +1 -1
  32. package/dist/kbBuilder.js +1 -2
  33. package/dist/kbBuilder.js.map +1 -1
  34. package/dist/main.d.ts +2 -1
  35. package/dist/main.d.ts.map +1 -1
  36. package/dist/main.js +148 -7
  37. package/dist/main.js.map +1 -1
  38. package/dist/optimize.d.ts +13 -6
  39. package/dist/optimize.d.ts.map +1 -1
  40. package/dist/optimize.js +433 -142
  41. package/dist/optimize.js.map +1 -1
  42. package/dist/pipeline.d.ts +19 -21
  43. package/dist/pipeline.d.ts.map +1 -1
  44. package/dist/pipeline.js +1093 -160
  45. package/dist/pipeline.js.map +1 -1
  46. package/dist/preferences.d.ts +80 -0
  47. package/dist/preferences.d.ts.map +1 -0
  48. package/dist/preferences.js +238 -0
  49. package/dist/preferences.js.map +1 -0
  50. package/dist/runtimeState.d.ts +30 -0
  51. package/dist/runtimeState.d.ts.map +1 -0
  52. package/dist/runtimeState.js +39 -0
  53. package/dist/runtimeState.js.map +1 -0
  54. package/dist/scopedRules.d.ts +84 -0
  55. package/dist/scopedRules.d.ts.map +1 -0
  56. package/dist/scopedRules.js +449 -0
  57. package/dist/scopedRules.js.map +1 -0
  58. package/dist/ui/Dashboard.d.ts +4 -16
  59. package/dist/ui/Dashboard.d.ts.map +1 -1
  60. package/dist/ui/Dashboard.js +339 -140
  61. package/dist/ui/Dashboard.js.map +1 -1
  62. package/dist/ui/MemoryMap.d.ts +16 -0
  63. package/dist/ui/MemoryMap.d.ts.map +1 -0
  64. package/dist/ui/MemoryMap.js +266 -0
  65. package/dist/ui/MemoryMap.js.map +1 -0
  66. package/dist/ui/SettingsPanel.d.ts +18 -0
  67. package/dist/ui/SettingsPanel.d.ts.map +1 -0
  68. package/dist/ui/SettingsPanel.js +241 -0
  69. package/dist/ui/SettingsPanel.js.map +1 -0
  70. package/dist/ui/prompts.d.ts +7 -0
  71. package/dist/ui/prompts.d.ts.map +1 -1
  72. package/dist/ui/prompts.js +63 -0
  73. package/dist/ui/prompts.js.map +1 -1
  74. package/dist/ui/store.d.ts +154 -18
  75. package/dist/ui/store.d.ts.map +1 -1
  76. package/dist/ui/store.js +154 -24
  77. package/dist/ui/store.js.map +1 -1
  78. package/dist/ui/theme.d.ts +1 -8
  79. package/dist/ui/theme.d.ts.map +1 -1
  80. package/dist/ui/theme.js +2 -21
  81. package/dist/ui/theme.js.map +1 -1
  82. package/dist/updateChecker.d.ts +13 -0
  83. package/dist/updateChecker.d.ts.map +1 -0
  84. package/dist/updateChecker.js +66 -0
  85. package/dist/updateChecker.js.map +1 -0
  86. package/dist/usageTracker.d.ts +12 -0
  87. package/dist/usageTracker.d.ts.map +1 -0
  88. package/dist/usageTracker.js +89 -0
  89. package/dist/usageTracker.js.map +1 -0
  90. package/dist/writer.d.ts +1 -7
  91. package/dist/writer.d.ts.map +1 -1
  92. package/dist/writer.js +1 -11
  93. package/dist/writer.js.map +1 -1
  94. package/node_modules/@aspectcode/core/dist/analysis/repo.d.ts.map +1 -1
  95. package/node_modules/@aspectcode/core/dist/analysis/repo.js +13 -2
  96. package/node_modules/@aspectcode/core/dist/analysis/repo.js.map +1 -1
  97. package/node_modules/@aspectcode/core/dist/index.d.ts +1 -3
  98. package/node_modules/@aspectcode/core/dist/index.d.ts.map +1 -1
  99. package/node_modules/@aspectcode/core/dist/index.js +1 -3
  100. package/node_modules/@aspectcode/core/dist/index.js.map +1 -1
  101. package/node_modules/@aspectcode/core/dist/parsers/genericExtractors.d.ts +14 -0
  102. package/node_modules/@aspectcode/core/dist/parsers/genericExtractors.d.ts.map +1 -0
  103. package/node_modules/@aspectcode/core/dist/parsers/genericExtractors.js +191 -0
  104. package/node_modules/@aspectcode/core/dist/parsers/genericExtractors.js.map +1 -0
  105. package/node_modules/@aspectcode/core/dist/parsers/index.d.ts +1 -0
  106. package/node_modules/@aspectcode/core/dist/parsers/index.d.ts.map +1 -1
  107. package/node_modules/@aspectcode/core/dist/parsers/index.js +6 -1
  108. package/node_modules/@aspectcode/core/dist/parsers/index.js.map +1 -1
  109. package/node_modules/@aspectcode/core/dist/parsers/languages.d.ts +20 -0
  110. package/node_modules/@aspectcode/core/dist/parsers/languages.d.ts.map +1 -1
  111. package/node_modules/@aspectcode/core/dist/parsers/languages.js +25 -0
  112. package/node_modules/@aspectcode/core/dist/parsers/languages.js.map +1 -1
  113. package/node_modules/@aspectcode/core/dist/parsers/tsJsExtractors.d.ts.map +1 -1
  114. package/node_modules/@aspectcode/core/dist/parsers/tsJsExtractors.js +4 -1
  115. package/node_modules/@aspectcode/core/dist/parsers/tsJsExtractors.js.map +1 -1
  116. package/node_modules/@aspectcode/core/package.json +2 -2
  117. package/node_modules/@aspectcode/core/parsers/cpp.wasm +0 -0
  118. package/node_modules/@aspectcode/core/parsers/go.wasm +0 -0
  119. package/node_modules/@aspectcode/core/parsers/php.wasm +0 -0
  120. package/node_modules/@aspectcode/core/parsers/ruby.wasm +0 -0
  121. package/node_modules/@aspectcode/core/parsers/rust.wasm +0 -0
  122. package/node_modules/@aspectcode/emitters/dist/index.d.ts +1 -17
  123. package/node_modules/@aspectcode/emitters/dist/index.d.ts.map +1 -1
  124. package/node_modules/@aspectcode/emitters/dist/index.js +2 -90
  125. package/node_modules/@aspectcode/emitters/dist/index.js.map +1 -1
  126. package/node_modules/@aspectcode/emitters/dist/instructions/index.d.ts +0 -2
  127. package/node_modules/@aspectcode/emitters/dist/instructions/index.d.ts.map +1 -1
  128. package/node_modules/@aspectcode/emitters/dist/instructions/index.js +1 -7
  129. package/node_modules/@aspectcode/emitters/dist/instructions/index.js.map +1 -1
  130. package/node_modules/@aspectcode/emitters/dist/kb/analyzers.d.ts +0 -18
  131. package/node_modules/@aspectcode/emitters/dist/kb/analyzers.d.ts.map +1 -1
  132. package/node_modules/@aspectcode/emitters/dist/kb/analyzers.js +0 -57
  133. package/node_modules/@aspectcode/emitters/dist/kb/analyzers.js.map +1 -1
  134. package/node_modules/@aspectcode/emitters/dist/kb/conventions.d.ts +0 -18
  135. package/node_modules/@aspectcode/emitters/dist/kb/conventions.d.ts.map +1 -1
  136. package/node_modules/@aspectcode/emitters/dist/kb/conventions.js +0 -130
  137. package/node_modules/@aspectcode/emitters/dist/kb/conventions.js.map +1 -1
  138. package/node_modules/@aspectcode/emitters/dist/kb/index.d.ts +2 -4
  139. package/node_modules/@aspectcode/emitters/dist/kb/index.d.ts.map +1 -1
  140. package/node_modules/@aspectcode/emitters/dist/kb/index.js +1 -11
  141. package/node_modules/@aspectcode/emitters/dist/kb/index.js.map +1 -1
  142. package/node_modules/@aspectcode/emitters/package.json +3 -3
  143. package/node_modules/@aspectcode/evaluator/dist/apply.d.ts +55 -0
  144. package/node_modules/@aspectcode/evaluator/dist/apply.d.ts.map +1 -0
  145. package/node_modules/@aspectcode/evaluator/dist/apply.js +368 -0
  146. package/node_modules/@aspectcode/evaluator/dist/apply.js.map +1 -0
  147. package/node_modules/@aspectcode/evaluator/dist/diagnosis.d.ts +16 -25
  148. package/node_modules/@aspectcode/evaluator/dist/diagnosis.d.ts.map +1 -1
  149. package/node_modules/@aspectcode/evaluator/dist/diagnosis.js +115 -138
  150. package/node_modules/@aspectcode/evaluator/dist/diagnosis.js.map +1 -1
  151. package/node_modules/@aspectcode/evaluator/dist/index.d.ts +8 -43
  152. package/node_modules/@aspectcode/evaluator/dist/index.d.ts.map +1 -1
  153. package/node_modules/@aspectcode/evaluator/dist/index.js +15 -61
  154. package/node_modules/@aspectcode/evaluator/dist/index.js.map +1 -1
  155. package/node_modules/@aspectcode/evaluator/dist/judge.d.ts +32 -0
  156. package/node_modules/@aspectcode/evaluator/dist/judge.d.ts.map +1 -0
  157. package/node_modules/@aspectcode/evaluator/dist/judge.js +165 -0
  158. package/node_modules/@aspectcode/evaluator/dist/judge.js.map +1 -0
  159. package/node_modules/@aspectcode/evaluator/dist/llmUtil.d.ts +15 -0
  160. package/node_modules/@aspectcode/evaluator/dist/llmUtil.d.ts.map +1 -0
  161. package/node_modules/@aspectcode/evaluator/dist/llmUtil.js +41 -0
  162. package/node_modules/@aspectcode/evaluator/dist/llmUtil.js.map +1 -0
  163. package/node_modules/@aspectcode/evaluator/dist/probes.d.ts +20 -47
  164. package/node_modules/@aspectcode/evaluator/dist/probes.d.ts.map +1 -1
  165. package/node_modules/@aspectcode/evaluator/dist/probes.js +188 -278
  166. package/node_modules/@aspectcode/evaluator/dist/probes.js.map +1 -1
  167. package/node_modules/@aspectcode/evaluator/dist/runner.d.ts +7 -32
  168. package/node_modules/@aspectcode/evaluator/dist/runner.d.ts.map +1 -1
  169. package/node_modules/@aspectcode/evaluator/dist/runner.js +21 -146
  170. package/node_modules/@aspectcode/evaluator/dist/runner.js.map +1 -1
  171. package/node_modules/@aspectcode/evaluator/dist/types.d.ts +141 -99
  172. package/node_modules/@aspectcode/evaluator/dist/types.d.ts.map +1 -1
  173. package/node_modules/@aspectcode/evaluator/dist/types.js +10 -2
  174. package/node_modules/@aspectcode/evaluator/dist/types.js.map +1 -1
  175. package/node_modules/@aspectcode/evaluator/package.json +4 -4
  176. package/node_modules/@aspectcode/optimizer/dist/index.d.ts +3 -10
  177. package/node_modules/@aspectcode/optimizer/dist/index.d.ts.map +1 -1
  178. package/node_modules/@aspectcode/optimizer/dist/index.js +1 -19
  179. package/node_modules/@aspectcode/optimizer/dist/index.js.map +1 -1
  180. package/node_modules/@aspectcode/optimizer/dist/providers/anthropic.d.ts.map +1 -1
  181. package/node_modules/@aspectcode/optimizer/dist/providers/anthropic.js +40 -0
  182. package/node_modules/@aspectcode/optimizer/dist/providers/anthropic.js.map +1 -1
  183. package/node_modules/@aspectcode/optimizer/dist/providers/aspectcode.d.ts +9 -0
  184. package/node_modules/@aspectcode/optimizer/dist/providers/aspectcode.d.ts.map +1 -0
  185. package/node_modules/@aspectcode/optimizer/dist/providers/aspectcode.js +83 -0
  186. package/node_modules/@aspectcode/optimizer/dist/providers/aspectcode.js.map +1 -0
  187. package/node_modules/@aspectcode/optimizer/dist/providers/index.d.ts +4 -3
  188. package/node_modules/@aspectcode/optimizer/dist/providers/index.d.ts.map +1 -1
  189. package/node_modules/@aspectcode/optimizer/dist/providers/index.js +24 -10
  190. package/node_modules/@aspectcode/optimizer/dist/providers/index.js.map +1 -1
  191. package/node_modules/@aspectcode/optimizer/dist/providers/openai.d.ts.map +1 -1
  192. package/node_modules/@aspectcode/optimizer/dist/providers/openai.js +22 -0
  193. package/node_modules/@aspectcode/optimizer/dist/providers/openai.js.map +1 -1
  194. package/node_modules/@aspectcode/optimizer/dist/providers/retry.d.ts +14 -0
  195. package/node_modules/@aspectcode/optimizer/dist/providers/retry.d.ts.map +1 -1
  196. package/node_modules/@aspectcode/optimizer/dist/providers/retry.js +1 -0
  197. package/node_modules/@aspectcode/optimizer/dist/providers/retry.js.map +1 -1
  198. package/node_modules/@aspectcode/optimizer/dist/types.d.ts +14 -0
  199. package/node_modules/@aspectcode/optimizer/dist/types.d.ts.map +1 -1
  200. package/node_modules/@aspectcode/optimizer/dist/types.js.map +1 -1
  201. package/node_modules/@aspectcode/optimizer/package.json +2 -2
  202. package/package.json +6 -7
  203. package/dist/complaintProcessor.d.ts +0 -16
  204. package/dist/complaintProcessor.d.ts.map +0 -1
  205. package/dist/complaintProcessor.js +0 -134
  206. package/dist/complaintProcessor.js.map +0 -1
  207. package/node_modules/@aspectcode/emitters/dist/emitter.d.ts +0 -72
  208. package/node_modules/@aspectcode/emitters/dist/emitter.d.ts.map +0 -1
  209. package/node_modules/@aspectcode/emitters/dist/emitter.js +0 -10
  210. package/node_modules/@aspectcode/emitters/dist/emitter.js.map +0 -1
  211. package/node_modules/@aspectcode/emitters/dist/instructions/content.d.ts +0 -26
  212. package/node_modules/@aspectcode/emitters/dist/instructions/content.d.ts.map +0 -1
  213. package/node_modules/@aspectcode/emitters/dist/instructions/content.js +0 -501
  214. package/node_modules/@aspectcode/emitters/dist/instructions/content.js.map +0 -1
  215. package/node_modules/@aspectcode/emitters/dist/instructions/detection.d.ts +0 -13
  216. package/node_modules/@aspectcode/emitters/dist/instructions/detection.d.ts.map +0 -1
  217. package/node_modules/@aspectcode/emitters/dist/instructions/detection.js +0 -55
  218. package/node_modules/@aspectcode/emitters/dist/instructions/detection.js.map +0 -1
  219. package/node_modules/@aspectcode/emitters/dist/instructions/instructionsEmitter.d.ts +0 -9
  220. package/node_modules/@aspectcode/emitters/dist/instructions/instructionsEmitter.d.ts.map +0 -1
  221. package/node_modules/@aspectcode/emitters/dist/instructions/instructionsEmitter.js +0 -30
  222. package/node_modules/@aspectcode/emitters/dist/instructions/instructionsEmitter.js.map +0 -1
  223. package/node_modules/@aspectcode/emitters/dist/kb/kbEmitter.d.ts +0 -21
  224. package/node_modules/@aspectcode/emitters/dist/kb/kbEmitter.d.ts.map +0 -1
  225. package/node_modules/@aspectcode/emitters/dist/kb/kbEmitter.js +0 -125
  226. package/node_modules/@aspectcode/emitters/dist/kb/kbEmitter.js.map +0 -1
  227. package/node_modules/@aspectcode/emitters/dist/manifest.d.ts +0 -37
  228. package/node_modules/@aspectcode/emitters/dist/manifest.d.ts.map +0 -1
  229. package/node_modules/@aspectcode/emitters/dist/manifest.js +0 -50
  230. package/node_modules/@aspectcode/emitters/dist/manifest.js.map +0 -1
  231. package/node_modules/@aspectcode/emitters/dist/report.d.ts +0 -22
  232. package/node_modules/@aspectcode/emitters/dist/report.d.ts.map +0 -1
  233. package/node_modules/@aspectcode/emitters/dist/report.js +0 -3
  234. package/node_modules/@aspectcode/emitters/dist/report.js.map +0 -1
  235. package/node_modules/@aspectcode/emitters/dist/stableJson.d.ts +0 -14
  236. package/node_modules/@aspectcode/emitters/dist/stableJson.d.ts.map +0 -1
  237. package/node_modules/@aspectcode/emitters/dist/stableJson.js +0 -40
  238. package/node_modules/@aspectcode/emitters/dist/stableJson.js.map +0 -1
  239. package/node_modules/@aspectcode/emitters/dist/transaction.d.ts +0 -29
  240. package/node_modules/@aspectcode/emitters/dist/transaction.d.ts.map +0 -1
  241. package/node_modules/@aspectcode/emitters/dist/transaction.js +0 -104
  242. package/node_modules/@aspectcode/emitters/dist/transaction.js.map +0 -1
@@ -1,22 +1,10 @@
1
1
  "use strict";
2
2
  /**
3
- * Dashboard — condensed ink-based CLI dashboard.
3
+ * Dashboard — ink-based CLI dashboard with memory map and real-time assessments.
4
4
  *
5
- * Layout (full mode):
6
- * Banner (hidden in compact mode)
7
- * First-run message (only on first run, early phases)
8
- * Input bar (watching/done only)
9
- * Setup notes (compact single line)
10
- * Status line (spinner/icon + phase + stats)
11
- * Eval progress (harvest → probes → diagnosis)
12
- * Token usage (after LLM generation)
13
- * Summary card (after writing — sections, rules, paths)
14
- * Diff summary (watch-mode: +N lines, -M lines)
15
- * [Detail] (change trigger, warning, reasoning)
16
- * Applied changes (after refinement)
17
- *
18
- * Layout (compact mode):
19
- * Same but no banner, no reasoning, setup only if warning.
5
+ * Layout:
6
+ * Header → Memory Map → (Working status | Eval progress)
7
+ * Assessment area Status bar
20
8
  */
21
9
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
22
10
  if (k2 === undefined) k2 = k;
@@ -51,13 +39,22 @@ var __importStar = (this && this.__importStar) || (function () {
51
39
  return result;
52
40
  };
53
41
  })();
42
+ var __importDefault = (this && this.__importDefault) || function (mod) {
43
+ return (mod && mod.__esModule) ? mod : { "default": mod };
44
+ };
54
45
  Object.defineProperty(exports, "__esModule", { value: true });
55
46
  const react_1 = __importStar(require("react"));
56
47
  const ink_1 = require("ink");
57
48
  const theme_1 = require("./theme");
58
49
  const store_1 = require("./store");
50
+ const MemoryMap_1 = __importDefault(require("./MemoryMap"));
51
+ const SettingsPanel_1 = __importDefault(require("./SettingsPanel"));
52
+ const config_1 = require("../config");
53
+ const usageTracker_1 = require("../usageTracker");
54
+ const version_1 = require("../version");
59
55
  // ── Spinner ──────────────────────────────────────────────────
60
56
  const FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
57
+ const DREAM_FRAMES = ['✦', '◆', '✦', '◇'];
61
58
  function useSpinner(active) {
62
59
  const [frame, setFrame] = (0, react_1.useState)(0);
63
60
  (0, react_1.useEffect)(() => {
@@ -68,24 +65,74 @@ function useSpinner(active) {
68
65
  }, [active]);
69
66
  return FRAMES[frame];
70
67
  }
71
- // ── Live elapsed timer ───────────────────────────────────────
72
- function useElapsedTimer(startMs, finalElapsed, isWorking) {
68
+ function useDreamSpinner(active) {
69
+ const [frame, setFrame] = (0, react_1.useState)(0);
70
+ (0, react_1.useEffect)(() => {
71
+ if (!active)
72
+ return;
73
+ const id = setInterval(() => setFrame((f) => (f + 1) % DREAM_FRAMES.length), 400);
74
+ return () => clearInterval(id);
75
+ }, [active]);
76
+ return DREAM_FRAMES[frame];
77
+ }
78
+ // ── Auto-clear hooks ─────────────────────────────────────────
79
+ function useAutoMessage(msg, clearFn, durationMs = 4000) {
80
+ const [visible, setVisible] = (0, react_1.useState)(msg);
81
+ (0, react_1.useEffect)(() => {
82
+ if (!msg) {
83
+ setVisible('');
84
+ return;
85
+ }
86
+ setVisible(msg);
87
+ const id = setTimeout(() => { setVisible(''); clearFn(); }, durationMs);
88
+ return () => clearTimeout(id);
89
+ }, [msg]);
90
+ return visible;
91
+ }
92
+ // ── Eval phase elapsed timer ─────────────────────────────────
93
+ function useEvalElapsed(phase) {
94
+ const [startMs, setStartMs] = (0, react_1.useState)(0);
73
95
  const [now, setNow] = (0, react_1.useState)(Date.now());
74
96
  (0, react_1.useEffect)(() => {
75
- if (!isWorking || startMs === 0)
97
+ if (phase === 'idle' || phase === 'done') {
98
+ setStartMs(0);
76
99
  return;
77
- const id = setInterval(() => setNow(Date.now()), 100);
100
+ }
101
+ setStartMs(Date.now());
102
+ }, [phase]);
103
+ (0, react_1.useEffect)(() => {
104
+ if (!startMs)
105
+ return;
106
+ const id = setInterval(() => setNow(Date.now()), 1000);
78
107
  return () => clearInterval(id);
79
- }, [isWorking, startMs]);
80
- // Use the final value once set
81
- if (finalElapsed)
82
- return finalElapsed;
83
- if (startMs === 0)
108
+ }, [startMs]);
109
+ if (!startMs || phase === 'idle' || phase === 'done')
84
110
  return '';
85
- if (!isWorking)
111
+ const secs = Math.floor((now - startMs) / 1000);
112
+ if (secs < 1)
86
113
  return '';
87
- const ms = now - startMs;
88
- return `${(ms / 1000).toFixed(1)}s`;
114
+ return `${secs}s`;
115
+ }
116
+ // ── Slow pulse for watching indicator ─────────────────────────
117
+ const PULSE_FRAMES = ['●', '●', '○', '○'];
118
+ function usePulse(active) {
119
+ const [frame, setFrame] = (0, react_1.useState)(0);
120
+ (0, react_1.useEffect)(() => {
121
+ if (!active)
122
+ return;
123
+ const id = setInterval(() => setFrame((f) => (f + 1) % PULSE_FRAMES.length), 1500);
124
+ return () => clearInterval(id);
125
+ }, [active]);
126
+ return PULSE_FRAMES[frame];
127
+ }
128
+ // ── Tick for relative timestamps ─────────────────────────────
129
+ function useTick(intervalMs) {
130
+ const [tick, setTick] = (0, react_1.useState)(0);
131
+ (0, react_1.useEffect)(() => {
132
+ const id = setInterval(() => setTick((t) => t + 1), intervalMs);
133
+ return () => clearInterval(id);
134
+ }, [intervalMs]);
135
+ return tick;
89
136
  }
90
137
  // ── Phase labels ─────────────────────────────────────────────
91
138
  const PHASE_TEXT = {
@@ -103,150 +150,302 @@ const PHASE_TEXT = {
103
150
  const WORKING = new Set([
104
151
  'idle', 'discovering', 'analyzing', 'building-kb', 'optimizing', 'evaluating', 'writing',
105
152
  ]);
106
- // ── Helpers ──────────────────────────────────────────────────
107
- function statsText(s, liveElapsed) {
108
- const parts = [];
109
- if (s.fileCount > 0)
110
- parts.push(`${s.fileCount} files`);
111
- if (s.edgeCount > 0)
112
- parts.push(`${s.edgeCount} edges`);
113
- if (s.provider)
114
- parts.push(s.provider);
115
- const elapsed = liveElapsed || s.elapsed;
116
- if (elapsed)
117
- parts.push(elapsed);
118
- return parts.length > 0 ? parts.join(' · ') : '';
119
- }
120
- function setupLine(notes) {
121
- if (notes.length === 0)
122
- return '';
123
- return notes.join(' · ');
124
- }
153
+ // ── Eval progress text ───────────────────────────────────────
125
154
  function evalText(phase, s) {
155
+ const round = s.iteration && s.maxIterations && s.maxIterations > 1
156
+ ? `Round ${s.iteration}/${s.maxIterations}: `
157
+ : '';
126
158
  switch (phase) {
127
159
  case 'idle': return null;
128
- case 'harvesting':
129
- return s.harvestCount !== undefined
130
- ? `Harvested ${s.harvestCount} prompt${s.harvestCount === 1 ? '' : 's'}`
131
- : 'Harvesting prompts…';
132
- case 'probing':
133
- return s.probesPassed !== undefined && s.probesTotal !== undefined
134
- ? `Probes: ${s.probesPassed}/${s.probesTotal} passed`
135
- : 'Running probes…';
136
- case 'diagnosing':
137
- return 'Diagnosing failures…';
138
- case 'done':
139
- if (s.probesPassed !== undefined && s.probesTotal !== undefined) {
140
- const parts = [`${s.probesPassed}/${s.probesTotal} probes passed`];
141
- if (s.diagnosisEdits && s.diagnosisEdits > 0) {
142
- parts.push(`${s.diagnosisEdits} fix${s.diagnosisEdits === 1 ? '' : 'es'} applied`);
143
- }
144
- return parts.join(' · ');
160
+ case 'generating-probes':
161
+ return `${round}Generating synthetic test scenarios…`;
162
+ case 'probing': {
163
+ const progress = s.probesPassed !== undefined && s.probesTotal !== undefined
164
+ ? ` (${s.probesPassed}/${s.probesTotal})`
165
+ : '';
166
+ return `${round}Simulating AI responses${progress}…`;
167
+ }
168
+ case 'judging': {
169
+ const progress = s.judgedCount !== undefined && s.probesTotal !== undefined
170
+ ? ` (${s.judgedCount}/${s.probesTotal})`
171
+ : '';
172
+ return `${round}Judging response quality${progress}…`;
173
+ }
174
+ case 'diagnosing': {
175
+ const detail = s.weakCount !== undefined && s.strongCount !== undefined
176
+ ? ` — ${s.weakCount} gap${s.weakCount === 1 ? '' : 's'} found`
177
+ : '';
178
+ return `${round}Identifying improvements${detail}…`;
179
+ }
180
+ case 'applying': {
181
+ const count = s.proposedEditCount ? ` ${s.proposedEditCount}` : '';
182
+ return `${round}Applying${count} improvement${s.proposedEditCount === 1 ? '' : 's'} to AGENTS.md…`;
183
+ }
184
+ case 'done': {
185
+ const edits = s.diagnosisEdits ?? 0;
186
+ const rounds = s.iterationSummaries?.length ?? 0;
187
+ const roundNote = rounds > 1 ? ` across ${rounds} rounds` : '';
188
+ if (s.cancelled) {
189
+ return edits > 0
190
+ ? `Cancelled — ${edits} improvement${edits === 1 ? '' : 's'} applied${roundNote}`
191
+ : 'Cancelled — no changes applied';
145
192
  }
146
- return 'Evaluation complete';
193
+ return edits > 0
194
+ ? `Complete — ${edits} improvement${edits === 1 ? '' : 's'} applied${roundNote}`
195
+ : 'Complete — no changes needed';
196
+ }
147
197
  }
148
198
  }
149
- /** Format a token count with k suffix for readability. */
150
- function fmtTokens(n) {
151
- return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n);
152
- }
199
+ // ── Separator line ───────────────────────────────────────────
200
+ const SEP_CHAR = '┄';
153
201
  // ── Component ────────────────────────────────────────────────
154
- /** Phases where the complaint input and hints are shown. */
155
- const INPUT_VISIBLE = new Set(['watching', 'done']);
156
- /** Phases where the first-run message should be visible. */
157
- const FIRST_RUN_VISIBLE = new Set(['idle', 'discovering', 'analyzing']);
158
202
  const Dashboard = () => {
159
203
  const [s, setS] = (0, react_1.useState)({ ...store_1.store.state });
204
+ const [showSettings, setShowSettings] = (0, react_1.useState)(false);
205
+ const [settingsUserData, setSettingsUserData] = (0, react_1.useState)({});
206
+ const [settingsProjectData, setSettingsProjectData] = (0, react_1.useState)({});
160
207
  (0, react_1.useEffect)(() => {
161
208
  const fn = () => setS({ ...store_1.store.state });
162
209
  store_1.store.on('change', fn);
163
210
  return () => { store_1.store.removeListener('change', fn); };
164
211
  }, []);
165
- // ── Complaint text input via useInput ────────────────────
166
- (0, ink_1.useInput)((input, key) => {
167
- if (key.return) {
168
- const text = store_1.store.state.complaintInput.trim();
169
- if (text.length > 0) {
170
- store_1.store.queueComplaint(text);
212
+ // Force re-render every 10s so relative timestamps update
213
+ useTick(10000);
214
+ // ── Keyboard handling ──────────────────────────────────────
215
+ (0, ink_1.useInput)((input, _key) => {
216
+ // Settings panel handles its own input when open
217
+ if (showSettings)
218
+ return;
219
+ if (input === 'x') {
220
+ const evalPhase = store_1.store.state.evalStatus.phase;
221
+ if (evalPhase !== 'idle' && evalPhase !== 'done') {
222
+ store_1.store.cancelEval();
171
223
  }
172
224
  return;
173
225
  }
174
- if (key.backspace || key.delete) {
175
- const cur = store_1.store.state.complaintInput;
176
- if (cur.length > 0) {
177
- store_1.store.setComplaintInput(cur.slice(0, -1));
226
+ if (input === 'c') {
227
+ store_1.store.dismissEvalStatus();
228
+ return;
229
+ }
230
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
231
+ const handler = store_1.store._onAssessmentAction;
232
+ if (!handler)
233
+ return;
234
+ const current = store_1.store.state.currentAssessment;
235
+ // Tier exhaustion actions
236
+ if (store_1.store.state.tierExhausted) {
237
+ if (input === 'u') {
238
+ handler({ type: 'open-pricing' });
239
+ return;
178
240
  }
241
+ if (input === 'k') {
242
+ store_1.store.setLearnedMessage('Add "apiKey": "sk-..." to aspectcode.json or ASPECTCODE_LLM_KEY to .env, then restart aspectcode');
243
+ return;
244
+ }
245
+ }
246
+ if (input === 'r') {
247
+ handler({ type: 'probe-and-refine' });
179
248
  return;
180
249
  }
181
- if (key.escape) {
182
- store_1.store.setComplaintInput('');
250
+ if (input === 'l' && !store_1.store.state.userEmail) {
251
+ handler({ type: 'login' });
183
252
  return;
184
253
  }
185
- // Ignore control / arrow / meta keys
186
- if (key.ctrl || key.meta || key.upArrow || key.downArrow || key.leftArrow || key.rightArrow || key.tab) {
254
+ if (!current) {
255
+ // No active assessment 's' opens settings
256
+ if (input === 's' && store_1.store.state.phase === 'watching') {
257
+ const root = store_1.store.state.rootPath;
258
+ setSettingsProjectData((0, config_1.loadConfig)(root) ?? {});
259
+ // User settings are loaded from store (set by pipeline on startup)
260
+ setSettingsUserData(store_1.store._userSettings ?? {});
261
+ setShowSettings(true);
262
+ }
187
263
  return;
188
264
  }
189
- if (input) {
190
- store_1.store.setComplaintInput(store_1.store.state.complaintInput + input);
265
+ if (current.llmRecommendation) {
266
+ // Space pauses/unpauses the timer
267
+ if (input === ' ') {
268
+ setTimerPaused((p) => !p);
269
+ return;
270
+ }
271
+ // Enter accepts the LLM recommendation immediately
272
+ if (_key.return) {
273
+ handler({
274
+ type: current.llmRecommendation.decision === 'allow' ? 'dismiss' : 'confirm',
275
+ assessment: current,
276
+ });
277
+ return;
278
+ }
279
+ // y = confirm (enforce rule), n = dismiss (allow / suppress)
280
+ if (input === 'n') {
281
+ handler({ type: 'dismiss', assessment: current });
282
+ }
283
+ else if (input === 'y') {
284
+ handler({ type: 'confirm', assessment: current });
285
+ }
286
+ }
287
+ else {
288
+ // No LLM recommendation — classic y/n/s
289
+ if (input === 'n') {
290
+ handler({ type: 'dismiss', assessment: current });
291
+ }
292
+ else if (input === 'y') {
293
+ if (current.suggestion) {
294
+ process.stderr.write(`\n Suggestion:\n ${current.suggestion}\n\n`);
295
+ }
296
+ handler({ type: 'confirm', assessment: current });
297
+ }
298
+ else if (input === 's') {
299
+ handler({ type: 'skip', assessment: current });
300
+ }
191
301
  }
192
302
  });
193
- const compact = s.compact;
194
303
  const working = WORKING.has(s.phase);
195
- const spinner = useSpinner(working || s.processingComplaint);
196
- const liveElapsed = useElapsedTimer(s.runStartMs, s.elapsed, working);
197
- const stats = statsText(s, liveElapsed);
304
+ const isWatching = s.phase === 'watching';
305
+ const spinner = useSpinner(working || s.dreaming);
306
+ const dreamSpinner = useDreamSpinner(s.dreaming);
307
+ const pulse = usePulse(isWatching);
198
308
  const detail = s.phaseDetail ? ` (${s.phaseDetail})` : '';
199
- const setup = setupLine(s.setupNotes);
200
309
  const evalLabel = evalText(s.evalStatus.phase, s.evalStatus);
201
310
  const evalDone = s.evalStatus.phase === 'done';
202
311
  const evalActive = s.evalStatus.phase !== 'idle';
203
- const allPassed = s.evalStatus.probesPassed === s.evalStatus.probesTotal;
204
- const hasProbes = (s.evalStatus.probesTotal ?? 0) > 0;
205
- const isDone = s.phase === 'done' || s.phase === 'watching';
206
- // Collapse reasoning to a single short line; hide the trivial "generation complete" message
207
- const TRIVIAL_RE = /single.pass generation|generation complete/i;
208
- const meaningful = s.reasoning.filter((r) => !TRIVIAL_RE.test(r));
209
- const raw = meaningful.join(' · ');
210
- const reasoningLine = raw.length > 80 ? raw.slice(0, 77) + '…' : raw;
312
+ const evalElapsed = useEvalElapsed(s.evalStatus.phase);
313
+ const learnedMsg = useAutoMessage(s.learnedMessage, () => store_1.store.setLearnedMessage(''));
314
+ // Timer for auto-resolving assessments with LLM recommendation
315
+ const [autoTimer, setAutoTimer] = (0, react_1.useState)(30);
316
+ const [timerPaused, setTimerPaused] = (0, react_1.useState)(false);
317
+ (0, react_1.useEffect)(() => {
318
+ const cur = s.currentAssessment;
319
+ if (!cur?.llmRecommendation) {
320
+ setAutoTimer(20);
321
+ setTimerPaused(false);
322
+ return;
323
+ }
324
+ setAutoTimer(20);
325
+ setTimerPaused(false);
326
+ const interval = setInterval(() => {
327
+ setAutoTimer((t) => {
328
+ if (timerPaused)
329
+ return t;
330
+ if (t <= 1) {
331
+ // Auto-apply LLM decision
332
+ const handler = store_1.store._onAssessmentAction;
333
+ if (handler && cur.llmRecommendation) {
334
+ handler({
335
+ type: cur.llmRecommendation.decision === 'allow' ? 'dismiss' : 'confirm',
336
+ assessment: cur,
337
+ });
338
+ }
339
+ return 0;
340
+ }
341
+ return t - 1;
342
+ });
343
+ }, 1000);
344
+ return () => clearInterval(interval);
345
+ }, [s.currentAssessment, timerPaused]);
346
+ const warningMsg = useAutoMessage(s.warning, () => store_1.store.setWarning(''), 5000);
347
+ const changeFlash = useAutoMessage(s.lastChangeFlash, () => store_1.store.setLastChangeFlash(''));
348
+ const current = s.currentAssessment;
349
+ const queueLen = s.pendingAssessments.length;
350
+ // ── Build header info ──────────────────────────────────────
351
+ const rootLabel = s.rootPath ? s.rootPath.replace(/\\/g, '/').split('/').pop() || s.rootPath : '';
352
+ // ── Settings panel ────────────────────────────────────────
353
+ if (showSettings) {
354
+ return (react_1.default.createElement(SettingsPanel_1.default, { userSettings: settingsUserData, projectConfig: settingsProjectData, onSave: (user, project) => {
355
+ const root = s.rootPath;
356
+ // Save user settings to cloud
357
+ (0, config_1.saveUserSettings)(user);
358
+ // Save project settings to local file
359
+ if (root)
360
+ (0, config_1.saveConfig)(root, project);
361
+ // Store user settings for future reference
362
+ store_1.store._userSettings = user;
363
+ setShowSettings(false);
364
+ store_1.store.setLearnedMessage('Settings saved');
365
+ }, onCancel: () => setShowSettings(false) }));
366
+ }
211
367
  return (react_1.default.createElement(ink_1.Box, { flexDirection: "column" },
212
- !compact && (react_1.default.createElement(ink_1.Box, { marginBottom: 0 },
213
- react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primary, bold: true }, (0, theme_1.getBannerText)()))),
214
- s.isFirstRun && FIRST_RUN_VISIBLE.has(s.phase) && (react_1.default.createElement(ink_1.Box, { marginBottom: 0 },
215
- react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ' Analyzing your codebase to generate AGENTS.md the coding\n guidelines AI assistants follow in this project.'))),
216
- INPUT_VISIBLE.has(s.phase) && !s.processingComplaint && (react_1.default.createElement(ink_1.Box, { marginTop: 0 },
217
- react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primary }, ' > '),
218
- react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.white }, s.complaintInput),
219
- react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primaryDim }, '|'))),
220
- s.complaintQueue.length > 0 && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primaryDim }, ` ${s.complaintQueue.length} pending`)),
221
- setup !== '' && !(compact && !s.warning) && (react_1.default.createElement(ink_1.Box, { marginTop: 1 },
222
- react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` ${setup}`))),
223
- react_1.default.createElement(ink_1.Box, null,
224
- s.processingComplaint && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primary }, ` ${spinner} Refining…`)),
225
- !s.processingComplaint && working && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primary }, ` ${spinner} ${PHASE_TEXT[s.phase]}${detail}`)),
226
- !s.processingComplaint && s.phase === 'watching' && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.green }, ' * Watching')),
227
- !s.processingComplaint && s.phase === 'done' && s.outputs.length > 0 && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.green }, ` ✔ ${s.outputs.join(', ')}`)),
228
- !s.processingComplaint && s.phase === 'done' && s.outputs.length === 0 && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.green }, ' ✔ Done')),
229
- !s.processingComplaint && s.phase === 'error' && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.red }, ' ✖ Error')),
230
- stats !== '' && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` ${stats}`))),
231
- evalActive && evalLabel && !(evalDone && !hasProbes) && (react_1.default.createElement(ink_1.Text, { color: evalDone && allPassed ? theme_1.COLORS.green : evalDone ? theme_1.COLORS.yellow : theme_1.COLORS.primaryDim }, ` ${evalLabel}`)),
232
- s.tokenUsage && isDone && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` ${fmtTokens(s.tokenUsage.inputTokens)} in · ${fmtTokens(s.tokenUsage.outputTokens)} out`)),
233
- s.summary && isDone && (react_1.default.createElement(ink_1.Box, { flexDirection: "column" },
234
- react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` ├ ${s.summary.sections} sections · ${s.summary.rules} rules` +
235
- (s.summary.filePaths.length > 0 ? ` · ${s.summary.filePaths.length} file-specific guidelines` : '')),
236
- s.summary.filePaths.length > 0 && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` covers: ${s.summary.filePaths.slice(0, 3).join(', ')}` +
237
- (s.summary.filePaths.length > 3 ? `, +${s.summary.filePaths.length - 3} more` : ''))))),
238
- s.diffSummary && s.diffSummary.changed && isDone && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` AGENTS.md: ` +
239
- (s.diffSummary.added > 0 ? `+${s.diffSummary.added} lines` : '') +
240
- (s.diffSummary.added > 0 && s.diffSummary.removed > 0 ? ', ' : '') +
241
- (s.diffSummary.removed > 0 ? `-${s.diffSummary.removed} lines` : ''))),
242
- s.diffSummary && !s.diffSummary.changed && isDone && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ' ↳ AGENTS.md: no changes')),
243
- s.lastChange !== '' && working && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` ↳ ${s.lastChange}`)),
244
- s.warning !== '' && (react_1.default.createElement(ink_1.Box, { marginTop: 0 },
245
- react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.yellow }, ` ! ${s.warning}`))),
246
- s.complaintChanges.length > 0 && (react_1.default.createElement(ink_1.Box, { flexDirection: "column", marginTop: 1 },
247
- react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primary }, ' Changes applied:'),
248
- s.complaintChanges.map((c, i) => (react_1.default.createElement(ink_1.Text, { key: i, color: theme_1.COLORS.primaryDim }, ` → ${c}`))))),
249
- !compact && reasoningLine !== '' && isDone && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` ℹ ${reasoningLine}`))));
368
+ react_1.default.createElement(ink_1.Text, null,
369
+ react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primary, bold: true }, `◆ aspect code v${(0, version_1.getVersion)()}`),
370
+ rootLabel ? react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` ${SEP_CHAR} ${rootLabel}`) : null,
371
+ s.activePlatform ? react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` ${SEP_CHAR} ${s.activePlatform}`) : null,
372
+ s.updateMessage ? react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` ${SEP_CHAR} ${s.updateMessage}`) : null),
373
+ working && s.phase !== 'evaluating' && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primary },
374
+ `${spinner} ${PHASE_TEXT[s.phase]}${detail}`,
375
+ s.phase === 'analyzing' && s.fileCount > 0 && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` — ${s.fileCount.toLocaleString()} files, ${s.edgeCount.toLocaleString()} edges`)),
376
+ s.phase === 'optimizing' && s.provider && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, `${s.provider}`)))),
377
+ s.isFirstRun && working && s.phase !== 'evaluating' && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, 'Analyzing your codebase to generate AGENTS.md')),
378
+ s.isFirstRun && s.phase === 'evaluating' && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, 'Optimizing AGENTS.md — testing with synthetic scenarios to find gaps')),
379
+ s.managedFiles.length > 0 && (react_1.default.createElement(ink_1.Box, { marginTop: 0 },
380
+ react_1.default.createElement(MemoryMap_1.default, { files: s.managedFiles, dreaming: s.dreaming, userEmail: s.userEmail }))),
381
+ evalActive && evalLabel && !s.evalStatus.dismissed && (react_1.default.createElement(ink_1.Box, { flexDirection: "column" },
382
+ react_1.default.createElement(ink_1.Text, { color: evalDone ? theme_1.COLORS.primary : theme_1.COLORS.primaryDim },
383
+ evalDone ? evalLabel : `${spinner} ${evalLabel}`,
384
+ !evalDone && evalElapsed ? react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` ${evalElapsed}`) : null,
385
+ !evalDone && !s.evalStatus.cancelled ? ' [x] cancel' : '',
386
+ evalDone ? ' [c] clear' : ''),
387
+ s.evalStatus.phase === 'judging' && s.evalStatus.probeResults && (react_1.default.createElement(react_1.default.Fragment, null, s.evalStatus.probeResults.map((pr, i) => {
388
+ if (pr.status === 'pending')
389
+ return null;
390
+ if (pr.status === 'strong')
391
+ return null; // Only show gaps, not passes
392
+ return react_1.default.createElement(ink_1.Text, { key: `pr-${i}`, color: theme_1.COLORS.gray }, ` gap: ${pr.task}`);
393
+ }))),
394
+ s.evalStatus.phase === 'applying' && s.evalStatus.editSummaries && s.evalStatus.editSummaries.length > 0 && (react_1.default.createElement(react_1.default.Fragment, null, s.evalStatus.editSummaries.map((line, i) => (react_1.default.createElement(ink_1.Text, { key: `ae-${i}`, color: theme_1.COLORS.gray }, ` + ${line}`))))),
395
+ s.evalStatus.iterationSummaries && s.evalStatus.iterationSummaries.map((summary, i) => (react_1.default.createElement(ink_1.Text, { key: `iter-${i}`, color: theme_1.COLORS.gray }, `├ ${summary}`))),
396
+ evalDone && s.evalStatus.editSummaries && s.evalStatus.editSummaries.length > 0 && (react_1.default.createElement(react_1.default.Fragment, null,
397
+ s.evalStatus.editSummaries.slice(0, 5).map((line, i, arr) => {
398
+ const isLast = i === arr.length - 1 && (s.evalStatus.editSummaries?.length ?? 0) <= 5;
399
+ return react_1.default.createElement(ink_1.Text, { key: `edit-${i}`, color: theme_1.COLORS.gray }, `${isLast ? '└' : '├'} ${line}`);
400
+ }),
401
+ s.evalStatus.editSummaries.length > 5 && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, `└ +${s.evalStatus.editSummaries.length - 5} more`)))))),
402
+ warningMsg !== '' && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.yellow }, `● ${warningMsg}`)),
403
+ isWatching && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray },
404
+ `${pulse} watching`,
405
+ s.userEmail && s.syncStatus === 'synced' && s.lastSyncAt > 0 ? (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` — ☁ synced`)) : null,
406
+ s.userEmail && s.syncStatus === 'offline' ? (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.yellow }, ` — ☁ offline`)) : null)),
407
+ s.dreaming && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primary }, `${dreamSpinner} refining context…`)),
408
+ isWatching && !s.suggestionsDismissed && s.suggestions.length > 0 && !current && !s.dreaming && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` ✦ ${s.suggestions.length} community insight${s.suggestions.length === 1 ? '' : 's'} — will refine on next dream cycle`)),
409
+ !s.dreaming && current && (current.type === 'warning' || current.type === 'violation') && (react_1.default.createElement(ink_1.Box, { flexDirection: "column" },
410
+ react_1.default.createElement(ink_1.Box, null,
411
+ react_1.default.createElement(ink_1.Text, { color: current.type === 'violation' ? theme_1.COLORS.red : theme_1.COLORS.yellow }, current.type === 'violation' ? '✗ ' : '⚠ '),
412
+ react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.white, bold: true }, current.file)),
413
+ react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` ${current.rule} · ${current.message}`),
414
+ current.details ? (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` ${current.details}`)) : null,
415
+ current.llmRecommendation ? (react_1.default.createElement(react_1.default.Fragment, null,
416
+ react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray, dimColor: true }, ` ${Math.round(current.llmRecommendation.confidence * 100)}% — ${current.llmRecommendation.reasoning}`),
417
+ react_1.default.createElement(ink_1.Box, null,
418
+ current.llmRecommendation.decision === 'deny' ? (react_1.default.createElement(ink_1.Text, null,
419
+ react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primary, bold: true }, ' [enter] enforce rule'),
420
+ react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ' [n] allow [space] pause timer'))) : (react_1.default.createElement(ink_1.Text, null,
421
+ react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primary, bold: true }, ' [enter] allow'),
422
+ react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ' [y] enforce rule [space] pause timer'))),
423
+ autoTimer > 0 && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, timerPaused ? ' (paused)' : ` (${autoTimer}s)`))))) : (react_1.default.createElement(ink_1.Box, null,
424
+ react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ' [y] confirm [n] dismiss [s] skip'))),
425
+ react_1.default.createElement(ink_1.Box, null, queueLen > 0 && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, ` (1 of ${queueLen + 1})`))))),
426
+ !s.dreaming && !current && changeFlash !== '' && isWatching && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray }, `✓ ${changeFlash}`)),
427
+ learnedMsg !== '' && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primary }, `● ${learnedMsg}`)),
428
+ isWatching && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray, dimColor: true }, (() => {
429
+ const stats = s.assessmentStats;
430
+ const parts = [];
431
+ parts.push(`${stats.changes} source file change${stats.changes === 1 ? '' : 's'}`);
432
+ if (stats.warnings > 0)
433
+ parts.push(`${stats.warnings} warnings`);
434
+ if (stats.violations > 0)
435
+ parts.push(`${stats.violations} violations`);
436
+ if (stats.autoResolved > 0)
437
+ parts.push(`${stats.autoResolved} auto-resolved`);
438
+ return parts.join(' · ');
439
+ })())),
440
+ isWatching && (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray, dimColor: true }, '[r] optimize [s] settings')),
441
+ s.tierExhausted && (react_1.default.createElement(ink_1.Box, { flexDirection: "column", marginTop: 1 },
442
+ react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.red, bold: true }, `${s.userTier === 'free' ? 'Free' : 'Weekly'} limit reached (${(0, usageTracker_1.formatTokens)(s.tierTokensUsed)} / ${(0, usageTracker_1.formatTokens)(s.tierTokensCap)} tokens).`),
443
+ react_1.default.createElement(ink_1.Text, null, ''),
444
+ react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.primaryDim }, ' [u] Upgrade to Pro — $8/mo, 1M tokens/week'),
445
+ react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray, dimColor: true }, ' [k] Add your own key (restart required after adding)'))),
446
+ s.userTier === 'byok' ? (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray, dimColor: true }, s.sessionUsage.calls > 0
447
+ ? `${(0, usageTracker_1.formatTokens)(s.sessionUsage.inputTokens)} in · ${(0, usageTracker_1.formatTokens)(s.sessionUsage.outputTokens)} out · ${s.sessionUsage.calls} call${s.sessionUsage.calls === 1 ? '' : 's'} (BYOK)`
448
+ : 'BYOK — 0 calls')) : s.userTier === 'pro' ? (react_1.default.createElement(ink_1.Text, { color: s.tierTokensCap > 0 && s.tierTokensUsed / s.tierTokensCap >= 0.95 ? theme_1.COLORS.red : s.tierTokensCap > 0 && s.tierTokensUsed / s.tierTokensCap >= 0.8 ? theme_1.COLORS.yellow : theme_1.COLORS.gray, dimColor: s.tierTokensCap === 0 || s.tierTokensUsed / s.tierTokensCap < 0.8 }, `${(0, usageTracker_1.formatTokens)(s.tierTokensUsed)} / ${(0, usageTracker_1.formatTokens)(s.tierTokensCap)} weekly tokens${s.sessionUsage.calls > 0 ? ` · ${s.sessionUsage.calls} call${s.sessionUsage.calls === 1 ? '' : 's'}` : ''}${s.tierResetAt ? ` (resets ${new Date(s.tierResetAt).toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' })})` : ''}`)) : s.tierTokensUsed >= 75000 ? (react_1.default.createElement(ink_1.Text, { color: s.tierTokensCap > 0 && s.tierTokensUsed / s.tierTokensCap >= 0.95 ? theme_1.COLORS.red : s.tierTokensCap > 0 && s.tierTokensUsed / s.tierTokensCap >= 0.8 ? theme_1.COLORS.yellow : theme_1.COLORS.gray, dimColor: s.tierTokensCap === 0 || s.tierTokensUsed / s.tierTokensCap < 0.8 }, `${(0, usageTracker_1.formatTokens)(s.tierTokensUsed)} / ${(0, usageTracker_1.formatTokens)(s.tierTokensCap)} free tokens${s.sessionUsage.calls > 0 ? ` · ${s.sessionUsage.calls} call${s.sessionUsage.calls === 1 ? '' : 's'}` : ''}`)) : (s.sessionUsage.calls > 0 ? (react_1.default.createElement(ink_1.Text, { color: theme_1.COLORS.gray, dimColor: true }, `${s.sessionUsage.calls} call${s.sessionUsage.calls === 1 ? '' : 's'}`)) : null)));
250
449
  };
251
450
  exports.default = Dashboard;
252
451
  //# sourceMappingURL=Dashboard.js.map