agent-canvas 0.1.0 → 0.1.3
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/agent-canvas.ts +11 -4
- package/hooks/session-start.sh +6 -4
- package/package.json +5 -1
- package/skills/canvas/SKILL.md +14 -12
- package/skills/canvas/flows.md +2 -2
- package/daemon/dist/theme.css +0 -66
package/bin/agent-canvas.ts
CHANGED
|
@@ -15,7 +15,14 @@ const WS_URL = `ws://localhost:${DAEMON_PORT}`;
|
|
|
15
15
|
const TIMEOUT_MS = parseInt(process.env.CANVAS_TIMEOUT || String(60 * 60 * 1000), 10);
|
|
16
16
|
const PID_FILE = join(TEMP_DIR, "daemon.pid");
|
|
17
17
|
|
|
18
|
-
function getSessionId(): string {
|
|
18
|
+
function getSessionId(args?: string[]): string {
|
|
19
|
+
// Check --session flag first
|
|
20
|
+
if (args) {
|
|
21
|
+
const idx = args.indexOf("--session");
|
|
22
|
+
if (idx !== -1 && args[idx + 1]) {
|
|
23
|
+
return args[idx + 1];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
19
26
|
return process.env.CANVAS_SESSION_ID || (() => {
|
|
20
27
|
const id = randomUUID();
|
|
21
28
|
console.error(`Warning: CANVAS_SESSION_ID not set, using generated ID: ${id}`);
|
|
@@ -51,7 +58,7 @@ function printUsage() {
|
|
|
51
58
|
Commands:
|
|
52
59
|
agent-canvas install [local|global] Install skill & hooks for Claude Code
|
|
53
60
|
agent-canvas push <file.jsx> Push a canvas, open browser
|
|
54
|
-
agent-canvas wait
|
|
61
|
+
agent-canvas wait [--session <id>] Wait for user feedback (prints to stdout)
|
|
55
62
|
agent-canvas daemon status Show daemon status
|
|
56
63
|
agent-canvas daemon stop Stop the daemon
|
|
57
64
|
|
|
@@ -165,7 +172,7 @@ async function handlePush(args: string[]) {
|
|
|
165
172
|
jsx = readFileSync(filePath, "utf-8");
|
|
166
173
|
}
|
|
167
174
|
|
|
168
|
-
const sessionId = getSessionId();
|
|
175
|
+
const sessionId = getSessionId(args);
|
|
169
176
|
const projectRoot = process.env.CANVAS_PROJECT_ROOT || process.cwd();
|
|
170
177
|
|
|
171
178
|
// Extract --label flag
|
|
@@ -203,7 +210,7 @@ async function handlePush(args: string[]) {
|
|
|
203
210
|
// ── wait ──
|
|
204
211
|
|
|
205
212
|
async function handleWait(args: string[]) {
|
|
206
|
-
const sessionId = getSessionId();
|
|
213
|
+
const sessionId = getSessionId(args);
|
|
207
214
|
|
|
208
215
|
await ensureDaemon();
|
|
209
216
|
|
package/hooks/session-start.sh
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# Injects CANVAS_SESSION_ID and CANVAS_PROJECT_ROOT into Claude Code environment.
|
|
3
3
|
# Called by Claude Code's SessionStart hook.
|
|
4
|
-
INPUT=$(cat /dev/stdin)
|
|
5
|
-
SESSION_ID=$(echo "$INPUT" | grep -o '"session_id":"[^"]*"' | cut -d'"' -f4)
|
|
6
|
-
CWD=$(echo "$INPUT" | grep -o '"cwd":"[^"]*"' | cut -d'"' -f4)
|
|
7
4
|
|
|
8
|
-
if [ -n "$
|
|
5
|
+
if [ -n "$CLAUDE_ENV_FILE" ]; then
|
|
6
|
+
# Extract session ID from CLAUDE_ENV_FILE path:
|
|
7
|
+
# /home/.../.claude/session-env/<SESSION_ID>/sessionstart-hook-0.sh
|
|
8
|
+
SESSION_ID=$(basename "$(dirname "$CLAUDE_ENV_FILE")")
|
|
9
|
+
CWD="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
10
|
+
|
|
9
11
|
echo "export CANVAS_SESSION_ID=$SESSION_ID" >> "$CLAUDE_ENV_FILE"
|
|
10
12
|
echo "export CANVAS_PROJECT_ROOT=$CWD" >> "$CLAUDE_ENV_FILE"
|
|
11
13
|
fi
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-canvas",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
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"
|
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
"@types/react-dom": "^18.3.1",
|
|
30
30
|
"tailwindcss": "4"
|
|
31
31
|
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/contember/agent-canvas"
|
|
35
|
+
},
|
|
32
36
|
"license": "MIT",
|
|
33
37
|
"keywords": [
|
|
34
38
|
"claude-code",
|
package/skills/canvas/SKILL.md
CHANGED
|
@@ -23,10 +23,10 @@ Canvas opens a rich, annotatable document in the user's browser. You write JSX,
|
|
|
23
23
|
|
|
24
24
|
### Writing a Canvas
|
|
25
25
|
|
|
26
|
-
Use the **Write** tool to create a `.jsx` file in `.claude/canvas/`:
|
|
26
|
+
Use the **Write** tool to create a `.jsx` file in `.claude/agent-canvas/`:
|
|
27
27
|
|
|
28
28
|
```jsx
|
|
29
|
-
// Write to: .claude/canvas/plan.jsx
|
|
29
|
+
// Write to: .claude/agent-canvas/plan.jsx
|
|
30
30
|
|
|
31
31
|
<Section title="Authentication Redesign">
|
|
32
32
|
A proposal to replace session-based auth with JWT tokens.
|
|
@@ -50,10 +50,10 @@ Components are auto-available — no imports needed. The file is a JSX fragment
|
|
|
50
50
|
After writing the file, push it to open the canvas in the browser:
|
|
51
51
|
|
|
52
52
|
```bash
|
|
53
|
-
bunx agent-canvas push .claude/canvas/plan.jsx --label "Implementation Plan"
|
|
53
|
+
bunx agent-canvas push .claude/agent-canvas/plan.jsx --label "Implementation Plan"
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
This opens the canvas in the user's browser (first time) and exits immediately. The round label defaults to the filename if `--label` is omitted.
|
|
56
|
+
This opens the canvas in the user's browser (first time) and exits immediately. The round label defaults to the filename if `--label` is omitted. **Always show the `browserUrl` from the push output to the user** so they can open the canvas manually if auto-open didn't work.
|
|
57
57
|
|
|
58
58
|
### Waiting for feedback
|
|
59
59
|
|
|
@@ -65,12 +65,14 @@ bunx agent-canvas wait
|
|
|
65
65
|
|
|
66
66
|
This **blocks until the user submits feedback**, then prints feedback markdown to stdout. If feedback was already submitted (e.g. retrying after a disconnect), it returns immediately with the existing feedback.
|
|
67
67
|
|
|
68
|
+
> **Note:** If `push` outputs a warning "CANVAS_SESSION_ID not set, using generated ID: ...", you must pass that ID to wait: `bunx agent-canvas wait --session <id>`
|
|
69
|
+
|
|
68
70
|
### Iterating
|
|
69
71
|
|
|
70
72
|
Use the **Edit** tool to modify the existing JSX based on feedback — targeted edits, not full rewrites. Then push and wait again:
|
|
71
73
|
|
|
72
74
|
```bash
|
|
73
|
-
bunx agent-canvas push .claude/canvas/plan.jsx --label "Implementation Plan (revised)"
|
|
75
|
+
bunx agent-canvas push .claude/agent-canvas/plan.jsx --label "Implementation Plan (revised)"
|
|
74
76
|
bunx agent-canvas wait
|
|
75
77
|
```
|
|
76
78
|
|
|
@@ -81,19 +83,19 @@ Each push creates a new **round** — the user sees previous rounds and their fe
|
|
|
81
83
|
Maintain separate files for different phases:
|
|
82
84
|
|
|
83
85
|
```bash
|
|
84
|
-
bunx agent-canvas push .claude/canvas/discovery.jsx --label "Discovery"
|
|
86
|
+
bunx agent-canvas push .claude/agent-canvas/discovery.jsx --label "Discovery"
|
|
85
87
|
bunx agent-canvas wait
|
|
86
88
|
# ... process feedback ...
|
|
87
|
-
bunx agent-canvas push .claude/canvas/requirements.jsx --label "Requirements"
|
|
89
|
+
bunx agent-canvas push .claude/agent-canvas/requirements.jsx --label "Requirements"
|
|
88
90
|
bunx agent-canvas wait
|
|
89
91
|
# ... process feedback ...
|
|
90
|
-
bunx agent-canvas push .claude/canvas/plan.jsx --label "Implementation Plan"
|
|
92
|
+
bunx agent-canvas push .claude/agent-canvas/plan.jsx --label "Implementation Plan"
|
|
91
93
|
bunx agent-canvas wait
|
|
92
94
|
```
|
|
93
95
|
|
|
94
96
|
### File Location
|
|
95
97
|
|
|
96
|
-
All canvas files go in `.claude/canvas/` within the project root. Add `.claude/canvas/` to `.gitignore` — these are ephemeral working files.
|
|
98
|
+
All canvas files go in `.claude/agent-canvas/` within the project root. Add `.claude/agent-canvas/` to `.gitignore` — these are ephemeral working files.
|
|
97
99
|
|
|
98
100
|
## Choosing a Flow
|
|
99
101
|
|
|
@@ -127,8 +129,8 @@ User wants to make a decision?
|
|
|
127
129
|
|
|
128
130
|
1. **Determine flow** from user intent
|
|
129
131
|
2. **Announce** briefly: "I'll start with discovery, then create a detailed plan."
|
|
130
|
-
3. **Write canvas JSX** with the Write tool to `.claude/canvas/<name>.jsx`
|
|
131
|
-
4. **Push**: `bunx agent-canvas push .claude/canvas/<name>.jsx --label "<Label>"`
|
|
132
|
+
3. **Write canvas JSX** with the Write tool to `.claude/agent-canvas/<name>.jsx`
|
|
133
|
+
4. **Push**: `bunx agent-canvas push .claude/agent-canvas/<name>.jsx --label "<Label>"`
|
|
132
134
|
5. **Tell the user** the canvas is ready for review (they see it in their browser)
|
|
133
135
|
6. **Wait**: `bunx agent-canvas wait` — this blocks until the user submits feedback
|
|
134
136
|
7. **Read feedback** — check for annotations, answers, added context files, approval
|
|
@@ -163,7 +165,7 @@ Then interview deeply in each selected area across subsequent rounds. Or ask in
|
|
|
163
165
|
|
|
164
166
|
## Important Rules
|
|
165
167
|
|
|
166
|
-
- **Write** canvas files to `.claude/canvas/` using the Write tool. Never use bash heredocs or cat.
|
|
168
|
+
- **Write** canvas files to `.claude/agent-canvas/` using the Write tool. Never use bash heredocs or cat.
|
|
167
169
|
- **Edit** canvas files using the Edit tool. Never rewrite entire files — make targeted edits.
|
|
168
170
|
- JSX can be a fragment (just tags) or a full module with `export default function Canvas()`.
|
|
169
171
|
- Every `<Item>` and interactive component needs a unique `id`.
|
package/skills/canvas/flows.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Each flow is a sequence of canvas rounds. Phases can be skipped or combined based on context.
|
|
4
4
|
|
|
5
|
-
**Tooling reminder**: Write all `.jsx` files using the **Write** tool to `.claude/canvas/`. Edit them with the **Edit** tool. Push with `bunx agent-canvas push .claude/canvas/<file>.jsx --label "<Label>"`, then `bunx agent-canvas wait` to block for feedback. The JSX blocks below show what to write — they are the file content, not bash commands.
|
|
5
|
+
**Tooling reminder**: Write all `.jsx` files using the **Write** tool to `.claude/agent-canvas/`. Edit them with the **Edit** tool. Push with `bunx agent-canvas push .claude/agent-canvas/<file>.jsx --label "<Label>"`, then `bunx agent-canvas wait` to block for feedback. The JSX blocks below show what to write — they are the file content, not bash commands.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -16,7 +16,7 @@ Each flow is a sequence of canvas rounds. Phases can be skipped or combined base
|
|
|
16
16
|
|
|
17
17
|
Goal: understand scope, constraints, and user expectations. Start broad, go deep.
|
|
18
18
|
|
|
19
|
-
Write to `.claude/canvas/discovery.jsx`, then push and wait:
|
|
19
|
+
Write to `.claude/agent-canvas/discovery.jsx`, then push and wait:
|
|
20
20
|
|
|
21
21
|
```jsx
|
|
22
22
|
<Section title="Discovery: [Feature Name]">
|
package/daemon/dist/theme.css
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
@theme {
|
|
2
|
-
/* Colors — initial values, overridden by [data-theme] in styles.css */
|
|
3
|
-
--color-bg-base: #1a1a1a;
|
|
4
|
-
--color-bg-surface: #1e1e1e;
|
|
5
|
-
--color-bg-elevated: #242424;
|
|
6
|
-
--color-bg-code: #1c1c1c;
|
|
7
|
-
--color-bg-input: rgba(255, 248, 240, 0.03);
|
|
8
|
-
--color-bg-elevated-half: rgba(36, 36, 36, 0.5);
|
|
9
|
-
|
|
10
|
-
--color-text-primary: #e8e4df;
|
|
11
|
-
--color-text-secondary: #a09a92;
|
|
12
|
-
--color-text-tertiary: #847d75;
|
|
13
|
-
--color-text-code: #c4beb7;
|
|
14
|
-
--color-text-disabled: #3a3530;
|
|
15
|
-
--color-text-inverse: #1a1a1a;
|
|
16
|
-
|
|
17
|
-
--color-border-subtle: rgba(255, 248, 240, 0.06);
|
|
18
|
-
--color-border-medium: rgba(255, 248, 240, 0.08);
|
|
19
|
-
--color-border-hover: rgba(255, 248, 240, 0.12);
|
|
20
|
-
--color-border-strong: rgba(255, 248, 240, 0.15);
|
|
21
|
-
|
|
22
|
-
--color-accent-green: #4a9e6d;
|
|
23
|
-
--color-accent-green-muted: rgba(74, 158, 109, 0.12);
|
|
24
|
-
--color-accent-amber: #c49a3a;
|
|
25
|
-
--color-accent-amber-muted: rgba(196, 154, 58, 0.12);
|
|
26
|
-
--color-accent-red: #c45a5a;
|
|
27
|
-
--color-accent-red-muted: rgba(196, 90, 90, 0.12);
|
|
28
|
-
--color-accent-blue: #5a8ec4;
|
|
29
|
-
--color-accent-blue-muted: rgba(90, 142, 196, 0.10);
|
|
30
|
-
|
|
31
|
-
--color-highlight-bg: rgba(255, 220, 100, 0.15);
|
|
32
|
-
--color-highlight-border: rgba(255, 220, 100, 0.35);
|
|
33
|
-
--color-highlight-annotation: rgba(255, 220, 100, 0.08);
|
|
34
|
-
--color-highlight-active: rgba(255, 220, 100, 0.25);
|
|
35
|
-
--color-highlight-selected: rgba(255, 220, 100, 0.10);
|
|
36
|
-
|
|
37
|
-
--color-badge-bg: rgba(196, 154, 58, 0.20);
|
|
38
|
-
--color-btn-primary: #e8e4df;
|
|
39
|
-
--color-btn-primary-text: #1a1a1a;
|
|
40
|
-
|
|
41
|
-
/* Fonts */
|
|
42
|
-
--font-heading: 'Instrument Serif', Georgia, 'Times New Roman', serif;
|
|
43
|
-
--font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
44
|
-
--font-mono: 'JetBrains Mono', 'Fira Code', Consolas, monospace;
|
|
45
|
-
|
|
46
|
-
/* Font sizes */
|
|
47
|
-
--text-section: 1.75rem;
|
|
48
|
-
--text-section--line-height: 1.25;
|
|
49
|
-
--text-section--letter-spacing: -0.01em;
|
|
50
|
-
--text-task-label: 0.9375rem;
|
|
51
|
-
--text-task-label--line-height: 1.4;
|
|
52
|
-
--text-body: 0.875rem;
|
|
53
|
-
--text-body--line-height: 1.65;
|
|
54
|
-
--text-code: 0.8125rem;
|
|
55
|
-
--text-code--line-height: 1.6;
|
|
56
|
-
--text-meta: 0.75rem;
|
|
57
|
-
--text-meta--line-height: 1.4;
|
|
58
|
-
--text-meta--letter-spacing: 0.02em;
|
|
59
|
-
--text-tiny: 0.6875rem;
|
|
60
|
-
--text-tiny--line-height: 1.4;
|
|
61
|
-
|
|
62
|
-
/* Shadows */
|
|
63
|
-
--shadow-sm: 0 1px 2px var(--color-shadow);
|
|
64
|
-
--shadow-md: 0 4px 12px var(--color-shadow);
|
|
65
|
-
--shadow-lg: 0 8px 24px var(--color-shadow);
|
|
66
|
-
}
|