cckit 0.2.1__tar.gz → 0.3.0__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.0/.gitignore +7 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/.gitignore +4 -1
- {cckit-0.2.1 → cckit-0.3.0}/Docs/02-architecture.md +15 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/05-design-log.md +45 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/06-platform-findings.md +4 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/07-security.md +34 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/08-installation.md +12 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/11-web-panel.md +24 -1
- {cckit-0.2.1 → cckit-0.3.0}/Docs/README.md +10 -3
- {cckit-0.2.1 → cckit-0.3.0}/Docs/cli-spec.md +41 -0
- cckit-0.3.0/Docs/kit-development.md +12 -0
- cckit-0.3.0/Docs/test/hello-skill/SKILL.md +7 -0
- cckit-0.3.0/Docs/test/test-skill-dependency/.gitignore +5 -0
- cckit-0.3.0/Docs/test/test-skill-dependency/README.md +63 -0
- cckit-0.3.0/Docs/test/test-skill-dependency/json-pretty/SKILL.md +18 -0
- cckit-0.3.0/Docs/test/test-skill-dependency/json-pretty/scripts/pretty.js +12 -0
- cckit-0.3.0/Docs/test/test-skill-dependency/package.json +9 -0
- cckit-0.3.0/Docs/test/test-skill-dependency/plain-advisor/SKILL.md +12 -0
- cckit-0.3.0/Docs/test/test-skill-dependency/requirements.txt +1 -0
- cckit-0.3.0/Docs/test/test-skill-dependency/test-skill-dependency/SKILL.md +22 -0
- cckit-0.3.0/Docs/test/test-skill-dependency/test-skill-dependency/scripts/test.py +48 -0
- cckit-0.3.0/PKG-INFO +270 -0
- {cckit-0.2.1 → cckit-0.3.0}/README.md +25 -2
- {cckit-0.2.1 → cckit-0.3.0}/pyproject.toml +45 -38
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/__init__.py +1 -1
- cckit-0.3.0/src/cckit/alt.py +646 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/cli.py +15 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/env.py +10 -2
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/manifest.py +10 -1
- cckit-0.3.0/src/cckit/web/app.py +534 -0
- cckit-0.3.0/tests/test_alt.py +389 -0
- cckit-0.3.0/tests/test_env.py +33 -0
- cckit-0.3.0/tests/test_web_alt.py +126 -0
- {cckit-0.2.1 → cckit-0.3.0}/uv.lock +335 -2
- cckit-0.3.0/web/dist/assets/index-Cm-V9D5_.js +68 -0
- cckit-0.3.0/web/dist/assets/index-RaOeRefK.css +1 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/dist/index.html +2 -2
- {cckit-0.2.1 → cckit-0.3.0}/web/package-lock.json +2 -2
- {cckit-0.2.1 → cckit-0.3.0}/web/package.json +1 -1
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/AddKitDialog.tsx +306 -6
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/AppSidebar.tsx +1 -1
- {cckit-0.2.1 → cckit-0.3.0}/web/src/hooks/useSSE.ts +11 -1
- {cckit-0.2.1 → cckit-0.3.0}/web/src/lib/api.ts +77 -1
- cckit-0.2.1/.gitignore +0 -4
- cckit-0.2.1/Docs/kit-development.md +0 -6
- cckit-0.2.1/PKG-INFO +0 -12
- cckit-0.2.1/src/cckit/web/app.py +0 -291
- cckit-0.2.1/web/dist/assets/index-DlYI_0eV.js +0 -68
- cckit-0.2.1/web/dist/assets/index-TshdTLiY.css +0 -1
- {cckit-0.2.1 → cckit-0.3.0}/Docs/01-overview.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/03-manifest-spec.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/04-cli-spec.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/09-state-api.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/10-kit-authoring.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/examples/video-toolkit/cckit.yaml +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/pics/architecture.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/pics/directory-layout.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/pics/four-state-model.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/pics/install-flow.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/pics/pain-points-solution.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/pics/state-transitions.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/Docs/schema/cckit.schema.json +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/LICENSE +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/hatch_build.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/skills/kit-builder/cckit.yaml +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/skills/kit-builder/kit-builder/SKILL.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/skills/kit-builder/kit-builder/kit-authoring.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/skills/kit-builder/kit-builder/manifest-spec.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/skills/kit-builder/kit-builder/templates/SKILL.md +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/skills/kit-builder/kit-builder/templates/cckit.yaml +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/__main__.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/cckit.schema.json +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/config.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/doctor.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/errors.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/exec.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/installer.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/link.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/lint.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/projects.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/registry.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/schema.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/state.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/src/cckit/web/__init__.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/tests/conftest.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/tests/helpers.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/tests/test_budget.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/tests/test_exec.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/tests/test_installer.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/tests/test_link.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/tests/test_lint.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/tests/test_manifest.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/tests/test_registry.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/tests/test_state.py +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/.gitignore +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/components.json +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/index.html +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/App.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/AddScopeDialog.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/DoctorDialog.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/KitList.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/badge.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/button.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/card.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/dialog.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/dropdown-menu.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/input.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/popover.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/progress.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/separator.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/sheet.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/sidebar.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/skeleton.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/sonner.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/components/ui/tooltip.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/hooks/use-mobile.ts +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/index.css +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/lib/utils.ts +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/src/main.tsx +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/tsconfig.json +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/tsconfig.node.json +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/tsconfig.node.tsbuildinfo +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/tsconfig.tsbuildinfo +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/vite.config.d.ts +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/vite.config.js +0 -0
- {cckit-0.2.1 → cckit-0.3.0}/web/vite.config.ts +0 -0
cckit-0.3.0/.gitignore
ADDED
|
@@ -89,6 +89,21 @@ skill,全局 `--purge` 还会清掉它在各项目根留下的项目级覆盖(
|
|
|
89
89
|
**纯 prompt 类 skill 不创建 env。** 由 manifest 的 `needs: []` 表达,装它时完全不触发
|
|
90
90
|
环境安装。
|
|
91
91
|
|
|
92
|
+
## 非标准仓库导入(alt)
|
|
93
|
+
|
|
94
|
+
标准安装的唯一硬判据是仓库根目录有合法 `cckit.yaml`;没有它,`cckit add` 直接拒绝。
|
|
95
|
+
`--alt`(或 Web 的「允许导入非标准仓库」开关)是一条**显式开启的旁路**:
|
|
96
|
+
|
|
97
|
+
物化(pull/copy)→ kit-builder 改造 → 确定性校验 → Claude Code 审计 → 复用本地安装。
|
|
98
|
+
|
|
99
|
+
- **标准仓库不碰 LLM**:即使带 `--alt`,只要有 `cckit.yaml` 就走原确定性流程。
|
|
100
|
+
- **Claude Code 只做改造与审计,不做安装**:安装仍是 `stage_install → execute_install`
|
|
101
|
+
的确定性管线,审计失败/不明确即中止。
|
|
102
|
+
- **`alt.py` 是编排层**:负责前置条件(claude-agent-sdk 可导入 + 全局 `kit-builder`
|
|
103
|
+
处于 enabled)、临时目录生命周期、物化、Agent SDK 调用、事件转发、取消与清理;复用
|
|
104
|
+
`installer.stage_install` / `execute_install`,不复制安装逻辑。
|
|
105
|
+
- 安全边界见 [07-security.md](07-security.md);决策记录见 [05-design-log.md](05-design-log.md) 的 D-16。
|
|
106
|
+
|
|
92
107
|
## 状态真相来源
|
|
93
108
|
|
|
94
109
|
避免多处记录同一事实导致漂移:
|
|
@@ -409,6 +409,51 @@ Web 把全局 skill 单独折叠一组、用独立覆盖选择器(不复用四
|
|
|
409
409
|
|
|
410
410
|
---
|
|
411
411
|
|
|
412
|
+
## D-16 非标准仓库导入:显式开启的 alt 流程
|
|
413
|
+
|
|
414
|
+
**提出的问题**:普通 Skill 仓库通常不会为了 cckit 预先采用 `cckit.yaml` 目录结构,
|
|
415
|
+
于是 `cckit add` 对它们一律拒绝,扩展性受限。能否放宽?
|
|
416
|
+
|
|
417
|
+
**最终方案**:不放宽标准校验,而是加一个**显式开启**(`--alt` / Web 开关)、经过
|
|
418
|
+
前置条件检查、由 Claude Code 辅助改造的可选 `alt` 流程:
|
|
419
|
+
|
|
420
|
+
物化 → kit-builder 改造 → 确定性校验 → Claude Code 审计 → 复用本地安装。
|
|
421
|
+
|
|
422
|
+
标准仓库即使带 `--alt` 也走原流程、**不调用 Claude Code**——alt 只是"发现非标准时
|
|
423
|
+
允许转换",不是"所有仓库都过一遍 LLM"。
|
|
424
|
+
|
|
425
|
+
**为什么这样定**:
|
|
426
|
+
|
|
427
|
+
- **不改 `manifest.py` 放宽校验。** 标准 Kit 的唯一硬判据仍是根目录有合法
|
|
428
|
+
`cckit.yaml`。alt 是标准安装之外的一条旁路,不是给标准校验松绑。这也保证了
|
|
429
|
+
D-01「确定性安装不碰 LLM」对标准仓库仍然成立。
|
|
430
|
+
- **Claude Code 只做改造与审计,不做安装。** 安装仍是 `stage_install →
|
|
431
|
+
execute_install` 的确定性管线。审计是语义层补充,不可绕过的安全闸门仍是
|
|
432
|
+
manifest 校验 + lint + 安装计划确认 + 回滚。
|
|
433
|
+
- **`kit-builder` 的唯一可信来源是当前源码树。** 同名 Skill 在网络上不可依赖,
|
|
434
|
+
所以自动安装只能等价 `cckit add <abs>/skills/kit-builder --local` 到全局。
|
|
435
|
+
检测到同名冲突、来源冲突、项目作用域安装时一律停止,不静默覆盖。
|
|
436
|
+
- **不伪造 SHA。** 改造后临时目录已非原始仓库状态,本地目录可能根本没有 Git。
|
|
437
|
+
alt 最终按本地目录交给安装接口,registry 不记录改造后 SHA,只保留原始来源 URL/ref。
|
|
438
|
+
- **权限用 `auto`,不设 `can_use_tool`、不用 `bypassPermissions`。** 一旦设了
|
|
439
|
+
`can_use_tool`,SDK 会把权限请求转交回调,`auto` 的自动判断就不再生效,退化成
|
|
440
|
+
逐工具人工确认。`auto` 是"由模型自动判断是否放行",不是无条件放行。
|
|
441
|
+
- **隔离仓库自带的 settings/MCP。** `cwd` 指向的是不可信仓库的副本,若照默认加载,
|
|
442
|
+
仓库里的 `.claude/settings.json`(权限 allow-list、additionalDirectories)与
|
|
443
|
+
`.mcp.json`(MCP 服务器)会被 Claude Code 读入,等于让仓库给自己授权、甚至借
|
|
444
|
+
MCP 初始化执行任意代码。故 `setting_sources=["user"]`(只加载用户级 settings,
|
|
445
|
+
含 kit-builder 的 enabled 态,跳过 project/local)+ `strict_mcp_config=True`
|
|
446
|
+
(忽略一切 MCP 配置)。
|
|
447
|
+
- **`cwd` 不是沙箱。** 它只是把 Agent 的工作目录限定在临时仓库,不能误认为完整
|
|
448
|
+
文件系统隔离。真正的防线仍是确定性校验 + 安装计划确认(与 D-02 一致)。
|
|
449
|
+
- **临时目录在最外层 `try/finally` 清理。** 成功、失败、取消、Ctrl+C 都要清掉
|
|
450
|
+
`cckit-alt-*` 目录,并关闭 SDK client 与底层 CLI 子进程。
|
|
451
|
+
|
|
452
|
+
**代价(必须记录)**:alt 在安装前多跑两次 LLM 调用(builder + audit),成本与
|
|
453
|
+
不确定性都比标准安装高;且 `auto` 权限模式下模型仍可能在临时仓库里执行
|
|
454
|
+
kit 作者诱导的操作。因此审计这一步聚焦 prompt injection / 敏感读取 / 外传 /
|
|
455
|
+
越界,并要求输出明确的 PASS/FAIL 结论,结论不明确一律视为不通过。
|
|
456
|
+
|
|
412
457
|
## 我的判断失误汇总
|
|
413
458
|
|
|
414
459
|
集中列出,便于后续开发者校准对本文档其余部分的信任度:
|
|
@@ -192,6 +192,10 @@ os.open(O_CREAT|O_EXCL) 加锁 + os.replace → 8 条完整保留
|
|
|
192
192
|
|
|
193
193
|
- **venv 布局**:Windows `.venv/Scripts/python.exe`,POSIX `.venv/bin/python`。
|
|
194
194
|
这是 `cckit exec` 存在的理由之一——SKILL.md 里不写解释器路径。
|
|
195
|
+
- **npm 是 .cmd(已实测)**:Windows 上 `subprocess.run(["npm", ...])` 抛
|
|
196
|
+
`FileNotFoundError`(WinError 2)——Python 的 `CreateProcess` 只能直接执行 `.exe`,
|
|
197
|
+
找不到 `.cmd`。`env.create_node_env` 已用 `cmd /c` 转发(不用 shell=True,避免
|
|
198
|
+
路径含空格时的注入)。实测 npm install 成功。
|
|
195
199
|
- **大小写敏感**:Linux 上 `Foo` 与 `foo` 是两个目录(已实测),Windows 上是一个。
|
|
196
200
|
故 skill 名强制小写 kebab-case,lint 拒大写。否则同一 kit 在 Linux 装出两个 skill、
|
|
197
201
|
在 Windows 装出一个。
|
|
@@ -106,6 +106,40 @@ Web 管理界面能改 CC 行为、能触发安装(而安装会执行仓库作
|
|
|
106
106
|
**绝不能监听 `0.0.0.0`。** 确需远程访问必须加鉴权。这条要写在用户文档显眼处,
|
|
107
107
|
不能默认放开让用户自己发现。
|
|
108
108
|
|
|
109
|
+
## alt 流程的安全边界(非标准仓库导入)
|
|
110
|
+
|
|
111
|
+
`--alt` 会在安装前调用 Claude Code 去改造并审计一个**临时目录里**的仓库。它没有
|
|
112
|
+
推翻上面的任何一条硬要求,只是在标准安装之前插入了一段 LLM 辅助的改造。额外的
|
|
113
|
+
边界如下:
|
|
114
|
+
|
|
115
|
+
- **标准仓库不碰 LLM。** 仓库根目录已有合法 `cckit.yaml` 时,即使带 `--alt` 也走
|
|
116
|
+
原确定性流程。alt 只在"没有 `cckit.yaml` 且显式开启"时触发。
|
|
117
|
+
- **权限是 `auto`,不是无条件放行。** `ClaudeAgentOptions(permission_mode="auto")`
|
|
118
|
+
由 Claude Code 自动判断每个工具调用是否放行。**不设置** `can_use_tool`(否则
|
|
119
|
+
回调会接管权限判断、退化成逐工具人工确认),**不使用** `bypassPermissions`。
|
|
120
|
+
- **`cwd` 只是工作目录,不是沙箱。** 它把 Agent 的工作目录限定在临时仓库,但不能
|
|
121
|
+
误认为完整文件系统隔离。SDK 的 sandbox 配置主要作用于 Bash 沙箱、依赖
|
|
122
|
+
macOS/Linux,而本项目重点环境是 Windows,故不采用 `bypassPermissions + sandbox`。
|
|
123
|
+
- **隔离仓库自带的 settings/MCP。** `cwd` 是不可信仓库的副本,必须阻止它自我授权:
|
|
124
|
+
`setting_sources=["user"]` 只加载用户级 settings(含 kit-builder 的 enabled 态),
|
|
125
|
+
跳过仓库自带的 `.claude/settings*.json`(权限 allow-list / additionalDirectories);
|
|
126
|
+
`strict_mcp_config=True` 忽略仓库自带的 `.mcp.json`,避免借 MCP 初始化执行任意代码。
|
|
127
|
+
- **确定性校验与安装计划确认仍是不可绕过的闸门。** 改造完成后依次跑
|
|
128
|
+
`manifest.load → validate_schema → semantic_check → lint`,审计通过后再走
|
|
129
|
+
`stage_install` 的安装计划展示与用户确认、`execute_install` 的回滚。审计失败、
|
|
130
|
+
无法完成或结论不明确时不得继续。
|
|
131
|
+
- **审计聚焦语义层威胁。** 重点看 `cckit.yaml` 是否忠实反映仓库内容、是否添加了
|
|
132
|
+
不必要或危险的 `postinstall`、是否存在 prompt injection / 敏感文件读取 /
|
|
133
|
+
外传数据 / 越界操作意图。
|
|
134
|
+
- **不记录改造后的 SHA。** 改造后的临时内容已非原始仓库状态,registry 保留原始
|
|
135
|
+
来源 URL / ref,但**不**把原始 SHA 误标为改造后内容的 SHA。
|
|
136
|
+
- **临时目录必然清理。** 成功、失败、取消、Ctrl+C 都在最外层 `try/finally` 清理
|
|
137
|
+
`cckit-alt-*` 目录,并关闭 SDK client 与底层 CLI 子进程。
|
|
138
|
+
|
|
139
|
+
> ⚠️ `--alt` 意味着在安装前,Claude Code 会拿着工具执行权限去读并改造一个陌生仓库。
|
|
140
|
+
> 它比标准安装多暴露一层"仓库内容影响一个带工具权限的 agent"的风险。请只对
|
|
141
|
+
> **你信任的来源**使用 `--alt`。
|
|
142
|
+
|
|
109
143
|
## 明确不做的事
|
|
110
144
|
|
|
111
145
|
### 不让 CC 读 README 自行配置环境
|
|
@@ -17,6 +17,18 @@ uv tool install cckit
|
|
|
17
17
|
**用户不需要预装 Python。** `uv` 是独立静态二进制,会自己拉 cckit 需要的 Python 3.12+。
|
|
18
18
|
安装前提只有 `uv` 一个。
|
|
19
19
|
|
|
20
|
+
## 可选 extra
|
|
21
|
+
|
|
22
|
+
cckit 本体只有 3 个依赖。两个可选功能各自独立成 extra,不装则完全不影响:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
uv tool install 'cckit[web]' # Web 管理面板(FastAPI + 前端静态产物)
|
|
26
|
+
uv tool install 'cckit[alt]' # 非标准仓库导入(--alt,含 claude-agent-sdk)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`--alt` 依赖 `claude-agent-sdk`,只在需要把普通 skill 仓库改造成 kit 时才需要;
|
|
30
|
+
未装该 extra 时,`cckit add <src> --alt` 会提示安装命令并以明确错误结束。
|
|
31
|
+
|
|
20
32
|
## 为什么是 `uv tool install`
|
|
21
33
|
|
|
22
34
|
### `pip install` 出局:Linux 上被 PEP 668 拒绝
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Web 管理面板
|
|
2
2
|
|
|
3
|
-
配套 v0.
|
|
3
|
+
配套 v0.3.0 的可选管理面板:平时展示 skill 列表,支持导入(add)、卸载(remove)、
|
|
4
4
|
四态开关切换、诊断(doctor)。**纯增量**——不装 `[web]` 额外依赖时,`cckit` 本体
|
|
5
5
|
与命令行工具完全不变。
|
|
6
6
|
|
|
@@ -60,6 +60,11 @@ FastAPI (src/cckit/web/) ── 静态托管 web/dist/
|
|
|
60
60
|
| `POST /api/add/execute` | `installer.execute_install` | 确认后执行,SSE 进度 |
|
|
61
61
|
| `DELETE /api/add/preview/{id}` | `StagedInstall.cleanup` | 取消时清理临时目录 |
|
|
62
62
|
| `POST /api/doctor` | `doctor.run(fix, on_event)` | SSE 进度 + findings |
|
|
63
|
+
| `GET /api/add/alt/check` | `alt.check_sdk_available` + `alt.kit_builder_status` | alt 开关的前置条件检查 |
|
|
64
|
+
| `POST /api/add/alt/fix` | `alt.apply_kit_builder_fix` | 修复 kit-builder(安装/切 enabled),重新校验前置条件防冲突/来源不一致 |
|
|
65
|
+
| `POST /api/add/alt/start` | `alt.run_alt_conversion`(后台线程) | 三阶段转换,SSE `alt_progress`/`alt_done`/`alt_error`/`alt_cancelled` |
|
|
66
|
+
| `POST /api/add/alt/cancel` | 取消标志 + `ClaudeSDKClient.interrupt` | 终止后台转换,等线程结束 + 清理 |
|
|
67
|
+
| `POST /api/add/alt/complete` | `installer.stage_install` | 转换结果交给现有本地安装流程 |
|
|
63
68
|
|
|
64
69
|
错误契约:`CckitError`(含 `InstallError`)统一捕获 → `{error:{message}}` + 400;
|
|
65
70
|
参数校验失败 → 422。前端只读 `message`,不依赖状态码区分。
|
|
@@ -116,6 +121,24 @@ CLI 与 Web 共用这套语义:CLI `list --project` 显示「项目覆盖 已关
|
|
|
116
121
|
已启用」;Web 把全局 skill 单独折叠成一组,用独立的覆盖选择器(不复用四态),只展示
|
|
117
122
|
当前全局状态下允许的选项。
|
|
118
123
|
|
|
124
|
+
### 非标准仓库导入(alt)
|
|
125
|
+
|
|
126
|
+
「添加 Kit」弹窗新增「允许导入非标准仓库」开关(默认关闭)。开启时立即执行与 CLI 一致的
|
|
127
|
+
前置条件检查:未装 `alt` extra → 提示 `uv tool install 'cckit[alt]'`;`kit-builder`
|
|
128
|
+
缺失/冲突/状态不合适 → 分别给出安装、修改或仅关闭的处理,开关保持关闭;全部满足才保持开启。
|
|
129
|
+
|
|
130
|
+
标准仓库不触发转换,直接复用原有「计划 → 确认 → 安装」流程。非标准仓库则进入三阶段
|
|
131
|
+
进度面板(准备仓库 / 改造仓库 / 审计结果),后端在**独立后台线程**里跑 `alt` 流程,
|
|
132
|
+
线程内部用 `asyncio.run()` 执行 Claude Agent SDK,通过线程安全队列 → 现有 SSE 机制把
|
|
133
|
+
结构化事件(`event: alt_progress`,含 `stage` / `kind` / `message`)推给前端。前端
|
|
134
|
+
**不依赖自由文本判断阶段状态**,只认结构化字段。
|
|
135
|
+
|
|
136
|
+
三阶段全部成功后「完成」才可点击;点击后把转换出的临时 Kit 交给现有 `stage_install`,
|
|
137
|
+
复用安装计划弹窗、lint 展示、确认与安装进度。「终止」不只断开 SSE:设置取消标志、
|
|
138
|
+
请求 `ClaudeSDKClient` 断开、等待后台线程结束、清理临时目录,并向前端发 `cancelled`。
|
|
139
|
+
转换、取消、出错、浏览器断开等路径都保证临时目录最终被清理,清理完成前不报告
|
|
140
|
+
「资源已全部释放」。
|
|
141
|
+
|
|
119
142
|
## 前端(`web/`)
|
|
120
143
|
|
|
121
144
|
```
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
|
|
55
55
|
## 当前状态
|
|
56
56
|
|
|
57
|
-
**v0.
|
|
57
|
+
**v0.3.0 已实现**:`cckit` 命令行工具与全部 9 个命令(`add` / `list` / `enable` /
|
|
58
58
|
`disable` / `name-only` / `remove` / `doctor` / `exec` / `web`),`uv run cckit --help` 可用。(0.2.0因为打包失误,版本号被弃用)
|
|
59
59
|
|
|
60
60
|
已落地模块(`src/cckit/`):
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
- `config` / `schema` / `manifest` —— 配置解析、JSON Schema + 语义校验
|
|
64
64
|
- `env` —— uv venv / node env 与解释器解析
|
|
65
65
|
- `installer` —— add 全流程(锁 sha、计划确认、store/env/postinstall/registry/link)
|
|
66
|
+
- `alt` —— 非标准仓库导入(前置条件 → 物化 → kit-builder 改造 → 审计 → 复用本地安装)
|
|
66
67
|
- `exec` —— skill 脚本统一入口(白名单 + 环境变量注入)
|
|
67
68
|
- `state` —— 四态派生 + 文件锁 + 原子写 + 清单预算
|
|
68
69
|
- `registry` —— registry.json 原子读写
|
|
@@ -71,7 +72,7 @@
|
|
|
71
72
|
- `projects` —— 关注项目清单 projects.json 原子读写
|
|
72
73
|
- `web` —— Web 管理面板后端(FastAPI,惰性 import,`[web]` 可选依赖)
|
|
73
74
|
|
|
74
|
-
测试:`tests/` 下
|
|
75
|
+
测试:`tests/` 下 126 项,`uv run pytest -q` 全绿;`Docs/examples/video-toolkit` 作为夹具。
|
|
75
76
|
|
|
76
77
|
## v0.1 范围
|
|
77
78
|
|
|
@@ -86,7 +87,13 @@
|
|
|
86
87
|
|
|
87
88
|
- Web 管理面板(`cckit web`):列表/导入/卸载/四态开关/诊断,iframe 融合(见 [11](11-web-panel.md))
|
|
88
89
|
|
|
89
|
-
|
|
90
|
+
## v0.3 范围
|
|
91
|
+
|
|
92
|
+
- 非标准仓库导入(`--alt` / Web 开关):对没有 `cckit.yaml` 的普通 skill 仓库,
|
|
93
|
+
由 Claude Code(kit-builder)改造 + 审计后复用现有安装流程;标准仓库不碰 LLM。
|
|
94
|
+
详见 [cli-spec](cli-spec.md)、[02](02-architecture.md) 的 alt 节、[05](05-design-log.md) 的 D-16。
|
|
95
|
+
|
|
96
|
+
**推迟到 v0.4+**:`cckit.lock` 与 `sync`、`profile`、`update` 的 diff 展示、
|
|
90
97
|
用量统计。
|
|
91
98
|
|
|
92
99
|
## 约定
|
|
@@ -36,8 +36,49 @@ cckit add ./local-kit --project --local
|
|
|
36
36
|
| `--no-enable` | 只装不启用(落到 `installed` 态) |
|
|
37
37
|
| `--project` | 装到当前项目而非全局 |
|
|
38
38
|
| `--only <skill,...>` | 只启用 kit 中的部分 skill |
|
|
39
|
+
| `--alt` | 允许导入非标准仓库(没有 `cckit.yaml` 的普通 skill 仓库),由 Claude Code 改造 |
|
|
39
40
|
| `-y` | 跳过确认。CI 用,文档需警示风险 |
|
|
40
41
|
|
|
42
|
+
### 非标准仓库导入(`--alt`)
|
|
43
|
+
|
|
44
|
+
默认情况下,仓库根目录没有合法 `cckit.yaml` 会直接拒绝安装。加上 `--alt` 后,
|
|
45
|
+
cckit 会在**显式开启、经过前置条件检查**的前提下,调用 Claude Code 把一个普通
|
|
46
|
+
skill 仓库改造成标准 kit,再复用现有安装流程:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# 前置依赖:alt extra(内含 claude-agent-sdk)
|
|
50
|
+
uv tool install 'cckit[alt]'
|
|
51
|
+
|
|
52
|
+
# 导入一个普通 skill 仓库(没有 cckit.yaml)
|
|
53
|
+
cckit add https://github.com/someone/my-skill --alt
|
|
54
|
+
cckit add ./my-skill --local --alt
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
流程:
|
|
58
|
+
|
|
59
|
+
1. 把远程仓库按 `--ref` 拉取、或把本地目录复制到临时目录(总是剥离 `.git`);
|
|
60
|
+
2. 若仓库根目录已有 `cckit.yaml`,**仍走标准流程,不调用 Claude Code**;
|
|
61
|
+
3. 前置条件检查:`claude-agent-sdk` 可导入 + 全局 `kit-builder` 处于 `enabled`;
|
|
62
|
+
- 未装 SDK → 提示 `uv tool install 'cckit[alt]'` 并以错误结束;
|
|
63
|
+
- `kit-builder` 缺失/状态不合适 → 提示修复命令,无冲突时可选择自动修复;
|
|
64
|
+
- 存在作用域/来源冲突 → 停止,不静默覆盖;
|
|
65
|
+
4. 以临时仓库为 `cwd` 调用 `kit-builder` 改造仓库;
|
|
66
|
+
5. 确定性校验:`manifest.load → validate_schema → semantic_check → lint`;
|
|
67
|
+
6. 调用 Claude Code **审计**改造结果(prompt injection、敏感读取、外传、越界等);
|
|
68
|
+
7. 只有校验与审计都通过,才把临时目录作为本地 Kit 交给现有安装接口,继续沿用
|
|
69
|
+
`--project` / `--no-enable` / `--only` / `-y` 等参数与安装计划确认;
|
|
70
|
+
8. 无论成功、失败、取消还是 Ctrl+C,临时目录都在最外层 `try/finally` 清理。
|
|
71
|
+
|
|
72
|
+
安全边界(详见 [07-security.md](07-security.md) 与 [05-design-log.md](05-design-log.md)):
|
|
73
|
+
|
|
74
|
+
- 使用 `ClaudeAgentOptions(permission_mode="auto", cwd=临时目录)`,**不设置**
|
|
75
|
+
`can_use_tool`,**不使用** `bypassPermissions`;`auto` 是自动权限判断,不是无条件放行;
|
|
76
|
+
- **隔离仓库自带的 settings/MCP**:`setting_sources=["user"]` 只加载用户级 settings,
|
|
77
|
+
`strict_mcp_config=True` 忽略仓库的 `.mcp.json`,防止仓库自我授权或借 MCP 执行代码;
|
|
78
|
+
- `cwd` 只是限定 Agent 的工作目录,不是完整文件系统沙箱;
|
|
79
|
+
- 审计失败、审计无法完成或审计结论不明确时,不得继续安装;
|
|
80
|
+
- alt 流程**不记录改造后的 SHA**(改造后的内容已非原始仓库状态);保留原始来源 URL、ref。
|
|
81
|
+
|
|
41
82
|
### 必须拦截的情况
|
|
42
83
|
|
|
43
84
|
- 当前平台不在 `platforms` 内 → 拒绝,不等装完才发现
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# kit 开发手册
|
|
2
|
+
|
|
3
|
+
请参照 [manifest-spec.md](../skills/kit-builder/kit-builder/manifest-spec.md) 和
|
|
4
|
+
[kit-authoring.md](../skills/kit-builder/kit-builder/kit-authoring.md)
|
|
5
|
+
|
|
6
|
+
或者使用 `kit-builder` [SKILL](../skills/kit-builder/kit-builder/SKILL.md) 来把 skill 构建成 cckit 支持的模式。
|
|
7
|
+
|
|
8
|
+
如果你的仓库是**没有 `cckit.yaml` 的普通 skill 仓库**,也可以直接用
|
|
9
|
+
`cckit add <仓库> --alt` 让它自动走 `kit-builder` 改造 + Claude Code 审计后导入,
|
|
10
|
+
无需手动写 manifest(需先装 `cckit[alt]`,详见 [cli-spec.md](./cli-spec.md))。
|
|
11
|
+
|
|
12
|
+
*当然,建议您手动进行构建,使用自动构建可能造成部分内容与您的预期不符!*
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# test-skill-dependency
|
|
2
|
+
|
|
3
|
+
一个用于测试 cckit **非标准仓库导入(`--alt`)** 功能的示例 Skill 仓库。
|
|
4
|
+
|
|
5
|
+
> ⚠️ 这是一个**非标准仓库**:根目录**没有** `cckit.yaml`。
|
|
6
|
+
> - 用 `cckit add <本目录> --local` 会被直接拒绝(缺少合法 cckit.yaml);
|
|
7
|
+
> - 用 `cckit add <本目录> --local --alt` 会先由 Claude Code(kit-builder)把它改造成标准 kit,再走正常安装。
|
|
8
|
+
|
|
9
|
+
## 包含的 Skill
|
|
10
|
+
|
|
11
|
+
| Skill | 类型 | 依赖 |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `test-skill-dependency` | 带脚本 | Python(pandas)+ 系统工具 ffmpeg + 可选环境变量 `OPENAI_API_KEY` |
|
|
14
|
+
| `json-pretty` | 带脚本 | Node(js-yaml) |
|
|
15
|
+
| `plain-advisor` | 纯 prompt | 无 |
|
|
16
|
+
|
|
17
|
+
## 依赖
|
|
18
|
+
|
|
19
|
+
### Python
|
|
20
|
+
|
|
21
|
+
见 [requirements.txt](./requirements.txt)(`pandas`),由 `test-skill-dependency` 使用。
|
|
22
|
+
|
|
23
|
+
### Node
|
|
24
|
+
|
|
25
|
+
见 [package.json](./package.json)(`js-yaml`),由 `json-pretty` 使用。
|
|
26
|
+
|
|
27
|
+
### 系统工具
|
|
28
|
+
|
|
29
|
+
- `ffmpeg` —— `test-skill-dependency` 用它读取视频信息。缺失时 cckit 只提示、**不自动安装**。
|
|
30
|
+
|
|
31
|
+
### 环境变量
|
|
32
|
+
|
|
33
|
+
- `OPENAI_API_KEY`(可选)—— `test-skill-dependency` 用于字幕润色,不填则跳过该步骤。
|
|
34
|
+
|
|
35
|
+
## 安装(测试 alt)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# 标准安装会被拒绝(没有 cckit.yaml)
|
|
39
|
+
cckit add ./Docs/test/test-skill-dependency --local
|
|
40
|
+
|
|
41
|
+
# alt 安装:由 Claude Code 改造后安装
|
|
42
|
+
cckit add ./Docs/test/test-skill-dependency --local --alt
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 目录结构
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
test-skill-dependency/ # 仓库根 = 传给 cckit 的 source
|
|
49
|
+
├── README.md
|
|
50
|
+
├── .gitignore
|
|
51
|
+
├── requirements.txt # Python 依赖
|
|
52
|
+
├── package.json # Node 依赖
|
|
53
|
+
├── test-skill-dependency/ # skill 1:python + ffmpeg + env
|
|
54
|
+
│ ├── SKILL.md
|
|
55
|
+
│ └── scripts/
|
|
56
|
+
│ └── test.py
|
|
57
|
+
├── json-pretty/ # skill 2:node
|
|
58
|
+
│ ├── SKILL.md
|
|
59
|
+
│ └── scripts/
|
|
60
|
+
│ └── pretty.js
|
|
61
|
+
└── plain-advisor/ # skill 3:纯 prompt
|
|
62
|
+
└── SKILL.md
|
|
63
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: json-pretty
|
|
3
|
+
description: 把 JSON 文件转成 YAML 输出,方便查看配置文件;需要 Node 与 js-yaml。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# json-pretty
|
|
7
|
+
|
|
8
|
+
读取一个 JSON 文件,用 `js-yaml` 转成 YAML 输出,便于阅读配置。
|
|
9
|
+
|
|
10
|
+
## 依赖
|
|
11
|
+
|
|
12
|
+
- **Node**:`js-yaml`(见根目录 `package.json`)
|
|
13
|
+
|
|
14
|
+
## 脚本调用
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
cckit exec json-pretty scripts/pretty.js <file.json>
|
|
18
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// 把 JSON 文件转成 YAML 输出。依赖 js-yaml(见根目录 package.json)。
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const yaml = require("js-yaml");
|
|
4
|
+
|
|
5
|
+
const input = process.argv[2];
|
|
6
|
+
if (!input) {
|
|
7
|
+
console.error("用法: cckit exec json-pretty scripts/pretty.js <file.json>");
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const data = JSON.parse(fs.readFileSync(input, "utf8"));
|
|
12
|
+
process.stdout.write(yaml.dump(data));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pandas>=2.0
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-skill-dependency
|
|
3
|
+
description: 读取视频文件并提取元数据、生成 CSV 报告;需要 pandas 与 ffmpeg,可用 OPENAI_API_KEY 做字幕润色。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# test-skill-dependency
|
|
7
|
+
|
|
8
|
+
读取一个视频文件,用 `ffmpeg` 提取格式信息,用 `pandas` 汇总成一份 CSV 报告。
|
|
9
|
+
|
|
10
|
+
## 依赖
|
|
11
|
+
|
|
12
|
+
- **Python**:`pandas`(见根目录 `requirements.txt`)
|
|
13
|
+
- **系统工具**:`ffmpeg`(读取视频信息;缺失时请手动安装,cckit 只提示不自动装)
|
|
14
|
+
- **环境变量**:`OPENAI_API_KEY`(可选,用于字幕润色,不填则跳过该步骤)
|
|
15
|
+
|
|
16
|
+
## 脚本调用
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
cckit exec test-skill-dependency scripts/test.py <视频文件>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
脚本通过 `CCKIT_SKILL_DIR` 定位自身资源,不要假设当前工作目录。
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""分析视频文件并生成 CSV 报告。
|
|
2
|
+
|
|
3
|
+
依赖:
|
|
4
|
+
- pandas(requirements.txt)
|
|
5
|
+
- ffmpeg(系统工具,用 `ffmpeg -i` 读视频信息)
|
|
6
|
+
- 环境变量 OPENAI_API_KEY(可选,字幕润色)
|
|
7
|
+
"""
|
|
8
|
+
import os
|
|
9
|
+
import subprocess
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
import pandas as pd
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def read_video_info(path: str) -> str:
|
|
16
|
+
"""用 ffmpeg 读取视频格式信息(ffmpeg 会把信息写到 stderr)。"""
|
|
17
|
+
proc = subprocess.run(
|
|
18
|
+
["ffmpeg", "-i", path],
|
|
19
|
+
capture_output=True,
|
|
20
|
+
text=True,
|
|
21
|
+
)
|
|
22
|
+
return (proc.stderr or proc.stdout).strip()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main() -> int:
|
|
26
|
+
if len(sys.argv) < 2:
|
|
27
|
+
print("用法: cckit exec test-skill-dependency scripts/test.py <视频文件>")
|
|
28
|
+
return 1
|
|
29
|
+
|
|
30
|
+
video = sys.argv[1]
|
|
31
|
+
info = read_video_info(video)
|
|
32
|
+
|
|
33
|
+
api_key = os.environ.get("OPENAI_API_KEY")
|
|
34
|
+
polished = bool(api_key)
|
|
35
|
+
|
|
36
|
+
df = pd.DataFrame([
|
|
37
|
+
{"file": video, "info": info[:200], "polished": polished},
|
|
38
|
+
])
|
|
39
|
+
|
|
40
|
+
out_dir = os.environ.get("CCKIT_SKILL_DIR", ".")
|
|
41
|
+
out = os.path.join(out_dir, "report.csv")
|
|
42
|
+
df.to_csv(out, index=False)
|
|
43
|
+
print(f"已生成报告: {out}")
|
|
44
|
+
return 0
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
raise SystemExit(main())
|