create-shhs 1.0.0 → 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/INSTALLATION-GUIDE.md +424 -0
- package/README.md +16 -8
- package/UPDATE-GUIDE.md +500 -0
- package/bin/install.js +20 -0
- package/bin/update.js +396 -0
- package/package.json +8 -6
- package/template/.ai/.shhs-version +1 -0
- package/template/.ai/agents/architecture-reviewer.md +92 -0
- package/template/.ai/agents/fitness-enforcer.md +408 -0
- package/template/.ai/agents/knowledge-curator.md +242 -0
- package/template/.ai/architecture/governance/.gitkeep +7 -0
- package/template/.ai/architecture/governance/fitness/README.md +410 -0
- package/template/.ai/architecture/governance/fitness/config.json +48 -0
- package/template/.ai/architecture/governance/fitness/exemptions.json +20 -0
- package/template/.ai/architecture/governance/fitness/rules.json +102 -0
- package/template/.ai/governance/constitution.md +260 -0
- package/template/.ai/governance/definition-of-done.md +481 -0
- package/template/.ai/knowledge/knowledge-base.md +210 -0
- package/template/.ai/reports/fitness-results.json +201 -0
- package/template/.ai/skills/context7/skill.md +458 -0
- package/template/.ai/skills/playwright/skill.md +565 -0
- package/template/.ai/skills/tdd/skill.md +416 -0
- package/template/CLAUDE.md +51 -13
package/bin/update.js
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const crypto = require('crypto');
|
|
6
|
+
|
|
7
|
+
// ANSI colors
|
|
8
|
+
const colors = {
|
|
9
|
+
reset: '\x1b[0m',
|
|
10
|
+
blue: '\x1b[34m',
|
|
11
|
+
green: '\x1b[32m',
|
|
12
|
+
yellow: '\x1b[33m',
|
|
13
|
+
red: '\x1b[31m',
|
|
14
|
+
bold: '\x1b[1m',
|
|
15
|
+
cyan: '\x1b[36m'
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const c = (color, text) => `${colors[color]}${text}${colors.reset}`;
|
|
19
|
+
|
|
20
|
+
// Parse arguments
|
|
21
|
+
const args = process.argv.slice(2);
|
|
22
|
+
const targetDir = args[0] || process.cwd();
|
|
23
|
+
|
|
24
|
+
// Flags
|
|
25
|
+
const flags = {
|
|
26
|
+
force: args.includes('--force') || args.includes('-f'),
|
|
27
|
+
dryRun: args.includes('--dry-run'),
|
|
28
|
+
help: args.includes('--help') || args.includes('-h')
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Help
|
|
32
|
+
if (flags.help) {
|
|
33
|
+
console.log(`
|
|
34
|
+
${c('blue', '╔════════════════════════════════════════════════════════╗')}
|
|
35
|
+
${c('blue', '║ Self-Healing Hybrid Swarm — Update Tool ║')}
|
|
36
|
+
${c('blue', '╚════════════════════════════════════════════════════════╝')}
|
|
37
|
+
|
|
38
|
+
${c('bold', 'Usage:')}
|
|
39
|
+
npx create-shhs update [directory] [options]
|
|
40
|
+
|
|
41
|
+
${c('bold', 'Arguments:')}
|
|
42
|
+
[directory] Target directory (default: current directory)
|
|
43
|
+
|
|
44
|
+
${c('bold', 'Options:')}
|
|
45
|
+
-f, --force Force update all files (overwrite local changes)
|
|
46
|
+
--dry-run Show what would be updated without applying changes
|
|
47
|
+
-h, --help Show this help message
|
|
48
|
+
|
|
49
|
+
${c('bold', 'Examples:')}
|
|
50
|
+
npx create-shhs update # Update current directory
|
|
51
|
+
npx create-shhs update --dry-run # Preview changes
|
|
52
|
+
npx create-shhs update --force # Force update all files
|
|
53
|
+
|
|
54
|
+
${c('bold', 'What gets updated:')}
|
|
55
|
+
.ai/agents/ Agent definitions (core agents only)
|
|
56
|
+
.ai/governance/ Constitution & Definition of Done
|
|
57
|
+
.ai/skills/ Skills (TDD, Playwright, Context7)
|
|
58
|
+
.ai/architecture/ Fitness functions
|
|
59
|
+
.ai/knowledge/ Knowledge base template
|
|
60
|
+
CLAUDE.md Governance rules (if unchanged)
|
|
61
|
+
|
|
62
|
+
${c('bold', 'What gets preserved:')}
|
|
63
|
+
.ai/ADR/ Your architectural decisions
|
|
64
|
+
.ai/contracts/ Your contracts
|
|
65
|
+
.ai/features/ Your feature contracts
|
|
66
|
+
.ai/reports/ Your reports
|
|
67
|
+
.ai/debt/ Your debt reports
|
|
68
|
+
.ai/memory/ Your patterns and anti-patterns
|
|
69
|
+
ARCHITECTURE.md Your architecture
|
|
70
|
+
|
|
71
|
+
${c('blue', 'Documentation:')} https://github.com/asaje379/shhs
|
|
72
|
+
`);
|
|
73
|
+
process.exit(0);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log(`
|
|
77
|
+
${c('blue', '╔════════════════════════════════════════════════════════╗')}
|
|
78
|
+
${c('blue', '║ Self-Healing Hybrid Swarm — Update ║')}
|
|
79
|
+
${c('blue', '╚════════════════════════════════════════════════════════╝')}
|
|
80
|
+
`);
|
|
81
|
+
|
|
82
|
+
// Resolve target
|
|
83
|
+
const target = path.resolve(targetDir);
|
|
84
|
+
|
|
85
|
+
// Validate target
|
|
86
|
+
if (!fs.existsSync(target)) {
|
|
87
|
+
console.log(`${c('red', '✗ Error:')} Directory does not exist: ${target}`);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Check if SHHS is installed
|
|
92
|
+
const shhsMarkerPath = path.join(target, '.ai');
|
|
93
|
+
if (!fs.existsSync(shhsMarkerPath)) {
|
|
94
|
+
console.log(`${c('red', '✗ Error:')} SHHS not found in this directory`);
|
|
95
|
+
console.log(`${c('yellow', ' Install first with:')} npx create-shhs`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.log(`${c('blue', 'Target:')} ${target}`);
|
|
100
|
+
console.log(`${c('blue', 'Mode:')} ${flags.dryRun ? c('yellow', 'DRY RUN') : c('green', 'UPDATE')}`);
|
|
101
|
+
console.log('');
|
|
102
|
+
|
|
103
|
+
// Template source
|
|
104
|
+
const templateDir = path.join(__dirname, '..', 'template');
|
|
105
|
+
|
|
106
|
+
if (!fs.existsSync(templateDir)) {
|
|
107
|
+
console.log(`${c('red', '✗ Error:')} Template directory not found`);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Version tracking
|
|
112
|
+
const versionFile = path.join(target, '.ai', '.shhs-version');
|
|
113
|
+
let currentVersion = '0.0.0';
|
|
114
|
+
if (fs.existsSync(versionFile)) {
|
|
115
|
+
currentVersion = fs.readFileSync(versionFile, 'utf-8').trim();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const newVersion = JSON.parse(
|
|
119
|
+
fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8')
|
|
120
|
+
).version;
|
|
121
|
+
|
|
122
|
+
console.log(`${c('cyan', 'Current version:')} ${currentVersion}`);
|
|
123
|
+
console.log(`${c('cyan', 'Available version:')} ${newVersion}`);
|
|
124
|
+
console.log('');
|
|
125
|
+
|
|
126
|
+
if (currentVersion === newVersion && !flags.force) {
|
|
127
|
+
console.log(`${c('green', '✓ Already up to date!')}`);
|
|
128
|
+
console.log(`${c('yellow', ' Use --force to reinstall anyway')}`);
|
|
129
|
+
process.exit(0);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Files to update (always safe to update)
|
|
133
|
+
const updateableFiles = [
|
|
134
|
+
// Core agents (framework-defined, should be updated)
|
|
135
|
+
{ src: '.ai/agents/architect.md', dest: '.ai/agents/architect.md', type: 'agent' },
|
|
136
|
+
{ src: '.ai/agents/domain-architect.md', dest: '.ai/agents/domain-architect.md', type: 'agent' },
|
|
137
|
+
{ src: '.ai/agents/developer.md', dest: '.ai/agents/developer.md', type: 'agent' },
|
|
138
|
+
{ src: '.ai/agents/static-reviewer.md', dest: '.ai/agents/static-reviewer.md', type: 'agent' },
|
|
139
|
+
{ src: '.ai/agents/qa.md', dest: '.ai/agents/qa.md', type: 'agent' },
|
|
140
|
+
{ src: '.ai/agents/debt-observer.md', dest: '.ai/agents/debt-observer.md', type: 'agent' },
|
|
141
|
+
{ src: '.ai/agents/architecture-reviewer.md', dest: '.ai/agents/architecture-reviewer.md', type: 'agent' },
|
|
142
|
+
{ src: '.ai/agents/knowledge-curator.md', dest: '.ai/agents/knowledge-curator.md', type: 'agent' },
|
|
143
|
+
{ src: '.ai/agents/fitness-enforcer.md', dest: '.ai/agents/fitness-enforcer.md', type: 'agent' },
|
|
144
|
+
|
|
145
|
+
// Governance (core rules, should be updated)
|
|
146
|
+
{ src: '.ai/governance/constitution.md', dest: '.ai/governance/constitution.md', type: 'governance' },
|
|
147
|
+
{ src: '.ai/governance/definition-of-done.md', dest: '.ai/governance/definition-of-done.md', type: 'governance' },
|
|
148
|
+
|
|
149
|
+
// Skills (procedures, should be updated)
|
|
150
|
+
{ src: '.ai/skills/tdd/skill.md', dest: '.ai/skills/tdd/skill.md', type: 'skill' },
|
|
151
|
+
{ src: '.ai/skills/playwright/skill.md', dest: '.ai/skills/playwright/skill.md', type: 'skill' },
|
|
152
|
+
{ src: '.ai/skills/context7/skill.md', dest: '.ai/skills/context7/skill.md', type: 'skill' },
|
|
153
|
+
|
|
154
|
+
// Fitness functions (core rules, should be updated)
|
|
155
|
+
{ src: '.ai/architecture/governance/fitness/README.md', dest: '.ai/architecture/governance/fitness/README.md', type: 'fitness' },
|
|
156
|
+
{ src: '.ai/architecture/governance/fitness/rules.json', dest: '.ai/architecture/governance/fitness/rules.json', type: 'fitness', merge: true },
|
|
157
|
+
{ src: '.ai/architecture/governance/fitness/config.json', dest: '.ai/architecture/governance/fitness/config.json', type: 'fitness', preserve: true },
|
|
158
|
+
{ src: '.ai/architecture/governance/fitness/exemptions.json', dest: '.ai/architecture/governance/fitness/exemptions.json', type: 'fitness', preserve: true },
|
|
159
|
+
|
|
160
|
+
// Knowledge base (template only, preserve if exists)
|
|
161
|
+
{ src: '.ai/knowledge/knowledge-base.md', dest: '.ai/knowledge/knowledge-base.md', type: 'knowledge', preserve: true },
|
|
162
|
+
|
|
163
|
+
// Reports format (schema, should be updated)
|
|
164
|
+
{ src: '.ai/reports/fitness-results.json', dest: '.ai/reports/fitness-results.json', type: 'schema' },
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
// Files to check for changes (user might have modified)
|
|
168
|
+
const checkFiles = [
|
|
169
|
+
{ src: 'CLAUDE.md', dest: 'CLAUDE.md', type: 'doc' },
|
|
170
|
+
{ src: '.ai/memory/patterns.md', dest: '.ai/memory/patterns.md', type: 'memory', preserve: true },
|
|
171
|
+
{ src: '.ai/memory/anti-patterns.md', dest: '.ai/memory/anti-patterns.md', type: 'memory', preserve: true },
|
|
172
|
+
];
|
|
173
|
+
|
|
174
|
+
// Helper: Calculate file hash
|
|
175
|
+
function getFileHash(filePath) {
|
|
176
|
+
if (!fs.existsSync(filePath)) return null;
|
|
177
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
178
|
+
return crypto.createHash('md5').update(content).digest('hex');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Helper: Check if file was modified by user
|
|
182
|
+
function isModifiedByUser(destPath, srcPath) {
|
|
183
|
+
if (!fs.existsSync(destPath)) return false;
|
|
184
|
+
|
|
185
|
+
const destHash = getFileHash(destPath);
|
|
186
|
+
const srcHash = getFileHash(srcPath);
|
|
187
|
+
|
|
188
|
+
return destHash !== srcHash;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Update statistics
|
|
192
|
+
const stats = {
|
|
193
|
+
updated: [],
|
|
194
|
+
created: [],
|
|
195
|
+
skipped: [],
|
|
196
|
+
preserved: [],
|
|
197
|
+
conflicts: []
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Process updates
|
|
201
|
+
console.log(`${c('blue', '[1/3] Updating core files')}`);
|
|
202
|
+
console.log('');
|
|
203
|
+
|
|
204
|
+
for (const file of updateableFiles) {
|
|
205
|
+
const srcPath = path.join(templateDir, file.src);
|
|
206
|
+
const destPath = path.join(target, file.dest);
|
|
207
|
+
|
|
208
|
+
if (!fs.existsSync(srcPath)) {
|
|
209
|
+
console.log(`${c('yellow', '⊙ Warning:')} Source file not found: ${file.src}`);
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Check if file should be preserved
|
|
214
|
+
if (file.preserve && fs.existsSync(destPath) && !flags.force) {
|
|
215
|
+
console.log(`${c('cyan', '→ Preserving')} ${file.dest} (user file)`);
|
|
216
|
+
stats.preserved.push(file.dest);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Check if file needs merge (e.g., rules.json - user might have added custom rules)
|
|
221
|
+
if (file.merge && fs.existsSync(destPath) && !flags.force) {
|
|
222
|
+
const modified = isModifiedByUser(destPath, srcPath);
|
|
223
|
+
if (modified) {
|
|
224
|
+
console.log(`${c('yellow', '⚠ Conflict:')} ${file.dest} has local changes`);
|
|
225
|
+
console.log(`${c('yellow', ' Manual merge required or use --force to overwrite')}`);
|
|
226
|
+
stats.conflicts.push(file.dest);
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Check if file exists
|
|
232
|
+
if (fs.existsSync(destPath)) {
|
|
233
|
+
const modified = isModifiedByUser(destPath, srcPath);
|
|
234
|
+
|
|
235
|
+
if (modified && !flags.force) {
|
|
236
|
+
console.log(`${c('yellow', '⊙ Skipping')} ${file.dest} (locally modified, use --force to overwrite)`);
|
|
237
|
+
stats.skipped.push(file.dest);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (!flags.dryRun) {
|
|
242
|
+
// Create backup
|
|
243
|
+
const backupPath = `${destPath}.backup-${Date.now()}`;
|
|
244
|
+
fs.copyFileSync(destPath, backupPath);
|
|
245
|
+
|
|
246
|
+
// Update file
|
|
247
|
+
fs.copyFileSync(srcPath, destPath);
|
|
248
|
+
console.log(`${c('green', '✓ Updated')} ${file.dest} ${c('yellow', '(backup created)')}`);
|
|
249
|
+
stats.updated.push(file.dest);
|
|
250
|
+
} else {
|
|
251
|
+
console.log(`${c('cyan', '→ Would update')} ${file.dest}`);
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
// Create directory if needed
|
|
255
|
+
const dir = path.dirname(destPath);
|
|
256
|
+
if (!fs.existsSync(dir)) {
|
|
257
|
+
if (!flags.dryRun) {
|
|
258
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (!flags.dryRun) {
|
|
263
|
+
fs.copyFileSync(srcPath, destPath);
|
|
264
|
+
console.log(`${c('green', '✓ Created')} ${file.dest}`);
|
|
265
|
+
stats.created.push(file.dest);
|
|
266
|
+
} else {
|
|
267
|
+
console.log(`${c('cyan', '→ Would create')} ${file.dest}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
console.log('');
|
|
273
|
+
|
|
274
|
+
// Check CLAUDE.md and other user-modifiable files
|
|
275
|
+
console.log(`${c('blue', '[2/3] Checking user-modifiable files')}`);
|
|
276
|
+
console.log('');
|
|
277
|
+
|
|
278
|
+
for (const file of checkFiles) {
|
|
279
|
+
const srcPath = path.join(templateDir, file.src);
|
|
280
|
+
const destPath = path.join(target, file.dest);
|
|
281
|
+
|
|
282
|
+
if (!fs.existsSync(destPath)) {
|
|
283
|
+
// File doesn't exist, create it
|
|
284
|
+
if (!flags.dryRun) {
|
|
285
|
+
const dir = path.dirname(destPath);
|
|
286
|
+
if (!fs.existsSync(dir)) {
|
|
287
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
288
|
+
}
|
|
289
|
+
fs.copyFileSync(srcPath, destPath);
|
|
290
|
+
console.log(`${c('green', '✓ Created')} ${file.dest}`);
|
|
291
|
+
stats.created.push(file.dest);
|
|
292
|
+
} else {
|
|
293
|
+
console.log(`${c('cyan', '→ Would create')} ${file.dest}`);
|
|
294
|
+
}
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (file.preserve && !flags.force) {
|
|
299
|
+
console.log(`${c('cyan', '→ Preserving')} ${file.dest} (user file)`);
|
|
300
|
+
stats.preserved.push(file.dest);
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const modified = isModifiedByUser(destPath, srcPath);
|
|
305
|
+
|
|
306
|
+
if (modified) {
|
|
307
|
+
if (flags.force) {
|
|
308
|
+
if (!flags.dryRun) {
|
|
309
|
+
const backupPath = `${destPath}.backup-${Date.now()}`;
|
|
310
|
+
fs.copyFileSync(destPath, backupPath);
|
|
311
|
+
fs.copyFileSync(srcPath, destPath);
|
|
312
|
+
console.log(`${c('green', '✓ Updated')} ${file.dest} ${c('yellow', '(backup created, was modified)')}`);
|
|
313
|
+
stats.updated.push(file.dest);
|
|
314
|
+
} else {
|
|
315
|
+
console.log(`${c('cyan', '→ Would update')} ${file.dest} ${c('yellow', '(is modified)')}`);
|
|
316
|
+
}
|
|
317
|
+
} else {
|
|
318
|
+
console.log(`${c('yellow', '⊙ Skipping')} ${file.dest} (locally modified, use --force to overwrite)`);
|
|
319
|
+
stats.skipped.push(file.dest);
|
|
320
|
+
}
|
|
321
|
+
} else {
|
|
322
|
+
// File unchanged, update it
|
|
323
|
+
if (!flags.dryRun) {
|
|
324
|
+
fs.copyFileSync(srcPath, destPath);
|
|
325
|
+
console.log(`${c('green', '✓ Updated')} ${file.dest}`);
|
|
326
|
+
stats.updated.push(file.dest);
|
|
327
|
+
} else {
|
|
328
|
+
console.log(`${c('cyan', '→ Would update')} ${file.dest}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
console.log('');
|
|
334
|
+
|
|
335
|
+
// Update version file
|
|
336
|
+
console.log(`${c('blue', '[3/3] Updating version')}`);
|
|
337
|
+
console.log('');
|
|
338
|
+
|
|
339
|
+
if (!flags.dryRun) {
|
|
340
|
+
fs.writeFileSync(versionFile, newVersion, 'utf-8');
|
|
341
|
+
console.log(`${c('green', '✓ Version updated:')} ${currentVersion} → ${newVersion}`);
|
|
342
|
+
} else {
|
|
343
|
+
console.log(`${c('cyan', '→ Would update version:')} ${currentVersion} → ${newVersion}`);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
console.log('');
|
|
347
|
+
|
|
348
|
+
// Summary
|
|
349
|
+
console.log(`${c('green', '╔════════════════════════════════════════════════════════╗')}`);
|
|
350
|
+
console.log(`${c('green', '║ Update Summary ║')}`);
|
|
351
|
+
console.log(`${c('green', '╚════════════════════════════════════════════════════════╝')}`);
|
|
352
|
+
console.log('');
|
|
353
|
+
|
|
354
|
+
console.log(`${c('green', '✓ Updated:')} ${stats.updated.length} files`);
|
|
355
|
+
console.log(`${c('green', '✓ Created:')} ${stats.created.length} files`);
|
|
356
|
+
console.log(`${c('cyan', '→ Preserved:')} ${stats.preserved.length} files (user content)`);
|
|
357
|
+
console.log(`${c('yellow', '⊙ Skipped:')} ${stats.skipped.length} files (modified locally)`);
|
|
358
|
+
console.log(`${c('yellow', '⚠ Conflicts:')} ${stats.conflicts.length} files (manual merge needed)`);
|
|
359
|
+
console.log('');
|
|
360
|
+
|
|
361
|
+
if (stats.conflicts.length > 0) {
|
|
362
|
+
console.log(`${c('yellow', 'Conflicts requiring manual merge:')}`);
|
|
363
|
+
stats.conflicts.forEach(file => console.log(` • ${file}`));
|
|
364
|
+
console.log('');
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (stats.skipped.length > 0 && !flags.force) {
|
|
368
|
+
console.log(`${c('yellow', 'Skipped files (use --force to update):')}`);
|
|
369
|
+
stats.skipped.forEach(file => console.log(` • ${file}`));
|
|
370
|
+
console.log('');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (flags.dryRun) {
|
|
374
|
+
console.log(`${c('cyan', 'This was a dry run. No files were modified.')}`);
|
|
375
|
+
console.log(`${c('cyan', 'Run without --dry-run to apply changes.')}`);
|
|
376
|
+
console.log('');
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Backups info
|
|
380
|
+
const backupFiles = fs.readdirSync(target, { recursive: true })
|
|
381
|
+
.filter(file => file.includes('.backup-'));
|
|
382
|
+
|
|
383
|
+
if (backupFiles.length > 0 && !flags.dryRun) {
|
|
384
|
+
console.log(`${c('yellow', 'Backups created:')}`);
|
|
385
|
+
backupFiles.slice(0, 5).forEach(file => console.log(` • ${file}`));
|
|
386
|
+
if (backupFiles.length > 5) {
|
|
387
|
+
console.log(` ... and ${backupFiles.length - 5} more`);
|
|
388
|
+
}
|
|
389
|
+
console.log('');
|
|
390
|
+
console.log(`${c('yellow', 'To clean up backups:')}`);
|
|
391
|
+
console.log(` find . -name "*.backup-*" -delete`);
|
|
392
|
+
console.log('');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
console.log(`${c('blue', '📚 Changelog:')} See SHHS release notes for what changed`);
|
|
396
|
+
console.log('');
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-shhs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Self-Healing Hybrid Swarm - AI governance system installer",
|
|
5
5
|
"main": "bin/install.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"create-shhs": "
|
|
7
|
+
"create-shhs": "bin/install.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"test": "node bin/install.js --help"
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"repository": {
|
|
27
27
|
"type": "git",
|
|
28
|
-
"url": "https://github.com/
|
|
28
|
+
"url": "git+https://github.com/asaje379/shhs.git"
|
|
29
29
|
},
|
|
30
|
-
"homepage": "https://github.com/
|
|
30
|
+
"homepage": "https://github.com/asaje379/shhs#readme",
|
|
31
31
|
"bugs": {
|
|
32
|
-
"url": "https://github.com/
|
|
32
|
+
"url": "https://github.com/asaje379/shhs/issues"
|
|
33
33
|
},
|
|
34
34
|
"engines": {
|
|
35
35
|
"node": ">=14.0.0"
|
|
@@ -38,6 +38,8 @@
|
|
|
38
38
|
"bin/",
|
|
39
39
|
"template/",
|
|
40
40
|
"README.md",
|
|
41
|
-
"LICENSE"
|
|
41
|
+
"LICENSE",
|
|
42
|
+
"UPDATE-GUIDE.md",
|
|
43
|
+
"INSTALLATION-GUIDE.md"
|
|
42
44
|
]
|
|
43
45
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.1.0
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Architecture Reviewer
|
|
2
|
+
|
|
3
|
+
## Role
|
|
4
|
+
|
|
5
|
+
You are operating inside the Self-Healing Hybrid Swarm (SHHS).
|
|
6
|
+
|
|
7
|
+
Your role is **ARCHITECTURE REVIEWER**.
|
|
8
|
+
|
|
9
|
+
You are NOT the original architect.
|
|
10
|
+
You must evaluate the system as an independent governance authority.
|
|
11
|
+
|
|
12
|
+
## Mission
|
|
13
|
+
|
|
14
|
+
Detect architectural drift, hidden coupling, and long-term scalability risks.
|
|
15
|
+
|
|
16
|
+
Assume the system will evolve for 10+ years with multiple teams.
|
|
17
|
+
|
|
18
|
+
## Review Scope
|
|
19
|
+
|
|
20
|
+
Analyze:
|
|
21
|
+
|
|
22
|
+
- domain boundaries
|
|
23
|
+
- shared/platform services
|
|
24
|
+
- module dependencies
|
|
25
|
+
- event flows
|
|
26
|
+
- ownership clarity
|
|
27
|
+
- autonomy of teams
|
|
28
|
+
- risk of centralization
|
|
29
|
+
|
|
30
|
+
## Review Questions
|
|
31
|
+
|
|
32
|
+
You must explicitly answer:
|
|
33
|
+
|
|
34
|
+
1. Which parts risk becoming bottlenecks?
|
|
35
|
+
2. Where does reuse reduce autonomy?
|
|
36
|
+
3. Which abstractions are premature?
|
|
37
|
+
4. Which domains are becoming too dependent?
|
|
38
|
+
5. What will slow development in year 3–5?
|
|
39
|
+
6. What architectural debt is silently forming?
|
|
40
|
+
|
|
41
|
+
## Output Responsibilities
|
|
42
|
+
|
|
43
|
+
Create or update:
|
|
44
|
+
|
|
45
|
+
**`.ai/architecture/governance/architecture-review.md`**
|
|
46
|
+
|
|
47
|
+
Include:
|
|
48
|
+
|
|
49
|
+
- Critical risks
|
|
50
|
+
- Medium-term risks
|
|
51
|
+
- Architectural fitness rules to introduce
|
|
52
|
+
- Recommended corrective actions
|
|
53
|
+
|
|
54
|
+
## Behavior Rules
|
|
55
|
+
|
|
56
|
+
- Challenge assumptions
|
|
57
|
+
- Prefer resilience over purity
|
|
58
|
+
- Assume humans will take shortcuts
|
|
59
|
+
- Optimize for long-term evolution
|
|
60
|
+
- Question centralizing patterns
|
|
61
|
+
- Identify Conway's Law violations
|
|
62
|
+
- Flag team boundary misalignments
|
|
63
|
+
|
|
64
|
+
## Forbidden Actions
|
|
65
|
+
|
|
66
|
+
- Never implement solutions yourself
|
|
67
|
+
- Never rewrite the architecture without an ADR
|
|
68
|
+
- Never approve or reject implementations (that's the Domain Architect's role)
|
|
69
|
+
- Never modify production code
|
|
70
|
+
|
|
71
|
+
## Workflow
|
|
72
|
+
|
|
73
|
+
1. Load current `ARCHITECTURE.md`
|
|
74
|
+
2. Review all ADRs in `.ai/ADR/`
|
|
75
|
+
3. Analyze domain boundaries and dependencies
|
|
76
|
+
4. Consult `.ai/memory/patterns.md` and `.ai/memory/anti-patterns.md`
|
|
77
|
+
5. Run architectural fitness functions (if available)
|
|
78
|
+
6. Answer all review questions explicitly
|
|
79
|
+
7. Generate architecture-review.md with findings
|
|
80
|
+
8. Propose corrective ADRs if needed
|
|
81
|
+
|
|
82
|
+
## When to Run
|
|
83
|
+
|
|
84
|
+
The Architecture Reviewer should be invoked:
|
|
85
|
+
|
|
86
|
+
- After every milestone
|
|
87
|
+
- Before major feature additions
|
|
88
|
+
- When technical debt reports accumulate
|
|
89
|
+
- When team velocity decreases
|
|
90
|
+
- On request from any agent or human stakeholder
|
|
91
|
+
|
|
92
|
+
Begin review.
|