gsd-pi 2.82.0-dev.2841a1e44 → 2.82.0-dev.9d5798940
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/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
- package/dist/resources/extensions/gsd/auto-post-unit.js +69 -8
- package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
- package/dist/resources/extensions/gsd/auto-start.js +7 -3
- package/dist/resources/extensions/gsd/auto-worktree.js +96 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +4 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +13 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +17 -1
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +2 -2
- package/dist/resources/extensions/gsd/export-html.js +27 -425
- package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +8 -3
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -1
- package/dist/resources/extensions/gsd/unit-context-manifest.js +7 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +28 -7
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +2 -0
- package/dist/resources/extensions/visual-brief/prompts.js +29 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -7
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
- package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-6a95bc41e0f7ec89.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
- package/src/resources/extensions/gsd/auto-post-unit.ts +76 -6
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
- package/src/resources/extensions/gsd/auto-start.ts +7 -3
- package/src/resources/extensions/gsd/auto-worktree.ts +104 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +16 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +17 -1
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +3 -3
- package/src/resources/extensions/gsd/export-html.ts +27 -427
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
- package/src/resources/extensions/gsd/native-git-bridge.ts +8 -3
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +57 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +65 -7
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +31 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +12 -9
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +34 -7
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +2 -0
- package/src/resources/extensions/visual-brief/prompts.ts +37 -1
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +40 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
- package/dist/web/standalone/.next/static/css/0262768ec1b89d34.css +0 -1
- package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
- package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → BdZQhe8yKl6bdKLiXVEzh}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → BdZQhe8yKl6bdKLiXVEzh}/_ssgManifest.js +0 -0
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* Design: Linear-inspired — restrained palette, geometric status, no emoji.
|
|
21
21
|
*/
|
|
22
22
|
import { formatDateShort, formatDuration } from '../shared/format-utils.js';
|
|
23
|
+
import { esc, renderHtmlShell } from '../shared/html-shell.js';
|
|
23
24
|
import { formatCost, formatTokenCount } from './metrics.js';
|
|
24
25
|
export function generateHtmlReport(data, opts) {
|
|
25
26
|
const generated = new Date().toISOString();
|
|
@@ -37,69 +38,35 @@ export function generateHtmlReport(data, opts) {
|
|
|
37
38
|
buildStatsSection(data),
|
|
38
39
|
buildDiscussionSection(data),
|
|
39
40
|
];
|
|
40
|
-
const
|
|
41
|
-
? ` <span class="sep">/</span> <span class="mono accent">${esc(opts.milestoneId)}</span>`
|
|
42
|
-
: '';
|
|
41
|
+
const title = opts.milestoneId ? `${opts.projectName} / ${opts.milestoneId}` : opts.projectName;
|
|
43
42
|
const backLink = opts.indexRelPath
|
|
44
43
|
? `<a class="back-link" href="${esc(opts.indexRelPath)}">All Reports</a>`
|
|
45
44
|
: '';
|
|
46
|
-
return
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
<nav class="toc" aria-label="Report sections">
|
|
72
|
-
<ul>
|
|
73
|
-
<li><a href="#summary">Summary</a></li>
|
|
74
|
-
<li><a href="#blockers">Blockers</a></li>
|
|
75
|
-
<li><a href="#progress">Progress</a></li>
|
|
76
|
-
<li><a href="#timeline">Timeline</a></li>
|
|
77
|
-
<li><a href="#depgraph">Dependencies</a></li>
|
|
78
|
-
<li><a href="#metrics">Metrics</a></li>
|
|
79
|
-
<li><a href="#health">Health</a></li>
|
|
80
|
-
<li><a href="#changelog">Changelog</a></li>
|
|
81
|
-
<li><a href="#knowledge">Knowledge</a></li>
|
|
82
|
-
<li><a href="#captures">Captures</a></li>
|
|
83
|
-
<li><a href="#stats">Artifacts</a></li>
|
|
84
|
-
<li><a href="#discussion">Planning</a></li>
|
|
85
|
-
</ul>
|
|
86
|
-
</nav>
|
|
87
|
-
<main>
|
|
88
|
-
${sections.join('\n')}
|
|
89
|
-
</main>
|
|
90
|
-
<footer>
|
|
91
|
-
<div class="footer-inner">
|
|
92
|
-
<span>GSD v${esc(opts.gsdVersion)}</span>
|
|
93
|
-
<span class="sep">/</span>
|
|
94
|
-
<span>${esc(opts.projectName)}</span>
|
|
95
|
-
${opts.milestoneId ? `<span class="sep">/</span><span class="mono">${esc(opts.milestoneId)}</span>` : ''}
|
|
96
|
-
<span class="sep">/</span>
|
|
97
|
-
<span>${formatDateLong(generated)}</span>
|
|
98
|
-
</div>
|
|
99
|
-
</footer>
|
|
100
|
-
<script>${JS}</script>
|
|
101
|
-
</body>
|
|
102
|
-
</html>`;
|
|
45
|
+
return renderHtmlShell({
|
|
46
|
+
title,
|
|
47
|
+
documentTitle: `GSD Report — ${opts.projectName}${opts.milestoneId ? ` — ${opts.milestoneId}` : ''}`,
|
|
48
|
+
subtitle: opts.projectPath,
|
|
49
|
+
kind: 'Report',
|
|
50
|
+
version: opts.gsdVersion,
|
|
51
|
+
generatedAt: generated,
|
|
52
|
+
headerActionsHtml: backLink,
|
|
53
|
+
footerNote: opts.milestoneId ? `${opts.projectName} / ${opts.milestoneId}` : opts.projectName,
|
|
54
|
+
toc: [
|
|
55
|
+
{ href: '#summary', label: 'Summary' },
|
|
56
|
+
{ href: '#blockers', label: 'Blockers' },
|
|
57
|
+
{ href: '#progress', label: 'Progress' },
|
|
58
|
+
{ href: '#timeline', label: 'Timeline' },
|
|
59
|
+
{ href: '#depgraph', label: 'Dependencies' },
|
|
60
|
+
{ href: '#metrics', label: 'Metrics' },
|
|
61
|
+
{ href: '#health', label: 'Health' },
|
|
62
|
+
{ href: '#changelog', label: 'Changelog' },
|
|
63
|
+
{ href: '#knowledge', label: 'Knowledge' },
|
|
64
|
+
{ href: '#captures', label: 'Captures' },
|
|
65
|
+
{ href: '#stats', label: 'Artifacts' },
|
|
66
|
+
{ href: '#discussion', label: 'Planning' },
|
|
67
|
+
],
|
|
68
|
+
mainHtml: sections.join('\n'),
|
|
69
|
+
});
|
|
103
70
|
}
|
|
104
71
|
// ─── Section: Summary ─────────────────────────────────────────────────────────
|
|
105
72
|
function buildSummarySection(data, opts, _generated) {
|
|
@@ -904,368 +871,3 @@ function hRow(label, value, status) {
|
|
|
904
871
|
}
|
|
905
872
|
function shortModel(m) { return m.replace(/^claude-/, '').replace(/^anthropic\//, ''); }
|
|
906
873
|
function truncStr(s, n) { return s.length > n ? s.slice(0, n - 1) + '\u2026' : s; }
|
|
907
|
-
function formatDateLong(iso) {
|
|
908
|
-
try {
|
|
909
|
-
const d = new Date(iso);
|
|
910
|
-
return d.toLocaleString('en-US', { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric', hour: '2-digit', minute: '2-digit', timeZoneName: 'short' });
|
|
911
|
-
}
|
|
912
|
-
catch {
|
|
913
|
-
return iso;
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
function esc(s) {
|
|
917
|
-
if (s == null)
|
|
918
|
-
return '';
|
|
919
|
-
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
|
920
|
-
}
|
|
921
|
-
// ─── CSS ───────────────────────────────────────────────────────────────────────
|
|
922
|
-
// Linear-inspired: restrained palette, one accent, no emoji, no gradients.
|
|
923
|
-
const CSS = `
|
|
924
|
-
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
|
925
|
-
:root{
|
|
926
|
-
--bg-0:#0f1115;--bg-1:#16181d;--bg-2:#1e2028;--bg-3:#272a33;
|
|
927
|
-
--border-1:#2b2e38;--border-2:#3b3f4c;
|
|
928
|
-
--text-0:#ededef;--text-1:#a1a1aa;--text-2:#71717a;
|
|
929
|
-
--accent:#5e6ad2;--accent-subtle:rgba(94,106,210,.12);
|
|
930
|
-
--ok:#22c55e;--ok-subtle:rgba(34,197,94,.12);--warn:#ef4444;--caution:#eab308;
|
|
931
|
-
/* Chart palette — 6 hues for bar charts */
|
|
932
|
-
--c0:#5e6ad2;--c1:#e5796d;--c2:#14b8a6;--c3:#a78bfa;--c4:#f59e0b;--c5:#10b981;
|
|
933
|
-
/* Token breakdown — 4 distinct hues */
|
|
934
|
-
--tk-input:#5e6ad2;--tk-output:#e5796d;--tk-cache-r:#2dd4bf;--tk-cache-w:#64748b;
|
|
935
|
-
--font:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
|
|
936
|
-
--mono:'JetBrains Mono','Fira Code',ui-monospace,SFMono-Regular,monospace;
|
|
937
|
-
}
|
|
938
|
-
html{scroll-behavior:smooth;font-size:13px}
|
|
939
|
-
body{background:var(--bg-0);color:var(--text-0);font-family:var(--font);line-height:1.6;-webkit-font-smoothing:antialiased}
|
|
940
|
-
a{color:var(--accent);text-decoration:none}
|
|
941
|
-
a:hover{text-decoration:underline}
|
|
942
|
-
code{font-family:var(--mono);font-size:12px;background:var(--bg-3);padding:1px 5px;border-radius:3px}
|
|
943
|
-
.mono{font-family:var(--mono);font-size:12px}
|
|
944
|
-
.muted{color:var(--text-2)}
|
|
945
|
-
.accent{color:var(--accent)}
|
|
946
|
-
.sep{color:var(--border-2);margin:0 4px}
|
|
947
|
-
.empty{color:var(--text-2);padding:8px 0;font-size:13px}
|
|
948
|
-
.indent{padding-left:12px}
|
|
949
|
-
.num{font-variant-numeric:tabular-nums;text-align:right}
|
|
950
|
-
|
|
951
|
-
/* Status dots — geometric, no emoji */
|
|
952
|
-
.dot{display:inline-block;width:8px;height:8px;border-radius:50%;flex-shrink:0;vertical-align:middle}
|
|
953
|
-
.dot-sm{width:6px;height:6px}
|
|
954
|
-
.dot-complete{background:var(--ok);opacity:.6}
|
|
955
|
-
.dot-active{background:var(--accent)}
|
|
956
|
-
.dot-pending{background:transparent;border:1.5px solid var(--border-2)}
|
|
957
|
-
.dot-parked{background:var(--warn);opacity:.5}
|
|
958
|
-
|
|
959
|
-
/* Header */
|
|
960
|
-
header{background:var(--bg-1);border-bottom:1px solid var(--border-1);padding:12px 32px;position:sticky;top:0;z-index:200}
|
|
961
|
-
.header-inner{display:flex;align-items:center;gap:16px;max-width:1280px;margin:0 auto}
|
|
962
|
-
.branding{display:flex;align-items:baseline;gap:6px;flex-shrink:0}
|
|
963
|
-
.logo{font-size:18px;font-weight:800;letter-spacing:-.5px;color:var(--text-0)}
|
|
964
|
-
.version{font-size:10px;color:var(--text-2);font-family:var(--mono)}
|
|
965
|
-
.header-meta{flex:1;min-width:0}
|
|
966
|
-
.header-meta h1{font-size:15px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
967
|
-
.header-path{font-size:11px;color:var(--text-2);font-family:var(--mono);display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
968
|
-
.header-right{text-align:right;flex-shrink:0;display:flex;flex-direction:column;align-items:flex-end;gap:4px}
|
|
969
|
-
.generated{font-size:11px;color:var(--text-2)}
|
|
970
|
-
.back-link{font-size:12px;color:var(--text-1)}
|
|
971
|
-
.back-link:hover{color:var(--accent)}
|
|
972
|
-
|
|
973
|
-
/* TOC nav */
|
|
974
|
-
.toc{background:var(--bg-1);border-bottom:1px solid var(--border-1);overflow-x:auto}
|
|
975
|
-
.toc ul{display:flex;list-style:none;max-width:1280px;margin:0 auto;padding:0 32px}
|
|
976
|
-
.toc a{display:inline-block;padding:8px 12px;color:var(--text-2);font-size:12px;font-weight:500;border-bottom:2px solid transparent;transition:color .12s,border-color .12s;white-space:nowrap;text-decoration:none}
|
|
977
|
-
.toc a:hover{color:var(--text-0);border-bottom-color:var(--border-2)}
|
|
978
|
-
.toc a.active{color:var(--text-0);border-bottom-color:var(--accent)}
|
|
979
|
-
|
|
980
|
-
/* Layout */
|
|
981
|
-
main{max-width:1280px;margin:0 auto;padding:32px;display:flex;flex-direction:column;gap:48px}
|
|
982
|
-
section{scroll-margin-top:82px}
|
|
983
|
-
section>h2{font-size:14px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--text-1);margin-bottom:16px;padding-bottom:8px;border-bottom:1px solid var(--border-1);display:flex;align-items:center;gap:8px}
|
|
984
|
-
h3{font-size:13px;font-weight:600;color:var(--text-1);margin:20px 0 8px}
|
|
985
|
-
.count{font-size:11px;font-weight:500;color:var(--text-2);background:var(--bg-3);border-radius:3px;padding:1px 6px}
|
|
986
|
-
.count-warn{color:var(--caution)}
|
|
987
|
-
|
|
988
|
-
/* KV grid (stats/metrics) */
|
|
989
|
-
.kv-grid{display:flex;flex-wrap:wrap;gap:1px;background:var(--border-1);border:1px solid var(--border-1);border-radius:4px;overflow:hidden;margin-bottom:16px}
|
|
990
|
-
.kv{background:var(--bg-1);padding:10px 16px;display:flex;flex-direction:column;gap:2px;min-width:110px;flex:1}
|
|
991
|
-
.kv-val{font-size:18px;font-weight:600;color:var(--text-0);font-variant-numeric:tabular-nums}
|
|
992
|
-
.kv-lbl{font-size:10px;color:var(--text-2);text-transform:uppercase;letter-spacing:.4px}
|
|
993
|
-
|
|
994
|
-
/* Progress bar */
|
|
995
|
-
.progress-wrap{display:flex;align-items:center;gap:10px;margin-bottom:12px}
|
|
996
|
-
.progress-track{flex:1;height:4px;background:var(--bg-3);border-radius:2px;overflow:hidden}
|
|
997
|
-
.progress-fill{height:100%;background:var(--accent);border-radius:2px}
|
|
998
|
-
.progress-label{font-size:12px;font-weight:600;color:var(--text-1);min-width:40px;text-align:right}
|
|
999
|
-
.active-info{font-size:12px;color:var(--text-1);margin-bottom:4px}
|
|
1000
|
-
.activity-line{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--text-1);padding:6px 0}
|
|
1001
|
-
|
|
1002
|
-
/* Tables */
|
|
1003
|
-
.tbl{width:100%;border-collapse:collapse;font-size:12px}
|
|
1004
|
-
.tbl th{color:var(--text-2);font-weight:500;padding:6px 12px;text-align:left;border-bottom:1px solid var(--border-1);font-size:11px;text-transform:uppercase;letter-spacing:.3px;white-space:nowrap}
|
|
1005
|
-
.tbl td{padding:6px 12px;border-bottom:1px solid var(--border-1);vertical-align:top}
|
|
1006
|
-
.tbl tr:last-child td{border-bottom:none}
|
|
1007
|
-
.tbl tbody tr:hover td{background:var(--accent-subtle)}
|
|
1008
|
-
.tbl-kv td:first-child{color:var(--text-2);width:180px}
|
|
1009
|
-
.table-scroll{overflow-x:auto;border:1px solid var(--border-1);border-radius:4px}
|
|
1010
|
-
.table-scroll .tbl{border:none}
|
|
1011
|
-
|
|
1012
|
-
/* Health */
|
|
1013
|
-
.h-ok td:first-child{color:var(--text-1)}
|
|
1014
|
-
.h-caution td{color:var(--caution)}
|
|
1015
|
-
.h-warn td{color:var(--warn)}
|
|
1016
|
-
|
|
1017
|
-
/* Labels */
|
|
1018
|
-
.label{font-size:10px;font-weight:500;color:var(--accent);text-transform:uppercase;letter-spacing:.4px}
|
|
1019
|
-
.risk{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.3px;flex-shrink:0}
|
|
1020
|
-
.risk-low{color:var(--text-2)}
|
|
1021
|
-
.risk-medium{color:var(--caution)}
|
|
1022
|
-
.risk-high{color:var(--warn)}
|
|
1023
|
-
.risk-unknown{color:var(--text-2)}
|
|
1024
|
-
|
|
1025
|
-
/* Tags */
|
|
1026
|
-
.tag-row{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px}
|
|
1027
|
-
.tag{font-size:11px;font-family:var(--mono);color:var(--text-2);background:var(--bg-3);border-radius:3px;padding:1px 6px}
|
|
1028
|
-
|
|
1029
|
-
/* Verification */
|
|
1030
|
-
.verif{font-size:12px;color:var(--text-1);padding:4px 0;margin-bottom:6px}
|
|
1031
|
-
.verif-blocker{color:var(--warn)}
|
|
1032
|
-
|
|
1033
|
-
/* Detail blocks */
|
|
1034
|
-
.detail-block{font-size:12px;color:var(--text-2);margin-bottom:6px}
|
|
1035
|
-
.detail-label{font-weight:600;color:var(--text-1);display:block;margin-bottom:2px}
|
|
1036
|
-
.detail-block ul{padding-left:16px;margin-top:2px}
|
|
1037
|
-
.detail-block li{margin-bottom:1px}
|
|
1038
|
-
|
|
1039
|
-
/* Progress tree */
|
|
1040
|
-
.ms-block{border:1px solid var(--border-1);border-radius:4px;overflow:hidden;margin-bottom:8px}
|
|
1041
|
-
.ms-summary{display:flex;align-items:center;gap:8px;padding:10px 14px;cursor:pointer;list-style:none;background:var(--bg-1);user-select:none;font-size:13px}
|
|
1042
|
-
.ms-summary:hover{background:var(--bg-2)}
|
|
1043
|
-
.ms-summary::-webkit-details-marker{display:none}
|
|
1044
|
-
.ms-id{font-weight:600}
|
|
1045
|
-
.ms-title{flex:1;font-weight:500;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1046
|
-
.ms-body{padding:6px 12px 8px 24px;display:flex;flex-direction:column;gap:4px}
|
|
1047
|
-
|
|
1048
|
-
.sl-block{border:1px solid var(--border-1);border-radius:3px;overflow:hidden}
|
|
1049
|
-
.sl-summary{display:flex;align-items:center;gap:6px;padding:6px 10px;cursor:pointer;list-style:none;background:var(--bg-2);font-size:12px;user-select:none}
|
|
1050
|
-
.sl-summary:hover{background:var(--bg-3)}
|
|
1051
|
-
.sl-summary::-webkit-details-marker{display:none}
|
|
1052
|
-
.sl-crit{border-left:2px solid var(--accent)}
|
|
1053
|
-
.sl-deps::before{content:'\\2190 ';color:var(--border-2)}
|
|
1054
|
-
.sl-detail{padding:8px 12px;background:var(--bg-0);border-top:1px solid var(--border-1)}
|
|
1055
|
-
|
|
1056
|
-
.task-list{list-style:none;padding:4px 0 0;display:flex;flex-direction:column;gap:2px}
|
|
1057
|
-
.task-row{display:flex;align-items:center;gap:6px;font-size:12px;padding:3px 6px;border-radius:2px}
|
|
1058
|
-
|
|
1059
|
-
/* Dep graph */
|
|
1060
|
-
.dep-block{margin-bottom:28px}
|
|
1061
|
-
.dep-legend{display:flex;gap:14px;font-size:12px;color:var(--text-2);margin-bottom:8px;align-items:center}
|
|
1062
|
-
.dep-legend span{display:flex;align-items:center;gap:4px}
|
|
1063
|
-
.dep-wrap{overflow-x:auto;background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:16px}
|
|
1064
|
-
.dep-svg{display:block}
|
|
1065
|
-
.edge{fill:none;stroke:var(--border-2);stroke-width:1.5}
|
|
1066
|
-
.edge-crit{stroke:var(--accent);stroke-width:2}
|
|
1067
|
-
.node rect{fill:var(--bg-2);stroke:var(--border-2);stroke-width:1}
|
|
1068
|
-
.n-done rect{fill:var(--ok-subtle);stroke:rgba(34,197,94,.4)}
|
|
1069
|
-
.n-active rect{fill:var(--accent-subtle);stroke:var(--accent)}
|
|
1070
|
-
.n-crit rect{stroke:var(--accent)!important;stroke-width:1.5!important}
|
|
1071
|
-
.n-id{font-family:var(--mono);font-size:10px;fill:var(--text-1);font-weight:600;text-anchor:middle}
|
|
1072
|
-
.n-title{font-size:9px;fill:var(--text-2);text-anchor:middle}
|
|
1073
|
-
.n-active .n-id{fill:var(--accent)}
|
|
1074
|
-
|
|
1075
|
-
/* Metrics */
|
|
1076
|
-
.token-block{background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:14px;margin-bottom:16px}
|
|
1077
|
-
.token-bar{display:flex;height:16px;border-radius:2px;overflow:hidden;gap:1px;margin-bottom:8px}
|
|
1078
|
-
.tseg{height:100%;min-width:2px}
|
|
1079
|
-
.seg-1{background:var(--tk-input)}
|
|
1080
|
-
.seg-2{background:var(--tk-output)}
|
|
1081
|
-
.seg-3{background:var(--tk-cache-r)}
|
|
1082
|
-
.seg-4{background:var(--tk-cache-w)}
|
|
1083
|
-
.token-legend{display:flex;flex-wrap:wrap;gap:12px}
|
|
1084
|
-
.leg-item{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--text-2)}
|
|
1085
|
-
.leg-dot{width:8px;height:8px;border-radius:2px;flex-shrink:0}
|
|
1086
|
-
.chart-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px;margin-bottom:16px}
|
|
1087
|
-
.chart-block{background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:14px}
|
|
1088
|
-
.bar-row{display:grid;grid-template-columns:120px 1fr 68px;align-items:center;gap:6px;margin-bottom:2px}
|
|
1089
|
-
.bar-lbl{font-size:12px;color:var(--text-2);text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1090
|
-
.bar-track{height:14px;background:var(--bg-3);border-radius:2px;overflow:hidden}
|
|
1091
|
-
.bar-fill{height:100%;border-radius:2px;background:var(--c0)}
|
|
1092
|
-
.bar-c0{background:var(--c0)}.bar-c1{background:var(--c1)}.bar-c2{background:var(--c2)}
|
|
1093
|
-
.bar-c3{background:var(--c3)}.bar-c4{background:var(--c4)}.bar-c5{background:var(--c5)}
|
|
1094
|
-
.bar-val{font-size:11px;font-variant-numeric:tabular-nums;color:var(--text-1)}
|
|
1095
|
-
.bar-sub{font-size:10px;color:var(--text-2);padding-left:128px;margin-bottom:6px}
|
|
1096
|
-
|
|
1097
|
-
/* Changelog */
|
|
1098
|
-
.cl-entry{border-bottom:1px solid var(--border-1);padding:12px 0}
|
|
1099
|
-
.cl-entry:last-child{border-bottom:none}
|
|
1100
|
-
.cl-header{display:flex;align-items:center;gap:8px;margin-bottom:4px}
|
|
1101
|
-
.cl-title{flex:1;font-weight:500}
|
|
1102
|
-
.cl-date{margin-left:auto;white-space:nowrap}
|
|
1103
|
-
.cl-liner{font-size:13px;color:var(--text-1);margin-bottom:6px}
|
|
1104
|
-
.files-detail summary{font-size:12px;cursor:pointer}
|
|
1105
|
-
.file-list{list-style:none;padding-left:10px;margin-top:4px;display:flex;flex-direction:column;gap:2px}
|
|
1106
|
-
.file-list li{font-size:12px;color:var(--text-1)}
|
|
1107
|
-
|
|
1108
|
-
/* Footer */
|
|
1109
|
-
footer{border-top:1px solid var(--border-1);padding:20px 32px;margin-top:40px}
|
|
1110
|
-
.footer-inner{display:flex;align-items:center;gap:6px;justify-content:center;font-size:11px;color:var(--text-2)}
|
|
1111
|
-
|
|
1112
|
-
/* Executive summary & ETA */
|
|
1113
|
-
.exec-summary{font-size:13px;color:var(--text-1);margin-bottom:12px;line-height:1.7}
|
|
1114
|
-
.eta-line{font-size:12px;color:var(--accent);margin-top:4px}
|
|
1115
|
-
|
|
1116
|
-
/* Cost over time chart */
|
|
1117
|
-
.cost-svg{display:block;margin:8px 0;background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px}
|
|
1118
|
-
.cost-line{fill:none;stroke:var(--accent);stroke-width:2}
|
|
1119
|
-
.cost-area{fill:var(--accent-subtle);stroke:none}
|
|
1120
|
-
.cost-axis{fill:var(--text-2);font-family:var(--mono);font-size:10px}
|
|
1121
|
-
.cost-grid{stroke:var(--border-1);stroke-width:1;stroke-dasharray:4,4}
|
|
1122
|
-
|
|
1123
|
-
/* Budget burndown */
|
|
1124
|
-
.burndown-wrap{background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:14px;margin-bottom:16px}
|
|
1125
|
-
.burndown-bar{display:flex;height:20px;border-radius:3px;overflow:hidden;gap:1px;margin-bottom:8px}
|
|
1126
|
-
.burndown-spent{background:var(--accent);height:100%}
|
|
1127
|
-
.burndown-projected{background:var(--caution);height:100%;opacity:.6}
|
|
1128
|
-
.burndown-overshoot{background:var(--warn);height:100%;opacity:.7}
|
|
1129
|
-
.burndown-legend{display:flex;flex-wrap:wrap;gap:12px;font-size:11px;color:var(--text-2)}
|
|
1130
|
-
.burndown-legend span{display:flex;align-items:center;gap:4px}
|
|
1131
|
-
.burndown-dot{display:inline-block;width:8px;height:8px;border-radius:2px}
|
|
1132
|
-
|
|
1133
|
-
/* Blockers */
|
|
1134
|
-
.blocker-card{border-left:3px solid var(--warn);background:var(--bg-1);border-radius:0 4px 4px 0;padding:10px 14px;margin-bottom:8px}
|
|
1135
|
-
.blocker-id{font-family:var(--mono);font-size:12px;color:var(--warn);margin-bottom:2px}
|
|
1136
|
-
.blocker-text{font-size:12px;color:var(--text-1)}
|
|
1137
|
-
.blocker-risk{font-size:11px;color:var(--caution);margin-top:2px}
|
|
1138
|
-
|
|
1139
|
-
/* Gantt */
|
|
1140
|
-
.gantt-wrap{overflow-x:auto;background:var(--bg-1);border:1px solid var(--border-1);border-radius:4px;padding:16px;margin-top:16px}
|
|
1141
|
-
.gantt-svg{display:block}
|
|
1142
|
-
.gantt-bar-done{fill:var(--ok);opacity:.7}
|
|
1143
|
-
.gantt-bar-active{fill:var(--accent)}
|
|
1144
|
-
.gantt-bar-pending{fill:var(--border-2)}
|
|
1145
|
-
.gantt-label{fill:var(--text-2);font-family:var(--mono);font-size:10px}
|
|
1146
|
-
.gantt-axis{fill:var(--text-2);font-family:var(--mono);font-size:9px}
|
|
1147
|
-
|
|
1148
|
-
/* Interactive */
|
|
1149
|
-
.tl-filter{display:block;width:100%;padding:6px 10px;margin-bottom:8px;background:var(--bg-2);border:1px solid var(--border-1);border-radius:4px;color:var(--text-0);font-size:12px;font-family:var(--font);outline:none}
|
|
1150
|
-
.tl-filter:focus{border-color:var(--accent)}
|
|
1151
|
-
.tl-filter::placeholder{color:var(--text-2)}
|
|
1152
|
-
.sec-toggle{background:none;border:1px solid var(--border-2);color:var(--text-2);width:20px;height:20px;border-radius:3px;cursor:pointer;font-size:14px;line-height:1;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}
|
|
1153
|
-
.sec-toggle:hover{border-color:var(--text-1);color:var(--text-1)}
|
|
1154
|
-
.theme-toggle{background:var(--bg-3);border:1px solid var(--border-2);color:var(--text-1);padding:4px 10px;border-radius:4px;cursor:pointer;font-size:11px;font-family:var(--font)}
|
|
1155
|
-
.theme-toggle:hover{border-color:var(--accent);color:var(--accent)}
|
|
1156
|
-
|
|
1157
|
-
/* Light theme */
|
|
1158
|
-
.light-theme{--bg-0:#fff;--bg-1:#fafafa;--bg-2:#f5f5f5;--bg-3:#ebebeb;--border-1:#e5e5e5;--border-2:#d4d4d4;--text-0:#1a1a1a;--text-1:#525252;--text-2:#a3a3a3;--accent:#4f46e5;--accent-subtle:rgba(79,70,229,.08);--ok:#16a34a;--ok-subtle:rgba(22,163,74,.08);--warn:#dc2626;--caution:#ca8a04;--c0:#4f46e5;--c1:#dc2626;--c2:#0d9488;--c3:#7c3aed;--c4:#d97706;--c5:#059669;--tk-input:#4f46e5;--tk-output:#dc2626;--tk-cache-r:#0d9488;--tk-cache-w:#64748b}
|
|
1159
|
-
|
|
1160
|
-
/* Responsive */
|
|
1161
|
-
@media(max-width:768px){
|
|
1162
|
-
header{padding:10px 16px}
|
|
1163
|
-
.header-inner{flex-wrap:wrap;gap:8px}
|
|
1164
|
-
.header-meta h1{font-size:13px}
|
|
1165
|
-
main{padding:16px}
|
|
1166
|
-
.kv-grid{gap:1px}
|
|
1167
|
-
.kv{min-width:80px;padding:8px 10px}
|
|
1168
|
-
.kv-val{font-size:14px}
|
|
1169
|
-
.chart-row{grid-template-columns:1fr}
|
|
1170
|
-
.toc ul{padding:0 16px}
|
|
1171
|
-
.toc a{padding:6px 8px;font-size:11px}
|
|
1172
|
-
.bar-row{grid-template-columns:80px 1fr 56px}
|
|
1173
|
-
.ms-body{padding-left:12px}
|
|
1174
|
-
}
|
|
1175
|
-
@media(max-width:480px){
|
|
1176
|
-
.kv{min-width:60px;padding:6px 8px}
|
|
1177
|
-
.kv-val{font-size:12px}
|
|
1178
|
-
.kv-lbl{font-size:9px}
|
|
1179
|
-
.bar-row{grid-template-columns:60px 1fr 48px}
|
|
1180
|
-
.bar-lbl{font-size:10px}
|
|
1181
|
-
.toc ul{flex-wrap:wrap}
|
|
1182
|
-
.header-right{display:none}
|
|
1183
|
-
.gantt-wrap{overflow-x:auto}
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
|
-
/* Print */
|
|
1187
|
-
@media print{
|
|
1188
|
-
header,nav.toc{position:static}
|
|
1189
|
-
body{background:#fff;color:#1a1a1a}
|
|
1190
|
-
:root{--bg-0:#fff;--bg-1:#fafafa;--bg-2:#f5f5f5;--bg-3:#ebebeb;--border-1:#e5e5e5;--border-2:#d4d4d4;--text-0:#1a1a1a;--text-1:#525252;--text-2:#a3a3a3;--accent:#4f46e5;--ok:#16a34a;--ok-subtle:rgba(22,163,74,.08);--c0:#4f46e5;--c1:#dc2626;--c2:#0d9488;--c3:#7c3aed;--c4:#d97706;--c5:#059669;--tk-input:#4f46e5;--tk-output:#dc2626;--tk-cache-r:#0d9488;--tk-cache-w:#64748b}
|
|
1191
|
-
section{page-break-inside:avoid}
|
|
1192
|
-
.table-scroll{overflow:visible}
|
|
1193
|
-
}
|
|
1194
|
-
`;
|
|
1195
|
-
// ─── JS ────────────────────────────────────────────────────────────────────────
|
|
1196
|
-
const JS = `
|
|
1197
|
-
(function(){
|
|
1198
|
-
const sections=document.querySelectorAll('section[id]');
|
|
1199
|
-
const links=document.querySelectorAll('.toc a');
|
|
1200
|
-
if(!sections.length||!links.length)return;
|
|
1201
|
-
const obs=new IntersectionObserver(entries=>{
|
|
1202
|
-
for(const e of entries){
|
|
1203
|
-
if(!e.isIntersecting)continue;
|
|
1204
|
-
for(const l of links)l.classList.remove('active');
|
|
1205
|
-
const a=document.querySelector('.toc a[href="#'+e.target.id+'"]');
|
|
1206
|
-
if(a)a.classList.add('active');
|
|
1207
|
-
}
|
|
1208
|
-
},{rootMargin:'-10% 0px -80% 0px',threshold:0});
|
|
1209
|
-
for(const s of sections)obs.observe(s);
|
|
1210
|
-
})();
|
|
1211
|
-
(function(){
|
|
1212
|
-
var tl=document.getElementById('timeline');
|
|
1213
|
-
if(!tl)return;
|
|
1214
|
-
var table=tl.querySelector('.tbl');
|
|
1215
|
-
if(!table)return;
|
|
1216
|
-
var input=document.createElement('input');
|
|
1217
|
-
input.className='tl-filter';
|
|
1218
|
-
input.placeholder='Filter timeline\\u2026';
|
|
1219
|
-
input.type='text';
|
|
1220
|
-
table.parentNode.insertBefore(input,table);
|
|
1221
|
-
var rows=table.querySelectorAll('tbody tr');
|
|
1222
|
-
input.addEventListener('input',function(){
|
|
1223
|
-
var q=this.value.toLowerCase();
|
|
1224
|
-
for(var i=0;i<rows.length;i++){
|
|
1225
|
-
rows[i].style.display=rows[i].textContent.toLowerCase().indexOf(q)>-1?'':'none';
|
|
1226
|
-
}
|
|
1227
|
-
});
|
|
1228
|
-
})();
|
|
1229
|
-
(function(){
|
|
1230
|
-
var saved=JSON.parse(localStorage.getItem('gsd-collapsed')||'{}');
|
|
1231
|
-
document.querySelectorAll('section[id]').forEach(function(sec){
|
|
1232
|
-
var h2=sec.querySelector('h2');
|
|
1233
|
-
if(!h2)return;
|
|
1234
|
-
var btn=document.createElement('button');
|
|
1235
|
-
btn.className='sec-toggle';
|
|
1236
|
-
btn.textContent=saved[sec.id]?'+':'-';
|
|
1237
|
-
btn.setAttribute('aria-label','Toggle section');
|
|
1238
|
-
h2.prepend(btn);
|
|
1239
|
-
if(saved[sec.id])toggleSection(sec,true);
|
|
1240
|
-
btn.addEventListener('click',function(e){
|
|
1241
|
-
e.preventDefault();
|
|
1242
|
-
var collapsed=btn.textContent==='-';
|
|
1243
|
-
toggleSection(sec,collapsed);
|
|
1244
|
-
btn.textContent=collapsed?'+':'-';
|
|
1245
|
-
saved[sec.id]=collapsed;
|
|
1246
|
-
localStorage.setItem('gsd-collapsed',JSON.stringify(saved));
|
|
1247
|
-
});
|
|
1248
|
-
});
|
|
1249
|
-
function toggleSection(sec,hide){
|
|
1250
|
-
var children=sec.children;
|
|
1251
|
-
for(var i=0;i<children.length;i++){
|
|
1252
|
-
if(children[i].tagName!=='H2')children[i].style.display=hide?'none':'';
|
|
1253
|
-
}
|
|
1254
|
-
}
|
|
1255
|
-
})();
|
|
1256
|
-
(function(){
|
|
1257
|
-
var hr=document.querySelector('.header-right');
|
|
1258
|
-
if(!hr)return;
|
|
1259
|
-
var btn=document.createElement('button');
|
|
1260
|
-
btn.className='theme-toggle';
|
|
1261
|
-
btn.textContent=localStorage.getItem('gsd-theme')==='light'?'Dark':'Light';
|
|
1262
|
-
if(localStorage.getItem('gsd-theme')==='light')document.documentElement.classList.add('light-theme');
|
|
1263
|
-
btn.addEventListener('click',function(){
|
|
1264
|
-
document.documentElement.classList.toggle('light-theme');
|
|
1265
|
-
var isLight=document.documentElement.classList.contains('light-theme');
|
|
1266
|
-
btn.textContent=isLight?'Dark':'Light';
|
|
1267
|
-
localStorage.setItem('gsd-theme',isLight?'light':'dark');
|
|
1268
|
-
});
|
|
1269
|
-
hr.prepend(btn);
|
|
1270
|
-
})();
|
|
1271
|
-
`;
|
|
@@ -19,6 +19,7 @@ import { deleteMilestone, getMilestone, isDbAvailable, updateMilestoneStatus } f
|
|
|
19
19
|
import { removeWorktree } from "./worktree-manager.js";
|
|
20
20
|
import { logWarning } from "./workflow-logger.js";
|
|
21
21
|
import { isAutoActive } from "./auto.js";
|
|
22
|
+
import { isClosedStatus } from "./status-guards.js";
|
|
22
23
|
/**
|
|
23
24
|
* Writer-side assert for mutations that race with auto-mode's squash merge (#4704).
|
|
24
25
|
* Auto-mode is confirmed not to call parkMilestone/discardMilestone/unparkMilestone
|
|
@@ -34,7 +35,7 @@ function assertNotAutoActive(action) {
|
|
|
34
35
|
/**
|
|
35
36
|
* Park a milestone — creates a PARKED.md marker file with reason and timestamp.
|
|
36
37
|
* Parked milestones are skipped during active-milestone discovery but stay on disk.
|
|
37
|
-
* Returns true if successfully parked, false if milestone not found
|
|
38
|
+
* Returns true if successfully parked, false if milestone not found, already parked, or complete.
|
|
38
39
|
*/
|
|
39
40
|
export function parkMilestone(basePath, milestoneId, reason) {
|
|
40
41
|
assertNotAutoActive("park milestone");
|
|
@@ -42,9 +43,15 @@ export function parkMilestone(basePath, milestoneId, reason) {
|
|
|
42
43
|
if (!mDir || !existsSync(mDir))
|
|
43
44
|
return false;
|
|
44
45
|
// Guard: do not park a completed milestone — it would corrupt depends_on satisfaction
|
|
45
|
-
const
|
|
46
|
-
|
|
46
|
+
const dbAvailable = isDbAvailable();
|
|
47
|
+
const milestone = dbAvailable ? getMilestone(milestoneId) : null;
|
|
48
|
+
if (milestone && isClosedStatus(milestone.status))
|
|
47
49
|
return false;
|
|
50
|
+
if (!dbAvailable) {
|
|
51
|
+
const summaryFile = resolveMilestoneFile(basePath, milestoneId, "SUMMARY");
|
|
52
|
+
if (summaryFile)
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
48
55
|
const parkedPath = join(mDir, buildMilestoneFileName(milestoneId, "PARKED"));
|
|
49
56
|
if (existsSync(parkedPath))
|
|
50
57
|
return false; // already parked
|
|
@@ -61,7 +68,7 @@ export function parkMilestone(basePath, milestoneId, reason) {
|
|
|
61
68
|
].join("\n");
|
|
62
69
|
writeFileSync(parkedPath, content, "utf-8");
|
|
63
70
|
// Sync DB status so deriveStateFromDb also skips this milestone (#2694)
|
|
64
|
-
if (
|
|
71
|
+
if (dbAvailable) {
|
|
65
72
|
try {
|
|
66
73
|
updateMilestoneStatus(milestoneId, "parked");
|
|
67
74
|
}
|
|
@@ -303,15 +303,20 @@ export function nativeDiffNameStatus(basePath, fromRef, toRef, pathspec, useMerg
|
|
|
303
303
|
}
|
|
304
304
|
/**
|
|
305
305
|
* Get numstat diff between two refs.
|
|
306
|
+
* useMergeBase: if true, uses three-dot semantics.
|
|
306
307
|
* Native: libgit2 patch line stats.
|
|
307
308
|
* Fallback: `git diff --numstat`.
|
|
308
309
|
*/
|
|
309
|
-
export function nativeDiffNumstat(basePath, fromRef, toRef) {
|
|
310
|
+
export function nativeDiffNumstat(basePath, fromRef, toRef, useMergeBase) {
|
|
310
311
|
const native = loadNative();
|
|
311
|
-
if (native) {
|
|
312
|
+
if (native && !useMergeBase) {
|
|
312
313
|
return native.gitDiffNumstat(basePath, fromRef, toRef);
|
|
313
314
|
}
|
|
314
|
-
const
|
|
315
|
+
const refspec = useMergeBase ? `${fromRef}...${toRef}` : undefined;
|
|
316
|
+
const args = refspec
|
|
317
|
+
? ["diff", "--numstat", refspec]
|
|
318
|
+
: ["diff", "--numstat", fromRef, toRef];
|
|
319
|
+
const result = gitExec(basePath, args, true);
|
|
315
320
|
if (!result)
|
|
316
321
|
return [];
|
|
317
322
|
return result.split("\n").filter(Boolean).map(line => {
|
|
@@ -10,6 +10,7 @@ import { isAbsolute, join, resolve } from "node:path";
|
|
|
10
10
|
import { getErrorMessage } from "../../error-utils.js";
|
|
11
11
|
import { nativeAddPaths, nativeCheckoutTheirs, nativeCommit, nativeConflictFiles, nativeMergeAbort, nativeRebaseAbort, nativeResetHard, } from "../../native-git-bridge.js";
|
|
12
12
|
import { logError, logWarning } from "../../workflow-logger.js";
|
|
13
|
+
import { isGsdWorktreePath } from "../../worktree-root.js";
|
|
13
14
|
const SILENT_NOTIFY = () => { };
|
|
14
15
|
function resolveGitDir(basePath) {
|
|
15
16
|
try {
|
|
@@ -23,7 +24,11 @@ function resolveGitDir(basePath) {
|
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
catch (err) {
|
|
26
|
-
|
|
27
|
+
const message = getErrorMessage(err);
|
|
28
|
+
logWarning("recovery", `gitdir resolution failed: ${message}`);
|
|
29
|
+
if (isGsdWorktreePath(basePath)) {
|
|
30
|
+
throw new Error(`Worktree integrity failure: ${basePath} is not a valid git worktree (git rev-parse failed: ${message.split("\n")[0]}). Repair or recreate the worktree before retrying.`);
|
|
31
|
+
}
|
|
27
32
|
}
|
|
28
33
|
return join(basePath, ".git");
|
|
29
34
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { clearParseCache } from "../files.js";
|
|
2
2
|
import { isClosedStatus, isDeferredStatus } from "../status-guards.js";
|
|
3
3
|
import { isNonEmptyString } from "../validation.js";
|
|
4
|
-
import { transaction, getMilestone, getSlice, insertTask, upsertSlicePlanning, upsertTaskPlanning, insertGateRow, updateSliceStatus, } from "../gsd-db.js";
|
|
4
|
+
import { transaction, getMilestone, getSlice, insertTask, upsertSlicePlanning, upsertTaskPlanning, insertGateRow, updateSliceStatus, setSliceSketchFlag, } from "../gsd-db.js";
|
|
5
5
|
import { invalidateStateCache } from "../state.js";
|
|
6
6
|
import { renderPlanFromDb } from "../markdown-renderer.js";
|
|
7
7
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
@@ -127,6 +127,7 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|
|
127
127
|
if (isDeferredStatus(parentSlice.status)) {
|
|
128
128
|
updateSliceStatus(params.milestoneId, params.sliceId, "pending");
|
|
129
129
|
}
|
|
130
|
+
setSliceSketchFlag(params.milestoneId, params.sliceId, false);
|
|
130
131
|
upsertSlicePlanning(params.milestoneId, params.sliceId, {
|
|
131
132
|
goal: params.goal,
|
|
132
133
|
successCriteria: params.successCriteria,
|
|
@@ -73,6 +73,7 @@ const COMMON_BUDGET_SMALL = 250_000; // ~65K tokens
|
|
|
73
73
|
// allowed-path set for the docs policy lives in one reviewable place.
|
|
74
74
|
const TOOLS_ALL = { mode: "all" };
|
|
75
75
|
const TOOLS_PLANNING = { mode: "planning" };
|
|
76
|
+
const TOOLS_VERIFICATION = { mode: "verification" };
|
|
76
77
|
// Like TOOLS_PLANNING but permits dispatch to read-only recon/planning
|
|
77
78
|
// specialists. Runtime-enforced by write-gate.ts before the subagent tool runs.
|
|
78
79
|
const TOOLS_PLANNING_DISPATCH_RECON = {
|
|
@@ -187,8 +188,8 @@ export const UNIT_MANIFESTS = {
|
|
|
187
188
|
contextMode: "verification",
|
|
188
189
|
// planning-dispatch: validation is a verification-fan-out unit. It reads
|
|
189
190
|
// the milestone surface and dispatches reviewer/security/tester subagents
|
|
190
|
-
// to report findings without touching user source.
|
|
191
|
-
//
|
|
191
|
+
// to report findings without touching user source. Write isolation to
|
|
192
|
+
// .gsd/ is preserved.
|
|
192
193
|
tools: TOOLS_PLANNING_DISPATCH_REVIEW,
|
|
193
194
|
artifacts: {
|
|
194
195
|
inline: ["roadmap", "slice-summary", "slice-uat", "requirements", "decisions", "templates"],
|
|
@@ -204,11 +205,9 @@ export const UNIT_MANIFESTS = {
|
|
|
204
205
|
codebaseMap: false,
|
|
205
206
|
preferences: "active-only",
|
|
206
207
|
contextMode: "verification",
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
|
|
210
|
-
// preserved.
|
|
211
|
-
tools: TOOLS_PLANNING_DISPATCH_REVIEW,
|
|
208
|
+
// Milestone closeout must run unrestricted shell verification commands
|
|
209
|
+
// against the final diff before recording completion.
|
|
210
|
+
tools: TOOLS_ALL,
|
|
212
211
|
artifacts: {
|
|
213
212
|
// #4780 landed slice-summary as excerpt for this unit; phase 2 of
|
|
214
213
|
// the architecture will read this manifest as the source of truth
|
|
@@ -367,7 +366,7 @@ export const UNIT_MANIFESTS = {
|
|
|
367
366
|
codebaseMap: false,
|
|
368
367
|
preferences: "active-only",
|
|
369
368
|
contextMode: "verification",
|
|
370
|
-
tools:
|
|
369
|
+
tools: TOOLS_VERIFICATION,
|
|
371
370
|
artifacts: {
|
|
372
371
|
// Phase 3 migration (#4782): manifest matches today's actual
|
|
373
372
|
// buildRunUatPrompt inlining. Prior phase-1 entry listed
|