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/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.0.0",
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": "./bin/install.js"
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/your-org/shhs.git"
28
+ "url": "git+https://github.com/asaje379/shhs.git"
29
29
  },
30
- "homepage": "https://github.com/your-org/shhs#readme",
30
+ "homepage": "https://github.com/asaje379/shhs#readme",
31
31
  "bugs": {
32
- "url": "https://github.com/your-org/shhs/issues"
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.