@xera-ai/core 0.9.7 → 0.10.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 (34) hide show
  1. package/dist/bin/internal.js +1415 -534
  2. package/dist/bin/templates/LICENSE-vis-network.txt +2 -0
  3. package/dist/bin/templates/coverage-panel.html.fragment +20 -0
  4. package/dist/bin/templates/graph.css +379 -43
  5. package/dist/bin/templates/graph.html.template +35 -15
  6. package/dist/bin/templates/graph.js +458 -56
  7. package/dist/bin/templates/vis-network.min.js +3 -24976
  8. package/dist/src/index.js +6 -0
  9. package/package.json +3 -3
  10. package/src/bin-internal/ac-coverage-backfill-finalize.ts +90 -0
  11. package/src/bin-internal/ac-coverage-backfill-prepare.ts +72 -0
  12. package/src/bin-internal/coverage-prepare.ts +123 -0
  13. package/src/bin-internal/fill-gap-finalize.ts +115 -0
  14. package/src/bin-internal/fill-gap-prepare.ts +150 -0
  15. package/src/bin-internal/graph-render.ts +32 -4
  16. package/src/bin-internal/index.ts +10 -0
  17. package/src/bin-internal/verify-prompts.ts +2 -0
  18. package/src/config/schema.ts +9 -0
  19. package/src/coverage/index.ts +29 -0
  20. package/src/coverage/report.ts +206 -0
  21. package/src/coverage/risk.ts +69 -0
  22. package/src/coverage/status.ts +76 -0
  23. package/src/coverage/types.ts +11 -0
  24. package/src/coverage/why.ts +122 -0
  25. package/src/graph/render.ts +16 -2
  26. package/src/graph/schema.ts +54 -1
  27. package/src/graph/store.ts +96 -6
  28. package/src/graph/templates/LICENSE-vis-network.txt +2 -0
  29. package/src/graph/templates/coverage-panel.html.fragment +20 -0
  30. package/src/graph/templates/graph.css +379 -43
  31. package/src/graph/templates/graph.html.template +35 -15
  32. package/src/graph/templates/graph.js +458 -56
  33. package/src/graph/templates/vis-network.min.js +3 -24976
  34. package/src/graph/types.ts +56 -1
@@ -1,3 +1,5 @@
1
+ vis-network v9.1.6 — https://visjs.github.io/vis-network/
2
+
1
3
  Apache License
2
4
  Version 2.0, January 2004
3
5
  http://www.apache.org/licenses/
@@ -0,0 +1,20 @@
1
+ <section data-tab-panel="coverage" hidden>
2
+ <nav class="subtabs">
3
+ <button data-subtab="map" class="active">Map</button>
4
+ <button data-subtab="list">List</button>
5
+ <button data-subtab="trend">Trend</button>
6
+ </nav>
7
+ <div data-subpanel="map" class="active">
8
+ <p class="subpanel-hint">Area nodes are colored by status. Red = UNCOVERED, amber = STALE, green = COVERED. Other nodes neutral.</p>
9
+ <main id="coverage-map-canvas"></main>
10
+ </div>
11
+ <div data-subpanel="list" hidden>
12
+ <table id="coverage-list-table"><thead><tr><th>Status</th><th>Area</th><th>Risk</th><th>Recent tickets</th><th>Recent bugs</th></tr></thead><tbody></tbody></table>
13
+ <h3>AC Gaps</h3>
14
+ <table id="coverage-ac-table"><thead><tr><th>Ticket</th><th>Coverage</th><th>Gap</th><th>Unsatisfied</th></tr></thead><tbody></tbody></table>
15
+ </div>
16
+ <div data-subpanel="trend" hidden>
17
+ <p class="subpanel-hint">UNCOVERED + STALE area count over time (one point per day, latest snapshot wins).</p>
18
+ <div id="coverage-trend-svg"></div>
19
+ </div>
20
+ </section>
@@ -1,88 +1,424 @@
1
1
  * {
2
2
  box-sizing: border-box;
3
3
  }
4
+
4
5
  body {
5
6
  margin: 0;
6
7
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
7
8
  height: 100vh;
9
+ background: #050810;
8
10
  display: grid;
9
- grid-template-rows: 56px 1fr 32px;
10
- grid-template-columns: 1fr 320px;
11
+ grid-template-rows: 52px 1fr 26px;
12
+ grid-template-columns: 1fr 280px;
11
13
  }
