@abhinav2203/codeflow-canvas 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/abhinav2203-codeflow-canvas-0.1.0.tgz +0 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +84 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/components/blueprint-workbench.d.ts +2 -0
- package/dist/components/blueprint-workbench.d.ts.map +1 -0
- package/dist/components/blueprint-workbench.js +144 -0
- package/dist/components/blueprint-workbench.js.map +1 -0
- package/dist/components/code-diff-editor.d.ts +12 -0
- package/dist/components/code-diff-editor.d.ts.map +1 -0
- package/dist/components/code-diff-editor.js +39 -0
- package/dist/components/code-diff-editor.js.map +1 -0
- package/dist/components/code-editor.d.ts +25 -0
- package/dist/components/code-editor.d.ts.map +1 -0
- package/dist/components/code-editor.js +264 -0
- package/dist/components/code-editor.js.map +1 -0
- package/dist/components/file-tabs.d.ts +5 -0
- package/dist/components/file-tabs.d.ts.map +1 -0
- package/dist/components/file-tabs.js +164 -0
- package/dist/components/file-tabs.js.map +1 -0
- package/dist/components/file-tree.d.ts +7 -0
- package/dist/components/file-tree.d.ts.map +1 -0
- package/dist/components/file-tree.js +176 -0
- package/dist/components/file-tree.js.map +1 -0
- package/dist/components/graph-canvas.d.ts +25 -0
- package/dist/components/graph-canvas.d.ts.map +1 -0
- package/dist/components/graph-canvas.js +224 -0
- package/dist/components/graph-canvas.js.map +1 -0
- package/dist/components/ide-layout.d.ts +10 -0
- package/dist/components/ide-layout.d.ts.map +1 -0
- package/dist/components/ide-layout.js +40 -0
- package/dist/components/ide-layout.js.map +1 -0
- package/dist/components/ide-workbench.d.ts +4 -0
- package/dist/components/ide-workbench.d.ts.map +1 -0
- package/dist/components/ide-workbench.js +6 -0
- package/dist/components/ide-workbench.js.map +1 -0
- package/dist/components/index.d.ts +13 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +13 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/monaco-setup.d.ts +4 -0
- package/dist/components/monaco-setup.d.ts.map +1 -0
- package/dist/components/monaco-setup.js +34 -0
- package/dist/components/monaco-setup.js.map +1 -0
- package/dist/components/opencode-settings.d.ts +8 -0
- package/dist/components/opencode-settings.d.ts.map +1 -0
- package/dist/components/opencode-settings.js +33 -0
- package/dist/components/opencode-settings.js.map +1 -0
- package/dist/components/policy-workbench.d.ts +2 -0
- package/dist/components/policy-workbench.d.ts.map +1 -0
- package/dist/components/policy-workbench.js +102 -0
- package/dist/components/policy-workbench.js.map +1 -0
- package/dist/components/ts-language-service.d.ts +14 -0
- package/dist/components/ts-language-service.d.ts.map +1 -0
- package/dist/components/ts-language-service.js +123 -0
- package/dist/components/ts-language-service.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/browser/storage.d.ts +16 -0
- package/dist/lib/browser/storage.d.ts.map +1 -0
- package/dist/lib/browser/storage.js +18 -0
- package/dist/lib/browser/storage.js.map +1 -0
- package/dist/lib/edit.d.ts +14 -0
- package/dist/lib/edit.d.ts.map +1 -0
- package/dist/lib/edit.js +57 -0
- package/dist/lib/edit.js.map +1 -0
- package/dist/lib/flow-view.d.ts +80 -0
- package/dist/lib/flow-view.d.ts.map +1 -0
- package/dist/lib/flow-view.js +850 -0
- package/dist/lib/flow-view.js.map +1 -0
- package/dist/lib/heatmap.d.ts +28 -0
- package/dist/lib/heatmap.d.ts.map +1 -0
- package/dist/lib/heatmap.js +61 -0
- package/dist/lib/heatmap.js.map +1 -0
- package/dist/lib/index.d.ts +9 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +6 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/node-navigation.d.ts +36 -0
- package/dist/lib/node-navigation.d.ts.map +1 -0
- package/dist/lib/node-navigation.js +52 -0
- package/dist/lib/node-navigation.js.map +1 -0
- package/dist/lib/traces.d.ts +3 -0
- package/dist/lib/traces.d.ts.map +1 -0
- package/dist/lib/traces.js +64 -0
- package/dist/lib/traces.js.map +1 -0
- package/dist/lib/types.d.ts +57 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +7 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/store/blueprint-store.d.ts +35 -0
- package/dist/store/blueprint-store.d.ts.map +1 -0
- package/dist/store/blueprint-store.js +79 -0
- package/dist/store/blueprint-store.js.map +1 -0
- package/dist/store/index.d.ts +3 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +2 -0
- package/dist/store/index.js.map +1 -0
- package/package.json +52 -0
- package/scripts/wrap-cli.mjs +15 -0
- package/src/bin/cli.ts +128 -0
- package/src/components/blueprint-workbench.tsx +305 -0
- package/src/components/code-diff-editor.tsx +80 -0
- package/src/components/code-editor.tsx +389 -0
- package/src/components/file-tabs.tsx +288 -0
- package/src/components/file-tree.tsx +301 -0
- package/src/components/graph-canvas.tsx +404 -0
- package/src/components/ide-layout.tsx +104 -0
- package/src/components/ide-workbench.tsx +5 -0
- package/src/components/index.ts +12 -0
- package/src/components/monaco-setup.ts +67 -0
- package/src/components/opencode-settings.tsx +82 -0
- package/src/components/policy-workbench.tsx +233 -0
- package/src/components/ts-language-service.ts +170 -0
- package/src/index.ts +54 -0
- package/src/lib/browser/storage.ts +19 -0
- package/src/lib/edit.ts +74 -0
- package/src/lib/flow-view.ts +1176 -0
- package/src/lib/heatmap.ts +103 -0
- package/src/lib/index.ts +41 -0
- package/src/lib/node-navigation.ts +76 -0
- package/src/lib/traces.ts +79 -0
- package/src/lib/types.ts +79 -0
- package/src/store/blueprint-store.ts +136 -0
- package/src/store/index.ts +2 -0
- package/test-fixtures/minimal-blueprint.json +34 -0
- package/test-fixtures/sample-blueprint.json +184 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +22 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +9 -0
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@abhinav2203/codeflow-canvas",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "React Flow graph canvas with Monaco code editors and IDE layout components",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./flow-view": { "types": "./dist/flow-view/index.d.ts", "default": "./dist/flow-view/index.js" },
|
|
15
|
+
"./edit": { "types": "./dist/edit/index.d.ts", "default": "./dist/edit/index.js" },
|
|
16
|
+
"./traces": { "types": "./dist/traces/index.d.ts", "default": "./dist/traces/index.js" },
|
|
17
|
+
"./heatmap": { "types": "./dist/heatmap/index.d.ts", "default": "./dist/heatmap/index.js" },
|
|
18
|
+
"./store": { "types": "./dist/store/index.d.ts", "default": "./dist/store/index.js" }
|
|
19
|
+
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"codeflow-canvas": "./dist/bin/cli.js"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"check": "tsc --noEmit",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"build": "tsc --build && node scripts/wrap-cli.mjs",
|
|
27
|
+
"clean": "rm -rf dist"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@abhinav2203/codeflow-core": "^1.1.6",
|
|
31
|
+
"@xyflow/react": "^12.0.0",
|
|
32
|
+
"@monaco-editor/react": "^4.0.0",
|
|
33
|
+
"monaco-editor": "^0.52.0",
|
|
34
|
+
"react": "^18.0.0",
|
|
35
|
+
"react-dom": "^18.0.0",
|
|
36
|
+
"react-rnd": "^10.5.3",
|
|
37
|
+
"zustand": "^5.0.0",
|
|
38
|
+
"dotenv": "^16.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^22.0.0",
|
|
42
|
+
"@types/react": "^18.0.0",
|
|
43
|
+
"next": "^16.0.0",
|
|
44
|
+
"typescript": "^5.7.0",
|
|
45
|
+
"vitest": "^3.0.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"next": "^16.0.0",
|
|
49
|
+
"react": "^18.0.0",
|
|
50
|
+
"react-dom": "^18.0.0"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { resolve, dirname } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const cliSrc = resolve(__dirname, "../bin/cli.js");
|
|
7
|
+
const cliDest = resolve(__dirname, "../dist/bin/cli.js");
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
const content = readFileSync(cliSrc, "utf-8");
|
|
11
|
+
writeFileSync(cliDest, content, "utf-8");
|
|
12
|
+
console.log("CLI wrapper created at dist/bin/cli.js");
|
|
13
|
+
} catch {
|
|
14
|
+
// If the compiled CLI doesn't exist yet, that's fine for the build step
|
|
15
|
+
}
|
package/src/bin/cli.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { resolve, dirname } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
|
|
8
|
+
interface RawLog {
|
|
9
|
+
level: string;
|
|
10
|
+
msg: string;
|
|
11
|
+
time?: string;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface RawSpan {
|
|
16
|
+
spanId: string;
|
|
17
|
+
name: string;
|
|
18
|
+
status: string;
|
|
19
|
+
runtime: string;
|
|
20
|
+
timestamp: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface RenderOptions {
|
|
24
|
+
format?: "json" | "text";
|
|
25
|
+
nodeId?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function renderJson(graph: BlueprintGraph, options: RenderOptions): string {
|
|
29
|
+
if (options.nodeId) {
|
|
30
|
+
const node = graph.nodes.find((n) => n.id === options.nodeId);
|
|
31
|
+
if (!node) {
|
|
32
|
+
return JSON.stringify({ error: `Node ${options.nodeId} not found` }, null, 2);
|
|
33
|
+
}
|
|
34
|
+
return JSON.stringify(node, null, 2);
|
|
35
|
+
}
|
|
36
|
+
return JSON.stringify(graph, null, 2);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function renderText(graph: BlueprintGraph): string {
|
|
40
|
+
const lines: string[] = [];
|
|
41
|
+
lines.push(`# ${graph.projectName}`);
|
|
42
|
+
lines.push(`Phase: ${graph.phase}`);
|
|
43
|
+
lines.push("");
|
|
44
|
+
lines.push("## Nodes");
|
|
45
|
+
for (const node of graph.nodes) {
|
|
46
|
+
lines.push(`- [${node.kind}] ${node.name}: ${node.summary}`);
|
|
47
|
+
}
|
|
48
|
+
lines.push("");
|
|
49
|
+
lines.push("## Edges");
|
|
50
|
+
for (const edge of graph.edges) {
|
|
51
|
+
lines.push(`- ${edge.from} --[${edge.kind}]--> ${edge.to}`);
|
|
52
|
+
}
|
|
53
|
+
return lines.join("\n");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface BlueprintGraph {
|
|
57
|
+
projectName: string;
|
|
58
|
+
phase: string;
|
|
59
|
+
nodes: Array<{
|
|
60
|
+
id: string;
|
|
61
|
+
kind: string;
|
|
62
|
+
name: string;
|
|
63
|
+
summary: string;
|
|
64
|
+
[key: string]: unknown;
|
|
65
|
+
}>;
|
|
66
|
+
edges: Array<{
|
|
67
|
+
from: string;
|
|
68
|
+
to: string;
|
|
69
|
+
kind: string;
|
|
70
|
+
label?: string;
|
|
71
|
+
[key: string]: unknown;
|
|
72
|
+
}>;
|
|
73
|
+
workflows: Array<{ id: string; name: string; [key: string]: unknown }>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function main() {
|
|
77
|
+
const args = process.argv.slice(2);
|
|
78
|
+
let filePath: string | undefined;
|
|
79
|
+
let command = "render";
|
|
80
|
+
const options: RenderOptions = { format: "json" };
|
|
81
|
+
|
|
82
|
+
for (let i = 0; i < args.length; i++) {
|
|
83
|
+
if (args[i] === "render" && i + 1 < args.length) {
|
|
84
|
+
command = "render";
|
|
85
|
+
filePath = args[++i];
|
|
86
|
+
} else if (args[i] === "--format" && i + 1 < args.length) {
|
|
87
|
+
options.format = args[++i] as "json" | "text";
|
|
88
|
+
} else if (args[i] === "--node" && i + 1 < args.length) {
|
|
89
|
+
options.nodeId = args[++i];
|
|
90
|
+
} else if (!args[i].startsWith("--")) {
|
|
91
|
+
filePath = args[i];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!filePath) {
|
|
96
|
+
console.error("Usage: codeflow-canvas render <file> [--format json|text] [--node <id>]");
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const resolvedPath = resolve(filePath);
|
|
101
|
+
let graph: BlueprintGraph;
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const content = readFileSync(resolvedPath, "utf-8");
|
|
105
|
+
graph = JSON.parse(content);
|
|
106
|
+
} catch {
|
|
107
|
+
console.error(`Failed to read or parse blueprint file: ${resolvedPath}`);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
switch (command) {
|
|
112
|
+
case "render":
|
|
113
|
+
if (options.format === "text") {
|
|
114
|
+
console.log(renderText(graph));
|
|
115
|
+
} else {
|
|
116
|
+
console.log(renderJson(graph, options));
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
default:
|
|
120
|
+
console.error(`Unknown command: ${command}`);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
main().catch((err) => {
|
|
126
|
+
console.error("CLI error:", err);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
});
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { QueryResult } from "@abhinav2203/coderag";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
|
7
|
+
|
|
8
|
+
import { useBlueprintStore } from "../store/blueprint-store.js";
|
|
9
|
+
|
|
10
|
+
import { CodeEditor } from "./code-editor.js";
|
|
11
|
+
import { FileTabs } from "./file-tabs.js";
|
|
12
|
+
import { FileTree } from "./file-tree.js";
|
|
13
|
+
import { GraphCanvas } from "./graph-canvas.js";
|
|
14
|
+
import { IdeLayout } from "./ide-layout.js";
|
|
15
|
+
import { buildDetailFlow, indexRuntimeExecutionResult } from "../lib/flow-view.js";
|
|
16
|
+
import { computeHeatmap } from "../lib/heatmap.js";
|
|
17
|
+
import type { HeatmapData } from "../lib/heatmap.js";
|
|
18
|
+
import { formatNavigationTarget, getNavigationTarget, isValidNavigationTarget } from "../lib/node-navigation.js";
|
|
19
|
+
import { applyTraceOverlay } from "../lib/traces.js";
|
|
20
|
+
import type { CycleReport, SmellReport, GraphMetrics, RefactorReport, HealResult, OpencodeServerInfo } from "../lib/types.js";
|
|
21
|
+
import {
|
|
22
|
+
AUTO_IMPLEMENT_STORAGE_KEY,
|
|
23
|
+
LIVE_COMPLETIONS_STORAGE_KEY,
|
|
24
|
+
loadSessionApiKey,
|
|
25
|
+
readLocalBooleanPreference,
|
|
26
|
+
readRepoPath,
|
|
27
|
+
storeSessionApiKey,
|
|
28
|
+
writeLocalBooleanPreference,
|
|
29
|
+
writeRepoPath
|
|
30
|
+
} from "../lib/browser/storage.js";
|
|
31
|
+
import type {
|
|
32
|
+
ApprovalRecord,
|
|
33
|
+
BlueprintGraph,
|
|
34
|
+
BlueprintNode,
|
|
35
|
+
BranchDiff,
|
|
36
|
+
ConflictReport,
|
|
37
|
+
DigitalTwinSnapshot,
|
|
38
|
+
ExecutionMode,
|
|
39
|
+
ExportResult,
|
|
40
|
+
ExecutionArtifact,
|
|
41
|
+
ExecutionStep,
|
|
42
|
+
GhostNode,
|
|
43
|
+
GraphBranch,
|
|
44
|
+
McpServerConfig,
|
|
45
|
+
McpTool,
|
|
46
|
+
ObservabilityLog,
|
|
47
|
+
PersistedSession,
|
|
48
|
+
RiskReport,
|
|
49
|
+
RunPlan,
|
|
50
|
+
RuntimeExecutionResult,
|
|
51
|
+
TournamentResult,
|
|
52
|
+
VcrRecording
|
|
53
|
+
} from "@abhinav2203/codeflow-core/schema";
|
|
54
|
+
import { emptyContract, traceSpanSchema } from "@abhinav2203/codeflow-core/schema";
|
|
55
|
+
|
|
56
|
+
type BuildResponse = {
|
|
57
|
+
graph?: BlueprintGraph;
|
|
58
|
+
runPlan?: RunPlan;
|
|
59
|
+
session?: PersistedSession;
|
|
60
|
+
error?: string;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
type ExportResponse = {
|
|
64
|
+
result?: ExportResult;
|
|
65
|
+
runPlan?: RunPlan;
|
|
66
|
+
riskReport?: RiskReport;
|
|
67
|
+
session?: PersistedSession;
|
|
68
|
+
approval?: ApprovalRecord;
|
|
69
|
+
requiresApproval?: boolean;
|
|
70
|
+
error?: string;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
type ExecutionResponse = {
|
|
74
|
+
result?: RuntimeExecutionResult;
|
|
75
|
+
executedNodeId?: string;
|
|
76
|
+
graph?: BlueprintGraph;
|
|
77
|
+
runPlan?: RunPlan;
|
|
78
|
+
session?: PersistedSession;
|
|
79
|
+
error?: string;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
type ObservabilityLatestResponse = {
|
|
83
|
+
graph?: BlueprintGraph | null;
|
|
84
|
+
latestSpans?: Array<{ spanId: string; name: string; status: string; runtime: string; provenance?: string }>;
|
|
85
|
+
latestLogs?: ObservabilityLog[];
|
|
86
|
+
error?: string;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
type ConflictResponse = {
|
|
90
|
+
report?: ConflictReport;
|
|
91
|
+
error?: string;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
type CyclesResponse = {
|
|
95
|
+
report?: CycleReport;
|
|
96
|
+
error?: string;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
type SmellsResponse = {
|
|
100
|
+
report?: SmellReport;
|
|
101
|
+
error?: string;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
type MetricsResponse = {
|
|
105
|
+
metrics?: GraphMetrics;
|
|
106
|
+
error?: string;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const tracesSchema = z.array(traceSpanSchema);
|
|
110
|
+
|
|
111
|
+
const maskApiKey = (value: string) => {
|
|
112
|
+
const trimmed = value.trim();
|
|
113
|
+
if (trimmed.length <= 8) {
|
|
114
|
+
return trimmed;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return `${trimmed.slice(0, 4)}...${trimmed.slice(-4)}`;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
type StatusTone = "info" | "success" | "danger";
|
|
121
|
+
type IdeDockTab = "terminal" | "repo" | "heatmap" | "vcr" | "traces" | "problems";
|
|
122
|
+
type ActivityEntryTone = "info" | "success" | "error" | "command";
|
|
123
|
+
type ActivityEntry = {
|
|
124
|
+
id: string;
|
|
125
|
+
source: string;
|
|
126
|
+
message: string;
|
|
127
|
+
tone: ActivityEntryTone;
|
|
128
|
+
timestamp: string;
|
|
129
|
+
detail?: string;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export function BlueprintWorkbench() {
|
|
133
|
+
const {
|
|
134
|
+
activeFile,
|
|
135
|
+
floatingGraph,
|
|
136
|
+
graph,
|
|
137
|
+
openFiles,
|
|
138
|
+
repoPath,
|
|
139
|
+
selectedNodeId,
|
|
140
|
+
setActiveFile,
|
|
141
|
+
setFloatingGraph,
|
|
142
|
+
setGraph,
|
|
143
|
+
setOpenFiles,
|
|
144
|
+
setRepoPath,
|
|
145
|
+
setSelectedNodeId
|
|
146
|
+
} = useBlueprintStore();
|
|
147
|
+
|
|
148
|
+
const MIN_OBSERVABILITY_INTERVAL_SECS = 2;
|
|
149
|
+
const [projectName, setProjectName] = useState("CodeFlow Workspace");
|
|
150
|
+
const [prdText, setPrdText] = useState("");
|
|
151
|
+
const [aiPrompt, setAiPrompt] = useState("");
|
|
152
|
+
const [nvidiaApiKey, setNvidiaApiKey] = useState("");
|
|
153
|
+
const [executionMode, setExecutionMode] = useState<ExecutionMode>("essential");
|
|
154
|
+
const [outputDir, setOutputDir] = useState("");
|
|
155
|
+
const [traceInput, setTraceInput] = useState("");
|
|
156
|
+
const [runInput, setRunInput] = useState("{}");
|
|
157
|
+
const [error, setError] = useState<string | null>(null);
|
|
158
|
+
const [busyLabel, setBusyLabel] = useState<string | null>(null);
|
|
159
|
+
const [exportResult, setExportResult] = useState<ExportResult | null>(null);
|
|
160
|
+
const [runPlan, setRunPlan] = useState<RunPlan | null>(null);
|
|
161
|
+
const [riskReport, setRiskReport] = useState<RiskReport | null>(null);
|
|
162
|
+
const [session, setSession] = useState<PersistedSession | null>(null);
|
|
163
|
+
const [pendingApproval, setPendingApproval] = useState<ApprovalRecord | null>(null);
|
|
164
|
+
const [executionResult, setExecutionResult] = useState<RuntimeExecutionResult | null>(null);
|
|
165
|
+
const [latestLogs, setLatestLogs] = useState<ObservabilityLog[]>([]);
|
|
166
|
+
const [latestSpans, setLatestSpans] = useState<ObservabilityLatestResponse["latestSpans"]>([]);
|
|
167
|
+
const [conflictReport, setConflictReport] = useState<ConflictReport | null>(null);
|
|
168
|
+
const [newNodeName, setNewNodeName] = useState("");
|
|
169
|
+
const [newNodeKind, setNewNodeKind] = useState<BlueprintNode["kind"]>("function");
|
|
170
|
+
const [edgeFrom, setEdgeFrom] = useState("");
|
|
171
|
+
const [edgeTo, setEdgeTo] = useState("");
|
|
172
|
+
const [edgeKind, setEdgeKind] = useState<"calls" | "imports" | "inherits">("calls");
|
|
173
|
+
const [useAI, setUseAI] = useState(true);
|
|
174
|
+
const [drilldownStack, setDrilldownStack] = useState<string[]>([]);
|
|
175
|
+
const [selectedDetailNodeId, setSelectedDetailNodeId] = useState<string | null>(null);
|
|
176
|
+
const [codeDrafts, setCodeDrafts] = useState<Record<string, string>>({});
|
|
177
|
+
const [suggestionInstruction, setSuggestionInstruction] = useState("");
|
|
178
|
+
const [codeSuggestion, setCodeSuggestion] = useState<{ summary: string; code: string; notes: string[] } | null>(null);
|
|
179
|
+
const [liveCompletionsEnabled, setLiveCompletionsEnabled] = useState(true);
|
|
180
|
+
const [serverApiKeyConfigured, setServerApiKeyConfigured] = useState(false);
|
|
181
|
+
const [apiKeyStatusLoaded, setApiKeyStatusLoaded] = useState(false);
|
|
182
|
+
const [statusTitle, setStatusTitle] = useState("Ready to build");
|
|
183
|
+
const [statusDetail, setStatusDetail] = useState(
|
|
184
|
+
"Enter a project description or repo input, then build a blueprint."
|
|
185
|
+
);
|
|
186
|
+
const [statusTone, setStatusTone] = useState<StatusTone>("info");
|
|
187
|
+
const [activeDockTab, setActiveDockTab] = useState<IdeDockTab>("terminal");
|
|
188
|
+
const [activityFeed, setActivityFeed] = useState<ActivityEntry[]>([]);
|
|
189
|
+
const [showSettings, setShowSettings] = useState(false);
|
|
190
|
+
const [showPromptPanel, setShowPromptPanel] = useState(true);
|
|
191
|
+
const [showEditPanel, setShowEditPanel] = useState(false);
|
|
192
|
+
const [showInspector, setShowInspector] = useState(false);
|
|
193
|
+
const [showObservabilityPanel, setShowObservabilityPanel] = useState(false);
|
|
194
|
+
const [autoObservability, setAutoObservability] = useState(false);
|
|
195
|
+
const [observabilityIntervalSecs, setObservabilityIntervalSecs] = useState(5);
|
|
196
|
+
const autoObsRef = useRef(autoObservability);
|
|
197
|
+
autoObsRef.current = autoObservability;
|
|
198
|
+
const [autoImplementNodes, setAutoImplementNodes] = useState(false);
|
|
199
|
+
const [cycleReport, setCycleReport] = useState<CycleReport | null>(null);
|
|
200
|
+
const [smellReport, setSmellReport] = useState<SmellReport | null>(null);
|
|
201
|
+
const [graphMetrics, setGraphMetrics] = useState<GraphMetrics | null>(null);
|
|
202
|
+
const [mermaidDiagram, setMermaidDiagram] = useState<string | null>(null);
|
|
203
|
+
const [ghostSuggestions, setGhostSuggestions] = useState<GhostNode[]>([]);
|
|
204
|
+
const [showMcpPanel, setShowMcpPanel] = useState(false);
|
|
205
|
+
const [mcpServerUrl, setMcpServerUrl] = useState("");
|
|
206
|
+
const [mcpHeadersJson, setMcpHeadersJson] = useState("{}");
|
|
207
|
+
const [mcpToolName, setMcpToolName] = useState("");
|
|
208
|
+
const [mcpToolArgsJson, setMcpToolArgsJson] = useState("{}");
|
|
209
|
+
const [availableMcpTools, setAvailableMcpTools] = useState<McpTool[]>([]);
|
|
210
|
+
const [mcpInvokeResult, setMcpInvokeResult] = useState<string | null>(null);
|
|
211
|
+
const [mcpError, setMcpError] = useState<string | null>(null);
|
|
212
|
+
|
|
213
|
+
const [branches, setBranches] = useState<GraphBranch[]>([]);
|
|
214
|
+
const [showBranchPanel, setShowBranchPanel] = useState(false);
|
|
215
|
+
const [newBranchName, setNewBranchName] = useState("");
|
|
216
|
+
const [newBranchDescription, setNewBranchDescription] = useState("");
|
|
217
|
+
const [activeBranchId, setActiveBranchId] = useState<string | null>(null);
|
|
218
|
+
const [branchDiff, setBranchDiff] = useState<BranchDiff | null>(null);
|
|
219
|
+
const [diffTargetBranchId, setDiffTargetBranchId] = useState<string | null>(null);
|
|
220
|
+
|
|
221
|
+
const [showVcrPanel, setShowVcrPanel] = useState(false);
|
|
222
|
+
const [vcrRecording, setVcrRecording] = useState<VcrRecording | null>(null);
|
|
223
|
+
const [vcrFrameIndex, setVcrFrameIndex] = useState(0);
|
|
224
|
+
const [vcrPlaying, setVcrPlaying] = useState(false);
|
|
225
|
+
const [vcrGraph, setVcrGraph] = useState<BlueprintGraph | null>(null);
|
|
226
|
+
const [vcrError, setVcrError] = useState<string | null>(null);
|
|
227
|
+
|
|
228
|
+
const [showDigitalTwinPanel, setShowDigitalTwinPanel] = useState(false);
|
|
229
|
+
const [digitalTwinSnapshot, setDigitalTwinSnapshot] = useState<DigitalTwinSnapshot | null>(null);
|
|
230
|
+
const [digitalTwinGraph, setDigitalTwinGraph] = useState<BlueprintGraph | null>(null);
|
|
231
|
+
const [digitalTwinWindowSecs, setDigitalTwinWindowSecs] = useState(60);
|
|
232
|
+
const [autoDigitalTwin, setAutoDigitalTwin] = useState(false);
|
|
233
|
+
const autoDigitalTwinRef = useRef(autoDigitalTwin);
|
|
234
|
+
autoDigitalTwinRef.current = autoDigitalTwin;
|
|
235
|
+
const [simulateNodeIds, setSimulateNodeIds] = useState("");
|
|
236
|
+
const [simulateLabel, setSimulateLabel] = useState("");
|
|
237
|
+
const [digitalTwinError, setDigitalTwinError] = useState<string | null>(null);
|
|
238
|
+
const [digitalTwinPollError, setDigitalTwinPollError] = useState<string | null>(null);
|
|
239
|
+
const [digitalTwinLastUpdatedAt, setDigitalTwinLastUpdatedAt] = useState<string | null>(null);
|
|
240
|
+
|
|
241
|
+
const [showRefactorPanel, setShowRefactorPanel] = useState(false);
|
|
242
|
+
const [refactorReport, setRefactorReport] = useState<RefactorReport | null>(null);
|
|
243
|
+
const [healResult, setHealResult] = useState<HealResult | null>(null);
|
|
244
|
+
const [refactorError, setRefactorError] = useState<string | null>(null);
|
|
245
|
+
const graphReplacedByHealRef = useRef(false);
|
|
246
|
+
const refactorAbortRef = useRef<AbortController | null>(null);
|
|
247
|
+
|
|
248
|
+
const [showGeneticPanel, setShowGeneticPanel] = useState(false);
|
|
249
|
+
const [showMascotPanel, setShowMascotPanel] = useState(false);
|
|
250
|
+
const [showPhasePanel, setShowPhasePanel] = useState(false);
|
|
251
|
+
const [geneticGenerations, setGeneticGenerations] = useState(3);
|
|
252
|
+
const [geneticPopulationSize, setGeneticPopulationSize] = useState(6);
|
|
253
|
+
const [tournamentResult, setTournamentResult] = useState<TournamentResult | null>(null);
|
|
254
|
+
const [geneticError, setGeneticError] = useState<string | null>(null);
|
|
255
|
+
const [editorRevealTarget, setEditorRevealTarget] = useState<ReturnType<typeof getNavigationTarget>>(null);
|
|
256
|
+
const [navigationError, setNavigationError] = useState<string | null>(null);
|
|
257
|
+
|
|
258
|
+
const [showOpencodePanel, setShowOpencodePanel] = useState(false);
|
|
259
|
+
const [opencodeStatus, setOpencodeStatus] = useState<OpencodeServerInfo>({ status: "stopped" });
|
|
260
|
+
const [useOpencodeForAgent, setUseOpencodeForAgent] = useState(false);
|
|
261
|
+
|
|
262
|
+
const selectedNode = graph?.nodes.find((node) => node.id === selectedNodeId) ?? null;
|
|
263
|
+
const drilldownNodeId = drilldownStack.at(-1) ?? null;
|
|
264
|
+
const drilldownRootNode = graph?.nodes.find((node) => node.id === drilldownNodeId) ?? null;
|
|
265
|
+
const executionIndex = useMemo(
|
|
266
|
+
() => indexRuntimeExecutionResult(executionResult),
|
|
267
|
+
[executionResult]
|
|
268
|
+
);
|
|
269
|
+
const detailFlow =
|
|
270
|
+
graph && drilldownNodeId
|
|
271
|
+
? buildDetailFlow(graph, drilldownNodeId, selectedDetailNodeId ?? undefined, executionResult)
|
|
272
|
+
: null;
|
|
273
|
+
const heatmapData: HeatmapData | undefined = useMemo(
|
|
274
|
+
() =>
|
|
275
|
+
graph &&
|
|
276
|
+
graph.nodes.some(
|
|
277
|
+
(node) => node.traceState && node.traceState.count > 0
|
|
278
|
+
)
|
|
279
|
+
? computeHeatmap(graph)
|
|
280
|
+
: undefined,
|
|
281
|
+
[graph]
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
const canStartImplementation = false;
|
|
285
|
+
const canStartIntegration = false;
|
|
286
|
+
const canImplementActiveNode = false;
|
|
287
|
+
const canRunActiveNode = false;
|
|
288
|
+
const isBusy = Boolean(busyLabel);
|
|
289
|
+
const isBuilding = busyLabel === "Building blueprint";
|
|
290
|
+
|
|
291
|
+
return (
|
|
292
|
+
<div className="workbench-shell">
|
|
293
|
+
<div className="workbench-main">
|
|
294
|
+
<div className="graph-panel">
|
|
295
|
+
<GraphCanvas
|
|
296
|
+
graph={graph}
|
|
297
|
+
selectedNodeId={selectedNodeId}
|
|
298
|
+
onSelect={setSelectedNodeId}
|
|
299
|
+
heatmapData={heatmapData}
|
|
300
|
+
/>
|
|
301
|
+
</div>
|
|
302
|
+
</div>
|
|
303
|
+
</div>
|
|
304
|
+
);
|
|
305
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useRef } from "react";
|
|
4
|
+
|
|
5
|
+
import dynamic from "next/dynamic";
|
|
6
|
+
import type * as Monaco from "monaco-editor";
|
|
7
|
+
|
|
8
|
+
import { prepareMonaco, toMonacoPath } from "./monaco-setup.js";
|
|
9
|
+
|
|
10
|
+
const MonacoDiffEditor = dynamic(() => import("@monaco-editor/react").then(mod => mod.DiffEditor), {
|
|
11
|
+
ssr: false,
|
|
12
|
+
loading: () => <div className="code-diff-editor-loading">Loading diff editor...</div>
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
type CodeDiffEditorProps = {
|
|
16
|
+
originalValue: string;
|
|
17
|
+
modifiedValue: string;
|
|
18
|
+
language?: "typescript" | "javascript" | "json" | "markdown";
|
|
19
|
+
height?: string;
|
|
20
|
+
readOnly?: boolean;
|
|
21
|
+
theme?: "light" | "dark";
|
|
22
|
+
onModifiedChange?: (value: string) => void;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function CodeDiffEditor({
|
|
26
|
+
originalValue,
|
|
27
|
+
modifiedValue,
|
|
28
|
+
language = "typescript",
|
|
29
|
+
height = "28rem",
|
|
30
|
+
readOnly = false,
|
|
31
|
+
theme = "dark",
|
|
32
|
+
onModifiedChange
|
|
33
|
+
}: CodeDiffEditorProps): React.JSX.Element {
|
|
34
|
+
const monacoRef = useRef<typeof Monaco | null>(null);
|
|
35
|
+
const modifiedListenerRef = useRef<Monaco.IDisposable | null>(null);
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div
|
|
39
|
+
className="code-diff-editor-shell"
|
|
40
|
+
style={{
|
|
41
|
+
height,
|
|
42
|
+
minHeight: height === "100%" ? 0 : height
|
|
43
|
+
}}
|
|
44
|
+
>
|
|
45
|
+
<MonacoDiffEditor
|
|
46
|
+
beforeMount={prepareMonaco}
|
|
47
|
+
height={height}
|
|
48
|
+
language={language}
|
|
49
|
+
modified={modifiedValue}
|
|
50
|
+
modifiedModelPath={toMonacoPath("diff/modified.ts")}
|
|
51
|
+
options={{
|
|
52
|
+
automaticLayout: true,
|
|
53
|
+
diffCodeLens: true,
|
|
54
|
+
enableSplitViewResizing: true,
|
|
55
|
+
fontFamily: "IBM Plex Mono, SFMono-Regular, SF Mono, monospace",
|
|
56
|
+
fontLigatures: true,
|
|
57
|
+
fontSize: 14,
|
|
58
|
+
lineNumbersMinChars: 3,
|
|
59
|
+
minimap: { enabled: false },
|
|
60
|
+
padding: { top: 16, bottom: 16 },
|
|
61
|
+
readOnly,
|
|
62
|
+
renderSideBySide: true,
|
|
63
|
+
scrollBeyondLastLine: false,
|
|
64
|
+
smoothScrolling: true,
|
|
65
|
+
wordWrap: "on"
|
|
66
|
+
}}
|
|
67
|
+
original={originalValue}
|
|
68
|
+
originalModelPath={toMonacoPath("diff/original.ts")}
|
|
69
|
+
onMount={(editor, monaco) => {
|
|
70
|
+
monacoRef.current = monaco;
|
|
71
|
+
modifiedListenerRef.current?.dispose();
|
|
72
|
+
modifiedListenerRef.current = editor.getModifiedEditor().onDidChangeModelContent(() => {
|
|
73
|
+
onModifiedChange?.(editor.getModifiedEditor().getValue());
|
|
74
|
+
});
|
|
75
|
+
}}
|
|
76
|
+
theme={theme === "dark" ? "vs-dark" : "vs-light"}
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
}
|