Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions editors/vscode-prototype/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,11 @@
],
"default": "module",
"description": "Experimental local prototype default declaration kind used by navigation; not a stable API."
},
"pccxSystemVerilog.kv260.preflightTranscriptPath": {
"type": "string",
"default": "~/.codex/private-state/board-preflight/preflight-tty-2026-05-06.md",
"description": "Experimental local prototype path for the read-only KV260 preflight transcript summary; not a stable API."
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions editors/vscode-prototype/src/config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const CONFIG_KEYS = Object.freeze([
"defaultNavigationRoot",
"defaultModule",
"defaultDeclarationKind",
"kv260.preflightTranscriptPath",
]);

export const FACADE_COMMAND_IDS = Object.freeze([
Expand Down Expand Up @@ -105,6 +106,9 @@ const DEFAULT_CONFIG = Object.freeze({
defaultNavigationRoot: "fixtures/modules",
defaultModule: "simple_mod",
defaultDeclarationKind: "module",
kv260: Object.freeze({
preflightTranscriptPath: "~/.codex/private-state/board-preflight/preflight-tty-2026-05-06.md",
}),
});

const SHELL_CONTROL_PATTERN = /(?:&&|\|\||;|`|\$\()/;
Expand Down Expand Up @@ -197,6 +201,7 @@ export function defaultConfig() {
pccxLab: { ...DEFAULT_CONFIG.pccxLab },
workflowBoundary: { ...DEFAULT_CONFIG.workflowBoundary },
validationRunner: { ...DEFAULT_CONFIG.validationRunner },
kv260: { ...DEFAULT_CONFIG.kv260 },
};
}

Expand Down Expand Up @@ -272,6 +277,13 @@ export function normalizeConfig(rawConfig = {}) {
DEFAULT_CONFIG.defaultDeclarationKind,
DECLARATION_KINDS,
),
kv260: {
preflightTranscriptPath: stringSetting(
rawConfig,
"kv260.preflightTranscriptPath",
DEFAULT_CONFIG.kv260.preflightTranscriptPath,
),
},
};
}

Expand Down
63 changes: 62 additions & 1 deletion editors/vscode-prototype/src/extension.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Copyright 2026 pccxai

import { execFile } from "node:child_process";
import { readFile } from "node:fs/promises";
import { homedir } from "node:os";
import { dirname, isAbsolute, resolve } from "node:path";
import { fileURLToPath } from "node:url";

Expand Down Expand Up @@ -75,6 +77,8 @@ import {
import {
createKv260StatusPanel,
formatKv260StatusPanel,
parseKv260PreflightTranscript,
renderKv260StatusPanelHtml,
} from "./kv260-status-panel.mjs";

const EXTENSION_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
Expand Down Expand Up @@ -452,6 +456,26 @@ function appendCommandOutput(outputChannel, commandId, result) {
outputChannel.show?.(true);
}

function showKv260StatusWebview(vscodeApi, panel) {
const createWebviewPanel = vscodeApi?.window?.createWebviewPanel;
if (typeof createWebviewPanel !== "function") {
return null;
}
const viewColumn = vscodeApi?.ViewColumn?.Beside ?? vscodeApi?.ViewColumn?.One ?? 1;
const webviewPanel = createWebviewPanel.call(
vscodeApi.window,
"pccxKv260Readiness",
"PCCX KV260 Readiness",
viewColumn,
{ enableScripts: false },
);
if (!webviewPanel?.webview) {
return null;
}
webviewPanel.webview.html = renderKv260StatusPanelHtml(panel);
return webviewPanel;
}

function facadeRunnerFromRuntime(runtime = {}) {
return async (facadeArgs, env = {}) => {
const invocation = {
Expand All @@ -475,6 +499,35 @@ function diagnosticFileForUri(file, root = DEFAULT_DIAGNOSTIC_FILE_ROOT) {
return resolve(root, filePath);
}

function resolveConfiguredPath(path, runtime = {}) {
const value = typeof path === "string" ? path : "";
if (value === "~") {
return runtime.homeDir ?? homedir();
}
if (value.startsWith("~/")) {
return resolve(runtime.homeDir ?? homedir(), value.slice(2));
}
if (isAbsolute(value)) {
return value;
}
return resolve(runtime.repoRoot ?? DEFAULT_DIAGNOSTIC_FILE_ROOT, value);
}

export async function readKv260PreflightTranscriptSummary(rawConfig = {}, runtime = {}) {
if (typeof runtime.kv260PreflightTranscriptText === "string") {
return parseKv260PreflightTranscript(runtime.kv260PreflightTranscriptText);
}
const config = normalizeConfig(rawConfig);
const configuredPath = config.kv260.preflightTranscriptPath;
const transcriptPath = resolveConfiguredPath(configuredPath, runtime);
const reader = runtime.kv260PreflightTranscriptReader ?? readFile;
try {
return parseKv260PreflightTranscript(await reader(transcriptPath, "utf8"));
} catch {
return parseKv260PreflightTranscript("");
}
}

export function createPresenterDeps(vscodeApi, runtime = {}) {
const diagnosticSeverity = {
Error: vscodeApi?.DiagnosticSeverity?.Error ?? "Error",
Expand Down Expand Up @@ -1118,13 +1171,21 @@ export function createCommandHandler(commandId, vscodeApi, runtime = {}) {
if (commandId === SHOW_KV260_STATUS_PANEL_COMMAND) {
let result;
try {
const panel = createKv260StatusPanel(runtime.kv260StatusInputs);
const preflightTranscript = await readKv260PreflightTranscriptSummary(rawConfig, runtime);
const panel = createKv260StatusPanel({
...(runtime.kv260StatusInputs ?? {}),
preflightTranscript,
});
result = {
ok: true,
commandId,
kind: "kv260-status-panel",
panel,
};
const webviewPanel = showKv260StatusWebview(vscodeApi, panel);
if (webviewPanel) {
result.presentation = "webview";
}
vscodeApi?.window?.showInformationMessage?.(
`KV260 status surface: ${panel.lab.frameCount} trace frame(s).`,
result,
Expand Down
Loading