@monoes/monomindcli 2.10.10 → 2.10.13

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 (233) hide show
  1. package/.claude/commands/mastermind/brain.md +14 -14
  2. package/.claude/commands/mastermind/help.md +2 -2
  3. package/.claude/commands/mastermind/master.md +24 -19
  4. package/.claude/commands/mastermind/memory.md +8 -8
  5. package/.claude/commands/mastermind/monoswarm.md +4 -4
  6. package/.claude/commands/mastermind.md +7 -7
  7. package/.claude/commands/truth/start.md +3 -3
  8. package/.claude/skills/mastermind/SKILL.md +7 -16
  9. package/.claude/skills/mastermind-debug/SKILL.md +3 -3
  10. package/.claude/skills/mastermind-design/SKILL.md +2 -0
  11. package/.claude/skills/mastermind-execute/SKILL.md +66 -11
  12. package/.claude/skills/mastermind-idea/SKILL.md +9 -2
  13. package/.claude/skills/mastermind-intake/SKILL.md +31 -7
  14. package/.claude/skills/mastermind-issue-detail/SKILL.md +70 -16
  15. package/.claude/skills/mastermind-issues/SKILL.md +111 -16
  16. package/.claude/skills/mastermind-liveness/SKILL.md +96 -26
  17. package/.claude/skills/mastermind-my-issues/SKILL.md +40 -8
  18. package/.claude/skills/mastermind-org/SKILL.md +2 -0
  19. package/.claude/skills/mastermind-plan/SKILL.md +7 -16
  20. package/.claude/skills/mastermind-plan-to-tasks/SKILL.md +132 -24
  21. package/.claude/skills/mastermind-protocol/SKILL.md +33 -22
  22. package/.claude/skills/mastermind-runorg/SKILL.md +22 -3
  23. package/.claude/skills/mastermind-skill-builder/SKILL.md +1 -1
  24. package/.claude/skills/mastermind-tasks/SKILL.md +5 -0
  25. package/.claude/skills/mastermind-techport/SKILL.md +1 -1
  26. package/.claude/skills/performance-analysis/SKILL.md +1 -1
  27. package/.claude/skills/verification-quality/SKILL.md +2 -3
  28. package/README.md +2 -2
  29. package/dist/src/commands/doc.js +2 -2
  30. package/dist/src/commands/doc.js.map +1 -1
  31. package/dist/src/commands/doctor-project-checks.d.ts.map +1 -1
  32. package/dist/src/commands/doctor-project-checks.js +20 -1
  33. package/dist/src/commands/doctor-project-checks.js.map +1 -1
  34. package/dist/src/commands/monograph.d.ts.map +1 -1
  35. package/dist/src/commands/monograph.js +11 -4
  36. package/dist/src/commands/monograph.js.map +1 -1
  37. package/dist/src/commands/org-observe.d.ts.map +1 -1
  38. package/dist/src/commands/org-observe.js +56 -6
  39. package/dist/src/commands/org-observe.js.map +1 -1
  40. package/dist/src/commands/org.d.ts +26 -0
  41. package/dist/src/commands/org.d.ts.map +1 -1
  42. package/dist/src/commands/org.js +144 -28
  43. package/dist/src/commands/org.js.map +1 -1
  44. package/dist/src/init/executor.d.ts.map +1 -1
  45. package/dist/src/init/executor.js +10 -9
  46. package/dist/src/init/executor.js.map +1 -1
  47. package/dist/src/init/settings-generator.d.ts.map +1 -1
  48. package/dist/src/init/settings-generator.js.map +1 -1
  49. package/dist/src/init/write-codex.d.ts.map +1 -1
  50. package/dist/src/init/write-codex.js.map +1 -1
  51. package/dist/src/knowledge/document-pipeline.d.ts +5 -0
  52. package/dist/src/knowledge/document-pipeline.d.ts.map +1 -1
  53. package/dist/src/knowledge/document-pipeline.js +32 -16
  54. package/dist/src/knowledge/document-pipeline.js.map +1 -1
  55. package/dist/src/mcp-tools/hooks-routing.d.ts +9 -0
  56. package/dist/src/mcp-tools/hooks-routing.d.ts.map +1 -1
  57. package/dist/src/mcp-tools/hooks-routing.js +12 -1
  58. package/dist/src/mcp-tools/hooks-routing.js.map +1 -1
  59. package/dist/src/mcp-tools/knowledge-tools.d.ts.map +1 -1
  60. package/dist/src/mcp-tools/knowledge-tools.js +105 -13
  61. package/dist/src/mcp-tools/knowledge-tools.js.map +1 -1
  62. package/dist/src/mcp-tools/memory-tools.d.ts +13 -0
  63. package/dist/src/mcp-tools/memory-tools.d.ts.map +1 -1
  64. package/dist/src/mcp-tools/memory-tools.js +257 -31
  65. package/dist/src/mcp-tools/memory-tools.js.map +1 -1
  66. package/dist/src/mcp-tools/monograph/health-tools.d.ts.map +1 -1
  67. package/dist/src/mcp-tools/monograph/health-tools.js +99 -42
  68. package/dist/src/mcp-tools/monograph/health-tools.js.map +1 -1
  69. package/dist/src/mcp-tools/monograph/impact-tools.d.ts.map +1 -1
  70. package/dist/src/mcp-tools/monograph/impact-tools.js +123 -51
  71. package/dist/src/mcp-tools/monograph/impact-tools.js.map +1 -1
  72. package/dist/src/mcp-tools/monograph/query-tools.d.ts.map +1 -1
  73. package/dist/src/mcp-tools/monograph/query-tools.js +113 -96
  74. package/dist/src/mcp-tools/monograph/query-tools.js.map +1 -1
  75. package/dist/src/mcp-tools/monograph/shared.d.ts +37 -4
  76. package/dist/src/mcp-tools/monograph/shared.d.ts.map +1 -1
  77. package/dist/src/mcp-tools/monograph/shared.js +75 -56
  78. package/dist/src/mcp-tools/monograph/shared.js.map +1 -1
  79. package/dist/src/memory/memory-bridge.d.ts +60 -1
  80. package/dist/src/memory/memory-bridge.d.ts.map +1 -1
  81. package/dist/src/memory/memory-bridge.js +172 -42
  82. package/dist/src/memory/memory-bridge.js.map +1 -1
  83. package/dist/src/memory/memory-kg.d.ts +495 -28
  84. package/dist/src/memory/memory-kg.d.ts.map +1 -1
  85. package/dist/src/memory/memory-kg.js +2186 -251
  86. package/dist/src/memory/memory-kg.js.map +1 -1
  87. package/dist/src/memory/query-router.d.ts +51 -0
  88. package/dist/src/memory/query-router.d.ts.map +1 -1
  89. package/dist/src/memory/query-router.js +38 -2
  90. package/dist/src/memory/query-router.js.map +1 -1
  91. package/dist/src/orgrt/agent-exec.d.ts.map +1 -1
  92. package/dist/src/orgrt/agent-exec.js +7 -0
  93. package/dist/src/orgrt/agent-exec.js.map +1 -1
  94. package/dist/src/orgrt/agent-runner.d.ts +26 -1
  95. package/dist/src/orgrt/agent-runner.d.ts.map +1 -1
  96. package/dist/src/orgrt/agent-runner.js +73 -22
  97. package/dist/src/orgrt/agent-runner.js.map +1 -1
  98. package/dist/src/orgrt/antigravity-runner.d.ts +1 -1
  99. package/dist/src/orgrt/antigravity-runner.d.ts.map +1 -1
  100. package/dist/src/orgrt/antigravity-runner.js +36 -19
  101. package/dist/src/orgrt/antigravity-runner.js.map +1 -1
  102. package/dist/src/orgrt/approvals.d.ts +26 -2
  103. package/dist/src/orgrt/approvals.d.ts.map +1 -1
  104. package/dist/src/orgrt/approvals.js +67 -7
  105. package/dist/src/orgrt/approvals.js.map +1 -1
  106. package/dist/src/orgrt/broker.d.ts +21 -2
  107. package/dist/src/orgrt/broker.d.ts.map +1 -1
  108. package/dist/src/orgrt/broker.js +56 -8
  109. package/dist/src/orgrt/broker.js.map +1 -1
  110. package/dist/src/orgrt/bus.d.ts +8 -0
  111. package/dist/src/orgrt/bus.d.ts.map +1 -1
  112. package/dist/src/orgrt/bus.js +27 -0
  113. package/dist/src/orgrt/bus.js.map +1 -1
  114. package/dist/src/orgrt/checkpoint-ops.d.ts.map +1 -1
  115. package/dist/src/orgrt/checkpoint-ops.js +15 -5
  116. package/dist/src/orgrt/checkpoint-ops.js.map +1 -1
  117. package/dist/src/orgrt/checkpoint.d.ts +42 -4
  118. package/dist/src/orgrt/checkpoint.d.ts.map +1 -1
  119. package/dist/src/orgrt/checkpoint.js +75 -4
  120. package/dist/src/orgrt/checkpoint.js.map +1 -1
  121. package/dist/src/orgrt/codex-runner.d.ts +1 -1
  122. package/dist/src/orgrt/codex-runner.d.ts.map +1 -1
  123. package/dist/src/orgrt/codex-runner.js +50 -23
  124. package/dist/src/orgrt/codex-runner.js.map +1 -1
  125. package/dist/src/orgrt/copilot-runner.d.ts +24 -2
  126. package/dist/src/orgrt/copilot-runner.d.ts.map +1 -1
  127. package/dist/src/orgrt/copilot-runner.js +257 -157
  128. package/dist/src/orgrt/copilot-runner.js.map +1 -1
  129. package/dist/src/orgrt/cross-org.d.ts +10 -3
  130. package/dist/src/orgrt/cross-org.d.ts.map +1 -1
  131. package/dist/src/orgrt/cross-org.js +225 -10
  132. package/dist/src/orgrt/cross-org.js.map +1 -1
  133. package/dist/src/orgrt/crush-runner.d.ts +22 -2
  134. package/dist/src/orgrt/crush-runner.d.ts.map +1 -1
  135. package/dist/src/orgrt/crush-runner.js +227 -120
  136. package/dist/src/orgrt/crush-runner.js.map +1 -1
  137. package/dist/src/orgrt/daemon.d.ts +77 -7
  138. package/dist/src/orgrt/daemon.d.ts.map +1 -1
  139. package/dist/src/orgrt/daemon.js +989 -385
  140. package/dist/src/orgrt/daemon.js.map +1 -1
  141. package/dist/src/orgrt/decisions.d.ts +2 -2
  142. package/dist/src/orgrt/decisions.d.ts.map +1 -1
  143. package/dist/src/orgrt/decisions.js +90 -18
  144. package/dist/src/orgrt/decisions.js.map +1 -1
  145. package/dist/src/orgrt/grok-runner.d.ts +29 -3
  146. package/dist/src/orgrt/grok-runner.d.ts.map +1 -1
  147. package/dist/src/orgrt/grok-runner.js +286 -150
  148. package/dist/src/orgrt/grok-runner.js.map +1 -1
  149. package/dist/src/orgrt/kimicode-runner.d.ts +5 -5
  150. package/dist/src/orgrt/kimicode-runner.d.ts.map +1 -1
  151. package/dist/src/orgrt/kimicode-runner.js +53 -32
  152. package/dist/src/orgrt/kimicode-runner.js.map +1 -1
  153. package/dist/src/orgrt/mailbox.d.ts +15 -0
  154. package/dist/src/orgrt/mailbox.d.ts.map +1 -1
  155. package/dist/src/orgrt/mailbox.js +29 -1
  156. package/dist/src/orgrt/mailbox.js.map +1 -1
  157. package/dist/src/orgrt/migrate.d.ts.map +1 -1
  158. package/dist/src/orgrt/migrate.js +8 -5
  159. package/dist/src/orgrt/migrate.js.map +1 -1
  160. package/dist/src/orgrt/opencode-runner.d.ts +1 -1
  161. package/dist/src/orgrt/opencode-runner.d.ts.map +1 -1
  162. package/dist/src/orgrt/opencode-runner.js +29 -3
  163. package/dist/src/orgrt/opencode-runner.js.map +1 -1
  164. package/dist/src/orgrt/org-memory.d.ts +19 -3
  165. package/dist/src/orgrt/org-memory.d.ts.map +1 -1
  166. package/dist/src/orgrt/org-memory.js +110 -38
  167. package/dist/src/orgrt/org-memory.js.map +1 -1
  168. package/dist/src/orgrt/pi-rpc-runner.d.ts +3 -1
  169. package/dist/src/orgrt/pi-rpc-runner.d.ts.map +1 -1
  170. package/dist/src/orgrt/pi-rpc-runner.js +35 -3
  171. package/dist/src/orgrt/pi-rpc-runner.js.map +1 -1
  172. package/dist/src/orgrt/pi-runner.d.ts +25 -2
  173. package/dist/src/orgrt/pi-runner.d.ts.map +1 -1
  174. package/dist/src/orgrt/pi-runner.js +271 -152
  175. package/dist/src/orgrt/pi-runner.js.map +1 -1
  176. package/dist/src/orgrt/policy.d.ts +1 -0
  177. package/dist/src/orgrt/policy.d.ts.map +1 -1
  178. package/dist/src/orgrt/policy.js +199 -39
  179. package/dist/src/orgrt/policy.js.map +1 -1
  180. package/dist/src/orgrt/provider.d.ts +4 -0
  181. package/dist/src/orgrt/provider.d.ts.map +1 -1
  182. package/dist/src/orgrt/provider.js +16 -0
  183. package/dist/src/orgrt/provider.js.map +1 -1
  184. package/dist/src/orgrt/qwen-rpc-runner.d.ts +3 -1
  185. package/dist/src/orgrt/qwen-rpc-runner.d.ts.map +1 -1
  186. package/dist/src/orgrt/qwen-rpc-runner.js +35 -3
  187. package/dist/src/orgrt/qwen-rpc-runner.js.map +1 -1
  188. package/dist/src/orgrt/qwen-runner.d.ts +30 -3
  189. package/dist/src/orgrt/qwen-runner.d.ts.map +1 -1
  190. package/dist/src/orgrt/qwen-runner.js +282 -142
  191. package/dist/src/orgrt/qwen-runner.js.map +1 -1
  192. package/dist/src/orgrt/role-slot.d.ts +88 -0
  193. package/dist/src/orgrt/role-slot.d.ts.map +1 -0
  194. package/dist/src/orgrt/role-slot.js +133 -0
  195. package/dist/src/orgrt/role-slot.js.map +1 -0
  196. package/dist/src/orgrt/runtime-options.d.ts +17 -0
  197. package/dist/src/orgrt/runtime-options.d.ts.map +1 -0
  198. package/dist/src/orgrt/runtime-options.js +32 -0
  199. package/dist/src/orgrt/runtime-options.js.map +1 -0
  200. package/dist/src/orgrt/scheduler-integration.d.ts +11 -0
  201. package/dist/src/orgrt/scheduler-integration.d.ts.map +1 -1
  202. package/dist/src/orgrt/scheduler-integration.js +75 -17
  203. package/dist/src/orgrt/scheduler-integration.js.map +1 -1
  204. package/dist/src/orgrt/scheduler.d.ts +4 -0
  205. package/dist/src/orgrt/scheduler.d.ts.map +1 -1
  206. package/dist/src/orgrt/scheduler.js +7 -1
  207. package/dist/src/orgrt/scheduler.js.map +1 -1
  208. package/dist/src/orgrt/server.d.ts +8 -3
  209. package/dist/src/orgrt/server.d.ts.map +1 -1
  210. package/dist/src/orgrt/server.js +48 -13
  211. package/dist/src/orgrt/server.js.map +1 -1
  212. package/dist/src/orgrt/session.d.ts +26 -2
  213. package/dist/src/orgrt/session.d.ts.map +1 -1
  214. package/dist/src/orgrt/session.js +98 -4
  215. package/dist/src/orgrt/session.js.map +1 -1
  216. package/dist/src/orgrt/task-dag.d.ts +5 -0
  217. package/dist/src/orgrt/task-dag.d.ts.map +1 -1
  218. package/dist/src/orgrt/task-dag.js +41 -0
  219. package/dist/src/orgrt/task-dag.js.map +1 -1
  220. package/dist/src/orgrt/test-loop.js +2 -2
  221. package/dist/src/orgrt/test-loop.js.map +1 -1
  222. package/dist/src/orgrt/types.d.ts +14 -2
  223. package/dist/src/orgrt/types.d.ts.map +1 -1
  224. package/dist/src/orgrt/types.js +15 -1
  225. package/dist/src/orgrt/types.js.map +1 -1
  226. package/dist/src/orgrt/vercel-runner.d.ts.map +1 -1
  227. package/dist/src/orgrt/vercel-runner.js +4 -0
  228. package/dist/src/orgrt/vercel-runner.js.map +1 -1
  229. package/dist/src/ui/routes-org.mjs +27 -7
  230. package/dist/src/ui/server.mjs +82 -48
  231. package/dist/tsconfig.tsbuildinfo +1 -1
  232. package/package.json +3 -2
  233. package/dist/src/ui/data/mastermind-sessions.json +0 -1
