Skip to content

Commit 9cb7e98

Browse files
Light ChengLight Cheng
authored andcommitted
feat: vendor light-kanban-worker Skill snapshot for offline/manual install
skills/light-kanban-worker/ is a byte-identical snapshot of LightDevCoder/skills v0.1.4 (commit a9cc8aa). skills/manifest.json pins source identity and per-file SHA-256; scripts/verify-vendored-skill.cjs (with positive/negative self-test) is wired into make check and CI so the snapshot cannot drift. README Quick Start Step 2 now offers both install paths (npx recommended, manual copy offline); AGENTS.md, spec.md, PROGRESS.md, and the manual checklist (S1b + regenerated xlsx) updated.
1 parent a26d632 commit 9cb7e98

22 files changed

Lines changed: 1323 additions & 8 deletions

.github/workflows/ci.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,12 @@ jobs:
5959

6060
- name: go test
6161
run: go test ./...
62+
63+
# v1.0.5: the vendored light-kanban-worker Skill snapshot must match
64+
# skills/manifest.json (SHA-256 pinned from the upstream
65+
# LightDevCoder/skills release tag); the script self-test exercises
66+
# positive and negative fixtures.
67+
- name: Verify vendored Worker Skill snapshot
68+
run: |
69+
node scripts/verify-vendored-skill.cjs
70+
node scripts/verify-vendored-skill.cjs --self-test

