@x-otto/cli 0.0.1-alpha.43 → 0.0.1-alpha.44

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 (60) hide show
  1. package/dist/build-id-D_JURZdd.js +3 -0
  2. package/dist/build-id-D_JURZdd.js.map +1 -0
  3. package/dist/bundled-extensions/plugin-otto-wire-protocols/plugin-dist/meta.json +1 -1
  4. package/dist/bundled-extensions/plugin-otto-wire-protocols/plugin-dist/plugin.cjs +2 -1
  5. package/dist/bundled-extensions/plugin-otto-wire-protocols/src/openai-responses.ts +5 -1
  6. package/dist/{command-dispatcher-DhcLUPR5.js → command-dispatcher-Dxj41r5P.js} +4 -4
  7. package/dist/{command-dispatcher-DhcLUPR5.js.map → command-dispatcher-Dxj41r5P.js.map} +1 -1
  8. package/dist/{daemon-base-Bc9p51Um.js → daemon-base-Y1XI61JY.js} +1 -1
  9. package/dist/{daemon-base-Bc9p51Um.js.map → daemon-base-Y1XI61JY.js.map} +1 -1
  10. package/dist/{doctor-lT2QhG2q.js → doctor-DXBLkbkP.js} +9 -9
  11. package/dist/doctor-DXBLkbkP.js.map +1 -0
  12. package/dist/{doctor-attach-_zeIJewx.js → doctor-attach-DEMuyBOk.js} +2 -2
  13. package/dist/{doctor-attach-_zeIJewx.js.map → doctor-attach-DEMuyBOk.js.map} +1 -1
  14. package/dist/{doctor-cdp-K_mIFRfA.js → doctor-cdp-CnJUVNOB.js} +1 -1
  15. package/dist/{doctor-cdp-K_mIFRfA.js.map → doctor-cdp-CnJUVNOB.js.map} +1 -1
  16. package/dist/{doctor-heap-Rr2nNvcw.js → doctor-heap-Eu3LZj-F.js} +2 -2
  17. package/dist/{doctor-heap-Rr2nNvcw.js.map → doctor-heap-Eu3LZj-F.js.map} +1 -1
  18. package/dist/{doctor-ps-OL3FGQYu.js → doctor-ps-JBgCH77n.js} +2 -2
  19. package/dist/{doctor-ps-OL3FGQYu.js.map → doctor-ps-JBgCH77n.js.map} +1 -1
  20. package/dist/export-trajectory-D-BcH0Wt.js +14 -0
  21. package/dist/export-trajectory-D-BcH0Wt.js.map +1 -0
  22. package/dist/{feedback-BQ_oz5nh.js → feedback-CYFY2MC4.js} +2 -2
  23. package/dist/{feedback-BQ_oz5nh.js.map → feedback-CYFY2MC4.js.map} +1 -1
  24. package/dist/feedback-D7Po4mlE.js +2 -0
  25. package/dist/{feishu-setup-B6ETf-8Y.js → feishu-setup-5ZoxtH0J.js} +1 -1
  26. package/dist/{feishu-setup-B6ETf-8Y.js.map → feishu-setup-5ZoxtH0J.js.map} +1 -1
  27. package/dist/{ftue-doctor-recovery-DeAf8jVo.js → ftue-doctor-recovery-8FeDBFOc.js} +1 -1
  28. package/dist/{ftue-doctor-recovery-DeAf8jVo.js.map → ftue-doctor-recovery-8FeDBFOc.js.map} +1 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +4 -4
  31. package/dist/index.js.map +1 -1
  32. package/dist/{mcp-9P_AmnDk.js → mcp-Cm4-OhXI.js} +1 -1
  33. package/dist/{mcp-9P_AmnDk.js.map → mcp-Cm4-OhXI.js.map} +1 -1
  34. package/dist/{mcp-server-BK4L-YBN.js → mcp-server-Dpza3yn2.js} +1 -1
  35. package/dist/{mcp-server-BK4L-YBN.js.map → mcp-server-Dpza3yn2.js.map} +1 -1
  36. package/dist/{migrate-DDNkik_0.js → migrate-RlBJqJnB.js} +1 -1
  37. package/dist/{migrate-DDNkik_0.js.map → migrate-RlBJqJnB.js.map} +1 -1
  38. package/dist/{observe-CzIv09hO.js → observe-Dxfud-t7.js} +1 -1
  39. package/dist/{observe-CzIv09hO.js.map → observe-Dxfud-t7.js.map} +1 -1
  40. package/dist/parse-cli-BSJEQtBo.js +3 -0
  41. package/dist/parse-cli-BSJEQtBo.js.map +1 -0
  42. package/dist/{persistence-DOaizHMA.js → persistence-CRFhOYx6.js} +2 -2
  43. package/dist/{persistence-DOaizHMA.js.map → persistence-CRFhOYx6.js.map} +1 -1
  44. package/dist/{plugin-assembly-check-Ov17ra7G.js → plugin-assembly-check-DEozmcJ7.js} +1 -1
  45. package/dist/{plugin-assembly-check-Ov17ra7G.js.map → plugin-assembly-check-DEozmcJ7.js.map} +1 -1
  46. package/dist/{ps-BovE9XMQ.js → ps-DiKCLKbs.js} +1 -1
  47. package/dist/{ps-BovE9XMQ.js.map → ps-DiKCLKbs.js.map} +1 -1
  48. package/dist/{run-attach-z7YECztf.js → run-attach-DDpMk2_N.js} +1 -1
  49. package/dist/{run-attach-z7YECztf.js.map → run-attach-DDpMk2_N.js.map} +1 -1
  50. package/dist/{serve-DaxogAZ5.js → serve-Ke0nwN9Y.js} +2 -2
  51. package/dist/{serve-DaxogAZ5.js.map → serve-Ke0nwN9Y.js.map} +1 -1
  52. package/dist/{version-Eh8zZKgk.js → version-BKPdYoHG.js} +2 -2
  53. package/dist/{version-Eh8zZKgk.js.map → version-BKPdYoHG.js.map} +1 -1
  54. package/package.json +12 -12
  55. package/dist/build-id-ClyMIKLy.js +0 -3
  56. package/dist/build-id-ClyMIKLy.js.map +0 -1
  57. package/dist/doctor-lT2QhG2q.js.map +0 -1
  58. package/dist/feedback-C2Hdxp1y.js +0 -2
  59. package/dist/parse-cli-3fWEIMWc.js +0 -3
  60. package/dist/parse-cli-3fWEIMWc.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"feishu-setup-B6ETf-8Y.js","names":[],"sources":["../src/commands/handlers/feishu-setup.ts"],"sourcesContent":["/**\n * /feishu-setup 命令:飞书 webhook 绑定交互向导。\n */\nimport { spawn } from 'node:child_process'\nimport { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { findWorkspaceRoot } from '@x-otto/coding'\nimport { discoverPluginsWithBundled } from '../../discover-with-bundled'\nimport type { CliContext } from '../../command-dispatcher'\n\n/** 按优先级计算 feishu-use 配置文件候选路径(project > repo > user),返回最高优先级路径。 */\nfunction resolveConfigPath(cwd: string): string {\n const repoRoot = findWorkspaceRoot(cwd)\n if (repoRoot && join(repoRoot) !== join(cwd)) {\n return join(cwd, '.otto', 'feishu-use.json')\n }\n return join(cwd, '.otto', 'feishu-use.json')\n}\n\nexport interface FeishuSetupResult {\n /** app_id 已写入配置 */\n appId: string\n /** bot/v3/info 返回的 bot 身份;验证失败时为 undefined */\n botOpenId?: string\n botName?: string\n /** 实际写入的配置文件路径 */\n configPath: string\n /** setup 是否完整成功(凭据已写入 + bot 身份已验证) */\n success: boolean\n}\n\n/** 往指定路径写入 feishu-use 配置文件(mode 0o600),覆盖已有文件。 */\nfunction writeFeishuConfigFile(configPath: string, overrides: Record<string, unknown>): string {\n const base = {\n app_id: 'REPLACE_WITH_YOUR_FEISHU_APP_ID',\n app_secret: 'REPLACE_WITH_YOUR_FEISHU_APP_SECRET',\n allowed_chats: [] as string[],\n workspace_dir: join(configPath, '..', '..', 'feishu-use-workspace'),\n max_reply_chunk_length: 4000,\n }\n const merged = { ...base }\n for (const [k, v] of Object.entries(overrides)) {\n if (v !== undefined && v !== '') (merged as Record<string, unknown>)[k] = v\n }\n mkdirSync(join(configPath, '..'), { recursive: true })\n writeFileSync(configPath, JSON.stringify(merged, null, 2) + '\\n', { mode: 0o600 })\n return configPath\n}\n\n/** 从配置文件读取当前值;文件不存在时返回 undefined。 */\nfunction readConfigSafe(configPath: string): Record<string, unknown> | undefined {\n try {\n if (!existsSync(configPath)) return undefined\n return JSON.parse(readFileSync(configPath, 'utf8')) as Record<string, unknown>\n } catch {\n return undefined\n }\n}\n\n/** openSelect 的 Promise 包装:用户选择 → resolve(value),Esc/取消 → resolve(undefined)。 */\nfunction promiseSelect(\n ctx: CliContext,\n opts: { title: string; options: Array<{ label: string; value: string; detail?: string }> },\n): Promise<string | undefined> {\n return new Promise((resolve) => {\n ctx.tui.modal.openModal({\n kind: 'select',\n ...opts,\n onSelect: (v) => resolve(v),\n onCancel: () => resolve(undefined),\n })\n })\n}\n\n/** openConfirm 的 Promise 包装:确认 → resolve(true),取消 → resolve(false)。 */\nfunction promiseConfirm(ctx: CliContext, title: string, message: string | string[]): Promise<boolean> {\n return new Promise((resolve) => {\n ctx.tui.modal.openModal({\n kind: 'confirm',\n title,\n message,\n onConfirm: () => resolve(true),\n onCancel: () => resolve(false),\n })\n })\n}\n\n/**\n * 启动 `registerApp` 子进程并等待结果。\n *\n * 子进程 stdout 输出 JSON `{ client_id, client_secret }` 表示成功;\n * 超时/崩溃/非零退出码 → resolve(undefined)。\n *\n * `pluginDir` 是 feishu-use 插件安装目录(含 node_modules/@larksuiteoapi/node-sdk)。\n *\n * `onQrCodeUrl`(RFC-134 §8 F1 修复):QR 码 URL 由 SDK `onQRCodeReady` 回调在子进程侧\n * 产生,经 `QRCODE_URL::<json>` 前缀行写入 stderr——本函数解析该前缀行并回调给调用方展示,\n * 修复此前\"stderr 从未被读取、URL 被静默丢弃\"的缺陷(用户选择扫码后永远看不到二维码)。\n */\nfunction runRegisterApp(\n pluginDir: string,\n timeoutMs = 5 * 60 * 1000,\n onQrCodeUrl?: (info: { url: string; expireIn: number }) => void,\n): Promise<{ client_id: string; client_secret: string } | undefined> {\n return new Promise((resolve) => {\n const scriptPath = join(pluginDir, 'scripts', 'register-app.mjs')\n if (!existsSync(scriptPath)) {\n resolve(undefined)\n return\n }\n\n const child = spawn('node', [scriptPath], {\n cwd: pluginDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n timeout: timeoutMs,\n env: { ...process.env },\n })\n\n let stdout = ''\n let stderr = ''\n let qrEmitted = false\n child.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString()\n })\n child.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString()\n if (qrEmitted || !onQrCodeUrl) return\n const line = stderr.split('\\n').find((l) => l.startsWith('QRCODE_URL::'))\n if (!line) return\n try {\n const info = JSON.parse(line.slice('QRCODE_URL::'.length)) as { url: string; expireIn: number }\n if (info.url) {\n qrEmitted = true\n onQrCodeUrl(info)\n }\n } catch {\n /* 前缀行畸形,忽略,等待后续 data 事件或直到子进程结束都拿不到 URL */\n }\n })\n\n child.on('error', () => resolve(undefined))\n child.on('close', (code) => {\n if (code !== 0) return resolve(undefined)\n try {\n const result = JSON.parse(stdout.trim().split('\\n').pop()!) as {\n client_id: string\n client_secret: string\n }\n if (result.client_id && result.client_secret) {\n resolve(result)\n return\n }\n } catch {\n /* fall through */\n }\n resolve(undefined)\n })\n })\n}\n\n/**\n * 用 app_id/app_secret 调用 `bot/v3/info` 验证凭据并获取 bot 身份。\n *\n * 子进程执行插件自带脚本 `scripts/verify-bot.mjs`(与 `runRegisterApp` 调用\n * `register-app.mjs` 同模式,终局架构 review 2026-07-20 下沉)——宿主 CLI 只负责\n * spawn + 传参 + 解析结果,不内联飞书 SDK 的具体调用细节(`bot/v3/info` 端点/Client\n * 构造方式),保持 RFC-134 D2 的架构隔离:`packages/cli` 对插件内部实现零认知。\n * 失败(网络不通/凭据错误/权限不足/脚本缺失)返回 undefined。\n */\nfunction verifyBotIdentity(\n pluginDir: string,\n appId: string,\n appSecret: string,\n): Promise<{ openId: string; name: string } | undefined> {\n return new Promise((resolve) => {\n const scriptPath = join(pluginDir, 'scripts', 'verify-bot.mjs')\n if (!existsSync(scriptPath)) {\n resolve(undefined)\n return\n }\n\n const child = spawn('node', [scriptPath], {\n cwd: pluginDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n timeout: 15_000,\n env: { ...process.env, FEISHU_VERIFY_APP_ID: appId, FEISHU_VERIFY_APP_SECRET: appSecret },\n })\n\n let stdout = ''\n child.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString()\n })\n\n child.on('error', () => resolve(undefined))\n child.on('close', (code) => {\n if (code !== 0) return resolve(undefined)\n try {\n const r = JSON.parse(stdout.trim()) as { openId: string; name: string }\n resolve(r)\n } catch {\n resolve(undefined)\n }\n })\n })\n}\n\n/** 脱敏 App ID:前 8 字符 + *** + 后 4 字符。 */\nfunction maskAppId(appId: string): string {\n if (appId.length <= 12) return appId.slice(0, 4) + '***'\n return appId.slice(0, 8) + '***' + appId.slice(-4)\n}\n\n/**\n * feishu-use 交互式配置向导主入口(RFC-134 M1)。\n *\n * 在 TUI 内调用(需已有 TUI 上下文),通过 async/await 链式编排对话框。\n * 外部调用方负责提供 configPath 和 pluginDir。\n *\n * @param ctx CliContext(需 TUI 可用)\n * @param configPath 配置文件的目标路径(如 `<cwd>/.otto/feishu-use.json`)\n * @param pluginDir feishu-use 插件的安装目录(含 node_modules)\n * @param existingConfig 已有配置(存在时为重配置模式,展示当前值)\n */\nexport async function runFeishuSetupWizard(\n ctx: CliContext,\n configPath: string,\n pluginDir: string,\n existingConfig?: Record<string, unknown>,\n): Promise<FeishuSetupResult | undefined> {\n // ── 重配置模式:展示当前值 + 确认覆盖 ──\n if (existingConfig?.app_id) {\n const currentAppId = String(existingConfig.app_id)\n const lines = [\n `App ID: ${maskAppId(currentAppId)}`,\n existingConfig.allowed_chats\n ? `allowed_chats: ${(existingConfig.allowed_chats as string[]).length} 个`\n : 'allowed_chats: 空(拒绝所有)',\n `配置路径: ${configPath}`,\n ]\n const confirmed = await promiseConfirm(ctx, 'feishu-use 重配置', ['当前配置:', '', ...lines, '', '确定要重新配置吗?当前凭据将被覆盖。'])\n if (!confirmed) return undefined\n }\n\n // ── Step 1: 选择配置方式 ──\n const method = await promiseSelect(ctx, {\n title: 'feishu-use 配置',\n options: [\n { label: '扫码自动创建飞书应用(推荐)', value: 'qr', detail: '飞书 App 扫码确认后自动获取凭据' },\n { label: '手动输入 App ID / App Secret', value: 'manual', detail: '已有飞书自建应用,直接填入凭据' },\n ],\n })\n if (!method) return undefined // user cancelled\n\n let appId = ''\n let appSecret = ''\n let allowedChats: string[] = []\n let trustedChats: string[] = []\n\n // ── Step 2a: QR 码路径 ──\n if (method === 'qr') {\n ctx.tui.info.showToast('plugin-feishu-use', '正在生成飞书应用注册二维码,请稍候…')\n\n const result = await runRegisterApp(pluginDir, 5 * 60 * 1000, (info) => {\n // RFC-134 §8 F1 修复:QR URL 必须展示给用户才能完成扫码,此前写入 stderr 后\n // 从未被读取,用户永远看不到二维码。用 pushMessage(非 toast)展示——toast 会\n // 在几秒后自动消失,而用户需要足够时间打开飞书 App 扫码。\n const expireMinutes = Math.round(info.expireIn / 60)\n ctx.tui.messages.pushMessage({\n role: 'assistant',\n content: [{\n type: 'text',\n text: `feishu-use:请在飞书 App 中打开以下链接扫码确认创建应用(${expireMinutes} 分钟内有效):\\n${info.url}`,\n }],\n })\n })\n if (!result) {\n // 超时或失败 → 回退到手动输入\n const retry = await promiseConfirm(ctx, 'plugin-feishu-use', '扫码注册失败(超时或网络错误)。是否改为手动输入凭据?')\n if (!retry) return undefined\n // 继续执行 manual 路径(故意 fall-through)\n } else {\n appId = result.client_id\n appSecret = result.client_secret\n ctx.tui.info.showToast('plugin-feishu-use', '扫码注册成功!凭据已自动填充。')\n }\n }\n\n // ── Step 2b: 手动输入路径(或 QR 失败后回退) ──\n if (!appId) {\n const hintId = existingConfig?.app_id ? `(当前: ${maskAppId(String(existingConfig.app_id))},留空保留原值)` : ''\n const enteredId = await ctx.tui.modal.openModal({\n kind: 'input',\n title: '飞书 App ID',\n placeholder: `cli_xxxxxxxxxxxx ${hintId}`,\n description: [],\n })\n if (enteredId === null) return undefined\n appId = enteredId || String(existingConfig?.app_id ?? '')\n\n const enteredSecret = await ctx.tui.modal.openModal({\n kind: 'input',\n title: '飞书 App Secret',\n mask: true,\n description: existingConfig?.app_secret ? ['留空保留当前 Secret'] : [],\n })\n if (enteredSecret === null) return undefined\n appSecret = enteredSecret || String(existingConfig?.app_secret ?? '')\n\n if (!appId || !appSecret) {\n ctx.tui.info.showToast('plugin-feishu-use', 'App ID 和 App Secret 不能为空,配置已取消。')\n return undefined\n }\n\n // 可选字段\n const chatsRaw = await ctx.tui.modal.openModal({\n kind: 'input',\n title: '允许的 chat_id(逗号分隔,留空=拒绝所有)',\n placeholder: existingConfig ? `当前: ${(existingConfig.allowed_chats as string[] | undefined)?.join(', ') ?? '空'}` : '',\n description: [],\n })\n if (chatsRaw === null) return undefined\n if (chatsRaw) {\n allowedChats = chatsRaw.split(',').map(s => s.trim()).filter(Boolean)\n } else if (existingConfig?.allowed_chats) {\n allowedChats = existingConfig.allowed_chats as string[]\n }\n\n const trustedRaw = await ctx.tui.modal.openModal({\n kind: 'input',\n title: '可信 chat_id(逗号分隔,留空=仅只读)',\n placeholder: existingConfig ? `当前: ${(existingConfig.trusted_chats as string[] | undefined)?.join(', ') ?? '空'}` : '',\n description: [],\n })\n if (trustedRaw === null) return undefined\n if (trustedRaw) {\n trustedChats = trustedRaw.split(',').map(s => s.trim()).filter(Boolean)\n } else if (existingConfig?.trusted_chats) {\n trustedChats = existingConfig.trusted_chats as string[]\n }\n }\n\n // ── Step 3: 写入配置 ──\n const workspaceDir = existingConfig?.workspace_dir\n ? String(existingConfig.workspace_dir)\n : join(pluginDir, '..', '..', 'feishu-use-workspace')\n writeFeishuConfigFile(configPath, {\n app_id: appId,\n app_secret: appSecret,\n allowed_chats: allowedChats,\n trusted_chats: trustedChats,\n workspace_dir: workspaceDir,\n })\n\n ctx.tui.info.showToast('plugin-feishu-use', `配置已写入 ${configPath}`)\n\n // ── Step 4: 验证 bot 身份 ──\n const bot = await verifyBotIdentity(pluginDir, appId, appSecret)\n if (bot) {\n ctx.tui.info.showToast('plugin-feishu-use', `Bot 身份验证成功:${bot.name} (${bot.openId})`)\n } else {\n ctx.tui.messages.pushMessage({\n role: 'command_echo',\n command: '/feishu setup',\n status: 'error',\n summary: 'bot 身份验证失败(凭据不正确或网络不可达)',\n detail: '请稍后用 `otto feishu config set` 修正凭据,或手动编辑配置文件。',\n })\n }\n\n return {\n appId,\n botOpenId: bot?.openId,\n botName: bot?.name,\n configPath,\n success: !!bot,\n }\n}\n\n/**\n * 给 runFeishuSetupWizard 准备参数的外层封装:计算 configPath 和 pluginDir。\n *\n * @returns setup 结果,或 undefined(用户取消)\n */\nexport async function launchFeishuSetup(\n ctx: CliContext,\n): Promise<FeishuSetupResult | undefined> {\n const ws = ctx.app.workspaceDir ?? process.cwd()\n const configPath = resolveConfigPath(ws)\n\n // 找到 feishu-use 的安装目录(插件目录 = 含 otto-plugin.json 的目录)\n const allPlugins = discoverPluginsWithBundled({ cwd: ws, homedir: homedir() })\n const feishuPlugin = allPlugins.find(p => p.id === 'plugin-feishu-use')\n if (!feishuPlugin) {\n ctx.tui.info.showToast('plugin-feishu-use', 'feishu-use 插件尚未安装,请先在 `/model` 安装入口安装 feishu-use。')\n return undefined\n }\n\n const pluginDir = feishuPlugin.dir\n const existing = readConfigSafe(configPath)\n\n return runFeishuSetupWizard(ctx, configPath, pluginDir, existing)\n}\n"],"mappings":";kTAYA,SAAS,EAAkB,EAAqB,CAC9C,IAAM,EAAW,EAAkB,EAAI,CAIvC,OAHI,IAAY,EAAK,EAAS,CAAK,EAAK,EAAI,EACnC,EAAK,EAAK,QAAS,kBAAkB,CAkBhD,SAAS,EAAsB,EAAoB,EAA4C,CAQ7F,IAAM,EAAS,CANb,OAAQ,kCACR,WAAY,sCACZ,cAAe,EAAE,CACjB,cAAe,EAAK,EAAY,KAAM,KAAM,uBAAuB,CACnE,uBAAwB,IAEA,CAC1B,IAAK,GAAM,CAAC,EAAG,KAAM,OAAO,QAAQ,EAAU,CACxC,IAAM,IAAA,IAAa,IAAM,KAAK,EAAmC,GAAK,GAI5E,OAFA,EAAU,EAAK,EAAY,KAAK,CAAE,CAAE,UAAW,GAAM,CAAC,CACtD,EAAc,EAAY,KAAK,UAAU,EAAQ,KAAM,EAAE,CAAG;EAAM,CAAE,KAAM,IAAO,CAAC,CAC3E,EAIT,SAAS,EAAe,EAAyD,CAC/E,GAAI,CAEF,OADK,EAAW,EAAW,CACpB,KAAK,MAAM,EAAa,EAAY,OAAO,CAAC,CADtB,YAEvB,CACN,QAKJ,SAAS,EACP,EACA,EAC6B,CAC7B,OAAO,IAAI,QAAS,GAAY,CAC9B,EAAI,IAAI,MAAM,UAAU,CACtB,KAAM,SACN,GAAG,EACH,SAAW,GAAM,EAAQ,EAAE,CAC3B,aAAgB,EAAQ,IAAA,GAAU,CACnC,CAAC,EACF,CAIJ,SAAS,EAAe,EAAiB,EAAe,EAA8C,CACpG,OAAO,IAAI,QAAS,GAAY,CAC9B,EAAI,IAAI,MAAM,UAAU,CACtB,KAAM,UACN,QACA,UACA,cAAiB,EAAQ,GAAK,CAC9B,aAAgB,EAAQ,GAAM,CAC/B,CAAC,EACF,CAeJ,SAAS,EACP,EACA,EAAY,IAAS,IACrB,EACmE,CACnE,OAAO,IAAI,QAAS,GAAY,CAC9B,IAAM,EAAa,EAAK,EAAW,UAAW,mBAAmB,CACjE,GAAI,CAAC,EAAW,EAAW,CAAE,CAC3B,EAAQ,IAAA,GAAU,CAClB,OAGF,IAAM,EAAQ,EAAM,OAAQ,CAAC,EAAW,CAAE,CACxC,IAAK,EACL,MAAO,CAAC,SAAU,OAAQ,OAAO,CACjC,QAAS,EACT,IAAK,CAAE,GAAG,QAAQ,IAAK,CACxB,CAAC,CAEE,EAAS,GACT,EAAS,GACT,EAAY,GAChB,EAAM,OAAO,GAAG,OAAS,GAAkB,CACzC,GAAU,EAAM,UAAU,EAC1B,CACF,EAAM,OAAO,GAAG,OAAS,GAAkB,CAEzC,GADA,GAAU,EAAM,UAAU,CACtB,GAAa,CAAC,EAAa,OAC/B,IAAM,EAAO,EAAO,MAAM;EAAK,CAAC,KAAM,GAAM,EAAE,WAAW,eAAe,CAAC,CACpE,KACL,GAAI,CACF,IAAM,EAAO,KAAK,MAAM,EAAK,MAAM,GAAsB,CAAC,CACtD,EAAK,MACP,EAAY,GACZ,EAAY,EAAK,OAEb,IAGR,CAEF,EAAM,GAAG,YAAe,EAAQ,IAAA,GAAU,CAAC,CAC3C,EAAM,GAAG,QAAU,GAAS,CAC1B,GAAI,IAAS,EAAG,OAAO,EAAQ,IAAA,GAAU,CACzC,GAAI,CACF,IAAM,EAAS,KAAK,MAAM,EAAO,MAAM,CAAC,MAAM;EAAK,CAAC,KAAK,CAAE,CAI3D,GAAI,EAAO,WAAa,EAAO,cAAe,CAC5C,EAAQ,EAAO,CACf,aAEI,EAGR,EAAQ,IAAA,GAAU,EAClB,EACF,CAYJ,SAAS,EACP,EACA,EACA,EACuD,CACvD,OAAO,IAAI,QAAS,GAAY,CAC9B,IAAM,EAAa,EAAK,EAAW,UAAW,iBAAiB,CAC/D,GAAI,CAAC,EAAW,EAAW,CAAE,CAC3B,EAAQ,IAAA,GAAU,CAClB,OAGF,IAAM,EAAQ,EAAM,OAAQ,CAAC,EAAW,CAAE,CACxC,IAAK,EACL,MAAO,CAAC,SAAU,OAAQ,OAAO,CACjC,QAAS,KACT,IAAK,CAAE,GAAG,QAAQ,IAAK,qBAAsB,EAAO,yBAA0B,EAAW,CAC1F,CAAC,CAEE,EAAS,GACb,EAAM,OAAO,GAAG,OAAS,GAAkB,CACzC,GAAU,EAAM,UAAU,EAC1B,CAEF,EAAM,GAAG,YAAe,EAAQ,IAAA,GAAU,CAAC,CAC3C,EAAM,GAAG,QAAU,GAAS,CAC1B,GAAI,IAAS,EAAG,OAAO,EAAQ,IAAA,GAAU,CACzC,GAAI,CAEF,EADU,KAAK,MAAM,EAAO,MAAM,CAAC,CACzB,MACJ,CACN,EAAQ,IAAA,GAAU,GAEpB,EACF,CAIJ,SAAS,EAAU,EAAuB,CAExC,OADI,EAAM,QAAU,GAAW,EAAM,MAAM,EAAG,EAAE,CAAG,MAC5C,EAAM,MAAM,EAAG,EAAE,CAAG,MAAQ,EAAM,MAAM,GAAG,CAcpD,eAAsB,EACpB,EACA,EACA,EACA,EACwC,CAExC,GAAI,GAAgB,QAUd,CADc,MAAM,EAAe,EAAK,iBAAkB,CAAC,QAAS,GAAI,GAP9D,CACZ,WAAW,EAFQ,OAAO,EAAe,OAAO,CAEd,GAClC,EAAe,cACX,kBAAmB,EAAe,cAA2B,OAAO,IACpE,yBACJ,SAAS,IACV,CACqF,GAAI,qBAAqB,CAAC,CAChG,OAIlB,IAAM,EAAS,MAAM,EAAc,EAAK,CACtC,MAAO,gBACP,QAAS,CACP,CAAE,MAAO,iBAAkB,MAAO,KAAM,OAAQ,qBAAsB,CACtE,CAAE,MAAO,2BAA4B,MAAO,SAAU,OAAQ,kBAAmB,CAClF,CACF,CAAC,CACF,GAAI,CAAC,EAAQ,OAEb,IAAI,EAAQ,GACR,EAAY,GACZ,EAAyB,EAAE,CAC3B,EAAyB,EAAE,CAG/B,GAAI,IAAW,KAAM,CACnB,EAAI,IAAI,KAAK,UAAU,oBAAqB,qBAAqB,CAEjE,IAAM,EAAS,MAAM,EAAe,EAAW,IAAS,IAAO,GAAS,CAItE,IAAM,EAAgB,KAAK,MAAM,EAAK,SAAW,GAAG,CACpD,EAAI,IAAI,SAAS,YAAY,CAC3B,KAAM,YACN,QAAS,CAAC,CACR,KAAM,OACN,KAAM,uCAAuC,EAAc,YAAY,EAAK,MAC7E,CAAC,CACH,CAAC,EACF,CACF,GAAK,EAMH,EAAQ,EAAO,UACf,EAAY,EAAO,cACnB,EAAI,IAAI,KAAK,UAAU,oBAAqB,kBAAkB,SAL1D,CADU,MAAM,EAAe,EAAK,oBAAqB,8BAA8B,CAC/E,OAUhB,GAAI,CAAC,EAAO,CACV,IAAM,EAAS,GAAgB,OAAS,QAAQ,EAAU,OAAO,EAAe,OAAO,CAAC,CAAC,UAAY,GAC/F,EAAY,MAAM,EAAI,IAAI,MAAM,UAAU,CAC9C,KAAM,QACN,MAAO,YACP,YAAa,oBAAoB,IACjC,YAAa,EAAE,CAChB,CAAC,CACF,GAAI,IAAc,KAAM,OACxB,EAAQ,GAAa,OAAO,GAAgB,QAAU,GAAG,CAEzD,IAAM,EAAgB,MAAM,EAAI,IAAI,MAAM,UAAU,CAClD,KAAM,QACN,MAAO,gBACP,KAAM,GACN,YAAa,GAAgB,WAAa,CAAC,gBAAgB,CAAG,EAAE,CACjE,CAAC,CACF,GAAI,IAAkB,KAAM,OAG5B,GAFA,EAAY,GAAiB,OAAO,GAAgB,YAAc,GAAG,CAEjE,CAAC,GAAS,CAAC,EAAW,CACxB,EAAI,IAAI,KAAK,UAAU,oBAAqB,kCAAkC,CAC9E,OAIF,IAAM,EAAW,MAAM,EAAI,IAAI,MAAM,UAAU,CAC7C,KAAM,QACN,MAAO,4BACP,YAAa,EAAiB,OAAQ,EAAe,eAAwC,KAAK,KAAK,EAAI,MAAQ,GACnH,YAAa,EAAE,CAChB,CAAC,CACF,GAAI,IAAa,KAAM,OACnB,EACF,EAAe,EAAS,MAAM,IAAI,CAAC,IAAI,GAAK,EAAE,MAAM,CAAC,CAAC,OAAO,QAAQ,CAC5D,GAAgB,gBACzB,EAAe,EAAe,eAGhC,IAAM,EAAa,MAAM,EAAI,IAAI,MAAM,UAAU,CAC/C,KAAM,QACN,MAAO,0BACP,YAAa,EAAiB,OAAQ,EAAe,eAAwC,KAAK,KAAK,EAAI,MAAQ,GACnH,YAAa,EAAE,CAChB,CAAC,CACF,GAAI,IAAe,KAAM,OACrB,EACF,EAAe,EAAW,MAAM,IAAI,CAAC,IAAI,GAAK,EAAE,MAAM,CAAC,CAAC,OAAO,QAAQ,CAC9D,GAAgB,gBACzB,EAAe,EAAe,eAKlC,IAAM,EAAe,GAAgB,cACjC,OAAO,EAAe,cAAc,CACpC,EAAK,EAAW,KAAM,KAAM,uBAAuB,CACvD,EAAsB,EAAY,CAChC,OAAQ,EACR,WAAY,EACZ,cAAe,EACf,cAAe,EACf,cAAe,EAChB,CAAC,CAEF,EAAI,IAAI,KAAK,UAAU,oBAAqB,SAAS,IAAa,CAGlE,IAAM,EAAM,MAAM,EAAkB,EAAW,EAAO,EAAU,CAahE,OAZI,EACF,EAAI,IAAI,KAAK,UAAU,oBAAqB,cAAc,EAAI,KAAK,IAAI,EAAI,OAAO,GAAG,CAErF,EAAI,IAAI,SAAS,YAAY,CAC3B,KAAM,eACN,QAAS,gBACT,OAAQ,QACR,QAAS,0BACT,OAAQ,gDACT,CAAC,CAGG,CACL,QACA,UAAW,GAAK,OAChB,QAAS,GAAK,KACd,aACA,QAAS,CAAC,CAAC,EACZ,CAQH,eAAsB,EACpB,EACwC,CACxC,IAAM,EAAK,EAAI,IAAI,cAAgB,QAAQ,KAAK,CAC1C,EAAa,EAAkB,EAAG,CAIlC,EADa,EAA2B,CAAE,IAAK,EAAI,QAAS,GAAS,CAAE,CAAC,CAC9C,KAAK,GAAK,EAAE,KAAO,oBAAoB,CACvE,GAAI,CAAC,EAAc,CACjB,EAAI,IAAI,KAAK,UAAU,oBAAqB,oDAAoD,CAChG,OAGF,IAAM,EAAY,EAAa,IAG/B,OAAO,EAAqB,EAAK,EAAY,EAF5B,EAAe,EAAW,CAEsB"}
