@jungjaehoon/mama-os 0.9.2 → 0.9.4

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 (139) hide show
  1. package/README.md +41 -7
  2. package/dist/agent/agent-loop.d.ts.map +1 -1
  3. package/dist/agent/agent-loop.js +2 -3
  4. package/dist/agent/agent-loop.js.map +1 -1
  5. package/dist/agent/claude-cli-wrapper.d.ts +4 -4
  6. package/dist/agent/claude-cli-wrapper.d.ts.map +1 -1
  7. package/dist/agent/claude-cli-wrapper.js +17 -5
  8. package/dist/agent/claude-cli-wrapper.js.map +1 -1
  9. package/dist/agent/claude-client.js +3 -3
  10. package/dist/agent/claude-client.js.map +1 -1
  11. package/dist/agent/codex-mcp-process.d.ts +10 -0
  12. package/dist/agent/codex-mcp-process.d.ts.map +1 -1
  13. package/dist/agent/codex-mcp-process.js +226 -58
  14. package/dist/agent/codex-mcp-process.js.map +1 -1
  15. package/dist/agent/gateway-tool-executor.d.ts +15 -1
  16. package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
  17. package/dist/agent/gateway-tool-executor.js +37 -3
  18. package/dist/agent/gateway-tool-executor.js.map +1 -1
  19. package/dist/agent/gateway-tools.md +1 -0
  20. package/dist/agent/persistent-cli-process.d.ts +2 -0
  21. package/dist/agent/persistent-cli-process.d.ts.map +1 -1
  22. package/dist/agent/persistent-cli-process.js +15 -0
  23. package/dist/agent/persistent-cli-process.js.map +1 -1
  24. package/dist/agent/types.d.ts +3 -3
  25. package/dist/agent/types.d.ts.map +1 -1
  26. package/dist/agent/types.js.map +1 -1
  27. package/dist/api/graph-api.d.ts.map +1 -1
  28. package/dist/api/graph-api.js +31 -5
  29. package/dist/api/graph-api.js.map +1 -1
  30. package/dist/cli/commands/start.d.ts.map +1 -1
  31. package/dist/cli/commands/start.js +91 -6
  32. package/dist/cli/commands/start.js.map +1 -1
  33. package/dist/cli/commands/stop.d.ts +7 -1
  34. package/dist/cli/commands/stop.d.ts.map +1 -1
  35. package/dist/cli/commands/stop.js +49 -0
  36. package/dist/cli/commands/stop.js.map +1 -1
  37. package/dist/cli/config/config-manager.d.ts.map +1 -1
  38. package/dist/cli/config/config-manager.js +60 -15
  39. package/dist/cli/config/config-manager.js.map +1 -1
  40. package/dist/cli/config/types.d.ts +19 -5
  41. package/dist/cli/config/types.d.ts.map +1 -1
  42. package/dist/cli/config/types.js +3 -3
  43. package/dist/cli/config/types.js.map +1 -1
  44. package/dist/gateways/image-analyzer.js +1 -1
  45. package/dist/gateways/image-analyzer.js.map +1 -1
  46. package/dist/gateways/slack.d.ts.map +1 -1
  47. package/dist/gateways/slack.js +8 -19
  48. package/dist/gateways/slack.js.map +1 -1
  49. package/dist/multi-agent/agent-process-manager.d.ts +15 -1
  50. package/dist/multi-agent/agent-process-manager.d.ts.map +1 -1
  51. package/dist/multi-agent/agent-process-manager.js +121 -22
  52. package/dist/multi-agent/agent-process-manager.js.map +1 -1
  53. package/dist/multi-agent/background-task-manager.d.ts +2 -2
  54. package/dist/multi-agent/background-task-manager.js +2 -2
  55. package/dist/multi-agent/bmad-templates.d.ts +67 -0
  56. package/dist/multi-agent/bmad-templates.d.ts.map +1 -0
  57. package/dist/multi-agent/bmad-templates.js +248 -0
  58. package/dist/multi-agent/bmad-templates.js.map +1 -0
  59. package/dist/multi-agent/council-engine.d.ts +60 -0
  60. package/dist/multi-agent/council-engine.d.ts.map +1 -0
  61. package/dist/multi-agent/council-engine.js +284 -0
  62. package/dist/multi-agent/council-engine.js.map +1 -0
  63. package/dist/multi-agent/multi-agent-base.d.ts +18 -9
  64. package/dist/multi-agent/multi-agent-base.d.ts.map +1 -1
  65. package/dist/multi-agent/multi-agent-base.js +116 -33
  66. package/dist/multi-agent/multi-agent-base.js.map +1 -1
  67. package/dist/multi-agent/multi-agent-discord.d.ts +3 -35
  68. package/dist/multi-agent/multi-agent-discord.d.ts.map +1 -1
  69. package/dist/multi-agent/multi-agent-discord.js +81 -302
  70. package/dist/multi-agent/multi-agent-discord.js.map +1 -1
  71. package/dist/multi-agent/multi-agent-slack.d.ts +2 -25
  72. package/dist/multi-agent/multi-agent-slack.d.ts.map +1 -1
  73. package/dist/multi-agent/multi-agent-slack.js +173 -253
  74. package/dist/multi-agent/multi-agent-slack.js.map +1 -1
  75. package/dist/multi-agent/runtime-process.d.ts +3 -0
  76. package/dist/multi-agent/runtime-process.d.ts.map +1 -1
  77. package/dist/multi-agent/runtime-process.js +4 -0
  78. package/dist/multi-agent/runtime-process.js.map +1 -1
  79. package/dist/multi-agent/shared-context.d.ts.map +1 -1
  80. package/dist/multi-agent/shared-context.js +4 -4
  81. package/dist/multi-agent/shared-context.js.map +1 -1
  82. package/dist/multi-agent/system-reminder.d.ts +1 -1
  83. package/dist/multi-agent/system-reminder.js +1 -1
  84. package/dist/multi-agent/types.d.ts +31 -15
  85. package/dist/multi-agent/types.d.ts.map +1 -1
  86. package/dist/multi-agent/types.js +1 -3
  87. package/dist/multi-agent/types.js.map +1 -1
  88. package/dist/multi-agent/ultrawork-state.d.ts +57 -0
  89. package/dist/multi-agent/ultrawork-state.d.ts.map +1 -0
  90. package/dist/multi-agent/ultrawork-state.js +191 -0
  91. package/dist/multi-agent/ultrawork-state.js.map +1 -0
  92. package/dist/multi-agent/ultrawork.d.ts +37 -19
  93. package/dist/multi-agent/ultrawork.d.ts.map +1 -1
  94. package/dist/multi-agent/ultrawork.js +587 -41
  95. package/dist/multi-agent/ultrawork.js.map +1 -1
  96. package/dist/multi-agent/workflow-engine.d.ts +7 -0
  97. package/dist/multi-agent/workflow-engine.d.ts.map +1 -1
  98. package/dist/multi-agent/workflow-engine.js +238 -33
  99. package/dist/multi-agent/workflow-engine.js.map +1 -1
  100. package/dist/multi-agent/workflow-types.d.ts +74 -1
  101. package/dist/multi-agent/workflow-types.d.ts.map +1 -1
  102. package/dist/onboarding/complete-autonomous-prompt.d.ts +1 -1
  103. package/dist/onboarding/complete-autonomous-prompt.d.ts.map +1 -1
  104. package/dist/onboarding/complete-autonomous-prompt.js +27 -10
  105. package/dist/onboarding/complete-autonomous-prompt.js.map +1 -1
  106. package/dist/onboarding/phase-7-integrations.d.ts.map +1 -1
  107. package/dist/onboarding/phase-7-integrations.js +23 -3
  108. package/dist/onboarding/phase-7-integrations.js.map +1 -1
  109. package/dist/onboarding/phase-9-finalization.d.ts.map +1 -1
  110. package/dist/onboarding/phase-9-finalization.js +33 -0
  111. package/dist/onboarding/phase-9-finalization.js.map +1 -1
  112. package/dist/setup/setup-prompt.d.ts +1 -1
  113. package/dist/setup/setup-prompt.d.ts.map +1 -1
  114. package/dist/setup/setup-prompt.js +1 -1
  115. package/package.json +1 -1
  116. package/public/viewer/js/modules/settings.js +110 -15
  117. package/public/viewer/js/utils/format.js +10 -7
  118. package/public/viewer/src/modules/settings.ts +133 -16
  119. package/public/viewer/src/utils/api.ts +2 -1
  120. package/public/viewer/src/utils/format.ts +10 -7
  121. package/public/viewer/viewer.html +1 -0
  122. package/templates/bmad/LICENSE +28 -0
  123. package/templates/bmad/architecture.md +343 -0
  124. package/templates/bmad/bmm-workflow-status.template.yaml +66 -0
  125. package/templates/bmad/prd.md +198 -0
  126. package/templates/bmad/product-brief.md +149 -0
  127. package/templates/bmad/sprint-status.template.yaml +35 -0
  128. package/templates/bmad/tech-spec.md +151 -0
  129. package/templates/personas/architect.md +70 -0
  130. package/templates/personas/conductor.md +373 -0
  131. package/templates/personas/developer.md +20 -7
  132. package/templates/personas/pm.md +49 -33
  133. package/templates/personas/reviewer.md +18 -5
  134. package/dist/multi-agent/pr-review-poller.d.ts +0 -197
  135. package/dist/multi-agent/pr-review-poller.d.ts.map +0 -1
  136. package/dist/multi-agent/pr-review-poller.js +0 -972
  137. package/dist/multi-agent/pr-review-poller.js.map +0 -1
  138. package/templates/personas/sisyphus-builtin-en.md +0 -161
  139. package/templates/personas/sisyphus.md +0 -218
