@x-otto/install 0.0.1-alpha.6 → 0.0.1-alpha.7

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.
package/README.md CHANGED
@@ -13,39 +13,45 @@ pnpm add @x-otto/install
13
13
  ## Usage
14
14
 
15
15
  ```typescript
16
- import { InstallManager } from '@x-otto/install'
17
-
18
- const manager = new InstallManager()
16
+ import { install } from '@x-otto/install'
19
17
 
20
18
  // Install a skill from a local .tgz archive
21
- const result = await manager.install('./my-skill.tgz', {
19
+ const result = await install('./my-skill.tgz', {
22
20
  workspaceDir: '/path/to/project',
23
21
  onProgress: (p) => console.log(`[${p.phase}] ${p.message}`),
24
22
  })
25
23
 
26
24
  // Install a plugin from npm
27
- const pluginResult = await manager.install('@scope/my-plugin', {
25
+ const pluginResult = await install('@scope/my-plugin', {
28
26
  global: true,
29
27
  })
30
28
 
31
- // Install an MCP server from a git repo tag
32
- const mcpResult = await manager.install('https://github.com/user/mcp-server.git', {
33
- ref: 'v1.2.0',
34
- env: { API_KEY: 'xxx' },
35
- })
29
+ // Install an MCP server from a git repo tag (MCP needs settings accessors)
30
+ const mcpResult = await install(
31
+ 'https://github.com/user/mcp-server.git',
32
+ { ref: 'v1.2.0', env: { API_KEY: 'xxx' } },
33
+ () => readMcpSettings(),
34
+ (servers) => persistMcpSettings(servers),
35
+ )
36
36
  ```
37
37
 
38
- The `InstallManager` auto-detects the source type (file/url/git/npm) and content type (skill/plugin/mcp). Use `--as` to override auto-detection:
38
+ `install()` auto-detects the source type (file/url/git/npm) and content type (skill/plugin/mcp). Use `as` to override auto-detection:
39
39
 
40
40
  ```typescript
41
41
  // Force treat content as plugin even if auto-detect might guess skill
42
- await manager.install('./dir', { as: 'plugin' })
42
+ await install('./dir', { as: 'plugin' })
43
43
  ```
44
44
 
45
+ > **Note (endgame review 2026-08-14):** `install` is a pure function — it replaced the
46
+ > stateless `InstallManager` class (which held no instance state, so `new InstallManager()`
47
+ > was an empty shell). MCP settings access is injected via the optional `getMcpSettings` /
48
+ > `persistMcpSettings` callbacks; single-install semantics stay in `options`.
49
+
45
50
  ## Key Exports
46
51
 
47
52
  ### Installation
48
- - `InstallManager` — Top-level orchestrator with `install()` and `installSkill()` methods
53
+ - `install()` — Top-level orchestrator (auto-detect source + content, dispatch to installer)
54
+ - `installSkill()` — Convenience wrapper forcing `as: 'skill'`
49
55
  - `InstallOptions` — Workspace, scope, force, dry-run, sub-path, ref, progress callbacks
50
56
  - `InstallResult` — Success status, target path, definition/manifest, warnings, pending capabilities
51
57
 
