Run the ticket skills through T3 Code, with a review council before pre-mr-review
Agents now start pre-mr-review on the work account themselves, through a Klaude delegate, and continue from its verdict. A council of models on my own accounts replaces the single reviewer before it, and adding a seat is one table row. Proof comes from T3's browser, with mp4 recordings, and capture-proof stays as the fallback. Ticket pages carry their own data, so index.html renders alone in T3's file viewer, and worktree threads share the main checkout's docs. A PreToolUse hook sends subagents in T3 threads to delegate_task. Blocker, proof, review and MR summary rules come from ideas in t3dotgg/tstack.
This commit is contained in:
1 parent
968e0a1045
commit
86f6e391b7
14 files changed
+410
-187
No files matched your search
@@ -1,8 +1,9 @@
|
||||
// Renderer for ticket and epic pages. ticket-page inlines it into every page shell, so a
|
||||
// page needs nothing outside its own folder (T3 Code's file viewer allows nothing else).
|
||||
// A page shell names its data file in <body data-src>. This script loads that file with a
|
||||
// <script> tag (file:// pages cannot fetch), re-loads it every two seconds, and redraws
|
||||
// only when the data changed. The data shape is defined in scripts/ticket-data.ts.
|
||||
// Renderer for ticket and epic pages. ticket-page inlines it and the page's data into every
|
||||
// page shell, so index.html renders on its own with no server and no other file.
|
||||
// A page shell also names its data file in <body data-src>. Re-loading that file every two
|
||||
// seconds with a <script> tag (file:// and T3 Code's sandboxed viewer cannot fetch) is what
|
||||
// keeps an open page live, and a page that cannot reach it still shows its last write.
|
||||
// The data shape is defined in scripts/ticket-data.ts.
|
||||
// @ts-check
|
||||
/** @typedef {import('../../scripts/ticket-data').Ticket} Ticket */
|
||||
/** @typedef {import('../../scripts/ticket-data').Epic} Epic */
|
||||
@@ -40,12 +41,14 @@
|
||||
const mark = st => h('span.mark' + (st === 'done' ? '.done' : st === 'running' ? '.run' : ''), { title: st });
|
||||
const pill = (text, tone) => h('span.pill' + (tone ? '.' + tone : ''), text);
|
||||
|
||||
// T3 Code's sandboxed viewer has no localStorage, so ticks there last while the page stays open.
|
||||
const ticks = new Map();
|
||||
/** The viewer's own review tick, kept in this browser only and separate from the agent's done mark. */
|
||||
function seen(scope, id) {
|
||||
const key = `seen:${scope}:${id}`;
|
||||
let on = false; try { on = localStorage.getItem(key) === '1'; } catch {}
|
||||
let on = ticks.get(key) ?? false; try { on ||= localStorage.getItem(key) === '1'; } catch {}
|
||||
return h('label.seen', { title: 'Your own review tick, stored in this browser' },
|
||||
h('input', { type: 'checkbox', checked: on || null, onchange: e => { try { localStorage.setItem(key, e.target.checked ? '1' : '0'); } catch {} } }), 'reviewed');
|
||||
h('input', { type: 'checkbox', checked: on || null, onchange: e => { ticks.set(key, e.target.checked); try { localStorage.setItem(key, e.target.checked ? '1' : '0'); } catch {} } }), 'reviewed');
|
||||
}
|
||||
|
||||
// ── Loading and live reload ──────────────────────────────────────────────
|
||||
@@ -66,7 +69,7 @@
|
||||
const el = document.querySelector('.live');
|
||||
if (!el) return;
|
||||
el.classList.toggle('stale', failed);
|
||||
el.textContent = failed ? 'Live: last reload failed, showing the previous version' : `Live, checked ${clock(new Date(loadedAt).toISOString())}`;
|
||||
el.textContent = failed ? 'Snapshot from the last write' : `Live, checked ${clock(new Date(loadedAt).toISOString())}`;
|
||||
}
|
||||
|
||||
function draw() {
|
||||
@@ -151,7 +154,8 @@
|
||||
/** @param {Ticket} t @param {import('../../scripts/ticket-data').Proof} p */
|
||||
function compare(t, p) {
|
||||
const m = p.mock && t.plan?.mocks.find(x => x.id === p.mock);
|
||||
const evidence = p.kind === 'text' ? h('pre.textproof', p.text || '') : p.kind === 'test' ? h('pre.textproof', 'Passing test: ' + p.test) : h('a', { href: p.file, target: '_blank' }, h('img.shot', { src: p.file, alt: p.file }));
|
||||
const evidence = p.kind === 'text' ? h('pre.textproof', p.text || '') : p.kind === 'test' ? h('pre.textproof', 'Passing test: ' + p.test)
|
||||
: p.kind === 'video' ? keep('video:' + p.file, () => h('video.shot', { src: p.file, controls: true, preload: 'metadata' })) : h('a', { href: p.file, target: '_blank' }, h('img.shot', { src: p.file, alt: p.file }));
|
||||
return h('div.compare',
|
||||
h('figure', h('figcaption', 'Mock, drawn at plan time'), m ? artboard(m) : h('div.placeholder', 'No mock for this one.')),
|
||||
h('figure', h('figcaption', 'Proof, captured from the build'), evidence));
|
||||
@@ -304,6 +308,7 @@
|
||||
e.closed.length ? h('p.muted', { style: 'margin-top:18px;font-size:.9em' }, 'Closed: ', e.closed.map(c => `${c.key} ${c.title}`).join(', '), '.') : null));
|
||||
}
|
||||
|
||||
if (window[GLOBAL]) { last = JSON.stringify(window[GLOBAL]); loadedAt = Date.now(); draw(); }
|
||||
load();
|
||||
setInterval(load, 2000);
|
||||
})();
|
||||
Reference in new issue
Block a user