@monoes/monomindcli 2.16.11 → 2.16.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 (225) hide show
  1. package/.claude/agents/core/coder.md +1 -1
  2. package/.claude/agents/engineering/engineering-devops-automator.md +1 -1
  3. package/.claude/agents/github/repo-architect.md +1 -1
  4. package/.claude/agents/testing/production-validator.md +1 -1
  5. package/.claude/agents/testing/testing-tool-evaluator.md +1 -1
  6. package/.claude/commands/github/pr-manager.md +1 -1
  7. package/.claude/helpers/pick-rank.cjs +34 -4
  8. package/.claude/skills/monolean-audit/SKILL.md +1 -1
  9. package/dist/src/commands/cleanup-data.d.ts +30 -0
  10. package/dist/src/commands/cleanup-data.d.ts.map +1 -0
  11. package/dist/src/commands/cleanup-data.js +138 -0
  12. package/dist/src/commands/cleanup-data.js.map +1 -0
  13. package/dist/src/commands/cleanup-origin.d.ts +24 -0
  14. package/dist/src/commands/cleanup-origin.d.ts.map +1 -0
  15. package/dist/src/commands/cleanup-origin.js +67 -0
  16. package/dist/src/commands/cleanup-origin.js.map +1 -0
  17. package/dist/src/commands/cleanup-scratch.d.ts +43 -0
  18. package/dist/src/commands/cleanup-scratch.d.ts.map +1 -0
  19. package/dist/src/commands/cleanup-scratch.js +125 -0
  20. package/dist/src/commands/cleanup-scratch.js.map +1 -0
  21. package/dist/src/commands/cleanup.d.ts +2 -39
  22. package/dist/src/commands/cleanup.d.ts.map +1 -1
  23. package/dist/src/commands/cleanup.js +9 -296
  24. package/dist/src/commands/cleanup.js.map +1 -1
  25. package/dist/src/commands/doctor-gitignore-checks.d.ts +10 -0
  26. package/dist/src/commands/doctor-gitignore-checks.d.ts.map +1 -0
  27. package/dist/src/commands/doctor-gitignore-checks.js +141 -0
  28. package/dist/src/commands/doctor-gitignore-checks.js.map +1 -0
  29. package/dist/src/commands/doctor-helpers-checks.d.ts +10 -0
  30. package/dist/src/commands/doctor-helpers-checks.d.ts.map +1 -0
  31. package/dist/src/commands/doctor-helpers-checks.js +292 -0
  32. package/dist/src/commands/doctor-helpers-checks.js.map +1 -0
  33. package/dist/src/commands/doctor-memory-checks.d.ts +47 -0
  34. package/dist/src/commands/doctor-memory-checks.d.ts.map +1 -0
  35. package/dist/src/commands/doctor-memory-checks.js +298 -0
  36. package/dist/src/commands/doctor-memory-checks.js.map +1 -0
  37. package/dist/src/commands/doctor-monograph-checks.d.ts +9 -0
  38. package/dist/src/commands/doctor-monograph-checks.d.ts.map +1 -0
  39. package/dist/src/commands/doctor-monograph-checks.js +331 -0
  40. package/dist/src/commands/doctor-monograph-checks.js.map +1 -0
  41. package/dist/src/commands/doctor-project-checks.d.ts +7 -66
  42. package/dist/src/commands/doctor-project-checks.d.ts.map +1 -1
  43. package/dist/src/commands/doctor-project-checks.js +10 -1331
  44. package/dist/src/commands/doctor-project-checks.js.map +1 -1
  45. package/dist/src/commands/doctor-routing-checks.d.ts +10 -0
  46. package/dist/src/commands/doctor-routing-checks.d.ts.map +1 -0
  47. package/dist/src/commands/doctor-routing-checks.js +194 -0
  48. package/dist/src/commands/doctor-routing-checks.js.map +1 -0
  49. package/dist/src/commands/doctor-worker-checks.d.ts +17 -0
  50. package/dist/src/commands/doctor-worker-checks.d.ts.map +1 -0
  51. package/dist/src/commands/doctor-worker-checks.js +122 -0
  52. package/dist/src/commands/doctor-worker-checks.js.map +1 -0
  53. package/dist/src/commands/hooks-routing-commands.js +1 -1
  54. package/dist/src/commands/hooks-routing-commands.js.map +1 -1
  55. package/dist/src/commands/init.d.ts.map +1 -1
  56. package/dist/src/commands/init.js +6 -15
  57. package/dist/src/commands/init.js.map +1 -1
  58. package/dist/src/index.js +2 -2
  59. package/dist/src/index.js.map +1 -1
  60. package/dist/src/init/never-commit.d.ts +3 -3
  61. package/dist/src/init/types.d.ts +1 -1
  62. package/dist/src/init/types.js +1 -1
  63. package/dist/src/knowledge/document-store.js +1 -1
  64. package/dist/src/knowledge/document-store.js.map +1 -1
  65. package/dist/src/mcp-tools/hooks-edit-command.d.ts +10 -0
  66. package/dist/src/mcp-tools/hooks-edit-command.d.ts.map +1 -0
  67. package/dist/src/mcp-tools/hooks-edit-command.js +247 -0
  68. package/dist/src/mcp-tools/hooks-edit-command.js.map +1 -0
  69. package/dist/src/mcp-tools/hooks-learning.d.ts +9 -0
  70. package/dist/src/mcp-tools/hooks-learning.d.ts.map +1 -0
  71. package/dist/src/mcp-tools/hooks-learning.js +408 -0
  72. package/dist/src/mcp-tools/hooks-learning.js.map +1 -0
  73. package/dist/src/mcp-tools/hooks-metrics-list.d.ts +8 -0
  74. package/dist/src/mcp-tools/hooks-metrics-list.d.ts.map +1 -0
  75. package/dist/src/mcp-tools/hooks-metrics-list.js +205 -0
  76. package/dist/src/mcp-tools/hooks-metrics-list.js.map +1 -0
  77. package/dist/src/mcp-tools/hooks-route.d.ts +12 -0
  78. package/dist/src/mcp-tools/hooks-route.d.ts.map +1 -0
  79. package/dist/src/mcp-tools/hooks-route.js +251 -0
  80. package/dist/src/mcp-tools/hooks-route.js.map +1 -0
  81. package/dist/src/mcp-tools/hooks-routing.d.ts +6 -27
  82. package/dist/src/mcp-tools/hooks-routing.d.ts.map +1 -1
  83. package/dist/src/mcp-tools/hooks-routing.js +6 -1727
  84. package/dist/src/mcp-tools/hooks-routing.js.map +1 -1
  85. package/dist/src/mcp-tools/hooks-session.d.ts +9 -0
  86. package/dist/src/mcp-tools/hooks-session.d.ts.map +1 -0
  87. package/dist/src/mcp-tools/hooks-session.js +243 -0
  88. package/dist/src/mcp-tools/hooks-session.js.map +1 -0
  89. package/dist/src/mcp-tools/hooks-task.d.ts +17 -0
  90. package/dist/src/mcp-tools/hooks-task.d.ts.map +1 -0
  91. package/dist/src/mcp-tools/hooks-task.js +427 -0
  92. package/dist/src/mcp-tools/hooks-task.js.map +1 -0
  93. package/dist/src/mcp-tools/hooks-tools.d.ts +2 -1
  94. package/dist/src/mcp-tools/hooks-tools.d.ts.map +1 -1
  95. package/dist/src/mcp-tools/hooks-tools.js +2 -1
  96. package/dist/src/mcp-tools/hooks-tools.js.map +1 -1
  97. package/dist/src/mcp-tools/memory-tools.js +1 -1
  98. package/dist/src/mcp-tools/memory-tools.js.map +1 -1
  99. package/dist/src/memory/bm25-index.d.ts +2 -2
  100. package/dist/src/memory/bm25-index.js +2 -2
  101. package/dist/src/memory/embedding-operations.js +2 -2
  102. package/dist/src/memory/embedding-operations.js.map +1 -1
  103. package/dist/src/memory/entity-name-key.d.ts +1 -1
  104. package/dist/src/memory/entity-name-key.js +1 -1
  105. package/dist/src/memory/hnsw-operations.d.ts +1 -1
  106. package/dist/src/memory/hnsw-operations.js +1 -1
  107. package/dist/src/memory/memory-bridge-backend.d.ts +43 -0
  108. package/dist/src/memory/memory-bridge-backend.d.ts.map +1 -0
  109. package/dist/src/memory/memory-bridge-backend.js +363 -0
  110. package/dist/src/memory/memory-bridge-backend.js.map +1 -0
  111. package/dist/src/memory/memory-bridge-core.d.ts +42 -0
  112. package/dist/src/memory/memory-bridge-core.d.ts.map +1 -0
  113. package/dist/src/memory/memory-bridge-core.js +126 -0
  114. package/dist/src/memory/memory-bridge-core.js.map +1 -0
  115. package/dist/src/memory/memory-bridge-entries.d.ts +131 -0
  116. package/dist/src/memory/memory-bridge-entries.d.ts.map +1 -0
  117. package/dist/src/memory/memory-bridge-entries.js +227 -0
  118. package/dist/src/memory/memory-bridge-entries.js.map +1 -0
  119. package/dist/src/memory/memory-bridge-feedback.d.ts +60 -0
  120. package/dist/src/memory/memory-bridge-feedback.d.ts.map +1 -0
  121. package/dist/src/memory/memory-bridge-feedback.js +118 -0
  122. package/dist/src/memory/memory-bridge-feedback.js.map +1 -0
  123. package/dist/src/memory/memory-bridge-paths.d.ts +123 -0
  124. package/dist/src/memory/memory-bridge-paths.d.ts.map +1 -0
  125. package/dist/src/memory/memory-bridge-paths.js +335 -0
  126. package/dist/src/memory/memory-bridge-paths.js.map +1 -0
  127. package/dist/src/memory/memory-bridge-search.d.ts +48 -0
  128. package/dist/src/memory/memory-bridge-search.d.ts.map +1 -0
  129. package/dist/src/memory/memory-bridge-search.js +383 -0
  130. package/dist/src/memory/memory-bridge-search.js.map +1 -0
  131. package/dist/src/memory/memory-bridge-sessions.d.ts +38 -0
  132. package/dist/src/memory/memory-bridge-sessions.d.ts.map +1 -0
  133. package/dist/src/memory/memory-bridge-sessions.js +109 -0
  134. package/dist/src/memory/memory-bridge-sessions.js.map +1 -0
  135. package/dist/src/memory/memory-bridge-store.d.ts +58 -0
  136. package/dist/src/memory/memory-bridge-store.d.ts.map +1 -0
  137. package/dist/src/memory/memory-bridge-store.js +201 -0
  138. package/dist/src/memory/memory-bridge-store.js.map +1 -0
  139. package/dist/src/memory/memory-bridge.d.ts +10 -438
  140. package/dist/src/memory/memory-bridge.d.ts.map +1 -1
  141. package/dist/src/memory/memory-bridge.js +14 -1787
  142. package/dist/src/memory/memory-bridge.js.map +1 -1
  143. package/dist/src/memory/memory-kg-claims.d.ts +52 -0
  144. package/dist/src/memory/memory-kg-claims.d.ts.map +1 -0
  145. package/dist/src/memory/memory-kg-claims.js +99 -0
  146. package/dist/src/memory/memory-kg-claims.js.map +1 -0
  147. package/dist/src/memory/memory-kg-index.d.ts +86 -0
  148. package/dist/src/memory/memory-kg-index.d.ts.map +1 -0
  149. package/dist/src/memory/memory-kg-index.js +256 -0
  150. package/dist/src/memory/memory-kg-index.js.map +1 -0
  151. package/dist/src/memory/memory-kg-ingest.d.ts +44 -0
  152. package/dist/src/memory/memory-kg-ingest.d.ts.map +1 -0
  153. package/dist/src/memory/memory-kg-ingest.js +361 -0
  154. package/dist/src/memory/memory-kg-ingest.js.map +1 -0
  155. package/dist/src/memory/memory-kg-model.d.ts +168 -0
  156. package/dist/src/memory/memory-kg-model.d.ts.map +1 -0
  157. package/dist/src/memory/memory-kg-model.js +158 -0
  158. package/dist/src/memory/memory-kg-model.js.map +1 -0
  159. package/dist/src/memory/memory-kg-names.d.ts +64 -0
  160. package/dist/src/memory/memory-kg-names.d.ts.map +1 -0
  161. package/dist/src/memory/memory-kg-names.js +187 -0
  162. package/dist/src/memory/memory-kg-names.js.map +1 -0
  163. package/dist/src/memory/memory-kg-promote.d.ts +79 -0
  164. package/dist/src/memory/memory-kg-promote.d.ts.map +1 -0
  165. package/dist/src/memory/memory-kg-promote.js +248 -0
  166. package/dist/src/memory/memory-kg-promote.js.map +1 -0
  167. package/dist/src/memory/memory-kg-rebuild.d.ts +77 -0
  168. package/dist/src/memory/memory-kg-rebuild.d.ts.map +1 -0
  169. package/dist/src/memory/memory-kg-rebuild.js +299 -0
  170. package/dist/src/memory/memory-kg-rebuild.js.map +1 -0
  171. package/dist/src/memory/memory-kg-rollback.d.ts +47 -0
  172. package/dist/src/memory/memory-kg-rollback.d.ts.map +1 -0
  173. package/dist/src/memory/memory-kg-rollback.js +193 -0
  174. package/dist/src/memory/memory-kg-rollback.js.map +1 -0
  175. package/dist/src/memory/memory-kg-rules.d.ts +64 -0
  176. package/dist/src/memory/memory-kg-rules.d.ts.map +1 -0
  177. package/dist/src/memory/memory-kg-rules.js +251 -0
  178. package/dist/src/memory/memory-kg-rules.js.map +1 -0
  179. package/dist/src/memory/memory-kg-scan.d.ts +118 -0
  180. package/dist/src/memory/memory-kg-scan.d.ts.map +1 -0
  181. package/dist/src/memory/memory-kg-scan.js +209 -0
  182. package/dist/src/memory/memory-kg-scan.js.map +1 -0
  183. package/dist/src/memory/memory-kg-search.d.ts +80 -0
  184. package/dist/src/memory/memory-kg-search.d.ts.map +1 -0
  185. package/dist/src/memory/memory-kg-search.js +239 -0
  186. package/dist/src/memory/memory-kg-search.js.map +1 -0
  187. package/dist/src/memory/memory-kg.d.ts +19 -547
  188. package/dist/src/memory/memory-kg.d.ts.map +1 -1
  189. package/dist/src/memory/memory-kg.js +10 -2389
  190. package/dist/src/memory/memory-kg.js.map +1 -1
  191. package/dist/src/orgrt/sandbox-stubs.d.ts +4 -0
  192. package/dist/src/orgrt/sandbox-stubs.d.ts.map +1 -1
  193. package/dist/src/orgrt/sandbox-stubs.js +12 -2
  194. package/dist/src/orgrt/sandbox-stubs.js.map +1 -1
  195. package/dist/src/ui/org-hil.mjs +1 -1
  196. package/dist/src/ui/routes-org-agents.mjs +318 -0
  197. package/dist/src/ui/routes-org-approvals.mjs +133 -0
  198. package/dist/src/ui/routes-org-config.mjs +459 -0
  199. package/dist/src/ui/routes-org-control.mjs +300 -0
  200. package/dist/src/ui/routes-org-files.mjs +172 -0
  201. package/dist/src/ui/routes-org-helpers.mjs +84 -0
  202. package/dist/src/ui/routes-org-knowledge.mjs +262 -0
  203. package/dist/src/ui/routes-org-lifecycle.mjs +224 -0
  204. package/dist/src/ui/routes-org-live.mjs +278 -0
  205. package/dist/src/ui/routes-org-mastermind.mjs +346 -0
  206. package/dist/src/ui/routes-org-planning.mjs +398 -0
  207. package/dist/src/ui/routes-org-runs.mjs +430 -0
  208. package/dist/src/ui/routes-org-status.mjs +342 -0
  209. package/dist/src/ui/routes-org-workflows.mjs +212 -0
  210. package/dist/src/ui/routes-org.mjs +26 -3847
  211. package/dist/src/ui/server.mjs +1 -1
  212. package/dist/src/utils/native-error.d.ts +1 -1
  213. package/dist/src/utils/native-error.js +1 -1
  214. package/dist/src/utils/paths.d.ts +2 -1
  215. package/dist/src/utils/paths.d.ts.map +1 -1
  216. package/dist/src/utils/paths.js +2 -1
  217. package/dist/src/utils/paths.js.map +1 -1
  218. package/dist/tsconfig.tsbuildinfo +1 -1
  219. package/org-skills/adversarial-reviewer/SKILL.md +1 -1
  220. package/org-skills/board-deck-builder/SKILL.md +1 -1
  221. package/org-skills/code-reviewer/SKILL.md +1 -1
  222. package/org-skills/debugging-wizard/SKILL.md +1 -1
  223. package/org-skills/scientific-thinking-literature-review/SKILL.md +1 -1
  224. package/org-skills/scientific-thinking-scholar-evaluation/SKILL.md +1 -1
  225. package/package.json +8 -8
