conductor-remote 1.53.2 → 1.53.4

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/index.html CHANGED
@@ -13,7 +13,7 @@
13
13
  <title>Conductor Remote</title>
14
14
  <!-- Runs before the module bundle so it can catch a stale shell that fails to boot. -->
15
15
  <script src="/self-heal.js"></script>
16
- <script type="module" crossorigin src="/assets/index-CQuR_IG3.js"></script>
16
+ <script type="module" crossorigin src="/assets/index-Dw55ffnp.js"></script>
17
17
  <link rel="stylesheet" crossorigin href="/assets/index-CNdG7lFR.css">
18
18
  <link rel="manifest" href="/manifest.webmanifest"></head>
19
19
  <body>
package/dist/sw.js CHANGED
@@ -1 +1 @@
1
- if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(s[o])return;let l={};const t=e=>i(e,o),c={module:{uri:o},exports:l,require:t};s[o]=Promise.all(n.map(e=>c[e]||t(e))).then(e=>(r(...e),l))}}define(["./workbox-9c191d2f"],function(e){"use strict";importScripts("/push-sw.js"),self.addEventListener("message",e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}),e.clientsClaim(),e.precacheAndRoute([{url:"self-heal.js",revision:"49bd63adb25a09341f8d2610e8bd3c76"},{url:"push-sw.js",revision:"e1e682e2e5e88fa03b7808ae9db8e098"},{url:"index.html",revision:"6fd3f4c8b836fbae3791d6d273888b16"},{url:"assets/workbox-window.prod.es5-BBnX5xw4.js",revision:null},{url:"assets/index-CQuR_IG3.js",revision:null},{url:"assets/index-CNdG7lFR.css",revision:null},{url:"apple-touch-icon.png",revision:"2b9301416b880d45d4bb655f2600d1f2"},{url:"icon-192.png",revision:"c5e01ac58768627e18ee7b8b6a9239ef"},{url:"icon-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon-maskable-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon.svg",revision:"c1aee186821798733dd477e69a0ef243"},{url:"manifest.webmanifest",revision:"cf88fbc5755108a7fe0616fa160a8a15"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"),{denylist:[/^\/api\//]}))});
1
+ if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(s[o])return;let l={};const t=e=>i(e,o),c={module:{uri:o},exports:l,require:t};s[o]=Promise.all(n.map(e=>c[e]||t(e))).then(e=>(r(...e),l))}}define(["./workbox-9c191d2f"],function(e){"use strict";importScripts("/push-sw.js"),self.addEventListener("message",e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}),e.clientsClaim(),e.precacheAndRoute([{url:"self-heal.js",revision:"49bd63adb25a09341f8d2610e8bd3c76"},{url:"push-sw.js",revision:"e1e682e2e5e88fa03b7808ae9db8e098"},{url:"index.html",revision:"dda2e743b9942d72e38b3d9ca7a409c3"},{url:"assets/workbox-window.prod.es5-BBnX5xw4.js",revision:null},{url:"assets/index-Dw55ffnp.js",revision:null},{url:"assets/index-CNdG7lFR.css",revision:null},{url:"apple-touch-icon.png",revision:"2b9301416b880d45d4bb655f2600d1f2"},{url:"icon-192.png",revision:"c5e01ac58768627e18ee7b8b6a9239ef"},{url:"icon-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon-maskable-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon.svg",revision:"c1aee186821798733dd477e69a0ef243"},{url:"manifest.webmanifest",revision:"cf88fbc5755108a7fe0616fa160a8a15"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"),{denylist:[/^\/api\//]}))});
@@ -11,7 +11,8 @@
11
11
 
12
12
  The target rides in on the environment (RELAY_WS_*, RELAY_TAB_*, RELAY_SET_*,
13
13
  RELAY_PROMPT_FILE) rather than being interpolated, which keeps AppleScript
14
- string escaping out of the picture entirely.
14
+ string escaping out of the picture entirely. The three matching labels use a
15
+ UTF-8 temporary file because `system attribute` decodes text as MacRoman.
15
16
 
16
17
  Two traps to respect when editing:
17
18
 
@@ -61,13 +62,30 @@
61
62
  *)
62
63
 
63
64
  on splitLines(s)
64
- set saved to AppleScript's text item delimiters
65
- set AppleScript's text item delimiters to linefeed
66
- set parts to text items of s
67
- set AppleScript's text item delimiters to saved
68
- return parts
65
+ -- `do shell script` converts the file's LF separators to AppleScript returns.
66
+ -- `paragraphs` handles that form and keeps empty fields between separators.
67
+ return paragraphs of s
69
68
  end splitLines
70
69
 
70
+ -- The target file's first two lines are tab title and palette query. The
71
+ -- remaining lines are sidebar-title candidates. The path is ASCII; the file
72
+ -- contents reach AppleScript through `do shell script` as UTF-8.
73
+ on targetField(fieldIndex)
74
+ set fields to my splitLines(do shell script "cat " & quoted form of (system attribute "RELAY_TARGET_FILE"))
75
+ if fieldIndex > (count of fields) then return ""
76
+ return item fieldIndex of fields
77
+ end targetField
78
+
79
+ on targetSidebarTitles()
80
+ set fields to my splitLines(do shell script "cat " & quoted form of (system attribute "RELAY_TARGET_FILE"))
81
+ if (count of fields) < 3 then return {}
82
+ set titles to {}
83
+ repeat with fieldIndex from 3 to (count of fields)
84
+ set end of titles to item fieldIndex of fields
85
+ end repeat
86
+ return titles
87
+ end targetSidebarTitles
88
+
71
89
  on windowProbe()
72
90
  -- One read, three outcomes, none of them guessed: {count, errNum, errText}.
73
91
  -- count is -1 when macOS refused the read at all. Everything that wants to
@@ -413,7 +431,7 @@ on findSidebarRow()
413
431
  -- in the AX tree (a collapsed section has none), and the title follows
414
432
  -- Conductor's precedence, so we try each candidate and require a *unique* hit —
415
433
  -- anything ambiguous returns nothing rather than guessing at a neighbour.
416
- set titles to my splitLines(system attribute "RELAY_WS_TITLES")
434
+ set titles to my targetSidebarTitles()
417
435
  if (count of titles) is 0 then return missing value
418
436
  set repoName to system attribute "RELAY_WS_REPO"
419
437
  set rows to my sidebarLinks()
@@ -455,7 +473,7 @@ on focusViaPalette()
455
473
  delay 0.25
456
474
  keystroke "k" using {command down}
457
475
  delay 0.7
458
- keystroke (system attribute "RELAY_WS_QUERY")
476
+ keystroke (my targetField(2))
459
477
  delay 0.9
460
478
  key code 36
461
479
  delay 1.3
@@ -522,7 +540,7 @@ on openViaDeepLink()
522
540
  end openViaDeepLink
523
541
 
524
542
  on focusWorkspace()
525
- if (system attribute "RELAY_WS_QUERY") is "" then return
543
+ if (my targetField(2)) is "" then return
526
544
  if my openViaDeepLink() then return
527
545
  if my atTargetWorkspace() then return
528
546
  if my focusViaSidebar() then
@@ -754,7 +772,7 @@ on selectChatTab()
754
772
  set wantIndex to (system attribute "RELAY_TAB_INDEX") as integer
755
773
  if wantIndex is 0 then return
756
774
  set wantCount to (system attribute "RELAY_TAB_COUNT") as integer
757
- set wantTitle to system attribute "RELAY_TAB_TITLE"
775
+ set wantTitle to my targetField(1)
758
776
  set strips to my tabGroups()
759
777
  if (count of strips) is 0 then
760
778
  -- A lone chat has no ambiguity to resolve; more than one and we must not guess.
@@ -305,20 +305,41 @@ function restartAllowed() {
305
305
  return false;
306
306
  }
307
307
  }
308
- /** The target rides in on the environment, like RELAY_WS_QUERY, to dodge AppleScript escaping. */
308
+ /** Fixed targeting values travel in the environment; the three UI labels ride in RELAY_TARGET_FILE. */
309
309
  function targetEnv(target) {
310
310
  return {
311
311
  RELAY_ALLOW_RESTART: restartAllowed() ? '1' : '',
312
312
  RELAY_TAB_INDEX: String(target.tab?.index ?? 0),
313
313
  RELAY_TAB_COUNT: String(target.tab?.count ?? 0),
314
- RELAY_TAB_TITLE: target.tab?.title ?? '',
315
314
  RELAY_WS_BRANCH: target.workspace.branch ?? '',
316
315
  RELAY_WS_REPO: target.workspace.repo_name ?? '',
317
- RELAY_WS_QUERY: focusQuery(target.workspace),
318
- RELAY_WS_LINK: workspaceLink(target.workspace.id, target.sessionId),
319
- RELAY_WS_TITLES: sidebarTitles(target.workspace).join('\n')
316
+ RELAY_WS_LINK: workspaceLink(target.workspace.id, target.sessionId)
320
317
  };
321
318
  }
319
+ /**
320
+ * The target file is line-based: tab title, palette query, then sidebar-title candidates. Conductor labels
321
+ * cannot contain a newline, and `do shell script` reads this file as UTF-8 rather than MacRoman.
322
+ */
323
+ function targetLines(target) {
324
+ return [target.tab?.title ?? '', focusQuery(target.workspace), ...sidebarTitles(target.workspace)];
325
+ }
326
+ /**
327
+ * Give one UI action the three matching labels in a UTF-8 file. `system attribute` decodes text as MacRoman,
328
+ * but it safely carries the temporary file path.
329
+ */
330
+ export async function withTargetEnvironment(target, action) {
331
+ const fs = await import('node:fs/promises');
332
+ const os = await import('node:os');
333
+ const directory = await fs.mkdtemp(path.join(os.tmpdir(), 'relay-target-'));
334
+ const file = path.join(directory, 'text');
335
+ try {
336
+ await fs.writeFile(file, targetLines(target).join('\n'), 'utf8');
337
+ return await action({ ...targetEnv(target), RELAY_TARGET_FILE: file });
338
+ }
339
+ finally {
340
+ await fs.rm(directory, { recursive: true, force: true }).catch(() => undefined);
341
+ }
342
+ }
322
343
  /** osascript echoes the whole failing script back; keep just the reason for the phone. */
323
344
  function osaError(err, timeoutMsg = 'Conductor took too long to respond') {
324
345
  const raw = err instanceof Error ? err.message : String(err);
@@ -380,15 +401,15 @@ end tell
380
401
  const tmp = path.join(os.tmpdir(), `relay-prompt-${process.pid}-${Date.now()}.txt`);
381
402
  await fs.writeFile(tmp, text, 'utf8');
382
403
  try {
383
- await uiTurn(() => exec('osascript', ['-e', script], {
404
+ await withTargetEnvironment(target, targetEnvironment => uiTurn(() => exec('osascript', ['-e', script], {
384
405
  env: {
385
406
  ...process.env,
386
407
  RELAY_PROMPT_FILE: tmp,
387
408
  RELAY_QUEUE_PROMPT: options.queue ? '1' : '',
388
- ...targetEnv(target)
409
+ ...targetEnvironment
389
410
  },
390
411
  timeout: runCeiling(deadline)
391
- }));
412
+ })));
392
413
  return { ok: true, strategy: this.name };
393
414
  }
394
415
  catch (err) {
@@ -427,10 +448,10 @@ my selectChatTab()
427
448
  my cancelAgent()
428
449
  return "ok"`.trim();
429
450
  try {
430
- await uiTurn(() => exec('osascript', ['-e', script], {
431
- env: { ...process.env, ...targetEnv(target) },
451
+ await withTargetEnvironment(target, targetEnvironment => uiTurn(() => exec('osascript', ['-e', script], {
452
+ env: { ...process.env, ...targetEnvironment },
432
453
  timeout: SEND_ATTEMPT_MS
433
- }));
454
+ })));
434
455
  return { ok: true, strategy: 'applescript' };
435
456
  }
436
457
  catch (err) {
@@ -512,17 +533,17 @@ my selectChatTab()
512
533
  my applyAgentOptions()
513
534
  return "ok"`.trim();
514
535
  try {
515
- await uiTurn(() => exec('osascript', ['-e', script], {
536
+ await withTargetEnvironment(target, targetEnvironment => uiTurn(() => exec('osascript', ['-e', script], {
516
537
  env: {
517
538
  ...process.env,
518
- ...targetEnv(target),
539
+ ...targetEnvironment,
519
540
  RELAY_SET_EFFORT: opts.effort ? EFFORT_LABELS[opts.effort] : '',
520
541
  RELAY_SET_PLAN: opts.plan === undefined ? '' : opts.plan ? '1' : '0',
521
542
  RELAY_SET_FAST: opts.toggleFast ? '1' : '',
522
543
  RELAY_SET_MODEL: opts.model ?? ''
523
544
  },
524
545
  timeout: SEND_ATTEMPT_MS
525
- }));
546
+ })));
526
547
  return { ok: true, strategy: 'applescript' };
527
548
  }
528
549
  catch (err) {
@@ -564,14 +585,14 @@ my activateConductor()
564
585
  my setWorkspaceStatus()
565
586
  return "ok"`.trim();
566
587
  try {
567
- await uiTurn(() => exec('osascript', ['-e', script], {
588
+ await withTargetEnvironment({ workspace, sessionId: null }, targetEnvironment => uiTurn(() => exec('osascript', ['-e', script], {
568
589
  env: {
569
590
  ...process.env,
570
- ...targetEnv({ workspace, sessionId: null }),
591
+ ...targetEnvironment,
571
592
  RELAY_SET_STATUS: label
572
593
  },
573
594
  timeout: 25000
574
- }));
595
+ })));
575
596
  return { ok: true, strategy: 'applescript' };
576
597
  }
577
598
  catch (err) {
@@ -588,10 +609,10 @@ my focusWorkspace()
588
609
  my selectChatTab()
589
610
  return my listModels()`.trim();
590
611
  try {
591
- const { stdout } = await uiTurn(() => exec('osascript', ['-e', script], {
592
- env: { ...process.env, ...targetEnv(target) },
612
+ const { stdout } = await withTargetEnvironment(target, targetEnvironment => uiTurn(() => exec('osascript', ['-e', script], {
613
+ env: { ...process.env, ...targetEnvironment },
593
614
  timeout: SEND_ATTEMPT_MS
594
- }));
615
+ })));
595
616
  const models = stdout
596
617
  .split('\n')
597
618
  .map(s => s.trim())
@@ -683,10 +704,10 @@ end tell`.trim();
683
704
  try {
684
705
  // Shares the focus path with a send, so it needs the same ceiling: 15s was under
685
706
  // the cost of activating a cold Conductor and finding the row on its own.
686
- await uiTurn(() => exec('osascript', ['-e', script], {
687
- env: { ...process.env, ...targetEnv({ workspace, sessionId: null }) },
707
+ await withTargetEnvironment({ workspace, sessionId: null }, targetEnvironment => uiTurn(() => exec('osascript', ['-e', script], {
708
+ env: { ...process.env, ...targetEnvironment },
688
709
  timeout: SEND_ATTEMPT_MS
689
- }));
710
+ })));
690
711
  return { ok: true, strategy: 'applescript' };
691
712
  }
692
713
  catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conductor-remote",
3
- "version": "1.53.2",
3
+ "version": "1.53.4",
4
4
  "type": "module",
5
5
  "packageManager": "yarn@4.15.0",
6
6
  "description": "Phone control panel for local Conductor agents. Reads ride SQLite + git; prompts ride Conductor's own dispatch path.",
@@ -50,13 +50,14 @@
50
50
  "typecheck": "tsc -p tsconfig.json",
51
51
  "lint": "biome check .",
52
52
  "fix": "biome check . --fix",
53
- "verify": "yarn typecheck && yarn lint && yarn check:imports && yarn check:routes && yarn check:attachments && yarn check:applescript && yarn check:config && yarn check:file-links && yarn check:model-labels && yarn check:nosleep && yarn check:uilock && yarn check:firstprompt && yarn check:sendonce && yarn check:notify && yarn check:online",
53
+ "verify": "yarn typecheck && yarn lint && yarn check:imports && yarn check:routes && yarn check:attachments && yarn check:applescript && yarn check:config && yarn check:utf8-target && yarn check:file-links && yarn check:model-labels && yarn check:nosleep && yarn check:uilock && yarn check:firstprompt && yarn check:sendonce && yarn check:notify && yarn check:online",
54
54
  "release": "semantic-release",
55
55
  "prepack": "yarn build && yarn build:node",
56
56
  "postinstall": "husky || true",
57
57
  "check:attachments": "node scripts/check-attachments.ts",
58
58
  "check:applescript": "node scripts/check-applescript.ts",
59
59
  "check:config": "node scripts/check-config.ts",
60
+ "check:utf8-target": "node scripts/check-utf8-target.ts",
60
61
  "check:file-links": "node scripts/check-file-links.ts",
61
62
  "check:firstprompt": "node scripts/check-firstprompt.ts",
62
63
  "check:model-labels": "node scripts/check-model-labels.ts",