paneful 0.5.1 → 0.6.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/server/index.js
CHANGED
|
@@ -204,14 +204,27 @@ function startServer(devMode, port) {
|
|
|
204
204
|
const killed = ptyManager.killProject(req.params.id);
|
|
205
205
|
res.json({ killed: killed.length });
|
|
206
206
|
});
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if (
|
|
210
|
-
res.json({
|
|
207
|
+
app.post('/api/validate-path', (req, res) => {
|
|
208
|
+
const { path: rawPath } = req.body;
|
|
209
|
+
if (!rawPath) {
|
|
210
|
+
res.json({ valid: false });
|
|
211
211
|
return;
|
|
212
212
|
}
|
|
213
|
-
|
|
214
|
-
|
|
213
|
+
const resolved = rawPath.replace(/^~/, os.homedir());
|
|
214
|
+
try {
|
|
215
|
+
const stat = fs.statSync(resolved);
|
|
216
|
+
res.json({ valid: stat.isDirectory(), resolved });
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
res.json({ valid: false });
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
// Active editor detection — polls server-side so the client gets an instant cached response
|
|
223
|
+
const editorPatterns = ['cursor', 'code', 'vscode', 'visual studio code', 'zed', 'windsurf'];
|
|
224
|
+
let editorCache = { projectName: null };
|
|
225
|
+
function pollActiveEditor() {
|
|
226
|
+
if (process.platform !== 'darwin')
|
|
227
|
+
return;
|
|
215
228
|
const findScript = `
|
|
216
229
|
tell application "System Events"
|
|
217
230
|
set procNames to name of every process whose background only is false
|
|
@@ -225,18 +238,15 @@ function startServer(devMode, port) {
|
|
|
225
238
|
execFile('osascript', ['-e', findScript], { timeout: 2000 }, (err, stdout, stderr) => {
|
|
226
239
|
if (err) {
|
|
227
240
|
const needsAccess = stderr?.includes('not allowed assistive access') || stderr?.includes('1719');
|
|
228
|
-
|
|
241
|
+
editorCache = { projectName: null, needsAccessibility: needsAccess || undefined };
|
|
229
242
|
return;
|
|
230
243
|
}
|
|
231
244
|
const processes = stdout.trim().split('\n').map((p) => p.trim()).filter(Boolean);
|
|
232
|
-
console.log('[active-editor] processes:', processes);
|
|
233
245
|
const editorProcess = processes.find((p) => editorPatterns.some((pat) => p.toLowerCase().includes(pat)));
|
|
234
|
-
console.log('[active-editor] matched:', editorProcess ?? 'none');
|
|
235
246
|
if (!editorProcess) {
|
|
236
|
-
|
|
247
|
+
editorCache = { projectName: null };
|
|
237
248
|
return;
|
|
238
249
|
}
|
|
239
|
-
// Step 2: Get the front window title of the matched editor
|
|
240
250
|
const titleScript = `
|
|
241
251
|
tell application "System Events"
|
|
242
252
|
tell process "${editorProcess.replace(/"/g, '\\"')}"
|
|
@@ -247,26 +257,43 @@ function startServer(devMode, port) {
|
|
|
247
257
|
end tell
|
|
248
258
|
return ""
|
|
249
259
|
`;
|
|
250
|
-
execFile('osascript', ['-e', titleScript], { timeout: 2000 }, (err2, stdout2
|
|
251
|
-
console.log('[active-editor] title stdout:', JSON.stringify(stdout2));
|
|
252
|
-
console.log('[active-editor] title err:', err2?.message ?? 'none');
|
|
260
|
+
execFile('osascript', ['-e', titleScript], { timeout: 2000 }, (err2, stdout2) => {
|
|
253
261
|
if (err2 || !stdout2.trim()) {
|
|
254
|
-
|
|
262
|
+
editorCache = { projectName: null };
|
|
255
263
|
return;
|
|
256
264
|
}
|
|
257
265
|
const title = stdout2.trim();
|
|
258
|
-
// Editor titles: "file — project — Editor" or "project — Editor"
|
|
259
|
-
const parts = title.split(' \u2014 ');
|
|
260
266
|
let projectName = null;
|
|
261
|
-
|
|
262
|
-
|
|
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;
|
|
263
272
|
}
|
|
264
|
-
|
|
265
|
-
|
|
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
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const prev = editorCache.projectName;
|
|
284
|
+
editorCache = { projectName };
|
|
285
|
+
// Push change to client over WebSocket
|
|
286
|
+
if (projectName && projectName !== prev) {
|
|
287
|
+
wsHandler.send({ type: 'editor:active', projectName });
|
|
266
288
|
}
|
|
267
|
-
res.json({ projectName });
|
|
268
289
|
});
|
|
269
290
|
});
|
|
291
|
+
}
|
|
292
|
+
// Poll every 2 seconds server-side
|
|
293
|
+
pollActiveEditor();
|
|
294
|
+
setInterval(pollActiveEditor, 2000);
|
|
295
|
+
app.get('/api/active-editor', (_req, res) => {
|
|
296
|
+
res.json(editorCache);
|
|
270
297
|
});
|
|
271
298
|
// Resolve a dropped file's full path using OS file index (Spotlight on macOS)
|
|
272
299
|
app.post('/api/resolve-path', (req, res) => {
|