cckit 0.3.1__tar.gz → 0.3.2__tar.gz
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.
- {cckit-0.3.1 → cckit-0.3.2}/Docs/01-overview.md +8 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/02-architecture.md +7 -2
- {cckit-0.3.1 → cckit-0.3.2}/Docs/05-design-log.md +59 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/07-security.md +42 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/09-state-api.md +60 -2
- {cckit-0.3.1 → cckit-0.3.2}/Docs/11-web-panel.md +36 -6
- {cckit-0.3.1 → cckit-0.3.2}/Docs/README.md +27 -6
- {cckit-0.3.1 → cckit-0.3.2}/Docs/cli-spec.md +90 -3
- {cckit-0.3.1 → cckit-0.3.2}/Docs/examples/video-toolkit/cckit.yaml +8 -1
- {cckit-0.3.1 → cckit-0.3.2}/Docs/pics/architecture.md +4 -1
- {cckit-0.3.1 → cckit-0.3.2}/Docs/pics/directory-layout.md +1 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/schema/cckit.schema.json +17 -2
- cckit-0.3.2/Docs/test/README.md +169 -0
- cckit-0.3.2/Docs/test/test-skill-dependency/.gitignore +5 -0
- cckit-0.3.2/Docs/test/test-skill-dependency/README.md +70 -0
- cckit-0.3.2/Docs/test/test-skill-dependency/json-pretty/SKILL.md +39 -0
- cckit-0.3.2/Docs/test/test-skill-dependency/json-pretty/pretty.config.json +5 -0
- cckit-0.3.2/Docs/test/test-skill-dependency/json-pretty/scripts/pretty.js +54 -0
- cckit-0.3.2/Docs/test/test-skill-dependency/package.json +9 -0
- cckit-0.3.2/Docs/test/test-skill-dependency/plain-advisor/SKILL.md +19 -0
- cckit-0.3.2/Docs/test/test-skill-dependency/requirements.txt +1 -0
- cckit-0.3.2/Docs/test/test-skill-dependency/test-skill-dependency/SKILL.md +43 -0
- cckit-0.3.2/Docs/test/test-skill-dependency/test-skill-dependency/config.json +5 -0
- cckit-0.3.2/Docs/test/test-skill-dependency/test-skill-dependency/scripts/test.py +99 -0
- cckit-0.3.2/Docs/test/test-skill-dependency-converted/README.md +86 -0
- cckit-0.3.2/Docs/test/test-skill-dependency-converted/cckit.yaml +50 -0
- cckit-0.3.2/Docs/test/test-skill-dependency-converted/json-pretty/SKILL.md +39 -0
- cckit-0.3.2/Docs/test/test-skill-dependency-converted/json-pretty/pretty.config.json +5 -0
- cckit-0.3.2/Docs/test/test-skill-dependency-converted/json-pretty/scripts/pretty.js +54 -0
- cckit-0.3.2/Docs/test/test-skill-dependency-converted/plain-advisor/SKILL.md +19 -0
- cckit-0.3.2/Docs/test/test-skill-dependency-converted/test-skill-dependency/SKILL.md +43 -0
- cckit-0.3.2/Docs/test/test-skill-dependency-converted/test-skill-dependency/config.json +5 -0
- cckit-0.3.2/Docs/test/test-skill-dependency-converted/test-skill-dependency/scripts/test.py +99 -0
- cckit-0.3.2/Docs/test/test_notice.txt +5 -0
- {cckit-0.3.1 → cckit-0.3.2}/PKG-INFO +29 -6
- {cckit-0.3.1 → cckit-0.3.2}/README.md +28 -5
- {cckit-0.3.1 → cckit-0.3.2}/pyproject.toml +1 -1
- cckit-0.3.2/skills/kit-builder/kit-builder/SKILL.md +182 -0
- {cckit-0.3.1 → cckit-0.3.2}/skills/kit-builder/kit-builder/kit-authoring.md +57 -12
- {cckit-0.3.1 → cckit-0.3.2}/skills/kit-builder/kit-builder/manifest-spec.md +40 -3
- {cckit-0.3.1 → cckit-0.3.2}/skills/kit-builder/kit-builder/templates/cckit.yaml +11 -4
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/__init__.py +1 -1
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/alt.py +680 -656
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/cckit.schema.json +17 -2
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/cli.py +142 -5
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/config.py +10 -0
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/exec.py +13 -11
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/installer.py +74 -1
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/manifest.py +39 -2
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/state.py +353 -12
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/web/app.py +152 -14
- cckit-0.3.2/tests/test_exec.py +234 -0
- {cckit-0.3.1 → cckit-0.3.2}/tests/test_installer.py +322 -211
- {cckit-0.3.1 → cckit-0.3.2}/tests/test_manifest.py +81 -5
- {cckit-0.3.1 → cckit-0.3.2}/tests/test_state.py +93 -0
- {cckit-0.3.1 → cckit-0.3.2}/tests/test_web_alt.py +18 -4
- cckit-0.3.2/tests/test_web_config.py +184 -0
- cckit-0.3.2/tests/test_web_notice.py +111 -0
- {cckit-0.3.1 → cckit-0.3.2}/uv.lock +1 -1
- cckit-0.3.2/web/dist/assets/index-DyKMbG6Y.css +1 -0
- cckit-0.3.2/web/dist/assets/index-VQNfSAQl.js +68 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/dist/index.html +2 -2
- {cckit-0.3.1 → cckit-0.3.2}/web/package-lock.json +2 -2
- {cckit-0.3.1 → cckit-0.3.2}/web/package.json +1 -1
- {cckit-0.3.1 → cckit-0.3.2}/web/src/App.tsx +7 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/AppSidebar.tsx +1 -1
- cckit-0.3.2/web/src/components/KitList.tsx +824 -0
- cckit-0.3.2/web/src/components/NoticeMenu.tsx +86 -0
- cckit-0.3.2/web/src/components/ui/textarea.tsx +17 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/lib/api.ts +109 -7
- cckit-0.3.2/web/tsconfig.tsbuildinfo +1 -0
- cckit-0.3.1/Docs/test/test-skill-dependency/README.md +0 -63
- cckit-0.3.1/Docs/test/test-skill-dependency/json-pretty/SKILL.md +0 -18
- cckit-0.3.1/Docs/test/test-skill-dependency/json-pretty/scripts/pretty.js +0 -12
- cckit-0.3.1/Docs/test/test-skill-dependency/plain-advisor/SKILL.md +0 -12
- cckit-0.3.1/Docs/test/test-skill-dependency/test-skill-dependency/SKILL.md +0 -22
- cckit-0.3.1/Docs/test/test-skill-dependency/test-skill-dependency/scripts/test.py +0 -48
- cckit-0.3.1/skills/kit-builder/kit-builder/SKILL.md +0 -102
- cckit-0.3.1/tests/test_exec.py +0 -111
- cckit-0.3.1/web/dist/assets/index-CSuOYCbo.js +0 -68
- cckit-0.3.1/web/dist/assets/index-Cp1Xoa9J.css +0 -1
- cckit-0.3.1/web/src/components/KitList.tsx +0 -422
- cckit-0.3.1/web/tsconfig.tsbuildinfo +0 -1
- {cckit-0.3.1 → cckit-0.3.2}/.gitignore +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/.gitignore +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/03-manifest-spec.md +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/04-cli-spec.md +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/06-platform-findings.md +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/08-installation.md +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/10-kit-authoring.md +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/kit-development.md +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/pics/four-state-model.md +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/pics/install-flow.md +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/pics/pain-points-solution.md +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/pics/state-transitions.md +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/Docs/test/hello-skill/SKILL.md +0 -0
- {cckit-0.3.1/Docs/test/test-skill-dependency → cckit-0.3.2/Docs/test/test-skill-dependency-converted}/.gitignore +0 -0
- {cckit-0.3.1/Docs/test/test-skill-dependency → cckit-0.3.2/Docs/test/test-skill-dependency-converted}/package.json +0 -0
- {cckit-0.3.1/Docs/test/test-skill-dependency → cckit-0.3.2/Docs/test/test-skill-dependency-converted}/requirements.txt +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/LICENSE +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/hatch_build.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/skills/kit-builder/cckit.yaml +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/skills/kit-builder/kit-builder/templates/SKILL.md +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/__main__.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/doctor.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/env.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/errors.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/link.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/lint.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/projects.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/registry.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/schema.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/src/cckit/web/__init__.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/tests/conftest.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/tests/helpers.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/tests/test_alt.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/tests/test_budget.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/tests/test_env.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/tests/test_link.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/tests/test_lint.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/tests/test_registry.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/tests/test_web_base.py +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/.gitignore +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/components.json +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/index.html +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/AddKitDialog.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/AddScopeDialog.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/DoctorDialog.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/badge.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/button.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/card.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/dialog.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/dropdown-menu.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/input.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/popover.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/progress.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/separator.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/sheet.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/sidebar.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/skeleton.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/sonner.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/components/ui/tooltip.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/hooks/use-mobile.ts +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/hooks/useSSE.ts +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/index.css +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/lib/utils.ts +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/src/main.tsx +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/tsconfig.json +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/tsconfig.node.json +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/tsconfig.node.tsbuildinfo +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/vite.config.d.ts +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/vite.config.js +0 -0
- {cckit-0.3.1 → cckit-0.3.2}/web/vite.config.ts +0 -0
|
@@ -29,6 +29,14 @@ Claude Code 2.1.245 原生已有 plugin + marketplace 系统,并且已经解决
|
|
|
29
29
|
后果:Python 依赖、原生编译、系统级二进制,官方全部无解。作者只能自己写
|
|
30
30
|
`SessionStart` hook 比对 `package.json` 哈希再手动装——只覆盖 Node,且很笨。
|
|
31
31
|
|
|
32
|
+
同一个缺口还有另一半:**skill 需要的用户配置**(API key、字体目录、一份要改的
|
|
33
|
+
`config.json`)官方同样没有位置可放。作者只能在 SKILL.md 里写"请先 export XXX",
|
|
34
|
+
用户装完看不出缺什么,唯一发现时机是脚本跑崩那一刻。cckit 把这两半一起补上:
|
|
35
|
+
|
|
36
|
+
- 依赖由 `requires` 声明,`cckit add` 建隔离环境(D-01 / D-02);
|
|
37
|
+
- 用户配置由 `kit_env` / `env` / `conf_files` 声明,用户在 CLI 与 Web 面板里填,
|
|
38
|
+
`cckit exec` 时注入(见 [03-manifest-spec.md](03-manifest-spec.md))。
|
|
39
|
+
|
|
32
40
|
> **CCKitKit 的核心功能,正是官方明确拒绝实现的那件事。**
|
|
33
41
|
> 这不代表不能做——我们是本机工具、用户自己装的,信任模型不同。但安全责任是官方
|
|
34
42
|
> 推给我们的,不是顺手接的。详见 [07-security.md](07-security.md)。
|
|
@@ -154,11 +154,16 @@ cckit 负责:
|
|
|
154
154
|
- `CCKIT_SKILL_DIR` — skill 自己的目录。**必需**,因为 CC 跑 Bash 时 cwd 是项目根,
|
|
155
155
|
脚本引用自己的资源文件需要这个
|
|
156
156
|
- `CCKIT_KIT_DIR`、`CCKIT_ENV_DIR`
|
|
157
|
-
-
|
|
157
|
+
- `kit_env`(kit 级)与 skill 的 `env`(skill 级)声明的变量。同名时 skill 级优先;
|
|
158
|
+
**值先取用户在 CLI/Web 填的**(`~/.cckit/envs.json`),没有再回落调用方的进程环境
|
|
158
159
|
4. 记录用量(用于预算优化建议)
|
|
159
160
|
5. cwd **保持调用方的 cwd**,让用户给的相对路径正常工作
|
|
160
161
|
|
|
161
|
-
|
|
162
|
+
必需的变量却哪儿都取不到时不静默失败,报错并给出填写的命令。
|
|
163
|
+
|
|
164
|
+
> 值**不写 Claude Code 的 `settings.json`**。往那里写会把用户的 `model`/`env`/
|
|
165
|
+
> `permissions` 一起卷进写入路径,而且"哪些变量是 cckit 写的"无从追踪、卸载时不敢删。
|
|
166
|
+
> 改由 cckit 自己存(`envs.json`,按 `{作用域}|{kit}[|{skill}]` 分桶),只在 exec 时注入。
|
|
162
167
|
|
|
163
168
|
> 这个入口顺带给了我们一个真实的拦截点——用户最初设想的"总控 skill 拦截调用"在这里
|
|
164
169
|
> 才真正拿得到。但它只覆盖带脚本的 skill;纯 prompt skill 的开关仍靠可见性。详见 D-04。
|
|
@@ -457,6 +457,65 @@ Web 把全局 skill 单独折叠一组、用独立覆盖选择器(不复用四
|
|
|
457
457
|
kit 作者诱导的操作。因此审计这一步聚焦 prompt injection / 敏感读取 / 外传 /
|
|
458
458
|
越界,并要求输出明确的 PASS/FAIL 结论,结论不明确一律视为不通过。
|
|
459
459
|
|
|
460
|
+
## D-17 用户配置:声明在 manifest,值由用户填,只在 exec 注入
|
|
461
|
+
|
|
462
|
+
**提出的问题**:skill 常常需要用户提供参数——一个 API key、一个字体目录、一份要改的
|
|
463
|
+
`config.json`。cckit 原本只有一份 **kit 级**的 `env:` 声明,而且值必须由用户自己在
|
|
464
|
+
shell 里 export。结果是:装完看不出缺什么(唯一发现时机是脚本跑崩那一刻),CLI 与
|
|
465
|
+
Web 上都没有填写的入口,粒度还和 `needs`(skill 级)不一致。
|
|
466
|
+
|
|
467
|
+
**最终方案**:分两层声明 + 一个独立的值存储 + 只在 exec 注入。
|
|
468
|
+
|
|
469
|
+
- **manifest 三层字段**:顶层 `env` 改名 `kit_env`(kit 共用);skill 新增 `env`
|
|
470
|
+
(skill 专属,同名时覆盖 kit 级)与 `conf_files`(相对 skill 目录的可改文件)。
|
|
471
|
+
三者都**只声明"要什么"**,没有 `value` / `default`。
|
|
472
|
+
- **值**:用户在 `cckit env <skill> <NAME> <VALUE>` 或 Web 面板里填,存
|
|
473
|
+
`~/.cckit/envs.json`(按 `{作用域}|{kit}[|{skill}]` 分桶,带锁 + 原子写)。
|
|
474
|
+
取值优先级:`envs.json` > 调用方的进程环境。`cckit exec` 时注入。
|
|
475
|
+
- **声明快照进 registry**:与 `needs` 同样处理,`list` 与 Web 不必每次现场解析 manifest。
|
|
476
|
+
- **缺配置要看得见**:`list_skills` 顺带算出每个 skill "声明了 `required` 却还没值"的变量名
|
|
477
|
+
(`missing_env`),CLI 在 `cckit list` 对应行末尾提醒、Web 在 skill 名字旁挂一个琥珀色钥匙
|
|
478
|
+
图标。**判定口径与 `cckit exec` 注入完全一致**(kit 级+skill 级、同名 skill 覆盖、值先看
|
|
479
|
+
`envs.json` 再看进程环境),否则会出现"列表说没事、一跑就报错"这种最费解的不一致。
|
|
480
|
+
|
|
481
|
+
**为什么这样定**:
|
|
482
|
+
|
|
483
|
+
- **不写 Claude Code 的 `settings.json`。** 最初的设计是把值写进 CC `settings.json`
|
|
484
|
+
的 `env` 键,并维护"基线快照 + 变量引用计数"。放弃它的理由有两条:一是那个键里
|
|
485
|
+
装着用户的核心配置(`ANTHROPIC_BASE_URL`、`ANTHROPIC_AUTH_TOKEN` 等),写坏等于
|
|
486
|
+
Claude Code 直接不可用;二是**基线快照抓不住快照之后发生的事**——用户事后手改
|
|
487
|
+
会被误判成 cckit 写的进而删除,基线文件丢了又会把 cckit 自己写的变量当成用户原有的
|
|
488
|
+
从而永远删不掉。改成自己存、exec 时注入之后,这些问题连同"误删用户凭据"的风险
|
|
489
|
+
一起消失(见 [07-security.md](07-security.md) 第 10 条)。
|
|
490
|
+
- **值不由作者提供。** manifest 里没有放值的地方,从根上堵死"作者把密钥提交进仓库、
|
|
491
|
+
随 kit 分发给所有用户"。作者能做的只有声明"我需要这个变量",值一律由用户填。
|
|
492
|
+
- **`envs.json` 不并进 `registry.json`。** registry 是安装元数据(`remove` 即清),
|
|
493
|
+
用户填的值是用户数据。混在一起会让"重装即恢复"的语义变乱。
|
|
494
|
+
- **分桶键带 (kit, skill),因此不需要引用计数。** 删一个 skill 只删它自己那份,
|
|
495
|
+
不会波及同 kit 的其他 skill。key 必须带作用域:同名 skill 在全局与项目各装一份时,
|
|
496
|
+
各自的配置是独立的。
|
|
497
|
+
- **`conf_files` 就放在 skill 目录里**,承认它会被 `remove`/重装一起删掉。要长期保留的
|
|
498
|
+
数据应由脚本写到用户自己的目录——把用户数据搬出 store 会引入"配置目录 + 注入路径 +
|
|
499
|
+
升级时合并用户改动"一整套设计,而那是作者该决定的事,不该由 cckit 规定。
|
|
500
|
+
- **`envs` 这个名字留给虚拟环境。** 代码里 `envs` 早已指 `{runtime: env_dir}` 与
|
|
501
|
+
`~/.cckit/envs/`(venv 目录),`env_ok`、doctor 的 env 项、`CCKIT_ENV_DIR` 也都是这个
|
|
502
|
+
意思。所以"环境变量"一律用 `env`(单数):`kit_env` / skill 的 `env` / `envs.json`。
|
|
503
|
+
同一份 registry 记录里 `envs` 与 `env` 并存,这是刻意区分的,不是笔误。
|
|
504
|
+
- **版本号不变(`cckit: 1`)。** 顶层 schema 是 `additionalProperties: false`,所以改名后
|
|
505
|
+
仍写旧 `env:` 的 kit 会被新 schema **明确拒绝**安装,而不是静默忽略——可以接受的
|
|
506
|
+
失败方式。代价是"1"从此不再能表达兼容性边界(见下)。
|
|
507
|
+
|
|
508
|
+
**代价(必须记录)**:
|
|
509
|
+
|
|
510
|
+
- **`env` → `kit_env` 是破坏性改名。** 任何已发布的、用了顶层 `env:` 的 kit,在新版
|
|
511
|
+
cckit 下会被 schema 拒绝安装,作者需要改字段名。因为 cckit 尚在 0.x 且生态未铺开,
|
|
512
|
+
判断为可接受;官方 kit-builder 的规范文档、模板与自检清单已同步更新。
|
|
513
|
+
- **`conf_files` 里的用户改动会随卸载/重装丢失。** 这是明确接受的限制,已在
|
|
514
|
+
manifest-spec 与 kit-authoring 里以警告形式写给作者。
|
|
515
|
+
- **`installed` 态(无 link)与 `managed=False` 的 skill 不允许改配置。** 前者尚未启用,
|
|
516
|
+
后者不是 cckit 管的。UI 禁用之外,服务端也重新校验一遍——UI 禁用了不代表可以信任
|
|
517
|
+
客户端传来的请求。
|
|
518
|
+
|
|
460
519
|
## 我的判断失误汇总
|
|
461
520
|
|
|
462
521
|
集中列出,便于后续开发者校准对本文档其余部分的信任度:
|
|
@@ -106,6 +106,48 @@ Web 管理界面能改 CC 行为、能触发安装(而安装会执行仓库作
|
|
|
106
106
|
**绝不能监听 `0.0.0.0`。** 确需远程访问必须加鉴权。这条要写在用户文档显眼处,
|
|
107
107
|
不能默认放开让用户自己发现。
|
|
108
108
|
|
|
109
|
+
### 10. 用户配置:注入点是 `exec`,写入面只有 skill 目录
|
|
110
|
+
|
|
111
|
+
skill 需要的用户配置(环境变量的值、可改的配置文件)有两个新面:
|
|
112
|
+
|
|
113
|
+
**a) 环境变量的值不写 `settings.json`。** 最初的设想是把值写进 CC `settings.json`
|
|
114
|
+
的 `env` 键,被否决:那个键是用户的核心配置,写进去就要处理"哪些变量是 cckit 写的"
|
|
115
|
+
(基线快照 + 引用计数),而快照抓不住用户事后手改、基线丢了又会把 cckit 自己写的变量
|
|
116
|
+
误判成用户原有的。改为 cckit 自己存 (`envs.json`) 并在 `cckit exec` 时注入,
|
|
117
|
+
上述问题连同"误删用户凭据"的风险一起消失。
|
|
118
|
+
|
|
119
|
+
**b) 保存配置文件必须服务端校验路径。** Web 面板能改 skill 目录里的文件,这是一个
|
|
120
|
+
**任意文件写入**的潜在入口。两道闸缺一不可:
|
|
121
|
+
|
|
122
|
+
- 路径必须**逐字命中** registry 快照里的 `conf_files` 声明 —— 客户端传来的一律不可信,
|
|
123
|
+
"装的时候声明过"不等于"这次传的就是那一条";
|
|
124
|
+
- 解析(`resolve`)之后仍要落在 skill 目录内 —— 防 `..` 与符号链接逃逸。
|
|
125
|
+
|
|
126
|
+
安装时 `semantic_check` 会先拦一遍(拒绝绝对路径与 `..`),但那只是作者侧的第一道;
|
|
127
|
+
文件系统在安装之后仍可能变化,所以运行期必须重新校验。
|
|
128
|
+
|
|
129
|
+
**c) 值不在终端回显。** `cckit list --envs` 与 `cckit env <skill>` 只显示
|
|
130
|
+
"变量名 + 是否必需 + 已设/未设",不回显明文 —— 否则密钥会进终端 scrollback 与日志。
|
|
131
|
+
面板里的值绑定在 127.0.0.1 上传输(见第 9 条)。
|
|
132
|
+
|
|
133
|
+
**d) manifest 里没有放值的地方。** `kit_env` / `env` 只有 `name` / `required` /
|
|
134
|
+
`description`,没有 `value` / `default`。这从根上堵死了"作者把自己的密钥提交进仓库、
|
|
135
|
+
随 kit 分发给所有用户"。作者能做的只有声明"我需要这个变量"。
|
|
136
|
+
|
|
137
|
+
### 11. 管理员通知的内容等同公开
|
|
138
|
+
|
|
139
|
+
`cckit web --notice TITLE FILE` 让运维在面板顶部挂一条公告。两点必须写进用户文档:
|
|
140
|
+
|
|
141
|
+
- **能访问面板的人都看得到 `FILE` 的内容。** 默认只绑 `127.0.0.1` 时还好,但文档是
|
|
142
|
+
明确支持 `--host 0.0.0.0` 部署的 —— 那时公告就是公开的。**不要往公告文件里放密钥。**
|
|
143
|
+
- **正文按纯文本渲染,不走 HTML 也不走 Markdown。** 文件内容原样进 `<pre>`,既不能
|
|
144
|
+
执行脚本,也不会因为解析器的某个 bug 变成注入点。每多支持一种富文本格式就多一个
|
|
145
|
+
XSS 面,而这个功能并不需要它。
|
|
146
|
+
|
|
147
|
+
实现上另有两道防御:`--notice` 的 TITLE 会被注入 `index.html`,所以对 `<` / `>` / `&`
|
|
148
|
+
做了转义(与 `--base` 同一套 `_js_string`),防止标题里的 `</script>` 跳出去;正文读取
|
|
149
|
+
有 256 KiB 上限、用 `errors="replace"` 解码,免得一个非 UTF-8 文件把面板打挂。
|
|
150
|
+
|
|
109
151
|
## alt 流程的安全边界(非标准仓库导入)
|
|
110
152
|
|
|
111
153
|
`--alt` 会在安装前调用 Claude Code 去改造并审计一个**临时目录里**的仓库。它没有
|
|
@@ -42,10 +42,15 @@ CC 实际 不加载
|
|
|
42
42
|
|---|---|---|
|
|
43
43
|
| 装了哪些 kit、版本、sha、来源 | `registry.json` | 观测不出来,必须存 |
|
|
44
44
|
| env 路径映射(runtime → env_dir)| `registry.json` | 同上 |
|
|
45
|
+
| 声明快照(`kit_env` / `env` / `conf_files` / `needs`)| `registry.json` | 从 manifest 抄一份,免得 list/Web 每次现场解析 |
|
|
45
46
|
| 用量统计 | `registry.json` | 同上 |
|
|
47
|
+
| **用户填的环境变量值** | `envs.json` | 用户的输入,观测不出来;与安装元数据分开存 |
|
|
46
48
|
| 团队期望装什么 | `cckit.lock` | 这是声明,不是现状 |
|
|
47
49
|
| **是否启用 / name-only / off** | **文件系统 + settings.json** | 观测得到,存了会漂移 |
|
|
48
50
|
|
|
51
|
+
> `envs.json` 单独一个文件、不并进 `registry.json`:registry 是**安装元数据**
|
|
52
|
+
> (`remove` 即清),用户填的值是**用户数据**,混在一起会让"重装即恢复"的语义变乱。
|
|
53
|
+
|
|
49
54
|
## API 契约
|
|
50
55
|
|
|
51
56
|
```python
|
|
@@ -64,13 +69,33 @@ class SkillState:
|
|
|
64
69
|
is_global_skill: bool = False # project 作用域下,此条目是「全局 skill 的项目覆盖/跟随」
|
|
65
70
|
global_state: str | None = None # 全局 skill 在全局作用域的状态
|
|
66
71
|
override: bool = False # 全局 skill 是否带项目级覆盖(off/name-only)
|
|
72
|
+
envs: list[dict] = [] # skill 级环境变量声明(name/required/description)
|
|
73
|
+
conf_files: list[str] = [] # 可修改的配置文件,相对 skill 根
|
|
74
|
+
missing_env: list[str] = [] # 声明 required 却还没值的变量名(CLI/Web 的提醒就靠它)
|
|
67
75
|
|
|
68
76
|
def list_skills(scope=None, root=None) -> list[SkillState]: ...
|
|
69
77
|
def get_state(name, scope, root=None) -> str: ...
|
|
70
78
|
def set_state(name, state, scope, root=None) -> None: ... # 带锁 + 原子写
|
|
71
79
|
def budget(scope=None, root=None) -> tuple[int, int]: ... # (已用字符, 上限)
|
|
80
|
+
|
|
81
|
+
# 用户填的环境变量值(envs.json,带锁 + 原子写)
|
|
82
|
+
def set_user_env(name, value, *, kit, skill=None, scope='global', root=None) -> None: ...
|
|
83
|
+
def remove_user_envs(kit, scope='global', *, skill=None, root=None) -> None: ...
|
|
84
|
+
def stored_env(scope, kit, skill=None, root=None) -> dict[str, str]: ...
|
|
85
|
+
def env_requirements(kit, skill, scope='global', root=None) -> list[EnvRequirement]: ...
|
|
86
|
+
def missing_required_env(kit_info, skill_rec, values) -> list[str]: ...
|
|
87
|
+
def env_scope_of(s) -> str: ... # 该条目的值存在哪个作用域(全局 skill 的项目视图仍是 global)
|
|
88
|
+
|
|
89
|
+
# 可修改的配置文件(conf_files)
|
|
90
|
+
def ensure_config_editable(scope, root, kit, skill) -> None: ...
|
|
91
|
+
def conf_files(kit, skill) -> list[str]: ...
|
|
92
|
+
def read_conf_file(kit, skill, rel) -> str: ...
|
|
93
|
+
def write_conf_file(kit, skill, rel, content) -> None: ... # 原子替换
|
|
72
94
|
```
|
|
73
95
|
|
|
96
|
+
⚠️ `envs` 与 `env` 是**两个不同的东西**,只差一个字母:前者是 `{runtime: env_dir}`
|
|
97
|
+
(虚拟环境目录),后者是环境变量声明。同一份 registry 记录里两者并存,别混。
|
|
98
|
+
|
|
74
99
|
`list_skills()` 必须同时列出**非 cckit 管理**的 skill,标记 `managed=False`。
|
|
75
100
|
用户看到的是完整工具箱视图,但只有 cckit 装的能被开关。
|
|
76
101
|
|
|
@@ -106,11 +131,17 @@ def budget(scope=None, root=None) -> tuple[int, int]: ... # (已用字符, 上
|
|
|
106
131
|
"version": "1.2.0",
|
|
107
132
|
"installed_at": "2026-08-27T02:10:00Z",
|
|
108
133
|
"store": "~/.cckit/store/video-toolkit",
|
|
134
|
+
"kit_env": [
|
|
135
|
+
{ "name": "OPENAI_API_KEY", "required": false, "description": "字幕润色" }
|
|
136
|
+
],
|
|
109
137
|
"skills": [
|
|
110
138
|
{ "name": "burn-subtitles",
|
|
111
139
|
"envs": { "python": "~/.cckit/envs/video-toolkit__burn-subtitles__python" },
|
|
112
|
-
"needs": ["ffmpeg", "python"]
|
|
113
|
-
|
|
140
|
+
"needs": ["ffmpeg", "python"],
|
|
141
|
+
"env": [{ "name": "FONT_DIR", "required": true, "description": "字体目录" }],
|
|
142
|
+
"conf_files": ["config.json"] },
|
|
143
|
+
{ "name": "describe-video", "envs": {}, "needs": [],
|
|
144
|
+
"env": [], "conf_files": [] }
|
|
114
145
|
],
|
|
115
146
|
"known_scopes": ["global", "C:/work/proj-a"],
|
|
116
147
|
"override_scopes": []
|
|
@@ -119,6 +150,33 @@ def budget(scope=None, root=None) -> tuple[int, int]: ... # (已用字符, 上
|
|
|
119
150
|
}
|
|
120
151
|
```
|
|
121
152
|
|
|
153
|
+
注意 `envs`(虚拟环境目录)与 `env`(环境变量声明)并存 —— 前者由 `installer.build_envs`
|
|
154
|
+
建好后写入,后者是从 manifest 抄来的声明快照。
|
|
155
|
+
|
|
156
|
+
## `envs.json` 结构
|
|
157
|
+
|
|
158
|
+
用户在 CLI(`cckit env`)或 Web 面板里填的环境变量值。按
|
|
159
|
+
`{作用域}|{kit}` 与 `{作用域}|{kit}|{skill}` 分桶;作用域是 `"global"` 或项目根绝对路径
|
|
160
|
+
(与 `known_scopes` 的表示一致)。
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"version": 1,
|
|
165
|
+
"kit_env": {
|
|
166
|
+
"global|video-toolkit": { "OPENAI_API_KEY": "sk-..." }
|
|
167
|
+
},
|
|
168
|
+
"skill_env": {
|
|
169
|
+
"global|video-toolkit|burn-subtitles": { "FONT_DIR": "D:/fonts" }
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
- **按 (kit, skill) 分桶意味着不需要引用计数**:删一个 skill 只删它自己那份,
|
|
175
|
+
不会波及同 kit 的其他 skill。`remove_kit` 会把这个 kit 的 kit 桶与全部 skill 桶一起清掉
|
|
176
|
+
(除非 `--keep-env`)。
|
|
177
|
+
- 读取顺序:`stored_env()` 先取 kit 桶打底、再叠加 skill 桶(同名以 skill 级为准)。
|
|
178
|
+
- 与写 `settings.json` 同一套纪律:**文件锁 + 原子替换**。空桶会被顺手删掉。
|
|
179
|
+
|
|
122
180
|
`skills[].envs` 是 `runtime → env_dir` 的映射。一个 skill 可同时有 `python` 与
|
|
123
181
|
`node` 两个 env(各自独立目录);纯 prompt skill 为 `{}`。
|
|
124
182
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Web 管理面板
|
|
2
2
|
|
|
3
|
-
配套 v0.3.
|
|
3
|
+
配套 v0.3.2 的可选管理面板:平时展示 skill 列表,支持导入(add)、卸载(remove)、
|
|
4
4
|
四态开关切换、诊断(doctor)。**纯增量**——不装 `[web]` 额外依赖时,`cckit` 本体
|
|
5
5
|
与命令行工具完全不变。
|
|
6
6
|
|
|
@@ -38,7 +38,7 @@ FastAPI (src/cckit/web/) ── 静态托管 web/dist/
|
|
|
38
38
|
│ ├─ cckit.installer └── POST /api/doctor (SSE)
|
|
39
39
|
│ └─ cckit.doctor
|
|
40
40
|
▼
|
|
41
|
-
~/.cckit/ store + registry.json + projects.json + envs
|
|
41
|
+
~/.cckit/ store + registry.json + projects.json + envs/ + envs.json
|
|
42
42
|
<CC 配置目录>/skills + settings.json (状态派生源)
|
|
43
43
|
```
|
|
44
44
|
|
|
@@ -53,8 +53,13 @@ FastAPI (src/cckit/web/) ── 静态托管 web/dist/
|
|
|
53
53
|
|---|---|---|
|
|
54
54
|
| `GET /api/scopes` | `state.list_scopes()` | 侧栏作用域(全局 + 历史项目 + 关注项目) |
|
|
55
55
|
| `POST/DELETE /api/scopes` | `projects.add/remove` | 关注/取关项目,add 时建 `.claude` |
|
|
56
|
-
| `GET /api/skills?scope=&root=` | `state.list_skills` + `state.budget` | 列表 + 预算一次返回;skill 带 `is_global_skill`/`global_state`/`override` |
|
|
56
|
+
| `GET /api/skills?scope=&root=` | `state.list_skills` + `state.budget` | 列表 + 预算一次返回;skill 带 `is_global_skill`/`global_state`/`override`/`envs`/`conf_files`;另含 `kit_env`(按 kit 名索引的 kit 级声明) |
|
|
57
57
|
| `POST /api/skills/{name}/state` | `state.set_state` | 四态切换,返回 `{message}` |
|
|
58
|
+
| `GET /api/config?scope=&kit=&skill=` | `state.env_requirements` + `state.conf_files` | 配置需求 + 当前值;`skill` 省略时只返回 kit 级(`kit_env`) |
|
|
59
|
+
| `POST /api/config/env` | `state.set_user_env` | 保存/清除一个环境变量的值 |
|
|
60
|
+
| `GET /api/config/conf?scope=&kit=&skill=&path=` | `state.read_conf_file` | 读一个可修改的配置文件 |
|
|
61
|
+
| `PUT /api/config/conf` | `state.write_conf_file` | 写回(服务端校验路径,见下) |
|
|
62
|
+
| `GET /api/info` | 读 `--notice` 指定的文件 | 管理员通知正文。**没配 `--notice` 时 404**,前端据此不渲染控件 |
|
|
58
63
|
| `GET /api/kits` | `registry.load()` | kit 头部元信息 |
|
|
59
64
|
| `POST /api/kits/{kit}/remove` | `installer.remove_kit` | 卸载 |
|
|
60
65
|
| `POST /api/add/preview` | `installer.stage_install` | 克隆+校验+计划,存 `preview_id` |
|
|
@@ -149,17 +154,42 @@ src/
|
|
|
149
154
|
lib/utils.ts # cn()
|
|
150
155
|
hooks/useSSE.ts # 消费 SSE 流(data: {json} 帧解析)
|
|
151
156
|
components/
|
|
152
|
-
AppSidebar / KitList / AddKitDialog / DoctorDialog / AddScopeDialog
|
|
153
|
-
ui/ # shadcn 组件(button/dialog/dropdown-menu/tooltip/input/
|
|
154
|
-
# badge/progress/separator/popover/sonner/sidebar/sheet/skeleton)
|
|
157
|
+
AppSidebar / KitList / AddKitDialog / DoctorDialog / AddScopeDialog / NoticeMenu
|
|
158
|
+
ui/ # shadcn 组件(button/dialog/dropdown-menu/tooltip/input/textarea/
|
|
159
|
+
# card/badge/progress/separator/popover/sonner/sidebar/sheet/skeleton)
|
|
155
160
|
```
|
|
156
161
|
|
|
157
162
|
- **布局**:dashboard 式——官方 `Sidebar`(variant=inset)+ 右侧 `SidebarInset`。
|
|
158
163
|
Sidebar 内:Header(CCKitKit + 版本)、4 个分组(作用域 / 添加关注项目 / Kit 管理 /
|
|
159
164
|
刷新)、Footer(清单预算,收起时变圆环);右侧顶部 `SidebarTrigger` 收起/展开。
|
|
165
|
+
- **管理员通知**(`cckit web --notice TITLE FILE`,没配就完全不渲染):
|
|
166
|
+
在右侧 **`Skills` 那一行的最右端**。位置选这里的理由:这行 header 在 `SidebarInset` 里,
|
|
167
|
+
与 `<Sidebar>` 是兄弟节点,所以**收起侧栏不影响它**,而且它在滚动容器之外,始终可见。
|
|
168
|
+
控件用 `Dialog` + `DialogTrigger` + `Button`(都是已装的官方组件)拼成:按钮用
|
|
169
|
+
**`default`(`primary`)变体**让它在 header 里足够显眼,左侧一个 `Megaphone` 图标,
|
|
170
|
+
右侧两行——第一行 `管理员通知`,第二行是 `TITLE`。图标与文字都用按钮自己的
|
|
171
|
+
`primary-foreground`(标签行取 70% 那一档),不另指定灰色,免得压在彩色底上发糊。
|
|
172
|
+
按钮宽度是 `w-1/2`,即**内容区宽度的一半**(用百分比而非固定值:这样侧栏收起/展开时
|
|
173
|
+
它自动跟着变,不需要读侧栏状态);标题超出用 `truncate` 截断,完整标题在弹窗里。
|
|
174
|
+
点击弹窗以**纯文本**(`<pre>`)显示 `FILE` 内容。
|
|
175
|
+
标题由后端启动时注入、**首屏即渲染**;正文在打开弹窗时才请求,所以改了公告不用重启。
|
|
160
176
|
- **列表**:项目 kit 可收起/展开/卸载(卸载用 Popover + destructive 确认);skill
|
|
161
177
|
四态选择器(`name-only` 附解释)、`env_ok=False` 警示、`managed=False` 置灰只读;
|
|
162
178
|
全局 skill 单独折叠一组、无卸载按钮、用覆盖选择器。
|
|
179
|
+
名字旁边有两类互不相同的提示图标:
|
|
180
|
+
- 🔴 **红色 `Warning`** —— `env_ok === false`,运行环境(venv)缺失或损坏,去「诊断」修;
|
|
181
|
+
- 🔑 **琥珀色 `Key`** —— `missing_env` 非空,有声明 `required: true` 的环境变量还没填。
|
|
182
|
+
Tooltip 列出变量名并提示"点右侧齿轮填写"。**只是提醒不是报错**,所以用琥珀色与红色
|
|
183
|
+
区分开——点齿轮就能解决,不用离开这一屏。
|
|
184
|
+
两者都只在真有事时出现,不给每一行加噪声。
|
|
185
|
+
- **配置管理**(齿轮图标 + 下拉,内容为空时显示「无」):
|
|
186
|
+
- **skill 级**:在**状态下拉左侧**。下拉分「环境变量」与「配置文件」两段;
|
|
187
|
+
点 env 行弹对话框改值(输入框 + 取消/保存),点 conf 行弹对话框预览与编辑
|
|
188
|
+
(Textarea + 取消/保存)。
|
|
189
|
+
- **kit 级**:在**卸载按钮左侧**,复用同一形态,只有环境变量(没有 `conf_files`)。
|
|
190
|
+
- 值在展开时才向后端取 —— 可能在别处改过,缓存会给出过期的默认值。
|
|
191
|
+
- `installed` 态(无 link)与 `managed=False` 的 skill 一律禁用;服务端也拦
|
|
192
|
+
(见 [07-security.md](07-security.md) 第 10 条)。
|
|
163
193
|
- **添加 Kit**:两阶段弹窗(表单 → 计划确认,lint error 禁用安装 → SSE 日志)。
|
|
164
194
|
- **诊断**:`--fix` 勾选 + SSE 进度 + findings 结果。
|
|
165
195
|
- **刷新三层**:侧栏刷新按钮 + 写操作后 `invalidateQueries` 自动重拉 + 可选轮询。
|
|
@@ -54,8 +54,9 @@
|
|
|
54
54
|
|
|
55
55
|
## 当前状态
|
|
56
56
|
|
|
57
|
-
**v0.3.
|
|
58
|
-
`disable` / `name-only` / `remove` / `doctor` / `exec` / `web`)
|
|
57
|
+
**v0.3.2 已实现**:`cckit` 命令行工具与全部 10 个命令(`add` / `list` / `env` /
|
|
58
|
+
`enable` / `disable` / `name-only` / `remove` / `doctor` / `exec` / `web`),
|
|
59
|
+
`uv run cckit --help` 可用。(0.2.0因为打包失误,版本号被弃用)
|
|
59
60
|
|
|
60
61
|
已落地模块(`src/cckit/`):
|
|
61
62
|
|
|
@@ -64,15 +65,15 @@
|
|
|
64
65
|
- `env` —— uv venv / node env 与解释器解析
|
|
65
66
|
- `installer` —— add 全流程(锁 sha、计划确认、store/env/postinstall/registry/link)
|
|
66
67
|
- `alt` —— 非标准仓库导入(前置条件 → 物化 → kit-builder 改造 → 审计 → 复用本地安装)
|
|
67
|
-
- `exec` —— skill 脚本统一入口(白名单 +
|
|
68
|
-
- `state` —— 四态派生 + 文件锁 + 原子写 + 清单预算
|
|
68
|
+
- `exec` —— skill 脚本统一入口(白名单 + 环境变量注入:`envs.json` 优先,回落进程环境)
|
|
69
|
+
- `state` —— 四态派生 + 文件锁 + 原子写 + 清单预算 + 用户配置(envs.json / conf_files)
|
|
69
70
|
- `registry` —— registry.json 原子读写
|
|
70
71
|
- `lint` —— 命名 / description / CRLF / prompt injection / typosquatting
|
|
71
72
|
- `doctor` —— 只读诊断 + 安全修复
|
|
72
73
|
- `projects` —— 关注项目清单 projects.json 原子读写
|
|
73
|
-
- `web` —— Web 管理面板后端(FastAPI,惰性 import,`[web]`
|
|
74
|
+
- `web` —— Web 管理面板后端(FastAPI,惰性 import,`[web]` 可选依赖;含配置读写与管理员通知端点)
|
|
74
75
|
|
|
75
|
-
测试:`tests/` 下
|
|
76
|
+
测试:`tests/` 下 189 项,`uv run pytest -q` 全绿;`Docs/examples/video-toolkit` 作为夹具。
|
|
76
77
|
|
|
77
78
|
## v0.1 范围
|
|
78
79
|
|
|
@@ -102,6 +103,26 @@
|
|
|
102
103
|
「允许导入非标准仓库」检测不到 `skills/kit-builder`、无法给出安装选项的问题。
|
|
103
104
|
- **修复安装弹窗残留状态**:安装成功后关闭弹窗,再次打开不再显示上一次的「安装成功」。
|
|
104
105
|
|
|
106
|
+
## v0.3.2 范围
|
|
107
|
+
|
|
108
|
+
- **skill 级用户配置(`kit_env` / `env` / `conf_files`)**:作者在 manifest 里只**声明**
|
|
109
|
+
需要哪些环境变量、哪些文件用户可改;值由用户在 `cckit env` 或 Web 面板里填,存在
|
|
110
|
+
`~/.cckit/envs.json`,由 `cckit exec` 注入——**不写 CC 的 `settings.json`**。
|
|
111
|
+
配套:`cckit list` 的 `[env]` / `[envs]` / `[conf_files]` 标记与 `--envs` / `--confs`
|
|
112
|
+
明细、「缺必需变量」提醒、Web 上每个 kit / skill 的配置入口。
|
|
113
|
+
⚠️ **顶层 `env` 改名为 `kit_env`**,旧字段名的 kit 会被 schema 直接拒绝(见 D-17)。
|
|
114
|
+
详见 [05](05-design-log.md) 的 D-17、[09](09-state-api.md)、[cli-spec](cli-spec.md)。
|
|
115
|
+
- **管理员通知(`cckit web --notice TITLE FILE`)**:面板顶部(`Skills` 那一行最右端)
|
|
116
|
+
挂一条公告,点开看文件内容;不传该参数就完全不渲染。⚠️ 内容对所有能访问面板的人可见。
|
|
117
|
+
详见 [11](11-web-panel.md)、[07](07-security.md)。
|
|
118
|
+
- **同名 skill 明确报错**:同一作用域内已存在同名 skill 时,安装阶段直接拒绝并点名占用者,
|
|
119
|
+
不再静默跳过 link(那会让新装的 skill 永远不生效,且此后按名操作全部歧义报错)。
|
|
120
|
+
详见 [cli-spec](cli-spec.md) 的「必须拦截的情况」。
|
|
121
|
+
- **kit-builder 改造更准**:补上一套可执行的「从代码里找环境变量与可配置文件」流程
|
|
122
|
+
(逐个脚本搜读取点、判定 kit 级还是 skill 级、`required` 怎么定),并要求逐条给出依据;
|
|
123
|
+
`--alt` 的改造 / 审计提示词同步收紧,漏声明现在会导致审计不通过。
|
|
124
|
+
规范与流程见 [`../skills/kit-builder/`](../skills/kit-builder/)。
|
|
125
|
+
|
|
105
126
|
**推迟到 v0.4+**:`cckit.lock` 与 `sync`、`profile`、`update` 的 diff 展示、
|
|
106
127
|
用量统计。
|
|
107
128
|
|
|
@@ -84,15 +84,24 @@ cckit add ./my-skill --local --alt
|
|
|
84
84
|
- 当前平台不在 `platforms` 内 → 拒绝,不等装完才发现
|
|
85
85
|
- 系统依赖缺失 → 报告并给**当前平台**的 hint,询问是继续(env 仍可建)还是中止
|
|
86
86
|
- link 目标已存在真实目录 → 报错说明这是用户手写的 skill,不覆盖
|
|
87
|
-
-
|
|
87
|
+
- **同作用域已存在同名 skill → 拒绝安装**。CC 的 skill 名字空间是单层的(link 落点
|
|
88
|
+
是 `<skills_dir>/<name>`,没有 kit 前缀),一个名字在一个作用域内只能属于一个 kit。
|
|
89
|
+
不拦的后果是静默失效:`state.set_state` 见到已有 link 直接 `pass`,后装的 skill
|
|
90
|
+
只写进 registry 却永远建不上 link(在 `list` 里显示为 installed),此后按名操作
|
|
91
|
+
(`enable` / `disable` / `exec`)还会因归属歧义报错。报错需点名占用者(哪个 kit、
|
|
92
|
+
悬空 link、还是用户手写的目录)并给出释放该名字的办法;`--only` 排除掉的 skill
|
|
93
|
+
本次不建 link,不参与检查。检查看的是**目标作用域的名字有没有被 link 占用**,
|
|
94
|
+
与 `--no-enable` 无关(该名字在这个作用域已注定建不上 link)。
|
|
95
|
+
- **项目安装时存在同名全局 skill → 明确警告"全局会覆盖项目版"**(跨作用域同名是
|
|
96
|
+
允许的,由 CC 的优先级决定谁生效,不属于上一条的拒绝范围)
|
|
88
97
|
|
|
89
98
|
## `cckit list`
|
|
90
99
|
|
|
91
100
|
```
|
|
92
101
|
$ cckit list
|
|
93
102
|
|
|
94
|
-
video-toolkit 1.2.0
|
|
95
|
-
● burn-subtitles enabled env ok
|
|
103
|
+
video-toolkit 1.2.0 [env]
|
|
104
|
+
● burn-subtitles enabled env ok [envs] [conf_files] ⚠ 缺必需变量 FONT_DIR → cckit env
|
|
96
105
|
◐ describe-video name-only prompt-only
|
|
97
106
|
doc-tools 0.4.1 (sha a1b2c3d)
|
|
98
107
|
○ pdf-extract off env ok
|
|
@@ -106,9 +115,59 @@ doc-tools 0.4.1 (sha a1b2c3d)
|
|
|
106
115
|
|
|
107
116
|
选项:`--project` 只列项目;`--all` 全作用域;`--json` 机器可读。
|
|
108
117
|
|
|
118
|
+
**依赖标记**:kit 行末尾的 `[env]` 表示该 kit 有 `kit_env` 声明;skill 行末尾的
|
|
119
|
+
`[envs]` / `[conf_files]` 表示该 skill 有相应声明。没有就不显示,不给每一行加噪声。
|
|
120
|
+
|
|
121
|
+
**缺配置提醒**:skill 行末尾的 `⚠ 缺必需变量 <名字> → cckit env` 表示该 skill 生效的
|
|
122
|
+
环境变量里有声明 `required: true` 却还没值的(见下)。判定口径与 `cckit exec` 注入时完全
|
|
123
|
+
一致:kit 级与 skill 级声明都算、同名以 skill 级为准、值先看 `envs.json` 再看进程环境。
|
|
124
|
+
没有未填的项就不显示这行 —— 与依赖标记同样是"只在真有事时出现"。
|
|
125
|
+
|
|
126
|
+
> 注意与 `env MISSING → cckit doctor` 区分:那个是**运行环境(venv)坏了**,要去诊断;
|
|
127
|
+
> 这个只是**变量还没填**,`cckit env` 填上即可。
|
|
128
|
+
|
|
129
|
+
**`--envs` / `--confs`** 在列表之后追加明细:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
$ cckit list --envs
|
|
133
|
+
|
|
134
|
+
[envs]
|
|
135
|
+
burn-subtitles
|
|
136
|
+
[kit ] OPENAI_API_KEY 可选 未设 用于字幕润色,不填则跳过
|
|
137
|
+
[skill] FONT_DIR 必需 已设 字幕字体所在目录
|
|
138
|
+
describe-video
|
|
139
|
+
无
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
⚠️ **只报"已设/未设",绝不回显值** —— 否则密钥会进终端 scrollback 与日志。
|
|
143
|
+
没有声明时显示「无」。
|
|
144
|
+
|
|
145
|
+
`--json` 每个 skill 额外带 `envs` / `conf_files`。
|
|
146
|
+
|
|
109
147
|
`--json` 应同时列出**非 cckit 管理**的 skill(用户手写、插件带的),标记为只读。
|
|
110
148
|
用户看到的是完整工具箱视图,但只有 cckit 装的能被开关。
|
|
111
149
|
|
|
150
|
+
## `cckit env <skill> [name] [value]`
|
|
151
|
+
|
|
152
|
+
查看 / 设置 / 清除 skill 需要的环境变量。
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
cckit env burn-subtitles # 列出声明与「已设/未设」
|
|
156
|
+
cckit env burn-subtitles FONT_DIR /usr/fonts # 设置
|
|
157
|
+
cckit env burn-subtitles FONT_DIR # 省略值则交互输入
|
|
158
|
+
cckit env burn-subtitles FONT_DIR --unset # 清除
|
|
159
|
+
cckit env burn-subtitles FONT_DIR --project # 作用于项目作用域
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
- 变量必须**已在 manifest 里声明**(`kit_env` 或 skill 的 `env`),不能凭空造 ——
|
|
163
|
+
否则就是往脚本环境里塞任意变量。
|
|
164
|
+
- 声明在 `kit_env` 里的写 **kit 桶**(整个 kit 共用一份);声明在 skill 里的写
|
|
165
|
+
**skill 桶**。同名时 skill 级覆盖 kit 级。
|
|
166
|
+
- 值存在 cckit 数据目录的 `envs.json`(锁 + 原子写),由 `cckit exec` 注入。
|
|
167
|
+
**不写 Claude Code 的 `settings.json`** —— 见 [07-security.md](07-security.md) 第 10 条。
|
|
168
|
+
- 取值优先级:`envs.json` > 调用方的进程环境。两处都没有且声明 `required: true`
|
|
169
|
+
时,`cckit exec` 报错中止(不静默跳过)。
|
|
170
|
+
|
|
112
171
|
实现上直接调 `cckit.state.list_skills()`,**不要自己扫目录**——该函数同时服务
|
|
113
172
|
Web 接口,两边必须共用同一份逻辑。
|
|
114
173
|
|
|
@@ -170,6 +229,14 @@ skill 脚本的统一入口。SKILL.md 里只写这一句,不写解释器路径
|
|
|
170
229
|
要点:cwd **保持调用方 cwd**(让用户给的相对路径正常工作),脚本自身资源通过
|
|
171
230
|
`CCKIT_SKILL_DIR` 定位。`scripts` 未在 manifest 声明的路径应拒绝执行。
|
|
172
231
|
|
|
232
|
+
除 `CCKIT_SKILL_DIR` / `CCKIT_KIT_DIR` / `CCKIT_ENV_DIR`(以及 node 的 `NODE_PATH`)
|
|
233
|
+
外,还注入 `kit_env` 与 skill 的 `env` 声明的环境变量:
|
|
234
|
+
|
|
235
|
+
- 同名时 **skill 级覆盖 kit 级**;
|
|
236
|
+
- 值先取用户在 CLI/Web 填的(`envs.json`),没有再回落调用方的进程环境;
|
|
237
|
+
- 声明 `required: true` 却两处都取不到 → **报错中止**,并给出 `cckit env` 的填写命令;
|
|
238
|
+
- `required: false` 且没值 → 不注入、不报错,由脚本自己决定跳过哪一步。
|
|
239
|
+
|
|
173
240
|
## `cckit web`
|
|
174
241
|
|
|
175
242
|
启动 Web 管理面板(需 `[web]` extra,缺失时提示 `uv tool install 'cckit[web]'`)。
|
|
@@ -179,6 +246,7 @@ skill 脚本的统一入口。SKILL.md 里只写这一句,不写解释器路径
|
|
|
179
246
|
cckit web # 前端后端一起起,打开 http://127.0.0.1:8000 即用
|
|
180
247
|
cckit web --host 0.0.0.0 --port 8000 # 部署到服务器
|
|
181
248
|
cckit web --base /cckit # 挂到根路径前缀 /cckit 下
|
|
249
|
+
cckit web --notice "维护通知" ./notice.md # 面板顶部挂一条管理员通知
|
|
182
250
|
```
|
|
183
251
|
|
|
184
252
|
| 选项 | 说明 |
|
|
@@ -187,6 +255,25 @@ cckit web --base /cckit # 挂到根路径前缀 /cckit 下
|
|
|
187
255
|
| `--port` | 端口,默认 `8000` |
|
|
188
256
|
| `--static-dir` | 前端静态产物目录(缺省不托管,配合 vite dev 使用) |
|
|
189
257
|
| `--base` | 根路径前缀(如 `/cckit`)。运行时把整站(`/api/*`、`/assets/*`)挂到该前缀下,反向代理只需原样透传 `/base/*`;用于把面板以 iframe 嵌入宿主 dashboard 的子路径而不与宿主 `/api` 冲突 |
|
|
258
|
+
| `--notice TITLE FILE` | 面板顶部显示一条**管理员通知**,点开看 `FILE` 的内容。不传就不显示任何控件 |
|
|
190
259
|
|
|
191
260
|
`--base` 是**运行时**配置:后端 serve 时把 `window.__CCKIT_BASE__` 注入 `index.html`,
|
|
192
261
|
前端据此拼 `/api` 前缀;前端资源用相对路径(`Vite base: "./"`)自动跟随子路径,无需重新构建。
|
|
262
|
+
|
|
263
|
+
### 管理员通知(`--notice`)
|
|
264
|
+
|
|
265
|
+
给运维一个"在面板上挂公告"的口子。**不传 `--notice` 时前后端都不做任何额外的事** ——
|
|
266
|
+
没有控件、没有额外请求。
|
|
267
|
+
|
|
268
|
+
- **启动时校验 `FILE` 是否存在**(不是普通文件就直接报错退出)。路径写错当场暴露,
|
|
269
|
+
不会等到用户点开弹窗才发现。
|
|
270
|
+
- 标题随 `index.html` 注入(`window.__CCKIT_NOTICE_TITLE__`),所以**首屏就画得出来**,
|
|
271
|
+
不会先空一下再冒出来;正文走 `GET /api/info` **按需取**,因此改了公告文件**不用重启服务**。
|
|
272
|
+
- 正文按**纯文本**返回、前端用 `<pre>` 渲染 —— 不解析 Markdown,也不走 HTML,
|
|
273
|
+
免得平白多一个 XSS 面。大小上限 256 KiB,非 UTF-8 用 `errors="replace"` 兜住。
|
|
274
|
+
- 没配 `--notice` 时 `/api/info` 返回 **404**,前端据此完全不渲染那个控件
|
|
275
|
+
(比返回空对象更能区分"没配置"和"配置了但没内容")。
|
|
276
|
+
|
|
277
|
+
⚠️ **通知内容对所有能访问面板的人都可见。** 默认只绑 `127.0.0.1` 没问题,但
|
|
278
|
+
`--host 0.0.0.0` 部署时它就是公开的 —— **不要往公告文件里放密钥**。见
|
|
279
|
+
[07-security.md](07-security.md)。
|
|
@@ -24,7 +24,9 @@ requires:
|
|
|
24
24
|
python:
|
|
25
25
|
file: requirements.txt
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
# kit 共用的环境变量:只声明名字与用途,值由用户在 CLI/Web 填写。
|
|
28
|
+
# 值存在 ~/.cckit/envs.json(不写 Claude Code 的 settings.json),cckit exec 时注入。
|
|
29
|
+
kit_env:
|
|
28
30
|
- name: OPENAI_API_KEY
|
|
29
31
|
required: false
|
|
30
32
|
description: 用于 describe-video 的字幕润色;不填则跳过该步骤
|
|
@@ -34,6 +36,11 @@ skills:
|
|
|
34
36
|
- name: burn-subtitles
|
|
35
37
|
needs: [ffmpeg, python]
|
|
36
38
|
scripts: [scripts/burn.py]
|
|
39
|
+
env: # skill 专属环境变量;与 kit_env 同名时以这里为准
|
|
40
|
+
- name: FONT_DIR
|
|
41
|
+
required: true
|
|
42
|
+
description: 字幕字体所在目录
|
|
43
|
+
conf_files: [config.json] # 相对 skill 根;用户可在 CLI/Web 里查看与修改
|
|
37
44
|
|
|
38
45
|
# 纯 prompt:needs 为空,装它不触发任何环境安装
|
|
39
46
|
- name: describe-video
|
|
@@ -16,7 +16,7 @@ flowchart TB
|
|
|
16
16
|
Manifest["manifest / schema · cckit.yaml 校验"]
|
|
17
17
|
Lint["lint · 安全检查"]
|
|
18
18
|
Env["env · 隔离环境"]
|
|
19
|
-
State["state · 四态派生 + 原子写"]
|
|
19
|
+
State["state · 四态派生 + 原子写 + 用户配置"]
|
|
20
20
|
Registry["registry · registry.json 读写"]
|
|
21
21
|
Link["link · 目录链接"]
|
|
22
22
|
ExecMod["exec · 脚本执行"]
|
|
@@ -28,6 +28,7 @@ flowchart TB
|
|
|
28
28
|
Store["store / kit / skill / SKILL.md"]
|
|
29
29
|
Envs["envs / kit__skill__runtime /"]
|
|
30
30
|
Reg["registry.json"]
|
|
31
|
+
UserEnv["envs.json / 用户填的环境变量值"]
|
|
31
32
|
Usage["usage.jsonl"]
|
|
32
33
|
end
|
|
33
34
|
|
|
@@ -55,9 +56,11 @@ flowchart TB
|
|
|
55
56
|
Registry --> Reg
|
|
56
57
|
State --> Usage
|
|
57
58
|
State -. 扫描 .-> Reg
|
|
59
|
+
State --> UserEnv
|
|
58
60
|
Link --> Store
|
|
59
61
|
Link --> Global
|
|
60
62
|
Link --> Project
|
|
61
63
|
ExecMod --> Store
|
|
62
64
|
ExecMod --> Envs
|
|
65
|
+
ExecMod --> UserEnv
|
|
63
66
|
```
|
|
@@ -25,7 +25,11 @@
|
|
|
25
25
|
"description": "缺省视为全平台支持"
|
|
26
26
|
},
|
|
27
27
|
"requires": { "$ref": "#/$defs/requires" },
|
|
28
|
-
"
|
|
28
|
+
"kit_env": {
|
|
29
|
+
"type": "array",
|
|
30
|
+
"items": { "$ref": "#/$defs/envVar" },
|
|
31
|
+
"description": "kit 共用的环境变量。只声明名字与用途,值由用户在 CLI/Web 填写"
|
|
32
|
+
},
|
|
29
33
|
"skills": {
|
|
30
34
|
"type": "array",
|
|
31
35
|
"minItems": 1,
|
|
@@ -117,7 +121,18 @@
|
|
|
117
121
|
"items": { "type": "string" },
|
|
118
122
|
"description": "python/node 触发环境安装;其余值须为 requires.system[].bin"
|
|
119
123
|
},
|
|
120
|
-
"scripts": { "type": "array", "items": { "type": "string" } }
|
|
124
|
+
"scripts": { "type": "array", "items": { "type": "string" } },
|
|
125
|
+
"env": {
|
|
126
|
+
"type": "array",
|
|
127
|
+
"items": { "$ref": "#/$defs/envVar" },
|
|
128
|
+
"description": "该 skill 专属的环境变量。与 kit_env 同名时 skill 级优先"
|
|
129
|
+
},
|
|
130
|
+
"conf_files": {
|
|
131
|
+
"type": "array",
|
|
132
|
+
"uniqueItems": true,
|
|
133
|
+
"items": { "type": "string" },
|
|
134
|
+
"description": "相对 skill 根目录的路径,标识可供用户修改的配置文件。不得逃逸出 skill 目录"
|
|
135
|
+
}
|
|
121
136
|
}
|
|
122
137
|
},
|
|
123
138
|
"postinstallStep": {
|