codex-skills-mcp 1.5.0-beta.2 → 1.5.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +49 -17
  2. package/dist/app.html +41 -26
  3. package/dist/config.d.ts +6 -2
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +64 -36
  6. package/dist/config.js.map +1 -1
  7. package/dist/index.js +73 -96
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib/deadline.d.ts +3 -2
  10. package/dist/lib/deadline.d.ts.map +1 -1
  11. package/dist/lib/deadline.js +4 -3
  12. package/dist/lib/deadline.js.map +1 -1
  13. package/dist/lib/http-server.d.ts +19 -0
  14. package/dist/lib/http-server.d.ts.map +1 -0
  15. package/dist/lib/http-server.js +154 -0
  16. package/dist/lib/http-server.js.map +1 -0
  17. package/dist/lib/logger.d.ts.map +1 -1
  18. package/dist/lib/logger.js +2 -1
  19. package/dist/lib/logger.js.map +1 -1
  20. package/dist/lib/paths.d.ts +3 -0
  21. package/dist/lib/paths.d.ts.map +1 -0
  22. package/dist/lib/paths.js +26 -0
  23. package/dist/lib/paths.js.map +1 -0
  24. package/dist/loader/index.d.ts.map +1 -1
  25. package/dist/loader/index.js +22 -24
  26. package/dist/loader/index.js.map +1 -1
  27. package/dist/openai/app.d.ts.map +1 -1
  28. package/dist/openai/app.js +8 -5
  29. package/dist/openai/app.js.map +1 -1
  30. package/dist/openai/mentions.d.ts.map +1 -1
  31. package/dist/openai/mentions.js +134 -81
  32. package/dist/openai/mentions.js.map +1 -1
  33. package/dist/openai/settings.d.ts +0 -1
  34. package/dist/openai/settings.d.ts.map +1 -1
  35. package/dist/openai/settings.js +47 -29
  36. package/dist/openai/settings.js.map +1 -1
  37. package/dist/remote/github.d.ts +3 -1
  38. package/dist/remote/github.d.ts.map +1 -1
  39. package/dist/remote/github.js +379 -237
  40. package/dist/remote/github.js.map +1 -1
  41. package/dist/search/index.d.ts +6 -0
  42. package/dist/search/index.d.ts.map +1 -1
  43. package/dist/search/index.js +55 -39
  44. package/dist/search/index.js.map +1 -1
  45. package/dist/tools/diagnostics.js +1 -1
  46. package/dist/tools/diagnostics.js.map +1 -1
  47. package/dist/tools/list-skill-files.d.ts.map +1 -1
  48. package/dist/tools/list-skill-files.js +3 -1
  49. package/dist/tools/list-skill-files.js.map +1 -1
  50. package/dist/tools/load-skill-file.d.ts.map +1 -1
  51. package/dist/tools/load-skill-file.js +2 -0
  52. package/dist/tools/load-skill-file.js.map +1 -1
  53. package/dist/tools/plan-workflow.js +2 -2
  54. package/dist/tools/plan-workflow.js.map +1 -1
  55. package/dist/tools/read-skill.d.ts.map +1 -1
  56. package/dist/tools/read-skill.js +8 -2
  57. package/dist/tools/read-skill.js.map +1 -1
  58. package/dist/tools/search-skills.d.ts.map +1 -1
  59. package/dist/tools/search-skills.js +9 -14
  60. package/dist/tools/search-skills.js.map +1 -1
  61. package/package.json +8 -4
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # codex-skills-mcp
2
2
 
3
- > 🧠 Codex-Skills 技能库的 MCP (Model Context Protocol) Server — 让任意 AI 编程工具都能检索、阅读和使用 180+ 专业技能。
3
+ > 🧠 Codex-Skills 技能库的 MCP (Model Context Protocol) Server — 让 AI 编程工具检索、阅读和使用持续更新的专业技能库。
4
4
 
5
5
  ## 这是什么
6
6
 
