@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
@@ -14,9 +14,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.MultiAgentSlackHandler = void 0;
15
15
  const slack_multi_bot_manager_js_1 = require("./slack-multi-bot-manager.js");
16
16
  const message_splitter_js_1 = require("../gateways/message-splitter.js");
17
- const pr_review_poller_js_1 = require("./pr-review-poller.js");
18
17
  const delegation_format_validator_js_1 = require("./delegation-format-validator.js");
19
18
  const log_sanitizer_js_1 = require("../utils/log-sanitizer.js");
19
+ const channel_history_js_1 = require("../gateways/channel-history.js");
20
20
  const multi_agent_base_js_1 = require("./multi-agent-base.js");
21
21
  /** Heartbeat interval for status polling (60 seconds) */
22
22
  const HEARTBEAT_INTERVAL_MS = 60 * 1000;
@@ -41,10 +41,10 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
41
41
  heartbeatChannelId = null;
42
42
  /** Heartbeat polling interval handle */
43
43
  heartbeatInterval;
44
- /** PR poller summaries by channel for LEAD wake-up context. */
45
- prPollerSummaries = new Map();
46
44
  /** Interval handle for periodic cleanup */
47
45
  mentionCleanupInterval;
46
+ /** Tracks the process used for history seeding per agent:channel */
47
+ historySeedProcess = new Map();
48
48
  constructor(config, processOptions = {}, runtimeOptions = {}) {
49
49
  super(config, processOptions, runtimeOptions);
50
50
  this.multiBotManager = new slack_multi_bot_manager_js_1.SlackMultiBotManager(config);
@@ -83,7 +83,7 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
83
83
  const userId = match[1];
84
84
  const agentId = this.multiBotManager.resolveAgentIdFromUserId(userId);
85
85
  if (agentId) {
86
- // Resolve 'main' to the actual agent ID (e.g., 'sisyphus')
86
+ // Resolve 'main' to the actual agent ID (e.g., 'conductor')
87
87
  const resolvedId = agentId === 'main' ? (this.multiBotManager.getMainBotAgentId() ?? agentId) : agentId;
88
88
  agentIds.push(resolvedId);
89
89
  }
@@ -96,6 +96,7 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
96
96
  clearInterval(this.mentionCleanupInterval);
97
97
  this.mentionCleanupInterval = undefined;
98
98
  }
99
+ this.historySeedProcess.clear();
99
100
  await this.multiBotManager.stopAll();
100
101
  }
