@brainmcp/brainmcp 0.1.12 → 0.1.14

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 (108) hide show
  1. package/README.md +79 -5
  2. package/dist/agent-config.js +155 -24
  3. package/dist/commands/auth.d.ts +47 -0
  4. package/dist/commands/auth.js +392 -0
  5. package/dist/commands/auth.js.map +1 -0
  6. package/dist/commands/capture.d.ts +34 -0
  7. package/dist/commands/capture.js +349 -0
  8. package/dist/commands/capture.js.map +1 -0
  9. package/dist/commands/dispatch.d.ts +43 -0
  10. package/dist/commands/dispatch.js +287 -0
  11. package/dist/commands/dispatch.js.map +1 -0
  12. package/dist/commands/index.d.ts +4 -0
  13. package/dist/commands/index.js +198 -36
  14. package/dist/commands/index.js.map +1 -1
  15. package/dist/hooks/adapters.d.ts +14 -0
  16. package/dist/hooks/adapters.js +41 -0
  17. package/dist/hooks/adapters.js.map +1 -0
  18. package/dist/hooks/claude.d.ts +24 -0
  19. package/dist/hooks/claude.js +36 -0
  20. package/dist/hooks/claude.js.map +1 -0
  21. package/dist/hooks/codex.d.ts +18 -0
  22. package/dist/hooks/codex.js +36 -0
  23. package/dist/hooks/codex.js.map +1 -0
  24. package/dist/hooks/cursor.d.ts +22 -0
  25. package/dist/hooks/cursor.js +26 -0
  26. package/dist/hooks/cursor.js.map +1 -0
  27. package/dist/hooks/managed-hooks.d.ts +30 -0
  28. package/dist/hooks/managed-hooks.js +189 -0
  29. package/dist/hooks/managed-hooks.js.map +1 -0
  30. package/dist/hooks/vscode.d.ts +22 -0
  31. package/dist/hooks/vscode.js +27 -0
  32. package/dist/hooks/vscode.js.map +1 -0
  33. package/dist/index.js +7 -102
  34. package/dist/index.js.map +1 -1
  35. package/dist/lib/api-client.d.ts +32 -0
  36. package/dist/lib/api-client.js +207 -0
  37. package/dist/lib/api-client.js.map +1 -0
  38. package/dist/lib/callback-server.d.ts +17 -0
  39. package/dist/lib/callback-server.js +145 -0
  40. package/dist/lib/callback-server.js.map +1 -0
  41. package/dist/lib/cli-contracts.d.ts +193 -0
  42. package/dist/lib/cli-contracts.js +242 -0
  43. package/dist/lib/cli-contracts.js.map +1 -0
  44. package/dist/lib/config.d.ts +2 -0
  45. package/dist/lib/config.js +11 -0
  46. package/dist/lib/config.js.map +1 -1
  47. package/dist/lib/credentials.d.ts +89 -0
  48. package/dist/lib/credentials.js +304 -0
  49. package/dist/lib/credentials.js.map +1 -0
  50. package/dist/lib/endpoints.d.ts +5 -0
  51. package/dist/lib/endpoints.js +31 -0
  52. package/dist/lib/endpoints.js.map +1 -0
  53. package/dist/lib/http.d.ts +3 -0
  54. package/dist/lib/http.js +51 -0
  55. package/dist/lib/http.js.map +1 -0
  56. package/dist/lib/managed.d.ts +8 -0
  57. package/dist/lib/managed.js +72 -6
  58. package/dist/lib/managed.js.map +1 -1
  59. package/dist/lib/oauth-client.d.ts +55 -0
  60. package/dist/lib/oauth-client.js +155 -0
  61. package/dist/lib/oauth-client.js.map +1 -0
  62. package/dist/lib/pkce.d.ts +14 -0
  63. package/dist/lib/pkce.js +33 -0
  64. package/dist/lib/pkce.js.map +1 -0
  65. package/dist/lib/vault.d.ts +26 -0
  66. package/dist/lib/vault.js +221 -0
  67. package/dist/lib/vault.js.map +1 -0
  68. package/dist/runtime/brainmcp-hook-runtime.mjs +3243 -0
  69. package/dist/runtime/capture.d.ts +83 -0
  70. package/dist/runtime/capture.js +332 -0
  71. package/dist/runtime/capture.js.map +1 -0
  72. package/dist/runtime/diagnostics.d.ts +7 -0
  73. package/dist/runtime/diagnostics.js +75 -0
  74. package/dist/runtime/diagnostics.js.map +1 -0
  75. package/dist/runtime/doctor-checks.d.ts +15 -0
  76. package/dist/runtime/doctor-checks.js +233 -0
  77. package/dist/runtime/doctor-checks.js.map +1 -0
  78. package/dist/runtime/flush.d.ts +30 -0
  79. package/dist/runtime/flush.js +193 -0
  80. package/dist/runtime/flush.js.map +1 -0
  81. package/dist/runtime/hook-dispatcher.d.ts +31 -0
  82. package/dist/runtime/hook-dispatcher.js +381 -0
  83. package/dist/runtime/hook-dispatcher.js.map +1 -0
  84. package/dist/runtime/index.d.ts +12 -0
  85. package/dist/runtime/index.js +69 -0
  86. package/dist/runtime/index.js.map +1 -0
  87. package/dist/runtime/installer.d.ts +26 -0
  88. package/dist/runtime/installer.js +134 -0
  89. package/dist/runtime/installer.js.map +1 -0
  90. package/dist/runtime/lock.d.ts +19 -0
  91. package/dist/runtime/lock.js +116 -0
  92. package/dist/runtime/lock.js.map +1 -0
  93. package/dist/runtime/orient.d.ts +55 -0
  94. package/dist/runtime/orient.js +256 -0
  95. package/dist/runtime/orient.js.map +1 -0
  96. package/dist/runtime/queue.d.ts +7 -0
  97. package/dist/runtime/queue.js +80 -0
  98. package/dist/runtime/queue.js.map +1 -0
  99. package/dist/runtime/retention.d.ts +26 -0
  100. package/dist/runtime/retention.js +175 -0
  101. package/dist/runtime/retention.js.map +1 -0
  102. package/dist/runtime/session.d.ts +68 -0
  103. package/dist/runtime/session.js +283 -0
  104. package/dist/runtime/session.js.map +1 -0
  105. package/dist/runtime/storage.d.ts +32 -0
  106. package/dist/runtime/storage.js +236 -0
  107. package/dist/runtime/storage.js.map +1 -0
  108. package/package.json +3 -2
