@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
@@ -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 { getClaudeDir, getProjectRoot, copyRules } from '../utils/file-utils.js';
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 (!options.force) {
24
- console.log(chalk.yellow('⚠️ .claude/ directory already exists'));
25
- console.log(chalk.gray(' Use --force to overwrite'));
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
+
@@ -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(' Role ') + chalk.gray('│') + chalk.white(' Variants ') + chalk.gray('│'));
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 role = (agent.variants?.base_role || 'unknown').padEnd(11).slice(0, 11);
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 variants
46
- let variantsStr = '';
47
- if (agent.variants?.installed_variants) {
48
- const v = Object.entries(agent.variants.installed_variants)
49
- .filter(([_, val]) => val)
50
- .map(([k, val]) => `${k}=${val}`)
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
- variantsStr = '(none)'.padEnd(36);
53
+ desc = '(no description)'.padEnd(26);
55
54
  }
56
55
 
57
- console.log(chalk.gray('│') + chalk.cyan(name) + chalk.gray('│') + chalk.yellow(role) + chalk.gray('') + chalk.gray(variantsStr) + chalk.gray('│'));
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('Switch to an agent:'));
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
+ }