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.
Files changed (74) hide show
  1. package/README.md +955 -697
  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 +149 -38
  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 +50 -50
  32. package/scripts/diff-version.js +96 -0
  33. package/scripts/generate-adapters.js +80 -80
  34. package/scripts/generate-from-template.js +97 -97
  35. package/scripts/generate-openapi.js +75 -75
  36. package/scripts/github-team-sync.js +80 -80
  37. package/scripts/install-hooks.js +20 -20
  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 -62
  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 -807
  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,128 +1,152 @@
1
- #!/usr/bin/env node
2
-
3
- const fs = require("fs");
4
- const path = require("path");
5
- const { execSync } = require("child_process");
6
- const { getWorkflowState, saveWorkflowState, isGateApproved } = require("./gates");
7
-
8
- const projectRoot = process.cwd();
9
-
10
- function loadManifest() {
11
- const manifestPath = path.join(projectRoot, ".sdrive", "commands", "manifest.json");
12
-
13
- if (!fs.existsSync(manifestPath)) {
14
- console.error("❌ manifest.json not found. Run `sdrive init` first.");
15
- process.exit(1);
16
- }
17
-
18
- return JSON.parse(fs.readFileSync(manifestPath, "utf8"));
19
- }
20
-
21
- function findCommand(commandName) {
22
- const manifest = loadManifest();
23
- return manifest.commands.find((cmd) => cmd.command === commandName);
24
- }
25
-
26
- function loadAgent(agentFile) {
27
- const agentPath = path.join(projectRoot, agentFile);
28
-
29
- if (!fs.existsSync(agentPath)) {
30
- console.error(`❌ Agent file not found: ${agentFile}`);
31
- process.exit(1);
32
- }
33
-
34
- return fs.readFileSync(agentPath, "utf8");
35
- }
36
-
37
- function runValidators(validators) {
38
- const validatorPath = path.join(projectRoot, ".sdrive", "scripts", "validate-governance.js");
39
-
40
- if (!validators || validators.length === 0) {
41
- return true;
42
- }
43
-
44
- if (!fs.existsSync(validatorPath)) {
45
- console.warn("⚠️ Validator script not found. Skipping validation.");
46
- return true;
47
- }
48
-
49
- try {
50
- execSync(`node "${validatorPath}"`, { stdio: "inherit" });
51
- return true;
52
- } catch (error) {
53
- console.error("❌ Validation failed.");
54
- return false;
55
- }
56
- }
57
-
58
- function toKebabCase(text) {
59
- return text
60
- .toLowerCase()
61
- .trim()
62
- .replace(/[^a-z0-9]+/g, "-")
63
- .replace(/^-+|-+$/g, "");
64
- }
65
-
66
- function main() {
67
- const commandName = process.argv[2];
68
- const rawFeature = process.argv[3];
69
-
70
- if (!commandName) {
71
- console.error("❌ Usage: node router.js /sdrive:<command> [feature-description]");
72
- process.exit(1);
73
- }
74
-
75
- const command = findCommand(commandName);
76
-
77
- if (!command) {
78
- console.error(`❌ Unknown command: ${commandName}`);
79
- process.exit(1);
80
- }
81
-
82
- let featureName = null;
83
-
84
- if (rawFeature) {
85
- featureName = toKebabCase(rawFeature);
86
- console.log(`\n📦 Feature: ${featureName}`);
87
- }
88
-
89
- console.log(`\n🚀 SpecDrive Command: ${command.command}`);
90
- console.log(`📄 Agent: ${command.agent}`);
91
- console.log(`📁 Agent File: ${command.agentFile}`);
92
- console.log(`📝 Description: ${command.description}`);
93
-
94
- if (command.gates && command.gates.length > 0) {
95
- if (!featureName) {
96
- console.error(`❌ This command requires a feature name or description.`);
97
- console.error(` Usage: node router.js ${commandName} "<feature-description>"`);
98
- process.exit(1);
99
- }
100
-
101
- console.log(`\n🚧 Required Gates: ${command.gates.join(", ")}`);
102
-
103
- for (const gate of command.gates) {
104
- if (!isGateApproved(featureName, gate)) {
105
- console.log(`\n⏸️ Gate "${gate}" is NOT approved for "${featureName}".`);
106
- console.log(` Please approve this gate before running this command.`);
107
- console.log(` Use: sdrive approve ${gate}\n`);
108
- process.exit(1);
109
- }
110
- console.log(`✅ Gate "${gate}" is approved.`);
111
- }
112
- }
113
-
114
- const agentContent = loadAgent(command.agentFile);
115
- console.log(`\n✅ Loaded agent instructions (${agentContent.length} characters).`);
116
-
117
- const valid = runValidators(command.validators);
118
-
119
- if (!valid) {
120
- console.error("\n❌ Command execution blocked due to validation failure.");
121
- process.exit(1);
122
- }
123
-
124
- console.log("\n🤖 The AI tool should now read the agent instructions and execute the command.");
125
- console.log("⏸️ Remember to stop for human approval after the command completes.\n");
126
- }
127
-
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const { execSync } = require("child_process");
6
+ const { getWorkflowState, saveWorkflowState, isGateApproved } = require("./gates");
7
+
8
+ const projectRoot = process.cwd();
9
+
10
+ function checkPermission(command) {
11
+ const permScript = path.join(projectRoot, ".sdrive", "scripts", "check-permission.js");
12
+
13
+ if (!fs.existsSync(permScript)) {
14
+ console.warn("⚠️ Permission checker not found. Skipping permission check.");
15
+ return true;
16
+ }
17
+
18
+ try {
19
+ execSync(`node "${permScript}" slash "${command.command}"`, { stdio: "pipe" });
20
+ return true;
21
+ } catch (error) {
22
+ console.error(`\n❌ Permission denied for ${command.command}`);
23
+ if (error.stdout) console.error(error.stdout.toString());
24
+ if (error.stderr) console.error(error.stderr.toString());
25
+ return false;
26
+ }
27
+ }
28
+
29
+ function loadManifest() {
30
+ const manifestPath = path.join(projectRoot, ".sdrive", "commands", "manifest.json");
31
+
32
+ if (!fs.existsSync(manifestPath)) {
33
+ console.error("❌ manifest.json not found. Run `sdrive init` first.");
34
+ process.exit(1);
35
+ }
36
+
37
+ return JSON.parse(fs.readFileSync(manifestPath, "utf8"));
38
+ }
39
+
40
+ function findCommand(commandName) {
41
+ const manifest = loadManifest();
42
+ return manifest.commands.find((cmd) => cmd.command === commandName);
43
+ }
44
+
45
+ function loadAgent(agentFile) {
46
+ const agentPath = path.join(projectRoot, agentFile);
47
+
48
+ if (!fs.existsSync(agentPath)) {
49
+ console.error(`❌ Agent file not found: ${agentFile}`);
50
+ process.exit(1);
51
+ }
52
+
53
+ return fs.readFileSync(agentPath, "utf8");
54
+ }
55
+
56
+ function runValidators(validators) {
57
+ const validatorPath = path.join(projectRoot, ".sdrive", "scripts", "validate-governance.js");
58
+
59
+ if (!validators || validators.length === 0) {
60
+ return true;
61
+ }
62
+
63
+ if (!fs.existsSync(validatorPath)) {
64
+ console.warn("⚠️ Validator script not found. Skipping validation.");
65
+ return true;
66
+ }
67
+
68
+ try {
69
+ execSync(`node "${validatorPath}"`, { stdio: "inherit" });
70
+ return true;
71
+ } catch (error) {
72
+ console.error("❌ Validation failed.");
73
+ return false;
74
+ }
75
+ }
76
+
77
+ function toKebabCase(text) {
78
+ return text
79
+ .toLowerCase()
80
+ .trim()
81
+ .replace(/[^a-z0-9]+/g, "-")
82
+ .replace(/^-+|-+$/g, "");
83
+ }
84
+
85
+ function main() {
86
+ const commandName = process.argv[2];
87
+ const rawFeature = process.argv[3];
88
+
89
+ if (!commandName) {
90
+ console.error("❌ Usage: node router.js /sdrive:<command> [feature-description]");
91
+ process.exit(1);
92
+ }
93
+
94
+ const command = findCommand(commandName);
95
+
96
+ if (!command) {
97
+ console.error(`❌ Unknown command: ${commandName}`);
98
+ process.exit(1);
99
+ }
100
+
101
+ // Permission check
102
+ if (!checkPermission(command)) {
103
+ process.exit(1);
104
+ }
105
+
106
+ let featureName = null;
107
+
108
+ if (rawFeature) {
109
+ featureName = toKebabCase(rawFeature);
110
+ console.log(`\n📦 Feature: ${featureName}`);
111
+ }
112
+
113
+ console.log(`\n🚀 SpecDrive Command: ${command.command}`);
114
+ console.log(`📄 Agent: ${command.agent}`);
115
+ console.log(`📁 Agent File: ${command.agentFile}`);
116
+ console.log(`📝 Description: ${command.description}`);
117
+
118
+ if (command.gates && command.gates.length > 0) {
119
+ if (!featureName) {
120
+ console.error(`❌ This command requires a feature name or description.`);
121
+ console.error(` Usage: node router.js ${commandName} "<feature-description>"`);
122
+ process.exit(1);
123
+ }
124
+
125
+ console.log(`\n🚧 Required Gates: ${command.gates.join(", ")}`);
126
+
127
+ for (const gate of command.gates) {
128
+ if (!isGateApproved(featureName, gate)) {
129
+ console.log(`\n⏸️ Gate "${gate}" is NOT approved for "${featureName}".`);
130
+ console.log(` Please approve this gate before running this command.`);
131
+ console.log(` Use: sdrive approve ${gate}\n`);
132
+ process.exit(1);
133
+ }
134
+ console.log(`✅ Gate "${gate}" is approved.`);
135
+ }
136
+ }
137
+
138
+ const agentContent = loadAgent(command.agentFile);
139
+ console.log(`\n✅ Loaded agent instructions (${agentContent.length} characters).`);
140
+
141
+ const valid = runValidators(command.validators);
142
+
143
+ if (!valid) {
144
+ console.error("\n❌ Command execution blocked due to validation failure.");
145
+ process.exit(1);
146
+ }
147
+
148
+ console.log("\n🤖 The AI tool should now read the agent instructions and execute the command.");
149
+ console.log("⏸️ Remember to stop for human approval after the command completes.\n");
150
+ }
151
+
128
152
  main();
