@shipers-dev/multi 0.65.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 +183 -5
  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();
@@ -36935,7 +36956,7 @@ class ChatPeer {
36935
36956
  return;
36936
36957
  const body = new TextEncoder().encode(JSON.stringify(obj));
36937
36958
  const frame = new Uint8Array(1 + body.byteLength);
36938
- frame[0] = FRAME_JSON;
36959
+ frame[0] = FRAME_JSON2;
36939
36960
  frame.set(body, 1);
36940
36961
  try {
36941
36962
  this.ws.send(frame);
@@ -36978,7 +36999,7 @@ class ChatPeer {
36978
36999
  this.persist();
36979
37000
  return;
36980
37001
  }
36981
- if (tag3 === FRAME_JSON) {
37002
+ if (tag3 === FRAME_JSON2) {
36982
37003
  try {
36983
37004
  const txt = new TextDecoder().decode(buf.subarray(1));
36984
37005
  const msg = JSON.parse(txt);
@@ -36988,7 +37009,7 @@ class ChatPeer {
36988
37009
  }
36989
37010
  }
36990
37011
  }
36991
- var FRAME_JSON = 0, FRAME_LORO = 1;
37012
+ var FRAME_JSON2 = 0, FRAME_LORO = 1;
36992
37013
  var init_chat_peer = __esm(() => {
36993
37014
  init_paths();
36994
37015
  init_chat_doc();
@@ -38853,7 +38874,7 @@ import { parseArgs } from "util";
38853
38874
  // package.json
38854
38875
  var package_default = {
38855
38876
  name: "@shipers-dev/multi",
38856
- version: "0.65.0",
38877
+ version: "0.66.0",
38857
38878
  type: "module",
38858
38879
  bin: {
38859
38880
  "multi-agent": "./dist/index.js"
@@ -39934,10 +39955,101 @@ import { homedir as homedir4 } from "os";
39934
39955
  import { join as join16 } from "path";
39935
39956
  init_adapter_pidfile();
39936
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
+ }
39937
40049
  // package.json
39938
40050
  var package_default2 = {
39939
40051
  name: "@shipers-dev/multi",
39940
- version: "0.65.0",
40052
+ version: "0.66.0",
39941
40053
  type: "module",
39942
40054
  bin: {
39943
40055
  "multi-agent": "./dist/index.js"
@@ -40931,6 +41043,69 @@ var daemonProgram = ({ cfg, apiUrl }) => exports_Effect.gen(function* () {
40931
41043
  cli_version: CLI_VERSION
40932
41044
  }, null, 2));
40933
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
+ }
40934
41109
  let tunnel;
40935
41110
  if (localMode) {
40936
41111
  tunnel = { child: null, url: `http://127.0.0.1:${port}` };
@@ -41043,6 +41218,9 @@ var daemonProgram = ({ cfg, apiUrl }) => exports_Effect.gen(function* () {
41043
41218
  try {
41044
41219
  tunnel?.child?.kill();
41045
41220
  } catch {}
41221
+ try {
41222
+ deviceLink?.stop();
41223
+ } catch {}
41046
41224
  yield* exports_Effect.promise(async () => {
41047
41225
  try {
41048
41226
  const { chatSessionRegistry: chatSessionRegistry2 } = await Promise.resolve().then(() => (init_chat_session_registry(), exports_chat_session_registry));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipers-dev/multi",
3
- "version": "0.65.0",
3
+ "version": "0.66.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "multi-agent": "./dist/index.js"