agent-canvas 0.1.5 → 0.1.7

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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +71 -0
  3. package/bin/agent-canvas.ts +26 -353
  4. package/bin/lib/commands/daemon.ts +51 -0
  5. package/bin/lib/commands/fetch.ts +20 -0
  6. package/bin/lib/commands/install.ts +48 -0
  7. package/bin/lib/commands/push.ts +66 -0
  8. package/bin/lib/commands/watch.ts +23 -0
  9. package/bin/lib/config.ts +10 -0
  10. package/bin/lib/daemon-lifecycle.ts +74 -0
  11. package/bin/lib/helpers.ts +78 -0
  12. package/daemon/build.ts +27 -61
  13. package/daemon/client/AnnotationProvider.tsx +2 -2
  14. package/daemon/client/AnnotationSidebar.tsx +199 -31
  15. package/daemon/client/App.tsx +4 -3
  16. package/daemon/client/FileBrowser.tsx +8 -7
  17. package/daemon/client/FileViewer.tsx +153 -16
  18. package/daemon/client/PlanRenderer.tsx +6 -3
  19. package/daemon/client/ResponsePreview.tsx +5 -116
  20. package/daemon/client/SessionSwitcher.tsx +21 -10
  21. package/daemon/client/compat/preact-all.ts +4 -0
  22. package/daemon/client/components/Markdown.tsx +44 -0
  23. package/daemon/client/components/ResponseNote.tsx +3 -8
  24. package/daemon/client/components/UserInput.tsx +2 -4
  25. package/daemon/client/components/index.ts +1 -0
  26. package/daemon/client/domDiff.ts +82 -2
  27. package/daemon/client/generateMarkdown.ts +46 -9
  28. package/daemon/client/highlightRange.ts +8 -6
  29. package/daemon/client/runtime.ts +2 -0
  30. package/daemon/client/styles.css +126 -0
  31. package/daemon/client/unifiedDiff.ts +155 -2
  32. package/daemon/client/utils.ts +10 -0
  33. package/daemon/dist/client.css +1 -1
  34. package/daemon/dist/client.js +83 -36
  35. package/daemon/dist/components.js +63 -5
  36. package/daemon/dist/index.html +5 -12
  37. package/daemon/dist/jsx-runtime.js +3 -0
  38. package/daemon/dist/preact-compat.js +1 -0
  39. package/daemon/src/compiler.ts +28 -2
  40. package/daemon/src/handlers/api.ts +150 -0
  41. package/daemon/src/handlers/files.ts +114 -0
  42. package/daemon/src/handlers/static.ts +61 -0
  43. package/daemon/src/handlers/utils.ts +14 -0
  44. package/daemon/src/router.ts +16 -0
  45. package/daemon/src/server.ts +28 -403
  46. package/daemon/src/session.ts +41 -23
  47. package/daemon/src/websocket.ts +83 -0
  48. package/package.json +3 -3
  49. package/skills/canvas/SKILL.md +32 -22
  50. package/skills/canvas/components.md +31 -0
  51. package/skills/canvas/flows.md +2 -2
  52. package/daemon/dist/jsx-dev-runtime-shim.js +0 -17
  53. package/daemon/dist/jsx-runtime-shim.js +0 -17
  54. package/daemon/dist/react-dom-client-shim.js +0 -4
  55. package/daemon/dist/react-dom-shim.js +0 -4
  56. package/daemon/dist/react-shim.js +0 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-canvas",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
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"
@@ -21,8 +21,8 @@
21
21
  "prepublishOnly": "bun daemon/build.ts"
22
22
  },
