@moxxy/cli 0.14.5 → 0.14.6
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 +108 -14
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -85713,17 +85713,25 @@ function handleCollabEvent(e3, ref, root) {
|
|
|
85713
85713
|
if (typeof item.id === "string") {
|
|
85714
85714
|
const existing = block.tasks.find((x4) => x4.id === item.id);
|
|
85715
85715
|
const owner = typeof item.owner === "string" ? item.owner : null;
|
|
85716
|
+
const paths = Array.isArray(item.paths) ? item.paths.filter((x4) => typeof x4 === "string") : void 0;
|
|
85717
|
+
const detail = typeof item.detail === "string" ? item.detail : void 0;
|
|
85716
85718
|
if (!existing) {
|
|
85717
85719
|
block.tasks.push({
|
|
85718
85720
|
id: item.id,
|
|
85719
85721
|
title: String(item.title ?? ""),
|
|
85720
85722
|
status: String(item.status ?? "open"),
|
|
85721
|
-
owner
|
|
85723
|
+
owner,
|
|
85724
|
+
...paths && paths.length > 0 ? { paths } : {},
|
|
85725
|
+
...detail ? { detail } : {}
|
|
85722
85726
|
});
|
|
85723
85727
|
} else {
|
|
85724
85728
|
existing.title = String(item.title ?? existing.title);
|
|
85725
85729
|
existing.status = String(item.status ?? existing.status);
|
|
85726
85730
|
existing.owner = owner ?? existing.owner;
|
|
85731
|
+
if (paths && paths.length > 0)
|
|
85732
|
+
existing.paths = paths;
|
|
85733
|
+
if (detail)
|
|
85734
|
+
existing.detail = detail;
|
|
85727
85735
|
}
|
|
85728
85736
|
}
|
|
85729
85737
|
break;
|
|
@@ -139148,6 +139156,21 @@ function buildBrief(task, events) {
|
|
|
139148
139156
|
return `${brief}
|
|
139149
139157
|
`;
|
|
139150
139158
|
}
|
|
139159
|
+
function moxxyHome2() {
|
|
139160
|
+
return process.env.MOXXY_HOME ?? join(homedir(), ".moxxy");
|
|
139161
|
+
}
|
|
139162
|
+
function collabRunsDir() {
|
|
139163
|
+
return join(moxxyHome2(), "collab", "runs");
|
|
139164
|
+
}
|
|
139165
|
+
function writeRunRecord(rec) {
|
|
139166
|
+
try {
|
|
139167
|
+
const dir = collabRunsDir();
|
|
139168
|
+
mkdirSync(dir, { recursive: true });
|
|
139169
|
+
writeFileSync(join(dir, `${rec.runId}.json`), `${JSON.stringify(rec, null, 2)}
|
|
139170
|
+
`);
|
|
139171
|
+
} catch {
|
|
139172
|
+
}
|
|
139173
|
+
}
|
|
139151
139174
|
var IDENTITY = ["-c", "user.name=moxxy-collab", "-c", "user.email=collab@moxxy.local"];
|
|
139152
139175
|
function git(cwd2, args) {
|
|
139153
139176
|
return new Promise((resolve13) => {
|
|
@@ -139526,14 +139549,22 @@ async function* runCollaborative(ctx, deps) {
|
|
|
139526
139549
|
return;
|
|
139527
139550
|
}
|
|
139528
139551
|
const runId = collabRunId(String(ctx.sessionId), String(ctx.turnId));
|
|
139552
|
+
const startedAtMs = Date.now();
|
|
139529
139553
|
const worktrees = /* @__PURE__ */ new Map();
|
|
139530
139554
|
let hub = null;
|
|
139531
139555
|
let supervisor = null;
|
|
139532
139556
|
let unsubscribe = null;
|
|
139557
|
+
let archiveParallel = false;
|
|
139558
|
+
let archiveGitRepo = false;
|
|
139559
|
+
let briefText = "";
|
|
139560
|
+
let mergeForArchive;
|
|
139561
|
+
let completed = false;
|
|
139533
139562
|
try {
|
|
139534
139563
|
mkdirSync(collabRunDir(runId), { recursive: true });
|
|
139535
139564
|
const { installed: gitInstalled2, repo: gitRepo } = await detectGit(cwd2);
|
|
139536
139565
|
const parallel = cfg.concurrency === "parallel" && gitRepo;
|
|
139566
|
+
archiveParallel = parallel;
|
|
139567
|
+
archiveGitRepo = gitRepo;
|
|
139537
139568
|
if (!parallel) {
|
|
139538
139569
|
yield await ctx.emit(plugin4(ctx, "collab_fallback_sequential", {
|
|
139539
139570
|
reason: !gitInstalled2 ? "git is not installed \u2014 running agents sequentially in your workspace" : !gitRepo ? "this folder is not a git repository \u2014 running agents sequentially in your workspace" : "sequential mode selected"
|
|
@@ -139571,8 +139602,9 @@ async function* runCollaborative(ctx, deps) {
|
|
|
139571
139602
|
supervisor = (deps.createSupervisor ?? ((o2) => new PeerSupervisor(o2)))(supervisorOpts, hub);
|
|
139572
139603
|
yield await ctx.emit(plugin4(ctx, "collab_started", { task, parallel, gitInstalled: gitInstalled2, gitRepo }));
|
|
139573
139604
|
try {
|
|
139605
|
+
briefText = buildBrief(task, ctx.log.slice());
|
|
139574
139606
|
mkdirSync(join(cwd2, COLLAB_SCAFFOLD_DIR), { recursive: true });
|
|
139575
|
-
writeFileSync(join(cwd2, COLLAB_SCAFFOLD_DIR, BRIEF_FILENAME),
|
|
139607
|
+
writeFileSync(join(cwd2, COLLAB_SCAFFOLD_DIR, BRIEF_FILENAME), briefText);
|
|
139576
139608
|
yield await ctx.emit(plugin4(ctx, "collab_brief_written", { path: join(COLLAB_SCAFFOLD_DIR, BRIEF_FILENAME) }));
|
|
139577
139609
|
} catch {
|
|
139578
139610
|
}
|
|
@@ -139665,6 +139697,12 @@ ${why}` : ""}`));
|
|
|
139665
139697
|
board: hub.state.boardItems(),
|
|
139666
139698
|
mergePolicy: cfg.mergePolicy
|
|
139667
139699
|
});
|
|
139700
|
+
mergeForArchive = {
|
|
139701
|
+
merged: result.merged,
|
|
139702
|
+
promoted: result.promoted,
|
|
139703
|
+
conflicts: result.conflicts.length,
|
|
139704
|
+
...result.stagingBranch ? { stagingBranch: result.stagingBranch } : {}
|
|
139705
|
+
};
|
|
139668
139706
|
yield await ctx.emit(plugin4(ctx, "collab_merge", result));
|
|
139669
139707
|
for (const c2 of result.conflicts) {
|
|
139670
139708
|
yield await ctx.emit(plugin4(ctx, "collab_conflict", c2));
|
|
@@ -139678,10 +139716,54 @@ ${why}` : ""}`));
|
|
|
139678
139716
|
${summaryBlock}${mergeNote ? `
|
|
139679
139717
|
|
|
139680
139718
|
${mergeNote}` : ""}`));
|
|
139719
|
+
completed = true;
|
|
139681
139720
|
yield await ctx.emit(plugin4(ctx, "collab_completed", { done: doneIds, total: roster.length }));
|
|
139682
139721
|
} finally {
|
|
139683
139722
|
if (supervisor)
|
|
139684
139723
|
await supervisor.shutdownAll("collaboration complete");
|
|
139724
|
+
if (hub) {
|
|
139725
|
+
try {
|
|
139726
|
+
const agents = hub.state.rosterView().agents;
|
|
139727
|
+
const implementers = agents.filter((a2) => a2.role !== "architect");
|
|
139728
|
+
writeRunRecord({
|
|
139729
|
+
runId,
|
|
139730
|
+
task,
|
|
139731
|
+
startedAtMs,
|
|
139732
|
+
finishedAtMs: Date.now(),
|
|
139733
|
+
outcome: completed ? "completed" : ctx.signal.aborted ? "aborted" : "failed",
|
|
139734
|
+
parallel: archiveParallel,
|
|
139735
|
+
gitRepo: archiveGitRepo,
|
|
139736
|
+
agents: agents.map((a2) => ({
|
|
139737
|
+
id: a2.id,
|
|
139738
|
+
name: a2.name,
|
|
139739
|
+
role: a2.role,
|
|
139740
|
+
status: a2.status,
|
|
139741
|
+
subtask: a2.subtask,
|
|
139742
|
+
...a2.doneSummary ? { doneSummary: a2.doneSummary } : {}
|
|
139743
|
+
})),
|
|
139744
|
+
doneCount: implementers.filter((a2) => a2.status === "done").length,
|
|
139745
|
+
totalCount: implementers.length,
|
|
139746
|
+
board: hub.state.boardItems().map((b3) => ({
|
|
139747
|
+
id: b3.id,
|
|
139748
|
+
title: b3.title,
|
|
139749
|
+
status: b3.status,
|
|
139750
|
+
...b3.owner ? { owner: b3.owner } : {},
|
|
139751
|
+
...b3.paths ? { paths: b3.paths } : {}
|
|
139752
|
+
})),
|
|
139753
|
+
contracts: hub.state.contractList().map((c2) => ({
|
|
139754
|
+
id: c2.id,
|
|
139755
|
+
title: c2.title,
|
|
139756
|
+
owner: c2.owner,
|
|
139757
|
+
status: c2.status,
|
|
139758
|
+
version: c2.version
|
|
139759
|
+
})),
|
|
139760
|
+
messageCount: hub.state.allMessages().length,
|
|
139761
|
+
...mergeForArchive ? { merge: mergeForArchive } : {},
|
|
139762
|
+
...briefText ? { brief: briefText } : {}
|
|
139763
|
+
});
|
|
139764
|
+
} catch {
|
|
139765
|
+
}
|
|
139766
|
+
}
|
|
139685
139767
|
if (unsubscribe)
|
|
139686
139768
|
unsubscribe();
|
|
139687
139769
|
unregisterActiveHub(String(ctx.sessionId));
|
|
@@ -139729,7 +139811,9 @@ function readRoster(path62, maxAgents) {
|
|
|
139729
139811
|
out.push({
|
|
139730
139812
|
id,
|
|
139731
139813
|
name: typeof r2.name === "string" ? r2.name : id,
|
|
139732
|
-
role
|
|
139814
|
+
// Carry the architect's proposed role (pm/designer/developer/qa/writer/…)
|
|
139815
|
+
// so the team is cross-functional, not a pool of identical implementers.
|
|
139816
|
+
role: cleanRole(r2.role),
|
|
139733
139817
|
subtask: r2.subtask,
|
|
139734
139818
|
...Array.isArray(r2.ownedPaths) ? { ownedPaths: r2.ownedPaths.filter((p3) => typeof p3 === "string") } : {},
|
|
139735
139819
|
...typeof r2.model === "string" ? { model: r2.model } : {}
|
|
@@ -139745,6 +139829,14 @@ function readRoster(path62, maxAgents) {
|
|
|
139745
139829
|
function slug(s2) {
|
|
139746
139830
|
return s2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32);
|
|
139747
139831
|
}
|
|
139832
|
+
function cleanRole(raw) {
|
|
139833
|
+
if (typeof raw !== "string")
|
|
139834
|
+
return "implementer";
|
|
139835
|
+
const r2 = raw.toLowerCase().replace(/[^a-z0-9 -]/g, "").replace(/\s+/g, " ").trim().slice(0, 24);
|
|
139836
|
+
if (!r2 || r2 === ARCHITECT_AGENT_ID)
|
|
139837
|
+
return "implementer";
|
|
139838
|
+
return r2;
|
|
139839
|
+
}
|
|
139748
139840
|
function statusOf(hub, id) {
|
|
139749
139841
|
return hub.state.rosterView().agents.find((a2) => a2.id === id)?.status;
|
|
139750
139842
|
}
|
|
@@ -139885,22 +139977,22 @@ The team coordinates through a shared hub (use these tools):
|
|
|
139885
139977
|
|
|
139886
139978
|
Cooperation rules:
|
|
139887
139979
|
- 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.
|
|
139888
|
-
- The human may step in at any time
|
|
139980
|
+
- 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.
|
|
139889
139981
|
- Keep teammates informed: broadcast meaningful progress and blockers.
|
|
139890
139982
|
- When YOUR sub-task is fully complete and verified, call collab_done with a short summary. The run finishes when everyone is done.`;
|
|
139891
139983
|
var COLLAB_PEER_PROMPT = `${COLLAB_COMMON}
|
|
139892
139984
|
|
|
139893
|
-
You are
|
|
139985
|
+
You are a TEAM MEMBER with a specific role (given below) and sub-task. Work as that role \u2014 a writer writes, a designer designs, a developer builds, a QA reviews, a PM sequences + verifies. Start by reading ${COLLAB_SCAFFOLD_DIR}/${BRIEF_FILENAME} (the goal + intent) and ${COLLAB_SCAFFOLD_DIR}/${CONTRACTS_FILENAME}, and calling collab_contracts, collab_roster, and collab_board so you know the plan and who owns what. Claim your files, deliver your part against the contracts, coordinate on intersections, then call collab_done.`;
|
|
139894
139986
|
var COLLAB_ARCHITECT_PROMPT = `${COLLAB_COMMON}
|
|
139895
139987
|
|
|
139896
139988
|
You are the ARCHITECT \u2014 you run FIRST and set the team up for success. Your job, in order:
|
|
139897
139989
|
0. Read ${COLLAB_SCAFFOLD_DIR}/${BRIEF_FILENAME} \u2014 the user's goal and the conversation behind it \u2014 so you decompose toward what they actually want.
|
|
139898
139990
|
1. Explore the workspace to understand the task and its boundaries.
|
|
139899
|
-
2.
|
|
139900
|
-
3. Define the shared CONTRACTS \u2014 the interfaces, types, API shapes,
|
|
139991
|
+
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".
|
|
139992
|
+
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).
|
|
139901
139993
|
4. Write two files into the repo:
|
|
139902
|
-
- ${COLLAB_SCAFFOLD_DIR}/${CONTRACTS_FILENAME} \u2014 human-readable contracts/boundaries the
|
|
139903
|
-
- ${COLLAB_SCAFFOLD_DIR}/${ROSTER_FILENAME} \u2014 a JSON array proposing the
|
|
139994
|
+
- ${COLLAB_SCAFFOLD_DIR}/${CONTRACTS_FILENAME} \u2014 human-readable contracts/boundaries the team must follow.
|
|
139995
|
+
- ${COLLAB_SCAFFOLD_DIR}/${ROSTER_FILENAME} \u2014 a JSON array proposing the team. Each entry: { "id": "kebab-slug", "name": "Display Name", "role": "<function>", "subtask": "what this agent delivers", "ownedPaths": ["dir/", "file.md"] }. "role" is the agent's FUNCTION \u2014 e.g. "developer", "designer", "pm", "qa", "writer", "researcher", "editor" \u2014 choose what fits. Do NOT include yourself, and do NOT use "architect" (that's you).
|
|
139904
139996
|
5. Broadcast a short kickoff summary, then call collab_done.
|
|
139905
139997
|
|
|
139906
139998
|
After the implementers start, you stay available as the BROKER: answer interface questions, and when an implementer proposes a contract change, review it and (if sound) commit it with collab_contract_update so everyone re-syncs.`;
|
|
@@ -149574,13 +149666,13 @@ async function runWorkflow(workflow, deps, opts = {}) {
|
|
|
149574
149666
|
const startedAt = (deps.now ?? Date.now)();
|
|
149575
149667
|
const result = await executor.run(workflow, deps);
|
|
149576
149668
|
if (opts.recordDir !== null) {
|
|
149577
|
-
await
|
|
149669
|
+
await writeRunRecord2(workflow, result, startedAt, executor.name, deps, opts.recordDir ?? defaultRunRecordDir()).catch((err) => deps.logger?.warn?.("workflow: failed to write run record", {
|
|
149578
149670
|
error: err instanceof Error ? err.message : String(err)
|
|
149579
149671
|
}));
|
|
149580
149672
|
}
|
|
149581
149673
|
return result;
|
|
149582
149674
|
}
|
|
149583
|
-
async function
|
|
149675
|
+
async function writeRunRecord2(workflow, result, startedAt, executorName, deps, dir) {
|
|
149584
149676
|
await promises.mkdir(dir, { recursive: true });
|
|
149585
149677
|
const stamp = new Date(startedAt).toISOString().replace(/[:.]/g, "-");
|
|
149586
149678
|
const file = path3.join(dir, `${stamp}-${workflow.name}-${ulid().slice(-6)}.jsonl`);
|
|
@@ -153961,11 +154053,11 @@ function servicePlatform() {
|
|
|
153961
154053
|
if (process.platform === "linux") return "linux";
|
|
153962
154054
|
return "unsupported";
|
|
153963
154055
|
}
|
|
153964
|
-
function
|
|
154056
|
+
function moxxyHome3() {
|
|
153965
154057
|
return process.env.MOXXY_HOME ?? path3__default.join(homedir(), ".moxxy");
|
|
153966
154058
|
}
|
|
153967
154059
|
function serviceLogPath(spec) {
|
|
153968
|
-
return path3__default.join(
|
|
154060
|
+
return path3__default.join(moxxyHome3(), "services", `${spec.id}.log`);
|
|
153969
154061
|
}
|
|
153970
154062
|
function nodeBin() {
|
|
153971
154063
|
return process.execPath;
|
|
@@ -156057,7 +156149,9 @@ function buildSeedTurn(args) {
|
|
|
156057
156149
|
|
|
156058
156150
|
${pointer}` : pointer;
|
|
156059
156151
|
}
|
|
156060
|
-
|
|
156152
|
+
const roleLine = role && role !== "implementer" ? `Your role on the team: ${role}.
|
|
156153
|
+
` : "";
|
|
156154
|
+
return `${roleLine}Overall team goal: ${parentTask}
|
|
156061
156155
|
|
|
156062
156156
|
Your sub-task: ${subtask}
|
|
156063
156157
|
|