@shipers-dev/multi 0.11.0 → 0.12.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 +14907 -4474
- package/package.json +4 -3
- package/src/acp-runner.ts +4 -9
- package/src/index.ts +10 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipers-dev/multi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"multi-agent": "./dist/index.js"
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"build": "bun build src/index.ts --outdir=dist --target=bun"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@
|
|
14
|
-
"@
|
|
13
|
+
"@agentclientprotocol/sdk": "^0.20.0",
|
|
14
|
+
"@agentclientprotocol/claude-agent-acp": "^0.31.0",
|
|
15
|
+
"@multi/lib": "workspace:*"
|
|
15
16
|
}
|
|
16
17
|
}
|
package/src/acp-runner.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// Spawns the adapter as a subprocess over stdio, converts ACP events → our StreamEvent shape
|
|
3
3
|
// and handles client-side callbacks (requestPermission forwarded to server, fs read/write local).
|
|
4
4
|
|
|
5
|
-
import { ClientSideConnection, ndJsonStream } from '@
|
|
6
|
-
import type { Client, SessionNotification, RequestPermissionRequest, RequestPermissionResponse, ReadTextFileRequest, ReadTextFileResponse, WriteTextFileRequest, WriteTextFileResponse } from '@
|
|
5
|
+
import { ClientSideConnection, ndJsonStream } from '@agentclientprotocol/sdk';
|
|
6
|
+
import type { Client, SessionNotification, RequestPermissionRequest, RequestPermissionResponse, ReadTextFileRequest, ReadTextFileResponse, WriteTextFileRequest, WriteTextFileResponse } from '@agentclientprotocol/sdk';
|
|
7
7
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
8
8
|
import { dirname } from 'path';
|
|
9
9
|
import { apiClient } from './client';
|
|
@@ -22,13 +22,8 @@ function fmtErr(e: any): string {
|
|
|
22
22
|
return String(e);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
| { event_type: 'assistant_text'; payload: { text: string } }
|
|
28
|
-
| { event_type: 'tool_call'; payload: { id: string; tool: string; kind?: string; status?: string; input?: any; locations?: any[] } }
|
|
29
|
-
| { event_type: 'tool_result'; payload: { tool_use_id: string; content: string } }
|
|
30
|
-
| { event_type: 'result'; payload: { result?: string; duration_ms?: number; total_cost_usd?: number; stopReason?: string } }
|
|
31
|
-
| { event_type: 'error'; payload: { message: string } };
|
|
25
|
+
import type { CliStreamEmit } from '@multi/lib';
|
|
26
|
+
export type AcpEvent = CliStreamEmit;
|
|
32
27
|
|
|
33
28
|
export type AcpRunOpts = {
|
|
34
29
|
apiUrl: string;
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { apiClient, setAuthToken } from './client';
|
|
|
5
5
|
import { Database } from 'bun:sqlite';
|
|
6
6
|
import { runAcp } from './acp-runner';
|
|
7
7
|
import { runAcpx } from './acpx-runner';
|
|
8
|
+
import { STREAM_SCHEMA_VERSION, type StreamEventType, type CliStreamEmit } from '@multi/lib';
|
|
8
9
|
import { ensureWorktree } from './worktree';
|
|
9
10
|
import { materializeBundle, lastMaterializedRevision } from './materializer';
|
|
10
11
|
import { parseArgs } from 'util';
|
|
@@ -1130,7 +1131,7 @@ Rules:
|
|
|
1130
1131
|
- Omit the block if no actions are needed.
|
|
1131
1132
|
- Max 10 actions per turn. Sub-caps: agent.create=2, skill.create=3 per turn.
|
|
1132
1133
|
- Planning depth capped at ${PLANNING_DEPTH_LIMIT}. At depth ≥ 1 you can only \`update\` your own issue — no creates, no agents, no skills.
|
|
1133
|
-
- \`agent.create\`
|
|
1134
|
+
- \`agent.create\` is auto-approved on auto-autonomy issues. Caps + rate limits prevent abuse.
|
|
1134
1135
|
- \`skill.create\` ALWAYS waits for human review (skill bodies become future system prompts).
|
|
1135
1136
|
- \`allowed_tools\` on a new agent must be a subset of your own tools.
|
|
1136
1137
|
- \`create\` / \`update\` / \`delegate\` target issues only in the current project (${projectId || 'this project'}).
|
|
@@ -1235,7 +1236,7 @@ async function executePlanActions(apiUrl: string, parentTask: any, actions: Plan
|
|
|
1235
1236
|
const res = await apiClient.post<any>(`${apiUrl}/api/agent_ops/agents/mutate`, { action: 'create', name: a.name, type: a.agent_type, prompt: a.prompt, skill_ids: a.skill_ids, allowed_tools: a.allowed_tools }, { headers });
|
|
1236
1237
|
if (!res.success) { lines.push(`- ❌ agent.create "${a.name}": ${res.error || res.status}`); continue; }
|
|
1237
1238
|
if (res.data?.queued) lines.push(`- ⏳ agent.create "${a.name}" queued for human approval (op ${res.data.pending_op_id})`);
|
|
1238
|
-
else lines.push(`- ✓ agent.create "${a.name}" → ${res.data?.agent_id}
|
|
1239
|
+
else lines.push(`- ✓ agent.create "${a.name}" → ${res.data?.agent_id}`);
|
|
1239
1240
|
} else if (a.type === 'agent.update') {
|
|
1240
1241
|
const res = await apiClient.post<any>(`${apiUrl}/api/agent_ops/agents/mutate`, { action: 'update', ...a }, { headers });
|
|
1241
1242
|
if (!res.success) { lines.push(`- ❌ agent.update ${a.id}: ${res.error || res.status}`); continue; }
|
|
@@ -1304,8 +1305,8 @@ async function resolveAcpAdapter(agentType: string, detectedPath?: string): Prom
|
|
|
1304
1305
|
return [detectedPath, '--mode', 'rpc'];
|
|
1305
1306
|
}
|
|
1306
1307
|
|
|
1307
|
-
// claude-code →
|
|
1308
|
-
const adapterName = 'claude-
|
|
1308
|
+
// claude-code → claude-agent-acp adapter wrapper (stdio ACP)
|
|
1309
|
+
const adapterName = 'claude-agent-acp';
|
|
1309
1310
|
const candidates = [
|
|
1310
1311
|
join(HOME, '.bun', 'install', 'global', 'node_modules', '.bin', adapterName),
|
|
1311
1312
|
];
|
|
@@ -1371,7 +1372,7 @@ async function drainOfflineDispatches(apiUrl: string, deviceId: string, secret:
|
|
|
1371
1372
|
onEnqueued();
|
|
1372
1373
|
}
|
|
1373
1374
|
|
|
1374
|
-
async function postStream(apiUrl: string, issueId: string, event_type:
|
|
1375
|
+
async function postStream(apiUrl: string, issueId: string, event_type: StreamEventType, payload: unknown) {
|
|
1375
1376
|
// Local ndjson sink for tail -f debugging.
|
|
1376
1377
|
try {
|
|
1377
1378
|
ensureDirs();
|
|
@@ -1379,7 +1380,9 @@ async function postStream(apiUrl: string, issueId: string, event_type: string, p
|
|
|
1379
1380
|
const path = join(MULTI_DIR, 'logs', `events-${date}.ndjson`);
|
|
1380
1381
|
appendFileSync(path, JSON.stringify({ ts: Date.now(), issue_id: issueId, event_type, payload }) + '\n');
|
|
1381
1382
|
} catch {}
|
|
1382
|
-
await apiClient.post(`${apiUrl}/api/streams/${issueId}`, { event_type, payload }
|
|
1383
|
+
await apiClient.post(`${apiUrl}/api/streams/${issueId}`, { event_type, payload }, {
|
|
1384
|
+
headers: { 'X-Stream-Version': String(STREAM_SCHEMA_VERSION) },
|
|
1385
|
+
});
|
|
1383
1386
|
}
|
|
1384
1387
|
|
|
1385
1388
|
// Download attachments of a comment to a local dir. Returns list of absolute paths.
|
|
@@ -1445,7 +1448,7 @@ async function uploadOutputDir(apiUrl: string, commentId: string, dir: string):
|
|
|
1445
1448
|
return uploaded;
|
|
1446
1449
|
}
|
|
1447
1450
|
|
|
1448
|
-
type StreamEvent =
|
|
1451
|
+
type StreamEvent = CliStreamEmit;
|
|
1449
1452
|
type Runner = (task: any) => AsyncGenerator<StreamEvent>;
|
|
1450
1453
|
|
|
1451
1454
|
function pickRunner(detected: { type: string; path: string }[], preferType?: string): Runner {
|