@elvis1513/auto-coding-skill 0.2.0 → 0.3.0

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.
package/README.md CHANGED
@@ -6,8 +6,8 @@ Engineering workflow skill for:
6
6
  - Codex CLI
7
7
 
8
8
  This branch is specialized for Go backend + frontend monorepo projects that build Docker images locally, validate with project `docker compose`, and rely on Jenkins to auto-build and update target environments after push.
9
- It supports both Claude and Codex. During development, it should prefer already available MCP servers, installed skills, plugins, and app connectors for design, research, documentation, verification, and external system updates.
10
- It should also prefer multi-agent execution whenever the work can be split into parallel subtasks safely.
9
+ It supports both Claude and Codex. During development, it prefers already available MCP servers, installed skills, plugins, and app connectors for design, research, documentation, verification, and external system updates.
10
+ It also prefers multi-agent execution whenever the work can be split into parallel subtasks safely.
11
11
 
12
12
  ## Install
13
13
 
@@ -71,6 +71,13 @@ This frontmatter is the only manual config source (commands + local Docker runti
71
71
  - `git push` is expected to trigger Jenkins automatically.
72
72
  - Task is not complete until Jenkins succeeds and the target environment health check passes.
73
73
 
74
+ 8. Branch rule during execution:
75
+
76
+ - `dev` is the long-lived integration branch.
77
+ - If there is no parallel work conflict, prefer `dev`-first.
78
+ - If the repo is in detached HEAD, worktree mode, or another task is already mutating `dev`, create a temporary task branch first.
79
+ - Temporary branches should stay task-scoped and rebase back to latest `dev` before final integration.
80
+
74
81
  ## AGENTS.md Constraint Example
75
82
 
76
83
  ```md
@@ -79,7 +86,7 @@ This frontmatter is the only manual config source (commands + local Docker runti
79
86
  - Before any code change, read and obey:
80
87
  1) docs/ENGINEERING.md
81
88
  2) docs/tasks/taskbook.md
82
- - Execute gates using `python3 scripts/autopipeline/ap.py`.
89
+ - Execute gates using `python3 docs/tools/autopipeline/ap.py`.
83
90
  - If required docs are missing, create/update docs first, then code.
84
91
  ```
85
92
 
@@ -139,30 +146,56 @@ This frontmatter is the only manual config source (commands + local Docker runti
139
146
  - Purpose:
140
147
  - Full regression matrix against the local Compose environment; must be 0 FAIL.
141
148
  - How to record:
142
- - Add/maintain rows by regression ID (R-xxx), area, steps/command, expected, status, evidence.
143
- - If any FAIL exists, gate fails.
149
+ - Add rows by regression ID (R-xxx), area, steps/command, expected, status, evidence.
150
+ - New or unexecuted rows must stay `TODO`.
151
+ - `PASS` is valid only after real execution with non-placeholder evidence.
152
+ - If any row is not `PASS`, or evidence is placeholder text, gate fails.
153
+
154
+ ## Branch Policy
155
+
156
+ - `dev` is the only long-lived integration branch.
157
+ - Temporary branches are preferred when parallel worktrees or concurrent tasks would otherwise collide on `dev`.
158
+ - Temporary branches should be small, task-scoped, and rebased frequently against latest `dev`.
159
+ - Final integration target remains `dev`; temporary branches are not release branches.
160
+
161
+ ## CI Trigger Strategy
162
+
163
+ - Prefer split Jenkins behavior:
164
+ - Branch or MR validation job for build/test/lint/typecheck and optional non-deploy runtime checks.
165
+ - `dev` integration/deploy job for actual deployment-triggering pushes.
166
+ - Avoid duplicate deploy triggers from both merge acceptance events and `dev` push events.
144
167
 
145
168
  ## Commands
146
169
 
147
170
  ```bash
148
171
  pip install pyyaml requests
149
- python3 scripts/autopipeline/ap.py run build
150
- python3 scripts/autopipeline/ap.py run test
151
- python3 scripts/autopipeline/ap.py run lint
152
- python3 scripts/autopipeline/ap.py run docker_build
153
- python3 scripts/autopipeline/ap.py runtime-up
154
- python3 scripts/autopipeline/ap.py wait-health
155
- python3 scripts/autopipeline/ap.py run smoke
156
- python3 scripts/autopipeline/ap.py run regression
157
- python3 scripts/autopipeline/ap.py runtime-down
158
- python3 scripts/autopipeline/ap.py verify-jenkins
159
- python3 scripts/autopipeline/ap.py wait-health --scope prod
160
- python3 scripts/autopipeline/ap.py verify-api-docs
161
- python3 scripts/autopipeline/ap.py check-matrix
162
- python3 scripts/autopipeline/ap.py gen-summary T0001-1
163
- python3 scripts/autopipeline/ap.py commit-push T0001-1 --msg "T0001-1: <summary>" --require-runtime-health --require-jenkins --require-matrix
172
+ python3 docs/tools/autopipeline/ap.py run build
173
+ python3 docs/tools/autopipeline/ap.py run test
174
+ python3 docs/tools/autopipeline/ap.py run lint
175
+ python3 docs/tools/autopipeline/ap.py run typecheck
176
+ python3 docs/tools/autopipeline/ap.py run docker_build
177
+ python3 docs/tools/autopipeline/ap.py runtime-up
178
+ python3 docs/tools/autopipeline/ap.py wait-health
179
+ python3 docs/tools/autopipeline/ap.py run smoke
180
+ python3 docs/tools/autopipeline/ap.py run regression
181
+ python3 docs/tools/autopipeline/ap.py runtime-down
182
+ python3 docs/tools/autopipeline/ap.py verify-jenkins
183
+ python3 docs/tools/autopipeline/ap.py verify-jenkins-build --git-ref HEAD
184
+ python3 docs/tools/autopipeline/ap.py wait-health --scope prod
185
+ python3 docs/tools/autopipeline/ap.py verify-api-docs
186
+ python3 docs/tools/autopipeline/ap.py check-matrix
187
+ python3 docs/tools/autopipeline/ap.py gen-summary T0001-1
188
+ python3 docs/tools/autopipeline/ap.py commit-push T0001-1 --msg "T0001-1: <summary>" --require-runtime-health --require-jenkins --require-matrix
164
189
  ```
165
190
 
191
+ ## Quality Gate Expectations
192
+
193
+ - Backend quality gate: `commands.test` must pass.
194
+ - Frontend quality gate: at minimum `commands.build`, `commands.lint`, and `commands.typecheck` must pass.
195
+ - Regression matrix rows must start as `TODO` until actually executed.
196
+ - `PASS` requires real evidence, not placeholders.
197
+ - Before final commit/push, clean temporary logs, screenshots, generated artifacts, and cache by-products. `.local/` may remain when it is the intended local runtime data directory.
198
+
166
199
  ## Publish (NPM)
167
200
 
168
201
  1. Sync assets and basic check:
@@ -75,35 +75,66 @@ This contains all manual fields:
75
75
 
76
76
  Do not duplicate config in other md/yaml files.
77
77
 
78
+ ## Branch policy
79
+
80
+ - `dev` remains the only long-lived integration branch.
81
+ - Default behavior stays `dev`-first when there is no parallel work conflict.
82
+ - If Claude or Codex is operating in a derived worktree, detached HEAD, or any parallel task context where another thread is already changing `dev`, prefer creating a temporary branch from the latest `dev` before editing.
83
+ - Name temporary branches after the task, preferably `codex/<task-id>-<slug>` such as `codex/t0005-domestic-payment-site`.
84
+ - Keep the temporary branch scoped to one task, complete design/implementation/verification there, then merge or rebase it back onto `dev` only after local gates pass.
85
+ - Do not treat temporary branches as release branches; the final integration target is still `dev`.
86
+ - In temporary-branch mode, work in small, closed-loop slices. Each slice should have a clear scope, synchronized docs, the relevant local validation, and a commit that can stand on its own.
87
+ - Rebase temporary branches frequently against the latest `dev` to keep merge surfaces small.
88
+
89
+ ## CI trigger strategy
90
+
91
+ - Prefer a split Jenkins model when parallel worktrees are active:
92
+ - MR or branch validation job: build/test/lint/typecheck and optional non-deploy runtime checks on temporary branches or merge requests.
93
+ - `dev` integration/deploy job: trigger only from pushes that land on `dev`.
94
+ - Do not rely on merge-request acceptance events to drive production deployment when a `dev` push event already exists; that commonly creates duplicate builds around merge time.
95
+
78
96
  ## Execution order
79
97
 
80
- 1) `docs/ENGINEERING.md`
81
- 2) `docs/tasks/taskbook.md`
82
- 3) `docs/design/**`
83
- 4) implementation
84
- 5) local build/test/lint gates
85
- 6) start and validate local Docker Compose runtime
86
- 7) update API docs + regression matrix + bug list + summary
87
- 8) verify Jenkins config / Jenkinsfile readiness
88
- 9) commit/push to trigger Jenkins
89
- 10) verify Jenkins pipeline + target environment health
98
+ 1) choose branch mode (`dev` directly, or temporary branch if parallel worktree rules apply)
99
+ 2) `docs/ENGINEERING.md`
100
+ 3) `docs/tasks/taskbook.md`
101
+ 4) `docs/design/**`
102
+ 5) implementation
103
+ 6) local build/test/lint gates
104
+ 7) start and validate local Docker Compose runtime
105
+ 8) update API docs + regression matrix + bug list + summary
106
+ 9) verify Jenkins config / Jenkinsfile readiness
107
+ 10) if temporary-branch mode is used, close one small slice at a time with reviewable commits and rebase regularly onto `dev`
108
+ 11) merge/rebase temporary branch back to latest `dev` when temporary-branch mode was used
109
+ 12) commit/push to trigger Jenkins
110
+ 13) verify Jenkins pipeline + target environment health, preferably with `verify-jenkins-build --git-ref HEAD` (strict deploy check by default; use `--allow-no-deploy` only for docs-only sync verification)
90
111
 
