specdrive-cli 0.1.9 → 0.1.12

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.
Files changed (74) hide show
  1. package/README.md +955 -506
  2. package/agents/00-onboarding.md +261 -0
  3. package/agents/01-constitution.md +214 -201
  4. package/agents/02-specification.md +249 -226
  5. package/agents/03-uiux.md +156 -144
  6. package/agents/04-cascade.md +151 -122
  7. package/agents/05-discover-skills.md +136 -136
  8. package/agents/06-documentation.md +158 -145
  9. package/agents/07-implementation.md +201 -169
  10. package/agents/08-performance.md +179 -165
  11. package/agents/09-review-complete.md +239 -168
  12. package/agents/10-security.md +180 -167
  13. package/agents/11-test.md +195 -0
  14. package/commands/gates.js +73 -73
  15. package/commands/manifest.json +113 -95
  16. package/commands/permissions.json +39 -0
  17. package/commands/router.js +151 -127
  18. package/commands/tools.json +19 -19
  19. package/dashboard/app.js +394 -0
  20. package/dashboard/index.html +74 -0
  21. package/dashboard/server.js +166 -0
  22. package/dashboard/style.css +157 -0
  23. package/mcp/mcp.json +31 -0
  24. package/mcp/server.js +108 -0
  25. package/package.json +35 -32
  26. package/schemas/config.schema.json +20 -0
  27. package/schemas/workflow-state.schema.json +152 -35
  28. package/scripts/anti-redundancy.js +176 -176
  29. package/scripts/audit-log.js +46 -46
  30. package/scripts/check-permission.js +87 -0
  31. package/scripts/diff-spec.js +51 -0
  32. package/scripts/diff-version.js +96 -0
  33. package/scripts/generate-adapters.js +80 -80
  34. package/scripts/generate-from-template.js +97 -70
  35. package/scripts/generate-openapi.js +76 -0
  36. package/scripts/github-team-sync.js +81 -0
  37. package/scripts/install-hooks.js +21 -0
  38. package/scripts/load-plugins.js +65 -65
  39. package/scripts/migrate-openspec.js +318 -0
  40. package/scripts/migrate-speckit.js +322 -0
  41. package/scripts/migrate.js +12 -0
  42. package/scripts/onboard.js +312 -0
  43. package/scripts/pre-commit.js +56 -20
  44. package/scripts/team.js +113 -113
  45. package/scripts/test-adapters.js +118 -118
  46. package/scripts/test-create.js +13 -13
  47. package/scripts/test-end-to-end.js +137 -137
  48. package/scripts/test-router.js +110 -110
  49. package/scripts/test-state-transitions.js +146 -146
  50. package/scripts/test-validator.js +152 -152
  51. package/scripts/validate-config.js +36 -0
  52. package/scripts/validate-governance.js +150 -130
  53. package/scripts/verify.js +525 -0
  54. package/scripts/version-new.js +202 -0
  55. package/src/index.js +1010 -400
  56. package/templates/expo/plan.json +12 -0
  57. package/templates/expo/spec.json +12 -0
  58. package/templates/expo/tasks.json +5 -0
  59. package/templates/fastapi/plan.json +12 -0
  60. package/templates/fastapi/spec.json +12 -0
  61. package/templates/fastapi/tasks.json +5 -0
  62. package/templates/generic/plan.json +12 -0
  63. package/templates/generic/spec.json +11 -0
  64. package/templates/generic/tasks.json +5 -0
  65. package/templates/nextjs/plan.json +23 -0
  66. package/templates/nextjs/spec.json +12 -0
  67. package/templates/nextjs/tasks.json +5 -0
  68. package/templates/react-node/plan.json +15 -0
  69. package/templates/react-node/spec.json +12 -0
  70. package/templates/react-node/tasks.json +5 -0
  71. package/templates/registry.json +30 -0
  72. package/templates/turborepo/plan.json +12 -0
  73. package/templates/turborepo/spec.json +12 -0
  74. package/templates/turborepo/tasks.json +5 -0
