@dtt_siye/atool 1.3.1 → 1.5.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.
Files changed (56) hide show
  1. package/README.md +97 -214
  2. package/README.md.atool-backup.20260410_114701 +299 -0
  3. package/VERSION +1 -1
  4. package/bin/atool.js +55 -9
  5. package/hooks/doc-sync-reminder +4 -4
  6. package/hooks/hooks-cursor.json +20 -0
  7. package/hooks/hooks.json +21 -1
  8. package/hooks/pre-commit +191 -0
  9. package/hooks/prompt-guard +84 -35
  10. package/hooks/session-start +34 -12
  11. package/hooks/task-state-tracker +145 -0
  12. package/install.sh +14 -4
  13. package/lib/common.sh +36 -23
  14. package/lib/compute-importance.sh +73 -0
  15. package/lib/install-cursor.sh +24 -2
  16. package/lib/install-hooks.sh +64 -0
  17. package/lib/install-kiro.sh +26 -2
  18. package/lib/install-skills.sh +5 -2
  19. package/lib/pre-scan.sh +13 -1
  20. package/lib/project-init.sh +28 -9
  21. package/package.json +1 -1
  22. package/skills/agent-audit/SKILL.md +180 -0
  23. package/skills/ai-project-architecture/SKILL.md +33 -534
  24. package/skills/ai-project-architecture/rules/architecture-validation.md +200 -0
  25. package/skills/ai-project-architecture/rules/compliance-check.md +83 -0
  26. package/skills/ai-project-architecture/rules/iron-laws.md +188 -0
  27. package/skills/ai-project-architecture/rules/migration.md +94 -0
  28. package/skills/ai-project-architecture/rules/refactoring.md +91 -0
  29. package/skills/ai-project-architecture/rules/testing.md +249 -0
  30. package/skills/ai-project-architecture/rules/verification.md +111 -0
  31. package/skills/architecture-guard/SKILL.md +164 -0
  32. package/skills/architecture-guard/rules/violation-detection.md +90 -0
  33. package/skills/atool-init/SKILL.md +24 -4
  34. package/skills/ci-feedback/SKILL.md +165 -0
  35. package/skills/project-analyze/SKILL.md +129 -19
  36. package/skills/project-analyze/phases/phase1-setup.md +76 -5
  37. package/skills/project-analyze/phases/phase2-understand.md +137 -26
  38. package/skills/project-analyze/phases/phase2.5-refine.md +32 -23
  39. package/skills/project-analyze/phases/phase3-graph.md +39 -5
  40. package/skills/project-analyze/phases/phase4-synthesize.md +17 -1
  41. package/skills/project-analyze/phases/phase5-export.md +42 -4
  42. package/skills/project-analyze/prompts/understand-agent.md +156 -298
  43. package/skills/project-analyze/rules/java.md +69 -1
  44. package/skills/project-query/SKILL.md +91 -200
  45. package/skills/project-query/rules/aggregate-stats.md +301 -0
  46. package/skills/project-query/rules/data-lineage.md +228 -0
  47. package/skills/project-query/rules/impact-analysis.md +218 -0
  48. package/skills/project-query/rules/neighborhood.md +234 -0
  49. package/skills/project-query/rules/node-lookup.md +97 -0
  50. package/skills/project-query/rules/path-query.md +135 -0
  51. package/skills/software-architecture/SKILL.md +39 -501
  52. package/skills/software-architecture/rules/concurrency-ha.md +346 -0
  53. package/skills/software-architecture/rules/ddd.md +450 -0
  54. package/skills/software-architecture/rules/decision-workflow.md +155 -0
  55. package/skills/software-architecture/rules/deployment.md +508 -0
  56. package/skills/software-architecture/rules/styles.md +232 -0
