brainhub-mcp 0.1.0

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 (156) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +84 -0
  3. package/dist/adapters/claude.d.ts +2 -0
  4. package/dist/adapters/claude.js +50 -0
  5. package/dist/adapters/claude.js.map +1 -0
  6. package/dist/adapters/codex.d.ts +2 -0
  7. package/dist/adapters/codex.js +52 -0
  8. package/dist/adapters/codex.js.map +1 -0
  9. package/dist/adapters/content.d.ts +6 -0
  10. package/dist/adapters/content.js +68 -0
  11. package/dist/adapters/content.js.map +1 -0
  12. package/dist/adapters/grok.d.ts +2 -0
  13. package/dist/adapters/grok.js +44 -0
  14. package/dist/adapters/grok.js.map +1 -0
  15. package/dist/adapters/index.d.ts +31 -0
  16. package/dist/adapters/index.js +111 -0
  17. package/dist/adapters/index.js.map +1 -0
  18. package/dist/adapters/jsonl.d.ts +6 -0
  19. package/dist/adapters/jsonl.js +26 -0
  20. package/dist/adapters/jsonl.js.map +1 -0
  21. package/dist/adapters/types.d.ts +10 -0
  22. package/dist/adapters/types.js +2 -0
  23. package/dist/adapters/types.js.map +1 -0
  24. package/dist/auth/account-status.d.ts +50 -0
  25. package/dist/auth/account-status.js +59 -0
  26. package/dist/auth/account-status.js.map +1 -0
  27. package/dist/auth/google-account.d.ts +21 -0
  28. package/dist/auth/google-account.js +45 -0
  29. package/dist/auth/google-account.js.map +1 -0
  30. package/dist/auth/google-oauth.d.ts +35 -0
  31. package/dist/auth/google-oauth.js +191 -0
  32. package/dist/auth/google-oauth.js.map +1 -0
  33. package/dist/auth/oauth-loopback.d.ts +10 -0
  34. package/dist/auth/oauth-loopback.js +81 -0
  35. package/dist/auth/oauth-loopback.js.map +1 -0
  36. package/dist/auth/official-oauth-client.d.ts +5 -0
  37. package/dist/auth/official-oauth-client.js +6 -0
  38. package/dist/auth/official-oauth-client.js.map +1 -0
  39. package/dist/auth/platform-secrets.d.ts +14 -0
  40. package/dist/auth/platform-secrets.js +81 -0
  41. package/dist/auth/platform-secrets.js.map +1 -0
  42. package/dist/auth/secret-store-factory.d.ts +11 -0
  43. package/dist/auth/secret-store-factory.js +37 -0
  44. package/dist/auth/secret-store-factory.js.map +1 -0
  45. package/dist/auth/secret-store.d.ts +13 -0
  46. package/dist/auth/secret-store.js +40 -0
  47. package/dist/auth/secret-store.js.map +1 -0
  48. package/dist/capture/images.d.ts +11 -0
  49. package/dist/capture/images.js +27 -0
  50. package/dist/capture/images.js.map +1 -0
  51. package/dist/capture/normalize.d.ts +11 -0
  52. package/dist/capture/normalize.js +43 -0
  53. package/dist/capture/normalize.js.map +1 -0
  54. package/dist/capture/redact.d.ts +10 -0
  55. package/dist/capture/redact.js +60 -0
  56. package/dist/capture/redact.js.map +1 -0
  57. package/dist/cli/index.d.ts +20 -0
  58. package/dist/cli/index.js +781 -0
  59. package/dist/cli/index.js.map +1 -0
  60. package/dist/clients/registry.d.ts +24 -0
  61. package/dist/clients/registry.js +105 -0
  62. package/dist/clients/registry.js.map +1 -0
  63. package/dist/domain/config-io.d.ts +15 -0
  64. package/dist/domain/config-io.js +168 -0
  65. package/dist/domain/config-io.js.map +1 -0
  66. package/dist/domain/config.d.ts +74 -0
  67. package/dist/domain/config.js +130 -0
  68. package/dist/domain/config.js.map +1 -0
  69. package/dist/domain/errors.d.ts +6 -0
  70. package/dist/domain/errors.js +11 -0
  71. package/dist/domain/errors.js.map +1 -0
  72. package/dist/domain/session.d.ts +62 -0
  73. package/dist/domain/session.js +47 -0
  74. package/dist/domain/session.js.map +1 -0
  75. package/dist/drive/drive-port.d.ts +51 -0
  76. package/dist/drive/drive-port.js +2 -0
  77. package/dist/drive/drive-port.js.map +1 -0
  78. package/dist/drive/google-drive.d.ts +28 -0
  79. package/dist/drive/google-drive.js +501 -0
  80. package/dist/drive/google-drive.js.map +1 -0
  81. package/dist/drive/memory-drive.d.ts +19 -0
  82. package/dist/drive/memory-drive.js +148 -0
  83. package/dist/drive/memory-drive.js.map +1 -0
  84. package/dist/drive/scoped-drive.d.ts +17 -0
  85. package/dist/drive/scoped-drive.js +115 -0
  86. package/dist/drive/scoped-drive.js.map +1 -0
  87. package/dist/mcp/server.d.ts +55 -0
  88. package/dist/mcp/server.js +133 -0
  89. package/dist/mcp/server.js.map +1 -0
  90. package/dist/portrait/obsidian.d.ts +7 -0
  91. package/dist/portrait/obsidian.js +16 -0
  92. package/dist/portrait/obsidian.js.map +1 -0
  93. package/dist/portrait/portrait-service.d.ts +12 -0
  94. package/dist/portrait/portrait-service.js +18 -0
  95. package/dist/portrait/portrait-service.js.map +1 -0
  96. package/dist/portrait/portrait-sync-service.d.ts +21 -0
  97. package/dist/portrait/portrait-sync-service.js +43 -0
  98. package/dist/portrait/portrait-sync-service.js.map +1 -0
  99. package/dist/runtime/command.d.ts +4 -0
  100. package/dist/runtime/command.js +2 -0
  101. package/dist/runtime/command.js.map +1 -0
  102. package/dist/runtime/container.d.ts +72 -0
  103. package/dist/runtime/container.js +361 -0
  104. package/dist/runtime/container.js.map +1 -0
  105. package/dist/scheduler/jobs.d.ts +2 -0
  106. package/dist/scheduler/jobs.js +7 -0
  107. package/dist/scheduler/jobs.js.map +1 -0
  108. package/dist/scheduler/launchd.d.ts +7 -0
  109. package/dist/scheduler/launchd.js +40 -0
  110. package/dist/scheduler/launchd.js.map +1 -0
  111. package/dist/scheduler/manager.d.ts +26 -0
  112. package/dist/scheduler/manager.js +113 -0
  113. package/dist/scheduler/manager.js.map +1 -0
  114. package/dist/search/chunk-text.d.ts +11 -0
  115. package/dist/search/chunk-text.js +40 -0
  116. package/dist/search/chunk-text.js.map +1 -0
  117. package/dist/search/e5-embedder.d.ts +19 -0
  118. package/dist/search/e5-embedder.js +71 -0
  119. package/dist/search/e5-embedder.js.map +1 -0
  120. package/dist/search/embedder.d.ts +8 -0
  121. package/dist/search/embedder.js +5 -0
  122. package/dist/search/embedder.js.map +1 -0
  123. package/dist/search/model-cache.d.ts +7 -0
  124. package/dist/search/model-cache.js +38 -0
  125. package/dist/search/model-cache.js.map +1 -0
  126. package/dist/search/search-service.d.ts +46 -0
  127. package/dist/search/search-service.js +319 -0
  128. package/dist/search/search-service.js.map +1 -0
  129. package/dist/setup/backfill-service.d.ts +33 -0
  130. package/dist/setup/backfill-service.js +47 -0
  131. package/dist/setup/backfill-service.js.map +1 -0
  132. package/dist/setup/setup-service.d.ts +65 -0
  133. package/dist/setup/setup-service.js +90 -0
  134. package/dist/setup/setup-service.js.map +1 -0
  135. package/dist/setup/uninstall-service.d.ts +34 -0
  136. package/dist/setup/uninstall-service.js +91 -0
  137. package/dist/setup/uninstall-service.js.map +1 -0
  138. package/dist/state/sqlite-store.d.ts +19 -0
  139. package/dist/state/sqlite-store.js +299 -0
  140. package/dist/state/sqlite-store.js.map +1 -0
  141. package/dist/state/store.d.ts +52 -0
  142. package/dist/state/store.js +2 -0
  143. package/dist/state/store.js.map +1 -0
  144. package/dist/status/status-service.d.ts +38 -0
  145. package/dist/status/status-service.js +93 -0
  146. package/dist/status/status-service.js.map +1 -0
  147. package/dist/update/update-check-service.d.ts +38 -0
  148. package/dist/update/update-check-service.js +105 -0
  149. package/dist/update/update-check-service.js.map +1 -0
  150. package/dist/upload/lock.d.ts +7 -0
  151. package/dist/upload/lock.js +68 -0
  152. package/dist/upload/lock.js.map +1 -0
  153. package/dist/upload/upload-service.d.ts +36 -0
  154. package/dist/upload/upload-service.js +360 -0
  155. package/dist/upload/upload-service.js.map +1 -0
  156. package/package.json +82 -0
