@shipers-dev/multi 0.6.3 → 0.6.4

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 CHANGED
@@ -5381,6 +5381,16 @@ function extractText(content) {
5381
5381
  }
5382
5382
 
5383
5383
  // src/acpx-runner.ts
5384
+ import { appendFileSync } from "fs";
5385
+ import { join } from "path";
5386
+ var HOME = process.env.HOME || process.env.USERPROFILE || ".";
5387
+ var LOG_PATH = join(HOME, ".multi", "logs", "agent.log");
5388
+ function dlog(msg) {
5389
+ try {
5390
+ appendFileSync(LOG_PATH, `[${new Date().toISOString()}] ${msg}
5391
+ `);
5392
+ } catch {}
5393
+ }
5384
5394
  async function runAcpx(opts) {
5385
5395
  const args = ["acpx", "--format", "json", "--json-strict", "--approve-all", "--ttl", "0"];
5386
5396
  if (opts.cwd)
@@ -5388,15 +5398,22 @@ async function runAcpx(opts) {
5388
5398
  args.push(opts.agentType);
5389
5399
  if (opts.sessionName) {
5390
5400
  const ensureArgs = ["acpx", "--ttl", "0", ...opts.cwd ? ["--cwd", opts.cwd] : [], opts.agentType, "sessions", "ensure", "--name", opts.sessionName];
5401
+ dlog(`[acpx] ensure: ${ensureArgs.join(" ")}`);
5391
5402
  try {
5392
5403
  const ensure = Bun.spawn(ensureArgs, { stdout: "pipe", stderr: "pipe", stdin: "ignore" });
5393
- await ensure.exited;
5394
- } catch {}
5404
+ const ensureOut = await new Response(ensure.stdout).text();
5405
+ const ensureErr = await new Response(ensure.stderr).text();
5406
+ const ensureCode = await ensure.exited;
5407
+ dlog(`[acpx] ensure exit=${ensureCode} stdout=${ensureOut.slice(0, 300)} stderr=${ensureErr.slice(0, 300)}`);
5408
+ } catch (e) {
5409
+ dlog(`[acpx] ensure spawn error: ${String(e)}`);
5410
+ }
5395
5411
  args.push("prompt", "-s", opts.sessionName);
5396
5412
  } else {
5397
5413
  args.push("prompt");
5398
5414
  }
5399
5415
  args.push(opts.prompt);
5416
+ dlog(`[acpx] prompt: ${args.slice(0, 10).join(" ")} ... (prompt len=${opts.prompt.length})`);
5400
5417
  const proc = Bun.spawn(args, { stdout: "pipe", stderr: "pipe", stdin: "ignore" });
5401
5418
  let stopReason = "end_turn";
5402
5419
  (async () => {
@@ -5415,7 +5432,7 @@ async function runAcpx(opts) {
5415
5432
  const ln = sb.slice(0, nl).trim();
5416
5433
  sb = sb.slice(nl + 1);
5417
5434
  if (ln)
5418
- await opts.onEvent({ event_type: "progress", payload: { message: `[acpx] ${ln.slice(0, 500)}` } });
5435
+ dlog(`[acpx stderr] ${ln.slice(0, 500)}`);
5419
5436
  }
5420
5437
  }
5421
5438
  } catch {}
@@ -5423,6 +5440,7 @@ async function runAcpx(opts) {
5423
5440
  const reader = proc.stdout.getReader();
5424
5441
  const dec = new TextDecoder;
5425
5442
  let buf = "";
5443
+ let lineCount = 0;
5426
5444
  while (true) {
5427
5445
  const { value, done } = await reader.read();
5428
5446
  if (done)
@@ -5435,6 +5453,8 @@ async function runAcpx(opts) {
5435
5453
  buf = buf.slice(nl + 1);
5436
5454
  if (!line)
5437
5455
  continue;
5456
+ lineCount++;
5457
+ dlog(`[acpx stdout] ${line.slice(0, 500)}`);
5438
5458
  const events = parseAcpLine(line, (r) => {
5439
5459
  stopReason = r;
5440
5460
  });
@@ -5442,6 +5462,7 @@ async function runAcpx(opts) {
5442
5462
  await opts.onEvent(ev);
5443
5463
  }
5444
5464
  }
5465
+ dlog(`[acpx] stdout lines total=${lineCount}`);
5445
5466
  if (buf.trim()) {
5446
5467
  const events = parseAcpLine(buf.trim(), (r) => {
5447
5468
  stopReason = r;
@@ -5481,7 +5502,6 @@ function handleSessionUpdate(params) {
5481
5502
  const u = params.update || {};
5482
5503
  const kind = u.sessionUpdate;
5483
5504
  const out = [];
5484
- out.push({ event_type: "progress", payload: { message: `[acpx upd] ${kind} keys=${Object.keys(u).join(",")}` } });
5485
5505
  switch (kind) {
5486
5506
  case "agent_message_chunk":
5487
5507
  case "agent_thought_chunk": {
@@ -5543,17 +5563,17 @@ function extractText2(content) {
5543
5563
 
5544
5564
  // src/index.ts
5545
5565
  import { parseArgs } from "util";
5546
- import { mkdirSync as mkdirSync2, existsSync as existsSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync2, appendFileSync, unlinkSync, readdirSync, statSync } from "fs";
5547
- import { join, dirname as dirname2 } from "path";
5548
- var HOME = process.env.HOME || process.env.USERPROFILE || ".";
5549
- var MULTI_DIR = join(HOME, ".multi");
5550
- var CONFIG_PATH = join(MULTI_DIR, "config.json");
5551
- var PID_PATH = join(MULTI_DIR, "agent.pid");
5552
- var LOG_PATH = join(MULTI_DIR, "logs", "agent.log");
5553
- var SKILLS_DIR = join(MULTI_DIR, "skills");
5554
- var STOP_PATH = join(MULTI_DIR, "stop.flag");
5555
- var TASKS_DB_PATH = join(MULTI_DIR, "tasks.db");
5556
- var VERSION = "0.6.3";
5566
+ import { mkdirSync as mkdirSync2, existsSync as existsSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync2, appendFileSync as appendFileSync2, unlinkSync, readdirSync, statSync } from "fs";
5567
+ import { join as join2, dirname as dirname2 } from "path";
5568
+ var HOME2 = process.env.HOME || process.env.USERPROFILE || ".";
5569
+ var MULTI_DIR = join2(HOME2, ".multi");
5570
+ var CONFIG_PATH = join2(MULTI_DIR, "config.json");
5571
+ var PID_PATH = join2(MULTI_DIR, "agent.pid");
5572
+ var LOG_PATH2 = join2(MULTI_DIR, "logs", "agent.log");
5573
+ var SKILLS_DIR = join2(MULTI_DIR, "skills");
5574
+ var STOP_PATH = join2(MULTI_DIR, "stop.flag");
5575
+ var TASKS_DB_PATH = join2(MULTI_DIR, "tasks.db");
5576
+ var VERSION = "0.6.4";
5557
5577
  var COMMANDS = {
5558
5578
  setup: "Register this device with a workspace",
5559
5579
  connect: "Connect device to realtime hub and execute assigned tasks",
@@ -5563,7 +5583,7 @@ var COMMANDS = {
5563
5583
  logs: "View execution logs"
5564
5584
  };
5565
5585
  function ensureDirs() {
5566
- for (const d of [MULTI_DIR, join(MULTI_DIR, "logs"), SKILLS_DIR]) {
5586
+ for (const d of [MULTI_DIR, join2(MULTI_DIR, "logs"), SKILLS_DIR]) {
5567
5587
  if (!existsSync2(d))
5568
5588
  mkdirSync2(d, { recursive: true });
5569
5589
  }
@@ -5572,7 +5592,7 @@ function log(msg) {
5572
5592
  ensureDirs();
5573
5593
  const line = `[${new Date().toISOString()}] ${msg}
5574
5594
  `;
5575
- appendFileSync(LOG_PATH, line);
5595
+ appendFileSync2(LOG_PATH2, line);
5576
5596
  process.stdout.write(line);
5577
5597
  }
5578
5598
  async function main() {
@@ -5738,7 +5758,7 @@ async function syncSkills(apiUrl, workspaceId) {
5738
5758
  return;
5739
5759
  ensureDirs();
5740
5760
  for (const skill of res.data) {
5741
- writeFileSync2(join(SKILLS_DIR, `${skill.name}.json`), JSON.stringify(skill, null, 2));
5761
+ writeFileSync2(join2(SKILLS_DIR, `${skill.name}.json`), JSON.stringify(skill, null, 2));
5742
5762
  }
5743
5763
  if (res.data.length)
5744
5764
  console.log(` Synced ${res.data.length} skill(s) \u2192 ${SKILLS_DIR}`);
@@ -5906,7 +5926,7 @@ async function cmdConnectDetached(apiUrl) {
5906
5926
  }
5907
5927
  }
5908
5928
  ensureDirs();
5909
- const logFd = Bun.file(LOG_PATH);
5929
+ const logFd = Bun.file(LOG_PATH2);
5910
5930
  const args = Bun.argv.slice(1).filter((a) => a !== "-d" && a !== "--detach");
5911
5931
  const proc = Bun.spawn([process.execPath, ...args, "--api", apiUrl], {
5912
5932
  stdio: ["ignore", "ignore", "ignore"],
@@ -5965,13 +5985,13 @@ async function handleRunTask(apiUrl, deviceId, task, detected) {
5965
5985
  await postStream(apiUrl, issueId, "progress", { message: `Device ${deviceId} picked up ${isFollowup ? "follow-up" : "task"}` });
5966
5986
  let attachmentRefs = [];
5967
5987
  if (task.from_comment_id) {
5968
- const baseDir = workingDir || join(MULTI_DIR, "tmp", issueId);
5969
- const inDir = join(baseDir, ".multi-in", task.from_comment_id);
5988
+ const baseDir = workingDir || join2(MULTI_DIR, "tmp", issueId);
5989
+ const inDir = join2(baseDir, ".multi-in", task.from_comment_id);
5970
5990
  attachmentRefs = await downloadCommentAttachments(apiUrl, task.from_comment_id, inDir);
5971
5991
  if (attachmentRefs.length)
5972
5992
  log(` fetched ${attachmentRefs.length} attachment(s) \u2192 ${inDir}`);
5973
5993
  }
5974
- const outDir = join(workingDir || join(MULTI_DIR, "tmp", issueId), ".multi-out");
5994
+ const outDir = join2(workingDir || join2(MULTI_DIR, "tmp", issueId), ".multi-out");
5975
5995
  let liveCommentId;
5976
5996
  let liveBody = "";
5977
5997
  let hadError = false;
@@ -6400,14 +6420,14 @@ async function resolveAcpAdapter(agentType, detectedPath) {
6400
6420
  }
6401
6421
  const adapterName = "claude-code-acp";
6402
6422
  const candidates = [
6403
- join(HOME, ".bun", "install", "global", "node_modules", ".bin", adapterName)
6423
+ join2(HOME2, ".bun", "install", "global", "node_modules", ".bin", adapterName)
6404
6424
  ];
6405
6425
  try {
6406
6426
  const here = new URL(import.meta.url).pathname;
6407
6427
  let dir = here;
6408
6428
  for (let i = 0;i < 8; i++) {
6409
6429
  dir = dirname2(dir);
6410
- const bin = join(dir, "node_modules", ".bin", adapterName);
6430
+ const bin = join2(dir, "node_modules", ".bin", adapterName);
6411
6431
  if (existsSync2(bin))
6412
6432
  return [bin];
6413
6433
  }
@@ -6435,7 +6455,7 @@ async function downloadCommentAttachments(apiUrl, commentId, destDir) {
6435
6455
  continue;
6436
6456
  const buf = new Uint8Array(await res.arrayBuffer());
6437
6457
  const safe = it.filename.replace(/[^A-Za-z0-9._-]/g, "_");
6438
- const p = join(destDir, safe);
6458
+ const p = join2(destDir, safe);
6439
6459
  writeFileSync2(p, buf);
6440
6460
  out.push({ filename: it.filename, path: p });
6441
6461
  }
@@ -6456,7 +6476,7 @@ async function uploadOutputDir(apiUrl, commentId, dir) {
6456
6476
  if (depth > 3)
6457
6477
  return;
6458
6478
  for (const name of readdirSync(d)) {
6459
- const p = join(d, name);
6479
+ const p = join2(d, name);
6460
6480
  try {
6461
6481
  const st = statSync(p);
6462
6482
  if (st.isDirectory())
@@ -6732,11 +6752,11 @@ async function cmdStop() {
6732
6752
  } catch {}
6733
6753
  }
6734
6754
  async function cmdLogs() {
6735
- if (!existsSync2(LOG_PATH)) {
6755
+ if (!existsSync2(LOG_PATH2)) {
6736
6756
  console.log("No logs yet.");
6737
6757
  return;
6738
6758
  }
6739
- const content = readFileSync2(LOG_PATH, "utf8");
6759
+ const content = readFileSync2(LOG_PATH2, "utf8");
6740
6760
  console.log(content.split(`
6741
6761
  `).slice(-100).join(`
6742
6762
  `));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipers-dev/multi",
3
- "version": "0.6.3",
3
+ "version": "0.6.4",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "multi-agent": "./dist/index.js"
@@ -6,6 +6,14 @@
6
6
  // Runs with --approve-all for now (no permission UI forwarding).
7
7
 
8
8
  import type { AcpEvent } from './acp-runner';
9
+ import { appendFileSync } from 'fs';
10
+ import { join } from 'path';
11
+
12
+ const HOME = process.env.HOME || process.env.USERPROFILE || '.';
13
+ const LOG_PATH = join(HOME, '.multi', 'logs', 'agent.log');
14
+ function dlog(msg: string) {
15
+ try { appendFileSync(LOG_PATH, `[${new Date().toISOString()}] ${msg}\n`); } catch {}
16
+ }
9
17
 
10
18
  export interface AcpxRunOpts {
11
19
  agentType: 'pi' | 'codex' | 'openclaw' | 'claude' | string;
@@ -23,16 +31,23 @@ export async function runAcpx(opts: AcpxRunOpts): Promise<{ stopReason: string }
23
31
  // We run it as a separate invocation, then prompt.
24
32
  if (opts.sessionName) {
25
33
  const ensureArgs = ['acpx', '--ttl', '0', ...(opts.cwd ? ['--cwd', opts.cwd] : []), opts.agentType, 'sessions', 'ensure', '--name', opts.sessionName];
34
+ dlog(`[acpx] ensure: ${ensureArgs.join(' ')}`);
26
35
  try {
27
36
  const ensure = Bun.spawn(ensureArgs, { stdout: 'pipe', stderr: 'pipe', stdin: 'ignore' });
28
- await ensure.exited;
29
- } catch {}
37
+ const ensureOut = await new Response(ensure.stdout as any).text();
38
+ const ensureErr = await new Response(ensure.stderr as any).text();
39
+ const ensureCode = await ensure.exited;
40
+ dlog(`[acpx] ensure exit=${ensureCode} stdout=${ensureOut.slice(0, 300)} stderr=${ensureErr.slice(0, 300)}`);
41
+ } catch (e) {
42
+ dlog(`[acpx] ensure spawn error: ${String(e)}`);
43
+ }
30
44
  args.push('prompt', '-s', opts.sessionName);
31
45
  } else {
32
46
  args.push('prompt');
33
47
  }
34
48
  args.push(opts.prompt);
35
49
 
50
+ dlog(`[acpx] prompt: ${args.slice(0, 10).join(' ')} ... (prompt len=${opts.prompt.length})`);
36
51
  const proc = Bun.spawn(args, { stdout: 'pipe', stderr: 'pipe', stdin: 'ignore' });
37
52
  let stopReason = 'end_turn';
38
53
 
@@ -50,7 +65,7 @@ export async function runAcpx(opts: AcpxRunOpts): Promise<{ stopReason: string }
50
65
  while ((nl = sb.indexOf('\n')) !== -1) {
51
66
  const ln = sb.slice(0, nl).trim();
52
67
  sb = sb.slice(nl + 1);
53
- if (ln) await opts.onEvent({ event_type: 'progress', payload: { message: `[acpx] ${ln.slice(0, 500)}` } });
68
+ if (ln) dlog(`[acpx stderr] ${ln.slice(0, 500)}`);
54
69
  }
55
70
  }
56
71
  } catch {}
@@ -60,6 +75,7 @@ export async function runAcpx(opts: AcpxRunOpts): Promise<{ stopReason: string }
60
75
  const dec = new TextDecoder();
61
76
  let buf = '';
62
77
 
78
+ let lineCount = 0;
63
79
  while (true) {
64
80
  const { value, done } = await reader.read();
65
81
  if (done) break;
@@ -69,10 +85,13 @@ export async function runAcpx(opts: AcpxRunOpts): Promise<{ stopReason: string }
69
85
  const line = buf.slice(0, nl).trim();
70
86
  buf = buf.slice(nl + 1);
71
87
  if (!line) continue;
88
+ lineCount++;
89
+ dlog(`[acpx stdout] ${line.slice(0, 500)}`);
72
90
  const events = parseAcpLine(line, (r) => { stopReason = r; });
73
91
  for (const ev of events) await opts.onEvent(ev);
74
92
  }
75
93
  }
94
+ dlog(`[acpx] stdout lines total=${lineCount}`);
76
95
  if (buf.trim()) {
77
96
  const events = parseAcpLine(buf.trim(), (r) => { stopReason = r; });
78
97
  for (const ev of events) await opts.onEvent(ev);
@@ -112,8 +131,6 @@ function handleSessionUpdate(params: any): AcpEvent[] {
112
131
  const u = params.update || {};
113
132
  const kind = u.sessionUpdate;
114
133
  const out: AcpEvent[] = [];
115
- // Fallthrough debug: emit the update kind + keys so we can see what acpx is sending
116
- out.push({ event_type: 'progress', payload: { message: `[acpx upd] ${kind} keys=${Object.keys(u).join(',')}` } });
117
134
  switch (kind) {
118
135
  case 'agent_message_chunk':
119
136
  case 'agent_thought_chunk': {
package/src/index.ts CHANGED
@@ -17,7 +17,7 @@ const LOG_PATH = join(MULTI_DIR, 'logs', 'agent.log');
17
17
  const SKILLS_DIR = join(MULTI_DIR, 'skills');
18
18
  const STOP_PATH = join(MULTI_DIR, 'stop.flag');
19
19
  const TASKS_DB_PATH = join(MULTI_DIR, 'tasks.db');
20
- const VERSION = '0.6.3';
20
+ const VERSION = '0.6.4';
21
21
 
22
22
  const COMMANDS = {
23
23
  setup: 'Register this device with a workspace',