@shipers-dev/multi 0.23.0 → 0.23.1
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 +99 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15000,7 +15000,7 @@ import { parseArgs as parseArgs2 } from "util";
|
|
|
15000
15000
|
// package.json
|
|
15001
15001
|
var package_default = {
|
|
15002
15002
|
name: "@shipers-dev/multi",
|
|
15003
|
-
version: "0.23.
|
|
15003
|
+
version: "0.23.1",
|
|
15004
15004
|
type: "module",
|
|
15005
15005
|
bin: {
|
|
15006
15006
|
"multi-agent": "./dist/index.js"
|
|
@@ -31195,6 +31195,41 @@ class RequestError extends Error {
|
|
|
31195
31195
|
// src/_impl/acp-runner.ts
|
|
31196
31196
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync4 } from "fs";
|
|
31197
31197
|
import { dirname as dirname5, join as join6 } from "path";
|
|
31198
|
+
|
|
31199
|
+
// src/_impl/workspace-mutex.ts
|
|
31200
|
+
var tails = new Map;
|
|
31201
|
+
var WRITE_TOOLS = new Set([
|
|
31202
|
+
"Edit",
|
|
31203
|
+
"Write",
|
|
31204
|
+
"Bash",
|
|
31205
|
+
"NotebookEdit",
|
|
31206
|
+
"mcp__acp__Edit",
|
|
31207
|
+
"mcp__acp__Write"
|
|
31208
|
+
]);
|
|
31209
|
+
function isWriteTool(name) {
|
|
31210
|
+
if (!name)
|
|
31211
|
+
return false;
|
|
31212
|
+
return WRITE_TOOLS.has(name);
|
|
31213
|
+
}
|
|
31214
|
+
async function withWorkspaceWrite(workspaceId, fn2) {
|
|
31215
|
+
const prev = tails.get(workspaceId) ?? Promise.resolve();
|
|
31216
|
+
let release;
|
|
31217
|
+
const next = new Promise((res) => {
|
|
31218
|
+
release = res;
|
|
31219
|
+
});
|
|
31220
|
+
tails.set(workspaceId, prev.then(() => next));
|
|
31221
|
+
try {
|
|
31222
|
+
await prev;
|
|
31223
|
+
return await fn2();
|
|
31224
|
+
} finally {
|
|
31225
|
+
release();
|
|
31226
|
+
if (tails.get(workspaceId) === prev.then(() => next)) {
|
|
31227
|
+
tails.delete(workspaceId);
|
|
31228
|
+
}
|
|
31229
|
+
}
|
|
31230
|
+
}
|
|
31231
|
+
|
|
31232
|
+
// src/_impl/acp-runner.ts
|
|
31198
31233
|
function ensureBypassPermissions(cwd) {
|
|
31199
31234
|
try {
|
|
31200
31235
|
const dir = join6(cwd, ".claude");
|
|
@@ -31429,8 +31464,13 @@ ${entries2}` } });
|
|
|
31429
31464
|
const alwaysOpt = opts2.find((op) => /always/i.test(op.name || "") || /allow_always/i.test(op.kind || ""));
|
|
31430
31465
|
const allowOpt = opts2.find((op) => /allow/i.test(op.kind || "") || /allow/i.test(op.name || ""));
|
|
31431
31466
|
const chosen = alwaysOpt || allowOpt;
|
|
31432
|
-
if (chosen)
|
|
31467
|
+
if (chosen) {
|
|
31468
|
+
const toolName = tc.title || tc.toolName || "";
|
|
31469
|
+
if (o.workspaceId && isWriteTool(toolName)) {
|
|
31470
|
+
return await withWorkspaceWrite(o.workspaceId, async () => ({ outcome: { outcome: "selected", optionId: chosen.optionId } }));
|
|
31471
|
+
}
|
|
31433
31472
|
return { outcome: { outcome: "selected", optionId: chosen.optionId } };
|
|
31473
|
+
}
|
|
31434
31474
|
}
|
|
31435
31475
|
if (toolKey && allowCache.has(toolKey)) {
|
|
31436
31476
|
const allowOpt = params.options.find((op) => /allow/i.test(op.kind || "") || /allow/i.test(op.name || ""));
|
|
@@ -32137,6 +32177,39 @@ var ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
|
32137
32177
|
var ID_LENGTH = 21;
|
|
32138
32178
|
var generate = customAlphabet(ALPHABET, ID_LENGTH);
|
|
32139
32179
|
var ID_REGEX = new RegExp(`^[${ALPHABET}]+$`);
|
|
32180
|
+
// ../lib/agent-workspaces.ts
|
|
32181
|
+
var AGENT_WORKSPACE_STATUSES = [
|
|
32182
|
+
"initializing",
|
|
32183
|
+
"setup_pending",
|
|
32184
|
+
"ready",
|
|
32185
|
+
"archived"
|
|
32186
|
+
];
|
|
32187
|
+
var AgentWorkspaceStatusSchema = exports_external.enum(AGENT_WORKSPACE_STATUSES);
|
|
32188
|
+
var AgentWorkspaceSchema = exports_external.object({
|
|
32189
|
+
id: exports_external.string(),
|
|
32190
|
+
project_id: exports_external.string(),
|
|
32191
|
+
issue_id: exports_external.string().nullable(),
|
|
32192
|
+
branch: exports_external.string(),
|
|
32193
|
+
worktree_path: exports_external.string().nullable(),
|
|
32194
|
+
device_id: exports_external.string().nullable(),
|
|
32195
|
+
status: AgentWorkspaceStatusSchema,
|
|
32196
|
+
agent_session_id: exports_external.string().nullable(),
|
|
32197
|
+
runtime: exports_external.string().nullable(),
|
|
32198
|
+
created_at: exports_external.number(),
|
|
32199
|
+
archived_at: exports_external.number().nullable()
|
|
32200
|
+
}).meta({ id: "AgentWorkspace" });
|
|
32201
|
+
var CreateAgentWorkspaceSchema = exports_external.object({
|
|
32202
|
+
project_id: exports_external.string(),
|
|
32203
|
+
issue_id: exports_external.string().nullable().optional(),
|
|
32204
|
+
branch: exports_external.string().min(1),
|
|
32205
|
+
device_id: exports_external.string().nullable().optional(),
|
|
32206
|
+
runtime: exports_external.string().nullable().optional()
|
|
32207
|
+
}).meta({ id: "CreateAgentWorkspace" });
|
|
32208
|
+
var TransitionAgentWorkspaceSchema = exports_external.object({
|
|
32209
|
+
status: AgentWorkspaceStatusSchema,
|
|
32210
|
+
worktree_path: exports_external.string().nullable().optional(),
|
|
32211
|
+
agent_session_id: exports_external.string().nullable().optional()
|
|
32212
|
+
}).meta({ id: "TransitionAgentWorkspace" });
|
|
32140
32213
|
// src/_impl/legacy-main.ts
|
|
32141
32214
|
import { parseArgs } from "util";
|
|
32142
32215
|
import { mkdirSync as mkdirSync5, existsSync as existsSync7, writeFileSync as writeFileSync5, readFileSync as readFileSync7, appendFileSync as appendFileSync3, unlinkSync as unlinkSync3, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
@@ -32423,17 +32496,12 @@ async function cmdConnect(apiUrl, config2) {
|
|
|
32423
32496
|
}
|
|
32424
32497
|
function pickNext() {
|
|
32425
32498
|
const busyAgents = Array.from(running3.values()).map((e) => e.agentId).filter((v) => !!v);
|
|
32426
|
-
const busyIssues = Array.from(running3.values()).map((e) => e.issueId).filter((v) => !!v);
|
|
32427
32499
|
const clauses = [];
|
|
32428
32500
|
const binds = [];
|
|
32429
32501
|
if (busyAgents.length) {
|
|
32430
32502
|
clauses.push(`(agent_id IS NULL OR agent_id NOT IN (${busyAgents.map(() => "?").join(",")}))`);
|
|
32431
32503
|
binds.push(...busyAgents);
|
|
32432
32504
|
}
|
|
32433
|
-
if (busyIssues.length) {
|
|
32434
|
-
clauses.push(`(issue_id IS NULL OR issue_id NOT IN (${busyIssues.map(() => "?").join(",")}))`);
|
|
32435
|
-
binds.push(...busyIssues);
|
|
32436
|
-
}
|
|
32437
32505
|
const where = clauses.length ? `AND ${clauses.join(" AND ")}` : "";
|
|
32438
32506
|
const sql = `SELECT id, payload, agent_id, issue_id FROM tasks WHERE status = 'queued' ${where} ORDER BY created_at ASC LIMIT 1`;
|
|
32439
32507
|
return db.query(sql).get(...binds);
|
|
@@ -32446,8 +32514,6 @@ async function cmdConnect(apiUrl, config2) {
|
|
|
32446
32514
|
const ids4 = resolvePayloadIds(row);
|
|
32447
32515
|
if (ids4.agent_id && Array.from(running3.values()).some((e) => e.agentId === ids4.agent_id))
|
|
32448
32516
|
return;
|
|
32449
|
-
if (ids4.issue_id && Array.from(running3.values()).some((e) => e.issueId === ids4.issue_id))
|
|
32450
|
-
return;
|
|
32451
32517
|
db.run("UPDATE tasks SET status = 'running', started_at = unixepoch(), attempts = attempts + 1 WHERE id = ?", [row.id]);
|
|
32452
32518
|
const entry = { agentId: ids4.agent_id || "", issueId: ids4.issue_id, startedAt: Date.now(), child: null, worktreePath: "" };
|
|
32453
32519
|
running3.set(row.id, entry);
|
|
@@ -32935,6 +33001,13 @@ async function handleRunTask(apiUrl, deviceId, task, detected, ctx) {
|
|
|
32935
33001
|
workingDir = wt.path;
|
|
32936
33002
|
worktreeBranch = wt.branch;
|
|
32937
33003
|
await postStream(apiUrl, issueId, "worktree_created", { path: wt.path, branch: wt.branch, reused: !wt.created });
|
|
33004
|
+
if (task.workspace_id && task.project_id) {
|
|
33005
|
+
try {
|
|
33006
|
+
await apiClient.post(`${apiUrl}/api/agent-workspaces/${task.workspace_id}/ready?project_id=${encodeURIComponent(task.project_id)}`, { status: "ready", worktree_path: wt.path });
|
|
33007
|
+
} catch (e) {
|
|
33008
|
+
await postStream(apiUrl, issueId, "worktree_error", { message: `agent-workspace ack failed: ${fmtError(e)}` });
|
|
33009
|
+
}
|
|
33010
|
+
}
|
|
32938
33011
|
} catch (e) {
|
|
32939
33012
|
await postStream(apiUrl, issueId, "worktree_error", { message: fmtError(e) });
|
|
32940
33013
|
}
|
|
@@ -33262,6 +33335,8 @@ ${userPart}` : userPart;
|
|
|
33262
33335
|
issueId,
|
|
33263
33336
|
deviceId,
|
|
33264
33337
|
prompt,
|
|
33338
|
+
workspaceId: task.workspace_id || issueId,
|
|
33339
|
+
workspaceSessionId: task.workspace_session_id || null,
|
|
33265
33340
|
sessionId: task.session_id || null,
|
|
33266
33341
|
adapterBin,
|
|
33267
33342
|
autonomy: task.autonomy_level,
|
|
@@ -33271,6 +33346,11 @@ ${userPart}` : userPart;
|
|
|
33271
33346
|
try {
|
|
33272
33347
|
await apiClient.post(`${apiUrl}/api/issues/${issueId}/session`, { session_id: sid });
|
|
33273
33348
|
} catch {}
|
|
33349
|
+
if (task.workspace_session_id) {
|
|
33350
|
+
try {
|
|
33351
|
+
await apiClient.patch(`${apiUrl}/api/sessions/${task.workspace_session_id}?workspace_id=${encodeURIComponent(task.workspace_id || issueId)}`, { provider_session_id: sid, status: "running" });
|
|
33352
|
+
} catch {}
|
|
33353
|
+
}
|
|
33274
33354
|
},
|
|
33275
33355
|
onSpawn: (child) => {
|
|
33276
33356
|
if (ctx?.runEntry) {
|
|
@@ -33569,7 +33649,7 @@ async function executePlanActions(apiUrl, parentTask, actions, ctx) {
|
|
|
33569
33649
|
if (blocked3)
|
|
33570
33650
|
lines.push(`- \u26A0 ${blocked3} non-update action(s) blocked (planning depth limit ${PLANNING_DEPTH_LIMIT})`);
|
|
33571
33651
|
}
|
|
33572
|
-
const SUBCAPS = { "agent.create": 2, "skill.create": 3, "skill.attach": 5, "skill.detach": 5, "agent.update": 5 };
|
|
33652
|
+
const SUBCAPS = { "agent.create": 2, "skill.create": 3, "skill.attach": 5, "skill.detach": 5, "agent.update": 5, "session.create": 3 };
|
|
33573
33653
|
const counts = {};
|
|
33574
33654
|
actions = actions.filter((a) => {
|
|
33575
33655
|
const cap = SUBCAPS[a.type];
|
|
@@ -33660,6 +33740,15 @@ async function executePlanActions(apiUrl, parentTask, actions, ctx) {
|
|
|
33660
33740
|
continue;
|
|
33661
33741
|
}
|
|
33662
33742
|
lines.push(`- \u23F3 skill.create "${a.name}" queued for human review (op ${res.data?.pending_op_id})`);
|
|
33743
|
+
} else if (a.type === "session.create") {
|
|
33744
|
+
const res = await apiClient.post(`${apiUrl}/api/sessions`, { workspace_id: a.workspace_id, agent_id: a.agent_id, role: a.role, device_id: a.device_id }, { headers });
|
|
33745
|
+
if (!res.success) {
|
|
33746
|
+
lines.push(`- \u274C session.create role=${a.role}: ${res.error || res.status}`);
|
|
33747
|
+
continue;
|
|
33748
|
+
}
|
|
33749
|
+
const sess = res.data?.session;
|
|
33750
|
+
const reused = res.data?.reused;
|
|
33751
|
+
lines.push(`- ${reused ? "\u21BA" : "\u2713"} session.${reused ? "reuse" : "create"} ${sess?.id?.slice(0, 8) || "?"} (role=${a.role})`);
|
|
33663
33752
|
} else if (a.type === "skill.attach" || a.type === "skill.detach") {
|
|
33664
33753
|
const action = a.type === "skill.attach" ? "attach_skill" : "detach_skill";
|
|
33665
33754
|
const res = await apiClient.post(`${apiUrl}/api/agent_ops/agents/mutate`, { action, agent_id: a.agent_id, skill_id: a.skill_id }, { headers });
|