91
112
  ## Commands
92
113
 
93
114
  ```bash
94
- python3 scripts/autopipeline/ap.py run build
95
- python3 scripts/autopipeline/ap.py run test
96
- python3 scripts/autopipeline/ap.py run lint
97
- python3 scripts/autopipeline/ap.py run docker_build
98
- python3 scripts/autopipeline/ap.py runtime-up
99
- python3 scripts/autopipeline/ap.py wait-health
100
- python3 scripts/autopipeline/ap.py run smoke
101
- python3 scripts/autopipeline/ap.py run regression
102
- python3 scripts/autopipeline/ap.py runtime-down
103
- python3 scripts/autopipeline/ap.py verify-jenkins
104
- python3 scripts/autopipeline/ap.py wait-health --scope prod
105
- python3 scripts/autopipeline/ap.py verify-api-docs
106
- python3 scripts/autopipeline/ap.py check-matrix
107
- python3 scripts/autopipeline/ap.py gen-summary T0001-1
108
- python3 scripts/autopipeline/ap.py commit-push T0001-1 --msg "T0001-1: <summary>" --require-runtime-health --require-jenkins --require-matrix
115
+ python3 docs/tools/autopipeline/ap.py run build
116
+ python3 docs/tools/autopipeline/ap.py run test
117
+ python3 docs/tools/autopipeline/ap.py run lint
118
+ python3 docs/tools/autopipeline/ap.py run typecheck
119
+ python3 docs/tools/autopipeline/ap.py run docker_build
120
+ python3 docs/tools/autopipeline/ap.py runtime-up
121
+ python3 docs/tools/autopipeline/ap.py wait-health
122
+ python3 docs/tools/autopipeline/ap.py run smoke
123
+ python3 docs/tools/autopipeline/ap.py run regression
124
+ python3 docs/tools/autopipeline/ap.py runtime-down
125
+ python3 docs/tools/autopipeline/ap.py verify-jenkins
126
+ python3 docs/tools/autopipeline/ap.py verify-jenkins-build --git-ref HEAD
127
+ python3 docs/tools/autopipeline/ap.py wait-health --scope prod
128
+ python3 docs/tools/autopipeline/ap.py verify-api-docs
129
+ python3 docs/tools/autopipeline/ap.py check-matrix
130
+ python3 docs/tools/autopipeline/ap.py gen-summary T0001-1
131
+ python3 docs/tools/autopipeline/ap.py commit-push T0001-1 --msg "T0001-1: <summary>" --require-runtime-health --require-jenkins --require-matrix
109
132
  ```