@@ -0,0 +1,175 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { getBrainHome, assertNotSymlink, resolveStateDir } from './storage.js';
4
+ import { listQueueItems, removeQueueItem } from './queue.js';
5
+ import { isProcessAlive } from './lock.js';
6
+ const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
7
+ const FOURTEEN_DAYS_MS = 14 * 24 * 60 * 60 * 1000;
8
+ const FIVE_MB_BYTES = 5 * 1024 * 1024;
9
+ function listOwnedJsonFiles(directory, accepts) {
10
+ if (!fs.existsSync(directory))
11
+ return [];
12
+ assertNotSymlink(directory);
13
+ return fs.readdirSync(directory).flatMap((entry) => {
14
+ if (!accepts(entry))
15
+ return [];
16
+ const filePath = path.join(directory, entry);
17
+ try {
18
+ const stat = fs.lstatSync(filePath);
19
+ return stat.isFile() && !stat.isSymbolicLink() ? [filePath] : [];
20
+ }
21
+ catch {
22
+ return [];
23
+ }
24
+ });
25
+ }
26
+ export function previewCapturePurge(baseDir) {
27
+ const stateDir = resolveStateDir(baseDir);
28
+ return {
29
+ queueItems: listOwnedJsonFiles(path.join(stateDir, 'queue'), (name) => name.endsWith('.json')).length,
30
+ sessionLedgers: listOwnedJsonFiles(path.join(stateDir, 'sessions'), (name) => name.endsWith('.json')).length,
31
+ orientationCacheFiles: listOwnedJsonFiles(path.join(stateDir, 'cache'), (name) => name.startsWith('orient-') && name.endsWith('.json')).length,
32
+ };
33
+ }
34
+ /** Delete only BrainMCP-owned queue, session-ledger, and orientation-cache files. */
35
+ export function purgeCaptureLocalState(baseDir) {
36
+ const stateDir = resolveStateDir(baseDir);
37
+ const groups = [
38
+ listOwnedJsonFiles(path.join(stateDir, 'queue'), (name) => name.endsWith('.json')),
39
+ listOwnedJsonFiles(path.join(stateDir, 'sessions'), (name) => name.endsWith('.json')),
40
+ listOwnedJsonFiles(path.join(stateDir, 'cache'), (name) => name.startsWith('orient-') && name.endsWith('.json')),
41
+ ];
42
+ const removed = {
43
+ queueItems: 0,
44
+ sessionLedgers: 0,
45
+ orientationCacheFiles: 0,
46
+ };
47
+ const keys = ['queueItems', 'sessionLedgers', 'orientationCacheFiles'];
48
+ groups.forEach((files, index) => {
49
+ for (const filePath of files) {
50
+ try {
51
+ fs.unlinkSync(filePath);
52
+ removed[keys[index]] += 1;
53
+ }
54
+ catch {
55
+ // Report only confirmed deletions; callers can preview again if needed.
56
+ }
57
+ }
58
+ });
59
+ return removed;
60
+ }
61
+ /**
62
+ * Safely prunes expired queue items, old session ledgers, stale locks, and trims logs (AHI-058).
63
+ * Never touches active credentials or installed runtime files.
64
+ */
65
+ export function pruneLocalState(options) {
66
+ const baseDir = resolveStateDir(options?.baseDir ?? getBrainHome());
67
+ const now = options?.now ?? Date.now();
68
+ const maxQueueAge = options?.maxQueueAgeMs ?? SEVEN_DAYS_MS;
69
+ const maxSessionAge = options?.maxSessionAgeMs ?? FOURTEEN_DAYS_MS;
70
+ const maxLogSize = options?.maxLogSizeBytes ?? FIVE_MB_BYTES;
71
+ let prunedQueueCount = 0;
72
+ let prunedSessionCount = 0;
73
+ let prunedLockCount = 0;
74
+ let logRotated = false;
75
+ // 1. Prune queue items
76
+ try {
77
+ const items = listQueueItems(baseDir);
78
+ for (const item of items) {
79
+ const createdAtMs = new Date(item.createdAt).getTime();
80
+ if (now - createdAtMs > maxQueueAge || item.status === 'delivered') {
81
+ if (removeQueueItem(item.digestId, baseDir)) {
82
+ prunedQueueCount += 1;
83
+ }
84
+ }
85
+ }
86
+ }
87
+ catch {
88
+ // Ignore pruning errors
89
+ }
90
+ // 2. Prune old session files
91
+ const sessionsDir = path.join(baseDir, 'sessions');
92
+ if (fs.existsSync(sessionsDir)) {
93
+ try {
94
+ assertNotSymlink(sessionsDir);
95
+ const sessionFiles = fs.readdirSync(sessionsDir);
96
+ for (const file of sessionFiles) {
97
+ if (!file.endsWith('.json'))
98
+ continue;
99
+ const filePath = path.join(sessionsDir, file);
100
+ try {
101
+ const stat = fs.lstatSync(filePath);
102
+ if (!stat.isSymbolicLink() && now - stat.mtimeMs > maxSessionAge) {
103
+ fs.unlinkSync(filePath);
104
+ prunedSessionCount += 1;
105
+ }
106
+ }
107
+ catch {
108
+ // Ignore
109
+ }
110
+ }
111
+ }
112
+ catch {
113
+ // Ignore
114
+ }
115
+ }
116
+ // 3. Prune stale locks (> 1 hour old or definitely dead)
117
+ const locksDir = path.join(baseDir, 'locks');
118
+ if (fs.existsSync(locksDir)) {
119
+ try {
120
+ assertNotSymlink(locksDir);
121
+ const lockFiles = fs.readdirSync(locksDir);
122
+ for (const file of lockFiles) {
123
+ if (!file.endsWith('.lock'))
124
+ continue;
125
+ const filePath = path.join(locksDir, file);
126
+ try {
127
+ const stat = fs.lstatSync(filePath);
128
+ if (!stat.isSymbolicLink() && now - stat.mtimeMs > 60 * 1000) {
129
+ try {
130
+ if (isProcessAlive(JSON.parse(fs.readFileSync(filePath, 'utf8')).pid))
131
+ continue;
132
+ }
133
+ catch { /* Old malformed locks have no owner to protect. */ }
134
+ fs.unlinkSync(filePath);
135
+ prunedLockCount += 1;
136
+ }
137
+ }
138
+ catch {
139
+ // Ignore
140
+ }
141
+ }
142
+ }
143
+ catch {
144
+ // Ignore
145
+ }
146
+ }
147
+ // 4. Rotate or truncate runtime log if exceeding size
148
+ const logFile = path.join(baseDir, 'logs', 'runtime.log');
149
+ if (fs.existsSync(logFile)) {
150
+ try {
151
+ assertNotSymlink(logFile);
152
+ const stat = fs.lstatSync(logFile);
153
+ if (!stat.isSymbolicLink() && stat.size > maxLogSize) {
154
+ // Truncate keeping the last 1MB
155
+ const keepBytes = 1024 * 1024;
156
+ const buffer = Buffer.alloc(keepBytes);
157
+ const fd = fs.openSync(logFile, 'r');
158
+ fs.readSync(fd, buffer, 0, keepBytes, stat.size - keepBytes);
159
+ fs.closeSync(fd);
160
+ fs.writeFileSync(logFile, buffer, { mode: 0o600 });
161
+ logRotated = true;
162
+ }
163
+ }
164
+ catch {
165
+ // Ignore
166
+ }
167
+ }
168
+ return {
169
+ prunedQueueCount,
170
+ prunedSessionCount,
171
+ prunedLockCount,
172
+ logRotated,
173
+ };
174
+ }
175
+ //# sourceMappingURL=retention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retention.js","sourceRoot":"","sources":["../../src/runtime/retention.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { type SessionLedgerRecord, type QueueItemRecord } from '../lib/cli-contracts.js';
2
+ import { enqueueCaptureItem } from './queue.js';
3
+ export interface BrainToolExecutionResult {
4
+ isWriteBack: boolean;
5
+ actionKind?: 'proposal_created' | 'proposal_applied' | 'idempotent' | 'tags_updated' | 'other_write';
6
+ status?: string;
7
+ proposalId?: string;
8
+ note?: string;
9
+ }
10
+ /**
11
+ * Parse structured Brain tool results to distinguish proposal created/applied/idempotent
12
+ * from failed calls and digest capture (AHI-056).
13
+ */
14
+ export declare function parseBrainToolResult(toolName: string, toolResult: unknown): BrainToolExecutionResult;
15
+ export declare function getSessionLedgerPath(sessionKey: string, baseDir?: string): string;
16
+ export declare function loadSessionLedger(sessionKey: string, baseDir?: string): SessionLedgerRecord;
17
+ export declare function saveSessionLedger(sessionKey: string, ledger: SessionLedgerRecord, baseDir?: string): void;
18
+ /**
19
+ * Return the most recently active valid session ledger without creating one.
20
+ * Manual capture uses this bounded local record instead of inventing content or
21
+ * opening host transcript files.
22
+ */
23
+ export declare function loadMostRecentSessionLedger(baseDir?: string, projectKey?: string): SessionLedgerRecord | null;
24
+ export interface RecordEventInput {
25
+ sessionKey: string;
26
+ baseDir?: string;
27
+ isMeaningful?: boolean;
28
+ editedPath?: string;
29
+ prompt?: string;
30
+ assistantSummary?: string;
31
+ model?: string;
32
+ /** Persist prompt text only after capture + includePrompts consent (AHI-D02). */
33
+ persistPrompts?: boolean;
34
+ toolResult?: {
35
+ toolName: string;
36
+ result: unknown;
37
+ };
38
+ deliveryId?: string;
39
+ now?: string;
40
+ captureRevision?: number;
41
+ projectKey?: string;
42
+ workspaceId?: string;
43
+ }
44
+ /**
45
+ * Updates session ledger under session lock maintaining monotonic sequence counters (AHI-055).
46
+ */
47
+ export declare function recordSessionEvent(input: RecordEventInput): Promise<SessionLedgerRecord>;
48
+ /** Mark a queued slice without creating another lifecycle event sequence. */
49
+ export declare function markSessionCaptured(input: {
50
+ sessionKey: string;
51
+ digestId: string;
52
+ capturedThroughSequence: number;
53
+ baseDir?: string;
54
+ now?: string;
55
+ }): Promise<SessionLedgerRecord>;
56
+ /** Reserve a sequence and enqueue it in the same local critical section. */
57
+ export declare function queueSessionCapture(input: {
58
+ sessionKey: string;
59
+ capturedThroughSequence: number;
60
+ baseDir?: string;
61
+ item: Parameters<typeof enqueueCaptureItem>[0];
62
+ }): Promise<QueueItemRecord | null>;
63
+ export declare function markSessionNudged(input: {
64
+ sessionKey: string;
65
+ nudgedThroughSequence: number;
66
+ baseDir?: string;
67
+ now?: string;
68
+ }): Promise<SessionLedgerRecord>;
@@ -0,0 +1,283 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { createHash } from 'node:crypto';
4
+ import { SESSION_LEDGER_SCHEMA_VERSION, validateSessionLedgerRecord, scrubSecrets, } from '../lib/cli-contracts.js';
5
+ import { enqueueCaptureItem, listQueueItems } from './queue.js';
6
+ import { canEnqueueCapture } from './flush.js';
7
+ import { ensureDirectory0700, writeAtomic0600, readSafeJson, resolveStateDir } from './storage.js';
8
+ import { withSessionLock } from './lock.js';
9
+ /**
10
+ * Parse structured Brain tool results to distinguish proposal created/applied/idempotent
11
+ * from failed calls and digest capture (AHI-056).
12
+ */
13
+ export function parseBrainToolResult(toolName, toolResult) {
14
+ toolName = toolName.replace(/^mcp__brain__/, '').replace(/^mcp__brainmcp__/, '');
15
+ if (!toolName || !toolResult) {
16
+ return { isWriteBack: false };
17
+ }
18
+ // Digest capture or read operations NEVER count as graph write-back
19
+ if (toolName === 'brain_session_digest' ||
20
+ toolName === 'brain_digest_pending' ||
21
+ toolName === 'brain_digest_complete' ||
22
+ toolName.includes('read') ||
23
+ toolName.includes('overview') ||
24
+ toolName.includes('search') ||
25
+ toolName.includes('list')) {
26
+ return { isWriteBack: false };
27
+ }
28
+ let resultObj = toolResult;
29
+ if (typeof toolResult === 'string') {
30
+ try {
31
+ resultObj = JSON.parse(toolResult);
32
+ }
33
+ catch {
34
+ // Plain text output is not structured tool result
35
+ return { isWriteBack: false };
36
+ }
37
+ }
38
+ if (typeof resultObj !== 'object' || resultObj === null) {
39
+ return { isWriteBack: false };
40
+ }
41
+ // If MCP call returned isError or error field
42
+ if (resultObj.isError || resultObj.error) {
43
+ return { isWriteBack: false, status: 'error' };
44
+ }
45
+ // Current MCP results wrap the payload in structuredContent/data. Some
46
+ // hosts expose the serialized text-content fallback instead.
47
+ if (resultObj.structuredContent)
48
+ return parseBrainToolResult(toolName, resultObj.structuredContent);
49
+ if (resultObj.kind === 'tool_error')
50
+ return { isWriteBack: false, status: 'error' };
51
+ if (resultObj.data && typeof resultObj.data === 'object')
52
+ return parseBrainToolResult(toolName, resultObj.data);
53
+ if (Array.isArray(resultObj.content)) {
54
+ for (const block of resultObj.content.slice(0, 8)) {
55
+ if (block?.type !== 'text' || typeof block.text !== 'string')
56
+ continue;
57
+ const parsed = parseBrainToolResult(toolName, block.text);
58
+ if (parsed.isWriteBack)
59
+ return parsed;
60
+ }
61
+ return { isWriteBack: false };
62
+ }
63
+ // Handle brain_change_propose / brain_remember / brain_amend
64
+ if (toolName === 'brain_change_propose' ||
65
+ toolName === 'brain_remember' ||
66
+ toolName === 'brain_amend' ||
67
+ toolName === 'brain_tags_set') {
68
+ const proposal = resultObj.proposal ?? resultObj;
69
+ const status = proposal.status ?? resultObj.status;
70
+ const proposalId = proposal.id ?? resultObj.id ?? resultObj.proposalId;
71
+ if (status === 'applied' && proposalId) {
72
+ const isIdempotent = Boolean(resultObj.idempotentReplay || resultObj.idempotent || proposal.idempotent);
73
+ return {
74
+ isWriteBack: true,
75
+ actionKind: isIdempotent ? 'idempotent' : 'proposal_applied',
76
+ status: 'applied',
77
+ proposalId,
78
+ };
79
+ }
80
+ if (proposalId && (status === 'pending' || status === 'pending_review' || status === 'review_required' || status === 'queued')) {
81
+ return {
82
+ isWriteBack: true,
83
+ actionKind: 'proposal_created',
84
+ status: 'pending_review',
85
+ proposalId,
86
+ note: 'Proposal created awaiting review',
87
+ };
88
+ }
89
+ if (status === 'rejected' || status === 'failed') {
90
+ return { isWriteBack: false, status };
91
+ }
92
+ // Default if proposal created with an ID
93
+ if (proposalId) {
94
+ return {
95
+ isWriteBack: true,
96
+ actionKind: 'proposal_created',
97
+ proposalId,
98
+ status: status ?? 'created',
99
+ };
100
+ }
101
+ }
102
+ return { isWriteBack: false };
103
+ }
104
+ export function getSessionLedgerPath(sessionKey, baseDir) {
105
+ const sessionsDir = path.join(resolveStateDir(baseDir), 'sessions');
106
+ ensureDirectory0700(sessionsDir);
107
+ const safeKey = sessionKey.replace(/[^a-zA-Z0-9_-]/g, '_');
108
+ return path.join(sessionsDir, `${safeKey}.json`);
109
+ }
110
+ export function loadSessionLedger(sessionKey, baseDir) {
111
+ const filePath = getSessionLedgerPath(sessionKey, baseDir);
112
+ const existing = readSafeJson(filePath, validateSessionLedgerRecord);
113
+ if (existing) {
114
+ return existing;
115
+ }
116
+ const now = new Date().toISOString();
117
+ return {
118
+ version: SESSION_LEDGER_SCHEMA_VERSION,
119
+ sessionKey,
120
+ createdAt: now,
121
+ lastEventAt: now,
122
+ eventSequence: 0,
123
+ editedPaths: [],
124
+ deliveryIds: [],
125
+ };
126
+ }
127
+ export function saveSessionLedger(sessionKey, ledger, baseDir) {
128
+ const filePath = getSessionLedgerPath(sessionKey, baseDir);
129
+ writeAtomic0600(filePath, JSON.stringify(ledger, null, 2));
130
+ }
131
+ /**
132
+ * Return the most recently active valid session ledger without creating one.
133
+ * Manual capture uses this bounded local record instead of inventing content or
134
+ * opening host transcript files.
135
+ */
136
+ export function loadMostRecentSessionLedger(baseDir, projectKey) {
137
+ const sessionsDir = path.join(resolveStateDir(baseDir), 'sessions');
138
+ if (!fs.existsSync(sessionsDir))
139
+ return null;
140
+ const directory = fs.lstatSync(sessionsDir);
141
+ if (directory.isSymbolicLink() || !directory.isDirectory()) {
142
+ throw new Error(`Security violation: ${sessionsDir} is not a safe session directory`);
143
+ }
144
+ let latest = null;
145
+ let latestAt = Number.NEGATIVE_INFINITY;
146
+ for (const entry of fs.readdirSync(sessionsDir).slice(0, 1_000)) {
147
+ if (!entry.endsWith('.json'))
148
+ continue;
149
+ const filePath = path.join(sessionsDir, entry);
150
+ try {
151
+ const ledger = readSafeJson(filePath, validateSessionLedgerRecord);
152
+ if (!ledger)
153
+ continue;
154
+ if (projectKey && ledger.projectKey !== projectKey)
155
+ continue;
156
+ const timestamp = Date.parse(ledger.lastEventAt);
157
+ const comparable = Number.isFinite(timestamp) ? timestamp : fs.lstatSync(filePath).mtimeMs;
158
+ if (comparable > latestAt) {
159
+ latest = ledger;
160
+ latestAt = comparable;
161
+ }
162
+ }
163
+ catch {
164
+ // A malformed, unsafe, or stale entry must not block other valid ledgers.
165
+ }
166
+ }
167
+ return latest;
168
+ }
169
+ /**
170
+ * Updates session ledger under session lock maintaining monotonic sequence counters (AHI-055).
171
+ */
172
+ export async function recordSessionEvent(input) {
173
+ return withSessionLock(input.sessionKey, async () => {
174
+ const ledger = loadSessionLedger(input.sessionKey, input.baseDir);
175
+ const timestamp = input.now ?? new Date().toISOString();
176
+ if (input.captureRevision !== undefined && (ledger.captureRevision !== input.captureRevision || ledger.workspaceId !== input.workspaceId)) {
177
+ ledger.prompts = [];
178
+ ledger.editedPaths = [];
179
+ ledger.assistantSummary = undefined;
180
+ ledger.model = undefined;
181
+ ledger.lastCapturedSequence = ledger.eventSequence;
182
+ ledger.captureRevision = input.captureRevision;
183
+ ledger.workspaceId = input.workspaceId;
184
+ }
185
+ // Monotonic sequence bump
186
+ ledger.eventSequence += 1;
187
+ ledger.lastEventAt = timestamp;
188
+ if (input.projectKey)
189
+ ledger.projectKey = input.projectKey;
190
+ if (input.editedPath && !ledger.editedPaths.includes(input.editedPath)) {
191
+ if (ledger.editedPaths.length >= 100) {
192
+ ledger.editedPaths.shift();
193
+ }
194
+ ledger.editedPaths.push(input.editedPath);
195
+ }
196
+ if (input.prompt && input.persistPrompts) {
197
+ if (!ledger.prompts)
198
+ ledger.prompts = [];
199
+ if (ledger.prompts.length >= 50) {
200
+ ledger.prompts.shift();
201
+ }
202
+ ledger.prompts.push(scrubSecrets(input.prompt).slice(0, 1000));
203
+ }
204
+ if (input.assistantSummary?.trim()) {
205
+ ledger.assistantSummary = scrubSecrets(input.assistantSummary.trim()).slice(0, 4000);
206
+ }
207
+ if (input.model?.trim()) {
208
+ ledger.model = input.model.trim().slice(0, 120);
209
+ }
210
+ if (input.deliveryId && !ledger.deliveryIds.includes(input.deliveryId)) {
211
+ ledger.deliveryIds.push(input.deliveryId);
212
+ ledger.deliveryIds = ledger.deliveryIds.slice(-100);
213
+ }
214
+ if (input.isMeaningful) {
215
+ ledger.lastMeaningfulAt = timestamp;
216
+ ledger.lastMeaningfulSequence = Math.max(ledger.lastMeaningfulSequence ?? 0, ledger.eventSequence);
217
+ }
218
+ // Check tool result for structured Brain write-back (AHI-056)
219
+ if (input.toolResult) {
220
+ const parsed = parseBrainToolResult(input.toolResult.toolName, input.toolResult.result);
221
+ if (parsed.isWriteBack) {
222
+ ledger.lastSuccessfulWriteBackAt = timestamp;
223
+ ledger.lastSuccessfulWriteBackSequence = Math.max(ledger.lastSuccessfulWriteBackSequence ?? 0, ledger.eventSequence);
224
+ }
225
+ }
226
+ saveSessionLedger(input.sessionKey, ledger, input.baseDir);
227
+ return ledger;
228
+ }, { baseDir: input.baseDir, timeoutMs: 250 });
229
+ }
230
+ /** Mark a queued slice without creating another lifecycle event sequence. */
231
+ export async function markSessionCaptured(input) {
232
+ return withSessionLock(input.sessionKey, async () => {
233
+ const ledger = loadSessionLedger(input.sessionKey, input.baseDir);
234
+ ledger.lastCapturedAt = input.now ?? new Date().toISOString();
235
+ ledger.lastCapturedSequence = Math.max(ledger.lastCapturedSequence ?? 0, input.capturedThroughSequence);
236
+ if (!ledger.deliveryIds.includes(input.digestId))
237
+ ledger.deliveryIds.push(input.digestId);
238
+ ledger.deliveryIds = ledger.deliveryIds.slice(-100);
239
+ saveSessionLedger(input.sessionKey, ledger, input.baseDir);
240
+ return ledger;
241
+ }, { baseDir: input.baseDir });
242
+ }
243
+ /** Reserve a sequence and enqueue it in the same local critical section. */
244
+ export async function queueSessionCapture(input) {
245
+ return withSessionLock(input.sessionKey, () => withSessionLock('capture-queue', () => {
246
+ const ledger = loadSessionLedger(input.sessionKey, input.baseDir);
247
+ if ((ledger.lastCapturedSequence ?? 0) >= input.capturedThroughSequence)
248
+ return null;
249
+ // Deterministic UUID makes a crash between enqueue and ledger save retry
250
+ // the same server idempotency key without resetting an existing delivery.
251
+ const hash = createHash('sha256').update(JSON.stringify([input.sessionKey, input.capturedThroughSequence,
252
+ input.item.authorizationId, input.item.consentRevision, input.item.workspaceId])).digest('hex');
253
+ const digestId = `${hash.slice(0, 8)}-${hash.slice(8, 12)}-4${hash.slice(13, 16)}-8${hash.slice(17, 20)}-${hash.slice(20, 32)}`;
254
+ let item = listQueueItems(input.baseDir).find((queued) => queued.digestId === digestId);
255
+ if (!item) {
256
+ if (!canEnqueueCapture(input.baseDir))
257
+ return null;
258
+ let digestText = input.item.digestText;
259
+ try {
260
+ const payload = JSON.parse(digestText);
261
+ if (payload && typeof payload === 'object' && 'clientDigestId' in payload)
262
+ digestText = JSON.stringify({ ...payload, clientDigestId: digestId });
263
+ }
264
+ catch { /* A bounded plain-text digest is also valid. */ }
265
+ item = enqueueCaptureItem({ ...input.item, digestId, digestText }, input.baseDir);
266
+ }
267
+ ledger.lastCapturedAt = item.createdAt;
268
+ ledger.lastCapturedSequence = input.capturedThroughSequence;
269
+ ledger.deliveryIds = [...ledger.deliveryIds, item.digestId].slice(-100);
270
+ saveSessionLedger(input.sessionKey, ledger, input.baseDir);
271
+ return item;
272
+ }, { baseDir: input.baseDir, timeoutMs: 250 }), { baseDir: input.baseDir, timeoutMs: 250 });
273
+ }
274
+ export async function markSessionNudged(input) {
275
+ return withSessionLock(input.sessionKey, async () => {
276
+ const ledger = loadSessionLedger(input.sessionKey, input.baseDir);
277
+ ledger.lastNudgedAt = input.now ?? new Date().toISOString();
278
+ ledger.lastNudgedSequence = Math.max(ledger.lastNudgedSequence ?? 0, input.nudgedThroughSequence);
279
+ saveSessionLedger(input.sessionKey, ledger, input.baseDir);
280
+ return ledger;
281
+ }, { baseDir: input.baseDir });
282
+ }
283
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/runtime/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { type PreferencesRecord } from '../lib/cli-contracts.js';
2
+ export declare const CURRENT_ACCOUNT_SCHEMA_VERSION = 1;
3
+ export declare const SERVICE_ACCOUNT_ID = "service";
4
+ export declare const ACCOUNTS_DIR_NAME = "accounts";
5
+ export declare const CURRENT_ACCOUNT_FILENAME = "current.json";
6
+ export interface CurrentAccountRecord {
7
+ version: typeof CURRENT_ACCOUNT_SCHEMA_VERSION;
8
+ accountId: string;
9
+ updatedAt: string;
10
+ }
11
+ export declare function getBrainHome(): string;
12
+ export declare function sanitizeAccountId(accountId: string): string;
13
+ export declare function getCurrentAccountPath(brainHome?: string): string;
14
+ export declare function validateCurrentAccountRecord(data: unknown): CurrentAccountRecord;
15
+ export declare function getCurrentAccountId(brainHome?: string): string | null;
16
+ export declare function getAccountStateDir(brainHome: string, accountId: string): string;
17
+ /**
18
+ * Per-account state directory when `current.json` is present.
19
+ * Without a current account, callers keep using the brain home (legacy layout and tests).
20
+ */
21
+ export declare function resolveStateDir(brainHome?: string): string;
22
+ export declare function switchCurrentAccount(brainHome: string, accountId: string): string;
23
+ export declare function clearCurrentAccount(brainHome: string): void;
24
+ export declare function migrateLegacyFlatState(brainHome: string, accountId: string): string[];
25
+ export declare function activateAccount(brainHome: string, accountId: string): string;
26
+ export declare function ensureDirectory0700(dirPath: string): void;
27
+ export declare function assertNotSymlink(targetPath: string): void;
28
+ export declare function writeAtomic0600(filePath: string, content: string): void;
29
+ export declare function readSafeJson<T>(filePath: string, validator?: (data: unknown) => T): T | null;
30
+ export declare function getPreferencesPath(baseDir?: string): string;
31
+ export declare function readPreferences(baseDir?: string): PreferencesRecord | null;
32
+ export declare function writePreferences(prefs: PreferencesRecord, baseDir?: string): void;