@monoes/monomindcli 2.16.12 → 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.
- package/.claude/agents/core/coder.md +1 -1
- package/.claude/agents/engineering/engineering-devops-automator.md +1 -1
- package/.claude/agents/github/repo-architect.md +1 -1
- package/.claude/agents/testing/production-validator.md +1 -1
- package/.claude/agents/testing/testing-tool-evaluator.md +1 -1
- package/.claude/commands/github/pr-manager.md +1 -1
- package/.claude/helpers/pick-rank.cjs +34 -4
- package/.claude/skills/monolean-audit/SKILL.md +1 -1
- package/dist/src/commands/cleanup-data.d.ts +30 -0
- package/dist/src/commands/cleanup-data.d.ts.map +1 -0
- package/dist/src/commands/cleanup-data.js +138 -0
- package/dist/src/commands/cleanup-data.js.map +1 -0
- package/dist/src/commands/cleanup-scratch.d.ts +43 -0
- package/dist/src/commands/cleanup-scratch.d.ts.map +1 -0
- package/dist/src/commands/cleanup-scratch.js +125 -0
- package/dist/src/commands/cleanup-scratch.js.map +1 -0
- package/dist/src/commands/cleanup.d.ts +2 -39
- package/dist/src/commands/cleanup.d.ts.map +1 -1
- package/dist/src/commands/cleanup.js +5 -247
- package/dist/src/commands/cleanup.js.map +1 -1
- package/dist/src/commands/doctor-gitignore-checks.d.ts +10 -0
- package/dist/src/commands/doctor-gitignore-checks.d.ts.map +1 -0
- package/dist/src/commands/doctor-gitignore-checks.js +141 -0
- package/dist/src/commands/doctor-gitignore-checks.js.map +1 -0
- package/dist/src/commands/doctor-helpers-checks.d.ts +10 -0
- package/dist/src/commands/doctor-helpers-checks.d.ts.map +1 -0
- package/dist/src/commands/doctor-helpers-checks.js +292 -0
- package/dist/src/commands/doctor-helpers-checks.js.map +1 -0
- package/dist/src/commands/doctor-memory-checks.d.ts +47 -0
- package/dist/src/commands/doctor-memory-checks.d.ts.map +1 -0
- package/dist/src/commands/doctor-memory-checks.js +298 -0
- package/dist/src/commands/doctor-memory-checks.js.map +1 -0
- package/dist/src/commands/doctor-monograph-checks.d.ts +9 -0
- package/dist/src/commands/doctor-monograph-checks.d.ts.map +1 -0
- package/dist/src/commands/doctor-monograph-checks.js +331 -0
- package/dist/src/commands/doctor-monograph-checks.js.map +1 -0
- package/dist/src/commands/doctor-project-checks.d.ts +7 -66
- package/dist/src/commands/doctor-project-checks.d.ts.map +1 -1
- package/dist/src/commands/doctor-project-checks.js +10 -1331
- package/dist/src/commands/doctor-project-checks.js.map +1 -1
- package/dist/src/commands/doctor-routing-checks.d.ts +10 -0
- package/dist/src/commands/doctor-routing-checks.d.ts.map +1 -0
- package/dist/src/commands/doctor-routing-checks.js +194 -0
- package/dist/src/commands/doctor-routing-checks.js.map +1 -0
- package/dist/src/commands/doctor-worker-checks.d.ts +17 -0
- package/dist/src/commands/doctor-worker-checks.d.ts.map +1 -0
- package/dist/src/commands/doctor-worker-checks.js +122 -0
- package/dist/src/commands/doctor-worker-checks.js.map +1 -0
- package/dist/src/commands/hooks-routing-commands.js +1 -1
- package/dist/src/commands/hooks-routing-commands.js.map +1 -1
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +6 -15
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/init/never-commit.d.ts +3 -3
- package/dist/src/init/types.d.ts +1 -1
- package/dist/src/init/types.js +1 -1
- package/dist/src/knowledge/document-store.js +1 -1
- package/dist/src/knowledge/document-store.js.map +1 -1
- package/dist/src/mcp-tools/hooks-edit-command.d.ts +10 -0
- package/dist/src/mcp-tools/hooks-edit-command.d.ts.map +1 -0
- package/dist/src/mcp-tools/hooks-edit-command.js +247 -0
- package/dist/src/mcp-tools/hooks-edit-command.js.map +1 -0
- package/dist/src/mcp-tools/hooks-learning.d.ts +9 -0
- package/dist/src/mcp-tools/hooks-learning.d.ts.map +1 -0
- package/dist/src/mcp-tools/hooks-learning.js +408 -0
- package/dist/src/mcp-tools/hooks-learning.js.map +1 -0
- package/dist/src/mcp-tools/hooks-metrics-list.d.ts +8 -0
- package/dist/src/mcp-tools/hooks-metrics-list.d.ts.map +1 -0
- package/dist/src/mcp-tools/hooks-metrics-list.js +205 -0
- package/dist/src/mcp-tools/hooks-metrics-list.js.map +1 -0
- package/dist/src/mcp-tools/hooks-route.d.ts +12 -0
- package/dist/src/mcp-tools/hooks-route.d.ts.map +1 -0
- package/dist/src/mcp-tools/hooks-route.js +251 -0
- package/dist/src/mcp-tools/hooks-route.js.map +1 -0
- package/dist/src/mcp-tools/hooks-routing.d.ts +6 -27
- package/dist/src/mcp-tools/hooks-routing.d.ts.map +1 -1
- package/dist/src/mcp-tools/hooks-routing.js +6 -1727
- package/dist/src/mcp-tools/hooks-routing.js.map +1 -1
- package/dist/src/mcp-tools/hooks-session.d.ts +9 -0
- package/dist/src/mcp-tools/hooks-session.d.ts.map +1 -0
- package/dist/src/mcp-tools/hooks-session.js +243 -0
- package/dist/src/mcp-tools/hooks-session.js.map +1 -0
- package/dist/src/mcp-tools/hooks-task.d.ts +17 -0
- package/dist/src/mcp-tools/hooks-task.d.ts.map +1 -0
- package/dist/src/mcp-tools/hooks-task.js +427 -0
- package/dist/src/mcp-tools/hooks-task.js.map +1 -0
- package/dist/src/mcp-tools/hooks-tools.d.ts +2 -1
- package/dist/src/mcp-tools/hooks-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/hooks-tools.js +2 -1
- package/dist/src/mcp-tools/hooks-tools.js.map +1 -1
- package/dist/src/mcp-tools/memory-tools.js +1 -1
- package/dist/src/mcp-tools/memory-tools.js.map +1 -1
- package/dist/src/memory/bm25-index.d.ts +2 -2
- package/dist/src/memory/bm25-index.js +2 -2
- package/dist/src/memory/embedding-operations.js +2 -2
- package/dist/src/memory/embedding-operations.js.map +1 -1
- package/dist/src/memory/entity-name-key.d.ts +1 -1
- package/dist/src/memory/entity-name-key.js +1 -1
- package/dist/src/memory/hnsw-operations.d.ts +1 -1
- package/dist/src/memory/hnsw-operations.js +1 -1
- package/dist/src/memory/memory-bridge-backend.d.ts +43 -0
- package/dist/src/memory/memory-bridge-backend.d.ts.map +1 -0
- package/dist/src/memory/memory-bridge-backend.js +363 -0
- package/dist/src/memory/memory-bridge-backend.js.map +1 -0
- package/dist/src/memory/memory-bridge-core.d.ts +42 -0
- package/dist/src/memory/memory-bridge-core.d.ts.map +1 -0
- package/dist/src/memory/memory-bridge-core.js +126 -0
- package/dist/src/memory/memory-bridge-core.js.map +1 -0
- package/dist/src/memory/memory-bridge-entries.d.ts +131 -0
- package/dist/src/memory/memory-bridge-entries.d.ts.map +1 -0
- package/dist/src/memory/memory-bridge-entries.js +227 -0
- package/dist/src/memory/memory-bridge-entries.js.map +1 -0
- package/dist/src/memory/memory-bridge-feedback.d.ts +60 -0
- package/dist/src/memory/memory-bridge-feedback.d.ts.map +1 -0
- package/dist/src/memory/memory-bridge-feedback.js +118 -0
- package/dist/src/memory/memory-bridge-feedback.js.map +1 -0
- package/dist/src/memory/memory-bridge-paths.d.ts +123 -0
- package/dist/src/memory/memory-bridge-paths.d.ts.map +1 -0
- package/dist/src/memory/memory-bridge-paths.js +335 -0
- package/dist/src/memory/memory-bridge-paths.js.map +1 -0
- package/dist/src/memory/memory-bridge-search.d.ts +48 -0
- package/dist/src/memory/memory-bridge-search.d.ts.map +1 -0
- package/dist/src/memory/memory-bridge-search.js +383 -0
- package/dist/src/memory/memory-bridge-search.js.map +1 -0
- package/dist/src/memory/memory-bridge-sessions.d.ts +38 -0
- package/dist/src/memory/memory-bridge-sessions.d.ts.map +1 -0
- package/dist/src/memory/memory-bridge-sessions.js +109 -0
- package/dist/src/memory/memory-bridge-sessions.js.map +1 -0
- package/dist/src/memory/memory-bridge-store.d.ts +58 -0
- package/dist/src/memory/memory-bridge-store.d.ts.map +1 -0
- package/dist/src/memory/memory-bridge-store.js +201 -0
- package/dist/src/memory/memory-bridge-store.js.map +1 -0
- package/dist/src/memory/memory-bridge.d.ts +10 -438
- package/dist/src/memory/memory-bridge.d.ts.map +1 -1
- package/dist/src/memory/memory-bridge.js +14 -1787
- package/dist/src/memory/memory-bridge.js.map +1 -1
- package/dist/src/memory/memory-kg-claims.d.ts +52 -0
- package/dist/src/memory/memory-kg-claims.d.ts.map +1 -0
- package/dist/src/memory/memory-kg-claims.js +99 -0
- package/dist/src/memory/memory-kg-claims.js.map +1 -0
- package/dist/src/memory/memory-kg-index.d.ts +86 -0
- package/dist/src/memory/memory-kg-index.d.ts.map +1 -0
- package/dist/src/memory/memory-kg-index.js +256 -0
- package/dist/src/memory/memory-kg-index.js.map +1 -0
- package/dist/src/memory/memory-kg-ingest.d.ts +44 -0
- package/dist/src/memory/memory-kg-ingest.d.ts.map +1 -0
- package/dist/src/memory/memory-kg-ingest.js +361 -0
- package/dist/src/memory/memory-kg-ingest.js.map +1 -0
- package/dist/src/memory/memory-kg-model.d.ts +168 -0
- package/dist/src/memory/memory-kg-model.d.ts.map +1 -0
- package/dist/src/memory/memory-kg-model.js +158 -0
- package/dist/src/memory/memory-kg-model.js.map +1 -0
- package/dist/src/memory/memory-kg-names.d.ts +64 -0
- package/dist/src/memory/memory-kg-names.d.ts.map +1 -0
- package/dist/src/memory/memory-kg-names.js +187 -0
- package/dist/src/memory/memory-kg-names.js.map +1 -0
- package/dist/src/memory/memory-kg-promote.d.ts +79 -0
- package/dist/src/memory/memory-kg-promote.d.ts.map +1 -0
- package/dist/src/memory/memory-kg-promote.js +248 -0
- package/dist/src/memory/memory-kg-promote.js.map +1 -0
- package/dist/src/memory/memory-kg-rebuild.d.ts +77 -0
- package/dist/src/memory/memory-kg-rebuild.d.ts.map +1 -0
- package/dist/src/memory/memory-kg-rebuild.js +299 -0
- package/dist/src/memory/memory-kg-rebuild.js.map +1 -0
- package/dist/src/memory/memory-kg-rollback.d.ts +47 -0
- package/dist/src/memory/memory-kg-rollback.d.ts.map +1 -0
- package/dist/src/memory/memory-kg-rollback.js +193 -0
- package/dist/src/memory/memory-kg-rollback.js.map +1 -0
- package/dist/src/memory/memory-kg-rules.d.ts +64 -0
- package/dist/src/memory/memory-kg-rules.d.ts.map +1 -0
- package/dist/src/memory/memory-kg-rules.js +251 -0
- package/dist/src/memory/memory-kg-rules.js.map +1 -0
- package/dist/src/memory/memory-kg-scan.d.ts +118 -0
- package/dist/src/memory/memory-kg-scan.d.ts.map +1 -0
- package/dist/src/memory/memory-kg-scan.js +209 -0
- package/dist/src/memory/memory-kg-scan.js.map +1 -0
- package/dist/src/memory/memory-kg-search.d.ts +80 -0
- package/dist/src/memory/memory-kg-search.d.ts.map +1 -0
- package/dist/src/memory/memory-kg-search.js +239 -0
- package/dist/src/memory/memory-kg-search.js.map +1 -0
- package/dist/src/memory/memory-kg.d.ts +19 -547
- package/dist/src/memory/memory-kg.d.ts.map +1 -1
- package/dist/src/memory/memory-kg.js +10 -2389
- package/dist/src/memory/memory-kg.js.map +1 -1
- package/dist/src/ui/org-hil.mjs +1 -1
- package/dist/src/ui/routes-org-agents.mjs +318 -0
- package/dist/src/ui/routes-org-approvals.mjs +133 -0
- package/dist/src/ui/routes-org-config.mjs +459 -0
- package/dist/src/ui/routes-org-control.mjs +300 -0
- package/dist/src/ui/routes-org-files.mjs +172 -0
- package/dist/src/ui/routes-org-helpers.mjs +84 -0
- package/dist/src/ui/routes-org-knowledge.mjs +262 -0
- package/dist/src/ui/routes-org-lifecycle.mjs +224 -0
- package/dist/src/ui/routes-org-live.mjs +278 -0
- package/dist/src/ui/routes-org-mastermind.mjs +346 -0
- package/dist/src/ui/routes-org-planning.mjs +398 -0
- package/dist/src/ui/routes-org-runs.mjs +430 -0
- package/dist/src/ui/routes-org-status.mjs +342 -0
- package/dist/src/ui/routes-org-workflows.mjs +212 -0
- package/dist/src/ui/routes-org.mjs +26 -3847
- package/dist/src/ui/server.mjs +1 -1
- package/dist/src/utils/native-error.d.ts +1 -1
- package/dist/src/utils/native-error.js +1 -1
- package/dist/src/utils/paths.d.ts +2 -1
- package/dist/src/utils/paths.d.ts.map +1 -1
- package/dist/src/utils/paths.js +2 -1
- package/dist/src/utils/paths.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/org-skills/adversarial-reviewer/SKILL.md +1 -1
- package/org-skills/board-deck-builder/SKILL.md +1 -1
- package/org-skills/code-reviewer/SKILL.md +1 -1
- package/org-skills/debugging-wizard/SKILL.md +1 -1
- package/org-skills/scientific-thinking-literature-review/SKILL.md +1 -1
- package/org-skills/scientific-thinking-scholar-evaluation/SKILL.md +1 -1
- 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
|
+
}
|