@brainmcp/brainmcp 0.1.11 → 0.1.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/README.md +72 -5
- package/dist/agent-config.js +229 -32
- package/dist/commands/auth.d.ts +47 -0
- package/dist/commands/auth.js +390 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/capture.d.ts +34 -0
- package/dist/commands/capture.js +349 -0
- package/dist/commands/capture.js.map +1 -0
- package/dist/commands/dispatch.d.ts +43 -0
- package/dist/commands/dispatch.js +287 -0
- package/dist/commands/dispatch.js.map +1 -0
- package/dist/commands/index.d.ts +4 -0
- package/dist/commands/index.js +180 -36
- package/dist/commands/index.js.map +1 -1
- package/dist/hooks/adapters.d.ts +14 -0
- package/dist/hooks/adapters.js +41 -0
- package/dist/hooks/adapters.js.map +1 -0
- package/dist/hooks/claude.d.ts +24 -0
- package/dist/hooks/claude.js +36 -0
- package/dist/hooks/claude.js.map +1 -0
- package/dist/hooks/codex.d.ts +18 -0
- package/dist/hooks/codex.js +36 -0
- package/dist/hooks/codex.js.map +1 -0
- package/dist/hooks/cursor.d.ts +22 -0
- package/dist/hooks/cursor.js +26 -0
- package/dist/hooks/cursor.js.map +1 -0
- package/dist/hooks/managed-hooks.d.ts +30 -0
- package/dist/hooks/managed-hooks.js +189 -0
- package/dist/hooks/managed-hooks.js.map +1 -0
- package/dist/hooks/vscode.d.ts +22 -0
- package/dist/hooks/vscode.js +27 -0
- package/dist/hooks/vscode.js.map +1 -0
- package/dist/index.js +7 -102
- package/dist/index.js.map +1 -1
- package/dist/lib/api-client.d.ts +32 -0
- package/dist/lib/api-client.js +203 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/callback-server.d.ts +17 -0
- package/dist/lib/callback-server.js +145 -0
- package/dist/lib/callback-server.js.map +1 -0
- package/dist/lib/cli-contracts.d.ts +193 -0
- package/dist/lib/cli-contracts.js +242 -0
- package/dist/lib/cli-contracts.js.map +1 -0
- package/dist/lib/config.d.ts +4 -2
- package/dist/lib/config.js +11 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/credentials.d.ts +89 -0
- package/dist/lib/credentials.js +304 -0
- package/dist/lib/credentials.js.map +1 -0
- package/dist/lib/http.d.ts +3 -0
- package/dist/lib/http.js +50 -0
- package/dist/lib/http.js.map +1 -0
- package/dist/lib/managed.d.ts +8 -0
- package/dist/lib/managed.js +72 -6
- package/dist/lib/managed.js.map +1 -1
- package/dist/lib/oauth-client.d.ts +55 -0
- package/dist/lib/oauth-client.js +154 -0
- package/dist/lib/oauth-client.js.map +1 -0
- package/dist/lib/pkce.d.ts +14 -0
- package/dist/lib/pkce.js +33 -0
- package/dist/lib/pkce.js.map +1 -0
- package/dist/lib/vault.d.ts +26 -0
- package/dist/lib/vault.js +221 -0
- package/dist/lib/vault.js.map +1 -0
- package/dist/runtime/brainmcp-hook-runtime.mjs +3211 -0
- package/dist/runtime/capture.d.ts +83 -0
- package/dist/runtime/capture.js +332 -0
- package/dist/runtime/capture.js.map +1 -0
- package/dist/runtime/diagnostics.d.ts +7 -0
- package/dist/runtime/diagnostics.js +75 -0
- package/dist/runtime/diagnostics.js.map +1 -0
- package/dist/runtime/doctor-checks.d.ts +14 -0
- package/dist/runtime/doctor-checks.js +205 -0
- package/dist/runtime/doctor-checks.js.map +1 -0
- package/dist/runtime/flush.d.ts +30 -0
- package/dist/runtime/flush.js +193 -0
- package/dist/runtime/flush.js.map +1 -0
- package/dist/runtime/hook-dispatcher.d.ts +31 -0
- package/dist/runtime/hook-dispatcher.js +381 -0
- package/dist/runtime/hook-dispatcher.js.map +1 -0
- package/dist/runtime/index.d.ts +12 -0
- package/dist/runtime/index.js +69 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/installer.d.ts +26 -0
- package/dist/runtime/installer.js +134 -0
- package/dist/runtime/installer.js.map +1 -0
- package/dist/runtime/lock.d.ts +19 -0
- package/dist/runtime/lock.js +116 -0
- package/dist/runtime/lock.js.map +1 -0
- package/dist/runtime/orient.d.ts +55 -0
- package/dist/runtime/orient.js +255 -0
- package/dist/runtime/orient.js.map +1 -0
- package/dist/runtime/queue.d.ts +7 -0
- package/dist/runtime/queue.js +80 -0
- package/dist/runtime/queue.js.map +1 -0
- package/dist/runtime/retention.d.ts +26 -0
- package/dist/runtime/retention.js +175 -0
- package/dist/runtime/retention.js.map +1 -0
- package/dist/runtime/session.d.ts +68 -0
- package/dist/runtime/session.js +283 -0
- package/dist/runtime/session.js.map +1 -0
- package/dist/runtime/storage.d.ts +32 -0
- package/dist/runtime/storage.js +236 -0
- package/dist/runtime/storage.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { filterRelativePaths } from '../lib/cli-contracts.js';
|
|
3
|
+
import { emitHostOutput } from '../hooks/adapters.js';
|
|
4
|
+
import { markSessionNudged, queueSessionCapture, recordSessionEvent } from './session.js';
|
|
5
|
+
import { logRuntimeEvent } from './diagnostics.js';
|
|
6
|
+
import { readPreferences, resolveStateDir } from './storage.js';
|
|
7
|
+
import { pruneLocalState } from './retention.js';
|
|
8
|
+
import { withRequestDeadline } from '../lib/http.js';
|
|
9
|
+
import { captureTriggerForEvent, captureProjectKey, buildDigestPayload, collectGitMetadata, isCaptureEligible, isStopEvent, readProjectCaptureRestrictions, resolveCaptureWorkspaceId, serializeDigestPayload, } from './capture.js';
|
|
10
|
+
import { canEnqueueCapture, flushCaptureQueue } from './flush.js';
|
|
11
|
+
import { isSessionStartEvent, isUserPromptEvent, loginOrientationMessage, safeSessionStartOrientation, readProjectWorkspaceId, } from './orient.js';
|
|
12
|
+
import { ApiClient } from '../lib/api-client.js';
|
|
13
|
+
import { createDefaultCredentialStore } from '../lib/credentials.js';
|
|
14
|
+
export const MAX_STDIN_BYTES = 1024 * 1024; // 1 MB
|
|
15
|
+
export const DEFAULT_EVENT_TIMEOUT_MS = 1000;
|
|
16
|
+
export const SESSION_END_TIMEOUT_MS = 3000;
|
|
17
|
+
function isSessionEndEvent(event) {
|
|
18
|
+
return event === 'SessionEnd' || event === 'sessionEnd' || event === 'session_end';
|
|
19
|
+
}
|
|
20
|
+
function editedPathFromEvent(event) {
|
|
21
|
+
if (!event.cwd || !event.toolInput || typeof event.toolInput !== 'object')
|
|
22
|
+
return undefined;
|
|
23
|
+
const input = event.toolInput;
|
|
24
|
+
const candidate = [input.file_path, input.filePath, input.path].find((value) => typeof value === 'string' && value.trim().length > 0);
|
|
25
|
+
return candidate ? filterRelativePaths([candidate], event.cwd)[0] : undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Strict bounded stdin reader with length check.
|
|
29
|
+
*/
|
|
30
|
+
export async function readBoundedStdin(stream = process.stdin, maxBytes = MAX_STDIN_BYTES, signal) {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
let totalBytes = 0;
|
|
33
|
+
const chunks = [];
|
|
34
|
+
let settled = false;
|
|
35
|
+
const cleanup = () => {
|
|
36
|
+
stream.removeListener('data', data);
|
|
37
|
+
stream.removeListener('end', end);
|
|
38
|
+
stream.removeListener('error', fail);
|
|
39
|
+
signal?.removeEventListener('abort', abort);
|
|
40
|
+
stream.pause();
|
|
41
|
+
};
|
|
42
|
+
const fail = (err) => {
|
|
43
|
+
if (settled)
|
|
44
|
+
return;
|
|
45
|
+
settled = true;
|
|
46
|
+
cleanup();
|
|
47
|
+
reject(err);
|
|
48
|
+
};
|
|
49
|
+
const abort = () => fail(new Error('Hook input timed out'));
|
|
50
|
+
const data = (chunk) => {
|
|
51
|
+
const buf = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
|
|
52
|
+
totalBytes += buf.length;
|
|
53
|
+
if (totalBytes > maxBytes) {
|
|
54
|
+
fail(new Error(`Input exceeded maximum size limit of ${maxBytes} bytes`));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
chunks.push(buf);
|
|
58
|
+
};
|
|
59
|
+
const end = () => {
|
|
60
|
+
if (settled)
|
|
61
|
+
return;
|
|
62
|
+
settled = true;
|
|
63
|
+
cleanup();
|
|
64
|
+
resolve(Buffer.concat(chunks).toString('utf8'));
|
|
65
|
+
};
|
|
66
|
+
stream.on('data', data);
|
|
67
|
+
stream.on('end', end);
|
|
68
|
+
stream.on('error', fail);
|
|
69
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
70
|
+
if (signal?.aborted)
|
|
71
|
+
abort();
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function hostOutput(event, additionalContext) {
|
|
75
|
+
try {
|
|
76
|
+
return emitHostOutput(event.client, event, additionalContext);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return {};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function loadRuntimeClient(options) {
|
|
83
|
+
if (options?.apiClient) {
|
|
84
|
+
return {
|
|
85
|
+
apiClient: options.apiClient,
|
|
86
|
+
creds: options.credentials === undefined ? await options.apiClient.getEffectiveCredentials() : options.credentials,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const { store } = await createDefaultCredentialStore({
|
|
91
|
+
baseDir: options?.baseDir,
|
|
92
|
+
warn: () => undefined,
|
|
93
|
+
});
|
|
94
|
+
const apiClient = new ApiClient({ store });
|
|
95
|
+
return { apiClient, creds: await apiClient.getEffectiveCredentials() };
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return { apiClient: null, creds: null };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Dispatches a normalized HookEvent under deadline/abort control (AHI-053).
|
|
103
|
+
* Always fails open with empty success on error or timeout.
|
|
104
|
+
*
|
|
105
|
+
* Stop/SessionStop never queues or flushes digests (AHI-D03).
|
|
106
|
+
* Capture queue writes require user-local consent (AHI-D01) and are further
|
|
107
|
+
* restrictable by project `.brainmcp.json` (AHI-D02).
|
|
108
|
+
*/
|
|
109
|
+
export async function dispatchHookEvent(event, options) {
|
|
110
|
+
const timeoutMs = options?.timeoutMs ??
|
|
111
|
+
(isSessionEndEvent(event.event)
|
|
112
|
+
? SESSION_END_TIMEOUT_MS
|
|
113
|
+
: DEFAULT_EVENT_TIMEOUT_MS);
|
|
114
|
+
const controller = new AbortController();
|
|
115
|
+
const onExternalAbort = () => controller.abort();
|
|
116
|
+
options?.signal?.addEventListener('abort', onExternalAbort, { once: true });
|
|
117
|
+
if (options?.signal?.aborted)
|
|
118
|
+
controller.abort();
|
|
119
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
120
|
+
// Keep credential lookup rooted at the Brain home; the pinned account
|
|
121
|
+
// directory below is only for this event's local state.
|
|
122
|
+
const credentialOptions = options;
|
|
123
|
+
try {
|
|
124
|
+
// Never persist host IDs or share ledgers across hosts/projects. A missing
|
|
125
|
+
// session ID permits orientation only, never a shared fallback ledger.
|
|
126
|
+
if ((!event.sessionKey || event.sessionKey === 'default_session') && !isSessionStartEvent(event.event)) {
|
|
127
|
+
return { handled: false, emptyFallback: true, outputPayload: {} };
|
|
128
|
+
}
|
|
129
|
+
event = { ...event, sessionKey: crypto.createHash('sha256').update(JSON.stringify([
|
|
130
|
+
event.client, event.sessionKey, event.workspaceRoots?.length ? [...event.workspaceRoots].sort() : [event.cwd ?? ''],
|
|
131
|
+
])).digest('hex') };
|
|
132
|
+
options = { ...options, baseDir: resolveStateDir(options?.baseDir) };
|
|
133
|
+
if (controller.signal.aborted) {
|
|
134
|
+
throw new Error('Hook dispatch timed out');
|
|
135
|
+
}
|
|
136
|
+
const prefs = readPreferences(options?.baseDir);
|
|
137
|
+
const roots = event.workspaceRoots?.length ? event.workspaceRoots : event.cwd ? [event.cwd] : [];
|
|
138
|
+
const policies = roots.map(readProjectCaptureRestrictions);
|
|
139
|
+
const projectWorkspaces = roots.map(readProjectWorkspaceId);
|
|
140
|
+
const projectPolicy = {
|
|
141
|
+
captureDisabled: policies.some((policy) => policy.captureDisabled) || projectWorkspaces.some((workspace) => workspace.kind === 'invalid' || (workspace.kind === 'workspace' && workspace.workspaceId !== prefs?.enabledWorkspaceId)),
|
|
142
|
+
promptsDisabled: policies.some((policy) => policy.promptsDisabled),
|
|
143
|
+
};
|
|
144
|
+
const persistPrompts = Boolean(prefs?.consent?.captureEnabled &&
|
|
145
|
+
prefs?.consent?.includePrompts &&
|
|
146
|
+
!projectPolicy.promptsDisabled);
|
|
147
|
+
const captureRuntimeEnabled = Boolean(prefs?.consent?.captureEnabled && !projectPolicy.captureDisabled);
|
|
148
|
+
// Stop is a hard zero-persistence and zero-egress boundary. StopNudge is a
|
|
149
|
+
// separate, explicitly installed command and only reads bounded local state.
|
|
150
|
+
if (event.event !== 'StopNudge' && isStopEvent(event.event, event.stopHookActive)) {
|
|
151
|
+
logRuntimeEvent('info', 'hook_stop_ignored', { event: event.event, sessionKey: event.sessionKey, client: event.client }, options?.baseDir);
|
|
152
|
+
return {
|
|
153
|
+
handled: true,
|
|
154
|
+
emptyFallback: false,
|
|
155
|
+
outputPayload: hostOutput(event),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
// Init installs dormant lifecycle boundaries so a later capture opt-in can
|
|
159
|
+
// work without rewriting every host config. Until then they persist no
|
|
160
|
+
// prompt, tool, path, summary, or session ledger data. The nudge ledger is
|
|
161
|
+
// separately tagged in the managed command and never enables capture.
|
|
162
|
+
if (!isSessionStartEvent(event.event) &&
|
|
163
|
+
!captureRuntimeEnabled &&
|
|
164
|
+
!event.nudgeLedger &&
|
|
165
|
+
event.event !== 'StopNudge') {
|
|
166
|
+
return {
|
|
167
|
+
handled: true,
|
|
168
|
+
emptyFallback: false,
|
|
169
|
+
outputPayload: hostOutput(event),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
// Orientation-only SessionStart must not create a session ledger before
|
|
173
|
+
// capture consent. It may read or refresh the authorization-scoped orient
|
|
174
|
+
// cache, but it stores no session, prompt, tool, path, or summary record.
|
|
175
|
+
if (isSessionStartEvent(event.event) && !captureRuntimeEnabled && !event.nudgeLedger) {
|
|
176
|
+
const { apiClient, creds } = await withRequestDeadline(timeoutMs, controller.signal, () => loadRuntimeClient(credentialOptions));
|
|
177
|
+
const additionalContext = apiClient
|
|
178
|
+
? await safeSessionStartOrientation({
|
|
179
|
+
apiClient,
|
|
180
|
+
creds,
|
|
181
|
+
signal: controller.signal,
|
|
182
|
+
baseDir: options?.baseDir,
|
|
183
|
+
cwd: event.cwd,
|
|
184
|
+
workspaceRoots: event.workspaceRoots,
|
|
185
|
+
})
|
|
186
|
+
: loginOrientationMessage();
|
|
187
|
+
if (controller.signal.aborted)
|
|
188
|
+
throw new Error('Hook dispatch timed out');
|
|
189
|
+
return {
|
|
190
|
+
handled: true,
|
|
191
|
+
emptyFallback: false,
|
|
192
|
+
outputPayload: hostOutput(event, additionalContext),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
const isMeaningful = Boolean(event.prompt ||
|
|
196
|
+
event.assistantText ||
|
|
197
|
+
event.event === 'UserPrompt' ||
|
|
198
|
+
event.event === 'prompt' ||
|
|
199
|
+
(event.toolName && !/read|list/i.test(event.toolName)));
|
|
200
|
+
if (isSessionStartEvent(event.event))
|
|
201
|
+
pruneLocalState({ baseDir: options.baseDir });
|
|
202
|
+
const ledger = await recordSessionEvent({
|
|
203
|
+
sessionKey: event.sessionKey,
|
|
204
|
+
baseDir: options?.baseDir,
|
|
205
|
+
isMeaningful,
|
|
206
|
+
editedPath: captureRuntimeEnabled ? editedPathFromEvent(event) : undefined,
|
|
207
|
+
prompt: persistPrompts ? event.prompt : undefined,
|
|
208
|
+
assistantSummary: captureRuntimeEnabled ? event.assistantText : undefined,
|
|
209
|
+
model: captureRuntimeEnabled ? event.model : undefined,
|
|
210
|
+
persistPrompts,
|
|
211
|
+
captureRevision: captureRuntimeEnabled ? prefs?.consent.revision ?? 0 : undefined,
|
|
212
|
+
workspaceId: captureRuntimeEnabled ? prefs?.enabledWorkspaceId : undefined,
|
|
213
|
+
projectKey: event.cwd ? captureProjectKey(event.cwd) : undefined,
|
|
214
|
+
toolResult: event.toolName
|
|
215
|
+
? {
|
|
216
|
+
toolName: event.toolName,
|
|
217
|
+
result: event.toolResult,
|
|
218
|
+
}
|
|
219
|
+
: undefined,
|
|
220
|
+
});
|
|
221
|
+
if (controller.signal.aborted) {
|
|
222
|
+
throw new Error('Hook dispatch timed out');
|
|
223
|
+
}
|
|
224
|
+
if (event.event === 'StopNudge') {
|
|
225
|
+
const lastMeaningful = ledger.lastMeaningfulSequence ?? 0;
|
|
226
|
+
const alreadyHandledThrough = Math.max(ledger.lastSuccessfulWriteBackSequence ?? 0, ledger.lastNudgedSequence ?? 0);
|
|
227
|
+
if (!event.stopHookActive && lastMeaningful > alreadyHandledThrough) {
|
|
228
|
+
await markSessionNudged({
|
|
229
|
+
sessionKey: event.sessionKey,
|
|
230
|
+
nudgedThroughSequence: lastMeaningful,
|
|
231
|
+
baseDir: options?.baseDir,
|
|
232
|
+
});
|
|
233
|
+
return {
|
|
234
|
+
handled: true,
|
|
235
|
+
emptyFallback: false,
|
|
236
|
+
outputPayload: hostOutput(event, 'Before finishing, consider whether this work produced genuinely new durable project knowledge. If so, use brain_remember, brain_amend, or brain_change_propose; otherwise continue without writing.'),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
return { handled: true, emptyFallback: false, outputPayload: {} };
|
|
240
|
+
}
|
|
241
|
+
// Defensive invariant for any future stop alias added after the early gate.
|
|
242
|
+
if (isStopEvent(event.event, event.stopHookActive)) {
|
|
243
|
+
logRuntimeEvent('info', 'hook_stop_ignored', {
|
|
244
|
+
event: event.event,
|
|
245
|
+
sessionKey: event.sessionKey,
|
|
246
|
+
client: event.client,
|
|
247
|
+
}, options?.baseDir);
|
|
248
|
+
return {
|
|
249
|
+
handled: true,
|
|
250
|
+
emptyFallback: false,
|
|
251
|
+
outputPayload: hostOutput(event),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
const { apiClient, creds } = await withRequestDeadline(timeoutMs, controller.signal, () => loadRuntimeClient(credentialOptions));
|
|
255
|
+
let additionalContext;
|
|
256
|
+
if (isSessionStartEvent(event.event)) {
|
|
257
|
+
additionalContext = apiClient
|
|
258
|
+
? await safeSessionStartOrientation({
|
|
259
|
+
apiClient,
|
|
260
|
+
creds,
|
|
261
|
+
signal: controller.signal,
|
|
262
|
+
baseDir: options?.baseDir,
|
|
263
|
+
cwd: event.cwd,
|
|
264
|
+
workspaceRoots: event.workspaceRoots,
|
|
265
|
+
})
|
|
266
|
+
: loginOrientationMessage();
|
|
267
|
+
}
|
|
268
|
+
else if (isUserPromptEvent(event.event)) {
|
|
269
|
+
// AHI-D18: never transmit prompt text as an /orient query.
|
|
270
|
+
additionalContext = undefined;
|
|
271
|
+
}
|
|
272
|
+
if (controller.signal.aborted) {
|
|
273
|
+
throw new Error('Hook dispatch timed out');
|
|
274
|
+
}
|
|
275
|
+
const trigger = captureTriggerForEvent(event.event);
|
|
276
|
+
const hasUncapturedMeaningfulSlice = (ledger.lastMeaningfulSequence ?? 0) > (ledger.lastCapturedSequence ?? 0);
|
|
277
|
+
if (trigger &&
|
|
278
|
+
isCaptureEligible(event.event, prefs, projectPolicy) &&
|
|
279
|
+
hasUncapturedMeaningfulSlice) {
|
|
280
|
+
const workspaceId = resolveCaptureWorkspaceId(prefs);
|
|
281
|
+
if (!workspaceId) {
|
|
282
|
+
logRuntimeEvent('warn', 'capture_workspace_unresolved', {
|
|
283
|
+
event: event.event,
|
|
284
|
+
sessionKey: event.sessionKey,
|
|
285
|
+
}, options?.baseDir);
|
|
286
|
+
}
|
|
287
|
+
else if (!canEnqueueCapture(options?.baseDir)) {
|
|
288
|
+
logRuntimeEvent('warn', 'capture_queue_capped', { event: event.event, sessionKey: event.sessionKey }, options?.baseDir);
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
if (creds?.authType !== 'oauth' ||
|
|
292
|
+
!creds.authorizationId ||
|
|
293
|
+
!creds.scopes?.includes('digests:write') ||
|
|
294
|
+
!creds.workspaces?.includes(workspaceId)) {
|
|
295
|
+
logRuntimeEvent('warn', 'capture_authorization_unresolved', { event: event.event, sessionKey: event.sessionKey }, options?.baseDir);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
const payload = buildDigestPayload({
|
|
299
|
+
trigger,
|
|
300
|
+
workspaceId,
|
|
301
|
+
host: event.client,
|
|
302
|
+
model: event.model ?? ledger.model,
|
|
303
|
+
summary: ledger.assistantSummary,
|
|
304
|
+
paths: ledger.editedPaths,
|
|
305
|
+
gitMetadata: collectGitMetadata(event.cwd ?? event.workspaceRoots?.[0]),
|
|
306
|
+
prompts: ledger.prompts,
|
|
307
|
+
includePrompts: Boolean(prefs?.consent?.includePrompts && !projectPolicy.promptsDisabled),
|
|
308
|
+
});
|
|
309
|
+
const digestId = payload.clientDigestId;
|
|
310
|
+
await queueSessionCapture({
|
|
311
|
+
sessionKey: event.sessionKey,
|
|
312
|
+
capturedThroughSequence: ledger.lastMeaningfulSequence ?? ledger.eventSequence,
|
|
313
|
+
baseDir: options?.baseDir,
|
|
314
|
+
item: {
|
|
315
|
+
digestId,
|
|
316
|
+
workspaceId,
|
|
317
|
+
captureTrigger: trigger,
|
|
318
|
+
policyVersion: prefs?.consent?.policyVersion ?? '2026-09-02.capture-v1',
|
|
319
|
+
digestText: serializeDigestPayload(payload),
|
|
320
|
+
authorizationId: creds.authorizationId,
|
|
321
|
+
consentRevision: prefs?.consent?.revision ?? 0,
|
|
322
|
+
},
|
|
323
|
+
});
|
|
324
|
+
logRuntimeEvent('info', 'capture_queued', {
|
|
325
|
+
sessionKey: event.sessionKey,
|
|
326
|
+
digestId,
|
|
327
|
+
trigger,
|
|
328
|
+
}, options?.baseDir);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
const canFlush = Boolean(apiClient) &&
|
|
333
|
+
creds?.authType === 'oauth' &&
|
|
334
|
+
Boolean(creds.accessToken) &&
|
|
335
|
+
Boolean(creds.authorizationId) &&
|
|
336
|
+
Array.isArray(creds.scopes) &&
|
|
337
|
+
creds.scopes.includes('digests:write');
|
|
338
|
+
const isSessionEnd = isSessionEndEvent(event.event);
|
|
339
|
+
if (canFlush &&
|
|
340
|
+
apiClient &&
|
|
341
|
+
!controller.signal.aborted &&
|
|
342
|
+
!isSessionStartEvent(event.event) &&
|
|
343
|
+
!isSessionEnd) {
|
|
344
|
+
await flushCaptureQueue({
|
|
345
|
+
apiClient,
|
|
346
|
+
baseDir: options?.baseDir,
|
|
347
|
+
signal: controller.signal,
|
|
348
|
+
allowAutomatic: prefs?.consent?.captureEnabled === true && !projectPolicy.captureDisabled,
|
|
349
|
+
credentials: creds,
|
|
350
|
+
}).catch(() => undefined);
|
|
351
|
+
}
|
|
352
|
+
logRuntimeEvent('info', 'hook_event_processed', {
|
|
353
|
+
event: event.event,
|
|
354
|
+
sessionKey: event.sessionKey,
|
|
355
|
+
client: event.client,
|
|
356
|
+
}, options?.baseDir);
|
|
357
|
+
return {
|
|
358
|
+
handled: true,
|
|
359
|
+
emptyFallback: false,
|
|
360
|
+
outputPayload: hostOutput(event, additionalContext),
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
catch (err) {
|
|
364
|
+
logRuntimeEvent('warn', 'hook_dispatch_failed', {
|
|
365
|
+
event: event.event,
|
|
366
|
+
sessionKey: event.sessionKey,
|
|
367
|
+
error: err instanceof Error ? err.message : String(err),
|
|
368
|
+
}, options?.baseDir);
|
|
369
|
+
return {
|
|
370
|
+
handled: false,
|
|
371
|
+
emptyFallback: true,
|
|
372
|
+
outputPayload: {},
|
|
373
|
+
error: err instanceof Error ? err.message : String(err),
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
finally {
|
|
377
|
+
clearTimeout(timeoutId);
|
|
378
|
+
options?.signal?.removeEventListener('abort', onExternalAbort);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
//# sourceMappingURL=hook-dispatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-dispatcher.js","sourceRoot":"","sources":["../../src/runtime/hook-dispatcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './storage.js';
|
|
2
|
+
export * from './lock.js';
|
|
3
|
+
export * from './session.js';
|
|
4
|
+
export * from './queue.js';
|
|
5
|
+
export * from './retention.js';
|
|
6
|
+
export * from './installer.js';
|
|
7
|
+
export * from './diagnostics.js';
|
|
8
|
+
export * from './hook-dispatcher.js';
|
|
9
|
+
/**
|
|
10
|
+
* Main execution function when runtime script is called directly by agent host hooks.
|
|
11
|
+
*/
|
|
12
|
+
export declare function runHookRuntimeCli(args?: string[]): Promise<void>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { readBoundedStdin, dispatchHookEvent } from './hook-dispatcher.js';
|
|
5
|
+
import { parseHostEvent } from '../hooks/adapters.js';
|
|
6
|
+
import { withRequestDeadline } from '../lib/http.js';
|
|
7
|
+
import { logRuntimeEvent } from './diagnostics.js';
|
|
8
|
+
export * from './storage.js';
|
|
9
|
+
export * from './lock.js';
|
|
10
|
+
export * from './session.js';
|
|
11
|
+
export * from './queue.js';
|
|
12
|
+
export * from './retention.js';
|
|
13
|
+
export * from './installer.js';
|
|
14
|
+
export * from './diagnostics.js';
|
|
15
|
+
export * from './hook-dispatcher.js';
|
|
16
|
+
/**
|
|
17
|
+
* Main execution function when runtime script is called directly by agent host hooks.
|
|
18
|
+
*/
|
|
19
|
+
export async function runHookRuntimeCli(args = process.argv.slice(2)) {
|
|
20
|
+
try {
|
|
21
|
+
await withRequestDeadline(args[1]?.toLowerCase().includes('sessionend') ? 2500 : 1500, undefined, async (signal) => {
|
|
22
|
+
const rawInput = await readBoundedStdin(process.stdin, undefined, signal);
|
|
23
|
+
if (!rawInput.trim()) {
|
|
24
|
+
process.stdout.write('{}\n');
|
|
25
|
+
process.exitCode = 0;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
let parsed;
|
|
29
|
+
try {
|
|
30
|
+
parsed = JSON.parse(rawInput);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
process.stdout.write('{}\n');
|
|
34
|
+
process.exitCode = 0;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const host = String(args[0] || parsed.client || 'claude-code');
|
|
38
|
+
const eventName = String(args[1] || parsed.event || parsed.hook_event_name || 'GenericEvent');
|
|
39
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
40
|
+
throw new Error('Invalid hook input');
|
|
41
|
+
const normalizedEvent = parseHostEvent(host, parsed, eventName);
|
|
42
|
+
normalizedEvent.nudgeLedger = args.includes('--nudge-ledger');
|
|
43
|
+
const res = await dispatchHookEvent(normalizedEvent, { signal });
|
|
44
|
+
signal.throwIfAborted();
|
|
45
|
+
process.stdout.write(JSON.stringify(res.outputPayload ?? {}) + '\n');
|
|
46
|
+
process.exitCode = 0;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
logRuntimeEvent('warn', 'hook_input_or_deadline_failed');
|
|
51
|
+
process.stdout.write('{}\n');
|
|
52
|
+
process.exitCode = 0;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function isMainModule() {
|
|
56
|
+
const entry = process.argv[1];
|
|
57
|
+
if (!entry)
|
|
58
|
+
return false;
|
|
59
|
+
try {
|
|
60
|
+
return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(entry));
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (isMainModule()) {
|
|
67
|
+
void runHookRuntimeCli();
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare function normalizeRuntimeVersion(version: string): string;
|
|
2
|
+
export interface InstalledRuntime {
|
|
3
|
+
version: string;
|
|
4
|
+
runtimePath: string;
|
|
5
|
+
installedAt: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function getRuntimesDir(baseDir?: string): string;
|
|
8
|
+
export declare function getVersionedRuntimeDir(version: string, baseDir?: string): string;
|
|
9
|
+
export declare function getVersionedRuntimePath(version: string, baseDir?: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Installs runtime bundle atomically to ~/.brainmcp/runtime/v<version>/brainmcp-hook-runtime.mjs (AHI-052).
|
|
12
|
+
*/
|
|
13
|
+
export declare function installRuntimeBundle(version: string, bundleContent: string, baseDir?: string): InstalledRuntime;
|
|
14
|
+
/**
|
|
15
|
+
* Lists all currently installed runtime versions.
|
|
16
|
+
*/
|
|
17
|
+
export declare function listInstalledRuntimes(baseDir?: string): InstalledRuntime[];
|
|
18
|
+
/**
|
|
19
|
+
* Removes an old runtime version, but BLOCKS removal if any known config references it (AHI-052).
|
|
20
|
+
*/
|
|
21
|
+
export declare function removeRuntimeVersion(version: string, referencedPaths: string[], baseDir?: string): {
|
|
22
|
+
removed: boolean;
|
|
23
|
+
blockedReason?: string;
|
|
24
|
+
};
|
|
25
|
+
export declare function cliPackageVersion(): string;
|
|
26
|
+
export declare function loadPackagedRuntimeBundle(): string | null;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { getBrainHome, ensureDirectory0700, assertNotSymlink } from './storage.js';
|
|
7
|
+
const RUNTIME_VERSION_RE = /^[0-9A-Za-z][0-9A-Za-z._-]{0,63}$/;
|
|
8
|
+
export function normalizeRuntimeVersion(version) {
|
|
9
|
+
const normalized = version.trim().replace(/^v/, '');
|
|
10
|
+
if (!RUNTIME_VERSION_RE.test(normalized) || normalized.includes('..')) {
|
|
11
|
+
throw new Error(`Invalid BrainMCP runtime version: ${version}`);
|
|
12
|
+
}
|
|
13
|
+
return normalized;
|
|
14
|
+
}
|
|
15
|
+
export function getRuntimesDir(baseDir) {
|
|
16
|
+
const home = baseDir ?? getBrainHome();
|
|
17
|
+
const runtimesDir = path.join(home, 'runtime');
|
|
18
|
+
ensureDirectory0700(runtimesDir);
|
|
19
|
+
return runtimesDir;
|
|
20
|
+
}
|
|
21
|
+
export function getVersionedRuntimeDir(version, baseDir) {
|
|
22
|
+
const runtimesDir = getRuntimesDir(baseDir);
|
|
23
|
+
const versionDir = path.join(runtimesDir, `v${normalizeRuntimeVersion(version)}`);
|
|
24
|
+
ensureDirectory0700(versionDir);
|
|
25
|
+
return versionDir;
|
|
26
|
+
}
|
|
27
|
+
export function getVersionedRuntimePath(version, baseDir) {
|
|
28
|
+
const versionDir = getVersionedRuntimeDir(version, baseDir);
|
|
29
|
+
return path.join(versionDir, 'brainmcp-hook-runtime.mjs');
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Installs runtime bundle atomically to ~/.brainmcp/runtime/v<version>/brainmcp-hook-runtime.mjs (AHI-052).
|
|
33
|
+
*/
|
|
34
|
+
export function installRuntimeBundle(version, bundleContent, baseDir) {
|
|
35
|
+
const versionDir = getVersionedRuntimeDir(version, baseDir);
|
|
36
|
+
const targetPath = path.join(versionDir, 'brainmcp-hook-runtime.mjs');
|
|
37
|
+
assertNotSymlink(targetPath);
|
|
38
|
+
const tmpPath = `${targetPath}.tmp.${crypto.randomUUID()}`;
|
|
39
|
+
try {
|
|
40
|
+
fs.writeFileSync(tmpPath, bundleContent, { flag: 'wx', mode: 0o755 });
|
|
41
|
+
fs.renameSync(tmpPath, targetPath);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
try {
|
|
45
|
+
fs.unlinkSync(tmpPath);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Best-effort cleanup.
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
version,
|
|
54
|
+
runtimePath: targetPath,
|
|
55
|
+
installedAt: new Date().toISOString(),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Lists all currently installed runtime versions.
|
|
60
|
+
*/
|
|
61
|
+
export function listInstalledRuntimes(baseDir) {
|
|
62
|
+
const runtimesDir = getRuntimesDir(baseDir);
|
|
63
|
+
const entries = fs.readdirSync(runtimesDir);
|
|
64
|
+
const runtimes = [];
|
|
65
|
+
for (const entry of entries) {
|
|
66
|
+
if (!entry.startsWith('v'))
|
|
67
|
+
continue;
|
|
68
|
+
const versionDir = path.join(runtimesDir, entry);
|
|
69
|
+
const runtimePath = path.join(versionDir, 'brainmcp-hook-runtime.mjs');
|
|
70
|
+
if (fs.existsSync(runtimePath)) {
|
|
71
|
+
try {
|
|
72
|
+
const stat = fs.lstatSync(runtimePath);
|
|
73
|
+
if (!stat.isSymbolicLink()) {
|
|
74
|
+
runtimes.push({
|
|
75
|
+
version: entry.replace(/^v/, ''),
|
|
76
|
+
runtimePath,
|
|
77
|
+
installedAt: stat.mtime.toISOString(),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Ignore
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return runtimes;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Removes an old runtime version, but BLOCKS removal if any known config references it (AHI-052).
|
|
90
|
+
*/
|
|
91
|
+
export function removeRuntimeVersion(version, referencedPaths, baseDir) {
|
|
92
|
+
const targetPath = getVersionedRuntimePath(version, baseDir);
|
|
93
|
+
const normalizedTarget = path.resolve(targetPath);
|
|
94
|
+
// Check if any referenced path in host configs references this runtime
|
|
95
|
+
const isReferenced = referencedPaths.some((ref) => {
|
|
96
|
+
const normRef = path.resolve(ref);
|
|
97
|
+
return normRef === normalizedTarget || normRef.includes(`/v${normalizeRuntimeVersion(version)}/`);
|
|
98
|
+
});
|
|
99
|
+
if (isReferenced) {
|
|
100
|
+
return {
|
|
101
|
+
removed: false,
|
|
102
|
+
blockedReason: `Runtime v${version} is still referenced by an active host configuration`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const versionDir = getVersionedRuntimeDir(version, baseDir);
|
|
106
|
+
if (fs.existsSync(versionDir)) {
|
|
107
|
+
fs.rmSync(versionDir, { recursive: true, force: true });
|
|
108
|
+
return { removed: true };
|
|
109
|
+
}
|
|
110
|
+
return { removed: false, blockedReason: `Runtime v${version} does not exist` };
|
|
111
|
+
}
|
|
112
|
+
export function cliPackageVersion() {
|
|
113
|
+
try {
|
|
114
|
+
const require = createRequire(import.meta.url);
|
|
115
|
+
return String(require('../../package.json').version);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return '0.1.13';
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
export function loadPackagedRuntimeBundle() {
|
|
122
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
123
|
+
const candidates = [
|
|
124
|
+
path.join(here, 'brainmcp-hook-runtime.mjs'),
|
|
125
|
+
path.join(here, '../../dist/runtime/brainmcp-hook-runtime.mjs'),
|
|
126
|
+
];
|
|
127
|
+
for (const candidate of candidates) {
|
|
128
|
+
if (fs.existsSync(candidate)) {
|
|
129
|
+
return fs.readFileSync(candidate, 'utf8');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=installer.js.map
|