@moxxy/cli 0.14.4 → 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 +202 -32
- 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, rmSync, statSync, readdirSync,
|
|
5
|
+
import fs32__default, { existsSync, promises, ReadStream, mkdirSync, writeFileSync, rmSync, statSync, readdirSync, 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';
|
|
@@ -81553,10 +81553,10 @@ var init_output = __esm({
|
|
|
81553
81553
|
transformers
|
|
81554
81554
|
});
|
|
81555
81555
|
}
|
|
81556
|
-
clip(
|
|
81556
|
+
clip(clip2) {
|
|
81557
81557
|
this.operations.push({
|
|
81558
81558
|
type: "clip",
|
|
81559
|
-
clip
|
|
81559
|
+
clip: clip2
|
|
81560
81560
|
});
|
|
81561
81561
|
}
|
|
81562
81562
|
unclip() {
|
|
@@ -81590,40 +81590,40 @@ var init_output = __esm({
|
|
|
81590
81590
|
const { text, transformers } = operation;
|
|
81591
81591
|
let { x: x4, y: y2 } = operation;
|
|
81592
81592
|
let lines = text.split("\n");
|
|
81593
|
-
const
|
|
81594
|
-
if (
|
|
81595
|
-
const clipHorizontally = typeof
|
|
81596
|
-
const clipVertically = typeof
|
|
81593
|
+
const clip2 = clips.at(-1);
|
|
81594
|
+
if (clip2) {
|
|
81595
|
+
const clipHorizontally = typeof clip2?.x1 === "number" && typeof clip2?.x2 === "number";
|
|
81596
|
+
const clipVertically = typeof clip2?.y1 === "number" && typeof clip2?.y2 === "number";
|
|
81597
81597
|
if (clipHorizontally) {
|
|
81598
81598
|
const width = widestLine(text);
|
|
81599
|
-
if (x4 + width <
|
|
81599
|
+
if (x4 + width < clip2.x1 || x4 > clip2.x2) {
|
|
81600
81600
|
continue;
|
|
81601
81601
|
}
|
|
81602
81602
|
}
|
|
81603
81603
|
if (clipVertically) {
|
|
81604
81604
|
const height = lines.length;
|
|
81605
|
-
if (y2 + height <
|
|
81605
|
+
if (y2 + height < clip2.y1 || y2 > clip2.y2) {
|
|
81606
81606
|
continue;
|
|
81607
81607
|
}
|
|
81608
81608
|
}
|
|
81609
81609
|
if (clipHorizontally) {
|
|
81610
81610
|
lines = lines.map((line) => {
|
|
81611
|
-
const from = x4 <
|
|
81611
|
+
const from = x4 < clip2.x1 ? clip2.x1 - x4 : 0;
|
|
81612
81612
|
const width = stringWidth(line);
|
|
81613
|
-
const to = x4 + width >
|
|
81613
|
+
const to = x4 + width > clip2.x2 ? clip2.x2 - x4 : width;
|
|
81614
81614
|
return sliceAnsi2(line, from, to);
|
|
81615
81615
|
});
|
|
81616
|
-
if (x4 <
|
|
81617
|
-
x4 =
|
|
81616
|
+
if (x4 < clip2.x1) {
|
|
81617
|
+
x4 = clip2.x1;
|
|
81618
81618
|
}
|
|
81619
81619
|
}
|
|
81620
81620
|
if (clipVertically) {
|
|
81621
|
-
const from = y2 <
|
|
81621
|
+
const from = y2 < clip2.y1 ? clip2.y1 - y2 : 0;
|
|
81622
81622
|
const height = lines.length;
|
|
81623
|
-
const to = y2 + height >
|
|
81623
|
+
const to = y2 + height > clip2.y2 ? clip2.y2 - y2 : height;
|
|
81624
81624
|
lines = lines.slice(from, to);
|
|
81625
|
-
if (y2 <
|
|
81626
|
-
y2 =
|
|
81625
|
+
if (y2 < clip2.y1) {
|
|
81626
|
+
y2 = clip2.y1;
|
|
81627
81627
|
}
|
|
81628
81628
|
}
|
|
81629
81629
|
}
|
|
@@ -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;
|
|
@@ -136051,6 +136059,7 @@ var ARCHITECT_AGENT_ID = "architect";
|
|
|
136051
136059
|
var COLLAB_SCAFFOLD_DIR = ".moxxy-collab";
|
|
136052
136060
|
var CONTRACTS_FILENAME = "CONTRACTS.md";
|
|
136053
136061
|
var ROSTER_FILENAME = "roster.json";
|
|
136062
|
+
var BRIEF_FILENAME = "BRIEF.md";
|
|
136054
136063
|
function collabRunId(sessionId, turnId) {
|
|
136055
136064
|
const tail = (s2) => s2.replace(/[^a-zA-Z0-9]/g, "").slice(-6) || "x";
|
|
136056
136065
|
return `${tail(sessionId)}-${tail(turnId)}`;
|
|
@@ -139100,6 +139109,68 @@ function resolveCollabConfig(persisted, overrides) {
|
|
|
139100
139109
|
function stripUndefined(obj) {
|
|
139101
139110
|
return Object.fromEntries(Object.entries(obj).filter(([, v3]) => v3 !== void 0));
|
|
139102
139111
|
}
|
|
139112
|
+
var MAX_MSG_CHARS = 600;
|
|
139113
|
+
var MAX_TOTAL_CHARS = 6e3;
|
|
139114
|
+
function clip(s2, n2) {
|
|
139115
|
+
const t2 = s2.trim().replace(/\s+/g, " ");
|
|
139116
|
+
return t2.length > n2 ? `${t2.slice(0, n2 - 1)}\u2026` : t2;
|
|
139117
|
+
}
|
|
139118
|
+
function digestTurns(events) {
|
|
139119
|
+
const out = [];
|
|
139120
|
+
for (const raw of events) {
|
|
139121
|
+
const e3 = raw;
|
|
139122
|
+
if (e3.type === "user_prompt" && typeof e3.text === "string" && e3.text.trim()) {
|
|
139123
|
+
out.push({ role: "user", text: e3.text });
|
|
139124
|
+
} else if (e3.type === "assistant_message" && e3.source === "model" && typeof e3.content === "string" && e3.content.trim()) {
|
|
139125
|
+
out.push({ role: "assistant", text: e3.content });
|
|
139126
|
+
}
|
|
139127
|
+
}
|
|
139128
|
+
return out;
|
|
139129
|
+
}
|
|
139130
|
+
function buildBrief(task, events) {
|
|
139131
|
+
const turns = digestTurns(events);
|
|
139132
|
+
const trimmed = turns.length > 0 && turns[turns.length - 1].role === "user" && turns[turns.length - 1].text.trim() === task.trim() ? turns.slice(0, -1) : turns;
|
|
139133
|
+
const recent = trimmed.slice(-12);
|
|
139134
|
+
const lines = [
|
|
139135
|
+
"# Collaboration brief",
|
|
139136
|
+
"",
|
|
139137
|
+
"This is the shared context for the whole team. It is the user's goal and the",
|
|
139138
|
+
"conversation that led to it \u2014 read it before planning so your work fits the",
|
|
139139
|
+
"real intent, not just your narrow sub-task.",
|
|
139140
|
+
"",
|
|
139141
|
+
"## Goal",
|
|
139142
|
+
"",
|
|
139143
|
+
clip(task, 1500) || "(no goal text)"
|
|
139144
|
+
];
|
|
139145
|
+
if (recent.length > 0) {
|
|
139146
|
+
lines.push("", "## Conversation so far", "");
|
|
139147
|
+
for (const t2 of recent) {
|
|
139148
|
+
const who = t2.role === "user" ? "User" : "Assistant";
|
|
139149
|
+
lines.push(`- **${who}:** ${clip(t2.text, MAX_MSG_CHARS)}`);
|
|
139150
|
+
}
|
|
139151
|
+
}
|
|
139152
|
+
let brief = lines.join("\n");
|
|
139153
|
+
if (brief.length > MAX_TOTAL_CHARS) {
|
|
139154
|
+
brief = `${brief.slice(0, MAX_TOTAL_CHARS - 1)}\u2026`;
|
|
139155
|
+
}
|
|
139156
|
+
return `${brief}
|
|
139157
|
+
`;
|
|
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
|
+
}
|
|
139103
139174
|
var IDENTITY = ["-c", "user.name=moxxy-collab", "-c", "user.email=collab@moxxy.local"];
|
|
139104
139175
|
function git(cwd2, args) {
|
|
139105
139176
|
return new Promise((resolve13) => {
|
|
@@ -139478,14 +139549,22 @@ async function* runCollaborative(ctx, deps) {
|
|
|
139478
139549
|
return;
|
|
139479
139550
|
}
|
|
139480
139551
|
const runId = collabRunId(String(ctx.sessionId), String(ctx.turnId));
|
|
139552
|
+
const startedAtMs = Date.now();
|
|
139481
139553
|
const worktrees = /* @__PURE__ */ new Map();
|
|
139482
139554
|
let hub = null;
|
|
139483
139555
|
let supervisor = null;
|
|
139484
139556
|
let unsubscribe = null;
|
|
139557
|
+
let archiveParallel = false;
|
|
139558
|
+
let archiveGitRepo = false;
|
|
139559
|
+
let briefText = "";
|
|
139560
|
+
let mergeForArchive;
|
|
139561
|
+
let completed = false;
|
|
139485
139562
|
try {
|
|
139486
139563
|
mkdirSync(collabRunDir(runId), { recursive: true });
|
|
139487
139564
|
const { installed: gitInstalled2, repo: gitRepo } = await detectGit(cwd2);
|
|
139488
139565
|
const parallel = cfg.concurrency === "parallel" && gitRepo;
|
|
139566
|
+
archiveParallel = parallel;
|
|
139567
|
+
archiveGitRepo = gitRepo;
|
|
139489
139568
|
if (!parallel) {
|
|
139490
139569
|
yield await ctx.emit(plugin4(ctx, "collab_fallback_sequential", {
|
|
139491
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"
|
|
@@ -139522,6 +139601,13 @@ async function* runCollaborative(ctx, deps) {
|
|
|
139522
139601
|
};
|
|
139523
139602
|
supervisor = (deps.createSupervisor ?? ((o2) => new PeerSupervisor(o2)))(supervisorOpts, hub);
|
|
139524
139603
|
yield await ctx.emit(plugin4(ctx, "collab_started", { task, parallel, gitInstalled: gitInstalled2, gitRepo }));
|
|
139604
|
+
try {
|
|
139605
|
+
briefText = buildBrief(task, ctx.log.slice());
|
|
139606
|
+
mkdirSync(join(cwd2, COLLAB_SCAFFOLD_DIR), { recursive: true });
|
|
139607
|
+
writeFileSync(join(cwd2, COLLAB_SCAFFOLD_DIR, BRIEF_FILENAME), briefText);
|
|
139608
|
+
yield await ctx.emit(plugin4(ctx, "collab_brief_written", { path: join(COLLAB_SCAFFOLD_DIR, BRIEF_FILENAME) }));
|
|
139609
|
+
} catch {
|
|
139610
|
+
}
|
|
139525
139611
|
supervisor.spawn({ entry: architectEntry, cwd: cwd2, mode: COLLAB_ARCHITECT_MODE_NAME });
|
|
139526
139612
|
yield await ctx.emit(plugin4(ctx, "collab_agent_spawned", { id: ARCHITECT_AGENT_ID, role: "architect" }));
|
|
139527
139613
|
const architectOk = await waitForAgent(hub, supervisor, ARCHITECT_AGENT_ID, ctx.signal, cfg.wallClockMs);
|
|
@@ -139611,6 +139697,12 @@ ${why}` : ""}`));
|
|
|
139611
139697
|
board: hub.state.boardItems(),
|
|
139612
139698
|
mergePolicy: cfg.mergePolicy
|
|
139613
139699
|
});
|
|
139700
|
+
mergeForArchive = {
|
|
139701
|
+
merged: result.merged,
|
|
139702
|
+
promoted: result.promoted,
|
|
139703
|
+
conflicts: result.conflicts.length,
|
|
139704
|
+
...result.stagingBranch ? { stagingBranch: result.stagingBranch } : {}
|
|
139705
|
+
};
|
|
139614
139706
|
yield await ctx.emit(plugin4(ctx, "collab_merge", result));
|
|
139615
139707
|
for (const c2 of result.conflicts) {
|
|
139616
139708
|
yield await ctx.emit(plugin4(ctx, "collab_conflict", c2));
|
|
@@ -139624,10 +139716,54 @@ ${why}` : ""}`));
|
|
|
139624
139716
|
${summaryBlock}${mergeNote ? `
|
|
139625
139717
|
|
|
139626
139718
|
${mergeNote}` : ""}`));
|
|
139719
|
+
completed = true;
|
|
139627
139720
|
yield await ctx.emit(plugin4(ctx, "collab_completed", { done: doneIds, total: roster.length }));
|
|
139628
139721
|
} finally {
|
|
139629
139722
|
if (supervisor)
|
|
139630
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
|
+
}
|
|
139631
139767
|
if (unsubscribe)
|
|
139632
139768
|
unsubscribe();
|
|
139633
139769
|
unregisterActiveHub(String(ctx.sessionId));
|
|
@@ -139675,7 +139811,9 @@ function readRoster(path62, maxAgents) {
|
|
|
139675
139811
|
out.push({
|
|
139676
139812
|
id,
|
|
139677
139813
|
name: typeof r2.name === "string" ? r2.name : id,
|
|
139678
|
-
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),
|
|
139679
139817
|
subtask: r2.subtask,
|
|
139680
139818
|
...Array.isArray(r2.ownedPaths) ? { ownedPaths: r2.ownedPaths.filter((p3) => typeof p3 === "string") } : {},
|
|
139681
139819
|
...typeof r2.model === "string" ? { model: r2.model } : {}
|
|
@@ -139691,6 +139829,14 @@ function readRoster(path62, maxAgents) {
|
|
|
139691
139829
|
function slug(s2) {
|
|
139692
139830
|
return s2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32);
|
|
139693
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
|
+
}
|
|
139694
139840
|
function statusOf(hub, id) {
|
|
139695
139841
|
return hub.state.rosterView().agents.find((a2) => a2.id === id)?.status;
|
|
139696
139842
|
}
|
|
@@ -139813,7 +139959,11 @@ function emitAbort(ctx, reason) {
|
|
|
139813
139959
|
}
|
|
139814
139960
|
|
|
139815
139961
|
// ../mode-collaborative/dist/prompts.js
|
|
139816
|
-
var COLLAB_COMMON = `You are one agent on a TEAM of separate agents collaborating on one task in a shared
|
|
139962
|
+
var COLLAB_COMMON = `You are one agent on a TEAM of separate agents collaborating on one task in a shared workspace. You are a peer, not in charge \u2014 you cooperate.
|
|
139963
|
+
|
|
139964
|
+
Know the WHOLE picture before you act:
|
|
139965
|
+
- ${COLLAB_SCAFFOLD_DIR}/${BRIEF_FILENAME} is the shared brief \u2014 the user's overall goal and the conversation/intent behind it. Read it FIRST so your work serves the real goal, not just the literal words of your sub-task.
|
|
139966
|
+
- Before planning, recall() any relevant prior knowledge about this workspace/task. When you discover a durable fact (a decision, a gotcha, an interface, a convention), memory_save it so the team \u2014 and future work \u2014 keeps it.
|
|
139817
139967
|
|
|
139818
139968
|
The team coordinates through a shared hub (use these tools):
|
|
139819
139969
|
- collab_roster \u2014 who is on the team, their roles, sub-tasks, and status.
|
|
@@ -139827,21 +139977,22 @@ The team coordinates through a shared hub (use these tools):
|
|
|
139827
139977
|
|
|
139828
139978
|
Cooperation rules:
|
|
139829
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.
|
|
139830
|
-
- 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.
|
|
139831
139981
|
- Keep teammates informed: broadcast meaningful progress and blockers.
|
|
139832
139982
|
- When YOUR sub-task is fully complete and verified, call collab_done with a short summary. The run finishes when everyone is done.`;
|
|
139833
139983
|
var COLLAB_PEER_PROMPT = `${COLLAB_COMMON}
|
|
139834
139984
|
|
|
139835
|
-
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.`;
|
|
139836
139986
|
var COLLAB_ARCHITECT_PROMPT = `${COLLAB_COMMON}
|
|
139837
139987
|
|
|
139838
139988
|
You are the ARCHITECT \u2014 you run FIRST and set the team up for success. Your job, in order:
|
|
139839
|
-
|
|
139840
|
-
|
|
139841
|
-
|
|
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.
|
|
139990
|
+
1. Explore the workspace to understand the task and its boundaries.
|
|
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).
|
|
139842
139993
|
4. Write two files into the repo:
|
|
139843
|
-
- ${COLLAB_SCAFFOLD_DIR}/${CONTRACTS_FILENAME} \u2014 human-readable contracts/boundaries the
|
|
139844
|
-
- ${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).
|
|
139845
139996
|
5. Broadcast a short kickoff summary, then call collab_done.
|
|
139846
139997
|
|
|
139847
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.`;
|
|
@@ -149515,13 +149666,13 @@ async function runWorkflow(workflow, deps, opts = {}) {
|
|
|
149515
149666
|
const startedAt = (deps.now ?? Date.now)();
|
|
149516
149667
|
const result = await executor.run(workflow, deps);
|
|
149517
149668
|
if (opts.recordDir !== null) {
|
|
149518
|
-
await
|
|
149669
|
+
await writeRunRecord2(workflow, result, startedAt, executor.name, deps, opts.recordDir ?? defaultRunRecordDir()).catch((err) => deps.logger?.warn?.("workflow: failed to write run record", {
|
|
149519
149670
|
error: err instanceof Error ? err.message : String(err)
|
|
149520
149671
|
}));
|
|
149521
149672
|
}
|
|
149522
149673
|
return result;
|
|
149523
149674
|
}
|
|
149524
|
-
async function
|
|
149675
|
+
async function writeRunRecord2(workflow, result, startedAt, executorName, deps, dir) {
|
|
149525
149676
|
await promises.mkdir(dir, { recursive: true });
|
|
149526
149677
|
const stamp = new Date(startedAt).toISOString().replace(/[:.]/g, "-");
|
|
149527
149678
|
const file = path3.join(dir, `${stamp}-${workflow.name}-${ulid().slice(-6)}.jsonl`);
|
|
@@ -153902,11 +154053,11 @@ function servicePlatform() {
|
|
|
153902
154053
|
if (process.platform === "linux") return "linux";
|
|
153903
154054
|
return "unsupported";
|
|
153904
154055
|
}
|
|
153905
|
-
function
|
|
154056
|
+
function moxxyHome3() {
|
|
153906
154057
|
return process.env.MOXXY_HOME ?? path3__default.join(homedir(), ".moxxy");
|
|
153907
154058
|
}
|
|
153908
154059
|
function serviceLogPath(spec) {
|
|
153909
|
-
return path3__default.join(
|
|
154060
|
+
return path3__default.join(moxxyHome3(), "services", `${spec.id}.log`);
|
|
153910
154061
|
}
|
|
153911
154062
|
function nodeBin() {
|
|
153912
154063
|
return process.execPath;
|
|
@@ -155948,7 +156099,10 @@ async function runAgentCommand(argv) {
|
|
|
155948
156099
|
const sessionId = process.env.MOXXY_SESSION_ID?.trim();
|
|
155949
156100
|
const mode = process.env.MOXXY_MODE?.trim() || "collab-peer";
|
|
155950
156101
|
const subtask = process.env.MOXXY_COLLAB_SUBTASK ?? "";
|
|
156102
|
+
const parentTask = process.env.MOXXY_COLLAB_PARENT_TASK?.trim() ?? "";
|
|
156103
|
+
const role = process.env.MOXXY_COLLAB_ROLE?.trim() ?? "";
|
|
155951
156104
|
const model = process.env.MOXXY_MODEL?.trim();
|
|
156105
|
+
const seededTurn = buildSeedTurn({ role, parentTask, subtask });
|
|
155952
156106
|
const setup = await bootSessionWithConfig(argv, {
|
|
155953
156107
|
skipKeyPrompt: true,
|
|
155954
156108
|
tolerateNoProvider: true,
|
|
@@ -155970,7 +156124,7 @@ async function runAgentCommand(argv) {
|
|
|
155970
156124
|
const runnerServer = await startRunnerServer(session);
|
|
155971
156125
|
const turnDone = (async () => {
|
|
155972
156126
|
try {
|
|
155973
|
-
for await (const _2 of session.runTurn(
|
|
156127
|
+
for await (const _2 of session.runTurn(seededTurn)) void _2;
|
|
155974
156128
|
} catch {
|
|
155975
156129
|
}
|
|
155976
156130
|
try {
|
|
@@ -155987,6 +156141,22 @@ async function runAgentCommand(argv) {
|
|
|
155987
156141
|
await runUntilSignal2(runnerServer, session, turnDone);
|
|
155988
156142
|
return 0;
|
|
155989
156143
|
}
|
|
156144
|
+
function buildSeedTurn(args) {
|
|
156145
|
+
const { role, parentTask, subtask } = args;
|
|
156146
|
+
const pointer = "Shared team context is in `.moxxy-collab/BRIEF.md` (the user's overall goal + the conversation/intent) and `.moxxy-collab/CONTRACTS.md` (the agreed interfaces). Read them before you start so your work fits the real goal.";
|
|
156147
|
+
if (role === "architect" || !parentTask || parentTask === subtask) {
|
|
156148
|
+
return subtask ? `${subtask}
|
|
156149
|
+
|
|
156150
|
+
${pointer}` : pointer;
|
|
156151
|
+
}
|
|
156152
|
+
const roleLine = role && role !== "implementer" ? `Your role on the team: ${role}.
|
|
156153
|
+
` : "";
|
|
156154
|
+
return `${roleLine}Overall team goal: ${parentTask}
|
|
156155
|
+
|
|
156156
|
+
Your sub-task: ${subtask}
|
|
156157
|
+
|
|
156158
|
+
${pointer}`;
|
|
156159
|
+
}
|
|
155990
156160
|
async function runUntilSignal2(runnerServer, session, turnDone) {
|
|
155991
156161
|
let stopping = false;
|
|
155992
156162
|
const shutdown = async (signal) => {
|