specdrive-cli 0.1.10 โ 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.
- package/README.md +955 -697
- package/agents/00-onboarding.md +261 -0
- package/agents/01-constitution.md +214 -201
- package/agents/02-specification.md +249 -226
- package/agents/03-uiux.md +156 -144
- package/agents/04-cascade.md +151 -122
- package/agents/05-discover-skills.md +136 -136
- package/agents/06-documentation.md +158 -145
- package/agents/07-implementation.md +201 -169
- package/agents/08-performance.md +179 -165
- package/agents/09-review-complete.md +239 -168
- package/agents/10-security.md +180 -167
- package/agents/11-test.md +195 -0
- package/commands/gates.js +73 -73
- package/commands/manifest.json +113 -95
- package/commands/permissions.json +39 -0
- package/commands/router.js +151 -127
- package/commands/tools.json +19 -19
- package/dashboard/app.js +394 -0
- package/dashboard/index.html +74 -0
- package/dashboard/server.js +166 -0
- package/dashboard/style.css +157 -0
- package/mcp/mcp.json +31 -0
- package/mcp/server.js +108 -0
- package/package.json +35 -32
- package/schemas/config.schema.json +20 -0
- package/schemas/workflow-state.schema.json +149 -38
- package/scripts/anti-redundancy.js +176 -176
- package/scripts/audit-log.js +46 -46
- package/scripts/check-permission.js +87 -0
- package/scripts/diff-spec.js +50 -50
- package/scripts/diff-version.js +96 -0
- package/scripts/generate-adapters.js +80 -80
- package/scripts/generate-from-template.js +97 -97
- package/scripts/generate-openapi.js +75 -75
- package/scripts/github-team-sync.js +80 -80
- package/scripts/install-hooks.js +20 -20
- package/scripts/load-plugins.js +65 -65
- package/scripts/migrate-openspec.js +318 -0
- package/scripts/migrate-speckit.js +322 -0
- package/scripts/migrate.js +12 -62
- package/scripts/onboard.js +312 -0
- package/scripts/pre-commit.js +56 -20
- package/scripts/team.js +113 -113
- package/scripts/test-adapters.js +118 -118
- package/scripts/test-create.js +13 -13
- package/scripts/test-end-to-end.js +137 -137
- package/scripts/test-router.js +110 -110
- package/scripts/test-state-transitions.js +146 -146
- package/scripts/test-validator.js +152 -152
- package/scripts/validate-config.js +36 -0
- package/scripts/validate-governance.js +150 -130
- package/scripts/verify.js +525 -0
- package/scripts/version-new.js +202 -0
- package/src/index.js +1010 -807
- package/templates/expo/plan.json +12 -0
- package/templates/expo/spec.json +12 -0
- package/templates/expo/tasks.json +5 -0
- package/templates/fastapi/plan.json +12 -0
- package/templates/fastapi/spec.json +12 -0
- package/templates/fastapi/tasks.json +5 -0
- package/templates/generic/plan.json +12 -0
- package/templates/generic/spec.json +11 -0
- package/templates/generic/tasks.json +5 -0
- package/templates/nextjs/plan.json +23 -0
- package/templates/nextjs/spec.json +12 -0
- package/templates/nextjs/tasks.json +5 -0
- package/templates/react-node/plan.json +15 -0
- package/templates/react-node/spec.json +12 -0
- package/templates/react-node/tasks.json +5 -0
- package/templates/registry.json +30 -0
- package/templates/turborepo/plan.json +12 -0
- package/templates/turborepo/spec.json +12 -0
- package/templates/turborepo/tasks.json +5 -0
|
@@ -1,138 +1,138 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const { execSync } = require("child_process");
|
|
4
|
-
|
|
5
|
-
const projectRoot = process.cwd();
|
|
6
|
-
|
|
7
|
-
function runCommand(command) {
|
|
8
|
-
try {
|
|
9
|
-
execSync(command, { stdio: "pipe" });
|
|
10
|
-
return true;
|
|
11
|
-
} catch (error) {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function resetEnvironment() {
|
|
17
|
-
console.log("๐งน Resetting test environment...");
|
|
18
|
-
|
|
19
|
-
const specDir = path.join(projectRoot, ".sdrive", "specs", "backlog", "test-feature");
|
|
20
|
-
const govDir = path.join(projectRoot, ".sdrive", "governance", "test-feature");
|
|
21
|
-
|
|
22
|
-
if (fs.existsSync(specDir)) {
|
|
23
|
-
fs.rmSync(specDir, { recursive: true, force: true });
|
|
24
|
-
}
|
|
25
|
-
if (fs.existsSync(govDir)) {
|
|
26
|
-
fs.rmSync(govDir, { recursive: true, force: true });
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const workflowStatePath = path.join(projectRoot, ".sdrive", "workflow-state.json");
|
|
30
|
-
fs.writeFileSync(workflowStatePath, JSON.stringify({ features: [] }, null, 2));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function testFeatureCreation() {
|
|
34
|
-
console.log("\n๐งช Test 1: Feature creation");
|
|
35
|
-
|
|
36
|
-
const passed = runCommand(`node .sdrive/scripts/test-create.js`);
|
|
37
|
-
|
|
38
|
-
if (passed) {
|
|
39
|
-
console.log("โ
PASS: Feature created.");
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
console.log("โ FAIL: Feature creation failed.");
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function testSpecGeneration() {
|
|
48
|
-
console.log("\n๐งช Test 2: Spec generation");
|
|
49
|
-
|
|
50
|
-
const specPath = path.join(projectRoot, ".sdrive", "specs", "backlog", "test-feature", "spec.md");
|
|
51
|
-
const govPath = path.join(projectRoot, ".sdrive", "governance", "test-feature", "spec.json");
|
|
52
|
-
|
|
53
|
-
const specExists = fs.existsSync(specPath);
|
|
54
|
-
const govExists = fs.existsSync(govPath);
|
|
55
|
-
|
|
56
|
-
if (specExists && govExists) {
|
|
57
|
-
console.log("โ
PASS: Spec and governance files exist.");
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
console.log("โ FAIL: Spec or governance files missing.");
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function testTraceabilityGenerated() {
|
|
66
|
-
console.log("\n๐งช Test 3: Traceability matrix generated");
|
|
67
|
-
|
|
68
|
-
const tracePath = path.join(projectRoot, ".sdrive", "governance", "test-feature", "traceability.json");
|
|
69
|
-
|
|
70
|
-
if (fs.existsSync(tracePath)) {
|
|
71
|
-
console.log("โ
PASS: Traceability matrix exists.");
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
console.log("โ FAIL: Traceability matrix missing.");
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function testValidationPasses() {
|
|
80
|
-
console.log("\n๐งช Test 4: Governance validation passes");
|
|
81
|
-
|
|
82
|
-
const passed = runCommand("node .sdrive/scripts/validate-governance.js");
|
|
83
|
-
|
|
84
|
-
if (passed) {
|
|
85
|
-
console.log("โ
PASS: Governance validation passed.");
|
|
86
|
-
return true;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
console.log("โ FAIL: Governance validation failed.");
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function testWorkflowState() {
|
|
94
|
-
console.log("\n๐งช Test 5: Workflow state updated");
|
|
95
|
-
|
|
96
|
-
const workflowStatePath = path.join(projectRoot, ".sdrive", "workflow-state.json");
|
|
97
|
-
|
|
98
|
-
if (!fs.existsSync(workflowStatePath)) {
|
|
99
|
-
console.log("โ FAIL: workflow-state.json missing.");
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const state = JSON.parse(fs.readFileSync(workflowStatePath, "utf8"));
|
|
104
|
-
|
|
105
|
-
if (state.features && Array.isArray(state.features)) {
|
|
106
|
-
console.log("โ
PASS: Workflow state has features array.");
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
console.log("โ FAIL: Workflow state invalid.");
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function main() {
|
|
115
|
-
console.log("=== SpecDrive End-to-End Tests ===\n");
|
|
116
|
-
|
|
117
|
-
resetEnvironment();
|
|
118
|
-
|
|
119
|
-
let allPassed = true;
|
|
120
|
-
|
|
121
|
-
allPassed &= testFeatureCreation();
|
|
122
|
-
allPassed &= testSpecGeneration();
|
|
123
|
-
allPassed &= testTraceabilityGenerated();
|
|
124
|
-
allPassed &= testValidationPasses();
|
|
125
|
-
allPassed &= testWorkflowState();
|
|
126
|
-
|
|
127
|
-
resetEnvironment();
|
|
128
|
-
|
|
129
|
-
if (allPassed) {
|
|
130
|
-
console.log("\nโ
All end-to-end tests passed.");
|
|
131
|
-
process.exit(0);
|
|
132
|
-
} else {
|
|
133
|
-
console.log("\nโ Some end-to-end tests failed.");
|
|
134
|
-
process.exit(1);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { execSync } = require("child_process");
|
|
4
|
+
|
|
5
|
+
const projectRoot = process.cwd();
|
|
6
|
+
|
|
7
|
+
function runCommand(command) {
|
|
8
|
+
try {
|
|
9
|
+
execSync(command, { stdio: "pipe" });
|
|
10
|
+
return true;
|
|
11
|
+
} catch (error) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function resetEnvironment() {
|
|
17
|
+
console.log("๐งน Resetting test environment...");
|
|
18
|
+
|
|
19
|
+
const specDir = path.join(projectRoot, ".sdrive", "specs", "backlog", "test-feature");
|
|
20
|
+
const govDir = path.join(projectRoot, ".sdrive", "governance", "test-feature");
|
|
21
|
+
|
|
22
|
+
if (fs.existsSync(specDir)) {
|
|
23
|
+
fs.rmSync(specDir, { recursive: true, force: true });
|
|
24
|
+
}
|
|
25
|
+
if (fs.existsSync(govDir)) {
|
|
26
|
+
fs.rmSync(govDir, { recursive: true, force: true });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const workflowStatePath = path.join(projectRoot, ".sdrive", "workflow-state.json");
|
|
30
|
+
fs.writeFileSync(workflowStatePath, JSON.stringify({ features: [] }, null, 2));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function testFeatureCreation() {
|
|
34
|
+
console.log("\n๐งช Test 1: Feature creation");
|
|
35
|
+
|
|
36
|
+
const passed = runCommand(`node .sdrive/scripts/test-create.js`);
|
|
37
|
+
|
|
38
|
+
if (passed) {
|
|
39
|
+
console.log("โ
PASS: Feature created.");
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log("โ FAIL: Feature creation failed.");
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function testSpecGeneration() {
|
|
48
|
+
console.log("\n๐งช Test 2: Spec generation");
|
|
49
|
+
|
|
50
|
+
const specPath = path.join(projectRoot, ".sdrive", "specs", "backlog", "test-feature", "spec.md");
|
|
51
|
+
const govPath = path.join(projectRoot, ".sdrive", "governance", "test-feature", "spec.json");
|
|
52
|
+
|
|
53
|
+
const specExists = fs.existsSync(specPath);
|
|
54
|
+
const govExists = fs.existsSync(govPath);
|
|
55
|
+
|
|
56
|
+
if (specExists && govExists) {
|
|
57
|
+
console.log("โ
PASS: Spec and governance files exist.");
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log("โ FAIL: Spec or governance files missing.");
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function testTraceabilityGenerated() {
|
|
66
|
+
console.log("\n๐งช Test 3: Traceability matrix generated");
|
|
67
|
+
|
|
68
|
+
const tracePath = path.join(projectRoot, ".sdrive", "governance", "test-feature", "traceability.json");
|
|
69
|
+
|
|
70
|
+
if (fs.existsSync(tracePath)) {
|
|
71
|
+
console.log("โ
PASS: Traceability matrix exists.");
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.log("โ FAIL: Traceability matrix missing.");
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function testValidationPasses() {
|
|
80
|
+
console.log("\n๐งช Test 4: Governance validation passes");
|
|
81
|
+
|
|
82
|
+
const passed = runCommand("node .sdrive/scripts/validate-governance.js");
|
|
83
|
+
|
|
84
|
+
if (passed) {
|
|
85
|
+
console.log("โ
PASS: Governance validation passed.");
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
console.log("โ FAIL: Governance validation failed.");
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function testWorkflowState() {
|
|
94
|
+
console.log("\n๐งช Test 5: Workflow state updated");
|
|
95
|
+
|
|
96
|
+
const workflowStatePath = path.join(projectRoot, ".sdrive", "workflow-state.json");
|
|
97
|
+
|
|
98
|
+
if (!fs.existsSync(workflowStatePath)) {
|
|
99
|
+
console.log("โ FAIL: workflow-state.json missing.");
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const state = JSON.parse(fs.readFileSync(workflowStatePath, "utf8"));
|
|
104
|
+
|
|
105
|
+
if (state.features && Array.isArray(state.features)) {
|
|
106
|
+
console.log("โ
PASS: Workflow state has features array.");
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log("โ FAIL: Workflow state invalid.");
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function main() {
|
|
115
|
+
console.log("=== SpecDrive End-to-End Tests ===\n");
|
|
116
|
+
|
|
117
|
+
resetEnvironment();
|
|
118
|
+
|
|
119
|
+
let allPassed = true;
|
|
120
|
+
|
|
121
|
+
allPassed &= testFeatureCreation();
|
|
122
|
+
allPassed &= testSpecGeneration();
|
|
123
|
+
allPassed &= testTraceabilityGenerated();
|
|
124
|
+
allPassed &= testValidationPasses();
|
|
125
|
+
allPassed &= testWorkflowState();
|
|
126
|
+
|
|
127
|
+
resetEnvironment();
|
|
128
|
+
|
|
129
|
+
if (allPassed) {
|
|
130
|
+
console.log("\nโ
All end-to-end tests passed.");
|
|
131
|
+
process.exit(0);
|
|
132
|
+
} else {
|
|
133
|
+
console.log("\nโ Some end-to-end tests failed.");
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
138
|
main();
|
package/scripts/test-router.js
CHANGED
|
@@ -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();
|