@shipers-dev/multi 0.64.0 → 0.66.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.
Files changed (2) hide show
  1. package/dist/index.js +377 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -34493,6 +34493,27 @@ var init_chat = __esm(() => {
34493
34493
  primary_agent_id: exports_external.string().nullable().optional()
34494
34494
  });
34495
34495
  });
34496
+ // ../lib/device-link.ts
34497
+ function encodeFrame(frame) {
34498
+ const body = new TextEncoder().encode(JSON.stringify(frame));
34499
+ const out = new Uint8Array(1 + body.byteLength);
34500
+ out[0] = FRAME_JSON;
34501
+ out.set(body, 1);
34502
+ return out;
34503
+ }
34504
+ function decodeFrame(buf) {
34505
+ if (buf.byteLength < 1)
34506
+ return null;
34507
+ if (buf[0] !== FRAME_JSON)
34508
+ return null;
34509
+ try {
34510
+ return JSON.parse(new TextDecoder().decode(buf.subarray(1)));
34511
+ } catch {
34512
+ return null;
34513
+ }
34514
+ }
34515
+ var FRAME_JSON = 0;
34516
+
34496
34517
  // ../lib/index.ts
34497
34518
  var init_lib = __esm(() => {
34498
34519
  init_streams();
@@ -35192,6 +35213,10 @@ _${bits.join(" · ")}_`);
35192
35213
  const acpCapable = detected.filter((d) => d.type === "claude-code");
35193
35214
  const useAcp = preferType !== "pi" && acpCapable.length > 0 && process.env.MULTI_LEGACY !== "1";
35194
35215
  const useAcpx = !useAcp && preferType && ["pi", "codex", "openclaw"].includes(preferType) && process.env.MULTI_LEGACY !== "1";
35216
+ let issueHistoryBlock = "";
35217
+ if (tenantWsId && ISSUE_BASE) {
35218
+ issueHistoryBlock = await fetchIssueHistory(apiUrl, tenantWsId, projectId, issueId, log3);
35219
+ }
35195
35220
  try {
35196
35221
  if (useAcp) {
35197
35222
  const issueContext = `## Issue ${task.key}: ${task.title}${task.description ? `
@@ -35209,6 +35234,20 @@ ${task.description}` : ""}`;
35209
35234
  ${cleanFollowup}`;
35210
35235
  } else {
35211
35236
  userPart = stripSelfMention(issueContext, preferType);
35237
+ userPart += `
35238
+
35239
+ ---
35240
+
35241
+ You have been assigned this issue. Investigate and resolve it. Read the codebase, understand the problem, implement a fix or complete the described work, and use your tools to make progress. When finished, emit a multi-plan action to mark the issue done (or blocked if you need human input).`;
35242
+ }
35243
+ if (issueHistoryBlock) {
35244
+ userPart += `
35245
+
35246
+ ---
35247
+
35248
+ ## Issue history (prior activity)
35249
+
35250
+ ${issueHistoryBlock}`;
35212
35251
  }
35213
35252
  if (attachmentRefs.length) {
35214
35253
  const lines = attachmentRefs.map((a) => `- ${a.filename}: ${a.path}`).join(`
@@ -35227,6 +35266,7 @@ Note: if (and only if) you produce binary or large artifact outputs (screenshots
35227
35266
  Respond in the chat. Only if you produce large artifact files (screenshots, data exports, generated source code), write them under ${outDir}. Do not put your answer in a file.`;
35228
35267
  }
35229
35268
  let preamble = "";
35269
+ let preambleFailed = false;
35230
35270
  try {
35231
35271
  if (tenantWsId) {
35232
35272
  const agentRes = await apiClient.get(`${apiUrl}/api/workspaces/${tenantWsId}/agents/${task.agent_id}`);
@@ -35256,7 +35296,9 @@ ${body}
35256
35296
  }
35257
35297
  }
35258
35298
  } catch (e) {
35299
+ preambleFailed = true;
35259
35300
  log3(`preamble fetch failed: ${String(e)}`);
35301
+ await postBoundChatMessage(apiUrl, task, `⚠️ System: agent preamble (prompt + skills) fetch failed — the agent is running without its role definition. Error: ${String(e).slice(0, 200)}`);
35260
35302
  }
35261
35303
  preamble += await buildPlanningPreamble(apiUrl, task);
35262
35304
  const prompt = preamble ? `${preamble}
@@ -35337,7 +35379,10 @@ ${body}
35337
35379
  }
35338
35380
  }
35339
35381
  }
