@kl-c/matrixos 0.1.7 → 0.1.9

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 (123) hide show
  1. package/.agents/command/adopt.md +50 -0
  2. package/.agents/command/features.md +35 -0
  3. package/.opencode/command/adopt.md +50 -0
  4. package/.opencode/command/features.md +35 -0
  5. package/dist/cli/config-manager/write-gateway-env.d.ts +7 -0
  6. package/dist/cli/index.js +941 -788
  7. package/dist/cli/install-validators.d.ts +1 -0
  8. package/dist/cli/skills/debugging/references/methodology/02-investigate.md +1 -1
  9. package/dist/cli/skills/refactor/SKILL.md +1 -1
  10. package/dist/cli/skills/superpowers-brainstorming/SKILL.md +162 -0
  11. package/dist/cli/skills/superpowers-brainstorming/SUPERPOWERS_LICENSE +21 -0
  12. package/dist/cli/skills/superpowers-brainstorming/scripts/frame-template.html +213 -0
  13. package/dist/cli/skills/superpowers-brainstorming/scripts/helper.js +167 -0
  14. package/dist/cli/skills/superpowers-brainstorming/scripts/server.cjs +723 -0
  15. package/dist/cli/skills/superpowers-brainstorming/scripts/start-server.sh +209 -0
  16. package/dist/cli/skills/superpowers-brainstorming/scripts/stop-server.sh +120 -0
  17. package/dist/cli/skills/superpowers-brainstorming/spec-document-reviewer-prompt.md +49 -0
  18. package/dist/cli/skills/superpowers-brainstorming/visual-companion.md +291 -0
  19. package/dist/cli/skills/superpowers-receiving-code-review/SKILL.md +216 -0
  20. package/dist/cli/skills/superpowers-receiving-code-review/SUPERPOWERS_LICENSE +21 -0
  21. package/dist/cli/skills/superpowers-systematic-debugging/CREATION-LOG.md +119 -0
  22. package/dist/cli/skills/superpowers-systematic-debugging/SKILL.md +299 -0
  23. package/dist/cli/skills/superpowers-systematic-debugging/SUPERPOWERS_LICENSE +21 -0
  24. package/dist/cli/skills/superpowers-systematic-debugging/condition-based-waiting-example.ts +158 -0
  25. package/dist/cli/skills/superpowers-systematic-debugging/condition-based-waiting.md +115 -0
  26. package/dist/cli/skills/superpowers-systematic-debugging/defense-in-depth.md +122 -0
  27. package/dist/cli/skills/superpowers-systematic-debugging/find-polluter.sh +63 -0
  28. package/dist/cli/skills/superpowers-systematic-debugging/root-cause-tracing.md +169 -0
  29. package/dist/cli/skills/superpowers-systematic-debugging/test-academic.md +14 -0
  30. package/dist/cli/skills/superpowers-systematic-debugging/test-pressure-1.md +58 -0
  31. package/dist/cli/skills/superpowers-systematic-debugging/test-pressure-2.md +68 -0
  32. package/dist/cli/skills/superpowers-systematic-debugging/test-pressure-3.md +69 -0
  33. package/dist/cli/skills/superpowers-writing-skills/SKILL.md +692 -0
  34. package/dist/cli/skills/superpowers-writing-skills/SUPERPOWERS_LICENSE +21 -0
  35. package/dist/cli/skills/superpowers-writing-skills/anthropic-best-practices.md +1150 -0
  36. package/dist/cli/skills/superpowers-writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  37. package/dist/cli/skills/superpowers-writing-skills/graphviz-conventions.dot +172 -0
  38. package/dist/cli/skills/superpowers-writing-skills/persuasion-principles.md +187 -0
  39. package/dist/cli/skills/superpowers-writing-skills/render-graphs.js +168 -0
  40. package/dist/cli/skills/superpowers-writing-skills/testing-skills-with-subagents.md +384 -0
  41. package/dist/cli/types.d.ts +4 -0
  42. package/dist/cli-node/index.js +941 -788
  43. package/dist/config/schema/oh-my-opencode-config.d.ts +6 -0
  44. package/dist/config/schema/watchdog.d.ts +6 -0
  45. package/dist/features/anti-loop/background-registry.d.ts +10 -0
  46. package/dist/features/dashboard/frontend/css/style.css +211 -0
  47. package/dist/features/dashboard/frontend/index.html +173 -0
  48. package/dist/features/dashboard/frontend/js/api.js +2 -0
  49. package/dist/features/dashboard/frontend/js/app.js +349 -0
  50. package/dist/features/matrix-inventory/features.d.ts +45 -0
  51. package/dist/hooks/agent-anti-loop/hook.d.ts +16 -0
  52. package/dist/index.js +220 -45
  53. package/dist/oh-my-opencode.schema.json +42 -0
  54. package/dist/plugin/agent-anti-loop.d.ts +6 -0
  55. package/dist/skills/debugging/references/methodology/02-investigate.md +1 -1
  56. package/dist/skills/refactor/SKILL.md +1 -1
  57. package/dist/skills/superpowers-brainstorming/SKILL.md +162 -0
  58. package/dist/skills/superpowers-brainstorming/SUPERPOWERS_LICENSE +21 -0
  59. package/dist/skills/superpowers-brainstorming/scripts/frame-template.html +213 -0
  60. package/dist/skills/superpowers-brainstorming/scripts/helper.js +167 -0
  61. package/dist/skills/superpowers-brainstorming/scripts/server.cjs +723 -0
  62. package/dist/skills/superpowers-brainstorming/scripts/start-server.sh +209 -0
  63. package/dist/skills/superpowers-brainstorming/scripts/stop-server.sh +120 -0
  64. package/dist/skills/superpowers-brainstorming/spec-document-reviewer-prompt.md +49 -0
  65. package/dist/skills/superpowers-brainstorming/visual-companion.md +291 -0
  66. package/dist/skills/superpowers-receiving-code-review/SKILL.md +216 -0
  67. package/dist/skills/superpowers-receiving-code-review/SUPERPOWERS_LICENSE +21 -0
  68. package/dist/skills/superpowers-systematic-debugging/CREATION-LOG.md +119 -0
  69. package/dist/skills/superpowers-systematic-debugging/SKILL.md +299 -0
  70. package/dist/skills/superpowers-systematic-debugging/SUPERPOWERS_LICENSE +21 -0
  71. package/dist/skills/superpowers-systematic-debugging/condition-based-waiting-example.ts +158 -0
  72. package/dist/skills/superpowers-systematic-debugging/condition-based-waiting.md +115 -0
  73. package/dist/skills/superpowers-systematic-debugging/defense-in-depth.md +122 -0
  74. package/dist/skills/superpowers-systematic-debugging/find-polluter.sh +63 -0
  75. package/dist/skills/superpowers-systematic-debugging/root-cause-tracing.md +169 -0
  76. package/dist/skills/superpowers-systematic-debugging/test-academic.md +14 -0
  77. package/dist/skills/superpowers-systematic-debugging/test-pressure-1.md +58 -0
  78. package/dist/skills/superpowers-systematic-debugging/test-pressure-2.md +68 -0
  79. package/dist/skills/superpowers-systematic-debugging/test-pressure-3.md +69 -0
  80. package/dist/skills/superpowers-writing-skills/SKILL.md +692 -0
  81. package/dist/skills/superpowers-writing-skills/SUPERPOWERS_LICENSE +21 -0
  82. package/dist/skills/superpowers-writing-skills/anthropic-best-practices.md +1150 -0
  83. package/dist/skills/superpowers-writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  84. package/dist/skills/superpowers-writing-skills/graphviz-conventions.dot +172 -0
  85. package/dist/skills/superpowers-writing-skills/persuasion-principles.md +187 -0
  86. package/dist/skills/superpowers-writing-skills/render-graphs.js +168 -0
  87. package/dist/skills/superpowers-writing-skills/testing-skills-with-subagents.md +384 -0
  88. package/dist/testing/create-gateway-relay.d.ts +26 -0
  89. package/dist/tui.js +13 -0
  90. package/package.json +2 -1
  91. package/packages/shared-skills/skills/debugging/references/methodology/02-investigate.md +1 -1
  92. package/packages/shared-skills/skills/refactor/SKILL.md +1 -1
  93. package/packages/shared-skills/skills/superpowers-brainstorming/SKILL.md +162 -0
  94. package/packages/shared-skills/skills/superpowers-brainstorming/SUPERPOWERS_LICENSE +21 -0
  95. package/packages/shared-skills/skills/superpowers-brainstorming/scripts/frame-template.html +213 -0
  96. package/packages/shared-skills/skills/superpowers-brainstorming/scripts/helper.js +167 -0
  97. package/packages/shared-skills/skills/superpowers-brainstorming/scripts/server.cjs +723 -0
  98. package/packages/shared-skills/skills/superpowers-brainstorming/scripts/start-server.sh +209 -0
  99. package/packages/shared-skills/skills/superpowers-brainstorming/scripts/stop-server.sh +120 -0
  100. package/packages/shared-skills/skills/superpowers-brainstorming/spec-document-reviewer-prompt.md +49 -0
  101. package/packages/shared-skills/skills/superpowers-brainstorming/visual-companion.md +291 -0
  102. package/packages/shared-skills/skills/superpowers-receiving-code-review/SKILL.md +216 -0
  103. package/packages/shared-skills/skills/superpowers-receiving-code-review/SUPERPOWERS_LICENSE +21 -0
  104. package/packages/shared-skills/skills/superpowers-systematic-debugging/CREATION-LOG.md +119 -0
  105. package/packages/shared-skills/skills/superpowers-systematic-debugging/SKILL.md +299 -0
  106. package/packages/shared-skills/skills/superpowers-systematic-debugging/SUPERPOWERS_LICENSE +21 -0
  107. package/packages/shared-skills/skills/superpowers-systematic-debugging/condition-based-waiting-example.ts +158 -0
  108. package/packages/shared-skills/skills/superpowers-systematic-debugging/condition-based-waiting.md +115 -0
  109. package/packages/shared-skills/skills/superpowers-systematic-debugging/defense-in-depth.md +122 -0
  110. package/packages/shared-skills/skills/superpowers-systematic-debugging/find-polluter.sh +63 -0
  111. package/packages/shared-skills/skills/superpowers-systematic-debugging/root-cause-tracing.md +169 -0
  112. package/packages/shared-skills/skills/superpowers-systematic-debugging/test-academic.md +14 -0
  113. package/packages/shared-skills/skills/superpowers-systematic-debugging/test-pressure-1.md +58 -0
  114. package/packages/shared-skills/skills/superpowers-systematic-debugging/test-pressure-2.md +68 -0
  115. package/packages/shared-skills/skills/superpowers-systematic-debugging/test-pressure-3.md +69 -0
  116. package/packages/shared-skills/skills/superpowers-writing-skills/SKILL.md +692 -0
  117. package/packages/shared-skills/skills/superpowers-writing-skills/SUPERPOWERS_LICENSE +21 -0
  118. package/packages/shared-skills/skills/superpowers-writing-skills/anthropic-best-practices.md +1150 -0
  119. package/packages/shared-skills/skills/superpowers-writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  120. package/packages/shared-skills/skills/superpowers-writing-skills/graphviz-conventions.dot +172 -0
  121. package/packages/shared-skills/skills/superpowers-writing-skills/persuasion-principles.md +187 -0
  122. package/packages/shared-skills/skills/superpowers-writing-skills/render-graphs.js +168 -0
  123. package/packages/shared-skills/skills/superpowers-writing-skills/testing-skills-with-subagents.md +384 -0
