@x-otto/cli 0.0.1-alpha.2 → 0.0.1-alpha.20

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 (121) hide show
  1. package/README.md +65 -65
  2. package/bin/otto.js +6 -0
  3. package/dist/{auth-command-CXAB3_hs.js → auth-command-kkJh-O5y.js} +3 -3
  4. package/dist/auth-command-kkJh-O5y.js.map +1 -0
  5. package/dist/build-id-D7Wf4tQw.js +3 -0
  6. package/dist/build-id-D7Wf4tQw.js.map +1 -0
  7. package/dist/bundled-extensions/plugin-otto-wire-protocols/plugin-dist/meta.json +1 -1
  8. package/dist/bundled-extensions/plugin-otto-wire-protocols/plugin-dist/plugin.cjs +2083 -18164
  9. package/dist/bundled-extensions/plugin-otto-wire-protocols/src/anthropic-messages.ts +2 -2
  10. package/dist/bundled-extensions/plugin-otto-wire-protocols/src/openai-completions.ts +12 -5
  11. package/dist/bundled-extensions/plugin-otto-wire-protocols/src/openai-responses.ts +4 -1
  12. package/dist/bundled-extensions/plugin-skill-inductor/plugin-dist/meta.json +1 -1
  13. package/dist/bundled-extensions/plugin-skill-inductor/plugin-dist/plugin.cjs +78 -52294
  14. package/dist/bundled-extensions-C3n8jg20.js +3 -0
  15. package/dist/bundled-extensions-C3n8jg20.js.map +1 -0
  16. package/dist/command-dispatcher-CahuAJnO.js +17 -0
  17. package/dist/command-dispatcher-CahuAJnO.js.map +1 -0
  18. package/dist/{config-migration-DatflIxs.js → config-migration-0zdXsEDB.js} +1 -1
  19. package/dist/{config-migration-DatflIxs.js.map → config-migration-0zdXsEDB.js.map} +1 -1
  20. package/dist/create-host-app-BXQ8bU-B.js +3 -0
  21. package/dist/create-host-app-BXQ8bU-B.js.map +1 -0
  22. package/dist/create-host-app-DXII2WTM.js +2 -0
  23. package/dist/{daemon-COESl-zU.js → daemon-BtiaXSxn.js} +1 -1
  24. package/dist/{daemon-COESl-zU.js.map → daemon-BtiaXSxn.js.map} +1 -1
  25. package/dist/{daemon-base-YOWgYYN7.js → daemon-base-BzhYY4FS.js} +1 -1
  26. package/dist/{daemon-base-YOWgYYN7.js.map → daemon-base-BzhYY4FS.js.map} +1 -1
  27. package/dist/{debug-CiosFwme.js → debug-DfgcrVCI.js} +2 -2
  28. package/dist/{debug-CiosFwme.js.map → debug-DfgcrVCI.js.map} +1 -1
  29. package/dist/discover-with-bundled-B5d4q___.js +2 -0
  30. package/dist/discover-with-bundled-CF8qFP41.js +3 -0
  31. package/dist/discover-with-bundled-CF8qFP41.js.map +1 -0
  32. package/dist/doctor-DbQC8Z7p.js +36 -0
  33. package/dist/doctor-DbQC8Z7p.js.map +1 -0
  34. package/dist/{doctor-attach-_zeIJewx.js → doctor-attach-OJHn8L52.js} +2 -2
  35. package/dist/{doctor-attach-_zeIJewx.js.map → doctor-attach-OJHn8L52.js.map} +1 -1
  36. package/dist/{doctor-cdp-K_mIFRfA.js → doctor-cdp-D66ChCCN.js} +1 -1
  37. package/dist/{doctor-cdp-K_mIFRfA.js.map → doctor-cdp-D66ChCCN.js.map} +1 -1
  38. package/dist/{doctor-heap-Rr2nNvcw.js → doctor-heap-Brsro5QJ.js} +2 -2
  39. package/dist/{doctor-heap-Rr2nNvcw.js.map → doctor-heap-Brsro5QJ.js.map} +1 -1
  40. package/dist/{doctor-ps-OL3FGQYu.js → doctor-ps-B4Syy9qa.js} +2 -2
  41. package/dist/{doctor-ps-OL3FGQYu.js.map → doctor-ps-B4Syy9qa.js.map} +1 -1
  42. package/dist/{extension-BKXIr86F.js → extension-DLFCUBJr.js} +41 -33
  43. package/dist/extension-DLFCUBJr.js.map +1 -0
  44. package/dist/extension-I87MkZYp.js +2 -0
  45. package/dist/extension-plugin-BEQlmUET.js +2 -0
  46. package/dist/extension-plugin-BYR-MJ1U.js +7 -0
  47. package/dist/extension-plugin-BYR-MJ1U.js.map +1 -0
  48. package/dist/feedback-DjNFsjeN.js +2 -0
  49. package/dist/feedback-DrUjMuKw.js +21 -0
  50. package/dist/feedback-DrUjMuKw.js.map +1 -0
  51. package/dist/{feishu-setup-D6vnuNLw.js → feishu-setup-C2UDdpIm.js} +2 -2
  52. package/dist/{feishu-setup-D6vnuNLw.js.map → feishu-setup-C2UDdpIm.js.map} +1 -1
  53. package/dist/ftue-doctor-recovery-DhiseXnP.js +3 -0
  54. package/dist/ftue-doctor-recovery-DhiseXnP.js.map +1 -0
  55. package/dist/index.js +10 -12
  56. package/dist/index.js.map +1 -1
  57. package/dist/install-DkJgbg2p.js +2 -0
  58. package/dist/{install-DlVJRHRT.js → install-hTDjeo61.js} +1 -1
  59. package/dist/{install-DlVJRHRT.js.map → install-hTDjeo61.js.map} +1 -1
  60. package/dist/{mcp-DbTYT7hB.js → mcp-BDfBf6gx.js} +1 -1
  61. package/dist/{mcp-DbTYT7hB.js.map → mcp-BDfBf6gx.js.map} +1 -1
  62. package/dist/{migrate-boDXhEyV.js → migrate-4QDwYLf6.js} +2 -2
  63. package/dist/{migrate-boDXhEyV.js.map → migrate-4QDwYLf6.js.map} +1 -1
  64. package/dist/{model-auth-qY5zeBF7.js → model-auth-BMY86Bk4.js} +2 -2
  65. package/dist/{model-auth-qY5zeBF7.js.map → model-auth-BMY86Bk4.js.map} +1 -1
  66. package/dist/model-auth-CSLiEFJ-.js +2 -0
  67. package/dist/{observe-CVg-MRM2.js → observe-DSrUS2YI.js} +10 -8
  68. package/dist/observe-DSrUS2YI.js.map +1 -0
  69. package/dist/parse-cli-klcuBpG2.js +3 -0
  70. package/dist/parse-cli-klcuBpG2.js.map +1 -0
  71. package/dist/{persistenced-CCwHu1Ww.js → persistenced-CW8sdhd0.js} +2 -2
  72. package/dist/{persistenced-CCwHu1Ww.js.map → persistenced-CW8sdhd0.js.map} +1 -1
  73. package/dist/plugin-assembly-check-CvuJ4dHf.js +3 -0
  74. package/dist/plugin-assembly-check-CvuJ4dHf.js.map +1 -0
  75. package/dist/{proxy-evg7ZvoD.js → proxy-CMQBvdZC.js} +1 -1
  76. package/dist/{proxy-evg7ZvoD.js.map → proxy-CMQBvdZC.js.map} +1 -1
  77. package/dist/proxy-TzOLqtkc.js +2 -0
  78. package/dist/{ps-DKrluEuy.js → ps-Kb6ZsEpC.js} +1 -1
  79. package/dist/{ps-DKrluEuy.js.map → ps-Kb6ZsEpC.js.map} +1 -1
  80. package/dist/{registry-D0NONjLv.js → registry-Cr5To_5r.js} +3 -3
  81. package/dist/registry-Cr5To_5r.js.map +1 -0
  82. package/dist/registry-DAJ7oZTe.js +2 -0
  83. package/dist/{remote-persistence-server-B_hONoVR.js → remote-persistence-server-BLBIop0u.js} +2 -2
  84. package/dist/{remote-persistence-server-B_hONoVR.js.map → remote-persistence-server-BLBIop0u.js.map} +1 -1
  85. package/dist/{run-attach-Ci5jYyCa.js → run-attach-CgYMem8s.js} +2 -2
  86. package/dist/{run-attach-Ci5jYyCa.js.map → run-attach-CgYMem8s.js.map} +1 -1
  87. package/dist/{serve-pVR6UIT9.js → serve-Bq21zw1O.js} +3 -3
  88. package/dist/serve-Bq21zw1O.js.map +1 -0
  89. package/dist/{service-client-BLNeugM9.js → service-client-Cr4sxDVM.js} +1 -1
  90. package/dist/{service-client-BLNeugM9.js.map → service-client-Cr4sxDVM.js.map} +1 -1
  91. package/dist/{time-travel-ZozuPPI-.js → time-travel-8X-uAgHw.js} +2 -2
  92. package/dist/{time-travel-ZozuPPI-.js.map → time-travel-8X-uAgHw.js.map} +1 -1
  93. package/dist/{version-C0qM-qJM.js → version-Cq2kcrXL.js} +2 -2
  94. package/dist/{version-C0qM-qJM.js.map → version-Cq2kcrXL.js.map} +1 -1
  95. package/package.json +5 -5
  96. package/dist/auth-command-CXAB3_hs.js.map +0 -1
  97. package/dist/build-id-BX4QHzM0.js +0 -3
  98. package/dist/build-id-BX4QHzM0.js.map +0 -1
  99. package/dist/command-dispatcher-Vb_AJSAR.js +0 -13
  100. package/dist/command-dispatcher-Vb_AJSAR.js.map +0 -1
  101. package/dist/discover-with-bundled-CznLjkkw.js +0 -3
  102. package/dist/discover-with-bundled-CznLjkkw.js.map +0 -1
  103. package/dist/doctor-C84-hhEr.js +0 -30
  104. package/dist/doctor-C84-hhEr.js.map +0 -1
  105. package/dist/extension-BKXIr86F.js.map +0 -1
  106. package/dist/extension-CnON6Xum.js +0 -2
  107. package/dist/extension-plugin-Bmqlc6as.js +0 -2
  108. package/dist/extension-plugin-C2Yhv77x.js +0 -7
  109. package/dist/extension-plugin-C2Yhv77x.js.map +0 -1
  110. package/dist/feedback-BES_6ebi.js +0 -21
  111. package/dist/feedback-BES_6ebi.js.map +0 -1
  112. package/dist/feedback-BRbLUn9u.js +0 -2
  113. package/dist/install-WCcQ9k9M.js +0 -2
  114. package/dist/model-auth-DUPFPOjY.js +0 -2
  115. package/dist/observe-CVg-MRM2.js.map +0 -1
  116. package/dist/parse-cli-BCfFgFAC.js +0 -3
  117. package/dist/parse-cli-BCfFgFAC.js.map +0 -1
  118. package/dist/proxy-BvdBsB1O.js +0 -2
  119. package/dist/registry-B3nfN62q.js +0 -2
  120. package/dist/registry-D0NONjLv.js.map +0 -1
  121. package/dist/serve-pVR6UIT9.js.map +0 -1