35340
- } catch {}
35382
+ } catch (e) {
35383
+ log3(`preamble fetch failed (acpx): ${String(e)}`);
35384
+ await postBoundChatMessage(apiUrl, task, `⚠️ System: agent preamble fetch failed — running without role definition. Error: ${String(e).slice(0, 200)}`);
35385
+ }
35341
35386
  preamble += await buildPlanningPreamble(apiUrl, task);
35342
35387
  const issueContext = `## Issue ${task.key}: ${task.title}${task.description ? `
35343
35388
 
@@ -35354,6 +35399,20 @@ ${task.description}` : ""}`;
35354
35399
  ${cleanFollowup}`;
35355
35400
  } else {
35356
35401
  userPart = stripSelfMention(issueContext, preferType);
35402
+ userPart += `
35403
+
35404
+ ---
35405
+
35406
+ You have been assigned this issue. Investigate and resolve it. Read the codebase, understand the problem, implement a fix or complete the described work, and use your tools to make progress. When finished, emit a multi-plan action to mark the issue done (or blocked if you need human input).`;
35407
+ }
35408
+ if (issueHistoryBlock) {
35409
+ userPart += `
35410
+
35411
+ ---
35412
+
35413
+ ## Issue history (prior activity)
35414
+
35415
+ ${issueHistoryBlock}`;
35357
35416
  }
35358
35417
  if (attachmentRefs.length) {
35359
35418
  const lines = attachmentRefs.map((a) => `- ${a.filename}: ${a.path}`).join(`
