dw-kit 1.2.1 → 1.3.4
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/.claude/hooks/post-write.sh +64 -58
- package/.claude/hooks/pre-commit-gate.sh +96 -90
- package/.claude/hooks/privacy-block.sh +99 -94
- package/.claude/hooks/progress-ping.sh +53 -47
- package/.claude/hooks/safety-guard.sh +60 -54
- package/.claude/hooks/scout-block.sh +88 -82
- package/.claude/hooks/session-init.sh +6 -0
- package/.claude/hooks/stop-check.sh +88 -36
- package/.claude/hooks/telemetry-log.sh +34 -0
- package/.claude/rules/dw.md +138 -0
- package/.claude/settings.json +28 -1
- package/.claude/skills/dw-arch-review/SKILL.md +119 -119
- package/.claude/skills/dw-archive/SKILL.md +81 -81
- package/.claude/skills/dw-commit/SKILL.md +81 -81
- package/.claude/skills/dw-config-init/SKILL.md +91 -91
- package/.claude/skills/dw-config-validate/SKILL.md +75 -75
- package/.claude/skills/dw-dashboard/SKILL.md +209 -209
- package/.claude/skills/dw-debug/SKILL.md +97 -97
- package/.claude/skills/dw-decision/SKILL.md +116 -0
- package/.claude/skills/dw-docs-update/SKILL.md +125 -125
- package/.claude/skills/dw-estimate/SKILL.md +90 -90
- package/.claude/skills/dw-execute/SKILL.md +121 -98
- package/.claude/skills/dw-flow/SKILL.md +274 -274
- package/.claude/skills/dw-handoff/SKILL.md +92 -81
- package/.claude/skills/dw-kit-report/SKILL.md +152 -152
- package/.claude/skills/dw-log-work/SKILL.md +69 -69
- package/.claude/skills/dw-onboard/SKILL.md +201 -201
- package/.claude/skills/dw-plan/SKILL.md +222 -125
- package/.claude/skills/dw-prompt/SKILL.md +62 -62
- package/.claude/skills/dw-requirements/SKILL.md +98 -98
- package/.claude/skills/dw-research/SKILL.md +128 -114
- package/.claude/skills/dw-retroactive/SKILL.md +195 -311
- package/.claude/skills/dw-review/SKILL.md +66 -66
- package/.claude/skills/dw-rollback/SKILL.md +90 -90
- package/.claude/skills/dw-sprint-review/SKILL.md +99 -99
- package/.claude/skills/dw-task-init/SKILL.md +71 -59
- package/.claude/skills/dw-test-plan/SKILL.md +113 -113
- package/.claude/skills/dw-thinking/SKILL.md +70 -70
- package/.claude/skills/dw-upgrade/SKILL.md +72 -72
- package/.dw/core/PILLARS.md +122 -0
- package/.dw/core/ROLES.md +257 -257
- package/.dw/core/templates/v2/spec.md +68 -0
- package/.dw/core/templates/v2/tracking.md +62 -0
- package/.dw/core/v14-evaluation-protocol.md +118 -0
- package/CLAUDE.md +42 -39
- package/MIGRATION-v1.3.md +202 -0
- package/README.md +35 -6
- package/package.json +4 -2
- package/src/cli.mjs +29 -1
- package/src/commands/dashboard.mjs +116 -0
- package/src/commands/doctor.mjs +165 -149
- package/src/commands/init.mjs +339 -332
- package/src/commands/metrics.mjs +185 -0
- package/src/lib/active-index.mjs +87 -0
- package/src/lib/cut-analysis.mjs +240 -0
- package/src/lib/telemetry.mjs +80 -0
- package/.claude/rules/dw-core.md +0 -100
- package/.claude/rules/dw-skills.md +0 -53
- package/.claude/rules/workflow-rules.md +0 -77
|
@@ -1,58 +1,64 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# .claude/hooks/post-write.sh
|
|
3
|
-
# Chạy lint trên file vừa được Write/Edit — non-blocking.
|
|
4
|
-
# Được gọi bởi PostToolUse hook sau Write và Edit.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
fi
|
|
57
|
-
|
|
58
|
-
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# .claude/hooks/post-write.sh
|
|
3
|
+
# Chạy lint trên file vừa được Write/Edit — non-blocking.
|
|
4
|
+
# Được gọi bởi PostToolUse hook sau Write và Edit.
|
|
5
|
+
|
|
6
|
+
# Telemetry (local, fire-and-forget)
|
|
7
|
+
TELEMETRY_SCRIPT="${CLAUDE_PROJECT_DIR:-$(pwd)}/.claude/hooks/telemetry-log.sh"
|
|
8
|
+
if [ -x "$TELEMETRY_SCRIPT" ] && [ "${DW_NO_TELEMETRY:-}" != "1" ]; then
|
|
9
|
+
"$TELEMETRY_SCRIPT" hook post-write >/dev/null 2>&1 || true
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
INPUT=$(cat)
|
|
13
|
+
|
|
14
|
+
# Extract file path từ tool result
|
|
15
|
+
FILE_PATH=$(echo "$INPUT" | node -e "
|
|
16
|
+
let d='';
|
|
17
|
+
process.stdin.on('data',c=>d+=c).on('end',()=>{
|
|
18
|
+
try{
|
|
19
|
+
const data=JSON.parse(d);
|
|
20
|
+
const p=data.file_path||data.path||data.filePath||(data.tool_input&&(data.tool_input.file_path||data.tool_input.path))||'';
|
|
21
|
+
process.stdout.write(p);
|
|
22
|
+
}catch(e){}
|
|
23
|
+
});
|
|
24
|
+
" 2>/dev/null || true)
|
|
25
|
+
|
|
26
|
+
[ -z "$FILE_PATH" ] && exit 0
|
|
27
|
+
|
|
28
|
+
# ── Đọc lint command từ config ────────────────────────────────────────────────
|
|
29
|
+
CONFIG_FILE="${CLAUDE_PROJECT_DIR:-$PWD}/.dw/config/dw.config.yml"
|
|
30
|
+
[ ! -f "$CONFIG_FILE" ] && exit 0
|
|
31
|
+
|
|
32
|
+
LINT_CMD=$(grep -m1 "lint_command:" "$CONFIG_FILE" 2>/dev/null \
|
|
33
|
+
| sed 's/.*:[[:space:]]*//' | tr -d '"' | tr -d "'" | tr -d '[:space:]' || true)
|
|
34
|
+
|
|
35
|
+
[ -z "$LINT_CMD" ] || [ "$LINT_CMD" = "" ] && exit 0
|
|
36
|
+
|
|
37
|
+
# ── Kiểm tra file có phải source code không ──────────────────────────────────
|
|
38
|
+
is_source_file() {
|
|
39
|
+
local f="$1"
|
|
40
|
+
echo "$f" | grep -qE '\.(ts|tsx|js|jsx|py|go|rs|java|rb|php|vue|svelte|css|scss)$'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
is_source_file "$FILE_PATH" || exit 0
|
|
44
|
+
|
|
45
|
+
# ── Chạy lint trên file (non-blocking) ───────────────────────────────────────
|
|
46
|
+
# Thử chạy lint chỉ trên file vừa thay đổi nếu tool hỗ trợ
|
|
47
|
+
if echo "$LINT_CMD" | grep -q "eslint"; then
|
|
48
|
+
RESULT=$(eval "$LINT_CMD '$FILE_PATH'" 2>&1 || true)
|
|
49
|
+
elif echo "$LINT_CMD" | grep -q "ruff"; then
|
|
50
|
+
RESULT=$(eval "ruff check '$FILE_PATH'" 2>&1 || true)
|
|
51
|
+
elif echo "$LINT_CMD" | grep -q "pylint"; then
|
|
52
|
+
RESULT=$(eval "pylint '$FILE_PATH'" 2>&1 || true)
|
|
53
|
+
else
|
|
54
|
+
# Generic: chạy toàn bộ lint command
|
|
55
|
+
RESULT=$(eval "$LINT_CMD" 2>&1 || true)
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
if [ -n "$RESULT" ]; then
|
|
59
|
+
echo "⚠ Lint warnings sau khi write $FILE_PATH:" >&2
|
|
60
|
+
echo "$RESULT" | head -20 >&2
|
|
61
|
+
echo " (non-blocking — kiểm tra và fix nếu cần)" >&2
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
exit 0
|
|
@@ -1,90 +1,96 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# .claude/hooks/pre-commit-gate.sh
|
|
3
|
-
# Quality gate: chạy trước mỗi Bash tool call.
|
|
4
|
-
# Intercepts `git commit` để kiểm tra quality config (v1 schema).
|
|
5
|
-
# exit 0 = allow (có thể warn), exit 2 = block
|
|
6
|
-
|
|
7
|
-
INPUT=$(cat)
|
|
8
|
-
|
|
9
|
-
# Extract command từ JSON input — pure grep/sed, no Python needed
|
|
10
|
-
COMMAND=$(echo "$INPUT" | grep -o '"command"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/"command"[[:space:]]*:[[:space:]]*"//;s/"$//' | head -1)
|
|
11
|
-
|
|
12
|
-
# Chỉ xử lý git commit commands
|
|
13
|
-
if ! echo "$COMMAND" | grep -qE '^\s*git\s+commit'; then
|
|
14
|
-
exit 0
|
|
15
|
-
fi
|
|
16
|
-
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
if [
|
|
20
|
-
|
|
21
|
-
fi
|
|
22
|
-
|
|
23
|
-
#
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
fi
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
echo "
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# .claude/hooks/pre-commit-gate.sh
|
|
3
|
+
# Quality gate: chạy trước mỗi Bash tool call.
|
|
4
|
+
# Intercepts `git commit` để kiểm tra quality config (v1 schema).
|
|
5
|
+
# exit 0 = allow (có thể warn), exit 2 = block
|
|
6
|
+
|
|
7
|
+
INPUT=$(cat)
|
|
8
|
+
|
|
9
|
+
# Extract command từ JSON input — pure grep/sed, no Python needed
|
|
10
|
+
COMMAND=$(echo "$INPUT" | grep -o '"command"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/"command"[[:space:]]*:[[:space:]]*"//;s/"$//' | head -1)
|
|
11
|
+
|
|
12
|
+
# Chỉ xử lý git commit commands
|
|
13
|
+
if ! echo "$COMMAND" | grep -qE '^\s*git\s+commit'; then
|
|
14
|
+
exit 0
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Telemetry (local, fire-and-forget)
|
|
18
|
+
TELEMETRY_SCRIPT="${CLAUDE_PROJECT_DIR:-$(pwd)}/.claude/hooks/telemetry-log.sh"
|
|
19
|
+
if [ -x "$TELEMETRY_SCRIPT" ] && [ "${DW_NO_TELEMETRY:-}" != "1" ]; then
|
|
20
|
+
"$TELEMETRY_SCRIPT" hook pre-commit-gate >/dev/null 2>&1 || true
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# Đọc config
|
|
24
|
+
CONFIG_FILE="$CLAUDE_PROJECT_DIR/.dw/config/dw.config.yml"
|
|
25
|
+
if [ ! -f "$CONFIG_FILE" ]; then
|
|
26
|
+
exit 0
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# Parse values từ YAML — pure grep/sed, no Python needed
|
|
30
|
+
get_value() {
|
|
31
|
+
local key="$1"
|
|
32
|
+
grep -m1 "^[[:space:]]*${key}:" "$CONFIG_FILE" 2>/dev/null \
|
|
33
|
+
| sed 's/.*:[[:space:]]*//' \
|
|
34
|
+
| sed 's/[[:space:]]*#.*//' \
|
|
35
|
+
| sed 's/["'\'']//g' \
|
|
36
|
+
| tr '[:upper:]' '[:lower:]' \
|
|
37
|
+
| tr -d '[:space:]' \
|
|
38
|
+
|| echo ""
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
BLOCK_ON_FAIL=$(get_value "block_on_fail")
|
|
42
|
+
TEST_COMMAND=$(get_value "test_command")
|
|
43
|
+
LINT_COMMAND=$(get_value "lint_command")
|
|
44
|
+
HAS_TESTS=false
|
|
45
|
+
HAS_LINT=false
|
|
46
|
+
[ -n "$TEST_COMMAND" ] && HAS_TESTS=true
|
|
47
|
+
[ -n "$LINT_COMMAND" ] && HAS_LINT=true
|
|
48
|
+
|
|
49
|
+
# Nếu không cấu hình test/lint command → allow (chỉ chạy safety checks)
|
|
50
|
+
if [ "$HAS_TESTS" = false ] && [ "$HAS_LINT" = false ]; then
|
|
51
|
+
exit 0
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# Thông báo quality gate đang check
|
|
55
|
+
echo "⚙️ dw-kit quality gate đang kiểm tra..." >&2
|
|
56
|
+
|
|
57
|
+
ISSUES=0
|
|
58
|
+
|
|
59
|
+
# Check: có debug code không?
|
|
60
|
+
STAGED_FILES=$(git diff --cached --name-only 2>/dev/null)
|
|
61
|
+
if [ -n "$STAGED_FILES" ]; then
|
|
62
|
+
DEBUG_FOUND=$(git diff --cached 2>/dev/null | grep "^+" | grep -E "console\.log\(|debugger|var_dump\(|dd\(|pdb\.set_trace" | grep -v "^+++" | head -5)
|
|
63
|
+
if [ -n "$DEBUG_FOUND" ]; then
|
|
64
|
+
echo "⚠️ Warning: Phát hiện debug code còn sót:" >&2
|
|
65
|
+
echo "$DEBUG_FOUND" >&2
|
|
66
|
+
ISSUES=$((ISSUES + 1))
|
|
67
|
+
fi
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# Check: sensitive patterns?
|
|
71
|
+
SENSITIVE=$(git diff --cached 2>/dev/null | grep "^+" | grep -iE '(password|secret|api_key|private_key)[[:space:]]*=[[:space:]]*.{8,}' | grep -v "^+++" | head -3)
|
|
72
|
+
if [ -n "$SENSITIVE" ]; then
|
|
73
|
+
echo "🚨 CẢNH BÁO: Có thể có sensitive data trong commit!" >&2
|
|
74
|
+
echo "$SENSITIVE" >&2
|
|
75
|
+
if [ "$BLOCK_ON_FAIL" = "true" ]; then
|
|
76
|
+
echo "Commit bị block. Kiểm tra lại staged files." >&2
|
|
77
|
+
exit 2
|
|
78
|
+
fi
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Reminder về tests/lint theo config v1
|
|
82
|
+
if [ "$HAS_TESTS" = true ]; then
|
|
83
|
+
echo "📋 Reminder: Hãy đảm bảo tests đã pass trước khi commit." >&2
|
|
84
|
+
echo " Test command: $TEST_COMMAND" >&2
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
if [ "$HAS_LINT" = true ]; then
|
|
88
|
+
echo "📋 Reminder: Hãy đảm bảo lint đã pass trước khi commit." >&2
|
|
89
|
+
echo " Lint command: $LINT_COMMAND" >&2
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
if [ "$ISSUES" -eq 0 ]; then
|
|
93
|
+
echo "✅ Quality gate: OK" >&2
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
exit 0
|
|
@@ -1,94 +1,99 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# .claude/hooks/privacy-block.sh — dw-kit v1.
|
|
3
|
-
# Block agent reads vào sensitive files (credentials, secrets, private keys).
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# .claude/hooks/privacy-block.sh — dw-kit v1.3 (Guards pillar)
|
|
3
|
+
# Block agent reads vào sensitive files (credentials, secrets, private keys).
|
|
4
|
+
#
|
|
5
|
+
# PreToolUse hook cho: Read
|
|
6
|
+
# exit 0 = allow, exit 2 = block
|
|
7
|
+
|
|
8
|
+
# Telemetry (local, fire-and-forget) — log every check
|
|
9
|
+
TELEMETRY_SCRIPT="${CLAUDE_PROJECT_DIR:-$(pwd)}/.claude/hooks/telemetry-log.sh"
|
|
10
|
+
if [ -x "$TELEMETRY_SCRIPT" ] && [ "${DW_NO_TELEMETRY:-}" != "1" ]; then
|
|
11
|
+
"$TELEMETRY_SCRIPT" hook privacy-block >/dev/null 2>&1 || true
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
INPUT=$(cat)
|
|
15
|
+
|
|
16
|
+
TOOL_NAME=$(echo "$INPUT" | node -e "
|
|
17
|
+
let d='';
|
|
18
|
+
process.stdin.on('data',c=>d+=c).on('end',()=>{
|
|
19
|
+
try{ process.stdout.write(JSON.parse(d).tool_name||''); }catch(e){}
|
|
20
|
+
});
|
|
21
|
+
" 2>/dev/null || true)
|
|
22
|
+
|
|
23
|
+
[ "$TOOL_NAME" != "Read" ] && exit 0
|
|
24
|
+
|
|
25
|
+
FILE_PATH=$(echo "$INPUT" | node -e "
|
|
26
|
+
let d='';
|
|
27
|
+
process.stdin.on('data',c=>d+=c).on('end',()=>{
|
|
28
|
+
try{ const p=JSON.parse(d); process.stdout.write((p.tool_input&&p.tool_input.file_path)||''); }catch(e){}
|
|
29
|
+
});
|
|
30
|
+
" 2>/dev/null || true)
|
|
31
|
+
|
|
32
|
+
[ -z "$FILE_PATH" ] && exit 0
|
|
33
|
+
|
|
34
|
+
BASENAME=$(basename "$FILE_PATH")
|
|
35
|
+
NORM=$(echo "$FILE_PATH" | tr '\\' '/')
|
|
36
|
+
|
|
37
|
+
# ── Allow-list: safe files dù tên giống sensitive ─────────────────────────────
|
|
38
|
+
ALLOWED_PATTERNS=(
|
|
39
|
+
".env.example"
|
|
40
|
+
".env.sample"
|
|
41
|
+
".env.template"
|
|
42
|
+
".env.test"
|
|
43
|
+
".env.local.example"
|
|
44
|
+
"*.example"
|
|
45
|
+
"*.sample"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
for allow in "${ALLOWED_PATTERNS[@]}"; do
|
|
49
|
+
if [[ "$BASENAME" == $allow ]]; then
|
|
50
|
+
exit 0
|
|
51
|
+
fi
|
|
52
|
+
done
|
|
53
|
+
|
|
54
|
+
# ── Block patterns ──────────────────────────────────────────────────────────────
|
|
55
|
+
BLOCKED=false
|
|
56
|
+
REASON=""
|
|
57
|
+
|
|
58
|
+
# .env files (nhưng không phải .env.example đã allow ở trên)
|
|
59
|
+
if [[ "$BASENAME" == ".env" ]] || [[ "$BASENAME" == .env.* ]]; then
|
|
60
|
+
BLOCKED=true
|
|
61
|
+
REASON="Environment file (có thể chứa secrets/API keys)"
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# Private key files
|
|
65
|
+
if [[ "$BASENAME" == *.pem ]] || [[ "$BASENAME" == *.key ]] || \
|
|
66
|
+
[[ "$BASENAME" == *.p12 ]] || [[ "$BASENAME" == *.pfx ]] || \
|
|
67
|
+
[[ "$BASENAME" == *.jks ]]; then
|
|
68
|
+
BLOCKED=true
|
|
69
|
+
REASON="Private key / certificate file"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Credentials & secrets files
|
|
73
|
+
if echo "$BASENAME" | grep -qiE '^(credentials|secrets?|secret[-_]key|api[-_]key|auth[-_]token|access[-_]token)(\.[a-z]+)?$'; then
|
|
74
|
+
BLOCKED=true
|
|
75
|
+
REASON="Credentials / secrets file"
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Known credential file patterns
|
|
79
|
+
if [[ "$BASENAME" == "*.credentials.json" ]] || \
|
|
80
|
+
echo "$NORM" | grep -qiE '/(credentials|secrets)/'; then
|
|
81
|
+
BLOCKED=true
|
|
82
|
+
REASON="Credentials directory hoặc file"
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# Service account / GCP keys
|
|
86
|
+
if echo "$BASENAME" | grep -qiE 'service[-_]account.*\.json$|gcp.*key.*\.json$|firebase.*key.*\.json$'; then
|
|
87
|
+
BLOCKED=true
|
|
88
|
+
REASON="Service account / cloud credentials"
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
if [ "$BLOCKED" = true ]; then
|
|
92
|
+
echo "🔒 privacy-block: Blocked sensitive file read" >&2
|
|
93
|
+
echo " File: $FILE_PATH" >&2
|
|
94
|
+
echo " Lý do: $REASON" >&2
|
|
95
|
+
echo " Nếu thực sự cần đọc file này, hãy confirm rõ ràng trong prompt." >&2
|
|
96
|
+
exit 2
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
exit 0
|
|
@@ -1,47 +1,53 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# .claude/hooks/progress-ping.sh
|
|
3
|
-
# Nhắc cập nhật progress file khi notification event xảy ra.
|
|
4
|
-
# Non-blocking, informational only.
|
|
5
|
-
# Được gọi bởi Notification hook.
|
|
6
|
-
|
|
7
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD}"
|
|
8
|
-
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
[
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
[
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
#
|
|
42
|
-
if
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# .claude/hooks/progress-ping.sh
|
|
3
|
+
# Nhắc cập nhật progress file khi notification event xảy ra.
|
|
4
|
+
# Non-blocking, informational only.
|
|
5
|
+
# Được gọi bởi Notification hook.
|
|
6
|
+
|
|
7
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD}"
|
|
8
|
+
|
|
9
|
+
# Telemetry (local, fire-and-forget)
|
|
10
|
+
TELEMETRY_SCRIPT="$PROJECT_DIR/.claude/hooks/telemetry-log.sh"
|
|
11
|
+
if [ -x "$TELEMETRY_SCRIPT" ] && [ "${DW_NO_TELEMETRY:-}" != "1" ]; then
|
|
12
|
+
"$TELEMETRY_SCRIPT" hook progress-ping >/dev/null 2>&1 || true
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
# ── Tìm active tasks ──────────────────────────────────────────────────────────
|
|
16
|
+
CONFIG_FILE="$PROJECT_DIR/config/dw.config.yml"
|
|
17
|
+
[ ! -f "$CONFIG_FILE" ] && CONFIG_FILE="$PROJECT_DIR/config/dw.config.yml"
|
|
18
|
+
|
|
19
|
+
TASKS_DIR="$PROJECT_DIR/.dw/tasks"
|
|
20
|
+
|
|
21
|
+
# Đọc paths.tasks từ config nếu có
|
|
22
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
23
|
+
CUSTOM_TASKS=$(grep -m1 "tasks:" "$CONFIG_FILE" 2>/dev/null \
|
|
24
|
+
| sed 's/.*:[[:space:]]*//' | tr -d '"' | tr -d "'" | tr -d '[:space:]' || true)
|
|
25
|
+
[ -n "$CUSTOM_TASKS" ] && TASKS_DIR="$PROJECT_DIR/$CUSTOM_TASKS"
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
[ ! -d "$TASKS_DIR" ] && exit 0
|
|
29
|
+
|
|
30
|
+
# ── Kiểm tra in-progress tasks ───────────────────────────────────────────────
|
|
31
|
+
in_progress_tasks=()
|
|
32
|
+
|
|
33
|
+
for task_dir in "$TASKS_DIR"/*/; do
|
|
34
|
+
[ -d "$task_dir" ] || continue
|
|
35
|
+
task_name=$(basename "$task_dir")
|
|
36
|
+
[ "$task_name" = "archive" ] && continue
|
|
37
|
+
|
|
38
|
+
progress_file="$task_dir/${task_name}-progress.md"
|
|
39
|
+
[ -f "$progress_file" ] || continue
|
|
40
|
+
|
|
41
|
+
# Kiểm tra status
|
|
42
|
+
if grep -q "Trạng thái: In Progress" "$progress_file" 2>/dev/null; then
|
|
43
|
+
in_progress_tasks+=("$task_name")
|
|
44
|
+
fi
|
|
45
|
+
done
|
|
46
|
+
|
|
47
|
+
# ── Chỉ remind nếu có active tasks ───────────────────────────────────────────
|
|
48
|
+
if [ ${#in_progress_tasks[@]} -gt 0 ]; then
|
|
49
|
+
echo "📋 Active task(s): ${in_progress_tasks[*]}" >&2
|
|
50
|
+
echo " Nhớ cập nhật progress file sau khi hoàn thành subtask." >&2
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
exit 0
|