@@ -45,7 +45,6 @@ const message_splitter_js_1 = require("../gateways/message-splitter.js");
45
45
  const delegation_format_validator_js_1 = require("./delegation-format-validator.js");
46
46
  const channel_history_js_1 = require("../gateways/channel-history.js");
47
47
  const prompt_enhancer_js_1 = require("../agent/prompt-enhancer.js");
48
- const pr_review_poller_js_1 = require("./pr-review-poller.js");
49
48
  const child_process_1 = require("child_process");
50
49
  const util_1 = require("util");
51
50
  const debugLogger = __importStar(require("@jungjaehoon/mama-core/debug-logger"));
@@ -97,16 +96,8 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
97
96
  historyInjected = new Set();
98
97
  /** Cleanup interval handle for periodic tasks */
99
98
  cleanupInterval = null;
100
- /** PR poller summaries per channel for LEAD wake-up */
101
- prPollerSummaries = new Map();
102
- /** Tracks channels where APPROVE+commit was processed (prevents congratulation loops) */
103
- approveProcessedChannels = new Map();
104
- /** APPROVE cooldown period -- blocks agent-to-agent routing after commit (30 seconds) */
105
- static APPROVE_COOLDOWN_MS = 30 * 1000;
106
99
  /** Cleanup interval period (1 minute) */
