opencode-matrixx 2.0.0 → 2.2.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 (187) hide show
  1. package/README.md +138 -23
  2. package/dist/agents/architect/agent.d.ts +9 -9
  3. package/dist/agents/architect/default.d.ts +3 -3
  4. package/dist/agents/architect/gpt.d.ts +3 -3
  5. package/dist/agents/architect/index.d.ts +4 -4
  6. package/dist/agents/architect/prompt-section-builder.d.ts +1 -1
  7. package/dist/agents/builtin-agents/{atlas-agent.d.ts → architect-agent.d.ts} +1 -1
  8. package/dist/agents/builtin-agents/general-agents.d.ts +1 -1
  9. package/dist/agents/builtin-agents/model-resolution.d.ts +1 -1
  10. package/dist/agents/index.d.ts +2 -2
  11. package/dist/agents/merovingian.d.ts +3 -2
  12. package/dist/agents/types.d.ts +2 -2
  13. package/dist/config/index.d.ts +2 -2
  14. package/dist/config/schema/agent-names.d.ts +4 -18
  15. package/dist/config/schema/assembly.d.ts +13 -0
  16. package/dist/config/schema/categories.d.ts +0 -1
  17. package/dist/config/schema/commands.d.ts +4 -0
  18. package/dist/config/schema/hooks.d.ts +1 -2
  19. package/dist/config/schema/matrixx-config.d.ts +18 -3
  20. package/dist/config/schema/security.d.ts +0 -5
  21. package/dist/config/schema.d.ts +1 -0
  22. package/dist/create-hooks.d.ts +2 -2
  23. package/dist/features/assembly-state/index.d.ts +1 -0
  24. package/dist/features/assembly-state/manager.d.ts +6 -0
  25. package/dist/features/background-agent/error-helpers.d.ts +6 -0
  26. package/dist/features/background-agent/manager.d.ts +6 -8
  27. package/dist/features/background-agent/message-dir.d.ts +5 -0
  28. package/dist/features/background-agent/notification-builder.d.ts +17 -0
  29. package/dist/features/builtin-commands/templates/assembly.d.ts +1 -0
  30. package/dist/features/builtin-commands/templates/research.d.ts +1 -0
  31. package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
  32. package/dist/features/builtin-commands/templates/ultrawork.d.ts +1 -0
  33. package/dist/features/builtin-commands/types.d.ts +1 -1
  34. package/dist/features/builtin-skills/skills/index.d.ts +2 -0
  35. package/dist/features/builtin-skills/skills/remove-ai-slops.d.ts +2 -0
  36. package/dist/features/builtin-skills/skills/ulw-research.d.ts +2 -0
  37. package/dist/features/claude-code-command-loader/loader.d.ts +0 -1
  38. package/dist/features/hook-message-injector/injector.d.ts +2 -3
  39. package/dist/features/mission-state/types.d.ts +1 -1
  40. package/dist/features/tmux-subagent/index.d.ts +0 -2
  41. package/dist/features/ultrawork-state/index.d.ts +1 -0
  42. package/dist/features/ultrawork-state/manager.d.ts +6 -0
  43. package/dist/hooks/architect/{atlas-hook.d.ts → architect-hook.d.ts} +2 -2
  44. package/dist/hooks/architect/event-handler.d.ts +3 -3
  45. package/dist/hooks/architect/index.d.ts +2 -2
  46. package/dist/hooks/architect/types.d.ts +1 -1
  47. package/dist/hooks/auto-update-checker/cache.d.ts +0 -2
  48. package/dist/hooks/auto-update-checker/index.d.ts +1 -1
  49. package/dist/hooks/index.d.ts +1 -1
  50. package/dist/hooks/interactive-bash-session/parser.d.ts +0 -6
  51. package/dist/hooks/mouse-notepad/constants.d.ts +1 -1
  52. package/dist/index.js +1966 -631
  53. package/dist/plugin/hooks/create-continuation-hooks.d.ts +2 -2
  54. package/dist/plugin/hooks/create-core-hooks.d.ts +1 -1
  55. package/dist/plugin/hooks/create-session-hooks.d.ts +1 -1
  56. package/dist/shared/index.d.ts +1 -0
  57. package/dist/shared/model-resolution-pipeline.d.ts +1 -24
  58. package/dist/shared/model-resolution-types.d.ts +1 -0
  59. package/dist/shared/model-resolver.d.ts +4 -2
  60. package/dist/shared/opencode-config-dir.d.ts +1 -2
  61. package/dist/shared/session-directory-resolver.d.ts +0 -6
  62. package/dist/shared/tool-guards.d.ts +16 -0
  63. package/dist/tools/assembly/assembly-executor.d.ts +17 -0
  64. package/dist/tools/assembly/constants.d.ts +6 -0
  65. package/dist/tools/assembly/index.d.ts +2 -0
  66. package/dist/tools/assembly/provider-selector.d.ts +3 -0
  67. package/dist/tools/assembly/synthesizer.d.ts +3 -0
  68. package/dist/tools/assembly/tool-description.d.ts +2 -0
  69. package/dist/tools/assembly/tools.d.ts +10 -0
  70. package/dist/tools/assembly/types.d.ts +25 -0
  71. package/dist/tools/assembly/voter-spawner.d.ts +3 -0
  72. package/dist/tools/delegate-task/executor-types.d.ts +1 -1
  73. package/dist/tools/delegate-task/mouse-agent.d.ts +1 -1
  74. package/dist/tools/delegate-task/types.d.ts +1 -1
  75. package/dist/tools/handoff/constants.d.ts +0 -3
  76. package/dist/tools/index.d.ts +1 -0
  77. package/package.json +4 -29
  78. package/bin/matrixx.js +0 -80
  79. package/bin/platform.js +0 -38
  80. package/bin/platform.test.ts +0 -148
  81. package/dist/cli/cli-installer.d.ts +0 -2
  82. package/dist/cli/cli-program.d.ts +0 -1
  83. package/dist/cli/config-manager/add-plugin-to-opencode-config.d.ts +0 -2
  84. package/dist/cli/config-manager/add-provider-config.d.ts +0 -2
  85. package/dist/cli/config-manager/antigravity-provider-configuration.d.ts +0 -122
  86. package/dist/cli/config-manager/auth-plugins.d.ts +0 -3
  87. package/dist/cli/config-manager/bun-install.d.ts +0 -7
  88. package/dist/cli/config-manager/config-context.d.ts +0 -13
  89. package/dist/cli/config-manager/deep-merge-record.d.ts +0 -1
  90. package/dist/cli/config-manager/detect-current-config.d.ts +0 -2
  91. package/dist/cli/config-manager/ensure-config-directory-exists.d.ts +0 -1
  92. package/dist/cli/config-manager/format-error-with-suggestion.d.ts +0 -1
  93. package/dist/cli/config-manager/generate-matrixx-config.d.ts +0 -2
  94. package/dist/cli/config-manager/jsonc-provider-editor.d.ts +0 -1
  95. package/dist/cli/config-manager/npm-dist-tags.d.ts +0 -7
  96. package/dist/cli/config-manager/opencode-binary.d.ts +0 -2
  97. package/dist/cli/config-manager/opencode-config-format.d.ts +0 -6
  98. package/dist/cli/config-manager/parse-opencode-config-file.d.ts +0 -10
  99. package/dist/cli/config-manager/plugin-name-with-version.d.ts +0 -1
  100. package/dist/cli/config-manager/write-matrixx-config.d.ts +0 -2
  101. package/dist/cli/config-manager.d.ts +0 -14
  102. package/dist/cli/doctor/checks/config.d.ts +0 -2
  103. package/dist/cli/doctor/checks/dependencies.d.ts +0 -4
  104. package/dist/cli/doctor/checks/index.d.ts +0 -7
  105. package/dist/cli/doctor/checks/model-resolution-cache.d.ts +0 -2
  106. package/dist/cli/doctor/checks/model-resolution-config.d.ts +0 -2
  107. package/dist/cli/doctor/checks/model-resolution-details.d.ts +0 -6
  108. package/dist/cli/doctor/checks/model-resolution-effective-model.d.ts +0 -3
  109. package/dist/cli/doctor/checks/model-resolution-types.d.ts +0 -37
  110. package/dist/cli/doctor/checks/model-resolution-variant.d.ts +0 -5
  111. package/dist/cli/doctor/checks/model-resolution.d.ts +0 -6
  112. package/dist/cli/doctor/checks/system-binary.d.ts +0 -8
  113. package/dist/cli/doctor/checks/system-loaded-version.d.ts +0 -10
  114. package/dist/cli/doctor/checks/system-plugin.d.ts +0 -15
  115. package/dist/cli/doctor/checks/system.d.ts +0 -3
  116. package/dist/cli/doctor/checks/tools-gh.d.ts +0 -11
  117. package/dist/cli/doctor/checks/tools-lsp.d.ts +0 -6
  118. package/dist/cli/doctor/checks/tools-mcp.d.ts +0 -3
  119. package/dist/cli/doctor/checks/tools.d.ts +0 -3
  120. package/dist/cli/doctor/constants.d.ts +0 -31
  121. package/dist/cli/doctor/format-default.d.ts +0 -2
  122. package/dist/cli/doctor/format-shared.d.ts +0 -6
  123. package/dist/cli/doctor/format-status.d.ts +0 -2
  124. package/dist/cli/doctor/format-verbose.d.ts +0 -2
  125. package/dist/cli/doctor/formatter.d.ts +0 -3
  126. package/dist/cli/doctor/index.d.ts +0 -5
  127. package/dist/cli/doctor/runner.d.ts +0 -5
  128. package/dist/cli/doctor/types.d.ts +0 -96
  129. package/dist/cli/fallback-chain-resolution.d.ts +0 -10
  130. package/dist/cli/get-local-version/formatter.d.ts +0 -3
  131. package/dist/cli/get-local-version/get-local-version.d.ts +0 -2
  132. package/dist/cli/get-local-version/index.d.ts +0 -2
  133. package/dist/cli/get-local-version/types.d.ts +0 -13
  134. package/dist/cli/index.d.ts +0 -2
  135. package/dist/cli/index.js +0 -30690
  136. package/dist/cli/install-validators.d.ts +0 -31
  137. package/dist/cli/install.d.ts +0 -2
  138. package/dist/cli/mcp-oauth/index.d.ts +0 -6
  139. package/dist/cli/mcp-oauth/login.d.ts +0 -7
  140. package/dist/cli/mcp-oauth/logout.d.ts +0 -5
  141. package/dist/cli/mcp-oauth/status.d.ts +0 -1
  142. package/dist/cli/model-fallback-types.d.ts +0 -25
  143. package/dist/cli/model-fallback.d.ts +0 -4
  144. package/dist/cli/provider-availability.d.ts +0 -4
  145. package/dist/cli/provider-model-id-transform.d.ts +0 -1
  146. package/dist/cli/run/agent-resolver.d.ts +0 -5
  147. package/dist/cli/run/completion.d.ts +0 -2
  148. package/dist/cli/run/event-formatting.d.ts +0 -3
  149. package/dist/cli/run/event-handlers.d.ts +0 -10
  150. package/dist/cli/run/event-state.d.ts +0 -13
  151. package/dist/cli/run/event-stream-processor.d.ts +0 -3
  152. package/dist/cli/run/events.d.ts +0 -4
  153. package/dist/cli/run/index.d.ts +0 -9
  154. package/dist/cli/run/json-output.d.ts +0 -12
  155. package/dist/cli/run/on-complete-hook.d.ts +0 -7
  156. package/dist/cli/run/opencode-bin-path.d.ts +0 -3
  157. package/dist/cli/run/opencode-binary-resolver.d.ts +0 -4
  158. package/dist/cli/run/poll-for-completion.d.ts +0 -9
  159. package/dist/cli/run/runner.d.ts +0 -5
  160. package/dist/cli/run/server-connection.d.ts +0 -6
  161. package/dist/cli/run/session-resolver.d.ts +0 -6
  162. package/dist/cli/run/types.d.ts +0 -119
  163. package/dist/cli/tui-install-prompts.d.ts +0 -2
  164. package/dist/cli/tui-installer.d.ts +0 -2
  165. package/dist/cli/types.d.ts +0 -36
  166. package/dist/features/background-agent/background-task-notification-template.d.ts +0 -11
  167. package/dist/features/background-agent/opencode-client.d.ts +0 -2
  168. package/dist/features/background-agent/task-poller.d.ts +0 -21
  169. package/dist/features/claude-tasks/index.d.ts +0 -3
  170. package/dist/features/claude-tasks/session-storage.d.ts +0 -10
  171. package/dist/features/mcp-oauth/index.d.ts +0 -3
  172. package/dist/features/mcp-oauth/schema.d.ts +0 -5
  173. package/dist/features/run-continuation-state/constants.d.ts +0 -1
  174. package/dist/features/run-continuation-state/index.d.ts +0 -3
  175. package/dist/features/run-continuation-state/storage.d.ts +0 -6
  176. package/dist/features/run-continuation-state/types.d.ts +0 -13
  177. package/dist/features/tmux-subagent/cleanup.d.ts +0 -1
  178. package/dist/features/tmux-subagent/polling.d.ts +0 -1
  179. package/dist/hooks/session-recovery/recover-empty-content-message-sdk.d.ts +0 -13
  180. package/dist/hooks/task-reminder/hook.d.ts +0 -19
  181. package/dist/hooks/task-reminder/index.d.ts +0 -1
  182. package/dist/tools/delegate-agent/background-agent-executor.d.ts +0 -5
  183. package/dist/tools/delegate-agent/message-storage-directory.d.ts +0 -1
  184. package/dist/tools/delegate-agent/subagent-session-creator.d.ts +0 -10
  185. package/dist/tools/delegate-agent/tool-context-with-metadata.d.ts +0 -10
  186. package/postinstall.mjs +0 -43
  187. /package/dist/agents/builtin-agents/{sisyphus-agent.d.ts → morpheus-agent.d.ts} +0 -0
package/dist/index.js CHANGED
@@ -4531,7 +4531,7 @@ var require_picomatch2 = __commonJS((exports, module) => {
4531
4531
  });
4532
4532
 
4533
4533
  // src/hooks/matrix-loop/constants.ts
4534
- var HOOK_NAME4 = "matrix-loop", DEFAULT_STATE_FILE = ".matrixx/matrix-loop.local.md", DEFAULT_MAX_ITERATIONS = 100, DEFAULT_COMPLETION_PROMISE = "DONE", DEFAULT_VERIFICATION_AGENT = "merovingian", DEFAULT_VERIFICATION_TIMEOUT_MS = 30000, DEFAULT_VERIFICATION_MAX_RETRIES = 2;
4534
+ var HOOK_NAME5 = "matrix-loop", DEFAULT_STATE_FILE = ".matrixx/matrix-loop.local.md", DEFAULT_MAX_ITERATIONS = 100, DEFAULT_COMPLETION_PROMISE = "DONE", DEFAULT_VERIFICATION_AGENT = "merovingian", DEFAULT_VERIFICATION_TIMEOUT_MS = 30000, DEFAULT_VERIFICATION_MAX_RETRIES = 2;
4535
4535
 
4536
4536
  // src/hooks/matrix-loop/storage.ts
4537
4537
  var exports_storage = {};
@@ -17496,7 +17496,8 @@ import * as fs4 from "fs";
17496
17496
  // src/shared/migration/hook-names.ts
17497
17497
  var HOOK_NAME_MAP = {
17498
17498
  "anthropic-auto-compact": "anthropic-context-window-limit-recovery",
17499
- "sisyphus-orchestrator": "atlas",
17499
+ "sisyphus-orchestrator": "architect",
17500
+ "sisyphus-junior-notepad": "mouse-notepad",
17500
17501
  "empty-message-sanitizer": null
17501
17502
  };
17502
17503
  function migrateHookNames(hooks) {
@@ -18876,7 +18877,7 @@ async function isCallerOrchestrator(sessionID, client) {
18876
18877
  if (isSqliteBackend() && client) {
18877
18878
  try {
18878
18879
  const nearest2 = await findNearestMessageWithFieldsFromSDK(client, sessionID);
18879
- return getAgentConfigKey(nearest2?.agent ?? "") === "atlas";
18880
+ return getAgentConfigKey(nearest2?.agent ?? "") === "architect";
18880
18881
  } catch (error) {
18881
18882
  log("[session-utils] SDK orchestrator check failed", { sessionID, error: String(error) });
18882
18883
  return false;
@@ -18967,6 +18968,7 @@ function getCurrentPaneId() {
18967
18968
  var {spawn: spawn4 } = globalThis.Bun;
18968
18969
 
18969
18970
  // src/tools/interactive-bash/tmux-path-resolver.ts
18971
+ init_logger();
18970
18972
  var {spawn: spawn3 } = globalThis.Bun;
18971
18973
  var tmuxPath = null;
18972
18974
  var initPromise = null;
@@ -19021,7 +19023,9 @@ function getCachedTmuxPath() {
19021
19023
  function startBackgroundCheck() {
19022
19024
  if (!initPromise) {
19023
19025
  initPromise = getTmuxPath();
19024
- initPromise.catch(() => {});
19026
+ initPromise.catch((err) => {
19027
+ log("[interactive-bash] Background tmux path resolution failed:", err);
19028
+ });
19025
19029
  }
19026
19030
  }
19027
19031
 
@@ -19251,6 +19255,13 @@ async function spawnTmuxPane(sessionId, description, config, serverUrl, targetPa
19251
19255
  }
19252
19256
  return { success: true, paneId };
19253
19257
  }
19258
+ // src/shared/tool-guards.ts
19259
+ function isReadTool(toolName) {
19260
+ return toolName.toLowerCase() === "read";
19261
+ }
19262
+ function isWriteTool(toolName) {
19263
+ return toolName.toLowerCase() === "write";
19264
+ }
19254
19265
  // src/shared/transcript-path.ts
19255
19266
  import { join as join15 } from "path";
19256
19267
  var TRANSCRIPT_DIR = join15(getClaudeConfigDir(), "transcripts");
@@ -19405,6 +19416,9 @@ function createAgentUsageReminderHook(_ctx) {
19405
19416
  event: eventHandler
19406
19417
  };
19407
19418
  }
19419
+ // src/hooks/anthropic-context-window-limit-recovery/executor.ts
19420
+ init_logger();
19421
+
19408
19422
  // src/hooks/anthropic-context-window-limit-recovery/aggressive-truncation-strategy.ts
19409
19423
  init_logger();
19410
19424
 
@@ -20269,7 +20283,9 @@ async function runAggressiveTruncationStrategy(params) {
20269
20283
  variant: aggressiveResult.sufficient ? "success" : "warning",
20270
20284
  duration: 4000
20271
20285
  }
20272
- }).catch(() => {});
20286
+ }).catch((err) => {
20287
+ log("[auto-compact] Toast failed:", err);
20288
+ });
20273
20289
  log("[auto-compact] aggressive truncation completed", aggressiveResult);
20274
20290
  if (aggressiveResult.sufficient) {
20275
20291
  clearSessionState(params.autoCompactState, params.sessionID);
@@ -20283,7 +20299,9 @@ async function runAggressiveTruncationStrategy(params) {
20283
20299
  },
20284
20300
  query: { directory: params.directory }
20285
20301
  });
20286
- } catch {}
20302
+ } catch (err) {
20303
+ log("[auto-compact] Failed to send continue prompt:", err);
20304
+ }
20287
20305
  }, 500);
20288
20306
  return { handled: true, nextTruncateAttempt };
20289
20307
  }
@@ -20294,6 +20312,12 @@ async function runAggressiveTruncationStrategy(params) {
20294
20312
  });
20295
20313
  return { handled: false, nextTruncateAttempt };
20296
20314
  }
20315
+ // src/hooks/anthropic-context-window-limit-recovery/summarize-retry-strategy.ts
20316
+ init_logger();
20317
+
20318
+ // src/hooks/anthropic-context-window-limit-recovery/empty-content-recovery.ts
20319
+ init_logger();
20320
+
20297
20321
  // src/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.ts
20298
20322
  var IGNORE_TYPES2 = new Set(["thinking", "redacted_thinking", "meta"]);
20299
20323
  var TOOL_TYPES2 = new Set(["tool", "tool_use", "tool_result"]);
@@ -20440,7 +20464,9 @@ async function fixEmptyMessages(params) {
20440
20464
  variant: "error",
20441
20465
  duration: 5000
20442
20466
  }
20443
- }).catch(() => {});
20467
+ }).catch((err) => {
20468
+ log("[auto-compact] Toast failed:", err);
20469
+ });
20444
20470
  return false;
20445
20471
  }
20446
20472
  if (result.fixed) {
@@ -20451,7 +20477,9 @@ async function fixEmptyMessages(params) {
20451
20477
  variant: "warning",
20452
20478
  duration: 3000
20453
20479
  }
20454
- }).catch(() => {});
20480
+ }).catch((err) => {
20481
+ log("[auto-compact] Toast failed:", err);
20482
+ });
20455
20483
  }
20456
20484
  return result.fixed;
20457
20485
  }
@@ -20481,7 +20509,9 @@ async function fixEmptyMessages(params) {
20481
20509
  variant: "error",
20482
20510
  duration: 5000
20483
20511
  }
20484
- }).catch(() => {});
20512
+ }).catch((err) => {
20513
+ log("[auto-compact] Toast failed:", err);
20514
+ });
20485
20515
  return false;
20486
20516
  }
20487
20517
  for (const messageID of emptyMessageIds) {
@@ -20506,7 +20536,9 @@ async function fixEmptyMessages(params) {
20506
20536
  variant: "warning",
20507
20537
  duration: 3000
20508
20538
  }
20509
- }).catch(() => {});
20539
+ }).catch((err) => {
20540
+ log("[auto-compact] Toast failed:", err);
20541
+ });
20510
20542
  }
20511
20543
  return fixed;
20512
20544
  }
@@ -20537,7 +20569,9 @@ async function runSummarizeRetryStrategy(params) {
20537
20569
  variant: "error",
20538
20570
  duration: 1e4
20539
20571
  }
20540
- }).catch(() => {});
20572
+ }).catch((err) => {
20573
+ log("[auto-compact] Toast failed:", err);
20574
+ });
20541
20575
  return;
20542
20576
  }
20543
20577
  }
@@ -20560,7 +20594,9 @@ async function runSummarizeRetryStrategy(params) {
20560
20594
  variant: "warning",
20561
20595
  duration: 3000
20562
20596
  }
20563
- }).catch(() => {});
20597
+ }).catch((err) => {
20598
+ log("[auto-compact] Toast failed:", err);
20599
+ });
20564
20600
  const summarizeBody = { providerID, modelID, auto: true };
20565
20601
  await params.client.session.summarize({
20566
20602
  path: { id: params.sessionID },
@@ -20584,7 +20620,9 @@ async function runSummarizeRetryStrategy(params) {
20584
20620
  variant: "warning",
20585
20621
  duration: 3000
20586
20622
  }
20587
- }).catch(() => {});
20623
+ }).catch((err) => {
20624
+ log("[auto-compact] Toast failed:", err);
20625
+ });
20588
20626
  }
20589
20627
  }
20590
20628
  clearSessionState(params.autoCompactState, params.sessionID);
@@ -20595,7 +20633,9 @@ async function runSummarizeRetryStrategy(params) {
20595
20633
  variant: "error",
20596
20634
  duration: 5000
20597
20635
  }
20598
- }).catch(() => {});
20636
+ }).catch((err) => {
20637
+ log("[auto-compact] Toast failed:", err);
20638
+ });
20599
20639
  }
20600
20640
  // src/hooks/anthropic-context-window-limit-recovery/executor.ts
20601
20641
  async function executeCompact(sessionID, msg, autoCompactState, client, directory, experimental) {
@@ -20607,7 +20647,9 @@ async function executeCompact(sessionID, msg, autoCompactState, client, director
20607
20647
  variant: "warning",
20608
20648
  duration: 5000
20609
20649
  }
20610
- }).catch(() => {});
20650
+ }).catch((err) => {
20651
+ log("[auto-compact] Toast failed:", err);
20652
+ });
20611
20653
  return;
20612
20654
  }
20613
20655
  autoCompactState.compactionInProgress.add(sessionID);
@@ -20883,7 +20925,9 @@ function createAnthropicContextWindowLimitRecoveryHook(ctx, options) {
20883
20925
  variant: "warning",
20884
20926
  duration: 3000
20885
20927
  }
20886
- }).catch(() => {});
20928
+ }).catch((err) => {
20929
+ log("[auto-compact] Toast failed:", err);
20930
+ });
20887
20931
  const timeoutID = setTimeout(() => {
20888
20932
  pendingCompactionTimeoutBySession.delete(sessionID);
20889
20933
  executeCompact(sessionID, { providerID, modelID }, autoCompactState, ctx.client, ctx.directory, experimental);
@@ -20934,7 +20978,9 @@ function createAnthropicContextWindowLimitRecoveryHook(ctx, options) {
20934
20978
  variant: "warning",
20935
20979
  duration: 3000
20936
20980
  }
20937
- }).catch(() => {});
20981
+ }).catch((err) => {
20982
+ log("[auto-compact] Toast failed:", err);
20983
+ });
20938
20984
  await executeCompact(sessionID, { providerID, modelID }, autoCompactState, ctx.client, ctx.directory, experimental);
20939
20985
  }
20940
20986
  };
@@ -21178,7 +21224,7 @@ You have an active work plan with incomplete tasks. Continue working.
21178
21224
  RULES:
21179
21225
  - **FIRST**: Read the plan file NOW to check exact current progress \u2014 count remaining \`- [ ]\` tasks
21180
21226
  - Proceed without asking for permission
21181
- - Change \`- [ ]\` to \`- [x]\` in the plan file when done
21227
+ - **IMMEDIATELY AFTER COMPLETION**: Mark \`- [ ]\` \u2192 \`- [x]\` in the plan file. This is MANDATORY \u2014 unmarked checkboxes = lost progress.
21182
21228
  - Use the notepad at .matrixx/notepads/{PLAN_NAME}/ to record learnings
21183
21229
  - Do not stop until all tasks are complete
21184
21230
  - If blocked, document the blocker and move to the next task`;
@@ -21250,7 +21296,7 @@ ${createSystemDirective(SystemDirectiveTypes.DELEGATION_REQUIRED)}
21250
21296
 
21251
21297
  **STOP. YOU ARE VIOLATING ORCHESTRATOR PROTOCOL.**
21252
21298
 
21253
- You (Atlas) are attempting to directly modify a file outside \`.matrixx/\`.
21299
+ You (Architect) are attempting to directly modify a file outside \`.matrixx/\`.
21254
21300
 
21255
21301
  **Path attempted:** $FILE_PATH
21256
21302
 
@@ -21376,7 +21422,7 @@ async function getLastAgentFromSession(sessionID, client) {
21376
21422
 
21377
21423
  // src/hooks/architect/event-handler.ts
21378
21424
  var CONTINUATION_COOLDOWN_MS = 5000;
21379
- function createAtlasEventHandler(input) {
21425
+ function createArchitectEventHandler(input) {
21380
21426
  const { ctx, options, sessions, getState } = input;
21381
21427
  return async ({ event }) => {
21382
21428
  const props = event.properties;
@@ -21450,6 +21496,7 @@ function createAtlasEventHandler(input) {
21450
21496
  const progress = getPlanProgress(missionState.active_plan);
21451
21497
  if (progress.isComplete) {
21452
21498
  log(`[${HOOK_NAME}] Mission complete`, { sessionID, plan: missionState.plan_name });
21499
+ clearMissionState(ctx.directory);
21453
21500
  return;
21454
21501
  }
21455
21502
  const now = Date.now();
@@ -21591,15 +21638,24 @@ Read(".matrixx/plans/${planName}.md")
21591
21638
  Count exactly: how many \`- [ ]\` remain? How many \`- [x]\` completed?
21592
21639
  This is YOUR ground truth. Use it to decide what comes next.
21593
21640
 
21594
- **STEP 7: MARK COMPLETION IN PLAN FILE (IMMEDIATELY)**
21641
+ **STEP 7: MARK COMPLETION IN PLAN FILE (IMMEDIATELY \u2014 NON-NEGOTIABLE)**
21595
21642
 
21596
- RIGHT NOW - Do not delay. Verification passed \u2192 Mark IMMEDIATELY.
21643
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
21597
21644
 
21598
- Update the plan file \`.matrixx/plans/${planName}.md\`:
21599
- - Change \`- [ ]\` to \`- [x]\` for the completed task
21600
- - Use \`Edit\` tool to modify the checkbox
21645
+ **CRITICAL: THIS STEP IS MANDATORY. Skipping it = progress lost.**
21601
21646
 
21602
- **DO THIS BEFORE ANYTHING ELSE. Unmarked = Untracked = Lost progress.**
21647
+ RIGHT NOW \u2014 Do not delay. Verification passed \u2192 Mark IMMEDIATELY.
21648
+
21649
+ 1. Open plan file: \`.matrixx/plans/${planName}.md\`
21650
+ 2. Find the \`- [ ]\` checkbox for the completed task
21651
+ 3. Change \`- [ ]\` \u2192 \`- [x]\` using the \`Edit\` tool
21652
+ 4. Verify the edit was applied
21653
+
21654
+ **WARNING**: If you skip this step, the task appears UNDONE.
21655
+ The system counts \`- [x]\` checkboxes to track progress.
21656
+ No checkbox = No progress = Work wasted.
21657
+
21658
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
21603
21659
 
21604
21660
  **STEP 8: COMMIT ATOMIC UNIT**
21605
21661
 
@@ -21700,6 +21756,9 @@ function createToolExecuteAfterHandler(input) {
21700
21756
  const missionState = readMissionState(ctx.directory);
21701
21757
  if (missionState) {
21702
21758
  const progress = getPlanProgress(missionState.active_plan);
21759
+ if (progress.isComplete) {
21760
+ return;
21761
+ }
21703
21762
  if (toolInput.sessionID && !missionState.session_ids?.includes(toolInput.sessionID)) {
21704
21763
  appendSessionId(ctx.directory, toolInput.sessionID);
21705
21764
  log(`[${HOOK_NAME}] Appended session to mission`, {
@@ -21778,8 +21837,8 @@ ${prompt}`;
21778
21837
  };
21779
21838
  }
21780
21839
 
