@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,430 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
// forwarder.js is compiled from orgrt/forwarder.ts (dist/src/orgrt/forwarder.js
|
|
4
|
+
// sits alongside this file's own compiled copy in dist/src/ui/ after
|
|
5
|
+
// build; under vitest the .js specifier resolves straight to the .ts source,
|
|
6
|
+
// same as every other cross-reference in this codebase). translate()/
|
|
7
|
+
// companionEvents() are pure — no filesystem or process side effects — so
|
|
8
|
+
// importing them here doesn't pull in attachForwarder's spawn/heal logic.
|
|
9
|
+
import { companionEvents, translate } from '../orgrt/forwarder.js';
|
|
10
|
+
|
|
11
|
+
// Org dashboard routes: run list and run events.
|
|
12
|
+
// Registered, in order, by handleOrgRoutes in routes-org.mjs.
|
|
13
|
+
export async function handleOrgRunRoutes(req, res, url, corsOrigin, ctx) {
|
|
14
|
+
// GET /api/org/:name/runs — list structured run files for an org
|
|
15
|
+
if (req.method === 'GET' && /^\/api\/org\/[a-z0-9][a-z0-9_-]{0,63}\/runs(\?.*)?$/i.test(url)) {
|
|
16
|
+
try {
|
|
17
|
+
const _rQs = new URL(req.url, 'http://localhost').searchParams;
|
|
18
|
+
const _rOrgName = decodeURIComponent(url.split('/')[3] || '');
|
|
19
|
+
if (_rOrgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(_rOrgName)) {
|
|
20
|
+
res.writeHead(400);
|
|
21
|
+
res.end('{"error":"Invalid org name"}');
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
const _rExplicitDir = _rQs.get('dir');
|
|
25
|
+
const _rServerRoot = path.resolve(_rExplicitDir || ctx.projectDir || process.cwd());
|
|
26
|
+
// Search across known projects (same logic as /api/orgs) unless explicit dir given
|
|
27
|
+
const _rProjDirs = new Set([_rServerRoot]);
|
|
28
|
+
if (!_rExplicitDir) {
|
|
29
|
+
try {
|
|
30
|
+
const _rKnown = JSON.parse(
|
|
31
|
+
fs.readFileSync(path.join(_rServerRoot, 'data', 'known-projects.json'), 'utf8'),
|
|
32
|
+
);
|
|
33
|
+
_rKnown.forEach((p) => _rProjDirs.add(p));
|
|
34
|
+
} catch (_) {}
|
|
35
|
+
}
|
|
36
|
+
const _rSeenFiles = new Set();
|
|
37
|
+
const runs = [];
|
|
38
|
+
const _parseRun = (filePath, f) => {
|
|
39
|
+
try {
|
|
40
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
41
|
+
const allLines = raw.split('\n').filter(Boolean);
|
|
42
|
+
const parse = (l) => {
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(l);
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
// Merge .warm.jsonl (promoted pre-complete events) for accurate event count + metadata
|
|
50
|
+
const warmFile = filePath.replace(/\.jsonl$/, '.warm.jsonl');
|
|
51
|
+
let warmLines = [];
|
|
52
|
+
let warmEvents = [];
|
|
53
|
+
try {
|
|
54
|
+
if (fs.existsSync(warmFile)) {
|
|
55
|
+
warmLines = fs.readFileSync(warmFile, 'utf8').split('\n').filter(Boolean);
|
|
56
|
+
warmEvents = warmLines.map(parse).filter(Boolean);
|
|
57
|
+
}
|
|
58
|
+
} catch (_) {}
|
|
59
|
+
const combinedLines = [...warmLines, ...allLines];
|
|
60
|
+
const eventCount = combinedLines.length;
|
|
61
|
+
const headEvents = (
|
|
62
|
+
warmEvents.length ? warmEvents : allLines.map(parse).filter(Boolean)
|
|
63
|
+
).slice(0, 10);
|
|
64
|
+
const _tailEvents = allLines.map(parse).filter(Boolean).slice(-5).length
|
|
65
|
+
? allLines.map(parse).filter(Boolean).slice(-5)
|
|
66
|
+
: warmEvents.slice(-5);
|
|
67
|
+
const first = headEvents.find((e) => e.type === 'run:start') || headEvents[0];
|
|
68
|
+
const last = [...warmEvents.slice(-5), ...allLines.map(parse).filter(Boolean).slice(-3)]
|
|
69
|
+
.slice()
|
|
70
|
+
.reverse()
|
|
71
|
+
.find((e) => e.type === 'run:complete' || e.type === 'org:complete');
|
|
72
|
+
const cycles = combinedLines.filter((l) => l.includes('"org:checkpoint"')).length;
|
|
73
|
+
const lastEvent =
|
|
74
|
+
allLines.map(parse).filter(Boolean).slice(-1)[0] || warmEvents.slice(-1)[0];
|
|
75
|
+
const ageMs = lastEvent?.ts ? Date.now() - lastEvent.ts : Infinity;
|
|
76
|
+
const isStale = !last && ageMs > 30 * 60 * 1000;
|
|
77
|
+
const firstBossComms = headEvents.find(
|
|
78
|
+
(e) => e.type === 'org:comms' && (e.from === 'boss' || e.role === 'boss') && e.msg,
|
|
79
|
+
);
|
|
80
|
+
const derivedGoal = first?.goal || firstBossComms?.msg?.slice(0, 80) || '';
|
|
81
|
+
return {
|
|
82
|
+
runId: f.replace(/\.warm\.jsonl$|\.jsonl$/, ''),
|
|
83
|
+
startedAt: first?.ts || 0,
|
|
84
|
+
endedAt: last?.ts || 0,
|
|
85
|
+
status: last ? 'complete' : isStale ? 'stale' : 'running',
|
|
86
|
+
eventCount,
|
|
87
|
+
cycleCount: cycles,
|
|
88
|
+
goal: derivedGoal,
|
|
89
|
+
bossRole: first?.bossRole || '',
|
|
90
|
+
};
|
|
91
|
+
} catch (_) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
// Org Runtime v2 (#238): each run's raw BusEvents live under a
|
|
96
|
+
// per-run directory named for the run itself — orgs/<org>/<runId>/bus.jsonl
|
|
97
|
+
// — never the flat orgs/<org>/runs/<runId>.jsonl layout _parseRun above
|
|
98
|
+
// expects. Translate through the same translate()/companionEvents()
|
|
99
|
+
// forwarder.ts uses for the live view, so historical and live event
|
|
100
|
+
// shapes always match.
|
|
101
|
+
const _parseV2RunDir = (orgDir, runId) => {
|
|
102
|
+
try {
|
|
103
|
+
const busFile = path.join(orgDir, runId, 'bus.jsonl');
|
|
104
|
+
if (!fs.existsSync(busFile)) return null;
|
|
105
|
+
const raw = fs
|
|
106
|
+
.readFileSync(busFile, 'utf8')
|
|
107
|
+
.split('\n')
|
|
108
|
+
.filter(Boolean)
|
|
109
|
+
.map((l) => {
|
|
110
|
+
try {
|
|
111
|
+
return JSON.parse(l);
|
|
112
|
+
} catch {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
.filter(Boolean);
|
|
117
|
+
if (!raw.length) return null;
|
|
118
|
+
const translated = raw.flatMap((e) => [...companionEvents(e), translate(e)]);
|
|
119
|
+
const done = translated.find(
|
|
120
|
+
(e) => e.type === 'session:complete' || e.type === 'org:complete',
|
|
121
|
+
);
|
|
122
|
+
const start = translated.find((e) => e.type === 'org:start');
|
|
123
|
+
const firstComms = translated.find((e) => e.type === 'org:comms' && e.msg);
|
|
124
|
+
return {
|
|
125
|
+
runId,
|
|
126
|
+
startedAt: raw[0]?.ts || 0,
|
|
127
|
+
endedAt: done?.ts || 0,
|
|
128
|
+
status: done ? 'complete' : 'running',
|
|
129
|
+
eventCount: raw.length,
|
|
130
|
+
cycleCount: translated.filter((e) => e.type === 'org:checkpoint').length,
|
|
131
|
+
goal: start?.goal || firstComms?.msg?.slice(0, 80) || '',
|
|
132
|
+
bossRole: '',
|
|
133
|
+
};
|
|
134
|
+
} catch (_) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
for (const _rpd of _rProjDirs) {
|
|
139
|
+
// Check both .monomind and .git/monomind locations
|
|
140
|
+
const _rMonoDir = ctx._getGitMonomindDir(_rpd) || path.join(_rpd, '.monomind');
|
|
141
|
+
const _rOrgDirs = [path.join(_rMonoDir, 'orgs', _rOrgName)];
|
|
142
|
+
if (_rMonoDir !== path.join(_rpd, '.monomind'))
|
|
143
|
+
_rOrgDirs.push(path.join(_rpd, '.monomind', 'orgs', _rOrgName));
|
|
144
|
+
for (const _rOrgDir of _rOrgDirs) {
|
|
145
|
+
if (!fs.existsSync(_rOrgDir)) continue;
|
|
146
|
+
const runDirs = fs
|
|
147
|
+
.readdirSync(_rOrgDir)
|
|
148
|
+
.filter(
|
|
149
|
+
(d) => d.startsWith('run-') && fs.statSync(path.join(_rOrgDir, d)).isDirectory(),
|
|
150
|
+
)
|
|
151
|
+
.sort()
|
|
152
|
+
.reverse();
|
|
153
|
+
for (const runId of runDirs.slice(0, 50)) {
|
|
154
|
+
if (_rSeenFiles.has(runId)) continue;
|
|
155
|
+
const r = _parseV2RunDir(_rOrgDir, runId);
|
|
156
|
+
if (!r) continue;
|
|
157
|
+
_rSeenFiles.add(runId);
|
|
158
|
+
runs.push(r);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const _rSearchDirs = [path.join(_rMonoDir, 'orgs', _rOrgName, 'runs')];
|
|
162
|
+
if (_rMonoDir !== path.join(_rpd, '.monomind'))
|
|
163
|
+
_rSearchDirs.push(path.join(_rpd, '.monomind', 'orgs', _rOrgName, 'runs'));
|
|
164
|
+
for (const _rDir of _rSearchDirs) {
|
|
165
|
+
if (!fs.existsSync(_rDir)) continue;
|
|
166
|
+
// Include .warm.jsonl — completed runs are renamed hot→warm on org:complete and
|
|
167
|
+
// must stay visible in the chat history dropdown.
|
|
168
|
+
const files = fs
|
|
169
|
+
.readdirSync(_rDir)
|
|
170
|
+
.filter(
|
|
171
|
+
(f) =>
|
|
172
|
+
f.endsWith('.jsonl') &&
|
|
173
|
+
!f.startsWith('._') &&
|
|
174
|
+
!f.endsWith('.convs.jsonl') &&
|
|
175
|
+
!f.endsWith('.cold.jsonl'),
|
|
176
|
+
)
|
|
177
|
+
.sort()
|
|
178
|
+
.reverse();
|
|
179
|
+
for (const f of files.slice(0, 50)) {
|
|
180
|
+
const _rFileId = f.replace(/\.warm\.jsonl$|\.jsonl$/, '');
|
|
181
|
+
if (_rSeenFiles.has(_rFileId)) continue;
|
|
182
|
+
_rSeenFiles.add(_rFileId);
|
|
183
|
+
const r = _parseRun(path.join(_rDir, f), f);
|
|
184
|
+
if (r) runs.push(r);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
runs.sort((a, b) => (b.startedAt || 0) - (a.startedAt || 0));
|
|
189
|
+
// Threads fallback: if no run files found, synthesize a run from the org threads file
|
|
190
|
+
// so orgs whose boss never emitted runId-tagged events still show in the chat dropdown.
|
|
191
|
+
if (runs.length === 0) {
|
|
192
|
+
for (const _rpd of _rProjDirs) {
|
|
193
|
+
const _tf = path.join(_rpd, '.monomind', 'orgs', `${_rOrgName}-threads.jsonl`);
|
|
194
|
+
if (!fs.existsSync(_tf)) continue;
|
|
195
|
+
const _tLines = fs.readFileSync(_tf, 'utf8').split('\n').filter(Boolean);
|
|
196
|
+
if (!_tLines.length) continue;
|
|
197
|
+
const _tEvs = _tLines
|
|
198
|
+
.map((l) => {
|
|
199
|
+
try {
|
|
200
|
+
return JSON.parse(l);
|
|
201
|
+
} catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
.filter(Boolean);
|
|
206
|
+
if (!_tEvs.length) continue;
|
|
207
|
+
const _firstTs = _tEvs[0].ts
|
|
208
|
+
? typeof _tEvs[0].ts === 'number'
|
|
209
|
+
? _tEvs[0].ts
|
|
210
|
+
: new Date(_tEvs[0].ts).getTime()
|
|
211
|
+
: Date.now();
|
|
212
|
+
const _lastTs = _tEvs[_tEvs.length - 1].ts
|
|
213
|
+
? typeof _tEvs[_tEvs.length - 1].ts === 'number'
|
|
214
|
+
? _tEvs[_tEvs.length - 1].ts
|
|
215
|
+
: new Date(_tEvs[_tEvs.length - 1].ts).getTime()
|
|
216
|
+
: _firstTs;
|
|
217
|
+
runs.push({
|
|
218
|
+
id: `threads-${_rOrgName}`,
|
|
219
|
+
orgName: _rOrgName,
|
|
220
|
+
goal: `${_rOrgName} threads`,
|
|
221
|
+
status: 'complete',
|
|
222
|
+
startedAt: _firstTs,
|
|
223
|
+
endedAt: _lastTs,
|
|
224
|
+
eventCount: _tEvs.length,
|
|
225
|
+
_threadsFile: _tf,
|
|
226
|
+
});
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
res.writeHead(200, {
|
|
231
|
+
'Content-Type': 'application/json',
|
|
232
|
+
...(corsOrigin ? { 'Access-Control-Allow-Origin': corsOrigin } : {}),
|
|
233
|
+
'Cache-Control': 'no-cache',
|
|
234
|
+
});
|
|
235
|
+
res.end(JSON.stringify(runs));
|
|
236
|
+
} catch (_) {
|
|
237
|
+
res.writeHead(500);
|
|
238
|
+
res.end('[]');
|
|
239
|
+
}
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// GET /api/org/:name/runs/:runId — get all events for a specific run
|
|
244
|
+
if (
|
|
245
|
+
req.method === 'GET' &&
|
|
246
|
+
/^\/api\/org\/[a-z0-9][a-z0-9_-]{0,63}\/runs\/[a-z0-9][a-z0-9_-]{0,79}(\?.*)?$/i.test(url)
|
|
247
|
+
) {
|
|
248
|
+
try {
|
|
249
|
+
const _rvQs = new URL(req.url, 'http://localhost').searchParams;
|
|
250
|
+
const _rvParts = url.replace(/\?.*$/, '').split('/');
|
|
251
|
+
const _rvOrgName = decodeURIComponent(_rvParts[3] || '');
|
|
252
|
+
const _rvRunId = decodeURIComponent(_rvParts[5] || '');
|
|
253
|
+
if (
|
|
254
|
+
_rvOrgName.length > 64 ||
|
|
255
|
+
!/^[a-z0-9][a-z0-9_-]*$/i.test(_rvOrgName) ||
|
|
256
|
+
_rvRunId.length > 80 ||
|
|
257
|
+
!/^[a-z0-9][a-z0-9_-]*$/i.test(_rvRunId)
|
|
258
|
+
) {
|
|
259
|
+
res.writeHead(400);
|
|
260
|
+
res.end('{"error":"Invalid org or run id"}');
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
const _rvExplicitDir = _rvQs.get('dir');
|
|
264
|
+
const _rvServerRoot = path.resolve(_rvExplicitDir || ctx.projectDir || process.cwd());
|
|
265
|
+
// Threads fallback: threads-${orgName} is a synthetic runId served from threads file
|
|
266
|
+
if (_rvRunId === `threads-${_rvOrgName}`) {
|
|
267
|
+
const _rvProjDirsT = new Set([_rvServerRoot]);
|
|
268
|
+
if (!_rvExplicitDir) {
|
|
269
|
+
try {
|
|
270
|
+
JSON.parse(
|
|
271
|
+
fs.readFileSync(path.join(_rvServerRoot, 'data', 'known-projects.json'), 'utf8'),
|
|
272
|
+
).forEach((p) => _rvProjDirsT.add(p));
|
|
273
|
+
} catch (_) {}
|
|
274
|
+
}
|
|
275
|
+
for (const _rvpd of _rvProjDirsT) {
|
|
276
|
+
const _tf = path.join(_rvpd, '.monomind', 'orgs', `${_rvOrgName}-threads.jsonl`);
|
|
277
|
+
if (!fs.existsSync(_tf)) continue;
|
|
278
|
+
const _tLines = fs.readFileSync(_tf, 'utf8').split('\n').filter(Boolean);
|
|
279
|
+
const _tEvs = _tLines
|
|
280
|
+
.map((l) => {
|
|
281
|
+
try {
|
|
282
|
+
const e = JSON.parse(l);
|
|
283
|
+
return {
|
|
284
|
+
type: 'org:comms',
|
|
285
|
+
from: e.role || e.from || 'agent',
|
|
286
|
+
to: e.to || 'all',
|
|
287
|
+
msg: e.message || e.msg || '',
|
|
288
|
+
ts: e.ts
|
|
289
|
+
? typeof e.ts === 'number'
|
|
290
|
+
? e.ts
|
|
291
|
+
: new Date(e.ts).getTime()
|
|
292
|
+
: Date.now(),
|
|
293
|
+
org: _rvOrgName,
|
|
294
|
+
runId: _rvRunId,
|
|
295
|
+
};
|
|
296
|
+
} catch {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
})
|
|
300
|
+
.filter(Boolean);
|
|
301
|
+
res.writeHead(200, {
|
|
302
|
+
'Content-Type': 'application/json',
|
|
303
|
+
...(corsOrigin ? { 'Access-Control-Allow-Origin': corsOrigin } : {}),
|
|
304
|
+
});
|
|
305
|
+
res.end(JSON.stringify(_tEvs));
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
res.writeHead(404);
|
|
309
|
+
res.end('{"error":"threads file not found"}');
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
// Search across known projects
|
|
313
|
+
const _rvProjDirs = new Set([_rvServerRoot]);
|
|
314
|
+
if (!_rvExplicitDir) {
|
|
315
|
+
try {
|
|
316
|
+
JSON.parse(
|
|
317
|
+
fs.readFileSync(path.join(_rvServerRoot, 'data', 'known-projects.json'), 'utf8'),
|
|
318
|
+
).forEach((p) => _rvProjDirs.add(p));
|
|
319
|
+
} catch (_) {}
|
|
320
|
+
}
|
|
321
|
+
// Org Runtime v2 (#238): try the per-run-directory bus.jsonl layout
|
|
322
|
+
// first — orgs/<org>/<runId>/bus.jsonl — translated to the same
|
|
323
|
+
// dashboard vocabulary the live view gets from forwarder.ts, before
|
|
324
|
+
// falling back to the v1 flat orgs/<org>/runs/<runId>.jsonl lookup
|
|
325
|
+
// below (v1 files are already stored pre-translated).
|
|
326
|
+
for (const _rvpd of _rvProjDirs) {
|
|
327
|
+
const _rvMonoDir = ctx._getGitMonomindDir(_rvpd) || path.join(_rvpd, '.monomind');
|
|
328
|
+
const _v2Candidates = [path.join(_rvMonoDir, 'orgs', _rvOrgName, _rvRunId, 'bus.jsonl')];
|
|
329
|
+
if (_rvMonoDir !== path.join(_rvpd, '.monomind'))
|
|
330
|
+
_v2Candidates.push(
|
|
331
|
+
path.join(_rvpd, '.monomind', 'orgs', _rvOrgName, _rvRunId, 'bus.jsonl'),
|
|
332
|
+
);
|
|
333
|
+
for (const _v2File of _v2Candidates) {
|
|
334
|
+
if (!fs.existsSync(_v2File)) continue;
|
|
335
|
+
const raw = fs
|
|
336
|
+
.readFileSync(_v2File, 'utf8')
|
|
337
|
+
.split('\n')
|
|
338
|
+
.filter(Boolean)
|
|
339
|
+
.map((l) => {
|
|
340
|
+
try {
|
|
341
|
+
return JSON.parse(l);
|
|
342
|
+
} catch {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
.filter(Boolean);
|
|
347
|
+
const events = raw.flatMap((e) => [...companionEvents(e), translate(e)]);
|
|
348
|
+
events.sort((a, b) => (a.ts || 0) - (b.ts || 0));
|
|
349
|
+
res.writeHead(200, {
|
|
350
|
+
'Content-Type': 'application/json',
|
|
351
|
+
...(corsOrigin ? { 'Access-Control-Allow-Origin': corsOrigin } : {}),
|
|
352
|
+
'Cache-Control': 'no-cache',
|
|
353
|
+
});
|
|
354
|
+
res.end(JSON.stringify(events));
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
let _rvFile = null;
|
|
359
|
+
for (const _rvpd of _rvProjDirs) {
|
|
360
|
+
const _rvMonoDir = ctx._getGitMonomindDir(_rvpd) || path.join(_rvpd, '.monomind');
|
|
361
|
+
const _candidates = [
|
|
362
|
+
path.join(_rvMonoDir, 'orgs', _rvOrgName, 'runs', `${_rvRunId}.jsonl`),
|
|
363
|
+
path.join(_rvMonoDir, 'orgs', _rvOrgName, 'runs', `${_rvRunId}.warm.jsonl`),
|
|
364
|
+
];
|
|
365
|
+
if (_rvMonoDir !== path.join(_rvpd, '.monomind')) {
|
|
366
|
+
_candidates.push(
|
|
367
|
+
path.join(_rvpd, '.monomind', 'orgs', _rvOrgName, 'runs', `${_rvRunId}.jsonl`),
|
|
368
|
+
);
|
|
369
|
+
_candidates.push(
|
|
370
|
+
path.join(_rvpd, '.monomind', 'orgs', _rvOrgName, 'runs', `${_rvRunId}.warm.jsonl`),
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
for (const c of _candidates) {
|
|
374
|
+
if (fs.existsSync(c)) {
|
|
375
|
+
_rvFile = c;
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
if (_rvFile) break;
|
|
380
|
+
}
|
|
381
|
+
if (!_rvFile) {
|
|
382
|
+
res.writeHead(404);
|
|
383
|
+
res.end('{"error":"run not found"}');
|
|
384
|
+
return true;
|
|
385
|
+
}
|
|
386
|
+
const _parseLines = (p) => {
|
|
387
|
+
try {
|
|
388
|
+
return fs
|
|
389
|
+
.readFileSync(p, 'utf8')
|
|
390
|
+
.split('\n')
|
|
391
|
+
.filter(Boolean)
|
|
392
|
+
.map((l) => {
|
|
393
|
+
try {
|
|
394
|
+
return JSON.parse(l);
|
|
395
|
+
} catch {
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
})
|
|
399
|
+
.filter(Boolean);
|
|
400
|
+
} catch {
|
|
401
|
+
return [];
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
const events = _parseLines(_rvFile);
|
|
405
|
+
// Merge .warm.jsonl (pre-run:complete events, including org:comms) if it exists.
|
|
406
|
+
// When run:complete fires, the hot .jsonl is renamed to .warm.jsonl so all pre-complete
|
|
407
|
+
// events live there. The current .jsonl then only holds post-complete events (e.g. org:stop).
|
|
408
|
+
const _rvWarmFile = _rvFile.endsWith('.warm.jsonl')
|
|
409
|
+
? _rvFile
|
|
410
|
+
: _rvFile.replace(/\.jsonl$/, '.warm.jsonl');
|
|
411
|
+
if (_rvWarmFile !== _rvFile && fs.existsSync(_rvWarmFile)) {
|
|
412
|
+
events.push(..._parseLines(_rvWarmFile));
|
|
413
|
+
}
|
|
414
|
+
// For in-progress runs (no .warm.jsonl), org:comms also go to .convs.jsonl (stripped form).
|
|
415
|
+
// They're already in .jsonl as full events, so .convs.jsonl would duplicate — skip it.
|
|
416
|
+
events.sort((a, b) => (a.ts || 0) - (b.ts || 0));
|
|
417
|
+
res.writeHead(200, {
|
|
418
|
+
'Content-Type': 'application/json',
|
|
419
|
+
...(corsOrigin ? { 'Access-Control-Allow-Origin': corsOrigin } : {}),
|
|
420
|
+
'Cache-Control': 'no-cache',
|
|
421
|
+
});
|
|
422
|
+
res.end(JSON.stringify(events));
|
|
423
|
+
} catch (_) {
|
|
424
|
+
res.writeHead(500);
|
|
425
|
+
res.end('[]');
|
|
426
|
+
}
|
|
427
|
+
return true;
|
|
428
|
+
}
|
|
429
|
+
return false;
|
|
430
|
+
}
|