@fredericboyer/dev-team 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +128 -0
  2. package/bin/dev-team.js +1 -21
  3. package/dist/bin/dev-team.d.ts +1 -0
  4. package/dist/bin/dev-team.js +36 -0
  5. package/dist/bin/dev-team.js.map +1 -0
  6. package/dist/create-agent.d.ts +1 -0
  7. package/dist/create-agent.js +106 -0
  8. package/dist/create-agent.js.map +1 -0
  9. package/dist/files.d.ts +51 -0
  10. package/dist/files.js +155 -0
  11. package/dist/files.js.map +1 -0
  12. package/dist/init.d.ts +24 -0
  13. package/dist/init.js +358 -0
  14. package/dist/init.js.map +1 -0
  15. package/dist/prompts.d.ts +25 -0
  16. package/dist/prompts.js +109 -0
  17. package/dist/prompts.js.map +1 -0
  18. package/dist/scan.d.ts +15 -0
  19. package/dist/scan.js +187 -0
  20. package/dist/scan.js.map +1 -0
  21. package/dist/update.d.ts +5 -0
  22. package/dist/update.js +229 -0
  23. package/dist/update.js.map +1 -0
  24. package/package.json +30 -9
  25. package/templates/CLAUDE.md +21 -0
  26. package/templates/agent-memory/dev-team-architect/MEMORY.md +12 -0
  27. package/templates/agent-memory/dev-team-docs/MEMORY.md +12 -0
  28. package/templates/agent-memory/dev-team-lead/MEMORY.md +12 -0
  29. package/templates/agent-memory/dev-team-release/MEMORY.md +12 -0
  30. package/templates/agents/dev-team-architect.md +62 -0
  31. package/templates/agents/dev-team-deming.md +2 -1
  32. package/templates/agents/dev-team-docs.md +63 -0
  33. package/templates/agents/dev-team-lead.md +95 -0
  34. package/templates/agents/dev-team-release.md +65 -0
  35. package/templates/hooks/dev-team-post-change-review.js +63 -10
  36. package/templates/hooks/dev-team-pre-commit-gate.js +43 -14
  37. package/templates/hooks/dev-team-safety-guard.js +21 -11
  38. package/templates/hooks/dev-team-task-loop.js +17 -9
  39. package/templates/hooks/dev-team-tdd-enforce.js +42 -23
  40. package/templates/hooks/dev-team-watch-list.js +84 -0
  41. package/templates/settings.json +4 -0
  42. package/templates/skills/dev-team-audit/SKILL.md +85 -0
  43. package/templates/skills/dev-team-review/SKILL.md +68 -0
  44. package/lib/files.js +0 -160
  45. package/lib/init.js +0 -206
  46. package/lib/prompts.js +0 -123
