Files
archify-vscode-ext/src/runtime.ts
T
root-at-skicandClaude Opus 5.5 5e53348252 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>
2026-09-30 12:44:15 +03:00

78 lines
3.2 KiB
TypeScript

import { execFile } from 'node:child_process';
import path from 'node:path';
import * as vscode from 'vscode';
import { RuntimeOptions } from './renderer';
import { ViewerTheme } from './webviewHtml';
let output: vscode.LogOutputChannel | undefined;
export function log(): vscode.LogOutputChannel {
output ??= vscode.window.createOutputChannel('Archify', { log: true });
return output;
}
const gitRoots = new Map<string, Promise<string | undefined>>();
function gitTopLevel(dir: string): Promise<string | undefined> {
let pending = gitRoots.get(dir);
if (!pending) {
pending = new Promise((resolve) => {
execFile('git', ['rev-parse', '--show-toplevel'], { cwd: dir, timeout: 10_000 }, (error, stdout) => {
resolve(error ? undefined : path.resolve(stdout.trim()));
});
});
gitRoots.set(dir, pending);
}
return pending;
}
export function clearGitRootCache(): void {
gitRoots.clear();
}
/** The checkout used to verify source evidence for a file, if any. */
export async function repoRootFor(uri: vscode.Uri | undefined): Promise<string | undefined> {
const configured = vscode.workspace.getConfiguration('archify', uri).get<string>('repoRoot', '').trim();
if (configured) {
if (path.isAbsolute(configured)) return configured;
const folder = (uri && vscode.workspace.getWorkspaceFolder(uri)) ?? vscode.workspace.workspaceFolders?.[0];
return folder ? path.resolve(folder.uri.fsPath, configured) : path.resolve(configured);
}
if (!uri || uri.scheme !== 'file') return undefined;
return gitTopLevel(path.dirname(uri.fsPath));
}
export async function runtimeFor(context: vscode.ExtensionContext, uri: vscode.Uri | undefined): Promise<RuntimeOptions> {
const config = vscode.workspace.getConfiguration('archify', uri);
const nodePath = config.get<string>('nodePath', '').trim();
const quality = config.get<string>('quality', '');
return {
cliPath: context.asAbsolutePath(path.join('vendor', 'archify', 'bin', 'archify.mjs')),
nodePath: nodePath || process.execPath,
runAsNode: !nodePath,
workDir: path.join(context.globalStorageUri.fsPath, 'renders'),
quality: quality || undefined,
repoRoot: await repoRootFor(uri),
log: (line) => log().debug(line),
};
}
export function evidenceMode(uri: vscode.Uri | undefined): 'fallback' | 'strict' {
return vscode.workspace.getConfiguration('archify', uri).get<'fallback' | 'strict'>('sourceEvidence', 'fallback');
}
export function viewerTheme(): ViewerTheme {
const setting = vscode.workspace.getConfiguration('archify').get<string>('theme', 'vscode');
if (setting === 'dark' || setting === 'light') return setting;
if (setting === 'diagram') return undefined;
const kind = vscode.window.activeColorTheme.kind;
return kind === vscode.ColorThemeKind.Light || kind === vscode.ColorThemeKind.HighContrastLight ? 'light' : 'dark';
}
/** Current text of a document: the open editor buffer, else the file on disk. */
export async function readText(uri: vscode.Uri): Promise<string> {
const open = vscode.workspace.textDocuments.find((doc) => doc.uri.toString() === uri.toString());
if (open) return open.getText();
return new TextDecoder('utf-8').decode(await vscode.workspace.fs.readFile(uri));
}