14
+
15
+ /* ─── Topbar ─────────────────────────────────────── */
12
16
  #topbar {
13
17
  grid-column: 1 / -1;
14
18
  display: flex;
15
19
  align-items: center;
16
- gap: 16px;
20
+ gap: 0;
17
21
  padding: 0 16px;
18
- background: #1f2937;
19
- color: #f9fafb;
20
- border-bottom: 1px solid #374151;
22
+ background: #080c14;
23
+ border-bottom: 1px solid #1a2035;
21
24
  }
22
- #topbar .title {
23
- font-weight: 600;
24
- font-size: 16px;
25
+
26
+ .topbar-brand {
27
+ display: flex;
28
+ align-items: center;
29
+ gap: 8px;
30
+ padding-right: 20px;
31
+ border-right: 1px solid #1a2035;
32
+ margin-right: 16px;
25
33
  }
26
- #topbar .stats {
27
- color: #9ca3af;
34
+
35
+ .topbar-brand .logo {
36
+ width: 18px;
37
+ height: 18px;
38
+ border-radius: 4px;
39
+ background: linear-gradient(135deg, #3b82f6 0%, #6366f1 100%);
40
+ display: flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ flex-shrink: 0;
44
+ }
45
+
46
+ .topbar-brand .logo::after {
47
+ content: "";
48
+ display: block;
49
+ width: 6px;
50
+ height: 6px;
51
+ border-radius: 50%;
52
+ background: white;
53
+ opacity: 0.9;
54
+ }
55
+
56
+ .topbar-brand .title {
57
+ font-weight: 600;
28
58
  font-size: 13px;
59
+ color: #e2e8f0;
60
+ letter-spacing: -0.01em;
61
+ }
62
+
63
+ #stats-bar {
64
+ display: flex;
65
+ gap: 6px;
66
+ align-items: center;
29
67
  flex: 1;
30
68
  }
31
- #topbar .filters {
69
+
70
+ .stat-chip {
71
+ display: inline-flex;
72
+ align-items: center;
73
+ gap: 5px;
74
+ font-size: 11px;
75
+ font-weight: 500;
76
+ color: #64748b;
77
+ background: #0f1624;
78
+ border: 1px solid #1e2d45;
79
+ border-radius: 20px;
80
+ padding: 2px 9px;
81
+ line-height: 1.6;
82
+ transition:
83
+ color 0.15s,
84
+ border-color 0.15s;
85
+ }
86
+
87
+ .stat-chip .dot {
88
+ width: 6px;
89
+ height: 6px;
90
+ border-radius: 50%;
91
+ flex-shrink: 0;
92
+ }
93
+
94
+ .topbar-controls {
32
95
  display: flex;
33
96
  gap: 8px;
34
97
  align-items: center;
35
- font-size: 13px;
98
+ padding-left: 16px;
99
+ border-left: 1px solid #1a2035;
36
100
  }
37
- #topbar input[type="text"] {
38
- background: #111827;
39
- color: #f9fafb;
40
- border: 1px solid #374151;
41
- border-radius: 4px;
42
- padding: 4px 8px;
101
+
102
+ #search {
103
+ background: #0f1624;
104
+ color: #c9d1d9;
105
+ border: 1px solid #1e2d45;
106
+ border-radius: 6px;
107
+ padding: 4px 10px 4px 28px;
43
108
  width: 160px;
109
+ font-size: 12px;
110
+ outline: none;
111
+ transition:
112
+ border-color 0.15s,
113
+ box-shadow 0.15s;
114
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%234b5563' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E");
115
+ background-repeat: no-repeat;
116
+ background-position: 10px center;
44
117
  }
