@x-otto/cli 0.0.1-alpha.42 → 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 (71) hide show
  1. package/README.md +13 -6
  2. package/dist/build-id-D_JURZdd.js +3 -0
  3. package/dist/build-id-D_JURZdd.js.map +1 -0
  4. package/dist/bundled-extensions/plugin-otto-wire-protocols/plugin-dist/meta.json +1 -1
  5. package/dist/bundled-extensions/plugin-otto-wire-protocols/plugin-dist/plugin.cjs +2 -1
  6. package/dist/bundled-extensions/plugin-otto-wire-protocols/src/openai-responses.ts +5 -1
  7. package/dist/{command-dispatcher-yqVwk7Gk.js → command-dispatcher-Dxj41r5P.js} +14 -14
  8. package/dist/command-dispatcher-Dxj41r5P.js.map +1 -0
  9. package/dist/config-migration-DatflIxs.js.map +1 -1
  10. package/dist/create-host-app-DG58-vRA.js +2 -0
  11. package/dist/{daemon-base-YOWgYYN7.js → daemon-base-Y1XI61JY.js} +1 -1
  12. package/dist/{daemon-base-YOWgYYN7.js.map → daemon-base-Y1XI61JY.js.map} +1 -1
  13. package/dist/{doctor-CuNvDmyA.js → doctor-DXBLkbkP.js} +9 -9
  14. package/dist/doctor-DXBLkbkP.js.map +1 -0
  15. package/dist/{doctor-attach-_zeIJewx.js → doctor-attach-DEMuyBOk.js} +2 -2
  16. package/dist/{doctor-attach-_zeIJewx.js.map → doctor-attach-DEMuyBOk.js.map} +1 -1
  17. package/dist/{doctor-cdp-K_mIFRfA.js → doctor-cdp-CnJUVNOB.js} +1 -1
  18. package/dist/{doctor-cdp-K_mIFRfA.js.map → doctor-cdp-CnJUVNOB.js.map} +1 -1
  19. package/dist/{doctor-heap-Rr2nNvcw.js → doctor-heap-Eu3LZj-F.js} +2 -2
  20. package/dist/{doctor-heap-Rr2nNvcw.js.map → doctor-heap-Eu3LZj-F.js.map} +1 -1
  21. package/dist/{doctor-ps-OL3FGQYu.js → doctor-ps-JBgCH77n.js} +2 -2
  22. package/dist/{doctor-ps-OL3FGQYu.js.map → doctor-ps-JBgCH77n.js.map} +1 -1
  23. package/dist/export-trajectory-D-BcH0Wt.js +14 -0
  24. package/dist/export-trajectory-D-BcH0Wt.js.map +1 -0
  25. package/dist/extension-CTyrcdT1.js +2 -0
  26. package/dist/{extension-1-lxuerZ.js → extension-DVEml5IN.js} +35 -34
  27. package/dist/{extension-1-lxuerZ.js.map → extension-DVEml5IN.js.map} +1 -1
  28. package/dist/{feedback-CYxO8zho.js → feedback-CYFY2MC4.js} +2 -2
  29. package/dist/{feedback-CYxO8zho.js.map → feedback-CYFY2MC4.js.map} +1 -1
  30. package/dist/feedback-D7Po4mlE.js +2 -0
  31. package/dist/{feishu-setup-B6ETf-8Y.js → feishu-setup-5ZoxtH0J.js} +1 -1
  32. package/dist/{feishu-setup-B6ETf-8Y.js.map → feishu-setup-5ZoxtH0J.js.map} +1 -1
  33. package/dist/{ftue-doctor-recovery-DeAf8jVo.js → ftue-doctor-recovery-8FeDBFOc.js} +1 -1
  34. package/dist/{ftue-doctor-recovery-DeAf8jVo.js.map → ftue-doctor-recovery-8FeDBFOc.js.map} +1 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +7 -7
  37. package/dist/index.js.map +1 -1
  38. package/dist/install-DlVJRHRT.js.map +1 -1
  39. package/dist/{mcp-DbTYT7hB.js → mcp-Cm4-OhXI.js} +1 -1
  40. package/dist/{mcp-DbTYT7hB.js.map → mcp-Cm4-OhXI.js.map} +1 -1
  41. package/dist/mcp-server-Dpza3yn2.js +5 -0
  42. package/dist/mcp-server-Dpza3yn2.js.map +1 -0
  43. package/dist/{migrate-boDXhEyV.js → migrate-RlBJqJnB.js} +1 -1
  44. package/dist/{migrate-boDXhEyV.js.map → migrate-RlBJqJnB.js.map} +1 -1
  45. package/dist/{observe-CZ96Vre9.js → observe-Dxfud-t7.js} +1 -1
  46. package/dist/{observe-CZ96Vre9.js.map → observe-Dxfud-t7.js.map} +1 -1
  47. package/dist/parse-cli-BSJEQtBo.js +3 -0
  48. package/dist/parse-cli-BSJEQtBo.js.map +1 -0
  49. package/dist/{persistence-CpwMgSMe.js → persistence-CRFhOYx6.js} +2 -2
  50. package/dist/{persistence-CpwMgSMe.js.map → persistence-CRFhOYx6.js.map} +1 -1
  51. package/dist/{plugin-assembly-check-C2TephMb.js → plugin-assembly-check-DEozmcJ7.js} +1 -1
  52. package/dist/{plugin-assembly-check-C2TephMb.js.map → plugin-assembly-check-DEozmcJ7.js.map} +1 -1
  53. package/dist/proxy-evg7ZvoD.js.map +1 -1
  54. package/dist/{ps-DKrluEuy.js → ps-DiKCLKbs.js} +1 -1
  55. package/dist/{ps-DKrluEuy.js.map → ps-DiKCLKbs.js.map} +1 -1
  56. package/dist/{run-attach-CvGCWF_i.js → run-attach-DDpMk2_N.js} +1 -1
  57. package/dist/{run-attach-CvGCWF_i.js.map → run-attach-DDpMk2_N.js.map} +1 -1
  58. package/dist/{serve-DbBDYdoC.js → serve-Ke0nwN9Y.js} +2 -2
  59. package/dist/{serve-DbBDYdoC.js.map → serve-Ke0nwN9Y.js.map} +1 -1
  60. package/dist/{version-BmdAi4pI.js → version-BKPdYoHG.js} +2 -2
  61. package/dist/{version-BmdAi4pI.js.map → version-BKPdYoHG.js.map} +1 -1
  62. package/package.json +11 -11
  63. package/dist/build-id-CGCF2QT6.js +0 -3
  64. package/dist/build-id-CGCF2QT6.js.map +0 -1
  65. package/dist/command-dispatcher-yqVwk7Gk.js.map +0 -1
  66. package/dist/create-host-app-DXII2WTM.js +0 -2
  67. package/dist/doctor-CuNvDmyA.js.map +0 -1
  68. package/dist/extension-DWGIIBc6.js +0 -2
  69. package/dist/feedback-CvjPT9wO.js +0 -2
  70. package/dist/parse-cli--eliQ1xw.js +0 -3
  71. package/dist/parse-cli--eliQ1xw.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{t as e}from"./discover-with-bundled-CF8qFP41.js";import{homedir as t}from"node:os";import{HIGH_RISK_CAPABILITIES as n,InstallManager as r,RegistryClient as i,builtinOfficialSource as a,checkUpgrades as o,compilePluginModule as s,compilePluginPanels as c,defaultPostInstallExecutor as l,evaluatePluginTrust as u,findWorkspaceRoot as d,grantPluginCapabilities as f,installPluginFromDir as p,installPluginFromPackage as m,purgePluginState as h,readHighRiskCapabilities as g,recordPluginInstalled as _,resolvePackageDir as v,scanInstalledVersions as ee,trustPlugin as y,untrustPlugin as te}from"@x-otto/coding";import{OTTO_CONFIG_FILENAME as b,OTTO_HOME as x,OTTO_USER_CONFIG_DIR as S}from"@x-otto/env";import{join as C,resolve as w,sep as ne}from"node:path";import{existsSync as T,lstatSync as E,mkdirSync as D,readFileSync as O,readlinkSync as re,symlinkSync as ie,watch as ae,writeFileSync as oe}from"node:fs";import{createInterface as se}from"node:readline/promises";import ce from"react";import{ConfirmDialog as le,runStandaloneTui as ue}from"@x-otto/tui/standalone";import{SettingsManager as k}from"@x-otto/setting";const A=/^[a-z0-9]+(?:-[a-z0-9]+)*$/;function de(e,t={}){let n={commands:!0,panels:[{id:`status`,title:`${e} status`,entry:`panels-dist/status.mjs`}]},r=[];t.withProvider&&(n.providers=[{id:`example`,baseUrl:`https://api.example.com/v1`,wireApi:`openai-completions`,envKey:`EXAMPLE_API_KEY`,models:[{id:`example/gpt-tiny`,contextWindow:8192,maxOutput:512}]}],r.push(`provider`)),t.withRenderer&&(n.renderers=[{id:`screenshot`,matcher:{toolName:`browser_screenshot`},entry:`renderers-dist/screenshot.js`}],r.push(`tui.renderer`)),t.withI18n!==!1&&(n.i18nDir=`locale`);let i={id:e,name:e,version:`0.1.0`,description:`An otto extension: ${e}`,contributes:n,scripts:{postinstall:`otto extension build`}};return r.length&&(i.capabilities=r),`${JSON.stringify(i,null,2)}\n`}function fe(e){return`${JSON.stringify({"hello.description":`Say hello from the ${e} plugin`},null,2)}\n`}function pe(e){return`${JSON.stringify({"hello.description":`从 ${e} 插件说 hello`},null,2)}\n`}function me(e){return`/**
2
+ import{t as e}from"./discover-with-bundled-CF8qFP41.js";import{homedir as t}from"node:os";import{HIGH_RISK_CAPABILITIES as n,InstallManager as r,RegistryClient as i,builtinOfficialSource as a,checkUpgrades as o,compilePluginModule as s,compilePluginPanels as c,defaultPostInstallExecutor as l,evaluatePluginTrust as u,findWorkspaceRoot as d,grantPluginCapabilities as f,grantPluginCapabilitiesWithVersion as p,grantedPluginCapabilitiesForVersion as m,installPluginFromDir as h,installPluginFromPackage as g,purgePluginState as _,readHighRiskCapabilities as v,recordPluginInstalled as ee,resolvePackageDir as y,scanInstalledVersions as te,trustPlugin as b,untrustPlugin as ne}from"@x-otto/coding";import{OTTO_CONFIG_FILENAME as x,OTTO_HOME as S,OTTO_USER_CONFIG_DIR as re}from"@x-otto/env";import{join as C,resolve as w,sep as T}from"node:path";import{existsSync as E,lstatSync as ie,mkdirSync as D,readFileSync as O,readlinkSync as ae,symlinkSync as oe,watch as se,writeFileSync as ce}from"node:fs";import{createInterface as le}from"node:readline/promises";import ue from"react";import{ConfirmDialog as de,runStandaloneTui as fe}from"@x-otto/tui/standalone";import{SettingsManager as k}from"@x-otto/setting";const A=/^[a-z0-9]+(?:-[a-z0-9]+)*$/;function pe(e,t={}){let n={commands:!0,panels:[{id:`status`,title:`${e} status`,entry:`panels-dist/status.mjs`}]},r=[];t.withProvider&&(n.providers=[{id:`example`,baseUrl:`https://api.example.com/v1`,wireApi:`openai-completions`,envKey:`EXAMPLE_API_KEY`,models:[{id:`example/gpt-tiny`,contextWindow:8192,maxOutput:512}]}],r.push(`provider`)),t.withRenderer&&(n.renderers=[{id:`screenshot`,matcher:{toolName:`browser_screenshot`},entry:`renderers-dist/screenshot.js`}],r.push(`tui.renderer`)),t.withI18n!==!1&&(n.i18nDir=`locale`);let i={id:e,name:e,version:`0.1.0`,description:`An otto extension: ${e}`,contributes:n,scripts:{postinstall:`otto extension build`}};return r.length&&(i.capabilities=r),`${JSON.stringify(i,null,2)}\n`}function me(e){return`${JSON.stringify({"hello.description":`Say hello from the ${e} plugin`},null,2)}\n`}function he(e){return`${JSON.stringify({"hello.description":`从 ${e} 插件说 hello`},null,2)}\n`}function j(e){return`/**
3
3
  * ${e} — definePlugin 工具示例(RFC-105 D4)。
4
4
  * 需 manifest 声明 capabilities: ["tools"] 并经信任门后才加载执行。
5
5
  * 运行 otto extension build → 编译 → /extension reload 生效。
@@ -27,7 +27,7 @@ export default definePlugin((ctx) => ({
27
27
  },
28
28
  ],
29
29
  }))