@@ -0,0 +1,148 @@
1
+ import { createHash } from "node:crypto";
2
+ export class MemoryDrive {
3
+ #objects = new Map();
4
+ #corruptReads;
5
+ #counter = 0;
6
+ #changeCounter = 0;
7
+ #changes = [];
8
+ constructor(options = {}) {
9
+ this.#corruptReads = options.corruptReads ?? false;
10
+ }
11
+ #entry(object) {
12
+ return {
13
+ id: object.id,
14
+ path: object.path,
15
+ mimeType: object.mimeType,
16
+ size: object.size,
17
+ modifiedTime: object.modifiedTime,
18
+ etag: object.etag,
19
+ appProperties: { ...object.appProperties },
20
+ };
21
+ }
22
+ #create(input, id) {
23
+ const bytes = Buffer.from(input.bytes);
24
+ const objectId = id ?? `file-${String(++this.#counter).padStart(8, "0")}`;
25
+ return {
26
+ id: objectId,
27
+ path: input.path,
28
+ bytes,
29
+ mimeType: input.mimeType,
30
+ size: bytes.length,
31
+ modifiedTime: new Date().toISOString(),
32
+ etag: createHash("sha256")
33
+ .update(bytes)
34
+ .update(String(this.#counter))
35
+ .digest("hex"),
36
+ appProperties: { ...input.appProperties },
37
+ trashed: false,
38
+ };
39
+ }
40
+ #recordChange(id) {
41
+ this.#changeCounter += 1;
42
+ this.#changes.push({ sequence: this.#changeCounter, id });
43
+ }
44
+ async list(query) {
45
+ return [...this.#objects.values()]
46
+ .filter((object) => !object.trashed)
47
+ .filter((object) => !query.prefix || object.path.startsWith(query.prefix))
48
+ .filter((object) => !query.appProperty ||
49
+ object.appProperties[query.appProperty.key] ===
50
+ query.appProperty.value)
51
+ .filter((object) => !query.modifiedAfter || object.modifiedTime > query.modifiedAfter)
52
+ .sort((left, right) => left.path.localeCompare(right.path) ||
53
+ left.id.localeCompare(right.id))
54
+ .map((object) => this.#entry(object));
55
+ }
56
+ async put(input) {
57
+ const object = this.#create(input);
58
+ this.#objects.set(object.id, object);
59
+ this.#recordChange(object.id);
60
+ return this.#entry(object);
61
+ }
62
+ async upsert(input) {
63
+ const existing = [...this.#objects.values()].find((object) => !object.trashed && object.path === input.path);
64
+ if (input.ifMatch && existing?.etag !== input.ifMatch) {
65
+ const error = new Error("Drive precondition failed");
66
+ error.code = 412;
67
+ throw error;
68
+ }
69
+ const object = this.#create(input, existing?.id);
70
+ this.#objects.set(object.id, object);
71
+ this.#recordChange(object.id);
72
+ return this.#entry(object);
73
+ }
74
+ async changes(query) {
75
+ if (query.cursor === undefined) {
76
+ return {
77
+ entries: await this.list({ prefix: query.prefix }),
78
+ removedIds: [],
79
+ cursor: String(this.#changeCounter),
80
+ reset: true,
81
+ };
82
+ }
83
+ const sequence = Number(query.cursor);
84
+ if (!Number.isSafeInteger(sequence) || sequence < 0) {
85
+ throw new Error("Invalid Drive change cursor");
86
+ }
87
+ const changedIds = new Set(this.#changes
88
+ .filter((change) => change.sequence > sequence)
89
+ .map((change) => change.id));
90
+ const entries = [];
91
+ const removedIds = [];
92
+ for (const id of changedIds) {
93
+ const object = this.#objects.get(id);
94
+ if (object && !object.trashed && object.path.startsWith(query.prefix)) {
95
+ entries.push(this.#entry(object));
96
+ }
97
+ else {
98
+ removedIds.push(id);
99
+ }
100
+ }
101
+ entries.sort((left, right) => left.path.localeCompare(right.path));
102
+ removedIds.sort();
103
+ return {
104
+ entries,
105
+ removedIds,
106
+ cursor: String(this.#changeCounter),
107
+ reset: false,
108
+ };
109
+ }
110
+ async read(id) {
111
+ const object = this.#objects.get(id);
112
+ if (!object || object.trashed)
113
+ throw new Error(`Drive object not found: ${id}`);
114
+ const bytes = this.#corruptReads
115
+ ? Buffer.concat([object.bytes, Buffer.from("corrupt")])
116
+ : Buffer.from(object.bytes);
117
+ return { ...this.#entry(object), bytes };
118
+ }
119
+ async readPath(path) {
120
+ const object = [...this.#objects.values()]
121
+ .filter((candidate) => !candidate.trashed && candidate.path === path)
122
+ .sort((left, right) => right.id.localeCompare(left.id))[0];
123
+ return object ? this.read(object.id) : null;
124
+ }
125
+ async move(id, path) {
126
+ const object = this.#objects.get(id);
127
+ if (!object || object.trashed)
128
+ throw new Error(`Drive object not found: ${id}`);
129
+ object.path = path;
130
+ object.modifiedTime = new Date().toISOString();
131
+ this.#recordChange(object.id);
132
+ return this.#entry(object);
133
+ }
134
+ async trash(id) {
135
+ const object = this.#objects.get(id);
136
+ if (object) {
137
+ object.trashed = true;
138
+ this.#recordChange(object.id);
139
+ }
140
+ }
141
+ async quota() {
142
+ const usedBytes = [...this.#objects.values()]
143
+ .filter((object) => !object.trashed)
144
+ .reduce((sum, object) => sum + object.size, 0);
145
+ return { usedBytes, totalBytes: 15 * 1024 ** 3 };
146
+ }
147
+ }
148
+ //# sourceMappingURL=memory-drive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-drive.js","sourceRoot":"","sources":["../../src/drive/memory-drive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { DriveEntry, DriveChanges, DriveListQuery, DriveObject, DrivePort, DrivePutInput, DriveQuota } from "./drive-port.js";
2
+ export declare class InboxScopedDrive implements DrivePort {
3
+ #private;
4
+ constructor(drive: DrivePort);
5
+ list(query: DriveListQuery): Promise<DriveEntry[]>;
6
+ changes(query: {
7
+ prefix: string;
8
+ cursor?: string;
9
+ }): Promise<DriveChanges>;
10
+ put(input: DrivePutInput): Promise<DriveEntry>;
11
+ upsert(input: DrivePutInput): Promise<DriveEntry>;
12
+ read(id: string): Promise<DriveObject>;
13
+ readPath(path: string): Promise<DriveObject | null>;
14
+ move(id: string, path: string): Promise<DriveEntry>;
15
+ trash(id: string): Promise<void>;
16
+ quota(): Promise<DriveQuota>;
17
+ }
@@ -0,0 +1,115 @@
1
+ import { posix } from "node:path";
2
+ import { BrainHubError } from "../domain/errors.js";
3
+ const inboxPrefix = "inbox/";
4
+ function inboxPath(path) {
5
+ const normalized = posix.normalize(path);
6
+ if (path.includes("\\") ||
7
+ normalized.startsWith("/") ||
8
+ !normalized.startsWith(inboxPrefix)) {
9
+ throw new BrainHubError("INVALID_INPUT", "Session upload is restricted to the Drive inbox");
10
+ }
11
+ return normalized;
12
+ }
13
+ export class InboxScopedDrive {
14
+ #drive;
15
+ #knownIds = new Set();
16
+ constructor(drive) {
17
+ this.#drive = drive;
18
+ }
19
+ #register(entry) {
20
+ try {
21
+ inboxPath(entry.path);
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ this.#knownIds.add(entry.id);
27
+ return entry;
28
+ }
29
+ #requireKnown(id) {
30
+ if (!this.#knownIds.has(id)) {
31
+ throw new BrainHubError("INVALID_INPUT", "Drive object is outside the session upload inbox");
32
+ }
33
+ }
34
+ async list(query) {
35
+ const prefix = query.prefix ? inboxPath(query.prefix) : inboxPrefix;
36
+ const entries = await this.#drive.list({ ...query, prefix });
37
+ return entries.flatMap((entry) => {
38
+ const registered = this.#register(entry);
39
+ return registered ? [registered] : [];
40
+ });
41
+ }
42
+ async changes(query) {
43
+ const prefix = query.prefix ? inboxPath(query.prefix) : inboxPrefix;
44
+ const changes = await this.#drive.changes({
45
+ prefix,
46
+ ...(query.cursor ? { cursor: query.cursor } : {}),
47
+ });
48
+ const entries = changes.entries.flatMap((entry) => {
49
+ const registered = this.#register(entry);
50
+ return registered ? [registered] : [];
51
+ });
52
+ for (const id of changes.removedIds)
53
+ this.#knownIds.delete(id);
54
+ return { ...changes, entries };
55
+ }
56
+ async put(input) {
57
+ const entry = await this.#drive.put({
58
+ ...input,
59
+ path: inboxPath(input.path),
60
+ });
61
+ const registered = this.#register(entry);
62
+ if (!registered) {
63
+ throw new BrainHubError("INVALID_INPUT", "Drive returned an object outside inbox");
64
+ }
65
+ return registered;
66
+ }
67
+ async upsert(input) {
68
+ const entry = await this.#drive.upsert({
69
+ ...input,
70
+ path: inboxPath(input.path),
71
+ });
72
+ const registered = this.#register(entry);
73
+ if (!registered) {
74
+ throw new BrainHubError("INVALID_INPUT", "Drive returned an object outside inbox");
75
+ }
76
+ return registered;
77
+ }
78
+ async read(id) {
79
+ this.#requireKnown(id);
80
+ const object = await this.#drive.read(id);
81
+ const registered = this.#register(object);
82
+ if (!registered) {
83
+ throw new BrainHubError("INVALID_INPUT", "Drive returned an object outside inbox");
84
+ }
85
+ return registered;
86
+ }
87
+ async readPath(path) {
88
+ const object = await this.#drive.readPath(inboxPath(path));
89
+ if (!object)
90
+ return null;
91
+ const registered = this.#register(object);
92
+ if (!registered) {
93
+ throw new BrainHubError("INVALID_INPUT", "Drive returned an object outside inbox");
94
+ }
95
+ return registered;
96
+ }
97
+ async move(id, path) {
98
+ this.#requireKnown(id);
99
+ const entry = await this.#drive.move(id, inboxPath(path));
100
+ const registered = this.#register(entry);
101
+ if (!registered) {
102
+ throw new BrainHubError("INVALID_INPUT", "Drive returned an object outside inbox");
103
+ }
104
+ return registered;
105
+ }
106
+ async trash(id) {
107
+ this.#requireKnown(id);
108
+ await this.#drive.trash(id);
109
+ this.#knownIds.delete(id);
110
+ }
111
+ quota() {
112
+ return this.#drive.quota();
113
+ }
114
+ }
115
+ //# sourceMappingURL=scoped-drive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoped-drive.js","sourceRoot":"","sources":["../../src/drive/scoped-drive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { SessionSource } from "../domain/session.js";
3
+ interface RuntimeServices {
4
+ uploadSessions(input: {
5
+ sources?: SessionSource[];
6
+ backfill?: boolean;
7
+ includeSubagents?: boolean;
8
+ dryRun?: boolean;
9
+ }): Promise<object>;
10
+ searchSessions(input: {
11
+ query: string;
12
+ from?: string;
13
+ to?: string;
14
+ sources?: string[];
15
+ limit?: number;
16
+ }): Promise<object>;
17
+ getSession(input: {
18
+ source: SessionSource;
19
+ conversationId: string;
20
+ }): Promise<object>;
21
+ getPortrait(): Promise<object>;
22
+ hubStatus(): Promise<object>;
23
+ }
24
+ type ToolResult = {
25
+ content: Array<{
26
+ type: "text";
27
+ text: string;
28
+ }>;
29
+ structuredContent: Record<string, unknown>;
30
+ isError?: boolean;
31
+ };
32
+ export declare function createToolHandlers(services: RuntimeServices): {
33
+ upload_sessions: (input: {
34
+ sources?: SessionSource[] | undefined;
35
+ backfill?: boolean | undefined;
36
+ include_subagents?: boolean | undefined;
37
+ dry_run?: boolean | undefined;
38
+ }) => Promise<ToolResult>;
39
+ search_sessions: (input: {
40
+ query: string;
41
+ from?: string | undefined;
42
+ to?: string | undefined;
43
+ sources?: string[] | undefined;
44
+ limit?: number | undefined;
45
+ }) => Promise<ToolResult>;
46
+ get_portrait: () => Promise<ToolResult>;
47
+ get_session: (input: {
48
+ source: SessionSource;
49
+ conversation_id: string;
50
+ }) => Promise<ToolResult>;
51
+ hub_status: () => Promise<ToolResult>;
52
+ };
53
+ export declare function createMcpServer(services: RuntimeServices): McpServer;
54
+ export declare function serveMcp(services: RuntimeServices): Promise<void>;
55
+ export {};
@@ -0,0 +1,133 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { z } from "zod";
4
+ function success(output, text) {
5
+ return {
6
+ content: [{ type: "text", text }],
7
+ structuredContent: output,
8
+ };
9
+ }
10
+ function failure(error) {
11
+ const candidate = error;
12
+ const code = typeof candidate.code === "string" ? candidate.code : "INTERNAL_ERROR";
13
+ const message = typeof candidate.message === "string"
14
+ ? candidate.message
15
+ : "BrainHub operation failed";
16
+ return {
17
+ content: [{ type: "text", text: `${code}: ${message}` }],
18
+ structuredContent: { error: { code, message } },
19
+ isError: true,
20
+ };
21
+ }
22
+ export function createToolHandlers(services) {
23
+ return {
24
+ upload_sessions: async (input) => {
25
+ try {
26
+ const output = await services.uploadSessions({
27
+ ...(input.sources ? { sources: input.sources } : {}),
28
+ ...(input.backfill !== undefined ? { backfill: input.backfill } : {}),
29
+ ...(input.include_subagents !== undefined
30
+ ? { includeSubagents: input.include_subagents }
31
+ : {}),
32
+ ...(input.dry_run !== undefined ? { dryRun: input.dry_run } : {}),
33
+ });
34
+ const scanned = output.scanned ?? 0;
35
+ const uploaded = output.uploaded ?? 0;
36
+ return success(output, `BrainHub 扫描 ${scanned} 个会话,上传 ${uploaded} 个。`);
37
+ }
38
+ catch (error) {
39
+ return failure(error);
40
+ }
41
+ },
42
+ search_sessions: async (input) => {
43
+ try {
44
+ const output = await services.searchSessions({
45
+ query: input.query,
46
+ ...(input.from ? { from: input.from } : {}),
47
+ ...(input.to ? { to: input.to } : {}),
48
+ ...(input.sources ? { sources: input.sources } : {}),
49
+ ...(input.limit !== undefined ? { limit: input.limit } : {}),
50
+ });
51
+ return success(output, JSON.stringify(output, null, 2));
52
+ }
53
+ catch (error) {
54
+ return failure(error);
55
+ }
56
+ },
57
+ get_portrait: async () => {
58
+ try {
59
+ const output = await services.getPortrait();
60
+ return success(output, output.portrait ?? "画像不可用");
61
+ }
62
+ catch (error) {
63
+ return failure(error);
64
+ }
65
+ },
66
+ get_session: async (input) => {
67
+ try {
68
+ const output = await services.getSession({
69
+ source: input.source,
70
+ conversationId: input.conversation_id,
71
+ });
72
+ return success(output, output.content ?? "会话不可用");
73
+ }
74
+ catch (error) {
75
+ return failure(error);
76
+ }
77
+ },
78
+ hub_status: async () => {
79
+ try {
80
+ const output = await services.hubStatus();
81
+ return success(output, JSON.stringify(output, null, 2));
82
+ }
83
+ catch (error) {
84
+ return failure(error);
85
+ }
86
+ },
87
+ };
88
+ }
89
+ export function createMcpServer(services) {
90
+ const server = new McpServer({ name: "brainhub-mcp", version: "0.1.0" });
91
+ const handlers = createToolHandlers(services);
92
+ const source = z.enum(["claude-code", "codex", "grok-build"]);
93
+ server.registerTool("upload_sessions", {
94
+ description: "扫描、脱敏并增量上传本机 AI CLI 会话到 BrainHub",
95
+ inputSchema: {
96
+ sources: z.array(source).optional(),
97
+ backfill: z.boolean().optional(),
98
+ include_subagents: z.boolean().optional(),
99
+ dry_run: z.boolean().optional(),
100
+ },
101
+ }, handlers.upload_sessions);
102
+ server.registerTool("search_sessions", {
103
+ description: "搜索 BrainHub inbox 中的 AI CLI 会话",
104
+ inputSchema: {
105
+ query: z.string().min(1),
106
+ from: z.string().optional(),
107
+ to: z.string().optional(),
108
+ sources: z.array(z.string()).optional(),
109
+ limit: z.number().int().min(1).max(50).optional(),
110
+ },
111
+ }, handlers.search_sessions);
112
+ server.registerTool("get_portrait", {
113
+ description: "读取 My Drive 根目录下完整的 Digital_Twin_Profile.md",
114
+ inputSchema: {},
115
+ }, handlers.get_portrait);
116
+ server.registerTool("get_session", {
117
+ description: "根据搜索返回的来源和会话标识读取 inbox 中的完整会话",
118
+ inputSchema: {
119
+ source,
120
+ conversation_id: z.string().min(1),
121
+ },
122
+ }, handlers.get_session);
123
+ server.registerTool("hub_status", {
124
+ description: "读取 BrainHub 账号、上传、搜索索引和定时任务状态",
125
+ inputSchema: {},
126
+ }, handlers.hub_status);
127
+ return server;
128
+ }
129
+ export async function serveMcp(services) {
130
+ const server = createMcpServer(services);
131
+ await server.connect(new StdioServerTransport());
132
+ }
133
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface PublishDiscoveryOptions {
2
+ platform: NodeJS.Platform;
3
+ homeDir: string;
4
+ fallbackPath: string;
5
+ xdgConfigHome?: string;
6
+ }
7
+ export declare function discoverPublishDirectory(options: PublishDiscoveryOptions): Promise<string | null>;
@@ -0,0 +1,16 @@
1
+ import { constants } from "node:fs";
2
+ import { access, mkdir } from "node:fs/promises";
3
+ async function ensureWritable(path) {
4
+ try {
5
+ await mkdir(path, { recursive: true });
6
+ await access(path, constants.W_OK);
7
+ return path;
8
+ }
9
+ catch {
10
+ return null;
11
+ }
12
+ }
13
+ export async function discoverPublishDirectory(options) {
14
+ return options.fallbackPath ? ensureWritable(options.fallbackPath) : null;
15
+ }
16
+ //# sourceMappingURL=obsidian.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"obsidian.js","sourceRoot":"","sources":["../../src/portrait/obsidian.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AASjD,KAAK,UAAU,cAAc,CAAC,IAAY;IACxC,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,MAAM,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAgC;IAEhC,OAAO,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5E,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { DrivePort } from "../drive/drive-port.js";
2
+ export declare const DIGITAL_TWIN_PROFILE_PATH = "Digital_Twin_Profile.md";
3
+ export declare class PortraitService {
4
+ #private;
5
+ constructor(options: {
6
+ drive: DrivePort;
7
+ path?: string;
8
+ });
9
+ getPortrait(): Promise<{
10
+ portrait: string;
11
+ }>;
12
+ }
@@ -0,0 +1,18 @@
1
+ import { BrainHubError } from "../domain/errors.js";
2
+ export const DIGITAL_TWIN_PROFILE_PATH = "Digital_Twin_Profile.md";
3
+ export class PortraitService {
4
+ #drive;
5
+ #path;
6
+ constructor(options) {
7
+ this.#drive = options.drive;
8
+ this.#path = options.path ?? DIGITAL_TWIN_PROFILE_PATH;
9
+ }
10
+ async getPortrait() {
11
+ const object = await this.#drive.readPath(this.#path);
12
+ if (!object) {
13
+ throw new BrainHubError("SOURCE_UNAVAILABLE", `Drive portrait source ${this.#path} is not available`);
14
+ }
15
+ return { portrait: object.bytes.toString("utf8") };
16
+ }
17
+ }
18
+ //# sourceMappingURL=portrait-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portrait-service.js","sourceRoot":"","sources":["../../src/portrait/portrait-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,MAAM,CAAC,MAAM,yBAAyB,GAAG,yBAAyB,CAAC;AAEnE,MAAM,OAAO,eAAe;IACjB,MAAM,CAAY;IAClB,KAAK,CAAS;IAEvB,YAAY,OAA4C;QACtD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,IAAI,yBAAyB,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,aAAa,CACrB,oBAAoB,EACpB,yBAAyB,IAAI,CAAC,KAAK,mBAAmB,CACvD,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;IACrD,CAAC;CACF"}
@@ -0,0 +1,21 @@
1
+ import type { DrivePort } from "../drive/drive-port.js";
2
+ import { type PublishDiscoveryOptions } from "./obsidian.js";
3
+ export interface PortraitSyncOutput {
4
+ synced: boolean;
5
+ path?: string;
6
+ warnings: Array<{
7
+ code: string;
8
+ message: string;
9
+ }>;
10
+ }
11
+ export declare class PortraitSyncService {
12
+ #private;
13
+ constructor(options: {
14
+ portraitSource: {
15
+ drive: DrivePort;
16
+ path: string;
17
+ };
18
+ publish: PublishDiscoveryOptions;
19
+ });
20
+ sync(): Promise<PortraitSyncOutput>;
21
+ }
@@ -0,0 +1,43 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { rename, unlink, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { BrainHubError } from "../domain/errors.js";
5
+ import { discoverPublishDirectory, } from "./obsidian.js";
6
+ export class PortraitSyncService {
7
+ #portraitSource;
8
+ #publish;
9
+ constructor(options) {
10
+ this.#portraitSource = options.portraitSource;
11
+ this.#publish = options.publish;
12
+ }
13
+ async sync() {
14
+ const portrait = await this.#portraitSource.drive.readPath(this.#portraitSource.path);
15
+ if (!portrait) {
16
+ throw new BrainHubError("SOURCE_UNAVAILABLE", `Drive portrait source ${this.#portraitSource.path} is not available`);
17
+ }
18
+ const directory = await discoverPublishDirectory(this.#publish);
19
+ if (!directory) {
20
+ return {
21
+ synced: false,
22
+ warnings: [
23
+ {
24
+ code: "PUBLISH_PATH_REQUIRED",
25
+ message: "No writable Obsidian BrainHub directory was found",
26
+ },
27
+ ],
28
+ };
29
+ }
30
+ const path = join(directory, "portrait.md");
31
+ const temporary = join(directory, `.portrait.${randomUUID()}.tmp`);
32
+ try {
33
+ await writeFile(temporary, portrait.bytes, { mode: 0o600 });
34
+ await rename(temporary, path);
35
+ }
36
+ catch (error) {
37
+ await unlink(temporary).catch(() => undefined);
38
+ throw error;
39
+ }
40
+ return { synced: true, path, warnings: [] };
41
+ }
42
+ }
43
+ //# sourceMappingURL=portrait-sync-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portrait-sync-service.js","sourceRoot":"","sources":["../../src/portrait/portrait-sync-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EACL,wBAAwB,GAEzB,MAAM,eAAe,CAAC;AAQvB,MAAM,OAAO,mBAAmB;IACrB,eAAe,CAAqC;IACpD,QAAQ,CAA0B;IAE3C,YAAY,OAGX;QACC,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;QAC9C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,QAAQ,CACxD,IAAI,CAAC,eAAe,CAAC,IAAI,CAC1B,CAAC;QACF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,aAAa,CACrB,oBAAoB,EACpB,yBAAyB,IAAI,CAAC,eAAe,CAAC,IAAI,mBAAmB,CACtE,CAAC;QACJ,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChE,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO;gBACL,MAAM,EAAE,KAAK;gBACb,QAAQ,EAAE;oBACR;wBACE,IAAI,EAAE,uBAAuB;wBAC7B,OAAO,EAAE,mDAAmD;qBAC7D;iBACF;aACF,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,UAAU,EAAE,MAAM,CAAC,CAAC;QACnE,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,SAAS,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAC5D,MAAM,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC/C,MAAM,KAAK,CAAC;QACd,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC9C,CAAC;CACF"}
@@ -0,0 +1,4 @@
1
+ export interface CommandSpec {
2
+ command: string;
3
+ args: string[];
4
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/runtime/command.ts"],"names":[],"mappings":""}