@@ -35488,6 +35547,52 @@ ${userPart}` : userPart;
35488
35547
  }
35489
35548
  }
35490
35549
  }
35550
+ async function fetchIssueHistory(apiUrl, tenantWsId, projectId, issueId, log4) {
35551
+ const MAX_HISTORY_CHARS = 6000;
35552
+ try {
35553
+ const issueBase = `${apiUrl}/api/workspaces/${tenantWsId}/projects/${projectId}/issues/${issueId}`;
35554
+ const res = await apiClient.get(`${issueBase}/activity`);
35555
+ const activities = Array.isArray(res.data?.results) ? res.data.results : Array.isArray(res.data) ? res.data : [];
35556
+ if (!activities.length)
35557
+ return "";
35558
+ const lines = [];
35559
+ const recent = activities.slice(-20).reverse();
35560
+ for (const act of recent) {
35561
+ const action = act.action || "activity";
35562
+ const actor = act.actor_name || act.actor_id || "system";
35563
+ const ts = act.created_at ? new Date(act.created_at * 1000).toISOString().slice(0, 16) : "";
35564
+ let line = `- **${actor}** ${action}`;
35565
+ if (ts)
35566
+ line += ` _${ts}_`;
35567
+ if (act.details) {
35568
+ try {
35569
+ const d = typeof act.details === "string" ? JSON.parse(act.details) : act.details;
35570
+ if (d.message)
35571
+ line += `: ${String(d.message).slice(0, 200)}`;
35572
+ else if (d.title)
35573
+ line += `: ${String(d.title).slice(0, 200)}`;
35574
+ else if (d.from && d.to)
35575
+ line += `: ${d.from} → ${d.to}`;
35576
+ else if (d.text)
35577
+ line += `: ${String(d.text).slice(0, 200)}`;
35578
+ } catch {}
35579
+ }
35580
+ lines.push(line);
35581
+ }
35582
+ const block = lines.join(`
35583
+ `);
35584
+ if (block.length > MAX_HISTORY_CHARS) {
35585
+ log4(` issue history truncated: ${block.length} → ${MAX_HISTORY_CHARS} chars`);
35586
+ return block.slice(0, MAX_HISTORY_CHARS) + `
35587
+
35588
+ _… truncated_`;
35589
+ }
35590
+ return block;
35591
+ } catch (e) {
35592
+ log4(` issue history fetch failed: ${String(e).slice(0, 200)}`);
35593
+ return "";
35594
+ }
35595
+ }
35491
35596
  async function buildPlanningPreamble(apiUrl, task, _wsId) {
35492
35597
  const depth = typeof task.planning_depth === "number" ? task.planning_depth : 0;
35493
35598
  if (depth >= PLANNING_DEPTH_LIMIT) {
@@ -35686,7 +35791,7 @@ async function executePlanActions(apiUrl, parentTask, actions, ctx, parseErrors
35686
35791
  }
35687
35792
  }
35688
35793
  } else if (a.type === "delegate") {
35689
- const res = await apiClient.post(mutateUrl, { action: "update", id: a.id, assignee_type: "agent", assignee_id: a.assignee_id, status: "todo" }, { headers });
35794
+ const res = await apiClient.post(mutateUrl, { action: "update", id: a.id, assignee_type: "agent", assignee_id: a.assignee_id, status: "in_progress" }, { headers });
35690
35795
  if (!res.success) {
35691
35796
  lines.push(`- [err] delegate ${a.id}: ${res.error || res.status}`);
35692
35797
  results.push({ type: "delegate", status: "error", error: String(res.error || res.status), label: a.id });
@@ -36851,7 +36956,7 @@ class ChatPeer {
36851
36956
  return;
36852
36957
  const body = new TextEncoder().encode(JSON.stringify(obj));
36853
36958
  const frame = new Uint8Array(1 + body.byteLength);
36854
- frame[0] = FRAME_JSON;
36959
+ frame[0] = FRAME_JSON2;
36855
36960
  frame.set(body, 1);
36856
36961
  try {
36857
36962
  this.ws.send(frame);
@@ -36894,7 +36999,7 @@ class ChatPeer {
36894
36999
  this.persist();
36895
37000
  return;
36896
37001
  }
36897
- if (tag3 === FRAME_JSON) {
37002
+ if (tag3 === FRAME_JSON2) {
36898
37003
  try {
36899
37004
  const txt = new TextDecoder().decode(buf.subarray(1));
36900
37005
  const msg = JSON.parse(txt);
@@ -36904,7 +37009,7 @@ class ChatPeer {
36904
37009
  }
36905
37010
  }
36906
37011
  }
36907
- var FRAME_JSON = 0, FRAME_LORO = 1;
37012
+ var FRAME_JSON2 = 0, FRAME_LORO = 1;
36908
37013
  var init_chat_peer = __esm(() => {
36909
37014
  init_paths();
36910
37015
  init_chat_doc();
@@ -37123,7 +37228,7 @@ async function executeChatPlanActions(actionsIn, parseErrors, ctx) {
37123
37228
  results.push({ type: "update", status: "ok", issue_id: res.data.id, key: res.data.key, status_to: a.status ?? null, title_to: a.title ?? null });
37124
37229
  tally(true);
37125
37230
  } else if (a.type === "delegate") {
37126
- const res = await apiClient.post(mutateUrl, { action: "update", id: a.id, assignee_type: "agent", assignee_id: a.assignee_id, status: "todo" }, { headers });
37231
+ const res = await apiClient.post(mutateUrl, { action: "update", id: a.id, assignee_type: "agent", assignee_id: a.assignee_id, status: "in_progress" }, { headers });
37127
37232
  if (!res.success) {
37128
37233
  lines.push(`- [err] delegate ${a.id}: ${res.error || res.status}`);
37129
37234
  results.push({ type: "delegate", status: "error", error: String(res.error || res.status), label: a.id });
@@ -38769,7 +38874,7 @@ import { parseArgs } from "util";
38769
38874
  // package.json
38770
38875
  var package_default = {
38771
38876
  name: "@shipers-dev/multi",
38772
- version: "0.64.0",
38877
+ version: "0.66.0",
38773
38878
  type: "module",
38774
38879
  bin: {
38775
38880
  "multi-agent": "./dist/index.js"
@@ -39850,6 +39955,157 @@ import { homedir as homedir4 } from "os";
39850
39955
  import { join as join16 } from "path";
39851
39956
  init_adapter_pidfile();
39852
39957
  init_errors();
39958
+
39959
+ // src/_impl/device-link-client.ts
39960
+ function startDeviceLinkClient(opts) {
39961
+ let ws = null;
39962
+ let stopped = false;
39963
+ let attempt = 0;
39964
+ let reconnectTimer = null;
39965
+ const connect = () => {
39966
+ if (stopped)
39967
+ return;
39968
+ let socket;
39969
+ try {
39970
+ socket = new WebSocket(opts.url);
39971
+ } catch (e) {
39972
+ opts.log(`[device-link] ws construct error: ${e.message}`);
39973
+ scheduleReconnect();
39974
+ return;
39975
+ }
39976
+ socket.binaryType = "arraybuffer";
39977
+ socket.addEventListener("open", () => {
39978
+ attempt = 0;
39979
+ ws = socket;
39980
+ opts.log("[device-link] connected");
39981
+ try {
39982
+ socket.send(encodeFrame({ kind: "hello", cli_version: opts.cliVersion, device_id: opts.deviceId }));
39983
+ } catch {}
39984
+ });
39985
+ socket.addEventListener("message", (ev) => {
39986
+ const data = ev.data;
39987
+ if (!(data instanceof ArrayBuffer))
39988
+ return;
39989
+ const frame = decodeFrame(new Uint8Array(data));
39990
+ if (!frame)
39991
+ return;
39992
+ try {
39993
+ const ret = opts.onFrame(frame);
39994
+ if (ret && typeof ret.catch === "function") {
39995
+ ret.catch((e) => {
39996
+ opts.log(`[device-link] onFrame rejected: ${e?.message ?? String(e)}`);
39997
+ });
39998
+ }
39999
+ } catch (e) {
40000
+ opts.log(`[device-link] onFrame threw: ${e.message}`);
40001
+ }
40002
+ });
40003
+ const handleEnd = (reason) => {
40004
+ if (ws === socket)
40005
+ ws = null;
40006
+ opts.log(`[device-link] disconnected (${reason})`);
40007
+ scheduleReconnect();
40008
+ };
40009
+ socket.addEventListener("close", (ev) => handleEnd(`code=${ev.code}`));
40010
+ socket.addEventListener("error", () => handleEnd("error"));
40011
+ };
40012
+ const scheduleReconnect = () => {
40013
+ if (stopped || reconnectTimer !== null)
40014
+ return;
40015
+ attempt++;
40016
+ const base = Math.min(60000, 1000 * Math.pow(2, Math.min(6, attempt - 1)));
40017
+ const jitter = base * (0.75 + Math.random() * 0.5);
40018
+ reconnectTimer = setTimeout(() => {
40019
+ reconnectTimer = null;
40020
+ connect();
40021
+ }, jitter);
40022
+ };
40023
+ connect();
40024
+ return {
40025
+ isConnected: () => ws !== null && ws.readyState === WebSocket.OPEN,
40026
+ send: (frame) => {
40027
+ if (!ws || ws.readyState !== WebSocket.OPEN)
40028
+ return false;
40029
+ try {
40030
+ ws.send(encodeFrame(frame));
40031
+ return true;
40032
+ } catch {
40033
+ return false;
40034
+ }
40035
+ },
40036
+ stop: () => {
40037
+ stopped = true;
40038
+ if (reconnectTimer !== null) {
40039
+ clearTimeout(reconnectTimer);
40040
+ reconnectTimer = null;
40041
+ }
40042
+ try {
40043
+ ws?.close(1000, "stopping");
40044
+ } catch {}
40045
+ ws = null;
40046
+ }
40047
+ };
40048
+ }
40049
+ // package.json
40050
+ var package_default2 = {
40051
+ name: "@shipers-dev/multi",
40052
+ version: "0.66.0",
40053
+ type: "module",
40054
+ bin: {
40055
+ "multi-agent": "./dist/index.js"
40056
+ },
40057
+ files: [
40058
+ "dist"
40059
+ ],
40060
+ scripts: {
40061
+ dev: "MULTI_HOME=${MULTI_HOME:-$HOME/.multi-dev} MULTI_API=${MULTI_API:-http://127.0.0.1:8787} bun run src/index.ts connect",
40062
+ build: "bun build src/index.ts --outdir=dist --target=node --sourcemap=none --external undici --external loro-crdt && node scripts/post-build.cjs",
40063
+ prepublishOnly: "bun run build"
40064
+ },
40065
+ dependencies: {
40066
+ "@agentclientprotocol/claude-agent-acp": "^0.31.0",
40067
+ "@agentclientprotocol/sdk": "^0.20.0",
40068
+ "@effect/platform-node": "^0.103.0",
40069
+ effect: "^3.21.2",
40070
+ "loro-crdt": "^1.12.1",
40071
+ undici: "^7.0.0"
40072
+ },
40073
+ devDependencies: {
40074
+ "@multi/lib": "workspace:*"
40075
+ }
40076
+ };
40077
+
40078
+ // src/_impl/daemon-main.ts
40079
+ var CLI_VERSION = package_default2.version;
40080
+ function findBunBinary() {
40081
+ const tryPath = (p) => {
40082
+ try {
40083
+ return existsSync16(p) ? p : null;
40084
+ } catch {
40085
+ return null;
40086
+ }
40087
+ };
40088
+ if (process.execPath && process.execPath.endsWith("/bun")) {
40089
+ const hit = tryPath(process.execPath);
40090
+ if (hit)
40091
+ return hit;
40092
+ }
40093
+ const fromWhich = Bun.which?.("bun");
40094
+ if (fromWhich)
40095
+ return fromWhich;
40096
+ const candidates = [
40097
+ join16(homedir4(), ".bun", "bin", "bun"),
40098
+ "/opt/homebrew/bin/bun",
40099
+ "/usr/local/bin/bun",
40100
+ "/home/linuxbrew/.linuxbrew/bin/bun"
40101
+ ];
40102
+ for (const c of candidates) {
40103
+ const hit = tryPath(c);
40104
+ if (hit)
40105
+ return hit;
40106
+ }
40107
+ return null;
40108
+ }
39853
40109
  var MULTI_DIR5 = join16(homedir4(), ".multi");
39854
40110
  var PID_PATH2 = join16(MULTI_DIR5, "agent.pid");
39855
40111
  var PORT_PATH2 = join16(MULTI_DIR5, "agent.port");
@@ -40220,7 +40476,7 @@ var daemonProgram = ({ cfg, apiUrl }) => exports_Effect.gen(function* () {
40220
40476
  }
40221
40477
  const route = () => {
40222
40478
  if (url2.pathname === "/health")
40223
- return Response.json({ ok: true, device_id: cfg.deviceId });
40479
+ return Response.json({ ok: true, device_id: cfg.deviceId, cli_version: CLI_VERSION });
40224
40480
  if (url2.pathname === "/files" && req.method === "GET") {
40225
40481
  if (req.headers.get("authorization") !== expectedAuth)
40226
40482
  return new Response("unauthorized", { status: 401 });
@@ -40627,6 +40883,47 @@ var daemonProgram = ({ cfg, apiUrl }) => exports_Effect.gen(function* () {
40627
40883
  }
40628
40884
  })();
40629
40885
  }
40886
+ if (url2.pathname === "/upgrade" && req.method === "POST") {
40887
+ if (req.headers.get("authorization") !== expectedAuth)
40888
+ return new Response("unauthorized", { status: 401 });
40889
+ return (async () => {
40890
+ const bunBin = findBunBinary();
40891
+ if (!bunBin) {
40892
+ return Response.json({ error: "bun binary not found; run `bun add -g @shipers-dev/multi` manually" }, { status: 503 });
40893
+ }
40894
+ let body = {};
40895
+ try {
40896
+ body = await req.json();
40897
+ } catch {}
40898
+ const spec = body.target ? `@shipers-dev/multi@${body.target}` : "@shipers-dev/multi";
40899
+ log3(`[upgrade] spawning ${bunBin} add -g ${spec}`);
40900
+ const child = Bun.spawn([bunBin, "add", "-g", spec], {
40901
+ stdout: "pipe",
40902
+ stderr: "pipe",
40903
+ stdin: "ignore"
40904
+ });
40905
+ (async () => {
40906
+ try {
40907
+ const stdoutTxt = await new Response(child.stdout).text();
40908
+ const stderrTxt = await new Response(child.stderr).text();
40909
+ const code = await child.exited;
40910
+ if (stdoutTxt.trim())
40911
+ log3(`[upgrade] stdout: ${stdoutTxt.trim()}`);
40912
+ if (stderrTxt.trim())
40913
+ log3(`[upgrade] stderr: ${stderrTxt.trim()}`);
40914
+ if (code === 0) {
40915
+ log3("[upgrade] success; exiting so service manager respawns with new binary");
40916
+ setTimeout(() => process.exit(0), 500);
40917
+ } else {
40918
+ log3(`[upgrade] failed with exit code ${code}`);
40919
+ }
40920
+ } catch (e) {
40921
+ log3(`[upgrade] error: ${e.message}`);
40922
+ }
40923
+ })();
40924
+ return Response.json({ accepted: true, current_version: CLI_VERSION, target: spec }, { status: 202 });
40925
+ })();
40926
+ }
40630
40927
  if (url2.pathname === "/stop" && req.method === "POST") {
40631
40928
  if (req.headers.get("authorization") !== expectedAuth)
40632
40929
  return new Response("unauthorized", { status: 401 });
@@ -40742,9 +41039,73 @@ var daemonProgram = ({ cfg, apiUrl }) => exports_Effect.gen(function* () {
40742
41039
  device_id: cfg.deviceId,
40743
41040
  workspace_id: cfg.workspaceId,
40744
41041
  api_url: apiUrl,
40745
- pid: process.pid
41042
+ pid: process.pid,
41043
+ cli_version: CLI_VERSION
40746
41044
  }, null, 2));
40747
41045
  } catch {}
41046
+ let deviceLink = null;
41047
+ if (!localMode && cfg.workspaceId && cfg.deviceId && cfg.dispatchSecret) {
41048
+ const linkUrl = `${apiUrl.replace(/^http/, "ws")}/api/daemon/link?device_id=${encodeURIComponent(cfg.deviceId)}&token=${encodeURIComponent(cfg.dispatchSecret)}`;
41049
+ const onFrame = async (frame) => {
41050
+ switch (frame.kind) {
41051
+ case "chat_turn": {
41052
+ try {
41053
+ const { chatSessionRegistry: chatSessionRegistry2 } = await Promise.resolve().then(() => (init_chat_session_registry(), exports_chat_session_registry));
41054
+ await chatSessionRegistry2.ensureAndProcess(frame.workspace_id, frame.chat_id, frame.message_id, { apiUrl, authToken: cfg.authToken, workspaceId: frame.workspace_id, deviceId: cfg.deviceId, log: log3 });
41055
+ deviceLink?.send({ id: frame.id, kind: "ack", for: frame.id, ok: true });
41056
+ } catch (e) {
41057
+ deviceLink?.send({ id: frame.id, kind: "ack", for: frame.id, ok: false, error: e.message });
41058
+ }
41059
+ return;
41060
+ }
41061
+ case "supervisor_tick": {
41062
+ try {
41063
+ const { runSupervisorTick: runSupervisorTick2 } = await Promise.resolve().then(() => (init_supervisor_tick(), exports_supervisor_tick));
41064
+ await runSupervisorTick2({
41065
+ apiUrl,
41066
+ tickId: frame.tick_id,
41067
+ projectId: frame.project_id,
41068
+ system: frame.system,
41069
+ user: frame.user,
41070
+ callbackUrl: frame.callback_url,
41071
+ callbackToken: frame.callback_token,
41072
+ log: log3
41073
+ });
41074
+ deviceLink?.send({ id: frame.id, kind: "ack", for: frame.id, ok: true });
41075
+ } catch (e) {
41076
+ deviceLink?.send({ id: frame.id, kind: "ack", for: frame.id, ok: false, error: e.message });
41077
+ }
41078
+ return;
41079
+ }
41080
+ case "stop": {
41081
+ const entries2 = Array.from(running3.values()).filter((e) => e.issueId === frame.issue_id);
41082
+ for (const entry of entries2) {
41083
+ entry.stopped = true;
41084
+ entry.stopReason = "user requested";
41085
+ try {
41086
+ entry.child?.kill("SIGTERM");
41087
+ } catch {}
41088
+ setTimeout(() => {
41089
+ try {
41090
+ entry.child?.kill("SIGKILL");
41091
+ } catch {}
41092
+ }, 1500);
41093
+ }
41094
+ deviceLink?.send({ id: frame.id, kind: "ack", for: frame.id, ok: true });
41095
+ return;
41096
+ }
41097
+ default:
41098
+ return;
41099
+ }
41100
+ };
41101
+ deviceLink = startDeviceLinkClient({
41102
+ url: linkUrl,
41103
+ cliVersion: CLI_VERSION,
41104
+ deviceId: cfg.deviceId,
41105
+ onFrame,
41106
+ log: log3
41107
+ });
41108
+ }
40748
41109
  let tunnel;
40749
41110
  if (localMode) {
40750
41111
  tunnel = { child: null, url: `http://127.0.0.1:${port}` };