101
102
  /**
@@ -185,131 +186,6 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
185
186
  this.processManager.setMentionDelegation(true);
186
187
  this.logger.log(`[MultiAgentSlack] Mention delegation enabled with ${botUserIdMap.size} bot IDs`);
187
188
  }
188
- // Configure PR poller wiring (if enabled)
189
- this.configurePrPoller();
190
- }
191
- /**
192
- * Configure PR Review Poller callbacks.
193
- * Extracted so it can be called from both initializeMultiBots() and updateConfig()
194
- * to enable hot-reload of PR poller.
195
- */
196
- configurePrPoller() {
197
- if (!this.isPrReviewPollingEnabled()) {
198
- return;
199
- }
200
- if (this.config.mention_delegation) {
201
- const botUserIdMap = this.multiBotManager.getBotUserIdMap();
202
- const orchestratorId = this.config.default_agent || 'sisyphus';
203
- const orchestratorUserId = botUserIdMap.get(orchestratorId);
204
- if (orchestratorUserId) {
205
- this.prReviewPoller.setTargetAgentUserId(orchestratorUserId);
206
- }
207
- }
208
- // PR Review Poller: wake up LEAD with compact summaries from new review items.
209
- this.prReviewPoller.setMessageSender(async () => { });
210
- this.prReviewPoller.setOnBatchItem(async (channelId, summary, item) => {
211
- const compact = this.compactPrReviewBatchSummary(summary);
212
- const bucket = this.prPollerSummaries.get(channelId) ?? [];
213
- if (!compact || bucket.some((candidate) => candidate.id === item.id)) {
214
- return;
215
- }
216
- const merged = { ...item, summary: compact };
217
- this.prPollerSummaries.set(channelId, [...bucket, merged].slice(-12));
218
- });
219
- this.prReviewPoller.setOnBatchComplete(async (channelId, digest) => {
220
- const items = (digest?.items && digest.items.length > 0
221
- ? digest.items
222
- : this.prPollerSummaries.get(channelId)) ?? [];
223
- const count = items.length;
224
- if (count === 0) {
225
- return;
226
- }
227
- const actionableItems = digest?.newItems ?? items.filter((item) => !item.isReminder);
228
- if (actionableItems.length === 0) {
229
- this.prPollerSummaries.delete(channelId);
230
- return;
231
- }
232
- const reminderCount = (digest?.reminderItems ?? items.filter((item) => item.isReminder))
233
- .length;
234
- this.prPollerSummaries.delete(channelId);
235
- const sessions = this.prReviewPoller.getSessionDetails();
236
- const session = sessions.find((s) => s.channelId === channelId);
237
- if (!session) {
238
- return;
239
- }
240
- const prLabel = `${session.owner}/${session.repo}#${session.prNumber}`;
241
- const summaryLines = items
242
- .map((item, idx) => `- ${idx + 1}. [${item.severity}] ${item.summary}`)
243
- .join('\n');
244
- const promptSummary = `\n${summaryLines}`;
245
- const reminderSuffix = reminderCount > 0 ? `\nπŸ”” Reminders: ${reminderCount} item(s).` : '';
246
- if (this.mainWebClient) {
247
- await this.mainWebClient.chat.postMessage({
248
- channel: channelId,
249
- text: `πŸ“Š PR ${prLabel} β€” ${count} new review item(s)\n\n${promptSummary}${reminderSuffix}`,
250
- });
251
- }
252
- this.orchestrator.resetChain(channelId);
253
- const defaultAgentId = this.config.default_agent || 'sisyphus';
254
- const basePrompt = `πŸ“Š PR Review follow-up (${count} new item(s))\n` +
255
- `Target: ${prLabel}\n` +
256
- `Workspace: \`${session.workspaceDir}\`\n` +
257
- `Items:\n${promptSummary}${reminderSuffix}`;
258
- this.messageQueue.enqueue(defaultAgentId, {
259
- prompt: `${basePrompt}\n\nClassify severity, implement fixable items, and coordinate with Dev/Reviewer.`,
260
- channelId,
261
- source: 'slack',
262
- enqueuedAt: Date.now(),
263
- context: { channelId, userId: 'pr-poller' },
264
- });
265
- this.logger.info(`[MultiAgentSlack] PR Poller -> LEAD wake-up (${count} items)`);
266
- this.tryDrainNow(defaultAgentId, 'slack', channelId).catch(() => { });
267
- const helperAgents = this.resolvePrReviewAssistants(defaultAgentId);
268
- for (const helperAgentId of helperAgents) {
269
- const helperPrompt = helperAgentId === 'developer'
270
- ? `${basePrompt}\n\nImplement available fixes in the workspace and request Reviewer verification when changes are made.`
271
- : `${basePrompt}\n\nInspect the comments for correctness issues and provide reviewer guidance.`;
272
- this.messageQueue.enqueue(helperAgentId, {
273
- prompt: helperPrompt,
274
- channelId,
275
- source: 'slack',
276
- enqueuedAt: Date.now(),
277
- context: { channelId, userId: 'pr-poller' },
278
- });
279
- this.logger.info(`[MultiAgentSlack] PR Poller -> ${helperAgentId} wake-up (${count} items)`);
280
- this.tryDrainNow(helperAgentId, 'slack', channelId).catch(() => { });
281
- }
282
- });
283
- this.logger.log('[MultiAgentSlack] PR Poller summaries now feed LEAD wake-up');
284
- }
285
- /**
286
- * Keep PR poller summaries short and remove duplicates.
287
- */
288
- compactPrReviewBatchSummary(summary) {
289
- const compact = summary.replace(/[\r\n]+/g, ' ').trim();
290
- const max = 230;
291
- if (!compact) {
292
- return '';
293
- }
294
- return compact.length > max ? `${compact.slice(0, max)}…` : compact;
295
- }
296
- /**
297
- * Resolve helper agents for PR review workflow in addition to default lead.
298
- */
299
- resolvePrReviewAssistants(defaultAgentId) {
300
- const candidateIds = ['developer', 'reviewer', 'dev', 'lead'];
301
- const helperAgents = [];
302
- for (const id of candidateIds) {
303
- const cfg = this.config.agents[id];
304
- if (!cfg || id === defaultAgentId) {
305
- continue;
306
- }
307
- if (cfg.enabled === false) {
308
- continue;
309
- }
310
- helperAgents.push(id);
311
- }
312
- return [...new Set(helperAgents)];
313
189
  }
