codeharness 0.20.0 → 0.21.1

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/patches/AGENTS.md CHANGED
@@ -28,7 +28,12 @@ Semgrep YAML rules for static analysis of observability gaps. Each `.yaml` file
28
28
  - `function-no-debug-log.yaml` — Detects functions without debug/info logging (INFO)
29
29
  - `error-path-no-log.yaml` — Detects error paths (throw/return err) without preceding log (WARNING)
30
30
 
31
- **Testing:** `semgrep --test patches/observability/` runs annotated test fixtures (`.ts` files alongside rules).
31
+ **Test fixtures** (`.ts` files alongside rules, annotated with `// ruleid:` / `// ok:` comments):
32
+ - `catch-without-logging.ts` — Test cases for catch-without-logging rule
33
+ - `function-no-debug-log.ts` — Test cases for function-no-debug-log rule
34
+ - `error-path-no-log.ts` — Test cases for error-path-no-log rule
35
+
36
+ **Testing:** `semgrep --test patches/observability/` runs annotated test fixtures.
32
37
 
33
38
  **Customization:** Edit YAML rules to add custom logger patterns (e.g., `logger.error(...)` for winston). Rules use `pattern-not` / `pattern-not-inside` to detect absence of logging.
34
39
 
@@ -0,0 +1,27 @@
1
+ # patches/observability/ — Semgrep Rules for Observability Gap Detection
2
+
3
+ Standalone Semgrep YAML rules for static analysis of observability gaps. Each `.yaml` file is a complete Semgrep config — no build step, no TypeScript. Deleting a rule file removes that check.
4
+
5
+ ## Rules
6
+
7
+ | File | Purpose | Severity |
8
+ |------|---------|----------|
9
+ | catch-without-logging.yaml | Detects catch blocks without error/warn logging | WARNING |
10
+ | function-no-debug-log.yaml | Detects functions without debug/info logging | INFO |
11
+ | error-path-no-log.yaml | Detects error paths (throw/return err) without preceding log | WARNING |
12
+
13
+ ## Test Fixtures
14
+
15
+ | File | Purpose |
16
+ |------|---------|
17
+ | catch-without-logging.ts | Test cases for catch-without-logging rule (annotated with `// ruleid:` / `// ok:`) |
18
+ | function-no-debug-log.ts | Test cases for function-no-debug-log rule |
19
+ | error-path-no-log.ts | Test cases for error-path-no-log rule |
20
+
21
+ ## Testing
22
+
23
+ Run `semgrep --test patches/observability/` to execute all test fixtures against their rules.
24
+
25
+ ## Customization
26
+
27
+ Edit YAML rules to add custom logger patterns (e.g., `logger.error(...)` for winston). Rules use `pattern-not` / `pattern-not-inside` to detect absence of logging.
package/ralph/bridge.sh CHANGED
@@ -99,9 +99,9 @@ fi
99
99
 
100
100
  # ─── Sprint Status Parsing ────────────────────────────────────────────────
101
101
 
102
- # Parse sprint status YAML into an associative array
102
+ # Parse sprint status YAML into a newline-delimited key=value store
103
103
  # Maps story slug (e.g., "1-1-login-page") to status
104
- declare -A SPRINT_STATUSES
104
+ SPRINT_STATUSES=""
105
105
 
