@kairyou/agent-tools 0.14.0 → 0.16.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 +3 -3
- package/README.zh-CN.md +3 -3
- package/config.default.jsonc +2 -2
- package/dist/log/hook.mjs +19 -5
- package/docs/en/extras.md +4 -4
- package/docs/en/repository-structure.md +2 -2
- package/docs/zh-CN/extras.md +4 -4
- package/docs/zh-CN/repository-structure.md +2 -2
- package/integrations/log/hook.mjs +33 -7
- package/package.json +1 -1
- package/skills/integrations/at-zentao/SKILL.md +145 -109
- package/skills/integrations/at-zentao/scripts/zentao-cli.mjs +607 -0
- package/skills/workflow/at-daily-log/SKILL.md +6 -4
- package/skills/workflow/at-review/SKILL.md +4 -2
- package/skills/workflow/at-review/references/review-targets.md +70 -0
- package/skills/workflow/at-self-eval/SKILL.md +6 -2
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ Usage:
|
|
|
32
32
|
|
|
33
33
|
### at-review
|
|
34
34
|
|
|
35
|
-
Review changes for correctness bugs, regressions, convention violations, and high-value cleanup findings.
|
|
35
|
+
Review local changes or a hosted PR/MR for correctness bugs, regressions, convention violations, and high-value cleanup findings.
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
npx -y skills@latest add kairyou/agent-tools --skill at-review -g -y
|
|
@@ -40,7 +40,7 @@ npx -y skills@latest add kairyou/agent-tools --skill at-review -g -y
|
|
|
40
40
|
|
|
41
41
|
Usage:
|
|
42
42
|
|
|
43
|
-
- `/at-review [--fix] [<pr|branch|path>]` — reports review findings; `--fix`
|
|
43
|
+
- `/at-review [--fix] [<pr-or-mr-url|branch|path>]` — reports review findings; private hosted targets require locally available read access, and `--fix` applies fixes only to a matching working tree
|
|
44
44
|
|
|
45
45
|
### at-simplify
|
|
46
46
|
|
|
@@ -69,7 +69,7 @@ Usage:
|
|
|
69
69
|
- `/at-zentao bug <id>` — work a specific bug
|
|
70
70
|
- `/at-zentao task <id>` — work a specific task
|
|
71
71
|
|
|
72
|
-
Config: `~/.agent-tools/config.jsonc` → `"zentao": { "url", "account", "password" }`.
|
|
72
|
+
Config: `~/.agent-tools/config.jsonc` → `"zentao": { "url", "account", "password" }`. The password can be entered directly or referenced with `"password": { "env": "ZENTAO_PASSWORD" }`; never paste credentials or tokens into chat.
|
|
73
73
|
|
|
74
74
|
## Integrations
|
|
75
75
|
|
package/README.zh-CN.md
CHANGED
|
@@ -32,7 +32,7 @@ npx -y skills@latest add kairyou/agent-tools --skill at-commit -g -y
|
|
|
32
32
|
|
|
33
33
|
### at-review
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
审查本地改动或托管的 PR/MR 中的正确性 bug, 回归风险, 约定违规和高价值清理项.
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
npx -y skills@latest add kairyou/agent-tools --skill at-review -g -y
|
|
@@ -40,7 +40,7 @@ npx -y skills@latest add kairyou/agent-tools --skill at-review -g -y
|
|
|
40
40
|
|
|
41
41
|
用法:
|
|
42
42
|
|
|
43
|
-
- `/at-review [--fix] [<
|
|
43
|
+
- `/at-review [--fix] [<PR/MR-URL|分支|路径>]` — 输出审查结果; 私有托管目标需要本地已有只读访问权限, `--fix` 仅对匹配的工作树应用修复
|
|
44
44
|
|
|
45
45
|
### at-simplify
|
|
46
46
|
|
|
@@ -69,7 +69,7 @@ npx -y skills@latest add kairyou/agent-tools --skill at-zentao -g -y
|
|
|
69
69
|
- `/at-zentao bug <id>` — 直接处理指定 bug
|
|
70
70
|
- `/at-zentao task <id>` — 直接处理指定 task
|
|
71
71
|
|
|
72
|
-
配置: `~/.agent-tools/config.jsonc` → `"zentao": { "url", "account", "password" }`.
|
|
72
|
+
配置: `~/.agent-tools/config.jsonc` → `"zentao": { "url", "account", "password" }`. 密码可以直接填写, 也可以使用 `"password": { "env": "ZENTAO_PASSWORD" }` 引用环境变量; 不要在对话中粘贴凭据或 token.
|
|
73
73
|
|
|
74
74
|
## Integrations
|
|
75
75
|
|
package/config.default.jsonc
CHANGED
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
// log capability: AI session work log; see the extras doc for details.
|
|
20
20
|
"log": {
|
|
21
21
|
"enabled": true, // false: pause recording without uninstalling
|
|
22
|
-
"output": "~/.agent-tools/logs/ai-log
|
|
22
|
+
"output": "~/.agent-tools/logs/ai-log", // detailed: one <date>.md file per day; daily: one file
|
|
23
23
|
"language": "zh", // zh | en (detailed report headings)
|
|
24
|
-
"format": "
|
|
24
|
+
"format": "detailed", // detailed | daily
|
|
25
25
|
"projects": [ // record only these; empty: record everything
|
|
26
26
|
// "C:\\projects\\project-a"
|
|
27
27
|
]
|
package/dist/log/hook.mjs
CHANGED
|
@@ -868,7 +868,8 @@ var ParseErrorCode;
|
|
|
868
868
|
// integrations/log/hook.mjs
|
|
869
869
|
var MAX_SNAPSHOT_BYTES = 512 * 1024;
|
|
870
870
|
var MIN_RESULT_SUMMARY_LENGTH = 24;
|
|
871
|
-
var
|
|
871
|
+
var DAILY_ITEM_TARGET_CHARS = 160;
|
|
872
|
+
var DAILY_ITEM_HARD_MAX_CHARS = 320;
|
|
872
873
|
var INSTALL_ROOT = process.env.AGENT_TOOLS_HOME || path.join(os.homedir(), ".agent-tools");
|
|
873
874
|
var CACHE_ROOT = path.join(INSTALL_ROOT, "cache", "log");
|
|
874
875
|
async function main() {
|
|
@@ -980,7 +981,8 @@ async function loadLogConfig() {
|
|
|
980
981
|
}
|
|
981
982
|
const section = isPlainObject(parsed.log) ? parsed.log : {};
|
|
982
983
|
const enabled = section.enabled !== false;
|
|
983
|
-
const
|
|
984
|
+
const inferredFormat = section.format === void 0 && typeof section.output === "string" && section.output.trim().toLowerCase().endsWith(".md") ? "daily" : "detailed";
|
|
985
|
+
const format2 = pickFormat(section.format, inferredFormat);
|
|
984
986
|
const language = pickLanguage(section.language, "zh");
|
|
985
987
|
const output = pickOutput(section.output, format2, defaultOutput(format2));
|
|
986
988
|
const projects = [];
|
|
@@ -1239,11 +1241,23 @@ function buildDailyItems(state, scopeKey) {
|
|
|
1239
1241
|
function dailyItemText(turn) {
|
|
1240
1242
|
const request = String(turn.request_text || "");
|
|
1241
1243
|
const outcome = String(turn.result_summary || "");
|
|
1242
|
-
if (!hasSubstantiveTurn(request, outcome) || isTrivialTurn(request, outcome)) return "";
|
|
1243
|
-
const source = outcome
|
|
1244
|
+
if (!outcome || !hasSubstantiveTurn(request, outcome) || isTrivialTurn(request, outcome)) return "";
|
|
1245
|
+
const source = outcome;
|
|
1244
1246
|
const flattened = source.split("\n").map((line) => line.replace(/^[#>*\-\s`|]+/, "").trim()).filter(Boolean).join(" ");
|
|
1245
1247
|
if (!flattened) return "";
|
|
1246
|
-
return flattened
|
|
1248
|
+
return truncateDailyItem(flattened);
|
|
1249
|
+
}
|
|
1250
|
+
function truncateDailyItem(text) {
|
|
1251
|
+
if (text.length <= DAILY_ITEM_HARD_MAX_CHARS) return text;
|
|
1252
|
+
const limit = DAILY_ITEM_HARD_MAX_CHARS - 3;
|
|
1253
|
+
const prefix = text.slice(0, limit);
|
|
1254
|
+
const boundaries = [...prefix.matchAll(/[。!?;;]|[.!?](?=\s|$)/g)];
|
|
1255
|
+
const boundary = boundaries.at(-1)?.index;
|
|
1256
|
+
if (boundary !== void 0 && boundary + 1 >= Math.floor(DAILY_ITEM_TARGET_CHARS * 0.6)) {
|
|
1257
|
+
return `${prefix.slice(0, boundary + 1)}...`;
|
|
1258
|
+
}
|
|
1259
|
+
const targetPrefix = text.slice(0, DAILY_ITEM_TARGET_CHARS - 3);
|
|
1260
|
+
return `${targetPrefix}...`;
|
|
1247
1261
|
}
|
|
1248
1262
|
async function updateDailyFile(outputFile, day, items) {
|
|
1249
1263
|
if (items.length === 0) return;
|
package/docs/en/extras.md
CHANGED
|
@@ -69,8 +69,8 @@ Independent of and complementary to `at-daily-log` above; use them together or a
|
|
|
69
69
|
npx -y @kairyou/agent-tools@latest log -a claude codex opencode
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
- `format: "
|
|
73
|
-
- `format: "
|
|
72
|
+
- `format: "detailed"` (default): one detailed report per day with each turn's request and outcome, the files changed, and estimated lines added and removed
|
|
73
|
+
- `format: "daily"`: writes to a single Markdown file grouped by date; each completed answer with substantive results is recorded as one line, while pending prompts are omitted; content may be truncated by the length limit, so use it only as a lightweight activity index
|
|
74
74
|
- Codex: run `/hooks` once after installing to approve it; opencode: restart after installing or updating
|
|
75
75
|
|
|
76
76
|
`daily` output example:
|
|
@@ -123,9 +123,9 @@ All in `~/.agent-tools/config.jsonc`:
|
|
|
123
123
|
// log capability: AI session log
|
|
124
124
|
"log": {
|
|
125
125
|
"enabled": true, // false: pause recording without uninstalling
|
|
126
|
-
"output": "C:\\logs\\ai-log
|
|
126
|
+
"output": "C:\\logs\\ai-log", // detailed: one <date>.md per day; daily: one file
|
|
127
127
|
"language": "zh", // zh | en
|
|
128
|
-
"format": "
|
|
128
|
+
"format": "detailed", // detailed | daily
|
|
129
129
|
"projects": [ // optional: record only these; entries may override the keys above
|
|
130
130
|
"C:\\projects\\project-a",
|
|
131
131
|
{ "path": "C:\\projects\\project-b", "format": "detailed", "output": "C:\\logs\\project-b" }
|
|
@@ -11,10 +11,10 @@ agent-tools/
|
|
|
11
11
|
├── skills/ # Reusable Agent Skills.
|
|
12
12
|
│ ├── workflow/ # Workflow-oriented skills.
|
|
13
13
|
│ │ ├── at-commit/ # Conventional Commit message skill.
|
|
14
|
-
│ │ ├── at-review/ # Review changes for bugs and regressions.
|
|
14
|
+
│ │ ├── at-review/ # Review local or hosted changes for bugs and regressions.
|
|
15
15
|
│ │ └── at-simplify/ # Reduce complexity and duplication in changes.
|
|
16
16
|
│ └── integrations/ # Skills that integrate external systems.
|
|
17
|
-
│ └── at-zentao/ # ZenTao
|
|
17
|
+
│ └── at-zentao/ # Self-contained ZenTao workflow and secure API script.
|
|
18
18
|
├── docs/ # Advanced guides and contributor reference.
|
|
19
19
|
├── tools/ # Maintainer-only upstream sync and repository tooling.
|
|
20
20
|
└── scripts/ # Install, sync, validation, and maintenance scripts.
|
package/docs/zh-CN/extras.md
CHANGED
|
@@ -67,8 +67,8 @@ npx -y skills@latest add kairyou/agent-tools --skill at-daily-log -g -y
|
|
|
67
67
|
npx -y @kairyou/agent-tools@latest log -a claude codex opencode
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
- `format: "
|
|
71
|
-
- `format: "
|
|
70
|
+
- `format: "detailed"` (默认): 每天生成一份详细报告, 记录每轮请求与结果, 修改的文件, 以及新增/删除代码行数的估算
|
|
71
|
+
- `format: "daily"`: 写入单个 Markdown 文件, 并按日期归档; 每个已完成且有实质结果的回答记录为一行, 不记录未完成的提问; 内容可能因长度限制被截断, 因此仅适合作为轻量活动索引
|
|
72
72
|
- Codex 安装后运行 `/hooks` 批准一次; opencode 安装或更新后需要重启
|
|
73
73
|
|
|
74
74
|
`daily` 输出示例:
|
|
@@ -120,9 +120,9 @@ Changes
|
|
|
120
120
|
// log capability: AI 会话日志
|
|
121
121
|
"log": {
|
|
122
122
|
"enabled": true, // false: 临时停止记录, 不用卸载
|
|
123
|
-
"output": "C:\\logs\\ai-log
|
|
123
|
+
"output": "C:\\logs\\ai-log", // detailed: 每天一个 <date>.md; daily: 单一文件
|
|
124
124
|
"language": "zh", // zh | en
|
|
125
|
-
"format": "
|
|
125
|
+
"format": "detailed", // detailed | daily
|
|
126
126
|
"projects": [ // 可选: 只记录这些目录, 条目可覆盖上面的键
|
|
127
127
|
"C:\\projects\\project-a",
|
|
128
128
|
{ "path": "C:\\projects\\project-b", "format": "detailed", "output": "C:\\logs\\project-b" }
|
|
@@ -11,10 +11,10 @@ agent-tools/
|
|
|
11
11
|
├── skills/ # 可复用的 Agent Skills.
|
|
12
12
|
│ ├── workflow/ # 工作流类 skills.
|
|
13
13
|
│ │ ├── at-commit/ # 生成 Conventional Commits message.
|
|
14
|
-
│ │ ├── at-review/ #
|
|
14
|
+
│ │ ├── at-review/ # 审查本地或托管改动中的 bug 与回归风险.
|
|
15
15
|
│ │ └── at-simplify/ # 减少改动中的冗余和复杂度.
|
|
16
16
|
│ └── integrations/ # 对接外部系统的 skills.
|
|
17
|
-
│ └── at-zentao/ #
|
|
17
|
+
│ └── at-zentao/ # 自包含的禅道工作流和安全 API 脚本.
|
|
18
18
|
├── docs/ # 高级指南和贡献者参考.
|
|
19
19
|
├── tools/ # 仅供维护者使用的上游同步和仓库工具.
|
|
20
20
|
└── scripts/ # 安装, 同步, 校验和仓库维护脚本.
|
|
@@ -26,7 +26,8 @@ import { parse as parseJsonc } from "jsonc-parser";
|
|
|
26
26
|
|
|
27
27
|
const MAX_SNAPSHOT_BYTES = 512 * 1024;
|
|
28
28
|
const MIN_RESULT_SUMMARY_LENGTH = 24;
|
|
29
|
-
const
|
|
29
|
+
const DAILY_ITEM_TARGET_CHARS = 160;
|
|
30
|
+
const DAILY_ITEM_HARD_MAX_CHARS = 320;
|
|
30
31
|
|
|
31
32
|
const INSTALL_ROOT = process.env.AGENT_TOOLS_HOME || path.join(os.homedir(), ".agent-tools");
|
|
32
33
|
const CACHE_ROOT = path.join(INSTALL_ROOT, "cache", "log");
|
|
@@ -167,7 +168,15 @@ async function loadLogConfig() {
|
|
|
167
168
|
}
|
|
168
169
|
const section = isPlainObject(parsed.log) ? parsed.log : {};
|
|
169
170
|
const enabled = section.enabled !== false;
|
|
170
|
-
|
|
171
|
+
// Keep existing file-based configurations on daily while new installs use
|
|
172
|
+
// detailed by default. Explicit format always wins.
|
|
173
|
+
const inferredFormat =
|
|
174
|
+
section.format === undefined &&
|
|
175
|
+
typeof section.output === "string" &&
|
|
176
|
+
section.output.trim().toLowerCase().endsWith(".md")
|
|
177
|
+
? "daily"
|
|
178
|
+
: "detailed";
|
|
179
|
+
const format = pickFormat(section.format, inferredFormat);
|
|
171
180
|
const language = pickLanguage(section.language, "zh");
|
|
172
181
|
const output = pickOutput(section.output, format, defaultOutput(format));
|
|
173
182
|
|
|
@@ -497,8 +506,11 @@ function buildDailyItems(state, scopeKey) {
|
|
|
497
506
|
function dailyItemText(turn) {
|
|
498
507
|
const request = String(turn.request_text || "");
|
|
499
508
|
const outcome = String(turn.result_summary || "");
|
|
500
|
-
|
|
501
|
-
|
|
509
|
+
// Daily is an outcome index, not a prompt inbox. Keep request-only turns in
|
|
510
|
+
// detailed reports, but do not present an unfinished question as completed
|
|
511
|
+
// work in the compact daily file.
|
|
512
|
+
if (!outcome || !hasSubstantiveTurn(request, outcome) || isTrivialTurn(request, outcome)) return "";
|
|
513
|
+
const source = outcome;
|
|
502
514
|
// Flattened rather than first-line: a structured summary often opens with a
|
|
503
515
|
// preamble line, and the substance sits in the lines after it.
|
|
504
516
|
const flattened = source
|
|
@@ -507,9 +519,23 @@ function dailyItemText(turn) {
|
|
|
507
519
|
.filter(Boolean)
|
|
508
520
|
.join(" ");
|
|
509
521
|
if (!flattened) return "";
|
|
510
|
-
return flattened
|
|
511
|
-
|
|
512
|
-
|
|
522
|
+
return truncateDailyItem(flattened);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function truncateDailyItem(text) {
|
|
526
|
+
if (text.length <= DAILY_ITEM_HARD_MAX_CHARS) return text;
|
|
527
|
+
const limit = DAILY_ITEM_HARD_MAX_CHARS - 3;
|
|
528
|
+
const prefix = text.slice(0, limit);
|
|
529
|
+
// Prefer the longest complete sentence within the hard cap. The target is a
|
|
530
|
+
// soft guide: retaining more complete context is better when the next
|
|
531
|
+
// sentence ends before the hard limit.
|
|
532
|
+
const boundaries = [...prefix.matchAll(/[。!?;;]|[.!?](?=\s|$)/g)];
|
|
533
|
+
const boundary = boundaries.at(-1)?.index;
|
|
534
|
+
if (boundary !== undefined && boundary + 1 >= Math.floor(DAILY_ITEM_TARGET_CHARS * 0.6)) {
|
|
535
|
+
return `${prefix.slice(0, boundary + 1)}...`;
|
|
536
|
+
}
|
|
537
|
+
const targetPrefix = text.slice(0, DAILY_ITEM_TARGET_CHARS - 3);
|
|
538
|
+
return `${targetPrefix}...`;
|
|
513
539
|
}
|
|
514
540
|
|
|
515
541
|
async function updateDailyFile(outputFile, day, items) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kairyou/agent-tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Reusable Agent Skills, plus integrations (statusline, provider usage, vision) that install into Codex, Claude Code, and opencode.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -6,143 +6,179 @@ argument-hint: "bug <id> | task <id> | bugs | tasks | export bug|task <id>"
|
|
|
6
6
|
|
|
7
7
|
# ZenTao Bug/Task Workflow
|
|
8
8
|
|
|
9
|
+
## Secure CLI boundary
|
|
10
|
+
|
|
11
|
+
This Skill bundles `scripts/zentao-cli.mjs`. Resolve the Skill root as the
|
|
12
|
+
directory containing this `SKILL.md`, then run the script with Node using its
|
|
13
|
+
resolved path from any working directory:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
node <skill-root>/scripts/zentao-cli.mjs <command>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The script is the only component allowed to read ZenTao configuration,
|
|
20
|
+
exchange credentials for a token, send authenticated requests, or inspect raw
|
|
21
|
+
error responses. Run it directly without reading or copying its source into
|
|
22
|
+
the conversation. Never read `~/.agent-tools/config.jsonc`, print ZenTao env
|
|
23
|
+
vars, call the token endpoint, or construct a ZenTao `Token` header yourself.
|
|
24
|
+
|
|
25
|
+
The CLI emits only sanitized JSON. Treat a nonzero exit as a stopped ZenTao
|
|
26
|
+
operation and report its safe `error`, `message`, and optional HTTP `status`.
|
|
27
|
+
Do not work around the CLI with `curl` when authentication or an endpoint
|
|
28
|
+
fails.
|
|
29
|
+
|
|
9
30
|
## Configuration
|
|
10
31
|
|
|
11
|
-
|
|
32
|
+
The CLI reads the global `~/.agent-tools/config.jsonc`, or
|
|
33
|
+
`$AGENT_TOOLS_HOME/config.jsonc` when `AGENT_TOOLS_HOME` is set. It never reads
|
|
34
|
+
repository-level configuration. Basic configuration:
|
|
12
35
|
|
|
13
36
|
```jsonc
|
|
14
37
|
{
|
|
15
38
|
"zentao": {
|
|
16
|
-
"url": "
|
|
17
|
-
"account": "
|
|
18
|
-
"password": "
|
|
39
|
+
"url": "https://zentao.example.com",
|
|
40
|
+
"account": "user",
|
|
41
|
+
"password": "your-password"
|
|
19
42
|
}
|
|
20
43
|
}
|
|
21
44
|
```
|
|
22
45
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
ZenTao config comes ONLY from env vars and the global `~/.agent-tools/config.jsonc`, never a repository-level file — so an untrusted repo can't redirect the endpoint to capture your credentials.
|
|
46
|
+
To avoid storing the password in the file, use
|
|
47
|
+
`"password": { "env": "ZENTAO_PASSWORD" }` and set that environment variable.
|
|
48
|
+
Direct env overrides are `ZENTAO_URL`, `ZENTAO_ACCOUNT`, and
|
|
49
|
+
`ZENTAO_PASSWORD`. `ZENTAO_TOKEN` may be used instead of password exchange; it
|
|
50
|
+
is accepted only from the environment.
|
|
29
51
|
|
|
30
|
-
|
|
52
|
+
When configuration is missing, tell the user which file to edit and show the
|
|
53
|
+
template above. Never ask them to paste a password or token into chat, and do
|
|
54
|
+
not edit or inspect the file after they add credentials. Ask them to say
|
|
55
|
+
"done", then validate with:
|
|
31
56
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
2. Ask for the URL and account as a PLAIN chat question and wait for the reply — never collect free-form values via a multiple-choice prompt (its fixed option labels would be submitted as the answer). Write the reply into the config — these are not secrets.
|
|
35
|
-
3. NEVER ask the user to paste the password into the chat (it would persist in transcripts). Tell them — in the same message as step 2 — to fill `zentao.password` in the file themselves or set env `ZENTAO_PASSWORD`, and to say "done" when finished.
|
|
36
|
-
4. Then validate immediately: exchange a token and call `GET /api.php/v1/user`. Report the result before doing any real work.
|
|
37
|
-
|
|
38
|
-
## Authentication (once per session)
|
|
39
|
-
|
|
40
|
-
ZenTao tokens expire, so exchange credentials for a fresh token at the start of each session:
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
POST $ZENTAO_URL/api.php/v1/tokens
|
|
44
|
-
Content-Type: application/json
|
|
45
|
-
{"account":"...","password":"..."}
|
|
57
|
+
```text
|
|
58
|
+
node <skill-root>/scripts/zentao-cli.mjs doctor
|
|
46
59
|
```
|
|
47
60
|
|
|
48
|
-
|
|
61
|
+
Report only whether the connection succeeded and whether authentication used
|
|
62
|
+
`token` or `account-password`.
|
|
49
63
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
**Connectivity check**: after obtaining the token, `GET $ZENTAO_URL/api.php/v1/user` must succeed before any other work. On failure, stop and tell the user to check URL/credentials.
|
|
53
|
-
|
|
54
|
-
## Usage
|
|
64
|
+
## CLI commands
|
|
55
65
|
|
|
56
|
-
-
|
|
57
|
-
- `/at-zentao task <id>` — handle a single task
|
|
58
|
-
- `/at-zentao bugs` — list bugs assigned to the configured account; the user picks one or several (multiple = batch mode)
|
|
59
|
-
- `/at-zentao tasks` — same for tasks
|
|
60
|
-
- `/at-zentao export bug <id>` (or `export task <id>`) — export to a self-contained Markdown bundle for handoff; does NOT fix or write back (see Export mode)
|
|
66
|
+
Read-only commands:
|
|
61
67
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
- `GET /my-work-task.json` — tasks assigned to the configured account
|
|
70
|
-
- Response shape: `{"status":"success","data":"<JSON-encoded string>"}` — the `data` field is a STRING containing JSON (with `\uXXXX` escapes), so decode it a second time. Bugs are in `.bugs[]` (fields: `id`, `title`, `severity`, `pri`, `status`, `project`, `product`), tasks in `.tasks[]`. The first page usually suffices, but read the pager info inside `data` for the total — if there are more pages, tell the user (e.g. "showing 20 of 45; say more to load the rest") instead of silently truncating, and fetch further pages only on request.
|
|
71
|
-
|
|
72
|
-
**Details and write-back** (REST v1):
|
|
73
|
-
|
|
74
|
-
- `GET /api.php/v1/bugs/{id}` — bug details (title, steps, severity, module)
|
|
75
|
-
- `GET /api.php/v1/tasks/{id}` — task details
|
|
76
|
-
|
|
77
|
-
**Attachments / inline images** (legacy, same Token header; binary — save with `curl -o`, never read as text):
|
|
78
|
-
|
|
79
|
-
- `GET /file-read-{fileID}.{ext}` — view/inline. Observed on 18.12: bug screenshots are embedded in the `steps` HTML as `<img src=".../file-read-{id}.png">` while the `files` list is empty — so scan `steps`, don't rely on `files`.
|
|
80
|
-
- `GET /file-download-{fileID}.html` — download an attachment (when `files` is populated).
|
|
81
|
-
|
|
82
|
-
**Resolving a bug** (the REST `PUT /bugs/{id}` does NOT perform a real resolve — do not use it for status changes; use the legacy action, which mirrors the web form and triggers the full workflow):
|
|
83
|
-
|
|
84
|
-
1. `POST /bug-resolve-{id}.json` with a form body (`Content-Type: application/x-www-form-urlencoded`, same Token header):
|
|
85
|
-
`resolution=fixed&resolvedBuild=trunk&responsibleBy=<account>&comment=<...>`
|
|
86
|
-
where `responsibleBy` is the authenticated account (from config) — this instance requires it.
|
|
87
|
-
Encoding: NEVER pass non-ASCII (Chinese) text as a command-line argument — Windows curl.exe converts argv through the ANSI codepage and mangles it regardless of terminal. Feed such text via stdin: `--data-urlencode "comment@-"` plus a herestring/pipe/heredoc. ASCII fields may go inline in `-d`; all data flags merge into one form body. Verified one-liner:
|
|
88
|
-
`curl -s -X POST -H "Token: $TOKEN" -d "resolution=fixed&resolvedBuild=trunk&responsibleBy=<account>" --data-urlencode "comment@-" "$ZENTAO_URL/bug-resolve-{id}.json" <<< $'<comment line 1>\n<line 2>'`
|
|
89
|
-
2. To add a comment WITHOUT changing status: `POST /action-comment-bug-{id}.json`, comment fed via stdin the same way (`--data-urlencode "comment@-"`).
|
|
90
|
-
3. Check the DECODED response: legacy endpoints return HTTP 200 with `{"status":"success","data":"..."}` even on failure — the real outcome is inside `data` (`result: "fail"` + per-field `message`). Surface those validation messages to the user verbatim; if a required field is missing, discover the form's fields and defaults via `GET /bug-resolve-{id}.json`, fill it, and re-confirm with the user before retrying.
|
|
91
|
-
|
|
92
|
-
**Finishing a task**:
|
|
68
|
+
```text
|
|
69
|
+
node <skill-root>/scripts/zentao-cli.mjs list bugs
|
|
70
|
+
node <skill-root>/scripts/zentao-cli.mjs list tasks
|
|
71
|
+
node <skill-root>/scripts/zentao-cli.mjs get bug <id>
|
|
72
|
+
node <skill-root>/scripts/zentao-cli.mjs get task <id>
|
|
73
|
+
node <skill-root>/scripts/zentao-cli.mjs get bug <id> --download-dir <path>
|
|
74
|
+
```
|
|
93
75
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- `consumed` — TOTAL consumed, must exceed the previous total: compute as `data.task.consumed + currentConsumed`.
|
|
98
|
-
- `realStarted` — required; reuse `data.task.realStarted` if set, otherwise use a sensible date confirmed with the user (format `YYYY-MM-DD HH:MM:SS`; a space, so either `--data-urlencode` it or write the space as `+` inside `-d`).
|
|
99
|
-
- `finishedDate` — now, same format.
|
|
100
|
-
3. To comment on a task without finishing it: `POST /action-comment-task-{id}.json`.
|
|
76
|
+
`get` downloads token-gated inline images and attachments into a temporary
|
|
77
|
+
directory by default and returns only local paths. Inspect those local files;
|
|
78
|
+
never pass the original ZenTao URL to an image tool.
|
|
101
79
|
|
|
102
|
-
|
|
80
|
+
Write commands require JSON on stdin and are allowed only after the explicit
|
|
81
|
+
confirmation steps below:
|
|
103
82
|
|
|
104
|
-
|
|
83
|
+
```text
|
|
84
|
+
node <skill-root>/scripts/zentao-cli.mjs comment bug <id>
|
|
85
|
+
node <skill-root>/scripts/zentao-cli.mjs comment task <id>
|
|
86
|
+
node <skill-root>/scripts/zentao-cli.mjs resolve bug <id>
|
|
87
|
+
node <skill-root>/scripts/zentao-cli.mjs finish task <id>
|
|
88
|
+
```
|
|
105
89
|
|
|
106
|
-
|
|
90
|
+
Input shapes:
|
|
107
91
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
6. **git add** — first run `git diff --staged --name-only`; if the index already holds unrelated changes, STOP and ask the user (commit those separately / unstage them / proceed anyway) so the `bug#<id>` commit isn't polluted. Then stage only the files changed for THIS item, listing them explicitly (never `git add -A`).
|
|
114
|
-
7. **Ask whether to commit** (never commit automatically):
|
|
115
|
-
- 1) Commit — generate and show a Conventional Commits message, following all at-commit conventions (language policy, ≤74-char single-line title). Right after `type(scope):`, add the ZenTao link token — `bug#<id>` or `task#<id>` — e.g. `fix(<scope>): bug#30887 <desc>` (scope optional). Rewrite the description from the diff rather than copying the title, keeping the title's domain terms.
|
|
116
|
-
- 2) Not yet — keep the changes staged and continue
|
|
117
|
-
- 3) Needs adjustment — take the feedback and return to step 4
|
|
118
|
-
8. **Ask whether to update ZenTao** (never change status automatically). First DRAFT the write-back, then show it in the confirmation question. If the item was NOT committed (you chose "Not yet" at step 7), do not draft a `fixed` resolution or a commit hash — at most a comment with the status left unchanged, since a `fixed` write-back must reference a real commit:
|
|
119
|
-
- **Resolution** — pick the value that matches what actually happened (ZenTao's enum): `fixed` 已解决 (default after a code fix), `notrepro` 无法重现, `duplicate` 重复Bug (needs the duplicate bug id), `bydesign` 设计如此, `external` 外部原因, `postponed` 延期处理, `willnotfix` 不予解决. If investigation showed the bug needs no code fix, propose the fitting non-`fixed` resolution instead.
|
|
120
|
-
- **Comment** — one sentence: root cause + change summary, plus the commit hash if committed. Don't list files or expand into narrative.
|
|
121
|
-
- Options (reply with a number): 1) Submit 2) Edit first 3) Comment only (no status change).
|
|
122
|
-
- **For tasks**, default to adding a comment only (drafted the same way). Offer "finish" ONLY for simple tasks completable in one sitting — it asks the user for hours (`currentConsumed`) and submits once. For multi-day tasks or teams that log per-day workhours, do NOT attempt finish via API; post the comment and point the user to the web UI's 记录工时/完成 forms, which handle per-day entries properly.
|
|
92
|
+
```json
|
|
93
|
+
{"comment":"Root cause and result."}
|
|
94
|
+
{"resolution":"fixed","resolvedBuild":"trunk","comment":"Root cause and result, commit abc1234."}
|
|
95
|
+
{"currentConsumed":1.5,"realStarted":"2026-08-11 09:00:00","finishedDate":"2026-08-11 10:30:00"}
|
|
96
|
+
```
|
|
123
97
|
|
|
124
|
-
|
|
98
|
+
For `duplicate`, also pass `"duplicateBug": <id>`. Send JSON through stdin,
|
|
99
|
+
not as a command-line argument. The CLI handles UTF-8 form encoding and
|
|
100
|
+
computes a task's total consumed hours from its current ZenTao value.
|
|
125
101
|
|
|
126
|
-
|
|
102
|
+
## Usage
|
|
127
103
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
104
|
+
- `/at-zentao bug <id>` — handle a single bug.
|
|
105
|
+
- `/at-zentao task <id>` — handle a single task.
|
|
106
|
+
- `/at-zentao bugs` — list bugs assigned to the configured account; let the
|
|
107
|
+
user select one or more.
|
|
108
|
+
- `/at-zentao tasks` — list assigned tasks and let the user select.
|
|
109
|
+
- `/at-zentao export bug <id>` or `export task <id>` — create a read-only,
|
|
110
|
+
self-contained handoff bundle.
|
|
111
|
+
|
|
112
|
+
If a list response includes pager data showing more items than returned, tell
|
|
113
|
+
the user the shown and total counts. Do not silently imply the list is complete.
|
|
114
|
+
Do not browse through products/projects; start from assigned lists or an
|
|
115
|
+
explicit item id.
|
|
116
|
+
|
|
117
|
+
## Per-item workflow
|
|
118
|
+
|
|
119
|
+
Follow these steps in order:
|
|
120
|
+
|
|
121
|
+
1. **Fetch details** — use the CLI `get` command. Read every downloaded image
|
|
122
|
+
now so screenshots inform the fix. If no image-inspection tool is available,
|
|
123
|
+
continue from text and state that screenshots were skipped.
|
|
124
|
+
2. **Restate and confirm** — explain the problem and intended fix in your own
|
|
125
|
+
words. Ask before editing when the item is ambiguous.
|
|
126
|
+
3. **Locate the code** — search the current project and explain how the relevant
|
|
127
|
+
code was identified.
|
|
128
|
+
4. **Fix** — change only what this item requires.
|
|
129
|
+
5. **Verify** — run the narrowest meaningful test, build, or typecheck. Reproduce
|
|
130
|
+
a code-observable bug before and after when practical. For visual changes,
|
|
131
|
+
state what was checked and what still needs the user's eyes. Stop on a failed
|
|
132
|
+
check.
|
|
133
|
+
6. **Stage** — first inspect `git diff --staged --name-only`. If unrelated files
|
|
134
|
+
are staged, stop and ask how to handle them. Otherwise stage only files for
|
|
135
|
+
this item by explicit path; never use `git add -A`.
|
|
136
|
+
7. **Ask whether to commit** — offer Commit, Not yet, or Needs adjustment. For a
|
|
137
|
+
commit, show a single-line Conventional Commit message before committing.
|
|
138
|
+
Put `bug#<id>` or `task#<id>` immediately after `type(scope):`, for example
|
|
139
|
+
`fix(auth): bug#30887 reject expired sessions`. Never commit automatically.
|
|
140
|
+
8. **Ask whether to update ZenTao** — draft the exact resolution/comment and
|
|
141
|
+
offer Submit, Edit first, or Comment only. Never invoke a write CLI command
|
|
142
|
+
before confirmation. A `fixed` resolution must cite a real commit; without a
|
|
143
|
+
commit, offer at most a comment with status unchanged.
|
|
144
|
+
|
|
145
|
+
Bug resolutions are `fixed`, `notrepro`, `duplicate`, `bydesign`, `external`,
|
|
146
|
+
`postponed`, and `willnotfix`. Choose what matches the verified outcome. A
|
|
147
|
+
write-back comment is one sentence containing root cause, change summary, and
|
|
148
|
+
the commit hash when committed.
|
|
149
|
+
|
|
150
|
+
For tasks, default to comment only. Offer `finish` only for a simple task
|
|
151
|
+
completed in one sitting, and ask the user for `currentConsumed`; never invent
|
|
152
|
+
hours. For multi-day work or per-day time records, comment and direct the user
|
|
153
|
+
to ZenTao's web UI.
|
|
154
|
+
|
|
155
|
+
## Export mode
|
|
156
|
+
|
|
157
|
+
Export is read-only and never fixes code, commits, or writes back:
|
|
158
|
+
|
|
159
|
+
1. Fetch the item with `get`, including every downloaded image/attachment.
|
|
160
|
+
2. Ask where to save; default to the Desktop and never the code repository.
|
|
161
|
+
3. Write a Markdown handoff with id, title, status, severity/priority,
|
|
162
|
+
module/product, description/steps, and useful history available in the safe
|
|
163
|
+
CLI response. Do not include credentials or login-gated URLs.
|
|
164
|
+
4. With no images, write `<dest>/zentao-<bug|task>-<id>.md`. With images, create
|
|
165
|
+
a same-named directory containing the Markdown and real image files, rewrite
|
|
166
|
+
image references to relative paths, and zip only when a single artifact is
|
|
167
|
+
needed.
|
|
134
168
|
|
|
135
169
|
## Batch mode
|
|
136
170
|
|
|
137
|
-
-
|
|
138
|
-
-
|
|
139
|
-
-
|
|
140
|
-
|
|
171
|
+
- Process one item at a time, each with its own stage and commit.
|
|
172
|
+
- Show the pending order before starting.
|
|
173
|
+
- Continue only after the current item is committed. If it remains staged,
|
|
174
|
+
offer commit, stash and continue, or stop.
|
|
175
|
+
- After each item, ask whether to continue or stop and summarize progress.
|
|
141
176
|
|
|
142
177
|
## Hard rules
|
|
143
178
|
|
|
144
|
-
- Never
|
|
145
|
-
-
|
|
146
|
-
-
|
|
147
|
-
-
|
|
148
|
-
-
|
|
179
|
+
- Never expose account, password, token, cookies, or authorization headers.
|
|
180
|
+
- Never bypass the bundled CLI for ZenTao authentication or API access.
|
|
181
|
+
- Never commit or change ZenTao state without separate explicit confirmation.
|
|
182
|
+
- Keep the `bug#<id>` or `task#<id>` token in every related commit subject.
|
|
183
|
+
- Collect free-form values such as output paths and hours in plain chat, not a
|
|
184
|
+
fixed-choice prompt. Passwords and tokens are never collected in chat.
|