agent-canvas 0.1.5 → 0.1.8
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/.github/workflows/ci.yml +23 -0
- package/.github/workflows/release.yml +36 -0
- package/CLAUDE.md +86 -0
- package/LICENSE +21 -0
- package/README.md +71 -0
- package/bin/agent-canvas.ts +26 -353
- package/bin/lib/commands/daemon.ts +51 -0
- package/bin/lib/commands/fetch.ts +20 -0
- package/bin/lib/commands/install.ts +48 -0
- package/bin/lib/commands/push.ts +67 -0
- package/bin/lib/commands/watch.ts +23 -0
- package/bin/lib/config.ts +10 -0
- package/bin/lib/daemon-lifecycle.ts +74 -0
- package/bin/lib/helpers.ts +78 -0
- package/bun.lock +176 -0
- package/daemon/build.ts +27 -61
- package/daemon/bunfig.toml +2 -0
- package/daemon/client/AnnotationProvider.tsx +2 -2
- package/daemon/client/AnnotationSidebar.tsx +199 -31
- package/daemon/client/App.tsx +39 -3
- package/daemon/client/FileBrowser.tsx +8 -7
- package/daemon/client/FileViewer.tsx +153 -16
- package/daemon/client/PlanRenderer.tsx +6 -3
- package/daemon/client/ResponsePreview.tsx +5 -116
- package/daemon/client/SessionSwitcher.tsx +21 -10
- package/daemon/client/compat/preact-all.ts +4 -0
- package/daemon/client/components/Markdown.tsx +44 -0
- package/daemon/client/components/ResponseNote.tsx +3 -8
- package/daemon/client/components/UserInput.tsx +2 -4
- package/daemon/client/components/index.ts +1 -0
- package/daemon/client/domDiff.ts +82 -2
- package/daemon/client/generateMarkdown.ts +46 -9
- package/daemon/client/highlightRange.ts +8 -6
- package/daemon/client/runtime.ts +2 -0
- package/daemon/client/styles.css +126 -0
- package/daemon/client/unifiedDiff.ts +155 -2
- package/daemon/client/utils.ts +10 -0
- package/daemon/dist/client.css +1 -1
- package/daemon/dist/client.js +83 -36
- package/daemon/dist/components.js +63 -5
- package/daemon/dist/index.html +5 -12
- package/daemon/dist/jsx-runtime.js +3 -0
- package/daemon/dist/preact-compat.js +1 -0
- package/daemon/langMap.ts +8 -0
- package/daemon/src/compiler.ts +28 -2
- package/daemon/src/handlers/api.ts +150 -0
- package/daemon/src/handlers/files.ts +114 -0
- package/daemon/src/handlers/static.ts +61 -0
- package/daemon/src/handlers/utils.ts +14 -0
- package/daemon/src/router.ts +16 -0
- package/daemon/src/server.ts +28 -403
- package/daemon/src/session.ts +43 -24
- package/daemon/src/websocket.ts +83 -0
- package/daemon/tsconfig.json +20 -0
- package/package.json +4 -14
- package/skills/canvas/SKILL.md +47 -22
- package/skills/canvas/components.md +31 -0
- package/skills/canvas/flows.md +2 -2
- package/tsconfig.json +14 -0
- package/daemon/dist/jsx-dev-runtime-shim.js +0 -17
- package/daemon/dist/jsx-runtime-shim.js +0 -17
- package/daemon/dist/react-dom-client-shim.js +0 -4
- package/daemon/dist/react-dom-shim.js +0 -4
- package/daemon/dist/react-shim.js +0 -4
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { parseArgs } from "util";
|
|
2
|
+
import { ensureDaemon } from "../daemon-lifecycle.ts";
|
|
3
|
+
import { getSessionId, consumeFeedback } from "../helpers.ts";
|
|
4
|
+
|
|
5
|
+
export async function handleFetch(args: string[]) {
|
|
6
|
+
const { values } = parseArgs({
|
|
7
|
+
args,
|
|
8
|
+
options: {
|
|
9
|
+
session: { type: "string" },
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const sessionId = getSessionId(values.session);
|
|
14
|
+
await ensureDaemon();
|
|
15
|
+
|
|
16
|
+
const feedback = await consumeFeedback(sessionId);
|
|
17
|
+
if (feedback) {
|
|
18
|
+
process.stdout.write(feedback);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { parseArgs } from "util";
|
|
2
|
+
import { existsSync, mkdirSync, cpSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
import { PACKAGE_ROOT } from "../config.ts";
|
|
6
|
+
import { readLine } from "../helpers.ts";
|
|
7
|
+
|
|
8
|
+
export async function handleInstall(args: string[]) {
|
|
9
|
+
const { positionals } = parseArgs({
|
|
10
|
+
args,
|
|
11
|
+
allowPositionals: true,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
let mode = positionals[0] as "local" | "global" | undefined;
|
|
15
|
+
|
|
16
|
+
if (!mode) {
|
|
17
|
+
process.stdout.write("Install canvas skill for Claude Code.\n\n");
|
|
18
|
+
process.stdout.write(" local — install to .claude/ in current project\n");
|
|
19
|
+
process.stdout.write(" global — install to ~/.claude/ for all projects\n\n");
|
|
20
|
+
process.stdout.write("Choose [local/global]: ");
|
|
21
|
+
|
|
22
|
+
const input = await readLine();
|
|
23
|
+
mode = input.trim().toLowerCase() as "local" | "global";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (mode !== "local" && mode !== "global") {
|
|
27
|
+
console.error("Error: specify 'local' or 'global'");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const targetBase = mode === "global"
|
|
32
|
+
? join(homedir(), ".claude")
|
|
33
|
+
: join(process.cwd(), ".claude");
|
|
34
|
+
|
|
35
|
+
const skillTarget = join(targetBase, "skills", "canvas");
|
|
36
|
+
mkdirSync(skillTarget, { recursive: true });
|
|
37
|
+
|
|
38
|
+
const skillSrc = join(PACKAGE_ROOT, "skills", "canvas");
|
|
39
|
+
for (const file of ["SKILL.md", "components.md", "flows.md"]) {
|
|
40
|
+
const src = join(skillSrc, file);
|
|
41
|
+
if (existsSync(src)) {
|
|
42
|
+
cpSync(src, join(skillTarget, file));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log(` Skill installed to ${skillTarget}`);
|
|
47
|
+
console.log(`\nInstalled! The /canvas command is now available in Claude Code.`);
|
|
48
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { parseArgs } from "util";
|
|
2
|
+
import { readFileSync, existsSync } from "fs";
|
|
3
|
+
import { resolve } from "path";
|
|
4
|
+
import { BASE_URL } from "../config.ts";
|
|
5
|
+
import { ensureDaemon } from "../daemon-lifecycle.ts";
|
|
6
|
+
import { getSessionId, openBrowser } from "../helpers.ts";
|
|
7
|
+
|
|
8
|
+
export async function handlePush(args: string[]) {
|
|
9
|
+
const { values, positionals } = parseArgs({
|
|
10
|
+
args,
|
|
11
|
+
options: {
|
|
12
|
+
session: { type: "string" },
|
|
13
|
+
label: { type: "string" },
|
|
14
|
+
response: { type: "string" },
|
|
15
|
+
},
|
|
16
|
+
allowPositionals: true,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const filePath = positionals[0];
|
|
20
|
+
if (!filePath) {
|
|
21
|
+
console.error("Error: No file specified. Usage: agent-canvas push <file.jsx>");
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const resolvedPath = resolve(filePath);
|
|
26
|
+
if (!existsSync(resolvedPath)) {
|
|
27
|
+
console.error(`Error: File not found: ${resolvedPath}`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
const jsx = readFileSync(resolvedPath, "utf-8");
|
|
31
|
+
|
|
32
|
+
const sessionId = getSessionId(values.session);
|
|
33
|
+
const projectRoot = process.env.CANVAS_PROJECT_ROOT || process.cwd();
|
|
34
|
+
const label = values.label;
|
|
35
|
+
const autoLabel = !label ? resolvedPath.split("/").pop()?.replace(/\.jsx$/, "") : undefined;
|
|
36
|
+
|
|
37
|
+
await ensureDaemon();
|
|
38
|
+
|
|
39
|
+
const response = await fetch(`${BASE_URL}/api/session/${sessionId}/plan`, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: { "Content-Type": "application/json" },
|
|
42
|
+
body: JSON.stringify({ jsx, projectRoot, label: label || autoLabel, sourceFile: resolvedPath.split("/").pop(), ...(values.response ? { response: values.response } : {}) }),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const result = await response.json() as any;
|
|
46
|
+
|
|
47
|
+
if (!result.ok) {
|
|
48
|
+
if (result.unconsumedFeedback) {
|
|
49
|
+
console.error(`Error: ${result.error}`);
|
|
50
|
+
console.log(result.unconsumedFeedback);
|
|
51
|
+
} else {
|
|
52
|
+
console.error(`Compilation error:\n${result.error}`);
|
|
53
|
+
}
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (result.isNew) {
|
|
58
|
+
openBrowser(result.browserUrl);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log(JSON.stringify({
|
|
62
|
+
ok: true,
|
|
63
|
+
browserUrl: result.browserUrl,
|
|
64
|
+
revision: result.revision,
|
|
65
|
+
sessionId,
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { parseArgs } from "util";
|
|
2
|
+
import { ensureDaemon } from "../daemon-lifecycle.ts";
|
|
3
|
+
import { getSessionId, consumeFeedback, waitForFeedback } from "../helpers.ts";
|
|
4
|
+
|
|
5
|
+
export async function handleWatch(args: string[]) {
|
|
6
|
+
const { values } = parseArgs({
|
|
7
|
+
args,
|
|
8
|
+
options: {
|
|
9
|
+
session: { type: "string" },
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const sessionId = getSessionId(values.session);
|
|
14
|
+
await ensureDaemon();
|
|
15
|
+
|
|
16
|
+
const feedback = await consumeFeedback(sessionId);
|
|
17
|
+
if (feedback) {
|
|
18
|
+
process.stdout.write(feedback);
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
await waitForFeedback(sessionId);
|
|
23
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { resolve, join, dirname } from "path";
|
|
2
|
+
import { tmpdir } from "os";
|
|
3
|
+
|
|
4
|
+
export const PACKAGE_ROOT = resolve(join(dirname(import.meta.path), "../.."));
|
|
5
|
+
export const TEMP_DIR = join(tmpdir(), "agent-canvas");
|
|
6
|
+
export const DAEMON_PORT = parseInt(process.env.CANVAS_PORT || "19400", 10);
|
|
7
|
+
export const BASE_URL = `http://localhost:${DAEMON_PORT}`;
|
|
8
|
+
export const WS_URL = `ws://localhost:${DAEMON_PORT}`;
|
|
9
|
+
export const TIMEOUT_MS = parseInt(process.env.CANVAS_TIMEOUT || String(60 * 60 * 1000), 10);
|
|
10
|
+
export const PID_FILE = join(TEMP_DIR, "daemon.pid");
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { openSync, closeSync, readFileSync, existsSync, mkdirSync, unlinkSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { PACKAGE_ROOT, TEMP_DIR, BASE_URL, PID_FILE } from "./config.ts";
|
|
5
|
+
|
|
6
|
+
export async function isDaemonRunning(): Promise<boolean> {
|
|
7
|
+
try {
|
|
8
|
+
const res = await fetch(`${BASE_URL}/health`, { signal: AbortSignal.timeout(1000) });
|
|
9
|
+
const data = await res.json() as any;
|
|
10
|
+
return data.ok === true;
|
|
11
|
+
} catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function startDaemon(): Promise<void> {
|
|
17
|
+
console.error("Starting canvas daemon...");
|
|
18
|
+
mkdirSync(TEMP_DIR, { recursive: true });
|
|
19
|
+
|
|
20
|
+
const daemonScript = join(PACKAGE_ROOT, "daemon", "src", "server.ts");
|
|
21
|
+
const stderrPath = join(TEMP_DIR, "daemon-startup.log");
|
|
22
|
+
const stderrFd = openSync(stderrPath, "w");
|
|
23
|
+
|
|
24
|
+
const child = spawn("bun", ["run", daemonScript], {
|
|
25
|
+
detached: true,
|
|
26
|
+
stdio: ["ignore", "ignore", stderrFd],
|
|
27
|
+
cwd: join(PACKAGE_ROOT, "daemon"),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
child.unref();
|
|
31
|
+
closeSync(stderrFd);
|
|
32
|
+
|
|
33
|
+
for (let i = 0; i < 30; i++) {
|
|
34
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
35
|
+
if (await isDaemonRunning()) {
|
|
36
|
+
console.error("Daemon started.");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (existsSync(stderrPath)) {
|
|
42
|
+
const stderr = readFileSync(stderrPath, "utf-8").trim();
|
|
43
|
+
if (stderr) {
|
|
44
|
+
console.error("Daemon stderr:\n" + stderr);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
console.error("Error: Daemon failed to start within 3 seconds.");
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function ensureDaemon(): Promise<void> {
|
|
53
|
+
if (await isDaemonRunning()) return;
|
|
54
|
+
await startDaemon();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function stopDaemon(): boolean {
|
|
58
|
+
if (existsSync(PID_FILE)) {
|
|
59
|
+
const pid = parseInt(readFileSync(PID_FILE, "utf-8").trim(), 10);
|
|
60
|
+
try {
|
|
61
|
+
process.kill(pid, "SIGTERM");
|
|
62
|
+
console.log("Daemon stopped.");
|
|
63
|
+
try { unlinkSync(PID_FILE); } catch {}
|
|
64
|
+
return true;
|
|
65
|
+
} catch {
|
|
66
|
+
console.log("Daemon was not running (stale PID file).");
|
|
67
|
+
try { unlinkSync(PID_FILE); } catch {}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
console.log("No daemon PID file found.");
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { randomUUID } from "crypto";
|
|
3
|
+
import { BASE_URL, WS_URL, TIMEOUT_MS } from "./config.ts";
|
|
4
|
+
|
|
5
|
+
export function getSessionId(session?: string): string {
|
|
6
|
+
if (session) return session;
|
|
7
|
+
return process.env.CANVAS_SESSION_ID || (() => {
|
|
8
|
+
const id = randomUUID();
|
|
9
|
+
console.error(`Warning: CANVAS_SESSION_ID not set, using generated ID: ${id}`);
|
|
10
|
+
return id;
|
|
11
|
+
})();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function consumeFeedback(sessionId: string): Promise<string | null> {
|
|
15
|
+
const res = await fetch(`${BASE_URL}/api/session/${sessionId}/feedback/consume`, { method: "POST" });
|
|
16
|
+
const data = await res.json() as any;
|
|
17
|
+
if (data.found) return data.feedback;
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function openBrowser(url: string) {
|
|
22
|
+
const candidates = process.platform === "darwin"
|
|
23
|
+
? ["open"]
|
|
24
|
+
: ["xdg-open", "wslview", "sensible-browser"];
|
|
25
|
+
|
|
26
|
+
for (const cmd of candidates) {
|
|
27
|
+
const which = Bun.spawnSync(["which", cmd]);
|
|
28
|
+
if (which.exitCode === 0) {
|
|
29
|
+
spawn(cmd, [url], { detached: true, stdio: "ignore" }).unref();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
console.error(`Open this URL in your browser: ${url}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function waitForFeedback(sessionId: string): Promise<void> {
|
|
37
|
+
return new Promise((resolveP, rejectP) => {
|
|
38
|
+
const ws = new WebSocket(`${WS_URL}/ws/wait/${sessionId}`);
|
|
39
|
+
const timeout = setTimeout(() => {
|
|
40
|
+
ws.close();
|
|
41
|
+
console.error("Error: Timeout waiting for feedback.");
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}, TIMEOUT_MS);
|
|
44
|
+
|
|
45
|
+
ws.onmessage = (event) => {
|
|
46
|
+
try {
|
|
47
|
+
const data = JSON.parse(typeof event.data === "string" ? event.data : "");
|
|
48
|
+
if (data.type === "submit") {
|
|
49
|
+
clearTimeout(timeout);
|
|
50
|
+
process.stdout.write(data.feedback);
|
|
51
|
+
ws.close();
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
} catch {}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
ws.onerror = () => {
|
|
58
|
+
clearTimeout(timeout);
|
|
59
|
+
console.error("Error: WebSocket connection failed.");
|
|
60
|
+
process.exit(1);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
ws.onclose = () => {
|
|
64
|
+
clearTimeout(timeout);
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function readLine(): Promise<string> {
|
|
70
|
+
const buf: number[] = [];
|
|
71
|
+
for await (const chunk of Bun.stdin.stream()) {
|
|
72
|
+
for (const byte of chunk) {
|
|
73
|
+
if (byte === 10) return Buffer.from(buf).toString("utf-8");
|
|
74
|
+
buf.push(byte);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return Buffer.from(buf).toString("utf-8");
|
|
78
|
+
}
|
package/bun.lock
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"configVersion": 1,
|
|
4
|
+
"workspaces": {
|
|
5
|
+
"": {
|
|
6
|
+
"name": "agent-canvas",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"marked": "^17.0.4",
|
|
9
|
+
"preact": "^10.25.0",
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@tailwindcss/cli": "4",
|
|
13
|
+
"@types/bun": "^1.3.10",
|
|
14
|
+
"@types/react": "^18.3.12",
|
|
15
|
+
"@types/react-dom": "^18.3.1",
|
|
16
|
+
"tailwindcss": "4",
|
|
17
|
+
"typescript": "^5.9.3",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
"packages": {
|
|
22
|
+
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
|
23
|
+
|
|
24
|
+
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
|
|
25
|
+
|
|
26
|
+
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
|
27
|
+
|
|
28
|
+
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
|
29
|
+
|
|
30
|
+
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
|
31
|
+
|
|
32
|
+
"@parcel/watcher": ["@parcel/watcher@2.5.6", "", { "dependencies": { "detect-libc": "^2.0.3", "is-glob": "^4.0.3", "node-addon-api": "^7.0.0", "picomatch": "^4.0.3" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.6", "@parcel/watcher-darwin-arm64": "2.5.6", "@parcel/watcher-darwin-x64": "2.5.6", "@parcel/watcher-freebsd-x64": "2.5.6", "@parcel/watcher-linux-arm-glibc": "2.5.6", "@parcel/watcher-linux-arm-musl": "2.5.6", "@parcel/watcher-linux-arm64-glibc": "2.5.6", "@parcel/watcher-linux-arm64-musl": "2.5.6", "@parcel/watcher-linux-x64-glibc": "2.5.6", "@parcel/watcher-linux-x64-musl": "2.5.6", "@parcel/watcher-win32-arm64": "2.5.6", "@parcel/watcher-win32-ia32": "2.5.6", "@parcel/watcher-win32-x64": "2.5.6" } }, "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ=="],
|
|
33
|
+
|
|
34
|
+
"@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.6", "", { "os": "android", "cpu": "arm64" }, "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A=="],
|
|
35
|
+
|
|
36
|
+
"@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA=="],
|
|
37
|
+
|
|
38
|
+
"@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg=="],
|
|
39
|
+
|
|
40
|
+
"@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.6", "", { "os": "freebsd", "cpu": "x64" }, "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng=="],
|
|
41
|
+
|
|
42
|
+
"@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.6", "", { "os": "linux", "cpu": "arm" }, "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ=="],
|
|
43
|
+
|
|
44
|
+
"@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.6", "", { "os": "linux", "cpu": "arm" }, "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg=="],
|
|
45
|
+
|
|
46
|
+
"@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA=="],
|
|
47
|
+
|
|
48
|
+
"@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA=="],
|
|
49
|
+
|
|
50
|
+
"@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ=="],
|
|
51
|
+
|
|
52
|
+
"@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg=="],
|
|
53
|
+
|
|
54
|
+
"@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q=="],
|
|
55
|
+
|
|
56
|
+
"@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.6", "", { "os": "win32", "cpu": "ia32" }, "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g=="],
|
|
57
|
+
|
|
58
|
+
"@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw=="],
|
|
59
|
+
|
|
60
|
+
"@tailwindcss/cli": ["@tailwindcss/cli@4.2.1", "", { "dependencies": { "@parcel/watcher": "^2.5.1", "@tailwindcss/node": "4.2.1", "@tailwindcss/oxide": "4.2.1", "enhanced-resolve": "^5.19.0", "mri": "^1.2.0", "picocolors": "^1.1.1", "tailwindcss": "4.2.1" }, "bin": { "tailwindcss": "dist/index.mjs" } }, "sha512-b7MGn51IA80oSG+7fuAgzfQ+7pZBgjzbqwmiv6NO7/+a1sev32cGqnwhscT7h0EcAvMa9r7gjRylqOH8Xhc4DA=="],
|
|
61
|
+
|
|
62
|
+
"@tailwindcss/node": ["@tailwindcss/node@4.2.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.31.1", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.1" } }, "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg=="],
|
|
63
|
+
|
|
64
|
+
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.1", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.1", "@tailwindcss/oxide-darwin-arm64": "4.2.1", "@tailwindcss/oxide-darwin-x64": "4.2.1", "@tailwindcss/oxide-freebsd-x64": "4.2.1", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", "@tailwindcss/oxide-linux-x64-musl": "4.2.1", "@tailwindcss/oxide-wasm32-wasi": "4.2.1", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" } }, "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw=="],
|
|
65
|
+
|
|
66
|
+
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.1", "", { "os": "android", "cpu": "arm64" }, "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg=="],
|
|
67
|
+
|
|
68
|
+
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw=="],
|
|
69
|
+
|
|
70
|
+
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw=="],
|
|
71
|
+
|
|
72
|
+
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA=="],
|
|
73
|
+
|
|
74
|
+
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw=="],
|
|
75
|
+
|
|
76
|
+
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ=="],
|
|
77
|
+
|
|
78
|
+
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ=="],
|
|
79
|
+
|
|
80
|
+
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g=="],
|
|
81
|
+
|
|
82
|
+
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g=="],
|
|
83
|
+
|
|
84
|
+
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.1", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q=="],
|
|
85
|
+
|
|
86
|
+
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA=="],
|
|
87
|
+
|
|
88
|
+
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.1", "", { "os": "win32", "cpu": "x64" }, "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ=="],
|
|
89
|
+
|
|
90
|
+
"@types/bun": ["@types/bun@1.3.10", "", { "dependencies": { "bun-types": "1.3.10" } }, "sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ=="],
|
|
91
|
+
|
|
92
|
+
"@types/node": ["@types/node@25.5.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw=="],
|
|
93
|
+
|
|
94
|
+
"@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="],
|
|
95
|
+
|
|
96
|
+
"@types/react": ["@types/react@18.3.28", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" } }, "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw=="],
|
|
97
|
+
|
|
98
|
+
"@types/react-dom": ["@types/react-dom@18.3.7", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ=="],
|
|
99
|
+
|
|
100
|
+
"bun-types": ["bun-types@1.3.10", "", { "dependencies": { "@types/node": "*" } }, "sha512-tcpfCCl6XWo6nCVnpcVrxQ+9AYN1iqMIzgrSKYMB/fjLtV2eyAVEg7AxQJuCq/26R6HpKWykQXuSOq/21RYcbg=="],
|
|
101
|
+
|
|
102
|
+
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
|
103
|
+
|
|
104
|
+
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
|
105
|
+
|
|
106
|
+
"enhanced-resolve": ["enhanced-resolve@5.20.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ=="],
|
|
107
|
+
|
|
108
|
+
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
|
109
|
+
|
|
110
|
+
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
|
111
|
+
|
|
112
|
+
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
|
113
|
+
|
|
114
|
+
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
|
|
115
|
+
|
|
116
|
+
"lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="],
|
|
117
|
+
|
|
118
|
+
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="],
|
|
119
|
+
|
|
120
|
+
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="],
|
|
121
|
+
|
|
122
|
+
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="],
|
|
123
|
+
|
|
124
|
+
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="],
|
|
125
|
+
|
|
126
|
+
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="],
|
|
127
|
+
|
|
128
|
+
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="],
|
|
129
|
+
|
|
130
|
+
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="],
|
|
131
|
+
|
|
132
|
+
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="],
|
|
133
|
+
|
|
134
|
+
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="],
|
|
135
|
+
|
|
136
|
+
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="],
|
|
137
|
+
|
|
138
|
+
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="],
|
|
139
|
+
|
|
140
|
+
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
|
141
|
+
|
|
142
|
+
"marked": ["marked@17.0.4", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ=="],
|
|
143
|
+
|
|
144
|
+
"mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
|
|
145
|
+
|
|
146
|
+
"node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],
|
|
147
|
+
|
|
148
|
+
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
|
149
|
+
|
|
150
|
+
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
|
151
|
+
|
|
152
|
+
"preact": ["preact@10.29.0", "", {}, "sha512-wSAGyk2bYR1c7t3SZ3jHcM6xy0lcBcDel6lODcs9ME6Th++Dx2KU+6D3HD8wMMKGA8Wpw7OMd3/4RGzYRpzwRg=="],
|
|
153
|
+
|
|
154
|
+
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
|
155
|
+
|
|
156
|
+
"tailwindcss": ["tailwindcss@4.2.1", "", {}, "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw=="],
|
|
157
|
+
|
|
158
|
+
"tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
|
|
159
|
+
|
|
160
|
+
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
|
161
|
+
|
|
162
|
+
"undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
|
|
163
|
+
|
|
164
|
+
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w=="],
|
|
165
|
+
|
|
166
|
+
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw=="],
|
|
167
|
+
|
|
168
|
+
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg=="],
|
|
169
|
+
|
|
170
|
+
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
|
|
171
|
+
|
|
172
|
+
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
|
|
173
|
+
|
|
174
|
+
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
|
175
|
+
}
|
|
176
|
+
}
|
package/daemon/build.ts
CHANGED
|
@@ -12,6 +12,26 @@ async function build() {
|
|
|
12
12
|
|
|
13
13
|
const REACT_EXTERNALS = ["react", "react-dom", "react-dom/client", "react/jsx-runtime", "react/jsx-dev-runtime"];
|
|
14
14
|
|
|
15
|
+
// 0. Build preact-compat bundle
|
|
16
|
+
console.log(" Building preact-compat...");
|
|
17
|
+
const preactResult = await Bun.build({
|
|
18
|
+
entrypoints: [join(ROOT, "client/compat/preact-all.ts")],
|
|
19
|
+
outdir: DIST,
|
|
20
|
+
format: "esm",
|
|
21
|
+
naming: "preact-compat.js",
|
|
22
|
+
minify: true,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (!preactResult.success) {
|
|
26
|
+
console.error("Preact-compat build failed:", preactResult.logs);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Write jsx-runtime shim
|
|
31
|
+
writeFileSync(join(DIST, "jsx-runtime.js"),
|
|
32
|
+
`import { jsx, jsxs, Fragment } from "./preact-compat.js";\nexport { jsx, jsxs, Fragment };\nexport const jsxDEV = jsx;\n`
|
|
33
|
+
);
|
|
34
|
+
|
|
15
35
|
// 1. Build runtime (shared context between app and components)
|
|
16
36
|
console.log(" Building #canvas/runtime...");
|
|
17
37
|
const runtimeResult = await Bun.build({
|
|
@@ -67,11 +87,9 @@ async function build() {
|
|
|
67
87
|
// 5. Read theme.css to inline into HTML for browser Tailwind runtime
|
|
68
88
|
const themeCss = readFileSync(join(ROOT, "client/theme.css"), "utf-8");
|
|
69
89
|
|
|
70
|
-
// 6. Create
|
|
71
|
-
|
|
72
|
-
console.log(" Creating React shims...");
|
|
90
|
+
// 6. Create index.html
|
|
91
|
+
console.log(" Creating index.html...");
|
|
73
92
|
|
|
74
|
-
// Write the index.html to use CDN React
|
|
75
93
|
const indexHtml = `<!DOCTYPE html>
|
|
76
94
|
<html lang="en" data-theme="dark">
|
|
77
95
|
<head>
|
|
@@ -91,21 +109,14 @@ ${themeCss}
|
|
|
91
109
|
<script src="https://unpkg.com/@highlightjs/cdn-assets@11.11.1/highlight.min.js"></script>
|
|
92
110
|
<script src="https://unpkg.com/mermaid@11.4.1/dist/mermaid.min.js"></script>
|
|
93
111
|
<script>mermaid.initialize({ startOnLoad: false, theme: document.documentElement.dataset.theme === 'light' ? 'default' : 'dark' });</script>
|
|
94
|
-
<script src="https://unpkg.com/react@18.3.1/umd/react.production.min.js"></script>
|
|
95
|
-
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js"></script>
|
|
96
|
-
<script>
|
|
97
|
-
// Create ESM modules from UMD globals
|
|
98
|
-
window.__REACT_ESM__ = Object.keys(React).reduce((m, k) => { m[k] = React[k]; return m; }, { default: React, __esModule: true });
|
|
99
|
-
window.__REACT_DOM_ESM__ = Object.keys(ReactDOM).reduce((m, k) => { m[k] = ReactDOM[k]; return m; }, { default: ReactDOM, __esModule: true });
|
|
100
|
-
</script>
|
|
101
112
|
<script type="importmap">
|
|
102
113
|
{
|
|
103
114
|
"imports": {
|
|
104
|
-
"react": "/assets/
|
|
105
|
-
"react-dom": "/assets/
|
|
106
|
-
"react-dom/client": "/assets/
|
|
107
|
-
"react/jsx-runtime": "/assets/jsx-runtime
|
|
108
|
-
"react/jsx-dev-runtime": "/assets/jsx-
|
|
115
|
+
"react": "/assets/preact-compat.js",
|
|
116
|
+
"react-dom": "/assets/preact-compat.js",
|
|
117
|
+
"react-dom/client": "/assets/preact-compat.js",
|
|
118
|
+
"react/jsx-runtime": "/assets/jsx-runtime.js",
|
|
119
|
+
"react/jsx-dev-runtime": "/assets/jsx-runtime.js",
|
|
109
120
|
"#canvas/components": "/assets/components.js",
|
|
110
121
|
"#canvas/runtime": "/assets/runtime.js"
|
|
111
122
|
}
|
|
@@ -117,51 +128,6 @@ ${themeCss}
|
|
|
117
128
|
|
|
118
129
|
writeFileSync(join(DIST, "index.html"), indexHtml);
|
|
119
130
|
|
|
120
|
-
// React ESM shims
|
|
121
|
-
writeFileSync(join(DIST, "react-shim.js"), `
|
|
122
|
-
const R = window.React;
|
|
123
|
-
export default R;
|
|
124
|
-
export const { useState, useEffect, useRef, useCallback, useContext, useMemo, useReducer, createContext, createElement, Fragment, Children, cloneElement, isValidElement, memo, forwardRef, lazy, Suspense, startTransition, useTransition, useDeferredValue, useId, useSyncExternalStore, useInsertionEffect, useImperativeHandle, useLayoutEffect, useDebugValue, Component, PureComponent } = R;
|
|
125
|
-
`);
|
|
126
|
-
|
|
127
|
-
writeFileSync(join(DIST, "react-dom-shim.js"), `
|
|
128
|
-
const RD = window.ReactDOM;
|
|
129
|
-
export default RD;
|
|
130
|
-
export const { createPortal, flushSync, hydrate, render, unmountComponentAtNode, findDOMNode, unstable_batchedUpdates } = RD;
|
|
131
|
-
`);
|
|
132
|
-
|
|
133
|
-
writeFileSync(join(DIST, "react-dom-client-shim.js"), `
|
|
134
|
-
const RD = window.ReactDOM;
|
|
135
|
-
export const { createRoot, hydrateRoot } = RD;
|
|
136
|
-
export default { createRoot: RD.createRoot, hydrateRoot: RD.hydrateRoot };
|
|
137
|
-
`);
|
|
138
|
-
|
|
139
|
-
// jsxDEV signature: (type, props, key, isStaticChildren, source, self)
|
|
140
|
-
// jsx/jsxs signature: (type, props, key)
|
|
141
|
-
// createElement signature: (type, props, ...children)
|
|
142
|
-
// We need to adapt: extract children from props and pass to createElement
|
|
143
|
-
const jsxShimCode = `
|
|
144
|
-
const R = window.React;
|
|
145
|
-
export const Fragment = R.Fragment;
|
|
146
|
-
function _jsx(type, props, key) {
|
|
147
|
-
if (props && 'children' in props) {
|
|
148
|
-
const { children, ...rest } = props;
|
|
149
|
-
if (key !== undefined && key !== null) rest.key = key;
|
|
150
|
-
return Array.isArray(children)
|
|
151
|
-
? R.createElement(type, rest, ...children)
|
|
152
|
-
: R.createElement(type, rest, children);
|
|
153
|
-
}
|
|
154
|
-
if (key !== undefined && key !== null) props = { ...props, key };
|
|
155
|
-
return R.createElement(type, props);
|
|
156
|
-
}
|
|
157
|
-
export const jsx = _jsx;
|
|
158
|
-
export const jsxs = _jsx;
|
|
159
|
-
export function jsxDEV(type, props, key) { return _jsx(type, props, key); }
|
|
160
|
-
`;
|
|
161
|
-
|
|
162
|
-
writeFileSync(join(DIST, "jsx-runtime-shim.js"), jsxShimCode);
|
|
163
|
-
writeFileSync(join(DIST, "jsx-dev-runtime-shim.js"), jsxShimCode);
|
|
164
|
-
|
|
165
131
|
console.log("Build complete! Output in dist/");
|
|
166
132
|
}
|
|
167
133
|
|