106
106
  parse_sprint_status() {
107
107
  local file="$1"
@@ -133,7 +133,8 @@ parse_sprint_status() {
133
133
  # Extract story number from slug: "1-1-login-page" -> "1.1"
134
134
  if [[ "$key" =~ ^([0-9]+)-([0-9]+) ]]; then
135
135
  local story_id="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
136
- SPRINT_STATUSES["$story_id"]="$value"
136
+ SPRINT_STATUSES="${SPRINT_STATUSES}${story_id}=${value}
137
+ "
137
138
  fi
138
139
  fi
139
140
  fi
@@ -181,8 +182,10 @@ parse_epics() {
181
182
 
182
183
  # Determine status from sprint status or default to pending
183
184
  local status="pending"
184
- if [[ -n "${SPRINT_STATUSES[$current_story_id]:-}" ]]; then
185
- status=$(map_status "${SPRINT_STATUSES[$current_story_id]}")
185
+ local _sprint_val
186
+ _sprint_val=$(echo "$SPRINT_STATUSES" | grep "^${current_story_id}=" | head -1 | cut -d= -f2-)
187
+ if [[ -n "$_sprint_val" ]]; then
188
+ status=$(map_status "$_sprint_val")
186
189
  fi
187
190
 
188
191
  # Clean up description
@@ -79,10 +79,8 @@ driver_build_command() {
79
79
  CLAUDE_CMD_ARGS+=("--plugin-dir" "$plugin_dir")
80
80
  fi
81
81
 
82
- # Output format
83
- if [[ "$CLAUDE_OUTPUT_FORMAT" == "json" ]]; then
84
- CLAUDE_CMD_ARGS+=("--output-format" "json")
85
- fi
82
+ # Output format — always stream-json for real-time NDJSON output
83
+ CLAUDE_CMD_ARGS+=("--output-format" "stream-json" "--verbose" "--include-partial-messages")
86
84
 
87
85
  # Allowed tools
88
86
  if [[ -n "$CLAUDE_ALLOWED_TOOLS" ]]; then
@@ -123,30 +121,6 @@ driver_supports_live_output() {
123
121
  return 0
124
122
  }
125
123
 
126
- # Prepare command arguments for live stream-json output
127
- driver_prepare_live_command() {
128
- LIVE_CMD_ARGS=()
129
- local skip_next=false
130
-
131
- for arg in "${CLAUDE_CMD_ARGS[@]}"; do
132
- if [[ "$skip_next" == "true" ]]; then
133
- LIVE_CMD_ARGS+=("stream-json")
134
- skip_next=false
135
- elif [[ "$arg" == "--output-format" ]]; then
136
- LIVE_CMD_ARGS+=("$arg")
137
- skip_next=true
138
- else
139
- LIVE_CMD_ARGS+=("$arg")
140
- fi
141
- done
142
-
143
- if [[ "$skip_next" == "true" ]]; then
144
- return 1
145
- fi
146
-
147
- LIVE_CMD_ARGS+=("--verbose" "--include-partial-messages")
148
- }
149
-
150
124
  # Stream filter for raw Claude stream-json events
151
125
  driver_stream_filter() {
152
126
  echo '
@@ -27,7 +27,7 @@ NC='\033[0m'
27
27
 
28
28
  init_circuit_breaker() {
29
29
  if [[ -f "$CB_STATE_FILE" ]]; then
30
- if ! jq '.' "$CB_STATE_FILE" > /dev/null 2>&1; then
30
+ if ! jq -e type "$CB_STATE_FILE" > /dev/null 2>&1; then
31
31
  rm -f "$CB_STATE_FILE"
32
32
  fi
33
33
  fi
package/ralph/ralph.sh CHANGED
@@ -47,7 +47,7 @@ RATE_LIMIT_SLEEP=3600 # 1 hour
47
47
 
48
48
  # Driver
49
49
  PLATFORM_DRIVER="${PLATFORM_DRIVER:-claude-code}"
50
- CLAUDE_OUTPUT_FORMAT="${CLAUDE_OUTPUT_FORMAT:-json}"
50
+ CLAUDE_OUTPUT_FORMAT="${CLAUDE_OUTPUT_FORMAT:-stream-json}"
51
51
  CLAUDE_ALLOWED_TOOLS="${CLAUDE_ALLOWED_TOOLS:-}"
52
52
  CLAUDE_USE_CONTINUE="${CLAUDE_USE_CONTINUE:-false}" # Fresh context per iteration by default
53
53
 
@@ -829,7 +829,8 @@ execute_iteration() {
829
829
  log_status "ERROR" "Claude API usage limit reached"
830
830
  return 2
831
831
  # Check for transient API errors (500, 529, overloaded) — don't count against story
832
- elif grep -qi "Internal server error\|api_error\|overloaded\|529\|503" "$output_file" 2>/dev/null; then
832
+ # Status code patterns exclude decimal prefixes (e.g., cost_usd=0.503 HTTP 503)
833
+ elif grep -qiE 'Internal server error|api_error|overloaded|(^|[^0-9.])529([^0-9]|$)|(^|[^0-9.])503([^0-9]|$)' "$output_file" 2>/dev/null; then
833
834
  log_status "WARN" "Transient API error (not story's fault) — will retry"
834
835
  return 4
835
836
  else
@@ -5,12 +5,19 @@ FROM node:20-slim
5
5
 
6
6
  ARG TARBALL=package.tgz
7
7
 
8
- # System utilities
8
+ # System utilities + Python for Semgrep
9
9
  RUN apt-get update && apt-get install -y --no-install-recommends \
10
10
  curl \
11
11
  jq \
12
+ python3 \
13
+ python3-pip \
14
+ pipx \
12
15
  && rm -rf /var/lib/apt/lists/*
13
16
 
17
+ # Semgrep for static analysis verification
18
+ RUN pipx install semgrep && pipx ensurepath
19
+ ENV PATH="/root/.local/bin:${PATH}"
20
+
14
21
  # Verification tools + Claude Code CLI
15
22
  RUN npm install -g showboat @anthropic-ai/claude-code
16
23