cckit 0.1.1__tar.gz → 0.2.1__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.1.1 → cckit-0.2.1}/.gitignore +1 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/.gitignore +4 -1
- {cckit-0.1.1 → cckit-0.2.1}/Docs/05-design-log.md +15 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/09-state-api.md +23 -5
- cckit-0.2.1/Docs/11-web-panel.md +182 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/README.md +12 -6
- cckit-0.2.1/Docs/pics/architecture.md +63 -0
- cckit-0.2.1/Docs/pics/directory-layout.md +15 -0
- cckit-0.2.1/Docs/pics/four-state-model.md +16 -0
- cckit-0.2.1/Docs/pics/install-flow.md +15 -0
- cckit-0.2.1/Docs/pics/pain-points-solution.md +20 -0
- cckit-0.2.1/Docs/pics/state-transitions.md +33 -0
- {cckit-0.1.1 → cckit-0.2.1}/PKG-INFO +4 -1
- {cckit-0.1.1 → cckit-0.2.1}/README.md +51 -5
- cckit-0.2.1/hatch_build.py +27 -0
- {cckit-0.1.1 → cckit-0.2.1}/pyproject.toml +16 -1
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/__init__.py +1 -1
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/cli.py +31 -1
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/doctor.py +9 -3
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/exec.py +1 -1
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/installer.py +137 -61
- cckit-0.2.1/src/cckit/projects.py +74 -0
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/registry.py +11 -8
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/state.py +120 -58
- cckit-0.2.1/src/cckit/web/__init__.py +4 -0
- cckit-0.2.1/src/cckit/web/app.py +291 -0
- {cckit-0.1.1 → cckit-0.2.1}/tests/test_state.py +6 -2
- {cckit-0.1.1 → cckit-0.2.1}/uv.lock +212 -1
- cckit-0.2.1/web/.gitignore +8 -0
- cckit-0.2.1/web/components.json +25 -0
- cckit-0.2.1/web/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- cckit-0.2.1/web/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- cckit-0.2.1/web/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- cckit-0.2.1/web/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- cckit-0.2.1/web/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- cckit-0.2.1/web/dist/assets/index-DlYI_0eV.js +68 -0
- cckit-0.2.1/web/dist/assets/index-TshdTLiY.css +1 -0
- cckit-0.2.1/web/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- cckit-0.2.1/web/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- cckit-0.2.1/web/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- cckit-0.2.1/web/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- cckit-0.2.1/web/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- cckit-0.2.1/web/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- cckit-0.2.1/web/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- cckit-0.2.1/web/dist/index.html +13 -0
- cckit-0.2.1/web/index.html +12 -0
- cckit-0.2.1/web/package-lock.json +6233 -0
- cckit-0.2.1/web/package.json +38 -0
- cckit-0.2.1/web/src/App.tsx +133 -0
- cckit-0.2.1/web/src/components/AddKitDialog.tsx +369 -0
- cckit-0.2.1/web/src/components/AddScopeDialog.tsx +64 -0
- cckit-0.2.1/web/src/components/AppSidebar.tsx +222 -0
- cckit-0.2.1/web/src/components/DoctorDialog.tsx +185 -0
- cckit-0.2.1/web/src/components/KitList.tsx +422 -0
- cckit-0.2.1/web/src/components/ui/badge.tsx +52 -0
- cckit-0.2.1/web/src/components/ui/button.tsx +56 -0
- cckit-0.2.1/web/src/components/ui/card.tsx +100 -0
- cckit-0.2.1/web/src/components/ui/dialog.tsx +158 -0
- cckit-0.2.1/web/src/components/ui/dropdown-menu.tsx +266 -0
- cckit-0.2.1/web/src/components/ui/input.tsx +20 -0
- cckit-0.2.1/web/src/components/ui/popover.tsx +88 -0
- cckit-0.2.1/web/src/components/ui/progress.tsx +81 -0
- cckit-0.2.1/web/src/components/ui/separator.tsx +23 -0
- cckit-0.2.1/web/src/components/ui/sheet.tsx +136 -0
- cckit-0.2.1/web/src/components/ui/sidebar.tsx +726 -0
- cckit-0.2.1/web/src/components/ui/skeleton.tsx +13 -0
- cckit-0.2.1/web/src/components/ui/sonner.tsx +39 -0
- cckit-0.2.1/web/src/components/ui/tooltip.tsx +66 -0
- cckit-0.2.1/web/src/hooks/use-mobile.ts +19 -0
- cckit-0.2.1/web/src/hooks/useSSE.ts +55 -0
- cckit-0.2.1/web/src/index.css +200 -0
- cckit-0.2.1/web/src/lib/api.ts +171 -0
- cckit-0.2.1/web/src/lib/utils.ts +6 -0
- cckit-0.2.1/web/src/main.tsx +21 -0
- cckit-0.2.1/web/tsconfig.json +25 -0
- cckit-0.2.1/web/tsconfig.node.json +12 -0
- cckit-0.2.1/web/tsconfig.node.tsbuildinfo +1 -0
- cckit-0.2.1/web/tsconfig.tsbuildinfo +1 -0
- cckit-0.2.1/web/vite.config.d.ts +2 -0
- cckit-0.2.1/web/vite.config.js +21 -0
- cckit-0.2.1/web/vite.config.ts +23 -0
- cckit-0.1.1/.claude/settings.local.json +0 -1
- {cckit-0.1.1 → cckit-0.2.1}/Docs/01-overview.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/02-architecture.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/03-manifest-spec.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/04-cli-spec.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/06-platform-findings.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/07-security.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/08-installation.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/10-kit-authoring.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/cli-spec.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/examples/video-toolkit/cckit.yaml +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/kit-development.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/Docs/schema/cckit.schema.json +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/LICENSE +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/skills/kit-builder/cckit.yaml +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/skills/kit-builder/kit-builder/SKILL.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/skills/kit-builder/kit-builder/kit-authoring.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/skills/kit-builder/kit-builder/manifest-spec.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/skills/kit-builder/kit-builder/templates/SKILL.md +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/skills/kit-builder/kit-builder/templates/cckit.yaml +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/__main__.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/cckit.schema.json +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/config.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/env.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/errors.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/link.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/lint.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/manifest.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/src/cckit/schema.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/tests/conftest.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/tests/helpers.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/tests/test_budget.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/tests/test_exec.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/tests/test_installer.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/tests/test_link.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/tests/test_lint.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/tests/test_manifest.py +0 -0
- {cckit-0.1.1 → cckit-0.2.1}/tests/test_registry.py +0 -0
|
@@ -385,6 +385,21 @@ skill 报成项目安装。所以刻意分列:`override_scopes` 只给 `remove`
|
|
|
385
385
|
skill 补。若项目里真有同名项目 kit,该覆盖是写给项目 kit 的(`set_state` 定位顺序先项目后
|
|
386
386
|
全局),不能误归属到全局 kit。
|
|
387
387
|
|
|
388
|
+
**读回路径的扩展(Web 接入后)**:最初「读回」只补**带项目覆盖**的全局 skill
|
|
389
|
+
(`name in proj_ov`)——因为 CLI 的 `list --project` 语义是"项目里实际有什么"。但 Web
|
|
390
|
+
侧栏要能「看到」全局 skill 才能让用户发起**首次**覆盖;只列出带覆盖的,还没覆盖过的全局
|
|
391
|
+
skill 根本不可见,覆盖无从点起。
|
|
392
|
+
|
|
393
|
+
故 `list_skills("project")` 改为列出**所有**全局 skill,`SkillState` 带三字段:
|
|
394
|
+
`is_global_skill`(是否全局 skill)、`global_state`(它在全局的当前状态,决策依据)、
|
|
395
|
+
`override`(有无项目覆盖)。有覆盖时 `state`=覆盖态,无覆盖时 `state`=`global_state`
|
|
396
|
+
(跟随全局)。`budget` 相应排除 `is_global_skill` 的 `enabled` 条目——全局 skill 的
|
|
397
|
+
description 在全局作用域已计一次,项目作用域的「跟随全局」条目不能重复计入。
|
|
398
|
+
|
|
399
|
+
CLI 与 Web 由此共用同一套覆盖语义:CLI 显示「项目覆盖 已关闭」/「跟随全局 已启用」;
|
|
400
|
+
Web 把全局 skill 单独折叠一组、用独立覆盖选择器(不复用四态),只展示当前全局状态下允许的
|
|
401
|
+
选项(全局 `enabled`→跟随/name-only/off;`name-only`→跟随/off;`off`→仅跟随)。
|
|
402
|
+
|
|
388
403
|
**已知取舍**:这条没有让"全局 skill 在项目里**强制开启**"成为可表达的状态——`enable
|
|
389
404
|
--project` 是清覆盖(跟随全局)。要"全局 off 但本项目 on"属于罕见需求,且 `skillOverrides`
|
|
390
405
|
的项目层覆盖能否压过全局层的 off 尚未验证,不主动提供。
|
|
@@ -61,16 +61,34 @@ class SkillState:
|
|
|
61
61
|
env_ok: bool | None # None = 该 skill 无需 env
|
|
62
62
|
desc_chars: int # 用于预算统计
|
|
63
63
|
version: str | None
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def
|
|
64
|
+
is_global_skill: bool = False # project 作用域下,此条目是「全局 skill 的项目覆盖/跟随」
|
|
65
|
+
global_state: str | None = None # 全局 skill 在全局作用域的状态
|
|
66
|
+
override: bool = False # 全局 skill 是否带项目级覆盖(off/name-only)
|
|
67
|
+
|
|
68
|
+
def list_skills(scope=None, root=None) -> list[SkillState]: ...
|
|
69
|
+
def get_state(name, scope, root=None) -> str: ...
|
|
70
|
+
def set_state(name, state, scope, root=None) -> None: ... # 带锁 + 原子写
|
|
71
|
+
def budget(scope=None, root=None) -> tuple[int, int]: ... # (已用字符, 上限)
|
|
69
72
|
```
|
|
70
73
|
|
|
71
74
|
`list_skills()` 必须同时列出**非 cckit 管理**的 skill,标记 `managed=False`。
|
|
72
75
|
用户看到的是完整工具箱视图,但只有 cckit 装的能被开关。
|
|
73
76
|
|
|
77
|
+
### 全局 skill 的项目级覆盖(D-15)
|
|
78
|
+
|
|
79
|
+
`list_skills(scope="project")` 会把**所有全局 kit 的 skill** 也列出来(标记
|
|
80
|
+
`is_global_skill=True`),供项目里单独覆盖:
|
|
81
|
+
|
|
82
|
+
- **有项目覆盖**(`override=True`):`state` 是覆盖状态(off/name-only)。
|
|
83
|
+
- **无覆盖、跟随全局**(`override=False`):`state` 等于 `global_state`(全局状态)。
|
|
84
|
+
|
|
85
|
+
`global_state` 是决策依据:`set_state` 在项目作用域对全局 skill 只允许
|
|
86
|
+
`off`/`name-only`(写项目 `skillOverrides`)、`enabled`(清覆盖=跟随全局),
|
|
87
|
+
不允许 `installed`(项目无 link 可删)。前端据此只展示当前全局状态下允许的覆盖选项。
|
|
88
|
+
|
|
89
|
+
`budget()` 排除 `is_global_skill` 的 `enabled` 条目——全局 skill 的 description
|
|
90
|
+
在全局作用域已计入一次,项目作用域的「跟随全局」条目不应重复计算。
|
|
91
|
+
|
|
74
92
|
## `registry.json` 结构
|
|
75
93
|
|
|
76
94
|
唯一的持久化存储。只放**观测不出来**的东西。
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Web 管理面板
|
|
2
|
+
|
|
3
|
+
配套 v0.2.1 的可选管理面板:平时展示 skill 列表,支持导入(add)、卸载(remove)、
|
|
4
|
+
四态开关切换、诊断(doctor)。**纯增量**——不装 `[web]` 额外依赖时,`cckit` 本体
|
|
5
|
+
与命令行工具完全不变。
|
|
6
|
+
|
|
7
|
+
## 定位
|
|
8
|
+
|
|
9
|
+
- 目标是**管理界面**,不是运行界面:`exec` 这类"跑 skill"的能力在网页上不做
|
|
10
|
+
(服务器上直接跑 `ccb`/Claude Code 即可)。
|
|
11
|
+
- 部署形态是**独立面板 + iframe 融合**:它要和一个外部 dashboard(Vite+React,
|
|
12
|
+
非本项目维护)一起上 Linux 服务器,通过 `<iframe>` 嵌入对方页面,因此必须
|
|
13
|
+
独立开发、独立部署、独立端口,不依赖改对方代码。
|
|
14
|
+
|
|
15
|
+
## 技术方案
|
|
16
|
+
|
|
17
|
+
| 决策 | 选择 | 理由 |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| 仓库 | 当前仓库(`web/` + `src/cckit/web/`) | Web 要动状态层(root 推广)与 installer(两阶段),本就是同一件事;版本天然锁步 |
|
|
20
|
+
| 后端 | FastAPI + uvicorn,import `cckit.*` | 状态/安装/诊断逻辑只有一份,Web 不重实现;SSE 流式 |
|
|
21
|
+
| 前端 | Vite + React 19 + TypeScript + Tailwind v4 + shadcn/ui | 纯客户端 SPA,无 SSR 需求;shadcn 4.x 用 base-ui 原语 |
|
|
22
|
+
| 图标 | @phosphor-icons/react | shadcn 4.x 默认图标库 |
|
|
23
|
+
| 数据层 | TanStack Query | 缓存 + 失效即"刷新机制" |
|
|
24
|
+
| 提示 | sonner(shadcn 包装) | 四类 toast + 弹窗/toast 分工 |
|
|
25
|
+
| 依赖隔离 | `[web]` 可选 extra | `uv tool install cckit` 仍是 3 依赖纯本体 |
|
|
26
|
+
| 安全 | 后端默认 `127.0.0.1` | Web 能装 kit(跑作者代码)、能改状态,不放开监听 |
|
|
27
|
+
|
|
28
|
+
## 架构
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
浏览器 (外部 dashboard 内 iframe)
|
|
32
|
+
│ http://<server>:<port>/
|
|
33
|
+
▼
|
|
34
|
+
FastAPI (src/cckit/web/) ── 静态托管 web/dist/
|
|
35
|
+
│ import ├── GET/POST /api/* (JSON)
|
|
36
|
+
│ ┌─ cckit.state ├── POST /api/add/execute (SSE)
|
|
37
|
+
│ ├─ cckit.installer └── POST /api/doctor (SSE)
|
|
38
|
+
│ └─ cckit.doctor
|
|
39
|
+
▼
|
|
40
|
+
~/.cckit/ store + registry.json + projects.json + envs
|
|
41
|
+
<CC 配置目录>/skills + settings.json (状态派生源)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**核心原则**:状态读写只走 `cckit.state`,安装只走 `cckit.installer`,诊断只走
|
|
45
|
+
`cckit.doctor`。Web 后端是这些模块的薄前端,零逻辑重实现,杜绝「改两边」——
|
|
46
|
+
改核心逻辑一处,CLI 与 Web 自动同步;唯一要保证的是核心函数**只返回数据、不发声音**
|
|
47
|
+
(不 `print`/`input`),由 CLI/Web 各自渲染。
|
|
48
|
+
|
|
49
|
+
## 后端 API
|
|
50
|
+
|
|
51
|
+
| 端点 | 底层调用 | 说明 |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| `GET /api/scopes` | `state.list_scopes()` | 侧栏作用域(全局 + 历史项目 + 关注项目) |
|
|
54
|
+
| `POST/DELETE /api/scopes` | `projects.add/remove` | 关注/取关项目,add 时建 `.claude` |
|
|
55
|
+
| `GET /api/skills?scope=&root=` | `state.list_skills` + `state.budget` | 列表 + 预算一次返回;skill 带 `is_global_skill`/`global_state`/`override` |
|
|
56
|
+
| `POST /api/skills/{name}/state` | `state.set_state` | 四态切换,返回 `{message}` |
|
|
57
|
+
| `GET /api/kits` | `registry.load()` | kit 头部元信息 |
|
|
58
|
+
| `POST /api/kits/{kit}/remove` | `installer.remove_kit` | 卸载 |
|
|
59
|
+
| `POST /api/add/preview` | `installer.stage_install` | 克隆+校验+计划,存 `preview_id` |
|
|
60
|
+
| `POST /api/add/execute` | `installer.execute_install` | 确认后执行,SSE 进度 |
|
|
61
|
+
| `DELETE /api/add/preview/{id}` | `StagedInstall.cleanup` | 取消时清理临时目录 |
|
|
62
|
+
| `POST /api/doctor` | `doctor.run(fix, on_event)` | SSE 进度 + findings |
|
|
63
|
+
|
|
64
|
+
错误契约:`CckitError`(含 `InstallError`)统一捕获 → `{error:{message}}` + 400;
|
|
65
|
+
参数校验失败 → 422。前端只读 `message`,不依赖状态码区分。
|
|
66
|
+
|
|
67
|
+
`preview_id → StagedInstall` 存进程内字典,带 30 分钟过期回收 + 取消清理,避免
|
|
68
|
+
临时 clone 目录堆积。
|
|
69
|
+
|
|
70
|
+
## 关键改动(相对 v0.1)
|
|
71
|
+
|
|
72
|
+
### 状态层作用域推广
|
|
73
|
+
|
|
74
|
+
`list_skills` / `get_state` / `set_state` / `budget` 增加 `root: Path | None` 参数,
|
|
75
|
+
缺省回落 `config.project_root()`(cwd)——CLI 行为不变。`registry._kit_in_scope` /
|
|
76
|
+
`find_skill` 等同步线程 root。这让 Web 侧栏能操作**任意项目作用域**,而非只有 cwd。
|
|
77
|
+
|
|
78
|
+
### 关注项目清单 `projects.py`
|
|
79
|
+
|
|
80
|
+
`~/.cckit/projects.json`(声明式存储):记录「用户想持续关注的项目目录」。与
|
|
81
|
+
`registry.json` 分工——registry 存「装了什么」(观测不到),projects 存「想关注什么」
|
|
82
|
+
(用户意图)。`add()` 顺带建 `.claude` 目录使其成为合法项目作用域。
|
|
83
|
+
|
|
84
|
+
`state.list_scopes()` 返回三源并集(去重):全局 + registry 的
|
|
85
|
+
`known_scopes`/`override_scopes` + 关注清单,每项带 `{path, source, has_skills}`。
|
|
86
|
+
|
|
87
|
+
### installer 拆两阶段
|
|
88
|
+
|
|
89
|
+
`install()` 原是一条龙(clone→校验→print→`input()`→执行),混着 I/O。拆为:
|
|
90
|
+
|
|
91
|
+
- `stage_install(...) -> StagedInstall`:clone → 校验 → lint → 计算计划,不落盘。
|
|
92
|
+
lint 的 error **不在此中止**(消息进 `lint_msgs`),由调用方决定是否继续。
|
|
93
|
+
- `execute_install(staged, ...) -> Iterator[ProgressEvent]`:移入 store → env →
|
|
94
|
+
postinstall → registry → link,逐条 yield 进度;异常回滚 store/env/registry。
|
|
95
|
+
|
|
96
|
+
CLI 的 `install()` 变为薄封装(stage → print 计划 → input 确认 → 迭代打印进度),
|
|
97
|
+
行为与拆分前一致;Web 用 stage/preview + SSE 消费 progress。这是**根治「改两边」**
|
|
98
|
+
的关键:核心函数只返回数据。
|
|
99
|
+
|
|
100
|
+
### doctor 流式回调
|
|
101
|
+
|
|
102
|
+
`doctor.run(fix, on_event=None)` 增加可选回调,`_apply_fixes` 重建 env 前后推送
|
|
103
|
+
事件。向后兼容(不传回调行为不变)。
|
|
104
|
+
|
|
105
|
+
### 全局 skill 项目级覆盖(D-15 读回)
|
|
106
|
+
|
|
107
|
+
`list_skills(scope="project")` 会把所有全局 kit 的 skill 也列出,`SkillState` 带
|
|
108
|
+
`is_global_skill` / `global_state` / `override` 三个字段(详见
|
|
109
|
+
[09](09-state-api.md))。项目作用域下能「按项目单独覆盖」全局 skill:
|
|
110
|
+
|
|
111
|
+
- 覆盖 `off` / `name-only`:写项目 `skillOverrides`,不影响全局。
|
|
112
|
+
- `enabled`:清覆盖 = 跟随全局。
|
|
113
|
+
- `installed`(purge)不允许:项目里没有 link 可删。
|
|
114
|
+
|
|
115
|
+
CLI 与 Web 共用这套语义:CLI `list --project` 显示「项目覆盖 已关闭」或「跟随全局
|
|
116
|
+
已启用」;Web 把全局 skill 单独折叠成一组,用独立的覆盖选择器(不复用四态),只展示
|
|
117
|
+
当前全局状态下允许的选项。
|
|
118
|
+
|
|
119
|
+
## 前端(`web/`)
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
src/
|
|
123
|
+
App.tsx # 编排:SidebarProvider + AppSidebar + SidebarInset + 弹窗开关
|
|
124
|
+
lib/api.ts # 类型 + fetch 封装(SSE 端点返回原生 Response)
|
|
125
|
+
lib/utils.ts # cn()
|
|
126
|
+
hooks/useSSE.ts # 消费 SSE 流(data: {json} 帧解析)
|
|
127
|
+
components/
|
|
128
|
+
AppSidebar / KitList / AddKitDialog / DoctorDialog / AddScopeDialog
|
|
129
|
+
ui/ # shadcn 组件(button/dialog/dropdown-menu/tooltip/input/card/
|
|
130
|
+
# badge/progress/separator/popover/sonner/sidebar/sheet/skeleton)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- **布局**:dashboard 式——官方 `Sidebar`(variant=inset)+ 右侧 `SidebarInset`。
|
|
134
|
+
Sidebar 内:Header(CCKitKit + 版本)、4 个分组(作用域 / 添加关注项目 / Kit 管理 /
|
|
135
|
+
刷新)、Footer(清单预算,收起时变圆环);右侧顶部 `SidebarTrigger` 收起/展开。
|
|
136
|
+
- **列表**:项目 kit 可收起/展开/卸载(卸载用 Popover + destructive 确认);skill
|
|
137
|
+
四态选择器(`name-only` 附解释)、`env_ok=False` 警示、`managed=False` 置灰只读;
|
|
138
|
+
全局 skill 单独折叠一组、无卸载按钮、用覆盖选择器。
|
|
139
|
+
- **添加 Kit**:两阶段弹窗(表单 → 计划确认,lint error 禁用安装 → SSE 日志)。
|
|
140
|
+
- **诊断**:`--fix` 勾选 + SSE 进度 + findings 结果。
|
|
141
|
+
- **刷新三层**:侧栏刷新按钮 + 写操作后 `invalidateQueries` 自动重拉 + 可选轮询。
|
|
142
|
+
所有开关改动提示「**新会话生效**」(对齐 09 的语义)。
|
|
143
|
+
- **提示框**:后端错误契约统一拦截,`set_state` 的返回串走 error、成功走 success。
|
|
144
|
+
|
|
145
|
+
## 使用与部署
|
|
146
|
+
|
|
147
|
+
**普通用户**(前端已随 wheel 打包,一条命令即用):
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
uv tool install 'cckit[web]'
|
|
151
|
+
cckit web # 打开 http://127.0.0.1:8000 即用
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**开发者**(源码仓库里改前端):
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# 开发调试
|
|
158
|
+
uv run cckit web # 后端 :8000(不托管前端)
|
|
159
|
+
cd web && npm run dev # 前端 :5173(vite dev 代理 /api)
|
|
160
|
+
|
|
161
|
+
# 生产 / 部署
|
|
162
|
+
cd web && npm install && npm run build # 产出 web/dist/,uv build 时打进 wheel
|
|
163
|
+
uv run cckit web --host 0.0.0.0 --port 8000 # 自动定位前端,缺省也无需 --static-dir
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**安全**:`--host` 默认 `127.0.0.1`。上服务器被浏览器访问时用 `--host 0.0.0.0`,
|
|
167
|
+
⚠️ 放开即把「能装 kit(跑作者代码)、能改状态」的能力暴露给网段,只在可信内网用,
|
|
168
|
+
必要时在反向代理层加鉴权。
|
|
169
|
+
|
|
170
|
+
**iframe 融合**:后端托管前端后,宿主页 `<iframe src="http://<server>:<port>/">`
|
|
171
|
+
即可。同源策略保证宿主页读不到 iframe 内部、也调不了 cckit 接口(无 CORS 问题);
|
|
172
|
+
不设 `frame-ancestors` CSP(Starlette 默认即可嵌)。HTTPS 宿主嵌 `http://<server>`
|
|
173
|
+
需在目标浏览器实测(Safari 较严)。
|
|
174
|
+
|
|
175
|
+
## 验证
|
|
176
|
+
|
|
177
|
+
- `uv run pytest -q` 82 项全绿(状态层 root 推广、installer 拆分后 CLI 行为不回归)。
|
|
178
|
+
- `cd web && npm run build` 通过(tsc 类型检查 + vite 打包)。
|
|
179
|
+
- 端到端:装 wheel 到隔离 venv 后 `cckit web` 一键启动,静态页面、`/api/*`、静态资源
|
|
180
|
+
均可达,非法 API 路径返回 404 而非 index.html。
|
|
181
|
+
- 纯净性:`uv build`(不先跑前端构建)产出的 wheel 不含前端,`[web]` 依赖也不随
|
|
182
|
+
`uv tool install cckit` 安装;前端产物仅在前端 build 后才由 hatch 钩子打进 wheel。
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
| [08-installation.md](08-installation.md) | 分发方案与理由 | 打包发布时 |
|
|
18
18
|
| [09-state-api.md](09-state-api.md) | 状态层契约、并发要求、Web 接入 | **实现 list/开关 或 Web 前必读** |
|
|
19
19
|
| [10-kit-authoring.md](10-kit-authoring.md) | 开发手册:把普通 skill 改造成 kit | 发布 kit / 写 kit 时 |
|
|
20
|
+
| [11-web-panel.md](11-web-panel.md) | Web 管理面板:架构、API、部署、iframe | 接入/部署 Web 或改前端时 |
|
|
20
21
|
|
|
21
22
|
配套:[`schema/cckit.schema.json`](schema/cckit.schema.json)、
|
|
22
23
|
[`examples/video-toolkit/`](examples/video-toolkit/)(参考 kit,应作为测试夹具)、
|
|
@@ -53,8 +54,8 @@
|
|
|
53
54
|
|
|
54
55
|
## 当前状态
|
|
55
56
|
|
|
56
|
-
**v0.1 已实现**:`cckit` 命令行工具与全部
|
|
57
|
-
`disable` / `name-only` / `remove` / `doctor` / `exec`),`uv run cckit --help`
|
|
57
|
+
**v0.2.1 已实现**:`cckit` 命令行工具与全部 9 个命令(`add` / `list` / `enable` /
|
|
58
|
+
`disable` / `name-only` / `remove` / `doctor` / `exec` / `web`),`uv run cckit --help` 可用。(0.2.0因为打包失误,版本号被弃用)
|
|
58
59
|
|
|
59
60
|
已落地模块(`src/cckit/`):
|
|
60
61
|
|
|
@@ -67,8 +68,10 @@
|
|
|
67
68
|
- `registry` —— registry.json 原子读写
|
|
68
69
|
- `lint` —— 命名 / description / CRLF / prompt injection / typosquatting
|
|
69
70
|
- `doctor` —— 只读诊断 + 安全修复
|
|
71
|
+
- `projects` —— 关注项目清单 projects.json 原子读写
|
|
72
|
+
- `web` —— Web 管理面板后端(FastAPI,惰性 import,`[web]` 可选依赖)
|
|
70
73
|
|
|
71
|
-
测试:`tests/` 下
|
|
74
|
+
测试:`tests/` 下 82 项,`uv run pytest -q` 全绿;`Docs/examples/video-toolkit` 作为夹具。
|
|
72
75
|
|
|
73
76
|
## v0.1 范围
|
|
74
77
|
|
|
@@ -77,10 +80,13 @@
|
|
|
77
80
|
- 运行时只支持 Python(uv venv)与 Node
|
|
78
81
|
- 依赖文件复用 `requirements.txt` / `package.json`,不自创格式
|
|
79
82
|
- 四态开关、安装计划展示、`list` 报预算、`doctor` 全项检查
|
|
80
|
-
- `cckit.state` 状态层(含文件锁与原子写)
|
|
81
|
-
——它是 Web 的接入点,事后补会导致两套逻辑
|
|
83
|
+
- `cckit.state` 状态层(含文件锁与原子写)——CLI 与 Web 共用的唯一状态入口
|
|
82
84
|
|
|
83
|
-
|
|
85
|
+
## v0.2 范围
|
|
86
|
+
|
|
87
|
+
- Web 管理面板(`cckit web`):列表/导入/卸载/四态开关/诊断,iframe 融合(见 [11](11-web-panel.md))
|
|
88
|
+
|
|
89
|
+
**推迟到 v0.3+**:`cckit.lock` 与 `sync`、`profile`、`update` 的 diff 展示、
|
|
84
90
|
用量统计。
|
|
85
91
|
|
|
86
92
|
## 约定
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# cckit 架构图
|
|
2
|
+
|
|
3
|
+
```mermaid
|
|
4
|
+
flowchart TB
|
|
5
|
+
subgraph CLI["cckit CLI · 8 个子命令"]
|
|
6
|
+
Add["add"]
|
|
7
|
+
List["list"]
|
|
8
|
+
Switch["enable / disable / name-only"]
|
|
9
|
+
Remove["remove"]
|
|
10
|
+
Doctor["doctor"]
|
|
11
|
+
Exec["exec"]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
subgraph Core["核心模块 src/cckit/"]
|
|
15
|
+
Installer["installer · add 全流程"]
|
|
16
|
+
Manifest["manifest / schema · cckit.yaml 校验"]
|
|
17
|
+
Lint["lint · 安全检查"]
|
|
18
|
+
Env["env · 隔离环境"]
|
|
19
|
+
State["state · 四态派生 + 原子写"]
|
|
20
|
+
Registry["registry · registry.json 读写"]
|
|
21
|
+
Link["link · 目录链接"]
|
|
22
|
+
ExecMod["exec · 脚本执行"]
|
|
23
|
+
DoctorMod["doctor · 诊断修复"]
|
|
24
|
+
Config["config · 路径与平台"]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
subgraph Storage["本地存储 ~/.cckit/"]
|
|
28
|
+
Store["store / kit / skill / SKILL.md"]
|
|
29
|
+
Envs["envs / kit__skill__runtime /"]
|
|
30
|
+
Reg["registry.json"]
|
|
31
|
+
Usage["usage.jsonl"]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
subgraph CC["Claude Code 扫描目录"]
|
|
35
|
+
Global["全局 skills 目录"]
|
|
36
|
+
Project["项目 .claude/skills 目录"]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
Add --> Installer
|
|
40
|
+
List --> State
|
|
41
|
+
Switch --> State
|
|
42
|
+
Remove --> Installer
|
|
43
|
+
Doctor --> DoctorMod
|
|
44
|
+
Exec --> ExecMod
|
|
45
|
+
|
|
46
|
+
Installer --> Manifest
|
|
47
|
+
Installer --> Lint
|
|
48
|
+
Installer --> Env
|
|
49
|
+
Installer --> Registry
|
|
50
|
+
Installer --> Link
|
|
51
|
+
Installer --> State
|
|
52
|
+
Installer --> Config
|
|
53
|
+
|
|
54
|
+
Env --> Envs
|
|
55
|
+
Registry --> Reg
|
|
56
|
+
State --> Usage
|
|
57
|
+
State -. 扫描 .-> Reg
|
|
58
|
+
Link --> Store
|
|
59
|
+
Link --> Global
|
|
60
|
+
Link --> Project
|
|
61
|
+
ExecMod --> Store
|
|
62
|
+
ExecMod --> Envs
|
|
63
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# 目录布局
|
|
2
|
+
|
|
3
|
+
```mermaid
|
|
4
|
+
flowchart TD
|
|
5
|
+
Root["~/.cckit/"] --> Store["store / {kit}/"]
|
|
6
|
+
Root --> Envs["envs / {kit}__{skill}__{runtime}/"]
|
|
7
|
+
Root --> Reg["registry.json"]
|
|
8
|
+
Root --> Usage["usage.jsonl"]
|
|
9
|
+
|
|
10
|
+
Store --> Skill["{skill} / SKILL.md"]
|
|
11
|
+
Store --> Yaml["cckit.yaml"]
|
|
12
|
+
|
|
13
|
+
Store -. "link(目录链接)" .-> Global["CC 配置目录 / skills / {skill}"]
|
|
14
|
+
Store -. "link" .-> Project["项目 / .claude / skills / {skill}"]
|
|
15
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# 四态模型示意图
|
|
2
|
+
|
|
3
|
+
```mermaid
|
|
4
|
+
flowchart TD
|
|
5
|
+
Skill["一个 skill"] --> HasLink{"是否已建立 link?"}
|
|
6
|
+
|
|
7
|
+
HasLink -- "否" --> Installed["installed<br/>CC 什么都看不到"]
|
|
8
|
+
|
|
9
|
+
HasLink -- "是" --> Override{"skillOverrides 状态?"}
|
|
10
|
+
|
|
11
|
+
Override -- "无覆盖" --> Enabled["enabled<br/>名字 + description"]
|
|
12
|
+
|
|
13
|
+
Override -- "name-only" --> NameOnly["name-only<br/>只有名字 · 不占预算"]
|
|
14
|
+
|
|
15
|
+
Override -- "off" --> Off["off<br/>CC 什么都看不到"]
|
|
16
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# add 安装流程
|
|
2
|
+
|
|
3
|
+
```mermaid
|
|
4
|
+
flowchart LR
|
|
5
|
+
Start["cckit add<br/>git URL / 本地路径"] --> Clone["git clone<br/>锁 commit sha"]
|
|
6
|
+
Clone --> Validate["manifest 校验<br/>schema + 语义检查"]
|
|
7
|
+
Validate --> Lint["lint<br/>命名 / description / CRLF<br/>prompt injection / typosquatting"]
|
|
8
|
+
Lint --> Plan["展示执行计划<br/>等待确认(-y 跳过)"]
|
|
9
|
+
Plan --> Store["写入 store"]
|
|
10
|
+
Store --> Env["构建隔离环境<br/>venv / node_modules(uv)"]
|
|
11
|
+
Env --> Postinstall["运行 postinstall<br/>(限 kit 目录内)"]
|
|
12
|
+
Postinstall --> Registry["写 registry.json"]
|
|
13
|
+
Registry --> Link["建立 link<br/>→ CC 扫描目录"]
|
|
14
|
+
Link --> Done["完成 · enabled"]
|
|
15
|
+
```
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 痛点与方案映射
|
|
2
|
+
|
|
3
|
+
```mermaid
|
|
4
|
+
flowchart TB
|
|
5
|
+
subgraph Problems["当前痛点"]
|
|
6
|
+
P1["Skill 数量多<br/>半串行执行 · 自由度有限"]
|
|
7
|
+
P2["依赖复杂<br/>部署困难"]
|
|
8
|
+
P3["迭代中舍弃了<br/>有潜力的 Skill"]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
subgraph Solution["cckit 工具箱管理器"]
|
|
12
|
+
S1["四态开关<br/>精确控制调度与预算"]
|
|
13
|
+
S2["隔离环境 + 依赖检查<br/>一键部署"]
|
|
14
|
+
S3["工具箱化<br/>按需召回复用"]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
P1 --> S1
|
|
18
|
+
P2 --> S2
|
|
19
|
+
P3 --> S3
|
|
20
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# 状态迁移图
|
|
2
|
+
|
|
3
|
+
```mermaid
|
|
4
|
+
stateDiagram-v2
|
|
5
|
+
direction LR
|
|
6
|
+
|
|
7
|
+
[*] --> installed : add
|
|
8
|
+
|
|
9
|
+
state "installed<br/>无 link · CC 看不到" as installed
|
|
10
|
+
state "enabled<br/>link ✓ · 名字 + description" as enabled
|
|
11
|
+
state "name-only<br/>link ✓ · 只有名字" as nameonly
|
|
12
|
+
state "off<br/>link ✓ · CC 看不到" as off
|
|
13
|
+
|
|
14
|
+
installed --> enabled : enable
|
|
15
|
+
installed --> nameonly : name-only
|
|
16
|
+
|
|
17
|
+
enabled --> off : disable
|
|
18
|
+
enabled --> nameonly : name-only
|
|
19
|
+
enabled --> installed : disable --purge
|
|
20
|
+
|
|
21
|
+
nameonly --> enabled : enable
|
|
22
|
+
nameonly --> off : disable
|
|
23
|
+
nameonly --> installed : disable --purge
|
|
24
|
+
|
|
25
|
+
off --> enabled : enable
|
|
26
|
+
off --> nameonly : name-only
|
|
27
|
+
off --> installed : disable --purge
|
|
28
|
+
|
|
29
|
+
installed --> [*] : remove
|
|
30
|
+
enabled --> [*] : remove
|
|
31
|
+
nameonly --> [*] : remove
|
|
32
|
+
off --> [*] : remove
|
|
33
|
+
```
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cckit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Claude Code 的 Skill 工具箱管理器
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
7
7
|
Requires-Dist: jsonschema>=4.20
|
|
8
8
|
Requires-Dist: packaging>=24.0
|
|
9
9
|
Requires-Dist: pyyaml>=6.0
|
|
10
|
+
Provides-Extra: web
|
|
11
|
+
Requires-Dist: fastapi>=0.115; extra == 'web'
|
|
12
|
+
Requires-Dist: uvicorn>=0.30; extra == 'web'
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# CCKitKit
|
|
4
4
|
|
|
5
|
-
[](#) [](#) [](#) [](#)
|
|
6
6
|
|
|
7
7
|
</div>
|
|
8
8
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
## 安装
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
**用户安装(推荐):**
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
18
|
# 先装 uv
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
uv tool install cckit
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
从 Releases 下载安装: 见 [Releases](https://github.com/0Ra1n416/CCKitKit/releases) 。
|
|
27
|
+
|
|
26
28
|
从源码安装(开发者):
|
|
27
29
|
|
|
28
30
|
```bash
|
|
@@ -59,7 +61,49 @@ cckit doctor --fix # 只修明确安全的项
|
|
|
59
61
|
cckit exec my-skill scripts/run.py [args...]
|
|
60
62
|
```
|
|
61
63
|
|
|
62
|
-
共 **
|
|
64
|
+
共 **9 个命令**:`add` / `list` / `enable` / `disable` / `name-only` / `remove` / `doctor` / `exec` / `web`。完整规格见 [Docs/cli-spec.md](Docs/cli-spec.md)。
|
|
65
|
+
|
|
66
|
+
## Web 管理面板
|
|
67
|
+
|
|
68
|
+
cckit 附带一个可选的管理面板(列表 / 导入 / 卸载 / 状态切换 / 诊断)。它是**纯增量**:不装 `[web]` 额外依赖时,`cckit` 本体与现在完全一样,`uv tool install cckit` 也不会带入任何 web 依赖。
|
|
69
|
+
|
|
70
|
+
### 启用
|
|
71
|
+
|
|
72
|
+
**普通用户**(前端已随 wheel 打包,一条命令即用):
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
uv tool install 'cckit[web]' # 带后端依赖 + 前端静态产物
|
|
76
|
+
cckit web # 前后端一起起,打开 http://127.0.0.1:8000 即用
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**开发者**(源码仓库里改前端):
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
cd web && npm install && npm run build # 产出 web/dist/,uv build 时打进 wheel
|
|
83
|
+
cckit web # 自动定位前端(包内 static → 源码 web/dist)
|
|
84
|
+
|
|
85
|
+
# 开发调试:前端单独起 vite dev(自带 /api 代理)
|
|
86
|
+
cckit web # 后端(不托管前端)
|
|
87
|
+
cd web && npm run dev # 前端 dev server(:5173),代理 /api 到 :8000
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
前端是 Vite + React 19 + Tailwind v4 + shadcn/ui,静态产物由后端托管。
|
|
91
|
+
|
|
92
|
+
### 功能
|
|
93
|
+
|
|
94
|
+
- **dashboard 布局**:`Sidebar`(可收起成图标条)+ 右侧内容区。
|
|
95
|
+
- **作用域**:全局 + 装过 kit 的项目 + 手动「关注」的项目(即使暂无 skill 也显示,并自动建 `.claude`;关注项可取消关注)。
|
|
96
|
+
- **kit 列表**:项目 kit 可收起/展开/卸载;每个 skill 带四态开关,`name-only` 附解释。
|
|
97
|
+
- **全局 skill 项目覆盖**:项目作用域下,全局 skill 单独一组,可「跟随全局 / 仅名字 / 关闭」单独覆盖(不复用四态)。
|
|
98
|
+
- **添加 Kit**:填仓库地址或本地路径 → 展示安装计划(依赖 / postinstall / 系统依赖 / 来源+sha)等确认 → 实时日志。
|
|
99
|
+
- **诊断**:勾选 `--fix` 自动修复明确安全的项,下方展示逐项结果。
|
|
100
|
+
- **刷新**:侧栏刷新按钮 + 写操作后自动刷新;所有开关改动提示「新会话生效」。
|
|
101
|
+
|
|
102
|
+
### 安全与部署
|
|
103
|
+
|
|
104
|
+
- 后端**默认只绑 `127.0.0.1`**。要作为服务器面板被浏览器访问时,用 `cckit web --host 0.0.0.0`。
|
|
105
|
+
⚠️ 放开即把「能装 kit(跑作者代码)、能改 skill 状态」的能力暴露给网段,请只在可信内网使用,必要时在反向代理层加鉴权。
|
|
106
|
+
- 嵌入其他页面用 **iframe**:后端托管前端后,宿主页 `<iframe src="http://<server>:<port>/">` 即可(同源隔离,无 CORS 问题)。
|
|
63
107
|
|
|
64
108
|
## 特色
|
|
65
109
|
|
|
@@ -166,11 +210,11 @@ uv run cckit --help # 直接跑,无需安装
|
|
|
166
210
|
uv tool install --editable . # 本机可编辑安装
|
|
167
211
|
```
|
|
168
212
|
|
|
169
|
-
代码结构(`src/cckit/`,
|
|
213
|
+
代码结构(`src/cckit/`,18 个文件,含 `web/` 子包):
|
|
170
214
|
|
|
171
215
|
| 模块 | 职责 |
|
|
172
216
|
|---|---|
|
|
173
|
-
| `cli.py` | argparse 分发到
|
|
217
|
+
| `cli.py` | argparse 分发到 9 个子命令 |
|
|
174
218
|
| `installer.py` | `add` 全流程:锁 sha → 校验 → lint → 计划确认 → store/env/postinstall/registry/link |
|
|
175
219
|
| `manifest.py` | `cckit.yaml` 加载 + schema 校验 + 语义检查 |
|
|
176
220
|
| `schema.py` | JSON Schema 加载器(Draft 2020-12) |
|
|
@@ -183,3 +227,5 @@ uv tool install --editable . # 本机可编辑安装
|
|
|
183
227
|
| `doctor.py` | 只读诊断 + 安全修复 |
|
|
184
228
|
| `config.py` | 路径与平台解析(`CCKIT_HOME` / `CLAUDE_CONFIG_DIR` / 项目根) |
|
|
185
229
|
| `errors.py` | 受检错误 `CckitError` |
|
|
230
|
+
| `projects.py` | 关注项目清单 `projects.json` 原子读写 |
|
|
231
|
+
| `web/` | Web 管理面板后端(FastAPI,惰性 import,`[web]` 可选依赖) |
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""hatch 构建钩子:若前端产物 web/dist 存在,把它作为 package data 打进 wheel。
|
|
2
|
+
|
|
3
|
+
这样「完整构建」(先 `cd web && npm run build` 再 `uv build`)产出的 wheel 自带
|
|
4
|
+
前端,用户 `uv tool install 'cckit[web]'` 后 `cckit web` 一键启动;「纯本体构建」
|
|
5
|
+
(不跑前端构建)则 wheel 不含前端,核心安装保持纯净(见 Docs/11-web-panel.md)。
|
|
6
|
+
|
|
7
|
+
要点:wheel 是从 sdist 解压目录构建的(uv build),所以 sdist 阶段要把 web/dist
|
|
8
|
+
以**原始路径**带进 sdist,否则 wheel 阶段在解压目录里找不到它。
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CustomBuildHook(BuildHookInterface):
|
|
18
|
+
def initialize(self, version, build_data):
|
|
19
|
+
dist = Path(self.root) / "web" / "dist"
|
|
20
|
+
if not (dist / "index.html").is_file():
|
|
21
|
+
return
|
|
22
|
+
if self.target_name == "sdist":
|
|
23
|
+
# sdist 保留原始路径,供 wheel 阶段从解压目录读取
|
|
24
|
+
build_data.setdefault("force_include", {})[str(dist)] = "web/dist"
|
|
25
|
+
else: # wheel
|
|
26
|
+
# wheel 阶段把解压目录里的 web/dist 放到最终位置 cckit/web/static
|
|
27
|
+
build_data.setdefault("force_include", {})[str(dist)] = "cckit/web/static"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "cckit"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.1"
|
|
4
4
|
description = "Claude Code 的 Skill 工具箱管理器"
|
|
5
5
|
requires-python = ">=3.12"
|
|
6
6
|
dependencies = [
|
|
@@ -9,6 +9,9 @@ dependencies = [
|
|
|
9
9
|
"packaging>=24.0",
|
|
10
10
|
]
|
|
11
11
|
|
|
12
|
+
[project.optional-dependencies]
|
|
13
|
+
web = ["fastapi>=0.115", "uvicorn>=0.30"]
|
|
14
|
+
|
|
12
15
|
[project.scripts]
|
|
13
16
|
cckit = "cckit.cli:main" # 装完后 `cckit` 命令指向这里
|
|
14
17
|
|
|
@@ -19,5 +22,17 @@ build-backend = "hatchling.build"
|
|
|
19
22
|
[tool.hatch.build.targets.wheel]
|
|
20
23
|
packages = ["src/cckit"] # 显式声明 src layout
|
|
21
24
|
|
|
25
|
+
[tool.hatch.build.targets.sdist]
|
|
26
|
+
exclude = [
|
|
27
|
+
"/.git",
|
|
28
|
+
"/.venv",
|
|
29
|
+
"/.claude",
|
|
30
|
+
"/dist",
|
|
31
|
+
"/web/node_modules",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[tool.hatch.build.hooks.custom]
|
|
35
|
+
path = "hatch_build.py" # 条件打包前端产物(web/dist 存在才打进 wheel)
|
|
36
|
+
|
|
22
37
|
[dependency-groups]
|
|
23
38
|
dev = ["pytest>=8"] # uv sync 默认装上,供 `uv run pytest`
|