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,111 +1,111 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
- const { execSync } = require("child_process");
4
-
5
- const projectRoot = process.cwd();
6
- const routerPath = path.join(projectRoot, ".sdrive", "commands", "router.js");
7
-
8
- function runRouter(command, feature) {
9
- try {
10
- const args = feature ? ` ${feature}` : "";
11
- execSync(`node "${routerPath}" ${command}${args}`, { stdio: "pipe" });
12
- return true;
13
- } catch (error) {
14
- return false;
15
- }
16
- }
17
-
18
- function testKnownCommand() {
19
- console.log("\n🧪 Test 1: Known command should pass");
20
-
21
- const passed = runRouter("/sdrive:constitution");
22
-
23
- if (passed) {
24
- console.log("āœ… PASS: Router accepted /sdrive:constitution.");
25
- return true;
26
- }
27
-
28
- console.log("āŒ FAIL: Router rejected /sdrive:constitution.");
29
- return false;
30
- }
31
-
32
- function testUnknownCommand() {
33
- console.log("\n🧪 Test 2: Unknown command should fail");
34
-
35
- const passed = runRouter("/sdrive:unknown");
36
-
37
- if (!passed) {
38
- console.log("āœ… PASS: Router rejected unknown command.");
39
- return true;
40
- }
41
-
42
- console.log("āŒ FAIL: Router accepted unknown command.");
43
- return false;
44
- }
45
-
46
- function testMissingFeatureForGatedCommand() {
47
- console.log("\n🧪 Test 3: Gated command without feature should fail");
48
-
49
- const passed = runRouter("/sdrive:propose");
50
-
51
- if (!passed) {
52
- console.log("āœ… PASS: Router blocked gated command without feature.");
53
- return true;
54
- }
55
-
56
- console.log("āŒ FAIL: Router allowed gated command without feature.");
57
- return false;
58
- }
59
-
60
- function testFeatureConversion() {
61
- console.log("\n🧪 Test 4: Natural feature description should convert to kebab-case");
62
-
63
- try {
64
- const output = execSync(
65
- `node "${routerPath}" /sdrive:propose "User login with email"`,
66
- { stdio: "pipe", encoding: "utf8" }
67
- );
68
-
69
- if (output.includes("user-login-with-email")) {
70
- console.log("āœ… PASS: Feature converted to kebab-case.");
71
- return true;
72
- }
73
-
74
- console.log("āŒ FAIL: Feature not converted correctly.");
75
- return false;
76
- } catch (error) {
77
- if (error.stdout && error.stdout.includes("user-login-with-email")) {
78
- console.log("āœ… PASS: Feature converted to kebab-case.");
79
- return true;
80
- }
81
-
82
- if (error.stdout && error.stdout.includes("user-login-with-email")) {
83
- console.log("āœ… PASS: Feature converted to kebab-case.");
84
- return true;
85
- }
86
-
87
- console.log("āŒ FAIL: Feature not converted correctly.");
88
- return false;
89
- }
90
- }
91
-
92
- function main() {
93
- console.log("=== SpecDrive Router Tests ===\n");
94
-
95
- let allPassed = true;
96
-
97
- allPassed &= testKnownCommand();
98
- allPassed &= testUnknownCommand();
99
- allPassed &= testMissingFeatureForGatedCommand();
100
- allPassed &= testFeatureConversion();
101
-
102
- if (allPassed) {
103
- console.log("\nāœ… All router tests passed.");
104
- process.exit(0);
105
- } else {
106
- console.log("\nāŒ Some router tests failed.");
107
- process.exit(1);
108
- }
109
- }
110
-
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { execSync } = require("child_process");
4
+
5
+ const projectRoot = process.cwd();
6
+ const routerPath = path.join(projectRoot, ".sdrive", "commands", "router.js");
7
+
8
+ function runRouter(command, feature) {
9
+ try {
10
+ const args = feature ? ` ${feature}` : "";
11
+ execSync(`node "${routerPath}" ${command}${args}`, { stdio: "pipe" });
12
+ return true;
13
+ } catch (error) {
14
+ return false;
15
+ }
16
+ }
17
+
18
+ function testKnownCommand() {
19
+ console.log("\n🧪 Test 1: Known command should pass");
20
+
21
+ const passed = runRouter("/sdrive:constitution");
22
+
23
+ if (passed) {
24
+ console.log("āœ… PASS: Router accepted /sdrive:constitution.");
25
+ return true;
26
+ }
27
+
28
+ console.log("āŒ FAIL: Router rejected /sdrive:constitution.");
29
+ return false;
30
+ }
31
+
32
+ function testUnknownCommand() {
33
+ console.log("\n🧪 Test 2: Unknown command should fail");
34
+
35
+ const passed = runRouter("/sdrive:unknown");
36
+
37
+ if (!passed) {
38
+ console.log("āœ… PASS: Router rejected unknown command.");
39
+ return true;
40
+ }
41
+
42
+ console.log("āŒ FAIL: Router accepted unknown command.");
43
+ return false;
44
+ }
45
+
46
+ function testMissingFeatureForGatedCommand() {
47
+ console.log("\n🧪 Test 3: Gated command without feature should fail");
48
+
49
+ const passed = runRouter("/sdrive:propose");
50
+
51
+ if (!passed) {
52
+ console.log("āœ… PASS: Router blocked gated command without feature.");
53
+ return true;
54
+ }
55
+
56
+ console.log("āŒ FAIL: Router allowed gated command without feature.");
57
+ return false;
58
+ }
59
+
60
+ function testFeatureConversion() {
61
+ console.log("\n🧪 Test 4: Natural feature description should convert to kebab-case");
62
+
63
+ try {
64
+ const output = execSync(
65
+ `node "${routerPath}" /sdrive:propose "User login with email"`,
66
+ { stdio: "pipe", encoding: "utf8" }
67
+ );
68
+
69
+ if (output.includes("user-login-with-email")) {
70
+ console.log("āœ… PASS: Feature converted to kebab-case.");
71
+ return true;
72
+ }
73
+
74
+ console.log("āŒ FAIL: Feature not converted correctly.");
75
+ return false;
76
+ } catch (error) {
77
+ if (error.stdout && error.stdout.includes("user-login-with-email")) {
78
+ console.log("āœ… PASS: Feature converted to kebab-case.");
79
+ return true;
80
+ }
81
+
82
+ if (error.stdout && error.stdout.includes("user-login-with-email")) {
83
+ console.log("āœ… PASS: Feature converted to kebab-case.");
84
+ return true;
85
+ }
86
+
87
+ console.log("āŒ FAIL: Feature not converted correctly.");
88
+ return false;
89
+ }
90
+ }
91
+
92
+ function main() {
93
+ console.log("=== SpecDrive Router Tests ===\n");
94
+
95
+ let allPassed = true;
96
+
97
+ allPassed &= testKnownCommand();
98
+ allPassed &= testUnknownCommand();
99
+ allPassed &= testMissingFeatureForGatedCommand();
100
+ allPassed &= testFeatureConversion();
101
+
102
+ if (allPassed) {
103
+ console.log("\nāœ… All router tests passed.");
104
+ process.exit(0);
105
+ } else {
106
+ console.log("\nāŒ Some router tests failed.");
107
+ process.exit(1);
108
+ }
109
+ }
110
+
111
111
  main();
