@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 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, readFileSync, unlinkSync, chmodSync, watch, createReadStream } from 'fs';
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 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);
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 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.",
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 (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)}`);
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 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}
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
- briefText = buildBrief(task, ctx.log.slice());
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", { path: join(COLLAB_SCAFFOLD_DIR, BRIEF_FILENAME) }));
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) => `${i2 + 1}. [${r2.id}] ${r2.name} \u2014 ${r2.role}
139636
- ${r2.subtask}`).join("\n\n"),
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
- supervisor.spawn({ entry, cwd: wt3, mode: COLLAB_PEER_MODE_NAME });
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
- supervisor.spawn({ entry, cwd: cwd2, mode: COLLAB_PEER_MODE_NAME });
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 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.
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 user's goal and the conversation behind it \u2014 so you decompose toward what they actually want.
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): an implementer building to the shared contracts.",
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: COLLAB_PEER_PROMPT })
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 MAX_SUMMARIZE_INPUT_CHARS = 48e3;
140284
- var SUMMARY_MAX_TOKENS = 1024;
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 > MAX_SUMMARIZE_INPUT_CHARS ? `${text.slice(0, MAX_SUMMARIZE_INPUT_CHARS / 2)}
140507
+ const input = text.length > MAX_SUMMARIZE_INPUT_CHARS2 ? `${text.slice(0, MAX_SUMMARIZE_INPUT_CHARS2 / 2)}
140352
140508
  [... digest truncated ...]
140353
- ${text.slice(-MAX_SUMMARIZE_INPUT_CHARS / 2)}` : text;
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: SUMMARY_MAX_TOKENS,
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 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.";
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