1
+ {"version":3,"file":"feishu-setup-5ZoxtH0J.js","names":[],"sources":["../src/commands/handlers/feishu-setup.ts"],"sourcesContent":["/**\n * /feishu-setup 命令:飞书 webhook 绑定交互向导。\n */\nimport { spawn } from 'node:child_process'\nimport { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { findWorkspaceRoot } from '@x-otto/coding'\nimport { discoverPluginsWithBundled } from '../../discover-with-bundled'\nimport type { CliContext } from '../../command-dispatcher'\n\n/** 按优先级计算 feishu-use 配置文件候选路径(project > repo > user),返回最高优先级路径。 */\nfunction resolveConfigPath(cwd: string): string {\n const repoRoot = findWorkspaceRoot(cwd)\n if (repoRoot && join(repoRoot) !== join(cwd)) {\n return join(cwd, '.otto', 'feishu-use.json')\n }\n return join(cwd, '.otto', 'feishu-use.json')\n}\n\nexport interface FeishuSetupResult {\n /** app_id 已写入配置 */\n appId: string\n /** bot/v3/info 返回的 bot 身份;验证失败时为 undefined */\n botOpenId?: string\n botName?: string\n /** 实际写入的配置文件路径 */\n configPath: string\n /** setup 是否完整成功(凭据已写入 + bot 身份已验证) */\n success: boolean\n}\n\n/** 往指定路径写入 feishu-use 配置文件(mode 0o600),覆盖已有文件。 */\nfunction writeFeishuConfigFile(configPath: string, overrides: Record<string, unknown>): string {\n const base = {\n app_id: 'REPLACE_WITH_YOUR_FEISHU_APP_ID',\n app_secret: 'REPLACE_WITH_YOUR_FEISHU_APP_SECRET',\n allowed_chats: [] as string[],\n workspace_dir: join(configPath, '..', '..', 'feishu-use-workspace'),\n max_reply_chunk_length: 4000,\n }\n const merged = { ...base }\n for (const [k, v] of Object.entries(overrides)) {\n if (v !== undefined && v !== '') (merged as Record<string, unknown>)[k] = v\n }\n mkdirSync(join(configPath, '..'), { recursive: true })\n writeFileSync(configPath, JSON.stringify(merged, null, 2) + '\\n', { mode: 0o600 })\n return configPath\n}\n\n/** 从配置文件读取当前值;文件不存在时返回 undefined。 */\nfunction readConfigSafe(configPath: string): Record<string, unknown> | undefined {\n try {\n if (!existsSync(configPath)) return undefined\n return JSON.parse(readFileSync(configPath, 'utf8')) as Record<string, unknown>\n } catch {\n return undefined\n }\n}\n\n/** openSelect 的 Promise 包装:用户选择 → resolve(value),Esc/取消 → resolve(undefined)。 */\nfunction promiseSelect(\n ctx: CliContext,\n opts: { title: string; options: Array<{ label: string; value: string; detail?: string }> },\n): Promise<string | undefined> {\n return new Promise((resolve) => {\n ctx.tui.modal.openModal({\n kind: 'select',\n ...opts,\n onSelect: (v) => resolve(v),\n onCancel: () => resolve(undefined),\n })\n })\n}\n\n/** openConfirm 的 Promise 包装:确认 → resolve(true),取消 → resolve(false)。 */\nfunction promiseConfirm(ctx: CliContext, title: string, message: string | string[]): Promise<boolean> {\n return new Promise((resolve) => {\n ctx.tui.modal.openModal({\n kind: 'confirm',\n title,\n message,\n onConfirm: () => resolve(true),\n onCancel: () => resolve(false),\n })\n })\n}\n\n/**\n * 启动 `registerApp` 子进程并等待结果。\n *\n * 子进程 stdout 输出 JSON `{ client_id, client_secret }` 表示成功;\n * 超时/崩溃/非零退出码 → resolve(undefined)。\n *\n * `pluginDir` 是 feishu-use 插件安装目录(含 node_modules/@larksuiteoapi/node-sdk)。\n *\n * `onQrCodeUrl`(RFC-134 §8 F1 修复):QR 码 URL 由 SDK `onQRCodeReady` 回调在子进程侧\n * 产生,经 `QRCODE_URL::<json>` 前缀行写入 stderr——本函数解析该前缀行并回调给调用方展示,\n * 修复此前\"stderr 从未被读取、URL 被静默丢弃\"的缺陷(用户选择扫码后永远看不到二维码)。\n */\nfunction runRegisterApp(\n pluginDir: string,\n timeoutMs = 5 * 60 * 1000,\n onQrCodeUrl?: (info: { url: string; expireIn: number }) => void,\n): Promise<{ client_id: string; client_secret: string } | undefined> {\n return new Promise((resolve) => {\n const scriptPath = join(pluginDir, 'scripts', 'register-app.mjs')\n if (!existsSync(scriptPath)) {\n resolve(undefined)\n return\n }\n\n const child = spawn('node', [scriptPath], {\n cwd: pluginDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n timeout: timeoutMs,\n env: { ...process.env },\n })\n\n let stdout = ''\n let stderr = ''\n let qrEmitted = false\n child.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString()\n })\n child.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString()\n if (qrEmitted || !onQrCodeUrl) return\n const line = stderr.split('\\n').find((l) => l.startsWith('QRCODE_URL::'))\n if (!line) return\n try {\n const info = JSON.parse(line.slice('QRCODE_URL::'.length)) as { url: string; expireIn: number }\n if (info.url) {\n qrEmitted = true\n onQrCodeUrl(info)\n }\n } catch {\n /* 前缀行畸形,忽略,等待后续 data 事件或直到子进程结束都拿不到 URL */\n }\n })\n\n child.on('error', () => resolve(undefined))\n child.on('close', (code) => {\n if (code !== 0) return resolve(undefined)\n try {\n const result = JSON.parse(stdout.trim().split('\\n').pop()!) as {\n client_id: string\n client_secret: string\n }\n if (result.client_id && result.client_secret) {\n resolve(result)\n return\n }\n } catch {\n /* fall through */\n }\n resolve(undefined)\n })\n })\n}\n\n/**\n * 用 app_id/app_secret 调用 `bot/v3/info` 验证凭据并获取 bot 身份。\n *\n * 子进程执行插件自带脚本 `scripts/verify-bot.mjs`(与 `runRegisterApp` 调用\n * `register-app.mjs` 同模式,终局架构 review 2026-07-20 下沉)——宿主 CLI 只负责\n * spawn + 传参 + 解析结果,不内联飞书 SDK 的具体调用细节(`bot/v3/info` 端点/Client\n * 构造方式),保持 RFC-134 D2 的架构隔离:`packages/cli` 对插件内部实现零认知。\n * 失败(网络不通/凭据错误/权限不足/脚本缺失)返回 undefined。\n */\nfunction verifyBotIdentity(\n pluginDir: string,\n appId: string,\n appSecret: string,\n): Promise<{ openId: string; name: string } | undefined> {\n return new Promise((resolve) => {\n const scriptPath = join(pluginDir, 'scripts', 'verify-bot.mjs')\n if (!existsSync(scriptPath)) {\n resolve(undefined)\n return\n }\n\n const child = spawn('node', [scriptPath], {\n cwd: pluginDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n timeout: 15_000,\n env: { ...process.env, FEISHU_VERIFY_APP_ID: appId, FEISHU_VERIFY_APP_SECRET: appSecret },\n })\n\n let stdout = ''\n child.stdout.on('data', (chunk: Buffer) => {\n stdout += chunk.toString()\n })\n\n child.on('error', () => resolve(undefined))\n child.on('close', (code) => {\n if (code !== 0) return resolve(undefined)\n try {\n const r = JSON.parse(stdout.trim()) as { openId: string; name: string }\n resolve(r)\n } catch {\n resolve(undefined)\n }\n })\n })\n}\n\n/** 脱敏 App ID:前 8 字符 + *** + 后 4 字符。 */\nfunction maskAppId(appId: string): string {\n if (appId.length <= 12) return appId.slice(0, 4) + '***'\n return appId.slice(0, 8) + '***' + appId.slice(-4)\n}\n\n/**\n * feishu-use 交互式配置向导主入口(RFC-134 M1)。\n *\n * 在 TUI 内调用(需已有 TUI 上下文),通过 async/await 链式编排对话框。\n * 外部调用方负责提供 configPath 和 pluginDir。\n *\n * @param ctx CliContext(需 TUI 可用)\n * @param configPath 配置文件的目标路径(如 `<cwd>/.otto/feishu-use.json`)\n * @param pluginDir feishu-use 插件的安装目录(含 node_modules)\n * @param existingConfig 已有配置(存在时为重配置模式,展示当前值)\n */\nexport async function runFeishuSetupWizard(\n ctx: CliContext,\n configPath: string,\n pluginDir: string,\n existingConfig?: Record<string, unknown>,\n): Promise<FeishuSetupResult | undefined> {\n // ── 重配置模式:展示当前值 + 确认覆盖 ──\n if (existingConfig?.app_id) {\n const currentAppId = String(existingConfig.app_id)\n const lines = [\n `App ID: ${maskAppId(currentAppId)}`,\n existingConfig.allowed_chats\n ? `allowed_chats: ${(existingConfig.allowed_chats as string[]).length} 个`\n : 'allowed_chats: 空(拒绝所有)',\n `配置路径: ${configPath}`,\n ]\n const confirmed = await promiseConfirm(ctx, 'feishu-use 重配置', ['当前配置:', '', ...lines, '', '确定要重新配置吗?当前凭据将被覆盖。'])\n if (!confirmed) return undefined\n }\n\n // ── Step 1: 选择配置方式 ──\n const method = await promiseSelect(ctx, {\n title: 'feishu-use 配置',\n options: [\n { label: '扫码自动创建飞书应用(推荐)', value: 'qr', detail: '飞书 App 扫码确认后自动获取凭据' },\n { label: '手动输入 App ID / App Secret', value: 'manual', detail: '已有飞书自建应用,直接填入凭据' },\n ],\n })\n if (!method) return undefined // user cancelled\n\n let appId = ''\n let appSecret = ''\n let allowedChats: string[] = []\n let trustedChats: string[] = []\n\n // ── Step 2a: QR 码路径 ──\n if (method === 'qr') {\n ctx.tui.info.showToast('plugin-feishu-use', '正在生成飞书应用注册二维码,请稍候…')\n\n const result = await runRegisterApp(pluginDir, 5 * 60 * 1000, (info) => {\n // RFC-134 §8 F1 修复:QR URL 必须展示给用户才能完成扫码,此前写入 stderr 后\n // 从未被读取,用户永远看不到二维码。用 pushMessage(非 toast)展示——toast 会\n // 在几秒后自动消失,而用户需要足够时间打开飞书 App 扫码。\n const expireMinutes = Math.round(info.expireIn / 60)\n ctx.tui.messages.pushMessage({\n role: 'assistant',\n content: [{\n type: 'text',\n text: `feishu-use:请在飞书 App 中打开以下链接扫码确认创建应用(${expireMinutes} 分钟内有效):\\n${info.url}`,\n }],\n })\n })\n if (!result) {\n // 超时或失败 → 回退到手动输入\n const retry = await promiseConfirm(ctx, 'plugin-feishu-use', '扫码注册失败(超时或网络错误)。是否改为手动输入凭据?')\n if (!retry) return undefined\n // 继续执行 manual 路径(故意 fall-through)\n } else {\n appId = result.client_id\n appSecret = result.client_secret\n ctx.tui.info.showToast('plugin-feishu-use', '扫码注册成功!凭据已自动填充。')\n }\n }\n\n // ── Step 2b: 手动输入路径(或 QR 失败后回退) ──\n if (!appId) {\n const hintId = existingConfig?.app_id ? `(当前: ${maskAppId(String(existingConfig.app_id))},留空保留原值)` : ''\n const enteredId = await ctx.tui.modal.openModal({\n kind: 'input',\n title: '飞书 App ID',\n placeholder: `cli_xxxxxxxxxxxx ${hintId}`,\n description: [],\n })\n if (enteredId === null) return undefined\n appId = enteredId || String(existingConfig?.app_id ?? '')\n\n const enteredSecret = await ctx.tui.modal.openModal({\n kind: 'input',\n title: '飞书 App Secret',\n mask: true,\n description: existingConfig?.app_secret ? ['留空保留当前 Secret'] : [],\n })\n if (enteredSecret === null) return undefined\n appSecret = enteredSecret || String(existingConfig?.app_secret ?? '')\n\n if (!appId || !appSecret) {\n ctx.tui.info.showToast('plugin-feishu-use', 'App ID 和 App Secret 不能为空,配置已取消。')\n return undefined\n }\n\n // 可选字段\n const chatsRaw = await ctx.tui.modal.openModal({\n kind: 'input',\n title: '允许的 chat_id(逗号分隔,留空=拒绝所有)',\n placeholder: existingConfig ? `当前: ${(existingConfig.allowed_chats as string[] | undefined)?.join(', ') ?? '空'}` : '',\n description: [],\n })\n if (chatsRaw === null) return undefined\n if (chatsRaw) {\n allowedChats = chatsRaw.split(',').map(s => s.trim()).filter(Boolean)\n } else if (existingConfig?.allowed_chats) {\n allowedChats = existingConfig.allowed_chats as string[]\n }\n\n const trustedRaw = await ctx.tui.modal.openModal({\n kind: 'input',\n title: '可信 chat_id(逗号分隔,留空=仅只读)',\n placeholder: existingConfig ? `当前: ${(existingConfig.trusted_chats as string[] | undefined)?.join(', ') ?? '空'}` : '',\n description: [],\n })\n if (trustedRaw === null) return undefined\n if (trustedRaw) {\n trustedChats = trustedRaw.split(',').map(s => s.trim()).filter(Boolean)\n } else if (existingConfig?.trusted_chats) {\n trustedChats = existingConfig.trusted_chats as string[]\n }\n }\n\n // ── Step 3: 写入配置 ──\n const workspaceDir = existingConfig?.workspace_dir\n ? String(existingConfig.workspace_dir)\n : join(pluginDir, '..', '..', 'feishu-use-workspace')\n writeFeishuConfigFile(configPath, {\n app_id: appId,\n app_secret: appSecret,\n allowed_chats: allowedChats,\n trusted_chats: trustedChats,\n workspace_dir: workspaceDir,\n })\n\n ctx.tui.info.showToast('plugin-feishu-use', `配置已写入 ${configPath}`)\n\n // ── Step 4: 验证 bot 身份 ──\n const bot = await verifyBotIdentity(pluginDir, appId, appSecret)\n if (bot) {\n ctx.tui.info.showToast('plugin-feishu-use', `Bot 身份验证成功:${bot.name} (${bot.openId})`)\n } else {\n ctx.tui.messages.pushMessage({\n role: 'command_echo',\n command: '/feishu setup',\n status: 'error',\n summary: 'bot 身份验证失败(凭据不正确或网络不可达)',\n detail: '请稍后用 `otto feishu config set` 修正凭据,或手动编辑配置文件。',\n })\n }\n\n return {\n appId,\n botOpenId: bot?.openId,\n botName: bot?.name,\n configPath,\n success: !!bot,\n }\n}\n\n/**\n * 给 runFeishuSetupWizard 准备参数的外层封装:计算 configPath 和 pluginDir。\n *\n * @returns setup 结果,或 undefined(用户取消)\n */\nexport async function launchFeishuSetup(\n ctx: CliContext,\n): Promise<FeishuSetupResult | undefined> {\n const ws = ctx.app.workspaceDir ?? process.cwd()\n const configPath = resolveConfigPath(ws)\n\n // 找到 feishu-use 的安装目录(插件目录 = 含 otto-plugin.json 的目录)\n const allPlugins = discoverPluginsWithBundled({ cwd: ws, homedir: homedir() })\n const feishuPlugin = allPlugins.find(p => p.id === 'plugin-feishu-use')\n if (!feishuPlugin) {\n ctx.tui.info.showToast('plugin-feishu-use', 'feishu-use 插件尚未安装,请先在 `/model` 安装入口安装 feishu-use。')\n return undefined\n }\n\n const pluginDir = feishuPlugin.dir\n const existing = readConfigSafe(configPath)\n\n return runFeishuSetupWizard(ctx, configPath, pluginDir, existing)\n}\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
2
  const e={"no-provider-plugin":{summary:`No provider plugin detected.`,recoveryAction:"Run `otto` and follow the setup prompt, or `otto extension install <provider>` directly."},"no-credential":{summary:`Provider plugin found, but no credential is registered.`,recoveryAction:"Run `otto` and connect your account, or `otto auth login <provider>`."},"looks-configured":{summary:`Provider and credential look configured (not a readiness guarantee — model usability is verified at runtime).`,recoveryAction:"Run `otto` in a project to start."}};function t(t){let n;return n=t.providerPluginDiscovered?t.hasAnyCredential?`looks-configured`:`no-credential`:`no-provider-plugin`,{status:n,...e[n]}}export{t as deriveDoctorFtueGuidance};
3
- //# sourceMappingURL=ftue-doctor-recovery-DeAf8jVo.js.map
3
+ //# sourceMappingURL=ftue-doctor-recovery-8FeDBFOc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ftue-doctor-recovery-DeAf8jVo.js","names":[],"sources":["../src/commands/ftue/ftue-doctor-recovery.ts"],"sourcesContent":["/**\n * ftue-doctor-recovery.ts — RFC-326 M6-01:`otto doctor` 的 FTUE 环境自检 + recovery\n * action 映射。\n *\n * 与 `ftue-snapshot.ts`(TUI 运行时权威判定,5 阶段 `provider→authentication→model→\n * ready→first-prompt`)的关系:**本模块不是它的替代品,是它的轻量诊断变体**。\n *\n * 为什么不能直接复用 `deriveFtueSnapshot`:该函数的 `model` 阶段判据依赖\n * `usableModelIds`——必须先构造真实 `ModelRegistry` 并跑完整 `createModelUsabilityGate`\n * (逐模型探查凭据+订阅风险),这正是 `doctor.ts` 头部已声明的设计约束(RFC-150 D3:\n * doctor 是轻量诊断命令,不承担重依赖/不构造完整 App)。构造完整 App 来回答\"配置好了\n * 没有\"违反了这条约束本身。\n *\n * 因此本模块只收集三个**廉价**事实(无需 App/ModelRegistry):\n * 1. 是否发现任一声明 `provider` capability 的插件(`discoverPluginsWithBundled` 已在\n * doctor 的 `collectPlugins()` 跑过,直接复用其产出,零额外扫描);\n * 2. 是否有任一已登记凭据(`AuthStore.listProviders()`,只读本地 auth.json + env,\n * 不发网络请求、不做 OAuth 刷新,见 `getAuthSource` 头注释);\n * 3. 是否已发出过第一条 prompt(`first_prompt_submitted_at` 是否已写入,读 settings 一个\n * 字段)。\n *\n * 代价:**判据比 TUI 运行时权威判定更宽松**——\"有凭据条目\"不等于\"凭据仍然有效\",\n * 更不等于\"至少一个模型可用\"(那需要逐模型探查订阅 429 风险等,doctor 明确不做)。\n * 这是刻意的取舍:doctor 给出的是\"大方向卡在哪一步\"的诊断提示,不是可发 prompt 的\n * 权威裁决——用户装了 provider、连了凭据后,doctor 会显示\"看起来已配置\",但真正的\n * ready 判定仍然只由 TUI 运行时的 `FtueController` 给出。字段命名与文案措辞需体现\n * 这种不确定性(\"looks configured\" 而非 \"ready\")。\n */\n\n/** doctor 能廉价收集到的三个 FTUE 事实——均为只读本地探查,零网络请求。 */\nexport interface DoctorFtueFacts {\n /** 是否发现任一声明 `provider` capability 的插件(builtin/project/repository/user 任一层)。 */\n providerPluginDiscovered: boolean\n /** 是否有任一已登记凭据(`AuthStore.listProviders().length > 0`)。 */\n hasAnyCredential: boolean\n /** 是否已发出过第一条 prompt(`first_prompt_submitted_at` 已写入)。 */\n firstPromptSubmitted: boolean\n}\n\n/** 廉价诊断阶段——刻意用与 `FtueStage` 不同的类型名,避免调用方误当作权威判定复用。 */\nexport type DoctorFtueStatus =\n | 'no-provider-plugin'\n | 'no-credential'\n | 'looks-configured'\n\nexport interface DoctorFtueGuidance {\n status: DoctorFtueStatus\n /** 面向终端用户的一行诊断文案(英文,doctor 全量输出是纯文本、无 i18n 依赖)。 */\n summary: string\n /** 推荐的下一步命令(纯文本,可直接复制执行)。 */\n recoveryAction: string\n}\n\nconst GUIDANCE: Record<DoctorFtueStatus, Omit<DoctorFtueGuidance, 'status'>> = {\n 'no-provider-plugin': {\n summary: 'No provider plugin detected.',\n recoveryAction: 'Run `otto` and follow the setup prompt, or `otto extension install <provider>` directly.',\n },\n 'no-credential': {\n summary: 'Provider plugin found, but no credential is registered.',\n recoveryAction: 'Run `otto` and connect your account, or `otto auth login <provider>`.',\n },\n 'looks-configured': {\n summary: 'Provider and credential look configured (not a readiness guarantee — model usability is verified at runtime).',\n recoveryAction: 'Run `otto` in a project to start.',\n },\n}\n\n/**\n * 纯函数:由三个廉价事实推导诊断状态 + 建议动作。\n *\n * 判定顺序刻意与 `deriveStage`(ftue-snapshot.ts)的前两级保持一致(provider → 凭据),\n * 但到此为止——本模块不判定\"model\"/\"first-prompt\"两级,因为那需要真实可用性探查。\n * `firstPromptSubmitted` 入参目前只影响 `looks-configured` 分支的文案精细度预留,不\n * 参与状态判定本身(doctor 无法验证\"发过 prompt 时是否真的成功\",展示\"看起来已配置\"\n * 已是本模块能给出的诚实上限)。\n */\nexport function deriveDoctorFtueGuidance(facts: DoctorFtueFacts): DoctorFtueGuidance {\n let status: DoctorFtueStatus\n if (!facts.providerPluginDiscovered) {\n status = 'no-provider-plugin'\n } else if (!facts.hasAnyCredential) {\n status = 'no-credential'\n } else {\n status = 'looks-configured'\n }\n return { status, ...GUIDANCE[status] }\n}\n"],"mappings":";AAqDA,MAAM,EAAyE,CAC7E,qBAAsB,CACpB,QAAS,+BACT,eAAgB,2FACjB,CACD,gBAAiB,CACf,QAAS,0DACT,eAAgB,wEACjB,CACD,mBAAoB,CAClB,QAAS,gHACT,eAAgB,oCACjB,CACF,CAWD,SAAgB,EAAyB,EAA4C,CACnF,IAAI,EAQJ,MAPA,CACE,EADG,EAAM,yBAEC,EAAM,iBAGP,mBAFA,gBAFA,qBAMJ,CAAE,SAAQ,GAAG,EAAS,GAAS"}
1
+ {"version":3,"file":"ftue-doctor-recovery-8FeDBFOc.js","names":[],"sources":["../src/commands/ftue/ftue-doctor-recovery.ts"],"sourcesContent":["/**\n * ftue-doctor-recovery.ts — RFC-326 M6-01:`otto doctor` 的 FTUE 环境自检 + recovery\n * action 映射。\n *\n * 与 `ftue-snapshot.ts`(TUI 运行时权威判定,5 阶段 `provider→authentication→model→\n * ready→first-prompt`)的关系:**本模块不是它的替代品,是它的轻量诊断变体**。\n *\n * 为什么不能直接复用 `deriveFtueSnapshot`:该函数的 `model` 阶段判据依赖\n * `usableModelIds`——必须先构造真实 `ModelRegistry` 并跑完整 `createModelUsabilityGate`\n * (逐模型探查凭据+订阅风险),这正是 `doctor.ts` 头部已声明的设计约束(RFC-150 D3:\n * doctor 是轻量诊断命令,不承担重依赖/不构造完整 App)。构造完整 App 来回答\"配置好了\n * 没有\"违反了这条约束本身。\n *\n * 因此本模块只收集三个**廉价**事实(无需 App/ModelRegistry):\n * 1. 是否发现任一声明 `provider` capability 的插件(`discoverPluginsWithBundled` 已在\n * doctor 的 `collectPlugins()` 跑过,直接复用其产出,零额外扫描);\n * 2. 是否有任一已登记凭据(`AuthStore.listProviders()`,只读本地 auth.json + env,\n * 不发网络请求、不做 OAuth 刷新,见 `getAuthSource` 头注释);\n * 3. 是否已发出过第一条 prompt(`first_prompt_submitted_at` 是否已写入,读 settings 一个\n * 字段)。\n *\n * 代价:**判据比 TUI 运行时权威判定更宽松**——\"有凭据条目\"不等于\"凭据仍然有效\",\n * 更不等于\"至少一个模型可用\"(那需要逐模型探查订阅 429 风险等,doctor 明确不做)。\n * 这是刻意的取舍:doctor 给出的是\"大方向卡在哪一步\"的诊断提示,不是可发 prompt 的\n * 权威裁决——用户装了 provider、连了凭据后,doctor 会显示\"看起来已配置\",但真正的\n * ready 判定仍然只由 TUI 运行时的 `FtueController` 给出。字段命名与文案措辞需体现\n * 这种不确定性(\"looks configured\" 而非 \"ready\")。\n */\n\n/** doctor 能廉价收集到的三个 FTUE 事实——均为只读本地探查,零网络请求。 */\nexport interface DoctorFtueFacts {\n /** 是否发现任一声明 `provider` capability 的插件(builtin/project/repository/user 任一层)。 */\n providerPluginDiscovered: boolean\n /** 是否有任一已登记凭据(`AuthStore.listProviders().length > 0`)。 */\n hasAnyCredential: boolean\n /** 是否已发出过第一条 prompt(`first_prompt_submitted_at` 已写入)。 */\n firstPromptSubmitted: boolean\n}\n\n/** 廉价诊断阶段——刻意用与 `FtueStage` 不同的类型名,避免调用方误当作权威判定复用。 */\nexport type DoctorFtueStatus =\n | 'no-provider-plugin'\n | 'no-credential'\n | 'looks-configured'\n\nexport interface DoctorFtueGuidance {\n status: DoctorFtueStatus\n /** 面向终端用户的一行诊断文案(英文,doctor 全量输出是纯文本、无 i18n 依赖)。 */\n summary: string\n /** 推荐的下一步命令(纯文本,可直接复制执行)。 */\n recoveryAction: string\n}\n\nconst GUIDANCE: Record<DoctorFtueStatus, Omit<DoctorFtueGuidance, 'status'>> = {\n 'no-provider-plugin': {\n summary: 'No provider plugin detected.',\n recoveryAction: 'Run `otto` and follow the setup prompt, or `otto extension install <provider>` directly.',\n },\n 'no-credential': {\n summary: 'Provider plugin found, but no credential is registered.',\n recoveryAction: 'Run `otto` and connect your account, or `otto auth login <provider>`.',\n },\n 'looks-configured': {\n summary: 'Provider and credential look configured (not a readiness guarantee — model usability is verified at runtime).',\n recoveryAction: 'Run `otto` in a project to start.',\n },\n}\n\n/**\n * 纯函数:由三个廉价事实推导诊断状态 + 建议动作。\n *\n * 判定顺序刻意与 `deriveStage`(ftue-snapshot.ts)的前两级保持一致(provider → 凭据),\n * 但到此为止——本模块不判定\"model\"/\"first-prompt\"两级,因为那需要真实可用性探查。\n * `firstPromptSubmitted` 入参目前只影响 `looks-configured` 分支的文案精细度预留,不\n * 参与状态判定本身(doctor 无法验证\"发过 prompt 时是否真的成功\",展示\"看起来已配置\"\n * 已是本模块能给出的诚实上限)。\n */\nexport function deriveDoctorFtueGuidance(facts: DoctorFtueFacts): DoctorFtueGuidance {\n let status: DoctorFtueStatus\n if (!facts.providerPluginDiscovered) {\n status = 'no-provider-plugin'\n } else if (!facts.hasAnyCredential) {\n status = 'no-credential'\n } else {\n status = 'looks-configured'\n }\n return { status, ...GUIDANCE[status] }\n}\n"],"mappings":";AAqDA,MAAM,EAAyE,CAC7E,qBAAsB,CACpB,QAAS,+BACT,eAAgB,2FACjB,CACD,gBAAiB,CACf,QAAS,0DACT,eAAgB,wEACjB,CACD,mBAAoB,CAClB,QAAS,gHACT,eAAgB,oCACjB,CACF,CAWD,SAAgB,EAAyB,EAA4C,CACnF,IAAI,EAQJ,MAPA,CACE,EADG,EAAM,yBAEC,EAAM,iBAGP,mBAFA,gBAFA,qBAMJ,CAAE,SAAQ,GAAG,EAAS,GAAS"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/cli.ts"],"mappings":";;iBAoTsB,MAAA,CAAA,GAAU,OAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/cli.ts"],"mappings":";;iBA2TsB,MAAA,CAAA,GAAU,OAAA"}
package/dist/index.js CHANGED
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
- import{$ as e,A as t,B as n,C as r,D as i,E as a,F as o,G as s,H as c,I as l,J as u,K as d,L as f,M as p,N as m,O as h,P as g,Q as _,R as v,S as y,T as b,U as x,V as S,W as C,X as w,Y as ee,Z as T,_ as E,at as D,b as O,c as te,d as k,et as A,f as ne,i as j,it as M,j as N,k as P,l as F,m as I,n as re,nt as L,o as R,p as z,q as ie,r as B,rt as ae,s as V,t as oe,tt as se,u as H,v as ce,w as le,x as U,y as ue,z as W}from"./command-dispatcher-DhcLUPR5.js";import{t as de}from"./version-Eh8zZKgk.js";import{n as fe,t as pe}from"./parse-cli-3fWEIMWc.js";import{t as me}from"./discover-with-bundled-CF8qFP41.js";import{t as G}from"./create-host-app-BXQ8bU-B.js";import{n as he}from"./proxy-evg7ZvoD.js";import{r as K}from"./registry-BdCcwyGy.js";import{homedir as ge}from"node:os";import{execFile as _e,spawn as ve}from"node:child_process";import{SANDBOX_ESCALATION_MARKER as ye,apiCredentialId as be,buildPluginCliRegistry as xe,collectPluginThemePresets as Se,evaluatePluginTrust as Ce,evaluateWorkspaceTrustPrompt as we,expandCommandBody as Te,findPluginCliNameConflict as Ee,globalAgentJobRegistry as q,globalAgentObservability as J,globalProcessRegistry as Y,installEsbuildExitHook as De,installEsbuildSignalBridges as Oe,readTaskOutputTail as ke,resolvePluginCliBin as Ae,resolveSessionTitle as je,spawnPluginCli as Me,trustProject as Ne}from"@x-otto/coding";import{globalAgentJobRegistry as Pe,globalProcessRuntime as Fe,installExitReaper as Ie}from"@x-otto/runtime";import{buildAllowedEnv as Le,checkShellCommand as Re,createLogger as ze,markStartupPhase as Be,rankCandidates as X,setLogLevel as Ve,traceStartupPhase as He,traceStartupPhaseSync as Ue}from"@x-otto/shared";import{BUILD_ID as We,OTTO_HOME as Ge,OTTO_SESSIONS_DIR as Ke,SDK_VERSION as qe,flushEnvWarnings as Je,isShadowModeEnabled as Ye,loadUserIdentity as Xe}from"@x-otto/env";import{dirname as Ze,join as Z,resolve as Qe}from"node:path";import{existsSync as $e}from"node:fs";import{fileURLToPath as et}from"node:url";import{BASH_HISTFILE_SOURCE as tt,COMPACTING_SENTINEL as nt,FISH_HISTFILE_SOURCE as rt,ZSH_HISTFILE_SOURCE as it,createBuiltinThemeRegistry as at,entriesToCommands as ot,formatAgentDiagnosticsText as st,formatTranscriptText as ct,formatTurnTimeline as lt,i18next as Q,isUsingOverage as ut,observationLiveFields as dt,observationRow as ft,parseBashHistory as pt,parseFishHistory as mt,parseZshHistory as ht,promptParentWorkspaceChoice as gt,promptWorkspaceTrust as _t,setMarkdownThemeUserOverrides as vt,subagentEntryStatus as yt}from"@x-otto/tui";import{access as bt,mkdir as xt,readFile as St,readdir as Ct,rename as wt,stat as Tt,unlink as Et,writeFile as Dt}from"node:fs/promises";import{createModelUsabilityGate as Ot}from"@x-otto/ai";import{ScheduleRegistry as kt,SchedulerService as At,createLocalFireOwnership as jt,createRemoteFireOwnership as Mt,createRemoteScheduleStore as Nt,createScheduleStore as Pt,parseCron as Ft}from"@x-otto/schedule";import{SESSION_RESUME_WINDOW_MESSAGES as It,createProjectorState as Lt,projectSessionEvent as Rt,resolveChoiceAnswer as zt,resolveTextAnswer as Bt,sandboxBypassCommand as Vt,shouldShowPulseSurvey as Ht}from"@x-otto/session-contract";function Ut(e=process.stdout){if(process.env.OTTO_TUI_SCOPED_VIEWPORT===`0`&&process.env.OTTO_TUI_CLEAR_ON_EXIT!==`0`&&e.isTTY)try{e.write(`\x1B[2J\x1B[3J\x1B[H`)}catch{}}function Wt(e=process.stdout){if(!e.isTTY)return;let t=e=>{try{e()}catch{}};t(()=>{e.write(`\x1B[?1049l`)}),t(()=>{e.write(`\x1B[?25h`)}),t(()=>{e.write(`\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l`)}),t(()=>{process.stdin.isTTY&&typeof process.stdin.setRawMode==`function`&&process.stdin.setRawMode(!1)})}function Gt(e,t){return e||t}function Kt(e,t){return e===`pin`&&t?`unpin`:e}function qt(e,t){return e===`pause`&&t?`continue`:e}function Jt(e,t,n){let r=e.list().sort((e,t)=>e.name.localeCompare(t.name)),i=r.map(e=>` /${Kt(e.name,t)}${e.aliases?.length?` (${e.aliases.join(`, `)})`:``}`),a=Math.max(...i.map(e=>e.length)),o=[];for(let e=0;e<r.length;e++){let s=r[e],c=n[Kt(s.name,t)]??n[s.name]??s.description;o.push(`${i[e].padEnd(a)} — ${c}`)}return o.push(``,`Prefixes: !<cmd> run shell | @<file> read file`),o}function Yt(e,t,n,r,i=!1,a=!1){return e.list().filter(e=>e.name===`pause`?t||a:!0).map(e=>{let o=qt(Kt(e.name,i),a);return{name:o,description:r?.[o]??r?.[e.name]??e.description,disabled:t&&!n.has(e.name)&&e.name!==`abort`,sortKey:e.name,deprecated:e.deprecated}})}function Xt(e){for(let t of j)t.tuiHidden||t.envGate&&process.env[t.envGate]!==`1`||(e.has(t.name)&&e.unregister(t.name),e.register({name:t.name,description:t.description??t.name,aliases:t.aliases,deprecated:t.deprecated,type:`action`,source:`builtin`,execute:()=>``}))}function Zt(e){let{app:t,getTui:n}=e,r=[],i=()=>{for(let e of r)e();r=[]},a,o,s,c,l,u=()=>{a&&=(clearInterval(a),void 0),o&&=(q.retain(o,!1),void 0),l=void 0},d=()=>{s&&=(clearInterval(s),void 0),c&&=(J?.unpin(c),q.get(c)&&q.retain(c,!1),void 0)};return{clearBgSubs:i,stopBgOutputPoll:u,stopBgSubagentPoll:d,setBgUnsubs:e=>{r=e},handlers:{onBackgroundKill:e=>{if(q.get(e)){q.cancel(e);return}J.abort(e)||Y.kill(e)},onBackgroundApply:e=>{let r=n(),i=e=>r.messages.pushMessage({role:`assistant`,content:[{type:`text`,text:e}]}),a=t.agentJobs.apply(e);if(a.applied){let n=a.forbiddenZone?.length?Q.t(`cmd.bgForbiddenZone`,{count:a.forbiddenZone.length,files:a.forbiddenZone.join(`
2
+ import{$ as e,A as t,B as n,C as r,D as i,E as a,F as o,G as s,H as c,I as l,J as u,K as d,L as f,M as p,N as m,O as h,P as g,Q as _,R as v,S as y,T as b,U as x,V as S,W as C,X as w,Y as ee,Z as T,_ as E,at as D,b as O,c as te,d as k,et as A,f as ne,i as j,it as M,j as N,k as P,l as F,m as I,n as re,nt as L,o as R,p as z,q as ie,r as B,rt as ae,s as V,t as oe,tt as se,u as H,v as ce,w as le,x as U,y as ue,z as W}from"./command-dispatcher-Dxj41r5P.js";import{t as de}from"./version-BKPdYoHG.js";import{n as fe,t as pe}from"./parse-cli-BSJEQtBo.js";import{t as me}from"./discover-with-bundled-CF8qFP41.js";import{t as G}from"./create-host-app-BXQ8bU-B.js";import{n as he}from"./proxy-evg7ZvoD.js";import{r as K}from"./registry-BdCcwyGy.js";import{homedir as ge}from"node:os";import{execFile as _e,spawn as ve}from"node:child_process";import{SANDBOX_ESCALATION_MARKER as ye,apiCredentialId as be,buildPluginCliRegistry as xe,collectPluginThemePresets as Se,evaluatePluginTrust as Ce,evaluateWorkspaceTrustPrompt as we,expandCommandBody as Te,findPluginCliNameConflict as Ee,globalAgentJobRegistry as q,globalAgentObservability as J,globalProcessRegistry as Y,installEsbuildExitHook as De,installEsbuildSignalBridges as Oe,readTaskOutputTail as ke,resolvePluginCliBin as Ae,resolveSessionTitle as je,spawnPluginCli as Me,trustProject as Ne}from"@x-otto/coding";import{globalAgentJobRegistry as Pe,globalProcessRuntime as Fe,installExitReaper as Ie}from"@x-otto/runtime";import{buildAllowedEnv as Le,checkShellCommand as Re,createLogger as ze,markStartupPhase as Be,rankCandidates as X,setLogLevel as Ve,traceStartupPhase as He,traceStartupPhaseSync as Ue}from"@x-otto/shared";import{BUILD_ID as We,OTTO_HOME as Ge,OTTO_SESSIONS_DIR as Ke,SDK_VERSION as qe,flushEnvWarnings as Je,isShadowModeEnabled as Ye,loadUserIdentity as Xe}from"@x-otto/env";import{dirname as Ze,join as Z,resolve as Qe}from"node:path";import{existsSync as $e}from"node:fs";import{fileURLToPath as et}from"node:url";import{BASH_HISTFILE_SOURCE as tt,COMPACTING_SENTINEL as nt,FISH_HISTFILE_SOURCE as rt,ZSH_HISTFILE_SOURCE as it,createBuiltinThemeRegistry as at,entriesToCommands as ot,formatAgentDiagnosticsText as st,formatTranscriptText as ct,formatTurnTimeline as lt,i18next as Q,isUsingOverage as ut,observationLiveFields as dt,observationRow as ft,parseBashHistory as pt,parseFishHistory as mt,parseZshHistory as ht,promptParentWorkspaceChoice as gt,promptWorkspaceTrust as _t,setMarkdownThemeUserOverrides as vt,subagentEntryStatus as yt}from"@x-otto/tui";import{access as bt,mkdir as xt,readFile as St,readdir as Ct,rename as wt,stat as Tt,unlink as Et,writeFile as Dt}from"node:fs/promises";import{createModelUsabilityGate as Ot}from"@x-otto/ai";import{ScheduleRegistry as kt,SchedulerService as At,createLocalFireOwnership as jt,createRemoteFireOwnership as Mt,createRemoteScheduleStore as Nt,createScheduleStore as Pt,parseCron as Ft}from"@x-otto/schedule";import{SESSION_RESUME_WINDOW_MESSAGES as It,createProjectorState as Lt,projectSessionEvent as Rt,resolveChoiceAnswer as zt,resolveTextAnswer as Bt,sandboxBypassCommand as Vt,shouldShowPulseSurvey as Ht}from"@x-otto/session-contract";function Ut(e=process.stdout){if(process.env.OTTO_TUI_SCOPED_VIEWPORT===`0`&&process.env.OTTO_TUI_CLEAR_ON_EXIT!==`0`&&e.isTTY)try{e.write(`\x1B[2J\x1B[3J\x1B[H`)}catch{}}function Wt(e=process.stdout){if(!e.isTTY)return;let t=e=>{try{e()}catch{}};t(()=>{e.write(`\x1B[?1049l`)}),t(()=>{e.write(`\x1B[?25h`)}),t(()=>{e.write(`\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l`)}),t(()=>{process.stdin.isTTY&&typeof process.stdin.setRawMode==`function`&&process.stdin.setRawMode(!1)})}function Gt(e,t){return e||t}function Kt(e,t){return e===`pin`&&t?`unpin`:e}function qt(e,t){return e===`pause`&&t?`continue`:e}function Jt(e,t,n){let r=e.list().sort((e,t)=>e.name.localeCompare(t.name)),i=r.map(e=>` /${Kt(e.name,t)}${e.aliases?.length?` (${e.aliases.join(`, `)})`:``}`),a=Math.max(...i.map(e=>e.length)),o=[];for(let e=0;e<r.length;e++){let s=r[e],c=n[Kt(s.name,t)]??n[s.name]??s.description;o.push(`${i[e].padEnd(a)} — ${c}`)}return o.push(``,`Prefixes: !<cmd> run shell | @<file> read file`),o}function Yt(e,t,n,r,i=!1,a=!1){return e.list().filter(e=>e.name===`pause`?t||a:!0).map(e=>{let o=qt(Kt(e.name,i),a);return{name:o,description:r?.[o]??r?.[e.name]??e.description,disabled:t&&!n.has(e.name)&&e.name!==`abort`,sortKey:e.name,deprecated:e.deprecated}})}function Xt(e){for(let t of j)t.tuiHidden||t.envGate&&process.env[t.envGate]!==`1`||(e.has(t.name)&&e.unregister(t.name),e.register({name:t.name,description:t.description??t.name,aliases:t.aliases,deprecated:t.deprecated,type:`action`,source:`builtin`,execute:()=>``}))}function Zt(e){let{app:t,getTui:n}=e,r=[],i=()=>{for(let e of r)e();r=[]},a,o,s,c,l,u=()=>{a&&=(clearInterval(a),void 0),o&&=(q.retain(o,!1),void 0),l=void 0},d=()=>{s&&=(clearInterval(s),void 0),c&&=(J?.unpin(c),q.get(c)&&q.retain(c,!1),void 0)};return{clearBgSubs:i,stopBgOutputPoll:u,stopBgSubagentPoll:d,setBgUnsubs:e=>{r=e},handlers:{onBackgroundKill:e=>{if(q.get(e)){q.cancel(e);return}J.abort(e)||Y.kill(e)},onBackgroundApply:e=>{let r=n(),i=e=>r.messages.pushMessage({role:`assistant`,content:[{type:`text`,text:e}]}),a=t.agentJobs.apply(e);if(a.applied){let n=a.forbiddenZone?.length?Q.t(`cmd.bgForbiddenZone`,{count:a.forbiddenZone.length,files:a.forbiddenZone.join(`
3
3
  `),id:e}):``;i(Q.t(`cmd.bgJobApplied`,{id:e,message:a.message,zone:n})),a.capabilityTouched&&t.reloadCapabilities().then(e=>{r.plugins.setPluginRegistrations(t.getPluginRegistrations()),r.info.showToast(Q.t(`cmd.titleReload`),Q.t(`cmd.reloadDone`,{mcpTools:e.mcpTools,models:e.models,agents:e.agents,teams:e.teams}))},e=>i(Q.t(`cmd.bgAutoReloadFailed`,{msg:e instanceof Error?e.message:String(e)})))}else{let t=a.conflictPaths.length?Q.t(`cmd.bgConflictFiles`,{joined:a.conflictPaths.join(`
4
4
  `)}):``;i(Q.t(`cmd.bgJobIncomplete`,{id:e,status:a.status,message:a.message,conflicts:t}))}},onDelegateSupply:(e,n)=>{t.agentJobs.supply(e,n)},onBackgroundViewOutput:e=>{let t=n(),r=async()=>{let n=e=>{let n=`${e.status}|${e.text}|${e.responseText??``}|${e.diff??``}`;n!==l&&(l=n,t.stores.tasks.setBackgroundOutput(e))},r=q.get(e);if(r){let t=r.status===`running`||r.status===`needs_input`?`running`:r.status===`applied`?`exited`:r.status===`failed`?`failed`:`killed`,i=(r.status===`ready`||r.status===`applied`)&&r.diff?.trim()?r.diff:void 0;n({id:e,command:r.title,status:t,text:ke(r.outputPath,20),prompt:J.get(e)?.prompt,diff:i}),t!==`running`&&u();return}let i=J.get(e);if(i){let t=x(J.getMessages(e)??[]),r=J.getStreamingText(e),a=ct(t,r),o=Date.now(),s=st(ft(i),o),c=lt(J.getTurns(e),o),l=[s.length?s.join(`
5
5
  `):``,c.length?c.join(`
6
6
  `):``].filter(Boolean).join(`\n${`─`.repeat(40)}\n\n`),d=i.status===`done`?`exited`:i.status===`error`||i.status===`aborted`?`failed`:`running`;n({id:e,command:`@${i.agentName}`,status:d,text:a,messages:t,streamText:r,responseText:l,prompt:i.prompt}),d!==`running`&&u();return}let a=Y.get(e);if(!a){u(),t.stores.tasks.setBackgroundOutput(null);return}let o=a.status===`running`?`running`:a.status===`exited`?`exited`:`killed`,s=``;if(a.logPath)try{s=(await St(a.logPath,`utf-8`)).split(`
7
7
  `).slice(-20).join(`
8
- `).trimEnd()}catch{s=``}n({id:e,command:a.command,status:o,text:s}),o!==`running`&&u()};u(),q.get(e)&&(q.retain(e,!0),o=e),a=setInterval(()=>{r()},500),r()},onBackgroundOutputClose:()=>{u()},onBackgroundSwitch:e=>{let t=n();d();let r=()=>{let n=J?.getMessages(e),r=J?.get(e),i=r?.agentName??``,a=q.get(e);a&&(i=a.title||i);let o=n?x(n):[],s=J?.getTurns(e),c=J?.getStreamingText(e),l=Date.now(),u={id:e,title:i,messages:o,status:a?.status??`running`,diagnostics:r?st(ft(r),l):[],timeline:s?lt(s,l):[],streamText:c};t.panes.switchToSubagentContext(u)};J?.pin(e),q.get(e)&&q.retain(e,!0),c=e,r(),s=setInterval(()=>{r()},500)},onBackgroundDelete:e=>{if(q.get(e)){q.remove(e);return}if(Y.get(e)){Y.remove(e);return}J.remove(e)},onSubagentExit:()=>{d(),n().panes.switchToSubagentContext(null)}}}}const Qt=ze(`@x-otto/cli:theme-preset-wiring`);function $t(e,t){let n={kind:`extension`,extensionId:t.pluginId};return e.register(n,{localId:t.localId,label:t.label,appearance:t.appearance,colors:t.colors,markdown:t.markdown})}function en(e,t){let n=[];for(let r of t)try{n.push($t(e,r))}catch(e){Qt.warn({pluginId:r.pluginId,localId:r.localId,err:String(e)},`theme preset registration failed, skipped`)}return n}function tn(e){let t=at();return en(t,Se(e.activePlugins())),t}function nn(e){let t=e??et(import.meta.url);t=Ze(t);let n=t===`/`?t:`/`;for(;t!==n;){try{if($e(t+`/.git`))return t}catch{}t=Ze(t)}try{if($e(n+`/.git`))return n}catch{}}var rn=class{repoRoot;currentBuildId;checkIntervalMs;onStale;logger;lastNotifiedBuildId=void 0;disposed=!1;timer;activeChild;constructor(e){this.repoRoot=e.repoRoot,this.currentBuildId=e.currentBuildId,this.checkIntervalMs=e.checkIntervalMs??6e5,this.onStale=e.onStale,this.logger=e.logger}start(){this.disposed||this.scheduleNext()}dispose(){if(this.disposed=!0,this.timer&&=(clearTimeout(this.timer),void 0),this.activeChild){try{this.activeChild.kill()}catch{}this.activeChild=void 0}this.lastNotifiedBuildId=void 0}scheduleNext(){this.disposed||(this.timer=setTimeout(()=>{this.timer=void 0,this.performCheck().then(()=>{this.scheduleNext()})},this.checkIntervalMs),this.timer.unref())}performCheck(){return new Promise(e=>{if(this.disposed){e();return}let t=_e(`git`,[`rev-list`,`--count`,`HEAD`],{cwd:this.repoRoot,timeout:5e3},(t,n)=>{if(this.activeChild=void 0,t){this.logger?.warn({err:t instanceof Error?t.message:String(t)},`[stale-build-detector] git rev-list failed`),e();return}let r=n.trim(),i=parseInt(r,10);if(!Number.isFinite(i)){this.logger?.warn({raw:r},`[stale-build-detector] failed to parse git output as number`),e();return}if(i>this.currentBuildId&&i!==this.lastNotifiedBuildId){this.lastNotifiedBuildId=i;try{this.onStale?.(i)}catch(e){this.logger?.warn({err:e instanceof Error?e.message:String(e)},`[stale-build-detector] onStale callback threw`)}}e()});this.activeChild=t,t.on(`error`,()=>{this.activeChild=void 0})})}};function an(e,t,n){return e-t<50?`dedup`:n.shellRunning?`kill-shell`:n.busy?n.stopDialogOpen?`escalate-exit`:`open-stop-dialog`:n.idleCtrlCCount+1>=2?`exit-process`:`hint-exit`}function on(e){let{getTui:t,getSession:n,dispatchAbort:r,clearTodoLayers:i,markUserAborted:a,resetCtrlCCount:o,markRestartRequested:s,stopTui:c,isBusy:l}=e,u=null,d=()=>u!==null&&t()?.info.getCurrentPath()===`/dialog/confirm`,f=()=>{a(),o(),r(),i()},p=e=>{e&&s(),a(),o();try{r()}catch{}c()},m=e=>{if(e===`abort`)return{title:Q.t(`confirm.abortConfirmTitle`),message:Q.t(`confirm.abortConfirmMessage`),confirmLabel:Q.t(`common.abortButton`),extraLabel:Q.t(`common.pauseButton`),onConfirm:()=>{f(),t()?.info.showToast(Q.t(`cmd.titleAborted`),Q.t(`cmd.runAborted`))}};let n=e===`exit-restart`;return{title:n?Q.t(`confirm.exitRestartConfirmTitle`):Q.t(`confirm.exitConfirmTitle`),message:Q.t(`confirm.exitConfirmMessage`),confirmLabel:n?Q.t(`common.abortAndRestartButton`):Q.t(`common.abortAndExitButton`),extraLabel:void 0,onConfirm:()=>{p(n)}}},h=e=>{let r=t();if(!r)return;let i=m(e);u=e,r.modal.openModal({kind:`confirm`,title:i.title,message:i.message,confirmLabel:i.confirmLabel,confirmColor:`amber`,extraLabel:i.extraLabel,extraColor:`accent`,dangerous:!0,onConfirm:()=>{u=null,i.onConfirm()},onCancel:()=>{u=null},onExtra:i.extraLabel?()=>{u=null,n().pauseRun()?t()?.info.showToast(Q.t(`cmd.titlePaused`),Q.t(`cmd.runWillPauseAfterTurn`)):t()?.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`cmd.noRunningTaskToPause`))}:void 0})};return{requestStop:e=>{if(!t()){e===`abort`?f():p(e===`exit-restart`);return}if(e!==`abort`&&!l()){p(e===`exit-restart`);return}h(e)},isStopDialogOpen:d,escalateToExit:()=>{let e=t();!e||!d()||(h(`exit`),e.modal.resolveConfirm(!0))},abortNow:f}}var sn=class{entries=[];filePath;constructor(e,t=Z(Ge,`sessions`)){this.filePath=Z(t,`${e}.history.json`)}list(e){return this.entries.slice(-(e??100))}append(e){e.trim()&&(this.entries.push(e),this.entries.length>100&&(this.entries=this.entries.slice(-100)))}hydrate(e){this.entries=e.slice(-100)}async persist(){if(Ye())return;let e=JSON.stringify(this.entries,null,2),t=`${this.filePath}.tmp`;try{await xt(Ze(this.filePath),{recursive:!0}),await Dt(t,e,`utf-8`),await wt(t,this.filePath)}catch(e){throw await Et(t).catch(()=>{}),e}}async load(){try{let e=await St(this.filePath,`utf-8`),t=JSON.parse(e);return Array.isArray(t)&&t.every(e=>typeof e==`string`)?(this.entries=t.slice(-100),this.entries):[]}catch{return[]}}};const cn={[it]:e=>ht(e),[tt]:e=>pt(e),[rt]:e=>mt(e)};function ln(){let e=process.env.SHELL??``,t=ge(),n=process.env.HISTFILE;return e.includes(`fish`)?[{id:rt,path:Z(t,`.local/share/fish/fish_history`)},{id:rt,path:Z(t,`.config/fish/fish_history`)}]:e.includes(`bash`)?[{id:tt,path:n?.startsWith(`~`)?Z(t,n.slice(2)):n??Z(t,`.bash_history`)}]:e.includes(`zsh`)||!e?[{id:it,path:n?.startsWith(`~`)?Z(t,n.slice(2)):n??Z(t,`.zsh_history`)}]:[]}function un(e){let t=e?.sources?.filter(e=>e?.enabled!==!1&&!!e?.id&&!!e?.path);if(t&&t.length>0){let e=ge();return t.map(t=>({id:t.id,path:dn(t.path,e)}))}return ln()}function dn(e,t){return e.startsWith(`~/`)?Z(t,e.slice(2)):e===`~`?t:e}async function fn(e){try{return await bt(e),!0}catch{return!1}}async function pn(e,t){let n=cn[e.id];if(!n||!await fn(e.path))return[];try{return n(await St(e.path,`utf8`)).slice(-t)}catch{return[]}}async function mn(e){if(e?.enabled!==!0)return[];let t=e.maxEntries??2e3,n=un(e),r=new Set,i=[];for(let e of n){if(r.has(e.path))continue;r.add(e.path);let n=await pn(e,t);i.push(...n)}return i.slice(-t)}async function hn(e,t){let n=new sn(e.id);return{historyStore:n,inputHistory:await n.load().then(t=>{if(t.length>0)return t;let r=e.session.getInputHistory();return r&&r.length>0?(n.hydrate(r),n.persist().catch(()=>{}),e.session.setInputHistory([]),r):[]}),externalHistoryCommands:t?.enabled===!0?ot(await mn(t)):void 0}}async function gn(e,t,n){if(n){let n=t.settings.get(`model`);if(typeof n==`string`&&n&&e.model?.id!==n){let r=t.modelRegistry.find(n);r&&await t.providerRegistry.hasCredential(r.provider)&&(e.model=r,t.storage.memory?.reconfigure?.({contextWindow:r.contextWindow,maxOutput:r.maxOutputTokens}))}}{let n=t.settings.get(`thinking_level`),r=[`low`,`medium`,`high`,`xhigh`,`max`],i=n===`minimal`?`low`:n;typeof i==`string`&&r.includes(i)&&(e.thinkingLevel=i)}}async function _n(e,t){let n=`__otto_setup__`,r=e.settings.get(`permission_mode`);(r===void 0||r===`auto`)&&await e.settings.update({permission_mode:`confirm`}),e.modelRegistry.getAll().length===0&&e.modelRegistry.register({id:n,name:`Setup required`,provider:`otto`,api:`otto`,baseUrl:``,reasoning:!1,input:[`text`],contextWindow:32e3,maxOutputTokens:4e3});let i=t.continueSession?e.getSession(t.continueSession)??await e.sessionManager.restore(t.continueSession)??void 0:void 0,a=i?i.session.buildContext().messages.filter(e=>{let t=e.role;return t===`user`||t===`assistant`}).length:0,o={value:i?e.sessionManager.consumeCrashGap(i.id):void 0},s=t.continueSession?i?Q.t(`cmd.resumeRestored`,{idShort:t.continueSession.slice(0,8),count:a}):Q.t(`cmd.resumeNotFound`,{id:t.continueSession}):void 0,c=!!(t.continueSession&&i),l=!!(t.model||e.settings.get(`model`)||e.settings.get(`model_slots`)?.default),u={skip:!1},d=await e.hydrateModelCache().catch(()=>new Set),f=e.modelRegistry.getAll().every(e=>e.id===n),p=f?!1:l,m=e.modelRegistry.getAll().find(e=>e.id!==n)??e.modelRegistry.getAll()[0],h=i??await e.createSession({interactive:!0,retryAccelerate:u,...p?{}:{model:m}});await gn(h,e,!!i);let g=p||c,_={get value(){return g},set value(e){g=e}},v={models:e.modelRegistry.getAll().filter(e=>e.id!==n).map(e=>({id:e.id,name:e.name,provider:e.provider,api:e.api,strengths:e.strengths??[],contextWindow:e.contextWindow})),availableModelIds:new Set([...d,...e.getSessionAvailableModels(h.id)]),wasUnconfigured:!1};v.wasUnconfigured=v.availableModelIds.size===0;let y=()=>e.setSessionAvailableModels(h.id,[...v.availableModelIds]);y();let b=new H(k({modelRegistry:e.modelRegistry,authStore:e.authStore,settings:e.settings,selectedModelId:()=>h.model?.id,isModelUsable:Ot(e.authStore,`delegation`),isModelUsableInMainSession:Ot(e.authStore,`main-session`)})),x,S={get value(){return x},set value(e){x=e}},C=async t=>{let r=await e.refreshModels().catch(()=>[]);v.models=e.modelRegistry.getAll().filter(e=>e.id!==n).map(e=>({id:e.id,name:e.name,provider:e.provider,api:e.api,strengths:e.strengths??[],contextWindow:e.contextWindow}));for(let e of r)if(e.status===`ok`)for(let t of e.availableIds??[])v.availableModelIds.add(t);v.models.length>0&&e.modelRegistry.getAll().some(e=>e.id===n)&&e.modelRegistry.unregister(n),y();let i=v.availableModelIds.size===0,a=S.value;a?.stores?.tasks?.setNeedsSetup?.(i);let o=await b.refresh().catch(()=>null);if(o&&a?.stores?.tasks?.setFtueStage?.(o.stage),v.wasUnconfigured&&!i&&(v.wasUnconfigured=!1,a?.info?.showToast?.(Q.t(`cmd.titleSetupReady`),Q.t(`cmd.setupReadyMessage`))),t){let e=r.filter(e=>e.status===`ok`);t(e.length>0?Q.t(`cmd.modelsRefreshed`,{summary:e.map(e=>`${e.provider} ${e.total}`).join(` · `)}):Q.t(`cmd.modelsRefreshedEmpty`))}};return C(),{session:h,startupCrashGapRef:o,resumedNote:s,modelReadyRef:_,registryOnlyPlaceholder:f,firstRealModel:m,modelRefreshState:v,persistAvailable:y,ftueController:b,refreshModelsNow:C,tuiRefBox:S,SETUP_PLACEHOLDER_ID:n,continuedExisting:c,retryAccelerate:u,resumed:i,convoCount:a}}function vn(e){let t=[],n=0,r=``,i=()=>{r&&=(t.push(r),``)};for(;n<e.length;){let t=e[n];if(t===` `||t===` `){i(),n++;continue}if(t===`\\`){n++,n<e.length&&(r+=e[n]),n++;continue}if(t===`"`){n++;let t=yn(e,n,`"`);r+=t.value,n=t.next;continue}if(t===`'`){n++;let t=yn(e,n,`'`,!1);r+=t.value,n=t.next;continue}r+=t,n++}return i(),{tokens:t}}function yn(e,t,n,r=!0){let i=``,a=t;for(;a<e.length;){let t=e[a];if(r&&t===`\\`){a++,a<e.length&&(i+=e[a]),a++;continue}if(t===n)return a++,{value:i,next:a};i+=t,a++}return{value:i,next:a}}function bn(e){let t=e.trim();if(!t.startsWith(`/`)||t===`/`||t.startsWith(`//`))return{isCommand:!1,text:t};let{tokens:n}=vn(t.slice(1));if(n.length===0)return{isCommand:!1,text:t};let[r,...i]=n;return{isCommand:!0,command:r,args:i}}async function xn(e,t){let n=e;for(;n.type===`response`&&n.endReason===`max-tool-turns`&&n.notice;){if(!await t.askBudgetContinue()){t.onBudgetStopped();return}t.beforeContinuationTurn();let e=await t.runTurn(`Continue with the remaining work until the task is complete.`);if(t.onTurnResult(e)===`exit`)return;n=e}}const Sn=[{extensionId:`plugin-browser-use`,reasonKey:`capability.reasonWebApp`,detect:async e=>{let t=await e.packageDependencyNames();return[`react`,`vue`,`next`,`nuxt`,`svelte`,`vite`,`@angular/core`,`express`,`koa`,`fastify`].some(e=>t.has(e))?!0:e.hasFile(`index.html`)}},{extensionId:`plugin-mobile-use`,reasonKey:`capability.reasonMobile`,detect:async e=>{if(await e.hasFile(`AndroidManifest.xml`)||await e.hasFile(`build.gradle`)||await e.hasFile(`build.gradle.kts`)||await e.hasFile(`Info.plist`)||await e.hasFile(`Podfile`))return!0;let t=await e.packageDependencyNames();return t.has(`react-native`)||t.has(`expo`)}},{extensionId:`plugin-schedule`,reasonKey:`capability.reasonSchedule`,detect:async e=>{if(await e.hasFile(`crontab`))return!0;let t=await e.packageDependencyNames();return t.has(`node-cron`)||t.has(`node-schedule`)||t.has(`agenda`)}}];async function Cn(e,t,n=Sn){let r=[];for(let i of n){if(t.has(i.extensionId))continue;let n=!1;try{n=await i.detect(e)}catch{n=!1}n&&r.push({extensionId:i.extensionId,reasonKey:i.reasonKey})}return r}function wn(e,t,n,r){return{ts:r?.ts??Date.now(),sessionId:n,...r?.turn===void 0?{}:{turn:r.turn},kind:`lifecycle`,node:e,payload:t}}function Tn(e){let t=new Map;if(e?.role===`assistant`&&Array.isArray(e.content))for(let n of e.content)n.type===`tool_call`&&t.set(n.id,n);return t}async function En(e,t,n){let r,i=new Set,a=new Map,o=new Set,c=new Map;if(n){let n=await e.loadTailEntries(t,It);r=n.length>0?n[0].seq:0;for(let e of n)e.type===`message`&&i.add(e.seq)}else r=await e.getEntryCount(t);return{async loadEarlier(n=500){if(r<=0)return null;let l=await e.loadEntriesBefore(t,r,n);if(l.length===0)return null;let u=new Map,d=new Set;for(let e of l){if(e.type!==`message`)continue;let t=e.data;if(t?.role===`assistant`)for(let[e,n]of Tn(t))u.set(e,n);else t?.role===`tool_result`&&typeof t.toolCallId==`string`&&d.add(t.toolCallId)}let f=[],p=(e,t)=>({...e,id:`hist-${t}`,seq:t});for(let e of l){if(e.type===`clear`){r=0,f.length=0;continue}if(e.type!==`message`||i.has(e.seq))continue;let t=e.data;if(!t||typeof t.role!=`string`||t.internal)continue;if(t.role===`tool_result`){let n=a.get(t.toolCallId??``)??u.get(t.toolCallId??``);if(n){let r=n.arguments??{};f.push(p({role:`tool`,name:t.toolName||n.name||`tool`,args:C(r),argsObj:r,result:s(t.content),isError:t.isError},e.seq)),o.add(t.toolCallId)}else c.set(t.toolCallId,{toolName:t.toolName,content:t.content,isError:t.isError});continue}if(t.role===`assistant`){let n=Tn(t);if(n.size>0){let r=new Set([...d,...o,...c.keys()]),i=x([t],{resolvedIds:r});for(let t of i)f.push(p(t,e.seq));for(let[t,r]of n){if(d.has(t))continue;let n=c.get(t);if(n){c.delete(t);let i=r.arguments??{};f.push(p({role:`tool`,name:r.name,args:C(i),argsObj:i,result:s(n.content),isError:n.isError??!1},e.seq))}}continue}}let n=x([t]);for(let t of n)f.push(p(t,e.seq))}for(let[e,t]of u)a.set(e,t);return r>0&&(r=l[0].seq),f.length>0?f:null}}}function Dn(e){let{app:t,getTui:n,getTuiRef:r,getSession:i,getCliCtx:a,historyStore:o}=e;return{onCyclePermissionMode:()=>{let e=n(),r=ee(t.getPermissionMode());e.stores.tasks.setPermissionMode(r),e.info.showToast(Q.t(`cmd.titlePermission`),Q.t(`pref.permModeSwitched`,{label:Q.t(`pref.permModeLabel`,{context:r})})),t.setPermissionMode(r)},onHistoryPush:t=>{try{o.hydrate([...t]),o.persist().catch(()=>{})}catch{}e.getPasteBinder?.()?.save(i().id)},onDraftSave:e=>{let n=i(),a=n.session.getDrafts()??[],o=f(void 0,e,a),s=l([...a,o]);n.session.setDrafts(s),t.sessionManager.save(n.id).catch(()=>{}),r()?.stores.tasks.setDrafts(v(s))},onDraftDelete:e=>{let n=i(),a=(n.session.getDrafts()??[]).filter(t=>t.id!==e);n.session.setDrafts(a),t.sessionManager.save(n.id).catch(()=>{}),r()?.stores.tasks.setDrafts(v(a))},onDraftDeleteMany:e=>{let n=i(),a=new Set(e),o=(n.session.getDrafts()??[]).filter(e=>!a.has(e.id));n.session.setDrafts(o),t.sessionManager.save(n.id).catch(()=>{}),r()?.stores.tasks.setDrafts(v(o))},onA2uiAction:(e,t,n)=>{R(`a2ui-action`,n?[e,t,JSON.stringify(n)]:[e,t],a())},onPerfRefresh:()=>{R(`status`,[`perf`],a())},onProxySubmitUrl:e=>{R(`preference`,[`proxy`,e],a())},onProxyToggleEnabled:()=>{R(`preference`,[`proxy`,t.settings.get(`proxy`)?.enabled===!1?`on`:`off`],a())},onProxyClear:()=>{R(`preference`,[`proxy`,`clear`],a())},onProxyTest:()=>{R(`preference`,[`proxy`,`test`],a())}}}function On(e){return{...kn(e),pluginSource:e.pluginSource,intervalSeconds:e.errorRetryIntervalSeconds}}function kn(e){let{msg:t,provider:n,authError:r,isRefreshFailed:i,unsupported:a,rateLimit:o,rateLimitInfo:s,getErrorRetryAttempt:c,incErrorRetryAttempt:l,errorRetryMax:u,retryQueued:d,resetAndRetry:f,cancelRetry:p,switchModelThenRetry:m,goToAuth:h}=e;if(s)return s.resetsAt===void 0?{reason:t,attempt:0,max:u,mode:`manual`,limitType:s.limitType,actions:[{kind:`switchModel`,label:Q.t(`error.switchModel`),run:m},{kind:`retryNow`,label:Q.t(`retry.nowButton`),run:d}],onExpired:()=>{},onCancel:p}:{reason:t,attempt:0,max:u,mode:`resetsAt`,resetsAt:s.resetsAt,limitType:s.limitType,actions:[{kind:`retryNow`,label:Q.t(`error.retryNow`),run:d},{kind:`switchModel`,label:Q.t(`error.switchModel`),run:m}],onExpired:d,onCancel:p};if(r)return{reason:i?Q.t(`cmd.authRefreshFailed`,{ps:n?` (${n})`:``,ls:n?` ${n}`:``}):Q.t(`cmd.authFailed`,{ps:n?` (${n})`:``,ls:n?` ${n}`:``}),attempt:c(),max:u,mode:`manual`,actions:[{kind:`login`,label:Q.t(`model.goToLoginButton`),run:h},{kind:`switchModel`,label:Q.t(`error.switchModel`),run:m},{kind:`retryNow`,label:Q.t(`retry.nowButton`),run:d}],onExpired:()=>{},onCancel:p};if(a)return{reason:Q.t(`cmd.modelNotSupported`),attempt:c(),max:u,mode:`manual`,actions:[{kind:`switchModel`,label:Q.t(`error.switchModel`),run:m},{kind:`retryNow`,label:Q.t(`retry.nowButton`),run:d}],onExpired:()=>{},onCancel:p};let g=l(),_=g>u;return{reason:o?Q.t(`cmd.rateLimitedRetriesExhausted`):Q.t(`cmd.requestFailed`,{msg:t}),attempt:Math.min(g,u),max:u,mode:`auto`,exhausted:_,actions:[{kind:`retryNow`,label:Q.t(`retry.nowButton`),run:_?f:d}],onExpired:_?()=>{}:d,onCancel:p}}function An(e){let{err:n}=e,r=n instanceof Error?n.message:String(n),i=n?.code===`AGENT_ABORTED`;if(!(e.submitState.userAborted||i)){let i=e.provider,a=n?.code,o=n?.pluginSource,{authError:s,isRefreshFailed:c,unsupported:l,rateLimit:u,pluginSource:d}=ie(r,a,o),f=e.rateLimitInfoRef.current;e.rateLimitInfoRef.current=void 0;let p=(()=>{let t=e.cliCtx,n=t?.app?.storage?.traceStore,r=t?.state?.session;if(!n||!r)return null;let i=r.session.getTurnCount();return{traceStore:n,sessionId:r.id,...i===void 0?{}:{turn:i}}})(),m=()=>{p&&P(p,{attempt:e.errorRetryAttemptRef.current+1,max:e.ERROR_RETRY_MAX,mode:f?`resetsAt`:s||l?`manual`:`auto`,reason:r.slice(0,120)}),e.retryModeRef.current=!0;let t=e.latestSubmittedPromptRef?.current,n=e.tui.engine.takeLastQueuedFollowUp?.(),i=t!=null&&t.text!==e.text,a=i?t.text:n?.text??e.text,o=i?t.mode:n?.mode??e.mode;a===e.text&&!i&&n==null&&e.retryLastRound?.()||queueMicrotask(()=>e.handleSubmit?.(a,o,`send`))};e.tui.engine.showErrorRetry(On({msg:r,provider:i,authError:s,isRefreshFailed:c,unsupported:l,rateLimit:u,rateLimitInfo:f,pluginSource:d,getErrorRetryAttempt:()=>e.errorRetryAttemptRef.current,incErrorRetryAttempt:()=>++e.errorRetryAttemptRef.current,errorRetryMax:e.ERROR_RETRY_MAX,errorRetryIntervalSeconds:e.ERROR_RETRY_INTERVAL_SECONDS,retryQueued:m,resetAndRetry:()=>{p&&t(p),e.errorRetryAttemptRef.current=0,m()},cancelRetry:()=>{p&&h(p,{attempt:e.errorRetryAttemptRef.current}),e.errorRetryAttemptRef.current=0},switchModelThenRetry:()=>{e.handleModel([],e.cliCtx,{afterSwitch:m})},goToAuth:()=>{e.handleProviderAuth([i??``].filter(Boolean),e.cliCtx)}}))}}function jn(e){return e.trim().length===0}function Mn(e){let{tui:t,app:n,submitState:r}=e;return(e,i=`!!`)=>{let a=e.trim();if(!a)return;let o=Re(a);if(!o.safe){t.info.showToast(Q.t(`cmd.titleShell`),Q.t(`cmd.dangerousBlocked`,{reason:o.reason})),t.messages.pushMessage({role:`assistant`,content:[{type:`text`,text:Q.t(`cmd.dangerousBlockedDetail`,{reason:o.reason,cmd:a})}]});return}t.messages.echoUserInput(`${i} ${a}`),t.shell.startShellExecution(a),r.shellChild=ve(a,{shell:!0,cwd:n.workspaceDir,stdio:[`ignore`,`pipe`,`pipe`],env:Le()}),Fe.registerChild({command:a,args:[],owner:{type:`cli-shell`,id:`!!`},category:`shell`,lifecycle:`evictable`,cwd:n.workspaceDir},r.shellChild),r.shellChild.stdout.on(`data`,e=>{t.shell.appendShellOutput(e.toString(`utf-8`))}),r.shellChild.stderr.on(`data`,e=>{t.shell.appendShellOutput(e.toString(`utf-8`))}),r.shellChild.on(`close`,(e,n)=>{r.shellChild=null,n?t.shell.finishShellExecution(null,void 0,!0):t.shell.finishShellExecution(e)}),r.shellChild.on(`error`,e=>{r.shellChild=null,t.shell.finishShellExecution(null,`\nError: ${e.message}`)})}}function Nn(e){let{agentProcessingRef:t,tui:n,requestStop:r}=e;return(e,i)=>{let a=bn(e);return a.isCommand&&a.command.toLowerCase()===`abort`&&i===`send`?(t.value?r(`abort`):n.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`cmd.noRunningTask`)),!0):!1}}function Pn(e){let{app:t,tui:n}=e;return async e=>{let r=e.trim();if(!r)return;if(!t.storage.autoMemory){n.info.showToast(Q.t(`cmd.titleMemory`),Q.t(`cmd.memoryDisabled`));return}let i=await N(r,process.env.OTTO_MEMORY_LLM_NAMING===`1`?t.completeText:void 0);await t.storage.autoMemory.record(i),n.messages.echoUserInput(`# ${r}`),n.messages.pushMessage({role:`assistant`,content:[{type:`text`,text:Q.t(`cmd.memorySaved`,{name:i.name})}]})}}function Fn(e){let t=e.terminated===!0?Q.t(`shell.askAiTerminated`):e.exitCode===null?Q.t(`shell.unknownError`):Q.t(`shell.exitCode`,{code:e.exitCode}),n=e.output.length>5e4?`${e.output.slice(0,5e4)}\n${Q.t(`shell.truncated`)}`:e.output;return Q.t(`shell.prompt`,{command:e.command,errorLabel:t,output:n})}function In(e,t){let n=e=>`${e.kind}\u0000${e.label}`,r=n(t);return[t,...e.filter(e=>n(e)!==r)].slice(0,5)}function Ln(e){return{label:e.label,value:e.value,kind:e.kind,description:e.description}}function Rn(e){return e.map(e=>({label:e.label,value:e.value,kind:e.kind,description:e.description,source:`recent`}))}async function zn(e){let{app:t,session:n,options:i,tuiRefBox:a,tuiRef:o,turn:s,projState:c,redState:l,isBusyNow:u,dispatchToEngine:d,stopController:f,finishInteractive:p,stopTuiGuarded:m,applyModel:h,ensureModelUsableForPrompt:g,refreshSlashCommands:_,fileCommands:b,modelReady:x,availableModelIds:S,currentModel:C,fmtDisplayModel:w,cfgLang:ee,themeRegistry:T,presetSelection:D,keybindingOverrides:O,continuedExisting:k,convoCount:A,historyStore:ne,inputHistory:j,externalHistoryCommands:M,bg:N,reg:P,slashCommands:L,interactive:ie,handleExitRef:ae,cliCtxRef:V,handleAbortInterceptRef:oe,runAsyncBashRef:se,runMemoryCaptureRef:H,allCommandNames:ce}=e,U,ue=t.getResilienceConfig().errorRetry.maxAttempts;Be(`startTui() begin`);let de=performance.now(),fe=F(await te(t.workspaceDir,{readdir:e=>Ct(e,{withFileTypes:!0})})).map(e=>Q.t(e));return{stdin:process.stdin,stdout:process.stdout,modelName:w(C),needsSetup:S.size===0,promptSuggestions:fe,commands:L,pluginInput:t.pluginInput,isImmediateCommand:e=>u()?B.has(e):ce.has(e),isInterruptCommand:e=>e===`abort`,isAgentBusy:u,isPaused:()=>n.isPaused,initialPath:k&&A>0?`/`:`/home`,shadow:t._shadow,welcome:{cwd:process.cwd(),version:qe,buildId:We,nickname:t.settings.get(`nickname`)||void 0,updateAvailable:void 0},onSessionSelect:e=>{R(`session`,[`resume`,e],V.current)},onInstallCapability:e=>{import(`./command-dispatcher-DhcLUPR5.js`).then(e=>e.g).then(({runPluginInstall:t})=>t(e,V.current))},onDismissCapabilityRecommendations:()=>{o.value?.stores.tasks.dismissCapabilityRecommendations()},loadHistory:t.sessionRepoRef?.current?await(async()=>{let e=t.sessionRepoRef.current;if(!e)return;let r=await En(e,n.id,!!i.continueSession);return e=>r.loadEarlier(e.limit)})():void 0,language:ee,themeRegistry:T,presetSelection:D,keybindingOverrides:O,permissionMode:t.getPermissionMode(),onFocusChange:e=>t.setTerminalFocus(e),...N.handlers,initialHistory:j,externalHistoryCommands:M,residencyGovernor:t._residencyGovernor,resolveWholeFileDiff:async(e,n)=>{try{return await W(Qe(t.workspaceDir,e),n)}catch(e){return{error:e instanceof Error?e.message:String(e)}}},initialDrafts:v(n.session.getDrafts()??[]),initialRecentMentions:Rn(t.settings.get(`recent_mentions`)??[]),onSigilSelect:e=>{let n=In(t.settings.get(`recent_mentions`)??[],Ln(e));t.settings.persist({recent_mentions:n}).catch(()=>{}),o.value?.stores.tasks.setRecentMentions(Rn(n))},...Dn({app:t,getTui:()=>a.value,getTuiRef:()=>o.value,getSession:()=>n,getCliCtx:()=>V.current,historyStore:ne,getPasteBinder:()=>V.current.callbacks.pasteBinder}),onQueueSendNow:(e,t)=>{if(t===`memory`){H.current(e);return}if(t===`bash`||t===`bash_async`){se.current(e,t===`bash`?`!`:`!!`);return}U?.(e,`send`,u()?`steer`:`send`)},onSubmit:U=async(e,i,d)=>{if(s.ctrlCCount=0,oe.current(e,i))return;if(n.isPaused&&n.resumeRun(),d===`steer`&&n.isBusy){s.latestSubmittedPrompt={text:e,mode:i};let t=r(await le(e,{currentModelId:n.model?.id,applyModel:h,onSwitchFailed:e=>a.value.info.showToast(Q.t(`cmd.titleModel`),e)}),{currentEffort:n.thinkingLevel,applyEffort:e=>E(V.current,e),onInvalidLevel:e=>a.value.info.showToast(Q.t(`cmd.titleEffort`),Q.t(`cmd.effortUnknown`,{arg:e,levels:y.join(` / `)}))});if(jn(t))return;let{id:o}=n.steer(t);a.value.pending.setPendingSteer(t,o);return}if(i===`memory`){await H.current(e);return}if(i===`bash`||i===`bash_async`){se.current(e,i===`bash`?`!`:`!!`);return}let f=bn(e),p=e,m=!1;if(f.isCommand){if(await R(f.command,f.args,V.current))return;t.firePluginActivationEvent?.(`onCommand:${f.command}`);let e=b.find(e=>e.name===f.command);e&&(m=!0,p=await Te(e.body,{args:f.args,workspaceDir:t.workspaceDir}))}let v=f.isCommand&&!m&&re.has(f.command.toLowerCase());if(!v&&!x&&(!f.isCommand||m)){a.value.info.showToast(Q.t(`cmd.titleSetupRequired`),Q.t(`cmd.noModelConfigured`));return}if(c.todoList.length>0&&c.todoList.every(e=>e.status===`done`||e.status===`skipped`||e.status===`failed`)&&(c.todoList=[],a.value.stores.tasks.setTasks([]),n.session.setTodoList([])),u()&&(!f.isCommand||m)){a.value.engine.enqueueFollowUp(e,i),a.value.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`queue.dFollowUpToast`));return}if(!v){if(await g()===`abort`)return;a.value.engine.pushEngineEvent({kind:`agentProcessing`,value:!0}),s.agentProcessing=!0,a.value.plugins.setCommands(_())}if(s.userAborted=!1,p=await le(p,{currentModelId:n.model?.id,applyModel:h,onSwitchFailed:e=>a.value.info.showToast(Q.t(`cmd.titleModel`),e)}),p=r(p,{currentEffort:n.thinkingLevel,applyEffort:e=>E(V.current,e),onInvalidLevel:e=>a.value.info.showToast(Q.t(`cmd.titleEffort`),Q.t(`cmd.effortUnknown`,{arg:e,levels:y.join(` / `)}))}),jn(p))return;s.latestSubmittedPrompt={text:e,mode:i},s.retryMode||(s.errorRetryAttempt=0),s.retryMode=!1,l.lastTasks=c.todoList.slice();let S=r=>{An({err:r,submitState:s,provider:n.model?.provider,rateLimitInfoRef:{get current(){return s.lastRateLimitInfo},set current(e){s.lastRateLimitInfo=e}},retryModeRef:{get current(){return s.retryMode},set current(e){s.retryMode=e}},errorRetryAttemptRef:{get current(){return s.errorRetryAttempt},set current(e){s.errorRetryAttempt=e}},ERROR_RETRY_MAX:ue,ERROR_RETRY_INTERVAL_SECONDS:t.getResilienceConfig().errorRetry.intervalMs/1e3,handleSubmit:U,retryLastRound:()=>{let t=[...n.session.messages()].reverse().find(e=>e.role===`user`);return!t||(Array.isArray(t.content)?t.content.map(e=>e.type===`text`?e.text:``).join(``):String(t.content??``))!==e?!1:(a.value.engine.pushEngineEvent({kind:`agentProcessing`,value:!0}),s.agentProcessing=!0,n.retryLastRound().catch(t=>{if(t?.code===`RETRY_NO_RESUMABLE_ROUND`){queueMicrotask(()=>U?.(e,i,`send`));return}a.value.pending.withdrawPendingEcho(),S(t)}).finally(()=>{s.agentProcessing=!1,a.value.engine.pushEngineEvent({kind:`agentProcessing`,value:!1})}),!0)},latestSubmittedPromptRef:{get current(){return s.latestSubmittedPrompt},set current(e){s.latestSubmittedPrompt=e}},text:e,mode:i,handleModel:z,handleProviderAuth:I,cliCtx:V.current,tui:a.value})};try{p=await t.expandSigilChips(p,{skipPrefixes:new Set([`model`])}),(!f.isCommand||m)&&!s.retryMode&&(a.value.messages.echoUserInput(p,{pending:!0}),a.value.pending.setPendingEcho(p,i),t.settings.get(`first_prompt_submitted_at`)===void 0&&(t.settings.persist({first_prompt_submitted_at:Date.now()}).catch(()=>{}),t.storage.traceStore.append(n.id,wn(`ftue.first_prompt.submitted`,{timeToFirstPromptMs:Math.round(performance.now()-de)},n.id,{turn:n.session.getTurnCount()})).catch(()=>{}),(async()=>{let e=await Cn({hasFile:async e=>{try{return await Tt(Z(t.workspaceDir,e)),!0}catch{return!1}},packageDependencyNames:async()=>{try{let e=await St(Z(t.workspaceDir,`package.json`),`utf-8`),n=JSON.parse(e);return new Set([...Object.keys(n.dependencies??{}),...Object.keys(n.devDependencies??{})])}catch{return new Set}}},new Set(t.activePlugins().map(e=>e.id))).catch(()=>[]);o.value?.stores.tasks.setCapabilityRecommendations(e)})()));let e=p;s.streamedText=!1;let r=await ie.handleInput(e);if(r.type===`exit`){ae.current(r);return}if(r.type===`help`){a.value.modal.openModal({kind:`helpViewer`,title:`Help`,lines:Jt(P,n.pinned,Q.t(`cmdDesc`,{returnObjects:!0})),onDismiss:()=>{}});return}r.type!==`noop`&&r.text&&!s.streamedText&&(r.type===`system`&&r.text.length<=80?a.value.info.showToast(Q.t(`cmd.titleInfo`),r.text):a.value.messages.pushMessage({role:`assistant`,content:[{type:`text`,text:r.text}]})),r.type===`response`&&r.endReason&&(a.value.pending.clearPendingEcho(),r.notice&&a.value.info.showToast(Q.t(`cmd.titleInfo`),r.notice)),await xn(r,{runTurn:e=>ie.handleInput(e),onTurnResult:e=>e.type===`exit`?(ae.current(e),`exit`):(e.type!==`noop`&&e.type!==`help`&&e.text&&!s.streamedText&&a.value.messages.pushMessage({role:`assistant`,content:[{type:`text`,text:e.text}]}),`continue`),askBudgetContinue:()=>new Promise(e=>{a.value.modal.openModal({kind:`select`,title:Q.t(`budget.exhaustedTitle`),layout:`buttons`,options:[{label:Q.t(`budget.continue`),value:`go`,color:`accent`},{label:Q.t(`budget.stop`),value:`stop`,color:`amber`}],onSelect:t=>e(t===`go`),onCancel:()=>e(!1)})}),onBudgetStopped:()=>{a.value.messages.pushMessage({role:`assistant`,content:[{type:`text`,text:Q.t(`budget.stoppedNote`)}]})},beforeContinuationTurn:()=>{s.streamedText=!1}})}catch(e){a.value.pending.withdrawPendingEcho(),S(e)}finally{s.agentProcessing=!1,s.userAborted=!1,a.value.engine.pushEngineEvent({kind:`agentProcessing`,value:!1}),a.value.plugins.setCommands(_())}},onInterrupt:()=>{let e=Date.now(),t=an(e,s.lastCtrlCTime,{shellRunning:!!s.shellChild,busy:u(),stopDialogOpen:f.isStopDialogOpen(),idleCtrlCCount:s.ctrlCCount});if(t!==`dedup`)switch(s.lastCtrlCTime=e,t){case`kill-shell`:s.shellChild.kill(`SIGTERM`),setTimeout(()=>{s.shellChild&&!s.shellChild.killed&&s.shellChild.kill(`SIGKILL`)},3e3);return;case`open-stop-dialog`:f.requestStop(`abort`);return;case`escalate-exit`:f.escalateToExit();return;case`exit-process`:m();return;case`hint-exit`:s.ctrlCCount++,setTimeout(()=>{s.ctrlCCount=0},800).unref(),a.value.info.showToast(Q.t(`cmd.titleExit`),Q.t(`cmd.pressCtrlCAgain`));return}},onShellAskAi:()=>{let e=o.value?.shell.getShellExecutionSnapshot();if(!e)return;let t=Fn(e);U?.(t,`send`,u()?`steer`:`send`)},onWithdrawPending:(e,t)=>{a.value.pending.withdrawPendingEcho(),a.value.pending.restoreInputText(e),s.agentProcessing&&(s.userAborted=!0,d({kind:`abort`}),a.value.info.showToast(Q.t(`cmd.titleAborted`),Q.t(`cmd.runAborted`)))},onWithdrawSteer:e=>{n.removeSteer(e)?a.value.pending.withdrawPendingSteer(e):f.requestStop(`abort`)},onStop:()=>{p()}}}var Bn=class{estimate;intervalMs;now;text=``;measuredTokens=0;measuredChars=0;measuredAt=-1/0;constructor(e){this.estimate=e.estimate,this.intervalMs=e.intervalMs??250,this.now=e.now??(()=>Date.now())}reset(){this.text=``,this.measuredTokens=0,this.measuredChars=0,this.measuredAt=-1/0}push(e){if(!e)return;this.text+=e;let t=this.now();t-this.measuredAt>=this.intervalMs&&this.measure(t)}flush(){this.measure(this.now())}tokens(){let e=this.text.length-this.measuredChars;if(e<=0)return this.measuredTokens;let t=this.measuredChars>0?this.measuredTokens/this.measuredChars:.25;return this.measuredTokens+Math.ceil(e*t)}measure(e){this.measuredTokens=this.text?this.estimate(this.text):0,this.measuredChars=this.text.length,this.measuredAt=e}};function Vn(e,t){if(/^(bash|shell|run_command|execute|exec)$/i.test(e)){let e=t?.command;if(e)return e}return JSON.stringify(t??{}).slice(0,300)}async function Hn(e,t){let n=[`● ${t.header} — ${t.askedBy} asks:`,t.background?`\n${t.background}`:``,Q.t(`cmd.grillRecommendation`,{rec:t.recommendation}),t.evidence?.length?Q.t(`cmd.grillEvidence`,{joined:t.evidence.map(e=>` · ${e}`).join(`
8
+ `).trimEnd()}catch{s=``}n({id:e,command:a.command,status:o,text:s}),o!==`running`&&u()};u(),q.get(e)&&(q.retain(e,!0),o=e),a=setInterval(()=>{r()},500),r()},onBackgroundOutputClose:()=>{u()},onBackgroundSwitch:e=>{let t=n();d();let r=()=>{let n=J?.getMessages(e),r=J?.get(e),i=r?.agentName??``,a=q.get(e);a&&(i=a.title||i);let o=n?x(n):[],s=J?.getTurns(e),c=J?.getStreamingText(e),l=Date.now(),u={id:e,title:i,messages:o,status:a?.status??`running`,diagnostics:r?st(ft(r),l):[],timeline:s?lt(s,l):[],streamText:c};t.panes.switchToSubagentContext(u)};J?.pin(e),q.get(e)&&q.retain(e,!0),c=e,r(),s=setInterval(()=>{r()},500)},onBackgroundDelete:e=>{if(q.get(e)){q.remove(e);return}if(Y.get(e)){Y.remove(e);return}J.remove(e)},onSubagentExit:()=>{d(),n().panes.switchToSubagentContext(null)}}}}const Qt=ze(`@x-otto/cli:theme-preset-wiring`);function $t(e,t){let n={kind:`extension`,extensionId:t.pluginId};return e.register(n,{localId:t.localId,label:t.label,appearance:t.appearance,colors:t.colors,markdown:t.markdown})}function en(e,t){let n=[];for(let r of t)try{n.push($t(e,r))}catch(e){Qt.warn({pluginId:r.pluginId,localId:r.localId,err:String(e)},`theme preset registration failed, skipped`)}return n}function tn(e){let t=at();return en(t,Se(e.activePlugins())),t}function nn(e){let t=e??et(import.meta.url);t=Ze(t);let n=t===`/`?t:`/`;for(;t!==n;){try{if($e(t+`/.git`))return t}catch{}t=Ze(t)}try{if($e(n+`/.git`))return n}catch{}}var rn=class{repoRoot;currentBuildId;checkIntervalMs;onStale;logger;lastNotifiedBuildId=void 0;disposed=!1;timer;activeChild;constructor(e){this.repoRoot=e.repoRoot,this.currentBuildId=e.currentBuildId,this.checkIntervalMs=e.checkIntervalMs??6e5,this.onStale=e.onStale,this.logger=e.logger}start(){this.disposed||this.scheduleNext()}dispose(){if(this.disposed=!0,this.timer&&=(clearTimeout(this.timer),void 0),this.activeChild){try{this.activeChild.kill()}catch{}this.activeChild=void 0}this.lastNotifiedBuildId=void 0}scheduleNext(){this.disposed||(this.timer=setTimeout(()=>{this.timer=void 0,this.performCheck().then(()=>{this.scheduleNext()})},this.checkIntervalMs),this.timer.unref())}performCheck(){return new Promise(e=>{if(this.disposed){e();return}let t=_e(`git`,[`rev-list`,`--count`,`HEAD`],{cwd:this.repoRoot,timeout:5e3},(t,n)=>{if(this.activeChild=void 0,t){this.logger?.warn({err:t instanceof Error?t.message:String(t)},`[stale-build-detector] git rev-list failed`),e();return}let r=n.trim(),i=parseInt(r,10);if(!Number.isFinite(i)){this.logger?.warn({raw:r},`[stale-build-detector] failed to parse git output as number`),e();return}if(i>this.currentBuildId&&i!==this.lastNotifiedBuildId){this.lastNotifiedBuildId=i;try{this.onStale?.(i)}catch(e){this.logger?.warn({err:e instanceof Error?e.message:String(e)},`[stale-build-detector] onStale callback threw`)}}e()});this.activeChild=t,t.on(`error`,()=>{this.activeChild=void 0})})}};function an(e,t,n){return e-t<50?`dedup`:n.shellRunning?`kill-shell`:n.busy?n.stopDialogOpen?`escalate-exit`:`open-stop-dialog`:n.idleCtrlCCount+1>=2?`exit-process`:`hint-exit`}function on(e){let{getTui:t,getSession:n,dispatchAbort:r,clearTodoLayers:i,markUserAborted:a,resetCtrlCCount:o,markRestartRequested:s,stopTui:c,isBusy:l}=e,u=null,d=()=>u!==null&&t()?.info.getCurrentPath()===`/dialog/confirm`,f=()=>{a(),o(),r(),i()},p=e=>{e&&s(),a(),o();try{r()}catch{}c()},m=e=>{if(e===`abort`)return{title:Q.t(`confirm.abortConfirmTitle`),message:Q.t(`confirm.abortConfirmMessage`),confirmLabel:Q.t(`common.abortButton`),extraLabel:Q.t(`common.pauseButton`),onConfirm:()=>{f(),t()?.info.showToast(Q.t(`cmd.titleAborted`),Q.t(`cmd.runAborted`))}};let n=e===`exit-restart`;return{title:n?Q.t(`confirm.exitRestartConfirmTitle`):Q.t(`confirm.exitConfirmTitle`),message:Q.t(`confirm.exitConfirmMessage`),confirmLabel:n?Q.t(`common.abortAndRestartButton`):Q.t(`common.abortAndExitButton`),extraLabel:void 0,onConfirm:()=>{p(n)}}},h=e=>{let r=t();if(!r)return;let i=m(e);u=e,r.modal.openModal({kind:`confirm`,title:i.title,message:i.message,confirmLabel:i.confirmLabel,confirmColor:`amber`,extraLabel:i.extraLabel,extraColor:`accent`,dangerous:!0,onConfirm:()=>{u=null,i.onConfirm()},onCancel:()=>{u=null},onExtra:i.extraLabel?()=>{u=null,n().pauseRun()?t()?.info.showToast(Q.t(`cmd.titlePaused`),Q.t(`cmd.runWillPauseAfterTurn`)):t()?.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`cmd.noRunningTaskToPause`))}:void 0})};return{requestStop:e=>{if(!t()){e===`abort`?f():p(e===`exit-restart`);return}if(e!==`abort`&&!l()){p(e===`exit-restart`);return}h(e)},isStopDialogOpen:d,escalateToExit:()=>{let e=t();!e||!d()||(h(`exit`),e.modal.resolveConfirm(!0))},abortNow:f}}var sn=class{entries=[];filePath;constructor(e,t=Z(Ge,`sessions`)){this.filePath=Z(t,`${e}.history.json`)}list(e){return this.entries.slice(-(e??100))}append(e){e.trim()&&(this.entries.push(e),this.entries.length>100&&(this.entries=this.entries.slice(-100)))}hydrate(e){this.entries=e.slice(-100)}async persist(){if(Ye())return;let e=JSON.stringify(this.entries,null,2),t=`${this.filePath}.tmp`;try{await xt(Ze(this.filePath),{recursive:!0}),await Dt(t,e,`utf-8`),await wt(t,this.filePath)}catch(e){throw await Et(t).catch(()=>{}),e}}async load(){try{let e=await St(this.filePath,`utf-8`),t=JSON.parse(e);return Array.isArray(t)&&t.every(e=>typeof e==`string`)?(this.entries=t.slice(-100),this.entries):[]}catch{return[]}}};const cn={[it]:e=>ht(e),[tt]:e=>pt(e),[rt]:e=>mt(e)};function ln(){let e=process.env.SHELL??``,t=ge(),n=process.env.HISTFILE;return e.includes(`fish`)?[{id:rt,path:Z(t,`.local/share/fish/fish_history`)},{id:rt,path:Z(t,`.config/fish/fish_history`)}]:e.includes(`bash`)?[{id:tt,path:n?.startsWith(`~`)?Z(t,n.slice(2)):n??Z(t,`.bash_history`)}]:e.includes(`zsh`)||!e?[{id:it,path:n?.startsWith(`~`)?Z(t,n.slice(2)):n??Z(t,`.zsh_history`)}]:[]}function un(e){let t=e?.sources?.filter(e=>e?.enabled!==!1&&!!e?.id&&!!e?.path);if(t&&t.length>0){let e=ge();return t.map(t=>({id:t.id,path:dn(t.path,e)}))}return ln()}function dn(e,t){return e.startsWith(`~/`)?Z(t,e.slice(2)):e===`~`?t:e}async function fn(e){try{return await bt(e),!0}catch{return!1}}async function pn(e,t){let n=cn[e.id];if(!n||!await fn(e.path))return[];try{return n(await St(e.path,`utf8`)).slice(-t)}catch{return[]}}async function mn(e){if(e?.enabled!==!0)return[];let t=e.maxEntries??2e3,n=un(e),r=new Set,i=[];for(let e of n){if(r.has(e.path))continue;r.add(e.path);let n=await pn(e,t);i.push(...n)}return i.slice(-t)}async function hn(e,t){let n=new sn(e.id);return{historyStore:n,inputHistory:await n.load().then(t=>{if(t.length>0)return t;let r=e.session.getInputHistory();return r&&r.length>0?(n.hydrate(r),n.persist().catch(()=>{}),e.session.setInputHistory([]),r):[]}),externalHistoryCommands:t?.enabled===!0?ot(await mn(t)):void 0}}async function gn(e,t,n){if(n){let n=t.settings.get(`model`);if(typeof n==`string`&&n&&e.model?.id!==n){let r=t.modelRegistry.find(n);r&&await t.providerRegistry.hasCredential(r.provider)&&(e.model=r,t.storage.memory?.reconfigure?.({contextWindow:r.contextWindow,maxOutput:r.maxOutputTokens}))}}{let n=t.settings.get(`thinking_level`),r=[`low`,`medium`,`high`,`xhigh`,`max`],i=n===`minimal`?`low`:n;typeof i==`string`&&r.includes(i)&&(e.thinkingLevel=i)}}async function _n(e,t){let n=`__otto_setup__`,r=e.settings.get(`permission_mode`);(r===void 0||r===`auto`)&&await e.settings.update({permission_mode:`confirm`}),e.modelRegistry.getAll().length===0&&e.modelRegistry.register({id:n,name:`Setup required`,provider:`otto`,api:`otto`,baseUrl:``,reasoning:!1,input:[`text`],contextWindow:32e3,maxOutputTokens:4e3});let i=t.continueSession?e.getSession(t.continueSession)??await e.sessionManager.restore(t.continueSession)??void 0:void 0,a=i?i.session.buildContext().messages.filter(e=>{let t=e.role;return t===`user`||t===`assistant`}).length:0,o={value:i?e.sessionManager.consumeCrashGap(i.id):void 0},s=t.continueSession?i?Q.t(`cmd.resumeRestored`,{idShort:t.continueSession.slice(0,8),count:a}):Q.t(`cmd.resumeNotFound`,{id:t.continueSession}):void 0,c=!!(t.continueSession&&i),l=!!(t.model||e.settings.get(`model`)||e.settings.get(`model_slots`)?.default),u={skip:!1},d=await e.hydrateModelCache().catch(()=>new Set),f=e.modelRegistry.getAll().every(e=>e.id===n),p=f?!1:l,m=e.modelRegistry.getAll().find(e=>e.id!==n)??e.modelRegistry.getAll()[0],h=i??await e.createSession({interactive:!0,retryAccelerate:u,...p?{}:{model:m}});await gn(h,e,!!i);let g=p||c,_={get value(){return g},set value(e){g=e}},v={models:e.modelRegistry.getAll().filter(e=>e.id!==n).map(e=>({id:e.id,name:e.name,provider:e.provider,api:e.api,strengths:e.strengths??[],contextWindow:e.contextWindow})),availableModelIds:new Set([...d,...e.getSessionAvailableModels(h.id)]),wasUnconfigured:!1};v.wasUnconfigured=v.availableModelIds.size===0;let y=()=>e.setSessionAvailableModels(h.id,[...v.availableModelIds]);y();let b=new H(k({modelRegistry:e.modelRegistry,authStore:e.authStore,settings:e.settings,selectedModelId:()=>h.model?.id,isModelUsable:Ot(e.authStore,`delegation`),isModelUsableInMainSession:Ot(e.authStore,`main-session`)})),x,S={get value(){return x},set value(e){x=e}},C=async t=>{let r=await e.refreshModels().catch(()=>[]);v.models=e.modelRegistry.getAll().filter(e=>e.id!==n).map(e=>({id:e.id,name:e.name,provider:e.provider,api:e.api,strengths:e.strengths??[],contextWindow:e.contextWindow}));for(let e of r)if(e.status===`ok`)for(let t of e.availableIds??[])v.availableModelIds.add(t);v.models.length>0&&e.modelRegistry.getAll().some(e=>e.id===n)&&e.modelRegistry.unregister(n),y();let i=v.availableModelIds.size===0,a=S.value;a?.stores?.tasks?.setNeedsSetup?.(i);let o=await b.refresh().catch(()=>null);if(o&&a?.stores?.tasks?.setFtueStage?.(o.stage),v.wasUnconfigured&&!i&&(v.wasUnconfigured=!1,a?.info?.showToast?.(Q.t(`cmd.titleSetupReady`),Q.t(`cmd.setupReadyMessage`))),t){let e=r.filter(e=>e.status===`ok`);t(e.length>0?Q.t(`cmd.modelsRefreshed`,{summary:e.map(e=>`${e.provider} ${e.total}`).join(` · `)}):Q.t(`cmd.modelsRefreshedEmpty`))}};return C(),{session:h,startupCrashGapRef:o,resumedNote:s,modelReadyRef:_,registryOnlyPlaceholder:f,firstRealModel:m,modelRefreshState:v,persistAvailable:y,ftueController:b,refreshModelsNow:C,tuiRefBox:S,SETUP_PLACEHOLDER_ID:n,continuedExisting:c,retryAccelerate:u,resumed:i,convoCount:a}}function vn(e){let t=[],n=0,r=``,i=()=>{r&&=(t.push(r),``)};for(;n<e.length;){let t=e[n];if(t===` `||t===` `){i(),n++;continue}if(t===`\\`){n++,n<e.length&&(r+=e[n]),n++;continue}if(t===`"`){n++;let t=yn(e,n,`"`);r+=t.value,n=t.next;continue}if(t===`'`){n++;let t=yn(e,n,`'`,!1);r+=t.value,n=t.next;continue}r+=t,n++}return i(),{tokens:t}}function yn(e,t,n,r=!0){let i=``,a=t;for(;a<e.length;){let t=e[a];if(r&&t===`\\`){a++,a<e.length&&(i+=e[a]),a++;continue}if(t===n)return a++,{value:i,next:a};i+=t,a++}return{value:i,next:a}}function bn(e){let t=e.trim();if(!t.startsWith(`/`)||t===`/`||t.startsWith(`//`))return{isCommand:!1,text:t};let{tokens:n}=vn(t.slice(1));if(n.length===0)return{isCommand:!1,text:t};let[r,...i]=n;return{isCommand:!0,command:r,args:i}}async function xn(e,t){let n=e;for(;n.type===`response`&&n.endReason===`max-tool-turns`&&n.notice;){if(!await t.askBudgetContinue()){t.onBudgetStopped();return}t.beforeContinuationTurn();let e=await t.runTurn(`Continue with the remaining work until the task is complete.`);if(t.onTurnResult(e)===`exit`)return;n=e}}const Sn=[{extensionId:`plugin-browser-use`,reasonKey:`capability.reasonWebApp`,detect:async e=>{let t=await e.packageDependencyNames();return[`react`,`vue`,`next`,`nuxt`,`svelte`,`vite`,`@angular/core`,`express`,`koa`,`fastify`].some(e=>t.has(e))?!0:e.hasFile(`index.html`)}},{extensionId:`plugin-mobile-use`,reasonKey:`capability.reasonMobile`,detect:async e=>{if(await e.hasFile(`AndroidManifest.xml`)||await e.hasFile(`build.gradle`)||await e.hasFile(`build.gradle.kts`)||await e.hasFile(`Info.plist`)||await e.hasFile(`Podfile`))return!0;let t=await e.packageDependencyNames();return t.has(`react-native`)||t.has(`expo`)}},{extensionId:`plugin-schedule`,reasonKey:`capability.reasonSchedule`,detect:async e=>{if(await e.hasFile(`crontab`))return!0;let t=await e.packageDependencyNames();return t.has(`node-cron`)||t.has(`node-schedule`)||t.has(`agenda`)}}];async function Cn(e,t,n=Sn){let r=[];for(let i of n){if(t.has(i.extensionId))continue;let n=!1;try{n=await i.detect(e)}catch{n=!1}n&&r.push({extensionId:i.extensionId,reasonKey:i.reasonKey})}return r}function wn(e,t,n,r){return{ts:r?.ts??Date.now(),sessionId:n,...r?.turn===void 0?{}:{turn:r.turn},kind:`lifecycle`,node:e,payload:t}}function Tn(e){let t=new Map;if(e?.role===`assistant`&&Array.isArray(e.content))for(let n of e.content)n.type===`tool_call`&&t.set(n.id,n);return t}async function En(e,t,n){let r,i=new Set,a=new Map,o=new Set,c=new Map;if(n){let n=await e.loadTailEntries(t,It);r=n.length>0?n[0].seq:0;for(let e of n)e.type===`message`&&i.add(e.seq)}else r=await e.getEntryCount(t);return{async loadEarlier(n=500){if(r<=0)return null;let l=await e.loadEntriesBefore(t,r,n);if(l.length===0)return null;let u=new Map,d=new Set;for(let e of l){if(e.type!==`message`)continue;let t=e.data;if(t?.role===`assistant`)for(let[e,n]of Tn(t))u.set(e,n);else t?.role===`tool_result`&&typeof t.toolCallId==`string`&&d.add(t.toolCallId)}let f=[],p=(e,t)=>({...e,id:`hist-${t}`,seq:t});for(let e of l){if(e.type===`clear`){r=0,f.length=0;continue}if(e.type!==`message`||i.has(e.seq))continue;let t=e.data;if(!t||typeof t.role!=`string`||t.internal)continue;if(t.role===`tool_result`){let n=a.get(t.toolCallId??``)??u.get(t.toolCallId??``);if(n){let r=n.arguments??{};f.push(p({role:`tool`,name:t.toolName||n.name||`tool`,args:C(r),argsObj:r,result:s(t.content),isError:t.isError},e.seq)),o.add(t.toolCallId)}else c.set(t.toolCallId,{toolName:t.toolName,content:t.content,isError:t.isError});continue}if(t.role===`assistant`){let n=Tn(t);if(n.size>0){let r=new Set([...d,...o,...c.keys()]),i=x([t],{resolvedIds:r});for(let t of i)f.push(p(t,e.seq));for(let[t,r]of n){if(d.has(t))continue;let n=c.get(t);if(n){c.delete(t);let i=r.arguments??{};f.push(p({role:`tool`,name:r.name,args:C(i),argsObj:i,result:s(n.content),isError:n.isError??!1},e.seq))}}continue}}let n=x([t]);for(let t of n)f.push(p(t,e.seq))}for(let[e,t]of u)a.set(e,t);return r>0&&(r=l[0].seq),f.length>0?f:null}}}function Dn(e){let{app:t,getTui:n,getTuiRef:r,getSession:i,getCliCtx:a,historyStore:o}=e;return{onCyclePermissionMode:()=>{let e=n(),r=ee(t.getPermissionMode());e.stores.tasks.setPermissionMode(r),e.info.showToast(Q.t(`cmd.titlePermission`),Q.t(`pref.permModeSwitched`,{label:Q.t(`pref.permModeLabel`,{context:r})})),t.setPermissionMode(r)},onHistoryPush:t=>{try{o.hydrate([...t]),o.persist().catch(()=>{})}catch{}e.getPasteBinder?.()?.save(i().id)},onDraftSave:e=>{let n=i(),a=n.session.getDrafts()??[],o=f(void 0,e,a),s=l([...a,o]);n.session.setDrafts(s),t.sessionManager.save(n.id).catch(()=>{}),r()?.stores.tasks.setDrafts(v(s))},onDraftDelete:e=>{let n=i(),a=(n.session.getDrafts()??[]).filter(t=>t.id!==e);n.session.setDrafts(a),t.sessionManager.save(n.id).catch(()=>{}),r()?.stores.tasks.setDrafts(v(a))},onDraftDeleteMany:e=>{let n=i(),a=new Set(e),o=(n.session.getDrafts()??[]).filter(e=>!a.has(e.id));n.session.setDrafts(o),t.sessionManager.save(n.id).catch(()=>{}),r()?.stores.tasks.setDrafts(v(o))},onA2uiAction:(e,t,n)=>{R(`a2ui-action`,n?[e,t,JSON.stringify(n)]:[e,t],a())},onPerfRefresh:()=>{R(`status`,[`perf`],a())},onProxySubmitUrl:e=>{R(`preference`,[`proxy`,e],a())},onProxyToggleEnabled:()=>{R(`preference`,[`proxy`,t.settings.get(`proxy`)?.enabled===!1?`on`:`off`],a())},onProxyClear:()=>{R(`preference`,[`proxy`,`clear`],a())},onProxyTest:()=>{R(`preference`,[`proxy`,`test`],a())}}}function On(e){return{...kn(e),pluginSource:e.pluginSource,intervalSeconds:e.errorRetryIntervalSeconds}}function kn(e){let{msg:t,provider:n,authError:r,isRefreshFailed:i,unsupported:a,rateLimit:o,rateLimitInfo:s,getErrorRetryAttempt:c,incErrorRetryAttempt:l,errorRetryMax:u,retryQueued:d,resetAndRetry:f,cancelRetry:p,switchModelThenRetry:m,goToAuth:h}=e;if(s)return s.resetsAt===void 0?{reason:t,attempt:0,max:u,mode:`manual`,limitType:s.limitType,actions:[{kind:`switchModel`,label:Q.t(`error.switchModel`),run:m},{kind:`retryNow`,label:Q.t(`retry.nowButton`),run:d}],onExpired:()=>{},onCancel:p}:{reason:t,attempt:0,max:u,mode:`resetsAt`,resetsAt:s.resetsAt,limitType:s.limitType,actions:[{kind:`retryNow`,label:Q.t(`error.retryNow`),run:d},{kind:`switchModel`,label:Q.t(`error.switchModel`),run:m}],onExpired:d,onCancel:p};if(r)return{reason:i?Q.t(`cmd.authRefreshFailed`,{ps:n?` (${n})`:``,ls:n?` ${n}`:``}):Q.t(`cmd.authFailed`,{ps:n?` (${n})`:``,ls:n?` ${n}`:``}),attempt:c(),max:u,mode:`manual`,actions:[{kind:`login`,label:Q.t(`model.goToLoginButton`),run:h},{kind:`switchModel`,label:Q.t(`error.switchModel`),run:m},{kind:`retryNow`,label:Q.t(`retry.nowButton`),run:d}],onExpired:()=>{},onCancel:p};if(a)return{reason:Q.t(`cmd.modelNotSupported`),attempt:c(),max:u,mode:`manual`,actions:[{kind:`switchModel`,label:Q.t(`error.switchModel`),run:m},{kind:`retryNow`,label:Q.t(`retry.nowButton`),run:d}],onExpired:()=>{},onCancel:p};let g=l(),_=g>u;return{reason:o?Q.t(`cmd.rateLimitedRetriesExhausted`):Q.t(`cmd.requestFailed`,{msg:t}),attempt:Math.min(g,u),max:u,mode:`auto`,exhausted:_,actions:[{kind:`retryNow`,label:Q.t(`retry.nowButton`),run:_?f:d}],onExpired:_?()=>{}:d,onCancel:p}}function An(e){let{err:n}=e,r=n instanceof Error?n.message:String(n),i=n?.code===`AGENT_ABORTED`||n instanceof Error&&n.name===`AbortError`;if(!(e.submitState.userAborted||i)){let i=e.provider,a=n?.code,o=n?.pluginSource,{authError:s,isRefreshFailed:c,unsupported:l,rateLimit:u,pluginSource:d}=ie(r,a,o),f=e.rateLimitInfoRef.current;e.rateLimitInfoRef.current=void 0;let p=(()=>{let t=e.cliCtx,n=t?.app?.storage?.traceStore,r=t?.state?.session;if(!n||!r)return null;let i=r.session.getTurnCount();return{traceStore:n,sessionId:r.id,...i===void 0?{}:{turn:i}}})(),m=()=>{p&&P(p,{attempt:e.errorRetryAttemptRef.current+1,max:e.ERROR_RETRY_MAX,mode:f?`resetsAt`:s||l?`manual`:`auto`,reason:r.slice(0,120)}),e.retryModeRef.current=!0;let t=e.latestSubmittedPromptRef?.current,n=e.tui.engine.takeLastQueuedFollowUp?.(),i=t!=null&&t.text!==e.text,a=i?t.text:n?.text??e.text,o=i?t.mode:n?.mode??e.mode;a===e.text&&!i&&n==null&&e.retryLastRound?.()||queueMicrotask(()=>e.handleSubmit?.(a,o,`send`))};e.tui.engine.showErrorRetry(On({msg:r,provider:i,authError:s,isRefreshFailed:c,unsupported:l,rateLimit:u,rateLimitInfo:f,pluginSource:d,getErrorRetryAttempt:()=>e.errorRetryAttemptRef.current,incErrorRetryAttempt:()=>++e.errorRetryAttemptRef.current,errorRetryMax:e.ERROR_RETRY_MAX,errorRetryIntervalSeconds:e.ERROR_RETRY_INTERVAL_SECONDS,retryQueued:m,resetAndRetry:()=>{p&&t(p),e.errorRetryAttemptRef.current=0,m()},cancelRetry:()=>{p&&h(p,{attempt:e.errorRetryAttemptRef.current}),e.errorRetryAttemptRef.current=0},switchModelThenRetry:()=>{e.handleModel([],e.cliCtx,{afterSwitch:m})},goToAuth:()=>{e.handleProviderAuth([i??``].filter(Boolean),e.cliCtx)}}))}}function jn(e){return e.trim().length===0}function Mn(e){let{tui:t,app:n,submitState:r}=e;return(e,i=`!!`)=>{let a=e.trim();if(!a)return;let o=Re(a);if(!o.safe){t.info.showToast(Q.t(`cmd.titleShell`),Q.t(`cmd.dangerousBlocked`,{reason:o.reason})),t.messages.pushMessage({role:`assistant`,content:[{type:`text`,text:Q.t(`cmd.dangerousBlockedDetail`,{reason:o.reason,cmd:a})}]});return}t.messages.echoUserInput(`${i} ${a}`),t.shell.startShellExecution(a),r.shellChild=ve(a,{shell:!0,cwd:n.workspaceDir,stdio:[`ignore`,`pipe`,`pipe`],env:Le()}),Fe.registerChild({command:a,args:[],owner:{type:`cli-shell`,id:`!!`},category:`shell`,lifecycle:`evictable`,cwd:n.workspaceDir},r.shellChild),r.shellChild.stdout.on(`data`,e=>{t.shell.appendShellOutput(e.toString(`utf-8`))}),r.shellChild.stderr.on(`data`,e=>{t.shell.appendShellOutput(e.toString(`utf-8`))}),r.shellChild.on(`close`,(e,n)=>{r.shellChild=null,n?t.shell.finishShellExecution(null,void 0,!0):t.shell.finishShellExecution(e)}),r.shellChild.on(`error`,e=>{r.shellChild=null,t.shell.finishShellExecution(null,`\nError: ${e.message}`)})}}function Nn(e){let{agentProcessingRef:t,tui:n,requestStop:r}=e;return(e,i)=>{let a=bn(e);return a.isCommand&&a.command.toLowerCase()===`abort`&&i===`send`?(t.value?r(`abort`):n.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`cmd.noRunningTask`)),!0):!1}}function Pn(e){let{app:t,tui:n}=e;return async e=>{let r=e.trim();if(!r)return;if(!t.storage.autoMemory){n.info.showToast(Q.t(`cmd.titleMemory`),Q.t(`cmd.memoryDisabled`));return}let i=await N(r,process.env.OTTO_MEMORY_LLM_NAMING===`1`?t.completeText:void 0);await t.storage.autoMemory.record(i),n.messages.echoUserInput(`# ${r}`),n.messages.pushMessage({role:`assistant`,content:[{type:`text`,text:Q.t(`cmd.memorySaved`,{name:i.name})}]})}}function Fn(e){let t=e.terminated===!0?Q.t(`shell.askAiTerminated`):e.exitCode===null?Q.t(`shell.unknownError`):Q.t(`shell.exitCode`,{code:e.exitCode}),n=e.output.length>5e4?`${e.output.slice(0,5e4)}\n${Q.t(`shell.truncated`)}`:e.output;return Q.t(`shell.prompt`,{command:e.command,errorLabel:t,output:n})}function In(e,t){let n=e=>`${e.kind}\u0000${e.label}`,r=n(t);return[t,...e.filter(e=>n(e)!==r)].slice(0,5)}function Ln(e){return{label:e.label,value:e.value,kind:e.kind,description:e.description}}function Rn(e){return e.map(e=>({label:e.label,value:e.value,kind:e.kind,description:e.description,source:`recent`}))}async function zn(e){let{app:t,session:n,options:i,tuiRefBox:a,tuiRef:o,turn:s,projState:c,redState:l,isBusyNow:u,dispatchToEngine:d,stopController:f,finishInteractive:p,stopTuiGuarded:m,applyModel:h,ensureModelUsableForPrompt:g,refreshSlashCommands:_,fileCommands:b,modelReady:x,availableModelIds:S,currentModel:C,fmtDisplayModel:w,cfgLang:ee,themeRegistry:T,presetSelection:D,keybindingOverrides:O,continuedExisting:k,convoCount:A,historyStore:ne,inputHistory:j,externalHistoryCommands:M,bg:N,reg:P,slashCommands:L,interactive:ie,handleExitRef:ae,cliCtxRef:V,handleAbortInterceptRef:oe,runAsyncBashRef:se,runMemoryCaptureRef:H,allCommandNames:ce}=e,U,ue=t.getResilienceConfig().errorRetry.maxAttempts;Be(`startTui() begin`);let de=performance.now(),fe=F(await te(t.workspaceDir,{readdir:e=>Ct(e,{withFileTypes:!0})})).map(e=>Q.t(e));return{stdin:process.stdin,stdout:process.stdout,modelName:w(C),needsSetup:S.size===0,promptSuggestions:fe,commands:L,pluginInput:t.pluginInput,isImmediateCommand:e=>u()?B.has(e):ce.has(e),isInterruptCommand:e=>e===`abort`,isAgentBusy:u,isPaused:()=>n.isPaused,initialPath:k&&A>0?`/`:`/home`,shadow:t._shadow,welcome:{cwd:process.cwd(),version:qe,buildId:We,nickname:t.settings.get(`nickname`)||void 0,updateAvailable:void 0},onSessionSelect:e=>{R(`session`,[`resume`,e],V.current)},onInstallCapability:e=>{import(`./command-dispatcher-Dxj41r5P.js`).then(e=>e.g).then(({runPluginInstall:t})=>t(e,V.current))},onDismissCapabilityRecommendations:()=>{o.value?.stores.tasks.dismissCapabilityRecommendations()},loadHistory:t.sessionRepoRef?.current?await(async()=>{let e=t.sessionRepoRef.current;if(!e)return;let r=await En(e,n.id,!!i.continueSession);return e=>r.loadEarlier(e.limit)})():void 0,language:ee,themeRegistry:T,presetSelection:D,keybindingOverrides:O,permissionMode:t.getPermissionMode(),onFocusChange:e=>t.setTerminalFocus(e),...N.handlers,initialHistory:j,externalHistoryCommands:M,residencyGovernor:t._residencyGovernor,resolveWholeFileDiff:async(e,n)=>{try{return await W(Qe(t.workspaceDir,e),n)}catch(e){return{error:e instanceof Error?e.message:String(e)}}},initialDrafts:v(n.session.getDrafts()??[]),initialRecentMentions:Rn(t.settings.get(`recent_mentions`)??[]),onSigilSelect:e=>{let n=In(t.settings.get(`recent_mentions`)??[],Ln(e));t.settings.persist({recent_mentions:n}).catch(()=>{}),o.value?.stores.tasks.setRecentMentions(Rn(n))},...Dn({app:t,getTui:()=>a.value,getTuiRef:()=>o.value,getSession:()=>n,getCliCtx:()=>V.current,historyStore:ne,getPasteBinder:()=>V.current.callbacks.pasteBinder}),onQueueSendNow:(e,t)=>{if(t===`memory`){H.current(e);return}if(t===`bash`||t===`bash_async`){se.current(e,t===`bash`?`!`:`!!`);return}U?.(e,`send`,u()?`steer`:`send`)},onSubmit:U=async(e,i,d)=>{if(s.ctrlCCount=0,oe.current(e,i))return;if(n.isPaused&&n.resumeRun(),d===`steer`&&n.isBusy){s.latestSubmittedPrompt={text:e,mode:i};let t=r(await le(e,{currentModelId:n.model?.id,applyModel:h,onSwitchFailed:e=>a.value.info.showToast(Q.t(`cmd.titleModel`),e)}),{currentEffort:n.thinkingLevel,applyEffort:e=>E(V.current,e),onInvalidLevel:e=>a.value.info.showToast(Q.t(`cmd.titleEffort`),Q.t(`cmd.effortUnknown`,{arg:e,levels:y.join(` / `)}))});if(jn(t))return;let{id:o}=n.steer(t);a.value.pending.setPendingSteer(t,o);return}if(i===`memory`){await H.current(e);return}if(i===`bash`||i===`bash_async`){se.current(e,i===`bash`?`!`:`!!`);return}let f=bn(e),p=e,m=!1;if(f.isCommand){if(await R(f.command,f.args,V.current))return;t.firePluginActivationEvent?.(`onCommand:${f.command}`);let e=b.find(e=>e.name===f.command);e&&(m=!0,p=await Te(e.body,{args:f.args,workspaceDir:t.workspaceDir}))}let v=f.isCommand&&!m&&re.has(f.command.toLowerCase());if(!v&&!x&&(!f.isCommand||m)){a.value.info.showToast(Q.t(`cmd.titleSetupRequired`),Q.t(`cmd.noModelConfigured`));return}if(c.todoList.length>0&&c.todoList.every(e=>e.status===`done`||e.status===`skipped`||e.status===`failed`)&&(c.todoList=[],a.value.stores.tasks.setTasks([]),n.session.setTodoList([])),u()&&(!f.isCommand||m)){a.value.engine.enqueueFollowUp(e,i),a.value.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`queue.dFollowUpToast`));return}if(!v){if(await g()===`abort`)return;a.value.engine.pushEngineEvent({kind:`agentProcessing`,value:!0}),s.agentProcessing=!0,a.value.plugins.setCommands(_())}if(s.userAborted=!1,p=await le(p,{currentModelId:n.model?.id,applyModel:h,onSwitchFailed:e=>a.value.info.showToast(Q.t(`cmd.titleModel`),e)}),p=r(p,{currentEffort:n.thinkingLevel,applyEffort:e=>E(V.current,e),onInvalidLevel:e=>a.value.info.showToast(Q.t(`cmd.titleEffort`),Q.t(`cmd.effortUnknown`,{arg:e,levels:y.join(` / `)}))}),jn(p))return;s.latestSubmittedPrompt={text:e,mode:i},s.retryMode||(s.errorRetryAttempt=0),s.retryMode=!1,l.lastTasks=c.todoList.slice();let S=r=>{An({err:r,submitState:s,provider:n.model?.provider,rateLimitInfoRef:{get current(){return s.lastRateLimitInfo},set current(e){s.lastRateLimitInfo=e}},retryModeRef:{get current(){return s.retryMode},set current(e){s.retryMode=e}},errorRetryAttemptRef:{get current(){return s.errorRetryAttempt},set current(e){s.errorRetryAttempt=e}},ERROR_RETRY_MAX:ue,ERROR_RETRY_INTERVAL_SECONDS:t.getResilienceConfig().errorRetry.intervalMs/1e3,handleSubmit:U,retryLastRound:()=>{let t=[...n.session.messages()].reverse().find(e=>e.role===`user`);return!t||(Array.isArray(t.content)?t.content.map(e=>e.type===`text`?e.text:``).join(``):String(t.content??``))!==e?!1:(a.value.engine.pushEngineEvent({kind:`agentProcessing`,value:!0}),s.agentProcessing=!0,n.retryLastRound().catch(t=>{if(t?.code===`RETRY_NO_RESUMABLE_ROUND`){queueMicrotask(()=>U?.(e,i,`send`));return}a.value.pending.withdrawPendingEcho(),S(t)}).finally(()=>{s.agentProcessing=!1,a.value.engine.pushEngineEvent({kind:`agentProcessing`,value:!1})}),!0)},latestSubmittedPromptRef:{get current(){return s.latestSubmittedPrompt},set current(e){s.latestSubmittedPrompt=e}},text:e,mode:i,handleModel:z,handleProviderAuth:I,cliCtx:V.current,tui:a.value})};try{p=await t.expandSigilChips(p,{skipPrefixes:new Set([`model`])}),(!f.isCommand||m)&&!s.retryMode&&(a.value.messages.echoUserInput(p,{pending:!0}),a.value.pending.setPendingEcho(p,i),t.settings.get(`first_prompt_submitted_at`)===void 0&&(t.settings.persist({first_prompt_submitted_at:Date.now()}).catch(()=>{}),t.storage.traceStore.append(n.id,wn(`ftue.first_prompt.submitted`,{timeToFirstPromptMs:Math.round(performance.now()-de)},n.id,{turn:n.session.getTurnCount()})).catch(()=>{}),(async()=>{let e=await Cn({hasFile:async e=>{try{return await Tt(Z(t.workspaceDir,e)),!0}catch{return!1}},packageDependencyNames:async()=>{try{let e=await St(Z(t.workspaceDir,`package.json`),`utf-8`),n=JSON.parse(e);return new Set([...Object.keys(n.dependencies??{}),...Object.keys(n.devDependencies??{})])}catch{return new Set}}},new Set(t.activePlugins().map(e=>e.id))).catch(()=>[]);o.value?.stores.tasks.setCapabilityRecommendations(e)})()));let e=p;s.streamedText=!1;let r=await ie.handleInput(e);if(r.type===`exit`){ae.current(r);return}if(r.type===`help`){a.value.modal.openModal({kind:`helpViewer`,title:`Help`,lines:Jt(P,n.pinned,Q.t(`cmdDesc`,{returnObjects:!0})),onDismiss:()=>{}});return}r.type!==`noop`&&r.text&&!s.streamedText&&(r.type===`system`&&r.text.length<=80?a.value.info.showToast(Q.t(`cmd.titleInfo`),r.text):a.value.messages.pushMessage({role:`assistant`,content:[{type:`text`,text:r.text}]})),r.type===`response`&&r.endReason&&(a.value.pending.clearPendingEcho(),r.notice&&a.value.info.showToast(Q.t(`cmd.titleInfo`),r.notice)),await xn(r,{runTurn:e=>ie.handleInput(e),onTurnResult:e=>e.type===`exit`?(ae.current(e),`exit`):(e.type!==`noop`&&e.type!==`help`&&e.text&&!s.streamedText&&a.value.messages.pushMessage({role:`assistant`,content:[{type:`text`,text:e.text}]}),`continue`),askBudgetContinue:()=>new Promise(e=>{a.value.modal.openModal({kind:`select`,title:Q.t(`budget.exhaustedTitle`),layout:`buttons`,options:[{label:Q.t(`budget.continue`),value:`go`,color:`accent`},{label:Q.t(`budget.stop`),value:`stop`,color:`amber`}],onSelect:t=>e(t===`go`),onCancel:()=>e(!1)})}),onBudgetStopped:()=>{a.value.messages.pushMessage({role:`assistant`,content:[{type:`text`,text:Q.t(`budget.stoppedNote`)}]})},beforeContinuationTurn:()=>{s.streamedText=!1}})}catch(e){a.value.pending.withdrawPendingEcho(),S(e)}finally{s.agentProcessing=!1,s.userAborted=!1,a.value.engine.pushEngineEvent({kind:`agentProcessing`,value:!1}),a.value.plugins.setCommands(_())}},onInterrupt:()=>{let e=Date.now(),t=an(e,s.lastCtrlCTime,{shellRunning:!!s.shellChild,busy:u(),stopDialogOpen:f.isStopDialogOpen(),idleCtrlCCount:s.ctrlCCount});if(t!==`dedup`)switch(s.lastCtrlCTime=e,t){case`kill-shell`:s.shellChild.kill(`SIGTERM`),setTimeout(()=>{s.shellChild&&!s.shellChild.killed&&s.shellChild.kill(`SIGKILL`)},3e3);return;case`open-stop-dialog`:f.requestStop(`abort`);return;case`escalate-exit`:f.escalateToExit();return;case`exit-process`:m();return;case`hint-exit`:s.ctrlCCount++,setTimeout(()=>{s.ctrlCCount=0},800).unref(),a.value.info.showToast(Q.t(`cmd.titleExit`),Q.t(`cmd.pressCtrlCAgain`));return}},onShellAskAi:()=>{let e=o.value?.shell.getShellExecutionSnapshot();if(!e)return;let t=Fn(e);U?.(t,`send`,u()?`steer`:`send`)},onWithdrawPending:(e,t)=>{a.value.pending.withdrawPendingEcho()&&a.value.pending.restoreInputText(e),s.agentProcessing&&(s.userAborted=!0,d({kind:`abort`}),a.value.info.showToast(Q.t(`cmd.titleAborted`),Q.t(`cmd.runAborted`)))},onWithdrawSteer:e=>{n.removeSteer(e)?a.value.pending.withdrawPendingSteer(e):f.requestStop(`abort`)},onStop:()=>{p()}}}var Bn=class{estimate;intervalMs;now;text=``;measuredTokens=0;measuredChars=0;measuredAt=-1/0;constructor(e){this.estimate=e.estimate,this.intervalMs=e.intervalMs??250,this.now=e.now??(()=>Date.now())}reset(){this.text=``,this.measuredTokens=0,this.measuredChars=0,this.measuredAt=-1/0}push(e){if(!e)return;this.text+=e;let t=this.now();t-this.measuredAt>=this.intervalMs&&this.measure(t)}flush(){this.measure(this.now())}tokens(){let e=this.text.length-this.measuredChars;if(e<=0)return this.measuredTokens;let t=this.measuredChars>0?this.measuredTokens/this.measuredChars:.25;return this.measuredTokens+Math.ceil(e*t)}measure(e){this.measuredTokens=this.text?this.estimate(this.text):0,this.measuredChars=this.text.length,this.measuredAt=e}};function Vn(e,t){if(/^(bash|shell|run_command|execute|exec)$/i.test(e)){let e=t?.command;if(e)return e}return JSON.stringify(t??{}).slice(0,300)}async function Hn(e,t){let n=[`● ${t.header} — ${t.askedBy} asks:`,t.background?`\n${t.background}`:``,Q.t(`cmd.grillRecommendation`,{rec:t.recommendation}),t.evidence?.length?Q.t(`cmd.grillEvidence`,{joined:t.evidence.map(e=>` · ${e}`).join(`
9
9
  `)}):``].join(``);e.messages.pushMessage({role:`assistant`,content:[{type:`text`,text:n}]});let r=t.options??[];if(r.length>0){if(r.length<=2&&!t.multiSelect&&t.allowFreeform===!1){let n=await new Promise(n=>{e.modal.openModal({kind:`confirm`,title:t.question,message:r.map(e=>`${e.label}${e.recommended?` (recommended)`:``}: ${e.rationale}`).join(`
10
10
  `),confirmLabel:r[0]?.label??Q.t(`cmd.grillOptionYes`),cancelLabel:r[1]?.label??Q.t(`cmd.grillOptionNo`),onConfirm:()=>n(!0),onCancel:()=>n(!1)})})?r[0]?.label:r[1]?.label;return zt(t,n?[n]:[])}let n=await e.modal.openModal({kind:`questions`,title:t.question,questions:[{header:t.header,question:t.question,multiSelect:!!t.multiSelect,freeformInput:t.allowFreeform!==!1,freeformPlaceholder:Q.t(`cmd.grillFreeformPlaceholder`),options:r.map(e=>({label:e.recommended?`${e.label} ★`:e.label,description:e.rationale}))}]});return zt(t,(n?.answers?.[t.header]??[]).map(e=>e.replace(/\s*★$/,``)),n?.freeformText)}return Bt(t,await e.modal.openModal({kind:`input`,title:t.header,description:[t.question],placeholder:Q.t(`cmd.grillAnswerPlaceholder`)}))}function Un(t){let{getSession:r,app:a,tui:o,projState:s,redState:l,recomputeBudget:u,persistEditedFiles:d,persistSubagents:f,persistTurnCount:p,onContextCompacted:m,markStreamed:h}=t,g=null,_=!1,v=!1,y=null,b=null,x=e=>{let t=r(),n=t.session.getTurnCount();i({traceStore:a.storage.traceStore,sessionId:t.id,...n===void 0?{}:{turn:n}},e,`session-event`)},S=e=>{r().session.append({role:`system`,subtype:e,content:e,level:`info`,timestamp:Date.now()})},C=!1,w,ee={currentModel:()=>r().model.id,cacheHitRatio:()=>r().getLastCacheHitRatio(),turnTokens:()=>{let e=r().session.messages(),t=0;for(let n of e)n.role===`assistant`&&n.usage&&(t+=(n.usage.inputTokens??0)+(n.usage.outputTokens??0)+(n.usage.cacheReadTokens??0)+(n.usage.cacheWriteTokens??0));let n=w;if(w=t,!(n==null||t<=n))return t-n}},T,E=!1,D=0,O=0,te=0,k=new Bn({estimate:e}),A=()=>{O=0,te=0,D=0,k.reset()},ne=()=>{u(O+te+k.tokens())},j=0,M={},N=e=>{let t=0,n=0;for(let r of e.split(`
11
11
  `))r.startsWith(`+`)&&!r.startsWith(`+++`)?t++:r.startsWith(`-`)&&!r.startsWith(`---`)&&n++;return`+${t}/-${n}`},P=()=>{let e=Y.listForSession(r().id).map(e=>({id:e.id,command:e.command,type:`process`,origin:`main`,status:e.status===`running`?`running`:e.status===`exited`?`exited`:`killed`,port:e.port,startedAt:e.startedAt,exitCode:e.exitCode,detectedService:e.detectedService})),t=new Map(J.list().map(e=>[e.id,e])),n=e=>{let n=t.get(e);return n?dt(n):{}},i=q.listForSession(r().id).map(e=>({id:e.id,command:e.title,type:`agent-session`,origin:e.origin,status:e.status===`running`||e.status===`ready`||e.status===`needs_input`?`running`:e.status===`applied`?`exited`:e.status===`failed`?`failed`:`killed`,agentStatus:e.status,diffStat:e.diff?N(e.diff):void 0,startedAt:e.startedAt,...n(e.id)})),a=new Set(i.map(e=>e.id)),s=J.list().filter(e=>!a.has(e.id)).map(ft),c=[...e,...i,...s];o.stores.tasks.setBackgroundTasks([...c.filter(e=>e.origin===`user`),...c.filter(e=>e.origin!==`user`)])},F=null,I=()=>{F===null&&(F=setTimeout(()=>{F=null,P()},30))},re=()=>{F!==null&&(clearTimeout(F),F=null),P()},L=[Y.onSpawn(I),Y.onExit(re),q.onSpawn(I),q.onUpdate(I),q.onExit(re),q.onRemove(re),J.subscribe(I)];P();let R;return{bgUnsubs:L,attachSessionHandler:()=>{R?.(),_=!1,R=r().subscribe(t=>{for(let e of Rt(t,s,ee)){if(e.kind===`prompt.end`){let t=n(e,l),i={turn:s.currentTurn,completedAt:Date.now(),...t},a=r().session.getTurnSummaries()??[];r().session.setTurnSummaries([...a.filter(e=>e.turn!==i.turn),i])}c(e,{pushMessage:o.messages.pushMessage,echoUserInput:o.messages.echoUserInput,pushEngineEvent:o.engine.pushEngineEvent,getNotifyStats:o.info.getNotifyStats,setTasks:(e,t)=>o.stores.tasks.setTasks(e,t),addTurnBoundary:e=>o.stores.tasks.addTurnBoundary(e)},l),e.kind===`tasks.update`&&(r().session.setTodoList(s.todoList),a.sessionManager.save(r().id).catch(()=>{}))}if(t.type===`stream.event`&&t.event?.type===`text_delta`){h();let e=t.event?.delta??``;D+=e.length,k.push(e),o.engine.pushEngineEvent({kind:`outputTokensThisTurn`,n:Math.floor(D/4)}),ne()}if(t.type===`stream.event`&&t.event?.type===`done`){let e=t.event?.providerUsage;if(e!==void 0){let t=e!==null&&ut(e.status,e.overageStatus);if(e===null||e.status===`rejected`&&!t)o.stores.notification.setProviderUsage(null),g=null;else{let t=r().model.provider;a.authStore.getAuthSource(t).then(n=>{if(r().model.provider!==t)return;let i=n===`oauth`?e:null;o.stores.notification.setProviderUsage(i),g=i}).catch(()=>{})}}}switch(t.type){case`turn.start`:D=0,k.reset(),ne(),o.engine.pushEngineEvent({kind:`spinnerMode`,mode:`requesting`});break;case`turn.end`:A(),u();break;case`streaming.start`:o.engine.pushEngineEvent({kind:`spinnerMode`,mode:`responding`}),o.pending.clearPendingEcho();break;case`streaming.end`:o.engine.pushEngineEvent({kind:`spinnerMode`,mode:null}),o.pending.clearPendingEcho();break;case`prompt.start`:A(),O=e(t.text),ne(),o.info.setTopView({session:r().id}),o.panes.clearEditedFiles(),o.plugins.clearSubagents(),j=l.messageIndex,o.info.addContextTurn({turnIndex:s.currentTurn,role:`assistant`,messageCount:0,estimatedTokens:0,compacted:!1,truncated:!1,pruned:!1});break;case`compaction.start`:T=t.messageCount,o.engine.pushEngineEvent({kind:`activeTool`,name:nt});break;case`compaction.end`:{let e=T??t.retainedCount,n=t.retainedCount;o.engine.pushEngineEvent({kind:`activeTool`,name:null}),n<e&&(o.messages.pushMessage({role:`compact_boundary`,before:e,after:n}),o.engine.pushEngineEvent({kind:`compactionLog`,entryKind:`compact`,before:e,after:n,summary:t.summary}),m()),T=void 0,u(void 0,{before:e,after:n});break}case`compaction.reactive.notice`:{let{messagesBefore:e,messagesAfter:n}=t;n<e&&(o.messages.pushMessage({role:`compact_boundary`,before:e,after:n}),o.engine.pushEngineEvent({kind:`compactionLog`,entryKind:`compact`,before:e,after:n,summary:t.summary}),m()),u(void 0,{before:e,after:n});break}case`image.degradation.notice`:t.degradedCount>0&&o.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`cmd.imageDegradationNotice`,{count:t.degradedCount,context:t.trigger===`image-constraint`?`image-constraint`:`other`}));break;case`session.history-capped`:o.messages.pushMessage({role:`history_capped`,removedCount:t.removedCount,trigger:t.trigger,...t.lossy?{lossy:!0}:{}}),o.engine.pushEngineEvent({kind:`compactionLog`,entryKind:`history_capped`,removedCount:t.removedCount});break;case`session.write-lease-denied`:_=!0,o.messages.pushMessage({role:`write_lease_denied`}),o.info.showToast(Q.t(`lease.deniedToastTitle`),Q.t(`lease.deniedToastBody`));break;case`session.write-lease-restored`:_=!1,o.messages.pushMessage({role:`write_lease_restored`}),o.info.showToast(Q.t(`lease.restoredToastTitle`),Q.t(`lease.restoredToastBody`));break;case`session.crash-gap-detected`:o.info.showToast(Q.t(`crashGap.toastTitle`),Q.t(`crashGap.toastBody`,{lostTurns:t.lostTurns}));break;case`run.pause_requested`:v=!0,y={at:Date.now(),toolCount:0},x(`requested`),o.engine.setPauseDialog?.({phase:`requested`,requestedAt:Date.now(),toolCount:0,onCancel:()=>{},onDismiss:()=>{o.engine.setPauseDialog?.(null)}}),b&&clearInterval(b),b=setInterval(()=>{if(!y){clearInterval(b),b=null;return}let e=Math.floor((Date.now()-y.at)/1e3);o.stores.notification.setPausePending({elapsedSec:e,toolCount:y.toolCount})},1e3);break;case`tool.call.end`:{let n=typeof t.resultTokensEstimate==`number`?t.resultTokensEstimate:t.resultText?e(t.resultText):0;n>0&&(te+=n,ne()),y&&(y.toolCount++,o.engine.setPauseDialog?.({phase:`requested`,requestedAt:y.at,toolCount:y.toolCount,onCancel:()=>{},onDismiss:()=>{o.engine.setPauseDialog?.(null)}})),(async()=>{try{let e={role:`tool_result`,name:t.toolCall.name,toolCallId:t.toolCall.id,content:[{type:`text`,text:t.resultText??``}],details:t.details},n=await a.resolveA2uiRendererPayload(e);n&&n.length>0&&o.messages.pushMessage({role:`assistant`,content:[{type:`a2ui`,components:n}]})}catch{}})();break}case`run.paused`:x(`paused`),y?(o.engine.setPauseDialog?.({phase:`active`,requestedAt:y.at,toolCount:y.toolCount,totalToolCount:y.toolCount}),o.messages.pushMessage({role:`run_paused`,toolCount:y.toolCount}),S(`run_paused`),b&&=(clearInterval(b),null),o.stores.notification.setPausePending(null),y=null):(o.messages.pushMessage({role:`run_paused`}),S(`run_paused`)),o.stores.notification.setPaused(!0);break;case`run.pause_cancelled`:x(`cancelled`),o.engine.setPauseDialog?.(null),o.messages.pushMessage({role:`run.pause_cancelled`}),S(`run_pause_cancelled`),b&&=(clearInterval(b),null),o.stores.notification.setPausePending(null),y=null,v=!1;break;case`run.resumed`:x(`resumed`),o.engine.setPauseDialog?.(null),o.messages.pushMessage({role:`run_resumed`}),S(`run_resumed`),b&&=(clearInterval(b),null),o.stores.notification.setPausePending(null),y=null,v=!1,o.stores.notification.setPaused(!1);break;case`steer.consumed`:o.pending.commitPendingSteer(t.id);break;case`image.vision-delegate`:!C&&t.describedCount>0&&(C=!0,o.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`model.visionDelegateToast`,{count:t.describedCount})));break;case`memory.pruned`:E||(E=!0,o.messages.pushMessage({role:`prune_boundary`})),o.engine.pushEngineEvent({kind:`compactionLog`,entryKind:`prune`,tokensSaved:t.tokensSaved,prunedCount:t.prunedCount}),u();break;case`error`:d(),f(),o.pending.withdrawPendingEcho();break;case`prompt.continued`:o.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`cmd.todoGateContinuing`,{round:t.round,cap:t.maxRounds,left:t.incompleteCount}));break;case`prompt.budget.notice`:t.steered&&o.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`cmd.promptBudgetExceeded`,{context:t.dimension,used:t.used,budget:t.budget}));break;case`budget.notice`:t.extended?o.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`cmd.budgetExtended`,{maxTurns:t.maxTurns})):t.steered&&o.info.showToast(Q.t(`cmd.titleInfo`),t.progressDenied?Q.t(`cmd.budgetProgressDenied`):Q.t(`cmd.budgetSteered`,{maxTurns:t.maxTurns}));break;case`progress.stall.notice`:o.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`cmd.progressStallDetected`,{maxRepeat:t.maxRepeat}));break;case`tool.call.mismatch.notice`:t.outcome===`retry`?o.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`cmd.toolCallMismatchRetry`,{retryCount:t.retryCount})):o.info.showToast(Q.t(`cmd.titleError`),Q.t(`cmd.toolCallMismatchTerminated`));break;case`session.cost-budget-exceeded`:o.info.showToast(Q.t(`cmd.titleInfo`),Q.t(`cmd.sessionCostBudgetExceeded`,{used:t.totalCostUSD.toFixed(2),budget:t.budgetUSD.toFixed(2)}));break;case`prompt.end`:A(),o.pending.clearPendingSteers(),u(),o.info.markContextTurns({turnIndex:s.currentTurn,messageCount:Math.max(0,l.messageIndex-j)}),d(),f(),p();{let e=r(),t=je(e.session.metadata().title,e.session.messages(),e.id);o.stores.tasks.setSessionTitle(t),o.lifecycle.setTerminalTitle(t)}if(process.env.OTTO_TUI_DEBUG_NOTIFY_STATS){let e=o.info.getNotifyStats();if(e.coalescedCalls>0){let t=(e.coalescedCalls/Math.max(1,e.coalescedFires)).toFixed(1);console.error(`\x1b[90m\x1b[2m[perf] notify merge ${e.coalescedCalls}→${e.coalescedFires} (${t}x) direct ${e.immediateCalls} flush ${e.flushFires}\x1b[0m`)}}{let e=a.settings.get(`pulse_survey`);a.feedbackRegistry.get()!==void 0&&Ht(s.currentTurn,{enabled:e?.enabled??!0,probability:e?.probability??.05,minTurnGap:e?.min_turn_gap??20,forcedUpgradeActive:o.info.isForcedUpgradeActive()},M)&&(M.lastShownTurn=s.currentTurn,o.stores.notification.setPulseSurvey({phase:`rating`,rating:null,selectedIndex:0,commentText:``,commentOffset:0,onSubmit:(e,t)=>{a.feedbackRegistry.get()?.recordPulseSurvey?.({ts:Date.now(),rating:e,comment:t,sdkVersion:qe,modelId:r().model?.id})},onClose:()=>o.stores.notification.setPulseSurvey(null)}))}break;case`ask.user.required`:{let e=t.question,n=t.requestId;(async()=>{let i=a.inquiryCenter;if(!i.enqueue({id:n,origin:{kind:`session`,sessionId:t.sessionId},question:e}).accepted){r().resolveAskUser(n,{answer:``,acceptedRecommendation:!1,resolvedBy:`human`});return}if(!await i.waitForTurn(n)){r().resolveAskUser(n,{answer:``,acceptedRecommendation:!1,resolvedBy:`human`});return}try{let t=await Hn(o,e);r().resolveAskUser(n,t)}finally{i.release(n)}})();break}case`approval.required`:{if(t.semanticVerdict){let e=Vt(t.description,t.arguments,ye);t.semanticVerdict===`allow`&&e&&a.approveSandboxBypass(e),a.logger?.info?.({approvalId:t.id,verdict:t.semanticVerdict,toolName:t.toolName},`Semantic approval verdict handled (no prompt)`);break}let e=t.toolName===`bash`&&typeof t.arguments?.command==`string`?t.arguments.command:``,n=e?a.bashAlwaysAllowPrefix(e):null;o.modal.requestPermission({tool:t.toolName,input:Vn(t.toolName,t.arguments),risk:t.risk??`medium`,description:t.description,alwaysAllowLabel:n??void 0}).then(e=>{let i=Vt(t.description,t.arguments,ye);e.approved&&i&&a.approveSandboxBypass(i),r().resolveApproval(t.id,e.approved),e.approved&&e.mode===`always`&&(t.toolName===`bash`?n&&a.allowToolAlways(`bash(${n})`,r().id):a.allowToolAlways(t.toolName,r().id))});break}}})},getSessionUnsub:()=>R,getLastProviderUsage:()=>g,isWriteLeaseReadOnly:()=>_,isRunPaused:()=>v}}function Wn(e){let t=(t,n)=>{e.onError?.(t,n)},n=async n=>{let r=e.gateway(),i=e.bridge();if(!(!r||!i))try{let e=await r.getPaste(n);i.hydratePaste({entries:e.entries,nextId:e.nextId})}catch(e){t(`load`,e);try{i.hydratePaste(null)}catch{}}},r=async n=>{let r=e.gateway(),i=e.bridge();if(!(!r||!i))try{let e=i.exportPaste();if(!e)return;await r.setPaste(n,{sessionId:n,entries:e.entries,nextId:e.nextId})}catch(e){t(`save`,e)}};return{load:n,save:r,async switchTo(e,t){e!==t&&(e!==void 0&&await r(e),await n(t))},async fork(n,r){let i=e.gateway(),a=e.bridge();if(!(!i||!a))try{let e=a.exportPaste()??await i.getPaste(n);await i.setPaste(r,{sessionId:r,entries:e.entries,nextId:e.nextId})}catch(e){t(`fork`,e)}}}}function Gn(e){e.setEcosystemSearch(async t=>{try{let{registries:n,warnings:r}=await K(e).loadAll();return{hits:X(n.flatMap(e=>e.entries.map(t=>({entry:t,registry:e}))).map(e=>({text:e.entry.id,aliases:[e.entry.description,...e.entry.keywords??[]],payload:e})),t.join(` `),{maxResults:8}).map(e=>({id:e.item.payload.entry.id,description:e.item.payload.entry.description,capabilities:e.item.payload.entry.capabilities,sourceName:e.item.payload.registry.sourceName,stale:e.item.payload.registry.stale})),warnings:r}}catch{return}})}function Kn(e){let{app:t,tui:n}=e;t.setMcpStartupCallback(e=>{let r=[`HTTP_PROXY`,`HTTPS_PROXY`,`http_proxy`,`https_proxy`].find(e=>process.env[e]),i=r?process.env[r]:void 0,a=t.settings.get(`proxy`);i&&r&&!a?.url&&(he(i,r),n.info.showToast(Q.t(`proxy.title`),Q.t(`proxy.envDetectedToast`,{source:r,value:i})))})}function qn(e){let{app:t,tui:n,session:r}=e;n.plugins.registerArgumentSuggester(`model`,(e,n=20)=>X(t.modelRegistry.getAll().filter(e=>e.id!==`__otto_setup__`).map(e=>({text:e.id,aliases:[e.name,e.provider],payload:e})),e,{maxResults:n}).map(e=>({name:e.item.payload.id,description:e.item.payload.name})));let i=je(r.session.metadata().title,r.session.messages(),r.id);n.lifecycle.setTerminalTitle(i),n.stores.tasks.setSessionTitle(i)}function Jn(e){let{app:t,tui:n,getScheduler:r}=e;n.plugins.registerArgumentSuggester(`schedule`,(e,t=20)=>{let n=[`remove`,`run`,`enable`,`disable`],i=n.find(t=>e.toLowerCase().startsWith(`${t} `));if(!i)return X([...n,`list`,`add`,`logs`].map(e=>({text:e,aliases:[],payload:e})),e,{maxResults:t}).map(e=>({name:e.item.payload}));let a=r();if(!a)return[];let o=e.slice(i.length+1);return X(a.list().map(e=>({text:e.id,aliases:[e.name],payload:e})),o,{maxResults:t}).map(e=>({name:`${i} ${e.item.payload.id}`,description:e.item.payload.name}))}),n.plugins.registerArgumentSuggester(`replay`,(e,n=20)=>X(t.listSessions().map(e=>({text:e.id,aliases:e.title?[e.title]:[],payload:e})),e,{maxResults:n}).map(e=>({name:e.item.payload.id,description:e.item.payload.title??e.item.payload.id.slice(0,8)}))),n.plugins.registerArgumentSuggester(`session`,(e,n=20)=>{let r=e.toLowerCase().startsWith(`unlock `)?e.slice(7):e;return r===e?X([{name:`fork`,description:`Fork current session into a named branch`},{name:`unlock`,description:`Write-lease diagnostics/force-unlock`},{name:`kill`,description:`Terminate a session`},{name:`inspect`,description:`Read-only remote snapshot preview`},{name:`pin`,description:`Toggle pin state (pinned sort to top of session list)`},{name:`archive`,description:`Toggle archive state`},{name:`resume`,description:`List and switch to an existing session`},{name:`compact`,description:"Compact context now (or `compact log` for details)"},{name:`context`,description:`Show context usage breakdown`}].map(e=>({text:e.name,aliases:[],payload:e})),e,{maxResults:n}).map(e=>({name:e.item.payload.name,description:e.item.payload.description})):X(t.listSessions().map(e=>({text:e.id,aliases:e.title?[e.title]:[],payload:e})),r,{maxResults:n}).map(e=>({name:`unlock ${e.item.payload.id}`,description:e.item.payload.title??e.item.payload.id.slice(0,8)}))}),n.plugins.registerArgumentSuggester(`status`,(e,t=20)=>X([`perf`,`cache`,`diagnose`,`services`].map(e=>({text:e,aliases:[],payload:e})),e,{maxResults:t}).map(e=>({name:e.item.payload}))),n.plugins.registerArgumentSuggester(`preference`,(e,t=20)=>X([`general`,`lang`,`theme`,`keybindings`,`shortcuts`,`proxy`].map(e=>({text:e,aliases:[],payload:e})),e,{maxResults:t}).map(e=>({name:e.item.payload}))),n.plugins.registerArgumentSuggester(`extension`,(e,n=20)=>{let r=e.toLowerCase();if(r.startsWith(`trust plugin `)){let r=e.slice(13);return X(me({cwd:t.workspaceDir??process.cwd(),homedir:ge()}).map(e=>({text:e.id,aliases:[],payload:e})),r,{maxResults:n}).map(e=>({name:`trust plugin ${e.item.payload.id}`,description:e.item.payload.scope}))}if(r.startsWith(`trust `)){let t=e.slice(6);return X([`status`,`trust`,`untrust`,`plugin`].map(e=>({text:e,aliases:[],payload:e})),t,{maxResults:n}).map(e=>({name:`trust ${e.item.payload}`}))}if(r.startsWith(`registry `)){let t=e.slice(9);return X([`list`,`add`,`remove`].map(e=>({text:e,aliases:[],payload:e})),t,{maxResults:n}).map(e=>({name:`registry ${e.item.payload}`}))}return X([`trust`,`install`,`registry`,`search`,`update`,`reload`].map(e=>({text:e,aliases:[],payload:e})),e,{maxResults:n}).map(e=>({name:e.item.payload}))}),n.plugins.registerArgumentSuggester(`registry`,(e,n=20)=>{let r=e.toLowerCase().startsWith(`remove `)?e.slice(7):e;return r===e?X([`list`,`add`,`remove`].map(e=>({text:e,aliases:[],payload:e})),e,{maxResults:n}).map(e=>({name:e.item.payload})):X(K(t).listSources().filter(e=>!e.builtin).map(e=>({text:e.name,aliases:[e.url],payload:e})),r,{maxResults:n}).map(e=>({name:`remove ${e.item.payload.name}`,description:e.item.payload.url}))}),n.plugins.registerArgumentSuggester(`trust`,(e,n=20)=>{let r=e.toLowerCase().startsWith(`plugin `)?e.slice(7):e;return r===e?X([`status`,`trust`,`untrust`,`plugin`].map(e=>({text:e,aliases:[],payload:e})),e,{maxResults:n}).map(e=>({name:e.item.payload})):X(me({cwd:t.workspaceDir??process.cwd(),homedir:ge()}).map(e=>({text:e.id,aliases:[],payload:e})),r,{maxResults:n}).map(e=>({name:`plugin ${e.item.payload.id}`,description:e.item.payload.scope}))})}function Yn(e){let t=e[e.length-1];if(t?.type===`message`&&t.message?.role===`user`)return{parentId:t.parentId}}function Xn(e,t){!t||!t.newer||(e.stores.tasks.setUpdateAvailable(t),t.forced?(e.info.pushNotification(Q.t(`cmd.titleUpdate`),Q.t(`cmd.updateNotifForced`,{latest:t.latest,current:t.current}),`version`,`error`),e.stores.tasks.setForcedUpgrade(Q.t(`cmd.updateForcedBanner`,{latest:t.latest,current:t.current})),e.stores.notification.setPulseSurvey(null)):(e.info.pushNotification(Q.t(`cmd.titleUpdate`),Q.t(`cmd.updateNotifAvailable`,{latest:t.latest,current:t.current}),`version`,`info`),e.info.showToast(Q.t(`cmd.titleUpdate`),Q.t(`cmd.updateToast`,{latest:t.latest}))))}async function Zn(e){let{tui:t,options:n,app:r,session:i,projState:a,resumedNote:o,resumed:s,updateCheckPromise:c,bg:l,events:u}=e;if(o&&g({resumedNote:o,isFound:!!s,session:i,projState:a,tui:t}),n.resumePrompt&&s)if(r.memoryGovernor.sample().level===`critical`)t.info.showToast(Q.t(`cmd.titleMemoryPressure`),Q.t(`cmd.memoryPressureResumeAbortedMessage`));else{let e=Yn(i.session.branchEntries());e&&(e.parentId&&i.session.branch(e.parentId),i.prompt(n.resumePrompt).catch(e=>{r.logger.warn({err:e instanceof Error?e.message:String(e)},`[memory-governor] auto-resume prompt failed`),t.info.showToast(Q.t(`cmd.titleError`),Q.t(`cmd.memoryPressureResumeFailedMessage`))}))}c.then(e=>Xn(t,e)),l.setBgUnsubs(u.bgUnsubs),u.attachSessionHandler(),Qn(t,r)}function Qn(e,t){p(n=>{if(n.status!==`needs-input`)return;let r=n.id.slice(0,8),i=t.listSessions().find(e=>e.id===n.id)?.title??r;e.info.pushNotification(`session needs input`,`Background session '${i}' (${r}) requires your input (/resume ${r})`,`system`,`warning`)}),t.hookRegistry.on(`session.deleted`,`rfc234-background-cleanup`,e=>{m(e.sessionId)})}function $n(e){return e.startsWith(`backend/`)?e.slice(8):e}function er(e){let t=()=>({tasks:e.list(),runningTaskIds:[...e.getRunningTaskIds()],isFireOwner:e.isFireOwner(),fireOwnerFailureReason:e.fireOwnerFailureReason()});return{call:async(n,r)=>{let i=$n(n);switch(i){case`schedule.list`:return t();case`schedule.add`:{let t=r;try{let n=e.add({name:t.name,prompt:t.prompt,cronExpression:t.cronExpression,recurring:t.recurring,origin:`user`,target:t.target});return{ok:!0,taskId:n.id,name:n.name,target:n.target}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}}case`schedule.update`:{let t=r,n={};return t.name!==void 0&&(n.name=t.name),t.prompt!==void 0&&(n.prompt=t.prompt),t.cronExpression!==void 0&&(n.cronExpression=t.cronExpression),t.enabled!==void 0&&(n.enabled=t.enabled),{ok:e.update(t.taskId,n)}}case`schedule.runNow`:{let{taskId:t}=r;return e.runNow(t),{ok:!0}}case`schedule.toggle`:{let{taskId:t,enabled:n}=r;return{ok:e.update(t,{enabled:n})}}case`schedule.cancel`:{let{taskId:t}=r;return e.cancel(t)}case`schedule.remove`:{let{taskId:t}=r;return{ok:e.remove(t)}}case`schedule.readLogs`:{let{taskId:t,limit:n}=r;return{entries:e.readFireLogs(t,n??20)}}case`schedule.parseCron`:{let{expr:e}=r;try{return{ok:!0,next:Ft(e).toISOString()}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}}default:throw Error(`unknown schedule backend method: ${i}`)}},getSnapshot:t}}function tr(e){return t=>{let n=e.value;if(n.id!==t.boundSessionId||n.isPaused||n.status===`archived`)return!1;try{return n.prompt(t.prompt,{streamingBehavior:`followUp`}).catch(()=>{}),!0}catch{return!1}}}function nr(e,t,n,r){let i=e.workspaceRef?.key??`default`,a=new kt,o,s;if(e.storage.remoteSessionConfigured&&r){let e=async()=>({token:r.sessionToken});o=Nt({sessionUrl:r.sessionUrl,getAuth:e,wsKey:i}),s=Mt({sessionUrl:r.sessionUrl,wsKey:i,getAuth:e})}else o=Pt(i),s=jt(i);let c=new At({registry:a,store:o,ownership:s,jobRegistry:Pe,startJob:t=>({id:e.agentJobs.start({title:t.title,prompt:t.prompt,sessionId:t.sessionId,origin:t.origin}).id}),getSessionId:()=>t.value.id,notifySubscriber:(t,n)=>e.notifyPluginServiceSchedule({pluginId:t.pluginId,serviceId:t.serviceId},n),followUpCurrentSession:tr(t),retryBackoffMs:e.getResilienceConfig().schedule.retryBackoffMs});c.start().catch(e=>{console.error(`\x1b[3m\x1b[2m[schedule] scheduler failed to start: ${e instanceof Error?e.message:String(e)}\x1b[0m`)}),V(c),e.setScheduleService(c);let l=er(c);e.panelBackendController.registerInProcessBackend(`plugin-schedule`,l.call);let u=setInterval(()=>{if(!n)return;let e=c.list().map(e=>({id:e.id,name:e.name,prompt:e.prompt,cronExpression:e.cronExpression,enabled:e.enabled,recurring:e.recurring,nextFireAt:e.nextFireAt,lastFiredAt:e.lastFiredAt,lastFireFailed:e.lastFireFailed,lastFireError:e.lastFireError,lastFireCancelled:e.lastFireCancelled}));n.stores.tasks.setScheduleTasks(e)},5e3);return u.unref(),{pollInterval:u,scheduler:c}}function rr(e){let{app:t,session:n,options:r,tui:i,memoryConflictRef:a,turn:o,stopController:s,runAsyncBashRef:c,handleAbortInterceptRef:l,runMemoryCaptureRef:u,schedulePollIntervalRef:d,scheduleServiceRef:f}=e;a&&(a.current=(e,t)=>{i.info.showToast(`Memory Conflict`,`Concurrent edit detected for ${e} — saved to ${t}`)}),Be(`startTui() ready (first frame mounted)`),t.setUserAskRenderer(e=>Hn(i,e));let p=Wn({gateway:()=>t.sessionManager.panelState,bridge:()=>i.pending,onError:(e,n)=>{t.logger?.debug?.({stage:e,error:n},`paste cache binding failed (non-fatal)`)}});Kn({app:t,tui:i}),Gn(t),t.listAllSessions().then(e=>{let t=n.id,r=e.filter(e=>e.status!==`archived`&&(e.entryCount??e.messageCount)>0&&e.id!==t).slice(0,10).map(e=>({id:e.id,title:e.title??e.id.slice(0,8),status:e.id===t?`busy`:`idle-cold`,lastActivityAt:e.updatedAt?new Date(e.updatedAt).toLocaleString():``,isCurrent:e.id===t,isPinned:e.pinned??!1,isArchived:e.status===`archived`,isReadOnly:e.writeLocked??!1}));i.stores.tasks.setSessionList(r)}).catch(()=>{});let{pollInterval:m,scheduler:h}=nr(t,{get value(){return n}},i,r.sessionUrl&&r.sessionToken?{sessionUrl:r.sessionUrl,sessionToken:r.sessionToken}:void 0);return d.current=m,f.current=h,c.current=Mn({tui:i,app:t,submitState:o}),l.current=Nn({agentProcessingRef:{get value(){return o.agentProcessing},set value(e){o.agentProcessing=e}},tui:i,requestStop:e=>s.requestStop(e)}),u.current=Pn({app:t,tui:i}),qn({app:t,tui:i,session:n}),Jn({app:t,tui:i,getScheduler:()=>h}),{pasteBinder:p}}const ir=[`approaching`,`nearing`,`critical`],ar={maxReminders:{approaching:1,nearing:3,critical:1},backoffBaseTurns:4,resetMarginPct:10,approachingMarginPct:10};function $(){return{count:0,lastRemindedTurn:void 0,peakPct:0,active:!1}}function or(e,t,n,r){return e>=n?`critical`:e>=t?`nearing`:e>=t-r?`approaching`:null}function sr(e,t,n,r){return e===`critical`?n:e===`nearing`?t:t-r}function cr(e,t){return t<=1?0:e.backoffBaseTurns*2**(t-2)}var lr=class{config;zones;suppressed=!1;constructor(e={}){this.config={...ar,...e},this.zones={approaching:$(),nearing:$(),critical:$()}}check(e){if(this.suppressed)return null;let{contextPercent:t,pruneLinePct:n,compactLinePct:r,currentTurn:i}=e,a=or(t,n,r,this.config.approachingMarginPct);for(let e of ir)e!==a&&this.zones[e].active&&t<sr(e,n,r,this.config.approachingMarginPct)-this.config.resetMarginPct&&(this.zones[e]=$());if(a===null)return null;let o=this.zones[a];o.lastRemindedTurn!==void 0&&i<o.lastRemindedTurn&&(this.zones[a]=$());let s=this.zones[a];s.active=!0,s.peakPct=Math.max(s.peakPct,t);let c=this.config.maxReminders[a];if(s.count>=c)return null;let l=s.count+1;if(s.lastRemindedTurn!==void 0){let e=cr(this.config,l);if(i-s.lastRemindedTurn<e)return null}return s.count=l,s.lastRemindedTurn=i,{zone:a,pct:Math.round(t)}}onCompacted(){this.zones={approaching:$(),nearing:$(),critical:$()}}suppress(){this.suppressed=!0}snapshot(){return{approaching:{count:this.zones.approaching.count,lastTurn:this.zones.approaching.lastRemindedTurn},nearing:{count:this.zones.nearing.count,lastTurn:this.zones.nearing.lastRemindedTurn},critical:{count:this.zones.critical.count,lastTurn:this.zones.critical.lastRemindedTurn}}}};function ur(e){let{getSession:t,app:n,tui:r,projState:i,contextWindow:a,currentModelId:o}=e,s,c=new lr,l={approaching:e=>Q.t(`cmd.contextPressureApproaching`,{pct:e}),nearing:e=>Q.t(`cmd.contextPressureNearing`,{pct:e}),critical:e=>Q.t(`cmd.contextPressureCritical`,{pct:e})},u=()=>{let e=t(),n=e.session.messages(),r=0,i=0,a=0,o=0,s=!1,c=0,l=0;for(let e=n.length-1;e>=0;e--){let t=n[e]?.usage;t&&(s||=(r=t.inputTokens??0,i=t.outputTokens??0,a=t.cacheReadTokens??0,o=t.cacheWriteTokens??0,!0),n[e]?.role===`assistant`&&(c+=t.inputTokens??0,l+=t.outputTokens??0))}return{sessionId:e.session.id,lastIn:r,lastOut:i,lastCacheRead:a,lastCacheWrite:o,totIn:c,totOut:l,messageCount:n.length}},d=(e,d)=>{let f=e!==void 0,p=f&&s&&s.sessionId===t().session.id?s:u();s=p;let m=d?d.before:1,h=d?d.after/m:1,g=e=>h<1?Math.round(e*h):e,v=n.modelRegistry.find(o.value??``)?.cost,y=v?p.totIn*(v.input??0)+p.totOut*(v.output??0):0,b=_({systemPrompt:t().systemPrompt,tools:t().tools,lastIn:g(p.lastIn),lastOut:g(p.lastOut),lastCacheRead:g(p.lastCacheRead),lastCacheWrite:g(p.lastCacheWrite),contextWindow:a.value,modelName:t().model?.name??``,totIn:p.totIn,totOut:p.totOut,cost:y>0?y:void 0,messageCount:p.messageCount,streamingOutputTokens:e});if(r.stores.budget.setBudget(b),r.stores.context.setBudget(b),!f&&b.contextWindow>0){let e=b.pruneLine/b.contextWindow*100,t=b.compactLine/b.contextWindow*100,n=c.check({contextPercent:b.contextPercent,pruneLinePct:e,compactLinePct:t,currentTurn:i.currentTurn});n&&r.info.pushNotification(Q.t(`cmd.titleContextPressure`),l[n.zone](n.pct),`system`,n.zone===`critical`?`warning`:`info`)}},f=()=>{try{t().session.setEditedFiles(r.messages.getEditedFiles().map(e=>({path:e.path,operation:e.operation,addedLines:e.addedLines,removedLines:e.removedLines,timestamp:e.timestamp,toolCallId:e.toolCallId}))),n.sessionManager.save(t().id).catch(()=>{})}catch(e){console.error(`\x1b[90m\x1b[2m[persist] editedFiles skipped (non-fatal): ${e instanceof Error?e.message:String(e)}\x1b[0m`)}};return{recomputeBudget:d,persistEditedFiles:f,persistSubagents:()=>{try{let e=[...r.plugins.getSubagents().values()].map(e=>({id:e.id,name:e.command||e.id,status:yt(e),startedAt:e.startedAt}));t().session.setSubagents(e),n.sessionManager.save(t().id).catch(()=>{})}catch(e){console.error(`\x1b[90m\x1b[2m[persist] subagents skipped (non-fatal): ${e instanceof Error?e.message:String(e)}\x1b[0m`)}},persistTurnCount:()=>{try{t().session.setTurnCount(i.currentTurn)}catch(e){console.error(`\x1b[90m\x1b[2m[persist] turnCount skipped (non-fatal): ${e instanceof Error?e.message:String(e)}\x1b[0m`)}},editFileCallback:e=>{try{r.stores.tasks.addEditedFile({path:e.path,operation:e.operation,oldContent:e.oldContent,newContent:e.newContent,addedLines:e.addedLines,removedLines:e.removedLines,timestamp:e.timestamp,toolCallId:e.toolCallId})}catch(e){console.error(`\x1b[90m\x1b[2m[panel] addEditedFile skipped (non-fatal): ${e instanceof Error?e.message:String(e)}\x1b[0m`)}f()},onContextCompacted:()=>{c.onCompacted()}}}function dr(e){let{tui:t,app:n,themeRegistry:r,sessionRef:i,interactiveRef:a,regRef:s,slashCommandsRef:c,modelReadyRef:l,currentModelIdRef:u,currentLangRef:d,projState:f,agentProcessingRef:p,modelsRef:m,availableModelIds:h,restartRequestedRef:g,applyModel:_,persistAvailable:v,refreshModelsNow:y,refreshSlashCommands:b,events:x,redState:C,agentMessagesToChatMessages:w,PROVIDER_DISPLAY_NAMES:ee,apiCredentialId:T,onContextCompacted:E}=e;return{tui:t,app:n,state:{get session(){return i.value},set session(e){i.value=e},get interactive(){return a.value},set interactive(e){a.value=e},get reg(){return s.value},set reg(e){s.value=e},get slashCommands(){return c.value},set slashCommands(e){c.value=e},get modelReady(){return l.value},set modelReady(e){l.value=e},get currentModelId(){return u.value},set currentModelId(e){u.value=e},get currentLang(){return d.value},set currentLang(e){d.value=e},get todoList(){return f.todoList},set todoList(e){f.todoList=e},get agentProcessing(){return p.value},set agentProcessing(e){p.value=e},get models(){return m.value},set models(e){m.value=e},get availableModelIds(){return h},get restartRequested(){return g.value},set restartRequested(e){g.value=!!e},themeRegistry:r},callbacks:{applyModel:_,persistAvailable:v,refreshModelsNow:y,registerAllTuiCommands:()=>{Xt(s.value)},refreshSlashCommands:b,attachSessionHandler:()=>x.attachSessionHandler(),restoreSwitchedSession:()=>{f.delegated.clear(),f.todoList=[],f.currentTurn=0,Object.assign(C,S()),t.stores.tasks.setTasks([],void 0),t.panes.clearEditedFiles(),t.plugins.clearSubagents(),o({session:i.value,projState:f,tui:t}),E()},resetCurrentTurn:()=>{f.currentTurn=0},onContextCompacted:E,sessionUnsub:()=>x.getSessionUnsub(),getLastProviderUsage:()=>x.getLastProviderUsage(),isWriteLeaseReadOnly:()=>x.isWriteLeaseReadOnly(),isRunPaused:()=>x.isRunPaused(),agentMessagesToChatMessages:w,PROVIDER_DISPLAY_NAMES:ee,apiCredentialId:T}}}function fr(e){let{session:t,tui:n,retryAccelerate:r,setRateLimitInfo:i,abortNow:a}=e;t.coreAgent.on(`stream.retry`,({attempt:e,maxRetries:t,delayMs:i,reason:o})=>{n.engine.showRetryDialog(e,t,i,r,()=>{n.engine.clearRetryDialog()},o,()=>{a()})}),t.coreAgent.on(`rate.limit.exhausted`,({limitType:e,resetsAt:t})=>{n.engine.clearRetryDialog(),i({limitType:e,resetsAt:t})}),t.coreAgent.on(`lifecycle.tool.completed.crossBoundary`,({toolName:e,result:t})=>{let r=Q.t(`cmd.titleBackgroundTask`),i=t.isError?Q.t(`cmd.lifecycleCrossBoundaryFailed`,{toolName:e}):Q.t(`cmd.lifecycleCrossBoundaryDone`,{toolName:e});n.info.showToast(r,i)})}function pr(e,t){let n=process.env[e];if(!n)return t;let r=Number(n);return Number.isFinite(r)&&r>0?r:t}function mr(e,t){let n=process.env[e];if(!n)return t;let r=Number(n);return Number.isFinite(r)&&r>0&&Number.isInteger(r)?r:t}function hr(e){let{app:t,tui:n,getSession:r,setRestartResumePrompt:i,setRestartMemoryTriggered:a,handleExit:o,onContextCompacted:c,recomputeBudget:l}=e,u=!1,d=0,f,p=!1,m=0,h=!1,g=pr(`OTTO_MEMORY_CRITICAL_NOTIFY_INTERVAL_MS`,18e5),_=mr(`OTTO_MEMORY_CRITICAL_NOTIFY_ESCALATION_CYCLES`,4),v,y=()=>{let e=r();if(e.isBusy){let t=e.session.messages(),n=t[t.length-1];if(n?.role===`user`&&!n.internal){let e=s(n.content);e&&i(e)}}a(!0),o({type:`exit`,restart:!0})},b=()=>{v&&=(clearInterval(v),void 0),m=0,h=!1};t.memoryGovernor.setCallbacks({onWarning:()=>{r().compactNow().then(e=>{e.compacted&&(n.info.showToast(Q.t(`cmd.titleAutoCompact`),Q.t(`compact.edResult`,{before:e.before,after:e.after})),c(),l())}).catch(e=>{let r=e instanceof Error?e.message:String(e);t.logger.warn({err:r},`[memory-governor] compactNow (soft degrade) failed`),n.info.showToast(Q.t(`cmd.titleAutoCompact`),Q.t(`cmd.autoCompactFailed`,{msg:r}))})},onCritical:e=>{if(u){n.info.pushNotification(Q.t(`cmd.titleMemoryPressure`),Q.t(`cmd.memoryPressureMessage`,{usedPct:e.usedPct.toFixed(0)}),`system`,`info`);return}n.info.isFullScreenPaneActive()&&(d++,f??=Date.now(),d<3&&Date.now()-f<300*1e3)||(d=0,p=!0,n.modal.openModal({kind:`confirm`,title:Q.t(`cmd.titleMemoryPressure`),message:Q.t(`cmd.memoryPressureMessage`,{usedPct:e.usedPct.toFixed(0)}),confirmLabel:Q.t(`cmd.memoryPressureRestartNow`),cancelLabel:Q.t(`cmd.memoryPressureRemindLater`),confirmColor:`amber`,extraLabel:Q.t(`cmd.memoryPressureSuppress`),onConfirm:()=>{p=!1,b(),y()},onCancel:()=>{p=!1},onExtra:()=>{p=!1,u=!0}}))},onCriticalDuringGrace:e=>{n.info.pushNotification(Q.t(`cmd.titleMemoryPressure`),Q.t(`cmd.memoryPressureMessage`,{usedPct:e.usedPct.toFixed(0)}),`system`,`warning`)},onCriticalTimeout:e=>{if(p){p=!1,y();return}let i=()=>{m++,n.info.pushNotification(Q.t(`cmd.titleMemoryPressure`),Q.t(`cmd.memoryPressureMessage`,{usedPct:t.memoryGovernor.sample().usedPct.toFixed(0)}),`system`,`warning`),!h&&m>=_&&(h=!0,r().compactNow().catch(e=>{let n=e instanceof Error?e.message:String(e);t.logger.warn({err:n},`[memory-governor] critical-unattended-escalation compactNow failed`)}),t.storage.traceStore?.append(r().id,{ts:Date.now(),sessionId:r().id,kind:`lifecycle`,node:`critical-unattended-escalation`,payload:{usedPct:e.usedPct,cycles:m}}).catch(e=>{t.logger.warn({err:e instanceof Error?e.message:String(e)},`[memory-governor] critical-unattended-escalation trace append failed`)}))};v||(i(),v=setInterval(i,g),v.unref?.())},onLevelChange:e=>{e!==`critical`&&(d=0,f=void 0,b()),n.engine.pushEngineEvent({kind:`perf`,indicatorLevel:e,memory:t.memoryGovernor.sample()})}}),t.fleetMonitor.setCallbacks({onBudgetExceeded:e=>{n.info.pushNotification(Q.t(`cmd.titleFleetBudget`),Q.t(`cmd.fleetBudgetExceeded`,{processCount:e.processCount,totalRssMb:e.totalRssMb}),`system`,`warning`)}})}async function gr(e){let{app:t,options:n,tui:r,tuiRef:i,turn:a,projState:o,redState:s,stopController:c,themeRegistry:l,availableModelIds:u,applyModel:f,refreshSlashCommands:p,retryAccelerate:m,startupCrashGapRef:h,resumedNote:g,resumed:_,updateCheckPromise:v,bg:y,ftueController:b,refreshModelsNow:S,persistAvailable:C,cfgLang:ee,sessionRef:T,interactiveRef:E,regRef:D,slashCommandsRef:O,modelReadyRef:te,currentModelIdRef:k,currentLangRef:A,modelsRef:j,restartRequestedRef:M,restartMemoryTriggeredRef:N,restartResumePromptRef:P,pushBudgetNowRef:F,staleBuildDetectorRef:I,eventsRef:re,cliCtxRef:z,handleExitRef:ie,pasteBinder:B,contextWindowRef:ae}=e;ie.current=e=>{c.requestStop(e.restart?`exit-restart`:`exit`)},n.memoryRestartGrace&&t.memoryGovernor.markRestarted();let V=n.restartGeneration??0;V>=3&&r.info.pushNotification(Q.t(`cmd.titleFleetBudget`),Q.t(`cmd.restartChainDeep`,{generation:V}),`system`,`warning`),r.engine.pushEngineEvent({kind:`perf`,indicatorLevel:t.memoryGovernor.currentLevel,memory:t.memoryGovernor.sample()}),fr({session:T.value,tui:r,retryAccelerate:m,setRateLimitInfo:e=>{a.lastRateLimitInfo=e},abortNow:()=>{c.abortNow()}});let oe=ur({getSession:()=>T.value,app:t,tui:r,projState:o,contextWindow:ae,currentModelId:k}),{recomputeBudget:H,persistEditedFiles:ce,persistSubagents:le,persistTurnCount:U,onContextCompacted:ue}=oe;F.value=H,H(),t.editFileCallback=oe.editFileCallback,hr({app:t,tui:r,getSession:()=>T.value,setRestartResumePrompt:e=>{P.value=e},setRestartMemoryTriggered:e=>{N.value=e},handleExit:ie.current,onContextCompacted:ue,recomputeBudget:H}),t.registerInAppNotificationChannel((e,t,n)=>r.info.pushNotification(e,t,`system`,w(n))),t.setFollowUpPendingProbe(()=>r.engine.hasQueuedFollowUp());let W=Un({getSession:()=>T.value,app:t,tui:r,projState:o,redState:s,recomputeBudget:H,persistEditedFiles:ce,persistSubagents:le,persistTurnCount:U,onContextCompacted:ue,markStreamed:()=>{a.streamedText=!0}});re.value=W,z.current=dr({tui:r,app:t,themeRegistry:l,sessionRef:T,interactiveRef:E,regRef:D,slashCommandsRef:O,modelReadyRef:te,currentModelIdRef:k,currentLangRef:A,projState:o,agentProcessingRef:{get value(){return a.agentProcessing},set value(e){a.agentProcessing=e}},modelsRef:j,availableModelIds:u,restartRequestedRef:M,applyModel:f,persistAvailable:C,refreshModelsNow:S,refreshSlashCommands:p,events:W,redState:s,agentMessagesToChatMessages:x,PROVIDER_DISPLAY_NAMES:d,apiCredentialId:be,onContextCompacted:ue}),z.current.callbacks.pasteBinder=B,B.load(T.value.id),r.plugins.setPluginRegistrations(t.getPluginRegistrations());let de=await b.refresh();if(i.value?.stores.tasks.setFtueStage(de.stage),ne(de)&&ee===`auto`&&!t.settings.get(`has_completed_onboarding`)){let e=await r.modal.openModal({kind:`onboarding`,onLanguagePreview:e=>{let t=e===`auto`?se():e;L(t),r.lifecycle.setLanguage(t),A.value=t}});if(e.nickname&&t.settings.persist({nickname:e.nickname}).catch(()=>{}),e.language){let n=e.language===`auto`?se():e.language;L(n),r.lifecycle.setLanguage(n),A.value=n,t.settings.persist({language:e.language}).catch(()=>{})}t.settings.persist({has_completed_onboarding:!0}).catch(()=>{})}de.recommendation.autoOpen&&R(`setup`,[],z.current);let fe=nn();fe&&(I.current=new rn({repoRoot:fe,currentBuildId:We,logger:t.logger,onStale:e=>{r.info.pushNotification(Q.t(`cmd.titleStaleBuild`),Q.t(`cmd.staleBuildMessage`,{current:We,latest:e}),`system`,`info`)}}),I.current.start()),await Zn({tui:r,options:n,app:t,session:T.value,projState:o,resumedNote:g,resumed:_??void 0,updateCheckPromise:v,bg:y,events:W}),h.value&&r.info.showToast(Q.t(`crashGap.toastTitle`),Q.t(`crashGap.toastBody`,{lostTurns:h.value.lostTurns}))}async function _r(e,t,n){let r=!1,i=!1,o,s={get value(){return r},set value(e){r=!!e}},c={get value(){return i},set value(e){i=e}},l={get value(){return o},set value(e){o=e}},d;try{let f=await _n(t,{continueSession:e.continueSession,model:e.model,sessionUrl:e.sessionUrl}),p=f.SETUP_PLACEHOLDER_ID,m=f.session,h=f.startupCrashGapRef,g=f.resumedNote,_=f.modelReadyRef,v=_.value,y=f.ftueController,x=f.refreshModelsNow,C=f.modelRefreshState,w=C.availableModelIds,ee=f.persistAvailable,E=C.models,D=f.continuedExisting,te=f.retryAccelerate,k=f.resumed,ne=f.convoCount,j=f.tuiRefBox,M=j,N=v?m.model?.id:void 0,P=t.modelRegistry.getAll().filter(e=>e.id!==p).find(e=>e.id===N)?.contextWindow??0,F={get value(){return P},set value(e){P=e}},I=N,re={get value(){return I},set value(e){I=e}},R=e=>u(t,e,m.thinkingLevel),z,ie={get value(){return z},set value(e){z=e}},V={value:void 0},H={value:e},le=e=>{switch(e.kind){case`steer`:m.steer(e.input);break;case`abort`:pe.abort();break;case`pauseAfterTurn`:m.pauseRun();break;case`resumeRun`:m.resumeRun();break}},W=b({modelReady:_,currentModelId:re,contextWindow:F,tuiRef:j,pushBudgetNow:ie,app:t,getSession:()=>m,options:H,fmtDisplayModel:R,onEngineModelAction:le}),fe=a({getSession:()=>m,app:t,tuiRef:j,options:H,fmtDisplayModel:R,applyModel:W,onExitSession:()=>V.value?.()}),pe=new ae(m,{models:E,currentModel:N,onModelChange:W}),{startTui:me}=await import(`@x-otto/tui`),G=pe.getRegistry();Xt(G);let he=T(G,t),K={agentProcessing:!1,ctrlCCount:0,lastCtrlCTime:0,userAborted:!1,shellChild:null,streamedText:!1,retryMode:!1,errorRetryAttempt:0,lastRateLimitInfo:void 0,latestSubmittedPrompt:void 0},ge=()=>Gt(m.isBusy,K.agentProcessing),_e=Yt(G,K.agentProcessing,B,Q.t(`cmdDesc`,{returnObjects:!0}),m.pinned,m.isPaused),ve=()=>(_e=Yt(G,K.agentProcessing,B,Q.t(`cmdDesc`,{returnObjects:!0}),m.pinned,m.isPaused),_e);U(t),O(t,w),ue(t),ce(t);let ye=Lt(),be=t.settings.get(`language`)??`auto`,xe=be===`auto`?se():be,Se=tn(t),Ce=t.settings.get(`theme_preset`),we=t.settings.get(`keybinding_overrides`);L(xe);let Te=A({currentVersion:de(),lastCheck:t.settings.get(`last_update_check`),autoCheck:t.settings.get(`auto_update_check`)!==!1,persistLastCheck:()=>t.settings.persist({last_update_check:Date.now()})}),Ee={get value(){return m},set value(e){m=e}},q={get value(){return pe},set value(e){pe=e}},J={get value(){return G},set value(e){G=e}},Y={get value(){return _e},set value(e){_e=e}},De={get value(){return xe},set value(e){xe=e}},Oe={get value(){return E},set value(e){E=e}};await new Promise(async i=>{let a={current:void 0},o={current:void 0},u={current:void 0},f=!1,p=()=>{if(!f){f=!0;try{d?.clearBgSubs()}catch{}try{d?.stopBgOutputPoll()}catch{}try{d?.stopBgSubagentPoll()}catch{}try{clearInterval(o.current)}catch{}try{u.current.stop()}catch{}try{a.current?.dispose()}catch{}i()}};V.value=p;let b=()=>{setTimeout(p,3e3).unref();try{M.value?.lifecycle.stop()}catch{p()}},C=on({getTui:()=>M.value??null,getSession:()=>m,dispatchAbort:()=>le({kind:`abort`}),clearTodoLayers:()=>{ye.todoList.length!==0&&(ye.todoList=[],M.value?.stores.tasks.setTasks([]),m.session.setTodoList([]))},markUserAborted:()=>{K.userAborted=!0},resetCtrlCCount:()=>{K.ctrlCCount=0},markRestartRequested:()=>{r=!0},stopTui:b,isBusy:()=>ge()}),T=oe,{historyStore:E,inputHistory:O,externalHistoryCommands:A}=await hn(m,t.settings.get(`history`)?.external),P=Zt({app:t,session:m,getTui:()=>U});d=P;let L={current:void 0},z={current:void 0},B={current:void 0},ae={current:void 0},se={current:void 0},H={value:void 0},ce=S(),U=await me(await zn({app:t,session:m,options:e,tuiRefBox:j,tuiRef:M,turn:K,projState:ye,redState:ce,isBusyNow:ge,dispatchToEngine:le,stopController:C,finishInteractive:p,stopTuiGuarded:b,applyModel:W,ensureModelUsableForPrompt:fe,refreshSlashCommands:ve,fileCommands:he,modelReady:v,availableModelIds:w,currentModel:N,currentModelId:I,fmtDisplayModel:R,cfgLang:be,themeRegistry:Se,presetSelection:Ce,keybindingOverrides:we,continuedExisting:D,convoCount:ne,historyStore:E,inputHistory:O,externalHistoryCommands:A,bg:P,bgController:d,reg:G,slashCommands:_e,interactive:pe,handleExitRef:se,cliCtxRef:ae,handleAbortInterceptRef:z,runAsyncBashRef:L,runMemoryCaptureRef:B,allCommandNames:T}));j.value=U;let{pasteBinder:ue}=rr({app:t,session:m,options:e,tui:U,memoryConflictRef:n,turn:K,stopController:C,runAsyncBashRef:L,handleAbortInterceptRef:z,runMemoryCaptureRef:B,schedulePollIntervalRef:o,scheduleServiceRef:u});await gr({app:t,options:e,tui:U,tuiRef:M,turn:K,projState:ye,redState:ce,stopController:C,themeRegistry:Se,availableModelIds:w,applyModel:W,refreshSlashCommands:ve,retryAccelerate:te,startupCrashGapRef:h,resumedNote:g,resumed:k??void 0,updateCheckPromise:Te,bg:P,ftueController:y,refreshModelsNow:x,persistAvailable:ee,cfgLang:be,sessionRef:Ee,interactiveRef:q,regRef:J,slashCommandsRef:Y,modelReadyRef:_,currentModelIdRef:re,currentLangRef:De,modelsRef:Oe,restartRequestedRef:s,restartMemoryTriggeredRef:c,restartResumePromptRef:l,pushBudgetNowRef:ie,staleBuildDetectorRef:a,eventsRef:H,cliCtxRef:ae,handleExitRef:se,pasteBinder:ue,contextWindowRef:F})});let ke;if(t.codingSessionPool.autoPersist&&m.session.messages().length>0){let t=e.sessionUrl?` --session-url ${e.sessionUrl}`:``,n=e.sessionToken?` --session-token <redacted>`:``;ke=`\n\x1b[2m${Q.t(`cmd.resumeContinueLabel`)}\x1b[0motto --continue ${m.id}${t}${n}\n`}return{restart:r?{sessionId:m.id,memoryTriggered:i,resumePrompt:o}:void 0,resumeHint:ke}}finally{d?.clearBgSubs(),d?.stopBgOutputPoll(),d?.stopBgSubagentPoll()}}async function vr(e){if(e.hasParentWorkspace()){let t=e.parentWorkspaceExisted,n=await gt({parentRoot:t.parentRoot,currentRoot:t.currentRoot,language:e.settings.get(`language`)});n===`exit`&&(process.stdout.write(`
12
12
  `),process.exit(0)),n===`use_parent`?await e.adoptParentWorkspace():await e.createLocalWorkspace()}let t=we(e.workspaceDir,{interactive:!0});if(!t.shouldPrompt){e.needsWorkspaceInit()&&await e.confirmWorkspaceInit();return}let n=await _t({root:t.root,language:e.settings.get(`language`)});if(n===`exit`&&(process.stdout.write(`
13
13
  `),process.exit(0)),n===`trust`){Ne(t.root),await e.settings.reload(),e.needsWorkspaceInit()&&await e.confirmWorkspaceInit();return}await e.settings.update({permission_mode:`readonly`}),e.needsWorkspaceInit()&&await e.confirmWorkspaceInit()}function yr(e){throw e instanceof Error&&e.message.startsWith(`No model configured`)?Error("No model configured. Run `otto` (interactive) to complete setup — it walks you through: install a provider plugin → /auth → /model. Or authenticate directly with `otto auth login`."):e}async function br(e,t){e.prompt&&await D(await t.createSession({listable:!1}).catch(yr),e.prompt,{tui:!0})}async function xr(e,t){if(e.prompt){let n=await M(await t.createSession({listable:!1}).catch(yr),e.prompt);process.stdout.write(JSON.stringify(n,null,2)+`
14
- `)}}function Sr(e){vt(e.settings.get(`theme_overrides`)?.markdown)}Be(`cli.ts imports resolved`);const Cr=new Map([[`doctor`,async e=>{let{runDoctorCommand:t}=await import(`./doctor-lT2QhG2q.js`);return t(e.args,{stdout:e.stdout,stderr:e.stderr})}],[`auth`,async e=>{let{runAuthCommand:t}=await import(`./auth-command-D1T16ed-.js`);return t(e.args,{bootstrap:{workspaceDir:e.options.projectDir,projectConfigPath:e.options.configPath,verbose:e.options.verbose},stdout:e.stdout,stderr:e.stderr})}],[`serve`,async e=>{let{runServeCommand:t}=await import(`./serve-DaxogAZ5.js`);return t(e.args,{projectDir:e.options.projectDir,configPath:e.options.configPath,modelId:e.options.model,verbose:e.options.verbose})}],[`daemon`,async e=>{let{runDaemonCommand:t}=await import(`./daemon-COESl-zU.js`);return t(e.args,{projectDir:e.options.projectDir,stdout:e.stdout,stderr:e.stderr})}],[`persistenced`,async e=>{let{runPersistenceCommand:t}=await import(`./persistence-DOaizHMA.js`);return t([`local`,...e.args])}],[`remote-persistence-server`,async e=>{let{runPersistenceCommand:t}=await import(`./persistence-DOaizHMA.js`);return t([`remote`,...e.args])}],[`persistence`,async e=>{let{runPersistenceCommand:t}=await import(`./persistence-DOaizHMA.js`);return t(e.args)}],[`observe`,async e=>{let{runObserveCommand:t}=await import(`./observe-CzIv09hO.js`);return t(e.args)}],[`debug`,async e=>{let{runObserveCommand:t}=await import(`./observe-CzIv09hO.js`);return t([`debug`,...e.args])}],[`time-travel`,async e=>{let{runObserveCommand:t}=await import(`./observe-CzIv09hO.js`);return t([`replay`,...e.args])}],[`mcp`,async e=>{let{runMcpCommand:t}=await import(`./mcp-9P_AmnDk.js`);return t(e.args)}],[`mcp-server`,async e=>{let{runMcpServerCommand:t,buildMcpServerDepsFromApp:n}=await import(`./mcp-server-BK4L-YBN.js`),{createHostApp:r}=await import(`./create-host-app-DG58-vRA.js`),i=r({logger:{name:`otto-mcp-server`,level:`error`,destination:`stderr`},...e.options.projectDir?{workspaceDir:e.options.projectDir}:{},...e.options.model?{modelId:e.options.model}:{}});await i.start();let a=n(i.tools,i.permissionRegistry),o=new AbortController;return process.on(`SIGTERM`,()=>o.abort()),process.on(`SIGINT`,()=>o.abort()),t(e.args,{...a,signal:o.signal,onShutdown:()=>i.stop()})}],[`config`,async e=>{let{runConfigMigrationCommand:t}=await import(`./config-migration-DatflIxs.js`);return t(e.args,{stdout:e.stdout,stderr:e.stderr})}],[`migrate`,async e=>{let{runMigrateCommand:t}=await import(`./migrate-DDNkik_0.js`);return t(e.args,{stdout:e.stdout,stderr:e.stderr})}],[`extension`,async e=>{let{runExtensionCommand:t}=await import(`./extension-CTyrcdT1.js`);return t(e.args,{stdout:e.stdout,stderr:e.stderr})}],[`ps`,async e=>{let{runPsCommand:t}=await import(`./ps-BovE9XMQ.js`);return t(e.args,{stdout:e.stdout,stderr:e.stderr})}],[`feedback`,async e=>{let{runFeedbackCommand:t}=await import(`./feedback-C2Hdxp1y.js`);return t(e.args,{stdout:e.stdout,stderr:e.stderr,projectDir:e.options.projectDir,configPath:e.options.configPath})}]]);async function wr(e,t,n){let r=me({cwd:n.projectDir,homedir:ge()}),i=new Set(pe),a=xe(r,i).get(e);if(!a){let t=Ee(r,i,e);return t?(process.stderr.write(`otto: 命令 "${e}" 被多个插件声明(${t.join(`, `)}),已禁用以避免歧义。\n请重命名其中一个插件的 \`contributes.cli.name\` 后重试(编辑对应插件目录的 otto-plugin.json)。\n`),1):void 0}if(Ce(a).gated)return process.stderr.write(`otto: 插件 "${a.id}" 声明了 \`otto ${e}\` 命令但尚未被信任。\n请先在 TUI 内运行 \`/trust plugin ${a.id}\`(或 \`/extension\` 信任该插件)后重试。\n`),1;let o=Ae(a);if(!o)return process.stderr.write(`otto: 插件 "${a.id}" 声明了 \`contributes.cli\` 但找不到可执行入口,请检查其 manifest 的 bin 字段或重新安装该插件。\n`),1;try{return await Me(o,t,a.dir)}catch(e){return process.stderr.write(`otto: 插件 "${a.id}" 的 CLI 命令执行失败:${e instanceof Error?e.message:String(e)}\n`),1}}function Tr(e,t){return e.mode===`interactive`&&!e.verbose&&!t?`fatal`:t}function Er(e,t){return e.mode===`interactive`&&!t?`0`:t}function Dr(e,t,n={}){let r=[];for(let t=0;t<e.length;t++){if(e[t]===`--continue`){t++;continue}e[t].startsWith(`--restart-generation=`)||r.push(e[t])}return[...n.execArgv??[],...r,`--continue`,t,...n.generation===void 0?[]:[`--restart-generation=${n.generation}`],...n.sessionUrl?[`--session-url`,n.sessionUrl]:[],...n.sessionToken?[`--session-token`,n.sessionToken]:[],...n.memoryRestartGrace?[`--memory-restart-grace`]:[],...n.resumePrompt?[`--resume-prompt`,n.resumePrompt]:[]]}async function Or(){process.stdin.on(`error`,e=>{e.code}),De(),Oe();let{options:e,subCommand:t,subCommandArgs:n,unresolvedCommandName:r,unresolvedCommandArgs:i}=fe(process.argv);e.shadow&&(process.env.OTTO_SHADOW=`1`);let a=e.verbose?`debug`:e.mode===`interactive`?`fatal`:e.quiet?`error`:`info`;Ve(a);let o=Tr(e,process.env.OTTO_LOG_LEVEL);o&&(process.env.OTTO_LOG_LEVEL=o);let s=Er(e,process.env.OTTO_LOG_STDERR);s&&(process.env.OTTO_LOG_STDERR=s),process.env.OTTO_LOG_STDERR===`0`?Je(()=>{}):Je(e=>process.stderr.write(`${e}\n`)),process.on(`beforeExit`,()=>{process.env.OTTO_LOG_STDERR!==`0`&&Je(e=>process.stderr.write(`${e}\n`))});let c=n.split(` `).filter(Boolean),l=Cr.get(t??``);if(l)return l({args:c,options:e,stdout:e=>process.stdout.write(e),stderr:e=>process.stderr.write(e)});if(r){let t=await wr(r,i??[],e);if(t!==void 0)return t}if(e.showHelp){let{getHelpLines:e}=await import(`./parse-cli-3fWEIMWc.js`).then(e=>e.r);return process.stdout.write(e().join(`
14
+ `)}}function Sr(e){vt(e.settings.get(`theme_overrides`)?.markdown)}Be(`cli.ts imports resolved`);const Cr=new Map([[`doctor`,async e=>{let{runDoctorCommand:t}=await import(`./doctor-DXBLkbkP.js`);return t(e.args,{stdout:e.stdout,stderr:e.stderr})}],[`auth`,async e=>{let{runAuthCommand:t}=await import(`./auth-command-D1T16ed-.js`);return t(e.args,{bootstrap:{workspaceDir:e.options.projectDir,projectConfigPath:e.options.configPath,verbose:e.options.verbose},stdout:e.stdout,stderr:e.stderr})}],[`serve`,async e=>{let{runServeCommand:t}=await import(`./serve-Ke0nwN9Y.js`);return t(e.args,{projectDir:e.options.projectDir,configPath:e.options.configPath,modelId:e.options.model,verbose:e.options.verbose})}],[`daemon`,async e=>{let{runDaemonCommand:t}=await import(`./daemon-COESl-zU.js`);return t(e.args,{projectDir:e.options.projectDir,stdout:e.stdout,stderr:e.stderr})}],[`persistenced`,async e=>{let{runPersistenceCommand:t}=await import(`./persistence-CRFhOYx6.js`);return t([`local`,...e.args])}],[`remote-persistence-server`,async e=>{let{runPersistenceCommand:t}=await import(`./persistence-CRFhOYx6.js`);return t([`remote`,...e.args])}],[`persistence`,async e=>{let{runPersistenceCommand:t}=await import(`./persistence-CRFhOYx6.js`);return t(e.args)}],[`observe`,async e=>{let{runObserveCommand:t}=await import(`./observe-Dxfud-t7.js`);return t(e.args)}],[`debug`,async e=>{let{runObserveCommand:t}=await import(`./observe-Dxfud-t7.js`);return t([`debug`,...e.args])}],[`time-travel`,async e=>{let{runObserveCommand:t}=await import(`./observe-Dxfud-t7.js`);return t([`replay`,...e.args])}],[`mcp`,async e=>{let{runMcpCommand:t}=await import(`./mcp-Cm4-OhXI.js`);return t(e.args)}],[`mcp-server`,async e=>{let{runMcpServerCommand:t,buildMcpServerDepsFromApp:n}=await import(`./mcp-server-Dpza3yn2.js`),{createHostApp:r}=await import(`./create-host-app-DG58-vRA.js`),i=r({logger:{name:`otto-mcp-server`,level:`error`,destination:`stderr`},...e.options.projectDir?{workspaceDir:e.options.projectDir}:{},...e.options.model?{modelId:e.options.model}:{}});await i.start();let a=n(i.tools,i.permissionRegistry),o=new AbortController;return process.on(`SIGTERM`,()=>o.abort()),process.on(`SIGINT`,()=>o.abort()),t(e.args,{...a,signal:o.signal,onShutdown:()=>i.stop()})}],[`config`,async e=>{let{runConfigMigrationCommand:t}=await import(`./config-migration-DatflIxs.js`);return t(e.args,{stdout:e.stdout,stderr:e.stderr})}],[`migrate`,async e=>{let{runMigrateCommand:t}=await import(`./migrate-RlBJqJnB.js`);return t(e.args,{stdout:e.stdout,stderr:e.stderr})}],[`extension`,async e=>{let{runExtensionCommand:t}=await import(`./extension-CTyrcdT1.js`);return t(e.args,{stdout:e.stdout,stderr:e.stderr})}],[`ps`,async e=>{let{runPsCommand:t}=await import(`./ps-DiKCLKbs.js`);return t(e.args,{stdout:e.stdout,stderr:e.stderr})}],[`feedback`,async e=>{let{runFeedbackCommand:t}=await import(`./feedback-D7Po4mlE.js`);return t(e.args,{stdout:e.stdout,stderr:e.stderr,projectDir:e.options.projectDir,configPath:e.options.configPath})}],[`export-trajectory`,async e=>{let{runExportTrajectoryCommand:t}=await import(`./export-trajectory-D-BcH0Wt.js`);return t(e.args,{stdout:e.stdout,stderr:e.stderr})}]]);async function wr(e,t,n){let r=me({cwd:n.projectDir,homedir:ge()}),i=new Set(pe),a=xe(r,i).get(e);if(!a){let t=Ee(r,i,e);return t?(process.stderr.write(`otto: 命令 "${e}" 被多个插件声明(${t.join(`, `)}),已禁用以避免歧义。\n请重命名其中一个插件的 \`contributes.cli.name\` 后重试(编辑对应插件目录的 otto-plugin.json)。\n`),1):void 0}if(Ce(a).gated)return process.stderr.write(`otto: 插件 "${a.id}" 声明了 \`otto ${e}\` 命令但尚未被信任。\n请先在 TUI 内运行 \`/trust plugin ${a.id}\`(或 \`/extension\` 信任该插件)后重试。\n`),1;let o=Ae(a);if(!o)return process.stderr.write(`otto: 插件 "${a.id}" 声明了 \`contributes.cli\` 但找不到可执行入口,请检查其 manifest 的 bin 字段或重新安装该插件。\n`),1;try{return await Me(o,t,a.dir)}catch(e){return process.stderr.write(`otto: 插件 "${a.id}" 的 CLI 命令执行失败:${e instanceof Error?e.message:String(e)}\n`),1}}function Tr(e,t){return e.mode===`interactive`&&!e.verbose&&!t?`fatal`:t}function Er(e,t){return e.mode===`interactive`&&!t?`0`:t}function Dr(e,t,n={}){let r=[];for(let t=0;t<e.length;t++){if(e[t]===`--continue`){t++;continue}e[t].startsWith(`--restart-generation=`)||r.push(e[t])}return[...n.execArgv??[],...r,`--continue`,t,...n.generation===void 0?[]:[`--restart-generation=${n.generation}`],...n.sessionUrl?[`--session-url`,n.sessionUrl]:[],...n.sessionToken?[`--session-token`,n.sessionToken]:[],...n.memoryRestartGrace?[`--memory-restart-grace`]:[],...n.resumePrompt?[`--resume-prompt`,n.resumePrompt]:[]]}async function Or(){process.stdin.on(`error`,e=>{e.code}),De(),Oe();let{options:e,subCommand:t,subCommandArgs:n,unresolvedCommandName:r,unresolvedCommandArgs:i}=fe(process.argv);e.shadow&&(process.env.OTTO_SHADOW=`1`);let a=e.verbose?`debug`:e.mode===`interactive`?`fatal`:e.quiet?`error`:`info`;Ve(a);let o=Tr(e,process.env.OTTO_LOG_LEVEL);o&&(process.env.OTTO_LOG_LEVEL=o);let s=Er(e,process.env.OTTO_LOG_STDERR);s&&(process.env.OTTO_LOG_STDERR=s),e.mode===`interactive`&&!e.verbose&&(console.warn=()=>{}),process.env.OTTO_LOG_STDERR===`0`?Je(()=>{}):Je(e=>process.stderr.write(`${e}\n`)),process.on(`beforeExit`,()=>{process.env.OTTO_LOG_STDERR!==`0`&&Je(e=>process.stderr.write(`${e}\n`))});let c=n.split(` `).filter(Boolean),l=Cr.get(t??``);if(l)return l({args:c,options:e,stdout:e=>process.stdout.write(e),stderr:e=>process.stderr.write(e)});if(r){let t=await wr(r,i??[],e);if(t!==void 0)return t}if(e.showHelp){let{getHelpLines:e}=await import(`./parse-cli-BSJEQtBo.js`).then(e=>e.r);return process.stdout.write(e().join(`
15
15
  `)+`
16
16
  `),0}if(!e.prompt&&e.mode!==`interactive`)return process.stderr.write(`otto: no prompt provided. Use --help for usage.
17
- `),1;let u=await Xe(),d=e.sessionUrl??u?.serviceUrl,f=e.sessionToken??u?.token,p={},m=Ue(`new App() ctor`,()=>G({inspect:e.inspect!==void 0||e.mode===`interactive`,logger:{name:`otto-cli`,level:a,destination:`stderr`},workspaceDir:e.projectDir,workspaceId:e.workspaceId,projectConfigPath:e.configPath,interactive:e.mode===`interactive`,shadow:e.shadow??!1,modelId:e.model,userIdentity:u??void 0,...e.maxToolTurns===void 0?{}:{maxToolTurns:e.maxToolTurns},...e.maxToolTurnExtensions===void 0?{}:{maxToolTurnExtensions:e.maxToolTurnExtensions},...e.promptTokenBudget===void 0?{}:{promptOutputTokenBudget:e.promptTokenBudget},...e.promptTimeBudgetMin===void 0?{}:{promptWallClockBudgetMs:e.promptTimeBudgetMin*6e4},...e.sessionCostBudget===void 0?{}:{sessionCostBudgetUSD:e.sessionCostBudget},...e.noStallDetection?{stallDetection:!1}:e.stallWindowTurns!==void 0&&e.stallRepeatThreshold!==void 0?{stallDetection:{windowTurns:e.stallWindowTurns,repeatThreshold:e.stallRepeatThreshold}}:{},storage:d&&f?{session:{url:d},remote:{getAuth:async()=>({token:f})}}:{session:{dir:Ke}},onMemoryConflict:(e,t)=>p.current?.(e,t)}));await He(`app.start()`,()=>m.start()),m.authStore.on(`credential.persist-deferred`,e=>{e.state===`exhausted`&&console.error(`[otto] ⚠️ 凭据变更无法落盘(${e.attempt} 次重试均失败:${e.reason})。\n 本次会话的新凭据只存在于内存中,退出后会丢失。请检查文件锁/磁盘权限后重启。\n (deferred/recovered 档为诊断信息,仅 exhausted 需告警)`)}),Sr(m),Ie(Fe);let h=!1,g=()=>{h&&(e.mode===`interactive`&&Wt(),process.exit(1)),h=!0,Promise.race([m.stop(),new Promise(e=>setTimeout(e,1e4))]).finally(()=>{e.mode===`interactive`&&(Wt(),Ut()),process.exit(1)})};process.on(`SIGTERM`,g),process.on(`SIGHUP`,g);let _,v=!1,y,b;if(e.attachSession){let t=process.env.OTTO_SERVICE_URL??`http://127.0.0.1:8417`,{runAttach:n}=await import(`./run-attach-z7YECztf.js`);return await n({sessionId:e.attachSession,baseUrl:t,token:process.env.OTTO_SERVICE_TOKEN,forceWriteLease:e.forceWriteLease}),0}try{switch(e.mode){case`print`:await br(e,m);break;case`json`:await xr(e,m);break;case`interactive`:{await vr(m);let t=await _r(e,m,p);_=t.restart?.sessionId,v=!!t.restart?.memoryTriggered,y=t.restart?.resumePrompt,t.restart||(b=t.resumeHint);break}}}finally{let t=()=>{};process.on(`SIGINT`,t);let n=setTimeout(()=>{e.mode===`interactive`&&(Wt(),Ut()),process.exit(1)},1e4);try{await m.stop()}finally{clearTimeout(n),process.removeListener(`SIGINT`,t)}}if(_){process.removeListener(`SIGTERM`,g),process.removeListener(`SIGHUP`,g);let t=e.sessionUrl,n=e.sessionToken,r=()=>{},i,a=e=>{try{console.error(`\n[otto] 重启陪跑期父进程异常,终止子会话以避免孤儿挂起:${e instanceof Error?e.stack??e.message:String(e)}`)}catch{}try{i?.kill(`SIGTERM`)}catch{}process.exit(1)};return process.on(`SIGINT`,r),process.on(`SIGTERM`,r),process.on(`uncaughtException`,a),process.on(`unhandledRejection`,a),i=ve(process.execPath,Dr(process.argv.slice(1),_,{sessionUrl:t,sessionToken:n,memoryRestartGrace:v,resumePrompt:y,execArgv:process.execArgv,generation:(e.restartGeneration??0)+1}),{stdio:`inherit`,env:{...process.env}}),i.on(`exit`,(e,t)=>{process.removeListener(`SIGINT`,r),process.removeListener(`SIGTERM`,r),process.removeListener(`uncaughtException`,a),process.removeListener(`unhandledRejection`,a),process.exit(e??(t?1:0))}),0}if(e.mode===`interactive`){if(Ut(),b)try{process.stdout.write(b)}catch{}process.exit(process.exitCode??0)}return 0}Or().then(e=>{e!==0&&(process.exitCode=e)}).catch(e=>{process.stderr.write(`otto: ${e instanceof Error?e.message:String(e)}\n`),process.exitCode=1});export{Or as runCli};
17
+ `),1;let u=await Xe(),d=e.sessionUrl??u?.serviceUrl,f=e.sessionToken??u?.token,p={},m=Ue(`new App() ctor`,()=>G({inspect:e.inspect!==void 0||e.mode===`interactive`,logger:{name:`otto-cli`,level:a,destination:`stderr`},workspaceDir:e.projectDir,workspaceId:e.workspaceId,projectConfigPath:e.configPath,interactive:e.mode===`interactive`,shadow:e.shadow??!1,modelId:e.model,userIdentity:u??void 0,...e.maxToolTurns===void 0?{}:{maxToolTurns:e.maxToolTurns},...e.maxToolTurnExtensions===void 0?{}:{maxToolTurnExtensions:e.maxToolTurnExtensions},...e.promptTokenBudget===void 0?{}:{promptOutputTokenBudget:e.promptTokenBudget},...e.promptTimeBudgetMin===void 0?{}:{promptWallClockBudgetMs:e.promptTimeBudgetMin*6e4},...e.sessionCostBudget===void 0?{}:{sessionCostBudgetUSD:e.sessionCostBudget},...e.noStallDetection?{stallDetection:!1}:e.stallWindowTurns!==void 0&&e.stallRepeatThreshold!==void 0?{stallDetection:{windowTurns:e.stallWindowTurns,repeatThreshold:e.stallRepeatThreshold}}:{},storage:d&&f?{session:{url:d},remote:{getAuth:async()=>({token:f})}}:{session:{dir:Ke}},onMemoryConflict:(e,t)=>p.current?.(e,t)}));await He(`app.start()`,()=>m.start()),m.authStore.on(`credential.persist-deferred`,e=>{e.state===`exhausted`&&console.error(`[otto] ⚠️ 凭据变更无法落盘(${e.attempt} 次重试均失败:${e.reason})。\n 本次会话的新凭据只存在于内存中,退出后会丢失。请检查文件锁/磁盘权限后重启。\n (deferred/recovered 档为诊断信息,仅 exhausted 需告警)`)}),Sr(m),Ie(Fe);let h=!1,g=()=>{h&&(e.mode===`interactive`&&Wt(),process.exit(1)),h=!0,Promise.race([m.stop(),new Promise(e=>setTimeout(e,1e4))]).finally(()=>{e.mode===`interactive`&&(Wt(),Ut()),process.exit(1)})};process.on(`SIGTERM`,g),process.on(`SIGHUP`,g);let _,v=!1,y,b;if(e.attachSession){let t=process.env.OTTO_SERVICE_URL??`http://127.0.0.1:8417`,{runAttach:n}=await import(`./run-attach-DDpMk2_N.js`);return await n({sessionId:e.attachSession,baseUrl:t,token:process.env.OTTO_SERVICE_TOKEN,forceWriteLease:e.forceWriteLease}),0}try{switch(e.mode){case`print`:await br(e,m);break;case`json`:await xr(e,m);break;case`interactive`:{await vr(m);let t=await _r(e,m,p);_=t.restart?.sessionId,v=!!t.restart?.memoryTriggered,y=t.restart?.resumePrompt,t.restart||(b=t.resumeHint);break}}}finally{let t=()=>{};process.on(`SIGINT`,t);let n=setTimeout(()=>{e.mode===`interactive`&&(Wt(),Ut()),process.exit(1)},1e4);try{await m.stop()}finally{clearTimeout(n),process.removeListener(`SIGINT`,t)}}if(_){process.removeListener(`SIGTERM`,g),process.removeListener(`SIGHUP`,g);let t=e.sessionUrl,n=e.sessionToken,r=()=>{},i,a=e=>{try{console.error(`\n[otto] 重启陪跑期父进程异常,终止子会话以避免孤儿挂起:${e instanceof Error?e.stack??e.message:String(e)}`)}catch{}try{i?.kill(`SIGTERM`)}catch{}process.exit(1)};return process.on(`SIGINT`,r),process.on(`SIGTERM`,r),process.on(`uncaughtException`,a),process.on(`unhandledRejection`,a),i=ve(process.execPath,Dr(process.argv.slice(1),_,{sessionUrl:t,sessionToken:n,memoryRestartGrace:v,resumePrompt:y,execArgv:process.execArgv,generation:(e.restartGeneration??0)+1}),{stdio:`inherit`,env:{...process.env}}),i.on(`exit`,(e,t)=>{process.removeListener(`SIGINT`,r),process.removeListener(`SIGTERM`,r),process.removeListener(`uncaughtException`,a),process.removeListener(`unhandledRejection`,a),process.exit(e??(t?1:0))}),0}if(e.mode===`interactive`){if(Ut(),b)try{process.stdout.write(b)}catch{}process.exit(process.exitCode??0)}return 0}Or().then(e=>{e!==0&&(process.exitCode=e)}).catch(e=>{process.stderr.write(`otto: ${e instanceof Error?e.message:String(e)}\n`),process.exitCode=1});export{Or as runCli};
18
18
  //# sourceMappingURL=index.js.map