21781
- // src/hooks/architect/atlas-hook.ts
21782
- function createAtlasHook(ctx, options) {
21840
+ // src/hooks/architect/architect-hook.ts
21841
+ function createArchitectHook(ctx, options) {
21783
21842
  const sessions = new Map;
21784
21843
  const pendingFilePaths = new Map;
21785
21844
  function getState(sessionID) {
@@ -21791,7 +21850,7 @@ function createAtlasHook(ctx, options) {
21791
21850
  return state3;
21792
21851
  }
21793
21852
  return {
21794
- handler: createAtlasEventHandler({ ctx, options, sessions, getState }),
21853
+ handler: createArchitectEventHandler({ ctx, options, sessions, getState }),
21795
21854
  "tool.execute.before": createToolExecuteBeforeHandler({ ctx, pendingFilePaths }),
21796
21855
  "tool.execute.after": createToolExecuteAfterHandler({ ctx, pendingFilePaths })
21797
21856
  };
@@ -21870,6 +21929,22 @@ function findSlashCommandPartIndex(parts) {
21870
21929
  import { existsSync as existsSync22, readdirSync as readdirSync10, readFileSync as readFileSync17 } from "fs";
21871
21930
  import { basename as basename3, dirname as dirname4, join as join31 } from "path";
21872
21931
 
21932
+ // src/features/builtin-commands/templates/assembly.ts
21933
+ var ASSEMBLY_TEMPLATE = `Toggle assembly tool availability for the current session.
21934
+
21935
+ This command will:
21936
+ 1. Enable the assembly tool \u2014 makes multi-model voting available to the LLM
21937
+ 2. Disable the assembly tool \u2014 hides it from the LLM for this session
21938
+ 3. Show current assembly tool status
21939
+
21940
+ Usage:
21941
+ /assembly enable \u2014 Show assembly tool
21942
+ /assembly disable \u2014 Hide assembly tool
21943
+ /assembly status \u2014 Show current state
21944
+
21945
+ The change is per-session and clears when the session ends.
21946
+ By default, the assembly tool is enabled and available in every session.`;
21947
+
21873
21948
  // src/features/builtin-commands/templates/end-ultrawork.ts
21874
21949
  var END_ULTRAWORK_TEMPLATE = `Deactivate ultrawork mode for the current session.
21875
21950
 
@@ -23438,6 +23513,51 @@ $ARGUMENTS
23438
23513
  </user-request>
23439
23514
  `;
23440
23515
 
23516
+ // src/features/builtin-commands/templates/research.ts
23517
+ var RESEARCH_TEMPLATE = `# /research \u2014 Saturation Research Command
23518
+
23519
+ Execute a systematic multi-round research process on the given topic.
23520
+
23521
+ ## Usage
23522
+
23523
+ \`\`\`
23524
+ /research <topic> \u2192 Full research (all directions)
23525
+ /research <topic> --scope=code \u2192 Local codebase only
23526
+ /research <topic> --scope=docs \u2192 Documentation only
23527
+ /research <topic> --scope=web \u2192 Web search only
23528
+ /research <topic> --scope=oss \u2192 OSS repos only
23529
+ /research <topic> --max-rounds=3 \u2192 Limit to 3 rounds
23530
+ \`\`\`
23531
+
23532
+ ## What Happens
23533
+
23534
+ 1. Creates artifact directory: \`.matrixx/research-<topic>-<timestamp>/\`
23535
+ 2. Spawns 4 parallel research agents (explore + operator swarms)
23536
+ 3. Collects findings, identifies new leads
23537
+ 4. Recursively follows leads until convergence (novelty-based stop, max 5 rounds)
23538
+ 5. Verifies contested claims by running code
23539
+ 6. Produces cited synthesis in \`final-synthesis.md\`
23540
+
23541
+ ## Output
23542
+
23543
+ All artifacts written to \`.matrixx/research-<topic>-<timestamp>/\`:
23544
+ - \`round-N-findings.md\` \u2014 per-round findings
23545
+ - \`leads.md\` \u2014 tracked leads
23546
+ - \`contested-claims.md\` \u2014 claims needing verification
23547
+ - \`final-synthesis.md\` \u2014 the final cited synthesis
23548
+
23549
+ ## Examples
23550
+
23551
+ \`\`\`
23552
+ /research how does context window management work in this codebase
23553
+ /research React 19 server component patterns --scope=web --max-rounds=3
23554
+ /research authentication middleware best practices --scope=all
23555
+ \`\`\`
23556
+
23557
+ ---
23558
+
23559
+ Execute the full research protocol using the ulw-research skill.`;
23560
+
23441
23561
  // src/features/builtin-commands/templates/start-work.ts
23442
23562
  var START_WORK_TEMPLATE = `You are starting a Morpheus work session.
23443
23563
 
@@ -23466,7 +23586,7 @@ var START_WORK_TEMPLATE = `You are starting a Morpheus work session.
23466
23586
  }
23467
23587
  \`\`\`
23468
23588
 
23469
- 5. **Read the plan file** and start executing tasks according to atlas workflow
23589
+ 5. **Read the plan file** and start executing tasks according to architect workflow
23470
23590
 
23471
23591
  ## OUTPUT FORMAT
23472
23592
 
@@ -23510,7 +23630,7 @@ Reading plan and beginning execution...
23510
23630
  - The session_id is injected by the hook - use it directly
23511
23631
  - Always update mission.json BEFORE starting work
23512
23632
  - Read the FULL plan file before delegating any tasks
23513
- - Follow atlas delegation protocols (7-section format)`;
23633
+ - Follow architect delegation protocols (7-section format)`;
23514
23634
 
23515
23635
  // src/features/builtin-commands/templates/stop-continuation.ts
23516
23636
  var STOP_CONTINUATION_TEMPLATE = `Stop all continuation mechanisms for the current session.
@@ -23527,6 +23647,22 @@ After running this command:
23527
23647
 
23528
23648
  Use this when you need to pause automated continuation and take manual control.`;
23529
23649
 
23650
+ // src/features/builtin-commands/templates/ultrawork.ts
23651
+ var ULTRAWORK_TEMPLATE = `Toggle ultrawork mode for the current session.
23652
+
23653
+ This command will:
23654
+ 1. Enable ultrawork mode \u2014 injects ultrawork mode instructions into every message
23655
+ 2. Disable ultrawork mode \u2014 prevents ultrawork mode from activating (even on "ultrawork" keyword)
23656
+ 3. Show current ultrawork mode status
23657
+
23658
+ Usage:
23659
+ /ultrawork enable \u2014 Force ultrawork mode on all messages
23660
+ /ultrawork disable \u2014 Block ultrawork mode (keyword ignored)
23661
+ /ultrawork status \u2014 Show current state
23662
+
23663
+ The change is per-session and clears when the session ends.
23664
+ By default, ultrawork mode activates when the LLM or user mentions the "ultrawork" keyword.`;
23665
+
23530
23666
  // src/features/builtin-commands/commands.ts
23531
23667
  var BUILTIN_COMMAND_DEFINITIONS = {
23532
23668
  "init-deep": {
@@ -23653,6 +23789,39 @@ ${END_ULTRAWORK_TEMPLATE}
23653
23789
  $ARGUMENTS
23654
23790
  </user-request>`,
23655
23791
  argumentHint: "[optional follow-up task]"
23792
+ },
23793
+ research: {
23794
+ description: "(builtin) Saturation research with parallel swarms and convergence \u2014 code, docs, web, and OSS repos",
23795
+ template: `<command-instruction>
23796
+ ${RESEARCH_TEMPLATE}
23797
+ </command-instruction>
23798
+
23799
+ <user-request>
23800
+ $ARGUMENTS
23801
+ </user-request>`,
23802
+ argumentHint: "<topic> [--scope=code|docs|web|oss|all] [--max-rounds=N]"
23803
+ },
23804
+ assembly: {
23805
+ description: "(builtin) Toggle assembly tool enable/disable for the current session",
23806
+ template: `<command-instruction>
23807
+ ${ASSEMBLY_TEMPLATE}
23808
+ </command-instruction>
23809
+
23810
+ <user-request>
23811
+ $ARGUMENTS
23812
+ </user-request>`,
23813
+ argumentHint: "[enable|disable|status]"
23814
+ },
23815
+ ultrawork: {
23816
+ description: "(builtin) Toggle ultrawork mode on/off for the current session",
23817
+ template: `<command-instruction>
23818
+ ${ULTRAWORK_TEMPLATE}
23819
+ </command-instruction>
23820
+
23821
+ <user-request>
23822
+ $ARGUMENTS
23823
+ </user-request>`,
23824
+ argumentHint: "[enable|disable|status]"
23656
23825
  }
23657
23826
  };
23658
23827
  function loadBuiltinCommands(disabledCommands) {
@@ -30252,17 +30421,306 @@ Fix these inline when possible. For bulk fixes, run \`bun run lint:fix\`.
30252
30421
  | Report done without running verification | Never trust \u2014 always verify |
30253
30422
  `
30254
30423
  };
30424
+ // src/features/builtin-skills/skills/remove-ai-slops.ts
30425
+ var REMOVE_AI_SLOPS_SKILL_NAME = "remove-ai-slops";
30426
+ var REMOVE_AI_SLOPS_SKILL_DESCRIPTION = "Detects and removes AI-generated code smells across 7 categories: verbose comments, redundant error handling, over-engineered patterns, generic AI phrasing, cargo-cult boilerplate, padding/verbosity, weird codegen artifacts. Hybrid mode: scan first, then guide fixes. Triggers: 'cleanup code', 'remove ai slop', 'code cleanup', 'fix ai code', 'de-ai', 'remove ai comments', 'clean ai smells'.";
30427
+ var removeAiSlopsSkill = {
30428
+ name: REMOVE_AI_SLOPS_SKILL_NAME,
30429
+ description: REMOVE_AI_SLOPS_SKILL_DESCRIPTION,
30430
+ allowedTools: [
30431
+ "read",
30432
+ "write",
30433
+ "edit",
30434
+ "grep",
30435
+ "glob",
30436
+ "ast_grep_search",
30437
+ "ast_grep_replace",
30438
+ "lsp_diagnostics",
30439
+ "lsp_find_references"
30440
+ ],
30441
+ template: `# Remove AI Slops \u2014 Code Smell Detector & Fixer
30442
+
30443
+ Detect and fix AI-generated code smells across 7 categories. Operates in **hybrid mode**: scan first to identify issues, then guide you through fixes one finding at a time.
30444
+
30445
+ ## Phase 0: Scope & Setup
30446
+
30447
+ Determine scope:
30448
+ - If no files specified, scan recently changed files (\`git diff --name-only HEAD~1\`)
30449
+ - If a file/dir is specified, scan those
30450
+ - If \`--all\` flag, scan entire \`src/\` directory
30451
+
30452
+ Create \`.matrixx/slop-scan-<timestamp>.md\` for tracking findings.
30453
+
30454
+ ## Phase 1: Scan for Slop
30455
+
30456
+ Run all 7 category detectors. For each category, output findings grouped by file with line ranges.
30457
+
30458
+ ---
30459
+
30460
+ ### Category 1: Verbose Comments
30461
+
30462
+ **Detect**: AST patterns and regex for comments that restate the obvious.
30463
+
30464
+ **Patterns to flag:**
30465
+ - \`// This function does X by doing Y\` \u2014 describes implementation, not intent
30466
+ - \`// Loop through each item\` \u2014 obvious from the \`for\` loop itself
30467
+ - \`// Initialize variable\` \u2014 obvious from \`const x =\`
30468
+ - \`// Return result\` \u2014 obvious from \`return\`
30469
+ - \`// Call the API\` \u2014 obvious from the function call on the next line
30470
+ - \`// Check if condition is true\` \u2014 obvious from \`if\`
30471
+ - Block comments that just repeat what the function signature says
30472
+
30473
+ **Detection:**
30474
+ - Use \`ast_grep_search\` with patterns like:
30475
+ - \`// $COMMENT\` where $COMMENT matches obvious patterns
30476
+ - Function-level JSDoc that adds no info beyond the signature
30477
+ - Use \`grep\` with regex for known AI comment phrases
30478
+
30479
+ **Severity**: LOW (cosmetic, but clutters code)
30480
+
30481
+ ---
30482
+
30483
+ ### Category 2: Redundant Error Handling
30484
+
30485
+ **Detect**: Error handling patterns that add no value.
30486
+
30487
+ **Patterns to flag:**
30488
+ - Empty catch blocks: \`catch (e) {}\`
30489
+ - Catch-and-rethrow: \`catch(e) { console.error(e); throw e; }\` (re-throw with no added value)
30490
+ - Redundant null checks on already-guarded paths
30491
+ - \`try/catch\` that wraps every single function call individually
30492
+ - \`catch (error: any)\` (TypeScript \u2014 \`unknown\` preferred)
30493
+
30494
+ **Detection:**
30495
+ - Use \`ast_grep_search\` for \`catch($$$) { $$$ }\` and analyze body
30496
+ - \`ast_grep_search\` for \`if ($VAR != null)\` patterns on already-checked variables
30497
+ - Use \`lsp_find_references\` to check if null checks are redundant
30498
+
30499
+ **Severity**: MEDIUM (adds noise, but doesn't break things)
30500
+
30501
+ ---
30502
+
30503
+ ### Category 3: Over-Engineered Patterns
30504
+
30505
+ **Detect**: Unnecessary abstraction layers and overly complex patterns.
30506
+
30507
+ **Patterns to flag:**
30508
+ - Abstract factory factory or other nested indirection
30509
+ - AbstractSingletonProxyBean-style pattern names
30510
+ - Single-implementation interfaces (unless part of a public API contract)
30511
+ - Builder pattern for objects with 1-3 simple properties
30512
+ - Strategy pattern with a single strategy
30513
+ - Decorator patterns around every function
30514
+ - Excessive generic constraints (\`<T extends X extends Y extends Z>\`)
30515
+
30516
+ **Detection:**
30517
+ - Use \`lsp_find_references\` to check if interfaces have exactly 1 implementation
30518
+ - \`ast_grep_search\` for class names containing "Abstract", "Factory", "Builder", "Manager"
30519
+ - \`grep\` for pattern names like \`*Abstract*\`, \`*Factory*\`, \`*Proxy*\`, \`*Singleton*\`
30520
+ - Check for builder functions/classes with very few properties
30521
+
30522
+ **Severity**: HIGH (indicates misunderstanding of the codebase)
30523
+
30524
+ ---
30525
+
30526
+ ### Category 4: Generic AI Phrasing
30527
+
30528
+ **Detect**: Code comments and documentation with AI-typical phrasing.
30529
+
30530
+ **Phrases to flag (regex case-insensitive):**
30531
+ - "It's worth noting that"
30532
+ - "It is important to note"
30533
+ - "It is important to mention"
30534
+ - "Let's step through this"
30535
+ - "In conclusion"
30536
+ - "As previously mentioned"
30537
+ - "It should be noted that"
30538
+ - "It's crucial to understand"
30539
+ - "Let's break this down"
30540
+ - "The beauty of this approach"
30541
+ - "This is a classic example of"
30542
+ - "Essentially, what this does is"
30543
+ - "In the world of"
30544
+ - "When it comes to"
30545
+ - "One might argue that"
30546
+ - "It goes without saying"
30547
+
30548
+ **Detection:**
30549
+ - Use \`grep -i\` with regex patterns for each phrase in \`*.ts\` and \`*.md\` files
30550
+ - Focus comments, docstrings, and inline documentation
30551
+
30552
+ **Severity**: LOW (cosmetic, but unprofessional)
30553
+
30554
+ ---
30555
+
30556
+ ### Category 5: Cargo-Cult Boilerplate
30557
+
30558
+ **Detect**: Patterns copied without understanding.
30559
+
30560
+ **Patterns to flag:**
30561
+ - Excessive defensive programming (checking the same condition at multiple levels)
30562
+ - \`try/catch\` with \`console.error\` and rethrow in every function
30563
+ - Identical error handling block copy-pasted across multiple functions
30564
+ - Redundant type guards on already-typed parameters
30565
+ - \`if (process.env.NODE_ENV !== 'production')\` debug logging patterns
30566
+ - \`// TODO: implement\` stubs in production code
30567
+ - Mock implementations that replicate the real implementation exactly
30568
+
30569
+ **Detection:**
30570
+ - Use \`grep\` to find repeated identical code blocks across files
30571
+ - \`ast_grep_search\` for try/catch patterns in every function of a file
30572
+ - \`grep\` for TODO/FIXME/HACK comments in non-test files
30573
+ - Check for \`console.log\` statements in production code
30574
+
30575
+ **Severity**: MEDIUM (code bloat, maintenance burden)
30576
+
30577
+ ---
30578
+
30579
+ ### Category 6: Padding/Verbosity
30580
+
30581
+ **Detect**: Unnecessary code that adds no information.
30582
+
30583
+ **Patterns to flag:**
30584
+ - Empty \`@returns\` tags in JSDoc
30585
+ - \`@param {string} name - The name\` \u2014 repeats the obvious
30586
+ - Redundant type annotations: \`const x: string = "hello"\` (type is obvious)
30587
+ - Unnecessary intermediate variables: \`const result = doSomething(); return result;\` when \`return doSomething()\` works
30588
+ - \`const x = y as SomeType\` when y is already SomeType
30589
+ - \`() => { return x }\` when \`() => x\` works
30590
+ - Destructuring with unused variables
30591
+ - \`export default\` for a single export (prefer named)
30592
+ - Variables assigned but never read
30593
+
30594
+ **Detection:**
30595
+ - Use \`ast_grep_search\` for \`const $VAR = $EXPR as $TYPE\` where $VAR is typed
30596
+ - \`ast_grep_search\` for \`() => { return { $$$ } }\`
30597
+ - \`grep\` for \`@returns\` without description in JSDoc
30598
+ - \`lsp_diagnostics\` will catch unused variables
30599
+
30600
+ **Severity**: LOW (cosmetic, minor bloat)
30601
+
30602
+ ---
30603
+
30604
+ ### Category 7: Weird Codegen Artifacts
30605
+
30606
+ **Detect**: Inconsistencies that suggest AI-generated code was inserted without review.
30607
+
30608
+ **Patterns to flag:**
30609
+ - Mix of import styles in the same file (CommonJS + ESM, default + named)
30610
+ - Inconsistent error handling within the same file (some async/await, some .then())
30611
+ - Mixed indentation or naming conventions in the same file
30612
+ - Unused imports (LSP will catch these)
30613
+ - \`import * as\` that imports everything but only uses one thing
30614
+ - Code that doesn't follow the file's established patterns
30615
+ - Types/interfaces defined inline instead of in a shared types file
30616
+ - Magic numbers and strings that should be constants
30617
+ - Language-mismatched conventions (e.g., Java-style getters/setters in TypeScript)
30618
+
30619
+ **Detection:**
30620
+ - Use \`grep\` for mixed module systems in the same file
30621
+ - \`lsp_diagnostics\` for unused imports
30622
+ - \`ast_grep_search\` for inline type definitions that should be shared
30623
+ - Manual review of file-level pattern consistency
30624
+
30625
+ **Severity**: MEDIUM-HIGH (indicates un-reviewed code)
30626
+
30627
+ ---
30628
+
30629
+ ## Phase 2: Report Findings
30630
+
30631
+ After scanning all categories, present a structured report:
30632
+
30633
+ \`\`\`markdown
30634
+ # AI Slop Scan Results
30635
+
30636
+ Scanned: <files/dirs>
30637
+ Total findings: <count>
30638
+
30639
+ | Category | Count | Critical | High | Medium | Low |
30640
+ |----------|-------|----------|------|--------|-----|
30641
+ | 1. Verbose Comments | N | - | - | - | N |
30642
+ | 2. Redundant Error Handling | N | - | N | N | - |
30643
+ | ... | ... | ... | ... | ... | ... |
30644
+
30645
+ ## Findings by File
30646
+
30647
+ ### <file-path.ts>
30648
+
30649
+ #### [HIGH] Category 3: Over-Engineered \u2014 AbstractUserFactoryManager
30650
+ - **Location**: line 42-89
30651
+ - **Current**: \`class AbstractUserFactoryManager<T extends ...>\`
30652
+ - **Suggestion**: Replace with simple function \`createUser()\`
30653
+ - **Severity**: HIGH
30654
+ - **Status**: PENDING
30655
+
30656
+ #### [MED] Category 2: Redundant Error Handling
30657
+ - **Location**: line 15-18
30658
+ - **Current**:
30659
+ \`\`\`typescript
30660
+ try {
30661
+ await doSomething()
30662
+ } catch (e) {
30663
+ console.error(e)
30664
+ throw e
30665
+ }
30666
+ \`\`\`
30667
+ - **Suggestion**: Remove try/catch \u2014 caller handles errors. Or add meaningful error context.
30668
+ - **Severity**: MEDIUM
30669
+ - **Status**: PENDING
30670
+
30671
+ ... (repeat for all findings)
30672
+ \`\`\`
30673
+
30674
+ ## Phase 3: Guided Fix
30675
+
30676
+ For each finding, present the user with options:
30677
+
30678
+ 1. **Apply fix** \u2014 Show the proposed change as a diff, ask for confirmation
30679
+ 2. **Skip** \u2014 Mark as reviewed and acceptable
30680
+ 3. **Snooze** \u2014 Skip for now but flag for later review
30681
+ 4. **Adjust** \u2014 User provides alternative fix
30682
+
30683
+ Apply fixes using the \`edit\` tool only after user confirmation.
30684
+
30685
+ **Fix application pattern:**
30686
+ 1. Present the proposed replacement code
30687
+ 2. Wait for user response (\`y\`/\`n\`/\`skip\`/\`adjust\`)
30688
+ 3. On approval: \`edit\` the file
30689
+ 4. Run \`lsp_diagnostics\` on the file to verify no new errors
30690
+ 5. Mark finding as FIXED / SKIPPED
30691
+
30692
+ **Batch support**: User can say "apply all LOW" or "apply all for file X" to batch-approve.
30693
+
30694
+ ## Phase 4: Verify
30695
+
30696
+ After all fixes applied:
30697
+ 1. \`bun run typecheck\` \u2014 no new type errors
30698
+ 2. \`bun run lint\` \u2014 no new lint errors
30699
+ 3. Verify no changes broke tests for affected files
30700
+
30701
+ Write final summary to \`.matrixx/slop-scan-<timestamp>.md\`.
30702
+
30703
+ ## Rules
30704
+
30705
+ - NEVER auto-apply fixes without user approval
30706
+ - ALWAYS show the proposed change before applying
30707
+ - ALWAYS run \`lsp_diagnostics\` after each edit
30708
+ - Scan ALL 7 categories every time \u2014 don't skip categories
30709
+ - Flag findings only once (deduplicate across rounds)
30710
+ - For \`--all\` mode, process files in batches of 5 to avoid overload
30711
+ - If a pattern is clearly intentional (pre-existing convention), skip it`
30712
+ };
30255
30713
  // src/features/builtin-skills/skills/review-work.ts
30256
30714
  var REVIEW_WORK_SKILL_NAME = "review-work";
30257
- var REVIEW_WORK_SKILL_DESCRIPTION = "Post-implementation review orchestrator. Launches 5 parallel background sub-agents: Oracle (goal/constraint verification), Oracle (code quality), Oracle (security), unspecified-high (hands-on QA execution), unspecified-high (context mining from GitHub/git/Slack/Notion). All must pass for review to pass. MUST USE after completing any significant implementation work. Triggers: 'review work', 'review my work', 'review changes', 'QA my work', 'verify implementation', 'check my work', 'validate changes', 'post-implementation review'.";
30715
+ var REVIEW_WORK_SKILL_DESCRIPTION = "Post-implementation review orchestrator. Launches 6 parallel background sub-agents: Oracle (goal/constraint verification), Oracle (code quality), Oracle (security), unspecified-high (hands-on QA execution), unspecified-high (context mining from GitHub/git/Slack/Notion), unspecified-high (AI slop detection). All must pass for review to pass. MUST USE after completing any significant implementation work. Triggers: 'review work', 'review my work', 'review changes', 'QA my work', 'verify implementation', 'check my work', 'validate changes', 'post-implementation review'.";
30258
30716
  var reviewWorkSkill = {
30259
30717
  name: REVIEW_WORK_SKILL_NAME,
30260
30718
  description: REVIEW_WORK_SKILL_DESCRIPTION,
30261
30719
  template: `# Review Work - 5-Agent Parallel Review Orchestrator
30262
30720
 
30263
- Launch 5 specialized sub-agents in parallel to review completed implementation work from every angle. All 5 must pass for the review to pass. If even ONE fails, the review fails.
30721
+ Launch 6 specialized sub-agents in parallel to review completed implementation work from every angle. All 6 must pass for the review to pass. If even ONE fails, the review fails.
30264
30722
 
30265
- The 5 agents cover complementary concerns - together they form a comprehensive review that no single reviewer could match:
30723
+ The 6 agents cover complementary concerns - together they form a comprehensive review that no single reviewer could match:
30266
30724
 
30267
30725
  | # | Agent | Type | Role | Focus Level |
30268
30726
  |---|-------|------|------|-------------|
@@ -30271,6 +30729,7 @@ The 5 agents cover complementary concerns - together they form a comprehensive r
30271
30729
  | 3 | Code Reviewer | Oracle | Is the code well-written? | MAIN |
30272
30730
  | 4 | Security Auditor | Oracle | Is it secure? | SUB |
30273
30731
  | 5 | Context Miner | unspecified-high | Did we miss any context? | MAIN |
30732
+ | 6 | AI Slop Detector | unspecified-high | Remove AI-generated code smells | SUP |
30274
30733
 
30275
30734
  ---
30276
30735
 
@@ -30604,9 +31063,54 @@ OUTPUT FORMAT:
30604
31063
 
30605
31064
  ---
30606
31065
 
31066
+ ### Agent 6: AI Slop Detection (unspecified-high) - SUP
31067
+
31068
+ \`\`\`
31069
+ task(
31070
+ category="unspecified-high",
31071
+ run_in_background=true,
31072
+ load_skills=["remove-ai-slops"],
31073
+ description="Detect AI-generated code smells in changes",
31074
+ prompt="""
31075
+ <review_type>AI SLOP DETECTION (supplementary)</review_type>
31076
+
31077
+ <original_goal>
31078
+ {GOAL}
31079
+ </original_goal>
31080
+
31081
+ <changed_files>
31082
+ {CHANGED_FILES}
31083
+ </changed_files>
31084
+
31085
+ <background>
31086
+ {BACKGROUND}
31087
+ </background>
31088
+
31089
+ Review the changed files for AI-generated code smells. Load and follow the \`remove-ai-slops\` skill.
31090
+
31091
+ Run the scan across all 7 categories:
31092
+ 1. Verbose Comments \u2014 comments that restate the obvious
31093
+ 2. Redundant Error Handling \u2014 catch-and-rethrow, empty catches, redundant null checks
31094
+ 3. Over-Engineered Patterns \u2014 unnecessary abstractions, single-use interfaces
31095
+ 4. Generic AI Phrasing \u2014 "It's worth noting...", "Let's step through..."
31096
+ 5. Cargo-Cult Boilerplate \u2014 repeated identical blocks, TODO stubs
31097
+ 6. Padding/Verbosity \u2014 empty JSDoc, redundant type annotations
31098
+ 7. Weird Codegen Artifacts \u2014 mixed import styles, inconsistent patterns
31099
+
31100
+ OUTPUT FORMAT:
31101
+ <verdict>PASS or FAIL (FAIL only if HIGH severity issues found)</verdict>
31102
+ <severity>NONE / LOW / MEDIUM / HIGH</severity>
31103
+ <summary>1-3 sentence overall assessment</summary>
31104
+ <findings>- [CATEGORY_N] [HIGH/MEDIUM/LOW] Description - File:path:line - Current / Suggestion</findings>
31105
+ <recommendations>Suggested fixes for findings. Empty if PASS.</recommendations>
31106
+ """)
31107
+ \`\`\`
31108
+
31109
+ ---
31110
+
30607
31111
  ## Phase 2: Wait & Collect
30608
31112
 
30609
- After launching all 5 agents in one turn, **end your response**. Wait for system notifications as each agent completes.
31113
+ After launching all 6 agents in one turn, **end your response**. Wait for system notifications as each agent completes.
30610
31114
 
30611
31115
  Collect via \`background_output(task_id="...")\` as each completes. Track verdicts:
30612
31116
 
@@ -30617,14 +31121,15 @@ Collect via \`background_output(task_id="...")\` as each completes. Track verdic
30617
31121
  | 3. Code Quality | pending | - |
30618
31122
  | 4. Security | pending | - |
30619
31123
  | 5. Context Mining | pending | - |
31124
+ | 6. AI Slop Detection | pending | - |
30620
31125
 
30621
- Do NOT deliver the final report until ALL 5 have completed.
31126
+ Do NOT deliver the final report until ALL 6 have completed.
30622
31127
 
30623
31128
  ---
30624
31129
 
30625
31130
  ## Phase 3: Deliver Verdict
30626
31131
 
30627
- ALL 5 returned PASS \u2192 **REVIEW PASSED**
31132
+ ALL 6 returned PASS \u2192 **REVIEW PASSED**
30628
31133
  ANY returned FAIL \u2192 **REVIEW FAILED**
30629
31134
 
30630
31135
  Final report format:
@@ -30641,6 +31146,7 @@ Final report format:
30641
31146
  | 3 | Code Quality | Oracle | PASS/FAIL | HIGH/MED/LOW |
30642
31147
  | 4 | Security (supplementary) | Oracle | PASS/FAIL | Severity |
30643
31148
  | 5 | Context Mining | unspecified-high | PASS/FAIL | HIGH/MED/LOW |
31149
+ | 6 | AI Slop Detection (supplementary) | unspecified-high | PASS/FAIL | NONE/LOW/MED/HIGH |
30644
31150
 
30645
31151
  ## Blocking Issues
30646
31152
  [Aggregated from all agents - deduplicated, prioritized]
@@ -31828,6 +32334,252 @@ NEVER write tests AFTER implementation \u2014 write them BEFORE
31828
32334
  \`\`\`
31829
32335
  `
31830
32336
  };
32337
+ // src/features/builtin-skills/skills/ulw-research.ts
32338
+ var ULW_RESEARCH_SKILL_NAME = "ulw-research";
32339
+ var ULW_RESEARCH_SKILL_DESCRIPTION = "Saturation research orchestrator. Spawns parallel explore/librarian swarms across code, docs, web, and OSS repos. Recursively follows EXPAND leads until convergence (novelty-based, max 5 rounds). Proves contested claims by running code. Returns cited synthesis. Writes artifacts to .matrixx/. Triggers: 'research', 'deep dive', 'investigate', 'explore codebase', 'find how', 'saturation research', 'ulw research'.";
32340
+ var ulwResearchSkill = {
32341
+ name: ULW_RESEARCH_SKILL_NAME,
32342
+ description: ULW_RESEARCH_SKILL_DESCRIPTION,
32343
+ agent: "oracle",
32344
+ allowedTools: [
32345
+ "read",
32346
+ "write",
32347
+ "edit",
32348
+ "bash",
32349
+ "grep",
32350
+ "glob",
32351
+ "look_at",
32352
+ "delegate_agent",
32353
+ "websearch_web_search_exa",
32354
+ "grep_app_searchGitHub",
32355
+ "context7_resolve-library-id",
32356
+ "context7_query-docs"
32357
+ ],
32358
+ template: `# ULW-Research \u2014 Saturation Research Orchestrator
32359
+
32360
+ Run a systematic, multi-round research process that converges on comprehensive coverage.
32361
+
32362
+ ## Inputs
32363
+
32364
+ - **TOPIC**: The research question or topic (from user message)
32365
+ - **SCOPE**: Optional scope narrowing (--scope=code|docs|web|oss|all, default: all)
32366
+ - **MAX_ROUNDS**: Optional (--max-rounds=N, default: 5, hard limit: 5)
32367
+
32368
+ ## Artifact Directory
32369
+
32370
+ Create \`.matrixx/research-<slug>-<timestamp>/\` for all outputs:
32371
+ - \`meta.md\` \u2014 Research metadata (topic, scope, start time, max rounds)
32372
+ - \`round-<N>-findings.md\` \u2014 Per-round combined findings
32373
+ - \`leads.md\` \u2014 Tracked EXPAND leads across rounds (status: pending/explored/exhausted)
32374
+ - \`contested-claims.md\` \u2014 Claims that need code verification
32375
+ - \`convergence-log.md\` \u2014 Novelty scores and decisions per round
32376
+ - \`final-synthesis.md\` \u2014 Cited synthesis (final deliverable)
32377
+
32378
+ All artifacts are written via the \`write\` tool. The next session can resume from artifacts if interrupted.
32379
+
32380
+ ## Phase 0: Parse and Seed
32381
+
32382
+ 1. Create artifact directory: \`.matrixx/research-<topic-slug>-<YYYYMMDD-HHmmss>/\`
32383
+ 2. Write \`meta.md\` with topic, timestamp, scope, max rounds
32384
+ 3. Initialize \`leads.md\` with seed queries extracted from the topic:
32385
+ - 1-3 code-local search terms
32386
+ - 1-3 documentation/Context7 search terms
32387
+ - 1-3 web search terms
32388
+ - 1-3 OSS repository search terms
32389
+ 4. Write round 0 to \`convergence-log.md\`
32390
+
32391
+ ## Phase 1: Parallel Swarm (per round)
32392
+
32393
+ For each round, spawn 4 parallel background agents. Each agent gets ONLY its direction-specific query (not the full research state).
32394
+
32395
+ ### Direction 1: Local Code (explore agent)
32396
+
32397
+ \`\`\`
32398
+ task(
32399
+ subagent_type="explore",
32400
+ run_in_background=true,
32401
+ description="Research code: <lead>",
32402
+ prompt="""
32403
+ Search the local codebase for implementations, patterns, and references related to: <CURRENT_LEAD>
32404
+
32405
+ Use grep, glob, and read tools. Find:
32406
+ - Relevant source files and their key functions
32407
+ - Architectural patterns used
32408
+ - Configuration and usage examples
32409
+ - Related tests that reveal intended behavior
32410
+
32411
+ OUTPUT: List of findings with file paths, line numbers, and brief descriptions.
32412
+ Flag any claims that seem contested or unverifiable by reading alone.
32413
+ """)
32414
+ \`\`\`
32415
+
32416
+ ### Direction 2: Documentation (explore agent)
32417
+
32418
+ \`\`\`
32419
+ task(
32420
+ subagent_type="explore",
32421
+ run_in_background=true,
32422
+ description="Research docs: <lead>",
32423
+ prompt="""
32424
+ Research documentation and knowledge base files related to: <CURRENT_LEAD>
32425
+
32426
+ Read AGENTS.md files, README.md, doc/ directories, and inline documentation.
32427
+ Use context7_resolve-library-id and context7_query-docs for library/framework docs.
32428
+
32429
+ OUTPUT: Structured findings from docs with source attribution.
32430
+ Flag any claims that contradict other sources.
32431
+ """)
32432
+ \`\`\`
32433
+
32434
+ ### Direction 3: Web (operator agent)
32435
+
32436
+ \`\`\`
32437
+ task(
32438
+ subagent_type="operator",
32439
+ run_in_background=true,
32440
+ description="Research web: <lead>",
32441
+ prompt="""
32442
+ Research the web for information about: <CURRENT_LEAD>
32443
+
32444
+ Use websearch_web_search_exa and context7 tools. Find:
32445
+ - Official documentation and blog posts
32446
+ - Technical articles and tutorials
32447
+ - Implementation patterns and best practices
32448
+ - Real-world usage examples
32449
+
32450
+ OUTPUT: Cited findings with URLs, publication dates, and reliability assessment.
32451
+ Flag any contested claims or conflicting information.
32452
+ """)
32453
+ \`\`\`
32454
+
32455
+ ### Direction 4: OSS Repos (operator agent)
32456
+
32457
+ \`\`\`
32458
+ task(
32459
+ subagent_type="operator",
32460
+ run_in_background=true,
32461
+ description="Research OSS: <lead>",
32462
+ prompt="""
32463
+ Search open source repositories for implementations related to: <CURRENT_LEAD>
32464
+
32465
+ Use grep_app_searchGitHub to find real-world code patterns.
32466
+ Focus on:
32467
+ - Production implementations in similar projects
32468
+ - Reference implementations or canonical examples
32469
+ - Common patterns and anti-patterns
32470
+ - Version-specific changes or migrations
32471
+
32472
+ OUTPUT: Code patterns with repo URLs, file paths, and usage context.
32473
+ Flag any patterns that seem contested or deprecated.
32474
+ """)
32475
+ \`\`\`
32476
+
32477
+ ### Collect Results
32478
+
32479
+ After all 4 agents complete, collect via \`background_output(task_id="...")\`:
32480
+ 1. Merge findings into \`round-<N>-findings.md\`
32481
+ 2. Extract new EXPAND leads \u2192 append to \`leads.md\`
32482
+ 3. Extract contested claims \u2192 append to \`contested-claims.md\`
32483
+
32484
+ ## Phase 2: Convergence Check (after each round)
32485
+
32486
+ Evaluate novelty by comparing this round's findings against ALL previous rounds:
32487
+
32488
+ 1. **Total items this round**: Count of unique file paths, URLs, code patterns, concepts, library names
32489
+ 2. **Novel items**: Items not present in ANY prior round
32490
+ 3. **Novelty ratio**: novel_items / total_items_this_round
32491
+
32492
+ **Decision:**
32493
+ - \`novelty_ratio > 0.3\` AND \`round < MAX_ROUNDS\` \u2192 **EXPAND**: Pick top 3 new leads, go to Phase 1
32494
+ - \`novelty_ratio <= 0.3\` \u2192 **STOP**: Natural convergence, proceed to Phase 4
32495
+ - \`round == MAX_ROUNDS\` \u2192 **STOP**: Forced convergence
32496
+ - \`total_items_this_round == 0\` \u2192 **STOP**: No findings
32497
+
32498
+ Record convergence state in \`convergence-log.md\` with round number and novelty score.
32499
+
32500
+ **Lead selection for next round**: Pick top 3 leads prioritizing:
32501
+ - Specificity (concrete file paths or URLs > vague concepts)
32502
+ - Freshness (leads from current round > old leads)
32503
+ - Diversity (one per direction preferred)
32504
+
32505
+ ## Phase 3: Contested Claim Verification (if needed)
32506
+
32507
+ If \`contested-claims.md\` is non-empty after convergence, verify each claim:
32508
+
32509
+ \`\`\`
32510
+ task(
32511
+ subagent_type="explore",
32512
+ run_in_background=true,
32513
+ description="Verify claim: <summary>",
32514
+ prompt="""
32515
+ Verify this contested claim by examining code:
32516
+
32517
+ CLAIM: <claim_text>
32518
+ EVIDENCE FOR: <supporting_evidence>
32519
+ EVIDENCE AGAINST: <opposing_evidence>
32520
+
32521
+ Verification steps:
32522
+ 1. Find the relevant source files
32523
+ 2. Read the implementation
32524
+ 3. If runnable: write a minimal test script and execute it
32525
+ 4. Determine verdict
32526
+
32527
+ OUTPUT:
32528
+ <verdict>CONFIRMED / REFUTED / INCONCLUSIVE</verdict>
32529
+ <evidence>Specific code or outputs supporting the verdict</evidence>
32530
+ """)
32531
+ \`\`\`
32532
+
32533
+ Max 10 contested claims verified. If none, skip Phase 3.
32534
+
32535
+ ## Phase 4: Final Synthesis
32536
+
32537
+ Produce \`final-synthesis.md\`:
32538
+
32539
+ \`\`\`markdown
32540
+ # Research Synthesis: <TOPIC>
32541
+
32542
+ **Date**: <timestamp>
32543
+ **Rounds**: <N> (converged at round <M>)
32544
+ **Sources**: <count> unique sources
32545
+
32546
+ ## Executive Summary
32547
+ 2-3 paragraphs synthesizing the most important findings.
32548
+
32549
+ ## Key Findings
32550
+
32551
+ ### Finding 1: <title>
32552
+ - **Status**: CONFIRMED / CONTESTED / INCONCLUSIVE
32553
+ - **Confidence**: HIGH / MEDIUM / LOW
32554
+ - **Summary**: 2-3 sentence synthesis
32555
+ - **Evidence**: Details with citations
32556
+ - **Sources**: [1] path, [2] URL, [3] repo
32557
+
32558
+ (Repeat for all significant findings)
32559
+
32560
+ ## Contested Claims Resolution
32561
+ | Claim | Verdict | Evidence |
32562
+ |-------|---------|----------|
32563
+
32564
+ ## Research Gaps
32565
+ - Areas not fully covered
32566
+ - Questions remaining unanswered
32567
+
32568
+ ## Source Index
32569
+ | # | Type | Source | Key Insight |
32570
+ |---|------|--------|-------------|
32571
+ \`\`\`
32572
+
32573
+ ## Rules
32574
+
32575
+ - NEVER fabricate citations \u2014 every claim must reference a real source found during research
32576
+ - ALWAYS write intermediate artifacts \u2014 preserves partial results if interrupted
32577
+ - MAX 5 rounds regardless of novelty
32578
+ - Each background agent gets a FOCUSED prompt \u2014 never dump the entire research state
32579
+ - Contested claims MUST be verified by code execution when possible
32580
+ - The final synthesis must be self-contained without intermediate artifacts
32581
+ - If a round produces zero findings, STOP immediately`
32582
+ };
31831
32583
  // src/features/builtin-skills/skills.ts
31832
32584
  function createBuiltinSkills(options = {}) {
31833
32585
  const { browserProvider = "playwright", disabledSkills: rawDisabledSkills } = options;
@@ -31840,7 +32592,7 @@ function createBuiltinSkills(options = {}) {
31840
32592
  } else {
31841
32593
  browserSkill = playwrightSkill;
31842
32594
  }
31843
- const skills = [browserSkill, frontendUiUxSkill, gitMasterSkill, devBrowserSkill, dslCoreSkill, dslGrammarSkill, dslCodegenSkill, dslMetamodelSkill, dslToolingSkill, dslTextxEcosystemSkill, dslPyecoreAdvancedSkill, dslModelTransformationSkill, dslTestingSkill, dslValidationSkill, dslCompositionSkill, frontendA11ySkill, frontendBuildToolingSkill, frontendPerfSkill, frontendStateDataSkill, frontendTestingSkill, reactNextjsPatternsSkill, svelteSveltekitPatternsSkill, documentReaderSkill, securityCoreSkill, securitySecretsSkill, securitySastSkill, securityDastSkill, securityDependenciesSkill, securityApiSkill, securityCryptoSkill, securityInfraSkill, securityReviewSkill, tddEnforcerSkill, reviewWorkSkill, qualityGateSkill, softwareDevSkill, matrixxSelfConfigSkill];
32595
+ const skills = [browserSkill, frontendUiUxSkill, gitMasterSkill, devBrowserSkill, dslCoreSkill, dslGrammarSkill, dslCodegenSkill, dslMetamodelSkill, dslToolingSkill, dslTextxEcosystemSkill, dslPyecoreAdvancedSkill, dslModelTransformationSkill, dslTestingSkill, dslValidationSkill, dslCompositionSkill, frontendA11ySkill, frontendBuildToolingSkill, frontendPerfSkill, frontendStateDataSkill, frontendTestingSkill, reactNextjsPatternsSkill, svelteSveltekitPatternsSkill, documentReaderSkill, securityCoreSkill, securitySecretsSkill, securitySastSkill, securityDastSkill, securityDependenciesSkill, securityApiSkill, securityCryptoSkill, securityInfraSkill, securityReviewSkill, tddEnforcerSkill, reviewWorkSkill, qualityGateSkill, softwareDevSkill, matrixxSelfConfigSkill, ulwResearchSkill, removeAiSlopsSkill];
31844
32596
  if (!disabledSkills) {
31845
32597
  return skills;
31846
32598
  }
@@ -32541,67 +33293,6 @@ function revertPinnedVersion(configPath, failedVersion, originalEntry) {
32541
33293
  // src/hooks/auto-update-checker/hook.ts
32542
33294
  init_logger();
32543
33295
 
32544
- // src/cli/config-manager/config-context.ts
32545
- var configContext = null;
32546
- function getConfigContext() {
32547
- if (!configContext) {
32548
- if (true) {
32549
- console.warn("[config-context] getConfigContext() called before initConfigContext(); defaulting to CLI paths.");
32550
- }
32551
- const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
32552
- configContext = { binary: "opencode", version: null, paths };
32553
- }
32554
- return configContext;
32555
- }
32556
- function getConfigDir() {
32557
- return getConfigContext().paths.configDir;
32558
- }
32559
- // src/cli/config-manager/bun-install.ts
32560
- var BUN_INSTALL_TIMEOUT_SECONDS = 60;
32561
- var BUN_INSTALL_TIMEOUT_MS = BUN_INSTALL_TIMEOUT_SECONDS * 1000;
32562
- async function runBunInstall() {
32563
- const result = await runBunInstallWithDetails();
32564
- return result.success;
32565
- }
32566
- async function runBunInstallWithDetails() {
32567
- try {
32568
- const proc = Bun.spawn(["bun", "install"], {
32569
- cwd: getConfigDir(),
32570
- stdout: "inherit",
32571
- stderr: "inherit"
32572
- });
32573
- let timeoutId;
32574
- const timeoutPromise = new Promise((resolve3) => {
32575
- timeoutId = setTimeout(() => resolve3("timeout"), BUN_INSTALL_TIMEOUT_MS);
32576
- });
32577
- const exitPromise = proc.exited.then(() => "completed");
32578
- const result = await Promise.race([exitPromise, timeoutPromise]);
32579
- clearTimeout(timeoutId);
32580
- if (result === "timeout") {
32581
- try {
32582
- proc.kill();
32583
- } catch {}
32584
- return {
32585
- success: false,
32586
- timedOut: true,
32587
- error: `bun install timed out after ${BUN_INSTALL_TIMEOUT_SECONDS} seconds. Try running manually: cd ${getConfigDir()} && bun i`
32588
- };
32589
- }
32590
- if (proc.exitCode !== 0) {
32591
- return {
32592
- success: false,
32593
- error: `bun install failed with exit code ${proc.exitCode}`
32594
- };
32595
- }
32596
- return { success: true };
32597
- } catch (err) {
32598
- const message = err instanceof Error ? err.message : String(err);
32599
- return {
32600
- success: false,
32601
- error: `bun install failed: ${message}. Is bun installed? Try: curl -fsSL https://bun.sh/install | bash`
32602
- };
32603
- }
32604
- }
32605
33296
  // src/hooks/auto-update-checker/hook/background-update-check.ts
32606
33297
  init_logger();
32607
33298
 
@@ -32615,7 +33306,9 @@ async function showUpdateAvailableToast(ctx, latestVersion, getToastMessage) {
32615
33306
  variant: "info",
32616
33307
  duration: 8000
32617
33308
  }
32618
- }).catch(() => {});
33309
+ }).catch((err) => {
33310
+ log("[auto-update] Update available toast failed:", err);
33311
+ });
32619
33312
  log(`[auto-update-checker] Update available toast shown: v${latestVersion}`);