@@ -1,147 +1,147 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
- const { execSync } = require("child_process");
4
-
5
- const projectRoot = process.cwd();
6
- const workflowStatePath = path.join(projectRoot, ".sdrive", "workflow-state.json");
7
-
8
- function resetState() {
9
- const initialState = {
10
- features: [
11
- {
12
- name: "test-feature",
13
- phase: "backlog",
14
- currentStep: "specification",
15
- gates: {
16
- specification: "pending",
17
- planning: "pending",
18
- implementation: "pending",
19
- review: "pending"
20
- },
21
- history: [
22
- {
23
- event: "feature_created",
24
- timestamp: new Date().toISOString()
25
- }
26
- ]
27
- }
28
- ]
29
- };
30
-
31
- fs.writeFileSync(workflowStatePath, JSON.stringify(initialState, null, 2));
32
- }
33
-
34
- function readState() {
35
- return JSON.parse(fs.readFileSync(workflowStatePath, "utf8"));
36
- }
37
-
38
- function approveGate(gate) {
39
- try {
40
- execSync(`node ${path.join(projectRoot, ".sdrive", "src", "index.js")} approve ${gate}`, {
41
- stdio: "pipe"
42
- });
43
- return true;
44
- } catch (error) {
45
- return false;
46
- }
47
- }
48
-
49
- function testInitialState() {
50
- console.log("\n🧪 Test 1: Initial state should be pending");
51
- resetState();
52
- const state = readState();
53
- const feature = state.features[0];
54
-
55
- if (
56
- feature.gates.specification === "pending" &&
57
- feature.gates.planning === "pending" &&
58
- feature.gates.implementation === "pending" &&
59
- feature.gates.review === "pending"
60
- ) {
61
- console.log("āœ… PASS: All gates are pending initially.");
62
- return true;
63
- }
64
-
65
- console.log("āŒ FAIL: Initial gates are not pending.");
66
- return false;
67
- }
68
-
69
- function testGateApproval() {
70
- console.log("\n🧪 Test 2: Gate approval should update state");
71
- resetState();
72
-
73
- const passed = approveGate("specification");
74
-
75
- if (!passed) {
76
- console.log("āŒ FAIL: Could not approve gate.");
77
- return false;
78
- }
79
-
80
- const state = readState();
81
- const feature = state.features[0];
82
-
83
- if (feature.gates.specification === "approved") {
84
- console.log("āœ… PASS: specification gate approved.");
85
- return true;
86
- }
87
-
88
- console.log("āŒ FAIL: specification gate not approved.");
89
- return false;
90
- }
91
-
92
- function testInvalidGate() {
93
- console.log("\n🧪 Test 3: Invalid gate should be rejected");
94
- resetState();
95
-
96
- try {
97
- execSync(`node ${path.join(projectRoot, ".sdrive", "src", "index.js")} approve invalid-gate`, {
98
- stdio: "pipe"
99
- });
100
- console.log("āŒ FAIL: Invalid gate was accepted.");
101
- return false;
102
- } catch (error) {
103
- console.log("āœ… PASS: Invalid gate was rejected.");
104
- return true;
105
- }
106
- }
107
-
108
- function testHistory() {
109
- console.log("\n🧪 Test 4: History should record approvals");
110
- resetState();
111
-
112
- approveGate("specification");
113
-
114
- const state = readState();
115
- const feature = state.features[0];
116
-
117
- if (feature.history.some((event) => event.event === "specification_approved")) {
118
- console.log("āœ… PASS: History recorded approval.");
119
- return true;
120
- }
121
-
122
- console.log("āŒ FAIL: History did not record approval.");
123
- return false;
124
- }
125
-
126
- function main() {
127
- console.log("=== SpecDrive State Transition Tests ===\n");
128
-
129
- let allPassed = true;
130
-
131
- allPassed &= testInitialState();
132
- allPassed &= testGateApproval();
133
- allPassed &= testInvalidGate();
134
- allPassed &= testHistory();
135
-
136
- resetState();
137
-
138
- if (allPassed) {
139
- console.log("\nāœ… All state transition tests passed.");
140
- process.exit(0);
141
- } else {
142
- console.log("\nāŒ Some state transition tests failed.");
143
- process.exit(1);
144
- }
145
- }
146
-
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { execSync } = require("child_process");
4
+
5
+ const projectRoot = process.cwd();
6
+ const workflowStatePath = path.join(projectRoot, ".sdrive", "workflow-state.json");
7
+
8
+ function resetState() {
9
+ const initialState = {
10
+ features: [
11
+ {
12
+ name: "test-feature",
13
+ phase: "backlog",
14
+ currentStep: "specification",
15
+ gates: {
16
+ specification: "pending",
17
+ planning: "pending",
18
+ implementation: "pending",
19
+ review: "pending"
20
+ },
21
+ history: [
22
+ {
23
+ event: "feature_created",
24
+ timestamp: new Date().toISOString()
25
+ }
26
+ ]
27
+ }
28
+ ]
29
+ };
30
+
31
+ fs.writeFileSync(workflowStatePath, JSON.stringify(initialState, null, 2));
32
+ }
33
+
34
+ function readState() {
35
+ return JSON.parse(fs.readFileSync(workflowStatePath, "utf8"));
36
+ }
37
+
38
+ function approveGate(gate) {
39
+ try {
40
+ execSync(`node ${path.join(projectRoot, ".sdrive", "src", "index.js")} approve ${gate}`, {
41
+ stdio: "pipe"
42
+ });
43
+ return true;
44
+ } catch (error) {
45
+ return false;
46
+ }
47
+ }
48
+
49
+ function testInitialState() {
50
+ console.log("\n🧪 Test 1: Initial state should be pending");
51
+ resetState();
52
+ const state = readState();
53
+ const feature = state.features[0];
54
+
55
+ if (
56
+ feature.gates.specification === "pending" &&
57
+ feature.gates.planning === "pending" &&
58
+ feature.gates.implementation === "pending" &&
59
+ feature.gates.review === "pending"
60
+ ) {
61
+ console.log("āœ… PASS: All gates are pending initially.");
62
+ return true;
63
+ }
64
+
65
+ console.log("āŒ FAIL: Initial gates are not pending.");
66
+ return false;
67
+ }
68
+
69
+ function testGateApproval() {
70
+ console.log("\n🧪 Test 2: Gate approval should update state");
71
+ resetState();
72
+
73
+ const passed = approveGate("specification");
74
+
75
+ if (!passed) {
76
+ console.log("āŒ FAIL: Could not approve gate.");
77
+ return false;
78
+ }
79
+
80
+ const state = readState();
81
+ const feature = state.features[0];
82
+
83
+ if (feature.gates.specification === "approved") {
84
+ console.log("āœ… PASS: specification gate approved.");
85
+ return true;
86
+ }
87
+
88
+ console.log("āŒ FAIL: specification gate not approved.");
89
+ return false;
90
+ }
91
+
92
+ function testInvalidGate() {
93
+ console.log("\n🧪 Test 3: Invalid gate should be rejected");
94
+ resetState();
95
+
96
+ try {
97
+ execSync(`node ${path.join(projectRoot, ".sdrive", "src", "index.js")} approve invalid-gate`, {
98
+ stdio: "pipe"
99
+ });
100
+ console.log("āŒ FAIL: Invalid gate was accepted.");
101
+ return false;
102
+ } catch (error) {
103
+ console.log("āœ… PASS: Invalid gate was rejected.");
104
+ return true;
105
+ }
106
+ }
107
+
108
+ function testHistory() {
109
+ console.log("\n🧪 Test 4: History should record approvals");
110
+ resetState();
111
+
112
+ approveGate("specification");
113
+
114
+ const state = readState();
115
+ const feature = state.features[0];
116
+
117
+ if (feature.history.some((event) => event.event === "specification_approved")) {
118
+ console.log("āœ… PASS: History recorded approval.");
119
+ return true;
120
+ }
121
+
122
+ console.log("āŒ FAIL: History did not record approval.");
123
+ return false;
124
+ }
125
+
126
+ function main() {
127
+ console.log("=== SpecDrive State Transition Tests ===\n");
128
+
129
+ let allPassed = true;
130
+
131
+ allPassed &= testInitialState();
132
+ allPassed &= testGateApproval();
133
+ allPassed &= testInvalidGate();
134
+ allPassed &= testHistory();
135
+
136
+ resetState();
137
+
138
+ if (allPassed) {
139
+ console.log("\nāœ… All state transition tests passed.");
140
+ process.exit(0);
141
+ } else {
142
+ console.log("\nāŒ Some state transition tests failed.");
143
+ process.exit(1);
144
+ }
145
+ }
146
+
147
147
  main();