133
+
134
+ ## Quality gate expectations
135
+
136
+ - Gate-4: backend must pass `commands.test`; frontend must at least pass `commands.build`, `commands.lint`, and `commands.typecheck`. Frontend automated tests are added incrementally when the repo gains them.
137
+ - Gate-9: `docs/testing/regression-matrix.md` rows must start as `TODO` until they are actually executed.
138
+ - A matrix row can be marked `PASS` only after real execution, and `Evidence` must contain non-placeholder logs, screenshots, or report paths.
139
+ - `python3 docs/tools/autopipeline/ap.py check-matrix` should be treated as a hard gate; placeholder evidence is equivalent to incomplete regression.
140
+ - Before the final commit/push, clean temporary files, logs, screenshots, generated verification artifacts, cache directories, and similar by-products created during the task. The only persistent local runtime data that may remain is `.local/`.
@@ -42,6 +42,10 @@ jenkins:
42
42
  deploy_timeout_sec: 1800
43
43
  prod_health_base_url: ""
44
44
  prod_health_path: ""
45
+ api_user: ""
46
+ api_token: ""
47
+ api_user_env: "JENKINS_USER"
48
+ api_token_env: "JENKINS_TOKEN"
45
49
 
46
50
  docs:
47
51
  taskbook: "docs/tasks/taskbook.md"
@@ -64,6 +68,9 @@ docs:
64
68
 
65
69
  规则:任一步骤失败或缺产物,禁止进入下一步;本地 compose 验证未通过禁止 commit;Jenkins 未成功或生产健康检查未通过,任务不视为完成。
66
70
 
71
+ 补充规则:
72
+ - 每次任务闭环后,必须清理临时文件、临时目录、日志、截图、回归中间产物、构建缓存等非必要产物;仅 `.local/` 下的本地运行数据允许保留。
73
+
67
74
  ---
