| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- import fs from 'fs/promises';
- import os from 'os';
- import path from 'path';
- const repoRoot = '/Users/ivx/Documents/VLCode-Lite';
- const examplesDir = path.join(repoRoot, 'examples', 'workflows');
- const emptyWindowWorkflowDir = path.join(os.homedir(), '.vl-code', 'empty-window', '.vl-code', 'workflows');
- const solverSource = `import fs from 'fs';
- const cavePath = process.argv[2] || 'cave.json';
- const cave = JSON.parse(fs.readFileSync(cavePath, 'utf8'));
- const trace = [];
- const seen = new Map();
- let best = null;
- function scoreState(node, energy, crystals, path) {
- return (node === cave.goal ? 500 : 0) + (crystals * 11) + energy - path.length;
- }
- function remember(signature, score) {
- const prev = seen.get(signature) ?? -Infinity;
- if (prev >= score) return false;
- seen.set(signature, score);
- return true;
- }
- function explore(node, energy, crystals, path, visitedRooms) {
- const room = cave.rooms[node] || {};
- const nextVisitedRooms = new Set(visitedRooms);
- const gained = nextVisitedRooms.has(node) ? 0 : (room.crystals || 0);
- nextVisitedRooms.add(node);
- const nextCrystals = crystals + gained;
- const nextPath = [...path, node];
- const signature = [node, energy, nextCrystals, [...nextVisitedRooms].sort().join(',')].join('|');
- const score = scoreState(node, energy, nextCrystals, nextPath);
- if (!remember(signature, score)) return;
- trace.push(\`visit=\${node}; energy=\${energy}; crystals=\${nextCrystals}; path=\${nextPath.join('>')}\`);
- if (!best || score > best.score) {
- best = { node, energy, crystals: nextCrystals, path: nextPath, score };
- }
- if (node === cave.goal) return;
- const edges = (cave.tunnels[node] || []).slice().sort((a, b) => {
- const aReward = (cave.rooms[a.to]?.crystals || 0) - a.cost;
- const bReward = (cave.rooms[b.to]?.crystals || 0) - b.cost;
- return bReward - aReward;
- });
- for (const edge of edges) {
- if (energy < edge.cost) {
- trace.push(\`skip=\${node}->\${edge.to}; reason=energy; need=\${edge.cost}; have=\${energy}\`);
- continue;
- }
- const recharge = cave.rooms[edge.to]?.recharge || 0;
- explore(edge.to, energy - edge.cost + recharge, nextCrystals, nextPath, nextVisitedRooms);
- }
- }
- explore(cave.start, cave.energy, 0, [], new Set());
- const reportLines = [
- \`zone=\${cave.zone}\`,
- \`goal=\${cave.goal}\`,
- \`bestNode=\${best?.node || 'unknown'}\`,
- \`score=\${best?.score ?? 0}\`,
- \`energyLeft=\${best?.energy ?? 0}\`,
- \`crystals=\${best?.crystals ?? 0}\`,
- \`route=\${best?.path?.join('>') || ''}\`
- ];
- fs.writeFileSync('report.txt', reportLines.join('\\n'));
- fs.writeFileSync('trace.txt', trace.join('\\n'));
- console.log(\`best=\${best?.node || 'unknown'}; score=\${best?.score ?? 0}; route=\${best?.path?.join('>') || ''}; crystals=\${best?.crystals ?? 0}\`);
- `;
- function makeScoutWorkflow(name = 'CaveZoneScout') {
- return {
- version: '3.16',
- name,
- description: 'Writes a cave-search program into an isolated child space, runs it, and captures the trace/report.',
- steps: [
- {
- id: 'Tool_010_WriteMap',
- tool: 'WriteFile',
- input: {
- file_path: '="cave.json"',
- content: '=mapJson',
- },
- next: 'Tool_020_WriteSolver',
- },
- {
- id: 'Tool_020_WriteSolver',
- tool: 'WriteFile',
- input: {
- file_path: '="explore-cave.mjs"',
- content: solverSource,
- },
- next: 'Tool_030_RunSolver',
- },
- {
- id: 'Tool_030_RunSolver',
- tool: 'Bash',
- input: {
- command: '="node explore-cave.mjs cave.json"',
- },
- out: {
- '$solverStdout': '=_result',
- },
- next: 'Tool_040_ReadReport',
- },
- {
- id: 'Tool_040_ReadReport',
- tool: 'ReadFile',
- input: {
- file_path: '="report.txt"',
- },
- out: {
- '$reportText': '=_result',
- },
- next: 'Tool_050_ReadTrace',
- },
- {
- id: 'Tool_050_ReadTrace',
- tool: 'ReadFile',
- input: {
- file_path: '="trace.txt"',
- limit: 80,
- },
- out: {
- '$traceText': '=_result',
- },
- next: 'Set_060_Summary',
- },
- {
- id: 'Set_060_Summary',
- target: '$zoneSummary',
- value: '=zoneName + " => " + $solverStdout',
- next: 'Write_070_Summary',
- },
- {
- id: 'Write_070_Summary',
- target: '="Artifacts/zone-summary.txt"',
- value: '=$zoneSummary',
- mode: 'overwrite',
- next: 'Stop_End',
- },
- { id: 'Stop_End' },
- ],
- };
- }
- const northMap = {
- zone: 'North Rim',
- start: 'N0',
- goal: 'N7',
- energy: 10,
- rooms: {
- N0: { crystals: 0 },
- N1: { crystals: 2 },
- N2: { crystals: 1, recharge: 1 },
- N3: { crystals: 3 },
- N4: { crystals: 2 },
- N5: { crystals: 4, recharge: 2 },
- N6: { crystals: 1 },
- N7: { crystals: 6 },
- },
- tunnels: {
- N0: [{ to: 'N1', cost: 2 }, { to: 'N2', cost: 3 }],
- N1: [{ to: 'N3', cost: 2 }, { to: 'N4', cost: 3 }],
- N2: [{ to: 'N4', cost: 2 }, { to: 'N5', cost: 4 }],
- N3: [{ to: 'N6', cost: 2 }],
- N4: [{ to: 'N6', cost: 1 }, { to: 'N5', cost: 2 }],
- N5: [{ to: 'N7', cost: 2 }],
- N6: [{ to: 'N7', cost: 1 }],
- },
- };
- const southMap = {
- zone: 'South Spiral',
- start: 'S0',
- goal: 'S8',
- energy: 11,
- rooms: {
- S0: { crystals: 0 },
- S1: { crystals: 1 },
- S2: { crystals: 3 },
- S3: { crystals: 2, recharge: 1 },
- S4: { crystals: 4 },
- S5: { crystals: 1 },
- S6: { crystals: 5, recharge: 2 },
- S7: { crystals: 2 },
- S8: { crystals: 7 },
- },
- tunnels: {
- S0: [{ to: 'S1', cost: 1 }, { to: 'S2', cost: 3 }],
- S1: [{ to: 'S3', cost: 2 }, { to: 'S4', cost: 4 }],
- S2: [{ to: 'S4', cost: 2 }, { to: 'S5', cost: 3 }],
- S3: [{ to: 'S6', cost: 2 }],
- S4: [{ to: 'S6', cost: 1 }, { to: 'S7', cost: 2 }],
- S5: [{ to: 'S7', cost: 2 }],
- S6: [{ to: 'S8', cost: 2 }],
- S7: [{ to: 'S8', cost: 1 }],
- },
- };
- const anomalyMap = {
- zone: 'Deep Anomaly',
- start: 'D0',
- goal: 'D9',
- energy: 14,
- rooms: {
- D0: { crystals: 0 },
- D1: { crystals: 2 },
- D2: { crystals: 3 },
- D3: { crystals: 1, recharge: 1 },
- D4: { crystals: 4 },
- D5: { crystals: 2, recharge: 2 },
- D6: { crystals: 6 },
- D7: { crystals: 3 },
- D8: { crystals: 5 },
- D9: { crystals: 9 },
- },
- tunnels: {
- D0: [{ to: 'D1', cost: 2 }, { to: 'D2', cost: 2 }],
- D1: [{ to: 'D3', cost: 2 }, { to: 'D4', cost: 4 }],
- D2: [{ to: 'D4', cost: 2 }, { to: 'D5', cost: 3 }],
- D3: [{ to: 'D6', cost: 3 }],
- D4: [{ to: 'D6', cost: 2 }, { to: 'D7', cost: 2 }],
- D5: [{ to: 'D7', cost: 1 }, { to: 'D8', cost: 3 }],
- D6: [{ to: 'D9', cost: 2 }],
- D7: [{ to: 'D9', cost: 2 }],
- D8: [{ to: 'D9', cost: 1 }],
- },
- };
- const scoutWorkflow = makeScoutWorkflow('CaveZoneScout');
- const deepScoutWorkflow = makeScoutWorkflow('GeneratedDeepScout');
- const supervisorWorkflow = {
- version: '3.16',
- name: 'CaveSupervisorDemo',
- description: 'Supervisor workflow that runs two scout subflows in parallel, pauses for review, then generates a deep-scout child workflow and resumes exploration.',
- steps: [
- {
- id: 'Set_010_OutputRoot',
- target: '$outputRoot',
- value: '=".codex/demo-artifacts/cave-workflow-demo"',
- next: 'Set_020_DeepFlowFile',
- },
- {
- id: 'Set_020_DeepFlowFile',
- target: '$deepFlowFile',
- value: '=".vl-code/workflows/cave-deep-scout-generated.json"',
- next: 'Fork_030_InitialScouts',
- },
- {
- id: 'Fork_030_InitialScouts',
- children: ['Subflow_040_NorthScout', 'Subflow_050_SouthScout'],
- next: 'Pause_060_ManagerReview',
- },
- {
- id: 'Subflow_040_NorthScout',
- workflow_path: 'cave-zone-scout',
- mode: 'sync',
- work_dir: '=$outputRoot + "/north"',
- params: {
- zoneName: '="north-rim"',
- mapJson: JSON.stringify(northMap, null, 2),
- },
- out: {
- '$northSummary': '=_result.variables["$zoneSummary"]',
- '$northReport': '=_result.variables["$reportText"]',
- },
- },
- {
- id: 'Subflow_050_SouthScout',
- workflow_path: 'cave-zone-scout',
- mode: 'sync',
- work_dir: '=$outputRoot + "/south"',
- params: {
- zoneName: '="south-spiral"',
- mapJson: JSON.stringify(southMap, null, 2),
- },
- out: {
- '$southSummary': '=_result.variables["$zoneSummary"]',
- '$southReport': '=_result.variables["$reportText"]',
- },
- },
- {
- id: 'Pause_060_ManagerReview',
- reason: 'Manager review: compare north/south scout reports before dispatching a deep anomaly probe.',
- next: 'Tool_070_WriteDeepScoutWorkflow',
- },
- {
- id: 'Tool_070_WriteDeepScoutWorkflow',
- tool: 'WriteFile',
- input: {
- file_path: '=$deepFlowFile',
- content: JSON.stringify(deepScoutWorkflow, null, 2),
- },
- next: 'Subflow_080_DeepScout',
- },
- {
- id: 'Subflow_080_DeepScout',
- workflow_path: 'cave-deep-scout-generated',
- mode: 'sync',
- work_dir: '=$outputRoot + "/deep-scout"',
- params: {
- zoneName: '="deep-anomaly"',
- mapJson: JSON.stringify(anomalyMap, null, 2),
- },
- out: {
- '$deepSummary': '=_result.variables["$zoneSummary"]',
- '$deepReport': '=_result.variables["$reportText"]',
- },
- next: 'Set_090_FinalNarrative',
- },
- {
- id: 'Set_090_FinalNarrative',
- target: '$finalNarrative',
- value: '="North\\n" + $northSummary + "\\n\\nSouth\\n" + $southSummary + "\\n\\nDeep\\n" + $deepSummary',
- next: 'Write_100_ManagerReport',
- },
- {
- id: 'Write_100_ManagerReport',
- target: '=$outputRoot + "/manager-report.txt"',
- value: '=$finalNarrative',
- mode: 'overwrite',
- next: 'Stop_End',
- },
- { id: 'Stop_End' },
- ],
- };
- async function writeWorkflow(targetDir, fileName, workflow) {
- await fs.mkdir(targetDir, { recursive: true });
- await fs.writeFile(path.join(targetDir, fileName), JSON.stringify(workflow, null, 2), 'utf8');
- }
- await writeWorkflow(examplesDir, 'cave-zone-scout.json', scoutWorkflow);
- await writeWorkflow(examplesDir, 'cave-supervisor-demo.json', supervisorWorkflow);
- await writeWorkflow(emptyWindowWorkflowDir, 'cave-zone-scout.json', scoutWorkflow);
- await writeWorkflow(emptyWindowWorkflowDir, 'cave-supervisor-demo.json', supervisorWorkflow);
- console.log(JSON.stringify({
- ok: true,
- examplesDir,
- emptyWindowWorkflowDir,
- files: ['cave-zone-scout.json', 'cave-supervisor-demo.json'],
- }, null, 2));
|