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.
- package/README.md +1 -1
- package/dist/cli/detect.d.ts +6 -0
- package/dist/cli/detect.d.ts.map +1 -1
- package/dist/cli/detect.js +133 -0
- package/dist/cli/detect.js.map +1 -1
- package/dist/cli/detect.test.js +119 -1
- package/dist/cli/detect.test.js.map +1 -1
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +32 -8
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/init.test.js +44 -1
- package/dist/cli/init.test.js.map +1 -1
- package/dist/cli/prompt.d.ts +8 -0
- package/dist/cli/prompt.d.ts.map +1 -1
- package/dist/cli/prompt.js +89 -20
- package/dist/cli/prompt.js.map +1 -1
- package/dist/cli/prompt.test.d.ts +2 -0
- package/dist/cli/prompt.test.d.ts.map +1 -0
- package/dist/cli/prompt.test.js +58 -0
- package/dist/cli/prompt.test.js.map +1 -0
- package/dist/cli/types.d.ts +1 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +2 -8
- package/dist/cli/update.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/detect.test.ts +133 -1
- package/src/cli/detect.ts +144 -0
- package/src/cli/init.test.ts +53 -1
- package/src/cli/init.ts +32 -8
- package/src/cli/prompt.test.ts +66 -0
- package/src/cli/prompt.ts +108 -22
- package/src/cli/types.ts +1 -1
- package/src/cli/update.ts +2 -8
- package/src/dashboard/dist/index.html +2 -2
- package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
- package/src/dashboard/package-lock.json +6 -0
- package/src/dashboard/scripts/generate-seed-data.ts +10 -10
- package/src/dashboard/seed-data/delegations.ndjson +35 -35
- package/src/dashboard/seed-data/panels.ndjson +12 -12
- package/src/dashboard/seed-data/reviews.ndjson +6 -6
- package/src/dashboard/seed-data/sessions.ndjson +50 -50
- package/src/dashboard/src/pages/index.astro +2 -2
- package/src/orchestrator/agents/api-designer.agent.md +1 -0
- package/src/orchestrator/agents/architect.agent.md +2 -1
- package/src/orchestrator/agents/content-engineer.agent.md +1 -0
- package/src/orchestrator/agents/copywriter.agent.md +1 -0
- package/src/orchestrator/agents/data-expert.agent.md +1 -0
- package/src/orchestrator/agents/database-engineer.agent.md +1 -0
- package/src/orchestrator/agents/developer.agent.md +2 -1
- package/src/orchestrator/agents/devops-expert.agent.md +1 -0
- package/src/orchestrator/agents/documentation-writer.agent.md +1 -0
- package/src/orchestrator/agents/performance-expert.agent.md +1 -0
- package/src/orchestrator/agents/release-manager.agent.md +1 -0
- package/src/orchestrator/agents/researcher.agent.md +3 -2
- package/src/orchestrator/agents/reviewer.agent.md +1 -0
- package/src/orchestrator/agents/security-expert.agent.md +2 -1
- package/src/orchestrator/agents/seo-specialist.agent.md +1 -0
- package/src/orchestrator/agents/session-guard.agent.md +3 -2
- package/src/orchestrator/agents/team-lead.agent.md +31 -17
- package/src/orchestrator/agents/testing-expert.agent.md +1 -0
- package/src/orchestrator/agents/ui-ux-expert.agent.md +2 -1
- package/src/orchestrator/customizations/agents/agent-registry.md +9 -9
- package/src/orchestrator/customizations/logs/README.md +11 -11
- package/src/orchestrator/customizations/logs/disputes.ndjson +0 -0
- package/src/orchestrator/customizations/logs/reviews.ndjson +0 -0
- package/src/orchestrator/instructions/general.instructions.md +28 -14
- package/src/orchestrator/skills/agent-hooks/SKILL.md +6 -26
- package/src/orchestrator/skills/fast-review/SKILL.md +2 -1
- package/src/orchestrator/skills/orchestration-protocols/SKILL.md +34 -0
- package/src/orchestrator/skills/panel-majority-vote/SKILL.md +3 -3
- package/src/orchestrator/skills/self-improvement/SKILL.md +1 -30
- package/src/orchestrator/skills/session-checkpoints/SKILL.md +0 -86
- 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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (
|
|
121
|
-
stdout.write(moveUp(
|
|
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 =
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
174
|
-
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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 =
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
352
|
-
|
|
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 =
|
|
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.
|
|
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.
|
|
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": "
|
|
2
|
+
"hash": "96d8fe83",
|
|
3
3
|
"configHash": "30f8ea04",
|
|
4
|
-
"lockfileHash": "
|
|
5
|
-
"browserHash": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
22
|
+
"fileHash": "6e84e164",
|
|
23
23
|
"needsInterop": true
|
|
24
24
|
}
|
|
25
25
|
},
|
|
@@ -43,7 +43,7 @@ const TIERS: Array<{ name: string; weight: number }> = [
|
|
|
43
43
|
|
|
44
44
|
const _MECHANISMS = ['sub-agent', 'background'];
|
|
45
45
|
|
|
46
|
-
const
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
11
|
-
{"timestamp":"2026-02-21T21:26:17.711Z","session_id":"feat/tas-58","agent":"Sanity Expert","model":"gpt-5-mini","tier":"utility","mechanism":"background","
|
|
12
|
-
{"timestamp":"2026-02-22T00:51:23.821Z","session_id":"feat/tas-33","agent":"DevOps Expert","model":"gpt-5-mini","tier":"utility","mechanism":"background","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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","
|
|
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/"]}
|