specweave 2.0.3 → 2.1.0
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 +3 -3
- package/README.md +15 -6
- package/dist/dashboard/assets/index-BeKUULf0.css +1 -0
- package/dist/dashboard/assets/index-Bf5TF0_l.js +13 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/src/cli/commands/sync.d.ts.map +1 -1
- package/dist/src/cli/commands/sync.js +23 -5
- package/dist/src/cli/commands/sync.js.map +1 -1
- package/dist/src/core/doctor/checkers/hooks-checker.d.ts +1 -1
- package/dist/src/core/doctor/checkers/hooks-checker.js +1 -1
- package/dist/src/core/hooks/handlers/session-start.d.ts.map +1 -1
- package/dist/src/core/hooks/handlers/session-start.js +20 -0
- package/dist/src/core/hooks/handlers/session-start.js.map +1 -1
- package/dist/src/core/intent/portable-context.d.ts +4 -0
- package/dist/src/core/intent/portable-context.d.ts.map +1 -0
- package/dist/src/core/intent/portable-context.js +68 -0
- package/dist/src/core/intent/portable-context.js.map +1 -0
- package/dist/src/core/intent/types.d.ts +28 -0
- package/dist/src/core/intent/types.d.ts.map +1 -0
- package/dist/src/core/intent/types.js +3 -0
- package/dist/src/core/intent/types.js.map +1 -0
- package/dist/src/core/intent/validation.d.ts +5 -0
- package/dist/src/core/intent/validation.d.ts.map +1 -0
- package/dist/src/core/intent/validation.js +39 -0
- package/dist/src/core/intent/validation.js.map +1 -0
- package/dist/src/core/session/handoff-pointer.d.ts +4 -0
- package/dist/src/core/session/handoff-pointer.d.ts.map +1 -0
- package/dist/src/core/session/handoff-pointer.js +60 -0
- package/dist/src/core/session/handoff-pointer.js.map +1 -0
- package/dist/src/core/session/work-handoff.d.ts.map +1 -1
- package/dist/src/core/session/work-handoff.js +10 -3
- package/dist/src/core/session/work-handoff.js.map +1 -1
- package/dist/src/dashboard/server/dashboard-server.d.ts +1 -0
- package/dist/src/dashboard/server/dashboard-server.d.ts.map +1 -1
- package/dist/src/dashboard/server/dashboard-server.js +10 -90
- package/dist/src/dashboard/server/dashboard-server.js.map +1 -1
- package/dist/src/dashboard/server/data/cost-aggregator.d.ts +10 -5
- package/dist/src/dashboard/server/data/cost-aggregator.d.ts.map +1 -1
- package/dist/src/dashboard/server/data/cost-aggregator.js +31 -33
- package/dist/src/dashboard/server/data/cost-aggregator.js.map +1 -1
- package/dist/src/dashboard/server/data/dashboard-data-aggregator.d.ts +0 -1
- package/dist/src/dashboard/server/data/dashboard-data-aggregator.d.ts.map +1 -1
- package/dist/src/dashboard/server/data/dashboard-data-aggregator.js +14 -66
- package/dist/src/dashboard/server/data/dashboard-data-aggregator.js.map +1 -1
- package/dist/src/dashboard/server/data/dashboard-task-board.d.ts +4 -0
- package/dist/src/dashboard/server/data/dashboard-task-board.d.ts.map +1 -0
- package/dist/src/dashboard/server/data/dashboard-task-board.js +56 -0
- package/dist/src/dashboard/server/data/dashboard-task-board.js.map +1 -0
- package/dist/src/dashboard/server/data/intent-store.d.ts +19 -0
- package/dist/src/dashboard/server/data/intent-store.d.ts.map +1 -0
- package/dist/src/dashboard/server/data/intent-store.js +268 -0
- package/dist/src/dashboard/server/data/intent-store.js.map +1 -0
- package/dist/src/dashboard/server/data/local-sessions.d.ts +15 -0
- package/dist/src/dashboard/server/data/local-sessions.d.ts.map +1 -0
- package/dist/src/dashboard/server/data/local-sessions.js +197 -0
- package/dist/src/dashboard/server/data/local-sessions.js.map +1 -0
- package/dist/src/dashboard/server/data/work-projection.d.ts +8 -0
- package/dist/src/dashboard/server/data/work-projection.d.ts.map +1 -0
- package/dist/src/dashboard/server/data/work-projection.js +175 -0
- package/dist/src/dashboard/server/data/work-projection.js.map +1 -0
- package/dist/src/dashboard/server/file-watcher.d.ts.map +1 -1
- package/dist/src/dashboard/server/file-watcher.js +2 -1
- package/dist/src/dashboard/server/file-watcher.js.map +1 -1
- package/dist/src/dashboard/server/local-request.d.ts +4 -0
- package/dist/src/dashboard/server/local-request.d.ts.map +1 -0
- package/dist/src/dashboard/server/local-request.js +29 -0
- package/dist/src/dashboard/server/local-request.js.map +1 -0
- package/dist/src/dashboard/server/routes/work-routes.d.ts +5 -0
- package/dist/src/dashboard/server/routes/work-routes.d.ts.map +1 -0
- package/dist/src/dashboard/server/routes/work-routes.js +37 -0
- package/dist/src/dashboard/server/routes/work-routes.js.map +1 -0
- package/dist/src/dashboard/types.d.ts +3 -3
- package/dist/src/dashboard/types.d.ts.map +1 -1
- package/dist/src/dashboard/work-types.d.ts +39 -0
- package/dist/src/dashboard/work-types.d.ts.map +1 -0
- package/dist/src/dashboard/work-types.js +3 -0
- package/dist/src/dashboard/work-types.js.map +1 -0
- package/dist/src/sync/external-change-puller.d.ts +19 -0
- package/dist/src/sync/external-change-puller.d.ts.map +1 -1
- package/dist/src/sync/external-change-puller.js +87 -77
- package/dist/src/sync/external-change-puller.js.map +1 -1
- package/package.json +3 -3
- package/plugins/specweave/.claude-plugin/plugin.json +2 -2
- package/plugins/specweave/hooks/hooks.json +1 -24
- package/plugins/specweave/hooks/run.mjs +24 -1
- package/plugins/specweave/skills/increment/SKILL.md +7 -5
- package/src/templates/AGENTS.md.template +5 -5
- package/src/templates/CLAUDE.md.template +5 -5
- package/dist/dashboard/assets/index-BiJhGDZV.js +0 -13
- package/dist/dashboard/assets/index-heYRtWFf.css +0 -1
|
@@ -12,6 +12,17 @@
|
|
|
12
12
|
* @module sync/external-change-puller
|
|
13
13
|
*/
|
|
14
14
|
import { consoleLogger } from '../utils/logger.js';
|
|
15
|
+
import { maskCredentials } from '../utils/credential-masker.js';
|
|
16
|
+
/** A rejected fetch must not be mistaken for a complete synchronization. */
|
|
17
|
+
export class ExternalPullError extends Error {
|
|
18
|
+
constructor(changes, failures, completedPlatforms) {
|
|
19
|
+
super(`External pull incomplete: ${failures.map(f => f.platform).join(', ')}.`);
|
|
20
|
+
this.changes = changes;
|
|
21
|
+
this.failures = failures;
|
|
22
|
+
this.completedPlatforms = completedPlatforms;
|
|
23
|
+
this.name = 'ExternalPullError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
15
26
|
/**
|
|
16
27
|
* ExternalChangePuller - Fetches changes from external tools
|
|
17
28
|
*
|
|
@@ -23,6 +34,7 @@ export class ExternalChangePuller {
|
|
|
23
34
|
this.projectRoot = options.projectRoot;
|
|
24
35
|
this.logger = options.logger ?? consoleLogger;
|
|
25
36
|
this.platforms = options.platforms ?? ['ado', 'jira', 'github'];
|
|
37
|
+
this.github = options.github;
|
|
26
38
|
}
|
|
27
39
|
/**
|
|
28
40
|
* Fetch recent changes from all configured platforms
|
|
@@ -30,30 +42,42 @@ export class ExternalChangePuller {
|
|
|
30
42
|
* @param since - Timestamp to query changes from
|
|
31
43
|
* @param linkedItems - Optional map of platform -> item IDs to filter
|
|
32
44
|
* @returns Array of external changes from all platforms
|
|
45
|
+
* @throws ExternalPullError with successful results when any provider fails
|
|
33
46
|
*/
|
|
34
47
|
async fetchRecentChanges(since, linkedItems) {
|
|
35
48
|
const allChanges = [];
|
|
49
|
+
const failures = [];
|
|
50
|
+
const recordFailure = (platform, error) => {
|
|
51
|
+
const message = maskCredentials(error instanceof Error ? error.message : String(error));
|
|
52
|
+
failures.push({ platform, message });
|
|
53
|
+
this.logger.warn(`${platform} fetch failed: ${message}`);
|
|
54
|
+
};
|
|
36
55
|
this.logger.log(`⬇️ Fetching changes since ${since.toISOString()}`);
|
|
37
56
|
// Fetch from each platform in parallel
|
|
38
57
|
const fetchPromises = [];
|
|
39
58
|
if (this.platforms.includes('ado')) {
|
|
40
59
|
fetchPromises.push(this.fetchAdoChanges(since, linkedItems?.ado)
|
|
41
60
|
.then(changes => { allChanges.push(...changes); })
|
|
42
|
-
.catch(err => {
|
|
61
|
+
.catch(err => { recordFailure('ado', err); }));
|
|
43
62
|
}
|
|
44
63
|
if (this.platforms.includes('jira')) {
|
|
45
64
|
fetchPromises.push(this.fetchJiraChanges(since, linkedItems?.jira)
|
|
46
65
|
.then(changes => { allChanges.push(...changes); })
|
|
47
|
-
.catch(err => {
|
|
66
|
+
.catch(err => { recordFailure('jira', err); }));
|
|
48
67
|
}
|
|
49
68
|
if (this.platforms.includes('github')) {
|
|
50
69
|
fetchPromises.push(this.fetchGitHubChanges(since, linkedItems?.github)
|
|
51
70
|
.then(changes => { allChanges.push(...changes); })
|
|
52
|
-
.catch(err => {
|
|
71
|
+
.catch(err => { recordFailure('github', err); }));
|
|
53
72
|
}
|
|
54
73
|
await Promise.all(fetchPromises);
|
|
55
74
|
// Sort by changedAt (most recent first)
|
|
56
75
|
allChanges.sort((a, b) => new Date(b.changedAt).getTime() - new Date(a.changedAt).getTime());
|
|
76
|
+
if (failures.length > 0) {
|
|
77
|
+
failures.sort((a, b) => a.platform.localeCompare(b.platform));
|
|
78
|
+
const completed = this.platforms.filter(platform => !failures.some(f => f.platform === platform));
|
|
79
|
+
throw new ExternalPullError(allChanges, failures, completed);
|
|
80
|
+
}
|
|
57
81
|
this.logger.log(`📥 Fetched ${allChanges.length} changes from external tools`);
|
|
58
82
|
return allChanges;
|
|
59
83
|
}
|
|
@@ -61,91 +85,77 @@ export class ExternalChangePuller {
|
|
|
61
85
|
* Fetch changes from Azure DevOps
|
|
62
86
|
*/
|
|
63
87
|
async fetchAdoChanges(since, linkedItemIds) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}));
|
|
82
|
-
}
|
|
83
|
-
catch (err) {
|
|
84
|
-
this.logger.debug(`ADO not configured or error: ${err.message}`);
|
|
85
|
-
return [];
|
|
86
|
-
}
|
|
88
|
+
// Dynamic import to avoid initialization errors when ADO is not configured
|
|
89
|
+
const { AdoClient } = await import('../integrations/ado/ado-client.js');
|
|
90
|
+
const client = new AdoClient();
|
|
91
|
+
const adoChanges = await client.fetchRecentChanges(since, linkedItemIds);
|
|
92
|
+
// Map to unified format
|
|
93
|
+
return adoChanges.map(change => ({
|
|
94
|
+
platform: 'ado',
|
|
95
|
+
externalId: change.externalId,
|
|
96
|
+
changedAt: change.changedAt,
|
|
97
|
+
changedBy: change.changedBy,
|
|
98
|
+
changedFields: change.changedFields,
|
|
99
|
+
currentState: {
|
|
100
|
+
status: change.currentState.status,
|
|
101
|
+
priority: change.currentState.priority,
|
|
102
|
+
assignee: change.currentState.assignee,
|
|
103
|
+
},
|
|
104
|
+
}));
|
|
87
105
|
}
|
|
88
106
|
/**
|
|
89
107
|
* Fetch changes from JIRA
|
|
90
108
|
*/
|
|
91
109
|
async fetchJiraChanges(since, linkedIssueKeys) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}));
|
|
110
|
-
}
|
|
111
|
-
catch (err) {
|
|
112
|
-
this.logger.debug(`JIRA not configured or error: ${err.message}`);
|
|
113
|
-
return [];
|
|
114
|
-
}
|
|
110
|
+
// Dynamic import to avoid initialization errors when JIRA is not configured
|
|
111
|
+
const { JiraClient } = await import('../integrations/jira/jira-client.js');
|
|
112
|
+
const client = new JiraClient();
|
|
113
|
+
const jiraChanges = await client.fetchRecentChanges(since, linkedIssueKeys);
|
|
114
|
+
// Map to unified format
|
|
115
|
+
return jiraChanges.map(change => ({
|
|
116
|
+
platform: 'jira',
|
|
117
|
+
externalId: change.externalId,
|
|
118
|
+
changedAt: change.changedAt,
|
|
119
|
+
changedBy: change.changedBy,
|
|
120
|
+
changedFields: change.changedFields,
|
|
121
|
+
currentState: {
|
|
122
|
+
status: change.currentState.status,
|
|
123
|
+
priority: change.currentState.priority,
|
|
124
|
+
assignee: change.currentState.assignee,
|
|
125
|
+
},
|
|
126
|
+
}));
|
|
115
127
|
}
|
|
116
128
|
/**
|
|
117
129
|
* Fetch changes from GitHub
|
|
118
130
|
*/
|
|
119
131
|
async fetchGitHubChanges(since, linkedIssueNumbers) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
this.logger.debug('GitHub: No git remote detected');
|
|
127
|
-
return [];
|
|
128
|
-
}
|
|
129
|
-
const client = GitHubClientV2.fromRepo(detected.owner, detected.repo);
|
|
130
|
-
const githubChanges = await client.fetchRecentChanges(since, linkedIssueNumbers);
|
|
131
|
-
// Map to unified format (GitHub returns slightly different format)
|
|
132
|
-
return githubChanges.map(change => ({
|
|
133
|
-
platform: 'github',
|
|
134
|
-
externalId: change.externalId,
|
|
135
|
-
changedAt: change.changedAt,
|
|
136
|
-
changedBy: change.changedBy,
|
|
137
|
-
changedFields: change.changedFields,
|
|
138
|
-
currentState: {
|
|
139
|
-
status: change.currentState.status,
|
|
140
|
-
priority: null, // GitHub doesn't have priority
|
|
141
|
-
assignee: change.currentState.assignee,
|
|
142
|
-
},
|
|
143
|
-
}));
|
|
144
|
-
}
|
|
145
|
-
catch (err) {
|
|
146
|
-
this.logger.debug(`GitHub not configured or error: ${err.message}`);
|
|
147
|
-
return [];
|
|
132
|
+
// Dynamic import to avoid initialization errors when GitHub is not configured
|
|
133
|
+
const { GitHubClientV2 } = await import('../../plugins/specweave/lib/integrations/github/github-client-v2.js');
|
|
134
|
+
// Detect repo from git remote
|
|
135
|
+
const detected = this.github ?? await GitHubClientV2.detectRepo(this.projectRoot);
|
|
136
|
+
if (!detected) {
|
|
137
|
+
throw new Error('No GitHub repository configured and no GitHub remote detected. Run specweave sync setup.');
|
|
148
138
|
}
|
|
139
|
+
const client = new GitHubClientV2({
|
|
140
|
+
provider: 'github',
|
|
141
|
+
displayName: `${detected.owner}/${detected.repo}`,
|
|
142
|
+
config: { owner: detected.owner, repo: detected.repo, ...(this.github?.token ? { token: this.github.token } : {}) },
|
|
143
|
+
timeRange: { default: '1M', max: '6M' },
|
|
144
|
+
}, this.projectRoot);
|
|
145
|
+
const githubChanges = await client.fetchRecentChanges(since, linkedIssueNumbers);
|
|
146
|
+
// Map to unified format (GitHub returns slightly different format)
|
|
147
|
+
return githubChanges.map(change => ({
|
|
148
|
+
platform: 'github',
|
|
149
|
+
externalId: change.externalId,
|
|
150
|
+
changedAt: change.changedAt,
|
|
151
|
+
changedBy: change.changedBy,
|
|
152
|
+
changedFields: change.changedFields,
|
|
153
|
+
currentState: {
|
|
154
|
+
status: change.currentState.status,
|
|
155
|
+
priority: null, // GitHub doesn't have priority
|
|
156
|
+
assignee: change.currentState.assignee,
|
|
157
|
+
},
|
|
158
|
+
}));
|
|
149
159
|
}
|
|
150
160
|
/**
|
|
151
161
|
* Map external status to SpecWeave status
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-change-puller.js","sourceRoot":"","sources":["../../../src/sync/external-change-puller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAU,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"external-change-puller.js","sourceRoot":"","sources":["../../../src/sync/external-change-puller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAU,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAG3D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AA4BhE,4EAA4E;AAC5E,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YACkB,OAAyB,EACzB,QAA+B,EAC/B,kBAAgD;QAEhE,KAAK,CAAC,6BAA6B,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAJhE,YAAO,GAAP,OAAO,CAAkB;QACzB,aAAQ,GAAR,QAAQ,CAAuB;QAC/B,uBAAkB,GAAlB,kBAAkB,CAA8B;QAGhE,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAwBD;;;;;GAKG;AACH,MAAM,OAAO,oBAAoB;IAM/B,YAAY,OAAoC;QAC9C,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC;QAC9C,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QAChE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,kBAAkB,CACtB,KAAW,EACX,WAIC;QAED,MAAM,UAAU,GAAqB,EAAE,CAAC;QACxC,MAAM,QAAQ,GAA0B,EAAE,CAAC;QAC3C,MAAM,aAAa,GAAG,CAAC,QAAoC,EAAE,KAAc,EAAE,EAAE;YAC7E,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACxF,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;YACrC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,kBAAkB,OAAO,EAAE,CAAC,CAAC;QAC3D,CAAC,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,8BAA8B,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAErE,uCAAuC;QACvC,MAAM,aAAa,GAAoB,EAAE,CAAC;QAE1C,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACnC,aAAa,CAAC,IAAI,CAChB,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,CAAC;iBAC1C,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;iBACjD,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAChD,CAAC;QACJ,CAAC;QAED,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACpC,aAAa,CAAC,IAAI,CAChB,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC;iBAC5C,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;iBACjD,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CACjD,CAAC;QACJ,CAAC;QAED,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtC,aAAa,CAAC,IAAI,CAChB,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC;iBAChD,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;iBACjD,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,aAAa,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CACnD,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAEjC,wCAAwC;QACxC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACvB,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAClE,CAAC;QAEF,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC9D,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC;YAClG,MAAM,IAAI,iBAAiB,CAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,UAAU,CAAC,MAAM,8BAA8B,CAAC,CAAC;QAE/E,OAAO,UAAU,CAAC;IACpB,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,eAAe,CAC3B,KAAW,EACX,aAAwB;QAExB,2EAA2E;QAC3E,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,mCAAmC,CAAC,CAAC;QACxE,MAAM,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAE/B,MAAM,UAAU,GAAwB,MAAM,MAAM,CAAC,kBAAkB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QAE9F,wBAAwB;QACxB,OAAO,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC/B,QAAQ,EAAE,KAAc;YACxB,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,YAAY,EAAE;gBACZ,MAAM,EAAE,MAAM,CAAC,YAAY,CAAC,MAAM;gBAClC,QAAQ,EAAE,MAAM,CAAC,YAAY,CAAC,QAAQ;gBACtC,QAAQ,EAAE,MAAM,CAAC,YAAY,CAAC,QAAQ;aACvC;SACF,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,gBAAgB,CAC5B,KAAW,EACX,eAA0B;QAE1B,4EAA4E;QAC5E,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,qCAAqC,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAEhC,MAAM,WAAW,GAAyB,MAAM,MAAM,CAAC,kBAAkB,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;QAElG,wBAAwB;QACxB,OAAO,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAChC,QAAQ,EAAE,MAAe;YACzB,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,YAAY,EAAE;gBACZ,MAAM,EAAE,MAAM,CAAC,YAAY,CAAC,MAAM;gBAClC,QAAQ,EAAE,MAAM,CAAC,YAAY,CAAC,QAAQ;gBACtC,QAAQ,EAAE,MAAM,CAAC,YAAY,CAAC,QAAQ;aACvC;SACF,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,kBAAkB,CAC9B,KAAW,EACX,kBAA6B;QAE7B,8EAA8E;QAC9E,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,qEAAqE,CAAC,CAAC;QAE/G,8BAA8B;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAClF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,0FAA0F,CAAC,CAAC;QAC9G,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;YAChC,QAAQ,EAAE,QAAQ;YAClB,WAAW,EAAE,GAAG,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC,IAAI,EAAE;YACjD,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;YACnH,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE;SACxC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACrB,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;QAEjF,mEAAmE;QACnE,OAAO,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAClC,QAAQ,EAAE,QAAiB;YAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,YAAY,EAAE;gBACZ,MAAM,EAAE,MAAM,CAAC,YAAY,CAAC,MAAM;gBAClC,QAAQ,EAAE,IAA8B,EAAE,+BAA+B;gBACzE,QAAQ,EAAE,MAAM,CAAC,YAAY,CAAC,QAAQ;aACvC;SACF,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;;;OAIG;IACH,oBAAoB,CAClB,QAAmC,EACnC,cAAsB;QAEtB,6BAA6B;QAC7B,MAAM,UAAU,GAA2C;YACzD,GAAG,EAAE;gBACH,KAAK,EAAE,SAAS;gBAChB,QAAQ,EAAE,aAAa;gBACvB,UAAU,EAAE,WAAW;gBACvB,QAAQ,EAAE,WAAW;gBACrB,SAAS,EAAE,WAAW;aACvB;YACD,IAAI,EAAE;gBACJ,OAAO,EAAE,SAAS;gBAClB,aAAa,EAAE,aAAa;gBAC5B,MAAM,EAAE,WAAW;gBACnB,QAAQ,EAAE,WAAW;gBACrB,WAAW,EAAE,WAAW;aACzB;YACD,MAAM,EAAE;gBACN,MAAM,EAAE,aAAa;gBACrB,QAAQ,EAAE,WAAW;aACtB;SACF,CAAC;QAEF,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACvC,OAAO,GAAG,CAAC,cAAc,CAAC,IAAI,cAAc,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAClF,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specweave",
|
|
3
|
-
"version": "2.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.1.0",
|
|
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": {
|
|
7
7
|
"specweave": "./bin/specweave.js"
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"preinstall": "node scripts/check-node-version.js || exit 0",
|
|
11
11
|
"preuninstall": "node scripts/preuninstall.cjs",
|
|
12
12
|
"version": "node scripts/build/auto-changelog.js && node scripts/build/stamp-plugin-version.cjs && git add CHANGELOG.md plugins/specweave/.claude-plugin/plugin.json .claude-plugin/marketplace.json",
|
|
13
|
-
"postversion": "echo '
|
|
13
|
+
"postversion": "echo '\u2705 Version bumped with CHANGELOG entry'",
|
|
14
14
|
"clean": "rm -rf dist/",
|
|
15
15
|
"build": "tsc && npm run build:dashboard && npm run copy:locales && npm run copy:plugins && npm run copy:hook-deps && npm run copy:adapters && npm run stamp:plugin-version",
|
|
16
16
|
"stamp:plugin-version": "node scripts/build/stamp-plugin-version.cjs",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sw",
|
|
3
|
-
"description": "
|
|
4
|
-
"version": "2.0
|
|
3
|
+
"description": "Portable intent and verified progress across coding tools. Ten focused workflow skills, two default lifecycle hooks, and a deterministic CLI and live local dashboard.",
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "SpecWeave Team",
|
|
7
7
|
"url": "https://spec-weave.com"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "
|
|
2
|
+
"description": "Minimal hooks: compact session context and an opt-in auto loop. Handoffs are explicit CLI actions.",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"SessionStart": [
|
|
5
5
|
{
|
|
@@ -12,18 +12,6 @@
|
|
|
12
12
|
]
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
|
-
"PreToolUse": [
|
|
16
|
-
{
|
|
17
|
-
"matcher": "Write|Edit",
|
|
18
|
-
"hooks": [
|
|
19
|
-
{
|
|
20
|
-
"type": "command",
|
|
21
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run.mjs\" pre-tool-use",
|
|
22
|
-
"timeout": 10
|
|
23
|
-
}
|
|
24
|
-
]
|
|
25
|
-
}
|
|
26
|
-
],
|
|
27
15
|
"Stop": [
|
|
28
16
|
{
|
|
29
17
|
"hooks": [
|
|
@@ -34,17 +22,6 @@
|
|
|
34
22
|
}
|
|
35
23
|
]
|
|
36
24
|
}
|
|
37
|
-
],
|
|
38
|
-
"PreCompact": [
|
|
39
|
-
{
|
|
40
|
-
"hooks": [
|
|
41
|
-
{
|
|
42
|
-
"type": "command",
|
|
43
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run.mjs\" pre-compact",
|
|
44
|
-
"timeout": 10
|
|
45
|
-
}
|
|
46
|
-
]
|
|
47
|
-
}
|
|
48
25
|
]
|
|
49
26
|
}
|
|
50
27
|
}
|
|
@@ -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, mkdirSync } from 'node:fs';
|
|
4
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
5
5
|
import { homedir } from 'node:os';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
@@ -10,6 +10,27 @@ const worker = path.join(path.dirname(fileURLToPath(import.meta.url)), 'run-work
|
|
|
10
10
|
const budget = event === 'stop' ? 25000 : 7500;
|
|
11
11
|
let child, finished = false, input = '', output = '', size = 0;
|
|
12
12
|
const started = Date.now();
|
|
13
|
+
// Ordinary turns should not resolve npm, import the CLI, or start a second Node
|
|
14
|
+
// process. Auto mode is explicit and its small local marker is authoritative.
|
|
15
|
+
function hasActiveAutoSession(data) {
|
|
16
|
+
let current = path.resolve(typeof data.cwd === 'string' ? data.cwd : process.cwd());
|
|
17
|
+
for (let depth = 0; depth < 100; depth++) {
|
|
18
|
+
const state = path.join(current, '.specweave', 'state');
|
|
19
|
+
if (existsSync(path.join(current, '.specweave', 'config.json'))) {
|
|
20
|
+
const sessionId = process.env.CLAUDE_SESSION_ID;
|
|
21
|
+
// Match session-state-manager's path-safe IDs, including dots and spaces.
|
|
22
|
+
const scoped = sessionId && !/[/\\]|\.\.|\0/.test(sessionId)
|
|
23
|
+
? path.join(state, 'sessions', sessionId, 'auto-mode.json') : null;
|
|
24
|
+
const marker = scoped && existsSync(scoped) ? scoped : path.join(state, 'auto-mode.json');
|
|
25
|
+
try { return JSON.parse(readFileSync(marker, 'utf8')).active === true; }
|
|
26
|
+
catch { return false; }
|
|
27
|
+
}
|
|
28
|
+
const parent = path.dirname(current);
|
|
29
|
+
if (parent === current) break;
|
|
30
|
+
current = parent;
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
13
34
|
function record(reason) {
|
|
14
35
|
try {
|
|
15
36
|
const dir = path.join(homedir(), '.specweave', 'logs');
|
|
@@ -49,6 +70,8 @@ process.stdin.on('end',()=>{
|
|
|
49
70
|
try {data=JSON.parse(input);if(!data || typeof data!=='object'||Array.isArray(data))throw Error();}
|
|
50
71
|
catch {return finish({},'invalid_input');}
|
|
51
72
|
if(!['session-start','pre-tool-use','pre-compact','stop'].includes(event))return finish({});
|
|
73
|
+
if(process.env.SPECWEAVE_DISABLE_HOOKS === '1')return finish({});
|
|
74
|
+
if(event === 'stop' && !hasActiveAutoSession(data))return finish({});
|
|
52
75
|
const env={...process.env};
|
|
53
76
|
child=spawn(process.execPath,[worker,event],{env,detached:process.platform !== 'win32',stdio:['pipe','pipe','pipe']});
|
|
54
77
|
child.stdout.setEncoding('utf8');
|
|
@@ -11,11 +11,13 @@ An increment is one folder — `.specweave/increments/NNNN-slug/` — holding
|
|
|
11
11
|
`ledger.jsonl` (state, written by the CLI) and `metadata.json`. It is the unit of
|
|
12
12
|
work and the tracker; every commit for it carries its id in the subject.
|
|
13
13
|
|
|
14
|
-
##
|
|
14
|
+
## Scope before implementation
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
Write a concise plan for work that needs shared acceptance criteria. Ask only about
|
|
17
|
+
material ambiguity or actions beyond the user's authorization. When the user has
|
|
18
|
+
asked for autonomous execution, make routine decisions and continue through
|
|
19
|
+
implementation and verification. A small self-contained fix can remain a
|
|
20
|
+
lightweight intent without this workflow.
|
|
19
21
|
|
|
20
22
|
## Steps
|
|
21
23
|
|
|
@@ -79,7 +81,7 @@ confirmation. Do not create files, do not implement, until the plan is approved.
|
|
|
79
81
|
least one task; every task needs a `Test:` that a machine can run (or an explicit
|
|
80
82
|
"manual: <what to check>"). Shared contracts (types, schema, migrations) go in an early
|
|
81
83
|
task everything else depends on.
|
|
82
|
-
6. **
|
|
84
|
+
6. **Share the plan** (problem, ACs, tasks, material risks). Resolve any remaining decision that needs the user; otherwise continue within existing authorization.
|
|
83
85
|
7. **Hand off to execution**: `sw:do <id>` for one agent; `sw:team <id>` when the work has
|
|
84
86
|
3+ disjoint lanes or 15+ tasks.
|
|
85
87
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- SECTION:header required -->
|
|
2
2
|
# {PROJECT_NAME}
|
|
3
3
|
|
|
4
|
-
SpecWeave project.
|
|
4
|
+
SpecWeave project. Small requests live in the intent board; scoped work lives in increments under `.specweave/increments/NNNN-slug/`. `spec.md` (Problem, ACs, Approach) is the source of truth; the ledger records who did what. This file is for Codex, OpenCode, Cursor, Gemini, Aider and humans; Claude Code reads CLAUDE.md (same content). Keep it under one page; project-specific notes go in **Project notes** at the bottom.
|
|
5
5
|
<!-- /SECTION -->
|
|
6
6
|
|
|
7
7
|
<!-- SECTION:structure -->
|
|
@@ -9,6 +9,7 @@ SpecWeave project. Work happens in increments under `.specweave/increments/NNNN-
|
|
|
9
9
|
|
|
10
10
|
```
|
|
11
11
|
.specweave/
|
|
12
|
+
intents/board.jsonl append-only intent history (latest revision per id; planning state, not verification)
|
|
12
13
|
increments/NNNN-slug/ spec.md (Problem · ACs · Approach) · tasks.md (tasks + rendered board) · ledger.jsonl (claims/done, CLI-written) · handoff.md · reports/ (evidence; binaries in reports/artifacts/, gitignored)
|
|
13
14
|
docs/ ADRs and hand-written docs (read before changing architecture)
|
|
14
15
|
config.json
|
|
@@ -23,7 +24,7 @@ Only those files (plus optional `plan.md` when Approach outgrows a page, and `sc
|
|
|
23
24
|
|
|
24
25
|
| Step | Command (each step is also a standalone skill you can install into any tool with `npx vskill install anton-abyzov/specweave/sw-do` — same for `sw-increment`, `sw-review`, `sw-handoff`, `sw-task`) |
|
|
25
26
|
|---|---|
|
|
26
|
-
| Plan a feature: write `spec.md` (Problem, Scope, `AC-01…` checkboxes, Approach: files that change, order of work, risks, decisions),
|
|
27
|
+
| Plan a feature: write `spec.md` (Problem, Scope, `AC-01…` checkboxes, Approach: files that change, order of work, risks, decisions), resolve material scope questions before implementation | `specweave create-increment "title"` |
|
|
27
28
|
| Work the tasks | `specweave task next` → `specweave task claim T-NN` → implement → commit (`NNNN: …`) → `specweave task done T-NN --run "<test cmd>"` (the command runs through your OS shell: cmd.exe on Windows, sh elsewhere) |
|
|
28
29
|
| Verify the whole increment | `specweave verify` |
|
|
29
30
|
| Review before closing (recommended for anything that ships) | in a fresh session: read spec.md, list findings by severity citing path:line, re-verify each before writing `reports/review.md`; the authoring session never approves its own work |
|
|
@@ -31,7 +32,7 @@ Only those files (plus optional `plan.md` when Approach outgrows a page, and `sc
|
|
|
31
32
|
| Stop for any reason | `specweave handoff` |
|
|
32
33
|
|
|
33
34
|
Without the `specweave` CLI: create the folder by hand (id = highest existing 4-digit prefix + 1, zero-padded); append one JSON line per event to `ledger.jsonl` as UTF-8 without BOM, LF-terminated, e.g. `{"t":"T-01","e":"claim","by":"<tool>@<host>","at":"<ISO>"}` (bash: `>>`; PowerShell: `[IO.File]::AppendAllText('ledger.jsonl', $line + "`n")`, never `>>`, it writes UTF-16); mark done with the same line using `"e":"done","evidence":"<commit sha>"` after the Test command exits 0; write `reports/verify.md` with the real test output and say the increment is ready to close (closing itself needs the CLI).
|
|
34
|
-
|
|
35
|
+
Use an increment for work that needs shared scope, acceptance criteria, or a handoff. Small self-contained fixes can remain a lightweight intent. For bugs, reproduce the failure and add a regression test when it protects behavior. User authorization carries through routine implementation and verification.
|
|
35
36
|
<!-- /SECTION -->
|
|
36
37
|
|
|
37
38
|
<!-- SECTION:verify required -->
|
|
@@ -48,8 +49,7 @@ Run the project's build/test/lint (see **Commands**) before reporting any task c
|
|
|
48
49
|
3. Never edit ledger lines or another task's status; append only. On a git conflict in `ledger.jsonl` keep every line from both sides.
|
|
49
50
|
4. `done` needs the task's **Test** command exit 0 and a commit sha. A task that turns out unnecessary is closed with `specweave task skip T-NN --reason "..."` (no CLI: append a `skip` ledger line with a reason), never ticked.
|
|
50
51
|
5. When you stop: `specweave task release --all-mine` then `specweave handoff`.
|
|
51
|
-
|
|
52
|
-
Resuming: find the active increment with `specweave status` (or the `NNNN-*` folder whose `metadata.json` has `"status": "active"`), read `spec.md`, then the latest `handoff.md`, then `specweave task next`.
|
|
52
|
+
Resuming: check `.specweave/intents/board.jsonl` (latest revision per id) or `specweave dashboard` for unfinished intents, including work without an increment. Then find the active increment with `specweave status` (or the `NNNN-*` folder whose `metadata.json` has `"status": "active"`), read `spec.md`, then the latest `handoff.md`, then `specweave task next`.
|
|
53
53
|
<!-- /SECTION -->
|
|
54
54
|
|
|
55
55
|
<!-- SECTION:conventions required -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- SECTION:header required -->
|
|
2
2
|
# {PROJECT_NAME}
|
|
3
3
|
|
|
4
|
-
SpecWeave project.
|
|
4
|
+
SpecWeave project. Small requests live in the intent board; scoped work lives in increments under `.specweave/increments/NNNN-slug/`. `spec.md` (Problem, ACs, Approach) is the source of truth; the ledger records who did what. Keep this file under one page; project-specific notes go in **Project notes** at the bottom.
|
|
5
5
|
<!-- /SECTION -->
|
|
6
6
|
|
|
7
7
|
<!-- SECTION:structure -->
|
|
@@ -9,6 +9,7 @@ SpecWeave project. Work happens in increments under `.specweave/increments/NNNN-
|
|
|
9
9
|
|
|
10
10
|
```
|
|
11
11
|
.specweave/
|
|
12
|
+
intents/board.jsonl append-only intent history (latest revision per id; planning state, not verification)
|
|
12
13
|
increments/NNNN-slug/ spec.md (Problem · ACs · Approach) · tasks.md (tasks + rendered board) · ledger.jsonl (claims/done, CLI-written) · handoff.md · reports/ (evidence; binaries in reports/artifacts/, gitignored)
|
|
13
14
|
docs/ ADRs and hand-written docs (read before changing architecture)
|
|
14
15
|
config.json
|
|
@@ -23,14 +24,14 @@ Only those files (plus optional `plan.md` when Approach outgrows a page, and `sc
|
|
|
23
24
|
|
|
24
25
|
| Step | Command |
|
|
25
26
|
|---|---|
|
|
26
|
-
| Plan a feature (spec.md with ACs + Approach
|
|
27
|
+
| Plan a feature (spec.md with ACs + Approach; resolve material scope questions) | `/sw:increment "title"` |
|
|
27
28
|
| Work the tasks (claim → implement → commit → done with evidence) | `/sw:do` (loops `specweave task next` / `claim` / `done --run`) |
|
|
28
29
|
| Verify the whole increment | `specweave verify` |
|
|
29
30
|
| Review before closing (recommended for anything that ships: fresh context, findings cite path:line and are re-verified) | `/sw:review` |
|
|
30
31
|
| Close (needs a green verify or `--reason`) | `/sw:done` |
|
|
31
32
|
| Stop for any reason (context, tokens, switching tools) | `/sw:handoff` |
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
Use an increment for work that needs shared scope, acceptance criteria, or a handoff. Small self-contained fixes can remain a lightweight intent. For bugs, reproduce the failure and add a regression test when it protects behavior. User authorization carries through routine implementation and verification.
|
|
34
35
|
<!-- /SECTION -->
|
|
35
36
|
|
|
36
37
|
<!-- SECTION:verify required -->
|
|
@@ -47,8 +48,7 @@ Run the project's build/test/lint (see **Commands**) before reporting any task c
|
|
|
47
48
|
3. Never edit ledger lines or another task's status; append only. On a git conflict in `ledger.jsonl` keep every line from both sides.
|
|
48
49
|
4. `done` needs the task's **Test** command exit 0 and a commit sha. A task that turns out unnecessary is closed with `specweave task skip T-NN --reason "..."`, never ticked.
|
|
49
50
|
5. When you stop: `specweave task release --all-mine` then `/sw:handoff`.
|
|
50
|
-
|
|
51
|
-
Resuming: find the active increment with `specweave status` (or the `NNNN-*` folder whose `metadata.json` has `"status": "active"`), read `spec.md`, then the latest `handoff.md`, then `/sw:do`.
|
|
51
|
+
Resuming: check `.specweave/intents/board.jsonl` (latest revision per id) or `specweave dashboard` for unfinished intents, including work without an increment. Then find the active increment with `specweave status` (or the `NNNN-*` folder whose `metadata.json` has `"status": "active"`), read `spec.md`, then the latest `handoff.md`, then `/sw:do`.
|
|
52
52
|
<!-- /SECTION -->
|
|
53
53
|
|
|
54
54
|
<!-- SECTION:conventions required -->
|