@claude-canvas/vite-plugin 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4,37 +4,42 @@ import { ClaudeBridge } from "@claude-canvas/bridge";
4
4
  import { GitManager } from "@claude-canvas/bridge";
5
5
  import { QARunner } from "@claude-canvas/bridge";
6
6
  import { PromptBuilder } from "@claude-canvas/bridge";
7
+ import { mkdir, writeFile } from "fs/promises";
7
8
  function createServerHook(options) {
8
9
  return (server) => {
9
10
  const bridge = new ClaudeBridge(options);
10
11
  const gitManager = new GitManager();
11
12
  const qaRunner = new QARunner(options.qa);
12
- server.ws.on("canvas:message", (rawData) => {
13
+ server.ws.on("canvas:message", async (rawData) => {
13
14
  try {
14
15
  const msg = WSProtocol.parseClientMessage(rawData);
15
16
  switch (msg.type) {
16
17
  case "canvas:session-start":
17
- handleSessionStart(server, gitManager, options);
18
+ await handleSessionStart(server, gitManager, options);
18
19
  break;
19
20
  case "canvas:session-end":
20
- handleSessionEnd(server, gitManager, qaRunner, msg.payload.action);
21
+ await handleSessionEnd(server, gitManager, qaRunner, msg.payload.action);
21
22
  break;
22
23
  case "canvas:annotate":
23
- handleAnnotate(server, bridge, msg.payload);
24
+ await handleAnnotate(server, bridge, msg.payload);
24
25
  break;
25
26
  case "canvas:chat":
26
- handleChat(server, bridge, msg.payload.message);
27
+ await handleChat(server, bridge, msg.payload);
27
28
  break;
28
29
  case "canvas:qa-retry":
29
- handleQARetry(server, qaRunner);
30
+ await handleQARetry(server, qaRunner);
30
31
  break;
31
32
  }
32
33
  } catch (err) {
33
- const errMsg = WSProtocol.createErrorMessage(
34
- err instanceof Error ? err.message : "Unknown error",
35
- true
36
- );
37
- server.ws.send("canvas:message", WSProtocol.serializeServerMessage(errMsg));
34
+ console.warn("[claude-canvas] Error handling message:", err instanceof Error ? err.message : err);
35
+ try {
36
+ const errMsg = WSProtocol.createErrorMessage(
37
+ err instanceof Error ? err.message : "Unknown error",
38
+ true
39
+ );
40
+ server.ws.send("canvas:message", WSProtocol.serializeServerMessage(errMsg));
41
+ } catch {
42
+ }
38
43
  }
39
44
  });
40
45
  server.httpServer?.on("close", async () => {
@@ -92,16 +97,19 @@ async function handleAnnotate(server, bridge, payload) {
92
97
  payload: { delta: "", done: true }
93
98
  }));
94
99
  }
95
- async function handleChat(server, bridge, message) {
96
- for await (const delta of bridge.sendPrompt(message)) {
97
- server.ws.send("canvas:message", JSON.stringify({
98
- type: "canvas:stream",
99
- payload: { delta, done: false }
100
- }));
101
- }
100
+ var RELAY_DIR = "/tmp/claude-canvas";
101
+ async function handleChat(server, _bridge, payload) {
102
+ const request = {
103
+ element: payload.context?.source ?? null,
104
+ route: payload.context?.route ?? null,
105
+ instruction: payload.message,
106
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
107
+ };
108
+ await mkdir(RELAY_DIR, { recursive: true });
109
+ await writeFile(`${RELAY_DIR}/request.json`, JSON.stringify(request, null, 2));
102
110
  server.ws.send("canvas:message", JSON.stringify({
103
- type: "canvas:stream",
104
- payload: { delta: "", done: true }
111
+ type: "canvas:relay-saved",
112
+ payload: { path: `${RELAY_DIR}/request.json` }
105
113
  }));
106
114
  }
107
115
  async function handleQARetry(server, qa) {
@@ -120,30 +128,23 @@ async function handleQARetry(server, qa) {
120
128
  }));
121
129
  }
122
130
 
123
- // src/html-inject.ts
124
- function createHtmlInject(options) {
125
- return () => {
126
- return {
127
- html: "",
128
- tags: [
129
- {
130
- tag: "script",
131
- attrs: { type: "module" },
132
- children: generateClientScript(options),
133
- injectTo: "body"
134
- }
135
- ]
136
- };
137
- };
138
- }
131
+ // src/index.ts
132
+ var VIRTUAL_MODULE_ID = "virtual:claude-canvas-init";
133
+ var RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
139
134
  function generateClientScript(options) {
140
135
  const shortcut = options.shortcut || "ctrl+shift+a";
141
136
  return `
142
- import { ShadowContainer, CanvasOverlayPanel, ToolbarPanel, InspectorPopupPanel, ChatPanel, SessionBarPanel, QAResultPanel, FabButtonPanel, KeyboardHandler } from '@claude-canvas/core';
137
+ import { ShadowContainer, CanvasOverlayPanel, ToolbarPanel, InspectorPopupPanel, ChatPanel, SessionBarPanel, QAResultPanel, FabButton, KeyboardHandler, FiberWalker } from '@claude-canvas/core';
143
138
 
144
139
  const container = new ShadowContainer();
145
140
  container.mount();
146
141
  const shadow = container.getShadowRoot();
142
+ const shadowHost = shadow.host;
143
+
144
+ // Check if an element belongs to the canvas UI (shadow DOM)
145
+ function isCanvasUI(el) {
146
+ return el === shadowHost || shadowHost.contains(el);
147
+ }
147
148
 
148
149
  const overlay = new CanvasOverlayPanel();
149
150
  overlay.mount();
@@ -153,34 +154,202 @@ function generateClientScript(options) {
153
154
  const chat = new ChatPanel(shadow);
154
155
  const sessionBar = new SessionBarPanel(shadow);
155
156
  const qaResult = new QAResultPanel(shadow);
156
- const fab = new FabButtonPanel(shadow);
157
157
 
158
- // Wire up WebSocket via Vite HMR
158
+ let canvasActive = false;
159
+ let selectedSource = null;
160
+ let selectedRect = null;
161
+
162
+ // Helper: extract source info from element (fiber or DOM fallback)
163
+ function getSourceFromElement(el) {
164
+ const fiber = FiberWalker.getFiberFromElement(el);
165
+ if (fiber) {
166
+ const source = FiberWalker.getSourceInfo(fiber);
167
+ if (source) return source;
168
+ }
169
+ // DOM fallback
170
+ return {
171
+ componentName: el.tagName.toLowerCase(),
172
+ file: '',
173
+ line: 0,
174
+ column: 0,
175
+ tagName: el.tagName.toLowerCase(),
176
+ className: el.className || undefined,
177
+ };
178
+ }
179
+
180
+ function activateCanvas() {
181
+ canvasActive = true;
182
+ overlay.setMode('select');
183
+ if (chat.isCollapsed()) chat.toggle();
184
+ fab.setVisible(false);
185
+ chat.addMessage({ role: 'system', content: '\uC5B4\uB178\uD14C\uC774\uC158 \uBAA8\uB4DC \uD65C\uC131\uD654. \uC694\uC18C\uB97C \uD074\uB9AD\uD558\uC5EC \uC120\uD0DD\uD558\uC138\uC694.' });
186
+ }
187
+
188
+ function deactivateCanvas() {
189
+ canvasActive = false;
190
+ overlay.setMode('off');
191
+ overlay.clearAnnotations();
192
+ selectedSource = null;
193
+ selectedRect = null;
194
+ inspector.forceHide();
195
+ if (!chat.isCollapsed()) chat.toggle();
196
+ fab.setVisible(true);
197
+ }
198
+
199
+ function toggleCanvas() {
200
+ if (canvasActive) deactivateCanvas();
201
+ else activateCanvas();
202
+ }
203
+
204
+ const fab = new FabButton(shadow, { onActivate: toggleCanvas });
205
+ fab.mount();
206
+
207
+ // ---- Select mode: hover + click ----
208
+ document.addEventListener('mousemove', (e) => {
209
+ if (!canvasActive || overlay.getMode() !== 'select') return;
210
+ const el = document.elementFromPoint(e.clientX, e.clientY);
211
+ if (el && el instanceof HTMLElement && !isCanvasUI(el)) {
212
+ overlay.handleElementHover(el);
213
+ }
214
+ }, true);
215
+
216
+ document.addEventListener('click', (e) => {
217
+ if (!canvasActive || overlay.getMode() !== 'select') return;
218
+ const el = document.elementFromPoint(e.clientX, e.clientY);
219
+ if (!el || !(el instanceof HTMLElement) || isCanvasUI(el)) return;
220
+
221
+ e.preventDefault();
222
+ e.stopPropagation();
223
+
224
+ const rect = el.getBoundingClientRect();
225
+ const source = getSourceFromElement(el);
226
+ selectedSource = source;
227
+ selectedRect = rect;
228
+
229
+ // Draw orange select highlight
230
+ overlay.handleElementSelect(el);
231
+
232
+ // Show inspector popup with source info
233
+ inspector.show(source, rect);
234
+ inspector.pin();
235
+
236
+ // Add selection info to chat
237
+ const label = source.file
238
+ ? source.componentName + ' \u2014 ' + source.file + ':' + source.line
239
+ : '<' + source.componentName + '>' + (source.className ? '.' + source.className.split(' ')[0] : '');
240
+ chat.addMessage({ role: 'system', content: '\uC120\uD0DD: ' + label });
241
+ }, true);
242
+
243
+ // ---- Box mode: drag red rectangle ----
244
+ let boxDragging = false;
245
+ document.addEventListener('mousedown', (e) => {
246
+ if (!canvasActive || overlay.getMode() !== 'box') return;
247
+ e.preventDefault();
248
+ boxDragging = true;
249
+ overlay.boxTool.startDraw(e.clientX, e.clientY);
250
+ }, true);
251
+
252
+ document.addEventListener('mousemove', (e) => {
253
+ if (!boxDragging) return;
254
+ const rect = overlay.boxTool.updateDraw(e.clientX, e.clientY);
255
+ overlay.clearAnnotations();
256
+ overlay.setMode('box');
257
+ }, true);
258
+
259
+ document.addEventListener('mouseup', (e) => {
260
+ if (!boxDragging) return;
261
+ boxDragging = false;
262
+ const rect = overlay.boxTool.endDraw(e.clientX, e.clientY);
263
+ if (rect.width > 5 && rect.height > 5) {
264
+ chat.addMessage({ role: 'system', content: '\uC601\uC5ED \uC120\uD0DD: ' + Math.round(rect.width) + 'x' + Math.round(rect.height) + 'px' });
265
+ }
266
+ }, true);
267
+
268
+ // ---- Chat send \u2192 WS ----
269
+ chat.onMessageSend((message) => {
270
+ // Add user message to chat
271
+ chat.addMessage({ role: 'user', content: message });
272
+
273
+ // Build context with selected element info + current route
274
+ const route = window.location.pathname;
275
+ const context = selectedSource
276
+ ? { source: selectedSource, rect: selectedRect, annotations: overlay.collectAnnotationSet(), route }
277
+ : { annotations: overlay.collectAnnotationSet(), route };
278
+
279
+ // Send via Vite HMR WebSocket
280
+ if (import.meta.hot) {
281
+ import.meta.hot.send('canvas:message', JSON.stringify({
282
+ type: 'canvas:chat',
283
+ payload: { message, context },
284
+ }));
285
+ }
286
+
287
+ // Show pending response
288
+ chat.addMessage({ role: 'assistant', content: '...' });
289
+ });
290
+
291
+ // ---- Receive WS messages ----
159
292
  if (import.meta.hot) {
160
293
  import.meta.hot.on('canvas:message', (data) => {
161
- const msg = JSON.parse(data);
162
- // Route messages to appropriate panels
294
+ try {
295
+ const msg = typeof data === 'string' ? JSON.parse(data) : data;
296
+ if (msg.type === 'canvas:stream') {
297
+ if (msg.payload.delta) chat.appendStream(msg.payload.delta);
298
+ if (msg.payload.done) chat.appendStream(' [\uC644\uB8CC]');
299
+ } else if (msg.type === 'canvas:relay-saved') {
300
+ chat.appendStream('\uC800\uC7A5\uB428 \u2014 \uD130\uBBF8\uB110\uC5D0\uC11C \uCC98\uB9AC\uD558\uC138\uC694');
301
+ } else if (msg.type === 'canvas:error') {
302
+ chat.appendStream('[\uC624\uB958] ' + (msg.payload.message || 'Unknown error'));
303
+ }
304
+ } catch (err) {
305
+ console.warn('[claude-canvas] WS parse error:', err);
306
+ }
163
307
  });
164
308
  }
165
309
 
166
- // Keyboard handler (shortcut: ${shortcut})
310
+ // ---- Keyboard handler ----
167
311
  const keyboard = new KeyboardHandler({
168
- onToggleMode: () => { /* toggle annotation mode */ },
169
- onEscape: () => { overlay.setMode('off'); },
170
- onToolSwitch: (mode) => { overlay.setMode(mode); toolbar.setActiveTool(mode); },
171
- onSend: () => { /* send via chat */ },
172
- });
312
+ onToggleMode: toggleCanvas,
313
+ onEscape: deactivateCanvas,
314
+ onToolSwitch: (mode) => {
315
+ if (!canvasActive) return;
316
+ overlay.setMode(mode);
317
+ toolbar.setActiveTool(mode);
318
+ },
319
+ onSend: () => {},
320
+ }, { shortcut: '${shortcut}' });
173
321
  keyboard.mount();
174
322
  `;
175
323
  }
176
-
177
- // src/index.ts
178
324
  function claudeCanvas(options = {}) {
179
325
  return {
180
326
  name: "vite-plugin-claude-canvas",
181
327
  apply: "serve",
182
- configureServer: createServerHook(options),
183
- transformIndexHtml: createHtmlInject(options)
328
+ resolveId(id) {
329
+ if (id === VIRTUAL_MODULE_ID) {
330
+ return RESOLVED_VIRTUAL_MODULE_ID;
331
+ }
332
+ return void 0;
333
+ },
334
+ load(id) {
335
+ if (id === RESOLVED_VIRTUAL_MODULE_ID) {
336
+ return generateClientScript(options);
337
+ }
338
+ return void 0;
339
+ },
340
+ transformIndexHtml() {
341
+ return {
342
+ html: "",
343
+ tags: [
344
+ {
345
+ tag: "script",
346
+ attrs: { type: "module", src: `/@id/${VIRTUAL_MODULE_ID}` },
347
+ injectTo: "body"
348
+ }
349
+ ]
350
+ };
351
+ },
352
+ configureServer: createServerHook(options)
184
353
  };
185
354
  }
186
355
  var index_default = claudeCanvas;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server-hook.ts","../src/html-inject.ts","../src/index.ts"],"sourcesContent":["import type { ViteDevServer } from 'vite'\nimport type { AnnotationSet } from '@claude-canvas/core'\nimport type { ClaudeCanvasOptions } from './types.js'\nimport { WSProtocol } from '@claude-canvas/bridge'\nimport { ClaudeBridge } from '@claude-canvas/bridge'\nimport { GitManager } from '@claude-canvas/bridge'\nimport { QARunner } from '@claude-canvas/bridge'\nimport { PromptBuilder } from '@claude-canvas/bridge'\n\nexport function createServerHook(options: ClaudeCanvasOptions) {\n return (server: ViteDevServer) => {\n const bridge = new ClaudeBridge(options)\n const gitManager = new GitManager()\n const qaRunner = new QARunner(options.qa)\n\n server.ws.on('canvas:message', (rawData: string) => {\n try {\n const msg = WSProtocol.parseClientMessage(rawData)\n\n switch (msg.type) {\n case 'canvas:session-start':\n handleSessionStart(server, gitManager, options)\n break\n case 'canvas:session-end':\n handleSessionEnd(server, gitManager, qaRunner, msg.payload.action)\n break\n case 'canvas:annotate':\n handleAnnotate(server, bridge, msg.payload)\n break\n case 'canvas:chat':\n handleChat(server, bridge, msg.payload.message)\n break\n case 'canvas:qa-retry':\n handleQARetry(server, qaRunner)\n break\n }\n } catch (err) {\n const errMsg = WSProtocol.createErrorMessage(\n err instanceof Error ? err.message : 'Unknown error',\n true\n )\n server.ws.send('canvas:message', WSProtocol.serializeServerMessage(errMsg))\n }\n })\n\n // Cleanup on server close\n server.httpServer?.on('close', async () => {\n await bridge.shutdown()\n })\n }\n}\n\nasync function handleSessionStart(\n server: ViteDevServer,\n git: GitManager,\n options: ClaudeCanvasOptions\n) {\n const session = await git.startSession({ branchPrefix: options.git?.branchPrefix })\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:session-status',\n payload: session,\n }))\n}\n\nasync function handleSessionEnd(\n server: ViteDevServer,\n git: GitManager,\n qa: QARunner,\n action: 'merge' | 'discard'\n) {\n if (action === 'merge') {\n const steps = []\n for await (const step of qa.run()) {\n steps.push(step)\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:qa-progress',\n payload: { step: step.name, status: step.pass ? 'pass' : 'fail' },\n }))\n }\n const result = qa.getResult(steps)\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:qa-result',\n payload: result,\n }))\n\n if (result.overallPass) {\n const mergeResult = await git.endSession('merge')\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:merge-result',\n payload: mergeResult,\n }))\n }\n } else {\n const mergeResult = await git.endSession('discard')\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:merge-result',\n payload: mergeResult,\n }))\n }\n}\n\nasync function handleAnnotate(\n server: ViteDevServer,\n bridge: ClaudeBridge,\n payload: { annotations: AnnotationSet; memo: string }\n) {\n const prompt = PromptBuilder.buildPrompt(payload.annotations, payload.memo)\n for await (const delta of bridge.sendPrompt(prompt)) {\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:stream',\n payload: { delta, done: false },\n }))\n }\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:stream',\n payload: { delta: '', done: true },\n }))\n}\n\nasync function handleChat(\n server: ViteDevServer,\n bridge: ClaudeBridge,\n message: string\n) {\n for await (const delta of bridge.sendPrompt(message)) {\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:stream',\n payload: { delta, done: false },\n }))\n }\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:stream',\n payload: { delta: '', done: true },\n }))\n}\n\nasync function handleQARetry(server: ViteDevServer, qa: QARunner) {\n const steps = []\n for await (const step of qa.run()) {\n steps.push(step)\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:qa-progress',\n payload: { step: step.name, status: step.pass ? 'pass' : 'fail' },\n }))\n }\n const result = qa.getResult(steps)\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:qa-result',\n payload: result,\n }))\n}\n","import type { IndexHtmlTransformResult } from 'vite'\nimport type { ClaudeCanvasOptions } from './types.js'\n\nexport function createHtmlInject(options: ClaudeCanvasOptions) {\n return (): IndexHtmlTransformResult => {\n return {\n html: '',\n tags: [\n {\n tag: 'script',\n attrs: { type: 'module' },\n children: generateClientScript(options),\n injectTo: 'body',\n },\n ],\n }\n }\n}\n\nfunction generateClientScript(options: ClaudeCanvasOptions): string {\n const shortcut = options.shortcut || 'ctrl+shift+a'\n return `\n import { ShadowContainer, CanvasOverlayPanel, ToolbarPanel, InspectorPopupPanel, ChatPanel, SessionBarPanel, QAResultPanel, FabButtonPanel, KeyboardHandler } from '@claude-canvas/core';\n\n const container = new ShadowContainer();\n container.mount();\n const shadow = container.getShadowRoot();\n\n const overlay = new CanvasOverlayPanel();\n overlay.mount();\n\n const toolbar = new ToolbarPanel(shadow);\n const inspector = new InspectorPopupPanel(shadow);\n const chat = new ChatPanel(shadow);\n const sessionBar = new SessionBarPanel(shadow);\n const qaResult = new QAResultPanel(shadow);\n const fab = new FabButtonPanel(shadow);\n\n // Wire up WebSocket via Vite HMR\n if (import.meta.hot) {\n import.meta.hot.on('canvas:message', (data) => {\n const msg = JSON.parse(data);\n // Route messages to appropriate panels\n });\n }\n\n // Keyboard handler (shortcut: ${shortcut})\n const keyboard = new KeyboardHandler({\n onToggleMode: () => { /* toggle annotation mode */ },\n onEscape: () => { overlay.setMode('off'); },\n onToolSwitch: (mode) => { overlay.setMode(mode); toolbar.setActiveTool(mode); },\n onSend: () => { /* send via chat */ },\n });\n keyboard.mount();\n `\n}\n","import type { Plugin } from 'vite'\r\nimport type { ClaudeCanvasOptions } from './types.js'\r\nimport { createServerHook } from './server-hook.js'\r\nimport { createHtmlInject } from './html-inject.js'\r\n\r\nexport function claudeCanvas(options: ClaudeCanvasOptions = {}): Plugin {\r\n return {\r\n name: 'vite-plugin-claude-canvas',\r\n apply: 'serve',\r\n configureServer: createServerHook(options),\r\n transformIndexHtml: createHtmlInject(options),\r\n }\r\n}\r\n\r\nexport default claudeCanvas\r\n\r\nexport type { ClaudeCanvasOptions }\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/server-hook.ts","../src/index.ts"],"sourcesContent":["import type { ViteDevServer } from 'vite'\nimport type { AnnotationSet } from '@claude-canvas/core'\nimport type { ClaudeCanvasOptions } from './types.js'\nimport { WSProtocol } from '@claude-canvas/bridge'\nimport { ClaudeBridge } from '@claude-canvas/bridge'\nimport { GitManager } from '@claude-canvas/bridge'\nimport { QARunner } from '@claude-canvas/bridge'\nimport { PromptBuilder } from '@claude-canvas/bridge'\nimport { mkdir, writeFile } from 'node:fs/promises'\n\nexport function createServerHook(options: ClaudeCanvasOptions) {\n return (server: ViteDevServer) => {\n const bridge = new ClaudeBridge(options)\n const gitManager = new GitManager()\n const qaRunner = new QARunner(options.qa)\n\n server.ws.on('canvas:message', async (rawData: string) => {\n try {\n const msg = WSProtocol.parseClientMessage(rawData)\n\n switch (msg.type) {\n case 'canvas:session-start':\n await handleSessionStart(server, gitManager, options)\n break\n case 'canvas:session-end':\n await handleSessionEnd(server, gitManager, qaRunner, msg.payload.action)\n break\n case 'canvas:annotate':\n await handleAnnotate(server, bridge, msg.payload)\n break\n case 'canvas:chat':\n await handleChat(server, bridge, msg.payload)\n break\n case 'canvas:qa-retry':\n await handleQARetry(server, qaRunner)\n break\n }\n } catch (err) {\n console.warn('[claude-canvas] Error handling message:', err instanceof Error ? err.message : err)\n try {\n const errMsg = WSProtocol.createErrorMessage(\n err instanceof Error ? err.message : 'Unknown error',\n true\n )\n server.ws.send('canvas:message', WSProtocol.serializeServerMessage(errMsg))\n } catch {\n // WS send failed — client may have disconnected\n }\n }\n })\n\n // Cleanup on server close\n server.httpServer?.on('close', async () => {\n await bridge.shutdown()\n })\n }\n}\n\nasync function handleSessionStart(\n server: ViteDevServer,\n git: GitManager,\n options: ClaudeCanvasOptions\n) {\n const session = await git.startSession({ branchPrefix: options.git?.branchPrefix })\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:session-status',\n payload: session,\n }))\n}\n\nasync function handleSessionEnd(\n server: ViteDevServer,\n git: GitManager,\n qa: QARunner,\n action: 'merge' | 'discard'\n) {\n if (action === 'merge') {\n const steps = []\n for await (const step of qa.run()) {\n steps.push(step)\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:qa-progress',\n payload: { step: step.name, status: step.pass ? 'pass' : 'fail' },\n }))\n }\n const result = qa.getResult(steps)\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:qa-result',\n payload: result,\n }))\n\n if (result.overallPass) {\n const mergeResult = await git.endSession('merge')\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:merge-result',\n payload: mergeResult,\n }))\n }\n } else {\n const mergeResult = await git.endSession('discard')\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:merge-result',\n payload: mergeResult,\n }))\n }\n}\n\nasync function handleAnnotate(\n server: ViteDevServer,\n bridge: ClaudeBridge,\n payload: { annotations: AnnotationSet; memo: string }\n) {\n const prompt = PromptBuilder.buildPrompt(payload.annotations, payload.memo)\n for await (const delta of bridge.sendPrompt(prompt)) {\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:stream',\n payload: { delta, done: false },\n }))\n }\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:stream',\n payload: { delta: '', done: true },\n }))\n}\n\nconst RELAY_DIR = '/tmp/claude-canvas'\n\nasync function handleChat(\n server: ViteDevServer,\n _bridge: ClaudeBridge,\n payload: { message: string; context?: { source?: unknown; route?: string } }\n) {\n const request = {\n element: payload.context?.source ?? null,\n route: payload.context?.route ?? null,\n instruction: payload.message,\n timestamp: new Date().toISOString(),\n }\n\n await mkdir(RELAY_DIR, { recursive: true })\n await writeFile(`${RELAY_DIR}/request.json`, JSON.stringify(request, null, 2))\n\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:relay-saved',\n payload: { path: `${RELAY_DIR}/request.json` },\n }))\n}\n\nasync function handleQARetry(server: ViteDevServer, qa: QARunner) {\n const steps = []\n for await (const step of qa.run()) {\n steps.push(step)\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:qa-progress',\n payload: { step: step.name, status: step.pass ? 'pass' : 'fail' },\n }))\n }\n const result = qa.getResult(steps)\n server.ws.send('canvas:message', JSON.stringify({\n type: 'canvas:qa-result',\n payload: result,\n }))\n}\n","import type { Plugin } from 'vite'\r\nimport type { ClaudeCanvasOptions } from './types.js'\r\nimport { createServerHook } from './server-hook.js'\r\n\r\nconst VIRTUAL_MODULE_ID = 'virtual:claude-canvas-init'\r\nconst RESOLVED_VIRTUAL_MODULE_ID = '\\0' + VIRTUAL_MODULE_ID\r\n\r\nfunction generateClientScript(options: ClaudeCanvasOptions): string {\r\n const shortcut = options.shortcut || 'ctrl+shift+a'\r\n return `\r\n import { ShadowContainer, CanvasOverlayPanel, ToolbarPanel, InspectorPopupPanel, ChatPanel, SessionBarPanel, QAResultPanel, FabButton, KeyboardHandler, FiberWalker } from '@claude-canvas/core';\r\n\r\n const container = new ShadowContainer();\r\n container.mount();\r\n const shadow = container.getShadowRoot();\r\n const shadowHost = shadow.host;\r\n\r\n // Check if an element belongs to the canvas UI (shadow DOM)\r\n function isCanvasUI(el) {\r\n return el === shadowHost || shadowHost.contains(el);\r\n }\r\n\r\n const overlay = new CanvasOverlayPanel();\r\n overlay.mount();\r\n\r\n const toolbar = new ToolbarPanel(shadow);\r\n const inspector = new InspectorPopupPanel(shadow);\r\n const chat = new ChatPanel(shadow);\r\n const sessionBar = new SessionBarPanel(shadow);\r\n const qaResult = new QAResultPanel(shadow);\r\n\r\n let canvasActive = false;\r\n let selectedSource = null;\r\n let selectedRect = null;\r\n\r\n // Helper: extract source info from element (fiber or DOM fallback)\r\n function getSourceFromElement(el) {\r\n const fiber = FiberWalker.getFiberFromElement(el);\r\n if (fiber) {\r\n const source = FiberWalker.getSourceInfo(fiber);\r\n if (source) return source;\r\n }\r\n // DOM fallback\r\n return {\r\n componentName: el.tagName.toLowerCase(),\r\n file: '',\r\n line: 0,\r\n column: 0,\r\n tagName: el.tagName.toLowerCase(),\r\n className: el.className || undefined,\r\n };\r\n }\r\n\r\n function activateCanvas() {\r\n canvasActive = true;\r\n overlay.setMode('select');\r\n if (chat.isCollapsed()) chat.toggle();\r\n fab.setVisible(false);\r\n chat.addMessage({ role: 'system', content: '어노테이션 모드 활성화. 요소를 클릭하여 선택하세요.' });\r\n }\r\n\r\n function deactivateCanvas() {\r\n canvasActive = false;\r\n overlay.setMode('off');\r\n overlay.clearAnnotations();\r\n selectedSource = null;\r\n selectedRect = null;\r\n inspector.forceHide();\r\n if (!chat.isCollapsed()) chat.toggle();\r\n fab.setVisible(true);\r\n }\r\n\r\n function toggleCanvas() {\r\n if (canvasActive) deactivateCanvas();\r\n else activateCanvas();\r\n }\r\n\r\n const fab = new FabButton(shadow, { onActivate: toggleCanvas });\r\n fab.mount();\r\n\r\n // ---- Select mode: hover + click ----\r\n document.addEventListener('mousemove', (e) => {\r\n if (!canvasActive || overlay.getMode() !== 'select') return;\r\n const el = document.elementFromPoint(e.clientX, e.clientY);\r\n if (el && el instanceof HTMLElement && !isCanvasUI(el)) {\r\n overlay.handleElementHover(el);\r\n }\r\n }, true);\r\n\r\n document.addEventListener('click', (e) => {\r\n if (!canvasActive || overlay.getMode() !== 'select') return;\r\n const el = document.elementFromPoint(e.clientX, e.clientY);\r\n if (!el || !(el instanceof HTMLElement) || isCanvasUI(el)) return;\r\n\r\n e.preventDefault();\r\n e.stopPropagation();\r\n\r\n const rect = el.getBoundingClientRect();\r\n const source = getSourceFromElement(el);\r\n selectedSource = source;\r\n selectedRect = rect;\r\n\r\n // Draw orange select highlight\r\n overlay.handleElementSelect(el);\r\n\r\n // Show inspector popup with source info\r\n inspector.show(source, rect);\r\n inspector.pin();\r\n\r\n // Add selection info to chat\r\n const label = source.file\r\n ? source.componentName + ' — ' + source.file + ':' + source.line\r\n : '<' + source.componentName + '>' + (source.className ? '.' + source.className.split(' ')[0] : '');\r\n chat.addMessage({ role: 'system', content: '선택: ' + label });\r\n }, true);\r\n\r\n // ---- Box mode: drag red rectangle ----\r\n let boxDragging = false;\r\n document.addEventListener('mousedown', (e) => {\r\n if (!canvasActive || overlay.getMode() !== 'box') return;\r\n e.preventDefault();\r\n boxDragging = true;\r\n overlay.boxTool.startDraw(e.clientX, e.clientY);\r\n }, true);\r\n\r\n document.addEventListener('mousemove', (e) => {\r\n if (!boxDragging) return;\r\n const rect = overlay.boxTool.updateDraw(e.clientX, e.clientY);\r\n overlay.clearAnnotations();\r\n overlay.setMode('box');\r\n }, true);\r\n\r\n document.addEventListener('mouseup', (e) => {\r\n if (!boxDragging) return;\r\n boxDragging = false;\r\n const rect = overlay.boxTool.endDraw(e.clientX, e.clientY);\r\n if (rect.width > 5 && rect.height > 5) {\r\n chat.addMessage({ role: 'system', content: '영역 선택: ' + Math.round(rect.width) + 'x' + Math.round(rect.height) + 'px' });\r\n }\r\n }, true);\r\n\r\n // ---- Chat send → WS ----\r\n chat.onMessageSend((message) => {\r\n // Add user message to chat\r\n chat.addMessage({ role: 'user', content: message });\r\n\r\n // Build context with selected element info + current route\r\n const route = window.location.pathname;\r\n const context = selectedSource\r\n ? { source: selectedSource, rect: selectedRect, annotations: overlay.collectAnnotationSet(), route }\r\n : { annotations: overlay.collectAnnotationSet(), route };\r\n\r\n // Send via Vite HMR WebSocket\r\n if (import.meta.hot) {\r\n import.meta.hot.send('canvas:message', JSON.stringify({\r\n type: 'canvas:chat',\r\n payload: { message, context },\r\n }));\r\n }\r\n\r\n // Show pending response\r\n chat.addMessage({ role: 'assistant', content: '...' });\r\n });\r\n\r\n // ---- Receive WS messages ----\r\n if (import.meta.hot) {\r\n import.meta.hot.on('canvas:message', (data) => {\r\n try {\r\n const msg = typeof data === 'string' ? JSON.parse(data) : data;\r\n if (msg.type === 'canvas:stream') {\r\n if (msg.payload.delta) chat.appendStream(msg.payload.delta);\r\n if (msg.payload.done) chat.appendStream(' [완료]');\r\n } else if (msg.type === 'canvas:relay-saved') {\r\n chat.appendStream('저장됨 — 터미널에서 처리하세요');\r\n } else if (msg.type === 'canvas:error') {\r\n chat.appendStream('[오류] ' + (msg.payload.message || 'Unknown error'));\r\n }\r\n } catch (err) {\r\n console.warn('[claude-canvas] WS parse error:', err);\r\n }\r\n });\r\n }\r\n\r\n // ---- Keyboard handler ----\r\n const keyboard = new KeyboardHandler({\r\n onToggleMode: toggleCanvas,\r\n onEscape: deactivateCanvas,\r\n onToolSwitch: (mode) => {\r\n if (!canvasActive) return;\r\n overlay.setMode(mode);\r\n toolbar.setActiveTool(mode);\r\n },\r\n onSend: () => {},\r\n }, { shortcut: '${shortcut}' });\r\n keyboard.mount();\r\n `\r\n}\r\n\r\nexport function claudeCanvas(options: ClaudeCanvasOptions = {}): Plugin {\r\n return {\r\n name: 'vite-plugin-claude-canvas',\r\n apply: 'serve',\r\n\r\n resolveId(id): string | undefined {\r\n if (id === VIRTUAL_MODULE_ID) {\r\n return RESOLVED_VIRTUAL_MODULE_ID\r\n }\r\n return undefined\r\n },\r\n\r\n load(id): string | undefined {\r\n if (id === RESOLVED_VIRTUAL_MODULE_ID) {\r\n return generateClientScript(options)\r\n }\r\n return undefined\r\n },\r\n\r\n transformIndexHtml() {\r\n return {\r\n html: '',\r\n tags: [\r\n {\r\n tag: 'script',\r\n attrs: { type: 'module', src: `/@id/${VIRTUAL_MODULE_ID}` },\r\n injectTo: 'body',\r\n },\r\n ],\r\n }\r\n },\r\n\r\n configureServer: createServerHook(options),\r\n }\r\n}\r\n\r\nexport default claudeCanvas\r\n\r\nexport type { ClaudeCanvasOptions }\r\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,54 +1,52 @@
1
- {
2
- "name": "@claude-canvas/vite-plugin",
3
- "version": "0.2.0",
4
- "description": "Vite plugin for visual annotation → Claude code modification → HMR verification",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
12
- }
13
- },
14
- "files": [
15
- "dist"
16
- ],
17
- "publishConfig": {
18
- "access": "public"
19
- },
20
- "repository": {
21
- "type": "git",
22
- "url": "https://github.com/claude-canvas/claude-canvas.git",
23
- "directory": "packages/vite-plugin"
24
- },
25
- "dependencies": {
26
- "@claude-canvas/core": "0.2.0",
27
- "@claude-canvas/bridge": "0.2.0"
28
- },
29
- "devDependencies": {
30
- "tsup": "^8.4.0",
31
- "vitest": "^3.0.0",
32
- "typescript": "^5.7.0",
33
- "vite": "^6.1.0",
34
- "@types/node": "^22.0.0"
35
- },
36
- "peerDependencies": {
37
- "vite": ">=5.0.0"
38
- },
39
- "keywords": [
40
- "vite",
41
- "vite-plugin",
42
- "claude",
43
- "annotation",
44
- "devtools"
45
- ],
46
- "scripts": {
47
- "build": "tsup",
48
- "test": "vitest run",
49
- "test:watch": "vitest",
50
- "lint": "eslint src/",
51
- "typecheck": "tsc --noEmit",
52
- "clean": "rm -rf dist"
53
- }
54
- }
1
+ {
2
+ "name": "@claude-canvas/vite-plugin",
3
+ "version": "1.0.0",
4
+ "description": "Vite plugin for visual annotation → Claude code modification → HMR verification",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": ["dist"],
15
+ "scripts": {
16
+ "build": "tsup",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "lint": "eslint src/",
20
+ "typecheck": "tsc --noEmit",
21
+ "clean": "rm -rf dist"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/whdudguq/claude-canvas.git",
29
+ "directory": "packages/vite-plugin"
30
+ },
31
+ "dependencies": {
32
+ "@claude-canvas/core": "workspace:*",
33
+ "@claude-canvas/bridge": "workspace:*"
34
+ },
35
+ "devDependencies": {
36
+ "tsup": "^8.4.0",
37
+ "vitest": "^3.0.0",
38
+ "typescript": "^5.7.0",
39
+ "vite": "^6.1.0",
40
+ "@types/node": "^22.0.0"
41
+ },
42
+ "peerDependencies": {
43
+ "vite": ">=5.0.0"
44
+ },
45
+ "keywords": [
46
+ "vite",
47
+ "vite-plugin",
48
+ "claude",
49
+ "annotation",
50
+ "devtools"
51
+ ]
52
+ }