@@ -100,6 +100,37 @@ function liveServeDaemonPid(cwd) {
100
100
  return null;
101
101
  }
102
102
  }
103
+ /** Mutual-exclusion check for `org serve` startup.
104
+ *
105
+ * Two `org serve` processes started against the same project root have zero
106
+ * visibility into each other — each builds its own in-memory `OrgDaemon` and
107
+ * independently decides which orgs are "due now", so both can call
108
+ * `daemon.startOrg(name)` for the same org and have both processes write to
109
+ * the same on-disk state (runtime.json, decisions.jsonl, history.jsonl,
110
+ * .mail/) at once. `liveServeDaemonPid` already knows how to read this
111
+ * project's serve-heartbeat.json and tell a live daemon's heartbeat from a
112
+ * stale one (dead pid, or aged past a few missed 30s beats) — reused here
113
+ * as the actual pidfile lock, rather than inventing a second file, since it
114
+ * already IS a pidfile (pid + timestamp, written at startup and every
115
+ * heartbeat, removed on clean shutdown by `daemon.clearHeartbeat()`).
116
+ *
117
+ * Call this before the daemon/server/scheduler are constructed, so a
118
+ * refusal never opens a port, binds a broker lease, or touches any org's
119
+ * state. */
120
+ export function checkServeLock(cwd) {
121
+ const owner = liveServeDaemonPid(cwd);
122
+ if (owner != null)
123
+ return { ok: false, pid: owner };
124
+ // liveServeDaemonPid() has already ruled out a live owner — any heartbeat
125
+ // file still on disk here is stale (dead pid, or a SIGKILLed daemon that
126
+ // never reached clearHeartbeat()). Remove it so it can't be misread by
127
+ // `org run`/`org status` before this daemon's own writeHeartbeat() lands.
128
+ const heartbeatPath = join(cwd, '.monomind', 'serve-heartbeat.json');
129
+ const staleHeartbeatRemoved = existsSync(heartbeatPath);
130
+ if (staleHeartbeatRemoved)
131
+ rmSync(heartbeatPath, { force: true });
132
+ return { ok: true, staleHeartbeatRemoved };
133
+ }
103
134
  const runAction = async (ctx) => {
104
135
  // Org runs skip local embeddings entirely — on some machines
105
136
  // @huggingface/transformers' native ONNX runtime crashes the whole
@@ -152,7 +183,11 @@ const runAction = async (ctx) => {
152
183
  const glossary = await (async () => {
153
184
  try {
154
185
  const kg = await import('../memory/memory-kg.js');
155
- return await kg.kgGlossary({ dbPath: join(process.cwd(), '.monomind', 'org-memory') });
186
+ const { orgKgScope } = await import('../orgrt/org-memory.js');
187
+ return await kg.kgGlossary({
188
+ dbPath: join(process.cwd(), '.monomind', 'org-memory'),
189
+ scope: orgKgScope(name),
190
+ });
156
191
  }
157
192
  catch {
158
193
  return [];
@@ -343,7 +378,7 @@ const runAction = async (ctx) => {
343
378
  let srv;
344
379
  if (crossProcess) {
345
380
  srv = await startOrgServer(daemon, 0);
346
- daemon.setInboxUrl(`http://127.0.0.1:${srv.port}`, srv.credential);
381
+ daemon.setInboxUrl(`http://127.0.0.1:${srv.port}`, srv.operatorCredential);
347
382
  }
348
383
  let running;
349
384
  try {
@@ -1004,6 +1039,21 @@ WantedBy=default.target
1004
1039
  return { success: true, message: `${format} unit emitted` };
1005
1040
  };
1006
1041
  const serveAction = async (ctx) => {
1042
+ // Mutual exclusion: refuse to start a second `org serve` for this project
1043
+ // root. Checked before anything else so a refusal never opens a port,
1044
+ // registers a broker lease, or starts a scheduled org that a live daemon
1045
+ // is already running — see checkServeLock's header for the failure mode
1046
+ // this prevents.
1047
+ const lock = checkServeLock(ctx.cwd);
1048
+ if (!lock.ok) {
1049
+ log(output.error(`org serve: another daemon (pid ${lock.pid}) is already running for this project root.`));
1050
+ log(output.info(` Check what it's doing with: monomind org status`));
1051
+ log(output.info(` Stop it first (Ctrl-C in its terminal, or "kill ${lock.pid}"), then retry.`));
1052
+ return { success: false, message: `org serve already running (pid ${lock.pid})` };
1053
+ }
1054
+ if (lock.staleHeartbeatRemoved) {
1055
+ log(output.warning('org serve: cleaned up a stale heartbeat left by a previous daemon that did not shut down cleanly.'));
1056
+ }
1007
1057
  // See the matching comment in runAction — same rationale, same guard.
1008
1058
  process.env.MONOMIND_NO_LOCAL_EMBEDDINGS = '1';
1009
1059
  // The embedding-model crash above has a sibling: loadReranker() in
@@ -1020,16 +1070,27 @@ const serveAction = async (ctx) => {
1020
1070
  let srv;
1021
1071
  if (crossProcess) {
1022
1072
  srv = await startOrgServer(daemon, 0);
1023
- daemon.setInboxUrl(`http://127.0.0.1:${srv.port}`, srv.credential);
1073
+ daemon.setInboxUrl(`http://127.0.0.1:${srv.port}`, srv.operatorCredential);
1024
1074
  }
1025
1075
  // Crash handlers: log the reason and persist crashed state so `org status`
1026
- // shows what happened instead of a silent "pid is gone".
1076
+ // shows what happened instead of a silent "pid is gone". A truly unknown
1077
+ // uncaught exception's blast radius can't always be attributed to one org,
1078
+ // so the whole process still exits (the safety-first default) — but naming
1079
+ // which orgs were in flight at the moment it fired at least tells the
1080
+ // operator the blast radius they actually hit, instead of leaving them to
1081
+ // guess from an error with no org context.
1027
1082
  const crashExit = (label, err) => {
1028
1083
  try {
1029
- console.error(`[org serve] ${label}:`, err);
1084
+ const running = daemon.listRunning();
1085
+ console.error(`[org serve] ${label}:`, err, running.length ? `— orgs in flight: ${running.join(', ')}` : '— no orgs were running');
1030
1086
  }
1031
1087
  catch {
1032
- /* stderr gone */
1088
+ try {
1089
+ console.error(`[org serve] ${label}:`, err);
1090
+ }
1091
+ catch {
1092
+ /* stderr gone */
1093
+ }
1033
1094
  }
1034
1095
  daemon.persistCrashStateAll(`${label}: ${err instanceof Error ? err.message : String(err)}`);
1035
1096
  daemon.clearHeartbeat();
@@ -1207,16 +1268,30 @@ const serveAction = async (ctx) => {
1207
1268
  }
1208
1269
  }
1209
1270
  }
1271
+ // Each poll pass already wraps its own per-org daemon calls in try/catch,
1272
+ // but a synchronous throw from something ahead of those (e.g.
1273
+ // daemon.listRunning(), listOrgConfigFiles()) still rejects the async
1274
+ // function itself. `void`-ing that call, as before, discards the promise
1275
+ // without observing a rejection — which becomes an unhandled rejection at
1276
+ // the process level and takes down every other org's in-flight run via
1277
+ // crashExit, even though the failure was local to one poll pass. .catch()
1278
+ // keeps it a per-pass, logged failure instead.
1210
1279
  const stopPoll = setInterval(() => {
1211
- void pollStopfiles(ctx.cwd, daemon);
1280
+ pollStopfiles(ctx.cwd, daemon).catch((err) => {
1281
+ console.error('[org serve] stopfile poll failed:', err);
1282
+ });
1212
1283
  }, 2000);
1213
1284
  stopPoll.unref?.();
1214
1285
  const runPoll = setInterval(() => {
1215
- void pollRunfiles(ctx.cwd, daemon);
1286
+ pollRunfiles(ctx.cwd, daemon).catch((err) => {
1287
+ console.error('[org serve] runfile poll failed:', err);
1288
+ });
1216
1289
  }, 2000);
1217
1290
  runPoll.unref?.();
1218
1291
  const reloadPoll = setInterval(() => {
1219
- void pollReloadfiles(ctx.cwd, daemon);
1292
+ pollReloadfiles(ctx.cwd, daemon).catch((err) => {
1293
+ console.error('[org serve] reloadfile poll failed:', err);
1294
+ });
1220
1295
  }, 2000);
1221
1296
  reloadPoll.unref?.();
1222
1297
  await new Promise((r) => {
@@ -1798,7 +1873,7 @@ export const orgCommand = {
1798
1873
  },
1799
1874
  {
1800
1875
  name: 'memory',
1801
- description: "Inspect an org's cross-run memory and knowledge graph (stats | search <query> | rules | rollback <run-ref>)",
1876
+ description: "Inspect an org's cross-run memory and knowledge graph (stats | search <query> | rules | rollback <run-ref> | promote <run-ref>)",
1802
1877
  examples: [
1803
1878
  { command: 'monomind org memory growth stats', description: 'KG size and namespaces' },
1804
1879
  {
@@ -1807,7 +1882,11 @@ export const orgCommand = {
1807
1882
  },
1808
1883
  {
1809
1884
  command: 'monomind org memory growth rollback run:m4x2',
1810
- description: 'Delete everything one run wrote to the KG',
1885
+ description: "Withdraw one run's support from this org's KG",
1886
+ },
1887
+ {
1888
+ command: 'monomind org memory growth promote run:m4x2',
1889
+ description: "Share one run's claims with project-wide knowledge",
1811
1890
  },
1812
1891
  ],
1813
1892
  action: async (ctx) => {
@@ -1816,31 +1895,47 @@ export const orgCommand = {
1816
1895
  return v.result;
1817
1896
  const sub = String(ctx.args[1] ?? 'stats');
1818
1897
  const { join } = await import('node:path');
1819
- const dbPath = join(process.cwd(), '.monomind', 'org-memory');
1898
+ const cwd = ctx.cwd || process.cwd();
1899
+ const dbPath = join(cwd, '.monomind', 'org-memory');
1820
1900
  const kg = await import('../memory/memory-kg.js');
1821
1901
  const bridge = await import('../memory/memory-bridge.js');
1902
+ const { orgKgScope, orgMemoryNamespace } = await import('../orgrt/org-memory.js');
1903
+ // Every KG operation below is scoped to the requested org, so the org
1904
+ // name in the output describes what was actually read, not just what
1905
+ // was asked for. Reads of the shared store are unchanged.
1906
+ const scope = orgKgScope(v.name);
1907
+ const kgNs = kg.kgNamespaces(scope);
1908
+ // Flat org memory is namespaced by the org DEFINITION, not by name —
1909
+ // resolve it the way the runtime writes it (B4), so a configured
1910
+ // `memory_namespace` is searched instead of a guessed `org:<name>`.
1911
+ const defPath = join(cwd, ORG_DIR, `${v.name}.json`);
1912
+ const flatNs = existsSync(defPath)
1913
+ ? orgMemoryNamespace(v.name, OrgDefSchema.parse(JSON.parse(readFileSync(defPath, 'utf8'))))
1914
+ : `org:${v.name}`;
1822
1915
  try {
1823
1916
  if (sub === 'stats') {
1824
1917
  const [stats, glossary, backend] = await Promise.all([
1825
- kg.kgStats({ dbPath }),
1826
- kg.kgGlossary({ dbPath, limit: 15 }),
1918
+ kg.kgStats({ dbPath, scope }),
1919
+ kg.kgGlossary({ dbPath, limit: 15, scope }),
1827
1920
  bridge.bridgeGetBackendStats(dbPath),
1828
1921
  ]);
1922
+ // The backend reports every namespace in the SHARED store, so
1923
+ // listing it raw put other orgs' namespaces (and their counts)
1924
+ // under this org's name. Keep only what this org owns.
1925
+ // Spread kgNs rather than listing namespaces: the identity work
1926
+ // added `names` (the entity name index), and a hand-written list
1927
+ // silently omits any namespace added later, hiding rows this org
1928
+ // does own.
1929
+ const owned = new Set([...Object.values(kgNs), flatNs]);
1930
+ const byNs = Object.fromEntries(Object.entries(backend?.entriesByNamespace ?? {}).filter(([ns]) => owned.has(ns) || ns.startsWith(`agent:${flatNs}:`)));
1829
1931
  if (ctx.flags.format === 'json') {
1830
- const payload = {
1831
- v: 1,
1832
- org: v.name,
1833
- ...stats,
1834
- glossary,
1835
- namespaces: backend?.entriesByNamespace ?? {},
1836
- };
1932
+ const payload = { v: 1, org: v.name, ...stats, glossary, namespaces: byNs };
1837
1933
  process.stdout.write(`${JSON.stringify(payload)}\n`);
1838
1934
  return { success: true, data: payload };
1839
1935
  }
1840
1936
  log(output.info(`Knowledge graph: ${stats.nodes} entities, ${stats.edges} relations, ${stats.rules} rules`));
1841
1937
  if (glossary.length)
1842
1938
  log(output.info(`Top entities: ${glossary.join(', ')}`));
1843
- const byNs = backend?.entriesByNamespace ?? {};
1844
1939
  for (const [ns, count] of Object.entries(byNs))
1845
1940
  log(output.info(` ${ns}: ${count} entries`));
1846
1941
  return {
@@ -1856,11 +1951,11 @@ export const orgCommand = {
1856
1951
  const [mem, graph] = await Promise.all([
1857
1952
  bridge.bridgeSearchEntries({
1858
1953
  query: q,
1859
- namespace: `org:${v.name}`,
1954
+ namespace: flatNs,
1860
1955
  limit: 5,
1861
1956
  dbPath,
1862
1957
  }),
1863
- kg.kgSearch({ query: q, dbPath, limit: 8 }),
1958
+ kg.kgSearch({ query: q, dbPath, limit: 8, scope }),
1864
1959
  ]);
1865
1960
  if (ctx.flags.format === 'json') {
1866
1961
  const payload = {
@@ -1884,7 +1979,7 @@ export const orgCommand = {
1884
1979
  };
1885
1980
  }
1886
1981
  if (sub === 'rules') {
1887
- const rules = await kg.kgListRules({ dbPath, limit: 50 });
1982
+ const rules = await kg.kgListRules({ dbPath, limit: 50, scope });
1888
1983
  if (ctx.flags.format === 'json') {
1889
1984
  const payload = { v: 1, org: v.name, items: rules };
1890
1985
  process.stdout.write(`${JSON.stringify(payload)}\n`);
@@ -1901,18 +1996,39 @@ export const orgCommand = {
1901
1996
  success: false,
1902
1997
  message: 'usage: org memory <org> rollback <origin-ref> (e.g. run:m4x2)',
1903
1998
  };
1904
- const res = await kg.kgRollback({ originRef: ref, dbPath });
1999
+ // Scoped: the ref is resolved inside this org's namespaces and
2000
+ // origin space, so the org name in the command is an ownership
2001
+ // restriction rather than a label on an unfiltered rollback.
2002
+ const res = await kg.kgRollback({ originRef: ref, scope, dbPath });
1905
2003
  if (ctx.flags.format === 'json') {
1906
2004
  const payload = { v: 1, org: v.name, ref, ...res };
1907
2005
  process.stdout.write(`${JSON.stringify(payload)}\n`);
1908
2006
  return { success: res.success, data: payload };
1909
2007
  }
1910
- log(output.info(`Rolled back ${ref}: ${res.deleted} deleted, ${res.retained} retained (shared with other origins)`));
2008
+ log(output.info(`Rolled back ${ref} for org ${v.name}: ${res.deleted} deleted, ${res.retained} retained (shared with other origins)`));
1911
2009
  return { success: res.success, message: `rollback ${ref}`, data: res };
1912
2010
  }
2011
+ if (sub === 'promote') {
2012
+ const ref = ctx.args[2];
2013
+ if (!ref)
2014
+ return {
2015
+ success: false,
2016
+ message: 'usage: org memory <org> promote <origin-ref> (e.g. run:m4x2)',
2017
+ };
2018
+ const res = await kg.kgPromote({ originRef: ref, from: scope, dbPath });
2019
+ if (ctx.flags.format === 'json') {
2020
+ const payload = { v: 1, org: v.name, ref, ...res };
2021
+ process.stdout.write(`${JSON.stringify(payload)}\n`);
2022
+ return { success: res.success, data: payload };
2023
+ }
2024
+ log(output.info(res.success
2025
+ ? `Promoted ${ref} from org ${v.name} to project-shared knowledge: ${res.nodes} entities, ${res.edges} relations, ${res.rules} rules. Withdraw with origin ref ${res.promotedAs}.`
2026
+ : `Promotion of ${ref} failed: ${res.error ?? 'unknown error'}`));
2027
+ return { success: res.success, message: `promote ${ref}`, data: res };
2028
+ }
1913
2029
  return {
1914
2030
  success: false,
1915
- message: `unknown subcommand "${sub}" — use stats | search | rules | rollback`,
2031
+ message: `unknown subcommand "${sub}" — use stats | search | rules | rollback | promote`,
1916
2032
  };
1917
2033
  }
1918
2034
  finally {