68
75
 
69
76
  ## 0. 配置填写(必须)
@@ -124,15 +131,15 @@ docs:
124
131
  Gate-1 读任务:只从 taskbook 取范围与验收;缺信息先补 taskbook
125
132
  Gate-2 写DD:无DD禁止写代码;DD必须含 时序图/ER图/接口时序(Mermaid)
126
133
  Gate-3 实现:严格按DD;接口变更必须同步 API Markdown
127
- Gate-4 本地CI:必须通过(commands.build / commands.test);Go 后端与前端都必须覆盖
134
+ Gate-4 本地CI:后端必须通过 `commands.test`;前端至少通过 `commands.build`、`commands.lint`、`commands.typecheck`;前端自动化测试能力逐步补齐
128
135
  Gate-5 静态分析+Review:静态分析通过;docs/reviews/ 生成记录
129
136
  Gate-6 文档:更新 api.md + 追加 api-change-log.md
130
137
  Gate-7 本地运行:必须用项目 Compose 启动本地 Docker 环境;失败先修复再继续
131
138
  Gate-8 健康检查:本地容器启动后必须健康检查通过
132
- Gate-9 全量回归:按 API Markdown 对本地 Compose 环境全量回归;回归矩阵全量 PASS(0 fail);发现问题必须写 bug-list 并新增自动化回归用例
139
+ Gate-9 全量回归:按 API Markdown 对本地 Compose 环境全量回归;回归矩阵仅可在真实执行后标记 PASS,且必须附证据;发现问题必须写 bug-list 并新增自动化回归用例
133
140
  Gate-10 Jenkins 准备:Jenkinsfile、Job 配置、镜像仓库策略必须可用
134
141
  Gate-11 任务总结:必须生成 docs/tasks/summaries/<TASK_ID>.md
135
- Gate-12 提交触发:本地门禁全过后才允许 commit+push
142
+ Gate-12 提交触发:本地门禁全过且临时产物已清理后,才允许 commit+push
136
143
  Gate-13 流水线验证:push 后必须确认 Jenkins 自动构建、镜像发布、目标环境更新成功
137
144
  Gate-14 完成:生产健康检查通过并补齐部署记录后,任务才完成
138
145
 
@@ -140,4 +147,8 @@ Gate-14 完成:生产健康检查通过并补齐部署记录后,任务才完
140
147
 
141
148
  ## 3. Repo 工具入口
142
149
 
143
- 统一用 `python3 scripts/autopipeline/ap.py <command>` 执行。
150
+ 统一用 `python3 docs/tools/autopipeline/ap.py <command>` 执行。
151
+
152
+ 补充:
153
+ - `commands.smoke` / `commands.regression` 可以封装 repo 脚本,但必须真正在本地运行目标系统。
154
+ - `docs/testing/regression-matrix.md` 中的 `PASS` 只在真实执行并填入证据后允许保留;占位符证据会被视为未完成。
@@ -13,12 +13,12 @@
13
13
  ## 2. Endpoint Index(目录)
14
14
  | Method | Path | Summary | Auth | Request | Response |
15
15
  |---|---|---|---|---|---|
16
- | GET | /health | Health check | No | - | 200 OK |
16
+ | <METHOD> | <PATH> | <Summary> | <Yes/No> | <Request shape> | <Response shape> |
17
17
 
18
18
  ## 3. Endpoints
19
19
 
20
- ### 3.1 GET /health
21
- **Summary**: Health check
20
+ ### 3.1 <METHOD> <PATH>
21
+ **Summary**: <Summary>
22
22
 
23
23
  **Request**
24
24
  - Headers: -
@@ -26,10 +26,10 @@
26
26
  - Body: -
27
27
 
28
28
  **Response**
29
- - 200: OK
29
+ - <Status>: <Meaning>
30
30
  - Example:
31
31
  ```json
32
- {"status":"ok"}
32
+ {}
33
33
  ```
34
34
 
35
35
  ## 4. Changelog
@@ -7,7 +7,7 @@
7
7
  - Resolved/Deferred(deferred 必须给出后续任务):
8
8
 
9
9
  ## 2. 代码质量
10
- ## 3. 本地构建与测试质量(Go 后端 + 前端)
10
+ ## 3. 本地构建与测试质量(后端 test + 前端 build/lint/typecheck)
11
11
  ## 4. 本地 Compose 验证(health / smoke / regression)
12
12
  ## 5. 接口契约(API Markdown + change-log)
13
13
  ## 6. Jenkins 准备度(Jenkinsfile / job config / image strategy)
@@ -29,12 +29,14 @@
29
29
 
30
30
  ## 5. 质量门禁证据(必须可追溯)
31
31
  - 项目配置:`docs/ENGINEERING.md`(frontmatter)
