feat: add /update skill for pulling upstream changes (#372)

Interactive skill that guides Claude through fetching upstream NanoClaw,
previewing changes, merging with customizations, running migrations, and
verifying the result. Includes:

- SKILL.md with 9-step update flow
- fetch-upstream.sh: detects remote, fetches, extracts tracked paths
- run-migrations.ts: discovers and runs version-ordered migrations
- post-update.ts: clears backup after conflict resolution
- update-core.ts: adds --json and --preview-only flags
- BASE_INCLUDES moved to constants.ts as single source of truth
- 16 new tests covering fetch, migrations, and CLI flags

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-02-23 01:03:13 +02:00
committed by GitHub
parent 628d434799
commit 1216b5b99c
10 changed files with 1026 additions and 22 deletions

View File

@@ -1,34 +1,59 @@
#!/usr/bin/env tsx
import { applyUpdate, previewUpdate } from '../skills-engine/update.js';
const newCorePath = process.argv[2];
const args = process.argv.slice(2);
const jsonMode = args.includes('--json');
const previewOnly = args.includes('--preview-only');
const newCorePath = args.find((a) => !a.startsWith('--'));
if (!newCorePath) {
console.error('Usage: tsx scripts/update-core.ts <path-to-new-core>');
console.error(
'Usage: tsx scripts/update-core.ts [--json] [--preview-only] <path-to-new-core>',
);
process.exit(1);
}
// Preview
const preview = previewUpdate(newCorePath);
console.log('=== Update Preview ===');
console.log(`Current version: ${preview.currentVersion}`);
console.log(`New version: ${preview.newVersion}`);
console.log(`Files changed: ${preview.filesChanged.length}`);
if (preview.filesChanged.length > 0) {
for (const f of preview.filesChanged) {
console.log(` ${f}`);
if (jsonMode && previewOnly) {
console.log(JSON.stringify(preview, null, 2));
process.exit(0);
}
function printPreview(): void {
console.log('=== Update Preview ===');
console.log(`Current version: ${preview.currentVersion}`);
console.log(`New version: ${preview.newVersion}`);
console.log(`Files changed: ${preview.filesChanged.length}`);
if (preview.filesChanged.length > 0) {
for (const f of preview.filesChanged) {
console.log(` ${f}`);
}
}
if (preview.conflictRisk.length > 0) {
console.log(`Conflict risk: ${preview.conflictRisk.join(', ')}`);
}
if (preview.customPatchesAtRisk.length > 0) {
console.log(
`Custom patches at risk: ${preview.customPatchesAtRisk.join(', ')}`,
);
}
}
if (preview.conflictRisk.length > 0) {
console.log(`Conflict risk: ${preview.conflictRisk.join(', ')}`);
}
if (preview.customPatchesAtRisk.length > 0) {
console.log(`Custom patches at risk: ${preview.customPatchesAtRisk.join(', ')}`);
}
console.log('');
// Apply
console.log('Applying update...');
if (previewOnly) {
printPreview();
process.exit(0);
}
if (!jsonMode) {
printPreview();
console.log('');
console.log('Applying update...');
}
const result = await applyUpdate(newCorePath);
console.log(JSON.stringify(result, null, 2));
if (!result.success) {