@geminixiang/mama 0.2.0-beta.21 → 0.2.0-beta.22
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/dist/adapters/slack/branch-manager.d.ts.map +1 -1
- package/dist/adapters/slack/branch-manager.js +4 -0
- package/dist/adapters/slack/branch-manager.js.map +1 -1
- package/dist/execution-resolver.d.ts.map +1 -1
- package/dist/execution-resolver.js +1 -12
- package/dist/execution-resolver.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-manager.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/branch-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,oBAAoB,EAI1B,MAAM,wBAAwB,CAAC;AAIhC,MAAM,WAAW,+BAA+B;IAC9C,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,OAAO,CAAC;IAChC,eAAe,EAAE,MAAM,OAAO,CAAC;IAC/B,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,yBAAyB,GAAG,oBAAoB,CAAC;AAE7D,MAAM,WAAW,+BAA+B;IAC9C,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,+BAA+B;IAC9C,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;
|
|
1
|
+
{"version":3,"file":"branch-manager.d.ts","sourceRoot":"","sources":["../../../src/adapters/slack/branch-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,oBAAoB,EAI1B,MAAM,wBAAwB,CAAC;AAIhC,MAAM,WAAW,+BAA+B;IAC9C,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,OAAO,CAAC;IAChC,eAAe,EAAE,MAAM,OAAO,CAAC;IAC/B,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,yBAAyB,GAAG,oBAAoB,CAAC;AAE7D,MAAM,WAAW,+BAA+B;IAC9C,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,+BAA+B;IAC9C,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA0DD,wBAAgB,iCAAiC,CAC/C,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,GACjB,OAAO,CAGT;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,+BAA+B,GAAG,MAAM,GAAG,IAAI,CAShG;AAED,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,OAAO,CAAC,CAqBlB;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,yBAAyB,CAAC,CA+DpC","sourcesContent":["import {\n createManagedSessionFileAtPath,\n createThreadSessionFileFromRootMessage,\n forkThreadSessionFile,\n forkThreadSessionFileFromRootMessage,\n getChannelSessionDir,\n getThreadSessionFile,\n resolveChannelSessionFile,\n resolveManagedSessionFile,\n type ResolvedSessionScope,\n ThreadRootNotFoundError,\n tryResolveThreadSession,\n type ThreadRootMessage,\n} from \"../../session-store.js\";\nimport { findLogMessageById, type ConversationLogMessage } from \"../../context.js\";\nimport { parseSlackSessionKey } from \"./session.js\";\n\nexport interface SlackBranchBootstrapWaitOptions {\n parentSessionKey: string;\n sessionKey: string;\n hasThreadSession: () => boolean;\n isParentRunning: () => boolean;\n sleep?: (ms: number) => Promise<void>;\n pollMs?: number;\n}\n\nexport type SlackResolvedSessionScope = ResolvedSessionScope;\n\nexport interface ResolveSlackSessionScopeOptions {\n conversationDir: string;\n sessionKey: string;\n cwd?: string;\n sleep?: (ms: number) => Promise<void>;\n retryCount?: number;\n retryDelayMs?: number;\n}\n\nexport interface RegisterSlackForkSessionOptions {\n conversationDir: string;\n sessionKey: string;\n cwd?: string;\n}\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction buildThreadRootSeed(message: ConversationLogMessage): ThreadRootMessage | null {\n if (message.isBot) return null;\n return {\n text: message.text,\n userName: message.userName,\n user: message.user,\n loggedAt: message.date ? new Date(message.date).getTime() : undefined,\n };\n}\n\nasync function forkThreadSessionFromRootWithRetry(\n sourceSessionFile: string,\n targetSessionFile: string,\n cwd: string,\n rootMessage: ConversationLogMessage,\n sleep: (ms: number) => Promise<void>,\n retryCount: number,\n retryDelayMs: number,\n): Promise<string> {\n const seed = buildThreadRootSeed(rootMessage);\n if (!seed) throw new ThreadRootNotFoundError(sourceSessionFile);\n\n for (let attempt = 0; attempt < retryCount; attempt++) {\n try {\n return forkThreadSessionFileFromRootMessage(sourceSessionFile, targetSessionFile, cwd, seed);\n } catch (error) {\n if (!(error instanceof ThreadRootNotFoundError)) throw error;\n if (attempt === retryCount - 1) break;\n await sleep(retryDelayMs);\n }\n }\n\n return createThreadSessionFileFromRootMessage(targetSessionFile, cwd, seed, sourceSessionFile);\n}\n\nfunction createThreadSessionFromRootOrEmpty(\n threadFile: string,\n cwd: string,\n threadRootMessage: ThreadRootMessage | null,\n parentSession?: string,\n): string {\n if (threadRootMessage) {\n return createThreadSessionFileFromRootMessage(\n threadFile,\n cwd,\n threadRootMessage,\n parentSession,\n );\n }\n return createManagedSessionFileAtPath(threadFile, cwd);\n}\n\nexport function hasMaterializedSlackBranchSession(\n conversationDir: string,\n sessionKey: string,\n): boolean {\n if (parseSlackSessionKey(sessionKey).kind !== \"fork\") return false;\n return tryResolveThreadSession(getThreadSessionFile(conversationDir, sessionKey)) !== null;\n}\n\nexport function registerSlackForkSession(options: RegisterSlackForkSessionOptions): string | null {\n const { conversationDir, sessionKey } = options;\n if (parseSlackSessionKey(sessionKey).kind !== \"fork\") return null;\n\n const threadFile = getThreadSessionFile(conversationDir, sessionKey);\n return (\n tryResolveThreadSession(threadFile) ??\n createManagedSessionFileAtPath(threadFile, options.cwd ?? conversationDir)\n );\n}\n\nexport async function waitForSlackBranchBootstrap(\n options: SlackBranchBootstrapWaitOptions,\n): Promise<boolean> {\n const {\n parentSessionKey,\n sessionKey,\n hasThreadSession,\n isParentRunning,\n sleep = defaultSleep,\n pollMs = 100,\n } = options;\n\n if (parseSlackSessionKey(sessionKey).kind !== \"fork\") return false;\n if (sessionKey === parentSessionKey) return false;\n if (hasThreadSession()) return false;\n\n let waited = false;\n while (isParentRunning() && !hasThreadSession()) {\n waited = true;\n await sleep(pollMs);\n }\n\n return waited;\n}\n\nexport async function resolveSlackSessionScope(\n options: ResolveSlackSessionScopeOptions,\n): Promise<SlackResolvedSessionScope> {\n const {\n conversationDir,\n sessionKey,\n sleep = defaultSleep,\n retryCount = 5,\n retryDelayMs = 100,\n } = options;\n const cwd = options.cwd ?? conversationDir;\n\n const sessionDir = getChannelSessionDir(conversationDir);\n const sessionRef = parseSlackSessionKey(sessionKey);\n if (sessionRef.kind === \"channel\") {\n return {\n sessionDir,\n contextFile: resolveManagedSessionFile(sessionDir, cwd),\n threadRootMessage: null,\n };\n }\n\n const rootTs = sessionRef.anchorTs;\n const threadRootLogMessage = await findLogMessageById(conversationDir, rootTs);\n const threadRootMessage = threadRootLogMessage ? buildThreadRootSeed(threadRootLogMessage) : null;\n const threadFile = getThreadSessionFile(conversationDir, sessionKey);\n const existing = tryResolveThreadSession(threadFile);\n if (existing) {\n return { sessionDir, contextFile: existing, threadRootMessage };\n }\n\n const conversationSource = resolveChannelSessionFile(conversationDir);\n if (!conversationSource) {\n return {\n sessionDir,\n contextFile: createThreadSessionFromRootOrEmpty(threadFile, cwd, threadRootMessage),\n threadRootMessage,\n };\n }\n\n try {\n const contextFile = threadRootMessage\n ? await forkThreadSessionFromRootWithRetry(\n conversationSource,\n threadFile,\n cwd,\n threadRootLogMessage!,\n sleep,\n retryCount,\n retryDelayMs,\n )\n : forkThreadSessionFile(conversationSource, threadFile, cwd);\n return { sessionDir, contextFile, threadRootMessage };\n } catch {\n return {\n sessionDir,\n contextFile: createThreadSessionFromRootOrEmpty(\n threadFile,\n cwd,\n threadRootMessage,\n conversationSource,\n ),\n threadRootMessage,\n };\n }\n}\n"]}
|
|
@@ -5,6 +5,8 @@ function defaultSleep(ms) {
|
|
|
5
5
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6
6
|
}
|
|
7
7
|
function buildThreadRootSeed(message) {
|
|
8
|
+
if (message.isBot)
|
|
9
|
+
return null;
|
|
8
10
|
return {
|
|
9
11
|
text: message.text,
|
|
10
12
|
userName: message.userName,
|
|
@@ -14,6 +16,8 @@ function buildThreadRootSeed(message) {
|
|
|
14
16
|
}
|
|
15
17
|
async function forkThreadSessionFromRootWithRetry(sourceSessionFile, targetSessionFile, cwd, rootMessage, sleep, retryCount, retryDelayMs) {
|
|
16
18
|
const seed = buildThreadRootSeed(rootMessage);
|
|
19
|
+
if (!seed)
|
|
20
|
+
throw new ThreadRootNotFoundError(sourceSessionFile);
|
|
17
21
|
for (let attempt = 0; attempt < retryCount; attempt++) {
|
|
18
22
|
try {
|
|
19
23
|
return forkThreadSessionFileFromRootMessage(sourceSessionFile, targetSessionFile, cwd, seed);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-manager.js","sourceRoot":"","sources":["../../../src/adapters/slack/branch-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createManagedSessionFileAtPath,\n createThreadSessionFileFromRootMessage,\n forkThreadSessionFile,\n forkThreadSessionFileFromRootMessage,\n getChannelSessionDir,\n getThreadSessionFile,\n resolveChannelSessionFile,\n resolveManagedSessionFile,\n type ResolvedSessionScope,\n ThreadRootNotFoundError,\n tryResolveThreadSession,\n type ThreadRootMessage,\n} from \"../../session-store.js\";\nimport { findLogMessageById, type ConversationLogMessage } from \"../../context.js\";\nimport { parseSlackSessionKey } from \"./session.js\";\n\nexport interface SlackBranchBootstrapWaitOptions {\n parentSessionKey: string;\n sessionKey: string;\n hasThreadSession: () => boolean;\n isParentRunning: () => boolean;\n sleep?: (ms: number) => Promise<void>;\n pollMs?: number;\n}\n\nexport type SlackResolvedSessionScope = ResolvedSessionScope;\n\nexport interface ResolveSlackSessionScopeOptions {\n conversationDir: string;\n sessionKey: string;\n cwd?: string;\n sleep?: (ms: number) => Promise<void>;\n retryCount?: number;\n retryDelayMs?: number;\n}\n\nexport interface RegisterSlackForkSessionOptions {\n conversationDir: string;\n sessionKey: string;\n cwd?: string;\n}\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction buildThreadRootSeed(message: ConversationLogMessage): ThreadRootMessage {\n return {\n text: message.text,\n userName: message.userName,\n user: message.user,\n loggedAt: message.date ? new Date(message.date).getTime() : undefined,\n };\n}\n\nasync function forkThreadSessionFromRootWithRetry(\n sourceSessionFile: string,\n targetSessionFile: string,\n cwd: string,\n rootMessage: ConversationLogMessage,\n sleep: (ms: number) => Promise<void>,\n retryCount: number,\n retryDelayMs: number,\n): Promise<string> {\n const seed = buildThreadRootSeed(rootMessage);\n\n for (let attempt = 0; attempt < retryCount; attempt++) {\n try {\n return forkThreadSessionFileFromRootMessage(sourceSessionFile, targetSessionFile, cwd, seed);\n } catch (error) {\n if (!(error instanceof ThreadRootNotFoundError)) throw error;\n if (attempt === retryCount - 1) break;\n await sleep(retryDelayMs);\n }\n }\n\n return createThreadSessionFileFromRootMessage(targetSessionFile, cwd, seed, sourceSessionFile);\n}\n\nfunction createThreadSessionFromRootOrEmpty(\n threadFile: string,\n cwd: string,\n threadRootMessage: ThreadRootMessage | null,\n parentSession?: string,\n): string {\n if (threadRootMessage) {\n return createThreadSessionFileFromRootMessage(\n threadFile,\n cwd,\n threadRootMessage,\n parentSession,\n );\n }\n return createManagedSessionFileAtPath(threadFile, cwd);\n}\n\nexport function hasMaterializedSlackBranchSession(\n conversationDir: string,\n sessionKey: string,\n): boolean {\n if (parseSlackSessionKey(sessionKey).kind !== \"fork\") return false;\n return tryResolveThreadSession(getThreadSessionFile(conversationDir, sessionKey)) !== null;\n}\n\nexport function registerSlackForkSession(options: RegisterSlackForkSessionOptions): string | null {\n const { conversationDir, sessionKey } = options;\n if (parseSlackSessionKey(sessionKey).kind !== \"fork\") return null;\n\n const threadFile = getThreadSessionFile(conversationDir, sessionKey);\n return (\n tryResolveThreadSession(threadFile) ??\n createManagedSessionFileAtPath(threadFile, options.cwd ?? conversationDir)\n );\n}\n\nexport async function waitForSlackBranchBootstrap(\n options: SlackBranchBootstrapWaitOptions,\n): Promise<boolean> {\n const {\n parentSessionKey,\n sessionKey,\n hasThreadSession,\n isParentRunning,\n sleep = defaultSleep,\n pollMs = 100,\n } = options;\n\n if (parseSlackSessionKey(sessionKey).kind !== \"fork\") return false;\n if (sessionKey === parentSessionKey) return false;\n if (hasThreadSession()) return false;\n\n let waited = false;\n while (isParentRunning() && !hasThreadSession()) {\n waited = true;\n await sleep(pollMs);\n }\n\n return waited;\n}\n\nexport async function resolveSlackSessionScope(\n options: ResolveSlackSessionScopeOptions,\n): Promise<SlackResolvedSessionScope> {\n const {\n conversationDir,\n sessionKey,\n sleep = defaultSleep,\n retryCount = 5,\n retryDelayMs = 100,\n } = options;\n const cwd = options.cwd ?? conversationDir;\n\n const sessionDir = getChannelSessionDir(conversationDir);\n const sessionRef = parseSlackSessionKey(sessionKey);\n if (sessionRef.kind === \"channel\") {\n return {\n sessionDir,\n contextFile: resolveManagedSessionFile(sessionDir, cwd),\n threadRootMessage: null,\n };\n }\n\n const rootTs = sessionRef.anchorTs;\n const threadRootLogMessage = await findLogMessageById(conversationDir, rootTs);\n const threadRootMessage = threadRootLogMessage ? buildThreadRootSeed(threadRootLogMessage) : null;\n const threadFile = getThreadSessionFile(conversationDir, sessionKey);\n const existing = tryResolveThreadSession(threadFile);\n if (existing) {\n return { sessionDir, contextFile: existing, threadRootMessage };\n }\n\n const conversationSource = resolveChannelSessionFile(conversationDir);\n if (!conversationSource) {\n return {\n sessionDir,\n contextFile: createThreadSessionFromRootOrEmpty(threadFile, cwd, threadRootMessage),\n threadRootMessage,\n };\n }\n\n try {\n const contextFile = threadRootMessage\n ? await forkThreadSessionFromRootWithRetry(\n conversationSource,\n threadFile,\n cwd,\n threadRootLogMessage!,\n sleep,\n retryCount,\n retryDelayMs,\n )\n : forkThreadSessionFile(conversationSource, threadFile, cwd);\n return { sessionDir, contextFile, threadRootMessage };\n } catch {\n return {\n sessionDir,\n contextFile: createThreadSessionFromRootOrEmpty(\n threadFile,\n cwd,\n threadRootMessage,\n conversationSource,\n ),\n threadRootMessage,\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"branch-manager.js","sourceRoot":"","sources":["../../../src/adapters/slack/branch-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createManagedSessionFileAtPath,\n createThreadSessionFileFromRootMessage,\n forkThreadSessionFile,\n forkThreadSessionFileFromRootMessage,\n getChannelSessionDir,\n getThreadSessionFile,\n resolveChannelSessionFile,\n resolveManagedSessionFile,\n type ResolvedSessionScope,\n ThreadRootNotFoundError,\n tryResolveThreadSession,\n type ThreadRootMessage,\n} from \"../../session-store.js\";\nimport { findLogMessageById, type ConversationLogMessage } from \"../../context.js\";\nimport { parseSlackSessionKey } from \"./session.js\";\n\nexport interface SlackBranchBootstrapWaitOptions {\n parentSessionKey: string;\n sessionKey: string;\n hasThreadSession: () => boolean;\n isParentRunning: () => boolean;\n sleep?: (ms: number) => Promise<void>;\n pollMs?: number;\n}\n\nexport type SlackResolvedSessionScope = ResolvedSessionScope;\n\nexport interface ResolveSlackSessionScopeOptions {\n conversationDir: string;\n sessionKey: string;\n cwd?: string;\n sleep?: (ms: number) => Promise<void>;\n retryCount?: number;\n retryDelayMs?: number;\n}\n\nexport interface RegisterSlackForkSessionOptions {\n conversationDir: string;\n sessionKey: string;\n cwd?: string;\n}\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction buildThreadRootSeed(message: ConversationLogMessage): ThreadRootMessage | null {\n if (message.isBot) return null;\n return {\n text: message.text,\n userName: message.userName,\n user: message.user,\n loggedAt: message.date ? new Date(message.date).getTime() : undefined,\n };\n}\n\nasync function forkThreadSessionFromRootWithRetry(\n sourceSessionFile: string,\n targetSessionFile: string,\n cwd: string,\n rootMessage: ConversationLogMessage,\n sleep: (ms: number) => Promise<void>,\n retryCount: number,\n retryDelayMs: number,\n): Promise<string> {\n const seed = buildThreadRootSeed(rootMessage);\n if (!seed) throw new ThreadRootNotFoundError(sourceSessionFile);\n\n for (let attempt = 0; attempt < retryCount; attempt++) {\n try {\n return forkThreadSessionFileFromRootMessage(sourceSessionFile, targetSessionFile, cwd, seed);\n } catch (error) {\n if (!(error instanceof ThreadRootNotFoundError)) throw error;\n if (attempt === retryCount - 1) break;\n await sleep(retryDelayMs);\n }\n }\n\n return createThreadSessionFileFromRootMessage(targetSessionFile, cwd, seed, sourceSessionFile);\n}\n\nfunction createThreadSessionFromRootOrEmpty(\n threadFile: string,\n cwd: string,\n threadRootMessage: ThreadRootMessage | null,\n parentSession?: string,\n): string {\n if (threadRootMessage) {\n return createThreadSessionFileFromRootMessage(\n threadFile,\n cwd,\n threadRootMessage,\n parentSession,\n );\n }\n return createManagedSessionFileAtPath(threadFile, cwd);\n}\n\nexport function hasMaterializedSlackBranchSession(\n conversationDir: string,\n sessionKey: string,\n): boolean {\n if (parseSlackSessionKey(sessionKey).kind !== \"fork\") return false;\n return tryResolveThreadSession(getThreadSessionFile(conversationDir, sessionKey)) !== null;\n}\n\nexport function registerSlackForkSession(options: RegisterSlackForkSessionOptions): string | null {\n const { conversationDir, sessionKey } = options;\n if (parseSlackSessionKey(sessionKey).kind !== \"fork\") return null;\n\n const threadFile = getThreadSessionFile(conversationDir, sessionKey);\n return (\n tryResolveThreadSession(threadFile) ??\n createManagedSessionFileAtPath(threadFile, options.cwd ?? conversationDir)\n );\n}\n\nexport async function waitForSlackBranchBootstrap(\n options: SlackBranchBootstrapWaitOptions,\n): Promise<boolean> {\n const {\n parentSessionKey,\n sessionKey,\n hasThreadSession,\n isParentRunning,\n sleep = defaultSleep,\n pollMs = 100,\n } = options;\n\n if (parseSlackSessionKey(sessionKey).kind !== \"fork\") return false;\n if (sessionKey === parentSessionKey) return false;\n if (hasThreadSession()) return false;\n\n let waited = false;\n while (isParentRunning() && !hasThreadSession()) {\n waited = true;\n await sleep(pollMs);\n }\n\n return waited;\n}\n\nexport async function resolveSlackSessionScope(\n options: ResolveSlackSessionScopeOptions,\n): Promise<SlackResolvedSessionScope> {\n const {\n conversationDir,\n sessionKey,\n sleep = defaultSleep,\n retryCount = 5,\n retryDelayMs = 100,\n } = options;\n const cwd = options.cwd ?? conversationDir;\n\n const sessionDir = getChannelSessionDir(conversationDir);\n const sessionRef = parseSlackSessionKey(sessionKey);\n if (sessionRef.kind === \"channel\") {\n return {\n sessionDir,\n contextFile: resolveManagedSessionFile(sessionDir, cwd),\n threadRootMessage: null,\n };\n }\n\n const rootTs = sessionRef.anchorTs;\n const threadRootLogMessage = await findLogMessageById(conversationDir, rootTs);\n const threadRootMessage = threadRootLogMessage ? buildThreadRootSeed(threadRootLogMessage) : null;\n const threadFile = getThreadSessionFile(conversationDir, sessionKey);\n const existing = tryResolveThreadSession(threadFile);\n if (existing) {\n return { sessionDir, contextFile: existing, threadRootMessage };\n }\n\n const conversationSource = resolveChannelSessionFile(conversationDir);\n if (!conversationSource) {\n return {\n sessionDir,\n contextFile: createThreadSessionFromRootOrEmpty(threadFile, cwd, threadRootMessage),\n threadRootMessage,\n };\n }\n\n try {\n const contextFile = threadRootMessage\n ? await forkThreadSessionFromRootWithRetry(\n conversationSource,\n threadFile,\n cwd,\n threadRootLogMessage!,\n sleep,\n retryCount,\n retryDelayMs,\n )\n : forkThreadSessionFile(conversationSource, threadFile, cwd);\n return { sessionDir, contextFile, threadRootMessage };\n } catch {\n return {\n sessionDir,\n contextFile: createThreadSessionFromRootOrEmpty(\n threadFile,\n cwd,\n threadRootMessage,\n conversationSource,\n ),\n threadRootMessage,\n };\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution-resolver.d.ts","sourceRoot":"","sources":["../src/execution-resolver.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,sBAAsB,EAAuB,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEvF,OAAO,EAAgD,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG7F,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,MAAM,CAAC;AAEzD,wBAAgB,kCAAkC,CAChD,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,cAAc,EAAE,MAAM,GACrB,uBAAuB,CAgBzB;AAyBD,qBAAa,sBAAsB;IAI/B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,WAAW,CAAC;IACpB,OAAO,CAAC,YAAY,CAAC;IANvB,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAqB;IAE7D,YACU,UAAU,EAAE,aAAa,EACzB,YAAY,EAAE,YAAY,EAC1B,WAAW,CAAC,EAAE,sBAAsB,YAAA,EACpC,YAAY,CAAC,EAAE,MAAM,YAAA,EAC3B;IAEE,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAatD;IAED,OAAO,CAAC,wBAAwB;
|
|
1
|
+
{"version":3,"file":"execution-resolver.d.ts","sourceRoot":"","sources":["../src/execution-resolver.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,sBAAsB,EAAuB,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEvF,OAAO,EAAgD,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG7F,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,MAAM,CAAC;AAEzD,wBAAgB,kCAAkC,CAChD,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,cAAc,EAAE,MAAM,GACrB,uBAAuB,CAgBzB;AAyBD,qBAAa,sBAAsB;IAI/B,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,WAAW,CAAC;IACpB,OAAO,CAAC,YAAY,CAAC;IANvB,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAqB;IAE7D,YACU,UAAU,EAAE,aAAa,EACzB,YAAY,EAAE,YAAY,EAC1B,WAAW,CAAC,EAAE,sBAAsB,YAAA,EACpC,YAAY,CAAC,EAAE,MAAM,YAAA,EAC3B;IAEE,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAatD;IAED,OAAO,CAAC,wBAAwB;IAehC,OAAO,CAAC,oBAAoB;IAgB5B,OAAO,CAAC,wBAAwB;IA4ChC,OAAO,CAAC,aAAa;IA0BrB,OAAO,CAAC,uBAAuB;CAsBhC","sourcesContent":["import { existsSync } from \"fs\";\nimport { join } from \"path\";\nimport { loadAgentConfig, loadAgentConfigForConversation } from \"./config.js\";\nimport { ensureDirExists, isRecord, readJsonFileIfExists } from \"./file-guards.js\";\nimport { DockerContainerManager, type ContainerMount } from \"./provisioner.js\";\nimport { createExecutor, type Executor, type SandboxConfig } from \"./sandbox/index.js\";\nimport { reportUserFacingError } from \"./sentry.js\";\nimport { normalizeSharedVaultName, type ResolvedVault, type VaultManager } from \"./vault.js\";\nimport { resolveActorVaultKey } from \"./vault-routing.js\";\n\nexport interface ActorContext {\n platform: string;\n userId: string;\n conversationId: string;\n}\n\nexport type ImageWorkspaceMountMode = \"private\" | \"full\";\n\nexport function readConversationWorkspaceMountMode(\n workspaceDir: string | undefined,\n conversationId: string,\n): ImageWorkspaceMountMode {\n const globalDefault = readGlobalWorkspaceMountMode();\n if (!workspaceDir) {\n return globalDefault;\n }\n\n const conversationDir = join(workspaceDir, conversationId);\n try {\n return (\n loadAgentConfigForConversation(conversationDir).sandboxImageWorkspaceMount ?? globalDefault\n );\n } catch {\n const conversationSettingsPath = join(conversationDir, \"settings.json\");\n const raw = readConversationSettingsFallback(conversationSettingsPath);\n return raw?.sandbox?.image?.workspaceMount ?? globalDefault;\n }\n}\n\nfunction readGlobalWorkspaceMountMode(): ImageWorkspaceMountMode {\n try {\n return loadAgentConfig().sandboxImageWorkspaceMount ?? \"private\";\n } catch {\n return \"private\";\n }\n}\n\nfunction readConversationSettingsFallback(\n settingsPath: string,\n): { sandbox?: { image?: { workspaceMount?: ImageWorkspaceMountMode } } } | undefined {\n try {\n return readJsonFileIfExists(\n settingsPath,\n (value): value is { sandbox?: { image?: { workspaceMount?: ImageWorkspaceMountMode } } } =>\n isRecord(value),\n () => \"Ignoring malformed conversation settings file while resolving workspace mount\",\n );\n } catch {\n return undefined;\n }\n}\n\nexport class ActorExecutionResolver {\n private readonly ensuredConversationDirs = new Set<string>();\n\n constructor(\n private baseConfig: SandboxConfig,\n private vaultManager: VaultManager,\n private provisioner?: DockerContainerManager,\n private workspaceDir?: string,\n ) {}\n\n async resolve(context: ActorContext): Promise<Executor> {\n const vaultKey = resolveActorVaultKey(this.baseConfig, context.userId, context.conversationId);\n this.ensureDefaultSharedVault(vaultKey);\n\n const vault = this.vaultManager.resolve(vaultKey);\n const config = this.resolveSandboxConfig(vaultKey);\n const env =\n config.type !== \"host\" && vault && Object.keys(vault.env).length > 0 ? vault.env : undefined;\n return createExecutor(\n config,\n env,\n this.buildEnsureReadyCallback(vaultKey, context.conversationId, config, vault),\n );\n }\n\n private ensureDefaultSharedVault(vaultKey: string): void {\n if (this.baseConfig.type !== \"image\" && this.baseConfig.type !== \"cloudflare\") return;\n if (this.vaultManager.hasEntry(vaultKey)) return;\n\n let profile: string | undefined;\n try {\n profile = loadAgentConfig().defaultSharedVault;\n } catch {\n return;\n }\n if (!profile || normalizeSharedVaultName(profile) !== profile) return;\n\n this.vaultManager.copySharedVaultTo(profile, vaultKey);\n }\n\n private resolveSandboxConfig(vaultKey: string): SandboxConfig {\n const config = this.vaultManager.getSandboxConfig(vaultKey, this.baseConfig);\n if (this.baseConfig.type !== \"image\") {\n return config;\n }\n\n if (config.type === \"container\") {\n return config;\n }\n\n return {\n type: \"container\",\n container: DockerContainerManager.containerName(vaultKey),\n };\n }\n\n private buildEnsureReadyCallback(\n vaultKey: string,\n conversationId: string,\n config: SandboxConfig,\n vault?: ResolvedVault,\n ): (() => Promise<void>) | undefined {\n if (this.baseConfig.type !== \"image\" || config.type !== \"container\") {\n return undefined;\n }\n\n return async () => {\n const expected = config.container || DockerContainerManager.containerName(vaultKey);\n let actual: string | undefined;\n try {\n actual = await this.provisioner?.provision(vaultKey, {\n containerName: expected,\n mounts: this.resolveMounts(conversationId, vault),\n conversationId,\n });\n } catch (err) {\n reportUserFacingError(err, {\n domain: \"sandbox\",\n surface: \"sandbox_provision\",\n operation: \"ensure_image_container_ready\",\n severity: \"error\",\n context: {\n sandboxType: \"image\",\n resolvedSandboxType: config.type,\n conversationId,\n vaultKey,\n expectedContainer: expected,\n hasVault: Boolean(vault),\n },\n });\n throw err;\n }\n if (actual && actual !== expected) {\n throw new Error(\n `Provisioner returned container \"${actual}\" for container key \"${vaultKey}\", expected \"${expected}\"`,\n );\n }\n };\n }\n\n private resolveMounts(conversationId: string, vault?: ResolvedVault): ContainerMount[] {\n const mountsByTarget = new Map<string, ContainerMount>();\n for (const mount of this.buildImageSandboxMounts(conversationId)) {\n mountsByTarget.set(mount.target, mount);\n }\n for (const mount of vault?.mounts ?? []) {\n if (!existsSync(mount.source)) {\n reportUserFacingError(new Error(\"Vault mount source is missing\"), {\n domain: \"sandbox\",\n surface: \"vault_injection\",\n operation: \"resolve_mounts\",\n severity: \"warning\",\n context: {\n sandboxType: \"image\",\n conversationId,\n target: mount.target,\n hasVault: Boolean(vault),\n },\n });\n continue;\n }\n mountsByTarget.set(mount.target, { source: mount.source, target: mount.target });\n }\n return [...mountsByTarget.values()];\n }\n\n private buildImageSandboxMounts(conversationId: string): ContainerMount[] {\n if (!this.workspaceDir) {\n return [];\n }\n\n if (readConversationWorkspaceMountMode(this.workspaceDir, conversationId) === \"full\") {\n return [{ source: this.workspaceDir, target: \"/workspace\" }];\n }\n\n const conversationDir = join(this.workspaceDir, conversationId);\n if (!this.ensuredConversationDirs.has(conversationId)) {\n ensureDirExists(conversationDir);\n this.ensuredConversationDirs.add(conversationId);\n }\n\n return [\n { source: join(this.workspaceDir, \"MEMORY.md\"), target: \"/workspace/MEMORY.md\" },\n { source: join(this.workspaceDir, \"skills\"), target: \"/workspace/skills\" },\n { source: join(this.workspaceDir, \"events\"), target: \"/workspace/events\" },\n { source: conversationDir, target: `/workspace/${conversationId}` },\n ];\n }\n}\n"]}
|
|
@@ -68,18 +68,7 @@ export class ActorExecutionResolver {
|
|
|
68
68
|
}
|
|
69
69
|
if (!profile || normalizeSharedVaultName(profile) !== profile)
|
|
70
70
|
return;
|
|
71
|
-
|
|
72
|
-
this.vaultManager.copySharedVaultTo(profile, vaultKey);
|
|
73
|
-
}
|
|
74
|
-
catch (err) {
|
|
75
|
-
reportUserFacingError(err, {
|
|
76
|
-
domain: "sandbox",
|
|
77
|
-
surface: "vault_injection",
|
|
78
|
-
operation: "copy_default_shared_vault",
|
|
79
|
-
severity: "warning",
|
|
80
|
-
context: { vaultKey, profile, fatal: false },
|
|
81
|
-
});
|
|
82
|
-
}
|
|
71
|
+
this.vaultManager.copySharedVaultTo(profile, vaultKey);
|
|
83
72
|
}
|
|
84
73
|
resolveSandboxConfig(vaultKey) {
|
|
85
74
|
const config = this.vaultManager.getSandboxConfig(vaultKey, this.baseConfig);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution-resolver.js","sourceRoot":"","sources":["../src/execution-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"fs\";\nimport { join } from \"path\";\nimport { loadAgentConfig, loadAgentConfigForConversation } from \"./config.js\";\nimport { ensureDirExists, isRecord, readJsonFileIfExists } from \"./file-guards.js\";\nimport { DockerContainerManager, type ContainerMount } from \"./provisioner.js\";\nimport { createExecutor, type Executor, type SandboxConfig } from \"./sandbox/index.js\";\nimport { reportUserFacingError } from \"./sentry.js\";\nimport { normalizeSharedVaultName, type ResolvedVault, type VaultManager } from \"./vault.js\";\nimport { resolveActorVaultKey } from \"./vault-routing.js\";\n\nexport interface ActorContext {\n platform: string;\n userId: string;\n conversationId: string;\n}\n\nexport type ImageWorkspaceMountMode = \"private\" | \"full\";\n\nexport function readConversationWorkspaceMountMode(\n workspaceDir: string | undefined,\n conversationId: string,\n): ImageWorkspaceMountMode {\n const globalDefault = readGlobalWorkspaceMountMode();\n if (!workspaceDir) {\n return globalDefault;\n }\n\n const conversationDir = join(workspaceDir, conversationId);\n try {\n return (\n loadAgentConfigForConversation(conversationDir).sandboxImageWorkspaceMount ?? globalDefault\n );\n } catch {\n const conversationSettingsPath = join(conversationDir, \"settings.json\");\n const raw = readConversationSettingsFallback(conversationSettingsPath);\n return raw?.sandbox?.image?.workspaceMount ?? globalDefault;\n }\n}\n\nfunction readGlobalWorkspaceMountMode(): ImageWorkspaceMountMode {\n try {\n return loadAgentConfig().sandboxImageWorkspaceMount ?? \"private\";\n } catch {\n return \"private\";\n }\n}\n\nfunction readConversationSettingsFallback(\n settingsPath: string,\n): { sandbox?: { image?: { workspaceMount?: ImageWorkspaceMountMode } } } | undefined {\n try {\n return readJsonFileIfExists(\n settingsPath,\n (value): value is { sandbox?: { image?: { workspaceMount?: ImageWorkspaceMountMode } } } =>\n isRecord(value),\n () => \"Ignoring malformed conversation settings file while resolving workspace mount\",\n );\n } catch {\n return undefined;\n }\n}\n\nexport class ActorExecutionResolver {\n private readonly ensuredConversationDirs = new Set<string>();\n\n constructor(\n private baseConfig: SandboxConfig,\n private vaultManager: VaultManager,\n private provisioner?: DockerContainerManager,\n private workspaceDir?: string,\n ) {}\n\n async resolve(context: ActorContext): Promise<Executor> {\n const vaultKey = resolveActorVaultKey(this.baseConfig, context.userId, context.conversationId);\n this.ensureDefaultSharedVault(vaultKey);\n\n const vault = this.vaultManager.resolve(vaultKey);\n const config = this.resolveSandboxConfig(vaultKey);\n const env =\n config.type !== \"host\" && vault && Object.keys(vault.env).length > 0 ? vault.env : undefined;\n return createExecutor(\n config,\n env,\n this.buildEnsureReadyCallback(vaultKey, context.conversationId, config, vault),\n );\n }\n\n private ensureDefaultSharedVault(vaultKey: string): void {\n if (this.baseConfig.type !== \"image\" && this.baseConfig.type !== \"cloudflare\") return;\n if (this.vaultManager.hasEntry(vaultKey)) return;\n\n let profile: string | undefined;\n try {\n profile = loadAgentConfig().defaultSharedVault;\n } catch {\n return;\n }\n if (!profile || normalizeSharedVaultName(profile) !== profile) return;\n\n try {\n this.vaultManager.copySharedVaultTo(profile, vaultKey);\n } catch (err) {\n reportUserFacingError(err, {\n domain: \"sandbox\",\n surface: \"vault_injection\",\n operation: \"copy_default_shared_vault\",\n severity: \"warning\",\n context: { vaultKey, profile, fatal: false },\n });\n }\n }\n\n private resolveSandboxConfig(vaultKey: string): SandboxConfig {\n const config = this.vaultManager.getSandboxConfig(vaultKey, this.baseConfig);\n if (this.baseConfig.type !== \"image\") {\n return config;\n }\n\n if (config.type === \"container\") {\n return config;\n }\n\n return {\n type: \"container\",\n container: DockerContainerManager.containerName(vaultKey),\n };\n }\n\n private buildEnsureReadyCallback(\n vaultKey: string,\n conversationId: string,\n config: SandboxConfig,\n vault?: ResolvedVault,\n ): (() => Promise<void>) | undefined {\n if (this.baseConfig.type !== \"image\" || config.type !== \"container\") {\n return undefined;\n }\n\n return async () => {\n const expected = config.container || DockerContainerManager.containerName(vaultKey);\n let actual: string | undefined;\n try {\n actual = await this.provisioner?.provision(vaultKey, {\n containerName: expected,\n mounts: this.resolveMounts(conversationId, vault),\n conversationId,\n });\n } catch (err) {\n reportUserFacingError(err, {\n domain: \"sandbox\",\n surface: \"sandbox_provision\",\n operation: \"ensure_image_container_ready\",\n severity: \"error\",\n context: {\n sandboxType: \"image\",\n resolvedSandboxType: config.type,\n conversationId,\n vaultKey,\n expectedContainer: expected,\n hasVault: Boolean(vault),\n },\n });\n throw err;\n }\n if (actual && actual !== expected) {\n throw new Error(\n `Provisioner returned container \"${actual}\" for container key \"${vaultKey}\", expected \"${expected}\"`,\n );\n }\n };\n }\n\n private resolveMounts(conversationId: string, vault?: ResolvedVault): ContainerMount[] {\n const mountsByTarget = new Map<string, ContainerMount>();\n for (const mount of this.buildImageSandboxMounts(conversationId)) {\n mountsByTarget.set(mount.target, mount);\n }\n for (const mount of vault?.mounts ?? []) {\n if (!existsSync(mount.source)) {\n reportUserFacingError(new Error(\"Vault mount source is missing\"), {\n domain: \"sandbox\",\n surface: \"vault_injection\",\n operation: \"resolve_mounts\",\n severity: \"warning\",\n context: {\n sandboxType: \"image\",\n conversationId,\n target: mount.target,\n hasVault: Boolean(vault),\n },\n });\n continue;\n }\n mountsByTarget.set(mount.target, { source: mount.source, target: mount.target });\n }\n return [...mountsByTarget.values()];\n }\n\n private buildImageSandboxMounts(conversationId: string): ContainerMount[] {\n if (!this.workspaceDir) {\n return [];\n }\n\n if (readConversationWorkspaceMountMode(this.workspaceDir, conversationId) === \"full\") {\n return [{ source: this.workspaceDir, target: \"/workspace\" }];\n }\n\n const conversationDir = join(this.workspaceDir, conversationId);\n if (!this.ensuredConversationDirs.has(conversationId)) {\n ensureDirExists(conversationDir);\n this.ensuredConversationDirs.add(conversationId);\n }\n\n return [\n { source: join(this.workspaceDir, \"MEMORY.md\"), target: \"/workspace/MEMORY.md\" },\n { source: join(this.workspaceDir, \"skills\"), target: \"/workspace/skills\" },\n { source: join(this.workspaceDir, \"events\"), target: \"/workspace/events\" },\n { source: conversationDir, target: `/workspace/${conversationId}` },\n ];\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"execution-resolver.js","sourceRoot":"","sources":["../src/execution-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"fs\";\nimport { join } from \"path\";\nimport { loadAgentConfig, loadAgentConfigForConversation } from \"./config.js\";\nimport { ensureDirExists, isRecord, readJsonFileIfExists } from \"./file-guards.js\";\nimport { DockerContainerManager, type ContainerMount } from \"./provisioner.js\";\nimport { createExecutor, type Executor, type SandboxConfig } from \"./sandbox/index.js\";\nimport { reportUserFacingError } from \"./sentry.js\";\nimport { normalizeSharedVaultName, type ResolvedVault, type VaultManager } from \"./vault.js\";\nimport { resolveActorVaultKey } from \"./vault-routing.js\";\n\nexport interface ActorContext {\n platform: string;\n userId: string;\n conversationId: string;\n}\n\nexport type ImageWorkspaceMountMode = \"private\" | \"full\";\n\nexport function readConversationWorkspaceMountMode(\n workspaceDir: string | undefined,\n conversationId: string,\n): ImageWorkspaceMountMode {\n const globalDefault = readGlobalWorkspaceMountMode();\n if (!workspaceDir) {\n return globalDefault;\n }\n\n const conversationDir = join(workspaceDir, conversationId);\n try {\n return (\n loadAgentConfigForConversation(conversationDir).sandboxImageWorkspaceMount ?? globalDefault\n );\n } catch {\n const conversationSettingsPath = join(conversationDir, \"settings.json\");\n const raw = readConversationSettingsFallback(conversationSettingsPath);\n return raw?.sandbox?.image?.workspaceMount ?? globalDefault;\n }\n}\n\nfunction readGlobalWorkspaceMountMode(): ImageWorkspaceMountMode {\n try {\n return loadAgentConfig().sandboxImageWorkspaceMount ?? \"private\";\n } catch {\n return \"private\";\n }\n}\n\nfunction readConversationSettingsFallback(\n settingsPath: string,\n): { sandbox?: { image?: { workspaceMount?: ImageWorkspaceMountMode } } } | undefined {\n try {\n return readJsonFileIfExists(\n settingsPath,\n (value): value is { sandbox?: { image?: { workspaceMount?: ImageWorkspaceMountMode } } } =>\n isRecord(value),\n () => \"Ignoring malformed conversation settings file while resolving workspace mount\",\n );\n } catch {\n return undefined;\n }\n}\n\nexport class ActorExecutionResolver {\n private readonly ensuredConversationDirs = new Set<string>();\n\n constructor(\n private baseConfig: SandboxConfig,\n private vaultManager: VaultManager,\n private provisioner?: DockerContainerManager,\n private workspaceDir?: string,\n ) {}\n\n async resolve(context: ActorContext): Promise<Executor> {\n const vaultKey = resolveActorVaultKey(this.baseConfig, context.userId, context.conversationId);\n this.ensureDefaultSharedVault(vaultKey);\n\n const vault = this.vaultManager.resolve(vaultKey);\n const config = this.resolveSandboxConfig(vaultKey);\n const env =\n config.type !== \"host\" && vault && Object.keys(vault.env).length > 0 ? vault.env : undefined;\n return createExecutor(\n config,\n env,\n this.buildEnsureReadyCallback(vaultKey, context.conversationId, config, vault),\n );\n }\n\n private ensureDefaultSharedVault(vaultKey: string): void {\n if (this.baseConfig.type !== \"image\" && this.baseConfig.type !== \"cloudflare\") return;\n if (this.vaultManager.hasEntry(vaultKey)) return;\n\n let profile: string | undefined;\n try {\n profile = loadAgentConfig().defaultSharedVault;\n } catch {\n return;\n }\n if (!profile || normalizeSharedVaultName(profile) !== profile) return;\n\n this.vaultManager.copySharedVaultTo(profile, vaultKey);\n }\n\n private resolveSandboxConfig(vaultKey: string): SandboxConfig {\n const config = this.vaultManager.getSandboxConfig(vaultKey, this.baseConfig);\n if (this.baseConfig.type !== \"image\") {\n return config;\n }\n\n if (config.type === \"container\") {\n return config;\n }\n\n return {\n type: \"container\",\n container: DockerContainerManager.containerName(vaultKey),\n };\n }\n\n private buildEnsureReadyCallback(\n vaultKey: string,\n conversationId: string,\n config: SandboxConfig,\n vault?: ResolvedVault,\n ): (() => Promise<void>) | undefined {\n if (this.baseConfig.type !== \"image\" || config.type !== \"container\") {\n return undefined;\n }\n\n return async () => {\n const expected = config.container || DockerContainerManager.containerName(vaultKey);\n let actual: string | undefined;\n try {\n actual = await this.provisioner?.provision(vaultKey, {\n containerName: expected,\n mounts: this.resolveMounts(conversationId, vault),\n conversationId,\n });\n } catch (err) {\n reportUserFacingError(err, {\n domain: \"sandbox\",\n surface: \"sandbox_provision\",\n operation: \"ensure_image_container_ready\",\n severity: \"error\",\n context: {\n sandboxType: \"image\",\n resolvedSandboxType: config.type,\n conversationId,\n vaultKey,\n expectedContainer: expected,\n hasVault: Boolean(vault),\n },\n });\n throw err;\n }\n if (actual && actual !== expected) {\n throw new Error(\n `Provisioner returned container \"${actual}\" for container key \"${vaultKey}\", expected \"${expected}\"`,\n );\n }\n };\n }\n\n private resolveMounts(conversationId: string, vault?: ResolvedVault): ContainerMount[] {\n const mountsByTarget = new Map<string, ContainerMount>();\n for (const mount of this.buildImageSandboxMounts(conversationId)) {\n mountsByTarget.set(mount.target, mount);\n }\n for (const mount of vault?.mounts ?? []) {\n if (!existsSync(mount.source)) {\n reportUserFacingError(new Error(\"Vault mount source is missing\"), {\n domain: \"sandbox\",\n surface: \"vault_injection\",\n operation: \"resolve_mounts\",\n severity: \"warning\",\n context: {\n sandboxType: \"image\",\n conversationId,\n target: mount.target,\n hasVault: Boolean(vault),\n },\n });\n continue;\n }\n mountsByTarget.set(mount.target, { source: mount.source, target: mount.target });\n }\n return [...mountsByTarget.values()];\n }\n\n private buildImageSandboxMounts(conversationId: string): ContainerMount[] {\n if (!this.workspaceDir) {\n return [];\n }\n\n if (readConversationWorkspaceMountMode(this.workspaceDir, conversationId) === \"full\") {\n return [{ source: this.workspaceDir, target: \"/workspace\" }];\n }\n\n const conversationDir = join(this.workspaceDir, conversationId);\n if (!this.ensuredConversationDirs.has(conversationId)) {\n ensureDirExists(conversationDir);\n this.ensuredConversationDirs.add(conversationId);\n }\n\n return [\n { source: join(this.workspaceDir, \"MEMORY.md\"), target: \"/workspace/MEMORY.md\" },\n { source: join(this.workspaceDir, \"skills\"), target: \"/workspace/skills\" },\n { source: join(this.workspaceDir, \"events\"), target: \"/workspace/events\" },\n { source: conversationDir, target: `/workspace/${conversationId}` },\n ];\n }\n}\n"]}
|