package/bin/atool.js CHANGED
@@ -61,6 +61,14 @@ function findBashOnWindows() {
61
61
  function runInstallSh(args) {
62
62
  const argList = Array.isArray(args) ? args : [args];
63
63
 
64
+ // Prepare environment variables
65
+ const env = { ...process.env, ATOOL_ROOT: ROOT_DIR };
66
+
67
+ // Include ATOOL_STACK if set
68
+ if (env.ATOOL_STACK) {
69
+ env.ATOOL_STACK = env.ATOOL_STACK;
70
+ }
71
+
64
72
  if (isWindows()) {
65
73
  const bash = findBashOnWindows();
66
74
  if (!bash) {
@@ -74,14 +82,14 @@ function runInstallSh(args) {
74
82
  execFileSync(bash, [INSTALL_SH, ...argList], {
75
83
  stdio: 'inherit',
76
84
  cwd: ROOT_DIR,
77
- env: { ...process.env, ATOOL_ROOT: ROOT_DIR },
85
+ env: env,
78
86
  });
79
87
  } else {
80
88
  // macOS / Linux — delegate directly to bash
81
89
  execFileSync('bash', [INSTALL_SH, ...argList], {
82
90
  stdio: 'inherit',
83
91
  cwd: ROOT_DIR,
84
- env: { ...process.env, ATOOL_ROOT: ROOT_DIR },
92
+ env: env,
85
93
  });
86
94
  }
87
95
  }
@@ -145,6 +153,38 @@ function cmdInstall(flags) {
145
153
  runInstallSh(installArgs);
146
154
  }
147
155
 
156
+ function cmdInit(flags) {
157
+ const initArgs = ['--project'];
158
+
159
+ // Extract path argument (only if it's not the value after --stack)
160
+ let pathArg = null;
161
+ let stackValue = null;
162
+
163
+ // Find --stack and its value first
164
+ const stackIndex = flags.indexOf('--stack');
165
+ if (stackIndex !== -1 && stackIndex + 1 < flags.length && !flags[stackIndex + 1].startsWith('--')) {
166
+ stackValue = flags[stackIndex + 1];
167
+ // Remove --stack and its value from consideration for pathArg
168
+ const filteredFlags = flags.filter((flag, index) =>
169
+ index !== stackIndex && index !== stackIndex + 1
170
+ );
171
+ pathArg = filteredFlags.find(flag => !flag.startsWith('--'));
172
+ } else {
173
+ pathArg = flags.find(flag => !flag.startsWith('--'));
174
+ }
175
+
176
+ if (pathArg) {
177
+ initArgs.push(pathArg);
178
+ }
179
+
180
+ // Handle --stack flag
181
+ if (stackValue) {
182
+ process.env.ATOOL_STACK = stackValue;
183
+ }
184
+
185
+ runInstallSh(initArgs);
186
+ }
187
+
148
188
  function cmdUpdate(flags) {
149
189
  const updateArgs = ['--update'];
150
190
  if (hasFlag(flags, 'yes') || hasFlag(flags, 'y')) {
@@ -175,20 +215,22 @@ function cmdHelp() {
175
215
  console.log(`aTool - AI Developer Toolkit v${version}`);
176
216
  console.log('');
177
217
  console.log('Usage:');
178
- console.log(' atool install [--all] [--yes] [--claude] [--cursor] [--kiro]');
179
- console.log(' atool update [--yes]');
180
- console.log(' atool check-updates');
181
- console.log(' atool version');
182
- console.log(' atool help');
218
+ console.log(' atool [command] [options]');
183
219
  console.log('');
184
220
  console.log('Commands:');
185
221
  console.log(' install Install aTool to detected AI IDEs (default: --all)');
222
+ console.log(' init [PATH] Initialize a project in current or specified directory');
186
223
  console.log(' update Update aTool to the latest version');
187
224
  console.log(' check-updates Check installed version info (JSON output)');
188
225
  console.log(' version Show current version');
189
226
  console.log(' help Show this help message');
190
227
  console.log('');
191
- console.log('Options:');
228
+ console.log('Project Initialization:');
229
+ console.log(' atool init Initialize project in current directory');
230
+ console.log(' atool init ./my-app Initialize project in specified directory');
231
+ console.log(' atool init --stack react Initialize with specific tech stack');
232
+ console.log('');
233
+ console.log('Installation Options:');
192
234
  console.log(' --all Install to all detected IDEs');
193
235
  console.log(' --claude Install to Claude Code CLI only');
194
236
  console.log(' --cursor Install to Cursor only');
@@ -196,8 +238,9 @@ function cmdHelp() {
196
238
  console.log(' --yes, -y Skip confirmation prompts');
197
239
  console.log(' --dry-run Preview mode — no changes made');
198
240
  console.log(' --force Overwrite existing configs');
199
- console.log(' --project PATH Initialize a project');
241
+ console.log(' --project PATH Initialize a project (legacy alias for "atool init")');
200
242
  console.log(' --analyze PATH Prepare project for deep analysis');
243
+ console.log(' --stack STACK Specify tech stack (e.g., react, vue, java)');
201
244
  }
202
245
 
203
246
  // ── Main ─────────────────────────────────────────────────────────────────────
@@ -210,6 +253,9 @@ function main() {
210
253
  case 'i':
211
254
  cmdInstall(flags);
212
255
  break;
256
+ case 'init':
257
+ cmdInit(flags);
258
+ break;
213
259
  case 'update':
214
260
  case 'u':
215
261
  cmdUpdate(flags);
@@ -36,8 +36,8 @@ main() {
36
36
  FILE_PATH=$(printf '%s' "$INPUT" | grep -oE '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' 2>/dev/null | head -1 | sed 's/.*"file_path"[[:space:]]*:[[:space:]]*"//;s/"$//' || echo "")
37
37
  fi
38
38
 
39
- # Only respond to Write/Edit
40
- if [[ "$TOOL_NAME" != "Write" && "$TOOL_NAME" != "Edit" ]]; then
39
+ # Only respond to Write/Edit/MultiEdit
40
+ if [[ "$TOOL_NAME" != "Write" && "$TOOL_NAME" != "Edit" && "$TOOL_NAME" != "MultiEdit" ]]; then
41
41
  exit 0
42
42
  fi
43
43
 
@@ -120,9 +120,9 @@ main() {
120
120
  fi
121
121
  fi
122
122
 
123
- # If no stale doc detection available, always remind (conservative)
123
+ # If no stale doc detection available, exit silently (consistent with task-state-tracker fallback)
124
124
  if ! $_LIB_FOUND; then
125
- STALE=true
125
+ exit 0
126
126
  fi
127
127
 
128
128
  if ! $STALE; then
@@ -22,6 +22,17 @@
22
22
  ]
23
23
  }
24
24
  ],
25
+ "PreToolUse": [
26
+ {
27
+ "matcher": "Bash",
28
+ "hooks": [
29
+ {
30
+ "type": "command",
31
+ "command": "bash ~/.cursor/hooks/atool-pre-commit"
32
+ }
33
+ ]
34
+ }
35
+ ],
25
36
  "PostToolUse": [
26
37
  {
27
38
  "matcher": "Write|Edit",
@@ -31,6 +42,15 @@
31
42
  "command": "bash ~/.cursor/hooks/atool-doc-sync-reminder"
32
43
  }
33
44
  ]
45
+ },
46
+ {
47
+ "matcher": "Write|Edit",
48
+ "hooks": [
49
+ {
50
+ "type": "command",
51
+ "command": "bash ~/.cursor/hooks/atool-task-state-tracker"
52
+ }
53
+ ]
34
54
  }
35
55
  ]
36
56
  }
package/hooks/hooks.json CHANGED
@@ -22,15 +22,35 @@
22
22
  ]
23
23
  }
24
24
  ],