@@ -40857,6 +41218,9 @@ var daemonProgram = ({ cfg, apiUrl }) => exports_Effect.gen(function* () {
40857
41218
  try {
40858
41219
  tunnel?.child?.kill();
40859
41220
  } catch {}
41221
+ try {
41222
+ deviceLink?.stop();
41223
+ } catch {}
40860
41224
  yield* exports_Effect.promise(async () => {
40861
41225
  try {
40862
41226
  const { chatSessionRegistry: chatSessionRegistry2 } = await Promise.resolve().then(() => (init_chat_session_registry(), exports_chat_session_registry));
@@ -41157,14 +41521,14 @@ var collectServiceEnv = () => {
41157
41521
  env.PATH = process.env.PATH;
41158
41522
  if (process.env.HOME)
41159
41523
  env.HOME = process.env.HOME;
41160
- if (process.env.MULTI_HOME)
41161
- env.MULTI_HOME = process.env.MULTI_HOME;
41162
- if (process.env.MULTI_API)
41163
- env.MULTI_API = process.env.MULTI_API;
41164
41524
  if (process.env.SHELL)
41165
41525
  env.SHELL = process.env.SHELL;
41166
41526
  if (process.env.LANG)
41167
41527
  env.LANG = process.env.LANG;
41528
+ for (const [k, v] of Object.entries(process.env)) {
41529
+ if (k.startsWith("MULTI_") && typeof v === "string" && v.length > 0)
41530
+ env[k] = v;
41531
+ }
41168
41532
  return env;
41169
41533
  };
41170
41534
  var ensureSupported = exports_Effect.fn("service.ensureSupported")(function* () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipers-dev/multi",
3
- "version": "0.64.0",
3
+ "version": "0.66.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "multi-agent": "./dist/index.js"