orchestr8 2.1.3
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/.blueprint/agents/AGENT_BA_CASS.md +400 -0
- package/.blueprint/agents/AGENT_DEVELOPER_CODEY.md +476 -0
- package/.blueprint/agents/AGENT_SPECIFICATION_ALEX.md +165 -0
- package/.blueprint/agents/AGENT_TESTER_NIGEL.md +249 -0
- package/.blueprint/templates/FEATURE_SPEC.md +125 -0
- package/.blueprint/templates/SYSTEM_SPEC.md +128 -0
- package/.blueprint/ways_of_working/DEVELOPMENT_RITUAL.md +142 -0
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/SKILL.md +381 -0
- package/bin/cli.js +93 -0
- package/package.json +35 -0
- package/src/index.js +5 -0
- package/src/init.js +107 -0
- package/src/orchestrator.js +217 -0
- package/src/skills.js +93 -0
- package/src/update.js +105 -0
package/src/init.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const readline = require('readline');
|
|
4
|
+
|
|
5
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
6
|
+
const TARGET_DIR = process.cwd();
|
|
7
|
+
|
|
8
|
+
async function prompt(question) {
|
|
9
|
+
const rl = readline.createInterface({
|
|
10
|
+
input: process.stdin,
|
|
11
|
+
output: process.stdout
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
return new Promise((resolve) => {
|
|
15
|
+
rl.question(question, (answer) => {
|
|
16
|
+
rl.close();
|
|
17
|
+
resolve(answer.toLowerCase().trim());
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function copyDir(src, dest) {
|
|
23
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
24
|
+
|
|
25
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
26
|
+
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
const srcPath = path.join(src, entry.name);
|
|
29
|
+
const destPath = path.join(dest, entry.name);
|
|
30
|
+
|
|
31
|
+
if (entry.isDirectory()) {
|
|
32
|
+
copyDir(srcPath, destPath);
|
|
33
|
+
} else {
|
|
34
|
+
fs.copyFileSync(srcPath, destPath);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function updateGitignore() {
|
|
40
|
+
const gitignorePath = path.join(TARGET_DIR, '.gitignore');
|
|
41
|
+
const entriesToAdd = [
|
|
42
|
+
'# agent-workflow',
|
|
43
|
+
'.claude/implement-queue.json'
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
let content = '';
|
|
47
|
+
if (fs.existsSync(gitignorePath)) {
|
|
48
|
+
content = fs.readFileSync(gitignorePath, 'utf8');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const newEntries = entriesToAdd.filter(entry => !content.includes(entry));
|
|
52
|
+
|
|
53
|
+
if (newEntries.length > 0) {
|
|
54
|
+
const addition = '\n' + newEntries.join('\n') + '\n';
|
|
55
|
+
fs.appendFileSync(gitignorePath, addition);
|
|
56
|
+
console.log('Updated .gitignore');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function init() {
|
|
61
|
+
const blueprintSrc = path.join(PACKAGE_ROOT, '.blueprint');
|
|
62
|
+
const blueprintDest = path.join(TARGET_DIR, '.blueprint');
|
|
63
|
+
const skillSrc = path.join(PACKAGE_ROOT, 'SKILL.md');
|
|
64
|
+
const skillDest = path.join(TARGET_DIR, 'SKILL.md');
|
|
65
|
+
|
|
66
|
+
// Check if .blueprint already exists
|
|
67
|
+
if (fs.existsSync(blueprintDest)) {
|
|
68
|
+
const answer = await prompt('.blueprint directory already exists. Overwrite? (y/N): ');
|
|
69
|
+
if (answer !== 'y' && answer !== 'yes') {
|
|
70
|
+
console.log('Aborted. Use "agent-workflow update" to update existing installation.');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
fs.rmSync(blueprintDest, { recursive: true });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Check if SKILL.md already exists
|
|
77
|
+
if (fs.existsSync(skillDest)) {
|
|
78
|
+
const answer = await prompt('SKILL.md already exists. Overwrite? (y/N): ');
|
|
79
|
+
if (answer !== 'y' && answer !== 'yes') {
|
|
80
|
+
console.log('Skipping SKILL.md');
|
|
81
|
+
} else {
|
|
82
|
+
fs.copyFileSync(skillSrc, skillDest);
|
|
83
|
+
console.log('Copied SKILL.md');
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
fs.copyFileSync(skillSrc, skillDest);
|
|
87
|
+
console.log('Copied SKILL.md');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Copy .blueprint directory
|
|
91
|
+
console.log('Copying .blueprint directory...');
|
|
92
|
+
copyDir(blueprintSrc, blueprintDest);
|
|
93
|
+
console.log('Copied .blueprint directory');
|
|
94
|
+
|
|
95
|
+
// Update .gitignore
|
|
96
|
+
updateGitignore();
|
|
97
|
+
|
|
98
|
+
console.log(`
|
|
99
|
+
agent-workflow initialized successfully!
|
|
100
|
+
|
|
101
|
+
Next steps:
|
|
102
|
+
1. Add business context to .blueprint/.business_context/
|
|
103
|
+
2. Run /implement-feature in Claude Code to start your first feature
|
|
104
|
+
`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
module.exports = { init };
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const QUEUE_PATH = '.claude/implement-queue.json';
|
|
5
|
+
|
|
6
|
+
function ensureQueueDir() {
|
|
7
|
+
const dir = path.dirname(QUEUE_PATH);
|
|
8
|
+
if (!fs.existsSync(dir)) {
|
|
9
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function createEmptyQueue() {
|
|
14
|
+
return {
|
|
15
|
+
lastUpdated: new Date().toISOString(),
|
|
16
|
+
current: null,
|
|
17
|
+
alexQueue: [],
|
|
18
|
+
cassQueue: [],
|
|
19
|
+
nigelQueue: [],
|
|
20
|
+
codeyQueue: [],
|
|
21
|
+
completed: [],
|
|
22
|
+
failed: []
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function readQueue() {
|
|
27
|
+
ensureQueueDir();
|
|
28
|
+
if (!fs.existsSync(QUEUE_PATH)) {
|
|
29
|
+
const queue = createEmptyQueue();
|
|
30
|
+
writeQueue(queue);
|
|
31
|
+
return queue;
|
|
32
|
+
}
|
|
33
|
+
const content = fs.readFileSync(QUEUE_PATH, 'utf8');
|
|
34
|
+
return JSON.parse(content);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function writeQueue(queue) {
|
|
38
|
+
ensureQueueDir();
|
|
39
|
+
queue.lastUpdated = new Date().toISOString();
|
|
40
|
+
fs.writeFileSync(QUEUE_PATH, JSON.stringify(queue, null, 2));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function updateQueue(updates) {
|
|
44
|
+
const queue = readQueue();
|
|
45
|
+
Object.assign(queue, updates);
|
|
46
|
+
writeQueue(queue);
|
|
47
|
+
return queue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function setCurrent(slug, stage) {
|
|
51
|
+
const queue = readQueue();
|
|
52
|
+
queue.current = {
|
|
53
|
+
slug,
|
|
54
|
+
stage,
|
|
55
|
+
startedAt: new Date().toISOString()
|
|
56
|
+
};
|
|
57
|
+
writeQueue(queue);
|
|
58
|
+
return queue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function clearCurrent() {
|
|
62
|
+
const queue = readQueue();
|
|
63
|
+
queue.current = null;
|
|
64
|
+
writeQueue(queue);
|
|
65
|
+
return queue;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function moveToNextStage(slug, fromStage, toStage) {
|
|
69
|
+
const queue = readQueue();
|
|
70
|
+
const fromQueueName = `${fromStage}Queue`;
|
|
71
|
+
const toQueueName = `${toStage}Queue`;
|
|
72
|
+
|
|
73
|
+
// Remove from source queue
|
|
74
|
+
if (queue[fromQueueName]) {
|
|
75
|
+
queue[fromQueueName] = queue[fromQueueName].filter(item => item.slug !== slug);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Add to destination queue
|
|
79
|
+
if (!queue[toQueueName]) {
|
|
80
|
+
queue[toQueueName] = [];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const entry = { slug, movedAt: new Date().toISOString() };
|
|
84
|
+
queue[toQueueName].push(entry);
|
|
85
|
+
|
|
86
|
+
// Update current stage
|
|
87
|
+
if (queue.current && queue.current.slug === slug) {
|
|
88
|
+
queue.current.stage = toStage;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
writeQueue(queue);
|
|
92
|
+
return queue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function markCompleted(slug, metadata = {}) {
|
|
96
|
+
const queue = readQueue();
|
|
97
|
+
|
|
98
|
+
// Remove from codeyQueue
|
|
99
|
+
queue.codeyQueue = queue.codeyQueue.filter(item => item.slug !== slug);
|
|
100
|
+
|
|
101
|
+
// Add to completed
|
|
102
|
+
queue.completed.push({
|
|
103
|
+
slug,
|
|
104
|
+
completedAt: new Date().toISOString(),
|
|
105
|
+
...metadata
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Clear current if this was it
|
|
109
|
+
if (queue.current && queue.current.slug === slug) {
|
|
110
|
+
queue.current = null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
writeQueue(queue);
|
|
114
|
+
return queue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function markFailed(slug, stage, reason) {
|
|
118
|
+
const queue = readQueue();
|
|
119
|
+
|
|
120
|
+
// Remove from all stage queues
|
|
121
|
+
['alexQueue', 'cassQueue', 'nigelQueue', 'codeyQueue'].forEach(queueName => {
|
|
122
|
+
if (queue[queueName]) {
|
|
123
|
+
queue[queueName] = queue[queueName].filter(item => item.slug !== slug);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Add to failed
|
|
128
|
+
queue.failed.push({
|
|
129
|
+
slug,
|
|
130
|
+
stage,
|
|
131
|
+
reason,
|
|
132
|
+
failedAt: new Date().toISOString()
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Clear current if this was it
|
|
136
|
+
if (queue.current && queue.current.slug === slug) {
|
|
137
|
+
queue.current = null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
writeQueue(queue);
|
|
141
|
+
return queue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function resetQueue() {
|
|
145
|
+
const queue = createEmptyQueue();
|
|
146
|
+
writeQueue(queue);
|
|
147
|
+
return queue;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function getQueueStatus() {
|
|
151
|
+
const queue = readQueue();
|
|
152
|
+
return {
|
|
153
|
+
current: queue.current,
|
|
154
|
+
pending: {
|
|
155
|
+
alex: queue.alexQueue.length,
|
|
156
|
+
cass: queue.cassQueue.length,
|
|
157
|
+
nigel: queue.nigelQueue.length,
|
|
158
|
+
codey: queue.codeyQueue.length
|
|
159
|
+
},
|
|
160
|
+
completed: queue.completed.length,
|
|
161
|
+
failed: queue.failed.length
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function displayQueue() {
|
|
166
|
+
const queue = readQueue();
|
|
167
|
+
|
|
168
|
+
console.log('\nImplement Feature Queue Status');
|
|
169
|
+
console.log('==============================\n');
|
|
170
|
+
|
|
171
|
+
if (queue.current) {
|
|
172
|
+
console.log('Current:');
|
|
173
|
+
console.log(` ${queue.current.slug} (stage: ${queue.current.stage})`);
|
|
174
|
+
console.log(` Started: ${queue.current.startedAt}\n`);
|
|
175
|
+
} else {
|
|
176
|
+
console.log('Current: (none)\n');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
console.log('Queues:');
|
|
180
|
+
console.log(` Alex: ${queue.alexQueue.length} pending`);
|
|
181
|
+
console.log(` Cass: ${queue.cassQueue.length} pending`);
|
|
182
|
+
console.log(` Nigel: ${queue.nigelQueue.length} pending`);
|
|
183
|
+
console.log(` Codey: ${queue.codeyQueue.length} pending\n`);
|
|
184
|
+
|
|
185
|
+
if (queue.completed.length > 0) {
|
|
186
|
+
console.log('Completed:');
|
|
187
|
+
queue.completed.forEach(item => {
|
|
188
|
+
console.log(` - ${item.slug} (${item.completedAt})`);
|
|
189
|
+
});
|
|
190
|
+
console.log('');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (queue.failed.length > 0) {
|
|
194
|
+
console.log('Failed:');
|
|
195
|
+
queue.failed.forEach(item => {
|
|
196
|
+
console.log(` - ${item.slug} at ${item.stage}: ${item.reason}`);
|
|
197
|
+
});
|
|
198
|
+
console.log('');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
console.log(`Last updated: ${queue.lastUpdated}`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
module.exports = {
|
|
205
|
+
QUEUE_PATH,
|
|
206
|
+
readQueue,
|
|
207
|
+
writeQueue,
|
|
208
|
+
updateQueue,
|
|
209
|
+
setCurrent,
|
|
210
|
+
clearCurrent,
|
|
211
|
+
moveToNextStage,
|
|
212
|
+
markCompleted,
|
|
213
|
+
markFailed,
|
|
214
|
+
resetQueue,
|
|
215
|
+
getQueueStatus,
|
|
216
|
+
displayQueue
|
|
217
|
+
};
|
package/src/skills.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
|
|
3
|
+
const AGENT_SKILLS = {
|
|
4
|
+
alex: {
|
|
5
|
+
name: 'Alex',
|
|
6
|
+
role: 'System Specification & Chief-of-Staff',
|
|
7
|
+
skills: [
|
|
8
|
+
{ repo: 'https://github.com/waynesutton/convexskills', skill: 'avoid-feature-creep' },
|
|
9
|
+
{ repo: 'https://github.com/pproenca/dot-skills', skill: 'feature-spec' }
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
cass: {
|
|
13
|
+
name: 'Cass',
|
|
14
|
+
role: 'Story Writer / BA',
|
|
15
|
+
skills: [
|
|
16
|
+
{ repo: 'https://github.com/aj-geddes/useful-ai-prompts', skill: 'user-story-writing' }
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
nigel: {
|
|
20
|
+
name: 'Nigel',
|
|
21
|
+
role: 'Tester',
|
|
22
|
+
skills: [
|
|
23
|
+
{ repo: 'https://github.com/wshobson/agents', skill: 'javascript-testing-patterns' },
|
|
24
|
+
{ repo: 'https://github.com/wshobson/agents', skill: 'modern-javascript-patterns' }
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
codey: {
|
|
28
|
+
name: 'Codey',
|
|
29
|
+
role: 'Developer',
|
|
30
|
+
skills: [
|
|
31
|
+
{ repo: 'https://github.com/martinholovsky/claude-skills-generator', skill: 'javascript-expert' },
|
|
32
|
+
{ repo: 'https://github.com/wshobson/agents', skill: 'modern-javascript-patterns' }
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function installSkill(repo, skill) {
|
|
38
|
+
const cmd = `npx skills add ${repo} --skill ${skill}`;
|
|
39
|
+
console.log(` Running: ${cmd}`);
|
|
40
|
+
try {
|
|
41
|
+
execSync(cmd, { stdio: 'inherit' });
|
|
42
|
+
return true;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error(` Failed to install ${skill}`);
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function addSkills(agent) {
|
|
50
|
+
const agents = agent === 'all' ? Object.keys(AGENT_SKILLS) : [agent.toLowerCase()];
|
|
51
|
+
|
|
52
|
+
for (const agentKey of agents) {
|
|
53
|
+
const agentConfig = AGENT_SKILLS[agentKey];
|
|
54
|
+
|
|
55
|
+
if (!agentConfig) {
|
|
56
|
+
console.error(`Unknown agent: ${agentKey}`);
|
|
57
|
+
console.error(`Available agents: ${Object.keys(AGENT_SKILLS).join(', ')}, all`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log(`\nInstalling skills for ${agentConfig.name} (${agentConfig.role}):`);
|
|
62
|
+
|
|
63
|
+
for (const { repo, skill } of agentConfig.skills) {
|
|
64
|
+
installSkill(repo, skill);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log('\nSkills installation complete.');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function listSkills(agent) {
|
|
72
|
+
const agents = agent ? [agent.toLowerCase()] : Object.keys(AGENT_SKILLS);
|
|
73
|
+
|
|
74
|
+
console.log('\nAgent Workflow - Recommended Skills\n');
|
|
75
|
+
|
|
76
|
+
for (const agentKey of agents) {
|
|
77
|
+
const agentConfig = AGENT_SKILLS[agentKey];
|
|
78
|
+
|
|
79
|
+
if (!agentConfig) {
|
|
80
|
+
console.error(`Unknown agent: ${agentKey}`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log(`${agentConfig.name} (${agentConfig.role}):`);
|
|
85
|
+
for (const { repo, skill } of agentConfig.skills) {
|
|
86
|
+
console.log(` - ${skill}`);
|
|
87
|
+
console.log(` ${repo}`);
|
|
88
|
+
}
|
|
89
|
+
console.log('');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
module.exports = { addSkills, listSkills, AGENT_SKILLS };
|
package/src/update.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const readline = require('readline');
|
|
4
|
+
|
|
5
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
6
|
+
const TARGET_DIR = process.cwd();
|
|
7
|
+
|
|
8
|
+
// Directories that contain user content and should NOT be overwritten
|
|
9
|
+
const USER_CONTENT_DIRS = [
|
|
10
|
+
'features',
|
|
11
|
+
'system_specification',
|
|
12
|
+
'.business_context'
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
// Directories/files that should be updated
|
|
16
|
+
const UPDATABLE = [
|
|
17
|
+
'agents',
|
|
18
|
+
'templates',
|
|
19
|
+
'ways_of_working'
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
async function prompt(question) {
|
|
23
|
+
const rl = readline.createInterface({
|
|
24
|
+
input: process.stdin,
|
|
25
|
+
output: process.stdout
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
rl.question(question, (answer) => {
|
|
30
|
+
rl.close();
|
|
31
|
+
resolve(answer.toLowerCase().trim());
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function copyDir(src, dest) {
|
|
37
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
38
|
+
|
|
39
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
40
|
+
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
const srcPath = path.join(src, entry.name);
|
|
43
|
+
const destPath = path.join(dest, entry.name);
|
|
44
|
+
|
|
45
|
+
if (entry.isDirectory()) {
|
|
46
|
+
copyDir(srcPath, destPath);
|
|
47
|
+
} else {
|
|
48
|
+
fs.copyFileSync(srcPath, destPath);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function update() {
|
|
54
|
+
const blueprintDest = path.join(TARGET_DIR, '.blueprint');
|
|
55
|
+
const blueprintSrc = path.join(PACKAGE_ROOT, '.blueprint');
|
|
56
|
+
const skillSrc = path.join(PACKAGE_ROOT, 'SKILL.md');
|
|
57
|
+
const skillDest = path.join(TARGET_DIR, 'SKILL.md');
|
|
58
|
+
|
|
59
|
+
// Check if .blueprint exists
|
|
60
|
+
if (!fs.existsSync(blueprintDest)) {
|
|
61
|
+
console.log('.blueprint directory not found. Run "agent-workflow init" first.');
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log('Updating agent-workflow...');
|
|
66
|
+
console.log('(Preserving: features/, system_specification/, .business_context/)\n');
|
|
67
|
+
|
|
68
|
+
// Update each updatable directory
|
|
69
|
+
for (const dir of UPDATABLE) {
|
|
70
|
+
const srcDir = path.join(blueprintSrc, dir);
|
|
71
|
+
const destDir = path.join(blueprintDest, dir);
|
|
72
|
+
|
|
73
|
+
if (fs.existsSync(srcDir)) {
|
|
74
|
+
if (fs.existsSync(destDir)) {
|
|
75
|
+
fs.rmSync(destDir, { recursive: true });
|
|
76
|
+
}
|
|
77
|
+
copyDir(srcDir, destDir);
|
|
78
|
+
console.log(`Updated .blueprint/${dir}/`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Update SKILL.md
|
|
83
|
+
const answer = await prompt('\nUpdate SKILL.md? (Y/n): ');
|
|
84
|
+
if (answer !== 'n' && answer !== 'no') {
|
|
85
|
+
fs.copyFileSync(skillSrc, skillDest);
|
|
86
|
+
console.log('Updated SKILL.md');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
console.log(`
|
|
90
|
+
Update complete!
|
|
91
|
+
|
|
92
|
+
Updated:
|
|
93
|
+
- .blueprint/agents/
|
|
94
|
+
- .blueprint/templates/
|
|
95
|
+
- .blueprint/ways_of_working/
|
|
96
|
+
- SKILL.md
|
|
97
|
+
|
|
98
|
+
Preserved:
|
|
99
|
+
- .blueprint/features/
|
|
100
|
+
- .blueprint/system_specification/
|
|
101
|
+
- .blueprint/.business_context/
|
|
102
|
+
`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = { update };
|