@geminixiang/mikan 0.4.8 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +13 -13
  3. package/dist/adapter.d.ts +1 -1
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js.map +1 -1
  6. package/dist/adapters/discord/bot.d.ts +9 -6
  7. package/dist/adapters/discord/bot.d.ts.map +1 -1
  8. package/dist/adapters/discord/bot.js +22 -22
  9. package/dist/adapters/discord/bot.js.map +1 -1
  10. package/dist/adapters/discord/context.d.ts +6 -6
  11. package/dist/adapters/discord/context.d.ts.map +1 -1
  12. package/dist/adapters/discord/context.js +3 -3
  13. package/dist/adapters/discord/context.js.map +1 -1
  14. package/dist/adapters/discord/types.d.ts +2 -2
  15. package/dist/adapters/discord/types.d.ts.map +1 -1
  16. package/dist/adapters/discord/types.js.map +1 -1
  17. package/dist/adapters/intake.d.ts +2 -2
  18. package/dist/adapters/intake.d.ts.map +1 -1
  19. package/dist/adapters/intake.js +4 -4
  20. package/dist/adapters/intake.js.map +1 -1
  21. package/dist/adapters/shared.d.ts +3 -3
  22. package/dist/adapters/shared.d.ts.map +1 -1
  23. package/dist/adapters/shared.js +2 -2
  24. package/dist/adapters/shared.js.map +1 -1
  25. package/dist/adapters/slack/bot.d.ts +10 -7
  26. package/dist/adapters/slack/bot.d.ts.map +1 -1
  27. package/dist/adapters/slack/bot.js +46 -46
  28. package/dist/adapters/slack/bot.js.map +1 -1
  29. package/dist/adapters/slack/context.d.ts +6 -6
  30. package/dist/adapters/slack/context.d.ts.map +1 -1
  31. package/dist/adapters/slack/context.js +2 -2
  32. package/dist/adapters/slack/context.js.map +1 -1
  33. package/dist/adapters/slack/response-lifecycle.d.ts +6 -6
  34. package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
  35. package/dist/adapters/slack/response-lifecycle.js +3 -3
  36. package/dist/adapters/slack/response-lifecycle.js.map +1 -1
  37. package/dist/adapters/slack/session.d.ts.map +1 -1
  38. package/dist/adapters/slack/tools/attach.d.ts.map +1 -1
  39. package/dist/adapters/slack/tools/block-kit.d.ts.map +1 -1
  40. package/dist/adapters/slack/types.d.ts +1 -1
  41. package/dist/adapters/slack/types.d.ts.map +1 -1
  42. package/dist/adapters/slack/types.js.map +1 -1
  43. package/dist/adapters/streaming.d.ts.map +1 -1
  44. package/dist/adapters/telegram/bot.d.ts +10 -7
  45. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  46. package/dist/adapters/telegram/bot.js +21 -21
  47. package/dist/adapters/telegram/bot.js.map +1 -1
  48. package/dist/adapters/telegram/context.d.ts +6 -6
  49. package/dist/adapters/telegram/context.d.ts.map +1 -1
  50. package/dist/adapters/telegram/context.js +3 -3
  51. package/dist/adapters/telegram/context.js.map +1 -1
  52. package/dist/adapters/telegram/html.d.ts.map +1 -1
  53. package/dist/adapters/telegram/types.d.ts +2 -2
  54. package/dist/adapters/telegram/types.d.ts.map +1 -1
  55. package/dist/adapters/telegram/types.js.map +1 -1
  56. package/dist/adapters/types.d.ts +6 -6
  57. package/dist/adapters/types.d.ts.map +1 -1
  58. package/dist/adapters/types.js.map +1 -1
  59. package/dist/agent-events.d.ts +5 -0
  60. package/dist/agent-events.d.ts.map +1 -0
  61. package/dist/agent-events.js +26 -0
  62. package/dist/agent-events.js.map +1 -0
  63. package/dist/agent.d.ts +7 -7
  64. package/dist/agent.d.ts.map +1 -1
  65. package/dist/agent.js +84 -41
  66. package/dist/agent.js.map +1 -1
  67. package/dist/commands/admin.d.ts.map +1 -1
  68. package/dist/commands/admin.js +1 -1
  69. package/dist/commands/admin.js.map +1 -1
  70. package/dist/commands/auto-reply.d.ts.map +1 -1
  71. package/dist/commands/auto-reply.js +3 -3
  72. package/dist/commands/auto-reply.js.map +1 -1
  73. package/dist/commands/login.d.ts.map +1 -1
  74. package/dist/commands/login.js +1 -1
  75. package/dist/commands/login.js.map +1 -1
  76. package/dist/commands/model.d.ts.map +1 -1
  77. package/dist/commands/model.js +5 -5
  78. package/dist/commands/model.js.map +1 -1
  79. package/dist/commands/new.d.ts.map +1 -1
  80. package/dist/commands/new.js +2 -2
  81. package/dist/commands/new.js.map +1 -1
  82. package/dist/commands/parse.d.ts.map +1 -1
  83. package/dist/commands/registry.d.ts.map +1 -1
  84. package/dist/commands/sandbox.d.ts.map +1 -1
  85. package/dist/commands/sandbox.js +5 -5
  86. package/dist/commands/sandbox.js.map +1 -1
  87. package/dist/commands/session-view.d.ts.map +1 -1
  88. package/dist/commands/session-view.js +1 -1
  89. package/dist/commands/session-view.js.map +1 -1
  90. package/dist/commands/types.d.ts +5 -5
  91. package/dist/commands/types.d.ts.map +1 -1
  92. package/dist/commands/types.js.map +1 -1
  93. package/dist/commands/utils.d.ts +3 -3
  94. package/dist/commands/utils.d.ts.map +1 -1
  95. package/dist/commands/utils.js +6 -6
  96. package/dist/commands/utils.js.map +1 -1
  97. package/dist/config.d.ts.map +1 -1
  98. package/dist/context.d.ts.map +1 -1
  99. package/dist/download.d.ts.map +1 -1
  100. package/dist/events.d.ts +2 -2
  101. package/dist/events.d.ts.map +1 -1
  102. package/dist/events.js.map +1 -1
  103. package/dist/execution-resolver.d.ts.map +1 -1
  104. package/dist/index.d.ts +3 -3
  105. package/dist/index.d.ts.map +1 -1
  106. package/dist/index.js +2 -2
  107. package/dist/index.js.map +1 -1
  108. package/dist/log.d.ts.map +1 -1
  109. package/dist/main.d.ts.map +1 -1
  110. package/dist/main.js +35 -27
  111. package/dist/main.js.map +1 -1
  112. package/dist/model-registry.d.ts.map +1 -1
  113. package/dist/observability/instrument.d.ts.map +1 -1
  114. package/dist/observability/sentry.d.ts.map +1 -1
  115. package/dist/observability/sentry.js +27 -9
  116. package/dist/observability/sentry.js.map +1 -1
  117. package/dist/observability/types.d.ts.map +1 -1
  118. package/dist/platform-messages.d.ts +2 -2
  119. package/dist/platform-messages.d.ts.map +1 -1
  120. package/dist/platform-messages.js +2 -2
  121. package/dist/platform-messages.js.map +1 -1
  122. package/dist/portal-shell.d.ts.map +1 -1
  123. package/dist/provisioner.d.ts.map +1 -1
  124. package/dist/runtime/{conversation-orchestrator.d.ts → agent-run-controller.d.ts} +5 -5
  125. package/dist/runtime/agent-run-controller.d.ts.map +1 -0
  126. package/dist/runtime/{conversation-orchestrator.js → agent-run-controller.js} +17 -17
  127. package/dist/runtime/agent-run-controller.js.map +1 -0
  128. package/dist/runtime/conversation-runtime.d.ts +4 -0
  129. package/dist/runtime/conversation-runtime.d.ts.map +1 -0
  130. package/dist/runtime/{session-runtime.js → conversation-runtime.js} +12 -12
  131. package/dist/runtime/conversation-runtime.js.map +1 -0
  132. package/dist/runtime/types.d.ts +9 -9
  133. package/dist/runtime/types.d.ts.map +1 -1
  134. package/dist/runtime/types.js.map +1 -1
  135. package/dist/sandbox/cloudflare.d.ts.map +1 -1
  136. package/dist/sandbox/container.d.ts.map +1 -1
  137. package/dist/sandbox/errors.d.ts.map +1 -1
  138. package/dist/sandbox/firecracker.d.ts.map +1 -1
  139. package/dist/sandbox/host.d.ts.map +1 -1
  140. package/dist/sandbox/image.d.ts.map +1 -1
  141. package/dist/sandbox/index.d.ts.map +1 -1
  142. package/dist/sandbox/path-context.d.ts.map +1 -1
  143. package/dist/sandbox/types.d.ts.map +1 -1
  144. package/dist/sandbox/utils.d.ts.map +1 -1
  145. package/dist/sessions/{chat-session-manager.d.ts → agent-memory-file-manager.d.ts} +6 -6
  146. package/dist/sessions/agent-memory-file-manager.d.ts.map +1 -0
  147. package/dist/sessions/{chat-session-manager.js → agent-memory-file-manager.js} +16 -16
  148. package/dist/sessions/agent-memory-file-manager.js.map +1 -0
  149. package/dist/sessions/metadata.d.ts.map +1 -1
  150. package/dist/sessions/policy.d.ts.map +1 -1
  151. package/dist/sessions/store.d.ts.map +1 -1
  152. package/dist/sessions/store.js +4 -4
  153. package/dist/sessions/store.js.map +1 -1
  154. package/dist/sessions/types.d.ts +3 -3
  155. package/dist/sessions/types.d.ts.map +1 -1
  156. package/dist/sessions/types.js.map +1 -1
  157. package/dist/store.d.ts +3 -0
  158. package/dist/store.d.ts.map +1 -1
  159. package/dist/store.js +1 -1
  160. package/dist/store.js.map +1 -1
  161. package/dist/tool-diagnostics.d.ts.map +1 -1
  162. package/dist/tools/bash.d.ts.map +1 -1
  163. package/dist/tools/edit.d.ts.map +1 -1
  164. package/dist/tools/event.d.ts.map +1 -1
  165. package/dist/tools/index.d.ts.map +1 -1
  166. package/dist/tools/read.d.ts.map +1 -1
  167. package/dist/tools/sandbox.d.ts.map +1 -1
  168. package/dist/tools/truncate.d.ts.map +1 -1
  169. package/dist/tools/types.d.ts.map +1 -1
  170. package/dist/tools/write.d.ts.map +1 -1
  171. package/dist/trigger.d.ts +2 -2
  172. package/dist/trigger.d.ts.map +1 -1
  173. package/dist/trigger.js +1 -1
  174. package/dist/trigger.js.map +1 -1
  175. package/dist/types.d.ts +47 -24
  176. package/dist/types.d.ts.map +1 -1
  177. package/dist/types.js +1 -1
  178. package/dist/types.js.map +1 -1
  179. package/dist/utils/date.d.ts +1 -1
  180. package/dist/utils/date.d.ts.map +1 -1
  181. package/dist/utils/date.js +1 -1
  182. package/dist/utils/date.js.map +1 -1
  183. package/dist/utils/env.d.ts.map +1 -1
  184. package/dist/utils/file-guards.d.ts.map +1 -1
  185. package/dist/utils/fs-atomic.d.ts.map +1 -1
  186. package/dist/utils/html.d.ts.map +1 -1
  187. package/dist/utils/http-body.d.ts.map +1 -1
  188. package/dist/vault/index.d.ts.map +1 -1
  189. package/dist/vault/routing.d.ts.map +1 -1
  190. package/dist/vault/types.d.ts.map +1 -1
  191. package/dist/web/admin/portal.d.ts.map +1 -1
  192. package/dist/web/admin/portal.js +1 -1
  193. package/dist/web/admin/portal.js.map +1 -1
  194. package/dist/web/admin/provider-models.d.ts.map +1 -1
  195. package/dist/web/admin/store.d.ts.map +1 -1
  196. package/dist/web/admin/types.d.ts +1 -1
  197. package/dist/web/admin/types.d.ts.map +1 -1
  198. package/dist/web/admin/types.js.map +1 -1
  199. package/dist/web/agent-events/portal.d.ts +3 -0
  200. package/dist/web/agent-events/portal.d.ts.map +1 -0
  201. package/dist/web/agent-events/portal.js +18 -0
  202. package/dist/web/agent-events/portal.js.map +1 -0
  203. package/dist/web/login/oauth.d.ts.map +1 -1
  204. package/dist/web/login/oauth.js.map +1 -1
  205. package/dist/web/login/portal.d.ts +2 -14
  206. package/dist/web/login/portal.d.ts.map +1 -1
  207. package/dist/web/login/portal.js +53 -130
  208. package/dist/web/login/portal.js.map +1 -1
  209. package/dist/web/login/store.d.ts.map +1 -1
  210. package/dist/web/login/types.d.ts.map +1 -1
  211. package/dist/web/request.d.ts +3 -0
  212. package/dist/web/request.d.ts.map +1 -0
  213. package/dist/web/request.js +13 -0
  214. package/dist/web/request.js.map +1 -0
  215. package/dist/web/server.d.ts +28 -0
  216. package/dist/web/server.d.ts.map +1 -0
  217. package/dist/web/server.js +66 -0
  218. package/dist/web/server.js.map +1 -0
  219. package/dist/web/session-view/command.d.ts.map +1 -1
  220. package/dist/web/session-view/portal.d.ts.map +1 -1
  221. package/dist/web/session-view/portal.js +8 -8
  222. package/dist/web/session-view/portal.js.map +1 -1
  223. package/dist/web/session-view/service.d.ts.map +1 -1
  224. package/dist/web/session-view/store.d.ts.map +1 -1
  225. package/dist/web/session-view/types.d.ts +4 -4
  226. package/dist/web/session-view/types.d.ts.map +1 -1
  227. package/dist/web/session-view/types.js.map +1 -1
  228. package/dist/web/token-store.d.ts.map +1 -1
  229. package/dist/web/types.d.ts.map +1 -1
  230. package/package.json +44 -20
  231. package/dist/runtime/conversation-orchestrator.d.ts.map +0 -1
  232. package/dist/runtime/conversation-orchestrator.js.map +0 -1
  233. package/dist/runtime/session-runtime.d.ts +0 -4
  234. package/dist/runtime/session-runtime.d.ts.map +0 -1
  235. package/dist/runtime/session-runtime.js.map +0 -1
  236. package/dist/sessions/chat-session-manager.d.ts.map +0 -1
  237. package/dist/sessions/chat-session-manager.js.map +0 -1
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 \"./observability/instrument.js\";\n\nimport { join, resolve } from \"path\";\nimport { mkdirSync, 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/bot.js\";\nimport { TelegramBot } from \"./adapters/telegram/bot.js\";\nimport { SlackBot as SlackBotClass } from \"./adapters/slack/bot.js\";\nimport { downloadChannel } from \"./download.js\";\nimport { EventsWatcher } from \"./events.js\";\nimport * as log from \"./log.js\";\nimport { startLinkServer } from \"./web/login/portal.js\";\nimport { InMemoryAdminTokenStore } from \"./web/admin/store.js\";\nimport { InMemoryLinkTokenStore } from \"./web/login/store.js\";\nimport { InMemorySessionViewTokenStore } from \"./web/session-view/store.js\";\nimport { DockerContainerManager } from \"./provisioner.js\";\nimport {\n createGlobalSettingsFile,\n loadGlobalSettings,\n MissingGlobalSettingsError,\n} from \"./config.js\";\nimport { readEnv, setEnvAliases } from \"./utils/env.js\";\nimport { ensureDirExists, isRecord, readJsonFileIfExists } from \"./utils/file-guards.js\";\nimport {\n SandboxError,\n parseSandboxArg,\n type SandboxConfig,\n validateSandbox,\n} from \"./sandbox/index.js\";\nimport { FileVaultManager } from \"./vault/index.js\";\nimport { createSessionRuntime } from \"./runtime/session-runtime.js\";\nimport { ChannelStore } from \"./store.js\";\nimport * as Sentry from \"@sentry/node\";\n\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 const pkg = readJsonFileIfExists(\n pkgPath,\n (value): value is { version?: unknown } => isRecord(value),\n () => \"Ignoring package.json while resolving version\",\n );\n if (typeof pkg?.version === \"string\" && pkg.version) return pkg.version;\n }\n return \"unknown\";\n}\n\nconst SLACK_APP_TOKEN = readEnv(\"SLACK_APP_TOKEN\");\nconst SLACK_BOT_TOKEN = readEnv(\"SLACK_BOT_TOKEN\");\nconst TELEGRAM_BOT_TOKEN = readEnv(\"TELEGRAM_BOT_TOKEN\");\nconst DISCORD_BOT_TOKEN = readEnv(\"DISCORD_BOT_TOKEN\");\nconst LINK_URL = readEnv(\"LINK_URL\");\nconst LINK_PORT = readEnv(\"LINK_PORT\")\n ? parseInt(readEnv(\"LINK_PORT\") ?? \"\", 10)\n : LINK_URL\n ? 8181\n : undefined;\n\ninterface ParsedArgs {\n workingDir?: string;\n stateDir?: string;\n sandbox: SandboxConfig;\n downloadChannel?: string;\n showOnboard?: boolean;\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 showOnboard = false;\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 === \"--onboard\") {\n showOnboard = 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 showOnboard,\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 mikan is running as uid ${euid}. ` +\n `Run mikan 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 if (error instanceof MissingGlobalSettingsError) {\n console.error(`Missing global settings: ${error.settingsPath}`);\n console.error(\"\");\n console.error(\"Run onboarding to create it:\");\n console.error(` mikan --onboard --state-dir ${stateDir}`);\n console.error(\"\");\n console.error(\"Then review the generated settings.json and start mikan again.\");\n process.exit(1);\n }\n if (error instanceof Error) {\n console.error(`Error: ${error.message}`);\n process.exit(1);\n }\n console.error(String(error));\n process.exit(1);\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 --onboard mode\nif (parsedArgs.showOnboard) {\n const stateDir = parsedArgs.stateDir ?? join(homedir(), \".mikan\");\n setEnvAliases(\"STATE_DIR\", stateDir);\n ensureSecureStateDir(stateDir);\n try {\n const settingsPath = createGlobalSettingsFile(stateDir);\n console.log(`Created global settings at ${settingsPath}`);\n console.log(\"Review the file, then start mikan with your working directory.\");\n process.exit(0);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\n// Handle --download mode (Slack only)\nif (parsedArgs.downloadChannel) {\n if (!SLACK_BOT_TOKEN) {\n console.error(\"Missing env: SLACK_BOT_TOKEN\");\n process.exit(1);\n }\n await downloadChannel(parsedArgs.downloadChannel, SLACK_BOT_TOKEN);\n process.exit(0);\n}\n\n// Normal bot mode - require working dir\nif (!parsedArgs.workingDir) {\n console.error(\n \"Usage: mikan [--state-dir=<dir>] [--sandbox=host|container:<name>|image:<image>|firecracker:<vm-id>:<host-path>|cloudflare:<sandbox-id>] <working-directory>\",\n );\n console.error(\" mikan --onboard [--state-dir=<dir>]\");\n console.error(\" mikan --download <channel-id>\");\n process.exit(1);\n}\n\nconst { workingDir, sandbox } = { workingDir: parsedArgs.workingDir, sandbox: parsedArgs.sandbox };\nconst stateDir = parsedArgs.stateDir ?? join(homedir(), \".mikan\");\nsetEnvAliases(\"STATE_DIR\", stateDir);\nensureSecureStateDir(stateDir);\n\n// Validate platform tokens\nconst hasSlack = !!(SLACK_APP_TOKEN && SLACK_BOT_TOKEN);\nconst hasTelegram = !!TELEGRAM_BOT_TOKEN;\nconst hasDiscord = !!DISCORD_BOT_TOKEN;\n\nif (!hasSlack && !hasTelegram && !hasDiscord) {\n console.error(\n \"No platform tokens found. Set one of:\\n\" +\n \" Slack: SLACK_APP_TOKEN + SLACK_BOT_TOKEN\\n\" +\n \" Telegram: TELEGRAM_BOT_TOKEN\\n\" +\n \" Discord: 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 startupConfig = (() => {\n try {\n return loadGlobalSettings();\n } catch (error) {\n handleStartupError(error);\n }\n})();\nconst sandboxLimits =\n startupConfig.sandboxCpus || startupConfig.sandboxMemory\n ? { cpus: startupConfig.sandboxCpus, memory: startupConfig.sandboxMemory }\n : undefined;\nconst sandboxBoostLimits =\n startupConfig.sandboxBoostCpus || startupConfig.sandboxBoostMemory\n ? { cpus: startupConfig.sandboxBoostCpus, memory: startupConfig.sandboxBoostMemory }\n : undefined;\n\nconst provisioner =\n sandbox.type === \"image\"\n ? new DockerContainerManager(sandbox.image, {\n limits: sandboxLimits,\n boostLimits: sandboxBoostLimits,\n })\n : undefined;\n\nif (sandbox.type === \"image\") {\n ensureDirExists(join(workingDir, \"skills\"));\n ensureDirExists(join(workingDir, \"events\"));\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();\nconst adminTokenStore = new InMemoryAdminTokenStore();\nsetInterval(() => linkTokenStore.purge(), 5 * 60 * 1000).unref();\nsetInterval(() => sessionViewTokenStore.purge(), 5 * 60 * 1000).unref();\nsetInterval(() => adminTokenStore.purge(), 5 * 60 * 1000).unref();\n\nfunction portalBaseUrl(): string | undefined {\n if (LINK_URL) return LINK_URL.replace(/\\/+$/, \"\");\n if (LINK_PORT) return `http://localhost:${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 provisioner,\n linkTokenStore,\n sessionViewTokenStore,\n adminTokenStore,\n portalBaseUrl: portalBaseUrl(),\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\nconst bots: Bot[] = [];\nconst botsByPlatform: Record<string, Bot> = {};\n\nif (hasSlack) {\n const slackBotToken = SLACK_BOT_TOKEN;\n const slackAppToken = SLACK_APP_TOKEN;\n if (!slackBotToken || !slackAppToken) {\n throw new Error(\"Slack startup requires both SLACK_APP_TOKEN and SLACK_BOT_TOKEN\");\n }\n const sharedStore = new ChannelStore({ workingDir, botToken: slackBotToken });\n const slackBot = new SlackBotClass(handler, {\n appToken: slackAppToken,\n botToken: slackBotToken,\n workingDir,\n store: sharedStore,\n });\n bots.push(slackBot);\n botsByPlatform.slack = slackBot;\n log.logInfo(\"Platform: Slack\");\n}\nif (hasTelegram) {\n const telegramToken = TELEGRAM_BOT_TOKEN;\n if (!telegramToken) {\n throw new Error(\"Telegram startup requires TELEGRAM_BOT_TOKEN\");\n }\n const telegramBot = new TelegramBot(handler, {\n token: telegramToken,\n workingDir,\n });\n bots.push(telegramBot);\n botsByPlatform.telegram = telegramBot;\n log.logInfo(\"Platform: Telegram\");\n}\nif (hasDiscord) {\n const discordToken = DISCORD_BOT_TOKEN;\n if (!discordToken) {\n throw new Error(\"Discord startup requires DISCORD_BOT_TOKEN\");\n }\n const discordBot = new DiscordBot(handler, {\n token: discordToken,\n workingDir,\n });\n bots.push(discordBot);\n botsByPlatform.discord = discordBot;\n log.logInfo(\"Platform: Discord\");\n}\n\nif (LINK_PORT) {\n startLinkServer(\n 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 { handler, botsByPlatform },\n { adminTokenStore, workingDir, runtime: handler, sandbox, botsByPlatform },\n );\n}\n\n// Start events watcher with explicit platform routing\nconst eventsWatcher = new EventsWatcher(join(workingDir, \"events\"), 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"]}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\nimport \"./observability/instrument.js\";\n\nimport { join, resolve } from \"path\";\nimport { mkdirSync, statSync, writeFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { fileURLToPath } from \"url\";\nimport { dirname, join as pathJoin } from \"path\";\nimport type { MessagingBot } from \"./adapter.js\";\nimport { DiscordMessagingBot } from \"./adapters/discord/bot.js\";\nimport { TelegramMessagingBot } from \"./adapters/telegram/bot.js\";\nimport { SlackMessagingBot as SlackMessagingBotClass } from \"./adapters/slack/bot.js\";\nimport { downloadChannel } from \"./download.js\";\nimport { EventsWatcher } from \"./events.js\";\nimport * as log from \"./log.js\";\nimport { startWebServer } from \"./web/server.js\";\nimport { InMemoryAdminTokenStore } from \"./web/admin/store.js\";\nimport { InMemoryLinkTokenStore } from \"./web/login/store.js\";\nimport { InMemorySessionViewTokenStore } from \"./web/session-view/store.js\";\nimport { DockerContainerManager } from \"./provisioner.js\";\nimport {\n createGlobalSettingsFile,\n loadGlobalSettings,\n MissingGlobalSettingsError,\n} from \"./config.js\";\nimport { readEnv, setEnvAliases } from \"./utils/env.js\";\nimport { ensureDirExists, isRecord, readJsonFileIfExists } from \"./utils/file-guards.js\";\nimport {\n SandboxError,\n parseSandboxArg,\n type SandboxConfig,\n validateSandbox,\n} from \"./sandbox/index.js\";\nimport { FileVaultManager } from \"./vault/index.js\";\nimport { createConversationRuntime } from \"./runtime/conversation-runtime.js\";\nimport { ChannelStore } from \"./store.js\";\nimport * as Sentry from \"@sentry/node\";\n\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 const pkg = readJsonFileIfExists(\n pkgPath,\n (value): value is { version?: unknown } => isRecord(value),\n () => \"Ignoring package.json while resolving version\",\n );\n if (typeof pkg?.version === \"string\" && pkg.version) return pkg.version;\n }\n return \"unknown\";\n}\n\nconst SLACK_APP_TOKEN = readEnv(\"SLACK_APP_TOKEN\");\nconst SLACK_BOT_TOKEN = readEnv(\"SLACK_BOT_TOKEN\");\nconst TELEGRAM_BOT_TOKEN = readEnv(\"TELEGRAM_BOT_TOKEN\");\nconst DISCORD_BOT_TOKEN = readEnv(\"DISCORD_BOT_TOKEN\");\nconst LINK_URL = readEnv(\"LINK_URL\");\nconst LINK_PORT = readEnv(\"LINK_PORT\")\n ? parseInt(readEnv(\"LINK_PORT\") ?? \"\", 10)\n : LINK_URL\n ? 8181\n : undefined;\n\ninterface ParsedArgs {\n workingDir?: string;\n stateDir?: string;\n sandbox: SandboxConfig;\n downloadChannel?: string;\n showOnboard?: boolean;\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 showOnboard = false;\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 === \"--onboard\") {\n showOnboard = 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 showOnboard,\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 mikan is running as uid ${euid}. ` +\n `Run mikan 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 if (error instanceof MissingGlobalSettingsError) {\n console.error(`Missing global settings: ${error.settingsPath}`);\n console.error(\"\");\n console.error(\"Run onboarding to create it:\");\n console.error(` mikan --onboard --state-dir ${stateDir}`);\n console.error(\"\");\n console.error(\"Then review the generated settings.json and start mikan again.\");\n process.exit(1);\n }\n if (error instanceof Error) {\n console.error(`Error: ${error.message}`);\n process.exit(1);\n }\n console.error(String(error));\n process.exit(1);\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 --onboard mode\nif (parsedArgs.showOnboard) {\n const stateDir = parsedArgs.stateDir ?? join(homedir(), \".mikan\");\n setEnvAliases(\"STATE_DIR\", stateDir);\n ensureSecureStateDir(stateDir);\n try {\n const settingsPath = createGlobalSettingsFile(stateDir);\n console.log(`Created global settings at ${settingsPath}`);\n console.log(\"Review the file, then start mikan with your working directory.\");\n process.exit(0);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\n// Handle --download mode (Slack only)\nif (parsedArgs.downloadChannel) {\n if (!SLACK_BOT_TOKEN) {\n console.error(\"Missing env: SLACK_BOT_TOKEN\");\n process.exit(1);\n }\n await downloadChannel(parsedArgs.downloadChannel, SLACK_BOT_TOKEN);\n process.exit(0);\n}\n\n// Normal bot mode - require working dir\nif (!parsedArgs.workingDir) {\n console.error(\n \"Usage: mikan [--state-dir=<dir>] [--sandbox=host|container:<name>|image:<image>|firecracker:<vm-id>:<host-path>|cloudflare:<sandbox-id>] <working-directory>\",\n );\n console.error(\" mikan --onboard [--state-dir=<dir>]\");\n console.error(\" mikan --download <channel-id>\");\n process.exit(1);\n}\n\nconst { workingDir, sandbox } = { workingDir: parsedArgs.workingDir, sandbox: parsedArgs.sandbox };\nconst stateDir = parsedArgs.stateDir ?? join(homedir(), \".mikan\");\nsetEnvAliases(\"STATE_DIR\", stateDir);\nensureSecureStateDir(stateDir);\n\n// Validate platform tokens\nconst hasSlack = !!(SLACK_APP_TOKEN && SLACK_BOT_TOKEN);\nconst hasTelegram = !!TELEGRAM_BOT_TOKEN;\nconst hasDiscord = !!DISCORD_BOT_TOKEN;\n\nif (!hasSlack && !hasTelegram && !hasDiscord) {\n console.error(\n \"No platform tokens found. Set one of:\\n\" +\n \" Slack: SLACK_APP_TOKEN + SLACK_BOT_TOKEN\\n\" +\n \" Telegram: TELEGRAM_BOT_TOKEN\\n\" +\n \" Discord: 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 startupConfig = (() => {\n try {\n return loadGlobalSettings();\n } catch (error) {\n handleStartupError(error);\n }\n})();\nconst sandboxLimits =\n startupConfig.sandboxCpus || startupConfig.sandboxMemory\n ? { cpus: startupConfig.sandboxCpus, memory: startupConfig.sandboxMemory }\n : undefined;\nconst sandboxBoostLimits =\n startupConfig.sandboxBoostCpus || startupConfig.sandboxBoostMemory\n ? { cpus: startupConfig.sandboxBoostCpus, memory: startupConfig.sandboxBoostMemory }\n : undefined;\n\nconst provisioner =\n sandbox.type === \"image\"\n ? new DockerContainerManager(sandbox.image, {\n limits: sandboxLimits,\n boostLimits: sandboxBoostLimits,\n })\n : undefined;\n\nif (sandbox.type === \"image\") {\n ensureDirExists(join(workingDir, \"skills\"));\n ensureDirExists(join(workingDir, \"events\"));\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();\nconst adminTokenStore = new InMemoryAdminTokenStore();\nsetInterval(() => linkTokenStore.purge(), 5 * 60 * 1000).unref();\nsetInterval(() => sessionViewTokenStore.purge(), 5 * 60 * 1000).unref();\nsetInterval(() => adminTokenStore.purge(), 5 * 60 * 1000).unref();\n\nfunction portalBaseUrl(): string | undefined {\n if (LINK_URL) return LINK_URL.replace(/\\/+$/, \"\");\n if (LINK_PORT) return `http://localhost:${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 = createConversationRuntime({\n workingDir,\n sandbox,\n vaultManager,\n provisioner,\n linkTokenStore,\n sessionViewTokenStore,\n adminTokenStore,\n portalBaseUrl: portalBaseUrl(),\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\nconst bots: MessagingBot[] = [];\nconst botsByPlatform: Record<string, MessagingBot> = {};\n\nif (hasSlack) {\n const slackMessagingBotToken = SLACK_BOT_TOKEN;\n const slackAppToken = SLACK_APP_TOKEN;\n if (!slackMessagingBotToken || !slackAppToken) {\n throw new Error(\"Slack startup requires both SLACK_APP_TOKEN and SLACK_BOT_TOKEN\");\n }\n const sharedStore = new ChannelStore({ workingDir, botToken: slackMessagingBotToken });\n const slackMessagingBot = new SlackMessagingBotClass(handler, {\n appToken: slackAppToken,\n botToken: slackMessagingBotToken,\n workingDir,\n store: sharedStore,\n });\n bots.push(slackMessagingBot);\n botsByPlatform.slack = slackMessagingBot;\n log.logInfo(\"Platform: Slack\");\n}\nif (hasTelegram) {\n const telegramToken = TELEGRAM_BOT_TOKEN;\n if (!telegramToken) {\n throw new Error(\"Telegram startup requires TELEGRAM_BOT_TOKEN\");\n }\n const telegramMessagingBot = new TelegramMessagingBot(handler, {\n token: telegramToken,\n workingDir,\n });\n bots.push(telegramMessagingBot);\n botsByPlatform.telegram = telegramMessagingBot;\n log.logInfo(\"Platform: Telegram\");\n}\nif (hasDiscord) {\n const discordToken = DISCORD_BOT_TOKEN;\n if (!discordToken) {\n throw new Error(\"Discord startup requires DISCORD_BOT_TOKEN\");\n }\n const discordMessagingBot = new DiscordMessagingBot(handler, {\n token: discordToken,\n workingDir,\n });\n bots.push(discordMessagingBot);\n botsByPlatform.discord = discordMessagingBot;\n log.logInfo(\"Platform: Discord\");\n}\n\nif (LINK_PORT) {\n startWebServer({\n port: LINK_PORT,\n linkTokenStore,\n vaultManager,\n notify: async (platform, conversationId, message) => {\n const bot = botsByPlatform[platform];\n if (bot) await bot.postMessage(conversationId, message);\n },\n sessionViewTokenStore,\n sessionViewInteractive: { handler, botsByPlatform },\n adminOptions: { adminTokenStore, workingDir, runtime: handler, sandbox, botsByPlatform },\n });\n}\n\n// Start events watcher with explicit platform routing\nconst eventsWatcher = new EventsWatcher(join(workingDir, \"events\"), botsByPlatform);\nconst slackMessagingBot = botsByPlatform.slack as SlackMessagingBotClass | undefined;\nif (slackMessagingBot) {\n slackMessagingBot.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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"model-registry.d.ts","sourceRoot":"","sources":["../src/model-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAEhE,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,aAAa,EAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,KAAK,CAAC,GAAG,CAAC,CAOZ","sourcesContent":["import { type Api, type Model } from \"@earendil-works/pi-ai\";\nimport { ModelRegistry } from \"@earendil-works/pi-coding-agent\";\n\nexport function resolveConfiguredModel(\n modelRegistry: ModelRegistry,\n provider: string,\n modelId: string,\n): Model<Api> {\n const model = modelRegistry.find(provider, modelId) as Model<Api> | undefined;\n if (model) return model;\n\n throw new Error(\n `Unknown model \"${provider}/${modelId}\". Configure it in pi models.json or choose a registered model.`,\n );\n}\n"]}
1
+ {"version":3,"file":"model-registry.d.ts","sourceRoot":"","sources":["../src/model-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAEhE,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,aAAa,EAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,KAAK,CAAC,GAAG,CAAC,CAOZ"}
@@ -1 +1 @@
1
- {"version":3,"file":"instrument.d.ts","sourceRoot":"","sources":["../../src/observability/instrument.ts"],"names":[],"mappings":"","sourcesContent":["import * as Sentry from \"@sentry/node\";\nimport { resolveSentryDsn, resolveStateDirFromArgv } from \"../config.js\";\nimport { setEnvAliases } from \"../utils/env.js\";\nimport { createSentryInitOptions } from \"./sentry.js\";\n\nif (!process.env.STATE_DIR && !process.env.MIKAN_STATE_DIR) {\n setEnvAliases(\"STATE_DIR\", resolveStateDirFromArgv());\n}\nconst sentryDsn = resolveSentryDsn();\n\nSentry.init(createSentryInitOptions(sentryDsn));\n"]}
1
+ {"version":3,"file":"instrument.d.ts","sourceRoot":"","sources":["../../src/observability/instrument.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"sentry.d.ts","sourceRoot":"","sources":["../../src/observability/sentry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAwDpF,YAAY,EACV,4BAA4B,EAC5B,2BAA2B,EAC3B,qBAAqB,EACrB,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,4BAA4B,EAC5B,2BAA2B,EAC3B,qBAAqB,EACrB,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAIpB,wBAAgB,uBAAuB,CAAC,GAAG,CAAC,EAAE,MAAM;;;;;;;;sBAS9B,UAAU,QAAQ,SAAS,GAAG,UAAU,GAAG,IAAI;yBAG5C,iBAAiB,GAAG,iBAAiB;iCAG7B,wBAAwB,GAAG,wBAAwB,GAAG,IAAI;iCAG1D,UAAU,GAAG,UAAU,GAAG,IAAI;EAI9D;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,4BAA4B,GACpC,MAAM,GAAG,SAAS,CAkCpB;AAMD,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,qBAAqB,GAC7B,2BAA2B,CAY7B;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE;IAAE,aAAa,CAAC,UAAU,EAAE,2BAA2B,GAAG,OAAO,CAAA;CAAE,EACzE,UAAU,EAAE,2BAA2B,GACtC,IAAI,CAKN;AAED,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,2BAA2B,GAAG,IAAI,CAIzF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAyBhF;AAED,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,GAChE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAO3C;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,GAC3D,IAAI,CAON;AAED,wBAAgB,aAAa,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,SAAS,GAAG,CAAC,GAAG,IAAI,CA2CpF;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,iBAAiB,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAU5E;AAsBD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI,CAU5E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,OAAO,CAwB9E","sourcesContent":["import type { Breadcrumb, ErrorEvent, Event, EventHint, Scope } from \"@sentry/node\";\nimport * as Sentry from \"@sentry/node\";\n\nconst REDACTED = \"[REDACTED]\";\nconst REDACTED_PATH = \"[REDACTED_PATH]\";\nconst MAX_STRING_LENGTH = 256;\nconst MAX_DEPTH = 4;\n\nconst SENSITIVE_KEYS = new Set([\n \"accesstoken\",\n \"apikey\",\n \"args\",\n \"attachment\",\n \"attachments\",\n \"authorization\",\n \"body\",\n \"code\",\n \"content\",\n \"contents\",\n \"cookie\",\n \"cookies\",\n \"credential\",\n \"filepath\",\n \"headers\",\n \"image\",\n \"imageattachments\",\n \"images\",\n \"localpath\",\n \"messages\",\n \"newusermessage\",\n \"password\",\n \"path\",\n \"paths\",\n \"prompt\",\n \"refreshtoken\",\n \"response\",\n \"result\",\n \"secret\",\n \"systemprompt\",\n \"text\",\n \"thinking\",\n \"token\",\n \"url\",\n \"uri\",\n \"workspacepath\",\n]);\n\nconst ABSOLUTE_PATH_PATTERN =\n /(?:\\/Users\\/[^\\s\"'`]+|\\/workspace\\/[^\\s\"'`]+|\\/tmp\\/[^\\s\"'`]+|\\/var\\/folders\\/[^\\s\"'`]+|[A-Za-z]:\\\\[^\\s\"'`]+)/;\nconst TOKEN_PATTERNS = [\n /\\bsk-[A-Za-z0-9_-]{12,}\\b/,\n /\\bxox[a-z]-[A-Za-z0-9-]{10,}\\b/,\n /\\bAIza[0-9A-Za-z_-]{20,}\\b/,\n /\\bgh[pousr]_[A-Za-z0-9]{20,}\\b/,\n];\n\nexport type {\n ReportUserFacingErrorOptions,\n SentryAttributionAttributes,\n SentryRunScopeContext,\n SentrySpanPayload,\n SentryTransactionPayload,\n} from \"./types.js\";\nimport type {\n ReportUserFacingErrorOptions,\n SentryAttributionAttributes,\n SentryRunScopeContext,\n SentrySpanPayload,\n SentryTransactionPayload,\n} from \"./types.js\";\n\nconst traceAttribution = new Map<string, SentryAttributionAttributes>();\n\nexport function createSentryInitOptions(dsn?: string) {\n return {\n dsn,\n environment: process.env.SENTRY_ENVIRONMENT ?? \"production\",\n enabled: Boolean(dsn) && process.env.SENTRY_ENABLED !== \"false\",\n sendDefaultPii: false,\n tracesSampleRate: process.env.NODE_ENV === \"development\" ? 1.0 : 1.0,\n includeLocalVariables: false,\n enableLogs: true,\n beforeSend(event: ErrorEvent, hint: EventHint): ErrorEvent | null {\n return sanitizeEvent(event, hint);\n },\n beforeSendSpan(span: SentrySpanPayload): SentrySpanPayload {\n return applySpanAttribution(span);\n },\n beforeSendTransaction(event: SentryTransactionPayload): SentryTransactionPayload | null {\n return sanitizeTransactionEvent(event);\n },\n beforeBreadcrumb(breadcrumb: Breadcrumb): Breadcrumb | null {\n return sanitizeBreadcrumb(breadcrumb);\n },\n };\n}\n\nexport function reportUserFacingError(\n error: unknown,\n options: ReportUserFacingErrorOptions,\n): string | undefined {\n if (options.expected) return undefined;\n\n const exception = error instanceof Error ? error : new Error(String(error));\n return Sentry.withScope((scope) => {\n scope.setLevel(options.severity ?? \"error\");\n scope.setTag(\"user_facing\", \"true\");\n scope.setTag(\"expected\", \"false\");\n scope.setTag(\"error_domain\", options.domain);\n scope.setTag(\"error_surface\", options.surface);\n scope.setTag(\"operation\", options.operation);\n setOptionalTag(scope, \"platform\", options.platform);\n setOptionalTag(scope, \"provider\", options.provider);\n setOptionalTag(scope, \"model\", options.model);\n setOptionalTag(scope, \"tool\", options.toolName);\n setOptionalTag(scope, \"stop_reason\", options.stopReason);\n for (const [key, value] of Object.entries(options.tags ?? {})) {\n if (value !== undefined) scope.setTag(key, String(value));\n }\n if (options.fingerprint) scope.setFingerprint(options.fingerprint);\n scope.setContext(\"user_facing_error\", {\n domain: options.domain,\n surface: options.surface,\n operation: options.operation,\n severity: options.severity ?? \"error\",\n platform: options.platform,\n provider: options.provider,\n model: options.model,\n toolName: options.toolName,\n stopReason: options.stopReason,\n ...(sanitizeValue(options.context ?? {}) as Record<string, unknown>),\n });\n return Sentry.captureException(exception);\n });\n}\n\nfunction setOptionalTag(scope: Scope, key: string, value: string | undefined): void {\n if (value !== undefined) scope.setTag(key, value);\n}\n\nexport function createRunAttributionAttributes(\n context: SentryRunScopeContext,\n): SentryAttributionAttributes {\n return metricAttributes({\n conversation_id: context.conversationId,\n channel_id: context.conversationId,\n session_key: context.sessionKey,\n message_id: context.messageId,\n platform: context.platform,\n user_id: context.userId,\n thread_ts: context.threadTs,\n provider: context.provider,\n model: context.model,\n });\n}\n\nexport function registerTraceAttribution(\n span: { setAttributes(attributes: SentryAttributionAttributes): unknown },\n attributes: SentryAttributionAttributes,\n): void {\n span.setAttributes(attributes);\n const traceId = Sentry.spanToJSON(span as Parameters<typeof Sentry.spanToJSON>[0]).trace_id;\n if (!traceId) return;\n traceAttribution.set(traceId, { ...traceAttribution.get(traceId), ...attributes });\n}\n\nexport function updateActiveSpanAttribution(attributes: SentryAttributionAttributes): void {\n const span = Sentry.getActiveSpan();\n if (!span) return;\n registerTraceAttribution(span, attributes);\n}\n\nexport function applyRunScope(scope: Scope, context: SentryRunScopeContext): void {\n const attributes = createRunAttributionAttributes(context);\n\n for (const [key, value] of Object.entries(attributes)) {\n scope.setTag(key, value);\n }\n scope.setTag(\"conversation_id\", context.conversationId);\n scope.setTag(\"channel_id\", context.conversationId);\n if (context.threadTs) scope.setTag(\"thread_ts\", context.threadTs);\n\n scope.setAttributes(attributes);\n scope.setUser({\n id: context.userId,\n username: context.userName,\n });\n scope.setContext(\"agent_run\", {\n conversationId: context.conversationId,\n channelId: context.conversationId,\n sessionKey: context.sessionKey,\n messageId: context.messageId,\n threadTs: context.threadTs,\n platform: context.platform,\n provider: context.provider,\n model: context.model,\n });\n}\n\nexport function metricAttributes(\n attributes: Record<string, string | number | boolean | undefined>,\n): Record<string, string | number | boolean> {\n return Object.fromEntries(\n Object.entries(attributes).filter((entry): entry is [string, string | number | boolean] => {\n const [, value] = entry;\n return value !== undefined;\n }),\n );\n}\n\nexport function addLifecycleBreadcrumb(\n message: string,\n data?: Record<string, string | number | boolean | undefined>,\n): void {\n Sentry.addBreadcrumb({\n category: \"agent.lifecycle\",\n message,\n level: \"info\",\n data: data ? metricAttributes(data) : undefined,\n });\n}\n\nexport function sanitizeEvent<T extends Event>(event: T, _hint?: EventHint): T | null {\n const sanitized: T = {\n ...event,\n breadcrumbs: event.breadcrumbs\n ?.map((breadcrumb) => sanitizeBreadcrumb(breadcrumb))\n .filter((breadcrumb): breadcrumb is Breadcrumb => breadcrumb !== null),\n extra: sanitizeValue(event.extra) as T[\"extra\"],\n contexts: sanitizeValue(event.contexts) as T[\"contexts\"],\n request: sanitizeRequest(event.request),\n user: undefined,\n server_name: undefined,\n };\n\n if (sanitized.message) {\n sanitized.message = sanitizeString(sanitized.message);\n }\n\n if (sanitized.logentry) {\n sanitized.logentry = {\n ...sanitized.logentry,\n message: sanitized.logentry.message ? sanitizeString(sanitized.logentry.message) : undefined,\n };\n }\n\n if (sanitized.exception?.values) {\n sanitized.exception.values = sanitized.exception.values.map((value) => ({\n ...value,\n value: value.value ? sanitizeString(value.value) : value.value,\n stacktrace: value.stacktrace\n ? {\n ...value.stacktrace,\n frames: value.stacktrace.frames?.map((frame) => ({\n ...frame,\n filename: frame.filename ? sanitizeString(frame.filename) : frame.filename,\n abs_path: frame.abs_path ? sanitizeString(frame.abs_path) : frame.abs_path,\n vars: undefined,\n })),\n }\n : value.stacktrace,\n }));\n }\n\n return sanitized;\n}\n\nexport function applySpanAttribution<T extends SentrySpanPayload>(span: T): T {\n const attributes = traceAttribution.get(span.trace_id);\n if (!attributes) return span;\n return {\n ...span,\n data: {\n ...span.data,\n ...attributes,\n },\n };\n}\n\nfunction sanitizeTransactionEvent<T extends SentryTransactionPayload>(event: T): T | null {\n const sanitized = sanitizeEvent(event);\n if (!sanitized) return null;\n\n const traceContext = sanitized.contexts?.trace;\n const traceId = traceContext?.trace_id;\n if (typeof traceId !== \"string\") return sanitized;\n const attributes = traceAttribution.get(traceId);\n if (!attributes) return sanitized;\n\n const entries = (sanitized as { entries?: Array<{ type?: string; data?: unknown }> }).entries;\n for (const entry of entries ?? []) {\n if (entry.type !== \"spans\" || !Array.isArray(entry.data)) continue;\n entry.data = entry.data.map((span: SentrySpanPayload) => applySpanAttribution(span));\n }\n\n traceAttribution.delete(traceId);\n return sanitized;\n}\n\nexport function sanitizeBreadcrumb(breadcrumb: Breadcrumb): Breadcrumb | null {\n if (breadcrumb.category === \"console\") {\n return null;\n }\n\n return {\n ...breadcrumb,\n message: breadcrumb.message ? sanitizeString(breadcrumb.message) : breadcrumb.message,\n data: sanitizeValue(breadcrumb.data) as Breadcrumb[\"data\"],\n };\n}\n\nexport function sanitizeValue(value: unknown, key?: string, depth = 0): unknown {\n if (value == null) return value;\n if (depth > MAX_DEPTH) return \"[Truncated]\";\n\n if (isSensitiveKey(key)) {\n return summarizeValue(value, key);\n }\n\n if (typeof value === \"string\") {\n return sanitizeString(value);\n }\n\n if (Array.isArray(value)) {\n return value.slice(0, 20).map((entry) => sanitizeValue(entry, key, depth + 1));\n }\n\n if (typeof value === \"object\") {\n const entries = Object.entries(value as Record<string, unknown>).map(\n ([entryKey, entryValue]) => [entryKey, sanitizeValue(entryValue, entryKey, depth + 1)],\n );\n return Object.fromEntries(entries);\n }\n\n return value;\n}\n\nfunction sanitizeRequest(request: Event[\"request\"]): Event[\"request\"] {\n if (!request) return request;\n\n return {\n ...request,\n data: request.data ? summarizeValue(request.data, \"body\") : undefined,\n headers: undefined,\n cookies: undefined,\n };\n}\n\nfunction isSensitiveKey(key?: string): boolean {\n if (!key) return false;\n return SENSITIVE_KEYS.has(key.toLowerCase());\n}\n\nfunction summarizeValue(value: unknown, key?: string): string {\n const label = key ?? \"field\";\n if (typeof value === \"string\") {\n return `[Redacted ${label}; length=${value.length}]`;\n }\n if (Array.isArray(value)) {\n return `[Redacted ${label}; items=${value.length}]`;\n }\n if (value && typeof value === \"object\") {\n return `[Redacted ${label}; keys=${Object.keys(value as Record<string, unknown>).length}]`;\n }\n return `[Redacted ${label}]`;\n}\n\nfunction sanitizeString(value: string): string {\n let sanitized = value.replace(new RegExp(ABSOLUTE_PATH_PATTERN, \"g\"), REDACTED_PATH);\n for (const pattern of TOKEN_PATTERNS) {\n sanitized = sanitized.replace(new RegExp(pattern, \"g\"), REDACTED);\n }\n if (sanitized.length > MAX_STRING_LENGTH) {\n return `${sanitized.slice(0, MAX_STRING_LENGTH)}… [truncated ${sanitized.length - MAX_STRING_LENGTH} chars]`;\n }\n return sanitized;\n}\n"]}
1
+ {"version":3,"file":"sentry.d.ts","sourceRoot":"","sources":["../../src/observability/sentry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AA0DpF,YAAY,EACV,4BAA4B,EAC5B,2BAA2B,EAC3B,qBAAqB,EACrB,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,4BAA4B,EAC5B,2BAA2B,EAC3B,qBAAqB,EACrB,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AASpB,wBAAgB,uBAAuB,CAAC,GAAG,CAAC,EAAE,MAAM;;;;;;;;sBAS9B,UAAU,QAAQ,SAAS,GAAG,UAAU,GAAG,IAAI;yBAG5C,iBAAiB,GAAG,iBAAiB;iCAG7B,wBAAwB,GAAG,wBAAwB,GAAG,IAAI;iCAG1D,UAAU,GAAG,UAAU,GAAG,IAAI;EAI9D;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,4BAA4B,GACpC,MAAM,GAAG,SAAS,CAkCpB;AAMD,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,qBAAqB,GAC7B,2BAA2B,CAY7B;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE;IAAE,aAAa,CAAC,UAAU,EAAE,2BAA2B,GAAG,OAAO,CAAA;CAAE,EACzE,UAAU,EAAE,2BAA2B,GACtC,IAAI,CAWN;AAED,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,2BAA2B,GAAG,IAAI,CAIzF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAqBhF;AAED,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,GAChE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAO3C;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,GAC3D,IAAI,CAON;AAED,wBAAgB,aAAa,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,SAAS,GAAG,CAAC,GAAG,IAAI,CA2CpF;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,iBAAiB,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAU5E;AAsBD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI,CAU5E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,OAAO,CAwB9E"}
@@ -3,6 +3,7 @@ const REDACTED = "[REDACTED]";
3
3
  const REDACTED_PATH = "[REDACTED_PATH]";
4
4
  const MAX_STRING_LENGTH = 256;
5
5
  const MAX_DEPTH = 4;
6
+ const TRACE_ATTRIBUTION_TTL_MS = 5 * 60 * 1000;
6
7
  const SENSITIVE_KEYS = new Set([
7
8
  "accesstoken",
8
9
  "apikey",
@@ -11,6 +12,7 @@ const SENSITIVE_KEYS = new Set([
11
12
  "attachments",
12
13
  "authorization",
13
14
  "body",
15
+ "clientsecret",
14
16
  "code",
15
17
  "content",
16
18
  "contents",
@@ -55,7 +57,7 @@ export function createSentryInitOptions(dsn) {
55
57
  environment: process.env.SENTRY_ENVIRONMENT ?? "production",
56
58
  enabled: Boolean(dsn) && process.env.SENTRY_ENABLED !== "false",
57
59
  sendDefaultPii: false,
58
- tracesSampleRate: process.env.NODE_ENV === "development" ? 1.0 : 1.0,
60
+ tracesSampleRate: 1.0,
59
61
  includeLocalVariables: false,
60
62
  enableLogs: true,
61
63
  beforeSend(event, hint) {
@@ -131,7 +133,12 @@ export function registerTraceAttribution(span, attributes) {
131
133
  const traceId = Sentry.spanToJSON(span).trace_id;
132
134
  if (!traceId)
133
135
  return;
134
- traceAttribution.set(traceId, { ...traceAttribution.get(traceId), ...attributes });
136
+ const now = Date.now();
137
+ pruneExpiredTraceAttributions(now);
138
+ traceAttribution.set(traceId, {
139
+ attributes: { ...traceAttribution.get(traceId)?.attributes, ...attributes },
140
+ expiresAt: now + TRACE_ATTRIBUTION_TTL_MS,
141
+ });
135
142
  }
136
143
  export function updateActiveSpanAttribution(attributes) {
137
144
  const span = Sentry.getActiveSpan();
@@ -144,10 +151,6 @@ export function applyRunScope(scope, context) {
144
151
  for (const [key, value] of Object.entries(attributes)) {
145
152
  scope.setTag(key, value);
146
153
  }
147
- scope.setTag("conversation_id", context.conversationId);
148
- scope.setTag("channel_id", context.conversationId);
149
- if (context.threadTs)
150
- scope.setTag("thread_ts", context.threadTs);
151
154
  scope.setAttributes(attributes);
152
155
  scope.setUser({
153
156
  id: context.userId,
@@ -219,7 +222,7 @@ export function sanitizeEvent(event, _hint) {
219
222
  return sanitized;
220
223
  }
221
224
  export function applySpanAttribution(span) {
222
- const attributes = traceAttribution.get(span.trace_id);
225
+ const attributes = getTraceAttribution(span.trace_id);
223
226
  if (!attributes)
224
227
  return span;
225
228
  return {
@@ -238,7 +241,7 @@ function sanitizeTransactionEvent(event) {
238
241
  const traceId = traceContext?.trace_id;
239
242
  if (typeof traceId !== "string")
240
243
  return sanitized;
241
- const attributes = traceAttribution.get(traceId);
244
+ const attributes = getTraceAttribution(traceId);
242
245
  if (!attributes)
243
246
  return sanitized;
244
247
  const entries = sanitized.entries;
@@ -290,10 +293,25 @@ function sanitizeRequest(request) {
290
293
  cookies: undefined,
291
294
  };
292
295
  }
296
+ function getTraceAttribution(traceId) {
297
+ const entry = traceAttribution.get(traceId);
298
+ if (!entry)
299
+ return undefined;
300
+ if (entry.expiresAt > Date.now())
301
+ return entry.attributes;
302
+ traceAttribution.delete(traceId);
303
+ return undefined;
304
+ }
305
+ function pruneExpiredTraceAttributions(now) {
306
+ for (const [traceId, entry] of traceAttribution) {
307
+ if (entry.expiresAt <= now)
308
+ traceAttribution.delete(traceId);
309
+ }
310
+ }
293
311
  function isSensitiveKey(key) {
294
312
  if (!key)
295
313
  return false;
296
- return SENSITIVE_KEYS.has(key.toLowerCase());
314
+ return SENSITIVE_KEYS.has(key.toLowerCase().replace(/[^a-z0-9]/g, ""));
297
315
  }
298
316
  function summarizeValue(value, key) {
299
317
  const label = key ?? "field";
@@ -1 +1 @@
1
- {"version":3,"file":"sentry.js","sourceRoot":"","sources":["../../src/observability/sentry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Breadcrumb, ErrorEvent, Event, EventHint, Scope } from \"@sentry/node\";\nimport * as Sentry from \"@sentry/node\";\n\nconst REDACTED = \"[REDACTED]\";\nconst REDACTED_PATH = \"[REDACTED_PATH]\";\nconst MAX_STRING_LENGTH = 256;\nconst MAX_DEPTH = 4;\n\nconst SENSITIVE_KEYS = new Set([\n \"accesstoken\",\n \"apikey\",\n \"args\",\n \"attachment\",\n \"attachments\",\n \"authorization\",\n \"body\",\n \"code\",\n \"content\",\n \"contents\",\n \"cookie\",\n \"cookies\",\n \"credential\",\n \"filepath\",\n \"headers\",\n \"image\",\n \"imageattachments\",\n \"images\",\n \"localpath\",\n \"messages\",\n \"newusermessage\",\n \"password\",\n \"path\",\n \"paths\",\n \"prompt\",\n \"refreshtoken\",\n \"response\",\n \"result\",\n \"secret\",\n \"systemprompt\",\n \"text\",\n \"thinking\",\n \"token\",\n \"url\",\n \"uri\",\n \"workspacepath\",\n]);\n\nconst ABSOLUTE_PATH_PATTERN =\n /(?:\\/Users\\/[^\\s\"'`]+|\\/workspace\\/[^\\s\"'`]+|\\/tmp\\/[^\\s\"'`]+|\\/var\\/folders\\/[^\\s\"'`]+|[A-Za-z]:\\\\[^\\s\"'`]+)/;\nconst TOKEN_PATTERNS = [\n /\\bsk-[A-Za-z0-9_-]{12,}\\b/,\n /\\bxox[a-z]-[A-Za-z0-9-]{10,}\\b/,\n /\\bAIza[0-9A-Za-z_-]{20,}\\b/,\n /\\bgh[pousr]_[A-Za-z0-9]{20,}\\b/,\n];\n\nexport type {\n ReportUserFacingErrorOptions,\n SentryAttributionAttributes,\n SentryRunScopeContext,\n SentrySpanPayload,\n SentryTransactionPayload,\n} from \"./types.js\";\nimport type {\n ReportUserFacingErrorOptions,\n SentryAttributionAttributes,\n SentryRunScopeContext,\n SentrySpanPayload,\n SentryTransactionPayload,\n} from \"./types.js\";\n\nconst traceAttribution = new Map<string, SentryAttributionAttributes>();\n\nexport function createSentryInitOptions(dsn?: string) {\n return {\n dsn,\n environment: process.env.SENTRY_ENVIRONMENT ?? \"production\",\n enabled: Boolean(dsn) && process.env.SENTRY_ENABLED !== \"false\",\n sendDefaultPii: false,\n tracesSampleRate: process.env.NODE_ENV === \"development\" ? 1.0 : 1.0,\n includeLocalVariables: false,\n enableLogs: true,\n beforeSend(event: ErrorEvent, hint: EventHint): ErrorEvent | null {\n return sanitizeEvent(event, hint);\n },\n beforeSendSpan(span: SentrySpanPayload): SentrySpanPayload {\n return applySpanAttribution(span);\n },\n beforeSendTransaction(event: SentryTransactionPayload): SentryTransactionPayload | null {\n return sanitizeTransactionEvent(event);\n },\n beforeBreadcrumb(breadcrumb: Breadcrumb): Breadcrumb | null {\n return sanitizeBreadcrumb(breadcrumb);\n },\n };\n}\n\nexport function reportUserFacingError(\n error: unknown,\n options: ReportUserFacingErrorOptions,\n): string | undefined {\n if (options.expected) return undefined;\n\n const exception = error instanceof Error ? error : new Error(String(error));\n return Sentry.withScope((scope) => {\n scope.setLevel(options.severity ?? \"error\");\n scope.setTag(\"user_facing\", \"true\");\n scope.setTag(\"expected\", \"false\");\n scope.setTag(\"error_domain\", options.domain);\n scope.setTag(\"error_surface\", options.surface);\n scope.setTag(\"operation\", options.operation);\n setOptionalTag(scope, \"platform\", options.platform);\n setOptionalTag(scope, \"provider\", options.provider);\n setOptionalTag(scope, \"model\", options.model);\n setOptionalTag(scope, \"tool\", options.toolName);\n setOptionalTag(scope, \"stop_reason\", options.stopReason);\n for (const [key, value] of Object.entries(options.tags ?? {})) {\n if (value !== undefined) scope.setTag(key, String(value));\n }\n if (options.fingerprint) scope.setFingerprint(options.fingerprint);\n scope.setContext(\"user_facing_error\", {\n domain: options.domain,\n surface: options.surface,\n operation: options.operation,\n severity: options.severity ?? \"error\",\n platform: options.platform,\n provider: options.provider,\n model: options.model,\n toolName: options.toolName,\n stopReason: options.stopReason,\n ...(sanitizeValue(options.context ?? {}) as Record<string, unknown>),\n });\n return Sentry.captureException(exception);\n });\n}\n\nfunction setOptionalTag(scope: Scope, key: string, value: string | undefined): void {\n if (value !== undefined) scope.setTag(key, value);\n}\n\nexport function createRunAttributionAttributes(\n context: SentryRunScopeContext,\n): SentryAttributionAttributes {\n return metricAttributes({\n conversation_id: context.conversationId,\n channel_id: context.conversationId,\n session_key: context.sessionKey,\n message_id: context.messageId,\n platform: context.platform,\n user_id: context.userId,\n thread_ts: context.threadTs,\n provider: context.provider,\n model: context.model,\n });\n}\n\nexport function registerTraceAttribution(\n span: { setAttributes(attributes: SentryAttributionAttributes): unknown },\n attributes: SentryAttributionAttributes,\n): void {\n span.setAttributes(attributes);\n const traceId = Sentry.spanToJSON(span as Parameters<typeof Sentry.spanToJSON>[0]).trace_id;\n if (!traceId) return;\n traceAttribution.set(traceId, { ...traceAttribution.get(traceId), ...attributes });\n}\n\nexport function updateActiveSpanAttribution(attributes: SentryAttributionAttributes): void {\n const span = Sentry.getActiveSpan();\n if (!span) return;\n registerTraceAttribution(span, attributes);\n}\n\nexport function applyRunScope(scope: Scope, context: SentryRunScopeContext): void {\n const attributes = createRunAttributionAttributes(context);\n\n for (const [key, value] of Object.entries(attributes)) {\n scope.setTag(key, value);\n }\n scope.setTag(\"conversation_id\", context.conversationId);\n scope.setTag(\"channel_id\", context.conversationId);\n if (context.threadTs) scope.setTag(\"thread_ts\", context.threadTs);\n\n scope.setAttributes(attributes);\n scope.setUser({\n id: context.userId,\n username: context.userName,\n });\n scope.setContext(\"agent_run\", {\n conversationId: context.conversationId,\n channelId: context.conversationId,\n sessionKey: context.sessionKey,\n messageId: context.messageId,\n threadTs: context.threadTs,\n platform: context.platform,\n provider: context.provider,\n model: context.model,\n });\n}\n\nexport function metricAttributes(\n attributes: Record<string, string | number | boolean | undefined>,\n): Record<string, string | number | boolean> {\n return Object.fromEntries(\n Object.entries(attributes).filter((entry): entry is [string, string | number | boolean] => {\n const [, value] = entry;\n return value !== undefined;\n }),\n );\n}\n\nexport function addLifecycleBreadcrumb(\n message: string,\n data?: Record<string, string | number | boolean | undefined>,\n): void {\n Sentry.addBreadcrumb({\n category: \"agent.lifecycle\",\n message,\n level: \"info\",\n data: data ? metricAttributes(data) : undefined,\n });\n}\n\nexport function sanitizeEvent<T extends Event>(event: T, _hint?: EventHint): T | null {\n const sanitized: T = {\n ...event,\n breadcrumbs: event.breadcrumbs\n ?.map((breadcrumb) => sanitizeBreadcrumb(breadcrumb))\n .filter((breadcrumb): breadcrumb is Breadcrumb => breadcrumb !== null),\n extra: sanitizeValue(event.extra) as T[\"extra\"],\n contexts: sanitizeValue(event.contexts) as T[\"contexts\"],\n request: sanitizeRequest(event.request),\n user: undefined,\n server_name: undefined,\n };\n\n if (sanitized.message) {\n sanitized.message = sanitizeString(sanitized.message);\n }\n\n if (sanitized.logentry) {\n sanitized.logentry = {\n ...sanitized.logentry,\n message: sanitized.logentry.message ? sanitizeString(sanitized.logentry.message) : undefined,\n };\n }\n\n if (sanitized.exception?.values) {\n sanitized.exception.values = sanitized.exception.values.map((value) => ({\n ...value,\n value: value.value ? sanitizeString(value.value) : value.value,\n stacktrace: value.stacktrace\n ? {\n ...value.stacktrace,\n frames: value.stacktrace.frames?.map((frame) => ({\n ...frame,\n filename: frame.filename ? sanitizeString(frame.filename) : frame.filename,\n abs_path: frame.abs_path ? sanitizeString(frame.abs_path) : frame.abs_path,\n vars: undefined,\n })),\n }\n : value.stacktrace,\n }));\n }\n\n return sanitized;\n}\n\nexport function applySpanAttribution<T extends SentrySpanPayload>(span: T): T {\n const attributes = traceAttribution.get(span.trace_id);\n if (!attributes) return span;\n return {\n ...span,\n data: {\n ...span.data,\n ...attributes,\n },\n };\n}\n\nfunction sanitizeTransactionEvent<T extends SentryTransactionPayload>(event: T): T | null {\n const sanitized = sanitizeEvent(event);\n if (!sanitized) return null;\n\n const traceContext = sanitized.contexts?.trace;\n const traceId = traceContext?.trace_id;\n if (typeof traceId !== \"string\") return sanitized;\n const attributes = traceAttribution.get(traceId);\n if (!attributes) return sanitized;\n\n const entries = (sanitized as { entries?: Array<{ type?: string; data?: unknown }> }).entries;\n for (const entry of entries ?? []) {\n if (entry.type !== \"spans\" || !Array.isArray(entry.data)) continue;\n entry.data = entry.data.map((span: SentrySpanPayload) => applySpanAttribution(span));\n }\n\n traceAttribution.delete(traceId);\n return sanitized;\n}\n\nexport function sanitizeBreadcrumb(breadcrumb: Breadcrumb): Breadcrumb | null {\n if (breadcrumb.category === \"console\") {\n return null;\n }\n\n return {\n ...breadcrumb,\n message: breadcrumb.message ? sanitizeString(breadcrumb.message) : breadcrumb.message,\n data: sanitizeValue(breadcrumb.data) as Breadcrumb[\"data\"],\n };\n}\n\nexport function sanitizeValue(value: unknown, key?: string, depth = 0): unknown {\n if (value == null) return value;\n if (depth > MAX_DEPTH) return \"[Truncated]\";\n\n if (isSensitiveKey(key)) {\n return summarizeValue(value, key);\n }\n\n if (typeof value === \"string\") {\n return sanitizeString(value);\n }\n\n if (Array.isArray(value)) {\n return value.slice(0, 20).map((entry) => sanitizeValue(entry, key, depth + 1));\n }\n\n if (typeof value === \"object\") {\n const entries = Object.entries(value as Record<string, unknown>).map(\n ([entryKey, entryValue]) => [entryKey, sanitizeValue(entryValue, entryKey, depth + 1)],\n );\n return Object.fromEntries(entries);\n }\n\n return value;\n}\n\nfunction sanitizeRequest(request: Event[\"request\"]): Event[\"request\"] {\n if (!request) return request;\n\n return {\n ...request,\n data: request.data ? summarizeValue(request.data, \"body\") : undefined,\n headers: undefined,\n cookies: undefined,\n };\n}\n\nfunction isSensitiveKey(key?: string): boolean {\n if (!key) return false;\n return SENSITIVE_KEYS.has(key.toLowerCase());\n}\n\nfunction summarizeValue(value: unknown, key?: string): string {\n const label = key ?? \"field\";\n if (typeof value === \"string\") {\n return `[Redacted ${label}; length=${value.length}]`;\n }\n if (Array.isArray(value)) {\n return `[Redacted ${label}; items=${value.length}]`;\n }\n if (value && typeof value === \"object\") {\n return `[Redacted ${label}; keys=${Object.keys(value as Record<string, unknown>).length}]`;\n }\n return `[Redacted ${label}]`;\n}\n\nfunction sanitizeString(value: string): string {\n let sanitized = value.replace(new RegExp(ABSOLUTE_PATH_PATTERN, \"g\"), REDACTED_PATH);\n for (const pattern of TOKEN_PATTERNS) {\n sanitized = sanitized.replace(new RegExp(pattern, \"g\"), REDACTED);\n }\n if (sanitized.length > MAX_STRING_LENGTH) {\n return `${sanitized.slice(0, MAX_STRING_LENGTH)}… [truncated ${sanitized.length - MAX_STRING_LENGTH} chars]`;\n }\n return sanitized;\n}\n"]}
1
+ {"version":3,"file":"sentry.js","sourceRoot":"","sources":["../../src/observability/sentry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Breadcrumb, ErrorEvent, Event, EventHint, Scope } from \"@sentry/node\";\nimport * as Sentry from \"@sentry/node\";\n\nconst REDACTED = \"[REDACTED]\";\nconst REDACTED_PATH = \"[REDACTED_PATH]\";\nconst MAX_STRING_LENGTH = 256;\nconst MAX_DEPTH = 4;\nconst TRACE_ATTRIBUTION_TTL_MS = 5 * 60 * 1000;\n\nconst SENSITIVE_KEYS = new Set([\n \"accesstoken\",\n \"apikey\",\n \"args\",\n \"attachment\",\n \"attachments\",\n \"authorization\",\n \"body\",\n \"clientsecret\",\n \"code\",\n \"content\",\n \"contents\",\n \"cookie\",\n \"cookies\",\n \"credential\",\n \"filepath\",\n \"headers\",\n \"image\",\n \"imageattachments\",\n \"images\",\n \"localpath\",\n \"messages\",\n \"newusermessage\",\n \"password\",\n \"path\",\n \"paths\",\n \"prompt\",\n \"refreshtoken\",\n \"response\",\n \"result\",\n \"secret\",\n \"systemprompt\",\n \"text\",\n \"thinking\",\n \"token\",\n \"url\",\n \"uri\",\n \"workspacepath\",\n]);\n\nconst ABSOLUTE_PATH_PATTERN =\n /(?:\\/Users\\/[^\\s\"'`]+|\\/workspace\\/[^\\s\"'`]+|\\/tmp\\/[^\\s\"'`]+|\\/var\\/folders\\/[^\\s\"'`]+|[A-Za-z]:\\\\[^\\s\"'`]+)/;\nconst TOKEN_PATTERNS = [\n /\\bsk-[A-Za-z0-9_-]{12,}\\b/,\n /\\bxox[a-z]-[A-Za-z0-9-]{10,}\\b/,\n /\\bAIza[0-9A-Za-z_-]{20,}\\b/,\n /\\bgh[pousr]_[A-Za-z0-9]{20,}\\b/,\n];\n\nexport type {\n ReportUserFacingErrorOptions,\n SentryAttributionAttributes,\n SentryRunScopeContext,\n SentrySpanPayload,\n SentryTransactionPayload,\n} from \"./types.js\";\nimport type {\n ReportUserFacingErrorOptions,\n SentryAttributionAttributes,\n SentryRunScopeContext,\n SentrySpanPayload,\n SentryTransactionPayload,\n} from \"./types.js\";\n\ntype TraceAttributionEntry = {\n attributes: SentryAttributionAttributes;\n expiresAt: number;\n};\n\nconst traceAttribution = new Map<string, TraceAttributionEntry>();\n\nexport function createSentryInitOptions(dsn?: string) {\n return {\n dsn,\n environment: process.env.SENTRY_ENVIRONMENT ?? \"production\",\n enabled: Boolean(dsn) && process.env.SENTRY_ENABLED !== \"false\",\n sendDefaultPii: false,\n tracesSampleRate: 1.0,\n includeLocalVariables: false,\n enableLogs: true,\n beforeSend(event: ErrorEvent, hint: EventHint): ErrorEvent | null {\n return sanitizeEvent(event, hint);\n },\n beforeSendSpan(span: SentrySpanPayload): SentrySpanPayload {\n return applySpanAttribution(span);\n },\n beforeSendTransaction(event: SentryTransactionPayload): SentryTransactionPayload | null {\n return sanitizeTransactionEvent(event);\n },\n beforeBreadcrumb(breadcrumb: Breadcrumb): Breadcrumb | null {\n return sanitizeBreadcrumb(breadcrumb);\n },\n };\n}\n\nexport function reportUserFacingError(\n error: unknown,\n options: ReportUserFacingErrorOptions,\n): string | undefined {\n if (options.expected) return undefined;\n\n const exception = error instanceof Error ? error : new Error(String(error));\n return Sentry.withScope((scope) => {\n scope.setLevel(options.severity ?? \"error\");\n scope.setTag(\"user_facing\", \"true\");\n scope.setTag(\"expected\", \"false\");\n scope.setTag(\"error_domain\", options.domain);\n scope.setTag(\"error_surface\", options.surface);\n scope.setTag(\"operation\", options.operation);\n setOptionalTag(scope, \"platform\", options.platform);\n setOptionalTag(scope, \"provider\", options.provider);\n setOptionalTag(scope, \"model\", options.model);\n setOptionalTag(scope, \"tool\", options.toolName);\n setOptionalTag(scope, \"stop_reason\", options.stopReason);\n for (const [key, value] of Object.entries(options.tags ?? {})) {\n if (value !== undefined) scope.setTag(key, String(value));\n }\n if (options.fingerprint) scope.setFingerprint(options.fingerprint);\n scope.setContext(\"user_facing_error\", {\n domain: options.domain,\n surface: options.surface,\n operation: options.operation,\n severity: options.severity ?? \"error\",\n platform: options.platform,\n provider: options.provider,\n model: options.model,\n toolName: options.toolName,\n stopReason: options.stopReason,\n ...(sanitizeValue(options.context ?? {}) as Record<string, unknown>),\n });\n return Sentry.captureException(exception);\n });\n}\n\nfunction setOptionalTag(scope: Scope, key: string, value: string | undefined): void {\n if (value !== undefined) scope.setTag(key, value);\n}\n\nexport function createRunAttributionAttributes(\n context: SentryRunScopeContext,\n): SentryAttributionAttributes {\n return metricAttributes({\n conversation_id: context.conversationId,\n channel_id: context.conversationId,\n session_key: context.sessionKey,\n message_id: context.messageId,\n platform: context.platform,\n user_id: context.userId,\n thread_ts: context.threadTs,\n provider: context.provider,\n model: context.model,\n });\n}\n\nexport function registerTraceAttribution(\n span: { setAttributes(attributes: SentryAttributionAttributes): unknown },\n attributes: SentryAttributionAttributes,\n): void {\n span.setAttributes(attributes);\n const traceId = Sentry.spanToJSON(span as Parameters<typeof Sentry.spanToJSON>[0]).trace_id;\n if (!traceId) return;\n\n const now = Date.now();\n pruneExpiredTraceAttributions(now);\n traceAttribution.set(traceId, {\n attributes: { ...traceAttribution.get(traceId)?.attributes, ...attributes },\n expiresAt: now + TRACE_ATTRIBUTION_TTL_MS,\n });\n}\n\nexport function updateActiveSpanAttribution(attributes: SentryAttributionAttributes): void {\n const span = Sentry.getActiveSpan();\n if (!span) return;\n registerTraceAttribution(span, attributes);\n}\n\nexport function applyRunScope(scope: Scope, context: SentryRunScopeContext): void {\n const attributes = createRunAttributionAttributes(context);\n\n for (const [key, value] of Object.entries(attributes)) {\n scope.setTag(key, value);\n }\n scope.setAttributes(attributes);\n scope.setUser({\n id: context.userId,\n username: context.userName,\n });\n scope.setContext(\"agent_run\", {\n conversationId: context.conversationId,\n channelId: context.conversationId,\n sessionKey: context.sessionKey,\n messageId: context.messageId,\n threadTs: context.threadTs,\n platform: context.platform,\n provider: context.provider,\n model: context.model,\n });\n}\n\nexport function metricAttributes(\n attributes: Record<string, string | number | boolean | undefined>,\n): Record<string, string | number | boolean> {\n return Object.fromEntries(\n Object.entries(attributes).filter((entry): entry is [string, string | number | boolean] => {\n const [, value] = entry;\n return value !== undefined;\n }),\n );\n}\n\nexport function addLifecycleBreadcrumb(\n message: string,\n data?: Record<string, string | number | boolean | undefined>,\n): void {\n Sentry.addBreadcrumb({\n category: \"agent.lifecycle\",\n message,\n level: \"info\",\n data: data ? metricAttributes(data) : undefined,\n });\n}\n\nexport function sanitizeEvent<T extends Event>(event: T, _hint?: EventHint): T | null {\n const sanitized: T = {\n ...event,\n breadcrumbs: event.breadcrumbs\n ?.map((breadcrumb) => sanitizeBreadcrumb(breadcrumb))\n .filter((breadcrumb): breadcrumb is Breadcrumb => breadcrumb !== null),\n extra: sanitizeValue(event.extra) as T[\"extra\"],\n contexts: sanitizeValue(event.contexts) as T[\"contexts\"],\n request: sanitizeRequest(event.request),\n user: undefined,\n server_name: undefined,\n };\n\n if (sanitized.message) {\n sanitized.message = sanitizeString(sanitized.message);\n }\n\n if (sanitized.logentry) {\n sanitized.logentry = {\n ...sanitized.logentry,\n message: sanitized.logentry.message ? sanitizeString(sanitized.logentry.message) : undefined,\n };\n }\n\n if (sanitized.exception?.values) {\n sanitized.exception.values = sanitized.exception.values.map((value) => ({\n ...value,\n value: value.value ? sanitizeString(value.value) : value.value,\n stacktrace: value.stacktrace\n ? {\n ...value.stacktrace,\n frames: value.stacktrace.frames?.map((frame) => ({\n ...frame,\n filename: frame.filename ? sanitizeString(frame.filename) : frame.filename,\n abs_path: frame.abs_path ? sanitizeString(frame.abs_path) : frame.abs_path,\n vars: undefined,\n })),\n }\n : value.stacktrace,\n }));\n }\n\n return sanitized;\n}\n\nexport function applySpanAttribution<T extends SentrySpanPayload>(span: T): T {\n const attributes = getTraceAttribution(span.trace_id);\n if (!attributes) return span;\n return {\n ...span,\n data: {\n ...span.data,\n ...attributes,\n },\n };\n}\n\nfunction sanitizeTransactionEvent<T extends SentryTransactionPayload>(event: T): T | null {\n const sanitized = sanitizeEvent(event);\n if (!sanitized) return null;\n\n const traceContext = sanitized.contexts?.trace;\n const traceId = traceContext?.trace_id;\n if (typeof traceId !== \"string\") return sanitized;\n const attributes = getTraceAttribution(traceId);\n if (!attributes) return sanitized;\n\n const entries = (sanitized as { entries?: Array<{ type?: string; data?: unknown }> }).entries;\n for (const entry of entries ?? []) {\n if (entry.type !== \"spans\" || !Array.isArray(entry.data)) continue;\n entry.data = entry.data.map((span: SentrySpanPayload) => applySpanAttribution(span));\n }\n\n traceAttribution.delete(traceId);\n return sanitized;\n}\n\nexport function sanitizeBreadcrumb(breadcrumb: Breadcrumb): Breadcrumb | null {\n if (breadcrumb.category === \"console\") {\n return null;\n }\n\n return {\n ...breadcrumb,\n message: breadcrumb.message ? sanitizeString(breadcrumb.message) : breadcrumb.message,\n data: sanitizeValue(breadcrumb.data) as Breadcrumb[\"data\"],\n };\n}\n\nexport function sanitizeValue(value: unknown, key?: string, depth = 0): unknown {\n if (value == null) return value;\n if (depth > MAX_DEPTH) return \"[Truncated]\";\n\n if (isSensitiveKey(key)) {\n return summarizeValue(value, key);\n }\n\n if (typeof value === \"string\") {\n return sanitizeString(value);\n }\n\n if (Array.isArray(value)) {\n return value.slice(0, 20).map((entry) => sanitizeValue(entry, key, depth + 1));\n }\n\n if (typeof value === \"object\") {\n const entries = Object.entries(value as Record<string, unknown>).map(\n ([entryKey, entryValue]) => [entryKey, sanitizeValue(entryValue, entryKey, depth + 1)],\n );\n return Object.fromEntries(entries);\n }\n\n return value;\n}\n\nfunction sanitizeRequest(request: Event[\"request\"]): Event[\"request\"] {\n if (!request) return request;\n\n return {\n ...request,\n data: request.data ? summarizeValue(request.data, \"body\") : undefined,\n headers: undefined,\n cookies: undefined,\n };\n}\n\nfunction getTraceAttribution(traceId: string): SentryAttributionAttributes | undefined {\n const entry = traceAttribution.get(traceId);\n if (!entry) return undefined;\n if (entry.expiresAt > Date.now()) return entry.attributes;\n traceAttribution.delete(traceId);\n return undefined;\n}\n\nfunction pruneExpiredTraceAttributions(now: number): void {\n for (const [traceId, entry] of traceAttribution) {\n if (entry.expiresAt <= now) traceAttribution.delete(traceId);\n }\n}\n\nfunction isSensitiveKey(key?: string): boolean {\n if (!key) return false;\n return SENSITIVE_KEYS.has(key.toLowerCase().replace(/[^a-z0-9]/g, \"\"));\n}\n\nfunction summarizeValue(value: unknown, key?: string): string {\n const label = key ?? \"field\";\n if (typeof value === \"string\") {\n return `[Redacted ${label}; length=${value.length}]`;\n }\n if (Array.isArray(value)) {\n return `[Redacted ${label}; items=${value.length}]`;\n }\n if (value && typeof value === \"object\") {\n return `[Redacted ${label}; keys=${Object.keys(value as Record<string, unknown>).length}]`;\n }\n return `[Redacted ${label}]`;\n}\n\nfunction sanitizeString(value: string): string {\n let sanitized = value.replace(new RegExp(ABSOLUTE_PATH_PATTERN, \"g\"), REDACTED_PATH);\n for (const pattern of TOKEN_PATTERNS) {\n sanitized = sanitized.replace(new RegExp(pattern, \"g\"), REDACTED);\n }\n if (sanitized.length > MAX_STRING_LENGTH) {\n return `${sanitized.slice(0, MAX_STRING_LENGTH)}… [truncated ${sanitized.length - MAX_STRING_LENGTH} chars]`;\n }\n return sanitized;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/observability/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,KAAK,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AACjD,KAAK,wBAAwB,GACzB,eAAe,GACf,KAAK,CAAC,IAAI,GAAG,SAAS,GAAG,MAAM,CAAC,GAChC,KAAK,CAAC,IAAI,GAAG,SAAS,GAAG,MAAM,CAAC,GAChC,KAAK,CAAC,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC;AAEtC,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,2BAA2B,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAE1E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,wBAAyB,SAAQ,KAAK;IACrD,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACpD;AAED,KAAK,qBAAqB,GACtB,KAAK,GACL,eAAe,GACf,OAAO,GACP,SAAS,GACT,OAAO,GACP,QAAQ,GACR,cAAc,CAAC;AAEnB,KAAK,uBAAuB,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAE7D,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,qBAAqB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,uBAAuB,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAAC,CAAC;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC","sourcesContent":["import type { Event } from \"@sentry/node\";\n\ntype SentryPrimitive = string | number | boolean;\ntype SentrySpanAttributeValue =\n | SentryPrimitive\n | Array<null | undefined | string>\n | Array<null | undefined | number>\n | Array<null | undefined | boolean>;\n\nexport interface SentryRunScopeContext {\n conversationId: string;\n sessionKey: string;\n messageId: string;\n platform: string;\n userId: string;\n userName?: string;\n threadTs?: string;\n provider?: string;\n model?: string;\n}\n\nexport type SentryAttributionAttributes = Record<string, SentryPrimitive>;\n\nexport interface SentrySpanPayload {\n trace_id: string;\n span_id: string;\n start_timestamp: number;\n data: Record<string, SentrySpanAttributeValue | undefined>;\n}\n\nexport interface SentryTransactionPayload extends Event {\n type: \"transaction\";\n entries?: Array<{ type?: string; data?: unknown }>;\n}\n\ntype UserFacingErrorDomain =\n | \"llm\"\n | \"chat_platform\"\n | \"mikan\"\n | \"sandbox\"\n | \"login\"\n | \"events\"\n | \"session_view\";\n\ntype UserFacingErrorSeverity = \"warning\" | \"error\" | \"fatal\";\n\nexport interface ReportUserFacingErrorOptions {\n domain: UserFacingErrorDomain;\n surface: string;\n operation: string;\n severity?: UserFacingErrorSeverity;\n platform?: string;\n provider?: string;\n model?: string;\n toolName?: string;\n stopReason?: string;\n expected?: boolean;\n fingerprint?: string[];\n tags?: Record<string, SentryPrimitive | undefined>;\n context?: Record<string, unknown>;\n}\n"]}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/observability/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,KAAK,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AACjD,KAAK,wBAAwB,GACzB,eAAe,GACf,KAAK,CAAC,IAAI,GAAG,SAAS,GAAG,MAAM,CAAC,GAChC,KAAK,CAAC,IAAI,GAAG,SAAS,GAAG,MAAM,CAAC,GAChC,KAAK,CAAC,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC;AAEtC,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,2BAA2B,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAE1E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,wBAAyB,SAAQ,KAAK;IACrD,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACpD;AAED,KAAK,qBAAqB,GACtB,KAAK,GACL,eAAe,GACf,OAAO,GACP,SAAS,GACT,OAAO,GACP,QAAQ,GACR,cAAc,CAAC;AAEnB,KAAK,uBAAuB,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAE7D,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,qBAAqB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,uBAAuB,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAAC,CAAC;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC"}
@@ -1,6 +1,6 @@
1
- import type { Bot, PlatformInfo } from "./adapter.js";
1
+ import type { MessagingBot, MessagingInfo } from "./adapter.js";
2
2
  export declare const PRODUCT_NAME = "mikan";
3
- type PlatformSource = Bot | PlatformInfo | string;
3
+ type PlatformSource = MessagingBot | MessagingInfo | string;
4
4
  export declare function formatNothingRunning(source: PlatformSource): string;
5
5
  export declare function formatStopping(source: PlatformSource): string;
6
6
  export declare function formatStopped(source: PlatformSource): string;
@@ -1 +1 @@
1
- {"version":3,"file":"platform-messages.d.ts","sourceRoot":"","sources":["../src/platform-messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEtD,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,KAAK,cAAc,GAAG,GAAG,GAAG,YAAY,GAAG,MAAM,CAAC;AAoBlD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAEnE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAE7D;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAE5D;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,EACtB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,QAAQ,CAAA;CAAE,GAC7B,MAAM,CAMR;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAErF","sourcesContent":["import type { Bot, PlatformInfo } from \"./adapter.js\";\n\nexport const PRODUCT_NAME = \"mikan\";\n\ntype PlatformSource = Bot | PlatformInfo | string;\n\nfunction resolvePlatformName(source: PlatformSource): string {\n if (typeof source === \"string\") return source;\n if (\"getPlatformInfo\" in source) return source.getPlatformInfo().name;\n return source.name;\n}\n\nfunction supportsHtmlFormatting(platformName: string): boolean {\n return platformName === \"telegram\";\n}\n\nfunction formatItalic(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? text : `_${text}_`;\n}\n\nfunction formatCode(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? `<code>${text}</code>` : `\\`${text}\\``;\n}\n\nexport function formatNothingRunning(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Nothing running.\");\n}\n\nexport function formatStopping(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopping…\");\n}\n\nexport function formatStopped(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopped.\");\n}\n\nexport function formatAlreadyWorking(\n source: PlatformSource,\n stopCommand: string,\n options?: { scope?: \"thread\" },\n): string {\n const platformName = resolvePlatformName(source);\n const command = formatCode(platformName, stopCommand);\n const prefix =\n options?.scope === \"thread\" ? \"Already working in this thread.\" : \"Already working.\";\n return formatItalic(platformName, `${prefix} Send ${command} to cancel.`);\n}\n\nexport function formatForceStopped(source: PlatformSource, actorLabel: string): string {\n return formatItalic(resolvePlatformName(source), `Force stopped by ${actorLabel}.`);\n}\n"]}
1
+ {"version":3,"file":"platform-messages.d.ts","sourceRoot":"","sources":["../src/platform-messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEhE,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,KAAK,cAAc,GAAG,YAAY,GAAG,aAAa,GAAG,MAAM,CAAC;AAoB5D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAEnE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAE7D;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAE5D;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,EACtB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,QAAQ,CAAA;CAAE,GAC7B,MAAM,CAMR;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAErF"}
@@ -2,8 +2,8 @@ export const PRODUCT_NAME = "mikan";
2
2
  function resolvePlatformName(source) {
3
3
  if (typeof source === "string")
4
4
  return source;
5
- if ("getPlatformInfo" in source)
6
- return source.getPlatformInfo().name;
5
+ if ("getMessagingInfo" in source)
6
+ return source.getMessagingInfo().name;
7
7
  return source.name;
8
8
  }
9
9
  function supportsHtmlFormatting(platformName) {
@@ -1 +1 @@
1
- {"version":3,"file":"platform-messages.js","sourceRoot":"","sources":["../src/platform-messages.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AAIpC,SAAS,mBAAmB,CAAC,MAAsB;IACjD,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC9C,IAAI,iBAAiB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC;IACtE,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,SAAS,sBAAsB,CAAC,YAAoB;IAClD,OAAO,YAAY,KAAK,UAAU,CAAC;AACrC,CAAC;AAED,SAAS,YAAY,CAAC,YAAoB,EAAE,IAAY;IACtD,OAAO,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;AACnE,CAAC;AAED,SAAS,UAAU,CAAC,YAAoB,EAAE,IAAY;IACpD,OAAO,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC;AACvF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAsB;IACzD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAsB;IACnD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAsB;IAClD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,MAAsB,EACtB,WAAmB,EACnB,OAA8B;IAE9B,MAAM,YAAY,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACtD,MAAM,MAAM,GACV,OAAO,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,kBAAkB,CAAC;IACvF,OAAO,YAAY,CAAC,YAAY,EAAE,GAAG,MAAM,SAAS,OAAO,aAAa,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAsB,EAAE,UAAkB;IAC3E,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,oBAAoB,UAAU,GAAG,CAAC,CAAC;AACtF,CAAC","sourcesContent":["import type { Bot, PlatformInfo } from \"./adapter.js\";\n\nexport const PRODUCT_NAME = \"mikan\";\n\ntype PlatformSource = Bot | PlatformInfo | string;\n\nfunction resolvePlatformName(source: PlatformSource): string {\n if (typeof source === \"string\") return source;\n if (\"getPlatformInfo\" in source) return source.getPlatformInfo().name;\n return source.name;\n}\n\nfunction supportsHtmlFormatting(platformName: string): boolean {\n return platformName === \"telegram\";\n}\n\nfunction formatItalic(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? text : `_${text}_`;\n}\n\nfunction formatCode(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? `<code>${text}</code>` : `\\`${text}\\``;\n}\n\nexport function formatNothingRunning(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Nothing running.\");\n}\n\nexport function formatStopping(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopping…\");\n}\n\nexport function formatStopped(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopped.\");\n}\n\nexport function formatAlreadyWorking(\n source: PlatformSource,\n stopCommand: string,\n options?: { scope?: \"thread\" },\n): string {\n const platformName = resolvePlatformName(source);\n const command = formatCode(platformName, stopCommand);\n const prefix =\n options?.scope === \"thread\" ? \"Already working in this thread.\" : \"Already working.\";\n return formatItalic(platformName, `${prefix} Send ${command} to cancel.`);\n}\n\nexport function formatForceStopped(source: PlatformSource, actorLabel: string): string {\n return formatItalic(resolvePlatformName(source), `Force stopped by ${actorLabel}.`);\n}\n"]}
1
+ {"version":3,"file":"platform-messages.js","sourceRoot":"","sources":["../src/platform-messages.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AAIpC,SAAS,mBAAmB,CAAC,MAAsB;IACjD,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC9C,IAAI,kBAAkB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC;IACxE,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,SAAS,sBAAsB,CAAC,YAAoB;IAClD,OAAO,YAAY,KAAK,UAAU,CAAC;AACrC,CAAC;AAED,SAAS,YAAY,CAAC,YAAoB,EAAE,IAAY;IACtD,OAAO,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;AACnE,CAAC;AAED,SAAS,UAAU,CAAC,YAAoB,EAAE,IAAY;IACpD,OAAO,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC;AACvF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAsB;IACzD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAsB;IACnD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAsB;IAClD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,MAAsB,EACtB,WAAmB,EACnB,OAA8B;IAE9B,MAAM,YAAY,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACtD,MAAM,MAAM,GACV,OAAO,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,kBAAkB,CAAC;IACvF,OAAO,YAAY,CAAC,YAAY,EAAE,GAAG,MAAM,SAAS,OAAO,aAAa,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAsB,EAAE,UAAkB;IAC3E,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,oBAAoB,UAAU,GAAG,CAAC,CAAC;AACtF,CAAC","sourcesContent":["import type { MessagingBot, MessagingInfo } from \"./adapter.js\";\n\nexport const PRODUCT_NAME = \"mikan\";\n\ntype PlatformSource = MessagingBot | MessagingInfo | string;\n\nfunction resolvePlatformName(source: PlatformSource): string {\n if (typeof source === \"string\") return source;\n if (\"getMessagingInfo\" in source) return source.getMessagingInfo().name;\n return source.name;\n}\n\nfunction supportsHtmlFormatting(platformName: string): boolean {\n return platformName === \"telegram\";\n}\n\nfunction formatItalic(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? text : `_${text}_`;\n}\n\nfunction formatCode(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? `<code>${text}</code>` : `\\`${text}\\``;\n}\n\nexport function formatNothingRunning(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Nothing running.\");\n}\n\nexport function formatStopping(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopping…\");\n}\n\nexport function formatStopped(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopped.\");\n}\n\nexport function formatAlreadyWorking(\n source: PlatformSource,\n stopCommand: string,\n options?: { scope?: \"thread\" },\n): string {\n const platformName = resolvePlatformName(source);\n const command = formatCode(platformName, stopCommand);\n const prefix =\n options?.scope === \"thread\" ? \"Already working in this thread.\" : \"Already working.\";\n return formatItalic(platformName, `${prefix} Send ${command} to cancel.`);\n}\n\nexport function formatForceStopped(source: PlatformSource, actorLabel: string): string {\n return formatItalic(resolvePlatformName(source), `Force stopped by ${actorLabel}.`);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"portal-shell.d.ts","sourceRoot":"","sources":["../src/portal-shell.ts"],"names":[],"mappings":"AAcA,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAiFrD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CA8BrE","sourcesContent":["import { escapeHtml } from \"./utils/html.js\";\nimport { PRODUCT_NAME } from \"./platform-messages.js\";\n\n// ── Shared portal shell ────────────────────────────────────────────────────────\n//\n// Three portals (admin / session / vault aka login) share the same chrome:\n// - Fixed left rail with three round icon buttons (admin, session, vault)\n// - Compact topbar (product wordmark + identity + optional conversation switcher)\n// - Main content area\n//\n// Each portal renders its own page-head + body inside <main class=\"shell\">.\n// Sidebar buttons whose target token isn't available are rendered as anchors\n// only when href is provided; otherwise they are buttons in a disabled state.\n\nexport type { PortalShellOptions } from \"./types.js\";\nimport type { PortalShellOptions } from \"./types.js\";\n\ntype PortalView = \"admin\" | \"session\" | \"vault\";\n\nconst NAV_ICONS: Record<PortalView, { label: string; svg: string }> = {\n admin: {\n label: \"Admin\",\n svg: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"3\"/>\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h.01a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82v.01a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\"/>\n </svg>`,\n },\n session: {\n label: \"Session\",\n svg: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z\"/>\n </svg>`,\n },\n vault: {\n label: \"Vault\",\n svg: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"/>\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\"/>\n </svg>`,\n },\n};\n\nfunction renderNav(activeView: PortalView, navLinks: Partial<Record<PortalView, string>>): string {\n const views: PortalView[] = [\"admin\", \"session\", \"vault\"];\n const buttons = views.map((view) => {\n const meta = NAV_ICONS[view];\n const isActive = view === activeView;\n const href = navLinks[view];\n const baseClass = `view-nav-btn${isActive ? \" active\" : \"\"}${!href && !isActive ? \" disabled\" : \"\"}`;\n const attrs = `data-view=\"${view}\" aria-label=\"${escapeHtml(meta.label)}\" data-tooltip=\"${escapeHtml(meta.label)}\"`;\n if (href && !isActive) {\n return `<a class=\"${baseClass}\" href=\"${escapeHtml(href)}\" ${attrs}>${meta.svg}</a>`;\n }\n if (isActive) {\n return `<span class=\"${baseClass}\" aria-current=\"page\" ${attrs}>${meta.svg}</span>`;\n }\n return `<span class=\"${baseClass}\" aria-disabled=\"true\" ${attrs} data-tooltip=\"${escapeHtml(meta.label)} (no token)\">${meta.svg}</span>`;\n });\n return `<nav class=\"floating-view-nav\" aria-label=\"Primary views\">${buttons.join(\"\")}</nav>`;\n}\n\nfunction renderTopbar(options: PortalShellOptions): string {\n const identity = options.identity\n ? `<span class=\"topbar-user\">${escapeHtml(options.identity.primary)}${options.identity.secondary ? ` · ${escapeHtml(options.identity.secondary)}` : \"\"}</span>`\n : \"\";\n\n let switcher = \"\";\n if (options.conversationSwitcher) {\n const { currentId, options: convOptions } = options.conversationSwitcher;\n if (convOptions && convOptions.length > 0) {\n const opts = convOptions\n .map((c) => {\n const label = `${c.label}${c.running ? \" (running)\" : \"\"}`;\n const selected = c.id === currentId ? \" selected\" : \"\";\n return `<option value=\"${escapeHtml(c.id)}\"${selected}>${escapeHtml(label)}</option>`;\n })\n .join(\"\");\n switcher = `<select id=\"conv-switcher\" class=\"conv-inline-select\" aria-label=\"Switch conversation\">${opts}</select>`;\n } else {\n switcher = `<select id=\"conv-switcher\" class=\"conv-inline-select\" aria-label=\"Switch conversation\"><option>${escapeHtml(currentId)}</option></select>`;\n }\n }\n\n return `<header class=\"topbar\">\n <div class=\"topbar-brand\">\n <span class=\"topbar-wordmark\">${PRODUCT_NAME}</span>\n <span class=\"topbar-sep\">·</span>\n <span class=\"topbar-title\">${escapeHtml(options.pageTitle)}</span>\n </div>\n <div class=\"topbar-meta\">\n ${identity}\n ${switcher}\n </div>\n </header>`;\n}\n\nexport function renderPortalShell(options: PortalShellOptions): string {\n const bodyAttrs = Object.entries(options.bodyAttributes ?? {})\n .map(([key, value]) => `${escapeHtml(key)}=\"${escapeHtml(value)}\"`)\n .join(\" \");\n const titleText = `${options.pageTitle} — ${PRODUCT_NAME}`;\n const nav = renderNav(options.activeView, options.navLinks ?? {});\n const topbar = renderTopbar(options);\n const extraStyles = options.extraStyles ? `<style>${options.extraStyles}</style>` : \"\";\n const inlineScript = options.inlineScript ? `<script>${options.inlineScript}</script>` : \"\";\n const extraHead = options.extraHead ?? \"\";\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>${escapeHtml(titleText)}</title>\n <style>${portalShellStyles}</style>\n ${extraStyles}\n ${extraHead}\n</head>\n<body${bodyAttrs ? ` ${bodyAttrs}` : \"\"}>\n ${nav}\n <main class=\"shell\">\n ${topbar}\n ${options.body}\n </main>\n ${inlineScript}\n</body>\n</html>`;\n}\n\n// ── Shared stylesheet ──────────────────────────────────────────────────────────\n\nconst portalShellStyles = `\n @import url('https://fonts.googleapis.com/css2?family=Lora:wght@400;600&family=DM+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap');\n\n :root {\n --bg: #f0ece3;\n --surface: #ffffff;\n --border: rgba(0, 0, 0, 0.08);\n --text: #18181b;\n --muted: #71717a;\n --subtle: #a1a1aa;\n --accent: #d97706;\n\n --ok-bg: #f0fdf4;\n --ok-text: #15803d;\n --ok-border: rgba(21, 128, 61, 0.16);\n --warn-bg: #fffbeb;\n --warn-text: #92400e;\n --err-bg: #fef2f2;\n --err-text: #b91c1c;\n --err-border: rgba(185, 28, 28, 0.14);\n }\n\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n\n body {\n min-height: 100vh;\n padding: 28px 24px 60px;\n display: flex;\n flex-direction: column;\n align-items: center;\n background-color: var(--bg);\n background-image: radial-gradient(ellipse 80% 40% at 50% -10%, rgba(255,255,255,0.65) 0%, transparent 70%);\n color: var(--text);\n font-family: 'DM Sans', 'Segoe UI', system-ui, sans-serif;\n font-size: 15px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n }\n\n .shell {\n width: 100%;\n max-width: 960px;\n margin-left: 72px;\n display: flex;\n flex-direction: column;\n gap: 18px;\n }\n\n /* ── Topbar ─────────────────────────────────────────────────────────── */\n\n .topbar {\n display: flex; align-items: center; justify-content: space-between;\n gap: 16px; padding: 10px 18px;\n border: 1px solid var(--border); border-radius: 14px;\n background: rgba(255,255,255,0.7); backdrop-filter: blur(8px);\n }\n .topbar-brand { display: flex; align-items: baseline; gap: 8px; min-width: 0; }\n .topbar-wordmark {\n font-family: 'Lora', Georgia, serif; font-size: 1.05rem; font-weight: 600;\n color: var(--text); letter-spacing: -0.01em;\n }\n .topbar-sep { color: var(--subtle); font-size: 0.9rem; }\n .topbar-title { font-size: 0.86rem; color: var(--muted); font-weight: 500; }\n .topbar-meta {\n display: flex; align-items: center; gap: 12px; min-width: 0; flex-wrap: wrap;\n justify-content: flex-end;\n }\n .topbar-user {\n font-size: 0.8rem; color: var(--muted);\n padding: 4px 10px; border-radius: 999px; background: rgba(0,0,0,0.04);\n white-space: nowrap;\n }\n .conv-inline-select {\n max-width: min(360px, 100%);\n padding: 6px 10px; border: 1px solid var(--border); border-radius: 10px;\n background: #fff; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 0.76rem;\n color: var(--text); cursor: pointer;\n transition: border-color 120ms;\n }\n .conv-inline-select:hover { border-color: rgba(0,0,0,0.18); }\n .conv-inline-select:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }\n\n /* ── Floating icon nav ──────────────────────────────────────────────── */\n\n .floating-view-nav {\n position: fixed;\n left: 20px;\n top: 50%;\n transform: translateY(-50%);\n z-index: 20;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 6px;\n border: 1px solid var(--border);\n border-radius: 999px;\n background: rgba(255,255,255,0.88);\n box-shadow: 0 10px 32px rgba(0,0,0,0.10), 0 2px 6px rgba(0,0,0,0.04);\n backdrop-filter: blur(14px);\n }\n .view-nav-btn {\n position: relative;\n display: flex; align-items: center; justify-content: center;\n width: 40px; height: 40px;\n border: none; border-radius: 999px; background: transparent;\n color: var(--muted); cursor: pointer;\n text-decoration: none;\n transition: background 160ms, color 160ms, transform 160ms;\n }\n .view-nav-btn:hover { background: rgba(0,0,0,0.05); color: var(--text); }\n .view-nav-btn:active { transform: scale(0.94); }\n .view-nav-btn.active {\n background: var(--text); color: #fff;\n box-shadow: 0 2px 8px rgba(0,0,0,0.18);\n cursor: default;\n }\n .view-nav-btn.disabled {\n opacity: 0.4; cursor: not-allowed;\n }\n .view-nav-btn.disabled:hover { background: transparent; color: var(--muted); }\n .view-nav-btn svg { display: block; }\n\n /* Tooltip */\n .view-nav-btn::after {\n content: attr(data-tooltip);\n position: absolute;\n left: calc(100% + 12px);\n top: 50%;\n transform: translateY(-50%) translateX(-4px);\n padding: 5px 10px;\n border-radius: 8px;\n background: var(--text);\n color: #fff;\n font: 500 0.76rem/1 'DM Sans', sans-serif;\n white-space: nowrap;\n opacity: 0;\n pointer-events: none;\n transition: opacity 140ms, transform 140ms;\n box-shadow: 0 4px 12px rgba(0,0,0,0.16);\n }\n .view-nav-btn::before {\n content: '';\n position: absolute;\n left: calc(100% + 6px);\n top: 50%;\n transform: translateY(-50%);\n border: 5px solid transparent;\n border-right-color: var(--text);\n opacity: 0;\n pointer-events: none;\n transition: opacity 140ms;\n }\n .view-nav-btn:hover::after,\n .view-nav-btn:focus-visible::after {\n opacity: 1;\n transform: translateY(-50%) translateX(0);\n }\n .view-nav-btn:hover::before,\n .view-nav-btn:focus-visible::before {\n opacity: 1;\n }\n\n /* ── Generic page-head ───────────────────────────────────────────────── */\n\n .page-head {\n display: flex; justify-content: space-between; align-items: flex-start; gap: 14px;\n padding: 2px 4px;\n }\n .page-title {\n font-family: 'Lora', Georgia, serif;\n font-size: clamp(1.35rem, 2.4vw, 1.6rem);\n font-weight: 600; line-height: 1.2; letter-spacing: -0.01em;\n }\n .page-desc { color: var(--muted); font-size: 0.9rem; margin-top: 4px; }\n .eyebrow {\n color: var(--subtle); font-size: 0.72rem; font-weight: 600;\n letter-spacing: 0.12em; text-transform: uppercase; margin-bottom: 6px;\n }\n\n /* ── Cards ──────────────────────────────────────────────────────────── */\n\n .card {\n padding: 24px 28px;\n border: 1px solid var(--border);\n border-radius: 20px;\n background: var(--surface);\n box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 4px 16px rgba(0,0,0,0.06);\n }\n .card-title {\n font-family: 'Lora', Georgia, serif;\n font-size: clamp(1.1rem, 2vw, 1.3rem);\n font-weight: 600; line-height: 1.25; letter-spacing: -0.01em;\n margin-bottom: 10px;\n }\n .card-subtitle { font-size: 1rem; font-weight: 650; margin-bottom: 10px; line-height: 1.3; }\n\n code {\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n font-size: 0.82em; padding: 0.14em 0.36em;\n border-radius: 6px; background: rgba(0,0,0,0.05); color: var(--text);\n }\n\n button:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }\n\n .primary-action-btn {\n padding: 9px 16px;\n border: none; border-radius: 10px;\n background: var(--text); color: #fff;\n font: 500 0.86rem/1.2 'DM Sans', sans-serif;\n cursor: pointer;\n transition: opacity 120ms;\n }\n .primary-action-btn:hover:not(:disabled) { opacity: 0.85; }\n .primary-action-btn:disabled { opacity: 0.5; cursor: wait; }\n\n .loading-msg { color: var(--muted); font-size: 0.9rem; padding: 8px 0; }\n .err-msg {\n padding: 12px 16px; border-radius: 10px;\n background: var(--err-bg); color: var(--err-text);\n border: 1px solid var(--err-border); font-size: 0.88rem;\n }\n .empty-state {\n padding: 18px 8px; text-align: center; color: var(--muted);\n font-size: 0.88rem;\n }\n .inline-result {\n padding: 8px 12px; border-radius: 8px; font-size: 0.82rem; margin-top: 4px;\n }\n .inline-result.ok { background: var(--ok-bg); color: var(--ok-text); border: 1px solid var(--ok-border); }\n .inline-result.err { background: var(--err-bg); color: var(--err-text); border: 1px solid var(--err-border); }\n\n @media (max-width: 900px) {\n .shell { margin-left: 0; }\n .floating-view-nav {\n left: 50%; right: auto; top: auto; bottom: 18px;\n transform: translateX(-50%); flex-direction: row;\n }\n .view-nav-btn::after {\n left: 50%; top: auto; bottom: calc(100% + 10px);\n transform: translateX(-50%) translateY(4px);\n }\n .view-nav-btn::before {\n left: 50%; top: auto; bottom: calc(100% + 4px);\n transform: translateX(-50%);\n border-right-color: transparent;\n border-top-color: var(--text);\n }\n .view-nav-btn:hover::after,\n .view-nav-btn:focus-visible::after { transform: translateX(-50%) translateY(0); }\n }\n\n @media (max-width: 640px) {\n body { padding: 16px 12px 96px; }\n .topbar { padding: 10px 14px; border-radius: 12px; }\n .topbar-meta { gap: 8px; }\n .page-head { padding-inline: 2px; }\n .card { padding: 18px; border-radius: 16px; }\n }\n`;\n"]}
1
+ {"version":3,"file":"portal-shell.d.ts","sourceRoot":"","sources":["../src/portal-shell.ts"],"names":[],"mappings":"AAcA,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAiFrD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CA8BrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"provisioner.d.ts","sourceRoot":"","sources":["../src/provisioner.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile } from \"child_process\";\nimport { createHash } from \"crypto\";\nimport { readFileSync, statSync } from \"fs\";\nimport { promisify } from \"util\";\nimport * as log from \"./log.js\";\nimport { reportUserFacingError } from \"./observability/sentry.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 type {\n ContainerMount,\n DockerContainerManagerOptions,\n ProvisionOptions,\n ResourceLimits,\n SandboxLimitStatus,\n} from \"./types.js\";\nimport type {\n ContainerMount,\n DockerContainerManagerOptions,\n ProvisionOptions,\n ResourceLimits,\n SandboxLimitStatus,\n} from \"./types.js\";\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 = \"mikan.managed=true\";\n private static readonly IMAGE_MODE_LABEL = \"mikan.sandbox=image\";\n private static readonly VAULT_ID_LABEL_KEY = \"mikan.vault-id\";\n private static readonly CONVERSATION_ID_LABEL_KEY = \"mikan.conversation-id\";\n private static readonly MOUNT_SIGNATURE_LABEL_KEY = \"mikan.mount-signature\";\n\n private readonly limits?: ResourceLimits;\n private readonly boostLimits?: ResourceLimits;\n private readonly boostedKeys = new Set<string>();\n private readonly overrideLimits = new Map<string, 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.boostLimits = options.boostLimits;\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 `mikan-sandbox-${containerKey}`;\n }\n\n static networkName(containerKey: string): string {\n return `mikan-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(containerKey, containerName);\n return containerName;\n }\n\n async boost(containerKey: string): Promise<SandboxLimitStatus> {\n if (!this.boostLimits?.cpus && !this.boostLimits?.memory) {\n return this.getLimitStatus(containerKey);\n }\n\n this.overrideLimits.delete(containerKey);\n this.boostedKeys.add(containerKey);\n const state = this.state.get(containerKey);\n if (state?.status === \"running\") {\n await this.applyResourceLimits(containerKey, state.containerName);\n }\n return this.getLimitStatus(containerKey);\n }\n\n async setLimits(containerKey: string, limits: ResourceLimits): Promise<SandboxLimitStatus> {\n this.boostedKeys.delete(containerKey);\n this.overrideLimits.set(containerKey, { ...this.limits, ...limits });\n const state = this.state.get(containerKey);\n if (state?.status === \"running\") {\n await this.applyResourceLimits(containerKey, state.containerName);\n }\n return this.getLimitStatus(containerKey);\n }\n\n getLimitStatus(containerKey: string): SandboxLimitStatus {\n const boosted = this.boostedKeys.has(containerKey);\n return { limits: this.effectiveLimits(containerKey), boosted };\n }\n\n getDefaultLimits(): ResourceLimits | undefined {\n return this.limits;\n }\n\n getBoostLimits(): ResourceLimits | undefined {\n return this.boostLimits;\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 this.boostedKeys.delete(containerKey);\n this.overrideLimits.delete(containerKey);\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 this.boostedKeys.delete(containerKey);\n this.overrideLimits.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 if (mounts.length > 0) {\n labels.push(\n \"--label\",\n `${DockerContainerManager.MOUNT_SIGNATURE_LABEL_KEY}=${this.mountSignature(mounts)}`,\n );\n }\n await this.execFileImpl(\"docker\", [\n \"run\",\n \"-d\",\n \"--name\",\n containerName,\n \"--network\",\n networkName,\n \"--cap-drop\",\n \"ALL\",\n \"--security-opt\",\n \"no-new-privileges\",\n \"--pids-limit\",\n \"1024\",\n ...labels,\n ...this.resourceLimitArgs(this.effectiveLimits(containerKey)),\n ...this.mountArgs(mounts),\n this.image,\n \"sleep\",\n \"infinity\",\n ]);\n }\n\n private effectiveLimits(containerKey: string): ResourceLimits | undefined {\n const override = this.overrideLimits.get(containerKey);\n if (override) return override;\n if (!this.boostedKeys.has(containerKey)) return this.limits;\n return { ...this.limits, ...this.boostLimits };\n }\n\n private resourceLimitArgs(limits: ResourceLimits | undefined): string[] {\n const args: string[] = [];\n if (limits?.cpus) args.push(\"--cpus\", limits.cpus);\n if (limits?.memory) {\n args.push(\"--memory\", limits.memory);\n // Keep Docker's no-extra-swap semantics explicit. Docker requires\n // memory-swap to be updated together when raising an existing memory\n // limit above the current swap limit.\n args.push(\"--memory-swap\", limits.memory);\n }\n return args;\n }\n\n private async applyResourceLimits(containerKey: string, containerName: string): Promise<void> {\n const limitArgs = this.resourceLimitArgs(this.effectiveLimits(containerKey));\n if (limitArgs.length === 0) return;\n const args = [\"update\", ...limitArgs, 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 reportUserFacingError(err, {\n domain: \"sandbox\",\n surface: \"sandbox_provision\",\n operation: \"apply_resource_limits\",\n severity: \"warning\",\n context: {\n sandboxType: \"image\",\n containerKey,\n containerName,\n limitArgCount: limitArgs.length,\n fatal: false,\n },\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 if (await this.hasMountSignatureDrift(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 .toSorted();\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 hasMountSignatureDrift(\n containerName: string,\n mounts: ContainerMount[],\n ): Promise<boolean> {\n if (mounts.length === 0) return false;\n const expected = this.mountSignature(mounts);\n const { stdout } = await this.execFileImpl(\"docker\", [\n \"inspect\",\n \"-f\",\n `{{index .Config.Labels \"${DockerContainerManager.MOUNT_SIGNATURE_LABEL_KEY}\"}}`,\n containerName,\n ]);\n const actual = this.normalizeDockerValue(stdout.trim());\n return actual !== expected;\n }\n\n private mountSignature(mounts: ContainerMount[]): string {\n const payload = mounts\n .map((mount) => ({\n source: mount.source,\n target: mount.target,\n fingerprint: this.mountSourceFingerprint(mount.source),\n }))\n .toSorted((left, right) =>\n `${left.target}\\0${left.source}`.localeCompare(`${right.target}\\0${right.source}`),\n );\n return createHash(\"sha256\").update(JSON.stringify(payload)).digest(\"hex\");\n }\n\n private mountSourceFingerprint(source: string): string {\n try {\n const stat = statSync(source);\n if (stat.isFile()) {\n return createHash(\"sha256\").update(readFileSync(source)).digest(\"hex\");\n }\n return `${stat.isDirectory() ? \"dir\" : \"other\"}:${stat.size}:${stat.mtimeMs}`;\n } catch {\n return \"missing\";\n }\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].toSorted();\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 mikan container ${containerName} (pre-channel-isolation scheme)`,\n `Failed to remove legacy mikan container ${containerName}`,\n );\n }\n}\n"]}
1
+ {"version":3,"file":"provisioner.d.ts","sourceRoot":"","sources":["../src/provisioner.ts"],"names":[],"mappings":"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"}