paneful 0.5.0 → 0.5.2

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.
@@ -210,42 +210,67 @@ function startServer(devMode, port) {
210
210
  res.json({ projectName: null });
211
211
  return;
212
212
  }
213
- const script = `
213
+ // Step 1: Find editor processes dynamically — match known editor keywords
214
+ const editorPatterns = ['cursor', 'code', 'vscode', 'visual studio code', 'zed', 'windsurf'];
215
+ const findScript = `
214
216
  tell application "System Events"
215
- set editorNames to {"Cursor", "Code"}
216
- repeat with editorName in editorNames
217
- if exists process editorName then
218
- tell process editorName
219
- if exists front window then
220
- return name of front window
221
- end if
222
- end tell
223
- end if
217
+ set procNames to name of every process whose background only is false
218
+ set output to ""
219
+ repeat with p in procNames
220
+ set output to output & p & linefeed
224
221
  end repeat
222
+ return output
225
223
  end tell
226
- return ""
227
224
  `;
228
- execFile('osascript', ['-e', script], { timeout: 2000 }, (err, stdout, stderr) => {
225
+ execFile('osascript', ['-e', findScript], { timeout: 2000 }, (err, stdout, stderr) => {
229
226
  if (err) {
230
227
  const needsAccess = stderr?.includes('not allowed assistive access') || stderr?.includes('1719');
231
228
  res.json({ projectName: null, needsAccessibility: needsAccess || undefined });
232
229
  return;
233
230
  }
234
- if (!stdout.trim()) {
231
+ const processes = stdout.trim().split('\n').map((p) => p.trim()).filter(Boolean);
232
+ const editorProcess = processes.find((p) => editorPatterns.some((pat) => p.toLowerCase().includes(pat)));
233
+ if (!editorProcess) {
235
234
  res.json({ projectName: null });
236
235
  return;
237
236
  }
238
- const title = stdout.trim();
239
- // VS Code/Cursor titles: "file — project — Editor" or "project — Editor"
240
- const parts = title.split(' \u2014 ');
241
- let projectName = null;
242
- if (parts.length >= 3) {
243
- projectName = parts[parts.length - 2];
244
- }
245
- else if (parts.length === 2) {
246
- projectName = parts[0];
247
- }
248
- res.json({ projectName });
237
+ // Step 2: Get the front window title of the matched editor
238
+ const titleScript = `
239
+ tell application "System Events"
240
+ tell process "${editorProcess.replace(/"/g, '\\"')}"
241
+ if exists front window then
242
+ return name of front window
243
+ end if
244
+ end tell
245
+ end tell
246
+ return ""
247
+ `;
248
+ execFile('osascript', ['-e', titleScript], { timeout: 2000 }, (err2, stdout2) => {
249
+ if (err2 || !stdout2.trim()) {
250
+ res.json({ projectName: null });
251
+ return;
252
+ }
253
+ const title = stdout2.trim();
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
+ // Grab the deepest folder from the path
259
+ const segments = pathMatch[1].replace(/\/$/, '').split('/');
260
+ projectName = segments[segments.length - 1] || null;
261
+ }
262
+ // Fallback: default title format "file — project — Editor" or "project — Editor"
263
+ if (!projectName) {
264
+ const parts = title.split(' \u2014 ');
265
+ if (parts.length >= 3) {
266
+ projectName = parts[parts.length - 2];
267
+ }
268
+ else if (parts.length === 2) {
269
+ projectName = parts[0];
270
+ }
271
+ }
272
+ res.json({ projectName });
273
+ });
249
274
  });
250
275
  });
251
276
  // Resolve a dropped file's full path using OS file index (Spotlight on macOS)