agent-canvas 0.1.43 → 0.1.45
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/bin/lib/commands/daemon.ts +3 -6
- package/bin/lib/commands/push.ts +1 -1
- package/bin/lib/daemon-lifecycle.ts +65 -72
- package/bin/lib/helpers.test.ts +1 -0
- package/bin/lib/helpers.ts +30 -74
- package/daemon/build.ts +16 -13
- package/daemon/client/App.tsx +38 -62
- package/daemon/client/CompareView.tsx +4 -4
- package/daemon/client/FileBrowser.tsx +4 -4
- package/daemon/client/FileViewer.tsx +4 -4
- package/daemon/client/OverviewView.tsx +2 -2
- package/daemon/client/RevisionSelect.tsx +1 -1
- package/daemon/client/clientApi.ts +18 -0
- package/daemon/client/components/index.ts +3 -16
- package/daemon/client/styles.css +4 -457
- package/daemon/dist/client.css +1 -1
- package/daemon/dist/client.js +76 -76
- package/daemon/dist/components.js +29 -29
- package/daemon/dist/runtime.js +1 -1
- package/daemon/src/components.ts +13 -0
- package/daemon/src/handlers/api.ts +14 -9
- package/daemon/src/handlers/files.ts +1 -3
- package/daemon/src/handlers/static.ts +1 -1
- package/daemon/src/handlers/uploads.ts +1 -3
- package/daemon/src/paths.ts +10 -24
- package/daemon/src/remote-feedback.test.ts +1 -1
- package/daemon/src/remote-feedback.ts +1 -1
- package/daemon/src/secrets-api.test.ts +1 -2
- package/daemon/src/server.ts +13 -10
- package/daemon/src/share-e2e.test.ts +1 -1
- package/daemon/src/share.test.ts +1 -1
- package/daemon/src/share.ts +1 -1
- package/daemon/tsconfig.json +1 -3
- package/package.json +10 -2
- package/.github/dark.png +0 -0
- package/.github/light.png +0 -0
- package/.github/workflows/ci.yml +0 -48
- package/.github/workflows/deploy-worker-prod.yml +0 -19
- package/.github/workflows/deploy-worker-stage.yml +0 -21
- package/.github/workflows/deploy-worker.yml +0 -72
- package/.github/workflows/release.yml +0 -36
- package/CLAUDE.md +0 -86
- package/bun.lock +0 -377
- package/daemon/client/AnnotationEditor.tsx +0 -315
- package/daemon/client/AnnotationProvider.tsx +0 -191
- package/daemon/client/AnnotationSidebar.tsx +0 -627
- package/daemon/client/FileIcon.tsx +0 -76
- package/daemon/client/PlanRenderer.tsx +0 -614
- package/daemon/client/Popover.tsx +0 -350
- package/daemon/client/RenderErrorContext.ts +0 -11
- package/daemon/client/ResponsePreview.tsx +0 -186
- package/daemon/client/SessionContext.tsx +0 -3
- package/daemon/client/annotationContext.ts +0 -114
- package/daemon/client/annotationDom.ts +0 -104
- package/daemon/client/annotationDraft.test.ts +0 -149
- package/daemon/client/annotationDraft.ts +0 -110
- package/daemon/client/compat/preact-all.ts +0 -4
- package/daemon/client/components/Callout.tsx +0 -26
- package/daemon/client/components/Checklist.tsx +0 -37
- package/daemon/client/components/Choice.tsx +0 -176
- package/daemon/client/components/CodeBlock.tsx +0 -35
- package/daemon/client/components/Diff.tsx +0 -65
- package/daemon/client/components/FilePreview.tsx +0 -88
- package/daemon/client/components/Image.tsx +0 -45
- package/daemon/client/components/Markdown.tsx +0 -44
- package/daemon/client/components/Mermaid.tsx +0 -565
- package/daemon/client/components/Note.tsx +0 -14
- package/daemon/client/components/Priority.tsx +0 -19
- package/daemon/client/components/ResponseNote.tsx +0 -19
- package/daemon/client/components/Section.tsx +0 -33
- package/daemon/client/components/Table.tsx +0 -35
- package/daemon/client/components/Task.tsx +0 -76
- package/daemon/client/components/UserInput.tsx +0 -174
- package/daemon/client/components/renderMarkdownChildren.tsx +0 -97
- package/daemon/client/generateMarkdown.ts +0 -273
- package/daemon/client/highlightRange.ts +0 -224
- package/daemon/client/popoverPosition.ts +0 -31
- package/daemon/client/runtime.ts +0 -123
- package/daemon/client/theme.css +0 -66
- package/daemon/client/useTextAnnotation.tsx +0 -188
- package/daemon/client/utils.ts +0 -13
- package/daemon/src/compiler.test.ts +0 -57
- package/daemon/src/compiler.ts +0 -360
- package/daemon/src/handlers/utils.ts +0 -14
- package/daemon/src/router.ts +0 -16
- package/daemon/src/session-secrets.test.ts +0 -83
- package/daemon/src/session.ts +0 -612
- package/daemon/src/watcher.ts +0 -71
- package/daemon/src/websocket.test.ts +0 -99
- package/daemon/src/websocket.ts +0 -211
- package/tsconfig.json +0 -14
- package/workers/canvas-share/README.md +0 -159
- package/workers/canvas-share/oblaka.ts +0 -56
- package/workers/canvas-share/package.json +0 -25
- package/workers/canvas-share/public/assets/.gitkeep +0 -0
- package/workers/canvas-share/public/assets/client.css +0 -2
- package/workers/canvas-share/public/assets/client.js +0 -91
- package/workers/canvas-share/public/assets/components.js +0 -65
- package/workers/canvas-share/public/assets/jsx-runtime.js +0 -3
- package/workers/canvas-share/public/assets/preact-compat.js +0 -1
- package/workers/canvas-share/public/assets/runtime.js +0 -1
- package/workers/canvas-share/public/index.html +0 -385
- package/workers/canvas-share/public/screenshot-dark.png +0 -0
- package/workers/canvas-share/public/screenshot-light.png +0 -0
- package/workers/canvas-share/src/index.test.ts +0 -209
- package/workers/canvas-share/src/index.ts +0 -518
- package/workers/canvas-share/src/types.ts +0 -119
- package/workers/canvas-share/src/util.ts +0 -156
- package/workers/canvas-share/src/validation.ts +0 -160
- package/workers/canvas-share/tsconfig.json +0 -16
package/daemon/dist/runtime.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createContext as
|
|
1
|
+
import{createContext as z,useContext as B,useEffect as D}from"react";import{createContext as J}from"react";var K=J("");var L=z(null);function G(){return B(L)}function S(h){let{registerResponse:j}=G();D(()=>{j(h)},[h,j])}function T(h,j,q){let{setFeedbackEntry:H,removeFeedbackEntry:I}=G();D(()=>{return H(h,{id:h,markdown:j,label:q?.label,required:q?.required}),()=>I(h)},[h,j,q?.label,q?.required])}var M=z("");function U(){return B(M)}var W=z({setActiveView:()=>{}});export{S as useResponseRegistration,T as useFeedback,U as useCanvasFile,G as useAnnotations,K as SessionContext,M as CanvasFileCtx,L as AnnotationCtx,W as ActiveViewCtx};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Components agent-canvas adds on top of the kernel's set.
|
|
3
|
+
*
|
|
4
|
+
* Keep in sync with `daemon/client/components/index.ts` — the compiler injects
|
|
5
|
+
* these names into authored JSX, and the browser resolves them from that barrel
|
|
6
|
+
* through `#canvas/components`. A name here with no matching export renders as
|
|
7
|
+
* undefined.
|
|
8
|
+
*/
|
|
9
|
+
import type { CanvasComponents } from "@fabrika/canvas-kernel/server";
|
|
10
|
+
|
|
11
|
+
export const HOST_COMPONENTS: CanvasComponents = {
|
|
12
|
+
SecretInput: { requiredProps: { id: "string", label: "string", env: "string" } },
|
|
13
|
+
};
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { readFileSync, readdirSync, existsSync } from "fs";
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import {
|
|
3
|
+
compileJsx,
|
|
4
|
+
jsonResponse,
|
|
5
|
+
watchSession,
|
|
6
|
+
type Route,
|
|
7
|
+
type SessionManager,
|
|
8
|
+
} from "@fabrika/canvas-kernel/server";
|
|
6
9
|
import { loadShareConfig, shareRevision, revokeShare } from "../share";
|
|
7
|
-
import
|
|
10
|
+
import { COMPILE_TEMP_DIR } from "../paths";
|
|
11
|
+
import { HOST_COMPONENTS } from "../components";
|
|
8
12
|
|
|
9
13
|
const SECRET_FIELD_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
10
14
|
const MAX_SECRET_BYTES = 64 * 1024;
|
|
@@ -83,7 +87,7 @@ export function createApiHandlers(ctx: ApiContext): Route[] {
|
|
|
83
87
|
const errors: Record<string, string> = {};
|
|
84
88
|
await Promise.all(
|
|
85
89
|
[...canvasFiles.entries()].map(async ([filename, jsx]) => {
|
|
86
|
-
const result = await
|
|
90
|
+
const result = await compileJsx(jsx, { projectRoot, tempDir: COMPILE_TEMP_DIR, components: HOST_COMPONENTS });
|
|
87
91
|
if (result.ok) {
|
|
88
92
|
compiled.set(filename, result.js);
|
|
89
93
|
} else {
|
|
@@ -106,7 +110,7 @@ export function createApiHandlers(ctx: ApiContext): Route[] {
|
|
|
106
110
|
}
|
|
107
111
|
|
|
108
112
|
broadcastPlanUpdate(sessionId);
|
|
109
|
-
watchSession(sessionId, sessionManager, broadcastPlanUpdate);
|
|
113
|
+
watchSession(sessionId, sessionManager, broadcastPlanUpdate, { tempDir: COMPILE_TEMP_DIR, components: HOST_COMPONENTS });
|
|
110
114
|
|
|
111
115
|
const browserUrl = `http://localhost:${port}/s/${sessionId}`;
|
|
112
116
|
return jsonResponse({
|
|
@@ -136,7 +140,7 @@ export function createApiHandlers(ctx: ApiContext): Route[] {
|
|
|
136
140
|
if (session) {
|
|
137
141
|
const jsx = sessionManager.readRevisionJsx(sessionId, rev, jsxFilename);
|
|
138
142
|
if (jsx) {
|
|
139
|
-
const result = await
|
|
143
|
+
const result = await compileJsx(jsx, { projectRoot: session.projectRoot, tempDir: COMPILE_TEMP_DIR, components: HOST_COMPONENTS });
|
|
140
144
|
if (result.ok) {
|
|
141
145
|
sessionManager.saveCompiled(sessionId, jsxFilename, result.js, rev);
|
|
142
146
|
compiled = result.js;
|
|
@@ -160,7 +164,8 @@ export function createApiHandlers(ctx: ApiContext): Route[] {
|
|
|
160
164
|
|
|
161
165
|
function handleHealth(): Response {
|
|
162
166
|
const sessions = sessionManager.list().map((s) => s.id);
|
|
163
|
-
|
|
167
|
+
// The pid is what the CLI signals to stop us — a pid file it cannot corroborate is not.
|
|
168
|
+
return jsonResponse({ ok: true, sessions, version: ctx.version, pid: process.pid });
|
|
164
169
|
}
|
|
165
170
|
|
|
166
171
|
function handleMeta(_req: Request, _url: URL, match: URLPatternResult): Response {
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { join, resolve } from "path";
|
|
2
2
|
import { readdir } from "fs/promises";
|
|
3
|
-
import type
|
|
3
|
+
import { jsonResponse, type Route, type SessionManager } from "@fabrika/canvas-kernel/server";
|
|
4
4
|
import { LANG_MAP } from "../../langMap";
|
|
5
|
-
import { jsonResponse } from "./utils";
|
|
6
|
-
import type { Route } from "../router";
|
|
7
5
|
|
|
8
6
|
const IMAGE_MIME: Record<string, string> = {
|
|
9
7
|
png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg",
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { writeFileSync } from "fs";
|
|
2
2
|
import { join } from "path";
|
|
3
|
+
import { jsonResponse, type Route, type SessionManager } from "@fabrika/canvas-kernel/server";
|
|
3
4
|
import { UPLOADS_DIR } from "../paths";
|
|
4
|
-
import type { SessionManager } from "../session";
|
|
5
|
-
import { jsonResponse } from "./utils";
|
|
6
|
-
import type { Route } from "../router";
|
|
7
5
|
|
|
8
6
|
const IMAGE_MIME: Record<string, string> = {
|
|
9
7
|
png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg",
|
package/daemon/src/paths.ts
CHANGED
|
@@ -1,29 +1,15 @@
|
|
|
1
1
|
import { join } from "path";
|
|
2
|
-
import {
|
|
3
|
-
import { mkdirSync } from "fs";
|
|
2
|
+
import { createCanvasPaths } from "@fabrika/canvas-kernel/server";
|
|
4
3
|
|
|
5
|
-
/**
|
|
6
|
-
export const
|
|
4
|
+
/** agent-canvas's on-disk layout. Kept in sync with bin/lib/config.ts. */
|
|
5
|
+
export const paths = createCanvasPaths({ appName: "agent-canvas" });
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
export const SESSIONS_DIR =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export const
|
|
13
|
-
|
|
14
|
-
/** PID file for daemon process */
|
|
15
|
-
export const PID_FILE = join(TEMP_DIR, "daemon.pid");
|
|
7
|
+
export const DATA_DIR = paths.dataDir;
|
|
8
|
+
export const SESSIONS_DIR = paths.sessionsDir;
|
|
9
|
+
export const TEMP_DIR = paths.tempDir;
|
|
10
|
+
export const PID_FILE = paths.pidFile;
|
|
11
|
+
export const COMPILE_TEMP_DIR = paths.compileTempDir;
|
|
12
|
+
export const UPLOADS_DIR = paths.uploadsDir;
|
|
16
13
|
|
|
17
14
|
/** Capability used only by the CLI to resolve secret values */
|
|
18
|
-
export const CLI_AUTH_FILE = join(
|
|
19
|
-
|
|
20
|
-
/** Temp dir for JSX compilation */
|
|
21
|
-
export const COMPILE_TEMP_DIR = join(TEMP_DIR, "compile");
|
|
22
|
-
|
|
23
|
-
/** Uploaded annotation images */
|
|
24
|
-
export const UPLOADS_DIR = join(TEMP_DIR, "uploads");
|
|
25
|
-
|
|
26
|
-
// Ensure dirs exist
|
|
27
|
-
mkdirSync(SESSIONS_DIR, { recursive: true });
|
|
28
|
-
mkdirSync(COMPILE_TEMP_DIR, { recursive: true });
|
|
29
|
-
mkdirSync(UPLOADS_DIR, { recursive: true });
|
|
15
|
+
export const CLI_AUTH_FILE = join(paths.tempDir, "daemon-auth-token");
|
|
@@ -8,7 +8,7 @@ import { describe, expect, test, afterEach, beforeEach } from "bun:test";
|
|
|
8
8
|
import { mkdtempSync, rmSync } from "fs";
|
|
9
9
|
import { join } from "path";
|
|
10
10
|
import { tmpdir } from "os";
|
|
11
|
-
import { SessionManager } from "
|
|
11
|
+
import { SessionManager } from "@fabrika/canvas-kernel/server";
|
|
12
12
|
import { startRemoteFeedbackPoller } from "./remote-feedback";
|
|
13
13
|
|
|
14
14
|
let testDir: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SessionManager, RemoteFeedbackEntry, RemoteAnnotation } from "
|
|
1
|
+
import type { SessionManager, RemoteFeedbackEntry, RemoteAnnotation } from "@fabrika/canvas-kernel/server";
|
|
2
2
|
import { loadShareConfig } from "./share";
|
|
3
3
|
import { importShareKey, decryptString } from "../client/shareCrypto";
|
|
4
4
|
|
|
@@ -3,8 +3,7 @@ import { mkdtempSync, rmSync } from "fs";
|
|
|
3
3
|
import { tmpdir } from "os";
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
import { createApiHandlers } from "./handlers/api";
|
|
6
|
-
import { dispatch, type Route } from "
|
|
7
|
-
import { SessionManager } from "./session";
|
|
6
|
+
import { dispatch, SessionManager, type Route } from "@fabrika/canvas-kernel/server";
|
|
8
7
|
|
|
9
8
|
const testDirectories: string[] = [];
|
|
10
9
|
|
package/daemon/src/server.ts
CHANGED
|
@@ -2,30 +2,33 @@ import { writeFileSync, mkdirSync, readFileSync, chmodSync } from "fs";
|
|
|
2
2
|
import { join, dirname } from "path";
|
|
3
3
|
import { tmpdir } from "os";
|
|
4
4
|
import { randomBytes } from "crypto";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
import {
|
|
6
|
+
corsHeaders,
|
|
7
|
+
createWebSocketManager,
|
|
8
|
+
dispatch,
|
|
9
|
+
jsonResponse,
|
|
10
|
+
SessionManager,
|
|
11
|
+
type WSData,
|
|
12
|
+
} from "@fabrika/canvas-kernel/server";
|
|
9
13
|
import { createApiHandlers } from "./handlers/api";
|
|
10
14
|
import { createFileHandlers } from "./handlers/files";
|
|
11
15
|
import { createStaticHandlers } from "./handlers/static";
|
|
12
16
|
import { createUploadHandlers } from "./handlers/uploads";
|
|
13
17
|
import { startRemoteFeedbackPoller } from "./remote-feedback";
|
|
14
|
-
import { CLI_AUTH_FILE } from "./paths";
|
|
18
|
+
import { CLI_AUTH_FILE, PID_FILE, SESSIONS_DIR, TEMP_DIR } from "./paths";
|
|
15
19
|
|
|
16
20
|
const PORT = parseInt(process.env.CANVAS_PORT || "19400", 10);
|
|
17
21
|
const VERSION = JSON.parse(readFileSync(join(dirname(import.meta.dir), "..", "package.json"), "utf-8")).version as string;
|
|
18
22
|
|
|
19
23
|
// Write PID file so CLI can find and stop us
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
writeFileSync(join(pidDir, "daemon.pid"), String(process.pid));
|
|
24
|
+
mkdirSync(TEMP_DIR, { recursive: true, mode: 0o700 });
|
|
25
|
+
chmodSync(TEMP_DIR, 0o700);
|
|
26
|
+
writeFileSync(PID_FILE, String(process.pid));
|
|
24
27
|
const cliAuthToken = randomBytes(32).toString("base64url");
|
|
25
28
|
writeFileSync(CLI_AUTH_FILE, cliAuthToken, { mode: 0o600 });
|
|
26
29
|
chmodSync(CLI_AUTH_FILE, 0o600);
|
|
27
30
|
|
|
28
|
-
const sessionManager = new SessionManager();
|
|
31
|
+
const sessionManager = new SessionManager(SESSIONS_DIR);
|
|
29
32
|
const wsManager = createWebSocketManager(sessionManager);
|
|
30
33
|
|
|
31
34
|
const routes = [
|
|
@@ -16,7 +16,7 @@ import { tmpdir } from "os";
|
|
|
16
16
|
|
|
17
17
|
import workerHandler from "../../workers/canvas-share/src/index";
|
|
18
18
|
import type { Env } from "../../workers/canvas-share/src/types";
|
|
19
|
-
import { SessionManager } from "
|
|
19
|
+
import { SessionManager } from "@fabrika/canvas-kernel/server";
|
|
20
20
|
import { buildSharePayload, encryptSharePayload } from "./share";
|
|
21
21
|
import {
|
|
22
22
|
generateShareKey,
|
package/daemon/src/share.test.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { describe, expect, test, beforeEach, afterEach } from "bun:test";
|
|
|
8
8
|
import { mkdtempSync, rmSync, mkdirSync, writeFileSync } from "fs";
|
|
9
9
|
import { join } from "path";
|
|
10
10
|
import { tmpdir } from "os";
|
|
11
|
-
import { SessionManager } from "
|
|
11
|
+
import { SessionManager } from "@fabrika/canvas-kernel/server";
|
|
12
12
|
import { buildSharePayload, pushShareToWorker, shareRevision, loadShareConfig, encryptSharePayload } from "./share";
|
|
13
13
|
import { generateShareKey, importShareKey, decryptString } from "../client/shareCrypto";
|
|
14
14
|
|
package/daemon/src/share.ts
CHANGED
package/daemon/tsconfig.json
CHANGED
|
@@ -8,16 +8,14 @@
|
|
|
8
8
|
"esModuleInterop": true,
|
|
9
9
|
"skipLibCheck": true,
|
|
10
10
|
"noEmit": true,
|
|
11
|
-
"rootDir": ".",
|
|
12
11
|
"types": ["@types/bun"],
|
|
13
12
|
"paths": {
|
|
14
|
-
"#canvas/runtime": ["
|
|
13
|
+
"#canvas/runtime": ["../packages/canvas-kernel/src/client/runtime.ts"],
|
|
15
14
|
"#canvas/components": ["./client/components/index.ts"]
|
|
16
15
|
}
|
|
17
16
|
},
|
|
18
17
|
"include": ["src/**/*", "client/**/*"],
|
|
19
18
|
"exclude": [
|
|
20
|
-
"client/compat/**/*",
|
|
21
19
|
"src/share-e2e.test.ts"
|
|
22
20
|
]
|
|
23
21
|
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-canvas",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.45",
|
|
4
4
|
"description": "Interactive visual canvas for Claude Code — rich annotatable documents in the browser",
|
|
5
5
|
"bin": {
|
|
6
6
|
"agent-canvas": "bin/agent-canvas.js"
|
|
7
7
|
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin",
|
|
10
|
+
"daemon",
|
|
11
|
+
"skills"
|
|
12
|
+
],
|
|
8
13
|
"scripts": {
|
|
9
14
|
"build": "bun daemon/build.ts",
|
|
10
|
-
"
|
|
15
|
+
"check:versions": "bun scripts/check-release-versions.ts",
|
|
16
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p packages/canvas-kernel/tsconfig.json && tsc --noEmit -p daemon/tsconfig.json",
|
|
11
17
|
"test": "bun test",
|
|
12
18
|
"prepublishOnly": "bun daemon/build.ts"
|
|
13
19
|
},
|
|
14
20
|
"dependencies": {
|
|
21
|
+
"@fabrika/canvas-kernel": "0.1.45",
|
|
15
22
|
"marked": "^17.0.4",
|
|
16
23
|
"mermaid-parser-bundle": "^0.1.2",
|
|
17
24
|
"preact": "^10.25.0",
|
|
@@ -30,6 +37,7 @@
|
|
|
30
37
|
"url": "https://github.com/contember/agent-canvas"
|
|
31
38
|
},
|
|
32
39
|
"workspaces": [
|
|
40
|
+
"packages/*",
|
|
33
41
|
"workers/*"
|
|
34
42
|
],
|
|
35
43
|
"license": "MIT",
|
package/.github/dark.png
DELETED
|
Binary file
|
package/.github/light.png
DELETED
|
Binary file
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
pull_request:
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
typecheck:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
steps:
|
|
12
|
-
- uses: actions/checkout@v4
|
|
13
|
-
|
|
14
|
-
- uses: oven-sh/setup-bun@v2
|
|
15
|
-
|
|
16
|
-
- name: Install dependencies
|
|
17
|
-
run: bun install --frozen-lockfile
|
|
18
|
-
|
|
19
|
-
- name: Typecheck
|
|
20
|
-
run: bun run typecheck
|
|
21
|
-
|
|
22
|
-
- name: Test
|
|
23
|
-
run: bun test
|
|
24
|
-
|
|
25
|
-
- name: Build
|
|
26
|
-
run: bun run build
|
|
27
|
-
|
|
28
|
-
worker:
|
|
29
|
-
runs-on: ubuntu-latest
|
|
30
|
-
steps:
|
|
31
|
-
- uses: actions/checkout@v4
|
|
32
|
-
|
|
33
|
-
- uses: oven-sh/setup-bun@v2
|
|
34
|
-
|
|
35
|
-
- name: Install dependencies
|
|
36
|
-
run: bun install --frozen-lockfile
|
|
37
|
-
|
|
38
|
-
- name: Typecheck
|
|
39
|
-
working-directory: workers/canvas-share
|
|
40
|
-
run: bun run typecheck
|
|
41
|
-
|
|
42
|
-
- name: Test
|
|
43
|
-
working-directory: workers/canvas-share
|
|
44
|
-
run: bun test
|
|
45
|
-
|
|
46
|
-
- name: Generate wrangler config (local env)
|
|
47
|
-
working-directory: workers/canvas-share
|
|
48
|
-
run: bun run oblaka
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
name: Deploy worker to prod
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
# Triggered by version tags so the worker deploys alongside the npm
|
|
5
|
-
# release. This keeps the runtime bundles served by the worker in
|
|
6
|
-
# lockstep with the @agent-canvas package version users install.
|
|
7
|
-
push:
|
|
8
|
-
tags:
|
|
9
|
-
- "v*"
|
|
10
|
-
workflow_dispatch:
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
deploy:
|
|
14
|
-
uses: ./.github/workflows/deploy-worker.yml
|
|
15
|
-
with:
|
|
16
|
-
env: prod
|
|
17
|
-
# inherit so the reusable workflow can resolve secrets; the env-scoped
|
|
18
|
-
# values (set on the `prod` environment) win over repo-level ones.
|
|
19
|
-
secrets: inherit
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
name: Deploy worker to stage
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
paths:
|
|
7
|
-
- "workers/canvas-share/**"
|
|
8
|
-
- "daemon/client/**"
|
|
9
|
-
- "daemon/build.ts"
|
|
10
|
-
- ".github/workflows/deploy-worker.yml"
|
|
11
|
-
- ".github/workflows/deploy-worker-stage.yml"
|
|
12
|
-
workflow_dispatch:
|
|
13
|
-
|
|
14
|
-
jobs:
|
|
15
|
-
deploy:
|
|
16
|
-
uses: ./.github/workflows/deploy-worker.yml
|
|
17
|
-
with:
|
|
18
|
-
env: stage
|
|
19
|
-
# inherit so the reusable workflow can resolve secrets; the env-scoped
|
|
20
|
-
# values (set on the `stage` environment) win over repo-level ones.
|
|
21
|
-
secrets: inherit
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
name: Reusable Worker Deploy
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
workflow_call:
|
|
5
|
-
inputs:
|
|
6
|
-
env:
|
|
7
|
-
description: "Target environment (stage or prod)"
|
|
8
|
-
required: true
|
|
9
|
-
type: string
|
|
10
|
-
# No `secrets:` inputs on purpose. The deploy job below declares
|
|
11
|
-
# `environment: ${{ inputs.env }}`, so referencing `secrets.X` directly
|
|
12
|
-
# resolves the matching *environment* secret (falling back to a
|
|
13
|
-
# repo-level secret of the same name). Callers pass `secrets: inherit`
|
|
14
|
-
# so org/repo secrets remain reachable too. This is what makes the
|
|
15
|
-
# CLOUDFLARE_* / SHARE_AUTH_TOKEN values environment-scoped — a prod
|
|
16
|
-
# token can never be read by a stage deploy and vice versa.
|
|
17
|
-
|
|
18
|
-
jobs:
|
|
19
|
-
deploy:
|
|
20
|
-
runs-on: ubuntu-latest
|
|
21
|
-
environment: ${{ inputs.env }}
|
|
22
|
-
steps:
|
|
23
|
-
- uses: actions/checkout@v4
|
|
24
|
-
|
|
25
|
-
- uses: oven-sh/setup-bun@v2
|
|
26
|
-
|
|
27
|
-
- name: Install dependencies
|
|
28
|
-
run: bun install --frozen-lockfile
|
|
29
|
-
|
|
30
|
-
# Build the daemon bundles first. The root build script auto-mirrors
|
|
31
|
-
# them into workers/canvas-share/public/assets/ so the worker's
|
|
32
|
-
# `[assets]` binding always ships the exact runtime that was pushed
|
|
33
|
-
# to npm for this version — no risk of drift between the client code
|
|
34
|
-
# inside a share payload and the runtime bundles served by the worker.
|
|
35
|
-
- name: Build runtime bundles
|
|
36
|
-
run: bun run build
|
|
37
|
-
|
|
38
|
-
# Ask oblaka to create/update the Cloudflare resources (R2 bucket,
|
|
39
|
-
# KV namespace) for this environment and emit a fresh wrangler.jsonc
|
|
40
|
-
# pointed at them. `--remote` is what triggers the actual CF API
|
|
41
|
-
# calls; without it oblaka just regenerates the config file locally.
|
|
42
|
-
- name: Provision Cloudflare resources
|
|
43
|
-
working-directory: workers/canvas-share
|
|
44
|
-
env:
|
|
45
|
-
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
46
|
-
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
47
|
-
run: bunx oblaka oblaka.ts --env ${{ inputs.env }} --remote --state-namespace agent-state-kv
|
|
48
|
-
|
|
49
|
-
# Push the bearer token as a Worker secret if it was provided. Using
|
|
50
|
-
# `secret bulk` lets us set multiple secrets in one API call and
|
|
51
|
-
# keeps the value out of the generated wrangler.jsonc. Skipped
|
|
52
|
-
# silently when no token is configured (dev envs).
|
|
53
|
-
- name: Set worker secrets
|
|
54
|
-
working-directory: workers/canvas-share
|
|
55
|
-
env:
|
|
56
|
-
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
57
|
-
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
58
|
-
SHARE_AUTH_TOKEN: ${{ secrets.SHARE_AUTH_TOKEN }}
|
|
59
|
-
run: |
|
|
60
|
-
if [ -z "$SHARE_AUTH_TOKEN" ]; then
|
|
61
|
-
echo "SHARE_AUTH_TOKEN not set — worker will run in open-share mode"
|
|
62
|
-
exit 0
|
|
63
|
-
fi
|
|
64
|
-
printf '{"SHARE_AUTH_TOKEN":"%s"}\n' "$SHARE_AUTH_TOKEN" \
|
|
65
|
-
| bunx wrangler secret bulk
|
|
66
|
-
|
|
67
|
-
- name: Deploy worker
|
|
68
|
-
working-directory: workers/canvas-share
|
|
69
|
-
env:
|
|
70
|
-
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
71
|
-
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
72
|
-
run: bunx wrangler deploy
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
name: Release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- "v*"
|
|
7
|
-
|
|
8
|
-
permissions: {}
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
publish:
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
permissions:
|
|
14
|
-
contents: read
|
|
15
|
-
id-token: write
|
|
16
|
-
steps:
|
|
17
|
-
- uses: actions/checkout@v4
|
|
18
|
-
|
|
19
|
-
- uses: oven-sh/setup-bun@v2
|
|
20
|
-
|
|
21
|
-
- uses: actions/setup-node@v4
|
|
22
|
-
with:
|
|
23
|
-
node-version: "24.x"
|
|
24
|
-
registry-url: "https://registry.npmjs.org"
|
|
25
|
-
|
|
26
|
-
- name: Install dependencies
|
|
27
|
-
run: bun install --frozen-lockfile
|
|
28
|
-
|
|
29
|
-
- name: Typecheck
|
|
30
|
-
run: bun run typecheck
|
|
31
|
-
|
|
32
|
-
- name: Build
|
|
33
|
-
run: bun run build
|
|
34
|
-
|
|
35
|
-
- name: Publish to npm
|
|
36
|
-
run: npm publish --provenance --access public
|
package/CLAUDE.md
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# CLAUDE.md
|
|
2
|
-
|
|
3
|
-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
-
|
|
5
|
-
## Project
|
|
6
|
-
|
|
7
|
-
Agent Canvas — an interactive browser-based visual canvas for Claude Code. Users author JSX documents that get compiled and rendered in the browser with annotation, feedback, and file browsing capabilities.
|
|
8
|
-
|
|
9
|
-
## Architecture
|
|
10
|
-
|
|
11
|
-
Three components communicate via HTTP and WebSocket:
|
|
12
|
-
|
|
13
|
-
- **CLI** (`bin/agent-canvas.ts`) — pushes JSX canvases to the daemon, waits for user feedback, manages daemon lifecycle
|
|
14
|
-
- **Daemon** (`daemon/src/server.ts`) — Bun HTTP+WS server on port 19400 (`CANVAS_PORT`). Compiles JSX, manages sessions, serves the browser UI
|
|
15
|
-
- **Browser UI** (`daemon/client/`) — React 18 app loaded via CDN UMD with ESM import maps. Handles annotations, revision history, feedback collection, file browsing
|
|
16
|
-
|
|
17
|
-
**Data flow:** CLI pushes JSX → daemon compiles via `Bun.build()` → browser loads compiled JS module → user annotates/responds → feedback sent back to CLI via WebSocket
|
|
18
|
-
|
|
19
|
-
**Session model:** Each canvas push creates/updates a session identified by `CANVAS_SESSION_ID` (set by hook). Sessions are stored on disk at `~/.claude/agent-canvas/sessions/{id}/` with a revision system (`revisions/{rev}/plan.jsx`, `plan.compiled.js`, `feedback.md`).
|
|
20
|
-
|
|
21
|
-
## Build
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
bun install
|
|
25
|
-
bun run build # builds client assets to daemon/dist/
|
|
26
|
-
bun daemon/build.ts --watch # watch mode with debounced rebuild
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
The build produces three bundles (runtime.js, components.js, client.js) plus Tailwind CSS. React is loaded from CDN, not bundled. Import maps route `#canvas/components` and `#canvas/runtime` to the local bundles.
|
|
30
|
-
|
|
31
|
-
## Typecheck
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
bun run typecheck # runs tsc --noEmit on both root (bin/) and daemon (client/ + src/)
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Two separate tsconfig files: `tsconfig.json` (root, covers `bin/`) and `daemon/tsconfig.json` (covers `daemon/src/` and `daemon/client/`). CI runs typecheck on every push and PR.
|
|
38
|
-
|
|
39
|
-
## Key Technical Details
|
|
40
|
-
|
|
41
|
-
- **Runtime is Bun only** — no Node.js compatibility needed
|
|
42
|
-
- **JSX compilation** uses temp files because `Bun.build()` doesn't support `stdin`. See `daemon/src/compiler.ts`
|
|
43
|
-
- **Component imports are injected** by the compiler — authored JSX can use `Section`, `Task`, `CodeBlock`, etc. without imports
|
|
44
|
-
- **Adding a new component:** create in `daemon/client/components/`, export from `index.ts`, add to `COMPONENT_IMPORTS` in `daemon/src/compiler.ts`, rebuild
|
|
45
|
-
- **Bun's `spawn` throws synchronously** on missing executables — always check with `which` before spawning
|
|
46
|
-
|
|
47
|
-
## Testing with Demo
|
|
48
|
-
|
|
49
|
-
A demo JSX file lives at `example/plan.jsx` in the project root. To test UI changes:
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
# 1. Start daemon (if not running)
|
|
53
|
-
bun bin/agent-canvas.ts daemon start
|
|
54
|
-
|
|
55
|
-
# 2. Build client assets (use --watch for live reload)
|
|
56
|
-
bun daemon/build.ts --watch
|
|
57
|
-
|
|
58
|
-
# 3. Push the demo plan
|
|
59
|
-
CANVAS_SESSION_ID=planner-demo bun bin/agent-canvas.ts push example/plan.jsx --label "Demo"
|
|
60
|
-
|
|
61
|
-
# 4. Open in browser
|
|
62
|
-
# http://localhost:19400/s/planner-demo
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
The CLI blocks waiting for feedback after push — press Ctrl+C to exit without submitting. Each push creates a new revision visible in the browser's revision selector.
|
|
66
|
-
|
|
67
|
-
## Publishing
|
|
68
|
-
|
|
69
|
-
To release a new version:
|
|
70
|
-
|
|
71
|
-
1. Bump the version in `package.json`
|
|
72
|
-
2. Commit the change and create a git tag: `git tag v<version>`
|
|
73
|
-
3. Push both the commit and the tag: `git push && git push origin v<version>`
|
|
74
|
-
|
|
75
|
-
The CI pipeline handles `npm publish` automatically when a new version tag is pushed. Do not run `npm publish` manually.
|
|
76
|
-
|
|
77
|
-
## Bundled Skill
|
|
78
|
-
|
|
79
|
-
This package distributes a Claude Code skill in `skills/canvas/`. It teaches Claude Code how to use Agent Canvas — writing JSX canvases, pushing, waiting for feedback, iterating, and responding to user feedback. The skill is automatically available to users who install this package.
|
|
80
|
-
|
|
81
|
-
## Environment Variables
|
|
82
|
-
|
|
83
|
-
- `CANVAS_SESSION_ID` — current session (set by SessionStart hook)
|
|
84
|
-
- `CANVAS_PROJECT_ROOT` — project directory for file serving
|
|
85
|
-
- `CANVAS_PORT` — daemon port (default: 19400)
|
|
86
|
-
- `CANVAS_TIMEOUT` — CLI feedback wait timeout (default: 1 hour)
|