32
- - 本地CI:`ci-local`
33
- - 静态分析:`static`
32
+ - 后端测试:`commands.test`
33
+ - 前端构建:`commands.build`
34
+ - 静态分析:`commands.lint`
35
+ - 前端类型检查:`commands.typecheck`
34
36
  - Review 文档:`docs/reviews/<TASK_ID>-<timestamp>.md`
35
37
  - API 文档:`docs/interfaces/api.md`
36
38
  - Jenkins 配置检查:`Jenkinsfile` + `jenkins.*`
37
- - 回归矩阵:`docs/testing/regression-matrix.md`(全量 PASS,0 fail
39
+ - 回归矩阵:`docs/testing/regression-matrix.md`(全量 PASS,0 fail,且每项必须有真实证据)
38
40
 
39
41
  ## 6. Bug 清单与回归用例
40
42
  - 新增/确认的 Bug(写入 `docs/bugs/bug-list.md`):
@@ -26,7 +26,7 @@
26
26
  - 本地CI:粘贴摘要或给出文件路径
27
27
  - 本地 Compose 验证:命令输出或 Review 文档摘要
28
28
  - Jenkins 部署记录:`docs/deployment/deploy-records/T0001-YYYYMMDD.md`
29
- - 回归矩阵:`docs/testing/regression-matrix.md`(全量PASS
29
+ - 回归矩阵:`docs/testing/regression-matrix.md`(全量PASS,且每项必须有真实证据)
30
30
  - Bug清单(如有):`docs/bugs/bug-list.md`
31
31
  - 任务总结(强制):`docs/tasks/summaries/T0001.md`
32
32
 
@@ -1,5 +1,11 @@
1
1
  # Regression Matrix(本地 Compose 环境回归矩阵:必须全量 PASS,0 fail)
2
2
 
3
- | ID | Area | Endpoint/Feature | Test Type | Steps / Command | Expected | Status(PASS/FAIL) | Evidence |
3
+ > 1. 仅记录当前真实实现,不要预填伪接口或目标态接口。
4
+ > 2. `Status` 允许值:`TODO` / `PASS` / `FAIL`。
5
+ > 3. 新增或未执行项默认填写 `TODO`,不得预填 `PASS`。
6
+ > 4. `PASS` 只允许在真实执行后填写,且 `Evidence` 不得保留占位符。
7
+ > 5. `python3 docs/tools/autopipeline/ap.py check-matrix` 会把非 `PASS` 行和占位符证据视为未完成。
8
+
9
+ | ID | Area | Endpoint/Feature | Test Type | Steps / Command | Expected | Status(TODO/PASS/FAIL) | Evidence |
4
10
  |---|---|---|---|---|---|---|---|
5
- | R-001 | API | GET /health | smoke | commands.smoke | local compose 200 OK | PASS | <paste log path> |
11
+ | R-001 | API | <Endpoint or feature> | <smoke/regression/manual> | <command or manual steps> | <expected result> | TODO | <fill-with-log-path-screenshot-or-report> |
@@ -5,8 +5,13 @@
5
5
  from __future__ import annotations
6
6
 
7
7
  import argparse
8
+ import base64
8
9
  import datetime as _dt
10
+ import json
11
+ import os
9
12
  import time
13
+ import urllib.parse
14
+ import urllib.request
10
15
  from pathlib import Path
11
16
  from typing import Optional, List
12
17
 
@@ -49,6 +54,55 @@ def _run_configured_command(repo: Path, cfg: dict, name: str) -> bool:
49
54
  return True
50
55
 
51
56
 
57
+ def _jenkins_basic_auth_headers(cfg: dict) -> dict:
58
+ jenkins_cfg = (cfg.get("jenkins") or {})
59
+ direct_user = str(jenkins_cfg.get("api_user") or "").strip()
60
+ direct_token = str(jenkins_cfg.get("api_token") or "").strip()
61
+ user_env = str(jenkins_cfg.get("api_user_env") or "JENKINS_USER").strip() or "JENKINS_USER"
62
+ token_env = str(jenkins_cfg.get("api_token_env") or "JENKINS_TOKEN").strip() or "JENKINS_TOKEN"
63
+ user = direct_user or os.getenv(user_env) or os.getenv("JENKINS_USER")
64
+ token = direct_token or os.getenv(token_env) or os.getenv("JENKINS_TOKEN") or os.getenv("JENKINS_PASSWORD")
65
+ if not user or not token:
66
+ raise APError(
67
+ f"Missing Jenkins API credentials. Fill jenkins.api_user / jenkins.api_token in docs/ENGINEERING.md, "
68
+ f"or set env vars {user_env} and {token_env}."
69
+ )
70
+ raw = f"{user}:{token}".encode("utf-8")
71
+ auth = base64.b64encode(raw).decode("ascii")
72
+ return {"Authorization": f"Basic {auth}"}
73
+
74
+
75
+ def _jenkins_api_get_json(url: str, cfg: dict, timeout_s: int = 15) -> dict:
76
+ headers = {"Accept": "application/json"}
77
+ headers.update(_jenkins_basic_auth_headers(cfg))
78
+ req = urllib.request.Request(url, headers=headers, method="GET")
79
+ try:
80
+ with urllib.request.urlopen(req, timeout=timeout_s) as resp:
81
+ data = resp.read().decode("utf-8")
82
+ except Exception as exc:
83
+ raise APError(f"Jenkins API request failed: {url}\n{exc}") from exc
84
+ try:
85
+ return json.loads(data)
86
+ except json.JSONDecodeError as exc:
87
+ raise APError(f"Jenkins API returned non-JSON response: {url}\n{exc}") from exc
88
+
89
+
90
+ def _resolve_git_short_sha(repo: Path, ref: str) -> str:
91
+ result = run(["git", "rev-parse", "--short=12", ref], cwd=repo, check=False)
92
+ value = result.stdout.strip()
93
+ if value:
94
+ return value
95
+ return ref.strip()
96
+
97
+
98
+ def _jenkins_builds_api_url(job_url: str, max_builds: int) -> str:
99
+ base = str(job_url or "").strip().rstrip("/")
100
+ if not base:
101
+ raise APError("Missing jenkins.job_url in docs/ENGINEERING.md")
102
+ tree = f"builds[number,result,building,description,url]{{0,{max_builds}}}"
103
+ return f"{base}/api/json?tree={urllib.parse.quote(tree, safe='=,')}"
104
+
105
+
52
106
  def cmd_install(args: argparse.Namespace) -> None:
53
107
  repo = Path(args.repo).resolve()
54
108
  templates = _skill_root() / "data" / "templates"
@@ -59,10 +113,11 @@ def cmd_install(args: argparse.Namespace) -> None:
59
113
  if args.bridges:
60
114
  copy_tree(templates / "bridges", repo)
61
115
 
62
- scripts_dir = repo / "scripts" / "autopipeline"
63
- scripts_dir.mkdir(parents=True, exist_ok=True)
64
- copy_tree(Path(__file__).resolve(), scripts_dir / "ap.py")
65
- copy_tree(Path(__file__).resolve().parent / "core.py", scripts_dir / "core.py")
116
+ tools_dir = repo / "docs" / "tools" / "autopipeline"
117
+ tools_dir.mkdir(parents=True, exist_ok=True)
118
+ copy_tree(Path(__file__).resolve(), tools_dir / "ap.py")
119
+ copy_tree(Path(__file__).resolve().parent / "core.py", tools_dir / "core.py")
120
+ copy_tree(Path(__file__).resolve().parent / "http_checks.py", tools_dir / "http_checks.py")
66
121
 
67
122
  gi = repo / ".gitignore"
68
123
  secret_line = "docs/ENGINEERING.md"
@@ -140,12 +195,14 @@ def cmd_gen_summary(args: argparse.Namespace) -> None:
140
195
  - 变更记录位置:`{api_change_log}`
141
196
 
142
197
  ## 5. 质量门禁证据(必须可追溯)
143
- - 本地CI:TODO
144
- - 静态分析:TODO
198
+ - 后端测试:`commands.test` — TODO
199
+ - 前端构建:`commands.build` — TODO
200
+ - 静态分析:`commands.lint` — TODO
201
+ - 前端类型检查:`commands.typecheck` — TODO
145
202
  - Review 文档:TODO
146
203
  - DD 文档:TODO
147
204
  - Jenkins 准备:TODO
148
- - 回归矩阵:`{regression_matrix}`(全量 PASS,0 fail
205
+ - 回归矩阵:`{regression_matrix}`(全量 PASS,0 fail,且每项必须有真实证据)
149
206
 
150
207
  ## 6. 本地运行与 Jenkins 部署记录
151
208
  - Local compose:TODO
@@ -166,6 +223,28 @@ def cmd_check_matrix(args: argparse.Namespace) -> None:
166
223
 
167
224
  rows = 0
168
225
  fail = []
226
+
227
+ def evidence_missing(value: str) -> bool:
228
+ stripped = value.strip()
229
+ lower = stripped.lower()
230
+ if not stripped:
231
+ return True
232
+ if stripped.startswith("<") and stripped.endswith(">"):
233
+ return True
234
+ placeholder_tokens = [
235
+ "todo",
236
+ "tbd",
237
+ "pending",
238
+ "replace-with",
239
+ "paste log path",
240
+ "paste evidence",
241
+ "fill-with",
242
+ "待补",
243
+ "待填",
244
+ "占位",
245
+ ]
246
+ return any(token in lower for token in placeholder_tokens)
247
+
169
248
  for line in matrix.read_text(encoding="utf-8").splitlines():
170
249
  s = line.strip()
171
250
  if not s.startswith("|"):
@@ -182,6 +261,10 @@ def cmd_check_matrix(args: argparse.Namespace) -> None:
182
261
  rows += 1
183
262
  if status != "PASS":
184
263
  fail.append((rid, status or "(empty)"))
264
+ continue
265
+ evidence = cols[7] if len(cols) > 7 else ""
266
+ if evidence_missing(evidence):
267
+ fail.append((rid, "PASS-without-evidence"))
185
268
 
186
269
  if rows == 0:
187
270
  raise APError(f"No regression rows found in matrix: {matrix}")
@@ -302,6 +385,67 @@ def cmd_verify_jenkins(args: argparse.Namespace) -> None:
302
385
  print(f"[verify-jenkins] OK: {jenkinsfile}")
303
386
 
304
387
 
388
+ def cmd_verify_jenkins_build(args: argparse.Namespace) -> None:
389
+ repo = Path(args.repo).resolve()
390
+ cfg = _load_cfg(repo)
391
+ jenkins_cfg = (cfg.get("jenkins") or {})
392
+ job_url = str(jenkins_cfg.get("job_url") or "").strip()
393
+ if not job_url:
394
+ raise APError("Missing jenkins.job_url in docs/ENGINEERING.md")
395
+
396
+ git_ref = str(args.git_ref or "HEAD").strip()
397
+ git_short_sha = _resolve_git_short_sha(repo, git_ref)
398
+ max_builds = int(args.max_builds or 20)
399
+ timeout_s = int(args.timeout_sec or 300)
400
+ poll_s = int(args.poll_sec or 5)
401
+
402
+ deadline = time.time() + timeout_s
403
+ matched = None
404
+ api_url = _jenkins_builds_api_url(job_url, max_builds)
405
+
406
+ while time.time() < deadline:
407
+ payload = _jenkins_api_get_json(api_url, cfg)
408
+ builds = payload.get("builds") or []
409
+ matched = next((b for b in builds if git_short_sha in str(b.get("description") or "")), None)
410
+ if matched and not matched.get("building"):
411
+ break
412
+ time.sleep(poll_s)
413
+
414
+ if not matched:
415
+ raise APError(
416
+ f"No Jenkins build found for commit {git_short_sha} under {job_url}. "
417
+ f"Checked latest {max_builds} builds for up to {timeout_s}s."
418
+ )
419
+
420
+ if matched.get("building"):
421
+ raise APError(
422
+ f"Jenkins build for commit {git_short_sha} is still running: "
423
+ f"#{matched.get('number')} {matched.get('url')}"
424
+ )
425
+
426
+ result = str(matched.get("result") or "").strip().upper()
427
+ description = str(matched.get("description") or "").strip()
428
+ if result != "SUCCESS":
429
+ raise APError(
430
+ f"Jenkins build for commit {git_short_sha} did not succeed: "
431
+ f"#{matched.get('number')} result={result or '(empty)'} {matched.get('url')}"
432
+ )
433
+ if not args.allow_no_deploy and description.startswith("no-deploy:"):
434
+ raise APError(
435
+ f"Jenkins build for commit {git_short_sha} succeeded but did not deploy: "
436
+ f"#{matched.get('number')} {description}"
437
+ )
438
+
439
+ print(
440
+ "[verify-jenkins-build] OK: "
441
+ f"commit={git_short_sha} "
442
+ f"build=#{matched.get('number')} "
443
+ f"result={result} "
444
+ f"description={description} "
445
+ f"url={matched.get('url')}"
446
+ )
447
+
448
+
305
449
  def cmd_verify_api_docs(args: argparse.Namespace) -> None:
306
450
  """Ensure API markdown doc and change-log exist."""
307
451
  repo = Path(args.repo).resolve()
@@ -329,7 +473,7 @@ def cmd_commit_push(args: argparse.Namespace) -> None:
329
473
  if not summary.exists():
330
474
  raise APError(
331
475
  f"Task summary missing: {summary}\n"
332
- f"Generate: python3 scripts/autopipeline/ap.py gen-summary {task_id}"
476
+ f"Generate: python3 docs/tools/autopipeline/ap.py gen-summary {task_id}"
333
477
  )
334
478
 
335
479
  if args.require_runtime_health:
@@ -385,6 +529,14 @@ def main(argv: Optional[List[str]] = None) -> int:
385
529
  s = sp.add_parser("verify-jenkins")
386
530
  s.set_defaults(func=cmd_verify_jenkins)
387
531
 
532
+ s = sp.add_parser("verify-jenkins-build")
533
+ s.add_argument("--git-ref", default="HEAD")
534
+ s.add_argument("--max-builds", type=int, default=20)
535
+ s.add_argument("--timeout-sec", type=int, default=300)
536
+ s.add_argument("--poll-sec", type=int, default=5)
537
+ s.add_argument("--allow-no-deploy", action="store_true")
538
+ s.set_defaults(func=cmd_verify_jenkins_build)
539
+
388
540
  s = sp.add_parser("verify-api-docs")
389
541
  s.set_defaults(func=cmd_verify_api_docs)
390
542
 
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import json
6
+ import urllib.error
7
+ import urllib.request
8
+
9
+
10
+ class CheckError(RuntimeError):
11
+ pass
12
+
13
+
14
+ def fetch(method: str, url: str, headers: dict[str, str] | None = None) -> tuple[int, str]:
15
+ req = urllib.request.Request(url, headers=headers or {}, method=method)
16
+ try:
17
+ with urllib.request.urlopen(req, timeout=10) as response:
18
+ return response.status, response.read().decode("utf-8", errors="replace")
19
+ except urllib.error.HTTPError as exc:
20
+ return exc.code, exc.read().decode("utf-8", errors="replace")
21
+
22
+
23
+ def cmd_status(args: argparse.Namespace) -> None:
24
+ status, body = fetch("GET", args.url)
25
+ if status != args.expect:
26
+ raise CheckError(f"GET {args.url} expected {args.expect}, got {status}: {body[:400]}")
27
+ print(f"[status] OK: {args.url} -> {status}")
28
+
29
+
30
+ def cmd_text_contains(args: argparse.Namespace) -> None:
31
+ status, body = fetch("GET", args.url)
32
+ if status != args.expect:
33
+ raise CheckError(f"GET {args.url} expected {args.expect}, got {status}: {body[:400]}")
34
+ if args.contains not in body:
35
+ raise CheckError(f"Response from {args.url} does not contain expected text: {args.contains}")
36
+ print(f"[text-contains] OK: {args.url}")
37
+
38
+
39
+ def cmd_json_field(args: argparse.Namespace) -> None:
40
+ status, body = fetch("GET", args.url, headers={"Accept": "application/json"})
41
+ if status != args.expect:
42
+ raise CheckError(f"GET {args.url} expected {args.expect}, got {status}: {body[:400]}")
43
+ try:
44
+ payload = json.loads(body)
45
+ except json.JSONDecodeError as exc:
46
+ raise CheckError(f"Response from {args.url} is not valid JSON: {exc}") from exc
47
+
48
+ current = payload
49
+ for part in args.path.split("."):
50
+ if isinstance(current, dict) and part in current:
51
+ current = current[part]
52
+ continue
53
+ raise CheckError(f"JSON path not found: {args.path}")
54
+
55
+ if str(current) != args.equals:
56
+ raise CheckError(f"JSON field {args.path} expected {args.equals}, got {current}")
57
+ print(f"[json-field] OK: {args.url} {args.path}={current}")
58
+
59
+
60
+ def main() -> int:
61
+ parser = argparse.ArgumentParser(prog="http_checks")
62
+ sub = parser.add_subparsers(dest="cmd", required=True)
63
+
64
+ s = sub.add_parser("status")
65
+ s.add_argument("url")
66
+ s.add_argument("--expect", type=int, default=200)
67
+ s.set_defaults(func=cmd_status)
68
+
69
+ s = sub.add_parser("text-contains")
70
+ s.add_argument("url")
71
+ s.add_argument("--contains", required=True)
72
+ s.add_argument("--expect", type=int, default=200)
73
+ s.set_defaults(func=cmd_text_contains)
74
+
75
+ s = sub.add_parser("json-field")
76
+ s.add_argument("url")
77
+ s.add_argument("--path", required=True)
78
+ s.add_argument("--equals", required=True)
79
+ s.add_argument("--expect", type=int, default=200)
80
+ s.set_defaults(func=cmd_json_field)
81
+
82
+ try:
83
+ args = parser.parse_args()
84
+ args.func(args)
85
+ return 0
86
+ except CheckError as exc:
87
+ print(f"[ERROR] {exc}")
88
+ return 2
89
+
90
+
91
+ if __name__ == "__main__":
92
+ raise SystemExit(main())
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elvis1513/auto-coding-skill",
3
- "version": "0.2.0",
4
- "description": "CLI installer for auto-coding-skill (Claude Code + Codex CLI).",
3
+ "version": "0.3.0",
4
+ "description": "CLI installer for auto-coding-skill (Claude Code + Codex CLI) with Go fullstack + Jenkins workflow support.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "autocoding": "cli/src/index.js"
@@ -29,6 +29,9 @@
29
29
  "engineering",
30
30
  "workflow",
31
31
  "ci",
32
+ "jenkins",
33
+ "go",
34
+ "monorepo",
32
35
  "docker",
33
36
  "local-testing"
34
37
  ],