@aprovan/patchwork 0.1.0 → 0.1.1

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 (71) hide show
  1. package/.github/workflows/publish.yml +1 -1
  2. package/.vscode/launch.json +19 -0
  3. package/README.md +24 -0
  4. package/apps/chat/package.json +4 -4
  5. package/apps/chat/vite.config.ts +8 -8
  6. package/docs/specs/directory-sync.md +822 -0
  7. package/docs/specs/patchwork-vscode.md +625 -0
  8. package/package.json +2 -2
  9. package/packages/compiler/package.json +3 -2
  10. package/packages/compiler/src/index.ts +13 -14
  11. package/packages/compiler/src/vfs/backends/http.ts +139 -0
  12. package/packages/compiler/src/vfs/backends/indexeddb.ts +185 -24
  13. package/packages/compiler/src/vfs/backends/memory.ts +166 -0
  14. package/packages/compiler/src/vfs/core/index.ts +26 -0
  15. package/packages/compiler/src/vfs/core/types.ts +93 -0
  16. package/packages/compiler/src/vfs/core/utils.ts +42 -0
  17. package/packages/compiler/src/vfs/core/virtual-fs.ts +120 -0
  18. package/packages/compiler/src/vfs/index.ts +37 -5
  19. package/packages/compiler/src/vfs/project.ts +16 -16
  20. package/packages/compiler/src/vfs/store.ts +183 -19
  21. package/packages/compiler/src/vfs/sync/differ.ts +47 -0
  22. package/packages/compiler/src/vfs/sync/engine.ts +398 -0
  23. package/packages/compiler/src/vfs/sync/index.ts +3 -0
  24. package/packages/compiler/src/vfs/sync/resolver.ts +46 -0
  25. package/packages/compiler/src/vfs/types.ts +1 -8
  26. package/packages/compiler/tsup.config.ts +5 -5
  27. package/packages/editor/package.json +1 -1
  28. package/packages/editor/src/components/CodeBlockExtension.tsx +1 -1
  29. package/packages/editor/src/components/CodePreview.tsx +59 -1
  30. package/packages/editor/src/components/edit/CodeBlockView.tsx +72 -0
  31. package/packages/editor/src/components/edit/EditModal.tsx +169 -28
  32. package/packages/editor/src/components/edit/FileTree.tsx +67 -13
  33. package/packages/editor/src/components/edit/MediaPreview.tsx +106 -0
  34. package/packages/editor/src/components/edit/SaveConfirmDialog.tsx +60 -0
  35. package/packages/editor/src/components/edit/fileTypes.ts +125 -0
  36. package/packages/editor/src/components/edit/index.ts +4 -0
  37. package/packages/editor/src/components/edit/types.ts +3 -0
  38. package/packages/editor/src/components/edit/useEditSession.ts +22 -4
  39. package/packages/editor/src/index.ts +17 -0
  40. package/packages/editor/src/lib/diff.ts +2 -1
  41. package/packages/editor/src/lib/vfs.ts +28 -10
  42. package/packages/editor/tsup.config.ts +10 -5
  43. package/packages/stitchery/package.json +5 -3
  44. package/packages/stitchery/src/server/index.ts +57 -57
  45. package/packages/stitchery/src/server/vfs-routes.ts +246 -56
  46. package/packages/stitchery/tsup.config.ts +5 -5
  47. package/packages/utcp/package.json +3 -2
  48. package/packages/utcp/tsconfig.json +6 -2
  49. package/packages/utcp/tsup.config.ts +6 -6
  50. package/packages/vscode/README.md +31 -0
  51. package/packages/vscode/media/outline.png +0 -0
  52. package/packages/vscode/media/outline.svg +70 -0
  53. package/packages/vscode/media/patchwork.png +0 -0
  54. package/packages/vscode/media/patchwork.svg +72 -0
  55. package/packages/vscode/node_modules/.bin/jiti +17 -0
  56. package/packages/vscode/node_modules/.bin/tsc +17 -0
  57. package/packages/vscode/node_modules/.bin/tsserver +17 -0
  58. package/packages/vscode/node_modules/.bin/tsup +17 -0
  59. package/packages/vscode/node_modules/.bin/tsup-node +17 -0
  60. package/packages/vscode/node_modules/.bin/tsx +17 -0
  61. package/packages/vscode/package.json +136 -0
  62. package/packages/vscode/src/extension.ts +612 -0
  63. package/packages/vscode/src/providers/PatchworkFileSystemProvider.ts +205 -0
  64. package/packages/vscode/src/providers/PatchworkTreeProvider.ts +177 -0
  65. package/packages/vscode/src/providers/PreviewPanelProvider.ts +536 -0
  66. package/packages/vscode/src/services/EditService.ts +24 -0
  67. package/packages/vscode/src/services/EmbeddedStitchery.ts +82 -0
  68. package/packages/vscode/tsconfig.json +13 -0
  69. package/packages/vscode/tsup.config.ts +11 -0
  70. package/packages/compiler/src/vfs/backends/local-fs.ts +0 -41
  71. package/packages/compiler/src/vfs/backends/s3.ts +0 -60
