@shipers-dev/multi 0.63.0 → 0.65.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 +305 -31
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -17116,29 +17116,49 @@ async function ensureWorktree(workingDir, issueKey, issueId, opts) {
|
|
|
17116
17116
|
return { path: workingDir, branch: "", created: false };
|
|
17117
17117
|
}
|
|
17118
17118
|
ensureGitignoreEntry(workingDir, ".multi/");
|
|
17119
|
-
const
|
|
17120
|
-
const branch = `multi/${
|
|
17119
|
+
const slug = normalizeKey(opts?.worktreeName ?? issueKey);
|
|
17120
|
+
const branch = `multi/${slug}`;
|
|
17121
17121
|
const wtDir = join5(workingDir, ".multi", "worktrees");
|
|
17122
|
-
const wtPath = join5(wtDir,
|
|
17122
|
+
const wtPath = join5(wtDir, slug);
|
|
17123
|
+
let baseRef = "HEAD";
|
|
17124
|
+
const explicit = opts?.baseBranch || opts?.parentBranch || null;
|
|
17125
|
+
if (explicit) {
|
|
17126
|
+
const localOk = await branchExists(workingDir, explicit);
|
|
17127
|
+
if (localOk) {
|
|
17128
|
+
baseRef = explicit;
|
|
17129
|
+
} else {
|
|
17130
|
+
const fetched = await run3(workingDir, "git", ["fetch", "origin", `${explicit}:${explicit}`]);
|
|
17131
|
+
if (fetched.code === 0)
|
|
17132
|
+
baseRef = explicit;
|
|
17133
|
+
}
|
|
17134
|
+
}
|
|
17123
17135
|
if (existsSync3(wtPath)) {
|
|
17136
|
+
if (await isDirty(wtPath)) {
|
|
17137
|
+
throw new WorktreeDirtyError({ path: wtPath, branch, reason: "dirty" });
|
|
17138
|
+
}
|
|
17139
|
+
if (opts?.baseBranch) {
|
|
17140
|
+
const mergeBase = await run3(wtPath, "git", ["merge-base", branch, opts.baseBranch]);
|
|
17141
|
+
if (mergeBase.code === 0 && mergeBase.stdout) {
|
|
17142
|
+
const forkOnBase = await run3(workingDir, "git", ["merge-base", "--is-ancestor", mergeBase.stdout, opts.baseBranch]);
|
|
17143
|
+
if (forkOnBase.code === 1) {
|
|
17144
|
+
const baseHead = await run3(workingDir, "git", ["rev-parse", "--verify", `${opts.baseBranch}^{commit}`]);
|
|
17145
|
+
throw new WorktreeDirtyError({
|
|
17146
|
+
path: wtPath,
|
|
17147
|
+
branch,
|
|
17148
|
+
reason: "base_mismatch",
|
|
17149
|
+
expectedBase: opts.baseBranch,
|
|
17150
|
+
actualBase: baseHead.code === 0 ? baseHead.stdout : mergeBase.stdout
|
|
17151
|
+
});
|
|
17152
|
+
}
|
|
17153
|
+
}
|
|
17154
|
+
}
|
|
17124
17155
|
if (issueId)
|
|
17125
|
-
setWorktreeIndexEntry(workingDir,
|
|
17156
|
+
setWorktreeIndexEntry(workingDir, slug, issueId);
|
|
17126
17157
|
return { path: wtPath, branch, created: false };
|
|
17127
17158
|
}
|
|
17128
17159
|
try {
|
|
17129
17160
|
mkdirSync3(wtDir, { recursive: true });
|
|
17130
17161
|
} catch {}
|
|
17131
|
-
let baseRef = "HEAD";
|
|
17132
|
-
if (opts?.parentBranch) {
|
|
17133
|
-
const localOk = await branchExists(workingDir, opts.parentBranch);
|
|
17134
|
-
if (localOk) {
|
|
17135
|
-
baseRef = opts.parentBranch;
|
|
17136
|
-
} else {
|
|
17137
|
-
const fetched = await run3(workingDir, "git", ["fetch", "origin", `${opts.parentBranch}:${opts.parentBranch}`]);
|
|
17138
|
-
if (fetched.code === 0)
|
|
17139
|
-
baseRef = opts.parentBranch;
|
|
17140
|
-
}
|
|
17141
|
-
}
|
|
17142
17162
|
const exists4 = await branchExists(workingDir, branch);
|
|
17143
17163
|
const args2 = exists4 ? ["worktree", "add", wtPath, branch] : ["worktree", "add", "-b", branch, wtPath, baseRef];
|
|
17144
17164
|
const r = await run3(workingDir, "git", args2);
|
|
@@ -17147,7 +17167,7 @@ async function ensureWorktree(workingDir, issueKey, issueId, opts) {
|
|
|
17147
17167
|
}
|
|
17148
17168
|
await linkIgnoredFiles(workingDir, wtPath);
|
|
17149
17169
|
if (issueId)
|
|
17150
|
-
setWorktreeIndexEntry(workingDir,
|
|
17170
|
+
setWorktreeIndexEntry(workingDir, slug, issueId);
|
|
17151
17171
|
return { path: wtPath, branch, created: true };
|
|
17152
17172
|
}
|
|
17153
17173
|
async function linkIgnoredFiles(workingDir, wtPath) {
|
|
@@ -17274,7 +17294,17 @@ async function squashMergeChild(wtPath, childBranch, childKey) {
|
|
|
17274
17294
|
result.message = `${childKey} squash-merged (${stagedFiles.length} file${stagedFiles.length === 1 ? "" : "s"})`;
|
|
17275
17295
|
return result;
|
|
17276
17296
|
}
|
|
17277
|
-
var
|
|
17297
|
+
var WorktreeDirtyError;
|
|
17298
|
+
var init_worktree = __esm(() => {
|
|
17299
|
+
WorktreeDirtyError = class WorktreeDirtyError extends Error {
|
|
17300
|
+
details;
|
|
17301
|
+
code = "E_WORKTREE_DIRTY";
|
|
17302
|
+
constructor(details) {
|
|
17303
|
+
super(`worktree dirty or base-mismatched at ${details.path} (${details.reason})`);
|
|
17304
|
+
this.details = details;
|
|
17305
|
+
}
|
|
17306
|
+
};
|
|
17307
|
+
});
|
|
17278
17308
|
|
|
17279
17309
|
// ../../node_modules/zod/v4/core/core.js
|
|
17280
17310
|
function $constructor(name, initializer, params) {
|
|
@@ -34022,7 +34052,8 @@ var init_streams = __esm(() => {
|
|
|
34022
34052
|
"stopped",
|
|
34023
34053
|
"queued",
|
|
34024
34054
|
"worktree_created",
|
|
34025
|
-
"worktree_error"
|
|
34055
|
+
"worktree_error",
|
|
34056
|
+
"worktree_dirty"
|
|
34026
34057
|
];
|
|
34027
34058
|
StreamEventTypeSchema = exports_external.enum(STREAM_EVENT_TYPES);
|
|
34028
34059
|
StreamEventInputSchema = exports_external.object({
|
|
@@ -34220,7 +34251,7 @@ function parsePlanBlocks(text) {
|
|
|
34220
34251
|
}
|
|
34221
34252
|
return { actions, errors: errors3 };
|
|
34222
34253
|
}
|
|
34223
|
-
var PLAN_SCHEMA_VERSION =
|
|
34254
|
+
var PLAN_SCHEMA_VERSION = 11, Priority, AssigneeType, IssueStatus, SessionRole, SkillFile, EvalPolicy, PlanActionSchema, PlanEnvelopeSchema, UiBlockSchema, UI_FENCE_RE, FENCE_RE;
|
|
34224
34255
|
var init_plans = __esm(() => {
|
|
34225
34256
|
init_zod();
|
|
34226
34257
|
Priority = exports_external.enum(["low", "medium", "high"]);
|
|
@@ -34243,6 +34274,8 @@ var init_plans = __esm(() => {
|
|
|
34243
34274
|
priority: Priority.optional(),
|
|
34244
34275
|
assignee_type: AssigneeType.optional(),
|
|
34245
34276
|
assignee_id: exports_external.string().optional(),
|
|
34277
|
+
base_ref: exports_external.string().min(1).max(200).optional(),
|
|
34278
|
+
worktree: exports_external.string().min(1).max(60).regex(/^[a-z0-9][a-z0-9_\-\/]*$/i).optional(),
|
|
34246
34279
|
parent_id: exports_external.string().optional(),
|
|
34247
34280
|
blocked_by: exports_external.array(exports_external.string().min(1)).optional(),
|
|
34248
34281
|
await_children: exports_external.boolean().optional(),
|
|
@@ -34853,9 +34886,54 @@ async function handleRunTask(apiUrl, deviceId, task, detected, ctx) {
|
|
|
34853
34886
|
const ISSUE_BASE = tenantWsId && projectId ? `${apiUrl}/api/workspaces/${tenantWsId}/projects/${projectId}/issues/${issueId}` : null;
|
|
34854
34887
|
let workingDir = baseWorkingDir;
|
|
34855
34888
|
let worktreeBranch = "";
|
|
34856
|
-
|
|
34889
|
+
const inlineMode = task.inline_mode === true;
|
|
34890
|
+
const baseBranch = task.base_branch ?? null;
|
|
34891
|
+
const worktreeName = task.worktree_name ?? null;
|
|
34892
|
+
let inlineRestoreHead = null;
|
|
34893
|
+
const blockOnDirty = async (reason, extra = {}) => {
|
|
34894
|
+
await postStream(apiUrl, issueId, "worktree_dirty", { reason, ...extra });
|
|
34895
|
+
if (tenantWsId) {
|
|
34896
|
+
try {
|
|
34897
|
+
await patchIssueStatus(apiUrl, tenantWsId, issueId, "blocked");
|
|
34898
|
+
} catch {}
|
|
34899
|
+
}
|
|
34900
|
+
await postStream(apiUrl, issueId, "run_finished", { stopReason: "blocked", duration_ms: 0 });
|
|
34901
|
+
};
|
|
34902
|
+
if (baseWorkingDir && inlineMode) {
|
|
34903
|
+
try {
|
|
34904
|
+
const status3 = Bun.spawnSync(["git", "status", "--porcelain"], { cwd: baseWorkingDir, stdout: "pipe" });
|
|
34905
|
+
const dirty = (status3.stdout?.toString() || "").trim().length > 0;
|
|
34906
|
+
if (dirty) {
|
|
34907
|
+
await blockOnDirty("inline_dirty", { path: baseWorkingDir });
|
|
34908
|
+
return;
|
|
34909
|
+
}
|
|
34910
|
+
if (baseBranch) {
|
|
34911
|
+
const origSymRef = Bun.spawnSync(["git", "symbolic-ref", "--quiet", "HEAD"], { cwd: baseWorkingDir, stdout: "pipe" });
|
|
34912
|
+
if (origSymRef.exitCode === 0) {
|
|
34913
|
+
inlineRestoreHead = (origSymRef.stdout?.toString() || "").trim().replace(/^refs\/heads\//, "") || null;
|
|
34914
|
+
} else {
|
|
34915
|
+
const origSha = Bun.spawnSync(["git", "rev-parse", "HEAD"], { cwd: baseWorkingDir, stdout: "pipe" });
|
|
34916
|
+
inlineRestoreHead = (origSha.stdout?.toString() || "").trim() || null;
|
|
34917
|
+
}
|
|
34918
|
+
const co = Bun.spawnSync(["git", "checkout", baseBranch], { cwd: baseWorkingDir, stdout: "pipe", stderr: "pipe" });
|
|
34919
|
+
if (co.exitCode !== 0) {
|
|
34920
|
+
await postStream(apiUrl, issueId, "worktree_error", { mode: "inline", message: co.stderr?.toString() || "checkout failed" });
|
|
34921
|
+
await blockOnDirty("inline_checkout_failed", { baseBranch });
|
|
34922
|
+
return;
|
|
34923
|
+
}
|
|
34924
|
+
worktreeBranch = baseBranch;
|
|
34925
|
+
}
|
|
34926
|
+
await postStream(apiUrl, issueId, "worktree_created", { path: baseWorkingDir, branch: worktreeBranch, reused: true, inline: true });
|
|
34927
|
+
} catch (e) {
|
|
34928
|
+
await postStream(apiUrl, issueId, "worktree_error", { mode: "inline", message: fmtError(e) });
|
|
34929
|
+
}
|
|
34930
|
+
} else if (baseWorkingDir) {
|
|
34857
34931
|
try {
|
|
34858
|
-
const wt = await ensureWorktree(baseWorkingDir, task.key || issueId, issueId, {
|
|
34932
|
+
const wt = await ensureWorktree(baseWorkingDir, task.key || issueId, issueId, {
|
|
34933
|
+
baseBranch: baseBranch ?? undefined,
|
|
34934
|
+
parentBranch: task.parent_branch ?? undefined,
|
|
34935
|
+
worktreeName: worktreeName ?? undefined
|
|
34936
|
+
});
|
|
34859
34937
|
workingDir = wt.path;
|
|
34860
34938
|
worktreeBranch = wt.branch;
|
|
34861
34939
|
await postStream(apiUrl, issueId, "worktree_created", { path: wt.path, branch: wt.branch, reused: !wt.created });
|
|
@@ -34867,6 +34945,10 @@ async function handleRunTask(apiUrl, deviceId, task, detected, ctx) {
|
|
|
34867
34945
|
}
|
|
34868
34946
|
}
|
|
34869
34947
|
} catch (e) {
|
|
34948
|
+
if (e?.code === "E_WORKTREE_DIRTY") {
|
|
34949
|
+
await blockOnDirty("worktree_dirty", { details: e.details });
|
|
34950
|
+
return;
|
|
34951
|
+
}
|
|
34870
34952
|
await postStream(apiUrl, issueId, "worktree_error", { message: fmtError(e) });
|
|
34871
34953
|
}
|
|
34872
34954
|
}
|
|
@@ -35110,6 +35192,10 @@ _${bits.join(" · ")}_`);
|
|
|
35110
35192
|
const acpCapable = detected.filter((d) => d.type === "claude-code");
|
|
35111
35193
|
const useAcp = preferType !== "pi" && acpCapable.length > 0 && process.env.MULTI_LEGACY !== "1";
|
|
35112
35194
|
const useAcpx = !useAcp && preferType && ["pi", "codex", "openclaw"].includes(preferType) && process.env.MULTI_LEGACY !== "1";
|
|
35195
|
+
let issueHistoryBlock = "";
|
|
35196
|
+
if (tenantWsId && ISSUE_BASE) {
|
|
35197
|
+
issueHistoryBlock = await fetchIssueHistory(apiUrl, tenantWsId, projectId, issueId, log3);
|
|
35198
|
+
}
|
|
35113
35199
|
try {
|
|
35114
35200
|
if (useAcp) {
|
|
35115
35201
|
const issueContext = `## Issue ${task.key}: ${task.title}${task.description ? `
|
|
@@ -35127,6 +35213,20 @@ ${task.description}` : ""}`;
|
|
|
35127
35213
|
${cleanFollowup}`;
|
|
35128
35214
|
} else {
|
|
35129
35215
|
userPart = stripSelfMention(issueContext, preferType);
|
|
35216
|
+
userPart += `
|
|
35217
|
+
|
|
35218
|
+
---
|
|
35219
|
+
|
|
35220
|
+
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).`;
|
|
35221
|
+
}
|
|
35222
|
+
if (issueHistoryBlock) {
|
|
35223
|
+
userPart += `
|
|
35224
|
+
|
|
35225
|
+
---
|
|
35226
|
+
|
|
35227
|
+
## Issue history (prior activity)
|
|
35228
|
+
|
|
35229
|
+
${issueHistoryBlock}`;
|
|
35130
35230
|
}
|
|
35131
35231
|
if (attachmentRefs.length) {
|
|
35132
35232
|
const lines = attachmentRefs.map((a) => `- ${a.filename}: ${a.path}`).join(`
|
|
@@ -35145,6 +35245,7 @@ Note: if (and only if) you produce binary or large artifact outputs (screenshots
|
|
|
35145
35245
|
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.`;
|
|
35146
35246
|
}
|
|
35147
35247
|
let preamble = "";
|
|
35248
|
+
let preambleFailed = false;
|
|
35148
35249
|
try {
|
|
35149
35250
|
if (tenantWsId) {
|
|
35150
35251
|
const agentRes = await apiClient.get(`${apiUrl}/api/workspaces/${tenantWsId}/agents/${task.agent_id}`);
|
|
@@ -35174,7 +35275,9 @@ ${body}
|
|
|
35174
35275
|
}
|
|
35175
35276
|
}
|
|
35176
35277
|
} catch (e) {
|
|
35278
|
+
preambleFailed = true;
|
|
35177
35279
|
log3(`preamble fetch failed: ${String(e)}`);
|
|
35280
|
+
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)}`);
|
|
35178
35281
|
}
|
|
35179
35282
|
preamble += await buildPlanningPreamble(apiUrl, task);
|
|
35180
35283
|
const prompt = preamble ? `${preamble}
|
|
@@ -35255,7 +35358,10 @@ ${body}
|
|
|
35255
35358
|
}
|
|
35256
35359
|
}
|
|
35257
35360
|
}
|
|
35258
|
-
} catch {
|
|
35361
|
+
} catch (e) {
|
|
35362
|
+
log3(`preamble fetch failed (acpx): ${String(e)}`);
|
|
35363
|
+
await postBoundChatMessage(apiUrl, task, `⚠️ System: agent preamble fetch failed — running without role definition. Error: ${String(e).slice(0, 200)}`);
|
|
35364
|
+
}
|
|
35259
35365
|
preamble += await buildPlanningPreamble(apiUrl, task);
|
|
35260
35366
|
const issueContext = `## Issue ${task.key}: ${task.title}${task.description ? `
|
|
35261
35367
|
|
|
@@ -35272,6 +35378,20 @@ ${task.description}` : ""}`;
|
|
|
35272
35378
|
${cleanFollowup}`;
|
|
35273
35379
|
} else {
|
|
35274
35380
|
userPart = stripSelfMention(issueContext, preferType);
|
|
35381
|
+
userPart += `
|
|
35382
|
+
|
|
35383
|
+
---
|
|
35384
|
+
|
|
35385
|
+
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).`;
|
|
35386
|
+
}
|
|
35387
|
+
if (issueHistoryBlock) {
|
|
35388
|
+
userPart += `
|
|
35389
|
+
|
|
35390
|
+
---
|
|
35391
|
+
|
|
35392
|
+
## Issue history (prior activity)
|
|
35393
|
+
|
|
35394
|
+
${issueHistoryBlock}`;
|
|
35275
35395
|
}
|
|
35276
35396
|
if (attachmentRefs.length) {
|
|
35277
35397
|
const lines = attachmentRefs.map((a) => `- ${a.filename}: ${a.path}`).join(`
|
|
@@ -35398,6 +35518,58 @@ ${userPart}` : userPart;
|
|
|
35398
35518
|
await apiClient.post(`${ISSUE_BASE}/fail`, {});
|
|
35399
35519
|
log3(` ✗ ${task.key} failed: ${msg}`);
|
|
35400
35520
|
}
|
|
35521
|
+
} finally {
|
|
35522
|
+
if (inlineMode && inlineRestoreHead && baseWorkingDir) {
|
|
35523
|
+
try {
|
|
35524
|
+
Bun.spawnSync(["git", "checkout", inlineRestoreHead], { cwd: baseWorkingDir, stdout: "pipe", stderr: "pipe" });
|
|
35525
|
+
} catch {}
|
|
35526
|
+
}
|
|
35527
|
+
}
|
|
35528
|
+
}
|
|
35529
|
+
async function fetchIssueHistory(apiUrl, tenantWsId, projectId, issueId, log4) {
|
|
35530
|
+
const MAX_HISTORY_CHARS = 6000;
|
|
35531
|
+
try {
|
|
35532
|
+
const issueBase = `${apiUrl}/api/workspaces/${tenantWsId}/projects/${projectId}/issues/${issueId}`;
|
|
35533
|
+
const res = await apiClient.get(`${issueBase}/activity`);
|
|
35534
|
+
const activities = Array.isArray(res.data?.results) ? res.data.results : Array.isArray(res.data) ? res.data : [];
|
|
35535
|
+
if (!activities.length)
|
|
35536
|
+
return "";
|
|
35537
|
+
const lines = [];
|
|
35538
|
+
const recent = activities.slice(-20).reverse();
|
|
35539
|
+
for (const act of recent) {
|
|
35540
|
+
const action = act.action || "activity";
|
|
35541
|
+
const actor = act.actor_name || act.actor_id || "system";
|
|
35542
|
+
const ts = act.created_at ? new Date(act.created_at * 1000).toISOString().slice(0, 16) : "";
|
|
35543
|
+
let line = `- **${actor}** ${action}`;
|
|
35544
|
+
if (ts)
|
|
35545
|
+
line += ` _${ts}_`;
|
|
35546
|
+
if (act.details) {
|
|
35547
|
+
try {
|
|
35548
|
+
const d = typeof act.details === "string" ? JSON.parse(act.details) : act.details;
|
|
35549
|
+
if (d.message)
|
|
35550
|
+
line += `: ${String(d.message).slice(0, 200)}`;
|
|
35551
|
+
else if (d.title)
|
|
35552
|
+
line += `: ${String(d.title).slice(0, 200)}`;
|
|
35553
|
+
else if (d.from && d.to)
|
|
35554
|
+
line += `: ${d.from} → ${d.to}`;
|
|
35555
|
+
else if (d.text)
|
|
35556
|
+
line += `: ${String(d.text).slice(0, 200)}`;
|
|
35557
|
+
} catch {}
|
|
35558
|
+
}
|
|
35559
|
+
lines.push(line);
|
|
35560
|
+
}
|
|
35561
|
+
const block = lines.join(`
|
|
35562
|
+
`);
|
|
35563
|
+
if (block.length > MAX_HISTORY_CHARS) {
|
|
35564
|
+
log4(` issue history truncated: ${block.length} → ${MAX_HISTORY_CHARS} chars`);
|
|
35565
|
+
return block.slice(0, MAX_HISTORY_CHARS) + `
|
|
35566
|
+
|
|
35567
|
+
_… truncated_`;
|
|
35568
|
+
}
|
|
35569
|
+
return block;
|
|
35570
|
+
} catch (e) {
|
|
35571
|
+
log4(` issue history fetch failed: ${String(e).slice(0, 200)}`);
|
|
35572
|
+
return "";
|
|
35401
35573
|
}
|
|
35402
35574
|
}
|
|
35403
35575
|
async function buildPlanningPreamble(apiUrl, task, _wsId) {
|
|
@@ -35598,7 +35770,7 @@ async function executePlanActions(apiUrl, parentTask, actions, ctx, parseErrors
|
|
|
35598
35770
|
}
|
|
35599
35771
|
}
|
|
35600
35772
|
} else if (a.type === "delegate") {
|
|
35601
|
-
const res = await apiClient.post(mutateUrl, { action: "update", id: a.id, assignee_type: "agent", assignee_id: a.assignee_id, status: "
|
|
35773
|
+
const res = await apiClient.post(mutateUrl, { action: "update", id: a.id, assignee_type: "agent", assignee_id: a.assignee_id, status: "in_progress" }, { headers });
|
|
35602
35774
|
if (!res.success) {
|
|
35603
35775
|
lines.push(`- [err] delegate ${a.id}: ${res.error || res.status}`);
|
|
35604
35776
|
results.push({ type: "delegate", status: "error", error: String(res.error || res.status), label: a.id });
|
|
@@ -37035,7 +37207,7 @@ async function executeChatPlanActions(actionsIn, parseErrors, ctx) {
|
|
|
37035
37207
|
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 });
|
|
37036
37208
|
tally(true);
|
|
37037
37209
|
} else if (a.type === "delegate") {
|
|
37038
|
-
const res = await apiClient.post(mutateUrl, { action: "update", id: a.id, assignee_type: "agent", assignee_id: a.assignee_id, status: "
|
|
37210
|
+
const res = await apiClient.post(mutateUrl, { action: "update", id: a.id, assignee_type: "agent", assignee_id: a.assignee_id, status: "in_progress" }, { headers });
|
|
37039
37211
|
if (!res.success) {
|
|
37040
37212
|
lines.push(`- [err] delegate ${a.id}: ${res.error || res.status}`);
|
|
37041
37213
|
results.push({ type: "delegate", status: "error", error: String(res.error || res.status), label: a.id });
|
|
@@ -38681,7 +38853,7 @@ import { parseArgs } from "util";
|
|
|
38681
38853
|
// package.json
|
|
38682
38854
|
var package_default = {
|
|
38683
38855
|
name: "@shipers-dev/multi",
|
|
38684
|
-
version: "0.
|
|
38856
|
+
version: "0.65.0",
|
|
38685
38857
|
type: "module",
|
|
38686
38858
|
bin: {
|
|
38687
38859
|
"multi-agent": "./dist/index.js"
|
|
@@ -39762,6 +39934,66 @@ import { homedir as homedir4 } from "os";
|
|
|
39762
39934
|
import { join as join16 } from "path";
|
|
39763
39935
|
init_adapter_pidfile();
|
|
39764
39936
|
init_errors();
|
|
39937
|
+
// package.json
|
|
39938
|
+
var package_default2 = {
|
|
39939
|
+
name: "@shipers-dev/multi",
|
|
39940
|
+
version: "0.65.0",
|
|
39941
|
+
type: "module",
|
|
39942
|
+
bin: {
|
|
39943
|
+
"multi-agent": "./dist/index.js"
|
|
39944
|
+
},
|
|
39945
|
+
files: [
|
|
39946
|
+
"dist"
|
|
39947
|
+
],
|
|
39948
|
+
scripts: {
|
|
39949
|
+
dev: "MULTI_HOME=${MULTI_HOME:-$HOME/.multi-dev} MULTI_API=${MULTI_API:-http://127.0.0.1:8787} bun run src/index.ts connect",
|
|
39950
|
+
build: "bun build src/index.ts --outdir=dist --target=node --sourcemap=none --external undici --external loro-crdt && node scripts/post-build.cjs",
|
|
39951
|
+
prepublishOnly: "bun run build"
|
|
39952
|
+
},
|
|
39953
|
+
dependencies: {
|
|
39954
|
+
"@agentclientprotocol/claude-agent-acp": "^0.31.0",
|
|
39955
|
+
"@agentclientprotocol/sdk": "^0.20.0",
|
|
39956
|
+
"@effect/platform-node": "^0.103.0",
|
|
39957
|
+
effect: "^3.21.2",
|
|
39958
|
+
"loro-crdt": "^1.12.1",
|
|
39959
|
+
undici: "^7.0.0"
|
|
39960
|
+
},
|
|
39961
|
+
devDependencies: {
|
|
39962
|
+
"@multi/lib": "workspace:*"
|
|
39963
|
+
}
|
|
39964
|
+
};
|
|
39965
|
+
|
|
39966
|
+
// src/_impl/daemon-main.ts
|
|
39967
|
+
var CLI_VERSION = package_default2.version;
|
|
39968
|
+
function findBunBinary() {
|
|
39969
|
+
const tryPath = (p) => {
|
|
39970
|
+
try {
|
|
39971
|
+
return existsSync16(p) ? p : null;
|
|
39972
|
+
} catch {
|
|
39973
|
+
return null;
|
|
39974
|
+
}
|
|
39975
|
+
};
|
|
39976
|
+
if (process.execPath && process.execPath.endsWith("/bun")) {
|
|
39977
|
+
const hit = tryPath(process.execPath);
|
|
39978
|
+
if (hit)
|
|
39979
|
+
return hit;
|
|
39980
|
+
}
|
|
39981
|
+
const fromWhich = Bun.which?.("bun");
|
|
39982
|
+
if (fromWhich)
|
|
39983
|
+
return fromWhich;
|
|
39984
|
+
const candidates = [
|
|
39985
|
+
join16(homedir4(), ".bun", "bin", "bun"),
|
|
39986
|
+
"/opt/homebrew/bin/bun",
|
|
39987
|
+
"/usr/local/bin/bun",
|
|
39988
|
+
"/home/linuxbrew/.linuxbrew/bin/bun"
|
|
39989
|
+
];
|
|
39990
|
+
for (const c of candidates) {
|
|
39991
|
+
const hit = tryPath(c);
|
|
39992
|
+
if (hit)
|
|
39993
|
+
return hit;
|
|
39994
|
+
}
|
|
39995
|
+
return null;
|
|
39996
|
+
}
|
|
39765
39997
|
var MULTI_DIR5 = join16(homedir4(), ".multi");
|
|
39766
39998
|
var PID_PATH2 = join16(MULTI_DIR5, "agent.pid");
|
|
39767
39999
|
var PORT_PATH2 = join16(MULTI_DIR5, "agent.port");
|
|
@@ -40132,7 +40364,7 @@ var daemonProgram = ({ cfg, apiUrl }) => exports_Effect.gen(function* () {
|
|
|
40132
40364
|
}
|
|
40133
40365
|
const route = () => {
|
|
40134
40366
|
if (url2.pathname === "/health")
|
|
40135
|
-
return Response.json({ ok: true, device_id: cfg.deviceId });
|
|
40367
|
+
return Response.json({ ok: true, device_id: cfg.deviceId, cli_version: CLI_VERSION });
|
|
40136
40368
|
if (url2.pathname === "/files" && req.method === "GET") {
|
|
40137
40369
|
if (req.headers.get("authorization") !== expectedAuth)
|
|
40138
40370
|
return new Response("unauthorized", { status: 401 });
|
|
@@ -40539,6 +40771,47 @@ var daemonProgram = ({ cfg, apiUrl }) => exports_Effect.gen(function* () {
|
|
|
40539
40771
|
}
|
|
40540
40772
|
})();
|
|
40541
40773
|
}
|
|
40774
|
+
if (url2.pathname === "/upgrade" && req.method === "POST") {
|
|
40775
|
+
if (req.headers.get("authorization") !== expectedAuth)
|
|
40776
|
+
return new Response("unauthorized", { status: 401 });
|
|
40777
|
+
return (async () => {
|
|
40778
|
+
const bunBin = findBunBinary();
|
|
40779
|
+
if (!bunBin) {
|
|
40780
|
+
return Response.json({ error: "bun binary not found; run `bun add -g @shipers-dev/multi` manually" }, { status: 503 });
|
|
40781
|
+
}
|
|
40782
|
+
let body = {};
|
|
40783
|
+
try {
|
|
40784
|
+
body = await req.json();
|
|
40785
|
+
} catch {}
|
|
40786
|
+
const spec = body.target ? `@shipers-dev/multi@${body.target}` : "@shipers-dev/multi";
|
|
40787
|
+
log3(`[upgrade] spawning ${bunBin} add -g ${spec}`);
|
|
40788
|
+
const child = Bun.spawn([bunBin, "add", "-g", spec], {
|
|
40789
|
+
stdout: "pipe",
|
|
40790
|
+
stderr: "pipe",
|
|
40791
|
+
stdin: "ignore"
|
|
40792
|
+
});
|
|
40793
|
+
(async () => {
|
|
40794
|
+
try {
|
|
40795
|
+
const stdoutTxt = await new Response(child.stdout).text();
|
|
40796
|
+
const stderrTxt = await new Response(child.stderr).text();
|
|
40797
|
+
const code = await child.exited;
|
|
40798
|
+
if (stdoutTxt.trim())
|
|
40799
|
+
log3(`[upgrade] stdout: ${stdoutTxt.trim()}`);
|
|
40800
|
+
if (stderrTxt.trim())
|
|
40801
|
+
log3(`[upgrade] stderr: ${stderrTxt.trim()}`);
|
|
40802
|
+
if (code === 0) {
|
|
40803
|
+
log3("[upgrade] success; exiting so service manager respawns with new binary");
|
|
40804
|
+
setTimeout(() => process.exit(0), 500);
|
|
40805
|
+
} else {
|
|
40806
|
+
log3(`[upgrade] failed with exit code ${code}`);
|
|
40807
|
+
}
|
|
40808
|
+
} catch (e) {
|
|
40809
|
+
log3(`[upgrade] error: ${e.message}`);
|
|
40810
|
+
}
|
|
40811
|
+
})();
|
|
40812
|
+
return Response.json({ accepted: true, current_version: CLI_VERSION, target: spec }, { status: 202 });
|
|
40813
|
+
})();
|
|
40814
|
+
}
|
|
40542
40815
|
if (url2.pathname === "/stop" && req.method === "POST") {
|
|
40543
40816
|
if (req.headers.get("authorization") !== expectedAuth)
|
|
40544
40817
|
return new Response("unauthorized", { status: 401 });
|
|
@@ -40654,7 +40927,8 @@ var daemonProgram = ({ cfg, apiUrl }) => exports_Effect.gen(function* () {
|
|
|
40654
40927
|
device_id: cfg.deviceId,
|
|
40655
40928
|
workspace_id: cfg.workspaceId,
|
|
40656
40929
|
api_url: apiUrl,
|
|
40657
|
-
pid: process.pid
|
|
40930
|
+
pid: process.pid,
|
|
40931
|
+
cli_version: CLI_VERSION
|
|
40658
40932
|
}, null, 2));
|
|
40659
40933
|
} catch {}
|
|
40660
40934
|
let tunnel;
|
|
@@ -41069,14 +41343,14 @@ var collectServiceEnv = () => {
|
|
|
41069
41343
|
env.PATH = process.env.PATH;
|
|
41070
41344
|
if (process.env.HOME)
|
|
41071
41345
|
env.HOME = process.env.HOME;
|
|
41072
|
-
if (process.env.MULTI_HOME)
|
|
41073
|
-
env.MULTI_HOME = process.env.MULTI_HOME;
|
|
41074
|
-
if (process.env.MULTI_API)
|
|
41075
|
-
env.MULTI_API = process.env.MULTI_API;
|
|
41076
41346
|
if (process.env.SHELL)
|
|
41077
41347
|
env.SHELL = process.env.SHELL;
|
|
41078
41348
|
if (process.env.LANG)
|
|
41079
41349
|
env.LANG = process.env.LANG;
|
|
41350
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
41351
|
+
if (k.startsWith("MULTI_") && typeof v === "string" && v.length > 0)
|
|
41352
|
+
env[k] = v;
|
|
41353
|
+
}
|
|
41080
41354
|
return env;
|
|
41081
41355
|
};
|
|
41082
41356
|
var ensureSupported = exports_Effect.fn("service.ensureSupported")(function* () {
|