107
100
  static CLEANUP_INTERVAL_MS = 60_000;
108
- /** PR review chain override (allows LEAD → DEV → REVIEWER → LEAD) */
109
- static PR_REVIEW_MAX_CHAIN = 6;
110
101
  constructor(config, processOptions = {}, runtimeOptions = {}) {
111
102
  super(config, processOptions, runtimeOptions);
112
103
  this.multiBotManager = new multi_bot_manager_js_1.MultiBotManager(config);
@@ -115,7 +106,6 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
115
106
  this.cleanupInterval = setInterval(() => {
116
107
  this.messageQueue.clearExpired();
117
108
  this.cleanupProcessedMentions();
118
- this.cleanupApproveChannels();
119
109
  }, MultiAgentDiscordHandler.CLEANUP_INTERVAL_MS);
120
110
  // Setup idle event listeners for all agents (F7)
121
111
  this.setupIdleListeners();
@@ -193,15 +183,6 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
193
183
  if (this.processedMentions.has(dedupKey))
194
184
  return;
195
185
  this.processedMentions.set(dedupKey, Date.now());
196
- // Block agent-to-LEAD mentions during post-APPROVE cooldown
197
- // Only blocks mentions targeting the default (LEAD) agent -- not other agents like DEV
198
- const approveCooldown = this.approveProcessedChannels.get(message.channel.id);
199
- if (message.author.bot &&
200
- approveCooldown &&
201
- Date.now() - approveCooldown < MultiAgentDiscordHandler.APPROVE_COOLDOWN_MS &&
202
- agentId === this.config.default_agent) {
203
- return;
204
- }
205
186
  const cleanContent = message.content.replace(/<@!?\d+>/g, '').trim();
206
187
  if (!cleanContent)
207
188
  return;
@@ -213,7 +194,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
213
194
  // Chain depth check for mention_delegation
214
195
  if (isFromAgent && senderAgentId && senderAgentId !== 'main') {
215
196
  const chainState = this.orchestrator.getChainState(message.channel.id);
216
- const maxDepth = this.getEffectiveMaxMentionDepth(message.channel.id);
197
+ const maxDepth = this.getEffectiveMaxMentionDepth();
217
198
  if (chainState.blocked) {
218
199
  logger.info(`[MultiAgent] Mention chain blocked in channel ${message.channel.id}, ignoring`);
219
200
  return;
@@ -300,7 +281,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
300
281
  if (this.config.mention_delegation) {
301
282
  const botUserIdMap = this.multiBotManager.getBotUserIdMap();
302
283
  // Include LEAD (default agent) which uses the main bot token
303
- // Without this, @Sisyphus in other agents' personas won't resolve to <@userId>
284
+ // Without this, @Conductor in other agents' personas won't resolve to <@userId>
304
285
  const defaultAgentId = this.config.default_agent;
305
286
  if (defaultAgentId && !botUserIdMap.has(defaultAgentId)) {
306
287
  const mainBotUserId = this.multiBotManager.getMainBotUserId();
@@ -311,16 +292,6 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
311
292
  this.processManager.setBotUserIdMap(botUserIdMap);
312
293
  this.processManager.setMentionDelegation(true);
313
294
  logger.info(`[MultiAgent] Mention delegation enabled with ${botUserIdMap.size} bot IDs`);
314
- if (this.isPrReviewPollingEnabled()) {
315
- // PR Review Poller: target LEAD directly.
316
- // LEAD analyzes → delegates to DevBot → DevBot fixes → Reviewer reviews after.
317
- const orchestratorId = defaultAgentId || 'sisyphus';
318
- const orchestratorUserId = botUserIdMap.get(orchestratorId);
319
- if (orchestratorUserId) {
320
- this.prReviewPoller.setTargetAgentUserId(orchestratorUserId);
321
- logger.info(`[MultiAgent] PR Poller target: ${orchestratorId} (LEAD)`);
322
- }
323
- }
324
295
  }
325
296
  }
326
297
  /**
@@ -354,109 +325,6 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
354
325
  }
355
326
  }
356
327
  }, 'discord');
357
- if (this.isPrReviewPollingEnabled()) {
358
- // Capture compact batch summaries so LEAD receives actionable context.
359
- this.prReviewPoller.setMessageSender(async () => { });
360
- this.prReviewPoller.setOnBatchItem(async (channelId, summary, item) => {
361
- const bucket = this.prPollerSummaries.get(channelId) ?? [];
362
- const compact = this.compactPrReviewBatchSummary(summary);
363
- if (!compact || bucket.some((candidate) => candidate.id === item.id)) {
364
- return;
365
- }
366
- const merged = {
367
- ...item,
368
- summary: compact,
369
- };
370
- // Keep bounded for prompt size and avoid repeats within one poll batch.
371
- this.prPollerSummaries.set(channelId, [...bucket, merged].slice(-12));
372
- });
373
- // After poll cycle: post count to channel and wake up PR workflow agents.
374
- this.prReviewPoller.setOnBatchComplete(async (channelId, digest) => {
375
- const items = (digest?.items && digest.items.length > 0
376
- ? digest.items
377
- : this.prPollerSummaries.get(channelId)) ?? [];
378
- if (items.length === 0) {
379
- return;
380
- }
381
- const actionItems = digest?.newItems ?? items.filter((item) => !item.isReminder);
382
- const reminderItems = digest?.reminderItems ?? items.filter((item) => item.isReminder);
383
- const allActionable = actionItems.length > 0;
384
- const count = items.length;
385
- if (!allActionable) {
386
- this.prPollerSummaries.delete(channelId);
387
- return;
388
- }
389
- const compactItems = items.map((item, idx) => `- ${idx + 1}. [${item.severity}] ${item.summary}`);
390
- const summaryLines = compactItems.join('\n');
391
- const sessions = this.prReviewPoller.getSessionDetails();
392
- const session = sessions.find((s) => s.channelId === channelId);
393
- if (!session) {
394
- // Clean up stale summary to prevent memory leak
395
- this.prPollerSummaries.delete(channelId);
396
- return;
397
- }
398
- const prLabel = `${session.owner}/${session.repo}#${session.prNumber}`;
399
- const promptSummary = `\n${summaryLines}`;
400
- const reminderSummary = reminderItems.length > 0 ? `\nšŸ”” Reminders only: ${reminderItems.length} item(s).` : '';
401
- this.prPollerSummaries.delete(channelId);
402
- // Post summary to channel (visible to humans)
403
- const channel = await client.channels.fetch(channelId);
404
- if (channel && 'send' in channel) {
405
- const content = `šŸ“Š PR ${prLabel} — ${count} new review item(s)\n\n${promptSummary}${reminderSummary}`;
406
- const chunks = (0, message_splitter_js_1.splitForDiscord)(content);
407
- for (const chunk of chunks) {
408
- await channel.send({
409
- content: chunk,
410
- });
411
- }
412
- }
413
- // Wake up LEAD with compact PR summary + workspace path.
414
- this.orchestrator.resetChain(channelId);
415
- const defaultAgentId = this.config.default_agent || 'sisyphus';
416
- const workspace = `\`${session.workspaceDir}\``;
417
- const workflowPrompt = `šŸ“Š PR Review follow-up (${count} new item(s))`;
418
- const taskContext = `Target: ${prLabel}\nWorkspace: ${workspace}\n`;
419
- const itemsContext = `Items:\n${summaryLines}`;
420
- const basePrompt = `${workflowPrompt}\n${taskContext}${itemsContext}${reminderSummary}`;
421
- this.messageQueue.enqueue(defaultAgentId, {
422
- prompt: `${basePrompt}\n\nClassify severity, implement fixable items, and coordinate with Dev/Reviewer.`,
423
- channelId,
424
- source: 'discord',
425
- enqueuedAt: Date.now(),
426
- context: { channelId, userId: 'pr-poller' },
427
- });
428
- logger.info(`[MultiAgent] PR Poller -> LEAD wake-up (${count} items)`);
429
- this.tryDrainNow(defaultAgentId, 'discord', channelId).catch(() => { });
430
- // Wake implementation/review agents in parallel so review loop can proceed autonomously.
431
- const helperAgents = this.resolvePrReviewAssistants(defaultAgentId);
432
- for (const helperAgentId of helperAgents) {
433
- const helperPrompt = helperAgentId === 'developer'
434
- ? `${basePrompt}\n\nImplement available fixes in the workspace and request Reviewer verification when changes are made.`
435
- : `${basePrompt}\n\nInspect the comments for correctness issues and provide reviewer guidance.`;
436
- this.messageQueue.enqueue(helperAgentId, {
437
- prompt: helperPrompt,
438
- channelId,
439
- source: 'discord',
440
- enqueuedAt: Date.now(),
441
- context: { channelId, userId: 'pr-poller' },
442
- });
443
- logger.info(`[MultiAgent] PR Poller -> ${helperAgentId} wake-up (${count} items)`);
444
- this.tryDrainNow(helperAgentId, 'discord', channelId).catch(() => { });
445
- }
446
- });
447
- logger.info('[MultiAgent] PR Review Poller message sender configured for Discord');
448
- }
449
- }
450
- /**
451
- * Keep PR poller summaries short and remove duplicates.
452
- */
453
- compactPrReviewBatchSummary(summary) {
454
- const compact = summary.replace(/[\r\n]+/g, ' ').trim();
455
- const max = 230;
456
- if (!compact) {
457
- return '';
458
- }
459
- return compact.length > max ? `${compact.slice(0, max)}…` : compact;
460
328
  }
461
329
  /**
462
330
  * Set main bot token (to avoid duplicate logins in MultiBotManager)
@@ -472,10 +340,6 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
472
340
  this.orchestrator.updateConfig(config);
473
341
  this.processManager.updateConfig(config);
474
342
  this.multiBotManager.updateConfig(config);
475
- if (!this.isPrReviewPollingEnabled()) {
476
- this.prReviewPoller.stopAll();
477
- this.prPollerSummaries.clear();
478
- }
479
343
  }
480
344
  /**
481
345
  * Handle a Discord message with multi-agent logic
@@ -490,14 +354,9 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
490
354
  }
491
355
  // Build message context
492
356
  const context = this.buildMessageContext(message, cleanContent);
493
- this.updateChainOverrideForChannel(context.channelId);
494
357
  // Record human message to shared context
495
358
  if (!context.isBot) {
496
359
  this.sharedContext.recordHumanMessage(context.channelId, message.author.username, cleanContent, message.id);
497
- if (this.isPrReviewPollingEnabled()) {
498
- // Auto-detect PR URLs in user messages and start polling
499
- this.detectAndPollPRUrls(cleanContent, context.channelId, message);
500
- }
501
360
  }
502
361
  // Select responding agents
503
362
  const selection = this.orchestrator.selectRespondingAgents(context);
@@ -532,10 +391,6 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
532
391
  if (responses.length === 0) {
533
392
  return null;
534
393
  }
535
- // Auto-detect PR URLs in agent responses and start polling
536
- for (const resp of responses) {
537
- this.detectAndPollPRUrls(resp.rawContent, context.channelId, message);
538
- }
539
394
  return {
540
395
  selectedAgents: selection.selectedAgents,
541
396
  reason: selection.reason,
@@ -637,7 +492,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
637
492
  // Inject agent availability status, active work, and channel context (Phase 2 + 3)
638
493
  const agentStatus = this.buildAgentStatusSection(agentId);
639
494
  const workSection = this.workTracker.buildWorkSection(agentId);
640
- const channelInfo = `## Current Channel\nDiscord channel_id: ${context.channelId}`;
495
+ const channelInfo = `## Current Channel\nPlatform: Discord\nchannel_id: ${context.channelId}\nUse **discord_send** to send messages/files to this channel.`;
641
496
  const dynamicContextRaw = [agentStatus, workSection, channelInfo].filter(Boolean).join('\n');
642
497
  const dynamicContext = dynamicContextRaw.length > MAX_DYNAMIC_CONTEXT_CHARS
643
498
  ? `${dynamicContextRaw.slice(0, MAX_DYNAMIC_CONTEXT_CHARS)}\n...`
@@ -808,21 +663,41 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
808
663
  }
809
664
  let msg = '';
810
665
  const modelTag = event.agentModel ? ` [${event.agentModel}]` : '';
666
+ const progress = event.totalSteps && event.completedSteps !== undefined
667
+ ? ` [${event.completedSteps}/${event.totalSteps}]`
668
+ : '';
811
669
  if (event.type === 'step-started') {
812
- msg = ` ${event.agentDisplayName}${modelTag} ģ‹œģž‘...`;
670
+ msg = ` ${event.agentDisplayName}${modelTag}${progress} ģ‹œģž‘...`;
813
671
  }
814
672
  else if (event.type === 'step-completed') {
815
673
  const sec = event.duration_ms ? Math.round(event.duration_ms / 1000) : 0;
816
- msg = `${event.agentDisplayName}${modelTag} (${sec}s) ģ™„ė£Œ`;
674
+ const pct = event.totalSteps && event.completedSteps !== undefined
675
+ ? ` (${Math.round((event.completedSteps / event.totalSteps) * 100)}%)`
676
+ : '';
677
+ msg = `${event.agentDisplayName}${modelTag} (${sec}s)${pct} ģ™„ė£Œ`;
817
678
  }
818
679
  else if (event.type === 'step-failed') {
819
- msg = `${event.agentDisplayName}${modelTag} āŒ ģ‹¤ķŒØ: ${event.error?.substring(0, 100)}`;
680
+ msg = `${event.agentDisplayName}${modelTag}${progress} āŒ ģ‹¤ķŒØ: ${event.error?.substring(0, 100)}`;
820
681
  }
821
682
  if (msg) {
822
683
  this.sendChannelNotification(context.channelId, msg).catch(() => { });
823
684
  }
824
685
  });
825
686
  if (workflowResult) {
687
+ if (workflowResult.failed) {
688
+ this.logger.warn(`[MultiAgentDiscord] Workflow failed: ${workflowResult.failed}, sending feedback to conductor`);
689
+ const feedback = `[SYSTEM] Your workflow_plan failed to execute.\nReason: ${workflowResult.failed}\nPlease adjust and retry, or respond without a workflow_plan.`;
690
+ const retryResult = await agentProcess.sendMessage(feedback);
691
+ const cleanedRetry = await this.executeAgentToolCalls(agentId, retryResult.response);
692
+ const formattedResponse = this.formatAgentResponse(agent, cleanedRetry);
693
+ return {
694
+ agentId,
695
+ agent,
696
+ content: formattedResponse,
697
+ rawContent: cleanedRetry,
698
+ duration: Date.now() - workflowStart + (result.duration_ms ?? 0),
699
+ };
700
+ }
826
701
  const display = workflowResult.directMessage
827
702
  ? `${workflowResult.directMessage}\n\n${workflowResult.result}`
828
703
  : workflowResult.result;
@@ -836,7 +711,47 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
836
711
  duration: totalDuration,
837
712
  };
838
713
  }
839
- const cleanedResponse = await this.executeAgentToolCalls(agentId, result.response);
714
+ // Check for council plan (after workflow, before tool calls)
715
+ const councilResult = await this.tryExecuteCouncil(result.response, context.channelId, 'discord', (event) => {
716
+ if (!this.discordClient)
717
+ return;
718
+ let msg = '';
719
+ if (event.type === 'council-round-started') {
720
+ msg = `šŸ—£ļø ${event.agentDisplayName} Round ${event.round} ģ‹œģž‘...`;
721
+ }
722
+ else if (event.type === 'council-round-completed') {
723
+ const sec = event.duration_ms ? Math.round(event.duration_ms / 1000) : 0;
724
+ msg = `šŸ—£ļø ${event.agentDisplayName} Round ${event.round} (${sec}s) ģ™„ė£Œ`;
725
+ }
726
+ else if (event.type === 'council-round-failed') {
727
+ msg = `šŸ—£ļø ${event.agentDisplayName} Round ${event.round} āŒ ģ‹¤ķŒØ: ${event.error?.substring(0, 100)}`;
728
+ }
729
+ if (msg) {
730
+ this.sendChannelNotification(context.channelId, msg).catch(() => { });
731
+ }
732
+ });
733
+ if (councilResult) {
734
+ const display = councilResult.directMessage
735
+ ? `${councilResult.directMessage}\n\n${councilResult.result}`
736
+ : councilResult.result;
737
+ const formattedResponse = this.formatAgentResponse(agent, display);
738
+ return {
739
+ agentId,
740
+ agent,
741
+ content: formattedResponse,
742
+ rawContent: display,
743
+ duration: Date.now() - workflowStart + (result.duration_ms ?? 0),
744
+ };
745
+ }
746
+ // Strip any workflow/council plan JSON that wasn't executed
747
+ let responseForProcessing = result.response;
748
+ if (this.workflowEngine?.isEnabled()) {
749
+ responseForProcessing = this.workflowEngine.extractNonPlanContent(responseForProcessing);
750
+ }
751
+ if (this.councilEngine) {
752
+ responseForProcessing = this.councilEngine.extractNonPlanContent(responseForProcessing);
753
+ }
754
+ const cleanedResponse = await this.executeAgentToolCalls(agentId, responseForProcessing);
840
755
  // Detect API error responses — skip mention resolution and delegation to prevent error loops
841
756
  const isErrorResponse = /API Error:\s*\d{3}\b/.test(cleanedResponse);
842
757
  const resolvedResponse = isErrorResponse
@@ -849,8 +764,9 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
849
764
  let submittedCount = 0;
850
765
  const submittedAgents = [];
851
766
  for (const delegation of bgDelegations) {
852
- if (!delegation.background)
767
+ if (!delegation.background) {
853
768
  continue;
769
+ }
854
770
  const check = this.delegationManager.isDelegationAllowed(delegation.fromAgentId, delegation.toAgentId);
855
771
  if (check.allowed) {
856
772
  this.backgroundTaskManager.submit({
@@ -975,8 +891,9 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
975
891
  if (delegations.length > 0 && hasBackground) {
976
892
  let submittedCount = 0;
977
893
  for (const delegation of delegations) {
978
- if (!delegation.background)
894
+ if (!delegation.background) {
979
895
  continue;
896
+ }
980
897
  const check = this.delegationManager.isDelegationAllowed(delegation.fromAgentId, delegation.toAgentId);
981
898
  if (check.allowed) {
982
899
  this.backgroundTaskManager.submit({
@@ -1119,7 +1036,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
1119
1036
  console.error(`[MultiAgent] Failed to send response for agent ${response.agentId}:`, err);
1120
1037
  }
1121
1038
  }
1122
- // Post-send: Auto-review trigger for default agent (Armed Sisyphus) self-implementations
1039
+ // Post-send: Auto-review trigger for default agent (Armed Conductor) self-implementations
1123
1040
  const defaultAgentId = this.config.default_agent;
1124
1041
  if (defaultAgentId) {
1125
1042
  const selfImplemented = responses.find((r) => r.agentId === defaultAgentId && this.detectSelfImplementation(r.rawContent));
@@ -1130,7 +1047,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
1130
1047
  return sentMessages;
1131
1048
  }
1132
1049
  /**
1133
- * Detect if the default agent (Sisyphus) performed direct code edits.
1050
+ * Detect if the default agent (Conductor) performed direct code edits.
1134
1051
  * Checks for Claude CLI tool-use markers that indicate Edit/Write operations.
1135
1052
  */
1136
1053
  detectSelfImplementation(rawContent) {
@@ -1149,7 +1066,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
1149
1066
  return editIndicators.some((pattern) => pattern.test(rawContent));
1150
1067
  }
1151
1068
  /**
1152
- * Check git diff size after Sisyphus self-implementation.
1069
+ * Check git diff size after Conductor self-implementation.
1153
1070
  * If diff exceeds thresholds, auto-trigger Reviewer for quality gate.
1154
1071
  *
1155
1072
  * Thresholds (PAIR mode auto-escalation):
@@ -1189,7 +1106,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
1189
1106
  }
1190
1107
  }
1191
1108
  if (filesChanged > MAX_FILES || totalLines > MAX_LINES) {
1192
- logger.info(`[AutoReview] Sisyphus self-implementation exceeded thresholds: ${filesChanged} files, ${totalLines} lines -> auto-triggering Reviewer`);
1109
+ logger.info(`[AutoReview] Conductor self-implementation exceeded thresholds: ${filesChanged} files, ${totalLines} lines -> auto-triggering Reviewer`);
1193
1110
  // Find reviewer agent using shared helper
1194
1111
  const reviewerEntry = this.findReviewerAgent();
1195
1112
  const reviewerAgentId = reviewerEntry?.[0];
@@ -1199,7 +1116,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
1199
1116
  }
1200
1117
  }
1201
1118
  else {
1202
- logger.info(`[AutoReview] Sisyphus self-implementation within thresholds: ${filesChanged} files, ${totalLines} lines -- no auto-review needed`);
1119
+ logger.info(`[AutoReview] Conductor self-implementation within thresholds: ${filesChanged} files, ${totalLines} lines -- no auto-review needed`);
1203
1120
  }
1204
1121
  }
1205
1122
  catch {
@@ -1256,33 +1173,14 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
1256
1173
  }
1257
1174
  }
1258
1175
  logger.info(`[MultiAgent] Auto-routing mentions from ${response.agentId}: -> ${mentionedAgentIds.join(', ')}`);
1259
- const defaultAgentId = this.config.default_agent;
1260
- const hasApproveSignal = /\b(APPROVE[DS]?|LGTM)\b/i.test(response.rawContent) &&
1261
- !/\b(not?\s+approve|don'?t\s+approve|cannot\s+approve|rejected)\b/i.test(response.rawContent);
1262
- const isReviewerApproveToLead = this.isReviewerAgent(response.agentId) &&
1263
- mentionedAgentIds.includes(defaultAgentId || '') &&
1264
- hasApproveSignal;
1265
- if (isReviewerApproveToLead) {
1266
- // Dedup: skip if APPROVE already processed for this channel
1267
- const lastApprove = this.approveProcessedChannels.get(originalMessage.channel.id);
1268
- if (lastApprove &&
1269
- Date.now() - lastApprove < MultiAgentDiscordHandler.APPROVE_COOLDOWN_MS) {
1270
- logger.info(`[MultiAgent] APPROVE already processed for ${originalMessage.channel.id}, skipping`);
1271
- continue;
1272
- }
1273
- }
1274
1176
  // Route to all mentioned agents in parallel
1275
- await Promise.all(mentionedAgentIds.map((targetAgentId) => this.handleDelegatedMention(targetAgentId, originalMessage, response, isReviewerApproveToLead ? 'REVIEWER_APPROVED' : null)));
1276
- // Set APPROVE cooldown AFTER routing to LEAD (so LEAD gets the first one)
1277
- if (isReviewerApproveToLead) {
1278
- this.approveProcessedChannels.set(originalMessage.channel.id, Date.now());
1279
- }
1177
+ await Promise.all(mentionedAgentIds.map((targetAgentId) => this.handleDelegatedMention(targetAgentId, originalMessage, response)));
1280
1178
  }
1281
1179
  }
1282
1180
  /**
1283
1181
  * Handle a delegated mention: process target agent response and recursively route.
1284
1182
  */
1285
- async handleDelegatedMention(targetAgentId, originalMessage, sourceResponse, reviewerSignal) {
1183
+ async handleDelegatedMention(targetAgentId, originalMessage, sourceResponse) {
1286
1184
  // Dedup: prevent double processing
1287
1185
  const dedupKey = `${targetAgentId}:${sourceResponse.messageId || originalMessage.id}`;
1288
1186
  if (this.processedMentions.has(dedupKey))
@@ -1333,16 +1231,10 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
1333
1231
  channelId,
1334
1232
  timestamp: Date.now(),
1335
1233
  });
1336
- let delegationContent = sourceResponse.rawContent
1234
+ const delegationContent = sourceResponse.rawContent
1337
1235
  .replace(/<@!?\d+>/g, '')
1338
1236
  .replace(/DELEGATE(?:_BG)?::[\w-]+::/g, '')
1339
1237
  .trim();
1340
- if (reviewerSignal === 'REVIEWER_APPROVED' && targetAgentId === this.config.default_agent) {
1341
- delegationContent +=
1342
- '\n\nšŸ”” [SYSTEM] Reviewer has APPROVED the changes.\n' +
1343
- 'Review the changes yourself, then commit and push when you are satisfied.\n' +
1344
- 'Use your judgement on the commit message and which files to include.';
1345
- }
1346
1238
  try {
1347
1239
  const response = await this.processAgentResponse(targetAgentId, {
1348
1240
  channelId,
@@ -1455,7 +1347,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
1455
1347
  }
1456
1348
  /**
1457
1349
  * Resolve @Name mentions in LLM response text to <@userId> Discord format.
1458
- * LLMs generate plain text like "@LEAD", "@Sisyphus", "@DevBot" which won't
1350
+ * LLMs generate plain text like "@LEAD", "@Conductor", "@DevBot" which won't
1459
1351
  * trigger Discord mentions or routeResponseMentions detection.
1460
1352
  */
1461
1353
  resolveResponseMentions(text) {
@@ -1503,122 +1395,9 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
1503
1395
  }
1504
1396
  return resolved;
1505
1397
  }
1506
- cleanupApproveChannels() {
1507
- const now = Date.now();
1508
- for (const [channelId, ts] of this.approveProcessedChannels) {
1509
- if (now - ts > MultiAgentDiscordHandler.APPROVE_COOLDOWN_MS) {
1510
- this.approveProcessedChannels.delete(channelId);
1511
- }
1512
- }
1513
- }
1514
- /**
1515
- * Detect PR URLs in text and auto-start polling.
1516
- * Sends a notification to the channel when polling starts.
1517
- */
1518
- detectAndPollPRUrls(text, channelId, message) {
1519
- if (!this.isPrReviewPollingEnabled())
1520
- return;
1521
- const prUrls = pr_review_poller_js_1.PRReviewPoller.extractPRUrls(text);
1522
- if (prUrls.length === 0)
1523
- return;
1524
- for (const prUrl of prUrls) {
1525
- this.prReviewPoller
1526
- .startPolling(prUrl, channelId)
1527
- .then((started) => {
1528
- const parsed = this.prReviewPoller.parsePRUrl(prUrl);
1529
- const key = parsed ? `${parsed.owner}/${parsed.repo}#${parsed.prNumber}` : prUrl;
1530
- if (started) {
1531
- this.updateChainOverrideForChannel(channelId);
1532
- if ('send' in message.channel) {
1533
- message.channel
1534
- .send({
1535
- content: `šŸ‘€ **PR Review Poller Started** -- ${key}\nDetecting new review comments every 60 seconds.`,
1536
- })
1537
- .catch((err) => {
1538
- console.warn(`[MultiAgent] Failed to send PR polling start message to Discord channel ${channelId}:`, err?.message || err);
1539
- });
1540
- }
1541
- logger.info(`[MultiAgent] PR Poller started for ${key} in Discord channel ${channelId}`);
1542
- }
1543
- else {
1544
- if ('send' in message.channel) {
1545
- message.channel
1546
- .send({
1547
- content: `ā„¹ļø PR Review Poller is already active for ${key}.`,
1548
- })
1549
- .catch((err) => {
1550
- console.warn(`[MultiAgent] Failed to send PR polling already-running message to Discord channel ${channelId}:`, err?.message || err);
1551
- });
1552
- }
1553
- }
1554
- })
1555
- .catch((err) => {
1556
- console.error(`[MultiAgent] Failed to start PR polling:`, err);
1557
- if ('send' in message.channel) {
1558
- message.channel
1559
- .send({
1560
- content: `āš ļø Failed to start PR Review Poller for ${prUrl}: ${String(err)}`,
1561
- })
1562
- .catch((sendErr) => {
1563
- console.warn(`[MultiAgent] Failed to send PR polling error message to Discord channel ${channelId}:`, sendErr?.message || sendErr);
1564
- });
1565
- }
1566
- });
1567
- }
1568
- }
1569
- /**
1570
- * Resolve helper agents for PR review workflow in addition to default lead.
1571
- */
1572
- resolvePrReviewAssistants(defaultAgentId) {
1573
- const candidateIds = ['developer', 'reviewer', 'dev', 'lead'];
1574
- const helperAgents = [];
1575
- for (const id of candidateIds) {
1576
- const cfg = this.config.agents[id];
1577
- if (!cfg || id === defaultAgentId) {
1578
- continue;
1579
- }
1580
- if (cfg.enabled === false) {
1581
- continue;
1582
- }
1583
- helperAgents.push(id);
1584
- }
1585
- return [...new Set(helperAgents)];
1586
- }
1587
- /**
1588
- * Update chain/mention depth overrides when PR review polling is active.
1589
- */
1590
- updateChainOverrideForChannel(channelId) {
1591
- if (this.isPrReviewActive(channelId)) {
1592
- this.orchestrator.setChannelChainLimit(channelId, MultiAgentDiscordHandler.PR_REVIEW_MAX_CHAIN);
1593
- }
1594
- else {
1595
- this.orchestrator.clearChannelChainLimit(channelId);
1596
- }
1597
- }
1598
- getEffectiveMaxMentionDepth(channelId) {
1599
- if (this.isPrReviewActive(channelId)) {
1600
- return MultiAgentDiscordHandler.PR_REVIEW_MAX_CHAIN;
1601
- }
1398
+ getEffectiveMaxMentionDepth() {
1602
1399
  return this.config.max_mention_depth ?? 3;
1603
1400
  }
1604
- isPrReviewActive(channelId) {
1605
- if (!this.isPrReviewPollingEnabled()) {
1606
- return false;
1607
- }
1608
- return this.prReviewPoller
1609
- .getSessionDetails()
1610
- .some((session) => session.channelId === channelId);
1611
- }
1612
- isPrReviewPollingEnabled() {
1613
- return this.config.pr_review_poller?.enabled === true;
1614
- }
1615
- /**
1616
- * Check if an agent ID is the reviewer agent
1617
- */
1618
- isReviewerAgent(agentId) {
1619
- return (agentId.toLowerCase().includes('review') ||
1620
- this.config.agents[agentId]?.name?.toLowerCase().includes('review') === true);
1621
- }
1622
1401
  /**
1623
1402
  * Find the reviewer agent entry from config
1624
1403
  */