@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 +220 -51
- package/dist/index.js.map +1 -1
- package/package.json +52 -54
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
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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:
|
|
104
|
-
payload: {
|
|
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/
|
|
124
|
-
|
|
125
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
162
|
-
|
|
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
|
|
310
|
+
// ---- Keyboard handler ----
|
|
167
311
|
const keyboard = new KeyboardHandler({
|
|
168
|
-
onToggleMode:
|
|
169
|
-
onEscape:
|
|
170
|
-
onToolSwitch: (mode) => {
|
|
171
|
-
|
|
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
|
-
|
|
183
|
-
|
|
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.
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
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
|
+
}
|