@moxxy/cli 0.14.3 → 0.14.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/bin.js +124 -50
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { z as z$1, createMutex, defineTunnelProvider, definePlugin, defineProvider, defineTool, MoxxyError, asTurnId, defineMode, asPluginId, defineCommand, defineChannel, defineWorkflowExecutor, toFriendlyError, estimateTextTokens, classifyHttpStatus, createStuckLoopDetector, runCompactionIfNeeded, runElisionIfNeeded, collectProviderStream, usageEventFields, isContextOverflowError, emitRequestsAndDetectStuck, executeToolUses, buildSystemPromptWithSkills, projectMessages, defineCompactor, defineCacheStrategy, denyByDefaultResolver, createAllowListResolver, zodToJsonSchema, fileDiffSummary, runSingleShotTurn, defineSurface, runManualCompaction, isFileDiffDisplay, renderFrontmatter, defineEmbedder, migrateModeName, skillFrontmatterSchema, asSkillId, startChannelWith, parseFrontmatterFile, createDeferredPermissionResolver, getInstallHint, defineTranscriber, summarizeTokensByModel, countNodes, moxxyPackageSchema, encodeLoginPrompt, classifyNetworkError, addModelTotals, createJsonFileStore, ISOLATION_RANK, MOXXY_PCM16_24KHZ_MIME, fileDiffVerb, parseFrontmatter, createCallbackResolver, autoAllowResolver, asSessionId, asToolCallId, defineViewRenderer, DEFAULT_VIEW_TAGS, isSafeViewUrl, evaluateToolRule, summarizeSessionTokensFromEvents, toDiffRows, diffGutterNo, computeElisionState, toolResultStubbed, toolResultStub, toolResultBytes, conversationalStubbed, conversationalStub, asEventId } from '@moxxy/sdk';
|
|
4
4
|
import * as fs32 from 'fs';
|
|
5
|
-
import fs32__default, { existsSync, promises, ReadStream, mkdirSync, statSync, readdirSync, writeFileSync, readFileSync, unlinkSync, chmodSync, watch, createReadStream } from 'fs';
|
|
5
|
+
import fs32__default, { existsSync, promises, ReadStream, mkdirSync, rmSync, statSync, readdirSync, writeFileSync, readFileSync, unlinkSync, chmodSync, watch, createReadStream } from 'fs';
|
|
6
6
|
import * as path3 from 'path';
|
|
7
7
|
import path3__default, { join, dirname, resolve, relative, isAbsolute, basename } from 'path';
|
|
8
8
|
import { isCliTunnelAvailable, writeFileAtomic, spawnCliTunnel, moxxyPath, moxxyHome, bearerTokenMatches, resolveChannelToken, rotateChannelToken, readRequestBody, MOXXY_WS_SUBPROTOCOL, bearerGuard, tokenFromWsProtocolHeader, writeFileAtomicSync } from '@moxxy/sdk/server';
|
|
@@ -138658,7 +138658,7 @@ var CollaborationState = class {
|
|
|
138658
138658
|
return;
|
|
138659
138659
|
agent.status = status;
|
|
138660
138660
|
this.emitFn({ kind: "agent_status", agentId, status, ...detail ? { detail } : {} });
|
|
138661
|
-
if (status === "crashed" || status === "killed")
|
|
138661
|
+
if (status === "crashed" || status === "killed" || status === "failed")
|
|
138662
138662
|
this.releaseAllFor(agentId);
|
|
138663
138663
|
}
|
|
138664
138664
|
markDone(agentId, summary, artifacts) {
|
|
@@ -138671,7 +138671,7 @@ var CollaborationState = class {
|
|
|
138671
138671
|
this.emitFn({ kind: "agent_done", agentId, summary, ...artifacts ? { artifacts } : {} });
|
|
138672
138672
|
}
|
|
138673
138673
|
allDone() {
|
|
138674
|
-
const live = this.agentOrder.map((id) => this.agents.get(id)).filter((a2) => a2.status !== "crashed" && a2.status !== "killed");
|
|
138674
|
+
const live = this.agentOrder.map((id) => this.agents.get(id)).filter((a2) => a2.status !== "crashed" && a2.status !== "killed" && a2.status !== "failed");
|
|
138675
138675
|
return live.length > 0 && live.every((a2) => a2.status === "done");
|
|
138676
138676
|
}
|
|
138677
138677
|
roleOf(agentId) {
|
|
@@ -139029,7 +139029,7 @@ async function createCollaborationHub(opts) {
|
|
|
139029
139029
|
connections.delete(peer);
|
|
139030
139030
|
if (agentId) {
|
|
139031
139031
|
const agent = state.rosterView().agents.find((a2) => a2.id === agentId);
|
|
139032
|
-
if (agent && agent.status !== "done" && agent.status !== "killed") {
|
|
139032
|
+
if (agent && agent.status !== "done" && agent.status !== "failed" && agent.status !== "killed") {
|
|
139033
139033
|
state.setStatus(agentId, "crashed");
|
|
139034
139034
|
}
|
|
139035
139035
|
}
|
|
@@ -139275,13 +139275,24 @@ var PeerSupervisor = class {
|
|
|
139275
139275
|
child.on("exit", () => {
|
|
139276
139276
|
proc.exited = true;
|
|
139277
139277
|
});
|
|
139278
|
+
child.on("error", (err) => {
|
|
139279
|
+
proc.exited = true;
|
|
139280
|
+
proc.stderr.push(`spawn error: ${err.message}`);
|
|
139281
|
+
});
|
|
139278
139282
|
return { socket };
|
|
139279
139283
|
}
|
|
139284
|
+
/** True once the child has exited or its spawn failed. */
|
|
139285
|
+
hasExited(agentId) {
|
|
139286
|
+
const proc = this.peers.get(agentId);
|
|
139287
|
+
return proc ? proc.exited : false;
|
|
139288
|
+
}
|
|
139280
139289
|
/** Last stderr lines from a peer — used to diagnose a crash. */
|
|
139281
139290
|
stderrOf(agentId) {
|
|
139282
139291
|
return this.peers.get(agentId)?.stderr ?? [];
|
|
139283
139292
|
}
|
|
139284
|
-
/**
|
|
139293
|
+
/** Stop a single peer and AWAIT its real exit (with a force-kill fallback), so
|
|
139294
|
+
* callers — e.g. the sequential fallback — can rely on the workspace being
|
|
139295
|
+
* free before the next agent starts. */
|
|
139285
139296
|
async stop(agentId) {
|
|
139286
139297
|
const proc = this.peers.get(agentId);
|
|
139287
139298
|
if (!proc || proc.exited)
|
|
@@ -139290,6 +139301,27 @@ var PeerSupervisor = class {
|
|
|
139290
139301
|
proc.child.kill("SIGTERM");
|
|
139291
139302
|
} catch {
|
|
139292
139303
|
}
|
|
139304
|
+
await new Promise((resolve13) => {
|
|
139305
|
+
if (proc.exited)
|
|
139306
|
+
return resolve13();
|
|
139307
|
+
let settled = false;
|
|
139308
|
+
const done = () => {
|
|
139309
|
+
if (settled)
|
|
139310
|
+
return;
|
|
139311
|
+
settled = true;
|
|
139312
|
+
clearTimeout(timer);
|
|
139313
|
+
resolve13();
|
|
139314
|
+
};
|
|
139315
|
+
proc.child.once("exit", done);
|
|
139316
|
+
const timer = setTimeout(() => {
|
|
139317
|
+
try {
|
|
139318
|
+
proc.child.kill("SIGKILL");
|
|
139319
|
+
} catch {
|
|
139320
|
+
}
|
|
139321
|
+
done();
|
|
139322
|
+
}, FORCE_KILL_GRACE_MS);
|
|
139323
|
+
timer.unref?.();
|
|
139324
|
+
});
|
|
139293
139325
|
}
|
|
139294
139326
|
async shutdownAll(_reason) {
|
|
139295
139327
|
if (this.shuttingDown)
|
|
@@ -139423,6 +139455,7 @@ function releaseCollabLock(sessionId) {
|
|
|
139423
139455
|
|
|
139424
139456
|
// ../mode-collaborative/dist/collab-loop.js
|
|
139425
139457
|
var POLL_MS = 500;
|
|
139458
|
+
var BOOT_DEADLINE_MS = 9e4;
|
|
139426
139459
|
function runCollaborativeMode(ctx) {
|
|
139427
139460
|
return runCollaborative(ctx, {});
|
|
139428
139461
|
}
|
|
@@ -139491,13 +139524,18 @@ async function* runCollaborative(ctx, deps) {
|
|
|
139491
139524
|
yield await ctx.emit(plugin4(ctx, "collab_started", { task, parallel, gitInstalled: gitInstalled2, gitRepo }));
|
|
139492
139525
|
supervisor.spawn({ entry: architectEntry, cwd: cwd2, mode: COLLAB_ARCHITECT_MODE_NAME });
|
|
139493
139526
|
yield await ctx.emit(plugin4(ctx, "collab_agent_spawned", { id: ARCHITECT_AGENT_ID, role: "architect" }));
|
|
139494
|
-
const architectOk = await waitForAgent(hub, ARCHITECT_AGENT_ID, ctx.signal, cfg.wallClockMs);
|
|
139527
|
+
const architectOk = await waitForAgent(hub, supervisor, ARCHITECT_AGENT_ID, ctx.signal, cfg.wallClockMs);
|
|
139495
139528
|
if (ctx.signal.aborted) {
|
|
139496
139529
|
yield await ctx.emit(emitAbort(ctx, "aborted during design"));
|
|
139497
139530
|
return;
|
|
139498
139531
|
}
|
|
139499
139532
|
if (!architectOk) {
|
|
139500
|
-
|
|
139533
|
+
const why = supervisor.stderrOf(ARCHITECT_AGENT_ID).slice(-4).join("\n");
|
|
139534
|
+
yield await ctx.emit(plugin4(ctx, "collab_agent_failed", { id: ARCHITECT_AGENT_ID, status: statusOf(hub, ARCHITECT_AGENT_ID), stderr: supervisor.stderrOf(ARCHITECT_AGENT_ID).slice(-6) }));
|
|
139535
|
+
yield await ctx.emit(assistant(ctx, `The architect did not finish the design \u2014 stopping the collaboration.${why ? `
|
|
139536
|
+
|
|
139537
|
+
Last diagnostics:
|
|
139538
|
+
${why}` : ""}`));
|
|
139501
139539
|
return;
|
|
139502
139540
|
}
|
|
139503
139541
|
let roster = readRoster(join(cwd2, COLLAB_SCAFFOLD_DIR, ROSTER_FILENAME), cfg.maxAgents);
|
|
@@ -139538,7 +139576,8 @@ async function* runCollaborative(ctx, deps) {
|
|
|
139538
139576
|
supervisor.spawn({ entry, cwd: wt3, mode: COLLAB_PEER_MODE_NAME });
|
|
139539
139577
|
yield await ctx.emit(plugin4(ctx, "collab_agent_spawned", { id: entry.id, role: entry.role }));
|
|
139540
139578
|
}
|
|
139541
|
-
await waitForAgents(hub, roster.map((r2) => r2.id), ctx.signal, cfg.wallClockMs);
|
|
139579
|
+
await waitForAgents(hub, supervisor, roster.map((r2) => r2.id), ctx.signal, cfg.wallClockMs);
|
|
139580
|
+
yield* surfaceFailures(ctx, hub, supervisor, roster.map((r2) => r2.id));
|
|
139542
139581
|
for (const r2 of roster)
|
|
139543
139582
|
if (statusOf(hub, r2.id) === "done")
|
|
139544
139583
|
doneIds.push(r2.id);
|
|
@@ -139549,7 +139588,9 @@ async function* runCollaborative(ctx, deps) {
|
|
|
139549
139588
|
hub.state.addAgent(entry);
|
|
139550
139589
|
supervisor.spawn({ entry, cwd: cwd2, mode: COLLAB_PEER_MODE_NAME });
|
|
139551
139590
|
yield await ctx.emit(plugin4(ctx, "collab_agent_spawned", { id: entry.id, role: entry.role }));
|
|
139552
|
-
const ok = await waitForAgent(hub, entry.id, ctx.signal, cfg.wallClockMs);
|
|
139591
|
+
const ok = await waitForAgent(hub, supervisor, entry.id, ctx.signal, cfg.wallClockMs);
|
|
139592
|
+
if (!ok)
|
|
139593
|
+
yield* surfaceFailures(ctx, hub, supervisor, [entry.id]);
|
|
139553
139594
|
await supervisor.stop(entry.id);
|
|
139554
139595
|
if (ok && statusOf(hub, entry.id) === "done")
|
|
139555
139596
|
doneIds.push(entry.id);
|
|
@@ -139593,6 +139634,16 @@ ${mergeNote}` : ""}`));
|
|
|
139593
139634
|
if (hub)
|
|
139594
139635
|
await hub.close();
|
|
139595
139636
|
releaseCollabLock(String(ctx.sessionId));
|
|
139637
|
+
for (const wt3 of worktrees.values()) {
|
|
139638
|
+
await removeWorktree(cwd2, wt3).catch(() => void 0);
|
|
139639
|
+
}
|
|
139640
|
+
try {
|
|
139641
|
+
rmSync(collabRunDir(runId), { recursive: true, force: true });
|
|
139642
|
+
rmSync(worktreeRoot(runId), { recursive: true, force: true });
|
|
139643
|
+
} catch {
|
|
139644
|
+
}
|
|
139645
|
+
if (worktrees.size > 0)
|
|
139646
|
+
await git(cwd2, ["worktree", "prune"]).catch(() => void 0);
|
|
139596
139647
|
}
|
|
139597
139648
|
}
|
|
139598
139649
|
function lastUserPromptText(ctx) {
|
|
@@ -139643,30 +139694,62 @@ function slug(s2) {
|
|
|
139643
139694
|
function statusOf(hub, id) {
|
|
139644
139695
|
return hub.state.rosterView().agents.find((a2) => a2.id === id)?.status;
|
|
139645
139696
|
}
|
|
139646
|
-
|
|
139647
|
-
const
|
|
139697
|
+
function agentSettled(hub, supervisor, id, connected, bootDeadlineAt) {
|
|
139698
|
+
const status = statusOf(hub, id);
|
|
139699
|
+
if (status && status !== "pending")
|
|
139700
|
+
connected.add(id);
|
|
139701
|
+
if (status === "done")
|
|
139702
|
+
return "done";
|
|
139703
|
+
if (status === "failed" || status === "crashed" || status === "killed")
|
|
139704
|
+
return "failed";
|
|
139705
|
+
if (supervisor?.hasExited(id))
|
|
139706
|
+
return "failed";
|
|
139707
|
+
if (!connected.has(id) && Date.now() > bootDeadlineAt)
|
|
139708
|
+
return "failed";
|
|
139709
|
+
return void 0;
|
|
139710
|
+
}
|
|
139711
|
+
async function waitForAgent(hub, supervisor, id, signal, wallClockMs) {
|
|
139712
|
+
const wallDeadline = Date.now() + wallClockMs;
|
|
139713
|
+
const bootDeadlineAt = Date.now() + BOOT_DEADLINE_MS;
|
|
139714
|
+
const connected = /* @__PURE__ */ new Set();
|
|
139648
139715
|
for (; ; ) {
|
|
139649
|
-
const
|
|
139650
|
-
if (
|
|
139716
|
+
const settled = agentSettled(hub, supervisor, id, connected, bootDeadlineAt);
|
|
139717
|
+
if (settled === "done")
|
|
139651
139718
|
return true;
|
|
139652
|
-
if (
|
|
139719
|
+
if (settled === "failed")
|
|
139653
139720
|
return false;
|
|
139654
|
-
if (signal.aborted || Date.now() >
|
|
139721
|
+
if (signal.aborted || Date.now() > wallDeadline)
|
|
139655
139722
|
return false;
|
|
139656
139723
|
await sleep5(POLL_MS, signal);
|
|
139657
139724
|
}
|
|
139658
139725
|
}
|
|
139659
|
-
async function waitForAgents(hub, ids, signal,
|
|
139660
|
-
const
|
|
139661
|
-
const
|
|
139726
|
+
async function waitForAgents(hub, supervisor, ids, signal, wallClockMs) {
|
|
139727
|
+
const wallDeadline = Date.now() + wallClockMs;
|
|
139728
|
+
const bootDeadlineAt = Date.now() + BOOT_DEADLINE_MS;
|
|
139729
|
+
const connected = /* @__PURE__ */ new Set();
|
|
139662
139730
|
for (; ; ) {
|
|
139663
|
-
if (ids.every((id) =>
|
|
139731
|
+
if (ids.every((id) => agentSettled(hub, supervisor, id, connected, bootDeadlineAt) !== void 0))
|
|
139664
139732
|
return;
|
|
139665
|
-
if (signal.aborted || Date.now() >
|
|
139733
|
+
if (signal.aborted || Date.now() > wallDeadline)
|
|
139666
139734
|
return;
|
|
139667
139735
|
await sleep5(POLL_MS, signal);
|
|
139668
139736
|
}
|
|
139669
139737
|
}
|
|
139738
|
+
async function* surfaceFailures(ctx, hub, supervisor, ids) {
|
|
139739
|
+
for (const id of ids) {
|
|
139740
|
+
const status = statusOf(hub, id);
|
|
139741
|
+
if (status === "done")
|
|
139742
|
+
continue;
|
|
139743
|
+
if (status !== "failed" && status !== "crashed" && status !== "killed") {
|
|
139744
|
+
hub.state.setStatus(id, "crashed", "did not reach a terminal status");
|
|
139745
|
+
}
|
|
139746
|
+
yield await ctx.emit(plugin4(ctx, "collab_agent_failed", {
|
|
139747
|
+
id,
|
|
139748
|
+
status: statusOf(hub, id),
|
|
139749
|
+
stderr: supervisor.stderrOf(id).slice(-6)
|
|
139750
|
+
}));
|
|
139751
|
+
}
|
|
139752
|
+
}
|
|
139670
139753
|
function sleep5(ms, signal) {
|
|
139671
139754
|
return new Promise((resolve13) => {
|
|
139672
139755
|
if (signal.aborted)
|
|
@@ -139788,6 +139871,8 @@ async function* runCollabAgentLoop(ctx, opts) {
|
|
|
139788
139871
|
permissions: autoApprove
|
|
139789
139872
|
};
|
|
139790
139873
|
const hub = await getProcessHubClient();
|
|
139874
|
+
if (hub)
|
|
139875
|
+
await hub.setStatus("working").catch(() => void 0);
|
|
139791
139876
|
const detector = createStuckLoopDetector();
|
|
139792
139877
|
const maxIterations = ctx.maxIterations ?? DEFAULT_MAX_ITERATIONS;
|
|
139793
139878
|
let noop3 = 0;
|
|
@@ -144390,12 +144475,9 @@ var REMOTE_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
144390
144475
|
// Voice input (capability-probed; transcribe fails coded without a transcriber).
|
|
144391
144476
|
"session.hasTranscriber",
|
|
144392
144477
|
"session.transcribe",
|
|
144393
|
-
//
|
|
144394
|
-
//
|
|
144395
|
-
"chat.
|
|
144396
|
-
"chat.loadSegment",
|
|
144397
|
-
"chat.clearLog",
|
|
144398
|
-
"chat.migrate",
|
|
144478
|
+
// Read a workspace's transcript history from the runner's authoritative log
|
|
144479
|
+
// (a paired phone may read history, scoped to a workspace, not host config).
|
|
144480
|
+
"chat.loadHistory",
|
|
144399
144481
|
// Workflows: READ + run an existing one only. Authoring (`workflows.save`,
|
|
144400
144482
|
// `workflows.validateDraft`, `workflows.setEnabled`) is host-only — a paired
|
|
144401
144483
|
// phone must not rewrite or re-enable the host's workflows.
|
|
@@ -144603,25 +144685,13 @@ var ipcInputSchemas = {
|
|
|
144603
144685
|
"mobileGateway.status": z.undefined(),
|
|
144604
144686
|
"mobileGateway.rotateToken": z.undefined(),
|
|
144605
144687
|
"mobileGateway.setEnabled": z.object({ enabled: z.boolean() }).strict(),
|
|
144606
|
-
|
|
144607
|
-
|
|
144608
|
-
|
|
144609
|
-
|
|
144610
|
-
"chat.loadSegment": z.object({
|
|
144688
|
+
// `before` is a runner `seq` cursor; the page is RAW events. The runner itself
|
|
144689
|
+
// re-validates and caps at its own MAX_HISTORY_PAGE_LIMIT (2000), so bound the
|
|
144690
|
+
// renderer's raw-window request to that ceiling.
|
|
144691
|
+
"chat.loadHistory": z.object({
|
|
144611
144692
|
workspaceId: z.string().min(1).max(256),
|
|
144612
144693
|
before: z.number().int().nonnegative().nullable(),
|
|
144613
|
-
limit: z.number().int().positive().max(
|
|
144614
|
-
}),
|
|
144615
|
-
"chat.clearLog": z.object({ workspaceId: z.string().min(1).max(256) }),
|
|
144616
|
-
// chat.migrate writes the supplied events straight into per-workspace NDJSON
|
|
144617
|
-
// logs on disk, so it's a filesystem-touching command: bound both the number
|
|
144618
|
-
// of workspaces and the events per workspace, and lock the workspaceId to a
|
|
144619
|
-
// non-empty bounded slug so it can't traverse out of the log directory.
|
|
144620
|
-
"chat.migrate": z.object({
|
|
144621
|
-
workspaces: z.array(z.object({
|
|
144622
|
-
workspaceId: z.string().min(1).max(256),
|
|
144623
|
-
events: z.array(z.unknown()).max(1e4)
|
|
144624
|
-
})).max(100)
|
|
144694
|
+
limit: z.number().int().positive().max(2e3)
|
|
144625
144695
|
}),
|
|
144626
144696
|
// Vault writes are security-sensitive: lock the key name to a safe slug
|
|
144627
144697
|
// (letters/digits + . _ / - , no traversal) and bound the secret size.
|
|
@@ -144866,13 +144936,7 @@ var MobileSessionHost = class {
|
|
|
144866
144936
|
this.bus.handle("ask.respond", async ({ requestId, response }) => {
|
|
144867
144937
|
this.answerAsk(requestId, response);
|
|
144868
144938
|
});
|
|
144869
|
-
this.bus.handle("chat.
|
|
144870
|
-
this.bus.handle("chat.append", async () => {
|
|
144871
|
-
});
|
|
144872
|
-
this.bus.handle("chat.clearLog", async () => {
|
|
144873
|
-
});
|
|
144874
|
-
this.bus.handle("chat.migrate", async () => {
|
|
144875
|
-
});
|
|
144939
|
+
this.bus.handle("chat.loadHistory", async () => ({ events: [], prevCursor: null }));
|
|
144876
144940
|
}
|
|
144877
144941
|
/** Stream session events to clients + install the ask resolvers. */
|
|
144878
144942
|
wire() {
|
|
@@ -155909,6 +155973,16 @@ async function runAgentCommand(argv) {
|
|
|
155909
155973
|
for await (const _2 of session.runTurn(subtask)) void _2;
|
|
155910
155974
|
} catch {
|
|
155911
155975
|
}
|
|
155976
|
+
try {
|
|
155977
|
+
const hub = await getProcessHubClient();
|
|
155978
|
+
if (hub) {
|
|
155979
|
+
const mine = (await hub.roster()).agents.find((a2) => a2.id === hub.agentId);
|
|
155980
|
+
if (mine && mine.status !== "done") {
|
|
155981
|
+
await hub.setStatus("failed", "turn ended without calling collab_done");
|
|
155982
|
+
}
|
|
155983
|
+
}
|
|
155984
|
+
} catch {
|
|
155985
|
+
}
|
|
155912
155986
|
})();
|
|
155913
155987
|
await runUntilSignal2(runnerServer, session, turnDone);
|
|
155914
155988
|
return 0;
|