package/dist/index.js CHANGED
@@ -263536,10 +263536,10 @@ var require_on_exit_leak_free = __commonJS((exports, module) => {
263536
263536
  exit: onExit,
263537
263537
  beforeExit: onBeforeExit
263538
263538
  };
263539
- var registry2;
263539
+ var registry3;
263540
263540
  function ensureRegistry() {
263541
- if (registry2 === undefined) {
263542
- registry2 = new FinalizationRegistry(clear);
263541
+ if (registry3 === undefined) {
263542
+ registry3 = new FinalizationRegistry(clear);
263543
263543
  }
263544
263544
  }
263545
263545
  function install(event) {
@@ -263554,7 +263554,7 @@ var require_on_exit_leak_free = __commonJS((exports, module) => {
263554
263554
  }
263555
263555
  process.removeListener(event, functions[event]);
263556
263556
  if (refs.exit.length === 0 && refs.beforeExit.length === 0) {
263557
- registry2 = undefined;
263557
+ registry3 = undefined;
263558
263558
  }
263559
263559
  }
263560
263560
  function onExit() {
@@ -263588,7 +263588,7 @@ var require_on_exit_leak_free = __commonJS((exports, module) => {
263588
263588
  const ref = new WeakRef(obj);
263589
263589
  ref.fn = fn;
263590
263590
  ensureRegistry();
263591
- registry2.register(obj, ref);
263591
+ registry3.register(obj, ref);
263592
263592
  refs[event].push(ref);
263593
263593
  }
263594
263594
  function register(obj, fn) {
@@ -263598,10 +263598,10 @@ var require_on_exit_leak_free = __commonJS((exports, module) => {
263598
263598
  _register("beforeExit", obj, fn);
263599
263599
  }
263600
263600
  function unregister(obj) {
263601
- if (registry2 === undefined) {
263601
+ if (registry3 === undefined) {
263602
263602
  return;
263603
263603
  }
263604
- registry2.unregister(obj);
263604
+ registry3.unregister(obj);
263605
263605
  for (const event of ["exit", "beforeExit"]) {
263606
263606
  refs[event] = refs[event].filter((ref) => {
263607
263607
  const _obj = ref.deref();
@@ -263787,7 +263787,7 @@ var require_thread_stream = __commonJS((exports, module) => {
263787
263787
  }
263788
263788
  var FinalizationRegistry2 = process.env.NODE_V8_COVERAGE ? FakeFinalizationRegistry : global.FinalizationRegistry || FakeFinalizationRegistry;
263789
263789
  var WeakRef2 = process.env.NODE_V8_COVERAGE ? FakeWeakRef : global.WeakRef || FakeWeakRef;
263790
- var registry2 = new FinalizationRegistry2((worker) => {
263790
+ var registry3 = new FinalizationRegistry2((worker) => {
263791
263791
  if (worker.exited) {
263792
263792
  return;
263793
263793
  }
@@ -263815,7 +263815,7 @@ var require_thread_stream = __commonJS((exports, module) => {
263815
263815
  worker.stream = new FakeWeakRef(stream3);
263816
263816
  worker.on("message", onWorkerMessage);
263817
263817
  worker.on("exit", onWorkerExit);
263818
- registry2.register(stream3, worker);
263818
+ registry3.register(stream3, worker);
263819
263819
  return worker;
263820
263820
  }
263821
263821
  function drain(stream3) {
@@ -263918,7 +263918,7 @@ var require_thread_stream = __commonJS((exports, module) => {
263918
263918
  if (stream3 === undefined) {
263919
263919
  return;
263920
263920
  }
263921
- registry2.unregister(stream3);
263921
+ registry3.unregister(stream3);
263922
263922
  stream3.worker.exited = true;
263923
263923
  stream3.worker.off("exit", onWorkerExit);
263924
263924
  destroy(stream3, code !== 0 ? new Error("the worker thread exited") : null);
@@ -297388,10 +297388,10 @@ var init_loader2 = __esm(() => {
297388
297388
 
297389
297389
  // packages/omo-config-core/src/loader/profile-resolution.ts
297390
297390
  function registryLookup(config3, name) {
297391
- const registry2 = config3.profileRegistry;
297392
- if (!registry2)
297391
+ const registry3 = config3.profileRegistry;
297392
+ if (!registry3)
297393
297393
  return;
297394
- const found = registry2.profiles[name];
297394
+ const found = registry3.profiles[name];
297395
297395
  if (!found)
297396
297396
  return;
297397
297397
  const parsed = ProfileSchema.safeParse(found);
@@ -367932,7 +367932,7 @@ function getCachedVersion(options = {}) {
367932
367932
  // package.json
367933
367933
  var package_default = {
367934
367934
  name: "@kl-c/matrixos",
367935
- version: "0.1.7",
367935
+ version: "0.1.9",
367936
367936
  description: "MaTrixOS \u2014 Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
367937
367937
  main: "./dist/index.js",
367938
367938
  types: "dist/index.d.ts",
@@ -368012,6 +368012,7 @@ var package_default = {
368012
368012
  scripts: {
368013
368013
  build: "bun run script/build.ts",
368014
368014
  "build:cli-node": "bun run script/build-cli-node.ts",
368015
+ "build:dashboard-frontend": "rm -rf dist/features/dashboard/frontend && mkdir -p dist/features/dashboard/frontend && cp -R packages/omo-opencode/src/features/dashboard/frontend/. dist/features/dashboard/frontend/",
368015
368016
  "build:shared-skills-assets": "rm -rf dist/skills && cp -R packages/shared-skills/skills dist/skills && mkdir -p dist/cli && rm -rf dist/cli/skills && cp -R packages/shared-skills/skills dist/cli/skills",
368016
368017
  "build:lsp-tools-mcp": "npm --prefix packages/lsp-tools-mcp ci && npm --prefix packages/lsp-tools-mcp run build",
368017
368018
  "build:lsp-daemon": "npm --prefix packages/lsp-daemon ci && npm --prefix packages/lsp-daemon run build",
@@ -441333,7 +441334,11 @@ function createAgentAntiLoopHooks(config) {
441333
441334
  nudged: false,
441334
441335
  fallbackTriggered: false,
441335
441336
  avoidanceCount: 0,
441336
- avoidanceEscalated: false
441337
+ avoidanceEscalated: false,
441338
+ hookExecutionTimestamps: [],
441339
+ hookRecursionBreachedAt: 0,
441340
+ contextTokens: 0,
441341
+ contextBloatBreachedAt: 0
441337
441342
  };
441338
441343
  function makeSignature(tool3, args) {
441339
441344
  try {
@@ -441386,6 +441391,25 @@ function createAgentAntiLoopHooks(config) {
441386
441391
  const elapsed = now - state3.lastMeaningfulToolAt;
441387
441392
  return { stuck: elapsed >= config.stuckTimeoutSec * 1000, secondsSinceLastMeaningful: Math.floor(elapsed / 1000) };
441388
441393
  },
441394
+ onHookExecute() {
441395
+ const now = Date.now();
441396
+ state3.hookExecutionTimestamps.push(now);
441397
+ const windowStart = now - config.hookRecursionWindowMs;
441398
+ state3.hookExecutionTimestamps = state3.hookExecutionTimestamps.filter((t2) => t2 >= windowStart);
441399
+ },
441400
+ isHookRecursion() {
441401
+ return state3.hookExecutionTimestamps.length >= config.hookRecursionThreshold;
441402
+ },
441403
+ onContextUpdate(tokens) {
441404
+ state3.contextTokens = tokens;
441405
+ },
441406
+ isContextBloat() {
441407
+ const now = Date.now();
441408
+ const elapsedSinceMeaningful = now - state3.lastMeaningfulToolAt;
441409
+ const bloated = state3.contextTokens >= config.contextBloatMaxTokens;
441410
+ const stale = elapsedSinceMeaningful >= config.contextBloatStuckSec * 1000;
441411
+ return bloated && stale;
441412
+ },
441389
441413
  reset() {
441390
441414
  state3.consecutiveBySignature.clear();
441391
441415
  state3.recentSignatures = [];
@@ -441394,6 +441418,10 @@ function createAgentAntiLoopHooks(config) {
441394
441418
  state3.fallbackTriggered = false;
441395
441419
  state3.avoidanceCount = 0;
441396
441420
  state3.avoidanceEscalated = false;
441421
+ state3.hookExecutionTimestamps = [];
441422
+ state3.hookRecursionBreachedAt = 0;
441423
+ state3.contextTokens = 0;
441424
+ state3.contextBloatBreachedAt = 0;
441397
441425
  },
441398
441426
  getState() {
441399
441427
  return { ...state3, consecutiveBySignature: new Map(state3.consecutiveBySignature), recentSignatures: [...state3.recentSignatures] };
@@ -441424,6 +441452,12 @@ function createAntiLoopLogger(logsDir) {
441424
441452
  };
441425
441453
  }
441426
441454
 
441455
+ // packages/omo-opencode/src/features/anti-loop/background-registry.ts
441456
+ var registry2 = new Map;
441457
+ function getRunningTasks() {
441458
+ return [...registry2.values()].filter((r) => r.status === "running");
441459
+ }
441460
+
441427
441461
  // packages/omo-opencode/src/plugin/agent-anti-loop.ts
441428
441462
  import { join as join135 } from "path";
441429
441463
  function createAgentAntiLoopWiring(config, deps) {
@@ -441470,9 +441504,62 @@ function createAgentAntiLoopWiring(config, deps) {
441470
441504
  if (config.recoveryStrategy === "nudge" && deps.injectNudge) {
441471
441505
  deps.injectNudge(`Watchdog: no progress for ${secondsSinceLastMeaningful}s. Try a different approach.`);
441472
441506
  }
441507
+ const running = getRunningTasks();
441508
+ if (running.length > 0) {
441509
+ const ids = running.map((r) => r.taskId).join(", ");
441510
+ deps.log("[agent-anti-loop] zombie session detected", { runningTasks: ids });
441511
+ antiLoopLog.log({ sessionId: process.env.OMO_SESSION_ID, pattern: "zombie_session", detail: `Session idle but ${running.length} background task(s) running: ${ids}`, actionTaken: config.recoveryStrategy });
441512
+ if (deps.injectNudge) {
441513
+ deps.injectNudge(`Watchdog: session idle but background task(s) still running (${ids}). Check for orphaned work.`);
441514
+ }
441515
+ }
441473
441516
  },
441474
441517
  sessionCreated() {
441475
441518
  hooks.reset();
441519
+ },
441520
+ onHookExecute() {
441521
+ hooks.onHookExecute();
441522
+ if (hooks.isHookRecursion()) {
441523
+ const now = Date.now();
441524
+ const state3 = hooks.getState();
441525
+ if (now - state3.hookRecursionBreachedAt > config.hookRecursionWindowMs) {
441526
+ state3.hookRecursionBreachedAt = now;
441527
+ deps.log("[agent-anti-loop] hook recursion detected", { count: state3.hookExecutionTimestamps.length, windowMs: config.hookRecursionWindowMs });
441528
+ antiLoopLog.log({ sessionId: process.env.OMO_SESSION_ID, pattern: "hook_recursion", detail: `${state3.hookExecutionTimestamps.length} hook executions within ${config.hookRecursionWindowMs}ms`, actionTaken: config.recoveryStrategy });
441529
+ if (deps.injectNudge) {
441530
+ deps.injectNudge("Watchdog: hook recursion detected. A hook is re-triggering itself in a loop.");
441531
+ }
441532
+ }
441533
+ }
441534
+ },
441535
+ onContextUpdate(tokens) {
441536
+ hooks.onContextUpdate(tokens);
441537
+ if (hooks.isContextBloat()) {
441538
+ const now = Date.now();
441539
+ const state3 = hooks.getState();
441540
+ if (now - state3.contextBloatBreachedAt > config.contextBloatStuckSec * 1000) {
441541
+ state3.contextBloatBreachedAt = now;
441542
+ deps.log("[agent-anti-loop] context bloat detected", { tokens, threshold: config.contextBloatMaxTokens });
441543
+ antiLoopLog.log({ sessionId: process.env.OMO_SESSION_ID, pattern: "context_bloat", detail: `Context ${tokens} tokens >= ${config.contextBloatMaxTokens} with no progress for ${config.contextBloatStuckSec}s`, actionTaken: config.recoveryStrategy });
441544
+ if (deps.injectNudge) {
441545
+ deps.injectNudge(`Watchdog: context bloat (${tokens} tokens) without progress. Consider compacting or clearing context.`);
441546
+ }
441547
+ }
441548
+ }
441549
+ },
441550
+ backgroundTaskCheck() {
441551
+ const running = getRunningTasks();
441552
+ const now = Date.now();
441553
+ for (const task of running) {
441554
+ const ageMs = now - task.startedAt;
441555
+ if (ageMs >= config.runawayTaskTimeoutSec * 1000) {
441556
+ deps.log("[agent-anti-loop] runaway task detected", { taskId: task.taskId, ageSec: Math.floor(ageMs / 1000) });
441557
+ antiLoopLog.log({ sessionId: process.env.OMO_SESSION_ID, pattern: "runaway_task", toolName: task.taskId, detail: `Background task running ${Math.floor(ageMs / 1000)}s >= ${config.runawayTaskTimeoutSec}s`, actionTaken: config.recoveryStrategy });
441558
+ if (deps.injectNudge) {
441559
+ deps.injectNudge(`Watchdog: background task ${task.taskId} has been running ${Math.floor(ageMs / 1000)}s without completing.`);
441560
+ }
441561
+ }
441562
+ }
441476
441563
  }
441477
441564
  };
441478
441565
  }
@@ -442765,6 +442852,13 @@ class MatrixGateway {
442765
442852
  async stop() {
442766
442853
  await Promise.all(Array.from(this.adapters.values()).map((a) => a.disconnect()));
442767
442854
  }
442855
+ async send(env2) {
442856
+ const adapter = this.adapters.get(env2.channel);
442857
+ if (!adapter) {
442858
+ throw new Error(`no adapter registered for channel "${env2.channel}"`);
442859
+ }
442860
+ return adapter.send(env2);
442861
+ }
442768
442862
  async handleInbound(env2) {
442769
442863
  if (this.seenIds.has(env2.id)) {
442770
442864
  return;
@@ -443466,6 +443560,12 @@ var WatchdogConfigSchema = z54.object({
443466
443560
  stuckTimeoutSec: z54.number().int().positive().max(600).default(90),
443467
443561
  auditLogPath: z54.string().optional(),
443468
443562
  recoveryStrategy: z54.enum(["nudge", "fallback", "restart", "notify", "safe"]).default("nudge"),
443563
+ hookRecursionWindowMs: z54.number().int().positive().max(60000).default(5000),
443564
+ hookRecursionThreshold: z54.number().int().positive().max(100).default(10),
443565
+ contextBloatMaxTokens: z54.number().int().positive().default(200000),
443566
+ contextBloatStuckSec: z54.number().int().positive().max(600).default(120),
443567
+ zombieSessionIdleSec: z54.number().int().positive().max(600).default(90),
443568
+ runawayTaskTimeoutSec: z54.number().int().positive().max(86400).default(600),
443469
443569
  heartbeatIntervalSec: z54.number().positive().max(300).default(30),
443470
443570
  heartbeatFilePath: z54.string().default(".matrixos/tmp/heartbeat"),
443471
443571
  fatalMarkerPath: z54.string().default(".matrixos/tmp/watchdog-fatal.json"),
@@ -451039,6 +451139,78 @@ function recordPluginTelemetry(input2) {
451039
451139
  posthog.shutdown();
451040
451140
  }
451041
451141
 
451142
+ // packages/omo-opencode/src/testing/create-gateway-relay.ts
451143
+ function createGatewayRelayHandler(deps) {
451144
+ const { input: input2, gateway, log: log8 } = deps;
451145
+ return async (env2) => {
451146
+ const inboundText = env2.content.text;
451147
+ if (!inboundText) {
451148
+ log8("[gateway] ignoring non-text inbound message", { channel: env2.channel });
451149
+ return;
451150
+ }
451151
+ log8("[gateway] inbound message \u2192 relaying to Morpheus", {
451152
+ channel: env2.channel,
451153
+ from: env2.sender.id,
451154
+ text: inboundText.slice(0, 200)
451155
+ });
451156
+ try {
451157
+ const createResult = await input2.client.session.create({
451158
+ body: {
451159
+ title: `Gateway relay (${env2.channel})`,
451160
+ parentID: undefined
451161
+ }
451162
+ });
451163
+ const sessionID = createResult.data?.id;
451164
+ if (!sessionID)
451165
+ throw new Error("session create returned no id");
451166
+ await input2.client.session.prompt({
451167
+ path: { id: sessionID },
451168
+ body: {
451169
+ agent: "morpheus",
451170
+ parts: [{ type: "text", text: inboundText }]
451171
+ },
451172
+ query: { directory: input2.directory }
451173
+ });
451174
+ await waitForCompletion(sessionID, { sessionID, messageID: "", agent: "morpheus", abort: new AbortController().signal }, input2);
451175
+ const reply = await processMessages(sessionID, input2);
451176
+ await gateway.send({
451177
+ id: makeEnvelopeId(env2.channel, env2.metadata.providerMessageId),
451178
+ channel: env2.channel,
451179
+ direction: "outbound",
451180
+ timestamp: new Date().toISOString(),
451181
+ sender: env2.sender,
451182
+ recipient: { id: env2.sender.id },
451183
+ content: { type: "text", text: reply },
451184
+ metadata: {
451185
+ providerMessageId: env2.metadata.providerMessageId,
451186
+ raw: null,
451187
+ isGroup: env2.metadata.isGroup
451188
+ }
451189
+ });
451190
+ deps.log("[gateway] reply sent", { channel: env2.channel, to: env2.sender.id });
451191
+ } catch (relayError) {
451192
+ const detail = relayError instanceof Error ? relayError.message : String(relayError);
451193
+ log8("[gateway] relay failed", { detail });
451194
+ try {
451195
+ await gateway.send({
451196
+ id: makeEnvelopeId(env2.channel, env2.metadata.providerMessageId),
451197
+ channel: env2.channel,
451198
+ direction: "outbound",
451199
+ timestamp: new Date().toISOString(),
451200
+ sender: env2.sender,
451201
+ recipient: { id: env2.sender.id },
451202
+ content: { type: "text", text: `\u26A0\uFE0F Erreur de traitement: ${detail}` },
451203
+ metadata: {
451204
+ providerMessageId: env2.metadata.providerMessageId,
451205
+ raw: null,
451206
+ isGroup: env2.metadata.isGroup
451207
+ }
451208
+ });
451209
+ } catch {}
451210
+ }
451211
+ };
451212
+ }
451213
+
451042
451214
  // packages/daily-brief-core/src/schema.ts
451043
451215
  import * as z64 from "zod";
451044
451216
  var DailyBriefConfigSchema = z64.object({
@@ -451704,36 +451876,6 @@ function createPluginModule(overrides2 = {}) {
451704
451876
  }
451705
451877
  return out;
451706
451878
  }
451707
- if (pluginConfig.gateway?.enabled) {
451708
- try {
451709
- const gwConfig = pluginConfig.gateway;
451710
- gateway = new MatrixGateway(gwConfig, {
451711
- handler: async (env2) => {
451712
- deps.log("[gateway] inbound message", {
451713
- channel: env2.channel,
451714
- from: env2.sender.id,
451715
- text: env2.content.text
451716
- });
451717
- }
451718
- });
451719
- for (const ch of gwConfig.channels) {
451720
- if (ch.type === "telegram") {
451721
- const voice = buildTelegramVoice(ch);
451722
- gateway.registerAdapter(new TelegramAdapter(ch, undefined, voice));
451723
- } else if (ch.type === "discord") {
451724
- gateway.registerAdapter(new DiscordAdapter(ch));
451725
- } else if (ch.type === "whatsapp") {
451726
- gateway.registerAdapter(new WhatsAppAdapter(ch, undefined, { enabled: true }));
451727
- }
451728
- }
451729
- await gateway.start();
451730
- deps.log("[gateway] started", { channels: gwConfig.channels.map((c2) => c2.type) });
451731
- } catch (error) {
451732
- const detail = error instanceof Error ? error.message : String(error);
451733
- console.warn(`[gateway] failed to start: ${detail}`);
451734
- gateway = undefined;
451735
- }
451736
- }
451737
451879
  if (pluginConfig.cron?.enabled) {
451738
451880
  try {
451739
451881
  const cronStore = createCronStore();
@@ -451886,6 +452028,39 @@ function createPluginModule(overrides2 = {}) {
451886
452028
  mergedSkills: toolsResult.mergedSkills,
451887
452029
  availableSkills: toolsResult.availableSkills
451888
452030
  });
452031
+ if (pluginConfig.gateway?.enabled) {
452032
+ try {
452033
+ const gwConfig = pluginConfig.gateway;
452034
+ let gwInstance;
452035
+ gwInstance = new MatrixGateway(gwConfig, {
452036
+ handler: createGatewayRelayHandler({
452037
+ input: input2,
452038
+ gateway: gwInstance,
452039
+ log: deps.log
452040
+ })
452041
+ });
452042
+ gateway = gwInstance;
452043
+ for (const ch of gwConfig.channels) {
452044
+ if (ch.type === "telegram") {
452045
+ const voice = buildTelegramVoice(ch);
452046
+ gateway.registerAdapter(new TelegramAdapter(ch, undefined, voice));
452047
+ } else if (ch.type === "discord") {
452048
+ gateway.registerAdapter(new DiscordAdapter(ch));
452049
+ } else if (ch.type === "whatsapp") {
452050
+ gateway.registerAdapter(new WhatsAppAdapter(ch, undefined, { enabled: true }));
452051
+ }
452052
+ }
452053
+ await gateway.start();
452054
+ const gw = gateway;
452055
+ deps.log("[gateway] started \u2014 Telegram/Discord/WhatsApp relay active", {
452056
+ channels: gwConfig.channels.map((c2) => c2.type)
452057
+ });
452058
+ } catch (error) {
452059
+ const detail = error instanceof Error ? error.message : String(error);
452060
+ console.warn(`[gateway] failed to start: ${detail}`);
452061
+ gateway = undefined;
452062
+ }
452063
+ }
451889
452064
  let dreamerTrigger;
451890
452065
  const dreamerConfig = pluginConfig.dreamer;
451891
452066
  if (dreamerConfig?.enabled) {
@@ -7117,6 +7117,42 @@
7117
7117
  "safe"
7118
7118
  ]
7119
7119
  },
7120
+ "hookRecursionWindowMs": {
7121
+ "default": 5000,
7122
+ "type": "integer",
7123
+ "exclusiveMinimum": 0,
7124
+ "maximum": 60000
7125
+ },
7126
+ "hookRecursionThreshold": {
7127
+ "default": 10,
7128
+ "type": "integer",
7129
+ "exclusiveMinimum": 0,
7130
+ "maximum": 100
7131
+ },
7132
+ "contextBloatMaxTokens": {
7133
+ "default": 200000,
7134
+ "type": "integer",
7135
+ "exclusiveMinimum": 0,
7136
+ "maximum": 9007199254740991
7137
+ },
7138
+ "contextBloatStuckSec": {
7139
+ "default": 120,
7140
+ "type": "integer",
7141
+ "exclusiveMinimum": 0,
7142
+ "maximum": 600
7143
+ },
7144
+ "zombieSessionIdleSec": {
7145
+ "default": 90,
7146
+ "type": "integer",
7147
+ "exclusiveMinimum": 0,
7148
+ "maximum": 600
7149
+ },
7150
+ "runawayTaskTimeoutSec": {
7151
+ "default": 600,
7152
+ "type": "integer",
7153
+ "exclusiveMinimum": 0,
7154
+ "maximum": 86400
7155
+ },
7120
7156
  "heartbeatIntervalSec": {
7121
7157
  "default": 30,
7122
7158
  "type": "number",
@@ -7186,6 +7222,12 @@
7186
7222
  "softDoomLoopThreshold",
7187
7223
  "stuckTimeoutSec",
7188
7224
  "recoveryStrategy",
7225
+ "hookRecursionWindowMs",
7226
+ "hookRecursionThreshold",
7227
+ "contextBloatMaxTokens",
7228
+ "contextBloatStuckSec",
7229
+ "zombieSessionIdleSec",
7230
+ "runawayTaskTimeoutSec",
7189
7231
  "heartbeatIntervalSec",
7190
7232
  "heartbeatFilePath",
7191
7233
  "fatalMarkerPath",
@@ -13,5 +13,11 @@ export interface AgentAntiLoopWiring {
13
13
  sessionIdle: () => Promise<void>;
14
14
  sessionCreated: () => void;
15
15
  onAgentMessage: (content: string) => void;
16
+ /** Record a hook execution for recursion detection (§4.12 0.1.8). */
17
+ onHookExecute: () => void;
18
+ /** Update the estimated context size in tokens (§4.12 0.1.8). */
19
+ onContextUpdate: (tokens: number) => void;
20
+ /** Scan for zombie_session + runaway_task among running background tasks (§4.12 0.1.8). */
21
+ backgroundTaskCheck: () => void;
16
22
  }
17
23
  export declare function createAgentAntiLoopWiring(config: WatchdogConfig, deps: AgentAntiLoopDeps): AgentAntiLoopWiring;
@@ -50,7 +50,7 @@ When the `team_*` tools are present, create a **debug-squad** team and split inv
50
50
  ```json
51
51
  {
52
52
  "name": "debug-squad",
53
- "lead": { "kind": "subagent_type", "subagent_type": "sisyphus" },
53
+ "lead": { "kind": "subagent_type", "subagent_type": "morpheus" },
54
54
  "members": [
55
55
  {
56
56
  "kind": "category",
@@ -664,7 +664,7 @@ Record the chosen path in the TodoWrite list.
664
664
  \`\`\`json
665
665
  {
666
666
  "name": "refactor-squad",
667
- "lead": { "kind": "subagent_type", "subagent_type": "sisyphus" },
667
+ "lead": { "kind": "subagent_type", "subagent_type": "morpheus" },
668
668
  "members": [
669
669
  {
670
670
  "kind": "category",
@@ -0,0 +1,162 @@
1
+ ---
2
+ name: brainstorming
3
+ description: "You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation."
4
+ ---
5
+ > **Forked from [obra/superpowers](https://github.com/obra/superpowers) — MIT License, Copyright (c) 2025 Jesse Vincent.**
6
+ > Vendored as a native MaTrixOS skill. The original MIT license text is in `SUPERPOWERS_LICENSE` in this folder.
7
+ > Routing rule: MaTrixOS owns plan/execute/verify (ulw-plan, start-work, review-work). This skill is a complementary aid, invoked on demand.
8
+
9
+ # Brainstorming Ideas Into Designs
10
+
11
+ Help turn ideas into fully formed designs and specs through natural collaborative dialogue.
12
+
13
+ Start by understanding the current project context, then ask questions one at a time to refine the idea. Once you understand what you're building, present the design and get user approval.
14
+
15
+ <HARD-GATE>
16
+ Do NOT invoke any implementation skill, write any code, scaffold any project, or take any implementation action until you have presented a design and the user has approved it. This applies to EVERY project regardless of perceived simplicity.
17
+ </HARD-GATE>
18
+
19
+ ## Anti-Pattern: "This Is Too Simple To Need A Design"
20
+
21
+ Every project goes through this process. A todo list, a single-function utility, a config change — all of them. "Simple" projects are where unexamined assumptions cause the most wasted work. The design can be short (a few sentences for truly simple projects), but you MUST present it and get approval.
22
+
23
+ ## Checklist
24
+
25
+ You MUST create a task for each of these items and complete them in order:
26
+
27
+ 1. **Explore project context** — check files, docs, recent commits
28
+ 2. **Offer the visual companion just-in-time** — NOT upfront. The first time a question would genuinely be clearer shown than described, offer it then (its own message); on approval its browser tab opens for you. If no visual question ever arises, never offer it. See the Visual Companion section below.
29
+ 3. **Ask clarifying questions** — one at a time, understand purpose/constraints/success criteria
30
+ 4. **Propose 2-3 approaches** — with trade-offs and your recommendation
31
+ 5. **Present design** — in sections scaled to their complexity, get user approval after each section
32
+ 6. **Write design doc** — save to `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md` and commit
33
+ 7. **Spec self-review** — quick inline check for placeholders, contradictions, ambiguity, scope (see below)
34
+ 8. **User reviews written spec** — ask user to review the spec file before proceeding
35
+ 9. **Transition to implementation** — invoke writing-plans skill to create implementation plan
36
+
37
+ ## Process Flow
38
+
39
+ ```dot
40
+ digraph brainstorming {
41
+ "Explore project context" [shape=box];
42
+ "Ask clarifying questions" [shape=box];
43
+ "Propose 2-3 approaches" [shape=box];
44
+ "Present design sections" [shape=box];
45
+ "User approves design?" [shape=diamond];
46
+ "Write design doc" [shape=box];
47
+ "Spec self-review\n(fix inline)" [shape=box];
48
+ "User reviews spec?" [shape=diamond];
49
+ "Invoke writing-plans skill" [shape=doublecircle];
50
+
51
+ "Explore project context" -> "Ask clarifying questions";
52
+ "Ask clarifying questions" -> "Propose 2-3 approaches";
53
+ "Propose 2-3 approaches" -> "Present design sections";
54
+ "Present design sections" -> "User approves design?";
55
+ "User approves design?" -> "Present design sections" [label="no, revise"];
56
+ "User approves design?" -> "Write design doc" [label="yes"];
57
+ "Write design doc" -> "Spec self-review\n(fix inline)";
58
+ "Spec self-review\n(fix inline)" -> "User reviews spec?";
59
+ "User reviews spec?" -> "Write design doc" [label="changes requested"];
60
+ "User reviews spec?" -> "Invoke writing-plans skill" [label="approved"];
61
+ }
62
+ ```
63
+
64
+ **The terminal state is invoking writing-plans.** Do NOT invoke frontend-design, mcp-builder, or any other implementation skill. The ONLY skill you invoke after brainstorming is writing-plans.
65
+
66
+ ## The Process
67
+
68
+ **Understanding the idea:**
69
+
70
+ - Check out the current project state first (files, docs, recent commits)
71
+ - Before asking detailed questions, assess scope: if the request describes multiple independent subsystems (e.g., "build a platform with chat, file storage, billing, and analytics"), flag this immediately. Don't spend questions refining details of a project that needs to be decomposed first.
72
+ - If the project is too large for a single spec, help the user decompose into sub-projects: what are the independent pieces, how do they relate, what order should they be built? Then brainstorm the first sub-project through the normal design flow. Each sub-project gets its own spec → plan → implementation cycle.
73
+ - For appropriately-scoped projects, ask questions one at a time to refine the idea
74
+ - Prefer multiple choice questions when possible, but open-ended is fine too
75
+ - Only one question per message - if a topic needs more exploration, break it into multiple questions
76
+ - Focus on understanding: purpose, constraints, success criteria
77
+
78
+ **Exploring approaches:**
79
+
80
+ - Propose 2-3 different approaches with trade-offs
81
+ - Present options conversationally with your recommendation and reasoning
82
+ - Lead with your recommended option and explain why
83
+
84
+ **Presenting the design:**
85
+
86
+ - Once you believe you understand what you're building, present the design
87
+ - Scale each section to its complexity: a few sentences if straightforward, up to 200-300 words if nuanced
88
+ - Ask after each section whether it looks right so far
89
+ - Cover: architecture, components, data flow, error handling, testing
90
+ - Be ready to go back and clarify if something doesn't make sense
91
+
92
+ **Design for isolation and clarity:**
93
+
94
+ - Break the system into smaller units that each have one clear purpose, communicate through well-defined interfaces, and can be understood and tested independently
95
+ - For each unit, you should be able to answer: what does it do, how do you use it, and what does it depend on?
96
+ - Can someone understand what a unit does without reading its internals? Can you change the internals without breaking consumers? If not, the boundaries need work.
97
+ - Smaller, well-bounded units are also easier for you to work with - you reason better about code you can hold in context at once, and your edits are more reliable when files are focused. When a file grows large, that's often a signal that it's doing too much.
98
+
99
+ **Working in existing codebases:**
100
+
101
+ - Explore the current structure before proposing changes. Follow existing patterns.
102
+ - Where existing code has problems that affect the work (e.g., a file that's grown too large, unclear boundaries, tangled responsibilities), include targeted improvements as part of the design - the way a good developer improves code they're working in.
103
+ - Don't propose unrelated refactoring. Stay focused on what serves the current goal.
104
+
105
+ ## After the Design
106
+
107
+ **Documentation:**
108
+
109
+ - Write the validated design (spec) to `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md`
110
+ - (User preferences for spec location override this default)
111
+ - Use elements-of-style:writing-clearly-and-concisely skill if available
112
+ - Commit the design document to git
113
+
114
+ **Spec Self-Review:**
115
+ After writing the spec document, look at it with fresh eyes:
116
+
117
+ 1. **Placeholder scan:** Any "TBD", "TODO", incomplete sections, or vague requirements? Fix them.
118
+ 2. **Internal consistency:** Do any sections contradict each other? Does the architecture match the feature descriptions?
119
+ 3. **Scope check:** Is this focused enough for a single implementation plan, or does it need decomposition?
120
+ 4. **Ambiguity check:** Could any requirement be interpreted two different ways? If so, pick one and make it explicit.
121
+
122
+ Fix any issues inline. No need to re-review — just fix and move on.
123
+
124
+ **User Review Gate:**
125
+ After the spec review loop passes, ask the user to review the written spec before proceeding:
126
+
127
+ > "Spec written and committed to `<path>`. Please review it and let me know if you want to make any changes before we start writing out the implementation plan."
128
+
129
+ Wait for the user's response. If they request changes, make them and re-run the spec review loop. Only proceed once the user approves.
130
+
131
+ **Implementation:**
132
+
133
+ - Invoke the writing-plans skill to create a detailed implementation plan
134
+ - Do NOT invoke any other skill. writing-plans is the next step.
135
+
136
+ ## Key Principles
137
+
138
+ - **One question at a time** - Don't overwhelm with multiple questions
139
+ - **Multiple choice preferred** - Easier to answer than open-ended when possible
140
+ - **YAGNI ruthlessly** - Remove unnecessary features from all designs
141
+ - **Explore alternatives** - Always propose 2-3 approaches before settling
142
+ - **Incremental validation** - Present design, get approval before moving on
143
+ - **Be flexible** - Go back and clarify when something doesn't make sense
144
+
145
+ ## Visual Companion
146
+
147
+ A browser-based companion for showing mockups, diagrams, and visual options during brainstorming. Available as a tool — not a mode. Accepting the companion means it's available for questions that benefit from visual treatment; it does NOT mean every question goes through the browser.
148
+
149
+ **Offering the companion (just-in-time):** Do NOT offer it upfront. Wait until a question would genuinely be clearer shown than told — a real mockup / layout / diagram question, not merely a UI *topic*. The first time that happens, offer it then, as its own message:
150
+ > "This next part might be easier if I show you — I can put together mockups, diagrams, and comparisons in a browser tab as we go. It's still new and can be token-intensive. Want me to? I'll open it for you."
151
+
152
+ **This offer MUST be its own message.** Only the offer — no clarifying question, summary, or other content. Wait for the user's response. If they accept, start the server with `--open` so their browser opens to the first screen automatically. If they decline, continue text-only and don't offer again unless they raise it.
153
+
154
+ **Per-question decision:** Even after the user accepts, decide FOR EACH QUESTION whether to use the browser or the terminal. The test: **would the user understand this better by seeing it than reading it?**
155
+
156
+ - **Use the browser** for content that IS visual — mockups, wireframes, layout comparisons, architecture diagrams, side-by-side visual designs
157
+ - **Use the terminal** for content that is text — requirements questions, conceptual choices, tradeoff lists, A/B/C/D text options, scope decisions
158
+
159
+ A question about a UI topic is not automatically a visual question. "What does personality mean in this context?" is a conceptual question — use the terminal. "Which wizard layout works better?" is a visual question — use the browser.
160
+
161
+ If they agree to the companion, read the detailed guide before proceeding:
162
+ `skills/brainstorming/visual-companion.md`