@markus-global/cli 0.2.3 → 0.3.0

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.
Files changed (34) hide show
  1. package/dist/commands/start.js +16 -6
  2. package/dist/commands/start.js.map +1 -1
  3. package/dist/markus.mjs +926 -818
  4. package/dist/web-ui/assets/index-CvTg0RPT.css +1 -0
  5. package/dist/web-ui/assets/index-DJ4hiBa1.js +61 -0
  6. package/dist/web-ui/index.html +2 -2
  7. package/package.json +1 -1
  8. package/templates/roles/agent-father/ROLE.md +15 -1
  9. package/templates/roles/developer/ROLE.md +61 -16
  10. package/templates/roles/devops/ROLE.md +26 -4
  11. package/templates/roles/project-manager/ROLE.md +59 -0
  12. package/templates/roles/qa-engineer/ROLE.md +36 -8
  13. package/templates/roles/research-assistant/ROLE.md +29 -2
  14. package/templates/roles/reviewer/ROLE.md +14 -7
  15. package/templates/roles/team-factory/ROLE.md +18 -1
  16. package/templates/skills/agent-building/SKILL.md +4 -2
  17. package/templates/skills/team-building/SKILL.md +25 -5
  18. package/templates/teams/content-team/ANNOUNCEMENT.md +20 -6
  19. package/templates/teams/content-team/NORMS.md +42 -14
  20. package/templates/teams/content-team/team.json +31 -6
  21. package/templates/teams/dev-squad/ANNOUNCEMENT.md +17 -6
  22. package/templates/teams/dev-squad/NORMS.md +60 -20
  23. package/templates/teams/dev-squad/team.json +38 -7
  24. package/templates/teams/engineering-pod/ANNOUNCEMENT.md +26 -0
  25. package/templates/teams/engineering-pod/NORMS.md +78 -0
  26. package/templates/teams/engineering-pod/team.json +50 -0
  27. package/templates/teams/research-lab/ANNOUNCEMENT.md +25 -0
  28. package/templates/teams/research-lab/NORMS.md +88 -0
  29. package/templates/teams/research-lab/team.json +43 -0
  30. package/templates/teams/startup-team/ANNOUNCEMENT.md +20 -7
  31. package/templates/teams/startup-team/NORMS.md +57 -19
  32. package/templates/teams/startup-team/team.json +24 -8
  33. package/dist/web-ui/assets/index-Bcc58A3R.css +0 -1
  34. package/dist/web-ui/assets/index-DuLIQUDd.js +0 -61
package/dist/markus.mjs CHANGED
@@ -6248,7 +6248,7 @@ var init_context_engine = __esm({
6248
6248
  }
6249
6249
  }
6250
6250
  parts.push("\n## Working Strategy");
6251
- parts.push("For multi-step tasks: (1) Plan first \u2014 outline approach, use `todo.md` for long tasks. (2) Update progress after each step. (3) Restate objectives before each action. (4) On errors, analyze before retrying \u2014 try a different approach. (5) Offload large tool output to files.");
6251
+ parts.push("For multi-step tasks: (1) Plan first \u2014 outline approach, use `todo.md` for long tasks. (2) Update progress after each step. (3) Restate objectives before each action. (4) On errors, analyze before retrying \u2014 try a different approach. (5) Offload large tool output to files. (6) For heavy subtasks that need many tool calls or lots of file reading, delegate to `spawn_subagent` to keep your own context lean. Use `spawn_subagents` to run independent subtasks in parallel.");
6252
6252
  const scenario = opts.scenario ?? "chat";
6253
6253
  parts.push(this.buildScenarioSection(scenario));
6254
6254
  const now2 = /* @__PURE__ */ new Date();
@@ -6313,6 +6313,28 @@ Current date and time: ${localStr} (${tz}, UTC${sign}${absH}:${absM})`);
6313
6313
  lines.push("4. **Handle blockers**: If you cannot proceed, set status to `blocked` with a clear explanation.");
6314
6314
  lines.push("5. **Submit for review**: When ALL subtasks are complete, call `task_submit_review` with summary + deliverables (MANDATORY \u2014 the task does NOT complete without this).");
6315
6315
  lines.push("");
6316
+ lines.push("**Delegating subtasks to subagents (`spawn_subagent` / `spawn_subagents`):**");
6317
+ lines.push("");
6318
+ lines.push("Subagents are lightweight child loops with independent context windows. They inherit your tools but do NOT pollute your conversation history. Use them strategically:");
6319
+ lines.push("");
6320
+ lines.push("*DELEGATE to a subagent when the subtask is:*");
6321
+ lines.push("- **Deep exploration / analysis**: reading and cross-referencing many files (>5), codebase-wide searches, architecture analysis \u2014 a subagent keeps your own context clean");
6322
+ lines.push("- **Independent code modifications**: editing files in separate modules that don't depend on each other \u2014 perfect for `spawn_subagents` (parallel)");
6323
+ lines.push("- **Research & information gathering**: web searches, reading long documents, comparing alternatives \u2014 heavy context that you don't need to retain");
6324
+ lines.push("- **Test generation**: writing tests for already-implemented code \u2014 self-contained work with clear inputs/outputs");
6325
+ lines.push("- **Documentation / content generation**: producing docs, READMEs, changelogs from existing code \u2014 doesn't need your live reasoning context");
6326
+ lines.push("- **Repetitive multi-file refactoring**: renaming, format migrations, pattern replacements across many files \u2014 especially in parallel");
6327
+ lines.push("");
6328
+ lines.push("*Do NOT delegate when:*");
6329
+ lines.push("- The subtask is quick (\u22643 tool calls) \u2014 overhead of spawning a subagent is not worth it");
6330
+ lines.push("- The next subtask depends on detailed intermediate reasoning from this one \u2014 keep it in your own context");
6331
+ lines.push("- The subtask requires back-and-forth decisions that depend on your overall plan");
6332
+ lines.push("");
6333
+ lines.push("*Parallel execution pattern (`spawn_subagents`):*");
6334
+ lines.push("When you have N independent subtasks, use `spawn_subagents` with an array of tasks to run them all concurrently. Example: implementing separate API endpoints, writing tests for different modules, analyzing different components.");
6335
+ lines.push("");
6336
+ lines.push("*Workflow:* `subtask_create` (track) \u2192 `spawn_subagent`/`spawn_subagents` (execute) \u2192 verify result \u2192 `subtask_complete` (mark done).");
6337
+ lines.push("");
6316
6338
  lines.push("**Quality standards:**");
6317
6339
  lines.push("- Use all available tools to produce thorough, high-quality output");
6318
6340
  lines.push("- If a tool call fails, analyze the error and try a different approach \u2014 do NOT repeat the same failing action");
@@ -6356,9 +6378,18 @@ Current date and time: ${localStr} (${tz}, UTC${sign}${absH}:${absM})`);
6356
6378
  const lines = ["\n## Your Identity"];
6357
6379
  if (opts.identity) {
6358
6380
  const self = opts.identity.self;
6381
+ const teamName = opts.identity.team?.name;
6359
6382
  lines.push(`- Name: ${self.name}`);
6360
6383
  lines.push(`- Role: ${opts.role.name} (${opts.role.description})`);
6361
- lines.push(`- Position: ${self.agentRole === "manager" ? "Organization Manager \u2014 you lead the AI team" : "Team Member"}`);
6384
+ if (self.agentRole === "manager" && teamName) {
6385
+ lines.push(`- Position: Team Manager of **${teamName}**`);
6386
+ } else if (self.agentRole === "manager") {
6387
+ lines.push(`- Position: Team Manager`);
6388
+ } else if (teamName) {
6389
+ lines.push(`- Position: Member of **${teamName}**`);
6390
+ } else {
6391
+ lines.push(`- Position: Team Member`);
6392
+ }
6362
6393
  if (self.skills.length > 0) {
6363
6394
  lines.push(`- Active Skills: ${self.skills.join(", ")}`);
6364
6395
  }
@@ -6378,19 +6409,25 @@ Current date and time: ${localStr} (${tz}, UTC${sign}${absH}:${absM})`);
6378
6409
  if (opts.identity.manager && opts.identity.self.agentRole !== "manager") {
6379
6410
  lines.push(`
6380
6411
  ### Your Manager`);
6381
- lines.push(`- ${opts.identity.manager.name} (AI Organization Manager) \u2014 report progress and escalate issues to them`);
6412
+ lines.push(`- ${opts.identity.manager.name} (Team Manager) \u2014 report progress and escalate issues to them`);
6382
6413
  }
6383
6414
  if (opts.identity.colleagues.length > 0) {
6384
- lines.push(`
6385
- ### Your Colleagues`);
6415
+ lines.push(teamName ? `
6416
+ ### Your Team \u2014 ${teamName}` : "\n### Your Team");
6386
6417
  for (const c of opts.identity.colleagues) {
6387
6418
  const statusTag = c.status ? ` [${c.status}]` : "";
6388
- lines.push(`- ${c.name} (${c.role}, ${c.type})${statusTag}${c.skills?.length ? ` \u2014 skills: ${c.skills.join(", ")}` : ""}`);
6419
+ lines.push(`- ${c.name} (${c.role})${statusTag}${c.skills?.length ? ` \u2014 skills: ${c.skills.join(", ")}` : ""}`);
6420
+ }
6421
+ }
6422
+ if (opts.identity.otherTeams && opts.identity.otherTeams.length > 0) {
6423
+ lines.push("\n### Other Teams (for cross-team coordination)");
6424
+ for (const t of opts.identity.otherTeams) {
6425
+ lines.push(`- **${t.name}**: ${t.members.map((m) => `${m.name} (${m.role})`).join(", ")}`);
6389
6426
  }
6390
6427
  }
