opencastle 0.10.2 → 0.10.4

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 (74) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/detect.d.ts +6 -0
  3. package/dist/cli/detect.d.ts.map +1 -1
  4. package/dist/cli/detect.js +133 -0
  5. package/dist/cli/detect.js.map +1 -1
  6. package/dist/cli/detect.test.js +119 -1
  7. package/dist/cli/detect.test.js.map +1 -1
  8. package/dist/cli/init.d.ts.map +1 -1
  9. package/dist/cli/init.js +32 -8
  10. package/dist/cli/init.js.map +1 -1
  11. package/dist/cli/init.test.js +44 -1
  12. package/dist/cli/init.test.js.map +1 -1
  13. package/dist/cli/prompt.d.ts +8 -0
  14. package/dist/cli/prompt.d.ts.map +1 -1
  15. package/dist/cli/prompt.js +89 -20
  16. package/dist/cli/prompt.js.map +1 -1
  17. package/dist/cli/prompt.test.d.ts +2 -0
  18. package/dist/cli/prompt.test.d.ts.map +1 -0
  19. package/dist/cli/prompt.test.js +58 -0
  20. package/dist/cli/prompt.test.js.map +1 -0
  21. package/dist/cli/types.d.ts +1 -1
  22. package/dist/cli/types.d.ts.map +1 -1
  23. package/dist/cli/update.d.ts.map +1 -1
  24. package/dist/cli/update.js +2 -8
  25. package/dist/cli/update.js.map +1 -1
  26. package/package.json +1 -1
  27. package/src/cli/detect.test.ts +133 -1
  28. package/src/cli/detect.ts +144 -0
  29. package/src/cli/init.test.ts +53 -1
  30. package/src/cli/init.ts +32 -8
  31. package/src/cli/prompt.test.ts +66 -0
  32. package/src/cli/prompt.ts +108 -22
  33. package/src/cli/types.ts +1 -1
  34. package/src/cli/update.ts +2 -8
  35. package/src/dashboard/dist/index.html +2 -2
  36. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
  37. package/src/dashboard/package-lock.json +6 -0
  38. package/src/dashboard/scripts/generate-seed-data.ts +10 -10
  39. package/src/dashboard/seed-data/delegations.ndjson +35 -35
  40. package/src/dashboard/seed-data/panels.ndjson +12 -12
  41. package/src/dashboard/seed-data/reviews.ndjson +6 -6
  42. package/src/dashboard/seed-data/sessions.ndjson +50 -50
  43. package/src/dashboard/src/pages/index.astro +2 -2
  44. package/src/orchestrator/agents/api-designer.agent.md +1 -0
  45. package/src/orchestrator/agents/architect.agent.md +2 -1
  46. package/src/orchestrator/agents/content-engineer.agent.md +1 -0
  47. package/src/orchestrator/agents/copywriter.agent.md +1 -0
  48. package/src/orchestrator/agents/data-expert.agent.md +1 -0
  49. package/src/orchestrator/agents/database-engineer.agent.md +1 -0
  50. package/src/orchestrator/agents/developer.agent.md +2 -1
  51. package/src/orchestrator/agents/devops-expert.agent.md +1 -0
  52. package/src/orchestrator/agents/documentation-writer.agent.md +1 -0
  53. package/src/orchestrator/agents/performance-expert.agent.md +1 -0
  54. package/src/orchestrator/agents/release-manager.agent.md +1 -0
  55. package/src/orchestrator/agents/researcher.agent.md +3 -2
  56. package/src/orchestrator/agents/reviewer.agent.md +1 -0
  57. package/src/orchestrator/agents/security-expert.agent.md +2 -1
  58. package/src/orchestrator/agents/seo-specialist.agent.md +1 -0
  59. package/src/orchestrator/agents/session-guard.agent.md +3 -2
  60. package/src/orchestrator/agents/team-lead.agent.md +31 -17
  61. package/src/orchestrator/agents/testing-expert.agent.md +1 -0
  62. package/src/orchestrator/agents/ui-ux-expert.agent.md +2 -1
  63. package/src/orchestrator/customizations/agents/agent-registry.md +9 -9
  64. package/src/orchestrator/customizations/logs/README.md +11 -11
  65. package/src/orchestrator/customizations/logs/disputes.ndjson +0 -0
  66. package/src/orchestrator/customizations/logs/reviews.ndjson +0 -0
  67. package/src/orchestrator/instructions/general.instructions.md +28 -14
  68. package/src/orchestrator/skills/agent-hooks/SKILL.md +6 -26
  69. package/src/orchestrator/skills/fast-review/SKILL.md +2 -1
  70. package/src/orchestrator/skills/orchestration-protocols/SKILL.md +34 -0
  71. package/src/orchestrator/skills/panel-majority-vote/SKILL.md +3 -3
  72. package/src/orchestrator/skills/self-improvement/SKILL.md +1 -30
  73. package/src/orchestrator/skills/session-checkpoints/SKILL.md +0 -86
  74. package/src/orchestrator/skills/team-lead-reference/SKILL.md +17 -71
@@ -0,0 +1,66 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { computeVisibleWindow } from './prompt.js';
3
+
4
+ describe('computeVisibleWindow', () => {
5
+ it('returns full range when all items fit', () => {
6
+ expect(computeVisibleWindow(0, 5, 10)).toEqual({ start: 0, end: 5 });
7
+ });
8
+
9
+ it('keeps cursor visible at top', () => {
10
+ const { start, end } = computeVisibleWindow(0, 20, 10);
11
+ expect(start).toBeLessThanOrEqual(0);
12
+ expect(end).toBeGreaterThan(0);
13
+ expect(end - start).toBe(10);
14
+ });
15
+
16
+ it('keeps cursor visible at bottom', () => {
17
+ const { start, end } = computeVisibleWindow(19, 20, 10);
18
+ expect(start).toBeLessThanOrEqual(19);
19
+ expect(end).toBeGreaterThanOrEqual(20);
20
+ expect(end - start).toBe(10);
21
+ });
22
+
23
+ it('keeps cursor visible in middle', () => {
24
+ const { start, end } = computeVisibleWindow(10, 20, 10);
25
+ expect(start).toBeLessThanOrEqual(10);
26
+ expect(end).toBeGreaterThan(10);
27
+ expect(end - start).toBe(10);
28
+ });
29
+
30
+ it('handles cursor at exact boundary', () => {
31
+ const { start, end } = computeVisibleWindow(9, 20, 10);
32
+ expect(start).toBeLessThanOrEqual(9);
33
+ expect(end).toBeGreaterThan(9);
34
+ });
35
+
36
+ it('window size never exceeds maxVisible', () => {
37
+ for (let cursor = 0; cursor < 20; cursor++) {
38
+ const { start, end } = computeVisibleWindow(cursor, 20, 10);
39
+ expect(end - start).toBeLessThanOrEqual(10);
40
+ expect(start).toBeGreaterThanOrEqual(0);
41
+ expect(end).toBeLessThanOrEqual(20);
42
+ expect(start).toBeLessThanOrEqual(cursor);
43
+ expect(end).toBeGreaterThan(cursor);
44
+ }
45
+ });
46
+
47
+ // Test that wrapping cursor (e.g. from 0 to 19 on arrow-up) stays visible
48
+ it('handles wrap from first to last item', () => {
49
+ const { start, end } = computeVisibleWindow(19, 20, 10);
50
+ expect(start).toBeLessThanOrEqual(19);
51
+ expect(end).toBe(20);
52
+ });
53
+
54
+ it('handles wrap from last to first item', () => {
55
+ const { start, end } = computeVisibleWindow(0, 20, 10);
56
+ expect(start).toBe(0);
57
+ expect(end).toBeGreaterThan(0);
58
+ });
59
+
60
+ it('returns valid range for maxVisible of 3 (minimum)', () => {
61
+ const { start, end } = computeVisibleWindow(10, 20, 3);
62
+ expect(end - start).toBe(3);
63
+ expect(start).toBeLessThanOrEqual(10);
64
+ expect(end).toBeGreaterThan(10);
65
+ });
66
+ });
package/src/cli/prompt.ts CHANGED
@@ -27,6 +27,31 @@ export const c = {
27
27
  magenta: (s: string) => `\x1B[35m${s}\x1B[0m`,
28
28
  };