package/lib/init.js DELETED
@@ -1,206 +0,0 @@
1
- 'use strict';
2
-
3
- const path = require('path');
4
- const {
5
- templateDir,
6
- copyFile,
7
- fileExists,
8
- dirExists,
9
- readFile,
10
- writeFile,
11
- mergeSettings,
12
- mergeClaudeMd,
13
- } = require('./files');
14
- const prompts = require('./prompts');
15
-
16
- const ALL_AGENTS = [
17
- { label: 'Voss', file: 'dev-team-voss.md', description: 'Backend Engineer' },
18
- { label: 'Mori', file: 'dev-team-mori.md', description: 'Frontend/UI Engineer' },
19
- { label: 'Szabo', file: 'dev-team-szabo.md', description: 'Security Auditor' },
20
- { label: 'Knuth', file: 'dev-team-knuth.md', description: 'Quality Auditor' },
21
- { label: 'Beck', file: 'dev-team-beck.md', description: 'Test Implementer' },
22
- { label: 'Deming', file: 'dev-team-deming.md', description: 'Tooling & DX Optimizer' },
23
- ];
24
-
25
- const QUALITY_HOOKS = [
26
- { label: 'TDD enforcement', file: 'dev-team-tdd-enforce.js', description: 'Block implementation changes without tests' },
27
- { label: 'Safety guard', file: 'dev-team-safety-guard.js', description: 'Block dangerous commands (rm -rf, force push)' },
28
- { label: 'Post-change review', file: 'dev-team-post-change-review.js', description: 'Flag which agents should review after edits' },
29
- { label: 'Pre-commit gate', file: 'dev-team-pre-commit-gate.js', description: 'Remind about reviews before committing' },
30
- { label: 'Task loop', file: 'dev-team-task-loop.js', description: 'Iterative task loop with adversarial review gates' },
31
- ];
32
-
33
- /**
34
- * Main init flow.
35
- */
36
- async function run(targetDir, flags = []) {
37
- const isAll = flags.includes('--all');
38
-
39
- console.log('\ndev-team — Adversarial AI agent team\n');
40
-
41
- // Step 1: Detect existing state
42
- const claudeDir = path.join(targetDir, '.claude');
43
- const agentsDir = path.join(claudeDir, 'agents');
44
- const hooksDir = path.join(claudeDir, 'hooks');
45
- const skillsDir = path.join(claudeDir, 'skills');
46
- const memoryDir = path.join(claudeDir, 'agent-memory');
47
- const settingsPath = path.join(claudeDir, 'settings.json');
48
- const claudeMdPath = path.join(targetDir, 'CLAUDE.md');
49
- const prefsPath = path.join(claudeDir, 'dev-team.json');
50
-
51
- console.log('Detected:');
52
- console.log(` .claude/ directory: ${dirExists(claudeDir) ? 'exists' : 'will be created'}`);
53
- console.log(` CLAUDE.md: ${fileExists(claudeMdPath) ? 'exists (will merge)' : 'will be created'}`);
54
- console.log('');
55
-
56
- // Step 2: Agent selection
57
- let selectedAgents;
58
- if (isAll) {
59
- selectedAgents = ALL_AGENTS.map((a) => a.label);
60
- } else {
61
- selectedAgents = await prompts.checkbox(
62
- 'Which agents would you like to install?',
63
- ALL_AGENTS.map((a) => ({
64
- label: a.label,
65
- description: `${a.description}`,
66
- defaultSelected: true,
67
- }))
68
- );
69
- }
70
-
71
- // Step 3: Hook selection
72
- let selectedHooks;
73
- if (isAll) {
74
- selectedHooks = QUALITY_HOOKS.map((h) => h.label);
75
- } else {
76
- selectedHooks = await prompts.checkbox(
77
- 'Which quality hooks do you want to enforce?',
78
- QUALITY_HOOKS.map((h) => ({
79
- label: h.label,
80
- description: h.description,
81
- defaultSelected: true,
82
- }))
83
- );
84
- }
85
-
86
- // Step 4: Copy agents
87
- const templates = templateDir();
88
- let agentCount = 0;
89
-
90
- for (const agent of ALL_AGENTS) {
91
- if (!selectedAgents.includes(agent.label)) continue;
92
-
93
- const src = path.join(templates, 'agents', agent.file);
94
- const dest = path.join(agentsDir, agent.file);
95
-
96
- if (fileExists(dest) && !isAll) {
97
- const overwrite = await prompts.confirm(` ${agent.file} already exists. Overwrite?`, false);
98
- if (!overwrite) continue;
99
- }
100
-
101
- copyFile(src, dest);
102
- agentCount++;
103
- }
104
-
105
- // Step 5: Create agent memory directories
106
- for (const agent of ALL_AGENTS) {
107
- if (!selectedAgents.includes(agent.label)) continue;
108
-
109
- const agentName = agent.file.replace('.md', '');
110
- const memorySrc = path.join(templates, 'agent-memory', agentName, 'MEMORY.md');
111
- const memoryDest = path.join(memoryDir, agentName, 'MEMORY.md');
112
-
113
- if (!fileExists(memoryDest)) {
114
- copyFile(memorySrc, memoryDest);
115
- }
116
- }
117
-
118
- // Step 6: Create shared team learnings
119
- const learningsSrc = path.join(templates, 'dev-team-learnings.md');
120
- const learningsDest = path.join(claudeDir, 'dev-team-learnings.md');
121
- if (!fileExists(learningsDest)) {
122
- copyFile(learningsSrc, learningsDest);
123
- }
124
-
125
- // Step 7: Copy hooks
126
- let hookCount = 0;
127
-
128
- for (const hook of QUALITY_HOOKS) {
129
- if (!selectedHooks.includes(hook.label)) continue;
130
-
131
- const src = path.join(templates, 'hooks', hook.file);
132
- const dest = path.join(hooksDir, hook.file);
133
-
134
- if (fileExists(dest) && !isAll) {
135
- const overwrite = await prompts.confirm(` ${hook.file} already exists. Overwrite?`, false);
136
- if (!overwrite) continue;
137
- }
138
-
139
- copyFile(src, dest);
140
- hookCount++;
141
- }
142
-
143
- // Step 8: Merge hook settings
144
- const settingsTemplate = JSON.parse(readFile(path.join(templates, 'settings.json')));
145
-
146
- // Filter settings to only include selected hooks
147
- const filteredSettings = { hooks: {} };
148
- const selectedHookFiles = QUALITY_HOOKS
149
- .filter((h) => selectedHooks.includes(h.label))
150
- .map((h) => h.file);
151
-
152
- for (const [event, entries] of Object.entries(settingsTemplate.hooks)) {
153
- const filteredEntries = entries.map((entry) => ({
154
- ...entry,
155
- hooks: (entry.hooks || []).filter((h) =>
156
- selectedHookFiles.some((f) => h.command && h.command.includes(f))
157
- ),
158
- })).filter((entry) => entry.hooks.length > 0);
159
-
160
- if (filteredEntries.length > 0) {
161
- filteredSettings.hooks[event] = filteredEntries;
162
- }
163
- }
164
-
165
- mergeSettings(settingsPath, filteredSettings);
166
-
167
- // Step 9: Copy skills
168
- const skillsSrcDir = path.join(templates, 'skills');
169
- const skillDirs = ['dev-team-challenge', 'dev-team-task'];
170
- for (const skillDir of skillDirs) {
171
- const src = path.join(skillsSrcDir, skillDir, 'SKILL.md');
172
- const dest = path.join(skillsDir, skillDir, 'SKILL.md');
173
- if (!fileExists(dest) || isAll) {
174
- copyFile(src, dest);
175
- }
176
- }
177
-
178
- // Step 10: Merge CLAUDE.md
179
- const claudeMdTemplate = readFile(path.join(templates, 'CLAUDE.md'));
180
- const claudeResult = mergeClaudeMd(claudeMdPath, claudeMdTemplate);
181
-
182
- // Save preferences
183
- const prefs = {
184
- version: '0.1.0',
185
- agents: selectedAgents,
186
- hooks: selectedHooks,
187
- };
188
- writeFile(prefsPath, JSON.stringify(prefs, null, 2) + '\n');
189
-
190
- // Step 11: Print summary
191
- console.log('\nDone! Installed:\n');
192
- console.log(` Agents: ${selectedAgents.join(', ')} (${agentCount} files)`);
193
- console.log(` Hooks: ${selectedHooks.join(', ')} (${hookCount} files)`);
194
- console.log(` Skills: challenge, task`);
195
- console.log(` Memory: ${selectedAgents.length} agent memories + shared learnings`);
196
- console.log(` CLAUDE.md: ${claudeResult}`);
197
- console.log(` Settings: ${settingsPath}`);
198
- console.log('');
199
- console.log('Next steps:');
200
- console.log(' 1. Review installed agents in .claude/agents/');
201
- console.log(' 2. Customize agent personas and focus areas to fit your project');
202
- console.log(' 3. Run @dev-team-deming to scan for additional tooling recommendations');
203
- console.log('');
204
- }
205
-
206
- module.exports = { run };
package/lib/prompts.js DELETED
@@ -1,123 +0,0 @@
1
- 'use strict';
2
-
3
- const readline = require('readline');
4
-
5
- /**
6
- * Creates a readline interface for a single question, then closes it.
7
- */
8
- function createInterface() {
9
- return readline.createInterface({
10
- input: process.stdin,
11
- output: process.stdout,
12
- });
13
- }
14
-
15
- /**
16
- * Asks a yes/no question. Returns true for yes.
17
- */
18
- async function confirm(question, defaultYes = true) {
19
- const rl = createInterface();
20
- const hint = defaultYes ? '[Y/n]' : '[y/N]';
21
-
22
- return new Promise((resolve) => {
23
- rl.question(`${question} ${hint} `, (answer) => {
24
- rl.close();
25
- const trimmed = answer.trim().toLowerCase();
26
- if (trimmed === '') {
27
- resolve(defaultYes);
28
- } else {
29
- resolve(trimmed === 'y' || trimmed === 'yes');
30
- }
31
- });
32
- });
33
- }
34
-
35
- /**
36
- * Asks a checkbox-style question. Returns array of selected labels.
37
- * Items: [{ label, description, defaultSelected }]
38
- */
39
- async function checkbox(question, items) {
40
- const rl = createInterface();
41
-
42
- console.log(`\n${question}`);
43
- items.forEach((item, i) => {
44
- const checked = item.defaultSelected ? 'x' : ' ';
45
- console.log(` ${i + 1}. [${checked}] ${item.label} — ${item.description}`);
46
- });
47
-
48
- return new Promise((resolve) => {
49
- rl.question('\nEnter numbers to toggle (e.g., 1 3 4), or press Enter for defaults: ', (answer) => {
50
- rl.close();
51
- const trimmed = answer.trim();
52
-
53
- if (trimmed === '') {
54
- // Use defaults
55
- resolve(items.filter((item) => item.defaultSelected).map((item) => item.label));
56
- return;
57
- }
58
-
59
- const toggled = new Set(
60
- trimmed.split(/[\s,]+/).map(Number).filter((n) => n >= 1 && n <= items.length)
61
- );
62
-
63
- const selected = items
64
- .filter((item, i) => {
65
- const isDefault = item.defaultSelected;
66
- const wasToggled = toggled.has(i + 1);
67
- return isDefault ? !wasToggled : wasToggled;
68
- })
69
- .map((item) => item.label);
70
-
71
- resolve(selected);
72
- });
73
- });
74
- }
75
-
76
- /**
77
- * Asks a single-choice question. Returns the selected label.
78
- * Options: [{ label, description }]
79
- */
80
- async function select(question, options) {
81
- const rl = createInterface();
82
-
83
- console.log(`\n${question}`);
84
- options.forEach((opt, i) => {
85
- console.log(` ${i + 1}. ${opt.label} — ${opt.description}`);
86
- });
87
-
88
- return new Promise((resolve) => {
89
- rl.question('\nEnter number (default: 1): ', (answer) => {
90
- rl.close();
91
- const trimmed = answer.trim();
92
-
93
- if (trimmed === '') {
94
- resolve(options[0].label);
95
- return;
96
- }
97
-
98
- const idx = Number(trimmed) - 1;
99
- if (idx >= 0 && idx < options.length) {
100
- resolve(options[idx].label);
101
- } else {
102
- resolve(options[0].label);
103
- }
104
- });
105
- });
106
- }
107
-
108
- /**
109
- * Asks for free-text input.
110
- */
111
- async function input(question, defaultValue = '') {
112
- const rl = createInterface();
113
- const hint = defaultValue ? ` [${defaultValue}]` : '';
114
-
115
- return new Promise((resolve) => {
116
- rl.question(`${question}${hint}: `, (answer) => {
117
- rl.close();
118
- resolve(answer.trim() || defaultValue);
119
- });
120
- });
121
- }
122
-
123
- module.exports = { confirm, checkbox, select, input };