@wipal/agent-team 1.0.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 (89) hide show
  1. package/.claude/rules/common/general-rules.md +141 -0
  2. package/.claude/rules/lessons/lessons.md +91 -0
  3. package/.claude/rules/role-rules/dev-fe-rules.md +146 -0
  4. package/.claude/rules/role-rules/sa-rules.md +226 -0
  5. package/.claude/skills/SKILL-INDEX.md +299 -0
  6. package/.claude/skills/community/security-validator/SKILL.md +392 -0
  7. package/.claude/skills/core/agent-creation/SKILL.md +338 -0
  8. package/.claude/skills/core/code-review/SKILL.md +154 -0
  9. package/.claude/skills/core/git-automation/SKILL.md +93 -0
  10. package/.claude/skills/core/retrospect-work/SKILL.md +172 -0
  11. package/.claude/skills/domain/architecture/adr-writing/SKILL.md +254 -0
  12. package/.claude/skills/domain/architecture/adr-writing/references/adr-best-practices.md +257 -0
  13. package/.claude/skills/domain/architecture/adr-writing/references/adr-examples.md +246 -0
  14. package/.claude/skills/domain/architecture/adr-writing/references/adr-template.md +160 -0
  15. package/.claude/skills/domain/architecture/architecture-patterns/SKILL.md +316 -0
  16. package/.claude/skills/domain/architecture/architecture-patterns/references/event-driven.md +393 -0
  17. package/.claude/skills/domain/architecture/architecture-patterns/references/microservices.md +315 -0
  18. package/.claude/skills/domain/architecture/architecture-patterns/references/monolith.md +321 -0
  19. package/.claude/skills/domain/architecture/architecture-patterns/references/serverless.md +457 -0
  20. package/.claude/skills/domain/architecture/performance-engineering/SKILL.md +227 -0
  21. package/.claude/skills/domain/architecture/performance-engineering/references/benchmarking.md +336 -0
  22. package/.claude/skills/domain/architecture/performance-engineering/references/caching-strategies.md +284 -0
  23. package/.claude/skills/domain/architecture/performance-engineering/references/optimization.md +298 -0
  24. package/.claude/skills/domain/architecture/security-architecture/SKILL.md +206 -0
  25. package/.claude/skills/domain/architecture/security-architecture/references/auth-patterns.md +209 -0
  26. package/.claude/skills/domain/architecture/security-architecture/references/compliance.md +246 -0
  27. package/.claude/skills/domain/architecture/security-architecture/references/threat-modeling.md +219 -0
  28. package/.claude/skills/domain/architecture/system-design/SKILL.md +227 -0
  29. package/.claude/skills/domain/architecture/system-design/references/distributed-systems.md +231 -0
  30. package/.claude/skills/domain/architecture/system-design/references/resilience.md +344 -0
  31. package/.claude/skills/domain/architecture/system-design/references/scalability.md +303 -0
  32. package/.claude/skills/domain/architecture/tech-selection/SKILL.md +192 -0
  33. package/.claude/skills/domain/architecture/tech-selection/references/build-vs-buy.md +258 -0
  34. package/.claude/skills/domain/architecture/tech-selection/references/evaluation-framework.md +203 -0
  35. package/.claude/skills/domain/architecture/tech-selection/references/tech-radar.md +257 -0
  36. package/.claude/skills/domain/backend/api-design/SKILL.md +121 -0
  37. package/.claude/skills/domain/backend/database-design/SKILL.md +156 -0
  38. package/.claude/skills/domain/backend/performance-be/SKILL.md +210 -0
  39. package/.claude/skills/domain/backend/security/SKILL.md +138 -0
  40. package/.claude/skills/domain/backend/testing-be/SKILL.md +203 -0
  41. package/.claude/skills/domain/devops/ci-cd/SKILL.md +188 -0
  42. package/.claude/skills/domain/devops/containerization/SKILL.md +177 -0
  43. package/.claude/skills/domain/devops/deployment/SKILL.md +198 -0
  44. package/.claude/skills/domain/devops/infrastructure-as-code/SKILL.md +178 -0
  45. package/.claude/skills/domain/devops/monitoring/SKILL.md +163 -0
  46. package/.claude/skills/domain/frontend/accessibility/SKILL.md +179 -0
  47. package/.claude/skills/domain/frontend/frontend-design/SKILL.md +138 -0
  48. package/.claude/skills/domain/frontend/performance-fe/SKILL.md +195 -0
  49. package/.claude/skills/domain/frontend/state-management/SKILL.md +190 -0
  50. package/.claude/skills/domain/frontend/testing-fe/SKILL.md +193 -0
  51. package/.claude/skills/domain/product/requirements-gathering/SKILL.md +136 -0
  52. package/.claude/skills/domain/product/roadmap-planning/SKILL.md +169 -0
  53. package/.claude/skills/domain/product/sprint-planning/SKILL.md +151 -0
  54. package/.claude/skills/domain/product/stakeholder-communication/SKILL.md +162 -0
  55. package/.claude/skills/domain/product/user-stories/SKILL.md +141 -0
  56. package/.claude/skills/domain/quality/bug-reporting/SKILL.md +150 -0
  57. package/.claude/skills/domain/quality/regression-testing/SKILL.md +178 -0
  58. package/.claude/skills/domain/quality/test-automation/SKILL.md +185 -0
  59. package/.claude/skills/domain/quality/test-planning/SKILL.md +177 -0
  60. package/.claude/skills/leadership/code-review-advanced/SKILL.md +167 -0
  61. package/.claude/skills/leadership/mentoring/SKILL.md +151 -0
  62. package/.claude/skills/leadership/technical-debt/SKILL.md +166 -0
  63. package/.claude/skills/leadership/technical-decision/SKILL.md +160 -0
  64. package/.claude/skills/security-reports/.gitkeep +0 -0
  65. package/.claude/skills/skills-registry.yaml +441 -0
  66. package/README.md +232 -0
  67. package/bin/agent-team.js +107 -0
  68. package/package.json +51 -0
  69. package/src/commands/add.js +227 -0
  70. package/src/commands/init.js +136 -0
  71. package/src/commands/list.js +66 -0
  72. package/src/commands/remove.js +71 -0
  73. package/src/commands/switch.js +53 -0
  74. package/src/index.js +11 -0
  75. package/src/interactive/prompts.js +153 -0
  76. package/src/server/api/agents.js +150 -0
  77. package/src/server/api/roles.js +97 -0
  78. package/src/server/api/skills.js +79 -0
  79. package/src/server/index.js +78 -0
  80. package/src/ui/agents.html +174 -0
  81. package/src/ui/css/styles.css +470 -0
  82. package/src/ui/index.html +107 -0
  83. package/src/ui/roles.html +371 -0
  84. package/src/ui/skills.html +332 -0
  85. package/src/utils/file-utils.js +193 -0
  86. package/src/utils/skill-resolver.js +594 -0
  87. package/src/utils/skill-scanner.js +154 -0
  88. package/templates/CLAUDE.md.tmpl +42 -0
  89. package/templates/knowledge.md.tmpl +31 -0
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Roles API Routes
3
+ */
4
+
5
+ import { Router } from 'express';
6
+ import fs from 'fs-extra';
7
+ import path from 'path';
8
+ import yaml from 'js-yaml';
9
+ import { getPackageRoot, getClaudeDir } from '../../utils/file-utils.js';
10
+
11
+ const router = Router();
12
+
13
+ /**
14
+ * Get roles configuration
15
+ */
16
+ router.get('/', async (req, res) => {
17
+ try {
18
+ const projectRoot = req.app.get('projectRoot');
19
+
20
+ // Load default config
21
+ const defaultPath = path.join(getPackageRoot(), 'config', 'roles.yaml');
22
+ const defaultConfig = await fs.exists(defaultPath)
23
+ ? yaml.load(await fs.readFile(defaultPath, 'utf-8'))
24
+ : { roles: {} };
25
+
26
+ // Load project override
27
+ const projectPath = path.join(getClaudeDir(projectRoot), 'roles.yaml');
28
+ const projectConfig = await fs.exists(projectPath)
29
+ ? yaml.load(await fs.readFile(projectPath, 'utf-8'))
30
+ : { roles: {} };
31
+
32
+ // Merge
33
+ const merged = {
34
+ ...defaultConfig,
35
+ roles: {
36
+ ...defaultConfig.roles,
37
+ ...projectConfig.roles
38
+ }
39
+ };
40
+
41
+ res.json(merged);
42
+ } catch (error) {
43
+ res.status(500).json({ error: error.message });
44
+ }
45
+ });
46
+
47
+ /**
48
+ * Update roles configuration (project-level only)
49
+ */
50
+ router.put('/', async (req, res) => {
51
+ try {
52
+ const projectRoot = req.app.get('projectRoot');
53
+ const configPath = path.join(getClaudeDir(projectRoot), 'roles.yaml');
54
+
55
+ // Validate YAML
56
+ const content = yaml.dump(req.body);
57
+
58
+ await fs.ensureDir(path.dirname(configPath));
59
+ await fs.writeFile(configPath, content, 'utf-8');
60
+
61
+ res.json({ success: true, message: 'Configuration saved' });
62
+ } catch (error) {
63
+ res.status(500).json({ error: error.message });
64
+ }
65
+ });
66
+
67
+ /**
68
+ * Get role details
69
+ */
70
+ router.get('/:name', async (req, res) => {
71
+ try {
72
+ const { name } = req.params;
73
+ const projectRoot = req.app.get('projectRoot');
74
+
75
+ // Load configs
76
+ const defaultPath = path.join(getPackageRoot(), 'config', 'roles.yaml');
77
+ const defaultConfig = yaml.load(await fs.readFile(defaultPath, 'utf-8'));
78
+
79
+ const projectPath = path.join(getClaudeDir(projectRoot), 'roles.yaml');
80
+ const projectConfig = await fs.exists(projectPath)
81
+ ? yaml.load(await fs.readFile(projectPath, 'utf-8'))
82
+ : { roles: {} };
83
+
84
+ // Get role (project override takes precedence)
85
+ const role = projectConfig.roles?.[name] || defaultConfig.roles?.[name];
86
+
87
+ if (!role) {
88
+ return res.status(404).json({ error: 'Role not found' });
89
+ }
90
+
91
+ res.json({ name, ...role });
92
+ } catch (error) {
93
+ res.status(500).json({ error: error.message });
94
+ }
95
+ });
96
+
97
+ export default router;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Skills API Routes
3
+ */
4
+
5
+ import { Router } from 'express';
6
+ import { getSkills, getCategories } from '../../utils/skill-scanner.js';
7
+ import { getPackageRoot } from '../../utils/file-utils.js';
8
+ import path from 'path';
9
+ import fs from 'fs-extra';
10
+
11
+ const router = Router();
12
+
13
+ /**
14
+ * List all available skills
15
+ */
16
+ router.get('/', async (req, res) => {
17
+ try {
18
+ const skills = await getSkills();
19
+ res.json(skills);
20
+ } catch (error) {
21
+ res.status(500).json({ error: error.message });
22
+ }
23
+ });
24
+
25
+ /**
26
+ * Get all categories
27
+ */
28
+ router.get('/categories', async (req, res) => {
29
+ try {
30
+ const skills = await getSkills();
31
+ const categories = getCategories(skills);
32
+ res.json(categories);
33
+ } catch (error) {
34
+ res.status(500).json({ error: error.message });
35
+ }
36
+ });
37
+
38
+ /**
39
+ * Get skill by name
40
+ */
41
+ router.get('/:name', async (req, res) => {
42
+ try {
43
+ const { name } = req.params;
44
+ const skills = await getSkills();
45
+ const skill = skills.find(s => s.name === name);
46
+
47
+ if (!skill) {
48
+ return res.status(404).json({ error: 'Skill not found' });
49
+ }
50
+
51
+ res.json(skill);
52
+ } catch (error) {
53
+ res.status(500).json({ error: error.message });
54
+ }
55
+ });
56
+
57
+ /**
58
+ * Get skill content (SKILL.md)
59
+ */
60
+ router.get('/:name/content', async (req, res) => {
61
+ try {
62
+ const { name } = req.params;
63
+ const skills = await getSkills();
64
+ const skill = skills.find(s => s.name === name);
65
+
66
+ if (!skill) {
67
+ return res.status(404).json({ error: 'Skill not found' });
68
+ }
69
+
70
+ const skillPath = path.join(skill.path, 'SKILL.md');
71
+ const content = await fs.readFile(skillPath, 'utf-8');
72
+
73
+ res.type('text/markdown').send(content);
74
+ } catch (error) {
75
+ res.status(500).json({ error: error.message });
76
+ }
77
+ });
78
+
79
+ export default router;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Express Server for Agent Team UI Dashboard
3
+ * Lightweight server with HTMX-based UI
4
+ */
5
+
6
+ import express from 'express';
7
+ import path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ import open from 'open';
10
+ import agentsRouter from './api/agents.js';
11
+ import rolesRouter from './api/roles.js';
12
+ import skillsRouter from './api/skills.js';
13
+
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = path.dirname(__filename);
16
+
17
+ const DEFAULT_PORT = 3456;
18
+
19
+ /**
20
+ * Create Express app
21
+ */
22
+ export function createApp(projectRoot = process.cwd()) {
23
+ const app = express();
24
+
25
+ // Store project root for use in routes
26
+ app.set('projectRoot', projectRoot);
27
+
28
+ // Middleware
29
+ app.use(express.json());
30
+ app.use(express.urlencoded({ extended: true }));
31
+
32
+ // Static files
33
+ const uiDir = path.join(__dirname, '..', 'ui');
34
+ app.use('/ui', express.static(uiDir));
35
+
36
+ // API Routes
37
+ app.use('/api/agents', agentsRouter);
38
+ app.use('/api/roles', rolesRouter);
39
+ app.use('/api/skills', skillsRouter);
40
+
41
+ // Main page redirect
42
+ app.get('/', (req, res) => {
43
+ res.redirect('/ui/');
44
+ });
45
+
46
+ return app;
47
+ }
48
+
49
+ /**
50
+ * Start server
51
+ */
52
+ export async function startServer(options = {}) {
53
+ const { port = DEFAULT_PORT, open: openBrowser = true, projectRoot = process.cwd() } = options;
54
+
55
+ const app = createApp(projectRoot);
56
+
57
+ return new Promise((resolve) => {
58
+ const server = app.listen(port, () => {
59
+ const url = `http://localhost:${port}`;
60
+ console.log('');
61
+ console.log(`🚀 Agent Team UI running at: ${url}`);
62
+ console.log('');
63
+
64
+ if (openBrowser) {
65
+ open(url).catch(() => {
66
+ console.log(`Please open ${url} in your browser`);
67
+ });
68
+ }
69
+
70
+ resolve({ server, url });
71
+ });
72
+ });
73
+ }
74
+
75
+ // Run if called directly
76
+ if (import.meta.url === `file://${process.argv[1]}`) {
77
+ startServer();
78
+ }
@@ -0,0 +1,174 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Agents - Agent Team Dashboard</title>
7
+ <script src="https://unpkg.com/htmx.org@1.9.10"></script>
8
+ <script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
9
+ <link rel="stylesheet" href="/ui/css/styles.css">
10
+ </head>
11
+ <body>
12
+ <div class="container" x-data="agentApp()">
13
+ <!-- Header -->
14
+ <header class="header">
15
+ <h1>🤖 Agent Management</h1>
16
+ <p class="subtitle">Create and manage AI agents</p>
17
+ </header>
18
+
19
+ <!-- Navigation -->
20
+ <nav class="nav">
21
+ <a href="/ui/" class="nav-link">Dashboard</a>
22
+ <a href="/ui/agents.html" class="nav-link active">Agents</a>
23
+ <a href="/ui/skills.html" class="nav-link">Skills</a>
24
+ <a href="/ui/roles.html" class="nav-link">Roles</a>
25
+ </nav>
26
+
27
+ <!-- Add Agent Button -->
28
+ <div class="actions-bar">
29
+ <button class="btn btn-primary" @click="showAddModal = true">
30
+ ➕ Add New Agent
31
+ </button>
32
+ </div>
33
+
34
+ <!-- Agents List -->
35
+ <section class="section">
36
+ <div id="agents-grid" hx-get="/api/agents" hx-trigger="load, refreshAgents from:body">
37
+ <div class="loading">Loading agents...</div>
38
+ </div>
39
+ </section>
40
+
41
+ <!-- Add Agent Modal -->
42
+ <div class="modal-overlay" x-show="showAddModal" x-cloak
43
+ @click.self="showAddModal = false"
44
+ @keydown.escape.window="showAddModal = false">
45
+ <div class="modal">
46
+ <div class="modal-header">
47
+ <h2>Add New Agent</h2>
48
+ <button class="modal-close" @click="showAddModal = false">&times;</button>
49
+ </div>
50
+
51
+ <div class="modal-body">
52
+ <!-- Step 1: Basic Info -->
53
+ <div class="form-group">
54
+ <label>Agent Name</label>
55
+ <input type="text" x-model="newAgent.name" placeholder="my-agent"
56
+ class="input" pattern="[a-z0-9-]+">
57
+ <small class="hint">Use lowercase letters, numbers, and hyphens</small>
58
+ </div>
59
+
60
+ <!-- Step 2: Select Role -->
61
+ <div class="form-group">
62
+ <label>Role</label>
63
+ <div class="role-selector" hx-get="/api/agents/meta/roles" hx-trigger="load">
64
+ <div class="loading">Loading roles...</div>
65
+ </div>
66
+ </div>
67
+
68
+ <!-- Step 3: Select Variants (shown when role selected) -->
69
+ <div x-show="newAgent.role" x-cloak class="variants-section">
70
+ <h3>Select Variants</h3>
71
+ <div id="variants-container"
72
+ hx-get="/api/agents/meta/variants/"
73
+ :hx-get="'/api/agents/meta/variants/' + newAgent.role"
74
+ hx-trigger="roleSelected from:body">
75
+ <div class="loading">Loading variants...</div>
76
+ </div>
77
+ </div>
78
+
79
+ <!-- Step 4: Preview Skills -->
80
+ <div x-show="newAgent.role" x-cloak class="skills-preview">
81
+ <h3>Skills Preview</h3>
82
+ <div id="skills-preview"
83
+ hx-post="/api/agents/preview-skills"
84
+ hx-include="[name='variants']"
85
+ hx-vals='{"role": newAgent.role}'
86
+ hx-trigger="load, change from:.variant-checkbox">
87
+ <div class="loading">Calculating skills...</div>
88
+ </div>
89
+ </div>
90
+ </div>
91
+
92
+ <div class="modal-footer">
93
+ <button class="btn btn-secondary" @click="showAddModal = false">Cancel</button>
94
+ <button class="btn btn-primary" @click="createAgent()"
95
+ :disabled="!newAgent.name || !newAgent.role">
96
+ Create Agent
97
+ </button>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ </div>
102
+
103
+ <script>
104
+ function agentApp() {
105
+ return {
106
+ showAddModal: false,
107
+ newAgent: {
108
+ name: '',
109
+ role: '',
110
+ variants: {}
111
+ },
112
+
113
+ selectRole(role) {
114
+ this.newAgent.role = role;
115
+ // Trigger variant loading
116
+ htmx.trigger(document.body, 'roleSelected', { role });
117
+ },
118
+
119
+ toggleVariant(category, value) {
120
+ if (this.newAgent.variants[category] === value) {
121
+ delete this.newAgent.variants[category];
122
+ } else {
123
+ this.newAgent.variants[category] = value;
124
+ }
125
+ },
126
+
127
+ async createAgent() {
128
+ try {
129
+ const response = await fetch('/api/agents', {
130
+ method: 'POST',
131
+ headers: { 'Content-Type': 'application/json' },
132
+ body: JSON.stringify(this.newAgent)
133
+ });
134
+
135
+ if (response.ok) {
136
+ this.showAddModal = false;
137
+ this.resetForm();
138
+ htmx.trigger(document.body, 'refreshAgents');
139
+ alert('Agent created successfully!');
140
+ } else {
141
+ const error = await response.json();
142
+ alert('Error: ' + error.error);
143
+ }
144
+ } catch (error) {
145
+ alert('Error creating agent: ' + error.message);
146
+ }
147
+ },
148
+
149
+ resetForm() {
150
+ this.newAgent = { name: '', role: '', variants: {} };
151
+ }
152
+ }
153
+ }
154
+
155
+ // Transform role list to radio buttons
156
+ document.body.addEventListener('htmx:beforeSwap', function(evt) {
157
+ if (evt.detail.pathInfo.requestPath.includes('/meta/roles')) {
158
+ try {
159
+ const roles = JSON.parse(evt.detail.xhr.response);
160
+ evt.detail.xhr.response = roles.map(r => `
161
+ <label class="role-option" :class="{'selected': newAgent.role === '${r.name}'}">
162
+ <input type="radio" name="role" value="${r.name}" @click="selectRole('${r.name}')">
163
+ <div class="role-info">
164
+ <strong>${r.name}</strong>
165
+ <p>${r.description}</p>
166
+ </div>
167
+ </label>
168
+ `).join('');
169
+ } catch (e) {}
170
+ }
171
+ });
172
+ </script>
173
+ </body>
174
+ </html>