45
- #topbar button {
46
- background: #374151;
47
- color: #f9fafb;
48
- border: none;
118
+
119
+ #search:focus {
120
+ border-color: #3b82f6;
121
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.15);
122
+ }
123
+
124
+ #search::placeholder {
125
+ color: #374151;
126
+ }
127
+
128
+ .filter-group {
129
+ display: flex;
130
+ gap: 2px;
131
+ background: #0f1624;
132
+ border: 1px solid #1e2d45;
133
+ border-radius: 6px;
134
+ padding: 3px;
135
+ }
136
+
137
+ .filter-group label {
138
+ cursor: pointer;
139
+ display: flex;
140
+ align-items: center;
141
+ gap: 4px;
142
+ font-size: 11px;
143
+ font-weight: 500;
144
+ color: #4b5563;
145
+ padding: 2px 7px;
49
146
  border-radius: 4px;
50
- padding: 4px 12px;
147
+ transition:
148
+ background 0.1s,
149
+ color 0.1s;
150
+ user-select: none;
151
+ }
152
+
153
+ .filter-group label:hover {
154
+ background: #1a2540;
155
+ color: #9ca3af;
156
+ }
157
+
158
+ .filter-group label input {
159
+ display: none;
160
+ }
161
+
162
+ .filter-group label.active {
163
+ color: #e2e8f0;
164
+ background: #1a2540;
165
+ }
166
+
167
+ .filter-group label .indicator {
168
+ width: 6px;
169
+ height: 6px;
170
+ border-radius: 2px;
171
+ }
172
+
173
+ #reset-btn {
174
+ background: transparent;
175
+ color: #4b5563;
176
+ border: 1px solid #1e2d45;
177
+ border-radius: 6px;
178
+ padding: 4px 10px;
51
179
  cursor: pointer;
180
+ font-size: 11px;
181
+ font-weight: 500;
182
+ transition:
183
+ background 0.15s,
184
+ color 0.15s,
185
+ border-color 0.15s;
186
+ white-space: nowrap;
52
187
  }
53
- #topbar button:hover {
54
- background: #4b5563;
188
+
189
+ #reset-btn:hover {
190
+ background: #1a2035;
191
+ color: #9ca3af;
192
+ border-color: #2d3f5f;
55
193
  }
194
+
195
+ /* ─── Canvas ──────────────────────────────────────── */
56
196
  #canvas {
57
- background: #fafbfc;
197
+ background-color: #050810;
198
+ background-image: radial-gradient(rgba(148, 163, 184, 0.06) 1px, transparent 1px);
199
+ background-size: 28px 28px;
58
200
  position: relative;
201
+ min-height: 0;
202
+ overflow: hidden;
203
+ }
204
+
205
+ #progress-wrap {
206
+ position: fixed;
207
+ top: 52px;
208
+ left: 0;
209
+ right: 0;
210
+ height: 2px;
211
+ z-index: 100;
212
+ pointer-events: none;
213
+ overflow: hidden;
59
214
  }
215
+
216
+ #progress-bar {
217
+ height: 100%;
218
+ width: 0%;
219
+ background: linear-gradient(90deg, #3b82f6, #6366f1);
220
+ transition: width 0.1s linear;
221
+ box-shadow: 0 0 6px rgba(99, 102, 241, 0.6);
222
+ }
223
+
224
+ /* ─── Side panel ──────────────────────────────────── */
60
225
  #sidepanel {
61
- background: #ffffff;
62
- border-left: 1px solid #e5e7eb;
63
- padding: 16px;
226
+ background: #080c14;
227
+ border-left: 1px solid #1a2035;
64
228
  overflow-y: auto;
229
+ color: #e2e8f0;
230
+ display: flex;
231
+ flex-direction: column;
232
+ transition: opacity 0.2s;
65
233
  }
234
+
66
235
  #sidepanel.hidden {
67
- display: none;
236
+ visibility: hidden;
237
+ opacity: 0;
238
+ pointer-events: none;
239
+ }
240
+
241
+ .sp-header {
242
+ padding: 16px 16px 12px;
243
+ border-bottom: 1px solid #1a2035;
244
+ }
245
+
246
+ .sp-group-badge {
247
+ display: inline-block;
248
+ font-size: 9px;
249
+ font-weight: 700;
250
+ letter-spacing: 0.08em;
251
+ text-transform: uppercase;
252
+ border-radius: 3px;
253
+ padding: 2px 6px;
254
+ margin-bottom: 8px;
68
255
  }
