@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.
- package/dist/index.js +377 -13
- 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: "
|
|
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] =
|
|
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 ===
|
|
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
|
|
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: "
|
|
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.
|
|
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* () {
|