32620
33313
  }
32621
33314
  async function showAutoUpdatedToast(ctx, oldVersion, newVersion) {
@@ -32627,14 +33320,36 @@ Restart OpenCode to apply.`,
32627
33320
  variant: "success",
32628
33321
  duration: 8000
32629
33322
  }
32630
- }).catch(() => {});
33323
+ }).catch((err) => {
33324
+ log("[auto-update] Auto-updated toast failed:", err);
33325
+ });
32631
33326
  log(`[auto-update-checker] Auto-updated toast shown: v${oldVersion} \u2192 v${newVersion}`);
32632
33327
  }
32633
33328
 
32634
33329
  // src/hooks/auto-update-checker/hook/background-update-check.ts
33330
+ var BUN_INSTALL_TIMEOUT_SECONDS = 60;
33331
+ var BUN_INSTALL_TIMEOUT_MS = BUN_INSTALL_TIMEOUT_SECONDS * 1000;
32635
33332
  async function runBunInstallSafe() {
32636
33333
  try {
32637
- return await runBunInstall();
33334
+ const configPaths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
33335
+ const proc = Bun.spawn(["bun", "install"], {
33336
+ cwd: configPaths.configDir,
33337
+ stdout: "inherit",
33338
+ stderr: "inherit"
33339
+ });
33340
+ let timeoutId;
33341
+ const timeoutPromise = new Promise((resolve3) => {
33342
+ timeoutId = setTimeout(() => resolve3(false), BUN_INSTALL_TIMEOUT_MS);
33343
+ });
33344
+ const exitPromise = proc.exited.then(() => true);
33345
+ const result = await Promise.race([exitPromise, timeoutPromise]);
33346
+ clearTimeout(timeoutId);
33347
+ if (!result) {
33348
+ try {
33349
+ proc.kill();
33350
+ } catch {}
33351
+ }
33352
+ return result;
32638
33353
  } catch (err) {
32639
33354
  const errorMessage = err instanceof Error ? err.message : String(err);
32640
33355
  log("[auto-update-checker] bun install error:", errorMessage);
@@ -32705,7 +33420,9 @@ ${errorMessages}`,
32705
33420
  variant: "error",
32706
33421
  duration: 1e4
32707
33422
  }
32708
- }).catch(() => {});
33423
+ }).catch((err) => {
33424
+ log("[auto-update] Config errors toast failed:", err);
33425
+ });
32709
33426
  log(`[auto-update-checker] Config load errors shown: ${errors.length} error(s)`);
32710
33427
  clearConfigLoadErrors();
32711
33428
  }
@@ -32714,7 +33431,9 @@ ${errorMessages}`,
32714
33431
  init_logger();
32715
33432
  async function updateAndShowConnectedProvidersCacheStatus(ctx) {
32716
33433
  const hadCache = hasConnectedProvidersCache();
32717
- updateConnectedProvidersCache(ctx.client).catch(() => {});
33434
+ updateConnectedProvidersCache(ctx.client).catch((err) => {
33435
+ log("[auto-update] Provider cache update failed:", err);
33436
+ });
32718
33437
  if (!hadCache) {
32719
33438
  await ctx.client.tui.showToast({
32720
33439
  body: {
@@ -32723,7 +33442,9 @@ async function updateAndShowConnectedProvidersCacheStatus(ctx) {
32723
33442
  variant: "info",
32724
33443
  duration: 8000
32725
33444
  }
32726
- }).catch(() => {});
33445
+ }).catch((err) => {
33446
+ log("[auto-update] Providers toast failed:", err);
33447
+ });
32727
33448
  log("[auto-update-checker] Connected providers cache toast shown (first run)");
32728
33449
  } else {
32729
33450
  log("[auto-update-checker] Connected providers cache exists, updating in background");
@@ -32742,7 +33463,9 @@ async function showModelCacheWarningIfNeeded(ctx) {
32742
33463
  variant: "warning",
32743
33464
  duration: 1e4
32744
33465
  }
32745
- }).catch(() => {});
33466
+ }).catch((err) => {
33467
+ log("[auto-update] Model cache warning toast failed:", err);
33468
+ });
32746
33469
  log("[auto-update-checker] Model cache warning shown");
32747
33470
  }
32748
33471
 
@@ -32750,6 +33473,7 @@ async function showModelCacheWarningIfNeeded(ctx) {
32750
33473
  init_logger();
32751
33474
 
32752
33475
  // src/hooks/auto-update-checker/hook/spinner-toast.ts
33476
+ init_logger();
32753
33477
  var SISYPHUS_SPINNER = ["\xB7", "\u2022", "\u25CF", "\u25CB", "\u25CC", "\u25E6", " "];
32754
33478
  async function showSpinnerToast(ctx, version, message) {
32755
33479
  const totalDuration = 5000;
@@ -32764,7 +33488,9 @@ async function showSpinnerToast(ctx, version, message) {
32764
33488
  variant: "info",
32765
33489
  duration: frameInterval + 50
32766
33490
  }
32767
- }).catch(() => {});
33491
+ }).catch((err) => {
33492
+ log("[auto-update] Spinner toast failed:", err);
33493
+ });
32768
33494
  await new Promise((resolve3) => setTimeout(resolve3, frameInterval));
32769
33495
  }
32770
33496
  }
@@ -32816,13 +33542,17 @@ v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on S
32816
33542
  await updateAndShowConnectedProvidersCacheStatus(ctx);
32817
33543
  if (localDevVersion) {
32818
33544
  if (showStartupToast) {
32819
- showLocalDevToast(ctx, displayVersion, isMorpheusEnabled).catch(() => {});
33545
+ showLocalDevToast(ctx, displayVersion, isMorpheusEnabled).catch((err) => {
33546
+ log("[auto-update] Startup toast failed:", err);
33547
+ });
32820
33548
  }
32821
33549
  log("[auto-update-checker] Local development mode");
32822
33550
  return;
32823
33551
  }
32824
33552
  if (showStartupToast) {
32825
- showVersionToast(ctx, displayVersion, getToastMessage(false)).catch(() => {});
33553
+ showVersionToast(ctx, displayVersion, getToastMessage(false)).catch((err) => {
33554
+ log("[auto-update] Version toast failed:", err);
33555
+ });
32826
33556
  }
32827
33557
  runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage).catch((err) => {
32828
33558
  log("[auto-update-checker] Background update check failed:", err);
@@ -48727,9 +49457,6 @@ function cleanupStaleEntries() {
48727
49457
  }
48728
49458
  }
48729
49459
  }
48730
- function isWriteTool(toolName) {
48731
- return toolName.toLowerCase() === "write";
48732
- }
48733
49460
  function extractFilePath(args) {
48734
49461
  const path10 = args.path ?? args.filePath ?? args.file_path;
48735
49462
  return typeof path10 === "string" ? path10 : undefined;
@@ -48801,12 +49528,6 @@ var CONTENT_CLOSE_TAG = "</content>";
48801
49528
  var FILE_OPEN_TAG = "<file>";
48802
49529
  var FILE_CLOSE_TAG = "</file>";
48803
49530
  var OPENCODE_LINE_TRUNCATION_SUFFIX = "... (line truncated to 2000 chars)";
48804
- function isReadTool(toolName) {
48805
- return toolName.toLowerCase() === "read";
48806
- }
48807
- function isWriteTool2(toolName) {
48808
- return toolName.toLowerCase() === "write";
48809
- }
48810
49531
  function shouldProcess(config2) {
48811
49532
  return config2.hashline_edit?.enabled ?? false;
48812
49533
  }
@@ -48927,7 +49648,7 @@ function createHashlineReadEnhancerHook(_ctx, config2) {
48927
49648
  return {
48928
49649
  "tool.execute.after": async (input, output) => {
48929
49650
  if (!isReadTool(input.tool)) {
48930
- if (isWriteTool2(input.tool) && typeof output.output === "string" && shouldProcess(config2)) {
49651
+ if (isWriteTool(input.tool) && typeof output.output === "string" && shouldProcess(config2)) {
48931
49652
  await appendWriteHashlineOutput(output);
48932
49653
  }
48933
49654
  return;
@@ -48942,6 +49663,9 @@ function createHashlineReadEnhancerHook(_ctx, config2) {
48942
49663
  }
48943
49664
  };
48944
49665
  }
49666
+ // src/hooks/interactive-bash-session/hook.ts
49667
+ init_logger();
49668
+
48945
49669
  // src/hooks/interactive-bash-session/constants.ts
48946
49670
  import { join as join46 } from "path";
48947
49671
  var INTERACTIVE_BASH_SESSION_STORAGE = join46(OPENCODE_STORAGE, "interactive-bash-session");
@@ -49121,7 +49845,9 @@ function createInteractiveBashSessionHook(ctx) {
49121
49845
  async function killAllTrackedSessionsLocal(state3) {
49122
49846
  await killAllTrackedSessions(state3);
49123
49847
  for (const sessionId of subagentSessions) {
49124
- ctx.client.session.abort({ path: { id: sessionId } }).catch(() => {});
49848
+ ctx.client.session.abort({ path: { id: sessionId } }).catch((err) => {
49849
+ log("[interactive-bash] Session abort failed:", err);
49850
+ });
49125
49851
  }
49126
49852
  }
49127
49853
  const toolExecuteAfter = async (input, output) => {
@@ -49950,6 +50676,21 @@ function detectKeywordsWithType(text, agentName, modelID) {
49950
50676
  function extractPromptText3(parts) {
49951
50677
  return parts.filter((p) => p.type === "text").map((p) => p.text || "").join(" ");
49952
50678
  }
50679
+ // src/features/ultrawork-state/manager.ts
50680
+ init_logger();
50681
+ var HOOK_NAME4 = "ultrawork-state";
50682
+ var sessionStates = new Map;
50683
+ function getUltraworkState(sessionID) {
50684
+ return sessionStates.get(sessionID);
50685
+ }
50686
+ function enableUltrawork(sessionID) {
50687
+ sessionStates.set(sessionID, "enabled");
50688
+ log(`[${HOOK_NAME4}] Ultrawork enabled for session`, { sessionID });
50689
+ }
50690
+ function disableUltrawork(sessionID) {
50691
+ sessionStates.set(sessionID, "disabled");
50692
+ log(`[${HOOK_NAME4}] Ultrawork disabled for session`, { sessionID });
50693
+ }
49953
50694
  // src/hooks/keyword-detector/hook.ts
49954
50695
  function createKeywordDetectorHook(ctx, _collector) {
49955
50696
  return {
@@ -49985,8 +50726,15 @@ function createKeywordDetectorHook(ctx, _collector) {
49985
50726
  return;
49986
50727
  }
49987
50728
  }
50729
+ const ultraworkState = getUltraworkState(input.sessionID);
49988
50730
  const hasUltrawork = detectedKeywords.some((k) => k.type === "ultrawork");
49989
- if (hasUltrawork) {
50731
+ const isUltraworkBlocked = ultraworkState === "disabled";
50732
+ const isUltraworkForced = ultraworkState === "enabled";
50733
+ if (isUltraworkBlocked) {
50734
+ log(`[keyword-detector] Ultrawork blocked by runtime state`, { sessionID: input.sessionID });
50735
+ return;
50736
+ }
50737
+ if (hasUltrawork || isUltraworkForced) {
49990
50738
  log(`[keyword-detector] Ultrawork mode activated`, { sessionID: input.sessionID });
49991
50739
  if (output.message.variant === undefined) {
49992
50740
  output.message.variant = "max";
@@ -50074,7 +50822,7 @@ function createLoopStateController(options) {
50074
50822
  };
50075
50823
  const success2 = writeState(directory, state3, stateDir);
50076
50824
  if (success2) {
50077
- log(`[${HOOK_NAME4}] Loop started`, {
50825
+ log(`[${HOOK_NAME5}] Loop started`, {
50078
50826
  sessionID,
50079
50827
  maxIterations: state3.max_iterations,
50080
50828
  completionPromise: state3.completion_promise
@@ -50089,7 +50837,7 @@ function createLoopStateController(options) {
50089
50837
  }
50090
50838
  const success2 = clearState(directory, stateDir);
50091
50839
  if (success2) {
50092
- log(`[${HOOK_NAME4}] Loop cancelled`, { sessionID, iteration: state3.iteration });
50840
+ log(`[${HOOK_NAME5}] Loop cancelled`, { sessionID, iteration: state3.iteration });
50093
50841
  }
50094
50842
  return success2;
50095
50843
  },
@@ -50185,7 +50933,7 @@ async function detectCompletionInSessionMessages(ctx, options) {
50185
50933
  return false;
50186
50934
  } catch (err) {
50187
50935
  setTimeout(() => {
50188
- log(`[${HOOK_NAME4}] Session messages check failed`, {
50936
+ log(`[${HOOK_NAME5}] Session messages check failed`, {
50189
50937
  sessionID: options.sessionID,
50190
50938
  error: String(err)
50191
50939
  });
@@ -50266,7 +51014,7 @@ async function verifyCompletion(ctx, options) {
50266
51014
  query: { directory: options.directory }
50267
51015
  });
50268
51016
  if (createResult.error || !createResult.data?.id) {
50269
- log(`[${HOOK_NAME4}] Verification session creation failed`);
51017
+ log(`[${HOOK_NAME5}] Verification session creation failed`);
50270
51018
  return { verified: true };
50271
51019
  }
50272
51020
  verifySessionID = createResult.data.id;
@@ -50296,20 +51044,22 @@ async function verifyCompletion(ctx, options) {
50296
51044
  return parseVerificationResponse(assistantText);
50297
51045
  }
50298
51046
  } catch {
50299
- log(`[${HOOK_NAME4}] Verification poll error`);
51047
+ log(`[${HOOK_NAME5}] Verification poll error`);
50300
51048
  }
50301
51049
  await new Promise((resolve5) => {
50302
51050
  setTimeout(resolve5, pollIntervalMs);
50303
51051
  });
50304
51052
  }
50305
- log(`[${HOOK_NAME4}] Verification timed out, assuming pass`);
51053
+ log(`[${HOOK_NAME5}] Verification timed out, assuming pass`);
50306
51054
  return { verified: true };
50307
51055
  } catch (err) {
50308
- log(`[${HOOK_NAME4}] Verification error: ${String(err)}`);
51056
+ log(`[${HOOK_NAME5}] Verification error: ${String(err)}`);
50309
51057
  return { verified: true };
50310
51058
  } finally {
50311
51059
  if (verifySessionID) {
50312
- ctx.client.session.delete({ path: { id: verifySessionID } }).catch(() => {});
51060
+ ctx.client.session.delete({ path: { id: verifySessionID } }).catch((err) => {
51061
+ log("[matrix-loop] Verification session cleanup failed:", err);
51062
+ });
50313
51063
  }
50314
51064
  }
50315
51065
  }
@@ -50379,7 +51129,7 @@ async function injectContinuationPrompt(ctx, options) {
50379
51129
 
50380
51130
  // src/hooks/matrix-loop/matrix-loop-event-handler.ts
50381
51131
  async function handleVerificationFailure(ctx, options, state3, sessionID, reason, failedCount) {
50382
- log(`[${HOOK_NAME4}] Verification failed`, { sessionID, reason });
51132
+ log(`[${HOOK_NAME5}] Verification failed`, { sessionID, reason });
50383
51133
  const newState = options.loopState.incrementIteration();
50384
51134
  if (newState) {
50385
51135
  newState.verification_failed_count = failedCount + 1;
@@ -50397,7 +51147,7 @@ ${buildContinuationPrompt(newState ?? state3)}`,
50397
51147
  apiTimeoutMs: options.apiTimeoutMs
50398
51148
  });
50399
51149
  } catch (err) {
50400
- log(`[${HOOK_NAME4}] Failed to inject verification feedback`, { sessionID, error: String(err) });
51150
+ log(`[${HOOK_NAME5}] Failed to inject verification feedback`, { sessionID, error: String(err) });
50401
51151
  }
50402
51152
  }
