adi_dev_workflow 1.1.1 → 1.3.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.
Files changed (98) hide show
  1. package/bin/index.js +8 -8
  2. package/frameworks/agents/qa-staff-engineer.md +311 -311
  3. package/frameworks/agents/qa-validation-expert.md +458 -458
  4. package/frameworks/agents/tech-review-conformance.md +200 -200
  5. package/frameworks/commands/ministack/README.md +2 -0
  6. package/frameworks/commands/ministack/code-review.md +2 -0
  7. package/frameworks/commands/ministack/generate-intent.md +2 -0
  8. package/frameworks/commands/ministack/generate-scope.md +2 -0
  9. package/frameworks/commands/ministack/generate-tasks.md +2 -0
  10. package/frameworks/commands/ministack/generate-tech-direction.md +2 -0
  11. package/frameworks/commands/ministack/run-ministack-tasks.md +3 -0
  12. package/frameworks/commands/ministack/run-ministack-withlinear.md +2 -0
  13. package/frameworks/commands/ministack/status.md +2 -0
  14. package/frameworks/commands/sdd/code-review.md +2 -0
  15. package/frameworks/commands/sdd/generate-prd.md +2 -0
  16. package/frameworks/commands/sdd/generate-task-plan.md +2 -0
  17. package/frameworks/commands/sdd/generate-tech-direction.md +2 -0
  18. package/frameworks/commands/sdd/generate-tech-spec.md +2 -0
  19. package/frameworks/commands/sdd/generate-tests.md +2 -0
  20. package/frameworks/commands/sdd/run_tasks.md +3 -0
  21. package/frameworks/commands/sdd/run_tasks_withlinear.md +2 -0
  22. package/frameworks/commands/sdd/status.md +2 -0
  23. package/frameworks/commands/sdd/validate-sdd.md +2 -0
  24. package/frameworks/commands/sync-tasks-to-linear.md +2 -0
  25. package/frameworks/commands/taskcard/generate-taskcard.md +2 -0
  26. package/frameworks/commands/taskcard/run-taskcard.md +2 -0
  27. package/frameworks/config/ai-framework-config.yaml +112 -0
  28. package/frameworks/skills/ministack-tasks-expert/SKILL.md +204 -204
  29. package/frameworks/skills/ministack-tasks-expert/templates/task_plan_template.md +78 -78
  30. package/frameworks/skills/ministack-tasks-expert/templates/task_template.md +103 -103
  31. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/benchmark.json +99 -99
  32. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/benchmark.md +64 -64
  33. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/eval_metadata.json +12 -12
  34. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/with_skill/grading.json +32 -32
  35. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/with_skill/outputs/response.md +134 -134
  36. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/with_skill/outputs/transcript.md +68 -68
  37. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/with_skill/timing.json +5 -5
  38. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/without_skill/grading.json +32 -32
  39. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/without_skill/outputs/response.md +525 -525
  40. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/without_skill/outputs/transcript.md +30 -30
  41. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/without_skill/timing.json +5 -5
  42. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/eval_metadata.json +12 -12
  43. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/with_skill/grading.json +32 -32
  44. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/with_skill/outputs/response.md +1126 -1126
  45. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/with_skill/outputs/transcript.md +131 -131
  46. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/with_skill/timing.json +5 -5
  47. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/without_skill/grading.json +32 -32
  48. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/without_skill/outputs/response.md +452 -452
  49. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/without_skill/outputs/transcript.md +78 -78
  50. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/without_skill/timing.json +5 -5
  51. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/eval_metadata.json +12 -12
  52. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/with_skill/grading.json +32 -32
  53. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/with_skill/outputs/response.md +101 -101
  54. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/with_skill/outputs/transcript.md +133 -133
  55. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/with_skill/timing.json +5 -5
  56. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/without_skill/grading.json +32 -32
  57. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/without_skill/outputs/response.md +248 -248
  58. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/without_skill/outputs/transcript.md +49 -49
  59. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/without_skill/timing.json +5 -5
  60. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/review.html +1325 -1325
  61. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/benchmark.json +94 -94
  62. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/benchmark.md +67 -67
  63. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/eval_metadata.json +12 -12
  64. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/with_skill/grading.json +32 -32
  65. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/with_skill/outputs/response.md +117 -117
  66. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/with_skill/outputs/transcript.md +91 -91
  67. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/with_skill/timing.json +1 -1
  68. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/without_skill/grading.json +32 -32
  69. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/without_skill/outputs/response.md +694 -694
  70. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/without_skill/outputs/transcript.md +45 -45
  71. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/without_skill/timing.json +1 -1
  72. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/eval_metadata.json +12 -12
  73. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/with_skill/grading.json +32 -32
  74. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/with_skill/outputs/response.md +1087 -1087
  75. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/with_skill/outputs/transcript.md +124 -124
  76. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/with_skill/timing.json +1 -1
  77. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/without_skill/grading.json +32 -32
  78. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/without_skill/outputs/response.md +458 -458
  79. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/without_skill/outputs/transcript.md +84 -84
  80. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/without_skill/timing.json +1 -1
  81. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/eval_metadata.json +12 -12
  82. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/with_skill/grading.json +32 -32
  83. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/with_skill/outputs/response.md +70 -70
  84. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/with_skill/outputs/transcript.md +148 -148
  85. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/with_skill/timing.json +1 -1
  86. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/without_skill/grading.json +32 -32
  87. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/without_skill/outputs/response.md +249 -249
  88. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/without_skill/outputs/transcript.md +80 -80
  89. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/without_skill/timing.json +1 -1
  90. package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/review.html +1325 -1325
  91. package/frameworks/skills/sdd-tech-spec-expert/SKILL.md +317 -317
  92. package/frameworks/skills/sdd-tech-spec-expert/evals/evals.json +199 -199
  93. package/frameworks/skills/sdd-tech-spec-expert/templates/spec_tech_template.md +290 -290
  94. package/frameworks/skills/sdd-tech-spec-expert/templates/tech_direction-template.md +23 -23
  95. package/package.json +28 -28
  96. package/src/cli.js +121 -121
  97. package/src/installer.js +155 -136
  98. package/src/transformer.js +86 -86
