@fission-ai/openspec 1.14.0 → 1.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/config.d.ts +8 -0
- package/dist/cli/commands/config.js +88 -0
- package/dist/cli/commands/context.d.ts +3 -0
- package/dist/cli/commands/context.js +20 -0
- package/dist/cli/commands/doctor.d.ts +3 -0
- package/dist/cli/commands/doctor.js +18 -0
- package/dist/cli/commands/schema.d.ts +6 -0
- package/dist/cli/commands/schema.js +57 -0
- package/dist/cli/commands/spec.d.ts +3 -0
- package/dist/cli/commands/spec.js +42 -0
- package/dist/cli/commands/store.d.ts +3 -0
- package/dist/cli/commands/store.js +130 -0
- package/dist/cli/commands/workset.d.ts +3 -0
- package/dist/cli/commands/workset.js +96 -0
- package/dist/cli/index.js +68 -43
- package/dist/commands/config.d.ts +16 -7
- package/dist/commands/config.js +342 -395
- package/dist/commands/context.d.ts +8 -2
- package/dist/commands/context.js +22 -37
- package/dist/commands/doctor.d.ts +6 -7
- package/dist/commands/doctor.js +14 -27
- package/dist/commands/schema.d.ts +19 -5
- package/dist/commands/schema.js +662 -702
- package/dist/commands/spec.d.ts +13 -4
- package/dist/commands/spec.js +91 -120
- package/dist/commands/store.d.ts +27 -2
- package/dist/commands/store.js +1 -120
- package/dist/commands/workflow/default-schema.d.ts +2 -0
- package/dist/commands/workflow/default-schema.js +4 -0
- package/dist/commands/workflow/instructions.js +1 -1
- package/dist/commands/workflow/shared.d.ts +1 -1
- package/dist/commands/workflow/shared.js +1 -1
- package/dist/commands/workset.d.ts +22 -2
- package/dist/commands/workset.js +1 -88
- package/dist/core/archive.js +13 -5
- package/dist/core/completion-tip.js +3 -1
- package/dist/core/config-schema.d.ts +1 -1
- package/dist/core/templates/workflows/apply-change.js +4 -3
- package/dist/core/templates/workflows/continue-change.js +17 -0
- package/dist/core/templates/workflows/verify-change.js +12 -12
- package/dist/core/validation/validator.js +12 -1
- package/dist/core/view.js +2 -26
- package/package.json +1 -1
- package/schemas/spec-driven/schema.yaml +28 -4
package/dist/core/archive.js
CHANGED
|
@@ -247,6 +247,14 @@ function toArchiveDiagnostic(error) {
|
|
|
247
247
|
if (isRootSelectionError(error)) {
|
|
248
248
|
return error.diagnostic;
|
|
249
249
|
}
|
|
250
|
+
if (error instanceof RetirementCleanupError) {
|
|
251
|
+
return {
|
|
252
|
+
severity: 'error',
|
|
253
|
+
code: 'archive_retirement_cleanup_failed',
|
|
254
|
+
message: error.message,
|
|
255
|
+
fix: 'Inspect the archived change and all recovery paths in this diagnostic; preserve any needed content before cleanup.',
|
|
256
|
+
};
|
|
257
|
+
}
|
|
250
258
|
return {
|
|
251
259
|
severity: 'error',
|
|
252
260
|
code: 'archive_error',
|
|
@@ -379,7 +387,7 @@ async function assertCopiedDirectoryUnchanged(stagedSource, destination, expecte
|
|
|
379
387
|
*/
|
|
380
388
|
class MoveDestinationRetainedError extends Error {
|
|
381
389
|
}
|
|
382
|
-
class
|
|
390
|
+
class RetirementCleanupError extends Error {
|
|
383
391
|
}
|
|
384
392
|
function isFallbackRenameCode(code) {
|
|
385
393
|
return code === 'EPERM' || code === 'EXDEV';
|
|
@@ -1012,12 +1020,12 @@ async function finalizeRetirementBackups(snapshots, mainSpecsDir) {
|
|
|
1012
1020
|
snapshot.displacedPath = undefined;
|
|
1013
1021
|
}
|
|
1014
1022
|
catch (error) {
|
|
1015
|
-
errors.push(`Could not
|
|
1023
|
+
errors.push(`Could not finalize the retirement backup at ${displacedPath} ` +
|
|
1016
1024
|
`(${error instanceof Error ? error.message : String(error)}).`);
|
|
1017
1025
|
}
|
|
1018
1026
|
}
|
|
1019
1027
|
if (errors.length > 0) {
|
|
1020
|
-
throw new
|
|
1028
|
+
throw new RetirementCleanupError(`${errors.join(' ')} The change was archived, but retirement cleanup did not complete. Inspect all reported recovery paths before recovery or cleanup.`);
|
|
1021
1029
|
}
|
|
1022
1030
|
}
|
|
1023
1031
|
export class ArchiveCommand {
|
|
@@ -1777,11 +1785,11 @@ export class ArchiveCommand {
|
|
|
1777
1785
|
await finalizeRetirementBackups(specSnapshots, mainSpecsDir);
|
|
1778
1786
|
}
|
|
1779
1787
|
catch (cleanupError) {
|
|
1780
|
-
throw new
|
|
1788
|
+
throw new RetirementCleanupError(`${error.message} ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
|
|
1781
1789
|
}
|
|
1782
1790
|
throw error;
|
|
1783
1791
|
}
|
|
1784
|
-
if (error instanceof
|
|
1792
|
+
if (error instanceof RetirementCleanupError)
|
|
1785
1793
|
throw error;
|
|
1786
1794
|
const rollbackErrors = [];
|
|
1787
1795
|
try {
|
|
@@ -22,7 +22,6 @@ import { getGlobalConfigPath } from './global-config.js';
|
|
|
22
22
|
import { writeFileAtomically } from './file-state.js';
|
|
23
23
|
import { isCiEnvironment } from '../utils/ci.js';
|
|
24
24
|
import { detectShell } from '../utils/shell-detection.js';
|
|
25
|
-
import { CompletionFactory } from './completions/factory.js';
|
|
26
25
|
export const COMPLETION_TIP_MESSAGE = "Tip: Run 'openspec completion install' for shell completions";
|
|
27
26
|
function isSuppressedByEnv() {
|
|
28
27
|
// isCiEnvironment, not a CI==='true' string check: providers set CI to "True",
|
|
@@ -54,6 +53,9 @@ async function decideTip() {
|
|
|
54
53
|
if (!shell) {
|
|
55
54
|
return 'retire';
|
|
56
55
|
}
|
|
56
|
+
// Loaded only here: every shell's generator and installer, needed only on
|
|
57
|
+
// the rare run that still owes the tip.
|
|
58
|
+
const { CompletionFactory } = await import('./completions/factory.js');
|
|
57
59
|
return (await CompletionFactory.createInstaller(shell).isInstalled())
|
|
58
60
|
? 'retire'
|
|
59
61
|
: 'show';
|
|
@@ -10,9 +10,9 @@ export declare const GlobalConfigSchema: z.ZodObject<{
|
|
|
10
10
|
core: "core";
|
|
11
11
|
}>>>;
|
|
12
12
|
delivery: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
13
|
-
commands: "commands";
|
|
14
13
|
both: "both";
|
|
15
14
|
skills: "skills";
|
|
15
|
+
commands: "commands";
|
|
16
16
|
}>>>;
|
|
17
17
|
workflows: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
18
18
|
defaultStore: z.ZodOptional<z.ZodString>;
|
|
@@ -66,7 +66,7 @@ ${PROJECT_ROOT_GUARD}
|
|
|
66
66
|
- If \`state: "blocked"\`: show the message and pause implementation.
|
|
67
67
|
- If \`missingArtifacts\` is non-empty: ${BLOCKED_STATE_HANDOFF}
|
|
68
68
|
- Otherwise, follow the CLI instruction to create or repair the schema-configured tracking file from existing planning artifacts. Do not assume another artifact is ready or start implementation while blocked.
|
|
69
|
-
- If \`state: "all_done"\`:
|
|
69
|
+
- If \`state: "all_done"\`: report that all tracked tasks are complete and suggest review or verification as appropriate before archiving
|
|
70
70
|
- Otherwise: proceed to implementation
|
|
71
71
|
|
|
72
72
|
Treat \`context\` as a required prompt-level input. Read and consider it, and
|
|
@@ -125,7 +125,7 @@ ${PROJECT_ROOT_GUARD}
|
|
|
125
125
|
Display:
|
|
126
126
|
- Tasks completed this session
|
|
127
127
|
- Overall progress: "N/M tasks complete"
|
|
128
|
-
- If all done: suggest
|
|
128
|
+
- If all done: report that tracked tasks are complete and suggest review or verification as appropriate before archiving
|
|
129
129
|
- If paused: explain why and wait for guidance
|
|
130
130
|
|
|
131
131
|
**Output During Implementation**
|
|
@@ -156,7 +156,8 @@ Working on task 4/7: <task description>
|
|
|
156
156
|
- [x] Task 2
|
|
157
157
|
...
|
|
158
158
|
|
|
159
|
-
All tasks complete
|
|
159
|
+
All tracked tasks are complete. Review or verify the change as appropriate
|
|
160
|
+
before archiving. ${ARCHIVE_HANDOFF}
|
|
160
161
|
\`\`\`
|
|
161
162
|
|
|
162
163
|
**Output On Pause (Issue Encountered)**
|
|
@@ -7,6 +7,15 @@ import { PROJECT_ROOT_GUARD } from './project-root.js';
|
|
|
7
7
|
* optional-workflow.ts).
|
|
8
8
|
*/
|
|
9
9
|
const PLANNING_COMPLETE_HANDOFF = optionalWorkflow('apply', 'You can now implement this change with `/opsx:apply`.', 'You can now implement this change - `openspec instructions apply --change "<name>" --json` returns the tasks and how to work them.') + ' ' + optionalWorkflow('archive', 'Once implementation and any tracked work are complete, archive it with `/opsx:archive`.', 'Once implementation and any tracked work are complete, archive it with `openspec archive "<name>"`.');
|
|
10
|
+
/**
|
|
11
|
+
* A glob artifact reads `done` once one matching file exists, so a run
|
|
12
|
+
* interrupted while writing several files leaves it `done` with files missing,
|
|
13
|
+
* and the next run would move on without reading its instruction again (#2034).
|
|
14
|
+
*/
|
|
15
|
+
const PARTIAL_ARTIFACT_CHECK = `**Before anything else, finish a partly written artifact**:
|
|
16
|
+
- An artifact whose output is a glob pattern (e.g. \`specs/**/*.md\`) reads \`done\` as soon as one matching file exists, so a run interrupted while writing its files leaves it \`done\` with some still missing
|
|
17
|
+
- For each such \`done\` artifact, first get its instructions and read any completed dependencies needed to determine the expected files. Then compare those files with \`artifactPaths.<id>.existingOutputPaths\`. For spec-driven's \`specs\`, read the proposal and check for one \`specs/<capability-path>/spec.md\` per capability it lists; resolve each expected path against \`changeRoot\` before comparing path identity
|
|
18
|
+
- If any are missing, write only the missing files, and STOP - that counts as this invocation's ONE artifact. If you cannot tell whether a file was left out on purpose, ask the user`;
|
|
10
19
|
export function getContinueChangeSkillTemplate() {
|
|
11
20
|
return {
|
|
12
21
|
name: 'openspec-continue-change',
|
|
@@ -51,6 +60,10 @@ ${PROJECT_ROOT_GUARD}
|
|
|
51
60
|
|
|
52
61
|
---
|
|
53
62
|
|
|
63
|
+
${PARTIAL_ARTIFACT_CHECK}
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
54
67
|
**If all planning artifacts are complete (\`isPlanningComplete: true\`, or legacy \`isComplete: true\`)**:
|
|
55
68
|
- Congratulate the user
|
|
56
69
|
- Show final status including the schema used
|
|
@@ -169,6 +182,10 @@ ${PROJECT_ROOT_GUARD}
|
|
|
169
182
|
|
|
170
183
|
---
|
|
171
184
|
|
|
185
|
+
${PARTIAL_ARTIFACT_CHECK}
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
172
189
|
**If all planning artifacts are complete (\`isPlanningComplete: true\`, or legacy \`isComplete: true\`)**:
|
|
173
190
|
- Congratulate the user
|
|
174
191
|
- Show final status including the schema used
|
|
@@ -76,9 +76,9 @@ ${PROJECT_ROOT_GUARD}
|
|
|
76
76
|
- Recommendation: "Complete task: <description>" or "Mark as done if already implemented"
|
|
77
77
|
|
|
78
78
|
**Spec Coverage**:
|
|
79
|
-
- If status marks the spec artifact skipped by \`skip_specs: true\`, or the schema defines no spec artifact, report the spec-dependent checks as not applicable.
|
|
80
|
-
- Otherwise, \`contextFiles\` is keyed by artifact id, and artifact ids come from the active schema
|
|
81
|
-
- If delta specs exist in
|
|
79
|
+
- If status marks the spec artifact skipped by \`skip_specs: true\`, or the schema defines no spec artifact (no artifact whose \`artifactPaths.<id>.outputPath\` is under \`specs/\`), report the spec-dependent checks as not applicable.
|
|
80
|
+
- Otherwise, \`contextFiles\` is keyed by artifact id, and artifact ids come from the active schema, so do not assume an id such as \`specs\`. The spec artifacts are those whose \`artifactPaths.<id>.outputPath\` is under \`specs/\`; read their files from \`contextFiles.<id>\`. If those spec files are absent or empty, mark **Spec Coverage**, **Requirement Implementation Mapping**, and **Scenario Coverage** as not verified; do not treat any of them as clean.
|
|
81
|
+
- If delta specs exist in those spec files:
|
|
82
82
|
- Extract all requirements (marked with "### Requirement:", or listed as \`FROM:\`/\`TO:\` pairs under \`## RENAMED Requirements\`) and note the delta section each one sits under: \`## ADDED\`, \`## MODIFIED\`, \`## REMOVED\`, or \`## RENAMED Requirements\`. The section decides what the check looks for.
|
|
83
83
|
- For each ADDED or MODIFIED requirement (for MODIFIED, check the text in the delta, not the old wording):
|
|
84
84
|
- Search codebase for keywords related to the requirement
|
|
@@ -127,14 +127,14 @@ ${PROJECT_ROOT_GUARD}
|
|
|
127
127
|
7. **Verify Coherence**
|
|
128
128
|
|
|
129
129
|
**Design Adherence**:
|
|
130
|
-
- If the schema defines no design artifact, report **Design Adherence** as not applicable.
|
|
131
|
-
- If \`contextFiles
|
|
130
|
+
- If the schema defines no design artifact (no artifact with id \`design\`, and none whose \`artifactPaths.<id>.outputPath\` is or ends in \`design.md\`), report **Design Adherence** as not applicable.
|
|
131
|
+
- If the design artifact's \`contextFiles.<id>\` file exists:
|
|
132
132
|
- Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:")
|
|
133
133
|
- Verify implementation follows those decisions
|
|
134
134
|
- If contradiction detected:
|
|
135
135
|
- Add WARNING: "Design decision not followed: <decision>"
|
|
136
136
|
- Recommendation: "Update implementation or revise design.md to match reality"
|
|
137
|
-
- Otherwise, if \`contextFiles
|
|
137
|
+
- Otherwise, if the design artifact's \`contextFiles.<id>\` file is absent or empty: mark **Design Adherence** as not verified. With other supporting artifacts, **Code Pattern Consistency** still runs; the task-only case remains limited to task completion.
|
|
138
138
|
|
|
139
139
|
**Code Pattern Consistency**:
|
|
140
140
|
- If implementation changes cannot be identified, mark **Code Pattern Consistency** as not verified and explain the missing evidence.
|
|
@@ -285,9 +285,9 @@ ${PROJECT_ROOT_GUARD}
|
|
|
285
285
|
- Recommendation: "Complete task: <description>" or "Mark as done if already implemented"
|
|
286
286
|
|
|
287
287
|
**Spec Coverage**:
|
|
288
|
-
- If status marks the spec artifact skipped by \`skip_specs: true\`, or the schema defines no spec artifact, report the spec-dependent checks as not applicable.
|
|
289
|
-
- Otherwise, \`contextFiles\` is keyed by artifact id, and artifact ids come from the active schema
|
|
290
|
-
- If delta specs exist in
|
|
288
|
+
- If status marks the spec artifact skipped by \`skip_specs: true\`, or the schema defines no spec artifact (no artifact whose \`artifactPaths.<id>.outputPath\` is under \`specs/\`), report the spec-dependent checks as not applicable.
|
|
289
|
+
- Otherwise, \`contextFiles\` is keyed by artifact id, and artifact ids come from the active schema, so do not assume an id such as \`specs\`. The spec artifacts are those whose \`artifactPaths.<id>.outputPath\` is under \`specs/\`; read their files from \`contextFiles.<id>\`. If those spec files are absent or empty, mark **Spec Coverage**, **Requirement Implementation Mapping**, and **Scenario Coverage** as not verified; do not treat any of them as clean.
|
|
290
|
+
- If delta specs exist in those spec files:
|
|
291
291
|
- Extract all requirements (marked with "### Requirement:", or listed as \`FROM:\`/\`TO:\` pairs under \`## RENAMED Requirements\`) and note the delta section each one sits under: \`## ADDED\`, \`## MODIFIED\`, \`## REMOVED\`, or \`## RENAMED Requirements\`. The section decides what the check looks for.
|
|
292
292
|
- For each ADDED or MODIFIED requirement (for MODIFIED, check the text in the delta, not the old wording):
|
|
293
293
|
- Search codebase for keywords related to the requirement
|
|
@@ -336,14 +336,14 @@ ${PROJECT_ROOT_GUARD}
|
|
|
336
336
|
7. **Verify Coherence**
|
|
337
337
|
|
|
338
338
|
**Design Adherence**:
|
|
339
|
-
- If the schema defines no design artifact, report **Design Adherence** as not applicable.
|
|
340
|
-
- If \`contextFiles
|
|
339
|
+
- If the schema defines no design artifact (no artifact with id \`design\`, and none whose \`artifactPaths.<id>.outputPath\` is or ends in \`design.md\`), report **Design Adherence** as not applicable.
|
|
340
|
+
- If the design artifact's \`contextFiles.<id>\` file exists:
|
|
341
341
|
- Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:")
|
|
342
342
|
- Verify implementation follows those decisions
|
|
343
343
|
- If contradiction detected:
|
|
344
344
|
- Add WARNING: "Design decision not followed: <decision>"
|
|
345
345
|
- Recommendation: "Update implementation or revise design.md to match reality"
|
|
346
|
-
- Otherwise, if \`contextFiles
|
|
346
|
+
- Otherwise, if the design artifact's \`contextFiles.<id>\` file is absent or empty: mark **Design Adherence** as not verified. With other supporting artifacts, **Code Pattern Consistency** still runs; the task-only case remains limited to task completion.
|
|
347
347
|
|
|
348
348
|
**Code Pattern Consistency**:
|
|
349
349
|
- If implementation changes cannot be identified, mark **Code Pattern Consistency** as not verified and explain the missing evidence.
|
|
@@ -252,6 +252,17 @@ export class Validator {
|
|
|
252
252
|
message: this.buildMissingShallOrMustMessage(`ADDED "${block.name}"`, block.name, true),
|
|
253
253
|
});
|
|
254
254
|
}
|
|
255
|
+
// Same limit the main spec enforces after archive (#1976), so
|
|
256
|
+
// `validate <change> --strict` catches a new overlong requirement
|
|
257
|
+
// before it lands. MODIFIED is left alone: its text is the existing
|
|
258
|
+
// requirement, which the specs instruction says to keep whole.
|
|
259
|
+
if (requirementText && requirementText.length > MAX_REQUIREMENT_TEXT_LENGTH) {
|
|
260
|
+
issues.push({
|
|
261
|
+
level: 'WARNING',
|
|
262
|
+
path: entryPath,
|
|
263
|
+
message: `ADDED "${block.name}": ${VALIDATION_MESSAGES.REQUIREMENT_TOO_LONG}`,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
255
266
|
const scenarioCount = this.countScenarios(block.raw);
|
|
256
267
|
if (scenarioCount < 1) {
|
|
257
268
|
issues.push({ level: 'ERROR', path: entryPath, message: `ADDED "${block.name}" must include at least one scenario${this.emptyScenarioHint(block.raw)}` });
|
|
@@ -711,7 +722,7 @@ export class Validator {
|
|
|
711
722
|
spec.requirements.forEach((req, index) => {
|
|
712
723
|
if (req.text.length > MAX_REQUIREMENT_TEXT_LENGTH) {
|
|
713
724
|
issues.push({
|
|
714
|
-
level: '
|
|
725
|
+
level: 'WARNING',
|
|
715
726
|
path: `requirements[${index}]`,
|
|
716
727
|
message: VALIDATION_MESSAGES.REQUIREMENT_TOO_LONG,
|
|
717
728
|
});
|
package/dist/core/view.js
CHANGED
|
@@ -52,14 +52,6 @@ export class ViewCommand {
|
|
|
52
52
|
console.log(` ${chalk.green('✓')} ${change.name}`);
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
|
-
// Display archived changes
|
|
56
|
-
if (changesData.archived.length > 0) {
|
|
57
|
-
console.log(chalk.bold.gray('\nArchived Changes'));
|
|
58
|
-
console.log('─'.repeat(60));
|
|
59
|
-
changesData.archived.forEach((change) => {
|
|
60
|
-
console.log(chalk.gray(` ◦ ${change.name}`));
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
55
|
// Display specifications
|
|
64
56
|
if (specsData.length > 0) {
|
|
65
57
|
console.log(chalk.bold.blue('\nSpecifications'));
|
|
@@ -78,25 +70,11 @@ export class ViewCommand {
|
|
|
78
70
|
const changesDir = path.join(openspecDir, 'changes');
|
|
79
71
|
const projectRoot = path.dirname(openspecDir);
|
|
80
72
|
if (!fs.existsSync(changesDir)) {
|
|
81
|
-
return { draft: [], active: [], completed: []
|
|
73
|
+
return { draft: [], active: [], completed: [] };
|
|
82
74
|
}
|
|
83
75
|
const draft = [];
|
|
84
76
|
const active = [];
|
|
85
77
|
const completed = [];
|
|
86
|
-
let archived = [];
|
|
87
|
-
try {
|
|
88
|
-
archived = fs.readdirSync(path.join(changesDir, 'archive'), { withFileTypes: true })
|
|
89
|
-
.filter((entry) => entry.isDirectory() && !entry.name.startsWith('.'))
|
|
90
|
-
.map((entry) => ({ name: entry.name }));
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
// A missing archive, or an `archive` path that is a file, has no archived
|
|
94
|
-
// changes to show; neither should break the rest of the dashboard.
|
|
95
|
-
const code = error.code;
|
|
96
|
-
if (code !== 'ENOENT' && code !== 'ENOTDIR') {
|
|
97
|
-
throw error;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
78
|
const entries = fs.readdirSync(changesDir, { withFileTypes: true });
|
|
101
79
|
for (const entry of entries) {
|
|
102
80
|
if (entry.isDirectory() && entry.name !== 'archive') {
|
|
@@ -136,8 +114,7 @@ export class ViewCommand {
|
|
|
136
114
|
return a.name.localeCompare(b.name);
|
|
137
115
|
});
|
|
138
116
|
completed.sort((a, b) => a.name.localeCompare(b.name));
|
|
139
|
-
|
|
140
|
-
return { draft, active, completed, archived };
|
|
117
|
+
return { draft, active, completed };
|
|
141
118
|
}
|
|
142
119
|
async getSpecsData(openspecDir) {
|
|
143
120
|
const specsDir = path.join(openspecDir, 'specs');
|
|
@@ -182,7 +159,6 @@ export class ViewCommand {
|
|
|
182
159
|
}
|
|
183
160
|
console.log(` ${chalk.yellow('●')} Active Changes: ${chalk.bold(changesData.active.length)} in progress`);
|
|
184
161
|
console.log(` ${chalk.green('●')} Completed Changes: ${chalk.bold(changesData.completed.length)}`);
|
|
185
|
-
console.log(` ${chalk.gray('●')} Archived Changes: ${chalk.bold(changesData.archived.length)}`);
|
|
186
162
|
if (totalTasks > 0) {
|
|
187
163
|
const overallProgress = Math.round((completedTasks / totalTasks) * 100);
|
|
188
164
|
console.log(` ${chalk.magenta('●')} Task Progress: ${chalk.bold(`${completedTasks}/${totalTasks}`)} (${overallProgress}% complete)`);
|
package/package.json
CHANGED
|
@@ -77,6 +77,17 @@ artifacts:
|
|
|
77
77
|
- New capabilities: use the exact path from the proposal at `specs/<capability-path>/spec.md`. Any path segment newly introduced in the proposal must be kebab-case. Follow the project's existing organization; do not add a new domain level when the project uses a flat layout.
|
|
78
78
|
- Modified capabilities: use the exact existing path from `openspec/specs/<capability-path>/` when creating the delta at `specs/<capability-path>/spec.md`. Run `openspec list --specs` to confirm that path before writing the delta, appending `--store "<id>"` only for a registered standalone store - a mistyped or invented path targets a capability that does not exist rather than the one you meant. Do not move or rename the capability.
|
|
79
79
|
|
|
80
|
+
Write the spec files one at a time, so the user sees progress and an
|
|
81
|
+
interrupted run keeps the files it already wrote:
|
|
82
|
+
- Before writing anything, compare the capabilities the proposal lists
|
|
83
|
+
with the `specs/<capability-path>/spec.md` files that already exist,
|
|
84
|
+
and start with the first capability that has no file. Do not rewrite
|
|
85
|
+
an existing file unless the user asks you to.
|
|
86
|
+
- Before each file, say in one line which capability you are writing.
|
|
87
|
+
- Write each file as soon as you have drafted it. Do not plan every file
|
|
88
|
+
before writing the first.
|
|
89
|
+
- Stop when every capability the proposal lists has its file.
|
|
90
|
+
|
|
80
91
|
There must be at least one spec file unless the change's `.openspec.yaml`
|
|
81
92
|
sets `skip_specs: true` (no spec-level behavior change) - `openspec validate`
|
|
82
93
|
rejects a zero-delta change without that marker. If the proposal lists no
|
|
@@ -94,7 +105,7 @@ artifacts:
|
|
|
94
105
|
- Each scenario: `#### Scenario: <name>` with WHEN/THEN format
|
|
95
106
|
- **CRITICAL**: Scenarios MUST use exactly 4 hashtags (`####`). Using 3 hashtags or bullets will fail silently.
|
|
96
107
|
- Every requirement MUST have at least one scenario.
|
|
97
|
-
- Keep each requirement's description (the text between `### Requirement:` and its first scenario) to 500 characters or fewer. `openspec validate` flags longer descriptions
|
|
108
|
+
- Keep each requirement's description (the text between `### Requirement:` and its first scenario) to 500 characters or fewer. `openspec validate` flags longer descriptions in ADDED requirements and in the main spec. This is a warning: normal validation still passes, but `openspec validate --strict` fails on it. When writing a new requirement, state one behavior per requirement: move examples and edge cases into scenarios, and split a requirement that covers several behaviors into separate `### Requirement:` blocks, each with its own scenarios. Under MODIFIED, keep the existing requirement block whole; never split, trim or rewrite existing text just to meet the length. Split an existing long requirement only when the user asks for it, in a change made for that purpose: under MODIFIED, keep its header and every scenario and cut its description down to one behavior without changing its meaning, then add each behavior you removed as its own ADDED requirement with its own scenarios.
|
|
98
109
|
|
|
99
110
|
New capabilities only: the delta spec's first section is `## Purpose` -
|
|
100
111
|
one or two sentences (50+ characters, or `openspec validate --strict`
|
|
@@ -195,17 +206,22 @@ artifacts:
|
|
|
195
206
|
would change what gets built, resolve them with the user first - do not
|
|
196
207
|
bake an unstated assumption into the task list.
|
|
197
208
|
|
|
198
|
-
**IMPORTANT: Follow the template below
|
|
209
|
+
**IMPORTANT: Follow the template below for tracked tasks.** The apply phase parses
|
|
199
210
|
checkbox format to track progress. A box holding only `x` counts as done,
|
|
200
211
|
upper or lower case and with any spacing, so `- [ x]` is done too. Every
|
|
201
212
|
other marker, including `- [~]`, `- [-]` and an empty `- []`, reads as
|
|
202
213
|
unfinished. A line with no checkbox is not tracked at all.
|
|
203
214
|
|
|
204
215
|
Guidelines:
|
|
205
|
-
- Group related tasks under ## numbered headings
|
|
206
|
-
- Each task MUST be a checkbox: `- [ ] X.Y Task description`
|
|
216
|
+
- Group related tracked tasks under ## numbered headings
|
|
217
|
+
- Each tracked task MUST be a checkbox: `- [ ] X.Y Task description`
|
|
207
218
|
- Tasks should be small enough to complete in one session
|
|
208
219
|
- Order tasks by dependency (what must be done first?)
|
|
220
|
+
- Track implementation and verification work that can be completed before
|
|
221
|
+
archive. If the requested workflow includes archive or work that requires
|
|
222
|
+
this change to be archived, preserve those steps as plain bullets in an
|
|
223
|
+
optional `## Workflow follow-up` section at the end of tasks.md. These
|
|
224
|
+
bullets are reference information outside tracked task progress.
|
|
209
225
|
- Each task MUST state how to verify completion (a test, command,
|
|
210
226
|
observable behavior, or delivered artifact). Put the verification in
|
|
211
227
|
that task's checkbox description. Use a separate verification task only
|
|
@@ -235,6 +251,14 @@ artifacts:
|
|
|
235
251
|
- [ ] 2.3 Document the export API in docs/export.md and verify the documented command runs as written
|
|
236
252
|
```
|
|
237
253
|
|
|
254
|
+
When applicable, append workflow follow-up as plain bullets, for example:
|
|
255
|
+
```
|
|
256
|
+
## Workflow follow-up
|
|
257
|
+
|
|
258
|
+
- Archive the change after the project's review requirements are satisfied.
|
|
259
|
+
- Verify the archived result.
|
|
260
|
+
```
|
|
261
|
+
|
|
238
262
|
Reference specs for what needs to be built, design for how to build it.
|
|
239
263
|
requires:
|
|
240
264
|
- specs
|