69
- #sidepanel h3 {
70
- margin: 0 0 8px;
256
+
257
+ .sp-group-badge.ticket {
258
+ background: rgba(59, 130, 246, 0.15);
259
+ color: #60a5fa;
260
+ border: 1px solid rgba(59, 130, 246, 0.25);
261
+ }
262
+ .sp-group-badge.scenario {
263
+ background: rgba(16, 185, 129, 0.12);
264
+ color: #34d399;
265
+ border: 1px solid rgba(16, 185, 129, 0.2);
266
+ }
267
+ .sp-group-badge.scenario-fail {
268
+ background: rgba(239, 68, 68, 0.12);
269
+ color: #f87171;
270
+ border: 1px solid rgba(239, 68, 68, 0.2);
271
+ }
272
+ .sp-group-badge.pom {
273
+ background: rgba(245, 158, 11, 0.12);
274
+ color: #fbbf24;
275
+ border: 1px solid rgba(245, 158, 11, 0.2);
276
+ }
277
+
278
+ .sp-title {
71
279
  font-size: 14px;
280
+ font-weight: 600;
281
+ color: #f1f5f9;
282
+ line-height: 1.4;
283
+ margin: 0;
72
284
  }
73
- #sidepanel p {
74
- margin: 0 0 12px;
75
- font-size: 13px;
76
- color: #4b5563;
285
+
286
+ .sp-desc {
287
+ padding: 12px 16px;
288
+ font-size: 12px;
289
+ color: #64748b;
290
+ line-height: 1.6;
291
+ border-bottom: 1px solid #1a2035;
292
+ flex: 1;
77
293
  }
294
+
295
+ .sp-actions {
296
+ padding: 12px 16px;
297
+ }
298
+
299
+ .sp-actions button {
300
+ background: linear-gradient(135deg, #1d4ed8, #4f46e5);
301
+ color: #eff6ff;
302
+ border: none;
303
+ border-radius: 6px;
304
+ padding: 7px 12px;
305
+ font-size: 12px;
306
+ font-weight: 500;
307
+ cursor: pointer;
308
+ width: 100%;
309
+ transition:
310
+ opacity 0.15s,
311
+ transform 0.1s;
312
+ letter-spacing: 0.01em;
313
+ }
314
+
315
+ .sp-actions button:hover {
316
+ opacity: 0.9;
317
+ }
318
+
319
+ .sp-actions button:active {
320
+ transform: scale(0.98);
321
+ }
322
+
323
+ .sp-actions button.copied {
324
+ background: linear-gradient(135deg, #065f46, #047857);
325
+ }
326
+
327
+ /* ─── Footer ──────────────────────────────────────── */
78
328
  #footer {
79
329
  grid-column: 1 / -1;
80
- background: #f3f4f6;
81
- padding: 6px 16px;
82
- font-size: 11px;
330
+ background: #050810;
331
+ padding: 4px 16px;
332
+ font-size: 10px;
333
+ color: #1e2d45;
334
+ border-top: 1px solid #0d1117;
335
+ display: flex;
336
+ align-items: center;
337
+ gap: 12px;
338
+ }
339
+
340
+ #footer span {
341
+ color: #374151;
342
+ }
343
+
344
+ /* ─── Coverage tab + subtabs ──────────────────────── */
345
+ .toplevel-tabs {
346
+ display: flex;
347
+ gap: 4px;
348
+ }
349
+ .toplevel-tabs button {
350
+ padding: 6px 12px;
351
+ border: 0;
352
+ background: transparent;
353
+ cursor: pointer;
354
+ color: #9ca3af;
355
+ }
356
+ .toplevel-tabs button.active {
357
+ border-bottom: 2px solid #3b82f6;
358
+ font-weight: bold;
359
+ color: #e2e8f0;
360
+ }
361
+ [data-tab-panel] {
362
+ display: none;
363
+ }
364
+ [data-tab-panel].active {
365
+ display: block;
366
+ }
367
+ .subtabs {
368
+ display: flex;
369
+ gap: 4px;
370
+ padding: 8px;
371
+ }
372
+ .subtabs button {
373
+ padding: 4px 10px;
374
+ border: 1px solid #d1d5db;
375
+ background: white;
376
+ cursor: pointer;
377
+ }
378
+ .subtabs button.active {
379
+ background: #3b82f6;
380
+ color: white;
381
+ }
382
+ [data-subpanel] {
383
+ padding: 12px;
384
+ }
385
+ .subpanel-hint {
83
386
  color: #6b7280;
84
- border-top: 1px solid #e5e7eb;
387
+ font-size: 13px;
388
+ margin: 4px 0 12px;
389
+ }
390
+ #coverage-list-table,
391
+ #coverage-ac-table {
392
+ border-collapse: collapse;
393
+ width: 100%;
394
+ font-size: 13px;
395
+ }
396
+ #coverage-list-table th,
397
+ #coverage-list-table td,
398
+ #coverage-ac-table th,
399
+ #coverage-ac-table td {
400
+ border: 1px solid #e5e7eb;
401
+ padding: 6px 10px;
402
+ text-align: left;
403
+ }
404
+ #coverage-list-table th {
405
+ background: #f9fafb;
406
+ cursor: pointer;
407
+ }
408
+ .status-uncovered {
409
+ background: #fee2e2;
410
+ }
411
+ .status-stale {
412
+ background: #fef3c7;
413
+ }
414
+ .status-covered {
415
+ background: #d1fae5;
416
+ }
417
+ #coverage-map-canvas {
418
+ width: 100%;
419
+ height: 600px;
85
420
  }
