specweave 3.1.5 → 3.1.7
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/.claude-plugin/marketplace.json +2 -2
- package/README.md +2 -2
- package/bin/specweave.js +17 -0
- package/dist/dashboard/assets/index-B4Xv671Q.css +1 -0
- package/dist/dashboard/assets/index-VnHjeVmH.js +16 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/src/cli/commands/card.d.ts.map +1 -1
- package/dist/src/cli/commands/card.js +15 -10
- package/dist/src/cli/commands/card.js.map +1 -1
- package/dist/src/cli/commands/complete.d.ts.map +1 -1
- package/dist/src/cli/commands/complete.js +6 -0
- package/dist/src/cli/commands/complete.js.map +1 -1
- package/dist/src/cli/commands/create-increment.d.ts.map +1 -1
- package/dist/src/cli/commands/create-increment.js +4 -0
- package/dist/src/cli/commands/create-increment.js.map +1 -1
- package/dist/src/cli/commands/dashboard.d.ts.map +1 -1
- package/dist/src/cli/commands/dashboard.js +2 -0
- package/dist/src/cli/commands/dashboard.js.map +1 -1
- package/dist/src/cli/commands/jev-helpers.d.ts +12 -4
- package/dist/src/cli/commands/jev-helpers.d.ts.map +1 -1
- package/dist/src/cli/commands/jev-helpers.js +22 -13
- package/dist/src/cli/commands/jev-helpers.js.map +1 -1
- package/dist/src/cli/commands/pickup.d.ts.map +1 -1
- package/dist/src/cli/commands/pickup.js +8 -4
- package/dist/src/cli/commands/pickup.js.map +1 -1
- package/dist/src/cli/commands/require-increment.d.ts +18 -0
- package/dist/src/cli/commands/require-increment.d.ts.map +1 -0
- package/dist/src/cli/commands/require-increment.js +75 -0
- package/dist/src/cli/commands/require-increment.js.map +1 -0
- package/dist/src/cli/commands/small-fix.d.ts +14 -0
- package/dist/src/cli/commands/small-fix.d.ts.map +1 -0
- package/dist/src/cli/commands/small-fix.js +52 -0
- package/dist/src/cli/commands/small-fix.js.map +1 -0
- package/dist/src/cli/commands/verify.d.ts.map +1 -1
- package/dist/src/cli/commands/verify.js +3 -0
- package/dist/src/cli/commands/verify.js.map +1 -1
- package/dist/src/cli/helpers/init/gitignore-generator.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/gitignore-generator.js +1 -0
- package/dist/src/cli/helpers/init/gitignore-generator.js.map +1 -1
- package/dist/src/core/config/types.d.ts +7 -0
- package/dist/src/core/config/types.d.ts.map +1 -1
- package/dist/src/core/config/types.js.map +1 -1
- package/dist/src/core/hooks/handlers/pre-compact.d.ts.map +1 -1
- package/dist/src/core/hooks/handlers/pre-compact.js +4 -1
- package/dist/src/core/hooks/handlers/pre-compact.js.map +1 -1
- package/dist/src/core/hooks/handlers/pre-tool-use.d.ts +5 -2
- package/dist/src/core/hooks/handlers/pre-tool-use.d.ts.map +1 -1
- package/dist/src/core/hooks/handlers/pre-tool-use.js +16 -3
- package/dist/src/core/hooks/handlers/pre-tool-use.js.map +1 -1
- package/dist/src/core/hooks/handlers/require-increment.d.ts +40 -0
- package/dist/src/core/hooks/handlers/require-increment.d.ts.map +1 -0
- package/dist/src/core/hooks/handlers/require-increment.js +128 -0
- package/dist/src/core/hooks/handlers/require-increment.js.map +1 -0
- package/dist/src/core/session/nested-repos.d.ts +16 -4
- package/dist/src/core/session/nested-repos.d.ts.map +1 -1
- package/dist/src/core/session/nested-repos.js +85 -23
- package/dist/src/core/session/nested-repos.js.map +1 -1
- package/dist/src/core/session/pickup.d.ts +2 -0
- package/dist/src/core/session/pickup.d.ts.map +1 -1
- package/dist/src/core/session/pickup.js +4 -3
- package/dist/src/core/session/pickup.js.map +1 -1
- package/dist/src/core/session/work-handoff.d.ts.map +1 -1
- package/dist/src/core/session/work-handoff.js +6 -3
- package/dist/src/core/session/work-handoff.js.map +1 -1
- package/dist/src/core/tasks/ledger.d.ts +7 -0
- package/dist/src/core/tasks/ledger.d.ts.map +1 -1
- package/dist/src/core/tasks/ledger.js +20 -4
- package/dist/src/core/tasks/ledger.js.map +1 -1
- package/dist/src/core/tasks/verify-runner.d.ts +21 -0
- package/dist/src/core/tasks/verify-runner.d.ts.map +1 -1
- package/dist/src/core/tasks/verify-runner.js +9 -4
- package/dist/src/core/tasks/verify-runner.js.map +1 -1
- package/dist/src/core/tasks/work-session.d.ts +58 -0
- package/dist/src/core/tasks/work-session.d.ts.map +1 -0
- package/dist/src/core/tasks/work-session.js +88 -0
- package/dist/src/core/tasks/work-session.js.map +1 -0
- package/dist/src/dashboard/server/dashboard-server.d.ts.map +1 -1
- package/dist/src/dashboard/server/dashboard-server.js +2 -0
- package/dist/src/dashboard/server/dashboard-server.js.map +1 -1
- package/dist/src/dashboard/server/data/plan-timeline.d.ts +40 -0
- package/dist/src/dashboard/server/data/plan-timeline.d.ts.map +1 -0
- package/dist/src/dashboard/server/data/plan-timeline.js +259 -0
- package/dist/src/dashboard/server/data/plan-timeline.js.map +1 -0
- package/dist/src/dashboard/server/data/work-projection.d.ts.map +1 -1
- package/dist/src/dashboard/server/data/work-projection.js +7 -2
- package/dist/src/dashboard/server/data/work-projection.js.map +1 -1
- package/dist/src/dashboard/server/routes/plan-routes.d.ts +4 -0
- package/dist/src/dashboard/server/routes/plan-routes.d.ts.map +1 -0
- package/dist/src/dashboard/server/routes/plan-routes.js +19 -0
- package/dist/src/dashboard/server/routes/plan-routes.js.map +1 -0
- package/dist/src/dashboard/work-types.d.ts +81 -0
- package/dist/src/dashboard/work-types.d.ts.map +1 -1
- package/dist/src/utils/find-project-root.d.ts +2 -0
- package/dist/src/utils/find-project-root.d.ts.map +1 -1
- package/dist/src/utils/find-project-root.js +8 -1
- package/dist/src/utils/find-project-root.js.map +1 -1
- package/dist/src/utils/main-checkout.d.ts +30 -0
- package/dist/src/utils/main-checkout.d.ts.map +1 -0
- package/dist/src/utils/main-checkout.js +74 -0
- package/dist/src/utils/main-checkout.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave/hooks/run-worker.mjs +42 -5
- package/plugins/specweave/hooks/run.mjs +101 -6
- package/plugins/specweave/skills/do/SKILL.md +1 -1
- package/plugins/specweave/skills/handoff/SKILL.md +2 -2
- package/src/templates/.gitignore.template +1 -0
- package/src/templates/AGENTS.md.template +2 -2
- package/src/templates/environments/minimal/README.md +3 -3
- package/src/templates/environments/progressive/README.md +5 -6
- package/src/templates/environments/standard/README.md +4 -4
- package/dist/dashboard/assets/index-BFPKNEDz.css +0 -1
- package/dist/dashboard/assets/index-DVaY9gOX.js +0 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-projection.d.ts","sourceRoot":"","sources":["../../../../../src/dashboard/server/data/work-projection.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAoB,QAAQ,EAAa,MAAM,qBAAqB,CAAC;AAEjF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM7C;AACD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAM1D;AACD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc1E;AAQD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"work-projection.d.ts","sourceRoot":"","sources":["../../../../../src/dashboard/server/data/work-projection.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAoB,QAAQ,EAAa,MAAM,qBAAqB,CAAC;AAEjF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM7C;AACD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAM1D;AACD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc1E;AAQD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CA0F1E;AAED,oFAAoF;AACpF,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CA2C1G"}
|
|
@@ -86,8 +86,13 @@ export function projectIncrement(root, id) {
|
|
|
86
86
|
const events = readLedger(path.join(dir, 'ledger.jsonl')).events.sort((a, b) => a.at.localeCompare(b.at));
|
|
87
87
|
const executions = [];
|
|
88
88
|
for (const [index, event] of events.entries()) {
|
|
89
|
-
|
|
89
|
+
const last = executions[executions.length - 1];
|
|
90
|
+
if (last?.actor === event.by && (!event.model || last.model === event.model))
|
|
90
91
|
continue;
|
|
92
|
+
if (last?.actor === event.by && !last.model) {
|
|
93
|
+
last.model = event.model ?? null;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
91
96
|
const tool = event.by.split('@')[0];
|
|
92
97
|
executions.push({
|
|
93
98
|
id: `ledger-${index}`,
|
|
@@ -97,7 +102,7 @@ export function projectIncrement(root, id) {
|
|
|
97
102
|
? 'Claude Code'
|
|
98
103
|
: tool
|
|
99
104
|
: null,
|
|
100
|
-
model: null,
|
|
105
|
+
model: event.model ?? null,
|
|
101
106
|
effort: null,
|
|
102
107
|
provider: null,
|
|
103
108
|
surface: null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-projection.js","sourceRoot":"","sources":["../../../../../src/dashboard/server/data/work-projection.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"work-projection.js","sourceRoot":"","sources":["../../../../../src/dashboard/server/data/work-projection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-routes.d.ts","sourceRoot":"","sources":["../../../../../src/dashboard/server/routes/plan-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAY,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAMrD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,KAAK,MAAM,GAAG,SAAS,GAAG,IAAI,CAWvH"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { buildPlanTimeline } from '../data/plan-timeline.js';
|
|
2
|
+
import { sendJson } from '../router.js';
|
|
3
|
+
/** Reads every increment folder; a short cache keeps the Timeline's polling cheap. */
|
|
4
|
+
const CACHE_MS = 5000;
|
|
5
|
+
export function registerPlanRoutes(router, resolveRoot) {
|
|
6
|
+
const cache = new Map();
|
|
7
|
+
router.get('/api/plan', async (req, res) => {
|
|
8
|
+
const root = resolveRoot(req);
|
|
9
|
+
if (!root)
|
|
10
|
+
return sendJson(res, { ok: false, error: 'No project selected' }, 404);
|
|
11
|
+
const hit = cache.get(root);
|
|
12
|
+
if (hit && Date.now() - hit.at < CACHE_MS)
|
|
13
|
+
return sendJson(res, { ok: true, data: hit.data });
|
|
14
|
+
const data = buildPlanTimeline(root);
|
|
15
|
+
cache.set(root, { at: Date.now(), data });
|
|
16
|
+
sendJson(res, { ok: true, data });
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=plan-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-routes.js","sourceRoot":"","sources":["../../../../../src/dashboard/server/routes/plan-routes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAe,MAAM,cAAc,CAAC;AAGrD,sFAAsF;AACtF,MAAM,QAAQ,GAAG,IAAI,CAAC;AAEtB,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,WAA8D;IAC/G,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqD,CAAC;IAC3E,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACzC,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI;YAAE,OAAO,QAAQ,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE,EAAE,GAAG,CAAC,CAAC;QAClF,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,QAAQ;YAAE,OAAO,QAAQ,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9F,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACrC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,QAAQ,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -36,4 +36,85 @@ export interface WorkBoardPayload {
|
|
|
36
36
|
generatedAt: string;
|
|
37
37
|
warnings: string[];
|
|
38
38
|
}
|
|
39
|
+
/** One increment on the Timeline page (`GET /api/plan`). */
|
|
40
|
+
export interface PlanRow {
|
|
41
|
+
incrementId: string;
|
|
42
|
+
title: string;
|
|
43
|
+
status: string;
|
|
44
|
+
state: WorkState;
|
|
45
|
+
/** Created, or the first ledger event when earlier. */
|
|
46
|
+
start: string;
|
|
47
|
+
/** Last ledger event or metadata update; null while nothing happened. */
|
|
48
|
+
end: string | null;
|
|
49
|
+
tasks: {
|
|
50
|
+
total: number;
|
|
51
|
+
done: number;
|
|
52
|
+
skipped: number;
|
|
53
|
+
open: number;
|
|
54
|
+
claimed: number;
|
|
55
|
+
blocked: number;
|
|
56
|
+
};
|
|
57
|
+
acs: {
|
|
58
|
+
total: number;
|
|
59
|
+
done: number;
|
|
60
|
+
};
|
|
61
|
+
tools: string[];
|
|
62
|
+
models: string[];
|
|
63
|
+
/** Most tasks were closed with no live claim-to-done span: the plan was written after the work. */
|
|
64
|
+
recordedAfter: boolean;
|
|
65
|
+
/** Open work only: remaining weight, minutes at the p50 and p80 rates and finish times, uninterrupted from now. */
|
|
66
|
+
remaining: {
|
|
67
|
+
tasks: number;
|
|
68
|
+
weight: number;
|
|
69
|
+
p50Minutes: number;
|
|
70
|
+
p80Minutes: number;
|
|
71
|
+
finishP50: string;
|
|
72
|
+
finishP80: string;
|
|
73
|
+
} | null;
|
|
74
|
+
lastEvent: {
|
|
75
|
+
at: string;
|
|
76
|
+
e: string;
|
|
77
|
+
t: string;
|
|
78
|
+
by: string;
|
|
79
|
+
} | null;
|
|
80
|
+
specPath: string;
|
|
81
|
+
}
|
|
82
|
+
export interface PlanActivity {
|
|
83
|
+
at: string;
|
|
84
|
+
incrementId: string;
|
|
85
|
+
title: string;
|
|
86
|
+
task: string;
|
|
87
|
+
event: string;
|
|
88
|
+
by: string;
|
|
89
|
+
tool: string;
|
|
90
|
+
model: string | null;
|
|
91
|
+
note: string | null;
|
|
92
|
+
}
|
|
93
|
+
export interface PlanRate {
|
|
94
|
+
key: string;
|
|
95
|
+
samples: number;
|
|
96
|
+
/** Minutes per weight unit of task work. */
|
|
97
|
+
p50: number;
|
|
98
|
+
p80: number;
|
|
99
|
+
}
|
|
100
|
+
export interface PlanTimelinePayload {
|
|
101
|
+
generatedAt: string;
|
|
102
|
+
rows: PlanRow[];
|
|
103
|
+
activity: PlanActivity[];
|
|
104
|
+
/** Every done or skipped task of the last 30 days, oldest first (throughput is computed from the filtered set). */
|
|
105
|
+
closes: Array<{
|
|
106
|
+
at: string;
|
|
107
|
+
incrementId: string;
|
|
108
|
+
tool: string;
|
|
109
|
+
}>;
|
|
110
|
+
rates: {
|
|
111
|
+
overall: PlanRate;
|
|
112
|
+
byTool: PlanRate[];
|
|
113
|
+
byModel: PlanRate[];
|
|
114
|
+
fallback: boolean;
|
|
115
|
+
};
|
|
116
|
+
/** Median agents finishing tasks per active day over the last week (at least 1): parallel lanes for the forecast. */
|
|
117
|
+
lanes: number;
|
|
118
|
+
smallFixes: number;
|
|
119
|
+
}
|
|
39
120
|
//# sourceMappingURL=work-types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-types.d.ts","sourceRoot":"","sources":["../../../src/dashboard/work-types.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,cAAc,yBAAyB,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACrE,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,YAAY,EAAE;QAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC1F,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AACD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAClC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB"}
|
|
1
|
+
{"version":3,"file":"work-types.d.ts","sourceRoot":"","sources":["../../../src/dashboard/work-types.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,cAAc,yBAAyB,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACrE,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,YAAY,EAAE;QAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC1F,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AACD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAClC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,4DAA4D;AAC5D,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACxG,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,mGAAmG;IACnG,aAAa,EAAE,OAAO,CAAC;IACvB,mHAAmH;IACnH,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClI,SAAS,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACnE,QAAQ,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AACD,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AACD,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,mHAAmH;IACnH,MAAM,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,KAAK,EAAE;QAAE,OAAO,EAAE,QAAQ,CAAC;QAAC,MAAM,EAAE,QAAQ,EAAE,CAAC;QAAC,OAAO,EAAE,QAAQ,EAAE,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IACzF,qHAAqH;IACrH,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -92,6 +92,8 @@ export declare function findUmbrellaRoot(startDir?: string): string | null;
|
|
|
92
92
|
*
|
|
93
93
|
* - In a multi-repo umbrella: returns the umbrella root (increments belong there)
|
|
94
94
|
* - In a single-repo project: returns the nearest project root
|
|
95
|
+
* - In a linked Git worktree outside the project (SpecWithCode threads): the
|
|
96
|
+
* same lookups from the worktree's main checkout
|
|
95
97
|
* - Otherwise: null
|
|
96
98
|
*
|
|
97
99
|
* Use this instead of resolveEffectiveRoot() for any command that scans or
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-project-root.d.ts","sourceRoot":"","sources":["../../../src/utils/find-project-root.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"find-project-root.d.ts","sourceRoot":"","sources":["../../../src/utils/find-project-root.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAOH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAmB/E;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAElF;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQ3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAqBhF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAKjF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAE7E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMnE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,QAAQ,GAAE,MAAsB,GAC/B,MAAM,GAAG,IAAI,CAKf"}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import * as fs from 'fs';
|
|
16
16
|
import path from 'path';
|
|
17
17
|
import { explicitWorkspaceRoot, isWorkspaceRoot, hasLegacyWorkspaceLayout, registeredRepositories, canonicalPath, isWithin } from '../core/workspace/context.js';
|
|
18
|
+
import { mainCheckoutOf } from './main-checkout.js';
|
|
18
19
|
/**
|
|
19
20
|
* Find project root by searching for .specweave/config.json
|
|
20
21
|
*
|
|
@@ -148,6 +149,8 @@ export function findUmbrellaRoot(startDir = process.cwd()) {
|
|
|
148
149
|
*
|
|
149
150
|
* - In a multi-repo umbrella: returns the umbrella root (increments belong there)
|
|
150
151
|
* - In a single-repo project: returns the nearest project root
|
|
152
|
+
* - In a linked Git worktree outside the project (SpecWithCode threads): the
|
|
153
|
+
* same lookups from the worktree's main checkout
|
|
151
154
|
* - Otherwise: null
|
|
152
155
|
*
|
|
153
156
|
* Use this instead of resolveEffectiveRoot() for any command that scans or
|
|
@@ -158,7 +161,11 @@ export function findUmbrellaRoot(startDir = process.cwd()) {
|
|
|
158
161
|
* @returns Effective project root path or null if not inside a SpecWeave project
|
|
159
162
|
*/
|
|
160
163
|
export function findEffectiveRoot(startDir = process.cwd()) {
|
|
161
|
-
|
|
164
|
+
const found = findUmbrellaRoot(startDir) ?? findProjectRoot(startDir);
|
|
165
|
+
if (found)
|
|
166
|
+
return found;
|
|
167
|
+
const main = mainCheckoutOf(startDir);
|
|
168
|
+
return main ? findUmbrellaRoot(main) ?? findProjectRoot(main) : null;
|
|
162
169
|
}
|
|
163
170
|
/**
|
|
164
171
|
* Resolve the effective project root for increment operations.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-project-root.js","sourceRoot":"","sources":["../../../src/utils/find-project-root.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"find-project-root.js","sourceRoot":"","sources":["../../../src/utils/find-project-root.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main checkout of a Git worktree.
|
|
3
|
+
*
|
|
4
|
+
* SpecWithCode runs threads in linked worktrees outside the project
|
|
5
|
+
* (`~/.specwithcode/<machine>/worktrees/*`), where no `.specweave/` is found by
|
|
6
|
+
* walking up. A linked worktree's `.git` is a file whose `gitdir:` line points
|
|
7
|
+
* into `<main>/.git/worktrees/<name>`, so the main checkout (and the planning
|
|
8
|
+
* root above it) can be found from that line alone.
|
|
9
|
+
*
|
|
10
|
+
* Sync `fs` only and no Git process: the hook launcher inlines the same logic
|
|
11
|
+
* (`plugins/specweave/hooks/run.mjs`, `run-worker.mjs`) and a parity test keeps
|
|
12
|
+
* the copies equal.
|
|
13
|
+
*
|
|
14
|
+
* @module utils/main-checkout
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* The main checkout of the linked worktree containing `dir`, or null when the
|
|
18
|
+
* nearest `.git` is a directory (an ordinary checkout), a submodule link
|
|
19
|
+
* (`.git/modules/`), unreadable, or absent.
|
|
20
|
+
*/
|
|
21
|
+
export declare function mainCheckoutOf(dir: string): string | null;
|
|
22
|
+
/** Top of the linked worktree containing `dir` (the folder holding its `.git` file), or null. */
|
|
23
|
+
export declare function linkedWorktreeRoot(dir: string): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Where Git commands for work started in `startDir` run. Planning state may
|
|
26
|
+
* resolve to the main checkout (`findEffectiveRoot`), but a thread's branch,
|
|
27
|
+
* diff and pushes live in its own worktree.
|
|
28
|
+
*/
|
|
29
|
+
export declare function gitCheckoutFor(startDir: string, planningRoot: string): string;
|
|
30
|
+
//# sourceMappingURL=main-checkout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-checkout.d.ts","sourceRoot":"","sources":["../../../src/utils/main-checkout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAOH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEzD;AAED,iGAAiG;AACjG,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE7D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAM7E"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main checkout of a Git worktree.
|
|
3
|
+
*
|
|
4
|
+
* SpecWithCode runs threads in linked worktrees outside the project
|
|
5
|
+
* (`~/.specwithcode/<machine>/worktrees/*`), where no `.specweave/` is found by
|
|
6
|
+
* walking up. A linked worktree's `.git` is a file whose `gitdir:` line points
|
|
7
|
+
* into `<main>/.git/worktrees/<name>`, so the main checkout (and the planning
|
|
8
|
+
* root above it) can be found from that line alone.
|
|
9
|
+
*
|
|
10
|
+
* Sync `fs` only and no Git process: the hook launcher inlines the same logic
|
|
11
|
+
* (`plugins/specweave/hooks/run.mjs`, `run-worker.mjs`) and a parity test keeps
|
|
12
|
+
* the copies equal.
|
|
13
|
+
*
|
|
14
|
+
* @module utils/main-checkout
|
|
15
|
+
*/
|
|
16
|
+
import * as fs from 'fs';
|
|
17
|
+
import path from 'path';
|
|
18
|
+
const WORKTREE_GITDIR = /^gitdir:\s*(.*?)[\\/]\.git[\\/]worktrees[\\/][^\\/]+[\\/]?\s*$/;
|
|
19
|
+
/**
|
|
20
|
+
* The main checkout of the linked worktree containing `dir`, or null when the
|
|
21
|
+
* nearest `.git` is a directory (an ordinary checkout), a submodule link
|
|
22
|
+
* (`.git/modules/`), unreadable, or absent.
|
|
23
|
+
*/
|
|
24
|
+
export function mainCheckoutOf(dir) {
|
|
25
|
+
return worktreeLink(dir)?.main ?? null;
|
|
26
|
+
}
|
|
27
|
+
/** Top of the linked worktree containing `dir` (the folder holding its `.git` file), or null. */
|
|
28
|
+
export function linkedWorktreeRoot(dir) {
|
|
29
|
+
return worktreeLink(dir)?.root ?? null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Where Git commands for work started in `startDir` run. Planning state may
|
|
33
|
+
* resolve to the main checkout (`findEffectiveRoot`), but a thread's branch,
|
|
34
|
+
* diff and pushes live in its own worktree.
|
|
35
|
+
*/
|
|
36
|
+
export function gitCheckoutFor(startDir, planningRoot) {
|
|
37
|
+
const own = linkedWorktreeRoot(startDir);
|
|
38
|
+
if (!own)
|
|
39
|
+
return planningRoot;
|
|
40
|
+
const rel = path.relative(own, path.resolve(planningRoot));
|
|
41
|
+
const inside = rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));
|
|
42
|
+
return inside ? planningRoot : own;
|
|
43
|
+
}
|
|
44
|
+
function worktreeLink(dir) {
|
|
45
|
+
let current;
|
|
46
|
+
try {
|
|
47
|
+
current = path.resolve(dir);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
for (let depth = 0; depth < 100; depth++) {
|
|
53
|
+
const dotGit = path.join(current, '.git');
|
|
54
|
+
try {
|
|
55
|
+
const stat = fs.statSync(dotGit, { throwIfNoEntry: false });
|
|
56
|
+
if (stat) {
|
|
57
|
+
if (!stat.isFile())
|
|
58
|
+
return null;
|
|
59
|
+
const first = fs.readFileSync(dotGit, 'utf8').split(/\r?\n/, 1)[0] ?? '';
|
|
60
|
+
const match = WORKTREE_GITDIR.exec(first.trim());
|
|
61
|
+
return match && match[1] ? { root: current, main: path.resolve(current, match[1]) } : null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const parent = path.dirname(current);
|
|
68
|
+
if (parent === current)
|
|
69
|
+
return null;
|
|
70
|
+
current = parent;
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=main-checkout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-checkout.js","sourceRoot":"","sources":["../../../src/utils/main-checkout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,eAAe,GAAG,gEAAgE,CAAC;AAEzF;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,OAAO,YAAY,CAAC,GAAG,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC;AACzC,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,OAAO,YAAY,CAAC,GAAG,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,YAAoB;IACnE,MAAM,GAAG,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,GAAG;QAAE,OAAO,YAAY,CAAC;IAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9E,OAAO,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC;AACrC,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAC/B,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC;YAC5D,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;oBAAE,OAAO,IAAI,CAAC;gBAChC,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACzE,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;gBACjD,OAAO,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7F,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC;QACpC,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specweave",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.7",
|
|
4
4
|
"description": "Keep intent, specifications, and verified progress portable across AI coding tools. A local live work board, append-only task evidence, explicit handoffs, and optional GitHub/Jira/Azure DevOps integrations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sw",
|
|
3
3
|
"description": "Portable intent and verified progress across coding tools. Six core workflow skills plus opt-in grill-me, glossary, sync, project and jev, two default lifecycle hooks, and a deterministic CLI and live local dashboard.",
|
|
4
|
-
"version": "3.1.
|
|
4
|
+
"version": "3.1.7",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "SpecWeave Team",
|
|
7
7
|
"url": "https://spec-weave.com"
|
|
@@ -21,11 +21,13 @@
|
|
|
21
21
|
* Fast path: PreToolUse for a file outside `.specweave/increments/` prints `{}`
|
|
22
22
|
* without loading the CLI at all (the guards only concern increment files), and
|
|
23
23
|
* PreToolUse for Bash prints `{}` unless the project opted into the Jev command
|
|
24
|
-
* guard with a `.specweave/state/jev-guard.enabled` marker.
|
|
24
|
+
* guard with a `.specweave/state/jev-guard.enabled` marker. Edits outside
|
|
25
|
+
* increments reach the required-increment guard only under a
|
|
26
|
+
* `.specweave/state/require-increment.enabled` marker.
|
|
25
27
|
*/
|
|
26
28
|
import { createRequire } from 'node:module';
|
|
27
29
|
import { spawnSync } from 'node:child_process';
|
|
28
|
-
import { existsSync, lstatSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
30
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
29
31
|
import { homedir } from 'node:os';
|
|
30
32
|
import path from 'node:path';
|
|
31
33
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
@@ -66,10 +68,44 @@ const event = process.argv[2] ?? '';
|
|
|
66
68
|
|
|
67
69
|
/** Opt-in marker for the Jev Bash guard, searched upward from cwd / project dir. */
|
|
68
70
|
const JEV_GUARD_MARKER = path.join('.specweave', 'state', 'jev-guard.enabled');
|
|
71
|
+
/** Opt-in marker for required increments (`specweave require-increment`): ordinary edits reach the guard. */
|
|
72
|
+
const REQUIRE_INCREMENT_MARKER = path.join('.specweave', 'state', 'require-increment.enabled');
|
|
73
|
+
const EDIT_TOOLS = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit']);
|
|
69
74
|
const JEV_GUARD_MAX_DEPTH = 8;
|
|
70
75
|
|
|
71
76
|
function hasJevGuardMarker(input) {
|
|
72
|
-
|
|
77
|
+
return hasMarker(input, JEV_GUARD_MARKER);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Main checkout of the linked Git worktree containing `dir`, or null. Keep in
|
|
81
|
+
// step with src/utils/main-checkout.ts (a parity test compares them): the
|
|
82
|
+
// SpecWithCode worktrees live outside the project, so markers are searched from
|
|
83
|
+
// the main checkout too. Sync reads only, no Git process.
|
|
84
|
+
const WORKTREE_GITDIR = /^gitdir:\s*(.*?)[\\/]\.git[\\/]worktrees[\\/][^\\/]+[\\/]?\s*$/;
|
|
85
|
+
function mainCheckoutOf(dir) {
|
|
86
|
+
let current;
|
|
87
|
+
try { current = path.resolve(dir); } catch { return null; }
|
|
88
|
+
for (let depth = 0; depth < 100; depth++) {
|
|
89
|
+
const dotGit = path.join(current, '.git');
|
|
90
|
+
try {
|
|
91
|
+
const stat = statSync(dotGit, { throwIfNoEntry: false });
|
|
92
|
+
if (stat) {
|
|
93
|
+
if (!stat.isFile()) return null;
|
|
94
|
+
const first = readFileSync(dotGit, 'utf8').split(/\r?\n/, 1)[0] ?? '';
|
|
95
|
+
const match = WORKTREE_GITDIR.exec(first.trim());
|
|
96
|
+
return match && match[1] ? path.resolve(current, match[1]) : null;
|
|
97
|
+
}
|
|
98
|
+
} catch { return null; }
|
|
99
|
+
const parent = path.dirname(current);
|
|
100
|
+
if (parent === current) return null;
|
|
101
|
+
current = parent;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function hasMarker(input, marker) {
|
|
107
|
+
const first = [typeof input.cwd === 'string' ? input.cwd : process.cwd(), process.env.CLAUDE_PROJECT_DIR].filter(Boolean);
|
|
108
|
+
const starts = [...first, ...first.map(mainCheckoutOf)];
|
|
73
109
|
for (const start of starts) {
|
|
74
110
|
if (!start) continue;
|
|
75
111
|
let current;
|
|
@@ -80,7 +116,7 @@ function hasJevGuardMarker(input) {
|
|
|
80
116
|
}
|
|
81
117
|
for (let depth = 0; depth < JEV_GUARD_MAX_DEPTH; depth++) {
|
|
82
118
|
try {
|
|
83
|
-
if (existsSync(path.join(current,
|
|
119
|
+
if (existsSync(path.join(current, marker))) return true;
|
|
84
120
|
} catch {
|
|
85
121
|
break;
|
|
86
122
|
}
|
|
@@ -158,7 +194,8 @@ function normalizeInput(raw) {
|
|
|
158
194
|
event === 'pre-tool-use' &&
|
|
159
195
|
(tool === 'Bash'
|
|
160
196
|
? !hasJevGuardMarker(input)
|
|
161
|
-
: !filePath.includes('.specweave/increments/')
|
|
197
|
+
: !filePath.includes('.specweave/increments/') &&
|
|
198
|
+
!(EDIT_TOOLS.has(tool) && hasMarker(input, REQUIRE_INCREMENT_MARKER)));
|
|
162
199
|
return { raw: JSON.stringify(input), skip };
|
|
163
200
|
}
|
|
164
201
|
} catch {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// SpecWeave hook supervisor: parent deadline remains live while the worker blocks in Git.
|
|
3
3
|
import { spawn, spawnSync } from 'node:child_process';
|
|
4
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
4
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, statSync } from 'node:fs';
|
|
5
5
|
import { homedir } from 'node:os';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
@@ -48,28 +48,123 @@ function hasClosePendingFor(data) {
|
|
|
48
48
|
// Jev guard with a local marker file.
|
|
49
49
|
const JEV_GUARD_MARKER = path.join('.specweave', 'state', 'jev-guard.enabled');
|
|
50
50
|
const JEV_GUARD_MAX_DEPTH = 8;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
// Edits outside increments only matter when the project opted into required
|
|
52
|
+
// increments (`specweave require-increment`), which leaves its own marker; a
|
|
53
|
+
// session or SpecWithCode thread with a small fix there, or a thread bound to
|
|
54
|
+
// an open increment there, skips too.
|
|
55
|
+
const REQUIRE_INCREMENT_MARKER = path.join('.specweave', 'state', 'require-increment.enabled');
|
|
56
|
+
const EDIT_TOOLS = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit']);
|
|
57
|
+
// Main checkout of the linked Git worktree containing `dir`, or null. Keep in
|
|
58
|
+
// step with src/utils/main-checkout.ts (a parity test compares them): the
|
|
59
|
+
// SpecWithCode worktrees live outside the project, so markers are searched from
|
|
60
|
+
// the main checkout too. Sync reads only, no Git process.
|
|
61
|
+
const WORKTREE_GITDIR = /^gitdir:\s*(.*?)[\\/]\.git[\\/]worktrees[\\/][^\\/]+[\\/]?\s*$/;
|
|
62
|
+
function mainCheckoutOf(dir) {
|
|
63
|
+
let current;
|
|
64
|
+
try { current = path.resolve(dir); } catch { return null; }
|
|
65
|
+
for (let depth = 0; depth < 100; depth++) {
|
|
66
|
+
const dotGit = path.join(current, '.git');
|
|
67
|
+
try {
|
|
68
|
+
const stat = statSync(dotGit, { throwIfNoEntry: false });
|
|
69
|
+
if (stat) {
|
|
70
|
+
if (!stat.isFile()) return null;
|
|
71
|
+
const first = readFileSync(dotGit, 'utf8').split(/\r?\n/, 1)[0] ?? '';
|
|
72
|
+
const match = WORKTREE_GITDIR.exec(first.trim());
|
|
73
|
+
return match && match[1] ? path.resolve(current, match[1]) : null;
|
|
74
|
+
}
|
|
75
|
+
} catch { return null; }
|
|
76
|
+
const parent = path.dirname(current);
|
|
77
|
+
if (parent === current) return null;
|
|
78
|
+
current = parent;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
function markerStarts(data) {
|
|
83
|
+
const starts = [typeof data.cwd === 'string' ? data.cwd : process.cwd(), process.env.CLAUDE_PROJECT_DIR].filter(Boolean);
|
|
84
|
+
return [...starts, ...starts.map(mainCheckoutOf)];
|
|
85
|
+
}
|
|
86
|
+
function findMarker(data, marker) {
|
|
87
|
+
for (const start of markerStarts(data)) {
|
|
54
88
|
if (!start) continue;
|
|
55
89
|
let current;
|
|
56
90
|
try { current = path.resolve(start); } catch { continue; }
|
|
57
91
|
for (let depth = 0; depth < JEV_GUARD_MAX_DEPTH; depth++) {
|
|
58
|
-
try { if (existsSync(path.join(current,
|
|
92
|
+
try { if (existsSync(path.join(current, marker))) return current; } catch { break; }
|
|
59
93
|
const parent = path.dirname(current);
|
|
60
94
|
if (parent === current) break;
|
|
61
95
|
current = parent;
|
|
62
96
|
}
|
|
63
97
|
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
function hasJevGuardMarker(data) {
|
|
101
|
+
return findMarker(data, JEV_GUARD_MARKER) !== null;
|
|
102
|
+
}
|
|
103
|
+
// A small fix declared in this project by the session, or (Codex, Pi: no
|
|
104
|
+
// session id) by the SpecWithCode thread, keyed `studio-<thread>` and sanitized
|
|
105
|
+
// like workSessionFile. Worktrees count as their main checkout.
|
|
106
|
+
const SAFE_ID = /^[A-Za-z0-9._-]{1,128}$/;
|
|
107
|
+
function sessionWorksIn(data, root) {
|
|
108
|
+
const session = typeof data.session_id === 'string' ? data.session_id : '';
|
|
109
|
+
const thread = (process.env.SPECWEAVE_STUDIO_THREAD_ID ?? '').trim();
|
|
110
|
+
const ids = [session, thread ? `studio-${thread}`.replace(/[^\w.-]/g, '_') : '']
|
|
111
|
+
.filter((id) => SAFE_ID.test(id) && id !== '.' && id !== '..');
|
|
112
|
+
const project = (dir) => path.resolve(mainCheckoutOf(dir) ?? dir);
|
|
113
|
+
for (const id of ids) {
|
|
114
|
+
try {
|
|
115
|
+
const marker = JSON.parse(readFileSync(path.join(homedir(), '.specweave', 'sessions', `${id}.json`), 'utf8'));
|
|
116
|
+
if (marker?.kind !== 'small-fix' || typeof marker.root !== 'string') continue;
|
|
117
|
+
if (path.resolve(marker.root) === root || project(marker.root) === project(root)) return true;
|
|
118
|
+
} catch {}
|
|
119
|
+
}
|
|
64
120
|
return false;
|
|
65
121
|
}
|
|
122
|
+
// The SpecWithCode thread is bound to an increment of this project that is not
|
|
123
|
+
// closed: the guard would pass, so skip the worker. Same rule as the guard's
|
|
124
|
+
// binding check, with an exact project match (anything else asks the worker).
|
|
125
|
+
const CLOSED_STATUSES = new Set(['completed', 'abandoned', 'cancelled']);
|
|
126
|
+
function threadBoundIn(root) {
|
|
127
|
+
const thread = (process.env.SPECWEAVE_STUDIO_THREAD_ID ?? '').trim();
|
|
128
|
+
if (!thread) return false;
|
|
129
|
+
try {
|
|
130
|
+
const file = path.join(homedir(), '.specweave', 'studio', 'threads', `${thread.replace(/[^\w.-]/g, '_')}.json`);
|
|
131
|
+
const binding = JSON.parse(readFileSync(file, 'utf8'));
|
|
132
|
+
const id = binding?.incrementId;
|
|
133
|
+
if (typeof binding?.root !== 'string' || !binding.root || typeof id !== 'string' || !SAFE_ID.test(id) || id === '.' || id === '..') return false;
|
|
134
|
+
const project = (dir) => path.resolve(mainCheckoutOf(dir) ?? dir);
|
|
135
|
+
if (path.resolve(binding.root) !== root && project(binding.root) !== project(root)) return false;
|
|
136
|
+
let status = '';
|
|
137
|
+
try { status = String(JSON.parse(readFileSync(path.join(binding.root, '.specweave', 'increments', id, 'metadata.json'), 'utf8'))?.status ?? ''); }
|
|
138
|
+
catch {}
|
|
139
|
+
return !CLOSED_STATUSES.has(status);
|
|
140
|
+
} catch { return false; }
|
|
141
|
+
}
|
|
142
|
+
// `--scope user`: the entry `specweave require-increment` writes to
|
|
143
|
+
// ~/.claude/settings.json runs in every project. It guards nothing (not even
|
|
144
|
+
// increment files) unless an opted-in project's marker is found, and leaves a
|
|
145
|
+
// project whose own entry Claude loaded to that entry (no second worker).
|
|
146
|
+
const USER_SCOPE = process.argv[3] === '--scope' && process.argv[4] === 'user';
|
|
147
|
+
const EDIT_HOOK_MATCHER = 'Edit|Write|MultiEdit|NotebookEdit';
|
|
148
|
+
function projectEntryLoaded(data) {
|
|
149
|
+
const dir = process.env.CLAUDE_PROJECT_DIR || (typeof data.cwd === 'string' ? data.cwd : '');
|
|
150
|
+
if (!dir) return false;
|
|
151
|
+
try {
|
|
152
|
+
const groups = JSON.parse(readFileSync(path.join(dir, '.claude', 'settings.json'), 'utf8'))?.hooks?.PreToolUse;
|
|
153
|
+
return Array.isArray(groups) && groups.some((g) => g?.matcher === EDIT_HOOK_MATCHER && Array.isArray(g.hooks)
|
|
154
|
+
&& g.hooks.some((h) => typeof h?.command === 'string' && /hooks\/run\.mjs"?\s+pre-tool-use\s*$/.test(h.command.replace(/\\/g, '/'))));
|
|
155
|
+
} catch { return false; }
|
|
156
|
+
}
|
|
66
157
|
function skipPreToolUse(data) {
|
|
67
158
|
const tool = typeof data.tool_name === 'string' ? data.tool_name : '';
|
|
159
|
+
if (USER_SCOPE && (tool === 'Bash' || findMarker(data, REQUIRE_INCREMENT_MARKER) === null || projectEntryLoaded(data))) return true;
|
|
68
160
|
if (tool === 'Bash') return !hasJevGuardMarker(data);
|
|
69
161
|
const ti = data.tool_input;
|
|
70
162
|
const filePath = ti && typeof ti === 'object' && typeof ti.file_path === 'string'
|
|
71
163
|
? ti.file_path.replace(/\\/g, '/') : '';
|
|
72
|
-
|
|
164
|
+
if (filePath.includes('.specweave/increments/')) return false;
|
|
165
|
+
if (!EDIT_TOOLS.has(tool)) return true;
|
|
166
|
+
const root = findMarker(data, REQUIRE_INCREMENT_MARKER);
|
|
167
|
+
return root === null || sessionWorksIn(data, root) || threadBoundIn(root);
|
|
73
168
|
}
|
|
74
169
|
function record(reason) {
|
|
75
170
|
try {
|
|
@@ -65,7 +65,7 @@ merge and close; do not implement.
|
|
|
65
65
|
1. Group tasks into 2 to 5 lanes whose `Files` do not overlap. Shared contracts
|
|
66
66
|
(types, schema) go in an early task the others list under `**Dependencies**: T-01`.
|
|
67
67
|
2. One worktree and branch per lane agent (your tool's or app's worktree feature, or
|
|
68
|
-
`git worktree add
|
|
68
|
+
`git worktree add .worktrees/0042-api -b inc/0042-api`, never `../`), with `SPECWEAVE_AGENT=api` set.
|
|
69
69
|
Brief each one: its tasks, this loop, "edit only their Files", and on finish
|
|
70
70
|
`specweave task release --all-mine` plus `specweave note "api: done" 0042`.
|
|
71
71
|
3. Watch with `specweave task list 0042`; `blocked` rows are your queue. A claim older
|