package/package.json CHANGED
@@ -1,28 +1,28 @@
1
- {
2
- "name": "adi_dev_workflow",
3
- "version": "1.1.1",
4
- "description": "Install SDD, miniStack and TaskCard development frameworks for Claude Code and Cursor",
5
- "type": "module",
6
- "bin": {
7
- "adi_dev_workflow": "./bin/index.js"
8
- },
9
- "files": [
10
- "bin/",
11
- "src/",
12
- "frameworks/"
13
- ],
14
- "keywords": [
15
- "claude-code",
16
- "cursor",
17
- "sdd",
18
- "ministack",
19
- "taskcard",
20
- "dev-workflow",
21
- "ai-frameworks"
22
- ],
23
- "author": "",
24
- "license": "MIT",
25
- "dependencies": {
26
- "prompts": "^2.4.2"
27
- }
28
- }
1
+ {
2
+ "name": "adi_dev_workflow",
3
+ "version": "1.3.0",
4
+ "description": "Install SDD, miniStack and TaskCard development frameworks for Claude Code and Cursor",
5
+ "type": "module",
6
+ "bin": {
7
+ "adi_dev_workflow": "bin/index.js"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "src/",
12
+ "frameworks/"
13
+ ],
14
+ "keywords": [
15
+ "claude-code",
16
+ "cursor",
17
+ "sdd",
18
+ "ministack",
19
+ "taskcard",
20
+ "dev-workflow",
21
+ "ai-frameworks"
22
+ ],
23
+ "author": "",
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "prompts": "^2.4.2"
27
+ }
28
+ }
package/src/cli.js CHANGED
@@ -1,121 +1,121 @@
1
- import prompts from 'prompts';
2
- import { install } from './installer.js';
3
-
4
- const BANNER = `
5
- ╔══════════════════════════════════════╗
6
- ║ adi_dev_workflow v1.0 ║
7
- ║ SDD · miniStack · TaskCard ║
8
- ╚══════════════════════════════════════╝
9
- `;
10
-
11
- function parseArgs(argv) {
12
- const args = { ide: null, all: false };
13
- for (let i = 0; i < argv.length; i++) {
14
- if (argv[i] === '--all') args.all = true;
15
- if (argv[i] === '--ide' && argv[i + 1]) {
16
- args.ide = argv[++i];
17
- }
18
- }
19
- return args;
20
- }
21
-
22
- export async function run(argv) {
23
- console.log(BANNER);
24
-
25
- const args = parseArgs(argv);
26
- let target = args.ide;
27
- let frameworks;
28
-
29
- // IDE selection
30
- if (!target || !['claude', 'cursor'].includes(target)) {
31
- const res = await prompts({
32
- type: 'select',
33
- name: 'target',
34
- message: 'Which IDE are you using?',
35
- choices: [
36
- { title: 'Claude Code (.claude/)', value: 'claude' },
37
- { title: 'Cursor (.cursor/)', value: 'cursor' },
38
- ],
39
- });
40
- if (!res.target) {
41
- console.log('Cancelled.');
42
- return;
43
- }
44
- target = res.target;
45
- }
46
-
47
- // Framework selection
48
- if (args.all) {
49
- frameworks = ['sdd', 'ministack', 'taskcard', 'shared'];
50
- } else {
51
- const res = await prompts({
52
- type: 'multiselect',
53
- name: 'frameworks',
54
- message: 'Which frameworks do you want to install?',
55
- choices: [
56
- {
57
- title: 'SDD - Specification-Driven Development',
58
- description: 'PRD -> Spec Tech -> Task Plan -> Code',
59
- value: 'sdd',
60
- selected: true,
61
- },
62
- {
63
- title: 'miniStack - Minimal Feature Stack',
64
- description: 'Intent -> Scope -> Tasks -> Code',
65
- value: 'ministack',
66
- selected: true,
67
- },
68
- {
69
- title: 'TaskCard - Atomic Work Units',
70
- description: 'Description -> Card -> Code',
71
- value: 'taskcard',
72
- selected: true,
73
- },
74
- {
75
- title: 'Shared tools',
76
- description: 'Prompt generator, Linear sync',
77
- value: 'shared',
78
- selected: true,
79
- },
80
- ],
81
- hint: '- Space to toggle. Return to submit',
82
- });
83
- if (!res.frameworks || res.frameworks.length === 0) {
84
- console.log('No frameworks selected. Cancelled.');
85
- return;
86
- }
87
- frameworks = res.frameworks;
88
- }
89
-
90
- const cwd = process.cwd();
91
- const ideLabel = target === 'claude' ? '.claude/' : '.cursor/';
92
-
93
- console.log(`\nInstalling to ${ideLabel} ...\n`);
94
-
95
- const summary = await install({ cwd, target, frameworks });
96
-
97
- console.log(` Done!\n`);
98
- console.log(` ${summary.skills} skills + ${summary.commands} commands + ${summary.templates} templates installed.\n`);
99
-
100
- // Usage hints
101
- const hints = [];
102
- if (frameworks.includes('sdd')) {
103
- hints.push(' /sdd:generate-prd Start a new feature with SDD');
104
- }
105
- if (frameworks.includes('ministack')) {
106
- hints.push(' /ministack:generate-intent Start with miniStack');
107
- }
108
- if (frameworks.includes('taskcard')) {
109
- hints.push(' /taskcard:generate-taskcard Create a task card');
110
- }
111
- if (frameworks.includes('shared')) {
112
- hints.push(' /generate-prompt Generate an optimized prompt');
113
- hints.push(' /sync-tasks-to-linear Sync tasks to Linear');
114
- }
115
-
116
- if (hints.length > 0) {
117
- console.log(' Usage:\n');
118
- for (const h of hints) console.log(h);
119
- console.log('');
120
- }
121
- }
1
+ import prompts from 'prompts';
2
+ import { install } from './installer.js';
3
+
4
+ const BANNER = `
5
+ ╔══════════════════════════════════════╗
6
+ ║ adi_dev_workflow v1.0 ║
7
+ ║ SDD · miniStack · TaskCard ║
8
+ ╚══════════════════════════════════════╝
9
+ `;
10
+
11
+ function parseArgs(argv) {
12
+ const args = { ide: null, all: false };
13
+ for (let i = 0; i < argv.length; i++) {
14
+ if (argv[i] === '--all') args.all = true;
15
+ if (argv[i] === '--ide' && argv[i + 1]) {
16
+ args.ide = argv[++i];
17
+ }
18
+ }
19
+ return args;
20
+ }
21
+
22
+ export async function run(argv) {
23
+ console.log(BANNER);
24
+
25
+ const args = parseArgs(argv);
26
+ let target = args.ide;
27
+ let frameworks;
28
+
29
+ // IDE selection
30
+ if (!target || !['claude', 'cursor'].includes(target)) {
31
+ const res = await prompts({
32
+ type: 'select',
33
+ name: 'target',
34
+ message: 'Which IDE are you using?',
35
+ choices: [
36
+ { title: 'Claude Code (.claude/)', value: 'claude' },
37
+ { title: 'Cursor (.cursor/)', value: 'cursor' },
38
+ ],
39
+ });
40
+ if (!res.target) {
41
+ console.log('Cancelled.');
42
+ return;
43
+ }
44
+ target = res.target;
45
+ }
46
+
47
+ // Framework selection
48
+ if (args.all) {
49
+ frameworks = ['sdd', 'ministack', 'taskcard', 'shared'];
50
+ } else {
51
+ const res = await prompts({
52
+ type: 'multiselect',
53
+ name: 'frameworks',
54
+ message: 'Which frameworks do you want to install?',
55
+ choices: [
56
+ {
57
+ title: 'SDD - Specification-Driven Development',
58
+ description: 'PRD -> Spec Tech -> Task Plan -> Code',
59
+ value: 'sdd',
60
+ selected: true,
61
+ },
62
+ {
63
+ title: 'miniStack - Minimal Feature Stack',
64
+ description: 'Intent -> Scope -> Tasks -> Code',
65
+ value: 'ministack',
66
+ selected: true,
67
+ },
68
+ {
69
+ title: 'TaskCard - Atomic Work Units',
70
+ description: 'Description -> Card -> Code',
71
+ value: 'taskcard',
72
+ selected: true,
73
+ },
74
+ {
75
+ title: 'Shared tools',
76
+ description: 'Prompt generator, Linear sync',
77
+ value: 'shared',
78
+ selected: true,
79
+ },
80
+ ],
81
+ hint: '- Space to toggle. Return to submit',
82
+ });
83
+ if (!res.frameworks || res.frameworks.length === 0) {
84
+ console.log('No frameworks selected. Cancelled.');
85
+ return;
86
+ }
87
+ frameworks = res.frameworks;
88
+ }
89
+
90
+ const cwd = process.cwd();
91
+ const ideLabel = target === 'claude' ? '.claude/' : '.cursor/';
92
+
93
+ console.log(`\nInstalling to ${ideLabel} ...\n`);
94
+
95
+ const summary = await install({ cwd, target, frameworks });
96
+
97
+ console.log(` Done!\n`);
98
+ console.log(` ${summary.skills} skills + ${summary.commands} commands + ${summary.templates} templates + ${summary.agents} agents + ${summary.config} config installed.\n`);
99
+
100
+ // Usage hints
101
+ const hints = [];
102
+ if (frameworks.includes('sdd')) {
103
+ hints.push(' /sdd:generate-prd Start a new feature with SDD');
104
+ }
105
+ if (frameworks.includes('ministack')) {
106
+ hints.push(' /ministack:generate-intent Start with miniStack');
107
+ }
108
+ if (frameworks.includes('taskcard')) {
109
+ hints.push(' /taskcard:generate-taskcard Create a task card');
110
+ }
111
+ if (frameworks.includes('shared')) {
112
+ hints.push(' /generate-prompt Generate an optimized prompt');
113
+ hints.push(' /sync-tasks-to-linear Sync tasks to Linear');
114
+ }
115
+
116
+ if (hints.length > 0) {
117
+ console.log(' Usage:\n');
118
+ for (const h of hints) console.log(h);
119
+ console.log('');
120
+ }
121
+ }
package/src/installer.js CHANGED
@@ -1,136 +1,155 @@
1
- import { readdir, readFile, writeFile, mkdir, stat } from 'node:fs/promises';
2
- import { join, dirname } from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- import { transformContent } from './transformer.js';
5
-
6
- const __dirname = dirname(fileURLToPath(import.meta.url));
7
- const FRAMEWORKS_DIR = join(__dirname, '..', 'frameworks');
8
-
9
- const FRAMEWORK_MAP = {
10
- sdd: {
11
- commands: 'sdd',
12
- skills: ['sdd-prd-expert', 'sdd-spec-tech-expert', 'sdd-task-plan-expert', 'sdd-qa-expert'],
13
- },
14
- ministack: {
15
- commands: 'ministack',
16
- skills: ['ministack-intent-expert', 'ministack-scope-expert', 'ministack-expert', 'ministack-qa-expert'],
17
- },
18
- taskcard: {
19
- commands: 'taskcard',
20
- skills: ['taskcard-expert', 'taskcard-qa-expert'],
21
- },
22
- shared: {
23
- commands: null, // root-level commands
24
- skills: [],
25
- },
26
- };
27
-
28
- const IDE_DIRS = {
29
- claude: '.claude',
30
- cursor: '.cursor',
31
- };
32
-
33
- /**
34
- * Copy a directory recursively, applying transformation.
35
- */
36
- async function copyDir(src, dest, target) {
37
- await mkdir(dest, { recursive: true });
38
- const entries = await readdir(src, { withFileTypes: true });
39
-
40
- for (const entry of entries) {
41
- const srcPath = join(src, entry.name);
42
- const destPath = join(dest, entry.name);
43
-
44
- if (entry.isDirectory()) {
45
- await copyDir(srcPath, destPath, target);
46
- } else if (entry.name.endsWith('.md')) {
47
- const content = await readFile(srcPath, 'utf-8');
48
- const transformed = transformContent(content, target);
49
- await writeFile(destPath, transformed, 'utf-8');
50
- } else {
51
- const content = await readFile(srcPath);
52
- await writeFile(destPath, content);
53
- }
54
- }
55
- }
56
-
57
- /**
58
- * Check if a path exists.
59
- */
60
- async function exists(path) {
61
- try {
62
- await stat(path);
63
- return true;
64
- } catch {
65
- return false;
66
- }
67
- }
68
-
69
- /**
70
- * Install selected frameworks to the target directory.
71
- *
72
- * @param {Object} options
73
- * @param {string} options.cwd - Current working directory
74
- * @param {'claude'|'cursor'} options.target - Target IDE
75
- * @param {string[]} options.frameworks - Frameworks to install ('sdd', 'ministack', 'taskcard', 'shared')
76
- * @returns {Object} Summary of installed items
77
- */
78
- export async function install({ cwd, target, frameworks }) {
79
- const ideDir = join(cwd, IDE_DIRS[target]);
80
- const commandsDir = join(ideDir, 'commands');
81
- const skillsDir = join(ideDir, 'skills');
82
- const templatesDir = join(ideDir, 'templates');
83
-
84
- const summary = { commands: 0, skills: 0, templates: 0 };
85
-
86
- for (const fw of frameworks) {
87
- const config = FRAMEWORK_MAP[fw];
88
- if (!config) continue;
89
-
90
- // Copy commands
91
- if (fw === 'shared') {
92
- // Root-level commands (generate-prompt.md, sync-tasks-to-linear.md)
93
- await mkdir(commandsDir, { recursive: true });
94
- const srcCmds = join(FRAMEWORKS_DIR, 'commands');
95
- const entries = await readdir(srcCmds, { withFileTypes: true });
96
-
97
- for (const entry of entries) {
98
- if (entry.isFile() && entry.name.endsWith('.md')) {
99
- const content = await readFile(join(srcCmds, entry.name), 'utf-8');
100
- const transformed = transformContent(content, target);
101
- await writeFile(join(commandsDir, entry.name), transformed, 'utf-8');
102
- summary.commands++;
103
- }
104
- }
105
-
106
- // Shared templates
107
- const srcTemplates = join(FRAMEWORKS_DIR, 'templates');
108
- if (await exists(srcTemplates)) {
109
- await copyDir(srcTemplates, templatesDir, target);
110
- const tplEntries = await readdir(srcTemplates);
111
- summary.templates += tplEntries.filter((f) => f.endsWith('.md')).length;
112
- }
113
- } else {
114
- // Framework-specific commands
115
- if (config.commands) {
116
- const srcCmdDir = join(FRAMEWORKS_DIR, 'commands', config.commands);
117
- const destCmdDir = join(commandsDir, config.commands);
118
- await copyDir(srcCmdDir, destCmdDir, target);
119
- const entries = await readdir(srcCmdDir);
120
- summary.commands += entries.filter((f) => f.endsWith('.md')).length;
121
- }
122
-
123
- // Framework-specific skills
124
- for (const skillName of config.skills) {
125
- const srcSkillDir = join(FRAMEWORKS_DIR, 'skills', skillName);
126
- const destSkillDir = join(skillsDir, skillName);
127
- if (await exists(srcSkillDir)) {
128
- await copyDir(srcSkillDir, destSkillDir, target);
129
- summary.skills++;
130
- }
131
- }
132
- }
133
- }
134
-
135
- return summary;
136
- }
1
+ import { readdir, readFile, writeFile, mkdir, stat } from 'node:fs/promises';
2
+ import { join, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { transformContent } from './transformer.js';
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const FRAMEWORKS_DIR = join(__dirname, '..', 'frameworks');
8
+
9
+ const FRAMEWORK_MAP = {
10
+ sdd: {
11
+ commands: 'sdd',
12
+ skills: ['sdd-prd-expert', 'sdd-spec-tech-expert', 'sdd-task-plan-expert', 'sdd-qa-expert'],
13
+ },
14
+ ministack: {
15
+ commands: 'ministack',
16
+ skills: ['ministack-intent-expert', 'ministack-scope-expert', 'ministack-expert', 'ministack-qa-expert'],
17
+ },
18
+ taskcard: {
19
+ commands: 'taskcard',
20
+ skills: ['taskcard-expert', 'taskcard-qa-expert'],
21
+ },
22
+ shared: {
23
+ commands: null, // root-level commands
24
+ skills: [],
25
+ },
26
+ };
27
+
28
+ const IDE_DIRS = {
29
+ claude: '.claude',
30
+ cursor: '.cursor',
31
+ };
32
+
33
+ /**
34
+ * Copy a directory recursively, applying transformation.
35
+ */
36
+ async function copyDir(src, dest, target) {
37
+ await mkdir(dest, { recursive: true });
38
+ const entries = await readdir(src, { withFileTypes: true });
39
+
40
+ for (const entry of entries) {
41
+ const srcPath = join(src, entry.name);
42
+ const destPath = join(dest, entry.name);
43
+
44
+ if (entry.isDirectory()) {
45
+ await copyDir(srcPath, destPath, target);
46
+ } else if (entry.name.endsWith('.md')) {
47
+ const content = await readFile(srcPath, 'utf-8');
48
+ const transformed = transformContent(content, target);
49
+ await writeFile(destPath, transformed, 'utf-8');
50
+ } else {
51
+ const content = await readFile(srcPath);
52
+ await writeFile(destPath, content);
53
+ }
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Check if a path exists.
59
+ */
60
+ async function exists(path) {
61
+ try {
62
+ await stat(path);
63
+ return true;
64
+ } catch {
65
+ return false;
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Install selected frameworks to the target directory.
71
+ *
72
+ * @param {Object} options
73
+ * @param {string} options.cwd - Current working directory
74
+ * @param {'claude'|'cursor'} options.target - Target IDE
75
+ * @param {string[]} options.frameworks - Frameworks to install ('sdd', 'ministack', 'taskcard', 'shared')
76
+ * @returns {Object} Summary of installed items
77
+ */
78
+ export async function install({ cwd, target, frameworks }) {
79
+ const ideDir = join(cwd, IDE_DIRS[target]);
80
+ const commandsDir = join(ideDir, 'commands');
81
+ const skillsDir = join(ideDir, 'skills');
82
+ const templatesDir = join(ideDir, 'templates');
83
+ const agentsDir = join(ideDir, 'agents');
84
+
85
+ const summary = { commands: 0, skills: 0, templates: 0, agents: 0, config: 0 };
86
+
87
+ for (const fw of frameworks) {
88
+ const config = FRAMEWORK_MAP[fw];
89
+ if (!config) continue;
90
+
91
+ // Copy commands
92
+ if (fw === 'shared') {
93
+ // Root-level commands (generate-prompt.md, sync-tasks-to-linear.md)
94
+ await mkdir(commandsDir, { recursive: true });
95
+ const srcCmds = join(FRAMEWORKS_DIR, 'commands');
96
+ const entries = await readdir(srcCmds, { withFileTypes: true });
97
+
98
+ for (const entry of entries) {
99
+ if (entry.isFile() && entry.name.endsWith('.md')) {
100
+ const content = await readFile(join(srcCmds, entry.name), 'utf-8');
101
+ const transformed = transformContent(content, target);
102
+ await writeFile(join(commandsDir, entry.name), transformed, 'utf-8');
103
+ summary.commands++;
104
+ }
105
+ }
106
+
107
+ // Shared templates
108
+ const srcTemplates = join(FRAMEWORKS_DIR, 'templates');
109
+ if (await exists(srcTemplates)) {
110
+ await copyDir(srcTemplates, templatesDir, target);
111
+ const tplEntries = await readdir(srcTemplates);
112
+ summary.templates += tplEntries.filter((f) => f.endsWith('.md')).length;
113
+ }
114
+
115
+ // Shared agents
116
+ const srcAgents = join(FRAMEWORKS_DIR, 'agents');
117
+ if (await exists(srcAgents)) {
118
+ await copyDir(srcAgents, agentsDir, target);
119
+ const agentEntries = await readdir(srcAgents);
120
+ summary.agents += agentEntries.filter((f) => f.endsWith('.md')).length;
121
+ }
122
+
123
+ // Config file
124
+ const srcConfig = join(FRAMEWORKS_DIR, 'config', 'ai-framework-config.yaml');
125
+ if (await exists(srcConfig)) {
126
+ const configDestDir = join(ideDir, 'config');
127
+ await mkdir(configDestDir, { recursive: true });
128
+ const content = await readFile(srcConfig);
129
+ await writeFile(join(configDestDir, 'ai-framework-config.yaml'), content);
130
+ summary.config = 1;
131
+ }
132
+ } else {
133
+ // Framework-specific commands
134
+ if (config.commands) {
135
+ const srcCmdDir = join(FRAMEWORKS_DIR, 'commands', config.commands);
136
+ const destCmdDir = join(commandsDir, config.commands);
137
+ await copyDir(srcCmdDir, destCmdDir, target);
138
+ const entries = await readdir(srcCmdDir);
139
+ summary.commands += entries.filter((f) => f.endsWith('.md')).length;
140
+ }
141
+
142
+ // Framework-specific skills
143
+ for (const skillName of config.skills) {
144
+ const srcSkillDir = join(FRAMEWORKS_DIR, 'skills', skillName);
145
+ const destSkillDir = join(skillsDir, skillName);
146
+ if (await exists(srcSkillDir)) {
147
+ await copyDir(srcSkillDir, destSkillDir, target);
148
+ summary.skills++;
149
+ }
150
+ }
151
+ }
152
+ }
153
+
154
+ return summary;
155
+ }