@@ -1,21 +0,0 @@
1
- #!/usr/bin/env node
2
- import{n as e,t}from"./build-id-BX4QHzM0.js";import{platform as n,release as r}from"node:os";import{execFile as i}from"node:child_process";import{createApp as a}from"@x-otto/coding";import{openBrowser as o}from"@x-otto/shared";import{SDK_VERSION as s}from"@x-otto/env";import{promisify as c}from"node:util";const l=c(i);function u(e){let t=e.trim().replace(/\.git$/,``),n=t.match(/^git@[^:]+:(.+)$/);if(n)return n[1];let r=t.match(/^https?:\/\/[^/]+\/(.+)$/);if(r)return r[1]}async function d(e){try{let{stdout:t}=await l(`git`,[`remote`,`get-url`,`origin`],{cwd:e,timeout:5e3});return u(t)}catch{return}}async function f(e){return e.configuredRepo?e.configuredRepo:await d(e.cwd)||e.cliRepoArg}function p(i){return[`- otto version: ${s} (build ${e}, ${t}@dev)`,`- Node: ${process.version}`,`- OS: ${n()} ${process.arch} ${r()}`,`- Model: ${i??`(none configured)`}`].join(`
3
- `)}function m(e){let t,n,r,i,a,o=!1,s=(t,n)=>{let r=e[t+1];if(r===void 0||r.startsWith(`--`))throw Error(`${n} requires a value`);return r};for(let c=0;c<e.length;c++){let l=e[c];l===`--title`?(t=s(c,`--title`),c++):l===`--reproduce`?(n=s(c,`--reproduce`),c++):l===`--expected`?(r=s(c,`--expected`),c++):l===`--actual`?(i=s(c,`--actual`),c++):l===`--repo`?(a=s(c,`--repo`),c++):l===`--browser`&&(o=!0)}return{title:t,reproduce:n,expected:r,actual:i,repo:a,browser:o}}function h(e){e(`Usage: otto feedback --title <title> [options]
4
-
5
- Report an issue or send feedback via GitHub (non-interactive — for scripting/CI).
6
- For an interactive prompt-driven flow, use the "/feedback" command inside otto.
7
-
8
- Options:
9
- --title <title> Short issue title (required)
10
- --reproduce <text> Steps to reproduce (optional)
11
- --expected <text> Expected behavior (optional)
12
- --actual <text> Actual behavior (optional)
13
- --repo <owner/repo> Target repository (defaults to feedback_repo config, then git remote origin)
14
- --browser Skip the gh CLI channel and always use the browser fallback
15
- --help Show this help
16
- `)}async function g(e,t={}){let n=t.stdout??(e=>process.stdout.write(e)),r=t.stderr??(e=>process.stderr.write(e));if(e[0]===`help`||e[0]===`--help`)return h(n),0;let i;try{i=m(e)}catch(e){return r(`otto feedback: ${e instanceof Error?e.message:String(e)}\n`),1}if(!i.title)return r(`otto feedback: --title is required (see --help)
17
- `),1;let s=t.app??a({logger:{name:`otto-feedback`,level:`error`,destination:`stderr`},workspaceDir:t.projectDir,projectConfigPath:t.configPath});try{await s.start()}catch(e){return r(`otto feedback: failed to start app: ${e instanceof Error?e.message:String(e)}\n`),1}try{let e=s.feedbackRegistry.get();if(!e)return r(`otto feedback: feedback plugin is not available (disabled or not installed)
18
- `),1;let a=await f({configuredRepo:s.settings.get(`feedback_repo`),cliRepoArg:i.repo,cwd:t.projectDir??process.cwd()});if(!a)return r(`otto feedback: could not resolve a target repository — pass --repo or set "feedback_repo" in .otto/config.json
19
- `),1;let c=p(void 0),l={title:i.title,reproduce:i.reproduce,expected:i.expected,actual:i.actual,envInfo:c,repo:a};if(!i.browser&&e.submitIssueViaGh){let t=await e.submitIssueViaGh(l);if(t.ok)return n(`Issue created: ${t.url}\n`),0;r(`otto feedback: gh channel failed (${t.kind}) — falling back to browser\n`)}let u=e.buildIssueUrl?.(l);return u?(o(u),n(`Opened: ${u}\n`),0):(r(`otto feedback: feedback plugin does not support buildIssueUrl
20
- `),1)}finally{await s.stop()}}export{f as n,g as r,p as t};
21
- //# sourceMappingURL=feedback-BES_6ebi.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"feedback-BES_6ebi.js","names":["BUILD_ID"],"sources":["../src/commands/feedback.ts"],"sourcesContent":["/**\n * /feedback 命令的 TUI 接线层(提交/展示)。\n */\nimport { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { platform, release } from 'node:os'\nimport { SDK_VERSION } from '@x-otto/env'\nimport { BUILD_ID, BUILD_BRANCH, BUILD_HASH } from '../build-id'\nimport { createApp } from '@x-otto/coding'\nimport type { App } from '@x-otto/coding'\nimport { openBrowser } from '@x-otto/shared'\n\nconst execFileAsync = promisify(execFile)\n\n/** git remote origin URL → `owner/repo`(支持 `git@github.com:owner/repo.git` 与 `https://github.com/owner/repo.git` 两种形态)。 */\nfunction parseOwnerRepoFromGitUrl(url: string): string | undefined {\n const trimmed = url.trim().replace(/\\.git$/, '')\n const sshMatch = trimmed.match(/^git@[^:]+:(.+)$/)\n if (sshMatch) return sshMatch[1]\n const httpsMatch = trimmed.match(/^https?:\\/\\/[^/]+\\/(.+)$/)\n if (httpsMatch) return httpsMatch[1]\n return undefined\n}\n\n/** `git remote get-url origin` 解析当前工作目录的 owner/repo;非 git 仓库/无 origin 时返回 undefined(fail-soft,不抛出)。 */\nasync function resolveGitRemoteRepo(cwd: string): Promise<string | undefined> {\n try {\n const { stdout } = await execFileAsync('git', ['remote', 'get-url', 'origin'], { cwd, timeout: 5000 })\n return parseOwnerRepoFromGitUrl(stdout)\n } catch {\n return undefined\n }\n}\n\n/**\n * RFC-207 §3.4:目标仓库解析优先级——`feedback_repo` 配置 > git remote 解析 >\n * `--repo` 命令行参数。全部缺失时返回 `undefined`。\n */\nexport async function resolveFeedbackRepo(opts: {\n configuredRepo?: string\n cliRepoArg?: string\n cwd: string\n}): Promise<string | undefined> {\n if (opts.configuredRepo) return opts.configuredRepo\n const fromGit = await resolveGitRemoteRepo(opts.cwd)\n if (fromGit) return fromGit\n return opts.cliRepoArg\n}\n\n/**\n * RFC-207 §3.1 环境信息行(issue body 的\"环境信息\"小节,脱敏——只含版本/运行时/OS/\n * 模型,不含用户路径/环境变量等敏感信息)。\n */\nexport function buildFeedbackEnvInfo(modelId: string | undefined): string {\n return [\n `- otto version: ${SDK_VERSION} (build ${BUILD_ID}, ${BUILD_HASH}@${BUILD_BRANCH})`,\n `- Node: ${process.version}`,\n `- OS: ${platform()} ${process.arch} ${release()}`,\n `- Model: ${modelId ?? '(none configured)'}`,\n ].join('\\n')\n}\n\nexport interface FeedbackCommandDeps {\n stdout?: (s: string) => void\n stderr?: (s: string) => void\n projectDir?: string\n configPath?: string\n /** 测试注入:替代生产装配的 app(真实 App 类型——需要 feedbackRegistry/submitIssueViaGh,\n * 非 ServiceHostPort/AppContext 窄接口能覆盖,同 serve.ts 的 AppContext 注入模式不同)。 */\n app?: App\n}\n\nfunction parseFeedbackArgs(args: string[]): {\n title?: string\n reproduce?: string\n expected?: string\n actual?: string\n repo?: string\n browser: boolean\n} {\n let title: string | undefined\n let reproduce: string | undefined\n let expected: string | undefined\n let actual: string | undefined\n let repo: string | undefined\n let browser = false\n\n const takeValue = (i: number, name: string): string => {\n const raw = args[i + 1]\n if (raw === undefined || raw.startsWith('--')) {\n throw new Error(`${name} requires a value`)\n }\n return raw\n }\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]\n if (arg === '--title') { title = takeValue(i, '--title'); i++ }\n else if (arg === '--reproduce') { reproduce = takeValue(i, '--reproduce'); i++ }\n else if (arg === '--expected') { expected = takeValue(i, '--expected'); i++ }\n else if (arg === '--actual') { actual = takeValue(i, '--actual'); i++ }\n else if (arg === '--repo') { repo = takeValue(i, '--repo'); i++ }\n else if (arg === '--browser') { browser = true }\n }\n\n return { title, reproduce, expected, actual, repo, browser }\n}\n\nfunction printFeedbackHelp(stdout: (s: string) => void): void {\n stdout(`Usage: otto feedback --title <title> [options]\n\nReport an issue or send feedback via GitHub (non-interactive — for scripting/CI).\nFor an interactive prompt-driven flow, use the \"/feedback\" command inside otto.\n\nOptions:\n --title <title> Short issue title (required)\n --reproduce <text> Steps to reproduce (optional)\n --expected <text> Expected behavior (optional)\n --actual <text> Actual behavior (optional)\n --repo <owner/repo> Target repository (defaults to feedback_repo config, then git remote origin)\n --browser Skip the gh CLI channel and always use the browser fallback\n --help Show this help\n`)\n}\n\n/**\n * `otto feedback` 非交互顶层子命令(RFC-207 §3.2/§3.4)——CI/脚本化调用场景,\n * `--title`/`--body` 系参数直接传参跳过 TUI openInput 链。复用与 `/feedback` 斜杠\n * 命令相同的核心逻辑(`resolveFeedbackRepo`/`buildFeedbackEnvInfo`)+ 同一个\n * `FeedbackRegistry`/插件实现(`app.feedbackRegistry`),两个入口不重复业务逻辑。\n */\nexport async function runFeedbackCommand(args: string[], deps: FeedbackCommandDeps = {}): Promise<number> {\n const stdout = deps.stdout ?? ((s) => process.stdout.write(s))\n const stderr = deps.stderr ?? ((s) => process.stderr.write(s))\n\n if (args[0] === 'help' || args[0] === '--help') {\n printFeedbackHelp(stdout)\n return 0\n }\n\n let parsed: ReturnType<typeof parseFeedbackArgs>\n try {\n parsed = parseFeedbackArgs(args)\n } catch (error) {\n stderr(`otto feedback: ${error instanceof Error ? error.message : String(error)}\\n`)\n return 1\n }\n\n if (!parsed.title) {\n stderr('otto feedback: --title is required (see --help)\\n')\n return 1\n }\n\n const app =\n deps.app ??\n createApp({\n logger: { name: 'otto-feedback', level: 'error', destination: 'stderr' },\n workspaceDir: deps.projectDir,\n projectConfigPath: deps.configPath,\n })\n\n try {\n await app.start()\n } catch (error) {\n stderr(`otto feedback: failed to start app: ${error instanceof Error ? error.message : String(error)}\\n`)\n return 1\n }\n\n try {\n const provider = app.feedbackRegistry.get()\n if (!provider) {\n stderr('otto feedback: feedback plugin is not available (disabled or not installed)\\n')\n return 1\n }\n\n const configuredRepo = app.settings.get('feedback_repo') as string | undefined\n const repo = await resolveFeedbackRepo({ configuredRepo, cliRepoArg: parsed.repo, cwd: deps.projectDir ?? process.cwd() })\n if (!repo) {\n stderr('otto feedback: could not resolve a target repository — pass --repo or set \"feedback_repo\" in .otto/config.json\\n')\n return 1\n }\n\n const envInfo = buildFeedbackEnvInfo(undefined)\n const input = {\n title: parsed.title,\n reproduce: parsed.reproduce,\n expected: parsed.expected,\n actual: parsed.actual,\n envInfo,\n repo,\n }\n\n if (!parsed.browser && provider.submitIssueViaGh) {\n const result = await provider.submitIssueViaGh(input)\n if (result.ok) {\n stdout(`Issue created: ${result.url}\\n`)\n return 0\n }\n stderr(`otto feedback: gh channel failed (${result.kind}) — falling back to browser\\n`)\n }\n\n const url = provider.buildIssueUrl?.(input)\n if (!url) {\n stderr('otto feedback: feedback plugin does not support buildIssueUrl\\n')\n return 1\n }\n openBrowser(url)\n stdout(`Opened: ${url}\\n`)\n return 0\n } finally {\n await app.stop()\n }\n}\n"],"mappings":";mTAYA,MAAM,EAAgB,EAAU,EAAS,CAGzC,SAAS,EAAyB,EAAiC,CACjE,IAAM,EAAU,EAAI,MAAM,CAAC,QAAQ,SAAU,GAAG,CAC1C,EAAW,EAAQ,MAAM,mBAAmB,CAClD,GAAI,EAAU,OAAO,EAAS,GAC9B,IAAM,EAAa,EAAQ,MAAM,2BAA2B,CAC5D,GAAI,EAAY,OAAO,EAAW,GAKpC,eAAe,EAAqB,EAA0C,CAC5E,GAAI,CACF,GAAM,CAAE,UAAW,MAAM,EAAc,MAAO,CAAC,SAAU,UAAW,SAAS,CAAE,CAAE,MAAK,QAAS,IAAM,CAAC,CACtG,OAAO,EAAyB,EAAO,MACjC,CACN,QAQJ,eAAsB,EAAoB,EAIV,CAI9B,OAHI,EAAK,eAAuB,EAAK,eACrB,MAAM,EAAqB,EAAK,IAAI,EAE7C,EAAK,WAOd,SAAgB,EAAqB,EAAqC,CACxE,MAAO,CACL,mBAAmB,EAAY,UAAUA,EAAS,IAAI,EAAW,OACjE,WAAW,QAAQ,UACnB,SAAS,GAAU,CAAC,GAAG,QAAQ,KAAK,GAAG,GAAS,GAChD,YAAY,GAAW,sBACxB,CAAC,KAAK;EAAK,CAad,SAAS,EAAkB,EAOzB,CACA,IAAI,EACA,EACA,EACA,EACA,EACA,EAAU,GAER,GAAa,EAAW,IAAyB,CACrD,IAAM,EAAM,EAAK,EAAI,GACrB,GAAI,IAAQ,IAAA,IAAa,EAAI,WAAW,KAAK,CAC3C,MAAU,MAAM,GAAG,EAAK,mBAAmB,CAE7C,OAAO,GAGT,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,IAAM,EAAM,EAAK,GACb,IAAQ,WAAa,EAAQ,EAAU,EAAG,UAAU,CAAE,KACjD,IAAQ,eAAiB,EAAY,EAAU,EAAG,cAAc,CAAE,KAClE,IAAQ,cAAgB,EAAW,EAAU,EAAG,aAAa,CAAE,KAC/D,IAAQ,YAAc,EAAS,EAAU,EAAG,WAAW,CAAE,KACzD,IAAQ,UAAY,EAAO,EAAU,EAAG,SAAS,CAAE,KACnD,IAAQ,cAAe,EAAU,IAG5C,MAAO,CAAE,QAAO,YAAW,WAAU,SAAQ,OAAM,UAAS,CAG9D,SAAS,EAAkB,EAAmC,CAC5D,EAAO;;;;;;;;;;;;;EAaP,CASF,eAAsB,EAAmB,EAAgB,EAA4B,EAAE,CAAmB,CACxG,IAAM,EAAS,EAAK,SAAY,GAAM,QAAQ,OAAO,MAAM,EAAE,EACvD,EAAS,EAAK,SAAY,GAAM,QAAQ,OAAO,MAAM,EAAE,EAE7D,GAAI,EAAK,KAAO,QAAU,EAAK,KAAO,SAEpC,OADA,EAAkB,EAAO,CAClB,EAGT,IAAI,EACJ,GAAI,CACF,EAAS,EAAkB,EAAK,OACzB,EAAO,CAEd,OADA,EAAO,kBAAkB,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAAC,IAAI,CAC7E,EAGT,GAAI,CAAC,EAAO,MAEV,OADA,EAAO;EAAoD,CACpD,EAGT,IAAM,EACJ,EAAK,KACL,EAAU,CACR,OAAQ,CAAE,KAAM,gBAAiB,MAAO,QAAS,YAAa,SAAU,CACxE,aAAc,EAAK,WACnB,kBAAmB,EAAK,WACzB,CAAC,CAEJ,GAAI,CACF,MAAM,EAAI,OAAO,OACV,EAAO,CAEd,OADA,EAAO,uCAAuC,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAAC,IAAI,CAClG,EAGT,GAAI,CACF,IAAM,EAAW,EAAI,iBAAiB,KAAK,CAC3C,GAAI,CAAC,EAEH,OADA,EAAO;EAAgF,CAChF,EAIT,IAAM,EAAO,MAAM,EAAoB,CAAE,eADlB,EAAI,SAAS,IAAI,gBAAgB,CACC,WAAY,EAAO,KAAM,IAAK,EAAK,YAAc,QAAQ,KAAK,CAAE,CAAC,CAC1H,GAAI,CAAC,EAEH,OADA,EAAO;EAAmH,CACnH,EAGT,IAAM,EAAU,EAAqB,IAAA,GAAU,CACzC,EAAQ,CACZ,MAAO,EAAO,MACd,UAAW,EAAO,UAClB,SAAU,EAAO,SACjB,OAAQ,EAAO,OACf,UACA,OACD,CAED,GAAI,CAAC,EAAO,SAAW,EAAS,iBAAkB,CAChD,IAAM,EAAS,MAAM,EAAS,iBAAiB,EAAM,CACrD,GAAI,EAAO,GAET,OADA,EAAO,kBAAkB,EAAO,IAAI,IAAI,CACjC,EAET,EAAO,qCAAqC,EAAO,KAAK,+BAA+B,CAGzF,IAAM,EAAM,EAAS,gBAAgB,EAAM,CAO3C,OANK,GAIL,EAAY,EAAI,CAChB,EAAO,WAAW,EAAI,IAAI,CACnB,IALL,EAAO;EAAkE,CAClE,UAKD,CACR,MAAM,EAAI,MAAM"}
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{r as e}from"./feedback-BES_6ebi.js";export{e as runFeedbackCommand};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{i as e}from"./install-DlVJRHRT.js";export{e as handleInstall};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{n as e}from"./model-auth-qY5zeBF7.js";export{e as handleModel};
@@ -1 +0,0 @@
1
- {"version":3,"file":"observe-CVg-MRM2.js","names":[],"sources":["../src/commands/observe.ts"],"sourcesContent":["/**\n * `otto observe` 子命令 —— 观测面板:trace 时间线 / 摘要 / span 树。\n *\n * 设计依据:design/observability-platform.md §4/§5 + design/m17-platform-activation.md §3。\n * 数据源 = service REST。\n * 默认连 `http://127.0.0.1:${SERVICE_PORT}`(`otto serve` 启动),`--remote <url>` 覆盖;\n * service 不可达 → 明确报错而非静默空数据。聚合算法在 @x-otto/agent,两端同源。\n */\nimport { SERVICE_URL } from '@x-otto/env'\n\nimport {\n createServiceClient,\n reportServiceError,\n resolveRemote,\n type ServiceClient,\n} from './service-client'\nimport type { TraceSpan, TraceSummary } from '@x-otto/agent'\nimport type { TraceTimelineView } from '@x-otto/trace-view'\n\nexport interface ObserveDeps {\n /** 输出(便于测试注入)。 */\n stdout?: (s: string) => void\n stderr?: (s: string) => void\n /** fetch 注入(测试用)。 */\n fetch?: typeof globalThis.fetch\n}\n\nexport async function runObserveCommand(\n args: string[],\n deps: ObserveDeps = {},\n): Promise<number> {\n const stdout = deps.stdout ?? ((s) => process.stdout.write(s))\n const stderr = deps.stderr ?? ((s) => process.stderr.write(s))\n\n // 提取 --json 标志(在 resolveRemote 之前,避免被当作 remote URL)\n const jsonIdx = args.indexOf('--json')\n const json = jsonIdx >= 0\n const cleanArgs = json ? args.filter((_, i) => i !== jsonIdx) : args\n\n let baseUrl: string\n let rest: string[]\n try {\n ;({ baseUrl, rest } = resolveRemote(cleanArgs))\n } catch (error) {\n return reportServiceError('observe', error, stderr)\n }\n\n const [action, sessionId] = rest\n\n if (!action || action === 'help') {\n stdout(`otto observe — 观测面板(trace 时间线 / 摘要 / span 树)\n\n用法:\n otto observe summary <session-id> trace 聚合统计\n otto observe timeline <session-id> 文本时间线\n otto observe spans <session-id> span 树视图\n\n选项:\n --remote <url> service 地址(默认 OTTO_SERVICE_URL 或 ${SERVICE_URL})\n --json 输出结构化 JSON(需 service 运行)\n`)\n return 0\n }\n\n if (!sessionId) {\n stderr('otto observe: session-id is required.\\n')\n return 1\n }\n\n const client = createServiceClient(baseUrl, deps.fetch)\n\n try {\n // --json 模式:调用 /trace/timeline 输出结构化 JSON\n if (json) {\n return await observeJson(client, sessionId, stdout, stderr)\n }\n switch (action) {\n case 'summary':\n return await observeSummary(client, sessionId, stdout)\n case 'timeline':\n return await observeTimeline(client, sessionId, stdout)\n case 'spans':\n return await observeSpans(client, sessionId, stdout)\n default:\n stderr(`otto observe: unknown action '${action}'. Use summary | timeline | spans.\\n`)\n return 1\n }\n } catch (error) {\n return reportServiceError('observe', error, stderr)\n }\n}\n\nfunction fetchSpans(client: ServiceClient, sessionId: string): Promise<{ spans: TraceSpan[] }> {\n return client.get<{ spans: TraceSpan[] }>(`/api/sessions/${sessionId}/trace/spans`)\n}\n\nasync function observeSummary(\n client: ServiceClient,\n sessionId: string,\n stdout: (s: string) => void,\n): Promise<number> {\n const summary = await client.get<TraceSummary>(`/api/sessions/${sessionId}/trace/summary`)\n\n if (summary.totalEvents === 0) {\n stdout(`Session ${sessionId}: no trace events found.\\n`)\n return 0\n }\n\n const { totalEvents, kinds, turns, toolCalls, firstTs, lastTs } = summary\n const duration = firstTs !== undefined && lastTs !== undefined ? `${lastTs - firstTs}ms` : 'N/A'\n\n stdout(`Trace Summary — ${sessionId}\n──────────────────────────────────────────\n Total events: ${totalEvents}\n Turns: ${turns}\n Tool calls: ${toolCalls}\n Time span: ${duration}\n First event: ${firstTs ? new Date(firstTs).toISOString() : 'N/A'}\n Last event: ${lastTs ? new Date(lastTs).toISOString() : 'N/A'}\n\n By kind:\n${Object.entries(kinds).map(([k, v]) => ` ${k.padEnd(14)} ${v}`).join('\\n')}\n`)\n return 0\n}\n\nasync function observeTimeline(\n client: ServiceClient,\n sessionId: string,\n stdout: (s: string) => void,\n): Promise<number> {\n const { spans } = await fetchSpans(client, sessionId)\n if (spans.length === 0) {\n stdout(`Session ${sessionId}: no trace events found.\\n`)\n return 0\n }\n\n const lines = spans.map((span) => {\n const ts = new Date(span.ts).toISOString().slice(11, 23)\n const turn = span.turn !== undefined ? `T${String(span.turn).padStart(2)}` : ' -'\n const node = (span.node ?? '').padEnd(26)\n return `${String(span.seq).padStart(5)} ${ts} ${turn} ${span.kind.padEnd(12)} ${node}${span.digest ?? ''}`\n })\n\n stdout(`Trace Timeline — ${sessionId} (${lines.length} events)\n${'seq'.padStart(5)} ${'time'} ${'turn'} ${'kind'.padEnd(12)} ${'node'.padEnd(26)} digest\n${'-'.repeat(100)}\n${lines.join('\\n')}\n`)\n return 0\n}\n\nasync function observeSpans(\n client: ServiceClient,\n sessionId: string,\n stdout: (s: string) => void,\n): Promise<number> {\n const { spans } = await fetchSpans(client, sessionId)\n if (spans.length === 0) {\n stdout(`Session ${sessionId}: no trace events found.\\n`)\n return 0\n }\n\n const turnSpans = new Map<number, TraceSpan[]>()\n let maxTurn = -1\n for (const span of spans) {\n const turn = span.turn ?? 0\n if (turn > maxTurn) maxTurn = turn\n const group = turnSpans.get(turn) ?? []\n group.push(span)\n turnSpans.set(turn, group)\n }\n\n stdout(`Trace Spans — ${sessionId} (${maxTurn + 1} turns)\n`)\n for (let t = 0; t <= maxTurn; t++) {\n const group = turnSpans.get(t)\n if (!group) continue\n stdout(`▼ Turn ${t} (${group.length} events)\\n`)\n for (const span of group) {\n const node = span.node ? `[${span.node}] ` : ''\n stdout(` ├─ ${span.kind.padEnd(12)} ${node}${span.digest ?? ''}\\n`)\n }\n }\n return 0\n}\n\nasync function observeJson(\n client: ServiceClient,\n sessionId: string,\n stdout: (s: string) => void,\n stderr: (s: string) => void,\n): Promise<number> {\n try {\n const timeline = await client.get<TraceTimelineView>(\n `/api/sessions/${sessionId}/trace/timeline`,\n )\n stdout(`${JSON.stringify(timeline, null, 2)}\\n`)\n return 0\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error)\n stderr(`observe --json: ${msg}\\n`)\n return 1\n }\n}\n"],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- import{Y as e}from"./command-dispatcher-Vb_AJSAR.js";import{t}from"./version-C0qM-qJM.js";import{resolve as n}from"node:path";var r=e({SUB_COMMAND_NAMES:()=>i,getHelpLines:()=>c,parseCLI:()=>s});const i=new Set([`run`,`serve`,`daemon`,`doctor`,`config`,`migrate`,`auth`,`observe`,`debug`,`time-travel`,`mcp`,`persistenced`,`remote-persistence-server`,`extension`,`ps`,`feedback`]),a=new Map([{flags:[`--print`,`-p`],type:`mode`,value:`print`},{flags:[`--interactive`,`-i`],type:`mode`,value:`interactive`},{flags:[`--json`],type:`mode`,value:`json`},{flags:[`--model`,`-m`],type:`string`,key:`model`},{flags:[`--config`,`-c`],type:`string`,key:`configPath`},{flags:[`--project`,`-d`],type:`path`,key:`projectDir`},{flags:[`--quiet`,`-q`],type:`boolean`,key:`quiet`},{flags:[`--verbose`,`-v`],type:`boolean`,key:`verbose`},{flags:[`--max-tool-turns`],type:`number`,key:`maxToolTurns`},{flags:[`--max-tool-turn-extensions`],type:`number`,key:`maxToolTurnExtensions`},{flags:[`--prompt-token-budget`],type:`number`,key:`promptTokenBudget`},{flags:[`--prompt-time-budget`],type:`number`,key:`promptTimeBudgetMin`},{flags:[`--session-cost-budget`],type:`number`,key:`sessionCostBudget`},{flags:[`--no-stall-detection`],type:`boolean`,key:`noStallDetection`},{flags:[`--stall-window-turns`],type:`number`,key:`stallWindowTurns`},{flags:[`--stall-repeat-threshold`],type:`number`,key:`stallRepeatThreshold`},{flags:[`--continue`],type:`string`,key:`continueSession`},{flags:[`--attach`],type:`string`,key:`attachSession`},{flags:[`--force-write-lease`],type:`boolean`,key:`forceWriteLease`},{flags:[`--memory-restart-grace`],type:`boolean`,key:`memoryRestartGrace`},{flags:[`--resume-prompt`],type:`string`,key:`resumePrompt`},{flags:[`--session-url`],type:`string`,key:`sessionUrl`},{flags:[`--session-token`],type:`string`,key:`sessionToken`},{flags:[`--id`],type:`string`,key:`workspaceId`},{flags:[`--shadow`],type:`boolean`,key:`shadow`},{flags:[`--help`,`-h`],type:`boolean`,key:`showHelp`},{flags:[`--version`],type:`action`,handler:l}].flatMap(e=>e.flags.map(t=>[t,e])));var o=class{i;constructor(e){this.args=e,this.i=0}current(){return this.args[this.i]}next(){return this.args[++this.i]}advance(){this.i++}skip(e){this.i+=e}pos(){return this.i}};function s(e){let t=e.slice(2),r=new o(t),s={mode:`interactive`,projectDir:process.cwd(),verbose:!1,quiet:!1},c=r.current(),l,u=``,d,f;c&&i.has(c)?(l=c,u=t.slice(1).join(` `),r.skip(1),l===`run`&&(s.prompt=t.slice(1).filter(e=>!e.startsWith(`-`)).join(` `),s.mode=`print`)):c&&!c.startsWith(`-`)&&(d=c,f=t.slice(1));let p=s.prompt?[s.prompt]:[];for(;r.current()!==void 0;){let e=r.current();if(e===`--inspect`){s.inspect=!0,r.advance();continue}if(e?.startsWith(`--inspect=`)){let t=Number(e.slice(10));s.inspect=Number.isInteger(t)&&t>0?t:!0,r.advance();continue}if(e?.startsWith(`--restart-generation=`)){let t=Number(e.slice(21));Number.isInteger(t)&&t>0&&(s.restartGeneration=t),r.advance();continue}let t=a.get(e);if(t){switch(r.advance(),t.type){case`boolean`:s[t.key]=!0;break;case`mode`:s.mode=t.value;break;case`string`:s[t.key]=r.current(),r.advance();break;case`number`:s[t.key]=Number(r.current()),r.advance();break;case`path`:s[t.key]=n(r.current()??process.cwd()),r.advance();break;case`action`:t.handler();break}continue}e&&!e.startsWith(`-`)&&!l&&(s.prompt===void 0&&s.mode===`interactive`&&(s.mode=`print`),p.push(e)),r.advance()}return p.length>0&&(s.prompt=p.join(` `)),{options:s,subCommand:l,subCommandArgs:u,unresolvedCommandName:d,unresolvedCommandArgs:f}}function c(){return'(otto - AI 助理命令行工具((用法:( otto [提示词] 使用提示词启动(print 模式)( otto 进入交互式 TUI 模式( otto --json "query" JSON 输出模式((选项:( -i, --interactive Interactive 模式(默认)( -p, --print Print 模式(非交互)( --json JSON 输出模式( -m, --model <id> 指定模型( -c, --config <path> 配置文件路径( -d, --project <dir> 项目目录( -v, --verbose 输出详细日志( -q, --quiet 只输出 error 日志( --shadow 影子模式:otto 自有状态(凭据/会话/记忆/教训/配置/trace/日志)本次会话零磁盘写入(不保证 provider 服务端日志与 shell/OS 层痕迹;RFC-345)( --max-tool-turns <n> 单个用户回合最大工具回合数(默认 120)( --max-tool-turn-extensions <n> 触顶后压缩续跑的扩展次数(默认主会话 3 / 子 agent 0)( --prompt-token-budget <n> 单回合输出 token 预算(配置后轮次上限 ×4 退位安全阀;RFC-104)( --prompt-time-budget <min> 单回合墙钟时间预算(分钟)( --session-cost-budget <usd> 会话累计成本软预算(美元,超过一次性提醒不阻断;RFC-204)( --no-stall-detection 关闭早期停滞检测(默认开启;RFC-203)( --stall-window-turns <n> 停滞检测滑动窗口大小(需与 --stall-repeat-threshold 同时提供,默认 8)( --stall-repeat-threshold <n> 停滞检测同签名重复阈值(需与 --stall-window-turns 同时提供,默认 4)( --continue <id> 继续已有会话( --session-url <url> 远端会话持久化地址(如 http://host:3001/sessions)( --session-token <token> 远端会话持久化 Bearer token( --inspect[=port] 启用 Node.js inspector(默认: 9229)( -h, --help 显示帮助( --version 显示版本((命令:( otto run <prompt> 执行一次性任务( otto serve [--port N] [--inspect] [--static <dir>] [--token <t>] 启动 HTTP/WS service(--static 同源托管前端 SPA,--token 启用鉴权)( otto doctor [--summary|--json] 环境健康检查(环境/配置/存储状态/连通性)( otto auth login <provider> 登录(cursor / anthropic / openai-codex / github-copilot)( otto auth status 查看各 provider 凭据来源( otto auth logout <provider> 注销并清除凭据( otto config export [--project] [-o <path>] 导出配置(RFC-219)( otto config import <file> [--dry-run] [--scope global|project] [--no-plugins] [--plugins-only] [--yes] 导入配置( otto config restore [--list] 撤销最近一次导入( otto migrate export [--no-sessions] [-o <path>] 导出配置+插件清单+会话数据为迁移包(换电脑用)( otto migrate import <archive> [--no-sessions] 导入迁移包(目标已有会话数据时跳过会话部分)( otto observe <action> <id> 观测面板(summary / timeline / spans)( otto debug <action> [...] 调试面板(breakpoints / points / state)( otto time-travel <action> <id> 时间旅行(checkpoints / scrubber / restore / fork / replay)( otto mcp login <name> MCP server OAuth 登录( otto mcp logout <name> 登出 MCP server( otto mcp list 列出已认证的 MCP server( otto extension create <name> 生成插件骨架(命令 + 面板 + manifest,开箱即用)( otto extension install <name> [--yes] 安装首方/自定义插件(anthropic-provider / deepseek-provider / browser-use / …)( otto extension update [name] 检查并重装已过期的已安装 skill/plugin( otto persistenced --dir <path> --token <token> [...flags] 启动独立持久化服务(storage + events + sync)( otto remote-persistence-server [...flags] 启动最小化远程持久化服务(5 REST 端点)( otto ps [--sweep] [--include-weak] [--json] 进程群列表与孤儿清扫(SIGTERM only,RFC-196)((面板命令默认连 `otto serve` 实例(http://127.0.0.1:8417,OTTO_SERVICE_URL/--remote 可覆盖)。'.split(`(`)}function l(){process.stdout.write(`otto ${t()}\n`),process.exit(0)}export{s as n,r,i as t};
3
- //# sourceMappingURL=parse-cli-BCfFgFAC.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"parse-cli-BCfFgFAC.js","names":[],"sources":["../src/parse-cli.ts"],"sourcesContent":["import { resolve } from 'node:path'\n\nimport type { CLIOptions, RunMode } from './types'\nimport { getVersion } from './version'\n\nexport type SubCommand = 'run' | 'serve' | 'daemon' | 'doctor' | 'config' | 'migrate' | 'auth' | 'observe' | 'debug' | 'time-travel' | 'mcp' | 'persistenced' | 'remote-persistence-server' | 'extension' | 'ps' | 'feedback'\n\nexport interface ParsedCLI {\n options: CLIOptions\n /** 未命中任何内建子命令时为 `undefined`(而非 `null` 哨兵——与 SUB_COMMAND_NAMES 的\n * 元素类型保持一致,消费方无需 `.filter(n => n !== null)` 剔除哨兵值)。 */\n subCommand: SubCommand | undefined\n subCommandArgs: string\n /**\n * RFC-112 D2:内建 `SUB_COMMAND_NAMES` 未命中的第一个位置参数(候选插件 CLI 命令名,\n * 如 `otto feishu ...` 里的 `\"feishu\"`)。`undefined` 表示第一个参数已命中内建命令,\n * 或压根没有位置参数。**不改变** `options.prompt`/`subCommand` 的既有构建逻辑——\n * 这两者仍然按\"当作 prompt\"的旧行为完整计算好,供插件命令名查无匹配时零改动回退。\n */\n unresolvedCommandName?: string\n /**\n * 与 `unresolvedCommandName` 配对:该候选名之后的**原始** args(未做 flag 过滤,含 `-h`\n * 等字面量),只在插件命令表命中该名字时使用(透传给插件可执行文件)。\n */\n unresolvedCommandArgs?: string[]\n}\n\n/** RFC-112 D2:导出供 `cli.ts` 构建插件 CLI 命令表时用作保留字集合(插件不得覆盖)。 */\nexport const SUB_COMMAND_NAMES = new Set<SubCommand>([\n 'run', 'serve', 'daemon', 'doctor', 'config', 'migrate', 'auth', 'observe', 'debug', 'time-travel', 'mcp', 'persistenced', 'remote-persistence-server', 'extension', 'ps', 'feedback',\n])\n\ntype OptionEntry =\n | { flags: string[]; type: 'boolean'; key: keyof CLIOptions }\n | { flags: string[]; type: 'mode'; value: RunMode }\n | { flags: string[]; type: 'string'; key: keyof CLIOptions }\n | { flags: string[]; type: 'number'; key: keyof CLIOptions }\n | { flags: string[]; type: 'path'; key: keyof CLIOptions }\n | { flags: string[]; type: 'action'; handler: () => void }\n\nconst OPTIONS: OptionEntry[] = [\n { flags: ['--print', '-p'], type: 'mode', value: 'print' },\n { flags: ['--interactive', '-i'], type: 'mode', value: 'interactive' },\n { flags: ['--json'], type: 'mode', value: 'json' },\n { flags: ['--model', '-m'], type: 'string', key: 'model' },\n { flags: ['--config', '-c'], type: 'string', key: 'configPath' },\n { flags: ['--project', '-d'], type: 'path', key: 'projectDir' },\n { flags: ['--quiet', '-q'], type: 'boolean', key: 'quiet' },\n { flags: ['--verbose', '-v'], type: 'boolean', key: 'verbose' },\n { flags: ['--max-tool-turns'], type: 'number', key: 'maxToolTurns' },\n { flags: ['--max-tool-turn-extensions'], type: 'number', key: 'maxToolTurnExtensions' },\n { flags: ['--prompt-token-budget'], type: 'number', key: 'promptTokenBudget' },\n { flags: ['--prompt-time-budget'], type: 'number', key: 'promptTimeBudgetMin' },\n { flags: ['--session-cost-budget'], type: 'number', key: 'sessionCostBudget' },\n { flags: ['--no-stall-detection'], type: 'boolean', key: 'noStallDetection' },\n { flags: ['--stall-window-turns'], type: 'number', key: 'stallWindowTurns' },\n { flags: ['--stall-repeat-threshold'], type: 'number', key: 'stallRepeatThreshold' },\n { flags: ['--continue'], type: 'string', key: 'continueSession' },\n { flags: ['--attach'], type: 'string', key: 'attachSession' },\n { flags: ['--force-write-lease'], type: 'boolean', key: 'forceWriteLease' },\n // RFC-115 M3(P1-1 修正):仅由 cli.ts 的内存治理触发重启 chaperone 附加,不对外文档化——\n // 区分\"内存压力触发的自动重启\"与\"用户手动 otto --continue\",前者才应起算 D5 宽限期。\n { flags: ['--memory-restart-grace'], type: 'boolean', key: 'memoryRestartGrace' },\n // RFC-115 M4:仅由 cli.ts 的内存治理触发重启 chaperone 附加,不对外文档化——重启前\n // 会话正忙时的续跑原文,子进程启动后自动重新提交为续跑轮。\n { flags: ['--resume-prompt'], type: 'string', key: 'resumePrompt' },\n { flags: ['--session-url'], type: 'string', key: 'sessionUrl' },\n { flags: ['--session-token'], type: 'string', key: 'sessionToken' },\n { flags: ['--id'], type: 'string', key: 'workspaceId' },\n { flags: ['--shadow'], type: 'boolean', key: 'shadow' },\n { flags: ['--help', '-h'], type: 'boolean', key: 'showHelp' },\n { flags: ['--version'], type: 'action', handler: printVersion },\n]\n\nconst OPTION_LOOKUP: Map<string, OptionEntry> = new Map(\n OPTIONS.flatMap(e => e.flags.map(f => [f, e] as const)),\n)\n\nclass ArgCursor {\n private i: number\n constructor(private args: string[]) {\n this.i = 0\n }\n current(): string | undefined { return this.args[this.i] }\n next(): string | undefined { return this.args[++this.i] }\n advance(): void { this.i++ }\n skip(count: number): void { this.i += count }\n pos(): number { return this.i }\n}\n\nexport function parseCLI(argv: string[]): ParsedCLI {\n const args = argv.slice(2)\n const cursor = new ArgCursor(args)\n\n const options: CLIOptions = {\n mode: 'interactive',\n projectDir: process.cwd(),\n verbose: false,\n quiet: false,\n }\n\n const first = cursor.current()\n let subCommand: SubCommand | undefined\n let subCommandArgs = ''\n let unresolvedCommandName: string | undefined\n let unresolvedCommandArgs: string[] | undefined\n if (first && SUB_COMMAND_NAMES.has(first as SubCommand)) {\n subCommand = first as SubCommand\n subCommandArgs = args.slice(1).join(' ')\n cursor.skip(1)\n\n if (subCommand === 'run') {\n options.prompt = args.slice(1).filter(a => !a.startsWith('-')).join(' ')\n options.mode = 'print'\n }\n } else if (first && !first.startsWith('-')) {\n // RFC-112 D2:第一个位置参数不是内建命令,也不以 `-` 开头(不是 flag)——\n // 记录为候选插件 CLI 命令名,供 cli.ts 查插件表二次判定;不改变下方现有的\n // \"当作 prompt\" 逻辑(该逻辑仍会照常把 first 纳入 promptParts,回退路径零改动)。\n unresolvedCommandName = first\n unresolvedCommandArgs = args.slice(1)\n }\n\n let promptParts: string[] = options.prompt ? [options.prompt] : []\n\n while (cursor.current() !== undefined) {\n const arg = cursor.current()!\n\n if (arg === '--inspect') {\n options.inspect = true\n cursor.advance()\n continue\n }\n if (arg?.startsWith('--inspect=')) {\n const port = Number(arg.slice('--inspect='.length))\n options.inspect = Number.isInteger(port) && port > 0 ? port : true\n cursor.advance()\n continue\n }\n // RFC-196 M3:重启代际计数(chaperone 重启 spawn 注入,不文档化——内部可观测标记,\n // 供 ≥3 代告警与 otto ps GEN 列展示;不驱动任何行为分支)。\n if (arg?.startsWith('--restart-generation=')) {\n const gen = Number(arg.slice('--restart-generation='.length))\n if (Number.isInteger(gen) && gen > 0) options.restartGeneration = gen\n cursor.advance()\n continue\n }\n\n const entry = OPTION_LOOKUP.get(arg)\n if (entry) {\n cursor.advance()\n switch (entry.type) {\n case 'boolean':\n ;(options as unknown as Record<string, unknown>)[entry.key] = true\n break\n case 'mode':\n options.mode = entry.value\n break\n case 'string':\n ;(options as unknown as Record<string, unknown>)[entry.key] = cursor.current()\n cursor.advance()\n break\n case 'number':\n ;(options as unknown as Record<string, unknown>)[entry.key] = Number(cursor.current())\n cursor.advance()\n break\n case 'path':\n ;(options as unknown as Record<string, unknown>)[entry.key] = resolve(cursor.current() ?? process.cwd())\n cursor.advance()\n break\n case 'action':\n entry.handler()\n break\n }\n continue\n }\n\n if (arg && !arg.startsWith('-') && !subCommand) {\n if (options.prompt === undefined && options.mode === 'interactive') {\n options.mode = 'print'\n }\n promptParts.push(arg)\n }\n cursor.advance()\n }\n\n if (promptParts.length > 0) {\n options.prompt = promptParts.join(' ')\n }\n\n return { options, subCommand, subCommandArgs, unresolvedCommandName, unresolvedCommandArgs }\n}\n\n/** 帮助文本行(供 plain-text printHelp 与 TUI InfoDialog 共用)。 */\nexport function getHelpLines(): string[] {\n return [\n '',\n 'otto - AI 助理命令行工具',\n '',\n '用法:',\n ' otto [提示词] 使用提示词启动(print 模式)',\n ' otto 进入交互式 TUI 模式',\n ' otto --json \"query\" JSON 输出模式',\n '',\n '选项:',\n ' -i, --interactive Interactive 模式(默认)',\n ' -p, --print Print 模式(非交互)',\n ' --json JSON 输出模式',\n ' -m, --model <id> 指定模型',\n ' -c, --config <path> 配置文件路径',\n ' -d, --project <dir> 项目目录',\n ' -v, --verbose 输出详细日志',\n ' -q, --quiet 只输出 error 日志',\n ' --shadow 影子模式:otto 自有状态(凭据/会话/记忆/教训/配置/trace/日志)本次会话零磁盘写入(不保证 provider 服务端日志与 shell/OS 层痕迹;RFC-345)',\n ' --max-tool-turns <n> 单个用户回合最大工具回合数(默认 120)',\n ' --max-tool-turn-extensions <n> 触顶后压缩续跑的扩展次数(默认主会话 3 / 子 agent 0)',\n ' --prompt-token-budget <n> 单回合输出 token 预算(配置后轮次上限 ×4 退位安全阀;RFC-104)',\n ' --prompt-time-budget <min> 单回合墙钟时间预算(分钟)',\n ' --session-cost-budget <usd> 会话累计成本软预算(美元,超过一次性提醒不阻断;RFC-204)',\n ' --no-stall-detection 关闭早期停滞检测(默认开启;RFC-203)',\n ' --stall-window-turns <n> 停滞检测滑动窗口大小(需与 --stall-repeat-threshold 同时提供,默认 8)',\n ' --stall-repeat-threshold <n> 停滞检测同签名重复阈值(需与 --stall-window-turns 同时提供,默认 4)',\n ' --continue <id> 继续已有会话',\n ' --session-url <url> 远端会话持久化地址(如 http://host:3001/sessions)',\n ' --session-token <token> 远端会话持久化 Bearer token',\n ' --inspect[=port] 启用 Node.js inspector(默认: 9229)',\n ' -h, --help 显示帮助',\n ' --version 显示版本',\n '',\n '命令:',\n ' otto run <prompt> 执行一次性任务',\n ' otto serve [--port N] [--inspect] [--static <dir>] [--token <t>] 启动 HTTP/WS service(--static 同源托管前端 SPA,--token 启用鉴权)',\n ' otto doctor [--summary|--json] 环境健康检查(环境/配置/存储状态/连通性)',\n ' otto auth login <provider> 登录(cursor / anthropic / openai-codex / github-copilot)',\n ' otto auth status 查看各 provider 凭据来源',\n ' otto auth logout <provider> 注销并清除凭据',\n ' otto config export [--project] [-o <path>] 导出配置(RFC-219)',\n ' otto config import <file> [--dry-run] [--scope global|project] [--no-plugins] [--plugins-only] [--yes] 导入配置',\n ' otto config restore [--list] 撤销最近一次导入',\n ' otto migrate export [--no-sessions] [-o <path>] 导出配置+插件清单+会话数据为迁移包(换电脑用)',\n ' otto migrate import <archive> [--no-sessions] 导入迁移包(目标已有会话数据时跳过会话部分)',\n ' otto observe <action> <id> 观测面板(summary / timeline / spans)',\n ' otto debug <action> [...] 调试面板(breakpoints / points / state)',\n ' otto time-travel <action> <id> 时间旅行(checkpoints / scrubber / restore / fork / replay)',\n ' otto mcp login <name> MCP server OAuth 登录',\n ' otto mcp logout <name> 登出 MCP server',\n ' otto mcp list 列出已认证的 MCP server',\n ' otto extension create <name> 生成插件骨架(命令 + 面板 + manifest,开箱即用)',\n ' otto extension install <name> [--yes] 安装首方/自定义插件(anthropic-provider / deepseek-provider / browser-use / …)',\n ' otto extension update [name] 检查并重装已过期的已安装 skill/plugin',\n ' otto persistenced --dir <path> --token <token> [...flags] 启动独立持久化服务(storage + events + sync)',\n ' otto remote-persistence-server [...flags] 启动最小化远程持久化服务(5 REST 端点)',\n ' otto ps [--sweep] [--include-weak] [--json] 进程群列表与孤儿清扫(SIGTERM only,RFC-196)',\n '',\n '面板命令默认连 `otto serve` 实例(http://127.0.0.1:8417,OTTO_SERVICE_URL/--remote 可覆盖)。',\n ]\n}\n\nfunction printVersion(): void {\n process.stdout.write(`otto ${getVersion()}\\n`)\n process.exit(0)\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{t as e}from"./proxy-evg7ZvoD.js";export{e as handleProxy};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{i as e,r as t}from"./registry-D0NONjLv.js";export{t as makeRegistryClient,e as searchRegistries};
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry-D0NONjLv.js","names":[],"sources":["../src/commands/handlers/registry.ts"],"sourcesContent":["/**\n * /registry 命令:插件注册源管理(add/remove/list + 检查)\n */\nimport { RegistryClient, builtinOfficialSource } from '@x-otto/coding'\nimport { OTTO_HOME, OTTO_USER_CONFIG_DIR } from '@x-otto/env'\nimport { rankCandidates } from '@x-otto/shared'\n\nimport type { App, LoadedRegistry, RegistryEntry } from '@x-otto/coding'\nimport type { CliContext } from '../../command-dispatcher'\nimport type { SelectOption } from '@x-otto/tui'\n\n/**\n * 官方源 URL(RFC-221 D1):registry.json 经独立发布仓库(`x-ottojs/otto-registry`)\n * 的 GitHub Pages 单独发布,仓库本身保持 private(路径 B,已 grill 确认)。\n * `OTTO_OFFICIAL_REGISTRY_URL` 环境变量覆盖机制保留(开发者本地测试/CI 调试用)。\n *\n * 发布机制(RFC-221 M1):CI workflow `.github/workflows/publish-registry.yml` 在\n * `docs/registry/registry.json` 变更推送到 main 后自动同步到 otto-registry 仓库。\n * 首次发布在 CI 验证完整链路前已手动推送完成(因 GitHub Actions 计费额度暂限制了\n * CI runner 执行,已直接 SSH push 验证内容可达,计费恢复后 CI 自动化同步即正常)。\n */\nfunction officialRegistryUrl(_app: Pick<App, 'workspaceDir'>): string {\n return process.env['OTTO_OFFICIAL_REGISTRY_URL'] ??\n 'https://x-ottojs.github.io/otto-registry/registry.json'\n}\n\n/**\n * `App` 版工厂(导出复用于 `/registry remove` 参数补全接线——interactive-setup.ts 只持有\n * `App`,不持有完整 `CliContext`,见 RFC-125 D3 同款模式)。\n */\nexport function makeRegistryClient(app: Pick<App, 'workspaceDir'>): RegistryClient {\n return new RegistryClient({\n configDir: OTTO_USER_CONFIG_DIR,\n ottoHome: OTTO_HOME,\n officialSource: builtinOfficialSource(officialRegistryUrl(app)),\n })\n}\n\nfunction makeClient(ctx: CliContext): RegistryClient {\n return makeRegistryClient(ctx.app)\n}\n\nexport async function handleRegistry(args: string[], ctx: CliContext): Promise<void> {\n const client = makeClient(ctx)\n const [sub, ...rest] = args.filter((a) => !a.startsWith('-'))\n\n try {\n if (sub === 'add') {\n const [name, url] = rest\n if (!name || !url) {\n ctx.tui.info.showToast('Registry', 'Usage: /registry add <name> <url>')\n return\n }\n client.addSource(name, url)\n ctx.tui.info.showToast('Registry', `已注册 '${name}' → ${url}`)\n return\n }\n if (sub === 'remove') {\n const [name] = rest\n if (!name) {\n ctx.tui.info.showToast('Registry', 'Usage: /registry remove <name>')\n return\n }\n client.removeSource(name)\n ctx.tui.info.showToast('Registry', `已移除 '${name}'`)\n return\n }\n // 缺省/list:升级为交互式选择面板(此前是纯文本 system_notification 推对话流,\n // 无上下选择/详情展开/启用禁用入口,无法快速浏览或操作多源)。\n const sources = client.listSources()\n\n // 异步加载各源的条目计数(用于面板内展示,fail-soft:加载失败不阻断面板打开)\n const { registries, warnings } = await client.loadAll()\n const entryCounts = new Map<string, number>()\n const staleFlags = new Map<string, boolean>()\n for (const reg of registries) {\n entryCounts.set(reg.sourceName, reg.entries.length)\n staleFlags.set(reg.sourceName, reg.stale)\n }\n\n const options: SelectOption[] = sources.map((s) => {\n const count = entryCounts.get(s.name)\n const countStr = count !== undefined ? `${count} entries` : ''\n const stale = staleFlags.get(s.name) ? ' (stale cache)' : ''\n const status = s.disabled ? '✗ disabled' : '✓ enabled'\n const builtin = s.builtin ? ' · builtin' : ''\n return {\n label: s.name,\n value: s.name,\n detail: `${status}${builtin}${countStr ? ` · ${countStr}` : ''}${stale}\\n${s.url}`,\n disabled: false, // disabled 源仍可选中查看详情/重新启用\n }\n })\n\n const enabledCount = sources.filter((s) => !s.disabled).length\n ctx.tui.modal.openModal({\n kind: 'select',\n title: `Registry Sources (${enabledCount}/${sources.length} enabled)`,\n subtitle: warnings.length > 0 ? warnings.map((w) => `⚠ ${w}`).join('\\n') : undefined,\n options,\n onSelect: (value: string) => {\n const source = sources.find((s) => s.name === value)\n if (!source) return\n // 选中后显示详情 toast + 操作提示(启用/禁用、删除非内置源)\n const count = entryCounts.get(source.name)\n const countStr = count !== undefined ? `${count} entries · ` : ''\n const details = `${countStr}${source.disabled ? 'disabled' : 'enabled'}${source.builtin ? ' · builtin' : ''}\\n${source.url}`\n const actionHints: string[] = []\n if (source.builtin) {\n actionHints.push(source.disabled ? '/registry re-enable (coming soon)' : '/registry disable (coming soon)')\n } else {\n actionHints.push(`/registry remove ${source.name}`)\n }\n ctx.tui.info.showToast(source.name, `${details}\\n${actionHints.join(' · ')}`)\n },\n onCancel: () => {},\n })\n } catch (error) {\n ctx.tui.info.showToast('Registry', error instanceof Error ? error.message : String(error))\n }\n}\n\n/** search 数据面(/search 命令与 /extension 发现入口共用;RFC-201 M3)。 */\nexport async function searchRegistries(\n ctx: CliContext,\n keyword: string,\n): Promise<{ hits: Array<{ entry: RegistryEntry; sourceName: string; stale: boolean }>; warnings: string[] }> {\n const client = makeClient(ctx)\n const { registries, warnings } = await client.loadAll()\n const candidates = registries.flatMap((registry) =>\n registry.entries.map((entry) => ({ entry, registry })),\n )\n const ranked = rankCandidates(\n candidates.map((hit) => ({\n text: hit.entry.id,\n aliases: [hit.entry.description, ...(hit.entry.keywords ?? [])],\n payload: hit,\n })),\n keyword,\n { maxResults: 20 },\n )\n return {\n hits: ranked.map((r) => ({\n entry: r.item.payload.entry,\n sourceName: r.item.payload.registry.sourceName,\n stale: r.item.payload.registry.stale,\n })),\n warnings,\n }\n}\n\nexport async function handleSearch(args: string[], ctx: CliContext): Promise<void> {\n const keyword = args.filter((a) => !a.startsWith('-')).join(' ').trim()\n if (!keyword) {\n ctx.tui.info.showToast('Search', 'Usage: /search <keyword>')\n return\n }\n\n // RFC-227:框架层 async loading 门——将\"await 全流程 → openModal\"改为\n // \"openModal + async 字段:promise 内做 loadAll+rank,resolve 返回内容,\n // 框架层自动处理 loading→内容过渡\"。ranked 在 outer scope 声明供 onSelect\n // 闭包引用,async promise 内赋值(lesson_104:透传,非重新计算)。\n interface Hit { entry: RegistryEntry; registry: LoadedRegistry }\n let ranked: Array<{ item: { payload: Hit } }> | undefined\n\n ctx.tui.modal.openModal({\n kind: 'select',\n title: `Search '${keyword}'`,\n subtitle: '', // loading 态框架层填充,此处占位\n options: [] as never, // async 存在时 options 由框架层管理\n searchable: true, // 先占 searchable 模式,等结果数决定是否真的 searchable\n onSelect: (v: string) => {\n if (!ranked) return\n const hit = ranked[Number(v)]\n if (!hit) return\n const { entry } = hit.item.payload\n const installArgs = ['--as', entry.type, ...(entry.subPath ? ['--sub-path', entry.subPath] : []), entry.source]\n void import('./install').then(({ handleInstall }) => handleInstall(installArgs, ctx))\n },\n onCancel: () => {},\n async: (async () => {\n const client = makeClient(ctx)\n const { registries, warnings } = await client.loadAll()\n\n interface Hit { entry: RegistryEntry; registry: LoadedRegistry }\n const candidates: Hit[] = registries.flatMap((registry) =>\n registry.entries.map((entry) => ({ entry, registry })),\n )\n\n ranked = rankCandidates(\n candidates.map((hit) => ({\n text: hit.entry.id,\n aliases: [hit.entry.description, ...(hit.entry.keywords ?? [])],\n payload: hit,\n })),\n keyword,\n { maxResults: 20 },\n )\n\n if (ranked.length === 0) {\n const extra = warnings.length > 0 ? `\\n${warnings.map((w) => `⚠ ${w}`).join('\\n')}` : ''\n // 零命中结果——返回空选项列表,subtitle 告知用户\n return {\n title: `Search '${keyword}' — 0 hits`,\n subtitle: `No matches for '${keyword}'.${extra}`,\n options: [],\n }\n }\n\n const idCounts = new Map<string, number>()\n for (const r of ranked) {\n const id = r.item.payload.entry.id\n idCounts.set(id, (idCounts.get(id) ?? 0) + 1)\n }\n\n const subtitleWarnings = warnings.length > 0\n ? `\\n${warnings.map((w) => `⚠ ${w}`).join('\\n')}`\n : ''\n\n return {\n title: `Search '${keyword}' — ${ranked.length} hits`,\n subtitle: `Enter install (preview first) · Esc cancel${subtitleWarnings}`,\n options: ranked.map((r, i) => {\n const { entry, registry } = r.item.payload\n const caps = entry.capabilities?.length ? `[${entry.capabilities.join(', ')}]` : ''\n const stale = registry.stale ? ' (stale cache)' : ''\n const dupMark = (idCounts.get(entry.id) ?? 0) > 1 ? ` @${registry.sourceName}` : ''\n return {\n label: `${entry.id}${dupMark} (${entry.type}) ${caps}${stale}`,\n value: String(i),\n detail: entry.description,\n }\n }),\n }\n })(),\n })\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"serve-pVR6UIT9.js","names":[],"sources":["../src/commands/serve.ts"],"sourcesContent":["import type { AddressInfo } from 'node:net'\nimport { resolve } from 'node:path'\nimport { SERVICE_PORT } from '@x-otto/env'\nimport { createApp } from '@x-otto/coding'\nimport { createCodingService } from '@x-otto/service'\nimport type { AppContext } from '@x-otto/coding'\n\nimport { waitForShutdown } from './daemon-base'\n\nexport interface ServeDeps {\n stdout?: (s: string) => void\n stderr?: (s: string) => void\n /** 全局 CLI 选项透传(与 `otto run` 同源装配)。 */\n projectDir?: string\n configPath?: string\n modelId?: string\n verbose?: boolean\n /** 测试注入:替代生产装配的 app(结构 = AppContext + start/stop)。 */\n app?: AppContext & { start(): Promise<void>; stop(): Promise<void> }\n /** 测试注入:优雅退出信号(生产 = SIGINT/SIGTERM)。 */\n signal?: AbortSignal\n}\n\nexport async function runServeCommand(args: string[], deps: ServeDeps = {}): Promise<number> {\n const stdout = deps.stdout ?? ((s) => process.stdout.write(s))\n const stderr = deps.stderr ?? ((s) => process.stderr.write(s))\n\n if (args[0] === 'help' || args[0] === '--help') {\n printHelp(stdout)\n return 0\n }\n\n let port: number\n let inspect: boolean\n let staticDir: string | undefined\n let token: string | undefined\n try {\n ;({ port, inspect, staticDir, token } = parseServeArgs(args))\n } catch (error) {\n stderr(`otto serve: ${error instanceof Error ? error.message : String(error)}\\n`)\n return 1\n }\n\n const app =\n deps.app ??\n createApp({\n logger: {\n name: 'otto-serve',\n level: deps.verbose ? 'debug' : 'info',\n destination: 'stderr',\n },\n // `--inspect` 必须下传:`AppOptions.inspect` 是 `buildInspectDevtools` 的唯一开关\n // (devtools-setup.ts:19 `if (!inspect) return { devtools: null }`)。此前 serve 解析了\n // 该 flag、也据它打印\"调试器已启用\"提示,却从未传给 createApp —— 于是 `app.devtools`\n // 恒为 null,`/api/debugger/*` 全部 503、DebugBridge 也不会被构造。即 `otto serve\n // --inspect` 实际从不启用调试器(提示与事实相反)。\n inspect,\n workspaceDir: deps.projectDir,\n projectConfigPath: deps.configPath,\n modelId: deps.modelId,\n })\n\n try {\n await app.start()\n } catch (error) {\n stderr(`otto serve: failed to start app: ${error instanceof Error ? error.message : String(error)}\\n`)\n return 1\n }\n\n // --token 同时启用 HTTP Bearer(apiToken)与 WS ?token=(wsAuthToken);页面用 URL `?token=` 对上。\n const service = createCodingService(app, {\n port,\n host: '127.0.0.1',\n staticDir,\n apiToken: token,\n wsAuthToken: token,\n // RFC-335 M2:由 `otto daemon start` 下传,使 AuthorityDescriptor.instanceId 与\n // daemon state 记录一致(客户端据此确认\"连上的 authority 就是 state 里那个 daemon\")。\n // 前台直接 `otto serve` 时缺省,由 service 自行生成。\n authorityId: process.env['OTTO_AUTHORITY_ID'] || undefined,\n })\n\n try {\n await service.start()\n } catch (error) {\n stderr(`otto serve: failed to listen on port ${port}: ${error instanceof Error ? error.message : String(error)}\\n`)\n await app.stop()\n return 1\n }\n\n const actualPort = (service.httpServer.address() as AddressInfo).port\n // 不把 token 明文打进 stdout(会落 scrollback/CI 日志)——只提示需附加 ?token=。\n const webHint = token ? ' (打开时附加 ?token=<你的 token>)' : ''\n stdout(`otto service listening on http://127.0.0.1:${actualPort}${token ? ' (auth: token required)' : ''}\n${staticDir ? ` web: http://127.0.0.1:${actualPort}/${webHint} (静态页面同源托管 ${staticDir})\\n` : ''} panels: otto observe summary <session-id>\n otto time-travel checkpoints <session-id>\n otto debug breakpoints list${inspect ? '' : ' (debugger disabled — restart with `otto serve --inspect`)'}\n stop: Ctrl-C\n`)\n\n await waitForShutdown(deps.signal)\n\n stdout('otto serve: shutting down...\\n')\n await service.stop()\n await app.stop()\n return 0\n}\n\nfunction parseServeArgs(args: string[]): {\n port: number\n inspect: boolean\n staticDir?: string\n token?: string\n} {\n let port = SERVICE_PORT\n let inspect = false\n let staticDir: string | undefined\n let token: string | undefined\n\n // 取下一个值;缺失或形如 --flag(误把下个选项当值)即报错,避免静默吞掉选项。\n const takeValue = (i: number, name: string): string => {\n const raw = args[i + 1]\n if (raw === undefined || raw.startsWith('--')) {\n throw new Error(`${name} requires a value`)\n }\n return raw\n }\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]\n if (arg === '--port' || arg === '-p') {\n const raw = takeValue(i, '--port')\n i++\n const n = Number(raw)\n if (!Number.isInteger(n) || n < 0 || n > 65535) {\n throw new Error(`invalid --port value: ${raw}`)\n }\n port = n\n } else if (arg === '--inspect') {\n inspect = true\n } else if (arg === '--static') {\n staticDir = resolve(takeValue(i, '--static'))\n i++\n } else if (arg === '--token') {\n token = takeValue(i, '--token')\n i++\n }\n // 其它(含全局 flag --verbose/--model 等,经 ctx.args 透传进来)忽略——\n // 不能 throw,否则 `otto serve --verbose` 会误伤(全局 flag 由 parseCLI 已解析)。\n }\n\n return { port, inspect, staticDir, token }\n}\n\nfunction printHelp(stdout: (s: string) => void): void {\n stdout(`otto serve — 启动 HTTP/WS service(观测/调试/时间旅行面板的对端)\n\n用法:\n otto serve [--port <n>] [--inspect] [--static <dir>] [--token <t>]\n\n选项:\n --port, -p <n> 监听端口(默认 ${SERVICE_PORT},可经 OTTO_SERVICE_PORT 覆盖;0 = 随机)\n --inspect 启用调试器(断点/暂停面板需要)\n --static <dir> 同源托管一个已构建的前端目录(SPA),页面与 /api、/ws 同端口免 CORS\n --token <t> 启用鉴权:HTTP /api/* 需 Bearer,WS 需 ?token=;页面用 URL ?token=<t> 对上\n\n面板命令默认连 http://127.0.0.1:${SERVICE_PORT}(可 --remote 覆盖)\n`)\n}\n"],"mappings":";8NAuBA,eAAsB,EAAgB,EAAgB,EAAkB,EAAE,CAAmB,CAC3F,IAAM,EAAS,EAAK,SAAY,GAAM,QAAQ,OAAO,MAAM,EAAE,EACvD,EAAS,EAAK,SAAY,GAAM,QAAQ,OAAO,MAAM,EAAE,EAE7D,GAAI,EAAK,KAAO,QAAU,EAAK,KAAO,SAEpC,OADA,EAAU,EAAO,CACV,EAGT,IAAI,EACA,EACA,EACA,EACJ,GAAI,EACA,uCAAsC,EAAe,EAAK,QACrD,EAAO,CAEd,OADA,EAAO,eAAe,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAAC,IAAI,CAC1E,EAGT,IAAM,EACJ,EAAK,KACL,EAAU,CACR,OAAQ,CACN,KAAM,aACN,MAAO,EAAK,QAAU,QAAU,OAChC,YAAa,SACd,CAMD,UACA,aAAc,EAAK,WACnB,kBAAmB,EAAK,WACxB,QAAS,EAAK,QACf,CAAC,CAEJ,GAAI,CACF,MAAM,EAAI,OAAO,OACV,EAAO,CAEd,OADA,EAAO,oCAAoC,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAAC,IAAI,CAC/F,EAIT,IAAM,EAAU,EAAoB,EAAK,CACvC,OACA,KAAM,YACN,YACA,SAAU,EACV,YAAa,EAIb,YAAa,QAAQ,IAAI,mBAAwB,IAAA,GAClD,CAAC,CAEF,GAAI,CACF,MAAM,EAAQ,OAAO,OACd,EAAO,CAGd,OAFA,EAAO,wCAAwC,EAAK,IAAI,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAAC,IAAI,CACnH,MAAM,EAAI,MAAM,CACT,EAGT,IAAM,EAAc,EAAQ,WAAW,SAAS,CAAiB,KAejE,OAZA,EAAO,8CAA8C,IAAa,EAAQ,4BAA8B,GAAG;EAC3G,EAAY,+BAA+B,EAAW,GAFtC,EAAQ,6BAA+B,GAEU,eAAe,EAAU,KAAO,GAAG;;wCAE9D,EAAU,GAAK,+DAA+D;;EAEpH,CAEA,MAAM,EAAgB,EAAK,OAAO,CAElC,EAAO;EAAiC,CACxC,MAAM,EAAQ,MAAM,CACpB,MAAM,EAAI,MAAM,CACT,EAGT,SAAS,EAAe,EAKtB,CACA,IAAI,EAAO,EACP,EAAU,GACV,EACA,EAGE,GAAa,EAAW,IAAyB,CACrD,IAAM,EAAM,EAAK,EAAI,GACrB,GAAI,IAAQ,IAAA,IAAa,EAAI,WAAW,KAAK,CAC3C,MAAU,MAAM,GAAG,EAAK,mBAAmB,CAE7C,OAAO,GAGT,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,IAAM,EAAM,EAAK,GACjB,GAAI,IAAQ,UAAY,IAAQ,KAAM,CACpC,IAAM,EAAM,EAAU,EAAG,SAAS,CAClC,IACA,IAAM,EAAI,OAAO,EAAI,CACrB,GAAI,CAAC,OAAO,UAAU,EAAE,EAAI,EAAI,GAAK,EAAI,MACvC,MAAU,MAAM,yBAAyB,IAAM,CAEjD,EAAO,OACE,IAAQ,YACjB,EAAU,GACD,IAAQ,YACjB,EAAY,EAAQ,EAAU,EAAG,WAAW,CAAC,CAC7C,KACS,IAAQ,YACjB,EAAQ,EAAU,EAAG,UAAU,CAC/B,KAMJ,MAAO,CAAE,OAAM,UAAS,YAAW,QAAO,CAG5C,SAAS,EAAU,EAAmC,CACpD,EAAO;;;;;;6BAMoB,EAAa;;;;;2BAKf,EAAa;EACtC"}