@ai-agent-forge/agent-forge 0.88.8 → 0.88.10
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/CHANGELOG.md +13 -0
- package/bundled-plugins/agent-loop-policy/agent-forge.json +1 -1
- package/bundled-plugins/agent-loop-policy/plugin.json +1 -1
- package/bundled-plugins/alignment/agent-forge.json +1 -1
- package/bundled-plugins/alignment/plugin.json +1 -1
- package/bundled-plugins/browser-playwright/agent-forge.json +1 -1
- package/bundled-plugins/browser-playwright/plugin.json +1 -1
- package/bundled-plugins/coding-tools/agent-forge.json +1 -1
- package/bundled-plugins/coding-tools/plugin.json +1 -1
- package/bundled-plugins/compaction-policy/agent-forge.json +1 -1
- package/bundled-plugins/compaction-policy/plugin.json +1 -1
- package/bundled-plugins/overflow-policy/agent-forge.json +1 -1
- package/bundled-plugins/overflow-policy/plugin.json +1 -1
- package/bundled-plugins/provider-failover/agent-forge.json +1 -1
- package/bundled-plugins/provider-failover/plugin.json +1 -1
- package/bundled-plugins/retry-policy/agent-forge.json +1 -1
- package/bundled-plugins/retry-policy/plugin.json +1 -1
- package/dist/bundle/.build-manifest.json +11 -11
- package/dist/bundle/chunks/{chunk-ZS5JEI76.js → chunk-4BD6FSZA.js} +1 -1
- package/dist/bundle/chunks/{chunk-ISLHFRER.js → chunk-F73USSXE.js} +1 -1
- package/dist/bundle/chunks/{chunk-WJSKB3FC.js → chunk-HXGAAJQQ.js} +1 -1
- package/dist/bundle/chunks/{chunk-L2SXIPI5.js → chunk-ZZCUNSGO.js} +4 -4
- package/dist/bundle/chunks/image-resize-worker.js +1 -1
- package/dist/bundle/chunks/{virtual-modules-2QGILFV7.js → virtual-modules-UQRUJLPM.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/client.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/i18n/locales/zh-cn/cli.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/cli.js +2 -1
- package/dist/core/i18n/locales/zh-cn/cli.js.map +1 -1
- package/dist/plugins/ecosystem/catalog.d.ts +1 -1
- package/dist/plugins/ecosystem/catalog.d.ts.map +1 -1
- package/dist/plugins/ecosystem/catalog.js +10 -4
- package/dist/plugins/ecosystem/catalog.js.map +1 -1
- package/dist/plugins/ecosystem/node-disk-registry-source.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-disk-registry-source.js +12 -0
- package/dist/plugins/ecosystem/node-disk-registry-source.js.map +1 -1
- package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts +6 -1
- package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-plugin-bootstrap.js +11 -3
- package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
- package/dist/plugins/ecosystem/plugin-bootstrap.d.ts +10 -0
- package/dist/plugins/ecosystem/plugin-bootstrap.d.ts.map +1 -1
- package/dist/plugins/ecosystem/plugin-bootstrap.js +66 -23
- package/dist/plugins/ecosystem/plugin-bootstrap.js.map +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/extensions/with-deps/plugin.json +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../../../src/core/i18n/locales/zh-cn/cli.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAgRtC,CAAC","sourcesContent":["/**\n * CLI 输出层域词典(docs/design/国际化与本地化.md §3,批次⑤):覆盖\n * main.ts 启动/错误输出、--help(printHelp)、auth help、--list-models、\n * print-mode 的用户可见文案。key 为英文原文,占位符 `{name}` 原样保留。\n * 命令名、flag、路径、环境变量、suite 等代码标识符不译。\n */\nexport const cli: Record<string, string> = {\n\t// --- main.ts:诊断/错误前缀与兜底 ---\n\t\"Error: {message}\": \"错误:{message}\",\n\t\"Warning: {message}\": \"警告:{message}\",\n\t\"Failed to parse auth command\": \"解析 auth 命令失败\",\n\t\"Failed to resolve credential\": \"解析凭证失败\",\n\t\"Failed to export session\": \"导出会话失败\",\n\t\"Exported to: {result}\": \"已导出到:{result}\",\n\n\t// --- main.ts:auth 命令参数错误 ---\n\t'Invalid arguments for \"{command}\".': '\"{command}\" 的参数无效。',\n\t'Use \"{help}\" or \"{usage}\".': '请使用 \"{help}\" 或 \"{usage}\"。',\n\n\t// --- main.ts:suite 生命周期 ---\n\t'Created suite \"{id}\" at {dir}': '已创建 suite \"{id}\",位于 {dir}',\n\t\"Error: --clone-from requires --suite-create\": \"错误:--clone-from 需要与 --suite-create 一起使用\",\n\t'Error: suite \"{id}\" is referenced by {count} existing session(s); deletion refused:':\n\t\t'错误:suite \"{id}\" 被 {count} 个现有会话引用,拒绝删除:',\n\t'Deleting suite \"{id}\": the workspace directory {dir} will be moved to the trash and released.':\n\t\t'正在删除 suite \"{id}\":工作区目录 {dir} 将被移入回收站并释放。',\n\t'Refusing to delete suite \"{id}\" without an interactive confirmation (non-interactive stdin). Re-run in a terminal to confirm.':\n\t\t'拒绝删除 suite \"{id}\":缺少交互式确认(stdin 非交互)。请在终端中重新运行以确认。',\n\t'Delete suite \"{id}\"?': '删除 suite \"{id}\"?',\n\t'Aborted: suite \"{id}\" was not deleted.': '已中止:suite \"{id}\" 未删除。',\n\t'Cleared the {scope} settings \"suite\" key (pointed at \"{id}\").':\n\t\t'已清除 {scope} 设置中的 \"suite\" 键(原指向 \"{id}\")。',\n\t'Deleted suite \"{id}\"; the workspace was moved to {trashPath} and is being released.':\n\t\t'已删除 suite \"{id}\";工作区已移至 {trashPath},正在释放。',\n\t'Suite \"{id}\" is a user suite; only builtin suites can be reset — use --suite-delete instead.':\n\t\t'suite \"{id}\" 是用户 suite;只有内置 suite 可以重置——请改用 --suite-delete。',\n\t'Suite \"{id}\" already matches the factory contents; nothing to reset.': 'suite \"{id}\" 已与出厂内容一致,无需重置。',\n\t'Resetting builtin suite \"{id}\" to the factory contents:': '正在将内置 suite \"{id}\" 重置为出厂内容:',\n\t'Refusing to reset suite \"{id}\" without an interactive confirmation (non-interactive stdin). Review the diff above and re-run in a terminal to confirm.':\n\t\t'拒绝重置 suite \"{id}\":缺少交互式确认(stdin 非交互)。请先查看上方 diff,再在终端中重新运行以确认。',\n\t'Apply reset of suite \"{id}\"?': '应用 suite \"{id}\" 的重置?',\n\t'Aborted: suite \"{id}\" was not reset.': '已中止:suite \"{id}\" 未重置。',\n\t'Suite \"{id}\" was reset to the factory contents (profile lock generation {generation}).':\n\t\t'suite \"{id}\" 已重置为出厂内容(profile lock 代数 {generation})。',\n\n\t// --- main.ts:flag 冲突与模式错误 ---\n\t\"Error: --fork cannot be combined with {flags}\": \"错误:--fork 不能与 {flags} 组合使用\",\n\t\"Error: --session-id cannot be combined with {flags}. To resume that exact session, drop the other flags and use --session-id alone (or use --continue to resume the most recent session).\":\n\t\t\"错误:--session-id 不能与 {flags} 组合使用。要恢复该确切会话,请去掉其他 flag,单独使用 --session-id(或使用 --continue 恢复最近会话)。\",\n\t\"Error: --serve cannot be combined with {flags}\": \"错误:--serve 不能与 {flags} 组合使用\",\n\t\"--serve ignores session/model/tool options: {flags}\": \"--serve 会忽略会话/模型/工具选项:{flags}\",\n\t\"Error: @file arguments are not supported in RPC mode\": \"错误:RPC 模式不支持 @file 参数\",\n\t\"Error: --name requires a non-empty value\": \"错误:--name 需要非空值\",\n\t\"Error: AGENT_FORGE_STARTUP_BENCHMARK only supports interactive mode\":\n\t\t\"错误:AGENT_FORGE_STARTUP_BENCHMARK 仅支持交互模式\",\n\n\t// --- main.ts:会话选择/创建 ---\n\t\"Session already exists with id '{sessionId}'\": \"已存在 id 为 '{sessionId}' 的会话\",\n\t\"No session found matching '{arg}'\": \"没有找到匹配 '{arg}' 的会话\",\n\t\"Session found in different project: {cwd}\": \"会话位于其他项目:{cwd}\",\n\t\"Fork this session into current directory?\": \"将该会话 fork 到当前目录?\",\n\t\"Aborted.\": \"已中止。\",\n\t\"No session selected\": \"未选择会话\",\n\t\"Warning: No project session found with id '{sessionId}'; creating a new session with that id.\":\n\t\t\"警告:没有找到 id 为 '{sessionId}' 的项目会话;将创建使用该 id 的新会话。\",\n\n\t// --- main.ts:插件 bootstrap/拒绝 ---\n\t\"Plugin bootstrap {code}: {message}\": \"插件 bootstrap {code}:{message}\",\n\t\"First run: installing {count} factory plugins…\": \"首次运行:正在安装 {count} 个出厂插件…\",\n\t\"{pluginId}: installed {version}\": \"{pluginId}:已安装 {version}\",\n\t\"{pluginId}: install failed ({code}) — startup continues; the next startup retries automatically\":\n\t\t\"{pluginId}:安装失败({code})——启动继续,下次启动将自动重试\",\n\t\"Offline posture (AGENT_FORGE_OFFLINE) skips the startup plugin bootstrap; run `agent-forge plugin install <package>` explicitly to install plugins.\":\n\t\t\"离线姿态(AGENT_FORGE_OFFLINE)跳过启动插件引导;可用 `agent-forge plugin install <包名>` 显式安装插件。\",\n\t\"Warning: capability plugin rejected ({code}): {target}: {message}\":\n\t\t\"警告:能力插件被拒绝({code}):{target}:{message}\",\n\n\t// --- args.ts:printHelp 节标题与标题行 ---\n\t\"AI coding assistant with read, bash, edit, write tools\": \"具备 read、bash、edit、write 工具的 AI 编程助手\",\n\t\"Usage:\": \"用法:\",\n\t\"Commands:\": \"命令:\",\n\t\"Options:\": \"选项:\",\n\t\"Examples:\": \"示例:\",\n\t\"Environment Variables:\": \"环境变量:\",\n\t\"Built-in Tool Names:\": \"内置工具名:\",\n\n\t// --- args.ts:printHelp Commands 描述 ---\n\t\"Install extension source and add to settings\": \"安装扩展源并加入设置\",\n\t\"Remove extension source from settings\": \"从设置中移除扩展源\",\n\t\"Alias for remove\": \"remove 的别名\",\n\t\"Update Agent Forge, extensions, or model catalogs\": \"更新 Agent Forge、扩展或模型目录\",\n\t\"List installed extensions from settings\": \"列出设置中已安装的扩展\",\n\t\"Open TUI to enable/disable package resources (Tab switches scope)\": \"打开 TUI 启用/禁用包资源(Tab 切换作用域)\",\n\t\"Print credentials or check provider readiness\": \"打印凭证或检查提供商就绪状态\",\n\t\"Show help for install/remove/uninstall/update/list/config/auth\":\n\t\t\"显示 install/remove/uninstall/update/list/config/auth 的帮助\",\n\n\t// --- args.ts:printHelp Options 描述 ---\n\t\"Provider name (default: google)\": \"提供商名称(默认:google)\",\n\t'Model pattern or ID (supports \"provider/id\" and optional \":<thinking>\")':\n\t\t'模型模式或 ID(支持 \"provider/id\" 与可选的 \":<thinking>\")',\n\t\"API key (defaults to env vars)\": \"API key(默认取自环境变量)\",\n\t\"System prompt (default: coding assistant prompt)\": \"系统提示词(默认:编程助手提示词)\",\n\t\"Append text or file contents to the system prompt (can be used multiple times)\":\n\t\t\"向系统提示词追加文本或文件内容(可多次使用)\",\n\t\"Output mode: text (default), json, or rpc\": \"输出模式:text(默认)、json 或 rpc\",\n\t\"Non-interactive mode: process prompt and exit\": \"非交互模式:处理提示后退出\",\n\t\"Continue previous session\": \"继续上一个会话\",\n\t\"Select a session to resume\": \"选择要恢复的会话\",\n\t\"Use specific session file or partial UUID\": \"使用指定会话文件或部分 UUID\",\n\t\"Use exact project session ID, creating it if missing\": \"使用精确的项目会话 ID,不存在则创建\",\n\t\"Fork specific session file or partial UUID into a new session\": \"将指定会话文件或部分 UUID fork 为新会话\",\n\t\"Directory for session storage and lookup\": \"会话存储与查找目录\",\n\t\"Suite (方案) for this run: coding (default) or assistant; new sessions only\":\n\t\t\"本次运行的 suite(方案):coding(默认)或 assistant;仅对新会话生效\",\n\t\"Create a user suite workspace and exit; add --clone-from <id> to copy one\":\n\t\t\"创建用户 suite 工作区并退出;加 --clone-from <id> 可复制既有 suite\",\n\t\"Delete a user suite workspace (active session references refuse) and exit\":\n\t\t\"删除用户 suite 工作区(存在活动会话引用时拒绝)并退出\",\n\t\"Reset a builtin suite to factory contents (shows a diff) and exit\":\n\t\t\"将内置 suite 重置为出厂内容(显示 diff)并退出\",\n\t\"(Experimental, local trust only) Serve the coding-agent session runtime over the WebSocket gateway (default: 127.0.0.1; HTTP surface: /healthz plus token-protected artifact reads) and exit on SIGINT/SIGTERM\":\n\t\t\"(实验性,仅限本地信任)经 WebSocket 网关提供 coding-agent 会话运行时(默认:127.0.0.1;HTTP 面:/healthz 及受令牌保护的产物读取),SIGINT/SIGTERM 时退出\",\n\t\"Durable journal: <agentDir>/remote-server-journal.jsonl (never the process cwd)\":\n\t\t\"持久日志:<agentDir>/remote-server-journal.jsonl(绝不写入进程 cwd)\",\n\t\"Opt-in --serve boundary: remote creates must run inside one of these roots (repeatable); without it any local directory is allowed\":\n\t\t\"--serve 的可选边界:远程创建必须在这些根目录内运行(可重复);未指定时允许任意本地目录\",\n\t\"(Experimental) Run as a headless subagent runner: serve the subagent-task protocol on stdio for a parent session's runner pool (D-045)\":\n\t\t\"(实验性)作为无头子代理运行器:在 stdio 上为父会话的 runner 池提供 subagent-task 协议(D-045)\",\n\t\"Don't save session (ephemeral)\": \"不保存会话(一次性)\",\n\t\"Set session display name\": \"设置会话显示名称\",\n\t\"Comma-separated model patterns for Ctrl+P cycling\": \"逗号分隔的模型模式,用于 Ctrl+P 轮换\",\n\t\"Supports globs (anthropic/*, *sonnet*) and fuzzy matching\": \"支持 glob(anthropic/*、*sonnet*)与模糊匹配\",\n\t\"Disable all tools by default (built-in and plugin)\": \"默认禁用全部工具(内置与插件)\",\n\t\"Disable built-in tools by default but keep plugin/custom tools enabled\":\n\t\t\"默认禁用内置工具,但保持插件/自定义工具可用\",\n\t\"Comma-separated allowlist of tool names to enable\": \"逗号分隔的工具名白名单\",\n\t\"Applies to built-in, plugin, and custom tools\": \"作用于内置、插件与自定义工具\",\n\t\"Comma-separated denylist of tool names to disable\": \"逗号分隔的工具名黑名单\",\n\t\"Set thinking level: off, minimal, low, medium, high, xhigh, max\":\n\t\t\"设置思考级别:off、minimal、low、medium、high、xhigh、max\",\n\t\"Disable capability plugin discovery (D-028 escape hatch)\": \"禁用能力插件发现(D-028 逃生口)\",\n\t\"Disable session trace collection (no .trace.jsonl file is written)\": \"禁用会话轨迹收集(不写 .trace.jsonl 文件)\",\n\t\"Host log level: debug, info (default), warn, error\": \"宿主日志级别:debug、info(默认)、warn、error\",\n\t\"Select a builtin capability plugin profile for this run\": \"为本次运行选择内置能力插件 profile\",\n\t\"Select a plugin within the profile (repeatable)\": \"在 profile 内选择插件(可重复)\",\n\t\"Disable a plugin within the profile (repeatable)\": \"在 profile 内禁用插件(可重复)\",\n\t\"Read the explicit selection from global or project storage\": \"从全局或项目存储读取显式选择\",\n\t\"List installed/available ecosystem plugins (independent namespace)\": \"列出已安装/可用的生态插件(独立命名空间)\",\n\t\"Load a skill file or directory (can be used multiple times)\": \"加载 skill 文件或目录(可多次使用)\",\n\t\"Disable skills discovery and loading\": \"禁用 skill 发现与加载\",\n\t\"Load a prompt template file or directory (can be used multiple times)\": \"加载提示词模板文件或目录(可多次使用)\",\n\t\"Disable prompt template discovery and loading\": \"禁用提示词模板发现与加载\",\n\t\"Load a theme file or directory (can be used multiple times)\": \"加载主题文件或目录(可多次使用)\",\n\t\"Set the initial interactive theme for this run\": \"设置本次运行的初始交互主题\",\n\t\"Disable theme discovery and loading\": \"禁用主题发现与加载\",\n\t\"Disable AGENTS.md and CLAUDE.md discovery and loading\": \"禁用 AGENTS.md 与 CLAUDE.md 的发现与加载\",\n\t\"Export session file to HTML and exit\": \"将会话文件导出为 HTML 并退出\",\n\t\"View a session trace file as a text timeline and exit; <session> is a session id/prefix or trace/session file path, omit it for the most recent session\":\n\t\t\"以文本时间线查看会话轨迹文件并退出;<session> 为会话 id/前缀或轨迹/会话文件路径,省略则查看最近会话\",\n\t\"With --trace, output the structured trace records as JSON instead of the text timeline\":\n\t\t\"配合 --trace,以 JSON 输出结构化轨迹记录,而非文本时间线\",\n\t\"With --trace, show only records of these kinds (comma-separated); valid kinds: {kinds}\":\n\t\t\"配合 --trace,只显示这些类型的记录(逗号分隔);有效类型:{kinds}\",\n\t\"With --trace, show only the last N records (positive integer)\": \"配合 --trace,只显示最后 N 条记录(正整数)\",\n\t\"List available models (with optional fuzzy search)\": \"列出可用模型(可选模糊搜索)\",\n\t\"Force verbose startup (overrides quietStartup setting)\": \"强制详细启动(覆盖 quietStartup 设置)\",\n\t\"TUI mode: regular (default) or fullscreen\": \"TUI 模式:regular(默认)或 fullscreen\",\n\t\"Disable startup network operations (same as AGENT_FORGE_OFFLINE=1)\":\n\t\t\"禁用启动网络操作(等同 AGENT_FORGE_OFFLINE=1)\",\n\t\"End option parsing; treat remaining arguments as messages/files\": \"结束选项解析;剩余参数视为消息/文件\",\n\t\"Show this help\": \"显示此帮助\",\n\t\"Show version number\": \"显示版本号\",\n\n\t// --- args.ts:printHelp Examples 注释 ---\n\t\"Print a provider API key for an external client\": \"为外部客户端打印提供商 API key\",\n\t\"Print an OAuth bearer token for an external client (refreshes if expired)\":\n\t\t\"为外部客户端打印 OAuth bearer token(过期则刷新)\",\n\t\"Interactive mode\": \"交互模式\",\n\t\"Interactive mode with initial prompt\": \"带初始提示的交互模式\",\n\t\"Include files in initial message\": \"在初始消息中包含文件\",\n\t\"Non-interactive mode (process and exit)\": \"非交互模式(处理后退出)\",\n\t\"Prompt beginning with a dash\": \"以连字符开头的提示\",\n\t\"Multiple messages (interactive)\": \"多条消息(交互)\",\n\t\"Start a named session\": \"启动命名会话\",\n\t\"Use different model\": \"使用不同模型\",\n\t\"Use model with provider prefix (no --provider needed)\": \"使用带提供商前缀的模型(无需 --provider)\",\n\t\"Use model with thinking level shorthand\": \"使用思考级别简写形式的模型\",\n\t\"Limit model cycling to specific models\": \"将模型轮换限定为指定模型\",\n\t\"Limit to a specific provider with glob pattern\": \"用 glob 模式限定到指定提供商\",\n\t\"Cycle models with fixed thinking levels\": \"以固定思考级别轮换模型\",\n\t\"Start with a specific thinking level\": \"以指定思考级别启动\",\n\t\"Read-only mode (no file modifications possible)\": \"只读模式(不能修改文件)\",\n\t\"Disable one tool while keeping the rest available\": \"禁用单个工具,其余保持可用\",\n\t\"Export a session file to HTML\": \"导出会话文件为 HTML\",\n\n\t// --- args.ts:printHelp 环境变量描述 ---\n\t\"Anthropic bearer auth token\": \"Anthropic bearer 认证令牌\",\n\t\"Anthropic Claude API key\": \"Anthropic Claude API key\",\n\t\"Anthropic OAuth token (alternative to API key)\": \"Anthropic OAuth 令牌(API key 的替代)\",\n\t\"Ant Ling API key\": \"Ant Ling API key\",\n\t\"OpenAI GPT API key\": \"OpenAI GPT API key\",\n\t\"Azure OpenAI API key\": \"Azure OpenAI API key\",\n\t\"Azure OpenAI/Cognitive Services base URL (e.g. https://{resource}.openai.azure.com)\":\n\t\t\"Azure OpenAI/Cognitive Services base URL(如 https://{resource}.openai.azure.com)\",\n\t\"Azure OpenAI resource name (alternative to base URL)\": \"Azure OpenAI 资源名(base URL 的替代)\",\n\t\"Azure OpenAI API version (default: v1)\": \"Azure OpenAI API 版本(默认:v1)\",\n\t\"Azure OpenAI model=deployment map (comma-separated)\": \"Azure OpenAI 模型=部署映射(逗号分隔)\",\n\t\"DeepSeek API key\": \"DeepSeek API key\",\n\t\"NVIDIA NIM API key\": \"NVIDIA NIM API key\",\n\t\"Google Gemini API key\": \"Google Gemini API key\",\n\t\"Groq API key\": \"Groq API key\",\n\t\"Cerebras API key\": \"Cerebras API key\",\n\t\"xAI Grok API key\": \"xAI Grok API key\",\n\t\"Fireworks API key\": \"Fireworks API key\",\n\t\"Together AI API key\": \"Together AI API key\",\n\t\"Baseten API key\": \"Baseten API key\",\n\t\"OpenRouter API key\": \"OpenRouter API key\",\n\t\"Vercel AI Gateway API key\": \"Vercel AI Gateway API key\",\n\t\"ZAI Coding Plan API key (Global)\": \"ZAI Coding Plan API key(全球区)\",\n\t\"ZAI Coding Plan API key (China)\": \"ZAI Coding Plan API key(中国区)\",\n\t\"Mistral API key\": \"Mistral API key\",\n\t\"MiniMax API key\": \"MiniMax API key\",\n\t\"Moonshot AI API key\": \"Moonshot AI API key\",\n\t\"OpenCode Zen/OpenCode Go API key\": \"OpenCode Zen/OpenCode Go API key\",\n\t\"Kimi For Coding API key\": \"Kimi For Coding API key\",\n\t\"Cloudflare API token (Workers AI and AI Gateway)\": \"Cloudflare API 令牌(Workers AI 与 AI Gateway)\",\n\t\"Cloudflare account id (required for both)\": \"Cloudflare 账户 id(两者均需要)\",\n\t\"Cloudflare AI Gateway slug (required for AI Gateway)\": \"Cloudflare AI Gateway slug(AI Gateway 需要)\",\n\t\"Qwen Token Plan API key (international region)\": \"Qwen Token Plan API key(国际区)\",\n\t\"Qwen Token Plan API key (China region)\": \"Qwen Token Plan API key(中国区)\",\n\t\"Xiaomi MiMo API key (api.xiaomimimo.com billing)\": \"Xiaomi MiMo API key(按 api.xiaomimimo.com 计费)\",\n\t\"Xiaomi MiMo Token Plan API key (China region)\": \"Xiaomi MiMo Token Plan API key(中国区)\",\n\t\"Xiaomi MiMo Token Plan API key (Amsterdam region)\": \"Xiaomi MiMo Token Plan API key(阿姆斯特丹区)\",\n\t\"Xiaomi MiMo Token Plan API key (Singapore region)\": \"Xiaomi MiMo Token Plan API key(新加坡区)\",\n\t\"AWS profile for Amazon Bedrock\": \"Amazon Bedrock 的 AWS profile\",\n\t\"AWS access key for Amazon Bedrock\": \"Amazon Bedrock 的 AWS access key\",\n\t\"AWS secret key for Amazon Bedrock\": \"Amazon Bedrock 的 AWS secret key\",\n\t\"Bedrock API key (bearer token)\": \"Bedrock API key(bearer token)\",\n\t\"AWS region for Amazon Bedrock (e.g., us-east-1)\": \"Amazon Bedrock 的 AWS 区域(如 us-east-1)\",\n\t\"Config directory (default: ~/{configDir}/agent)\": \"配置目录(默认:~/{configDir}/agent)\",\n\t\"Session storage directory (overridden by --session-dir)\": \"会话存储目录(--session-dir 可覆盖)\",\n\t\"Override package directory (for Nix/Guix store paths)\": \"覆盖包目录(用于 Nix/Guix store 路径)\",\n\t\"Disable startup network operations when set to 1/true/yes\": \"设为 1/true/yes 时禁用启动网络操作\",\n\n\t// --- args.ts:printHelp 内置工具描述 ---\n\t\"Read file contents\": \"读取文件内容\",\n\t\"Execute bash commands\": \"执行 bash 命令\",\n\t\"Execute PowerShell commands on Windows\": \"在 Windows 上执行 PowerShell 命令\",\n\t\"Edit files with find/replace\": \"以查找/替换方式编辑文件\",\n\t\"Write files (creates/overwrites)\": \"写文件(创建/覆盖)\",\n\t\"Search file contents (read-only, off by default)\": \"搜索文件内容(只读,默认关闭)\",\n\t\"Find files by glob pattern (read-only, off by default)\": \"按 glob 模式查找文件(只读,默认关闭)\",\n\t\"List directory contents (read-only, off by default)\": \"列出目录内容(只读,默认关闭)\",\n\n\t// --- auth-command.ts:printAuthCommandHelp ---\n\t\"Auth commands require at least one of --provider or --model. Checks refresh expired OAuth credentials by default; --no-refresh prevents this. --credentials emits the credential, or includes it in JSON output. --no-refresh also leaves command-backed keys unresolved: --credentials reports them as unavailable instead of running the command.\":\n\t\t\"auth 命令需要 --provider 或 --model 至少其一。check 默认刷新已过期的 OAuth 凭证;--no-refresh 可阻止。--credentials 输出凭证,或将其包含在 JSON 输出中。--no-refresh 同时不解析命令型 key:--credentials 将其报告为不可用,而不会执行该命令。\",\n\n\t// --- list-models.ts ---\n\t\"Warning: errors loading models.json:\\n{loadError}\": \"警告:加载 models.json 出错:\\n{loadError}\",\n\t'No models matching \"{searchPattern}\"': '没有匹配 \"{searchPattern}\" 的模型',\n\tprovider: \"提供商\",\n\tmodel: \"模型\",\n\tcontext: \"上下文\",\n\t\"max-out\": \"最大输出\",\n\tthinking: \"思考\",\n\timages: \"图像\",\n\n\t// --- print-mode.ts ---\n\t\"{label}: {url}\": \"{label}:{url}\",\n\t\"Request {stopReason}\": \"请求 {stopReason}\",\n\n\t// --- serve.ts ---\n\t\"remote-server error: {error}\": \"remote-server 错误:{error}\",\n\t\"Port {port} is already in use\": \"端口 {port} 已被占用\",\n\t\"Remote server shutdown failed: {error}\": \"远程服务器关闭失败:{error}\",\n\t\"Remote server listening on {addresses}\": \"远程服务器监听于 {addresses}\",\n};\n"]}
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../../../src/core/i18n/locales/zh-cn/cli.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAiRtC,CAAC","sourcesContent":["/**\n * CLI 输出层域词典(docs/design/国际化与本地化.md §3,批次⑤):覆盖\n * main.ts 启动/错误输出、--help(printHelp)、auth help、--list-models、\n * print-mode 的用户可见文案。key 为英文原文,占位符 `{name}` 原样保留。\n * 命令名、flag、路径、环境变量、suite 等代码标识符不译。\n */\nexport const cli: Record<string, string> = {\n\t// --- main.ts:诊断/错误前缀与兜底 ---\n\t\"Error: {message}\": \"错误:{message}\",\n\t\"Warning: {message}\": \"警告:{message}\",\n\t\"Failed to parse auth command\": \"解析 auth 命令失败\",\n\t\"Failed to resolve credential\": \"解析凭证失败\",\n\t\"Failed to export session\": \"导出会话失败\",\n\t\"Exported to: {result}\": \"已导出到:{result}\",\n\n\t// --- main.ts:auth 命令参数错误 ---\n\t'Invalid arguments for \"{command}\".': '\"{command}\" 的参数无效。',\n\t'Use \"{help}\" or \"{usage}\".': '请使用 \"{help}\" 或 \"{usage}\"。',\n\n\t// --- main.ts:suite 生命周期 ---\n\t'Created suite \"{id}\" at {dir}': '已创建 suite \"{id}\",位于 {dir}',\n\t\"Error: --clone-from requires --suite-create\": \"错误:--clone-from 需要与 --suite-create 一起使用\",\n\t'Error: suite \"{id}\" is referenced by {count} existing session(s); deletion refused:':\n\t\t'错误:suite \"{id}\" 被 {count} 个现有会话引用,拒绝删除:',\n\t'Deleting suite \"{id}\": the workspace directory {dir} will be moved to the trash and released.':\n\t\t'正在删除 suite \"{id}\":工作区目录 {dir} 将被移入回收站并释放。',\n\t'Refusing to delete suite \"{id}\" without an interactive confirmation (non-interactive stdin). Re-run in a terminal to confirm.':\n\t\t'拒绝删除 suite \"{id}\":缺少交互式确认(stdin 非交互)。请在终端中重新运行以确认。',\n\t'Delete suite \"{id}\"?': '删除 suite \"{id}\"?',\n\t'Aborted: suite \"{id}\" was not deleted.': '已中止:suite \"{id}\" 未删除。',\n\t'Cleared the {scope} settings \"suite\" key (pointed at \"{id}\").':\n\t\t'已清除 {scope} 设置中的 \"suite\" 键(原指向 \"{id}\")。',\n\t'Deleted suite \"{id}\"; the workspace was moved to {trashPath} and is being released.':\n\t\t'已删除 suite \"{id}\";工作区已移至 {trashPath},正在释放。',\n\t'Suite \"{id}\" is a user suite; only builtin suites can be reset — use --suite-delete instead.':\n\t\t'suite \"{id}\" 是用户 suite;只有内置 suite 可以重置——请改用 --suite-delete。',\n\t'Suite \"{id}\" already matches the factory contents; nothing to reset.': 'suite \"{id}\" 已与出厂内容一致,无需重置。',\n\t'Resetting builtin suite \"{id}\" to the factory contents:': '正在将内置 suite \"{id}\" 重置为出厂内容:',\n\t'Refusing to reset suite \"{id}\" without an interactive confirmation (non-interactive stdin). Review the diff above and re-run in a terminal to confirm.':\n\t\t'拒绝重置 suite \"{id}\":缺少交互式确认(stdin 非交互)。请先查看上方 diff,再在终端中重新运行以确认。',\n\t'Apply reset of suite \"{id}\"?': '应用 suite \"{id}\" 的重置?',\n\t'Aborted: suite \"{id}\" was not reset.': '已中止:suite \"{id}\" 未重置。',\n\t'Suite \"{id}\" was reset to the factory contents (profile lock generation {generation}).':\n\t\t'suite \"{id}\" 已重置为出厂内容(profile lock 代数 {generation})。',\n\n\t// --- main.ts:flag 冲突与模式错误 ---\n\t\"Error: --fork cannot be combined with {flags}\": \"错误:--fork 不能与 {flags} 组合使用\",\n\t\"Error: --session-id cannot be combined with {flags}. To resume that exact session, drop the other flags and use --session-id alone (or use --continue to resume the most recent session).\":\n\t\t\"错误:--session-id 不能与 {flags} 组合使用。要恢复该确切会话,请去掉其他 flag,单独使用 --session-id(或使用 --continue 恢复最近会话)。\",\n\t\"Error: --serve cannot be combined with {flags}\": \"错误:--serve 不能与 {flags} 组合使用\",\n\t\"--serve ignores session/model/tool options: {flags}\": \"--serve 会忽略会话/模型/工具选项:{flags}\",\n\t\"Error: @file arguments are not supported in RPC mode\": \"错误:RPC 模式不支持 @file 参数\",\n\t\"Error: --name requires a non-empty value\": \"错误:--name 需要非空值\",\n\t\"Error: AGENT_FORGE_STARTUP_BENCHMARK only supports interactive mode\":\n\t\t\"错误:AGENT_FORGE_STARTUP_BENCHMARK 仅支持交互模式\",\n\n\t// --- main.ts:会话选择/创建 ---\n\t\"Session already exists with id '{sessionId}'\": \"已存在 id 为 '{sessionId}' 的会话\",\n\t\"No session found matching '{arg}'\": \"没有找到匹配 '{arg}' 的会话\",\n\t\"Session found in different project: {cwd}\": \"会话位于其他项目:{cwd}\",\n\t\"Fork this session into current directory?\": \"将该会话 fork 到当前目录?\",\n\t\"Aborted.\": \"已中止。\",\n\t\"No session selected\": \"未选择会话\",\n\t\"Warning: No project session found with id '{sessionId}'; creating a new session with that id.\":\n\t\t\"警告:没有找到 id 为 '{sessionId}' 的项目会话;将创建使用该 id 的新会话。\",\n\n\t// --- main.ts:插件 bootstrap/拒绝 ---\n\t\"Plugin bootstrap {code}: {message}\": \"插件 bootstrap {code}:{message}\",\n\t\"Aligning {count} factory plugin(s) from npm…\": \"正在从 npm 对齐 {count} 个出厂插件…\",\n\t\"{pluginId}: installing…\": \"{pluginId}:安装中…\",\n\t\"{pluginId}: installed {version}\": \"{pluginId}:已安装 {version}\",\n\t\"{pluginId}: install failed ({code}) — startup continues; the next startup retries automatically\":\n\t\t\"{pluginId}:安装失败({code})——启动继续,下次启动将自动重试\",\n\t\"Offline posture (AGENT_FORGE_OFFLINE) skips the startup plugin bootstrap; run `agent-forge plugin install <package>` explicitly to install plugins.\":\n\t\t\"离线姿态(AGENT_FORGE_OFFLINE)跳过启动插件引导;可用 `agent-forge plugin install <包名>` 显式安装插件。\",\n\t\"Warning: capability plugin rejected ({code}): {target}: {message}\":\n\t\t\"警告:能力插件被拒绝({code}):{target}:{message}\",\n\n\t// --- args.ts:printHelp 节标题与标题行 ---\n\t\"AI coding assistant with read, bash, edit, write tools\": \"具备 read、bash、edit、write 工具的 AI 编程助手\",\n\t\"Usage:\": \"用法:\",\n\t\"Commands:\": \"命令:\",\n\t\"Options:\": \"选项:\",\n\t\"Examples:\": \"示例:\",\n\t\"Environment Variables:\": \"环境变量:\",\n\t\"Built-in Tool Names:\": \"内置工具名:\",\n\n\t// --- args.ts:printHelp Commands 描述 ---\n\t\"Install extension source and add to settings\": \"安装扩展源并加入设置\",\n\t\"Remove extension source from settings\": \"从设置中移除扩展源\",\n\t\"Alias for remove\": \"remove 的别名\",\n\t\"Update Agent Forge, extensions, or model catalogs\": \"更新 Agent Forge、扩展或模型目录\",\n\t\"List installed extensions from settings\": \"列出设置中已安装的扩展\",\n\t\"Open TUI to enable/disable package resources (Tab switches scope)\": \"打开 TUI 启用/禁用包资源(Tab 切换作用域)\",\n\t\"Print credentials or check provider readiness\": \"打印凭证或检查提供商就绪状态\",\n\t\"Show help for install/remove/uninstall/update/list/config/auth\":\n\t\t\"显示 install/remove/uninstall/update/list/config/auth 的帮助\",\n\n\t// --- args.ts:printHelp Options 描述 ---\n\t\"Provider name (default: google)\": \"提供商名称(默认:google)\",\n\t'Model pattern or ID (supports \"provider/id\" and optional \":<thinking>\")':\n\t\t'模型模式或 ID(支持 \"provider/id\" 与可选的 \":<thinking>\")',\n\t\"API key (defaults to env vars)\": \"API key(默认取自环境变量)\",\n\t\"System prompt (default: coding assistant prompt)\": \"系统提示词(默认:编程助手提示词)\",\n\t\"Append text or file contents to the system prompt (can be used multiple times)\":\n\t\t\"向系统提示词追加文本或文件内容(可多次使用)\",\n\t\"Output mode: text (default), json, or rpc\": \"输出模式:text(默认)、json 或 rpc\",\n\t\"Non-interactive mode: process prompt and exit\": \"非交互模式:处理提示后退出\",\n\t\"Continue previous session\": \"继续上一个会话\",\n\t\"Select a session to resume\": \"选择要恢复的会话\",\n\t\"Use specific session file or partial UUID\": \"使用指定会话文件或部分 UUID\",\n\t\"Use exact project session ID, creating it if missing\": \"使用精确的项目会话 ID,不存在则创建\",\n\t\"Fork specific session file or partial UUID into a new session\": \"将指定会话文件或部分 UUID fork 为新会话\",\n\t\"Directory for session storage and lookup\": \"会话存储与查找目录\",\n\t\"Suite (方案) for this run: coding (default) or assistant; new sessions only\":\n\t\t\"本次运行的 suite(方案):coding(默认)或 assistant;仅对新会话生效\",\n\t\"Create a user suite workspace and exit; add --clone-from <id> to copy one\":\n\t\t\"创建用户 suite 工作区并退出;加 --clone-from <id> 可复制既有 suite\",\n\t\"Delete a user suite workspace (active session references refuse) and exit\":\n\t\t\"删除用户 suite 工作区(存在活动会话引用时拒绝)并退出\",\n\t\"Reset a builtin suite to factory contents (shows a diff) and exit\":\n\t\t\"将内置 suite 重置为出厂内容(显示 diff)并退出\",\n\t\"(Experimental, local trust only) Serve the coding-agent session runtime over the WebSocket gateway (default: 127.0.0.1; HTTP surface: /healthz plus token-protected artifact reads) and exit on SIGINT/SIGTERM\":\n\t\t\"(实验性,仅限本地信任)经 WebSocket 网关提供 coding-agent 会话运行时(默认:127.0.0.1;HTTP 面:/healthz 及受令牌保护的产物读取),SIGINT/SIGTERM 时退出\",\n\t\"Durable journal: <agentDir>/remote-server-journal.jsonl (never the process cwd)\":\n\t\t\"持久日志:<agentDir>/remote-server-journal.jsonl(绝不写入进程 cwd)\",\n\t\"Opt-in --serve boundary: remote creates must run inside one of these roots (repeatable); without it any local directory is allowed\":\n\t\t\"--serve 的可选边界:远程创建必须在这些根目录内运行(可重复);未指定时允许任意本地目录\",\n\t\"(Experimental) Run as a headless subagent runner: serve the subagent-task protocol on stdio for a parent session's runner pool (D-045)\":\n\t\t\"(实验性)作为无头子代理运行器:在 stdio 上为父会话的 runner 池提供 subagent-task 协议(D-045)\",\n\t\"Don't save session (ephemeral)\": \"不保存会话(一次性)\",\n\t\"Set session display name\": \"设置会话显示名称\",\n\t\"Comma-separated model patterns for Ctrl+P cycling\": \"逗号分隔的模型模式,用于 Ctrl+P 轮换\",\n\t\"Supports globs (anthropic/*, *sonnet*) and fuzzy matching\": \"支持 glob(anthropic/*、*sonnet*)与模糊匹配\",\n\t\"Disable all tools by default (built-in and plugin)\": \"默认禁用全部工具(内置与插件)\",\n\t\"Disable built-in tools by default but keep plugin/custom tools enabled\":\n\t\t\"默认禁用内置工具,但保持插件/自定义工具可用\",\n\t\"Comma-separated allowlist of tool names to enable\": \"逗号分隔的工具名白名单\",\n\t\"Applies to built-in, plugin, and custom tools\": \"作用于内置、插件与自定义工具\",\n\t\"Comma-separated denylist of tool names to disable\": \"逗号分隔的工具名黑名单\",\n\t\"Set thinking level: off, minimal, low, medium, high, xhigh, max\":\n\t\t\"设置思考级别:off、minimal、low、medium、high、xhigh、max\",\n\t\"Disable capability plugin discovery (D-028 escape hatch)\": \"禁用能力插件发现(D-028 逃生口)\",\n\t\"Disable session trace collection (no .trace.jsonl file is written)\": \"禁用会话轨迹收集(不写 .trace.jsonl 文件)\",\n\t\"Host log level: debug, info (default), warn, error\": \"宿主日志级别:debug、info(默认)、warn、error\",\n\t\"Select a builtin capability plugin profile for this run\": \"为本次运行选择内置能力插件 profile\",\n\t\"Select a plugin within the profile (repeatable)\": \"在 profile 内选择插件(可重复)\",\n\t\"Disable a plugin within the profile (repeatable)\": \"在 profile 内禁用插件(可重复)\",\n\t\"Read the explicit selection from global or project storage\": \"从全局或项目存储读取显式选择\",\n\t\"List installed/available ecosystem plugins (independent namespace)\": \"列出已安装/可用的生态插件(独立命名空间)\",\n\t\"Load a skill file or directory (can be used multiple times)\": \"加载 skill 文件或目录(可多次使用)\",\n\t\"Disable skills discovery and loading\": \"禁用 skill 发现与加载\",\n\t\"Load a prompt template file or directory (can be used multiple times)\": \"加载提示词模板文件或目录(可多次使用)\",\n\t\"Disable prompt template discovery and loading\": \"禁用提示词模板发现与加载\",\n\t\"Load a theme file or directory (can be used multiple times)\": \"加载主题文件或目录(可多次使用)\",\n\t\"Set the initial interactive theme for this run\": \"设置本次运行的初始交互主题\",\n\t\"Disable theme discovery and loading\": \"禁用主题发现与加载\",\n\t\"Disable AGENTS.md and CLAUDE.md discovery and loading\": \"禁用 AGENTS.md 与 CLAUDE.md 的发现与加载\",\n\t\"Export session file to HTML and exit\": \"将会话文件导出为 HTML 并退出\",\n\t\"View a session trace file as a text timeline and exit; <session> is a session id/prefix or trace/session file path, omit it for the most recent session\":\n\t\t\"以文本时间线查看会话轨迹文件并退出;<session> 为会话 id/前缀或轨迹/会话文件路径,省略则查看最近会话\",\n\t\"With --trace, output the structured trace records as JSON instead of the text timeline\":\n\t\t\"配合 --trace,以 JSON 输出结构化轨迹记录,而非文本时间线\",\n\t\"With --trace, show only records of these kinds (comma-separated); valid kinds: {kinds}\":\n\t\t\"配合 --trace,只显示这些类型的记录(逗号分隔);有效类型:{kinds}\",\n\t\"With --trace, show only the last N records (positive integer)\": \"配合 --trace,只显示最后 N 条记录(正整数)\",\n\t\"List available models (with optional fuzzy search)\": \"列出可用模型(可选模糊搜索)\",\n\t\"Force verbose startup (overrides quietStartup setting)\": \"强制详细启动(覆盖 quietStartup 设置)\",\n\t\"TUI mode: regular (default) or fullscreen\": \"TUI 模式:regular(默认)或 fullscreen\",\n\t\"Disable startup network operations (same as AGENT_FORGE_OFFLINE=1)\":\n\t\t\"禁用启动网络操作(等同 AGENT_FORGE_OFFLINE=1)\",\n\t\"End option parsing; treat remaining arguments as messages/files\": \"结束选项解析;剩余参数视为消息/文件\",\n\t\"Show this help\": \"显示此帮助\",\n\t\"Show version number\": \"显示版本号\",\n\n\t// --- args.ts:printHelp Examples 注释 ---\n\t\"Print a provider API key for an external client\": \"为外部客户端打印提供商 API key\",\n\t\"Print an OAuth bearer token for an external client (refreshes if expired)\":\n\t\t\"为外部客户端打印 OAuth bearer token(过期则刷新)\",\n\t\"Interactive mode\": \"交互模式\",\n\t\"Interactive mode with initial prompt\": \"带初始提示的交互模式\",\n\t\"Include files in initial message\": \"在初始消息中包含文件\",\n\t\"Non-interactive mode (process and exit)\": \"非交互模式(处理后退出)\",\n\t\"Prompt beginning with a dash\": \"以连字符开头的提示\",\n\t\"Multiple messages (interactive)\": \"多条消息(交互)\",\n\t\"Start a named session\": \"启动命名会话\",\n\t\"Use different model\": \"使用不同模型\",\n\t\"Use model with provider prefix (no --provider needed)\": \"使用带提供商前缀的模型(无需 --provider)\",\n\t\"Use model with thinking level shorthand\": \"使用思考级别简写形式的模型\",\n\t\"Limit model cycling to specific models\": \"将模型轮换限定为指定模型\",\n\t\"Limit to a specific provider with glob pattern\": \"用 glob 模式限定到指定提供商\",\n\t\"Cycle models with fixed thinking levels\": \"以固定思考级别轮换模型\",\n\t\"Start with a specific thinking level\": \"以指定思考级别启动\",\n\t\"Read-only mode (no file modifications possible)\": \"只读模式(不能修改文件)\",\n\t\"Disable one tool while keeping the rest available\": \"禁用单个工具,其余保持可用\",\n\t\"Export a session file to HTML\": \"导出会话文件为 HTML\",\n\n\t// --- args.ts:printHelp 环境变量描述 ---\n\t\"Anthropic bearer auth token\": \"Anthropic bearer 认证令牌\",\n\t\"Anthropic Claude API key\": \"Anthropic Claude API key\",\n\t\"Anthropic OAuth token (alternative to API key)\": \"Anthropic OAuth 令牌(API key 的替代)\",\n\t\"Ant Ling API key\": \"Ant Ling API key\",\n\t\"OpenAI GPT API key\": \"OpenAI GPT API key\",\n\t\"Azure OpenAI API key\": \"Azure OpenAI API key\",\n\t\"Azure OpenAI/Cognitive Services base URL (e.g. https://{resource}.openai.azure.com)\":\n\t\t\"Azure OpenAI/Cognitive Services base URL(如 https://{resource}.openai.azure.com)\",\n\t\"Azure OpenAI resource name (alternative to base URL)\": \"Azure OpenAI 资源名(base URL 的替代)\",\n\t\"Azure OpenAI API version (default: v1)\": \"Azure OpenAI API 版本(默认:v1)\",\n\t\"Azure OpenAI model=deployment map (comma-separated)\": \"Azure OpenAI 模型=部署映射(逗号分隔)\",\n\t\"DeepSeek API key\": \"DeepSeek API key\",\n\t\"NVIDIA NIM API key\": \"NVIDIA NIM API key\",\n\t\"Google Gemini API key\": \"Google Gemini API key\",\n\t\"Groq API key\": \"Groq API key\",\n\t\"Cerebras API key\": \"Cerebras API key\",\n\t\"xAI Grok API key\": \"xAI Grok API key\",\n\t\"Fireworks API key\": \"Fireworks API key\",\n\t\"Together AI API key\": \"Together AI API key\",\n\t\"Baseten API key\": \"Baseten API key\",\n\t\"OpenRouter API key\": \"OpenRouter API key\",\n\t\"Vercel AI Gateway API key\": \"Vercel AI Gateway API key\",\n\t\"ZAI Coding Plan API key (Global)\": \"ZAI Coding Plan API key(全球区)\",\n\t\"ZAI Coding Plan API key (China)\": \"ZAI Coding Plan API key(中国区)\",\n\t\"Mistral API key\": \"Mistral API key\",\n\t\"MiniMax API key\": \"MiniMax API key\",\n\t\"Moonshot AI API key\": \"Moonshot AI API key\",\n\t\"OpenCode Zen/OpenCode Go API key\": \"OpenCode Zen/OpenCode Go API key\",\n\t\"Kimi For Coding API key\": \"Kimi For Coding API key\",\n\t\"Cloudflare API token (Workers AI and AI Gateway)\": \"Cloudflare API 令牌(Workers AI 与 AI Gateway)\",\n\t\"Cloudflare account id (required for both)\": \"Cloudflare 账户 id(两者均需要)\",\n\t\"Cloudflare AI Gateway slug (required for AI Gateway)\": \"Cloudflare AI Gateway slug(AI Gateway 需要)\",\n\t\"Qwen Token Plan API key (international region)\": \"Qwen Token Plan API key(国际区)\",\n\t\"Qwen Token Plan API key (China region)\": \"Qwen Token Plan API key(中国区)\",\n\t\"Xiaomi MiMo API key (api.xiaomimimo.com billing)\": \"Xiaomi MiMo API key(按 api.xiaomimimo.com 计费)\",\n\t\"Xiaomi MiMo Token Plan API key (China region)\": \"Xiaomi MiMo Token Plan API key(中国区)\",\n\t\"Xiaomi MiMo Token Plan API key (Amsterdam region)\": \"Xiaomi MiMo Token Plan API key(阿姆斯特丹区)\",\n\t\"Xiaomi MiMo Token Plan API key (Singapore region)\": \"Xiaomi MiMo Token Plan API key(新加坡区)\",\n\t\"AWS profile for Amazon Bedrock\": \"Amazon Bedrock 的 AWS profile\",\n\t\"AWS access key for Amazon Bedrock\": \"Amazon Bedrock 的 AWS access key\",\n\t\"AWS secret key for Amazon Bedrock\": \"Amazon Bedrock 的 AWS secret key\",\n\t\"Bedrock API key (bearer token)\": \"Bedrock API key(bearer token)\",\n\t\"AWS region for Amazon Bedrock (e.g., us-east-1)\": \"Amazon Bedrock 的 AWS 区域(如 us-east-1)\",\n\t\"Config directory (default: ~/{configDir}/agent)\": \"配置目录(默认:~/{configDir}/agent)\",\n\t\"Session storage directory (overridden by --session-dir)\": \"会话存储目录(--session-dir 可覆盖)\",\n\t\"Override package directory (for Nix/Guix store paths)\": \"覆盖包目录(用于 Nix/Guix store 路径)\",\n\t\"Disable startup network operations when set to 1/true/yes\": \"设为 1/true/yes 时禁用启动网络操作\",\n\n\t// --- args.ts:printHelp 内置工具描述 ---\n\t\"Read file contents\": \"读取文件内容\",\n\t\"Execute bash commands\": \"执行 bash 命令\",\n\t\"Execute PowerShell commands on Windows\": \"在 Windows 上执行 PowerShell 命令\",\n\t\"Edit files with find/replace\": \"以查找/替换方式编辑文件\",\n\t\"Write files (creates/overwrites)\": \"写文件(创建/覆盖)\",\n\t\"Search file contents (read-only, off by default)\": \"搜索文件内容(只读,默认关闭)\",\n\t\"Find files by glob pattern (read-only, off by default)\": \"按 glob 模式查找文件(只读,默认关闭)\",\n\t\"List directory contents (read-only, off by default)\": \"列出目录内容(只读,默认关闭)\",\n\n\t// --- auth-command.ts:printAuthCommandHelp ---\n\t\"Auth commands require at least one of --provider or --model. Checks refresh expired OAuth credentials by default; --no-refresh prevents this. --credentials emits the credential, or includes it in JSON output. --no-refresh also leaves command-backed keys unresolved: --credentials reports them as unavailable instead of running the command.\":\n\t\t\"auth 命令需要 --provider 或 --model 至少其一。check 默认刷新已过期的 OAuth 凭证;--no-refresh 可阻止。--credentials 输出凭证,或将其包含在 JSON 输出中。--no-refresh 同时不解析命令型 key:--credentials 将其报告为不可用,而不会执行该命令。\",\n\n\t// --- list-models.ts ---\n\t\"Warning: errors loading models.json:\\n{loadError}\": \"警告:加载 models.json 出错:\\n{loadError}\",\n\t'No models matching \"{searchPattern}\"': '没有匹配 \"{searchPattern}\" 的模型',\n\tprovider: \"提供商\",\n\tmodel: \"模型\",\n\tcontext: \"上下文\",\n\t\"max-out\": \"最大输出\",\n\tthinking: \"思考\",\n\timages: \"图像\",\n\n\t// --- print-mode.ts ---\n\t\"{label}: {url}\": \"{label}:{url}\",\n\t\"Request {stopReason}\": \"请求 {stopReason}\",\n\n\t// --- serve.ts ---\n\t\"remote-server error: {error}\": \"remote-server 错误:{error}\",\n\t\"Port {port} is already in use\": \"端口 {port} 已被占用\",\n\t\"Remote server shutdown failed: {error}\": \"远程服务器关闭失败:{error}\",\n\t\"Remote server listening on {addresses}\": \"远程服务器监听于 {addresses}\",\n};\n"]}
|
|
@@ -50,7 +50,8 @@ export const cli = {
|
|
|
50
50
|
"Warning: No project session found with id '{sessionId}'; creating a new session with that id.": "警告:没有找到 id 为 '{sessionId}' 的项目会话;将创建使用该 id 的新会话。",
|
|
51
51
|
// --- main.ts:插件 bootstrap/拒绝 ---
|
|
52
52
|
"Plugin bootstrap {code}: {message}": "插件 bootstrap {code}:{message}",
|
|
53
|
-
"
|
|
53
|
+
"Aligning {count} factory plugin(s) from npm…": "正在从 npm 对齐 {count} 个出厂插件…",
|
|
54
|
+
"{pluginId}: installing…": "{pluginId}:安装中…",
|
|
54
55
|
"{pluginId}: installed {version}": "{pluginId}:已安装 {version}",
|
|
55
56
|
"{pluginId}: install failed ({code}) — startup continues; the next startup retries automatically": "{pluginId}:安装失败({code})——启动继续,下次启动将自动重试",
|
|
56
57
|
"Offline posture (AGENT_FORGE_OFFLINE) skips the startup plugin bootstrap; run `agent-forge plugin install <package>` explicitly to install plugins.": "离线姿态(AGENT_FORGE_OFFLINE)跳过启动插件引导;可用 `agent-forge plugin install <包名>` 显式安装插件。",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../../../src/core/i18n/locales/zh-cn/cli.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * CLI 输出层域词典(docs/design/国际化与本地化.md §3,批次⑤):覆盖\n * main.ts 启动/错误输出、--help(printHelp)、auth help、--list-models、\n * print-mode 的用户可见文案。key 为英文原文,占位符 `{name}` 原样保留。\n * 命令名、flag、路径、环境变量、suite 等代码标识符不译。\n */\nexport const cli: Record<string, string> = {\n\t// --- main.ts:诊断/错误前缀与兜底 ---\n\t\"Error: {message}\": \"错误:{message}\",\n\t\"Warning: {message}\": \"警告:{message}\",\n\t\"Failed to parse auth command\": \"解析 auth 命令失败\",\n\t\"Failed to resolve credential\": \"解析凭证失败\",\n\t\"Failed to export session\": \"导出会话失败\",\n\t\"Exported to: {result}\": \"已导出到:{result}\",\n\n\t// --- main.ts:auth 命令参数错误 ---\n\t'Invalid arguments for \"{command}\".': '\"{command}\" 的参数无效。',\n\t'Use \"{help}\" or \"{usage}\".': '请使用 \"{help}\" 或 \"{usage}\"。',\n\n\t// --- main.ts:suite 生命周期 ---\n\t'Created suite \"{id}\" at {dir}': '已创建 suite \"{id}\",位于 {dir}',\n\t\"Error: --clone-from requires --suite-create\": \"错误:--clone-from 需要与 --suite-create 一起使用\",\n\t'Error: suite \"{id}\" is referenced by {count} existing session(s); deletion refused:':\n\t\t'错误:suite \"{id}\" 被 {count} 个现有会话引用,拒绝删除:',\n\t'Deleting suite \"{id}\": the workspace directory {dir} will be moved to the trash and released.':\n\t\t'正在删除 suite \"{id}\":工作区目录 {dir} 将被移入回收站并释放。',\n\t'Refusing to delete suite \"{id}\" without an interactive confirmation (non-interactive stdin). Re-run in a terminal to confirm.':\n\t\t'拒绝删除 suite \"{id}\":缺少交互式确认(stdin 非交互)。请在终端中重新运行以确认。',\n\t'Delete suite \"{id}\"?': '删除 suite \"{id}\"?',\n\t'Aborted: suite \"{id}\" was not deleted.': '已中止:suite \"{id}\" 未删除。',\n\t'Cleared the {scope} settings \"suite\" key (pointed at \"{id}\").':\n\t\t'已清除 {scope} 设置中的 \"suite\" 键(原指向 \"{id}\")。',\n\t'Deleted suite \"{id}\"; the workspace was moved to {trashPath} and is being released.':\n\t\t'已删除 suite \"{id}\";工作区已移至 {trashPath},正在释放。',\n\t'Suite \"{id}\" is a user suite; only builtin suites can be reset — use --suite-delete instead.':\n\t\t'suite \"{id}\" 是用户 suite;只有内置 suite 可以重置——请改用 --suite-delete。',\n\t'Suite \"{id}\" already matches the factory contents; nothing to reset.': 'suite \"{id}\" 已与出厂内容一致,无需重置。',\n\t'Resetting builtin suite \"{id}\" to the factory contents:': '正在将内置 suite \"{id}\" 重置为出厂内容:',\n\t'Refusing to reset suite \"{id}\" without an interactive confirmation (non-interactive stdin). Review the diff above and re-run in a terminal to confirm.':\n\t\t'拒绝重置 suite \"{id}\":缺少交互式确认(stdin 非交互)。请先查看上方 diff,再在终端中重新运行以确认。',\n\t'Apply reset of suite \"{id}\"?': '应用 suite \"{id}\" 的重置?',\n\t'Aborted: suite \"{id}\" was not reset.': '已中止:suite \"{id}\" 未重置。',\n\t'Suite \"{id}\" was reset to the factory contents (profile lock generation {generation}).':\n\t\t'suite \"{id}\" 已重置为出厂内容(profile lock 代数 {generation})。',\n\n\t// --- main.ts:flag 冲突与模式错误 ---\n\t\"Error: --fork cannot be combined with {flags}\": \"错误:--fork 不能与 {flags} 组合使用\",\n\t\"Error: --session-id cannot be combined with {flags}. To resume that exact session, drop the other flags and use --session-id alone (or use --continue to resume the most recent session).\":\n\t\t\"错误:--session-id 不能与 {flags} 组合使用。要恢复该确切会话,请去掉其他 flag,单独使用 --session-id(或使用 --continue 恢复最近会话)。\",\n\t\"Error: --serve cannot be combined with {flags}\": \"错误:--serve 不能与 {flags} 组合使用\",\n\t\"--serve ignores session/model/tool options: {flags}\": \"--serve 会忽略会话/模型/工具选项:{flags}\",\n\t\"Error: @file arguments are not supported in RPC mode\": \"错误:RPC 模式不支持 @file 参数\",\n\t\"Error: --name requires a non-empty value\": \"错误:--name 需要非空值\",\n\t\"Error: AGENT_FORGE_STARTUP_BENCHMARK only supports interactive mode\":\n\t\t\"错误:AGENT_FORGE_STARTUP_BENCHMARK 仅支持交互模式\",\n\n\t// --- main.ts:会话选择/创建 ---\n\t\"Session already exists with id '{sessionId}'\": \"已存在 id 为 '{sessionId}' 的会话\",\n\t\"No session found matching '{arg}'\": \"没有找到匹配 '{arg}' 的会话\",\n\t\"Session found in different project: {cwd}\": \"会话位于其他项目:{cwd}\",\n\t\"Fork this session into current directory?\": \"将该会话 fork 到当前目录?\",\n\t\"Aborted.\": \"已中止。\",\n\t\"No session selected\": \"未选择会话\",\n\t\"Warning: No project session found with id '{sessionId}'; creating a new session with that id.\":\n\t\t\"警告:没有找到 id 为 '{sessionId}' 的项目会话;将创建使用该 id 的新会话。\",\n\n\t// --- main.ts:插件 bootstrap/拒绝 ---\n\t\"Plugin bootstrap {code}: {message}\": \"插件 bootstrap {code}:{message}\",\n\t\"First run: installing {count} factory plugins…\": \"首次运行:正在安装 {count} 个出厂插件…\",\n\t\"{pluginId}: installed {version}\": \"{pluginId}:已安装 {version}\",\n\t\"{pluginId}: install failed ({code}) — startup continues; the next startup retries automatically\":\n\t\t\"{pluginId}:安装失败({code})——启动继续,下次启动将自动重试\",\n\t\"Offline posture (AGENT_FORGE_OFFLINE) skips the startup plugin bootstrap; run `agent-forge plugin install <package>` explicitly to install plugins.\":\n\t\t\"离线姿态(AGENT_FORGE_OFFLINE)跳过启动插件引导;可用 `agent-forge plugin install <包名>` 显式安装插件。\",\n\t\"Warning: capability plugin rejected ({code}): {target}: {message}\":\n\t\t\"警告:能力插件被拒绝({code}):{target}:{message}\",\n\n\t// --- args.ts:printHelp 节标题与标题行 ---\n\t\"AI coding assistant with read, bash, edit, write tools\": \"具备 read、bash、edit、write 工具的 AI 编程助手\",\n\t\"Usage:\": \"用法:\",\n\t\"Commands:\": \"命令:\",\n\t\"Options:\": \"选项:\",\n\t\"Examples:\": \"示例:\",\n\t\"Environment Variables:\": \"环境变量:\",\n\t\"Built-in Tool Names:\": \"内置工具名:\",\n\n\t// --- args.ts:printHelp Commands 描述 ---\n\t\"Install extension source and add to settings\": \"安装扩展源并加入设置\",\n\t\"Remove extension source from settings\": \"从设置中移除扩展源\",\n\t\"Alias for remove\": \"remove 的别名\",\n\t\"Update Agent Forge, extensions, or model catalogs\": \"更新 Agent Forge、扩展或模型目录\",\n\t\"List installed extensions from settings\": \"列出设置中已安装的扩展\",\n\t\"Open TUI to enable/disable package resources (Tab switches scope)\": \"打开 TUI 启用/禁用包资源(Tab 切换作用域)\",\n\t\"Print credentials or check provider readiness\": \"打印凭证或检查提供商就绪状态\",\n\t\"Show help for install/remove/uninstall/update/list/config/auth\":\n\t\t\"显示 install/remove/uninstall/update/list/config/auth 的帮助\",\n\n\t// --- args.ts:printHelp Options 描述 ---\n\t\"Provider name (default: google)\": \"提供商名称(默认:google)\",\n\t'Model pattern or ID (supports \"provider/id\" and optional \":<thinking>\")':\n\t\t'模型模式或 ID(支持 \"provider/id\" 与可选的 \":<thinking>\")',\n\t\"API key (defaults to env vars)\": \"API key(默认取自环境变量)\",\n\t\"System prompt (default: coding assistant prompt)\": \"系统提示词(默认:编程助手提示词)\",\n\t\"Append text or file contents to the system prompt (can be used multiple times)\":\n\t\t\"向系统提示词追加文本或文件内容(可多次使用)\",\n\t\"Output mode: text (default), json, or rpc\": \"输出模式:text(默认)、json 或 rpc\",\n\t\"Non-interactive mode: process prompt and exit\": \"非交互模式:处理提示后退出\",\n\t\"Continue previous session\": \"继续上一个会话\",\n\t\"Select a session to resume\": \"选择要恢复的会话\",\n\t\"Use specific session file or partial UUID\": \"使用指定会话文件或部分 UUID\",\n\t\"Use exact project session ID, creating it if missing\": \"使用精确的项目会话 ID,不存在则创建\",\n\t\"Fork specific session file or partial UUID into a new session\": \"将指定会话文件或部分 UUID fork 为新会话\",\n\t\"Directory for session storage and lookup\": \"会话存储与查找目录\",\n\t\"Suite (方案) for this run: coding (default) or assistant; new sessions only\":\n\t\t\"本次运行的 suite(方案):coding(默认)或 assistant;仅对新会话生效\",\n\t\"Create a user suite workspace and exit; add --clone-from <id> to copy one\":\n\t\t\"创建用户 suite 工作区并退出;加 --clone-from <id> 可复制既有 suite\",\n\t\"Delete a user suite workspace (active session references refuse) and exit\":\n\t\t\"删除用户 suite 工作区(存在活动会话引用时拒绝)并退出\",\n\t\"Reset a builtin suite to factory contents (shows a diff) and exit\":\n\t\t\"将内置 suite 重置为出厂内容(显示 diff)并退出\",\n\t\"(Experimental, local trust only) Serve the coding-agent session runtime over the WebSocket gateway (default: 127.0.0.1; HTTP surface: /healthz plus token-protected artifact reads) and exit on SIGINT/SIGTERM\":\n\t\t\"(实验性,仅限本地信任)经 WebSocket 网关提供 coding-agent 会话运行时(默认:127.0.0.1;HTTP 面:/healthz 及受令牌保护的产物读取),SIGINT/SIGTERM 时退出\",\n\t\"Durable journal: <agentDir>/remote-server-journal.jsonl (never the process cwd)\":\n\t\t\"持久日志:<agentDir>/remote-server-journal.jsonl(绝不写入进程 cwd)\",\n\t\"Opt-in --serve boundary: remote creates must run inside one of these roots (repeatable); without it any local directory is allowed\":\n\t\t\"--serve 的可选边界:远程创建必须在这些根目录内运行(可重复);未指定时允许任意本地目录\",\n\t\"(Experimental) Run as a headless subagent runner: serve the subagent-task protocol on stdio for a parent session's runner pool (D-045)\":\n\t\t\"(实验性)作为无头子代理运行器:在 stdio 上为父会话的 runner 池提供 subagent-task 协议(D-045)\",\n\t\"Don't save session (ephemeral)\": \"不保存会话(一次性)\",\n\t\"Set session display name\": \"设置会话显示名称\",\n\t\"Comma-separated model patterns for Ctrl+P cycling\": \"逗号分隔的模型模式,用于 Ctrl+P 轮换\",\n\t\"Supports globs (anthropic/*, *sonnet*) and fuzzy matching\": \"支持 glob(anthropic/*、*sonnet*)与模糊匹配\",\n\t\"Disable all tools by default (built-in and plugin)\": \"默认禁用全部工具(内置与插件)\",\n\t\"Disable built-in tools by default but keep plugin/custom tools enabled\":\n\t\t\"默认禁用内置工具,但保持插件/自定义工具可用\",\n\t\"Comma-separated allowlist of tool names to enable\": \"逗号分隔的工具名白名单\",\n\t\"Applies to built-in, plugin, and custom tools\": \"作用于内置、插件与自定义工具\",\n\t\"Comma-separated denylist of tool names to disable\": \"逗号分隔的工具名黑名单\",\n\t\"Set thinking level: off, minimal, low, medium, high, xhigh, max\":\n\t\t\"设置思考级别:off、minimal、low、medium、high、xhigh、max\",\n\t\"Disable capability plugin discovery (D-028 escape hatch)\": \"禁用能力插件发现(D-028 逃生口)\",\n\t\"Disable session trace collection (no .trace.jsonl file is written)\": \"禁用会话轨迹收集(不写 .trace.jsonl 文件)\",\n\t\"Host log level: debug, info (default), warn, error\": \"宿主日志级别:debug、info(默认)、warn、error\",\n\t\"Select a builtin capability plugin profile for this run\": \"为本次运行选择内置能力插件 profile\",\n\t\"Select a plugin within the profile (repeatable)\": \"在 profile 内选择插件(可重复)\",\n\t\"Disable a plugin within the profile (repeatable)\": \"在 profile 内禁用插件(可重复)\",\n\t\"Read the explicit selection from global or project storage\": \"从全局或项目存储读取显式选择\",\n\t\"List installed/available ecosystem plugins (independent namespace)\": \"列出已安装/可用的生态插件(独立命名空间)\",\n\t\"Load a skill file or directory (can be used multiple times)\": \"加载 skill 文件或目录(可多次使用)\",\n\t\"Disable skills discovery and loading\": \"禁用 skill 发现与加载\",\n\t\"Load a prompt template file or directory (can be used multiple times)\": \"加载提示词模板文件或目录(可多次使用)\",\n\t\"Disable prompt template discovery and loading\": \"禁用提示词模板发现与加载\",\n\t\"Load a theme file or directory (can be used multiple times)\": \"加载主题文件或目录(可多次使用)\",\n\t\"Set the initial interactive theme for this run\": \"设置本次运行的初始交互主题\",\n\t\"Disable theme discovery and loading\": \"禁用主题发现与加载\",\n\t\"Disable AGENTS.md and CLAUDE.md discovery and loading\": \"禁用 AGENTS.md 与 CLAUDE.md 的发现与加载\",\n\t\"Export session file to HTML and exit\": \"将会话文件导出为 HTML 并退出\",\n\t\"View a session trace file as a text timeline and exit; <session> is a session id/prefix or trace/session file path, omit it for the most recent session\":\n\t\t\"以文本时间线查看会话轨迹文件并退出;<session> 为会话 id/前缀或轨迹/会话文件路径,省略则查看最近会话\",\n\t\"With --trace, output the structured trace records as JSON instead of the text timeline\":\n\t\t\"配合 --trace,以 JSON 输出结构化轨迹记录,而非文本时间线\",\n\t\"With --trace, show only records of these kinds (comma-separated); valid kinds: {kinds}\":\n\t\t\"配合 --trace,只显示这些类型的记录(逗号分隔);有效类型:{kinds}\",\n\t\"With --trace, show only the last N records (positive integer)\": \"配合 --trace,只显示最后 N 条记录(正整数)\",\n\t\"List available models (with optional fuzzy search)\": \"列出可用模型(可选模糊搜索)\",\n\t\"Force verbose startup (overrides quietStartup setting)\": \"强制详细启动(覆盖 quietStartup 设置)\",\n\t\"TUI mode: regular (default) or fullscreen\": \"TUI 模式:regular(默认)或 fullscreen\",\n\t\"Disable startup network operations (same as AGENT_FORGE_OFFLINE=1)\":\n\t\t\"禁用启动网络操作(等同 AGENT_FORGE_OFFLINE=1)\",\n\t\"End option parsing; treat remaining arguments as messages/files\": \"结束选项解析;剩余参数视为消息/文件\",\n\t\"Show this help\": \"显示此帮助\",\n\t\"Show version number\": \"显示版本号\",\n\n\t// --- args.ts:printHelp Examples 注释 ---\n\t\"Print a provider API key for an external client\": \"为外部客户端打印提供商 API key\",\n\t\"Print an OAuth bearer token for an external client (refreshes if expired)\":\n\t\t\"为外部客户端打印 OAuth bearer token(过期则刷新)\",\n\t\"Interactive mode\": \"交互模式\",\n\t\"Interactive mode with initial prompt\": \"带初始提示的交互模式\",\n\t\"Include files in initial message\": \"在初始消息中包含文件\",\n\t\"Non-interactive mode (process and exit)\": \"非交互模式(处理后退出)\",\n\t\"Prompt beginning with a dash\": \"以连字符开头的提示\",\n\t\"Multiple messages (interactive)\": \"多条消息(交互)\",\n\t\"Start a named session\": \"启动命名会话\",\n\t\"Use different model\": \"使用不同模型\",\n\t\"Use model with provider prefix (no --provider needed)\": \"使用带提供商前缀的模型(无需 --provider)\",\n\t\"Use model with thinking level shorthand\": \"使用思考级别简写形式的模型\",\n\t\"Limit model cycling to specific models\": \"将模型轮换限定为指定模型\",\n\t\"Limit to a specific provider with glob pattern\": \"用 glob 模式限定到指定提供商\",\n\t\"Cycle models with fixed thinking levels\": \"以固定思考级别轮换模型\",\n\t\"Start with a specific thinking level\": \"以指定思考级别启动\",\n\t\"Read-only mode (no file modifications possible)\": \"只读模式(不能修改文件)\",\n\t\"Disable one tool while keeping the rest available\": \"禁用单个工具,其余保持可用\",\n\t\"Export a session file to HTML\": \"导出会话文件为 HTML\",\n\n\t// --- args.ts:printHelp 环境变量描述 ---\n\t\"Anthropic bearer auth token\": \"Anthropic bearer 认证令牌\",\n\t\"Anthropic Claude API key\": \"Anthropic Claude API key\",\n\t\"Anthropic OAuth token (alternative to API key)\": \"Anthropic OAuth 令牌(API key 的替代)\",\n\t\"Ant Ling API key\": \"Ant Ling API key\",\n\t\"OpenAI GPT API key\": \"OpenAI GPT API key\",\n\t\"Azure OpenAI API key\": \"Azure OpenAI API key\",\n\t\"Azure OpenAI/Cognitive Services base URL (e.g. https://{resource}.openai.azure.com)\":\n\t\t\"Azure OpenAI/Cognitive Services base URL(如 https://{resource}.openai.azure.com)\",\n\t\"Azure OpenAI resource name (alternative to base URL)\": \"Azure OpenAI 资源名(base URL 的替代)\",\n\t\"Azure OpenAI API version (default: v1)\": \"Azure OpenAI API 版本(默认:v1)\",\n\t\"Azure OpenAI model=deployment map (comma-separated)\": \"Azure OpenAI 模型=部署映射(逗号分隔)\",\n\t\"DeepSeek API key\": \"DeepSeek API key\",\n\t\"NVIDIA NIM API key\": \"NVIDIA NIM API key\",\n\t\"Google Gemini API key\": \"Google Gemini API key\",\n\t\"Groq API key\": \"Groq API key\",\n\t\"Cerebras API key\": \"Cerebras API key\",\n\t\"xAI Grok API key\": \"xAI Grok API key\",\n\t\"Fireworks API key\": \"Fireworks API key\",\n\t\"Together AI API key\": \"Together AI API key\",\n\t\"Baseten API key\": \"Baseten API key\",\n\t\"OpenRouter API key\": \"OpenRouter API key\",\n\t\"Vercel AI Gateway API key\": \"Vercel AI Gateway API key\",\n\t\"ZAI Coding Plan API key (Global)\": \"ZAI Coding Plan API key(全球区)\",\n\t\"ZAI Coding Plan API key (China)\": \"ZAI Coding Plan API key(中国区)\",\n\t\"Mistral API key\": \"Mistral API key\",\n\t\"MiniMax API key\": \"MiniMax API key\",\n\t\"Moonshot AI API key\": \"Moonshot AI API key\",\n\t\"OpenCode Zen/OpenCode Go API key\": \"OpenCode Zen/OpenCode Go API key\",\n\t\"Kimi For Coding API key\": \"Kimi For Coding API key\",\n\t\"Cloudflare API token (Workers AI and AI Gateway)\": \"Cloudflare API 令牌(Workers AI 与 AI Gateway)\",\n\t\"Cloudflare account id (required for both)\": \"Cloudflare 账户 id(两者均需要)\",\n\t\"Cloudflare AI Gateway slug (required for AI Gateway)\": \"Cloudflare AI Gateway slug(AI Gateway 需要)\",\n\t\"Qwen Token Plan API key (international region)\": \"Qwen Token Plan API key(国际区)\",\n\t\"Qwen Token Plan API key (China region)\": \"Qwen Token Plan API key(中国区)\",\n\t\"Xiaomi MiMo API key (api.xiaomimimo.com billing)\": \"Xiaomi MiMo API key(按 api.xiaomimimo.com 计费)\",\n\t\"Xiaomi MiMo Token Plan API key (China region)\": \"Xiaomi MiMo Token Plan API key(中国区)\",\n\t\"Xiaomi MiMo Token Plan API key (Amsterdam region)\": \"Xiaomi MiMo Token Plan API key(阿姆斯特丹区)\",\n\t\"Xiaomi MiMo Token Plan API key (Singapore region)\": \"Xiaomi MiMo Token Plan API key(新加坡区)\",\n\t\"AWS profile for Amazon Bedrock\": \"Amazon Bedrock 的 AWS profile\",\n\t\"AWS access key for Amazon Bedrock\": \"Amazon Bedrock 的 AWS access key\",\n\t\"AWS secret key for Amazon Bedrock\": \"Amazon Bedrock 的 AWS secret key\",\n\t\"Bedrock API key (bearer token)\": \"Bedrock API key(bearer token)\",\n\t\"AWS region for Amazon Bedrock (e.g., us-east-1)\": \"Amazon Bedrock 的 AWS 区域(如 us-east-1)\",\n\t\"Config directory (default: ~/{configDir}/agent)\": \"配置目录(默认:~/{configDir}/agent)\",\n\t\"Session storage directory (overridden by --session-dir)\": \"会话存储目录(--session-dir 可覆盖)\",\n\t\"Override package directory (for Nix/Guix store paths)\": \"覆盖包目录(用于 Nix/Guix store 路径)\",\n\t\"Disable startup network operations when set to 1/true/yes\": \"设为 1/true/yes 时禁用启动网络操作\",\n\n\t// --- args.ts:printHelp 内置工具描述 ---\n\t\"Read file contents\": \"读取文件内容\",\n\t\"Execute bash commands\": \"执行 bash 命令\",\n\t\"Execute PowerShell commands on Windows\": \"在 Windows 上执行 PowerShell 命令\",\n\t\"Edit files with find/replace\": \"以查找/替换方式编辑文件\",\n\t\"Write files (creates/overwrites)\": \"写文件(创建/覆盖)\",\n\t\"Search file contents (read-only, off by default)\": \"搜索文件内容(只读,默认关闭)\",\n\t\"Find files by glob pattern (read-only, off by default)\": \"按 glob 模式查找文件(只读,默认关闭)\",\n\t\"List directory contents (read-only, off by default)\": \"列出目录内容(只读,默认关闭)\",\n\n\t// --- auth-command.ts:printAuthCommandHelp ---\n\t\"Auth commands require at least one of --provider or --model. Checks refresh expired OAuth credentials by default; --no-refresh prevents this. --credentials emits the credential, or includes it in JSON output. --no-refresh also leaves command-backed keys unresolved: --credentials reports them as unavailable instead of running the command.\":\n\t\t\"auth 命令需要 --provider 或 --model 至少其一。check 默认刷新已过期的 OAuth 凭证;--no-refresh 可阻止。--credentials 输出凭证,或将其包含在 JSON 输出中。--no-refresh 同时不解析命令型 key:--credentials 将其报告为不可用,而不会执行该命令。\",\n\n\t// --- list-models.ts ---\n\t\"Warning: errors loading models.json:\\n{loadError}\": \"警告:加载 models.json 出错:\\n{loadError}\",\n\t'No models matching \"{searchPattern}\"': '没有匹配 \"{searchPattern}\" 的模型',\n\tprovider: \"提供商\",\n\tmodel: \"模型\",\n\tcontext: \"上下文\",\n\t\"max-out\": \"最大输出\",\n\tthinking: \"思考\",\n\timages: \"图像\",\n\n\t// --- print-mode.ts ---\n\t\"{label}: {url}\": \"{label}:{url}\",\n\t\"Request {stopReason}\": \"请求 {stopReason}\",\n\n\t// --- serve.ts ---\n\t\"remote-server error: {error}\": \"remote-server 错误:{error}\",\n\t\"Port {port} is already in use\": \"端口 {port} 已被占用\",\n\t\"Remote server shutdown failed: {error}\": \"远程服务器关闭失败:{error}\",\n\t\"Remote server listening on {addresses}\": \"远程服务器监听于 {addresses}\",\n};\n"]}
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../../../src/core/i18n/locales/zh-cn/cli.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,GAAG,GAA2B;IAC1C,iDAA6B;IAC7B,kBAAkB,EAAE,oBAAc;IAClC,oBAAoB,EAAE,oBAAc;IACpC,8BAA8B,EAAE,0BAAc;IAC9C,8BAA8B,EAAE,oBAAQ;IACxC,0BAA0B,EAAE,oBAAQ;IACpC,uBAAuB,EAAE,yBAAe;IAExC,4CAA8B;IAC9B,oCAAoC,EAAE,gCAAoB;IAC1D,4BAA4B,EAAE,qCAA2B;IAEzD,uCAA6B;IAC7B,+BAA+B,EAAE,uCAA2B;IAC5D,6CAA6C,EAAE,6DAAyC;IACxF,qFAAqF,EACpF,2EAAyC;IAC1C,+FAA+F,EAC9F,qFAA2C;IAC5C,+HAA+H,EAC9H,kHAAoD;IACrD,sBAAsB,EAAE,wBAAkB;IAC1C,wCAAwC,EAAE,uCAAuB;IACjE,+DAA+D,EAC9D,qEAAyC;IAC1C,qFAAqF,EACpF,2EAA2C;IAC5C,gGAA8F,EAC7F,iGAA6D;IAC9D,sEAAsE,EAAE,yDAA6B;IACrG,yDAAyD,EAAE,uDAA6B;IACxF,wJAAwJ,EACvJ,4IAAgE;IACjE,8BAA8B,EAAE,kCAAsB;IACtD,sCAAsC,EAAE,uCAAuB;IAC/D,wFAAwF,EACvF,gFAAsD;IAEvD,+CAA+B;IAC/B,+CAA+C,EAAE,gDAA4B;IAC7E,2LAA2L,EAC1L,oLAAgG;IACjG,gDAAgD,EAAE,iDAA6B;IAC/E,qDAAqD,EAAE,uDAA+B;IACtF,sDAAsD,EAAE,2CAAuB;IAC/E,0CAA0C,EAAE,iCAAiB;IAC7D,qEAAqE,EACpE,8DAA0C;IAE3C,wCAA0B;IAC1B,8CAA8C,EAAE,0CAA4B;IAC5E,mCAAmC,EAAE,sCAAoB;IACzD,2CAA2C,EAAE,kCAAgB;IAC7D,2CAA2C,EAAE,sCAAkB;IAC/D,UAAU,EAAE,cAAM;IAClB,qBAAqB,EAAE,iBAAO;IAC9B,+FAA+F,EAC9F,oGAAkD;IAEnD,4CAAkC;IAClC,oCAAoC,EAAE,qCAA+B;IACrE,gDAA8C,EAAE,iDAA2B;IAC3E,2BAAyB,EAAE,2BAAiB;IAC5C,iCAAiC,EAAE,kCAA0B;IAC7D,mGAAiG,EAChG,uFAAyC;IAC1C,qJAAqJ,EACpJ,oIAAgF;IACjF,mEAAmE,EAClE,mEAAuC;IAExC,oDAAoC;IACpC,wDAAwD,EAAE,6DAAqC;IAC/F,QAAQ,EAAE,WAAK;IACf,WAAW,EAAE,WAAK;IAClB,UAAU,EAAE,WAAK;IACjB,WAAW,EAAE,WAAK;IAClB,wBAAwB,EAAE,iBAAO;IACjC,sBAAsB,EAAE,oBAAQ;IAEhC,8CAAwC;IACxC,8CAA8C,EAAE,gCAAY;IAC5D,uCAAuC,EAAE,6BAAW;IACpD,kBAAkB,EAAE,kBAAY;IAChC,mDAAmD,EAAE,4CAAwB;IAC7E,yCAAyC,EAAE,mCAAa;IACxD,mEAAmE,EAAE,4DAA4B;IACjG,+CAA+C,EAAE,4CAAgB;IACjE,gEAAgE,EAC/D,mEAAyD;IAE1D,6CAAuC;IACvC,iCAAiC,EAAE,sCAAkB;IACrD,yEAAyE,EACxE,yEAA+C;IAChD,gCAAgC,EAAE,uCAAmB;IACrD,kDAAkD,EAAE,qDAAmB;IACvE,gFAAgF,EAC/E,oEAAwB;IACzB,2CAA2C,EAAE,gDAA0B;IACvE,+CAA+C,EAAE,yCAAe;IAChE,2BAA2B,EAAE,uBAAS;IACtC,4BAA4B,EAAE,0BAAU;IACxC,2CAA2C,EAAE,wCAAkB;IAC/D,sDAAsD,EAAE,qDAAqB;IAC7E,+DAA+D,EAAE,uDAA2B;IAC5F,0CAA0C,EAAE,6BAAW;IACvD,+EAA2E,EAC1E,6FAA+C;IAChD,2EAA2E,EAC1E,qFAAmD;IACpD,2EAA2E,EAC1E,8EAAgC;IACjC,mEAAmE,EAClE,iEAA+B;IAChC,gNAAgN,EAC/M,wMAA8G;IAC/G,iFAAiF,EAChF,mFAAyD;IAC1D,oIAAoI,EACnI,+HAAiD;IAClD,wIAAwI,EACvI,+HAAmE;IACpE,gCAAgC,EAAE,gCAAY;IAC9C,0BAA0B,EAAE,0BAAU;IACtC,mDAAmD,EAAE,oDAAwB;IAC7E,2DAA2D,EAAE,wDAAoC;IACjG,oDAAoD,EAAE,+CAAiB;IACvE,wEAAwE,EACvE,kEAAwB;IACzB,mDAAmD,EAAE,mCAAa;IAClE,+CAA+C,EAAE,4CAAgB;IACjE,mDAAmD,EAAE,mCAAa;IAClE,iEAAiE,EAChE,wEAA8C;IAC/C,0DAA0D,EAAE,+CAAqB;IACjF,oEAAoE,EAAE,0DAA8B;IACpG,oDAAoD,EAAE,8DAAkC;IACxF,yDAAyD,EAAE,iDAAuB;IAClF,iDAAiD,EAAE,4CAAsB;IACzE,kDAAkD,EAAE,4CAAsB;IAC1E,4DAA4D,EAAE,4CAAgB;IAC9E,oEAAoE,EAAE,+DAAuB;IAC7F,6DAA6D,EAAE,mDAAuB;IACtF,sCAAsC,EAAE,8BAAgB;IACxD,uEAAuE,EAAE,2DAAqB;IAC9F,+CAA+C,EAAE,sCAAc;IAC/D,6DAA6D,EAAE,kDAAkB;IACjF,gDAAgD,EAAE,yCAAe;IACjE,qCAAqC,EAAE,6BAAW;IAClD,uDAAuD,EAAE,mDAAiC;IAC1F,sCAAsC,EAAE,yCAAmB;IAC3D,yJAAyJ,EACxJ,+IAA2D;IAC5D,wFAAwF,EACvF,+EAAqC;IACtC,wFAAwF,EACvF,4FAA0C;IAC3C,+DAA+D,EAAE,6DAA6B;IAC9F,oDAAoD,EAAE,4CAAgB;IACtE,wDAAwD,EAAE,oDAA4B;IACtF,2CAA2C,EAAE,gDAAgC;IAC7E,oEAAoE,EACnE,4DAAoC;IACrC,iEAAiE,EAAE,sDAAoB;IACvF,gBAAgB,EAAE,iBAAO;IACzB,qBAAqB,EAAE,iBAAO;IAE9B,8CAAwC;IACxC,iDAAiD,EAAE,2CAAqB;IACxE,2EAA2E,EAC1E,kEAAoC;IACrC,kBAAkB,EAAE,cAAM;IAC1B,sCAAsC,EAAE,gCAAY;IACpD,kCAAkC,EAAE,gCAAY;IAChD,yCAAyC,EAAE,sCAAc;IACzD,8BAA8B,EAAE,6BAAW;IAC3C,iCAAiC,EAAE,0BAAU;IAC7C,uBAAuB,EAAE,oBAAQ;IACjC,qBAAqB,EAAE,oBAAQ;IAC/B,uDAAuD,EAAE,0DAA4B;IACrF,yCAAyC,EAAE,yCAAe;IAC1D,wCAAwC,EAAE,sCAAc;IACxD,gDAAgD,EAAE,yCAAmB;IACrE,yCAAyC,EAAE,mCAAa;IACxD,sCAAsC,EAAE,6BAAW;IACnD,iDAAiD,EAAE,sCAAc;IACjE,mDAAmD,EAAE,yCAAe;IACpE,+BAA+B,EAAE,4BAAc;IAE/C,iDAAmC;IACnC,6BAA6B,EAAE,+BAAuB;IACtD,0BAA0B,EAAE,0BAA0B;IACtD,gDAAgD,EAAE,+CAAiC;IACnF,kBAAkB,EAAE,kBAAkB;IACtC,oBAAoB,EAAE,oBAAoB;IAC1C,sBAAsB,EAAE,sBAAsB;IAC9C,qFAAqF,EACpF,uFAAiF;IAClF,sDAAsD,EAAE,gDAAgC;IACxF,wCAAwC,EAAE,0CAA4B;IACtE,qDAAqD,EAAE,oDAA4B;IACnF,kBAAkB,EAAE,kBAAkB;IACtC,oBAAoB,EAAE,oBAAoB;IAC1C,uBAAuB,EAAE,uBAAuB;IAChD,cAAc,EAAE,cAAc;IAC9B,kBAAkB,EAAE,kBAAkB;IACtC,kBAAkB,EAAE,kBAAkB;IACtC,mBAAmB,EAAE,mBAAmB;IACxC,qBAAqB,EAAE,qBAAqB;IAC5C,iBAAiB,EAAE,iBAAiB;IACpC,oBAAoB,EAAE,oBAAoB;IAC1C,2BAA2B,EAAE,2BAA2B;IACxD,kCAAkC,EAAE,wCAA8B;IAClE,iCAAiC,EAAE,wCAA8B;IACjE,iBAAiB,EAAE,iBAAiB;IACpC,iBAAiB,EAAE,iBAAiB;IACpC,qBAAqB,EAAE,qBAAqB;IAC5C,kCAAkC,EAAE,kCAAkC;IACtE,yBAAyB,EAAE,yBAAyB;IACpD,kDAAkD,EAAE,sDAA4C;IAChG,2CAA2C,EAAE,2CAAyB;IACtE,sDAAsD,EAAE,mDAA2C;IACnG,gDAAgD,EAAE,wCAA8B;IAChF,wCAAwC,EAAE,wCAA8B;IACxE,kDAAkD,EAAE,wDAA8C;IAClG,+CAA+C,EAAE,+CAAqC;IACtF,mDAAmD,EAAE,wDAAwC;IAC7F,mDAAmD,EAAE,kDAAsC;IAC3F,gCAAgC,EAAE,gCAA8B;IAChE,mCAAmC,EAAE,mCAAiC;IACtE,mCAAmC,EAAE,mCAAiC;IACtE,gCAAgC,EAAE,mCAA+B;IACjE,iDAAiD,EAAE,kDAAsC;IACzF,iDAAiD,EAAE,gDAA8B;IACjF,yDAAyD,EAAE,iDAA2B;IACtF,uDAAuD,EAAE,mDAA6B;IACtF,2DAA2D,EAAE,+CAAyB;IAEtF,iDAAmC;IACnC,oBAAoB,EAAE,oBAAQ;IAC9B,uBAAuB,EAAE,oBAAY;IACrC,wCAAwC,EAAE,yCAA6B;IACvE,8BAA8B,EAAE,oCAAc;IAC9C,kCAAkC,EAAE,8BAAY;IAChD,kDAAkD,EAAE,+CAAiB;IACrE,wDAAwD,EAAE,wDAAwB;IAClF,qDAAqD,EAAE,+CAAiB;IAExE,iDAA+C;IAC/C,qVAAqV,EACpV,kTAA4K;IAE7K,yBAAyB;IACzB,mDAAmD,EAAE,oDAAoC;IACzF,sCAAsC,EAAE,0CAA4B;IACpE,QAAQ,EAAE,WAAK;IACf,KAAK,EAAE,QAAI;IACX,OAAO,EAAE,WAAK;IACd,SAAS,EAAE,cAAM;IACjB,QAAQ,EAAE,QAAI;IACd,MAAM,EAAE,QAAI;IAEZ,wBAAwB;IACxB,gBAAgB,EAAE,iBAAe;IACjC,sBAAsB,EAAE,qBAAiB;IAEzC,mBAAmB;IACnB,8BAA8B,EAAE,gCAA0B;IAC1D,+BAA+B,EAAE,4BAAgB;IACjD,wCAAwC,EAAE,uCAAmB;IAC7D,wCAAwC,EAAE,sCAAsB;CAChE,CAAC","sourcesContent":["/**\n * CLI 输出层域词典(docs/design/国际化与本地化.md §3,批次⑤):覆盖\n * main.ts 启动/错误输出、--help(printHelp)、auth help、--list-models、\n * print-mode 的用户可见文案。key 为英文原文,占位符 `{name}` 原样保留。\n * 命令名、flag、路径、环境变量、suite 等代码标识符不译。\n */\nexport const cli: Record<string, string> = {\n\t// --- main.ts:诊断/错误前缀与兜底 ---\n\t\"Error: {message}\": \"错误:{message}\",\n\t\"Warning: {message}\": \"警告:{message}\",\n\t\"Failed to parse auth command\": \"解析 auth 命令失败\",\n\t\"Failed to resolve credential\": \"解析凭证失败\",\n\t\"Failed to export session\": \"导出会话失败\",\n\t\"Exported to: {result}\": \"已导出到:{result}\",\n\n\t// --- main.ts:auth 命令参数错误 ---\n\t'Invalid arguments for \"{command}\".': '\"{command}\" 的参数无效。',\n\t'Use \"{help}\" or \"{usage}\".': '请使用 \"{help}\" 或 \"{usage}\"。',\n\n\t// --- main.ts:suite 生命周期 ---\n\t'Created suite \"{id}\" at {dir}': '已创建 suite \"{id}\",位于 {dir}',\n\t\"Error: --clone-from requires --suite-create\": \"错误:--clone-from 需要与 --suite-create 一起使用\",\n\t'Error: suite \"{id}\" is referenced by {count} existing session(s); deletion refused:':\n\t\t'错误:suite \"{id}\" 被 {count} 个现有会话引用,拒绝删除:',\n\t'Deleting suite \"{id}\": the workspace directory {dir} will be moved to the trash and released.':\n\t\t'正在删除 suite \"{id}\":工作区目录 {dir} 将被移入回收站并释放。',\n\t'Refusing to delete suite \"{id}\" without an interactive confirmation (non-interactive stdin). Re-run in a terminal to confirm.':\n\t\t'拒绝删除 suite \"{id}\":缺少交互式确认(stdin 非交互)。请在终端中重新运行以确认。',\n\t'Delete suite \"{id}\"?': '删除 suite \"{id}\"?',\n\t'Aborted: suite \"{id}\" was not deleted.': '已中止:suite \"{id}\" 未删除。',\n\t'Cleared the {scope} settings \"suite\" key (pointed at \"{id}\").':\n\t\t'已清除 {scope} 设置中的 \"suite\" 键(原指向 \"{id}\")。',\n\t'Deleted suite \"{id}\"; the workspace was moved to {trashPath} and is being released.':\n\t\t'已删除 suite \"{id}\";工作区已移至 {trashPath},正在释放。',\n\t'Suite \"{id}\" is a user suite; only builtin suites can be reset — use --suite-delete instead.':\n\t\t'suite \"{id}\" 是用户 suite;只有内置 suite 可以重置——请改用 --suite-delete。',\n\t'Suite \"{id}\" already matches the factory contents; nothing to reset.': 'suite \"{id}\" 已与出厂内容一致,无需重置。',\n\t'Resetting builtin suite \"{id}\" to the factory contents:': '正在将内置 suite \"{id}\" 重置为出厂内容:',\n\t'Refusing to reset suite \"{id}\" without an interactive confirmation (non-interactive stdin). Review the diff above and re-run in a terminal to confirm.':\n\t\t'拒绝重置 suite \"{id}\":缺少交互式确认(stdin 非交互)。请先查看上方 diff,再在终端中重新运行以确认。',\n\t'Apply reset of suite \"{id}\"?': '应用 suite \"{id}\" 的重置?',\n\t'Aborted: suite \"{id}\" was not reset.': '已中止:suite \"{id}\" 未重置。',\n\t'Suite \"{id}\" was reset to the factory contents (profile lock generation {generation}).':\n\t\t'suite \"{id}\" 已重置为出厂内容(profile lock 代数 {generation})。',\n\n\t// --- main.ts:flag 冲突与模式错误 ---\n\t\"Error: --fork cannot be combined with {flags}\": \"错误:--fork 不能与 {flags} 组合使用\",\n\t\"Error: --session-id cannot be combined with {flags}. To resume that exact session, drop the other flags and use --session-id alone (or use --continue to resume the most recent session).\":\n\t\t\"错误:--session-id 不能与 {flags} 组合使用。要恢复该确切会话,请去掉其他 flag,单独使用 --session-id(或使用 --continue 恢复最近会话)。\",\n\t\"Error: --serve cannot be combined with {flags}\": \"错误:--serve 不能与 {flags} 组合使用\",\n\t\"--serve ignores session/model/tool options: {flags}\": \"--serve 会忽略会话/模型/工具选项:{flags}\",\n\t\"Error: @file arguments are not supported in RPC mode\": \"错误:RPC 模式不支持 @file 参数\",\n\t\"Error: --name requires a non-empty value\": \"错误:--name 需要非空值\",\n\t\"Error: AGENT_FORGE_STARTUP_BENCHMARK only supports interactive mode\":\n\t\t\"错误:AGENT_FORGE_STARTUP_BENCHMARK 仅支持交互模式\",\n\n\t// --- main.ts:会话选择/创建 ---\n\t\"Session already exists with id '{sessionId}'\": \"已存在 id 为 '{sessionId}' 的会话\",\n\t\"No session found matching '{arg}'\": \"没有找到匹配 '{arg}' 的会话\",\n\t\"Session found in different project: {cwd}\": \"会话位于其他项目:{cwd}\",\n\t\"Fork this session into current directory?\": \"将该会话 fork 到当前目录?\",\n\t\"Aborted.\": \"已中止。\",\n\t\"No session selected\": \"未选择会话\",\n\t\"Warning: No project session found with id '{sessionId}'; creating a new session with that id.\":\n\t\t\"警告:没有找到 id 为 '{sessionId}' 的项目会话;将创建使用该 id 的新会话。\",\n\n\t// --- main.ts:插件 bootstrap/拒绝 ---\n\t\"Plugin bootstrap {code}: {message}\": \"插件 bootstrap {code}:{message}\",\n\t\"Aligning {count} factory plugin(s) from npm…\": \"正在从 npm 对齐 {count} 个出厂插件…\",\n\t\"{pluginId}: installing…\": \"{pluginId}:安装中…\",\n\t\"{pluginId}: installed {version}\": \"{pluginId}:已安装 {version}\",\n\t\"{pluginId}: install failed ({code}) — startup continues; the next startup retries automatically\":\n\t\t\"{pluginId}:安装失败({code})——启动继续,下次启动将自动重试\",\n\t\"Offline posture (AGENT_FORGE_OFFLINE) skips the startup plugin bootstrap; run `agent-forge plugin install <package>` explicitly to install plugins.\":\n\t\t\"离线姿态(AGENT_FORGE_OFFLINE)跳过启动插件引导;可用 `agent-forge plugin install <包名>` 显式安装插件。\",\n\t\"Warning: capability plugin rejected ({code}): {target}: {message}\":\n\t\t\"警告:能力插件被拒绝({code}):{target}:{message}\",\n\n\t// --- args.ts:printHelp 节标题与标题行 ---\n\t\"AI coding assistant with read, bash, edit, write tools\": \"具备 read、bash、edit、write 工具的 AI 编程助手\",\n\t\"Usage:\": \"用法:\",\n\t\"Commands:\": \"命令:\",\n\t\"Options:\": \"选项:\",\n\t\"Examples:\": \"示例:\",\n\t\"Environment Variables:\": \"环境变量:\",\n\t\"Built-in Tool Names:\": \"内置工具名:\",\n\n\t// --- args.ts:printHelp Commands 描述 ---\n\t\"Install extension source and add to settings\": \"安装扩展源并加入设置\",\n\t\"Remove extension source from settings\": \"从设置中移除扩展源\",\n\t\"Alias for remove\": \"remove 的别名\",\n\t\"Update Agent Forge, extensions, or model catalogs\": \"更新 Agent Forge、扩展或模型目录\",\n\t\"List installed extensions from settings\": \"列出设置中已安装的扩展\",\n\t\"Open TUI to enable/disable package resources (Tab switches scope)\": \"打开 TUI 启用/禁用包资源(Tab 切换作用域)\",\n\t\"Print credentials or check provider readiness\": \"打印凭证或检查提供商就绪状态\",\n\t\"Show help for install/remove/uninstall/update/list/config/auth\":\n\t\t\"显示 install/remove/uninstall/update/list/config/auth 的帮助\",\n\n\t// --- args.ts:printHelp Options 描述 ---\n\t\"Provider name (default: google)\": \"提供商名称(默认:google)\",\n\t'Model pattern or ID (supports \"provider/id\" and optional \":<thinking>\")':\n\t\t'模型模式或 ID(支持 \"provider/id\" 与可选的 \":<thinking>\")',\n\t\"API key (defaults to env vars)\": \"API key(默认取自环境变量)\",\n\t\"System prompt (default: coding assistant prompt)\": \"系统提示词(默认:编程助手提示词)\",\n\t\"Append text or file contents to the system prompt (can be used multiple times)\":\n\t\t\"向系统提示词追加文本或文件内容(可多次使用)\",\n\t\"Output mode: text (default), json, or rpc\": \"输出模式:text(默认)、json 或 rpc\",\n\t\"Non-interactive mode: process prompt and exit\": \"非交互模式:处理提示后退出\",\n\t\"Continue previous session\": \"继续上一个会话\",\n\t\"Select a session to resume\": \"选择要恢复的会话\",\n\t\"Use specific session file or partial UUID\": \"使用指定会话文件或部分 UUID\",\n\t\"Use exact project session ID, creating it if missing\": \"使用精确的项目会话 ID,不存在则创建\",\n\t\"Fork specific session file or partial UUID into a new session\": \"将指定会话文件或部分 UUID fork 为新会话\",\n\t\"Directory for session storage and lookup\": \"会话存储与查找目录\",\n\t\"Suite (方案) for this run: coding (default) or assistant; new sessions only\":\n\t\t\"本次运行的 suite(方案):coding(默认)或 assistant;仅对新会话生效\",\n\t\"Create a user suite workspace and exit; add --clone-from <id> to copy one\":\n\t\t\"创建用户 suite 工作区并退出;加 --clone-from <id> 可复制既有 suite\",\n\t\"Delete a user suite workspace (active session references refuse) and exit\":\n\t\t\"删除用户 suite 工作区(存在活动会话引用时拒绝)并退出\",\n\t\"Reset a builtin suite to factory contents (shows a diff) and exit\":\n\t\t\"将内置 suite 重置为出厂内容(显示 diff)并退出\",\n\t\"(Experimental, local trust only) Serve the coding-agent session runtime over the WebSocket gateway (default: 127.0.0.1; HTTP surface: /healthz plus token-protected artifact reads) and exit on SIGINT/SIGTERM\":\n\t\t\"(实验性,仅限本地信任)经 WebSocket 网关提供 coding-agent 会话运行时(默认:127.0.0.1;HTTP 面:/healthz 及受令牌保护的产物读取),SIGINT/SIGTERM 时退出\",\n\t\"Durable journal: <agentDir>/remote-server-journal.jsonl (never the process cwd)\":\n\t\t\"持久日志:<agentDir>/remote-server-journal.jsonl(绝不写入进程 cwd)\",\n\t\"Opt-in --serve boundary: remote creates must run inside one of these roots (repeatable); without it any local directory is allowed\":\n\t\t\"--serve 的可选边界:远程创建必须在这些根目录内运行(可重复);未指定时允许任意本地目录\",\n\t\"(Experimental) Run as a headless subagent runner: serve the subagent-task protocol on stdio for a parent session's runner pool (D-045)\":\n\t\t\"(实验性)作为无头子代理运行器:在 stdio 上为父会话的 runner 池提供 subagent-task 协议(D-045)\",\n\t\"Don't save session (ephemeral)\": \"不保存会话(一次性)\",\n\t\"Set session display name\": \"设置会话显示名称\",\n\t\"Comma-separated model patterns for Ctrl+P cycling\": \"逗号分隔的模型模式,用于 Ctrl+P 轮换\",\n\t\"Supports globs (anthropic/*, *sonnet*) and fuzzy matching\": \"支持 glob(anthropic/*、*sonnet*)与模糊匹配\",\n\t\"Disable all tools by default (built-in and plugin)\": \"默认禁用全部工具(内置与插件)\",\n\t\"Disable built-in tools by default but keep plugin/custom tools enabled\":\n\t\t\"默认禁用内置工具,但保持插件/自定义工具可用\",\n\t\"Comma-separated allowlist of tool names to enable\": \"逗号分隔的工具名白名单\",\n\t\"Applies to built-in, plugin, and custom tools\": \"作用于内置、插件与自定义工具\",\n\t\"Comma-separated denylist of tool names to disable\": \"逗号分隔的工具名黑名单\",\n\t\"Set thinking level: off, minimal, low, medium, high, xhigh, max\":\n\t\t\"设置思考级别:off、minimal、low、medium、high、xhigh、max\",\n\t\"Disable capability plugin discovery (D-028 escape hatch)\": \"禁用能力插件发现(D-028 逃生口)\",\n\t\"Disable session trace collection (no .trace.jsonl file is written)\": \"禁用会话轨迹收集(不写 .trace.jsonl 文件)\",\n\t\"Host log level: debug, info (default), warn, error\": \"宿主日志级别:debug、info(默认)、warn、error\",\n\t\"Select a builtin capability plugin profile for this run\": \"为本次运行选择内置能力插件 profile\",\n\t\"Select a plugin within the profile (repeatable)\": \"在 profile 内选择插件(可重复)\",\n\t\"Disable a plugin within the profile (repeatable)\": \"在 profile 内禁用插件(可重复)\",\n\t\"Read the explicit selection from global or project storage\": \"从全局或项目存储读取显式选择\",\n\t\"List installed/available ecosystem plugins (independent namespace)\": \"列出已安装/可用的生态插件(独立命名空间)\",\n\t\"Load a skill file or directory (can be used multiple times)\": \"加载 skill 文件或目录(可多次使用)\",\n\t\"Disable skills discovery and loading\": \"禁用 skill 发现与加载\",\n\t\"Load a prompt template file or directory (can be used multiple times)\": \"加载提示词模板文件或目录(可多次使用)\",\n\t\"Disable prompt template discovery and loading\": \"禁用提示词模板发现与加载\",\n\t\"Load a theme file or directory (can be used multiple times)\": \"加载主题文件或目录(可多次使用)\",\n\t\"Set the initial interactive theme for this run\": \"设置本次运行的初始交互主题\",\n\t\"Disable theme discovery and loading\": \"禁用主题发现与加载\",\n\t\"Disable AGENTS.md and CLAUDE.md discovery and loading\": \"禁用 AGENTS.md 与 CLAUDE.md 的发现与加载\",\n\t\"Export session file to HTML and exit\": \"将会话文件导出为 HTML 并退出\",\n\t\"View a session trace file as a text timeline and exit; <session> is a session id/prefix or trace/session file path, omit it for the most recent session\":\n\t\t\"以文本时间线查看会话轨迹文件并退出;<session> 为会话 id/前缀或轨迹/会话文件路径,省略则查看最近会话\",\n\t\"With --trace, output the structured trace records as JSON instead of the text timeline\":\n\t\t\"配合 --trace,以 JSON 输出结构化轨迹记录,而非文本时间线\",\n\t\"With --trace, show only records of these kinds (comma-separated); valid kinds: {kinds}\":\n\t\t\"配合 --trace,只显示这些类型的记录(逗号分隔);有效类型:{kinds}\",\n\t\"With --trace, show only the last N records (positive integer)\": \"配合 --trace,只显示最后 N 条记录(正整数)\",\n\t\"List available models (with optional fuzzy search)\": \"列出可用模型(可选模糊搜索)\",\n\t\"Force verbose startup (overrides quietStartup setting)\": \"强制详细启动(覆盖 quietStartup 设置)\",\n\t\"TUI mode: regular (default) or fullscreen\": \"TUI 模式:regular(默认)或 fullscreen\",\n\t\"Disable startup network operations (same as AGENT_FORGE_OFFLINE=1)\":\n\t\t\"禁用启动网络操作(等同 AGENT_FORGE_OFFLINE=1)\",\n\t\"End option parsing; treat remaining arguments as messages/files\": \"结束选项解析;剩余参数视为消息/文件\",\n\t\"Show this help\": \"显示此帮助\",\n\t\"Show version number\": \"显示版本号\",\n\n\t// --- args.ts:printHelp Examples 注释 ---\n\t\"Print a provider API key for an external client\": \"为外部客户端打印提供商 API key\",\n\t\"Print an OAuth bearer token for an external client (refreshes if expired)\":\n\t\t\"为外部客户端打印 OAuth bearer token(过期则刷新)\",\n\t\"Interactive mode\": \"交互模式\",\n\t\"Interactive mode with initial prompt\": \"带初始提示的交互模式\",\n\t\"Include files in initial message\": \"在初始消息中包含文件\",\n\t\"Non-interactive mode (process and exit)\": \"非交互模式(处理后退出)\",\n\t\"Prompt beginning with a dash\": \"以连字符开头的提示\",\n\t\"Multiple messages (interactive)\": \"多条消息(交互)\",\n\t\"Start a named session\": \"启动命名会话\",\n\t\"Use different model\": \"使用不同模型\",\n\t\"Use model with provider prefix (no --provider needed)\": \"使用带提供商前缀的模型(无需 --provider)\",\n\t\"Use model with thinking level shorthand\": \"使用思考级别简写形式的模型\",\n\t\"Limit model cycling to specific models\": \"将模型轮换限定为指定模型\",\n\t\"Limit to a specific provider with glob pattern\": \"用 glob 模式限定到指定提供商\",\n\t\"Cycle models with fixed thinking levels\": \"以固定思考级别轮换模型\",\n\t\"Start with a specific thinking level\": \"以指定思考级别启动\",\n\t\"Read-only mode (no file modifications possible)\": \"只读模式(不能修改文件)\",\n\t\"Disable one tool while keeping the rest available\": \"禁用单个工具,其余保持可用\",\n\t\"Export a session file to HTML\": \"导出会话文件为 HTML\",\n\n\t// --- args.ts:printHelp 环境变量描述 ---\n\t\"Anthropic bearer auth token\": \"Anthropic bearer 认证令牌\",\n\t\"Anthropic Claude API key\": \"Anthropic Claude API key\",\n\t\"Anthropic OAuth token (alternative to API key)\": \"Anthropic OAuth 令牌(API key 的替代)\",\n\t\"Ant Ling API key\": \"Ant Ling API key\",\n\t\"OpenAI GPT API key\": \"OpenAI GPT API key\",\n\t\"Azure OpenAI API key\": \"Azure OpenAI API key\",\n\t\"Azure OpenAI/Cognitive Services base URL (e.g. https://{resource}.openai.azure.com)\":\n\t\t\"Azure OpenAI/Cognitive Services base URL(如 https://{resource}.openai.azure.com)\",\n\t\"Azure OpenAI resource name (alternative to base URL)\": \"Azure OpenAI 资源名(base URL 的替代)\",\n\t\"Azure OpenAI API version (default: v1)\": \"Azure OpenAI API 版本(默认:v1)\",\n\t\"Azure OpenAI model=deployment map (comma-separated)\": \"Azure OpenAI 模型=部署映射(逗号分隔)\",\n\t\"DeepSeek API key\": \"DeepSeek API key\",\n\t\"NVIDIA NIM API key\": \"NVIDIA NIM API key\",\n\t\"Google Gemini API key\": \"Google Gemini API key\",\n\t\"Groq API key\": \"Groq API key\",\n\t\"Cerebras API key\": \"Cerebras API key\",\n\t\"xAI Grok API key\": \"xAI Grok API key\",\n\t\"Fireworks API key\": \"Fireworks API key\",\n\t\"Together AI API key\": \"Together AI API key\",\n\t\"Baseten API key\": \"Baseten API key\",\n\t\"OpenRouter API key\": \"OpenRouter API key\",\n\t\"Vercel AI Gateway API key\": \"Vercel AI Gateway API key\",\n\t\"ZAI Coding Plan API key (Global)\": \"ZAI Coding Plan API key(全球区)\",\n\t\"ZAI Coding Plan API key (China)\": \"ZAI Coding Plan API key(中国区)\",\n\t\"Mistral API key\": \"Mistral API key\",\n\t\"MiniMax API key\": \"MiniMax API key\",\n\t\"Moonshot AI API key\": \"Moonshot AI API key\",\n\t\"OpenCode Zen/OpenCode Go API key\": \"OpenCode Zen/OpenCode Go API key\",\n\t\"Kimi For Coding API key\": \"Kimi For Coding API key\",\n\t\"Cloudflare API token (Workers AI and AI Gateway)\": \"Cloudflare API 令牌(Workers AI 与 AI Gateway)\",\n\t\"Cloudflare account id (required for both)\": \"Cloudflare 账户 id(两者均需要)\",\n\t\"Cloudflare AI Gateway slug (required for AI Gateway)\": \"Cloudflare AI Gateway slug(AI Gateway 需要)\",\n\t\"Qwen Token Plan API key (international region)\": \"Qwen Token Plan API key(国际区)\",\n\t\"Qwen Token Plan API key (China region)\": \"Qwen Token Plan API key(中国区)\",\n\t\"Xiaomi MiMo API key (api.xiaomimimo.com billing)\": \"Xiaomi MiMo API key(按 api.xiaomimimo.com 计费)\",\n\t\"Xiaomi MiMo Token Plan API key (China region)\": \"Xiaomi MiMo Token Plan API key(中国区)\",\n\t\"Xiaomi MiMo Token Plan API key (Amsterdam region)\": \"Xiaomi MiMo Token Plan API key(阿姆斯特丹区)\",\n\t\"Xiaomi MiMo Token Plan API key (Singapore region)\": \"Xiaomi MiMo Token Plan API key(新加坡区)\",\n\t\"AWS profile for Amazon Bedrock\": \"Amazon Bedrock 的 AWS profile\",\n\t\"AWS access key for Amazon Bedrock\": \"Amazon Bedrock 的 AWS access key\",\n\t\"AWS secret key for Amazon Bedrock\": \"Amazon Bedrock 的 AWS secret key\",\n\t\"Bedrock API key (bearer token)\": \"Bedrock API key(bearer token)\",\n\t\"AWS region for Amazon Bedrock (e.g., us-east-1)\": \"Amazon Bedrock 的 AWS 区域(如 us-east-1)\",\n\t\"Config directory (default: ~/{configDir}/agent)\": \"配置目录(默认:~/{configDir}/agent)\",\n\t\"Session storage directory (overridden by --session-dir)\": \"会话存储目录(--session-dir 可覆盖)\",\n\t\"Override package directory (for Nix/Guix store paths)\": \"覆盖包目录(用于 Nix/Guix store 路径)\",\n\t\"Disable startup network operations when set to 1/true/yes\": \"设为 1/true/yes 时禁用启动网络操作\",\n\n\t// --- args.ts:printHelp 内置工具描述 ---\n\t\"Read file contents\": \"读取文件内容\",\n\t\"Execute bash commands\": \"执行 bash 命令\",\n\t\"Execute PowerShell commands on Windows\": \"在 Windows 上执行 PowerShell 命令\",\n\t\"Edit files with find/replace\": \"以查找/替换方式编辑文件\",\n\t\"Write files (creates/overwrites)\": \"写文件(创建/覆盖)\",\n\t\"Search file contents (read-only, off by default)\": \"搜索文件内容(只读,默认关闭)\",\n\t\"Find files by glob pattern (read-only, off by default)\": \"按 glob 模式查找文件(只读,默认关闭)\",\n\t\"List directory contents (read-only, off by default)\": \"列出目录内容(只读,默认关闭)\",\n\n\t// --- auth-command.ts:printAuthCommandHelp ---\n\t\"Auth commands require at least one of --provider or --model. Checks refresh expired OAuth credentials by default; --no-refresh prevents this. --credentials emits the credential, or includes it in JSON output. --no-refresh also leaves command-backed keys unresolved: --credentials reports them as unavailable instead of running the command.\":\n\t\t\"auth 命令需要 --provider 或 --model 至少其一。check 默认刷新已过期的 OAuth 凭证;--no-refresh 可阻止。--credentials 输出凭证,或将其包含在 JSON 输出中。--no-refresh 同时不解析命令型 key:--credentials 将其报告为不可用,而不会执行该命令。\",\n\n\t// --- list-models.ts ---\n\t\"Warning: errors loading models.json:\\n{loadError}\": \"警告:加载 models.json 出错:\\n{loadError}\",\n\t'No models matching \"{searchPattern}\"': '没有匹配 \"{searchPattern}\" 的模型',\n\tprovider: \"提供商\",\n\tmodel: \"模型\",\n\tcontext: \"上下文\",\n\t\"max-out\": \"最大输出\",\n\tthinking: \"思考\",\n\timages: \"图像\",\n\n\t// --- print-mode.ts ---\n\t\"{label}: {url}\": \"{label}:{url}\",\n\t\"Request {stopReason}\": \"请求 {stopReason}\",\n\n\t// --- serve.ts ---\n\t\"remote-server error: {error}\": \"remote-server 错误:{error}\",\n\t\"Port {port} is already in use\": \"端口 {port} 已被占用\",\n\t\"Remote server shutdown failed: {error}\": \"远程服务器关闭失败:{error}\",\n\t\"Remote server listening on {addresses}\": \"远程服务器监听于 {addresses}\",\n};\n"]}
|
|
@@ -11,7 +11,7 @@ export interface PluginCatalogSnapshotV1 {
|
|
|
11
11
|
readonly entries: readonly PluginCatalogEntryV1[];
|
|
12
12
|
readonly truncated: boolean;
|
|
13
13
|
}
|
|
14
|
-
export type PluginCatalogErrorCodeV1 = "
|
|
14
|
+
export type PluginCatalogErrorCodeV1 = "invalid_limit";
|
|
15
15
|
export declare class PluginCatalogErrorV1 extends Error {
|
|
16
16
|
readonly code: PluginCatalogErrorCodeV1;
|
|
17
17
|
constructor(code: PluginCatalogErrorCodeV1, message: string);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/catalog.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGrG,0EAA0E;AAC1E,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;CACxC;AAED,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAC;IAClD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,MAAM,wBAAwB,GAAG,
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/catalog.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGrG,0EAA0E;AAC1E,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;CACxC;AAED,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAC;IAClD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,MAAM,wBAAwB,GAAG,eAAe,CAAC;AAEvD,qBAAa,oBAAqB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IAExC,YAAY,IAAI,EAAE,wBAAwB,EAAE,OAAO,EAAE,MAAM,EAI1D;CACD;AAKD,sFAAsF;AACtF,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAmB3E;AAQD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC3C,QAAQ,CAAC,SAAS,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAChD,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/C,QAAQ,CAAC,qBAAqB,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAC5D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B,GAAG,uBAAuB,CA2C1B;AAED,wBAAgB,wBAAwB,CACvC,QAAQ,EAAE,uBAAuB,EACjC,QAAQ,EAAE,MAAM,EAChB,aAAa,CAAC,EAAE,MAAM,GACpB,oBAAoB,GAAG,SAAS,CAIlC","sourcesContent":["import { VERSION } from \"../../config.ts\";\nimport { t } from \"../../core/i18n/index.ts\";\nimport { resolvePluginCompatibilityV1 } from \"./resolver.ts\";\nimport type { CapabilityRefV1, HostFactsV1, PluginManifestV1, PluginResolutionV1 } from \"./types.ts\";\nimport { pluginManifestDigestV1 } from \"./updates.ts\";\n\n/** A bounded, read-only view consumed by Profile/plugin selection UIs. */\nexport interface PluginCatalogEntryV1 {\n\treadonly pluginId: string;\n\treadonly pluginVersion: string;\n\treadonly manifestDigest: string;\n\treadonly resolution: PluginResolutionV1;\n}\n\nexport interface PluginCatalogSnapshotV1 {\n\treadonly version: 1;\n\treadonly entries: readonly PluginCatalogEntryV1[];\n\treadonly truncated: boolean;\n}\n\nexport type PluginCatalogErrorCodeV1 = \"invalid_limit\";\n\nexport class PluginCatalogErrorV1 extends Error {\n\treadonly code: PluginCatalogErrorCodeV1;\n\n\tconstructor(code: PluginCatalogErrorCodeV1, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"PluginCatalogErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\nconst DEFAULT_MAX_ENTRIES = 128;\nconst MAX_ENTRIES = 256;\n\n/** Compare package versions numerically, with prereleases ordered before releases. */\nexport function comparePluginVersionsV1(left: string, right: string): number {\n\tconst parse = (value: string): (number | string)[] =>\n\t\tvalue\n\t\t\t.trim()\n\t\t\t.replace(/^[vV]/u, \"\")\n\t\t\t.split(/[.+-]/u)\n\t\t\t.map((part) => (/^\\d+$/u.test(part) ? Number.parseInt(part, 10) : part));\n\tconst leftParts = parse(left);\n\tconst rightParts = parse(right);\n\tfor (let index = 0; index < Math.max(leftParts.length, rightParts.length); index += 1) {\n\t\tconst a = leftParts[index] ?? 0;\n\t\tconst b = rightParts[index] ?? 0;\n\t\tif (a === b) continue;\n\t\tif (typeof a === \"number\" && typeof b === \"number\") return a < b ? -1 : 1;\n\t\tif (typeof a === \"number\") return 1;\n\t\tif (typeof b === \"number\") return -1;\n\t\treturn a < b ? -1 : 1;\n\t}\n\treturn 0;\n}\n\nfunction compareCatalogEntries(left: PluginManifestV1, right: PluginManifestV1): number {\n\tconst idOrder = left.id.localeCompare(right.id);\n\tif (idOrder !== 0) return idOrder;\n\treturn comparePluginVersionsV1(right.pluginVersion, left.pluginVersion);\n}\n\n/**\n * Build a deterministic catalog projection without exposing adapter objects,\n * file paths, credentials, or plugin-private state to the main session.\n *\n * The catalog is deliberately a pure snapshot. Installation, integrity\n * verification and activation remain explicit operations (`stage/verify/\n * activatePluginUpdateV1`) owned by a host or installer plugin.\n */\nexport function buildPluginCatalogV1(input: {\n\treadonly manifests: readonly PluginManifestV1[];\n\treadonly host: HostFactsV1;\n\treadonly required?: boolean;\n\treadonly disabledPluginIds?: readonly string[];\n\treadonly availableCapabilities?: readonly CapabilityRefV1[];\n\treadonly maxEntries?: number;\n}): PluginCatalogSnapshotV1 {\n\tconst maxEntries = input.maxEntries ?? DEFAULT_MAX_ENTRIES;\n\tif (!Number.isSafeInteger(maxEntries) || maxEntries < 1 || maxEntries > MAX_ENTRIES) {\n\t\tthrow new PluginCatalogErrorV1(\n\t\t\t\"invalid_limit\",\n\t\t\tt(\"maxEntries must be an integer between 1 and {max}\", { max: MAX_ENTRIES }),\n\t\t);\n\t}\n\n\tconst manifests = [...input.manifests].sort(compareCatalogEntries);\n\tconst seen = new Set<string>();\n\tconst unique: PluginManifestV1[] = [];\n\tfor (const manifest of manifests) {\n\t\tconst identity = `${manifest.id}@${manifest.pluginVersion}`;\n\t\tif (seen.has(identity)) continue;\n\t\tseen.add(identity);\n\t\tunique.push(manifest);\n\t}\n\t// 同一 pluginId@version 的重复实例是安装层的合法形态(installationRef 键控,\n\t// 重装/对齐重试会产生同版本新实例——2026-10-08 实证:升级重放后 index 同身份\n\t// 4 条记录,duplicate 抛错使整个 registry.load 失败、全部绑定\n\t// manifest_unavailable)。同一身份的实例内容一致(同一 tarball、同一 digest),\n\t// 排序后取第一个即可;不再作为错误抛出。\n\tconst disabled = new Set(input.disabledPluginIds ?? []);\n\tconst entries = unique.slice(0, maxEntries).map((manifest): PluginCatalogEntryV1 => {\n\t\tconst resolution = resolvePluginCompatibilityV1({\n\t\t\tmanifest,\n\t\t\thost: input.host,\n\t\t\trequired: input.required,\n\t\t\tdisabled: disabled.has(manifest.id),\n\t\t\tavailableCapabilities: input.availableCapabilities,\n\t\t\t// D-073: catalog snapshots enforce the declared host version range;\n\t\t\t// previously this path skipped the check entirely.\n\t\t\thostVersion: VERSION,\n\t\t});\n\t\treturn Object.freeze({\n\t\t\tpluginId: manifest.id,\n\t\t\tpluginVersion: manifest.pluginVersion,\n\t\t\tmanifestDigest: pluginManifestDigestV1(manifest),\n\t\t\tresolution,\n\t\t});\n\t});\n\treturn Object.freeze({ version: 1, entries: Object.freeze(entries), truncated: manifests.length > maxEntries });\n}\n\nexport function findPluginCatalogEntryV1(\n\tsnapshot: PluginCatalogSnapshotV1,\n\tpluginId: string,\n\tpluginVersion?: string,\n): PluginCatalogEntryV1 | undefined {\n\treturn snapshot.entries.find(\n\t\t(entry) => entry.pluginId === pluginId && (pluginVersion === undefined || entry.pluginVersion === pluginVersion),\n\t);\n}\n"]}
|
|
@@ -57,15 +57,21 @@ export function buildPluginCatalogV1(input) {
|
|
|
57
57
|
}
|
|
58
58
|
const manifests = [...input.manifests].sort(compareCatalogEntries);
|
|
59
59
|
const seen = new Set();
|
|
60
|
+
const unique = [];
|
|
60
61
|
for (const manifest of manifests) {
|
|
61
62
|
const identity = `${manifest.id}@${manifest.pluginVersion}`;
|
|
62
|
-
if (seen.has(identity))
|
|
63
|
-
|
|
64
|
-
}
|
|
63
|
+
if (seen.has(identity))
|
|
64
|
+
continue;
|
|
65
65
|
seen.add(identity);
|
|
66
|
+
unique.push(manifest);
|
|
66
67
|
}
|
|
68
|
+
// 同一 pluginId@version 的重复实例是安装层的合法形态(installationRef 键控,
|
|
69
|
+
// 重装/对齐重试会产生同版本新实例——2026-10-08 实证:升级重放后 index 同身份
|
|
70
|
+
// 4 条记录,duplicate 抛错使整个 registry.load 失败、全部绑定
|
|
71
|
+
// manifest_unavailable)。同一身份的实例内容一致(同一 tarball、同一 digest),
|
|
72
|
+
// 排序后取第一个即可;不再作为错误抛出。
|
|
67
73
|
const disabled = new Set(input.disabledPluginIds ?? []);
|
|
68
|
-
const entries =
|
|
74
|
+
const entries = unique.slice(0, maxEntries).map((manifest) => {
|
|
69
75
|
const resolution = resolvePluginCompatibilityV1({
|
|
70
76
|
manifest,
|
|
71
77
|
host: input.host,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/catalog.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import { VERSION } from \"../../config.ts\";\nimport { t } from \"../../core/i18n/index.ts\";\nimport { resolvePluginCompatibilityV1 } from \"./resolver.ts\";\nimport type { CapabilityRefV1, HostFactsV1, PluginManifestV1, PluginResolutionV1 } from \"./types.ts\";\nimport { pluginManifestDigestV1 } from \"./updates.ts\";\n\n/** A bounded, read-only view consumed by Profile/plugin selection UIs. */\nexport interface PluginCatalogEntryV1 {\n\treadonly pluginId: string;\n\treadonly pluginVersion: string;\n\treadonly manifestDigest: string;\n\treadonly resolution: PluginResolutionV1;\n}\n\nexport interface PluginCatalogSnapshotV1 {\n\treadonly version: 1;\n\treadonly entries: readonly PluginCatalogEntryV1[];\n\treadonly truncated: boolean;\n}\n\nexport type PluginCatalogErrorCodeV1 = \"invalid_limit\";\n\nexport class PluginCatalogErrorV1 extends Error {\n\treadonly code: PluginCatalogErrorCodeV1;\n\n\tconstructor(code: PluginCatalogErrorCodeV1, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"PluginCatalogErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\nconst DEFAULT_MAX_ENTRIES = 128;\nconst MAX_ENTRIES = 256;\n\n/** Compare package versions numerically, with prereleases ordered before releases. */\nexport function comparePluginVersionsV1(left: string, right: string): number {\n\tconst parse = (value: string): (number | string)[] =>\n\t\tvalue\n\t\t\t.trim()\n\t\t\t.replace(/^[vV]/u, \"\")\n\t\t\t.split(/[.+-]/u)\n\t\t\t.map((part) => (/^\\d+$/u.test(part) ? Number.parseInt(part, 10) : part));\n\tconst leftParts = parse(left);\n\tconst rightParts = parse(right);\n\tfor (let index = 0; index < Math.max(leftParts.length, rightParts.length); index += 1) {\n\t\tconst a = leftParts[index] ?? 0;\n\t\tconst b = rightParts[index] ?? 0;\n\t\tif (a === b) continue;\n\t\tif (typeof a === \"number\" && typeof b === \"number\") return a < b ? -1 : 1;\n\t\tif (typeof a === \"number\") return 1;\n\t\tif (typeof b === \"number\") return -1;\n\t\treturn a < b ? -1 : 1;\n\t}\n\treturn 0;\n}\n\nfunction compareCatalogEntries(left: PluginManifestV1, right: PluginManifestV1): number {\n\tconst idOrder = left.id.localeCompare(right.id);\n\tif (idOrder !== 0) return idOrder;\n\treturn comparePluginVersionsV1(right.pluginVersion, left.pluginVersion);\n}\n\n/**\n * Build a deterministic catalog projection without exposing adapter objects,\n * file paths, credentials, or plugin-private state to the main session.\n *\n * The catalog is deliberately a pure snapshot. Installation, integrity\n * verification and activation remain explicit operations (`stage/verify/\n * activatePluginUpdateV1`) owned by a host or installer plugin.\n */\nexport function buildPluginCatalogV1(input: {\n\treadonly manifests: readonly PluginManifestV1[];\n\treadonly host: HostFactsV1;\n\treadonly required?: boolean;\n\treadonly disabledPluginIds?: readonly string[];\n\treadonly availableCapabilities?: readonly CapabilityRefV1[];\n\treadonly maxEntries?: number;\n}): PluginCatalogSnapshotV1 {\n\tconst maxEntries = input.maxEntries ?? DEFAULT_MAX_ENTRIES;\n\tif (!Number.isSafeInteger(maxEntries) || maxEntries < 1 || maxEntries > MAX_ENTRIES) {\n\t\tthrow new PluginCatalogErrorV1(\n\t\t\t\"invalid_limit\",\n\t\t\tt(\"maxEntries must be an integer between 1 and {max}\", { max: MAX_ENTRIES }),\n\t\t);\n\t}\n\n\tconst manifests = [...input.manifests].sort(compareCatalogEntries);\n\tconst seen = new Set<string>();\n\tconst unique: PluginManifestV1[] = [];\n\tfor (const manifest of manifests) {\n\t\tconst identity = `${manifest.id}@${manifest.pluginVersion}`;\n\t\tif (seen.has(identity)) continue;\n\t\tseen.add(identity);\n\t\tunique.push(manifest);\n\t}\n\t// 同一 pluginId@version 的重复实例是安装层的合法形态(installationRef 键控,\n\t// 重装/对齐重试会产生同版本新实例——2026-10-08 实证:升级重放后 index 同身份\n\t// 4 条记录,duplicate 抛错使整个 registry.load 失败、全部绑定\n\t// manifest_unavailable)。同一身份的实例内容一致(同一 tarball、同一 digest),\n\t// 排序后取第一个即可;不再作为错误抛出。\n\tconst disabled = new Set(input.disabledPluginIds ?? []);\n\tconst entries = unique.slice(0, maxEntries).map((manifest): PluginCatalogEntryV1 => {\n\t\tconst resolution = resolvePluginCompatibilityV1({\n\t\t\tmanifest,\n\t\t\thost: input.host,\n\t\t\trequired: input.required,\n\t\t\tdisabled: disabled.has(manifest.id),\n\t\t\tavailableCapabilities: input.availableCapabilities,\n\t\t\t// D-073: catalog snapshots enforce the declared host version range;\n\t\t\t// previously this path skipped the check entirely.\n\t\t\thostVersion: VERSION,\n\t\t});\n\t\treturn Object.freeze({\n\t\t\tpluginId: manifest.id,\n\t\t\tpluginVersion: manifest.pluginVersion,\n\t\t\tmanifestDigest: pluginManifestDigestV1(manifest),\n\t\t\tresolution,\n\t\t});\n\t});\n\treturn Object.freeze({ version: 1, entries: Object.freeze(entries), truncated: manifests.length > maxEntries });\n}\n\nexport function findPluginCatalogEntryV1(\n\tsnapshot: PluginCatalogSnapshotV1,\n\tpluginId: string,\n\tpluginVersion?: string,\n): PluginCatalogEntryV1 | undefined {\n\treturn snapshot.entries.find(\n\t\t(entry) => entry.pluginId === pluginId && (pluginVersion === undefined || entry.pluginVersion === pluginVersion),\n\t);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-disk-registry-source.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-disk-registry-source.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAoC,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAG9F,QAAA,MAAM,oCAAoC,GAAa,CAAC;AACxD,oEAAoE;AACpE,eAAO,MAAM,qCAAqC,QAAc,CAAC;AACjE,+EAA+E;AAC/E,eAAO,MAAM,wCAAwC,QAAY,CAAC;AAClE,6FAA6F;AAC7F,eAAO,MAAM,iCAAiC,MAAM,CAAC;AAOrD,MAAM,MAAM,iCAAiC,GAC1C,WAAW,GACX,uBAAuB,GACvB,eAAe,GACf,kBAAkB,GAClB,mBAAmB,GACnB,kBAAkB,GAClB,WAAW,CAAC;AAEf;;;GAGG;AACH,qBAAa,6BAA8B,SAAQ,KAAK;IACvD,QAAQ,CAAC,IAAI,EAAE,iCAAiC,CAAC;IAEjD,YAAY,IAAI,EAAE,iCAAiC,EAAE,OAAO,EAAE,MAAM,EAInE;CACD;AAED,MAAM,WAAW,+BAA+B;IAC/C,0FAA0F;IAC1F,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,oCAAoC;IACpD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAyB,SAAQ,sBAAsB;IACvE,QAAQ,CAAC,OAAO,EAAE,OAAO,oCAAoC,CAAC;IAC9D;;;;;;OAMG;IACH,QAAQ,CAAC,6BAA6B,CAAC,EAAE,CACxC,KAAK,EAAE,oCAAoC,KACvC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACjC;AA6JD;;;;;;GAMG;AACH,wBAAgB,oCAAoC,CACnD,OAAO,EAAE,+BAA+B,GACtC,wBAAwB,CAqD1B","sourcesContent":["import { open } from \"node:fs/promises\";\nimport { isAbsolute, join } from \"node:path\";\nimport { t } from \"../../core/i18n/index.ts\";\nimport { withinInstallStoreRoot } from \"./install-store-paths.ts\";\nimport type { PluginRegistryManifestEnvelopeV1, PluginRegistrySourceV1 } from \"./registry.ts\";\nimport type { PluginManifestV1 } from \"./types.ts\";\n\nconst NODE_DISK_REGISTRY_SOURCE_VERSION_V1 = 1 as const;\n/** Maximum index.v1.json bytes accepted by this source boundary. */\nexport const MAX_NODE_DISK_REGISTRY_INDEX_BYTES_V1 = 1024 * 1024;\n/** Maximum per-installation agent-forge.json bytes accepted by this source. */\nexport const MAX_NODE_DISK_REGISTRY_MANIFEST_BYTES_V1 = 64 * 1024;\n/** Maximum index records projected by one list() call; matches the registry manifest cap. */\nexport const MAX_NODE_DISK_REGISTRY_RECORDS_V1 = 256;\n\nconst INDEX_FILE_V1 = \"index.v1.json\";\nconst ECOSYSTEM_MANIFEST_FILE_V1 = \"agent-forge.json\";\nconst CAPABILITY_MANIFEST_FILE_V1 = \"plugin.json\";\nconst NODE_PACKAGE_FORMAT_VERSION_V1 = 1;\n\nexport type NodeDiskRegistrySourceErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"invalid_configuration\"\n\t| \"invalid_index\"\n\t| \"invalid_manifest\"\n\t| \"identity_mismatch\"\n\t| \"too_many_records\"\n\t| \"io_failed\";\n\n/**\n * Deliberately does not retain filesystem exceptions or file contents: callers\n * must not turn registry diagnostics into a path or package disclosure.\n */\nexport class NodeDiskRegistrySourceErrorV1 extends Error {\n\treadonly code: NodeDiskRegistrySourceErrorCodeV1;\n\n\tconstructor(code: NodeDiskRegistrySourceErrorCodeV1, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"NodeDiskRegistrySourceErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\nexport interface NodeDiskRegistrySourceOptionsV1 {\n\t/** Absolute host-owned default install store directory. It is never returned in a DTO. */\n\treadonly rootDirectory: string;\n}\n\nexport interface NodeDiskRegistrySourceResolveInputV1 {\n\treadonly pluginId: string;\n\treadonly pluginVersion: string;\n\treadonly signal?: AbortSignal;\n}\n\nexport interface NodeDiskRegistrySourceV1 extends PluginRegistrySourceV1 {\n\treadonly version: typeof NODE_DISK_REGISTRY_SOURCE_VERSION_V1;\n\t/**\n\t * Internal host channel (D-075 S2): absolute `plugin.json` path of the\n\t * installation directory matching `{pluginId, pluginVersion}` in the store\n\t * index, for the sdk's installed-plugin code loading. Registry snapshots\n\t * still carry no paths; undefined means no matching record or the manifest\n\t * file is absent from the installation directory.\n\t */\n\treadonly resolveCapabilityManifestPath?: (\n\t\tinput: NodeDiskRegistrySourceResolveInputV1,\n\t) => Promise<string | undefined>;\n}\n\ninterface DiskIndexRecordV1 {\n\treadonly installationRef: string;\n\treadonly directory: string;\n\treadonly pluginId: string;\n\treadonly pluginVersion: string;\n\treadonly manifestDigest: string;\n\treadonly scope: \"global\" | \"project\";\n\treadonly scopeRef: string;\n\treadonly state: \"installed\" | \"active\" | \"retained\";\n}\n\nconst INDEX_KEYS_V1 = [\n\t\"installationRef\",\n\t\"directory\",\n\t\"pluginId\",\n\t\"pluginVersion\",\n\t\"manifestDigest\",\n\t\"scope\",\n\t\"scopeRef\",\n\t\"state\",\n] as const;\n\nfunction opaqueField(value: unknown, max: number): value is string {\n\treturn (\n\t\ttypeof value === \"string\" &&\n\t\tvalue.length > 0 &&\n\t\tvalue.length <= max &&\n\t\t!/[\\u0000-\\u001f\\u007f]/u.test(value) &&\n\t\t!/\\s/u.test(value) &&\n\t\t!/^(?:file:|[a-z]:[\\\\/]|[\\\\/]{1,2}|\\\\\\\\)/iu.test(value)\n\t);\n}\n\nfunction boundedField(value: unknown, max: number): value is string {\n\treturn typeof value === \"string\" && value.length > 0 && value.length <= max && !/[\\u0000-\\u001f\\u007f]/u.test(value);\n}\n\nfunction validateRecord(root: string, value: unknown, index: number): DiskIndexRecordV1 {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value))\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_index\", t(\"Index record {index} is not an object\", { index }));\n\tconst record = value as Record<string, unknown>;\n\tconst keys = INDEX_KEYS_V1;\n\tif (Object.keys(record).length !== keys.length || keys.some((key) => !(key in record)))\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\n\t\t\t\"invalid_index\",\n\t\t\tt(\"Index record {index} has an invalid schema\", { index }),\n\t\t);\n\tif (\n\t\t!opaqueField(record.installationRef, 2048) ||\n\t\t!boundedField(record.directory, 2048) ||\n\t\t!boundedField(record.pluginId, 256) ||\n\t\t!boundedField(record.pluginVersion, 256) ||\n\t\t!boundedField(record.manifestDigest, 512) ||\n\t\t!opaqueField(record.scopeRef, 2048) ||\n\t\t(record.scope !== \"global\" && record.scope !== \"project\") ||\n\t\t(record.state !== \"installed\" && record.state !== \"active\" && record.state !== \"retained\") ||\n\t\t!withinInstallStoreRoot(root, record.directory)\n\t)\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_index\", t(\"Index record {index} is invalid\", { index }));\n\treturn {\n\t\tinstallationRef: record.installationRef,\n\t\tdirectory: record.directory,\n\t\tpluginId: record.pluginId,\n\t\tpluginVersion: record.pluginVersion,\n\t\tmanifestDigest: record.manifestDigest,\n\t\tscope: record.scope,\n\t\tscopeRef: record.scopeRef,\n\t\tstate: record.state,\n\t};\n}\n\nfunction parseIndex(root: string, raw: string): readonly DiskIndexRecordV1[] {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_index\", t(\"Install store index JSON is invalid\"));\n\t}\n\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed))\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_index\", t(\"Install store index is not an object\"));\n\tconst value = parsed as Record<string, unknown>;\n\tif (\n\t\tObject.keys(value).length !== 2 ||\n\t\tvalue.version !== NODE_DISK_REGISTRY_SOURCE_VERSION_V1 ||\n\t\t!Array.isArray(value.records)\n\t)\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_index\", t(\"Install store index schema is unsupported\"));\n\tif (value.records.length > MAX_NODE_DISK_REGISTRY_RECORDS_V1)\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"too_many_records\", t(\"Install store index exceeds the record limit\"));\n\treturn value.records.map((record, index) => validateRecord(root, record, index));\n}\n\n/** Read a bounded UTF-8 file; the absolute path never appears in a thrown message. */\nasync function readBoundedFile(path: string, maxBytes: number, label: string): Promise<string> {\n\tconst handle = await open(path, \"r\");\n\ttry {\n\t\tconst stat = await handle.stat();\n\t\tif (!stat.isFile() || stat.size > maxBytes)\n\t\t\tthrow new NodeDiskRegistrySourceErrorV1(\n\t\t\t\tlabel === \"index\" ? \"invalid_index\" : \"invalid_manifest\",\n\t\t\t\tt(\"{label} exceeds the size limit\", { label }),\n\t\t\t);\n\t\treturn await handle.readFile(\"utf8\");\n\t} finally {\n\t\tawait handle.close().catch(() => undefined);\n\t}\n}\n\nfunction parseManifest(record: DiskIndexRecordV1, raw: string): PluginManifestV1 {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_manifest\", t(\"Installed plugin manifest JSON is invalid\"));\n\t}\n\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed))\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_manifest\", t(\"Installed plugin manifest is not an object\"));\n\tconst value = { ...(parsed as Record<string, unknown>) };\n\tif (value.packageFormatVersion !== undefined && value.packageFormatVersion !== NODE_PACKAGE_FORMAT_VERSION_V1)\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_manifest\", t(\"Installed plugin package format is unsupported\"));\n\t// The package envelope version is an install-host field; it is not part of\n\t// PluginManifestV1 and the stable manifest digest excludes it.\n\tdelete value.packageFormatVersion;\n\tif (value.id !== record.pluginId || value.pluginVersion !== record.pluginVersion)\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\n\t\t\t\"identity_mismatch\",\n\t\t\tt(\"Installed plugin manifest identity does not match index record for {identity}\", {\n\t\t\t\tidentity: `${record.pluginId}@${record.pluginVersion}`,\n\t\t\t}),\n\t\t);\n\treturn value as unknown as PluginManifestV1;\n}\n\n/** Read the install store index records; undefined when the store is empty. */\nasync function readIndexRecords(\n\trootDirectory: string,\n\tsignal: AbortSignal | undefined,\n): Promise<readonly DiskIndexRecordV1[] | undefined> {\n\tif (signal?.aborted)\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"cancelled\", t(\"Disk registry source read was cancelled\"));\n\tlet rawIndex: string;\n\ttry {\n\t\trawIndex = await readBoundedFile(\n\t\t\tjoin(rootDirectory, INDEX_FILE_V1),\n\t\t\tMAX_NODE_DISK_REGISTRY_INDEX_BYTES_V1,\n\t\t\t\"index\",\n\t\t);\n\t} catch (error) {\n\t\tif (error instanceof NodeDiskRegistrySourceErrorV1) throw error;\n\t\tif (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return undefined;\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"io_failed\", t(\"Install store index could not be read\"));\n\t}\n\treturn parseIndex(rootDirectory, rawIndex);\n}\n\n/**\n * Read-only registry source over the default install store. It projects the\n * persistent index and each installation instance's ecosystem manifest as\n * bounded envelopes for the registry's own digest verification. It never\n * writes the index or installation directories, and installation directories\n * stay inside the host-owned store.\n */\nexport function createNodeDiskPluginRegistrySourceV1(\n\toptions: NodeDiskRegistrySourceOptionsV1,\n): NodeDiskRegistrySourceV1 {\n\tconst rootDirectory = options.rootDirectory;\n\tif (typeof rootDirectory !== \"string\" || !isAbsolute(rootDirectory) || rootDirectory.trim() === \"\")\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"Install store root directory must be absolute\"),\n\t\t);\n\treturn {\n\t\tversion: NODE_DISK_REGISTRY_SOURCE_VERSION_V1,\n\t\tlist: async ({ signal } = {}) => {\n\t\t\tconst records = await readIndexRecords(rootDirectory, signal);\n\t\t\tif (records === undefined) return Object.freeze([]);\n\t\t\tconst envelopes: PluginRegistryManifestEnvelopeV1[] = [];\n\t\t\tfor (const record of records) {\n\t\t\t\tif (signal?.aborted)\n\t\t\t\t\tthrow new NodeDiskRegistrySourceErrorV1(\"cancelled\", t(\"Disk registry source read was cancelled\"));\n\t\t\t\tlet rawManifest: string;\n\t\t\t\ttry {\n\t\t\t\t\trawManifest = await readBoundedFile(\n\t\t\t\t\t\tjoin(record.directory, ECOSYSTEM_MANIFEST_FILE_V1),\n\t\t\t\t\t\tMAX_NODE_DISK_REGISTRY_MANIFEST_BYTES_V1,\n\t\t\t\t\t\t\"manifest\",\n\t\t\t\t\t);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof NodeDiskRegistrySourceErrorV1) throw error;\n\t\t\t\t\tthrow new NodeDiskRegistrySourceErrorV1(\"io_failed\", t(\"Installed plugin manifest could not be read\"));\n\t\t\t\t}\n\t\t\t\tconst manifest = parseManifest(record, rawManifest);\n\t\t\t\tenvelopes.push({\n\t\t\t\t\tmanifest,\n\t\t\t\t\tsource: record.installationRef,\n\t\t\t\t\tmanifestDigest: record.manifestDigest,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn Object.freeze(envelopes);\n\t\t},\n\t\tresolveCapabilityManifestPath: async ({ pluginId, pluginVersion, signal }) => {\n\t\t\tconst records = await readIndexRecords(rootDirectory, signal);\n\t\t\tif (records === undefined) return undefined;\n\t\t\tconst record = records.find(\n\t\t\t\t(candidate) => candidate.pluginId === pluginId && candidate.pluginVersion === pluginVersion,\n\t\t\t);\n\t\t\tif (record === undefined) return undefined;\n\t\t\tconst manifestPath = join(record.directory, CAPABILITY_MANIFEST_FILE_V1);\n\t\t\ttry {\n\t\t\t\tconst handle = await open(manifestPath, \"r\");\n\t\t\t\tawait handle.close().catch(() => undefined);\n\t\t\t} catch {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn manifestPath;\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"node-disk-registry-source.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-disk-registry-source.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAoC,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAG9F,QAAA,MAAM,oCAAoC,GAAa,CAAC;AACxD,oEAAoE;AACpE,eAAO,MAAM,qCAAqC,QAAc,CAAC;AACjE,+EAA+E;AAC/E,eAAO,MAAM,wCAAwC,QAAY,CAAC;AAClE,6FAA6F;AAC7F,eAAO,MAAM,iCAAiC,MAAM,CAAC;AAOrD,MAAM,MAAM,iCAAiC,GAC1C,WAAW,GACX,uBAAuB,GACvB,eAAe,GACf,kBAAkB,GAClB,mBAAmB,GACnB,kBAAkB,GAClB,WAAW,CAAC;AAEf;;;GAGG;AACH,qBAAa,6BAA8B,SAAQ,KAAK;IACvD,QAAQ,CAAC,IAAI,EAAE,iCAAiC,CAAC;IAEjD,YAAY,IAAI,EAAE,iCAAiC,EAAE,OAAO,EAAE,MAAM,EAInE;CACD;AAED,MAAM,WAAW,+BAA+B;IAC/C,0FAA0F;IAC1F,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,oCAAoC;IACpD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAyB,SAAQ,sBAAsB;IACvE,QAAQ,CAAC,OAAO,EAAE,OAAO,oCAAoC,CAAC;IAC9D;;;;;;OAMG;IACH,QAAQ,CAAC,6BAA6B,CAAC,EAAE,CACxC,KAAK,EAAE,oCAAoC,KACvC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACjC;AA6JD;;;;;;GAMG;AACH,wBAAgB,oCAAoC,CACnD,OAAO,EAAE,+BAA+B,GACtC,wBAAwB,CAoE1B","sourcesContent":["import { open } from \"node:fs/promises\";\nimport { isAbsolute, join } from \"node:path\";\nimport { t } from \"../../core/i18n/index.ts\";\nimport { withinInstallStoreRoot } from \"./install-store-paths.ts\";\nimport type { PluginRegistryManifestEnvelopeV1, PluginRegistrySourceV1 } from \"./registry.ts\";\nimport type { PluginManifestV1 } from \"./types.ts\";\n\nconst NODE_DISK_REGISTRY_SOURCE_VERSION_V1 = 1 as const;\n/** Maximum index.v1.json bytes accepted by this source boundary. */\nexport const MAX_NODE_DISK_REGISTRY_INDEX_BYTES_V1 = 1024 * 1024;\n/** Maximum per-installation agent-forge.json bytes accepted by this source. */\nexport const MAX_NODE_DISK_REGISTRY_MANIFEST_BYTES_V1 = 64 * 1024;\n/** Maximum index records projected by one list() call; matches the registry manifest cap. */\nexport const MAX_NODE_DISK_REGISTRY_RECORDS_V1 = 256;\n\nconst INDEX_FILE_V1 = \"index.v1.json\";\nconst ECOSYSTEM_MANIFEST_FILE_V1 = \"agent-forge.json\";\nconst CAPABILITY_MANIFEST_FILE_V1 = \"plugin.json\";\nconst NODE_PACKAGE_FORMAT_VERSION_V1 = 1;\n\nexport type NodeDiskRegistrySourceErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"invalid_configuration\"\n\t| \"invalid_index\"\n\t| \"invalid_manifest\"\n\t| \"identity_mismatch\"\n\t| \"too_many_records\"\n\t| \"io_failed\";\n\n/**\n * Deliberately does not retain filesystem exceptions or file contents: callers\n * must not turn registry diagnostics into a path or package disclosure.\n */\nexport class NodeDiskRegistrySourceErrorV1 extends Error {\n\treadonly code: NodeDiskRegistrySourceErrorCodeV1;\n\n\tconstructor(code: NodeDiskRegistrySourceErrorCodeV1, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"NodeDiskRegistrySourceErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\nexport interface NodeDiskRegistrySourceOptionsV1 {\n\t/** Absolute host-owned default install store directory. It is never returned in a DTO. */\n\treadonly rootDirectory: string;\n}\n\nexport interface NodeDiskRegistrySourceResolveInputV1 {\n\treadonly pluginId: string;\n\treadonly pluginVersion: string;\n\treadonly signal?: AbortSignal;\n}\n\nexport interface NodeDiskRegistrySourceV1 extends PluginRegistrySourceV1 {\n\treadonly version: typeof NODE_DISK_REGISTRY_SOURCE_VERSION_V1;\n\t/**\n\t * Internal host channel (D-075 S2): absolute `plugin.json` path of the\n\t * installation directory matching `{pluginId, pluginVersion}` in the store\n\t * index, for the sdk's installed-plugin code loading. Registry snapshots\n\t * still carry no paths; undefined means no matching record or the manifest\n\t * file is absent from the installation directory.\n\t */\n\treadonly resolveCapabilityManifestPath?: (\n\t\tinput: NodeDiskRegistrySourceResolveInputV1,\n\t) => Promise<string | undefined>;\n}\n\ninterface DiskIndexRecordV1 {\n\treadonly installationRef: string;\n\treadonly directory: string;\n\treadonly pluginId: string;\n\treadonly pluginVersion: string;\n\treadonly manifestDigest: string;\n\treadonly scope: \"global\" | \"project\";\n\treadonly scopeRef: string;\n\treadonly state: \"installed\" | \"active\" | \"retained\";\n}\n\nconst INDEX_KEYS_V1 = [\n\t\"installationRef\",\n\t\"directory\",\n\t\"pluginId\",\n\t\"pluginVersion\",\n\t\"manifestDigest\",\n\t\"scope\",\n\t\"scopeRef\",\n\t\"state\",\n] as const;\n\nfunction opaqueField(value: unknown, max: number): value is string {\n\treturn (\n\t\ttypeof value === \"string\" &&\n\t\tvalue.length > 0 &&\n\t\tvalue.length <= max &&\n\t\t!/[\\u0000-\\u001f\\u007f]/u.test(value) &&\n\t\t!/\\s/u.test(value) &&\n\t\t!/^(?:file:|[a-z]:[\\\\/]|[\\\\/]{1,2}|\\\\\\\\)/iu.test(value)\n\t);\n}\n\nfunction boundedField(value: unknown, max: number): value is string {\n\treturn typeof value === \"string\" && value.length > 0 && value.length <= max && !/[\\u0000-\\u001f\\u007f]/u.test(value);\n}\n\nfunction validateRecord(root: string, value: unknown, index: number): DiskIndexRecordV1 {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value))\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_index\", t(\"Index record {index} is not an object\", { index }));\n\tconst record = value as Record<string, unknown>;\n\tconst keys = INDEX_KEYS_V1;\n\tif (Object.keys(record).length !== keys.length || keys.some((key) => !(key in record)))\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\n\t\t\t\"invalid_index\",\n\t\t\tt(\"Index record {index} has an invalid schema\", { index }),\n\t\t);\n\tif (\n\t\t!opaqueField(record.installationRef, 2048) ||\n\t\t!boundedField(record.directory, 2048) ||\n\t\t!boundedField(record.pluginId, 256) ||\n\t\t!boundedField(record.pluginVersion, 256) ||\n\t\t!boundedField(record.manifestDigest, 512) ||\n\t\t!opaqueField(record.scopeRef, 2048) ||\n\t\t(record.scope !== \"global\" && record.scope !== \"project\") ||\n\t\t(record.state !== \"installed\" && record.state !== \"active\" && record.state !== \"retained\") ||\n\t\t!withinInstallStoreRoot(root, record.directory)\n\t)\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_index\", t(\"Index record {index} is invalid\", { index }));\n\treturn {\n\t\tinstallationRef: record.installationRef,\n\t\tdirectory: record.directory,\n\t\tpluginId: record.pluginId,\n\t\tpluginVersion: record.pluginVersion,\n\t\tmanifestDigest: record.manifestDigest,\n\t\tscope: record.scope,\n\t\tscopeRef: record.scopeRef,\n\t\tstate: record.state,\n\t};\n}\n\nfunction parseIndex(root: string, raw: string): readonly DiskIndexRecordV1[] {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_index\", t(\"Install store index JSON is invalid\"));\n\t}\n\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed))\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_index\", t(\"Install store index is not an object\"));\n\tconst value = parsed as Record<string, unknown>;\n\tif (\n\t\tObject.keys(value).length !== 2 ||\n\t\tvalue.version !== NODE_DISK_REGISTRY_SOURCE_VERSION_V1 ||\n\t\t!Array.isArray(value.records)\n\t)\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_index\", t(\"Install store index schema is unsupported\"));\n\tif (value.records.length > MAX_NODE_DISK_REGISTRY_RECORDS_V1)\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"too_many_records\", t(\"Install store index exceeds the record limit\"));\n\treturn value.records.map((record, index) => validateRecord(root, record, index));\n}\n\n/** Read a bounded UTF-8 file; the absolute path never appears in a thrown message. */\nasync function readBoundedFile(path: string, maxBytes: number, label: string): Promise<string> {\n\tconst handle = await open(path, \"r\");\n\ttry {\n\t\tconst stat = await handle.stat();\n\t\tif (!stat.isFile() || stat.size > maxBytes)\n\t\t\tthrow new NodeDiskRegistrySourceErrorV1(\n\t\t\t\tlabel === \"index\" ? \"invalid_index\" : \"invalid_manifest\",\n\t\t\t\tt(\"{label} exceeds the size limit\", { label }),\n\t\t\t);\n\t\treturn await handle.readFile(\"utf8\");\n\t} finally {\n\t\tawait handle.close().catch(() => undefined);\n\t}\n}\n\nfunction parseManifest(record: DiskIndexRecordV1, raw: string): PluginManifestV1 {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_manifest\", t(\"Installed plugin manifest JSON is invalid\"));\n\t}\n\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed))\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_manifest\", t(\"Installed plugin manifest is not an object\"));\n\tconst value = { ...(parsed as Record<string, unknown>) };\n\tif (value.packageFormatVersion !== undefined && value.packageFormatVersion !== NODE_PACKAGE_FORMAT_VERSION_V1)\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"invalid_manifest\", t(\"Installed plugin package format is unsupported\"));\n\t// The package envelope version is an install-host field; it is not part of\n\t// PluginManifestV1 and the stable manifest digest excludes it.\n\tdelete value.packageFormatVersion;\n\tif (value.id !== record.pluginId || value.pluginVersion !== record.pluginVersion)\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\n\t\t\t\"identity_mismatch\",\n\t\t\tt(\"Installed plugin manifest identity does not match index record for {identity}\", {\n\t\t\t\tidentity: `${record.pluginId}@${record.pluginVersion}`,\n\t\t\t}),\n\t\t);\n\treturn value as unknown as PluginManifestV1;\n}\n\n/** Read the install store index records; undefined when the store is empty. */\nasync function readIndexRecords(\n\trootDirectory: string,\n\tsignal: AbortSignal | undefined,\n): Promise<readonly DiskIndexRecordV1[] | undefined> {\n\tif (signal?.aborted)\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"cancelled\", t(\"Disk registry source read was cancelled\"));\n\tlet rawIndex: string;\n\ttry {\n\t\trawIndex = await readBoundedFile(\n\t\t\tjoin(rootDirectory, INDEX_FILE_V1),\n\t\t\tMAX_NODE_DISK_REGISTRY_INDEX_BYTES_V1,\n\t\t\t\"index\",\n\t\t);\n\t} catch (error) {\n\t\tif (error instanceof NodeDiskRegistrySourceErrorV1) throw error;\n\t\tif (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return undefined;\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\"io_failed\", t(\"Install store index could not be read\"));\n\t}\n\treturn parseIndex(rootDirectory, rawIndex);\n}\n\n/**\n * Read-only registry source over the default install store. It projects the\n * persistent index and each installation instance's ecosystem manifest as\n * bounded envelopes for the registry's own digest verification. It never\n * writes the index or installation directories, and installation directories\n * stay inside the host-owned store.\n */\nexport function createNodeDiskPluginRegistrySourceV1(\n\toptions: NodeDiskRegistrySourceOptionsV1,\n): NodeDiskRegistrySourceV1 {\n\tconst rootDirectory = options.rootDirectory;\n\tif (typeof rootDirectory !== \"string\" || !isAbsolute(rootDirectory) || rootDirectory.trim() === \"\")\n\t\tthrow new NodeDiskRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"Install store root directory must be absolute\"),\n\t\t);\n\treturn {\n\t\tversion: NODE_DISK_REGISTRY_SOURCE_VERSION_V1,\n\t\tlist: async ({ signal } = {}) => {\n\t\t\tconst records = await readIndexRecords(rootDirectory, signal);\n\t\t\tif (records === undefined) return Object.freeze([]);\n\t\t\tconst envelopes: PluginRegistryManifestEnvelopeV1[] = [];\n\t\t\t// index 按 installationRef 键控,重装/对齐重试会为同一 pluginId@version\n\t\t\t// 追加多条记录(2026-10-08 实证同身份 4 条、摘要零冲突)。同一身份内容\n\t\t\t// 一致(同一 tarball),按身份只投影一次;摘要冲突才是存储不一致。\n\t\t\tconst projectedDigests = new Map<string, string>();\n\t\t\tfor (const record of records) {\n\t\t\t\tif (signal?.aborted)\n\t\t\t\t\tthrow new NodeDiskRegistrySourceErrorV1(\"cancelled\", t(\"Disk registry source read was cancelled\"));\n\t\t\t\tconst identity = `${record.pluginId}@${record.pluginVersion}`;\n\t\t\t\tconst projectedDigest = projectedDigests.get(identity);\n\t\t\t\tif (projectedDigest !== undefined) {\n\t\t\t\t\tif (projectedDigest !== record.manifestDigest)\n\t\t\t\t\t\tthrow new NodeDiskRegistrySourceErrorV1(\n\t\t\t\t\t\t\t\"invalid_index\",\n\t\t\t\t\t\t\tt(\"Install store index contains conflicting manifests for {identity}\", { identity }),\n\t\t\t\t\t\t);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tlet rawManifest: string;\n\t\t\t\ttry {\n\t\t\t\t\trawManifest = await readBoundedFile(\n\t\t\t\t\t\tjoin(record.directory, ECOSYSTEM_MANIFEST_FILE_V1),\n\t\t\t\t\t\tMAX_NODE_DISK_REGISTRY_MANIFEST_BYTES_V1,\n\t\t\t\t\t\t\"manifest\",\n\t\t\t\t\t);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof NodeDiskRegistrySourceErrorV1) throw error;\n\t\t\t\t\tthrow new NodeDiskRegistrySourceErrorV1(\"io_failed\", t(\"Installed plugin manifest could not be read\"));\n\t\t\t\t}\n\t\t\t\tconst manifest = parseManifest(record, rawManifest);\n\t\t\t\tenvelopes.push({\n\t\t\t\t\tmanifest,\n\t\t\t\t\tsource: record.installationRef,\n\t\t\t\t\tmanifestDigest: record.manifestDigest,\n\t\t\t\t});\n\t\t\t\tprojectedDigests.set(identity, record.manifestDigest);\n\t\t\t}\n\t\t\treturn Object.freeze(envelopes);\n\t\t},\n\t\tresolveCapabilityManifestPath: async ({ pluginId, pluginVersion, signal }) => {\n\t\t\tconst records = await readIndexRecords(rootDirectory, signal);\n\t\t\tif (records === undefined) return undefined;\n\t\t\tconst record = records.find(\n\t\t\t\t(candidate) => candidate.pluginId === pluginId && candidate.pluginVersion === pluginVersion,\n\t\t\t);\n\t\t\tif (record === undefined) return undefined;\n\t\t\tconst manifestPath = join(record.directory, CAPABILITY_MANIFEST_FILE_V1);\n\t\t\ttry {\n\t\t\t\tconst handle = await open(manifestPath, \"r\");\n\t\t\t\tawait handle.close().catch(() => undefined);\n\t\t\t} catch {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn manifestPath;\n\t\t},\n\t};\n}\n"]}
|
|
@@ -163,9 +163,20 @@ export function createNodeDiskPluginRegistrySourceV1(options) {
|
|
|
163
163
|
if (records === undefined)
|
|
164
164
|
return Object.freeze([]);
|
|
165
165
|
const envelopes = [];
|
|
166
|
+
// index 按 installationRef 键控,重装/对齐重试会为同一 pluginId@version
|
|
167
|
+
// 追加多条记录(2026-10-08 实证同身份 4 条、摘要零冲突)。同一身份内容
|
|
168
|
+
// 一致(同一 tarball),按身份只投影一次;摘要冲突才是存储不一致。
|
|
169
|
+
const projectedDigests = new Map();
|
|
166
170
|
for (const record of records) {
|
|
167
171
|
if (signal?.aborted)
|
|
168
172
|
throw new NodeDiskRegistrySourceErrorV1("cancelled", t("Disk registry source read was cancelled"));
|
|
173
|
+
const identity = `${record.pluginId}@${record.pluginVersion}`;
|
|
174
|
+
const projectedDigest = projectedDigests.get(identity);
|
|
175
|
+
if (projectedDigest !== undefined) {
|
|
176
|
+
if (projectedDigest !== record.manifestDigest)
|
|
177
|
+
throw new NodeDiskRegistrySourceErrorV1("invalid_index", t("Install store index contains conflicting manifests for {identity}", { identity }));
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
169
180
|
let rawManifest;
|
|
170
181
|
try {
|
|
171
182
|
rawManifest = await readBoundedFile(join(record.directory, ECOSYSTEM_MANIFEST_FILE_V1), MAX_NODE_DISK_REGISTRY_MANIFEST_BYTES_V1, "manifest");
|
|
@@ -181,6 +192,7 @@ export function createNodeDiskPluginRegistrySourceV1(options) {
|
|
|
181
192
|
source: record.installationRef,
|
|
182
193
|
manifestDigest: record.manifestDigest,
|
|
183
194
|
});
|
|
195
|
+
projectedDigests.set(identity, record.manifestDigest);
|
|
184
196
|
}
|
|
185
197
|
return Object.freeze(envelopes);
|
|
186
198
|
},
|