@brainmcp/brainmcp 0.1.12 → 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.
Files changed (105) hide show
  1. package/README.md +72 -5
  2. package/dist/agent-config.js +153 -24
  3. package/dist/commands/auth.d.ts +47 -0
  4. package/dist/commands/auth.js +390 -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 +180 -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 +203 -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/http.d.ts +3 -0
  51. package/dist/lib/http.js +50 -0
  52. package/dist/lib/http.js.map +1 -0
  53. package/dist/lib/managed.d.ts +8 -0
  54. package/dist/lib/managed.js +72 -6
  55. package/dist/lib/managed.js.map +1 -1
  56. package/dist/lib/oauth-client.d.ts +55 -0
  57. package/dist/lib/oauth-client.js +154 -0
  58. package/dist/lib/oauth-client.js.map +1 -0
  59. package/dist/lib/pkce.d.ts +14 -0
  60. package/dist/lib/pkce.js +33 -0
  61. package/dist/lib/pkce.js.map +1 -0
  62. package/dist/lib/vault.d.ts +26 -0
  63. package/dist/lib/vault.js +221 -0
  64. package/dist/lib/vault.js.map +1 -0
  65. package/dist/runtime/brainmcp-hook-runtime.mjs +3211 -0
  66. package/dist/runtime/capture.d.ts +83 -0
  67. package/dist/runtime/capture.js +332 -0
  68. package/dist/runtime/capture.js.map +1 -0
  69. package/dist/runtime/diagnostics.d.ts +7 -0
  70. package/dist/runtime/diagnostics.js +75 -0
  71. package/dist/runtime/diagnostics.js.map +1 -0
  72. package/dist/runtime/doctor-checks.d.ts +14 -0
  73. package/dist/runtime/doctor-checks.js +205 -0
  74. package/dist/runtime/doctor-checks.js.map +1 -0
  75. package/dist/runtime/flush.d.ts +30 -0
  76. package/dist/runtime/flush.js +193 -0
  77. package/dist/runtime/flush.js.map +1 -0
  78. package/dist/runtime/hook-dispatcher.d.ts +31 -0
  79. package/dist/runtime/hook-dispatcher.js +381 -0
  80. package/dist/runtime/hook-dispatcher.js.map +1 -0
  81. package/dist/runtime/index.d.ts +12 -0
  82. package/dist/runtime/index.js +69 -0
  83. package/dist/runtime/index.js.map +1 -0
  84. package/dist/runtime/installer.d.ts +26 -0
  85. package/dist/runtime/installer.js +134 -0
  86. package/dist/runtime/installer.js.map +1 -0
  87. package/dist/runtime/lock.d.ts +19 -0
  88. package/dist/runtime/lock.js +116 -0
  89. package/dist/runtime/lock.js.map +1 -0
  90. package/dist/runtime/orient.d.ts +55 -0
  91. package/dist/runtime/orient.js +255 -0
  92. package/dist/runtime/orient.js.map +1 -0
  93. package/dist/runtime/queue.d.ts +7 -0
  94. package/dist/runtime/queue.js +80 -0
  95. package/dist/runtime/queue.js.map +1 -0
  96. package/dist/runtime/retention.d.ts +26 -0
  97. package/dist/runtime/retention.js +175 -0
  98. package/dist/runtime/retention.js.map +1 -0
  99. package/dist/runtime/session.d.ts +68 -0
  100. package/dist/runtime/session.js +283 -0
  101. package/dist/runtime/session.js.map +1 -0
  102. package/dist/runtime/storage.d.ts +32 -0
  103. package/dist/runtime/storage.js +236 -0
  104. package/dist/runtime/storage.js.map +1 -0
  105. package/package.json +12 -10
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installer.js","sourceRoot":"","sources":["../../src/runtime/installer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export interface LockMetadata {
2
+ pid: number;
3
+ createdAt: number;
4
+ sessionId: string;
5
+ owner?: string;
6
+ }
7
+ export declare function getSessionLockPath(sessionId: string, baseDir?: string): string;
8
+ export declare function isProcessAlive(pid: number): boolean;
9
+ export declare function acquireSessionLock(sessionId: string, options?: {
10
+ baseDir?: string;
11
+ timeoutMs?: number;
12
+ now?: number;
13
+ }): Promise<{
14
+ release: () => void;
15
+ }>;
16
+ export declare function withSessionLock<T>(sessionId: string, fn: () => Promise<T> | T, options?: {
17
+ baseDir?: string;
18
+ timeoutMs?: number;
19
+ }): Promise<T>;
@@ -0,0 +1,116 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { randomUUID } from 'node:crypto';
4
+ import { ensureDirectory0700, assertNotSymlink, resolveStateDir } from './storage.js';
5
+ const STALE_LOCK_MS = 5000;
6
+ export function getSessionLockPath(sessionId, baseDir) {
7
+ const locksDir = path.join(resolveStateDir(baseDir), 'locks');
8
+ ensureDirectory0700(locksDir);
9
+ // Sanitize sessionId for safe filename
10
+ const safeSessionId = sessionId.replace(/[^a-zA-Z0-9_-]/g, '_');
11
+ return path.join(locksDir, `${safeSessionId}.lock`);
12
+ }
13
+ export function isProcessAlive(pid) {
14
+ if (!Number.isInteger(pid) || pid <= 0)
15
+ return false;
16
+ try {
17
+ process.kill(pid, 0);
18
+ return true;
19
+ }
20
+ catch (err) {
21
+ return err.code === 'EPERM'; // Exists but belongs to another user
22
+ }
23
+ }
24
+ export async function acquireSessionLock(sessionId, options) {
25
+ const lockPath = getSessionLockPath(sessionId, options?.baseDir);
26
+ const timeoutMs = options?.timeoutMs ?? 5000;
27
+ const startTime = Date.now();
28
+ const pollInterval = 20;
29
+ while (true) {
30
+ try {
31
+ assertNotSymlink(lockPath);
32
+ // Try atomic exclusive file creation (flag 'wx')
33
+ const metadata = {
34
+ pid: process.pid,
35
+ createdAt: Date.now(),
36
+ sessionId,
37
+ owner: randomUUID(),
38
+ };
39
+ fs.writeFileSync(lockPath, JSON.stringify(metadata), { flag: 'wx', mode: 0o600 });
40
+ // Acquired lock successfully
41
+ let released = false;
42
+ return {
43
+ release: () => {
44
+ if (released)
45
+ return;
46
+ released = true;
47
+ try {
48
+ if (fs.existsSync(lockPath)) {
49
+ // Verify we still own this lock before unlinking
50
+ const content = fs.readFileSync(lockPath, 'utf8');
51
+ const parsed = JSON.parse(content);
52
+ if (parsed.owner === metadata.owner) {
53
+ fs.unlinkSync(lockPath);
54
+ }
55
+ }
56
+ }
57
+ catch {
58
+ // Ignore release errors
59
+ }
60
+ },
61
+ };
62
+ }
63
+ catch (err) {
64
+ if (err.code === 'EEXIST') {
65
+ const now = Date.now();
66
+ try {
67
+ const raw = fs.readFileSync(lockPath, 'utf8');
68
+ const meta = JSON.parse(raw);
69
+ const age = now - meta.createdAt;
70
+ // Stale if older than STALE_LOCK_MS and process is dead, or older than 2x STALE_LOCK_MS
71
+ if (age > STALE_LOCK_MS && !isProcessAlive(meta.pid)) {
72
+ // Recover stale lock: remove it and retry immediately
73
+ try {
74
+ fs.unlinkSync(lockPath);
75
+ continue;
76
+ }
77
+ catch {
78
+ // Concurrently unlinked or retried
79
+ }
80
+ }
81
+ }
82
+ catch {
83
+ // Corrupt lock file -> recover by removing
84
+ try {
85
+ // An exclusive creator may not yet have written its metadata.
86
+ if (now - fs.lstatSync(lockPath).mtimeMs > STALE_LOCK_MS) {
87
+ fs.unlinkSync(lockPath);
88
+ continue;
89
+ }
90
+ }
91
+ catch {
92
+ // Ignore
93
+ }
94
+ }
95
+ // Check if timeout reached
96
+ if (now - startTime > timeoutMs) {
97
+ throw new Error(`Timed out waiting for session lock: ${sessionId} (waited ${now - startTime}ms)`);
98
+ }
99
+ // Asynchronously sleep before retrying
100
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
101
+ continue;
102
+ }
103
+ throw err;
104
+ }
105
+ }
106
+ }
107
+ export async function withSessionLock(sessionId, fn, options) {
108
+ const lock = await acquireSessionLock(sessionId, options);
109
+ try {
110
+ return await fn();
111
+ }
112
+ finally {
113
+ lock.release();
114
+ }
115
+ }
116
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/runtime/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAStF,MAAM,aAAa,GAAG,IAAI,CAAC;AAE3B,MAAM,UAAU,kBAAkB,CAAC,SAAiB,EAAE,OAAgB;IACpE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;IAC9D,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC9B,uCAAuC;IACvC,MAAM,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;IAChE,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,aAAa,OAAO,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACrD,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,qCAAqC;IACpE,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,SAAiB,EACjB,OAAgE;IAEhE,MAAM,QAAQ,GAAG,kBAAkB,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,YAAY,GAAG,EAAE,CAAC;IAExB,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAC3B,iDAAiD;YACjD,MAAM,QAAQ,GAAiB;gBAC7B,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;gBACrB,SAAS;gBACT,KAAK,EAAE,UAAU,EAAE;aACpB,CAAC;YACF,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAElF,6BAA6B;YAC7B,IAAI,QAAQ,GAAG,KAAK,CAAC;YACrB,OAAO;gBACL,OAAO,EAAE,GAAG,EAAE;oBACZ,IAAI,QAAQ;wBAAE,OAAO;oBACrB,QAAQ,GAAG,IAAI,CAAC;oBAChB,IAAI,CAAC;wBACH,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;4BAC5B,iDAAiD;4BACjD,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;4BAClD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;4BACnC,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,KAAK,EAAE,CAAC;gCACpC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;4BAC1B,CAAC;wBACH,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,wBAAwB;oBAC1B,CAAC;gBACH,CAAC;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACvB,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;oBAC9C,MAAM,IAAI,GAAiB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAC3C,MAAM,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC;oBAEjC,wFAAwF;oBACxF,IAAI,GAAG,GAAG,aAAa,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;wBACrD,sDAAsD;wBACtD,IAAI,CAAC;4BACH,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;4BACxB,SAAS;wBACX,CAAC;wBAAC,MAAM,CAAC;4BACP,mCAAmC;wBACrC,CAAC;oBACH,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,2CAA2C;oBAC3C,IAAI,CAAC;wBACH,8DAA8D;wBAC9D,IAAI,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,OAAO,GAAG,aAAa,EAAE,CAAC;4BACzD,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;4BACxB,SAAS;wBACX,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,SAAS;oBACX,CAAC;gBACH,CAAC;gBAED,2BAA2B;gBAC3B,IAAI,GAAG,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;oBAChC,MAAM,IAAI,KAAK,CAAC,uCAAuC,SAAS,YAAY,GAAG,GAAG,SAAS,KAAK,CAAC,CAAC;gBACpG,CAAC;gBAED,uCAAuC;gBACvC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;gBAClE,SAAS;YACX,CAAC;YAED,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,SAAiB,EACjB,EAAwB,EACxB,OAAkD;IAElD,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC1D,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC;AACH,CAAC"}
@@ -0,0 +1,55 @@
1
+ import { ApiClient } from '../lib/api-client.js';
2
+ import type { StoredCredentials } from '../lib/credentials.js';
3
+ export declare const SESSION_START_EVENTS: Set<string>;
4
+ export declare function isSessionStartEvent(event: string): boolean;
5
+ export declare function isUserPromptEvent(event: string): boolean;
6
+ export interface OrientWorkspace {
7
+ id: string;
8
+ name?: string;
9
+ slug?: string;
10
+ isDefault?: boolean;
11
+ }
12
+ export declare function resolveOrientWorkspaceId(creds: StoredCredentials | null, listed?: OrientWorkspace[]): {
13
+ workspaceId: string | null;
14
+ reason: 'ok' | 'login' | 'select';
15
+ };
16
+ export declare function formatOrientAdditionalContext(payload: unknown): string;
17
+ export declare function loginOrientationMessage(): string;
18
+ export declare function selectWorkspaceOrientationMessage(): string;
19
+ export type ProjectWorkspaceResolution = {
20
+ kind: 'none';
21
+ } | {
22
+ kind: 'invalid';
23
+ configPath: string;
24
+ } | {
25
+ kind: 'workspace';
26
+ configPath: string;
27
+ workspaceId: string;
28
+ };
29
+ /** Resolve only the nearest project policy file; malformed/symlinked files fail closed. */
30
+ export declare function readProjectWorkspaceId(startDir?: string): ProjectWorkspaceResolution;
31
+ export declare function readOrientCache(creds: StoredCredentials, workspaceId: string, options?: {
32
+ baseDir?: string;
33
+ now?: number;
34
+ }): string | null;
35
+ export declare function writeOrientCache(creds: StoredCredentials, workspaceId: string, context: string, options?: {
36
+ baseDir?: string;
37
+ now?: number;
38
+ }): void;
39
+ export declare function clearOrientCache(baseDir?: string): void;
40
+ export declare function fetchSessionStartOrientation(input: {
41
+ apiClient: ApiClient;
42
+ creds: StoredCredentials | null;
43
+ signal?: AbortSignal;
44
+ baseDir?: string;
45
+ cwd?: string;
46
+ workspaceRoots?: string[];
47
+ }): Promise<string>;
48
+ export declare function safeSessionStartOrientation(input: {
49
+ apiClient?: ApiClient;
50
+ creds: StoredCredentials | null;
51
+ signal?: AbortSignal;
52
+ baseDir?: string;
53
+ cwd?: string;
54
+ workspaceRoots?: string[];
55
+ }): Promise<string>;
@@ -0,0 +1,255 @@
1
+ import { createHash } from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { ensureDirectory0700, writeAtomic0600, readSafeJson, resolveStateDir, } from './storage.js';
5
+ import { logRuntimeEvent } from './diagnostics.js';
6
+ const ORIENT_CACHE_TTL_MS = 10 * 60 * 1000;
7
+ const ORIENT_CONTEXT_MAX_CHARS = 2_400;
8
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9
+ export const SESSION_START_EVENTS = new Set([
10
+ 'SessionStart',
11
+ 'sessionStart',
12
+ 'session_start',
13
+ 'startup',
14
+ ]);
15
+ export function isSessionStartEvent(event) {
16
+ return SESSION_START_EVENTS.has(event);
17
+ }
18
+ export function isUserPromptEvent(event) {
19
+ return event === 'UserPromptSubmit' || event === 'UserPrompt' || event === 'prompt' || event === 'beforeSubmitPrompt';
20
+ }
21
+ export function resolveOrientWorkspaceId(creds, listed) {
22
+ if (!creds || creds.authType !== 'oauth' || !creds.accessToken) {
23
+ return { workspaceId: null, reason: 'login' };
24
+ }
25
+ if (creds.defaultWorkspaceId && UUID_RE.test(creds.defaultWorkspaceId)) {
26
+ return { workspaceId: creds.defaultWorkspaceId, reason: 'ok' };
27
+ }
28
+ const fromCreds = (creds.workspaces ?? []).filter((id) => UUID_RE.test(id));
29
+ if (fromCreds.length === 1) {
30
+ return { workspaceId: fromCreds[0], reason: 'ok' };
31
+ }
32
+ if (listed) {
33
+ const defaults = listed.filter((ws) => ws.isDefault);
34
+ if (defaults.length === 1 && UUID_RE.test(defaults[0].id)) {
35
+ return { workspaceId: defaults[0].id, reason: 'ok' };
36
+ }
37
+ if (listed.length === 1 && UUID_RE.test(listed[0].id)) {
38
+ return { workspaceId: listed[0].id, reason: 'ok' };
39
+ }
40
+ if (listed.length !== 1) {
41
+ return { workspaceId: null, reason: 'select' };
42
+ }
43
+ }
44
+ if (fromCreds.length !== 1) {
45
+ return { workspaceId: null, reason: fromCreds.length === 0 ? 'select' : 'select' };
46
+ }
47
+ return { workspaceId: null, reason: 'select' };
48
+ }
49
+ export function formatOrientAdditionalContext(payload) {
50
+ if (!payload || typeof payload !== 'object') {
51
+ return 'BrainMCP orientation is available. Call brain_workspace_overview before non-trivial work.';
52
+ }
53
+ const data = payload;
54
+ const lines = ['BrainMCP orientation (no user prompt was sent).'];
55
+ const workspace = data.workspace && typeof data.workspace === 'object'
56
+ ? data.workspace
57
+ : undefined;
58
+ if (typeof workspace?.name === 'string') {
59
+ lines.push(`Workspace: ${workspace.name}`);
60
+ }
61
+ const review = data.review && typeof data.review === 'object'
62
+ ? data.review
63
+ : undefined;
64
+ if (typeof review?.writePath === 'string') {
65
+ lines.push(`Write path: ${review.writePath}`);
66
+ }
67
+ if (review?.humanReviewRequired === true) {
68
+ lines.push('Human review is required before graph writes apply.');
69
+ }
70
+ if (typeof data.pendingProposalCount === 'number' && data.pendingProposalCount > 0) {
71
+ lines.push(`Pending proposals: ${data.pendingProposalCount}`);
72
+ }
73
+ if (typeof data.dueWorkflowCount === 'number' && data.dueWorkflowCount > 0) {
74
+ lines.push(`Due workflows: ${data.dueWorkflowCount}`);
75
+ }
76
+ const rules = data.rules && typeof data.rules === 'object'
77
+ ? data.rules
78
+ : undefined;
79
+ for (const rule of rules?.items?.slice(0, 3) ?? []) {
80
+ if (typeof rule.body === 'string' && rule.body.trim()) {
81
+ lines.push(`Rule: ${rule.body.trim().slice(0, 280)}`);
82
+ }
83
+ }
84
+ if (typeof data.writeBackHint === 'string' && data.writeBackHint.trim()) {
85
+ lines.push(data.writeBackHint.trim());
86
+ }
87
+ else {
88
+ lines.push('Propose only new durable project knowledge with brain_change_propose after meaningful work.');
89
+ }
90
+ const text = lines.join('\n');
91
+ return text.length > ORIENT_CONTEXT_MAX_CHARS ? `${text.slice(0, ORIENT_CONTEXT_MAX_CHARS - 1)}…` : text;
92
+ }
93
+ export function loginOrientationMessage() {
94
+ return 'BrainMCP CLI is not signed in. Run `brainmcp login`, then retry orientation. No remote request was made.';
95
+ }
96
+ export function selectWorkspaceOrientationMessage() {
97
+ return 'BrainMCP has more than one authorized workspace. Pass workspaceId or set a default before orientation. No workspace was guessed.';
98
+ }
99
+ /** Resolve only the nearest project policy file; malformed/symlinked files fail closed. */
100
+ export function readProjectWorkspaceId(startDir) {
101
+ if (!startDir)
102
+ return { kind: 'none' };
103
+ let dir = path.resolve(startDir);
104
+ for (let depth = 0; depth < 16; depth += 1) {
105
+ const configPath = path.join(dir, '.brainmcp.json');
106
+ if (fs.existsSync(configPath)) {
107
+ try {
108
+ const stat = fs.lstatSync(configPath);
109
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 64 * 1024) {
110
+ return { kind: 'invalid', configPath };
111
+ }
112
+ const parsed = JSON.parse(fs.readFileSync(configPath, 'utf8'));
113
+ const workspaceId = typeof parsed.workspaceId === 'string' ? parsed.workspaceId.trim() : '';
114
+ return UUID_RE.test(workspaceId)
115
+ ? { kind: 'workspace', configPath, workspaceId }
116
+ : { kind: 'invalid', configPath };
117
+ }
118
+ catch {
119
+ return { kind: 'invalid', configPath };
120
+ }
121
+ }
122
+ const parent = path.dirname(dir);
123
+ if (parent === dir)
124
+ break;
125
+ dir = parent;
126
+ }
127
+ return { kind: 'none' };
128
+ }
129
+ function invalidProjectWorkspaceMessage() {
130
+ return 'BrainMCP found an invalid nearest `.brainmcp.json` workspaceId and did not guess another workspace. Fix or remove that project policy file.';
131
+ }
132
+ function cacheKey(creds, workspaceId) {
133
+ const scopes = [...(creds.scopes ?? [])].sort().join(' ');
134
+ const identity = creds.authorizationId
135
+ || createHash('sha256')
136
+ .update(creds.refreshToken || creds.accessToken || creds.serviceToken || creds.clientId || '')
137
+ .digest('hex');
138
+ return createHash('sha256')
139
+ .update(JSON.stringify({
140
+ authorizationId: identity,
141
+ scopes,
142
+ workspaceId,
143
+ contract: '2026-09-02.orient-v1',
144
+ }))
145
+ .digest('hex');
146
+ }
147
+ function cachePath(baseDir, key) {
148
+ const dir = path.join(resolveStateDir(baseDir), 'cache');
149
+ ensureDirectory0700(dir);
150
+ return path.join(dir, `orient-${key.slice(0, 24)}.json`);
151
+ }
152
+ export function readOrientCache(creds, workspaceId, options) {
153
+ const key = cacheKey(creds, workspaceId);
154
+ const record = readSafeJson(cachePath(options?.baseDir, key));
155
+ if (!record || record.key !== key)
156
+ return null;
157
+ const storedAt = Date.parse(record.storedAt);
158
+ if (!Number.isFinite(storedAt))
159
+ return null;
160
+ if ((options?.now ?? Date.now()) - storedAt > ORIENT_CACHE_TTL_MS)
161
+ return null;
162
+ return record.context;
163
+ }
164
+ export function writeOrientCache(creds, workspaceId, context, options) {
165
+ const key = cacheKey(creds, workspaceId);
166
+ writeAtomic0600(cachePath(options?.baseDir, key), JSON.stringify({
167
+ key,
168
+ storedAt: new Date(options?.now ?? Date.now()).toISOString(),
169
+ context,
170
+ }));
171
+ }
172
+ export function clearOrientCache(baseDir) {
173
+ const dir = path.join(resolveStateDir(baseDir), 'cache');
174
+ if (!fs.existsSync(dir))
175
+ return;
176
+ for (const entry of fs.readdirSync(dir)) {
177
+ if (!entry.startsWith('orient-') || !entry.endsWith('.json'))
178
+ continue;
179
+ try {
180
+ fs.unlinkSync(path.join(dir, entry));
181
+ }
182
+ catch {
183
+ // Best-effort account-switch isolation.
184
+ }
185
+ }
186
+ }
187
+ export async function fetchSessionStartOrientation(input) {
188
+ const initial = resolveOrientWorkspaceId(input.creds);
189
+ if (initial.reason === 'login') {
190
+ return loginOrientationMessage();
191
+ }
192
+ const roots = (input.workspaceRoots?.length ? input.workspaceRoots : input.cwd ? [input.cwd] : [])
193
+ .filter((root, index, all) => Boolean(root) && all.indexOf(root) === index);
194
+ const projectResolutions = roots.map((root) => readProjectWorkspaceId(root));
195
+ if (projectResolutions.some((resolution) => resolution.kind === 'invalid')) {
196
+ return invalidProjectWorkspaceMessage();
197
+ }
198
+ const projectWorkspaceIds = projectResolutions
199
+ .filter((resolution) => resolution.kind === 'workspace')
200
+ .map((resolution) => resolution.workspaceId);
201
+ const hasUnboundRoot = roots.length === 0 || projectResolutions.some((resolution) => resolution.kind === 'none');
202
+ let fallbackWorkspaceId = initial.workspaceId;
203
+ if (hasUnboundRoot && !fallbackWorkspaceId) {
204
+ try {
205
+ const listed = await input.apiClient.request('/api/mcp/workspaces', { timeoutMs: 800, signal: input.signal });
206
+ const next = resolveOrientWorkspaceId(input.creds, listed.workspaces ?? []);
207
+ fallbackWorkspaceId = next.workspaceId;
208
+ }
209
+ catch {
210
+ fallbackWorkspaceId = null;
211
+ }
212
+ }
213
+ const workspaceIds = [...new Set([
214
+ ...projectWorkspaceIds,
215
+ ...(hasUnboundRoot && fallbackWorkspaceId ? [fallbackWorkspaceId] : []),
216
+ ])];
217
+ if (workspaceIds.length === 0)
218
+ return selectWorkspaceOrientationMessage();
219
+ const results = await Promise.allSettled(workspaceIds.map(async (workspaceId) => {
220
+ const payload = await input.apiClient.request(`/api/workspaces/${workspaceId}/orient`, { timeoutMs: 800, signal: input.signal });
221
+ return formatOrientAdditionalContext(payload);
222
+ }));
223
+ const contexts = results
224
+ .filter((result) => result.status === 'fulfilled')
225
+ .map((result) => result.value);
226
+ if (contexts.length === 0) {
227
+ throw new Error('No project workspace orientation request succeeded.');
228
+ }
229
+ if (hasUnboundRoot && !fallbackWorkspaceId) {
230
+ contexts.push('One or more workspace roots have no resolvable project/default workspace; no workspace was guessed for those roots.');
231
+ }
232
+ // Correctness first: pending proposals, due workflows, decisions, rules, and
233
+ // active-ref guidance must be fresh. The exported cache helpers remain only
234
+ // for a future stable-section cache; complete orientation responses are
235
+ // never read from or written to disk by the hook path.
236
+ const combined = contexts.join('\n\n---\n\n');
237
+ return combined.length > ORIENT_CONTEXT_MAX_CHARS
238
+ ? `${combined.slice(0, ORIENT_CONTEXT_MAX_CHARS - 1)}…`
239
+ : combined;
240
+ }
241
+ export async function safeSessionStartOrientation(input) {
242
+ if (!input.apiClient) {
243
+ return input.creds?.authType === 'oauth'
244
+ ? selectWorkspaceOrientationMessage()
245
+ : loginOrientationMessage();
246
+ }
247
+ try {
248
+ return await fetchSessionStartOrientation(input);
249
+ }
250
+ catch (error) {
251
+ logRuntimeEvent('warn', 'orient_fetch_failed', { error: error instanceof Error ? error.message : String(error) }, input.baseDir);
252
+ return 'BrainMCP orientation is temporarily unavailable. Continue locally and retry brain_workspace_overview when possible.';
253
+ }
254
+ }
255
+ //# sourceMappingURL=orient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orient.js","sourceRoot":"","sources":["../../src/runtime/orient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type QueueItemRecord } from '../lib/cli-contracts.js';
2
+ export declare function getQueueDir(baseDir?: string): string;
3
+ export declare function getQueueItemPath(digestId: string, baseDir?: string): string;
4
+ export declare function enqueueCaptureItem(item: Omit<QueueItemRecord, 'version' | 'createdAt' | 'updatedAt' | 'attempts' | 'status'>, baseDir?: string): QueueItemRecord;
5
+ export declare function listQueueItems(baseDir?: string): QueueItemRecord[];
6
+ export declare function updateQueueItem(digestId: string, updates: Partial<Pick<QueueItemRecord, 'status' | 'attempts' | 'nextRetryAt' | 'lastError' | 'deliveredAt' | 'deliveryLease'>>, baseDir?: string): QueueItemRecord | null;
7
+ export declare function removeQueueItem(digestId: string, baseDir?: string): boolean;
@@ -0,0 +1,80 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { QUEUE_SCHEMA_VERSION, validateQueueItemRecord, } from '../lib/cli-contracts.js';
4
+ import { ensureDirectory0700, writeAtomic0600, readSafeJson, assertNotSymlink, resolveStateDir, } from './storage.js';
5
+ export function getQueueDir(baseDir) {
6
+ const queueDir = path.join(resolveStateDir(baseDir), 'queue');
7
+ ensureDirectory0700(queueDir);
8
+ return queueDir;
9
+ }
10
+ export function getQueueItemPath(digestId, baseDir) {
11
+ const queueDir = getQueueDir(baseDir);
12
+ const safeId = digestId.replace(/[^a-zA-Z0-9_-]/g, '_');
13
+ return path.join(queueDir, `${safeId}.json`);
14
+ }
15
+ export function enqueueCaptureItem(item, baseDir) {
16
+ const now = new Date().toISOString();
17
+ const record = {
18
+ version: QUEUE_SCHEMA_VERSION,
19
+ digestId: item.digestId,
20
+ workspaceId: item.workspaceId,
21
+ captureTrigger: item.captureTrigger,
22
+ policyVersion: item.policyVersion,
23
+ digestText: item.digestText,
24
+ authorizationId: item.authorizationId,
25
+ consentRevision: item.consentRevision,
26
+ status: 'pending',
27
+ attempts: 0,
28
+ createdAt: now,
29
+ updatedAt: now,
30
+ };
31
+ const filePath = getQueueItemPath(record.digestId, baseDir);
32
+ writeAtomic0600(filePath, JSON.stringify(record, null, 2));
33
+ return record;
34
+ }
35
+ export function listQueueItems(baseDir) {
36
+ const queueDir = getQueueDir(baseDir);
37
+ const entries = fs.readdirSync(queueDir);
38
+ const items = [];
39
+ for (const entry of entries) {
40
+ if (!entry.endsWith('.json'))
41
+ continue;
42
+ const filePath = path.join(queueDir, entry);
43
+ try {
44
+ assertNotSymlink(filePath);
45
+ const item = readSafeJson(filePath, validateQueueItemRecord);
46
+ if (item) {
47
+ items.push(item);
48
+ }
49
+ }
50
+ catch {
51
+ // Corrupted items skipped in listing
52
+ }
53
+ }
54
+ // Sort by createdAt ascending
55
+ return items.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
56
+ }
57
+ export function updateQueueItem(digestId, updates, baseDir) {
58
+ const filePath = getQueueItemPath(digestId, baseDir);
59
+ const existing = readSafeJson(filePath, validateQueueItemRecord);
60
+ if (!existing) {
61
+ return null;
62
+ }
63
+ const updated = {
64
+ ...existing,
65
+ ...updates,
66
+ updatedAt: new Date().toISOString(),
67
+ };
68
+ writeAtomic0600(filePath, JSON.stringify(updated, null, 2));
69
+ return updated;
70
+ }
71
+ export function removeQueueItem(digestId, baseDir) {
72
+ const filePath = getQueueItemPath(digestId, baseDir);
73
+ if (fs.existsSync(filePath)) {
74
+ assertNotSymlink(filePath);
75
+ fs.unlinkSync(filePath);
76
+ return true;
77
+ }
78
+ return false;
79
+ }
80
+ //# sourceMappingURL=queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/runtime/queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export interface PruneOptions {
2
+ baseDir?: string;
3
+ maxQueueAgeMs?: number;
4
+ maxSessionAgeMs?: number;
5
+ maxLogSizeBytes?: number;
6
+ now?: number;
7
+ }
8
+ export interface PruneResult {
9
+ prunedQueueCount: number;
10
+ prunedSessionCount: number;
11
+ prunedLockCount: number;
12
+ logRotated: boolean;
13
+ }
14
+ export interface CapturePurgePreview {
15
+ queueItems: number;
16
+ sessionLedgers: number;
17
+ orientationCacheFiles: number;
18
+ }
19
+ export declare function previewCapturePurge(baseDir?: string): CapturePurgePreview;
20
+ /** Delete only BrainMCP-owned queue, session-ledger, and orientation-cache files. */
21
+ export declare function purgeCaptureLocalState(baseDir?: string): CapturePurgePreview;
22
+ /**
23
+ * Safely prunes expired queue items, old session ledgers, stale locks, and trims logs (AHI-058).
24
+ * Never touches active credentials or installed runtime files.
25
+ */
26
+ export declare function pruneLocalState(options?: PruneOptions): PruneResult;