@@ -0,0 +1,262 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+
4
+ // Org dashboard routes: warm knowledge search.
5
+ // Registered, in order, by handleOrgRoutes in routes-org.mjs.
6
+ export async function handleOrgKnowledgeRoutes(req, res, url, corsOrigin, ctx) {
7
+ // POST /api/knowledge/search — warm semantic knowledge search for hooks.
8
+ // The dashboard server is the one long-lived process on the machine, so it
9
+ // holds the local embedding model warm; per-prompt hook subprocesses (which
10
+ // cannot afford a model load) POST here and fall back to keyword scoring
11
+ // when this endpoint is cold/absent. Fully local — model + store on disk.
12
+ if (req.method === 'POST' && url === '/api/knowledge/search') {
13
+ let body = '';
14
+ let overLimit = false;
15
+ req.on('data', (c) => {
16
+ if (overLimit) return;
17
+ body += c;
18
+ if (body.length > 64 * 1024) {
19
+ // queries are prompts, not documents
20
+ overLimit = true;
21
+ res.writeHead(413, { 'Content-Type': 'application/json' });
22
+ res.end('{"error":"request body too large"}');
23
+ req.destroy();
24
+ }
25
+ });
26
+ req.on('end', async () => {
27
+ if (overLimit) return;
28
+ try {
29
+ const payload = JSON.parse(body || '{}');
30
+ const query = String(payload.query || '').slice(0, 2000);
31
+ const limit = Math.min(Math.max(parseInt(payload.limit, 10) || 3, 1), 10);
32
+ const namespace =
33
+ typeof payload.namespace === 'string' && /^[A-Za-z0-9:_-]{1,128}$/.test(payload.namespace)
34
+ ? payload.namespace
35
+ : 'knowledge:shared';
36
+ if (!query) {
37
+ res.writeHead(400, { 'Content-Type': 'application/json' });
38
+ res.end('{"error":"query required"}');
39
+ return;
40
+ }
41
+ const bridge = await ctx._getKnowledgeBridge();
42
+ if (!bridge) {
43
+ res.writeHead(503, { 'Content-Type': 'application/json' });
44
+ res.end('{"error":"knowledge bridge unavailable"}');
45
+ return;
46
+ }
47
+ // scope: project | global | all (default all) — project results get a
48
+ // small tie boost; global hits are flagged so callers can show origin.
49
+ const scope =
50
+ payload.scope === 'project' || payload.scope === 'global' ? payload.scope : 'all';
51
+ // Rule-based router (no LLM): chunks always run (this endpoint's
52
+ // bread and butter); the auxiliary surfaces — distilled rules,
53
+ // knowledge-graph triplets, pattern memories — only spend a query
54
+ // when the router votes for them or routing is unconfident.
55
+ let wantRules = true,
56
+ wantKg = true,
57
+ wantMemory = true;
58
+ let rrfFuse = null;
59
+ try {
60
+ const routerMod = await import('../memory/query-router.js');
61
+ const route = routerMod.routeQuery(query);
62
+ rrfFuse = routerMod.rrfFuse;
63
+ wantRules = !route.confident || route.surfaces.includes('rules');
64
+ wantKg = !route.confident || route.surfaces.includes('kg');
65
+ wantMemory = !route.confident || route.surfaces.includes('memory');
66
+ } catch {
67
+ /* router unavailable — keep all surfaces on */
68
+ }
69
+ let kgSearch = null;
70
+ if (wantKg && scope !== 'global') {
71
+ try {
72
+ kgSearch = (await import('../memory/memory-kg.js')).kgSearch;
73
+ } catch {
74
+ /* kg unavailable */
75
+ }
76
+ }
77
+ // Superseded-version filtering — the SAME rule `searchKnowledge` (and
78
+ // therefore `monomind doc search` / `knowledge_search`) applies. This
79
+ // endpoint queries the bridge directly for warmth, so without this it
80
+ // would inject old document versions the Second Brain itself hides.
81
+ let liveProj = new Set(),
82
+ liveGlob = new Set(),
83
+ isSuperseded = () => false,
84
+ overfetch = (n) => n;
85
+ // metaProj/metaGlob distinguish "no metadata log" (cannot judge, keep
86
+ // everything) from "log exists and is empty" (every document was
87
+ // removed, keep nothing). Without them, `doc remove` of the last
88
+ // document left its chunks being injected into every prompt.
89
+ let metaProj = false,
90
+ metaGlob = false;
91
+ try {
92
+ const dp = await import('../knowledge/document-pipeline.js');
93
+ // CLAUDE_PROJECT_DIR is whatever directory the user opened, which
94
+ // can be a package subdirectory, while the CLI writes the metadata
95
+ // log at the project root. Walk up to the nearest one that has it:
96
+ // resolving the wrong root yields an empty live set, which silently
97
+ // turns filtering OFF — and superseded rows are the large majority
98
+ // of a long-lived store, so injection would be dominated by stale
99
+ // document versions.
100
+ const resolveKnowledgeRoot = (start) => {
101
+ let probe = path.resolve(start);
102
+ for (let up = 0; up < 8; up++) {
103
+ if (dp.hasKnowledgeMetadata?.(probe)) return probe;
104
+ const parent = path.dirname(probe);
105
+ if (parent === probe) break;
106
+ probe = parent;
107
+ }
108
+ return path.resolve(start);
109
+ };
110
+ const projRoot = resolveKnowledgeRoot(process.env.CLAUDE_PROJECT_DIR || process.cwd());
111
+ const globRoot =
112
+ process.env.MONOMIND_GLOBAL_BRAIN_DIR ||
113
+ path.join(os.homedir(), '.monomind', 'global-brain');
114
+ liveProj = dp.liveContentHashes(projRoot);
115
+ liveGlob = dp.liveContentHashes(globRoot);
116
+ metaProj = dp.hasKnowledgeMetadata?.(projRoot) ?? liveProj.size > 0;
117
+ metaGlob = dp.hasKnowledgeMetadata?.(globRoot) ?? liveGlob.size > 0;
118
+ isSuperseded = dp.isSupersededKey;
119
+ overfetch = dp.supersededOverfetchLimit;
120
+ } catch {
121
+ /* pipeline unavailable — no filtering, same as before */
122
+ }
123
+ const keepLive = (rows, live, hasMeta) =>
124
+ (rows || [])
125
+ .filter((r) => !isSuperseded(String(r.key || ''), live, hasMeta))
126
+ .slice(0, limit);
127
+ const [projRaw, globRaw, rules, graph, mems] = await Promise.all([
128
+ scope !== 'global'
129
+ ? bridge
130
+ .bridgeSearchEntries({ query, namespace, limit: overfetch(limit, liveProj) })
131
+ .catch(() => null)
132
+ : null,
133
+ scope !== 'project'
134
+ ? bridge
135
+ .bridgeSearchEntries({
136
+ query,
137
+ namespace: 'knowledge:global',
138
+ limit: overfetch(limit, liveGlob),
139
+ dbPath: '@global',
140
+ })
141
+ .catch(() => null)
142
+ : null,
143
+ // Distilled rules ("when X do Y") learned from sessions/runs —
144
+ // small namespace, high injection value, threshold keeps it quiet.
145
+ scope !== 'global' && wantRules
146
+ ? bridge
147
+ .bridgeSearchEntries({ query, namespace: 'rules', limit: 2, threshold: 0.45 })
148
+ .catch(() => null)
149
+ : null,
150
+ // Knowledge-graph triplets: relationship-shaped queries surface
151
+ // facts no chunk contains. Triplet scores derive from seeded
152
+ // cosine matches (≥0.35), so they clear callers' relevance floors.
153
+ scope !== 'global' && kgSearch ? kgSearch({ query, limit: 4 }).catch(() => null) : null,
154
+ // Past patterns/decisions for "last time / previously" queries.
155
+ scope !== 'global' && wantMemory
156
+ ? bridge
157
+ .bridgeSearchEntries({ query, namespace: 'patterns', limit: 2, threshold: 0.4 })
158
+ .catch(() => null)
159
+ : null,
160
+ ]);
161
+ const lists = [
162
+ keepLive(projRaw?.results, liveProj, metaProj).map((r) => ({
163
+ id: r.id,
164
+ key: r.key,
165
+ content: String(r.content || '').slice(0, 2000),
166
+ score: r.score + 0.05,
167
+ global: false,
168
+ tags: r.tags,
169
+ importance: 0.6,
170
+ })),
171
+ keepLive(globRaw?.results, liveGlob, metaGlob).map((r) => ({
172
+ id: r.id,
173
+ key: r.key,
174
+ content: String(r.content || '').slice(0, 2000),
175
+ score: r.score,
176
+ global: true,
177
+ tags: r.tags,
178
+ })),
179
+ (rules?.results || []).map((r) => ({
180
+ id: r.id,
181
+ key: r.key,
182
+ content: String(r.content || '').slice(0, 2000),
183
+ score: r.score + 0.05,
184
+ global: false,
185
+ rule: true,
186
+ tags: r.tags,
187
+ importance: 0.7,
188
+ })),
189
+ (graph?.triplets || []).map((t, i) => ({
190
+ id: `kg:${i}:${t.source}|${t.relation}|${t.target}`,
191
+ key: `kg:${t.source}`,
192
+ content: String(
193
+ t.source +
194
+ ' —' +
195
+ t.relation +
196
+ '→ ' +
197
+ t.target +
198
+ (t.fact && t.fact !== `${t.source} ${t.relation} ${t.target}`
199
+ ? ` (${String(t.fact).slice(0, 300)})`
200
+ : ''),
201
+ ).slice(0, 2000),
202
+ score: t.score,
203
+ global: false,
204
+ triplet: true,
205
+ })),
206
+ (mems?.results || []).map((r) => ({
207
+ id: r.id,
208
+ key: r.key,
209
+ content: String(r.content || '').slice(0, 2000),
210
+ score: r.score,
211
+ global: false,
212
+ memory: true,
213
+ tags: r.tags,
214
+ })),
215
+ ];
216
+ // Rank-fuse across surfaces (raw scores aren't comparable between
217
+ // cosine chunks and blended triplets); each item keeps its native
218
+ // score so downstream relevance floors still apply. Fallback: flat
219
+ // score sort when the router module failed to load.
220
+ const merged = (
221
+ rrfFuse
222
+ ? rrfFuse(lists, limit)
223
+ : lists
224
+ .flat()
225
+ .sort((a, b) => b.score - a.score)
226
+ .slice(0, limit)
227
+ ).map(({ importance, rrf, ...r }) => r);
228
+ // Served excerpts are (very likely) injected into the caller's prompt —
229
+ // that IS usage. Reinforce frequency_weight, per-store, fire-and-forget.
230
+ try {
231
+ const projIds = merged.filter((m) => !m.global && !m.triplet && m.id).map((m) => m.id);
232
+ const globIds = merged.filter((m) => m.global && m.id).map((m) => m.id);
233
+ if (projIds.length) bridge.bridgeRecordUsage?.({ entryIds: projIds }).catch(() => {});
234
+ if (globIds.length)
235
+ bridge.bridgeRecordUsage?.({ entryIds: globIds, dbPath: '@global' }).catch(() => {});
236
+ } catch {
237
+ /* best effort */
238
+ }
239
+ res.writeHead(200, {
240
+ 'Content-Type': 'application/json',
241
+ ...(corsOrigin ? { 'Access-Control-Allow-Origin': corsOrigin } : {}),
242
+ });
243
+ res.end(
244
+ JSON.stringify({
245
+ method:
246
+ projRaw?.searchMethod ||
247
+ globRaw?.searchMethod ||
248
+ rules?.searchMethod ||
249
+ mems?.searchMethod ||
250
+ (merged.length ? 'mixed' : 'none'),
251
+ results: merged,
252
+ }),
253
+ );
254
+ } catch (err) {
255
+ res.writeHead(500, { 'Content-Type': 'application/json' });
256
+ res.end(JSON.stringify({ error: err.message }));
257
+ }
258
+ });
259
+ return true;
260
+ }
261
+ return false;
262
+ }
@@ -0,0 +1,224 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ // Org dashboard routes: org delete, stop and copy.
5
+ // Registered, in order, by handleOrgRoutes in routes-org.mjs.
6
+ export async function handleOrgLifecycleRoutes(req, res, url, corsOrigin, ctx) {
7
+ // DELETE /api/orgs/:name — delete an org config and all associated data files
8
+ if (req.method === 'DELETE' && url.match(/^\/api\/orgs\/[a-z0-9][a-z0-9_-]{0,63}(\?.*)?$/i)) {
9
+ try {
10
+ const orgName = decodeURIComponent(url.split('/')[3].split('?')[0]);
11
+ if (orgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) {
12
+ res.writeHead(400);
13
+ res.end('Invalid org name');
14
+ return true;
15
+ }
16
+ const _delOrgQs = new URL(req.url, 'http://localhost').searchParams;
17
+ const orgsDir = path.join(
18
+ path.resolve(_delOrgQs.get('dir') || ctx.projectDir || process.cwd()),
19
+ '.monomind',
20
+ 'orgs',
21
+ );
22
+ const configFile = path.join(orgsDir, `${orgName}.json`);
23
+ const v1ConfigFile = path.join(orgsDir, `${orgName}.v1.json`);
24
+ if (!fs.existsSync(configFile) && !fs.existsSync(v1ConfigFile)) {
25
+ res.writeHead(404);
26
+ res.end('{"error":"org not found"}');
27
+ return true;
28
+ }
29
+ // Remove all org-associated files (config + state + data)
30
+ try {
31
+ if (fs.existsSync(v1ConfigFile)) fs.unlinkSync(v1ConfigFile);
32
+ } catch (_) {}
33
+ const suffixes = [
34
+ '',
35
+ '-state',
36
+ '-goals',
37
+ '-routines',
38
+ '-approvals',
39
+ '-activity',
40
+ '-issues',
41
+ '-members',
42
+ '-projects',
43
+ '-workspaces',
44
+ '-worktrees',
45
+ '-environments',
46
+ '-plugins',
47
+ '-adapters',
48
+ '-budgets',
49
+ '-threads',
50
+ '-secrets',
51
+ '-join-requests',
52
+ '-bootstrap',
53
+ '-project-workspaces',
54
+ '-approval-comments',
55
+ '-skills',
56
+ ];
57
+ for (const suf of suffixes) {
58
+ const f = path.join(orgsDir, `${orgName}${suf}.json`);
59
+ try {
60
+ if (fs.existsSync(f)) fs.unlinkSync(f);
61
+ } catch (_) {}
62
+ const fjsonl = path.join(orgsDir, `${orgName}${suf}.jsonl`);
63
+ try {
64
+ if (fs.existsSync(fjsonl)) fs.unlinkSync(fjsonl);
65
+ } catch (_) {}
66
+ }
67
+ // Remove stop file if present
68
+ try {
69
+ fs.unlinkSync(path.join(orgsDir, '.stops', `${orgName}.stop`));
70
+ } catch (_) {}
71
+ // Remove org subdirectory under .monomind/orgs/ (legacy flat-file location)
72
+ try {
73
+ const orgWorkDir = path.join(orgsDir, orgName);
74
+ if (fs.existsSync(orgWorkDir)) fs.rmSync(orgWorkDir, { recursive: true, force: true });
75
+ } catch (_) {}
76
+ // Remove org subdirectory under git-safe location (.git/monomind/orgs/<name>/) so run
77
+ // files written by the worktree-aware path (feat 880f034e) are also cleaned up on delete
78
+ try {
79
+ const _delWorkDir = path.resolve(_delOrgQs.get('dir') || ctx.projectDir || process.cwd());
80
+ const _delGitMonoDir = ctx._getGitMonomindDir(_delWorkDir);
81
+ if (_delGitMonoDir) {
82
+ const gitOrgDir = path.join(_delGitMonoDir, 'orgs', orgName);
83
+ if (fs.existsSync(gitOrgDir)) fs.rmSync(gitOrgDir, { recursive: true, force: true });
84
+ }
85
+ } catch (_) {}
86
+ // Remove loop prompt file if present (created for scheduled orgs by createorg)
87
+ try {
88
+ const lpf = path.join(
89
+ path.resolve(ctx.projectDir || process.cwd()),
90
+ '.monomind',
91
+ 'loops',
92
+ `${orgName}.md`,
93
+ );
94
+ if (fs.existsSync(lpf)) fs.unlinkSync(lpf);
95
+ } catch (_) {}
96
+ // Emit org:delete event
97
+ const deleteEvent = { type: 'org:delete', org: orgName, ts: Date.now() };
98
+ ctx
99
+ .appendToFile(
100
+ path.join(ctx.projectDir || process.cwd(), 'data', 'mastermind-events.jsonl'),
101
+ `${JSON.stringify(deleteEvent)}\n`,
102
+ )
103
+ .catch(() => {});
104
+ ctx.broadcastMm(deleteEvent);
105
+ res.writeHead(200, {
106
+ 'Content-Type': 'application/json',
107
+ ...(corsOrigin ? { 'Access-Control-Allow-Origin': corsOrigin } : {}),
108
+ });
109
+ res.end('{"ok":true}');
110
+ } catch (_) {
111
+ res.writeHead(500);
112
+ res.end('{}');
113
+ }
114
+ return true;
115
+ }
116
+
117
+ // POST /api/orgs/:name/stop — send stop signal to a running org
118
+ if (req.method === 'POST' && url.match(/^\/api\/orgs\/[a-z0-9][a-z0-9_-]{0,63}\/stop$/i)) {
119
+ try {
120
+ const orgName = decodeURIComponent(url.split('/')[3]);
121
+ if (orgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) {
122
+ res.writeHead(400);
123
+ res.end('Invalid org name');
124
+ return true;
125
+ }
126
+ const _stopOrgQs = new URL(req.url, 'http://localhost').searchParams;
127
+ const _stopOrgBase = path.resolve(_stopOrgQs.get('dir') || ctx.projectDir || process.cwd());
128
+ const stopEvent = { type: 'org:stop', org: orgName, ts: Date.now() };
129
+ const dataDir = path.join(_stopOrgBase, 'data');
130
+ try {
131
+ fs.mkdirSync(dataDir, { recursive: true });
132
+ } catch (_) {}
133
+ ctx
134
+ .appendToFile(
135
+ path.join(dataDir, 'mastermind-events.jsonl'),
136
+ `${JSON.stringify(stopEvent)}\n`,
137
+ )
138
+ .catch(() => {});
139
+ // Write stop marker file at the path the REAL stop mechanisms poll:
140
+ // `org run`'s own poll loop and `org serve`'s pollStopfiles() both watch
141
+ // .monomind/orgs/<name>/stop (see clearStopfile/stopAction/pollStopfiles in
142
+ // commands/org.ts) — NOT .monomind/orgs/.stops/<name>.stop, which nothing
143
+ // in the CLI/daemon ever reads.
144
+ try {
145
+ const stopDir = path.join(_stopOrgBase, '.monomind', 'orgs', orgName);
146
+ fs.mkdirSync(stopDir, { recursive: true });
147
+ fs.writeFileSync(path.join(stopDir, 'stop'), new Date().toISOString());
148
+ } catch (_) {}
149
+ ctx.broadcastMm(stopEvent);
150
+ res.writeHead(200, {
151
+ 'Content-Type': 'application/json',
152
+ ...(corsOrigin ? { 'Access-Control-Allow-Origin': corsOrigin } : {}),
153
+ });
154
+ res.end('{"ok":true}');
155
+ } catch (_) {
156
+ res.writeHead(500);
157
+ res.end('{}');
158
+ }
159
+ return true;
160
+ }
161
+
162
+ // POST /api/orgs/:name/copy — copy org config to another project directory
163
+ if (req.method === 'POST' && url.match(/^\/api\/orgs\/[a-z0-9][a-z0-9_-]{0,63}\/copy$/i)) {
164
+ let body = '';
165
+ for await (const chunk of req) {
166
+ body += chunk;
167
+ if (body.length > 2097152) {
168
+ req.destroy();
169
+ break;
170
+ }
171
+ }
172
+ try {
173
+ const orgName = decodeURIComponent(url.split('/')[3]);
174
+ if (orgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) {
175
+ res.writeHead(400);
176
+ res.end(JSON.stringify({ error: 'Invalid org name' }));
177
+ return true;
178
+ }
179
+ let payload = {};
180
+ try {
181
+ payload = JSON.parse(body);
182
+ } catch (_) {}
183
+ const destination = payload.destination ? String(payload.destination).trim() : '';
184
+ if (!destination) {
185
+ res.writeHead(400);
186
+ res.end(JSON.stringify({ error: 'destination is required' }));
187
+ return true;
188
+ }
189
+ if (!path.isAbsolute(destination)) {
190
+ res.writeHead(400);
191
+ res.end(JSON.stringify({ error: 'destination must be an absolute path' }));
192
+ return true;
193
+ }
194
+ const _copyOrgQs = new URL(req.url, 'http://localhost').searchParams;
195
+ const srcOrgsDir = path.join(
196
+ path.resolve(_copyOrgQs.get('dir') || ctx.projectDir || process.cwd()),
197
+ '.monomind',
198
+ 'orgs',
199
+ );
200
+ const srcFile = path.join(srcOrgsDir, `${orgName}.json`);
201
+ if (!fs.existsSync(srcFile)) {
202
+ res.writeHead(404);
203
+ res.end(JSON.stringify({ error: 'org not found' }));
204
+ return true;
205
+ }
206
+ const destOrgsDir = path.join(path.resolve(destination), '.monomind', 'orgs');
207
+ try {
208
+ fs.mkdirSync(destOrgsDir, { recursive: true });
209
+ } catch (_) {}
210
+ const destFile = path.join(destOrgsDir, `${orgName}.json`);
211
+ fs.copyFileSync(srcFile, destFile);
212
+ res.writeHead(200, {
213
+ 'Content-Type': 'application/json',
214
+ ...(corsOrigin ? { 'Access-Control-Allow-Origin': corsOrigin } : {}),
215
+ });
216
+ res.end(JSON.stringify({ ok: true, destFile }));
217
+ } catch (e) {
218
+ res.writeHead(500);
219
+ res.end(JSON.stringify({ error: String(e.message || e) }));
220
+ }
221
+ return true;
222
+ }
223
+ return false;
224
+ }