agenthub-multiagent-mcp 1.14.1 → 1.15.1

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 (84) hide show
  1. package/dist/brain/journal.d.ts +77 -0
  2. package/dist/brain/journal.d.ts.map +1 -0
  3. package/dist/brain/journal.js +276 -0
  4. package/dist/brain/journal.js.map +1 -0
  5. package/dist/brain/journal.test.d.ts +5 -0
  6. package/dist/brain/journal.test.d.ts.map +1 -0
  7. package/dist/brain/journal.test.js +151 -0
  8. package/dist/brain/journal.test.js.map +1 -0
  9. package/dist/hooks/brainCapture.d.ts +29 -2
  10. package/dist/hooks/brainCapture.d.ts.map +1 -1
  11. package/dist/hooks/brainCapture.js +89 -7
  12. package/dist/hooks/brainCapture.js.map +1 -1
  13. package/dist/index.js +71 -6
  14. package/dist/index.js.map +1 -1
  15. package/dist/setup.js +65 -0
  16. package/dist/setup.js.map +1 -1
  17. package/dist/skillInstaller.d.ts +22 -0
  18. package/dist/skillInstaller.d.ts.map +1 -0
  19. package/dist/skillInstaller.js +163 -0
  20. package/dist/skillInstaller.js.map +1 -0
  21. package/dist/skillInstaller.test.d.ts +2 -0
  22. package/dist/skillInstaller.test.d.ts.map +1 -0
  23. package/dist/skillInstaller.test.js +121 -0
  24. package/dist/skillInstaller.test.js.map +1 -0
  25. package/package.json +5 -1
  26. package/skills/commands/start-session.md +52 -0
  27. package/skills/manifest.json +15 -0
  28. package/skills/skills/close-session.md +105 -0
  29. package/.agenthub/hook-agent-id +0 -1
  30. package/.agenthub/state +0 -1
  31. package/CHANGELOG.md +0 -23
  32. package/openspec_viz.md +0 -260
  33. package/run-claude.sh +0 -38
  34. package/scripts/memvid-smoke.ts +0 -89
  35. package/scripts/memvidBrain-smoke.ts +0 -83
  36. package/scripts/migrate-smoke.ts +0 -134
  37. package/session-capture.sh +0 -209
  38. package/src/activity.ts +0 -192
  39. package/src/brain/backend.ts +0 -37
  40. package/src/brain/jsonlBrain.ts +0 -62
  41. package/src/brain/localBrain.ts +0 -222
  42. package/src/brain/memvidBrain.test.ts +0 -136
  43. package/src/brain/memvidBrain.ts +0 -285
  44. package/src/brain/migrate.test.ts +0 -164
  45. package/src/brain/migrate.ts +0 -213
  46. package/src/brain/types.ts +0 -45
  47. package/src/channel.ts +0 -265
  48. package/src/client.test.ts +0 -223
  49. package/src/client.ts +0 -1164
  50. package/src/client.unit.test.ts +0 -103
  51. package/src/commands/resume.test.ts +0 -127
  52. package/src/commands/resume.ts +0 -205
  53. package/src/commands/setup-shell.test.ts +0 -185
  54. package/src/commands/setup-shell.ts +0 -200
  55. package/src/context.ts +0 -897
  56. package/src/daemon.ts +0 -399
  57. package/src/e2e.test.ts +0 -300
  58. package/src/heartbeat.ts +0 -195
  59. package/src/hooks/brainCapture.ts +0 -206
  60. package/src/hooks/index.ts +0 -184
  61. package/src/hooks/onConnect.ts +0 -115
  62. package/src/hooks/onDisconnect.ts +0 -138
  63. package/src/hooks/onTaskComplete.ts +0 -134
  64. package/src/hooks/onTaskStart.ts +0 -101
  65. package/src/hooks/periodicReminder.ts +0 -116
  66. package/src/hooks/sessionState.ts +0 -219
  67. package/src/hooks/types.ts +0 -95
  68. package/src/index.ts +0 -367
  69. package/src/planHookCli.ts +0 -178
  70. package/src/setup.ts +0 -476
  71. package/src/state.ts +0 -216
  72. package/src/tools/index.ts +0 -3403
  73. package/src/tools/openspec-viz/diagram-generator.ts +0 -714
  74. package/src/tools/openspec-viz/html-generator.ts +0 -682
  75. package/src/tools/openspec-viz/index.ts +0 -266
  76. package/src/tools/openspec-viz/parser.ts +0 -1156
  77. package/src/tools/openspec-viz/types.ts +0 -162
  78. package/src/tools/tools.test.ts +0 -664
  79. package/src/version.ts +0 -35
  80. package/src/websocket.ts +0 -293
  81. package/src/worker.ts +0 -781
  82. package/tmpclaude-6a14-cwd +0 -1
  83. package/tsconfig.json +0 -20
  84. package/vitest.config.ts +0 -8
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Session Journal — crash-safe, fire-and-forget event log for real-time
3
+ * session durability without polluting the sealed `.mv2` brain.
4
+ *
5
+ * Location: `~/.claude/brains/journal/<sanitized-agent-id>.jsonl`
6
+ *
7
+ * Design goals:
8
+ * 1. **Zero LLM token cost** — filesystem-only, no network per event.
9
+ * 2. **Zero measurable perf impact** — async `appendFile`, fire-and-forget,
10
+ * never awaited by the hot path. ~50–200μs per write on SSDs.
11
+ * 3. **Bounded power-cut loss** — no explicit fsync (fsync would add 2–10ms
12
+ * per event). Worst-case loss is OS write-buffer depth, typically <5s on
13
+ * Windows NTFS. Accept that; `.mv2` summary at session close is the
14
+ * durable record.
15
+ * 4. **Clean `.mv2`** — journals are summarized into a single `.mv2` frame
16
+ * on session end. `.mv2` BM25 search quality stays high.
17
+ * 5. **Recoverable** — if Claude Code crashes or power dies mid-session, the
18
+ * JSONL survives (up to the OS flush boundary). On next startup we
19
+ * summarize it into `.mv2` and archive.
20
+ *
21
+ * Event schema:
22
+ * { "t": "2026-04-23T...", "e": "tool", "n": "save_decision",
23
+ * "s": "ok", "p": { ...truncated args... } }
24
+ */
25
+ export interface JournalEvent {
26
+ t: string;
27
+ e: "tool" | "session_start" | "session_end" | "error";
28
+ n?: string;
29
+ s?: "ok" | "err";
30
+ p?: unknown;
31
+ }
32
+ export declare function getJournalPath(agentId: string): string;
33
+ /**
34
+ * Is this tool call worth journaling? Keep the allowlist in sync with the
35
+ * set of tools that represent real work worth recovering on crash.
36
+ */
37
+ export declare function shouldJournal(toolName: string): boolean;
38
+ /**
39
+ * Fire-and-forget append. Never throws, never awaits on the hot path.
40
+ * Returns void synchronously; I/O runs on the event-loop tail, serialized
41
+ * per-path to avoid Windows file-sharing violations.
42
+ */
43
+ export declare function logEvent(agentId: string, event: JournalEvent): void;
44
+ /**
45
+ * Test helper: await all pending writes for an agent. Not used in production.
46
+ * Exported so unit tests can assert against fully-flushed state without polling.
47
+ */
48
+ export declare function flushPending(agentId: string): Promise<void>;
49
+ /**
50
+ * Test helper: reset internal state. Not used in production.
51
+ */
52
+ export declare function _resetForTest(): void;
53
+ /** Convenience: log a tool call event. */
54
+ export declare function logTool(agentId: string, toolName: string, args: unknown, ok: boolean): void;
55
+ /** Returns true if a journal file exists for this agent. */
56
+ export declare function hasJournal(agentId: string): Promise<boolean>;
57
+ /** Read all events from the journal. Returns [] if missing/corrupt. */
58
+ export declare function readEvents(agentId: string): Promise<JournalEvent[]>;
59
+ /**
60
+ * Rename the journal to an archived path so a fresh session starts clean.
61
+ * Returns the archive path, or null if no journal existed.
62
+ */
63
+ export declare function archive(agentId: string): Promise<string | null>;
64
+ /**
65
+ * List agents that have an active (non-archived) journal file. Used on
66
+ * startup to recover journals from crashed prior sessions.
67
+ */
68
+ export declare function listAgentsWithJournal(): string[];
69
+ /**
70
+ * Summarize a list of journal events into a single text block suitable for
71
+ * a `.mv2` frame body. Deterministic ordering, compact format.
72
+ */
73
+ export declare function summarizeEvents(events: JournalEvent[]): {
74
+ summary: string;
75
+ content: string;
76
+ };
77
+ //# sourceMappingURL=journal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../../src/brain/journal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA6CH,MAAM,WAAW,YAAY;IAC3B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,aAAa,GAAG,OAAO,CAAC;IACtD,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,IAAI,GAAG,KAAK,CAAC;IACjB,CAAC,CAAC,EAAE,OAAO,CAAC;CACb;AAUD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEtD;AAsBD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEvD;AAWD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAkBnE;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIjE;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAGpC;AAED,0CAA0C;AAC1C,wBAAgB,OAAO,CACrB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,EAAE,EAAE,OAAO,GACV,IAAI,CASN;AAED,4DAA4D;AAC5D,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOlE;AAED,uEAAuE;AACvE,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAmBzE;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBrE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAUhD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CA+BA"}
@@ -0,0 +1,276 @@
1
+ /**
2
+ * Session Journal — crash-safe, fire-and-forget event log for real-time
3
+ * session durability without polluting the sealed `.mv2` brain.
4
+ *
5
+ * Location: `~/.claude/brains/journal/<sanitized-agent-id>.jsonl`
6
+ *
7
+ * Design goals:
8
+ * 1. **Zero LLM token cost** — filesystem-only, no network per event.
9
+ * 2. **Zero measurable perf impact** — async `appendFile`, fire-and-forget,
10
+ * never awaited by the hot path. ~50–200μs per write on SSDs.
11
+ * 3. **Bounded power-cut loss** — no explicit fsync (fsync would add 2–10ms
12
+ * per event). Worst-case loss is OS write-buffer depth, typically <5s on
13
+ * Windows NTFS. Accept that; `.mv2` summary at session close is the
14
+ * durable record.
15
+ * 4. **Clean `.mv2`** — journals are summarized into a single `.mv2` frame
16
+ * on session end. `.mv2` BM25 search quality stays high.
17
+ * 5. **Recoverable** — if Claude Code crashes or power dies mid-session, the
18
+ * JSONL survives (up to the OS flush boundary). On next startup we
19
+ * summarize it into `.mv2` and archive.
20
+ *
21
+ * Event schema:
22
+ * { "t": "2026-04-23T...", "e": "tool", "n": "save_decision",
23
+ * "s": "ok", "p": { ...truncated args... } }
24
+ */
25
+ import { appendFile, mkdir, readFile, rename, stat, unlink } from "fs/promises";
26
+ import { existsSync, readdirSync } from "fs";
27
+ import { join } from "path";
28
+ import { homedir } from "os";
29
+ const JOURNAL_DIR_NAME = "journal";
30
+ const MAX_PAYLOAD_CHARS = 500;
31
+ /**
32
+ * Tools worth journaling. Everything else (heartbeats, reads, list/get,
33
+ * searches) is pure noise and is skipped to keep journals tight.
34
+ */
35
+ const JOURNALED_TOOLS = new Set([
36
+ "save_decision",
37
+ "save_note",
38
+ "save_codebase_insight",
39
+ "save_blocker",
40
+ "clear_blocker",
41
+ "agent_start_work",
42
+ "agent_complete_task",
43
+ "agent_report_blocked",
44
+ "agent_report_failure",
45
+ "accept_task",
46
+ "decline_task",
47
+ "claim_ticket_task",
48
+ "create_task",
49
+ "update_ticket",
50
+ "add_comment",
51
+ "submit_plan",
52
+ "submit_code_review",
53
+ "reach_checkpoint",
54
+ "send_message",
55
+ "broadcast",
56
+ "send_to_channel",
57
+ "reply",
58
+ "brain_write_knowledge",
59
+ "openspec_publish",
60
+ "create_epic",
61
+ "create_story",
62
+ "sync_context",
63
+ "session_close_report",
64
+ ]);
65
+ function sanitizeAgentId(agentId) {
66
+ return agentId.replace(/[^a-zA-Z0-9_-]/g, "_");
67
+ }
68
+ function getJournalDir() {
69
+ return join(homedir(), ".claude", "brains", JOURNAL_DIR_NAME);
70
+ }
71
+ export function getJournalPath(agentId) {
72
+ return join(getJournalDir(), `${sanitizeAgentId(agentId)}.jsonl`);
73
+ }
74
+ async function ensureJournalDir() {
75
+ await mkdir(getJournalDir(), { recursive: true });
76
+ }
77
+ /**
78
+ * Truncate an arbitrary JS value to a compact JSON-safe payload.
79
+ * Keeps the journal bounded per event — an accidental 10MB `content` field
80
+ * won't balloon the file.
81
+ */
82
+ function truncatePayload(payload) {
83
+ if (payload === undefined || payload === null)
84
+ return payload;
85
+ try {
86
+ const json = JSON.stringify(payload);
87
+ if (json.length <= MAX_PAYLOAD_CHARS)
88
+ return payload;
89
+ return { _truncated: true, preview: json.slice(0, MAX_PAYLOAD_CHARS) };
90
+ }
91
+ catch {
92
+ return { _truncated: true, preview: String(payload).slice(0, MAX_PAYLOAD_CHARS) };
93
+ }
94
+ }
95
+ /**
96
+ * Is this tool call worth journaling? Keep the allowlist in sync with the
97
+ * set of tools that represent real work worth recovering on crash.
98
+ */
99
+ export function shouldJournal(toolName) {
100
+ return JOURNALED_TOOLS.has(toolName);
101
+ }
102
+ /**
103
+ * Per-path serialized write queue. Multiple concurrent appendFile calls against
104
+ * the same path on Windows can trip EBUSY / ERROR_SHARING_VIOLATION because
105
+ * each call opens its own handle. Chaining via a per-path promise serializes
106
+ * writes without blocking the caller — the caller still returns synchronously.
107
+ */
108
+ const writeQueues = new Map();
109
+ let dirEnsured = false;
110
+ /**
111
+ * Fire-and-forget append. Never throws, never awaits on the hot path.
112
+ * Returns void synchronously; I/O runs on the event-loop tail, serialized
113
+ * per-path to avoid Windows file-sharing violations.
114
+ */
115
+ export function logEvent(agentId, event) {
116
+ if (!agentId)
117
+ return;
118
+ const path = getJournalPath(agentId);
119
+ const line = JSON.stringify(event) + "\n";
120
+ const prev = writeQueues.get(path) ?? Promise.resolve();
121
+ const next = prev
122
+ .then(async () => {
123
+ if (!dirEnsured) {
124
+ await ensureJournalDir();
125
+ dirEnsured = true;
126
+ }
127
+ await appendFile(path, line, { encoding: "utf8" });
128
+ })
129
+ .catch(() => {
130
+ // Best-effort. Journal is a crash-safety net, not a correctness dependency.
131
+ });
132
+ writeQueues.set(path, next);
133
+ }
134
+ /**
135
+ * Test helper: await all pending writes for an agent. Not used in production.
136
+ * Exported so unit tests can assert against fully-flushed state without polling.
137
+ */
138
+ export async function flushPending(agentId) {
139
+ const path = getJournalPath(agentId);
140
+ const pending = writeQueues.get(path);
141
+ if (pending)
142
+ await pending;
143
+ }
144
+ /**
145
+ * Test helper: reset internal state. Not used in production.
146
+ */
147
+ export function _resetForTest() {
148
+ writeQueues.clear();
149
+ dirEnsured = false;
150
+ }
151
+ /** Convenience: log a tool call event. */
152
+ export function logTool(agentId, toolName, args, ok) {
153
+ if (!shouldJournal(toolName))
154
+ return;
155
+ logEvent(agentId, {
156
+ t: new Date().toISOString(),
157
+ e: "tool",
158
+ n: toolName,
159
+ s: ok ? "ok" : "err",
160
+ p: truncatePayload(args),
161
+ });
162
+ }
163
+ /** Returns true if a journal file exists for this agent. */
164
+ export async function hasJournal(agentId) {
165
+ try {
166
+ await stat(getJournalPath(agentId));
167
+ return true;
168
+ }
169
+ catch {
170
+ return false;
171
+ }
172
+ }
173
+ /** Read all events from the journal. Returns [] if missing/corrupt. */
174
+ export async function readEvents(agentId) {
175
+ const path = getJournalPath(agentId);
176
+ let raw;
177
+ try {
178
+ raw = await readFile(path, "utf8");
179
+ }
180
+ catch {
181
+ return [];
182
+ }
183
+ const events = [];
184
+ for (const line of raw.split("\n")) {
185
+ const trimmed = line.trim();
186
+ if (!trimmed)
187
+ continue;
188
+ try {
189
+ events.push(JSON.parse(trimmed));
190
+ }
191
+ catch {
192
+ // Skip malformed lines (e.g. a torn write at the tail from a power cut).
193
+ }
194
+ }
195
+ return events;
196
+ }
197
+ /**
198
+ * Rename the journal to an archived path so a fresh session starts clean.
199
+ * Returns the archive path, or null if no journal existed.
200
+ */
201
+ export async function archive(agentId) {
202
+ const path = getJournalPath(agentId);
203
+ if (!existsSync(path))
204
+ return null;
205
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
206
+ const dest = `${path}.archived.${stamp}`;
207
+ try {
208
+ await rename(path, dest);
209
+ return dest;
210
+ }
211
+ catch {
212
+ // If rename fails (e.g. locked on Windows), fall back to delete.
213
+ try {
214
+ await unlink(path);
215
+ }
216
+ catch {
217
+ // Swallow — worst case, next session re-summarizes the same content (idempotent enough).
218
+ }
219
+ return null;
220
+ }
221
+ }
222
+ /**
223
+ * List agents that have an active (non-archived) journal file. Used on
224
+ * startup to recover journals from crashed prior sessions.
225
+ */
226
+ export function listAgentsWithJournal() {
227
+ const dir = getJournalDir();
228
+ if (!existsSync(dir))
229
+ return [];
230
+ const result = [];
231
+ for (const file of readdirSync(dir)) {
232
+ if (!file.endsWith(".jsonl"))
233
+ continue;
234
+ if (file.includes(".archived."))
235
+ continue;
236
+ result.push(file.slice(0, -".jsonl".length));
237
+ }
238
+ return result;
239
+ }
240
+ /**
241
+ * Summarize a list of journal events into a single text block suitable for
242
+ * a `.mv2` frame body. Deterministic ordering, compact format.
243
+ */
244
+ export function summarizeEvents(events) {
245
+ if (events.length === 0) {
246
+ return { summary: "empty journal", content: "" };
247
+ }
248
+ const counts = new Map();
249
+ for (const ev of events) {
250
+ if (ev.e !== "tool" || !ev.n)
251
+ continue;
252
+ counts.set(ev.n, (counts.get(ev.n) ?? 0) + 1);
253
+ }
254
+ const topTools = [...counts.entries()]
255
+ .sort((a, b) => b[1] - a[1])
256
+ .slice(0, 5)
257
+ .map(([n, c]) => `${n}×${c}`)
258
+ .join(", ");
259
+ const first = events[0];
260
+ const last = events[events.length - 1];
261
+ const summary = `journal: ${events.length} events — ${topTools}`;
262
+ const content = [
263
+ `start=${first.t}`,
264
+ `end=${last.t}`,
265
+ `events=${events.length}`,
266
+ `tools=${topTools}`,
267
+ "",
268
+ ...events.map((ev) => {
269
+ const base = `${ev.t} ${ev.e}${ev.n ? " " + ev.n : ""}${ev.s ? " " + ev.s : ""}`;
270
+ const payload = ev.p !== undefined ? " " + JSON.stringify(ev.p) : "";
271
+ return base + payload;
272
+ }),
273
+ ].join("\n");
274
+ return { summary, content };
275
+ }
276
+ //# sourceMappingURL=journal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.js","sourceRoot":"","sources":["../../src/brain/journal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Unit tests for the crash-safe session journal.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=journal.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.test.d.ts","sourceRoot":"","sources":["../../src/brain/journal.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Unit tests for the crash-safe session journal.
3
+ */
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
+ import { mkdtempSync, rmSync, writeFileSync, existsSync, mkdirSync, readFileSync, readdirSync } from "fs";
6
+ import { tmpdir } from "os";
7
+ import { join } from "path";
8
+ let tempHome;
9
+ vi.mock("os", async () => {
10
+ const actual = await vi.importActual("os");
11
+ return {
12
+ ...actual,
13
+ homedir: () => process.env.__TEST_HOME__ ?? actual.homedir(),
14
+ };
15
+ });
16
+ async function importJournal() {
17
+ return await import("./journal.js");
18
+ }
19
+ describe("journal", () => {
20
+ beforeEach(async () => {
21
+ tempHome = mkdtempSync(join(tmpdir(), "journal-test-"));
22
+ process.env.__TEST_HOME__ = tempHome;
23
+ vi.resetModules();
24
+ const j = await importJournal();
25
+ j._resetForTest();
26
+ });
27
+ afterEach(() => {
28
+ rmSync(tempHome, { recursive: true, force: true });
29
+ delete process.env.__TEST_HOME__;
30
+ });
31
+ it("shouldJournal accepts allowlisted tools and rejects noise", async () => {
32
+ const j = await importJournal();
33
+ expect(j.shouldJournal("save_decision")).toBe(true);
34
+ expect(j.shouldJournal("agent_complete_task")).toBe(true);
35
+ expect(j.shouldJournal("heartbeat")).toBe(false);
36
+ expect(j.shouldJournal("check_inbox")).toBe(false);
37
+ expect(j.shouldJournal("list_agents")).toBe(false);
38
+ expect(j.shouldJournal("brain_search")).toBe(false);
39
+ });
40
+ it("logTool writes a JSONL line to the journal file", async () => {
41
+ const j = await importJournal();
42
+ j.logTool("agent-x", "save_decision", { what: "use bun", why: "speed" }, true);
43
+ // Fire-and-forget — give the event loop a tick to flush.
44
+ await j.flushPending("agent-x");
45
+ const path = j.getJournalPath("agent-x");
46
+ expect(existsSync(path)).toBe(true);
47
+ const raw = readFileSync(path, "utf8").trim();
48
+ const parsed = JSON.parse(raw);
49
+ expect(parsed.e).toBe("tool");
50
+ expect(parsed.n).toBe("save_decision");
51
+ expect(parsed.s).toBe("ok");
52
+ expect(parsed.p).toEqual({ what: "use bun", why: "speed" });
53
+ expect(typeof parsed.t).toBe("string");
54
+ });
55
+ it("logTool skips non-allowlisted tools silently", async () => {
56
+ const j = await importJournal();
57
+ j.logTool("agent-x", "heartbeat", {}, true);
58
+ await j.flushPending("agent-x");
59
+ expect(await j.hasJournal("agent-x")).toBe(false);
60
+ });
61
+ it("logTool truncates oversized payloads", async () => {
62
+ const j = await importJournal();
63
+ const huge = "x".repeat(5000);
64
+ j.logTool("agent-x", "save_note", { body: huge }, true);
65
+ await j.flushPending("agent-x");
66
+ const events = await j.readEvents("agent-x");
67
+ expect(events).toHaveLength(1);
68
+ const payload = events[0].p;
69
+ expect(payload._truncated).toBe(true);
70
+ expect(payload.preview.length).toBeLessThanOrEqual(500);
71
+ });
72
+ it("readEvents tolerates torn final line from a power-cut scenario", async () => {
73
+ const j = await importJournal();
74
+ const dir = join(tempHome, ".claude", "brains", "journal");
75
+ mkdirSync(dir, { recursive: true });
76
+ const path = j.getJournalPath("agent-x");
77
+ const good = JSON.stringify({ t: "2026-04-23T00:00:00Z", e: "tool", n: "save_decision", s: "ok" });
78
+ // Second line is truncated mid-JSON — simulates a power-cut append.
79
+ writeFileSync(path, good + "\n" + '{"t":"2026-04-23T00:00:01Z","e":"tool","n":"save_no', "utf8");
80
+ const events = await j.readEvents("agent-x");
81
+ expect(events).toHaveLength(1);
82
+ expect(events[0].n).toBe("save_decision");
83
+ });
84
+ it("archive renames the journal so the next session starts clean", async () => {
85
+ const j = await importJournal();
86
+ j.logTool("agent-x", "save_decision", { a: 1 }, true);
87
+ await j.flushPending("agent-x");
88
+ expect(await j.hasJournal("agent-x")).toBe(true);
89
+ const dest = await j.archive("agent-x");
90
+ expect(dest).not.toBeNull();
91
+ expect(existsSync(dest)).toBe(true);
92
+ expect(await j.hasJournal("agent-x")).toBe(false);
93
+ });
94
+ it("listAgentsWithJournal returns active journals and excludes archives", async () => {
95
+ const j = await importJournal();
96
+ j.logTool("agent-a", "save_decision", {}, true);
97
+ j.logTool("agent-b", "save_note", {}, true);
98
+ await j.flushPending("agent-a");
99
+ await j.flushPending("agent-b");
100
+ await j.archive("agent-b");
101
+ const active = j.listAgentsWithJournal();
102
+ expect(active).toContain("agent-a");
103
+ expect(active).not.toContain("agent-b");
104
+ });
105
+ it("summarizeEvents produces counts and deterministic content", async () => {
106
+ const j = await importJournal();
107
+ const events = [
108
+ { t: "2026-04-23T00:00:00Z", e: "tool", n: "save_decision", s: "ok" },
109
+ { t: "2026-04-23T00:00:01Z", e: "tool", n: "save_decision", s: "ok" },
110
+ { t: "2026-04-23T00:00:02Z", e: "tool", n: "save_note", s: "ok" },
111
+ ];
112
+ const { summary, content } = j.summarizeEvents(events);
113
+ expect(summary).toContain("3 events");
114
+ expect(summary).toContain("save_decision×2");
115
+ expect(summary).toContain("save_note×1");
116
+ expect(content).toContain("start=2026-04-23T00:00:00Z");
117
+ expect(content).toContain("end=2026-04-23T00:00:02Z");
118
+ expect(content).toContain("events=3");
119
+ });
120
+ it("summarizeEvents handles empty input without throwing", async () => {
121
+ const j = await importJournal();
122
+ const { summary, content } = j.summarizeEvents([]);
123
+ expect(summary).toBe("empty journal");
124
+ expect(content).toBe("");
125
+ });
126
+ it("serializes 5000 concurrent appends without dropping events (Windows sharing-violation regression)", async () => {
127
+ const j = await importJournal();
128
+ const N = 5000;
129
+ const start = Date.now();
130
+ for (let i = 0; i < N; i++) {
131
+ j.logTool("stress-agent", "save_decision", { i }, true);
132
+ }
133
+ const syncMs = Date.now() - start;
134
+ await j.flushPending("stress-agent");
135
+ const events = await j.readEvents("stress-agent");
136
+ expect(events).toHaveLength(N);
137
+ // Synchronous call cost must stay negligible. 5000 × <0.5ms = <2.5s.
138
+ expect(syncMs).toBeLessThan(2500);
139
+ }, 30_000);
140
+ it("sanitizes agent ids with unsafe characters in the filename", async () => {
141
+ const j = await importJournal();
142
+ j.logTool("agent/../../etc/passwd", "save_decision", {}, true);
143
+ await j.flushPending("agent/../../etc/passwd");
144
+ const dir = join(tempHome, ".claude", "brains", "journal");
145
+ const files = readdirSync(dir);
146
+ expect(files).toHaveLength(1);
147
+ expect(files[0]).not.toContain("/");
148
+ expect(files[0]).not.toContain("..");
149
+ });
150
+ });
151
+ //# sourceMappingURL=journal.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.test.js","sourceRoot":"","sources":["../../src/brain/journal.test.ts"],"names":[],"mappings":"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"}
@@ -30,10 +30,37 @@ interface BrainCaptureData {
30
30
  */
31
31
  export declare function captureOnTaskComplete(client: ApiClient, data: BrainCaptureData): Promise<void>;
32
32
  /**
33
- * Capture a brain session summary on disconnect.
34
- * Called from the agent_disconnect handler.
33
+ * Flush the current session to both the org brain (server-side `brain_sessions`
34
+ * row) and the local `.mv2` file. Does NOT delete the agent from the registry.
35
+ *
36
+ * Safe to call from process-exit signal handlers (SIGINT/SIGTERM) — the agent
37
+ * stays registered so the next Claude Code start can reconnect to the same
38
+ * agent_id. Idempotent; calling twice in quick succession produces two session
39
+ * rows but that's acceptable (cheap, no data loss).
40
+ */
41
+ export declare function flushSessionToBrain(client: ApiClient, agentId: string, project?: string): Promise<void>;
42
+ /**
43
+ * Capture a brain session summary on explicit agent_disconnect.
44
+ * Thin wrapper over flushSessionToBrain — the tool handler performs the
45
+ * actual registry delete separately.
35
46
  */
36
47
  export declare function captureOnDisconnect(client: ApiClient, agentId: string, project?: string): Promise<void>;
48
+ /**
49
+ * Recover journals left behind by crashed/power-cut sessions. For each orphaned
50
+ * journal file under `~/.claude/brains/journal/`, summarize the events into a
51
+ * single `.mv2` frame and archive the journal.
52
+ *
53
+ * Called on MCP server startup (before the new agent's session starts), so the
54
+ * prior session's work makes it into the searchable brain even if the previous
55
+ * process never got a chance to run its shutdown handler.
56
+ *
57
+ * Skips `excludeAgentId` (the currently-registering agent) when provided — its
58
+ * own journal will be summarized at session close, not at startup.
59
+ */
60
+ export declare function recoverOrphanedJournals(excludeAgentId?: string): Promise<{
61
+ recovered: number;
62
+ failed: number;
63
+ }>;
37
64
  /**
38
65
  * Extract decisions from the local context store.
39
66
  * Reads the decisions saved via save_decision tool during this session.
@@ -1 +1 @@
1
- {"version":3,"file":"brainCapture.d.ts","sourceRoot":"","sources":["../../src/hooks/brainCapture.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAI9C,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CA6Ff;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAoDf;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,GACd,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAUtC"}
1
+ {"version":3,"file":"brainCapture.d.ts","sourceRoot":"","sources":["../../src/hooks/brainCapture.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAK9C,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CA6Ff;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAyEf;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,uBAAuB,CAC3C,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA8BhD;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,GACd,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAUtC"}