@geminixiang/mama 0.2.0-beta.3 → 0.2.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +101 -422
  2. package/dist/adapter.d.ts +9 -0
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js.map +1 -1
  5. package/dist/adapters/discord/bot.d.ts +1 -0
  6. package/dist/adapters/discord/bot.d.ts.map +1 -1
  7. package/dist/adapters/discord/bot.js +62 -73
  8. package/dist/adapters/discord/bot.js.map +1 -1
  9. package/dist/adapters/discord/context.d.ts.map +1 -1
  10. package/dist/adapters/discord/context.js +9 -2
  11. package/dist/adapters/discord/context.js.map +1 -1
  12. package/dist/adapters/shared.d.ts +48 -0
  13. package/dist/adapters/shared.d.ts.map +1 -1
  14. package/dist/adapters/shared.js +111 -0
  15. package/dist/adapters/shared.js.map +1 -1
  16. package/dist/adapters/slack/bot.d.ts +3 -19
  17. package/dist/adapters/slack/bot.d.ts.map +1 -1
  18. package/dist/adapters/slack/bot.js +58 -188
  19. package/dist/adapters/slack/bot.js.map +1 -1
  20. package/dist/adapters/slack/context.d.ts.map +1 -1
  21. package/dist/adapters/slack/context.js +13 -3
  22. package/dist/adapters/slack/context.js.map +1 -1
  23. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  24. package/dist/adapters/telegram/bot.js +78 -100
  25. package/dist/adapters/telegram/bot.js.map +1 -1
  26. package/dist/adapters/telegram/context.d.ts.map +1 -1
  27. package/dist/adapters/telegram/context.js +9 -2
  28. package/dist/adapters/telegram/context.js.map +1 -1
  29. package/dist/agent.d.ts.map +1 -1
  30. package/dist/agent.js +15 -5
  31. package/dist/agent.js.map +1 -1
  32. package/dist/bindings.d.ts +2 -1
  33. package/dist/bindings.d.ts.map +1 -1
  34. package/dist/bindings.js +3 -2
  35. package/dist/bindings.js.map +1 -1
  36. package/dist/commands/index.d.ts +5 -0
  37. package/dist/commands/index.d.ts.map +1 -0
  38. package/dist/commands/index.js +8 -0
  39. package/dist/commands/index.js.map +1 -0
  40. package/dist/commands/login.d.ts +5 -0
  41. package/dist/commands/login.d.ts.map +1 -0
  42. package/dist/commands/login.js +37 -0
  43. package/dist/commands/login.js.map +1 -0
  44. package/dist/commands/registry.d.ts +7 -0
  45. package/dist/commands/registry.d.ts.map +1 -0
  46. package/dist/commands/registry.js +14 -0
  47. package/dist/commands/registry.js.map +1 -0
  48. package/dist/commands/session-view.d.ts +5 -0
  49. package/dist/commands/session-view.d.ts.map +1 -0
  50. package/dist/commands/session-view.js +38 -0
  51. package/dist/commands/session-view.js.map +1 -0
  52. package/dist/commands/types.d.ts +41 -0
  53. package/dist/commands/types.d.ts.map +1 -0
  54. package/dist/commands/types.js +2 -0
  55. package/dist/commands/types.js.map +1 -0
  56. package/dist/commands/utils.d.ts +5 -0
  57. package/dist/commands/utils.d.ts.map +1 -0
  58. package/dist/commands/utils.js +9 -0
  59. package/dist/commands/utils.js.map +1 -0
  60. package/dist/config.d.ts +4 -4
  61. package/dist/config.d.ts.map +1 -1
  62. package/dist/config.js +37 -42
  63. package/dist/config.js.map +1 -1
  64. package/dist/context.d.ts.map +1 -1
  65. package/dist/context.js +74 -68
  66. package/dist/context.js.map +1 -1
  67. package/dist/execution-resolver.d.ts +6 -3
  68. package/dist/execution-resolver.d.ts.map +1 -1
  69. package/dist/execution-resolver.js +47 -14
  70. package/dist/execution-resolver.js.map +1 -1
  71. package/dist/fs-atomic.d.ts +10 -0
  72. package/dist/fs-atomic.d.ts.map +1 -0
  73. package/dist/fs-atomic.js +45 -0
  74. package/dist/fs-atomic.js.map +1 -0
  75. package/dist/index.d.ts +7 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +4 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/instrument.d.ts.map +1 -1
  80. package/dist/instrument.js +2 -3
  81. package/dist/instrument.js.map +1 -1
  82. package/dist/login/index.d.ts.map +1 -1
  83. package/dist/login/index.js +19 -8
  84. package/dist/login/index.js.map +1 -1
  85. package/dist/login/portal.d.ts.map +1 -1
  86. package/dist/login/portal.js +7 -7
  87. package/dist/login/portal.js.map +1 -1
  88. package/dist/login/session.d.ts +3 -2
  89. package/dist/login/session.d.ts.map +1 -1
  90. package/dist/login/session.js.map +1 -1
  91. package/dist/main.d.ts.map +1 -1
  92. package/dist/main.js +63 -389
  93. package/dist/main.js.map +1 -1
  94. package/dist/provisioner.d.ts +11 -9
  95. package/dist/provisioner.d.ts.map +1 -1
  96. package/dist/provisioner.js +125 -87
  97. package/dist/provisioner.js.map +1 -1
  98. package/dist/runtime/index.d.ts +2 -0
  99. package/dist/runtime/index.d.ts.map +1 -0
  100. package/dist/runtime/index.js +2 -0
  101. package/dist/runtime/index.js.map +1 -0
  102. package/dist/runtime/session-runtime.d.ts +26 -0
  103. package/dist/runtime/session-runtime.d.ts.map +1 -0
  104. package/dist/runtime/session-runtime.js +285 -0
  105. package/dist/runtime/session-runtime.js.map +1 -0
  106. package/dist/sandbox/cloudflare.d.ts +14 -0
  107. package/dist/sandbox/cloudflare.d.ts.map +1 -0
  108. package/dist/sandbox/cloudflare.js +131 -0
  109. package/dist/sandbox/cloudflare.js.map +1 -0
  110. package/dist/sandbox/index.d.ts +6 -4
  111. package/dist/sandbox/index.d.ts.map +1 -1
  112. package/dist/sandbox/index.js +6 -3
  113. package/dist/sandbox/index.js.map +1 -1
  114. package/dist/sandbox/types.d.ts +5 -1
  115. package/dist/sandbox/types.d.ts.map +1 -1
  116. package/dist/sandbox/types.js.map +1 -1
  117. package/dist/session-store.d.ts +5 -1
  118. package/dist/session-store.d.ts.map +1 -1
  119. package/dist/session-store.js +14 -9
  120. package/dist/session-store.js.map +1 -1
  121. package/dist/session-view/portal.d.ts +2 -0
  122. package/dist/session-view/portal.d.ts.map +1 -1
  123. package/dist/session-view/portal.js +45 -7
  124. package/dist/session-view/portal.js.map +1 -1
  125. package/dist/session-view/service.d.ts.map +1 -1
  126. package/dist/session-view/service.js +94 -48
  127. package/dist/session-view/service.js.map +1 -1
  128. package/dist/session-view/store.d.ts +3 -2
  129. package/dist/session-view/store.d.ts.map +1 -1
  130. package/dist/session-view/store.js.map +1 -1
  131. package/dist/vault-routing.d.ts +3 -5
  132. package/dist/vault-routing.d.ts.map +1 -1
  133. package/dist/vault-routing.js +8 -20
  134. package/dist/vault-routing.js.map +1 -1
  135. package/dist/vault.d.ts +7 -5
  136. package/dist/vault.d.ts.map +1 -1
  137. package/dist/vault.js +111 -104
  138. package/dist/vault.js.map +1 -1
  139. package/package.json +7 -9
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\nimport \"./instrument.js\";\n\nimport { join, resolve } from \"path\";\nimport { mkdirSync, readFileSync, statSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { fileURLToPath } from \"url\";\nimport { dirname, join as pathJoin } from \"path\";\nimport type { Bot, BotAdapters, BotEvent, BotHandler } from \"./adapter.js\";\nimport { DiscordBot } from \"./adapters/discord/index.js\";\nimport { TelegramBot } from \"./adapters/telegram/index.js\";\nimport { SlackBot as SlackBotClass } from \"./adapters/slack/index.js\";\nimport { type AgentRunner, createRunner } from \"./agent.js\";\nimport {\n createManagedSessionFile,\n createManagedSessionFileAtPath,\n getChannelSessionDir,\n getThreadSessionFile,\n resolveGenericSessionScope,\n type ResolvedSessionScope,\n} from \"./session-store.js\";\nimport { downloadChannel } from \"./download.js\";\nimport { createEventsWatcher } from \"./events.js\";\nimport * as log from \"./log.js\";\nimport { FileUserBindingStore } from \"./bindings.js\";\nimport { parseLoginCommand } from \"./login/index.js\";\nimport { startLinkServer } from \"./login/portal.js\";\nimport { InMemoryLinkTokenStore } from \"./login/session.js\";\nimport { parseSessionViewCommand } from \"./session-view/command.js\";\nimport { resolveExistingSessionFile } from \"./session-view/service.js\";\nimport { InMemorySessionViewTokenStore } from \"./session-view/store.js\";\nimport { DockerContainerManager } from \"./provisioner.js\";\nimport { loadAgentConfig } from \"./config.js\";\nimport { SandboxError, parseSandboxArg, type SandboxConfig, validateSandbox } from \"./sandbox.js\";\nimport { FileVaultManager } from \"./vault.js\";\nimport {\n createManagedVaultEntry,\n ensureSandboxVaultEntry,\n resolveActorVaultKey,\n} from \"./vault-routing.js\";\nimport { addLifecycleBreadcrumb, applyRunScope } from \"./sentry.js\";\nimport { ChannelStore } from \"./store.js\";\nimport { formatNothingRunning, formatStopped, formatStopping } from \"./ui-copy.js\";\nimport {\n hasMaterializedSlackBranchSession,\n resolveSlackSessionScope,\n waitForSlackBranchBootstrap,\n} from \"./adapters/slack/branch-manager.js\";\nimport * as Sentry from \"@sentry/node\";\n\n// ============================================================================\n// Config\n// ============================================================================\n\n// Get version from package.json\nfunction getVersion(): string {\n // Try to find package.json in the dist directory or parent\n const possiblePaths = [\n pathJoin(dirname(fileURLToPath(import.meta.url)), \"package.json\"),\n pathJoin(dirname(fileURLToPath(import.meta.url)), \"..\", \"package.json\"),\n pathJoin(process.cwd(), \"package.json\"),\n ];\n\n for (const pkgPath of possiblePaths) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n if (pkg.version) return pkg.version;\n } catch {\n // Continue to next path\n }\n }\n return \"unknown\";\n}\n\nconst MOM_SLACK_APP_TOKEN = process.env.MOM_SLACK_APP_TOKEN;\nconst MOM_SLACK_BOT_TOKEN = process.env.MOM_SLACK_BOT_TOKEN;\nconst MOM_TELEGRAM_BOT_TOKEN = process.env.MOM_TELEGRAM_BOT_TOKEN;\nconst MOM_DISCORD_BOT_TOKEN = process.env.MOM_DISCORD_BOT_TOKEN;\nconst MOM_LINK_URL = process.env.MOM_LINK_URL;\nconst MOM_LINK_PORT = process.env.MOM_LINK_PORT\n ? parseInt(process.env.MOM_LINK_PORT, 10)\n : MOM_LINK_URL\n ? 8181\n : undefined;\n\ninterface ParsedArgs {\n workingDir?: string;\n stateDir?: string;\n sandbox: SandboxConfig;\n downloadChannel?: string;\n showVersion?: boolean;\n}\n\nfunction parseArgs(): ParsedArgs {\n const args = process.argv.slice(2);\n let sandbox: SandboxConfig = { type: \"host\" };\n let workingDir: string | undefined;\n let stateDirArg: string | undefined;\n let downloadChannelId: string | undefined;\n let showVersion = false;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === \"--version\" || arg === \"-v\" || arg === \"-V\") {\n showVersion = true;\n } else if (arg.startsWith(\"--sandbox=\")) {\n sandbox = parseSandboxArg(arg.slice(\"--sandbox=\".length));\n } else if (arg === \"--sandbox\") {\n sandbox = parseSandboxArg(args[++i] || \"\");\n } else if (arg.startsWith(\"--state-dir=\")) {\n stateDirArg = arg.slice(\"--state-dir=\".length);\n } else if (arg === \"--state-dir\") {\n stateDirArg = args[++i];\n } else if (arg.startsWith(\"--download=\")) {\n downloadChannelId = arg.slice(\"--download=\".length);\n } else if (arg === \"--download\") {\n downloadChannelId = args[++i];\n } else if (!arg.startsWith(\"-\")) {\n workingDir = arg;\n }\n }\n\n return {\n workingDir: workingDir ? resolve(workingDir) : undefined,\n stateDir: stateDirArg ? resolve(stateDirArg) : undefined,\n sandbox,\n downloadChannel: downloadChannelId,\n showVersion,\n };\n}\n\nconst WORLD_WRITABLE_MODE = 0o002;\n\nfunction ensureSecureStateDir(path: string): void {\n let stat;\n try {\n stat = statSync(path);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") {\n mkdirSync(path, { recursive: true, mode: 0o700 });\n return;\n }\n console.error(`Error: cannot access --state-dir ${path}: ${(err as Error).message}`);\n process.exit(1);\n }\n\n if (!stat.isDirectory()) {\n console.error(`Error: --state-dir ${path} exists but is not a directory`);\n process.exit(1);\n }\n\n if (stat.mode & WORLD_WRITABLE_MODE) {\n console.error(\n `Error: --state-dir ${path} is world-writable (mode ${(stat.mode & 0o777).toString(8)}). ` +\n `Credentials stored there would be exposed to other local users. ` +\n `Fix with: chmod 0700 ${path}`,\n );\n process.exit(1);\n }\n\n const euid = typeof process.geteuid === \"function\" ? process.geteuid() : undefined;\n if (euid !== undefined && stat.uid !== euid) {\n console.error(\n `Error: --state-dir ${path} is owned by uid ${stat.uid} but mama is running as uid ${euid}. ` +\n `Run mama as the directory owner or point --state-dir at a directory you own.`,\n );\n process.exit(1);\n }\n}\n\nfunction handleStartupError(error: unknown): never {\n if (error instanceof SandboxError) {\n for (const line of error.formatForCli()) {\n console.error(line);\n }\n process.exit(1);\n }\n throw error;\n}\n\nlet parsedArgs: ParsedArgs;\ntry {\n parsedArgs = parseArgs();\n} catch (error) {\n handleStartupError(error);\n}\n\n// Handle --version\nif (parsedArgs.showVersion) {\n console.log(getVersion());\n process.exit(0);\n}\n\n// Handle --download mode (Slack only)\nif (parsedArgs.downloadChannel) {\n if (!MOM_SLACK_BOT_TOKEN) {\n console.error(\"Missing env: MOM_SLACK_BOT_TOKEN\");\n process.exit(1);\n }\n await downloadChannel(parsedArgs.downloadChannel, MOM_SLACK_BOT_TOKEN);\n process.exit(0);\n}\n\n// Normal bot mode - require working dir\nif (!parsedArgs.workingDir) {\n console.error(\n \"Usage: mama [--state-dir=<dir>] [--sandbox=host|container:<name>|image:<image>|firecracker:<vm-id>:<host-path>] <working-directory>\",\n );\n console.error(\" mama --download <channel-id>\");\n process.exit(1);\n}\n\nconst { workingDir, sandbox } = { workingDir: parsedArgs.workingDir, sandbox: parsedArgs.sandbox };\nconst stateDir = parsedArgs.stateDir ?? join(homedir(), \".mama\");\nprocess.env.MAMA_STATE_DIR = stateDir;\nensureSecureStateDir(stateDir);\n\n// Validate platform tokens\nconst hasSlack = !!(MOM_SLACK_APP_TOKEN && MOM_SLACK_BOT_TOKEN);\nconst hasTelegram = !!MOM_TELEGRAM_BOT_TOKEN;\nconst hasDiscord = !!MOM_DISCORD_BOT_TOKEN;\n\nif (!hasSlack && !hasTelegram && !hasDiscord) {\n console.error(\n \"No platform tokens found. Set one of:\\n\" +\n \" Slack: MOM_SLACK_APP_TOKEN + MOM_SLACK_BOT_TOKEN\\n\" +\n \" Telegram: MOM_TELEGRAM_BOT_TOKEN\\n\" +\n \" Discord: MOM_DISCORD_BOT_TOKEN\",\n );\n process.exit(1);\n}\n\ntry {\n await validateSandbox(sandbox);\n} catch (error) {\n handleStartupError(error);\n}\n\nconst vaultManager = new FileVaultManager(stateDir);\nif (vaultManager.isEnabled()) {\n console.log(\n sandbox.type === \"container\"\n ? \" Vault system enabled. Container vault active.\"\n : sandbox.type === \"image\" || sandbox.type === \"firecracker\"\n ? \" Vault system enabled. Per-user credential routing active.\"\n : \" Vault system enabled. Host mode will not inject vault env.\",\n );\n}\n\nconst bindingStore = new FileUserBindingStore(stateDir);\nif (bindingStore.isEnabled()) {\n console.log(\n sandbox.type === \"container\"\n ? \" Binding store enabled. Container mode uses the container vault.\"\n : sandbox.type === \"image\" || sandbox.type === \"firecracker\"\n ? \" Binding store enabled. Platform user → vault routing active.\"\n : \" Binding store enabled. Host mode will not inject vault env.\",\n );\n}\n\nconst startupConfig = loadAgentConfig(workingDir);\nconst sandboxLimits =\n startupConfig.sandboxCpus || startupConfig.sandboxMemory\n ? { cpus: startupConfig.sandboxCpus, memory: startupConfig.sandboxMemory }\n : undefined;\n\nconst provisioner =\n sandbox.type === \"image\"\n ? new DockerContainerManager(sandbox.image, workingDir, { limits: sandboxLimits })\n : undefined;\n\nconst linkTokenStore = new InMemoryLinkTokenStore();\nconst sessionViewTokenStore = new InMemorySessionViewTokenStore();\nsetInterval(() => linkTokenStore.purge(), 5 * 60 * 1000).unref();\nsetInterval(() => sessionViewTokenStore.purge(), 5 * 60 * 1000).unref();\n\nfunction normalizePortalBaseUrl(): string | undefined {\n if (MOM_LINK_URL) {\n return MOM_LINK_URL.replace(/\\/+$/, \"\");\n }\n if (MOM_LINK_PORT) {\n return `http://localhost:${MOM_LINK_PORT}`;\n }\n return undefined;\n}\n\nfunction isPrivateConversation(event: BotEvent): boolean {\n return event.conversationKind === \"direct\" || event.type === \"dm\";\n}\n\nfunction ensureLoginVault(platform: string, platformUserId: string): string {\n const vaultId = resolveActorVaultKey(\n sandbox,\n vaultManager,\n bindingStore,\n platform,\n platformUserId,\n );\n\n ensureSandboxVaultEntry(sandbox, vaultManager, platform, platformUserId, vaultId);\n if (sandbox.type !== \"container\" && sandbox.type !== \"image\") {\n vaultManager.addEntry(vaultId, createManagedVaultEntry(platform, platformUserId, vaultId));\n }\n\n return vaultId;\n}\n\nasync function replyWithContext(\n responseCtx: BotAdapters[\"responseCtx\"],\n text: string,\n): Promise<void> {\n await responseCtx.setTyping(false);\n await responseCtx.setWorking(false);\n await responseCtx.respond(text);\n}\n\nasync function handleLoginCommand(\n platform: string,\n platformUserId: string,\n conversationId: string,\n responseCtx: BotAdapters[\"responseCtx\"],\n commandText: string,\n privateConversation: boolean,\n): Promise<boolean> {\n const parsed = parseLoginCommand(commandText);\n if (!parsed) return false;\n\n if (!privateConversation) {\n await replyWithContext(\n responseCtx,\n \"為了保護你的憑證,`/login` 只能在與機器人的私訊中使用。請先私訊機器人,再重新執行 `/login`。\",\n );\n return true;\n }\n\n const baseUrl = normalizePortalBaseUrl();\n if (!baseUrl) {\n await replyWithContext(\n responseCtx,\n \"Login is not configured. Set `MOM_LINK_URL` or `MOM_LINK_PORT` on the server.\",\n );\n return true;\n }\n\n let vaultId: string;\n try {\n vaultId = ensureLoginVault(platform, platformUserId);\n } catch (error) {\n log.logWarning(\n `[${conversationId}] Failed to prepare login vault for ${platform}/${platformUserId}`,\n error instanceof Error ? error.message : String(error),\n );\n await replyWithContext(\n responseCtx,\n \"Login setup failed on the server. 請稍後重試,或聯絡管理員檢查 vault 儲存權限。\",\n );\n return true;\n }\n\n const token = linkTokenStore.create(\n platform as \"slack\" | \"discord\" | \"telegram\",\n platformUserId,\n conversationId,\n vaultId,\n \"\",\n );\n const vaultLabel = sandbox.type === \"container\" ? `container vault (${vaultId})` : \"your vault\";\n await replyWithContext(\n responseCtx,\n `Open this link to store credentials in ${vaultLabel} (expires in 15 minutes):\\n${baseUrl}/link?token=${token.token}`,\n );\n return true;\n}\n\nasync function handleSessionViewCommand(\n platform: string,\n platformUserId: string,\n conversationId: string,\n sessionKey: string,\n bot: Bot,\n responseCtx: BotAdapters[\"responseCtx\"],\n commandText: string,\n privateConversation: boolean,\n): Promise<boolean> {\n if (!parseSessionViewCommand(commandText)) return false;\n\n const allowSharedPrivateDelivery = platform === \"slack\" || platform === \"discord\";\n const sendSessionViewReply = async (text: string): Promise<void> => {\n if (privateConversation) {\n await replyWithContext(responseCtx, text);\n return;\n }\n\n if (platform === \"slack\" && bot instanceof SlackBotClass) {\n await bot.postEphemeral(conversationId, platformUserId, text);\n return;\n }\n\n if (platform === \"discord\" && bot instanceof DiscordBot) {\n await bot.sendDirectMessage(platformUserId, text);\n return;\n }\n\n await replyWithContext(responseCtx, text);\n };\n\n if (!privateConversation && !allowSharedPrivateDelivery) {\n await sendSessionViewReply(\n \"為了保護對話內容,`/session` 目前只能在與機器人的私訊 / DM 中使用。\",\n );\n return true;\n }\n\n const baseUrl = normalizePortalBaseUrl();\n if (!baseUrl) {\n await sendSessionViewReply(\n \"Session viewer is not configured. Set `MOM_LINK_URL` or `MOM_LINK_PORT` on the server.\",\n );\n return true;\n }\n\n const sessionFile = resolveExistingSessionFile(workingDir, conversationId, sessionKey);\n if (!sessionFile) {\n await sendSessionViewReply(\n \"目前還沒有可查看的 session。先和機器人對話一次,建立 session 後再試。\",\n );\n return true;\n }\n\n const token = sessionViewTokenStore.create(\n platform as \"slack\" | \"discord\" | \"telegram\",\n platformUserId,\n conversationId,\n sessionKey,\n sessionFile,\n );\n\n const linkText = `Open this read-only session link (expires in 24 hours):\\n${baseUrl}/session?token=${token.token}`;\n await sendSessionViewReply(linkText);\n return true;\n}\n\n// ============================================================================\n// State (per conversation)\n// ============================================================================\n\ninterface ConversationState {\n running: boolean;\n runner: AgentRunner;\n stopRequested: boolean;\n stopMessageTs?: string;\n lastAccessedAt: number;\n startedAt?: number;\n lastActivityAt?: number;\n}\n\nconst conversationStates = new Map<string, ConversationState>();\n\n/** Track in-flight runs for graceful shutdown */\nconst inFlightRuns = new Set<Promise<void>>();\n\n/** Flag to stop accepting new events during shutdown */\nlet isShuttingDown = false;\n\n/** Maximum number of cached sessions */\nconst MAX_SESSIONS = 500;\n/** Idle timeout before a non-running session can be evicted (1 hour) */\nconst IDLE_TIMEOUT_MS = 3600000;\n/** Idle timeout for managed image containers (10 minutes) */\nconst IMAGE_IDLE_TIMEOUT_MS = 10 * 60 * 1000;\n\nif (provisioner) {\n await provisioner.reconcile();\n await provisioner.stopIdle(IMAGE_IDLE_TIMEOUT_MS);\n setInterval(() => provisioner.stopIdle(IMAGE_IDLE_TIMEOUT_MS), IMAGE_IDLE_TIMEOUT_MS).unref();\n}\n\nasync function resolveSessionScope(\n platformName: string,\n conversationDir: string,\n sessionKey: string,\n): Promise<ResolvedSessionScope> {\n if (platformName === \"slack\") {\n return resolveSlackSessionScope({ conversationDir, sessionKey });\n }\n return resolveGenericSessionScope({ conversationDir, sessionKey });\n}\n\nasync function getState(\n conversationId: string,\n platformName: string,\n sessionKey?: string,\n): Promise<ConversationState> {\n const key = sessionKey ?? conversationId;\n let state = conversationStates.get(key);\n if (!state) {\n const conversationDir = join(workingDir, conversationId);\n const sessionScope = await resolveSessionScope(platformName, conversationDir, key);\n state = {\n running: false,\n runner: await createRunner(\n sandbox,\n key,\n conversationId,\n conversationDir,\n workingDir,\n sessionScope,\n vaultManager,\n bindingStore,\n provisioner,\n ),\n stopRequested: false,\n lastAccessedAt: Date.now(),\n };\n conversationStates.set(key, state);\n } else {\n state.lastAccessedAt = Date.now();\n }\n return state;\n}\n\n/**\n * Evict idle sessions from conversationStates to bound memory usage.\n * Called after each handleEvent completes.\n */\nfunction evictIdleSessions(): void {\n const now = Date.now();\n\n for (const [key, state] of conversationStates) {\n if (!state.running && now - state.lastAccessedAt > IDLE_TIMEOUT_MS) {\n conversationStates.delete(key);\n }\n }\n\n if (conversationStates.size > MAX_SESSIONS) {\n const idleSessions: Array<{ key: string; lastAccessedAt: number }> = [];\n for (const [key, state] of conversationStates) {\n if (!state.running) {\n idleSessions.push({ key, lastAccessedAt: state.lastAccessedAt });\n }\n }\n\n idleSessions.sort((a, b) => a.lastAccessedAt - b.lastAccessedAt);\n\n const toEvict = conversationStates.size - MAX_SESSIONS;\n for (let i = 0; i < toEvict && i < idleSessions.length; i++) {\n conversationStates.delete(idleSessions[i].key);\n }\n }\n}\n\n// ============================================================================\n// Handler\n// ============================================================================\n\nconst handler: BotHandler = {\n isRunning(sessionKey: string): boolean {\n const state = conversationStates.get(sessionKey);\n return !!state?.running;\n },\n\n getRunningSessions() {\n const sessions: import(\"./adapter.js\").RunningSession[] = [];\n for (const [sessionKey, state] of conversationStates) {\n if (state.running && state.startedAt) {\n // Get current step from runner\n const currentStep = state.runner.getCurrentStep();\n sessions.push({\n sessionKey,\n startedAt: state.startedAt,\n lastActivityAt: state.lastActivityAt,\n currentTool: currentStep?.label || currentStep?.toolName,\n });\n }\n }\n return sessions;\n },\n\n async handleStop(sessionKey: string, conversationId: string, bot: Bot): Promise<void> {\n const state = conversationStates.get(sessionKey);\n if (state?.running) {\n state.stopRequested = true;\n state.runner.abort();\n const ts = await bot.postMessage(conversationId, formatStopping(bot));\n state.stopMessageTs = ts;\n } else {\n await bot.postMessage(conversationId, formatNothingRunning(bot));\n }\n },\n\n forceStop(sessionKey: string): void {\n const state = conversationStates.get(sessionKey);\n if (state?.running) {\n log.logInfo(`[Force Stop] Force stopping session: ${sessionKey}`);\n state.stopRequested = true;\n state.runner.abort();\n state.running = false;\n }\n },\n\n async handleNew(sessionKey: string, conversationId: string, bot: Bot): Promise<void> {\n const state = conversationStates.get(sessionKey);\n if (state?.running) {\n state.stopRequested = true;\n state.runner.abort();\n }\n\n // Conversation sessions rotate via current pointer. Thread sessions reset in place.\n const conversationDir = join(workingDir, conversationId);\n if (sessionKey.includes(\":\")) {\n createManagedSessionFileAtPath(\n getThreadSessionFile(conversationDir, sessionKey),\n conversationDir,\n );\n } else {\n createManagedSessionFile(getChannelSessionDir(conversationDir), conversationDir);\n }\n\n // Remove from in-memory cache\n conversationStates.delete(sessionKey);\n\n log.logInfo(`[${conversationId}] Session reset: ${sessionKey}`);\n await bot.postMessage(conversationId, \"Conversation reset. Send a new message to start fresh.\");\n },\n\n async handleEvent(\n event: BotEvent,\n bot: Bot,\n adapters: BotAdapters,\n _isEvent?: boolean,\n ): Promise<void> {\n const conversationId = event.conversationId;\n\n // Don't accept new events during shutdown\n if (isShuttingDown) {\n log.logInfo(\n `[${conversationId}] Rejected event during shutdown: ${event.text.substring(0, 50)}`,\n );\n return;\n }\n\n const sessionKey = event.sessionKey ?? `${conversationId}:${event.thread_ts ?? event.ts}`;\n const privateConversation = isPrivateConversation(event);\n const handledLogin = await handleLoginCommand(\n adapters.platform.name,\n event.user,\n conversationId,\n adapters.responseCtx,\n event.text,\n privateConversation,\n );\n if (handledLogin) return;\n\n const handledSessionView = await handleSessionViewCommand(\n adapters.platform.name,\n event.user,\n conversationId,\n sessionKey,\n bot,\n adapters.responseCtx,\n event.text,\n privateConversation,\n );\n if (handledSessionView) return;\n\n const conversationDir = join(workingDir, conversationId);\n const waitedForParent =\n adapters.platform.name === \"slack\"\n ? await waitForSlackBranchBootstrap({\n parentSessionKey: conversationId,\n sessionKey,\n hasThreadSession: () => hasMaterializedSlackBranchSession(conversationDir, sessionKey),\n isParentRunning: () => conversationStates.get(conversationId)?.running === true,\n })\n : false;\n if (waitedForParent) {\n log.logInfo(\n `[${conversationId}] Delayed thread bootstrap until parent session sealed: ${sessionKey}`,\n );\n }\n\n const state = await getState(conversationId, adapters.platform.name, sessionKey);\n\n // Start run\n state.running = true;\n state.stopRequested = false;\n state.startedAt = Date.now();\n state.lastActivityAt = Date.now();\n\n log.logInfo(`[${conversationId}] Starting run: ${event.text.substring(0, 50)}`);\n\n // Wrap in-flight run tracking\n Sentry.metrics.count(\"agent.run.started\", 1, {\n attributes: { channel: conversationId },\n });\n Sentry.metrics.gauge(\"agent.sessions.active\", inFlightRuns.size + 1);\n\n const runPromise = Sentry.startSpan(\n { name: \"agent.run\", op: \"agent\", attributes: { conversationId, sessionKey } },\n async () => {\n return Sentry.withScope(async (scope) => {\n const { message, responseCtx, platform } = adapters;\n applyRunScope(scope, {\n conversationId,\n sessionKey,\n messageId: message.id,\n platform: platform.name,\n userId: message.userId,\n userName: message.userName,\n threadTs: message.threadTs,\n isEvent: _isEvent,\n });\n addLifecycleBreadcrumb(\"agent.run.started\", {\n channel_id: conversationId,\n platform: platform.name,\n has_attachments: (message.attachments?.length ?? 0) > 0,\n });\n\n try {\n await responseCtx.setTyping(true);\n await responseCtx.setWorking(true);\n const result = await state.runner.run(message, responseCtx, platform);\n await responseCtx.setWorking(false);\n\n const durationMs = Date.now() - state.startedAt!;\n Sentry.metrics.distribution(\"agent.run.duration\", durationMs, {\n unit: \"millisecond\",\n attributes: {\n channel: conversationId,\n platform: platform.name,\n stop_reason: result.stopReason,\n },\n });\n Sentry.metrics.count(\"agent.run.completed\", 1, {\n attributes: {\n channel: conversationId,\n platform: platform.name,\n stop_reason: result.stopReason,\n },\n });\n addLifecycleBreadcrumb(\"agent.run.completed\", {\n channel_id: conversationId,\n platform: platform.name,\n stop_reason: result.stopReason,\n duration_ms: durationMs,\n });\n\n if (result.stopReason === \"aborted\" && state.stopRequested) {\n if (state.stopMessageTs) {\n await bot.updateMessage(conversationId, state.stopMessageTs, formatStopped(bot));\n state.stopMessageTs = undefined;\n } else {\n await bot.postMessage(conversationId, formatStopped(bot));\n }\n }\n } catch (err) {\n scope.setContext(\"agent_run_error\", {\n conversationId,\n sessionKey,\n platform: adapters.platform.name,\n messageId: adapters.message.id,\n threadTs: adapters.message.threadTs,\n });\n Sentry.captureException(err);\n Sentry.metrics.count(\"agent.run.errors\", 1, {\n attributes: { channel: conversationId, platform: adapters.platform.name },\n });\n log.logWarning(\n `[${conversationId}] Run error`,\n err instanceof Error ? err.message : String(err),\n );\n } finally {\n state.running = false;\n state.lastAccessedAt = Date.now();\n Sentry.metrics.gauge(\"agent.sessions.active\", inFlightRuns.size - 1);\n evictIdleSessions();\n }\n });\n },\n );\n\n inFlightRuns.add(runPromise);\n try {\n await runPromise;\n } finally {\n inFlightRuns.delete(runPromise);\n }\n },\n};\n\n// ============================================================================\n// Start\n// ============================================================================\n\nconst sandboxDesc =\n sandbox.type === \"host\"\n ? \"host\"\n : sandbox.type === \"container\"\n ? `container:${sandbox.container}`\n : sandbox.type === \"image\"\n ? `image:${sandbox.image}`\n : `firecracker:${sandbox.vmId}`;\nlog.logStartup(workingDir, sandboxDesc);\n\n// Create platform bots\nconst bots: Bot[] = [];\nconst botsByPlatform: Record<string, Bot> = {};\n\nif (hasSlack) {\n const sharedStore = new ChannelStore({ workingDir, botToken: MOM_SLACK_BOT_TOKEN! });\n const slackBot = new SlackBotClass(handler, {\n appToken: MOM_SLACK_APP_TOKEN!,\n botToken: MOM_SLACK_BOT_TOKEN!,\n workingDir,\n store: sharedStore,\n });\n bots.push(slackBot);\n botsByPlatform.slack = slackBot;\n log.logInfo(\"Platform: Slack\");\n}\nif (hasTelegram) {\n const telegramBot = new TelegramBot(handler, {\n token: MOM_TELEGRAM_BOT_TOKEN!,\n workingDir,\n });\n bots.push(telegramBot);\n botsByPlatform.telegram = telegramBot;\n log.logInfo(\"Platform: Telegram\");\n}\nif (hasDiscord) {\n const discordBot = new DiscordBot(handler, {\n token: MOM_DISCORD_BOT_TOKEN!,\n workingDir,\n });\n bots.push(discordBot);\n botsByPlatform.discord = discordBot;\n log.logInfo(\"Platform: Discord\");\n}\n\nif (MOM_LINK_PORT) {\n startLinkServer(\n MOM_LINK_PORT,\n linkTokenStore,\n vaultManager,\n async (platform, conversationId, message) => {\n const bot = botsByPlatform[platform];\n if (bot) await bot.postMessage(conversationId, message);\n },\n sessionViewTokenStore,\n );\n}\n\n// Start events watcher with explicit platform routing\nconst eventsWatcher = createEventsWatcher(workingDir, botsByPlatform);\nconst slackBot = botsByPlatform.slack as SlackBotClass | undefined;\nif (slackBot) {\n slackBot.setEventsWatcher(eventsWatcher);\n}\neventsWatcher.start();\n\n// Handle shutdown\nasync function shutdown(): Promise<void> {\n if (isShuttingDown) return;\n isShuttingDown = true;\n log.logInfo(\"Shutting down gracefully...\");\n\n const timeout = Date.now() + 30000;\n while (inFlightRuns.size > 0 && Date.now() < timeout) {\n await new Promise((resolve) => setTimeout(resolve, 500));\n }\n\n if (inFlightRuns.size > 0) {\n log.logWarning(`Forcing exit with ${inFlightRuns.size} runs still in progress`);\n }\n\n eventsWatcher.stop();\n await Sentry.close(5000);\n process.exit(0);\n}\n\nprocess.on(\"SIGINT\", shutdown);\nprocess.on(\"SIGTERM\", shutdown);\n\n// Start all bots\nawait Promise.all(\n bots.map((bot) =>\n bot.start().catch((err) => {\n log.logWarning(\"Failed to start bot\", err instanceof Error ? err.message : String(err));\n process.exit(1);\n }),\n ),\n);\n"]}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\nimport \"./instrument.js\";\n\nimport { join, resolve } from \"path\";\nimport { mkdirSync, readFileSync, statSync, writeFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { fileURLToPath } from \"url\";\nimport { dirname, join as pathJoin } from \"path\";\nimport type { Bot } from \"./adapter.js\";\nimport { DiscordBot } from \"./adapters/discord/index.js\";\nimport { TelegramBot } from \"./adapters/telegram/index.js\";\nimport { SlackBot as SlackBotClass } from \"./adapters/slack/index.js\";\nimport { downloadChannel } from \"./download.js\";\nimport { createEventsWatcher } from \"./events.js\";\nimport * as log from \"./log.js\";\nimport { FileUserBindingStore } from \"./bindings.js\";\nimport { startLinkServer } from \"./login/portal.js\";\nimport { InMemoryLinkTokenStore } from \"./login/session.js\";\nimport { InMemorySessionViewTokenStore } from \"./session-view/store.js\";\nimport { DockerContainerManager } from \"./provisioner.js\";\nimport { loadAgentConfig } from \"./config.js\";\nimport { SandboxError, parseSandboxArg, type SandboxConfig, validateSandbox } from \"./sandbox.js\";\nimport { FileVaultManager } from \"./vault.js\";\nimport { createSessionRuntime } from \"./runtime/index.js\";\nimport { ChannelStore } from \"./store.js\";\nimport * as Sentry from \"@sentry/node\";\n\n// ============================================================================\n// Config\n// ============================================================================\n\n// Get version from package.json\nfunction getVersion(): string {\n // Try to find package.json in the dist directory or parent\n const possiblePaths = [\n pathJoin(dirname(fileURLToPath(import.meta.url)), \"package.json\"),\n pathJoin(dirname(fileURLToPath(import.meta.url)), \"..\", \"package.json\"),\n pathJoin(process.cwd(), \"package.json\"),\n ];\n\n for (const pkgPath of possiblePaths) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n if (pkg.version) return pkg.version;\n } catch {\n // Continue to next path\n }\n }\n return \"unknown\";\n}\n\nconst MAMA_SLACK_APP_TOKEN = process.env.MAMA_SLACK_APP_TOKEN;\nconst MAMA_SLACK_BOT_TOKEN = process.env.MAMA_SLACK_BOT_TOKEN;\nconst MAMA_TELEGRAM_BOT_TOKEN = process.env.MAMA_TELEGRAM_BOT_TOKEN;\nconst MAMA_DISCORD_BOT_TOKEN = process.env.MAMA_DISCORD_BOT_TOKEN;\nconst MAMA_LINK_URL = process.env.MAMA_LINK_URL;\nconst MAMA_LINK_PORT = process.env.MAMA_LINK_PORT\n ? parseInt(process.env.MAMA_LINK_PORT, 10)\n : MAMA_LINK_URL\n ? 8181\n : undefined;\n\ninterface ParsedArgs {\n workingDir?: string;\n stateDir?: string;\n sandbox: SandboxConfig;\n downloadChannel?: string;\n showVersion?: boolean;\n}\n\nfunction parseArgs(): ParsedArgs {\n const args = process.argv.slice(2);\n let sandbox: SandboxConfig = { type: \"host\" };\n let workingDir: string | undefined;\n let stateDirArg: string | undefined;\n let downloadChannelId: string | undefined;\n let showVersion = false;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === \"--version\" || arg === \"-v\" || arg === \"-V\") {\n showVersion = true;\n } else if (arg.startsWith(\"--sandbox=\")) {\n sandbox = parseSandboxArg(arg.slice(\"--sandbox=\".length));\n } else if (arg === \"--sandbox\") {\n sandbox = parseSandboxArg(args[++i] || \"\");\n } else if (arg.startsWith(\"--state-dir=\")) {\n stateDirArg = arg.slice(\"--state-dir=\".length);\n } else if (arg === \"--state-dir\") {\n stateDirArg = args[++i];\n } else if (arg.startsWith(\"--download=\")) {\n downloadChannelId = arg.slice(\"--download=\".length);\n } else if (arg === \"--download\") {\n downloadChannelId = args[++i];\n } else if (!arg.startsWith(\"-\")) {\n workingDir = arg;\n }\n }\n\n return {\n workingDir: workingDir ? resolve(workingDir) : undefined,\n stateDir: stateDirArg ? resolve(stateDirArg) : undefined,\n sandbox,\n downloadChannel: downloadChannelId,\n showVersion,\n };\n}\n\nconst WORLD_WRITABLE_MODE = 0o002;\n\nfunction ensureSecureStateDir(path: string): void {\n let stat;\n try {\n stat = statSync(path);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") {\n mkdirSync(path, { recursive: true, mode: 0o700 });\n return;\n }\n console.error(`Error: cannot access --state-dir ${path}: ${(err as Error).message}`);\n process.exit(1);\n }\n\n if (!stat.isDirectory()) {\n console.error(`Error: --state-dir ${path} exists but is not a directory`);\n process.exit(1);\n }\n\n if (stat.mode & WORLD_WRITABLE_MODE) {\n console.error(\n `Error: --state-dir ${path} is world-writable (mode ${(stat.mode & 0o777).toString(8)}). ` +\n `Credentials stored there would be exposed to other local users. ` +\n `Fix with: chmod 0700 ${path}`,\n );\n process.exit(1);\n }\n\n const euid = typeof process.geteuid === \"function\" ? process.geteuid() : undefined;\n if (euid !== undefined && stat.uid !== euid) {\n console.error(\n `Error: --state-dir ${path} is owned by uid ${stat.uid} but mama is running as uid ${euid}. ` +\n `Run mama as the directory owner or point --state-dir at a directory you own.`,\n );\n process.exit(1);\n }\n}\n\nfunction handleStartupError(error: unknown): never {\n if (error instanceof SandboxError) {\n for (const line of error.formatForCli()) {\n console.error(line);\n }\n process.exit(1);\n }\n throw error;\n}\n\nlet parsedArgs: ParsedArgs;\ntry {\n parsedArgs = parseArgs();\n} catch (error) {\n handleStartupError(error);\n}\n\n// Handle --version\nif (parsedArgs.showVersion) {\n console.log(getVersion());\n process.exit(0);\n}\n\n// Handle --download mode (Slack only)\nif (parsedArgs.downloadChannel) {\n if (!MAMA_SLACK_BOT_TOKEN) {\n console.error(\"Missing env: MAMA_SLACK_BOT_TOKEN\");\n process.exit(1);\n }\n await downloadChannel(parsedArgs.downloadChannel, MAMA_SLACK_BOT_TOKEN);\n process.exit(0);\n}\n\n// Normal bot mode - require working dir\nif (!parsedArgs.workingDir) {\n console.error(\n \"Usage: mama [--state-dir=<dir>] [--sandbox=host|container:<name>|image:<image>|firecracker:<vm-id>:<host-path>|cloudflare:<sandbox-id>] <working-directory>\",\n );\n console.error(\" mama --download <channel-id>\");\n process.exit(1);\n}\n\nconst { workingDir, sandbox } = { workingDir: parsedArgs.workingDir, sandbox: parsedArgs.sandbox };\nconst stateDir = parsedArgs.stateDir ?? join(homedir(), \".mama\");\nprocess.env.MAMA_STATE_DIR = stateDir;\nensureSecureStateDir(stateDir);\n\n// Validate platform tokens\nconst hasSlack = !!(MAMA_SLACK_APP_TOKEN && MAMA_SLACK_BOT_TOKEN);\nconst hasTelegram = !!MAMA_TELEGRAM_BOT_TOKEN;\nconst hasDiscord = !!MAMA_DISCORD_BOT_TOKEN;\n\nif (!hasSlack && !hasTelegram && !hasDiscord) {\n console.error(\n \"No platform tokens found. Set one of:\\n\" +\n \" Slack: MAMA_SLACK_APP_TOKEN + MAMA_SLACK_BOT_TOKEN\\n\" +\n \" Telegram: MAMA_TELEGRAM_BOT_TOKEN\\n\" +\n \" Discord: MAMA_DISCORD_BOT_TOKEN\",\n );\n process.exit(1);\n}\n\ntry {\n await validateSandbox(sandbox);\n} catch (error) {\n handleStartupError(error);\n}\n\nconst vaultManager = new FileVaultManager(stateDir);\nif (vaultManager.isEnabled()) {\n console.log(\n sandbox.type === \"container\"\n ? \" Vault system enabled. Container vault active.\"\n : sandbox.type === \"image\" || sandbox.type === \"firecracker\" || sandbox.type === \"cloudflare\"\n ? \" Vault system enabled. Conversation-scoped credential routing active.\"\n : \" Vault system enabled. Host mode will not inject vault env.\",\n );\n}\n\nconst bindingStore = new FileUserBindingStore(stateDir);\nif (bindingStore.isEnabled()) {\n console.log(\n sandbox.type === \"container\"\n ? \" Binding store enabled. Container mode uses the container vault.\"\n : sandbox.type === \"image\" || sandbox.type === \"firecracker\" || sandbox.type === \"cloudflare\"\n ? \" Binding store enabled, but conversation-scoped sandbox routing does not use it.\"\n : \" Binding store enabled. Host mode will not inject vault env.\",\n );\n}\n\nconst startupConfig = loadAgentConfig();\nconst sandboxLimits =\n startupConfig.sandboxCpus || startupConfig.sandboxMemory\n ? { cpus: startupConfig.sandboxCpus, memory: startupConfig.sandboxMemory }\n : undefined;\n\nconst provisioner =\n sandbox.type === \"image\"\n ? new DockerContainerManager(sandbox.image, { limits: sandboxLimits })\n : undefined;\n\nif (sandbox.type === \"image\") {\n mkdirSync(join(workingDir, \"skills\"), { recursive: true });\n mkdirSync(join(workingDir, \"events\"), { recursive: true });\n try {\n writeFileSync(join(workingDir, \"MEMORY.md\"), \"\", { flag: \"wx\" });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") throw err;\n }\n}\n\nconst linkTokenStore = new InMemoryLinkTokenStore();\nconst sessionViewTokenStore = new InMemorySessionViewTokenStore();\nsetInterval(() => linkTokenStore.purge(), 5 * 60 * 1000).unref();\nsetInterval(() => sessionViewTokenStore.purge(), 5 * 60 * 1000).unref();\n\nfunction portalBaseUrl(): string | undefined {\n if (MAMA_LINK_URL) return MAMA_LINK_URL.replace(/\\/+$/, \"\");\n if (MAMA_LINK_PORT) return `http://localhost:${MAMA_LINK_PORT}`;\n return undefined;\n}\n/** Idle timeout for managed image containers (10 minutes) */\nconst IMAGE_IDLE_TIMEOUT_MS = 10 * 60 * 1000;\n\nif (provisioner) {\n await provisioner.reconcile();\n await provisioner.stopIdle(IMAGE_IDLE_TIMEOUT_MS);\n setInterval(() => provisioner.stopIdle(IMAGE_IDLE_TIMEOUT_MS), IMAGE_IDLE_TIMEOUT_MS).unref();\n}\nconst handler = createSessionRuntime({\n workingDir,\n sandbox,\n vaultManager,\n bindingStore,\n provisioner,\n linkTokenStore,\n sessionViewTokenStore,\n portalBaseUrl: portalBaseUrl(),\n});\n\n// ============================================================================\n// Start\n// ============================================================================\n\nconst sandboxDesc =\n sandbox.type === \"host\"\n ? \"host\"\n : sandbox.type === \"container\"\n ? `container:${sandbox.container}`\n : sandbox.type === \"image\"\n ? `image:${sandbox.image}`\n : sandbox.type === \"firecracker\"\n ? `firecracker:${sandbox.vmId}`\n : `cloudflare:${sandbox.sandboxId}`;\nlog.logStartup(workingDir, sandboxDesc);\n\n// Create platform bots\nconst bots: Bot[] = [];\nconst botsByPlatform: Record<string, Bot> = {};\n\nif (hasSlack) {\n const sharedStore = new ChannelStore({ workingDir, botToken: MAMA_SLACK_BOT_TOKEN! });\n const slackBot = new SlackBotClass(handler, {\n appToken: MAMA_SLACK_APP_TOKEN!,\n botToken: MAMA_SLACK_BOT_TOKEN!,\n workingDir,\n store: sharedStore,\n });\n bots.push(slackBot);\n botsByPlatform.slack = slackBot;\n log.logInfo(\"Platform: Slack\");\n}\nif (hasTelegram) {\n const telegramBot = new TelegramBot(handler, {\n token: MAMA_TELEGRAM_BOT_TOKEN!,\n workingDir,\n });\n bots.push(telegramBot);\n botsByPlatform.telegram = telegramBot;\n log.logInfo(\"Platform: Telegram\");\n}\nif (hasDiscord) {\n const discordBot = new DiscordBot(handler, {\n token: MAMA_DISCORD_BOT_TOKEN!,\n workingDir,\n });\n bots.push(discordBot);\n botsByPlatform.discord = discordBot;\n log.logInfo(\"Platform: Discord\");\n}\n\nif (MAMA_LINK_PORT) {\n startLinkServer(\n MAMA_LINK_PORT,\n linkTokenStore,\n vaultManager,\n async (platform, conversationId, message) => {\n const bot = botsByPlatform[platform];\n if (bot) await bot.postMessage(conversationId, message);\n },\n sessionViewTokenStore,\n );\n}\n\n// Start events watcher with explicit platform routing\nconst eventsWatcher = createEventsWatcher(workingDir, botsByPlatform);\nconst slackBot = botsByPlatform.slack as SlackBotClass | undefined;\nif (slackBot) {\n slackBot.setEventsWatcher(eventsWatcher);\n}\neventsWatcher.start();\n\n// Handle shutdown\nasync function shutdown(): Promise<void> {\n await handler.shutdown();\n eventsWatcher.stop();\n await Sentry.close(5000);\n process.exit(0);\n}\n\nprocess.on(\"SIGINT\", shutdown);\nprocess.on(\"SIGTERM\", shutdown);\n\n// Start all bots\nawait Promise.all(\n bots.map((bot) =>\n bot.start().catch((err) => {\n log.logWarning(\"Failed to start bot\", err instanceof Error ? err.message : String(err));\n process.exit(1);\n }),\n ),\n);\n"]}
@@ -12,6 +12,7 @@ export interface ResourceLimits {
12
12
  export interface ProvisionOptions {
13
13
  containerName?: string;
14
14
  mounts?: ContainerMount[];
15
+ conversationId?: string;
15
16
  }
16
17
  export interface DockerContainerManagerOptions {
17
18
  limits?: ResourceLimits;
@@ -19,23 +20,22 @@ export interface DockerContainerManagerOptions {
19
20
  }
20
21
  export declare class DockerContainerManager {
21
22
  private readonly image;
22
- private readonly workspaceDir;
23
23
  private state;
24
24
  private inflight;
25
25
  private static readonly MANAGED_LABEL;
26
26
  private static readonly IMAGE_MODE_LABEL;
27
27
  private static readonly VAULT_ID_LABEL_KEY;
28
+ private static readonly CONVERSATION_ID_LABEL_KEY;
28
29
  private readonly limits?;
29
30
  private readonly execFileImpl;
30
- constructor(image: string, workspaceDir: string, options?: DockerContainerManagerOptions | ExecFileAsync);
31
+ constructor(image: string, options?: DockerContainerManagerOptions | ExecFileAsync);
31
32
  static sanitizeSegment(value: string): string;
32
- static vaultId(platform: string, platformUserId: string): string;
33
- static containerName(vaultId: string): string;
34
- static networkName(vaultId: string): string;
35
- provision(vaultId: string, options?: ProvisionOptions): Promise<string>;
33
+ static containerName(containerKey: string): string;
34
+ static networkName(containerKey: string): string;
35
+ provision(containerKey: string, options?: ProvisionOptions): Promise<string>;
36
36
  private provisionInner;
37
- stop(vaultId: string): Promise<void>;
38
- remove(vaultId: string): Promise<void>;
37
+ stop(containerKey: string): Promise<void>;
38
+ remove(containerKey: string): Promise<void>;
39
39
  stopIdle(maxIdleMs: number): Promise<void>;
40
40
  reconcile(): Promise<void>;
41
41
  private setState;
@@ -59,7 +59,9 @@ export declare class DockerContainerManager {
59
59
  private inspectContainerDetails;
60
60
  private normalizeDockerValue;
61
61
  private parseDockerTimestamp;
62
- private vaultIdFromContainerName;
62
+ private containerKeyFromContainerName;
63
+ private forceRemoveContainer;
64
+ private removeLegacyContainer;
63
65
  }
64
66
  /** @deprecated Use DockerContainerManager */
65
67
  export declare const DockerProvisioner: typeof DockerContainerManager;
@@ -1 +1 @@
1
- {"version":3,"file":"provisioner.d.ts","sourceRoot":"","sources":["../src/provisioner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAIzC,QAAA,MAAM,aAAa,+BAAsB,CAAC;AAC1C,KAAK,aAAa,GAAG,OAAO,aAAa,CAAC;AAU1C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,6BAA6B;IAC5C,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED,qBAAa,sBAAsB;IAW/B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAX/B,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,QAAQ,CAAsC;IACtD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAuB;IAC5D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAwB;IAChE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAmB;IAE7D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAE7C,YACmB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACrC,OAAO,GAAE,6BAA6B,GAAG,aAAkB,EAQ5D;IAED,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM5C;IAED,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAE/D;IAED,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE5C;IAED,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1C;IAEK,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAShF;YAEa,cAAc;IA8BtB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYzC;IAEK,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB3C;IAEK,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS/C;IAEK,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CA6B/B;IAED,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,UAAU;YAIJ,YAAY;IA8B1B,OAAO,CAAC,iBAAiB;YAOX,mBAAmB;YAanB,eAAe;YAWf,iBAAiB;IAS/B,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,SAAS;YAQH,iBAAiB;YAqBjB,mBAAmB;YAWnB,aAAa;YAsBb,aAAa;YAcb,yBAAyB;YAsBzB,0BAA0B;IAoBxC,OAAO,CAAC,cAAc;YAOR,uBAAuB;IAwBrC,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,wBAAwB;CAMjC;AAED,6CAA6C;AAC7C,eAAO,MAAM,iBAAiB,+BAAyB,CAAC","sourcesContent":["import { execFile } from \"child_process\";\nimport { promisify } from \"util\";\nimport * as log from \"./log.js\";\n\nconst execFileAsync = promisify(execFile);\ntype ExecFileAsync = typeof execFileAsync;\n\ntype ContainerStatus = \"running\" | \"stopped\" | \"missing\";\n\ninterface ContainerState {\n status: ContainerStatus;\n lastUsed: number;\n containerName: string;\n}\n\nexport interface ContainerMount {\n source: string;\n target: string;\n}\n\nexport interface ResourceLimits {\n cpus?: string;\n memory?: string;\n}\n\nexport interface ProvisionOptions {\n containerName?: string;\n mounts?: ContainerMount[];\n}\n\nexport interface DockerContainerManagerOptions {\n limits?: ResourceLimits;\n execFileImpl?: ExecFileAsync;\n}\n\nexport class DockerContainerManager {\n private state = new Map<string, ContainerState>();\n private inflight = new Map<string, Promise<string>>();\n private static readonly MANAGED_LABEL = \"mama.managed=true\";\n private static readonly IMAGE_MODE_LABEL = \"mama.sandbox=image\";\n private static readonly VAULT_ID_LABEL_KEY = \"mama.vault-id\";\n\n private readonly limits?: ResourceLimits;\n private readonly execFileImpl: ExecFileAsync;\n\n constructor(\n private readonly image: string,\n private readonly workspaceDir: string,\n options: DockerContainerManagerOptions | ExecFileAsync = {},\n ) {\n if (typeof options === \"function\") {\n this.execFileImpl = options;\n } else {\n this.limits = options.limits;\n this.execFileImpl = options.execFileImpl ?? execFileAsync;\n }\n }\n\n static sanitizeSegment(value: string): string {\n const sanitized = value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return sanitized || \"unknown\";\n }\n\n static vaultId(platform: string, platformUserId: string): string {\n return `${DockerContainerManager.sanitizeSegment(platform)}-${DockerContainerManager.sanitizeSegment(platformUserId)}`;\n }\n\n static containerName(vaultId: string): string {\n return `mama-sandbox-${vaultId}`;\n }\n\n static networkName(vaultId: string): string {\n return `mama-sandbox-net-${vaultId}`;\n }\n\n async provision(vaultId: string, options: ProvisionOptions = {}): Promise<string> {\n const existing = this.inflight.get(vaultId);\n if (existing) return existing;\n\n const pending = this.provisionInner(vaultId, options).finally(() => {\n this.inflight.delete(vaultId);\n });\n this.inflight.set(vaultId, pending);\n return pending;\n }\n\n private async provisionInner(vaultId: string, options: ProvisionOptions): Promise<string> {\n const containerName = options.containerName ?? DockerContainerManager.containerName(vaultId);\n const mounts = options.mounts ?? [];\n const status = await this.inspectStatus(containerName);\n\n try {\n if (status !== \"missing\" && (await this.hasRuntimeDrift(vaultId, containerName, mounts))) {\n log.logInfo(`Container ${containerName} configuration changed; recreating container`);\n await this.execFileImpl(\"docker\", [\"rm\", \"-f\", containerName]);\n await this.runContainer(vaultId, containerName, mounts);\n log.logInfo(`Container ${containerName} recreated`);\n } else if (status === \"running\") {\n log.logInfo(`Container ${containerName} already running`);\n } else if (status === \"stopped\") {\n await this.execFileImpl(\"docker\", [\"start\", containerName]);\n log.logInfo(`Container ${containerName} started`);\n } else {\n await this.runContainer(vaultId, containerName, mounts);\n log.logInfo(`Container ${containerName} created`);\n }\n } catch (err) {\n this.state.delete(vaultId);\n throw err;\n }\n\n this.setState(vaultId, \"running\", containerName);\n await this.applyResourceLimits(containerName);\n return containerName;\n }\n\n async stop(vaultId: string): Promise<void> {\n const containerName = this.getContainerName(vaultId);\n try {\n await this.execFileImpl(\"docker\", [\"stop\", containerName]);\n this.setState(vaultId, \"stopped\", containerName);\n log.logInfo(`Container ${containerName} stopped (idle)`);\n } catch (err) {\n log.logWarning(\n `Failed to stop container ${containerName}`,\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n async remove(vaultId: string): Promise<void> {\n const containerName = this.getContainerName(vaultId);\n const networkName = DockerContainerManager.networkName(vaultId);\n\n try {\n await this.execFileImpl(\"docker\", [\"rm\", \"-f\", containerName]);\n log.logInfo(`Container ${containerName} removed`);\n } catch (err) {\n log.logWarning(\n `Failed to remove container ${containerName}`,\n err instanceof Error ? err.message : String(err),\n );\n }\n\n try {\n await this.execFileImpl(\"docker\", [\"network\", \"rm\", networkName]);\n log.logInfo(`Network ${networkName} removed`);\n } catch (err) {\n log.logWarning(\n `Failed to remove network ${networkName}`,\n err instanceof Error ? err.message : String(err),\n );\n }\n\n this.state.delete(vaultId);\n }\n\n async stopIdle(maxIdleMs: number): Promise<void> {\n const now = Date.now();\n const toStop: string[] = [];\n for (const [vaultId, containerState] of this.state) {\n if (containerState.status === \"running\" && now - containerState.lastUsed > maxIdleMs) {\n toStop.push(vaultId);\n }\n }\n await Promise.all(toStop.map((vaultId) => this.stop(vaultId)));\n }\n\n async reconcile(): Promise<void> {\n const discovered = new Set<string>();\n const labeledNames = await this.listContainerNamesByLabel();\n for (const name of labeledNames) discovered.add(name);\n const legacyNames = await this.listContainerNamesByPrefix();\n for (const name of legacyNames) discovered.add(name);\n\n this.state.clear();\n\n for (const containerName of discovered) {\n const details = await this.inspectContainerDetails(containerName);\n if (!details) continue;\n\n const vaultId = details.vaultId || this.vaultIdFromContainerName(containerName);\n if (!vaultId) {\n log.logWarning(`Skipping unmanaged-style container without vault id`, containerName);\n continue;\n }\n\n const status: ContainerStatus = details.running ? \"running\" : \"stopped\";\n const lastUsed = details.startedAtMs ?? Date.now();\n this.state.set(vaultId, { status, lastUsed, containerName });\n }\n\n const running = Array.from(this.state.values()).filter((s) => s.status === \"running\").length;\n const stopped = this.state.size - running;\n log.logInfo(\n `Reconciled ${this.state.size} managed containers (running=${running}, stopped=${stopped})`,\n );\n }\n\n private setState(vaultId: string, status: ContainerStatus, containerName: string): void {\n this.state.set(vaultId, { status, lastUsed: Date.now(), containerName });\n }\n\n private getContainerName(vaultId: string): string {\n return this.state.get(vaultId)?.containerName ?? DockerContainerManager.containerName(vaultId);\n }\n\n private mountArgs(mounts: ContainerMount[]): string[] {\n return mounts.flatMap((mount) => [\"-v\", this.toBindSpec(mount)]);\n }\n\n private toBindSpec(mount: ContainerMount): string {\n return `${mount.source}:${mount.target}`;\n }\n\n private async runContainer(\n vaultId: string,\n containerName: string,\n mounts: ContainerMount[],\n ): Promise<void> {\n const networkName = await this.ensureNetwork(vaultId);\n log.logInfo(`Creating container ${containerName} from image ${this.image}`);\n await this.execFileImpl(\"docker\", [\n \"run\",\n \"-d\",\n \"--name\",\n containerName,\n \"--network\",\n networkName,\n \"--label\",\n DockerContainerManager.MANAGED_LABEL,\n \"--label\",\n DockerContainerManager.IMAGE_MODE_LABEL,\n \"--label\",\n `${DockerContainerManager.VAULT_ID_LABEL_KEY}=${vaultId}`,\n ...this.resourceLimitArgs(),\n \"-v\",\n `${this.workspaceDir}:/workspace`,\n ...this.mountArgs(mounts),\n this.image,\n \"sleep\",\n \"infinity\",\n ]);\n }\n\n private resourceLimitArgs(): string[] {\n const args: string[] = [];\n if (this.limits?.cpus) args.push(\"--cpus\", this.limits.cpus);\n if (this.limits?.memory) args.push(\"--memory\", this.limits.memory);\n return args;\n }\n\n private async applyResourceLimits(containerName: string): Promise<void> {\n if (!this.limits?.cpus && !this.limits?.memory) return;\n const args = [\"update\", ...this.resourceLimitArgs(), containerName];\n try {\n await this.execFileImpl(\"docker\", args);\n } catch (err) {\n log.logWarning(\n `Failed to apply resource limits to container ${containerName}`,\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n private async hasRuntimeDrift(\n vaultId: string,\n containerName: string,\n mounts: ContainerMount[],\n ): Promise<boolean> {\n if (await this.hasBindMountDrift(containerName, mounts)) {\n return true;\n }\n return this.hasNetworkModeDrift(vaultId, containerName);\n }\n\n private async hasBindMountDrift(\n containerName: string,\n mounts: ContainerMount[],\n ): Promise<boolean> {\n const expected = this.expectedBinds(mounts);\n const actual = await this.inspectBindMounts(containerName);\n return !this.sameBinds(expected, actual);\n }\n\n private expectedBinds(mounts: ContainerMount[]): string[] {\n return [`${this.workspaceDir}:/workspace`, ...mounts.map((mount) => this.toBindSpec(mount))]\n .slice()\n .sort();\n }\n\n private sameBinds(expected: string[], actual: string[]): boolean {\n if (expected.length !== actual.length) {\n return false;\n }\n\n return expected.every((bind, index) => bind === actual[index]);\n }\n\n private async inspectBindMounts(containerName: string): Promise<string[]> {\n const { stdout } = await this.execFileImpl(\"docker\", [\n \"inspect\",\n \"-f\",\n \"{{json .HostConfig.Binds}}\",\n containerName,\n ]);\n const payload = stdout.trim();\n const parsed = JSON.parse(payload.length > 0 ? payload : \"null\") as unknown;\n\n if (parsed === null) {\n return [];\n }\n\n if (!Array.isArray(parsed) || parsed.some((bind) => typeof bind !== \"string\")) {\n throw new Error(`Unexpected docker bind mount payload for container \"${containerName}\"`);\n }\n\n return [...parsed].sort();\n }\n\n private async hasNetworkModeDrift(vaultId: string, containerName: string): Promise<boolean> {\n const expected = DockerContainerManager.networkName(vaultId);\n const { stdout } = await this.execFileImpl(\"docker\", [\n \"inspect\",\n \"-f\",\n \"{{.HostConfig.NetworkMode}}\",\n containerName,\n ]);\n return stdout.trim() !== expected;\n }\n\n private async ensureNetwork(vaultId: string): Promise<string> {\n const networkName = DockerContainerManager.networkName(vaultId);\n try {\n await this.execFileImpl(\"docker\", [\"network\", \"inspect\", networkName]);\n } catch {\n await this.execFileImpl(\"docker\", [\n \"network\",\n \"create\",\n \"--driver\",\n \"bridge\",\n \"--label\",\n DockerContainerManager.MANAGED_LABEL,\n \"--label\",\n DockerContainerManager.IMAGE_MODE_LABEL,\n \"--label\",\n `${DockerContainerManager.VAULT_ID_LABEL_KEY}=${vaultId}`,\n networkName,\n ]);\n }\n return networkName;\n }\n\n private async inspectStatus(containerName: string): Promise<ContainerStatus> {\n try {\n const { stdout } = await this.execFileImpl(\"docker\", [\n \"inspect\",\n \"-f\",\n \"{{.State.Running}}\",\n containerName,\n ]);\n return stdout.trim() === \"true\" ? \"running\" : \"stopped\";\n } catch {\n return \"missing\";\n }\n }\n\n private async listContainerNamesByLabel(): Promise<string[]> {\n try {\n const { stdout } = await this.execFileImpl(\"docker\", [\n \"ps\",\n \"-a\",\n \"--filter\",\n `label=${DockerContainerManager.MANAGED_LABEL}`,\n \"--filter\",\n `label=${DockerContainerManager.IMAGE_MODE_LABEL}`,\n \"--format\",\n \"{{.Names}}\",\n ]);\n return this.parseNameLines(stdout);\n } catch (err) {\n log.logWarning(\n \"Failed to list labeled managed containers\",\n err instanceof Error ? err.message : String(err),\n );\n return [];\n }\n }\n\n private async listContainerNamesByPrefix(): Promise<string[]> {\n try {\n const { stdout } = await this.execFileImpl(\"docker\", [\n \"ps\",\n \"-a\",\n \"--filter\",\n `name=${DockerContainerManager.containerName(\"\")}`,\n \"--format\",\n \"{{.Names}}\",\n ]);\n return this.parseNameLines(stdout);\n } catch (err) {\n log.logWarning(\n \"Failed to list legacy managed containers\",\n err instanceof Error ? err.message : String(err),\n );\n return [];\n }\n }\n\n private parseNameLines(stdout: string): string[] {\n return stdout\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n }\n\n private async inspectContainerDetails(\n containerName: string,\n ): Promise<{ running: boolean; startedAtMs?: number; vaultId?: string } | undefined> {\n try {\n const { stdout } = await this.execFileImpl(\"docker\", [\n \"inspect\",\n \"-f\",\n `{{.State.Running}}\\t{{.State.StartedAt}}\\t{{index .Config.Labels \"${DockerContainerManager.VAULT_ID_LABEL_KEY}\"}}`,\n containerName,\n ]);\n const [runningRaw, startedAtRaw, vaultIdRaw] = stdout.trim().split(\"\\t\");\n const running = runningRaw === \"true\";\n const startedAtMs = this.parseDockerTimestamp(startedAtRaw);\n const vaultId = this.normalizeDockerValue(vaultIdRaw);\n return { running, startedAtMs, vaultId };\n } catch (err) {\n log.logWarning(\n `Failed to inspect container ${containerName} during reconcile`,\n err instanceof Error ? err.message : String(err),\n );\n return undefined;\n }\n }\n\n private normalizeDockerValue(value?: string): string | undefined {\n if (!value || value === \"<no value>\") return undefined;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n\n private parseDockerTimestamp(value?: string): number | undefined {\n const normalized = this.normalizeDockerValue(value);\n if (!normalized || normalized.startsWith(\"0001-\")) return undefined;\n const parsed = Date.parse(normalized);\n return Number.isNaN(parsed) ? undefined : parsed;\n }\n\n private vaultIdFromContainerName(containerName: string): string | undefined {\n const prefix = DockerContainerManager.containerName(\"\");\n if (!containerName.startsWith(prefix)) return undefined;\n const vaultId = containerName.slice(prefix.length);\n return vaultId.length > 0 ? vaultId : undefined;\n }\n}\n\n/** @deprecated Use DockerContainerManager */\nexport const DockerProvisioner = DockerContainerManager;\n"]}
1
+ {"version":3,"file":"provisioner.d.ts","sourceRoot":"","sources":["../src/provisioner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAIzC,QAAA,MAAM,aAAa,+BAAsB,CAAC;AAC1C,KAAK,aAAa,GAAG,OAAO,aAAa,CAAC;AA2B1C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,6BAA6B;IAC5C,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED,qBAAa,sBAAsB;IAY/B,OAAO,CAAC,QAAQ,CAAC,KAAK;IAXxB,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,QAAQ,CAAsC;IACtD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAuB;IAC5D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAwB;IAChE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAmB;IAC7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAA0B;IAE3E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAE7C,YACmB,KAAK,EAAE,MAAM,EAC9B,OAAO,GAAE,6BAA6B,GAAG,aAAkB,EAQ5D;IAED,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM5C;IAED,MAAM,CAAC,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEjD;IAED,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE/C;IAEK,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CASrF;YAEa,cAAc;IAkCtB,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAY9C;IAEK,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBhD;IAEK,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS/C;IAEK,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CA0C/B;IAED,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,UAAU;YAIJ,YAAY;IAsC1B,OAAO,CAAC,iBAAiB;YAOX,mBAAmB;YAanB,eAAe;YAWf,iBAAiB;IAS/B,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,SAAS;YAQH,iBAAiB;YAqBjB,mBAAmB;YAWnB,aAAa;YAwBb,aAAa;YAeb,yBAAyB;YAsBzB,0BAA0B;IAoBxC,OAAO,CAAC,cAAc;YAOR,uBAAuB;IA4BrC,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,6BAA6B;YAOvB,oBAAoB;YAapB,qBAAqB;CAOpC;AAED,6CAA6C;AAC7C,eAAO,MAAM,iBAAiB,+BAAyB,CAAC","sourcesContent":["import { execFile } from \"child_process\";\nimport { promisify } from \"util\";\nimport * as log from \"./log.js\";\n\nconst execFileAsync = promisify(execFile);\ntype ExecFileAsync = typeof execFileAsync;\n\ntype ContainerStatus = \"running\" | \"stopped\" | \"missing\";\n\nfunction isDockerNotFoundError(err: unknown): boolean {\n if (!err || typeof err !== \"object\") return false;\n const stderr = (err as { stderr?: unknown }).stderr;\n const message = (err as { message?: unknown }).message;\n const haystack = `${typeof stderr === \"string\" ? stderr : \"\"}\\n${\n typeof message === \"string\" ? message : \"\"\n }`.toLowerCase();\n return (\n haystack.includes(\"no such network\") ||\n haystack.includes(\"no such container\") ||\n haystack.includes(\"no such object\") ||\n haystack.includes(\"network not found\") ||\n /network [^\\n]+ not found/.test(haystack) ||\n /error: no such [^\\n]+/.test(haystack)\n );\n}\n\ninterface ContainerState {\n status: ContainerStatus;\n lastUsed: number;\n containerName: string;\n}\n\nexport interface ContainerMount {\n source: string;\n target: string;\n}\n\nexport interface ResourceLimits {\n cpus?: string;\n memory?: string;\n}\n\nexport interface ProvisionOptions {\n containerName?: string;\n mounts?: ContainerMount[];\n conversationId?: string;\n}\n\nexport interface DockerContainerManagerOptions {\n limits?: ResourceLimits;\n execFileImpl?: ExecFileAsync;\n}\n\nexport class DockerContainerManager {\n private state = new Map<string, ContainerState>();\n private inflight = new Map<string, Promise<string>>();\n private static readonly MANAGED_LABEL = \"mama.managed=true\";\n private static readonly IMAGE_MODE_LABEL = \"mama.sandbox=image\";\n private static readonly VAULT_ID_LABEL_KEY = \"mama.vault-id\";\n private static readonly CONVERSATION_ID_LABEL_KEY = \"mama.conversation-id\";\n\n private readonly limits?: ResourceLimits;\n private readonly execFileImpl: ExecFileAsync;\n\n constructor(\n private readonly image: string,\n options: DockerContainerManagerOptions | ExecFileAsync = {},\n ) {\n if (typeof options === \"function\") {\n this.execFileImpl = options;\n } else {\n this.limits = options.limits;\n this.execFileImpl = options.execFileImpl ?? execFileAsync;\n }\n }\n\n static sanitizeSegment(value: string): string {\n const sanitized = value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return sanitized || \"unknown\";\n }\n\n static containerName(containerKey: string): string {\n return `mama-sandbox-${containerKey}`;\n }\n\n static networkName(containerKey: string): string {\n return `mama-sandbox-net-${containerKey}`;\n }\n\n async provision(containerKey: string, options: ProvisionOptions = {}): Promise<string> {\n const existing = this.inflight.get(containerKey);\n if (existing) return existing;\n\n const pending = this.provisionInner(containerKey, options).finally(() => {\n this.inflight.delete(containerKey);\n });\n this.inflight.set(containerKey, pending);\n return pending;\n }\n\n private async provisionInner(containerKey: string, options: ProvisionOptions): Promise<string> {\n const containerName =\n options.containerName ?? DockerContainerManager.containerName(containerKey);\n const mounts = options.mounts ?? [];\n const status = await this.inspectStatus(containerName);\n\n try {\n if (\n status !== \"missing\" &&\n (await this.hasRuntimeDrift(containerKey, containerName, mounts))\n ) {\n log.logInfo(`Container ${containerName} configuration changed; recreating container`);\n await this.execFileImpl(\"docker\", [\"rm\", \"-f\", containerName]);\n await this.runContainer(containerKey, containerName, mounts, options);\n log.logInfo(`Container ${containerName} recreated`);\n } else if (status === \"running\") {\n log.logInfo(`Container ${containerName} already running`);\n } else if (status === \"stopped\") {\n await this.execFileImpl(\"docker\", [\"start\", containerName]);\n log.logInfo(`Container ${containerName} started`);\n } else {\n await this.runContainer(containerKey, containerName, mounts, options);\n log.logInfo(`Container ${containerName} created`);\n }\n } catch (err) {\n this.state.delete(containerKey);\n throw err;\n }\n\n this.setState(containerKey, \"running\", containerName);\n await this.applyResourceLimits(containerName);\n return containerName;\n }\n\n async stop(containerKey: string): Promise<void> {\n const containerName = this.getContainerName(containerKey);\n try {\n await this.execFileImpl(\"docker\", [\"stop\", containerName]);\n this.setState(containerKey, \"stopped\", containerName);\n log.logInfo(`Container ${containerName} stopped (idle)`);\n } catch (err) {\n log.logWarning(\n `Failed to stop container ${containerName}`,\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n async remove(containerKey: string): Promise<void> {\n const containerName = this.getContainerName(containerKey);\n const networkName = DockerContainerManager.networkName(containerKey);\n\n await this.forceRemoveContainer(\n containerName,\n `Container ${containerName} removed`,\n `Failed to remove container ${containerName}`,\n );\n\n try {\n await this.execFileImpl(\"docker\", [\"network\", \"rm\", networkName]);\n log.logInfo(`Network ${networkName} removed`);\n } catch (err) {\n log.logWarning(\n `Failed to remove network ${networkName}`,\n err instanceof Error ? err.message : String(err),\n );\n }\n\n this.state.delete(containerKey);\n }\n\n async stopIdle(maxIdleMs: number): Promise<void> {\n const now = Date.now();\n const toStop: string[] = [];\n for (const [containerKey, containerState] of this.state) {\n if (containerState.status === \"running\" && now - containerState.lastUsed > maxIdleMs) {\n toStop.push(containerKey);\n }\n }\n await Promise.all(toStop.map((containerKey) => this.stop(containerKey)));\n }\n\n async reconcile(): Promise<void> {\n const discovered = new Set<string>();\n const labeledNames = await this.listContainerNamesByLabel();\n for (const name of labeledNames) discovered.add(name);\n const legacyNames = await this.listContainerNamesByPrefix();\n for (const name of legacyNames) discovered.add(name);\n\n this.state.clear();\n\n const inspected = await Promise.all(\n Array.from(discovered).map(async (containerName) => ({\n containerName,\n details: await this.inspectContainerDetails(containerName),\n })),\n );\n\n const legacyRemovals: Promise<void>[] = [];\n for (const { containerName, details } of inspected) {\n if (!details) continue;\n\n if (!details.conversationId) {\n legacyRemovals.push(this.removeLegacyContainer(containerName));\n continue;\n }\n\n const containerKey = this.containerKeyFromContainerName(containerName);\n if (!containerKey) {\n log.logWarning(`Skipping unmanaged-style container without container key`, containerName);\n continue;\n }\n\n const status: ContainerStatus = details.running ? \"running\" : \"stopped\";\n const lastUsed = details.startedAtMs ?? Date.now();\n this.state.set(containerKey, { status, lastUsed, containerName });\n }\n await Promise.all(legacyRemovals);\n\n const running = Array.from(this.state.values()).filter((s) => s.status === \"running\").length;\n const stopped = this.state.size - running;\n log.logInfo(\n `Reconciled ${this.state.size} managed containers (running=${running}, stopped=${stopped})`,\n );\n }\n\n private setState(containerKey: string, status: ContainerStatus, containerName: string): void {\n this.state.set(containerKey, { status, lastUsed: Date.now(), containerName });\n }\n\n private getContainerName(containerKey: string): string {\n return (\n this.state.get(containerKey)?.containerName ??\n DockerContainerManager.containerName(containerKey)\n );\n }\n\n private mountArgs(mounts: ContainerMount[]): string[] {\n return mounts.flatMap((mount) => [\"-v\", this.toBindSpec(mount)]);\n }\n\n private toBindSpec(mount: ContainerMount): string {\n return `${mount.source}:${mount.target}`;\n }\n\n private async runContainer(\n containerKey: string,\n containerName: string,\n mounts: ContainerMount[],\n options: ProvisionOptions,\n ): Promise<void> {\n const networkName = await this.ensureNetwork(containerKey);\n log.logInfo(`Creating container ${containerName} from image ${this.image}`);\n const labels = [\n \"--label\",\n DockerContainerManager.MANAGED_LABEL,\n \"--label\",\n DockerContainerManager.IMAGE_MODE_LABEL,\n \"--label\",\n `${DockerContainerManager.VAULT_ID_LABEL_KEY}=${containerKey}`,\n ];\n if (options.conversationId) {\n labels.push(\n \"--label\",\n `${DockerContainerManager.CONVERSATION_ID_LABEL_KEY}=${options.conversationId}`,\n );\n }\n await this.execFileImpl(\"docker\", [\n \"run\",\n \"-d\",\n \"--name\",\n containerName,\n \"--network\",\n networkName,\n ...labels,\n ...this.resourceLimitArgs(),\n ...this.mountArgs(mounts),\n this.image,\n \"sleep\",\n \"infinity\",\n ]);\n }\n\n private resourceLimitArgs(): string[] {\n const args: string[] = [];\n if (this.limits?.cpus) args.push(\"--cpus\", this.limits.cpus);\n if (this.limits?.memory) args.push(\"--memory\", this.limits.memory);\n return args;\n }\n\n private async applyResourceLimits(containerName: string): Promise<void> {\n if (!this.limits?.cpus && !this.limits?.memory) return;\n const args = [\"update\", ...this.resourceLimitArgs(), containerName];\n try {\n await this.execFileImpl(\"docker\", args);\n } catch (err) {\n log.logWarning(\n `Failed to apply resource limits to container ${containerName}`,\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n private async hasRuntimeDrift(\n containerKey: string,\n containerName: string,\n mounts: ContainerMount[],\n ): Promise<boolean> {\n if (await this.hasBindMountDrift(containerName, mounts)) {\n return true;\n }\n return this.hasNetworkModeDrift(containerKey, containerName);\n }\n\n private async hasBindMountDrift(\n containerName: string,\n mounts: ContainerMount[],\n ): Promise<boolean> {\n const expected = this.expectedBinds(mounts);\n const actual = await this.inspectBindMounts(containerName);\n return !this.sameBinds(expected, actual);\n }\n\n private expectedBinds(mounts: ContainerMount[]): string[] {\n return mounts\n .map((mount) => this.toBindSpec(mount))\n .slice()\n .sort();\n }\n\n private sameBinds(expected: string[], actual: string[]): boolean {\n if (expected.length !== actual.length) {\n return false;\n }\n\n return expected.every((bind, index) => bind === actual[index]);\n }\n\n private async inspectBindMounts(containerName: string): Promise<string[]> {\n const { stdout } = await this.execFileImpl(\"docker\", [\n \"inspect\",\n \"-f\",\n \"{{json .HostConfig.Binds}}\",\n containerName,\n ]);\n const payload = stdout.trim();\n const parsed = JSON.parse(payload.length > 0 ? payload : \"null\") as unknown;\n\n if (parsed === null) {\n return [];\n }\n\n if (!Array.isArray(parsed) || parsed.some((bind) => typeof bind !== \"string\")) {\n throw new Error(`Unexpected docker bind mount payload for container \"${containerName}\"`);\n }\n\n return [...parsed].sort();\n }\n\n private async hasNetworkModeDrift(containerKey: string, containerName: string): Promise<boolean> {\n const expected = DockerContainerManager.networkName(containerKey);\n const { stdout } = await this.execFileImpl(\"docker\", [\n \"inspect\",\n \"-f\",\n \"{{.HostConfig.NetworkMode}}\",\n containerName,\n ]);\n return stdout.trim() !== expected;\n }\n\n private async ensureNetwork(containerKey: string): Promise<string> {\n const networkName = DockerContainerManager.networkName(containerKey);\n try {\n await this.execFileImpl(\"docker\", [\"network\", \"inspect\", networkName]);\n return networkName;\n } catch (err) {\n if (!isDockerNotFoundError(err)) throw err;\n }\n await this.execFileImpl(\"docker\", [\n \"network\",\n \"create\",\n \"--driver\",\n \"bridge\",\n \"--label\",\n DockerContainerManager.MANAGED_LABEL,\n \"--label\",\n DockerContainerManager.IMAGE_MODE_LABEL,\n \"--label\",\n `${DockerContainerManager.VAULT_ID_LABEL_KEY}=${containerKey}`,\n networkName,\n ]);\n return networkName;\n }\n\n private async inspectStatus(containerName: string): Promise<ContainerStatus> {\n try {\n const { stdout } = await this.execFileImpl(\"docker\", [\n \"inspect\",\n \"-f\",\n \"{{.State.Running}}\",\n containerName,\n ]);\n return stdout.trim() === \"true\" ? \"running\" : \"stopped\";\n } catch (err) {\n if (isDockerNotFoundError(err)) return \"missing\";\n throw err;\n }\n }\n\n private async listContainerNamesByLabel(): Promise<string[]> {\n try {\n const { stdout } = await this.execFileImpl(\"docker\", [\n \"ps\",\n \"-a\",\n \"--filter\",\n `label=${DockerContainerManager.MANAGED_LABEL}`,\n \"--filter\",\n `label=${DockerContainerManager.IMAGE_MODE_LABEL}`,\n \"--format\",\n \"{{.Names}}\",\n ]);\n return this.parseNameLines(stdout);\n } catch (err) {\n log.logWarning(\n \"Failed to list labeled managed containers\",\n err instanceof Error ? err.message : String(err),\n );\n return [];\n }\n }\n\n private async listContainerNamesByPrefix(): Promise<string[]> {\n try {\n const { stdout } = await this.execFileImpl(\"docker\", [\n \"ps\",\n \"-a\",\n \"--filter\",\n `name=${DockerContainerManager.containerName(\"\")}`,\n \"--format\",\n \"{{.Names}}\",\n ]);\n return this.parseNameLines(stdout);\n } catch (err) {\n log.logWarning(\n \"Failed to list legacy managed containers\",\n err instanceof Error ? err.message : String(err),\n );\n return [];\n }\n }\n\n private parseNameLines(stdout: string): string[] {\n return stdout\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n }\n\n private async inspectContainerDetails(\n containerName: string,\n ): Promise<\n | { running: boolean; startedAtMs?: number; vaultId?: string; conversationId?: string }\n | undefined\n > {\n try {\n const { stdout } = await this.execFileImpl(\"docker\", [\n \"inspect\",\n \"-f\",\n `{{.State.Running}}\\t{{.State.StartedAt}}\\t{{index .Config.Labels \"${DockerContainerManager.VAULT_ID_LABEL_KEY}\"}}\\t{{index .Config.Labels \"${DockerContainerManager.CONVERSATION_ID_LABEL_KEY}\"}}`,\n containerName,\n ]);\n const [runningRaw, startedAtRaw, vaultIdRaw, conversationIdRaw] = stdout.trim().split(\"\\t\");\n const running = runningRaw === \"true\";\n const startedAtMs = this.parseDockerTimestamp(startedAtRaw);\n const vaultId = this.normalizeDockerValue(vaultIdRaw);\n const conversationId = this.normalizeDockerValue(conversationIdRaw);\n return { running, startedAtMs, vaultId, conversationId };\n } catch (err) {\n log.logWarning(\n `Failed to inspect container ${containerName} during reconcile`,\n err instanceof Error ? err.message : String(err),\n );\n return undefined;\n }\n }\n\n private normalizeDockerValue(value?: string): string | undefined {\n if (!value || value === \"<no value>\") return undefined;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n\n private parseDockerTimestamp(value?: string): number | undefined {\n const normalized = this.normalizeDockerValue(value);\n if (!normalized || normalized.startsWith(\"0001-\")) return undefined;\n const parsed = Date.parse(normalized);\n return Number.isNaN(parsed) ? undefined : parsed;\n }\n\n private containerKeyFromContainerName(containerName: string): string | undefined {\n const prefix = DockerContainerManager.containerName(\"\");\n if (!containerName.startsWith(prefix)) return undefined;\n const containerKey = containerName.slice(prefix.length);\n return containerKey.length > 0 ? containerKey : undefined;\n }\n\n private async forceRemoveContainer(\n containerName: string,\n successLog: string,\n failureLog: string,\n ): Promise<void> {\n try {\n await this.execFileImpl(\"docker\", [\"rm\", \"-f\", containerName]);\n log.logInfo(successLog);\n } catch (err) {\n log.logWarning(failureLog, err instanceof Error ? err.message : String(err));\n }\n }\n\n private async removeLegacyContainer(containerName: string): Promise<void> {\n await this.forceRemoveContainer(\n containerName,\n `Removed legacy mama container ${containerName} (pre-channel-isolation scheme)`,\n `Failed to remove legacy mama container ${containerName}`,\n );\n }\n}\n\n/** @deprecated Use DockerContainerManager */\nexport const DockerProvisioner = DockerContainerManager;\n"]}