30
- `}function j(e){return`/**
30
+ `}function M(e){return`/**
31
31
  * ${e} screenshot renderer — 自定义 browser_screenshot 工具结果的渲染方式。
32
32
  * 签名:(message: unknown, columns: number) => string[]
33
33
  * 返回 ANSI 着色字符串数组,与 renderMessageLines 同构(不引入 React)。
@@ -41,14 +41,14 @@ module.exports = function screenshotRenderer(message: unknown, columns: number):
41
41
  ' use /extension → ${e} → open panel → preview',
42
42
  ]
43
43
  }
44
- `}function M(e){return`---
44
+ `}function N(e){return`---
45
45
  description: Say hello from the ${e} plugin
46
46
  argument-hint: [your name]
47
47
  ---
48
48
  Hello from the **${e}** plugin! 👋
49
49
 
50
50
  You passed: $ARGUMENTS
51
- `}function N(e){return`import React from 'react'
51
+ `}function P(e){return`import React from 'react'
52
52
  import { Box, Text } from 'ink'
53
53
 
54
54
  /**
@@ -65,7 +65,7 @@ export default function StatusPanel(): React.ReactElement {
65
65
  </Box>
66
66
  )
67
67
  }
68
- `}function P(e){return`# ${e}
68
+ `}function F(e){return`# ${e}
69
69
 
70
70
  一个 otto 插件骨架(RFC-082 Tier 0:纯文件,零编译即可用)。
71
71
 
@@ -95,31 +95,31 @@ otto extension dev --link <workspace> # 链接进工作区 + 监视改动(
95
95
 
96
96
  改命令/agent/skill/manifest 后,在 otto 内 \`/extension reload\` 即生效。
97
97
  (面板 \`panels/*.tsx\` 的热编译待 esbuild 依赖接线,当前需手动编译为 \`panels-dist/*.js\`。)
98
- `}function F(e,t,n={}){if(!A.test(e))throw Error(`插件名须 kebab-case(小写字母/数字/连字符,首尾非连字符):${e}`);let r=C(t,e);if(T(r))throw Error(`目录已存在,拒绝覆盖:${r}`);D(C(r,`commands`),{recursive:!0}),D(C(r,`panels`),{recursive:!0});let i=[],a=(e,t)=>{D(C(r,e,`..`),{recursive:!0}),oe(C(r,e),t),i.push(e)};return a(`otto-plugin.json`,de(e,n)),a(`commands/hello.md`,M(e)),a(`panels/status.tsx`,N(e)),a(`.gitignore`,`panels-dist/
98
+ `}function I(e,t,n={}){if(!A.test(e))throw Error(`插件名须 kebab-case(小写字母/数字/连字符,首尾非连字符):${e}`);let r=C(t,e);if(E(r))throw Error(`目录已存在,拒绝覆盖:${r}`);D(C(r,`commands`),{recursive:!0}),D(C(r,`panels`),{recursive:!0});let i=[],a=(e,t)=>{D(C(r,e,`..`),{recursive:!0}),ce(C(r,e),t),i.push(e)};return a(`otto-plugin.json`,pe(e,n)),a(`commands/hello.md`,N(e)),a(`panels/status.tsx`,P(e)),a(`.gitignore`,`panels-dist/
99
99
  renderers-dist/
100
100
  plugin-dist/
101
101
  dist/
102
102
  bin/
103
- `),n.withTool&&a(`plugin.ts`,me(e)),n.withRenderer&&(D(C(r,`renderers`),{recursive:!0}),a(`renderers/screenshot.ts`,j(e))),n.withI18n!==!1&&(D(C(r,`locale`),{recursive:!0}),a(`locale/en.json`,fe(e)),a(`locale/zh.json`,pe(e))),a(`README.md`,P(e)),{dir:r,files:i}}function I(e,t){let n=e.find(e=>!e.startsWith(`-`));if(!n)return t.stderr(`用法: otto extension create <name> [--with-tool] [--with-provider] [--with-renderer] [--no-i18n]
104
- `),1;let r={withTool:e.includes(`--with-tool`),withProvider:e.includes(`--with-provider`),withRenderer:e.includes(`--with-renderer`),withI18n:!e.includes(`--no-i18n`)};try{let{files:e}=F(n,process.cwd(),r);t.stdout(`✓ 已创建插件 ${n}/\n`);for(let r of e)t.stdout(` ${n}/${r}\n`);let i=[`cp -r ${n} <workspace>/.otto/plugins/ # 装入工作区`,`# 在 otto 内 /extension reload,然后运行 /hello world`,`# 项目级插件含可执行面需 /trust plugin ${n}`];return r.withTool&&i.push(`# plugin.ts 编译/加载需信任门后 —— otto extension build → /extension reload`),r.withProvider&&i.push(`# 声明式 provider 无需编译,manifest 已含示例 —— /extension reload 后即生效`),r.withRenderer&&i.push(`# renderer 源码在 renderers/,需编译:otto extension build → /extension reload`),r.withI18n&&i.push(`# locale/*.json 无需编译,manifest 已声明 i18nDir —— /extension reload 后即生效`),t.stdout(`
103
+ `),n.withTool&&a(`plugin.ts`,j(e)),n.withRenderer&&(D(C(r,`renderers`),{recursive:!0}),a(`renderers/screenshot.ts`,M(e))),n.withI18n!==!1&&(D(C(r,`locale`),{recursive:!0}),a(`locale/en.json`,me(e)),a(`locale/zh.json`,he(e))),a(`README.md`,F(e)),{dir:r,files:i}}function L(e,t){let n=e.find(e=>!e.startsWith(`-`));if(!n)return t.stderr(`用法: otto extension create <name> [--with-tool] [--with-provider] [--with-renderer] [--no-i18n]
104
+ `),1;let r={withTool:e.includes(`--with-tool`),withProvider:e.includes(`--with-provider`),withRenderer:e.includes(`--with-renderer`),withI18n:!e.includes(`--no-i18n`)};try{let{files:e}=I(n,process.cwd(),r);t.stdout(`✓ 已创建插件 ${n}/\n`);for(let r of e)t.stdout(` ${n}/${r}\n`);let i=[`cp -r ${n} <workspace>/.otto/plugins/ # 装入工作区`,`# 在 otto 内 /extension reload,然后运行 /hello world`,`# 项目级插件含可执行面需 /trust plugin ${n}`];return r.withTool&&i.push(`# plugin.ts 编译/加载需信任门后 —— otto extension build → /extension reload`),r.withProvider&&i.push(`# 声明式 provider 无需编译,manifest 已含示例 —— /extension reload 后即生效`),r.withRenderer&&i.push(`# renderer 源码在 renderers/,需编译:otto extension build → /extension reload`),r.withI18n&&i.push(`# locale/*.json 无需编译,manifest 已声明 i18nDir —— /extension reload 后即生效`),t.stdout(`
105
105
  下一步:
106
106
  `+i.join(`
107
107
  `)+`
108
- `),0}catch(e){return t.stderr(`otto extension create 失败: ${e.message}\n`),1}}function L(e,t){let{compiled:n,errors:r,skipped:i}=c(e);if(i)return t.stdout(` (无 panels/*.tsx,跳过面板编译)
109
- `),0;for(let e of n)t.stdout(` ✓ 编译 ${e}\n`);for(let e of r)t.stderr(` ✗ ${e.entry}: ${e.message}\n`);return r.length}async function R(e,t){try{return await s(e)&&t.stdout(` ✓ 编译 ${C(`plugin-dist`,`plugin.cjs`)}\n`),0}catch(e){return t.stderr(` ✗ plugin.ts: ${e.message}\n`),1}}function z(e,t){let n=w(B(e,`--dir`)??process.cwd());return T(C(n,`otto-plugin.json`))?(t.stdout(`▶ otto extension build:${n}\n`),L(n,t)>0?1:0):(t.stderr(`otto extension build 失败: 未找到 otto-plugin.json:${n}\n`),1)}function B(e,t){let n=e.indexOf(t);return n>=0&&n+1<e.length?e[n+1]:void 0}function V(e){let t=C(e,`otto-plugin.json`);if(!T(t))throw Error(`未找到 otto-plugin.json:${e}(请在插件目录内运行,或用 --dir <path>)`);let n;try{n=JSON.parse(O(t,`utf-8`))}catch{throw Error(`otto-plugin.json 非法 JSON:${t}`)}let r=n?.id;if(typeof r!=`string`||!A.test(r))throw Error(`otto-plugin.json 缺少合法 id(kebab-case):${t}`);return r}function H(e,t,n){let r=C(n,`.otto`,`plugins`);D(r,{recursive:!0});let i=C(r,t);if(T(i)||U(i)){if(U(i))try{if(w(re(i))===w(e))return i}catch{}throw Error(`目标已存在且非本插件 dev 链接,拒绝覆盖:${i}`)}return ie(w(e),i),i}function U(e){try{return E(e).isSymbolicLink()}catch{return!1}}function W(e,t){return`[${t}] ${e} 改动 → 在 otto 内 /extension reload 生效\n`}function he(e){return[e.getHours(),e.getMinutes(),e.getSeconds()].map(e=>String(e).padStart(2,`0`)).join(`:`)}async function ge(e,t){let n=w(B(e,`--dir`)??process.cwd()),r;try{r=V(n)}catch(e){return t.stderr(`otto extension dev 失败: ${e.message}\n`),Promise.resolve(1)}t.stdout(`▶ otto extension dev:${r}\n 监视 ${n}\n`);let i=B(e,`--link`);if(i)try{let e=H(n,r,w(i));t.stdout(` 已链接 → ${e}\n`)}catch(e){t.stderr(` 链接失败:${e.message}\n`)}let a=T(C(n,`panels`));a&&(t.stdout(` 编译面板…
110
- `),L(n,t));let o=T(C(n,`plugin.ts`))||T(C(n,`plugin.tsx`));return o&&(t.stdout(` 编译 plugin.ts…
111
- `),await R(n,t)),t.stdout(` 改动后在 otto 内 /extension reload 生效。Ctrl+C 退出。
112
- `),new Promise(e=>{let r;try{r=ae(n,{recursive:!0},(e,r)=>{if(!r)return;let i=String(r);i.includes(`panels-dist`)||i.includes(`plugin-dist`)||i.startsWith(`.`)||(t.stdout(W(i,he(new Date))),a&&i.endsWith(`.tsx`)&&i!==`plugin.tsx`&&L(n,t),o&&(i===`plugin.ts`||i===`plugin.tsx`)&&R(n,t))})}catch(n){t.stderr(` 监视启动失败(平台可能不支持递归监视):${n.message}\n`),e(1);return}let i=()=>{r?.close(),process.off(`SIGINT`,i),t.stdout(`
108
+ `),0}catch(e){return t.stderr(`otto extension create 失败: ${e.message}\n`),1}}function R(e,t){let{compiled:n,errors:r,skipped:i}=c(e);if(i)return t.stdout(` (无 panels/*.tsx,跳过面板编译)
109
+ `),0;for(let e of n)t.stdout(` ✓ 编译 ${e}\n`);for(let e of r)t.stderr(` ✗ ${e.entry}: ${e.message}\n`);return r.length}async function z(e,t){try{return await s(e)&&t.stdout(` ✓ 编译 ${C(`plugin-dist`,`plugin.cjs`)}\n`),0}catch(e){return t.stderr(` ✗ plugin.ts: ${e.message}\n`),1}}function ge(e,t){let n=w(B(e,`--dir`)??process.cwd());return E(C(n,`otto-plugin.json`))?(t.stdout(`▶ otto extension build:${n}\n`),R(n,t)>0?1:0):(t.stderr(`otto extension build 失败: 未找到 otto-plugin.json:${n}\n`),1)}function B(e,t){let n=e.indexOf(t);return n>=0&&n+1<e.length?e[n+1]:void 0}function V(e){let t=C(e,`otto-plugin.json`);if(!E(t))throw Error(`未找到 otto-plugin.json:${e}(请在插件目录内运行,或用 --dir <path>)`);let n;try{n=JSON.parse(O(t,`utf-8`))}catch{throw Error(`otto-plugin.json 非法 JSON:${t}`)}let r=n?.id;if(typeof r!=`string`||!A.test(r))throw Error(`otto-plugin.json 缺少合法 id(kebab-case):${t}`);return r}function H(e,t,n){let r=C(n,`.otto`,`plugins`);D(r,{recursive:!0});let i=C(r,t);if(E(i)||U(i)){if(U(i))try{if(w(ae(i))===w(e))return i}catch{}throw Error(`目标已存在且非本插件 dev 链接,拒绝覆盖:${i}`)}return oe(w(e),i),i}function U(e){try{return ie(e).isSymbolicLink()}catch{return!1}}function W(e,t){return`[${t}] ${e} 改动 → 在 otto 内 /extension reload 生效\n`}function _e(e){return[e.getHours(),e.getMinutes(),e.getSeconds()].map(e=>String(e).padStart(2,`0`)).join(`:`)}async function ve(e,t){let n=w(B(e,`--dir`)??process.cwd()),r;try{r=V(n)}catch(e){return t.stderr(`otto extension dev 失败: ${e.message}\n`),Promise.resolve(1)}t.stdout(`▶ otto extension dev:${r}\n 监视 ${n}\n`);let i=B(e,`--link`);if(i)try{let e=H(n,r,w(i));t.stdout(` 已链接 → ${e}\n`)}catch(e){t.stderr(` 链接失败:${e.message}\n`)}let a=E(C(n,`panels`));a&&(t.stdout(` 编译面板…
110
+ `),R(n,t));let o=E(C(n,`plugin.ts`))||E(C(n,`plugin.tsx`));return o&&(t.stdout(` 编译 plugin.ts…
111
+ `),await z(n,t)),t.stdout(` 改动后在 otto 内 /extension reload 生效。Ctrl+C 退出。
112
+ `),new Promise(e=>{let r;try{r=se(n,{recursive:!0},(e,r)=>{if(!r)return;let i=String(r);i.includes(`panels-dist`)||i.includes(`plugin-dist`)||i.startsWith(`.`)||(t.stdout(W(i,_e(new Date))),a&&i.endsWith(`.tsx`)&&i!==`plugin.tsx`&&R(n,t),o&&(i===`plugin.ts`||i===`plugin.tsx`)&&z(n,t))})}catch(n){t.stderr(` 监视启动失败(平台可能不支持递归监视):${n.message}\n`),e(1);return}let i=()=>{r?.close(),process.off(`SIGINT`,i),t.stdout(`
113
113
  停止 dev。
114
- `),e(0)};process.on(`SIGINT`,i)})}const G={"plugin-browser-use":{pkg:`@x-otto/plugin-browser-use-mcp`,capabilities:[`tui.renderer`,`panel.backend`]},"plugin-mobile-use":{pkg:`@x-otto/plugin-mobile-use-mcp`,capabilities:[`tui.renderer`,`panel.backend`]},"plugin-feishu-use":{pkg:`@x-otto/plugin-feishu-use`,capabilities:[]},"plugin-miniprogram-use":{pkg:`@x-otto/plugin-miniprogram-use-mcp`,capabilities:[`tui.renderer`,`panel.backend`]},"plugin-schedule":{pkg:`@x-otto/plugin-schedule-panel`,capabilities:[`tui.renderer`]},"anthropic-provider":{pkg:`@x-otto/plugin-anthropic`,capabilities:[`provider`]},"deepseek-provider":{pkg:`@x-otto/plugin-deepseek`,capabilities:[`provider`]},"oxygen-provider":{pkg:`@x-otto/plugin-oxygen`,capabilities:[`provider`]},"openai-codex-provider":{pkg:`@x-otto/plugin-openai-codex`,capabilities:[`provider`]},"github-copilot-provider":{pkg:`@x-otto/plugin-github-copilot`,capabilities:[`provider`]},"cursor-provider":{pkg:`@x-otto/plugin-cursor`,capabilities:[`provider`]},"wire-protocols":{pkg:`@x-otto/plugin-otto-wire-protocols`,capabilities:[`wire-protocol`]}},K={provider:`provider —— 注册 LLM provider,将处理你的凭据与请求流量`,tools:`tools —— 注册可被 agent 调用的工具`,"tui.renderer":`tui.renderer —— 在 TUI 进程内运行自定义渲染代码`,network:`network —— 发起任意网络请求`,"wire-protocol":`wire-protocol —— 注册 wire 协议实现,可截获全部模型请求与响应流量(含凭据)`,"a2ui.component":`a2ui.component —— 在 TUI 进程内运行自定义渲染组件代码`,"panel.backend":`panel.backend —— 面板可驱动有副作用的后端业务操作`,"input.resolver":`input.resolver —— 在提交时展开 @ 引用,把内容注入 prompt`,"a2ui.renderer":`a2ui.renderer —— 运行自定义代码,跨 TUI 与 web-ui 渲染消息`};async function q(e,t,n,r){if(n.length===0)return!0;if(!r&&process.stdout.isTTY&&process.stdin.isTTY)return _e(t,n);let i=[`插件 '${t}' 申请以下高危能力:`,...n.map(e=>` • ${K[e]??e}`)];if(e.stdout(`${i.join(`
114
+ `),e(0)};process.on(`SIGINT`,i)})}const G={"plugin-browser-use":{pkg:`@x-otto/plugin-browser-use-mcp`,capabilities:[`tui.renderer`,`panel.backend`]},"plugin-mobile-use":{pkg:`@x-otto/plugin-mobile-use-mcp`,capabilities:[`tui.renderer`,`panel.backend`]},"plugin-feishu-use":{pkg:`@x-otto/plugin-feishu-use`,capabilities:[]},"plugin-miniprogram-use":{pkg:`@x-otto/plugin-miniprogram-use-mcp`,capabilities:[`tui.renderer`,`panel.backend`]},"plugin-schedule":{pkg:`@x-otto/plugin-schedule-panel`,capabilities:[`tui.renderer`]},"anthropic-provider":{pkg:`@x-otto/plugin-anthropic`,capabilities:[`provider`]},"deepseek-provider":{pkg:`@x-otto/plugin-deepseek`,capabilities:[`provider`]},"oxygen-provider":{pkg:`@x-otto/plugin-oxygen`,capabilities:[`provider`]},"openai-codex-provider":{pkg:`@x-otto/plugin-openai-codex`,capabilities:[`provider`]},"github-copilot-provider":{pkg:`@x-otto/plugin-github-copilot`,capabilities:[`provider`]},"cursor-provider":{pkg:`@x-otto/plugin-cursor`,capabilities:[`provider`]},"wire-protocols":{pkg:`@x-otto/plugin-otto-wire-protocols`,capabilities:[`wire-protocol`]}},K={provider:`provider —— 注册 LLM provider,将处理你的凭据与请求流量`,tools:`tools —— 注册可被 agent 调用的工具`,"tui.renderer":`tui.renderer —— 在 TUI 进程内运行自定义渲染代码`,network:`network —— 发起任意网络请求`,"wire-protocol":`wire-protocol —— 注册 wire 协议实现,可截获全部模型请求与响应流量(含凭据)`,"a2ui.component":`a2ui.component —— 在 TUI 进程内运行自定义渲染组件代码`,"panel.backend":`panel.backend —— 面板可驱动有副作用的后端业务操作`,"input.resolver":`input.resolver —— 在提交时展开 @ 引用,把内容注入 prompt`,"a2ui.renderer":`a2ui.renderer —— 运行自定义代码,跨 TUI 与 web-ui 渲染消息`};async function q(e,t,n,r){if(n.length===0)return!0;if(!r&&process.stdout.isTTY&&process.stdin.isTTY)return ye(t,n);let i=[`插件 '${t}' 申请以下高危能力:`,...n.map(e=>` • ${K[e]??e}`)];if(e.stdout(`${i.join(`
115
115
  `)}\n`),r)return e.stdout(`(--yes 已跳过交互确认,继续安装)
116
- `),!0;let a=se({input:process.stdin,output:process.stdout});try{let e=(await a.question(`继续安装并授予以上能力?[y/N] `)).trim().toLowerCase();return e===`y`||e===`yes`}finally{a.close()}}function _e(e,t){let n={current:null},r=[`插件 '${e}' 申请以下高危能力:`,...t.map(e=>` • ${K[e]??e}`),``,`继续安装即视为同意授予以上能力(等价于 /trust plugin 的确认动作)。`];return ue({routes:ce.createElement(le,{title:`高危能力确认`,message:r,confirmLabel:`继续安装`,cancelLabel:`取消`,confirmColor:`amber`,onConfirm:()=>n.current?.(!0),onCancel:()=>n.current?.(!1)})},e=>{n.current=e.resolve})}function J(e,t){t.length!==0&&(y(e.dir),f(e.dir,t))}async function Y(e){let t=new k({projectConfigPath:C(x,b)});await t.load(),await _(t,e)}async function ve(e){try{let{registries:t}=await new i({configDir:S,ottoHome:x,officialSource:a(process.env.OTTO_OFFICIAL_REGISTRY_URL??`https://x-ottojs.github.io/otto-registry/registry.json`)}).loadAll();for(let n of t){let t=n.entries.find(t=>t.id===e);if(t&&t.type===`plugin`&&!t.subPath)return t.source}return null}catch{return null}}async function ye(e,n){let i=B(e,`--link`),a=i?void 0:e.find(e=>!e.startsWith(`-`)),o=e.includes(`--project`),s=e.includes(`--repo`),c=e.includes(`--yes`)||e.includes(`-y`);if(i){if(o||s)return n.stderr("--link 仅支持用户级安装(`~/.otto/plugins/`),不接受 --project/--repo。\n"),1;let e=w(i),t=g(e);if(!await q(n,t.length>0?V(e):``,t,c))return n.stdout(`已取消安装。
117
- `),1;try{let r=await p(e);J(r,t),await Y({id:r.id,source:`dir`,sourceSpec:e,version:r.version,scope:`global`,capabilities:t}),n.stdout(`${r.created?`已安装`:`已是最新`}插件 '${r.id}' → ${r.dir}\n 来源: 本地 (${e})(软链)\n 用户级插件默认受信任。otto 内 /extension reload 生效。\n`+(t.length>0?` 已授予高危能力:${t.join(`, `)}(等价于 /trust plugin ${r.id} 的确认动作,\n 可随时用 /extension → ${r.id} → 撤销信任 关闭)。\n`:``));for(let e of r.compileWarnings)n.stderr(` ✗ ${e}\n`);return 0}catch(e){return n.stderr(`插件安装失败:${e.message}\n`),1}}if(!a)return n.stderr(`otto extension install <name|package> [--project] [--repo] 或 --link <dir>
118
- `),1;let u=G[a]?.pkg??await ve(a)??a;try{let e=o?C(process.cwd(),`.otto`):s?(()=>{let e=d(process.cwd());return e?C(e,`.otto`):(n.stderr(`--repo 要求当前目录在 pnpm workspace 内(向上未找到 pnpm-workspace.yaml)。
119
- `),``)})():C(t(),`.otto`);if(s&&!e)return 1;let i=[];if(!o&&!s){let e=v(u,process.cwd());e&&(i=g(e))}if(!await q(n,a,i,c))return n.stdout(`已取消安装。
120
- `),1;let p=!o&&!s?v(u,process.cwd()):void 0;if(!o&&!s&&!p){let e=new r;try{let t=await e.install(u,{global:!0,as:`plugin`,postInstallExecutor:l});if(!t.success)return n.stderr(`插件安装失败:${t.error??`未知错误`}\n`),1;let r=t.targetPath?g(t.targetPath):[];if(r.length>0&&t.targetPath)try{y(t.targetPath),f(t.targetPath,r)}catch{}return await Y({id:t.name??u,source:`npm`,sourceSpec:u,version:t.manifest?.version,scope:`global`,capabilities:r}),n.stdout(`已安装插件 '${t.name??u}' → ${t.targetPath}\n 来源: npm registry(${u})\n`+(r.length>0?` 已授予高危能力:${r.join(`, `)}(等价于 /trust plugin ${t.name} 的确认动作)。\n`:``)+` 用户级插件默认受信任。otto 内 /extension reload 生效。
121
- `),0}catch(e){return n.stderr(`插件安装失败:${e.message}\n`),1}}let h=await m({pkg:u,ottoDir:e,cwd:process.cwd()});!o&&!s&&J(h,i),await Y({id:h.id,source:`npm`,sourceSpec:u,version:h.version,scope:o?`project`:s?`repository`:`global`,capabilities:i}),n.stdout(`${h.created?`已安装`:`已是最新`}插件 '${h.id}' → ${h.dir}\n 来源包: ${u}(软链 → ${h.packageDir})\n`+(i.length>0?` 已授予高危能力:${i.join(`, `)}(等价于 /trust plugin ${h.id} 的确认动作,\n 可随时用 /extension → ${h.id} → 撤销信任 关闭)。\n`:``)+(o?` 项目级插件需先信任方激活:在 otto 内运行 /trust plugin ${h.id}(或 /extension)信任该插件。\n`:s?` 仓库级插件需先信任方激活:在 otto 内运行 /extension trust plugin ${h.id}(或打开 /extension 面板)信任该插件。\n`:a===`plugin-feishu-use`?` 用户级插件默认受信任(feishu-use 不提供 MCP 工具,是独立长连接进程,见下)。
122
- `:` 用户级插件默认受信任,工具 mcp__${h.id}__* 即刻可用(otto 内 /extension reload 生效)。\n`)+(a===`plugin-browser-use`?` 默认 auto:有 relay 用真 Chrome,否则本地 headless(自动探测浏览器,零配置)。
116
+ `),!0;let a=le({input:process.stdin,output:process.stdout});try{let e=(await a.question(`继续安装并授予以上能力?[y/N] `)).trim().toLowerCase();return e===`y`||e===`yes`}finally{a.close()}}function ye(e,t){let n={current:null},r=[`插件 '${e}' 申请以下高危能力:`,...t.map(e=>` • ${K[e]??e}`),``,`继续安装即视为同意授予以上能力(等价于 /trust plugin 的确认动作)。`];return fe({routes:ue.createElement(de,{title:`高危能力确认`,message:r,confirmLabel:`继续安装`,cancelLabel:`取消`,confirmColor:`amber`,onConfirm:()=>n.current?.(!0),onCancel:()=>n.current?.(!1)})},e=>{n.current=e.resolve})}function J(e,t){t.length!==0&&(b(e.dir),f(e.dir,t))}async function Y(e){let t=new k({projectConfigPath:C(S,x)});await t.load(),await ee(t,e)}async function be(e){try{let{registries:t}=await new i({configDir:re,ottoHome:S,officialSource:a(process.env.OTTO_OFFICIAL_REGISTRY_URL??`https://x-ottojs.github.io/otto-registry/registry.json`)}).loadAll();for(let n of t){let t=n.entries.find(t=>t.id===e);if(t&&t.type===`plugin`&&!t.subPath)return t.source}return null}catch{return null}}async function xe(e,n){let i=B(e,`--link`),a=i?void 0:e.find(e=>!e.startsWith(`-`)),o=e.includes(`--project`),s=e.includes(`--repo`),c=e.includes(`--yes`)||e.includes(`-y`);if(i){if(o||s)return n.stderr("--link 仅支持用户级安装(`~/.otto/plugins/`),不接受 --project/--repo。\n"),1;let e=w(i),t=v(e);if(!await q(n,t.length>0?V(e):``,t,c))return n.stdout(`已取消安装。
117
+ `),1;try{let r=await h(e);J(r,t),await Y({id:r.id,source:`dir`,sourceSpec:e,version:r.version,scope:`global`,capabilities:t}),n.stdout(`${r.created?`已安装`:`已是最新`}插件 '${r.id}' → ${r.dir}\n 来源: 本地 (${e})(软链)\n 用户级插件默认受信任。otto 内 /extension reload 生效。\n`+(t.length>0?` 已授予高危能力:${t.join(`, `)}(等价于 /trust plugin ${r.id} 的确认动作,\n 可随时用 /extension → ${r.id} → 撤销信任 关闭)。\n`:``));for(let e of r.compileWarnings)n.stderr(` ✗ ${e}\n`);return 0}catch(e){return n.stderr(`插件安装失败:${e.message}\n`),1}}if(!a)return n.stderr(`otto extension install <name|package> [--project] [--repo] 或 --link <dir>
118
+ `),1;let u=G[a]?.pkg??await be(a)??a;try{let e=o?C(process.cwd(),`.otto`):s?(()=>{let e=d(process.cwd());return e?C(e,`.otto`):(n.stderr(`--repo 要求当前目录在 pnpm workspace 内(向上未找到 pnpm-workspace.yaml)。
119
+ `),``)})():C(t(),`.otto`);if(s&&!e)return 1;let i=[];if(!o&&!s){let e=y(u,process.cwd());e&&(i=v(e))}if(!await q(n,a,i,c))return n.stdout(`已取消安装。
120
+ `),1;let p=!o&&!s?y(u,process.cwd()):void 0;if(!o&&!s&&!p){let e=new r;try{let t=await e.install(u,{global:!0,as:`plugin`,postInstallExecutor:l});if(!t.success)return n.stderr(`插件安装失败:${t.error??`未知错误`}\n`),1;let r=t.targetPath?v(t.targetPath):[];if(r.length>0&&t.targetPath)try{b(t.targetPath),f(t.targetPath,r)}catch{}return await Y({id:t.name??u,source:`npm`,sourceSpec:u,version:t.manifest?.version,scope:`global`,capabilities:r}),n.stdout(`已安装插件 '${t.name??u}' → ${t.targetPath}\n 来源: npm registry(${u})\n`+(r.length>0?` 已授予高危能力:${r.join(`, `)}(等价于 /trust plugin ${t.name} 的确认动作)。\n`:``)+` 用户级插件默认受信任。otto 内 /extension reload 生效。
121
+ `),0}catch(e){return n.stderr(`插件安装失败:${e.message}\n`),1}}let m=await g({pkg:u,ottoDir:e,cwd:process.cwd()});!o&&!s&&J(m,i),await Y({id:m.id,source:`npm`,sourceSpec:u,version:m.version,scope:o?`project`:s?`repository`:`global`,capabilities:i}),n.stdout(`${m.created?`已安装`:`已是最新`}插件 '${m.id}' → ${m.dir}\n 来源包: ${u}(软链 → ${m.packageDir})\n`+(i.length>0?` 已授予高危能力:${i.join(`, `)}(等价于 /trust plugin ${m.id} 的确认动作,\n 可随时用 /extension → ${m.id} → 撤销信任 关闭)。\n`:``)+(o?` 项目级插件需先信任方激活:在 otto 内运行 /trust plugin ${m.id}(或 /extension)信任该插件。\n`:s?` 仓库级插件需先信任方激活:在 otto 内运行 /extension trust plugin ${m.id}(或打开 /extension 面板)信任该插件。\n`:a===`plugin-feishu-use`?` 用户级插件默认受信任(feishu-use 不提供 MCP 工具,是独立长连接进程,见下)。
122
+ `:` 用户级插件默认受信任,工具 mcp__${m.id}__* 即刻可用(otto 内 /extension reload 生效)。\n`)+(a===`plugin-browser-use`?` 默认 auto:有 relay 用真 Chrome,否则本地 headless(自动探测浏览器,零配置)。
123
123
  relay native host 首次 /extension reload 由插件 setup 钩子自动注入(前提 cargo build --release -p otto-relay);
124
124
  之后 chrome://extensions 加载 packages/extension/dist 即可接管真实 Chrome。
125
125
  `:``)+(a===`plugin-mobile-use`?` 默认 Android:零配置自动探测首个已连接设备/模拟器(\`adb devices\` 可见即用)。
@@ -130,8 +130,8 @@ bin/
130
130
  真机连接默认拒绝(安全 fail-closed):需显式设 {"real_device_confirmation":"allow"}
131
131
  才允许连接真实 Android/iOS 设备(模拟器/Simulator 不受此限制,零配置可用)。
132
132
  `:``)+(a===`plugin-feishu-use`?` feishu-use 是一个 7×24 独立长连接进程,不由 otto 插件系统管理其常驻生命周期:
133
- 1) otto feishu config init # 交互式配置向导(${o?`写入 ${h.dir}/../../feishu-use.json`:s?`写入 <workspaceRoot>/.otto/feishu-use.json`:`默认写入项目级 <.otto>/feishu-use.json;--global 写 ~/.otto/`})\n 2) otto feishu config get # 核对配置(appSecret 自动脱敏)
134
- 3) node ${h.dir}/bin/bridge-cli.mjs # 前台启动(或用 launchd/systemd/pm2 常驻)\n 也可用 \`otto feishu config set <key> <value>\` 随时修改单个字段。
133
+ 1) otto feishu config init # 交互式配置向导(${o?`写入 ${m.dir}/../../feishu-use.json`:s?`写入 <workspaceRoot>/.otto/feishu-use.json`:`默认写入项目级 <.otto>/feishu-use.json;--global 写 ~/.otto/`})\n 2) otto feishu config get # 核对配置(appSecret 自动脱敏)
134
+ 3) node ${m.dir}/bin/bridge-cli.mjs # 前台启动(或用 launchd/systemd/pm2 常驻)\n 也可用 \`otto feishu config set <key> <value>\` 随时修改单个字段。
135
135
  配置按作用域自动选择(project > repo > user,first-found wins)。
136
136
  详见 extensions/plugin-feishu-use/README.md(含"用来迭代 otto 框架"专项章节)。
137
137
  `:``)+(a===`plugin-miniprogram-use`?` miniprogram-use 需要两步配置:
@@ -142,16 +142,17 @@ bin/
142
142
  可选:在 ~/.otto/miniprogram-use.json 配置 admin_endpoints(需真实抓包获得)后,
143
143
  才会注册后台管理只读工具(get_members/get_permission_status/
144
144
  get_experience_qrcode)。详见 docs/rfc/RFC-121-miniprogram-use.md。
145
- `:``));for(let e of h.compileWarnings)n.stderr(` ✗ ${e}\n`);return 0}catch(e){return n.stderr(`插件安装失败:${e.message}\n`),1}}async function be(e,n){let i=e.find(e=>!e.startsWith(`-`)),a=ee({workspaceDir:process.cwd(),workspaceRoot:d(process.cwd()),scope:`all`}),s=i?a.filter(e=>e.name===i):a;if(s.length===0)return n.stdout(i?`未找到已安装且带版本号的扩展 "${i}"。\n`:`未发现带版本号的已安装扩展(skill/plugin)。
145
+ `:``));for(let e of m.compileWarnings)n.stderr(` ✗ ${e}\n`);return 0}catch(e){return n.stderr(`插件安装失败:${e.message}\n`),1}}async function Se(e,n){let i=e.find(e=>!e.startsWith(`-`)),a=te({workspaceDir:process.cwd(),workspaceRoot:d(process.cwd()),scope:`all`}),s=i?a.filter(e=>e.name===i):a;if(s.length===0)return n.stdout(i?`未找到已安装且带版本号的扩展 "${i}"。\n`:`未发现带版本号的已安装扩展(skill/plugin)。
146
146
  `),i?1:0;let c=await o(s),u=c.filter(e=>e.newer);if(u.length===0){n.stdout(`全部扩展已是最新版本。
147
- `);for(let e of c)e.error&&n.stdout(` [${e.type}] ${e.name} v${e.installed} — ${e.error}\n`);return 0}n.stdout(`发现 ${u.length} 个可更新扩展,开始重装:\n`);let f=new r,p=0,m=0;for(let e of u){let r=s.find(t=>t.name===e.name&&t.type===e.type),i=r?xe(r):void 0;if(!i){n.stderr(` ✗ ${e.name}:无法确定重装来源(.otto-install.json 缺失或来源类型不支持自动重装)\n`),m++;continue}let a=r.path.startsWith(C(t(),`.otto`)+ne);try{let t=await f.install(i,{workspaceDir:process.cwd(),global:a,force:!0,as:e.type,postInstallExecutor:l});if(t.success)n.stdout(` ✓ ${e.name} v${e.installed} → v${e.latest??`?`}\n`),p++;else{let r=t.failureKind===`conflict`?`(已存在且未覆盖)`:``;n.stderr(` ✗ ${e.name}:${t.error??`重装失败`}${r}\n`),m++}}catch(t){n.stderr(` ✗ ${e.name}:${t.message}\n`),m++}}return n.stdout(`\n完成:${p} 个已更新${m>0?`,${m} 个失败`:``}。\n`),m>0?1:0}function xe(e){let t=C(e.path,`.otto-install.json`);if(T(t))try{let e=JSON.parse(O(t,`utf-8`));return e.sourceType===`npm`&&e.sourceUrl?.startsWith(`npm:`)?e.sourceUrl.slice(4):e.sourceType===`git`&&e.sourceUrl?e.sourceUrl:void 0}catch{return}}function X(){return new k({projectConfigPath:C(x,b)})}function Z(n){return e({cwd:process.cwd(),homedir:n??t()}).map(e=>({id:e.id,name:e.manifest.name??e.id,scope:e.scope}))}async function Q(e,t){let n=e.find(e=>!e.startsWith(`-`));if(!n)return t.stderr(`otto extension enable <id>
148
- `),1;let r=X();await r.load();let i=new Set(r.get(`disabled_plugins`)??[]);return i.has(n)?(i.delete(n),await r.persist({disabled_plugins:[...i]}),t.stdout(`已启用插件 '${n}'。运行中的 otto 会话内执行 /extension reload 或重启生效。\n`),0):(t.stdout(`插件 '${n}' 当前已是启用状态。\n`),0)}async function Se(e,t){let n=e.find(e=>!e.startsWith(`-`));if(!n)return t.stderr(`otto extension disable <id>
149
- `),1;if(Z().find(e=>e.id===n)?.scope===`builtin`)return t.stderr(`插件 "${n}" 是 otto 内置插件,恒定信任+启用,无法禁用。\n`),1;let r=X();await r.load();let i=new Set(r.get(`disabled_plugins`)??[]);return i.has(n)?(t.stdout(`插件 '${n}' 当前已是禁用状态。\n`),0):(i.add(n),await r.persist({disabled_plugins:[...i]}),t.stdout(`已禁用插件 '${n}'。运行中的 otto 会话内执行 /extension reload 或重启生效(CLI 路径不杀运行中进程,reload 时统一清理)。\n`),0)}async function Ce(e,t){let n=X();await n.load();let r=new Set(n.get(`disabled_plugins`)??[]),i=Z();if(i.length===0)return t.stdout(`(未发现任何插件)
150
- `),0;for(let e of i){let n=e.scope===`builtin`||!r.has(e.id)?`enabled `:`disabled`,i=e.scope===`builtin`?` (builtin, readonly)`:` (${e.scope})`;t.stdout(` ${n} ${e.id}${i} ${e.name}\n`)}return 0}async function we(e,t){let n=e.find(e=>!e.startsWith(`-`)),r=e.includes(`--yes`)||e.includes(`-y`);if(!n)return t.stderr(`otto extension purge <id> [--yes]
151
- `),1;let i=C(x,`plugin-state`,n);if(!T(i))return t.stdout(`插件 '${n}' 无持久化状态(${i} 不存在)。\n`),0;if(!r){if(!process.stdout.isTTY)return t.stderr(`插件 '${n}' 有持久化状态,删除不可逆——非交互终端请显式传 --yes。\n`),1;let{createInterface:e}=await import(`node:readline/promises`),r=e({input:process.stdin,output:process.stdout});try{let e=(await r.question(`确认删除插件 '${n}' 的全部持久化状态?此操作不可逆 [y/N] `)).trim().toLowerCase();if(e!==`y`&&e!==`yes`)return t.stdout(`已取消。
152
- `),0}finally{r.close()}}let a=h(n);return t.stdout(a.removed?`已清除插件 '${n}' 的持久化状态。\n`:`清除插件 '${n}' 状态失败(目录可能仍存在)。\n`),a.removed?0:1}function $(n){return e({cwd:process.cwd(),homedir:t()}).find(e=>e.id===n)}async function Te(e,t){let r=e.find(e=>!e.startsWith(`-`));if(!r)return t.stderr(`otto extension trust: 需要插件 id(用法:otto extension trust <id> [--grant <caps>])
153
- `),1;let i=$(r);if(!i)return t.stderr(`otto extension trust: 未找到插件 "${r}"(先 otto extension list 查看已安装插件)\n`),1;let a=(i.manifest?.capabilities??[]).filter(e=>n.includes(e)),o=e.find(e=>e.startsWith(`--grant=`)),s=e.indexOf(`--grant`),c=o?o.slice(8):s>=0?e[s+1]:void 0,l=e.includes(`--grant-declared`),d=[];if(l)d=[...a];else if(c){d=c.split(`,`).map(e=>e.trim()).filter(Boolean);let e=d.filter(e=>!n.includes(e));if(e.length>0)return t.stderr(`otto extension trust: 未知能力 ${e.join(`, `)}\n 可用高危能力:${n.join(`, `)}\n`),1;let i=d.filter(e=>!a.includes(e));if(i.length>0)return t.stderr(`otto extension trust: 插件 "${r}" 未声明能力 ${i.join(`, `)}——授予无效。\n 该插件声明的高危能力:${a.length?a.join(`, `):`(无)`}\n`),1}y(i.dir),d.length>0&&f(i.dir,d);let p=u(i);return t.stdout(`✓ 已信任 ${r}(${i.scope})\n`),d.length>0&&t.stdout(` 已授予能力:${d.join(`, `)}\n`),p.pendingCapabilities.length>0&&t.stdout(` ⚠ 仍待授权:${p.pendingCapabilities.join(`, `)}\n 这些能力未授予前对应贡献点不会注册(fail-closed)。\n 授予:otto extension trust ${r} --grant ${p.pendingCapabilities.join(`,`)}\n`),0}async function Ee(e,t){let n=e.find(e=>!e.startsWith(`-`));if(!n)return t.stderr(`otto extension untrust: 需要插件 id
154
- `),1;let r=$(n);return r?(te(r.dir),t.stdout(`✓ 已撤销信任 ${n}\n`),0):(t.stderr(`otto extension untrust: 未找到插件 "${n}"\n`),1)}function De(e,t){let[n,...r]=e;switch(n){case`create`:return I(r,t);case`build`:return z(r,t);case`dev`:return ge(r,t);case`install`:return ye(r,t);case`update`:return be(r,t);case`enable`:return Q(r,t);case`disable`:return Se(r,t);case`list`:return Ce(r,t);case`purge`:return we(r,t);case`trust`:return Te(r,t);case`untrust`:return Ee(r,t);default:return t.stdout(`otto extension <命令>
147
+ `);for(let e of c)e.error&&n.stdout(` [${e.type}] ${e.name} v${e.installed} — ${e.error}\n`);return 0}n.stdout(`发现 ${u.length} 个可更新扩展,开始重装:\n`);let f=new r,p=0,m=0;for(let e of u){let r=s.find(t=>t.name===e.name&&t.type===e.type),i=r?Ce(r):void 0;if(!i){n.stderr(` ✗ ${e.name}:无法确定重装来源(.otto-install.json 缺失或来源类型不支持自动重装)\n`),m++;continue}let a=r.path.startsWith(C(t(),`.otto`)+T);try{let t=await f.install(i,{workspaceDir:process.cwd(),global:a,force:!0,as:e.type,postInstallExecutor:l});if(t.success)n.stdout(` ✓ ${e.name} v${e.installed} → v${e.latest??`?`}\n`),p++;else{let r=t.failureKind===`conflict`?`(已存在且未覆盖)`:``;n.stderr(` ✗ ${e.name}:${t.error??`重装失败`}${r}\n`),m++}}catch(t){n.stderr(` ✗ ${e.name}:${t.message}\n`),m++}}return n.stdout(`\n完成:${p} 个已更新${m>0?`,${m} 个失败`:``}。\n`),m>0?1:0}function Ce(e){let t=C(e.path,`.otto-install.json`);if(E(t))try{let e=JSON.parse(O(t,`utf-8`));return e.sourceType===`npm`&&e.sourceUrl?.startsWith(`npm:`)?e.sourceUrl.slice(4):e.sourceType===`git`&&e.sourceUrl?e.sourceUrl:void 0}catch{return}}function X(){return new k({projectConfigPath:C(S,x)})}function Z(n){return e({cwd:process.cwd(),homedir:n??t()}).map(e=>({id:e.id,name:e.manifest.name??e.id,scope:e.scope}))}async function we(e,t){let n=e.find(e=>!e.startsWith(`-`));if(!n)return t.stderr(`otto extension enable <id>
148
+ `),1;let r=X();await r.load();let i=new Set(r.get(`disabled_plugins`)??[]);return i.has(n)?(i.delete(n),await r.persist({disabled_plugins:[...i]}),t.stdout(`已启用插件 '${n}'。运行中的 otto 会话内执行 /extension reload 或重启生效。\n`),0):(t.stdout(`插件 '${n}' 当前已是启用状态。\n`),0)}async function Q(e,t){let n=e.find(e=>!e.startsWith(`-`));if(!n)return t.stderr(`otto extension disable <id>
149
+ `),1;if(Z().find(e=>e.id===n)?.scope===`builtin`)return t.stderr(`插件 "${n}" 是 otto 内置插件,恒定信任+启用,无法禁用。\n`),1;let r=X();await r.load();let i=new Set(r.get(`disabled_plugins`)??[]);return i.has(n)?(t.stdout(`插件 '${n}' 当前已是禁用状态。\n`),0):(i.add(n),await r.persist({disabled_plugins:[...i]}),t.stdout(`已禁用插件 '${n}'。运行中的 otto 会话内执行 /extension reload 或重启生效(CLI 路径不杀运行中进程,reload 时统一清理)。\n`),0)}async function Te(e,t){let n=X();await n.load();let r=new Set(n.get(`disabled_plugins`)??[]),i=Z();if(i.length===0)return t.stdout(`(未发现任何插件)
150
+ `),0;for(let e of i){let n=e.scope===`builtin`||!r.has(e.id)?`enabled `:`disabled`,i=e.scope===`builtin`?` (builtin, readonly)`:` (${e.scope})`;t.stdout(` ${n} ${e.id}${i} ${e.name}\n`)}return 0}async function Ee(e,t){let n=e.find(e=>!e.startsWith(`-`)),r=e.includes(`--yes`)||e.includes(`-y`);if(!n)return t.stderr(`otto extension purge <id> [--yes]
151
+ `),1;let i=C(S,`plugin-state`,n);if(!E(i))return t.stdout(`插件 '${n}' 无持久化状态(${i} 不存在)。\n`),0;if(!r){if(!process.stdout.isTTY)return t.stderr(`插件 '${n}' 有持久化状态,删除不可逆——非交互终端请显式传 --yes。\n`),1;let{createInterface:e}=await import(`node:readline/promises`),r=e({input:process.stdin,output:process.stdout});try{let e=(await r.question(`确认删除插件 '${n}' 的全部持久化状态?此操作不可逆 [y/N] `)).trim().toLowerCase();if(e!==`y`&&e!==`yes`)return t.stdout(`已取消。
152
+ `),0}finally{r.close()}}let a=_(n);return t.stdout(a.removed?`已清除插件 '${n}' 的持久化状态。\n`:`清除插件 '${n}' 状态失败(目录可能仍存在)。\n`),a.removed?0:1}function $(n){return e({cwd:process.cwd(),homedir:t()}).find(e=>e.id===n)}async function De(e,t){let r=e.find(e=>!e.startsWith(`-`));if(!r)return t.stderr(`otto extension trust: 需要插件 id(用法:otto extension trust <id> [--grant <caps>])
153
+ `),1;let i=$(r);if(!i)return t.stderr(`otto extension trust: 未找到插件 "${r}"(先 otto extension list 查看已安装插件)\n`),1;let a=(i.manifest?.capabilities??[]).filter(e=>n.includes(e)),o=e.find(e=>e.startsWith(`--grant=`)),s=e.indexOf(`--grant`),c=o?o.slice(8):s>=0?e[s+1]:void 0,l=e.includes(`--grant-declared`),d=[];if(l)d=[...a];else if(c){d=c.split(`,`).map(e=>e.trim()).filter(Boolean);let e=d.filter(e=>!n.includes(e));if(e.length>0)return t.stderr(`otto extension trust: 未知能力 ${e.join(`, `)}\n 可用高危能力:${n.join(`, `)}\n`),1;let i=d.filter(e=>!a.includes(e));if(i.length>0)return t.stderr(`otto extension trust: 插件 "${r}" 未声明能力 ${i.join(`, `)}——授予无效。\n 该插件声明的高危能力:${a.length?a.join(`, `):`(无)`}\n`),1}b(i.dir);let h=i.manifest.version;d.length>0&&(h?p(i.dir,d,h):(t.stderr(`otto extension trust: 插件 "${i.id}" manifest 无版本字段——授权不绑定版本,后续插件更新后需重新信任(R6' 版本感知无法生效)。
154
+ `),f(i.dir,d)));let g=u(i);return t.stdout(`✓ 已信任 ${r}(${i.scope})\n`),d.length>0&&(t.stdout(` 已授予能力:${d.join(`, `)}\n`),h&&(m(i.dir,h).length===0?t.stderr(` 版本感知授权未生效(读回为空)——插件 "${i.id}" 的高危能力在版本不匹配时将被 fail-closed 拒绝,请确认 manifest 版本与授权版本一致。\n`):t.stdout(` ✓ 版本感知已生效(授权绑定 manifest v${h},更新后需重新信任)\n`))),g.pendingCapabilities.length>0&&t.stdout(` 仍待授权:${g.pendingCapabilities.join(`, `)}\n 这些能力未授予前对应贡献点不会注册(fail-closed)。\n 授予:otto extension trust ${r} --grant ${g.pendingCapabilities.join(`,`)}\n`),0}async function Oe(e,t){let n=e.find(e=>!e.startsWith(`-`));if(!n)return t.stderr(`otto extension untrust: 需要插件 id
155
+ `),1;let r=$(n);return r?(ne(r.dir),t.stdout(`✓ 已撤销信任 ${n}\n`),0):(t.stderr(`otto extension untrust: 未找到插件 "${n}"\n`),1)}function ke(e,t){let[n,...r]=e;switch(n){case`create`:return L(r,t);case`build`:return ge(r,t);case`dev`:return ve(r,t);case`install`:return xe(r,t);case`update`:return Se(r,t);case`enable`:return we(r,t);case`disable`:return Q(r,t);case`list`:return Te(r,t);case`purge`:return Ee(r,t);case`trust`:return De(r,t);case`untrust`:return Oe(r,t);default:return t.stdout(`otto extension <命令>
155
156
  create <name> 生成插件骨架(命令 + 面板 + manifest)
156
157
  install <name|pkg> [--project] [--repo] [--yes] 从 npm 安装插件(别名 browser-use/mobile-use/
157
158
  feishu-use/miniprogram-use/anthropic-provider/
@@ -174,5 +175,5 @@ bin/
174
175
  /trust plugin 同一份落盘。未授予的能力对应贡献点
175
176
  不会注册(fail-closed)
176
177
  untrust <id> 撤销信任
177
- `),n?1:0}}export{H as a,W as i,G as n,V as o,R as r,F as s,De as t};
178
- //# sourceMappingURL=extension-1-lxuerZ.js.map
178
+ `),n?1:0}}export{H as a,W as i,G as n,V as o,z as r,I as s,ke as t};
179
+ //# sourceMappingURL=extension-DVEml5IN.js.map