@@ -1,20 +1,20 @@
1
- {
2
- "version": "1.0.0",
3
- "tools": [
4
- { "name": "github-copilot", "adapterPath": ".github/copilot-instructions.md" },
5
- { "name": "cline", "adapterPath": ".clinerules/sdrive.md" },
6
- { "name": "claude-code", "adapterPath": ".claude/commands/sdrive.md" },
7
- { "name": "cursor", "adapterPath": ".cursor/rules/sdrive.md" },
8
- { "name": "vscode-native", "adapterPath": ".vscode/sdrive-commands.json" },
9
- { "name": "amazon-q", "adapterPath": ".amazonq/rules/sdrive.md" },
10
- { "name": "gemini-cli", "adapterPath": ".gemini/commands/sdrive.md" },
11
- { "name": "continue", "adapterPath": ".continue/rules/sdrive.md" },
12
- { "name": "codex", "adapterPath": ".codex/rules/sdrive.md" },
13
- { "name": "windsurf", "adapterPath": ".windsurf/rules/sdrive.md" },
14
- { "name": "kilo-code", "adapterPath": ".kilocode/rules/sdrive.md" },
15
- { "name": "opencode", "adapterPath": ".opencode/rules/sdrive.md" },
16
- { "name": "qoder", "adapterPath": ".qoder/rules/sdrive.md" },
17
- { "name": "qwen-code", "adapterPath": ".qwen/rules/sdrive.md" },
18
- { "name": "rovo-dev", "adapterPath": ".rovo/rules/sdrive.md" }
19
- ]
1
+ {
2
+ "version": "1.0.0",
3
+ "tools": [
4
+ { "name": "github-copilot", "adapterPath": ".github/copilot-instructions.md" },
5
+ { "name": "cline", "adapterPath": ".clinerules/sdrive.md" },
6
+ { "name": "claude-code", "adapterPath": ".claude/commands/sdrive.md" },
7
+ { "name": "cursor", "adapterPath": ".cursor/rules/sdrive.md" },
8
+ { "name": "vscode-native", "adapterPath": ".vscode/sdrive-commands.json" },
9
+ { "name": "amazon-q", "adapterPath": ".amazonq/rules/sdrive.md" },
10
+ { "name": "gemini-cli", "adapterPath": ".gemini/commands/sdrive.md" },
11
+ { "name": "continue", "adapterPath": ".continue/rules/sdrive.md" },
12
+ { "name": "codex", "adapterPath": ".codex/rules/sdrive.md" },
13
+ { "name": "windsurf", "adapterPath": ".windsurf/rules/sdrive.md" },
14
+ { "name": "kilo-code", "adapterPath": ".kilocode/rules/sdrive.md" },
15
+ { "name": "opencode", "adapterPath": ".opencode/rules/sdrive.md" },
16
+ { "name": "qoder", "adapterPath": ".qoder/rules/sdrive.md" },
17
+ { "name": "qwen-code", "adapterPath": ".qwen/rules/sdrive.md" },
18
+ { "name": "rovo-dev", "adapterPath": ".rovo/rules/sdrive.md" }
19
+ ]
20
20
  }