package/dist/index.d.ts CHANGED
@@ -154,30 +154,30 @@ interface InstallOptions {
154
154
  //#endregion
155
155
  //#region src/installer.d.ts
156
156
  /**
157
- * InstallManager安装编排器。
157
+ * install安装编排入口(自动检测来源类型和内容类型)。
158
158
  *
159
159
  * 支持四种来源 × 三种内容类型。
160
160
  * 来源:file(本地归档)、url(HTTP 下载)、git(浅克隆)、npm(npm pack)
161
161
  * 内容:skill、plugin、mcp
162
162
  *
163
- * **阶段归属(RFC-286 D4)**:本类只负责 resolve / detect / write 三段,只 fire
164
- * `resolving` / `detecting` / `installing`。**不再 fire `refreshing`**——该阶段语义是
165
- * 「能力热重载」,真实动作 `App.reloadCapabilities()` CLI 侧持有,install 包无 App
166
- * 句柄(引入会造成 install coding 反向依赖)。此前本类在真实 reload 之前自行 fire
167
- * `refreshing`,是不拥有真实动作却展示真实阶段的「伪进度」,会让失败面板看起来仍在
168
- * 刷新。谁执行谁上报:`refreshing` 现由 `handlers/install.ts` 在调用真实 reload 前 fire。
169
- * `ProgressPhase` 类型保留 `'refreshing'` 取值供 CLI 使用。
163
+ * **形态(终局 review 2026-08-14 P1-1)**:此前是 `class InstallManager`,但该类零实例状态
164
+ * (无 logger/fetchImpl/配置持有),CLI 侧每次 `new InstallManager()` 都是空壳——类壳只是形式
165
+ * 化封装,无语义价值。降级为纯函数:单次安装语义走 `options`,MCP settings 访问经 `getMcpSettings`
166
+ * /`persistMcpSettings` 回调注入(本就是参数)。未引入 logger/fetchImpl/timeout deps bag——
167
+ * 那三者当前无任何消费方(logger 在 url-resolver 硬编码、fetchImpl 仅 RegistryClient 用、timeout
168
+ * 已由 env var 覆盖),凭空造 bag 即为抽象而抽象。真需要时再随消费方一起引入。
169
+ *
170
+ * **阶段归属(RFC-286 D4)**:只负责 resolve / detect / write 三段,只 fire
171
+ * `resolving` / `detecting` / `installing`。**不 fire `refreshing`**——该阶段语义是「能力热重载」,
172
+ * 真实动作 `App.reloadCapabilities()` 由 CLI 侧持有,install 包无 App 句柄。谁执行谁上报:
173
+ * `refreshing` 由 `handlers/install.ts` 在调用真实 reload 前 fire。`ProgressPhase` 类型保留
174
+ * `'refreshing'` 取值供 CLI 使用。
170
175
  */
171
- declare class InstallManager {
172
- /**
173
- * 通用安装入口:自动检测来源类型和内容类型。
174
- */
175
- install(source: string, options: InstallOptions, getMcpSettings?: () => Record<string, unknown> | undefined, persistMcpSettings?: (servers: Record<string, unknown>) => Promise<void>): Promise<InstallResult>;
176
- /**
177
- * 安装 skill 包(兼容旧 API)。
178
- */
179
- installSkill(source: string, options: InstallOptions): Promise<InstallResult>;
180
- }
176
+ declare function install(source: string, options: InstallOptions, getMcpSettings?: () => Record<string, unknown> | undefined, persistMcpSettings?: (servers: Record<string, unknown>) => Promise<void>): Promise<InstallResult>;
177
+ /**
178
+ * 安装 skill 包(便捷入口:强制 `as: 'skill'`)。
179
+ */
180
+ declare function installSkill(source: string, options: InstallOptions): Promise<InstallResult>;
181
181
  //#endregion
182
182
  //#region src/uninstaller.d.ts
183
183
  type UninstallTarget = 'skill' | 'plugin' | 'mcp';
@@ -192,6 +192,13 @@ interface UninstallResult {
192
192
  error?: string;
193
193
  /** dry-run 预览 */
194
194
  plan?: string[];
195
+ /**
196
+ * 非阻断告警(RFC-354 安全修复):卸载成功但存在需用户知晓的残留风险。
197
+ * 典型:信任记录撤销失败——目录已删但信任白名单/能力授权可能残留,
198
+ * 重装同 id 插件到同一路径时旧授权会复活(fail-open)。撤销失败不阻断目录删除
199
+ * (删除是用户明确意图),但必须可见而非静默吞掉。
200
+ */
201
+ warnings?: string[];
195
202
  }
196
203
  interface InstalledItem {
197
204
  name: string;
@@ -295,8 +302,12 @@ interface GitUpgradeCheckResult {
295
302
  /**
296
303
  * 检查 git 来源 skill/plugin 是否有更新。
297
304
  * 扫描 baseDir 下所有子目录的 .otto-install.json → git ls-remote → 比较 hash。
305
+ *
306
+ * 异步化(终局 review 2026-08-14 P1-3):此前用 `spawnSync` 同步阻塞事件循环做
307
+ * 网络 `git ls-remote`——N 个 git 来源项串行最长阻塞 N×10s,TUI 环境冻结整个界面。
308
+ * 改为经包内共享 `spawnAsync`(与 git-resolver 同源),签名 `sync → async`。
298
309
  */
299
- declare function checkGitUpgrades(baseDir: string, type: 'skill' | 'plugin'): GitUpgradeCheckResult[];
310
+ declare function checkGitUpgrades(baseDir: string, type: 'skill' | 'plugin'): Promise<GitUpgradeCheckResult[]>;
300
311
  //#endregion
301
312
  //#region src/archive-utils.d.ts
302
313
  /**
@@ -2392,6 +2403,12 @@ interface LoadedRegistry extends ParsedRegistry {
2392
2403
  }
2393
2404
  /** 官方源缺省条目(url 由调用方装配注入——发布形态未定期间指向仓内文件)。 */
2394
2405
  declare function builtinOfficialSource(url: string): RegistrySourceConfig;
2406
+ /**
2407
+ * 2026-08-14 修订(用户指令):删除内网官方源(`otto-official-internal`)自动加载——
2408
+ * 原 RFC-341 G2 的 `OTTO_INTERNAL_REGISTRY_URL` + 内网可达探测机制整体退役,registry
2409
+ * 单一走官方源(GitHub Pages)+ 用户自添源。内网插件发现不再依赖 registry 分发,
2410
+ * 由插件自身的 install/装载链路负责(详见 RFC-341 修订记录)。
2411
+ */
2395
2412
  declare class RegistryClient {
2396
2413
  private readonly options;
2397
2414
  constructor(options: {
@@ -2402,20 +2419,13 @@ declare class RegistryClient {
2402
2419
  });
2403
2420
  private get registriesPath();
2404
2421
  private get cacheDir();
2405
- /** 读源清单(官方源恒在首位;用户文件坏/缺时退化为仅官方源)。不含内网源——同步场景
2406
- * (如 `/registry remove` 参数补全)不该为一次可能的网络探测阻塞输入响应,见 `listSourcesAsync`。 */
2407
- listSources(): RegistrySourceConfig[];
2408
2422
  /**
2409
- * 读源清单 + 内网可达时自动追加内网官方源(RFC-341 G2)——`otto-official`(公网)恒在
2410
- * 首位,`otto-official-internal`(内网)紧随其后(仅内网可达 + `OTTO_INTERNAL_REGISTRY_URL`
2411
- * 已配置时才出现),随后是用户自定义源。
2423
+ * 读源清单(官方源恒在首位;用户文件坏/缺时退化为仅官方源)。
2412
2424
  *
2413
- * `listSources()` 的取舍:本方法可能触发一次网络探测(`isIntranetReachable()` 内部
2414
- * 5 分钟缓存,非首次调用通常走缓存零延迟)——`loadAll()`/`/registry` 面板等本就是
2415
- * 异步流程的场景改用它;纯同步场景(如参数补全建议器)继续用 `listSources()`,
2416
- * 不因偶发探测延迟阻塞按键响应。
2425
+ * 2026-08-14 修订:原 RFC-341 G2 的内网官方源自动追加(`listSourcesAsync`)已随
2426
+ * 该特性整体退役删除——清单就是清单,不再含网络探测。
2417
2427
  */
2418
- listSourcesAsync(): Promise<RegistrySourceConfig[]>;
2428
+ listSources(): RegistrySourceConfig[];
2419
2429
  addSource(name: string, url: string): void;
2420
2430
  removeSource(name: string): void;
2421
2431
  /**
@@ -2424,19 +2434,19 @@ declare class RegistryClient {
2424
2434
  * - 第三方源:改写用户配置中该条目的 disabled 字段;条目不存在则抛错。
2425
2435
  */
2426
2436
  setSourceEnabled(name: string, enabled: boolean): void;
2427
- /** 拉取全部启用源(缓存优先 → fetch → 陈旧缓存降级)。坏源跳过并记 warning。
2428
- * RFC-341 G2:内网可达时自动含内网官方源(`listSourcesAsync`),公网用户/公网环境
2429
- * 不受影响(探测目标未配置时零网络请求、零延迟,见 `isIntranetReachable` doc)。 */
2437
+ /** 拉取全部启用源(缓存优先 → fetch → 陈旧缓存降级)。坏源跳过并记 warning。 */
2430
2438
  loadAll(): Promise<{
2431
2439
  registries: LoadedRegistry[];
2432
2440
  warnings: string[];
2433
2441
  }>;
2434
2442
  private loadOne;
2443
+ /** 缓存优先 → fetch → 陈旧缓存降级(URL 源与 npm 包源共用)。 */
2444
+ private loadWithCache;
2435
2445
  private readUserSources;
2436
2446
  private writeUserSources;
2437
2447
  private readCache;
2438
2448
  private writeCache;
2439
2449
  }
2440
2450
  //#endregion
2441
- export { type ContentType, type GitUpgradeCheckResult, InstallManager, type InstallOptions, type InstallProgress, type InstallResult, type InstallScope, type InstallSourceMetadata, type InstalledItem, type ListInstalledOptions, type LoadedRegistry, type ParsedRegistry, type PostInstallContext, type PostInstallResult, type ProgressPhase, type RegistriesFile, RegistryClient, type RegistryEntry, type RegistryEntryType, type RegistrySourceConfig, type ResolvedSource, type SourceType, type UninstallOptions, type UninstallResult, type UninstallTarget, type UpgradeCheckOptions, type UpgradeCheckResult, type VersionInfo, builtinOfficialSource, checkArchiveBomb, checkGitUpgrades, checkUpgrades, cleanTempDir, createArchive, createTempDir, detectUninstallTarget, extractArchive, listInstalledItems, parseRegistry, registryEntrySchema, registryEntryTypeSchema, registrySchema, sanitizeSourceUrl, scanInstalledVersions, uninstall, validateExtractedPaths };
2451
+ export { type ContentType, type GitUpgradeCheckResult, type InstallOptions, type InstallProgress, type InstallResult, type InstallScope, type InstallSourceMetadata, type InstalledItem, type ListInstalledOptions, type LoadedRegistry, type ParsedRegistry, type PostInstallContext, type PostInstallResult, type ProgressPhase, type RegistriesFile, RegistryClient, type RegistryEntry, type RegistryEntryType, type RegistrySourceConfig, type ResolvedSource, type SourceType, type UninstallOptions, type UninstallResult, type UninstallTarget, type UpgradeCheckOptions, type UpgradeCheckResult, type VersionInfo, builtinOfficialSource, checkArchiveBomb, checkGitUpgrades, checkUpgrades, cleanTempDir, createArchive, createTempDir, detectUninstallTarget, extractArchive, install, installSkill, listInstalledItems, parseRegistry, registryEntrySchema, registryEntryTypeSchema, registrySchema, sanitizeSourceUrl, scanInstalledVersions, uninstall, validateExtractedPaths };
2442
2452
  //# sourceMappingURL=index.d.ts.map