#!/usr/bin/env node import fs from 'fs'; import os from 'os'; import path from 'path'; import { fileURLToPath } from 'url'; import { DOCCENTER_API_URL } from '../src/data/doc-paths.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const ROOT = path.resolve(__dirname, '..'); const APPLY = process.argv.includes('--apply'); const AUTH_PATH = path.join(os.homedir(), '.vl-code', 'auth.json'); const cookie = process.env.DOCCENTER_COOKIE || (() => { try { return JSON.parse(fs.readFileSync(AUTH_PATH, 'utf-8')).cookie; } catch { return ''; } })(); const MANIFEST = [ { file: '.vl-code/workflows/parallel-codegen.json', path: '112', name: 'VL_Parallel_CodeGen_v3.16', description: 'Fast ProjectMeta-driven code generation with default Theme/Theme.vth and parallel VL file fanout.', changeNote: 'v3.16.2 — enforce Theme/Theme.vth, Database/.vdb, and parallel VL file generation', }, { file: '.vl-code/workflows/meta-direct-codegen.json', path: '113', name: 'VL_MetaDirect_CodeGen_v3.16', description: 'Small-project ProjectMeta-first code generation with default Theme/Theme.vth and parallel VL file fanout.', changeNote: 'v3.16.2 — enforce Theme/Theme.vth, Database/.vdb, and parallel VL file generation', }, { file: '.vl-code/workflows/3-file-codegen.json', path: '114', name: 'VL_3File_CodeGen_v3.16', description: '3-file auxiliary workflow using PRD + ServiceMap + UIMap, plus default Theme/Theme.vth.', changeNote: 'v3.16.2 — seed Theme/Theme.vth, remove main.vdb fallback, and parallelize final VL fanout', }, { file: '.vl-code/workflows/6-file-codegen.json', path: '60', name: 'VL_FullStack_CodeGen_6Files_v3.16', description: 'Full-stack code generation using 6 auxiliary spec files and DocCenter agent prompts.', changeNote: 'v3.16.2 — enforce Theme/Theme.vth, Database/.vdb, and parallel VL file generation', }, { file: '.vl-code/workflows/9-file-codegen.json', path: '115', name: 'VL_9File_CodeGen_v3.16', description: '9-file auxiliary workflow with manifest-driven parallel VL generation and default Theme/Theme.vth.', changeNote: 'v3.16.2 — enforce Theme/Theme.vth, Database/.vdb, and parallel VL file generation', }, { file: '.vl-code/workflows/add-page.json', path: '120', name: 'VL_AddPage_Workflow_v1', description: 'Workflow to add a new page (section + components + route) to an existing VL project', changeNote: 'v1.2 — fix DocCenter prompt refs and write updated route to the real target app file', }, { file: '.vl-code/workflows/add-service.json', path: '130', name: 'VL_AddService_Workflow_v1', description: 'Workflow to add a new backend service domain to an existing VL project', changeNote: 'v1.1 — fix prompt refs and write database changes to the ProjectMeta database file', }, { file: '.vl-code/workflows/theme-customize.json', path: '140', name: 'VL_ThemeCustomize_Workflow_v1', description: 'Workflow to regenerate theme tokens and cascade updates to affected VL files', changeNote: 'v1.1 — fix theme prompt path, dynamic theme file resolution, and cascade file writes', }, { file: '.vl-code/workflows/incremental-update.json', path: '141', name: 'VL_IncrementalUpdate_Workflow_v1', description: 'General existing-project adjustment workflow using meta diff plus targeted file regeneration.', changeNote: 'v1.0 — remove missing DocCenter prompt deps and strengthen inline regen instructions', }, { file: '.vl-code/workflows/compile-fix.json', path: '142', name: 'VL_CompileFix_Workflow_v2', description: 'Compile-report-driven workflow that applies file fixes from .vl-code/last-compile.json and hands verification back to VLCompile.', changeNote: 'v2.0 — replace fake compile/recompile steps with report-driven repair flow', }, { file: 'docs/workflow-audits/workflow-audit-2026-03-14.md', path: '161', name: 'VL-Code Workflow Audit Report 2026-03-14', description: 'Workflow/doc-center/debug-fix audit report for the 2026-03-14 correction pass.', changeNote: 'Initial audit report', }, ]; if (!cookie) { console.error('Missing DocCenter cookie. Set DOCCENTER_COOKIE or login so ~/.vl-code/auth.json exists.'); process.exit(1); } const headers = { 'Content-Type': 'application/json', Cookie: `ih5bearer=${cookie}`, }; async function dcPost(endpoint, body) { const res = await fetch(`${DOCCENTER_API_URL}/${endpoint}`, { method: 'POST', headers, body: JSON.stringify(body), }); const text = await res.text(); try { return JSON.parse(text); } catch { throw new Error(`DocCenter returned non-JSON for ${endpoint}: ${text.slice(0, 300)}`); } } async function loadCatalog() { const res = await dcPost('SERVICE_DocCenter_GetDocList', { keyword: '', tagId: 0, page: 1, pageSize: 200, }); return Array.isArray(res?.data) ? res.data : []; } async function getDocContent(docId) { const res = await dcPost('SERVICE_DocCenter_GetDocById', { docId }); return res?.data || null; } async function syncOne(entry, catalog) { const fullPath = path.join(ROOT, entry.file); const currentContent = fs.readFileSync(fullPath, 'utf-8'); const existing = catalog.find(doc => String(doc.path) === String(entry.path)) || catalog.find(doc => doc.name === entry.name); if (!existing) { if (!APPLY) { return { action: 'create', path: entry.path, name: entry.name, docId: null }; } const createRes = await dcPost('SERVICE_DocCenter_CreateDoc', { name: entry.name, description: entry.description, path: entry.path, }); const created = createRes?.data || createRes; const docId = created?._id || created?.id || createRes?.docId || createRes?.data?.docId; if (!docId) throw new Error(`CreateDoc did not return a docId for path ${entry.path}`); await dcPost('SERVICE_DocCenter_SaveAsVersion', { path: entry.path, name: entry.name, description: entry.description, currentContent, changeNote: entry.changeNote, }); catalog.push({ _id: docId, path: entry.path, name: entry.name }); return { action: 'created', path: entry.path, name: entry.name, docId }; } const docId = existing._id || existing.id; const remote = docId ? await getDocContent(docId) : null; if (remote?.currentContent === currentContent) { return { action: 'unchanged', path: entry.path, name: entry.name, docId }; } if (!APPLY) { return { action: 'publish', path: entry.path, name: entry.name, docId }; } await dcPost('SERVICE_DocCenter_SaveAsVersion', { path: entry.path, name: entry.name, description: entry.description, currentContent, changeNote: entry.changeNote, }); return { action: 'published', path: entry.path, name: entry.name, docId }; } async function main() { const catalog = await loadCatalog(); const results = []; console.log(`\nDocCenter workflow sync ${APPLY ? '(apply)' : '(dry-run)'}`); for (const entry of MANIFEST) { const result = await syncOne(entry, catalog); results.push(result); const label = `${result.action}`.padEnd(9, ' '); console.log(`${label} path ${result.path} ${result.name}${result.docId ? ` (docId ${result.docId})` : ''}`); } const counts = results.reduce((acc, item) => { acc[item.action] = (acc[item.action] || 0) + 1; return acc; }, {}); console.log('\nSummary:', counts); } main().catch(err => { console.error(err.message); process.exit(1); });