@moxxy/cli 0.14.7 → 0.14.8
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 +78 -22
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -139109,7 +139109,7 @@ function resolveCollabConfig(persisted, overrides) {
|
|
|
139109
139109
|
return {
|
|
139110
139110
|
...DEFAULT_COLLAB_CONFIG,
|
|
139111
139111
|
...stripUndefined(fromPrefs),
|
|
139112
|
-
...stripUndefined({})
|
|
139112
|
+
...stripUndefined(overrides ?? {})
|
|
139113
139113
|
};
|
|
139114
139114
|
}
|
|
139115
139115
|
function stripUndefined(obj) {
|
|
@@ -139292,6 +139292,16 @@ async function detectGit(cwd2) {
|
|
|
139292
139292
|
const repo = installed ? await isGitRepo(cwd2) : false;
|
|
139293
139293
|
return { installed, repo };
|
|
139294
139294
|
}
|
|
139295
|
+
async function tryInitGitRepo(cwd2) {
|
|
139296
|
+
let r2 = await git(cwd2, ["init", "-b", "main"]);
|
|
139297
|
+
if (r2.code !== 0)
|
|
139298
|
+
r2 = await git(cwd2, ["init"]);
|
|
139299
|
+
if (r2.code !== 0 || !await isGitRepo(cwd2))
|
|
139300
|
+
return false;
|
|
139301
|
+
await git(cwd2, ["add", "-A"]);
|
|
139302
|
+
const c2 = await git(cwd2, [...IDENTITY, "commit", "--allow-empty", "-m", "moxxy-collab: initial snapshot", "--no-verify"]);
|
|
139303
|
+
return c2.code === 0 && (await headSha(cwd2)).length > 0;
|
|
139304
|
+
}
|
|
139295
139305
|
async function headSha(cwd2) {
|
|
139296
139306
|
return (await git(cwd2, ["rev-parse", "HEAD"])).stdout.trim();
|
|
139297
139307
|
}
|
|
@@ -139397,6 +139407,19 @@ function peerReaderFor(worktrees, baseSha) {
|
|
|
139397
139407
|
}
|
|
139398
139408
|
};
|
|
139399
139409
|
}
|
|
139410
|
+
function cwdPeerReader(cwd2) {
|
|
139411
|
+
return {
|
|
139412
|
+
async files() {
|
|
139413
|
+
return await isGitRepo(cwd2) ? changedFiles(cwd2) : [];
|
|
139414
|
+
},
|
|
139415
|
+
async read(_agentId, path62) {
|
|
139416
|
+
return readFile(resolveWithin(cwd2, path62), "utf8");
|
|
139417
|
+
},
|
|
139418
|
+
async diff() {
|
|
139419
|
+
return "";
|
|
139420
|
+
}
|
|
139421
|
+
};
|
|
139422
|
+
}
|
|
139400
139423
|
var FORCE_KILL_GRACE_MS = 4e3;
|
|
139401
139424
|
var STDERR_RING = 40;
|
|
139402
139425
|
var PeerSupervisor = class {
|
|
@@ -139636,7 +139659,7 @@ async function* runCollaborative(ctx, deps) {
|
|
|
139636
139659
|
yield await ctx.emit(emitAbort(ctx, "aborted before collaboration start"));
|
|
139637
139660
|
return;
|
|
139638
139661
|
}
|
|
139639
|
-
const cfg = deps.config ?? resolveCollabConfig();
|
|
139662
|
+
const cfg = deps.config ?? resolveCollabConfig(void 0, deps.concurrencyOverride ? { concurrency: deps.concurrencyOverride } : void 0);
|
|
139640
139663
|
const cwd2 = deps.cwd ?? process.cwd();
|
|
139641
139664
|
const task = lastUserPromptText(ctx) ?? "";
|
|
139642
139665
|
if (!task.trim()) {
|
|
@@ -139662,17 +139685,22 @@ async function* runCollaborative(ctx, deps) {
|
|
|
139662
139685
|
let completed = false;
|
|
139663
139686
|
try {
|
|
139664
139687
|
mkdirSync(collabRunDir(runId), { recursive: true });
|
|
139665
|
-
const { installed: gitInstalled2, repo:
|
|
139666
|
-
|
|
139667
|
-
|
|
139688
|
+
const { installed: gitInstalled2, repo: alreadyGitRepo } = await (deps.detectGit ?? detectGit)(cwd2);
|
|
139689
|
+
let gitRepo = alreadyGitRepo;
|
|
139690
|
+
if (!gitRepo && gitInstalled2 && cfg.concurrency !== "sequential") {
|
|
139691
|
+
gitRepo = await tryInitGitRepo(cwd2).catch(() => false);
|
|
139692
|
+
}
|
|
139693
|
+
const execMode = resolveExecMode(cfg, gitRepo);
|
|
139694
|
+
const usesGit = execMode === "git-parallel";
|
|
139695
|
+
const runsParallel = execMode !== "sequential";
|
|
139696
|
+
archiveParallel = runsParallel;
|
|
139668
139697
|
archiveGitRepo = gitRepo;
|
|
139669
|
-
|
|
139670
|
-
|
|
139671
|
-
|
|
139672
|
-
}));
|
|
139698
|
+
yield await ctx.emit(plugin4(ctx, "collab_exec_mode", { mode: execMode, gitInstalled: gitInstalled2, gitRepo }));
|
|
139699
|
+
if (execMode === "sequential") {
|
|
139700
|
+
yield await ctx.emit(plugin4(ctx, "collab_fallback_sequential", { reason: "sequential mode \u2014 one agent at a time" }));
|
|
139673
139701
|
}
|
|
139674
139702
|
let baseSha = "";
|
|
139675
|
-
if (
|
|
139703
|
+
if (usesGit) {
|
|
139676
139704
|
const base2 = await resolveBase(cwd2, { snapshotDirty: true });
|
|
139677
139705
|
baseSha = base2.baseSha;
|
|
139678
139706
|
}
|
|
@@ -139686,7 +139714,9 @@ async function* runCollaborative(ctx, deps) {
|
|
|
139686
139714
|
socketPath: hubSocketPath(runId),
|
|
139687
139715
|
task,
|
|
139688
139716
|
roster: [architectEntry],
|
|
139689
|
-
|
|
139717
|
+
// git: read each agent's worktree. non-git: every agent shares one tree, so
|
|
139718
|
+
// peer-read is just "read the live shared workspace".
|
|
139719
|
+
peerReader: usesGit ? peerReaderFor(worktrees, baseSha) : cwdPeerReader(cwd2)
|
|
139690
139720
|
});
|
|
139691
139721
|
registerActiveHub(String(ctx.sessionId), hub);
|
|
139692
139722
|
unsubscribe = hub.subscribe((e3) => {
|
|
@@ -139701,7 +139731,7 @@ async function* runCollaborative(ctx, deps) {
|
|
|
139701
139731
|
signal: ctx.signal
|
|
139702
139732
|
};
|
|
139703
139733
|
supervisor = (deps.createSupervisor ?? ((o2) => new PeerSupervisor(o2)))(supervisorOpts, hub);
|
|
139704
|
-
yield await ctx.emit(plugin4(ctx, "collab_started", { task, parallel, gitInstalled: gitInstalled2, gitRepo }));
|
|
139734
|
+
yield await ctx.emit(plugin4(ctx, "collab_started", { task, parallel: runsParallel, execMode, gitInstalled: gitInstalled2, gitRepo }));
|
|
139705
139735
|
try {
|
|
139706
139736
|
const events = ctx.log.slice();
|
|
139707
139737
|
mkdirSync(join(cwd2, COLLAB_SCAFFOLD_DIR), { recursive: true });
|
|
@@ -139766,13 +139796,13 @@ ${why}` : ""}`));
|
|
|
139766
139796
|
}
|
|
139767
139797
|
}
|
|
139768
139798
|
yield await ctx.emit(plugin4(ctx, "collab_roster_confirmed", { roster }));
|
|
139769
|
-
if (
|
|
139799
|
+
if (usesGit) {
|
|
139770
139800
|
await commitAll(cwd2, "moxxy-collab: scaffold contracts");
|
|
139771
139801
|
baseSha = await headSha(cwd2);
|
|
139772
139802
|
mkdirSync(worktreeRoot(runId), { recursive: true });
|
|
139773
139803
|
}
|
|
139774
139804
|
const doneIds = [];
|
|
139775
|
-
if (parallel) {
|
|
139805
|
+
if (execMode === "git-parallel") {
|
|
139776
139806
|
for (const entry of roster) {
|
|
139777
139807
|
hub.state.addAgent(entry);
|
|
139778
139808
|
const wt3 = worktreePath(runId, entry.id);
|
|
@@ -139787,6 +139817,24 @@ ${why}` : ""}`));
|
|
|
139787
139817
|
for (const r2 of roster)
|
|
139788
139818
|
if (statusOf(hub, r2.id) === "done")
|
|
139789
139819
|
doneIds.push(r2.id);
|
|
139820
|
+
} else if (execMode === "cwd-parallel") {
|
|
139821
|
+
for (const entry of roster) {
|
|
139822
|
+
hub.state.addAgent(entry);
|
|
139823
|
+
if (entry.ownedPaths?.length) {
|
|
139824
|
+
const res = hub.state.boardClaim(entry.id, entry.ownedPaths);
|
|
139825
|
+
if (!res.ok) {
|
|
139826
|
+
yield await ctx.emit(plugin4(ctx, "collab_ownership_overlap", { id: entry.id, paths: entry.ownedPaths, ownedBy: res.ownedBy }));
|
|
139827
|
+
}
|
|
139828
|
+
}
|
|
139829
|
+
const charterFile = writeCharterFile(runId, entry);
|
|
139830
|
+
supervisor.spawn({ entry, cwd: cwd2, mode: COLLAB_PEER_MODE_NAME, ...charterFile ? { charterFile } : {} });
|
|
139831
|
+
yield await ctx.emit(plugin4(ctx, "collab_agent_spawned", { id: entry.id, role: entry.role }));
|
|
139832
|
+
}
|
|
139833
|
+
await waitForAgents(hub, supervisor, roster.map((r2) => r2.id), ctx.signal, cfg.wallClockMs);
|
|
139834
|
+
yield* surfaceFailures(ctx, hub, supervisor, roster.map((r2) => r2.id));
|
|
139835
|
+
for (const r2 of roster)
|
|
139836
|
+
if (statusOf(hub, r2.id) === "done")
|
|
139837
|
+
doneIds.push(r2.id);
|
|
139790
139838
|
} else {
|
|
139791
139839
|
for (const entry of roster) {
|
|
139792
139840
|
if (ctx.signal.aborted)
|
|
@@ -139808,7 +139856,7 @@ ${why}` : ""}`));
|
|
|
139808
139856
|
return;
|
|
139809
139857
|
}
|
|
139810
139858
|
let mergeNote = "";
|
|
139811
|
-
if (
|
|
139859
|
+
if (usesGit && doneIds.length > 0) {
|
|
139812
139860
|
const result = await integrate({
|
|
139813
139861
|
repoCwd: cwd2,
|
|
139814
139862
|
runId,
|
|
@@ -139832,11 +139880,13 @@ ${why}` : ""}`));
|
|
|
139832
139880
|
}
|
|
139833
139881
|
const summaries = hub.state.doneSummaries();
|
|
139834
139882
|
const summaryBlock = summaries.length ? summaries.map((s2) => `- **${s2.agentId}**: ${s2.summary}`).join("\n") : "(no agent reported a completion summary)";
|
|
139883
|
+
const cwdNote = execMode === "cwd-parallel" ? "The team worked together directly in your workspace; please review the result." : "";
|
|
139884
|
+
const tail = [mergeNote, cwdNote].filter(Boolean).join("\n\n");
|
|
139835
139885
|
yield await ctx.emit(assistant(ctx, `Collaboration complete \u2014 ${doneIds.length}/${roster.length} agents finished.
|
|
139836
139886
|
|
|
139837
|
-
${summaryBlock}${
|
|
139887
|
+
${summaryBlock}${tail ? `
|
|
139838
139888
|
|
|
139839
|
-
${
|
|
139889
|
+
${tail}` : ""}`));
|
|
139840
139890
|
completed = true;
|
|
139841
139891
|
yield await ctx.emit(plugin4(ctx, "collab_completed", { done: doneIds, total: roster.length }));
|
|
139842
139892
|
} finally {
|
|
@@ -139951,6 +140001,11 @@ function readRoster(path62, maxAgents) {
|
|
|
139951
140001
|
function slug(s2) {
|
|
139952
140002
|
return s2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32);
|
|
139953
140003
|
}
|
|
140004
|
+
function resolveExecMode(cfg, gitRepo) {
|
|
140005
|
+
if (cfg.concurrency === "sequential")
|
|
140006
|
+
return "sequential";
|
|
140007
|
+
return gitRepo ? "git-parallel" : "cwd-parallel";
|
|
140008
|
+
}
|
|
139954
140009
|
function cleanRole(raw) {
|
|
139955
140010
|
if (typeof raw !== "string")
|
|
139956
140011
|
return "implementer";
|
|
@@ -140108,12 +140163,13 @@ The team coordinates through a shared hub (use these tools):
|
|
|
140108
140163
|
- collab_send / collab_broadcast \u2014 message a teammate by id, or the whole team.
|
|
140109
140164
|
- collab_board / collab_add_task / collab_update \u2014 the shared task board (what's done / in progress / blocked).
|
|
140110
140165
|
- collab_contracts \u2014 the agreed interfaces/boundaries you must build to.
|
|
140111
|
-
- collab_claim(paths) \u2014
|
|
140112
|
-
- collab_release \u2014 release a claim
|
|
140113
|
-
- collab_peer_read / collab_peer_files / collab_peer_diff \u2014 read a teammate's ACTUAL in-progress work (get their real interface instead of guessing).
|
|
140166
|
+
- collab_claim(paths) \u2014 you may SHARE ONE LIVE WORKSPACE with the other agents (no isolation), so you MUST collab_claim a file BEFORE every edit and only edit files you currently own. If a claim is REJECTED another agent owns it: collab_send that owner, agree who edits, and do NOT touch it until you own it. Claim the NARROWEST set you need (single files, not whole dirs) so you don't block teammates. If you RENAME or MOVE a file, claim BOTH the old and the new path first.
|
|
140167
|
+
- collab_release \u2014 release a claim the moment you finish a file so others can proceed.
|
|
140168
|
+
- collab_peer_read / collab_peer_files / collab_peer_diff \u2014 read a teammate's ACTUAL in-progress work (get their real interface instead of guessing). Only rely on work a teammate has said is done \u2014 a file may be mid-write.
|
|
140114
140169
|
|
|
140115
140170
|
Cooperation rules:
|
|
140116
140171
|
- Build strictly to the shared contracts. If you must change a shared boundary, use collab_contract_propose_change and wait for acks \u2014 never break a contract unilaterally.
|
|
140172
|
+
- Shared/aggregator files (package.json, a lockfile, a barrel index, a shared types file) have ONE owner \u2014 never edit one you don't own; ask its owner via collab_send to make the change for you.
|
|
140117
140173
|
- The human may step in at any time. When you receive a HUMAN directive or a message from "human", treat it as authoritative (it overrides your current plan), and REPLY to them with collab_send to "human" \u2014 acknowledge it and say what you'll do (or ask a brief clarifying question). Don't go silent on the human. If the team is paused, finish your current edit and wait.
|
|
140118
140174
|
- Keep teammates informed: broadcast meaningful progress and blockers.
|
|
140119
140175
|
- When YOUR sub-task is fully complete and verified, call collab_done with a short summary. The run finishes when everyone is done.`;
|
|
@@ -140125,7 +140181,7 @@ var COLLAB_ARCHITECT_PROMPT = `${COLLAB_COMMON}
|
|
|
140125
140181
|
You are the ARCHITECT \u2014 you run FIRST and set the team up for success. Your job, in order:
|
|
140126
140182
|
0. Read ${COLLAB_SCAFFOLD_DIR}/${BRIEF_FILENAME} \u2014 the goal + key-requirements summary \u2014 so you decompose toward what the user actually wants. If you need a detail it omits, grep ${COLLAB_SCAFFOLD_DIR}/${CONVERSATION_FILENAME}.
|
|
140127
140183
|
1. Explore the workspace to understand the task and its boundaries.
|
|
140128
|
-
2. Assemble the RIGHT TEAM for THIS deliverable and decompose into INDEPENDENT sub-tasks with DISJOINT ownership (minimize overlap). Pick the roles the work actually needs \u2014 a coding task wants developers + a QA reviewer; a document/plan/design deliverable wants a writer, a researcher, a designer, an editor; a product effort may want a PM to sequence + verify. Don't default everyone to a generic "implementer".
|
|
140184
|
+
2. Assemble the RIGHT TEAM for THIS deliverable and decompose into INDEPENDENT sub-tasks with DISJOINT ownership (minimize overlap). Pick the roles the work actually needs \u2014 a coding task wants developers + a QA reviewer; a document/plan/design deliverable wants a writer, a researcher, a designer, an editor; a product effort may want a PM to sequence + verify. Don't default everyone to a generic "implementer". The team may run together in ONE shared workspace with only advisory file locks, so ownedPaths MUST be DISJOINT \u2014 give each agent its own specific files/leaf dirs with NO overlap. If two roles would both need one shared file (a router, a barrel index, package.json), give it to ONE owner and have the other coordinate via collab_send or a contract; never assign the same path to two agents. Every roster entry MUST declare ownedPaths.
|
|
140129
140185
|
3. Define the shared CONTRACTS \u2014 the interfaces, types, API shapes, section outlines, or boundaries where the team's work meets. Publish each with collab_contract_publish (give an owner + consumers).
|
|
140130
140186
|
4. Write two files into the repo:
|
|
140131
140187
|
- ${COLLAB_SCAFFOLD_DIR}/${CONTRACTS_FILENAME} \u2014 human-readable contracts/boundaries the team must follow.
|
|
@@ -156299,7 +156355,7 @@ async function runAgentCommand(argv) {
|
|
|
156299
156355
|
}
|
|
156300
156356
|
function buildSeedTurn(args) {
|
|
156301
156357
|
const { role, parentTask, subtask } = args;
|
|
156302
|
-
const pointer = "Shared team context is in `.moxxy-collab/BRIEF.md` (a concise summary of the user's goal + key requirements) and `.moxxy-collab/CONTRACTS.md` (the agreed interfaces). Read them before you start so your work fits the real goal. If you need a detail the brief omits, read or grep `.moxxy-collab/CONVERSATION.md` (the full transcript) \u2014 do not load it wholesale.";
|
|
156358
|
+
const pointer = "Shared team context is in `.moxxy-collab/BRIEF.md` (a concise summary of the user's goal + key requirements) and `.moxxy-collab/CONTRACTS.md` (the agreed interfaces). Read them before you start so your work fits the real goal. If you need a detail the brief omits, read or grep `.moxxy-collab/CONVERSATION.md` (the full transcript) \u2014 do not load it wholesale. You may share ONE live workspace with the other agents (no isolation) \u2014 collab_claim before every edit, edit only what you own, and release when done.";
|
|
156303
156359
|
if (role === "architect" || !parentTask || parentTask === subtask) {
|
|
156304
156360
|
return subtask ? `${subtask}
|
|
156305
156361
|
|