@@ -1,153 +1,153 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
- const { execSync } = require("child_process");
4
-
5
- const projectRoot = process.cwd();
6
- const govDir = path.join(projectRoot, ".sdrive", "governance", "test-feature");
7
- const validatorPath = path.join(projectRoot, ".sdrive", "scripts", "validate-governance.js");
8
-
9
- function createValidFiles() {
10
- fs.mkdirSync(govDir, { recursive: true });
11
-
12
- fs.writeFileSync(
13
- path.join(govDir, "spec.json"),
14
- JSON.stringify(
15
- {
16
- feature: "test-feature",
17
- title: "Test Feature",
18
- version: 1,
19
- overview: {
20
- problemStatement: "Test problem statement",
21
- proposedSolution: "Test proposed solution",
22
- targetAudience: "Test users"
23
- },
24
- userStories: [
25
- {
26
- id: "US-001",
27
- title: "Test story",
28
- role: "user",
29
- want: "test",
30
- benefit: "test",
31
- acceptanceCriteria: [
32
- {
33
- id: "AC-001",
34
- text: "Given test, when test, then test"
35
- }
36
- ]
37
- }
38
- ],
39
- functionalRequirements: [
40
- {
41
- id: "FR-001",
42
- text: "The system MUST test"
43
- }
44
- ]
45
- },
46
- null,
47
- 2
48
- )
49
- );
50
-
51
- fs.writeFileSync(
52
- path.join(govDir, "traceability.json"),
53
- JSON.stringify(
54
- {
55
- feature: "test-feature",
56
- version: 1,
57
- rows: [
58
- {
59
- requirementId: "FR-001",
60
- acceptanceCriteriaIds: ["AC-001"],
61
- taskIds: ["T1.1"],
62
- status: "not_started"
63
- }
64
- ]
65
- },
66
- null,
67
- 2
68
- )
69
- );
70
- }
71
-
72
- function createInvalidFiles() {
73
- fs.writeFileSync(
74
- path.join(govDir, "spec.json"),
75
- JSON.stringify(
76
- {
77
- feature: "test-feature",
78
- version: 1,
79
- overview: {},
80
- userStories: []
81
- },
82
- null,
83
- 2
84
- )
85
- );
86
- }
87
-
88
- function runValidator() {
89
- try {
90
- execSync(`node "${validatorPath}"`, { stdio: "pipe" });
91
- return true;
92
- } catch (error) {
93
- return false;
94
- }
95
- }
96
-
97
- function testValidFiles() {
98
- console.log("\n🧪 Test 1: Valid governance files should pass");
99
- createValidFiles();
100
-
101
- const passed = runValidator();
102
-
103
- if (passed) {
104
- console.log("✅ PASS: Validator accepted valid files.");
105
- } else {
106
- console.log("❌ FAIL: Validator rejected valid files.");
107
- }
108
-
109
- return passed;
110
- }
111
-
112
- function testInvalidFiles() {
113
- console.log("\n🧪 Test 2: Invalid governance files should fail");
114
- createInvalidFiles();
115
-
116
- const passed = runValidator();
117
-
118
- if (!passed) {
119
- console.log("✅ PASS: Validator rejected invalid files.");
120
- } else {
121
- console.log("❌ FAIL: Validator accepted invalid files.");
122
- }
123
-
124
- return !passed;
125
- }
126
-
127
- function cleanup() {
128
- if (fs.existsSync(govDir)) {
129
- fs.rmSync(govDir, { recursive: true, force: true });
130
- }
131
- console.log("\n🧹 Cleaned up test files.");
132
- }
133
-
134
- function main() {
135
- console.log("=== SpecDrive Validator Tests ===\n");
136
-
137
- let allPassed = true;
138
-
139
- allPassed &= testValidFiles();
140
- allPassed &= testInvalidFiles();
141
-
142
- cleanup();
143
-
144
- if (allPassed) {
145
- console.log("\n✅ All validator tests passed.");
146
- process.exit(0);
147
- } else {
148
- console.log("\n❌ Some validator tests failed.");
149
- process.exit(1);
150
- }
151
- }
152
-
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { execSync } = require("child_process");
4
+
5
+ const projectRoot = process.cwd();
6
+ const govDir = path.join(projectRoot, ".sdrive", "governance", "test-feature");
7
+ const validatorPath = path.join(projectRoot, ".sdrive", "scripts", "validate-governance.js");
8
+
9
+ function createValidFiles() {
10
+ fs.mkdirSync(govDir, { recursive: true });
11
+
12
+ fs.writeFileSync(
13
+ path.join(govDir, "spec.json"),
14
+ JSON.stringify(
15
+ {
16
+ feature: "test-feature",
17
+ title: "Test Feature",
18
+ version: 1,
19
+ overview: {
20
+ problemStatement: "Test problem statement",
21
+ proposedSolution: "Test proposed solution",
22
+ targetAudience: "Test users"
23
+ },
24
+ userStories: [
25
+ {
26
+ id: "US-001",
27
+ title: "Test story",
28
+ role: "user",
29
+ want: "test",
30
+ benefit: "test",
31
+ acceptanceCriteria: [
32
+ {
33
+ id: "AC-001",
34
+ text: "Given test, when test, then test"
35
+ }
36
+ ]
37
+ }
38
+ ],
39
+ functionalRequirements: [
40
+ {
41
+ id: "FR-001",
42
+ text: "The system MUST test"
43
+ }
44
+ ]
45
+ },
46
+ null,
47
+ 2
48
+ )
49
+ );
50
+
51
+ fs.writeFileSync(
52
+ path.join(govDir, "traceability.json"),
53
+ JSON.stringify(
54
+ {
55
+ feature: "test-feature",
56
+ version: 1,
57
+ rows: [
58
+ {
59
+ requirementId: "FR-001",
60
+ acceptanceCriteriaIds: ["AC-001"],
61
+ taskIds: ["T1.1"],
62
+ status: "not_started"
63
+ }
64
+ ]
65
+ },
66
+ null,
67
+ 2
68
+ )
69
+ );
70
+ }
71
+
72
+ function createInvalidFiles() {
73
+ fs.writeFileSync(
74
+ path.join(govDir, "spec.json"),
75
+ JSON.stringify(
76
+ {
77
+ feature: "test-feature",
78
+ version: 1,
79
+ overview: {},
80
+ userStories: []
81
+ },
82
+ null,
83
+ 2
84
+ )
85
+ );
86
+ }
87
+
88
+ function runValidator() {
89
+ try {
90
+ execSync(`node "${validatorPath}"`, { stdio: "pipe" });
91
+ return true;
92
+ } catch (error) {
93
+ return false;
94
+ }
95
+ }
96
+
97
+ function testValidFiles() {
98
+ console.log("\n🧪 Test 1: Valid governance files should pass");
99
+ createValidFiles();
100
+
101
+ const passed = runValidator();
102
+
103
+ if (passed) {
104
+ console.log("✅ PASS: Validator accepted valid files.");
105
+ } else {
106
+ console.log("❌ FAIL: Validator rejected valid files.");
107
+ }
108
+
109
+ return passed;
110
+ }
111
+
112
+ function testInvalidFiles() {
113
+ console.log("\n🧪 Test 2: Invalid governance files should fail");
114
+ createInvalidFiles();
115
+
116
+ const passed = runValidator();
117
+
118
+ if (!passed) {
119
+ console.log("✅ PASS: Validator rejected invalid files.");
120
+ } else {
121
+ console.log("❌ FAIL: Validator accepted invalid files.");
122
+ }
123
+
124
+ return !passed;
125
+ }
126
+
127
+ function cleanup() {
128
+ if (fs.existsSync(govDir)) {
129
+ fs.rmSync(govDir, { recursive: true, force: true });
130
+ }
131
+ console.log("\n🧹 Cleaned up test files.");
132
+ }
133
+
134
+ function main() {
135
+ console.log("=== SpecDrive Validator Tests ===\n");
136
+
137
+ let allPassed = true;
138
+
139
+ allPassed &= testValidFiles();
140
+ allPassed &= testInvalidFiles();
141
+
142
+ cleanup();
143
+
144
+ if (allPassed) {
145
+ console.log("\n✅ All validator tests passed.");
146
+ process.exit(0);
147
+ } else {
148
+ console.log("\n❌ Some validator tests failed.");
149
+ process.exit(1);
150
+ }
151
+ }
152
+
153
153
  main();
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+
3
+ const Ajv = require("ajv");
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+
7
+ const projectRoot = process.cwd();
8
+
9
+ const configPath = path.join(projectRoot, ".sdrive", "config.json");
10
+ const schemaPath = path.join(projectRoot, ".sdrive", "schemas", "config.schema.json");
11
+
12
+ if (!fs.existsSync(configPath)) {
13
+ console.error("❌ config.json not found. Run `sdrive init` first.");
14
+ process.exit(1);
15
+ }
16
+
17
+ if (!fs.existsSync(schemaPath)) {
18
+ console.error("❌ config.schema.json not found.");
19
+ process.exit(1);
20
+ }
21
+
22
+ const ajv = new Ajv({ allErrors: true });
23
+ const schema = JSON.parse(fs.readFileSync(schemaPath, "utf8"));
24
+ const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
25
+
26
+ const validate = ajv.compile(schema);
27
+ const valid = validate(config);
28
+
29
+ if (valid) {
30
+ console.log("✅ config.json is valid.");
31
+ process.exit(0);
32
+ } else {
33
+ console.error("❌ config.json is INVALID:");
34
+ console.error(validate.errors);
35
+ process.exit(1);
36
+ }
@@ -1,131 +1,151 @@
1
- const Ajv = require("ajv");
2
- const fs = require("fs");
3
- const path = require("path");
4
-
5
- const ajv = new Ajv({ allErrors: true });
6
-
7
- const projectRoot = path.join(__dirname, "..", "..");
8
-
9
- const schemaDir = path.join(projectRoot, ".sdrive", "schemas");
10
- const governanceDir = path.join(projectRoot, ".sdrive", "governance");
11
- const specsDir = path.join(projectRoot, ".sdrive", "specs");
12
- const workflowStatePath = path.join(projectRoot, ".sdrive", "workflow-state.json");
13
-
14
- function loadJson(filePath) {
15
- if (!fs.existsSync(filePath)) {
16
- console.error(`❌ Schema/file not found: ${filePath}`);
17
- process.exit(1);
18
- }
19
- return JSON.parse(fs.readFileSync(filePath, "utf8"));
20
- }
21
-
22
- function validateData(data, schema, label) {
23
- const validate = ajv.compile(schema);
24
- const valid = validate(data);
25
-
26
- if (valid) {
27
- console.log(`✅ ${label} is valid.`);
28
- return true;
29
- } else {
30
- console.log(`❌ ${label} is INVALID:`);
31
- console.log(validate.errors);
32
- return false;
33
- }
34
- }
35
-
36
- function validateWorkflowState() {
37
- if (!fs.existsSync(workflowStatePath)) {
38
- console.log("⚠️ workflow-state.json not found. Skipping.");
39
- return true;
40
- }
41
-
42
- const schema = loadJson(path.join(schemaDir, "workflow-state.schema.json"));
43
- const data = loadJson(workflowStatePath);
44
- return validateData(data, schema, "workflow-state.json");
45
- }
46
-
47
- function validateFeature(featureName) {
48
- const featureDir = path.join(governanceDir, featureName);
49
-
50
- if (!fs.existsSync(featureDir)) {
51
- console.log(`⚠️ Feature "${featureName}" has no governance folder. Skipping.`);
52
- return true;
53
- }
54
-
55
- let failed = false;
56
-
57
- const files = [
58
- { file: "spec.json", schema: "spec.schema.json" },
59
- { file: "plan.json", schema: "plan.schema.json" },
60
- { file: "tasks.json", schema: "tasks.schema.json" },
61
- { file: "traceability.json", schema: "traceability.schema.json" }
62
- ];
63
-
64
- files.forEach(({ file, schema }) => {
65
- const filePath = path.join(featureDir, file);
66
- const schemaPath = path.join(schemaDir, schema);
67
-
68
- if (!fs.existsSync(filePath)) {
69
- console.log(`⚠️ ${featureName}/${file} not found. Skipping.`);
70
- return;
71
- }
72
-
73
- const data = loadJson(filePath);
74
- const schemaData = loadJson(schemaPath);
75
- failed |= !validateData(data, schemaData, `${featureName}/${file}`);
76
- });
77
-
78
- return !failed;
79
- }
80
-
81
- function discoverFeatures() {
82
- const features = new Set();
83
-
84
- if (fs.existsSync(governanceDir)) {
85
- fs.readdirSync(governanceDir, { withFileTypes: true })
86
- .filter((d) => d.isDirectory())
87
- .forEach((d) => features.add(d.name));
88
- }
89
-
90
- ["backlog", "ongoing", "completed"].forEach((lifecycle) => {
91
- const lifecyclePath = path.join(specsDir, lifecycle);
92
- if (fs.existsSync(lifecyclePath)) {
93
- fs.readdirSync(lifecyclePath, { withFileTypes: true })
94
- .filter((d) => d.isDirectory())
95
- .forEach((d) => features.add(d.name));
96
- }
97
- });
98
-
99
- return Array.from(features);
100
- }
101
-
102
- function main() {
103
- console.log("🔍 SpecDrive Governance Validation\n");
104
-
105
- let failed = false;
106
-
107
- failed |= !validateWorkflowState();
108
-
109
- const features = discoverFeatures();
110
-
111
- if (features.length === 0) {
112
- console.log("⚠️ No features found under .sdrive/governance or .sdrive/specs.");
113
- }
114
-
115
- features.forEach((feature) => {
116
- console.log(`\n📁 Validating feature: ${feature}`);
117
- failed |= !validateFeature(feature);
118
- });
119
-
120
- console.log("\n----------------------------------------");
121
-
122
- if (failed) {
123
- console.log("❌ Validation FAILED. Fix the errors above.");
124
- process.exit(1);
125
- } else {
126
- console.log("✅ Governance validation complete. All files are valid.");
127
- process.exit(0);
128
- }
129
- }
130
-
1
+ const Ajv = require("ajv");
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+
5
+ const ajv = new Ajv({ allErrors: true });
6
+
7
+ const projectRoot = path.join(__dirname, "..", "..");
8
+
9
+ const schemaDir = path.join(projectRoot, ".sdrive", "schemas");
10
+ const governanceDir = path.join(projectRoot, ".sdrive", "governance");
11
+ const specsDir = path.join(projectRoot, ".sdrive", "specs");
12
+ const workflowStatePath = path.join(projectRoot, ".sdrive", "workflow-state.json");
13
+
14
+ const configPath = path.join(projectRoot, ".sdrive", "config.json");
15
+ const configSchemaPath = path.join(schemaDir, "config.schema.json");
16
+
17
+ function loadJson(filePath) {
18
+ if (!fs.existsSync(filePath)) {
19
+ console.error(`❌ Schema/file not found: ${filePath}`);
20
+ process.exit(1);
21
+ }
22
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
23
+ }
24
+
25
+ function validateData(data, schema, label) {
26
+ const validate = ajv.compile(schema);
27
+ const valid = validate(data);
28
+
29
+ if (valid) {
30
+ console.log(`✅ ${label} is valid.`);
31
+ return true;
32
+ } else {
33
+ console.log(`❌ ${label} is INVALID:`);
34
+ console.log(validate.errors);
35
+ return false;
36
+ }
37
+ }
38
+
39
+ function validateConfig() {
40
+ if (!fs.existsSync(configPath)) {
41
+ console.log("⚠️ config.json not found. Skipping.");
42
+ return true;
43
+ }
44
+
45
+ if (!fs.existsSync(configSchemaPath)) {
46
+ console.log("⚠️ config.schema.json not found. Skipping config validation.");
47
+ return true;
48
+ }
49
+
50
+ const schema = loadJson(configSchemaPath);
51
+ const data = loadJson(configPath);
52
+ return validateData(data, schema, "config.json");
53
+ }
54
+
55
+ function validateWorkflowState() {
56
+ if (!fs.existsSync(workflowStatePath)) {
57
+ console.log("⚠️ workflow-state.json not found. Skipping.");
58
+ return true;
59
+ }
60
+
61
+ const schema = loadJson(path.join(schemaDir, "workflow-state.schema.json"));
62
+ const data = loadJson(workflowStatePath);
63
+ return validateData(data, schema, "workflow-state.json");
64
+ }
65
+
66
+ function validateFeature(featureName) {
67
+ const featureDir = path.join(governanceDir, featureName);
68
+
69
+ if (!fs.existsSync(featureDir)) {
70
+ console.log(`⚠️ Feature "${featureName}" has no governance folder. Skipping.`);
71
+ return true;
72
+ }
73
+
74
+ let failed = false;
75
+
76
+ const files = [
77
+ { file: "spec.json", schema: "spec.schema.json" },
78
+ { file: "plan.json", schema: "plan.schema.json" },
79
+ { file: "tasks.json", schema: "tasks.schema.json" },
80
+ { file: "traceability.json", schema: "traceability.schema.json" }
81
+ ];
82
+
83
+ files.forEach(({ file, schema }) => {
84
+ const filePath = path.join(featureDir, file);
85
+ const schemaPath = path.join(schemaDir, schema);
86
+
87
+ if (!fs.existsSync(filePath)) {
88
+ console.log(`⚠️ ${featureName}/${file} not found. Skipping.`);
89
+ return;
90
+ }
91
+
92
+ const data = loadJson(filePath);
93
+ const schemaData = loadJson(schemaPath);
94
+ failed |= !validateData(data, schemaData, `${featureName}/${file}`);
95
+ });
96
+
97
+ return !failed;
98
+ }
99
+
100
+ function discoverFeatures() {
101
+ const features = new Set();
102
+
103
+ if (fs.existsSync(governanceDir)) {
104
+ fs.readdirSync(governanceDir, { withFileTypes: true })
105
+ .filter((d) => d.isDirectory())
106
+ .forEach((d) => features.add(d.name));
107
+ }
108
+
109
+ ["backlog", "ongoing", "completed"].forEach((lifecycle) => {
110
+ const lifecyclePath = path.join(specsDir, lifecycle);
111
+ if (fs.existsSync(lifecyclePath)) {
112
+ fs.readdirSync(lifecyclePath, { withFileTypes: true })
113
+ .filter((d) => d.isDirectory())
114
+ .forEach((d) => features.add(d.name));
115
+ }
116
+ });
117
+
118
+ return Array.from(features);
119
+ }
120
+
121
+ function main() {
122
+ console.log("🔍 SpecDrive Governance Validation\n");
123
+
124
+ let failed = false;
125
+
126
+ failed |= !validateConfig();
127
+ failed |= !validateWorkflowState();
128
+
129
+ const features = discoverFeatures();
130
+
131
+ if (features.length === 0) {
132
+ console.log("⚠️ No features found under .sdrive/governance or .sdrive/specs.");
133
+ }
134
+
135
+ features.forEach((feature) => {
136
+ console.log(`\n📁 Validating feature: ${feature}`);
137
+ failed |= !validateFeature(feature);
138
+ });
139
+
140
+ console.log("\n----------------------------------------");
141
+
142
+ if (failed) {
143
+ console.log("❌ Validation FAILED. Fix the errors above.");
144
+ process.exit(1);
145
+ } else {
146
+ console.log("✅ Governance validation complete. All files are valid.");
147
+ process.exit(0);
148
+ }
149
+ }
150
+
131
151
  main();