50403
51153
  function createMatrixLoopEventHandler(ctx, options) {
@@ -50409,13 +51159,13 @@ function createMatrixLoopEventHandler(ctx, options) {
50409
51159
  if (!sessionID)
50410
51160
  return;
50411
51161
  if (inFlightSessions.has(sessionID)) {
50412
- log(`[${HOOK_NAME4}] Skipped: handler in flight`, { sessionID });
51162
+ log(`[${HOOK_NAME5}] Skipped: handler in flight`, { sessionID });
50413
51163
  return;
50414
51164
  }
50415
51165
  inFlightSessions.add(sessionID);
50416
51166
  try {
50417
51167
  if (options.sessionRecovery.isRecovering(sessionID)) {
50418
- log(`[${HOOK_NAME4}] Skipped: in recovery`, { sessionID });
51168
+ log(`[${HOOK_NAME5}] Skipped: in recovery`, { sessionID });
50419
51169
  return;
50420
51170
  }
50421
51171
  const state3 = options.loopState.getState();
@@ -50427,11 +51177,11 @@ function createMatrixLoopEventHandler(ctx, options) {
50427
51177
  const exists = await options.checkSessionExists(state3.session_id);
50428
51178
  if (!exists) {
50429
51179
  options.loopState.clear();
50430
- log(`[${HOOK_NAME4}] Cleared orphaned state from deleted session`, { orphanedSessionId: state3.session_id, currentSessionId: sessionID });
51180
+ log(`[${HOOK_NAME5}] Cleared orphaned state from deleted session`, { orphanedSessionId: state3.session_id, currentSessionId: sessionID });
50431
51181
  return;
50432
51182
  }
50433
51183
  } catch (err) {
50434
- log(`[${HOOK_NAME4}] Failed to check session existence`, { sessionId: state3.session_id, error: String(err) });
51184
+ log(`[${HOOK_NAME5}] Failed to check session existence`, { sessionId: state3.session_id, error: String(err) });
50435
51185
  }
50436
51186
  }
50437
51187
  return;
@@ -50450,7 +51200,7 @@ function createMatrixLoopEventHandler(ctx, options) {
50450
51200
  messages = Array.isArray(messagesResponse) ? messagesResponse : Array.isArray(responseData) ? responseData : [];
50451
51201
  } catch (err) {
50452
51202
  setTimeout(() => {
50453
- log(`[${HOOK_NAME4}] Session messages fetch failed`, { sessionID, error: String(err) });
51203
+ log(`[${HOOK_NAME5}] Session messages fetch failed`, { sessionID, error: String(err) });
50454
51204
  }, 0);
50455
51205
  messages = [];
50456
51206
  }
@@ -50463,13 +51213,15 @@ function createMatrixLoopEventHandler(ctx, options) {
50463
51213
  preFetchedMessages: messages
50464
51214
  });
50465
51215
  if (completionViaTranscript || completionViaApi) {
50466
- log(`[${HOOK_NAME4}] Completion detected!`, { sessionID, iteration: state3.iteration, promise: state3.completion_promise, detectedVia: completionViaTranscript ? "transcript_file" : "session_messages_api" });
51216
+ log(`[${HOOK_NAME5}] Completion detected!`, { sessionID, iteration: state3.iteration, promise: state3.completion_promise, detectedVia: completionViaTranscript ? "transcript_file" : "session_messages_api" });
50467
51217
  if (options.verification?.enabled === true) {
50468
51218
  const maxRetries = options.verification?.maxRetries ?? DEFAULT_VERIFICATION_MAX_RETRIES;
50469
51219
  const failedCount = state3.verification_failed_count ?? 0;
50470
51220
  if (failedCount >= maxRetries) {
50471
51221
  options.loopState.clear();
50472
- await ctx.client.tui.showToast({ body: { title: "Matrix Loop Complete", message: `Force-completed after ${failedCount} failed verification(s)`, variant: "warning", duration: 5000 } }).catch(() => {});
51222
+ await ctx.client.tui.showToast({ body: { title: "Matrix Loop Complete", message: `Force-completed after ${failedCount} failed verification(s)`, variant: "warning", duration: 5000 } }).catch((err) => {
51223
+ log("[matrix-loop] Force complete toast failed:", err);
51224
+ });
50473
51225
  return;
50474
51226
  }
50475
51227
  const result = await verifyCompletion(ctx, {
@@ -50490,26 +51242,32 @@ function createMatrixLoopEventHandler(ctx, options) {
50490
51242
  options.loopState.clear();
50491
51243
  const title = state3.ultrawork ? "ULTRAWORK LOOP COMPLETE!" : "Matrix Loop Complete!";
50492
51244
  const message = state3.ultrawork ? `JUST ULW ULW! Task completed after ${state3.iteration} iteration(s)` : `Task completed after ${state3.iteration} iteration(s)`;
50493
- await ctx.client.tui.showToast({ body: { title, message, variant: "success", duration: 5000 } }).catch(() => {});
51245
+ await ctx.client.tui.showToast({ body: { title, message, variant: "success", duration: 5000 } }).catch((err) => {
51246
+ log("[matrix-loop] Loop complete toast failed:", err);
51247
+ });
50494
51248
  return;
50495
51249
  }
50496
51250
  if (state3.iteration >= state3.max_iterations) {
50497
- log(`[${HOOK_NAME4}] Max iterations reached`, { sessionID, iteration: state3.iteration, max: state3.max_iterations });
51251
+ log(`[${HOOK_NAME5}] Max iterations reached`, { sessionID, iteration: state3.iteration, max: state3.max_iterations });
50498
51252
  options.loopState.clear();
50499
- await ctx.client.tui.showToast({ body: { title: "Matrix Loop Stopped", message: `Max iterations (${state3.max_iterations}) reached without completion`, variant: "warning", duration: 5000 } }).catch(() => {});
51253
+ await ctx.client.tui.showToast({ body: { title: "Matrix Loop Stopped", message: `Max iterations (${state3.max_iterations}) reached without completion`, variant: "warning", duration: 5000 } }).catch((err) => {
51254
+ log("[matrix-loop] Max iterations toast failed:", err);
51255
+ });
50500
51256
  return;
50501
51257
  }
50502
51258
  const newState = options.loopState.incrementIteration();
50503
51259
  if (!newState) {
50504
- log(`[${HOOK_NAME4}] Failed to increment iteration`, { sessionID });
51260
+ log(`[${HOOK_NAME5}] Failed to increment iteration`, { sessionID });
50505
51261
  return;
50506
51262
  }
50507
- log(`[${HOOK_NAME4}] Continuing loop`, { sessionID, iteration: newState.iteration, max: newState.max_iterations });
50508
- await ctx.client.tui.showToast({ body: { title: "Matrix Loop", message: `Iteration ${newState.iteration}/${newState.max_iterations}`, variant: "info", duration: 2000 } }).catch(() => {});
51263
+ log(`[${HOOK_NAME5}] Continuing loop`, { sessionID, iteration: newState.iteration, max: newState.max_iterations });
51264
+ await ctx.client.tui.showToast({ body: { title: "Matrix Loop", message: `Iteration ${newState.iteration}/${newState.max_iterations}`, variant: "info", duration: 2000 } }).catch((err) => {
51265
+ log("[matrix-loop] Iteration toast failed:", err);
51266
+ });
50509
51267
  try {
50510
51268
  await injectContinuationPrompt(ctx, { sessionID, prompt: buildContinuationPrompt(newState), directory: options.directory, apiTimeoutMs: options.apiTimeoutMs });
50511
51269
  } catch (err) {
50512
- log(`[${HOOK_NAME4}] Failed to inject continuation`, { sessionID, error: String(err) });
51270
+ log(`[${HOOK_NAME5}] Failed to inject continuation`, { sessionID, error: String(err) });
50513
51271
  }
50514
51272
  return;
50515
51273
  } finally {
@@ -50523,7 +51281,7 @@ function createMatrixLoopEventHandler(ctx, options) {
50523
51281
  const state3 = options.loopState.getState();
50524
51282
  if (state3?.session_id === sessionInfo.id) {
50525
51283
  options.loopState.clear();
50526
- log(`[${HOOK_NAME4}] Session deleted, loop cleared`, { sessionID: sessionInfo.id });
51284
+ log(`[${HOOK_NAME5}] Session deleted, loop cleared`, { sessionID: sessionInfo.id });
50527
51285
  }
50528
51286
  options.sessionRecovery.clear(sessionInfo.id);
50529
51287
  return;
@@ -50536,7 +51294,7 @@ function createMatrixLoopEventHandler(ctx, options) {
50536
51294
  const state3 = options.loopState.getState();
50537
51295
  if (state3?.session_id === sessionID) {
50538
51296
  options.loopState.clear();
50539
- log(`[${HOOK_NAME4}] User aborted, loop cleared`, { sessionID });
51297
+ log(`[${HOOK_NAME5}] User aborted, loop cleared`, { sessionID });
50540
51298
  }
50541
51299
  options.sessionRecovery.clear(sessionID);
50542
51300
  }
@@ -50583,7 +51341,7 @@ function createMatrixLoopHook(ctx, options) {
50583
51341
  // src/hooks/matrix-loop/index.ts
50584
51342
  init_storage();
50585
51343
  // src/hooks/mouse-notepad/constants.ts
50586
- var HOOK_NAME5 = "sisyphus-junior-notepad";
51344
+ var HOOK_NAME6 = "mouse-notepad";
50587
51345
  var NOTEPAD_DIRECTIVE = `
50588
51346
  <Work_Context>
50589
51347
  ## Notepad Location (for recording learnings)
@@ -50630,14 +51388,14 @@ function createMouseNotepadHook(ctx) {
50630
51388
  return;
50631
51389
  }
50632
51390
  output.args.prompt = NOTEPAD_DIRECTIVE + prompt;
50633
- log(`[${HOOK_NAME5}] Injected notepad directive to task`, {
51391
+ log(`[${HOOK_NAME6}] Injected notepad directive to task`, {
50634
51392
  sessionID: input.sessionID
50635
51393
  });
50636
51394
  }
50637
51395
  };
50638
51396
  }
50639
51397
  // src/hooks/non-interactive-env/constants.ts
50640
- var HOOK_NAME6 = "non-interactive-env";
51398
+ var HOOK_NAME7 = "non-interactive-env";
50641
51399
  var NON_INTERACTIVE_ENV = {
50642
51400
  CI: "true",
50643
51401
  DEBIAN_FRONTEND: "noninteractive",
@@ -50728,7 +51486,7 @@ function createNonInteractiveEnvHook(_ctx) {
50728
51486
  }
50729
51487
  const envPrefix = buildEnvPrefix(NON_INTERACTIVE_ENV, "unix");
50730
51488
  output.args.command = `${envPrefix} ${command}`;
50731
- log(`[${HOOK_NAME6}] Prepended non-interactive env vars to git command`, {
51489
+ log(`[${HOOK_NAME7}] Prepended non-interactive env vars to git command`, {
50732
51490
  sessionID: input.sessionID,
50733
51491
  envPrefix
50734
51492
  });
@@ -50877,7 +51635,9 @@ function createPostCompactionDegradationMonitor(args) {
50877
51635
  variant: "warning",
50878
51636
  duration: 5000
50879
51637
  }
50880
- }).catch(() => {});
51638
+ }).catch((err) => {
51639
+ log("[preemptive-compaction] Degradation toast failed:", err);
51640
+ });
50881
51641
  await withTimeout2(client.session.summarize({
50882
51642
  path: { id: sessionID },
50883
51643
  body: { providerID: targetProviderID, modelID: targetModelID },
@@ -50935,6 +51695,7 @@ function createPostCompactionDegradationMonitor(args) {
50935
51695
 
50936
51696
  // src/shared/context-limit-resolver.ts
50937
51697
  var DEFAULT_ANTHROPIC_ACTUAL_LIMIT = 200000;
51698
+ var DEFAULT_NON_ANTHROPIC_FALLBACK_LIMIT = 128000;
50938
51699
  function isAnthropicProvider2(providerID) {
50939
51700
  const normalized = providerID.toLowerCase();
50940
51701
  return normalized === "anthropic" || normalized === "google-vertex-anthropic" || normalized === "aws-bedrock-anthropic";
@@ -50955,7 +51716,7 @@ function resolveActualContextLimit(providerID, modelID, modelCacheState) {
50955
51716
  return cachedLimit;
50956
51717
  return DEFAULT_ANTHROPIC_ACTUAL_LIMIT;
50957
51718
  }
50958
- return modelCacheState?.modelContextLimitsCache?.get(`${providerID}/${modelID}`) ?? null;
51719
+ return modelCacheState?.modelContextLimitsCache?.get(`${providerID}/${modelID}`) ?? DEFAULT_NON_ANTHROPIC_FALLBACK_LIMIT;
50959
51720
  }
50960
51721
 
50961
51722
  // src/hooks/preemptive-compaction-trigger.ts
@@ -51114,7 +51875,7 @@ function createPreemptiveCompactionHook(ctx, pluginConfig = {}, modelCacheState)
51114
51875
  };
51115
51876
  }
51116
51877
  // src/hooks/prometheus-md-only/constants.ts
51117
- var HOOK_NAME7 = "prometheus-md-only";
51878
+ var HOOK_NAME8 = "prometheus-md-only";
51118
51879
  var ORACLE_AGENT = "oracle";
51119
51880
  var ALLOWED_EXTENSIONS = [".md"];
51120
51881
  var BLOCKED_TOOLS = ["Write", "Edit", "write", "edit"];
@@ -51247,7 +52008,7 @@ function createOracleMdOnlyHook(ctx) {
51247
52008
  const prompt = output.args.prompt;
51248
52009
  if (prompt && !prompt.includes(SYSTEM_DIRECTIVE_PREFIX)) {
51249
52010
  output.args.prompt = PLANNING_CONSULT_WARNING + prompt;
51250
- log(`[${HOOK_NAME7}] Injected read-only planning warning to ${toolName}`, {
52011
+ log(`[${HOOK_NAME8}] Injected read-only planning warning to ${toolName}`, {
51251
52012
  sessionID: input.sessionID,
51252
52013
  tool: toolName,
51253
52014
  agent: agentName
@@ -51263,17 +52024,17 @@ function createOracleMdOnlyHook(ctx) {
51263
52024
  return;
51264
52025
  }
51265
52026
  if (!isAllowedFile(filePath, ctx.directory)) {
51266
- log(`[${HOOK_NAME7}] Blocked: Oracle can only write to .matrixx/*.md`, {
52027
+ log(`[${HOOK_NAME8}] Blocked: Oracle can only write to .matrixx/*.md`, {
51267
52028
  sessionID: input.sessionID,
51268
52029
  tool: toolName,
51269
52030
  filePath,
51270
52031
  agent: agentName
51271
52032
  });
51272
- throw new Error(`[${HOOK_NAME7}] ${getAgentDisplayName("oracle")} can only write/edit .md files inside .matrixx/ directory. ` + `Attempted to modify: ${filePath}. ` + `${getAgentDisplayName("oracle")} is a READ-ONLY planner. Use /start-work to execute the plan. ` + `APOLOGIZE TO THE USER, REMIND OF YOUR PLAN WRITING PROCESSES, TELL USER WHAT YOU WILL GOING TO DO AS THE PROCESS, WRITE THE PLAN`);
52033
+ throw new Error(`[${HOOK_NAME8}] ${getAgentDisplayName("oracle")} can only write/edit .md files inside .matrixx/ directory. ` + `Attempted to modify: ${filePath}. ` + `${getAgentDisplayName("oracle")} is a READ-ONLY planner. Use /start-work to execute the plan. ` + `APOLOGIZE TO THE USER, REMIND OF YOUR PLAN WRITING PROCESSES, TELL USER WHAT YOU WILL GOING TO DO AS THE PROCESS, WRITE THE PLAN`);
51273
52034
  }
51274
52035
  const normalizedPath = filePath.toLowerCase().replace(/\\/g, "/");
51275
52036
  if (normalizedPath.includes(".matrixx/plans/") || normalizedPath.includes(".matrixx\\plans\\")) {
51276
- log(`[${HOOK_NAME7}] Injecting workflow reminder for plan write`, {
52037
+ log(`[${HOOK_NAME8}] Injecting workflow reminder for plan write`, {
51277
52038
  sessionID: input.sessionID,
51278
52039
  tool: toolName,
51279
52040
  filePath,
@@ -51281,7 +52042,7 @@ function createOracleMdOnlyHook(ctx) {
51281
52042
  });
51282
52043
  output.message = (output.message || "") + PROMETHEUS_WORKFLOW_REMINDER;
51283
52044
  }
51284
- log(`[${HOOK_NAME7}] Allowed: .matrixx/*.md write permitted`, {
52045
+ log(`[${HOOK_NAME8}] Allowed: .matrixx/*.md write permitted`, {
51285
52046
  sessionID: input.sessionID,
51286
52047
  tool: toolName,
51287
52048
  filePath,
@@ -52014,9 +52775,6 @@ async function resizeImage(base64DataUrl, mimeType, target, deps = {}) {
52014
52775
  // src/hooks/read-image-resizer/hook.ts
52015
52776
  var SUPPORTED_IMAGE_MIMES = new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
52016
52777
  var TOKEN_DIVISOR = 750;
52017
- function isReadTool2(toolName) {
52018
- return toolName.toLowerCase() === "read";
52019
- }
52020
52778
  function asRecord(value) {
52021
52779
  if (!value || typeof value !== "object" || Array.isArray(value)) {
52022
52780
  return null;
@@ -52100,7 +52858,7 @@ function resolveFilename(attachment, index) {
52100
52858
  function createReadImageResizerHook(_ctx) {
52101
52859
  return {
52102
52860
  "tool.execute.after": async (input, output) => {
52103
- if (!isReadTool2(input.tool)) {
52861
+ if (!isReadTool(input.tool)) {
52104
52862
  return;
52105
52863
  }
52106
52864
  const sessionModel = getSessionModel(input.sessionID);
@@ -52837,7 +53595,7 @@ var RETRYABLE_ERROR_PATTERNS = [
52837
53595
  /(?:^|\s)503(?:\s|$)/,
52838
53596
  /(?:^|\s)529(?:\s|$)/
52839
53597
  ];
52840
- var HOOK_NAME8 = "runtime-fallback";
53598
+ var HOOK_NAME9 = "runtime-fallback";
52841
53599
 
52842
53600
  // src/hooks/runtime-fallback/fallback-models.ts
52843
53601
  init_logger();
@@ -52928,7 +53686,7 @@ function getRawFallbackModelsForSession(sessionID, agent, pluginConfig) {
52928
53686
  if (result)
52929
53687
  return result;
52930
53688
  }
52931
- log(`[${HOOK_NAME8}] No category/agent fallback models resolved for session`, { sessionID, agent });
53689
+ log(`[${HOOK_NAME9}] No category/agent fallback models resolved for session`, { sessionID, agent });
52932
53690
  return;
52933
53691
  }
52934
53692
 
@@ -52957,21 +53715,21 @@ function findNextAvailableFallback(state3, fallbackModels, cooldownSeconds) {
52957
53715
  if (!isModelInCooldown(candidate, state3, cooldownSeconds)) {
52958
53716
  return candidate;
52959
53717
  }
52960
- log(`[${HOOK_NAME8}] Skipping fallback model in cooldown`, { model: candidate, index: i });
53718
+ log(`[${HOOK_NAME9}] Skipping fallback model in cooldown`, { model: candidate, index: i });
52961
53719
  }
52962
53720
  return;
52963
53721
  }
52964
53722
  function prepareFallback(sessionID, state3, fallbackModels, config2) {
52965
53723
  if (state3.attemptCount >= config2.max_fallback_attempts) {
52966
- log(`[${HOOK_NAME8}] Max fallback attempts reached`, { sessionID, attempts: state3.attemptCount });
53724
+ log(`[${HOOK_NAME9}] Max fallback attempts reached`, { sessionID, attempts: state3.attemptCount });
52967
53725
  return { success: false, error: "Max fallback attempts reached", maxAttemptsReached: true };
52968
53726
  }
52969
53727
  const nextModel = findNextAvailableFallback(state3, fallbackModels, config2.cooldown_seconds);
52970
53728
  if (!nextModel) {
52971
- log(`[${HOOK_NAME8}] No available fallback models`, { sessionID });
53729
+ log(`[${HOOK_NAME9}] No available fallback models`, { sessionID });
52972
53730
  return { success: false, error: "No available fallback models (all in cooldown or exhausted)" };
52973
53731
  }
52974
- log(`[${HOOK_NAME8}] Preparing fallback`, {
53732
+ log(`[${HOOK_NAME9}] Preparing fallback`, {
52975
53733
  sessionID,
52976
53734
  from: state3.currentModel,
52977
53735
  to: nextModel,
@@ -53049,7 +53807,7 @@ function createAutoRetryHelpers(deps) {
53049
53807
  ctx,
53050
53808
  config: config2,
53051
53809
  options,
53052
- sessionStates,
53810
+ sessionStates: sessionStates2,
53053
53811
  sessionLastAccess,
53054
53812
  sessionRetryInFlight,
53055
53813
  sessionAwaitingFallbackResult,
@@ -53060,9 +53818,9 @@ function createAutoRetryHelpers(deps) {
53060
53818
  const abortSessionRequest = async (sessionID, source) => {
53061
53819
  try {
53062
53820
  await ctx.client.session.abort({ path: { id: sessionID } });
53063
- log(`[${HOOK_NAME8}] Aborted in-flight session request (${source})`, { sessionID });
53821
+ log(`[${HOOK_NAME9}] Aborted in-flight session request (${source})`, { sessionID });
53064
53822
  } catch (error51) {
53065
- log(`[${HOOK_NAME8}] Failed to abort in-flight session request (${source})`, {
53823
+ log(`[${HOOK_NAME9}] Failed to abort in-flight session request (${source})`, {
53066
53824
  sessionID,
53067
53825
  error: String(error51)
53068
53826
  });
@@ -53082,11 +53840,11 @@ function createAutoRetryHelpers(deps) {
53082
53840
  return;
53083
53841
  const timer = setTimeout(async () => {
53084
53842
  sessionFallbackTimeouts.delete(sessionID);
53085
- const state3 = sessionStates.get(sessionID);
53843
+ const state3 = sessionStates2.get(sessionID);
53086
53844
  if (!state3)
53087
53845
  return;
53088
53846
  if (sessionRetryInFlight.has(sessionID)) {
53089
- log(`[${HOOK_NAME8}] Overriding in-flight retry due to session timeout`, { sessionID });
53847
+ log(`[${HOOK_NAME9}] Overriding in-flight retry due to session timeout`, { sessionID });
53090
53848
  }
53091
53849
  await abortSessionRequest(sessionID, "session.timeout");
53092
53850
  sessionRetryInFlight.delete(sessionID);
@@ -53096,7 +53854,7 @@ function createAutoRetryHelpers(deps) {
53096
53854
  const fallbackModels = getFallbackModelsForSession(sessionID, resolvedAgent, pluginConfig);
53097
53855
  if (fallbackModels.length === 0)
53098
53856
  return;
53099
- log(`[${HOOK_NAME8}] Session fallback timeout reached`, {
53857
+ log(`[${HOOK_NAME9}] Session fallback timeout reached`, {
53100
53858
  sessionID,
53101
53859
  timeoutSeconds: config2.timeout_seconds,
53102
53860
  currentModel: state3.currentModel
@@ -53110,7 +53868,7 @@ function createAutoRetryHelpers(deps) {
53110
53868
  };
53111
53869
  const autoRetryWithFallback = async (sessionID, newModel, resolvedAgent, source) => {
53112
53870
  if (sessionRetryInFlight.has(sessionID)) {
53113
- log(`[${HOOK_NAME8}] Retry already in flight, skipping (${source})`, { sessionID });
53871
+ log(`[${HOOK_NAME9}] Retry already in flight, skipping (${source})`, { sessionID });
53114
53872
  return;
53115
53873
  }
53116
53874
  const agentSettings = resolvedAgent ? pluginConfig?.agents?.[resolvedAgent] : undefined;
@@ -53119,8 +53877,8 @@ function createAutoRetryHelpers(deps) {
53119
53877
  reasoningEffort: agentSettings.reasoningEffort
53120
53878
  } : undefined);
53121
53879
  if (!retryModelPayload) {
53122
- log(`[${HOOK_NAME8}] Invalid model format (missing provider prefix): ${newModel}`);
53123
- const state3 = sessionStates.get(sessionID);
53880
+ log(`[${HOOK_NAME9}] Invalid model format (missing provider prefix): ${newModel}`);
53881
+ const state3 = sessionStates2.get(sessionID);
53124
53882
  if (state3?.pendingFallbackModel) {
53125
53883
  state3.pendingFallbackModel = undefined;
53126
53884
  }
@@ -53135,7 +53893,7 @@ function createAutoRetryHelpers(deps) {
53135
53893
  });
53136
53894
  const retryParts = getLastUserRetryParts(messagesResp);
53137
53895
  if (retryParts.length > 0) {
53138
- log(`[${HOOK_NAME8}] Auto-retrying with fallback model (${source})`, {
53896
+ log(`[${HOOK_NAME9}] Auto-retrying with fallback model (${source})`, {
53139
53897
  sessionID,
53140
53898
  model: newModel
53141
53899
  });
@@ -53154,16 +53912,16 @@ function createAutoRetryHelpers(deps) {
53154
53912
  });
53155
53913
  retryDispatched = true;
53156
53914
  } else {
53157
- log(`[${HOOK_NAME8}] No user message found for auto-retry (${source})`, { sessionID });
53915
+ log(`[${HOOK_NAME9}] No user message found for auto-retry (${source})`, { sessionID });
53158
53916
  }
53159
53917
  } catch (retryError) {
53160
- log(`[${HOOK_NAME8}] Auto-retry failed (${source})`, { sessionID, error: String(retryError) });
53918
+ log(`[${HOOK_NAME9}] Auto-retry failed (${source})`, { sessionID, error: String(retryError) });
53161
53919
  } finally {
53162
53920
  sessionRetryInFlight.delete(sessionID);
53163
53921
  if (!retryDispatched) {
53164
53922
  sessionAwaitingFallbackResult.delete(sessionID);
53165
53923
  clearSessionFallbackTimeout(sessionID);
53166
- const state3 = sessionStates.get(sessionID);
53924
+ const state3 = sessionStates2.get(sessionID);
53167
53925
  if (state3?.pendingFallbackModel) {
53168
53926
  state3.pendingFallbackModel = undefined;
53169
53927
  }
@@ -53200,7 +53958,7 @@ function createAutoRetryHelpers(deps) {
53200
53958
  let cleanedCount = 0;
53201
53959
  for (const [sessionID, lastAccess] of sessionLastAccess.entries()) {
53202
53960
  if (now - lastAccess > SESSION_TTL_MS) {
53203
- sessionStates.delete(sessionID);
53961
+ sessionStates2.delete(sessionID);
53204
53962
  sessionLastAccess.delete(sessionID);
53205
53963
  sessionRetryInFlight.delete(sessionID);
53206
53964
  sessionAwaitingFallbackResult.delete(sessionID);
@@ -53211,7 +53969,7 @@ function createAutoRetryHelpers(deps) {
53211
53969
  }
53212
53970
  }
53213
53971
  if (cleanedCount > 0) {
53214
- log(`[${HOOK_NAME8}] Cleaned up ${cleanedCount} stale session states`);
53972
+ log(`[${HOOK_NAME9}] Cleaned up ${cleanedCount} stale session states`);
53215
53973
  }
53216
53974
  };
53217
53975
  return {
@@ -53227,12 +53985,12 @@ function createAutoRetryHelpers(deps) {
53227
53985
  // src/hooks/runtime-fallback/chat-message-handler.ts
53228
53986
  init_logger();
53229
53987
  function createChatMessageHandler(deps) {
53230
- const { config: config2, sessionStates, sessionLastAccess } = deps;
53988
+ const { config: config2, sessionStates: sessionStates2, sessionLastAccess } = deps;
53231
53989
  return async (input, output) => {
53232
53990
  if (!config2.enabled)
53233
53991
  return;
53234
53992
  const { sessionID } = input;
53235
- let state3 = sessionStates.get(sessionID);
53993
+ let state3 = sessionStates2.get(sessionID);
53236
53994
  if (!state3)
53237
53995
  return;
53238
53996
  sessionLastAccess.set(sessionID, Date.now());
@@ -53242,19 +54000,19 @@ function createChatMessageHandler(deps) {
53242
54000
  state3.pendingFallbackModel = undefined;
53243
54001
  return;
53244
54002
  }
53245
- log(`[${HOOK_NAME8}] Detected manual model change, resetting fallback state`, {
54003
+ log(`[${HOOK_NAME9}] Detected manual model change, resetting fallback state`, {
53246
54004
  sessionID,
53247
54005
  from: state3.currentModel,
53248
54006
  to: requestedModel
53249
54007
  });
53250
54008
  state3 = createFallbackState(requestedModel);
53251
- sessionStates.set(sessionID, state3);
54009
+ sessionStates2.set(sessionID, state3);
53252
54010
  return;
53253
54011
  }
53254
54012
  if (state3.currentModel === state3.originalModel)
53255
54013
  return;
53256
54014
  const activeModel = state3.currentModel;
53257
- log(`[${HOOK_NAME8}] Applying fallback model override`, {
54015
+ log(`[${HOOK_NAME9}] Applying fallback model override`, {
53258
54016
  sessionID,
53259
54017
  from: input.model,
53260
54018
  to: activeModel
@@ -53441,7 +54199,7 @@ function resolveFallbackBootstrapModel(options) {
53441
54199
  const agentConfig = options.resolvedAgent && agentConfigs ? agentConfigs[options.resolvedAgent] : undefined;
53442
54200
  const agentModel = typeof agentConfig?.model === "string" ? agentConfig.model : undefined;
53443
54201
  if (agentModel) {
53444
- log(`[${HOOK_NAME8}] Derived model from agent config for ${options.source}`, {
54202
+ log(`[${HOOK_NAME9}] Derived model from agent config for ${options.source}`, {
53445
54203
  sessionID: options.sessionID,
53446
54204
  agent: options.resolvedAgent,
53447
54205
  model: agentModel
@@ -53452,7 +54210,7 @@ function resolveFallbackBootstrapModel(options) {
53452
54210
  if (agentCategory) {
53453
54211
  const agentCategoryModel = options.pluginConfig?.categories?.[agentCategory]?.model;
53454
54212
  if (typeof agentCategoryModel === "string" && agentCategoryModel.length > 0) {
53455
- log(`[${HOOK_NAME8}] Derived model from agent category config for ${options.source}`, {
54213
+ log(`[${HOOK_NAME9}] Derived model from agent category config for ${options.source}`, {
53456
54214
  sessionID: options.sessionID,
53457
54215
  agent: options.resolvedAgent,
53458
54216
  category: agentCategory,
@@ -53464,7 +54222,7 @@ function resolveFallbackBootstrapModel(options) {
53464
54222
  const sessionCategory = SessionCategoryRegistry.get(options.sessionID);
53465
54223
  const categoryModel = sessionCategory ? options.pluginConfig?.categories?.[sessionCategory]?.model : undefined;
53466
54224
  if (typeof categoryModel === "string" && categoryModel.length > 0) {
53467
- log(`[${HOOK_NAME8}] Derived model from session category config for ${options.source}`, {
54225
+ log(`[${HOOK_NAME9}] Derived model from session category config for ${options.source}`, {
53468
54226
  sessionID: options.sessionID,
53469
54227
  category: sessionCategory,
53470
54228
  model: categoryModel
@@ -53486,13 +54244,15 @@ async function dispatchFallbackRetry(deps, helpers, options) {
53486
54244
  variant: "warning",
53487
54245
  duration: 5000
53488
54246
  }
53489
- }).catch(() => {});
54247
+ }).catch((err) => {
54248
+ log("[runtime-fallback] Fallback notification toast failed:", err);
54249
+ });
53490
54250
  }
53491
54251
  if (result.success && result.newModel) {
53492
54252
  await helpers.autoRetryWithFallback(options.sessionID, result.newModel, options.resolvedAgent, options.source);
53493
54253
  return;
53494
54254
  }
53495
- log(`[${HOOK_NAME8}] Fallback preparation failed`, {
54255
+ log(`[${HOOK_NAME9}] Fallback preparation failed`, {
53496
54256
  sessionID: options.sessionID,
53497
54257
  source: options.source,
53498
54258
  error: result.error
@@ -53540,7 +54300,7 @@ function extractRetryAttempt(statusAttempt, message) {
53540
54300
  function createSessionStatusHandler(deps, helpers, sessionStatusRetryKeys) {
53541
54301
  const {
53542
54302
  pluginConfig,
53543
- sessionStates,
54303
+ sessionStates: sessionStates2,
53544
54304
  sessionLastAccess,
53545
54305
  sessionRetryInFlight
53546
54306
  } = deps;
@@ -53567,26 +54327,26 @@ function createSessionStatusHandler(deps, helpers, sessionStatusRetryKeys) {
53567
54327
  sessionStatusRetryKeys.set(sessionID, retryKey);
53568
54328
  if (sessionRetryInFlight.has(sessionID)) {
53569
54329
  if (timeoutEnabled) {
53570
- log(`[${HOOK_NAME8}] Overriding in-flight retry due to provider auto-retry signal`, {
54330
+ log(`[${HOOK_NAME9}] Overriding in-flight retry due to provider auto-retry signal`, {
53571
54331
  sessionID,
53572
54332
  model
53573
54333
  });
53574
54334
  await helpers.abortSessionRequest(sessionID, "session.status.retry-signal");
53575
54335
  sessionRetryInFlight.delete(sessionID);
53576
54336
  } else {
53577
- log(`[${HOOK_NAME8}] session.status retry skipped - retry already in flight`, { sessionID });
54337
+ log(`[${HOOK_NAME9}] session.status retry skipped - retry already in flight`, { sessionID });
53578
54338
  return;
53579
54339
  }
53580
54340
  }
53581
54341
  const resolvedAgent = await helpers.resolveAgentForSessionFromContext(sessionID, agent);
53582
54342
  const fallbackModels = getFallbackModelsForSession(sessionID, resolvedAgent, pluginConfig);
53583
54343
  if (fallbackModels.length === 0) {
53584
- if (!sessionStates.has(sessionID)) {
54344
+ if (!sessionStates2.has(sessionID)) {
53585
54345
  sessionStatusRetryKeys.delete(sessionID);
53586
54346
  }
53587
54347
  return;
53588
54348
  }
53589
- let state3 = sessionStates.get(sessionID);
54349
+ let state3 = sessionStates2.get(sessionID);
53590
54350
  if (!state3) {
53591
54351
  const initialModel = resolveFallbackBootstrapModel({
53592
54352
  sessionID,
@@ -53597,29 +54357,29 @@ function createSessionStatusHandler(deps, helpers, sessionStatusRetryKeys) {
53597
54357
  });
53598
54358
  if (!initialModel) {
53599
54359
  sessionStatusRetryKeys.delete(sessionID);
53600
- log(`[${HOOK_NAME8}] session.status retry missing model info, cannot fallback`, { sessionID });
54360
+ log(`[${HOOK_NAME9}] session.status retry missing model info, cannot fallback`, { sessionID });
53601
54361
  return;
53602
54362
  }
53603
54363
  state3 = createFallbackState(initialModel);
53604
- sessionStates.set(sessionID, state3);
54364
+ sessionStates2.set(sessionID, state3);
53605
54365
  }
53606
54366
  sessionLastAccess.set(sessionID, Date.now());
53607
54367
  if (state3.pendingFallbackModel) {
53608
54368
  if (timeoutEnabled) {
53609
- log(`[${HOOK_NAME8}] Clearing pending fallback due to provider auto-retry signal`, {
54369
+ log(`[${HOOK_NAME9}] Clearing pending fallback due to provider auto-retry signal`, {
53610
54370
  sessionID,
53611
54371
  pendingFallbackModel: state3.pendingFallbackModel
53612
54372
  });
53613
54373
  state3.pendingFallbackModel = undefined;
53614
54374
  } else {
53615
- log(`[${HOOK_NAME8}] session.status retry skipped (pending fallback in progress)`, {
54375
+ log(`[${HOOK_NAME9}] session.status retry skipped (pending fallback in progress)`, {
53616
54376
  sessionID,
53617
54377
  pendingFallbackModel: state3.pendingFallbackModel
53618
54378
  });
53619
54379
  return;
53620
54380
  }
53621
54381
  }
53622
- log(`[${HOOK_NAME8}] Detected provider auto-retry signal in session.status`, {
54382
+ log(`[${HOOK_NAME9}] Detected provider auto-retry signal in session.status`, {
53623
54383
  sessionID,
53624
54384
  model: state3.currentModel,
53625
54385
  retryAttempt: status.attempt
@@ -53637,13 +54397,13 @@ function createSessionStatusHandler(deps, helpers, sessionStatusRetryKeys) {
53637
54397
 
53638
54398
  // src/hooks/runtime-fallback/event-handler.ts
53639
54399
  function createEventHandler(deps, helpers) {
53640
- const { config: config2, pluginConfig, sessionStates, sessionLastAccess, sessionRetryInFlight, sessionAwaitingFallbackResult, sessionFallbackTimeouts, sessionStatusRetryKeys } = deps;
54400
+ const { config: config2, pluginConfig, sessionStates: sessionStates2, sessionLastAccess, sessionRetryInFlight, sessionAwaitingFallbackResult, sessionFallbackTimeouts, sessionStatusRetryKeys } = deps;
53641
54401
  const sessionStatusHandler = createSessionStatusHandler(deps, helpers, sessionStatusRetryKeys);
53642
54402
  const cancelledSessions = new Set;
53643
54403
  const resetRetryState = (sessionID) => {
53644
- const state3 = sessionStates.get(sessionID);
54404
+ const state3 = sessionStates2.get(sessionID);
53645
54405
  if (state3) {
53646
- sessionStates.set(sessionID, createFallbackState(state3.originalModel));
54406
+ sessionStates2.set(sessionID, createFallbackState(state3.originalModel));
53647
54407
  }
53648
54408
  sessionRetryInFlight.delete(sessionID);
53649
54409
  sessionAwaitingFallbackResult.delete(sessionID);
@@ -53655,8 +54415,8 @@ function createEventHandler(deps, helpers) {
53655
54415
  const sessionID = sessionInfo?.id;
53656
54416
  const model = sessionInfo?.model;
53657
54417
  if (sessionID && model) {
53658
- log(`[${HOOK_NAME8}] Session created with model`, { sessionID, model });
53659
- sessionStates.set(sessionID, createFallbackState(model));
54418
+ log(`[${HOOK_NAME9}] Session created with model`, { sessionID, model });
54419
+ sessionStates2.set(sessionID, createFallbackState(model));
53660
54420
  sessionLastAccess.set(sessionID, Date.now());
53661
54421
  }
53662
54422
  };
@@ -53664,9 +54424,9 @@ function createEventHandler(deps, helpers) {
53664
54424
  const sessionInfo = props?.info;
53665
54425
  const sessionID = sessionInfo?.id;
53666
54426
  if (sessionID) {
53667
- log(`[${HOOK_NAME8}] Cleaning up session state`, { sessionID });
54427
+ log(`[${HOOK_NAME9}] Cleaning up session state`, { sessionID });
53668
54428
  cancelledSessions.delete(sessionID);
53669
- sessionStates.delete(sessionID);
54429
+ sessionStates2.delete(sessionID);
53670
54430
  sessionLastAccess.delete(sessionID);
53671
54431
  sessionRetryInFlight.delete(sessionID);
53672
54432
  sessionAwaitingFallbackResult.delete(sessionID);
@@ -53684,7 +54444,7 @@ function createEventHandler(deps, helpers) {
53684
54444
  }
53685
54445
  cancelledSessions.add(sessionID);
53686
54446
  resetRetryState(sessionID);
53687
- log(`[${HOOK_NAME8}] Cleared fallback retry state on session.stop`, { sessionID });
54447
+ log(`[${HOOK_NAME9}] Cleared fallback retry state on session.stop`, { sessionID });
53688
54448
  };
53689
54449
  const handleMessageUpdated = (props) => {
53690
54450
  const info = props?.info;
@@ -53700,23 +54460,23 @@ function createEventHandler(deps, helpers) {
53700
54460
  return;
53701
54461
  if (cancelledSessions.has(sessionID)) {
53702
54462
  resetRetryState(sessionID);
53703
- log(`[${HOOK_NAME8}] Cleared fallback retry state for cancelled session on idle`, { sessionID });
54463
+ log(`[${HOOK_NAME9}] Cleared fallback retry state for cancelled session on idle`, { sessionID });
53704
54464
  return;
53705
54465
  }
53706
54466
  if (sessionAwaitingFallbackResult.has(sessionID)) {
53707
- log(`[${HOOK_NAME8}] session.idle while awaiting fallback result; keeping timeout armed`, { sessionID });
54467
+ log(`[${HOOK_NAME9}] session.idle while awaiting fallback result; keeping timeout armed`, { sessionID });
53708
54468
  return;
53709
54469
  }
53710
54470
  const hadTimeout = sessionFallbackTimeouts.has(sessionID);
53711
54471
  helpers.clearSessionFallbackTimeout(sessionID);
53712
54472
  sessionRetryInFlight.delete(sessionID);
53713
54473
  sessionStatusRetryKeys.delete(sessionID);
53714
- const state3 = sessionStates.get(sessionID);
54474
+ const state3 = sessionStates2.get(sessionID);
53715
54475
  if (state3?.pendingFallbackModel) {
53716
54476
  state3.pendingFallbackModel = undefined;
53717
54477
  }
53718
54478
  if (hadTimeout) {
53719
- log(`[${HOOK_NAME8}] Cleared fallback timeout after session completion`, { sessionID });
54479
+ log(`[${HOOK_NAME9}] Cleared fallback timeout after session completion`, { sessionID });
53720
54480
  }
53721
54481
  };
53722
54482
  const handleSessionError = async (props) => {
@@ -53724,18 +54484,18 @@ function createEventHandler(deps, helpers) {
53724
54484
  const error51 = props?.error;
53725
54485
  const agent = props?.agent;
53726
54486
  if (!sessionID) {
53727
- log(`[${HOOK_NAME8}] session.error without sessionID, skipping`);
54487
+ log(`[${HOOK_NAME9}] session.error without sessionID, skipping`);
53728
54488
  return;
53729
54489
  }
53730
54490
  const resolvedAgent = await helpers.resolveAgentForSessionFromContext(sessionID, agent);
53731
54491
  if (isAbortError2(error51)) {
53732
54492
  cancelledSessions.add(sessionID);
53733
54493
  resetRetryState(sessionID);
53734
- log(`[${HOOK_NAME8}] session.error matched cancellation; cleared retry state`, { sessionID, resolvedAgent });
54494
+ log(`[${HOOK_NAME9}] session.error matched cancellation; cleared retry state`, { sessionID, resolvedAgent });
53735
54495
  return;
53736
54496
  }
53737
54497
  if (sessionRetryInFlight.has(sessionID)) {
53738
- log(`[${HOOK_NAME8}] session.error skipped - retry in flight`, {
54498
+ log(`[${HOOK_NAME9}] session.error skipped - retry in flight`, {
53739
54499
  sessionID,
53740
54500
  retryInFlight: true
53741
54501
  });
@@ -53743,7 +54503,7 @@ function createEventHandler(deps, helpers) {
53743
54503
  }
53744
54504
  sessionAwaitingFallbackResult.delete(sessionID);
53745
54505
  helpers.clearSessionFallbackTimeout(sessionID);
53746
- log(`[${HOOK_NAME8}] session.error received`, {
54506
+ log(`[${HOOK_NAME9}] session.error received`, {
53747
54507
  sessionID,
53748
54508
  agent,
53749
54509
  resolvedAgent,
@@ -53752,7 +54512,7 @@ function createEventHandler(deps, helpers) {
53752
54512
  errorType: classifyErrorType(error51)
53753
54513
  });
53754
54514
  if (!isRetryableError(error51, config2.retry_on_errors)) {
53755
- log(`[${HOOK_NAME8}] Error not retryable, skipping fallback`, {
54515
+ log(`[${HOOK_NAME9}] Error not retryable, skipping fallback`, {
53756
54516
  sessionID,
53757
54517
  retryable: false,
53758
54518
  statusCode: extractStatusCode(error51, config2.retry_on_errors),
@@ -53761,10 +54521,10 @@ function createEventHandler(deps, helpers) {
53761
54521
  });
53762
54522
  return;
53763
54523
  }
53764
- let state3 = sessionStates.get(sessionID);
54524
+ let state3 = sessionStates2.get(sessionID);
53765
54525
  const fallbackModels = getFallbackModelsForSession(sessionID, resolvedAgent, pluginConfig);
53766
54526
  if (fallbackModels.length === 0) {
53767
- log(`[${HOOK_NAME8}] No fallback models configured`, { sessionID, agent });
54527
+ log(`[${HOOK_NAME9}] No fallback models configured`, { sessionID, agent });
53768
54528
  return;
53769
54529
  }
53770
54530
  if (!state3) {
@@ -53776,11 +54536,11 @@ function createEventHandler(deps, helpers) {
53776
54536
  pluginConfig
53777
54537
  });
53778
54538
  if (!initialModel) {
53779
- log(`[${HOOK_NAME8}] No model info available, cannot fallback`, { sessionID });
54539
+ log(`[${HOOK_NAME9}] No model info available, cannot fallback`, { sessionID });
53780
54540
  return;
53781
54541
  }
53782
54542
  state3 = createFallbackState(initialModel);
53783
- sessionStates.set(sessionID, state3);
54543
+ sessionStates2.set(sessionID, state3);
53784
54544
  sessionLastAccess.set(sessionID, Date.now());
53785
54545
  } else {
53786
54546
  sessionLastAccess.set(sessionID, Date.now());
@@ -53892,7 +54652,7 @@ function hasVisibleAssistantResponse(extractAutoRetrySignalFn) {
53892
54652
 
53893
54653
  // src/hooks/runtime-fallback/message-update-handler.ts
53894
54654
  function createMessageUpdateHandler(deps, helpers) {
53895
- const { ctx, config: config2, pluginConfig, sessionStates, sessionLastAccess, sessionRetryInFlight, sessionAwaitingFallbackResult, sessionStatusRetryKeys } = deps;
54655
+ const { ctx, config: config2, pluginConfig, sessionStates: sessionStates2, sessionLastAccess, sessionRetryInFlight, sessionAwaitingFallbackResult, sessionStatusRetryKeys } = deps;
53896
54656
  const checkVisibleResponse = hasVisibleAssistantResponse(extractAutoRetrySignal);
53897
54657
  return async (props) => {
53898
54658
  const info = props?.info;
@@ -53916,7 +54676,7 @@ function createMessageUpdateHandler(deps, helpers) {
53916
54676
  }
53917
54677
  const hasVisible = await checkVisibleResponse(ctx, sessionID, info);
53918
54678
  if (!hasVisible) {
53919
- log(`[${HOOK_NAME8}] Assistant update observed without visible final response; keeping fallback timeout`, {
54679
+ log(`[${HOOK_NAME9}] Assistant update observed without visible final response; keeping fallback timeout`, {
53920
54680
  sessionID,
53921
54681
  model
53922
54682
  });
@@ -53925,21 +54685,21 @@ function createMessageUpdateHandler(deps, helpers) {
53925
54685
  sessionAwaitingFallbackResult.delete(sessionID);
53926
54686
  sessionStatusRetryKeys.delete(sessionID);
53927
54687
  helpers.clearSessionFallbackTimeout(sessionID);
53928
- const state3 = sessionStates.get(sessionID);
54688
+ const state3 = sessionStates2.get(sessionID);
53929
54689
  if (state3?.pendingFallbackModel) {
53930
54690
  state3.pendingFallbackModel = undefined;
53931
54691
  }
53932
- log(`[${HOOK_NAME8}] Assistant response observed; cleared fallback timeout`, { sessionID, model });
54692
+ log(`[${HOOK_NAME9}] Assistant response observed; cleared fallback timeout`, { sessionID, model });
53933
54693
  return;
53934
54694
  }
53935
54695
  if (sessionID && role === "assistant" && error51) {
53936
54696
  sessionAwaitingFallbackResult.delete(sessionID);
53937
54697
  if (sessionRetryInFlight.has(sessionID) && !retrySignal) {
53938
- log(`[${HOOK_NAME8}] message.updated fallback skipped (retry in flight)`, { sessionID });
54698
+ log(`[${HOOK_NAME9}] message.updated fallback skipped (retry in flight)`, { sessionID });
53939
54699
  return;
53940
54700
  }
53941
54701
  if (retrySignal && sessionRetryInFlight.has(sessionID) && timeoutEnabled) {
53942
- log(`[${HOOK_NAME8}] Overriding in-flight retry due to provider auto-retry signal`, {
54702
+ log(`[${HOOK_NAME9}] Overriding in-flight retry due to provider auto-retry signal`, {
53943
54703
  sessionID,
53944
54704
  model
53945
54705
  });
@@ -53947,12 +54707,12 @@ function createMessageUpdateHandler(deps, helpers) {
53947
54707
  sessionRetryInFlight.delete(sessionID);
53948
54708
  }
53949
54709
  if (retrySignal && timeoutEnabled) {
53950
- log(`[${HOOK_NAME8}] Detected provider auto-retry signal`, { sessionID, model });
54710
+ log(`[${HOOK_NAME9}] Detected provider auto-retry signal`, { sessionID, model });
53951
54711
  }
53952
54712
  if (!retrySignal) {
53953
54713
  helpers.clearSessionFallbackTimeout(sessionID);
53954
54714
  }
53955
- log(`[${HOOK_NAME8}] message.updated with assistant error`, {
54715
+ log(`[${HOOK_NAME9}] message.updated with assistant error`, {
53956
54716
  sessionID,
53957
54717
  model,
53958
54718
  statusCode: extractStatusCode(error51, config2.retry_on_errors),
@@ -53960,7 +54720,7 @@ function createMessageUpdateHandler(deps, helpers) {
53960
54720
  errorType: classifyErrorType(error51)
53961
54721
  });
53962
54722
  if (!isRetryableError(error51, config2.retry_on_errors)) {
53963
- log(`[${HOOK_NAME8}] message.updated error not retryable, skipping fallback`, {
54723
+ log(`[${HOOK_NAME9}] message.updated error not retryable, skipping fallback`, {
53964
54724
  sessionID,
53965
54725
  statusCode: extractStatusCode(error51, config2.retry_on_errors),
53966
54726
  errorName: extractErrorName(error51),
@@ -53968,7 +54728,7 @@ function createMessageUpdateHandler(deps, helpers) {
53968
54728
  });
53969
54729
  return;
53970
54730
  }
53971
- let state3 = sessionStates.get(sessionID);
54731
+ let state3 = sessionStates2.get(sessionID);
53972
54732
  const agent = info?.agent;
53973
54733
  const resolvedAgent = await helpers.resolveAgentForSessionFromContext(sessionID, agent);
53974
54734
  const fallbackModels = getFallbackModelsForSession(sessionID, resolvedAgent, pluginConfig);
@@ -53984,7 +54744,7 @@ function createMessageUpdateHandler(deps, helpers) {
53984
54744
  pluginConfig
53985
54745
  });
53986
54746
  if (!initialModel) {
53987
- log(`[${HOOK_NAME8}] message.updated missing model info, cannot fallback`, {
54747
+ log(`[${HOOK_NAME9}] message.updated missing model info, cannot fallback`, {
53988
54748
  sessionID,
53989
54749
  errorName: extractErrorName(error51),
53990
54750
  errorType: classifyErrorType(error51)
@@ -53992,19 +54752,19 @@ function createMessageUpdateHandler(deps, helpers) {
53992
54752
  return;
53993
54753
  }
53994
54754
  state3 = createFallbackState(initialModel);
53995
- sessionStates.set(sessionID, state3);
54755
+ sessionStates2.set(sessionID, state3);
53996
54756
  sessionLastAccess.set(sessionID, Date.now());
53997
54757
  } else {
53998
54758
  sessionLastAccess.set(sessionID, Date.now());
53999
54759
  if (state3.pendingFallbackModel) {
54000
54760
  if (retrySignal && timeoutEnabled) {
54001
- log(`[${HOOK_NAME8}] Clearing pending fallback due to provider auto-retry signal`, {
54761
+ log(`[${HOOK_NAME9}] Clearing pending fallback due to provider auto-retry signal`, {
54002
54762
  sessionID,
54003
54763
  pendingFallbackModel: state3.pendingFallbackModel
54004
54764
  });
54005
54765
  state3.pendingFallbackModel = undefined;
54006
54766
  } else {
54007
- log(`[${HOOK_NAME8}] message.updated fallback skipped (pending fallback in progress)`, {
54767
+ log(`[${HOOK_NAME9}] message.updated fallback skipped (pending fallback in progress)`, {
54008
54768
  sessionID,
54009
54769
  pendingFallbackModel: state3.pendingFallbackModel
54010
54770
  });
@@ -54348,6 +55108,7 @@ function createIdleNotificationScheduler(options) {
54348
55108
  }
54349
55109
 
54350
55110
  // src/hooks/session-notification-sender.ts
55111
+ init_logger();
54351
55112
  import { platform } from "os";
54352
55113
 
54353
55114
  // src/hooks/session-notification-formatting.ts
@@ -54375,6 +55136,7 @@ $Notifier.Show($Toast)
54375
55136
  }
54376
55137
 
54377
55138
  // src/hooks/session-notification-utils.ts
55139
+ init_logger();
54378
55140
  async function findCommand2(commandName) {
54379
55141
  try {
54380
55142
  return Bun.which(commandName);
@@ -54406,14 +55168,26 @@ var getPaplayPath = createCommandFinder("paplay");
54406
55168
  var getAplayPath = createCommandFinder("aplay");
54407
55169
  function startBackgroundCheck2(platform) {
54408
55170
  if (platform === "darwin") {
54409
- getOsascriptPath().catch(() => {});
54410
- getAfplayPath().catch(() => {});
55171
+ getOsascriptPath().catch((err) => {
55172
+ log("[notification] Background check failed for osascript:", err);
55173
+ });
55174
+ getAfplayPath().catch((err) => {
55175
+ log("[notification] Background check failed for afplay:", err);
55176
+ });
54411
55177
  } else if (platform === "linux") {
54412
- getNotifySendPath().catch(() => {});
54413
- getPaplayPath().catch(() => {});
54414
- getAplayPath().catch(() => {});
55178
+ getNotifySendPath().catch((err) => {
55179
+ log("[notification] Background check failed for notify-send:", err);
55180
+ });
55181
+ getPaplayPath().catch((err) => {
55182
+ log("[notification] Background check failed for paplay:", err);
55183
+ });
55184
+ getAplayPath().catch((err) => {
55185
+ log("[notification] Background check failed for aplay:", err);
55186
+ });
54415
55187
  } else if (platform === "win32") {
54416
- getPowershellPath().catch(() => {});
55188
+ getPowershellPath().catch((err) => {
55189
+ log("[notification] Background check failed for powershell:", err);
55190
+ });
54417
55191
  }
54418
55192
  }
54419
55193
 
@@ -54444,14 +55218,18 @@ async function sendSessionNotification(ctx, platform2, title, message) {
54444
55218
  return;
54445
55219
  const escapedTitle = escapeAppleScriptText(title);
54446
55220
  const escapedMessage = escapeAppleScriptText(message);
54447
- await ctx.$`${osascriptPath} -e ${`display notification "${escapedMessage}" with title "${escapedTitle}"`}`.catch(() => {});
55221
+ await ctx.$`${osascriptPath} -e ${`display notification "${escapedMessage}" with title "${escapedTitle}"`}`.catch((err) => {
55222
+ log("[notification] macOS notification failed:", err);
55223
+ });
54448
55224
  break;
54449
55225
  }
54450
55226
  case "linux": {
54451
55227
  const notifySendPath = await getNotifySendPath();
54452
55228
  if (!notifySendPath)
54453
55229
  return;
54454
- await ctx.$`${notifySendPath} ${title} ${message} 2>/dev/null`.catch(() => {});
55230
+ await ctx.$`${notifySendPath} ${title} ${message} 2>/dev/null`.catch((err) => {
55231
+ log("[notification] Linux notification failed:", err);
55232
+ });
54455
55233
  break;
54456
55234
  }
54457
55235
  case "win32": {
@@ -54459,7 +55237,9 @@ async function sendSessionNotification(ctx, platform2, title, message) {
54459
55237
  if (!powershellPath)
54460
55238
  return;
54461
55239
  const toastScript = buildWindowsToastScript(title, message);
54462
- await ctx.$`${powershellPath} -Command ${toastScript}`.catch(() => {});
55240
+ await ctx.$`${powershellPath} -Command ${toastScript}`.catch((err) => {
55241
+ log("[notification] Windows notification failed:", err);
55242
+ });
54463
55243
  break;
54464
55244
  }
54465
55245
  }
@@ -54470,17 +55250,23 @@ async function playSessionNotificationSound(ctx, platform2, soundPath) {
54470
55250
  const afplayPath = await getAfplayPath();
54471
55251
  if (!afplayPath)
54472
55252
  return;
54473
- ctx.$`${afplayPath} ${soundPath}`.catch(() => {});
55253
+ ctx.$`${afplayPath} ${soundPath}`.catch((err) => {
55254
+ log("[notification] macOS sound playback failed:", err);
55255
+ });
54474
55256
  break;
54475
55257
  }
54476
55258
  case "linux": {
54477
55259
  const paplayPath = await getPaplayPath();
54478
55260
  if (paplayPath) {
54479
- ctx.$`${paplayPath} ${soundPath} 2>/dev/null`.catch(() => {});
55261
+ ctx.$`${paplayPath} ${soundPath} 2>/dev/null`.catch((err) => {
55262
+ log("[notification] Linux sound playback (paplay) failed:", err);
55263
+ });
54480
55264
  } else {
54481
55265
  const aplayPath = await getAplayPath();
54482
55266
  if (aplayPath) {
54483
- ctx.$`${aplayPath} ${soundPath} 2>/dev/null`.catch(() => {});
55267
+ ctx.$`${aplayPath} ${soundPath} 2>/dev/null`.catch((err) => {
55268
+ log("[notification] Linux sound playback (aplay) failed:", err);
55269
+ });
54484
55270
  }
54485
55271
  }
54486
55272
  break;
@@ -54490,7 +55276,9 @@ async function playSessionNotificationSound(ctx, platform2, soundPath) {
54490
55276
  if (!powershellPath)
54491
55277
  return;
54492
55278
  const escaped = escapePowerShellSingleQuotedText(soundPath);
54493
- ctx.$`${powershellPath} -Command ${`(New-Object Media.SoundPlayer '${escaped}').PlaySync()`}`.catch(() => {});
55279
+ ctx.$`${powershellPath} -Command ${`(New-Object Media.SoundPlayer '${escaped}').PlaySync()`}`.catch((err) => {
55280
+ log("[notification] Windows sound playback failed:", err);
55281
+ });
54494
55282
  break;
54495
55283
  }
54496
55284
  }
@@ -54908,7 +55696,9 @@ function createSessionRecoveryHook(ctx, options) {
54908
55696
  if (onAbortCallback) {
54909
55697
  onAbortCallback(sessionID);
54910
55698
  }
54911
- await ctx.client.session.abort({ path: { id: sessionID } }).catch(() => {});
55699
+ await ctx.client.session.abort({ path: { id: sessionID } }).catch((err) => {
55700
+ log("[session-recovery] Session abort failed:", err);
55701
+ });
54912
55702
  const messagesResp = await ctx.client.session.messages({
54913
55703
  path: { id: sessionID },
54914
55704
  query: { directory: ctx.directory }
@@ -54937,7 +55727,9 @@ function createSessionRecoveryHook(ctx, options) {
54937
55727
  variant: "warning",
54938
55728
  duration: 3000
54939
55729
  }
54940
- }).catch(() => {});
55730
+ }).catch((err) => {
55731
+ log("[session-recovery] Recovery toast failed:", err);
55732
+ });
54941
55733
  let success2 = false;
54942
55734
  if (errorType === "tool_result_missing") {
54943
55735
  success2 = await recoverToolResultMissing(ctx.client, sessionID, failedMsg);
@@ -54978,7 +55770,7 @@ function createSessionRecoveryHook(ctx, options) {
54978
55770
  }
54979
55771
  // src/hooks/start-work/start-work-hook.ts
54980
55772
  init_logger();
54981
- var HOOK_NAME9 = "start-work";
55773
+ var HOOK_NAME10 = "start-work";
54982
55774
  var KEYWORD_PATTERN = /\b(ultrawork|ulw)\b/gi;
54983
55775
  function extractUserRequestPlanName(promptText) {
54984
55776
  const userRequestMatch = promptText.match(/<user-request>\s*([\s\S]*?)\s*<\/user-request>/i);
@@ -55008,7 +55800,7 @@ function createStartWorkHook(ctx) {
55008
55800
  if (!isStartWorkCommand) {
55009
55801
  return;
55010
55802
  }
55011
- log(`[${HOOK_NAME9}] Processing start-work command`, {
55803
+ log(`[${HOOK_NAME10}] Processing start-work command`, {
55012
55804
  sessionID: input.sessionID
55013
55805
  });
55014
55806
  updateSessionAgent(input.sessionID, "architect");
@@ -55018,7 +55810,7 @@ function createStartWorkHook(ctx) {
55018
55810
  let contextInfo = "";
55019
55811
  const explicitPlanName = extractUserRequestPlanName(promptText);
55020
55812
  if (explicitPlanName) {
55021
- log(`[${HOOK_NAME9}] Explicit plan name requested: ${explicitPlanName}`, {
55813
+ log(`[${HOOK_NAME10}] Explicit plan name requested: ${explicitPlanName}`, {
55022
55814
  sessionID: input.sessionID
55023
55815
  });
55024
55816
  const allPlans = findOraclePlans(ctx.directory);
@@ -55159,7 +55951,7 @@ Ask the user which plan to work on. Present the options above and wait for their
55159
55951
  ---
55160
55952
  ${contextInfo}`;
55161
55953
  }
55162
- log(`[${HOOK_NAME9}] Context injected`, {
55954
+ log(`[${HOOK_NAME10}] Context injected`, {
55163
55955
  sessionID: input.sessionID,
55164
55956
  hasExistingState: !!existingState
55165
55957
  });
@@ -55168,16 +55960,16 @@ ${contextInfo}`;
55168
55960
  }
55169
55961
  // src/hooks/stop-continuation-guard/hook.ts
55170
55962
  init_logger();
55171
- var HOOK_NAME10 = "stop-continuation-guard";
55963
+ var HOOK_NAME11 = "stop-continuation-guard";
55172
55964
  function createStopContinuationGuardHook(_ctx, options) {
55173
55965
  const stoppedSessions = new Set;
55174
55966
  const stop = (sessionID) => {
55175
55967
  stoppedSessions.add(sessionID);
55176
- log(`[${HOOK_NAME10}] Continuation stopped for session`, { sessionID });
55968
+ log(`[${HOOK_NAME11}] Continuation stopped for session`, { sessionID });
55177
55969
  if (options?.backgroundManager) {
55178
55970
  const cancelled = options.backgroundManager.cancelAllForSession(sessionID);
55179
55971
  if (cancelled > 0) {
55180
- log(`[${HOOK_NAME10}] Cancelled ${cancelled} background task(s) for session`, { sessionID });
55972
+ log(`[${HOOK_NAME11}] Cancelled ${cancelled} background task(s) for session`, { sessionID });
55181
55973
  }
55182
55974
  }
55183
55975
  };
@@ -55186,7 +55978,7 @@ function createStopContinuationGuardHook(_ctx, options) {
55186
55978
  };
55187
55979
  const clear = (sessionID) => {
55188
55980
  stoppedSessions.delete(sessionID);
55189
- log(`[${HOOK_NAME10}] Continuation guard cleared for session`, { sessionID });
55981
+ log(`[${HOOK_NAME11}] Continuation guard cleared for session`, { sessionID });
55190
55982
  };
55191
55983
  const event = async ({
55192
55984
  event: event2
@@ -55196,7 +55988,7 @@ function createStopContinuationGuardHook(_ctx, options) {
55196
55988
  const sessionInfo = props?.info;
55197
55989
  if (sessionInfo?.id) {
55198
55990
  clear(sessionInfo.id);
55199
- log(`[${HOOK_NAME10}] Session deleted: cleaned up`, { sessionID: sessionInfo.id });
55991
+ log(`[${HOOK_NAME11}] Session deleted: cleaned up`, { sessionID: sessionInfo.id });
55200
55992
  }
55201
55993
  }
55202
55994
  };
@@ -55205,7 +55997,7 @@ function createStopContinuationGuardHook(_ctx, options) {
55205
55997
  }) => {
55206
55998
  if (sessionID && stoppedSessions.has(sessionID)) {
55207
55999
  clear(sessionID);
55208
- log(`[${HOOK_NAME10}] Cleared stop state on new user message`, { sessionID });
56000
+ log(`[${HOOK_NAME11}] Cleared stop state on new user message`, { sessionID });
55209
56001
  }
55210
56002
  };
55211
56003
  return {
@@ -55217,7 +56009,7 @@ function createStopContinuationGuardHook(_ctx, options) {
55217
56009
  };
55218
56010
  }
55219
56011
  // src/hooks/task-notepad/constants.ts
55220
- var HOOK_NAME11 = "task-notepad";
56012
+ var HOOK_NAME12 = "task-notepad";
55221
56013
  var PLAN_DIR_NAME = ".matrixx";
55222
56014
  var PLANS_SUBDIR = "plans";
55223
56015
  var NOTEPAD_DIR_NAME = "notepads";
@@ -55246,7 +56038,7 @@ function createTaskNotepadHook(ctx) {
55246
56038
  const plan = resolveActivePlan(ctx.directory);
55247
56039
  if (inProgress) {
55248
56040
  if (!plan) {
55249
- log(`[${HOOK_NAME11}] No active plan, skipping notepad creation`, {
56041
+ log(`[${HOOK_NAME12}] No active plan, skipping notepad creation`, {
55250
56042
  sessionID: input.sessionID
55251
56043
  });
55252
56044
  } else {
@@ -55273,7 +56065,7 @@ async function fetchTodos(ctx, sessionID) {
55273
56065
  }
55274
56066
  return [];
55275
56067
  } catch (err) {
55276
- log(`[${HOOK_NAME11}] ${TODO_FETCH_ERROR_FRAGMENT}`, {
56068
+ log(`[${HOOK_NAME12}] ${TODO_FETCH_ERROR_FRAGMENT}`, {
55277
56069
  sessionID,
55278
56070
  error: String(err)
55279
56071
  });
@@ -55318,7 +56110,7 @@ function ensureNotepad(directory, planName, todo) {
55318
56110
  mkdirSync12(dirname15(notepadPath), { recursive: true });
55319
56111
  const content = renderNotepad(todo);
55320
56112
  writeFileSync16(notepadPath, content, "utf-8");
55321
- log(`[${HOOK_NAME11}] Created task notepad`, { plan: planName, taskID: todo.id });
56113
+ log(`[${HOOK_NAME12}] Created task notepad`, { plan: planName, taskID: todo.id });
55322
56114
  }
55323
56115
  function appendCompletion(directory, planName, todo) {
55324
56116
  const notepadPath = notepadPathFor(directory, planName, todo.id);
@@ -55334,7 +56126,7 @@ function appendCompletion(directory, planName, todo) {
55334
56126
  - status: completed
55335
56127
  `;
55336
56128
  writeFileSync16(notepadPath, updated, "utf-8");
55337
- log(`[${HOOK_NAME11}] Appended completion to notepad`, { plan: planName, taskID: todo.id });
56129
+ log(`[${HOOK_NAME12}] Appended completion to notepad`, { plan: planName, taskID: todo.id });
55338
56130
  }
55339
56131
  function notepadPathFor(directory, planName, taskID) {
55340
56132
  return join54(directory, PLAN_DIR_NAME, NOTEPAD_DIR_NAME, planName, TASKS_SUBDIR, `${taskID}${NOTEPAD_EXTENSION}`);
@@ -55916,7 +56708,7 @@ function createThinkingBlockValidatorHook() {
55916
56708
  init_logger();
55917
56709
 
55918
56710
  // src/hooks/todo-continuation-enforcer/constants.ts
55919
- var HOOK_NAME12 = "todo-continuation-enforcer";
56711
+ var HOOK_NAME13 = "todo-continuation-enforcer";
55920
56712
  var DEFAULT_SKIP_AGENTS = ["oracle", "compaction"];
55921
56713
  var CONTINUATION_PROMPT2 = `${createSystemDirective(SystemDirectiveTypes.TODO_CONTINUATION)}
55922
56714
 
@@ -55982,12 +56774,12 @@ async function injectContinuation(args) {
55982
56774
  } = args;
55983
56775
  const state3 = sessionStateStore.getExistingState(sessionID);
55984
56776
  if (state3?.isRecovering) {
55985
- log(`[${HOOK_NAME12}] Skipped injection: in recovery`, { sessionID });
56777
+ log(`[${HOOK_NAME13}] Skipped injection: in recovery`, { sessionID });
55986
56778
  return;
55987
56779
  }
55988
56780
  const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "running") : false;
55989
56781
  if (hasRunningBgTasks) {
55990
- log(`[${HOOK_NAME12}] Skipped injection: background tasks running`, { sessionID });
56782
+ log(`[${HOOK_NAME13}] Skipped injection: background tasks running`, { sessionID });
55991
56783
  return;
55992
56784
  }
55993
56785
  let todos = [];
@@ -55995,12 +56787,12 @@ async function injectContinuation(args) {
55995
56787
  const response = await ctx.client.session.todo({ path: { id: sessionID } });
55996
56788
  todos = normalizeSDKResponse(response, [], { preferResponseOnMissingData: true });
55997
56789
  } catch (error51) {
55998
- log(`[${HOOK_NAME12}] Failed to fetch todos`, { sessionID, error: String(error51) });
56790
+ log(`[${HOOK_NAME13}] Failed to fetch todos`, { sessionID, error: String(error51) });
55999
56791
  return;
56000
56792
  }
56001
56793
  const freshIncompleteCount = getIncompleteCount(todos);
56002
56794
  if (freshIncompleteCount === 0) {
56003
- log(`[${HOOK_NAME12}] Skipped injection: no incomplete todos`, { sessionID });
56795
+ log(`[${HOOK_NAME13}] Skipped injection: no incomplete todos`, { sessionID });
56004
56796
  return;
56005
56797
  }
56006
56798
  let agentName = resolvedInfo?.agent;
@@ -56023,11 +56815,11 @@ async function injectContinuation(args) {
56023
56815
  tools = tools ?? previousMessage?.tools;
56024
56816
  }
56025
56817
  if (agentName && skipAgents.some((s) => getAgentConfigKey(s) === getAgentConfigKey(agentName))) {
56026
- log(`[${HOOK_NAME12}] Skipped: agent in skipAgents list`, { sessionID, agent: agentName });
56818
+ log(`[${HOOK_NAME13}] Skipped: agent in skipAgents list`, { sessionID, agent: agentName });
56027
56819
  return;
56028
56820
  }
56029
56821
  if (!hasWritePermission(tools)) {
56030
- log(`[${HOOK_NAME12}] Skipped: agent lacks write permission`, { sessionID, agent: agentName });
56822
+ log(`[${HOOK_NAME13}] Skipped: agent lacks write permission`, { sessionID, agent: agentName });
56031
56823
  return;
56032
56824
  }
56033
56825
  const incompleteTodos = todos.filter((todo) => todo.status !== "completed" && todo.status !== "cancelled");
@@ -56044,7 +56836,7 @@ ${todoList}`;
56044
56836
  injectionState.inFlight = true;
56045
56837
  }
56046
56838
  try {
56047
- log(`[${HOOK_NAME12}] Injecting continuation`, {
56839
+ log(`[${HOOK_NAME13}] Injecting continuation`, {
56048
56840
  sessionID,
56049
56841
  agent: agentName,
56050
56842
  model,
@@ -56059,14 +56851,14 @@ ${todoList}`;
56059
56851
  },
56060
56852
  query: { directory: ctx.directory }
56061
56853
  });
56062
- log(`[${HOOK_NAME12}] Injection successful`, { sessionID });
56854
+ log(`[${HOOK_NAME13}] Injection successful`, { sessionID });
56063
56855
  if (injectionState) {
56064
56856
  injectionState.inFlight = false;
56065
56857
  injectionState.lastInjectedAt = Date.now();
56066
56858
  injectionState.consecutiveFailures = 0;
56067
56859
  }
56068
56860
  } catch (error51) {
56069
- log(`[${HOOK_NAME12}] Injection failed`, { sessionID, error: String(error51) });
56861
+ log(`[${HOOK_NAME13}] Injection failed`, { sessionID, error: String(error51) });
56070
56862
  if (injectionState) {
56071
56863
  injectionState.inFlight = false;
56072
56864
  injectionState.lastInjectedAt = Date.now();
@@ -56084,7 +56876,9 @@ async function showCountdownToast(ctx, seconds, incompleteCount) {
56084
56876
  variant: "warning",
56085
56877
  duration: TOAST_DURATION_MS
56086
56878
  }
56087
- }).catch(() => {});
56879
+ }).catch((err) => {
56880
+ log("[todo-continuation] Countdown toast failed:", err);
56881
+ });
56088
56882
  }
56089
56883
  function startCountdown(args) {
56090
56884
  const {
@@ -56118,7 +56912,7 @@ function startCountdown(args) {
56118
56912
  sessionStateStore
56119
56913
  });
56120
56914
  }, COUNTDOWN_SECONDS * 1000);
56121
- log(`[${HOOK_NAME12}] Countdown started`, {
56915
+ log(`[${HOOK_NAME13}] Countdown started`, {
56122
56916
  sessionID,
56123
56917
  seconds: COUNTDOWN_SECONDS,
56124
56918
  incompleteCount
@@ -56135,16 +56929,16 @@ async function handleSessionIdle(args) {
56135
56929
  skipAgents = DEFAULT_SKIP_AGENTS,
56136
56930
  isContinuationStopped
56137
56931
  } = args;
56138
- log(`[${HOOK_NAME12}] session.idle`, { sessionID });
56932
+ log(`[${HOOK_NAME13}] session.idle`, { sessionID });
56139
56933
  const state3 = sessionStateStore.getState(sessionID);
56140
56934
  if (state3.isRecovering) {
56141
- log(`[${HOOK_NAME12}] Skipped: in recovery`, { sessionID });
56935
+ log(`[${HOOK_NAME13}] Skipped: in recovery`, { sessionID });
56142
56936
  return;
56143
56937
  }
56144
56938
  if (state3.abortDetectedAt) {
56145
56939
  const timeSinceAbort = Date.now() - state3.abortDetectedAt;
56146
56940
  if (timeSinceAbort < ABORT_WINDOW_MS) {
56147
- log(`[${HOOK_NAME12}] Skipped: abort detected via event ${timeSinceAbort}ms ago`, { sessionID });
56941
+ log(`[${HOOK_NAME13}] Skipped: abort detected via event ${timeSinceAbort}ms ago`, { sessionID });
56148
56942
  state3.abortDetectedAt = undefined;
56149
56943
  return;
56150
56944
  }
@@ -56152,7 +56946,7 @@ async function handleSessionIdle(args) {
56152
56946
  }
56153
56947
  const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "running") : false;
56154
56948
  if (hasRunningBgTasks) {
56155
- log(`[${HOOK_NAME12}] Skipped: background tasks running`, { sessionID });
56949
+ log(`[${HOOK_NAME13}] Skipped: background tasks running`, { sessionID });
56156
56950
  return;
56157
56951
  }
56158
56952
  try {
@@ -56162,42 +56956,42 @@ async function handleSessionIdle(args) {
56162
56956
  });
56163
56957
  const messages = normalizeSDKResponse(messagesResp, []);
56164
56958
  if (isLastAssistantMessageAborted(messages)) {
56165
- log(`[${HOOK_NAME12}] Skipped: last assistant message was aborted (API fallback)`, { sessionID });
56959
+ log(`[${HOOK_NAME13}] Skipped: last assistant message was aborted (API fallback)`, { sessionID });
56166
56960
  return;
56167
56961
  }
56168
56962
  } catch (error51) {
56169
- log(`[${HOOK_NAME12}] Messages fetch failed, continuing`, { sessionID, error: String(error51) });
56963
+ log(`[${HOOK_NAME13}] Messages fetch failed, continuing`, { sessionID, error: String(error51) });
56170
56964
  }
56171
56965
  let todos = [];
56172
56966
  try {
56173
56967
  const response = await ctx.client.session.todo({ path: { id: sessionID } });
56174
56968
  todos = normalizeSDKResponse(response, [], { preferResponseOnMissingData: true });
56175
56969
  } catch (error51) {
56176
- log(`[${HOOK_NAME12}] Todo fetch failed`, { sessionID, error: String(error51) });
56970
+ log(`[${HOOK_NAME13}] Todo fetch failed`, { sessionID, error: String(error51) });
56177
56971
  return;
56178
56972
  }
56179
56973
  if (!todos || todos.length === 0) {
56180
- log(`[${HOOK_NAME12}] No todos`, { sessionID });
56974
+ log(`[${HOOK_NAME13}] No todos`, { sessionID });
56181
56975
  return;
56182
56976
  }
56183
56977
  const incompleteCount = getIncompleteCount(todos);
56184
56978
  if (incompleteCount === 0) {
56185
- log(`[${HOOK_NAME12}] All todos complete`, { sessionID, total: todos.length });
56979
+ log(`[${HOOK_NAME13}] All todos complete`, { sessionID, total: todos.length });
56186
56980
  return;
56187
56981
  }
56188
56982
  if (state3.inFlight) {
56189
- log(`[${HOOK_NAME12}] Skipped: injection in flight`, { sessionID });
56983
+ log(`[${HOOK_NAME13}] Skipped: injection in flight`, { sessionID });
56190
56984
  return;
56191
56985
  }
56192
56986
  if (state3.consecutiveFailures >= MAX_CONSECUTIVE_FAILURES && state3.lastInjectedAt && Date.now() - state3.lastInjectedAt >= FAILURE_RESET_WINDOW_MS) {
56193
56987
  state3.consecutiveFailures = 0;
56194
- log(`[${HOOK_NAME12}] Reset consecutive failures after recovery window`, {
56988
+ log(`[${HOOK_NAME13}] Reset consecutive failures after recovery window`, {
56195
56989
  sessionID,
56196
56990
  failureResetWindowMs: FAILURE_RESET_WINDOW_MS
56197
56991
  });
56198
56992
  }
56199
56993
  if (state3.consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
56200
- log(`[${HOOK_NAME12}] Skipped: max consecutive failures reached`, {
56994
+ log(`[${HOOK_NAME13}] Skipped: max consecutive failures reached`, {
56201
56995
  sessionID,
56202
56996
  consecutiveFailures: state3.consecutiveFailures,
56203
56997
  maxConsecutiveFailures: MAX_CONSECUTIVE_FAILURES
@@ -56206,7 +57000,7 @@ async function handleSessionIdle(args) {
56206
57000
  }
56207
57001
  const effectiveCooldown = CONTINUATION_COOLDOWN_MS2 * 2 ** Math.min(state3.consecutiveFailures, 5);
56208
57002
  if (state3.lastInjectedAt && Date.now() - state3.lastInjectedAt < effectiveCooldown) {
56209
- log(`[${HOOK_NAME12}] Skipped: cooldown active`, {
57003
+ log(`[${HOOK_NAME13}] Skipped: cooldown active`, {
56210
57004
  sessionID,
56211
57005
  effectiveCooldown,
56212
57006
  consecutiveFailures: state3.consecutiveFailures
@@ -56236,20 +57030,20 @@ async function handleSessionIdle(args) {
56236
57030
  }
56237
57031
  }
56238
57032
  } catch (error51) {
56239
- log(`[${HOOK_NAME12}] Failed to fetch messages for agent check`, { sessionID, error: String(error51) });
57033
+ log(`[${HOOK_NAME13}] Failed to fetch messages for agent check`, { sessionID, error: String(error51) });
56240
57034
  }
56241
- log(`[${HOOK_NAME12}] Agent check`, { sessionID, agentName: resolvedInfo?.agent, skipAgents, hasCompactionMessage });
57035
+ log(`[${HOOK_NAME13}] Agent check`, { sessionID, agentName: resolvedInfo?.agent, skipAgents, hasCompactionMessage });
56242
57036
  const resolvedAgentName = resolvedInfo?.agent;
56243
57037
  if (resolvedAgentName && skipAgents.some((s) => getAgentConfigKey(s) === getAgentConfigKey(resolvedAgentName))) {
56244
- log(`[${HOOK_NAME12}] Skipped: agent in skipAgents list`, { sessionID, agent: resolvedAgentName });
57038
+ log(`[${HOOK_NAME13}] Skipped: agent in skipAgents list`, { sessionID, agent: resolvedAgentName });
56245
57039
  return;
56246
57040
  }
56247
57041
  if (hasCompactionMessage && !resolvedInfo?.agent) {
56248
- log(`[${HOOK_NAME12}] Skipped: compaction occurred but no agent info resolved`, { sessionID });
57042
+ log(`[${HOOK_NAME13}] Skipped: compaction occurred but no agent info resolved`, { sessionID });
56249
57043
  return;
56250
57044
  }
56251
57045
  if (isContinuationStopped?.(sessionID)) {
56252
- log(`[${HOOK_NAME12}] Skipped: continuation stopped for session`, { sessionID });
57046
+ log(`[${HOOK_NAME13}] Skipped: continuation stopped for session`, { sessionID });
56253
57047
  return;
56254
57048
  }
56255
57049
  startCountdown({
@@ -56279,7 +57073,7 @@ function handleNonIdleEvent(args) {
56279
57073
  if (state3?.countdownStartedAt) {
56280
57074
  const elapsed = Date.now() - state3.countdownStartedAt;
56281
57075
  if (elapsed < COUNTDOWN_GRACE_PERIOD_MS) {
56282
- log(`[${HOOK_NAME12}] Ignoring user message in grace period`, { sessionID, elapsed });
57076
+ log(`[${HOOK_NAME13}] Ignoring user message in grace period`, { sessionID, elapsed });
56283
57077
  return;
56284
57078
  }
56285
57079
  }
@@ -56323,7 +57117,7 @@ function handleNonIdleEvent(args) {
56323
57117
  const sessionInfo = properties?.info;
56324
57118
  if (sessionInfo?.id) {
56325
57119
  sessionStateStore.cleanup(sessionInfo.id);
56326
- log(`[${HOOK_NAME12}] Session deleted: cleaned up`, { sessionID: sessionInfo.id });
57120
+ log(`[${HOOK_NAME13}] Session deleted: cleaned up`, { sessionID: sessionInfo.id });
56327
57121
  }
56328
57122
  return;
56329
57123
  }
@@ -56348,10 +57142,10 @@ function createTodoContinuationHandler(args) {
56348
57142
  if (error51?.name === "MessageAbortedError" || error51?.name === "AbortError") {
56349
57143
  const state3 = sessionStateStore.getState(sessionID);
56350
57144
  state3.abortDetectedAt = Date.now();
56351
- log(`[${HOOK_NAME12}] Abort detected via session.error`, { sessionID, errorName: error51.name });
57145
+ log(`[${HOOK_NAME13}] Abort detected via session.error`, { sessionID, errorName: error51.name });
56352
57146
  }
56353
57147
  sessionStateStore.cancelCountdown(sessionID);
56354
- log(`[${HOOK_NAME12}] session.error`, { sessionID });
57148
+ log(`[${HOOK_NAME13}] session.error`, { sessionID });
56355
57149
  return;
56356
57150
  }
56357
57151
  if (event.type === "session.idle") {
@@ -56466,13 +57260,13 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
56466
57260
  const state3 = sessionStateStore.getState(sessionID);
56467
57261
  state3.isRecovering = true;
56468
57262
  sessionStateStore.cancelCountdown(sessionID);
56469
- log(`[${HOOK_NAME12}] Session marked as recovering`, { sessionID });
57263
+ log(`[${HOOK_NAME13}] Session marked as recovering`, { sessionID });
56470
57264
  };
56471
57265
  const markRecoveryComplete = (sessionID) => {
56472
57266
  const state3 = sessionStateStore.getExistingState(sessionID);
56473
57267
  if (state3) {
56474
57268
  state3.isRecovering = false;
56475
- log(`[${HOOK_NAME12}] Session recovery complete`, { sessionID });
57269
+ log(`[${HOOK_NAME13}] Session recovery complete`, { sessionID });
56476
57270
  }
56477
57271
  };
56478
57272
  const handler = createTodoContinuationHandler({
@@ -56484,7 +57278,7 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
56484
57278
  });
56485
57279
  const cancelAllCountdowns = () => {
56486
57280
  sessionStateStore.cancelAllCountdowns();
56487
- log(`[${HOOK_NAME12}] All countdowns cancelled`);
57281
+ log(`[${HOOK_NAME13}] All countdowns cancelled`);
56488
57282
  };
56489
57283
  return {
56490
57284
  handler,
@@ -56744,7 +57538,7 @@ This is a reminder only. No automatic action was taken.`;
56744
57538
  }
56745
57539
  // src/hooks/unstable-agent-babysitter/unstable-agent-babysitter-hook.ts
56746
57540
  init_logger();
56747
- var HOOK_NAME13 = "unstable-agent-babysitter";
57541
+ var HOOK_NAME14 = "unstable-agent-babysitter";
56748
57542
  var DEFAULT_TIMEOUT_MS = 120000;
56749
57543
  var COOLDOWN_MS = 5 * 60 * 1000;
56750
57544
  async function resolveMainSessionTarget(ctx, sessionID) {
@@ -56764,7 +57558,7 @@ async function resolveMainSessionTarget(ctx, sessionID) {
56764
57558
  }
56765
57559
  }
56766
57560
  } catch (error51) {
56767
- log(`[${HOOK_NAME13}] Failed to resolve main session agent`, { sessionID, error: String(error51) });
57561
+ log(`[${HOOK_NAME14}] Failed to resolve main session agent`, { sessionID, error: String(error51) });
56768
57562
  }
56769
57563
  return { agent, model };
56770
57564
  }
@@ -56797,7 +57591,7 @@ async function getThinkingSummary(ctx, sessionID) {
56797
57591
  return combined;
56798
57592
  return `${combined.slice(0, THINKING_SUMMARY_MAX_CHARS)}...`;
56799
57593
  } catch (error51) {
56800
- log(`[${HOOK_NAME13}] Failed to fetch thinking summary`, { sessionID, error: String(error51) });
57594
+ log(`[${HOOK_NAME14}] Failed to fetch thinking summary`, { sessionID, error: String(error51) });
56801
57595
  return null;
56802
57596
  }
56803
57597
  }
@@ -56846,9 +57640,9 @@ function createUnstableAgentBabysitterHook(ctx, options) {
56846
57640
  query: { directory: ctx.directory }
56847
57641
  });
56848
57642
  reminderCooldowns.set(task.id, now);
56849
- log(`[${HOOK_NAME13}] Reminder injected`, { taskId: task.id, sessionID: mainSessionID });
57643
+ log(`[${HOOK_NAME14}] Reminder injected`, { taskId: task.id, sessionID: mainSessionID });
56850
57644
  } catch (error51) {
56851
- log(`[${HOOK_NAME13}] Reminder injection failed`, { taskId: task.id, error: String(error51) });
57645
+ log(`[${HOOK_NAME14}] Reminder injection failed`, { taskId: task.id, error: String(error51) });
56852
57646
  }
56853
57647
  }
56854
57648
  };
@@ -57014,8 +57808,8 @@ function createWriteExistingFileGuardHook(ctx) {
57014
57808
  }
57015
57809
  const resolvedPath = normalize(isAbsolute5(filePath) ? filePath : resolve7(ctx.directory, filePath));
57016
57810
  if (existsSync40(resolvedPath)) {
57017
- const sisyphusRoot = join55(ctx.directory, ".matrixx") + sep;
57018
- const isMatrixMarkdown = resolvedPath.startsWith(sisyphusRoot) && resolvedPath.endsWith(".md");
57811
+ const matrixxRoot = join55(ctx.directory, ".matrixx") + sep;
57812
+ const isMatrixMarkdown = resolvedPath.startsWith(matrixxRoot) && resolvedPath.endsWith(".md");
57019
57813
  if (isMatrixMarkdown) {
57020
57814
  log("[write-existing-file-guard] Allowing .matrixx/*.md overwrite", {
57021
57815
  sessionID: input.sessionID,
@@ -57103,7 +57897,7 @@ function createContinuationHooks(args) {
57103
57897
  }
57104
57898
  }
57105
57899
  const backgroundNotificationHook = isHookEnabled("background-notification") ? safeHook("background-notification", () => createBackgroundNotificationHook(backgroundManager)) : null;
57106
- const atlasHook = isHookEnabled("architect") ? safeHook("architect", () => createAtlasHook(ctx, {
57900
+ const architectHook = isHookEnabled("architect") ? safeHook("architect", () => createArchitectHook(ctx, {
57107
57901
  directory: ctx.directory,
57108
57902
  backgroundManager,
57109
57903
  isContinuationStopped: (sessionID) => stopContinuationGuard?.isStopped(sessionID) ?? false,
@@ -57116,7 +57910,7 @@ function createContinuationHooks(args) {
57116
57910
  todoContinuationEnforcer,
57117
57911
  unstableAgentBabysitter,
57118
57912
  backgroundNotificationHook,
57119
- atlasHook
57913
+ architectHook
57120
57914
  };
57121
57915
  }
57122
57916
 
@@ -58105,12 +58899,18 @@ class LSPClient extends LSPClientConnection {
58105
58899
  });
58106
58900
  }
58107
58901
  }
58902
+ // src/tools/lsp/lsp-server.ts
58903
+ init_logger();
58904
+
58108
58905
  // src/tools/lsp/lsp-manager-process-cleanup.ts
58906
+ init_logger();
58109
58907
  function registerLspManagerProcessCleanup(options) {
58110
58908
  const syncCleanup = () => {
58111
58909
  for (const [, managed] of options.getClients()) {
58112
58910
  try {
58113
- managed.client.stop().catch(() => {});
58911
+ managed.client.stop().catch((err) => {
58912
+ log("[lsp] Sync cleanup failed:", err);
58913
+ });
58114
58914
  } catch {}
58115
58915
  }
58116
58916
  options.clearClients();
@@ -58119,17 +58919,26 @@ function registerLspManagerProcessCleanup(options) {
58119
58919
  const asyncCleanup = async () => {
58120
58920
  const stopPromises = [];
58121
58921
  for (const [, managed] of options.getClients()) {
58122
- stopPromises.push(managed.client.stop().catch(() => {}));
58922
+ stopPromises.push(managed.client.stop().catch((err) => {
58923
+ log("[lsp] Async cleanup failed:", err);
58924
+ return;
58925
+ }));
58123
58926
  }
58124
58927
  await Promise.allSettled(stopPromises);
58125
58928
  options.clearClients();
58126
58929
  options.clearCleanupInterval();
58127
58930
  };
58128
58931
  process.on("exit", syncCleanup);
58129
- process.on("SIGINT", () => void asyncCleanup().catch(() => {}));
58130
- process.on("SIGTERM", () => void asyncCleanup().catch(() => {}));
58932
+ process.on("SIGINT", () => void asyncCleanup().catch((err) => {
58933
+ log("[lsp] Signal handler cleanup failed:", err);
58934
+ }));
58935
+ process.on("SIGTERM", () => void asyncCleanup().catch((err) => {
58936
+ log("[lsp] Signal handler cleanup failed:", err);
58937
+ }));
58131
58938
  if (process.platform === "win32") {
58132
- process.on("SIGBREAK", () => void asyncCleanup().catch(() => {}));
58939
+ process.on("SIGBREAK", () => void asyncCleanup().catch((err) => {
58940
+ log("[lsp] Signal handler cleanup failed:", err);
58941
+ }));
58133
58942
  }
58134
58943
  }
58135
58944
 
@@ -58299,7 +59108,9 @@ class LSPServerManager {
58299
59108
  }
58300
59109
  }).catch(() => {
58301
59110
  this.clients.delete(key);
58302
- client.stop().catch(() => {});
59111
+ client.stop().catch((err) => {
59112
+ log("[lsp] Warmup client stop failed:", err);
59113
+ });
58303
59114
  });
58304
59115
  }
58305
59116
  releaseClient(root, serverId) {
@@ -71157,6 +71968,7 @@ import { existsSync as existsSync48 } from "fs";
71157
71968
  var {spawn: spawn9 } = globalThis.Bun;
71158
71969
 
71159
71970
  // src/tools/ast-grep/cli-binary-path-resolution.ts
71971
+ init_logger();
71160
71972
  import { existsSync as existsSync47 } from "fs";
71161
71973
 
71162
71974
  // src/tools/ast-grep/language-support.ts
@@ -72783,6 +73595,9 @@ function createHandoffTools(ctx) {
72783
73595
  });
72784
73596
  return { handoff };
72785
73597
  }
73598
+ // src/tools/interactive-bash/tools.ts
73599
+ init_logger();
73600
+
72786
73601
  // src/tools/interactive-bash/constants.ts
72787
73602
  var DEFAULT_TIMEOUT_MS5 = 60000;
72788
73603
  var BLOCKED_TMUX_SUBCOMMANDS = [
@@ -72884,7 +73699,9 @@ The Bash tool can execute these commands directly. Do NOT retry with interactive
72884
73699
  const timeoutError = new Error(`Timeout after ${DEFAULT_TIMEOUT_MS5}ms`);
72885
73700
  try {
72886
73701
  proc.kill();
72887
- proc.exited.catch(() => {});
73702
+ proc.exited.catch((err) => {
73703
+ log("[interactive-bash] Process cleanup failed:", err);
73704
+ });
72888
73705
  } catch {}
72889
73706
  reject(timeoutError);
72890
73707
  }, DEFAULT_TIMEOUT_MS5);
@@ -74591,7 +75408,7 @@ ${textContent || "(No text output)"}`;
74591
75408
  }
74592
75409
 
74593
75410
  // src/tools/background-task/create-background-output.ts
74594
- var SISYPHUS_JUNIOR_AGENT = getAgentDisplayName("mouse");
75411
+ var MOUSE_AGENT = getAgentDisplayName("mouse");
74595
75412
  function resolveToolCallID(ctx) {
74596
75413
  if (typeof ctx.callID === "string" && ctx.callID.trim() !== "")
74597
75414
  return ctx.callID;
@@ -74602,7 +75419,7 @@ function resolveToolCallID(ctx) {
74602
75419
  return;
74603
75420
  }
74604
75421
  function formatResolvedTitle(task) {
74605
- const label = task.agent === SISYPHUS_JUNIOR_AGENT && task.category ? task.category : task.agent;
75422
+ const label = task.agent === MOUSE_AGENT && task.category ? task.category : task.agent;
74606
75423
  return `${label} - ${task.description}`;
74607
75424
  }
74608
75425
  function isTaskActiveStatus(status) {
@@ -74713,6 +75530,376 @@ function createBackgroundOutput(manager, client2) {
74713
75530
  }
74714
75531
  // src/tools/background-task/create-background-task.ts
74715
75532
  init_logger();
75533
+ // src/tools/assembly/constants.ts
75534
+ var DEFAULT_VOTERS = 3;
75535
+ var DEFAULT_ROUNDS = 2;
75536
+ var VOTER_TIMEOUT_MS = 120000;
75537
+ var POLL_INTERVAL_MS = 1000;
75538
+ var DEFAULT_PROVIDERS = [
75539
+ { providerID: "anthropic", modelID: "claude-sonnet-4-20250514" },
75540
+ { providerID: "openai", modelID: "gpt-4o" },
75541
+ { providerID: "google", modelID: "gemini-2.5-pro" }
75542
+ ];
75543
+
75544
+ // src/tools/assembly/provider-selector.ts
75545
+ function selectProviders(count, modelsOverride, config4) {
75546
+ if (modelsOverride && modelsOverride.length > 0) {
75547
+ return modelsOverride.slice(0, count).map((m) => {
75548
+ const parts = m.split(":");
75549
+ if (parts.length >= 2) {
75550
+ return { providerID: parts[0], modelID: parts.slice(1).join(":") };
75551
+ }
75552
+ return { providerID: "custom", modelID: m };
75553
+ });
75554
+ }
75555
+ const configuredProviders = config4?.providers ?? DEFAULT_PROVIDERS;
75556
+ if (configuredProviders.length === 0) {
75557
+ return DEFAULT_PROVIDERS.slice(0, count);
75558
+ }
75559
+ if (configuredProviders.length <= count) {
75560
+ return configuredProviders;
75561
+ }
75562
+ const selected = [];
75563
+ const usedProviderIds = new Set;
75564
+ for (const p of configuredProviders) {
75565
+ if (selected.length >= count)
75566
+ break;
75567
+ if (!usedProviderIds.has(p.providerID)) {
75568
+ selected.push(p);
75569
+ usedProviderIds.add(p.providerID);
75570
+ }
75571
+ }
75572
+ if (selected.length < count) {
75573
+ for (const p of configuredProviders) {
75574
+ if (selected.length >= count)
75575
+ break;
75576
+ if (!selected.includes(p)) {
75577
+ selected.push(p);
75578
+ }
75579
+ }
75580
+ }
75581
+ return selected;
75582
+ }
75583
+
75584
+ // src/tools/assembly/synthesizer.ts
75585
+ async function synthesizeResults(manager, question, voterResults, round, parentSessionID, parentMessageID) {
75586
+ const voterContext = voterResults.map((v, i) => `--- Voter ${i + 1} (${v.modelLabel}) ---
75587
+ Status: ${v.status}
75588
+ ${v.status === "completed" ? v.reasoning : `Error: ${v.error}`}`).join(`
75589
+
75590
+ `);
75591
+ const synthesisPrompt = `You are the synthesis agent. Multiple AI voters have independently analyzed a question. Your task is to synthesize their reasoning into a unified consensus.
75592
+
75593
+ ## Question
75594
+ ${question}
75595
+
75596
+ ## Voter Analyses
75597
+ ${voterContext}
75598
+
75599
+ ## Synthesis Round
75600
+ This is round #${round}.
75601
+
75602
+ ## Your Task
75603
+ 1. Identify points of agreement across all voters
75604
+ 2. Identify points of disagreement or divergence
75605
+ 3. Weigh the strength of evidence and reasoning from each
75606
+ 4. Produce a unified consensus with confidence level
75607
+
75608
+ ## Output Format
75609
+ ## Consensus
75610
+ [Your unified answer/conclusion]
75611
+
75612
+ ## Confidence Level
75613
+ [High/Medium/Low - with rationale]
75614
+
75615
+ ## Key Agreements
75616
+ - [Point 1]
75617
+ - [Point 2]
75618
+
75619
+ ## Key Disagreements
75620
+ - [Point 1]
75621
+ - [Point 2]
75622
+ `;
75623
+ const synthesisTask = await manager.launch({
75624
+ description: `Assembly synthesis round ${round}`,
75625
+ prompt: synthesisPrompt,
75626
+ agent: "mouse",
75627
+ parentSessionID,
75628
+ parentMessageID,
75629
+ model: {
75630
+ providerID: "anthropic",
75631
+ modelID: "claude-sonnet-4-20250514",
75632
+ temperature: 0.1
75633
+ }
75634
+ });
75635
+ const deadline = Date.now() + 120000;
75636
+ while (Date.now() < deadline) {
75637
+ const current = manager.getTask(synthesisTask.id);
75638
+ if (!current)
75639
+ break;
75640
+ if (current.status === "completed") {
75641
+ return parseSynthesis(current.result ?? "", round);
75642
+ }
75643
+ if (current.status === "error" || current.status === "cancelled" || current.status === "interrupt") {
75644
+ return {
75645
+ round,
75646
+ consensus: `Synthesis failed: ${current.error ?? "Unknown"}`,
75647
+ confidence: "low",
75648
+ disagreements: voterResults.filter((v) => v.status === "completed").map((v) => v.modelLabel)
75649
+ };
75650
+ }
75651
+ await delay4(POLL_INTERVAL_MS);
75652
+ }
75653
+ return {
75654
+ round,
75655
+ consensus: "Synthesis timed out",
75656
+ confidence: "low",
75657
+ disagreements: voterResults.filter((v) => v.status === "completed").map((v) => v.modelLabel)
75658
+ };
75659
+ }
75660
+ function parseSynthesis(text, round) {
75661
+ const confidenceMatch = text.match(/## Confidence Level\s*\n([^\n]+)/);
75662
+ const confidenceRaw = (confidenceMatch?.[1] ?? "medium").toLowerCase();
75663
+ const confidence = confidenceRaw.includes("high") ? "high" : confidenceRaw.includes("low") ? "low" : "medium";
75664
+ const consensusMatch = text.match(/## Consensus\s*\n([\s\S]*?)(?=\n## Confidence Level|\n## Key Agreements|\n$)/);
75665
+ const consensus = consensusMatch?.[1]?.trim() ?? text;
75666
+ const disagreements = [];
75667
+ const disagreementsMatch = text.match(/## Key Disagreements\s*\n([\s\S]*?)(?=\n## |$)/);
75668
+ if (disagreementsMatch) {
75669
+ const lines = disagreementsMatch[1].trim().split(`
75670
+ `);
75671
+ for (const line of lines) {
75672
+ const trimmed = line.replace(/^[-*]\s*/, "").trim();
75673
+ if (trimmed)
75674
+ disagreements.push(trimmed);
75675
+ }
75676
+ }
75677
+ return { round, consensus, confidence, disagreements };
75678
+ }
75679
+ function delay4(ms) {
75680
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
75681
+ }
75682
+
75683
+ // src/tools/assembly/voter-spawner.ts
75684
+ async function spawnVoters(manager, question, providers, parentSessionID, parentMessageID) {
75685
+ const tasks = providers.map((provider, index) => manager.launch({
75686
+ description: `Assembly voter ${index + 1}`,
75687
+ prompt: `You are voter #${index + 1} in a multi-model assembly process. Analyze the following question independently and provide your reasoning. Be thorough and consider multiple angles.
75688
+
75689
+ Question: ${question}
75690
+
75691
+ Output your analysis in this format:
75692
+ ## Reasoning
75693
+ [Your detailed step-by-step reasoning]
75694
+
75695
+ ## Conclusion
75696
+ [Your final answer/conclusion]
75697
+
75698
+ ## Confidence
75699
+ [High/Medium/Low - with justification]`,
75700
+ agent: "mouse",
75701
+ parentSessionID,
75702
+ parentMessageID,
75703
+ model: {
75704
+ providerID: provider.providerID,
75705
+ modelID: provider.modelID,
75706
+ temperature: 0.3
75707
+ }
75708
+ }));
75709
+ const launchedTasks = await Promise.all(tasks);
75710
+ const results = await Promise.all(launchedTasks.map(async (task, index) => {
75711
+ const provider = providers[index];
75712
+ const deadline = Date.now() + VOTER_TIMEOUT_MS;
75713
+ while (Date.now() < deadline) {
75714
+ const current = manager.getTask(task.id);
75715
+ if (!current)
75716
+ break;
75717
+ if (current.status === "completed") {
75718
+ return {
75719
+ voterIndex: index,
75720
+ modelLabel: `${provider.providerID}:${provider.modelID}`,
75721
+ reasoning: current.result ?? "",
75722
+ status: "completed"
75723
+ };
75724
+ }
75725
+ if (current.status === "error") {
75726
+ return {
75727
+ voterIndex: index,
75728
+ modelLabel: `${provider.providerID}:${provider.modelID}`,
75729
+ reasoning: "",
75730
+ status: "error",
75731
+ error: current.error ?? "Unknown error"
75732
+ };
75733
+ }
75734
+ if (current.status === "cancelled" || current.status === "interrupt") {
75735
+ return {
75736
+ voterIndex: index,
75737
+ modelLabel: `${provider.providerID}:${provider.modelID}`,
75738
+ reasoning: "",
75739
+ status: "error",
75740
+ error: `Voter ${index + 1} was ${current.status}`
75741
+ };
75742
+ }
75743
+ await delay5(POLL_INTERVAL_MS);
75744
+ }
75745
+ return {
75746
+ voterIndex: index,
75747
+ modelLabel: `${provider.providerID}:${provider.modelID}`,
75748
+ reasoning: "",
75749
+ status: "timeout",
75750
+ error: `Voter ${index + 1} timed out after ${VOTER_TIMEOUT_MS}ms`
75751
+ };
75752
+ }));
75753
+ return results;
75754
+ }
75755
+ function delay5(ms) {
75756
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
75757
+ }
75758
+
75759
+ // src/tools/assembly/assembly-executor.ts
75760
+ async function executeAssembly(input) {
75761
+ const { manager, args, config: config4, sessionID, messageID } = input;
75762
+ const voterCount = args.voters ?? config4?.default_voters ?? DEFAULT_VOTERS;
75763
+ const roundCount = args.rounds ?? config4?.default_rounds ?? DEFAULT_ROUNDS;
75764
+ const providers = selectProviders(voterCount, args.models, config4);
75765
+ let currentVoterResults = [];
75766
+ const synthesisRounds = [];
75767
+ for (let round = 0;round < roundCount; round++) {
75768
+ if (round === 0) {
75769
+ currentVoterResults = await spawnVoters(manager, args.question, providers, sessionID, messageID);
75770
+ }
75771
+ const synthesis = await synthesizeResults(manager, args.question, currentVoterResults, round + 1, sessionID, messageID);
75772
+ synthesisRounds.push(synthesis);
75773
+ if (synthesis.confidence === "high" && round < roundCount - 1) {
75774
+ break;
75775
+ }
75776
+ if (round < roundCount - 1) {
75777
+ currentVoterResults = currentVoterResults.map((v, _i) => ({
75778
+ ...v,
75779
+ reasoning: `${v.reasoning}
75780
+
75781
+ --- Round ${round + 1} Synthesis Feedback ---
75782
+ ${synthesis.consensus}`
75783
+ }));
75784
+ }
75785
+ }
75786
+ const finalSynthesis = synthesisRounds[synthesisRounds.length - 1];
75787
+ return {
75788
+ question: args.question,
75789
+ voters: currentVoterResults,
75790
+ rounds: synthesisRounds,
75791
+ finalConsensus: formatFinalConsensus(args.question, finalSynthesis, currentVoterResults)
75792
+ };
75793
+ }
75794
+ function formatFinalConsensus(question, final, voterResults) {
75795
+ const completed = voterResults.filter((v) => v.status === "completed");
75796
+ const errored = voterResults.filter((v) => v.status !== "completed");
75797
+ let output = `# Assembly Result
75798
+
75799
+ `;
75800
+ output += `**Question**: ${question}
75801
+ `;
75802
+ output += `**Confidence**: ${final.confidence}
75803
+ `;
75804
+ output += `**Voters**: ${completed.length}/${voterResults.length} completed`;
75805
+ if (errored.length > 0) {
75806
+ output += ` (${errored.map((v) => `${v.voterIndex + 1}: ${v.error}`).join(", ")})`;
75807
+ }
75808
+ output += `
75809
+
75810
+ ## Final Consensus
75811
+
75812
+ ${final.consensus}
75813
+
75814
+ `;
75815
+ if (final.disagreements.length > 0) {
75816
+ output += `## Disagreements
75817
+
75818
+ `;
75819
+ for (const d of final.disagreements) {
75820
+ output += `- ${d}
75821
+ `;
75822
+ }
75823
+ output += `
75824
+ `;
75825
+ }
75826
+ output += `## Per-Voter Reasoning
75827
+
75828
+ `;
75829
+ for (const v of voterResults) {
75830
+ output += `### Voter ${v.voterIndex + 1} (${v.modelLabel})
75831
+ `;
75832
+ output += `Status: ${v.status}
75833
+ `;
75834
+ if (v.status === "completed") {
75835
+ output += `
75836
+ ${v.reasoning}
75837
+
75838
+ `;
75839
+ } else {
75840
+ output += `Error: ${v.error}
75841
+
75842
+ `;
75843
+ }
75844
+ }
75845
+ return output;
75846
+ }
75847
+
75848
+ // src/tools/assembly/tool-description.ts
75849
+ var TOOL_DESCRIPTION = `
75850
+ Spawns multiple AI agents (voters) with different model providers to independently analyze a question or decision, then synthesizes their reasoning into a unified consensus.
75851
+
75852
+ ## When to use
75853
+ - Making critical decisions that benefit from multiple perspectives
75854
+ - Evaluating complex tradeoffs where bias reduction matters
75855
+ - Validating architectural choices through multi-model reasoning
75856
+ - When you need confidence scoring on analysis
75857
+
75858
+ ## How it works
75859
+ 1. **Voter selection**: Auto-selects N models from configured providers (or use your override)
75860
+ 2. **Independent voting**: Each voter independently analyzes the question
75861
+ 3. **Synthesis**: All voter outputs are fed to a synthesis round that identifies agreement, disagreement, and confidence
75862
+ 4. **Multi-round**: Optionally repeat synthesis for deeper convergence
75863
+
75864
+ ## Output format
75865
+ Returns a structured consensus with:
75866
+ - Unified answer/conclusion
75867
+ - Confidence level (high/medium/low)
75868
+ - Key disagreements between voters
75869
+ - Per-voter reasoning traces
75870
+ `;
75871
+
75872
+ // src/tools/assembly/types.ts
75873
+ var AssemblyArgsSchema = exports_external.object({
75874
+ question: exports_external.string().min(1).describe("The question or decision to reach consensus on"),
75875
+ voters: exports_external.number().int().min(2).max(5).optional().describe("Number of voters (default: 3)"),
75876
+ rounds: exports_external.number().int().min(1).max(3).optional().describe("Number of synthesis rounds (default: 2)"),
75877
+ models: exports_external.array(exports_external.string()).optional().describe("Override auto-selected models (e.g., ['anthropic:claude-sonnet-4-20250514', 'openai:gpt-4o'])")
75878
+ });
75879
+
75880
+ // src/tools/assembly/tools.ts
75881
+ function createAssemblyTool(options) {
75882
+ return tool({
75883
+ description: TOOL_DESCRIPTION,
75884
+ args: {
75885
+ question: tool.schema.string().describe("The question or decision to reach consensus on"),
75886
+ voters: tool.schema.number().optional().describe("Number of voters (2-5, default: 3)"),
75887
+ rounds: tool.schema.number().optional().describe("Number of synthesis rounds (1-3, default: 2)"),
75888
+ models: tool.schema.array(tool.schema.string()).optional().describe("Override auto-selected models")
75889
+ },
75890
+ async execute(args, toolContext) {
75891
+ const parsed = AssemblyArgsSchema.parse(args);
75892
+ const output = await executeAssembly({
75893
+ manager: options.manager,
75894
+ args: parsed,
75895
+ config: options.pluginConfig?.assembly,
75896
+ sessionID: toolContext.sessionID,
75897
+ messageID: toolContext.messageID
75898
+ });
75899
+ return output.finalConsensus;
75900
+ }
75901
+ });
75902
+ }
74716
75903
  // src/tools/delegate-agent/constants.ts
74717
75904
  var ALLOWED_AGENTS = [
74718
75905
  "trinity",
@@ -74812,7 +75999,7 @@ Use \`background_output\` tool with task_id="${task.id}" to check progress:
74812
75999
  // src/tools/delegate-agent/completion-poller.ts
74813
76000
  async function waitForCompletion(sessionID, toolContext, ctx) {
74814
76001
  log(`[delegate_agent] Polling for completion...`);
74815
- const POLL_INTERVAL_MS = 500;
76002
+ const POLL_INTERVAL_MS2 = 500;
74816
76003
  const MAX_POLL_TIME_MS = 5 * 60 * 1000;
74817
76004
  const pollStart = Date.now();
74818
76005
  let lastMsgCount = 0;
@@ -74823,7 +76010,7 @@ async function waitForCompletion(sessionID, toolContext, ctx) {
74823
76010
  log(`[delegate_agent] Aborted by user`);
74824
76011
  throw new Error("Task aborted.");
74825
76012
  }
74826
- await new Promise((resolve10) => setTimeout(resolve10, POLL_INTERVAL_MS));
76013
+ await new Promise((resolve10) => setTimeout(resolve10, POLL_INTERVAL_MS2));
74827
76014
  const statusResult = await ctx.client.session.status();
74828
76015
  const allStatuses = normalizeSDKResponse(statusResult, {});
74829
76016
  const sessionStatus = allStatuses[sessionID];
@@ -75117,7 +76304,7 @@ ${task.agent ? `subagent: ${task.agent}
75117
76304
  }
75118
76305
  }
75119
76306
  // src/tools/delegate-task/timing.ts
75120
- var POLL_INTERVAL_MS = 1000;
76307
+ var POLL_INTERVAL_MS2 = 1000;
75121
76308
  var MIN_STABILITY_TIME_MS = 1e4;
75122
76309
  var STABILITY_POLLS_REQUIRED = 3;
75123
76310
  var WAIT_FOR_SESSION_INTERVAL_MS = 100;
@@ -75126,7 +76313,7 @@ var MAX_POLL_TIME_MS = 10 * 60 * 1000;
75126
76313
  var SESSION_CONTINUATION_STABILITY_MS = 5000;
75127
76314
  function getTimingConfig() {
75128
76315
  return {
75129
- POLL_INTERVAL_MS,
76316
+ POLL_INTERVAL_MS: POLL_INTERVAL_MS2,
75130
76317
  MIN_STABILITY_TIME_MS,
75131
76318
  STABILITY_POLLS_REQUIRED,
75132
76319
  WAIT_FOR_SESSION_INTERVAL_MS,
@@ -75370,11 +76557,11 @@ function parseModelString2(model) {
75370
76557
  }
75371
76558
 
75372
76559
  // src/tools/delegate-task/mouse-agent.ts
75373
- var SISYPHUS_JUNIOR_AGENT2 = "mouse";
76560
+ var MOUSE_AGENT2 = "mouse";
75374
76561
 
75375
76562
  // src/tools/delegate-task/category-resolver.ts
75376
76563
  async function resolveCategoryExecution(args, executorCtx, inheritedModel, systemDefaultModel) {
75377
- const { client: client2, userCategories, sisyphusJuniorModel } = executorCtx;
76564
+ const { client: client2, userCategories, mouseModel } = executorCtx;
75378
76565
  const availableModels = await getAvailableModelsForDelegateTask(client2);
75379
76566
  const categoryName = args.category;
75380
76567
  const enabledCategories = mergeCategories(userCategories);
@@ -75419,16 +76606,16 @@ Available categories: ${allCategoryNames}`
75419
76606
  let actualModel;
75420
76607
  let modelInfo;
75421
76608
  let categoryModel;
75422
- const overrideModel = sisyphusJuniorModel;
76609
+ const overrideModel = mouseModel;
75423
76610
  const explicitCategoryModel = userCategories?.[args.category]?.model;
75424
76611
  if (!requirement) {
75425
- actualModel = explicitCategoryModel ?? overrideModel ?? resolved.model;
76612
+ actualModel = explicitCategoryModel ?? resolved.model ?? overrideModel;
75426
76613
  if (actualModel) {
75427
- modelInfo = explicitCategoryModel || overrideModel ? { model: actualModel, type: "user-defined", source: "override" } : { model: actualModel, type: "system-default", source: "system-default" };
76614
+ modelInfo = explicitCategoryModel ? { model: actualModel, type: "user-defined", source: "override" } : resolved.model ? { model: actualModel, type: "system-default", source: "system-default" } : { model: actualModel, type: "user-defined", source: "override" };
75428
76615
  }
75429
76616
  } else {
75430
76617
  const resolution = resolveModelForDelegateTask({
75431
- userModel: explicitCategoryModel ?? overrideModel,
76618
+ userModel: explicitCategoryModel,
75432
76619
  categoryDefaultModel: resolved.model,
75433
76620
  fallbackChain: requirement.fallbackChain,
75434
76621
  availableModels,
@@ -75448,7 +76635,7 @@ Available categories: ${allCategoryNames}`
75448
76635
  error: `Invalid model format "${actualModel}". Expected "provider/model" format (e.g., "anthropic/claude-sonnet-4-5").`
75449
76636
  };
75450
76637
  }
75451
- const type = explicitCategoryModel || overrideModel ? "user-defined" : systemDefaultModel && actualModel === systemDefaultModel ? "system-default" : "category-default";
76638
+ const type = explicitCategoryModel ? "user-defined" : systemDefaultModel && actualModel === systemDefaultModel ? "system-default" : "category-default";
75452
76639
  const source = type === "user-defined" ? "override" : type === "system-default" ? "system-default" : "category-default";
75453
76640
  modelInfo = { model: actualModel, type, source };
75454
76641
  const parsedModel = parseModelString2(actualModel);
@@ -75484,7 +76671,7 @@ Available categories: ${categoryNames.join(", ")}`
75484
76671
  const unstableModel = actualModel?.toLowerCase();
75485
76672
  const isUnstableAgent = resolved.config.is_unstable_agent === true || (unstableModel ? unstableModel.includes("gemini") || unstableModel.includes("minimax") : false);
75486
76673
  return {
75487
- agentToUse: SISYPHUS_JUNIOR_AGENT2,
76674
+ agentToUse: MOUSE_AGENT2,
75488
76675
  categoryModel,
75489
76676
  categoryPromptAppend,
75490
76677
  modelInfo,
@@ -75544,11 +76731,11 @@ async function resolveSubagentExecution(args, executorCtx, parentAgent, category
75544
76731
  return { agentToUse: "", categoryModel: undefined, error: `Agent name cannot be empty.` };
75545
76732
  }
75546
76733
  const agentName = args.subagent_type.trim();
75547
- if (agentName.toLowerCase() === SISYPHUS_JUNIOR_AGENT2.toLowerCase()) {
76734
+ if (agentName.toLowerCase() === MOUSE_AGENT2.toLowerCase()) {
75548
76735
  return {
75549
76736
  agentToUse: "",
75550
76737
  categoryModel: undefined,
75551
- error: `Cannot use subagent_type="${SISYPHUS_JUNIOR_AGENT2}" directly. Use category parameter instead (e.g., ${categoryExamples}).
76738
+ error: `Cannot use subagent_type="${MOUSE_AGENT2}" directly. Use category parameter instead (e.g., ${categoryExamples}).
75552
76739
 
75553
76740
  Mouse is spawned automatically when you specify a category. Pick the appropriate category for your task domain.`
75554
76741
  };
@@ -75629,6 +76816,8 @@ Create the work plan directly - that's your job as the planning agent.`
75629
76816
  return { agentToUse, categoryModel };
75630
76817
  }
75631
76818
  // src/features/task-toast-manager/manager.ts
76819
+ init_logger();
76820
+
75632
76821
  class TaskToastManager {
75633
76822
  tasks = new Map;
75634
76823
  client;
@@ -75748,7 +76937,9 @@ class TaskToastManager {
75748
76937
  variant: "info",
75749
76938
  duration: running.length + queued.length > 2 ? 5000 : 3000
75750
76939
  }
75751
- }).catch(() => {});
76940
+ }).catch((err) => {
76941
+ log("[task-toast] Toast failed:", err);
76942
+ });
75752
76943
  }
