@moxxy/cli 0.14.6 → 0.14.7
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 +194 -38
- 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, writeFileSync, rmSync, statSync, readdirSync,
|
|
5
|
+
import fs32__default, { existsSync, promises, readFileSync, ReadStream, mkdirSync, writeFileSync, rmSync, statSync, readdirSync, 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';
|
|
@@ -136060,6 +136060,7 @@ var COLLAB_SCAFFOLD_DIR = ".moxxy-collab";
|
|
|
136060
136060
|
var CONTRACTS_FILENAME = "CONTRACTS.md";
|
|
136061
136061
|
var ROSTER_FILENAME = "roster.json";
|
|
136062
136062
|
var BRIEF_FILENAME = "BRIEF.md";
|
|
136063
|
+
var CONVERSATION_FILENAME = "CONVERSATION.md";
|
|
136063
136064
|
function collabRunId(sessionId, turnId) {
|
|
136064
136065
|
const tail = (s2) => s2.replace(/[^a-zA-Z0-9]/g, "").slice(-6) || "x";
|
|
136065
136066
|
return `${tail(sessionId)}-${tail(turnId)}`;
|
|
@@ -136073,6 +136074,9 @@ function hubSocketPath(runId) {
|
|
|
136073
136074
|
function peerSocketPath(runId, agentId) {
|
|
136074
136075
|
return join(collabRunDir(runId), `p-${agentId}.sock`);
|
|
136075
136076
|
}
|
|
136077
|
+
function charterFilePath(runId, agentId) {
|
|
136078
|
+
return join(collabRunDir(runId), `charter-${agentId}.md`);
|
|
136079
|
+
}
|
|
136076
136080
|
function worktreeRoot(runId) {
|
|
136077
136081
|
return join(tmpdir(), "moxxy-collab", runId);
|
|
136078
136082
|
}
|
|
@@ -138250,7 +138254,9 @@ var COLLAB_ENV = {
|
|
|
138250
138254
|
Role: "MOXXY_COLLAB_ROLE",
|
|
138251
138255
|
Subtask: "MOXXY_COLLAB_SUBTASK",
|
|
138252
138256
|
ParentTask: "MOXXY_COLLAB_PARENT_TASK",
|
|
138253
|
-
RunnerSocket: "MOXXY_RUNNER_SOCKET"
|
|
138257
|
+
RunnerSocket: "MOXXY_RUNNER_SOCKET",
|
|
138258
|
+
/** Path (never the body) of this agent's architect-authored role charter. */
|
|
138259
|
+
CharterFile: "MOXXY_COLLAB_CHARTER_FILE"
|
|
138254
138260
|
};
|
|
138255
138261
|
var clientPromise = null;
|
|
138256
138262
|
function getProcessHubClient() {
|
|
@@ -139111,6 +139117,9 @@ function stripUndefined(obj) {
|
|
|
139111
139117
|
}
|
|
139112
139118
|
var MAX_MSG_CHARS = 600;
|
|
139113
139119
|
var MAX_TOTAL_CHARS = 6e3;
|
|
139120
|
+
var CONVERSATION_MSG_CHARS = 1200;
|
|
139121
|
+
var CONVERSATION_TOTAL_CHARS = 48e3;
|
|
139122
|
+
var SUMMARY_GUARD_CHARS = 4e3;
|
|
139114
139123
|
function clip(s2, n2) {
|
|
139115
139124
|
const t2 = s2.trim().replace(/\s+/g, " ");
|
|
139116
139125
|
return t2.length > n2 ? `${t2.slice(0, n2 - 1)}\u2026` : t2;
|
|
@@ -139127,35 +139136,126 @@ function digestTurns(events) {
|
|
|
139127
139136
|
}
|
|
139128
139137
|
return out;
|
|
139129
139138
|
}
|
|
139130
|
-
function
|
|
139131
|
-
const
|
|
139132
|
-
|
|
139133
|
-
|
|
139139
|
+
function withoutGoalTail(turns, task) {
|
|
139140
|
+
const last = turns[turns.length - 1];
|
|
139141
|
+
return turns.length > 0 && last.role === "user" && last.text.trim() === task.trim() ? turns.slice(0, -1) : turns;
|
|
139142
|
+
}
|
|
139143
|
+
function buildBrief(task, summary) {
|
|
139134
139144
|
const lines = [
|
|
139135
139145
|
"# Collaboration brief",
|
|
139136
139146
|
"",
|
|
139137
|
-
"This is the shared
|
|
139138
|
-
"
|
|
139139
|
-
"
|
|
139147
|
+
"This is the team's shared brief \u2014 the goal and the key requirements,",
|
|
139148
|
+
"constraints, and decisions distilled from the user's conversation. The full",
|
|
139149
|
+
"transcript is NOT in your context; if you need a specific detail this summary",
|
|
139150
|
+
"omits, read or grep `.moxxy-collab/CONVERSATION.md` (do not load it wholesale).",
|
|
139151
|
+
"",
|
|
139152
|
+
"## Goal",
|
|
139153
|
+
"",
|
|
139154
|
+
clip(task, 1500) || "(no goal text)",
|
|
139155
|
+
"",
|
|
139156
|
+
"## Summary",
|
|
139157
|
+
"",
|
|
139158
|
+
clip(summary, SUMMARY_GUARD_CHARS) || "(no summary available)"
|
|
139159
|
+
];
|
|
139160
|
+
return `${lines.join("\n")}
|
|
139161
|
+
`;
|
|
139162
|
+
}
|
|
139163
|
+
function heuristicSummary(task, events) {
|
|
139164
|
+
const recent = withoutGoalTail(digestTurns(events), task).slice(-12);
|
|
139165
|
+
if (recent.length === 0)
|
|
139166
|
+
return "(no prior conversation to summarize)";
|
|
139167
|
+
const lines = ["(heuristic summary \u2014 LLM summarizer unavailable; recent turns:)"];
|
|
139168
|
+
for (const t2 of recent) {
|
|
139169
|
+
lines.push(`- **${t2.role === "user" ? "User" : "Assistant"}:** ${clip(t2.text, MAX_MSG_CHARS)}`);
|
|
139170
|
+
}
|
|
139171
|
+
let body = lines.join("\n");
|
|
139172
|
+
if (body.length > MAX_TOTAL_CHARS)
|
|
139173
|
+
body = `${body.slice(0, MAX_TOTAL_CHARS - 1)}\u2026`;
|
|
139174
|
+
return body;
|
|
139175
|
+
}
|
|
139176
|
+
function buildConversation(task, events) {
|
|
139177
|
+
const turns = digestTurns(events);
|
|
139178
|
+
const lines = [
|
|
139179
|
+
"# Full conversation (recall-only)",
|
|
139180
|
+
"",
|
|
139181
|
+
"Not loaded into any agent by default. Read or grep this only when you need a",
|
|
139182
|
+
"specific detail the brief summary omits.",
|
|
139140
139183
|
"",
|
|
139141
139184
|
"## Goal",
|
|
139142
139185
|
"",
|
|
139143
|
-
clip(task, 1500) || "(no goal text)"
|
|
139186
|
+
clip(task, 1500) || "(no goal text)",
|
|
139187
|
+
"",
|
|
139188
|
+
"## Conversation",
|
|
139189
|
+
""
|
|
139144
139190
|
];
|
|
139145
|
-
if (
|
|
139146
|
-
lines.push("
|
|
139147
|
-
|
|
139148
|
-
|
|
139149
|
-
lines.push(`- **${
|
|
139191
|
+
if (turns.length === 0) {
|
|
139192
|
+
lines.push("(no prior conversation)");
|
|
139193
|
+
} else {
|
|
139194
|
+
for (const t2 of turns) {
|
|
139195
|
+
lines.push(`- **${t2.role === "user" ? "User" : "Assistant"}:** ${clip(t2.text, CONVERSATION_MSG_CHARS)}`);
|
|
139150
139196
|
}
|
|
139151
139197
|
}
|
|
139152
|
-
let
|
|
139153
|
-
if (
|
|
139154
|
-
|
|
139155
|
-
}
|
|
139156
|
-
return `${brief}
|
|
139198
|
+
let body = lines.join("\n");
|
|
139199
|
+
if (body.length > CONVERSATION_TOTAL_CHARS)
|
|
139200
|
+
body = `${body.slice(0, CONVERSATION_TOTAL_CHARS - 1)}\u2026`;
|
|
139201
|
+
return `${body}
|
|
139157
139202
|
`;
|
|
139158
139203
|
}
|
|
139204
|
+
|
|
139205
|
+
// ../mode-collaborative/dist/summarize.js
|
|
139206
|
+
var MAX_SUMMARIZE_INPUT_CHARS = 48e3;
|
|
139207
|
+
var SUMMARY_MAX_TOKENS = 700;
|
|
139208
|
+
var COLLAB_SUMMARY_SYSTEM = `You write a SHORT shared brief for a team of AI agents about to build ONE deliverable together. From the user's conversation, extract ONLY:
|
|
139209
|
+
1. The overall goal, in one or two sentences.
|
|
139210
|
+
2. The concrete requirements and constraints.
|
|
139211
|
+
3. Any decisions already made, and the reason.
|
|
139212
|
+
4. Explicit do-nots / out-of-scope.
|
|
139213
|
+
Use terse bullet points. Do NOT restate the raw conversation, do NOT invent details, omit chit-chat and pleasantries. Output ONLY the brief text \u2014 no preamble, no sign-off. Keep it well under 400 words.`;
|
|
139214
|
+
async function summarizeConversation(args) {
|
|
139215
|
+
const { task, events, provider, model, signal } = args;
|
|
139216
|
+
if (!provider || !model)
|
|
139217
|
+
return null;
|
|
139218
|
+
const turns = digestTurns(events);
|
|
139219
|
+
if (turns.length === 0)
|
|
139220
|
+
return null;
|
|
139221
|
+
const joined = turns.map((t2) => `[${t2.role}] ${t2.text}`).join("\n");
|
|
139222
|
+
const input = joined.length > MAX_SUMMARIZE_INPUT_CHARS ? `${joined.slice(0, MAX_SUMMARIZE_INPUT_CHARS / 2)}
|
|
139223
|
+
[... transcript truncated ...]
|
|
139224
|
+
${joined.slice(-MAX_SUMMARIZE_INPUT_CHARS / 2)}` : joined;
|
|
139225
|
+
try {
|
|
139226
|
+
let out = "";
|
|
139227
|
+
for await (const event of provider.stream({
|
|
139228
|
+
model,
|
|
139229
|
+
system: COLLAB_SUMMARY_SYSTEM,
|
|
139230
|
+
messages: [
|
|
139231
|
+
{
|
|
139232
|
+
role: "user",
|
|
139233
|
+
content: [
|
|
139234
|
+
{
|
|
139235
|
+
type: "text",
|
|
139236
|
+
text: `Task headline: ${task}
|
|
139237
|
+
|
|
139238
|
+
The user's conversation that produced this task:
|
|
139239
|
+
|
|
139240
|
+
${input}`
|
|
139241
|
+
}
|
|
139242
|
+
]
|
|
139243
|
+
}
|
|
139244
|
+
],
|
|
139245
|
+
maxTokens: SUMMARY_MAX_TOKENS,
|
|
139246
|
+
...signal ? { signal } : {}
|
|
139247
|
+
})) {
|
|
139248
|
+
if (event.type === "text_delta")
|
|
139249
|
+
out += event.delta;
|
|
139250
|
+
if (event.type === "error")
|
|
139251
|
+
return null;
|
|
139252
|
+
}
|
|
139253
|
+
const trimmed = out.trim();
|
|
139254
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
139255
|
+
} catch {
|
|
139256
|
+
return null;
|
|
139257
|
+
}
|
|
139258
|
+
}
|
|
139159
139259
|
function moxxyHome2() {
|
|
139160
139260
|
return process.env.MOXXY_HOME ?? join(homedir(), ".moxxy");
|
|
139161
139261
|
}
|
|
@@ -139320,6 +139420,7 @@ var PeerSupervisor = class {
|
|
|
139320
139420
|
[COLLAB_ENV.Subtask]: args.entry.subtask,
|
|
139321
139421
|
[COLLAB_ENV.ParentTask]: this.opts.parentTask,
|
|
139322
139422
|
[COLLAB_ENV.RunnerSocket]: socket,
|
|
139423
|
+
...args.charterFile ? { [COLLAB_ENV.CharterFile]: args.charterFile } : {},
|
|
139323
139424
|
MOXXY_SESSION_ID: `${this.opts.coordinatorSessionId}::${args.entry.id}`,
|
|
139324
139425
|
MOXXY_MODE: args.mode
|
|
139325
139426
|
};
|
|
@@ -139602,10 +139703,24 @@ async function* runCollaborative(ctx, deps) {
|
|
|
139602
139703
|
supervisor = (deps.createSupervisor ?? ((o2) => new PeerSupervisor(o2)))(supervisorOpts, hub);
|
|
139603
139704
|
yield await ctx.emit(plugin4(ctx, "collab_started", { task, parallel, gitInstalled: gitInstalled2, gitRepo }));
|
|
139604
139705
|
try {
|
|
139605
|
-
|
|
139706
|
+
const events = ctx.log.slice();
|
|
139606
139707
|
mkdirSync(join(cwd2, COLLAB_SCAFFOLD_DIR), { recursive: true });
|
|
139708
|
+
writeFileSync(join(cwd2, COLLAB_SCAFFOLD_DIR, CONVERSATION_FILENAME), buildConversation(task, events));
|
|
139709
|
+
const llmSummary = await summarizeConversation({
|
|
139710
|
+
task,
|
|
139711
|
+
events,
|
|
139712
|
+
provider: ctx.provider,
|
|
139713
|
+
model: ctx.model,
|
|
139714
|
+
signal: ctx.signal
|
|
139715
|
+
}).catch(() => null);
|
|
139716
|
+
const summary = llmSummary ?? heuristicSummary(task, events);
|
|
139717
|
+
briefText = buildBrief(task, summary);
|
|
139607
139718
|
writeFileSync(join(cwd2, COLLAB_SCAFFOLD_DIR, BRIEF_FILENAME), briefText);
|
|
139608
|
-
yield await ctx.emit(plugin4(ctx, "collab_brief_written", {
|
|
139719
|
+
yield await ctx.emit(plugin4(ctx, "collab_brief_written", {
|
|
139720
|
+
path: join(COLLAB_SCAFFOLD_DIR, BRIEF_FILENAME),
|
|
139721
|
+
conversationPath: join(COLLAB_SCAFFOLD_DIR, CONVERSATION_FILENAME),
|
|
139722
|
+
summarized: Boolean(llmSummary)
|
|
139723
|
+
}));
|
|
139609
139724
|
} catch {
|
|
139610
139725
|
}
|
|
139611
139726
|
supervisor.spawn({ entry: architectEntry, cwd: cwd2, mode: COLLAB_ARCHITECT_MODE_NAME });
|
|
@@ -139632,8 +139747,12 @@ ${why}` : ""}`));
|
|
|
139632
139747
|
if (cfg.requireRosterApproval && ctx.approval) {
|
|
139633
139748
|
const decision = await ctx.approval.confirm({
|
|
139634
139749
|
title: `Team of ${roster.length} agent${roster.length === 1 ? "" : "s"} \u2014 review before launch`,
|
|
139635
|
-
body: roster.map((r2, i2) =>
|
|
139636
|
-
|
|
139750
|
+
body: roster.map((r2, i2) => {
|
|
139751
|
+
const charterLine = r2.charter ? `
|
|
139752
|
+
charter: ${r2.charter.replace(/\s+/g, " ").slice(0, 140)}${r2.charter.length > 140 ? "\u2026" : ""}` : "";
|
|
139753
|
+
return `${i2 + 1}. [${r2.id}] ${r2.name} \u2014 ${r2.role}
|
|
139754
|
+
${r2.subtask}${charterLine}`;
|
|
139755
|
+
}).join("\n\n"),
|
|
139637
139756
|
kind: "collab.roster",
|
|
139638
139757
|
defaultOptionId: "launch",
|
|
139639
139758
|
options: [
|
|
@@ -139659,7 +139778,8 @@ ${why}` : ""}`));
|
|
|
139659
139778
|
const wt3 = worktreePath(runId, entry.id);
|
|
139660
139779
|
await addWorktree({ repoCwd: cwd2, path: wt3, branch: collabBranch(runId, entry.id), baseSha });
|
|
139661
139780
|
worktrees.set(entry.id, wt3);
|
|
139662
|
-
|
|
139781
|
+
const charterFile = writeCharterFile(runId, entry);
|
|
139782
|
+
supervisor.spawn({ entry, cwd: wt3, mode: COLLAB_PEER_MODE_NAME, ...charterFile ? { charterFile } : {} });
|
|
139663
139783
|
yield await ctx.emit(plugin4(ctx, "collab_agent_spawned", { id: entry.id, role: entry.role }));
|
|
139664
139784
|
}
|
|
139665
139785
|
await waitForAgents(hub, supervisor, roster.map((r2) => r2.id), ctx.signal, cfg.wallClockMs);
|
|
@@ -139672,7 +139792,8 @@ ${why}` : ""}`));
|
|
|
139672
139792
|
if (ctx.signal.aborted)
|
|
139673
139793
|
break;
|
|
139674
139794
|
hub.state.addAgent(entry);
|
|
139675
|
-
|
|
139795
|
+
const charterFile = writeCharterFile(runId, entry);
|
|
139796
|
+
supervisor.spawn({ entry, cwd: cwd2, mode: COLLAB_PEER_MODE_NAME, ...charterFile ? { charterFile } : {} });
|
|
139676
139797
|
yield await ctx.emit(plugin4(ctx, "collab_agent_spawned", { id: entry.id, role: entry.role }));
|
|
139677
139798
|
const ok = await waitForAgent(hub, supervisor, entry.id, ctx.signal, cfg.wallClockMs);
|
|
139678
139799
|
if (!ok)
|
|
@@ -139816,7 +139937,8 @@ function readRoster(path62, maxAgents) {
|
|
|
139816
139937
|
role: cleanRole(r2.role),
|
|
139817
139938
|
subtask: r2.subtask,
|
|
139818
139939
|
...Array.isArray(r2.ownedPaths) ? { ownedPaths: r2.ownedPaths.filter((p3) => typeof p3 === "string") } : {},
|
|
139819
|
-
...typeof r2.model === "string" ? { model: r2.model } : {}
|
|
139940
|
+
...typeof r2.model === "string" ? { model: r2.model } : {},
|
|
139941
|
+
...typeof r2.charter === "string" && r2.charter.trim() ? { charter: cleanCharter(r2.charter) } : {}
|
|
139820
139942
|
});
|
|
139821
139943
|
if (out.length >= maxAgents)
|
|
139822
139944
|
break;
|
|
@@ -139837,6 +139959,21 @@ function cleanRole(raw) {
|
|
|
139837
139959
|
return "implementer";
|
|
139838
139960
|
return r2;
|
|
139839
139961
|
}
|
|
139962
|
+
function cleanCharter(raw) {
|
|
139963
|
+
return raw.replace(/\u0000/g, "").trim().slice(0, 2e3);
|
|
139964
|
+
}
|
|
139965
|
+
function writeCharterFile(runId, entry) {
|
|
139966
|
+
if (!entry.charter)
|
|
139967
|
+
return void 0;
|
|
139968
|
+
const p3 = charterFilePath(runId, entry.id);
|
|
139969
|
+
try {
|
|
139970
|
+
writeFileSync(p3, `${entry.charter}
|
|
139971
|
+
`);
|
|
139972
|
+
return p3;
|
|
139973
|
+
} catch {
|
|
139974
|
+
return void 0;
|
|
139975
|
+
}
|
|
139976
|
+
}
|
|
139840
139977
|
function statusOf(hub, id) {
|
|
139841
139978
|
return hub.state.rosterView().agents.find((a2) => a2.id === id)?.status;
|
|
139842
139979
|
}
|
|
@@ -139962,7 +140099,7 @@ function emitAbort(ctx, reason) {
|
|
|
139962
140099
|
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
140100
|
|
|
139964
140101
|
Know the WHOLE picture before you act:
|
|
139965
|
-
- ${COLLAB_SCAFFOLD_DIR}/${BRIEF_FILENAME} is the shared brief \u2014 the user's
|
|
140102
|
+
- ${COLLAB_SCAFFOLD_DIR}/${BRIEF_FILENAME} is the shared brief \u2014 a concise summary of the user's goal and the key requirements/constraints/decisions. Read it FIRST so your work serves the real goal, not just the literal words of your sub-task. The full conversation is NOT in your context; if you need a specific detail the brief omits, read or grep ${COLLAB_SCAFFOLD_DIR}/${CONVERSATION_FILENAME} \u2014 do NOT load it wholesale.
|
|
139966
140103
|
- 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.
|
|
139967
140104
|
|
|
139968
140105
|
The team coordinates through a shared hub (use these tools):
|
|
@@ -139986,16 +140123,25 @@ You are a TEAM MEMBER with a specific role (given below) and sub-task. Work as t
|
|
|
139986
140123
|
var COLLAB_ARCHITECT_PROMPT = `${COLLAB_COMMON}
|
|
139987
140124
|
|
|
139988
140125
|
You are the ARCHITECT \u2014 you run FIRST and set the team up for success. Your job, in order:
|
|
139989
|
-
0. Read ${COLLAB_SCAFFOLD_DIR}/${BRIEF_FILENAME} \u2014 the
|
|
140126
|
+
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}.
|
|
139990
140127
|
1. Explore the workspace to understand the task and its boundaries.
|
|
139991
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".
|
|
139992
140129
|
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).
|
|
139993
140130
|
4. Write two files into the repo:
|
|
139994
140131
|
- ${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).
|
|
140132
|
+
- ${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"], "charter": "..." }. "role" is the agent's FUNCTION \u2014 e.g. "developer", "designer", "pm", "qa", "writer", "researcher", "editor" \u2014 choose what fits. For EACH agent write a tailored "charter": a short system-prompt-style brief (roughly 4-8 sentences, plain prose in the second person \u2014 "You are \u2026", no markdown headings) giving THIS agent, for THIS task: (a) its persona/expertise, (b) its concrete responsibilities and scope, (c) the quality bar it must hit, (d) how it works with the rest of the team, (e) its definition of done. Make each charter specific to the deliverable \u2014 this is how you create proper, task-suited roles instead of generic workers. Do NOT include yourself, and do NOT use "architect" (that's you).
|
|
139996
140133
|
5. Broadcast a short kickoff summary, then call collab_done.
|
|
139997
140134
|
|
|
139998
140135
|
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.`;
|
|
140136
|
+
function peerPromptWithCharter(charter) {
|
|
140137
|
+
if (!charter || !charter.trim())
|
|
140138
|
+
return COLLAB_PEER_PROMPT;
|
|
140139
|
+
return `${COLLAB_PEER_PROMPT}
|
|
140140
|
+
|
|
140141
|
+
## Your charter
|
|
140142
|
+
|
|
140143
|
+
${charter.trim()}`;
|
|
140144
|
+
}
|
|
139999
140145
|
var COLLAB_DONE_TOOL = "collab_done";
|
|
140000
140146
|
var DEFAULT_MAX_ITERATIONS = 60;
|
|
140001
140147
|
var MAX_NOOP_ITERATIONS = 3;
|
|
@@ -140261,11 +140407,21 @@ var collabArchitectMode = defineMode({
|
|
|
140261
140407
|
badge: { label: "ARCHITECT", tone: "attention" },
|
|
140262
140408
|
run: (ctx) => runCollabAgentLoop(ctx, { systemPrompt: COLLAB_ARCHITECT_PROMPT })
|
|
140263
140409
|
});
|
|
140410
|
+
function peerSystemPrompt(env3) {
|
|
140411
|
+
const path62 = env3[COLLAB_ENV.CharterFile]?.trim();
|
|
140412
|
+
if (!path62)
|
|
140413
|
+
return COLLAB_PEER_PROMPT;
|
|
140414
|
+
try {
|
|
140415
|
+
return peerPromptWithCharter(readFileSync(path62, "utf8"));
|
|
140416
|
+
} catch {
|
|
140417
|
+
return COLLAB_PEER_PROMPT;
|
|
140418
|
+
}
|
|
140419
|
+
}
|
|
140264
140420
|
var collabPeerMode = defineMode({
|
|
140265
140421
|
name: COLLAB_PEER_MODE_NAME,
|
|
140266
|
-
description: "Collaboration peer (internal):
|
|
140422
|
+
description: "Collaboration peer (internal): a team member building to the shared contracts.",
|
|
140267
140423
|
badge: { label: "TEAM", tone: "attention" },
|
|
140268
|
-
run: (ctx) => runCollabAgentLoop(ctx, { systemPrompt:
|
|
140424
|
+
run: (ctx) => runCollabAgentLoop(ctx, { systemPrompt: peerSystemPrompt(ctx.env) })
|
|
140269
140425
|
});
|
|
140270
140426
|
|
|
140271
140427
|
// ../mode-collaborative/dist/index.js
|
|
@@ -140280,8 +140436,8 @@ var collaborativeModePlugin = definePlugin({
|
|
|
140280
140436
|
version: "0.0.0",
|
|
140281
140437
|
modes: [collaborativeMode, collabArchitectMode, collabPeerMode]
|
|
140282
140438
|
});
|
|
140283
|
-
var
|
|
140284
|
-
var
|
|
140439
|
+
var MAX_SUMMARIZE_INPUT_CHARS2 = 48e3;
|
|
140440
|
+
var SUMMARY_MAX_TOKENS2 = 1024;
|
|
140285
140441
|
var FALLBACK_DIGEST_CHARS = 6e3;
|
|
140286
140442
|
var SUMMARY_SYSTEM_PROMPT = "You compress conversation history for an AI agent so it can keep working with less context. You are given a line-per-event digest of earlier turns. Write a dense, factual brief the agent can rely on: the task and its current state, key decisions and their reasons, important file paths / identifiers / values, tool outcomes (including failures), and any unresolved questions or TODOs. Do not editorialize, do not invent details, output ONLY the summary text.";
|
|
140287
140443
|
function createSummarizeCompactor(opts = {}) {
|
|
@@ -140348,9 +140504,9 @@ async function providerSummary(text, ctx) {
|
|
|
140348
140504
|
const model = ctx.model ?? provider.models[0]?.id;
|
|
140349
140505
|
if (!model)
|
|
140350
140506
|
return null;
|
|
140351
|
-
const input = text.length >
|
|
140507
|
+
const input = text.length > MAX_SUMMARIZE_INPUT_CHARS2 ? `${text.slice(0, MAX_SUMMARIZE_INPUT_CHARS2 / 2)}
|
|
140352
140508
|
[... digest truncated ...]
|
|
140353
|
-
${text.slice(-
|
|
140509
|
+
${text.slice(-MAX_SUMMARIZE_INPUT_CHARS2 / 2)}` : text;
|
|
140354
140510
|
try {
|
|
140355
140511
|
let out = "";
|
|
140356
140512
|
for await (const event of provider.stream({
|
|
@@ -140364,7 +140520,7 @@ ${text.slice(-MAX_SUMMARIZE_INPUT_CHARS / 2)}` : text;
|
|
|
140364
140520
|
${input}` }]
|
|
140365
140521
|
}
|
|
140366
140522
|
],
|
|
140367
|
-
maxTokens:
|
|
140523
|
+
maxTokens: SUMMARY_MAX_TOKENS2,
|
|
140368
140524
|
...ctx.signal ? { signal: ctx.signal } : {}
|
|
140369
140525
|
})) {
|
|
140370
140526
|
if (event.type === "text_delta")
|
|
@@ -156143,7 +156299,7 @@ async function runAgentCommand(argv) {
|
|
|
156143
156299
|
}
|
|
156144
156300
|
function buildSeedTurn(args) {
|
|
156145
156301
|
const { role, parentTask, subtask } = args;
|
|
156146
|
-
const pointer = "Shared team context is in `.moxxy-collab/BRIEF.md` (the user's
|
|
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.";
|
|
156147
156303
|
if (role === "architect" || !parentTask || parentTask === subtask) {
|
|
156148
156304
|
return subtask ? `${subtask}
|
|
156149
156305
|
|