@bobby_z/openspec 0.0.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/LICENSE +22 -0
- package/README.md +204 -0
- package/bin/openspec.js +3 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +482 -0
- package/dist/commands/change.d.ts +35 -0
- package/dist/commands/change.js +277 -0
- package/dist/commands/completion.d.ts +72 -0
- package/dist/commands/completion.js +257 -0
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.js +198 -0
- package/dist/commands/feedback.d.ts +9 -0
- package/dist/commands/feedback.js +183 -0
- package/dist/commands/schema.d.ts +6 -0
- package/dist/commands/schema.js +869 -0
- package/dist/commands/show.d.ts +14 -0
- package/dist/commands/show.js +132 -0
- package/dist/commands/spec.d.ts +15 -0
- package/dist/commands/spec.js +225 -0
- package/dist/commands/validate.d.ts +24 -0
- package/dist/commands/validate.js +294 -0
- package/dist/commands/workflow/index.d.ts +17 -0
- package/dist/commands/workflow/index.js +12 -0
- package/dist/commands/workflow/instructions.d.ts +29 -0
- package/dist/commands/workflow/instructions.js +381 -0
- package/dist/commands/workflow/new-change.d.ts +11 -0
- package/dist/commands/workflow/new-change.js +44 -0
- package/dist/commands/workflow/schemas.d.ts +10 -0
- package/dist/commands/workflow/schemas.js +34 -0
- package/dist/commands/workflow/shared.d.ts +52 -0
- package/dist/commands/workflow/shared.js +111 -0
- package/dist/commands/workflow/status.d.ts +14 -0
- package/dist/commands/workflow/status.js +58 -0
- package/dist/commands/workflow/templates.d.ts +16 -0
- package/dist/commands/workflow/templates.js +68 -0
- package/dist/core/archive.d.ts +11 -0
- package/dist/core/archive.js +328 -0
- package/dist/core/artifact-graph/graph.d.ts +56 -0
- package/dist/core/artifact-graph/graph.js +141 -0
- package/dist/core/artifact-graph/index.d.ts +7 -0
- package/dist/core/artifact-graph/index.js +13 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +143 -0
- package/dist/core/artifact-graph/instruction-loader.js +214 -0
- package/dist/core/artifact-graph/resolver.d.ts +81 -0
- package/dist/core/artifact-graph/resolver.js +257 -0
- package/dist/core/artifact-graph/schema.d.ts +13 -0
- package/dist/core/artifact-graph/schema.js +108 -0
- package/dist/core/artifact-graph/state.d.ts +12 -0
- package/dist/core/artifact-graph/state.js +54 -0
- package/dist/core/artifact-graph/types.d.ts +45 -0
- package/dist/core/artifact-graph/types.js +43 -0
- package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
- package/dist/core/command-generation/adapters/amazon-q.js +26 -0
- package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
- package/dist/core/command-generation/adapters/antigravity.js +26 -0
- package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
- package/dist/core/command-generation/adapters/auggie.js +27 -0
- package/dist/core/command-generation/adapters/claude.d.ts +13 -0
- package/dist/core/command-generation/adapters/claude.js +50 -0
- package/dist/core/command-generation/adapters/cline.d.ts +14 -0
- package/dist/core/command-generation/adapters/cline.js +27 -0
- package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
- package/dist/core/command-generation/adapters/codebuddy.js +28 -0
- package/dist/core/command-generation/adapters/codex.d.ts +16 -0
- package/dist/core/command-generation/adapters/codex.js +39 -0
- package/dist/core/command-generation/adapters/continue.d.ts +13 -0
- package/dist/core/command-generation/adapters/continue.js +28 -0
- package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
- package/dist/core/command-generation/adapters/costrict.js +27 -0
- package/dist/core/command-generation/adapters/crush.d.ts +13 -0
- package/dist/core/command-generation/adapters/crush.js +30 -0
- package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
- package/dist/core/command-generation/adapters/cursor.js +44 -0
- package/dist/core/command-generation/adapters/devagent.d.ts +15 -0
- package/dist/core/command-generation/adapters/devagent.js +28 -0
- package/dist/core/command-generation/adapters/factory.d.ts +13 -0
- package/dist/core/command-generation/adapters/factory.js +27 -0
- package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
- package/dist/core/command-generation/adapters/gemini.js +26 -0
- package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
- package/dist/core/command-generation/adapters/github-copilot.js +26 -0
- package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
- package/dist/core/command-generation/adapters/iflow.js +29 -0
- package/dist/core/command-generation/adapters/index.d.ts +28 -0
- package/dist/core/command-generation/adapters/index.js +28 -0
- package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/kilocode.js +23 -0
- package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
- package/dist/core/command-generation/adapters/opencode.js +29 -0
- package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
- package/dist/core/command-generation/adapters/qoder.js +30 -0
- package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
- package/dist/core/command-generation/adapters/qwen.js +26 -0
- package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/roocode.js +27 -0
- package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
- package/dist/core/command-generation/adapters/windsurf.js +51 -0
- package/dist/core/command-generation/generator.d.ts +21 -0
- package/dist/core/command-generation/generator.js +27 -0
- package/dist/core/command-generation/index.d.ts +22 -0
- package/dist/core/command-generation/index.js +24 -0
- package/dist/core/command-generation/registry.d.ts +36 -0
- package/dist/core/command-generation/registry.js +90 -0
- package/dist/core/command-generation/types.d.ts +56 -0
- package/dist/core/command-generation/types.js +8 -0
- package/dist/core/completions/command-registry.d.ts +7 -0
- package/dist/core/completions/command-registry.js +454 -0
- package/dist/core/completions/completion-provider.d.ts +60 -0
- package/dist/core/completions/completion-provider.js +102 -0
- package/dist/core/completions/factory.d.ts +64 -0
- package/dist/core/completions/factory.js +75 -0
- package/dist/core/completions/generators/bash-generator.d.ts +32 -0
- package/dist/core/completions/generators/bash-generator.js +174 -0
- package/dist/core/completions/generators/fish-generator.d.ts +32 -0
- package/dist/core/completions/generators/fish-generator.js +157 -0
- package/dist/core/completions/generators/powershell-generator.d.ts +33 -0
- package/dist/core/completions/generators/powershell-generator.js +207 -0
- package/dist/core/completions/generators/zsh-generator.d.ts +44 -0
- package/dist/core/completions/generators/zsh-generator.js +250 -0
- package/dist/core/completions/installers/bash-installer.d.ts +87 -0
- package/dist/core/completions/installers/bash-installer.js +318 -0
- package/dist/core/completions/installers/fish-installer.d.ts +43 -0
- package/dist/core/completions/installers/fish-installer.js +143 -0
- package/dist/core/completions/installers/powershell-installer.d.ts +88 -0
- package/dist/core/completions/installers/powershell-installer.js +327 -0
- package/dist/core/completions/installers/zsh-installer.d.ts +125 -0
- package/dist/core/completions/installers/zsh-installer.js +449 -0
- package/dist/core/completions/templates/bash-templates.d.ts +6 -0
- package/dist/core/completions/templates/bash-templates.js +24 -0
- package/dist/core/completions/templates/fish-templates.d.ts +7 -0
- package/dist/core/completions/templates/fish-templates.js +39 -0
- package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
- package/dist/core/completions/templates/powershell-templates.js +25 -0
- package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
- package/dist/core/completions/templates/zsh-templates.js +36 -0
- package/dist/core/completions/types.d.ts +79 -0
- package/dist/core/completions/types.js +2 -0
- package/dist/core/config-prompts.d.ts +9 -0
- package/dist/core/config-prompts.js +34 -0
- package/dist/core/config-schema.d.ts +76 -0
- package/dist/core/config-schema.js +200 -0
- package/dist/core/config.d.ts +17 -0
- package/dist/core/config.js +175 -0
- package/dist/core/converters/json-converter.d.ts +6 -0
- package/dist/core/converters/json-converter.js +51 -0
- package/dist/core/global-config.d.ts +39 -0
- package/dist/core/global-config.js +115 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +3 -0
- package/dist/core/init.d.ts +32 -0
- package/dist/core/init.js +447 -0
- package/dist/core/legacy-cleanup.d.ts +162 -0
- package/dist/core/legacy-cleanup.js +520 -0
- package/dist/core/list.d.ts +9 -0
- package/dist/core/list.js +171 -0
- package/dist/core/parsers/change-parser.d.ts +13 -0
- package/dist/core/parsers/change-parser.js +193 -0
- package/dist/core/parsers/markdown-parser.d.ts +22 -0
- package/dist/core/parsers/markdown-parser.js +187 -0
- package/dist/core/parsers/requirement-blocks.d.ts +37 -0
- package/dist/core/parsers/requirement-blocks.js +201 -0
- package/dist/core/project-config.d.ts +64 -0
- package/dist/core/project-config.js +223 -0
- package/dist/core/schemas/base.schema.d.ts +13 -0
- package/dist/core/schemas/base.schema.js +13 -0
- package/dist/core/schemas/change.schema.d.ts +73 -0
- package/dist/core/schemas/change.schema.js +31 -0
- package/dist/core/schemas/index.d.ts +4 -0
- package/dist/core/schemas/index.js +4 -0
- package/dist/core/schemas/spec.schema.d.ts +18 -0
- package/dist/core/schemas/spec.schema.js +15 -0
- package/dist/core/shared/index.d.ts +8 -0
- package/dist/core/shared/index.js +8 -0
- package/dist/core/shared/skill-generation.d.ts +42 -0
- package/dist/core/shared/skill-generation.js +80 -0
- package/dist/core/shared/tool-detection.d.ts +66 -0
- package/dist/core/shared/tool-detection.js +140 -0
- package/dist/core/specs-apply.d.ts +73 -0
- package/dist/core/specs-apply.js +384 -0
- package/dist/core/styles/palette.d.ts +7 -0
- package/dist/core/styles/palette.js +8 -0
- package/dist/core/templates/index.d.ts +8 -0
- package/dist/core/templates/index.js +9 -0
- package/dist/core/templates/skill-templates.d.ts +122 -0
- package/dist/core/templates/skill-templates.js +3437 -0
- package/dist/core/update.d.ts +42 -0
- package/dist/core/update.js +311 -0
- package/dist/core/validation/constants.d.ts +34 -0
- package/dist/core/validation/constants.js +40 -0
- package/dist/core/validation/types.d.ts +18 -0
- package/dist/core/validation/types.js +2 -0
- package/dist/core/validation/validator.d.ts +33 -0
- package/dist/core/validation/validator.js +409 -0
- package/dist/core/view.d.ts +8 -0
- package/dist/core/view.js +168 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/prompts/searchable-multi-select.d.ts +27 -0
- package/dist/prompts/searchable-multi-select.js +149 -0
- package/dist/telemetry/config.d.ts +32 -0
- package/dist/telemetry/config.js +68 -0
- package/dist/telemetry/index.d.ts +31 -0
- package/dist/telemetry/index.js +145 -0
- package/dist/ui/ascii-patterns.d.ts +16 -0
- package/dist/ui/ascii-patterns.js +133 -0
- package/dist/ui/welcome-screen.d.ts +10 -0
- package/dist/ui/welcome-screen.js +146 -0
- package/dist/utils/change-metadata.d.ts +51 -0
- package/dist/utils/change-metadata.js +147 -0
- package/dist/utils/change-utils.d.ts +62 -0
- package/dist/utils/change-utils.js +121 -0
- package/dist/utils/command-references.d.ts +18 -0
- package/dist/utils/command-references.js +20 -0
- package/dist/utils/file-system.d.ts +36 -0
- package/dist/utils/file-system.js +281 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/interactive.d.ts +18 -0
- package/dist/utils/interactive.js +21 -0
- package/dist/utils/item-discovery.d.ts +4 -0
- package/dist/utils/item-discovery.js +72 -0
- package/dist/utils/match.d.ts +3 -0
- package/dist/utils/match.js +22 -0
- package/dist/utils/shell-detection.d.ts +20 -0
- package/dist/utils/shell-detection.js +41 -0
- package/dist/utils/task-progress.d.ts +8 -0
- package/dist/utils/task-progress.js +36 -0
- package/package.json +83 -0
- package/schemas/spec-driven/schema.yaml +151 -0
- package/schemas/spec-driven/templates/design.md +21 -0
- package/schemas/spec-driven/templates/proposal.md +25 -0
- package/schemas/spec-driven/templates/spec.md +10 -0
- package/schemas/spec-driven/templates/tasks.md +9 -0
- package/scripts/postinstall.js +147 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
export function normalizeRequirementName(name) {
|
|
2
|
+
return name.trim();
|
|
3
|
+
}
|
|
4
|
+
const REQUIREMENT_HEADER_REGEX = /^###\s*Requirement:\s*(.+)\s*$/;
|
|
5
|
+
/**
|
|
6
|
+
* Extracts the Requirements section from a spec file and parses requirement blocks.
|
|
7
|
+
*/
|
|
8
|
+
export function extractRequirementsSection(content) {
|
|
9
|
+
const normalized = normalizeLineEndings(content);
|
|
10
|
+
const lines = normalized.split('\n');
|
|
11
|
+
const reqHeaderIndex = lines.findIndex(l => /^##\s+Requirements\s*$/i.test(l));
|
|
12
|
+
if (reqHeaderIndex === -1) {
|
|
13
|
+
// No requirements section; create an empty one at the end
|
|
14
|
+
const before = content.trimEnd();
|
|
15
|
+
const headerLine = '## Requirements';
|
|
16
|
+
return {
|
|
17
|
+
before: before ? before + '\n\n' : '',
|
|
18
|
+
headerLine,
|
|
19
|
+
preamble: '',
|
|
20
|
+
bodyBlocks: [],
|
|
21
|
+
after: '\n',
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
// Find end of this section: next line that starts with '## ' at same or higher level
|
|
25
|
+
let endIndex = lines.length;
|
|
26
|
+
for (let i = reqHeaderIndex + 1; i < lines.length; i++) {
|
|
27
|
+
if (/^##\s+/.test(lines[i])) {
|
|
28
|
+
endIndex = i;
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const before = lines.slice(0, reqHeaderIndex).join('\n');
|
|
33
|
+
const headerLine = lines[reqHeaderIndex];
|
|
34
|
+
const sectionBodyLines = lines.slice(reqHeaderIndex + 1, endIndex);
|
|
35
|
+
// Parse requirement blocks within section body
|
|
36
|
+
const blocks = [];
|
|
37
|
+
let cursor = 0;
|
|
38
|
+
let preambleLines = [];
|
|
39
|
+
// Collect preamble lines until first requirement header
|
|
40
|
+
while (cursor < sectionBodyLines.length && !/^###\s+Requirement:/.test(sectionBodyLines[cursor])) {
|
|
41
|
+
preambleLines.push(sectionBodyLines[cursor]);
|
|
42
|
+
cursor++;
|
|
43
|
+
}
|
|
44
|
+
while (cursor < sectionBodyLines.length) {
|
|
45
|
+
const headerStart = cursor;
|
|
46
|
+
const headerLineCandidate = sectionBodyLines[cursor];
|
|
47
|
+
const headerMatch = headerLineCandidate.match(REQUIREMENT_HEADER_REGEX);
|
|
48
|
+
if (!headerMatch) {
|
|
49
|
+
// Not a requirement header; skip line defensively
|
|
50
|
+
cursor++;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const name = normalizeRequirementName(headerMatch[1]);
|
|
54
|
+
cursor++;
|
|
55
|
+
// Gather lines until next requirement header or end of section
|
|
56
|
+
const bodyLines = [headerLineCandidate];
|
|
57
|
+
while (cursor < sectionBodyLines.length && !/^###\s+Requirement:/.test(sectionBodyLines[cursor]) && !/^##\s+/.test(sectionBodyLines[cursor])) {
|
|
58
|
+
bodyLines.push(sectionBodyLines[cursor]);
|
|
59
|
+
cursor++;
|
|
60
|
+
}
|
|
61
|
+
const raw = bodyLines.join('\n').trimEnd();
|
|
62
|
+
blocks.push({ headerLine: headerLineCandidate, name, raw });
|
|
63
|
+
}
|
|
64
|
+
const after = lines.slice(endIndex).join('\n');
|
|
65
|
+
const preamble = preambleLines.join('\n').trimEnd();
|
|
66
|
+
return {
|
|
67
|
+
before: before.trimEnd() ? before + '\n' : before,
|
|
68
|
+
headerLine,
|
|
69
|
+
preamble,
|
|
70
|
+
bodyBlocks: blocks,
|
|
71
|
+
after: after.startsWith('\n') ? after : '\n' + after,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function normalizeLineEndings(content) {
|
|
75
|
+
return content.replace(/\r\n?/g, '\n');
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Parse a delta-formatted spec change file content into a DeltaPlan with raw blocks.
|
|
79
|
+
*/
|
|
80
|
+
export function parseDeltaSpec(content) {
|
|
81
|
+
const normalized = normalizeLineEndings(content);
|
|
82
|
+
const sections = splitTopLevelSections(normalized);
|
|
83
|
+
const addedLookup = getSectionCaseInsensitive(sections, 'ADDED Requirements');
|
|
84
|
+
const modifiedLookup = getSectionCaseInsensitive(sections, 'MODIFIED Requirements');
|
|
85
|
+
const removedLookup = getSectionCaseInsensitive(sections, 'REMOVED Requirements');
|
|
86
|
+
const renamedLookup = getSectionCaseInsensitive(sections, 'RENAMED Requirements');
|
|
87
|
+
const added = parseRequirementBlocksFromSection(addedLookup.body);
|
|
88
|
+
const modified = parseRequirementBlocksFromSection(modifiedLookup.body);
|
|
89
|
+
const removedNames = parseRemovedNames(removedLookup.body);
|
|
90
|
+
const renamedPairs = parseRenamedPairs(renamedLookup.body);
|
|
91
|
+
return {
|
|
92
|
+
added,
|
|
93
|
+
modified,
|
|
94
|
+
removed: removedNames,
|
|
95
|
+
renamed: renamedPairs,
|
|
96
|
+
sectionPresence: {
|
|
97
|
+
added: addedLookup.found,
|
|
98
|
+
modified: modifiedLookup.found,
|
|
99
|
+
removed: removedLookup.found,
|
|
100
|
+
renamed: renamedLookup.found,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function splitTopLevelSections(content) {
|
|
105
|
+
const lines = content.split('\n');
|
|
106
|
+
const result = {};
|
|
107
|
+
const indices = [];
|
|
108
|
+
for (let i = 0; i < lines.length; i++) {
|
|
109
|
+
const m = lines[i].match(/^(##)\s+(.+)$/);
|
|
110
|
+
if (m) {
|
|
111
|
+
const level = m[1].length; // only care for '##'
|
|
112
|
+
indices.push({ title: m[2].trim(), index: i, level });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
for (let i = 0; i < indices.length; i++) {
|
|
116
|
+
const current = indices[i];
|
|
117
|
+
const next = indices[i + 1];
|
|
118
|
+
const body = lines.slice(current.index + 1, next ? next.index : lines.length).join('\n');
|
|
119
|
+
result[current.title] = body;
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
function getSectionCaseInsensitive(sections, desired) {
|
|
124
|
+
const target = desired.toLowerCase();
|
|
125
|
+
for (const [title, body] of Object.entries(sections)) {
|
|
126
|
+
if (title.toLowerCase() === target)
|
|
127
|
+
return { body, found: true };
|
|
128
|
+
}
|
|
129
|
+
return { body: '', found: false };
|
|
130
|
+
}
|
|
131
|
+
function parseRequirementBlocksFromSection(sectionBody) {
|
|
132
|
+
if (!sectionBody)
|
|
133
|
+
return [];
|
|
134
|
+
const lines = normalizeLineEndings(sectionBody).split('\n');
|
|
135
|
+
const blocks = [];
|
|
136
|
+
let i = 0;
|
|
137
|
+
while (i < lines.length) {
|
|
138
|
+
// Seek next requirement header
|
|
139
|
+
while (i < lines.length && !/^###\s+Requirement:/.test(lines[i]))
|
|
140
|
+
i++;
|
|
141
|
+
if (i >= lines.length)
|
|
142
|
+
break;
|
|
143
|
+
const headerLine = lines[i];
|
|
144
|
+
const m = headerLine.match(REQUIREMENT_HEADER_REGEX);
|
|
145
|
+
if (!m) {
|
|
146
|
+
i++;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const name = normalizeRequirementName(m[1]);
|
|
150
|
+
const buf = [headerLine];
|
|
151
|
+
i++;
|
|
152
|
+
while (i < lines.length && !/^###\s+Requirement:/.test(lines[i]) && !/^##\s+/.test(lines[i])) {
|
|
153
|
+
buf.push(lines[i]);
|
|
154
|
+
i++;
|
|
155
|
+
}
|
|
156
|
+
blocks.push({ headerLine, name, raw: buf.join('\n').trimEnd() });
|
|
157
|
+
}
|
|
158
|
+
return blocks;
|
|
159
|
+
}
|
|
160
|
+
function parseRemovedNames(sectionBody) {
|
|
161
|
+
if (!sectionBody)
|
|
162
|
+
return [];
|
|
163
|
+
const names = [];
|
|
164
|
+
const lines = normalizeLineEndings(sectionBody).split('\n');
|
|
165
|
+
for (const line of lines) {
|
|
166
|
+
const m = line.match(REQUIREMENT_HEADER_REGEX);
|
|
167
|
+
if (m) {
|
|
168
|
+
names.push(normalizeRequirementName(m[1]));
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
// Also support bullet list of headers
|
|
172
|
+
const bullet = line.match(/^\s*-\s*`?###\s*Requirement:\s*(.+?)`?\s*$/);
|
|
173
|
+
if (bullet) {
|
|
174
|
+
names.push(normalizeRequirementName(bullet[1]));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return names;
|
|
178
|
+
}
|
|
179
|
+
function parseRenamedPairs(sectionBody) {
|
|
180
|
+
if (!sectionBody)
|
|
181
|
+
return [];
|
|
182
|
+
const pairs = [];
|
|
183
|
+
const lines = normalizeLineEndings(sectionBody).split('\n');
|
|
184
|
+
let current = {};
|
|
185
|
+
for (const line of lines) {
|
|
186
|
+
const fromMatch = line.match(/^\s*-?\s*FROM:\s*`?###\s*Requirement:\s*(.+?)`?\s*$/);
|
|
187
|
+
const toMatch = line.match(/^\s*-?\s*TO:\s*`?###\s*Requirement:\s*(.+?)`?\s*$/);
|
|
188
|
+
if (fromMatch) {
|
|
189
|
+
current.from = normalizeRequirementName(fromMatch[1]);
|
|
190
|
+
}
|
|
191
|
+
else if (toMatch) {
|
|
192
|
+
current.to = normalizeRequirementName(toMatch[1]);
|
|
193
|
+
if (current.from && current.to) {
|
|
194
|
+
pairs.push({ from: current.from, to: current.to });
|
|
195
|
+
current = {};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return pairs;
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=requirement-blocks.js.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Zod schema for project configuration.
|
|
4
|
+
*
|
|
5
|
+
* Purpose:
|
|
6
|
+
* 1. Documentation - clearly defines the config file structure
|
|
7
|
+
* 2. Type safety - TypeScript infers ProjectConfig type from schema
|
|
8
|
+
* 3. Runtime validation - uses safeParse() for resilient field-by-field validation
|
|
9
|
+
*
|
|
10
|
+
* Why Zod over manual validation:
|
|
11
|
+
* - Helps understand OpenSpec's data interfaces at a glance
|
|
12
|
+
* - Single source of truth for type and validation
|
|
13
|
+
* - Consistent with other OpenSpec schemas
|
|
14
|
+
*/
|
|
15
|
+
export declare const ProjectConfigSchema: z.ZodObject<{
|
|
16
|
+
schema: z.ZodString;
|
|
17
|
+
context: z.ZodOptional<z.ZodString>;
|
|
18
|
+
rules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
19
|
+
}, z.core.$strip>;
|
|
20
|
+
export type ProjectConfig = z.infer<typeof ProjectConfigSchema>;
|
|
21
|
+
/**
|
|
22
|
+
* Read and parse openspec/config.yaml from project root.
|
|
23
|
+
* Uses resilient parsing - validates each field independently using Zod safeParse.
|
|
24
|
+
* Returns null if file doesn't exist.
|
|
25
|
+
* Returns partial config if some fields are invalid (with warnings).
|
|
26
|
+
*
|
|
27
|
+
* Performance note (Jan 2025):
|
|
28
|
+
* Benchmarks showed direct file reads are fast enough without caching:
|
|
29
|
+
* - Typical config (1KB): ~0.5ms per read
|
|
30
|
+
* - Large config (50KB): ~1.6ms per read
|
|
31
|
+
* - Missing config: ~0.01ms per read
|
|
32
|
+
* Config is read 1-2 times per command (schema resolution + instruction loading),
|
|
33
|
+
* adding ~1-3ms total overhead. Caching would add complexity (mtime checks,
|
|
34
|
+
* invalidation logic) for negligible benefit. Direct reads also ensure config
|
|
35
|
+
* changes are reflected immediately without stale cache issues.
|
|
36
|
+
*
|
|
37
|
+
* @param projectRoot - The root directory of the project (where `openspec/` lives)
|
|
38
|
+
* @returns Parsed config or null if file doesn't exist
|
|
39
|
+
*/
|
|
40
|
+
export declare function readProjectConfig(projectRoot: string): ProjectConfig | null;
|
|
41
|
+
/**
|
|
42
|
+
* Validate artifact IDs in rules against a schema's artifacts.
|
|
43
|
+
* Called during instruction loading (when schema is known).
|
|
44
|
+
* Returns warnings for unknown artifact IDs.
|
|
45
|
+
*
|
|
46
|
+
* @param rules - The rules object from config
|
|
47
|
+
* @param validArtifactIds - Set of valid artifact IDs from the schema
|
|
48
|
+
* @param schemaName - Name of the schema for error messages
|
|
49
|
+
* @returns Array of warning messages for unknown artifact IDs
|
|
50
|
+
*/
|
|
51
|
+
export declare function validateConfigRules(rules: Record<string, string[]>, validArtifactIds: Set<string>, schemaName: string): string[];
|
|
52
|
+
/**
|
|
53
|
+
* Suggest valid schema names when user provides invalid schema.
|
|
54
|
+
* Uses fuzzy matching to find similar names.
|
|
55
|
+
*
|
|
56
|
+
* @param invalidSchemaName - The invalid schema name from config
|
|
57
|
+
* @param availableSchemas - List of available schemas with their type (built-in or project-local)
|
|
58
|
+
* @returns Error message with suggestions and available schemas
|
|
59
|
+
*/
|
|
60
|
+
export declare function suggestSchemas(invalidSchemaName: string, availableSchemas: {
|
|
61
|
+
name: string;
|
|
62
|
+
isBuiltIn: boolean;
|
|
63
|
+
}[]): string;
|
|
64
|
+
//# sourceMappingURL=project-config.d.ts.map
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { parse as parseYaml } from 'yaml';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
/**
|
|
6
|
+
* Zod schema for project configuration.
|
|
7
|
+
*
|
|
8
|
+
* Purpose:
|
|
9
|
+
* 1. Documentation - clearly defines the config file structure
|
|
10
|
+
* 2. Type safety - TypeScript infers ProjectConfig type from schema
|
|
11
|
+
* 3. Runtime validation - uses safeParse() for resilient field-by-field validation
|
|
12
|
+
*
|
|
13
|
+
* Why Zod over manual validation:
|
|
14
|
+
* - Helps understand OpenSpec's data interfaces at a glance
|
|
15
|
+
* - Single source of truth for type and validation
|
|
16
|
+
* - Consistent with other OpenSpec schemas
|
|
17
|
+
*/
|
|
18
|
+
export const ProjectConfigSchema = z.object({
|
|
19
|
+
// Required: which schema to use (e.g., "spec-driven", or project-local schema name)
|
|
20
|
+
schema: z
|
|
21
|
+
.string()
|
|
22
|
+
.min(1)
|
|
23
|
+
.describe('The workflow schema to use (e.g., "spec-driven")'),
|
|
24
|
+
// Optional: project context (injected into all artifact instructions)
|
|
25
|
+
// Max size: 50KB (enforced during parsing)
|
|
26
|
+
context: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('Project context injected into all artifact instructions'),
|
|
30
|
+
// Optional: per-artifact rules (additive to schema's built-in guidance)
|
|
31
|
+
rules: z
|
|
32
|
+
.record(z.string(), // artifact ID
|
|
33
|
+
z.array(z.string()) // list of rules
|
|
34
|
+
)
|
|
35
|
+
.optional()
|
|
36
|
+
.describe('Per-artifact rules, keyed by artifact ID'),
|
|
37
|
+
});
|
|
38
|
+
const MAX_CONTEXT_SIZE = 50 * 1024; // 50KB hard limit
|
|
39
|
+
/**
|
|
40
|
+
* Read and parse openspec/config.yaml from project root.
|
|
41
|
+
* Uses resilient parsing - validates each field independently using Zod safeParse.
|
|
42
|
+
* Returns null if file doesn't exist.
|
|
43
|
+
* Returns partial config if some fields are invalid (with warnings).
|
|
44
|
+
*
|
|
45
|
+
* Performance note (Jan 2025):
|
|
46
|
+
* Benchmarks showed direct file reads are fast enough without caching:
|
|
47
|
+
* - Typical config (1KB): ~0.5ms per read
|
|
48
|
+
* - Large config (50KB): ~1.6ms per read
|
|
49
|
+
* - Missing config: ~0.01ms per read
|
|
50
|
+
* Config is read 1-2 times per command (schema resolution + instruction loading),
|
|
51
|
+
* adding ~1-3ms total overhead. Caching would add complexity (mtime checks,
|
|
52
|
+
* invalidation logic) for negligible benefit. Direct reads also ensure config
|
|
53
|
+
* changes are reflected immediately without stale cache issues.
|
|
54
|
+
*
|
|
55
|
+
* @param projectRoot - The root directory of the project (where `openspec/` lives)
|
|
56
|
+
* @returns Parsed config or null if file doesn't exist
|
|
57
|
+
*/
|
|
58
|
+
export function readProjectConfig(projectRoot) {
|
|
59
|
+
// Try both .yaml and .yml, prefer .yaml
|
|
60
|
+
let configPath = path.join(projectRoot, 'openspec', 'config.yaml');
|
|
61
|
+
if (!existsSync(configPath)) {
|
|
62
|
+
configPath = path.join(projectRoot, 'openspec', 'config.yml');
|
|
63
|
+
if (!existsSync(configPath)) {
|
|
64
|
+
return null; // No config is OK
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const content = readFileSync(configPath, 'utf-8');
|
|
69
|
+
const raw = parseYaml(content);
|
|
70
|
+
if (!raw || typeof raw !== 'object') {
|
|
71
|
+
console.warn(`openspec/config.yaml is not a valid YAML object`);
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const config = {};
|
|
75
|
+
// Parse schema field using Zod
|
|
76
|
+
const schemaField = z.string().min(1);
|
|
77
|
+
const schemaResult = schemaField.safeParse(raw.schema);
|
|
78
|
+
if (schemaResult.success) {
|
|
79
|
+
config.schema = schemaResult.data;
|
|
80
|
+
}
|
|
81
|
+
else if (raw.schema !== undefined) {
|
|
82
|
+
console.warn(`Invalid 'schema' field in config (must be non-empty string)`);
|
|
83
|
+
}
|
|
84
|
+
// Parse context field with size limit
|
|
85
|
+
if (raw.context !== undefined) {
|
|
86
|
+
const contextField = z.string();
|
|
87
|
+
const contextResult = contextField.safeParse(raw.context);
|
|
88
|
+
if (contextResult.success) {
|
|
89
|
+
const contextSize = Buffer.byteLength(contextResult.data, 'utf-8');
|
|
90
|
+
if (contextSize > MAX_CONTEXT_SIZE) {
|
|
91
|
+
console.warn(`Context too large (${(contextSize / 1024).toFixed(1)}KB, limit: ${MAX_CONTEXT_SIZE / 1024}KB)`);
|
|
92
|
+
console.warn(`Ignoring context field`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
config.context = contextResult.data;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.warn(`Invalid 'context' field in config (must be string)`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Parse rules field using Zod
|
|
103
|
+
if (raw.rules !== undefined) {
|
|
104
|
+
const rulesField = z.record(z.string(), z.array(z.string()));
|
|
105
|
+
// First check if it's an object structure (guard against null since typeof null === 'object')
|
|
106
|
+
if (typeof raw.rules === 'object' && raw.rules !== null && !Array.isArray(raw.rules)) {
|
|
107
|
+
const parsedRules = {};
|
|
108
|
+
let hasValidRules = false;
|
|
109
|
+
for (const [artifactId, rules] of Object.entries(raw.rules)) {
|
|
110
|
+
const rulesArrayResult = z.array(z.string()).safeParse(rules);
|
|
111
|
+
if (rulesArrayResult.success) {
|
|
112
|
+
// Filter out empty strings
|
|
113
|
+
const validRules = rulesArrayResult.data.filter((r) => r.length > 0);
|
|
114
|
+
if (validRules.length > 0) {
|
|
115
|
+
parsedRules[artifactId] = validRules;
|
|
116
|
+
hasValidRules = true;
|
|
117
|
+
}
|
|
118
|
+
if (validRules.length < rulesArrayResult.data.length) {
|
|
119
|
+
console.warn(`Some rules for '${artifactId}' are empty strings, ignoring them`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
console.warn(`Rules for '${artifactId}' must be an array of strings, ignoring this artifact's rules`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (hasValidRules) {
|
|
127
|
+
config.rules = parsedRules;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
console.warn(`Invalid 'rules' field in config (must be object)`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Return partial config even if some fields failed
|
|
135
|
+
return Object.keys(config).length > 0 ? config : null;
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
console.warn(`Failed to parse openspec/config.yaml:`, error);
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Validate artifact IDs in rules against a schema's artifacts.
|
|
144
|
+
* Called during instruction loading (when schema is known).
|
|
145
|
+
* Returns warnings for unknown artifact IDs.
|
|
146
|
+
*
|
|
147
|
+
* @param rules - The rules object from config
|
|
148
|
+
* @param validArtifactIds - Set of valid artifact IDs from the schema
|
|
149
|
+
* @param schemaName - Name of the schema for error messages
|
|
150
|
+
* @returns Array of warning messages for unknown artifact IDs
|
|
151
|
+
*/
|
|
152
|
+
export function validateConfigRules(rules, validArtifactIds, schemaName) {
|
|
153
|
+
const warnings = [];
|
|
154
|
+
for (const artifactId of Object.keys(rules)) {
|
|
155
|
+
if (!validArtifactIds.has(artifactId)) {
|
|
156
|
+
const validIds = Array.from(validArtifactIds).sort().join(', ');
|
|
157
|
+
warnings.push(`Unknown artifact ID in rules: "${artifactId}". ` +
|
|
158
|
+
`Valid IDs for schema "${schemaName}": ${validIds}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return warnings;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Suggest valid schema names when user provides invalid schema.
|
|
165
|
+
* Uses fuzzy matching to find similar names.
|
|
166
|
+
*
|
|
167
|
+
* @param invalidSchemaName - The invalid schema name from config
|
|
168
|
+
* @param availableSchemas - List of available schemas with their type (built-in or project-local)
|
|
169
|
+
* @returns Error message with suggestions and available schemas
|
|
170
|
+
*/
|
|
171
|
+
export function suggestSchemas(invalidSchemaName, availableSchemas) {
|
|
172
|
+
// Simple fuzzy match: Levenshtein distance
|
|
173
|
+
function levenshtein(a, b) {
|
|
174
|
+
const matrix = [];
|
|
175
|
+
for (let i = 0; i <= b.length; i++) {
|
|
176
|
+
matrix[i] = [i];
|
|
177
|
+
}
|
|
178
|
+
for (let j = 0; j <= a.length; j++) {
|
|
179
|
+
matrix[0][j] = j;
|
|
180
|
+
}
|
|
181
|
+
for (let i = 1; i <= b.length; i++) {
|
|
182
|
+
for (let j = 1; j <= a.length; j++) {
|
|
183
|
+
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
184
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return matrix[b.length][a.length];
|
|
192
|
+
}
|
|
193
|
+
// Find closest matches (distance <= 3)
|
|
194
|
+
const suggestions = availableSchemas
|
|
195
|
+
.map((s) => ({ ...s, distance: levenshtein(invalidSchemaName, s.name) }))
|
|
196
|
+
.filter((s) => s.distance <= 3)
|
|
197
|
+
.sort((a, b) => a.distance - b.distance)
|
|
198
|
+
.slice(0, 3);
|
|
199
|
+
const builtIn = availableSchemas.filter((s) => s.isBuiltIn).map((s) => s.name);
|
|
200
|
+
const projectLocal = availableSchemas.filter((s) => !s.isBuiltIn).map((s) => s.name);
|
|
201
|
+
let message = `Schema '${invalidSchemaName}' not found in openspec/config.yaml\n\n`;
|
|
202
|
+
if (suggestions.length > 0) {
|
|
203
|
+
message += `Did you mean one of these?\n`;
|
|
204
|
+
suggestions.forEach((s) => {
|
|
205
|
+
const type = s.isBuiltIn ? 'built-in' : 'project-local';
|
|
206
|
+
message += ` - ${s.name} (${type})\n`;
|
|
207
|
+
});
|
|
208
|
+
message += '\n';
|
|
209
|
+
}
|
|
210
|
+
message += `Available schemas:\n`;
|
|
211
|
+
if (builtIn.length > 0) {
|
|
212
|
+
message += ` Built-in: ${builtIn.join(', ')}\n`;
|
|
213
|
+
}
|
|
214
|
+
if (projectLocal.length > 0) {
|
|
215
|
+
message += ` Project-local: ${projectLocal.join(', ')}\n`;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
message += ` Project-local: (none found)\n`;
|
|
219
|
+
}
|
|
220
|
+
message += `\nFix: Edit openspec/config.yaml and change 'schema: ${invalidSchemaName}' to a valid schema name`;
|
|
221
|
+
return message;
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=project-config.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const ScenarioSchema: z.ZodObject<{
|
|
3
|
+
rawText: z.ZodString;
|
|
4
|
+
}, z.core.$strip>;
|
|
5
|
+
export declare const RequirementSchema: z.ZodObject<{
|
|
6
|
+
text: z.ZodString;
|
|
7
|
+
scenarios: z.ZodArray<z.ZodObject<{
|
|
8
|
+
rawText: z.ZodString;
|
|
9
|
+
}, z.core.$strip>>;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
export type Scenario = z.infer<typeof ScenarioSchema>;
|
|
12
|
+
export type Requirement = z.infer<typeof RequirementSchema>;
|
|
13
|
+
//# sourceMappingURL=base.schema.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { VALIDATION_MESSAGES } from '../validation/constants.js';
|
|
3
|
+
export const ScenarioSchema = z.object({
|
|
4
|
+
rawText: z.string().min(1, VALIDATION_MESSAGES.SCENARIO_EMPTY),
|
|
5
|
+
});
|
|
6
|
+
export const RequirementSchema = z.object({
|
|
7
|
+
text: z.string()
|
|
8
|
+
.min(1, VALIDATION_MESSAGES.REQUIREMENT_EMPTY)
|
|
9
|
+
.refine((text) => text.includes('SHALL') || text.includes('MUST'), VALIDATION_MESSAGES.REQUIREMENT_NO_SHALL),
|
|
10
|
+
scenarios: z.array(ScenarioSchema)
|
|
11
|
+
.min(1, VALIDATION_MESSAGES.REQUIREMENT_NO_SCENARIOS),
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=base.schema.js.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const DeltaOperationType: z.ZodEnum<{
|
|
3
|
+
ADDED: "ADDED";
|
|
4
|
+
MODIFIED: "MODIFIED";
|
|
5
|
+
REMOVED: "REMOVED";
|
|
6
|
+
RENAMED: "RENAMED";
|
|
7
|
+
}>;
|
|
8
|
+
export declare const DeltaSchema: z.ZodObject<{
|
|
9
|
+
spec: z.ZodString;
|
|
10
|
+
operation: z.ZodEnum<{
|
|
11
|
+
ADDED: "ADDED";
|
|
12
|
+
MODIFIED: "MODIFIED";
|
|
13
|
+
REMOVED: "REMOVED";
|
|
14
|
+
RENAMED: "RENAMED";
|
|
15
|
+
}>;
|
|
16
|
+
description: z.ZodString;
|
|
17
|
+
requirement: z.ZodOptional<z.ZodObject<{
|
|
18
|
+
text: z.ZodString;
|
|
19
|
+
scenarios: z.ZodArray<z.ZodObject<{
|
|
20
|
+
rawText: z.ZodString;
|
|
21
|
+
}, z.core.$strip>>;
|
|
22
|
+
}, z.core.$strip>>;
|
|
23
|
+
requirements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
24
|
+
text: z.ZodString;
|
|
25
|
+
scenarios: z.ZodArray<z.ZodObject<{
|
|
26
|
+
rawText: z.ZodString;
|
|
27
|
+
}, z.core.$strip>>;
|
|
28
|
+
}, z.core.$strip>>>;
|
|
29
|
+
rename: z.ZodOptional<z.ZodObject<{
|
|
30
|
+
from: z.ZodString;
|
|
31
|
+
to: z.ZodString;
|
|
32
|
+
}, z.core.$strip>>;
|
|
33
|
+
}, z.core.$strip>;
|
|
34
|
+
export declare const ChangeSchema: z.ZodObject<{
|
|
35
|
+
name: z.ZodString;
|
|
36
|
+
why: z.ZodString;
|
|
37
|
+
whatChanges: z.ZodString;
|
|
38
|
+
deltas: z.ZodArray<z.ZodObject<{
|
|
39
|
+
spec: z.ZodString;
|
|
40
|
+
operation: z.ZodEnum<{
|
|
41
|
+
ADDED: "ADDED";
|
|
42
|
+
MODIFIED: "MODIFIED";
|
|
43
|
+
REMOVED: "REMOVED";
|
|
44
|
+
RENAMED: "RENAMED";
|
|
45
|
+
}>;
|
|
46
|
+
description: z.ZodString;
|
|
47
|
+
requirement: z.ZodOptional<z.ZodObject<{
|
|
48
|
+
text: z.ZodString;
|
|
49
|
+
scenarios: z.ZodArray<z.ZodObject<{
|
|
50
|
+
rawText: z.ZodString;
|
|
51
|
+
}, z.core.$strip>>;
|
|
52
|
+
}, z.core.$strip>>;
|
|
53
|
+
requirements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
54
|
+
text: z.ZodString;
|
|
55
|
+
scenarios: z.ZodArray<z.ZodObject<{
|
|
56
|
+
rawText: z.ZodString;
|
|
57
|
+
}, z.core.$strip>>;
|
|
58
|
+
}, z.core.$strip>>>;
|
|
59
|
+
rename: z.ZodOptional<z.ZodObject<{
|
|
60
|
+
from: z.ZodString;
|
|
61
|
+
to: z.ZodString;
|
|
62
|
+
}, z.core.$strip>>;
|
|
63
|
+
}, z.core.$strip>>;
|
|
64
|
+
metadata: z.ZodOptional<z.ZodObject<{
|
|
65
|
+
version: z.ZodDefault<z.ZodString>;
|
|
66
|
+
format: z.ZodLiteral<"openspec-change">;
|
|
67
|
+
sourcePath: z.ZodOptional<z.ZodString>;
|
|
68
|
+
}, z.core.$strip>>;
|
|
69
|
+
}, z.core.$strip>;
|
|
70
|
+
export type DeltaOperation = z.infer<typeof DeltaOperationType>;
|
|
71
|
+
export type Delta = z.infer<typeof DeltaSchema>;
|
|
72
|
+
export type Change = z.infer<typeof ChangeSchema>;
|
|
73
|
+
//# sourceMappingURL=change.schema.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { RequirementSchema } from './base.schema.js';
|
|
3
|
+
import { MIN_WHY_SECTION_LENGTH, MAX_WHY_SECTION_LENGTH, MAX_DELTAS_PER_CHANGE, VALIDATION_MESSAGES } from '../validation/constants.js';
|
|
4
|
+
export const DeltaOperationType = z.enum(['ADDED', 'MODIFIED', 'REMOVED', 'RENAMED']);
|
|
5
|
+
export const DeltaSchema = z.object({
|
|
6
|
+
spec: z.string().min(1, VALIDATION_MESSAGES.DELTA_SPEC_EMPTY),
|
|
7
|
+
operation: DeltaOperationType,
|
|
8
|
+
description: z.string().min(1, VALIDATION_MESSAGES.DELTA_DESCRIPTION_EMPTY),
|
|
9
|
+
requirement: RequirementSchema.optional(),
|
|
10
|
+
requirements: z.array(RequirementSchema).optional(),
|
|
11
|
+
rename: z.object({
|
|
12
|
+
from: z.string(),
|
|
13
|
+
to: z.string(),
|
|
14
|
+
}).optional(),
|
|
15
|
+
});
|
|
16
|
+
export const ChangeSchema = z.object({
|
|
17
|
+
name: z.string().min(1, VALIDATION_MESSAGES.CHANGE_NAME_EMPTY),
|
|
18
|
+
why: z.string()
|
|
19
|
+
.min(MIN_WHY_SECTION_LENGTH, VALIDATION_MESSAGES.CHANGE_WHY_TOO_SHORT)
|
|
20
|
+
.max(MAX_WHY_SECTION_LENGTH, VALIDATION_MESSAGES.CHANGE_WHY_TOO_LONG),
|
|
21
|
+
whatChanges: z.string().min(1, VALIDATION_MESSAGES.CHANGE_WHAT_EMPTY),
|
|
22
|
+
deltas: z.array(DeltaSchema)
|
|
23
|
+
.min(1, VALIDATION_MESSAGES.CHANGE_NO_DELTAS)
|
|
24
|
+
.max(MAX_DELTAS_PER_CHANGE, VALIDATION_MESSAGES.CHANGE_TOO_MANY_DELTAS),
|
|
25
|
+
metadata: z.object({
|
|
26
|
+
version: z.string().default('1.0.0'),
|
|
27
|
+
format: z.literal('openspec-change'),
|
|
28
|
+
sourcePath: z.string().optional(),
|
|
29
|
+
}).optional(),
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=change.schema.js.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { ScenarioSchema, RequirementSchema, type Scenario, type Requirement, } from './base.schema.js';
|
|
2
|
+
export { SpecSchema, type Spec, } from './spec.schema.js';
|
|
3
|
+
export { DeltaOperationType, DeltaSchema, ChangeSchema, type DeltaOperation, type Delta, type Change, } from './change.schema.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const SpecSchema: z.ZodObject<{
|
|
3
|
+
name: z.ZodString;
|
|
4
|
+
overview: z.ZodString;
|
|
5
|
+
requirements: z.ZodArray<z.ZodObject<{
|
|
6
|
+
text: z.ZodString;
|
|
7
|
+
scenarios: z.ZodArray<z.ZodObject<{
|
|
8
|
+
rawText: z.ZodString;
|
|
9
|
+
}, z.core.$strip>>;
|
|
10
|
+
}, z.core.$strip>>;
|
|
11
|
+
metadata: z.ZodOptional<z.ZodObject<{
|
|
12
|
+
version: z.ZodDefault<z.ZodString>;
|
|
13
|
+
format: z.ZodLiteral<"openspec">;
|
|
14
|
+
sourcePath: z.ZodOptional<z.ZodString>;
|
|
15
|
+
}, z.core.$strip>>;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
export type Spec = z.infer<typeof SpecSchema>;
|
|
18
|
+
//# sourceMappingURL=spec.schema.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { RequirementSchema } from './base.schema.js';
|
|
3
|
+
import { VALIDATION_MESSAGES } from '../validation/constants.js';
|
|
4
|
+
export const SpecSchema = z.object({
|
|
5
|
+
name: z.string().min(1, VALIDATION_MESSAGES.SPEC_NAME_EMPTY),
|
|
6
|
+
overview: z.string().min(1, VALIDATION_MESSAGES.SPEC_PURPOSE_EMPTY),
|
|
7
|
+
requirements: z.array(RequirementSchema)
|
|
8
|
+
.min(1, VALIDATION_MESSAGES.SPEC_NO_REQUIREMENTS),
|
|
9
|
+
metadata: z.object({
|
|
10
|
+
version: z.string().default('1.0.0'),
|
|
11
|
+
format: z.literal('openspec'),
|
|
12
|
+
sourcePath: z.string().optional(),
|
|
13
|
+
}).optional(),
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=spec.schema.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Utilities
|
|
3
|
+
*
|
|
4
|
+
* Common code shared between init and update commands.
|
|
5
|
+
*/
|
|
6
|
+
export { SKILL_NAMES, type SkillName, type ToolSkillStatus, type ToolVersionStatus, getToolsWithSkillsDir, getToolSkillStatus, getToolStates, extractGeneratedByVersion, getToolVersionStatus, getConfiguredTools, getAllToolVersionStatus, } from './tool-detection.js';
|
|
7
|
+
export { type SkillTemplateEntry, type CommandTemplateEntry, getSkillTemplates, getCommandTemplates, getCommandContents, generateSkillContent, } from './skill-generation.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|