@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.
- package/.claude/commands/skills/discover.md +127 -0
- package/.claude/commands/skills/install.md +225 -0
- package/.claude/commands/skills/review.md +234 -0
- package/.claude/commands/utils/learn.md +142 -0
- package/.claude/commands/utils/retrospect.md +62 -0
- package/.claude/commands/utils/switch.md +113 -0
- package/.claude/commands/utils/sync.md +183 -0
- package/.claude/rules/common/general-rules.md +6 -0
- package/.claude/rules/role-rules/dev-be-rules.md +241 -0
- package/.claude/rules/role-rules/dev-fe-rules.md +76 -0
- package/.claude/skills/SKILL-INDEX.md +24 -5
- package/.claude/skills/core/knowledge-graph/SKILL.md +214 -0
- package/.claude/skills/core/sequential-thinking/SKILL.md +112 -0
- package/.claude/skills/core/sequential-thinking/references/advanced.md +122 -0
- package/.claude/skills/core/sequential-thinking/references/examples.md +274 -0
- package/.claude/skills/domain/architecture/c4-architecture/SKILL.md +314 -0
- package/.claude/skills/domain/architecture/c4-architecture/references/advanced-patterns.md +552 -0
- package/.claude/skills/domain/architecture/c4-architecture/references/c4-syntax.md +492 -0
- package/.claude/skills/domain/architecture/c4-architecture/references/common-mistakes.md +437 -0
- package/.claude/skills/domain/architecture/mermaid-diagrams/SKILL.md +238 -0
- package/.claude/skills/domain/architecture/mermaid-diagrams/references/advanced-features.md +556 -0
- package/.claude/skills/domain/architecture/mermaid-diagrams/references/architecture-diagrams.md +192 -0
- package/.claude/skills/domain/architecture/mermaid-diagrams/references/c4-diagrams.md +410 -0
- package/.claude/skills/domain/architecture/mermaid-diagrams/references/class-diagrams.md +361 -0
- package/.claude/skills/domain/architecture/mermaid-diagrams/references/erd-diagrams.md +510 -0
- package/.claude/skills/domain/architecture/mermaid-diagrams/references/flowcharts.md +450 -0
- package/.claude/skills/domain/architecture/mermaid-diagrams/references/sequence-diagrams.md +394 -0
- package/.claude/skills/domain/backend/testing-be/SKILL.md +121 -17
- package/.claude/skills/domain/design/design-system/SKILL.md +169 -0
- package/.claude/skills/domain/design/html-css-output/SKILL.md +253 -0
- package/.claude/skills/domain/design/mockup-creation/SKILL.md +230 -0
- package/.claude/skills/domain/design/responsive-design/SKILL.md +207 -0
- package/.claude/skills/domain/design/ui-design/SKILL.md +124 -0
- package/.claude/skills/domain/frontend/testing-fe/SKILL.md +143 -38
- package/.claude/skills/domain/frontend/ui-ux-pro-max/README.md +45 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/SKILL.md +404 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/charts.csv +26 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/colors.csv +97 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/icons.csv +101 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/landing.csv +31 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/products.csv +97 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/styles.csv +68 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/typography.csv +58 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/scripts/core.py +253 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/.claude/skills/domain/frontend/ui-ux-pro-max/scripts/search.py +114 -0
- package/.claude/skills/domain/product/requirements-clarity/SKILL.md +340 -0
- package/.claude/skills/skills-registry.yaml +103 -8
- package/README.md +107 -33
- package/README.npm.md +252 -0
- package/TUTORIAL.md +256 -0
- package/bin/agent-team.js +26 -7
- package/config/roles.yaml +107 -0
- package/docs/01-architecture.md +699 -0
- package/docs/02-setup-guide.md +634 -0
- package/docs/03-skills-guide.md +628 -0
- package/docs/04-workflows.md +792 -0
- package/docs/05-model-strategy.md +550 -0
- package/docs/06-extend-guide.md +1226 -0
- package/docs/07-quick-reference.md +578 -0
- package/docs/08-skills-discovery.md +342 -0
- package/docs/README.md +134 -0
- package/docs/rqm.md +560 -0
- package/package.json +9 -3
- package/scripts/postinstall.js +46 -0
- package/src/commands/add.js +131 -67
- package/src/commands/init.js +419 -9
- package/src/commands/list.js +20 -16
- package/src/commands/projects.js +127 -0
- package/src/commands/setup-hooks.js +261 -0
- package/src/index.js +0 -1
- package/src/utils/file-utils.js +147 -50
- package/src/utils/global-registry.js +224 -0
- package/templates/CLAUDE.md.tmpl +128 -20
- package/templates/MEMORY.md.tmpl +119 -0
- package/templates/agent.md.tmpl +205 -0
- package/templates/code/nestjs-controller.ts.tmpl +49 -0
- package/templates/code/nestjs-dto.ts.tmpl +63 -0
- package/templates/code/nestjs-service.ts.tmpl +45 -0
- package/templates/code/react-component.tsx.tmpl +24 -0
- package/templates/code/react-hook.ts.tmpl +54 -0
- package/templates/code/test.spec.ts.tmpl +50 -0
- package/templates/code/vue-component.vue.tmpl +49 -0
- package/templates/code/vue-composable.ts.tmpl +54 -0
- package/templates/knowledge.md.tmpl +152 -17
- package/templates/meeting-notes.md.tmpl +110 -0
- package/templates/memory/hooks.memory.json +50 -0
- package/templates/memory/settings.memory.json +16 -0
- package/templates/reports/bug-report.md.tmpl +164 -0
- package/templates/reports/code-review.md.tmpl +201 -0
- package/templates/reports/sprint-report.md.tmpl +218 -0
- package/templates/roles/ba.md +53 -0
- package/templates/roles/designer.md +82 -0
- package/templates/roles/dev-be.md +49 -0
- package/templates/roles/dev-fe.md +49 -0
- package/templates/roles/devops.md +53 -0
- package/templates/roles/pm.md +49 -0
- package/templates/roles/qa.md +53 -0
- package/templates/roles/sa.md +49 -0
- package/templates/roles/tech-lead.md +132 -0
- package/templates/skills/memory/memory-status.md +78 -0
- package/templates/skills/memory/recall.md +160 -0
- package/templates/skills/memory/reflect.md +168 -0
- package/templates/skills/memory/remember.md +105 -0
- package/templates/tasks/lessons.md.tmpl +77 -0
- package/templates/tasks/todo.md.tmpl +53 -0
- package/src/commands/switch.js +0 -53
package/src/commands/init.js
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import fs from 'fs-extra';
|
|
7
7
|
import path from 'path';
|
|
8
|
-
import
|
|
8
|
+
import inquirer from 'inquirer';
|
|
9
|
+
import { getClaudeDir, getProjectRoot, copyRules, getPackageRoot } from '../utils/file-utils.js';
|
|
10
|
+
import { registerProject } from '../utils/global-registry.js';
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* Initialize .claude/ structure
|
|
@@ -20,13 +22,47 @@ export async function initCommand(options) {
|
|
|
20
22
|
|
|
21
23
|
// Check if already initialized
|
|
22
24
|
if (await fs.exists(claudeDir)) {
|
|
23
|
-
if (
|
|
24
|
-
console.log(chalk.yellow('
|
|
25
|
-
|
|
25
|
+
if (options.force) {
|
|
26
|
+
console.log(chalk.yellow(' Removing existing .claude/ directory...'));
|
|
27
|
+
await fs.remove(claudeDir);
|
|
28
|
+
} else if (options.merge) {
|
|
29
|
+
console.log(chalk.blue(' Merging with existing .claude/ directory...'));
|
|
30
|
+
await mergeInit(claudeDir, projectRoot, options);
|
|
26
31
|
return;
|
|
32
|
+
} else if (options.update) {
|
|
33
|
+
console.log(chalk.blue(' Updating package files...'));
|
|
34
|
+
await updateInit(claudeDir, projectRoot, options);
|
|
35
|
+
return;
|
|
36
|
+
} else {
|
|
37
|
+
// Interactive prompt
|
|
38
|
+
const answer = await inquirer.prompt([
|
|
39
|
+
{
|
|
40
|
+
type: 'list',
|
|
41
|
+
name: 'action',
|
|
42
|
+
message: '.claude/ directory already exists. What would you like to do?',
|
|
43
|
+
choices: [
|
|
44
|
+
{ name: 'Merge (add missing files only)', value: 'merge' },
|
|
45
|
+
{ name: 'Update (refresh package files, keep custom)', value: 'update' },
|
|
46
|
+
{ name: 'Force (remove all and recreate)', value: 'force' },
|
|
47
|
+
{ name: 'Cancel', value: 'cancel' }
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
if (answer.action === 'cancel') {
|
|
53
|
+
console.log(chalk.gray(' Init cancelled'));
|
|
54
|
+
return;
|
|
55
|
+
} else if (answer.action === 'force') {
|
|
56
|
+
console.log(chalk.yellow(' Removing existing .claude/ directory...'));
|
|
57
|
+
await fs.remove(claudeDir);
|
|
58
|
+
} else if (answer.action === 'merge') {
|
|
59
|
+
await mergeInit(claudeDir, projectRoot, options);
|
|
60
|
+
return;
|
|
61
|
+
} else if (answer.action === 'update') {
|
|
62
|
+
await updateInit(claudeDir, projectRoot, options);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
27
65
|
}
|
|
28
|
-
console.log(chalk.yellow(' Removing existing .claude/ directory...'));
|
|
29
|
-
await fs.remove(claudeDir);
|
|
30
66
|
}
|
|
31
67
|
|
|
32
68
|
// Create directory structure
|
|
@@ -95,11 +131,11 @@ export async function initCommand(options) {
|
|
|
95
131
|
console.log(chalk.green(' ✓ Created settings.json'));
|
|
96
132
|
}
|
|
97
133
|
|
|
98
|
-
// Copy rules
|
|
134
|
+
// Copy rules (only common rules, no role-specific rules)
|
|
99
135
|
console.log(chalk.blue(' Copying rules...'));
|
|
100
136
|
try {
|
|
101
|
-
await copyRules(projectRoot);
|
|
102
|
-
console.log(chalk.green(' ✓ Copied rules'));
|
|
137
|
+
await copyRules(projectRoot, { includeRoleRules: [] });
|
|
138
|
+
console.log(chalk.green(' ✓ Copied common rules (role rules will be added when creating agents)'));
|
|
103
139
|
} catch (error) {
|
|
104
140
|
console.log(chalk.yellow(' ⚠ Could not copy rules (package may not have rules)'));
|
|
105
141
|
}
|
|
@@ -122,6 +158,18 @@ export async function initCommand(options) {
|
|
|
122
158
|
console.log(chalk.green(' ✓ Created lessons.md'));
|
|
123
159
|
}
|
|
124
160
|
|
|
161
|
+
// Ask about hooks setup
|
|
162
|
+
await promptForHooks(claudeDir, options);
|
|
163
|
+
|
|
164
|
+
// Setup SimpleMem if --memory flag
|
|
165
|
+
if (options.memory) {
|
|
166
|
+
await setupMemory(claudeDir, projectRoot);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Register project in global registry
|
|
170
|
+
await registerProject(projectRoot, { agents_count: 0 });
|
|
171
|
+
console.log(chalk.green(' ✓ Project registered in global registry'));
|
|
172
|
+
|
|
125
173
|
console.log('');
|
|
126
174
|
console.log(chalk.green('✅ Project initialized successfully!'));
|
|
127
175
|
console.log('');
|
|
@@ -134,3 +182,365 @@ export async function initCommand(options) {
|
|
|
134
182
|
console.log('');
|
|
135
183
|
console.log(chalk.gray(' 3. Available roles: dev-fe, dev-be, sa, tech-lead, devops, pm, qa'));
|
|
136
184
|
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Merge init - add missing files without destroying existing content
|
|
188
|
+
*/
|
|
189
|
+
async function mergeInit(claudeDir, projectRoot, options) {
|
|
190
|
+
// Create missing directories
|
|
191
|
+
const requiredDirs = [
|
|
192
|
+
'agents',
|
|
193
|
+
'shared-skills',
|
|
194
|
+
'rules/common',
|
|
195
|
+
'rules/role-rules',
|
|
196
|
+
'rules/lessons',
|
|
197
|
+
'commands/roles',
|
|
198
|
+
'commands/utils',
|
|
199
|
+
'commands/workflows'
|
|
200
|
+
];
|
|
201
|
+
|
|
202
|
+
for (const dir of requiredDirs) {
|
|
203
|
+
await fs.ensureDir(path.join(claudeDir, dir));
|
|
204
|
+
}
|
|
205
|
+
console.log(chalk.green(' ✓ Ensured all directories exist'));
|
|
206
|
+
|
|
207
|
+
// Create CLAUDE.md if missing
|
|
208
|
+
const claudeMdPath = path.join(claudeDir, 'CLAUDE.md');
|
|
209
|
+
if (!(await fs.exists(claudeMdPath))) {
|
|
210
|
+
const projectName = path.basename(projectRoot);
|
|
211
|
+
const claudeMdContent = `# Project Context: ${projectName}
|
|
212
|
+
|
|
213
|
+
## Description
|
|
214
|
+
[Brief description of the project]
|
|
215
|
+
|
|
216
|
+
## Tech Stack
|
|
217
|
+
- Frontend:
|
|
218
|
+
- Backend:
|
|
219
|
+
- Database:
|
|
220
|
+
- Infrastructure:
|
|
221
|
+
|
|
222
|
+
## Team Members (Agents)
|
|
223
|
+
[List of configured agents - run 'npx @wipal/agent-team list' to see]
|
|
224
|
+
`;
|
|
225
|
+
await fs.writeFile(claudeMdPath, claudeMdContent);
|
|
226
|
+
console.log(chalk.green(' ✓ Created CLAUDE.md'));
|
|
227
|
+
} else {
|
|
228
|
+
console.log(chalk.gray(' ℹ CLAUDE.md already exists, skipping'));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Create settings.json if missing
|
|
232
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
233
|
+
if (!(await fs.exists(settingsPath))) {
|
|
234
|
+
const settingsContent = {
|
|
235
|
+
mcpServers: {
|
|
236
|
+
context7: {
|
|
237
|
+
command: 'npx',
|
|
238
|
+
args: ['-y', '@context7/mcp-server']
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
await fs.writeJson(settingsPath, settingsContent, { spaces: 2 });
|
|
243
|
+
console.log(chalk.green(' ✓ Created settings.json'));
|
|
244
|
+
} else {
|
|
245
|
+
console.log(chalk.gray(' ℹ settings.json already exists, skipping'));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Copy rules (only if update flag is set)
|
|
249
|
+
if (options.updateRules) {
|
|
250
|
+
try {
|
|
251
|
+
await copyRules(projectRoot, { includeRoleRules: [], overwrite: true });
|
|
252
|
+
console.log(chalk.green(' ✓ Updated rules'));
|
|
253
|
+
} catch (error) {
|
|
254
|
+
console.log(chalk.yellow(' ⚠ Could not update rules'));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Ask about hooks
|
|
259
|
+
await promptForHooks(claudeDir, options);
|
|
260
|
+
|
|
261
|
+
// Register project
|
|
262
|
+
await registerProject(projectRoot, { agents_count: 0 });
|
|
263
|
+
|
|
264
|
+
console.log('');
|
|
265
|
+
console.log(chalk.green('✅ Project merged successfully!'));
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Update init - refresh package files, keep custom content
|
|
270
|
+
*/
|
|
271
|
+
async function updateInit(claudeDir, projectRoot, options) {
|
|
272
|
+
// Copy rules with overwrite
|
|
273
|
+
try {
|
|
274
|
+
await copyRules(projectRoot, { includeRoleRules: [], overwrite: true });
|
|
275
|
+
console.log(chalk.green(' ✓ Updated rules'));
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.log(chalk.yellow(' ⚠ Could not update rules'));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Register/update project
|
|
281
|
+
await registerProject(projectRoot, { agents_count: 0 });
|
|
282
|
+
|
|
283
|
+
console.log('');
|
|
284
|
+
console.log(chalk.green('✅ Project updated successfully!'));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Prompt for hooks setup
|
|
289
|
+
*/
|
|
290
|
+
async function promptForHooks(claudeDir, options) {
|
|
291
|
+
// Skip if --no-hooks flag or if hooks already set up
|
|
292
|
+
if (options.noHooks) {
|
|
293
|
+
console.log(chalk.gray(' ℹ Skipping hooks setup (--no-hooks)'));
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const hooksDir = path.join(claudeDir, 'hooks');
|
|
298
|
+
if (await fs.exists(hooksDir)) {
|
|
299
|
+
console.log(chalk.gray(' ℹ Hooks directory already exists, skipping'));
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Only prompt in interactive mode or if --hooks flag
|
|
304
|
+
if (!options.hooks && !process.stdin.isTTY) {
|
|
305
|
+
console.log(chalk.gray(' ℹ Run "npx @wipal/agent-team setup-hooks" to enable hooks later'));
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (options.hooks) {
|
|
310
|
+
await setupHooks(claudeDir, 'all');
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const answer = await inquirer.prompt([
|
|
315
|
+
{
|
|
316
|
+
type: 'list',
|
|
317
|
+
name: 'hooks',
|
|
318
|
+
message: 'Would you like to enable Claude Code hooks?',
|
|
319
|
+
choices: [
|
|
320
|
+
{ name: 'Yes, enable all hooks', value: 'all' },
|
|
321
|
+
{ name: 'Yes, let me choose which hooks', value: 'select' },
|
|
322
|
+
{ name: "No, I'll set up later with 'setup-hooks'", value: 'none' }
|
|
323
|
+
],
|
|
324
|
+
default: 'none'
|
|
325
|
+
}
|
|
326
|
+
]);
|
|
327
|
+
|
|
328
|
+
if (answer.hooks === 'all') {
|
|
329
|
+
await setupHooks(claudeDir, 'all');
|
|
330
|
+
} else if (answer.hooks === 'select') {
|
|
331
|
+
const selectAnswer = await inquirer.prompt([
|
|
332
|
+
{
|
|
333
|
+
type: 'checkbox',
|
|
334
|
+
name: 'selectedHooks',
|
|
335
|
+
message: 'Select hooks to enable:',
|
|
336
|
+
choices: [
|
|
337
|
+
{ name: 'pre_tool_use - Before any tool call', value: 'pre_tool_use', checked: true },
|
|
338
|
+
{ name: 'post_tool_use - After tool call completes', value: 'post_tool_use', checked: true },
|
|
339
|
+
{ name: 'notification - When notification triggered', value: 'notification', checked: false },
|
|
340
|
+
{ name: 'stop - When session stops', value: 'stop', checked: true }
|
|
341
|
+
]
|
|
342
|
+
}
|
|
343
|
+
]);
|
|
344
|
+
await setupHooks(claudeDir, selectAnswer.selectedHooks);
|
|
345
|
+
} else {
|
|
346
|
+
console.log(chalk.gray(' ℹ Run "npx @wipal/agent-team setup-hooks" to enable hooks later'));
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Setup hooks
|
|
352
|
+
*/
|
|
353
|
+
async function setupHooks(claudeDir, hooks) {
|
|
354
|
+
const hooksDir = path.join(claudeDir, 'hooks');
|
|
355
|
+
await fs.ensureDir(hooksDir);
|
|
356
|
+
|
|
357
|
+
const availableHooks = {
|
|
358
|
+
pre_tool_use: `#!/bin/bash
|
|
359
|
+
# Pre-tool-use hook for agent-team
|
|
360
|
+
# This runs before any tool is called
|
|
361
|
+
|
|
362
|
+
# Read stdin for tool info
|
|
363
|
+
read -r TOOL_INFO
|
|
364
|
+
|
|
365
|
+
# Log tool usage (optional)
|
|
366
|
+
# echo "Tool call: $TOOL_INFO" >> ~/.agent-team/logs/tool-usage.log
|
|
367
|
+
|
|
368
|
+
# Return 0 to allow tool, non-zero to block
|
|
369
|
+
exit 0
|
|
370
|
+
`,
|
|
371
|
+
post_tool_use: `#!/bin/bash
|
|
372
|
+
# Post-tool-use hook for agent-team
|
|
373
|
+
# This runs after a tool call completes
|
|
374
|
+
|
|
375
|
+
# Read stdin for result info
|
|
376
|
+
read -r TOOL_RESULT
|
|
377
|
+
|
|
378
|
+
# Log tool result (optional)
|
|
379
|
+
# echo "Tool result: $TOOL_RESULT" >> ~/.agent-team/logs/tool-usage.log
|
|
380
|
+
|
|
381
|
+
exit 0
|
|
382
|
+
`,
|
|
383
|
+
notification: `#!/bin/bash
|
|
384
|
+
# Notification hook for agent-team
|
|
385
|
+
# This runs when a notification is triggered
|
|
386
|
+
|
|
387
|
+
# Read notification content
|
|
388
|
+
read -r NOTIFICATION
|
|
389
|
+
|
|
390
|
+
# You can add custom notification handling here
|
|
391
|
+
# e.g., send to Slack, Discord, etc.
|
|
392
|
+
|
|
393
|
+
exit 0
|
|
394
|
+
`,
|
|
395
|
+
stop: `#!/bin/bash
|
|
396
|
+
# Stop hook for agent-team
|
|
397
|
+
# This runs when a session stops
|
|
398
|
+
|
|
399
|
+
# You can add cleanup or summary logic here
|
|
400
|
+
# e.g., save session state, generate summary
|
|
401
|
+
|
|
402
|
+
exit 0
|
|
403
|
+
`
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
const hooksToCreate = hooks === 'all' ? Object.keys(availableHooks) : hooks;
|
|
407
|
+
|
|
408
|
+
for (const hookName of hooksToCreate) {
|
|
409
|
+
if (availableHooks[hookName]) {
|
|
410
|
+
const hookPath = path.join(hooksDir, `${hookName}.sh`);
|
|
411
|
+
await fs.writeFile(hookPath, availableHooks[hookName]);
|
|
412
|
+
await fs.chmod(hookPath, '755');
|
|
413
|
+
console.log(chalk.green(` ✓ Created hook: ${hookName}.sh`));
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Update settings.json to include hooks
|
|
418
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
419
|
+
let settings = {};
|
|
420
|
+
|
|
421
|
+
if (await fs.exists(settingsPath)) {
|
|
422
|
+
settings = await fs.readJson(settingsPath);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
settings.hooks = {};
|
|
426
|
+
for (const hookName of hooksToCreate) {
|
|
427
|
+
if (availableHooks[hookName]) {
|
|
428
|
+
settings.hooks[hookName] = {
|
|
429
|
+
command: `.claude/hooks/${hookName}.sh`,
|
|
430
|
+
enabled: true
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
await fs.writeJson(settingsPath, settings, { spaces: 2 });
|
|
436
|
+
console.log(chalk.green(' ✓ Updated settings.json with hooks configuration'));
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Setup SimpleMem long-term memory system
|
|
441
|
+
*/
|
|
442
|
+
async function setupMemory(claudeDir, projectRoot) {
|
|
443
|
+
console.log(chalk.blue(' Setting up SimpleMem long-term memory...'));
|
|
444
|
+
|
|
445
|
+
const projectName = path.basename(projectRoot);
|
|
446
|
+
|
|
447
|
+
// 1. Check if Docker is available
|
|
448
|
+
try {
|
|
449
|
+
const { execSync } = await import('child_process');
|
|
450
|
+
execSync('docker --version', { stdio: 'pipe' });
|
|
451
|
+
} catch (error) {
|
|
452
|
+
console.log(chalk.yellow(' ⚠ Docker not found. SimpleMem requires Docker.'));
|
|
453
|
+
console.log(chalk.gray(' Install Docker: https://docs.docker.com/get-docker/'));
|
|
454
|
+
console.log(chalk.gray(' Then run: docker compose -f <agent-team>/docker/docker-compose.yml up -d'));
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// 2. Check if simplemem-mcp container is running
|
|
459
|
+
try {
|
|
460
|
+
const { execSync } = await import('child_process');
|
|
461
|
+
const containers = execSync('docker ps --filter name=simplemem-mcp --format {{.Names}}', {
|
|
462
|
+
encoding: 'utf-8'
|
|
463
|
+
}).trim();
|
|
464
|
+
|
|
465
|
+
if (!containers.includes('simplemem-mcp')) {
|
|
466
|
+
console.log(chalk.yellow(' ⚠ SimpleMem container not running.'));
|
|
467
|
+
console.log(chalk.gray(' Start it with:'));
|
|
468
|
+
console.log(chalk.cyan(' cd <agent-team-package>/docker && docker compose up -d'));
|
|
469
|
+
console.log(chalk.gray(' Or build and run manually.'));
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
console.log(chalk.green(' ✓ SimpleMem container is running'));
|
|
473
|
+
} catch (error) {
|
|
474
|
+
console.log(chalk.yellow(' ⚠ Could not check Docker container status'));
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// 3. Update settings.json with MCP server
|
|
478
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
479
|
+
let settings = {};
|
|
480
|
+
|
|
481
|
+
if (await fs.exists(settingsPath)) {
|
|
482
|
+
settings = await fs.readJson(settingsPath);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Add SimpleMem MCP server
|
|
486
|
+
settings.mcpServers = settings.mcpServers || {};
|
|
487
|
+
settings.mcpServers.simplemem = {
|
|
488
|
+
command: 'docker',
|
|
489
|
+
args: [
|
|
490
|
+
'exec', '-i', 'simplemem-mcp',
|
|
491
|
+
'python', '-m', 'simplemem_mcp.server',
|
|
492
|
+
'--project', projectName
|
|
493
|
+
]
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
await fs.writeJson(settingsPath, settings, { spaces: 2 });
|
|
497
|
+
console.log(chalk.green(' ✓ Added SimpleMem MCP server to settings.json'));
|
|
498
|
+
|
|
499
|
+
// 4. Copy memory skills
|
|
500
|
+
const skillsDir = path.join(claudeDir, 'skills', 'memory');
|
|
501
|
+
const packageRoot = getPackageRoot();
|
|
502
|
+
const memorySkillsSource = path.join(packageRoot, 'templates', 'skills', 'memory');
|
|
503
|
+
|
|
504
|
+
if (await fs.exists(memorySkillsSource)) {
|
|
505
|
+
await fs.ensureDir(skillsDir);
|
|
506
|
+
await fs.copy(memorySkillsSource, skillsDir, { overwrite: true });
|
|
507
|
+
console.log(chalk.green(' ✓ Copied memory skills (remember, recall, reflect)'));
|
|
508
|
+
} else {
|
|
509
|
+
console.log(chalk.yellow(' ⚠ Memory skills templates not found in package'));
|
|
510
|
+
console.log(chalk.gray(' Skills will need to be created manually'));
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// 5. Create agent-memory directory
|
|
514
|
+
const agentMemoryDir = path.join(claudeDir, 'agent-memory');
|
|
515
|
+
await fs.ensureDir(agentMemoryDir);
|
|
516
|
+
console.log(chalk.green(' ✓ Created agent-memory directory'));
|
|
517
|
+
|
|
518
|
+
// 6. Create memory config file
|
|
519
|
+
const memoryConfigPath = path.join(claudeDir, 'memory-config.yaml');
|
|
520
|
+
const memoryConfig = `# SimpleMem Configuration
|
|
521
|
+
# This file configures the long-term memory system
|
|
522
|
+
|
|
523
|
+
enabled: true
|
|
524
|
+
project: ${projectName}
|
|
525
|
+
|
|
526
|
+
# MCP Server (configured in settings.json)
|
|
527
|
+
# Tools available:
|
|
528
|
+
# - memory_add: Store new memory
|
|
529
|
+
# - memory_search: Semantic search
|
|
530
|
+
# - memory_get_context: Get context by intent
|
|
531
|
+
# - memory_consolidate: Synthesize patterns
|
|
532
|
+
|
|
533
|
+
# Skills available:
|
|
534
|
+
# - /remember: Store important information
|
|
535
|
+
# - /recall: Search memories
|
|
536
|
+
# - /reflect: Consolidate patterns
|
|
537
|
+
`;
|
|
538
|
+
await fs.writeFile(memoryConfigPath, memoryConfig);
|
|
539
|
+
console.log(chalk.green(' ✓ Created memory-config.yaml'));
|
|
540
|
+
|
|
541
|
+
console.log('');
|
|
542
|
+
console.log(chalk.cyan(' SimpleMem is now enabled!'));
|
|
543
|
+
console.log(chalk.gray(' Use /remember, /recall, /reflect skills'));
|
|
544
|
+
console.log(chalk.gray(' Or call memory_add, memory_search MCP tools directly'));
|
|
545
|
+
}
|
|
546
|
+
|
package/src/commands/list.js
CHANGED
|
@@ -33,34 +33,38 @@ export async function listCommand() {
|
|
|
33
33
|
console.log('');
|
|
34
34
|
|
|
35
35
|
// Table header
|
|
36
|
-
console.log(chalk.gray('
|
|
37
|
-
console.log(chalk.gray('│') + chalk.white(' Agent ') + chalk.gray('│') + chalk.white('
|
|
38
|
-
console.log(chalk.gray('
|
|
36
|
+
console.log(chalk.gray('┌─────────────────┬─────────────┬──────────┬────────────────────────────┐'));
|
|
37
|
+
console.log(chalk.gray('│') + chalk.white(' Agent ') + chalk.gray('│') + chalk.white(' Format ') + chalk.gray('│') + chalk.white(' Skills ') + chalk.gray('│') + chalk.white(' Description ') + chalk.gray('│'));
|
|
38
|
+
console.log(chalk.gray('├─────────────────┼─────────────┼──────────┼────────────────────────────┤'));
|
|
39
39
|
|
|
40
40
|
// Table rows
|
|
41
41
|
for (const agent of agents) {
|
|
42
42
|
const name = agent.name.padEnd(15).slice(0, 15);
|
|
43
|
-
const
|
|
43
|
+
const format = (agent.format === 'new' ? 'new (.md)' : 'legacy (dir)').padEnd(11).slice(0, 11);
|
|
44
|
+
const skillsCount = String(agent.skills?.length || 0).padEnd(8).slice(0, 8);
|
|
44
45
|
|
|
45
|
-
// Format
|
|
46
|
-
let
|
|
47
|
-
if (agent.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
.join(', ');
|
|
52
|
-
variantsStr = v.padEnd(36).slice(0, 36);
|
|
46
|
+
// Format description
|
|
47
|
+
let desc = '';
|
|
48
|
+
if (agent.format === 'new' && agent.description) {
|
|
49
|
+
desc = agent.description.substring(0, 26).padEnd(26);
|
|
50
|
+
} else if (agent.variants?.base_role) {
|
|
51
|
+
desc = `Role: ${agent.variants.base_role}`.substring(0, 26).padEnd(26);
|
|
53
52
|
} else {
|
|
54
|
-
|
|
53
|
+
desc = '(no description)'.padEnd(26);
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
|
|
56
|
+
const formatColor = agent.format === 'new' ? chalk.green : chalk.yellow;
|
|
57
|
+
console.log(chalk.gray('│') + chalk.cyan(name) + chalk.gray('│') + formatColor(format) + chalk.gray('│') + chalk.white(skillsCount) + chalk.gray('│') + chalk.gray(desc) + chalk.gray('│'));
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
// Table footer
|
|
61
|
-
console.log(chalk.gray('
|
|
61
|
+
console.log(chalk.gray('└─────────────────┴─────────────┴──────────┴────────────────────────────┘'));
|
|
62
62
|
|
|
63
63
|
console.log('');
|
|
64
|
-
console.log(chalk.gray('
|
|
64
|
+
console.log(chalk.gray('To use an agent:'));
|
|
65
|
+
console.log(chalk.cyan(' /<agent-name> <task>'));
|
|
66
|
+
console.log(chalk.gray(' or Claude will auto-delegate based on task description'));
|
|
67
|
+
console.log('');
|
|
68
|
+
console.log(chalk.gray('View agent details:'));
|
|
65
69
|
console.log(chalk.cyan(' npx @wipal/agent-team switch <name>'));
|
|
66
70
|
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projects command - Manage all registered projects
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import {
|
|
7
|
+
listProjects,
|
|
8
|
+
listValidProjects,
|
|
9
|
+
pruneProjects,
|
|
10
|
+
getProject,
|
|
11
|
+
unregisterProject
|
|
12
|
+
} from '../utils/global-registry.js';
|
|
13
|
+
import { getAgents, isInitialized } from '../utils/file-utils.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Projects command handler
|
|
17
|
+
*/
|
|
18
|
+
export async function projectsCommand(options) {
|
|
19
|
+
if (options.prune) {
|
|
20
|
+
await pruneCommand();
|
|
21
|
+
} else if (options.register) {
|
|
22
|
+
await registerCurrentProject();
|
|
23
|
+
} else {
|
|
24
|
+
await listCommand(options);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* List all registered projects
|
|
30
|
+
*/
|
|
31
|
+
async function listCommand(options) {
|
|
32
|
+
console.log(chalk.blue('📁 Registered Projects'));
|
|
33
|
+
console.log('');
|
|
34
|
+
|
|
35
|
+
const projects = await listValidProjects();
|
|
36
|
+
|
|
37
|
+
if (projects.length === 0) {
|
|
38
|
+
console.log(chalk.yellow('No projects registered yet.'));
|
|
39
|
+
console.log('');
|
|
40
|
+
console.log(chalk.gray('Projects are automatically registered when you run:'));
|
|
41
|
+
console.log(chalk.cyan(' npx @wipal/agent-team init'));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Separate valid and invalid
|
|
46
|
+
const validProjects = projects.filter(p => p.valid);
|
|
47
|
+
const invalidProjects = projects.filter(p => !p.valid);
|
|
48
|
+
|
|
49
|
+
// Show valid projects
|
|
50
|
+
if (validProjects.length > 0) {
|
|
51
|
+
console.log(chalk.green(`Valid Projects (${validProjects.length}):`));
|
|
52
|
+
console.log('');
|
|
53
|
+
|
|
54
|
+
for (const project of validProjects) {
|
|
55
|
+
const lastAccessed = project.last_accessed
|
|
56
|
+
? new Date(project.last_accessed).toLocaleDateString()
|
|
57
|
+
: 'Never';
|
|
58
|
+
|
|
59
|
+
console.log(chalk.cyan(` ${project.name}`));
|
|
60
|
+
console.log(chalk.gray(` Path: ${project.path}`));
|
|
61
|
+
console.log(chalk.gray(` Agents: ${project.agents_count || 0}`));
|
|
62
|
+
console.log(chalk.gray(` Last accessed: ${lastAccessed}`));
|
|
63
|
+
console.log('');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Show invalid projects
|
|
68
|
+
if (invalidProjects.length > 0) {
|
|
69
|
+
console.log(chalk.yellow(`Invalid Projects (${invalidProjects.length}):`));
|
|
70
|
+
console.log('');
|
|
71
|
+
|
|
72
|
+
for (const project of invalidProjects) {
|
|
73
|
+
console.log(chalk.red(` ${project.name}`));
|
|
74
|
+
console.log(chalk.gray(` Path: ${project.path}`));
|
|
75
|
+
console.log(chalk.gray(` Reason: ${project.reason}`));
|
|
76
|
+
console.log('');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
console.log(chalk.gray('Run with --prune to remove invalid entries'));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log(chalk.gray(`Registry location: ~/.agent-team/registry.json`));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Prune invalid project entries
|
|
87
|
+
*/
|
|
88
|
+
async function pruneCommand() {
|
|
89
|
+
console.log(chalk.blue('🧹 Pruning invalid project entries...'));
|
|
90
|
+
console.log('');
|
|
91
|
+
|
|
92
|
+
const result = await pruneProjects();
|
|
93
|
+
|
|
94
|
+
if (result.removed_count === 0) {
|
|
95
|
+
console.log(chalk.green('✓ No invalid entries found'));
|
|
96
|
+
} else {
|
|
97
|
+
console.log(chalk.green(`✓ Removed ${result.removed_count} invalid entries:`));
|
|
98
|
+
console.log('');
|
|
99
|
+
|
|
100
|
+
for (const removed of result.removed) {
|
|
101
|
+
console.log(chalk.gray(` - ${removed.name} (${removed.reason})`));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Register current project
|
|
108
|
+
*/
|
|
109
|
+
async function registerCurrentProject() {
|
|
110
|
+
const projectRoot = process.cwd();
|
|
111
|
+
|
|
112
|
+
if (!(await isInitialized(projectRoot))) {
|
|
113
|
+
console.log(chalk.red('❌ Current directory is not initialized'));
|
|
114
|
+
console.log(chalk.gray(' Run `npx @wipal/agent-team init` first'));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const agents = await getAgents(projectRoot);
|
|
119
|
+
const { registerProject } = await import('../utils/global-registry.js');
|
|
120
|
+
|
|
121
|
+
await registerProject(projectRoot, {
|
|
122
|
+
agents_count: agents.length
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
console.log(chalk.green('✓ Project registered successfully'));
|
|
126
|
+
console.log(chalk.gray(` Path: ${projectRoot}`));
|
|
127
|
+
}
|