conductor-remote 1.131.2 → 1.131.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/index.html CHANGED
@@ -25,7 +25,7 @@
25
25
  <title>Conductor Remote</title>
26
26
  <!-- Runs before the module bundle so it can catch a stale shell that fails to boot. -->
27
27
  <script src="/self-heal.js"></script>
28
- <script type="module" crossorigin src="/assets/index-fUZj9cRu.js"></script>
28
+ <script type="module" crossorigin src="/assets/index-Bsirxp4Y.js"></script>
29
29
  <link rel="stylesheet" crossorigin href="/assets/index-Dbu5DOed.css">
30
30
  <link rel="manifest" href="/manifest.webmanifest"></head>
31
31
  <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 l=e||("document"in self?document.currentScript.src:"")||location.href;if(s[l])return;let o={};const t=e=>i(e,l),a={module:{uri:l},exports:o,require:t};s[l]=Promise.all(n.map(e=>a[e]||t(e))).then(e=>(r(...e),o))}}define(["./workbox-dcde9eb3"],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:"4e0b714c0ea53e85c167e6d8f5b767aa"},{url:"index.html",revision:"5373066373ca133cbf24521227792444"},{url:"assets/workbox-window.prod.es5-BBnX5xw4.js",revision:null},{url:"assets/pierre-shiki-wasm-C8ETeZem.js",revision:null},{url:"assets/pierre-light-480U9XYS.js",revision:null},{url:"assets/pierre-dark-CyvmCCZW.js",revision:null},{url:"assets/index-fUZj9cRu.js",revision:null},{url:"assets/index-Dbu5DOed.css",revision:null},{url:"assets/PierrePatch-Dzam9HOM.js",revision:null},{url:"assets/AutoModelSettings-BeVICf6p.js",revision:null},{url:"apple-touch-icon.png",revision:"1127bb396b4648add53dce3f22c92aee"},{url:"icon-192.png",revision:"c5e01ac58768627e18ee7b8b6a9239ef"},{url:"icon-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon-maskable-512.png",revision:"a9b0d962686287452216492cd2247499"},{url:"icon.svg",revision:"c1aee186821798733dd477e69a0ef243"},{url:"manifest.webmanifest",revision:"cf88fbc5755108a7fe0616fa160a8a15"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"),{denylist:[/^\/api\//]})),e.registerRoute(({url:e})=>e.pathname.startsWith("/assets/diff-syntax/"),new e.CacheFirst({cacheName:"diff-syntax",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:31536e3})]}),"GET")});
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 l=e||("document"in self?document.currentScript.src:"")||location.href;if(s[l])return;let o={};const t=e=>i(e,l),a={module:{uri:l},exports:o,require:t};s[l]=Promise.all(n.map(e=>a[e]||t(e))).then(e=>(r(...e),o))}}define(["./workbox-dcde9eb3"],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:"4e0b714c0ea53e85c167e6d8f5b767aa"},{url:"index.html",revision:"f7c164d3affb878065d2f69b2fef65de"},{url:"assets/workbox-window.prod.es5-BBnX5xw4.js",revision:null},{url:"assets/pierre-shiki-wasm-C8ETeZem.js",revision:null},{url:"assets/pierre-light-480U9XYS.js",revision:null},{url:"assets/pierre-dark-CyvmCCZW.js",revision:null},{url:"assets/index-Dbu5DOed.css",revision:null},{url:"assets/index-Bsirxp4Y.js",revision:null},{url:"assets/PierrePatch-BKDmpkha.js",revision:null},{url:"assets/AutoModelSettings-CX-bCwFp.js",revision:null},{url:"apple-touch-icon.png",revision:"1127bb396b4648add53dce3f22c92aee"},{url:"icon-192.png",revision:"c5e01ac58768627e18ee7b8b6a9239ef"},{url:"icon-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon-maskable-512.png",revision:"a9b0d962686287452216492cd2247499"},{url:"icon.svg",revision:"c1aee186821798733dd477e69a0ef243"},{url:"manifest.webmanifest",revision:"cf88fbc5755108a7fe0616fa160a8a15"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"),{denylist:[/^\/api\//]})),e.registerRoute(({url:e})=>e.pathname.startsWith("/assets/diff-syntax/"),new e.CacheFirst({cacheName:"diff-syntax",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:31536e3})]}),"GET")});
@@ -1,5 +1,5 @@
1
1
  import { writeAttachment } from "../../files/attachments.js";
2
- import { delegatedPrompt } from "../../orchestration/delegation/prompt.js";
2
+ import { delegatedPrompt, writeDelegatedAssignment } from "../../orchestration/delegation/prompt.js";
3
3
  import { DelegationQueue } from "../../orchestration/delegation/queue.js";
4
4
  import { delegationReturnAttachment, delegationReturnText } from "../../orchestration/delegation/return.js";
5
5
  import { withoutWindowEvidence } from "../../shared.js";
@@ -60,8 +60,10 @@ export function createDelegationsServices(services) {
60
60
  return delegationError('opening_failed', 'The Mac is locked — unlock it and try again.');
61
61
  }
62
62
  let handoff;
63
+ let assignment;
63
64
  try {
64
65
  handoff = delegationHandoff(job, ws);
66
+ assignment = writeDelegatedAssignment({ ...job, handoff }, ws.worktree);
65
67
  }
66
68
  catch (err) {
67
69
  return delegationError('opening_failed', err instanceof Error ? err.message : String(err), false);
@@ -70,9 +72,7 @@ export function createDelegationsServices(services) {
70
72
  if ('error' in opened) {
71
73
  return delegationError('opening_failed', opened.result.error ?? 'Conductor did not open a child chat', opened.retryable !== false);
72
74
  }
73
- if (!opened.sessionId)
74
- return delegationError('opening_failed', 'Conductor opened a tab but did not record its chat id', false);
75
- return { ok: true, childSessionId: opened.sessionId, handoff };
75
+ return { ok: true, childSessionId: opened.sessionId, handoff, assignment };
76
76
  }
77
77
  async function configureDelegation(job) {
78
78
  const ws = reads.getWorkspace(job.workspaceId);
@@ -174,7 +174,7 @@ export function createDelegationsServices(services) {
174
174
  catch (err) {
175
175
  return delegationError('state_invalid', err instanceof Error ? err.message : String(err), false);
176
176
  }
177
- const result = await trackedPrompt(ws, job.childSessionId, text, job.sendDelivery, 'send_failed', job.handoff);
177
+ const result = await trackedPrompt(ws, job.childSessionId, text, job.sendDelivery, 'send_failed', job.assignment ?? job.handoff);
178
178
  if (!result.ok)
179
179
  return result;
180
180
  return 'pending' in result
@@ -280,7 +280,7 @@ export function createDelegationsServices(services) {
280
280
  const text = returning ? job.returnText : delegatedPrompt(job);
281
281
  if (!text)
282
282
  return null;
283
- const receipt = trackedReceipt(sessionId, text, delivery, returning ? job.returnAttachment : job.handoff);
283
+ const receipt = trackedReceipt(sessionId, text, delivery, returning ? job.returnAttachment : (job.assignment ?? job.handoff));
284
284
  return receipt
285
285
  ? { stage: returning ? 'returning' : 'sending', delivery: { ...delivery, messageId: receipt.id } }
286
286
  : null;
@@ -10,7 +10,7 @@ import { readPrefs } from "../../prefs.js";
10
10
  import { setAgentOptions } from "../../writes/agent-options.js";
11
11
  import { newChat } from "../../writes/chats.js";
12
12
  import { lockBlocked, retryWontHelp, screenLocked, sendNeverStarted } from "../../writes/guards.js";
13
- import { withUiPriority } from "../../writes/ui-lock.js";
13
+ import { uiTurn, withUiPriority } from "../../writes/ui-lock.js";
14
14
  export function createDeliveryServices(services) {
15
15
  const { reads, sleep, actuator, STAGED_ATTACHMENTS_DIR, assignWorkflowRoot, orchestration, stagedAttachmentIdsInObjective, modelCache } = services;
16
16
  /**
@@ -108,38 +108,47 @@ export function createDeliveryServices(services) {
108
108
  /**
109
109
  * Open a chat tab in a workspace and come back with its id.
110
110
  *
111
- * ⌘T is fire-and-forget like every other keystroke here, so the id is not something
112
- * the write can return the DB is the receipt. Which row is the new one is decided by
113
- * diffing the tab list against the one taken *before* the keystroke, not by taking the
114
- * newest: a sibling tab or another agent may have opened one in between, and picking by
115
- * `created_at` would hand back theirs.
111
+ * The UI lease spans the baseline, shortcut and DB receipt. Snapshotting before
112
+ * the lease or releasing it before the receipt lets concurrent opens claim each
113
+ * other's tabs. A script exit is only an attempted action; only one new row is
114
+ * success, including when a script fails after its shortcut already took effect.
116
115
  */
117
116
  async function openChat(ws) {
118
- const before = new Set(reads.listSessions(ws.id).map(s => s.id));
119
- const result = await newChat(ws);
120
- if (!result.ok)
121
- return { error: true, result };
122
- // The new session lands in the DB a beat after Cmd+T — poll for the fresh id.
123
- for (let i = 0; i < 12; i++) {
124
- await sleep(500);
125
- const fresh = reads.listSessions(ws.id).filter(s => !before.has(s.id));
126
- if (fresh.length > 1) {
127
- return {
128
- error: true,
129
- retryable: false,
130
- result: {
117
+ return uiTurn(async () => {
118
+ const before = new Set(reads.listSessions(ws.id).map(s => s.id));
119
+ const result = await newChat(ws);
120
+ for (let i = 0; i <= 12; i++) {
121
+ const fresh = reads.listSessions(ws.id).filter(s => !before.has(s.id));
122
+ if (fresh.length > 1) {
123
+ return {
124
+ error: true,
125
+ retryable: false,
126
+ result: {
127
+ ok: false,
128
+ strategy: result.strategy,
129
+ error: 'more than one new chat appeared; refusing to guess which one this request opened'
130
+ }
131
+ };
132
+ }
133
+ if (fresh[0])
134
+ return { sessionId: fresh[0].id };
135
+ if (i < 12)
136
+ await sleep(500);
137
+ }
138
+ return {
139
+ error: true,
140
+ // A late tab cannot be distinguished from a retry's tab. Do not replay an
141
+ // unconfirmed creation automatically; the user can inspect the workspace.
142
+ retryable: false,
143
+ result: result.ok
144
+ ? {
131
145
  ok: false,
132
- strategy: actuator.name,
133
- error: 'more than one new chat appeared; refusing to guess which one this request opened'
146
+ strategy: result.strategy,
147
+ error: 'Conductor did not confirm a new chat. Check the workspace before trying again.'
134
148
  }
135
- };
136
- }
137
- if (fresh[0])
138
- return { sessionId: fresh[0].id };
139
- }
140
- // The tab is almost certainly on screen; only its id is missing. Say so rather than
141
- // failing the call, so a caller can still tell the user where the work went.
142
- return { sessionId: null };
149
+ : result
150
+ };
151
+ });
143
152
  }
144
153
  /**
145
154
  * Deliver a prompt to one chat and confirm it landed, retrying until the caller's
@@ -137,9 +137,6 @@ export function createWorkflowServices(services) {
137
137
  if ('error' in opened) {
138
138
  throw new WorkflowCoordinatorError('workflow_effect_failed', opened.result.error ?? 'Conductor did not open a tracked child chat.', { retryable: opened.retryable !== false });
139
139
  }
140
- if (!opened.sessionId) {
141
- throw new WorkflowCoordinatorError('workflow_effect_failed', 'Conductor opened a child tab but did not record its exact session ID.');
142
- }
143
140
  return { sessionId: opened.sessionId };
144
141
  });
145
142
  },
@@ -171,6 +171,7 @@ export function decodeDelegation(raw) {
171
171
  createdAt: integer(value.createdAt, 'createdAt'),
172
172
  updatedAt: integer(value.updatedAt, 'updatedAt'),
173
173
  ...(value.handoff === undefined ? {} : { handoff: decodeAttachment(value.handoff) }),
174
+ ...(value.assignment === undefined ? {} : { assignment: decodeAttachment(value.assignment) }),
174
175
  ...(value.sendDelivery === undefined ? {} : { sendDelivery: decodeDelivery(value.sendDelivery, 'sendDelivery') }),
175
176
  ...(value.sentRowid === undefined ? {} : { sentRowid: integer(value.sentRowid, 'sentRowid', 1) }),
176
177
  ...(value.completionRowid === undefined
@@ -1,7 +1,32 @@
1
- import { attachmentPrompt } from "../../files/attachments.js";
1
+ import { attachmentPrompt, writeAttachment } from "../../files/attachments.js";
2
2
  import { chatCursor } from "../../transcript/cursor.js";
3
+ /**
4
+ * Conductor's runtime decodes socket chunks independently, so a split UTF-8
5
+ * character can be replaced before the prompt reaches its outbox. Keep new
6
+ * assignments in a file and send only an ASCII reference through that runtime.
7
+ * The reference is persisted with the job before any send. Existing jobs without
8
+ * it must retain the exact inline text used by their saved delivery receipts.
9
+ */
10
+ export function writeDelegatedAssignment(job, worktree) {
11
+ if (!job.handoff)
12
+ throw new Error('the delegated handoff is missing');
13
+ const body = [
14
+ '# Delegated assignment',
15
+ `Read the parent transcript at ${JSON.stringify(job.handoff.path)} as background context before working.`,
16
+ delegatedPrompt({ ...job, assignment: undefined })
17
+ ].join('\n\n');
18
+ const written = writeAttachment(worktree, 'assignment.md', body);
19
+ return { name: written.name, path: written.relPath, bytes: written.bytes, token: written.token };
20
+ }
3
21
  /** Ordinary delegation supplies transport context; the saved role and assignment supply the task. */
4
22
  export function delegatedPrompt(job) {
23
+ if (job.assignment) {
24
+ return [
25
+ 'Read and follow the complete delegated assignment in this UTF-8 file before doing any work:',
26
+ `[Delegated assignment](${encodeURIComponent(job.assignment.path)})`,
27
+ 'Read it from the shared worktree, complete the assignment, and put the full result in your final reply.'
28
+ ].join('\n\n');
29
+ }
5
30
  if (!job.handoff)
6
31
  throw new Error('the delegated handoff is missing');
7
32
  const parentRead = {
@@ -26,6 +26,7 @@ export function transitionDelegation(job, status, patch, updatedAt = Date.now())
26
26
  updatedAt,
27
27
  ...(patch.childSessionId === undefined ? {} : { childSessionId: patch.childSessionId }),
28
28
  ...(patch.handoff === undefined ? {} : { handoff: patch.handoff }),
29
+ ...(patch.assignment === undefined ? {} : { assignment: patch.assignment }),
29
30
  ...(patch.sentRowid === undefined ? {} : { sentRowid: patch.sentRowid }),
30
31
  ...(patch.completionRowid === undefined ? {} : { completionRowid: patch.completionRowid }),
31
32
  ...(patch.returnCursor === undefined ? {} : { returnCursor: patch.returnCursor }),
@@ -174,7 +175,7 @@ export class DelegationQueue {
174
175
  parentSessionId: job.parentSessionId,
175
176
  assignedAt: this.now()
176
177
  });
177
- store.put(transitionDelegation(job, 'configuring', { childSessionId: result.childSessionId, handoff: result.handoff }, this.now()));
178
+ store.put(transitionDelegation(job, 'configuring', { childSessionId: result.childSessionId, handoff: result.handoff, assignment: result.assignment }, this.now()));
178
179
  return true;
179
180
  }
180
181
  if (job.status === 'configuring') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conductor-remote",
3
- "version": "1.131.2",
3
+ "version": "1.131.3",
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.",