Check nested library pins and test the three agent libraries #152
+33
-13
@@ -8,20 +8,40 @@ on:
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GOPROXY: https://goproxy.cn,direct
|
||||
steps:
|
||||
- name: Configure submodule auth over HTTPS
|
||||
run: git config --global url."https://weichen:${{ secrets.SUBMODULE_TOKEN }}@git-home.u1680832.nyat.app:30319/".insteadOf "ssh://git@git-ssh.u1680832.nyat.app:31411/"
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.27"
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "22"
|
||||
- name: Combination test (core + backend + frontend)
|
||||
- name: Checkout
|
||||
env:
|
||||
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SUBMODULE_TOKEN: ${{ secrets.SUBMODULE_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git init -q
|
||||
git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
||||
git -c http.extraheader="AUTHORIZATION: token ${TOKEN}" fetch --depth=1 origin "${GITHUB_SHA}"
|
||||
git checkout -q --detach FETCH_HEAD
|
||||
if [ -z "${SUBMODULE_TOKEN}" ]; then
|
||||
echo "SUBMODULE_TOKEN is not configured" >&2
|
||||
exit 1
|
||||
fi
|
||||
git config --global url."https://weichen:${SUBMODULE_TOKEN}@git-home.u1680832.nyat.app:30319/".insteadOf "ssh://git@git-ssh.u1680832.nyat.app:31411/"
|
||||
git -c fetch.recurseSubmodules=false submodule update --init --recursive
|
||||
- name: Install Go 1.27.1
|
||||
run: |
|
||||
set -euo pipefail
|
||||
curl -fsSL -o "$RUNNER_TEMP/go.tgz" https://mirrors.aliyun.com/golang/go1.27.1.linux-amd64.tar.gz
|
||||
tar -C /usr/local -xzf "$RUNNER_TEMP/go.tgz"
|
||||
ln -sfn /usr/local/go/bin/go /usr/local/bin/go
|
||||
ln -sfn /usr/local/go/bin/gofmt /usr/local/bin/gofmt
|
||||
- name: Install Node 22
|
||||
run: |
|
||||
set -euo pipefail
|
||||
curl -fsSL -o "$RUNNER_TEMP/node.tar.xz" https://npmmirror.com/mirrors/node/v22.23.3/node-v22.23.3-linux-x64.tar.xz
|
||||
tar -C /usr/local --strip-components=1 -xJf "$RUNNER_TEMP/node.tar.xz"
|
||||
- name: Install house-style Python packages
|
||||
run: python3 -m pip install --break-system-packages -i https://pypi.tuna.tsinghua.edu.cn/simple python-docx python-pptx openpyxl
|
||||
- name: make test (boundaries, pins, libs, core, backend, frontend, ui, agent-command)
|
||||
run: make test
|
||||
- name: Build the single binary
|
||||
run: make build
|
||||
|
||||
+7
-1
@@ -1,6 +1,6 @@
|
||||
# feature/duplication-lesson-records 任务卡
|
||||
|
||||
任务主记录:Agent-System-Documents PR#7(内容)+ 本仓 PR(gitlink 钉入,链接见下方回填);状态:已完成;owner:weichen
|
||||
任务主记录:PR #13 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/13(merge f20c634fea);状态:已完成(回填);owner:weichen
|
||||
|
||||
## 基线与授权
|
||||
|
||||
@@ -65,3 +65,9 @@
|
||||
| 同步前验收 | 3072611209c445a0d87d54545cfd23d2b971e177 | 957de90142bc98bde3f479092e3892754000ef15 | 2026-10-01T05:23:44Z |
|
||||
| 同步前验收 | 4c4071e5d8e256dd8f82ba9c74efa1effd1e9df3 | 0ed945956af3f10231f7d80706c798fc83617e6c | 2026-10-01T04:50:27Z |
|
||||
| 同步前验收 | 4adc4cc458f15546e5605dc55843acc26b310c41 | 916437ca2d93310ed5b4e517f99b1a787d9af843 | 2026-10-01T06:09:46Z |
|
||||
|
||||
## 闭合记录(card-autoclose 回填)
|
||||
|
||||
- 依据:merge f20c634fea9e4316db664b4da7b4a6c772dd855e(PR #13)已包含于 origin/main,分支成果已落盘;本段为合入后回填。
|
||||
- 合并主题:Merge pull request 'Pin documents with the duplication lesson and follow-up records' (#13) from feature/duplication-lesson-records into main
|
||||
- 归档:随闭合移入 .task/archive/;任务执行期的过程证据见原任务记录与 PR。
|
||||
@@ -0,0 +1,66 @@
|
||||
# feature/agent-stack-r0-r1 任务卡
|
||||
|
||||
任务主记录:PR #152 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/152 ;状态:进行中;owner:weichen
|
||||
|
||||
## 基线与授权
|
||||
|
||||
- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= f4aa0348d7f60e4dd5b6b222205a2c561465db8e
|
||||
- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-agent-stack-r0-r1(worktree);分支:feature/agent-stack-r0-r1
|
||||
- 授权与交付终点:按提案第 5 节实施 R0(组合一致性)与 R1(三库 P0 与安全向 P1)。允许在 Agent-Intent、Agent-Native、Agent-Squad、Agent-System-Backend、Agent-System-Dev 五个仓各从 origin/main 切 feature/agent-stack-r0-r1,提交、推送并建 PR,推进 Dev 与 Backend 的 gitlink。终点 = 五个 PR 已开且均未合入。未授权:合入、发版、改写历史、变更分支保护、改 development-guidelines 嵌套指针。
|
||||
- 追加授权(2026-10-03,主检出 `make precheck` verdict READY,head=`f4aa0348d7`,linked worktrees=2):在同一批 `feature/agent-stack-r0-r1` 上补收尾加固与 CI。允许改 Squad 的并行审批与挂起、Dev 的指针检查、`make pin`、导入棘轮和 `task.sh`,五个仓的 CI workflow,以及任务卡欠账。R2 与 D1 等五个 PR 由所有者合入后再从各仓 main 开独立任务。未授权:合入、发版、改分支保护、配置 `SUBMODULE_TOKEN`。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
- 目标:Dev 测的就是发布的组合(go.work、指针一致性检查、库间依赖棘轮、库测试纳入 make test);修 I1/I2/I6、N1–N4/N13/N14、Q1–Q5/Q8/Q9/Q14–Q16,每条带回归测试。
|
||||
- 非目标:实现原生 Anthropic/Google 协议、合入 PR、发版、编排收敛到 Squad(后续批次)。
|
||||
|
||||
## 同步记录
|
||||
|
||||
| 节点 | sync_base_sha | tested_head_sha | checked_at |
|
||||
|---|---|---|---|
|
||||
| 启动 | f4aa0348d7f60e4dd5b6b222205a2c561465db8e | f4aa0348d7f60e4dd5b6b222205a2c561465db8e | 2026-10-03T00:27:10Z |
|
||||
| 同步前验收 | f4aa0348d7f60e4dd5b6b222205a2c561465db8e | 978bf8bdaec0890e241849f0fb9e6999b0a1de86 | 2026-10-03T02:10:29Z |
|
||||
|
||||
## 结果与验证
|
||||
|
||||
- 结果:五个 PR 已开,均未合入。合入顺序:Intent #3 https://git-home.u1680832.nyat.app:30319/weichen/Agent-Intent/pulls/3 、Native #8 https://git-home.u1680832.nyat.app:30319/weichen/Agent-Native/pulls/8 、Squad #7 https://git-home.u1680832.nyat.app:30319/weichen/Agent-Squad/pulls/7 、Backend #50 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Backend/pulls/50 、Dev #152 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/152 。指针:intent `3130190acb396589d6022c243bbe07ce7c31c881`,native `694b08cdbef5d52496f4425c9a22d1b77df14c23`,squad `8e987bf535efbbbf317147542e858217f2bb3504`,backend `898fdd137148836b2e52666a2b5e0d591ec308c3`。Dev 在 `978bf8b` 钉住这四条并加入指针检查、导入棘轮和三库测试。
|
||||
- go.work 未采用。实测工作区模块目录都落在 Dev 顶层 `deps/` 与 `modules/`,但最小版本选择把第三方抬高:`golang.org/x/crypto` v0.56.0→v0.57.0,`exp` `v0.0.0-20250305212735-054e65f0b394`→`v0.0.0-20251023183803-a4bb9ffd2546`,`net` v0.57.0→v0.59.0,`term` v0.45.0→v0.46.0,`text` v0.41.0→v0.42.0。库测试因此用 `GOWORK=off`。`development-guidelines` 嵌套指针仍是 `26b562d`,与 Dev 的 `ed2af3e` 不一致,`check-pins` 只告警。
|
||||
- 编号与回归测试:
|
||||
- I1 `TestRecognizeClassifierRejectsBadRefinement`、`TestRecognizeClassifierRebuildsTamperedHandler`
|
||||
- I2 `TestScopedSlotValidatorsDoNotInterfere`
|
||||
- I6 `TestRecognizeClassifierRefinedTopGetsSlots`
|
||||
- N1 `TestLoopBudgetToolCallCap`(含 `assertToolCallsPaired`)
|
||||
- N2 `TestParallelHostCallbacksAreSerial`、`TestHooksDoNotRunConcurrently`
|
||||
- N3 `TestStdioSlowCancelThenEcho`
|
||||
- N4 `TestPresetsAndClientForChatCompletions`
|
||||
- N13 `TestFetchResolveChangesToLoopbackRejected`
|
||||
- N14 `TestFetchHostCheckRedirectStillRejectsPrivate`
|
||||
- Q1 `TestStepApprovalApproveExecutes`、`TestStepApprovalSkipDoesNotCancel`
|
||||
- Q2 `TestApprovalSurvivesRestart`
|
||||
- Q3 `TestAtomicWriteLeavesNoTemp`、`TestAtomicWriteRenameFailureKeepsOriginal`
|
||||
- Q4 `TestInterruptedRunningStepStaysHeld`
|
||||
- Q5 `TestTwoEnginesOneRunIsBusy`
|
||||
- Q8/Q9 `TestWakeupDoesNotApprovePermission`(原有 `TestWakeupRunDone`、`TestWakeupGuardMaxFires` 仍通过)
|
||||
- Q14 `TestListenGuard`、`TestMissingTokenIsUnauthorized`
|
||||
- Q15 `TestPathTraversalRejected`
|
||||
- Q16 `TestOversizedBodyIs413`
|
||||
- 验证:
|
||||
- 启动 precheck(主检出,task-start 记录于 2026-10-03T00:27:10Z):verdict READY。head 与 origin/main 均为 `f4aa0348d7`。linked worktree 为 1(未合入的 `feature/agent-stack-blueprint`),未出现 `SHARED_WORKSPACE_BUSY` 或 `SYNC_REQUIRED`。
|
||||
- `make task-sync`:`Already up to date.` `[synced] sync_base=f4aa0348d7 tested_head=978bf8bdae checked_at=2026-10-03T02:10:29Z`。脚本按文件名把这一行写进了另一张任务卡,本提交已改回本卡。
|
||||
- `make test` 退出码 0(HEAD `314f798`,与 `978bf8b` 的代码相同):boundaries ok;pins ok(guidelines 三条 warn);intent 五包 ok;native 各包 ok(mcp 12.0s、tools 11.3s);squad 六包 ok;core ok;backend 各包 ok;frontend vitest 13 文件 68 项;ui tsc 与 vitest 11 文件 79 项;agent-command 两包 ok。
|
||||
- `make build` 退出码 0。版本串 `314f798+core=7c66075+backend=898fdd1+frontend=794c3e1+ui=b4a4fc1+agentcmd=cc1ad77+documents=acd6f01+native=694b08c+squad=8e987bf+intent=3130190`。
|
||||
- 负例:Backend 的 squad gitlink 临时改为 `5cbac00b994223b6aa76afd9bc70277b8b49e985` 后 `scripts/check-pins.sh` 退出码 1(`pin: modules/backend deps/agent-squad is 5cbac00b9942, Dev deps/agent-squad is 8e987bf535ef`)。已恢复到 `898fdd1`,再次运行 `pins ok`。该临时提交未推送。
|
||||
- 影响与剩余项:非 unix 平台没有 flock,只有进程内互斥(见 agent-squad PROJECT.md)。合入、发版、改写历史均未做。
|
||||
- 级联钉住与验收(2026-10-03,Dev `789a6f4`):
|
||||
- 指针:intent `7f7879b06b053f0a62746309b79e0e1b9a00f42d`,native `91c155618487e21edeb4f1d3cc27e985aae2b0d2`,squad `e928ea3c0fa649cbbbad22a93a1bc0a12dee5f7d`,backend `ef0a1bef0f7bee626e59f160be51fb0e5f6aa692`。
|
||||
- `make task-sync`:`Already up to date.` `[synced] sync_base=f4aa0348d7 tested_head=755474e6f5 checked_at=2026-10-03T10:22:12Z`。记录写在本卡。
|
||||
- `make test` 退出码 0:`boundaries ok`;`pins ok`(guidelines 三条 warn);intent、native、squad、core、backend、frontend(13 文件 68 项)、ui(tsc 与 11 文件 79 项)、agent-command 均通过。
|
||||
- `make build` 退出码 0。版本串 `789a6f4+core=7c66075+backend=ef0a1be+frontend=794c3e1+ui=b4a4fc1+agentcmd=cc1ad77+documents=acd6f01+native=91c1556+squad=e928ea3+intent=7f7879b`。
|
||||
- 各库在钉住后的头上另跑了 `scripts/submodule-consistency.sh`(intent、native、squad 均为 ok)以及 vet、test、race。Backend 跑了 `GOWORK=off go vet ./... && GOWORK=off go test -count=1 ./...`,退出码 0。
|
||||
- CI 首轮未绿。Intent 运行 661(头 `7f7879b`)在 30 秒内失败:克隆 `actions/checkout` 时 `dial tcp 20.205.243.166:443: i/o timeout`。按计划停下,没有改走宿主代理,也没有预热缓存。`SUBMODULE_TOKEN` 与必需检查都未配置。
|
||||
- 收尾加固(2026-10-03):
|
||||
- Squad `73b8d09545a8c479344aded2227de5fc520ef769`。并行组第二步 `TestParallelGroupSecondStepApprovalHolds`、`TestParallelGroupSecondStepPermissionHolds`;自由文本 `TestFreeTextKeepsChoiceHold`;失败后挂起仍在 `TestFailedDecisionRestoresPending`。`GOWORK=off go vet ./...`、`go test -count=1 ./squad/ ./cli/`、`go test -race -count=1 ./squad/` 均通过。
|
||||
- 同 tree 正例:Backend 所记 squad `8e987bf535efbbbf317147542e858217f2bb3504` 的 tree `0fe06ce3ceea5cfa32476e2f0eed7f86cebc44a0`,`commit-tree` 得本地 `6c0f1e8bf1be85f10163eb0c6eebb5a6aa8f8798` 并临时写入 Dev 索引。`check-pins` 输出 `ok modules/backend agent-squad (same tree)`,退出码 0。
|
||||
- 负例:空 tree 的本地提交 `8db069d7352d` 写入同一索引后,`check-pins` 退出码 1,`pin: modules/backend deps/agent-squad is 8e987bf535ef, Dev deps/agent-squad is 8db069d7352d`。索引已 `git reset` 恢复,再次 `pins ok`。两个临时对象都没有推送。
|
||||
- 棘轮:`scripts/lint-imports.go` 在空 `GOMODCACHE` 下的配对与有缓存的 `go list` 相同,14 对。`GOMODCACHE=$(mktemp -d) bash scripts/lint-boundaries.sh` 与默认缓存的输出都是 `boundaries ok`。
|
||||
| 同步前验收 | f4aa0348d7f60e4dd5b6b222205a2c561465db8e | 755474e6f5b4fb404c14d84437428d4886e5317f | 2026-10-03T10:22:12Z |
|
||||
@@ -10,10 +10,10 @@ BIN := bin/agent-system
|
||||
EMBED_DIR := $(BACKEND)/web/dist
|
||||
PLUGINS := plugins
|
||||
# 版本溯源(release-operations:运行制品须可对上固定组合)。无 tag 时 --always 给短 SHA。
|
||||
COMBO := core=$(shell git -C $(CORE) rev-parse --short HEAD 2>/dev/null)+backend=$(shell git -C $(BACKEND) rev-parse --short HEAD 2>/dev/null)+frontend=$(shell git -C $(FRONTEND) rev-parse --short HEAD 2>/dev/null)+ui=$(shell git -C $(UI) rev-parse --short HEAD 2>/dev/null)+agentcmd=$(shell git -C deps/agent-command rev-parse --short HEAD 2>/dev/null)+documents=$(shell git -C modules/documents rev-parse --short HEAD 2>/dev/null)
|
||||
COMBO := core=$(shell git -C $(CORE) rev-parse --short HEAD 2>/dev/null)+backend=$(shell git -C $(BACKEND) rev-parse --short HEAD 2>/dev/null)+frontend=$(shell git -C $(FRONTEND) rev-parse --short HEAD 2>/dev/null)+ui=$(shell git -C $(UI) rev-parse --short HEAD 2>/dev/null)+agentcmd=$(shell git -C deps/agent-command rev-parse --short HEAD 2>/dev/null)+documents=$(shell git -C modules/documents rev-parse --short HEAD 2>/dev/null)+native=$(shell git -C deps/agent-native rev-parse --short HEAD 2>/dev/null)+squad=$(shell git -C deps/agent-squad rev-parse --short HEAD 2>/dev/null)+intent=$(shell git -C deps/agent-intent rev-parse --short HEAD 2>/dev/null)
|
||||
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null)+$(COMBO)
|
||||
|
||||
.PHONY: help sync status build frontend svc svc-list svc-commits svc-history svc-update test-backend test-frontend test-ui test-core test-agentcmd dev pin clean setup precheck task-start task-sync task-close task-finish version
|
||||
.PHONY: help sync status build frontend svc svc-list svc-commits svc-history svc-update test-backend test-frontend test-ui test-core test-agentcmd test-pins test-libs dev pin clean setup precheck task-start task-sync task-close task-finish version
|
||||
|
||||
version:
|
||||
@echo "agent-system $(VERSION)"
|
||||
@@ -44,7 +44,7 @@ task-finish:
|
||||
help:
|
||||
@echo "make sync 物化全部 submodule(递归)"
|
||||
@echo "make build 构建单二进制 bin/agent-system(契约同步→前端构建→embed→静态链接)"
|
||||
@echo "make test 全量测试(core + backend + frontend)"
|
||||
@echo "make test 全量测试(boundaries + pins + libs + core + backend + frontend + ui + agent-command)"
|
||||
@echo "make svc 服务级操作:make svc ENV=<name> [ACTION=deploy|start|stop|restart|status|logs] [ARGS='--from dev@<sha> --tag ...']"
|
||||
@echo "make svc-list 服务总览:make svc-list [ARGS='--tag core'];数据库运维:scripts/svc.sh db create|dsn|backup|backups|restore|clone|copy|ls|set"
|
||||
@echo "make svc-commits 列出可部署提交:make svc-commits SRC=dev|release [N=20]"
|
||||
@@ -99,11 +99,21 @@ test-agentcmd:
|
||||
test-boundaries:
|
||||
bash scripts/lint-boundaries.sh
|
||||
|
||||
# 容器仓 deps/ gitlink 与 Dev 顶层指针一致。读索引中的 gitlink。
|
||||
test-pins:
|
||||
bash scripts/check-pins.sh
|
||||
|
||||
# 三个库在各自模块内测试。不用 go.work:工作区 MVS 会抬高 golang.org/x 版本。
|
||||
test-libs:
|
||||
cd deps/agent-intent && GOWORK=off go vet ./... && GOWORK=off go test -count=1 ./...
|
||||
cd deps/agent-native && GOWORK=off go vet ./... && GOWORK=off go test -count=1 ./...
|
||||
cd deps/agent-squad && GOWORK=off go vet ./... && GOWORK=off go test -count=1 ./...
|
||||
|
||||
plugin-new:
|
||||
@test -n "$(NAME)" || (echo "用法:make plugin-new NAME=<id>"; exit 2)
|
||||
bash scripts/plugin-new.sh "$(NAME)"
|
||||
|
||||
test: test-boundaries test-core test-backend test-frontend test-ui test-agentcmd
|
||||
test: test-boundaries test-pins test-libs test-core test-backend test-frontend test-ui test-agentcmd
|
||||
|
||||
# 运行演示(mock 模式):单二进制 + 示例插件 + 嵌入式存储,浏览器 http://127.0.0.1:8787
|
||||
# 环境服务管理(scripts/svc.sh):deploy = 停旧 → 构建 → 启动;dev/prod 相互隔离。
|
||||
@@ -139,9 +149,8 @@ pin:
|
||||
@for m in modules/core modules/backend modules/frontend modules/ui modules/documents deps/agent-native deps/agent-squad deps/agent-intent deps/error-code-system deps/logging-system deps/development-guidelines deps/agent-command; do \
|
||||
(git -C $$m fetch -q origin && git -C $$m checkout -q origin/main) || echo "skip $$m"; \
|
||||
done
|
||||
@cd $(BACKEND)/deps/agent-system-core && git fetch -q origin && git checkout -q origin/main || true
|
||||
@cd $(BACKEND)/deps/agent-command && git fetch -q origin && git checkout -q origin/main || true
|
||||
@echo "submodule 指针已推进;请 make test 后 git add .gitmodules modules deps && git commit"
|
||||
@scripts/check-pins.sh || echo "pin: check-pins 未通过,上面列出的容器需要重钉;pin 本身不失败"
|
||||
|
||||
clean:
|
||||
rm -rf $(BIN) $(FRONTEND)/dist $(FRONTEND)/node_modules $(UI)/node_modules data
|
||||
|
||||
+1
-1
@@ -2,5 +2,5 @@
|
||||
|
||||
- 用途:开发集成父仓(gitlink 权威);非分发单元。
|
||||
- 组合:modules/{core,backend,frontend,ui,documents} + deps/{development-guidelines,agent-native,agent-squad,agent-intent,agent-command,error-code-system,logging-system}。
|
||||
- 验证:make test(core+backend+frontend 全量);make build 产出 bin/agent-system。
|
||||
- 验证:`make test` = test-boundaries(公开边界,另含三库之间导入配对棘轮)+ test-pins + test-libs(agent-intent、agent-native、agent-squad 各自 `GOWORK=off` 的 vet 与 test)+ test-core + test-backend + test-frontend + test-ui + test-agentcmd。`make build` 在 backend 模块内编译,replace 指向该模块自己的 `deps/`;`scripts/check-pins.sh` 要求这些 gitlink 与 Dev 顶层指针相同。未加 go.work:工作区最小版本选择会把 `golang.org/x/crypto`、`exp`、`net`、`term`、`text` 选得比 backend 单独构建更新。Releases 仓的 `scripts/build-release.sh` 递归克隆本仓固定提交后运行 `make build`,因此跟随同一套指针。
|
||||
- 部署:非容器;Releases 仓从本仓固定提交导出版本。
|
||||
|
||||
Vendored
+1
-1
Submodule deps/agent-intent updated: 1dbbe8149c...7f7879b06b
Vendored
+1
-1
Submodule deps/agent-native updated: c6d867cde7...91c1556184
Vendored
+1
-1
Submodule deps/agent-squad updated: 590fd86f4c...e928ea3c0f
+1
-1
Submodule modules/backend updated: 46d5f7b668...ef0a1bef0f
@@ -0,0 +1,16 @@
|
||||
# 三个库之间的包导入现状。新增配对会使 scripts/lint-boundaries.sh 失败;
|
||||
# 已经消失的配对只告警,提示从本文件删除。每行:导入方包 被导入包。
|
||||
agent-native/adapters/intentgate agent-intent/intent
|
||||
agent-squad/cli agent-intent/intent
|
||||
agent-squad/cli agent-native/exec
|
||||
agent-squad/cli agent-native/runtime/llm
|
||||
agent-squad/platform agent-native/runtime
|
||||
agent-squad/platform agent-native/runtime/llm
|
||||
agent-squad/squad agent-native/adapters/native
|
||||
agent-squad/squad agent-native/exec
|
||||
agent-squad/squad agent-native/runtime/llm
|
||||
agent-squad/squad agent-native/runtime/mcp
|
||||
agent-squad/squad agent-native/runtime/subagent
|
||||
agent-squad/squad agent-native/runtime/tools
|
||||
agent-squad/squadintent agent-intent/intent
|
||||
agent-squad/squadintent agent-native/exec
|
||||
Executable
+69
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env bash
|
||||
# 组合指针一致:容器仓在 Dev 钉住的提交上,deps/ 里的每个 gitlink
|
||||
# 必须等于 Dev 顶层对应指针。development-guidelines 只告警。
|
||||
set -euo pipefail
|
||||
root=$(cd "$(dirname "$0")/.." && pwd)
|
||||
cd "$root"
|
||||
|
||||
fail=0
|
||||
|
||||
pin_of() {
|
||||
git rev-parse ":$1"
|
||||
}
|
||||
|
||||
check_link() {
|
||||
local container="$1" name="$2" sha="$3" expect_path="$4"
|
||||
local expect
|
||||
if ! expect=$(pin_of "$expect_path" 2>/dev/null); then
|
||||
echo "pin: $container deps/$name has no Dev pin at $expect_path" >&2
|
||||
fail=1
|
||||
return
|
||||
fi
|
||||
if [ "$sha" != "$expect" ]; then
|
||||
local sha_tree expect_tree
|
||||
if ! sha_tree=$(git -C "$expect_path" rev-parse "${sha}^{tree}" 2>/dev/null); then
|
||||
echo "pin: $container deps/$name ${sha:0:12} is missing locally; fetch $expect_path first" >&2
|
||||
fail=1
|
||||
return
|
||||
fi
|
||||
if ! expect_tree=$(git -C "$expect_path" rev-parse "${expect}^{tree}" 2>/dev/null); then
|
||||
echo "pin: Dev $expect_path ${expect:0:12} is missing locally; fetch $expect_path first" >&2
|
||||
fail=1
|
||||
return
|
||||
fi
|
||||
if [ "$sha_tree" = "$expect_tree" ]; then
|
||||
echo "ok $container $name (same tree)"
|
||||
return
|
||||
fi
|
||||
echo "pin: $container deps/$name is ${sha:0:12}, Dev $expect_path is ${expect:0:12}" >&2
|
||||
fail=1
|
||||
return
|
||||
fi
|
||||
echo "ok $container $name"
|
||||
}
|
||||
|
||||
containers=(modules/backend deps/agent-native deps/agent-squad deps/agent-intent)
|
||||
for container in "${containers[@]}"; do
|
||||
commit=$(pin_of "$container")
|
||||
while read -r mode _typ sha name; do
|
||||
[ "$mode" = "160000" ] || continue
|
||||
base=${name#deps/}
|
||||
if [ "$base" = "development-guidelines" ]; then
|
||||
dev=$(pin_of deps/development-guidelines)
|
||||
if [ "$sha" != "$dev" ]; then
|
||||
echo "warn: $container deps/development-guidelines is ${sha:0:12}, Dev is ${dev:0:12}" >&2
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
if [ "$base" = "agent-system-core" ]; then
|
||||
check_link "$container" "$base" "$sha" modules/core
|
||||
else
|
||||
check_link "$container" "$base" "$sha" "deps/$base"
|
||||
fi
|
||||
done < <(git -C "$container" ls-tree "$commit" deps/)
|
||||
done
|
||||
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
echo "pins ok"
|
||||
@@ -24,6 +24,49 @@ if [ -d "$sdk" ]; then
|
||||
fi
|
||||
fi
|
||||
check "$root/examples"
|
||||
|
||||
# 库间依赖棘轮:三个库的包导入兄弟库的配对,相对白名单只许减少、不许新增。
|
||||
allow="$root/policy/lib-deps-allowlist.txt"
|
||||
observed=$(mktemp)
|
||||
recorded=$(mktemp)
|
||||
trap 'rm -f "$observed" "$recorded"' EXIT
|
||||
siblings=(agent-intent agent-native agent-squad)
|
||||
for dir in deps/agent-intent deps/agent-native deps/agent-squad; do
|
||||
mod=$(awk '/^module /{print $2; exit}' "$root/$dir/go.mod")
|
||||
(
|
||||
cd "$root/scripts"
|
||||
go run lint-imports.go "$root/$dir"
|
||||
) | while read -r importer rest; do
|
||||
for imp in $rest; do
|
||||
for sib in "${siblings[@]}"; do
|
||||
case "$imp" in
|
||||
"$sib"|"$sib"/*) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
case "$importer" in
|
||||
"$mod"|"$mod"/*) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
if [ "$sib" != "$mod" ]; then
|
||||
echo "$importer $imp"
|
||||
fi
|
||||
done
|
||||
done
|
||||
done
|
||||
done | sort -u >"$observed"
|
||||
grep -v -e '^#' -e '^$' "$allow" | sort -u >"$recorded"
|
||||
new_pairs=$(comm -13 "$recorded" "$observed" || true)
|
||||
if [ -n "$new_pairs" ]; then
|
||||
echo "boundary: new sibling-library import pairs" >&2
|
||||
echo "$new_pairs" >&2
|
||||
fail=1
|
||||
fi
|
||||
stale_pairs=$(comm -23 "$recorded" "$observed" || true)
|
||||
if [ -n "$stale_pairs" ]; then
|
||||
echo "warn: sibling-library pairs no longer imported; delete from policy/lib-deps-allowlist.txt" >&2
|
||||
echo "$stale_pairs" >&2
|
||||
fi
|
||||
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
// 离线列出模块内非测试 Go 文件的导入。
|
||||
// 只使用标准库,跳过 _test.go 和带 go.mod 的子目录,避免 go list 去下载模块图。
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for _, root := range os.Args[1:] {
|
||||
mod := modulePath(filepath.Join(root, "go.mod"))
|
||||
if mod == "" {
|
||||
fmt.Fprintf(os.Stderr, "lint-imports: %s has no module path\n", root)
|
||||
os.Exit(1)
|
||||
}
|
||||
err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
|
||||
if err != nil || !d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
name := d.Name()
|
||||
if name == "vendor" || (name != "." && strings.HasPrefix(name, ".")) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if path != root {
|
||||
if _, statErr := os.Stat(filepath.Join(path, "go.mod")); statErr == nil {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
}
|
||||
return printImports(root, mod, path)
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "lint-imports: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func modulePath(goMod string) string {
|
||||
f, err := os.Open(goMod)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer f.Close()
|
||||
sc := bufio.NewScanner(f)
|
||||
for sc.Scan() {
|
||||
fields := strings.Fields(sc.Text())
|
||||
if len(fields) >= 2 && fields[0] == "module" {
|
||||
return fields[1]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func printImports(root, mod, dir string) error {
|
||||
rel, err := filepath.Rel(root, dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
importer := mod
|
||||
if rel != "." {
|
||||
importer = mod + "/" + filepath.ToSlash(rel)
|
||||
}
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fset := token.NewFileSet()
|
||||
seen := map[string]struct{}{}
|
||||
var imports []string
|
||||
for _, entry := range entries {
|
||||
name := entry.Name()
|
||||
if entry.IsDir() || !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
|
||||
continue
|
||||
}
|
||||
file, err := parser.ParseFile(fset, filepath.Join(dir, name), nil, parser.ImportsOnly)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, imp := range file.Imports {
|
||||
path := strings.Trim(imp.Path.Value, `"`)
|
||||
if _, ok := seen[path]; ok {
|
||||
continue
|
||||
}
|
||||
seen[path] = struct{}{}
|
||||
imports = append(imports, path)
|
||||
}
|
||||
}
|
||||
if len(imports) == 0 {
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("%s %s\n", importer, strings.Join(imports, " "))
|
||||
return nil
|
||||
}
|
||||
+48
-5
@@ -42,6 +42,23 @@ cmd_precheck() {
|
||||
fi
|
||||
done
|
||||
[ -n "$open_cards" ] && echo "[cards] 已合入未闭合任务卡:$(echo $open_cards)——make task-close 回填归档(主检出运行)"
|
||||
local done_open="" stale="" now ts ref
|
||||
for pc in .task/*.md; do
|
||||
[ -f "$pc" ] || continue
|
||||
case "$(card_status "$pc")" in
|
||||
已完成*) done_open="${done_open} ${pc##*/}" ;;
|
||||
esac
|
||||
done
|
||||
[ -n "$done_open" ] && echo "[cards] 已完成但未归档:$(echo $done_open)"
|
||||
now=$(date +%s)
|
||||
while read -r ref ts; do
|
||||
[ -n "$ref" ] || continue
|
||||
git merge-base --is-ancestor "$ref" "origin/${TARGET_BRANCH}" 2>/dev/null && continue
|
||||
if [ $((now - ts)) -gt 86400 ]; then
|
||||
stale="${stale} ${ref#origin/}"
|
||||
fi
|
||||
done < <(git for-each-ref --format='%(refname:short) %(committerdate:unix)' "refs/remotes/origin/feature/card-close-*")
|
||||
[ -n "$stale" ] && echo "[cards] 闭合分支超过 24 小时未合入:$(echo $stale)"
|
||||
echo "[required-reading] core/baseline.md, workflows/delivery.md §1$([ "$dirty" -gt 0 ] && echo ", standards/collaboration.md(树脏=他人或未收尾现场,不得写入)")"
|
||||
echo "[R0] $(echo "$rmain" | cut -c1-10)(完整:$rmain)"
|
||||
if [ "$dirty" -gt 0 ] || [ "${sub_drift:-0}" -gt 0 ]; then
|
||||
@@ -119,13 +136,27 @@ cmd_sync() {
|
||||
[ "$(git status --porcelain | grep -v '^.. \.zcode/' | wc -l)" -eq 0 ] || die "dirty tree — 先显式提交;不隐式 stash(collaboration.md:11)"
|
||||
git merge --no-edit "origin/${TARGET_BRANCH}"
|
||||
git merge-base --is-ancestor "origin/${TARGET_BRANCH}" HEAD || die "sync incomplete"
|
||||
local base head card
|
||||
local base head card branch slug pc
|
||||
base=$(git rev-parse "origin/${TARGET_BRANCH}"); head=$(git rev-parse HEAD)
|
||||
card=$(ls .task/*.md 2>/dev/null | head -1 || true)
|
||||
if [ -n "$card" ]; then
|
||||
branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
slug=$(echo "$branch" | tr '/' '-')
|
||||
card=".task/${slug}.md"
|
||||
if [ ! -f "$card" ]; then
|
||||
card=""
|
||||
for pc in .task/*.md; do
|
||||
[ -f "$pc" ] || continue
|
||||
if [ "$(card_of_branch "$pc")" = "$branch" ]; then
|
||||
card=$pc
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if [ -n "$card" ] && [ -f "$card" ]; then
|
||||
printf '| 同步前验收 | %s | %s | %s |\n' "$base" "$head" "$(date -u +%FT%TZ)" >> "$card"
|
||||
git add "$card"
|
||||
git commit -q -m "Record the sync checkpoint" || true
|
||||
else
|
||||
echo "[warn] 找不到分支 ${branch} 的任务卡,同步记录未写入" >&2
|
||||
fi
|
||||
echo "[synced] sync_base=$(echo "$base" | cut -c1-10) tested_head=$(echo "$head" | cut -c1-10) checked_at=$(date -u +%FT%TZ)"
|
||||
echo "[next] 跑正式验收(make test 等),证据写入任务卡"
|
||||
@@ -189,13 +220,18 @@ cmd_close() {
|
||||
for c in .task/*.md; do
|
||||
[ -f "$c" ] || continue
|
||||
b=$(card_of_branch "$c"); [ -n "$b" ] || continue
|
||||
st=$(card_status "$c"); case "$st" in 已完成*) continue ;; esac
|
||||
st=$(card_status "$c")
|
||||
done_unarchived=0
|
||||
case "$st" in 已完成*) done_unarchived=1 ;; esac
|
||||
if card_pending "${c##*/}"; then
|
||||
echo "[close] ${c##*/} 已有待合入的闭合分支,跳过(等其 PR 合入)"
|
||||
continue
|
||||
fi
|
||||
m=$(card_merge "$b") || m=""
|
||||
[ -n "$m" ] || continue
|
||||
if [ -z "$m" ]; then
|
||||
[ "$done_unarchived" = 1 ] || continue
|
||||
m="ARCHIVE"
|
||||
fi
|
||||
cards="$cards
|
||||
$c|$b|$m"
|
||||
done
|
||||
@@ -213,6 +249,13 @@ $c|$b|$m"
|
||||
local n=0 sha subject pr closed_list=""
|
||||
while IFS='|' read -r c b m; do
|
||||
[ -n "$c" ] || continue
|
||||
if [ "$m" = "ARCHIVE" ]; then
|
||||
mkdir -p .task/archive
|
||||
git mv "$c" ".task/archive/${c##*/}"
|
||||
closed_list="$closed_list ${c##*/}(already-complete)"
|
||||
n=$((n+1))
|
||||
continue
|
||||
fi
|
||||
sha="${m%%|*}"; subject="${m#*|}"
|
||||
pr=$(printf '%s' "$subject" | sed -n 's/.*(#\([0-9]\+\)) from.*/\1/p')
|
||||
[ -n "$pr" ] || pr=unknown
|
||||
|
||||
Reference in New Issue
Block a user