@fission-ai/openspec 1.8.0 → 1.9.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/dist/cli/index.d.ts +15 -0
- package/dist/cli/index.js +33 -4
- package/dist/commands/change.js +1 -0
- package/dist/commands/config.d.ts +5 -0
- package/dist/commands/config.js +5 -1
- package/dist/commands/schema.js +193 -28
- package/dist/commands/validate.d.ts +23 -0
- package/dist/commands/validate.js +148 -4
- package/dist/commands/workflow/schemas.d.ts +2 -0
- package/dist/commands/workflow/schemas.js +9 -2
- package/dist/core/archive.js +10 -3
- package/dist/core/artifact-graph/resolver.d.ts +0 -12
- package/dist/core/artifact-graph/resolver.js +14 -0
- package/dist/core/command-generation/adapters/command-code.d.ts +19 -0
- package/dist/core/command-generation/adapters/command-code.js +34 -0
- package/dist/core/command-generation/adapters/index.d.ts +1 -0
- package/dist/core/command-generation/adapters/index.js +1 -0
- package/dist/core/command-generation/registry.js +2 -0
- package/dist/core/completions/command-registry.js +5 -0
- package/dist/core/config.d.ts +1 -0
- package/dist/core/config.js +16 -15
- package/dist/core/init.js +19 -7
- package/dist/core/legacy-cleanup.d.ts +10 -0
- package/dist/core/legacy-cleanup.js +48 -26
- package/dist/core/parsers/requirement-blocks.js +41 -9
- package/dist/core/parsers/requirement-text.d.ts +8 -0
- package/dist/core/parsers/requirement-text.js +4 -3
- package/dist/core/root-selection.d.ts +1 -1
- package/dist/core/shared-skill-target.d.ts +15 -0
- package/dist/core/shared-skill-target.js +30 -0
- package/dist/core/specs-apply.js +11 -4
- package/dist/core/templates/workflows/apply-change.js +3 -0
- package/dist/core/templates/workflows/propose.js +2 -2
- package/dist/core/templates/workflows/store-selection.d.ts +1 -1
- package/dist/core/templates/workflows/store-selection.js +1 -1
- package/dist/core/templates/workflows/update-change.js +4 -4
- package/dist/core/update.js +34 -7
- package/dist/core/validation/task-numbering.d.ts +16 -0
- package/dist/core/validation/task-numbering.js +57 -0
- package/dist/core/validation/validator.d.ts +5 -2
- package/dist/core/validation/validator.js +57 -3
- package/dist/telemetry/index.d.ts +3 -1
- package/dist/telemetry/index.js +7 -1
- package/dist/utils/interactive.d.ts +30 -1
- package/dist/utils/interactive.js +105 -2
- package/dist/utils/task-progress.d.ts +34 -1
- package/dist/utils/task-progress.js +52 -28
- package/package.json +1 -1
|
@@ -64,24 +64,43 @@ function findTrackedTasksArtifact(schema) {
|
|
|
64
64
|
* when the schema cannot be resolved or no tracked-tasks artifact exists.
|
|
65
65
|
* `resolveSchema` throws on an unresolvable/misnamed schema; we swallow that so
|
|
66
66
|
* the caller falls back to a single top-level `tasks.md` and never crashes.
|
|
67
|
+
* A `schemaGlobCache`, when supplied, memoizes the schema-name → glob lookup for
|
|
68
|
+
* the duration of one run.
|
|
67
69
|
*/
|
|
68
|
-
function resolveTrackedTasksGlob(changeDir, projectRoot) {
|
|
70
|
+
function resolveTrackedTasksGlob(changeDir, projectRoot, schemaGlobCache) {
|
|
69
71
|
try {
|
|
70
72
|
const schemaName = resolveSchemaForChange(changeDir, undefined, projectRoot);
|
|
73
|
+
if (schemaGlobCache?.has(schemaName))
|
|
74
|
+
return schemaGlobCache.get(schemaName);
|
|
71
75
|
const schema = resolveSchema(schemaName, projectRoot);
|
|
72
|
-
|
|
76
|
+
const generates = findTrackedTasksArtifact(schema)?.generates;
|
|
77
|
+
schemaGlobCache?.set(schemaName, generates);
|
|
78
|
+
return generates;
|
|
73
79
|
}
|
|
74
80
|
catch {
|
|
75
81
|
return undefined;
|
|
76
82
|
}
|
|
77
83
|
}
|
|
78
|
-
|
|
79
|
-
|
|
84
|
+
/** Resolves the task files selected by the schema's apply tracking rule. */
|
|
85
|
+
export function resolveTaskFilesForChange(changeDir, projectRoot, schemaGlobCache) {
|
|
86
|
+
const generates = resolveTrackedTasksGlob(changeDir, projectRoot, schemaGlobCache);
|
|
87
|
+
return generates ? resolveArtifactOutputs(changeDir, generates) : [];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Reads one task file and counts its checkboxes. ENOENT (a glob file that
|
|
91
|
+
* vanished between resolve and read, or the absent single top-level `tasks.md`)
|
|
92
|
+
* means zero tasks, exactly as before. Any other error (permissions, I/O,
|
|
93
|
+
* ENOTDIR) is recorded in `unreadable` so a caller can surface it; the count
|
|
94
|
+
* still contributes zero, so existing callers see no change.
|
|
95
|
+
*/
|
|
96
|
+
async function countTaskFile(file, unreadable) {
|
|
80
97
|
try {
|
|
81
|
-
const content = await fs.readFile(
|
|
98
|
+
const content = await fs.readFile(file, 'utf-8');
|
|
82
99
|
return countTasksFromContent(content);
|
|
83
100
|
}
|
|
84
|
-
catch {
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (error?.code !== 'ENOENT')
|
|
103
|
+
unreadable.push(file);
|
|
85
104
|
return { total: 0, completed: 0 };
|
|
86
105
|
}
|
|
87
106
|
}
|
|
@@ -92,31 +111,36 @@ async function countSingleTopLevelTasksFile(changeDir) {
|
|
|
92
111
|
* artifact (`resolveArtifactOutputs`) — so progress is no longer blind to nested
|
|
93
112
|
* `tasks.md` files (#1202). Falls back to a single top-level `tasks.md` (exactly
|
|
94
113
|
* as before) when the schema is unresolvable, no tracked-tasks artifact is found,
|
|
95
|
-
* or the glob matches no file.
|
|
114
|
+
* or the glob matches no file. Also reports task files that exist but could not
|
|
115
|
+
* be read. Per-file read errors are captured (never thrown); the only throw path
|
|
116
|
+
* is a malformed/unsafe schema whose glob resolution rejects (path traversal or
|
|
117
|
+
* a linked-directory cycle in `resolveArtifactOutputs`). Pass `schemaGlobCache`
|
|
118
|
+
* to memoize schema→glob resolution across many changes in one run.
|
|
96
119
|
*/
|
|
97
|
-
export async function
|
|
120
|
+
export async function getTaskProgressDetailForChange(changesDir, changeName, projectRoot, schemaGlobCache) {
|
|
98
121
|
const changeDir = path.join(changesDir, changeName);
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const progress = countTasksFromContent(content);
|
|
109
|
-
total += progress.total;
|
|
110
|
-
completed += progress.completed;
|
|
111
|
-
}
|
|
112
|
-
catch {
|
|
113
|
-
// Swallow files that vanish between glob and read, as before.
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return { total, completed };
|
|
117
|
-
}
|
|
122
|
+
const files = resolveTaskFilesForChange(changeDir, projectRoot, schemaGlobCache);
|
|
123
|
+
const targets = files.length > 0 ? files : [path.join(changeDir, 'tasks.md')];
|
|
124
|
+
const unreadable = [];
|
|
125
|
+
let total = 0;
|
|
126
|
+
let completed = 0;
|
|
127
|
+
for (const file of targets) {
|
|
128
|
+
const progress = await countTaskFile(file, unreadable);
|
|
129
|
+
total += progress.total;
|
|
130
|
+
completed += progress.completed;
|
|
118
131
|
}
|
|
119
|
-
return
|
|
132
|
+
return { total, completed, unreadable };
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The task-completion counter `status`, `list`, and `archive` share. Delegates
|
|
136
|
+
* to `getTaskProgressDetailForChange` and drops the `unreadable` detail, so its
|
|
137
|
+
* returned totals are unchanged. Throws only on the same malformed/unsafe-schema
|
|
138
|
+
* glob-resolution path as that function (existing behavior; callers guard it as
|
|
139
|
+
* they did before).
|
|
140
|
+
*/
|
|
141
|
+
export async function getTaskProgressForChange(changesDir, changeName, projectRoot) {
|
|
142
|
+
const { total, completed } = await getTaskProgressDetailForChange(changesDir, changeName, projectRoot);
|
|
143
|
+
return { total, completed };
|
|
120
144
|
}
|
|
121
145
|
export function formatTaskStatus(progress) {
|
|
122
146
|
if (progress.total === 0)
|