@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.
Files changed (200) hide show
  1. package/lib/dist/bin/specship.js +9 -60
  2. package/lib/dist/bin/specship.js.map +1 -1
  3. package/lib/dist/db/spec-queries.d.ts +6 -0
  4. package/lib/dist/db/spec-queries.d.ts.map +1 -1
  5. package/lib/dist/db/spec-queries.js +8 -0
  6. package/lib/dist/db/spec-queries.js.map +1 -1
  7. package/lib/dist/index.d.ts +8 -0
  8. package/lib/dist/index.d.ts.map +1 -1
  9. package/lib/dist/index.js +9 -0
  10. package/lib/dist/index.js.map +1 -1
  11. package/lib/dist/reflect/index.d.ts +1 -1
  12. package/lib/dist/reflect/index.d.ts.map +1 -1
  13. package/lib/dist/reflect/index.js +2 -1
  14. package/lib/dist/reflect/index.js.map +1 -1
  15. package/lib/dist/reflect/miner.d.ts +8 -0
  16. package/lib/dist/reflect/miner.d.ts.map +1 -1
  17. package/lib/dist/reflect/miner.js +64 -36
  18. package/lib/dist/reflect/miner.js.map +1 -1
  19. package/lib/dist/server/cli.js +5 -49
  20. package/lib/dist/server/routes/claude.js +13 -5
  21. package/lib/dist/server/routes/workflow.js +16 -2
  22. package/lib/dist/server/server.js +17 -2
  23. package/lib/dist/server/ssr/md.mjs +83 -0
  24. package/lib/dist/server/ssr/render.mjs +596 -0
  25. package/lib/dist/server/ssr/routes.js +73 -0
  26. package/lib/dist/server/static-handler.js +30 -0
  27. package/lib/dist/statusline/active-run.d.ts +2 -2
  28. package/lib/dist/statusline/active-run.d.ts.map +1 -1
  29. package/lib/dist/statusline/active-run.js +2 -2
  30. package/lib/dist/statusline/active-run.js.map +1 -1
  31. package/lib/dist/statusline/render.d.ts.map +1 -1
  32. package/lib/dist/statusline/render.js +41 -5
  33. package/lib/dist/statusline/render.js.map +1 -1
  34. package/lib/dist/statusline/types.d.ts +15 -0
  35. package/lib/dist/statusline/types.d.ts.map +1 -1
  36. package/lib/dist/workflows/eta.d.ts +42 -0
  37. package/lib/dist/workflows/eta.d.ts.map +1 -0
  38. package/lib/dist/workflows/eta.js +146 -0
  39. package/lib/dist/workflows/eta.js.map +1 -0
  40. package/lib/dist/workflows/executor.d.ts.map +1 -1
  41. package/lib/dist/workflows/executor.js +21 -6
  42. package/lib/dist/workflows/executor.js.map +1 -1
  43. package/lib/node_modules/.package-lock.json +1 -1
  44. package/lib/package.json +3 -3
  45. package/package.json +1 -1
  46. package/lib/dist/web/chunk-2AJCHB7P.js +0 -1
  47. package/lib/dist/web/chunk-2CPLUFCH.js +0 -2
  48. package/lib/dist/web/chunk-2I7L37NS.js +0 -1
  49. package/lib/dist/web/chunk-2IVSOVQZ.js +0 -1
  50. package/lib/dist/web/chunk-2NAWAJB5.js +0 -1
  51. package/lib/dist/web/chunk-2OJBIPE4.js +0 -1
  52. package/lib/dist/web/chunk-3E2WB6D5.js +0 -1
  53. package/lib/dist/web/chunk-3EBFYSCH.js +0 -2
  54. package/lib/dist/web/chunk-3QCQ4BXS.js +0 -1
  55. package/lib/dist/web/chunk-42XVAQ6I.js +0 -1
  56. package/lib/dist/web/chunk-4G7XU55L.js +0 -1
  57. package/lib/dist/web/chunk-4IMMPEYM.js +0 -1
  58. package/lib/dist/web/chunk-4TJQJPCZ.js +0 -1
  59. package/lib/dist/web/chunk-4WZIHTPC.js +0 -1
  60. package/lib/dist/web/chunk-4YVSYOSD.js +0 -1
  61. package/lib/dist/web/chunk-5BQIOYKW.js +0 -1
  62. package/lib/dist/web/chunk-5HGWHUJA.js +0 -1
  63. package/lib/dist/web/chunk-5NTGUSXJ.js +0 -1
  64. package/lib/dist/web/chunk-5Y244R4G.js +0 -1
  65. package/lib/dist/web/chunk-6RRDPT5Z.js +0 -1
  66. package/lib/dist/web/chunk-6VKB2ZWM.js +0 -1
  67. package/lib/dist/web/chunk-7656MA24.js +0 -1
  68. package/lib/dist/web/chunk-7DMFVTU4.js +0 -1
  69. package/lib/dist/web/chunk-7KWBINA7.js +0 -1
  70. package/lib/dist/web/chunk-7SMPKVEP.js +0 -1
  71. package/lib/dist/web/chunk-AHI5XEVX.js +0 -1
  72. package/lib/dist/web/chunk-AS2GV63A.js +0 -1
  73. package/lib/dist/web/chunk-AZJVTPLU.js +0 -1
  74. package/lib/dist/web/chunk-AZUUBUEJ.js +0 -1
  75. package/lib/dist/web/chunk-BLBRMCN2.js +0 -1
  76. package/lib/dist/web/chunk-BMIAXD2V.js +0 -2
  77. package/lib/dist/web/chunk-BPCJLNBS.js +0 -47
  78. package/lib/dist/web/chunk-BUXWEHIY.js +0 -1
  79. package/lib/dist/web/chunk-CGVC666W.js +0 -1
  80. package/lib/dist/web/chunk-DLQPZWSI.css +0 -1
  81. package/lib/dist/web/chunk-DOKZOFKM.js +0 -1
  82. package/lib/dist/web/chunk-DTWIJ3GJ.js +0 -1
  83. package/lib/dist/web/chunk-DYRFLPJA.js +0 -1
  84. package/lib/dist/web/chunk-E3J3CXR5.js +0 -1
  85. package/lib/dist/web/chunk-E73OX2P7.js +0 -1
  86. package/lib/dist/web/chunk-EAXRKDLV.js +0 -1
  87. package/lib/dist/web/chunk-EBKKDHYI.js +0 -1
  88. package/lib/dist/web/chunk-EE7V7Q5P.js +0 -1
  89. package/lib/dist/web/chunk-EKY2FUHU.js +0 -1
  90. package/lib/dist/web/chunk-EP6XOPXH.js +0 -1
  91. package/lib/dist/web/chunk-ESGDLJOJ.js +0 -1
  92. package/lib/dist/web/chunk-ETJG7NCY.js +0 -1
  93. package/lib/dist/web/chunk-EUUEFEDI.js +0 -1
  94. package/lib/dist/web/chunk-EXBUKHH2.js +0 -17
  95. package/lib/dist/web/chunk-FC3R7YHR.js +0 -4
  96. package/lib/dist/web/chunk-FGNZDHTL.js +0 -11
  97. package/lib/dist/web/chunk-FIJW2UNJ.js +0 -1
  98. package/lib/dist/web/chunk-FMV5PXRC.js +0 -5
  99. package/lib/dist/web/chunk-G7RXFHYO.js +0 -1
  100. package/lib/dist/web/chunk-G7VZT5KB.js +0 -3
  101. package/lib/dist/web/chunk-GRZYXPSO.js +0 -7
  102. package/lib/dist/web/chunk-GYGPS3AN.js +0 -1
  103. package/lib/dist/web/chunk-H7AF7YS4.js +0 -1
  104. package/lib/dist/web/chunk-HDZDQILN.js +0 -1
  105. package/lib/dist/web/chunk-HMK6UO6N.js +0 -1
  106. package/lib/dist/web/chunk-IHEE5NYJ.js +0 -1
  107. package/lib/dist/web/chunk-IOB4JJT4.js +0 -1
  108. package/lib/dist/web/chunk-ISNEBICW.js +0 -1
  109. package/lib/dist/web/chunk-J2GZVLHH.js +0 -1
  110. package/lib/dist/web/chunk-JGDK6YKG.js +0 -1
  111. package/lib/dist/web/chunk-JLOJCDIY.js +0 -1
  112. package/lib/dist/web/chunk-JTFXTIPE.js +0 -903
  113. package/lib/dist/web/chunk-K7UD24Z4.js +0 -1
  114. package/lib/dist/web/chunk-KYSTCHAH.js +0 -1
  115. package/lib/dist/web/chunk-LB6JPLX2.js +0 -1
  116. package/lib/dist/web/chunk-LNSVDHCI.js +0 -1
  117. package/lib/dist/web/chunk-LVGIY3SO.js +0 -1
  118. package/lib/dist/web/chunk-LXLHIHEN.js +0 -1
  119. package/lib/dist/web/chunk-M42QOYAE.js +0 -1
  120. package/lib/dist/web/chunk-ML5ULGHY.js +0 -1
  121. package/lib/dist/web/chunk-MNFTHCSJ.js +0 -1
  122. package/lib/dist/web/chunk-N6SS4G6S.js +0 -1
  123. package/lib/dist/web/chunk-NKPK3BR3.js +0 -1
  124. package/lib/dist/web/chunk-NTBJG6SJ.js +0 -1
  125. package/lib/dist/web/chunk-NUDB3Q2Y.js +0 -3
  126. package/lib/dist/web/chunk-OTQR5VFM.js +0 -1
  127. package/lib/dist/web/chunk-OXEF5E3E.js +0 -1
  128. package/lib/dist/web/chunk-P62EJGSF.js +0 -1
  129. package/lib/dist/web/chunk-PCW6R7OP.js +0 -1
  130. package/lib/dist/web/chunk-PGGJPDJG.js +0 -1
  131. package/lib/dist/web/chunk-POCVU4VK.js +0 -2
  132. package/lib/dist/web/chunk-PS6HRYQQ.js +0 -3
  133. package/lib/dist/web/chunk-PUYSJNJR.js +0 -1
  134. package/lib/dist/web/chunk-PZSU53SS.js +0 -1
  135. package/lib/dist/web/chunk-Q2RVFS45.js +0 -1
  136. package/lib/dist/web/chunk-Q7L6LLAK.js +0 -1
  137. package/lib/dist/web/chunk-QCMKJIWY.js +0 -1
  138. package/lib/dist/web/chunk-QH6CF3M3.js +0 -1
  139. package/lib/dist/web/chunk-QIZ65CGB.js +0 -1
  140. package/lib/dist/web/chunk-QPA2REUE.js +0 -1
  141. package/lib/dist/web/chunk-QQ5LD7PI.js +0 -1
  142. package/lib/dist/web/chunk-QR6L3KAC.js +0 -1
  143. package/lib/dist/web/chunk-R2DLK4HO.js +0 -1
  144. package/lib/dist/web/chunk-RD6TVPOT.js +0 -1
  145. package/lib/dist/web/chunk-RKY4EJYJ.js +0 -1
  146. package/lib/dist/web/chunk-RONYWVY7.js +0 -1
  147. package/lib/dist/web/chunk-RXKXYF2C.js +0 -1
  148. package/lib/dist/web/chunk-S5J5WQXB.js +0 -6
  149. package/lib/dist/web/chunk-SQPYSOV6.js +0 -1
  150. package/lib/dist/web/chunk-SWKJRNYY.js +0 -1
  151. package/lib/dist/web/chunk-SYGIPC2P.js +0 -4
  152. package/lib/dist/web/chunk-T7AZ65JP.js +0 -1
  153. package/lib/dist/web/chunk-TCZDVOHD.js +0 -1
  154. package/lib/dist/web/chunk-TPTITA3V.js +0 -1
  155. package/lib/dist/web/chunk-TR335633.js +0 -1
  156. package/lib/dist/web/chunk-TWVVIWKO.js +0 -1
  157. package/lib/dist/web/chunk-U67LRNER.js +0 -1
  158. package/lib/dist/web/chunk-UR5KDXPX.js +0 -1
  159. package/lib/dist/web/chunk-UR6O2GEH.js +0 -1
  160. package/lib/dist/web/chunk-USVLLFVR.js +0 -1
  161. package/lib/dist/web/chunk-UTNMGWTP.js +0 -1
  162. package/lib/dist/web/chunk-V74ZPP4B.js +0 -1
  163. package/lib/dist/web/chunk-VECWMHJP.js +0 -1
  164. package/lib/dist/web/chunk-VUACT35R.js +0 -3
  165. package/lib/dist/web/chunk-VZI7H4SZ.js +0 -1
  166. package/lib/dist/web/chunk-W5TEIONI.js +0 -2
  167. package/lib/dist/web/chunk-WB6YHOD4.js +0 -1
  168. package/lib/dist/web/chunk-WBJ5VEB5.js +0 -1
  169. package/lib/dist/web/chunk-WBT64AWV.js +0 -1
  170. package/lib/dist/web/chunk-WFXJIXZE.js +0 -4
  171. package/lib/dist/web/chunk-WTGYRH3Z.js +0 -298
  172. package/lib/dist/web/chunk-WXTCVDTP.js +0 -1
  173. package/lib/dist/web/chunk-XAUQEKZX.js +0 -1
  174. package/lib/dist/web/chunk-XCDHWLVH.js +0 -1
  175. package/lib/dist/web/chunk-XKG5X37F.js +0 -1
  176. package/lib/dist/web/chunk-Y3H6FFUZ.js +0 -1
  177. package/lib/dist/web/chunk-Y4F5ULGJ.js +0 -1
  178. package/lib/dist/web/chunk-YEGKAAEE.js +0 -1
  179. package/lib/dist/web/chunk-YM2KU57F.js +0 -1
  180. package/lib/dist/web/chunk-YRERBP6T.js +0 -1
  181. package/lib/dist/web/chunk-YV5LB22R.js +0 -1
  182. package/lib/dist/web/chunk-YWIRU745.js +0 -1
  183. package/lib/dist/web/chunk-ZLV4VCDG.js +0 -3
  184. package/lib/dist/web/chunk-ZTVI5KFF.js +0 -1
  185. package/lib/dist/web/favicon-16.png +0 -0
  186. package/lib/dist/web/favicon-180.png +0 -0
  187. package/lib/dist/web/favicon-32.png +0 -0
  188. package/lib/dist/web/favicon-512.png +0 -0
  189. package/lib/dist/web/favicon-small.svg +0 -15
  190. package/lib/dist/web/favicon.ico +0 -0
  191. package/lib/dist/web/favicon.svg +0 -20
  192. package/lib/dist/web/icon-192.png +0 -0
  193. package/lib/dist/web/icon-512.png +0 -0
  194. package/lib/dist/web/index.html +0 -146
  195. package/lib/dist/web/main-ESADRXN2.css +0 -1
  196. package/lib/dist/web/main-JT2RR3JS.js +0 -1
  197. package/lib/dist/web/manifest.webmanifest +0 -15
  198. package/lib/dist/web/media/codicon-LN6W7LCM.ttf +0 -0
  199. package/lib/dist/web/sw.js +0 -69
  200. /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;AAGpC,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAO/F;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"}
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,wCAOC;AAGD,wCAMC;AAGD,sCAGC;AA3BD,uCAAyB;AAEzB,mCAAuE;AAEvE,mEAAmE;AACnE,SAAgB,cAAc,CAAC,WAAmB,EAAE,MAAqB,EAAE,MAAc;IACvF,MAAM,IAAI,GAAc,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACxE,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
+ {"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;AA+CD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CA6DxD"}
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
- parts.push(c(color, `CTX ${bar(context)} ${Math.round(context)}%${hint}`));
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
- parts.push(c(COLOR.calls, `${label} ${bar(w.pctUsed)} ${Math.round(w.pctUsed)}%${reset}`));
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
- return `${orn} ${brand}${sep}${parts.join(sep)} ${orn}`;
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":"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"}
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;CACnB"}
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;AAGzD,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;YAWb,QAAQ;YA6CR,aAAa;IAyB3B,OAAO,CAAC,KAAK;CA2Bd;AAMD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CA6BnD"}
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
- (0, statusline_1.writeActiveRun)(this.projectRoot, inputs?.SPEC_ID ?? null, status);
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) {