@wipal/agent-team 1.0.4 → 1.1.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 (124) hide show
  1. package/.claude/commands/skills/discover.md +127 -0
  2. package/.claude/commands/skills/install.md +225 -0
  3. package/.claude/commands/skills/review.md +234 -0
  4. package/.claude/commands/utils/learn.md +142 -0
  5. package/.claude/commands/utils/retrospect.md +62 -0
  6. package/.claude/commands/utils/switch.md +113 -0
  7. package/.claude/commands/utils/sync.md +183 -0
  8. package/.claude/rules/common/general-rules.md +6 -0
  9. package/.claude/rules/role-rules/dev-be-rules.md +241 -0
  10. package/.claude/rules/role-rules/dev-fe-rules.md +76 -0
  11. package/.claude/skills/SKILL-INDEX.md +24 -5
  12. package/.claude/skills/core/knowledge-graph/SKILL.md +214 -0
  13. package/.claude/skills/core/sequential-thinking/SKILL.md +112 -0
  14. package/.claude/skills/core/sequential-thinking/references/advanced.md +122 -0
  15. package/.claude/skills/core/sequential-thinking/references/examples.md +274 -0
  16. package/.claude/skills/domain/architecture/c4-architecture/SKILL.md +314 -0
  17. package/.claude/skills/domain/architecture/c4-architecture/references/advanced-patterns.md +552 -0
  18. package/.claude/skills/domain/architecture/c4-architecture/references/c4-syntax.md +492 -0
  19. package/.claude/skills/domain/architecture/c4-architecture/references/common-mistakes.md +437 -0
  20. package/.claude/skills/domain/architecture/mermaid-diagrams/SKILL.md +238 -0
  21. package/.claude/skills/domain/architecture/mermaid-diagrams/references/advanced-features.md +556 -0
  22. package/.claude/skills/domain/architecture/mermaid-diagrams/references/architecture-diagrams.md +192 -0
  23. package/.claude/skills/domain/architecture/mermaid-diagrams/references/c4-diagrams.md +410 -0
  24. package/.claude/skills/domain/architecture/mermaid-diagrams/references/class-diagrams.md +361 -0
  25. package/.claude/skills/domain/architecture/mermaid-diagrams/references/erd-diagrams.md +510 -0
  26. package/.claude/skills/domain/architecture/mermaid-diagrams/references/flowcharts.md +450 -0
  27. package/.claude/skills/domain/architecture/mermaid-diagrams/references/sequence-diagrams.md +394 -0
  28. package/.claude/skills/domain/backend/testing-be/SKILL.md +121 -17
  29. package/.claude/skills/domain/design/design-system/SKILL.md +169 -0
  30. package/.claude/skills/domain/design/html-css-output/SKILL.md +253 -0
  31. package/.claude/skills/domain/design/mockup-creation/SKILL.md +230 -0
  32. package/.claude/skills/domain/design/responsive-design/SKILL.md +207 -0
  33. package/.claude/skills/domain/design/ui-design/SKILL.md +124 -0
  34. package/.claude/skills/domain/frontend/testing-fe/SKILL.md +143 -38
  35. package/.claude/skills/domain/frontend/ui-ux-pro-max/README.md +45 -0
  36. package/.claude/skills/domain/frontend/ui-ux-pro-max/SKILL.md +404 -0
  37. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/charts.csv +26 -0
  38. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/colors.csv +97 -0
  39. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/icons.csv +101 -0
  40. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/landing.csv +31 -0
  41. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/products.csv +97 -0
  42. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/react-performance.csv +45 -0
  43. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  44. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  45. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  46. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  47. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  48. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  49. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  50. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  51. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/react.csv +54 -0
  52. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  53. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  54. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  55. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  56. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/styles.csv +68 -0
  57. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/typography.csv +58 -0
  58. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  59. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  60. package/.claude/skills/domain/frontend/ui-ux-pro-max/data/web-interface.csv +31 -0
  61. package/.claude/skills/domain/frontend/ui-ux-pro-max/scripts/core.py +253 -0
  62. package/.claude/skills/domain/frontend/ui-ux-pro-max/scripts/design_system.py +1067 -0
  63. package/.claude/skills/domain/frontend/ui-ux-pro-max/scripts/search.py +114 -0
  64. package/.claude/skills/domain/product/requirements-clarity/SKILL.md +340 -0
  65. package/.claude/skills/skills-registry.yaml +103 -8
  66. package/README.md +107 -33
  67. package/README.npm.md +252 -0
  68. package/TUTORIAL.md +256 -0
  69. package/bin/agent-team.js +26 -7
  70. package/config/roles.yaml +107 -0
  71. package/docs/01-architecture.md +699 -0
  72. package/docs/02-setup-guide.md +634 -0
  73. package/docs/03-skills-guide.md +628 -0
  74. package/docs/04-workflows.md +792 -0
  75. package/docs/05-model-strategy.md +550 -0
  76. package/docs/06-extend-guide.md +1226 -0
  77. package/docs/07-quick-reference.md +578 -0
  78. package/docs/08-skills-discovery.md +342 -0
  79. package/docs/README.md +134 -0
  80. package/docs/rqm.md +560 -0
  81. package/package.json +9 -3
  82. package/scripts/postinstall.js +46 -0
  83. package/src/commands/add.js +131 -67
  84. package/src/commands/init.js +419 -9
  85. package/src/commands/list.js +20 -16
  86. package/src/commands/projects.js +127 -0
  87. package/src/commands/setup-hooks.js +261 -0
  88. package/src/index.js +0 -1
  89. package/src/utils/file-utils.js +147 -50
  90. package/src/utils/global-registry.js +224 -0
  91. package/templates/CLAUDE.md.tmpl +128 -20
  92. package/templates/MEMORY.md.tmpl +119 -0
  93. package/templates/agent.md.tmpl +205 -0
  94. package/templates/code/nestjs-controller.ts.tmpl +49 -0
  95. package/templates/code/nestjs-dto.ts.tmpl +63 -0
  96. package/templates/code/nestjs-service.ts.tmpl +45 -0
  97. package/templates/code/react-component.tsx.tmpl +24 -0
  98. package/templates/code/react-hook.ts.tmpl +54 -0
  99. package/templates/code/test.spec.ts.tmpl +50 -0
  100. package/templates/code/vue-component.vue.tmpl +49 -0
  101. package/templates/code/vue-composable.ts.tmpl +54 -0
  102. package/templates/knowledge.md.tmpl +152 -17
  103. package/templates/meeting-notes.md.tmpl +110 -0
  104. package/templates/memory/hooks.memory.json +50 -0
  105. package/templates/memory/settings.memory.json +16 -0
  106. package/templates/reports/bug-report.md.tmpl +164 -0
  107. package/templates/reports/code-review.md.tmpl +201 -0
  108. package/templates/reports/sprint-report.md.tmpl +218 -0
  109. package/templates/roles/ba.md +53 -0
  110. package/templates/roles/designer.md +82 -0
  111. package/templates/roles/dev-be.md +49 -0
  112. package/templates/roles/dev-fe.md +49 -0
  113. package/templates/roles/devops.md +53 -0
  114. package/templates/roles/pm.md +49 -0
  115. package/templates/roles/qa.md +53 -0
  116. package/templates/roles/sa.md +49 -0
  117. package/templates/roles/tech-lead.md +132 -0
  118. package/templates/skills/memory/memory-status.md +78 -0
  119. package/templates/skills/memory/recall.md +160 -0
  120. package/templates/skills/memory/reflect.md +168 -0
  121. package/templates/skills/memory/remember.md +105 -0
  122. package/templates/tasks/lessons.md.tmpl +77 -0
  123. package/templates/tasks/todo.md.tmpl +53 -0
  124. package/src/commands/switch.js +0 -53
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Setup-hooks command - Configure Claude Code hooks
3
+ */
4
+
5
+ import chalk from 'chalk';
6
+ import fs from 'fs-extra';
7
+ import path from 'path';
8
+ import inquirer from 'inquirer';
9
+ import { getClaudeDir, isInitialized } from '../utils/file-utils.js';
10
+
11
+ /**
12
+ * Setup hooks command handler
13
+ */
14
+ export async function setupHooksCommand(options) {
15
+ const projectRoot = process.cwd();
16
+
17
+ if (!(await isInitialized(projectRoot))) {
18
+ console.log(chalk.red('❌ Project not initialized'));
19
+ console.log(chalk.gray(' Run `npx @wipal/agent-team init` first'));
20
+ return;
21
+ }
22
+
23
+ if (options.list) {
24
+ await listHooks();
25
+ return;
26
+ }
27
+
28
+ if (options.enable) {
29
+ await enableHook(options.enable, projectRoot);
30
+ return;
31
+ }
32
+
33
+ if (options.disable) {
34
+ await disableHook(options.disable, projectRoot);
35
+ return;
36
+ }
37
+
38
+ // Interactive setup
39
+ await interactiveSetup(projectRoot, options);
40
+ }
41
+
42
+ /**
43
+ * List available hooks
44
+ */
45
+ async function listHooks() {
46
+ console.log(chalk.blue('📋 Available Claude Code Hooks'));
47
+ console.log('');
48
+
49
+ const hooks = [
50
+ {
51
+ name: 'pre_tool_use',
52
+ description: 'Runs before any tool is called. Can block tool execution.'
53
+ },
54
+ {
55
+ name: 'post_tool_use',
56
+ description: 'Runs after a tool call completes. Receives tool result.'
57
+ },
58
+ {
59
+ name: 'notification',
60
+ description: 'Runs when a notification is triggered.'
61
+ },
62
+ {
63
+ name: 'stop',
64
+ description: 'Runs when a Claude Code session stops.'
65
+ }
66
+ ];
67
+
68
+ for (const hook of hooks) {
69
+ console.log(chalk.cyan(` ${hook.name}`));
70
+ console.log(chalk.gray(` ${hook.description}`));
71
+ console.log('');
72
+ }
73
+
74
+ console.log(chalk.gray('Usage:'));
75
+ console.log(chalk.cyan(' npx @wipal/agent-team setup-hooks --enable pre_tool_use'));
76
+ console.log(chalk.cyan(' npx @wipal/agent-team setup-hooks --disable post_tool_use'));
77
+ }
78
+
79
+ /**
80
+ * Enable a specific hook
81
+ */
82
+ async function enableHook(hookName, projectRoot) {
83
+ const claudeDir = getClaudeDir(projectRoot);
84
+ const hooksDir = path.join(claudeDir, 'hooks');
85
+ const settingsPath = path.join(claudeDir, 'settings.json');
86
+
87
+ const validHooks = ['pre_tool_use', 'post_tool_use', 'notification', 'stop'];
88
+ if (!validHooks.includes(hookName)) {
89
+ console.log(chalk.red(`❌ Invalid hook: ${hookName}`));
90
+ console.log(chalk.gray(` Valid hooks: ${validHooks.join(', ')}`));
91
+ return;
92
+ }
93
+
94
+ await fs.ensureDir(hooksDir);
95
+
96
+ // Create hook script
97
+ const hookScript = getHookScript(hookName);
98
+ const hookPath = path.join(hooksDir, `${hookName}.sh`);
99
+ await fs.writeFile(hookPath, hookScript);
100
+ await fs.chmod(hookPath, '755');
101
+
102
+ // Update settings.json
103
+ let settings = {};
104
+ if (await fs.exists(settingsPath)) {
105
+ settings = await fs.readJson(settingsPath);
106
+ }
107
+
108
+ if (!settings.hooks) {
109
+ settings.hooks = {};
110
+ }
111
+
112
+ settings.hooks[hookName] = {
113
+ command: `.claude/hooks/${hookName}.sh`,
114
+ enabled: true
115
+ };
116
+
117
+ await fs.writeJson(settingsPath, settings, { spaces: 2 });
118
+
119
+ console.log(chalk.green(`✓ Enabled hook: ${hookName}`));
120
+ }
121
+
122
+ /**
123
+ * Disable a specific hook
124
+ */
125
+ async function disableHook(hookName, projectRoot) {
126
+ const claudeDir = getClaudeDir(projectRoot);
127
+ const settingsPath = path.join(claudeDir, 'settings.json');
128
+
129
+ if (!(await fs.exists(settingsPath))) {
130
+ console.log(chalk.yellow('⚠ No settings.json found'));
131
+ return;
132
+ }
133
+
134
+ const settings = await fs.readJson(settingsPath);
135
+
136
+ if (settings.hooks && settings.hooks[hookName]) {
137
+ settings.hooks[hookName].enabled = false;
138
+ await fs.writeJson(settingsPath, settings, { spaces: 2 });
139
+ console.log(chalk.green(`✓ Disabled hook: ${hookName}`));
140
+ } else {
141
+ console.log(chalk.yellow(`⚠ Hook ${hookName} is not configured`));
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Interactive hooks setup
147
+ */
148
+ async function interactiveSetup(projectRoot, options) {
149
+ const claudeDir = getClaudeDir(projectRoot);
150
+
151
+ console.log(chalk.blue('🔧 Claude Code Hooks Setup'));
152
+ console.log('');
153
+
154
+ const answer = await inquirer.prompt([
155
+ {
156
+ type: 'checkbox',
157
+ name: 'hooks',
158
+ message: 'Select hooks to enable:',
159
+ choices: [
160
+ { name: 'pre_tool_use - Before any tool call', value: 'pre_tool_use', checked: true },
161
+ { name: 'post_tool_use - After tool call completes', value: 'post_tool_use', checked: true },
162
+ { name: 'notification - When notification triggered', value: 'notification', checked: false },
163
+ { name: 'stop - When session stops', value: 'stop', checked: true }
164
+ ]
165
+ }
166
+ ]);
167
+
168
+ if (answer.hooks.length === 0) {
169
+ console.log(chalk.yellow('No hooks selected'));
170
+ return;
171
+ }
172
+
173
+ const hooksDir = path.join(claudeDir, 'hooks');
174
+ await fs.ensureDir(hooksDir);
175
+
176
+ for (const hookName of answer.hooks) {
177
+ const hookScript = getHookScript(hookName);
178
+ const hookPath = path.join(hooksDir, `${hookName}.sh`);
179
+ await fs.writeFile(hookPath, hookScript);
180
+ await fs.chmod(hookPath, '755');
181
+ console.log(chalk.green(` ✓ Created hook: ${hookName}.sh`));
182
+ }
183
+
184
+ // Update settings.json
185
+ const settingsPath = path.join(claudeDir, 'settings.json');
186
+ let settings = {};
187
+
188
+ if (await fs.exists(settingsPath)) {
189
+ settings = await fs.readJson(settingsPath);
190
+ }
191
+
192
+ settings.hooks = {};
193
+ for (const hookName of answer.hooks) {
194
+ settings.hooks[hookName] = {
195
+ command: `.claude/hooks/${hookName}.sh`,
196
+ enabled: true
197
+ };
198
+ }
199
+
200
+ await fs.writeJson(settingsPath, settings, { spaces: 2 });
201
+ console.log(chalk.green(' ✓ Updated settings.json with hooks configuration'));
202
+
203
+ console.log('');
204
+ console.log(chalk.green('✅ Hooks setup complete!'));
205
+ }
206
+
207
+ /**
208
+ * Get hook script content
209
+ */
210
+ function getHookScript(hookName) {
211
+ const scripts = {
212
+ pre_tool_use: `#!/bin/bash
213
+ # Pre-tool-use hook for agent-team
214
+ # This runs before any tool is called
215
+
216
+ # Read stdin for tool info
217
+ read -r TOOL_INFO
218
+
219
+ # Log tool usage (optional)
220
+ # echo "Tool call: $TOOL_INFO" >> ~/.agent-team/logs/tool-usage.log
221
+
222
+ # Return 0 to allow tool, non-zero to block
223
+ exit 0
224
+ `,
225
+ post_tool_use: `#!/bin/bash
226
+ # Post-tool-use hook for agent-team
227
+ # This runs after a tool call completes
228
+
229
+ # Read stdin for result info
230
+ read -r TOOL_RESULT
231
+
232
+ # Log tool result (optional)
233
+ # echo "Tool result: $TOOL_RESULT" >> ~/.agent-team/logs/tool-usage.log
234
+
235
+ exit 0
236
+ `,
237
+ notification: `#!/bin/bash
238
+ # Notification hook for agent-team
239
+ # This runs when a notification is triggered
240
+
241
+ # Read notification content
242
+ read -r NOTIFICATION
243
+
244
+ # You can add custom notification handling here
245
+ # e.g., send to Slack, Discord, etc.
246
+
247
+ exit 0
248
+ `,
249
+ stop: `#!/bin/bash
250
+ # Stop hook for agent-team
251
+ # This runs when a session stops
252
+
253
+ # You can add cleanup or summary logic here
254
+ # e.g., save session state, generate summary
255
+
256
+ exit 0
257
+ `
258
+ };
259
+
260
+ return scripts[hookName] || '';
261
+ }
package/src/index.js CHANGED
@@ -6,6 +6,5 @@
6
6
  export { initCommand } from './commands/init.js';
7
7
  export { addCommand } from './commands/add.js';
8
8
  export { listCommand } from './commands/list.js';
9
- export { switchCommand } from './commands/switch.js';
10
9
  export { removeCommand } from './commands/remove.js';
11
10
  export { resolveSkills } from './utils/skill-resolver.js';
@@ -39,12 +39,26 @@ export function getAgentsDir(projectRoot = getProjectRoot()) {
39
39
  }
40
40
 
41
41
  /**
42
- * Get specific agent directory path
42
+ * Get specific agent directory path (legacy - for backward compatibility)
43
43
  */
44
44
  export function getAgentDir(agentName, projectRoot = getProjectRoot()) {
45
45
  return path.join(getAgentsDir(projectRoot), agentName);
46
46
  }
47
47
 
48
+ /**
49
+ * Get agent file path (new format: .claude/agents/<name>.md)
50
+ */
51
+ export function getAgentFilePath(agentName, projectRoot = getProjectRoot()) {
52
+ return path.join(getAgentsDir(projectRoot), `${agentName}.md`);
53
+ }
54
+
55
+ /**
56
+ * Get agent memory directory path (.claude/agent-memory/<name>/)
57
+ */
58
+ export function getAgentMemoryDir(agentName, projectRoot = getProjectRoot()) {
59
+ return path.join(getClaudeDir(projectRoot), 'agent-memory', agentName);
60
+ }
61
+
48
62
  /**
49
63
  * Check if .claude directory exists
50
64
  */
@@ -53,9 +67,15 @@ export async function isInitialized(projectRoot = getProjectRoot()) {
53
67
  }
54
68
 
55
69
  /**
56
- * Check if agent exists
70
+ * Check if agent exists (checks for .md file)
57
71
  */
58
72
  export async function agentExists(agentName, projectRoot = getProjectRoot()) {
73
+ // Check for new format (.md file)
74
+ const agentFile = getAgentFilePath(agentName, projectRoot);
75
+ if (await fs.exists(agentFile)) {
76
+ return true;
77
+ }
78
+ // Also check for legacy format (directory)
59
79
  return fs.exists(getAgentDir(agentName, projectRoot));
60
80
  }
61
81
 
@@ -73,7 +93,46 @@ export async function getAgents(projectRoot = getProjectRoot()) {
73
93
  const agents = [];
74
94
 
75
95
  for (const entry of entries) {
76
- if (entry.isDirectory()) {
96
+ // New format: .md files
97
+ if (entry.isFile() && entry.name.endsWith('.md')) {
98
+ const agentName = entry.name.replace('.md', '');
99
+ const agentPath = path.join(agentsDir, entry.name);
100
+
101
+ // Parse frontmatter to get metadata
102
+ let metadata = { name: agentName, description: '', skills: [] };
103
+ try {
104
+ const content = await fs.readFile(agentPath, 'utf-8');
105
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
106
+ if (frontmatterMatch) {
107
+ const frontmatter = frontmatterMatch[1];
108
+ // Parse simple YAML fields
109
+ const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
110
+ const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
111
+ const skillsMatch = frontmatter.match(/^skills:\s*\n((?: - .+\n?)+)/m);
112
+
113
+ if (nameMatch) metadata.name = nameMatch[1].trim();
114
+ if (descMatch) metadata.description = descMatch[1].trim();
115
+ if (skillsMatch) {
116
+ metadata.skills = skillsMatch[1]
117
+ .split('\n')
118
+ .filter(line => line.trim().startsWith('-'))
119
+ .map(line => line.replace(/^\s*-\s*/, '').trim());
120
+ }
121
+ }
122
+ } catch (e) {
123
+ // Ignore parse errors
124
+ }
125
+
126
+ agents.push({
127
+ name: agentName,
128
+ path: agentPath,
129
+ format: 'new',
130
+ description: metadata.description,
131
+ skills: metadata.skills
132
+ });
133
+ }
134
+ // Legacy format: directories
135
+ else if (entry.isDirectory()) {
77
136
  const agentDir = path.join(agentsDir, entry.name);
78
137
  const variantsPath = path.join(agentDir, 'variants.json');
79
138
  const skillsDir = path.join(agentDir, 'skills');
@@ -103,6 +162,7 @@ export async function getAgents(projectRoot = getProjectRoot()) {
103
162
  agents.push({
104
163
  name: entry.name,
105
164
  path: agentDir,
165
+ format: 'legacy',
106
166
  variants,
107
167
  skills
108
168
  });
@@ -113,61 +173,85 @@ export async function getAgents(projectRoot = getProjectRoot()) {
113
173
  }
114
174
 
115
175
  /**
116
- * Copy skills from package to agent folder
117
- */
118
- export async function copySkills(skillNames, targetDir, sourceDir = null) {
119
- const skillsSourceDir = sourceDir || path.join(PACKAGE_ROOT, '.claude', 'skills');
120
- const targetSkillsDir = path.join(targetDir, 'skills');
121
-
122
- await fs.ensureDir(targetSkillsDir);
123
-
124
- const copiedSkills = [];
125
-
126
- for (const skillName of skillNames) {
127
- // Find skill in various locations
128
- const possiblePaths = [
129
- // Core skills
130
- path.join(skillsSourceDir, 'core', skillName),
131
- // Domain skills - frontend
132
- path.join(skillsSourceDir, 'domain', 'frontend', skillName),
133
- // Domain skills - backend
134
- path.join(skillsSourceDir, 'domain', 'backend', skillName),
135
- // Domain skills - architecture
136
- path.join(skillsSourceDir, 'domain', 'architecture', skillName),
137
- // Domain skills - devops
138
- path.join(skillsSourceDir, 'domain', 'devops', skillName),
139
- // Domain skills - product
140
- path.join(skillsSourceDir, 'domain', 'product', skillName),
141
- // Domain skills - quality
142
- path.join(skillsSourceDir, 'domain', 'quality', skillName),
143
- // Leadership skills
144
- path.join(skillsSourceDir, 'leadership', skillName),
145
- // Community skills
146
- path.join(skillsSourceDir, 'community', skillName),
147
- ];
148
-
149
- for (const skillPath of possiblePaths) {
150
- if (await fs.exists(skillPath)) {
151
- const targetPath = path.join(targetSkillsDir, skillName);
152
- await fs.copy(skillPath, targetPath);
153
- copiedSkills.push(skillName);
154
- break;
155
- }
156
- }
176
+ * Copy rules from package to project
177
+ * @param {string} projectRoot - Project root directory
178
+ * @param {Object} options - Options for copying
179
+ * @param {string[]} options.includeRoleRules - List of roles to copy rules for
180
+ * @param {boolean} options.overwrite - Whether to overwrite existing files
181
+ */
182
+ export async function copyRules(projectRoot = getProjectRoot(), options = {}) {
183
+ const { includeRoleRules = [], overwrite = false } = options;
184
+ const rulesSourceDir = path.join(PACKAGE_ROOT, '.claude', 'rules');
185
+ const targetRulesDir = path.join(getClaudeDir(projectRoot), 'rules');
186
+
187
+ await fs.ensureDir(targetRulesDir);
188
+
189
+ // Always copy common rules
190
+ const commonSourceDir = path.join(rulesSourceDir, 'common');
191
+ const commonTargetDir = path.join(targetRulesDir, 'common');
192
+ if (await fs.exists(commonSourceDir)) {
193
+ await fs.copy(commonSourceDir, commonTargetDir, { overwrite });
157
194
  }
158
195
 
159
- return copiedSkills;
196
+ // Always ensure lessons directory exists and copy template if not present
197
+ const lessonsSourceDir = path.join(rulesSourceDir, 'lessons');
198
+ const lessonsTargetDir = path.join(targetRulesDir, 'lessons');
199
+ await fs.ensureDir(lessonsTargetDir);
200
+
201
+ const lessonsTemplate = path.join(lessonsSourceDir, 'lessons.md');
202
+ const lessonsTarget = path.join(lessonsTargetDir, 'lessons.md');
203
+ if (await fs.exists(lessonsTemplate) && (!(await fs.exists(lessonsTarget)) || overwrite)) {
204
+ await fs.copy(lessonsTemplate, lessonsTarget);
205
+ }
206
+
207
+ // Create role-rules directory (empty by default)
208
+ const roleRulesTargetDir = path.join(targetRulesDir, 'role-rules');
209
+ await fs.ensureDir(roleRulesTargetDir);
210
+
211
+ // Only copy specific role rules if requested
212
+ for (const role of includeRoleRules) {
213
+ const roleRuleFile = `${role}-rules.md`;
214
+ const roleRuleSource = path.join(rulesSourceDir, 'role-rules', roleRuleFile);
215
+ const roleRuleTarget = path.join(roleRulesTargetDir, roleRuleFile);
216
+ if (await fs.exists(roleRuleSource)) {
217
+ await fs.copy(roleRuleSource, roleRuleTarget, { overwrite });
218
+ }
219
+ }
160
220
  }
161
221
 
162
222
  /**
163
- * Copy rules from package to project
223
+ * Copy role-specific rules when adding agent
224
+ * @param {string} role - Role name (e.g., 'dev-fe', 'sa')
225
+ * @param {string} projectRoot - Project root directory
226
+ * @returns {string|null} - Name of copied file or null if not copied
164
227
  */
165
- export async function copyRules(projectRoot = getProjectRoot()) {
166
- const rulesSourceDir = path.join(PACKAGE_ROOT, '.claude', 'rules');
167
- const targetRulesDir = path.join(getClaudeDir(projectRoot), 'rules');
228
+ export async function copyRoleRules(role, projectRoot = getProjectRoot()) {
229
+ const rulesSourceDir = path.join(PACKAGE_ROOT, '.claude', 'rules', 'role-rules');
230
+ const targetRulesDir = path.join(getClaudeDir(projectRoot), 'rules', 'role-rules');
168
231
 
169
232
  await fs.ensureDir(targetRulesDir);
170
- await fs.copy(rulesSourceDir, targetRulesDir, { overwrite: false });
233
+
234
+ // Map role to rule file
235
+ const roleRuleMap = {
236
+ 'dev-fe': 'dev-fe-rules.md',
237
+ 'sa': 'sa-rules.md',
238
+ 'dev-be': 'dev-be-rules.md',
239
+ 'tech-lead': 'tech-lead-rules.md',
240
+ 'devops': 'devops-rules.md',
241
+ 'pm': 'pm-rules.md',
242
+ 'qa': 'qa-rules.md'
243
+ };
244
+
245
+ const ruleFile = roleRuleMap[role];
246
+ if (ruleFile) {
247
+ const source = path.join(rulesSourceDir, ruleFile);
248
+ const target = path.join(targetRulesDir, ruleFile);
249
+ if (await fs.exists(source) && !(await fs.exists(target))) {
250
+ await fs.copy(source, target);
251
+ return ruleFile;
252
+ }
253
+ }
254
+ return null;
171
255
  }
172
256
 
173
257
  /**
@@ -191,3 +275,16 @@ export function processTemplate(template, variables) {
191
275
 
192
276
  return result;
193
277
  }
278
+
279
+ /**
280
+ * Read role behavioral template
281
+ * @param {string} role - Role name (e.g., 'dev-fe', 'sa')
282
+ * @returns {string|null} - Template content or null if not found
283
+ */
284
+ export async function readRoleTemplate(role) {
285
+ const templatePath = path.join(PACKAGE_ROOT, 'templates', 'roles', `${role}.md`);
286
+ if (await fs.exists(templatePath)) {
287
+ return fs.readFile(templatePath, 'utf-8');
288
+ }
289
+ return null;
290
+ }