@exodus/openspec 1.2.3 → 1.2.5
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/core/init.js +2 -1
- package/dist/core/list.d.ts +1 -0
- package/dist/core/list.js +74 -0
- package/dist/core/templates/workflows/bulk-archive-change.js +34 -2
- package/dist/core/templates/workflows/ff-change.js +54 -22
- package/dist/core/templates/workflows/new-change.js +50 -18
- package/dist/core/templates/workflows/sync-specs.js +36 -2
- package/dist/core/templates/workflows/verify-change.js +36 -2
- package/dist/core/update.js +4 -2
- package/dist/utils/item-discovery.d.ts +7 -0
- package/dist/utils/item-discovery.js +57 -0
- package/package.json +1 -1
package/dist/core/init.js
CHANGED
|
@@ -407,7 +407,8 @@ export class InitCommand {
|
|
|
407
407
|
const generatedCommands = generateCommands(commandContents, adapter);
|
|
408
408
|
for (const cmd of generatedCommands) {
|
|
409
409
|
const commandFile = path.isAbsolute(cmd.path) ? cmd.path : path.join(projectPath, cmd.path);
|
|
410
|
-
|
|
410
|
+
const commandContent = cliTransformer ? cliTransformer(cmd.fileContent) : cmd.fileContent;
|
|
411
|
+
await FileSystemUtils.writeFile(commandFile, commandContent);
|
|
411
412
|
}
|
|
412
413
|
}
|
|
413
414
|
else {
|
package/dist/core/list.d.ts
CHANGED
package/dist/core/list.js
CHANGED
|
@@ -4,6 +4,7 @@ import { getTaskProgressForChange, formatTaskStatus } from '../utils/task-progre
|
|
|
4
4
|
import { readFileSync } from 'fs';
|
|
5
5
|
import { join } from 'path';
|
|
6
6
|
import { MarkdownParser } from './parsers/markdown-parser.js';
|
|
7
|
+
import { readWorkspaceConfig } from './workspace.js';
|
|
7
8
|
/**
|
|
8
9
|
* Get the most recent modification time of any file in a directory (recursive).
|
|
9
10
|
* Falls back to the directory's own mtime if no files are found.
|
|
@@ -63,6 +64,11 @@ export class ListCommand {
|
|
|
63
64
|
async execute(targetPath = '.', mode = 'changes', options = {}) {
|
|
64
65
|
const { sort = 'recent', json = false } = options;
|
|
65
66
|
if (mode === 'changes') {
|
|
67
|
+
const workspace = readWorkspaceConfig(targetPath);
|
|
68
|
+
if (workspace) {
|
|
69
|
+
await this.executeWorkspaceChanges(targetPath, workspace, { sort, json });
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
66
72
|
const changesDir = path.join(targetPath, 'openspec', 'changes');
|
|
67
73
|
// Check if changes directory exists
|
|
68
74
|
try {
|
|
@@ -167,5 +173,73 @@ export class ListCommand {
|
|
|
167
173
|
console.log(`${padding}${padded} requirements ${spec.requirementCount}`);
|
|
168
174
|
}
|
|
169
175
|
}
|
|
176
|
+
async executeWorkspaceChanges(targetPath, workspace, options) {
|
|
177
|
+
const changes = [];
|
|
178
|
+
const collectChanges = async (dir, scope) => {
|
|
179
|
+
try {
|
|
180
|
+
await fs.access(dir);
|
|
181
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
182
|
+
const changeDirs = entries
|
|
183
|
+
.filter(e => e.isDirectory() && e.name !== 'archive')
|
|
184
|
+
.map(e => e.name);
|
|
185
|
+
for (const changeDir of changeDirs) {
|
|
186
|
+
const progress = await getTaskProgressForChange(dir, changeDir);
|
|
187
|
+
const changePath = path.join(dir, changeDir);
|
|
188
|
+
const lastModified = await getLastModified(changePath);
|
|
189
|
+
changes.push({ name: changeDir, scope, completedTasks: progress.completed, totalTasks: progress.total, lastModified });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// directory doesn't exist — skip
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
await collectChanges(path.join(targetPath, 'openspec', 'changes'), null);
|
|
197
|
+
for (const scope of workspace.scopes) {
|
|
198
|
+
const scopeRoot = path.resolve(targetPath, scope.path);
|
|
199
|
+
await collectChanges(path.join(scopeRoot, 'openspec', 'changes'), scope.name);
|
|
200
|
+
}
|
|
201
|
+
if (changes.length === 0) {
|
|
202
|
+
if (options.json) {
|
|
203
|
+
console.log(JSON.stringify({ changes: [] }));
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
console.log('No active changes found.');
|
|
207
|
+
}
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (options.sort === 'recent') {
|
|
211
|
+
changes.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
changes.sort((a, b) => {
|
|
215
|
+
const scopeA = a.scope ?? '';
|
|
216
|
+
const scopeB = b.scope ?? '';
|
|
217
|
+
return scopeA !== scopeB ? scopeA.localeCompare(scopeB) : a.name.localeCompare(b.name);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
if (options.json) {
|
|
221
|
+
const jsonOutput = changes.map(c => ({
|
|
222
|
+
name: c.name,
|
|
223
|
+
scope: c.scope,
|
|
224
|
+
completedTasks: c.completedTasks,
|
|
225
|
+
totalTasks: c.totalTasks,
|
|
226
|
+
lastModified: c.lastModified.toISOString(),
|
|
227
|
+
status: c.totalTasks === 0 ? 'no-tasks' : c.completedTasks === c.totalTasks ? 'complete' : 'in-progress',
|
|
228
|
+
}));
|
|
229
|
+
console.log(JSON.stringify({ changes: jsonOutput }, null, 2));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
console.log('Changes:');
|
|
233
|
+
const padding = ' ';
|
|
234
|
+
const nameWidth = Math.max(...changes.map(c => c.name.length));
|
|
235
|
+
const scopeWidth = Math.max(...changes.map(c => (c.scope ?? 'root').length)) + 2;
|
|
236
|
+
for (const change of changes) {
|
|
237
|
+
const scopeLabel = `[${change.scope ?? 'root'}]`.padEnd(scopeWidth);
|
|
238
|
+
const paddedName = change.name.padEnd(nameWidth);
|
|
239
|
+
const status = formatTaskStatus({ total: change.totalTasks, completed: change.completedTasks });
|
|
240
|
+
const timeAgo = formatRelativeTime(change.lastModified);
|
|
241
|
+
console.log(`${padding}${scopeLabel} ${paddedName} ${status.padEnd(12)} ${timeAgo}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
170
244
|
}
|
|
171
245
|
//# sourceMappingURL=list.js.map
|
|
@@ -12,7 +12,23 @@ This skill allows you to batch-archive changes, handling spec conflicts intellig
|
|
|
12
12
|
|
|
13
13
|
1. **Get active changes**
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Check for a workspace manifest:
|
|
16
|
+
\`\`\`bash
|
|
17
|
+
cat openspec/workspace.yaml 2>/dev/null
|
|
18
|
+
\`\`\`
|
|
19
|
+
|
|
20
|
+
If workspace.yaml exists, list changes across all scopes:
|
|
21
|
+
\`\`\`bash
|
|
22
|
+
(cd <scope.path> && openspec list --json) # for each scope in workspace.yaml
|
|
23
|
+
ls openspec/changes/ 2>/dev/null # umbrella changes at root
|
|
24
|
+
\`\`\`
|
|
25
|
+
|
|
26
|
+
Otherwise:
|
|
27
|
+
\`\`\`bash
|
|
28
|
+
openspec list --json
|
|
29
|
+
\`\`\`
|
|
30
|
+
|
|
31
|
+
Aggregate all results. In workspace mode, track which scope each change belongs to.
|
|
16
32
|
|
|
17
33
|
If no active changes exist, inform user and stop.
|
|
18
34
|
|
|
@@ -258,7 +274,23 @@ This skill allows you to batch-archive changes, handling spec conflicts intellig
|
|
|
258
274
|
|
|
259
275
|
1. **Get active changes**
|
|
260
276
|
|
|
261
|
-
|
|
277
|
+
Check for a workspace manifest:
|
|
278
|
+
\`\`\`bash
|
|
279
|
+
cat openspec/workspace.yaml 2>/dev/null
|
|
280
|
+
\`\`\`
|
|
281
|
+
|
|
282
|
+
If workspace.yaml exists, list changes across all scopes:
|
|
283
|
+
\`\`\`bash
|
|
284
|
+
(cd <scope.path> && openspec list --json) # for each scope in workspace.yaml
|
|
285
|
+
ls openspec/changes/ 2>/dev/null # umbrella changes at root
|
|
286
|
+
\`\`\`
|
|
287
|
+
|
|
288
|
+
Otherwise:
|
|
289
|
+
\`\`\`bash
|
|
290
|
+
openspec list --json
|
|
291
|
+
\`\`\`
|
|
292
|
+
|
|
293
|
+
Aggregate all results. In workspace mode, track which scope each change belongs to.
|
|
262
294
|
|
|
263
295
|
If no active changes exist, inform user and stop.
|
|
264
296
|
|
|
@@ -17,21 +17,37 @@ export function getFfChangeSkillTemplate() {
|
|
|
17
17
|
|
|
18
18
|
**IMPORTANT**: Do NOT proceed without understanding what the user wants to build.
|
|
19
19
|
|
|
20
|
-
2. **
|
|
20
|
+
2. **Detect workspace and select scope**
|
|
21
|
+
|
|
22
|
+
Check for a workspace manifest:
|
|
23
|
+
\`\`\`bash
|
|
24
|
+
cat openspec/workspace.yaml 2>/dev/null
|
|
25
|
+
\`\`\`
|
|
26
|
+
|
|
27
|
+
If workspace.yaml exists, ask which scope this change belongs to (show the list of scopes from workspace.yaml). Store the selected scope's path as \`<workspace>\`.
|
|
28
|
+
|
|
29
|
+
If no workspace.yaml (single-project), set \`<workspace>\` to the current directory.
|
|
30
|
+
|
|
31
|
+
All subsequent \`openspec\` commands must run as:
|
|
32
|
+
\`\`\`bash
|
|
33
|
+
(cd <workspace> && openspec ...)
|
|
34
|
+
\`\`\`
|
|
35
|
+
|
|
36
|
+
3. **Create the change directory**
|
|
21
37
|
\`\`\`bash
|
|
22
|
-
openspec new change "<name>"
|
|
38
|
+
(cd <workspace> && openspec new change "<name>")
|
|
23
39
|
\`\`\`
|
|
24
|
-
This creates a scaffolded change at
|
|
40
|
+
This creates a scaffolded change at \`<workspace>/openspec/changes/<name>/\`.
|
|
25
41
|
|
|
26
|
-
|
|
42
|
+
4. **Get the artifact build order**
|
|
27
43
|
\`\`\`bash
|
|
28
|
-
openspec status --change "<name>" --json
|
|
44
|
+
(cd <workspace> && openspec status --change "<name>" --json)
|
|
29
45
|
\`\`\`
|
|
30
46
|
Parse the JSON to get:
|
|
31
47
|
- \`applyRequires\`: array of artifact IDs needed before implementation (e.g., \`["tasks"]\`)
|
|
32
48
|
- \`artifacts\`: list of all artifacts with their status and dependencies
|
|
33
49
|
|
|
34
|
-
|
|
50
|
+
5. **Create artifacts in sequence until apply-ready**
|
|
35
51
|
|
|
36
52
|
Use the **TodoWrite tool** to track progress through the artifacts.
|
|
37
53
|
|
|
@@ -40,7 +56,7 @@ export function getFfChangeSkillTemplate() {
|
|
|
40
56
|
a. **For each artifact that is \`ready\` (dependencies satisfied)**:
|
|
41
57
|
- Get instructions:
|
|
42
58
|
\`\`\`bash
|
|
43
|
-
openspec instructions <artifact-id> --change "<name>" --json
|
|
59
|
+
(cd <workspace> && openspec instructions <artifact-id> --change "<name>" --json)
|
|
44
60
|
\`\`\`
|
|
45
61
|
- The instructions JSON includes:
|
|
46
62
|
- \`context\`: Project background (constraints for you - do NOT include in output)
|
|
@@ -55,7 +71,7 @@ export function getFfChangeSkillTemplate() {
|
|
|
55
71
|
- Show brief progress: "✓ Created <artifact-id>"
|
|
56
72
|
|
|
57
73
|
b. **Continue until all \`applyRequires\` artifacts are complete**
|
|
58
|
-
- After creating each artifact, re-run \`openspec status --change "<name>" --json\`
|
|
74
|
+
- After creating each artifact, re-run \`(cd <workspace> && openspec status --change "<name>" --json)\`
|
|
59
75
|
- Check if every artifact ID in \`applyRequires\` has \`status: "done"\` in the artifacts array
|
|
60
76
|
- Stop when all \`applyRequires\` artifacts are done
|
|
61
77
|
|
|
@@ -63,15 +79,15 @@ export function getFfChangeSkillTemplate() {
|
|
|
63
79
|
- Use **AskUserQuestion tool** to clarify
|
|
64
80
|
- Then continue with creation
|
|
65
81
|
|
|
66
|
-
|
|
82
|
+
6. **Show final status**
|
|
67
83
|
\`\`\`bash
|
|
68
|
-
openspec status --change "<name>"
|
|
84
|
+
(cd <workspace> && openspec status --change "<name>")
|
|
69
85
|
\`\`\`
|
|
70
86
|
|
|
71
87
|
**Output**
|
|
72
88
|
|
|
73
89
|
After completing all artifacts, summarize:
|
|
74
|
-
- Change name and location
|
|
90
|
+
- Change name and location (including scope if in a workspace)
|
|
75
91
|
- List of artifacts created with brief descriptions
|
|
76
92
|
- What's ready: "All artifacts created! Ready for implementation."
|
|
77
93
|
- Prompt: "Run \`/opsx:apply\` or ask me to implement to start working on the tasks."
|
|
@@ -118,21 +134,37 @@ export function getOpsxFfCommandTemplate() {
|
|
|
118
134
|
|
|
119
135
|
**IMPORTANT**: Do NOT proceed without understanding what the user wants to build.
|
|
120
136
|
|
|
121
|
-
2. **
|
|
137
|
+
2. **Detect workspace and select scope**
|
|
138
|
+
|
|
139
|
+
Check for a workspace manifest:
|
|
140
|
+
\`\`\`bash
|
|
141
|
+
cat openspec/workspace.yaml 2>/dev/null
|
|
142
|
+
\`\`\`
|
|
143
|
+
|
|
144
|
+
If workspace.yaml exists, ask which scope this change belongs to (show the list of scopes from workspace.yaml). Store the selected scope's path as \`<workspace>\`.
|
|
145
|
+
|
|
146
|
+
If no workspace.yaml (single-project), set \`<workspace>\` to the current directory.
|
|
147
|
+
|
|
148
|
+
All subsequent \`openspec\` commands must run as:
|
|
149
|
+
\`\`\`bash
|
|
150
|
+
(cd <workspace> && openspec ...)
|
|
151
|
+
\`\`\`
|
|
152
|
+
|
|
153
|
+
3. **Create the change directory**
|
|
122
154
|
\`\`\`bash
|
|
123
|
-
openspec new change "<name>"
|
|
155
|
+
(cd <workspace> && openspec new change "<name>")
|
|
124
156
|
\`\`\`
|
|
125
|
-
This creates a scaffolded change at
|
|
157
|
+
This creates a scaffolded change at \`<workspace>/openspec/changes/<name>/\`.
|
|
126
158
|
|
|
127
|
-
|
|
159
|
+
4. **Get the artifact build order**
|
|
128
160
|
\`\`\`bash
|
|
129
|
-
openspec status --change "<name>" --json
|
|
161
|
+
(cd <workspace> && openspec status --change "<name>" --json)
|
|
130
162
|
\`\`\`
|
|
131
163
|
Parse the JSON to get:
|
|
132
164
|
- \`applyRequires\`: array of artifact IDs needed before implementation (e.g., \`["tasks"]\`)
|
|
133
165
|
- \`artifacts\`: list of all artifacts with their status and dependencies
|
|
134
166
|
|
|
135
|
-
|
|
167
|
+
5. **Create artifacts in sequence until apply-ready**
|
|
136
168
|
|
|
137
169
|
Use the **TodoWrite tool** to track progress through the artifacts.
|
|
138
170
|
|
|
@@ -141,7 +173,7 @@ export function getOpsxFfCommandTemplate() {
|
|
|
141
173
|
a. **For each artifact that is \`ready\` (dependencies satisfied)**:
|
|
142
174
|
- Get instructions:
|
|
143
175
|
\`\`\`bash
|
|
144
|
-
openspec instructions <artifact-id> --change "<name>" --json
|
|
176
|
+
(cd <workspace> && openspec instructions <artifact-id> --change "<name>" --json)
|
|
145
177
|
\`\`\`
|
|
146
178
|
- The instructions JSON includes:
|
|
147
179
|
- \`context\`: Project background (constraints for you - do NOT include in output)
|
|
@@ -156,7 +188,7 @@ export function getOpsxFfCommandTemplate() {
|
|
|
156
188
|
- Show brief progress: "✓ Created <artifact-id>"
|
|
157
189
|
|
|
158
190
|
b. **Continue until all \`applyRequires\` artifacts are complete**
|
|
159
|
-
- After creating each artifact, re-run \`openspec status --change "<name>" --json\`
|
|
191
|
+
- After creating each artifact, re-run \`(cd <workspace> && openspec status --change "<name>" --json)\`
|
|
160
192
|
- Check if every artifact ID in \`applyRequires\` has \`status: "done"\` in the artifacts array
|
|
161
193
|
- Stop when all \`applyRequires\` artifacts are done
|
|
162
194
|
|
|
@@ -164,15 +196,15 @@ export function getOpsxFfCommandTemplate() {
|
|
|
164
196
|
- Use **AskUserQuestion tool** to clarify
|
|
165
197
|
- Then continue with creation
|
|
166
198
|
|
|
167
|
-
|
|
199
|
+
6. **Show final status**
|
|
168
200
|
\`\`\`bash
|
|
169
|
-
openspec status --change "<name>"
|
|
201
|
+
(cd <workspace> && openspec status --change "<name>")
|
|
170
202
|
\`\`\`
|
|
171
203
|
|
|
172
204
|
**Output**
|
|
173
205
|
|
|
174
206
|
After completing all artifacts, summarize:
|
|
175
|
-
- Change name and location
|
|
207
|
+
- Change name and location (including scope if in a workspace)
|
|
176
208
|
- List of artifacts created with brief descriptions
|
|
177
209
|
- What's ready: "All artifacts created! Ready for implementation."
|
|
178
210
|
- Prompt: "Run \`/opsx:apply\` to start implementing."
|
|
@@ -27,33 +27,49 @@ export function getNewChangeSkillTemplate() {
|
|
|
27
27
|
|
|
28
28
|
**Otherwise**: Omit \`--schema\` to use the default.
|
|
29
29
|
|
|
30
|
-
3. **
|
|
30
|
+
3. **Detect workspace and select scope**
|
|
31
|
+
|
|
32
|
+
Check for a workspace manifest:
|
|
33
|
+
\`\`\`bash
|
|
34
|
+
cat openspec/workspace.yaml 2>/dev/null
|
|
35
|
+
\`\`\`
|
|
36
|
+
|
|
37
|
+
If workspace.yaml exists, ask which scope this change belongs to (show the list of scopes from workspace.yaml). Store the selected scope's path as \`<workspace>\`.
|
|
38
|
+
|
|
39
|
+
If no workspace.yaml (single-project), set \`<workspace>\` to the current directory.
|
|
40
|
+
|
|
41
|
+
All subsequent \`openspec\` commands must run as:
|
|
42
|
+
\`\`\`bash
|
|
43
|
+
(cd <workspace> && openspec ...)
|
|
44
|
+
\`\`\`
|
|
45
|
+
|
|
46
|
+
4. **Create the change directory**
|
|
31
47
|
\`\`\`bash
|
|
32
|
-
openspec new change "<name>"
|
|
48
|
+
(cd <workspace> && openspec new change "<name>")
|
|
33
49
|
\`\`\`
|
|
34
50
|
Add \`--schema <name>\` only if the user requested a specific workflow.
|
|
35
|
-
This creates a scaffolded change at
|
|
51
|
+
This creates a scaffolded change at \`<workspace>/openspec/changes/<name>/\` with the selected schema.
|
|
36
52
|
|
|
37
|
-
|
|
53
|
+
5. **Show the artifact status**
|
|
38
54
|
\`\`\`bash
|
|
39
|
-
openspec status --change "<name>"
|
|
55
|
+
(cd <workspace> && openspec status --change "<name>")
|
|
40
56
|
\`\`\`
|
|
41
57
|
This shows which artifacts need to be created and which are ready (dependencies satisfied).
|
|
42
58
|
|
|
43
|
-
|
|
59
|
+
6. **Get instructions for the first artifact**
|
|
44
60
|
The first artifact depends on the schema (e.g., \`proposal\` for spec-driven).
|
|
45
61
|
Check the status output to find the first artifact with status "ready".
|
|
46
62
|
\`\`\`bash
|
|
47
|
-
openspec instructions <first-artifact-id> --change "<name>"
|
|
63
|
+
(cd <workspace> && openspec instructions <first-artifact-id> --change "<name>")
|
|
48
64
|
\`\`\`
|
|
49
65
|
This outputs the template and context for creating the first artifact.
|
|
50
66
|
|
|
51
|
-
|
|
67
|
+
7. **STOP and wait for user direction**
|
|
52
68
|
|
|
53
69
|
**Output**
|
|
54
70
|
|
|
55
71
|
After completing the steps, summarize:
|
|
56
|
-
- Change name and location
|
|
72
|
+
- Change name and location (including scope if in a workspace)
|
|
57
73
|
- Schema/workflow being used and its artifact sequence
|
|
58
74
|
- Current status (0/N artifacts complete)
|
|
59
75
|
- The template for the first artifact
|
|
@@ -101,32 +117,48 @@ export function getOpsxNewCommandTemplate() {
|
|
|
101
117
|
|
|
102
118
|
**Otherwise**: Omit \`--schema\` to use the default.
|
|
103
119
|
|
|
104
|
-
3. **
|
|
120
|
+
3. **Detect workspace and select scope**
|
|
121
|
+
|
|
122
|
+
Check for a workspace manifest:
|
|
123
|
+
\`\`\`bash
|
|
124
|
+
cat openspec/workspace.yaml 2>/dev/null
|
|
125
|
+
\`\`\`
|
|
126
|
+
|
|
127
|
+
If workspace.yaml exists, ask which scope this change belongs to (show the list of scopes from workspace.yaml). Store the selected scope's path as \`<workspace>\`.
|
|
128
|
+
|
|
129
|
+
If no workspace.yaml (single-project), set \`<workspace>\` to the current directory.
|
|
130
|
+
|
|
131
|
+
All subsequent \`openspec\` commands must run as:
|
|
132
|
+
\`\`\`bash
|
|
133
|
+
(cd <workspace> && openspec ...)
|
|
134
|
+
\`\`\`
|
|
135
|
+
|
|
136
|
+
4. **Create the change directory**
|
|
105
137
|
\`\`\`bash
|
|
106
|
-
openspec new change "<name>"
|
|
138
|
+
(cd <workspace> && openspec new change "<name>")
|
|
107
139
|
\`\`\`
|
|
108
140
|
Add \`--schema <name>\` only if the user requested a specific workflow.
|
|
109
|
-
This creates a scaffolded change at
|
|
141
|
+
This creates a scaffolded change at \`<workspace>/openspec/changes/<name>/\` with the selected schema.
|
|
110
142
|
|
|
111
|
-
|
|
143
|
+
5. **Show the artifact status**
|
|
112
144
|
\`\`\`bash
|
|
113
|
-
openspec status --change "<name>"
|
|
145
|
+
(cd <workspace> && openspec status --change "<name>")
|
|
114
146
|
\`\`\`
|
|
115
147
|
This shows which artifacts need to be created and which are ready (dependencies satisfied).
|
|
116
148
|
|
|
117
|
-
|
|
149
|
+
6. **Get instructions for the first artifact**
|
|
118
150
|
The first artifact depends on the schema. Check the status output to find the first artifact with status "ready".
|
|
119
151
|
\`\`\`bash
|
|
120
|
-
openspec instructions <first-artifact-id> --change "<name>"
|
|
152
|
+
(cd <workspace> && openspec instructions <first-artifact-id> --change "<name>")
|
|
121
153
|
\`\`\`
|
|
122
154
|
This outputs the template and context for creating the first artifact.
|
|
123
155
|
|
|
124
|
-
|
|
156
|
+
7. **STOP and wait for user direction**
|
|
125
157
|
|
|
126
158
|
**Output**
|
|
127
159
|
|
|
128
160
|
After completing the steps, summarize:
|
|
129
|
-
- Change name and location
|
|
161
|
+
- Change name and location (including scope if in a workspace)
|
|
130
162
|
- Schema/workflow being used and its artifact sequence
|
|
131
163
|
- Current status (0/N artifacts complete)
|
|
132
164
|
- The template for the first artifact
|
|
@@ -12,7 +12,24 @@ This is an **agent-driven** operation - you will read delta specs and directly e
|
|
|
12
12
|
|
|
13
13
|
1. **If no change name provided, prompt for selection**
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Check for a workspace manifest:
|
|
16
|
+
\`\`\`bash
|
|
17
|
+
cat openspec/workspace.yaml 2>/dev/null
|
|
18
|
+
\`\`\`
|
|
19
|
+
|
|
20
|
+
If workspace.yaml exists, list changes across all scopes:
|
|
21
|
+
\`\`\`bash
|
|
22
|
+
(cd <scope.path> && openspec list --json) # for each scope in workspace.yaml
|
|
23
|
+
ls openspec/changes/ 2>/dev/null # umbrella changes at root
|
|
24
|
+
\`\`\`
|
|
25
|
+
|
|
26
|
+
Otherwise:
|
|
27
|
+
\`\`\`bash
|
|
28
|
+
openspec list --json
|
|
29
|
+
\`\`\`
|
|
30
|
+
|
|
31
|
+
Aggregate all results. Use the **AskUserQuestion tool** to let the user select.
|
|
32
|
+
In workspace mode, show which scope each change belongs to.
|
|
16
33
|
|
|
17
34
|
Show changes that have delta specs (under \`specs/\` directory).
|
|
18
35
|
|
|
@@ -150,7 +167,24 @@ This is an **agent-driven** operation - you will read delta specs and directly e
|
|
|
150
167
|
|
|
151
168
|
1. **If no change name provided, prompt for selection**
|
|
152
169
|
|
|
153
|
-
|
|
170
|
+
Check for a workspace manifest:
|
|
171
|
+
\`\`\`bash
|
|
172
|
+
cat openspec/workspace.yaml 2>/dev/null
|
|
173
|
+
\`\`\`
|
|
174
|
+
|
|
175
|
+
If workspace.yaml exists, list changes across all scopes:
|
|
176
|
+
\`\`\`bash
|
|
177
|
+
(cd <scope.path> && openspec list --json) # for each scope in workspace.yaml
|
|
178
|
+
ls openspec/changes/ 2>/dev/null # umbrella changes at root
|
|
179
|
+
\`\`\`
|
|
180
|
+
|
|
181
|
+
Otherwise:
|
|
182
|
+
\`\`\`bash
|
|
183
|
+
openspec list --json
|
|
184
|
+
\`\`\`
|
|
185
|
+
|
|
186
|
+
Aggregate all results. Use the **AskUserQuestion tool** to let the user select.
|
|
187
|
+
In workspace mode, show which scope each change belongs to.
|
|
154
188
|
|
|
155
189
|
Show changes that have delta specs (under \`specs/\` directory).
|
|
156
190
|
|
|
@@ -10,7 +10,24 @@ export function getVerifyChangeSkillTemplate() {
|
|
|
10
10
|
|
|
11
11
|
1. **If no change name provided, prompt for selection**
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Check for a workspace manifest:
|
|
14
|
+
\`\`\`bash
|
|
15
|
+
cat openspec/workspace.yaml 2>/dev/null
|
|
16
|
+
\`\`\`
|
|
17
|
+
|
|
18
|
+
If workspace.yaml exists, list changes across all scopes:
|
|
19
|
+
\`\`\`bash
|
|
20
|
+
(cd <scope.path> && openspec list --json) # for each scope in workspace.yaml
|
|
21
|
+
ls openspec/changes/ 2>/dev/null # umbrella changes at root
|
|
22
|
+
\`\`\`
|
|
23
|
+
|
|
24
|
+
Otherwise:
|
|
25
|
+
\`\`\`bash
|
|
26
|
+
openspec list --json
|
|
27
|
+
\`\`\`
|
|
28
|
+
|
|
29
|
+
Aggregate all results. Use the **AskUserQuestion tool** to let the user select.
|
|
30
|
+
In workspace mode, show which scope each change belongs to.
|
|
14
31
|
|
|
15
32
|
Show changes that have implementation tasks (tasks artifact exists).
|
|
16
33
|
Include the schema used for each change if available.
|
|
@@ -178,7 +195,24 @@ export function getOpsxVerifyCommandTemplate() {
|
|
|
178
195
|
|
|
179
196
|
1. **If no change name provided, prompt for selection**
|
|
180
197
|
|
|
181
|
-
|
|
198
|
+
Check for a workspace manifest:
|
|
199
|
+
\`\`\`bash
|
|
200
|
+
cat openspec/workspace.yaml 2>/dev/null
|
|
201
|
+
\`\`\`
|
|
202
|
+
|
|
203
|
+
If workspace.yaml exists, list changes across all scopes:
|
|
204
|
+
\`\`\`bash
|
|
205
|
+
(cd <scope.path> && openspec list --json) # for each scope in workspace.yaml
|
|
206
|
+
ls openspec/changes/ 2>/dev/null # umbrella changes at root
|
|
207
|
+
\`\`\`
|
|
208
|
+
|
|
209
|
+
Otherwise:
|
|
210
|
+
\`\`\`bash
|
|
211
|
+
openspec list --json
|
|
212
|
+
\`\`\`
|
|
213
|
+
|
|
214
|
+
Aggregate all results. Use the **AskUserQuestion tool** to let the user select.
|
|
215
|
+
In workspace mode, show which scope each change belongs to.
|
|
182
216
|
|
|
183
217
|
Show changes that have implementation tasks (tasks artifact exists).
|
|
184
218
|
Include the schema used for each change if available.
|
package/dist/core/update.js
CHANGED
|
@@ -152,7 +152,8 @@ export class UpdateCommand {
|
|
|
152
152
|
const generatedCommands = generateCommands(commandContents, adapter);
|
|
153
153
|
for (const cmd of generatedCommands) {
|
|
154
154
|
const commandFile = path.isAbsolute(cmd.path) ? cmd.path : path.join(resolvedProjectPath, cmd.path);
|
|
155
|
-
|
|
155
|
+
const commandContent = cliTransformer ? cliTransformer(cmd.fileContent) : cmd.fileContent;
|
|
156
|
+
await FileSystemUtils.writeFile(commandFile, commandContent);
|
|
156
157
|
}
|
|
157
158
|
removedDeselectedCommandCount += await this.removeUnselectedCommandFiles(resolvedProjectPath, toolId, desiredWorkflows);
|
|
158
159
|
}
|
|
@@ -527,7 +528,8 @@ export class UpdateCommand {
|
|
|
527
528
|
const generatedCommands = generateCommands(commandContents, adapter);
|
|
528
529
|
for (const cmd of generatedCommands) {
|
|
529
530
|
const commandFile = path.isAbsolute(cmd.path) ? cmd.path : path.join(projectPath, cmd.path);
|
|
530
|
-
|
|
531
|
+
const commandContent = legacyCliTransformer ? legacyCliTransformer(cmd.fileContent) : cmd.fileContent;
|
|
532
|
+
await FileSystemUtils.writeFile(commandFile, commandContent);
|
|
531
533
|
}
|
|
532
534
|
}
|
|
533
535
|
}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
export declare function getActiveChangeIds(root?: string): Promise<string[]>;
|
|
2
2
|
export declare function getSpecIds(root?: string): Promise<string[]>;
|
|
3
3
|
export declare function getArchivedChangeIds(root?: string): Promise<string[]>;
|
|
4
|
+
export interface ScopedChangeId {
|
|
5
|
+
id: string;
|
|
6
|
+
scope: string | null;
|
|
7
|
+
scopeRoot: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function getActiveChangeIdsAcrossWorkspace(root?: string): Promise<ScopedChangeId[]>;
|
|
10
|
+
export declare function getArchivedChangeIdsAcrossWorkspace(root?: string): Promise<ScopedChangeId[]>;
|
|
4
11
|
//# sourceMappingURL=item-discovery.d.ts.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { promises as fs } from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import { readWorkspaceConfig } from '../core/workspace.js';
|
|
3
4
|
export async function getActiveChangeIds(root = process.cwd()) {
|
|
4
5
|
const changesPath = path.join(root, 'openspec', 'changes');
|
|
5
6
|
try {
|
|
@@ -69,4 +70,60 @@ export async function getArchivedChangeIds(root = process.cwd()) {
|
|
|
69
70
|
return [];
|
|
70
71
|
}
|
|
71
72
|
}
|
|
73
|
+
export async function getActiveChangeIdsAcrossWorkspace(root = process.cwd()) {
|
|
74
|
+
const workspace = readWorkspaceConfig(root);
|
|
75
|
+
if (!workspace) {
|
|
76
|
+
const ids = await getActiveChangeIds(root);
|
|
77
|
+
return ids.map(id => ({ id, scope: null, scopeRoot: root }));
|
|
78
|
+
}
|
|
79
|
+
const results = [];
|
|
80
|
+
const umbrellaIds = await getActiveChangeIds(root);
|
|
81
|
+
for (const id of umbrellaIds) {
|
|
82
|
+
results.push({ id, scope: null, scopeRoot: root });
|
|
83
|
+
}
|
|
84
|
+
for (const scope of workspace.scopes) {
|
|
85
|
+
const scopeRoot = path.resolve(root, scope.path);
|
|
86
|
+
const ids = await getActiveChangeIds(scopeRoot);
|
|
87
|
+
for (const id of ids) {
|
|
88
|
+
results.push({ id, scope: scope.name, scopeRoot });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return results.sort((a, b) => {
|
|
92
|
+
if (a.scope === b.scope)
|
|
93
|
+
return a.id.localeCompare(b.id);
|
|
94
|
+
if (a.scope === null)
|
|
95
|
+
return -1;
|
|
96
|
+
if (b.scope === null)
|
|
97
|
+
return 1;
|
|
98
|
+
return a.scope.localeCompare(b.scope);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
export async function getArchivedChangeIdsAcrossWorkspace(root = process.cwd()) {
|
|
102
|
+
const workspace = readWorkspaceConfig(root);
|
|
103
|
+
if (!workspace) {
|
|
104
|
+
const ids = await getArchivedChangeIds(root);
|
|
105
|
+
return ids.map(id => ({ id, scope: null, scopeRoot: root }));
|
|
106
|
+
}
|
|
107
|
+
const results = [];
|
|
108
|
+
const umbrellaIds = await getArchivedChangeIds(root);
|
|
109
|
+
for (const id of umbrellaIds) {
|
|
110
|
+
results.push({ id, scope: null, scopeRoot: root });
|
|
111
|
+
}
|
|
112
|
+
for (const scope of workspace.scopes) {
|
|
113
|
+
const scopeRoot = path.resolve(root, scope.path);
|
|
114
|
+
const ids = await getArchivedChangeIds(scopeRoot);
|
|
115
|
+
for (const id of ids) {
|
|
116
|
+
results.push({ id, scope: scope.name, scopeRoot });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return results.sort((a, b) => {
|
|
120
|
+
if (a.scope === b.scope)
|
|
121
|
+
return a.id.localeCompare(b.id);
|
|
122
|
+
if (a.scope === null)
|
|
123
|
+
return -1;
|
|
124
|
+
if (b.scope === null)
|
|
125
|
+
return 1;
|
|
126
|
+
return a.scope.localeCompare(b.scope);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
72
129
|
//# sourceMappingURL=item-discovery.js.map
|