6391
6428
  if (opts.identity.humans.length > 0) {
6392
6429
  lines.push(`
6393
- ### Human Team Members`);
6430
+ ### Human Users`);
6394
6431
  for (const h of opts.identity.humans) {
6395
6432
  const tag = h.role === "owner" ? " \u2605 Owner" : h.role === "admin" ? " Admin" : "";
6396
6433
  lines.push(`- ${h.name}${tag}`);
@@ -6399,11 +6436,11 @@ Current date and time: ${localStr} (${tz}, UTC${sign}${absH}:${absM})`);
6399
6436
  if (opts.identity.self.agentRole === "manager") {
6400
6437
  lines.push(`
6401
6438
  ### Manager Responsibilities`);
6402
- lines.push("As Organization Manager, you are responsible for:");
6403
- lines.push("1. **Routing** \u2014 When receiving vague messages, determine which team member should handle it");
6404
- lines.push("2. **Coordination** \u2014 Assign tasks to the right agents based on their skills");
6405
- lines.push("3. **Reporting** \u2014 Proactively report team progress to human stakeholders");
6406
- lines.push("4. **Training** \u2014 Help new agents understand their roles and the organization context");
6439
+ lines.push(`You manage${teamName ? ` the **${teamName}** team` : " your team"}. Your scope is your own team members listed above.`);
6440
+ lines.push("1. **Routing** \u2014 Determine which team member should handle incoming requests");
6441
+ lines.push("2. **Coordination** \u2014 Assign tasks to team members based on their skills and availability");
6442
+ lines.push("3. **Reporting** \u2014 Report your team's progress to human stakeholders");
6443
+ lines.push("4. **Cross-team** \u2014 Coordinate with other team managers via `agent_send_message` when work crosses team boundaries");
6407
6444
  lines.push("5. **Escalation** \u2014 Escalate issues that require human decision to the Owner");
6408
6445
  }
6409
6446
  } else {
@@ -7366,7 +7403,9 @@ var init_tool_selector = __esm({
7366
7403
  "memory_save",
7367
7404
  "memory_search",
7368
7405
  "deliverable_search",
7369
- "deliverable_create"
7406
+ "deliverable_create",
7407
+ "spawn_subagent",
7408
+ "spawn_subagents"
7370
7409
  ]);
7371
7410
  ToolSelector = class {
7372
7411
  groups;
@@ -40979,10 +41018,53 @@ var init_patch = __esm({
40979
41018
  // ../core/dist/tools/process-manager.js
40980
41019
  import { spawn as spawn2 } from "node:child_process";
40981
41020
  import { resolve as resolve8 } from "node:path";
41021
+ function onBackgroundCompletion(cb) {
41022
+ completionListeners.push(cb);
41023
+ return () => {
41024
+ const idx = completionListeners.indexOf(cb);
41025
+ if (idx >= 0)
41026
+ completionListeners.splice(idx, 1);
41027
+ };
41028
+ }
41029
+ function drainCompletedNotifications() {
41030
+ const results = [];
41031
+ for (const s of sessions.values()) {
41032
+ if (s.exitCode !== null && !s.notified) {
41033
+ s.notified = true;
41034
+ results.push({
41035
+ sessionId: s.id,
41036
+ command: s.command.slice(0, 200),
41037
+ exitCode: s.exitCode,
41038
+ durationMs: Date.now() - s.startedAt,
41039
+ stderrTail: s.stderr.slice(-10).join("\n"),
41040
+ stdoutTail: s.stdout.slice(-10).join("\n")
41041
+ });
41042
+ }
41043
+ }
41044
+ return results;
41045
+ }
41046
+ function notifyCompletion(session) {
41047
+ if (completionListeners.length === 0)
41048
+ return;
41049
+ const notification = {
41050
+ sessionId: session.id,
41051
+ command: session.command.slice(0, 200),
41052
+ exitCode: session.exitCode ?? -1,
41053
+ durationMs: Date.now() - session.startedAt,
41054
+ stderrTail: session.stderr.slice(-10).join("\n"),
41055
+ stdoutTail: session.stdout.slice(-10).join("\n")
41056
+ };
41057
+ for (const cb of completionListeners) {
41058
+ try {
41059
+ cb(notification);
41060
+ } catch {
41061
+ }
41062
+ }
41063
+ }
40982
41064
  function createBackgroundExecTool(workspacePath) {
40983
41065
  return {
40984
41066
  name: "background_exec",
40985
- description: 'Run a shell command in the background. Returns immediately with a session ID. Use the "process" tool to poll for results, view logs, or kill the process. Ideal for long-running commands like dev servers, test suites, or builds.',
41067
+ description: 'Run a shell command in the background. Returns immediately with a session ID. Use the "process" tool to poll for results, view logs, or kill the process. Ideal for long-running commands like dev servers, test suites, or builds. You will be automatically notified when the process completes.',
40986
41068
  inputSchema: {
40987
41069
  type: "object",
40988
41070
  properties: {
@@ -41014,7 +41096,8 @@ function createBackgroundExecTool(workspacePath) {
41014
41096
  exitCode: null,
41015
41097
  stdout: [],
41016
41098
  stderr: [],
41017
- process: child
41099
+ process: child,
41100
+ notified: false
41018
41101
  };
41019
41102
  child.stdout?.on("data", (chunk) => {
41020
41103
  const lines = chunk.toString().split("\n");
@@ -41032,16 +41115,20 @@ function createBackgroundExecTool(workspacePath) {
41032
41115
  });
41033
41116
  child.on("close", (code) => {
41034
41117
  session.exitCode = code ?? -1;
41118
+ notifyCompletion(session);
41035
41119
  });
41036
41120
  child.on("exit", (code) => {
41037
- if (session.exitCode === null)
41121
+ if (session.exitCode === null) {
41038
41122
  session.exitCode = code ?? -1;
41123
+ notifyCompletion(session);
41124
+ }
41039
41125
  });
41040
41126
  if (timeoutSec > 0) {
41041
41127
  setTimeout(() => {
41042
41128
  if (session.exitCode === null) {
41043
41129
  child.kill("SIGTERM");
41044
41130
  session.exitCode = -1;
41131
+ notifyCompletion(session);
41045
41132
  }
41046
41133
  }, timeoutSec * 1e3);
41047
41134
  }
@@ -41147,12 +41234,13 @@ function createProcessTool() {
41147
41234
  }
41148
41235
  };
41149
41236
  }
41150
- var sessions, sessionCounter;
41237
+ var sessions, sessionCounter, completionListeners;
41151
41238
  var init_process_manager = __esm({
41152
41239
  "../core/dist/tools/process-manager.js"() {
41153
41240
  "use strict";
41154
41241
  sessions = /* @__PURE__ */ new Map();
41155
41242
  sessionCounter = 0;
41243
+ completionListeners = [];
41156
41244
  }
41157
41245
  });
41158
41246
 
@@ -41193,6 +41281,254 @@ var init_builtin = __esm({
41193
41281
  }
41194
41282
  });
41195
41283
 
41284
+ // ../core/dist/tools/subagent.js
41285
+ function buildToolMap(parentTools, allowedTools) {
41286
+ const toolMap = /* @__PURE__ */ new Map();
41287
+ if (allowedTools && allowedTools.length > 0) {
41288
+ for (const name of allowedTools) {
41289
+ const handler4 = parentTools.get(name);
41290
+ if (handler4 && !BLOCKED_TOOLS.has(name)) {
41291
+ toolMap.set(name, handler4);
41292
+ }
41293
+ }
41294
+ } else {
41295
+ for (const [name, handler4] of parentTools) {
41296
+ if (!BLOCKED_TOOLS.has(name)) {
41297
+ toolMap.set(name, handler4);
41298
+ }
41299
+ }
41300
+ }
41301
+ return toolMap;
41302
+ }
41303
+ async function runSubagentLoop(ctx, task, opts) {
41304
+ const hardCap = ctx.maxToolIterations ?? DEFAULT_MAX_SUBAGENT_ITERATIONS;
41305
+ const maxIter = Math.min(opts?.maxIterations ?? hardCap, hardCap);
41306
+ const parentTools = ctx.getTools();
41307
+ const provider = ctx.getProvider();
41308
+ const contextWindow = ctx.llmRouter.getModelContextWindow(provider);
41309
+ const toolMap = buildToolMap(parentTools, opts?.allowedTools);
41310
+ const llmTools = [...toolMap.values()].map((t) => ({
41311
+ name: t.name,
41312
+ description: t.description,
41313
+ inputSchema: t.inputSchema
41314
+ }));
41315
+ const systemContent = opts?.systemPrompt ?? "You are a focused subagent spawned to handle a specific subtask. Complete the task thoroughly and return a clear, concise result. Do not ask follow-up questions \u2014 work with what you have.";
41316
+ let messages2 = [
41317
+ { role: "system", content: systemContent },
41318
+ { role: "user", content: task }
41319
+ ];
41320
+ log12.info("Subagent started", {
41321
+ parentAgent: ctx.agentId,
41322
+ taskLength: task.length,
41323
+ toolCount: toolMap.size,
41324
+ maxIterations: maxIter
41325
+ });
41326
+ let response = await ctx.llmRouter.chat({
41327
+ messages: messages2,
41328
+ tools: llmTools.length > 0 ? llmTools : void 0,
41329
+ metadata: { agentId: ctx.agentId, sessionId: `subagent_${Date.now()}` }
41330
+ }, provider);
41331
+ let iterations = 0;
41332
+ while (response.finishReason === "tool_use" && response.toolCalls?.length || response.finishReason === "max_tokens") {
41333
+ if (++iterations > maxIter) {
41334
+ log12.warn("Subagent hit max iterations", { parentAgent: ctx.agentId, iterations });
41335
+ break;
41336
+ }
41337
+ if (response.finishReason === "max_tokens" && !response.toolCalls?.length) {
41338
+ messages2.push({ role: "assistant", content: response.content });
41339
+ messages2.push({
41340
+ role: "user",
41341
+ content: "[Continue from where you left off. Do not repeat what you already said.]"
41342
+ });
41343
+ } else {
41344
+ messages2.push({
41345
+ role: "assistant",
41346
+ content: response.content,
41347
+ toolCalls: response.toolCalls
41348
+ });
41349
+ for (const tc of response.toolCalls) {
41350
+ const handler4 = toolMap.get(tc.name);
41351
+ let result;
41352
+ if (!handler4) {
41353
+ result = JSON.stringify({ error: `Unknown tool: ${tc.name}` });
41354
+ } else {
41355
+ try {
41356
+ result = await handler4.execute(tc.arguments);
41357
+ result = ctx.offloadLargeResult(tc.name, result);
41358
+ } catch (err) {
41359
+ result = `Error: ${String(err)}`;
41360
+ }
41361
+ }
41362
+ messages2.push({ role: "tool", content: result, toolCallId: tc.id });
41363
+ }
41364
+ }
41365
+ messages2 = ctx.contextEngine.shrinkEphemeralMessages(messages2, contextWindow);
41366
+ response = await ctx.llmRouter.chat({
41367
+ messages: messages2,
41368
+ tools: llmTools.length > 0 ? llmTools : void 0,
41369
+ metadata: { agentId: ctx.agentId, sessionId: `subagent_${Date.now()}` }
41370
+ }, provider);
41371
+ }
41372
+ log12.info("Subagent completed", {
41373
+ parentAgent: ctx.agentId,
41374
+ iterations,
41375
+ resultLength: response.content.length
41376
+ });
41377
+ return response.content;
41378
+ }
41379
+ function createSubagentTool(ctx) {
41380
+ return {
41381
+ name: "spawn_subagent",
41382
+ description: "Spawn a lightweight subagent with a clean, independent context to handle a focused subtask. The subagent inherits your tools but gets its own message history \u2014 it will not pollute your conversation. Use this to break down complex tasks: deep code analysis, research, file refactoring, test generation, etc. The subagent runs to completion and returns its final result to you. For running multiple subagents in parallel, use spawn_subagents instead.",
41383
+ inputSchema: {
41384
+ type: "object",
41385
+ properties: {
41386
+ task: {
41387
+ type: "string",
41388
+ description: "The focused task prompt for the subagent. Be specific about what you want it to do and what result to return."
41389
+ },
41390
+ system_prompt: {
41391
+ type: "string",
41392
+ description: "Optional custom system prompt for the subagent. Defaults to a focused task-execution prompt."
41393
+ },
41394
+ allowed_tools: {
41395
+ type: "array",
41396
+ items: { type: "string" },
41397
+ description: "Optional subset of tool names the subagent can use. If omitted, it inherits all parent tools."
41398
+ },
41399
+ max_iterations: {
41400
+ type: "number",
41401
+ description: "Max tool iterations. Lower this for quick tasks."
41402
+ }
41403
+ },
41404
+ required: ["task"]
41405
+ },
41406
+ async execute(args) {
41407
+ const task = args["task"];
41408
+ if (!task) {
41409
+ return JSON.stringify({ status: "error", error: "task is required" });
41410
+ }
41411
+ try {
41412
+ const result = await runSubagentLoop(ctx, task, {
41413
+ systemPrompt: args["system_prompt"],
41414
+ allowedTools: args["allowed_tools"],
41415
+ maxIterations: args["max_iterations"]
41416
+ });
41417
+ return JSON.stringify({ status: "completed", result });
41418
+ } catch (err) {
41419
+ log12.error("Subagent execution failed", { error: String(err) });
41420
+ return JSON.stringify({ status: "error", error: `Subagent failed: ${String(err)}` });
41421
+ }
41422
+ }
41423
+ };
41424
+ }
41425
+ function createParallelSubagentTool(ctx) {
41426
+ return {
41427
+ name: "spawn_subagents",
41428
+ description: "Spawn multiple subagents in PARALLEL, each with an independent context. All subagents run concurrently and their results are collected and returned together. Use this when you have multiple independent subtasks that can be worked on simultaneously: analyzing different files, researching different topics, implementing separate modules, etc. Each subagent gets its own clean message history and inherits your tools. IMPORTANT: Only use for truly independent tasks \u2014 subagents cannot communicate with each other.",
41429
+ inputSchema: {
41430
+ type: "object",
41431
+ properties: {
41432
+ tasks: {
41433
+ type: "array",
41434
+ items: {
41435
+ type: "object",
41436
+ properties: {
41437
+ id: {
41438
+ type: "string",
41439
+ description: 'A short identifier for this subtask (used to label results). E.g. "auth-review", "api-tests".'
41440
+ },
41441
+ task: {
41442
+ type: "string",
41443
+ description: "The focused task prompt for this subagent."
41444
+ },
41445
+ allowed_tools: {
41446
+ type: "array",
41447
+ items: { type: "string" },
41448
+ description: "Optional subset of tools this subagent can use."
41449
+ },
41450
+ max_iterations: {
41451
+ type: "number",
41452
+ description: "Optional max iterations for this subagent."
41453
+ }
41454
+ },
41455
+ required: ["id", "task"]
41456
+ },
41457
+ description: "Array of subtasks to execute in parallel. Each gets an independent subagent."
41458
+ },
41459
+ system_prompt: {
41460
+ type: "string",
41461
+ description: "Optional shared system prompt for all subagents."
41462
+ }
41463
+ },
41464
+ required: ["tasks"]
41465
+ },
41466
+ async execute(args) {
41467
+ const tasks2 = args["tasks"];
41468
+ if (!tasks2 || !Array.isArray(tasks2) || tasks2.length === 0) {
41469
+ return JSON.stringify({ status: "error", error: "tasks array is required and must not be empty" });
41470
+ }
41471
+ const MAX_PARALLEL = 10;
41472
+ if (tasks2.length > MAX_PARALLEL) {
41473
+ return JSON.stringify({
41474
+ status: "error",
41475
+ error: `Too many parallel subagents (${tasks2.length}). Maximum is ${MAX_PARALLEL}.`
41476
+ });
41477
+ }
41478
+ const sharedSystemPrompt = args["system_prompt"];
41479
+ log12.info("Spawning parallel subagents", {
41480
+ parentAgent: ctx.agentId,
41481
+ count: tasks2.length,
41482
+ taskIds: tasks2.map((t) => t.id)
41483
+ });
41484
+ const startTime = Date.now();
41485
+ const results = await Promise.allSettled(tasks2.map(async (t) => {
41486
+ const result = await runSubagentLoop(ctx, t.task, {
41487
+ systemPrompt: sharedSystemPrompt,
41488
+ allowedTools: t.allowed_tools,
41489
+ maxIterations: t.max_iterations
41490
+ });
41491
+ return { id: t.id, result };
41492
+ }));
41493
+ const output = results.map((r, i) => {
41494
+ if (r.status === "fulfilled") {
41495
+ return { id: r.value.id, status: "completed", result: r.value.result };
41496
+ }
41497
+ return { id: tasks2[i].id, status: "error", error: String(r.reason) };
41498
+ });
41499
+ const completed = output.filter((o) => o.status === "completed").length;
41500
+ const failed = output.filter((o) => o.status === "error").length;
41501
+ log12.info("Parallel subagents finished", {
41502
+ parentAgent: ctx.agentId,
41503
+ completed,
41504
+ failed,
41505
+ totalDurationMs: Date.now() - startTime
41506
+ });
41507
+ return JSON.stringify({
41508
+ status: "completed",
41509
+ summary: `${completed}/${tasks2.length} subagents completed successfully${failed > 0 ? `, ${failed} failed` : ""}`,
41510
+ durationMs: Date.now() - startTime,
41511
+ results: output
41512
+ });
41513
+ }
41514
+ };
41515
+ }
41516
+ var log12, DEFAULT_MAX_SUBAGENT_ITERATIONS, BLOCKED_TOOLS;
41517
+ var init_subagent = __esm({
41518
+ "../core/dist/tools/subagent.js"() {
41519
+ "use strict";
41520
+ init_dist();
41521
+ log12 = createLogger("subagent");
41522
+ DEFAULT_MAX_SUBAGENT_ITERATIONS = 200;
41523
+ BLOCKED_TOOLS = /* @__PURE__ */ new Set([
41524
+ "spawn_subagent",
41525
+ "spawn_subagents",
41526
+ "send_user_message",
41527
+ "discover_tools"
41528
+ ]);
41529
+ }
41530
+ });
41531
+
41196
41532
  // ../core/dist/concurrent/task-queue.js
41197
41533
  var TaskPriority, TaskStatus, TaskType, TaskQueue;
41198
41534
  var init_task_queue = __esm({
@@ -41907,12 +42243,12 @@ function hashString(str) {
41907
42243
  function noDetection() {
41908
42244
  return { detected: false, severity: "none", pattern: "", message: "" };
41909
42245
  }
41910
- var log12, DEFAULT_CONFIG3, ToolLoopDetector;
42246
+ var log13, DEFAULT_CONFIG3, ToolLoopDetector;
41911
42247
  var init_tool_loop_detector = __esm({
41912
42248
  "../core/dist/tool-loop-detector.js"() {
41913
42249
  "use strict";
41914
42250
  init_dist();
41915
- log12 = createLogger("tool-loop-detector");
42251
+ log13 = createLogger("tool-loop-detector");
41916
42252
  DEFAULT_CONFIG3 = {
41917
42253
  enabled: true,
41918
42254
  historySize: 30,
@@ -41982,12 +42318,12 @@ var init_tool_loop_detector = __esm({
41982
42318
  }
41983
42319
  if (streak >= this.config.criticalThreshold) {
41984
42320
  const msg = `Critical: "${last.name}" called ${streak} times with identical arguments`;
41985
- log12.warn(msg);
42321
+ log13.warn(msg);
41986
42322
  return { detected: true, severity: "critical", pattern: "genericRepeat", message: msg };
41987
42323
  }
41988
42324
  if (streak >= this.config.warningThreshold) {
41989
42325
  const msg = `Warning: "${last.name}" called ${streak} times with identical arguments`;
41990
- log12.warn(msg);
42326
+ log13.warn(msg);
41991
42327
  return { detected: true, severity: "warning", pattern: "genericRepeat", message: msg };
41992
42328
  }
41993
42329
  return noDetection();
@@ -42015,12 +42351,12 @@ var init_tool_loop_detector = __esm({
42015
42351
  }
42016
42352
  if (cycles >= Math.ceil(this.config.criticalThreshold / 2)) {
42017
42353
  const msg = `Critical: ping-pong pattern detected \u2014 "${recent[recent.length - 2].name}" \u2194 "${recent[recent.length - 1].name}" for ${cycles} cycles`;
42018
- log12.warn(msg);
42354
+ log13.warn(msg);
42019
42355
  return { detected: true, severity: "critical", pattern: "pingPong", message: msg };
42020
42356
  }
42021
42357
  if (cycles >= Math.ceil(this.config.warningThreshold / 2)) {
42022
42358
  const msg = `Warning: ping-pong pattern \u2014 "${recent[recent.length - 2].name}" \u2194 "${recent[recent.length - 1].name}" for ${cycles} cycles`;
42023
- log12.warn(msg);
42359
+ log13.warn(msg);
42024
42360
  return { detected: true, severity: "warning", pattern: "pingPong", message: msg };
42025
42361
  }
42026
42362
  return noDetection();
@@ -42044,12 +42380,12 @@ var init_tool_loop_detector = __esm({
42044
42380
  }
42045
42381
  if (sameResultStreak >= this.config.criticalThreshold) {
42046
42382
  const msg = `Critical: "${recent[recent.length - 1].name}" returned identical results ${sameResultStreak} times \u2014 no progress`;
42047
- log12.warn(msg);
42383
+ log13.warn(msg);
42048
42384
  return { detected: true, severity: "critical", pattern: "noProgress", message: msg };
42049
42385
  }
42050
42386
  if (sameResultStreak >= this.config.warningThreshold) {
42051
42387
  const msg = `Warning: "${recent[recent.length - 1].name}" returned identical results ${sameResultStreak} times`;
42052
- log12.warn(msg);
42388
+ log13.warn(msg);
42053
42389
  return { detected: true, severity: "warning", pattern: "noProgress", message: msg };
42054
42390
  }
42055
42391
  return noDetection();
@@ -42076,7 +42412,7 @@ function isErrorResult(result) {
42076
42412
  return false;
42077
42413
  }
42078
42414
  }
42079
- var taskAsyncContext, log13, Agent;
42415
+ var taskAsyncContext, log14, Agent;
42080
42416
  var init_agent2 = __esm({
42081
42417
  "../core/dist/agent.js"() {
42082
42418
  "use strict";
@@ -42093,11 +42429,13 @@ var init_agent2 = __esm({
42093
42429
  init_environment_profile();
42094
42430
  init_tool_selector();
42095
42431
  init_builtin();
42432
+ init_subagent();
42433
+ init_process_manager();
42096
42434
  init_concurrent();
42097
42435
  init_task_queue();
42098
42436
  init_tool_loop_detector();
42099
42437
  taskAsyncContext = new AsyncLocalStorage();
42100
- log13 = createLogger("agent");
42438
+ log14 = createLogger("agent");
42101
42439
  Agent = class _Agent {
42102
42440
  id;
42103
42441
  config;
@@ -42172,6 +42510,9 @@ var init_agent2 = __esm({
42172
42510
  static NETWORK_RETRY_BASE_MS = 2e3;
42173
42511
  static MEMORY_CONSOLIDATION_INTERVAL_MS = 4 * 60 * 60 * 1e3;
42174
42512
  // 4 hours
42513
+ static DEFAULT_MAX_TOOL_ITERATIONS = 200;
42514
+ _maxToolIterations;
42515
+ _bgCompletionUnsub;
42175
42516
  constructor(options) {
42176
42517
  this.id = options.config.id || agentId();
42177
42518
  this.config = { ...options.config, id: this.id };
@@ -42189,6 +42530,7 @@ var init_agent2 = __esm({
42189
42530
  this.dataDir = options.dataDir;
42190
42531
  this.pathPolicy = options.pathPolicy;
42191
42532
  this.skillRegistry = options.skillRegistry;
42533
+ this._maxToolIterations = options.maxToolIterations ?? _Agent.DEFAULT_MAX_TOOL_ITERATIONS;
42192
42534
  this.eventBus = new EventBus();
42193
42535
  this.memory = options.memory ?? new MemoryStore(options.dataDir);
42194
42536
  this.contextEngine = new ContextEngine();
@@ -42207,6 +42549,37 @@ var init_agent2 = __esm({
42207
42549
  this.tools.set(tool.name, tool);
42208
42550
  }
42209
42551
  }
42552
+ const subagentCtx = {
42553
+ llmRouter: this.llmRouter,
42554
+ contextEngine: this.contextEngine,
42555
+ getTools: () => taskAsyncContext.getStore()?.tools ?? this.tools,
42556
+ getProvider: () => this.getEffectiveProvider(),
42557
+ agentId: this.id,
42558
+ offloadLargeResult: (toolName, result) => this.offloadLargeResult(toolName, result),
42559
+ maxToolIterations: this._maxToolIterations
42560
+ };
42561
+ this.tools.set("spawn_subagent", createSubagentTool(subagentCtx));
42562
+ this.tools.set("spawn_subagents", createParallelSubagentTool(subagentCtx));
42563
+ this._bgCompletionUnsub = onBackgroundCompletion((notification) => {
42564
+ const sessionId = this.currentSessionId;
42565
+ if (!sessionId)
42566
+ return;
42567
+ const status = notification.exitCode === 0 ? "succeeded" : `failed (exit ${notification.exitCode})`;
42568
+ const parts = [
42569
+ `[BACKGROUND PROCESS COMPLETED] Session ${notification.sessionId} ${status}.`,
42570
+ `Command: ${notification.command}`,
42571
+ `Duration: ${Math.round(notification.durationMs / 1e3)}s`
42572
+ ];
42573
+ if (notification.exitCode !== 0 && notification.stderrTail) {
42574
+ parts.push(`Stderr (last lines):
42575
+ ${notification.stderrTail}`);
42576
+ }
42577
+ if (notification.exitCode === 0 && notification.stdoutTail) {
42578
+ parts.push(`Output (last lines):
42579
+ ${notification.stdoutTail}`);
42580
+ }
42581
+ this.injectUserMessage(sessionId, parts.join("\n"));
42582
+ });
42210
42583
  this.taskExecutor = new TaskExecutor({
42211
42584
  agentId: this.id,
42212
42585
  maxConcurrentTasks: _Agent.MAX_CONCURRENT_TASKS,
@@ -42214,7 +42587,7 @@ var init_agent2 = __esm({
42214
42587
  });
42215
42588
  this.stateManager = new AgentStateManager(this.id, this.taskExecutor);
42216
42589
  this.eventBus.on("heartbeat:trigger", (ctx) => {
42217
- this.handleHeartbeat(ctx).catch((e) => log13.error("Heartbeat handler failed", { error: String(e) }));
42590
+ this.handleHeartbeat(ctx).catch((e) => log14.error("Heartbeat handler failed", { error: String(e) }));
42218
42591
  });
42219
42592
  const roleFilePath = join6(this.dataDir, "role", "ROLE.md");
42220
42593
  this.toolHooks.register({
@@ -42223,13 +42596,13 @@ var init_agent2 = __esm({
42223
42596
  if ((ctx.toolName === "file_edit" || ctx.toolName === "file_write") && ctx.success) {
42224
42597
  const targetPath = ctx.arguments["path"] ?? ctx.arguments["filePath"] ?? "";
42225
42598
  if (targetPath === roleFilePath || targetPath.endsWith("/role/ROLE.md")) {
42226
- log13.info("Agent modified its own ROLE.md \u2014 reloading role definition");
42599
+ log14.info("Agent modified its own ROLE.md \u2014 reloading role definition");
42227
42600
  this.reloadRole();
42228
42601
  }
42229
42602
  }
42230
42603
  }
42231
42604
  });
42232
- log13.info(`Agent created: ${this.id}`, { name: this.config.name, role: this.role.name });
42605
+ log14.info(`Agent created: ${this.id}`, { name: this.config.name, role: this.role.name });
42233
42606
  }
42234
42607
  /**
42235
42608
  * Resolve the LLM provider name for this agent.
@@ -42273,22 +42646,23 @@ var init_agent2 = __esm({
42273
42646
  try {
42274
42647
  this.environmentProfile = await detectEnvironment();
42275
42648
  } catch (e) {
42276
- log13.warn("Environment detection failed", { error: String(e) });
42649
+ log14.warn("Environment detection failed", { error: String(e) });
42277
42650
  }
42278
42651
  const latestSession = this.memory.getLatestSession(this.id);
42279
42652
  if (latestSession && latestSession.messages.length > 0) {
42280
42653
  this.currentSessionId = latestSession.id;
42281
- log13.info(`Resumed session ${latestSession.id} with ${latestSession.messages.length} messages`);
42654
+ log14.info(`Resumed session ${latestSession.id} with ${latestSession.messages.length} messages`);
42282
42655
  }
42283
42656
  this.heartbeat.start();
42284
42657
  this.memoryConsolidationTimer = setInterval(() => {
42285
- this.consolidateMemory().catch((e) => log13.warn("Memory consolidation failed", { error: String(e) }));
42658
+ this.consolidateMemory().catch((e) => log14.warn("Memory consolidation failed", { error: String(e) }));
42286
42659
  }, _Agent.MEMORY_CONSOLIDATION_INTERVAL_MS);
42287
42660
  this.eventBus.emit("agent:started", { agentId: this.id });
42288
- log13.info(`Agent started: ${this.config.name}`);
42661
+ log14.info(`Agent started: ${this.config.name}`);
42289
42662
  }
42290
42663
  async stop() {
42291
42664
  this.heartbeat.stop();
42665
+ this._bgCompletionUnsub?.();
42292
42666
  if (this.memoryConsolidationTimer) {
42293
42667
  clearInterval(this.memoryConsolidationTimer);
42294
42668
  this.memoryConsolidationTimer = void 0;
@@ -42296,7 +42670,7 @@ var init_agent2 = __esm({
42296
42670
  this.metricsCollector.flush();
42297
42671
  this.setStatus("offline");
42298
42672
  this.eventBus.emit("agent:stopped", { agentId: this.id });
42299
- log13.info(`Agent stopped: ${this.config.name}`);
42673
+ log14.info(`Agent stopped: ${this.config.name}`);
42300
42674
  }
42301
42675
  /**
42302
42676
  * Reload the agent's role from its ROLE.md file on disk.
@@ -42314,9 +42688,9 @@ var init_agent2 = __esm({
42314
42688
  name,
42315
42689
  systemPrompt: content
42316
42690
  };
42317
- log13.info(`Role reloaded from disk for agent ${this.config.name}`);
42691
+ log14.info(`Role reloaded from disk for agent ${this.config.name}`);
42318
42692
  } catch (err) {
42319
- log13.warn(`Failed to reload role for agent ${this.config.name}`, { error: String(err) });
42693
+ log14.warn(`Failed to reload role for agent ${this.config.name}`, { error: String(err) });
42320
42694
  }
42321
42695
  }
42322
42696
  /**
@@ -42326,7 +42700,7 @@ var init_agent2 = __esm({
42326
42700
  startNewSession() {
42327
42701
  const session = this.memory.createSession(this.id);
42328
42702
  this.currentSessionId = session.id;
42329
- log13.info(`New session started for agent ${this.config.name}: ${session.id}`);
42703
+ log14.info(`New session started for agent ${this.config.name}: ${session.id}`);
42330
42704
  }
42331
42705
  /**
42332
42706
  * Bind the current in-memory session to a DB session ID (ses_*).
@@ -42336,7 +42710,7 @@ var init_agent2 = __esm({
42336
42710
  bindDbSession(dbSessionId) {
42337
42711
  if (this.currentSessionId) {
42338
42712
  this.dbSessionMap.set(dbSessionId, this.currentSessionId);
42339
- log13.debug(`Bound DB session ${dbSessionId} \u2192 memory session ${this.currentSessionId}`);
42713
+ log14.debug(`Bound DB session ${dbSessionId} \u2192 memory session ${this.currentSessionId}`);
42340
42714
  }
42341
42715
  }
42342
42716
  /**
@@ -42350,7 +42724,7 @@ var init_agent2 = __esm({
42350
42724
  const session2 = this.memory.getSession(existingMemorySessionId);
42351
42725
  if (session2) {
42352
42726
  this.currentSessionId = existingMemorySessionId;
42353
- log13.debug(`Switched to existing memory session ${existingMemorySessionId} for DB session ${dbSessionId}`);
42727
+ log14.debug(`Switched to existing memory session ${existingMemorySessionId} for DB session ${dbSessionId}`);
42354
42728
  return;
42355
42729
  }
42356
42730
  this.dbSessionMap.delete(dbSessionId);
@@ -42366,7 +42740,7 @@ var init_agent2 = __esm({
42366
42740
  }
42367
42741
  }
42368
42742
  this.currentSessionId = session.id;
42369
- log13.info(`Restored session context for DB session ${dbSessionId} \u2192 memory session ${session.id} (${dbMessages.length} messages)`);
42743
+ log14.info(`Restored session context for DB session ${dbSessionId} \u2192 memory session ${session.id} (${dbMessages.length} messages)`);
42370
42744
  }
42371
42745
  pause(reason) {
42372
42746
  if (this.state.status === "offline")
@@ -42374,7 +42748,7 @@ var init_agent2 = __esm({
42374
42748
  this.pauseReason = reason;
42375
42749
  this.setStatus("paused");
42376
42750
  this.eventBus.emit("agent:paused", { agentId: this.id, reason });
42377
- log13.info(`Agent paused: ${this.config.name}`, { reason });
42751
+ log14.info(`Agent paused: ${this.config.name}`, { reason });
42378
42752
  }
42379
42753
  resume() {
42380
42754
  if (this.state.status !== "paused")
@@ -42382,7 +42756,7 @@ var init_agent2 = __esm({
42382
42756
  this.pauseReason = void 0;
42383
42757
  this.setStatus(this.activeTasks.size > 0 ? "working" : "idle");
42384
42758
  this.eventBus.emit("agent:resumed", { agentId: this.id });
42385
- log13.info(`Agent resumed: ${this.config.name}`);
42759
+ log14.info(`Agent resumed: ${this.config.name}`);
42386
42760
  }
42387
42761
  getPauseReason() {
42388
42762
  return this.pauseReason;
@@ -42397,7 +42771,7 @@ var init_agent2 = __esm({
42397
42771
  session = this.memory.getOrCreateSession(this.id, sessionId);
42398
42772
  }
42399
42773
  this.memory.appendMessage(sessionId, { role: "user", content });
42400
- log13.debug("Injected user message into session", { sessionId, contentLength: content.length });
42774
+ log14.debug("Injected user message into session", { sessionId, contentLength: content.length });
42401
42775
  }
42402
42776
  /**
42403
42777
  * 执行聊天任务(高优先级)
@@ -42515,7 +42889,7 @@ var init_agent2 = __esm({
42515
42889
  cancelActiveStream() {
42516
42890
  if (this.activeStreamToken) {
42517
42891
  this.activeStreamToken.cancelled = true;
42518
- log13.info("Active stream cancelled", { agentId: this.id });
42892
+ log14.info("Active stream cancelled", { agentId: this.id });
42519
42893
  }
42520
42894
  }
42521
42895
  /** Get a cancel token for the current stream */
@@ -42681,7 +43055,7 @@ ${conversationText}`
42681
43055
  const profile = this.config.profile;
42682
43056
  if (profile?.maxTokensPerDay !== void 0 && profile.maxTokensPerDay !== null && this.state.tokensUsedToday >= profile.maxTokensPerDay) {
42683
43057
  this.setStatus("paused");
42684
- log13.warn("Agent paused: daily token budget exceeded", {
43058
+ log14.warn("Agent paused: daily token budget exceeded", {
42685
43059
  agentId: this.id,
42686
43060
  tokensUsedToday: this.state.tokensUsedToday,
42687
43061
  maxTokensPerDay: profile.maxTokensPerDay
@@ -42716,9 +43090,15 @@ ${conversationText}`
42716
43090
  this.notifyStateChange();
42717
43091
  if (wasPausedByBudget) {
42718
43092
  this.setStatus("idle");
42719
- log13.info("Agent resumed after daily token reset", { agentId: this.id });
43093
+ log14.info("Agent resumed after daily token reset", { agentId: this.id });
42720
43094
  }
42721
43095
  }
43096
+ get maxToolIterations() {
43097
+ return this._maxToolIterations;
43098
+ }
43099
+ set maxToolIterations(value) {
43100
+ this._maxToolIterations = Math.max(1, Math.min(value, 1e4));
43101
+ }
42722
43102
  setOrgContext(ctx) {
42723
43103
  this.orgContext = ctx;
42724
43104
  }
@@ -42980,7 +43360,7 @@ No recent activity recorded.`,
42980
43360
  ${report}`);
42981
43361
  return report;
42982
43362
  } catch (error) {
42983
- log13.error("Failed to generate daily report", { error: String(error) });
43363
+ log14.error("Failed to generate daily report", { error: String(error) });
42984
43364
  return `Unable to generate report: ${String(error)}`;
42985
43365
  }
42986
43366
  }
@@ -43102,7 +43482,7 @@ ${report}`);
43102
43482
  toolDefinitions: llmTools
43103
43483
  });
43104
43484
  messages2 = prepared.messages;
43105
- log13.debug("Context usage for chat", { usagePercent: prepared.usage.usagePercent, totalUsed: prepared.usage.totalUsed });
43485
+ log14.debug("Context usage for chat", { usagePercent: prepared.usage.usagePercent, totalUsed: prepared.usage.totalUsed });
43106
43486
  }
43107
43487
  const useCompaction = this.llmRouter.isCompactionSupported(this.getEffectiveProvider());
43108
43488
  try {
@@ -43124,11 +43504,10 @@ ${report}`);
43124
43504
  durationMs: Date.now() - llmStart,
43125
43505
  success: true
43126
43506
  });
43127
- const MAX_TOOL_ITERATIONS = 200;
43128
43507
  let toolIterations = 0;
43129
43508
  while (response.finishReason === "tool_use" && response.toolCalls?.length || response.finishReason === "max_tokens") {
43130
- if (++toolIterations > MAX_TOOL_ITERATIONS) {
43131
- log13.warn("Tool loop hit max iterations", {
43509
+ if (++toolIterations > this._maxToolIterations) {
43510
+ log14.warn("Tool loop hit max iterations", {
43132
43511
  agentId: this.id,
43133
43512
  iterations: toolIterations
43134
43513
  });
@@ -43239,7 +43618,7 @@ ${report}`);
43239
43618
  const loopCheck = this.loopDetector.check();
43240
43619
  if (loopCheck.detected) {
43241
43620
  if (loopCheck.severity === "critical") {
43242
- log13.warn("Loop detector: critical pattern \u2014 breaking", {
43621
+ log14.warn("Loop detector: critical pattern \u2014 breaking", {
43243
43622
  agentId: this.id,
43244
43623
  pattern: loopCheck.pattern
43245
43624
  });
@@ -43335,7 +43714,7 @@ ${report}`);
43335
43714
  success: false,
43336
43715
  detail: String(error)
43337
43716
  });
43338
- log13.error("Failed to handle message", { error: String(error) });
43717
+ log14.error("Failed to handle message", { error: String(error) });
43339
43718
  throw error;
43340
43719
  }
43341
43720
  }
@@ -43401,7 +43780,7 @@ ${report}`);
43401
43780
  toolDefinitions: llmTools
43402
43781
  });
43403
43782
  const messages2 = preparedStream.messages;
43404
- log13.debug("Context usage for stream", { usagePercent: preparedStream.usage.usagePercent });
43783
+ log14.debug("Context usage for stream", { usagePercent: preparedStream.usage.usagePercent });
43405
43784
  const useCompaction = this.llmRouter.isCompactionSupported(this.getEffectiveProvider());
43406
43785
  const abortController = new AbortController();
43407
43786
  let cancelPollTimer;
@@ -43431,14 +43810,14 @@ ${report}`);
43431
43810
  let streamToolIterations = 0;
43432
43811
  while (response.finishReason === "tool_use" && response.toolCalls?.length || response.finishReason === "max_tokens") {
43433
43812
  if (++streamToolIterations > MAX_STREAM_TOOL_ITERATIONS) {
43434
- log13.warn("Stream tool loop hit max iterations", {
43813
+ log14.warn("Stream tool loop hit max iterations", {
43435
43814
  agentId: this.id,
43436
43815
  iterations: streamToolIterations
43437
43816
  });
43438
43817
  break;
43439
43818
  }
43440
43819
  if (cancelToken?.cancelled) {
43441
- log13.info("Stream cancelled by user during tool loop", { agentId: this.id });
43820
+ log14.info("Stream cancelled by user during tool loop", { agentId: this.id });
43442
43821
  if (lastResponseContent && this.currentSessionId) {
43443
43822
  this.memory.appendMessage(this.currentSessionId, {
43444
43823
  role: "assistant",
@@ -43512,7 +43891,7 @@ ${report}`);
43512
43891
  }
43513
43892
  const loopCheck = this.loopDetector.check();
43514
43893
  if (loopCheck.detected && loopCheck.severity === "critical") {
43515
- log13.warn("Stream loop detector: critical pattern \u2014 injecting warning", {
43894
+ log14.warn("Stream loop detector: critical pattern \u2014 injecting warning", {
43516
43895
  agentId: this.id,
43517
43896
  pattern: loopCheck.pattern
43518
43897
  });
@@ -43533,7 +43912,7 @@ ${report}`);
43533
43912
  });
43534
43913
  const updatedMessages = preparedCont.messages;
43535
43914
  if (cancelToken?.cancelled) {
43536
- log13.info("Stream cancelled before LLM re-call", { agentId: this.id });
43915
+ log14.info("Stream cancelled before LLM re-call", { agentId: this.id });
43537
43916
  if (lastResponseContent && this.currentSessionId) {
43538
43917
  this.memory.appendMessage(this.currentSessionId, {
43539
43918
  role: "assistant",
@@ -43617,7 +43996,7 @@ ${report}`);
43617
43996
  success: false,
43618
43997
  detail: String(error)
43619
43998
  });
43620
- log13.error("Failed to handle stream message", { error: String(error) });
43999
+ log14.error("Failed to handle stream message", { error: String(error) });
43621
44000
  throw error;
43622
44001
  } finally {
43623
44002
  if (cancelPollTimer)
@@ -43686,6 +44065,30 @@ ${report}`);
43686
44065
  onLog({ seq: -1, type: "text_delta", content: text2, persist: false });
43687
44066
  };
43688
44067
  emit("status", "started", { agentId: this.id, agentName: this.config.name });
44068
+ let createdWorktreePath;
44069
+ if (taskWorkspace && taskWorkspace.branch) {
44070
+ const repoRoot = taskWorkspace.worktreePath;
44071
+ const isolatedPath = join6(repoRoot, ".worktrees", `task-${taskId2}`);
44072
+ try {
44073
+ const { exec: execCb3 } = await import("node:child_process");
44074
+ const { promisify: promisify4 } = await import("node:util");
44075
+ const execAsync3 = promisify4(execCb3);
44076
+ await execAsync3(`git worktree add "${isolatedPath}" -b "${taskWorkspace.branch}" "${taskWorkspace.baseBranch}"`, { cwd: repoRoot });
44077
+ taskWorkspace = { ...taskWorkspace, worktreePath: isolatedPath };
44078
+ createdWorktreePath = isolatedPath;
44079
+ emit("status", `worktree created: ${isolatedPath}`, { branch: taskWorkspace.branch });
44080
+ log14.info("Git worktree created for task", { taskId: taskId2, path: isolatedPath, branch: taskWorkspace.branch });
44081
+ } catch (wtErr) {
44082
+ const msg = String(wtErr.message ?? wtErr);
44083
+ if (msg.includes("already exists")) {
44084
+ taskWorkspace = { ...taskWorkspace, worktreePath: isolatedPath };
44085
+ createdWorktreePath = isolatedPath;
44086
+ log14.warn("Worktree already exists, reusing", { taskId: taskId2, path: isolatedPath });
44087
+ } else {
44088
+ log14.warn("Failed to create worktree, falling back to repo root", { taskId: taskId2, error: msg });
44089
+ }
44090
+ }
44091
+ }
43689
44092
  if (taskWorkspace) {
43690
44093
  const worktreePolicy = {
43691
44094
  primaryWorkspace: taskWorkspace.worktreePath,
@@ -43710,7 +44113,7 @@ ${report}`);
43710
44113
  if (ctx) {
43711
44114
  ctx.tools = taskLocalTools;
43712
44115
  }
43713
- log13.info("Tools rebound to worktree workspace (task-local)", {
44116
+ log14.info("Tools rebound to worktree workspace (task-local)", {
43714
44117
  taskId: taskId2,
43715
44118
  agentId: this.id,
43716
44119
  worktreePath: taskWorkspace.worktreePath
@@ -43837,7 +44240,7 @@ ${report}`);
43837
44240
  toolDefinitions: llmTools
43838
44241
  });
43839
44242
  const messages2 = preparedTask.messages;
43840
- log13.debug("Context usage for task execution", { taskId: taskId2, usagePercent: preparedTask.usage.usagePercent, totalUsed: preparedTask.usage.totalUsed });
44243
+ log14.debug("Context usage for task execution", { taskId: taskId2, usagePercent: preparedTask.usage.usagePercent, totalUsed: preparedTask.usage.totalUsed });
43841
44244
  let taskLlmStart = Date.now();
43842
44245
  let response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages: messages2, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(sessionId), compaction: useCompaction }, (event) => {
43843
44246
  if (event.type === "text_delta" && event.text) {
@@ -43854,7 +44257,7 @@ ${report}`);
43854
44257
  if (cancelToken?.cancelled) {
43855
44258
  flushText();
43856
44259
  emit("status", "cancelled", { reason: "Task execution was stopped externally" });
43857
- log13.info("Task execution cancelled externally", { taskId: taskId2, agentId: this.id });
44260
+ log14.info("Task execution cancelled externally", { taskId: taskId2, agentId: this.id });
43858
44261
  return;
43859
44262
  }
43860
44263
  flushText();
@@ -43906,7 +44309,7 @@ ${report}`);
43906
44309
  }
43907
44310
  if (cancelToken?.cancelled) {
43908
44311
  emit("status", "cancelled", { reason: "Task execution was stopped externally" });
43909
- log13.info("Task execution cancelled externally after tools", { taskId: taskId2, agentId: this.id });
44312
+ log14.info("Task execution cancelled externally after tools", { taskId: taskId2, agentId: this.id });
43910
44313
  return;
43911
44314
  }
43912
44315
  if (taskToolIterations > 0 && taskToolIterations % 10 === 0) {
@@ -43921,7 +44324,7 @@ ${report}`);
43921
44324
  "- Use `task_note` to record progress before submitting."
43922
44325
  ].join("\n")
43923
44326
  });
43924
- log13.debug("Injected task completion reminder", { taskId: taskId2, iteration: taskToolIterations });
44327
+ log14.debug("Injected task completion reminder", { taskId: taskId2, iteration: taskToolIterations });
43925
44328
  }
43926
44329
  const preparedTaskCont = await this.contextEngine.prepareMessages({
43927
44330
  systemPrompt,
@@ -43953,7 +44356,7 @@ ${report}`);
43953
44356
  if (cancelToken?.cancelled) {
43954
44357
  flushText();
43955
44358
  emit("status", "cancelled", { reason: "Task execution was stopped externally" });
43956
- log13.info("Task execution cancelled externally after completion", { taskId: taskId2, agentId: this.id });
44359
+ log14.info("Task execution cancelled externally after completion", { taskId: taskId2, agentId: this.id });
43957
44360
  return;
43958
44361
  }
43959
44362
  flushText();
@@ -43962,12 +44365,12 @@ ${report}`);
43962
44365
  emit("status", "execution_finished", {});
43963
44366
  this.metricsCollector.recordTaskCompletion(taskId2, "completed", Date.now() - taskStartMs);
43964
44367
  this.eventBus.emit("task:completed", { taskId: taskId2, agentId: this.id });
43965
- log13.info("Task execution finished", { taskId: taskId2, agentId: this.id });
44368
+ log14.info("Task execution finished", { taskId: taskId2, agentId: this.id });
43966
44369
  } catch (error) {
43967
44370
  if (cancelToken?.cancelled) {
43968
44371
  flushText();
43969
44372
  emit("status", "cancelled", { reason: "Task execution was stopped externally" });
43970
- log13.info("Task execution cancelled (caught abort)", { taskId: taskId2, agentId: this.id });
44373
+ log14.info("Task execution cancelled (caught abort)", { taskId: taskId2, agentId: this.id });
43971
44374
  return;
43972
44375
  }
43973
44376
  if (textBuffer.trim()) {
@@ -43985,7 +44388,7 @@ ${report}`);
43985
44388
  success: false,
43986
44389
  detail: String(error)
43987
44390
  });
43988
- log13.error("Task execution failed", { taskId: taskId2, agentId: this.id, error: String(error) });
44391
+ log14.error("Task execution failed", { taskId: taskId2, agentId: this.id, error: String(error) });
43989
44392
  this.eventBus.emit("task:failed", { taskId: taskId2, agentId: this.id, error: String(error) });
43990
44393
  taskFailed = String(error);
43991
44394
  throw error;
@@ -44214,7 +44617,7 @@ ${report}`);
44214
44617
  for (const tool of updatedTools) {
44215
44618
  this.tools.set(tool.name, tool);
44216
44619
  }
44217
- log13.info("Granted read-only access", { agentId: this.id, path });
44620
+ log14.info("Granted read-only access", { agentId: this.id, path });
44218
44621
  }
44219
44622
  /**
44220
44623
  * Remove a previously granted read-only path and rebuild tools.
@@ -44235,7 +44638,7 @@ ${report}`);
44235
44638
  for (const tool of updatedTools) {
44236
44639
  this.tools.set(tool.name, tool);
44237
44640
  }
44238
- log13.info("Revoked read-only access", { agentId: this.id, path });
44641
+ log14.info("Revoked read-only access", { agentId: this.id, path });
44239
44642
  }
44240
44643
  getState() {
44241
44644
  const state = { ...this.state };
@@ -44354,7 +44757,7 @@ ${report}`);
44354
44757
  }
44355
44758
  try {
44356
44759
  const result2 = await this.skillInstaller(args);
44357
- log13.info("Skill installed via discover_tools", { agentId: this.id, skill: skillName, method: result2.method });
44760
+ log14.info("Skill installed via discover_tools", { agentId: this.id, skill: skillName, method: result2.method });
44358
44761
  return JSON.stringify({
44359
44762
  status: "ok",
44360
44763
  installed: result2.name,
@@ -44392,7 +44795,7 @@ ${report}`);
44392
44795
  this.activateTools(toolNames);
44393
44796
  mcpToolCount = mcpTools.length;
44394
44797
  } catch (err) {
44395
- log13.warn("Failed to activate skill MCP servers via discover_tools", {
44798
+ log14.warn("Failed to activate skill MCP servers via discover_tools", {
44396
44799
  agentId: this.id,
44397
44800
  skill: name,
44398
44801
  error: String(err)
@@ -44407,7 +44810,7 @@ ${report}`);
44407
44810
  if (!skill.manifest.instructions && mcpToolCount === 0)
44408
44811
  parts.push("skill found but has no instructions or MCP tools");
44409
44812
  activated.push(parts.length > 1 ? `${parts[0]} (${parts.slice(1).join(", ")})` : parts[0]);
44410
- log13.info("Skill activated via discover_tools", {
44813
+ log14.info("Skill activated via discover_tools", {
44411
44814
  agentId: this.id,
44412
44815
  skill: name,
44413
44816
  mcpToolCount,
@@ -44443,7 +44846,7 @@ ${report}`);
44443
44846
  }
44444
44847
  try {
44445
44848
  const result = await this.userMessageSender(message);
44446
- log13.info("Proactive message sent to user", { agentId: this.id, sessionId: result.sessionId });
44849
+ log14.info("Proactive message sent to user", { agentId: this.id, sessionId: result.sessionId });
44447
44850
  return JSON.stringify({ status: "ok", sessionId: result.sessionId, messageId: result.messageId });
44448
44851
  } catch (err) {
44449
44852
  return JSON.stringify({ status: "error", message: `Failed to send message: ${String(err)}` });
@@ -44467,7 +44870,7 @@ ${report}`);
44467
44870
  const needsApproval = this.config.profile?.requireApprovalFor?.some((pattern) => toolCall.name === pattern || toolCall.name.startsWith(pattern.replace("*", "")));
44468
44871
  if (needsApproval) {
44469
44872
  if (this.approvalCallback) {
44470
- log13.info(`Tool ${toolCall.name} requires approval, requesting...`, { agentId: this.id });
44873
+ log14.info(`Tool ${toolCall.name} requires approval, requesting...`, { agentId: this.id });
44471
44874
  const approved = await this.approvalCallback({
44472
44875
  agentId: this.id,
44473
44876
  agentName: this.config.name,
@@ -44476,15 +44879,15 @@ ${report}`);
44476
44879
  reason: `Agent wants to execute '${toolCall.name}'`
44477
44880
  });
44478
44881
  if (!approved) {
44479
- log13.info(`Tool ${toolCall.name} execution denied by human`, { agentId: this.id });
44882
+ log14.info(`Tool ${toolCall.name} execution denied by human`, { agentId: this.id });
44480
44883
  return JSON.stringify({
44481
44884
  status: "denied",
44482
44885
  error: `Execution of '${toolCall.name}' was denied by human reviewer`
44483
44886
  });
44484
44887
  }
44485
- log13.info(`Tool ${toolCall.name} approved by human`, { agentId: this.id });
44888
+ log14.info(`Tool ${toolCall.name} approved by human`, { agentId: this.id });
44486
44889
  } else {
44487
- log13.warn(`Tool ${toolCall.name} requires approval but no approval callback set`, {
44890
+ log14.warn(`Tool ${toolCall.name} requires approval but no approval callback set`, {
44488
44891
  agentId: this.id
44489
44892
  });
44490
44893
  }
@@ -44525,10 +44928,10 @@ ${report}`);
44525
44928
  try {
44526
44929
  if (attempt > 0) {
44527
44930
  const delay = _Agent.TOOL_RETRY_BASE_MS * Math.pow(2, attempt - 1);
44528
- log13.info(`Retrying tool ${toolCall.name} (attempt ${attempt + 1})`, { delay });
44931
+ log14.info(`Retrying tool ${toolCall.name} (attempt ${attempt + 1})`, { delay });
44529
44932
  await new Promise((r) => setTimeout(r, delay));
44530
44933
  }
44531
- log13.debug(`Executing tool: ${toolCall.name}`, { args: effectiveArgs, attempt });
44934
+ log14.debug(`Executing tool: ${toolCall.name}`, { args: effectiveArgs, attempt });
44532
44935
  const span = startSpan("agent.tool", { tool: toolCall.name, attempt });
44533
44936
  try {
44534
44937
  const result = await handler4.execute(effectiveArgs, onOutput);
@@ -44551,7 +44954,7 @@ ${report}`);
44551
44954
  }
44552
44955
  } catch (error) {
44553
44956
  lastError = error;
44554
- log13.error(`Tool execution failed: ${toolCall.name} (attempt ${attempt + 1})`, {
44957
+ log14.error(`Tool execution failed: ${toolCall.name} (attempt ${attempt + 1})`, {
44555
44958
  error: String(error)
44556
44959
  });
44557
44960
  }
@@ -44563,7 +44966,7 @@ ${report}`);
44563
44966
  handleFailure(reason) {
44564
44967
  this.consecutiveFailures++;
44565
44968
  if (this.consecutiveFailures >= _Agent.MAX_CONSECUTIVE_FAILURES) {
44566
- log13.warn("Consecutive failure threshold reached, escalating to human", {
44969
+ log14.warn("Consecutive failure threshold reached, escalating to human", {
44567
44970
  agentId: this.id,
44568
44971
  failures: this.consecutiveFailures
44569
44972
  });
@@ -44588,7 +44991,7 @@ ${report}`);
44588
44991
  throw error;
44589
44992
  }
44590
44993
  const delay = _Agent.NETWORK_RETRY_BASE_MS * Math.pow(2, attempt);
44591
- log13.warn(`${label} failed with network error, retrying (${attempt + 1}/${_Agent.NETWORK_RETRY_MAX})`, {
44994
+ log14.warn(`${label} failed with network error, retrying (${attempt + 1}/${_Agent.NETWORK_RETRY_MAX})`, {
44592
44995
  agentId: this.id,
44593
44996
  error: String(error).slice(0, 200),
44594
44997
  delay
@@ -44612,7 +45015,7 @@ ${report}`);
44612
45015
  }
44613
45016
  }
44614
45017
  async handleHeartbeat(ctx) {
44615
- log13.info("Processing heartbeat check-in");
45018
+ log14.info("Processing heartbeat check-in");
44616
45019
  const activityId = this.startActivity("heartbeat", "Heartbeat check-in", {});
44617
45020
  let lastHeartbeatSummary = "";
44618
45021
  try {
@@ -44664,10 +45067,12 @@ ${todayLog.slice(0, 3e3)}
44664
45067
  '- **type**: "file"',
44665
45068
  "- **Content must be concise, clear, and accurate**:",
44666
45069
  " 1. **My work today**: What you personally accomplished (tasks reviewed, approved/rejected, decisions made)",
44667
- " 2. **Team progress**: What each team member accomplished today (cross-reference with activity log)",
44668
- " 3. **Blockers & risks**: Anything stalled or at risk",
44669
- " 4. **Plan for tomorrow**: Top priorities for the next day",
45070
+ " 2. **My team progress**: What each member of YOUR team accomplished today (use `team_status` to check). Focus on your own team only.",
45071
+ " 3. **Cross-team interactions**: Any coordination with other teams (if applicable)",
45072
+ " 4. **Blockers & risks**: Anything stalled or at risk within your team",
45073
+ " 5. **Plan for tomorrow**: Top priorities for the next day",
44670
45074
  "- Keep it under 500 words. No filler. Every sentence must carry information.",
45075
+ "- IMPORTANT: Only report on YOUR team. Do NOT report on agents from other teams.",
44671
45076
  "- If no meaningful activity happened today, say so honestly \u2014 do not fabricate work.",
44672
45077
  "- The system will automatically mark the report as created after this heartbeat.",
44673
45078
  ""
@@ -44687,26 +45092,67 @@ ${todayLog.slice(0, 3e3)}
44687
45092
  "Quality bar: Only record insights that are **specific**, **actionable**, and **non-obvious**.",
44688
45093
  "Skip if nothing meaningful happened since last heartbeat."
44689
45094
  ].join("\n");
45095
+ const bgCompletions = drainCompletedNotifications();
45096
+ let bgCompletionSection = "";
45097
+ if (bgCompletions.length > 0) {
45098
+ const lines = bgCompletions.map((n) => {
45099
+ const status = n.exitCode === 0 ? "OK" : `FAILED (exit ${n.exitCode})`;
45100
+ return `- [${status}] \`${n.command}\` (${Math.round(n.durationMs / 1e3)}s)${n.exitCode !== 0 && n.stderrTail ? `
45101
+ stderr: ${n.stderrTail.slice(0, 200)}` : ""}`;
45102
+ });
45103
+ bgCompletionSection = [
45104
+ "",
45105
+ "## Background Processes Completed",
45106
+ `${bgCompletions.length} background process(es) finished since last check:`,
45107
+ ...lines,
45108
+ "Review any failures and take action if needed."
45109
+ ].join("\n");
45110
+ }
44690
45111
  const prompt = [
44691
45112
  "[HEARTBEAT CHECK-IN]",
44692
45113
  "",
44693
45114
  "## Your Checklist",
44694
45115
  checklist,
44695
45116
  lastHeartbeatSummary,
45117
+ bgCompletionSection,
44696
45118
  failedTaskRecoverySection,
44697
45119
  dailyReportSection,
44698
45120
  selfEvolutionSection,
44699
45121
  "",
44700
- "## Rules",
45122
+ "## Core Principle: Patrol, Don't Build",
45123
+ "Heartbeat is a patrol \u2014 observe, triage, and take lightweight actions. Heavy work belongs in tasks.",
45124
+ "",
45125
+ "## What You CAN Do (lightweight actions)",
45126
+ "- **Check status**: `task_list`, `task_get`, `team_status` \u2014 see what's going on",
45127
+ "- **Send messages**: `agent_send_message`, `send_user_message` \u2014 notify people of issues or updates",
45128
+ "- **Create tasks**: `task_create` \u2014 if you spot something that needs doing, create a task for it (assign to yourself or others)",
45129
+ '- **Trigger existing tasks**: `task_update(status: "in_progress")` \u2014 restart failed tasks or unblock stuck ones',
45130
+ '- **Retry failed tasks**: If tasks assigned to you are in `failed` status, retry via `task_update(status: "in_progress")` with a note',
45131
+ "- **Quick reviews**: If tasks are in `review` where you are the reviewer, review them now (may need more tool calls)",
45132
+ "- **Save insights**: `memory_save` \u2014 record observations, lessons, and patterns",
45133
+ "- **Propose requirements**: `requirement_propose` \u2014 suggest work based on what you observe",
45134
+ "",
45135
+ "## What You Must NOT Do",
45136
+ "- **No complex multi-step implementation** \u2014 don't write code, refactor modules, or do deep analysis in heartbeat",
45137
+ "- If you identify something complex that needs doing:",
45138
+ " 1. Notify the user via `send_user_message` explaining what you found and why it matters",
45139
+ " 2. Create a task via `task_create` with clear description and acceptance criteria",
45140
+ " 3. The user will approve and the task system handles execution",
45141
+ "",
45142
+ "## Conditional Actions",
45143
+ "- If background processes failed \u2192 check the error, notify the responsible developer or user",
45144
+ "- If tasks are blocked for too long \u2192 investigate blockers, send a message to the assignee or PM",
45145
+ "- If a dependency task completed \u2192 check if downstream tasks can be unblocked",
45146
+ "- If you notice a recurring pattern \u2192 save it as a lesson via `memory_save`",
45147
+ "",
45148
+ "## Finishing Up",
44701
45149
  "- Compare against your last heartbeat summary above. Skip unchanged items.",
44702
- "- For routine checks: max 5 tool calls. This is monitoring, not a work session.",
44703
- "- **Exception \u2014 review duty**: If you find tasks in `review` where you are the reviewer, you MUST review them now. Reviews may require more tool calls (task_get, file_read, task_note, task_update). Complete the review fully.",
44704
- '- **Exception \u2014 failed tasks**: If you find tasks assigned to you in `failed` status, retry them via `task_update(status: "in_progress")` with a note.',
44705
- "- **Exception \u2014 daily report**: If the Daily Report Required section is present above, you MUST produce the report. This may require additional tool calls.",
44706
- "- At the end, call `memory_save` with key `heartbeat:summary` \u2014 one line per finding.",
45150
+ "- If the Daily Report Required section is present above, you MUST produce the report.",
45151
+ "- Call `memory_save` with key `heartbeat:summary` \u2014 one line per finding.",
44707
45152
  "- If nothing needs attention and no daily report is due, respond with exactly: HEARTBEAT_OK"
44708
45153
  ].join("\n");
44709
45154
  const baseTools = [
45155
+ "task_create",
44710
45156
  "task_list",
44711
45157
  "task_update",
44712
45158
  "task_get",
@@ -44759,7 +45205,7 @@ ${todayLog.slice(0, 3e3)}
44759
45205
  lastError = error;
44760
45206
  if (attempt < HEARTBEAT_MAX_RETRIES) {
44761
45207
  const delay = HEARTBEAT_RETRY_BASE_MS * Math.pow(2, attempt);
44762
- log13.warn(`Heartbeat attempt ${attempt + 1}/${HEARTBEAT_MAX_RETRIES + 1} failed, retrying in ${delay}ms`, {
45208
+ log14.warn(`Heartbeat attempt ${attempt + 1}/${HEARTBEAT_MAX_RETRIES + 1} failed, retrying in ${delay}ms`, {
44763
45209
  agentId: this.id,
44764
45210
  error: String(error).slice(0, 200)
44765
45211
  });
@@ -44770,7 +45216,7 @@ ${todayLog.slice(0, 3e3)}
44770
45216
  this.emitActivityLog(activityId, "error", String(lastError));
44771
45217
  this.endActivity(activityId);
44772
45218
  this.metricsCollector.recordHeartbeat(false);
44773
- log13.error("Heartbeat failed after all retries", {
45219
+ log14.error("Heartbeat failed after all retries", {
44774
45220
  agentId: this.id,
44775
45221
  attempts: HEARTBEAT_MAX_RETRIES + 1,
44776
45222
  error: String(lastError)
@@ -44809,9 +45255,9 @@ ${todayLog.slice(0, 3e3)}
44809
45255
  maxHistory: 25,
44810
45256
  scenario: "heartbeat"
44811
45257
  });
44812
- log13.info("Memory flush completed before compaction", { agentId: this.id, sessionId });
45258
+ log14.info("Memory flush completed before compaction", { agentId: this.id, sessionId });
44813
45259
  } catch (error) {
44814
- log13.warn("Memory flush failed, proceeding with compaction anyway", { error: String(error) });
45260
+ log14.warn("Memory flush failed, proceeding with compaction anyway", { error: String(error) });
44815
45261
  }
44816
45262
  }
44817
45263
  /**
@@ -44829,7 +45275,7 @@ ${todayLog.slice(0, 3e3)}
44829
45275
  await this.memoryFlush(this.currentSessionId);
44830
45276
  const { flushedCount } = this.memory.compactSession(this.currentSessionId, 15);
44831
45277
  if (flushedCount > 0) {
44832
- log13.info("Memory consolidation: compacted main session", {
45278
+ log14.info("Memory consolidation: compacted main session", {
44833
45279
  agentId: this.id,
44834
45280
  flushedCount,
44835
45281
  remaining: session.messages.length
@@ -44843,9 +45289,9 @@ ${todayLog.slice(0, 3e3)}
44843
45289
  await this.dreamConsolidateMemory(entries2);
44844
45290
  this.pruneMemoryMd();
44845
45291
  }
44846
- log13.debug("Memory consolidation completed", { agentId: this.id });
45292
+ log14.debug("Memory consolidation completed", { agentId: this.id });
44847
45293
  } catch (error) {
44848
- log13.warn("Memory consolidation failed", { agentId: this.id, error: String(error) });
45294
+ log14.warn("Memory consolidation failed", { agentId: this.id, error: String(error) });
44849
45295
  }
44850
45296
  }
44851
45297
  /**
@@ -44861,7 +45307,7 @@ ${todayLog.slice(0, 3e3)}
44861
45307
  return `[${i}] id=${e.id} type=${e.type} date=${e.timestamp?.slice(0, 10) ?? "?"}${tags}
44862
45308
  ${e.content.slice(0, 200)}`;
44863
45309
  }).join("\n\n");
44864
- log13.info("Dream cycle starting", {
45310
+ log14.info("Dream cycle starting", {
44865
45311
  agentId: this.id,
44866
45312
  totalEntries: entries2.length,
44867
45313
  batchSize: batch.length,
@@ -44900,11 +45346,11 @@ ${e.content.slice(0, 200)}`;
44900
45346
  });
44901
45347
  const jsonMatch = response.match(/\{[\s\S]*\}/);
44902
45348
  if (!jsonMatch) {
44903
- log13.debug("Dream cycle: no valid JSON in response, skipping");
45349
+ log14.debug("Dream cycle: no valid JSON in response, skipping");
44904
45350
  return;
44905
45351
  }
44906
45352
  const plan = JSON.parse(jsonMatch[0]);
44907
- log13.info("Dream cycle plan", {
45353
+ log14.info("Dream cycle plan", {
44908
45354
  agentId: this.id,
44909
45355
  toRemove: plan.remove?.length ?? 0,
44910
45356
  toMerge: plan.merge?.length ?? 0,
@@ -44946,7 +45392,7 @@ ${e.content.slice(0, 200)}`;
44946
45392
  }
44947
45393
  }
44948
45394
  if (removedCount > 0 || mergedCount > 0) {
44949
- log13.info("Dream cycle completed", {
45395
+ log14.info("Dream cycle completed", {
44950
45396
  agentId: this.id,
44951
45397
  entriesBefore: entries2.length,
44952
45398
  removed: removedCount,
@@ -44954,10 +45400,10 @@ ${e.content.slice(0, 200)}`;
44954
45400
  entriesAfter: this.memory.getEntries().length
44955
45401
  });
44956
45402
  } else {
44957
- log13.debug("Dream cycle: no changes needed", { agentId: this.id });
45403
+ log14.debug("Dream cycle: no changes needed", { agentId: this.id });
44958
45404
  }
44959
45405
  } catch (error) {
44960
- log13.warn("Dream cycle failed", { agentId: this.id, error: String(error) });
45406
+ log14.warn("Dream cycle failed", { agentId: this.id, error: String(error) });
44961
45407
  }
44962
45408
  }
44963
45409
  /**
@@ -45000,7 +45446,7 @@ ${e.content.slice(0, 200)}`;
45000
45446
  if (pruned !== content.trim()) {
45001
45447
  const memoryMdPath = join6(this.dataDir, "MEMORY.md");
45002
45448
  writeFileSync7(memoryMdPath, pruned + "\n");
45003
- log13.info("Pruned MEMORY.md: removed daily-report sections and LLM artifacts", { agentId: this.id });
45449
+ log14.info("Pruned MEMORY.md: removed daily-report sections and LLM artifacts", { agentId: this.id });
45004
45450
  }
45005
45451
  }
45006
45452
  };
@@ -45158,12 +45604,12 @@ ${sharedContent}` : roleContent;
45158
45604
 
45159
45605
  // ../core/dist/tools/mcp-client.js
45160
45606
  import { spawn as spawn3 } from "node:child_process";
45161
- var log14, MCPClientManager;
45607
+ var log15, MCPClientManager;
45162
45608
  var init_mcp_client = __esm({
45163
45609
  "../core/dist/tools/mcp-client.js"() {
45164
45610
  "use strict";
45165
45611
  init_dist();
45166
- log14 = createLogger("mcp-client");
45612
+ log15 = createLogger("mcp-client");
45167
45613
  MCPClientManager = class _MCPClientManager {
45168
45614
  servers = /* @__PURE__ */ new Map();
45169
45615
  requestId = 0;
@@ -45179,31 +45625,31 @@ var init_mcp_client = __esm({
45179
45625
  async connectByKey(key2, displayName, config) {
45180
45626
  const existing = this.servers.get(key2);
45181
45627
  if (existing) {
45182
- log14.info(`MCP server ${displayName} already connected, reusing (${existing.tools.length} tools)`);
45628
+ log15.info(`MCP server ${displayName} already connected, reusing (${existing.tools.length} tools)`);
45183
45629
  return existing.tools;
45184
45630
  }
45185
- log14.info(`Connecting to MCP server: ${displayName}`, { command: config.command, key: key2 });
45631
+ log15.info(`Connecting to MCP server: ${displayName}`, { command: config.command, key: key2 });
45186
45632
  const proc = spawn3(config.command, config.args ?? [], {
45187
45633
  stdio: ["pipe", "pipe", "pipe"],
45188
45634
  env: { ...process.env, ...config.env }
45189
45635
  });
45190
45636
  proc.on("error", (err) => {
45191
- log14.error(`MCP server ${displayName} error`, { error: String(err) });
45637
+ log15.error(`MCP server ${displayName} error`, { error: String(err) });
45192
45638
  });
45193
45639
  const stderrChunks = [];
45194
45640
  proc.stderr?.on("data", (data) => {
45195
45641
  const text2 = data.toString();
45196
45642
  stderrChunks.push(text2);
45197
45643
  if (stderrChunks.length <= 5) {
45198
- log14.warn(`MCP server ${displayName} stderr`, { text: text2.trimEnd() });
45644
+ log15.warn(`MCP server ${displayName} stderr`, { text: text2.trimEnd() });
45199
45645
  }
45200
45646
  });
45201
45647
  proc.on("exit", (code) => {
45202
45648
  const stderr = stderrChunks.join("").trim();
45203
45649
  if (stderr) {
45204
- log14.error(`MCP server ${displayName} exited with stderr`, { code, stderr: stderr.slice(0, 500) });
45650
+ log15.error(`MCP server ${displayName} exited with stderr`, { code, stderr: stderr.slice(0, 500) });
45205
45651
  } else {
45206
- log14.info(`MCP server ${displayName} exited`, { code });
45652
+ log15.info(`MCP server ${displayName} exited`, { code });
45207
45653
  }
45208
45654
  this.servers.delete(key2);
45209
45655
  this.stdoutBuffers.delete(proc);
@@ -45227,7 +45673,7 @@ var init_mcp_client = __esm({
45227
45673
  const toolsResult = await this.sendRequest(proc, "tools/list", {});
45228
45674
  const tools = toolsResult?.tools ?? [];
45229
45675
  this.servers.set(key2, { process: proc, tools });
45230
- log14.info(`MCP server ${displayName} connected with ${tools.length} tools`);
45676
+ log15.info(`MCP server ${displayName} connected with ${tools.length} tools`);
45231
45677
  return tools;
45232
45678
  } catch (err) {
45233
45679
  proc.kill();
@@ -45302,7 +45748,7 @@ var init_mcp_client = __esm({
45302
45748
  server.process.kill();
45303
45749
  this.servers.delete(name);
45304
45750
  this.stdoutBuffers.delete(server.process);
45305
- log14.info(`MCP server disconnected: ${name}`);
45751
+ log15.info(`MCP server disconnected: ${name}`);
45306
45752
  }
45307
45753
  }
45308
45754
  async disconnectServerScoped(name, scopeId) {
@@ -45379,12 +45825,12 @@ var init_mcp_client = __esm({
45379
45825
  });
45380
45826
 
45381
45827
  // ../core/dist/tools/browser-session.js
45382
- var log15, TARGET_ID_PARAM_NAMES, BrowserSessionManager;
45828
+ var log16, TARGET_ID_PARAM_NAMES, BrowserSessionManager;
45383
45829
  var init_browser_session = __esm({
45384
45830
  "../core/dist/tools/browser-session.js"() {
45385
45831
  "use strict";
45386
45832
  init_dist();
45387
- log15 = createLogger("browser-session");
45833
+ log16 = createLogger("browser-session");
45388
45834
  TARGET_ID_PARAM_NAMES = ["targetId", "id", "pageId", "target"];
45389
45835
  BrowserSessionManager = class {
45390
45836
  /** agentId → set of owned target/page IDs */
@@ -45468,7 +45914,7 @@ var init_browser_session = __esm({
45468
45914
  const owned = this.getOwned(agentId2);
45469
45915
  for (const id of ids) {
45470
45916
  owned.add(id);
45471
- log15.debug(`Page ${id} assigned to agent ${agentId2}`);
45917
+ log16.debug(`Page ${id} assigned to agent ${agentId2}`);
45472
45918
  }
45473
45919
  return result;
45474
45920
  }
@@ -45491,7 +45937,7 @@ var init_browser_session = __esm({
45491
45937
  return owned.has(id);
45492
45938
  });
45493
45939
  if (parsed.length !== filtered.length) {
45494
- log15.debug(`list_pages: agent ${agentId2} sees ${filtered.length}/${parsed.length} pages (strict ownership filter)`);
45940
+ log16.debug(`list_pages: agent ${agentId2} sees ${filtered.length}/${parsed.length} pages (strict ownership filter)`);
45495
45941
  }
45496
45942
  return JSON.stringify(filtered);
45497
45943
  }
@@ -45509,7 +45955,7 @@ var init_browser_session = __esm({
45509
45955
  const targetId = this.extractTargetIdFromArgs(args);
45510
45956
  if (targetId && !this.isOwnedByMe(agentId2, targetId)) {
45511
45957
  const msg = `Cannot select page ${targetId}: you can only select pages you created with new_page. Use new_page to open your own tab.`;
45512
- log15.warn(msg, { agentId: agentId2, targetId });
45958
+ log16.warn(msg, { agentId: agentId2, targetId });
45513
45959
  return JSON.stringify({ error: msg });
45514
45960
  }
45515
45961
  return handler4.execute(args);
@@ -45524,7 +45970,7 @@ var init_browser_session = __esm({
45524
45970
  const targetId = this.extractTargetIdFromArgs(args);
45525
45971
  if (targetId && !this.isOwnedByMe(agentId2, targetId)) {
45526
45972
  const msg = `Cannot close page ${targetId}: you can only close pages you created with new_page. Do not close tabs you did not open.`;
45527
- log15.warn(msg, { agentId: agentId2, targetId });
45973
+ log16.warn(msg, { agentId: agentId2, targetId });
45528
45974
  return JSON.stringify({ error: msg });
45529
45975
  }
45530
45976
  const result = await handler4.execute(args);
@@ -45547,13 +45993,13 @@ var init_browser_session = __esm({
45547
45993
  const owned = this.getOwned(agentId2);
45548
45994
  if (owned.size === 0) {
45549
45995
  const msg = "You have no owned pages. Call new_page first to create your own tab before navigating.";
45550
- log15.warn(`Agent ${agentId2} called navigate_page with no owned pages`, { agentId: agentId2, url: args.url });
45996
+ log16.warn(`Agent ${agentId2} called navigate_page with no owned pages`, { agentId: agentId2, url: args.url });
45551
45997
  return JSON.stringify({ error: msg });
45552
45998
  }
45553
45999
  const targetId = this.extractTargetIdFromArgs(args);
45554
46000
  if (targetId && !owned.has(targetId)) {
45555
46001
  const msg = `Cannot navigate page ${targetId}: it is not a page you own. Use new_page to create your own tab.`;
45556
- log15.warn(msg, { agentId: agentId2, targetId });
46002
+ log16.warn(msg, { agentId: agentId2, targetId });
45557
46003
  return JSON.stringify({ error: msg });
45558
46004
  }
45559
46005
  return handler4.execute(args);
@@ -45577,13 +46023,13 @@ var init_browser_session = __esm({
45577
46023
  const owned = this.getOwned(agentId2);
45578
46024
  if (owned.size === 0) {
45579
46025
  const msg = `Cannot use ${toolName} before creating a tab. Call new_page first to create your own tab.`;
45580
- log15.warn(`Agent ${agentId2} called ${toolName} with no owned pages`, { agentId: agentId2 });
46026
+ log16.warn(`Agent ${agentId2} called ${toolName} with no owned pages`, { agentId: agentId2 });
45581
46027
  return JSON.stringify({ error: msg });
45582
46028
  }
45583
46029
  const targetId = this.extractTargetIdFromArgs(args);
45584
46030
  if (targetId && !owned.has(targetId)) {
45585
46031
  const msg = `Cannot use ${toolName} on page ${targetId}: it is not a page you own. Only interact with pages you created via new_page.`;
45586
- log15.warn(msg, { agentId: agentId2, targetId, toolName });
46032
+ log16.warn(msg, { agentId: agentId2, targetId, toolName });
45587
46033
  return JSON.stringify({ error: msg });
45588
46034
  }
45589
46035
  return handler4.execute(args);
@@ -45597,7 +46043,7 @@ var init_browser_session = __esm({
45597
46043
  cleanupAgent(agentId2) {
45598
46044
  const owned = this.ownedPages.get(agentId2);
45599
46045
  if (owned?.size) {
45600
- log15.info(`Cleaning up ${owned.size} browser page(s) for agent ${agentId2}`);
46046
+ log16.info(`Cleaning up ${owned.size} browser page(s) for agent ${agentId2}`);
45601
46047
  }
45602
46048
  this.ownedPages.delete(agentId2);
45603
46049
  }
@@ -45647,7 +46093,7 @@ function createManagerTools(ctx) {
45647
46093
  const targetId = args["agent_id"];
45648
46094
  const message = args["message"];
45649
46095
  ctx.delegateMessage(targetId, message, "manager").catch((err) => {
45650
- log16.warn(`Delegated task to ${targetId} failed in background`, { error: String(err) });
46096
+ log17.warn(`Delegated task to ${targetId} failed in background`, { error: String(err) });
45651
46097
  });
45652
46098
  return JSON.stringify({ status: "dispatched", message: "Task dispatched. The agent will work on it independently." });
45653
46099
  }
@@ -45726,12 +46172,12 @@ function createManagerTools(ctx) {
45726
46172
  ] : []
45727
46173
  ];
45728
46174
  }
45729
- var log16;
46175
+ var log17;
45730
46176
  var init_manager = __esm({
45731
46177
  "../core/dist/tools/manager.js"() {
45732
46178
  "use strict";
45733
46179
  init_dist();
45734
- log16 = createLogger("manager-tools");
46180
+ log17 = createLogger("manager-tools");
45735
46181
  }
45736
46182
  });
45737
46183
 
@@ -45771,19 +46217,19 @@ function createA2ATools(ctx) {
45771
46217
  return JSON.stringify({ status: "error", error: "Cannot send a message to yourself" });
45772
46218
  }
45773
46219
  if (waitForReply) {
45774
- log17.info(`A2A request (sync): ${ctx.selfName} \u2192 ${targetId}`, { messageLen: message.length });
46220
+ log18.info(`A2A request (sync): ${ctx.selfName} \u2192 ${targetId}`, { messageLen: message.length });
45775
46221
  try {
45776
46222
  const reply = await ctx.sendMessage(targetId, message, ctx.selfId, ctx.selfName);
45777
- log17.info(`A2A reply received: ${targetId} \u2192 ${ctx.selfName}`, { replyLen: reply.length });
46223
+ log18.info(`A2A reply received: ${targetId} \u2192 ${ctx.selfName}`, { replyLen: reply.length });
45778
46224
  return JSON.stringify({ status: "replied", from: targetId, reply });
45779
46225
  } catch (err) {
45780
- log17.warn(`A2A sync message to ${targetId} failed`, { error: String(err) });
46226
+ log18.warn(`A2A sync message to ${targetId} failed`, { error: String(err) });
45781
46227
  return JSON.stringify({ status: "error", error: `Failed to get reply: ${String(err)}` });
45782
46228
  }
45783
46229
  }
45784
- log17.info(`A2A notify (async): ${ctx.selfName} \u2192 ${targetId}`, { messageLen: message.length });
46230
+ log18.info(`A2A notify (async): ${ctx.selfName} \u2192 ${targetId}`, { messageLen: message.length });
45785
46231
  ctx.sendMessage(targetId, message, ctx.selfId, ctx.selfName).catch((err) => {
45786
- log17.warn(`A2A async message to ${targetId} failed in background`, { error: String(err) });
46232
+ log18.warn(`A2A async message to ${targetId} failed in background`, { error: String(err) });
45787
46233
  });
45788
46234
  return JSON.stringify({ status: "dispatched", message: "Notification sent. The agent will process it independently." });
45789
46235
  }
@@ -45859,12 +46305,12 @@ function createA2ATools(ctx) {
45859
46305
  }] : []
45860
46306
  ];
45861
46307
  }
45862
- var log17;
46308
+ var log18;
45863
46309
  var init_a2a = __esm({
45864
46310
  "../core/dist/tools/a2a.js"() {
45865
46311
  "use strict";
45866
46312
  init_dist();
45867
- log17 = createLogger("a2a-tools");
46313
+ log18 = createLogger("a2a-tools");
45868
46314
  }
45869
46315
  });
45870
46316
 
@@ -45891,7 +46337,7 @@ function createStructuredA2ATools(ctx) {
45891
46337
  }
45892
46338
  };
45893
46339
  const message = JSON.stringify(structuredMessage);
45894
- log18.info(`Structured A2A message dispatched: ${ctx.selfName} \u2192 ${targetId}`, {
46340
+ log19.info(`Structured A2A message dispatched: ${ctx.selfName} \u2192 ${targetId}`, {
45895
46341
  messageType,
45896
46342
  payloadSize: JSON.stringify(payload).length
45897
46343
  });
@@ -45899,7 +46345,7 @@ function createStructuredA2ATools(ctx) {
45899
46345
  try {
45900
46346
  await ctx.sendMessage(targetId, message, ctx.selfId, ctx.selfName);
45901
46347
  } catch (err) {
45902
- log18.warn(`Structured A2A message to ${targetId} failed in background`, {
46348
+ log19.warn(`Structured A2A message to ${targetId} failed in background`, {
45903
46349
  error: String(err),
45904
46350
  messageType
45905
46351
  });
@@ -45993,12 +46439,12 @@ function createStructuredA2ATools(ctx) {
45993
46439
  }
45994
46440
  ];
45995
46441
  }
45996
- var log18, A2A_SEND_INTERVAL_MS, sendQueue;
46442
+ var log19, A2A_SEND_INTERVAL_MS, sendQueue;
45997
46443
  var init_a2a_structured = __esm({
45998
46444
  "../core/dist/tools/a2a-structured.js"() {
45999
46445
  "use strict";
46000
46446
  init_dist();
46001
- log18 = createLogger("a2a-structured-tools");
46447
+ log19 = createLogger("a2a-structured-tools");
46002
46448
  A2A_SEND_INTERVAL_MS = 3e4;
46003
46449
  sendQueue = Promise.resolve();
46004
46450
  }
@@ -46118,7 +46564,7 @@ function createAgentTaskTools(ctx) {
46118
46564
  taskType,
46119
46565
  scheduleConfig
46120
46566
  });
46121
- log19.info(`Task created by agent ${ctx.agentId}`, { taskId: task.id, title: task.title, assignedAgentId });
46567
+ log20.info(`Task created by agent ${ctx.agentId}`, { taskId: task.id, title: task.title, assignedAgentId });
46122
46568
  if (task.status === "pending_approval") {
46123
46569
  return JSON.stringify({
46124
46570
  status: "pending_approval",
@@ -46132,7 +46578,7 @@ function createAgentTaskTools(ctx) {
46132
46578
  message: `Task created: "${task.title}" (ID: ${task.id})`
46133
46579
  });
46134
46580
  } catch (error) {
46135
- log19.error("task_create failed", { error: String(error) });
46581
+ log20.error("task_create failed", { error: String(error) });
46136
46582
  return JSON.stringify({ status: "error", error: String(error) });
46137
46583
  }
46138
46584
  }
@@ -46302,7 +46748,7 @@ function createAgentTaskTools(ctx) {
46302
46748
  await ctx.addTaskNote(task2.id, note, ctx.agentName).catch(() => {
46303
46749
  });
46304
46750
  }
46305
- log19.info(`Pending task cancelled by creator ${ctx.agentId}`, { taskId: task2.id });
46751
+ log20.info(`Pending task cancelled by creator ${ctx.agentId}`, { taskId: task2.id });
46306
46752
  return JSON.stringify({
46307
46753
  status: "success",
46308
46754
  task: task2,
@@ -46315,7 +46761,7 @@ function createAgentTaskTools(ctx) {
46315
46761
  });
46316
46762
  }
46317
46763
  if (existing?.assignedAgentId === ctx.agentId && existing?.status === "in_progress") {
46318
- log19.warn(`Agent ${ctx.agentId} attempted to set own running task to "${newStatus}"`, { taskId: taskId2 });
46764
+ log20.warn(`Agent ${ctx.agentId} attempted to set own running task to "${newStatus}"`, { taskId: taskId2 });
46319
46765
  return JSON.stringify({
46320
46766
  status: "denied",
46321
46767
  error: `Setting your own running task to "${newStatus}" will immediately abort all ongoing work. If you truly need to stop, confirm by adding a note explaining why. Otherwise, continue working on the task.`
@@ -46335,7 +46781,7 @@ function createAgentTaskTools(ctx) {
46335
46781
  await ctx.addTaskNote(task.id, note, ctx.agentName).catch(() => {
46336
46782
  });
46337
46783
  }
46338
- log19.info(`Task updated by agent ${ctx.agentId}`, {
46784
+ log20.info(`Task updated by agent ${ctx.agentId}`, {
46339
46785
  taskId: task.id,
46340
46786
  status: task.status
46341
46787
  });
@@ -46352,7 +46798,7 @@ function createAgentTaskTools(ctx) {
46352
46798
  await ctx.addTaskNote(taskId2, note, ctx.agentName);
46353
46799
  }
46354
46800
  const task = ctx.getTask ? await ctx.getTask(taskId2) : null;
46355
- log19.info(`Task updated by agent ${ctx.agentId}`, { taskId: taskId2, hasNote: !!note, hasDescription: description !== void 0, hasBlockedBy: blockedBy !== void 0 });
46801
+ log20.info(`Task updated by agent ${ctx.agentId}`, { taskId: taskId2, hasNote: !!note, hasDescription: description !== void 0, hasBlockedBy: blockedBy !== void 0 });
46356
46802
  return JSON.stringify({
46357
46803
  status: "success",
46358
46804
  task,
@@ -46646,7 +47092,7 @@ function createAgentTaskTools(ctx) {
46646
47092
  projectId: args["project_id"],
46647
47093
  tags: args["tags"]
46648
47094
  });
46649
- log19.info(`Requirement proposed by agent ${ctx.agentId}`, {
47095
+ log20.info(`Requirement proposed by agent ${ctx.agentId}`, {
46650
47096
  requirementId: req.id,
46651
47097
  title: req.title
46652
47098
  });
@@ -46656,7 +47102,7 @@ function createAgentTaskTools(ctx) {
46656
47102
  message: `Requirement proposed: "${req.title}" (ID: ${req.id}). It will be reviewed by a human user. Do NOT create tasks for this until it is approved.`
46657
47103
  });
46658
47104
  } catch (error) {
46659
- log19.error("requirement_propose failed", { error: String(error) });
47105
+ log20.error("requirement_propose failed", { error: String(error) });
46660
47106
  return JSON.stringify({ status: "error", error: String(error) });
46661
47107
  }
46662
47108
  }
@@ -46749,7 +47195,7 @@ function createAgentTaskTools(ctx) {
46749
47195
  async execute(args) {
46750
47196
  try {
46751
47197
  const req = await ctx.updateRequirementStatus(args["requirement_id"], args["status"], args["reason"]);
46752
- log19.info(`Requirement status updated by agent ${ctx.agentId}`, {
47198
+ log20.info(`Requirement status updated by agent ${ctx.agentId}`, {
46753
47199
  requirementId: req.id,
46754
47200
  newStatus: req.status,
46755
47201
  reason: args["reason"]
@@ -46760,7 +47206,7 @@ function createAgentTaskTools(ctx) {
46760
47206
  message: `Requirement "${req.title}" (ID: ${req.id}) status changed to ${req.status}.`
46761
47207
  });
46762
47208
  } catch (error) {
46763
- log19.error("requirement_update_status failed", { error: String(error) });
47209
+ log20.error("requirement_update_status failed", { error: String(error) });
46764
47210
  return JSON.stringify({ status: "error", error: String(error) });
46765
47211
  }
46766
47212
  }
@@ -46768,12 +47214,12 @@ function createAgentTaskTools(ctx) {
46768
47214
  ] : []
46769
47215
  ];
46770
47216
  }
46771
- var log19;
47217
+ var log20;
46772
47218
  var init_task_tools = __esm({
46773
47219
  "../core/dist/tools/task-tools.js"() {
46774
47220
  "use strict";
46775
47221
  init_dist();
46776
- log19 = createLogger("task-tools");
47222
+ log20 = createLogger("task-tools");
46777
47223
  }
46778
47224
  });
46779
47225
 
@@ -47100,10 +47546,10 @@ function createMemoryTools(ctx) {
47100
47546
  ctx.memory.addEntry(entry);
47101
47547
  if (ctx.semanticSearch?.isEnabled()) {
47102
47548
  ctx.semanticSearch.indexMemory(entry, ctx.agentId).catch((err) => {
47103
- log20.warn("Failed to index memory for semantic search", { error: String(err) });
47549
+ log21.warn("Failed to index memory for semantic search", { error: String(err) });
47104
47550
  });
47105
47551
  }
47106
- log20.info("Agent saved memory", { agentId: ctx.agentId, type, contentLen: content.length });
47552
+ log21.info("Agent saved memory", { agentId: ctx.agentId, type, contentLen: content.length });
47107
47553
  return JSON.stringify({ status: "saved", id: entry.id, type });
47108
47554
  }
47109
47555
  },
@@ -47142,7 +47588,7 @@ function createMemoryTools(ctx) {
47142
47588
  let entries2 = semResults.map((r) => r.entry);
47143
47589
  if (type)
47144
47590
  entries2 = entries2.filter((e) => e.type === type);
47145
- log20.debug("Semantic memory search", { agentId: ctx.agentId, query: query2, results: entries2.length });
47591
+ log21.debug("Semantic memory search", { agentId: ctx.agentId, query: query2, results: entries2.length });
47146
47592
  return JSON.stringify({
47147
47593
  results: entries2.map((e) => ({
47148
47594
  id: e.id,
@@ -47154,14 +47600,14 @@ function createMemoryTools(ctx) {
47154
47600
  count: entries2.length
47155
47601
  });
47156
47602
  } catch (err) {
47157
- log20.warn("Semantic search failed, falling back to substring", { error: String(err) });
47603
+ log21.warn("Semantic search failed, falling back to substring", { error: String(err) });
47158
47604
  }
47159
47605
  }
47160
47606
  let results = ctx.memory.search(query2);
47161
47607
  if (type)
47162
47608
  results = results.filter((e) => e.type === type);
47163
47609
  results = results.slice(0, limit);
47164
- log20.debug("Memory search (substring)", { agentId: ctx.agentId, query: query2, results: results.length });
47610
+ log21.debug("Memory search (substring)", { agentId: ctx.agentId, query: query2, results: results.length });
47165
47611
  return JSON.stringify({
47166
47612
  results: results.map((e) => ({
47167
47613
  id: e.id,
@@ -47227,18 +47673,18 @@ function createMemoryTools(ctx) {
47227
47673
  const section = args["section"];
47228
47674
  const content = args["content"];
47229
47675
  ctx.memory.addLongTermMemory(section, content);
47230
- log20.info("Agent updated long-term memory", { agentId: ctx.agentId, section, contentLen: content.length });
47676
+ log21.info("Agent updated long-term memory", { agentId: ctx.agentId, section, contentLen: content.length });
47231
47677
  return JSON.stringify({ status: "updated", section });
47232
47678
  }
47233
47679
  }
47234
47680
  ];
47235
47681
  }
47236
- var log20;
47682
+ var log21;
47237
47683
  var init_memory = __esm({
47238
47684
  "../core/dist/tools/memory.js"() {
47239
47685
  "use strict";
47240
47686
  init_dist();
47241
- log20 = createLogger("memory-tools");
47687
+ log21 = createLogger("memory-tools");
47242
47688
  }
47243
47689
  });
47244
47690
 
@@ -47257,12 +47703,12 @@ function cosineSimilarity(a, b) {
47257
47703
  const denom = Math.sqrt(normA) * Math.sqrt(normB);
47258
47704
  return denom === 0 ? 0 : dot / denom;
47259
47705
  }
47260
- var log21, OpenAIEmbeddingProvider, PgVectorStore, LocalVectorStore, SemanticMemorySearch;
47706
+ var log22, OpenAIEmbeddingProvider, PgVectorStore, LocalVectorStore, SemanticMemorySearch;
47261
47707
  var init_semantic_search = __esm({
47262
47708
  "../core/dist/memory/semantic-search.js"() {
47263
47709
  "use strict";
47264
47710
  init_dist();
47265
- log21 = createLogger("semantic-search");
47711
+ log22 = createLogger("semantic-search");
47266
47712
  OpenAIEmbeddingProvider = class {
47267
47713
  dimensions;
47268
47714
  apiKey;
@@ -47316,7 +47762,7 @@ var init_semantic_search = __esm({
47316
47762
  params: [id, metadata.agentId, metadata.content, metadata.type, vectorStr]
47317
47763
  });
47318
47764
  } catch (err) {
47319
- log21.warn("Vector upsert failed, pgvector may not be available", { error: String(err) });
47765
+ log22.warn("Vector upsert failed, pgvector may not be available", { error: String(err) });
47320
47766
  }
47321
47767
  }
47322
47768
  async search(queryEmbedding, opts) {
@@ -47340,7 +47786,7 @@ var init_semantic_search = __esm({
47340
47786
  type: r["type"]
47341
47787
  }));
47342
47788
  } catch (err) {
47343
- log21.warn("Vector search failed", { error: String(err) });
47789
+ log22.warn("Vector search failed", { error: String(err) });
47344
47790
  return [];
47345
47791
  }
47346
47792
  }
@@ -47372,10 +47818,10 @@ var init_semantic_search = __esm({
47372
47818
  params: []
47373
47819
  });
47374
47820
  this.pgvectorAvailable = true;
47375
- log21.info("pgvector memory_embeddings table ready");
47821
+ log22.info("pgvector memory_embeddings table ready");
47376
47822
  return true;
47377
47823
  } catch (err) {
47378
- log21.warn("pgvector setup failed, semantic search will use fallback", { error: String(err) });
47824
+ log22.warn("pgvector setup failed, semantic search will use fallback", { error: String(err) });
47379
47825
  this.pgvectorAvailable = false;
47380
47826
  return false;
47381
47827
  }
@@ -47424,10 +47870,10 @@ var init_semantic_search = __esm({
47424
47870
  if (existsSync14(this.storePath)) {
47425
47871
  const data = JSON.parse(readFileSync11(this.storePath, "utf-8"));
47426
47872
  this.vectors = new Map(data);
47427
- log21.info("Local vector store loaded", { entries: this.vectors.size });
47873
+ log22.info("Local vector store loaded", { entries: this.vectors.size });
47428
47874
  }
47429
47875
  } catch (err) {
47430
- log21.warn("Failed to load local vector store", { error: String(err) });
47876
+ log22.warn("Failed to load local vector store", { error: String(err) });
47431
47877
  }
47432
47878
  }
47433
47879
  scheduleSave() {
@@ -47442,7 +47888,7 @@ var init_semantic_search = __esm({
47442
47888
  writeFileSync8(this.storePath, JSON.stringify(Array.from(this.vectors.entries())));
47443
47889
  this.dirty = false;
47444
47890
  } catch (err) {
47445
- log21.warn("Failed to save local vector store", { error: String(err) });
47891
+ log22.warn("Failed to save local vector store", { error: String(err) });
47446
47892
  }
47447
47893
  }, 2e3);
47448
47894
  }
@@ -47477,7 +47923,7 @@ var init_semantic_search = __esm({
47477
47923
  type: entry.type
47478
47924
  });
47479
47925
  } catch (err) {
47480
- log21.warn("Failed to index memory entry", { id: entry.id, error: String(err) });
47926
+ log22.warn("Failed to index memory entry", { id: entry.id, error: String(err) });
47481
47927
  }
47482
47928
  }
47483
47929
  async search(query2, opts) {
@@ -47500,7 +47946,7 @@ var init_semantic_search = __esm({
47500
47946
  similarity: r.similarity
47501
47947
  }));
47502
47948
  } catch (err) {
47503
- log21.warn("Semantic search failed, returning empty results", { error: String(err) });
47949
+ log22.warn("Semantic search failed, returning empty results", { error: String(err) });
47504
47950
  return [];
47505
47951
  }
47506
47952
  }
@@ -47514,12 +47960,12 @@ var init_semantic_search = __esm({
47514
47960
  });
47515
47961
 
47516
47962
  // ../a2a/dist/bus.js
47517
- var log22, MAX_RETRIES, RETRY_BASE_MS, A2ABus;
47963
+ var log23, MAX_RETRIES, RETRY_BASE_MS, A2ABus;
47518
47964
  var init_bus = __esm({
47519
47965
  "../a2a/dist/bus.js"() {
47520
47966
  "use strict";
47521
47967
  init_dist();
47522
- log22 = createLogger("a2a-bus");
47968
+ log23 = createLogger("a2a-bus");
47523
47969
  MAX_RETRIES = 3;
47524
47970
  RETRY_BASE_MS = 1e3;
47525
47971
  A2ABus = class {
@@ -47527,11 +47973,11 @@ var init_bus = __esm({
47527
47973
  agentEndpoints = /* @__PURE__ */ new Map();
47528
47974
  registerAgent(agentId2, handler4) {
47529
47975
  this.agentEndpoints.set(agentId2, handler4);
47530
- log22.info(`Agent registered on A2A bus: ${agentId2}`);
47976
+ log23.info(`Agent registered on A2A bus: ${agentId2}`);
47531
47977
  }
47532
47978
  unregisterAgent(agentId2) {
47533
47979
  this.agentEndpoints.delete(agentId2);
47534
- log22.info(`Agent unregistered from A2A bus: ${agentId2}`);
47980
+ log23.info(`Agent unregistered from A2A bus: ${agentId2}`);
47535
47981
  }
47536
47982
  on(type, handler4) {
47537
47983
  const existing = this.handlers.get(type) ?? [];
@@ -47548,7 +47994,7 @@ var init_bus = __esm({
47548
47994
  lastError = error;
47549
47995
  if (attempt < MAX_RETRIES - 1) {
47550
47996
  const delay = RETRY_BASE_MS * Math.pow(2, attempt);
47551
- log22.warn(`${label} failed, retrying (${attempt + 1}/${MAX_RETRIES})`, {
47997
+ log23.warn(`${label} failed, retrying (${attempt + 1}/${MAX_RETRIES})`, {
47552
47998
  error: String(error).slice(0, 200),
47553
47999
  delay
47554
48000
  });
@@ -47556,10 +48002,10 @@ var init_bus = __esm({
47556
48002
  }
47557
48003
  }
47558
48004
  }
47559
- log22.error(`${label} failed after ${MAX_RETRIES} retries`, { error: String(lastError) });
48005
+ log23.error(`${label} failed after ${MAX_RETRIES} retries`, { error: String(lastError) });
47560
48006
  }
47561
48007
  async send(envelope) {
47562
- log22.debug(`A2A message: ${envelope.type} from=${envelope.from} to=${envelope.to}`, {
48008
+ log23.debug(`A2A message: ${envelope.type} from=${envelope.from} to=${envelope.to}`, {
47563
48009
  id: envelope.id,
47564
48010
  correlationId: envelope.correlationId
47565
48011
  });
@@ -47567,7 +48013,7 @@ var init_bus = __esm({
47567
48013
  if (agentHandler) {
47568
48014
  await this.deliverWithRetry(agentHandler, envelope, `A2A delivery to ${envelope.to}`);
47569
48015
  } else {
47570
- log22.warn(`A2A target agent not found: ${envelope.to}`);
48016
+ log23.warn(`A2A target agent not found: ${envelope.to}`);
47571
48017
  }
47572
48018
  const typeHandlers = this.handlers.get(envelope.type) ?? [];
47573
48019
  for (const handler4 of typeHandlers) {
@@ -47596,12 +48042,12 @@ var init_bus = __esm({
47596
48042
  });
47597
48043
 
47598
48044
  // ../a2a/dist/delegation.js
47599
- var log23, DelegationManager;
48045
+ var log24, DelegationManager;
47600
48046
  var init_delegation = __esm({
47601
48047
  "../a2a/dist/delegation.js"() {
47602
48048
  "use strict";
47603
48049
  init_dist();
47604
- log23 = createLogger("a2a-delegation");
48050
+ log24 = createLogger("a2a-delegation");
47605
48051
  DelegationManager = class {
47606
48052
  bus;
47607
48053
  agentCards = /* @__PURE__ */ new Map();
@@ -47661,7 +48107,7 @@ var init_delegation = __esm({
47661
48107
  payload: delegation
47662
48108
  };
47663
48109
  await this.bus.send(envelope);
47664
- log23.info(`Task delegated from ${fromAgentId} to ${targetId}`, {
48110
+ log24.info(`Task delegated from ${fromAgentId} to ${targetId}`, {
47665
48111
  taskId: delegation.taskId,
47666
48112
  title: delegation.title
47667
48113
  });
@@ -47700,7 +48146,7 @@ var init_delegation = __esm({
47700
48146
  }
47701
48147
  async handleDelegation(envelope) {
47702
48148
  const delegation = envelope.payload;
47703
- log23.info(`Received task delegation: ${delegation.title}`, {
48149
+ log24.info(`Received task delegation: ${delegation.title}`, {
47704
48150
  from: envelope.from,
47705
48151
  to: envelope.to,
47706
48152
  taskId: delegation.taskId
@@ -47711,14 +48157,14 @@ var init_delegation = __esm({
47711
48157
  }
47712
48158
  async handleUpdate(envelope) {
47713
48159
  const update2 = envelope.payload;
47714
- log23.info(`Task update: ${update2.taskId} -> ${update2.status}`, {
48160
+ log24.info(`Task update: ${update2.taskId} -> ${update2.status}`, {
47715
48161
  from: envelope.from,
47716
48162
  progress: update2.progress
47717
48163
  });
47718
48164
  }
47719
48165
  async handleComplete(envelope) {
47720
48166
  const update2 = envelope.payload;
47721
- log23.info(`Task completed: ${update2.taskId}`, {
48167
+ log24.info(`Task completed: ${update2.taskId}`, {
47722
48168
  from: envelope.from,
47723
48169
  to: envelope.to
47724
48170
  });
@@ -47728,22 +48174,22 @@ var init_delegation = __esm({
47728
48174
  });
47729
48175
 
47730
48176
  // ../a2a/dist/collaboration.js
47731
- var log24;
48177
+ var log25;
47732
48178
  var init_collaboration = __esm({
47733
48179
  "../a2a/dist/collaboration.js"() {
47734
48180
  "use strict";
47735
48181
  init_dist();
47736
- log24 = createLogger("a2a-collaboration");
48182
+ log25 = createLogger("a2a-collaboration");
47737
48183
  }
47738
48184
  });
47739
48185
 
47740
48186
  // ../a2a/dist/structured.js
47741
- var log25;
48187
+ var log26;
47742
48188
  var init_structured = __esm({
47743
48189
  "../a2a/dist/structured.js"() {
47744
48190
  "use strict";
47745
48191
  init_dist();
47746
- log25 = createLogger("a2a-structured");
48192
+ log26 = createLogger("a2a-structured");
47747
48193
  }
47748
48194
  });
47749
48195
 
@@ -47771,7 +48217,7 @@ function resolveCurrentTaskId(agentObj, ts, agentId2) {
47771
48217
  const currentTask = ts.getTask(currentId);
47772
48218
  if (currentTask?.status === "in_progress")
47773
48219
  return currentId;
47774
- log26.warn("Agent currentTaskId is no longer in_progress, searching activeTasks for a valid candidate", {
48220
+ log27.warn("Agent currentTaskId is no longer in_progress, searching activeTasks for a valid candidate", {
47775
48221
  agentId: agentId2,
47776
48222
  currentTaskId: currentId,
47777
48223
  actualStatus: currentTask?.status
@@ -47785,13 +48231,13 @@ function resolveCurrentTaskId(agentObj, ts, agentId2) {
47785
48231
  for (const t of activeTasks) {
47786
48232
  const task = ts.getTask(t.taskId);
47787
48233
  if (task && ["completed", "failed", "cancelled", "archived"].includes(task.status)) {
47788
- log26.warn("Removing stale task from agent activeTasks", { agentId: agentId2, taskId: t.taskId, status: task.status });
48234
+ log27.warn("Removing stale task from agent activeTasks", { agentId: agentId2, taskId: t.taskId, status: task.status });
47789
48235
  agentObj?.removeActiveTask(t.taskId);
47790
48236
  }
47791
48237
  }
47792
48238
  throw new Error(`No in_progress task found for agent ${agentId2} \u2014 cannot submit for review. Active task IDs: [${activeTasks.map((t) => t.taskId).join(", ")}]`);
47793
48239
  }
47794
- var log26, AgentManager;
48240
+ var log27, AgentManager;
47795
48241
  var init_agent_manager = __esm({
47796
48242
  "../core/dist/agent-manager.js"() {
47797
48243
  "use strict";
@@ -47811,7 +48257,7 @@ var init_agent_manager = __esm({
47811
48257
  init_semantic_search();
47812
48258
  init_security();
47813
48259
  init_dist3();
47814
- log26 = createLogger("agent-manager");
48260
+ log27 = createLogger("agent-manager");
47815
48261
  AgentManager = class _AgentManager {
47816
48262
  agents = /* @__PURE__ */ new Map();
47817
48263
  eventBus;
@@ -47840,6 +48286,7 @@ var init_agent_manager = __esm({
47840
48286
  activityCallbacks;
47841
48287
  a2aBus;
47842
48288
  delegationManager;
48289
+ _maxToolIterations = 200;
47843
48290
  templateRegistry;
47844
48291
  groupChatHandlers;
47845
48292
  buildKnowledgeCallbacks(agentId2, orgId2) {
@@ -47954,11 +48401,11 @@ var init_agent_manager = __esm({
47954
48401
  this.semanticSearch = new SemanticMemorySearch(embeddingProvider, vectorStore);
47955
48402
  this.semanticSearch.initialize().then((ok) => {
47956
48403
  if (ok)
47957
- log26.info("Semantic memory search initialized (LocalVectorStore)");
48404
+ log27.info("Semantic memory search initialized (LocalVectorStore)");
47958
48405
  else
47959
- log26.warn("Semantic memory search initialization failed");
48406
+ log27.warn("Semantic memory search initialization failed");
47960
48407
  }).catch((err) => {
47961
- log26.warn("Semantic memory search init error", { error: String(err) });
48408
+ log27.warn("Semantic memory search init error", { error: String(err) });
47962
48409
  });
47963
48410
  }
47964
48411
  this.a2aBus = new A2ABus();
@@ -47966,7 +48413,7 @@ var init_agent_manager = __esm({
47966
48413
  this.delegationManager.onDelegationReceived(async (envelope, delegation) => {
47967
48414
  const targetAgent = this.agents.get(envelope.to);
47968
48415
  if (!targetAgent) {
47969
- log26.warn("Delegation target agent not found", { to: envelope.to });
48416
+ log27.warn("Delegation target agent not found", { to: envelope.to });
47970
48417
  return;
47971
48418
  }
47972
48419
  if (this.taskService) {
@@ -47980,7 +48427,7 @@ var init_agent_manager = __esm({
47980
48427
  createdBy: envelope.from,
47981
48428
  creatorRole: "manager"
47982
48429
  });
47983
- log26.info("Delegation created real task", {
48430
+ log27.info("Delegation created real task", {
47984
48431
  taskId: task.id,
47985
48432
  delegatedTo: envelope.to,
47986
48433
  from: envelope.from,
@@ -47996,6 +48443,12 @@ Priority: ${delegation.priority}`, envelope.from, { name: envelope.from, role: "
47996
48443
  this.templateRegistry = options.templateRegistry;
47997
48444
  mkdirSync9(this.dataDir, { recursive: true });
47998
48445
  }
48446
+ get maxToolIterations() {
48447
+ return this._maxToolIterations;
48448
+ }
48449
+ set maxToolIterations(value) {
48450
+ this._maxToolIterations = Math.max(1, Math.min(value, 1e4));
48451
+ }
47999
48452
  setTaskService(taskService) {
48000
48453
  this.taskService = taskService;
48001
48454
  }
@@ -48117,7 +48570,8 @@ Priority: ${delegation.priority}`, envelope.from, { name: envelope.from, role: "
48117
48570
  tools,
48118
48571
  orgContext: request.orgContext,
48119
48572
  pathPolicy,
48120
- skillRegistry: this.skillRegistry
48573
+ skillRegistry: this.skillRegistry,
48574
+ maxToolIterations: this._maxToolIterations
48121
48575
  };
48122
48576
  const agent = new Agent(agentOpts);
48123
48577
  if (this.skillRegistry) {
@@ -48126,14 +48580,14 @@ Priority: ${delegation.priority}`, envelope.from, { name: envelope.from, role: "
48126
48580
  agent.injectSkillInstructions(skillName, instructions);
48127
48581
  }
48128
48582
  if (builtinInstructions.size > 0) {
48129
- log26.info(`Always-on builtin skills injected for agent ${id}`, { skills: [...builtinInstructions.keys()] });
48583
+ log27.info(`Always-on builtin skills injected for agent ${id}`, { skills: [...builtinInstructions.keys()] });
48130
48584
  }
48131
48585
  agent.setAvailableSkillCatalog(this.skillRegistry.getBuiltinSkillCatalog());
48132
48586
  }
48133
48587
  if (this.skillRegistry && config.skills.length > 0) {
48134
48588
  const missingSkills = config.skills.filter((s) => !this.skillRegistry.get(s));
48135
48589
  if (missingSkills.length > 0) {
48136
- log26.warn(`Agent ${config.name} (${id}) references skills not found in registry`, {
48590
+ log27.warn(`Agent ${config.name} (${id}) references skills not found in registry`, {
48137
48591
  missing: missingSkills,
48138
48592
  available: this.skillRegistry.list().map((s) => s.name)
48139
48593
  });
@@ -48165,12 +48619,12 @@ Priority: ${delegation.priority}`, envelope.from, { name: envelope.from, role: "
48165
48619
  toolNames.push(tool.name);
48166
48620
  }
48167
48621
  agent.activateTools(toolNames);
48168
- log26.info(`Skill ${skillName} MCP server ${serverName} connected for agent ${id}`, {
48622
+ log27.info(`Skill ${skillName} MCP server ${serverName} connected for agent ${id}`, {
48169
48623
  toolCount: mcpTools.length,
48170
48624
  isolated
48171
48625
  });
48172
48626
  } catch (error) {
48173
- log26.warn(`Failed to connect skill ${skillName} MCP server ${serverName} for agent ${id}`, {
48627
+ log27.warn(`Failed to connect skill ${skillName} MCP server ${serverName} for agent ${id}`, {
48174
48628
  error: String(error)
48175
48629
  });
48176
48630
  }
@@ -48401,7 +48855,7 @@ Known issues: ${knownIssues}` : ""}`
48401
48855
  return [];
48402
48856
  }
48403
48857
  });
48404
- log26.info(`Task tools injected for agent ${id}`);
48858
+ log27.info(`Task tools injected for agent ${id}`);
48405
48859
  }
48406
48860
  if (this.projectService) {
48407
48861
  for (const tool of createProjectTools({
@@ -48415,8 +48869,10 @@ Known issues: ${knownIssues}` : ""}`
48415
48869
  }
48416
48870
  }
48417
48871
  if (request.agentRole === "manager") {
48872
+ const myTeamId = config.teamId;
48873
+ const filterByTeam = (list2) => myTeamId ? list2.filter((a) => a.teamId === myTeamId) : list2;
48418
48874
  const managerTools = createManagerTools({
48419
- listAgents: () => this.listAgents().map((a) => {
48875
+ listAgents: () => filterByTeam(this.listAgents()).map((a) => {
48420
48876
  try {
48421
48877
  const ag = this.getAgent(a.id);
48422
48878
  return { ...a, skills: ag.config.skills };
@@ -48429,7 +48885,7 @@ Known issues: ${knownIssues}` : ""}`
48429
48885
  const reply = await target.handleMessage(message, id, { name: config.name, role: "manager" });
48430
48886
  return stripInternalBlocks(reply);
48431
48887
  },
48432
- getTeamStatus: () => this.listAgents().map((a) => {
48888
+ getTeamStatus: () => filterByTeam(this.listAgents()).map((a) => {
48433
48889
  try {
48434
48890
  const ag = this.getAgent(a.id);
48435
48891
  const state = ag.getState();
@@ -48459,11 +48915,11 @@ Known issues: ${knownIssues}` : ""}`
48459
48915
  for (const tool of mcpTools) {
48460
48916
  agent.registerTool(tool);
48461
48917
  }
48462
- log26.info(`MCP server ${serverName} tools registered for agent ${id}`, {
48918
+ log27.info(`MCP server ${serverName} tools registered for agent ${id}`, {
48463
48919
  toolCount: mcpTools.length
48464
48920
  });
48465
48921
  } catch (error) {
48466
- log26.warn(`Failed to connect MCP server ${serverName} for agent ${id}`, {
48922
+ log27.warn(`Failed to connect MCP server ${serverName} for agent ${id}`, {
48467
48923
  error: String(error)
48468
48924
  });
48469
48925
  }
@@ -48499,7 +48955,7 @@ Known issues: ${knownIssues}` : ""}`
48499
48955
  status: "idle"
48500
48956
  });
48501
48957
  this.eventBus.emit("agent:created", { agentId: id, name: request.name });
48502
- log26.info(`Agent created: ${request.name} (${id})`);
48958
+ log27.info(`Agent created: ${request.name} (${id})`);
48503
48959
  return agent;
48504
48960
  }
48505
48961
  /**
@@ -48604,7 +49060,8 @@ Known issues: ${knownIssues}` : ""}`
48604
49060
  tools,
48605
49061
  pathPolicy,
48606
49062
  restoredState: { tokensUsedToday: row.tokensUsedToday ?? 0 },
48607
- skillRegistry: this.skillRegistry
49063
+ skillRegistry: this.skillRegistry,
49064
+ maxToolIterations: this._maxToolIterations
48608
49065
  });
48609
49066
  if (this.skillRegistry) {
48610
49067
  const builtinInstructions = this.skillRegistry.getBuiltinInstructions();
@@ -48616,7 +49073,7 @@ Known issues: ${knownIssues}` : ""}`
48616
49073
  if (this.skillRegistry && config.skills.length > 0) {
48617
49074
  const missingSkills = config.skills.filter((s) => !this.skillRegistry.get(s));
48618
49075
  if (missingSkills.length > 0) {
48619
- log26.warn(`Restored agent ${config.name} (${id}) references skills not found in registry`, {
49076
+ log27.warn(`Restored agent ${config.name} (${id}) references skills not found in registry`, {
48620
49077
  missing: missingSkills,
48621
49078
  available: this.skillRegistry.list().map((s) => s.name)
48622
49079
  });
@@ -48648,12 +49105,12 @@ Known issues: ${knownIssues}` : ""}`
48648
49105
  toolNames.push(tool.name);
48649
49106
  }
48650
49107
  agent.activateTools(toolNames);
48651
- log26.info(`Skill ${skillName} MCP server ${serverName} restored for agent ${id}`, {
49108
+ log27.info(`Skill ${skillName} MCP server ${serverName} restored for agent ${id}`, {
48652
49109
  toolCount: mcpTools.length,
48653
49110
  isolated
48654
49111
  });
48655
49112
  } catch (error) {
48656
- log26.warn(`Failed to restore skill ${skillName} MCP server ${serverName} for agent ${id}`, {
49113
+ log27.warn(`Failed to restore skill ${skillName} MCP server ${serverName} for agent ${id}`, {
48657
49114
  error: String(error)
48658
49115
  });
48659
49116
  }
@@ -48866,8 +49323,10 @@ Known issues: ${knownIssues}` : ""}`
48866
49323
  }
48867
49324
  }
48868
49325
  if (config.agentRole === "manager") {
49326
+ const restoredTeamId = config.teamId;
49327
+ const filterByTeamRestored = (list2) => restoredTeamId ? list2.filter((a) => a.teamId === restoredTeamId) : list2;
48869
49328
  const managerTools = createManagerTools({
48870
- listAgents: () => this.listAgents().map((a) => {
49329
+ listAgents: () => filterByTeamRestored(this.listAgents()).map((a) => {
48871
49330
  try {
48872
49331
  const ag = this.getAgent(a.id);
48873
49332
  return { ...a, skills: ag.config.skills };
@@ -48880,7 +49339,7 @@ Known issues: ${knownIssues}` : ""}`
48880
49339
  const reply = await target.handleMessage(message, id, { name: config.name, role: "manager" });
48881
49340
  return stripInternalBlocks(reply);
48882
49341
  },
48883
- getTeamStatus: () => this.listAgents().map((a) => {
49342
+ getTeamStatus: () => filterByTeamRestored(this.listAgents()).map((a) => {
48884
49343
  try {
48885
49344
  const ag = this.getAgent(a.id);
48886
49345
  const state = ag.getState();
@@ -48930,7 +49389,7 @@ Known issues: ${knownIssues}` : ""}`
48930
49389
  status: "idle"
48931
49390
  });
48932
49391
  this.eventBus.emit("agent:created", { agentId: id, name: row.name });
48933
- log26.info(`Agent restored: ${row.name} (${id})`, {
49392
+ log27.info(`Agent restored: ${row.name} (${id})`, {
48934
49393
  profile: config.profile ? "yes" : "no",
48935
49394
  tokensUsedToday: row.tokensUsedToday ?? 0,
48936
49395
  activeTaskIds: Array.isArray(row.activeTaskIds) ? row.activeTaskIds.length : 0
@@ -48951,21 +49410,21 @@ Known issues: ${knownIssues}` : ""}`
48951
49410
  try {
48952
49411
  const task = this.taskService.getTask(taskId2);
48953
49412
  if (!task) {
48954
- log26.warn("Task not found during rehydration, skipping", { agentId: agentId2, taskId: taskId2 });
49413
+ log27.warn("Task not found during rehydration, skipping", { agentId: agentId2, taskId: taskId2 });
48955
49414
  continue;
48956
49415
  }
48957
49416
  if (task.status === "completed" || task.status === "cancelled" || task.status === "failed") {
48958
- log26.debug("Task already terminal, skipping rehydration", {
49417
+ log27.debug("Task already terminal, skipping rehydration", {
48959
49418
  agentId: agentId2,
48960
49419
  taskId: taskId2,
48961
49420
  status: task.status
48962
49421
  });
48963
49422
  continue;
48964
49423
  }
48965
- log26.info("Re-queuing interrupted task", { agentId: agentId2, taskId: taskId2, title: task.title });
49424
+ log27.info("Re-queuing interrupted task", { agentId: agentId2, taskId: taskId2, title: task.title });
48966
49425
  this.taskService.assignTask(taskId2, agentId2);
48967
49426
  } catch (error) {
48968
- log26.warn("Failed to rehydrate task", { agentId: agentId2, taskId: taskId2, error: String(error) });
49427
+ log27.warn("Failed to rehydrate task", { agentId: agentId2, taskId: taskId2, error: String(error) });
48969
49428
  }
48970
49429
  }
48971
49430
  }
@@ -48996,13 +49455,13 @@ Known issues: ${knownIssues}` : ""}`
48996
49455
  if (existsSync15(agentDir)) {
48997
49456
  try {
48998
49457
  rmSync(agentDir, { recursive: true, force: true });
48999
- log26.info(`Agent data directory purged: ${agentDir}`);
49458
+ log27.info(`Agent data directory purged: ${agentDir}`);
49000
49459
  } catch (err) {
49001
- log26.warn("Failed to purge agent data directory", { agentId: agentId2, error: String(err) });
49460
+ log27.warn("Failed to purge agent data directory", { agentId: agentId2, error: String(err) });
49002
49461
  }
49003
49462
  }
49004
49463
  }
49005
- log26.info(`Agent removed: ${agentId2}`, { purgeFiles: !!opts?.purgeFiles });
49464
+ log27.info(`Agent removed: ${agentId2}`, { purgeFiles: !!opts?.purgeFiles });
49006
49465
  }
49007
49466
  /** Remove orphaned agent directories that have no matching DB record */
49008
49467
  purgeOrphanedAgentDirs(knownAgentIds) {
@@ -49024,7 +49483,7 @@ Known issues: ${knownIssues}` : ""}`
49024
49483
  }
49025
49484
  }
49026
49485
  if (removed.length > 0)
49027
- log26.info(`Purged ${removed.length} orphaned agent directories`);
49486
+ log27.info(`Purged ${removed.length} orphaned agent directories`);
49028
49487
  return { removed, failed };
49029
49488
  }
49030
49489
  getAgent(agentId2) {
@@ -49045,7 +49504,7 @@ Known issues: ${knownIssues}` : ""}`
49045
49504
  return;
49046
49505
  const reviewer = this.getAgent(reviewerAgentId);
49047
49506
  reviewer.grantReadOnlyAccess(worktreePath);
49048
- log26.info("Granted reviewer access to worktree", { reviewerAgentId, worktreePath });
49507
+ log27.info("Granted reviewer access to worktree", { reviewerAgentId, worktreePath });
49049
49508
  }
49050
49509
  /**
49051
49510
  * Revoke a reviewer agent's read-only access to a task's worktree.
@@ -49056,7 +49515,7 @@ Known issues: ${knownIssues}` : ""}`
49056
49515
  return;
49057
49516
  const reviewer = this.getAgent(reviewerAgentId);
49058
49517
  reviewer.revokeReadOnlyAccess(worktreePath);
49059
- log26.info("Revoked reviewer access to worktree", { reviewerAgentId, worktreePath });
49518
+ log27.info("Revoked reviewer access to worktree", { reviewerAgentId, worktreePath });
49060
49519
  }
49061
49520
  setAuditCallback(cb) {
49062
49521
  this.agentAuditCallback = cb;
@@ -49219,7 +49678,7 @@ Known issues: ${knownIssues}` : ""}`
49219
49678
  }
49220
49679
  this.globalPaused = true;
49221
49680
  this.eventBus.emit("system:pause-all", { reason });
49222
- log26.info("All agents paused", { reason });
49681
+ log27.info("All agents paused", { reason });
49223
49682
  }
49224
49683
  async resumeAllAgents() {
49225
49684
  for (const [, agent] of this.agents) {
@@ -49230,7 +49689,7 @@ Known issues: ${knownIssues}` : ""}`
49230
49689
  this.globalPaused = false;
49231
49690
  this.emergencyMode = false;
49232
49691
  this.eventBus.emit("system:resume-all", {});
49233
- log26.info("All agents resumed");
49692
+ log27.info("All agents resumed");
49234
49693
  }
49235
49694
  async emergencyStop() {
49236
49695
  for (const [, agent] of this.agents) {
@@ -49240,7 +49699,7 @@ Known issues: ${knownIssues}` : ""}`
49240
49699
  this.emergencyMode = true;
49241
49700
  this.globalPaused = true;
49242
49701
  this.eventBus.emit("system:emergency-stop", {});
49243
- log26.warn("EMERGENCY STOP \u2014 all agents stopped");
49702
+ log27.warn("EMERGENCY STOP \u2014 all agents stopped");
49244
49703
  }
49245
49704
  isGlobalPaused() {
49246
49705
  return this.globalPaused;
@@ -49251,7 +49710,7 @@ Known issues: ${knownIssues}` : ""}`
49251
49710
  clearEmergencyMode() {
49252
49711
  this.emergencyMode = false;
49253
49712
  this.globalPaused = false;
49254
- log26.info("Emergency mode cleared");
49713
+ log27.info("Emergency mode cleared");
49255
49714
  }
49256
49715
  async shutdown() {
49257
49716
  for (const [, agent] of this.agents) {
@@ -49260,7 +49719,7 @@ Known issues: ${knownIssues}` : ""}`
49260
49719
  } catch {
49261
49720
  }
49262
49721
  }
49263
- log26.info("AgentManager shutdown complete \u2014 all metrics flushed");
49722
+ log27.info("AgentManager shutdown complete \u2014 all metrics flushed");
49264
49723
  }
49265
49724
  // ─── Role Template Versioning & Sync ──────────────────────────────────────
49266
49725
  static ROLE_FILES = ["ROLE.md", "HEARTBEAT.md", "POLICIES.md", "CONTEXT.md"];
@@ -49351,7 +49810,7 @@ Known issues: ${knownIssues}` : ""}`
49351
49810
  }
49352
49811
  }
49353
49812
  agent.reloadRole();
49354
- log26.info("Synced agent role from template", { agentId: agentId2, roleId, synced });
49813
+ log27.info("Synced agent role from template", { agentId: agentId2, roleId, synced });
49355
49814
  return { agentId: agentId2, success: true, synced };
49356
49815
  }
49357
49816
  checkAllRoleUpdates() {
@@ -49381,7 +49840,7 @@ Known issues: ${knownIssues}` : ""}`
49381
49840
  }
49382
49841
  }
49383
49842
  this.eventBus.emit("system:announcement", announcement);
49384
- log26.info("Announcement broadcast", { id: announcement.id, title: announcement.title });
49843
+ log27.info("Announcement broadcast", { id: announcement.id, title: announcement.title });
49385
49844
  }
49386
49845
  getActiveAnnouncements() {
49387
49846
  const now2 = (/* @__PURE__ */ new Date()).toISOString();
@@ -49395,13 +49854,20 @@ Known issues: ${knownIssues}` : ""}`
49395
49854
  }
49396
49855
  /**
49397
49856
  * Rebuild and inject identity context for all agents in an organization.
49398
- * Should be called after agents are added/removed or humans join/leave.
49857
+ * Colleagues are scoped to the agent's own team; other teams are listed for cross-team awareness.
49399
49858
  */
49400
- refreshIdentityContexts(orgId2, orgName, humans) {
49859
+ refreshIdentityContexts(orgId2, orgName, humans, teams2) {
49401
49860
  const orgAgents = [...this.agents.values()].filter((a) => a.config.orgId === orgId2);
49402
- const managerAgent = orgAgents.find((a) => a.config.agentRole === "manager");
49861
+ const agentTeamMap = /* @__PURE__ */ new Map();
49862
+ for (const t of teams2 ?? []) {
49863
+ for (const aid of t.memberAgentIds)
49864
+ agentTeamMap.set(aid, t.id);
49865
+ }
49403
49866
  for (const agent of orgAgents) {
49404
- const colleagues = orgAgents.filter((a) => a.id !== agent.id).map((a) => ({
49867
+ const myTeamId = agent.config.teamId ?? agentTeamMap.get(agent.id);
49868
+ const myTeam = teams2?.find((t) => t.id === myTeamId);
49869
+ const sameTeamAgents = myTeamId ? orgAgents.filter((a) => a.id !== agent.id && (a.config.teamId === myTeamId || agentTeamMap.get(a.id) === myTeamId)) : orgAgents.filter((a) => a.id !== agent.id);
49870
+ const colleagues = sameTeamAgents.map((a) => ({
49405
49871
  id: a.id,
49406
49872
  name: a.config.name,
49407
49873
  role: a.role.name,
@@ -49409,6 +49875,19 @@ Known issues: ${knownIssues}` : ""}`
49409
49875
  skills: a.config.skills,
49410
49876
  status: a.getState().status
49411
49877
  }));
49878
+ const teamManager = sameTeamAgents.find((a) => a.config.agentRole === "manager");
49879
+ const otherTeams = (teams2 ?? []).filter((t) => t.id !== myTeamId).map((t) => ({
49880
+ id: t.id,
49881
+ name: t.name,
49882
+ members: t.memberAgentIds.map((aid) => {
49883
+ try {
49884
+ const a = this.getAgent(aid);
49885
+ return { id: a.id, name: a.config.name, role: a.role.name };
49886
+ } catch {
49887
+ return null;
49888
+ }
49889
+ }).filter((m) => m !== null)
49890
+ })).filter((t) => t.members.length > 0);
49412
49891
  const identity = {
49413
49892
  self: {
49414
49893
  id: agent.id,
@@ -49418,13 +49897,15 @@ Known issues: ${knownIssues}` : ""}`
49418
49897
  skills: agent.config.skills
49419
49898
  },
49420
49899
  organization: { id: orgId2, name: orgName },
49900
+ team: myTeam ? { id: myTeam.id, name: myTeam.name, description: myTeam.description } : void 0,
49421
49901
  colleagues,
49902
+ otherTeams: otherTeams.length > 0 ? otherTeams : void 0,
49422
49903
  humans: humans.map((h) => ({ id: h.id, name: h.name, role: h.role })),
49423
- manager: managerAgent && managerAgent.id !== agent.id ? { id: managerAgent.id, name: managerAgent.config.name } : void 0
49904
+ manager: teamManager && teamManager.id !== agent.id ? { id: teamManager.id, name: teamManager.config.name } : void 0
49424
49905
  };
49425
49906
  agent.setIdentityContext(identity);
49426
49907
  }
49427
- log26.info(`Refreshed identity contexts for ${orgAgents.length} agents in org ${orgId2}`);
49908
+ log27.info(`Refreshed identity contexts for ${orgAgents.length} agents in org ${orgId2}`);
49428
49909
  }
49429
49910
  };
49430
49911
  }
@@ -50484,12 +50965,12 @@ var init_ollama = __esm({
50484
50965
  import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, existsSync as existsSync16, unlinkSync as unlinkSync2 } from "node:fs";
50485
50966
  import { join as join10 } from "node:path";
50486
50967
  import { homedir as homedir5 } from "node:os";
50487
- var log27, AuthProfileStore;
50968
+ var log28, AuthProfileStore;
50488
50969
  var init_auth_profiles = __esm({
50489
50970
  "../core/dist/llm/auth-profiles.js"() {
50490
50971
  "use strict";
50491
50972
  init_dist();
50492
- log27 = createLogger("auth-profiles");
50973
+ log28 = createLogger("auth-profiles");
50493
50974
  AuthProfileStore = class {
50494
50975
  filePath;
50495
50976
  lockPath;
@@ -50507,7 +50988,7 @@ var init_auth_profiles = __esm({
50507
50988
  const raw = readFileSync13(this.filePath, "utf-8");
50508
50989
  return JSON.parse(raw);
50509
50990
  } catch (err) {
50510
- log27.warn("Failed to read auth-profiles.json, starting fresh", { error: String(err) });
50991
+ log28.warn("Failed to read auth-profiles.json, starting fresh", { error: String(err) });
50511
50992
  return { version: 1, profiles: [] };
50512
50993
  }
50513
50994
  }
@@ -50543,7 +51024,7 @@ var init_auth_profiles = __esm({
50543
51024
  }
50544
51025
  } catch {
50545
51026
  }
50546
- log27.debug("Auth profile lock contention, proceeding without lock");
51027
+ log28.debug("Auth profile lock contention, proceeding without lock");
50547
51028
  return () => {
50548
51029
  };
50549
51030
  }
@@ -50571,7 +51052,7 @@ var init_auth_profiles = __esm({
50571
51052
  data.profiles.push({ ...profile, createdAt: Date.now(), updatedAt: Date.now() });
50572
51053
  }
50573
51054
  this.write(data);
50574
- log27.info(`Upserted auth profile: ${profile.id} (${profile.provider}/${profile.authType})`);
51055
+ log28.info(`Upserted auth profile: ${profile.id} (${profile.provider}/${profile.authType})`);
50575
51056
  } finally {
50576
51057
  release2();
50577
51058
  }
@@ -50582,13 +51063,13 @@ var init_auth_profiles = __esm({
50582
51063
  const data = this.read();
50583
51064
  const profile = data.profiles.find((p) => p.id === profileId);
50584
51065
  if (!profile) {
50585
- log27.warn(`Profile not found for token update: ${profileId}`);
51066
+ log28.warn(`Profile not found for token update: ${profileId}`);
50586
51067
  return;
50587
51068
  }
50588
51069
  profile.oauth = tokens;
50589
51070
  profile.updatedAt = Date.now();
50590
51071
  this.write(data);
50591
- log27.debug(`Updated OAuth tokens for profile: ${profileId}`);
51072
+ log28.debug(`Updated OAuth tokens for profile: ${profileId}`);
50592
51073
  } finally {
50593
51074
  release2();
50594
51075
  }
@@ -50601,7 +51082,7 @@ var init_auth_profiles = __esm({
50601
51082
  data.profiles = data.profiles.filter((p) => p.id !== id);
50602
51083
  if (data.profiles.length < before2) {
50603
51084
  this.write(data);
50604
- log27.info(`Deleted auth profile: ${id}`);
51085
+ log28.info(`Deleted auth profile: ${id}`);
50605
51086
  return true;
50606
51087
  }
50607
51088
  return false;
@@ -50702,12 +51183,12 @@ function callbackHtml(title, message, success2) {
50702
51183
  <p>${message}</p>
50703
51184
  </div></body></html>`;
50704
51185
  }
50705
- var log28, KNOWN_OAUTH_PROVIDERS, OAuthManager;
51186
+ var log29, KNOWN_OAUTH_PROVIDERS, OAuthManager;
50706
51187
  var init_oauth_manager = __esm({
50707
51188
  "../core/dist/llm/oauth-manager.js"() {
50708
51189
  "use strict";
50709
51190
  init_dist();
50710
- log28 = createLogger("oauth-manager");
51191
+ log29 = createLogger("oauth-manager");
50711
51192
  KNOWN_OAUTH_PROVIDERS = {
50712
51193
  "openai-codex": {
50713
51194
  authorizeUrl: "https://auth.openai.com/oauth/authorize",
@@ -50726,7 +51207,7 @@ var init_oauth_manager = __esm({
50726
51207
  }
50727
51208
  registerProvider(name, config) {
50728
51209
  this.customProviders.set(name, config);
50729
- log28.info(`Registered custom OAuth provider: ${name}`);
51210
+ log29.info(`Registered custom OAuth provider: ${name}`);
50730
51211
  }
50731
51212
  getProviderConfig(provider) {
50732
51213
  return this.customProviders.get(provider) ?? KNOWN_OAUTH_PROVIDERS[provider];
@@ -50805,10 +51286,10 @@ var init_oauth_manager = __esm({
50805
51286
  });
50806
51287
  pending.server = server;
50807
51288
  server.listen(port, "localhost", () => {
50808
- log28.info(`OAuth callback server listening on localhost:${port} for ${provider}`);
51289
+ log29.info(`OAuth callback server listening on localhost:${port} for ${provider}`);
50809
51290
  });
50810
51291
  server.on("error", (err) => {
50811
- log28.error(`Failed to start OAuth callback server on port ${port}`, { error: String(err) });
51292
+ log29.error(`Failed to start OAuth callback server on port ${port}`, { error: String(err) });
50812
51293
  this.cleanupPending(state);
50813
51294
  reject(new Error(`Cannot start callback server: ${err.message}. Port ${port} may be in use.`));
50814
51295
  });
@@ -50873,7 +51354,7 @@ var init_oauth_manager = __esm({
50873
51354
  expiresAt: Date.now() + (data.expires_in ?? 3600) * 1e3,
50874
51355
  accountId: extractAccountId(data.access_token)
50875
51356
  };
50876
- log28.info(`OAuth token exchange successful for ${provider}`, { accountId: tokens.accountId });
51357
+ log29.info(`OAuth token exchange successful for ${provider}`, { accountId: tokens.accountId });
50877
51358
  return tokens;
50878
51359
  }
50879
51360
  /**
@@ -50910,7 +51391,7 @@ var init_oauth_manager = __esm({
50910
51391
  accountId: profile.oauth.accountId ?? extractAccountId(data.access_token)
50911
51392
  };
50912
51393
  this.profileStore.updateOAuthTokens(profileId, newTokens);
50913
- log28.info(`Refreshed OAuth token for profile ${profileId}`);
51394
+ log29.info(`Refreshed OAuth token for profile ${profileId}`);
50914
51395
  return newTokens.accessToken;
50915
51396
  }
50916
51397
  /**
@@ -50931,7 +51412,7 @@ var init_oauth_manager = __esm({
50931
51412
  return profile.oauth.accessToken;
50932
51413
  }
50933
51414
  if (profile.oauth.refreshToken) {
50934
- log28.debug(`Token expiring soon for ${profileId}, refreshing...`);
51415
+ log29.debug(`Token expiring soon for ${profileId}, refreshing...`);
50935
51416
  return this.refreshToken(profileId);
50936
51417
  }
50937
51418
  if (profile.oauth.expiresAt > Date.now()) {
@@ -50976,7 +51457,7 @@ var init_oauth_manager = __esm({
50976
51457
  clearTimeout(pending.timeoutHandle);
50977
51458
  if (pending.server) {
50978
51459
  pending.server.close(() => {
50979
- log28.debug(`Closed OAuth callback server for state ${state.slice(0, 8)}...`);
51460
+ log29.debug(`Closed OAuth callback server for state ${state.slice(0, 8)}...`);
50980
51461
  });
50981
51462
  }
50982
51463
  this.pendingLogins.delete(state);
@@ -51009,7 +51490,7 @@ function buildTiers(providerNames, defaultProvider) {
51009
51490
  }
51010
51491
  return tiers;
51011
51492
  }
51012
- var log29, ALL_COMPLEXITY, LLMRouter, PROVIDER_DISPLAY_NAMES, BUILTIN_MODEL_CATALOG;
51493
+ var log30, ALL_COMPLEXITY, LLMRouter, PROVIDER_DISPLAY_NAMES, BUILTIN_MODEL_CATALOG;
51013
51494
  var init_router = __esm({
51014
51495
  "../core/dist/llm/router.js"() {
51015
51496
  "use strict";
@@ -51021,7 +51502,7 @@ var init_router = __esm({
51021
51502
  init_ollama();
51022
51503
  init_auth_profiles();
51023
51504
  init_oauth_manager();
51024
- log29 = createLogger("llm-router");
51505
+ log30 = createLogger("llm-router");
51025
51506
  ALL_COMPLEXITY = ["simple", "moderate", "complex"];
51026
51507
  LLMRouter = class _LLMRouter {
51027
51508
  providers = /* @__PURE__ */ new Map();
@@ -51078,7 +51559,7 @@ var init_router = __esm({
51078
51559
  };
51079
51560
  const provider = new OpenAIProvider({ ...providerConfig, provider: name }, async () => oauthMgr.getValidToken(profileId));
51080
51561
  this.registerProvider(name, provider);
51081
- log29.info(`Registered OAuth-backed provider: ${name}`, { profileId, model: providerConfig.model });
51562
+ log30.info(`Registered OAuth-backed provider: ${name}`, { profileId, model: providerConfig.model });
51082
51563
  }
51083
51564
  get defaultProviderName() {
51084
51565
  return this.defaultProvider;
@@ -51110,13 +51591,13 @@ var init_router = __esm({
51110
51591
  if (fatal && !h.degraded) {
51111
51592
  h.degraded = true;
51112
51593
  h.resetMs = this.CIRCUIT_RESET_FATAL_MS;
51113
- log29.warn(`Provider ${name} immediately degraded (non-retryable error) \u2014 skipping for ${this.CIRCUIT_RESET_FATAL_MS / 6e4} min`);
51594
+ log30.warn(`Provider ${name} immediately degraded (non-retryable error) \u2014 skipping for ${this.CIRCUIT_RESET_FATAL_MS / 6e4} min`);
51114
51595
  return;
51115
51596
  }
51116
51597
  if (h.consecutiveFailures >= this.CIRCUIT_OPEN_AFTER && !h.degraded) {
51117
51598
  h.degraded = true;
51118
51599
  h.resetMs = this.CIRCUIT_RESET_MS;
51119
- log29.warn(`Provider ${name} marked as degraded after ${h.consecutiveFailures} failures \u2014 skipping for ${this.CIRCUIT_RESET_MS / 6e4} min`);
51600
+ log30.warn(`Provider ${name} marked as degraded after ${h.consecutiveFailures} failures \u2014 skipping for ${this.CIRCUIT_RESET_MS / 6e4} min`);
51120
51601
  }
51121
51602
  }
51122
51603
  isAvailable(name) {
@@ -51127,7 +51608,7 @@ var init_router = __esm({
51127
51608
  return true;
51128
51609
  const resetMs = h.resetMs ?? this.CIRCUIT_RESET_MS;
51129
51610
  if (Date.now() - h.lastFailureAt > resetMs) {
51130
- log29.info(`Provider ${name} circuit reset \u2014 will retry`);
51611
+ log30.info(`Provider ${name} circuit reset \u2014 will retry`);
51131
51612
  h.degraded = false;
51132
51613
  h.consecutiveFailures = 0;
51133
51614
  return true;
@@ -51136,7 +51617,7 @@ var init_router = __esm({
51136
51617
  }
51137
51618
  registerProvider(name, provider) {
51138
51619
  this.providers.set(name, provider);
51139
- log29.info(`Registered LLM provider: ${name}`, { model: provider.model });
51620
+ log30.info(`Registered LLM provider: ${name}`, { model: provider.model });
51140
51621
  }
51141
51622
  enableAutoSelect(tiers) {
51142
51623
  this.autoSelect = true;
@@ -51170,15 +51651,15 @@ var init_router = __esm({
51170
51651
  const complexity = _LLMRouter.assessComplexity(request);
51171
51652
  const match = this.providerTiers.find((t) => t.complexity.includes(complexity) && this.providers.has(t.name) && this.isAvailable(t.name));
51172
51653
  if (match) {
51173
- log29.debug(`Auto-selected provider: ${match.name}`, { complexity });
51654
+ log30.debug(`Auto-selected provider: ${match.name}`, { complexity });
51174
51655
  return match.name;
51175
51656
  }
51176
51657
  const healthy = [...this.providers.keys()].find((n) => this.isAvailable(n));
51177
51658
  if (healthy) {
51178
- log29.warn(`All tiered providers degraded for complexity=${complexity}, falling back to: ${healthy}`);
51659
+ log30.warn(`All tiered providers degraded for complexity=${complexity}, falling back to: ${healthy}`);
51179
51660
  return healthy;
51180
51661
  }
51181
- log29.warn("All providers degraded \u2014 using default as last resort");
51662
+ log30.warn("All providers degraded \u2014 using default as last resort");
51182
51663
  return this.defaultProvider;
51183
51664
  }
51184
51665
  getFallbacks(primary) {
@@ -51228,7 +51709,7 @@ var init_router = __esm({
51228
51709
  timeoutMs: cfg?.timeoutMs
51229
51710
  });
51230
51711
  } catch (err) {
51231
- log29.warn(`Failed to auto-register OAuth provider ${providerName}`, { error: String(err) });
51712
+ log30.warn(`Failed to auto-register OAuth provider ${providerName}`, { error: String(err) });
51232
51713
  }
51233
51714
  }
51234
51715
  }
@@ -51241,7 +51722,7 @@ var init_router = __esm({
51241
51722
  ...providerNames.filter((n) => n !== effectiveDefault)
51242
51723
  ].filter((n) => providerNames.includes(n));
51243
51724
  router.setFallbackOrder(fallbackOrder);
51244
- log29.info("Auto-select enabled with fallback", { providers: providerNames, defaultProvider: effectiveDefault, fallbackOrder });
51725
+ log30.info("Auto-select enabled with fallback", { providers: providerNames, defaultProvider: effectiveDefault, fallbackOrder });
51245
51726
  }
51246
51727
  return router;
51247
51728
  }
@@ -51261,7 +51742,7 @@ var init_router = __esm({
51261
51742
  throw new Error(`LLM provider not found: ${primary}. Available: ${[...this.providers.keys()].join(", ")}`);
51262
51743
  }
51263
51744
  request = this.resolveMaxTokens(request, primary);
51264
- log29.debug(`Sending request to ${primary}`, { model: provider.model, messageCount: request.messages.length });
51745
+ log30.debug(`Sending request to ${primary}`, { model: provider.model, messageCount: request.messages.length });
51265
51746
  const span = startSpan("llm.chat", { provider: primary, model: provider.model });
51266
51747
  const startTime = Date.now();
51267
51748
  let lastError = null;
@@ -51269,27 +51750,27 @@ var init_router = __esm({
51269
51750
  const response = await provider.chat(request);
51270
51751
  this.recordSuccess(primary);
51271
51752
  span.end({ inputTokens: response.usage.inputTokens, outputTokens: response.usage.outputTokens, finishReason: response.finishReason });
51272
- log29.debug(`Response from ${primary}`, { tokens: response.usage, finishReason: response.finishReason });
51753
+ log30.debug(`Response from ${primary}`, { tokens: response.usage, finishReason: response.finishReason });
51273
51754
  this.emitLog(primary, provider.model, request, response, Date.now() - startTime);
51274
51755
  return response;
51275
51756
  } catch (error) {
51276
51757
  lastError = error;
51277
51758
  this.recordFailure(primary, error);
51278
- log29.error(`LLM request failed for ${primary}`, { error: String(error) });
51759
+ log30.error(`LLM request failed for ${primary}`, { error: String(error) });
51279
51760
  for (const fallbackName of this.getFallbacks(primary)) {
51280
51761
  const fb = this.providers.get(fallbackName);
51281
- log29.info(`Falling back to ${fallbackName}`, { model: fb.model });
51762
+ log30.info(`Falling back to ${fallbackName}`, { model: fb.model });
51282
51763
  try {
51283
51764
  const response = await fb.chat(request);
51284
51765
  this.recordSuccess(fallbackName);
51285
51766
  span.end({ inputTokens: response.usage.inputTokens, outputTokens: response.usage.outputTokens, finishReason: response.finishReason });
51286
- log29.info(`Fallback to ${fallbackName} succeeded`);
51767
+ log30.info(`Fallback to ${fallbackName} succeeded`);
51287
51768
  this.emitLog(fallbackName, fb.model, request, response, Date.now() - startTime);
51288
51769
  return response;
51289
51770
  } catch (fbError) {
51290
51771
  lastError = fbError;
51291
51772
  this.recordFailure(fallbackName, fbError);
51292
- log29.error(`Fallback ${fallbackName} also failed`, { error: String(fbError) });
51773
+ log30.error(`Fallback ${fallbackName} also failed`, { error: String(fbError) });
51293
51774
  }
51294
51775
  }
51295
51776
  span.setError(lastError instanceof Error ? lastError : String(lastError));
@@ -51307,7 +51788,7 @@ var init_router = __esm({
51307
51788
  const span = startSpan("llm.chatStream", { provider: primary, model: provider.model });
51308
51789
  const startTime = Date.now();
51309
51790
  if (!provider.chatStream) {
51310
- log29.debug(`Provider ${primary} does not support streaming, falling back to non-stream`);
51791
+ log30.debug(`Provider ${primary} does not support streaming, falling back to non-stream`);
51311
51792
  const response = await provider.chat(request);
51312
51793
  if (response.content)
51313
51794
  onEvent({ type: "text_delta", text: response.content });
@@ -51331,10 +51812,10 @@ var init_router = __esm({
51331
51812
  span.end();
51332
51813
  throw lastError;
51333
51814
  }
51334
- log29.error(`LLM stream request failed for ${primary}`, { error: String(error) });
51815
+ log30.error(`LLM stream request failed for ${primary}`, { error: String(error) });
51335
51816
  for (const fallbackName of this.getFallbacks(primary)) {
51336
51817
  const fb = this.providers.get(fallbackName);
51337
- log29.info(`Stream fallback to ${fallbackName}`);
51818
+ log30.info(`Stream fallback to ${fallbackName}`);
51338
51819
  try {
51339
51820
  let response;
51340
51821
  if (fb.chatStream) {
@@ -51348,14 +51829,14 @@ var init_router = __esm({
51348
51829
  this.recordSuccess(fallbackName);
51349
51830
  span.end({ inputTokens: response.usage.inputTokens, outputTokens: response.usage.outputTokens, finishReason: response.finishReason });
51350
51831
  this.emitLog(fallbackName, fb.model, request, response, Date.now() - startTime);
51351
- log29.info(`Stream fallback to ${fallbackName} succeeded`);
51832
+ log30.info(`Stream fallback to ${fallbackName} succeeded`);
51352
51833
  return response;
51353
51834
  } catch (fbError) {
51354
51835
  lastError = fbError;
51355
51836
  this.recordFailure(fallbackName, fbError);
51356
51837
  if (signal?.aborted)
51357
51838
  break;
51358
- log29.error(`Stream fallback ${fallbackName} failed`, { error: String(fbError) });
51839
+ log30.error(`Stream fallback ${fallbackName} failed`, { error: String(fbError) });
51359
51840
  }
51360
51841
  }
51361
51842
  span.setError(lastError instanceof Error ? lastError : String(lastError));
@@ -51382,7 +51863,7 @@ var init_router = __esm({
51382
51863
  throw new Error(`Cannot set default to unknown provider: ${name}. Available: ${[...this.providers.keys()].join(", ")}`);
51383
51864
  }
51384
51865
  this.defaultProvider = name;
51385
- log29.info(`Default LLM provider updated to: ${name}`);
51866
+ log30.info(`Default LLM provider updated to: ${name}`);
51386
51867
  const providerNames = this.listProviders();
51387
51868
  if (this.autoSelect && providerNames.length > 1) {
51388
51869
  this.providerTiers = buildTiers(providerNames, name);
@@ -51449,7 +51930,7 @@ var init_router = __esm({
51449
51930
  ...this.customModelConfigs.get(providerName) ?? {},
51450
51931
  ...config
51451
51932
  });
51452
- log29.info(`Updated model config for ${providerName}`, config);
51933
+ log30.info(`Updated model config for ${providerName}`, config);
51453
51934
  }
51454
51935
  setProviderEnabled(providerName, enabled) {
51455
51936
  if (enabled) {
@@ -51457,7 +51938,7 @@ var init_router = __esm({
51457
51938
  } else {
51458
51939
  this.disabledProviders.add(providerName);
51459
51940
  }
51460
- log29.info(`Provider ${providerName} ${enabled ? "enabled" : "disabled"}`);
51941
+ log30.info(`Provider ${providerName} ${enabled ? "enabled" : "disabled"}`);
51461
51942
  }
51462
51943
  isProviderEnabled(providerName) {
51463
51944
  return !this.disabledProviders.has(providerName);
@@ -51581,12 +52062,12 @@ var init_router = __esm({
51581
52062
  import { mkdirSync as mkdirSync11, appendFileSync as appendFileSync2 } from "node:fs";
51582
52063
  import { join as join11 } from "node:path";
51583
52064
  import { homedir as homedir6 } from "node:os";
51584
- var log30, LLMLogger;
52065
+ var log31, LLMLogger;
51585
52066
  var init_llm_logger = __esm({
51586
52067
  "../core/dist/llm/llm-logger.js"() {
51587
52068
  "use strict";
51588
52069
  init_dist();
51589
- log30 = createLogger("llm-logger");
52070
+ log31 = createLogger("llm-logger");
51590
52071
  LLMLogger = class {
51591
52072
  logDir;
51592
52073
  enabled;
@@ -51597,7 +52078,7 @@ var init_llm_logger = __esm({
51597
52078
  try {
51598
52079
  mkdirSync11(this.logDir, { recursive: true });
51599
52080
  } catch {
51600
- log30.warn("Failed to create LLM log directory", { dir: this.logDir });
52081
+ log31.warn("Failed to create LLM log directory", { dir: this.logDir });
51601
52082
  this.enabled = false;
51602
52083
  }
51603
52084
  }
@@ -51611,7 +52092,7 @@ var init_llm_logger = __esm({
51611
52092
  const line2 = JSON.stringify(entry) + "\n";
51612
52093
  appendFileSync2(filePath, line2, "utf-8");
51613
52094
  } catch (err) {
51614
- log30.warn("Failed to write LLM log entry", { error: String(err) });
52095
+ log31.warn("Failed to write LLM log entry", { error: String(err) });
51615
52096
  }
51616
52097
  }
51617
52098
  };
@@ -51637,12 +52118,12 @@ var init_enhanced_role_loader = __esm({
51637
52118
 
51638
52119
  // ../core/dist/external-gateway.js
51639
52120
  import { createHmac, randomBytes as randomBytes3, timingSafeEqual } from "node:crypto";
51640
- var log31, ExternalAgentGateway, GatewayError;
52121
+ var log32, ExternalAgentGateway, GatewayError;
51641
52122
  var init_external_gateway = __esm({
51642
52123
  "../core/dist/external-gateway.js"() {
51643
52124
  "use strict";
51644
52125
  init_dist();
51645
- log31 = createLogger("external-gateway");
52126
+ log32 = createLogger("external-gateway");
51646
52127
  ExternalAgentGateway = class {
51647
52128
  config;
51648
52129
  registrations = /* @__PURE__ */ new Map();
@@ -51688,14 +52169,14 @@ var init_external_gateway = __esm({
51688
52169
  if (this.store) {
51689
52170
  await this.store.saveRegistration(reg);
51690
52171
  }
51691
- log31.info("Recreated Markus agent for external registration", { externalAgentId: reg.externalAgentId, markusAgentId: created.id });
52172
+ log32.info("Recreated Markus agent for external registration", { externalAgentId: reg.externalAgentId, markusAgentId: created.id });
51692
52173
  } catch (err) {
51693
- log31.error("Failed to recreate Markus agent for external registration", { externalAgentId: reg.externalAgentId, error: String(err) });
52174
+ log32.error("Failed to recreate Markus agent for external registration", { externalAgentId: reg.externalAgentId, error: String(err) });
51694
52175
  }
51695
52176
  }
51696
52177
  }
51697
52178
  if (rows.length > 0) {
51698
- log31.info("Loaded external agent registrations from store", { count: rows.length });
52179
+ log32.info("Loaded external agent registrations from store", { count: rows.length });
51699
52180
  }
51700
52181
  return rows.length;
51701
52182
  }
@@ -51718,7 +52199,7 @@ var init_external_gateway = __esm({
51718
52199
  const created = await this.agentCreator({ name: agentName, orgId: orgId2, capabilities });
51719
52200
  markusAgentId = created.id;
51720
52201
  } catch (err) {
51721
- log31.error("Failed to create Markus agent for external registration", { externalAgentId, error: String(err) });
52202
+ log32.error("Failed to create Markus agent for external registration", { externalAgentId, error: String(err) });
51722
52203
  throw new GatewayError(`Failed to create internal agent: ${String(err)}`, 500);
51723
52204
  }
51724
52205
  }
@@ -51735,9 +52216,9 @@ var init_external_gateway = __esm({
51735
52216
  this.registrations.set(key2, registration);
51736
52217
  this.orgAgentCounts.set(orgId2, orgCount + 1);
51737
52218
  if (this.store) {
51738
- await this.store.saveRegistration(registration).catch((err) => log31.error("Failed to persist registration", { externalAgentId, error: String(err) }));
52219
+ await this.store.saveRegistration(registration).catch((err) => log32.error("Failed to persist registration", { externalAgentId, error: String(err) }));
51739
52220
  }
51740
- log31.info("External agent registered", { externalAgentId, orgId: orgId2, markusAgentId });
52221
+ log32.info("External agent registered", { externalAgentId, orgId: orgId2, markusAgentId });
51741
52222
  return registration;
51742
52223
  }
51743
52224
  authenticate(request) {
@@ -51767,7 +52248,7 @@ var init_external_gateway = __esm({
51767
52248
  expiresAt: Date.now() + this.config.tokenExpiryMs
51768
52249
  };
51769
52250
  const token = this.signToken(tokenPayload);
51770
- log31.info("External agent authenticated", { externalAgentId, orgId: orgId2, markusAgentId: registration.markusAgentId });
52251
+ log32.info("External agent authenticated", { externalAgentId, orgId: orgId2, markusAgentId: registration.markusAgentId });
51771
52252
  return {
51772
52253
  token,
51773
52254
  externalAgentId,
@@ -51832,7 +52313,7 @@ var init_external_gateway = __esm({
51832
52313
  const response = await this.messageRouter(token.markusAgentId, `[${message.type.toUpperCase()}] ${message.content}`, token.externalAgentId);
51833
52314
  return { success: true, messageId, response };
51834
52315
  } catch (err) {
51835
- log31.error("Message routing failed", { messageId, error: String(err) });
52316
+ log32.error("Message routing failed", { messageId, error: String(err) });
51836
52317
  return { success: false, messageId, error: String(err) };
51837
52318
  }
51838
52319
  }
@@ -51858,7 +52339,7 @@ var init_external_gateway = __esm({
51858
52339
  this.store.updateRegistration(externalAgentId, orgId2, { connected: false }).catch(() => {
51859
52340
  });
51860
52341
  }
51861
- log31.info("External agent disconnected", { externalAgentId, orgId: orgId2 });
52342
+ log32.info("External agent disconnected", { externalAgentId, orgId: orgId2 });
51862
52343
  }
51863
52344
  }
51864
52345
  async unregister(externalAgentId, orgId2) {
@@ -51870,9 +52351,9 @@ var init_external_gateway = __esm({
51870
52351
  const count = this.orgAgentCounts.get(orgId2) ?? 1;
51871
52352
  this.orgAgentCounts.set(orgId2, Math.max(0, count - 1));
51872
52353
  if (this.store) {
51873
- await this.store.deleteRegistration(externalAgentId, orgId2).catch((err) => log31.error("Failed to delete registration from store", { externalAgentId, error: String(err) }));
52354
+ await this.store.deleteRegistration(externalAgentId, orgId2).catch((err) => log32.error("Failed to delete registration from store", { externalAgentId, error: String(err) }));
51874
52355
  }
51875
- log31.info("External agent unregistered", { externalAgentId, orgId: orgId2 });
52356
+ log32.info("External agent unregistered", { externalAgentId, orgId: orgId2 });
51876
52357
  return reg;
51877
52358
  }
51878
52359
  listRegistrations(orgId2) {
@@ -52176,12 +52657,12 @@ var init_markus_handbook = __esm({
52176
52657
  });
52177
52658
 
52178
52659
  // ../core/dist/gateway/sync-handler.js
52179
- var log32, GatewaySyncHandler;
52660
+ var log33, GatewaySyncHandler;
52180
52661
  var init_sync_handler = __esm({
52181
52662
  "../core/dist/gateway/sync-handler.js"() {
52182
52663
  "use strict";
52183
52664
  init_dist();
52184
- log32 = createLogger("gateway-sync");
52665
+ log33 = createLogger("gateway-sync");
52185
52666
  GatewaySyncHandler = class {
52186
52667
  tasks;
52187
52668
  messages;
@@ -52212,9 +52693,9 @@ var init_sync_handler = __esm({
52212
52693
  for (const ct of req.completedTasks) {
52213
52694
  try {
52214
52695
  this.tasks.updateTaskStatus(ct.taskId, "completed", `ext:${markusAgentId}`);
52215
- log32.info("External agent completed task", { markusAgentId, taskId: ct.taskId });
52696
+ log33.info("External agent completed task", { markusAgentId, taskId: ct.taskId });
52216
52697
  } catch (e) {
52217
- log32.warn("Failed to complete task from sync", { taskId: ct.taskId, error: String(e) });
52698
+ log33.warn("Failed to complete task from sync", { taskId: ct.taskId, error: String(e) });
52218
52699
  }
52219
52700
  }
52220
52701
  }
@@ -52222,9 +52703,9 @@ var init_sync_handler = __esm({
52222
52703
  for (const ft of req.failedTasks) {
52223
52704
  try {
52224
52705
  this.tasks.updateTaskStatus(ft.taskId, "failed", `ext:${markusAgentId}`);
52225
- log32.info("External agent failed task", { markusAgentId, taskId: ft.taskId, error: ft.error });
52706
+ log33.info("External agent failed task", { markusAgentId, taskId: ft.taskId, error: ft.error });
52226
52707
  } catch (e) {
52227
- log32.warn("Failed to update task failure from sync", { taskId: ft.taskId, error: String(e) });
52708
+ log33.warn("Failed to update task failure from sync", { taskId: ft.taskId, error: String(e) });
52228
52709
  }
52229
52710
  }
52230
52711
  }
@@ -52241,7 +52722,7 @@ var init_sync_handler = __esm({
52241
52722
  try {
52242
52723
  this.messages.deliver(markusAgentId, msg.to, msg.content);
52243
52724
  } catch (e) {
52244
- log32.warn("Failed to deliver message from sync", { to: msg.to, error: String(e) });
52725
+ log33.warn("Failed to deliver message from sync", { to: msg.to, error: String(e) });
52245
52726
  }
52246
52727
  }
52247
52728
  }
@@ -52297,26 +52778,26 @@ var init_gateway = __esm({
52297
52778
  // ../core/dist/review-service.js
52298
52779
  import { exec as execCb } from "node:child_process";
52299
52780
  import { promisify as promisify2 } from "node:util";
52300
- var execAsync, log33;
52781
+ var execAsync, log34;
52301
52782
  var init_review_service = __esm({
52302
52783
  "../core/dist/review-service.js"() {
52303
52784
  "use strict";
52304
52785
  init_dist();
52305
52786
  execAsync = promisify2(execCb);
52306
- log33 = createLogger("review-service");
52787
+ log34 = createLogger("review-service");
52307
52788
  }
52308
52789
  });
52309
52790
 
52310
52791
  // ../core/dist/workspace-manager.js
52311
52792
  import { exec as execCb2 } from "node:child_process";
52312
52793
  import { promisify as promisify3 } from "node:util";
52313
- var execAsync2, log34;
52794
+ var execAsync2, log35;
52314
52795
  var init_workspace_manager = __esm({
52315
52796
  "../core/dist/workspace-manager.js"() {
52316
52797
  "use strict";
52317
52798
  init_dist();
52318
52799
  execAsync2 = promisify3(execCb2);
52319
- log34 = createLogger("workspace-manager");
52800
+ log35 = createLogger("workspace-manager");
52320
52801
  }
52321
52802
  });
52322
52803
 
@@ -52339,26 +52820,27 @@ var init_tools = __esm({
52339
52820
  init_a2a_structured();
52340
52821
  init_task_tools();
52341
52822
  init_memory();
52823
+ init_subagent();
52342
52824
  }
52343
52825
  });
52344
52826
 
52345
52827
  // ../core/dist/tool-profiles.js
52346
- var log35;
52828
+ var log36;
52347
52829
  var init_tool_profiles = __esm({
52348
52830
  "../core/dist/tool-profiles.js"() {
52349
52831
  "use strict";
52350
52832
  init_dist();
52351
- log35 = createLogger("tool-profiles");
52833
+ log36 = createLogger("tool-profiles");
52352
52834
  }
52353
52835
  });
52354
52836
 
52355
52837
  // ../core/dist/skills/registry.js
52356
- var log36, InMemorySkillRegistry;
52838
+ var log37, InMemorySkillRegistry;
52357
52839
  var init_registry = __esm({
52358
52840
  "../core/dist/skills/registry.js"() {
52359
52841
  "use strict";
52360
52842
  init_dist();
52361
- log36 = createLogger("skill-registry");
52843
+ log37 = createLogger("skill-registry");
52362
52844
  InMemorySkillRegistry = class _InMemorySkillRegistry {
52363
52845
  skills = /* @__PURE__ */ new Map();
52364
52846
  aliases = /* @__PURE__ */ new Map();
@@ -52368,18 +52850,18 @@ var init_registry = __esm({
52368
52850
  register(skill) {
52369
52851
  const name = skill.manifest.name;
52370
52852
  if (this.skills.has(name)) {
52371
- log36.warn(`Skill ${name} already registered, overwriting`);
52853
+ log37.warn(`Skill ${name} already registered, overwriting`);
52372
52854
  }
52373
52855
  this.skills.set(name, skill);
52374
52856
  this.aliases.set(_InMemorySkillRegistry.normalize(name), name);
52375
- log36.info(`Skill registered: ${name} v${skill.manifest.version}`, {
52857
+ log37.info(`Skill registered: ${name} v${skill.manifest.version}`, {
52376
52858
  hasInstructions: !!skill.manifest.instructions
52377
52859
  });
52378
52860
  }
52379
52861
  unregister(skillName) {
52380
52862
  this.skills.delete(skillName);
52381
52863
  this.aliases.delete(_InMemorySkillRegistry.normalize(skillName));
52382
- log36.info(`Skill unregistered: ${skillName}`);
52864
+ log37.info(`Skill unregistered: ${skillName}`);
52383
52865
  }
52384
52866
  get(skillName) {
52385
52867
  return this.skills.get(skillName) ?? this.skills.get(this.aliases.get(_InMemorySkillRegistry.normalize(skillName)) ?? "");
@@ -52451,12 +52933,12 @@ function readSkillInstructions(skillDir) {
52451
52933
  return void 0;
52452
52934
  }
52453
52935
  }
52454
- var log37;
52936
+ var log38;
52455
52937
  var init_loader = __esm({
52456
52938
  "../core/dist/skills/loader.js"() {
52457
52939
  "use strict";
52458
52940
  init_dist();
52459
- log37 = createLogger("skill-loader");
52941
+ log38 = createLogger("skill-loader");
52460
52942
  }
52461
52943
  });
52462
52944
 
@@ -52540,7 +53022,7 @@ function discoverSkillsInDir(dir) {
52540
53022
  results.push({ manifest, path: skillDir, source: dir });
52541
53023
  }
52542
53024
  } catch (err) {
52543
- log38.warn(`Invalid SKILL.md in ${skillDir}: ${err}`);
53025
+ log39.warn(`Invalid SKILL.md in ${skillDir}: ${err}`);
52544
53026
  }
52545
53027
  continue;
52546
53028
  }
@@ -52556,14 +53038,14 @@ async function createDefaultSkillRegistry(options) {
52556
53038
  const found = discoverSkillsInDir(dir);
52557
53039
  for (const { manifest, path: skillPath } of found) {
52558
53040
  if (registry.get(manifest.name)) {
52559
- log38.debug(`Skill ${manifest.name} already registered, skipping ${skillPath}`);
53041
+ log39.debug(`Skill ${manifest.name} already registered, skipping ${skillPath}`);
52560
53042
  continue;
52561
53043
  }
52562
53044
  manifest.sourcePath = skillPath;
52563
53045
  if (isBuiltin)
52564
53046
  manifest.builtIn = true;
52565
53047
  registry.register({ manifest });
52566
- log38.info(`Loaded skill: ${manifest.name} from ${skillPath}`, {
53048
+ log39.info(`Loaded skill: ${manifest.name} from ${skillPath}`, {
52567
53049
  hasInstructions: !!manifest.instructions,
52568
53050
  builtIn: isBuiltin
52569
53051
  });
@@ -52571,7 +53053,7 @@ async function createDefaultSkillRegistry(options) {
52571
53053
  }
52572
53054
  return registry;
52573
53055
  }
52574
- var log38, WELL_KNOWN_SKILL_DIRS;
53056
+ var log39, WELL_KNOWN_SKILL_DIRS;
52575
53057
  var init_skills = __esm({
52576
53058
  "../core/dist/skills/index.js"() {
52577
53059
  "use strict";
@@ -52579,7 +53061,7 @@ var init_skills = __esm({
52579
53061
  init_dist();
52580
53062
  init_registry();
52581
53063
  init_loader();
52582
- log38 = createLogger("skill-registry");
53064
+ log39 = createLogger("skill-registry");
52583
53065
  WELL_KNOWN_SKILL_DIRS = [
52584
53066
  join13(homedir7(), ".markus", "skills"),
52585
53067
  join13(homedir7(), ".claude", "skills"),
@@ -52797,12 +53279,12 @@ function createDefaultTemplateRegistry() {
52797
53279
  }
52798
53280
  return registry;
52799
53281
  }
52800
- var log39, TemplateRegistry;
53282
+ var log40, TemplateRegistry;
52801
53283
  var init_registry2 = __esm({
52802
53284
  "../core/dist/templates/registry.js"() {
52803
53285
  "use strict";
52804
53286
  init_dist();
52805
- log39 = createLogger("template-registry");
53287
+ log40 = createLogger("template-registry");
52806
53288
  TemplateRegistry = class {
52807
53289
  templates = /* @__PURE__ */ new Map();
52808
53290
  persistence;
@@ -52825,16 +53307,16 @@ var init_registry2 = __esm({
52825
53307
  loaded++;
52826
53308
  }
52827
53309
  }
52828
- log39.info(`Synced ${loaded} templates from database`, { total: this.templates.size });
53310
+ log40.info(`Synced ${loaded} templates from database`, { total: this.templates.size });
52829
53311
  return loaded;
52830
53312
  } catch (err) {
52831
- log39.warn("Failed to sync templates from database", { error: String(err) });
53313
+ log40.warn("Failed to sync templates from database", { error: String(err) });
52832
53314
  return 0;
52833
53315
  }
52834
53316
  }
52835
53317
  register(template) {
52836
53318
  this.templates.set(template.id, template);
52837
- log39.info(`Template registered: ${template.name} (${template.id})`, {
53319
+ log40.info(`Template registered: ${template.name} (${template.id})`, {
52838
53320
  source: template.source,
52839
53321
  category: template.category
52840
53322
  });
@@ -52896,12 +53378,12 @@ var init_templates = __esm({
52896
53378
  });
52897
53379
 
52898
53380
  // ../core/dist/workflow/engine.js
52899
- var log40, WorkflowEngine;
53381
+ var log41, WorkflowEngine;
52900
53382
  var init_engine = __esm({
52901
53383
  "../core/dist/workflow/engine.js"() {
52902
53384
  "use strict";
52903
53385
  init_dist();
52904
- log40 = createLogger("workflow-engine");
53386
+ log41 = createLogger("workflow-engine");
52905
53387
  WorkflowEngine = class {
52906
53388
  executor;
52907
53389
  executions = /* @__PURE__ */ new Map();
@@ -52922,7 +53404,7 @@ var init_engine = __esm({
52922
53404
  try {
52923
53405
  handler4(event);
52924
53406
  } catch (err) {
52925
- log40.warn("Event handler error", { error: String(err) });
53407
+ log41.warn("Event handler error", { error: String(err) });
52926
53408
  }
52927
53409
  }
52928
53410
  }
@@ -53017,7 +53499,7 @@ var init_engine = __esm({
53017
53499
  };
53018
53500
  this.executions.set(executionId, execution);
53019
53501
  this.emit({ type: "workflow_started", executionId, timestamp: /* @__PURE__ */ new Date() });
53020
- log40.info("Workflow started", { executionId, workflowId: def.id, stepCount: def.steps.length });
53502
+ log41.info("Workflow started", { executionId, workflowId: def.id, stepCount: def.steps.length });
53021
53503
  try {
53022
53504
  await this.executeGraph(def, execution);
53023
53505
  if (execution.status === "cancelled")
@@ -53030,13 +53512,13 @@ var init_engine = __esm({
53030
53512
  execution.status = "completed";
53031
53513
  execution.completedAt = /* @__PURE__ */ new Date();
53032
53514
  this.emit({ type: "workflow_completed", executionId, timestamp: /* @__PURE__ */ new Date(), data: execution.outputs });
53033
- log40.info("Workflow completed", { executionId, elapsed: Date.now() - execution.startedAt.getTime() });
53515
+ log41.info("Workflow completed", { executionId, elapsed: Date.now() - execution.startedAt.getTime() });
53034
53516
  } catch (err) {
53035
53517
  execution.status = "failed";
53036
53518
  execution.error = String(err);
53037
53519
  execution.completedAt = /* @__PURE__ */ new Date();
53038
53520
  this.emit({ type: "workflow_failed", executionId, timestamp: /* @__PURE__ */ new Date(), data: { error: String(err) } });
53039
- log40.error("Workflow failed", { executionId, error: String(err) });
53521
+ log41.error("Workflow failed", { executionId, error: String(err) });
53040
53522
  }
53041
53523
  return execution;
53042
53524
  }
@@ -53076,7 +53558,7 @@ var init_engine = __esm({
53076
53558
  const promises = readySteps.map((stepId) => {
53077
53559
  const stepDef = stepDefs.get(stepId);
53078
53560
  return this.executeStep(stepDef, execution).catch((err) => {
53079
- log40.error("Step execution error", { stepId, error: String(err) });
53561
+ log41.error("Step execution error", { stepId, error: String(err) });
53080
53562
  });
53081
53563
  });
53082
53564
  await Promise.all(promises);
@@ -53167,7 +53649,7 @@ var init_engine = __esm({
53167
53649
  timestamp: /* @__PURE__ */ new Date(),
53168
53650
  data: { attempt: stepExec.retryCount, maxRetries }
53169
53651
  });
53170
- log40.warn("Step retrying", { stepId: stepDef.id, attempt: stepExec.retryCount });
53652
+ log41.warn("Step retrying", { stepId: stepDef.id, attempt: stepExec.retryCount });
53171
53653
  } else {
53172
53654
  stepExec.status = "failed";
53173
53655
  stepExec.error = String(err);
@@ -53355,7 +53837,7 @@ var init_engine = __esm({
53355
53837
  const fn = new Function("steps", "inputs", `return !!(${expr})`);
53356
53838
  return fn(steps, execution.inputs);
53357
53839
  } catch {
53358
- log40.warn("Expression evaluation failed", { expr });
53840
+ log41.warn("Expression evaluation failed", { expr });
53359
53841
  return false;
53360
53842
  }
53361
53843
  }
@@ -53420,7 +53902,7 @@ function loadTeamTemplateFromDir(dirPath) {
53420
53902
  norms: existsSync19(normsPath) ? readFileSync16(normsPath, "utf-8") : void 0
53421
53903
  };
53422
53904
  } catch (err) {
53423
- log41.warn(`Failed to load team template from ${dirPath}`, { error: String(err) });
53905
+ log42.warn(`Failed to load team template from ${dirPath}`, { error: String(err) });
53424
53906
  return null;
53425
53907
  }
53426
53908
  }
@@ -53443,7 +53925,7 @@ function createDefaultTeamTemplates() {
53443
53925
  templatesDir = resolve11(process.cwd(), "templates", "teams");
53444
53926
  }
53445
53927
  if (!existsSync19(templatesDir)) {
53446
- log41.warn(`Team templates directory not found: ${templatesDir}`);
53928
+ log42.warn(`Team templates directory not found: ${templatesDir}`);
53447
53929
  return registry;
53448
53930
  }
53449
53931
  const entries2 = readdirSync7(templatesDir, { withFileTypes: true });
@@ -53455,22 +53937,21 @@ function createDefaultTeamTemplates() {
53455
53937
  registry.register(tpl);
53456
53938
  }
53457
53939
  }
53458
- log41.info(`Loaded ${registry.list().length} team templates from ${templatesDir}`);
53940
+ log42.info(`Loaded ${registry.list().length} team templates from ${templatesDir}`);
53459
53941
  return registry;
53460
53942
  }
53461
- var log41, TeamTemplateRegistry;
53943
+ var log42, TeamTemplateRegistry;
53462
53944
  var init_team_template = __esm({
53463
53945
  "../core/dist/workflow/team-template.js"() {
53464
53946
  "use strict";
53465
53947
  init_dist();
53466
- log41 = createLogger("team-template");
53948
+ log42 = createLogger("team-template");
53467
53949
  TeamTemplateRegistry = class {
53468
53950
  templates = /* @__PURE__ */ new Map();
53469
53951
  register(template) {
53470
53952
  this.templates.set(template.id, template);
53471
- log41.info(`Team template registered: ${template.name}`, {
53472
- members: template.members.length,
53473
- hasWorkflow: !!template.workflow
53953
+ log42.info(`Team template registered: ${template.name}`, {
53954
+ members: template.members.length
53474
53955
  });
53475
53956
  }
53476
53957
  unregister(id) {
@@ -53508,13 +53989,13 @@ var init_types = __esm({
53508
53989
  });
53509
53990
 
53510
53991
  // ../core/dist/federation/federation-manager.js
53511
- var log42;
53992
+ var log43;
53512
53993
  var init_federation_manager = __esm({
53513
53994
  "../core/dist/federation/federation-manager.js"() {
53514
53995
  "use strict";
53515
53996
  init_dist();
53516
53997
  init_types();
53517
- log42 = createLogger("federation");
53998
+ log43 = createLogger("federation");
53518
53999
  }
53519
54000
  });
53520
54001
 
@@ -53528,266 +54009,12 @@ var init_federation = __esm({
53528
54009
  });
53529
54010
 
53530
54011
  // ../core/dist/agent-snapshot.js
53531
- var log43;
54012
+ var log44;
53532
54013
  var init_agent_snapshot = __esm({
53533
54014
  "../core/dist/agent-snapshot.js"() {
53534
54015
  "use strict";
53535
54016
  init_dist();
53536
- log43 = createLogger("agent-snapshot");
53537
- }
53538
- });
53539
-
53540
- // ../core/dist/prompt-studio.js
53541
- var log44, PromptStudio;
53542
- var init_prompt_studio = __esm({
53543
- "../core/dist/prompt-studio.js"() {
53544
- "use strict";
53545
- init_dist();
53546
- log44 = createLogger("prompt-studio");
53547
- PromptStudio = class {
53548
- executor;
53549
- prompts = /* @__PURE__ */ new Map();
53550
- abTests = /* @__PURE__ */ new Map();
53551
- evaluations = [];
53552
- constructor(executor) {
53553
- this.executor = executor;
53554
- }
53555
- setExecutor(executor) {
53556
- this.executor = executor;
53557
- }
53558
- // ── Prompt Management ──────────────────────────────────────────────────
53559
- createPrompt(opts) {
53560
- const id = generateId("prompt");
53561
- const version2 = {
53562
- id: generateId("pv"),
53563
- promptId: id,
53564
- version: 1,
53565
- content: opts.content,
53566
- variables: this.extractVariables(opts.content),
53567
- author: opts.author,
53568
- createdAt: /* @__PURE__ */ new Date()
53569
- };
53570
- const prompt = {
53571
- id,
53572
- name: opts.name,
53573
- description: opts.description,
53574
- category: opts.category,
53575
- currentVersion: 1,
53576
- versions: [version2],
53577
- tags: opts.tags ?? [],
53578
- createdAt: /* @__PURE__ */ new Date(),
53579
- updatedAt: /* @__PURE__ */ new Date()
53580
- };
53581
- this.prompts.set(id, prompt);
53582
- log44.info("Prompt created", { promptId: id, name: opts.name });
53583
- return prompt;
53584
- }
53585
- updatePrompt(promptId, content, author, changelog) {
53586
- const prompt = this.prompts.get(promptId);
53587
- if (!prompt)
53588
- throw new Error(`Prompt ${promptId} not found`);
53589
- const newVersionNum = prompt.currentVersion + 1;
53590
- const version2 = {
53591
- id: generateId("pv"),
53592
- promptId,
53593
- version: newVersionNum,
53594
- content,
53595
- variables: this.extractVariables(content),
53596
- author,
53597
- createdAt: /* @__PURE__ */ new Date(),
53598
- changelog
53599
- };
53600
- prompt.versions.push(version2);
53601
- prompt.currentVersion = newVersionNum;
53602
- prompt.updatedAt = /* @__PURE__ */ new Date();
53603
- log44.info("Prompt updated", { promptId, version: newVersionNum });
53604
- return version2;
53605
- }
53606
- getPrompt(promptId) {
53607
- return this.prompts.get(promptId);
53608
- }
53609
- getVersion(promptId, version2) {
53610
- const prompt = this.prompts.get(promptId);
53611
- return prompt?.versions.find((v) => v.version === version2);
53612
- }
53613
- listPrompts(category) {
53614
- const all = [...this.prompts.values()];
53615
- if (!category)
53616
- return all;
53617
- return all.filter((p) => p.category === category);
53618
- }
53619
- searchPrompts(query2) {
53620
- const lower = query2.toLowerCase();
53621
- return [...this.prompts.values()].filter((p) => p.name.toLowerCase().includes(lower) || p.description.toLowerCase().includes(lower) || p.tags.some((t) => t.toLowerCase().includes(lower)));
53622
- }
53623
- deletePrompt(promptId) {
53624
- return this.prompts.delete(promptId);
53625
- }
53626
- renderPrompt(promptId, variables, version2) {
53627
- const prompt = this.prompts.get(promptId);
53628
- if (!prompt)
53629
- throw new Error(`Prompt ${promptId} not found`);
53630
- const v = version2 ? prompt.versions.find((pv) => pv.version === version2) : prompt.versions.find((pv) => pv.version === prompt.currentVersion);
53631
- if (!v)
53632
- throw new Error(`Version ${version2 ?? prompt.currentVersion} not found`);
53633
- return this.interpolatePrompt(v.content, variables);
53634
- }
53635
- // ── A/B Testing ────────────────────────────────────────────────────────
53636
- createABTest(opts) {
53637
- const prompt = this.prompts.get(opts.promptId);
53638
- if (!prompt)
53639
- throw new Error(`Prompt ${opts.promptId} not found`);
53640
- const findVersion2 = (v) => prompt.versions.find((pv) => pv.version === v);
53641
- if (!findVersion2(opts.variantA))
53642
- throw new Error(`Variant A (v${opts.variantA}) not found`);
53643
- if (!findVersion2(opts.variantB))
53644
- throw new Error(`Variant B (v${opts.variantB}) not found`);
53645
- const test = {
53646
- id: generateId("ab-test"),
53647
- name: opts.name,
53648
- promptId: opts.promptId,
53649
- variantA: opts.variantA,
53650
- variantB: opts.variantB,
53651
- splitRatio: opts.splitRatio ?? 0.5,
53652
- status: "draft",
53653
- metrics: {
53654
- variantATrials: 0,
53655
- variantBTrials: 0,
53656
- variantAScores: [],
53657
- variantBScores: []
53658
- },
53659
- createdAt: /* @__PURE__ */ new Date()
53660
- };
53661
- this.abTests.set(test.id, test);
53662
- log44.info("A/B test created", { testId: test.id, promptId: opts.promptId });
53663
- return test;
53664
- }
53665
- startABTest(testId) {
53666
- const test = this.abTests.get(testId);
53667
- if (!test || test.status !== "draft")
53668
- return false;
53669
- test.status = "running";
53670
- return true;
53671
- }
53672
- /** Pick which variant to use based on the split ratio */
53673
- pickVariant(testId) {
53674
- const test = this.abTests.get(testId);
53675
- if (!test || test.status !== "running") {
53676
- throw new Error(`A/B test ${testId} is not running`);
53677
- }
53678
- const isA = Math.random() < test.splitRatio;
53679
- return isA ? { version: test.variantA, variant: "A" } : { version: test.variantB, variant: "B" };
53680
- }
53681
- recordABResult(testId, variant, score) {
53682
- const test = this.abTests.get(testId);
53683
- if (!test || test.status !== "running")
53684
- return;
53685
- if (variant === "A") {
53686
- test.metrics.variantATrials++;
53687
- test.metrics.variantAScores.push(score);
53688
- } else {
53689
- test.metrics.variantBTrials++;
53690
- test.metrics.variantBScores.push(score);
53691
- }
53692
- }
53693
- completeABTest(testId) {
53694
- const test = this.abTests.get(testId);
53695
- if (!test || test.status !== "running")
53696
- return void 0;
53697
- test.status = "completed";
53698
- test.completedAt = /* @__PURE__ */ new Date();
53699
- log44.info("A/B test completed", {
53700
- testId,
53701
- variantAAvg: this.average(test.metrics.variantAScores),
53702
- variantBAvg: this.average(test.metrics.variantBScores)
53703
- });
53704
- return test;
53705
- }
53706
- getABTestResults(testId) {
53707
- const test = this.abTests.get(testId);
53708
- if (!test)
53709
- return void 0;
53710
- const avgA = this.average(test.metrics.variantAScores);
53711
- const avgB = this.average(test.metrics.variantBScores);
53712
- const diff = Math.abs(avgA - avgB);
53713
- const totalTrials = test.metrics.variantATrials + test.metrics.variantBTrials;
53714
- const confidence = totalTrials > 0 ? Math.min(1, totalTrials / 100 * (diff / Math.max(avgA, avgB, 0.01))) : 0;
53715
- let winner = "tie";
53716
- if (diff > 0.05)
53717
- winner = avgA > avgB ? "A" : "B";
53718
- return { test, variantAAvg: avgA, variantBAvg: avgB, winner, confidence };
53719
- }
53720
- listABTests(promptId) {
53721
- const all = [...this.abTests.values()];
53722
- if (!promptId)
53723
- return all;
53724
- return all.filter((t) => t.promptId === promptId);
53725
- }
53726
- // ── Evaluation ─────────────────────────────────────────────────────────
53727
- async evaluate(promptId, version2, testInput, variables = {}, evaluator) {
53728
- if (!this.executor)
53729
- throw new Error("No prompt executor configured");
53730
- const rendered = this.renderPrompt(promptId, variables, version2);
53731
- const fullPrompt = `${rendered}
53732
-
53733
- Input: ${testInput}`;
53734
- const { output, latencyMs, tokenCount } = await this.executor.execute(fullPrompt, variables);
53735
- const result = {
53736
- id: generateId("eval"),
53737
- promptId,
53738
- version: version2,
53739
- testInput,
53740
- output,
53741
- score: 0,
53742
- latencyMs,
53743
- tokenCount,
53744
- evaluatedAt: /* @__PURE__ */ new Date(),
53745
- evaluator
53746
- };
53747
- this.evaluations.push(result);
53748
- return result;
53749
- }
53750
- scoreEvaluation(evaluationId, score, notes) {
53751
- const ev = this.evaluations.find((e) => e.id === evaluationId);
53752
- if (!ev)
53753
- return false;
53754
- ev.score = Math.max(0, Math.min(10, score));
53755
- if (notes)
53756
- ev.notes = notes;
53757
- return true;
53758
- }
53759
- getEvaluations(promptId, version2) {
53760
- return this.evaluations.filter((e) => e.promptId === promptId && (version2 === void 0 || e.version === version2));
53761
- }
53762
- getEvaluationSummary(promptId, version2) {
53763
- const evals = this.getEvaluations(promptId, version2);
53764
- if (evals.length === 0)
53765
- return { avgScore: 0, avgLatencyMs: 0, avgTokenCount: 0, count: 0 };
53766
- return {
53767
- avgScore: this.average(evals.map((e) => e.score)),
53768
- avgLatencyMs: this.average(evals.map((e) => e.latencyMs)),
53769
- avgTokenCount: this.average(evals.map((e) => e.tokenCount)),
53770
- count: evals.length
53771
- };
53772
- }
53773
- // ── Helpers ────────────────────────────────────────────────────────────
53774
- extractVariables(content) {
53775
- const matches2 = content.match(/\{\{(\w+)\}\}/g);
53776
- if (!matches2)
53777
- return [];
53778
- return [...new Set(matches2.map((m) => m.slice(2, -2)))];
53779
- }
53780
- interpolatePrompt(content, variables) {
53781
- return content.replace(/\{\{(\w+)\}\}/g, (_match, name) => {
53782
- return variables[name] ?? `{{${name}}}`;
53783
- });
53784
- }
53785
- average(arr) {
53786
- if (arr.length === 0)
53787
- return 0;
53788
- return Math.round(arr.reduce((s, v) => s + v, 0) / arr.length * 100) / 100;
53789
- }
53790
- };
54017
+ log44 = createLogger("agent-snapshot");
53791
54018
  }
53792
54019
  });
53793
54020
 
@@ -53835,7 +54062,6 @@ var init_dist4 = __esm({
53835
54062
  init_workflow();
53836
54063
  init_federation();
53837
54064
  init_agent_snapshot();
53838
- init_prompt_studio();
53839
54065
  }
53840
54066
  });
53841
54067
 
@@ -54422,7 +54648,13 @@ var init_org_service = __esm({
54422
54648
  if (!org)
54423
54649
  return;
54424
54650
  const humans = this.listHumanUsers(targetOrgId);
54425
- this.agentManager.refreshIdentityContexts(targetOrgId, org.name, humans);
54651
+ const teams2 = this.listTeams(targetOrgId).map((t) => ({
54652
+ id: t.id,
54653
+ name: t.name,
54654
+ description: t.description,
54655
+ memberAgentIds: t.memberAgentIds
54656
+ }));
54657
+ this.agentManager.refreshIdentityContexts(targetOrgId, org.name, humans, teams2);
54426
54658
  }
54427
54659
  listAvailableRoles() {
54428
54660
  return this.roleLoader.listAvailableRoles();
@@ -54712,7 +54944,29 @@ var init_org_service = __esm({
54712
54944
  for (const r of roleNames) {
54713
54945
  parts.push(`- \`${r}\``);
54714
54946
  }
54947
+ const templateDirs = this.roleLoader.getTemplateDirs();
54948
+ if (templateDirs.length > 0) {
54949
+ parts.push("");
54950
+ parts.push("**Tip**: You can read existing role templates for reference when writing custom ROLE.md files.");
54951
+ parts.push(`Use \`file_read\` to inspect any template, e.g.: \`file_read("${templateDirs[0]}/developer/ROLE.md")\``);
54952
+ parts.push("This is especially useful for understanding the level of detail and workflow guidance expected in a good ROLE.md.");
54953
+ }
54715
54954
  }
54955
+ parts.push("");
54956
+ parts.push("## Platform Capabilities (reference when writing ROLE.md)");
54957
+ parts.push("");
54958
+ parts.push("When writing custom ROLE.md for agents, reference these platform capabilities where relevant:");
54959
+ parts.push("");
54960
+ parts.push("- **`spawn_subagent`** \u2014 Spawn lightweight in-process subagents for focused subtasks (deep analysis, research, boilerplate generation) without polluting the parent agent's context");
54961
+ parts.push("- **`background_exec`** \u2014 Run long-running commands (builds, test suites, deployments) in background with automatic completion notifications");
54962
+ parts.push("- **`shell_execute`** \u2014 Execute any shell command, including `git` (merge, diff, branch) and `gh` CLI (PRs, issues, releases) for Git/GitHub operations");
54963
+ parts.push("- **Worktree isolation** \u2014 Each task gets an isolated git worktree (`task/<id>` branch). Developers work in isolation; the reviewer merges after approval.");
54964
+ parts.push("- **`web_search` / `web_fetch`** \u2014 Search the web and fetch page content for research, documentation lookup, and real-time information");
54965
+ parts.push("- **Task dependencies** \u2014 Use `blockedBy` to express dependencies between tasks. Blocked tasks auto-start when dependencies complete.");
54966
+ parts.push("- **Deliverables** \u2014 Use `deliverable_create` to register outputs (files, conventions, architecture decisions) as trackable artifacts");
54967
+ parts.push("- **Memory** \u2014 Use `memory_save` / `memory_search` for persistent knowledge across sessions");
54968
+ parts.push("");
54969
+ parts.push("Include workflow guidance in ROLE.md that tells the agent *when* and *how* to use these capabilities for their specific role.");
54716
54970
  return parts.join("\n");
54717
54971
  }
54718
54972
  };
@@ -56587,10 +56841,25 @@ ${c.content}`;
56587
56841
  parts.push(`> ${note}`);
56588
56842
  }
56589
56843
  }
56844
+ if (task.projectId && this.projectService) {
56845
+ const project = this.projectService.getProject(task.projectId);
56846
+ const repo = project?.repositories?.find((r) => r.role === "primary" && r.localPath) ?? project?.repositories?.find((r) => r.localPath);
56847
+ if (repo?.localPath) {
56848
+ const branchName = `task/${task.id}`;
56849
+ const worktreePath = `${repo.localPath}/.worktrees/task-${task.id}`;
56850
+ parts.push("");
56851
+ parts.push("**Git Context:**");
56852
+ parts.push(`- Repository: \`${repo.localPath}\``);
56853
+ parts.push(`- Task branch: \`${branchName}\``);
56854
+ parts.push(`- Base branch: \`${repo.defaultBranch}\``);
56855
+ parts.push(`- Worktree: \`${worktreePath}\``);
56856
+ parts.push(`- To see changes: \`cd ${repo.localPath} && git diff ${repo.defaultBranch}...${branchName}\``);
56857
+ }
56858
+ }
56590
56859
  parts.push("");
56591
56860
  parts.push(`Please review immediately. Use \`task_get\` with task_id "${task.id}" to inspect deliverable files, then either:`);
56592
- parts.push(`- \`task_update\` with task_id "${task.id}" and status "completed" if the work meets requirements (this approves and completes the task)`);
56593
- parts.push(`- \`task_update\` with task_id "${task.id}" and a note explaining what needs to change (the system will automatically request revision and re-execute)`);
56861
+ parts.push(`- **Approve**: Review the code, merge the branch (via \`git merge\` or \`gh pr create\` + \`gh pr merge\`), then \`task_update\` with status "completed"`);
56862
+ parts.push(`- **Reject**: If the code has issues or merge conflicts, add a \`task_note\` explaining what needs to change, then \`task_update\` with status "in_progress" to send it back`);
56594
56863
  parts.push("");
56595
56864
  parts.push(`CRITICAL: You MUST ONLY review this specific task (ID: ${task.id}). Do NOT change the status of any other task.`);
56596
56865
  const reviewMessage = parts.join("\n");
@@ -58444,7 +58713,6 @@ var init_api_server = __esm({
58444
58713
  templateRegistry;
58445
58714
  workflowEngine;
58446
58715
  teamTemplateRegistry;
58447
- promptStudio;
58448
58716
  customGroupChats = [];
58449
58717
  constructor(orgService, taskService, port = 8056) {
58450
58718
  this.orgService = orgService;
@@ -58453,7 +58721,6 @@ var init_api_server = __esm({
58453
58721
  this.ws = new WSBroadcaster();
58454
58722
  this.teamTemplateRegistry = createDefaultTeamTemplates();
58455
58723
  this.templateRegistry = createDefaultTemplateRegistry();
58456
- this.promptStudio = new PromptStudio();
58457
58724
  const am = this.orgService.getAgentManager();
58458
58725
  if (this.templateRegistry && !am.getTemplateRegistry()) {
58459
58726
  am.setTemplateRegistry(this.templateRegistry);
@@ -62691,6 +62958,37 @@ var init_api_server = __esm({
62691
62958
  }
62692
62959
  return;
62693
62960
  }
62961
+ if (path === "/api/settings/agent" && req.method === "GET") {
62962
+ const am = this.orgService.getAgentManager();
62963
+ this.json(res, 200, { maxToolIterations: am.maxToolIterations });
62964
+ return;
62965
+ }
62966
+ if (path === "/api/settings/agent" && req.method === "POST") {
62967
+ const auth = await this.requireAuth(req, res);
62968
+ if (!auth)
62969
+ return;
62970
+ const body = await this.readBody(req);
62971
+ const am = this.orgService.getAgentManager();
62972
+ let changed = false;
62973
+ if (typeof body["maxToolIterations"] === "number") {
62974
+ am.maxToolIterations = body["maxToolIterations"];
62975
+ changed = true;
62976
+ }
62977
+ if (changed) {
62978
+ try {
62979
+ saveConfig({ agent: { maxToolIterations: am.maxToolIterations } }, this.markusConfigPath);
62980
+ } catch (e) {
62981
+ log51.warn("Failed to persist agent settings to config file", { error: String(e) });
62982
+ }
62983
+ for (const info of am.listAgents()) {
62984
+ const agent = am.getAgent(info.id);
62985
+ if (agent)
62986
+ agent.maxToolIterations = am.maxToolIterations;
62987
+ }
62988
+ }
62989
+ this.json(res, 200, { maxToolIterations: am.maxToolIterations });
62990
+ return;
62991
+ }
62694
62992
  if (path === "/api/settings/llm/models" && req.method === "GET") {
62695
62993
  if (!this.llmRouter) {
62696
62994
  this.json(res, 200, { models: [] });
@@ -63258,207 +63556,6 @@ var init_api_server = __esm({
63258
63556
  this.json(res, 200, { deleted: true });
63259
63557
  return;
63260
63558
  }
63261
- if (path === "/api/prompts" && req.method === "GET") {
63262
- const category = url.searchParams.get("category") ?? void 0;
63263
- const q = url.searchParams.get("q");
63264
- const prompts = q ? this.promptStudio.searchPrompts(q) : this.promptStudio.listPrompts(category);
63265
- this.json(res, 200, { prompts });
63266
- return;
63267
- }
63268
- if (path === "/api/prompts" && req.method === "POST") {
63269
- const auth = await this.requireAuth(req, res);
63270
- if (!auth)
63271
- return;
63272
- const body = await this.readBody(req);
63273
- const { name, description, category, content, tags } = body;
63274
- if (!name || !content) {
63275
- this.json(res, 400, { error: "name and content are required" });
63276
- return;
63277
- }
63278
- const prompt = this.promptStudio.createPrompt({
63279
- name,
63280
- description: description ?? "",
63281
- category: category ?? "general",
63282
- content,
63283
- author: auth.userId ?? "user",
63284
- tags
63285
- });
63286
- this.json(res, 201, { prompt });
63287
- return;
63288
- }
63289
- if (path.match(/^\/api\/prompts\/[^/]+$/) && req.method === "GET") {
63290
- const promptId = path.split("/")[3];
63291
- const prompt = this.promptStudio.getPrompt(promptId);
63292
- if (!prompt) {
63293
- this.json(res, 404, { error: "Prompt not found" });
63294
- return;
63295
- }
63296
- this.json(res, 200, { prompt });
63297
- return;
63298
- }
63299
- if (path.match(/^\/api\/prompts\/[^/]+$/) && req.method === "DELETE") {
63300
- const promptId = path.split("/")[3];
63301
- this.promptStudio.deletePrompt(promptId);
63302
- this.json(res, 200, { deleted: true });
63303
- return;
63304
- }
63305
- if (path.match(/^\/api\/prompts\/[^/]+\/versions$/) && req.method === "POST") {
63306
- const auth = await this.requireAuth(req, res);
63307
- if (!auth)
63308
- return;
63309
- const promptId = path.split("/")[3];
63310
- const body = await this.readBody(req);
63311
- const { content, changelog } = body;
63312
- if (!content) {
63313
- this.json(res, 400, { error: "content is required" });
63314
- return;
63315
- }
63316
- try {
63317
- const version2 = this.promptStudio.updatePrompt(promptId, content, auth.userId ?? "user", changelog);
63318
- this.json(res, 201, { version: version2 });
63319
- } catch (err) {
63320
- this.json(res, 404, { error: String(err) });
63321
- }
63322
- return;
63323
- }
63324
- if (path.match(/^\/api\/prompts\/[^/]+\/render$/) && req.method === "POST") {
63325
- const promptId = path.split("/")[3];
63326
- const body = await this.readBody(req);
63327
- const { variables, version: version2 } = body;
63328
- try {
63329
- const rendered = this.promptStudio.renderPrompt(promptId, variables ?? {}, version2);
63330
- this.json(res, 200, { rendered });
63331
- } catch (err) {
63332
- this.json(res, 400, { error: String(err) });
63333
- }
63334
- return;
63335
- }
63336
- if (path === "/api/prompts/ab-tests" && req.method === "GET") {
63337
- const promptId = url.searchParams.get("promptId") ?? void 0;
63338
- const tests = this.promptStudio.listABTests(promptId);
63339
- this.json(res, 200, { tests });
63340
- return;
63341
- }
63342
- if (path === "/api/prompts/ab-tests" && req.method === "POST") {
63343
- const auth = await this.requireAuth(req, res);
63344
- if (!auth)
63345
- return;
63346
- const body = await this.readBody(req);
63347
- const { name, promptId, variantA, variantB, splitRatio } = body;
63348
- try {
63349
- const test = this.promptStudio.createABTest({
63350
- name,
63351
- promptId,
63352
- variantA,
63353
- variantB,
63354
- splitRatio
63355
- });
63356
- this.json(res, 201, { test });
63357
- } catch (err) {
63358
- this.json(res, 400, { error: String(err) });
63359
- }
63360
- return;
63361
- }
63362
- if (path.match(/^\/api\/prompts\/ab-tests\/[^/]+\/start$/) && req.method === "POST") {
63363
- const testId = path.split("/")[4];
63364
- const started = this.promptStudio.startABTest(testId);
63365
- this.json(res, 200, { started });
63366
- return;
63367
- }
63368
- if (path.match(/^\/api\/prompts\/ab-tests\/[^/]+\/complete$/) && req.method === "POST") {
63369
- const testId = path.split("/")[4];
63370
- const result = this.promptStudio.completeABTest(testId);
63371
- if (!result) {
63372
- this.json(res, 404, { error: "Test not found or not running" });
63373
- return;
63374
- }
63375
- this.json(res, 200, { test: result });
63376
- return;
63377
- }
63378
- if (path.match(/^\/api\/prompts\/ab-tests\/[^/]+\/record$/) && req.method === "POST") {
63379
- const testId = path.split("/")[4];
63380
- const body = await this.readBody(req);
63381
- const { variant, score } = body;
63382
- this.promptStudio.recordABResult(testId, variant, score);
63383
- this.json(res, 200, { ok: true });
63384
- return;
63385
- }
63386
- if (path.match(/^\/api\/prompts\/ab-tests\/[^/]+\/results$/) && req.method === "GET") {
63387
- const testId = path.split("/")[4];
63388
- const results = this.promptStudio.getABTestResults(testId);
63389
- if (!results) {
63390
- this.json(res, 404, { error: "Test not found" });
63391
- return;
63392
- }
63393
- this.json(res, 200, results);
63394
- return;
63395
- }
63396
- if (path.match(/^\/api\/prompts\/[^/]+\/evaluations$/) && req.method === "GET") {
63397
- const promptId = path.split("/")[3];
63398
- const version2 = url.searchParams.get("version") ? parseInt(url.searchParams.get("version"), 10) : void 0;
63399
- const evaluations = this.promptStudio.getEvaluations(promptId, version2);
63400
- this.json(res, 200, { evaluations });
63401
- return;
63402
- }
63403
- if (path.match(/^\/api\/prompts\/[^/]+\/evaluate$/) && req.method === "POST") {
63404
- const auth = await this.requireAuth(req, res);
63405
- if (!auth)
63406
- return;
63407
- const promptId = path.split("/")[3];
63408
- const body = await this.readBody(req);
63409
- const { version: version2, testInput, variables } = body;
63410
- if (!testInput || version2 === void 0) {
63411
- this.json(res, 400, { error: "version and testInput are required" });
63412
- return;
63413
- }
63414
- if (this.llmRouter && !this.promptStudio["executor"]) {
63415
- this.promptStudio.setExecutor({
63416
- execute: async (prompt) => {
63417
- const startMs = Date.now();
63418
- const response = await this.llmRouter.chat({
63419
- messages: [
63420
- {
63421
- role: "system",
63422
- content: "You are a helpful assistant. Respond to the prompt accurately and concisely."
63423
- },
63424
- { role: "user", content: prompt }
63425
- ]
63426
- });
63427
- return {
63428
- output: response.content,
63429
- latencyMs: Date.now() - startMs,
63430
- tokenCount: (response.usage?.inputTokens ?? 0) + (response.usage?.outputTokens ?? 0)
63431
- };
63432
- }
63433
- });
63434
- }
63435
- try {
63436
- const result = await this.promptStudio.evaluate(promptId, version2, testInput, variables ?? {}, auth.userId ?? "user");
63437
- this.json(res, 200, { evaluation: result });
63438
- } catch (err) {
63439
- this.json(res, 400, { error: String(err) });
63440
- }
63441
- return;
63442
- }
63443
- if (path.match(/^\/api\/prompts\/evaluations\/[^/]+\/score$/) && req.method === "POST") {
63444
- const evaluationId = path.split("/")[4];
63445
- const body = await this.readBody(req);
63446
- const { score, notes } = body;
63447
- const updated = this.promptStudio.scoreEvaluation(evaluationId, score, notes);
63448
- this.json(res, 200, { updated });
63449
- return;
63450
- }
63451
- if (path.match(/^\/api\/prompts\/[^/]+\/evaluation-summary$/) && req.method === "GET") {
63452
- const promptId = path.split("/")[3];
63453
- const version2 = url.searchParams.get("version") ? parseInt(url.searchParams.get("version"), 10) : void 0;
63454
- if (version2 === void 0) {
63455
- this.json(res, 400, { error: "version query param is required" });
63456
- return;
63457
- }
63458
- const summary = this.promptStudio.getEvaluationSummary(promptId, version2);
63459
- this.json(res, 200, { summary });
63460
- return;
63461
- }
63462
63559
  if (path === "/api/system/open-path" && req.method === "POST") {
63463
63560
  try {
63464
63561
  const body = await this.readBody(req);
@@ -79362,6 +79459,9 @@ async function createServices(config) {
79362
79459
  taskService,
79363
79460
  mcpServers: config.mcpServers
79364
79461
  });
79462
+ if (config.agent?.maxToolIterations) {
79463
+ agentManager.maxToolIterations = config.agent.maxToolIterations;
79464
+ }
79365
79465
  taskService.setAgentManager(agentManager);
79366
79466
  const orgService = new OrganizationService(agentManager, roleLoader, storage ?? void 0);
79367
79467
  taskService.setOrgService(orgService);
@@ -79797,16 +79897,24 @@ async function startServer(config, values) {
79797
79897
  console.log(" Feishu integration enabled");
79798
79898
  }
79799
79899
  const webPort = config.server.webPort;
79800
- const webUiLine = webUiDir ? ` Web UI: http://localhost:${apiPort} (built-in)` : ` Web UI: http://localhost:${webPort} (run: pnpm --filter @markus/web-ui dev)`;
79801
- console.log(`
79900
+ if (webUiDir) {
79901
+ console.log(`
79902
+ Markus is running!
79903
+
79904
+ Dashboard: http://localhost:${apiPort}
79905
+
79906
+ Press Ctrl+C to stop.
79907
+ `);
79908
+ } else {
79909
+ console.log(`
79802
79910
  Markus is running!
79803
79911
 
79804
79912
  API Server: http://localhost:${apiPort}
79805
- ${webUiLine}
79806
- WebUI Comm: http://localhost:${commPort}
79913
+ Web UI: http://localhost:${webPort} (run: pnpm --filter @markus/web-ui dev)
79807
79914
 
79808
79915
  Press Ctrl+C to stop.
79809
79916
  `);
79917
+ }
79810
79918
  orgService.startRestoredAgentsInBackground();
79811
79919
  process.on("SIGINT", () => {
79812
79920
  console.log("\nShutting down...");