86
- .disputed-outline {
87
- border: 2px dashed #ef4444;
421
+ #coverage-trend-svg {
422
+ width: 100%;
423
+ min-height: 300px;
88
424
  }
@@ -7,25 +7,45 @@
7
7
  </head>
8
8
  <body>
9
9
  <header id="topbar">
10
- <div class="title">xera graph</div>
11
- <div class="stats">{{STATS}}</div>
12
- <div class="filters">
13
- <input type="text" id="search" placeholder="search…" />
14
- <label><input type="checkbox" id="filter-pass" checked> pass</label>
15
- <label><input type="checkbox" id="filter-fail" checked> fail</label>
16
- <label><input type="checkbox" id="filter-p0" checked> P0</label>
17
- <button id="reset">reset</button>
10
+ <div class="topbar-brand">
11
+ <div class="logo"></div>
12
+ <span class="title">xera graph</span>
13
+ </div>
14
+ <nav class="toplevel-tabs">
15
+ <button data-tab="knowledge" class="active">Knowledge</button>
16
+ {{COVERAGE_TAB_BUTTON}}
17
+ </nav>
18
+ <div id="stats-bar" data-stats="{{STATS}}"></div>
19
+ <div class="topbar-controls">
20
+ <input type="text" id="search" placeholder="search nodes…" autocomplete="off" />
21
+ <div class="filter-group">
22
+ <label id="label-pass"><input type="checkbox" id="filter-pass" checked /><span class="indicator" style="background:#3fb950"></span>pass</label>
23
+ <label id="label-fail"><input type="checkbox" id="filter-fail" checked /><span class="indicator" style="background:#f85149"></span>fail</label>
24
+ <label id="label-p0"><input type="checkbox" id="filter-p0" checked /><span class="indicator" style="background:#e3b341"></span>P0</label>
25
+ </div>
26
+ <button id="reset-btn">fit</button>
18
27
  </div>
19
28
  </header>
20
- <main id="canvas"></main>
21
- <aside id="sidepanel" class="hidden">
22
- <h3 id="sp-title"></h3>
23
- <p id="sp-desc"></p>
24
- <div id="sp-actions"></div>
25
- </aside>
26
- <footer id="footer">generated {{GENERATED_AT}} · double-click a node to open · right-click for options</footer>
29
+ <div id="progress-wrap"><div id="progress-bar"></div></div>
30
+ <section data-tab-panel="knowledge" class="active">
31
+ <main id="canvas"></main>
32
+ <aside id="sidepanel" class="hidden">
33
+ <div class="sp-header">
34
+ <div id="sp-group" class="sp-group-badge"></div>
35
+ <p id="sp-title" class="sp-title"></p>
36
+ </div>
37
+ <div id="sp-desc" class="sp-desc"></div>
38
+ <div id="sp-actions" class="sp-actions"></div>
39
+ </aside>
40
+ </section>
41
+ {{COVERAGE_TAB_PANEL}}
42
+ <footer id="footer">
43
+ generated {{GENERATED_AT}}
44
+ <span>· scroll to zoom · drag to pan · click to inspect</span>
45
+ </footer>
27
46
  <script>{{VIS_NETWORK_JS}}</script>
28
47
  <script>window.__GRAPH__ = {{GRAPH_DATA}};</script>
48
+ <script>window.__COVERAGE__ = {{COVERAGE_DATA}};</script>
29
49
  <script>{{INTERACTION_JS}}</script>
30
50
  </body>
31
51
  </html>