.scratch/task-board/spec.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,15 @@ knowledge of the REST API — one line suffices:
181181
Use light-kanban-worker to process at most one Light-Kanban task.
182182
```
183183

184+
### Vendored snapshot
185+
186+
This repository ships the Skill as a byte-identical snapshot in
187+
`skills/light-kanban-worker/` (pinned to `LightDevCoder/skills` tag
188+
`v0.1.4`, commit `a9cc8aa`) for offline / manual host installation. The
189+
upstream repository remains the behavioral authority; the snapshot is
190+
read-only, integrity-pinned by `skills/manifest.json` (SHA-256), and checked
191+
by `make check` and CI (`scripts/verify-vendored-skill.cjs`).
192+
184193
### Validation for this release
185194

186195
- Board-side: `make check` + `make cross` (four platforms), no Go/UI behavior

AGENTS.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ A single-binary Go kanban board: a human queues tasks (each card points at a wor
99
- `internal/store/` — SQLite store + state machine (+ `store_test.go`)
1010
- `internal/webui/``webui.go` embeds `dist/` via `go:embed`; **`dist/` is the committed production build of the frontend**
1111
- `frontend/` — React 18 + TypeScript + Vite app (the real UI source; see ADR-0002)
12-
- `scripts/``fetch-go.cjs` / `goenv.ps1` / `cross-build.ps1` / `make-checklist-xlsx.cjs` / `seed-demo.cjs`
12+
- `scripts/``fetch-go.cjs` / `goenv.ps1` / `cross-build.ps1` / `make-checklist-xlsx.cjs` / `seed-demo.cjs` / `verify-vendored-skill.cjs`
13+
- `skills/light-kanban-worker/`**vendored snapshot** of the official worker Skill from `LightDevCoder/skills` (see `skills/README.md`); integrity pinned by `skills/manifest.json` and checked by `make check`/CI
1314

1415
## Run / build / test
1516

@@ -18,7 +19,7 @@ A single-binary Go kanban board: a human queues tasks (each card points at a wor
1819
- **Frontend dev**: `make frontend-install` once, then `make dev-frontend` (Vite on :5173, proxies `/api` to a Go backend on :8641). Production staging: `make frontend-build` rebuilds and copies `frontend/dist``internal/webui/dist` (commit the result with your change).
1920
- **Test**: `go test ./...` — tests live at the two agreed Go seams: HTTP API (`internal/api/api_test.go`) and the store (`internal/store/store_test.go`), plus a tiny cmd seam (`cmd/light-kanban/main_test.go`) pinning the listen-address/startup-URL contract. v1.0.4 adds a frontend pure-logic seam: the product tour's decision logic (`frontend/src/components/ProductTour/logic.ts` + `steps.ts`) is unit-tested with vitest (`cd frontend && npm test`). The committed `internal/webui/dist` keeps the Go tests green on a fresh clone without npm.
2021
- **Vet / format**: `go vet ./...`; `gofmt -l internal cmd scripts` (never `gofmt -l .``.tools/` is the vendored toolchain).
21-
- **Pre-commit gate**: `make check` — rebuilds the frontend, runs the frontend unit tests, verifies the committed `internal/webui/dist` matches the source, then runs gofmt / vet / tests. CI (`.github/workflows/ci.yml`) runs the same checks on every push to main and every PR.
22+
- **Pre-commit gate**: `make check` — rebuilds the frontend, runs the frontend unit tests, verifies the committed `internal/webui/dist` matches the source, runs gofmt / vet / tests, and verifies the vendored Worker Skill snapshot (`node scripts/verify-vendored-skill.cjs` + `--self-test`). CI (`.github/workflows/ci.yml`) runs the same checks on every push to main and every PR.
2223
- **Cross-compile**: `make cross` (or `scripts\cross-build.ps1`) → `dist/` binaries: linux (amd64), darwin (amd64 + arm64), windows (amd64). Both build the frontend first.
2324
- **Demo data**: `node scripts/seed-demo.cjs` seeds a running board (35 tasks / 3 agents) for density checks and screenshots.
2425
- **Data**: SQLite at `-db kanban.db` (default, working directory); `:memory:` accepted. Uploaded agent avatars live in `-avatars avatars` (default) and are served from `/api/avatars/*`.
@@ -30,6 +31,7 @@ A single-binary Go kanban board: a human queues tasks (each card points at a wor
3031
- **i18n is dual-source**: `frontend/src/i18n/zh.ts` is the key schema; `en.ts` must stay structurally identical (tsc enforces it).
3132
- **Red-green discipline**: new behavior starts with a failing test at one of the agreed seams (Go: HTTP API / store / cmd; frontend: the ProductTour pure-logic module).
3233
- **Embedded dist ships with its source**: every change to `frontend/src/` must commit the regenerated `internal/webui/dist/` in the same commit (`make frontend-build`, then verify with `make check`) — otherwise the shipped binary silently keeps the old UI.
34+
- **Vendored Skill snapshot is read-only**: never edit files under `skills/light-kanban-worker/` in place. The behavioral authority is the upstream `LightDevCoder/skills` repository; to upgrade, re-vendor from the new upstream tag, regenerate `skills/manifest.json` (SHA-256) and update `skills/README.md``make check` (and CI) fail on any drift via `scripts/verify-vendored-skill.cjs`.
3335

3436
## Agent skills
3537

Makefile

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ NPM ?= npm
55
FRONTEND_DIR := frontend
66
WEBUI_DIST := internal/webui/dist
77

8-
.PHONY: build test vet cross run run-lan clean frontend-install frontend-build dev-frontend check
8+
.PHONY: build test vet cross run run-lan clean frontend-install frontend-build dev-frontend check check-vendor
99

1010
# Install frontend deps exactly from the lockfile (first run / after upgrades).
1111
frontend-install:
@@ -38,16 +38,26 @@ cross: frontend-build
3838
GOOS=darwin GOARCH=arm64 $(GO) build -o $(DIST)/light-kanban-darwin-arm64 ./cmd/light-kanban
3939
GOOS=windows GOARCH=amd64 $(GO) build -o $(DIST)/light-kanban.exe ./cmd/light-kanban
4040

41+
# Integrity guard for the vendored light-kanban-worker Skill snapshot
42+
# (skills/light-kanban-worker/): every file must match skills/manifest.json
43+
# (SHA-256 pinned from the upstream LightDevCoder/skills release tag).
44+
# The script also carries a --self-test with positive/negative fixtures.
45+
check-vendor:
46+
node scripts/verify-vendored-skill.cjs
47+
node scripts/verify-vendored-skill.cjs --self-test
48+
4149
# Pre-commit gate (v1.0.4): rebuild the frontend, run its unit tests
4250
# (vitest — product tour logic), verify the committed embedded dist matches
43-
# the source, and run every Go check.
51+
# the source, and run every Go check. v1.0.5 adds the vendored-Skill
52+
# integrity guard.
4453
# CI (.github/workflows/ci.yml) runs the same steps.
4554
check: frontend-build
4655
cd $(FRONTEND_DIR) && $(NPM) test
4756
test -z "$$(gofmt -l cmd internal scripts)"
4857
$(GO) vet ./...
4958
$(GO) test ./...
5059
git diff --exit-code -- $(WEBUI_DIST)
60+
$(MAKE) check-vendor
5161

5262
# Run with the program's own default: loopback-only (127.0.0.1:8641).
5363
run:

PROGRESS.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
- **无 Go / UI / API 变更**:v1.0.5 不新增、不修改任何 REST 端点;不修改 UI、不重新截图、不新增任务状态 / daemon / WebSocket / 认证 / scheduler
1717
- **Worker Skill(Skills 仓库,v0.1.4 已发布)**:第一方 `light-kanban-worker`(model-invoked,支持手动入口)——每次唤醒最多处理一张卡:稳定 identity(复用服务器已有 name/avatar)→ 先查自己持有的 in_progress(reviewFeedback 优先)→ 无遗留才领取 FIFO 第一张 todo(原子 claim,最多 2 次冲突重试)→ 校验 workspace(不可访问 → block 带具体原因)→ 读任务上下文 + 项目指令 → 执行 → `complete`(等你确认)或 `block` → 停止;绝不 archive/accept/delete/recycle/unblock,无 daemon / 无限轮询 / 运行时脚本
1818
- **准入与验证**:完整准入路径(`review-loop agent-skill` PASS,独立 Critic + Evaluator,3 findings 修复 + 1 驳回);行为场景 A–F 对真实 Light-Kanban 服务器全 PASS(新任务 / 退回返工 / 双 worker 原子 claim / workspace 缺失 block / 空队列无变更 / 离线无变更);v0.1.4 tag 发布后 fresh-install 验证 PASS(CLI 1.5.22,整集合 8 包 + 单 Skill,latest 与 #v0.1.4 形式,安装文件与 tag 逐字节一致);Skills CI green(顺带修复 ask-light scanner 的跨平台 `Test-PathUnder` 分隔符 bug——v0.1.3 Python 移植后 ubuntu CI 一直红的存量问题)
19-
- **Light-Kanban 文档**:README / README_CN Quick Start 重写为五步(运行二进制 → 装 Worker Skill → 建卡 → scheduler prompt → 验收),新增 Use Cases(定时编码 Agent / 多 Agent 共享队列 / 人工验收闭环 / 阻碍工作 / 跨项目个人队列 / 边界说明),curl 降级到「手动 Agent 接入(API 方式)」;spec.md 新增「v1.0.5 Worker Integration」章节(无 API 变更 + Skill 协议 + scheduler 边界 + 验证);manual-test-checklist.md 新增 S 节(8 条 worker 集成清单)+ xlsx 已重新生成;frontend/package.json + package-lock.json = `1.0.5`
20-
- **发布门禁**:Skills v0.1.4 已先发布并验证(README 引用真实 tag);Light-Kanban 需 `make check` + `make cross` 四平台 PASS,然后**停下来等用户最终验收**;未经「可以发布」不得创建 v1.0.5 Release
19+
- **Light-Kanban 文档**:README / README_CN Quick Start 重写为五步(运行二进制 → 装 Worker Skill → 建卡 → scheduler prompt → 验收),新增 Use Cases(定时编码 Agent / 多 Agent 共享队列 / 人工验收闭环 / 阻碍工作 / 跨项目个人队列 / 边界说明),curl 降级到「手动 Agent 接入(API 方式)」;spec.md 新增「v1.0.5 Worker Integration」章节(无 API 变更 + Skill 协议 + scheduler 边界 + vendored 快照 + 验证);manual-test-checklist.md 新增 S 节(worker 集成清单)+ xlsx 已重新生成;frontend/package.json + package-lock.json = `1.0.5`
20+
- **vendored Skill 快照(用户选定方案 2)**`skills/light-kanban-worker/` 为上游 `LightDevCoder/skills v0.1.4`(commit `a9cc8aa`)的逐字节快照,供离线 / 无 npx 用户手动复制安装(README Quick Start 第二步两种方式);`skills/manifest.json` 记录来源与 10 个文件 SHA-256,`scripts/verify-vendored-skill.cjs`(含 positive/negative 自测 4 断言)接入 `make check` 与 CI——快照只读,升级须从上游新 tag 重新抽取并重生成 manifest(AGENTS.md 开发契约已更新)
21+
- **发布门禁**:Skills v0.1.4 已先发布并验证(README 引用真实 tag);Light-Kanban 需 `make check` + `make cross` 四平台 PASS,然后**停下来等用户最终验收**;未经「可以发布」不得创建 v1.0.5 Release(发布时附 4 个二进制,并附 light-kanban-worker 快照 zip 作为 release asset)
2122

2223
## 2. v1.0.4(已发布)
2324

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ Download the binary for your machine from [Releases](https://github.com/LightDev
8383

8484
### Step 2 — Install the Worker Skill
8585

86-
Install the official worker Skill for your agent host:
86+
Install the official worker Skill for your agent host (recommended):
8787

8888
```bash
8989
npx skills add LightDevCoder/skills#v0.1.4 \
@@ -93,6 +93,8 @@ npx skills add LightDevCoder/skills#v0.1.4 \
9393
--agent '*'
9494
```
9595

96+
No `npx` / offline? This repository ships the same Skill as a byte-identical snapshot in [`skills/light-kanban-worker/`](skills/light-kanban-worker/SKILL.md) — copy the whole folder into your agent host's recognized skills root (e.g. `~/.agents/skills/light-kanban-worker`) and refresh the host. See [`skills/README.md`](skills/README.md).
97+
9698
Source and docs: [LightDevCoder/skills](https://github.com/LightDevCoder/skills)[`skills/light-kanban-worker/`](https://github.com/LightDevCoder/skills/tree/main/skills/light-kanban-worker) (behavior authority: its `SKILL.md`). Works with Light-Kanban v1.0.4+.
9799

98100
### Step 3 — Create Work

README_CN.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ chmod +x light-kanban-linux-amd64
8383

8484
### 第二步 — 安装 Worker Skill
8585

86-
给你的 agent host 安装官方 worker Skill:
86+
给你的 agent host 安装官方 worker Skill(推荐)
8787

8888
```bash
8989
npx skills add LightDevCoder/skills#v0.1.4 \
@@ -93,6 +93,8 @@ npx skills add LightDevCoder/skills#v0.1.4 \
9393
--agent '*'
9494
```
9595

96+
没有 npx / 离线环境?本仓库自带同一 Skill 的**逐字节快照**[`skills/light-kanban-worker/`](skills/light-kanban-worker/SKILL.md))——把整个目录复制到 agent host 认可的 skills root(例如 `~/.agents/skills/light-kanban-worker`),刷新 host 即可。详见 [`skills/README.md`](skills/README.md)
97+
9698
来源与文档:[LightDevCoder/skills](https://github.com/LightDevCoder/skills)[`skills/light-kanban-worker/`](https://github.com/LightDevCoder/skills/tree/main/skills/light-kanban-worker)(行为权威:其 `SKILL.md`)。兼容 Light-Kanban v1.0.4+。
9799

98100
### 第三步 — 创建任务
229 Bytes
Binary file not shown.

docs/manual-test-checklist.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@
218218
| # | 测什么 | 怎么测 | 预期结果 | 结果 | 评论(留给我) |
219219
|---|--------|--------|----------|------|--------------|
220220
| S1 | 安装 Worker Skill | `npx skills add LightDevCoder/skills#v0.1.4 --skill light-kanban-worker --yes --copy --agent '*'` | 安装成功;`npx --yes skills list` 列出 `light-kanban-worker`(不依赖源码 checkout) | |
221+
| S1b | 手动复制安装(离线 / 无 npx) | 把本仓库 `skills/light-kanban-worker/` 整个目录复制到 host 认可的 skills root(如 `~/.agents/skills/light-kanban-worker`),刷新 host | host 的 skill 列表能发现 `light-kanban-worker``node scripts/verify-vendored-skill.cjs` 输出 `VENDOR_SKILL=PASS (10 files …)` | |
221222
| S2 | 一次性手动运行 | 建一张 todo 卡后,用 prompt「Use light-kanban-worker to process one task from http://127.0.0.1:8641 as agent codex-main.」跑一次 | Agent 领取该卡 → 进入 workspace 执行 → `complete` → 卡片到**等你确认**,本次运行结束 | |
222223
| S3 | 定时 prompt | 用 README Quick Start 第四步的 scheduler prompt 创建每 15 分钟(或更短)的定时任务 | 每次唤醒只处理一张卡;没有卡时正常结束,不新建任务、不卡死 | |
223224
| S4 | 退回修改闭环 |**等你确认**卡点「退回修改」并附反馈 | 下一次唤醒同一 Agent 优先处理该卡,按反馈修改后重新 `complete`**等你确认**;不需要新建任务 | |

scripts/verify-vendored-skill.cjs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#!/usr/bin/env node
2+
// verify-vendored-skill.cjs — integrity guard for the vendored
3+
// light-kanban-worker Skill snapshot (skills/light-kanban-worker/).
4+
//
5+
// Reads skills/manifest.json and verifies every listed file is present and
6+
// byte-identical (SHA-256) to the pinned upstream snapshot. Wired into
7+
// `make check` so the vendored copy can never drift from the upstream tag
8+
// without the gate failing.
9+
//
10+
// Usage:
11+
// node scripts/verify-vendored-skill.cjs # verify the snapshot
12+
// node scripts/verify-vendored-skill.cjs --self-test
13+
// # positive + negative assertions: a temp copy passes; a tampered
14+
// # temp copy fails (non-zero assertion count, exit 0 only when the
15+
// # guard itself behaves correctly)
16+
17+
"use strict";
18+
19+
const fs = require("fs");
20+
const path = require("path");
21+
const crypto = require("crypto");
22+
const os = require("os");
23+
24+
const REPO_ROOT = path.resolve(__dirname, "..");
25+
const SKILL_DIR = path.join(REPO_ROOT, "skills", "light-kanban-worker");
26+
const MANIFEST_PATH = path.join(REPO_ROOT, "skills", "manifest.json");
27+
28+
function sha256(file) {
29+
return crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex");
30+
}
31+
32+
// verifyManifest(rootDir, manifestPath) -> { files, failures }
33+
// rootDir is the directory that contains manifest.json and the package dir.
34+
function verifyManifest(rootDir, manifestPath) {
35+
let manifest;
36+
try {
37+
manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
38+
} catch (err) {
39+
return { files: 0, failures: [`manifest unreadable: ${err.message}`] };
40+
}
41+
const failures = [];
42+
const pkg = manifest.vendor && manifest.vendor.package;
43+
if (!pkg) failures.push("manifest is missing vendor.package");
44+
if (!manifest.files || !Array.isArray(manifest.files) || manifest.files.length === 0) {
45+
failures.push("manifest has no file list");
46+
return { files: 0, failures };
47+
}
48+
const pkgDir = path.join(rootDir, "skills", pkg);
49+
for (const entry of manifest.files) {
50+
const file = path.join(pkgDir, entry.path);
51+
if (!fs.existsSync(file)) {
52+
failures.push(`missing file: ${entry.path}`);
53+
continue;
54+
}
55+
const actual = sha256(file);
56+
if (actual !== entry.sha256) failures.push(`hash mismatch: ${entry.path}`);
57+
}
58+
return { files: manifest.files.length, failures };
59+
}
60+
61+
function main() {
62+
if (process.argv.includes("--self-test")) {
63+
let assertions = 0;
64+
const failures = [];
65+
const assert = (cond, label) => {
66+
assertions += 1;
67+
if (!cond) failures.push(label);
68+
};
69+
70+
// Positive fixture: a pristine temp copy of the vendored snapshot passes.
71+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "lk-vendor-"));
72+
fs.cpSync(path.join(REPO_ROOT, "skills"), path.join(tmp, "skills"), { recursive: true });
73+
const ok = verifyManifest(tmp, path.join(tmp, "skills", "manifest.json"));
74+
assert(ok.files === 10, `pristine copy must verify 10 files (got ${ok.files})`);
75+
assert(ok.failures.length === 0, `pristine copy must pass (got: ${ok.failures.join("; ")})`);
76+
77+
// Negative fixture: a tampered copy fails with a hash mismatch.
78+
const tampered = path.join(tmp, "skills", "light-kanban-worker", "SKILL.md");
79+
fs.appendFileSync(tampered, "\n# tampered\n");
80+
const bad = verifyManifest(tmp, path.join(tmp, "skills", "manifest.json"));
81+
assert(bad.failures.some((f) => f.includes("hash mismatch: SKILL.md")), "tampered copy must fail with a SKILL.md hash mismatch");
82+
83+
// Negative fixture: a deleted file fails with a missing-file error.
84+
fs.rmSync(tampered);
85+
const missing = verifyManifest(tmp, path.join(tmp, "skills", "manifest.json"));
86+
assert(missing.failures.some((f) => f.includes("missing file: SKILL.md")), "deleted file must fail with a missing-file error");
87+
88+
fs.rmSync(tmp, { recursive: true, force: true });
89+
if (failures.length > 0) {
90+
console.error(`VENDOR_SELF_TEST=FAIL (${failures.length} failures, ${assertions} assertions)`);
91+
for (const f of failures) console.error(`FAIL: ${f}`);
92+
process.exit(1);
93+
}
94+
console.log(`VENDOR_SELF_TEST=PASS (${assertions} assertions)`);
95+
return;
96+
}
97+
98+
const { files, failures } = verifyManifest(REPO_ROOT, MANIFEST_PATH);
99+
if (failures.length > 0) {
100+
console.error(`VENDOR_SKILL=FAIL (${failures.length} failures, ${files} files checked)`);
101+
for (const f of failures) console.error(`FAIL: ${f}`);
102+
console.error("Re-vendor from the upstream LightDevCoder/skills tag and regenerate skills/manifest.json — do not edit the snapshot in place.");
103+
process.exit(1);
104+
}
105+
console.log(`VENDOR_SKILL=PASS (${files} files match skills/manifest.json)`);
106+
}
107+
108+
main();

0 commit comments

Comments
 (0)