#!/usr/bin/env node // Copies the Archify renderer runtime into vendor/archify and writes // VS Code-friendly copies of its JSON schemas into schemas/. // // Usage: node scripts/sync-archify.mjs [path-to-archify-checkout] // Default source: ../../ws-storm/archify (or $ARCHIFY_SRC). import fs from 'node:fs'; import path from 'node:path'; import { execFileSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const source = path.resolve( process.argv[2] || process.env.ARCHIFY_SRC || path.join(root, '..', '..', 'ws-storm', 'archify'), ); const skill = path.join(source, 'archify'); // Runtime pieces the CLI reads at render/validate time. test/ and examples/ // are development-only and large, so they are left out. const RUNTIME = [ 'LICENSE', 'THIRD_PARTY_NOTICES.md', 'package.json', 'skill-release.json', 'assets', 'bin', 'brand-marks', 'delta', 'migrations', 'recipes', 'references', 'renderers', 'schemas', 'scripts', ]; if (!fs.existsSync(path.join(skill, 'bin', 'archify.mjs'))) { console.error(`Archify checkout not found at ${source}`); process.exit(1); } const vendor = path.join(root, 'vendor', 'archify'); fs.rmSync(vendor, { recursive: true, force: true }); fs.mkdirSync(vendor, { recursive: true }); for (const entry of RUNTIME) { fs.cpSync(path.join(skill, entry), path.join(vendor, entry), { recursive: true }); } // The upstream schemas carry absolute GitHub $ids, which would make VS Code // resolve "common.schema.json" refs over the network. Dropping $id lets refs // resolve next to the bundled file instead. const schemaOut = path.join(root, 'schemas'); fs.rmSync(schemaOut, { recursive: true, force: true }); fs.mkdirSync(schemaOut, { recursive: true }); for (const file of fs.readdirSync(path.join(skill, 'schemas'))) { if (!file.endsWith('.schema.json')) continue; const schema = JSON.parse(fs.readFileSync(path.join(skill, 'schemas', file), 'utf8')); delete schema.$id; fs.writeFileSync(path.join(schemaOut, file), `${JSON.stringify(schema, null, 2)}\n`); } // *.archify files carry their type only in diagram_type, so they get one // schema that dispatches to the per-type schema. const TYPES = ['architecture', 'workflow', 'sequence', 'dataflow', 'lifecycle']; const dispatcher = { $schema: 'https://json-schema.org/draft/2020-12/schema', title: 'Archify Diagram', description: 'An Archify diagram source. diagram_type selects the schema that applies.', type: 'object', required: ['diagram_type'], properties: { diagram_type: { enum: TYPES, description: 'Kind of diagram: architecture, workflow, sequence, dataflow or lifecycle.', }, }, allOf: TYPES.map((type) => ({ if: { properties: { diagram_type: { const: type } }, required: ['diagram_type'] }, then: { $ref: `${type}.schema.json` }, })), }; fs.writeFileSync(path.join(schemaOut, 'archify.schema.json'), `${JSON.stringify(dispatcher, null, 2)}\n`); let revision = 'unknown'; try { revision = execFileSync('git', ['-C', source, 'rev-parse', 'HEAD'], { encoding: 'utf8' }).trim(); } catch {} const { version } = JSON.parse(fs.readFileSync(path.join(skill, 'package.json'), 'utf8')); fs.writeFileSync( path.join(root, 'vendor', 'archify.json'), `${JSON.stringify({ upstream: 'https://github.com/tt-a1i/archify', version, revision }, null, 2)}\n`, ); console.log(`Synced archify ${version} (${revision.slice(0, 12)}) from ${source}`);