@applica-software-guru/sdd-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/config-manager.d.ts +9 -0
- package/dist/config/config-manager.d.ts.map +1 -0
- package/dist/config/config-manager.js +44 -0
- package/dist/config/config-manager.js.map +1 -0
- package/dist/delta/delta-engine.d.ts +3 -0
- package/dist/delta/delta-engine.d.ts.map +1 -0
- package/dist/delta/delta-engine.js +18 -0
- package/dist/delta/delta-engine.js.map +1 -0
- package/dist/delta/hasher.d.ts +2 -0
- package/dist/delta/hasher.d.ts.map +1 -0
- package/dist/delta/hasher.js +8 -0
- package/dist/delta/hasher.js.map +1 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +32 -0
- package/dist/errors.js.map +1 -0
- package/dist/git/git.d.ts +12 -0
- package/dist/git/git.d.ts.map +1 -0
- package/dist/git/git.js +125 -0
- package/dist/git/git.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/lock/lock-manager.d.ts +6 -0
- package/dist/lock/lock-manager.d.ts.map +1 -0
- package/dist/lock/lock-manager.js +39 -0
- package/dist/lock/lock-manager.js.map +1 -0
- package/dist/parser/cr-parser.d.ts +8 -0
- package/dist/parser/cr-parser.d.ts.map +1 -0
- package/dist/parser/cr-parser.js +45 -0
- package/dist/parser/cr-parser.js.map +1 -0
- package/dist/parser/frontmatter.d.ts +7 -0
- package/dist/parser/frontmatter.d.ts.map +1 -0
- package/dist/parser/frontmatter.js +25 -0
- package/dist/parser/frontmatter.js.map +1 -0
- package/dist/parser/ref-extractor.d.ts +2 -0
- package/dist/parser/ref-extractor.d.ts.map +1 -0
- package/dist/parser/ref-extractor.js +17 -0
- package/dist/parser/ref-extractor.js.map +1 -0
- package/dist/parser/section-extractor.d.ts +4 -0
- package/dist/parser/section-extractor.d.ts.map +1 -0
- package/dist/parser/section-extractor.js +37 -0
- package/dist/parser/section-extractor.js.map +1 -0
- package/dist/parser/story-parser.d.ts +5 -0
- package/dist/parser/story-parser.d.ts.map +1 -0
- package/dist/parser/story-parser.js +41 -0
- package/dist/parser/story-parser.js.map +1 -0
- package/dist/prompt/prompt-generator.d.ts +3 -0
- package/dist/prompt/prompt-generator.d.ts.map +1 -0
- package/dist/prompt/prompt-generator.js +40 -0
- package/dist/prompt/prompt-generator.js.map +1 -0
- package/dist/scaffold/init.d.ts +3 -0
- package/dist/scaffold/init.d.ts.map +1 -0
- package/dist/scaffold/init.js +64 -0
- package/dist/scaffold/init.js.map +1 -0
- package/dist/scaffold/templates.d.ts +6 -0
- package/dist/scaffold/templates.d.ts.map +1 -0
- package/dist/scaffold/templates.js +164 -0
- package/dist/scaffold/templates.js.map +1 -0
- package/dist/sdd.d.ts +20 -0
- package/dist/sdd.d.ts.map +1 -0
- package/dist/sdd.js +110 -0
- package/dist/sdd.js.map +1 -0
- package/dist/types.d.ts +65 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/validate/validator.d.ts +3 -0
- package/dist/validate/validator.d.ts.map +1 -0
- package/dist/validate/validator.js +44 -0
- package/dist/validate/validator.js.map +1 -0
- package/package.json +18 -0
- package/src/config/config-manager.ts +39 -0
- package/src/delta/delta-engine.ts +18 -0
- package/src/errors.ts +27 -0
- package/src/git/git.ts +113 -0
- package/src/index.ts +19 -0
- package/src/parser/cr-parser.ts +41 -0
- package/src/parser/frontmatter.ts +24 -0
- package/src/parser/ref-extractor.ts +14 -0
- package/src/parser/section-extractor.ts +38 -0
- package/src/parser/story-parser.ts +40 -0
- package/src/prompt/prompt-generator.ts +49 -0
- package/src/scaffold/init.ts +71 -0
- package/src/scaffold/templates.ts +166 -0
- package/src/sdd.ts +123 -0
- package/src/types.ts +76 -0
- package/src/validate/validator.ts +46 -0
- package/tests/cr.test.ts +172 -0
- package/tests/delta.test.ts +94 -0
- package/tests/integration.test.ts +132 -0
- package/tests/parser.test.ts +92 -0
- package/tests/prompt.test.ts +57 -0
- package/tests/validator.test.ts +54 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.discoverStoryFiles = discoverStoryFiles;
|
|
4
|
+
exports.parseStoryFile = parseStoryFile;
|
|
5
|
+
exports.parseAllStoryFiles = parseAllStoryFiles;
|
|
6
|
+
const promises_1 = require("node:fs/promises");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const glob_1 = require("glob");
|
|
9
|
+
const node_crypto_1 = require("node:crypto");
|
|
10
|
+
const frontmatter_js_1 = require("./frontmatter.js");
|
|
11
|
+
const section_extractor_js_1 = require("./section-extractor.js");
|
|
12
|
+
const ref_extractor_js_1 = require("./ref-extractor.js");
|
|
13
|
+
async function discoverStoryFiles(root) {
|
|
14
|
+
const patterns = ['product/**/*.md', 'system/**/*.md'];
|
|
15
|
+
const files = [];
|
|
16
|
+
for (const pattern of patterns) {
|
|
17
|
+
const matches = await (0, glob_1.glob)(pattern, { cwd: root, absolute: true });
|
|
18
|
+
files.push(...matches);
|
|
19
|
+
}
|
|
20
|
+
return files.sort();
|
|
21
|
+
}
|
|
22
|
+
async function parseStoryFile(root, absolutePath) {
|
|
23
|
+
const content = await (0, promises_1.readFile)(absolutePath, 'utf-8');
|
|
24
|
+
const relPath = (0, node_path_1.relative)(root, absolutePath);
|
|
25
|
+
const { frontmatter, body } = (0, frontmatter_js_1.parseFrontmatter)(relPath, content);
|
|
26
|
+
const hash = (0, node_crypto_1.createHash)('sha256').update(content).digest('hex');
|
|
27
|
+
return {
|
|
28
|
+
relativePath: relPath,
|
|
29
|
+
frontmatter,
|
|
30
|
+
body,
|
|
31
|
+
pendingItems: (0, section_extractor_js_1.extractPendingItems)(body),
|
|
32
|
+
agentNotes: (0, section_extractor_js_1.extractAgentNotes)(body),
|
|
33
|
+
crossRefs: (0, ref_extractor_js_1.extractCrossRefs)(body),
|
|
34
|
+
hash,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async function parseAllStoryFiles(root) {
|
|
38
|
+
const paths = await discoverStoryFiles(root);
|
|
39
|
+
return Promise.all(paths.map((p) => parseStoryFile(root, p)));
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=story-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story-parser.js","sourceRoot":"","sources":["../../src/parser/story-parser.ts"],"names":[],"mappings":";;AASA,gDAQC;AAED,wCAeC;AAED,gDAGC;AAvCD,+CAA4C;AAC5C,yCAA8C;AAC9C,+BAA4B;AAC5B,6CAAyC;AAEzC,qDAAoD;AACpD,iEAAgF;AAChF,yDAAsD;AAE/C,KAAK,UAAU,kBAAkB,CAAC,IAAY;IACnD,MAAM,QAAQ,GAAG,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;IACvD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,MAAM,IAAA,WAAI,EAAC,OAAO,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACnE,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,IAAY,EAAE,YAAoB;IACrE,MAAM,OAAO,GAAG,MAAM,IAAA,mBAAQ,EAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,IAAA,oBAAQ,EAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC7C,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,IAAA,iCAAgB,EAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAEhE,OAAO;QACL,YAAY,EAAE,OAAO;QACrB,WAAW;QACX,IAAI;QACJ,YAAY,EAAE,IAAA,0CAAmB,EAAC,IAAI,CAAC;QACvC,UAAU,EAAE,IAAA,wCAAiB,EAAC,IAAI,CAAC;QACnC,SAAS,EAAE,IAAA,mCAAgB,EAAC,IAAI,CAAC;QACjC,IAAI;KACL,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,kBAAkB,CAAC,IAAY;IACnD,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-generator.d.ts","sourceRoot":"","sources":["../../src/prompt/prompt-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CA6CxE"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generatePrompt = generatePrompt;
|
|
4
|
+
const git_js_1 = require("../git/git.js");
|
|
5
|
+
function generatePrompt(files, root) {
|
|
6
|
+
const sections = [];
|
|
7
|
+
sections.push('# SDD Sync Prompt\n\nThis project uses Story Driven Development. Implement the changes described below.');
|
|
8
|
+
if (files.length === 0) {
|
|
9
|
+
sections.push('Nothing to do — all files are synced.');
|
|
10
|
+
return sections.join('\n\n');
|
|
11
|
+
}
|
|
12
|
+
const lines = [`## Files to process (${files.length})\n`];
|
|
13
|
+
for (const f of files) {
|
|
14
|
+
lines.push(`- \`${f.relativePath}\` — **${f.frontmatter.status}**`);
|
|
15
|
+
}
|
|
16
|
+
lines.push('');
|
|
17
|
+
lines.push('Read each file listed above before implementing.');
|
|
18
|
+
sections.push(lines.join('\n'));
|
|
19
|
+
// Show git diff for changed files so the agent knows what was modified
|
|
20
|
+
if (root) {
|
|
21
|
+
const changed = files.filter((f) => f.frontmatter.status === 'changed');
|
|
22
|
+
for (const f of changed) {
|
|
23
|
+
const diff = (0, git_js_1.getFileDiff)(root, f.relativePath);
|
|
24
|
+
if (diff) {
|
|
25
|
+
sections.push(`## Changes in \`${f.relativePath}\`\n\n\`\`\`diff\n${diff}\n\`\`\``);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const deleted = files.filter((f) => f.frontmatter.status === 'deleted');
|
|
30
|
+
if (deleted.length > 0) {
|
|
31
|
+
const delLines = ['## Files to remove\n'];
|
|
32
|
+
for (const f of deleted) {
|
|
33
|
+
delLines.push(`- \`${f.relativePath}\` — remove all related code in \`code/\``);
|
|
34
|
+
}
|
|
35
|
+
sections.push(delLines.join('\n'));
|
|
36
|
+
}
|
|
37
|
+
sections.push(`## Instructions\n\n1. Read each file listed above\n2. For **new** files: implement what the documentation describes\n3. For **changed** files: update the code to match the updated documentation (see diff above)\n4. For **deleted** files: remove the related code from \`code/\`\n5. If a file has a \`## Agent Notes\` section, respect those constraints\n6. All code goes inside \`code/\`\n7. After implementing each file, run \`sdd mark-synced <file>\`\n8. **Immediately after mark-synced, commit**: \`git add -A && git commit -m "sdd sync: <description>"\`\n9. When done with all files, list every file you created or modified`);
|
|
38
|
+
return sections.join('\n\n');
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=prompt-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-generator.js","sourceRoot":"","sources":["../../src/prompt/prompt-generator.ts"],"names":[],"mappings":";;AAGA,wCA6CC;AA/CD,0CAA4C;AAE5C,SAAgB,cAAc,CAAC,KAAkB,EAAE,IAAa;IAC9D,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,QAAQ,CAAC,IAAI,CACX,yGAAyG,CAC1G,CAAC;IAEF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,QAAQ,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;QACvD,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,wBAAwB,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;IAC1D,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,YAAY,UAAU,CAAC,CAAC,WAAW,CAAC,MAAM,IAAI,CAAC,CAAC;IACtE,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;IAC/D,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAEhC,uEAAuE;IACvE,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QACxE,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,IAAA,oBAAW,EAAC,IAAI,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC;YAC/C,IAAI,IAAI,EAAE,CAAC;gBACT,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,YAAY,qBAAqB,IAAI,UAAU,CAAC,CAAC;YACtF,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;IACxE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,CAAC,sBAAsB,CAAC,CAAC;QAC1C,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,YAAY,2CAA2C,CAAC,CAAC;QAClF,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,CAAC;IAED,QAAQ,CAAC,IAAI,CACX,mnBAAmnB,CACpnB,CAAC;IAEF,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/scaffold/init.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAKrE,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA8DrF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initProject = initProject;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const templates_js_1 = require("./templates.js");
|
|
8
|
+
const config_manager_js_1 = require("../config/config-manager.js");
|
|
9
|
+
const git_js_1 = require("../git/git.js");
|
|
10
|
+
async function initProject(root, info) {
|
|
11
|
+
const createdFiles = [];
|
|
12
|
+
const sddDir = (0, config_manager_js_1.sddDirPath)(root);
|
|
13
|
+
// Ensure git repo
|
|
14
|
+
if (!(0, git_js_1.isGitRepo)(root)) {
|
|
15
|
+
(0, git_js_1.gitInit)(root);
|
|
16
|
+
createdFiles.push('.git');
|
|
17
|
+
}
|
|
18
|
+
// Create .sdd directory
|
|
19
|
+
if (!(0, node_fs_1.existsSync)(sddDir)) {
|
|
20
|
+
await (0, promises_1.mkdir)(sddDir, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
// Write config
|
|
23
|
+
const config = {
|
|
24
|
+
description: info?.description ?? '',
|
|
25
|
+
};
|
|
26
|
+
await (0, config_manager_js_1.writeConfig)(root, config);
|
|
27
|
+
createdFiles.push('.sdd/config.yaml');
|
|
28
|
+
// Create directory structure
|
|
29
|
+
const dirs = ['product', 'product/features', 'system', 'code', 'change-requests'];
|
|
30
|
+
for (const dir of dirs) {
|
|
31
|
+
const absDir = (0, node_path_1.resolve)(root, dir);
|
|
32
|
+
if (!(0, node_fs_1.existsSync)(absDir)) {
|
|
33
|
+
await (0, promises_1.mkdir)(absDir, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Create agent instructions
|
|
37
|
+
const instructionsPath = (0, node_path_1.resolve)(root, 'INSTRUCTIONS.md');
|
|
38
|
+
if (!(0, node_fs_1.existsSync)(instructionsPath)) {
|
|
39
|
+
await (0, promises_1.writeFile)(instructionsPath, templates_js_1.AGENT_MD_TEMPLATE, 'utf-8');
|
|
40
|
+
createdFiles.push('INSTRUCTIONS.md');
|
|
41
|
+
}
|
|
42
|
+
// Create agent instruction pointers
|
|
43
|
+
const POINTER = 'Read INSTRUCTIONS.md in the project root for all instructions.\n';
|
|
44
|
+
const agentFiles = [
|
|
45
|
+
{ path: '.claude/CLAUDE.md', dir: '.claude' },
|
|
46
|
+
{ path: '.github/copilot-instructions.md', dir: '.github' },
|
|
47
|
+
{ path: '.cursorrules' },
|
|
48
|
+
];
|
|
49
|
+
for (const entry of agentFiles) {
|
|
50
|
+
const absPath = (0, node_path_1.resolve)(root, entry.path);
|
|
51
|
+
if ((0, node_fs_1.existsSync)(absPath))
|
|
52
|
+
continue;
|
|
53
|
+
if (entry.dir) {
|
|
54
|
+
const absDir = (0, node_path_1.resolve)(root, entry.dir);
|
|
55
|
+
if (!(0, node_fs_1.existsSync)(absDir)) {
|
|
56
|
+
await (0, promises_1.mkdir)(absDir, { recursive: true });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
await (0, promises_1.writeFile)(absPath, POINTER, 'utf-8');
|
|
60
|
+
createdFiles.push(entry.path);
|
|
61
|
+
}
|
|
62
|
+
return createdFiles;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/scaffold/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface ProjectInfo {
|
|
2
|
+
description: string;
|
|
3
|
+
}
|
|
4
|
+
export declare const AGENT_MD_TEMPLATE = "# SDD Project\n\nThis project uses **Story Driven Development (SDD)**.\nDocumentation drives implementation: read the docs first, then write code.\n\n## Workflow\n\n1. Run `sdd cr pending` \u2014 check if there are change requests to process first\n2. If there are pending CRs, apply them to the docs, then run `sdd mark-cr-applied`\n3. Run `sdd sync` to see what needs to be implemented\n4. Read the documentation files listed in the sync output\n5. Implement what each file describes, writing code inside `code/`\n6. After implementing, mark files as synced:\n\n```\nsdd mark-synced product/features/auth.md\n```\n\nOr mark all pending files at once:\n\n```\nsdd mark-synced\n```\n\n7. **Commit immediately after mark-synced** \u2014 this is mandatory:\n\n```\ngit add -A && git commit -m \"sdd sync: <brief description of what was implemented>\"\n```\n\nDo NOT skip this step. Every mark-synced must be followed by a git commit.\n\n### Removing a feature\n\nIf a documentation file has `status: deleted`, it means that feature should be removed.\nDelete the related code in `code/`, then run `sdd mark-synced <file>` (the doc file will be removed automatically), then commit.\n\n## Available commands\n\n- `sdd status` \u2014 See all documentation files and their state (new/changed/deleted/synced)\n- `sdd diff` \u2014 See what changed since last sync\n- `sdd sync` \u2014 Get the sync prompt for pending files (new/changed/deleted)\n- `sdd validate` \u2014 Check for broken references and issues\n- `sdd mark-synced [files...]` \u2014 Mark specific files (or all) as synced\n- `sdd cr list` \u2014 List all change requests with their status\n- `sdd cr pending` \u2014 Show draft change requests to process\n- `sdd mark-cr-applied [files...]` \u2014 Mark change requests as applied\n\n## Rules\n\n1. **Always commit after mark-synced** \u2014 run `git add -A && git commit -m \"sdd sync: ...\"` immediately after `sdd mark-synced`. Never leave synced files uncommitted.\n2. Before running `sdd sync`, check for pending change requests with `sdd cr pending`\n3. If there are pending CRs, apply them to the docs first, then mark them with `sdd mark-cr-applied`\n4. Only implement what the sync prompt asks for\n5. All generated code goes inside `code/`\n6. Respect all constraints in `## Agent Notes` sections (if present)\n7. Do not edit files inside `.sdd/` manually\n\n## File format\n\nEvery `.md` file in `product/` and `system/` must start with this YAML frontmatter:\n\n```yaml\n---\ntitle: \"File title\"\nstatus: new\nauthor: \"\"\nlast-modified: \"2025-01-01T00:00:00.000Z\"\nversion: \"1.0\"\n---\n```\n\n- **status**: one of:\n - `new` \u2014 new file, needs to be implemented\n - `changed` \u2014 modified since last sync, code needs updating\n - `deleted` \u2014 feature to be removed, agent should delete related code\n - `synced` \u2014 already implemented, up to date\n- **version**: patch-bump on each edit (1.0 \u2192 1.1 \u2192 1.2)\n- **last-modified**: ISO 8601 datetime, updated on each edit\n\n## Change Requests\n\nChange Requests (CRs) are markdown files in `change-requests/` that describe modifications to the documentation.\n\n### CR format\n\n```yaml\n---\ntitle: \"Add authentication feature\"\nstatus: draft\nauthor: \"user\"\ncreated-at: \"2025-01-01T00:00:00.000Z\"\n---\n```\n\n- **status**: `draft` (pending) or `applied` (already processed)\n\n### CR workflow\n\n1. Check for pending CRs: `sdd cr pending`\n2. Read each pending CR and apply the described changes to the documentation files (marking them as `new`, `changed`, or `deleted`)\n3. After applying a CR to the docs, mark it: `sdd mark-cr-applied change-requests/CR-001.md`\n4. Then run `sdd sync` to implement the code changes\n\n### CR commands\n\n- `sdd cr list` \u2014 See all change requests and their status\n- `sdd cr pending` \u2014 Show only draft CRs to process\n- `sdd mark-cr-applied [files...]` \u2014 Mark CRs as applied after updating the docs\n\n## UX and screenshots\n\nWhen a feature has UX mockups or screenshots, place them next to the feature doc:\n\n- **Simple feature** (no screenshots): `product/features/auth.md`\n- **Feature with screenshots**: use a folder with `index.md`:\n\n```\nproduct/features/auth/\n index.md \u2190 feature doc\n login.png \u2190 screenshot\n register.png \u2190 screenshot\n```\n\nReference images in the markdown with relative paths:\n\n```markdown\n## UX\n\n\n\n```\n\nBoth formats work \u2014 use a folder only when you have screenshots or multiple files for a feature.\n\n## Project structure\n\n- `product/` \u2014 What to build (vision, users, features)\n- `system/` \u2014 How to build it (entities, architecture, tech stack, interfaces)\n- `code/` \u2014 All generated source code goes here\n- `change-requests/` \u2014 Change requests to the documentation\n- `.sdd/` \u2014 Project config and sync state (do not edit)\n";
|
|
5
|
+
export declare const EMPTY_LOCK_TEMPLATE: () => string;
|
|
6
|
+
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/scaffold/templates.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,iBAAiB,02JA8I7B,CAAC;AAEF,eAAO,MAAM,mBAAmB,cAE/B,CAAC"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EMPTY_LOCK_TEMPLATE = exports.AGENT_MD_TEMPLATE = void 0;
|
|
4
|
+
const now = () => new Date().toISOString();
|
|
5
|
+
function mdTemplate(title, content) {
|
|
6
|
+
return `---
|
|
7
|
+
title: "${title}"
|
|
8
|
+
status: new
|
|
9
|
+
author: ""
|
|
10
|
+
last-modified: "${now()}"
|
|
11
|
+
version: "1.0"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
${content}
|
|
15
|
+
`;
|
|
16
|
+
}
|
|
17
|
+
exports.AGENT_MD_TEMPLATE = `# SDD Project
|
|
18
|
+
|
|
19
|
+
This project uses **Story Driven Development (SDD)**.
|
|
20
|
+
Documentation drives implementation: read the docs first, then write code.
|
|
21
|
+
|
|
22
|
+
## Workflow
|
|
23
|
+
|
|
24
|
+
1. Run \`sdd cr pending\` — check if there are change requests to process first
|
|
25
|
+
2. If there are pending CRs, apply them to the docs, then run \`sdd mark-cr-applied\`
|
|
26
|
+
3. Run \`sdd sync\` to see what needs to be implemented
|
|
27
|
+
4. Read the documentation files listed in the sync output
|
|
28
|
+
5. Implement what each file describes, writing code inside \`code/\`
|
|
29
|
+
6. After implementing, mark files as synced:
|
|
30
|
+
|
|
31
|
+
\`\`\`
|
|
32
|
+
sdd mark-synced product/features/auth.md
|
|
33
|
+
\`\`\`
|
|
34
|
+
|
|
35
|
+
Or mark all pending files at once:
|
|
36
|
+
|
|
37
|
+
\`\`\`
|
|
38
|
+
sdd mark-synced
|
|
39
|
+
\`\`\`
|
|
40
|
+
|
|
41
|
+
7. **Commit immediately after mark-synced** — this is mandatory:
|
|
42
|
+
|
|
43
|
+
\`\`\`
|
|
44
|
+
git add -A && git commit -m "sdd sync: <brief description of what was implemented>"
|
|
45
|
+
\`\`\`
|
|
46
|
+
|
|
47
|
+
Do NOT skip this step. Every mark-synced must be followed by a git commit.
|
|
48
|
+
|
|
49
|
+
### Removing a feature
|
|
50
|
+
|
|
51
|
+
If a documentation file has \`status: deleted\`, it means that feature should be removed.
|
|
52
|
+
Delete the related code in \`code/\`, then run \`sdd mark-synced <file>\` (the doc file will be removed automatically), then commit.
|
|
53
|
+
|
|
54
|
+
## Available commands
|
|
55
|
+
|
|
56
|
+
- \`sdd status\` — See all documentation files and their state (new/changed/deleted/synced)
|
|
57
|
+
- \`sdd diff\` — See what changed since last sync
|
|
58
|
+
- \`sdd sync\` — Get the sync prompt for pending files (new/changed/deleted)
|
|
59
|
+
- \`sdd validate\` — Check for broken references and issues
|
|
60
|
+
- \`sdd mark-synced [files...]\` — Mark specific files (or all) as synced
|
|
61
|
+
- \`sdd cr list\` — List all change requests with their status
|
|
62
|
+
- \`sdd cr pending\` — Show draft change requests to process
|
|
63
|
+
- \`sdd mark-cr-applied [files...]\` — Mark change requests as applied
|
|
64
|
+
|
|
65
|
+
## Rules
|
|
66
|
+
|
|
67
|
+
1. **Always commit after mark-synced** — run \`git add -A && git commit -m "sdd sync: ..."\` immediately after \`sdd mark-synced\`. Never leave synced files uncommitted.
|
|
68
|
+
2. Before running \`sdd sync\`, check for pending change requests with \`sdd cr pending\`
|
|
69
|
+
3. If there are pending CRs, apply them to the docs first, then mark them with \`sdd mark-cr-applied\`
|
|
70
|
+
4. Only implement what the sync prompt asks for
|
|
71
|
+
5. All generated code goes inside \`code/\`
|
|
72
|
+
6. Respect all constraints in \`## Agent Notes\` sections (if present)
|
|
73
|
+
7. Do not edit files inside \`.sdd/\` manually
|
|
74
|
+
|
|
75
|
+
## File format
|
|
76
|
+
|
|
77
|
+
Every \`.md\` file in \`product/\` and \`system/\` must start with this YAML frontmatter:
|
|
78
|
+
|
|
79
|
+
\`\`\`yaml
|
|
80
|
+
---
|
|
81
|
+
title: "File title"
|
|
82
|
+
status: new
|
|
83
|
+
author: ""
|
|
84
|
+
last-modified: "2025-01-01T00:00:00.000Z"
|
|
85
|
+
version: "1.0"
|
|
86
|
+
---
|
|
87
|
+
\`\`\`
|
|
88
|
+
|
|
89
|
+
- **status**: one of:
|
|
90
|
+
- \`new\` — new file, needs to be implemented
|
|
91
|
+
- \`changed\` — modified since last sync, code needs updating
|
|
92
|
+
- \`deleted\` — feature to be removed, agent should delete related code
|
|
93
|
+
- \`synced\` — already implemented, up to date
|
|
94
|
+
- **version**: patch-bump on each edit (1.0 → 1.1 → 1.2)
|
|
95
|
+
- **last-modified**: ISO 8601 datetime, updated on each edit
|
|
96
|
+
|
|
97
|
+
## Change Requests
|
|
98
|
+
|
|
99
|
+
Change Requests (CRs) are markdown files in \`change-requests/\` that describe modifications to the documentation.
|
|
100
|
+
|
|
101
|
+
### CR format
|
|
102
|
+
|
|
103
|
+
\`\`\`yaml
|
|
104
|
+
---
|
|
105
|
+
title: "Add authentication feature"
|
|
106
|
+
status: draft
|
|
107
|
+
author: "user"
|
|
108
|
+
created-at: "2025-01-01T00:00:00.000Z"
|
|
109
|
+
---
|
|
110
|
+
\`\`\`
|
|
111
|
+
|
|
112
|
+
- **status**: \`draft\` (pending) or \`applied\` (already processed)
|
|
113
|
+
|
|
114
|
+
### CR workflow
|
|
115
|
+
|
|
116
|
+
1. Check for pending CRs: \`sdd cr pending\`
|
|
117
|
+
2. Read each pending CR and apply the described changes to the documentation files (marking them as \`new\`, \`changed\`, or \`deleted\`)
|
|
118
|
+
3. After applying a CR to the docs, mark it: \`sdd mark-cr-applied change-requests/CR-001.md\`
|
|
119
|
+
4. Then run \`sdd sync\` to implement the code changes
|
|
120
|
+
|
|
121
|
+
### CR commands
|
|
122
|
+
|
|
123
|
+
- \`sdd cr list\` — See all change requests and their status
|
|
124
|
+
- \`sdd cr pending\` — Show only draft CRs to process
|
|
125
|
+
- \`sdd mark-cr-applied [files...]\` — Mark CRs as applied after updating the docs
|
|
126
|
+
|
|
127
|
+
## UX and screenshots
|
|
128
|
+
|
|
129
|
+
When a feature has UX mockups or screenshots, place them next to the feature doc:
|
|
130
|
+
|
|
131
|
+
- **Simple feature** (no screenshots): \`product/features/auth.md\`
|
|
132
|
+
- **Feature with screenshots**: use a folder with \`index.md\`:
|
|
133
|
+
|
|
134
|
+
\`\`\`
|
|
135
|
+
product/features/auth/
|
|
136
|
+
index.md ← feature doc
|
|
137
|
+
login.png ← screenshot
|
|
138
|
+
register.png ← screenshot
|
|
139
|
+
\`\`\`
|
|
140
|
+
|
|
141
|
+
Reference images in the markdown with relative paths:
|
|
142
|
+
|
|
143
|
+
\`\`\`markdown
|
|
144
|
+
## UX
|
|
145
|
+
|
|
146
|
+

|
|
147
|
+

|
|
148
|
+
\`\`\`
|
|
149
|
+
|
|
150
|
+
Both formats work — use a folder only when you have screenshots or multiple files for a feature.
|
|
151
|
+
|
|
152
|
+
## Project structure
|
|
153
|
+
|
|
154
|
+
- \`product/\` — What to build (vision, users, features)
|
|
155
|
+
- \`system/\` — How to build it (entities, architecture, tech stack, interfaces)
|
|
156
|
+
- \`code/\` — All generated source code goes here
|
|
157
|
+
- \`change-requests/\` — Change requests to the documentation
|
|
158
|
+
- \`.sdd/\` — Project config and sync state (do not edit)
|
|
159
|
+
`;
|
|
160
|
+
const EMPTY_LOCK_TEMPLATE = () => `synced-at: "${new Date().toISOString()}"
|
|
161
|
+
files: {}
|
|
162
|
+
`;
|
|
163
|
+
exports.EMPTY_LOCK_TEMPLATE = EMPTY_LOCK_TEMPLATE;
|
|
164
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/scaffold/templates.ts"],"names":[],"mappings":";;;AAAA,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAE3C,SAAS,UAAU,CAAC,KAAa,EAAE,OAAe;IAChD,OAAO;UACC,KAAK;;;kBAGG,GAAG,EAAE;;;;EAIrB,OAAO;CACR,CAAC;AACF,CAAC;AAMY,QAAA,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8IhC,CAAC;AAEK,MAAM,mBAAmB,GAAG,GAAG,EAAE,CAAC,eAAe,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;;CAE/E,CAAC;AAFW,QAAA,mBAAmB,uBAE9B"}
|
package/dist/sdd.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { StoryStatus, ValidationResult, SDDConfig, ChangeRequest } from './types.js';
|
|
2
|
+
import type { ProjectInfo } from './scaffold/templates.js';
|
|
3
|
+
export declare class SDD {
|
|
4
|
+
private root;
|
|
5
|
+
constructor(options: {
|
|
6
|
+
root: string;
|
|
7
|
+
});
|
|
8
|
+
init(info?: ProjectInfo): Promise<string[]>;
|
|
9
|
+
config(): Promise<SDDConfig>;
|
|
10
|
+
status(): Promise<StoryStatus>;
|
|
11
|
+
pending(): Promise<import('./types.js').StoryFile[]>;
|
|
12
|
+
sync(): Promise<string>;
|
|
13
|
+
validate(): Promise<ValidationResult>;
|
|
14
|
+
markSynced(paths?: string[]): Promise<string[]>;
|
|
15
|
+
changeRequests(): Promise<ChangeRequest[]>;
|
|
16
|
+
pendingChangeRequests(): Promise<ChangeRequest[]>;
|
|
17
|
+
markCRApplied(paths?: string[]): Promise<string[]>;
|
|
18
|
+
private ensureInitialized;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=sdd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdd.d.ts","sourceRoot":"","sources":["../src/sdd.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAQ1F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,qBAAa,GAAG;IACd,OAAO,CAAC,IAAI,CAAS;gBAET,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAI/B,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAI3C,MAAM,IAAI,OAAO,CAAC,SAAS,CAAC;IAK5B,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC;IAc9B,OAAO,IAAI,OAAO,CAAC,OAAO,YAAY,EAAE,SAAS,EAAE,CAAC;IAMpD,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAKvB,QAAQ,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAMrC,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IA6B/C,cAAc,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAK1C,qBAAqB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAKjD,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAmBxD,OAAO,CAAC,iBAAiB;CAK1B"}
|
package/dist/sdd.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SDD = void 0;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const errors_js_1 = require("./errors.js");
|
|
7
|
+
const story_parser_js_1 = require("./parser/story-parser.js");
|
|
8
|
+
const prompt_generator_js_1 = require("./prompt/prompt-generator.js");
|
|
9
|
+
const validator_js_1 = require("./validate/validator.js");
|
|
10
|
+
const init_js_1 = require("./scaffold/init.js");
|
|
11
|
+
const config_manager_js_1 = require("./config/config-manager.js");
|
|
12
|
+
const cr_parser_js_1 = require("./parser/cr-parser.js");
|
|
13
|
+
class SDD {
|
|
14
|
+
root;
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.root = options.root;
|
|
17
|
+
}
|
|
18
|
+
async init(info) {
|
|
19
|
+
return (0, init_js_1.initProject)(this.root, info);
|
|
20
|
+
}
|
|
21
|
+
async config() {
|
|
22
|
+
this.ensureInitialized();
|
|
23
|
+
return (0, config_manager_js_1.readConfig)(this.root);
|
|
24
|
+
}
|
|
25
|
+
async status() {
|
|
26
|
+
this.ensureInitialized();
|
|
27
|
+
const files = await (0, story_parser_js_1.parseAllStoryFiles)(this.root);
|
|
28
|
+
return {
|
|
29
|
+
files: files.map((f) => ({
|
|
30
|
+
relativePath: f.relativePath,
|
|
31
|
+
status: f.frontmatter.status,
|
|
32
|
+
version: f.frontmatter.version,
|
|
33
|
+
lastModified: f.frontmatter['last-modified'],
|
|
34
|
+
})),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async pending() {
|
|
38
|
+
this.ensureInitialized();
|
|
39
|
+
const files = await (0, story_parser_js_1.parseAllStoryFiles)(this.root);
|
|
40
|
+
return files.filter((f) => f.frontmatter.status !== 'synced');
|
|
41
|
+
}
|
|
42
|
+
async sync() {
|
|
43
|
+
const pending = await this.pending();
|
|
44
|
+
return (0, prompt_generator_js_1.generatePrompt)(pending, this.root);
|
|
45
|
+
}
|
|
46
|
+
async validate() {
|
|
47
|
+
this.ensureInitialized();
|
|
48
|
+
const files = await (0, story_parser_js_1.parseAllStoryFiles)(this.root);
|
|
49
|
+
return (0, validator_js_1.validate)(files);
|
|
50
|
+
}
|
|
51
|
+
async markSynced(paths) {
|
|
52
|
+
this.ensureInitialized();
|
|
53
|
+
const files = await (0, story_parser_js_1.parseAllStoryFiles)(this.root);
|
|
54
|
+
const marked = [];
|
|
55
|
+
for (const file of files) {
|
|
56
|
+
const { status } = file.frontmatter;
|
|
57
|
+
if (status === 'synced')
|
|
58
|
+
continue;
|
|
59
|
+
if (paths && paths.length > 0 && !paths.includes(file.relativePath))
|
|
60
|
+
continue;
|
|
61
|
+
const absPath = (0, node_path_1.resolve)(this.root, file.relativePath);
|
|
62
|
+
if (status === 'deleted') {
|
|
63
|
+
// File marked for deletion — remove it
|
|
64
|
+
const { unlink } = await import('node:fs/promises');
|
|
65
|
+
await unlink(absPath);
|
|
66
|
+
marked.push(`${file.relativePath} (removed)`);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// new or changed → synced
|
|
70
|
+
const content = await (0, promises_1.readFile)(absPath, 'utf-8');
|
|
71
|
+
const updated = content.replace(/^status:\s*(new|changed)/m, 'status: synced');
|
|
72
|
+
await (0, promises_1.writeFile)(absPath, updated, 'utf-8');
|
|
73
|
+
marked.push(file.relativePath);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return marked;
|
|
77
|
+
}
|
|
78
|
+
async changeRequests() {
|
|
79
|
+
this.ensureInitialized();
|
|
80
|
+
return (0, cr_parser_js_1.parseAllCRFiles)(this.root);
|
|
81
|
+
}
|
|
82
|
+
async pendingChangeRequests() {
|
|
83
|
+
const all = await this.changeRequests();
|
|
84
|
+
return all.filter((cr) => cr.frontmatter.status === 'draft');
|
|
85
|
+
}
|
|
86
|
+
async markCRApplied(paths) {
|
|
87
|
+
this.ensureInitialized();
|
|
88
|
+
const all = await this.changeRequests();
|
|
89
|
+
const marked = [];
|
|
90
|
+
for (const cr of all) {
|
|
91
|
+
if (cr.frontmatter.status === 'applied')
|
|
92
|
+
continue;
|
|
93
|
+
if (paths && paths.length > 0 && !paths.includes(cr.relativePath))
|
|
94
|
+
continue;
|
|
95
|
+
const absPath = (0, node_path_1.resolve)(this.root, cr.relativePath);
|
|
96
|
+
const content = await (0, promises_1.readFile)(absPath, 'utf-8');
|
|
97
|
+
const updated = content.replace(/^status:\s*draft/m, 'status: applied');
|
|
98
|
+
await (0, promises_1.writeFile)(absPath, updated, 'utf-8');
|
|
99
|
+
marked.push(cr.relativePath);
|
|
100
|
+
}
|
|
101
|
+
return marked;
|
|
102
|
+
}
|
|
103
|
+
ensureInitialized() {
|
|
104
|
+
if (!(0, config_manager_js_1.isSDDProject)(this.root)) {
|
|
105
|
+
throw new errors_js_1.ProjectNotInitializedError(this.root);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.SDD = SDD;
|
|
110
|
+
//# sourceMappingURL=sdd.js.map
|
package/dist/sdd.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdd.js","sourceRoot":"","sources":["../src/sdd.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export type StoryFileStatus = 'new' | 'changed' | 'deleted' | 'synced';
|
|
2
|
+
export interface StoryFrontmatter {
|
|
3
|
+
title: string;
|
|
4
|
+
status: StoryFileStatus;
|
|
5
|
+
author: string;
|
|
6
|
+
'last-modified': string;
|
|
7
|
+
version: string;
|
|
8
|
+
}
|
|
9
|
+
export interface StoryFile {
|
|
10
|
+
relativePath: string;
|
|
11
|
+
frontmatter: StoryFrontmatter;
|
|
12
|
+
body: string;
|
|
13
|
+
pendingItems: PendingItem[];
|
|
14
|
+
agentNotes: string | null;
|
|
15
|
+
crossRefs: string[];
|
|
16
|
+
hash: string;
|
|
17
|
+
}
|
|
18
|
+
export interface PendingItem {
|
|
19
|
+
text: string;
|
|
20
|
+
checked: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface Delta {
|
|
23
|
+
hasChanges: boolean;
|
|
24
|
+
files: DeltaFile[];
|
|
25
|
+
diff: string;
|
|
26
|
+
}
|
|
27
|
+
export interface DeltaFile {
|
|
28
|
+
relativePath: string;
|
|
29
|
+
status: 'modified' | 'new' | 'deleted';
|
|
30
|
+
}
|
|
31
|
+
export interface ValidationResult {
|
|
32
|
+
valid: boolean;
|
|
33
|
+
issues: ValidationIssue[];
|
|
34
|
+
}
|
|
35
|
+
export interface ValidationIssue {
|
|
36
|
+
severity: 'error' | 'warning';
|
|
37
|
+
filePath: string;
|
|
38
|
+
message: string;
|
|
39
|
+
rule: string;
|
|
40
|
+
}
|
|
41
|
+
export interface StoryStatus {
|
|
42
|
+
files: Array<{
|
|
43
|
+
relativePath: string;
|
|
44
|
+
status: 'new' | 'changed' | 'deleted' | 'synced';
|
|
45
|
+
version: string;
|
|
46
|
+
lastModified: string;
|
|
47
|
+
}>;
|
|
48
|
+
}
|
|
49
|
+
export interface SDDConfig {
|
|
50
|
+
description: string;
|
|
51
|
+
'last-sync-commit'?: string;
|
|
52
|
+
}
|
|
53
|
+
export type ChangeRequestStatus = 'draft' | 'applied';
|
|
54
|
+
export interface ChangeRequestFrontmatter {
|
|
55
|
+
title: string;
|
|
56
|
+
status: ChangeRequestStatus;
|
|
57
|
+
author: string;
|
|
58
|
+
'created-at': string;
|
|
59
|
+
}
|
|
60
|
+
export interface ChangeRequest {
|
|
61
|
+
relativePath: string;
|
|
62
|
+
frontmatter: ChangeRequestFrontmatter;
|
|
63
|
+
body: string;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEvE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,gBAAgB,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,KAAK;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,UAAU,GAAG,KAAK,GAAG,SAAS,CAAC;CACxC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,KAAK,CAAC;QACX,YAAY,EAAE,MAAM,CAAC;QACrB,MAAM,EAAE,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;QACjD,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,SAAS,CAAC;AAEtD,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,mBAAmB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,wBAAwB,CAAC;IACtC,IAAI,EAAE,MAAM,CAAC;CACd"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/validate/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAmB,MAAM,aAAa,CAAC;AAEhF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,gBAAgB,CA2C7D"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validate = validate;
|
|
4
|
+
function validate(files) {
|
|
5
|
+
const issues = [];
|
|
6
|
+
// Collect known entity names from system/entities.md
|
|
7
|
+
const entityNames = new Set();
|
|
8
|
+
const entitiesFile = files.find((f) => f.relativePath.endsWith('entities.md'));
|
|
9
|
+
if (entitiesFile) {
|
|
10
|
+
// Extract ### headings as entity names
|
|
11
|
+
const headingRe = /^### (.+)$/gm;
|
|
12
|
+
let match;
|
|
13
|
+
while ((match = headingRe.exec(entitiesFile.body)) !== null) {
|
|
14
|
+
entityNames.add(match[1].trim());
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
for (const file of files) {
|
|
18
|
+
// Check broken cross-references
|
|
19
|
+
for (const ref of file.crossRefs) {
|
|
20
|
+
if (entityNames.size > 0 && !entityNames.has(ref)) {
|
|
21
|
+
issues.push({
|
|
22
|
+
severity: 'warning',
|
|
23
|
+
filePath: file.relativePath,
|
|
24
|
+
message: `Broken reference [[${ref}]] — not found in system/entities.md`,
|
|
25
|
+
rule: 'broken-ref',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Check frontmatter has required fields
|
|
30
|
+
if (!file.frontmatter.title) {
|
|
31
|
+
issues.push({
|
|
32
|
+
severity: 'warning',
|
|
33
|
+
filePath: file.relativePath,
|
|
34
|
+
message: 'Missing "title" in frontmatter',
|
|
35
|
+
rule: 'missing-frontmatter',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
valid: issues.filter((i) => i.severity === 'error').length === 0,
|
|
41
|
+
issues,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=validator.js.map
|