paneful 0.6.1 → 0.6.3
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/server/index.js +41 -55
- package/dist/server/ipc.js +1 -1
- package/dist/server/project-store.js +7 -0
- package/dist/web/assets/index-CMxpGF4L.js +349 -0
- package/dist/web/assets/{index-BzkRN-9o.css → index-Dbp11YgF.css} +1 -1
- package/dist/web/index.html +8 -2
- package/package.json +1 -1
- package/dist/web/assets/index-Dl99eb4x.js +0 -335
package/dist/server/index.js
CHANGED
|
@@ -219,79 +219,65 @@ function startServer(devMode, port) {
|
|
|
219
219
|
res.json({ valid: false });
|
|
220
220
|
}
|
|
221
221
|
});
|
|
222
|
-
// Active editor detection —
|
|
222
|
+
// Active editor detection — single AppleScript gets frontmost app + window title
|
|
223
223
|
const editorPatterns = ['cursor', 'code', 'vscode', 'visual studio code', 'zed', 'windsurf'];
|
|
224
224
|
let editorCache = { projectName: null };
|
|
225
|
+
const editorScript = `
|
|
226
|
+
tell application "System Events"
|
|
227
|
+
set frontApp to name of first application process whose frontmost is true
|
|
228
|
+
set winTitle to ""
|
|
229
|
+
tell process frontApp
|
|
230
|
+
if exists front window then
|
|
231
|
+
set winTitle to name of front window
|
|
232
|
+
end if
|
|
233
|
+
end tell
|
|
234
|
+
return frontApp & linefeed & winTitle
|
|
235
|
+
end tell
|
|
236
|
+
`;
|
|
225
237
|
function pollActiveEditor() {
|
|
226
238
|
if (process.platform !== 'darwin')
|
|
227
239
|
return;
|
|
228
|
-
|
|
229
|
-
tell application "System Events"
|
|
230
|
-
set procNames to name of every process whose background only is false
|
|
231
|
-
set output to ""
|
|
232
|
-
repeat with p in procNames
|
|
233
|
-
set output to output & p & linefeed
|
|
234
|
-
end repeat
|
|
235
|
-
return output
|
|
236
|
-
end tell
|
|
237
|
-
`;
|
|
238
|
-
execFile('osascript', ['-e', findScript], { timeout: 2000 }, (err, stdout, stderr) => {
|
|
240
|
+
execFile('osascript', ['-e', editorScript], { timeout: 2000 }, (err, stdout, stderr) => {
|
|
239
241
|
if (err) {
|
|
240
242
|
const needsAccess = stderr?.includes('not allowed assistive access') || stderr?.includes('1719');
|
|
241
243
|
editorCache = { projectName: null, needsAccessibility: needsAccess || undefined };
|
|
242
244
|
return;
|
|
243
245
|
}
|
|
244
|
-
const
|
|
245
|
-
const
|
|
246
|
-
|
|
246
|
+
const lines = stdout.trim().split('\n');
|
|
247
|
+
const appName = (lines[0] || '').trim();
|
|
248
|
+
const title = (lines[1] || '').trim();
|
|
249
|
+
const isEditor = editorPatterns.some((pat) => appName.toLowerCase().includes(pat));
|
|
250
|
+
if (!isEditor || !title) {
|
|
247
251
|
editorCache = { projectName: null };
|
|
248
252
|
return;
|
|
249
253
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
editorCache = { projectName: null };
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
const title = stdout2.trim();
|
|
266
|
-
let projectName = null;
|
|
267
|
-
// Try to extract a path from the title (e.g. "~/Documents/source/foo - branch")
|
|
268
|
-
const pathMatch = title.match(/^(~?\/[^\s]+)/);
|
|
269
|
-
if (pathMatch) {
|
|
270
|
-
const segments = pathMatch[1].replace(/\/$/, '').split('/');
|
|
271
|
-
projectName = segments[segments.length - 1] || null;
|
|
272
|
-
}
|
|
273
|
-
// Fallback: default title format "file — project — Editor" or "project — Editor"
|
|
274
|
-
if (!projectName) {
|
|
275
|
-
const parts = title.split(' \u2014 ');
|
|
276
|
-
if (parts.length >= 3) {
|
|
277
|
-
projectName = parts[parts.length - 2];
|
|
278
|
-
}
|
|
279
|
-
else if (parts.length === 2) {
|
|
280
|
-
projectName = parts[0];
|
|
281
|
-
}
|
|
254
|
+
let projectName = null;
|
|
255
|
+
// Try to extract a path from the title (e.g. "~/Documents/source/foo - branch")
|
|
256
|
+
const pathMatch = title.match(/^(~?\/[^\s]+)/);
|
|
257
|
+
if (pathMatch) {
|
|
258
|
+
const segments = pathMatch[1].replace(/\/$/, '').split('/');
|
|
259
|
+
projectName = segments[segments.length - 1] || null;
|
|
260
|
+
}
|
|
261
|
+
// Fallback: default title format "file — project — Editor" or "project — Editor"
|
|
262
|
+
if (!projectName) {
|
|
263
|
+
const parts = title.split(' \u2014 ');
|
|
264
|
+
if (parts.length >= 3) {
|
|
265
|
+
projectName = parts[parts.length - 2];
|
|
282
266
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
// Push change to client over WebSocket
|
|
286
|
-
if (projectName && projectName !== prev) {
|
|
287
|
-
wsHandler.send({ type: 'editor:active', projectName });
|
|
267
|
+
else if (parts.length === 2) {
|
|
268
|
+
projectName = parts[0];
|
|
288
269
|
}
|
|
289
|
-
}
|
|
270
|
+
}
|
|
271
|
+
const prev = editorCache.projectName;
|
|
272
|
+
editorCache = { projectName };
|
|
273
|
+
if (projectName && projectName !== prev) {
|
|
274
|
+
wsHandler.send({ type: 'editor:active', projectName });
|
|
275
|
+
}
|
|
290
276
|
});
|
|
291
277
|
}
|
|
292
|
-
// Poll every
|
|
278
|
+
// Poll every 500ms — single osascript call is fast
|
|
293
279
|
pollActiveEditor();
|
|
294
|
-
setInterval(pollActiveEditor,
|
|
280
|
+
setInterval(pollActiveEditor, 500);
|
|
295
281
|
app.get('/api/active-editor', (_req, res) => {
|
|
296
282
|
res.json(editorCache);
|
|
297
283
|
});
|
package/dist/server/ipc.js
CHANGED
|
@@ -41,10 +41,10 @@ export function startIpcListener(socketPath, ptyManager, projectStore, wsHandler
|
|
|
41
41
|
function handleIpcRequest(request, ptyManager, projectStore, wsHandler) {
|
|
42
42
|
switch (request.command) {
|
|
43
43
|
case 'spawn': {
|
|
44
|
+
// Always send to frontend — it deduplicates by cwd
|
|
44
45
|
const id = uuidv4();
|
|
45
46
|
const project = newProject(id, request.name, request.cwd);
|
|
46
47
|
projectStore.create(project);
|
|
47
|
-
// Notify the frontend
|
|
48
48
|
wsHandler.send({
|
|
49
49
|
type: 'project:spawned',
|
|
50
50
|
projectId: id,
|
|
@@ -44,6 +44,13 @@ export class ProjectStore {
|
|
|
44
44
|
}
|
|
45
45
|
return undefined;
|
|
46
46
|
}
|
|
47
|
+
findByCwd(cwd) {
|
|
48
|
+
for (const p of this.projects.values()) {
|
|
49
|
+
if (p.cwd === cwd)
|
|
50
|
+
return p;
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
47
54
|
addTerminal(projectId, terminalId) {
|
|
48
55
|
const project = this.projects.get(projectId);
|
|
49
56
|
if (project && !project.terminal_ids.includes(terminalId)) {
|