314
190
  /**
315
191
  * Set main Slack WebClient (for heartbeat status messages)
@@ -322,12 +198,6 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
322
198
  await client.chat.postMessage({ channel: channelId, text: chunk });
323
199
  }
324
200
  }, 'slack');
325
- // Only set PR poller sender if not already configured (e.g., by reviewer bot)
326
- if (this.isPrReviewPollingEnabled() && !this.prReviewPoller.hasMessageSender?.()) {
327
- this.prReviewPoller.setMessageSender(async (channelId, text) => {
328
- await client.chat.postMessage({ channel: channelId, text });
329
- });
330
- }
331
201
  }
332
202
  /**
333
203
  * Set main bot's user ID (call when Slack connects via auth.test)
@@ -354,66 +224,6 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
354
224
  this.config = config;
355
225
  this.orchestrator.updateConfig(config);
356
226
  this.processManager.updateConfig(config);
357
- if (this.isPrReviewPollingEnabled()) {
358
- // Re-wire PR poller callbacks on hot-reload enable
359
- this.configurePrPoller();
360
- }
361
- else {
362
- this.prReviewPoller.stopAll();
363
- this.prPollerSummaries.clear();
364
- }
365
- }
366
- /**
367
- * Handle PR review polling commands from human messages.
368
- * Returns true if the message was a PR command (consumed), false otherwise.
369
- *
370
- * Start: message contains a GitHub PR URL (auto-detect)
371
- * Stop: message contains "pr stop", "stop polling"
372
- */
373
- async handlePRCommand(channelId, content) {
374
- if (!this.isPrReviewPollingEnabled()) {
375
- return false;
376
- }
377
- if (!this.mainWebClient) {
378
- return false;
379
- }
380
- const contentLower = content.toLowerCase();
381
- // Stop commands
382
- const stopPatterns = ['pr 쀑지', 'pr stop', '폴링 쀑지', 'stop polling', 'pr μ’…λ£Œ', 'stop pr'];
383
- if (stopPatterns.some((p) => contentLower.includes(p))) {
384
- const sessions = this.prReviewPoller.getActiveSessions();
385
- if (sessions.length === 0) {
386
- await this.mainWebClient.chat.postMessage({
387
- channel: channelId,
388
- text: 'πŸ“­ No active PR polling sessions.',
389
- });
390
- }
391
- else {
392
- this.prReviewPoller.stopAll();
393
- await this.mainWebClient.chat.postMessage({
394
- channel: channelId,
395
- text: `⏹️ PR review polling stopped: ${sessions.join(', ')}`,
396
- });
397
- }
398
- return true;
399
- }
400
- // Start: detect PR URL in message
401
- const prUrls = pr_review_poller_js_1.PRReviewPoller.extractPRUrls(content);
402
- if (prUrls.length > 0) {
403
- for (const prUrl of prUrls) {
404
- const started = await this.prReviewPoller.startPolling(prUrl, channelId);
405
- if (started) {
406
- const parsed = this.prReviewPoller.parsePRUrl(prUrl);
407
- const key = parsed ? `${parsed.owner}/${parsed.repo}#${parsed.prNumber}` : prUrl;
408
- await this.mainWebClient.chat.postMessage({
409
- channel: channelId,
410
- text: `πŸ‘€ *PR Review Poller started* -- ${key}\nPolling for new review comments every 60 seconds. Type "PR stop" to stop.`,
411
- });
412
- }
413
- }
414
- return true;
415
- }
416
- return false;
417
227
  }
