@specship/specship-win32-arm64 0.11.9 → 0.12.1
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/lib/dist/bin/specship.js +9 -60
- package/lib/dist/bin/specship.js.map +1 -1
- package/lib/dist/db/spec-queries.d.ts +6 -0
- package/lib/dist/db/spec-queries.d.ts.map +1 -1
- package/lib/dist/db/spec-queries.js +8 -0
- package/lib/dist/db/spec-queries.js.map +1 -1
- package/lib/dist/index.d.ts +8 -0
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +9 -0
- package/lib/dist/index.js.map +1 -1
- package/lib/dist/reflect/index.d.ts +1 -1
- package/lib/dist/reflect/index.d.ts.map +1 -1
- package/lib/dist/reflect/index.js +2 -1
- package/lib/dist/reflect/index.js.map +1 -1
- package/lib/dist/reflect/miner.d.ts +8 -0
- package/lib/dist/reflect/miner.d.ts.map +1 -1
- package/lib/dist/reflect/miner.js +64 -36
- package/lib/dist/reflect/miner.js.map +1 -1
- package/lib/dist/server/cli.js +5 -49
- package/lib/dist/server/routes/claude.js +13 -5
- package/lib/dist/server/routes/workflow.js +16 -2
- package/lib/dist/server/server.js +17 -2
- package/lib/dist/server/ssr/md.mjs +83 -0
- package/lib/dist/server/ssr/render.mjs +596 -0
- package/lib/dist/server/ssr/routes.js +73 -0
- package/lib/dist/server/static-handler.js +30 -0
- package/lib/dist/statusline/active-run.d.ts +2 -2
- package/lib/dist/statusline/active-run.d.ts.map +1 -1
- package/lib/dist/statusline/active-run.js +2 -2
- package/lib/dist/statusline/active-run.js.map +1 -1
- package/lib/dist/statusline/render.d.ts.map +1 -1
- package/lib/dist/statusline/render.js +41 -5
- package/lib/dist/statusline/render.js.map +1 -1
- package/lib/dist/statusline/types.d.ts +15 -0
- package/lib/dist/statusline/types.d.ts.map +1 -1
- package/lib/dist/workflows/eta.d.ts +42 -0
- package/lib/dist/workflows/eta.d.ts.map +1 -0
- package/lib/dist/workflows/eta.js +146 -0
- package/lib/dist/workflows/eta.js.map +1 -0
- package/lib/dist/workflows/executor.d.ts.map +1 -1
- package/lib/dist/workflows/executor.js +21 -6
- package/lib/dist/workflows/executor.js.map +1 -1
- package/lib/node_modules/.package-lock.json +1 -1
- package/lib/package.json +3 -3
- package/package.json +1 -1
- package/lib/dist/web/chunk-2AJCHB7P.js +0 -1
- package/lib/dist/web/chunk-2CPLUFCH.js +0 -2
- package/lib/dist/web/chunk-2I7L37NS.js +0 -1
- package/lib/dist/web/chunk-2IVSOVQZ.js +0 -1
- package/lib/dist/web/chunk-2NAWAJB5.js +0 -1
- package/lib/dist/web/chunk-2OJBIPE4.js +0 -1
- package/lib/dist/web/chunk-3E2WB6D5.js +0 -1
- package/lib/dist/web/chunk-3EBFYSCH.js +0 -2
- package/lib/dist/web/chunk-3QCQ4BXS.js +0 -1
- package/lib/dist/web/chunk-42XVAQ6I.js +0 -1
- package/lib/dist/web/chunk-4G7XU55L.js +0 -1
- package/lib/dist/web/chunk-4IMMPEYM.js +0 -1
- package/lib/dist/web/chunk-4TJQJPCZ.js +0 -1
- package/lib/dist/web/chunk-4WZIHTPC.js +0 -1
- package/lib/dist/web/chunk-4YVSYOSD.js +0 -1
- package/lib/dist/web/chunk-5BQIOYKW.js +0 -1
- package/lib/dist/web/chunk-5HGWHUJA.js +0 -1
- package/lib/dist/web/chunk-5NTGUSXJ.js +0 -1
- package/lib/dist/web/chunk-5Y244R4G.js +0 -1
- package/lib/dist/web/chunk-6RRDPT5Z.js +0 -1
- package/lib/dist/web/chunk-6VKB2ZWM.js +0 -1
- package/lib/dist/web/chunk-7656MA24.js +0 -1
- package/lib/dist/web/chunk-7DMFVTU4.js +0 -1
- package/lib/dist/web/chunk-7KWBINA7.js +0 -1
- package/lib/dist/web/chunk-7SMPKVEP.js +0 -1
- package/lib/dist/web/chunk-AHI5XEVX.js +0 -1
- package/lib/dist/web/chunk-AS2GV63A.js +0 -1
- package/lib/dist/web/chunk-AZJVTPLU.js +0 -1
- package/lib/dist/web/chunk-AZUUBUEJ.js +0 -1
- package/lib/dist/web/chunk-BLBRMCN2.js +0 -1
- package/lib/dist/web/chunk-BMIAXD2V.js +0 -2
- package/lib/dist/web/chunk-BPCJLNBS.js +0 -47
- package/lib/dist/web/chunk-BUXWEHIY.js +0 -1
- package/lib/dist/web/chunk-CGVC666W.js +0 -1
- package/lib/dist/web/chunk-DLQPZWSI.css +0 -1
- package/lib/dist/web/chunk-DOKZOFKM.js +0 -1
- package/lib/dist/web/chunk-DTWIJ3GJ.js +0 -1
- package/lib/dist/web/chunk-DYRFLPJA.js +0 -1
- package/lib/dist/web/chunk-E3J3CXR5.js +0 -1
- package/lib/dist/web/chunk-E73OX2P7.js +0 -1
- package/lib/dist/web/chunk-EAXRKDLV.js +0 -1
- package/lib/dist/web/chunk-EBKKDHYI.js +0 -1
- package/lib/dist/web/chunk-EE7V7Q5P.js +0 -1
- package/lib/dist/web/chunk-EKY2FUHU.js +0 -1
- package/lib/dist/web/chunk-EP6XOPXH.js +0 -1
- package/lib/dist/web/chunk-ESGDLJOJ.js +0 -1
- package/lib/dist/web/chunk-ETJG7NCY.js +0 -1
- package/lib/dist/web/chunk-EUUEFEDI.js +0 -1
- package/lib/dist/web/chunk-EXBUKHH2.js +0 -17
- package/lib/dist/web/chunk-FC3R7YHR.js +0 -4
- package/lib/dist/web/chunk-FGNZDHTL.js +0 -11
- package/lib/dist/web/chunk-FIJW2UNJ.js +0 -1
- package/lib/dist/web/chunk-FMV5PXRC.js +0 -5
- package/lib/dist/web/chunk-G7RXFHYO.js +0 -1
- package/lib/dist/web/chunk-G7VZT5KB.js +0 -3
- package/lib/dist/web/chunk-GRZYXPSO.js +0 -7
- package/lib/dist/web/chunk-GYGPS3AN.js +0 -1
- package/lib/dist/web/chunk-H7AF7YS4.js +0 -1
- package/lib/dist/web/chunk-HDZDQILN.js +0 -1
- package/lib/dist/web/chunk-HMK6UO6N.js +0 -1
- package/lib/dist/web/chunk-IHEE5NYJ.js +0 -1
- package/lib/dist/web/chunk-IOB4JJT4.js +0 -1
- package/lib/dist/web/chunk-ISNEBICW.js +0 -1
- package/lib/dist/web/chunk-J2GZVLHH.js +0 -1
- package/lib/dist/web/chunk-JGDK6YKG.js +0 -1
- package/lib/dist/web/chunk-JLOJCDIY.js +0 -1
- package/lib/dist/web/chunk-JTFXTIPE.js +0 -903
- package/lib/dist/web/chunk-K7UD24Z4.js +0 -1
- package/lib/dist/web/chunk-KYSTCHAH.js +0 -1
- package/lib/dist/web/chunk-LB6JPLX2.js +0 -1
- package/lib/dist/web/chunk-LNSVDHCI.js +0 -1
- package/lib/dist/web/chunk-LVGIY3SO.js +0 -1
- package/lib/dist/web/chunk-LXLHIHEN.js +0 -1
- package/lib/dist/web/chunk-M42QOYAE.js +0 -1
- package/lib/dist/web/chunk-ML5ULGHY.js +0 -1
- package/lib/dist/web/chunk-MNFTHCSJ.js +0 -1
- package/lib/dist/web/chunk-N6SS4G6S.js +0 -1
- package/lib/dist/web/chunk-NKPK3BR3.js +0 -1
- package/lib/dist/web/chunk-NTBJG6SJ.js +0 -1
- package/lib/dist/web/chunk-NUDB3Q2Y.js +0 -3
- package/lib/dist/web/chunk-OTQR5VFM.js +0 -1
- package/lib/dist/web/chunk-OXEF5E3E.js +0 -1
- package/lib/dist/web/chunk-P62EJGSF.js +0 -1
- package/lib/dist/web/chunk-PCW6R7OP.js +0 -1
- package/lib/dist/web/chunk-PGGJPDJG.js +0 -1
- package/lib/dist/web/chunk-POCVU4VK.js +0 -2
- package/lib/dist/web/chunk-PS6HRYQQ.js +0 -3
- package/lib/dist/web/chunk-PUYSJNJR.js +0 -1
- package/lib/dist/web/chunk-PZSU53SS.js +0 -1
- package/lib/dist/web/chunk-Q2RVFS45.js +0 -1
- package/lib/dist/web/chunk-Q7L6LLAK.js +0 -1
- package/lib/dist/web/chunk-QCMKJIWY.js +0 -1
- package/lib/dist/web/chunk-QH6CF3M3.js +0 -1
- package/lib/dist/web/chunk-QIZ65CGB.js +0 -1
- package/lib/dist/web/chunk-QPA2REUE.js +0 -1
- package/lib/dist/web/chunk-QQ5LD7PI.js +0 -1
- package/lib/dist/web/chunk-QR6L3KAC.js +0 -1
- package/lib/dist/web/chunk-R2DLK4HO.js +0 -1
- package/lib/dist/web/chunk-RD6TVPOT.js +0 -1
- package/lib/dist/web/chunk-RKY4EJYJ.js +0 -1
- package/lib/dist/web/chunk-RONYWVY7.js +0 -1
- package/lib/dist/web/chunk-RXKXYF2C.js +0 -1
- package/lib/dist/web/chunk-S5J5WQXB.js +0 -6
- package/lib/dist/web/chunk-SQPYSOV6.js +0 -1
- package/lib/dist/web/chunk-SWKJRNYY.js +0 -1
- package/lib/dist/web/chunk-SYGIPC2P.js +0 -4
- package/lib/dist/web/chunk-T7AZ65JP.js +0 -1
- package/lib/dist/web/chunk-TCZDVOHD.js +0 -1
- package/lib/dist/web/chunk-TPTITA3V.js +0 -1
- package/lib/dist/web/chunk-TR335633.js +0 -1
- package/lib/dist/web/chunk-TWVVIWKO.js +0 -1
- package/lib/dist/web/chunk-U67LRNER.js +0 -1
- package/lib/dist/web/chunk-UR5KDXPX.js +0 -1
- package/lib/dist/web/chunk-UR6O2GEH.js +0 -1
- package/lib/dist/web/chunk-USVLLFVR.js +0 -1
- package/lib/dist/web/chunk-UTNMGWTP.js +0 -1
- package/lib/dist/web/chunk-V74ZPP4B.js +0 -1
- package/lib/dist/web/chunk-VECWMHJP.js +0 -1
- package/lib/dist/web/chunk-VUACT35R.js +0 -3
- package/lib/dist/web/chunk-VZI7H4SZ.js +0 -1
- package/lib/dist/web/chunk-W5TEIONI.js +0 -2
- package/lib/dist/web/chunk-WB6YHOD4.js +0 -1
- package/lib/dist/web/chunk-WBJ5VEB5.js +0 -1
- package/lib/dist/web/chunk-WBT64AWV.js +0 -1
- package/lib/dist/web/chunk-WFXJIXZE.js +0 -4
- package/lib/dist/web/chunk-WTGYRH3Z.js +0 -298
- package/lib/dist/web/chunk-WXTCVDTP.js +0 -1
- package/lib/dist/web/chunk-XAUQEKZX.js +0 -1
- package/lib/dist/web/chunk-XCDHWLVH.js +0 -1
- package/lib/dist/web/chunk-XKG5X37F.js +0 -1
- package/lib/dist/web/chunk-Y3H6FFUZ.js +0 -1
- package/lib/dist/web/chunk-Y4F5ULGJ.js +0 -1
- package/lib/dist/web/chunk-YEGKAAEE.js +0 -1
- package/lib/dist/web/chunk-YM2KU57F.js +0 -1
- package/lib/dist/web/chunk-YRERBP6T.js +0 -1
- package/lib/dist/web/chunk-YV5LB22R.js +0 -1
- package/lib/dist/web/chunk-YWIRU745.js +0 -1
- package/lib/dist/web/chunk-ZLV4VCDG.js +0 -3
- package/lib/dist/web/chunk-ZTVI5KFF.js +0 -1
- package/lib/dist/web/favicon-16.png +0 -0
- package/lib/dist/web/favicon-180.png +0 -0
- package/lib/dist/web/favicon-32.png +0 -0
- package/lib/dist/web/favicon-512.png +0 -0
- package/lib/dist/web/favicon-small.svg +0 -15
- package/lib/dist/web/favicon.ico +0 -0
- package/lib/dist/web/favicon.svg +0 -20
- package/lib/dist/web/icon-192.png +0 -0
- package/lib/dist/web/icon-512.png +0 -0
- package/lib/dist/web/index.html +0 -146
- package/lib/dist/web/main-ESADRXN2.css +0 -1
- package/lib/dist/web/main-JT2RR3JS.js +0 -1
- package/lib/dist/web/manifest.webmanifest +0 -15
- package/lib/dist/web/media/codicon-LN6W7LCM.ttf +0 -0
- package/lib/dist/web/sw.js +0 -69
- /package/lib/dist/{web/styles-ATJUD7TT.css → server/ssr/public/app.css} +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
export async function registerSsrRoutes(app) {
|
|
5
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
// Server-local ESM module, copied next to this file by the build. No type
|
|
7
|
+
// declarations — it renders HTML strings from API-shaped data.
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
+
// @ts-expect-error -- untyped server-local module
|
|
10
|
+
const R = await import('./render.mjs');
|
|
11
|
+
const PUB = join(here, 'public');
|
|
12
|
+
const inject = async (url) => {
|
|
13
|
+
const res = await app.inject({ method: 'GET', url });
|
|
14
|
+
try {
|
|
15
|
+
return res.json();
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const send = (reply, title, active, body) => reply.header('content-type', 'text/html; charset=utf-8').send(R['layout']({ title, activeHref: active, body }));
|
|
22
|
+
// --- static assets (served by hand — no extra dependency) ---
|
|
23
|
+
const assets = {
|
|
24
|
+
'/app.css': ['app.css', 'text/css; charset=utf-8'],
|
|
25
|
+
'/islands.js': ['islands.js', 'text/javascript; charset=utf-8'],
|
|
26
|
+
'/islands/graph.js': [join('islands', 'graph.js'), 'text/javascript; charset=utf-8'],
|
|
27
|
+
};
|
|
28
|
+
for (const [route, spec] of Object.entries(assets)) {
|
|
29
|
+
const [file, type] = spec;
|
|
30
|
+
app.get(route, async (_req, reply) => reply.header('content-type', type).send(readFileSync(join(PUB, file))));
|
|
31
|
+
}
|
|
32
|
+
// --- pages ---
|
|
33
|
+
const page = (route, title, fn) => {
|
|
34
|
+
app.get(route, async (_req, reply) => {
|
|
35
|
+
let body;
|
|
36
|
+
try {
|
|
37
|
+
body = await fn();
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
body = `<div class="page-head"><h1>${title}</h1></div><p class="muted">Couldn't load data: ${e instanceof Error ? e.message : String(e)}</p>`;
|
|
41
|
+
}
|
|
42
|
+
send(reply, title, route, body);
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
app.get('/', async (_req, reply) => reply.redirect('/dashboard'));
|
|
46
|
+
page('/dashboard', 'Dashboard', async () => R['renderDashboard'](await inject('/api/status'), await inject('/api/claude/stats')));
|
|
47
|
+
app.get('/specs', async (_req, reply) => send(reply, 'Specs', '/specs', R['renderSpecs']((await inject('/api/specs'))['specs'] ?? [])));
|
|
48
|
+
app.get('/specs/:id', async (req, reply) => {
|
|
49
|
+
const id = req.params.id;
|
|
50
|
+
send(reply, 'Spec', '/specs', R['renderSpecDetail'](await inject(`/api/spec/${encodeURIComponent(id)}`)));
|
|
51
|
+
});
|
|
52
|
+
page('/drift', 'Drift', async () => R['renderDrift'](await inject('/api/drift')));
|
|
53
|
+
page('/maintainability', 'Maintainability', async () => R['renderMaintainability'](await inject('/api/maintainability')));
|
|
54
|
+
page('/domain', 'Domain', async () => R['renderDomain'](await inject('/api/domain')));
|
|
55
|
+
page('/memory', 'Memory', async () => R['renderMemory'](await inject('/api/memory')));
|
|
56
|
+
page('/improvements', 'Improvements', async () => R['renderImprovements'](await inject('/api/reflect')));
|
|
57
|
+
page('/compare', 'Compare', async () => R['renderCompare'](await inject('/api/claude/compare')));
|
|
58
|
+
page('/costs', 'Costs', async () => R['renderCosts'](await inject('/api/claude/costs')));
|
|
59
|
+
page('/specship-impact', 'SpecShip impact', async () => R['renderImpact'](await inject('/api/claude/specship-impact')));
|
|
60
|
+
page('/runs', 'Runs', async () => R['renderRuns'](await inject('/api/workflows/runs')));
|
|
61
|
+
app.get('/runs/:id', async (req, reply) => {
|
|
62
|
+
const id = req.params.id;
|
|
63
|
+
send(reply, 'Run', '/runs', R['renderRunDetail'](await inject(`/api/workflows/runs/${encodeURIComponent(id)}`)));
|
|
64
|
+
});
|
|
65
|
+
page('/sessions', 'Sessions', async () => R['renderSessions'](await inject('/api/claude/sessions')));
|
|
66
|
+
app.get('/sessions/:id', async (req, reply) => {
|
|
67
|
+
const id = req.params.id;
|
|
68
|
+
send(reply, 'Session', '/sessions', R['renderSessionDetail'](await inject(`/api/claude/session/${encodeURIComponent(id)}`)));
|
|
69
|
+
});
|
|
70
|
+
page('/mcp', 'MCP', async () => R['renderMcp']((await inject('/api/mcp/servers'))['servers']));
|
|
71
|
+
page('/graph', 'Graph', async () => R['renderGraph'](await inject('/api/graph/full?limit=250')));
|
|
72
|
+
page('/heatmap', 'Heatmap', async () => R['renderHeatmap'](await inject('/api/claude/heatmap')));
|
|
73
|
+
}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* }
|
|
15
15
|
* const hit = serveStatic(req.url);
|
|
16
16
|
* if (hit) { reply.type(hit.contentType).send(hit.body); return; }
|
|
17
|
+
* if (isAssetPath(req.url)) { reply.code(404).send({ error: 'not found' }); return; }
|
|
17
18
|
* reply.code(200).type('text/html').send(cachedIndex);
|
|
18
19
|
* });
|
|
19
20
|
*
|
|
@@ -44,6 +45,35 @@ const CT = {
|
|
|
44
45
|
'.txt': 'text/plain; charset=utf-8',
|
|
45
46
|
'.wasm': 'application/wasm',
|
|
46
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* Whether a URL path names a static asset (its final segment ends in a
|
|
50
|
+
* recognized asset extension). Used by the SPA fallback to answer a MISSING
|
|
51
|
+
* asset with 404 instead of index.html (REQ-OFFLINE-005): serving HTML at an
|
|
52
|
+
* asset URL poisons the browser's and the offline service worker's caches —
|
|
53
|
+
* a tab holding a stale build requests its old content-hashed bundle, gets
|
|
54
|
+
* the shell, and stores HTML under the bundle URL until site data is cleared.
|
|
55
|
+
*
|
|
56
|
+
* Only extensions from the content-type table count — client routes with
|
|
57
|
+
* dotted params (`/specs/REQ-OFFLINE-001.A1`) must keep the shell fallback.
|
|
58
|
+
*/
|
|
59
|
+
export function isAssetPath(urlPath) {
|
|
60
|
+
const qIdx = urlPath.indexOf('?');
|
|
61
|
+
const hIdx = urlPath.indexOf('#');
|
|
62
|
+
let clean = urlPath;
|
|
63
|
+
if (qIdx >= 0)
|
|
64
|
+
clean = clean.slice(0, qIdx);
|
|
65
|
+
if (hIdx >= 0)
|
|
66
|
+
clean = clean.slice(0, hIdx);
|
|
67
|
+
let decoded;
|
|
68
|
+
try {
|
|
69
|
+
decoded = decodeURIComponent(clean);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
decoded = clean;
|
|
73
|
+
}
|
|
74
|
+
const ext = path.extname(decoded).toLowerCase();
|
|
75
|
+
return ext !== '' && ext in CT;
|
|
76
|
+
}
|
|
47
77
|
export function makeStaticHandler(rootDir) {
|
|
48
78
|
const absRoot = path.resolve(rootDir);
|
|
49
79
|
return function serveStatic(urlPath) {
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* the `workflow_runs` table (which would mean a DB connection on the render
|
|
7
7
|
* path). `clearActiveRun` removes the marker when no run is active.
|
|
8
8
|
*/
|
|
9
|
-
import { ActiveRun } from './types';
|
|
9
|
+
import { ActiveRun, ActiveRunEta } from './types';
|
|
10
10
|
/** Atomically record the active run. Best-effort; never throws. */
|
|
11
|
-
export declare function writeActiveRun(projectRoot: string, specId: string | null, status: string): void;
|
|
11
|
+
export declare function writeActiveRun(projectRoot: string, specId: string | null, status: string, eta?: ActiveRunEta): void;
|
|
12
12
|
/** Remove the active-run marker (e.g. once a run is merged/cancelled). */
|
|
13
13
|
export declare function clearActiveRun(projectRoot: string): void;
|
|
14
14
|
/** Read the active-run marker, or null when none. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"active-run.d.ts","sourceRoot":"","sources":["../../src/statusline/active-run.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"active-run.d.ts","sourceRoot":"","sources":["../../src/statusline/active-run.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGlD,mEAAmE;AACnE,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE,YAAY,GACjB,IAAI,CAON;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAMxD;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAGnE"}
|
|
@@ -47,8 +47,8 @@ exports.readActiveRun = readActiveRun;
|
|
|
47
47
|
const fs = __importStar(require("fs"));
|
|
48
48
|
const paths_1 = require("./paths");
|
|
49
49
|
/** Atomically record the active run. Best-effort; never throws. */
|
|
50
|
-
function writeActiveRun(projectRoot, specId, status) {
|
|
51
|
-
const data = { v: 1, specId, status, updatedAt: Date.now() };
|
|
50
|
+
function writeActiveRun(projectRoot, specId, status, eta) {
|
|
51
|
+
const data = { v: 1, specId, status, updatedAt: Date.now(), ...(eta ? { eta } : {}) };
|
|
52
52
|
try {
|
|
53
53
|
(0, paths_1.writeJsonAtomic)((0, paths_1.activeRunPath)(projectRoot), data);
|
|
54
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"active-run.js","sourceRoot":"","sources":["../../src/statusline/active-run.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOH,
|
|
1
|
+
{"version":3,"file":"active-run.js","sourceRoot":"","sources":["../../src/statusline/active-run.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOH,wCAYC;AAGD,wCAMC;AAGD,sCAGC;AAhCD,uCAAyB;AAEzB,mCAAuE;AAEvE,mEAAmE;AACnE,SAAgB,cAAc,CAC5B,WAAmB,EACnB,MAAqB,EACrB,MAAc,EACd,GAAkB;IAElB,MAAM,IAAI,GAAc,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACjG,IAAI,CAAC;QACH,IAAA,uBAAe,EAAC,IAAA,qBAAa,EAAC,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,iBAAiB;IACnB,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,SAAgB,cAAc,CAAC,WAAmB;IAChD,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,IAAA,qBAAa,EAAC,WAAW,CAAC,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,oBAAoB;IACtB,CAAC;AACH,CAAC;AAED,qDAAqD;AACrD,SAAgB,aAAa,CAAC,WAAmB;IAC/C,MAAM,CAAC,GAAG,IAAA,oBAAY,EAAY,IAAA,qBAAa,EAAC,WAAW,CAAC,CAAC,CAAC;IAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/statusline/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEjF,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7B,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IACtB;;;;OAIG;IACH,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/statusline/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEjF,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7B,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IACtB;;;;OAIG;IACH,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC;CAClB;AA0ED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAoExD"}
|
|
@@ -18,6 +18,35 @@ function bar(pct) {
|
|
|
18
18
|
const filled = Math.max(0, Math.min(cells, Math.round((pct / 100) * cells)));
|
|
19
19
|
return `❮${'▰'.repeat(filled)}${'▱'.repeat(cells - filled)}❯`;
|
|
20
20
|
}
|
|
21
|
+
/** Compact duration for the run ETA element: `4m`, `1h20m`, `<1m`. */
|
|
22
|
+
function fmtEtaDur(ms) {
|
|
23
|
+
const m = Math.round(ms / 60_000);
|
|
24
|
+
if (m < 1)
|
|
25
|
+
return '<1m';
|
|
26
|
+
if (m < 60)
|
|
27
|
+
return `${m}m`;
|
|
28
|
+
const h = Math.floor(m / 60);
|
|
29
|
+
const rest = m % 60;
|
|
30
|
+
return rest === 0 ? `${h}h` : `${h}h${rest}m`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* ETA suffix for the active-run element (REQ-STATUSLINE-011): a compact
|
|
34
|
+
* range for a running run, a waiting signal for a gated one, '' when the
|
|
35
|
+
* marker carries no estimate (older writer / no history).
|
|
36
|
+
*/
|
|
37
|
+
function etaSuffix(run) {
|
|
38
|
+
const eta = run.eta;
|
|
39
|
+
if (!eta)
|
|
40
|
+
return '';
|
|
41
|
+
if (eta.kind === 'range') {
|
|
42
|
+
const low = fmtEtaDur(eta.lowMs);
|
|
43
|
+
const high = fmtEtaDur(eta.highMs);
|
|
44
|
+
return low === high ? ` ≈${low} left` : ` ≈${low}–${high} left`;
|
|
45
|
+
}
|
|
46
|
+
if (eta.kind === 'waiting')
|
|
47
|
+
return ' waiting on you';
|
|
48
|
+
return '';
|
|
49
|
+
}
|
|
21
50
|
/**
|
|
22
51
|
* Format a reset instant in the machine's local timezone: time-only when it
|
|
23
52
|
* falls on the same local day as `now` (e.g. `(4pm)`), date + time otherwise
|
|
@@ -84,11 +113,15 @@ function renderSegment(input) {
|
|
|
84
113
|
// Session call count — the honest usage signal. Zero placeholder when no marker.
|
|
85
114
|
const calls = marker ? marker.calls : 0;
|
|
86
115
|
parts.push(c(COLOR.calls, `${calls} ${calls === 1 ? 'call' : 'calls'}`));
|
|
87
|
-
// Active workflow run, only when one exists
|
|
116
|
+
// Active workflow run, only when one exists — with its remaining-time
|
|
117
|
+
// estimate when the marker carries one (REQ-STATUSLINE-011).
|
|
88
118
|
if (run) {
|
|
89
119
|
const label = run.specId ? `${run.specId}·${run.status}` : run.status;
|
|
90
|
-
parts.push(c(COLOR.run, label));
|
|
120
|
+
parts.push(c(COLOR.run, `${label}${etaSuffix(run)}`));
|
|
91
121
|
}
|
|
122
|
+
// Telemetry elements render on their own SECOND line (REQ-STATUSLINE-010):
|
|
123
|
+
// the SpecShip identity stays scannable while capacity bars get room.
|
|
124
|
+
const telemetry = [];
|
|
92
125
|
// Context-usage element (REQ-STATUSLINE-009) — Claude's real context %, with
|
|
93
126
|
// an escalating compaction warning past the threshold. Advisory only;
|
|
94
127
|
// SpecShip cannot compact. Omitted when no real percentage is available.
|
|
@@ -96,7 +129,7 @@ function renderSegment(input) {
|
|
|
96
129
|
const warn = context >= (ctxWarnPct ?? 80);
|
|
97
130
|
const color = warn ? COLOR.pending : COLOR.calls; // amber when high, else gold
|
|
98
131
|
const hint = warn ? ' ⚠ compact' : '';
|
|
99
|
-
|
|
132
|
+
telemetry.push(c(color, `CTX ${bar(context)} ${Math.round(context)}%${hint}`));
|
|
100
133
|
}
|
|
101
134
|
// Usage-limit sub-segment (REQ-STATUSLINE-008) — ONLY for windows with real
|
|
102
135
|
// numbers; SpecShip never estimates. `now` formats reset times in local time.
|
|
@@ -105,11 +138,14 @@ function renderSegment(input) {
|
|
|
105
138
|
if (!w)
|
|
106
139
|
return;
|
|
107
140
|
const reset = Number.isFinite(w.resetAt) ? ` ${formatReset(w.resetAt, now)}` : '';
|
|
108
|
-
|
|
141
|
+
telemetry.push(c(COLOR.calls, `${label} ${bar(w.pctUsed)} ${Math.round(w.pctUsed)}%${reset}`));
|
|
109
142
|
};
|
|
110
143
|
win('5h', usage.session);
|
|
111
144
|
win('7d', usage.weekly);
|
|
112
145
|
}
|
|
113
|
-
|
|
146
|
+
const line1 = `${orn} ${brand}${sep}${parts.join(sep)} ${orn}`;
|
|
147
|
+
if (telemetry.length === 0)
|
|
148
|
+
return line1;
|
|
149
|
+
return `${line1}\n${orn} ${telemetry.join(sep)} ${orn}`;
|
|
114
150
|
}
|
|
115
151
|
//# sourceMappingURL=render.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/statusline/render.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/statusline/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -78,6 +78,19 @@ export interface UsageLimits {
|
|
|
78
78
|
/** The weekly (7-day) window, or null when absent. */
|
|
79
79
|
weekly: UsageWindow | null;
|
|
80
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Remaining-time estimate embedded in the run marker (REQ-STATUSLINE-011).
|
|
83
|
+
* Computed by the executor at marker-write time (WORKFLOW-ETA-DOC), so the
|
|
84
|
+
* render path never opens the DB. Absent when no estimate exists.
|
|
85
|
+
*/
|
|
86
|
+
export type ActiveRunEta = {
|
|
87
|
+
kind: 'range';
|
|
88
|
+
lowMs: number;
|
|
89
|
+
highMs: number;
|
|
90
|
+
} | {
|
|
91
|
+
kind: 'waiting';
|
|
92
|
+
sinceMs?: number;
|
|
93
|
+
};
|
|
81
94
|
/** The active (or most recent) workflow run for the project. */
|
|
82
95
|
export interface ActiveRun {
|
|
83
96
|
v: 1;
|
|
@@ -87,5 +100,7 @@ export interface ActiveRun {
|
|
|
87
100
|
status: string;
|
|
88
101
|
/** ms epoch of the last status change. */
|
|
89
102
|
updatedAt: number;
|
|
103
|
+
/** Remaining-time estimate, when one exists (REQ-STATUSLINE-011). */
|
|
104
|
+
eta?: ActiveRunEta;
|
|
90
105
|
}
|
|
91
106
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/statusline/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC9B,sEAAsE;IACtE,CAAC,EAAE,CAAC,CAAC;IACL,yDAAyD;IACzD,WAAW,EAAE,OAAO,CAAC;IACrB,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,yFAAyF;IACzF,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,CAAC,EAAE,CAAC,CAAC;IACL,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,uEAAuE;IACvE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,sFAAsF;IACtF,OAAO,EAAE,MAAM,CAAC;IAChB,8FAA8F;IAC9F,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,8DAA8D;IAC9D,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,sDAAsD;IACtD,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;CAC5B;AAED,gEAAgE;AAChE,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,CAAC,CAAC;IACL,8DAA8D;IAC9D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,wFAAwF;IACxF,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/statusline/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC9B,sEAAsE;IACtE,CAAC,EAAE,CAAC,CAAC;IACL,yDAAyD;IACzD,WAAW,EAAE,OAAO,CAAC;IACrB,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,yFAAyF;IACzF,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,CAAC,EAAE,CAAC,CAAC;IACL,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,uEAAuE;IACvE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,sFAAsF;IACtF,OAAO,EAAE,MAAM,CAAC;IAChB,8FAA8F;IAC9F,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,8DAA8D;IAC9D,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,sDAAsD;IACtD,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C,gEAAgE;AAChE,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,CAAC,CAAC;IACL,8DAA8D;IAC9D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,wFAAwF;IACxF,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,GAAG,CAAC,EAAE,YAAY,CAAC;CACpB"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow run time-to-completion estimation (WORKFLOW-ETA-DOC).
|
|
3
|
+
*
|
|
4
|
+
* Estimates the remaining machine time of a `running` run as a range — the
|
|
5
|
+
* sum over its not-yet-completed steps of that step's historical duration
|
|
6
|
+
* quantiles (p50 → low, p90 → high), computed from prior completed runs of
|
|
7
|
+
* the SAME workflow (REQ-ETA-001/002). Recomputing after each step completes
|
|
8
|
+
* is what makes the estimate tighten as the run progresses — this function is
|
|
9
|
+
* pure read, cheap, and safe to call on every poll.
|
|
10
|
+
*
|
|
11
|
+
* Honesty rules:
|
|
12
|
+
* - Human gate-wait is unbounded latency: approval request→grant spans are
|
|
13
|
+
* subtracted from any step duration they overlap, and a paused run gets
|
|
14
|
+
* a "waiting since" timestamp instead of a number (REQ-ETA-003).
|
|
15
|
+
* - Fewer than MIN_HISTORY_RUNS completed prior runs → no estimate at all,
|
|
16
|
+
* never a fabricated default (REQ-ETA-004).
|
|
17
|
+
*
|
|
18
|
+
* Step identity: the executor logs step_started/step_completed with the step
|
|
19
|
+
* id inside the event's data JSON (the step_id column predates that and is
|
|
20
|
+
* often null), hence the COALESCE.
|
|
21
|
+
*/
|
|
22
|
+
import { SqliteDatabase } from '../db/sqlite-adapter';
|
|
23
|
+
export interface RunEtaAvailable {
|
|
24
|
+
available: true;
|
|
25
|
+
/** Optimistic remaining time — sum of remaining steps' historical medians. */
|
|
26
|
+
lowMs: number;
|
|
27
|
+
/** Pessimistic remaining time — sum of remaining steps' historical p90s. */
|
|
28
|
+
highMs: number;
|
|
29
|
+
/** How many completed prior runs the estimate is based on. */
|
|
30
|
+
basisRuns: number;
|
|
31
|
+
}
|
|
32
|
+
export interface RunEtaUnavailable {
|
|
33
|
+
available: false;
|
|
34
|
+
reason: 'not_found' | 'not_running' | 'paused' | 'insufficient_history';
|
|
35
|
+
/** For 'paused': when the run began waiting on the human (approval request). */
|
|
36
|
+
waitingSinceMs?: number;
|
|
37
|
+
}
|
|
38
|
+
export type RunEta = RunEtaAvailable | RunEtaUnavailable;
|
|
39
|
+
/** Below this many completed prior runs, report insufficient_history. */
|
|
40
|
+
export declare const MIN_HISTORY_RUNS = 3;
|
|
41
|
+
export declare function estimateRunEta(db: SqliteDatabase, runId: string): RunEta;
|
|
42
|
+
//# sourceMappingURL=eta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eta.d.ts","sourceRoot":"","sources":["../../src/workflows/eta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,IAAI,CAAC;IAChB,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,aAAa,GAAG,QAAQ,GAAG,sBAAsB,CAAC;IACxE,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,MAAM,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAEzD,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAoBlC,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA8GxE"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Workflow run time-to-completion estimation (WORKFLOW-ETA-DOC).
|
|
4
|
+
*
|
|
5
|
+
* Estimates the remaining machine time of a `running` run as a range — the
|
|
6
|
+
* sum over its not-yet-completed steps of that step's historical duration
|
|
7
|
+
* quantiles (p50 → low, p90 → high), computed from prior completed runs of
|
|
8
|
+
* the SAME workflow (REQ-ETA-001/002). Recomputing after each step completes
|
|
9
|
+
* is what makes the estimate tighten as the run progresses — this function is
|
|
10
|
+
* pure read, cheap, and safe to call on every poll.
|
|
11
|
+
*
|
|
12
|
+
* Honesty rules:
|
|
13
|
+
* - Human gate-wait is unbounded latency: approval request→grant spans are
|
|
14
|
+
* subtracted from any step duration they overlap, and a paused run gets
|
|
15
|
+
* a "waiting since" timestamp instead of a number (REQ-ETA-003).
|
|
16
|
+
* - Fewer than MIN_HISTORY_RUNS completed prior runs → no estimate at all,
|
|
17
|
+
* never a fabricated default (REQ-ETA-004).
|
|
18
|
+
*
|
|
19
|
+
* Step identity: the executor logs step_started/step_completed with the step
|
|
20
|
+
* id inside the event's data JSON (the step_id column predates that and is
|
|
21
|
+
* often null), hence the COALESCE.
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.MIN_HISTORY_RUNS = void 0;
|
|
25
|
+
exports.estimateRunEta = estimateRunEta;
|
|
26
|
+
/** Below this many completed prior runs, report insufficient_history. */
|
|
27
|
+
exports.MIN_HISTORY_RUNS = 3;
|
|
28
|
+
/** Quantile of a non-empty sorted array (nearest-rank on small samples). */
|
|
29
|
+
function quantile(sortedAsc, q) {
|
|
30
|
+
const idx = Math.min(sortedAsc.length - 1, Math.max(0, Math.ceil(q * sortedAsc.length) - 1));
|
|
31
|
+
return sortedAsc[idx] ?? 0;
|
|
32
|
+
}
|
|
33
|
+
/** Overlap of [aStart, aEnd] with [bStart, bEnd], ≥ 0. */
|
|
34
|
+
function overlap(aStart, aEnd, bStart, bEnd) {
|
|
35
|
+
return Math.max(0, Math.min(aEnd, bEnd) - Math.max(aStart, bStart));
|
|
36
|
+
}
|
|
37
|
+
function estimateRunEta(db, runId) {
|
|
38
|
+
const run = db
|
|
39
|
+
.prepare(`SELECT id, workflow_name AS name, status, metadata FROM workflow_runs WHERE id = ?`)
|
|
40
|
+
.get(runId);
|
|
41
|
+
if (!run)
|
|
42
|
+
return { available: false, reason: 'not_found' };
|
|
43
|
+
if (run.status === 'paused') {
|
|
44
|
+
const w = db
|
|
45
|
+
.prepare(`SELECT MAX(created_at) AS t FROM workflow_events
|
|
46
|
+
WHERE workflow_run_id = ? AND event_type = 'approval_requested'`)
|
|
47
|
+
.get(runId);
|
|
48
|
+
return { available: false, reason: 'paused', waitingSinceMs: w?.t ?? undefined };
|
|
49
|
+
}
|
|
50
|
+
if (run.status !== 'running')
|
|
51
|
+
return { available: false, reason: 'not_running' };
|
|
52
|
+
const prior = db
|
|
53
|
+
.prepare(`SELECT id FROM workflow_runs
|
|
54
|
+
WHERE workflow_name = ? AND status = 'completed' AND id != ?
|
|
55
|
+
ORDER BY completed_at DESC LIMIT 50`)
|
|
56
|
+
.all(run.name, runId);
|
|
57
|
+
if (prior.length < exports.MIN_HISTORY_RUNS)
|
|
58
|
+
return { available: false, reason: 'insufficient_history' };
|
|
59
|
+
const placeholders = prior.map(() => '?').join(',');
|
|
60
|
+
const events = db
|
|
61
|
+
.prepare(`SELECT workflow_run_id AS rid, event_type AS et,
|
|
62
|
+
COALESCE(step_id, json_extract(data, '$.stepId')) AS sid,
|
|
63
|
+
created_at AS t
|
|
64
|
+
FROM workflow_events
|
|
65
|
+
WHERE workflow_run_id IN (${placeholders})
|
|
66
|
+
AND event_type IN ('step_started', 'step_completed', 'approval_requested', 'approval_granted')
|
|
67
|
+
ORDER BY created_at ASC`)
|
|
68
|
+
.all(...prior.map((p) => p.id));
|
|
69
|
+
// Human-wait spans per prior run: sequential request→grant pairs.
|
|
70
|
+
const waitSpans = new Map();
|
|
71
|
+
const pendingReq = new Map();
|
|
72
|
+
for (const e of events) {
|
|
73
|
+
if (e.et === 'approval_requested')
|
|
74
|
+
pendingReq.set(e.rid, e.t);
|
|
75
|
+
else if (e.et === 'approval_granted') {
|
|
76
|
+
const req = pendingReq.get(e.rid);
|
|
77
|
+
if (req !== undefined) {
|
|
78
|
+
const spans = waitSpans.get(e.rid) ?? [];
|
|
79
|
+
spans.push([req, e.t]);
|
|
80
|
+
waitSpans.set(e.rid, spans);
|
|
81
|
+
pendingReq.delete(e.rid);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Per-step ACTIVE durations across prior runs (gate-wait subtracted), and
|
|
86
|
+
// the step universe in first-seen order.
|
|
87
|
+
const durations = new Map();
|
|
88
|
+
const firstSeen = new Map();
|
|
89
|
+
const openStep = new Map(); // rid → in-flight step
|
|
90
|
+
for (const e of events) {
|
|
91
|
+
if (!e.sid)
|
|
92
|
+
continue;
|
|
93
|
+
if (e.et === 'step_started') {
|
|
94
|
+
openStep.set(e.rid, { sid: e.sid, t: e.t });
|
|
95
|
+
if (!firstSeen.has(e.sid))
|
|
96
|
+
firstSeen.set(e.sid, e.t);
|
|
97
|
+
}
|
|
98
|
+
else if (e.et === 'step_completed') {
|
|
99
|
+
const open = openStep.get(e.rid);
|
|
100
|
+
if (!open || open.sid !== e.sid)
|
|
101
|
+
continue;
|
|
102
|
+
openStep.delete(e.rid);
|
|
103
|
+
let dur = e.t - open.t;
|
|
104
|
+
for (const [ws, we] of waitSpans.get(e.rid) ?? [])
|
|
105
|
+
dur -= overlap(open.t, e.t, ws, we);
|
|
106
|
+
if (dur >= 0) {
|
|
107
|
+
const arr = durations.get(e.sid) ?? [];
|
|
108
|
+
arr.push(dur);
|
|
109
|
+
durations.set(e.sid, arr);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (durations.size === 0)
|
|
114
|
+
return { available: false, reason: 'insufficient_history' };
|
|
115
|
+
// Steps this run has already completed: run metadata + its own event log.
|
|
116
|
+
const done = new Set();
|
|
117
|
+
try {
|
|
118
|
+
const meta = run.metadata ? JSON.parse(run.metadata) : {};
|
|
119
|
+
if (Array.isArray(meta.completedNodes))
|
|
120
|
+
for (const n of meta.completedNodes)
|
|
121
|
+
done.add(String(n));
|
|
122
|
+
}
|
|
123
|
+
catch { /* unreadable metadata — fall back to the event log alone */ }
|
|
124
|
+
const ownCompleted = db
|
|
125
|
+
.prepare(`SELECT DISTINCT COALESCE(step_id, json_extract(data, '$.stepId')) AS sid
|
|
126
|
+
FROM workflow_events
|
|
127
|
+
WHERE workflow_run_id = ? AND event_type IN ('step_completed', 'step_skipped')`)
|
|
128
|
+
.all(runId);
|
|
129
|
+
for (const r of ownCompleted)
|
|
130
|
+
if (r.sid)
|
|
131
|
+
done.add(r.sid);
|
|
132
|
+
const universe = [...durations.keys()].sort((a, b) => (firstSeen.get(a) ?? 0) - (firstSeen.get(b) ?? 0));
|
|
133
|
+
const remaining = universe.filter((sid) => !done.has(sid));
|
|
134
|
+
// Fallback distribution for a remaining step with no history of its own:
|
|
135
|
+
// this workflow's overall per-step durations (never another workflow's).
|
|
136
|
+
const allDurs = [...durations.values()].flat().sort((a, b) => a - b);
|
|
137
|
+
let lowMs = 0;
|
|
138
|
+
let highMs = 0;
|
|
139
|
+
for (const sid of remaining) {
|
|
140
|
+
const durs = (durations.get(sid) ?? allDurs).slice().sort((a, b) => a - b);
|
|
141
|
+
lowMs += quantile(durs, 0.5);
|
|
142
|
+
highMs += quantile(durs, 0.9);
|
|
143
|
+
}
|
|
144
|
+
return { available: true, lowMs: Math.round(lowMs), highMs: Math.round(highMs), basisRuns: prior.length };
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=eta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eta.js","sourceRoot":"","sources":["../../src/workflows/eta.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/workflows/executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,OAAO,EACL,kBAAkB,EAClB,OAAO,EAOR,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,WAAW,EACX,iBAAiB,EAGlB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/workflows/executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,OAAO,EACL,kBAAkB,EAClB,OAAO,EAOR,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,WAAW,EACX,iBAAiB,EAGlB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAIzD,OAAO,EACL,UAAU,EAIX,MAAM,uBAAuB,CAAC;AAQ/B,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,uBAAuB;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,WAAW,CAAC;IACjB,sCAAsC;IACtC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC3C,4CAA4C;IAC5C,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CAClC;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,OAAO,CAAmC;IAClD;;;;;OAKG;IACH,OAAO,CAAC,WAAW,CAAC,CAAS;gBAEjB,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,WAAW,CAAC,EAAE,MAAM;IAiBjF,KAAK,CACT,QAAQ,EAAE,kBAAkB,EAC5B,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,aAAa,CAAC;IA+EzB;;OAEG;IACG,MAAM,CACV,QAAQ,EAAE,kBAAkB,EAC5B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,aAAa,CAAC;IAqCzB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,MAA4B,GAAG,IAAI;IA+BjE;;;;OAIG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IA0C9C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;YA8B9B,cAAc;YA8Id,YAAY;IA2B1B,OAAO,CAAC,YAAY;IAuBpB;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;IAiDvB,OAAO,CAAC,uBAAuB;IAa/B;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;YAsBb,QAAQ;YA6CR,aAAa;IAyB3B,OAAO,CAAC,KAAK;CA2Bd;AAMD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CA6BnD"}
|
|
@@ -57,6 +57,7 @@ const os = __importStar(require("os"));
|
|
|
57
57
|
const crypto_1 = require("crypto");
|
|
58
58
|
const directory_1 = require("../directory");
|
|
59
59
|
const statusline_1 = require("../statusline");
|
|
60
|
+
const eta_1 = require("./eta");
|
|
60
61
|
const condition_evaluator_1 = require("./condition-evaluator");
|
|
61
62
|
const prompt_1 = require("./runners/prompt");
|
|
62
63
|
const bash_1 = require("./runners/bash");
|
|
@@ -160,7 +161,7 @@ class WorkflowExecutor {
|
|
|
160
161
|
},
|
|
161
162
|
};
|
|
162
163
|
this.specQueries.insertWorkflowRun(run);
|
|
163
|
-
this.syncActiveRunMarker(run.status, run.inputs);
|
|
164
|
+
this.syncActiveRunMarker(run.status, run.inputs, run.id);
|
|
164
165
|
this.event(runId, 'run_started', { workflowName: workflow.name, inputs: opts.inputs });
|
|
165
166
|
return this.driveExecution(workflow, run, cwd, artifactsDir, logsDir, opts);
|
|
166
167
|
}
|
|
@@ -189,7 +190,7 @@ class WorkflowExecutor {
|
|
|
189
190
|
errorMessage: undefined,
|
|
190
191
|
};
|
|
191
192
|
this.specQueries.updateWorkflowRun(refreshed);
|
|
192
|
-
this.syncActiveRunMarker(refreshed.status, refreshed.inputs);
|
|
193
|
+
this.syncActiveRunMarker(refreshed.status, refreshed.inputs, refreshed.id);
|
|
193
194
|
this.event(runId, 'run_started', { resumed: true });
|
|
194
195
|
return this.driveExecution(workflow, refreshed, cwd, artifactsDir, logsDir, opts);
|
|
195
196
|
}
|
|
@@ -266,7 +267,7 @@ class WorkflowExecutor {
|
|
|
266
267
|
});
|
|
267
268
|
// Archon's paused→failed-but-resumable convention: keep the run visible
|
|
268
269
|
// in the status line (resume drives it back to running).
|
|
269
|
-
this.syncActiveRunMarker('failed', run.inputs);
|
|
270
|
+
this.syncActiveRunMarker('failed', run.inputs, run.id);
|
|
270
271
|
this.event(runId, 'approval_granted', { nodeId: approval.nodeId, comment });
|
|
271
272
|
}
|
|
272
273
|
}
|
|
@@ -531,7 +532,7 @@ class WorkflowExecutor {
|
|
|
531
532
|
* marker; any live state (running / paused / failed-but-resumable) writes it.
|
|
532
533
|
* Best-effort and fully guarded — marker bookkeeping never affects a run.
|
|
533
534
|
*/
|
|
534
|
-
syncActiveRunMarker(status, inputs) {
|
|
535
|
+
syncActiveRunMarker(status, inputs, runId) {
|
|
535
536
|
if (!this.projectRoot)
|
|
536
537
|
return;
|
|
537
538
|
try {
|
|
@@ -539,7 +540,21 @@ class WorkflowExecutor {
|
|
|
539
540
|
(0, statusline_1.clearActiveRun)(this.projectRoot);
|
|
540
541
|
}
|
|
541
542
|
else {
|
|
542
|
-
|
|
543
|
+
// Embed the remaining-time estimate at write time (REQ-STATUSLINE-011)
|
|
544
|
+
// so the status-line render path never opens the DB. Best-effort: any
|
|
545
|
+
// estimator failure just writes a marker without an eta.
|
|
546
|
+
let eta;
|
|
547
|
+
if (runId) {
|
|
548
|
+
try {
|
|
549
|
+
const e = (0, eta_1.estimateRunEta)(this.specQueries.getRawDb(), runId);
|
|
550
|
+
if (e.available)
|
|
551
|
+
eta = { kind: 'range', lowMs: e.lowMs, highMs: e.highMs };
|
|
552
|
+
else if (e.reason === 'paused')
|
|
553
|
+
eta = { kind: 'waiting', sinceMs: e.waitingSinceMs };
|
|
554
|
+
}
|
|
555
|
+
catch { /* no estimate */ }
|
|
556
|
+
}
|
|
557
|
+
(0, statusline_1.writeActiveRun)(this.projectRoot, inputs?.SPEC_ID ?? null, status, eta);
|
|
543
558
|
}
|
|
544
559
|
}
|
|
545
560
|
catch { /* never let the status-line marker affect a workflow run */ }
|
|
@@ -561,7 +576,7 @@ class WorkflowExecutor {
|
|
|
561
576
|
errorMessage,
|
|
562
577
|
metadata: meta,
|
|
563
578
|
});
|
|
564
|
-
this.syncActiveRunMarker(status, run.inputs);
|
|
579
|
+
this.syncActiveRunMarker(status, run.inputs, run.id);
|
|
565
580
|
if (status === 'completed') {
|
|
566
581
|
this.event(run.id, 'run_completed', { duration_ms: now - run.createdAt });
|
|
567
582
|
if (run.isolationEnvId) {
|