paneful 0.9.13 → 0.9.14

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/README.md CHANGED
@@ -93,6 +93,15 @@ paneful --install-app
93
93
 
94
94
  A folder picker dialog lets you choose the install location (defaults to `/Applications`). The app launches Paneful in a native WebKit window — no browser tab needed. Updating via `paneful update` automatically rebuilds the `.app` in place.
95
95
 
96
+ ### VS Code Extension
97
+
98
+ Install the [Paneful extension](https://marketplace.visualstudio.com/items?itemName=kplates.paneful-vscode) from the VS Code Marketplace. Works with VS Code, Cursor, and other VS Code-based editors.
99
+
100
+ **Commands** (via Command Palette):
101
+
102
+ - **Paneful: Spawn project** — Creates or activates a Paneful project for the current workspace folder.
103
+ - **Paneful: Send open file paths** — Sends all open editor file paths to the focused Paneful terminal.
104
+
96
105
  ### Updating
97
106
 
98
107
  ```bash
@@ -3,13 +3,13 @@ import { join } from 'node:path';
3
3
  const INBOX_FILE = 'inbox.json';
4
4
  export class InboxMonitor {
5
5
  dir;
6
- onChange;
6
+ handlers;
7
7
  watcher = null;
8
8
  destroyed = false;
9
9
  debounceTimer = null;
10
- constructor(dataDir, onChange) {
10
+ constructor(dataDir, handlers) {
11
11
  this.dir = dataDir;
12
- this.onChange = onChange;
12
+ this.handlers = handlers;
13
13
  }
14
14
  resume() {
15
15
  if (this.destroyed || this.watcher)
@@ -65,10 +65,20 @@ export class InboxMonitor {
65
65
  }
66
66
  catch { }
67
67
  const data = JSON.parse(raw);
68
- if (data && Array.isArray(data.files) && data.files.length > 0) {
69
- const files = data.files.filter((f) => typeof f === 'string');
70
- if (files.length > 0) {
71
- this.onChange(files);
68
+ if (!data || typeof data !== 'object')
69
+ return;
70
+ if (data.action === 'spawn') {
71
+ if (typeof data.cwd === 'string' && typeof data.name === 'string') {
72
+ this.handlers.onSpawn?.(data.cwd, data.name);
73
+ }
74
+ }
75
+ else if (data.action === 'paste' || Array.isArray(data.files)) {
76
+ // 'paste' action, or backwards-compat: bare { files: [...] }
77
+ if (Array.isArray(data.files) && data.files.length > 0) {
78
+ const files = data.files.filter((f) => typeof f === 'string');
79
+ if (files.length > 0) {
80
+ this.handlers.onPaste?.(files);
81
+ }
72
82
  }
73
83
  }
74
84
  }
@@ -1,4 +1,5 @@
1
1
  import { WebSocket, WebSocketServer } from 'ws';
2
+ import { v4 as uuidv4 } from 'uuid';
2
3
  import { newProject } from './project-store.js';
3
4
  import { PortMonitor } from './port-monitor.js';
4
5
  import { ClaudeMonitor } from './claude-monitor.js';
@@ -35,8 +36,18 @@ export class WsHandler {
35
36
  }, (needsAccessibility) => {
36
37
  this.send({ type: 'editor:status', needsAccessibility });
37
38
  });
38
- this.inboxMonitor = new InboxMonitor(dataDir, (files) => {
39
- this.send({ type: 'inbox:paste', files });
39
+ this.inboxMonitor = new InboxMonitor(dataDir, {
40
+ onPaste: (files) => {
41
+ this.send({ type: 'inbox:paste', files });
42
+ },
43
+ onSpawn: (cwd, name) => {
44
+ const existing = this.projectStore.findByCwd(cwd);
45
+ const id = existing?.id ?? uuidv4();
46
+ if (!existing) {
47
+ this.projectStore.create(newProject(id, name, cwd));
48
+ }
49
+ this.send({ type: 'project:spawned', projectId: id, name, cwd });
50
+ },
40
51
  });
41
52
  this.wss = new WebSocketServer({ noServer: true });
42
53
  server.on('upgrade', (req, socket, head) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paneful",
3
- "version": "0.9.13",
3
+ "version": "0.9.14",
4
4
  "description": "A fast, GPU-accelerated terminal multiplexer in your browser or as a native macOS app. Split panes, organize projects, sync with your editor, detect AI agents.",
5
5
  "type": "module",
6
6
  "bin": {