bulkhead-runtime 0.1.0 → 2026.4.5-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +344 -262
- package/dist/cli.js +5 -1
- package/dist/cli.js.map +1 -1
- package/dist/config/index.d.ts +28 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +9 -6
- package/dist/config/index.js.map +1 -1
- package/dist/credentials/store.d.ts.map +1 -1
- package/dist/credentials/store.js +39 -15
- package/dist/credentials/store.js.map +1 -1
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -1
- package/dist/index.js.map +1 -1
- package/dist/infra/warning-filter.js +1 -1
- package/dist/infra/warning-filter.js.map +1 -1
- package/dist/logging/subsystem.d.ts +15 -1
- package/dist/logging/subsystem.d.ts.map +1 -1
- package/dist/logging/subsystem.js +310 -45
- package/dist/logging/subsystem.js.map +1 -1
- package/dist/memory/embedding-batch.d.ts +38 -0
- package/dist/memory/embedding-batch.d.ts.map +1 -0
- package/dist/memory/embedding-batch.js +253 -0
- package/dist/memory/embedding-batch.js.map +1 -0
- package/dist/memory/embedding-cache.d.ts +16 -0
- package/dist/memory/embedding-cache.d.ts.map +1 -0
- package/dist/memory/embedding-cache.js +113 -0
- package/dist/memory/embedding-cache.js.map +1 -0
- package/dist/memory/embeddings-debug.js +1 -1
- package/dist/memory/embeddings.d.ts +1 -0
- package/dist/memory/embeddings.d.ts.map +1 -1
- package/dist/memory/embeddings.js +115 -92
- package/dist/memory/embeddings.js.map +1 -1
- package/dist/memory/file-indexer.d.ts +26 -0
- package/dist/memory/file-indexer.d.ts.map +1 -0
- package/dist/memory/file-indexer.js +258 -0
- package/dist/memory/file-indexer.js.map +1 -0
- package/dist/memory/hybrid.d.ts.map +1 -1
- package/dist/memory/hybrid.js +6 -2
- package/dist/memory/hybrid.js.map +1 -1
- package/dist/memory/index.d.ts +5 -0
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +5 -2
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/session-indexer.d.ts +41 -0
- package/dist/memory/session-indexer.d.ts.map +1 -0
- package/dist/memory/session-indexer.js +367 -0
- package/dist/memory/session-indexer.js.map +1 -0
- package/dist/memory/simple-manager.d.ts +6 -0
- package/dist/memory/simple-manager.d.ts.map +1 -1
- package/dist/memory/simple-manager.js +35 -12
- package/dist/memory/simple-manager.js.map +1 -1
- package/dist/memory/ssrf.d.ts +18 -0
- package/dist/memory/ssrf.d.ts.map +1 -0
- package/dist/memory/ssrf.js +305 -0
- package/dist/memory/ssrf.js.map +1 -0
- package/dist/package.json +8 -5
- package/dist/platform/platform.d.ts.map +1 -1
- package/dist/platform/platform.js +30 -7
- package/dist/platform/platform.js.map +1 -1
- package/dist/platform/types.d.ts +2 -0
- package/dist/platform/types.d.ts.map +1 -1
- package/dist/runtime/agent.d.ts +8 -0
- package/dist/runtime/agent.d.ts.map +1 -1
- package/dist/runtime/agent.js +194 -46
- package/dist/runtime/agent.js.map +1 -1
- package/dist/runtime/api-key-rotation.d.ts +26 -0
- package/dist/runtime/api-key-rotation.d.ts.map +1 -0
- package/dist/runtime/api-key-rotation.js +174 -0
- package/dist/runtime/api-key-rotation.js.map +1 -0
- package/dist/runtime/context-guard.d.ts +32 -0
- package/dist/runtime/context-guard.d.ts.map +1 -0
- package/dist/runtime/context-guard.js +61 -0
- package/dist/runtime/context-guard.js.map +1 -0
- package/dist/runtime/failover-error.d.ts +62 -0
- package/dist/runtime/failover-error.d.ts.map +1 -0
- package/dist/runtime/failover-error.js +733 -0
- package/dist/runtime/failover-error.js.map +1 -0
- package/dist/runtime/failover-policy.d.ts +5 -0
- package/dist/runtime/failover-policy.d.ts.map +1 -0
- package/dist/runtime/failover-policy.js +18 -0
- package/dist/runtime/failover-policy.js.map +1 -0
- package/dist/runtime/index.d.ts +11 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +11 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/memory-flush.d.ts +24 -0
- package/dist/runtime/memory-flush.d.ts.map +1 -0
- package/dist/runtime/memory-flush.js +64 -0
- package/dist/runtime/memory-flush.js.map +1 -0
- package/dist/runtime/memory-tools.d.ts +14 -0
- package/dist/runtime/memory-tools.d.ts.map +1 -0
- package/dist/runtime/memory-tools.js +58 -0
- package/dist/runtime/memory-tools.js.map +1 -0
- package/dist/runtime/model-fallback.d.ts +56 -0
- package/dist/runtime/model-fallback.d.ts.map +1 -0
- package/dist/runtime/model-fallback.js +301 -0
- package/dist/runtime/model-fallback.js.map +1 -0
- package/dist/runtime/model-fallback.types.d.ts +14 -0
- package/dist/runtime/model-fallback.types.d.ts.map +1 -0
- package/dist/runtime/model-fallback.types.js +3 -0
- package/dist/runtime/model-fallback.types.js.map +1 -0
- package/dist/runtime/retry.d.ts +24 -0
- package/dist/runtime/retry.d.ts.map +1 -0
- package/dist/runtime/retry.js +102 -0
- package/dist/runtime/retry.js.map +1 -0
- package/dist/runtime/session-pruning.d.ts +22 -0
- package/dist/runtime/session-pruning.d.ts.map +1 -0
- package/dist/runtime/session-pruning.js +118 -0
- package/dist/runtime/session-pruning.js.map +1 -0
- package/dist/runtime/stream-adapters.d.ts +11 -0
- package/dist/runtime/stream-adapters.d.ts.map +1 -0
- package/dist/runtime/stream-adapters.js +46 -0
- package/dist/runtime/stream-adapters.js.map +1 -0
- package/dist/runtime/subagent.d.ts +83 -0
- package/dist/runtime/subagent.d.ts.map +1 -0
- package/dist/runtime/subagent.js +190 -0
- package/dist/runtime/subagent.js.map +1 -0
- package/dist/runtime/tool-result-truncation.d.ts +25 -0
- package/dist/runtime/tool-result-truncation.d.ts.map +1 -0
- package/dist/runtime/tool-result-truncation.js +115 -0
- package/dist/runtime/tool-result-truncation.js.map +1 -0
- package/dist/sandbox/cgroup.d.ts +4 -1
- package/dist/sandbox/cgroup.d.ts.map +1 -1
- package/dist/sandbox/cgroup.js +28 -15
- package/dist/sandbox/cgroup.js.map +1 -1
- package/dist/sandbox/index.d.ts +2 -1
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +2 -1
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/ipc.d.ts +4 -1
- package/dist/sandbox/ipc.d.ts.map +1 -1
- package/dist/sandbox/ipc.js +33 -17
- package/dist/sandbox/ipc.js.map +1 -1
- package/dist/sandbox/manager.d.ts +1 -2
- package/dist/sandbox/manager.d.ts.map +1 -1
- package/dist/sandbox/manager.js +136 -130
- package/dist/sandbox/manager.js.map +1 -1
- package/dist/sandbox/namespace.d.ts +1 -1
- package/dist/sandbox/namespace.d.ts.map +1 -1
- package/dist/sandbox/namespace.js +36 -37
- package/dist/sandbox/namespace.js.map +1 -1
- package/dist/sandbox/rootfs.d.ts +6 -1
- package/dist/sandbox/rootfs.d.ts.map +1 -1
- package/dist/sandbox/rootfs.js +114 -30
- package/dist/sandbox/rootfs.js.map +1 -1
- package/dist/sandbox/seccomp-apply.d.ts +9 -0
- package/dist/sandbox/seccomp-apply.d.ts.map +1 -0
- package/dist/sandbox/seccomp-apply.js +227 -0
- package/dist/sandbox/seccomp-apply.js.map +1 -0
- package/dist/sandbox/seccomp.js +3 -3
- package/dist/sandbox/seccomp.js.map +1 -1
- package/dist/sandbox/types.d.ts +1 -3
- package/dist/sandbox/types.d.ts.map +1 -1
- package/dist/sandbox/types.js.map +1 -1
- package/dist/sandbox/worker.d.ts +3 -0
- package/dist/sandbox/worker.d.ts.map +1 -1
- package/dist/sandbox/worker.js +84 -17
- package/dist/sandbox/worker.js.map +1 -1
- package/dist/sessions/index.d.ts +1 -0
- package/dist/sessions/index.d.ts.map +1 -1
- package/dist/sessions/index.js +1 -0
- package/dist/sessions/index.js.map +1 -1
- package/dist/sessions/store.d.ts +2 -2
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +49 -27
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/transcript-events.d.ts +11 -0
- package/dist/sessions/transcript-events.d.ts.map +1 -0
- package/dist/sessions/transcript-events.js +40 -0
- package/dist/sessions/transcript-events.js.map +1 -0
- package/dist/shared/agent-session.d.ts +10 -0
- package/dist/shared/agent-session.d.ts.map +1 -0
- package/dist/shared/agent-session.js +33 -0
- package/dist/shared/agent-session.js.map +1 -0
- package/dist/shared/constants.d.ts +6 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +11 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/fs.d.ts +7 -0
- package/dist/shared/fs.d.ts.map +1 -0
- package/dist/shared/fs.js +14 -0
- package/dist/shared/fs.js.map +1 -0
- package/dist/shared/index.d.ts +4 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/skills/enablement.d.ts.map +1 -1
- package/dist/skills/enablement.js +2 -2
- package/dist/skills/enablement.js.map +1 -1
- package/dist/workspace/runner.d.ts.map +1 -1
- package/dist/workspace/runner.js +436 -105
- package/dist/workspace/runner.js.map +1 -1
- package/dist/workspace/types.d.ts +1 -0
- package/dist/workspace/types.d.ts.map +1 -1
- package/dist/workspace/workspace.d.ts.map +1 -1
- package/dist/workspace/workspace.js +12 -3
- package/dist/workspace/workspace.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
// Simple memory manager that wraps OpenClaw's search/indexing components
|
|
2
|
-
// with a user-friendly store/search/delete/list API.
|
|
3
1
|
import * as fs from "node:fs";
|
|
4
2
|
import * as path from "node:path";
|
|
3
|
+
import * as crypto from "node:crypto";
|
|
5
4
|
import { requireNodeSqlite } from "./sqlite.js";
|
|
6
5
|
import { cosineSimilarity, parseEmbedding, hashText } from "./internal.js";
|
|
7
6
|
import { extractKeywords } from "./query-expansion.js";
|
|
8
|
-
import { buildFtsQuery, bm25RankToScore } from "./hybrid.js";
|
|
9
|
-
import { mergeHybridResults } from "./hybrid.js";
|
|
7
|
+
import { buildFtsQuery, bm25RankToScore, mergeHybridResults } from "./hybrid.js";
|
|
10
8
|
import { debugEmbeddingsLog } from "./embeddings-debug.js";
|
|
9
|
+
import { createEmbeddingCache, hashContent } from "./embedding-cache.js";
|
|
11
10
|
const SNIPPET_MAX_CHARS = 700;
|
|
11
|
+
const MAX_VECTOR_SEARCH_CHUNKS = 10_000;
|
|
12
12
|
function generateId() {
|
|
13
|
-
return `mem_${Date.now()}_${
|
|
13
|
+
return `mem_${Date.now()}_${crypto.randomBytes(4).toString("hex")}`;
|
|
14
14
|
}
|
|
15
15
|
export function createSimpleMemoryManager(options) {
|
|
16
16
|
fs.mkdirSync(options.dbDir, { recursive: true });
|
|
@@ -36,11 +36,15 @@ export function createSimpleMemoryManager(options) {
|
|
|
36
36
|
)
|
|
37
37
|
`);
|
|
38
38
|
let ftsAvailable = false;
|
|
39
|
+
let stmtFtsInsert = null;
|
|
40
|
+
let stmtFtsDelete = null;
|
|
39
41
|
try {
|
|
40
42
|
db.exec(`
|
|
41
43
|
CREATE VIRTUAL TABLE IF NOT EXISTS chunks_fts
|
|
42
44
|
USING fts5(id, content, source, model)
|
|
43
45
|
`);
|
|
46
|
+
stmtFtsInsert = db.prepare("INSERT INTO chunks_fts(id, content, source, model) VALUES (?, ?, ?, ?)");
|
|
47
|
+
stmtFtsDelete = db.prepare("DELETE FROM chunks_fts WHERE id = ?");
|
|
44
48
|
ftsAvailable = true;
|
|
45
49
|
}
|
|
46
50
|
catch {
|
|
@@ -48,6 +52,10 @@ export function createSimpleMemoryManager(options) {
|
|
|
48
52
|
}
|
|
49
53
|
const provider = options.embeddingProvider ?? null;
|
|
50
54
|
const providerModel = provider ? `${provider.id}/${provider.model}` : "none";
|
|
55
|
+
const embeddingCache = (options.enableEmbeddingCache !== false && provider)
|
|
56
|
+
? createEmbeddingCache(db)
|
|
57
|
+
: null;
|
|
58
|
+
const maxCacheEntries = options.maxCacheEntries ?? 50_000;
|
|
51
59
|
const stmtInsert = db.prepare(`
|
|
52
60
|
INSERT OR REPLACE INTO chunks (id, content, embedding, metadata, source, path, model, start_line, end_line, hash, created_at)
|
|
53
61
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
@@ -63,18 +71,28 @@ export function createSimpleMemoryManager(options) {
|
|
|
63
71
|
let embeddingJson = null;
|
|
64
72
|
if (provider) {
|
|
65
73
|
try {
|
|
66
|
-
const
|
|
74
|
+
const contentHash = hashContent(content);
|
|
75
|
+
const cached = embeddingCache?.get(provider.id, provider.model, contentHash);
|
|
76
|
+
let vec;
|
|
77
|
+
if (cached) {
|
|
78
|
+
vec = cached;
|
|
79
|
+
debugEmbeddingsLog("embedding from cache", { id, dims: vec.length });
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
vec = await provider.embedQuery(content);
|
|
83
|
+
embeddingCache?.set(provider.id, provider.model, "", contentHash, vec, vec.length);
|
|
84
|
+
debugEmbeddingsLog("embedded chunk", { id, dims: vec.length });
|
|
85
|
+
}
|
|
67
86
|
embeddingJson = JSON.stringify(vec);
|
|
68
|
-
debugEmbeddingsLog("embedded chunk", { id, dims: vec.length });
|
|
69
87
|
}
|
|
70
88
|
catch (err) {
|
|
71
89
|
debugEmbeddingsLog("embedding failed", { id, error: String(err) });
|
|
72
90
|
}
|
|
73
91
|
}
|
|
74
92
|
stmtInsert.run(id, content, embeddingJson, metadata ? JSON.stringify(metadata) : null, "memory", null, providerModel, 1, 1, hash, now);
|
|
75
|
-
if (
|
|
93
|
+
if (stmtFtsInsert) {
|
|
76
94
|
try {
|
|
77
|
-
|
|
95
|
+
stmtFtsInsert.run(id, content, "memory", providerModel);
|
|
78
96
|
}
|
|
79
97
|
catch {
|
|
80
98
|
// FTS insert failed, keyword search won't find this chunk
|
|
@@ -91,7 +109,7 @@ export function createSimpleMemoryManager(options) {
|
|
|
91
109
|
if (provider) {
|
|
92
110
|
try {
|
|
93
111
|
const queryVec = await provider.embedQuery(query);
|
|
94
|
-
const rows = db.prepare("SELECT * FROM chunks WHERE embedding IS NOT NULL AND model = ?").all(providerModel);
|
|
112
|
+
const rows = db.prepare("SELECT * FROM chunks WHERE embedding IS NOT NULL AND model = ? LIMIT ?").all(providerModel, MAX_VECTOR_SEARCH_CHUNKS);
|
|
95
113
|
const scored = [];
|
|
96
114
|
for (const row of rows) {
|
|
97
115
|
const embedding = parseEmbedding(row.embedding);
|
|
@@ -168,9 +186,9 @@ export function createSimpleMemoryManager(options) {
|
|
|
168
186
|
if (!row)
|
|
169
187
|
return false;
|
|
170
188
|
stmtDelete.run(id);
|
|
171
|
-
if (
|
|
189
|
+
if (stmtFtsDelete) {
|
|
172
190
|
try {
|
|
173
|
-
|
|
191
|
+
stmtFtsDelete.run(id);
|
|
174
192
|
}
|
|
175
193
|
catch { }
|
|
176
194
|
}
|
|
@@ -186,8 +204,13 @@ export function createSimpleMemoryManager(options) {
|
|
|
186
204
|
}));
|
|
187
205
|
},
|
|
188
206
|
async close() {
|
|
207
|
+
if (embeddingCache) {
|
|
208
|
+
embeddingCache.prune(maxCacheEntries);
|
|
209
|
+
}
|
|
189
210
|
db.close();
|
|
190
211
|
},
|
|
212
|
+
get db() { return db; },
|
|
213
|
+
get embeddingCache() { return embeddingCache; },
|
|
191
214
|
};
|
|
192
215
|
}
|
|
193
216
|
//# sourceMappingURL=simple-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simple-manager.js","sourceRoot":"","sources":["../../src/memory/simple-manager.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"simple-manager.js","sourceRoot":"","sources":["../../src/memory/simple-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare class SsrFBlockedError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export type SsrfPolicy = {
|
|
5
|
+
allowPrivateNetwork?: boolean;
|
|
6
|
+
allowedHostnames?: string[];
|
|
7
|
+
hostnameAllowlist?: string[];
|
|
8
|
+
};
|
|
9
|
+
export declare function isBlockedHostname(hostname: string): boolean;
|
|
10
|
+
export declare function isPrivateIpAddress(address: string): boolean;
|
|
11
|
+
export declare function isBlockedHostnameOrIp(hostname: string): boolean;
|
|
12
|
+
export declare function buildBaseUrlPolicy(baseUrl: string): SsrfPolicy | undefined;
|
|
13
|
+
export interface ValidateUrlResult {
|
|
14
|
+
resolvedAddresses: string[];
|
|
15
|
+
}
|
|
16
|
+
export declare function validateUrl(url: string, policy?: SsrfPolicy): Promise<ValidateUrlResult>;
|
|
17
|
+
export declare function fetchWithSsrfGuard(url: string, init: RequestInit, policy?: SsrfPolicy): Promise<Response>;
|
|
18
|
+
//# sourceMappingURL=ssrf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssrf.d.ts","sourceRoot":"","sources":["../../src/memory/ssrf.ts"],"names":[],"mappings":"AAaA,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B,CAAC;AA6BF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAI3D;AA8DD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAgB3D;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAI/D;AAyBD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAU1E;AAOD,MAAM,WAAW,iBAAiB;IAChC,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA4D9F;AAuBD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,QAAQ,CAAC,CAgDnB"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// Ported from OpenClaw src/infra/net/ssrf.ts + fetch-guard.ts
|
|
2
|
+
// DNS validation: we resolve DNS ourselves, validate ALL resolved IPs against
|
|
3
|
+
// the private/special-use blocklist, then let fetch() connect using the
|
|
4
|
+
// original hostname (required for TLS/SNI to work).
|
|
5
|
+
// Without undici dispatchers we cannot pin the TCP socket to our resolved IP,
|
|
6
|
+
// so a small TOCTOU window exists between our DNS check and fetch()'s own
|
|
7
|
+
// resolution. This is acceptable: an attacker would need to poison DNS
|
|
8
|
+
// between our check and fetch's connect, which is a very narrow window.
|
|
9
|
+
// Mitigation: fail-closed on DNS failure or empty results.
|
|
10
|
+
import * as dns from "node:dns/promises";
|
|
11
|
+
import * as net from "node:net";
|
|
12
|
+
export class SsrFBlockedError extends Error {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "SsrFBlockedError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// --- Hostname normalization ---
|
|
19
|
+
function normalizeHostname(hostname) {
|
|
20
|
+
const trimmed = hostname.trim().toLowerCase();
|
|
21
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
22
|
+
return trimmed.slice(1, -1);
|
|
23
|
+
}
|
|
24
|
+
return trimmed.replace(/\.+$/, "");
|
|
25
|
+
}
|
|
26
|
+
// --- Blocked hostnames (from OpenClaw) ---
|
|
27
|
+
const BLOCKED_HOSTNAMES = new Set([
|
|
28
|
+
"localhost",
|
|
29
|
+
"localhost.localdomain",
|
|
30
|
+
"metadata.google.internal",
|
|
31
|
+
]);
|
|
32
|
+
function isBlockedHostnameNormalized(normalized) {
|
|
33
|
+
if (BLOCKED_HOSTNAMES.has(normalized))
|
|
34
|
+
return true;
|
|
35
|
+
return (normalized.endsWith(".localhost") ||
|
|
36
|
+
normalized.endsWith(".local") ||
|
|
37
|
+
normalized.endsWith(".internal"));
|
|
38
|
+
}
|
|
39
|
+
export function isBlockedHostname(hostname) {
|
|
40
|
+
const normalized = normalizeHostname(hostname);
|
|
41
|
+
if (!normalized)
|
|
42
|
+
return false;
|
|
43
|
+
return isBlockedHostnameNormalized(normalized);
|
|
44
|
+
}
|
|
45
|
+
// --- IP validation (from OpenClaw) ---
|
|
46
|
+
function isCanonicalDottedDecimalIPv4(address) {
|
|
47
|
+
const parts = address.split(".");
|
|
48
|
+
if (parts.length !== 4)
|
|
49
|
+
return false;
|
|
50
|
+
for (const part of parts) {
|
|
51
|
+
if (!/^\d{1,3}$/.test(part))
|
|
52
|
+
return false;
|
|
53
|
+
const num = Number(part);
|
|
54
|
+
if (num < 0 || num > 255)
|
|
55
|
+
return false;
|
|
56
|
+
if (part.length > 1 && part.startsWith("0"))
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
function isLegacyIpv4Literal(address) {
|
|
62
|
+
return /^(?:0x[\da-f]+|\d+)(?:\.(?:0x[\da-f]+|\d+)){0,3}$/i.test(address);
|
|
63
|
+
}
|
|
64
|
+
function looksLikeUnsupportedIpv4Literal(address) {
|
|
65
|
+
const parts = address.split(".");
|
|
66
|
+
if (parts.length === 0 || parts.length > 4)
|
|
67
|
+
return false;
|
|
68
|
+
if (parts.some((part) => part.length === 0))
|
|
69
|
+
return true;
|
|
70
|
+
return parts.every((part) => /^[0-9]+$/.test(part) || /^0x/i.test(part));
|
|
71
|
+
}
|
|
72
|
+
function isBlockedSpecialUseIpv4(ip) {
|
|
73
|
+
if (!net.isIPv4(ip))
|
|
74
|
+
return false;
|
|
75
|
+
const parts = ip.split(".").map(Number);
|
|
76
|
+
const [a, b] = parts;
|
|
77
|
+
if (a === 0)
|
|
78
|
+
return true; // 0.0.0.0/8 "this network"
|
|
79
|
+
if (a === 10)
|
|
80
|
+
return true; // 10.0.0.0/8 RFC 1918
|
|
81
|
+
if (a === 100 && b >= 64 && b <= 127)
|
|
82
|
+
return true; // 100.64.0.0/10 CGN
|
|
83
|
+
if (a === 127)
|
|
84
|
+
return true; // 127.0.0.0/8 loopback
|
|
85
|
+
if (a === 169 && b === 254)
|
|
86
|
+
return true; // 169.254.0.0/16 link-local
|
|
87
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
88
|
+
return true; // 172.16.0.0/12 RFC 1918
|
|
89
|
+
if (a === 192 && b === 0 && parts[2] === 0)
|
|
90
|
+
return true; // 192.0.0.0/24 IETF protocol
|
|
91
|
+
if (a === 192 && b === 0 && parts[2] === 2)
|
|
92
|
+
return true; // 192.0.2.0/24 TEST-NET-1
|
|
93
|
+
if (a === 192 && b === 88 && parts[2] === 99)
|
|
94
|
+
return true; // 192.88.99.0/24 6to4 relay
|
|
95
|
+
if (a === 192 && b === 168)
|
|
96
|
+
return true; // 192.168.0.0/16 RFC 1918
|
|
97
|
+
if (a === 198 && (b === 18 || b === 19))
|
|
98
|
+
return true; // 198.18.0.0/15 benchmark
|
|
99
|
+
if (a === 198 && b === 51 && parts[2] === 100)
|
|
100
|
+
return true; // 198.51.100.0/24 TEST-NET-2
|
|
101
|
+
if (a === 203 && b === 0 && parts[2] === 113)
|
|
102
|
+
return true; // 203.0.113.0/24 TEST-NET-3
|
|
103
|
+
if (a >= 224)
|
|
104
|
+
return true; // 224.0.0.0/3 multicast + reserved
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
function isBlockedSpecialUseIpv6(ip) {
|
|
108
|
+
const lower = ip.toLowerCase();
|
|
109
|
+
if (lower === "::")
|
|
110
|
+
return true; // unspecified
|
|
111
|
+
if (lower === "::1")
|
|
112
|
+
return true; // loopback
|
|
113
|
+
if (lower.startsWith("fe80:"))
|
|
114
|
+
return true; // link-local
|
|
115
|
+
if (lower.startsWith("fc") || lower.startsWith("fd"))
|
|
116
|
+
return true; // ULA
|
|
117
|
+
if (lower.startsWith("ff"))
|
|
118
|
+
return true; // multicast
|
|
119
|
+
if (lower.startsWith("::ffff:")) {
|
|
120
|
+
const embedded = lower.slice(7);
|
|
121
|
+
if (net.isIPv4(embedded) && isBlockedSpecialUseIpv4(embedded))
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
export function isPrivateIpAddress(address) {
|
|
127
|
+
let normalized = address.trim().toLowerCase();
|
|
128
|
+
if (normalized.startsWith("[") && normalized.endsWith("]")) {
|
|
129
|
+
normalized = normalized.slice(1, -1);
|
|
130
|
+
}
|
|
131
|
+
if (!normalized)
|
|
132
|
+
return false;
|
|
133
|
+
if (net.isIPv4(normalized))
|
|
134
|
+
return isBlockedSpecialUseIpv4(normalized);
|
|
135
|
+
if (net.isIPv6(normalized))
|
|
136
|
+
return isBlockedSpecialUseIpv6(normalized);
|
|
137
|
+
// Malformed IPv6 literals: fail closed
|
|
138
|
+
if (normalized.includes(":") && !net.isIPv6(normalized))
|
|
139
|
+
return true;
|
|
140
|
+
if (!isCanonicalDottedDecimalIPv4(normalized) && isLegacyIpv4Literal(normalized))
|
|
141
|
+
return true;
|
|
142
|
+
if (looksLikeUnsupportedIpv4Literal(normalized))
|
|
143
|
+
return true;
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
export function isBlockedHostnameOrIp(hostname) {
|
|
147
|
+
const normalized = normalizeHostname(hostname);
|
|
148
|
+
if (!normalized)
|
|
149
|
+
return false;
|
|
150
|
+
return isBlockedHostnameNormalized(normalized) || isPrivateIpAddress(normalized);
|
|
151
|
+
}
|
|
152
|
+
// --- Hostname allowlist ---
|
|
153
|
+
function matchesHostnameAllowlist(hostname, allowlist) {
|
|
154
|
+
if (allowlist.length === 0)
|
|
155
|
+
return true;
|
|
156
|
+
return allowlist.some((pattern) => {
|
|
157
|
+
if (pattern.startsWith("*.")) {
|
|
158
|
+
const suffix = pattern.slice(2);
|
|
159
|
+
if (!suffix || hostname === suffix)
|
|
160
|
+
return false;
|
|
161
|
+
return hostname.endsWith(`.${suffix}`);
|
|
162
|
+
}
|
|
163
|
+
return hostname === pattern;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
// --- Policy helpers ---
|
|
167
|
+
function shouldSkipPrivateNetworkChecks(hostname, policy) {
|
|
168
|
+
return (policy?.allowPrivateNetwork === true ||
|
|
169
|
+
new Set(policy?.allowedHostnames?.map(normalizeHostname)).has(hostname));
|
|
170
|
+
}
|
|
171
|
+
export function buildBaseUrlPolicy(baseUrl) {
|
|
172
|
+
const trimmed = baseUrl.trim();
|
|
173
|
+
if (!trimmed)
|
|
174
|
+
return undefined;
|
|
175
|
+
try {
|
|
176
|
+
const parsed = new URL(trimmed);
|
|
177
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:")
|
|
178
|
+
return undefined;
|
|
179
|
+
return { allowedHostnames: [parsed.hostname], hostnameAllowlist: [normalizeHostname(parsed.hostname)] };
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// --- URL validation ---
|
|
186
|
+
const BLOCKED_HOST_OR_IP_MESSAGE = "Blocked hostname or private/internal/special-use IP address";
|
|
187
|
+
const BLOCKED_RESOLVED_IP_MESSAGE = "Blocked: resolves to private/internal/special-use IP address";
|
|
188
|
+
export async function validateUrl(url, policy) {
|
|
189
|
+
const parsed = new URL(url);
|
|
190
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
191
|
+
throw new SsrFBlockedError(`SSRF: blocked non-HTTP protocol: ${parsed.protocol}`);
|
|
192
|
+
}
|
|
193
|
+
const hostname = normalizeHostname(parsed.hostname);
|
|
194
|
+
if (!hostname)
|
|
195
|
+
throw new SsrFBlockedError("SSRF: empty hostname");
|
|
196
|
+
const hostnameAllowlist = (policy?.hostnameAllowlist ?? []).map(normalizeHostname).filter(Boolean);
|
|
197
|
+
if (hostnameAllowlist.length > 0 && !matchesHostnameAllowlist(hostname, hostnameAllowlist)) {
|
|
198
|
+
throw new SsrFBlockedError(`Blocked hostname (not in allowlist): ${parsed.hostname}`);
|
|
199
|
+
}
|
|
200
|
+
if (!shouldSkipPrivateNetworkChecks(hostname, policy)) {
|
|
201
|
+
if (isBlockedHostnameOrIp(hostname)) {
|
|
202
|
+
throw new SsrFBlockedError(BLOCKED_HOST_OR_IP_MESSAGE);
|
|
203
|
+
}
|
|
204
|
+
// Resolve both IPv4 and IPv6 and check ALL results.
|
|
205
|
+
// Fail-closed: if DNS resolution fails entirely, block the request
|
|
206
|
+
// (we cannot verify the target IP is safe).
|
|
207
|
+
const allAddresses = [];
|
|
208
|
+
let v4Error = null;
|
|
209
|
+
let v6Error = null;
|
|
210
|
+
try {
|
|
211
|
+
const v4 = await dns.resolve4(hostname);
|
|
212
|
+
allAddresses.push(...v4);
|
|
213
|
+
}
|
|
214
|
+
catch (err) {
|
|
215
|
+
if (err instanceof SsrFBlockedError)
|
|
216
|
+
throw err;
|
|
217
|
+
v4Error = err;
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
const v6 = await dns.resolve6(hostname);
|
|
221
|
+
allAddresses.push(...v6);
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
if (err instanceof SsrFBlockedError)
|
|
225
|
+
throw err;
|
|
226
|
+
v6Error = err;
|
|
227
|
+
}
|
|
228
|
+
// Fail-closed: if we got zero resolved addresses (whether DNS errored
|
|
229
|
+
// or returned empty results) and the hostname is not a literal IP,
|
|
230
|
+
// block the request — we cannot verify the target IP is safe.
|
|
231
|
+
if (allAddresses.length === 0 && !net.isIP(hostname)) {
|
|
232
|
+
throw new SsrFBlockedError(`SSRF: unable to resolve hostname "${hostname}" — blocking (fail-closed)`);
|
|
233
|
+
}
|
|
234
|
+
for (const addr of allAddresses) {
|
|
235
|
+
if (isBlockedHostnameOrIp(addr)) {
|
|
236
|
+
throw new SsrFBlockedError(BLOCKED_RESOLVED_IP_MESSAGE);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return { resolvedAddresses: allAddresses };
|
|
240
|
+
}
|
|
241
|
+
return { resolvedAddresses: [] };
|
|
242
|
+
}
|
|
243
|
+
// --- Guarded fetch with redirect handling (from fetch-guard.ts) ---
|
|
244
|
+
const DEFAULT_MAX_REDIRECTS = 3;
|
|
245
|
+
function retainSafeHeadersForCrossOriginRedirect(headers) {
|
|
246
|
+
if (!headers)
|
|
247
|
+
return undefined;
|
|
248
|
+
const safe = {};
|
|
249
|
+
const headerObj = new Headers(headers);
|
|
250
|
+
const SAFE_HEADERS = new Set(["accept", "accept-language", "content-language", "content-type"]);
|
|
251
|
+
headerObj.forEach((value, key) => {
|
|
252
|
+
if (SAFE_HEADERS.has(key.toLowerCase())) {
|
|
253
|
+
safe[key] = value;
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
return Object.keys(safe).length > 0 ? safe : undefined;
|
|
257
|
+
}
|
|
258
|
+
function isRedirectStatus(status) {
|
|
259
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
260
|
+
}
|
|
261
|
+
export async function fetchWithSsrfGuard(url, init, policy) {
|
|
262
|
+
const maxRedirects = DEFAULT_MAX_REDIRECTS;
|
|
263
|
+
const visited = new Set();
|
|
264
|
+
let currentUrl = url;
|
|
265
|
+
let currentInit = init ? { ...init } : undefined;
|
|
266
|
+
let redirectCount = 0;
|
|
267
|
+
while (true) {
|
|
268
|
+
let parsedUrl;
|
|
269
|
+
try {
|
|
270
|
+
parsedUrl = new URL(currentUrl);
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
throw new Error("Invalid URL: must be http or https");
|
|
274
|
+
}
|
|
275
|
+
if (!["http:", "https:"].includes(parsedUrl.protocol)) {
|
|
276
|
+
throw new Error("Invalid URL: must be http or https");
|
|
277
|
+
}
|
|
278
|
+
await validateUrl(currentUrl, policy);
|
|
279
|
+
const response = await fetch(parsedUrl.toString(), {
|
|
280
|
+
...(currentInit ?? {}),
|
|
281
|
+
redirect: "manual",
|
|
282
|
+
});
|
|
283
|
+
if (isRedirectStatus(response.status)) {
|
|
284
|
+
const location = response.headers.get("location");
|
|
285
|
+
if (!location)
|
|
286
|
+
throw new Error(`Redirect missing location header (${response.status})`);
|
|
287
|
+
redirectCount += 1;
|
|
288
|
+
if (redirectCount > maxRedirects)
|
|
289
|
+
throw new Error(`Too many redirects (limit: ${maxRedirects})`);
|
|
290
|
+
const nextParsedUrl = new URL(location, parsedUrl);
|
|
291
|
+
const nextUrl = nextParsedUrl.toString();
|
|
292
|
+
if (visited.has(nextUrl))
|
|
293
|
+
throw new Error("Redirect loop detected");
|
|
294
|
+
if (nextParsedUrl.origin !== parsedUrl.origin && currentInit?.headers) {
|
|
295
|
+
const safeHeaders = retainSafeHeadersForCrossOriginRedirect(currentInit.headers);
|
|
296
|
+
currentInit = { ...currentInit, headers: safeHeaders };
|
|
297
|
+
}
|
|
298
|
+
visited.add(nextUrl);
|
|
299
|
+
currentUrl = nextUrl;
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
return response;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=ssrf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssrf.js","sourceRoot":"","sources":["../../src/memory/ssrf.ts"],"names":[],"mappings":"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"}
|
package/dist/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
2
|
+
"name": "bulkhead-runtime",
|
|
3
|
+
"version": "2026.4.5-beta.2",
|
|
4
|
+
"description": "Multi-tenant AI agent runtime with OS-level isolation. Sandboxed execution, encrypted credentials, private memory per tenant — one server, no Docker.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/tonga54/
|
|
8
|
+
"url": "git+https://github.com/tonga54/bulkhead-runtime.git"
|
|
9
9
|
},
|
|
10
10
|
"type": "module",
|
|
11
11
|
"main": "index.js",
|
|
12
12
|
"types": "index.d.ts",
|
|
13
13
|
"bin": {
|
|
14
|
-
"
|
|
14
|
+
"bulkhead-runtime": "dist/cli.js"
|
|
15
15
|
},
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
@@ -32,5 +32,8 @@
|
|
|
32
32
|
"engines": {
|
|
33
33
|
"node": ">=22.12.0"
|
|
34
34
|
},
|
|
35
|
+
"os": [
|
|
36
|
+
"linux"
|
|
37
|
+
],
|
|
35
38
|
"packageManager": "pnpm@10.23.0"
|
|
36
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/platform/platform.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/platform/platform.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAc3D,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,QAAQ,CAyF/D"}
|
|
@@ -2,13 +2,21 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { createWorkspace, validateWorkspaceId, loadWorkspaceConfig, } from "../workspace/workspace.js";
|
|
4
4
|
import { createSkillRegistry } from "../skills/registry.js";
|
|
5
|
+
const PLATFORM_SENSITIVE_PATHS = new Set([
|
|
6
|
+
"/", "/root", "/proc", "/sys", "/dev", "/boot", "/run",
|
|
7
|
+
"/tmp", "/var", "/etc", "/bin", "/sbin", "/usr", "/lib",
|
|
8
|
+
]);
|
|
5
9
|
export function createPlatform(config) {
|
|
6
10
|
const { stateDir } = config;
|
|
11
|
+
const resolvedStateDir = path.resolve(stateDir);
|
|
12
|
+
if (PLATFORM_SENSITIVE_PATHS.has(resolvedStateDir)) {
|
|
13
|
+
throw new Error(`stateDir "${stateDir}" references a sensitive system path`);
|
|
14
|
+
}
|
|
7
15
|
const skillsDir = config.skillsDir ?? path.join(stateDir, "skills");
|
|
8
16
|
const workspacesDir = path.join(stateDir, "workspaces");
|
|
9
|
-
fs.mkdirSync(stateDir, { recursive: true });
|
|
10
|
-
fs.mkdirSync(skillsDir, { recursive: true });
|
|
11
|
-
fs.mkdirSync(workspacesDir, { recursive: true });
|
|
17
|
+
fs.mkdirSync(stateDir, { recursive: true, mode: 0o700 });
|
|
18
|
+
fs.mkdirSync(skillsDir, { recursive: true, mode: 0o700 });
|
|
19
|
+
fs.mkdirSync(workspacesDir, { recursive: true, mode: 0o700 });
|
|
12
20
|
const skills = createSkillRegistry(skillsDir);
|
|
13
21
|
return {
|
|
14
22
|
stateDir,
|
|
@@ -16,10 +24,19 @@ export function createPlatform(config) {
|
|
|
16
24
|
async createWorkspace(userId, wsConfig) {
|
|
17
25
|
validateWorkspaceId(userId);
|
|
18
26
|
const wsDir = path.join(workspacesDir, userId);
|
|
19
|
-
|
|
20
|
-
|
|
27
|
+
try {
|
|
28
|
+
fs.mkdirSync(wsDir, { mode: 0o700 });
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
if (err.code === "EEXIST") {
|
|
32
|
+
throw new Error(`Workspace "${userId}" already exists`);
|
|
33
|
+
}
|
|
34
|
+
throw err;
|
|
21
35
|
}
|
|
22
|
-
const mergedConfig = {
|
|
36
|
+
const mergedConfig = {
|
|
37
|
+
credentialPassphrase: config.credentialPassphrase,
|
|
38
|
+
...wsConfig,
|
|
39
|
+
};
|
|
23
40
|
return createWorkspace({
|
|
24
41
|
userId,
|
|
25
42
|
stateDir,
|
|
@@ -34,6 +51,9 @@ export function createPlatform(config) {
|
|
|
34
51
|
throw new Error(`Workspace "${userId}" does not exist`);
|
|
35
52
|
}
|
|
36
53
|
const wsConfig = loadWorkspaceConfig(wsDir);
|
|
54
|
+
if (!wsConfig.credentialPassphrase && config.credentialPassphrase) {
|
|
55
|
+
wsConfig.credentialPassphrase = config.credentialPassphrase;
|
|
56
|
+
}
|
|
37
57
|
return createWorkspace({
|
|
38
58
|
userId,
|
|
39
59
|
stateDir,
|
|
@@ -44,7 +64,10 @@ export function createPlatform(config) {
|
|
|
44
64
|
async listWorkspaces() {
|
|
45
65
|
try {
|
|
46
66
|
const entries = fs.readdirSync(workspacesDir, { withFileTypes: true });
|
|
47
|
-
return entries
|
|
67
|
+
return entries
|
|
68
|
+
.filter((e) => e.isDirectory())
|
|
69
|
+
.filter((e) => fs.existsSync(path.join(workspacesDir, e.name, "config.json")))
|
|
70
|
+
.map((e) => e.name);
|
|
48
71
|
}
|
|
49
72
|
catch {
|
|
50
73
|
return [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/platform/platform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,UAAU,cAAc,CAAC,MAAsB;IACnD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAC5B,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACpE,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAExD,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/platform/platform.ts"],"names":[],"mappings":"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"}
|
package/dist/platform/types.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import type { SkillRegistry } from "../skills/registry.js";
|
|
|
3
3
|
export interface PlatformConfig {
|
|
4
4
|
stateDir: string;
|
|
5
5
|
skillsDir?: string;
|
|
6
|
+
/** Default passphrase for credential encryption. Falls back to BULKHEAD_CREDENTIAL_KEY env var. */
|
|
7
|
+
credentialPassphrase?: string;
|
|
6
8
|
}
|
|
7
9
|
export interface Platform {
|
|
8
10
|
readonly stateDir: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/platform/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/platform/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mGAAmG;IACnG,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAE/B,eAAe,CACb,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAChC,OAAO,CAAC,SAAS,CAAC,CAAC;IACtB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACjD,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACpC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACnD"}
|