75753
76944
  showCompletionToast(task) {
75754
76945
  const tuiClient = this.client;
@@ -75770,7 +76961,9 @@ Still running: ${remaining.length} | Queued: ${queued.length}`;
75770
76961
  variant: "success",
75771
76962
  duration: 5000
75772
76963
  }
75773
- }).catch(() => {});
76964
+ }).catch((err) => {
76965
+ log("[task-toast] Toast failed:", err);
76966
+ });
75774
76967
  }
75775
76968
  }
75776
76969
  var instance = null;
@@ -76245,18 +77438,19 @@ async function sendSyncPrompt(client2, input, deps = sendSyncPromptDeps) {
76245
77438
  try {
76246
77439
  await deps.promptWithModelSuggestionRetry(client2, promptArgs);
76247
77440
  } catch (promptError) {
77441
+ let lastError = promptError;
76248
77442
  if (isOracleAgent2(input.agentToUse) && isUnexpectedEofError(promptError)) {
76249
77443
  try {
76250
77444
  await deps.promptSyncWithModelSuggestionRetry(client2, promptArgs);
76251
77445
  return null;
76252
77446
  } catch (oracleRetryError) {
76253
- promptError = oracleRetryError;
77447
+ lastError = oracleRetryError;
76254
77448
  }
76255
77449
  }
76256
77450
  if (input.toastManager && input.taskId !== undefined) {
76257
77451
  input.toastManager.removeTask(input.taskId);
76258
77452
  }
76259
- const errorMessage = promptError instanceof Error ? promptError.message : String(promptError);
77453
+ const errorMessage = lastError instanceof Error ? lastError.message : String(lastError);
76260
77454
  if (errorMessage.includes("agent.name") || errorMessage.includes("undefined")) {
76261
77455
  return formatDetailedError(new Error(`Agent "${input.agentToUse}" not found. Make sure the agent is registered in your opencode.json or provided by a plugin.`), {
76262
77456
  operation: "Send prompt to agent",
@@ -76266,7 +77460,7 @@ async function sendSyncPrompt(client2, input, deps = sendSyncPromptDeps) {
76266
77460
  category: input.args.category
76267
77461
  });
76268
77462
  }
76269
- return formatDetailedError(promptError, {
77463
+ return formatDetailedError(lastError, {
76270
77464
  operation: "Send prompt",
76271
77465
  args: input.args,
76272
77466
  sessionID: input.sessionID,
@@ -76429,7 +77623,9 @@ session_id: ${sessionID}
76429
77623
  } finally {
76430
77624
  if (syncSessionID) {
76431
77625
  subagentSessions.delete(syncSessionID);
76432
- client2.session.abort({ path: { id: syncSessionID } }).catch(() => {});
77626
+ client2.session.abort({ path: { id: syncSessionID } }).catch((err) => {
77627
+ log("[delegate-task] Sync session abort failed:", err);
77628
+ });
76433
77629
  }
76434
77630
  }
76435
77631
  }
@@ -76685,13 +77881,13 @@ Prompts MUST be in English.`;
76685
77881
  async execute(args, toolContext) {
76686
77882
  const ctx = toolContext;
76687
77883
  if (args.category) {
76688
- if (args.subagent_type && args.subagent_type !== SISYPHUS_JUNIOR_AGENT2) {
77884
+ if (args.subagent_type && args.subagent_type !== MOUSE_AGENT2) {
76689
77885
  log("[task] category provided - overriding subagent_type to mouse", {
76690
77886
  category: args.category,
76691
77887
  subagent_type: args.subagent_type
76692
77888
  });
76693
77889
  }
76694
- args.subagent_type = SISYPHUS_JUNIOR_AGENT2;
77890
+ args.subagent_type = MOUSE_AGENT2;
76695
77891
  }
76696
77892
  await ctx.metadata?.({
76697
77893
  title: args.description
@@ -78734,7 +79930,7 @@ function createSessionHooks(args) {
78734
79930
  const delegateTaskRetry = isHookEnabled("delegate-task-retry") ? safeHook("delegate-task-retry", () => createDelegateTaskRetryHook(ctx)) : null;
78735
79931
  const startWork = isHookEnabled("start-work") ? safeHook("start-work", () => createStartWorkHook(ctx)) : null;
78736
79932
  const prometheusMdOnly = isHookEnabled("prometheus-md-only") ? safeHook("prometheus-md-only", () => createOracleMdOnlyHook(ctx)) : null;
78737
- const sisyphusJuniorNotepad = isHookEnabled("sisyphus-junior-notepad") ? safeHook("sisyphus-junior-notepad", () => createMouseNotepadHook(ctx)) : null;
79933
+ const mouseNotepad = isHookEnabled("mouse-notepad") ? safeHook("mouse-notepad", () => createMouseNotepadHook(ctx)) : null;
78738
79934
  const questionLabelTruncator = createQuestionLabelTruncatorHook();
78739
79935
  const taskResumeInfo = createTaskResumeInfoHook();
78740
79936
  const anthropicEffort = isHookEnabled("anthropic-effort") ? safeHook("anthropic-effort", () => createAnthropicEffortHook()) : null;
@@ -78758,7 +79954,7 @@ function createSessionHooks(args) {
78758
79954
  delegateTaskRetry,
78759
79955
  startWork,
78760
79956
  prometheusMdOnly,
78761
- sisyphusJuniorNotepad,
79957
+ mouseNotepad,
78762
79958
  questionLabelTruncator,
78763
79959
  taskResumeInfo,
78764
79960
  anthropicEffort,
@@ -79156,10 +80352,6 @@ class ConcurrencyManager {
79156
80352
  return this.queues.get(model)?.length ?? 0;
79157
80353
  }
79158
80354
  }
79159
- // src/features/background-agent/manager.ts
79160
- import { existsSync as existsSync57, readdirSync as readdirSync19, readFileSync as readFileSync39 } from "fs";
79161
- import { join as join72 } from "path";
79162
-
79163
80355
  // src/features/background-agent/constants.ts
79164
80356
  var TASK_TTL_MS = 30 * 60 * 1000;
79165
80357
  var MIN_STABILITY_TIME_MS2 = 10 * 1000;
@@ -79174,6 +80366,59 @@ var POLLING_INTERVAL_MS = 3000;
79174
80366
  var PRUNE_THROTTLE_MS = 30000;
79175
80367
  var TASK_CLEANUP_DELAY_MS = 10 * 60 * 1000;
79176
80368
 
80369
+ // src/features/background-agent/error-helpers.ts
80370
+ function formatDuration2(start, end) {
80371
+ const duration5 = (end ?? new Date).getTime() - start.getTime();
80372
+ const seconds = Math.floor(duration5 / 1000);
80373
+ const minutes = Math.floor(seconds / 60);
80374
+ const hours = Math.floor(minutes / 60);
80375
+ if (hours > 0) {
80376
+ return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
80377
+ }
80378
+ if (minutes > 0) {
80379
+ return `${minutes}m ${seconds % 60}s`;
80380
+ }
80381
+ return `${seconds}s`;
80382
+ }
80383
+ function getErrorText(error95) {
80384
+ if (!error95)
80385
+ return "";
80386
+ if (typeof error95 === "string")
80387
+ return error95;
80388
+ if (error95 instanceof Error) {
80389
+ return `${error95.name}: ${error95.message}`;
80390
+ }
80391
+ if (typeof error95 === "object" && error95 !== null) {
80392
+ if ("message" in error95 && typeof error95.message === "string") {
80393
+ return error95.message;
80394
+ }
80395
+ if ("name" in error95 && typeof error95.name === "string") {
80396
+ return error95.name;
80397
+ }
80398
+ }
80399
+ return "";
80400
+ }
80401
+ function isAbortedSessionError(error95) {
80402
+ const message = getErrorText(error95);
80403
+ return message.toLowerCase().includes("aborted");
80404
+ }
80405
+ function isRecord5(value) {
80406
+ return typeof value === "object" && value !== null;
80407
+ }
80408
+ function getSessionErrorMessage(properties) {
80409
+ const errorRaw = properties.error;
80410
+ if (!isRecord5(errorRaw))
80411
+ return;
80412
+ const dataRaw = errorRaw.data;
80413
+ if (isRecord5(dataRaw)) {
80414
+ const message2 = dataRaw.message;
80415
+ if (typeof message2 === "string")
80416
+ return message2;
80417
+ }
80418
+ const message = errorRaw.message;
80419
+ return typeof message === "string" ? message : undefined;
80420
+ }
80421
+
79177
80422
  // src/features/background-agent/loop-detector.ts
79178
80423
  function resolveCircuitBreakerSettings(config4) {
79179
80424
  return {
@@ -79238,6 +80483,145 @@ function detectRepetitiveToolUse(window) {
79238
80483
  };
79239
80484
  }
79240
80485
 
80486
+ // src/features/background-agent/message-dir.ts
80487
+ import { existsSync as existsSync57, readdirSync as readdirSync19, readFileSync as readFileSync39 } from "fs";
80488
+ import { join as join72 } from "path";
80489
+ var MESSAGE_DIR_CACHE_CAP = 1000;
80490
+ var messageDirCache = new Map;
80491
+ function computeMessageDir(sessionID) {
80492
+ if (!existsSync57(MESSAGE_STORAGE))
80493
+ return null;
80494
+ const directPath = join72(MESSAGE_STORAGE, sessionID);
80495
+ if (existsSync57(directPath))
80496
+ return directPath;
80497
+ for (const dir of readdirSync19(MESSAGE_STORAGE)) {
80498
+ const sessionPath = join72(MESSAGE_STORAGE, dir, sessionID);
80499
+ if (existsSync57(sessionPath))
80500
+ return sessionPath;
80501
+ }
80502
+ return null;
80503
+ }
80504
+ function getMessageDir2(sessionID) {
80505
+ const cached3 = messageDirCache.get(sessionID);
80506
+ if (cached3 !== undefined) {
80507
+ messageDirCache.delete(sessionID);
80508
+ messageDirCache.set(sessionID, cached3);
80509
+ return cached3;
80510
+ }
80511
+ const result = computeMessageDir(sessionID);
80512
+ if (messageDirCache.size >= MESSAGE_DIR_CACHE_CAP) {
80513
+ const oldest = messageDirCache.keys().next().value;
80514
+ if (oldest !== undefined)
80515
+ messageDirCache.delete(oldest);
80516
+ }
80517
+ messageDirCache.set(sessionID, result);
80518
+ return result;
80519
+ }
80520
+ function isCompactionAgent(agent) {
80521
+ return agent?.trim().toLowerCase() === "compaction";
80522
+ }
80523
+ function hasFullAgentAndModel(message) {
80524
+ return !!message.agent && !isCompactionAgent(message.agent) && !!message.model?.providerID && !!message.model?.modelID;
80525
+ }
80526
+ function hasPartialAgentOrModel(message) {
80527
+ const hasAgent = !!message.agent && !isCompactionAgent(message.agent);
80528
+ const hasModel = !!message.model?.providerID && !!message.model?.modelID;
80529
+ return hasAgent || hasModel;
80530
+ }
80531
+ function findNearestMessageExcludingCompaction(messageDir) {
80532
+ try {
80533
+ const files = readdirSync19(messageDir).filter((name) => name.endsWith(".json")).sort().reverse();
80534
+ const parsedByFile = new Map;
80535
+ for (const file3 of files) {
80536
+ try {
80537
+ const content = readFileSync39(join72(messageDir, file3), "utf-8");
80538
+ const parsed = JSON.parse(content);
80539
+ parsedByFile.set(file3, parsed);
80540
+ if (hasFullAgentAndModel(parsed)) {
80541
+ return parsed;
80542
+ }
80543
+ } catch {}
80544
+ }
80545
+ for (const parsed of parsedByFile.values()) {
80546
+ if (hasPartialAgentOrModel(parsed)) {
80547
+ return parsed;
80548
+ }
80549
+ }
80550
+ return null;
80551
+ } catch {
80552
+ return null;
80553
+ }
80554
+ }
80555
+
80556
+ // src/features/background-agent/notification-builder.ts
80557
+ function buildCompletionNotification(task, allComplete, completedTasks, remainingCount, duration5, errorInfo) {
80558
+ if (allComplete) {
80559
+ const completedTasksText = completedTasks.map((t) => `- \`${t.id}\`: ${t.description}`).join(`
80560
+ `);
80561
+ return `<system-reminder>
80562
+ [ALL BACKGROUND TASKS COMPLETE]
80563
+
80564
+ **Completed:**
80565
+ ${completedTasksText || `- \`${task.id}\`: ${task.description}`}
80566
+
80567
+ Use \`background_output(task_id="<id>")\` to retrieve each result.
80568
+ </system-reminder>`;
80569
+ }
80570
+ const statusText = task.status === "completed" ? "COMPLETED" : task.status === "interrupt" ? "INTERRUPTED" : "CANCELLED";
80571
+ return `<system-reminder>
80572
+ [BACKGROUND TASK ${statusText}]
80573
+ **ID:** \`${task.id}\`
80574
+ **Description:** ${task.description}
80575
+ **Duration:** ${duration5}${errorInfo}
80576
+
80577
+ **${remainingCount} task${remainingCount === 1 ? "" : "s"} still in progress.** You WILL be notified when ALL complete.
80578
+ Do NOT poll - continue productive work.
80579
+
80580
+ Use \`background_output(task_id="${task.id}")\` to retrieve this result when ready.
80581
+ </system-reminder>`;
80582
+ }
80583
+ async function resolveAgentAndModel(client2, task, enableParentSessionNotifications) {
80584
+ let agent = task.parentAgent;
80585
+ let model;
80586
+ if (!enableParentSessionNotifications) {
80587
+ return { agent, model };
80588
+ }
80589
+ try {
80590
+ const messagesResp = await client2.session.messages({
80591
+ path: { id: task.parentSessionID }
80592
+ });
80593
+ const messages = normalizeSDKResponse(messagesResp, []);
80594
+ for (let i = messages.length - 1;i >= 0; i--) {
80595
+ const info = messages[i].info;
80596
+ if (isCompactionAgent(info?.agent)) {
80597
+ continue;
80598
+ }
80599
+ if (info?.agent || info?.model || info?.modelID && info?.providerID) {
80600
+ agent = info.agent ?? task.parentAgent;
80601
+ model = info.model ?? (info.providerID && info.modelID ? {
80602
+ providerID: info.providerID,
80603
+ modelID: info.modelID
80604
+ } : undefined);
80605
+ break;
80606
+ }
80607
+ }
80608
+ } catch (error95) {
80609
+ if (isAbortedSessionError(error95)) {
80610
+ log("[background-agent] Parent session aborted while loading messages; using messageDir fallback:", {
80611
+ taskParentSessionID: task.parentSessionID
80612
+ });
80613
+ }
80614
+ const messageDir = getMessageDir2(task.parentSessionID);
80615
+ const currentMessage = messageDir ? findNearestMessageExcludingCompaction(messageDir) : null;
80616
+ agent = currentMessage?.agent ?? task.parentAgent;
80617
+ model = currentMessage?.model?.providerID && currentMessage?.model?.modelID ? {
80618
+ providerID: currentMessage.model.providerID,
80619
+ modelID: currentMessage.model.modelID
80620
+ } : undefined;
80621
+ }
80622
+ return { agent, model };
80623
+ }
80624
+
79241
80625
  // src/features/background-agent/task-history.ts
79242
80626
  var MAX_ENTRIES_PER_PARENT = 100;
79243
80627
 
@@ -79544,9 +80928,7 @@ class BackgroundManager {
79544
80928
  this.concurrencyManager.release(existingTask.concurrencyKey);
79545
80929
  existingTask.concurrencyKey = undefined;
79546
80930
  }
79547
- this.client.session.abort({
79548
- path: { id: sessionID }
79549
- }).catch(() => {});
80931
+ this.abortSessionQuietly(sessionID, "error-recovery");
79550
80932
  this.markForNotification(existingTask);
79551
80933
  this.cleanupPendingByParent(existingTask);
79552
80934
  this.enqueueNotificationForParent(existingTask.parentSessionID, () => this.notifyParentSession(existingTask)).catch((err) => {
@@ -79750,9 +81132,7 @@ class BackgroundManager {
79750
81132
  existingTask.concurrencyKey = undefined;
79751
81133
  }
79752
81134
  if (existingTask.sessionID) {
79753
- this.client.session.abort({
79754
- path: { id: existingTask.sessionID }
79755
- }).catch(() => {});
81135
+ this.abortSessionQuietly(existingTask.sessionID, "resume-error");
79756
81136
  }
79757
81137
  this.markForNotification(existingTask);
79758
81138
  this.cleanupPendingByParent(existingTask);
@@ -79907,7 +81287,7 @@ class BackgroundManager {
79907
81287
  const task = this.findBySession(sessionID);
79908
81288
  if (task?.status !== "running")
79909
81289
  return;
79910
- const errorMessage = props ? this.getSessionErrorMessage(props) : undefined;
81290
+ const errorMessage = props ? getSessionErrorMessage(props) : undefined;
79911
81291
  task.status = "error";
79912
81292
  task.error = errorMessage ?? "Session error";
79913
81293
  task.completedAt = new Date;
@@ -80047,6 +81427,14 @@ class BackgroundManager {
80047
81427
  }
80048
81428
  }
80049
81429
  }
81430
+ abortSessionQuietly(sessionID, context) {
81431
+ this.client.session.abort({ path: { id: sessionID } }).catch((err) => {
81432
+ log(`[background-agent] Session abort failed${context ? ` (${context})` : ""}:`, {
81433
+ sessionID,
81434
+ error: err
81435
+ });
81436
+ });
81437
+ }
80050
81438
  async cancelTask(taskId, options) {
80051
81439
  const task = this.tasks.get(taskId);
80052
81440
  if (!task || task.status !== "running" && task.status !== "pending") {
@@ -80091,9 +81479,7 @@ class BackgroundManager {
80091
81479
  }
80092
81480
  this.cleanupPendingByParent(task);
80093
81481
  if (abortSession && task.sessionID) {
80094
- this.client.session.abort({
80095
- path: { id: task.sessionID }
80096
- }).catch(() => {});
81482
+ this.abortSessionQuietly(task.sessionID, "cancel");
80097
81483
  }
80098
81484
  if (options?.skipNotification) {
80099
81485
  const toastManager = getTaskToastManager();
@@ -80208,9 +81594,7 @@ class BackgroundManager {
80208
81594
  this.idleDeferralTimers.delete(task.id);
80209
81595
  }
80210
81596
  if (task.sessionID) {
80211
- this.client.session.abort({
80212
- path: { id: task.sessionID }
80213
- }).catch(() => {});
81597
+ this.abortSessionQuietly(task.sessionID, "complete");
80214
81598
  }
80215
81599
  try {
80216
81600
  await this.enqueueNotificationForParent(task.parentSessionID, () => this.notifyParentSession(task));
@@ -80221,7 +81605,7 @@ class BackgroundManager {
80221
81605
  return true;
80222
81606
  }
80223
81607
  async notifyParentSession(task) {
80224
- const duration5 = this.formatDuration(task.startedAt ?? new Date, task.completedAt);
81608
+ const duration5 = formatDuration2(task.startedAt ?? new Date, task.completedAt);
80225
81609
  log("[background-agent] notifyParentSession called for task:", task.id);
80226
81610
  const toastManager = getTaskToastManager();
80227
81611
  if (toastManager) {
@@ -80245,68 +81629,16 @@ class BackgroundManager {
80245
81629
  allComplete = true;
80246
81630
  }
80247
81631
  const completedTasks = allComplete ? Array.from(this.tasks.values()).filter((t) => t.parentSessionID === task.parentSessionID && t.status !== "running" && t.status !== "pending") : [];
80248
- const statusText = task.status === "completed" ? "COMPLETED" : task.status === "interrupt" ? "INTERRUPTED" : "CANCELLED";
80249
81632
  const errorInfo = task.error ? `
80250
81633
  **Error:** ${task.error}` : "";
80251
- let notification;
80252
- if (allComplete) {
80253
- const completedTasksText = completedTasks.map((t) => `- \`${t.id}\`: ${t.description}`).join(`
80254
- `);
80255
- notification = `<system-reminder>
80256
- [ALL BACKGROUND TASKS COMPLETE]
80257
-
80258
- **Completed:**
80259
- ${completedTasksText || `- \`${task.id}\`: ${task.description}`}
80260
-
80261
- Use \`background_output(task_id="<id>")\` to retrieve each result.
80262
- </system-reminder>`;
80263
- } else {
80264
- notification = `<system-reminder>
80265
- [BACKGROUND TASK ${statusText}]
80266
- **ID:** \`${task.id}\`
80267
- **Description:** ${task.description}
80268
- **Duration:** ${duration5}${errorInfo}
80269
-
80270
- **${remainingCount} task${remainingCount === 1 ? "" : "s"} still in progress.** You WILL be notified when ALL complete.
80271
- Do NOT poll - continue productive work.
80272
-
80273
- Use \`background_output(task_id="${task.id}")\` to retrieve this result when ready.
80274
- </system-reminder>`;
80275
- }
80276
- let agent = task.parentAgent;
80277
- let model;
81634
+ const notification = buildCompletionNotification(task, allComplete, completedTasks, remainingCount, duration5, errorInfo);
81635
+ const { agent, model } = await resolveAgentAndModel(this.client, task, this.enableParentSessionNotifications);
81636
+ log("[background-agent] notifyParentSession context:", {
81637
+ taskId: task.id,
81638
+ resolvedAgent: agent,
81639
+ resolvedModel: model
81640
+ });
80278
81641
  if (this.enableParentSessionNotifications) {
80279
- try {
80280
- const messagesResp = await this.client.session.messages({ path: { id: task.parentSessionID } });
80281
- const messages = normalizeSDKResponse(messagesResp, []);
80282
- for (let i = messages.length - 1;i >= 0; i--) {
80283
- const info = messages[i].info;
80284
- if (isCompactionAgent(info?.agent)) {
80285
- continue;
80286
- }
80287
- if (info?.agent || info?.model || info?.modelID && info?.providerID) {
80288
- agent = info.agent ?? task.parentAgent;
80289
- model = info.model ?? (info.providerID && info.modelID ? { providerID: info.providerID, modelID: info.modelID } : undefined);
80290
- break;
80291
- }
80292
- }
80293
- } catch (error95) {
80294
- if (this.isAbortedSessionError(error95)) {
80295
- log("[background-agent] Parent session aborted while loading messages; using messageDir fallback:", {
80296
- taskId: task.id,
80297
- parentSessionID: task.parentSessionID
80298
- });
80299
- }
80300
- const messageDir = getMessageDir2(task.parentSessionID);
80301
- const currentMessage = messageDir ? findNearestMessageExcludingCompaction(messageDir) : null;
80302
- agent = currentMessage?.agent ?? task.parentAgent;
80303
- model = currentMessage?.model?.providerID && currentMessage?.model?.modelID ? { providerID: currentMessage.model.providerID, modelID: currentMessage.model.modelID } : undefined;
80304
- }
80305
- log("[background-agent] notifyParentSession context:", {
80306
- taskId: task.id,
80307
- resolvedAgent: agent,
80308
- resolvedModel: model
80309
- });
80310
81642
  try {
80311
81643
  await this.client.session.promptAsync({
80312
81644
  path: { id: task.parentSessionID },
@@ -80324,7 +81656,7 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
80324
81656
  noReply: !allComplete
80325
81657
  });
80326
81658
  } catch (error95) {
80327
- if (this.isAbortedSessionError(error95)) {
81659
+ if (isAbortedSessionError(error95)) {
80328
81660
  log("[background-agent] Parent session aborted while sending notification; continuing cleanup:", {
80329
81661
  taskId: task.id,
80330
81662
  parentSessionID: task.parentSessionID
@@ -80359,56 +81691,6 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
80359
81691
  }
80360
81692
  }
80361
81693
  }
80362
- formatDuration(start, end) {
80363
- const duration5 = (end ?? new Date).getTime() - start.getTime();
80364
- const seconds = Math.floor(duration5 / 1000);
80365
- const minutes = Math.floor(seconds / 60);
80366
- const hours = Math.floor(minutes / 60);
80367
- if (hours > 0) {
80368
- return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
80369
- } else if (minutes > 0) {
80370
- return `${minutes}m ${seconds % 60}s`;
80371
- }
80372
- return `${seconds}s`;
80373
- }
80374
- isAbortedSessionError(error95) {
80375
- const message = this.getErrorText(error95);
80376
- return message.toLowerCase().includes("aborted");
80377
- }
80378
- getErrorText(error95) {
80379
- if (!error95)
80380
- return "";
80381
- if (typeof error95 === "string")
80382
- return error95;
80383
- if (error95 instanceof Error) {
80384
- return `${error95.name}: ${error95.message}`;
80385
- }
80386
- if (typeof error95 === "object" && error95 !== null) {
80387
- if ("message" in error95 && typeof error95.message === "string") {
80388
- return error95.message;
80389
- }
80390
- if ("name" in error95 && typeof error95.name === "string") {
80391
- return error95.name;
80392
- }
80393
- }
80394
- return "";
80395
- }
80396
- isRecord(value) {
80397
- return typeof value === "object" && value !== null;
80398
- }
80399
- getSessionErrorMessage(properties) {
80400
- const errorRaw = properties.error;
80401
- if (!this.isRecord(errorRaw))
80402
- return;
80403
- const dataRaw = errorRaw.data;
80404
- if (this.isRecord(dataRaw)) {
80405
- const message2 = dataRaw.message;
80406
- if (typeof message2 === "string")
80407
- return message2;
80408
- }
80409
- const message = errorRaw.message;
80410
- return typeof message === "string" ? message : undefined;
80411
- }
80412
81694
  hasRunningTasks() {
80413
81695
  for (const task of this.tasks.values()) {
80414
81696
  if (task.status === "running")
@@ -80505,7 +81787,7 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
80505
81787
  this.concurrencyManager.release(task.concurrencyKey);
80506
81788
  task.concurrencyKey = undefined;
80507
81789
  }
80508
- this.client.session.abort({ path: { id: sessionID } }).catch(() => {});
81790
+ this.abortSessionQuietly(sessionID, "stale-no-progress");
80509
81791
  log(`[background-agent] Task ${task.id} interrupted: no progress since start`);
80510
81792
  try {
80511
81793
  await this.enqueueNotificationForParent(task.parentSessionID, () => this.notifyParentSession(task));
@@ -80531,7 +81813,7 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
80531
81813
  this.concurrencyManager.release(task.concurrencyKey);
80532
81814
  task.concurrencyKey = undefined;
80533
81815
  }
80534
- this.client.session.abort({ path: { id: sessionID } }).catch(() => {});
81816
+ this.abortSessionQuietly(sessionID, "stale-timeout");
80535
81817
  log(`[background-agent] Task ${task.id} interrupted: stale timeout`);
80536
81818
  try {
80537
81819
  await this.enqueueNotificationForParent(task.parentSessionID, () => this.notifyParentSession(task));
@@ -80601,9 +81883,7 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
80601
81883
  this.stopPolling();
80602
81884
  for (const task of this.tasks.values()) {
80603
81885
  if (task.status === "running" && task.sessionID) {
80604
- this.client.session.abort({
80605
- path: { id: task.sessionID }
80606
- }).catch(() => {});
81886
+ this.abortSessionQuietly(task.sessionID, "shutdown");
80607
81887
  }
80608
81888
  }
80609
81889
  if (this.onShutdown) {
@@ -80642,13 +81922,17 @@ Use \`background_output(task_id="${task.id}")\` to retrieve this result when rea
80642
81922
  return operation();
80643
81923
  }
80644
81924
  const previous = this.notificationQueueByParent.get(parentSessionID) ?? Promise.resolve();
80645
- const current = previous.catch(() => {}).then(operation);
81925
+ const current = previous.catch((err) => {
81926
+ log("[background-agent] Previous notification failed, continuing queue:", err);
81927
+ }).then(operation);
80646
81928
  this.notificationQueueByParent.set(parentSessionID, current);
80647
81929
  current.finally(() => {
80648
81930
  if (this.notificationQueueByParent.get(parentSessionID) === current) {
80649
81931
  this.notificationQueueByParent.delete(parentSessionID);
80650
81932
  }
80651
- }).catch(() => {});
81933
+ }).catch((err) => {
81934
+ log("[background-agent] Notification queue cleanup failed:", err);
81935
+ });
80652
81936
  return current;
80653
81937
  }
80654
81938
  }
@@ -80663,72 +81947,6 @@ function registerProcessSignal(signal, handler, exitAfter) {
80663
81947
  process.on(signal, listener);
80664
81948
  return listener;
80665
81949
  }
80666
- function computeMessageDir(sessionID) {
80667
- if (!existsSync57(MESSAGE_STORAGE))
80668
- return null;
80669
- const directPath = join72(MESSAGE_STORAGE, sessionID);
80670
- if (existsSync57(directPath))
80671
- return directPath;
80672
- for (const dir of readdirSync19(MESSAGE_STORAGE)) {
80673
- const sessionPath = join72(MESSAGE_STORAGE, dir, sessionID);
80674
- if (existsSync57(sessionPath))
80675
- return sessionPath;
80676
- }
80677
- return null;
80678
- }
80679
- var MESSAGE_DIR_CACHE_CAP = 1000;
80680
- var messageDirCache = new Map;
80681
- function getMessageDir2(sessionID) {
80682
- const cached3 = messageDirCache.get(sessionID);
80683
- if (cached3 !== undefined) {
80684
- messageDirCache.delete(sessionID);
80685
- messageDirCache.set(sessionID, cached3);
80686
- return cached3;
80687
- }
80688
- const result = computeMessageDir(sessionID);
80689
- if (messageDirCache.size >= MESSAGE_DIR_CACHE_CAP) {
80690
- const oldest = messageDirCache.keys().next().value;
80691
- if (oldest !== undefined)
80692
- messageDirCache.delete(oldest);
80693
- }
80694
- messageDirCache.set(sessionID, result);
80695
- return result;
80696
- }
80697
- function isCompactionAgent(agent) {
80698
- return agent?.trim().toLowerCase() === "compaction";
80699
- }
80700
- function hasFullAgentAndModel(message) {
80701
- return !!message.agent && !isCompactionAgent(message.agent) && !!message.model?.providerID && !!message.model?.modelID;
80702
- }
80703
- function hasPartialAgentOrModel(message) {
80704
- const hasAgent = !!message.agent && !isCompactionAgent(message.agent);
80705
- const hasModel = !!message.model?.providerID && !!message.model?.modelID;
80706
- return hasAgent || hasModel;
80707
- }
80708
- function findNearestMessageExcludingCompaction(messageDir) {
80709
- try {
80710
- const files = readdirSync19(messageDir).filter((name) => name.endsWith(".json")).sort().reverse();
80711
- const parsedByFile = new Map;
80712
- for (const file3 of files) {
80713
- try {
80714
- const content = readFileSync39(join72(messageDir, file3), "utf-8");
80715
- const parsed = JSON.parse(content);
80716
- parsedByFile.set(file3, parsed);
80717
- if (hasFullAgentAndModel(parsed)) {
80718
- return parsed;
80719
- }
80720
- } catch {}
80721
- }
80722
- for (const parsed of parsedByFile.values()) {
80723
- if (hasPartialAgentOrModel(parsed)) {
80724
- return parsed;
80725
- }
80726
- }
80727
- return null;
80728
- } catch {
80729
- return null;
80730
- }
80731
- }
80732
81950
  // src/features/background-agent/state.ts
80733
81951
  class TaskStateManager {
80734
81952
  tasks = new Map;
@@ -80901,6 +82119,7 @@ class TaskStateManager {
80901
82119
  }
80902
82120
  }
80903
82121
  // src/features/skill-mcp-manager/cleanup.ts
82122
+ init_logger();
80904
82123
  async function closeManagedClient(managed) {
80905
82124
  try {
80906
82125
  await managed.client.close();
@@ -80921,7 +82140,9 @@ function registerProcessCleanup(state3) {
80921
82140
  state3.pendingConnections.clear();
80922
82141
  };
80923
82142
  const register = (signal) => {
80924
- const listener = () => void cleanup().catch(() => {});
82143
+ const listener = () => void cleanup().catch((err) => {
82144
+ log("[skill-mcp] Signal handler cleanup failed:", err);
82145
+ });
80925
82146
  state3.cleanupHandlers.push({ signal, listener });
80926
82147
  process.on(signal, listener);
80927
82148
  };
@@ -80944,7 +82165,9 @@ function startCleanupTimer(state3) {
80944
82165
  if (state3.cleanupInterval)
80945
82166
  return;
80946
82167
  state3.cleanupInterval = setInterval(() => {
80947
- cleanupIdleClients(state3).catch(() => {});
82168
+ cleanupIdleClients(state3).catch((err) => {
82169
+ log("[skill-mcp] Idle client cleanup failed:", err);
82170
+ });
80948
82171
  }, 60000);
80949
82172
  state3.cleanupInterval.unref();
80950
82173
  }
@@ -84601,13 +85824,13 @@ class StreamableHTTPClientTransport {
84601
85824
  this.onerror?.(new Error(`Maximum reconnection attempts (${maxRetries}) exceeded.`));
84602
85825
  return;
84603
85826
  }
84604
- const delay4 = this._getNextReconnectionDelay(attemptCount);
85827
+ const delay6 = this._getNextReconnectionDelay(attemptCount);
84605
85828
  this._reconnectionTimeout = setTimeout(() => {
84606
85829
  this._startOrAuthSse(options).catch((error95) => {
84607
85830
  this.onerror?.(new Error(`Failed to reconnect SSE stream: ${error95 instanceof Error ? error95.message : String(error95)}`));
84608
85831
  this._scheduleReconnection(options, attemptCount + 1);
84609
85832
  });
84610
- }, delay4);
85833
+ }, delay6);
84611
85834
  }
84612
85835
  _handleSseStream(stream, options, isReconnectable) {
84613
85836
  if (!stream) {
@@ -84918,7 +86141,7 @@ async function getOrRegisterClient(options) {
84918
86141
  }
84919
86142
  }
84920
86143
  function parseRegistrationResponse(data) {
84921
- if (!isRecord5(data))
86144
+ if (!isRecord6(data))
84922
86145
  return null;
84923
86146
  const clientId = data.client_id;
84924
86147
  if (typeof clientId !== "string" || clientId.length === 0)
@@ -84929,7 +86152,7 @@ function parseRegistrationResponse(data) {
84929
86152
  }
84930
86153
  return { clientId };
84931
86154
  }
84932
- function isRecord5(value) {
86155
+ function isRecord6(value) {
84933
86156
  return typeof value === "object" && value !== null;
84934
86157
  }
84935
86158
 
@@ -86958,9 +88181,9 @@ function buildOracleSection(agents) {
86958
88181
  const useWhen = oracleAgent.metadata.useWhen || [];
86959
88182
  const avoidWhen = oracleAgent.metadata.avoidWhen || [];
86960
88183
  return `<Oracle_Usage>
86961
- ## Oracle \u2014 Read-Only High-IQ Consultant
88184
+ ## Oracle \u2014 Plan Builder
86962
88185
 
86963
- Oracle is a read-only, expensive, high-quality reasoning model for debugging and architecture. Consultation only.
88186
+ Oracle is the Plan Builder \u2014 creates detailed, structured work plans from user requests. Use oracle when you need comprehensive planning before implementation.
86964
88187
 
86965
88188
  ### WHEN to Consult:
86966
88189
 
@@ -86975,7 +88198,7 @@ ${avoidWhen.map((w) => `- ${w}`).join(`
86975
88198
  `)}
86976
88199
 
86977
88200
  ### Usage Pattern:
86978
- Briefly announce "Consulting Oracle for [reason]" before invocation.
88201
+ Oracle creates plans, not code. Invoke oracle to decompose complex requests into structured work plans with clear steps, then execute the plan yourself or delegate to workers.
86979
88202
 
86980
88203
  **Exception**: This is the ONLY case where you announce before acting. For all other work, start immediately without status updates.
86981
88204
  </Oracle_Usage>`;
@@ -87011,9 +88234,9 @@ ${patterns.join(`
87011
88234
  }
87012
88235
 
87013
88236
  // src/agents/architect/default.ts
87014
- var ATLAS_SYSTEM_PROMPT = `
88237
+ var ARCHITECT_SYSTEM_PROMPT = `
87015
88238
  <identity>
87016
- You are Atlas - the Master Orchestrator from Matrixx.
88239
+ You are Architect - the Master Orchestrator from Matrixx.
87017
88240
 
87018
88241
  In Greek mythology, Atlas holds up the celestial heavens. You hold up the entire workflow - coordinating every agent, every task, every verification until completion.
87019
88242
 
@@ -87410,14 +88633,14 @@ You are the QA gate. Subagents lie. Verify EVERYTHING.
87410
88633
  - **Use \`session_id="{session_id}"\` for retries, fixes, and follow-ups**
87411
88634
  </critical_overrides>
87412
88635
  `;
87413
- function getDefaultAtlasPrompt() {
87414
- return ATLAS_SYSTEM_PROMPT;
88636
+ function getDefaultArchitectPrompt() {
88637
+ return ARCHITECT_SYSTEM_PROMPT;
87415
88638
  }
87416
88639
 
87417
88640
  // src/agents/architect/gpt.ts
87418
- var ATLAS_GPT_SYSTEM_PROMPT = `
88641
+ var ARCHITECT_GPT_SYSTEM_PROMPT = `
87419
88642
  <identity>
87420
- You are Atlas - Master Orchestrator from Matrixx.
88643
+ You are Architect - Master Orchestrator from Matrixx.
87421
88644
  Role: Conductor, not musician. General, not soldier.
87422
88645
  You DELEGATE, COORDINATE, and VERIFY. You NEVER write code yourself.
87423
88646
  </identity>
@@ -87763,8 +88986,8 @@ You are the QA gate. Subagents lie. Verify EVERYTHING.
87763
88986
  - Do NOT expand task scope; if you notice new work, call it out as optional
87764
88987
  </user_updates_spec>
87765
88988
  `;
87766
- function getGptAtlasPrompt() {
87767
- return ATLAS_GPT_SYSTEM_PROMPT;
88989
+ function getGptArchitectPrompt() {
88990
+ return ARCHITECT_GPT_SYSTEM_PROMPT;
87768
88991
  }
87769
88992
 
87770
88993
  // src/agents/architect/prompt-section-builder.ts
@@ -87884,19 +89107,19 @@ ${agentRows.join(`
87884
89107
 
87885
89108
  // src/agents/architect/agent.ts
87886
89109
  var MODE = "primary";
87887
- function getAtlasPromptSource(model) {
89110
+ function getArchitectPromptSource(model) {
87888
89111
  if (model && isGptModel(model)) {
87889
89112
  return "gpt";
87890
89113
  }
87891
89114
  return "default";
87892
89115
  }
87893
- function getAtlasPrompt(model) {
87894
- const source = getAtlasPromptSource(model);
89116
+ function getArchitectPrompt(model) {
89117
+ const source = getArchitectPromptSource(model);
87895
89118
  switch (source) {
87896
89119
  case "gpt":
87897
- return getGptAtlasPrompt();
89120
+ return getGptArchitectPrompt();
87898
89121
  default:
87899
- return getDefaultAtlasPrompt();
89122
+ return getDefaultArchitectPrompt();
87900
89123
  }
87901
89124
  }
87902
89125
  function buildDynamicOrchestratorPrompt(ctx) {
@@ -87914,16 +89137,16 @@ function buildDynamicOrchestratorPrompt(ctx) {
87914
89137
  const decisionMatrix = buildDecisionMatrix(agents, userCategories);
87915
89138
  const skillsSection = buildSkillsSection(skills);
87916
89139
  const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, skills);
87917
- const basePrompt = getAtlasPrompt(model);
89140
+ const basePrompt = getArchitectPrompt(model);
87918
89141
  return basePrompt.replace("{CATEGORY_SECTION}", categorySection).replace("{AGENT_SECTION}", agentSection).replace("{DECISION_MATRIX}", decisionMatrix).replace("{SKILLS_SECTION}", skillsSection).replace("{{CATEGORY_SKILLS_DELEGATION_GUIDE}}", categorySkillsGuide);
87919
89142
  }
87920
- function createAtlasAgent(ctx) {
89143
+ function createArchitectAgent(ctx) {
87921
89144
  const restrictions = createAgentToolRestrictions([
87922
89145
  "task",
87923
89146
  "delegate_agent"
87924
89147
  ]);
87925
89148
  const baseConfig = {
87926
- description: "Orchestrates work via task() to complete ALL tasks in a todo list until fully done. (Atlas - Matrixx)",
89149
+ description: "Orchestrates work via task() to complete ALL tasks in a todo list until fully done. (Architect - Matrixx)",
87927
89150
  mode: MODE,
87928
89151
  ...ctx.model ? { model: ctx.model } : {},
87929
89152
  temperature: 0.1,
@@ -87933,11 +89156,11 @@ function createAtlasAgent(ctx) {
87933
89156
  };
87934
89157
  return baseConfig;
87935
89158
  }
87936
- createAtlasAgent.mode = MODE;
87937
- var atlasPromptMetadata = {
89159
+ createArchitectAgent.mode = MODE;
89160
+ var architectPromptMetadata = {
87938
89161
  category: "advisor",
87939
89162
  cost: "EXPENSIVE",
87940
- promptAlias: "Atlas",
89163
+ promptAlias: "Architect",
87941
89164
  triggers: [
87942
89165
  {
87943
89166
  domain: "Todo list orchestration",
@@ -88059,8 +89282,8 @@ function getFirstFallbackModel(requirement) {
88059
89282
  };
88060
89283
  }
88061
89284
 
88062
- // src/agents/builtin-agents/atlas-agent.ts
88063
- function maybeCreateAtlasConfig(input) {
89285
+ // src/agents/builtin-agents/architect-agent.ts
89286
+ function maybeCreateArchitectConfig(input) {
88064
89287
  const {
88065
89288
  disabledAgents,
88066
89289
  agentOverrides,
@@ -88076,25 +89299,25 @@ function maybeCreateAtlasConfig(input) {
88076
89299
  if (disabledAgents.includes("architect"))
88077
89300
  return;
88078
89301
  const orchestratorOverride = agentOverrides.architect;
88079
- const atlasRequirement = AGENT_MODEL_REQUIREMENTS.architect;
88080
- const atlasResolution = applyModelResolution({
89302
+ const architectRequirement = AGENT_MODEL_REQUIREMENTS.architect;
89303
+ const architectResolution = applyModelResolution({
88081
89304
  uiSelectedModel: orchestratorOverride?.model ? undefined : uiSelectedModel,
88082
89305
  userModel: orchestratorOverride?.model,
88083
- requirement: atlasRequirement,
89306
+ requirement: architectRequirement,
88084
89307
  availableModels,
88085
89308
  systemDefaultModel
88086
89309
  });
88087
- if (!atlasResolution)
89310
+ if (!architectResolution)
88088
89311
  return;
88089
- const { model: atlasModel, variant: atlasResolvedVariant } = atlasResolution;
88090
- let orchestratorConfig = createAtlasAgent({
88091
- model: atlasModel,
89312
+ const { model: architectModel, variant: architectResolvedVariant } = architectResolution;
89313
+ let orchestratorConfig = createArchitectAgent({
89314
+ model: architectModel,
88092
89315
  availableAgents,
88093
89316
  availableSkills,
88094
89317
  userCategories
88095
89318
  });
88096
- if (atlasResolvedVariant) {
88097
- orchestratorConfig = { ...orchestratorConfig, variant: atlasResolvedVariant };
89319
+ if (architectResolvedVariant) {
89320
+ orchestratorConfig = { ...orchestratorConfig, variant: architectResolvedVariant };
88098
89321
  }
88099
89322
  orchestratorConfig = applyOverrides(orchestratorConfig, orchestratorOverride, mergedCategories, directory);
88100
89323
  return orchestratorConfig;
@@ -88223,6 +89446,8 @@ function collectPendingBuiltinAgents(input) {
88223
89446
  const pendingAgentConfigs = new Map;
88224
89447
  for (const [name, source] of Object.entries(agentSources)) {
88225
89448
  const agentName = name;
89449
+ if (!source)
89450
+ continue;
88226
89451
  if (agentName === "morpheus")
88227
89452
  continue;
88228
89453
  if (agentName === "keymaker")
@@ -88269,6 +89494,14 @@ function collectPendingBuiltinAgents(input) {
88269
89494
  });
88270
89495
  }
88271
89496
  }
89497
+ const oracleMetadata = agentMetadata.oracle;
89498
+ if (oracleMetadata) {
89499
+ availableAgents.push({
89500
+ name: "oracle",
89501
+ description: "Plan Builder agent. Creates detailed, structured work plans from user requests. (Oracle - Matrixx)",
89502
+ metadata: oracleMetadata
89503
+ });
89504
+ }
88272
89505
  return { pendingAgentConfigs, availableAgents };
88273
89506
  }
88274
89507
 
@@ -89386,7 +90619,7 @@ function createMorpheusAgent(model, availableAgents, availableToolNames, availab
89386
90619
  }
89387
90620
  createMorpheusAgent.mode = MODE3;
89388
90621
 
89389
- // src/agents/builtin-agents/sisyphus-agent.ts
90622
+ // src/agents/builtin-agents/morpheus-agent.ts
89390
90623
  function maybeCreateMorpheusConfig(input) {
89391
90624
  const {
89392
90625
  disabledAgents,
@@ -89403,25 +90636,25 @@ function maybeCreateMorpheusConfig(input) {
89403
90636
  useTaskSystem
89404
90637
  } = input;
89405
90638
  const morpheusOverride = agentOverrides.morpheus;
89406
- const sisyphusRequirement = AGENT_MODEL_REQUIREMENTS.morpheus;
90639
+ const morpheusRequirement = AGENT_MODEL_REQUIREMENTS.morpheus;
89407
90640
  const hasMorpheusExplicitConfig = morpheusOverride !== undefined;
89408
- const meetsMorpheusAnyModelRequirement = !sisyphusRequirement?.requiresAnyModel || hasMorpheusExplicitConfig || isFirstRunNoCache || isAnyFallbackModelAvailable(sisyphusRequirement.fallbackChain, availableModels);
90641
+ const meetsMorpheusAnyModelRequirement = !morpheusRequirement?.requiresAnyModel || hasMorpheusExplicitConfig || isFirstRunNoCache || isAnyFallbackModelAvailable(morpheusRequirement.fallbackChain, availableModels);
89409
90642
  if (disabledAgents.includes("morpheus") || !meetsMorpheusAnyModelRequirement)
89410
90643
  return;
89411
- let sisyphusResolution = applyModelResolution({
90644
+ let morpheusResolution = applyModelResolution({
89412
90645
  uiSelectedModel: morpheusOverride?.model ? undefined : uiSelectedModel,
89413
90646
  userModel: morpheusOverride?.model,
89414
- requirement: sisyphusRequirement,
90647
+ requirement: morpheusRequirement,
89415
90648
  availableModels,
89416
90649
  systemDefaultModel
89417
90650
  });
89418
90651
  if (isFirstRunNoCache && !morpheusOverride?.model && !uiSelectedModel) {
89419
- sisyphusResolution = getFirstFallbackModel(sisyphusRequirement);
90652
+ morpheusResolution = getFirstFallbackModel(morpheusRequirement);
89420
90653
  }
89421
- if (!sisyphusResolution)
90654
+ if (!morpheusResolution)
89422
90655
  return;
89423
- const { model: sisyphusModel, variant: morpheusResolvedVariant } = sisyphusResolution;
89424
- let morpheusConfig = createMorpheusAgent(sisyphusModel, availableAgents, undefined, availableSkills, availableCategories, useTaskSystem);
90656
+ const { model: morpheusModel, variant: morpheusResolvedVariant } = morpheusResolution;
90657
+ let morpheusConfig = createMorpheusAgent(morpheusModel, availableAgents, undefined, availableSkills, availableCategories, useTaskSystem);
89425
90658
  if (morpheusResolvedVariant) {
89426
90659
  morpheusConfig = { ...morpheusConfig, variant: morpheusResolvedVariant };
89427
90660
  }
@@ -89626,7 +90859,7 @@ createMultimodalLookerAgent.mode = MODE5;
89626
90859
  function sanitizeMarkdownTableCell(value) {
89627
90860
  return value.replace(/\r?\n/g, " ").replace(/\|/g, "\\|").replace(/\s+/g, " ").trim();
89628
90861
  }
89629
- function isRecord6(value) {
90862
+ function isRecord7(value) {
89630
90863
  return typeof value === "object" && value !== null;
89631
90864
  }
89632
90865
  function parseRegisteredAgentSummaries(input) {
@@ -89634,7 +90867,7 @@ function parseRegisteredAgentSummaries(input) {
89634
90867
  return [];
89635
90868
  const result = [];
89636
90869
  for (const item of input) {
89637
- if (!isRecord6(item))
90870
+ if (!isRecord7(item))
89638
90871
  continue;
89639
90872
  const name = typeof item.name === "string" ? item.name : undefined;
89640
90873
  if (!name)
@@ -89673,7 +90906,7 @@ var MODE6 = "subagent";
89673
90906
  var ORACLE_PROMPT_METADATA = {
89674
90907
  category: "advisor",
89675
90908
  cost: "EXPENSIVE",
89676
- promptAlias: "Oracle",
90909
+ promptAlias: "Consultant",
89677
90910
  triggers: [
89678
90911
  { domain: "Architecture decisions", trigger: "Multi-system tradeoffs, unfamiliar patterns" },
89679
90912
  { domain: "Self-review", trigger: "After completing significant implementation" },
@@ -89695,6 +90928,31 @@ var ORACLE_PROMPT_METADATA = {
89695
90928
  "Things you can infer from existing code patterns"
89696
90929
  ]
89697
90930
  };
90931
+ var ORACLE_PLAN_BUILDER_METADATA = {
90932
+ category: "advisor",
90933
+ cost: "EXPENSIVE",
90934
+ keyTrigger: "Complex feature implementation, refactoring, or architecture design \u2192 consult Oracle for planning first",
90935
+ triggers: [
90936
+ { domain: "Architecture decisions", trigger: "Multi-system tradeoffs, unfamiliar patterns" },
90937
+ { domain: "Work planning", trigger: "Complex feature implementation, refactoring" },
90938
+ { domain: "Complex task breakdown", trigger: "Large ambiguous requests needing decomposition" },
90939
+ { domain: "Self-review", trigger: "After completing significant implementation" }
90940
+ ],
90941
+ useWhen: [
90942
+ "Complex architecture design",
90943
+ "Work planning and task decomposition",
90944
+ "Large ambiguous requests needing structure",
90945
+ "After completing significant work for review",
90946
+ "Multi-system tradeoffs and integration planning"
90947
+ ],
90948
+ avoidWhen: [
90949
+ "Simple file operations (use direct tools)",
90950
+ "Questions answerable from code you've read",
90951
+ "Trivial decisions (variable names, formatting)",
90952
+ "Quick debugging tasks (try yourself first)",
90953
+ "Things you can infer from existing code patterns"
90954
+ ]
90955
+ };
89698
90956
  var ORACLE_SYSTEM_PROMPT = `You are a strategic technical advisor with deep reasoning capabilities, operating as a specialized consultant within an AI-assisted development environment.
89699
90957
 
89700
90958
  <context>
@@ -89805,7 +91063,7 @@ Before finalizing answers on architecture, security, or performance:
89805
91063
  <delivery>
89806
91064
  Your response goes directly to the user with no intermediate processing. Make your final message self-contained: a clear recommendation they can act on immediately, covering both what to do and why.
89807
91065
  </delivery>`;
89808
- function createOracleAgent(model) {
91066
+ function createMerovingianAgent(model) {
89809
91067
  const restrictions = createAgentToolRestrictions([
89810
91068
  "write",
89811
91069
  "edit",
@@ -89813,7 +91071,7 @@ function createOracleAgent(model) {
89813
91071
  "task"
89814
91072
  ]);
89815
91073
  const base = {
89816
- description: "Read-only consultation agent. High-IQ reasoning specialist for debugging hard problems and high-difficulty architecture design. (Oracle - Matrixx)",
91074
+ description: "Read-only consultation agent. High-IQ reasoning specialist for debugging hard problems and high-difficulty architecture design. (Merovingian - Matrixx)",
89817
91075
  mode: MODE6,
89818
91076
  model,
89819
91077
  temperature: 0.1,
@@ -89825,7 +91083,7 @@ function createOracleAgent(model) {
89825
91083
  }
89826
91084
  return { ...base, thinking: { type: "enabled", budgetTokens: 16000 } };
89827
91085
  }
89828
- createOracleAgent.mode = MODE6;
91086
+ createMerovingianAgent.mode = MODE6;
89829
91087
 
89830
91088
  // src/agents/operator.ts
89831
91089
  var MODE7 = "subagent";
@@ -91142,25 +92400,26 @@ createExploreAgent.mode = MODE12;
91142
92400
  var agentSources = {
91143
92401
  morpheus: createMorpheusAgent,
91144
92402
  keymaker: createKeymakerAgent,
91145
- merovingian: createOracleAgent,
92403
+ merovingian: createMerovingianAgent,
91146
92404
  operator: createLibrarianAgent,
91147
92405
  trinity: createExploreAgent,
91148
92406
  construct: createMultimodalLookerAgent,
91149
92407
  seraph: createSeraphAgent,
91150
92408
  smith: createSmithAgent,
91151
- architect: createAtlasAgent,
92409
+ architect: createArchitectAgent,
91152
92410
  cipher: createCipherAgent,
91153
92411
  sentinel: createSentinelAgent,
91154
92412
  sati: createSatiAgent
91155
92413
  };
91156
92414
  var agentMetadata = {
91157
92415
  merovingian: ORACLE_PROMPT_METADATA,
92416
+ oracle: ORACLE_PLAN_BUILDER_METADATA,
91158
92417
  operator: LIBRARIAN_PROMPT_METADATA,
91159
92418
  trinity: EXPLORE_PROMPT_METADATA,
91160
92419
  construct: MULTIMODAL_LOOKER_PROMPT_METADATA,
91161
92420
  seraph: seraphPromptMetadata,
91162
92421
  smith: smithPromptMetadata,
91163
- architect: atlasPromptMetadata,
92422
+ architect: architectPromptMetadata,
91164
92423
  cipher: CIPHER_PROMPT_METADATA,
91165
92424
  sentinel: SENTINEL_PROMPT_METADATA,
91166
92425
  sati: SATI_PROMPT_METADATA
@@ -91247,7 +92506,7 @@ async function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, dir
91247
92506
  for (const [name, config4] of pendingAgentConfigs) {
91248
92507
  result[name] = config4;
91249
92508
  }
91250
- const atlasConfig = maybeCreateAtlasConfig({
92509
+ const architectConfig = maybeCreateArchitectConfig({
91251
92510
  disabledAgents,
91252
92511
  agentOverrides,
91253
92512
  uiSelectedModel,
@@ -91259,8 +92518,8 @@ async function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, dir
91259
92518
  directory,
91260
92519
  userCategories: categories
91261
92520
  });
91262
- if (atlasConfig) {
91263
- result.architect = atlasConfig;
92521
+ if (architectConfig) {
92522
+ result.architect = architectConfig;
91264
92523
  }
91265
92524
  return result;
91266
92525
  }
@@ -94382,7 +95641,7 @@ function createToolRegistry(args) {
94382
95641
  client: ctx.client,
94383
95642
  directory: ctx.directory,
94384
95643
  userCategories: pluginConfig.categories,
94385
- sisyphusJuniorModel: pluginConfig.agents?.mouse?.model,
95644
+ mouseModel: pluginConfig.agents?.mouse?.model,
94386
95645
  browserProvider: skillContext.browserProvider,
94387
95646
  disabledSkills: skillContext.disabledSkills,
94388
95647
  availableCategories,
@@ -94431,6 +95690,11 @@ function createToolRegistry(args) {
94431
95690
  } : {};
94432
95691
  const hashlineEnabled = pluginConfig.experimental?.hashline_edit ?? false;
94433
95692
  const hashlineToolsRecord = hashlineEnabled ? { edit: createHashlineEditTool(ctx) } : {};
95693
+ const assemblyEnabled = pluginConfig.assembly?.enabled !== false;
95694
+ const assemblyTool = assemblyEnabled ? createAssemblyTool({
95695
+ manager: managers.backgroundManager,
95696
+ pluginConfig
95697
+ }) : null;
94434
95698
  const allTools = {
94435
95699
  ...builtinTools,
94436
95700
  ...createGrepTools(ctx),
@@ -94447,7 +95711,8 @@ function createToolRegistry(args) {
94447
95711
  slashcommand: slashcommandTool,
94448
95712
  interactive_bash,
94449
95713
  ...taskToolsRecord,
94450
- ...hashlineToolsRecord
95714
+ ...hashlineToolsRecord,
95715
+ ...assemblyTool ? { assembly: assemblyTool } : {}
94451
95716
  };
94452
95717
  const filteredTools = filterDisabledTools(allTools, pluginConfig.disabled_tools);
94453
95718
  return {
@@ -94871,7 +96136,9 @@ var BuiltinSkillNameSchema = exports_external.enum([
94871
96136
  "review-work",
94872
96137
  "quality-gate",
94873
96138
  "software-dev",
94874
- "matrixx-self-config"
96139
+ "matrixx-self-config",
96140
+ "ulw-research",
96141
+ "remove-ai-slops"
94875
96142
  ]);
94876
96143
  // src/config/schema/internal/permission.ts
94877
96144
  var PermissionValueSchema = exports_external.enum(["ask", "allow", "deny"]);
@@ -94937,6 +96204,17 @@ var AgentOverridesSchema = exports_external.object({
94937
96204
  sentinel: AgentOverrideConfigSchema.optional(),
94938
96205
  sati: AgentOverrideConfigSchema.optional()
94939
96206
  });
96207
+ // src/config/schema/assembly.ts
96208
+ var AssemblyConfigSchema = exports_external.object({
96209
+ providers: exports_external.array(exports_external.object({
96210
+ providerID: exports_external.string(),
96211
+ modelID: exports_external.string()
96212
+ })).optional(),
96213
+ default_voters: exports_external.number().int().min(2).max(5).optional(),
96214
+ default_rounds: exports_external.number().int().min(1).max(3).optional(),
96215
+ timeout_ms: exports_external.number().int().min(1e4).max(300000).optional(),
96216
+ enabled: exports_external.boolean().default(false)
96217
+ });
94940
96218
  // src/config/schema/babysitting.ts
94941
96219
  var BabysittingConfigSchema = exports_external.object({
94942
96220
  timeout_ms: exports_external.number().default(120000)
@@ -95016,7 +96294,11 @@ var BuiltinCommandNameSchema = exports_external.enum([
95016
96294
  "start-work",
95017
96295
  "stop-continuation",
95018
96296
  "profile",
95019
- "end-ultrawork"
96297
+ "end-ultrawork",
96298
+ "handoff",
96299
+ "research",
96300
+ "assembly",
96301
+ "ultrawork"
95020
96302
  ]);
95021
96303
  // src/config/schema/comment-checker.ts
95022
96304
  var CommentCheckerConfigSchema = exports_external.object({
@@ -95066,11 +96348,10 @@ var HookNameSchema = exports_external.enum([
95066
96348
  "edit-error-recovery",
95067
96349
  "delegate-task-retry",
95068
96350
  "prometheus-md-only",
95069
- "sisyphus-junior-notepad",
96351
+ "mouse-notepad",
95070
96352
  "start-work",
95071
96353
  "architect",
95072
96354
  "unstable-agent-babysitter",
95073
- "task-reminder",
95074
96355
  "task-resume-info",
95075
96356
  "stop-continuation-guard",
95076
96357
  "tasks-todowrite-disabler",
@@ -95271,6 +96552,7 @@ var MatrixxConfigSchema = exports_external.object({
95271
96552
  websearch: WebsearchConfigSchema.optional(),
95272
96553
  tmux: TmuxConfigSchema.optional(),
95273
96554
  morpheus: MorpheusConfigSchema.optional(),
96555
+ assembly: AssemblyConfigSchema.optional(),
95274
96556
  security: SecurityConfigSchema.optional(),
95275
96557
  runtime_fallback: RuntimeFallbackConfigSchema.optional(),
95276
96558
  agent_definitions: AgentDefinitionsConfigSchema.optional(),
@@ -95418,6 +96700,7 @@ function loadPluginConfig(directory, ctx) {
95418
96700
  }
95419
96701
 
95420
96702
  // src/plugin/chat-message.ts
96703
+ init_logger();
95421
96704
  function isStartWorkHookOutput(value) {
95422
96705
  if (typeof value !== "object" || value === null)
95423
96706
  return false;
@@ -95471,7 +96754,9 @@ function createChatMessageHandler2(args) {
95471
96754
  variant: "warning",
95472
96755
  duration: 6000
95473
96756
  }
95474
- }).catch(() => {});
96757
+ }).catch((err) => {
96758
+ log("[plugin] Provider cache toast failed:", err);
96759
+ });
95475
96760
  }
95476
96761
  if (hooks2.matrixLoop) {
95477
96762
  const parts = output.parts;
@@ -95498,11 +96783,11 @@ function createChatMessageHandler2(args) {
95498
96783
  }
95499
96784
 
95500
96785
  // src/plugin/chat-params.ts
95501
- function isRecord7(value) {
96786
+ function isRecord8(value) {
95502
96787
  return typeof value === "object" && value !== null;
95503
96788
  }
95504
96789
  function buildChatParamsInput(raw) {
95505
- if (!isRecord7(raw))
96790
+ if (!isRecord8(raw))
95506
96791
  return null;
95507
96792
  const sessionID = raw.sessionID;
95508
96793
  const agent = raw.agent;
@@ -95513,11 +96798,11 @@ function buildChatParamsInput(raw) {
95513
96798
  return null;
95514
96799
  if (typeof agent !== "string")
95515
96800
  return null;
95516
- if (!isRecord7(model))
96801
+ if (!isRecord8(model))
95517
96802
  return null;
95518
- if (!isRecord7(provider))
96803
+ if (!isRecord8(provider))
95519
96804
  return null;
95520
- if (!isRecord7(message))
96805
+ if (!isRecord8(message))
95521
96806
  return null;
95522
96807
  const providerID = model.providerID;
95523
96808
  const modelID = model.modelID;
@@ -95538,12 +96823,12 @@ function buildChatParamsInput(raw) {
95538
96823
  };
95539
96824
  }
95540
96825
  function isChatParamsOutput(raw) {
95541
- if (!isRecord7(raw))
96826
+ if (!isRecord8(raw))
95542
96827
  return false;
95543
- if (!isRecord7(raw.options)) {
96828
+ if (!isRecord8(raw.options)) {
95544
96829
  raw.options = {};
95545
96830
  }
95546
- return isRecord7(raw.options);
96831
+ return isRecord8(raw.options);
95547
96832
  }
95548
96833
  function createChatParamsHandler(args) {
95549
96834
  return async (input, output) => {
@@ -95561,6 +96846,9 @@ function createChatParamsHandler(args) {
95561
96846
  };
95562
96847
  }
95563
96848
 
96849
+ // src/plugin/event.ts
96850
+ init_logger();
96851
+
95564
96852
  // src/plugin/recent-synthetic-idles.ts
95565
96853
  function pruneRecentSyntheticIdles(args) {
95566
96854
  const { recentSyntheticIdles, recentRealIdles, now, dedupWindowMs } = args;
@@ -95618,7 +96906,7 @@ function createEventHandler2(args) {
95618
96906
  await Promise.resolve(hooks2.matrixLoop?.event?.(input));
95619
96907
  await Promise.resolve(hooks2.stopContinuationGuard?.event?.(input));
95620
96908
  await Promise.resolve(hooks2.compactionTodoPreserver?.event?.(input));
95621
- await Promise.resolve(hooks2.atlasHook?.handler?.(input));
96909
+ await Promise.resolve(hooks2.architectHook?.handler?.(input));
95622
96910
  };
95623
96911
  const recentSyntheticIdles = new Map;
95624
96912
  const recentRealIdles = new Map;
@@ -95704,7 +96992,9 @@ function createEventHandler2(args) {
95704
96992
  path: { id: sessionID },
95705
96993
  body: { parts: [{ type: "text", text: "continue" }] },
95706
96994
  query: { directory: ctx.directory }
95707
- }).catch(() => {});
96995
+ }).catch((err) => {
96996
+ log("[plugin] Session prompt failed:", err);
96997
+ });
95708
96998
  }
95709
96999
  }
95710
97000
  }
@@ -95803,7 +97093,7 @@ function createToolExecuteAfterHandler2(args) {
95803
97093
  await hooks2.interactiveBashSession?.["tool.execute.after"]?.(input, output);
95804
97094
  await hooks2.editErrorRecovery?.["tool.execute.after"]?.(input, output);
95805
97095
  await hooks2.delegateTaskRetry?.["tool.execute.after"]?.(input, output);
95806
- await hooks2.atlasHook?.["tool.execute.after"]?.(input, output);
97096
+ await hooks2.architectHook?.["tool.execute.after"]?.(input, output);
95807
97097
  await hooks2.taskResumeInfo?.["tool.execute.after"]?.(input, output);
95808
97098
  await hooks2.hashlineReadEnhancer?.["tool.execute.after"]?.(input, output);
95809
97099
  await hooks2.jsonErrorRecovery?.["tool.execute.after"]?.(input, output);
@@ -95818,6 +97108,25 @@ function createToolExecuteAfterHandler2(args) {
95818
97108
  };
95819
97109
  }
95820
97110
 
97111
+ // src/features/assembly-state/manager.ts
97112
+ init_logger();
97113
+ var HOOK_NAME15 = "assembly-state";
97114
+ var disabledSessions = new Set;
97115
+ function isAssemblyDisabled(sessionID) {
97116
+ return disabledSessions.has(sessionID);
97117
+ }
97118
+ function disableAssembly(sessionID) {
97119
+ disabledSessions.add(sessionID);
97120
+ log(`[${HOOK_NAME15}] Assembly disabled for session`, { sessionID });
97121
+ disabledSessions.add(sessionID);
97122
+ log(`[${HOOK_NAME15}] Consensus disabled for session`, { sessionID });
97123
+ }
97124
+ function enableAssembly(sessionID) {
97125
+ disabledSessions.delete(sessionID);
97126
+ log(`[${HOOK_NAME15}] Assembly enabled for session`, { sessionID });
97127
+ disabledSessions.delete(sessionID);
97128
+ log(`[${HOOK_NAME15}] Consensus enabled for session`, { sessionID });
97129
+ }
95821
97130
  // src/plugin/session-agent-resolver.ts
95822
97131
  async function resolveSessionAgent(client2, sessionId, timeoutMs = 5000) {
95823
97132
  try {
@@ -95862,8 +97171,8 @@ function createToolExecuteBeforeHandler2(args) {
95862
97171
  const nonInteractiveEnvHook = hooks2.nonInteractiveEnv?.["tool.execute.before"];
95863
97172
  const bashFileReadGuardHook = hooks2.bashFileReadGuard?.["tool.execute.before"];
95864
97173
  const questionLabelTruncatorHook = hooks2.questionLabelTruncator?.["tool.execute.before"];
95865
- const sisyphusJuniorNotepadHook = hooks2.sisyphusJuniorNotepad?.["tool.execute.before"];
95866
- const atlasHookHook = hooks2.atlasHook?.["tool.execute.before"];
97174
+ const mouseNotepadHook = hooks2.mouseNotepad?.["tool.execute.before"];
97175
+ const architectHookHook = hooks2.architectHook?.["tool.execute.before"];
95867
97176
  return async (input, output) => {
95868
97177
  await Promise.all([
95869
97178
  qualityGateHook?.(input, output),
@@ -95895,8 +97204,8 @@ function createToolExecuteBeforeHandler2(args) {
95895
97204
  await bashFileReadGuardHook?.(input, output);
95896
97205
  await questionLabelTruncatorHook?.(input, output);
95897
97206
  await prometheusMdOnlyHook?.(input, output);
95898
- await sisyphusJuniorNotepadHook?.(input, output);
95899
- await atlasHookHook?.(input, output);
97207
+ await mouseNotepadHook?.(input, output);
97208
+ await architectHookHook?.(input, output);
95900
97209
  if (resolvePromise) {
95901
97210
  const resolvedAgent = await resolvePromise;
95902
97211
  output.args.subagent_type = resolvedAgent ?? "continue";
@@ -95940,6 +97249,32 @@ function createToolExecuteBeforeHandler2(args) {
95940
97249
  sessionID
95941
97250
  });
95942
97251
  }
97252
+ if (command === "assembly" && sessionID) {
97253
+ const subcommand = rawCommand?.replace(/^\/?assembly\s*/i, "").trim().toLowerCase();
97254
+ if (subcommand === "disable" || subcommand === "off") {
97255
+ disableAssembly(sessionID);
97256
+ } else if (subcommand === "enable" || subcommand === "on") {
97257
+ enableAssembly(sessionID);
97258
+ } else {
97259
+ const state3 = isAssemblyDisabled(sessionID) ? "disabled" : "enabled";
97260
+ log("[assembly] Assembly state check", { sessionID, state: state3 });
97261
+ }
97262
+ }
97263
+ if (command === "ultrawork" && sessionID) {
97264
+ const subcommand = rawCommand?.replace(/^\/?ultrawork\s*/i, "").trim().toLowerCase();
97265
+ if (subcommand === "disable" || subcommand === "off") {
97266
+ disableUltrawork(sessionID);
97267
+ } else if (subcommand === "enable" || subcommand === "on") {
97268
+ enableUltrawork(sessionID);
97269
+ } else {
97270
+ const state3 = getUltraworkState(sessionID) ?? "default (keyword-triggered)";
97271
+ log("[ultrawork] Ultrawork state check", { sessionID, state: state3 });
97272
+ }
97273
+ }
97274
+ if (command === "end-ultrawork" && sessionID) {
97275
+ disableUltrawork(sessionID);
97276
+ log("[end-ultrawork] Ultrawork disabled via /end-ultrawork", { sessionID });
97277
+ }
95943
97278
  }
95944
97279
  };
95945
97280
  }