codecruise 0.1.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 (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/bin/codecruise.js +68 -0
  4. package/config/CLAUDE.md +107 -0
  5. package/config/agents/analyst.md +48 -0
  6. package/config/agents/architect-reviewer.md +161 -0
  7. package/config/agents/architect.md +119 -0
  8. package/config/agents/critic.md +63 -0
  9. package/config/agents/developer.md +96 -0
  10. package/config/agents/devops.md +81 -0
  11. package/config/agents/orchestrator.md +91 -0
  12. package/config/agents/planner.md +139 -0
  13. package/config/agents/retro.md +52 -0
  14. package/config/agents/reviewer.md +101 -0
  15. package/config/agents/security-reviewer.md +57 -0
  16. package/config/agents/stack/expo/AGENT.md +473 -0
  17. package/config/agents/stack/expo/rules/critical.md +427 -0
  18. package/config/agents/stack/expo/rules/native.md +455 -0
  19. package/config/agents/stack/expo/rules/navigation.md +445 -0
  20. package/config/agents/stack/expo/rules/performance.md +415 -0
  21. package/config/agents/stack/fastify/AGENT.md +397 -0
  22. package/config/agents/stack/fastify/rules/api-design.md +283 -0
  23. package/config/agents/stack/fastify/rules/critical.md +232 -0
  24. package/config/agents/stack/fastify/rules/queues.md +303 -0
  25. package/config/agents/stack/fastify/rules/security.md +384 -0
  26. package/config/agents/stack/index.yaml +48 -0
  27. package/config/agents/stack/nextjs/AGENT.md +421 -0
  28. package/config/agents/stack/nextjs/rules/components.md +413 -0
  29. package/config/agents/stack/nextjs/rules/critical.md +391 -0
  30. package/config/agents/stack/nextjs/rules/performance.md +403 -0
  31. package/config/agents/stack/nextjs/rules/styling.md +334 -0
  32. package/config/agents/stack/shared-ts/AGENT.md +384 -0
  33. package/config/agents/stack/shared-ts/rules/critical.md +315 -0
  34. package/config/agents/stack/shared-ts/rules/patterns.md +384 -0
  35. package/config/agents/stack/shared-ts/rules/zod.md +427 -0
  36. package/config/agents/tester.md +79 -0
  37. package/config/commands/architect-discuss.md +366 -0
  38. package/config/commands/architect-list.md +160 -0
  39. package/config/commands/architect-review.md +111 -0
  40. package/config/commands/architect.md +118 -0
  41. package/config/commands/compact.md +118 -0
  42. package/config/commands/companion.md +279 -0
  43. package/config/commands/dashboard.md +152 -0
  44. package/config/commands/doctor.md +227 -0
  45. package/config/commands/dogfood-report.md +101 -0
  46. package/config/commands/flags/run-autonomous.md +110 -0
  47. package/config/commands/flags/run-pause.md +80 -0
  48. package/config/commands/ingest.md +173 -0
  49. package/config/commands/init.md +128 -0
  50. package/config/commands/metrics.md +87 -0
  51. package/config/commands/parallel.md +320 -0
  52. package/config/commands/pause.md +55 -0
  53. package/config/commands/plan-review.md +130 -0
  54. package/config/commands/plan.md +216 -0
  55. package/config/commands/production-check.md +308 -0
  56. package/config/commands/refine.md +323 -0
  57. package/config/commands/resume.md +72 -0
  58. package/config/commands/retro.md +121 -0
  59. package/config/commands/retry.md +75 -0
  60. package/config/commands/role.md +310 -0
  61. package/config/commands/run.md +417 -0
  62. package/config/commands/scope.md +85 -0
  63. package/config/commands/setup-permissions.md +104 -0
  64. package/config/commands/skip.md +75 -0
  65. package/config/commands/spec-forge.md +213 -0
  66. package/config/commands/spec-help.md +194 -0
  67. package/config/commands/spec-patch.md +342 -0
  68. package/config/commands/spec-resolve.md +110 -0
  69. package/config/commands/spec-review.md +153 -0
  70. package/config/commands/status.md +114 -0
  71. package/config/commands/sync.md +131 -0
  72. package/config/commands/task.md +138 -0
  73. package/config/commands/verify.md +124 -0
  74. package/config/hooks/README.md +632 -0
  75. package/config/hooks/activity-log.sh +187 -0
  76. package/config/hooks/anti-rationalize.sh +52 -0
  77. package/config/hooks/capture-verification.sh +112 -0
  78. package/config/hooks/collect-metrics.sh +135 -0
  79. package/config/hooks/enforce-file-scope.sh +75 -0
  80. package/config/hooks/enforce-state-machine.sh +161 -0
  81. package/config/hooks/enforce-tdd.sh +180 -0
  82. package/config/hooks/format.sh +40 -0
  83. package/config/hooks/lib/activity-helpers.sh +162 -0
  84. package/config/hooks/lib/read-settings.sh +71 -0
  85. package/config/hooks/load-context-skills.sh +95 -0
  86. package/config/hooks/notify.sh +81 -0
  87. package/config/hooks/pre-commit.sample +35 -0
  88. package/config/hooks/protect-files.sh +63 -0
  89. package/config/hooks/track-agents.sh +41 -0
  90. package/config/hooks/track-commands.sh +37 -0
  91. package/config/hooks/track-enforcement.sh +44 -0
  92. package/config/hooks/track-ooda.sh +77 -0
  93. package/config/hooks/validate-commit-msg.sh +35 -0
  94. package/config/hooks/validate-plan.sh +213 -0
  95. package/config/hooks/verify-criteria.sh +46 -0
  96. package/config/hooks/verify-todo-completion.sh +140 -0
  97. package/config/rules/comments.md +25 -0
  98. package/config/rules/decision-rules.md +308 -0
  99. package/config/rules/hygiene.md +247 -0
  100. package/config/rules/pattern-detection.md +372 -0
  101. package/config/rules/profiles.md +193 -0
  102. package/config/rules/recovery.md +83 -0
  103. package/config/rules/scope-detection.md +213 -0
  104. package/config/rules/standards.md +127 -0
  105. package/config/rules/workflow.md +121 -0
  106. package/config/schemas.md +767 -0
  107. package/config/settings.json +195 -0
  108. package/config/skills/backend/SKILL.md +734 -0
  109. package/config/skills/database/SKILL.md +426 -0
  110. package/config/skills/frontend/SKILL.md +434 -0
  111. package/config/skills/git/SKILL.md +396 -0
  112. package/config/skills/index.yaml +36 -0
  113. package/config/skills/observability/SKILL.md +430 -0
  114. package/config/skills/package-dev/SKILL.md +498 -0
  115. package/config/skills/performance/SKILL.md +378 -0
  116. package/config/skills/resilience/SKILL.md +573 -0
  117. package/config/skills/testing/SKILL.md +398 -0
  118. package/config/skills/testing-patterns/SKILL.md +276 -0
  119. package/config/skills/typescript/SKILL.md +152 -0
  120. package/config/templates/CLAUDE.md +70 -0
  121. package/config/templates/README.md +117 -0
  122. package/config/templates/steering/adr-template.md +102 -0
  123. package/config/templates/steering/product.md +60 -0
  124. package/config/templates/steering/rfc-template.md +159 -0
  125. package/config/templates/steering/structure.md +146 -0
  126. package/config/templates/steering/tech.md +85 -0
  127. package/package.json +40 -0
  128. package/src/install.js +163 -0
  129. package/src/report.js +310 -0
@@ -0,0 +1,161 @@
1
+ #!/bin/bash
2
+ # PreToolUse hook - Enforces valid state transitions in progress.yaml
3
+ #
4
+ # P1 Enforcement: Prevents invalid TODO state transitions
5
+ #
6
+ # Valid transitions:
7
+ # pending → in_progress
8
+ # in_progress → done, blocked, failed
9
+ # blocked → in_progress
10
+ # failed → in_progress, skipped
11
+ # done → (terminal, no transitions)
12
+ # skipped → (terminal, no transitions)
13
+ #
14
+ # Also enforces:
15
+ # - Cannot mark done without passing quality gates
16
+ # - Cannot skip from pending (must attempt first)
17
+
18
+ # Load settings library
19
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20
+ if [[ -f "$SCRIPT_DIR/lib/read-settings.sh" ]]; then
21
+ source "$SCRIPT_DIR/lib/read-settings.sh"
22
+ elif [[ -f "$HOME/.claude/hooks/lib/read-settings.sh" ]]; then
23
+ source "$HOME/.claude/hooks/lib/read-settings.sh"
24
+ else
25
+ get_enforce_mode() { echo "${CODECRUISE_ENFORCE:-strict}"; }
26
+ fi
27
+
28
+ # Load enforcement tracking
29
+ if [[ -f "$SCRIPT_DIR/track-enforcement.sh" ]]; then
30
+ source "$SCRIPT_DIR/track-enforcement.sh"
31
+ elif [[ -f "$HOME/.claude/hooks/track-enforcement.sh" ]]; then
32
+ source "$HOME/.claude/hooks/track-enforcement.sh"
33
+ else
34
+ track_enforcement() { :; }
35
+ fi
36
+
37
+ INPUT=$(cat)
38
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')
39
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
40
+ NEW_CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // empty')
41
+
42
+ # Only check Edit/Write to progress.yaml or roadmap files
43
+ if [[ "$TOOL" != "Write" && "$TOOL" != "Edit" ]]; then
44
+ exit 0
45
+ fi
46
+
47
+ # Check if editing state files
48
+ if [[ "$FILE" != *"progress.yaml"* && "$FILE" != *"roadmap/"* ]]; then
49
+ exit 0
50
+ fi
51
+
52
+ # Get enforcement mode
53
+ ENFORCE_MODE=$(get_enforce_mode "state")
54
+
55
+ if [[ "$ENFORCE_MODE" == "off" ]]; then
56
+ exit 0
57
+ fi
58
+
59
+ # For progress.yaml edits, validate state transitions
60
+ if [[ "$FILE" == *"progress.yaml"* ]]; then
61
+ # Read current state
62
+ if [[ -f "progress.yaml" ]]; then
63
+ CURRENT_STATUS=$(grep -E "^\s*status:" progress.yaml | head -1 | sed 's/.*status:\s*//' | tr -d ' "' || echo "")
64
+ else
65
+ CURRENT_STATUS=""
66
+ fi
67
+
68
+ # Try to extract new status from the edit
69
+ # This is tricky because we get the new content, need to parse what's changing
70
+ NEW_STATUS=$(echo "$NEW_CONTENT" | grep -E "status:" | head -1 | sed 's/.*status:\s*//' | tr -d ' "' || echo "")
71
+
72
+ # If no status change detected, allow
73
+ if [[ -z "$NEW_STATUS" || "$NEW_STATUS" == "$CURRENT_STATUS" ]]; then
74
+ exit 0
75
+ fi
76
+
77
+ # Define valid transitions
78
+ VALID=false
79
+ case "$CURRENT_STATUS" in
80
+ "pending")
81
+ [[ "$NEW_STATUS" == "in_progress" ]] && VALID=true
82
+ ;;
83
+ "in_progress")
84
+ [[ "$NEW_STATUS" == "done" || "$NEW_STATUS" == "blocked" || "$NEW_STATUS" == "failed" ]] && VALID=true
85
+ ;;
86
+ "blocked")
87
+ [[ "$NEW_STATUS" == "in_progress" ]] && VALID=true
88
+ ;;
89
+ "failed")
90
+ [[ "$NEW_STATUS" == "in_progress" || "$NEW_STATUS" == "skipped" ]] && VALID=true
91
+ ;;
92
+ "done"|"skipped")
93
+ # Terminal states - no transitions allowed
94
+ VALID=false
95
+ ;;
96
+ "")
97
+ # No current status - allow setting initial status
98
+ VALID=true
99
+ ;;
100
+ *)
101
+ # Unknown current status - allow
102
+ VALID=true
103
+ ;;
104
+ esac
105
+
106
+ if [[ "$VALID" == false ]]; then
107
+ if [[ "$ENFORCE_MODE" == "ask" ]]; then
108
+ DECISION="ask"
109
+ REASON="Invalid state transition: $CURRENT_STATUS → $NEW_STATUS. Allow anyway?"
110
+ track_enforcement "state_ask" "$CURRENT_STATUS -> $NEW_STATUS" "enforce-state-machine"
111
+ else
112
+ DECISION="deny"
113
+ REASON="Invalid state transition: $CURRENT_STATUS → $NEW_STATUS. Valid transitions: pending→in_progress, in_progress→done/blocked/failed, blocked→in_progress, failed→in_progress/skipped. Terminal states (done, skipped) cannot transition."
114
+ track_enforcement "state_block" "$CURRENT_STATUS -> $NEW_STATUS" "enforce-state-machine"
115
+ fi
116
+
117
+ cat <<EOF
118
+ {
119
+ "hookSpecificOutput": {
120
+ "hookEventName": "PreToolUse",
121
+ "permissionDecision": "$DECISION",
122
+ "permissionDecisionReason": "$REASON"
123
+ }
124
+ }
125
+ EOF
126
+ exit 0
127
+ fi
128
+
129
+ # Additional check: Cannot mark done without quality gates
130
+ if [[ "$NEW_STATUS" == "done" ]]; then
131
+ SUMMARY_FILE=".codecruise/verification/summary.json"
132
+ if [[ -f "$SUMMARY_FILE" ]]; then
133
+ TEST_EXIT=$(jq -r '.tests.exit_code // 0' "$SUMMARY_FILE")
134
+ LINT_EXIT=$(jq -r '.lint.exit_code // 0' "$SUMMARY_FILE")
135
+
136
+ if [[ "$TEST_EXIT" != "0" && "$TEST_EXIT" != "-1" ]] || [[ "$LINT_EXIT" != "0" && "$LINT_EXIT" != "-1" ]]; then
137
+ if [[ "$ENFORCE_MODE" == "ask" ]]; then
138
+ DECISION="ask"
139
+ REASON="Quality gates not passed (test=$TEST_EXIT, lint=$LINT_EXIT). Mark as done anyway?"
140
+ else
141
+ DECISION="deny"
142
+ REASON="Cannot mark TODO as done: quality gates not passed (test exit=$TEST_EXIT, lint exit=$LINT_EXIT). Fix issues first or use /skip to skip this TODO."
143
+ fi
144
+
145
+ cat <<EOF
146
+ {
147
+ "hookSpecificOutput": {
148
+ "hookEventName": "PreToolUse",
149
+ "permissionDecision": "$DECISION",
150
+ "permissionDecisionReason": "$REASON"
151
+ }
152
+ }
153
+ EOF
154
+ exit 0
155
+ fi
156
+ fi
157
+ fi
158
+ fi
159
+
160
+ # Allow the operation
161
+ exit 0
@@ -0,0 +1,180 @@
1
+ #!/bin/bash
2
+ # PreToolUse hook - Enforces TDD by requiring tests before implementation
3
+ #
4
+ # P0 Enforcement: Blocks writes to implementation files unless:
5
+ # 1. A corresponding test file already exists, OR
6
+ # 2. The file being written IS a test file, OR
7
+ # 3. The file is configuration/non-code
8
+ #
9
+ # Configuration (highest to lowest priority):
10
+ # 1. Command flag: /run --enforce=off
11
+ # 2. Project: .claude/settings.json → codecruise.enforce_tdd
12
+ # 3. User: ~/.claude/settings.json → codecruise.enforce_tdd
13
+ # 4. Default: strict
14
+
15
+ # Load settings library
16
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17
+ if [[ -f "$SCRIPT_DIR/lib/read-settings.sh" ]]; then
18
+ source "$SCRIPT_DIR/lib/read-settings.sh"
19
+ elif [[ -f "$HOME/.claude/hooks/lib/read-settings.sh" ]]; then
20
+ source "$HOME/.claude/hooks/lib/read-settings.sh"
21
+ else
22
+ # Fallback if library not found
23
+ get_enforce_mode() { echo "${CODECRUISE_ENFORCE:-strict}"; }
24
+ fi
25
+
26
+ # Load enforcement tracking
27
+ if [[ -f "$SCRIPT_DIR/track-enforcement.sh" ]]; then
28
+ source "$SCRIPT_DIR/track-enforcement.sh"
29
+ elif [[ -f "$HOME/.claude/hooks/track-enforcement.sh" ]]; then
30
+ source "$HOME/.claude/hooks/track-enforcement.sh"
31
+ else
32
+ track_enforcement() { :; } # no-op fallback
33
+ fi
34
+
35
+ INPUT=$(cat)
36
+
37
+ # Get enforcement mode from settings hierarchy
38
+ ENFORCE_MODE=$(get_enforce_mode "tdd")
39
+
40
+ # If enforcement is off, allow everything
41
+ if [[ "$ENFORCE_MODE" == "off" ]]; then
42
+ exit 0
43
+ fi
44
+
45
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')
46
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
47
+
48
+ # Only check Write and Edit operations
49
+ if [[ "$TOOL" != "Write" && "$TOOL" != "Edit" ]]; then
50
+ exit 0
51
+ fi
52
+
53
+ # Skip if no file path
54
+ if [[ -z "$FILE" ]]; then
55
+ exit 0
56
+ fi
57
+
58
+ # Skip if not in a codecruise project
59
+ if [[ ! -f "progress.yaml" ]]; then
60
+ exit 0
61
+ fi
62
+
63
+ # Get execution status - only enforce during active TODO execution
64
+ EXEC_STATUS=$(grep "status:" progress.yaml 2>/dev/null | head -1 | sed 's/.*status: //' | tr -d ' "' || echo "")
65
+ if [[ "$EXEC_STATUS" != "running" && "$EXEC_STATUS" != "in_progress" ]]; then
66
+ exit 0
67
+ fi
68
+
69
+ # Files that don't need tests (configuration, assets, etc.)
70
+ SKIP_PATTERNS=(
71
+ "*.json"
72
+ "*.yaml"
73
+ "*.yml"
74
+ "*.md"
75
+ "*.txt"
76
+ "*.css"
77
+ "*.scss"
78
+ "*.svg"
79
+ "*.png"
80
+ "*.jpg"
81
+ "*.ico"
82
+ "*.env*"
83
+ "*.config.*"
84
+ "*.d.ts"
85
+ "tsconfig*"
86
+ "package.json"
87
+ "pnpm-lock.yaml"
88
+ ".gitignore"
89
+ ".eslintrc*"
90
+ ".prettierrc*"
91
+ "vite.config.*"
92
+ "next.config.*"
93
+ "tailwind.config.*"
94
+ "postcss.config.*"
95
+ "prisma/*"
96
+ "migrations/*"
97
+ )
98
+
99
+ # Check if file matches skip patterns
100
+ for pattern in "${SKIP_PATTERNS[@]}"; do
101
+ if [[ "$FILE" == $pattern ]]; then
102
+ exit 0
103
+ fi
104
+ done
105
+
106
+ # Check if this IS a test file (allow these)
107
+ if [[ "$FILE" == *.test.* ]] || \
108
+ [[ "$FILE" == *.spec.* ]] || \
109
+ [[ "$FILE" == *_test.* ]] || \
110
+ [[ "$FILE" == *_spec.* ]] || \
111
+ [[ "$FILE" == */__tests__/* ]] || \
112
+ [[ "$FILE" == */test/* ]] || \
113
+ [[ "$FILE" == */tests/* ]] || \
114
+ [[ "$FILE" == */e2e/* ]]; then
115
+ exit 0
116
+ fi
117
+
118
+ # Check if this is a source file that needs a test
119
+ if [[ "$FILE" == *.ts ]] || \
120
+ [[ "$FILE" == *.tsx ]] || \
121
+ [[ "$FILE" == *.js ]] || \
122
+ [[ "$FILE" == *.jsx ]] || \
123
+ [[ "$FILE" == *.py ]] || \
124
+ [[ "$FILE" == *.go ]] || \
125
+ [[ "$FILE" == *.rs ]]; then
126
+
127
+ # Get base name and extension
128
+ BASENAME="${FILE%.*}"
129
+ EXT="${FILE##*.}"
130
+ DIR=$(dirname "$FILE")
131
+ FILENAME=$(basename "$FILE")
132
+ FILENAME_NO_EXT="${FILENAME%.*}"
133
+
134
+ # Possible test file patterns
135
+ TEST_PATTERNS=(
136
+ "${BASENAME}.test.${EXT}"
137
+ "${BASENAME}.spec.${EXT}"
138
+ "${BASENAME}_test.${EXT}"
139
+ "${DIR}/__tests__/${FILENAME_NO_EXT}.test.${EXT}"
140
+ "${DIR}/__tests__/${FILENAME_NO_EXT}.spec.${EXT}"
141
+ "${DIR}/tests/${FILENAME_NO_EXT}.test.${EXT}"
142
+ "${DIR}/test/${FILENAME_NO_EXT}.test.${EXT}"
143
+ )
144
+
145
+ # Check if any test file exists
146
+ TEST_EXISTS=false
147
+ for test_file in "${TEST_PATTERNS[@]}"; do
148
+ if [[ -f "$test_file" ]]; then
149
+ TEST_EXISTS=true
150
+ break
151
+ fi
152
+ done
153
+
154
+ if [[ "$TEST_EXISTS" == false ]]; then
155
+ # Determine action based on enforcement mode
156
+ if [[ "$ENFORCE_MODE" == "ask" ]]; then
157
+ DECISION="ask"
158
+ REASON="TDD: No test file found. Expected: ${BASENAME}.test.${EXT}. Allow implementation anyway?"
159
+ track_enforcement "tdd_ask" "Missing test for $FILE" "enforce-tdd"
160
+ else
161
+ DECISION="deny"
162
+ REASON="TDD violation: Write tests first before implementing. Expected test file: ${BASENAME}.test.${EXT} or ${DIR}/__tests__/${FILENAME_NO_EXT}.test.${EXT}. Create the test file with failing tests (RED), then implement (GREEN)."
163
+ track_enforcement "tdd_block" "Missing test for $FILE" "enforce-tdd"
164
+ fi
165
+
166
+ cat <<EOF
167
+ {
168
+ "hookSpecificOutput": {
169
+ "hookEventName": "PreToolUse",
170
+ "permissionDecision": "$DECISION",
171
+ "permissionDecisionReason": "$REASON"
172
+ }
173
+ }
174
+ EOF
175
+ exit 0
176
+ fi
177
+ fi
178
+
179
+ # Allow the operation
180
+ exit 0
@@ -0,0 +1,40 @@
1
+ #!/bin/bash
2
+ # PostToolUse hook - auto-formats files after edit/write
3
+ # "Handles the last 10% before CI" — Boris Cherny
4
+
5
+ INPUT=$(cat)
6
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
7
+
8
+ if [[ -z "$FILE" || ! -f "$FILE" ]]; then
9
+ exit 0
10
+ fi
11
+
12
+ EXT="${FILE##*.}"
13
+
14
+ case "$EXT" in
15
+ js|ts|jsx|tsx|json|css|scss|md|html|yaml|yml)
16
+ if command -v npx &> /dev/null; then
17
+ npx prettier --write "$FILE" 2>/dev/null || true
18
+ fi
19
+ ;;
20
+ py)
21
+ if command -v black &> /dev/null; then
22
+ black "$FILE" 2>/dev/null || true
23
+ fi
24
+ if command -v isort &> /dev/null; then
25
+ isort "$FILE" 2>/dev/null || true
26
+ fi
27
+ ;;
28
+ go)
29
+ if command -v gofmt &> /dev/null; then
30
+ gofmt -w "$FILE" 2>/dev/null || true
31
+ fi
32
+ ;;
33
+ rs)
34
+ if command -v rustfmt &> /dev/null; then
35
+ rustfmt "$FILE" 2>/dev/null || true
36
+ fi
37
+ ;;
38
+ esac
39
+
40
+ exit 0
@@ -0,0 +1,162 @@
1
+ #!/bin/bash
2
+ # activity-helpers.sh — Helper functions for activity logging
3
+ #
4
+ # Source this in hooks or commands to log OODA events:
5
+ # source ~/.claude/hooks/lib/activity-helpers.sh
6
+ #
7
+ # Usage:
8
+ # log_ooda_observe "todo-1.1b-004"
9
+ # log_ooda_orient "0.85" ""
10
+ # log_ooda_decide "execute"
11
+ # log_ooda_act "todo-1.1b-004" "Implement validation"
12
+ # log_todo_complete "todo-1.1b-004" "3m 30s" "abc123"
13
+ # log_todo_fail "todo-1.1b-004" "connection refused"
14
+ # log_retry "todo-1.1b-004" "2" "3"
15
+ # log_skip "todo-1.1b-004" "external dep down"
16
+ # log_session_start
17
+ # log_session_pause
18
+
19
+ ACTIVITY_LOG="${CODECRUISE_ACTIVITY_LOG:-.codecruise/activity.log}"
20
+
21
+ # Ensure directory exists
22
+ _ensure_log_dir() {
23
+ mkdir -p "$(dirname "$ACTIVITY_LOG")" 2>/dev/null || true
24
+ }
25
+
26
+ # Get timestamp
27
+ _ts() {
28
+ date "+%Y-%m-%d %H:%M:%S"
29
+ }
30
+
31
+ # Base log function
32
+ _log() {
33
+ _ensure_log_dir
34
+ echo "[$(_ts)] $1" >> "$ACTIVITY_LOG"
35
+ }
36
+
37
+ # Indented detail
38
+ _log_detail() {
39
+ _ensure_log_dir
40
+ echo "[$(_ts)] $1" >> "$ACTIVITY_LOG"
41
+ }
42
+
43
+ # --- Session Events ---
44
+
45
+ log_session_start() {
46
+ _log "━━━ SESSION START ━━━"
47
+ }
48
+
49
+ log_session_pause() {
50
+ _log "⏸ PAUSE"
51
+ _log "━━━ SESSION PAUSE ━━━"
52
+ }
53
+
54
+ log_session_resume() {
55
+ _log "▶ RESUME"
56
+ }
57
+
58
+ # --- OODA Phase Events ---
59
+
60
+ log_ooda_observe() {
61
+ local todo="$1"
62
+ _log "👁 OBSERVE $todo"
63
+ }
64
+
65
+ log_ooda_observe_detail() {
66
+ local key="$1"
67
+ local value="$2"
68
+ local symbol="${3:-├─}" # Use └─ for last item
69
+ _log_detail "$symbol $key: $value"
70
+ }
71
+
72
+ log_ooda_orient() {
73
+ local confidence="$1"
74
+ local patterns="$2"
75
+ _log "🧭 ORIENT confidence=$confidence"
76
+ if [[ -n "$patterns" ]]; then
77
+ _log_detail "└─ patterns: $patterns"
78
+ fi
79
+ }
80
+
81
+ log_ooda_decide() {
82
+ local decision="$1"
83
+ _log "⚡ DECIDE $decision"
84
+ }
85
+
86
+ log_ooda_act() {
87
+ local todo="$1"
88
+ local description="$2"
89
+ _log "▶ ACT $todo \"$description\""
90
+ }
91
+
92
+ log_ooda_act_phase() {
93
+ local phase="$1" # red, green, refactor
94
+ local detail="$2"
95
+ case "$phase" in
96
+ red) _log_detail "├─ RED: $detail" ;;
97
+ green) _log_detail "├─ GREEN: $detail" ;;
98
+ refactor) _log_detail "├─ REFACTOR: $detail" ;;
99
+ verify) _log_detail "└─ VERIFY: $detail" ;;
100
+ esac
101
+ }
102
+
103
+ # --- TODO Events ---
104
+
105
+ log_todo_complete() {
106
+ local todo="$1"
107
+ local duration="$2"
108
+ local commit="$3"
109
+ _log "✓ COMPLETE $todo ($duration) commit:$commit"
110
+ }
111
+
112
+ log_todo_fail() {
113
+ local todo="$1"
114
+ local error="$2"
115
+ _log_detail "└─ ✗ FAIL: $error"
116
+ }
117
+
118
+ log_retry() {
119
+ local todo="$1"
120
+ local attempt="$2"
121
+ local max="$3"
122
+ _log "⚠ RETRY $todo (attempt $attempt/$max)"
123
+ }
124
+
125
+ log_skip() {
126
+ local todo="$1"
127
+ local reason="$2"
128
+ _log "⏭ SKIP $todo ($reason)"
129
+ }
130
+
131
+ log_next() {
132
+ local todo="$1"
133
+ _log "→ NEXT $todo"
134
+ }
135
+
136
+ # --- Verification Events ---
137
+
138
+ log_verify() {
139
+ local lint="$1" # ✓ or ✗
140
+ local tsc="$2" # ✓ or ✗
141
+ local test="$3" # ✓ or ✗
142
+ _log_detail "└─ VERIFY: lint $lint | tsc $tsc | test $test"
143
+ }
144
+
145
+ # --- Blocker Events ---
146
+
147
+ log_blocker() {
148
+ local pattern="$1"
149
+ local detail="$2"
150
+ _log "🔴 BLOCKER DETECTED $pattern"
151
+ _log_detail "└─ $detail"
152
+ }
153
+
154
+ # --- Checkpoint Events ---
155
+
156
+ log_checkpoint() {
157
+ local type="$1" # subfeature, feature
158
+ local id="$2"
159
+ local todos_done="$3"
160
+ local total="$4"
161
+ _log "═══ CHECKPOINT: $type $id ($todos_done/$total) ═══"
162
+ }
@@ -0,0 +1,71 @@
1
+ #!/bin/bash
2
+ # read-settings.sh - Reads codecruise settings with proper hierarchy
3
+ #
4
+ # Priority (highest to lowest):
5
+ # 1. Environment variable (from command flags)
6
+ # 2. Project settings (.claude/settings.json)
7
+ # 3. User settings (~/.claude/settings.json)
8
+ # 4. Default value
9
+ #
10
+ # Usage:
11
+ # source ~/.claude/hooks/lib/read-settings.sh
12
+ # ENFORCE=$(get_setting "enforce" "strict")
13
+ # TDD_ENFORCE=$(get_setting "enforce_tdd" "$ENFORCE")
14
+
15
+ # Get a codecruise setting with fallback chain
16
+ # Args: $1 = setting name, $2 = default value
17
+ get_setting() {
18
+ local setting_name="$1"
19
+ local default_value="$2"
20
+
21
+ # Convert setting name to env var name (enforce -> CODECRUISE_ENFORCE)
22
+ local env_var="CODECRUISE_$(echo "$setting_name" | tr '[:lower:]' '[:upper:]')"
23
+
24
+ # 1. Check environment variable first (highest priority - from command flags)
25
+ local env_value="${!env_var}"
26
+ if [[ -n "$env_value" ]]; then
27
+ echo "$env_value"
28
+ return
29
+ fi
30
+
31
+ # 2. Check project settings (.claude/settings.json)
32
+ if [[ -f ".claude/settings.json" ]]; then
33
+ local project_value
34
+ project_value=$(jq -r ".codecruise.${setting_name} // empty" .claude/settings.json 2>/dev/null)
35
+ if [[ -n "$project_value" && "$project_value" != "null" ]]; then
36
+ echo "$project_value"
37
+ return
38
+ fi
39
+ fi
40
+
41
+ # 3. Check user settings (~/.claude/settings.json)
42
+ if [[ -f "$HOME/.claude/settings.json" ]]; then
43
+ local user_value
44
+ user_value=$(jq -r ".codecruise.${setting_name} // empty" "$HOME/.claude/settings.json" 2>/dev/null)
45
+ if [[ -n "$user_value" && "$user_value" != "null" ]]; then
46
+ echo "$user_value"
47
+ return
48
+ fi
49
+ fi
50
+
51
+ # 4. Return default
52
+ echo "$default_value"
53
+ }
54
+
55
+ # Check if enforcement is enabled for a specific check
56
+ # Args: $1 = check name (tdd, quality, criteria)
57
+ # Returns: "strict", "ask", or "off"
58
+ get_enforce_mode() {
59
+ local check_name="$1"
60
+
61
+ # Get specific setting first, fall back to global enforce
62
+ local specific_setting="enforce_${check_name}"
63
+ local global_enforce
64
+ global_enforce=$(get_setting "enforce" "strict")
65
+
66
+ get_setting "$specific_setting" "$global_enforce"
67
+ }
68
+
69
+ # Export functions for use in hooks
70
+ export -f get_setting
71
+ export -f get_enforce_mode