23
23
  "dependencies": {
24
- "react": "^18.3.1",
25
- "react-dom": "^18.3.1"
24
+ "marked": "^17.0.4",
25
+ "preact": "^10.25.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@tailwindcss/cli": "4",
@@ -15,18 +15,18 @@ disable-model-invocation: true
15
15
 
16
16
  Canvas opens a rich, annotatable document in the user's browser. You write JSX, the user reviews and annotates it like Google Docs, and feedback comes back as markdown. Use it whenever structured visual communication beats inline chat.
17
17
 
18
- **Read the flow reference before starting**: Check `flows.md` to pick the right flow for your task. Each flow has a specific sequence of canvases with templates.
18
+ **Read the flow reference before starting**: Check `${CLAUDE_SKILL_DIR}/flows.md` to pick the right flow for your task. Each flow has a specific sequence of canvases with templates.
19
19
 
20
- **Read the component reference as needed**: Check `components.md` for the full component API.
20
+ **Read the component reference as needed**: Check `${CLAUDE_SKILL_DIR}/components.md` for the full component API.
21
21
 
22
22
  ## Core Mechanics
23
23
 
24
24
  ### Writing a Canvas
25
25
 
26
- Use the **Write** tool to create a `.jsx` file in `.claude/agent-canvas/`:
26
+ Use the **Write** tool to create a `.jsx` file in `.claude/agent-canvas/${CLAUDE_SESSION_ID}/`:
27
27
 
28
28
  ```jsx
29
- // Write to: .claude/agent-canvas/plan.jsx
29
+ // Write to: .claude/agent-canvas/${CLAUDE_SESSION_ID}/plan.jsx
30
30
 
31
31
  <Section title="Authentication Redesign">
32
32
  A proposal to replace session-based auth with JWT tokens.
@@ -50,7 +50,7 @@ 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/agent-canvas/plan.jsx --label "Implementation Plan"
53
+ bunx agent-canvas push .claude/agent-canvas/${CLAUDE_SESSION_ID}/plan.jsx --session ${CLAUDE_SESSION_ID} --label "Implementation Plan"
54
54
  ```
55
55
 
56
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.
@@ -60,20 +60,30 @@ This opens the canvas in the user's browser (first time) and exits immediately.
60
60
  After pushing, wait for the user to review and submit:
61
61
 
62
62
  ```bash
63
- bunx agent-canvas wait
63
+ bunx agent-canvas watch --session ${CLAUDE_SESSION_ID}
64
64
  ```
65
65
 
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.
66
+ This **blocks until the user submits feedback**, then prints feedback markdown to stdout. If feedback was already submitted but not yet consumed, 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>`
68
+ **Timeout handling**: The watch command may time out if the user takes a while to review. If it times out, don't retry automatically — wait for the user to tell you they've submitted feedback, then run the watch command again (or use `fetch`) to retrieve it.
69
+
70
+ ### Checking for feedback without blocking
71
+
72
+ Use `fetch` to check for feedback without waiting:
73
+
74
+ ```bash
75
+ bunx agent-canvas fetch --session ${CLAUDE_SESSION_ID}
76
+ ```
77
+
78
+ Returns immediately — prints feedback to stdout if available, otherwise produces no output. Use this to retry after a timeout or when the user tells you they've submitted.
69
79
 
70
80
  ### Iterating
71
81
 
72
82
  Use the **Edit** tool to modify the existing JSX based on feedback — targeted edits, not full rewrites. Then push and wait again:
73
83
 
74
84
  ```bash
75
- bunx agent-canvas push .claude/agent-canvas/plan.jsx --label "Implementation Plan (revised)"
76
- bunx agent-canvas wait
85
+ bunx agent-canvas push .claude/agent-canvas/${CLAUDE_SESSION_ID}/plan.jsx --session ${CLAUDE_SESSION_ID} --label "Implementation Plan (revised)"
86
+ bunx agent-canvas watch --session ${CLAUDE_SESSION_ID}
77
87
  ```
78
88
 
79
89
  Each push creates a new **round** — the user sees previous rounds and their feedback in the UI.
@@ -83,23 +93,23 @@ Each push creates a new **round** — the user sees previous rounds and their fe
83
93
  Maintain separate files for different phases:
84
94
 
85
95
  ```bash
86
- bunx agent-canvas push .claude/agent-canvas/discovery.jsx --label "Discovery"
87
- bunx agent-canvas wait
96
+ bunx agent-canvas push .claude/agent-canvas/${CLAUDE_SESSION_ID}/discovery.jsx --session ${CLAUDE_SESSION_ID} --label "Discovery"
97
+ bunx agent-canvas watch --session ${CLAUDE_SESSION_ID}
88
98
  # ... process feedback ...
89
- bunx agent-canvas push .claude/agent-canvas/requirements.jsx --label "Requirements"
90
- bunx agent-canvas wait
99
+ bunx agent-canvas push .claude/agent-canvas/${CLAUDE_SESSION_ID}/requirements.jsx --session ${CLAUDE_SESSION_ID} --label "Requirements"
100
+ bunx agent-canvas watch --session ${CLAUDE_SESSION_ID}
91
101
  # ... process feedback ...
92
- bunx agent-canvas push .claude/agent-canvas/plan.jsx --label "Implementation Plan"
93
- bunx agent-canvas wait
102
+ bunx agent-canvas push .claude/agent-canvas/${CLAUDE_SESSION_ID}/plan.jsx --session ${CLAUDE_SESSION_ID} --label "Implementation Plan"
103
+ bunx agent-canvas watch --session ${CLAUDE_SESSION_ID}
94
104
  ```
95
105
 
96
106
  ### File Location
97
107
 
98
- All canvas files go in `.claude/agent-canvas/` within the project root. Add `.claude/agent-canvas/` to `.gitignore` — these are ephemeral working files.
108
+ All canvas files go in `.claude/agent-canvas/${CLAUDE_SESSION_ID}/` within the project root. Add `.claude/agent-canvas/` to `.gitignore` — these are ephemeral working files.
99
109
 
100
110
  ## Choosing a Flow
101
111
 
102
- Determine which flow fits before starting. See `flows.md` for full details with templates.
112
+ Determine which flow fits before starting. See `${CLAUDE_SKILL_DIR}/flows.md` for full details with templates.
103
113
 
104
114
  ```
105
115
  User wants something built/changed?
@@ -129,10 +139,10 @@ User wants to make a decision?
129
139
 
130
140
  1. **Determine flow** from user intent
131
141
  2. **Announce** briefly: "I'll start with discovery, then create a detailed plan."
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>"`
142
+ 3. **Write canvas JSX** with the Write tool to `.claude/agent-canvas/${CLAUDE_SESSION_ID}/<name>.jsx`
143
+ 4. **Push**: `bunx agent-canvas push .claude/agent-canvas/${CLAUDE_SESSION_ID}/<name>.jsx --session ${CLAUDE_SESSION_ID} --label "<Label>"`
134
144
  5. **Tell the user** the canvas is ready for review (they see it in their browser)
135
- 6. **Wait**: `bunx agent-canvas wait` — this blocks until the user submits feedback
145
+ 6. **Wait**: `bunx agent-canvas watch --session ${CLAUDE_SESSION_ID}` — this blocks until the user submits feedback
136
146
  7. **Read feedback** — check for annotations, answers, added context files, approval
137
147
  8. **Edit with the Edit tool and re-push + wait**, or advance to next phase
138
148
  9. **After implementation**, push a summary canvas
@@ -165,7 +175,7 @@ Then interview deeply in each selected area across subsequent rounds. Or ask in
165
175
 
166
176
  ## Important Rules
167
177
 
168
- - **Write** canvas files to `.claude/agent-canvas/` using the Write tool. Never use bash heredocs or cat.
178
+ - **Write** canvas files to `.claude/agent-canvas/${CLAUDE_SESSION_ID}/` using the Write tool. Never use bash heredocs or cat.
169
179
  - **Edit** canvas files using the Edit tool. Never rewrite entire files — make targeted edits.
170
180
  - JSX can be a fragment (just tags) or a full module with `export default function Canvas()`.
171
181
  - Every `<Item>` and interactive component needs a unique `id`.
@@ -100,6 +100,37 @@ Inline code block with syntax highlighting. For code that's part of the narrativ
100
100
  **Props:**
101
101
  - `language` (string) — syntax highlighting language
102
102
 
103
+ ### `<Markdown>`
104
+
105
+ Renders markdown content with full GFM support (headings, lists, tables, code blocks, links, etc.). Two modes:
106
+
107
+ **Inline source** — markdown as children:
108
+ ```jsx
109
+ <Markdown>{`
110
+ # Summary
111
+
112
+ This is **bold** and *italic*. Here's a list:
113
+
114
+ - First item
115
+ - Second item
116
+ - Nested item
117
+
118
+ \`\`\`typescript
119
+ const x = 42;
120
+ \`\`\`
121
+ `}</Markdown>
122
+ ```
123
+
124
+ **File reference** — loads file content at compile time:
125
+ ```jsx
126
+ <Markdown file="docs/architecture.md" />
127
+ <Markdown file="CHANGELOG.md" />
128
+ ```
129
+
130
+ **Props:**
131
+ - `file` (string) — path relative to project root. Content is resolved at compile time.
132
+ - Children (string) — inline markdown source. Used when `file` is not specified.
133
+
103
134
  ### `<ImageView src="string">`
104
135
 
105
136
  Displays an image from the project directory.
@@ -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/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.
5
+ **Tooling reminder**: Write all `.jsx` files using the **Write** tool to `.claude/agent-canvas/${CLAUDE_SESSION_ID}/`. Edit them with the **Edit** tool. Push with `bunx agent-canvas push .claude/agent-canvas/${CLAUDE_SESSION_ID}/<file>.jsx --session ${CLAUDE_SESSION_ID} --label "<Label>"`, then `bunx agent-canvas watch --session ${CLAUDE_SESSION_ID}` 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/agent-canvas/discovery.jsx`, then push and wait:
19
+ Write to `.claude/agent-canvas/${CLAUDE_SESSION_ID}/discovery.jsx`, then push and wait:
20
20
 
