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.
- package/LICENSE +201 -0
- package/README.md +84 -0
- package/dist/adapters/claude.d.ts +2 -0
- package/dist/adapters/claude.js +50 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/codex.d.ts +2 -0
- package/dist/adapters/codex.js +52 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/content.d.ts +6 -0
- package/dist/adapters/content.js +68 -0
- package/dist/adapters/content.js.map +1 -0
- package/dist/adapters/grok.d.ts +2 -0
- package/dist/adapters/grok.js +44 -0
- package/dist/adapters/grok.js.map +1 -0
- package/dist/adapters/index.d.ts +31 -0
- package/dist/adapters/index.js +111 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/jsonl.d.ts +6 -0
- package/dist/adapters/jsonl.js +26 -0
- package/dist/adapters/jsonl.js.map +1 -0
- package/dist/adapters/types.d.ts +10 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/auth/account-status.d.ts +50 -0
- package/dist/auth/account-status.js +59 -0
- package/dist/auth/account-status.js.map +1 -0
- package/dist/auth/google-account.d.ts +21 -0
- package/dist/auth/google-account.js +45 -0
- package/dist/auth/google-account.js.map +1 -0
- package/dist/auth/google-oauth.d.ts +35 -0
- package/dist/auth/google-oauth.js +191 -0
- package/dist/auth/google-oauth.js.map +1 -0
- package/dist/auth/oauth-loopback.d.ts +10 -0
- package/dist/auth/oauth-loopback.js +81 -0
- package/dist/auth/oauth-loopback.js.map +1 -0
- package/dist/auth/official-oauth-client.d.ts +5 -0
- package/dist/auth/official-oauth-client.js +6 -0
- package/dist/auth/official-oauth-client.js.map +1 -0
- package/dist/auth/platform-secrets.d.ts +14 -0
- package/dist/auth/platform-secrets.js +81 -0
- package/dist/auth/platform-secrets.js.map +1 -0
- package/dist/auth/secret-store-factory.d.ts +11 -0
- package/dist/auth/secret-store-factory.js +37 -0
- package/dist/auth/secret-store-factory.js.map +1 -0
- package/dist/auth/secret-store.d.ts +13 -0
- package/dist/auth/secret-store.js +40 -0
- package/dist/auth/secret-store.js.map +1 -0
- package/dist/capture/images.d.ts +11 -0
- package/dist/capture/images.js +27 -0
- package/dist/capture/images.js.map +1 -0
- package/dist/capture/normalize.d.ts +11 -0
- package/dist/capture/normalize.js +43 -0
- package/dist/capture/normalize.js.map +1 -0
- package/dist/capture/redact.d.ts +10 -0
- package/dist/capture/redact.js +60 -0
- package/dist/capture/redact.js.map +1 -0
- package/dist/cli/index.d.ts +20 -0
- package/dist/cli/index.js +781 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/clients/registry.d.ts +24 -0
- package/dist/clients/registry.js +105 -0
- package/dist/clients/registry.js.map +1 -0
- package/dist/domain/config-io.d.ts +15 -0
- package/dist/domain/config-io.js +168 -0
- package/dist/domain/config-io.js.map +1 -0
- package/dist/domain/config.d.ts +74 -0
- package/dist/domain/config.js +130 -0
- package/dist/domain/config.js.map +1 -0
- package/dist/domain/errors.d.ts +6 -0
- package/dist/domain/errors.js +11 -0
- package/dist/domain/errors.js.map +1 -0
- package/dist/domain/session.d.ts +62 -0
- package/dist/domain/session.js +47 -0
- package/dist/domain/session.js.map +1 -0
- package/dist/drive/drive-port.d.ts +51 -0
- package/dist/drive/drive-port.js +2 -0
- package/dist/drive/drive-port.js.map +1 -0
- package/dist/drive/google-drive.d.ts +28 -0
- package/dist/drive/google-drive.js +501 -0
- package/dist/drive/google-drive.js.map +1 -0
- package/dist/drive/memory-drive.d.ts +19 -0
- package/dist/drive/memory-drive.js +148 -0
- package/dist/drive/memory-drive.js.map +1 -0
- package/dist/drive/scoped-drive.d.ts +17 -0
- package/dist/drive/scoped-drive.js +115 -0
- package/dist/drive/scoped-drive.js.map +1 -0
- package/dist/mcp/server.d.ts +55 -0
- package/dist/mcp/server.js +133 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/portrait/obsidian.d.ts +7 -0
- package/dist/portrait/obsidian.js +16 -0
- package/dist/portrait/obsidian.js.map +1 -0
- package/dist/portrait/portrait-service.d.ts +12 -0
- package/dist/portrait/portrait-service.js +18 -0
- package/dist/portrait/portrait-service.js.map +1 -0
- package/dist/portrait/portrait-sync-service.d.ts +21 -0
- package/dist/portrait/portrait-sync-service.js +43 -0
- package/dist/portrait/portrait-sync-service.js.map +1 -0
- package/dist/runtime/command.d.ts +4 -0
- package/dist/runtime/command.js +2 -0
- package/dist/runtime/command.js.map +1 -0
- package/dist/runtime/container.d.ts +72 -0
- package/dist/runtime/container.js +361 -0
- package/dist/runtime/container.js.map +1 -0
- package/dist/scheduler/jobs.d.ts +2 -0
- package/dist/scheduler/jobs.js +7 -0
- package/dist/scheduler/jobs.js.map +1 -0
- package/dist/scheduler/launchd.d.ts +7 -0
- package/dist/scheduler/launchd.js +40 -0
- package/dist/scheduler/launchd.js.map +1 -0
- package/dist/scheduler/manager.d.ts +26 -0
- package/dist/scheduler/manager.js +113 -0
- package/dist/scheduler/manager.js.map +1 -0
- package/dist/search/chunk-text.d.ts +11 -0
- package/dist/search/chunk-text.js +40 -0
- package/dist/search/chunk-text.js.map +1 -0
- package/dist/search/e5-embedder.d.ts +19 -0
- package/dist/search/e5-embedder.js +71 -0
- package/dist/search/e5-embedder.js.map +1 -0
- package/dist/search/embedder.d.ts +8 -0
- package/dist/search/embedder.js +5 -0
- package/dist/search/embedder.js.map +1 -0
- package/dist/search/model-cache.d.ts +7 -0
- package/dist/search/model-cache.js +38 -0
- package/dist/search/model-cache.js.map +1 -0
- package/dist/search/search-service.d.ts +46 -0
- package/dist/search/search-service.js +319 -0
- package/dist/search/search-service.js.map +1 -0
- package/dist/setup/backfill-service.d.ts +33 -0
- package/dist/setup/backfill-service.js +47 -0
- package/dist/setup/backfill-service.js.map +1 -0
- package/dist/setup/setup-service.d.ts +65 -0
- package/dist/setup/setup-service.js +90 -0
- package/dist/setup/setup-service.js.map +1 -0
- package/dist/setup/uninstall-service.d.ts +34 -0
- package/dist/setup/uninstall-service.js +91 -0
- package/dist/setup/uninstall-service.js.map +1 -0
- package/dist/state/sqlite-store.d.ts +19 -0
- package/dist/state/sqlite-store.js +299 -0
- package/dist/state/sqlite-store.js.map +1 -0
- package/dist/state/store.d.ts +52 -0
- package/dist/state/store.js +2 -0
- package/dist/state/store.js.map +1 -0
- package/dist/status/status-service.d.ts +38 -0
- package/dist/status/status-service.js +93 -0
- package/dist/status/status-service.js.map +1 -0
- package/dist/update/update-check-service.d.ts +38 -0
- package/dist/update/update-check-service.js +105 -0
- package/dist/update/update-check-service.js.map +1 -0
- package/dist/upload/lock.d.ts +7 -0
- package/dist/upload/lock.js +68 -0
- package/dist/upload/lock.js.map +1 -0
- package/dist/upload/upload-service.d.ts +36 -0
- package/dist/upload/upload-service.js +360 -0
- package/dist/upload/upload-service.js.map +1 -0
- 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":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAgBzC,MAAM,OAAO,WAAW;IACb,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAC;IAC3C,aAAa,CAAU;IAChC,QAAQ,GAAG,CAAC,CAAC;IACb,cAAc,GAAG,CAAC,CAAC;IACV,QAAQ,GAA4C,EAAE,CAAC;IAEhE,YAAY,UAAsC,EAAE;QAClD,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,YAAY,IAAI,KAAK,CAAC;IACrD,CAAC;IAED,MAAM,CAAC,MAAoB;QACzB,OAAO;YACL,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,aAAa,EAAE,EAAE,GAAG,MAAM,CAAC,aAAa,EAAE;SAC3C,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,KAAoB,EAAE,EAAW;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,EAAE,IAAI,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QAC1E,OAAO;YACL,EAAE,EAAE,QAAQ;YACZ,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK;YACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,IAAI,EAAE,KAAK,CAAC,MAAM;YAClB,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACtC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC;iBACvB,MAAM,CAAC,KAAK,CAAC;iBACb,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;iBAC7B,MAAM,CAAC,KAAK,CAAC;YAChB,aAAa,EAAE,EAAE,GAAG,KAAK,CAAC,aAAa,EAAE;YACzC,OAAO,EAAE,KAAK;SACf,CAAC;IACJ,CAAC;IAED,aAAa,CAAC,EAAU;QACtB,IAAI,CAAC,cAAc,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAqB;QAC9B,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;aAC/B,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;aACnC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;aACzE,MAAM,CACL,CAAC,MAAM,EAAE,EAAE,CACT,CAAC,KAAK,CAAC,WAAW;YAClB,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC;gBACzC,KAAK,CAAC,WAAW,CAAC,KAAK,CAC5B;aACA,MAAM,CACL,CAAC,MAAM,EAAE,EAAE,CACT,CAAC,KAAK,CAAC,aAAa,IAAI,MAAM,CAAC,YAAY,GAAG,KAAK,CAAC,aAAa,CACpE;aACA,IAAI,CACH,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CACd,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC;YACnC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAClC;aACA,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAoB;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAoB;QAC/B,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAC/C,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAC1D,CAAC;QACF,IAAI,KAAK,CAAC,OAAO,IAAI,QAAQ,EAAE,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;YACtD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,2BAA2B,CAElD,CAAC;YACF,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC;YACjB,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QACjD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,KAGb;QACC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC/B,OAAO;gBACL,OAAO,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;gBAClD,UAAU,EAAE,EAAE;gBACd,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC;gBACnC,KAAK,EAAE,IAAI;aACZ,CAAC;QACJ,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACjD,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,IAAI,CAAC,QAAQ;aACV,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;aAC9C,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAC9B,CAAC;QACF,MAAM,OAAO,GAAiB,EAAE,CAAC;QACjC,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;YAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACrC,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACnE,UAAU,CAAC,IAAI,EAAE,CAAC;QAClB,OAAO;YACL,OAAO;YACP,UAAU;YACV,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC;YACnC,KAAK,EAAE,KAAK;SACb,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAU;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO;YAC3B,MAAM,IAAI,KAAK,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa;YAC9B,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;YACvD,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9B,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAY;QACzB,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;aACvC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC;aACpE,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7D,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAU,EAAE,IAAY;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO;YAC3B,MAAM,IAAI,KAAK,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC;QACnD,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,MAAM,CAAC,YAAY,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC/C,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,EAAU;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;YACtB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;aAC1C,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;aACnC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACjD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC;IACnD,CAAC;CACF"}
|
|
@@ -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,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 @@
|
|
|
1
|
+
{"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/runtime/command.ts"],"names":[],"mappings":""}
|