@kunlv/atdc 1.0.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/AGENTS.md +58 -0
- package/GO.md +245 -0
- package/bin/add-command.py +144 -0
- package/bin/atdc.js +460 -0
- package/bin/cls.js +98 -0
- package/central/link.sh +60 -0
- package/central/ticket_center_server/.handoffs/TASK-238389_QYinVipLimit.md +128 -0
- package/central/ticket_center_server/.test_plans/TASK-227254-SupportMembership-self-test-plan.md +566 -0
- package/central/ticket_center_server/.test_plans/task-238389-qyin-vip-limit-self-test-plan.md +210 -0
- package/commands/claude/atd.md +3 -0
- package/commands/claude/atdc/1-spec.md +5 -0
- package/commands/claude/atdc/1-update.md +5 -0
- package/commands/claude/atdc/2-qa.md +3 -0
- package/commands/claude/atdc/3-impl-skip-spec.md +5 -0
- package/commands/claude/atdc/3-impl.md +3 -0
- package/commands/claude/atdc/4-verify.md +3 -0
- package/commands/claude/atdc/5-done.md +3 -0
- package/commands/claude/atdc/add-command.md +4 -0
- package/commands/claude/atdc/add-to-hc.md +3 -0
- package/commands/claude/atdc/analysis-cls-log.md +4 -0
- package/commands/claude/atdc/article.md +6 -0
- package/commands/claude/atdc/bugfix.md +4 -0
- package/commands/claude/atdc/code-simplifier.md +8 -0
- package/commands/claude/atdc/commit.md +4 -0
- package/commands/claude/atdc/compound.md +5 -0
- package/commands/claude/atdc/context.md +3 -0
- package/commands/claude/atdc/diagnose.md +8 -0
- package/commands/claude/atdc/git-guardrails.md +18 -0
- package/commands/claude/atdc/grill-with-docs.md +8 -0
- package/commands/claude/atdc/handoff.md +8 -0
- package/commands/claude/atdc/health.md +3 -0
- package/commands/claude/atdc/learn.md +4 -0
- package/commands/claude/atdc/review.md +10 -0
- package/commands/claude/atdc/search.md +4 -0
- package/commands/claude/atdc/strategy.md +3 -0
- package/commands/claude/atdc/table2xlsx.md +4 -0
- package/commands/claude/atdc/test-plan.md +5 -0
- package/commands/claude/atdc/travel-planner.md +4 -0
- package/commands/claude/atdc/xlsx2sql-insert.md +4 -0
- package/commands/claude/atdc/xlsx2sql-update.md +4 -0
- package/commands/claude/atdc/zoom-out.md +8 -0
- package/commands/codex/atdc/SKILL.md +8 -0
- package/commands/codex/atdc-1-spec/SKILL.md +8 -0
- package/commands/codex/atdc-1-update/SKILL.md +8 -0
- package/commands/codex/atdc-2-qa/SKILL.md +8 -0
- package/commands/codex/atdc-3-impl/SKILL.md +8 -0
- package/commands/codex/atdc-3-impl-skip-spec/SKILL.md +8 -0
- package/commands/codex/atdc-4-verify/SKILL.md +8 -0
- package/commands/codex/atdc-5-done/SKILL.md +8 -0
- package/commands/codex/atdc-add-command/SKILL.md +7 -0
- package/commands/codex/atdc-add-to-hc/SKILL.md +8 -0
- package/commands/codex/atdc-analysis-cls-log/SKILL.md +5 -0
- package/commands/codex/atdc-article/SKILL.md +8 -0
- package/commands/codex/atdc-bugfix/SKILL.md +5 -0
- package/commands/codex/atdc-code-simplifier/SKILL.md +7 -0
- package/commands/codex/atdc-commit/SKILL.md +7 -0
- package/commands/codex/atdc-compound/SKILL.md +8 -0
- package/commands/codex/atdc-context/SKILL.md +8 -0
- package/commands/codex/atdc-diagnose/SKILL.md +9 -0
- package/commands/codex/atdc-git-guardrails/SKILL.md +19 -0
- package/commands/codex/atdc-grill-with-docs/SKILL.md +9 -0
- package/commands/codex/atdc-handoff/SKILL.md +9 -0
- package/commands/codex/atdc-health/SKILL.md +8 -0
- package/commands/codex/atdc-learn/SKILL.md +7 -0
- package/commands/codex/atdc-review/SKILL.md +49 -0
- package/commands/codex/atdc-search/SKILL.md +5 -0
- package/commands/codex/atdc-strategy/SKILL.md +8 -0
- package/commands/codex/atdc-table2xlsx/SKILL.md +8 -0
- package/commands/codex/atdc-test-plan/SKILL.md +13 -0
- package/commands/codex/atdc-travel-planner/SKILL.md +7 -0
- package/commands/codex/atdc-xlsx2sql-insert/SKILL.md +8 -0
- package/commands/codex/atdc-xlsx2sql-update/SKILL.md +8 -0
- package/commands/codex/atdc-zoom-out/SKILL.md +9 -0
- package/commands/cursor/atdc/SKILL.md +8 -0
- package/commands/cursor/atdc-1-spec/SKILL.md +8 -0
- package/commands/cursor/atdc-1-update/SKILL.md +8 -0
- package/commands/cursor/atdc-2-qa/SKILL.md +8 -0
- package/commands/cursor/atdc-3-impl/SKILL.md +8 -0
- package/commands/cursor/atdc-3-impl-skip-spec/SKILL.md +8 -0
- package/commands/cursor/atdc-4-verify/SKILL.md +8 -0
- package/commands/cursor/atdc-5-done/SKILL.md +8 -0
- package/commands/cursor/atdc-add-command/SKILL.md +7 -0
- package/commands/cursor/atdc-add-to-hc/SKILL.md +8 -0
- package/commands/cursor/atdc-analysis-cls-log/SKILL.md +5 -0
- package/commands/cursor/atdc-article/SKILL.md +8 -0
- package/commands/cursor/atdc-bugfix/SKILL.md +5 -0
- package/commands/cursor/atdc-code-simplifier/SKILL.md +7 -0
- package/commands/cursor/atdc-commit/SKILL.md +7 -0
- package/commands/cursor/atdc-compound/SKILL.md +8 -0
- package/commands/cursor/atdc-context/SKILL.md +8 -0
- package/commands/cursor/atdc-diagnose/SKILL.md +8 -0
- package/commands/cursor/atdc-git-guardrails/SKILL.md +18 -0
- package/commands/cursor/atdc-grill-with-docs/SKILL.md +8 -0
- package/commands/cursor/atdc-handoff/SKILL.md +8 -0
- package/commands/cursor/atdc-health/SKILL.md +8 -0
- package/commands/cursor/atdc-learn/SKILL.md +7 -0
- package/commands/cursor/atdc-review/SKILL.md +49 -0
- package/commands/cursor/atdc-search/SKILL.md +5 -0
- package/commands/cursor/atdc-strategy/SKILL.md +8 -0
- package/commands/cursor/atdc-table2xlsx/SKILL.md +8 -0
- package/commands/cursor/atdc-test-plan/SKILL.md +7 -0
- package/commands/cursor/atdc-travel-planner/SKILL.md +7 -0
- package/commands/cursor/atdc-xlsx2sql-insert/SKILL.md +8 -0
- package/commands/cursor/atdc-xlsx2sql-update/SKILL.md +8 -0
- package/commands/cursor/atdc-zoom-out/SKILL.md +8 -0
- package/commands/opencode/atd.md +6 -0
- package/commands/opencode/atdc/1-spec.md +8 -0
- package/commands/opencode/atdc/1-update.md +8 -0
- package/commands/opencode/atdc/2-qa.md +6 -0
- package/commands/opencode/atdc/3-impl-skip-spec.md +8 -0
- package/commands/opencode/atdc/3-impl.md +6 -0
- package/commands/opencode/atdc/4-verify.md +6 -0
- package/commands/opencode/atdc/5-done.md +6 -0
- package/commands/opencode/atdc/add-command.md +6 -0
- package/commands/opencode/atdc/add-to-hc.md +6 -0
- package/commands/opencode/atdc/analysis-cls-log.md +6 -0
- package/commands/opencode/atdc/article.md +6 -0
- package/commands/opencode/atdc/bugfix.md +6 -0
- package/commands/opencode/atdc/code-simplifier.md +8 -0
- package/commands/opencode/atdc/commit.md +6 -0
- package/commands/opencode/atdc/compound.md +8 -0
- package/commands/opencode/atdc/context.md +6 -0
- package/commands/opencode/atdc/diagnose.md +8 -0
- package/commands/opencode/atdc/git-guardrails.md +18 -0
- package/commands/opencode/atdc/grill-with-docs.md +8 -0
- package/commands/opencode/atdc/handoff.md +8 -0
- package/commands/opencode/atdc/health.md +6 -0
- package/commands/opencode/atdc/learn.md +6 -0
- package/commands/opencode/atdc/review.md +7 -0
- package/commands/opencode/atdc/search.md +6 -0
- package/commands/opencode/atdc/strategy.md +6 -0
- package/commands/opencode/atdc/table2xlsx.md +6 -0
- package/commands/opencode/atdc/test-plan.md +6 -0
- package/commands/opencode/atdc/travel-planner.md +6 -0
- package/commands/opencode/atdc/xlsx2sql-insert.md +6 -0
- package/commands/opencode/atdc/xlsx2sql-update.md +6 -0
- package/commands/opencode/atdc/zoom-out.md +8 -0
- package/config/cls-defaults.json +19 -0
- package/hooks/atd-archive.sh +86 -0
- package/hooks/atd-state.sh +165 -0
- package/hooks/evidence-hook.sh +88 -0
- package/hooks/evidence-log.sh +54 -0
- package/hooks/guardrails.sh +65 -0
- package/hooks/handoff-compress.sh +104 -0
- package/hooks/phase-guard.sh +134 -0
- package/hooks/phase-write-guard.sh +96 -0
- package/hooks/ponytail-fix.sh +179 -0
- package/hooks/ponytail-guard.sh +66 -0
- package/hooks/ponytail-scan.sh +62 -0
- package/install.sh +276 -0
- package/package.json +20 -0
- package/packages/cls/bin/cls.js +146 -0
- package/packages/cls/config/defaults.json +17 -0
- package/packages/cls/mcp/server.js +142 -0
- package/packages/cls/package.json +29 -0
- package/packages/cls/scripts/postinstall.js +19 -0
- package/packages/cls/src/client.js +262 -0
- package/prompts/1-spec.md +271 -0
- package/prompts/1-update.md +198 -0
- package/prompts/2-qa.md +164 -0
- package/prompts/3-impl-bugfix.md +271 -0
- package/prompts/3-impl.md +419 -0
- package/prompts/4-verify.md +160 -0
- package/prompts/5-done.md +227 -0
- package/prompts/6-article.md +571 -0
- package/prompts/X-add-command.md +60 -0
- package/prompts/X-add-to-hc.md +178 -0
- package/prompts/X-analysis-cls-log.md +68 -0
- package/prompts/X-bugfix.md +10 -0
- package/prompts/X-code-simplifier.md +38 -0
- package/prompts/X-commit.md +116 -0
- package/prompts/X-compound.md +188 -0
- package/prompts/X-context-scan.md +101 -0
- package/prompts/X-diagnose.md +116 -0
- package/prompts/X-grill-with-docs.md +120 -0
- package/prompts/X-handoff.md +80 -0
- package/prompts/X-health.md +78 -0
- package/prompts/X-learn.md +151 -0
- package/prompts/X-review.md +417 -0
- package/prompts/X-search.md +74 -0
- package/prompts/X-strategy.md +95 -0
- package/prompts/X-table2xlsx.md +46 -0
- package/prompts/X-test-plan.md +436 -0
- package/prompts/X-travel-planner.md +22 -0
- package/prompts/X-xlsx2sql-insert.md +34 -0
- package/prompts/X-xlsx2sql-update.md +40 -0
- package/prompts/X-zoom-out.md +119 -0
- package/reference/diagnose-loop.md +66 -0
- package/reference/gates.md +90 -0
- package/reference/git-guardrails.md +71 -0
- package/reference/guards.md +275 -0
- package/reference/learn.md +100 -0
- package/reference/memory.md +190 -0
- package/reference/risk.md +74 -0
- package/reference/tdd.md +40 -0
- package/scripts/svg2png.js +46 -0
- package/src/cls/client.js +244 -0
- package/src/constants.js +49 -0
- package/src/evidence/ai-draft-metrics.js +157 -0
- package/src/evidence/canvas.js +184 -0
- package/src/evidence/index.js +98 -0
- package/src/evidence/sink-events.js +165 -0
- package/src/evidence/stage-timing.js +112 -0
- package/src/installers/claude.js +79 -0
- package/src/installers/codex.js +62 -0
- package/src/installers/opencode.js +72 -0
- package/src/manifest/ponytail-patterns.json +185 -0
- package/src/mcp/cls-mcp-server.js +142 -0
- package/src/utils.js +79 -0
- package/src/validators/state-validate.js +123 -0
- package/templates/.phase-state.json +13 -0
- package/templates/adr.md +62 -0
- package/templates/changelog.md +21 -0
- package/templates/concepts.md +35 -0
- package/templates/design.md +47 -0
- package/templates/handoff.md +64 -0
- package/templates/learn-skill.md +43 -0
- package/templates/progress.json +17 -0
- package/templates/proposal.md +29 -0
- package/templates/solution.md +36 -0
- package/templates/strategy.md +39 -0
- package/templates/tasks.md +41 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Git 安全防护(安装/检查 pre-push hook,拦截危险命令)。用法 /atdc:git-guardrails [install|check]
|
|
3
|
+
---
|
|
4
|
+
执行以下步骤:
|
|
5
|
+
|
|
6
|
+
1. 检查 hook 是否已安装:
|
|
7
|
+
```bash
|
|
8
|
+
ls -la .git/hooks/pre-push 2>/dev/null && echo "✅ 已安装" || echo "❌ 未安装"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
2. 如果用户说 `install` 或未安装:
|
|
12
|
+
```bash
|
|
13
|
+
ln -sf ~/atdc/hooks/guardrails.sh .git/hooks/pre-push && echo "✅ git-guardrails 已安装"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
3. 输出当前防护状态(参考 reference/git-guardrails.md 说明规则)
|
|
17
|
+
|
|
18
|
+
$ARGUMENTS
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "CLS MCP Client 配置文件。cls --init 自动生成,请按需修改。",
|
|
3
|
+
"skill_dir": "/Users/lvkun/Documents/Codes/agent-skills/cls-log-query",
|
|
4
|
+
"python": "python3",
|
|
5
|
+
"accounts": {
|
|
6
|
+
"tcs": { "account": "ticket", "project_id": "11559" }
|
|
7
|
+
},
|
|
8
|
+
"defaults": {
|
|
9
|
+
"limit": 200,
|
|
10
|
+
"out_dir": "~/.cls/logs",
|
|
11
|
+
"topic_type": "error",
|
|
12
|
+
"regions": "gz,bj",
|
|
13
|
+
"time_range": "15m"
|
|
14
|
+
},
|
|
15
|
+
"output": {
|
|
16
|
+
"format": "jsonl",
|
|
17
|
+
"filename": "{account}_{query}_{ts}-{suffix}.jsonl"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# atd-archive.sh — one-command archive automation
|
|
3
|
+
# Merges delta specs, moves change to archive, updates state.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# atd-archive.sh <change-name> archive
|
|
7
|
+
# atd-archive.sh --dry-run <change-name> preview only
|
|
8
|
+
|
|
9
|
+
set -e
|
|
10
|
+
|
|
11
|
+
DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
|
|
12
|
+
GUARD_SH="$DIR/phase-guard.sh"
|
|
13
|
+
STATE_SH="$DIR/atd-state.sh"
|
|
14
|
+
|
|
15
|
+
die() { echo "[HARD STOP] $*" >&2; exit 1; }
|
|
16
|
+
ok() { echo " ✓ $*"; }
|
|
17
|
+
|
|
18
|
+
_dry=false
|
|
19
|
+
_name=""
|
|
20
|
+
|
|
21
|
+
for arg in "$@"; do
|
|
22
|
+
case "$arg" in
|
|
23
|
+
--dry-run) _dry=true;;
|
|
24
|
+
*) _name="$arg";;
|
|
25
|
+
esac
|
|
26
|
+
done
|
|
27
|
+
|
|
28
|
+
[ -z "$_name" ] && die "Usage: atd-archive.sh [--dry-run] <change-name>"
|
|
29
|
+
|
|
30
|
+
_d="openspec/changes/$_name"
|
|
31
|
+
[ -d "$_d" ] || die "change directory not found: $_d"
|
|
32
|
+
|
|
33
|
+
# Step 1: guard check
|
|
34
|
+
echo "⚙ atd-archive: checking preconditions for $_name"
|
|
35
|
+
sh "$GUARD_SH" "$_name" archive || die "archive guard failed"
|
|
36
|
+
|
|
37
|
+
if $_dry; then
|
|
38
|
+
echo ""
|
|
39
|
+
echo "📋 DRY RUN — would archive: $_name"
|
|
40
|
+
echo " merge specs:"
|
|
41
|
+
for spec in "$_d"/specs/*/spec.md; do
|
|
42
|
+
[ -f "$spec" ] || continue
|
|
43
|
+
_module=$(basename "$(dirname "$spec")")
|
|
44
|
+
echo " $spec → openspec/specs/$_module/spec.md"
|
|
45
|
+
done
|
|
46
|
+
echo " move: $_d → openspec/changes/archive/$_name"
|
|
47
|
+
echo " state: archived = true"
|
|
48
|
+
exit 0
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Step 2: merge delta specs
|
|
52
|
+
echo ""
|
|
53
|
+
echo "📦 merging specs..."
|
|
54
|
+
for spec in "$_d"/specs/*/spec.md; do
|
|
55
|
+
[ -f "$spec" ] || continue
|
|
56
|
+
_module=$(basename "$(dirname "$spec")")
|
|
57
|
+
_target="openspec/specs/$_module/spec.md"
|
|
58
|
+
mkdir -p "$(dirname "$_target")"
|
|
59
|
+
if [ -f "$_target" ]; then
|
|
60
|
+
echo " appending: $_module/spec.md → $_target"
|
|
61
|
+
echo "" >> "$_target"
|
|
62
|
+
echo "<!-- merged from change $_name -->" >> "$_target"
|
|
63
|
+
cat "$spec" >> "$_target"
|
|
64
|
+
else
|
|
65
|
+
echo " creating: $_module/spec.md"
|
|
66
|
+
cp "$spec" "$_target"
|
|
67
|
+
fi
|
|
68
|
+
ok "merged $_module/spec.md"
|
|
69
|
+
done
|
|
70
|
+
|
|
71
|
+
# Step 3: update state (before move, while file is still accessible)
|
|
72
|
+
echo ""
|
|
73
|
+
echo "📝 updating state..."
|
|
74
|
+
sh "$STATE_SH" set "$_name" archived true
|
|
75
|
+
ok "archived = true"
|
|
76
|
+
|
|
77
|
+
# Step 4: move to archive
|
|
78
|
+
echo ""
|
|
79
|
+
echo "📁 moving to archive..."
|
|
80
|
+
_archive_dir="openspec/changes/archive"
|
|
81
|
+
mkdir -p "$_archive_dir"
|
|
82
|
+
mv "$_d" "$_archive_dir/$_name"
|
|
83
|
+
ok "moved to $_archive_dir/$_name"
|
|
84
|
+
|
|
85
|
+
echo ""
|
|
86
|
+
echo "✅ archive complete: $_name"
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# atd-state.sh — unified state management for .phase-state.json
|
|
3
|
+
# Usage: atd-state.sh <cmd> [args...]
|
|
4
|
+
# init <change-name> create .phase-state.json in openspec/changes/<name>/
|
|
5
|
+
# set <key> <value> update a field
|
|
6
|
+
# get <key> read a field
|
|
7
|
+
# check <phase> validate current phase legality
|
|
8
|
+
# transition <from> <to> execute phase transition with guard check
|
|
9
|
+
|
|
10
|
+
set -e
|
|
11
|
+
|
|
12
|
+
DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
|
|
13
|
+
EVIDENCE_LOG="$DIR/evidence-log.sh"
|
|
14
|
+
|
|
15
|
+
die() { echo "$@" >&2; exit 1; }
|
|
16
|
+
warn() { echo "$@" >&2; }
|
|
17
|
+
|
|
18
|
+
# JSON helper — prefer jq, fallback to node -e
|
|
19
|
+
_json_get() {
|
|
20
|
+
if command -v jq >/dev/null 2>&1; then
|
|
21
|
+
jq -r ".$2 // \"\"" "$1"
|
|
22
|
+
elif command -v node >/dev/null 2>&1; then
|
|
23
|
+
node -e "try{var d=require('$(cd "$(dirname "$1")" && pwd)/$(basename "$1")');console.log(d.$2||'')}catch(e){console.log('')}"
|
|
24
|
+
else
|
|
25
|
+
die "jq or node required for JSON operations"
|
|
26
|
+
fi
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_json_set() {
|
|
30
|
+
local file="$1" key="$2" value="$3"
|
|
31
|
+
if command -v jq >/dev/null 2>&1; then
|
|
32
|
+
jq ".$key = $value" "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
|
|
33
|
+
elif command -v node >/dev/null 2>&1; then
|
|
34
|
+
node -e "
|
|
35
|
+
var fs=require('fs');
|
|
36
|
+
var d=JSON.parse(fs.readFileSync('$file','utf8'));
|
|
37
|
+
d.$key = $value;
|
|
38
|
+
fs.writeFileSync('$file',JSON.stringify(d,null,2)+'\n');
|
|
39
|
+
"
|
|
40
|
+
else
|
|
41
|
+
die "jq or node required for JSON operations"
|
|
42
|
+
fi
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# Valid phase sequence: open -> design -> build -> verify -> archive
|
|
46
|
+
_valid_phases="open design build verify archive"
|
|
47
|
+
_phase_index() {
|
|
48
|
+
_i=0; for _p in $_valid_phases; do
|
|
49
|
+
[ "$_p" = "$1" ] && echo "$_i" && return 0
|
|
50
|
+
_i=$((_i + 1))
|
|
51
|
+
done
|
|
52
|
+
echo "-1"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Resolve change dir from current directory or explicit name
|
|
56
|
+
_find_change_dir() {
|
|
57
|
+
local name="$1"
|
|
58
|
+
[ -z "$name" ] && die "change name required"
|
|
59
|
+
local d="openspec/changes/$name"
|
|
60
|
+
[ -d "$d" ] || die "change directory not found: $d"
|
|
61
|
+
echo "$d"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
_state_file() {
|
|
65
|
+
echo "$(_find_change_dir "$1")/.phase-state.json"
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
cmd_init() {
|
|
69
|
+
local name="$1" mode="${2:-full}"
|
|
70
|
+
[ -z "$name" ] && die "Usage: atd-state.sh init <change-name> [mode]"
|
|
71
|
+
local d="openspec/changes/$name"
|
|
72
|
+
mkdir -p "$d"
|
|
73
|
+
local sf="$d/.phase-state.json"
|
|
74
|
+
local ts now
|
|
75
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || echo "")
|
|
76
|
+
cat > "$sf" <<EOF
|
|
77
|
+
{
|
|
78
|
+
"change": "$name",
|
|
79
|
+
"phase": "open",
|
|
80
|
+
"mode": "$mode",
|
|
81
|
+
"tasks": { "total": 0, "completed": 0 },
|
|
82
|
+
"verifiedAt": null,
|
|
83
|
+
"archived": false,
|
|
84
|
+
"verificationReport": null,
|
|
85
|
+
"branchStatus": "pending",
|
|
86
|
+
"startedAt": "$ts",
|
|
87
|
+
"updatedAt": "$ts"
|
|
88
|
+
}
|
|
89
|
+
EOF
|
|
90
|
+
echo "initialized $sf"
|
|
91
|
+
sh "$EVIDENCE_LOG" intake "$name" "$mode" 2>/dev/null || true
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
cmd_get() {
|
|
95
|
+
[ -z "$1" ] && die "Usage: atd-state.sh get <change-name> <key>"
|
|
96
|
+
local sf
|
|
97
|
+
sf=$(_state_file "$1")
|
|
98
|
+
[ -f "$sf" ] || die "state file not found: $sf"
|
|
99
|
+
shift
|
|
100
|
+
_json_get "$sf" "$1"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
cmd_set() {
|
|
104
|
+
[ -z "$1" ] && die "Usage: atd-state.sh set <change-name> <key> <value>"
|
|
105
|
+
local name="$1"; shift
|
|
106
|
+
local sf
|
|
107
|
+
sf=$(_state_file "$name")
|
|
108
|
+
[ -f "$sf" ] || die "state file not found: $sf"
|
|
109
|
+
local key="$1" value="$2"
|
|
110
|
+
# Auto-wrap non-JSON values in double quotes for jq compatibility
|
|
111
|
+
case "$value" in
|
|
112
|
+
\"*\"|true|false|null|{*|\[*) ;; # already valid JSON
|
|
113
|
+
*) value="\"$value\"" ;; # wrap string in quotes
|
|
114
|
+
esac
|
|
115
|
+
_json_set "$sf" "$key" "$value"
|
|
116
|
+
# update updatedAt
|
|
117
|
+
local ts
|
|
118
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || echo "")
|
|
119
|
+
_json_set "$sf" "updatedAt" "\"$ts\""
|
|
120
|
+
echo "ok"
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
cmd_check() {
|
|
124
|
+
[ -z "$1" ] && die "Usage: atd-state.sh check <change-name> <target-phase>"
|
|
125
|
+
local name="$1" target="$2"
|
|
126
|
+
local sf cur
|
|
127
|
+
sf=$(_state_file "$name")
|
|
128
|
+
[ -f "$sf" ] || die "state file not found: $sf"
|
|
129
|
+
cur=$(_json_get "$sf" "phase")
|
|
130
|
+
local ci ti
|
|
131
|
+
ci=$(_phase_index "$cur")
|
|
132
|
+
ti=$(_phase_index "$target")
|
|
133
|
+
[ "$ci" -lt 0 ] && die "invalid current phase: $cur"
|
|
134
|
+
[ "$ti" -lt 0 ] && die "invalid target phase: $target"
|
|
135
|
+
[ "$ti" -le "$ci" ] && die "cannot go backward: $cur -> $target"
|
|
136
|
+
[ $((ti - ci)) -gt 1 ] && die "cannot skip phases: $cur -> $target (must go through intermediate)"
|
|
137
|
+
echo "phase check ok: $cur -> $target"
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
cmd_transition() {
|
|
141
|
+
[ -z "$1" ] && die "Usage: atd-state.sh transition <change-name> <from> <to>"
|
|
142
|
+
local name="$1" from="$2" to="$3"
|
|
143
|
+
cmd_check "$name" "$to" || die "transition check failed"
|
|
144
|
+
local sf
|
|
145
|
+
sf=$(_state_file "$name")
|
|
146
|
+
local cur
|
|
147
|
+
cur=$(_json_get "$sf" "phase")
|
|
148
|
+
[ "$cur" = "$from" ] || die "current phase mismatch: expected $from, got $cur"
|
|
149
|
+
_json_set "$sf" "phase" "\"$to\""
|
|
150
|
+
local ts
|
|
151
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || echo "")
|
|
152
|
+
_json_set "$sf" "updatedAt" "\"$ts\""
|
|
153
|
+
[ "$to" = "verify" ] && _json_set "$sf" "verifiedAt" "\"$ts\""
|
|
154
|
+
echo "transitioned: $from -> $to"
|
|
155
|
+
sh "$EVIDENCE_LOG" phase "$name" "$from" "$to" 2>/dev/null || true
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
case "${1:-}" in
|
|
159
|
+
init) shift; cmd_init "$@";;
|
|
160
|
+
get) shift; cmd_get "$@";;
|
|
161
|
+
set) shift; cmd_set "$@";;
|
|
162
|
+
check) shift; cmd_check "$@";;
|
|
163
|
+
transition) shift; cmd_transition "$@";;
|
|
164
|
+
*) die "Usage: atd-state.sh {init|set|get|check|transition} ...";;
|
|
165
|
+
esac
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# evidence-hook.sh — PostToolUse hook for automatic evidence recording
|
|
3
|
+
# Detects writes to .phase-state.json / .progress.json and records events.
|
|
4
|
+
# No agent compliance needed — fires automatically on every tool use.
|
|
5
|
+
#
|
|
6
|
+
# Registered via: atdc hook install
|
|
7
|
+
# Detects events:
|
|
8
|
+
# - Write to .phase-state.json with phase change → phase_transition event
|
|
9
|
+
# - Write to .progress.json with new completed task → task_complete event
|
|
10
|
+
|
|
11
|
+
DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
|
|
12
|
+
EVIDENCE_LOG="$DIR/evidence-log.sh"
|
|
13
|
+
STATE_SH="$DIR/atd-state.sh"
|
|
14
|
+
|
|
15
|
+
_file="${1:-}"
|
|
16
|
+
[ -z "$_file" ] && exit 0
|
|
17
|
+
|
|
18
|
+
_file=$(echo "$_file" | sed 's|^\./||')
|
|
19
|
+
|
|
20
|
+
# Only care about state file writes
|
|
21
|
+
case "$_file" in
|
|
22
|
+
*/.phase-state.json)
|
|
23
|
+
;;
|
|
24
|
+
*/.progress.json)
|
|
25
|
+
;;
|
|
26
|
+
*)
|
|
27
|
+
exit 0
|
|
28
|
+
;;
|
|
29
|
+
esac
|
|
30
|
+
|
|
31
|
+
[ -f "$_file" ] || exit 0
|
|
32
|
+
|
|
33
|
+
_record_phase() {
|
|
34
|
+
local f="$1"
|
|
35
|
+
if ! command -v node >/dev/null 2>&1; then exit 0; fi
|
|
36
|
+
local change_dir
|
|
37
|
+
change_dir=$(dirname "$f")
|
|
38
|
+
local change_name
|
|
39
|
+
change_name=$(basename "$change_dir")
|
|
40
|
+
local phase mode
|
|
41
|
+
phase=$(python3 -c "import json; print(json.load(open('$f')).get('phase',''))" 2>/dev/null || node -e "console.log(JSON.parse(require('fs').readFileSync('$f','utf8')).phase||'')" 2>/dev/null)
|
|
42
|
+
mode=$(python3 -c "import json; print(json.load(open('$f')).get('mode','full'))" 2>/dev/null || node -e "console.log(JSON.parse(require('fs').readFileSync('$f','utf8')).mode||'full')" 2>/dev/null)
|
|
43
|
+
[ -z "$phase" ] && exit 0
|
|
44
|
+
|
|
45
|
+
local stamp="$change_dir/.evidence/.phase-stamp"
|
|
46
|
+
local prev=""
|
|
47
|
+
[ -f "$stamp" ] && prev=$(cat "$stamp")
|
|
48
|
+
|
|
49
|
+
if [ "$prev" != "$phase" ]; then
|
|
50
|
+
local from="${prev:-init}"
|
|
51
|
+
local to="$phase"
|
|
52
|
+
sh "$EVIDENCE_LOG" phase "$change_name" "$from" "$to" 2>/dev/null
|
|
53
|
+
mkdir -p "$(dirname "$stamp")"
|
|
54
|
+
echo "$phase" > "$stamp"
|
|
55
|
+
fi
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
_record_progress() {
|
|
59
|
+
local f="$1"
|
|
60
|
+
if ! command -v node >/dev/null 2>&1; then exit 0; fi
|
|
61
|
+
local change_dir change_name
|
|
62
|
+
change_dir=$(dirname "$f")
|
|
63
|
+
change_name=$(basename "$change_dir")
|
|
64
|
+
|
|
65
|
+
local status
|
|
66
|
+
status=$(python3 -c "import json; print(json.load(open('$f')).get('status',''))" 2>/dev/null || node -e "console.log(JSON.parse(require('fs').readFileSync('$f','utf8')).status||'')" 2>/dev/null)
|
|
67
|
+
|
|
68
|
+
local stamp="$change_dir/.evidence/.progress-stamp"
|
|
69
|
+
local prev=""
|
|
70
|
+
[ -f "$stamp" ] && prev=$(cat "$stamp")
|
|
71
|
+
|
|
72
|
+
if [ "$status" = "completed" ] && [ "$prev" != "completed" ]; then
|
|
73
|
+
sh "$EVIDENCE_LOG" done "$change_name" 2>/dev/null
|
|
74
|
+
mkdir -p "$(dirname "$stamp")"
|
|
75
|
+
echo "completed" > "$stamp"
|
|
76
|
+
fi
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
case "$_file" in
|
|
80
|
+
*/.phase-state.json)
|
|
81
|
+
_record_phase "$_file"
|
|
82
|
+
;;
|
|
83
|
+
*/.progress.json)
|
|
84
|
+
_record_progress "$_file"
|
|
85
|
+
;;
|
|
86
|
+
esac
|
|
87
|
+
|
|
88
|
+
exit 0
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# evidence-log.sh — record evidence events during phase transitions
|
|
3
|
+
# Usage:
|
|
4
|
+
# evidence-log.sh record <change-name> <event-type> [--phase=<p>] [--key=value...]
|
|
5
|
+
#
|
|
6
|
+
# Called automatically by atd-state.sh during transitions.
|
|
7
|
+
|
|
8
|
+
DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
|
|
9
|
+
ATD_BIN="$DIR/../bin/atdc.js"
|
|
10
|
+
|
|
11
|
+
_record() {
|
|
12
|
+
local change="$1" type="$2" phase="${3:-unknown}"
|
|
13
|
+
shift 3 2>/dev/null || true
|
|
14
|
+
|
|
15
|
+
local extra=""
|
|
16
|
+
for arg in "$@"; do
|
|
17
|
+
extra="$extra $arg"
|
|
18
|
+
done
|
|
19
|
+
|
|
20
|
+
if command -v node >/dev/null 2>&1; then
|
|
21
|
+
node "$ATD_BIN" evidence record "$change" "$type" "--phase=$phase" $extra 2>/dev/null || true
|
|
22
|
+
fi
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
_phase_event() {
|
|
26
|
+
local change="$1" from="$2" to="$3"
|
|
27
|
+
_record "$change" "phase_transition" "$to" "--from=$from" "--to=$to"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_intake_event() {
|
|
31
|
+
local change="$1" mode="$2"
|
|
32
|
+
_record "$change" "intake" "open" "--mode=$mode"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
_gate_event() {
|
|
36
|
+
local change="$1" gate="$2" result="$3"
|
|
37
|
+
_record "$change" "gate_check" "build" "--gate=$gate" "--result=$result"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
_done_event() {
|
|
41
|
+
local change="$1"
|
|
42
|
+
_record "$change" "done" "archive"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
case "${1:-}" in
|
|
46
|
+
phase) shift; _phase_event "$@";;
|
|
47
|
+
intake) shift; _intake_event "$@";;
|
|
48
|
+
gate) shift; _gate_event "$@";;
|
|
49
|
+
done) shift; _done_event "$@";;
|
|
50
|
+
record) shift; _record "$@";;
|
|
51
|
+
*)
|
|
52
|
+
echo "Usage: evidence-log.sh {phase|intake|gate|done|record} ..." >&2
|
|
53
|
+
;;
|
|
54
|
+
esac
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# atdc git guardrails — pre-push hook
|
|
3
|
+
# 拦截危险 git 命令,保护 main/master 分支
|
|
4
|
+
# 安装:ln -sf ~/atdc/hooks/guardrails.sh .git/hooks/pre-push
|
|
5
|
+
# 卸载:rm .git/hooks/pre-push
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
REMOTE="$1"
|
|
10
|
+
REMOTE_URL="$2"
|
|
11
|
+
|
|
12
|
+
# 当前分支
|
|
13
|
+
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
14
|
+
|
|
15
|
+
# 保护分支列表
|
|
16
|
+
PROTECTED_BRANCHES="main master"
|
|
17
|
+
|
|
18
|
+
# ── 检查是否推送到保护分支 ──
|
|
19
|
+
for branch in $PROTECTED_BRANCHES; do
|
|
20
|
+
if [ "$CURRENT_BRANCH" = "$branch" ]; then
|
|
21
|
+
echo "🔒 atdc guardrails: 禁止直接推送到 $branch 分支"
|
|
22
|
+
echo ""
|
|
23
|
+
echo " 请使用 PR/MR 方式合并代码。"
|
|
24
|
+
echo " 如果必须直推(紧急 hotfix),运行:"
|
|
25
|
+
echo " git push --no-verify"
|
|
26
|
+
echo ""
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
done
|
|
30
|
+
|
|
31
|
+
# ── 检查 WIP commit ──
|
|
32
|
+
while read local_ref local_sha remote_ref remote_sha; do
|
|
33
|
+
if [ "$local_sha" = "0000000000000000000000000000000000000000" ]; then
|
|
34
|
+
# 删除远程分支,允许
|
|
35
|
+
continue
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
if [ "$remote_sha" = "0000000000000000000000000000000000000000" ]; then
|
|
39
|
+
# 新分支首次推送,检查所有新 commit
|
|
40
|
+
WIP_COUNT=$(git log "$local_sha" --not --all --oneline 2>/dev/null | grep -ci "WIP" || true)
|
|
41
|
+
else
|
|
42
|
+
WIP_COUNT=$(git log "$remote_sha..$local_sha" --oneline 2>/dev/null | grep -ci "WIP" || true)
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
if [ "$WIP_COUNT" -gt 0 ]; then
|
|
46
|
+
echo "⚠️ atdc guardrails: 检测到 $WIP_COUNT 个 WIP commit"
|
|
47
|
+
echo ""
|
|
48
|
+
echo " 建议 squash 后再推送。"
|
|
49
|
+
echo " 继续推送:git push --no-verify"
|
|
50
|
+
echo ""
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
done
|
|
54
|
+
|
|
55
|
+
# ── CUSTOM RULES ──────────────────────────────────────────
|
|
56
|
+
# 在此处添加项目特定的检查规则
|
|
57
|
+
# 示例:
|
|
58
|
+
# if git log $remote_sha..$local_sha --oneline | grep -q "TODO"; then
|
|
59
|
+
# echo "❌ commit 中包含 TODO,请处理后再推送"
|
|
60
|
+
# exit 1
|
|
61
|
+
# fi
|
|
62
|
+
# ───────────────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
echo "✅ atdc guardrails: 检查通过"
|
|
65
|
+
exit 0
|