Archify Diagram Viewer 0.1.0
VS Code extension that previews Archify diagrams from their JSON sources (live, as you type) and opens rendered Archify HTML in a viewer tab. Bundles the Archify 3.0.1 renderer and runs it on VS Code's Node runtime. Adds validation diagnostics, JSON schema help, source-link navigation, export saving, render-to-file and open-in-browser commands. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+91
@@ -0,0 +1,91 @@
|
||||
import { spawn } from 'node:child_process';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const childPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'scripts', 'delivery-update-child.mjs');
|
||||
const DEADLINE_MS = 1_000;
|
||||
const MAX_OUTPUT_BYTES = 16 * 1_024;
|
||||
|
||||
function unavailable(reason) {
|
||||
return { status: 'unavailable', installedVersion: null, availableVersion: null,
|
||||
releaseNotes: null, checkedAt: null, source: null, noticeRequired: false,
|
||||
noticeText: null, reason };
|
||||
}
|
||||
|
||||
function normalize(result) {
|
||||
if (result?.status === 'current') return {
|
||||
status: 'current', installedVersion: result.installedVersion,
|
||||
availableVersion: result.availableVersion, releaseNotes: null,
|
||||
checkedAt: result.checkedAt, source: result.source,
|
||||
noticeRequired: false, noticeText: null,
|
||||
};
|
||||
if (result?.status !== 'update_available') {
|
||||
return unavailable(result?.reason || (result?.status === 'silent' ? 'no-update' : 'invalid-result'));
|
||||
}
|
||||
const noticeRequired = result.noticeRequired !== false;
|
||||
const cached = result.source === 'cache';
|
||||
const noticeText = noticeRequired
|
||||
? `Archify ${result.severity === 'security' ? 'security update' : 'update'}: ${result.installedVersion} → ${result.latestVersion}. ${cached
|
||||
? `A previous check at ${result.checkedAt} found a newer release.`
|
||||
: 'A newer release is available.'} Release notes: ${result.releaseNotes}. The installed Skill has not changed; ask to snooze or ignore this reminder.`
|
||||
: null;
|
||||
return {
|
||||
status: 'update_available',
|
||||
installedVersion: result.installedVersion,
|
||||
availableVersion: result.latestVersion,
|
||||
releaseNotes: result.releaseNotes,
|
||||
severity: result.severity,
|
||||
checkedAt: result.checkedAt,
|
||||
source: result.source,
|
||||
noticeRequired,
|
||||
noticeText,
|
||||
...(result.eventKey ? { eventKey: result.eventKey } : {}),
|
||||
...(result.reason ? { reason: result.reason } : {}),
|
||||
...(result.suppressedUntil ? { suppressedUntil: result.suppressedUntil } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
export function startDeliveryUpdateCheck({
|
||||
env = process.env, deadlineMs = DEADLINE_MS, checkerPath = childPath,
|
||||
} = {}) {
|
||||
if (env.ARCHIFY_UPDATE_CHECK_DISABLED === '1') return Promise.resolve(unavailable('disabled'));
|
||||
return new Promise((resolve) => {
|
||||
let child;
|
||||
try {
|
||||
const deadlineNs = process.hrtime.bigint() + BigInt(Math.floor(deadlineMs * 1_000_000));
|
||||
child = spawn(process.execPath, [checkerPath, String(deadlineNs)], {
|
||||
env,
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
windowsHide: true,
|
||||
});
|
||||
} catch {
|
||||
resolve(unavailable('runtime-unavailable'));
|
||||
return;
|
||||
}
|
||||
let output = '';
|
||||
let timedOut = false;
|
||||
let overflow = false;
|
||||
const timer = setTimeout(() => {
|
||||
timedOut = true;
|
||||
child.kill('SIGKILL');
|
||||
}, deadlineMs);
|
||||
child.stdout.on('data', (chunk) => {
|
||||
if (Buffer.byteLength(output) + chunk.length > MAX_OUTPUT_BYTES) {
|
||||
overflow = true;
|
||||
child.kill('SIGKILL');
|
||||
} else output += chunk.toString('utf8');
|
||||
});
|
||||
child.on('error', () => {});
|
||||
child.on('close', (code) => {
|
||||
clearTimeout(timer);
|
||||
if (overflow) return resolve(unavailable('invalid-result'));
|
||||
// A synchronous renderer can delay both this callback and the parent's
|
||||
// timer. A complete child result wins even if the timer fired meanwhile.
|
||||
if (code === 0 && output.endsWith('\n')) {
|
||||
try { return resolve(normalize(JSON.parse(output))); }
|
||||
catch { return resolve(unavailable('invalid-result')); }
|
||||
}
|
||||
resolve(unavailable(timedOut || child.signalCode === 'SIGKILL' ? 'timeout' : 'check-failed'));
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user