25
+ "PreToolUse": [
26
+ {
27
+ "matcher": "Bash",
28
+ "hooks": [
29
+ {
30
+ "type": "command",
31
+ "command": "bash ~/.claude/hooks/atool-pre-commit"
32
+ }
33
+ ]
34
+ }
35
+ ],
25
36
  "PostToolUse": [
26
37
  {
27
- "matcher": "Write|Edit",
38
+ "matcher": "Write|Edit|MultiEdit",
28
39
  "hooks": [
29
40
  {
30
41
  "type": "command",
31
42
  "command": "bash ~/.claude/hooks/atool-doc-sync-reminder"
32
43
  }
33
44
  ]
45
+ },
46
+ {
47
+ "matcher": "Write|Edit|MultiEdit",
48
+ "hooks": [
49
+ {
50
+ "type": "command",
51
+ "command": "bash ~/.claude/hooks/atool-task-state-tracker"
52
+ }
53
+ ]
34
54
  }
35
55
  ]
36
56
  }
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env bash
2
+ # aTool - hooks/pre-commit
3
+ # PreToolUse hook: enforces quality standards before git commit
4
+ # Checks: TODO/FIXME leftovers, sensitive files, conventional commits, large files
5
+
6
+ set -euo pipefail
7
+
8
+ # Detect which IDE is running this hook
9
+ HOOK_IDE="claude"
10
+ if [[ -n "${CURSOR_PLUGIN_ROOT:-}" ]]; then
11
+ HOOK_IDE="cursor"
12
+ fi
13
+
14
+ # Escape string for JSON embedding
15
+ escape_for_json() {
16
+ local s="$1"
17
+ s="${s//\\/\\\\}"
18
+ s="${s//\"/\\\"}"
19
+ s="${s//$'\n'/\\n}"
20
+ s="${s//$'\r'/\\r}"
21
+ s="${s//$'\t'/\\t}"
22
+ printf '%s' "$s"
23
+ }
24
+
25
+ # Read JSON from stdin (Claude Code provides tool input on stdin)
26
+ INPUT=""
27
+ if [[ ! -t 0 ]]; then
28
+ INPUT=$(cat)
29
+ fi
30
+
31
+ # Extract tool_name and command from tool input
32
+ TOOL_NAME=""
33
+ TOOL_INPUT=""
34
+ if command -v jq &>/dev/null && [[ -n "$INPUT" ]]; then
35
+ TOOL_NAME=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null || echo "")
36
+ TOOL_INPUT=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null || echo "")
37
+ fi
38
+
39
+ # Only intercept git commit commands
40
+ if [[ "$TOOL_NAME" != "Bash" ]]; then
41
+ exit 0
42
+ fi
43
+ if [[ -z "$TOOL_INPUT" ]]; then
44
+ exit 0
45
+ fi
46
+
47
+ # Check if this is a git commit command
48
+ TOOL_INPUT_LOWER=$(printf '%s' "$TOOL_INPUT" | tr '[:upper:]' '[:lower:]')
49
+ IS_GIT_COMMIT=false
50
+ if printf '%s' "$TOOL_INPUT_LOWER" | grep -qE 'git\s+commit'; then
51
+ IS_GIT_COMMIT=true
52
+ fi
53
+
54
+ if ! $IS_GIT_COMMIT; then
55
+ exit 0
56
+ fi
57
+
58
+ # ── Pre-commit checks ─────────────────────────────────────────────────────
59
+
60
+ WARNINGS=""
61
+ CHECKS_FAILED=0
62
+ PROJECT_DIR="${PWD:-}"
63
+
64
+ # 1. Check for TODO/FIXME in staged files (AI "lazy" patterns)
65
+ TODO_COUNT=0
66
+ if command -v git &>/dev/null && git rev-parse --is-inside-work-tree &>/dev/null; then
67
+ STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null || echo "")
68
+ if [[ -n "$STAGED_FILES" ]]; then
69
+ for file in $STAGED_FILES; do
70
+ if [[ -f "$PROJECT_DIR/$file" ]]; then
71
+ local_count=$(grep -cE '(TODO|FIXME|HACK|XXX)' "$PROJECT_DIR/$file" 2>/dev/null || echo "0")
72
+ if [[ "$local_count" -gt 0 ]]; then
73
+ TODO_COUNT=$((TODO_COUNT + local_count))
74
+ fi
75
+ fi
76
+ done
77
+ fi
78
+ fi
79
+
80
+ if [[ "$TODO_COUNT" -gt 0 ]]; then
81
+ WARNINGS+="- Found ${TODO_COUNT} TODO/FIXME/HACK/XXX marker(s) in staged files. Consider resolving before commit.\n"
82
+ CHECKS_FAILED=$((CHECKS_FAILED + 1))
83
+ fi
84
+
85
+ # 2. Check for sensitive files in staged changes
86
+ SENSITIVE_PATTERNS="(\.env$|\.env\.|credentials|\.pem$|\.key$|secret|\.p12$|\.pfx$|id_rsa|id_ed25519|\.npmrc$|\.pypirc$)"
87
+ SENSITIVE_FOUND=""
88
+ if command -v git &>/dev/null && git rev-parse --is-inside-work-tree &>/dev/null; then
89
+ if [[ -n "${STAGED_FILES:-}" ]]; then
90
+ for file in $STAGED_FILES; do
91
+ if printf '%s' "$file" | grep -qE "$SENSITIVE_PATTERNS" 2>/dev/null; then
92
+ if [[ -z "$SENSITIVE_FOUND" ]]; then
93
+ SENSITIVE_FOUND="$file"
94
+ else
95
+ SENSITIVE_FOUND="$SENSITIVE_FOUND, $file"
96
+ fi
97
+ fi
98
+ done
99
+ fi
100
+ fi
101
+
102
+ if [[ -n "$SENSITIVE_FOUND" ]]; then
103
+ WARNINGS+="- BLOCKED: Sensitive file(s) detected in commit: ${SENSITIVE_FOUND}. Do NOT commit secrets.\n"
104
+ CHECKS_FAILED=$((CHECKS_FAILED + 10)) # High severity
105
+ fi
106
+
107
+ # 3. Check conventional commit message format
108
+ # Note: PreToolUse hook runs BEFORE commit happens, so we can only extract from command line.
109
+ # However, commit message extraction from bash command is unreliable for heredoc format.
110
+ # This check is best-effort only. Use PostToolUse hook for reliable validation after commit.
111
+ COMMIT_MSG=""
112
+ if printf '%s' "$TOOL_INPUT" | grep -qE '\-m'; then
113
+ # Try to extract message after -m flag (only works for simple quoted messages)
114
+ COMMIT_MSG=$(printf '%s' "$TOOL_INPUT" | sed -n 's/.*-m[[:space:]]*\(['"'"'"][^'"'"'"]*['"'"'"]\|"[^"]*"\|\S\+\).*/\1/p' 2>/dev/null | head -1 || echo "")
115
+ # Strip surrounding quotes
116
+ COMMIT_MSG="${COMMIT_MSG#\"}"
117
+ COMMIT_MSG="${COMMIT_MSG%\"}"
118
+ COMMIT_MSG="${COMMIT_MSG#\'}"
119
+ COMMIT_MSG="${COMMIT_MSG%\'}"
120
+ fi
121
+
122
+ # Only warn if message extraction succeeded AND it doesn't match pattern
123
+ # (If extraction fails, skip validation — will be checked post-commit by PostToolUse hook)
124
+ if [[ -n "$COMMIT_MSG" ]] && [[ ! "$COMMIT_MSG" =~ \$\(cat ]]; then
125
+ CONVENTIONAL_PATTERN='^(feat|fix|docs|test|refactor|chore|style|perf|build|ci|revert|release)(\(.+\))?:'
126
+ if ! printf '%s' "$COMMIT_MSG" | grep -qE "$CONVENTIONAL_PATTERN" 2>/dev/null; then
127
+ WARNINGS+="- Commit message does not follow Conventional Commits: '${COMMIT_MSG}'\n"
128
+ WARNINGS+=" Expected: feat|fix|docs|test|refactor|chore|style|perf|build|ci|revert|release[(scope)]: description\n"
129
+ # This is a warning, not a hard block
130
+ fi
131
+ else
132
+ # If commit message extraction failed or detected heredoc, add note about post-validation
133
+ if printf '%s' "$TOOL_INPUT" | grep -qE '\-m.*\$\(cat'; then
134
+ WARNINGS+="- INFO: Using heredoc commit message format. Conventional Commits validation will be performed post-commit.\n"
135
+ fi
136
+ fi
137
+
138
+ # 4. Check for large files (> 1MB) in staged changes
139
+ LARGE_FILES=""
140
+ if command -v git &>/dev/null && git rev-parse --is-inside-work-tree &>/dev/null; then
141
+ if [[ -n "${STAGED_FILES:-}" ]]; then
142
+ for file in $STAGED_FILES; do
143
+ if [[ -f "$PROJECT_DIR/$file" ]]; then
144
+ file_size=$(wc -c < "$PROJECT_DIR/$file" 2>/dev/null || echo "0")
145
+ # 1MB = 1048576 bytes
146
+ if [[ "$file_size" -gt 1048576 ]]; then
147
+ size_mb=$((file_size / 1048576))
148
+ if [[ -z "$LARGE_FILES" ]]; then
149
+ LARGE_FILES="$file (${size_mb}MB)"
150
+ else
151
+ LARGE_FILES="$LARGE_FILES, $file (${size_mb}MB)"
152
+ fi
153
+ fi
154
+ fi
155
+ done
156
+ fi
157
+ fi
158
+
159
+ if [[ -n "$LARGE_FILES" ]]; then
160
+ WARNINGS+="- WARNING: Large file(s) in commit: ${LARGE_FILES}. Consider using .gitattributes or Git LFS.\n"
161
+ fi
162
+
163
+ # ── Output ────────────────────────────────────────────────────────────────
164
+
165
+ if [[ "$CHECKS_FAILED" -gt 0 ]] || [[ -n "$WARNINGS" ]]; then
166
+ SEVERITY="WARNING"
167
+ if [[ "$CHECKS_FAILED" -ge 10 ]]; then
168
+ SEVERITY="BLOCKED"
169
+ fi
170
+
171
+ _MSG="<ATOOL-PRE-COMMIT-CHECK>\n"
172
+ _MSG+="${SEVERITY}: Pre-commit quality checks found issues:\n\n"
173
+ _MSG+="$WARNINGS"
174
+ _MSG+="\n"
175
+
176
+ if [[ "$SEVERITY" == "BLOCKED" ]]; then
177
+ _MSG+="**This commit is BLOCKED.** Fix the critical issues above before proceeding.\n"
178
+ else
179
+ _MSG+="Please review the warnings above. You may proceed if they are acceptable, but consider addressing them.\n"
180
+ fi
181
+ _MSG+="</ATOOL-PRE-COMMIT-CHECK>"
182
+
183
+ if [[ "$HOOK_IDE" == "cursor" ]]; then
184
+ _ESCAPED=$(escape_for_json "$_MSG")
185
+ printf '{\n "hookSpecificOutput": {\n "hookEventName": "PreToolUse",\n "additionalContext": "%s"\n }\n}\n' "$_ESCAPED"
186
+ else
187
+ printf '%b' "$_MSG"
188
+ fi
189
+ fi
190
+
191
+ exit 0
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
  # aTool - hooks/prompt-guard
3
- # Lightweight UserPromptSubmit hook: reminds AI to clarify before implementing
4
- # Skips short/trivial prompts, triggers on substantial implementation requests
3
+ # UserPromptSubmit hook: reminds AI to clarify before implementing
4
+ # v2: Tightened skip conditions, structured template injection for Tier 2+
5
5
 
6
6
  set -euo pipefail
7
7
 
@@ -57,45 +57,41 @@ if printf '%s' "$PROMPT" | LC_ALL=C grep -q '[一-龥]' 2>/dev/null; then
57
57
  HAS_CJK=true
58
58
  fi
59
59
 
60
- # 1. Short messages
61
- if $HAS_CJK && [[ "$PROMPT_LEN" -lt 8 ]]; then
60
+ # 1. Short messages — TIGHTENED: lower thresholds
61
+ # Old: CJK < 8, Latin < 20
62
+ # New: CJK < 6, Latin < 15 (pure short replies like "ok", "好")
63
+ if $HAS_CJK && [[ "$PROMPT_LEN" -lt 6 ]]; then
62
64
  exit 0
63
- elif ! $HAS_CJK && [[ "$PROMPT_LEN" -lt 20 ]]; then
65
+ elif ! $HAS_CJK && [[ "$PROMPT_LEN" -lt 15 ]]; then
64
66
  exit 0
65
67
  fi
66
68
 
67
- # 2. Follow-up replies (affirmative, no new intent)
68
- FOLLOW_UP_PATTERNS="^(yes|ok|okay|好的|继续|继续做|go ahead|sure|yep|yeah|pls|please|go on|继续吧|对|嗯|是的|行|可以)$"
69
- if printf '%s' "$PROMPT_LOWER" | grep -qE "$FOLLOW_UP_PATTERNS" 2>/dev/null; then
69
+ # 2. Pure confirmations only TIGHTENED: strict single-word matches
70
+ # Old: included multi-word phrases like "go ahead", "pls", "please"
71
+ # New: only exact single-word affirmative replies
72
+ PURE_CONFIRMATIONS="^(yes|ok|okay|好的|继续|对|嗯|是的|行|可以|sure|yep|yeah|done|go|next)$"
73
+ if printf '%s' "$PROMPT_LOWER" | grep -qE "$PURE_CONFIRMATIONS" 2>/dev/null; then
70
74
  exit 0
71
75
  fi
72
76
 
73
- # 3. User asking a question (ends with ? or ?)
74
- if printf '%s' "$PROMPT" | grep -qE '[??]$' 2>/dev/null; then
75
- exit 0
76
- fi
77
-
78
- # 4. Meta-commands (non-implementation requests)
79
- # Note: Ambiguous words like "build", "test", "deploy" are NOT listed here
80
- # because they could be feature requests (e.g., "build a dashboard")
81
- META_COMMANDS="^(commit|git |run |npm |yarn |pnpm |bun |cargo |go run|python |pytest|jest|vitest|explain|diff |show |list |check |lint |format |log |tail |grep |find |cat |head )"
82
- if printf '%s' "$PROMPT_LOWER" | grep -qE "$META_COMMANDS" 2>/dev/null; then
83
- exit 0
84
- fi
85
-
86
- # 5. Exit signals (user wants to skip clarification)
77
+ # 3. Exit signals (user explicitly wants to skip clarification) — KEPT as-is
87
78
  EXIT_SIGNALS="(别问了|不要问|别再问|直接做|直接实现|直接开始|不用确认|跳过提问|不要确认|just do it|stop asking|no questions|don.t ask|skip asking|go ahead and implement)"
88
79
  if printf '%s' "$PROMPT_LOWER" | grep -qE "$EXIT_SIGNALS" 2>/dev/null; then
89
80
  exit 0
90
81
  fi
91
82
 
92
- # ── Trigger conditions ───────────────────────────────────────────────────
83
+ # ── REMOVED: Old skip conditions that were too broad ───────────────────────
84
+ # OLD: "Questions ending with ?" → REMOVED (questions like "能帮我实现一个搜索功能吗?" should trigger)
85
+ # OLD: "Meta-commands (commit, run, npm, explain...)" → REMOVED
86
+ # ("build a dashboard" starts with "build" but is a feature request)
87
+ # ("run the migration to add new user fields" is an implementation request)
88
+
89
+ # ── Classify task complexity ──────────────────────────────────────────────
93
90
 
94
91
  # Count words: for CJK text (no spaces), count CJK chars as words;
95
92
  # for Latin text, count whitespace-separated tokens
96
93
  WORD_COUNT=0
97
94
  if $HAS_CJK; then
98
- # CJK: count CJK characters (use LC_ALL=C for locale safety)
99
95
  CJK_COUNT=$(printf '%s' "$PROMPT" | LC_ALL=C grep -o '[一-龥]' 2>/dev/null | wc -l | tr -d '[:space:]')
100
96
  WORD_COUNT=$((CJK_COUNT))
101
97
  else
@@ -104,25 +100,78 @@ else
104
100
  done
105
101
  fi
106
102
 
107
- # Trigger: sufficient length + enough words/CJK chars + implementation keyword
108
- IMPLEMENT_KEYWORDS="(开发|创建|新增|实现|添加|加个|做一个|写一个|build|create|add|implement|make|develop|design|feature|refactor|extract|integrate|support|handle)"
103
+ # Detect implementation intent keywords
104
+ # Extended with common natural language patterns (CJK + English)
105
+ IMPLEMENT_KEYWORDS="(开发|创建|新增|实现|添加|加个|做一个|写一个|重构|优化|修改|调整|修复|集成|迁移|设计|拆分|改造|搭建|编写|扩展|帮我|需要|能不能|可以|请|麻烦|给我|加上|看看|想要|build|create|add|implement|make|develop|design|feature|refactor|extract|integrate|support|handle|fix|migrate|modify|update|change|enhance|improve|help.me|show.me|please|create.a|build.a|write.a|let.me|could.you|can.you)"
106
+
107
+ HAS_IMPLEMENT=false
109
108
  LENGTH_OK=false
110
- if $HAS_CJK && [[ "$PROMPT_LEN" -ge 8 ]]; then
109
+
110
+ if $HAS_CJK && [[ "$PROMPT_LEN" -ge 6 ]]; then
111
111
  LENGTH_OK=true
112
- elif ! $HAS_CJK && [[ "$PROMPT_LEN" -ge 20 ]]; then
112
+ elif ! $HAS_CJK && [[ "$PROMPT_LEN" -ge 15 ]]; then
113
113
  LENGTH_OK=true
114
114
  fi
115
115
 
116
- if $LENGTH_OK && [[ "$WORD_COUNT" -gt 5 ]] && \
117
- printf '%s' "$PROMPT_LOWER" | grep -qE "$IMPLEMENT_KEYWORDS" 2>/dev/null; then
118
- _REMINDER='<system-reminder>
116
+ if printf '%s' "$PROMPT_LOWER" | grep -qE "$IMPLEMENT_KEYWORDS" 2>/dev/null; then
117
+ HAS_IMPLEMENT=true
118
+ fi
119
+
120
+ # ── Determine tier and output ─────────────────────────────────────────────
121
+
122
+ if $LENGTH_OK && $HAS_IMPLEMENT && [[ "$WORD_COUNT" -gt 3 ]]; then
123
+ # Determine complexity tier
124
+ TIER=0
125
+
126
+ # Tier 3 indicators: architecture-level, multi-module, system-wide
127
+ TIER3_KEYWORDS="(架构|系统|整体|全面|重新设计|从零|微服务|拆分|architecture|system.redesign|from scratch|microservice|monolith|break down|overhaul)"
128
+ # Tier 2 indicators: new feature, multi-step, unclear scope
129
+ TIER2_KEYWORDS="(功能|模块|页面|组件|接口|服务|支持|feature|module|page|component|endpoint|service|support|workflow|pipeline|dashboard|integration)"
130
+
131
+ if printf '%s' "$PROMPT_LOWER" | grep -qE "$TIER3_KEYWORDS" 2>/dev/null; then
132
+ TIER=3
133
+ elif printf '%s' "$PROMPT_LOWER" | grep -qE "$TIER2_KEYWORDS" 2>/dev/null; then
134
+ TIER=2
135
+ else
136
+ TIER=1
137
+ fi
138
+
139
+ # Fallback tier escalation: if message has pronouns + concrete request context, bump tier
140
+ # This catches natural language requests without explicit keywords
141
+ if [[ "$TIER" -eq 1 ]] && [[ "$PROMPT_LEN" -gt 30 ]]; then
142
+ if printf '%s' "$PROMPT_LOWER" | grep -qE "(我|my|我们|our|帮|help|想|want|需要|need|能|can|可以|able)" 2>/dev/null; then
143
+ # Check if there are specific code/file references (suggests implementation request)
144
+ if printf '%s' "$PROMPT" | grep -qE "(\\.\\w+|/\\w+|\\{\\w+\\}|function|class|method|endpoint)" 2>/dev/null; then
145
+ TIER=2
146
+ fi
147
+ fi
148
+ fi
149
+
150
+ # Build tier-appropriate reminder
151
+ if [[ "$TIER" -ge 2 ]]; then
152
+ # Tier 2+: Structured template — require analysis before implementation
153
+ _REMINDER="<system-reminder>
154
+ **TIER ${TIER} TASK DETECTED** — This is a ${TIER}-level task. Before writing ANY code:
155
+
156
+ 1. **Analyze** — Read relevant source files first (CLAUDE.md, package.json, existing patterns)
157
+ 2. **Classify** — Confirm complexity: Tier ${TIER} = $([ "$TIER" -eq 2 ] && echo "3-5 clarification questions" || echo "delegate to /brainstorming")
158
+ 3. **Clarify** — Ask context-aware questions about: $([ "$TIER" -eq 2 ] && echo "scope, edge cases, existing patterns, acceptance criteria" || echo "architecture, constraints, trade-offs, migration strategy")
159
+ 4. **Plan** — Write implementation plan BEFORE touching code
160
+
161
+ Do NOT jump to implementation. Read first, ask second, plan third, code last.
162
+ See /clarify-before-build for full methodology.
163
+ </system-reminder>"
164
+ else
165
+ # Tier 1: Lightweight reminder
166
+ _REMINDER='<system-reminder>
119
167
  Before implementing, classify task complexity and clarify requirements if needed:
120
- - Tier 0 (direct): single-value change just do it
121
- - Tier 1 (1-2 questions): small change with ambiguity ask key questions
122
- - Tier 2 (3-5 questions): new feature read project files first, then ask context-aware questions
123
- - Tier 3: architecture-level delegate to /brainstorming
168
+ - Tier 0 (direct): single-value change, typo, format fix -> just do it
169
+ - Tier 1 (1-2 questions): small change with ambiguity -> ask key questions
170
+ - Tier 2 (3-5 questions): new feature, medium complexity -> structured clarification
171
+ - Tier 3: architecture-level, vague requirements -> delegate to /brainstorming
124
172
  See /clarify-before-build for full methodology.
125
173
  </system-reminder>'
174
+ fi
126
175
 
127
176
  if [[ "$HOOK_IDE" == "cursor" ]]; then
128
177
  _ESCAPED=$(escape_for_json "$_REMINDER")
@@ -245,26 +245,48 @@ if [[ -n "$DOC_SYNC" ]]; then
245
245
  INJECTION+=$'\n\n'
246
246
  fi
247
247
 
248
- INJECTION+="<ATOOL-CLARIFY-RULE>"
249
- INJECTION+=$'\n'
250
- INJECTION+="Before implementing ANY feature, first classify task complexity:"
251
- INJECTION+=$'\n'
252
- INJECTION+="Tier 0 (direct): single-value change, typo, format fix -> just do it"
248
+ # Only inject clarify rule if in a code project (detected by presence of common project files)
249
+ if [[ -f "package.json" || -f "pom.xml" || -f "go.mod" || -f "Cargo.toml" || -f "requirements.txt" || -f "build.gradle" || -f ".gradle" || -f "setup.py" || -f "Gemfile" ]]; then
250
+ INJECTION+="<ATOOL-CLARIFY-RULE>"
251
+ INJECTION+=$'\n'
252
+ INJECTION+="Before implementing ANY feature, first classify task complexity:"
253
+ INJECTION+=$'\n'
254
+ INJECTION+="Tier 0 (direct): single-value change, typo, format fix -> just do it"
255
+ INJECTION+=$'\n'
256
+ INJECTION+="Tier 1 (1-2 questions): small change with ambiguity -> ask key questions"
257
+ INJECTION+=$'\n'
258
+ INJECTION+="Tier 2 (3-5 questions): new feature, medium complexity -> structured clarification"
259
+ INJECTION+=$'\n'
260
+ INJECTION+="Tier 3: architecture-level, vague requirements -> delegate to /brainstorming"
261
+ INJECTION+=$'\n'
262
+ INJECTION+="Rules: Read project files BEFORE asking (CLAUDE.md, package.json, source code). Never assume installed libs or existing patterns. Ask context-aware questions, not obvious ones."
263
+ INJECTION+=$'\n'
264
+ INJECTION+="Exit: If user says '别问了'/'直接做'/'just do it'/'stop asking' -> skip all questions, Tier 0."
265
+ INJECTION+=$'\n'
266
+ INJECTION+="See /clarify-before-build for full methodology."
267
+ INJECTION+=$'\n'
268
+ INJECTION+="</ATOOL-CLARIFY-RULE>"
269
+ INJECTION+=$'\n'
270
+ fi
271
+
272
+ # Inject language rule (always, for all projects)
273
+ INJECTION+="<ATOOL-LANGUAGE-RULE>"
253
274
  INJECTION+=$'\n'
254
- INJECTION+="Tier 1 (1-2 questions): small change with ambiguity -> ask key questions"
275
+ INJECTION+="语言要求 (Language Requirement):"
255
276
  INJECTION+=$'\n'
256
- INJECTION+="Tier 2 (3-5 questions): new feature, medium complexity -> structured clarification"
277
+ INJECTION+="- 项目文档 (docs/, README, 架构指南): 必须中文"
257
278
  INJECTION+=$'\n'
258
- INJECTION+="Tier 3: architecture-level, vague requirements -> delegate to /brainstorming"
279
+ INJECTION+="- SKILL.md: 保持英文(AI 指令文件)"
259
280
  INJECTION+=$'\n'
260
- INJECTION+="Rules: Read project files BEFORE asking (CLAUDE.md, package.json, source code). Never assume installed libs or existing patterns. Ask context-aware questions, not obvious ones."
281
+ INJECTION+="- Commit message: 推荐中文"
261
282
  INJECTION+=$'\n'
262
- INJECTION+="Exit: If user says '别问了'/'直接做'/'just do it'/'stop asking' -> skip all questions, Tier 0."
283
+ INJECTION+="- 代码注释: 可中文或英文(跟随代码风格)"
263
284
  INJECTION+=$'\n'
264
- INJECTION+="See /clarify-before-build for full methodology."
285
+ INJECTION+="如果误用英文写项目文档,请用 /doc-coauthoring 重写为中文。"
265
286
  INJECTION+=$'\n'
266
- INJECTION+="</ATOOL-CLARIFY-RULE>"
287
+ INJECTION+="</ATOOL-LANGUAGE-RULE>"
267
288
  INJECTION+=$'\n'
289
+
268
290
  INJECTION+="</ATOOL-SESSION>"
269
291
  INJECTION+=$'\n'
270
292
  INJECTION+="</EXTREMELY_IMPORTANT>"