@@ -0,0 +1,625 @@
1
+ # Patchwork Viewer VS Code
2
+
3
+ Implement a VS Code extension for viewing Patchwork projects. This should be a fairly simple wrapper around the existing Patchwork file viewer/editor/render, with a few differences:
4
+
5
+ 1. The file selector widget shouldn't be shown for Patchwork. Instead, the extension should render a file tree using VS Code's native components. When a file is selected (opened), it should communicate this to Patchwork
6
+ 2. When a file stored in a Patchwork project is opened, it should operate like a normal VS Code file, opening as an open file rather than in the Patchwork tree.
7
+ 3. The preview renderer should show the Patchwork compilation/renderer, if supported. Defer to VS Code's in-built editor/preview otherwise (e.g. let VS Code's Markdown preview show)
8
+
9
+ Keep the same LLM-driven editing functionality and editor widget that Patchwork provides for browser-based widgets. The chat-based method and history editing should be available for all files, too.
10
+
11
+ We'll need a way to connect to an LLM provider. Provide a method for connecting to the GitHub Code Copilot proxy that we already use (i.e. let me run the Copilot proxy and give the extension the option to point to it. )
12
+
13
+ Where needed, prefer to add functionality to the other Patchwork packages/components rather than bundling into the VS Code extension (e.g. disabling the file tree viewer should be a Patchwork component property).
14
+
15
+ ---
16
+
17
+ ## Technical Overview
18
+
19
+ ### Existing Patchwork Architecture
20
+
21
+ The Patchwork monorepo contains these relevant packages:
22
+
23
+ | Package | Purpose |
24
+ |---------|---------|
25
+ | `@aprovan/patchwork` | Core services/types, service proxy system, context providers |
26
+ | `@aprovan/patchwork-editor` | React components: `MarkdownEditor`, `CodePreview`, `FileTree`, `EditModal`, `EditHistory`, `useEditSession` |
27
+ | `@aprovan/bobbin` | Visual element selection/editing with design tokens and change tracking |
28
+ | `@aprovan/patchwork-compiler` | JSX→ESM compilation, image loading, DOM mounting (`createCompiler`, `mount`, `unmount`) |
29
+ | `@aprovan/patchwork-stitchery` | LLM server (Vercel AI SDK), MCP client integration, service registry, edit/chat prompts |
30
+ | `@aprovan/patchwork-utcp` | Backend service integration through UTCP protocol |
31
+ | `@aprovan/patchwork-vscode` | **Placeholder** - only contains package.json stub |
32
+
33
+ ### Key Existing Components
34
+
35
+ **Editor Package (`@aprovan/patchwork-editor`)**:
36
+ - `FileTree.tsx` - React file tree component with `VirtualFile[]` input, supports file selection and media upload
37
+ - `EditModal.tsx` - Full editing UI with code view, preview, edit history, and LLM edit submission
38
+ - `useEditSession.ts` - React hook managing edit state, history, API calls to `/api/edit`
39
+ - `CodePreview.tsx` - Live compilation preview with save-to-VFS capability
40
+ - `api.ts` - `sendEditRequest()` for LLM-powered code edits
41
+
42
+ **Compiler Package (`@aprovan/patchwork-compiler`)**:
43
+ - `createCompiler(options)` - Returns a `Compiler` instance
44
+ - `compiler.compile(source, manifest, options)` - Compiles JSX/TSX to widget
45
+ - `compiler.mount(widget, { target, mode })` - Mounts to DOM element
46
+ - `compiler.unmount(mounted)` - Cleanup
47
+ - Supports browser platform with image packages (`@aprovan/patchwork-image-shadcn`)
48
+
49
+ **Stitchery Package (`@aprovan/patchwork-stitchery`)**:
50
+ - `createStitcheryServer(config)` - HTTP server with `/api/chat`, `/api/edit`, `/api/services` routes
51
+ - Uses `@ai-sdk/openai-compatible` provider pointed at Copilot proxy
52
+ - `ServiceRegistry` for tool discovery and registration
53
+ - `PATCHWORK_PROMPT`, `EDIT_PROMPT` - System prompts for LLM
54
+
55
+ **Copilot Proxy (`@aprovan/copilot-proxy`)**:
56
+ - Standalone package providing OpenAI-compatible API using GitHub Copilot
57
+ - `copilot-proxy serve --port 3000` starts the proxy server
58
+ - Device flow authentication via `copilot-proxy connect`
59
+ - Already used by stitchery server for LLM access
60
+
61
+ ---
62
+
63
+ ## Implementation Plan
64
+
65
+ ### Phase 1: Extension Foundation
66
+
67
+ #### 1.1 Project Setup (`packages/vscode/`)
68
+
69
+ ```
70
+ packages/vscode/
71
+ ├── package.json # VS Code extension manifest
72
+ ├── tsconfig.json
73
+ ├── tsup.config.ts # Bundle for VS Code
74
+ ├── src/
75
+ │ ├── extension.ts # activate/deactivate
76
+ │ ├── commands/ # Command handlers
77
+ │ ├── providers/ # Tree, Editor, Preview providers
78
+ │ ├── webview/ # Webview panel logic
79
+ │ └── config.ts # Settings management
80
+ └── media/
81
+ └── webview/ # Bundled React app for webviews
82
+ ```
83
+
84
+ **package.json contributions**:
85
+ ```json
86
+ {
87
+ "activationEvents": ["onView:patchworkExplorer", "onCommand:patchwork.*"],
88
+ "contributes": {
89
+ "viewsContainers": {
90
+ "activitybar": [{
91
+ "id": "patchwork",
92
+ "title": "Patchwork",
93
+ "icon": "media/icon.svg"
94
+ }]
95
+ },
96
+ "views": {
97
+ "patchwork": [{
98
+ "id": "patchworkExplorer",
99
+ "name": "Projects"
100
+ }]
101
+ },
102
+ "commands": [
103
+ { "command": "patchwork.openProject", "title": "Open Patchwork Project" },
104
+ { "command": "patchwork.newProject", "title": "New Patchwork Project" },
105
+ { "command": "patchwork.showPreview", "title": "Show Patchwork Preview" },
106
+ { "command": "patchwork.editWithAI", "title": "Edit with AI" }
107
+ ],
108
+ "configuration": {
109
+ "title": "Patchwork",
110
+ "properties": {
111
+ "patchwork.copilotProxyUrl": {
112
+ "type": "string",
113
+ "default": "http://localhost:3000",
114
+ "description": "URL of the GitHub Copilot proxy server"
115
+ },
116
+ "patchwork.imagePackage": {
117
+ "type": "string",
118
+ "default": "@aprovan/patchwork-image-shadcn",
119
+ "description": "Default image package for widget compilation"
120
+ },
121
+ "patchwork.vfsDir": {
122
+ "type": "string",
123
+ "default": "",
124
+ "description": "Directory for virtual file system storage (defaults to workspace)"
125
+ }
126
+ }
127
+ },
128
+ "menus": {
129
+ "editor/title": [{
130
+ "command": "patchwork.showPreview",
131
+ "when": "resourceExtname =~ /\\.(tsx|jsx)$/",
132
+ "group": "navigation"
133
+ }]
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ #### 1.2 Patchwork Project Tree Provider
140
+
141
+ Replace the React `FileTree` with VS Code's native `TreeDataProvider`:
142
+
143
+ ```typescript
144
+ // src/providers/PatchworkTreeProvider.ts
145
+ import * as vscode from 'vscode';
146
+ import type { VirtualProject, VirtualFile } from '@aprovan/patchwork-compiler';
147
+
148
+ export class PatchworkTreeProvider implements vscode.TreeDataProvider<PatchworkTreeItem> {
149
+ private _onDidChangeTreeData = new vscode.EventEmitter<PatchworkTreeItem | undefined>();
150
+ readonly onDidChangeTreeData = this._onDidChangeTreeData.event;
151
+
152
+ private projects: Map<string, VirtualProject> = new Map();
153
+
154
+ setProject(id: string, project: VirtualProject): void {
155
+ this.projects.set(id, project);
156
+ this._onDidChangeTreeData.fire(undefined);
157
+ }
158
+
159
+ getTreeItem(element: PatchworkTreeItem): vscode.TreeItem { /* ... */ }
160
+ getChildren(element?: PatchworkTreeItem): Thenable<PatchworkTreeItem[]> { /* ... */ }
161
+ }
162
+ ```
163
+
164
+ **File selection behavior**:
165
+ - Clicking a file in the tree opens it in VS Code's standard editor
166
+ - The extension listens for `vscode.window.onDidChangeActiveTextEditor` to sync state
167
+ - Preview panel updates when a compilable file is selected
168
+
169
+ #### 1.3 Webview Preview Panel
170
+
171
+ Create a webview that hosts the compiled widget preview:
172
+
173
+ ```typescript
174
+ // src/providers/PreviewPanelProvider.ts
175
+ export class PreviewPanelProvider {
176
+ private panel: vscode.WebviewPanel | undefined;
177
+
178
+ async showPreview(document: vscode.TextDocument): Promise<void> {
179
+ // Create or reveal panel
180
+ // Send code to webview for compilation via postMessage
181
+ }
182
+
183
+ private getWebviewContent(): string {
184
+ // Returns HTML that loads the bundled React preview app
185
+ // Includes @aprovan/patchwork-compiler and image package
186
+ }
187
+ }
188
+ ```
189
+
190
+ **Webview React App** (`media/webview/`):
191
+ - Minimal React app using `createCompiler()` and `mount()`
192
+ - Listens for `window.addEventListener('message', ...)` to receive code updates
193
+ - Reports compilation errors back to extension
194
+
195
+ ### Phase 2: Package Modifications
196
+
197
+ #### 2.1 Editor Package Changes
198
+
199
+ **Add `hideFileTree` prop to `EditModal`**:
200
+
201
+ ```typescript
202
+ // @aprovan/patchwork-editor - EditModal.tsx
203
+ export interface EditModalProps extends UseEditSessionOptions {
204
+ // ... existing props
205
+ hideFileTree?: boolean; // NEW: Hide built-in file tree for VS Code integration
206
+ }
207
+ ```
208
+
209
+ **Export standalone edit components**:
210
+ - `EditHistoryPanel` - Just the history list
211
+ - `EditInputBar` - Just the prompt input with submit
212
+ - `BobbinOverlay` - Visual selection without modal wrapper
213
+
214
+ #### 2.2 Compiler Package Changes
215
+
216
+ **Headless compilation mode**:
217
+
218
+ ```typescript
219
+ // @aprovan/patchwork-compiler
220
+ export interface CompileOptions {
221
+ // ... existing
222
+ headless?: boolean; // Return module without DOM dependencies for Node.js
223
+ }
224
+
225
+ export interface HeadlessCompileResult {
226
+ code: string; // Compiled ESM
227
+ css?: string; // Extracted styles
228
+ imports: string[]; // External dependencies
229
+ }
230
+ ```
231
+
232
+ This enables the extension to:
233
+ 1. Pre-compile code in the extension host
234
+ 2. Send compiled bundle to webview (faster reload)
235
+ 3. Surface compile errors in VS Code's Problems panel
236
+
237
+ #### 2.3 Create `@aprovan/patchwork-vscode-common`
238
+
239
+ Shared types and utilities for extension-webview communication:
240
+
241
+ ```typescript
242
+ // packages/vscode-common/src/index.ts
243
+ export interface ExtensionToWebviewMessage {
244
+ type: 'compile' | 'updateFile' | 'setServices' | 'setColorScheme' | 'serviceResult';
245
+ payload: unknown;
246
+ }
247
+
248
+ export interface WebviewToExtensionMessage {
249
+ type: 'ready' | 'compileError' | 'compileSuccess' | 'editRequest' | 'saveRequest' | 'serviceCall';
250
+ payload: unknown;
251
+ }
252
+
253
+ export interface PatchworkProjectState {
254
+ projectId: string;
255
+ activeFile: string;
256
+ files: Array<{ path: string; content: string; encoding: 'utf8' | 'base64' }>;
257
+ services: string[];
258
+ colorScheme: 'light' | 'dark';
259
+ }
260
+
261
+ export interface ServiceCallMessage {
262
+ id: string; // Correlation ID for response
263
+ namespace: string; // e.g., 'github'
264
+ procedure: string; // e.g., 'repos_list_for_user'
265
+ args: Record<string, unknown>;
266
+ }
267
+
268
+ export interface ServiceResultMessage {
269
+ id: string;
270
+ result?: unknown;
271
+ error?: string;
272
+ }
273
+ ```
274
+
275
+ ### Phase 3: LLM Integration
276
+
277
+ #### 3.1 Copilot Proxy Configuration
278
+
279
+ **Settings UI**:
280
+ - `patchwork.copilotProxyUrl` - URL to running proxy
281
+ - Status bar item showing connection state
282
+ - Command `patchwork.testConnection` to verify proxy is reachable
283
+
284
+ **Connection flow**:
285
+ 1. Extension checks proxy health on activation: `GET {proxyUrl}/health`
286
+ 2. If unreachable, show notification with "Start Proxy" action
287
+ 3. "Start Proxy" opens terminal and runs `npx @aprovan/copilot-proxy serve`
288
+
289
+ #### 3.2 Edit API Integration
290
+
291
+ **Direct API calls from extension** (no separate stitchery server needed):
292
+
293
+ ```typescript
294
+ // src/services/EditService.ts
295
+ import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
296
+ import { streamText } from 'ai';
297
+ import { EDIT_PROMPT } from '@aprovan/patchwork-stitchery';
298
+
299
+ export class EditService {
300
+ constructor(private copilotProxyUrl: string) {}
301
+
302
+ async *streamEdit(code: string, prompt: string): AsyncGenerator<string> {
303
+ const provider = createOpenAICompatible({
304
+ name: 'copilot-proxy',
305
+ baseURL: this.copilotProxyUrl,
306
+ });
307
+
308
+ const result = streamText({
309
+ model: provider('claude-sonnet-4'),
310
+ system: EDIT_PROMPT,
311
+ messages: [{ role: 'user', content: `Code:\n${code}\n\nEdit: ${prompt}` }],
312
+ });
313
+
314
+ for await (const chunk of result.textStream) {
315
+ yield chunk;
316
+ }
317
+ }
318
+ }
319
+ ```
320
+
321
+ #### 3.3 Embedded Stitchery for Services
322
+
323
+ Rather than requiring a separate stitchery server process, embed the service registry directly in the extension host:
324
+
325
+ ```typescript
326
+ // src/services/EmbeddedStitchery.ts
327
+ import { ServiceRegistry } from '@aprovan/patchwork-stitchery';
328
+ import { createUtcpBackend } from '@aprovan/patchwork-utcp';
329
+ import { createMCPClient } from '@ai-sdk/mcp';
330
+ import type { ServiceCallMessage, ServiceResultMessage } from '@aprovan/patchwork-vscode-common';
331
+
332
+ export class EmbeddedStitchery {
333
+ private registry: ServiceRegistry;
334
+
335
+ async initialize(utcpConfig?: object, mcpServers?: McpServerConfig[]): Promise<void> {
336
+ this.registry = new ServiceRegistry();
337
+
338
+ // Register UTCP services if configured
339
+ if (utcpConfig) {
340
+ const { toolInfos } = await createUtcpBackend(utcpConfig);
341
+ for (const tool of toolInfos) {
342
+ this.registry.registerTool(tool);
343
+ }
344
+ }
345
+
346
+ // Register MCP servers if configured
347
+ for (const server of mcpServers ?? []) {
348
+ const client = await createMCPClient({ /* ... */ });
349
+ this.registry.registerTools(await client.tools(), server.name);
350
+ }
351
+ }
352
+
353
+ async handleServiceCall(msg: ServiceCallMessage): Promise<ServiceResultMessage> {
354
+ try {
355
+ const result = await this.registry.callTool(msg.namespace, msg.procedure, msg.args);
356
+ return { id: msg.id, result };
357
+ } catch (err) {
358
+ return { id: msg.id, error: err instanceof Error ? err.message : 'Unknown error' };
359
+ }
360
+ }
361
+
362
+ getNamespaces(): string[] {
363
+ return this.registry.getNamespaces();
364
+ }
365
+ }
366
+ ```
367
+
368
+ **Service call flow**:
369
+ 1. Widget calls `services.github.repos_list_for_user({ username: 'foo' })`
370
+ 2. Webview intercepts via injected service proxy, sends `postMessage({ type: 'serviceCall', payload: {...} })`
371
+ 3. Extension host receives, routes to `EmbeddedStitchery.handleServiceCall()`
372
+ 4. Result sent back via `postMessage({ type: 'serviceResult', payload: {...} })`
373
+ 5. Webview resolves the original promise
374
+
375
+ #### 3.4 Edit UI in Webview
376
+
377
+ The webview includes a minimal edit interface:
378
+ - Input field at bottom for edit prompts
379
+ - Streaming response display
380
+ - Diff preview before applying
381
+ - History panel (collapsible)
382
+
383
+ This reuses logic from `useEditSession` but adapted for webview messaging.
384
+
385
+ ### Phase 4: File System Integration
386
+
387
+ #### 4.1 Virtual File System Provider
388
+
389
+ Implement `FileSystemProvider` for `patchwork://` URI scheme:
390
+
391
+ ```typescript
392
+ // src/providers/PatchworkFileSystemProvider.ts
393
+ export class PatchworkFileSystemProvider implements vscode.FileSystemProvider {
394
+ private projects: Map<string, VirtualProject> = new Map();
395
+
396
+ // Maps patchwork://projectId/path/to/file.tsx to VirtualFile
397
+ readFile(uri: vscode.Uri): Uint8Array { /* ... */ }
398
+ writeFile(uri: vscode.Uri, content: Uint8Array): void { /* ... */ }
399
+
400
+ // Sync changes back to in-memory project
401
+ }
402
+ ```
403
+
404
+ **URI format**: `patchwork://project-id/src/components/Button.tsx`
405
+
406
+ #### 4.2 Document Sync
407
+
408
+ Keep VS Code editor and Patchwork project in sync:
409
+
410
+ ```typescript
411
+ // On text document change
412
+ vscode.workspace.onDidChangeTextDocument((e) => {
413
+ if (e.document.uri.scheme === 'patchwork') {
414
+ const { projectId, filePath } = parseUri(e.document.uri);
415
+ this.updateProjectFile(projectId, filePath, e.document.getText());
416
+ this.previewPanel.refresh();
417
+ }
418
+ });
419
+ ```
420
+
421
+ #### 4.3 Save to Disk
422
+
423
+ Command to export Patchwork project to real filesystem:
424
+
425
+ ```typescript
426
+ // Command: patchwork.exportProject
427
+ async function exportProject(projectId: string, targetDir: vscode.Uri): Promise<void> {
428
+ const project = this.getProject(projectId);
429
+ for (const [path, file] of project.files) {
430
+ const targetPath = vscode.Uri.joinPath(targetDir, path);
431
+ await vscode.workspace.fs.writeFile(targetPath, Buffer.from(file.content));
432
+ }
433
+ }
434
+ ```
435
+
436
+ ### Phase 5: Preview & Compilation
437
+
438
+ #### 5.1 Preview Panel Architecture
439
+
440
+ Single shared preview panel that follows the active editor:
441
+
442
+ ```
443
+ ┌─────────────────────────────────────────────────────────────┐
444
+ │ VS Code Extension Host │
445
+ │ ┌─────────────────────────────────────────────────────────┤
446
+ │ │ PreviewPanelProvider (singleton) │
447
+ │ │ - Single WebviewPanel, follows active editor │
448
+ │ │ - Sends code updates via postMessage │
449
+ │ │ - Receives compile errors, edit requests │
450
+ │ ├─────────────────────────────────────────────────────────┤
451
+ │ │ EmbeddedStitchery │
452
+ │ │ - ServiceRegistry for UTCP/MCP tools │
453
+ │ │ - Routes webview service calls to backends │
454
+ │ │ - EditService for LLM-powered code edits │
455
+ │ └─────────────────────────────────────────────────────────┤
456
+ │ │ postMessage │
457
+ ├───────────────────────────┼─────────────────────────────────┤
458
+ │ Webview (sandboxed) ▼ │
459
+ │ ┌─────────────────────────────────────────────────────────┤
460
+ │ │ React App (pre-bundled with esbuild) │
461
+ │ │ - createCompiler() from @aprovan/patchwork-compiler │
462
+ │ │ - Renders compiled widget │
463
+ │ │ - Service calls → postMessage → extension host │
464
+ │ │ - EditInputBar for AI edits │
465
+ │ │ - EditHistory panel │
466
+ │ │ - Respects colorScheme: 'light' | 'dark' │
467
+ │ └─────────────────────────────────────────────────────────┤
468
+ └─────────────────────────────────────────────────────────────┘
469
+ ```
470
+
471
+ **Active editor tracking**:
472
+ ```typescript
473
+ // PreviewPanelProvider.ts
474
+ vscode.window.onDidChangeActiveTextEditor((editor) => {
475
+ if (editor && this.isPreviewableFile(editor.document.uri)) {
476
+ this.updatePreview(editor.document);
477
+ }
478
+ });
479
+
480
+ vscode.window.onDidChangeActiveColorTheme((theme) => {
481
+ const colorScheme = theme.kind === vscode.ColorThemeKind.Dark ? 'dark' : 'light';
482
+ this.panel?.webview.postMessage({ type: 'setColorScheme', payload: colorScheme });
483
+ });
484
+ ```
485
+
486
+ #### 5.2 Supported File Types
487
+
488
+ | Extension | Behavior |
489
+ |-----------|----------|
490
+ | `.tsx`, `.jsx` | Compile with patchwork-compiler, show in preview panel |
491
+ | `.ts`, `.js` | Open in VS Code editor, no preview |
492
+ | `.md` | Open in VS Code editor, use VS Code's markdown preview |
493
+ | `.css`, `.json` | Open in VS Code editor |
494
+ | Images | Show in preview panel using `MediaPreview` component |
495
+
496
+ #### 5.3 Error Handling
497
+
498
+ Compilation errors surface in multiple places:
499
+ 1. **Preview panel**: Inline error display with stack trace
500
+ 2. **Problems panel**: `vscode.languages.createDiagnosticCollection('patchwork')`
501
+ 3. **Editor decorations**: Squiggles on error lines
502
+
503
+ ### Phase 6: Polish & UX
504
+
505
+ #### 6.1 Status Bar
506
+
507
+ ```typescript
508
+ const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
509
+ statusBar.text = '$(plug) Patchwork';
510
+ statusBar.tooltip = 'Copilot Proxy: Connected';
511
+ statusBar.command = 'patchwork.showConnectionStatus';
512
+ ```
513
+
514
+ States:
515
+ - `$(plug)` Connected (green)
516
+ - `$(debug-disconnect)` Disconnected (red)
517
+ - `$(sync~spin)` Connecting...
518
+
519
+ #### 6.2 Code Actions
520
+
521
+ Register quick fixes for common scenarios:
522
+
523
+ ```typescript
524
+ vscode.languages.registerCodeActionsProvider(['typescriptreact', 'javascriptreact'], {
525
+ provideCodeActions(document, range, context) {
526
+ return [
527
+ {
528
+ title: 'Edit with Patchwork AI',
529
+ command: 'patchwork.editWithAI',
530
+ arguments: [document.uri, range]
531
+ }
532
+ ];
533
+ }
534
+ });
535
+ ```
536
+
537
+ #### 6.3 Keyboard Shortcuts
538
+
539
+ | Shortcut | Command |
540
+ |----------|---------|
541
+ | `Cmd+Shift+Alt+P` | Show Patchwork Preview |
542
+ | `Cmd+Shift+Alt+E` | Edit with AI (selected code) |
543
+ | `Cmd+Shift+Alt+H` | Show Edit History |
544
+
545
+ ---
546
+
547
+ ## Package Dependencies
548
+
549
+ ### `@aprovan/patchwork-vscode`
550
+
551
+ ```json
552
+ {
553
+ "dependencies": {
554
+ "@aprovan/patchwork": "workspace:*",
555
+ "@aprovan/patchwork-stitchery": "workspace:*",
556
+ "@aprovan/patchwork-utcp": "workspace:*",
557
+ "@ai-sdk/openai-compatible": "^0.1.0",
558
+ "@ai-sdk/mcp": "^0.1.0",
559
+ "ai": "^4.0.0"
560
+ },
561
+ "devDependencies": {
562
+ "@types/vscode": "^1.85.0",
563
+ "@vscode/vsce": "^2.22.0",
564
+ "esbuild": "^0.20.0"
565
+ }
566
+ }
567
+ ```
568
+
569
+ ### Webview Bundle
570
+
571
+ Pre-bundled React app (esbuild) including:
572
+ - `@aprovan/patchwork-compiler`
573
+ - `@aprovan/patchwork-editor` (EditHistory, EditInputBar components)
574
+ - `@aprovan/bobbin` (for visual editing)
575
+ - `@aprovan/patchwork-image-shadcn` (or configurable)
576
+ - Service proxy bridge that routes `services.*` calls through `postMessage` to extension host
577
+ - Light/dark mode support via CSS class toggle (`[data-theme="dark"]`)
578
+
579
+ ---
580
+
581
+ ## Development Milestones
582
+
583
+ ### Milestone 1: Basic Extension (1-2 weeks)
584
+ - [x] Extension scaffold with activation
585
+ - [x] TreeDataProvider showing hardcoded project
586
+ - [x] Basic webview panel with "Hello World"
587
+ - [x] Configuration for Copilot proxy URL
588
+
589
+ ### Milestone 2: Preview System (1-2 weeks)
590
+ - [x] Integrate patchwork-compiler in webview
591
+ - [x] Live preview of TSX files
592
+ - [x] Error display in preview and Problems panel
593
+ - [x] File selection syncs with preview
594
+
595
+ ### Milestone 3: AI Editing (1-2 weeks)
596
+ - [x] Edit input in webview
597
+ - [x] Direct calls to Copilot proxy from extension
598
+ - [x] Streaming response display
599
+ - [x] Apply edits to document
600
+ - [x] Edit history panel
601
+ - [x] EmbeddedStitchery for service registration (UTCP/MCP)
602
+
603
+ ### Milestone 4: File System (1 week)
604
+ - [x] PatchworkFileSystemProvider implementation
605
+ - [x] Persist patchwork:// saves to disk
606
+ - [x] Save/export to disk
607
+ - [x] Sync between editor and preview
608
+
609
+ ### Milestone 5: Polish (1 week)
610
+ - [x] Status bar connection indicator
611
+ - [x] Code actions integration
612
+ - [x] Keyboard shortcuts
613
+ - [x] Documentation and README
614
+
615
+ ---
616
+
617
+ ## Design Decisions
618
+
619
+ 1. **Webview bundling strategy**: Pre-bundle the webview with esbuild for offline capability and faster load. Fall back to CDN only if bundling proves overly complex.
620
+
621
+ 2. **Multiple preview panels**: Single shared preview panel with file indicator that follows the active editor. No per-file preview panels.
622
+
623
+ 3. **Service registration**: Embed Stitchery directly in the extension host to handle service calls. The webview communicates with the extension host via postMessage, which routes to the embedded Stitchery for UTCP/MCP service execution. Avoids requiring a separate background server process.
624
+
625
+ 4. **Theme synchronization**: Minimal theming—only respect VS Code's dark/light mode preference. Pass `colorScheme: 'dark' | 'light'` to the webview based on `vscode.window.activeColorTheme.kind`. No CSS variable mapping.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aprovan/patchwork",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Platform for building generative UI experiences",
5
5
  "type": "module",
6
6
  "devDependencies": {
@@ -23,7 +23,7 @@
23
23
  "node": ">=20.0.0"
24
24
  },
25
25
  "scripts": {
26
- "build": "turbo run build && ./scripts/sync-local.sh",
26
+ "build": "turbo run build",
27
27
  "check-types": "turbo run check-types",
28
28
  "dev": "turbo run dev --parallel",
29
29
  "lint": "eslint \"**/*.ts?(x)\"",
@@ -3,7 +3,7 @@
3
3
  "version": "0.1.0",
4
4
  "description": "Patchwork compiler - JSX→ESM compilation, image loading, DOM mounting",
5
5
  "type": "module",
6
- "main": "./dist/index.js",
6
+ "main": "./dist/index.cjs",
7
7
  "types": "./dist/index.d.ts",
8
8
  "files": [
9
9
  "dist"
@@ -14,7 +14,8 @@
14
14
  "exports": {
15
15
  ".": {
16
16
  "types": "./dist/index.d.ts",
17
- "import": "./dist/index.js"
17
+ "import": "./dist/index.js",
18
+ "require": "./dist/index.cjs"
18
19
  }
19
20
  },
20
21
  "scripts": {