21
21
  ```jsx
22
22
  <Section title="Discovery: [Feature Name]">
@@ -1,17 +0,0 @@
1
-
2
- const R = window.React;
3
- export const Fragment = R.Fragment;
4
- function _jsx(type, props, key) {
5
- if (props && 'children' in props) {
6
- const { children, ...rest } = props;
7
- if (key !== undefined && key !== null) rest.key = key;
8
- return Array.isArray(children)
9
- ? R.createElement(type, rest, ...children)
10
- : R.createElement(type, rest, children);
11
- }
12
- if (key !== undefined && key !== null) props = { ...props, key };
13
- return R.createElement(type, props);
14
- }
15
- export const jsx = _jsx;
16
- export const jsxs = _jsx;
17
- export function jsxDEV(type, props, key) { return _jsx(type, props, key); }
@@ -1,17 +0,0 @@
1
-
2
- const R = window.React;
3
- export const Fragment = R.Fragment;
4
- function _jsx(type, props, key) {
5
- if (props && 'children' in props) {
6
- const { children, ...rest } = props;
7
- if (key !== undefined && key !== null) rest.key = key;
8
- return Array.isArray(children)
9
- ? R.createElement(type, rest, ...children)
10
- : R.createElement(type, rest, children);
11
- }
12
- if (key !== undefined && key !== null) props = { ...props, key };
13
- return R.createElement(type, props);
14
- }
15
- export const jsx = _jsx;
16
- export const jsxs = _jsx;
17
- export function jsxDEV(type, props, key) { return _jsx(type, props, key); }
@@ -1,4 +0,0 @@
1
-
2
- const RD = window.ReactDOM;
3
- export const { createRoot, hydrateRoot } = RD;
4
- export default { createRoot: RD.createRoot, hydrateRoot: RD.hydrateRoot };
@@ -1,4 +0,0 @@
1
-
2
- const RD = window.ReactDOM;
3
- export default RD;
4
- export const { createPortal, flushSync, hydrate, render, unmountComponentAtNode, findDOMNode, unstable_batchedUpdates } = RD;
@@ -1,4 +0,0 @@
1
-
2
- const R = window.React;
3
- export default R;
4
- 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;