29
29
 
30
+ // ── Scrollable window helper ──────────────────────────────────────
31
+
32
+ /**
33
+ * Compute which slice of options to render in a scrollable window.
34
+ * Keeps the cursor visible within the window.
35
+ */
36
+ export function computeVisibleWindow(
37
+ cursor: number,
38
+ total: number,
39
+ maxVisible: number
40
+ ): { start: number; end: number } {
41
+ if (total <= maxVisible) return { start: 0, end: total };
42
+ let start = Math.max(0, cursor - maxVisible + 1);
43
+ let end = start + maxVisible;
44
+ if (end > total) {
45
+ end = total;
46
+ start = end - maxVisible;
47
+ }
48
+ if (cursor < start) {
49
+ start = cursor;
50
+ end = start + maxVisible;
51
+ }
52
+ return { start, end };
53
+ }
54
+
30
55
  // ── Line-buffered readline ────────────────────────────────────────
31
56
  // readline.question() drops lines that arrived between calls because
32
57
  // it only listens for the NEXT 'line' event. When piped input
@@ -114,14 +139,22 @@ export async function select(
114
139
  function renderOptions(
115
140
  options: SelectOption[],
116
141
  cursor: number,
117
- initial: boolean
118
- ): void {
119
- // Move back up to overwrite previous render (skip on first draw)
120
- if (!initial) {
121
- stdout.write(moveUp(options.length));
142
+ lastRenderedLines: number,
143
+ maxVisible: number
144
+ ): number {
145
+ if (lastRenderedLines > 0) {
146
+ stdout.write(moveUp(lastRenderedLines));
147
+ }
148
+
149
+ const { start, end } = computeVisibleWindow(cursor, options.length, maxVisible);
150
+ let lines = 0;
151
+
152
+ if (start > 0) {
153
+ stdout.write(`${ERASE_LINE}\r ${c.dim(`↑ ${start} more above`)}\n`);
154
+ lines++;
122
155
  }
123
156
 
124
- for (let i = 0; i < options.length; i++) {
157
+ for (let i = start; i < end; i++) {
125
158
  const active = i === cursor;
126
159
  const marker = active ? '❯' : ' ';
127
160
  const hint = options[i].hint ? ` — ${options[i].hint}` : '';
@@ -129,7 +162,20 @@ function renderOptions(
129
162
  ? `\x1B[36m${options[i].label}\x1B[0m${hint}`
130
163
  : `${options[i].label}${hint}`;
131
164
  stdout.write(`${ERASE_LINE}\r ${marker} ${label}\n`);
165
+ lines++;
166
+ }
167
+
168
+ if (end < options.length) {
169
+ stdout.write(`${ERASE_LINE}\r ${c.dim(`↓ ${options.length - end} more below`)}\n`);
170
+ lines++;
132
171
  }
172
+
173
+ // Clear leftover lines from previous longer render
174
+ if (lines < lastRenderedLines) {
175
+ stdout.write(`${CSI}J`);
176
+ }
177
+
178
+ return lines;
133
179
  }
134
180
 
135
181
  function selectInteractive(
@@ -138,13 +184,15 @@ function selectInteractive(
138
184
  ): Promise<string> {
139
185
  return new Promise<string>((resolve) => {
140
186
  let cursor = 0;
187
+ const maxVisible = Math.max(3, Math.min(options.length, (process.stdout.rows || 24) - 4));
188
+ let lastRenderedLines = 0;
141
189
 
142
190
  // Pause the readline interface so raw mode can take over
143
191
  if (_rl) _rl.pause();
144
192
 
145
193
  stdout.write(`\n ${message}\n\n`);
146
194
  stdout.write(HIDE_CURSOR);
147
- renderOptions(options, cursor, true);
195
+ lastRenderedLines = renderOptions(options, cursor, 0, maxVisible);
148
196
 
149
197
  stdin.setRawMode(true);
150
198
  stdin.resume();
@@ -155,14 +203,14 @@ function selectInteractive(
155
203
  // Arrow up or k
156
204
  if (key === `${ESC}[A` || key === 'k') {
157
205
  cursor = (cursor - 1 + options.length) % options.length;
158
- renderOptions(options, cursor, false);
206
+ lastRenderedLines = renderOptions(options, cursor, lastRenderedLines, maxVisible);
159
207
  return;
160
208
  }
161
209
 
162
210
  // Arrow down or j
163
211
  if (key === `${ESC}[B` || key === 'j') {
164
212
  cursor = (cursor + 1) % options.length;
165
- renderOptions(options, cursor, false);
213
+ lastRenderedLines = renderOptions(options, cursor, lastRenderedLines, maxVisible);
166
214
  return;
167
215
  }
168
216
 
@@ -170,8 +218,9 @@ function selectInteractive(
170
218
  if (key === '\r' || key === '\n') {
171
219
  cleanup();
172
220
  // Re-render final state with the selected option highlighted
173
- stdout.write(moveUp(options.length));
174
- for (let i = 0; i < options.length; i++) {
221
+ const { start, end } = computeVisibleWindow(cursor, options.length, maxVisible);
222
+ stdout.write(moveUp(lastRenderedLines));
223
+ for (let i = start; i < end; i++) {
175
224
  const active = i === cursor;
176
225
  const hint = options[i].hint ? ` — ${options[i].hint}` : '';
177
226
  const label = active
@@ -180,6 +229,11 @@ function selectInteractive(
180
229
  const marker = active ? '✔' : ' ';
181
230
  stdout.write(`${ERASE_LINE}\r ${marker} ${label}\n`);
182
231
  }
232
+ // Clear leftover lines only when final render has fewer lines
233
+ const finalLines = end - start;
234
+ if (finalLines < lastRenderedLines) {
235
+ stdout.write(`${CSI}J`);
236
+ }
183
237
  stdout.write('\n');
184
238
  resolve(options[cursor].value);
185
239
  return;
@@ -195,6 +249,7 @@ function selectInteractive(
195
249
 
196
250
  function cleanup(): void {
197
251
  stdin.removeListener('data', onData);
252
+ stdin.pause();
198
253
  stdin.setRawMode(false);
199
254
  stdout.write(SHOW_CURSOR);
200
255
  // Resume readline for subsequent confirm() calls
@@ -276,13 +331,22 @@ function renderMultiselectOptions(
276
331
  options: SelectOption[],
277
332
  cursor: number,
278
333
  selected: Set<number>,
279
- initial: boolean
280
- ): void {
281
- if (!initial) {
282
- stdout.write(moveUp(options.length));
334
+ lastRenderedLines: number,
335
+ maxVisible: number
336
+ ): number {
337
+ if (lastRenderedLines > 0) {
338
+ stdout.write(moveUp(lastRenderedLines));
339
+ }
340
+
341
+ const { start, end } = computeVisibleWindow(cursor, options.length, maxVisible);
342
+ let lines = 0;
343
+
344
+ if (start > 0) {
345
+ stdout.write(`${ERASE_LINE}\r ${c.dim(`↑ ${start} more above`)}\n`);
346
+ lines++;
283
347
  }
284
348
 
285
- for (let i = 0; i < options.length; i++) {
349
+ for (let i = start; i < end; i++) {
286
350
  const active = i === cursor;
287
351
  const checked = selected.has(i);
288
352
  const checkbox = checked ? `\x1B[32m✔\x1B[0m` : ' ';
@@ -292,7 +356,20 @@ function renderMultiselectOptions(
292
356
  ? `\x1B[36m${options[i].label}\x1B[0m${hint}`
293
357
  : `${options[i].label}${hint}`;
294
358
  stdout.write(`${ERASE_LINE}\r ${marker} [${checkbox}] ${label}\n`);
359
+ lines++;
295
360
  }
361
+
362
+ if (end < options.length) {
363
+ stdout.write(`${ERASE_LINE}\r ${c.dim(`↓ ${options.length - end} more below`)}\n`);
364
+ lines++;
365
+ }
366
+
367
+ // Clear leftover lines from previous longer render
368
+ if (lines < lastRenderedLines) {
369
+ stdout.write(`${CSI}J`);
370
+ }
371
+
372
+ return lines;
296
373
  }
297
374
 
298
375
  function multiselectInteractive(
@@ -302,6 +379,8 @@ function multiselectInteractive(
302
379
  return new Promise<string[]>((resolve) => {
303
380
  let cursor = 0;
304
381
  const selected = new Set<number>();
382
+ const maxVisible = Math.max(3, Math.min(options.length, (process.stdout.rows || 24) - 4));
383
+ let lastRenderedLines = 0;
305
384
  // Pre-select options marked as selected
306
385
  for (let i = 0; i < options.length; i++) {
307
386
  if (options[i].selected) selected.add(i);
@@ -311,7 +390,7 @@ function multiselectInteractive(
311
390
 
312
391
  stdout.write(`\n ${message} ${c.dim('(↑/↓ navigate, Space toggle, Enter confirm)')}\n\n`);
313
392
  stdout.write(HIDE_CURSOR);
314
- renderMultiselectOptions(options, cursor, selected, true);
393
+ lastRenderedLines = renderMultiselectOptions(options, cursor, selected, 0, maxVisible);
315
394
 
316
395
  stdin.setRawMode(true);
317
396
  stdin.resume();
@@ -322,14 +401,14 @@ function multiselectInteractive(
322
401
  // Arrow up or k
323
402
  if (key === `${ESC}[A` || key === 'k') {
324
403
  cursor = (cursor - 1 + options.length) % options.length;
325
- renderMultiselectOptions(options, cursor, selected, false);
404
+ lastRenderedLines = renderMultiselectOptions(options, cursor, selected, lastRenderedLines, maxVisible);
326
405
  return;
327
406
  }
328
407
 
329
408
  // Arrow down or j
330
409
  if (key === `${ESC}[B` || key === 'j') {
331
410
  cursor = (cursor + 1) % options.length;
332
- renderMultiselectOptions(options, cursor, selected, false);
411
+ lastRenderedLines = renderMultiselectOptions(options, cursor, selected, lastRenderedLines, maxVisible);
333
412
  return;
334
413
  }
335
414
 
@@ -340,7 +419,7 @@ function multiselectInteractive(
340
419
  } else {
341
420
  selected.add(cursor);
342
421
  }
343
- renderMultiselectOptions(options, cursor, selected, false);
422
+ lastRenderedLines = renderMultiselectOptions(options, cursor, selected, lastRenderedLines, maxVisible);
344
423
  return;
345
424
  }
346
425
 
@@ -348,8 +427,9 @@ function multiselectInteractive(
348
427
  if (key === '\r' || key === '\n') {
349
428
  cleanup();
350
429
  // Final render
351
- stdout.write(moveUp(options.length));
352
- for (let i = 0; i < options.length; i++) {
430
+ const { start, end } = computeVisibleWindow(cursor, options.length, maxVisible);
431
+ stdout.write(moveUp(lastRenderedLines));
432
+ for (let i = start; i < end; i++) {
353
433
  const checked = selected.has(i);
354
434
  const hint = options[i].hint ? ` ${c.dim('—')} ${c.dim(options[i].hint!)}` : '';
355
435
  const checkbox = checked ? `\x1B[32m✔\x1B[0m` : ' ';
@@ -358,6 +438,11 @@ function multiselectInteractive(
358
438
  : `\x1B[2m${options[i].label}${hint}\x1B[0m`;
359
439
  stdout.write(`${ERASE_LINE}\r [${checkbox}] ${label}\n`);
360
440
  }
441
+ // Clear leftover lines only when final render has fewer lines
442
+ const finalLines = end - start;
443
+ if (finalLines < lastRenderedLines) {
444
+ stdout.write(`${CSI}J`);
445
+ }
361
446
  stdout.write('\n');
362
447
  resolve(Array.from(selected).sort().map(i => options[i].value));
363
448
  return;
@@ -373,6 +458,7 @@ function multiselectInteractive(
373
458
 
374
459
  function cleanup(): void {
375
460
  stdin.removeListener('data', onData);
461
+ stdin.pause();
376
462
  stdin.setRawMode(false);
377
463
  stdout.write(SHOW_CURSOR);
378
464
  if (_rl) _rl.resume();
package/src/cli/types.ts CHANGED
@@ -3,7 +3,7 @@ import type { ChildProcess } from 'node:child_process';
3
3
  // ── Stack selection types ──────────────────────────────────────
4
4
 
5
5
  export type IdeChoice = 'vscode' | 'cursor' | 'claude-code' | 'opencode';
6
- export type TechTool = 'sanity' | 'contentful' | 'strapi' | 'supabase' | 'convex' | 'vercel' | 'nx' | 'chrome-devtools' | 'nextjs' | 'astro';
6
+ export type TechTool = 'sanity' | 'contentful' | 'strapi' | 'supabase' | 'convex' | 'vercel' | 'nx' | 'chrome-devtools' | 'nextjs' | 'astro' | 'netlify' | 'turborepo' | 'prisma' | 'cypress' | 'playwright' | 'vitest' | 'figma' | 'resend';
7
7
  export type TeamTool = 'linear' | 'jira' | 'slack' | 'teams';
8
8
 
9
9
  export interface StackConfig {
package/src/cli/update.ts CHANGED
@@ -7,7 +7,7 @@ import { TECH_PLUGINS, TEAM_PLUGINS } from '../orchestrator/plugins/index.js'
7
7
  import { IDE_ADAPTERS, VALID_IDES } from './adapters/index.js'
8
8
  import { getRequiredMcpEnvVars, updateSkillMatrixFile } from './stack-config.js'
9
9
  import { rebuildMcpConfig } from './mcp.js'
10
- import { detectRepoInfo, mergeStackIntoRepoInfo } from './detect.js'
10
+ import { detectRepoInfo, mergeStackIntoRepoInfo, buildDetectedToolsSet } from './detect.js'
11
11
  import type { CliContext, IdeChoice, TechTool, TeamTool, StackConfig } from './types.js'
12
12
 
13
13
  export default async function update({
@@ -75,13 +75,7 @@ export default async function update({
75
75
  let removedTools: string[] = []
76
76
 
77
77
  if (wantsReconfigure) {
78
- const detectedTools = new Set([
79
- ...(repoInfo.cms ?? []),
80
- ...(repoInfo.databases ?? []),
81
- ...(repoInfo.deployment ?? []),
82
- ...(repoInfo.monorepo ? [repoInfo.monorepo] : []),
83
- ...((repoInfo.frameworks ?? []).map((f) => (f === 'next' ? 'nextjs' : f))),
84
- ])
78
+ const detectedTools = buildDetectedToolsSet(repoInfo)
85
79
 
86
80
  const currentTech = new Set(oldStack?.techTools ?? [])
87
81
  const currentTeam = new Set(oldStack?.teamTools ?? [])
@@ -913,7 +913,7 @@ Export
913
913
  (s.retries != null ? s.retries : '\u2014') +
914
914
  '</td>' +
915
915
  '<td class="td-issue">' +
916
- (s.linear_issue ? escapeHtml(s.linear_issue) : '\u2014') +
916
+ (s.tracker_issue ? escapeHtml(s.tracker_issue) : '\u2014') +
917
917
  '</td>' +
918
918
  '</tr>'
919
919
  )
@@ -1049,7 +1049,7 @@ Export
1049
1049
  '<td class="td-num">' + (r.confidence || '\u2014') + '</td>' +
1050
1050
  '<td class="td-num">' + (r.attempt ?? 1) + '</td>' +
1051
1051
  '<td class="td-num">' + (r.escalated ? '\u26A0' : '\u2014') + '</td>' +
1052
- '<td class="td-issue">' + (r.linear_issue ? escapeHtml(r.linear_issue) : '\u2014') + '</td>' +
1052
+ '<td class="td-issue">' + (r.tracker_issue ? escapeHtml(r.tracker_issue) : '\u2014') + '</td>' +
1053
1053
  '</tr>'
1054
1054
  )
1055
1055
  .join('') +
@@ -1,25 +1,25 @@
1
1
  {
2
- "hash": "aa158bc8",
2
+ "hash": "96d8fe83",
3
3
  "configHash": "30f8ea04",
4
- "lockfileHash": "09e90d1c",
5
- "browserHash": "2f7bb5ff",
4
+ "lockfileHash": "5ea9e438",
5
+ "browserHash": "6c2f45c8",
6
6
  "optimized": {
7
7
  "astro > cssesc": {
8
8
  "src": "../../../../../node_modules/cssesc/cssesc.js",
9
9
  "file": "astro___cssesc.js",
10
- "fileHash": "ea61e9a5",
10
+ "fileHash": "424459bd",
11
11
  "needsInterop": true
12
12
  },
13
13
  "astro > aria-query": {
14
14
  "src": "../../../../../node_modules/aria-query/lib/index.js",
15
15
  "file": "astro___aria-query.js",
16
- "fileHash": "401c0a39",
16
+ "fileHash": "8cd71dbe",
17
17
  "needsInterop": true
18
18
  },
19
19
  "astro > axobject-query": {
20
20
  "src": "../../../../../node_modules/axobject-query/lib/index.js",
21
21
  "file": "astro___axobject-query.js",
22
- "fileHash": "15390df2",
22
+ "fileHash": "6e84e164",
23
23
  "needsInterop": true
24
24
  }
25
25
  },
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "dashboard",
3
+ "lockfileVersion": 3,
4
+ "requires": true,
5
+ "packages": {}
6
+ }
@@ -43,7 +43,7 @@ const TIERS: Array<{ name: string; weight: number }> = [
43
43
 
44
44
  const _MECHANISMS = ['sub-agent', 'background'];
45
45
 
46
- const LINEAR_ISSUES = Array.from({ length: 30 }, (_, i) => `TAS-${i + 30}`);
46
+ const TRACKER_ISSUES = Array.from({ length: 30 }, (_, i) => `TAS-${i + 30}`);
47
47
 
48
48
  const FILE_PARTITIONS = [
49
49
  ['libs/ui-kit/'],
@@ -160,7 +160,7 @@ interface SessionRecord {
160
160
  agent: string;
161
161
  model: string;
162
162
  task: string;
163
- linear_issue: string;
163
+ tracker_issue: string;
164
164
  outcome: string;
165
165
  duration_min: number;
166
166
  files_changed: number;
@@ -172,7 +172,7 @@ interface SessionRecord {
172
172
  function generateSessions(count: number): SessionRecord[] {
173
173
  const records: SessionRecord[] = [];
174
174
  for (let i = 0; i < count; i++) {
175
- const issue = rng.pick(LINEAR_ISSUES);
175
+ const issue = rng.pick(TRACKER_ISSUES);
176
176
  const outcomeRoll = rng.next();
177
177
  const outcome = outcomeRoll < 0.7 ? 'success' : outcomeRoll < 0.9 ? 'partial' : 'failed';
178
178
  const retries = outcome === 'failed' ? rng.int(1, 3) : outcome === 'partial' ? rng.int(0, 2) : rng.int(0, 1);
@@ -184,7 +184,7 @@ function generateSessions(count: number): SessionRecord[] {
184
184
  agent: rng.pick(AGENTS),
185
185
  model: rng.pick(MODELS),
186
186
  task: `${issue}: ${rng.pick(TASK_DESCRIPTIONS)}`,
187
- linear_issue: issue,
187
+ tracker_issue: issue,
188
188
  outcome,
189
189
  duration_min: rng.int(5, 45),
190
190
  files_changed: rng.int(1, 15),
@@ -205,7 +205,7 @@ interface DelegationRecord {
205
205
  model: string;
206
206
  tier: string;
207
207
  mechanism: string;
208
- linear_issue: string;
208
+ tracker_issue: string;
209
209
  outcome: string;
210
210
  retries: number;
211
211
  phase: number;
@@ -215,7 +215,7 @@ interface DelegationRecord {
215
215
  function generateDelegations(count: number): DelegationRecord[] {
216
216
  const records: DelegationRecord[] = [];
217
217
  for (let i = 0; i < count; i++) {
218
- const issue = rng.pick(LINEAR_ISSUES);
218
+ const issue = rng.pick(TRACKER_ISSUES);
219
219
  const outcomeRoll = rng.next();
220
220
  const outcome = outcomeRoll < 0.75 ? 'success' : outcomeRoll < 0.9 ? 'partial' : 'failed';
221
221
 
@@ -226,7 +226,7 @@ function generateDelegations(count: number): DelegationRecord[] {
226
226
  model: rng.pick(MODELS),
227
227
  tier: rng.weighted(TIERS),
228
228
  mechanism: rng.next() < 0.6 ? 'sub-agent' : 'background',
229
- linear_issue: issue,
229
+ tracker_issue: issue,
230
230
  outcome,
231
231
  retries: outcome === 'failed' ? rng.int(1, 2) : rng.int(0, 1),
232
232
  phase: rng.int(1, 4),
@@ -249,7 +249,7 @@ interface PanelRecord {
249
249
  reviewer_model: string;
250
250
  weighted: boolean;
251
251
  attempt: number;
252
- linear_issue: string;
252
+ tracker_issue: string;
253
253
  artifacts_count: number;
254
254
  report_path: string;
255
255
  }
@@ -261,7 +261,7 @@ function generatePanels(count: number): PanelRecord[] {
261
261
  const isPass = rng.next() < 0.75;
262
262
  const passCount = isPass ? rng.int(2, 3) : rng.int(0, 1);
263
263
  const blockCount = 3 - passCount;
264
- const issue = rng.pick(LINEAR_ISSUES);
264
+ const issue = rng.pick(TRACKER_ISSUES);
265
265
 
266
266
  records.push({
267
267
  timestamp: generateTimestamp(i, count, START_DATE, END_DATE),
@@ -274,7 +274,7 @@ function generatePanels(count: number): PanelRecord[] {
274
274
  reviewer_model: rng.pick(MODELS),
275
275
  weighted: rng.next() > 0.7,
276
276
  attempt: isPass ? 1 : rng.int(1, 3),
277
- linear_issue: issue,
277
+ tracker_issue: issue,
278
278
  artifacts_count: rng.int(3, 20),
279
279
  report_path: `docs/ai-agents/panel/${panelKey}.md`,
280
280
  });
@@ -1,35 +1,35 @@
1
- {"timestamp":"2026-02-20T08:00:00.000Z","session_id":"feat/tas-43","agent":"DevOps Expert","model":"gpt-5-mini","tier":"standard","mechanism":"sub-agent","linear_issue":"TAS-43","outcome":"success","retries":1,"phase":1,"file_partition":["libs/queries/","libs/server-utils/"]}
2
- {"timestamp":"2026-02-20T11:38:52.677Z","session_id":"feat/tas-31","agent":"Architect","model":"gpt-5.3-codex","tier":"economy","mechanism":"sub-agent","linear_issue":"TAS-31","outcome":"success","retries":0,"phase":2,"file_partition":["libs/data-pipeline/"]}
3
- {"timestamp":"2026-02-20T15:37:40.293Z","session_id":"feat/tas-59","agent":"Documentation Writer","model":"gemini-3.1-pro","tier":"standard","mechanism":"background","linear_issue":"TAS-59","outcome":"success","retries":0,"phase":2,"file_partition":["libs/data-pipeline/"]}
4
- {"timestamp":"2026-02-20T19:36:10.946Z","session_id":"feat/tas-49","agent":"Data Expert","model":"gemini-3.1-pro","tier":"utility","mechanism":"sub-agent","linear_issue":"TAS-49","outcome":"partial","retries":0,"phase":3,"file_partition":["libs/queries/","libs/server-utils/"]}
5
- {"timestamp":"2026-02-20T23:09:18.799Z","session_id":"feat/tas-49","agent":"Supabase DB Expert","model":"gpt-5-mini","tier":"utility","mechanism":"background","linear_issue":"TAS-49","outcome":"failed","retries":1,"phase":3,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
6
- {"timestamp":"2026-02-21T02:23:04.138Z","session_id":"feat/tas-32","agent":"Security Expert","model":"gpt-5-mini","tier":"utility","mechanism":"sub-agent","linear_issue":"TAS-32","outcome":"success","retries":0,"phase":1,"file_partition":["apps/tastebeer.eu/app/","apps/tastecoffee.eu/app/"]}
7
- {"timestamp":"2026-02-21T05:52:23.451Z","session_id":"feat/tas-39","agent":"Next.js Developer","model":"gpt-5.3-codex","tier":"utility","mechanism":"sub-agent","linear_issue":"TAS-39","outcome":"success","retries":0,"phase":4,"file_partition":["apps/cms-studio/"]}
8
- {"timestamp":"2026-02-21T10:29:16.394Z","session_id":"feat/tas-41","agent":"Testing Expert","model":"claude-opus-4-6","tier":"utility","mechanism":"background","linear_issue":"TAS-41","outcome":"success","retries":1,"phase":2,"file_partition":["libs/data-pipeline/","libs/queries/"]}
9
- {"timestamp":"2026-02-21T14:00:03.752Z","session_id":"feat/tas-50","agent":"Next.js Developer","model":"gpt-5.3-codex","tier":"utility","mechanism":"sub-agent","linear_issue":"TAS-50","outcome":"success","retries":0,"phase":1,"file_partition":["libs/supabase-auth/"]}
10
- {"timestamp":"2026-02-21T17:10:13.592Z","session_id":"feat/tas-41","agent":"UI/UX Expert","model":"gpt-5.3-codex","tier":"premium","mechanism":"sub-agent","linear_issue":"TAS-41","outcome":"success","retries":1,"phase":1,"file_partition":["apps/tastecoffee.eu/app/"]}
11
- {"timestamp":"2026-02-21T21:26:17.711Z","session_id":"feat/tas-58","agent":"Sanity Expert","model":"gpt-5-mini","tier":"utility","mechanism":"background","linear_issue":"TAS-58","outcome":"success","retries":1,"phase":1,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
12
- {"timestamp":"2026-02-22T00:51:23.821Z","session_id":"feat/tas-33","agent":"DevOps Expert","model":"gpt-5-mini","tier":"utility","mechanism":"background","linear_issue":"TAS-33","outcome":"failed","retries":2,"phase":1,"file_partition":["apps/tastebeer.eu/app/","apps/tastecoffee.eu/app/"]}
13
- {"timestamp":"2026-02-22T04:53:39.261Z","session_id":"feat/tas-35","agent":"Documentation Writer","model":"gpt-5.3-codex","tier":"utility","mechanism":"background","linear_issue":"TAS-35","outcome":"success","retries":1,"phase":1,"file_partition":["libs/server-utils/"]}
14
- {"timestamp":"2026-02-22T08:20:53.525Z","session_id":"feat/tas-59","agent":"DevOps Expert","model":"claude-opus-4-6","tier":"standard","mechanism":"sub-agent","linear_issue":"TAS-59","outcome":"success","retries":0,"phase":4,"file_partition":["libs/queries/"]}
15
- {"timestamp":"2026-02-22T11:43:14.243Z","session_id":"feat/tas-36","agent":"Next.js Developer","model":"gpt-5.3-codex","tier":"economy","mechanism":"sub-agent","linear_issue":"TAS-36","outcome":"success","retries":0,"phase":1,"file_partition":["libs/server-utils/"]}
16
- {"timestamp":"2026-02-22T15:29:36.510Z","session_id":"feat/tas-54","agent":"Supabase DB Expert","model":"gpt-5.3-codex","tier":"standard","mechanism":"background","linear_issue":"TAS-54","outcome":"success","retries":0,"phase":4,"file_partition":["apps/cms-studio/"]}
17
- {"timestamp":"2026-02-22T19:18:04.518Z","session_id":"feat/tas-41","agent":"DevOps Expert","model":"gemini-3.1-pro","tier":"utility","mechanism":"background","linear_issue":"TAS-41","outcome":"success","retries":1,"phase":3,"file_partition":["libs/server-utils/"]}
18
- {"timestamp":"2026-02-22T23:18:07.164Z","session_id":"feat/tas-44","agent":"Next.js Developer","model":"claude-opus-4-6","tier":"premium","mechanism":"sub-agent","linear_issue":"TAS-44","outcome":"success","retries":1,"phase":2,"file_partition":["libs/server-utils/"]}
19
- {"timestamp":"2026-02-23T02:34:46.644Z","session_id":"feat/tas-30","agent":"Sanity Expert","model":"gemini-3.1-pro","tier":"utility","mechanism":"sub-agent","linear_issue":"TAS-30","outcome":"failed","retries":2,"phase":4,"file_partition":["apps/tastebeer.eu/app/","apps/tastecoffee.eu/app/"]}
20
- {"timestamp":"2026-02-23T06:21:11.926Z","session_id":"feat/tas-45","agent":"Performance Expert","model":"gpt-5-mini","tier":"utility","mechanism":"sub-agent","linear_issue":"TAS-45","outcome":"success","retries":1,"phase":4,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
21
- {"timestamp":"2026-02-23T09:50:56.855Z","session_id":"feat/tas-50","agent":"Data Expert","model":"gemini-3.1-pro","tier":"standard","mechanism":"background","linear_issue":"TAS-50","outcome":"success","retries":1,"phase":2,"file_partition":["libs/supabase-auth/"]}
22
- {"timestamp":"2026-02-23T14:28:33.926Z","session_id":"feat/tas-55","agent":"UI/UX Expert","model":"gpt-5-mini","tier":"economy","mechanism":"background","linear_issue":"TAS-55","outcome":"success","retries":1,"phase":3,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
23
- {"timestamp":"2026-02-23T17:21:16.023Z","session_id":"feat/tas-34","agent":"Data Expert","model":"claude-opus-4-6","tier":"utility","mechanism":"sub-agent","linear_issue":"TAS-34","outcome":"partial","retries":1,"phase":4,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
24
- {"timestamp":"2026-02-23T21:23:59.785Z","session_id":"feat/tas-54","agent":"Supabase DB Expert","model":"claude-opus-4-6","tier":"standard","mechanism":"background","linear_issue":"TAS-54","outcome":"success","retries":0,"phase":1,"file_partition":["apps/tastebeer.eu/app/"]}
25
- {"timestamp":"2026-02-24T01:37:32.832Z","session_id":"feat/tas-45","agent":"UI/UX Expert","model":"gemini-3.1-pro","tier":"economy","mechanism":"background","linear_issue":"TAS-45","outcome":"success","retries":1,"phase":1,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
26
- {"timestamp":"2026-02-24T04:36:24.219Z","session_id":"feat/tas-32","agent":"Data Expert","model":"gpt-5.3-codex","tier":"utility","mechanism":"sub-agent","linear_issue":"TAS-32","outcome":"success","retries":1,"phase":4,"file_partition":["libs/data-pipeline/","libs/queries/"]}
27
- {"timestamp":"2026-02-24T08:15:17.039Z","session_id":"feat/tas-49","agent":"Data Expert","model":"gpt-5.3-codex","tier":"premium","mechanism":"sub-agent","linear_issue":"TAS-49","outcome":"success","retries":1,"phase":3,"file_partition":["libs/data-pipeline/"]}
28
- {"timestamp":"2026-02-24T12:28:28.251Z","session_id":"feat/tas-31","agent":"DevOps Expert","model":"claude-opus-4-6","tier":"premium","mechanism":"background","linear_issue":"TAS-31","outcome":"partial","retries":0,"phase":4,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
29
- {"timestamp":"2026-02-24T16:03:58.674Z","session_id":"feat/tas-51","agent":"Data Expert","model":"gpt-5-mini","tier":"standard","mechanism":"sub-agent","linear_issue":"TAS-51","outcome":"success","retries":0,"phase":2,"file_partition":["libs/queries/"]}
30
- {"timestamp":"2026-02-24T19:36:47.295Z","session_id":"feat/tas-45","agent":"Security Expert","model":"gpt-5.3-codex","tier":"premium","mechanism":"sub-agent","linear_issue":"TAS-45","outcome":"success","retries":0,"phase":1,"file_partition":["apps/tastecoffee.eu/app/"]}
31
- {"timestamp":"2026-02-24T23:22:20.331Z","session_id":"feat/tas-54","agent":"Documentation Writer","model":"gpt-5-mini","tier":"utility","mechanism":"sub-agent","linear_issue":"TAS-54","outcome":"success","retries":0,"phase":1,"file_partition":["apps/tastebeer.eu/app/","apps/tastecoffee.eu/app/"]}
32
- {"timestamp":"2026-02-25T03:04:08.793Z","session_id":"feat/tas-42","agent":"Next.js Developer","model":"gpt-5-mini","tier":"premium","mechanism":"sub-agent","linear_issue":"TAS-42","outcome":"success","retries":1,"phase":4,"file_partition":["apps/cms-studio/"]}
33
- {"timestamp":"2026-02-25T06:35:46.724Z","session_id":"feat/tas-38","agent":"DevOps Expert","model":"gpt-5.3-codex","tier":"utility","mechanism":"sub-agent","linear_issue":"TAS-38","outcome":"success","retries":1,"phase":4,"file_partition":["libs/server-utils/"]}
34
- {"timestamp":"2026-02-25T10:39:46.727Z","session_id":"feat/tas-38","agent":"Sanity Expert","model":"gemini-3.1-pro","tier":"standard","mechanism":"sub-agent","linear_issue":"TAS-38","outcome":"success","retries":0,"phase":3,"file_partition":["libs/ui-kit/"]}
35
- {"timestamp":"2026-02-25T14:30:07.967Z","session_id":"feat/tas-46","agent":"Sanity Expert","model":"gemini-3.1-pro","tier":"utility","mechanism":"sub-agent","linear_issue":"TAS-46","outcome":"success","retries":1,"phase":4,"file_partition":["apps/tastebeer.eu/app/","apps/tastecoffee.eu/app/"]}
1
+ {"timestamp":"2026-02-20T08:00:00.000Z","session_id":"feat/tas-43","agent":"DevOps Expert","model":"gpt-5-mini","tier":"standard","mechanism":"sub-agent","tracker_issue":"TAS-43","outcome":"success","retries":1,"phase":1,"file_partition":["libs/queries/","libs/server-utils/"]}
2
+ {"timestamp":"2026-02-20T11:38:52.677Z","session_id":"feat/tas-31","agent":"Architect","model":"gpt-5.3-codex","tier":"economy","mechanism":"sub-agent","tracker_issue":"TAS-31","outcome":"success","retries":0,"phase":2,"file_partition":["libs/data-pipeline/"]}
3
+ {"timestamp":"2026-02-20T15:37:40.293Z","session_id":"feat/tas-59","agent":"Documentation Writer","model":"gemini-3.1-pro","tier":"standard","mechanism":"background","tracker_issue":"TAS-59","outcome":"success","retries":0,"phase":2,"file_partition":["libs/data-pipeline/"]}
4
+ {"timestamp":"2026-02-20T19:36:10.946Z","session_id":"feat/tas-49","agent":"Data Expert","model":"gemini-3.1-pro","tier":"utility","mechanism":"sub-agent","tracker_issue":"TAS-49","outcome":"partial","retries":0,"phase":3,"file_partition":["libs/queries/","libs/server-utils/"]}
5
+ {"timestamp":"2026-02-20T23:09:18.799Z","session_id":"feat/tas-49","agent":"Supabase DB Expert","model":"gpt-5-mini","tier":"utility","mechanism":"background","tracker_issue":"TAS-49","outcome":"failed","retries":1,"phase":3,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
6
+ {"timestamp":"2026-02-21T02:23:04.138Z","session_id":"feat/tas-32","agent":"Security Expert","model":"gpt-5-mini","tier":"utility","mechanism":"sub-agent","tracker_issue":"TAS-32","outcome":"success","retries":0,"phase":1,"file_partition":["apps/tastebeer.eu/app/","apps/tastecoffee.eu/app/"]}
7
+ {"timestamp":"2026-02-21T05:52:23.451Z","session_id":"feat/tas-39","agent":"Next.js Developer","model":"gpt-5.3-codex","tier":"utility","mechanism":"sub-agent","tracker_issue":"TAS-39","outcome":"success","retries":0,"phase":4,"file_partition":["apps/cms-studio/"]}
8
+ {"timestamp":"2026-02-21T10:29:16.394Z","session_id":"feat/tas-41","agent":"Testing Expert","model":"claude-opus-4-6","tier":"utility","mechanism":"background","tracker_issue":"TAS-41","outcome":"success","retries":1,"phase":2,"file_partition":["libs/data-pipeline/","libs/queries/"]}
9
+ {"timestamp":"2026-02-21T14:00:03.752Z","session_id":"feat/tas-50","agent":"Next.js Developer","model":"gpt-5.3-codex","tier":"utility","mechanism":"sub-agent","tracker_issue":"TAS-50","outcome":"success","retries":0,"phase":1,"file_partition":["libs/supabase-auth/"]}
10
+ {"timestamp":"2026-02-21T17:10:13.592Z","session_id":"feat/tas-41","agent":"UI/UX Expert","model":"gpt-5.3-codex","tier":"premium","mechanism":"sub-agent","tracker_issue":"TAS-41","outcome":"success","retries":1,"phase":1,"file_partition":["apps/tastecoffee.eu/app/"]}
11
+ {"timestamp":"2026-02-21T21:26:17.711Z","session_id":"feat/tas-58","agent":"Sanity Expert","model":"gpt-5-mini","tier":"utility","mechanism":"background","tracker_issue":"TAS-58","outcome":"success","retries":1,"phase":1,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
12
+ {"timestamp":"2026-02-22T00:51:23.821Z","session_id":"feat/tas-33","agent":"DevOps Expert","model":"gpt-5-mini","tier":"utility","mechanism":"background","tracker_issue":"TAS-33","outcome":"failed","retries":2,"phase":1,"file_partition":["apps/tastebeer.eu/app/","apps/tastecoffee.eu/app/"]}
13
+ {"timestamp":"2026-02-22T04:53:39.261Z","session_id":"feat/tas-35","agent":"Documentation Writer","model":"gpt-5.3-codex","tier":"utility","mechanism":"background","tracker_issue":"TAS-35","outcome":"success","retries":1,"phase":1,"file_partition":["libs/server-utils/"]}
14
+ {"timestamp":"2026-02-22T08:20:53.525Z","session_id":"feat/tas-59","agent":"DevOps Expert","model":"claude-opus-4-6","tier":"standard","mechanism":"sub-agent","tracker_issue":"TAS-59","outcome":"success","retries":0,"phase":4,"file_partition":["libs/queries/"]}
15
+ {"timestamp":"2026-02-22T11:43:14.243Z","session_id":"feat/tas-36","agent":"Next.js Developer","model":"gpt-5.3-codex","tier":"economy","mechanism":"sub-agent","tracker_issue":"TAS-36","outcome":"success","retries":0,"phase":1,"file_partition":["libs/server-utils/"]}
16
+ {"timestamp":"2026-02-22T15:29:36.510Z","session_id":"feat/tas-54","agent":"Supabase DB Expert","model":"gpt-5.3-codex","tier":"standard","mechanism":"background","tracker_issue":"TAS-54","outcome":"success","retries":0,"phase":4,"file_partition":["apps/cms-studio/"]}
17
+ {"timestamp":"2026-02-22T19:18:04.518Z","session_id":"feat/tas-41","agent":"DevOps Expert","model":"gemini-3.1-pro","tier":"utility","mechanism":"background","tracker_issue":"TAS-41","outcome":"success","retries":1,"phase":3,"file_partition":["libs/server-utils/"]}
18
+ {"timestamp":"2026-02-22T23:18:07.164Z","session_id":"feat/tas-44","agent":"Next.js Developer","model":"claude-opus-4-6","tier":"premium","mechanism":"sub-agent","tracker_issue":"TAS-44","outcome":"success","retries":1,"phase":2,"file_partition":["libs/server-utils/"]}
19
+ {"timestamp":"2026-02-23T02:34:46.644Z","session_id":"feat/tas-30","agent":"Sanity Expert","model":"gemini-3.1-pro","tier":"utility","mechanism":"sub-agent","tracker_issue":"TAS-30","outcome":"failed","retries":2,"phase":4,"file_partition":["apps/tastebeer.eu/app/","apps/tastecoffee.eu/app/"]}
20
+ {"timestamp":"2026-02-23T06:21:11.926Z","session_id":"feat/tas-45","agent":"Performance Expert","model":"gpt-5-mini","tier":"utility","mechanism":"sub-agent","tracker_issue":"TAS-45","outcome":"success","retries":1,"phase":4,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
21
+ {"timestamp":"2026-02-23T09:50:56.855Z","session_id":"feat/tas-50","agent":"Data Expert","model":"gemini-3.1-pro","tier":"standard","mechanism":"background","tracker_issue":"TAS-50","outcome":"success","retries":1,"phase":2,"file_partition":["libs/supabase-auth/"]}
22
+ {"timestamp":"2026-02-23T14:28:33.926Z","session_id":"feat/tas-55","agent":"UI/UX Expert","model":"gpt-5-mini","tier":"economy","mechanism":"background","tracker_issue":"TAS-55","outcome":"success","retries":1,"phase":3,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
23
+ {"timestamp":"2026-02-23T17:21:16.023Z","session_id":"feat/tas-34","agent":"Data Expert","model":"claude-opus-4-6","tier":"utility","mechanism":"sub-agent","tracker_issue":"TAS-34","outcome":"partial","retries":1,"phase":4,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
24
+ {"timestamp":"2026-02-23T21:23:59.785Z","session_id":"feat/tas-54","agent":"Supabase DB Expert","model":"claude-opus-4-6","tier":"standard","mechanism":"background","tracker_issue":"TAS-54","outcome":"success","retries":0,"phase":1,"file_partition":["apps/tastebeer.eu/app/"]}
25
+ {"timestamp":"2026-02-24T01:37:32.832Z","session_id":"feat/tas-45","agent":"UI/UX Expert","model":"gemini-3.1-pro","tier":"economy","mechanism":"background","tracker_issue":"TAS-45","outcome":"success","retries":1,"phase":1,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
26
+ {"timestamp":"2026-02-24T04:36:24.219Z","session_id":"feat/tas-32","agent":"Data Expert","model":"gpt-5.3-codex","tier":"utility","mechanism":"sub-agent","tracker_issue":"TAS-32","outcome":"success","retries":1,"phase":4,"file_partition":["libs/data-pipeline/","libs/queries/"]}
27
+ {"timestamp":"2026-02-24T08:15:17.039Z","session_id":"feat/tas-49","agent":"Data Expert","model":"gpt-5.3-codex","tier":"premium","mechanism":"sub-agent","tracker_issue":"TAS-49","outcome":"success","retries":1,"phase":3,"file_partition":["libs/data-pipeline/"]}
28
+ {"timestamp":"2026-02-24T12:28:28.251Z","session_id":"feat/tas-31","agent":"DevOps Expert","model":"claude-opus-4-6","tier":"premium","mechanism":"background","tracker_issue":"TAS-31","outcome":"partial","retries":0,"phase":4,"file_partition":["libs/ui-kit/","apps/tastebeer.eu/app/"]}
29
+ {"timestamp":"2026-02-24T16:03:58.674Z","session_id":"feat/tas-51","agent":"Data Expert","model":"gpt-5-mini","tier":"standard","mechanism":"sub-agent","tracker_issue":"TAS-51","outcome":"success","retries":0,"phase":2,"file_partition":["libs/queries/"]}
30
+ {"timestamp":"2026-02-24T19:36:47.295Z","session_id":"feat/tas-45","agent":"Security Expert","model":"gpt-5.3-codex","tier":"premium","mechanism":"sub-agent","tracker_issue":"TAS-45","outcome":"success","retries":0,"phase":1,"file_partition":["apps/tastecoffee.eu/app/"]}
31
+ {"timestamp":"2026-02-24T23:22:20.331Z","session_id":"feat/tas-54","agent":"Documentation Writer","model":"gpt-5-mini","tier":"utility","mechanism":"sub-agent","tracker_issue":"TAS-54","outcome":"success","retries":0,"phase":1,"file_partition":["apps/tastebeer.eu/app/","apps/tastecoffee.eu/app/"]}
32
+ {"timestamp":"2026-02-25T03:04:08.793Z","session_id":"feat/tas-42","agent":"Next.js Developer","model":"gpt-5-mini","tier":"premium","mechanism":"sub-agent","tracker_issue":"TAS-42","outcome":"success","retries":1,"phase":4,"file_partition":["apps/cms-studio/"]}
33
+ {"timestamp":"2026-02-25T06:35:46.724Z","session_id":"feat/tas-38","agent":"DevOps Expert","model":"gpt-5.3-codex","tier":"utility","mechanism":"sub-agent","tracker_issue":"TAS-38","outcome":"success","retries":1,"phase":4,"file_partition":["libs/server-utils/"]}
34
+ {"timestamp":"2026-02-25T10:39:46.727Z","session_id":"feat/tas-38","agent":"Sanity Expert","model":"gemini-3.1-pro","tier":"standard","mechanism":"sub-agent","tracker_issue":"TAS-38","outcome":"success","retries":0,"phase":3,"file_partition":["libs/ui-kit/"]}
35
+ {"timestamp":"2026-02-25T14:30:07.967Z","session_id":"feat/tas-46","agent":"Sanity Expert","model":"gemini-3.1-pro","tier":"utility","mechanism":"sub-agent","tracker_issue":"TAS-46","outcome":"success","retries":1,"phase":4,"file_partition":["apps/tastebeer.eu/app/","apps/tastecoffee.eu/app/"]}