7
7
  一个独立的 MCP Server,为 [codex-skills](https://github.com/Zhan-ZhangZ/codex-skills) 技能库提供标准化的 AI 工具接入协议。
8
8
 
9
9
  - **无需先下载全部技能文件**:启动只拉取轻量清单(约 108KB),技能全文按需加载;
10
- - **180+ 技能、14 个分类**:技能库由专家在远端持续维护,用户端零操作;
10
+ - **技能与分类持续更新**:目录数量以实时清单为准,内容按需获取;
11
11
  - **内置国内网络加速**:自动回退链,国内网络免翻墙可用。
12
12
 
13
13
  | 特性 | 说明 |
@@ -20,9 +20,19 @@
20
20
  | **中文搜索优化** | CJK bigram 分词 + Leading Words 权重 |
21
21
  | **零外部 AI 依赖** | 纯关键词搜索,不需要 embedding 模型 |
22
22
  | **双传输模式** | stdio(本地)+ HTTP(远程) |
23
- | **自动网络加速** | GitHub 直连 → jsDelivr → gh-proxy.com → ghfast.top 四级回退 |
23
+ | **自动网络加速** | 官方加速端点优先,延迟加入 GitHub / CDN / 公共镜像竞速;完整正文通过校验后才接受 |
24
24
  | **增量缓存** | 技能文件按大小比对断点续传,重复使用不重复下载 |
25
25
 
26
+ ## beta.4 改进(2026-10-16)
27
+
28
+ 当前开发版本为 **1.5.0-beta.4**,需要 **Node.js 22+**。本地构建可通过 `npm ci && npm test` 验证,尚未发布到 npm。审计依据、性能数据与下一轮优化见 [完整审查报告](docs/BETA-4-REVIEW.md)。
29
+
30
+ - 搜索立即读取本地索引,后台轮询更新;`force_refresh=true` 明确等待刷新。索引重复刷新不再累积评分统计。
31
+ - 下载校验完整正文、大小及 Git blob SHA;刷新失败保留可用缓存,断网时可使用合法同源清单启动。
32
+ - App 完成宿主初始化握手,修复搜索/详情竞态、返回导航、原地重试及输入法体验。
33
+ - HTTP 增加会话容量、正确的 404/400 语义、关闭清理及 Host/Origin 校验;默认监听 `127.0.0.1`。
34
+ - 离线回归、前端类型检查、包内文件和真实 stdio 协议验收接入 CI。
35
+
26
36
  ## 快速开始
27
37
 
28
38
  ### 1. 远程模式(默认,零配置,推荐)
@@ -63,6 +73,8 @@ node dist/index.js --skills-dir /path/to/codex-skills --http --port 3456
63
73
  - MCP 端点:`http://localhost:3456/mcp`(POST / GET / DELETE,支持 `mcp-session-id` 会话管理)
64
74
  - 健康检查:`http://localhost:3456/health`
65
75
 
76
+ 默认只监听 `127.0.0.1`。局域网/容器部署可显式设置 `--host 0.0.0.0`,并通过 `--allowed-hosts localhost,127.0.0.1,skills.example.com` 配置 Host/Origin 白名单。隧道保留远端 Host 时也需加入对应域名。
77
+
66
78
  ```bash
67
79
  curl http://localhost:3456/health
68
80
  # 预期输出
@@ -162,7 +174,7 @@ flowchart LR
162
174
 
163
175
  ### 网络加速(并发竞速)
164
176
 
165
- 所有远端文件请求由多个下载节点**并发竞速,最快成功者胜出**,无需任何参数:
177
+ 技能文件默认先尝试官方加速端点,延迟后将公共节点加入竞速。完整响应体通过大小和 Git blob SHA 校验后才可胜出;清单与内容更新优先读取 GitHub 权威源。可用 `--no-hedge` 立即并发所有节点:
166
178
 
167
179
  1. **官方加速端点** `gh.251716.xyz`(自建于香港的 raw.githubusercontent.com 只读反向代理,大陆方向 RTT 最低,小文件场景最快);
168
180
  2. **GitHub 官方直连**;
@@ -175,8 +187,8 @@ flowchart LR
175
187
  #### 官方加速端点披露
176
188
 
177
189
  - **是什么**:`gh.251716.xyz` 是本项目自建的只读反向代理,用于改善中国大陆无代理环境下访问 GitHub raw 的速度。
178
- - **凭证说明**:若本机配置了 GitHub token(`--github-token` / `GITHUB_TOKEN` / git 凭据自动检测),该 token 会随请求**经 HTTPS 端到端透传**给 GitHub——这样 GitHub 按 token 配额(5000 次/小时)计费,而不是把所有用户挤在本服务器共享的匿名 IP 配额上。加速服务器不记录、不存储 Authorization 请求头(nginx 默认访问日志不含请求头)。未配置 token 的用户请求不带认证,行为不变。
179
- - **如何关闭**:启动参数加 `--no-official-mirror`,即回退为纯公共节点行为(token 也只会发送给 GitHub 官方直连节点)。
190
+ - **凭证说明**:GitHub token(`--github-token` / `GITHUB_TOKEN` / 自动检测的 git 凭据)只发送给 GitHub 官方 API 与 raw 地址。官方加速端点、CDN 和公共镜像均不接收 Authorization。
191
+ - **如何关闭**:启动参数加 `--no-official-mirror`。
180
192
  - **服务端日志**:命中官方端点的下载会在 stderr 输出 `official endpoint won: <文件名>`,便于观测命中率。
181
193
 
182
194
  ### Agent 标准工作流(行为合约)
@@ -203,7 +215,7 @@ flowchart LR
203
215
  - 已完整下载的技能直接本地读取,不重复请求远端;
204
216
  - 中断的下载支持断点续传:按文件大小比对,只补拉缺失/不完整的文件;
205
217
  - 技能文件并发下载,默认 16(可用 `--download-concurrency` 调整);
206
- - 需要强制同步远端最新内容时,删除 `.codex-skills-cache/` 后重启即可。
218
+ - 清单可通过 `search_skills(..., force_refresh=true)` 或 `refresh_skills_list` 立即刷新;技能内容在 TTL 到期后的下一次读取时重验证。刷新失败保留原来的完整文件。
207
219
 
208
220
  ## MCP Tools
209
221
 
@@ -322,13 +334,20 @@ Agent → 按 SKILL.md 从 local_path 执行任务 # EXECUTE:严
322
334
  | `--github-path` | `codex-skills` | 技能库在仓库内的目录 |
323
335
  | `--github-token` | 自动从 git 凭据 / `GITHUB_TOKEN` 获取 | GitHub API 鉴权 |
324
336
  | `--http` | - | 启动 HTTP 模式 |
325
- | `--port` | `3456` | HTTP 端口 |
326
- | `--download-concurrency` | `16` | 技能文件并发下载数 |
337
+ | `--host` | `127.0.0.1` | HTTP 监听地址 |
338
+ | `--allowed-hosts` | 本地主机白名单 | HTTP 允许的 Host/Origin 主机名,逗号分隔 |
339
+ | `--port` | `3456` | HTTP 端口,0–65535;0 自动选择空闲端口 |
340
+ | `--cache-dir` | `~/.codex-skills-cache` | 缓存目录,也可用 `CODEX_SKILLS_CACHE_DIR` |
341
+ | `--download-concurrency` | `16` | 技能文件并发下载数,1–64 |
342
+ | `--download-timeout` | `30` | 单请求超时秒数,1–300,覆盖完整正文 |
343
+ | `--soft-deadline-seconds` | `55` | 无 progress token 请求的响应期限;0 禁用 |
344
+ | `--hard-deadline-seconds` | `285` | 所有下载调用的响应期限;0 禁用 |
345
+ | `--no-official-mirror` | 关闭 | 禁用官方加速端点 |
346
+ | `--no-hedge` | 关闭 | 所有节点立即开始竞速 |
327
347
  | `--manifest-ttl <秒>` | `86400` | 清单缓存 TTL(0 = 永不按年龄刷新)。新技能可见性由下面的轮询负责 |
328
- | `--manifest-poll <秒>` | `300` | **清单新鲜度轮询间隔**:search/plan 调用时对权威源发条件请求(304 级开销),新集成技能最迟此时限内可被搜到;0 = 关闭。环境变量 `CODEX_SKILLS_MANIFEST_POLL_SECONDS` |
329
- | `--cn-mirror` | - | ⚠️ 已废弃(兼容保留):网络加速现为自动回退链,此参数不再生效 |
348
+ | `--manifest-poll <秒>` | `300` | 后台清单轮询间隔:search/plan/mentions/App 调用触发节流检查;完成后后续请求使用新索引。0 = 关闭,范围 0–3600 |
330
349
 
331
- 环境变量:`CODEX_SKILLS_DIR`(本地技能库路径)、`GITHUB_TOKEN`、`CODEX_SKILLS_DOWNLOAD_CONCURRENCY`。
350
+ 环境变量:`CODEX_SKILLS_DIR`、`CODEX_SKILLS_CACHE_DIR`、`GITHUB_TOKEN`、`CODEX_SKILLS_DOWNLOAD_CONCURRENCY`、`CODEX_SKILLS_DOWNLOAD_TIMEOUT`、`CODEX_SKILLS_MANIFEST_POLL_SECONDS`。设置文件默认位于 `~/.codex-skills-mcp/settings.json`,可通过 `CODEX_SKILLS_SETTINGS_DIR` 隔离。CLI 显式参数优先于启动时保存的设置;设置面板更新实时同步各会话。
332
351
 
333
352
  技能库清单(`skills_manifest.json`)为 JSON 数组,每项包含 `name` / `description` / `category` / `folder` / `relative_path` 五个字段。
334
353
 
@@ -340,8 +359,8 @@ Agent → 按 SKILL.md 从 local_path 执行任务 # EXECUTE:严
340
359
  | 想看 Agent 到底做了什么 | `diagnostics` 或直接读 `~/.codex-skills-cache/logs/mcp-activity-*.jsonl` |
341
360
  | npx 首次运行较慢 | 首次需下载 npm 包 + 拉取清单,属正常;之后走缓存 |
342
361
  | 日志出现 `Network warning` | 当前加速节点失败,自动降级到下一个,可忽略 |
343
- | 想强制更新技能内容 | 删除 `.codex-skills-cache/` 后重启,或设 `--manifest-ttl 60` 让清单自动高频刷新 |
344
- | 仓库新增了技能但搜不到 | v1.4.1 起 search/plan 每次调用先做节流条件轮询(默认 5 分钟一次,`--manifest-poll` 可调),新技能最迟一个轮询间隔内可见;read_skill 查无此名也会自动轮询复查。仍异常时 `search_skills(query, force_refresh=true)` 强刷,或删 `.codex-skills-cache/skills_manifest.json` 重启 |
362
+ | 想更新技能内容 | 使用 `--manifest-ttl 60`,到期后重新读取技能会按远端文件树重验证;失败时保留原缓存 |
363
+ | 仓库新增了技能但搜不到 | 普通搜索先返回现有索引,后台检查更新;立即获取可用 `search_skills(query, force_refresh=true)` 或设置面板的刷新动作 |
345
364
  | `load_skill_file` 读大文件失败 | 单文件上限 500KB,属保护设计 |
346
365
  | GitHub API 限流 | 每个技能仅 2 次 API 调用,已缓存技能不再请求;未登录配额 60 次/小时 |
347
366
  | 工具列表里看不到 MCP | 客户端未重启,重启会话即可 |
@@ -349,10 +368,23 @@ Agent → 按 SKILL.md 从 local_path 执行任务 # EXECUTE:严
349
368
  ## 技术栈
350
369
 
351
370
  - TypeScript + ESM
352
- - `@modelcontextprotocol/sdk` v1.12+
371
+ - `@modelcontextprotocol/sdk` v1.30+
353
372
  - `express` v5(仅 HTTP 模式)
354
- - `zod` v3 运行时 schema 验证
355
- - Node.js 18+
373
+ - `zod` v4 运行时 schema 验证
374
+ - Node.js 22+
375
+
376
+ ## 开发与验收
377
+
378
+ ```bash
379
+ npm ci
380
+ npm test # 前后端类型检查、构建、离线回归
381
+ npm run benchmark # 固定双语样本搜索基准
382
+ npm run build:plugin # 从源码重新构建插件
383
+ npm run check:package # npm 压缩包 + 插件的 stdio 端到端验收
384
+ npm audit
385
+ ```
386
+
387
+ 测试使用临时目录、模拟网络或本地随机端口。旧测试文件保留为兼容入口,统一转发到新的离线套件。CI 配置覆盖 Node 22 / 24。
356
388
 
357
389
  ## License
358
390
 
package/dist/app.html CHANGED
@@ -4,69 +4,79 @@
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>Codex Skills 技能库</title>
7
+ <style>@layer base{:root{color-scheme:light dark;--background: var( --color-background-primary, light-dark(rgb(255 255 255), rgb(24 24 24)) );--foreground: var( --color-text-primary, light-dark(rgb(26 28 31), rgb(255 255 255)) );--card: color-mix(in oklab, var(--foreground) 5%, var(--background));--card-foreground: var(--color-text-primary, var(--foreground));--primary: var( --color-text-info, light-dark(rgb(51 156 255), rgb(131 195 255)) );--primary-foreground: var( --color-text-inverse, light-dark(rgb(255 255 255), rgb(13 13 13)) );--secondary: var( --color-background-secondary, light-dark(rgb(255 255 255 / 96%), rgb(54 54 54 / 96%)) );--secondary-foreground: var(--color-text-primary, var(--foreground));--muted: color-mix(in srgb, var(--foreground) 10%, transparent);--muted-foreground: var( --color-text-secondary, light-dark(rgb(26 28 31 / 49.4%), rgb(255 255 255 / 49.8%)) );--accent: var( --color-background-info, light-dark(rgb(229 242 255), rgb(13 39 63)) );--accent-foreground: var(--color-text-info, var(--primary));--destructive: var( --color-text-warning, light-dark(rgb(226 85 7), rgb(255 133 73)) );--border: var( --color-border-secondary, light-dark(rgb(26 28 31 / 8%), rgb(255 255 255 / 8.2%)) );--input: var( --color-border-primary, light-dark(rgb(26 28 31 / 11.8%), rgb(255 255 255 / 12%)) );--ring: var(--color-ring-primary, var(--primary));--font-size-base: var(--font-text-md-size, 14px);--radius: var(--border-radius-lg, 12.5px)}:root[data-theme=light]{color-scheme:light}:root[data-theme=dark]{color-scheme:dark}body{margin:0;color:var(--foreground);background:var(--background);font-size:max(11px,var(--font-size-base));font-weight:var(--font-weight-normal, 430);line-height:1.5}body,body>*{font-family:var( --font-sans, -apple-system, system-ui, "Segoe UI", sans-serif )}h1,h2,h3,p{margin-block:0}h1,h2,h3{font-weight:var(--font-weight-medium, 500);line-height:1.25}h1{font-size:calc(var(--font-size-base) * 1.7142857143)}h2{font-size:calc(var(--font-size-base) * 1.4285714286)}h3{font-size:calc(var(--font-size-base) * 1.2857142857)}}@layer components{.cursor-interaction{cursor:var(--cursor-interaction, pointer)}.card{min-width:0;padding:12px;overflow-wrap:break-word;border-radius:calc(var(--radius) * 1.6);corner-shape:superellipse(1.5);color:var(--card-foreground);background:var(--card)}.btn,.form-check-input,.form-control,.form-select{box-sizing:border-box;font:inherit}.btn{appearance:button;display:inline-flex;inline-size:fit-content;max-inline-size:100%;min-height:28px;align-items:center;justify-content:center;gap:4px;margin:0;padding:0 8px;border:1px solid var(--input);border-radius:var(--radius);corner-shape:superellipse(1.5);color:var(--secondary-foreground);background:var(--secondary);cursor:var(--cursor-interaction, pointer);text-align:center;text-decoration:none;white-space:nowrap;user-select:none}.btn:not(:disabled):hover{background:color-mix(in srgb,var(--foreground) 6%,var(--secondary))}.btn-primary{border-color:transparent;color:var(--primary-foreground);background:var(--foreground);background-clip:padding-box}.btn-primary:not(:disabled):hover{background:color-mix(in srgb,var(--foreground) 80%,transparent);background-clip:padding-box}.btn-ghost{border-color:transparent;color:var(--muted-foreground);background:transparent}.btn-ghost:not(:disabled):hover{color:var(--foreground);background:color-mix(in srgb,var(--foreground) 6%,var(--secondary))}.btn:not(.btn-primary):is([aria-pressed=true],[aria-selected=true]){border-color:var(--primary);color:var(--primary-foreground);background:var(--primary)}.btn:focus-visible{outline:2px solid var(--ring);outline-offset:2px}.btn:disabled,.form-check-input:disabled,.form-control:disabled,.form-select:disabled{cursor:not-allowed;opacity:.4}.form-label{display:block;margin-bottom:6px;color:var(--foreground)}.form-control,.form-select{display:block;width:100%;min-height:28px;padding:0 8px;outline:none;border:1px solid var(--input);border-radius:var(--radius);corner-shape:superellipse(1.5);color:var(--foreground);background:var(--secondary)}.form-control::placeholder{color:var(--muted-foreground)}.form-select{appearance:none;padding-right:32px;background-image:linear-gradient(45deg,transparent 50%,var(--muted-foreground) 50%),linear-gradient(135deg,var(--muted-foreground) 50%,transparent 50%);background-position:calc(100% - 14px) 50%,calc(100% - 10px) 50%;background-repeat:no-repeat;background-size:4px 4px;cursor:var(--cursor-interaction, pointer)}.form-select:not(:disabled):hover{background-color:color-mix(in srgb,var(--foreground) 6%,var(--secondary))}textarea.form-control{min-height:72px;padding:8px 10px;resize:vertical}.form-control:focus-visible,.form-select:focus-visible{border-color:var(--ring);box-shadow:inset 0 0 0 1px var(--ring)}.form-check{display:flex;min-height:20px;align-items:center;gap:8px}.form-check-input{appearance:none;display:grid;width:16px;height:16px;flex:0 0 auto;place-items:center;margin:0;border:1px solid var(--input);border-radius:5px;corner-shape:superellipse(1.5);color:var(--primary-foreground);background:var(--secondary);cursor:var(--cursor-interaction, pointer)}.form-check-input:checked{border-color:var(--primary);background:var(--primary)}.form-check-input:checked:after{width:7px;height:4px;border-bottom:2px solid currentColor;border-left:2px solid currentColor;content:"";transform:translateY(-1px) rotate(-45deg)}.form-check-input:focus-visible{outline:2px solid var(--ring);outline-offset:2px}.form-check-label{color:var(--foreground)}svg.lucide{display:block;width:16px;height:16px;flex:none;stroke-width:1.6}.text-small{font-size:max(11px,calc(var(--font-size-base) - 2px))}.text-muted{color:var(--muted-foreground)}.text-destructive{color:var(--destructive)}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}}
8
+ </style>
7
9
  <style>
8
10
  :root { color-scheme: light dark; }
9
11
  * { box-sizing: border-box; margin: 0; padding: 0; }
10
12
  body {
11
13
  font: 14px var(--font-sans, -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif);
12
- background: var(--color-background-primary, #fafafa);
13
- color: var(--color-text-primary, #1f1f1f);
14
- min-height: 100vh; padding: 20px;
14
+ background: var(--background);
15
+ color: var(--foreground);
16
+ min-height: 100vh; padding: clamp(12px, 3vw, 24px); max-width: 1200px; margin: 0 auto;
15
17
  }
16
18
  [hidden] { display: none !important; }
17
19
  header { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
18
- h1 { font-size: 18px; font-weight: 650; flex: 1; }
19
- .muted { opacity: .65; font-size: 12px; }
20
+ h1 { font-size: 18px; font-weight: 650; flex: 1; min-width: 0; overflow-wrap: anywhere; }
21
+ .muted { color: var(--muted-foreground); font-size: 12px; }
20
22
  button, input {
21
- font: inherit; border: 1px solid var(--color-border-primary, #c9c9c9);
23
+ font: inherit; border: 1px solid var(--input);
22
24
  border-radius: 9px; padding: 8px 12px;
23
- background: var(--color-background-secondary, #fff); color: inherit;
25
+ background: var(--secondary); color: inherit;
24
26
  }
25
27
  button { cursor: var(--cursor-interaction, pointer); }
26
- button:hover:not(:disabled) { border-color: #5296c6; }
28
+ button:hover:not(:disabled) { border-color: var(--primary); }
29
+ :focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }
30
+ .sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
27
31
  button:disabled { opacity: .45; cursor: default; }
28
32
  #search { width: 100%; margin-bottom: 14px; }
29
- #cats { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 9px; margin-bottom: 18px; }
33
+ #cats { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); gap: 9px; margin-bottom: 18px; }
30
34
  .cat {
31
35
  display: flex; justify-content: space-between; align-items: center;
32
36
  padding: 11px 13px; border-radius: 10px; text-align: left;
33
- border: 1px solid var(--color-border-primary, #ddd);
34
- background: var(--color-background-secondary, #fff);
37
+ border: 1px solid var(--border);
38
+ background: var(--secondary);
35
39
  }
36
40
  .cat b { font-weight: 600; font-size: 13.5px; }
37
- #cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 9px; }
41
+ #cards, #cards-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 230px), 1fr)); gap: 9px; }
38
42
  .card {
39
43
  padding: 12px 13px; border-radius: 10px; text-align: left;
40
- border: 1px solid var(--color-border-primary, #ddd);
41
- background: var(--color-background-secondary, #fff);
44
+ border: 1px solid var(--border);
45
+ background: var(--secondary);
42
46
  display: flex; flex-direction: column; gap: 6px;
43
47
  }
44
- .card b { font-size: 13.5px; font-weight: 600; }
48
+ .card b { overflow-wrap: anywhere; font-size: 13.5px; font-weight: 600; }
45
49
  .card p { font-size: 12px; line-height: 1.5; opacity: .72;
46
50
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
47
51
  .badge {
48
52
  align-self: flex-start; font-size: 10.5px; padding: 2px 8px; border-radius: 99px;
49
- border: 1px solid var(--color-border-primary, #ccc);
53
+ border: 1px solid var(--border);
50
54
  }
51
- .badge.on { border-color: #3d9a50; color: #3d9a50; }
55
+ .badge.on { border-color: light-dark(#277a38, #78d68b); color: light-dark(#277a38, #78d68b); }
52
56
  .toolbar { display: flex; gap: 8px; margin-bottom: 12px; align-items: center; flex-wrap: wrap; }
53
57
  #detail pre {
54
58
  white-space: pre-wrap; word-break: break-word; font-size: 12px; line-height: 1.65;
55
- padding: 14px; border-radius: 10px; border: 1px solid var(--color-border-primary, #ddd);
56
- background: var(--color-background-secondary, #fff); max-height: 55vh; overflow: auto;
59
+ padding: 14px; border-radius: 10px; border: 1px solid var(--border);
60
+ background: var(--secondary); max-height: 55vh; overflow: auto;
57
61
  }
58
- footer { margin-top: 16px; font-size: 12px; opacity: .6; display: flex; justify-content: space-between; gap: 10px; }
62
+ footer { margin-top: 16px; font-size: 12px; color: var(--muted-foreground); display: flex; align-items: center; gap: 10px; }
63
+ #empty { padding: 24px 0; line-height: 1.7; color: var(--muted-foreground); }
64
+ #retry { flex-shrink: 0; }
65
+ @media (max-width: 360px) { header { flex-wrap: wrap; } #count { width: 100%; } }
59
66
  #status { overflow-wrap: anywhere; }
60
67
  </style>
61
68
  </head>
62
69
  <body>
63
70
  <header>
64
71
  <button id="back" hidden>← 返回</button>
65
- <h1 id="heading">Codex Skills 技能库</h1>
72
+ <h1 id="heading" tabindex="-1">Codex Skills 技能库</h1>
66
73
  <span class="muted" id="count"></span>
67
74
  </header>
68
75
 
69
- <input id="search" placeholder="搜索技能(中英文、功能描述…)" />
76
+ <label for="search" class="sr-only">搜索技能</label>
77
+ <input id="search" type="search" maxlength="500" autocomplete="off" spellcheck="false" placeholder="搜索技能(中英文、功能描述…)" disabled />
78
+
79
+ <main id="content" aria-busy="true">
70
80
 
71
81
  <section id="home">
72
82
  <p class="muted" style="margin-bottom:10px">常用技能</p>
@@ -77,6 +87,7 @@
77
87
 
78
88
  <section id="list" hidden>
79
89
  <div id="cards-list"></div>
90
+ <p id="empty" hidden></p>
80
91
  </section>
81
92
 
82
93
  <section id="detail" hidden>
@@ -85,12 +96,16 @@
85
96
  <span style="flex:1"></span>
86
97
  <button id="d-attach">加入对话</button>
87
98
  </div>
88
- <pre id="d-md">加载中…</pre>
99
+ <pre id="d-md" tabindex="0" aria-label="技能说明预览">加载中…</pre>
89
100
  </section>
90
101
 
91
- <footer><span id="status">连接中…</span><span id="ctx"></span></footer>
92
- <script>"use strict";(()=>{function C(){let e=0,t=new Map,a=new Map,c=new Map,o=r=>window.parent.postMessage({jsonrpc:"2.0",...r},"*"),m=async r=>{if(r.source!==window.parent||r.data?.jsonrpc!=="2.0")return;let n=r.data;if(!n.method&&n.id!=null){let d=t.get(n.id);if(!d)return;t.delete(n.id),clearTimeout(d.timer),n.error?d.reject(new Error(n.error.message)):d.resolve(n.result)}else if(n.method&&n.id!=null){let d=a.get(n.method);if(!d){o({id:n.id,error:{code:-32601,message:`Unsupported app method: ${n.method}`}});return}try{o({id:n.id,result:await d(n.params??{})})}catch(u){o({id:n.id,error:{code:-32603,message:u instanceof Error?u.message:String(u)}})}}else if(n.method)for(let d of c.get(n.method)??[])d(n.params??{})};return window.addEventListener("message",m),{request(r,n={},d=15e3){if(window.parent===window)return Promise.reject(new Error(`Open this app in an MCP host to use ${r}`));let u=++e;return new Promise((k,f)=>{let T=setTimeout(()=>{t.delete(u),f(new Error(`${r} timed out`))},d);t.set(u,{resolve:$=>k($),reject:f,timer:T}),o({id:u,method:r,params:n})})},notify(r,n={}){o({method:r,params:n})},handle(r,n){a.set(r,n)},on(r,n){return c.has(r)||c.set(r,new Set),c.get(r).add(n),()=>{c.get(r)?.delete(n)}},dispose(){window.removeEventListener("message",m);for(let r of t.values())clearTimeout(r.timer),r.reject(new Error("App disposed"));t.clear(),a.clear(),c.clear()}}}var s=e=>document.getElementById(e),h=C(),l={view:"home",category:"",query:"",detail:null},i=e=>s("status").textContent=e;async function w(e,t){let a=await h.request("tools/call",{name:e,arguments:t},3e4);if(a?.isError)throw new Error(`tool ${e} failed`);return a?.structuredContent??{}}async function b(e){let a=(await h.request("resources/read",{uri:`skill://${encodeURIComponent(e)}`},6e4))?.contents?.[0]?.text;if(typeof a!="string")throw new Error("SKILL.md unreadable");return a.length>6e3?a.slice(0,6e3)+`
93
- \u2026\uFF08\u9884\u89C8\u622A\u65AD\uFF09`:a}function q(e){let t=document.createElement("button");t.className="card";let a=document.createElement("b");a.textContent=e.name;let c=document.createElement("p");c.textContent=e.description;let o=document.createElement("span");return o.className="badge"+(e.cached?" on":""),o.textContent=e.cached?"\u5DF2\u7F13\u5B58":"\u6309\u9700\u4E0B\u8F7D",t.append(a,c,o),t.onclick=()=>L(e),t}function y(e,t){e.textContent="",t.forEach(a=>e.appendChild(q(a)))}function g(e){l.view=e,s("home").hidden=e!=="home",s("list").hidden=e!=="category"&&e!=="search",s("detail").hidden=e!=="detail",s("back").hidden=e==="home",s("heading").textContent=e==="category"?l.category:e==="search"?`\u641C\u7D22\u201C${l.query}\u201D`:e==="detail"?l.detail?.name??"\u6280\u80FD\u8BE6\u60C5":"Codex Skills \u6280\u80FD\u5E93",window.scrollTo(0,0)}async function p(){g("home"),i("\u52A0\u8F7D\u4E2D\u2026");try{let e=await w("skills.browse",{});s("count").textContent=`${e.totalSkills} \u6280\u80FD`,y(s("cards"),e.top??[]);let t=e.categories??[],a=s("cats");a.textContent="",t.forEach(c=>{let o=document.createElement("button");o.className="cat";let m=document.createElement("b");m.textContent=c.name;let r=document.createElement("span");r.className="muted",r.textContent=`${c.skill_count} \u4E2A`,o.append(m,r),o.onclick=()=>x(c.name),a.appendChild(o)}),i("\u5C31\u7EEA")}catch(e){i(`\u52A0\u8F7D\u5931\u8D25: ${e?.message??e}\uFF08\u70B9\u51FB\u91CD\u8BD5\uFF09`)}}async function x(e){l.category=e,g("category"),i("\u52A0\u8F7D\u4E2D\u2026");try{let t=await w("skills.browse",{category:e});s("count").textContent=`${t.skills?.length??0} \u4E2A`,y(s("cards-list"),t.skills??[]),i("\u5C31\u7EEA")}catch(t){i(`\u52A0\u8F7D\u5931\u8D25: ${t?.message??t}`)}}async function S(e){l.query=e,g("search"),i("\u641C\u7D22\u4E2D\u2026");try{let t=await w("skills.query",{query:e,limit:24});s("count").textContent=`${t.results?.length??0} \u7ED3\u679C`,y(s("cards-list"),t.results??[]),i("\u5C31\u7EEA")}catch(t){i(`\u641C\u7D22\u5931\u8D25: ${t?.message??t}`)}}async function L(e){l.detail=e,g("detail"),s("count").textContent="",s("d-cached").textContent=e.cached?"\u5DF2\u7F13\u5B58":"\u672A\u7F13\u5B58",s("d-cached").className="badge"+(e.cached?" on":""),s("d-md").textContent="\u52A0\u8F7D\u4E2D\u2026",i("");try{s("d-md").textContent=await b(e.name)}catch(t){s("d-md").textContent=`\u8BFB\u53D6\u5931\u8D25\uFF1A${t?.message??t}`}}s("d-attach").onclick=async()=>{let e=l.detail?.name;if(e)try{await h.request("ui/update-model-context",{content:[{type:"text",text:`\u5DF2\u9009\u62E9\u6280\u80FD: ${e}`}]},15e3),i(`\u5DF2\u5C06\u300C${e}\u300D\u52A0\u5165\u5BF9\u8BDD\u4E0A\u4E0B\u6587`)}catch(t){i(`\u52A0\u5165\u5931\u8D25: ${t?.message??t}`)}};s("back").onclick=()=>l.view==="detail"&&l.category?x(l.category):p();var E;s("search").addEventListener("input",e=>{let t=e.target.value.trim();if(clearTimeout(E),!t){p();return}E=setTimeout(()=>S(t),300)});s("status").addEventListener("click",()=>{(s("status").textContent??"").includes("\u5931\u8D25")&&p()});p();})();
102
+ </main>
103
+ <footer>
104
+ <span id="status" role="status" aria-live="polite" aria-atomic="true">连接中…</span>
105
+ <button id="retry" hidden>重试</button>
106
+ </footer>
107
+ <script>"use strict";(()=>{function q(){let e=0,t=new Map,n=new Map,r=new Map,o=a=>window.parent.postMessage({jsonrpc:"2.0",...a},"*"),v=async a=>{if(a.source!==window.parent||a.data?.jsonrpc!=="2.0")return;let s=a.data;if(!s.method&&s.id!=null){let l=t.get(s.id);if(!l)return;t.delete(s.id),clearTimeout(l.timer),s.error?l.reject(new Error(s.error.message)):l.resolve(s.result)}else if(s.method&&s.id!=null){let l=n.get(s.method);if(!l){o({id:s.id,error:{code:-32601,message:`Unsupported app method: ${s.method}`}});return}try{o({id:s.id,result:await l(s.params??{})})}catch(f){o({id:s.id,error:{code:-32603,message:f instanceof Error?f.message:String(f)}})}}else if(s.method)for(let l of r.get(s.method)??[])l(s.params??{})};return window.addEventListener("message",v),{request(a,s={},l=15e3){if(window.parent===window)return Promise.reject(new Error(`Open this app in an MCP host to use ${a}`));let f=++e;return new Promise((x,M)=>{let U=setTimeout(()=>{t.delete(f),M(new Error(`${a} timed out`))},l);t.set(f,{resolve:D=>x(D),reject:M,timer:U}),o({id:f,method:a,params:s})})},notify(a,s={}){o({method:a,params:s})},handle(a,s){n.set(a,s)},on(a,s){return r.has(a)||r.set(a,new Set),r.get(a).add(s),()=>{r.get(a)?.delete(s)}},dispose(){window.removeEventListener("message",v);for(let a of t.values())clearTimeout(a.timer),a.reject(new Error("App disposed"));t.clear(),n.clear(),r.clear()}}}var i=e=>{let t=document.getElementById(e);if(!t)throw new Error(`Missing app element: ${e}`);return t},u=q(),m=i("search"),C=i("d-attach"),P="2026-01-26",w={view:"home"},g=0,p=!1,b=!1,$=!1,S=!1,E=!1,_,I,d=new Map,k=new Map;async function N(e,t,n=3e4){let r=d.get(e);if(r&&r.expires>Date.now())return r.value;let o=k.get(e);if(o)return o;let v=t().then(a=>(d.delete(e),d.set(e,{value:a,expires:Date.now()+n}),d.size>32&&d.delete(d.keys().next().value),a)).finally(()=>k.delete(e));return k.set(e,v),v}function c(e,t){i("status").textContent=e,I=t,i("retry").hidden=!t}function y(e){i("content").setAttribute("aria-busy",String(e))}function L(){clearTimeout(_),_=void 0,g++}var R=e=>e instanceof Error?e.message:String(e);async function V(e,t){let n=await u.request("tools/call",{name:e,arguments:t},3e4);if(n?.isError)throw new Error(n.content?.find(r=>r.type==="text")?.text||`\u5DE5\u5177 ${e} \u8C03\u7528\u5931\u8D25`);if(!n?.structuredContent)throw new Error("\u670D\u52A1\u672A\u8FD4\u56DE\u6280\u80FD\u6570\u636E");return n.structuredContent}async function z(e){let n=(await u.request("resources/read",{uri:`skill://${encodeURIComponent(e)}`},6e4))?.contents?.find(r=>typeof r.text=="string")?.text;if(typeof n!="string")throw new Error("\u670D\u52A1\u672A\u8FD4\u56DE SKILL.md \u6587\u672C");return n.length>12e3?n.slice(0,12e3)+`
108
+ \u2026\uFF08\u9884\u89C8\u5DF2\u622A\u65AD\uFF0C\u52A0\u5165\u5BF9\u8BDD\u540E\u53EF\u8BFB\u53D6\u5B8C\u6574\u5185\u5BB9\uFF09`:n}function K(e){let t=document.createElement("button");t.className="card";let n=document.createElement("b");n.textContent=e.name;let r=document.createElement("p");r.textContent=e.description;let o=document.createElement("span");return o.className="badge"+(e.cached?" on":""),o.textContent=e.cached?"\u5DF2\u7F13\u5B58":"\u6309\u9700\u4E0B\u8F7D",t.append(n,r,o),t.onclick=()=>{w.view!=="detail"&&h({view:"detail",skill:e,from:w})},t}function B(e,t){e.replaceChildren(...t.map(K))}function W(e){i("cats").replaceChildren(...e.map(t=>{let n=document.createElement("button");n.className="cat";let r=document.createElement("b");r.textContent=t.name;let o=document.createElement("span");return o.className="muted",o.textContent=`${t.skill_count} \u4E2A`,n.append(r,o),n.onclick=()=>{h({view:"category",category:t.name})},n}))}function H(e){i("d-cached").textContent=e?"\u5DF2\u7F13\u5B58":"\u6309\u9700\u4E0B\u8F7D",i("d-cached").className="badge"+(e?" on":"")}function J(e){w=e,i("home").hidden=e.view!=="home",i("list").hidden=e.view!=="category"&&e.view!=="search",i("detail").hidden=e.view!=="detail",i("back").hidden=e.view==="home",i("heading").textContent=e.view==="category"?e.category:e.view==="search"?`\u641C\u7D22\u201C${e.query}\u201D`:e.view==="detail"?e.skill.name:"Codex Skills \u6280\u80FD\u5E93",i("count").textContent="",i("empty").hidden=!0,e.view!=="detail"&&(m.value=e.view==="search"?e.query:""),e.view==="detail"?(H(e.skill.cached),i("d-md").textContent="\u6B63\u5728\u8BFB\u53D6 SKILL.md\u2026",C.disabled=E):e.view==="home"?(i("cards").replaceChildren(),i("cats").replaceChildren()):i("cards-list").replaceChildren(),document.activeElement?.tagName==="BUTTON"&&i("heading").focus({preventScroll:!0}),window.scrollTo(0,0)}async function h(e){L();let t=g,n=()=>!p&&g===t;J(e),y(!0),c(e.view==="search"?"\u641C\u7D22\u4E2D\u2026":"\u52A0\u8F7D\u4E2D\u2026");try{if(e.view==="detail"){let r=await N(`detail:${e.skill.name}`,()=>z(e.skill.name),3e5);e.skill.cached=!0;for(let[o]of d)o.startsWith("detail:")||d.delete(o);if(!n())return;i("d-md").textContent=r,H(!0),c("\u6280\u80FD\u5DF2\u5C31\u7EEA\uFF0C\u53EF\u52A0\u5165\u5BF9\u8BDD")}else{let r=await N(JSON.stringify(e),()=>e.view==="search"?V("skills.query",{query:e.query,limit:24}):V("skills.browse",e.view==="category"?{category:e.category}:{}));if(!n())return;if(e.view==="home")i("count").textContent=`${r.totalSkills??0} \u6280\u80FD`,B(i("cards"),r.top??[]),W(r.categories??[]),c(r.totalSkills?"\u9009\u62E9\u5206\u7C7B\u6216\u641C\u7D22\u6280\u80FD":"\u6280\u80FD\u5E93\u4E3A\u7A7A\uFF0C\u8BF7\u68C0\u67E5\u670D\u52A1\u7AEF\u6280\u80FD\u6E90\u914D\u7F6E");else{let o=(e.view==="search"?r.results:r.skills)??[];i("count").textContent=`${o.length} ${e.view==="search"?"\u7ED3\u679C":"\u4E2A"}`,B(i("cards-list"),o),i("empty").hidden=o.length!==0,i("empty").textContent=e.view==="search"?"\u6CA1\u6709\u627E\u5230\u5339\u914D\u6280\u80FD\uFF0C\u8BD5\u8BD5\u66F4\u77ED\u7684\u5173\u952E\u8BCD\u6216\u63CF\u8FF0\u8981\u5B8C\u6210\u7684\u4EFB\u52A1\u3002":"\u8BE5\u5206\u7C7B\u6682\u65E0\u6280\u80FD\u3002",c(o.length?"\u9009\u62E9\u6280\u80FD\u67E5\u770B\u8BE6\u60C5":"\u6CA1\u6709\u5339\u914D\u7ED3\u679C")}}}catch(r){if(!n())return;e.view==="detail"&&(i("d-md").textContent="\u8BFB\u53D6\u672A\u5B8C\u6210\u3002\u91CD\u8BD5\u53EF\u7EE7\u7EED\u83B7\u53D6\u6280\u80FD\u5185\u5BB9\u3002"),c(`\u52A0\u8F7D\u5931\u8D25\uFF1A${R(r)}`,()=>{h(e)})}finally{n()&&y(!1)}}C.onclick=async()=>{if(w.view!=="detail"||E||!b)return;let e=w.skill,t=g;E=!0,C.disabled=!0;try{if((await u.request("ui/update-model-context",{content:[{type:"text",text:`\u5DF2\u9009\u62E9\u6280\u80FD\uFF1A${e.name}\u3002\u901A\u8FC7 resources/read \u8BFB\u53D6 skill://${encodeURIComponent(e.name)} \u83B7\u53D6\u5B8C\u6574\u4F7F\u7528\u8BF4\u660E\u3002`}],structuredContent:{skill:{name:e.name,uri:`skill://${encodeURIComponent(e.name)}`}}},15e3))?.isError)throw new Error("\u5BBF\u4E3B\u672A\u63A5\u53D7\u6280\u80FD\u4E0A\u4E0B\u6587");g===t&&!p&&c(`\u5DF2\u5C06\u300C${e.name}\u300D\u52A0\u5165\u5BF9\u8BDD\u4E0A\u4E0B\u6587`)}catch(n){g===t&&!p&&c(`\u52A0\u5165\u5931\u8D25\uFF1A${R(n)}`)}finally{E=!1,C.disabled=!b}};i("back").onclick=()=>{h(w.view==="detail"?w.from:{view:"home"})};i("retry").onclick=()=>I?.();function T(e=!1){if(!b||S)return;L();let t=m.value.trim();if(!t){h({view:"home"});return}let n=()=>{h({view:"search",query:t})};e?n():(y(!0),c("\u7B49\u5F85\u8F93\u5165\u2026"),_=setTimeout(n,250))}m.addEventListener("input",()=>T());m.addEventListener("compositionstart",()=>{S=!0,L()});m.addEventListener("compositionend",()=>{S=!1,T()});m.addEventListener("keydown",e=>{e.isComposing||S||(e.key==="Enter"&&(e.preventDefault(),T(!0)),e.key==="Escape"&&(m.value="",T(!0)))});function O(e){(e.theme==="light"||e.theme==="dark")&&(document.documentElement.dataset.theme=e.theme,document.documentElement.style.colorScheme=e.theme);for(let[t,n]of Object.entries(e.styles?.variables??{}))t.startsWith("--")&&typeof n=="string"&&document.documentElement.style.setProperty(t,n)}u.on("ui/notifications/host-context-changed",O);u.handle("ping",()=>({}));function A(){p=!0,L(),d.clear(),k.clear(),u.dispose()}u.handle("ui/resource-teardown",()=>(setTimeout(A,0),{}));window.addEventListener("pagehide",A,{once:!0});async function j(){if(!($||p)){$=!0,y(!0),m.disabled=!0,c("\u6B63\u5728\u8FDE\u63A5\u6280\u80FD\u5E93\u2026");try{let e=await u.request("ui/initialize",{protocolVersion:P,appInfo:{name:"codex-skills",version:"1.5.0-beta.4"},appCapabilities:{availableDisplayModes:["inline","fullscreen"]}});if(p)return;if(e.protocolVersion!==P)throw new Error(`\u4E0D\u652F\u6301\u7684\u754C\u9762\u534F\u8BAE\uFF1A${e.protocolVersion}`);O(e.hostContext??{}),u.notify("ui/notifications/initialized"),b=!0,m.disabled=!1,await h({view:"home"})}catch(e){p||(y(!1),c(`\u8FDE\u63A5\u5931\u8D25\uFF1A${R(e)}`,()=>{j()}))}finally{$=!1}}}j();})();
94
109
  </script>
95
110
  </body>
96
111
  </html>
package/dist/config.d.ts CHANGED
@@ -6,7 +6,6 @@ export interface Config {
6
6
  githubBranch?: string;
7
7
  githubPath: string;
8
8
  githubToken?: string;
9
- useCnMirror: boolean;
10
9
  /**
11
10
  * Route downloads through the official CN acceleration endpoint
12
11
  * (gh.251716.xyz — a self-hosted read-only reverse proxy of
@@ -34,7 +33,10 @@ export interface Config {
34
33
  /**
35
34
  * Hard absolute deadline for any single download call, in ms, regardless
36
35
  * of progress opt-in. Guards against pathological networks hanging a
37
- * call forever. Default 300s. 0 = disabled.
36
+ * call forever. Default 285s — deliberately UNDER common client request
37
+ * timeouts (e.g. Codex uses 300s) so our structured partial-progress
38
+ * response always arrives BEFORE the client would kill the call.
39
+ * 0 = disabled.
38
40
  */
39
41
  hardDeadlineMs: number;
40
42
  downloadConcurrency: number;
@@ -73,4 +75,6 @@ export interface ManifestEntry {
73
75
  stars?: number;
74
76
  }
75
77
  export declare function loadManifest(manifestPath: string): ManifestEntry[];
78
+ /** Validate remote/local data at the boundary, before indexing or writing it. */
79
+ export declare function parseManifest(value: unknown): ManifestEntry[];
76
80
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,MAAM;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B;;;;;;OAMG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,mFAAmF;IACnF,eAAe,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC3B;AAuBD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CA8JlD;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IAEtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,EAAE,CAGlE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,MAAM;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B;;;;;;OAMG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;;OAOG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,mFAAmF;IACnF,eAAe,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC3B;AA2BD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAuJlD;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IAEtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,EAAE,CAGlE;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,EAAE,CAwB7D"}
package/dist/config.js CHANGED
@@ -1,15 +1,19 @@
1
1
  import { readFileSync, existsSync, mkdirSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
3
  import { homedir } from "node:os";
4
- import { execSync } from "node:child_process";
4
+ import { execFileSync } from "node:child_process";
5
5
  /**
6
6
  * Helper to extract GitHub token from Git credentials
7
7
  */
8
8
  function getGitGithubToken() {
9
9
  try {
10
- const output = execSync('printf "protocol=https\nhost=github.com\n" | git credential fill', {
10
+ const output = execFileSync("git", ["credential", "fill"], {
11
+ input: "protocol=https\nhost=github.com\n\n",
11
12
  encoding: "utf-8",
12
- stdio: ["pipe", "pipe", "ignore"]
13
+ stdio: ["pipe", "pipe", "ignore"],
14
+ timeout: 2000,
15
+ maxBuffer: 64 * 1024,
16
+ env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GCM_INTERACTIVE: "never" },
13
17
  });
14
18
  const match = output.match(/^password=(.+)$/m);
15
19
  if (match && match[1]) {
@@ -31,14 +35,26 @@ export function parseConfig(args) {
31
35
  // Parse github arguments
32
36
  const getArg = (flag) => {
33
37
  const idx = args.indexOf(flag);
34
- return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
38
+ if (idx === -1)
39
+ return undefined;
40
+ const value = args[idx + 1];
41
+ if (!value || value.startsWith("--"))
42
+ throw new Error(`${flag} requires a value`);
43
+ return value;
44
+ };
45
+ const integerOption = (flag, fallback, min, max) => {
46
+ const raw = getArg(flag) ?? fallback;
47
+ const value = Number(raw);
48
+ if (!/^\d+$/.test(raw) || !Number.isSafeInteger(value) || value < min || value > max) {
49
+ throw new Error(`${flag} must be an integer between ${min} and ${max}`);
50
+ }
51
+ return value;
35
52
  };
36
53
  const explicitCli = new Set();
37
54
  const markExplicit = (flag, key) => {
38
55
  if (args.includes(flag))
39
56
  explicitCli.add(key);
40
57
  };
41
- markExplicit("--cn-mirror", "cn_mirror");
42
58
  markExplicit("--no-official-mirror", "official_mirror");
43
59
  markExplicit("--no-hedge", "hedge");
44
60
  markExplicit("--soft-deadline-seconds", "soft_deadline_seconds");
@@ -55,13 +71,14 @@ export function parseConfig(args) {
55
71
  if (!githubToken && process.env.GITHUB_TOKEN && process.env.GITHUB_TOKEN !== "github_pat_antigravitydummytoken") {
56
72
  githubToken = process.env.GITHUB_TOKEN;
57
73
  }
58
- // Fallback to Git credentials
59
- if (!githubToken) {
74
+ const isLocal = args.includes("--local") || args.includes("--skills-dir") || !!process.env.CODEX_SKILLS_DIR;
75
+ // Local mode never needs a credential helper or interactive prompt.
76
+ if (!githubToken && !isLocal) {
60
77
  githubToken = getGitGithubToken();
61
78
  }
62
79
  // It defaults to remote mode unless explicitly run locally
63
80
  let isRemote = true;
64
- if (args.includes("--local") || args.indexOf("--skills-dir") !== -1 || process.env.CODEX_SKILLS_DIR) {
81
+ if (isLocal) {
65
82
  isRemote = false;
66
83
  }
67
84
  if (isRemote) {
@@ -80,7 +97,7 @@ export function parseConfig(args) {
80
97
  // Local mode logic
81
98
  const dirIdx = args.indexOf("--skills-dir");
82
99
  if (dirIdx !== -1 && args[dirIdx + 1]) {
83
- skillsDir = resolve(args[dirIdx + 1]);
100
+ skillsDir = resolve(getArg("--skills-dir"));
84
101
  }
85
102
  if (!skillsDir && process.env.CODEX_SKILLS_DIR) {
86
103
  skillsDir = resolve(process.env.CODEX_SKILLS_DIR);
@@ -103,46 +120,29 @@ export function parseConfig(args) {
103
120
  console.error(`Error: skills_manifest.json not found in ${skillsDir}`);
104
121
  process.exit(1);
105
122
  }
106
- const useCnMirror = args.includes("--cn-mirror");
107
123
  const useOfficialMirror = !args.includes("--no-official-mirror");
108
124
  const hedgeEnabled = !args.includes("--no-hedge");
109
125
  // Soft/hard overall call deadlines (seconds; 0 disables). Soft applies
110
126
  // only to clients without a progressToken — see read-skill.ts.
111
- const softArg = getArg("--soft-deadline-seconds");
112
- const softDeadlineMs = softArg !== undefined ? parseInt(softArg, 10) * 1000 : 55 * 1000;
113
- const hardArg = getArg("--hard-deadline-seconds");
114
- const hardDeadlineMs = hardArg !== undefined ? parseInt(hardArg, 10) * 1000 : 300 * 1000;
127
+ const softDeadlineMs = integerOption("--soft-deadline-seconds", "55", 0, 86400) * 1000;
128
+ // 285s default: just under common 300s client timeouts (e.g. Codex) so
129
+ // our partial response wins the race against the client giving up.
130
+ const hardDeadlineMs = integerOption("--hard-deadline-seconds", "285", 0, 86400) * 1000;
115
131
  // Manifest cache TTL (default: 24 hours). --manifest-ttl <seconds> or 0 to disable.
116
- const ttlArg = getArg("--manifest-ttl");
117
- const manifestTTL = ttlArg !== undefined ? parseInt(ttlArg, 10) * 1000 : 24 * 60 * 60 * 1000;
132
+ const manifestTTL = integerOption("--manifest-ttl", "86400", 0, 604800) * 1000;
118
133
  // Freshness poll interval (default: 5 minutes). --manifest-poll <seconds>
119
134
  // or CODEX_SKILLS_MANIFEST_POLL_SECONDS; 0 disables the poll.
120
- const pollArg = getArg("--manifest-poll");
121
135
  const pollEnv = process.env.CODEX_SKILLS_MANIFEST_POLL_SECONDS;
122
- const manifestPollSeconds = parseInt(pollArg || pollEnv || "300", 10);
123
- if (!Number.isInteger(manifestPollSeconds) || manifestPollSeconds < 0) {
124
- console.error("Error: --manifest-poll must be a non-negative integer (seconds)");
125
- process.exit(1);
126
- }
136
+ const manifestPollSeconds = integerOption("--manifest-poll", pollEnv ?? "300", 0, 3600);
127
137
  const manifestPollMs = manifestPollSeconds * 1000;
128
138
  // Concurrent downloads for skill files (default 16). Configurable via
129
139
  // --download-concurrency <n> or CODEX_SKILLS_DOWNLOAD_CONCURRENCY env var.
130
- const concurrencyArg = getArg("--download-concurrency");
131
140
  const concurrencyEnv = process.env.CODEX_SKILLS_DOWNLOAD_CONCURRENCY;
132
- const downloadConcurrency = parseInt(concurrencyArg || concurrencyEnv || "16", 10);
133
- if (!Number.isInteger(downloadConcurrency) || downloadConcurrency < 1) {
134
- console.error("Error: --download-concurrency must be a positive integer");
135
- process.exit(1);
136
- }
141
+ const downloadConcurrency = integerOption("--download-concurrency", concurrencyEnv ?? "16", 1, 64);
137
142
  // Base download timeout for skill files (default 30 seconds). Configurable via
138
143
  // --download-timeout <seconds> or CODEX_SKILLS_DOWNLOAD_TIMEOUT env var.
139
- const timeoutArg = getArg("--download-timeout");
140
144
  const timeoutEnv = process.env.CODEX_SKILLS_DOWNLOAD_TIMEOUT;
141
- const downloadTimeoutSeconds = parseInt(timeoutArg || timeoutEnv || "30", 10);
142
- if (!Number.isInteger(downloadTimeoutSeconds) || downloadTimeoutSeconds < 1) {
143
- console.error("Error: --download-timeout must be a positive integer");
144
- process.exit(1);
145
- }
145
+ const downloadTimeoutSeconds = integerOption("--download-timeout", timeoutEnv ?? "30", 1, 300);
146
146
  const downloadTimeout = downloadTimeoutSeconds * 1000;
147
147
  return {
148
148
  explicitCli,
@@ -153,7 +153,6 @@ export function parseConfig(args) {
153
153
  githubBranch,
154
154
  githubPath,
155
155
  githubToken,
156
- useCnMirror,
157
156
  useOfficialMirror,
158
157
  hedgeEnabled,
159
158
  softDeadlineMs,
@@ -166,6 +165,35 @@ export function parseConfig(args) {
166
165
  }
167
166
  export function loadManifest(manifestPath) {
168
167
  const raw = readFileSync(manifestPath, "utf-8");
169
- return JSON.parse(raw);
168
+ return parseManifest(JSON.parse(raw));
169
+ }
170
+ /** Validate remote/local data at the boundary, before indexing or writing it. */
171
+ export function parseManifest(value) {
172
+ if (!Array.isArray(value))
173
+ throw new Error("Manifest must be an array");
174
+ const names = new Set();
175
+ for (const [index, entry] of value.entries()) {
176
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
177
+ throw new Error(`Invalid manifest entry ${index}`);
178
+ }
179
+ for (const field of ["name", "description", "category", "folder", "relative_path"]) {
180
+ if (typeof entry[field] !== "string")
181
+ throw new Error(`Manifest entry ${index}: ${field} must be a string`);
182
+ }
183
+ const path = entry.relative_path;
184
+ if (!entry.name.trim() || !path || /^[\/\\]|^[a-z]:/i.test(path) || path.includes("\\") || path.includes("\0") || path.split("/").includes("..")) {
185
+ throw new Error(`Manifest entry ${index}: invalid name or relative_path`);
186
+ }
187
+ const name = entry.name.toLowerCase();
188
+ if (names.has(name))
189
+ throw new Error(`Manifest contains duplicate name: ${entry.name}`);
190
+ names.add(name);
191
+ for (const field of ["aliases", "tags", "dependencies"]) {
192
+ if (entry[field] !== undefined && (!Array.isArray(entry[field]) || !entry[field].every((v) => typeof v === "string"))) {
193
+ throw new Error(`Manifest entry ${index}: ${field} must be a string array`);
194
+ }
195
+ }
196
+ }
197
+ return value;
170
198
  }
171
199
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}