418
228
  /**
419
229
  * Handle a Slack message with multi-agent logic
@@ -481,29 +291,38 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
481
291
  // Build context for this agent
482
292
  const agentContext = this.sharedContext.buildContextForAgent(context.channelId, agentId, 5);
483
293
  // Build full prompt with context.
484
- // NOTE: Do NOT inject historyContext into persistent processes -- the CLI process
485
- // already retains conversation memory across turns. Injecting historyContext causes
486
- // duplicate messages in Claude's context, making old messages appear "just conversed"
487
- // and creating cross-agent context confusion.
488
- // Only inject agentContext (other agents' messages) for inter-agent awareness.
489
294
  let fullPrompt = cleanMessage;
490
- if (agentContext) {
491
- fullPrompt = `${agentContext}\n\n${fullPrompt}`;
492
- }
493
- // Inject agent availability status and active work (Phase 2 + 3)
494
- const agentStatus = this.buildAgentStatusSection(agentId);
495
- const workSection = this.workTracker.buildWorkSection(agentId);
496
- const dynamicContext = [agentStatus, workSection].filter(Boolean).join('\n');
497
- if (dynamicContext) {
498
- fullPrompt = `${dynamicContext}\n\n${fullPrompt}`;
499
- }
500
- this.logger.log(`[MultiAgentSlack] Processing agent ${agentId}, prompt length: ${fullPrompt.length}`);
501
295
  // Track work start (completed in finally block)
502
296
  this.workTracker.startWork(agentId, context.channelId, cleanMessage);
503
297
  let process = null;
504
298
  try {
505
299
  // Get or create process for this agent in this channel
506
300
  process = await this.processManager.getProcess('slack', context.channelId, agentId);
301
+ // Inject channel history when process is new/replaced for this agent:channel.
302
+ // After process restart the CLI has no prior memory, so history must be re-seeded.
303
+ const sessionKey = `${agentId}:${context.channelId}`;
304
+ const needsHistorySeed = this.historySeedProcess.get(sessionKey) !== process;
305
+ if (needsHistorySeed) {
306
+ const channelHistory = (0, channel_history_js_1.getChannelHistory)();
307
+ const displayName = agent.display_name || agentId;
308
+ const historyContext = channelHistory.formatForContext(context.channelId, context.messageId, displayName);
309
+ if (historyContext) {
310
+ fullPrompt = `${historyContext}\n\n${fullPrompt}`;
311
+ }
312
+ this.historySeedProcess.set(sessionKey, process);
313
+ }
314
+ if (agentContext) {
315
+ fullPrompt = `${agentContext}\n\n${fullPrompt}`;
316
+ }
317
+ // Inject agent availability status and active work (Phase 2 + 3)
318
+ const agentStatus = this.buildAgentStatusSection(agentId);
319
+ const workSection = this.workTracker.buildWorkSection(agentId);
320
+ const channelInfo = `## Current Channel\nPlatform: Slack\nchannel_id: ${context.channelId}\nUse **slack_send** to send messages/files to this channel.`;
321
+ const dynamicContext = [agentStatus, workSection, channelInfo].filter(Boolean).join('\n');
322
+ if (dynamicContext) {
323
+ fullPrompt = `${dynamicContext}\n\n${fullPrompt}`;
324
+ }
325
+ this.logger.log(`[MultiAgentSlack] Processing agent ${agentId}, prompt length: ${fullPrompt.length}`);
507
326
  // Send message and get response (with timeout, properly cleaned up)
508
327
  let timeoutHandle;
509
328
  let result;
@@ -525,21 +344,42 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
525
344
  }
526
345
  let msg = '';
527
346
  const modelTag = event.agentModel ? ` [${event.agentModel}]` : '';
347
+ const progress = event.totalSteps && event.completedSteps !== undefined
348
+ ? ` [${event.completedSteps}/${event.totalSteps}]`
349
+ : '';
528
350
  if (event.type === 'step-started') {
529
- msg = ` ${event.agentDisplayName}${modelTag} μ‹œμž‘...`;
351
+ msg = ` ${event.agentDisplayName}${modelTag}${progress} μ‹œμž‘...`;
530
352
  }
531
353
  else if (event.type === 'step-completed') {
532
354
  const sec = event.duration_ms ? Math.round(event.duration_ms / 1000) : 0;
533
- msg = `${event.agentDisplayName}${modelTag} (${sec}s) μ™„λ£Œ`;
355
+ const pct = event.totalSteps && event.completedSteps !== undefined
356
+ ? ` (${Math.round((event.completedSteps / event.totalSteps) * 100)}%)`
357
+ : '';
358
+ msg = `${event.agentDisplayName}${modelTag} (${sec}s)${pct} μ™„λ£Œ`;
534
359
  }
535
360
  else if (event.type === 'step-failed') {
536
- msg = `${event.agentDisplayName}${modelTag} ❌ μ‹€νŒ¨: ${event.error?.substring(0, 100)}`;
361
+ msg = `${event.agentDisplayName}${modelTag}${progress} ❌ μ‹€νŒ¨: ${event.error?.substring(0, 100)}`;
537
362
  }
538
363
  if (msg) {
539
364
  this.mainWebClient.chat.postMessage({ channel: context.channelId, text: msg }).catch(() => { });
540
365
  }
541
366
  });
542
367
  if (workflowResult) {
368
+ if (workflowResult.failed) {
369
+ // Workflow plan parsed but execution failed β€” feed error back to Conductor
370
+ this.logger.warn(`[MultiAgentSlack] Workflow failed: ${workflowResult.failed}, sending feedback to conductor`);
371
+ const feedback = `[SYSTEM] Your workflow_plan failed to execute.\nReason: ${workflowResult.failed}\nPlease adjust and retry, or respond without a workflow_plan.`;
372
+ const retryResult = await process.sendMessage(feedback);
373
+ const cleanedRetry = await this.executeTextToolCalls(retryResult.response);
374
+ const formattedResponse = this.formatAgentResponse(agent, cleanedRetry);
375
+ return {
376
+ agentId,
377
+ agent,
378
+ content: formattedResponse,
379
+ rawContent: cleanedRetry,
380
+ duration: result.duration_ms,
381
+ };
382
+ }
543
383
  const display = workflowResult.directMessage
544
384
  ? `${workflowResult.directMessage}\n\n${workflowResult.result}`
545
385
  : workflowResult.result;
@@ -552,36 +392,103 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
552
392
  duration: result.duration_ms,
553
393
  };
554
394
  }
395
+ // Check for council plan (after workflow, before tool calls)
396
+ const councilResult = await this.tryExecuteCouncil(result.response, context.channelId, 'slack', async (event) => {
397
+ if (!this.mainWebClient) {
398
+ return;
399
+ }
400
+ let msg = '';
401
+ if (event.type === 'council-round-started') {
402
+ msg = `πŸ—£οΈ ${event.agentDisplayName} Round ${event.round} μ‹œμž‘...`;
403
+ }
404
+ else if (event.type === 'council-round-completed') {
405
+ const sec = event.duration_ms ? Math.round(event.duration_ms / 1000) : 0;
406
+ msg = `πŸ—£οΈ ${event.agentDisplayName} Round ${event.round} (${sec}s) μ™„λ£Œ`;
407
+ }
408
+ else if (event.type === 'council-round-failed') {
409
+ msg = `πŸ—£οΈ ${event.agentDisplayName} Round ${event.round} ❌ μ‹€νŒ¨: ${event.error?.substring(0, 100)}`;
410
+ }
411
+ if (msg) {
412
+ try {
413
+ await this.mainWebClient.chat.postMessage({ channel: context.channelId, text: msg });
414
+ }
415
+ catch (err) {
416
+ this.logger?.warn('[MultiAgentSlack] Failed to post council progress:', err);
417
+ }
418
+ }
419
+ });
420
+ if (councilResult) {
421
+ const display = councilResult.directMessage
422
+ ? `${councilResult.directMessage}\n\n${councilResult.result}`
423
+ : councilResult.result;
424
+ const formattedResponse = this.formatAgentResponse(agent, display);
425
+ return {
426
+ agentId,
427
+ agent,
428
+ content: formattedResponse,
429
+ rawContent: display,
430
+ duration: result.duration_ms,
431
+ };
432
+ }
433
+ // Strip any workflow/council plan JSON that wasn't executed
434
+ // (prevents raw JSON from leaking to Slack when plan execution is skipped)
435
+ let responseForProcessing = result.response;
436
+ if (this.workflowEngine?.isEnabled()) {
437
+ responseForProcessing = this.workflowEngine.extractNonPlanContent(responseForProcessing);
438
+ }
439
+ if (this.councilEngine) {
440
+ responseForProcessing = this.councilEngine.extractNonPlanContent(responseForProcessing);
441
+ }
555
442
  // Execute text-based gateway tool calls (```tool_call blocks in response)
556
- const cleanedResponse = await this.executeTextToolCalls(result.response);
557
- const bgDelegation = this.delegationManager.parseDelegation(agentId, cleanedResponse);
558
- if (bgDelegation && bgDelegation.background) {
559
- const check = this.delegationManager.isDelegationAllowed(bgDelegation.fromAgentId, bgDelegation.toAgentId);
443
+ const cleanedResponse = await this.executeTextToolCalls(responseForProcessing);
444
+ // Parse all delegation commands (both sync and background)
445
+ const delegations = this.delegationManager.parseAllDelegations(agentId, cleanedResponse);
446
+ let displayResponse = cleanedResponse;
447
+ // Handle background delegations
448
+ const bgDelegations = delegations.filter((d) => d.background);
449
+ if (bgDelegations.length > 0) {
450
+ let submittedCount = 0;
451
+ for (const delegation of bgDelegations) {
452
+ const check = this.delegationManager.isDelegationAllowed(delegation.fromAgentId, delegation.toAgentId);
453
+ if (check.allowed) {
454
+ this.backgroundTaskManager.submit({
455
+ description: delegation.task.substring(0, 200),
456
+ prompt: delegation.task,
457
+ agentId: delegation.toAgentId,
458
+ requestedBy: agentId,
459
+ channelId: context.channelId,
460
+ source: 'slack',
461
+ });
462
+ this.logger.log(`[MultiAgentSlack] Background delegation: ${agentId} -> ${delegation.toAgentId} (async)`);
463
+ submittedCount++;
464
+ }
465
+ }
466
+ if (submittedCount > 0) {
467
+ displayResponse =
468
+ bgDelegations[0].originalContent || `πŸ”„ ${submittedCount} background task(s) delegated`;
469
+ }
470
+ }
471
+ // Handle synchronous delegations via message queue
472
+ const syncDelegations = delegations.filter((d) => !d.background);
473
+ for (const delegation of syncDelegations) {
474
+ const check = this.delegationManager.isDelegationAllowed(delegation.fromAgentId, delegation.toAgentId);
560
475
  if (check.allowed) {
561
- const toAgent = this.orchestrator.getAgent(bgDelegation.toAgentId);
562
- this.backgroundTaskManager.submit({
563
- description: bgDelegation.task.substring(0, 200),
564
- prompt: bgDelegation.task,
565
- agentId: bgDelegation.toAgentId,
566
- requestedBy: agentId,
476
+ this.messageQueue.enqueue(delegation.toAgentId, {
477
+ prompt: delegation.task,
567
478
  channelId: context.channelId,
568
479
  source: 'slack',
480
+ enqueuedAt: Date.now(),
481
+ context,
569
482
  });
570
- this.logger.log(`[MultiAgentSlack] Background delegation: ${agentId} -> ${bgDelegation.toAgentId} (async)`);
571
- const displayResponse = bgDelegation.originalContent ||
572
- `πŸ”„ Background task submitted to *${toAgent?.display_name ?? bgDelegation.toAgentId}*`;
573
- const formattedResponse = this.formatAgentResponse(agent, displayResponse);
574
- return {
575
- agentId,
576
- agent,
577
- content: formattedResponse,
578
- rawContent: displayResponse,
579
- duration: result.duration_ms,
580
- };
483
+ this.logger.log(`[MultiAgentSlack] Sync delegation (queued): ${agentId} -> ${delegation.toAgentId}`);
484
+ this.tryDrainNow(delegation.toAgentId, 'slack', context.channelId).catch(() => { });
485
+ }
486
+ else {
487
+ this.logger.log(`[MultiAgentSlack] Sync delegation denied: ${agentId} -> ${delegation.toAgentId}: ${check.reason}`);
581
488
  }
582
489
  }
583
490
  // Format response with agent prefix
584
- const formattedResponse = this.formatAgentResponse(agent, cleanedResponse);
491
+ const formattedResponse = this.formatAgentResponse(agent, displayResponse);
585
492
  return {
586
493
  agentId,
587
494
  agent,
@@ -605,11 +512,33 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
605
512
  context,
606
513
  };
607
514
  this.messageQueue.enqueue(agentId, queuedMessage);
515
+ const queueSize = this.messageQueue.getQueueSize(agentId);
516
+ const queueText = queueSize > 0
517
+ ? `⚠️ ${agent.display_name}이(κ°€) ν˜„μž¬ μž‘μ—… μ€‘μž…λ‹ˆλ‹€. ${queueSize}개의 λ©”μ‹œμ§€κ°€ λŒ€κΈ°μ—΄μ— μžˆμŠ΅λ‹ˆλ‹€.`
518
+ : `⚠️ ${agent.display_name}이(κ°€) ν˜„μž¬ μž‘μ—… μ€‘μž…λ‹ˆλ‹€. μš”μ²­μ΄ λŒ€κΈ°μ—΄μ— λ“±λ‘λ˜μ—ˆμŠ΅λ‹ˆλ‹€.`;
608
519
  // Trigger immediate drain if process is idle or reaped
609
520
  this.tryDrainNow(agentId, 'slack', context.channelId).catch(() => { });
610
- return null;
521
+ return {
522
+ agentId,
523
+ agent,
524
+ content: this.formatAgentResponse(agent, queueText),
525
+ rawContent: queueText,
526
+ duration: 0,
527
+ };
611
528
  }
612
- return null;
529
+ const fallbackMessage = errMsg.toLowerCase().includes('timed out') || errMsg.toLowerCase().includes('timeout')
530
+ ? `⚠️ ${agent.display_name} 응닡이 μ‹œκ°„ μ΄ˆκ³Όλ˜μ–΄ 처리 κ²°κ³Όλ₯Ό λͺ» λ°›μ•˜μŠ΅λ‹ˆλ‹€. μž μ‹œ ν›„ λ‹€μ‹œ μ‹œλ„ν•΄ μ£Όμ„Έμš”.`
531
+ : `⚠️ ${agent.display_name} 처리 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: ${errMsg}`;
532
+ const fallbackRaw = errMsg.toLowerCase().includes('timed out') || errMsg.toLowerCase().includes('timeout')
533
+ ? 'Response timed out'
534
+ : `Error: ${errMsg}`;
535
+ return {
536
+ agentId,
537
+ agent,
538
+ content: this.formatAgentResponse(agent, fallbackMessage),
539
+ rawContent: fallbackRaw,
540
+ duration: 0,
541
+ };
613
542
  }
614
543
  finally {
615
544
  if (process) {
@@ -819,8 +748,9 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
819
748
  for (const response of responses) {
820
749
  // Filter out self-mentions to prevent routing an agent's response back to itself
821
750
  const mentionedAgentIds = this.extractMentionedAgentIds(response.rawContent).filter((id) => id !== response.agentId);
822
- if (mentionedAgentIds.length === 0)
751
+ if (mentionedAgentIds.length === 0) {
823
752
  continue;
753
+ }
824
754
  // Hard gate: block malformed delegations from can_delegate agents
825
755
  const senderAgent = this.orchestrator.getAgent(response.agentId);
826
756
  if (senderAgent?.can_delegate && (0, delegation_format_validator_js_1.isDelegationAttempt)(response.rawContent)) {
@@ -907,10 +837,7 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
907
837
  return;
908
838
  }
909
839
  const agentStates = this.processManager.getAgentStates();
910
- const prSessions = this.isPrReviewPollingEnabled()
911
- ? this.prReviewPoller.getActiveSessions()
912
- : [];
913
- // Check if any agent is busy or PR polling is active
840
+ // Check if any agent is busy
914
841
  let hasBusy = false;
915
842
  for (const state of agentStates.values()) {
916
843
  if (state === 'busy' || state === 'starting') {
@@ -918,8 +845,8 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
918
845
  break;
919
846
  }
920
847
  }
921
- // Silent when no agents are busy AND no PR polling active
922
- if (!hasBusy && prSessions.length === 0)
848
+ // Silent when no agents are busy
849
+ if (!hasBusy)
923
850
  return;
924
851
  // Build status line
925
852
  const agentConfigs = this.config.agents;
@@ -936,11 +863,7 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
936
863
  }
937
864
  parts.push(entry);
938
865
  }
939
- let statusLine = `⏱️ *Agent Status* | ${parts.join(' | ')}`;
940
- // Append PR polling info
941
- if (prSessions.length > 0) {
942
- statusLine += ` | πŸ‘€ PR: ${prSessions.join(', ')}`;
943
- }
866
+ const statusLine = `⏱️ *Agent Status* | ${parts.join(' | ')}`;
944
867
  try {
945
868
  await this.mainWebClient.chat.postMessage({
946
869
  channel: this.heartbeatChannelId,
@@ -951,9 +874,6 @@ class MultiAgentSlackHandler extends multi_agent_base_js_1.MultiAgentHandlerBase
951
874
  this.logger.error('[Heartbeat] Failed to post status:', err);
952
875
  }
953
876
  }
954
- isPrReviewPollingEnabled() {
955
- return this.config.pr_review_poller?.enabled === true;
956
- }
957
877
  /**
958
878
  * Get status of all agent bots
959
879
  */