juno-code 1.0.44 → 1.0.46

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 (34) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/cli.js +658 -50
  3. package/dist/bin/cli.js.map +1 -1
  4. package/dist/bin/cli.mjs +658 -50
  5. package/dist/bin/cli.mjs.map +1 -1
  6. package/dist/index.js +6 -4
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +6 -4
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/templates/scripts/__pycache__/attachment_downloader.cpython-38.pyc +0 -0
  11. package/dist/templates/scripts/__pycache__/github.cpython-38.pyc +0 -0
  12. package/dist/templates/scripts/__pycache__/slack_fetch.cpython-38.pyc +0 -0
  13. package/dist/templates/scripts/__pycache__/slack_state.cpython-38.pyc +0 -0
  14. package/dist/templates/scripts/attachment_downloader.py +405 -0
  15. package/dist/templates/scripts/github.py +282 -7
  16. package/dist/templates/scripts/hooks/session_counter.sh +328 -0
  17. package/dist/templates/scripts/kanban.sh +22 -4
  18. package/dist/templates/scripts/log_scanner.sh +790 -0
  19. package/dist/templates/scripts/slack_fetch.py +232 -20
  20. package/dist/templates/services/claude.py +50 -1
  21. package/dist/templates/services/codex.py +5 -4
  22. package/dist/templates/skills/claude/.gitkeep +0 -0
  23. package/dist/templates/skills/claude/plan-kanban-tasks/SKILL.md +25 -0
  24. package/dist/templates/skills/claude/ralph-loop/SKILL.md +43 -0
  25. package/dist/templates/skills/claude/ralph-loop/references/first_check.md +20 -0
  26. package/dist/templates/skills/claude/ralph-loop/references/implement.md +99 -0
  27. package/dist/templates/skills/claude/ralph-loop/scripts/kanban.sh +293 -0
  28. package/dist/templates/skills/claude/understand-project/SKILL.md +39 -0
  29. package/dist/templates/skills/codex/.gitkeep +0 -0
  30. package/dist/templates/skills/codex/ralph-loop/SKILL.md +43 -0
  31. package/dist/templates/skills/codex/ralph-loop/references/first_check.md +20 -0
  32. package/dist/templates/skills/codex/ralph-loop/references/implement.md +99 -0
  33. package/dist/templates/skills/codex/ralph-loop/scripts/kanban.sh +293 -0
  34. package/package.json +3 -2
@@ -0,0 +1,328 @@
1
+ #!/bin/bash
2
+ # session_counter.sh - Claude Code hook for tracking session message count
3
+ #
4
+ # This hook counts messages in a Claude Code session and warns when the session
5
+ # becomes lengthy (long conversations = lower performance = higher cost).
6
+ #
7
+ # Usage as a Claude Code hook:
8
+ # Configure in one of the following settings files:
9
+ #
10
+ # 1. Global settings: ~/.claude/settings.json
11
+ # (Applies to all projects for this user)
12
+ #
13
+ # 2. Project settings: $PROJECT_DIR/.claude/settings.json
14
+ # (Shared project settings, checked into version control)
15
+ #
16
+ # 3. Local settings: $PROJECT_DIR/.claude/settings.local.json
17
+ # (User-specific overrides, NOT checked into version control)
18
+ #
19
+ # Add this hook configuration:
20
+ # {
21
+ # "hooks": {
22
+ # "PreToolUse": [
23
+ # {
24
+ # "hooks": [
25
+ # {
26
+ # "type": "command",
27
+ # "command": "\"$CLAUDE_PROJECT_DIR\"/.juno_task/scripts/hooks/session_counter.sh --threshold 100"
28
+ # }
29
+ # ]
30
+ # }
31
+ # ]
32
+ # }
33
+ # }
34
+ #
35
+ # Environment Variables:
36
+ # JUNO_SESSION_COUNTER_THRESHOLD - Threshold for warning (default: 100)
37
+ # JUNO_SESSION_COUNTER_DIR - Directory for counter files (default: /tmp/juno_session_counters)
38
+ #
39
+ # Arguments:
40
+ # --threshold N, -t N Set warning threshold (overrides ENV)
41
+ # --reset Reset counter for current session
42
+ # --status Show current counter value without incrementing
43
+ # --help, -h Show this help message
44
+ #
45
+ # Exit Codes:
46
+ # 0 - Always (hooks should not block on counting)
47
+ #
48
+ # Output:
49
+ # When threshold is exceeded, outputs JSON to stdout for Claude to see:
50
+ # {
51
+ # "hookSpecificOutput": {
52
+ # "hookEventName": "PreToolUse",
53
+ # "additionalContext": "SESSION_LENGTH_WARNING: ..."
54
+ # }
55
+ # }
56
+ #
57
+
58
+ set -e
59
+
60
+ VERSION="1.0.0"
61
+
62
+ # Default values
63
+ DEFAULT_THRESHOLD=100
64
+ DEFAULT_COUNTER_DIR="/tmp/juno_session_counters"
65
+
66
+ # Parse environment variables with defaults
67
+ THRESHOLD="${JUNO_SESSION_COUNTER_THRESHOLD:-$DEFAULT_THRESHOLD}"
68
+ COUNTER_DIR="${JUNO_SESSION_COUNTER_DIR:-$DEFAULT_COUNTER_DIR}"
69
+
70
+ # Command mode flags
71
+ RESET_MODE=false
72
+ STATUS_MODE=false
73
+
74
+ show_help() {
75
+ cat << 'HELPEOF'
76
+ session_counter.sh - Claude Code hook for session length monitoring
77
+
78
+ SYNOPSIS
79
+ session_counter.sh [OPTIONS]
80
+
81
+ DESCRIPTION
82
+ This hook counts user prompts in a Claude Code session and warns Claude
83
+ when the session becomes too long. Long sessions lead to:
84
+
85
+ - Higher API costs (more tokens in context)
86
+ - Lower performance (context window limits)
87
+ - Potential loss of context coherence
88
+
89
+ When the threshold is exceeded, the hook outputs a JSON message that
90
+ Claude Code injects as context, reminding Claude to wrap up and save
91
+ progress to kanban/plan.md.
92
+
93
+ OPTIONS
94
+ --threshold N, -t N
95
+ Set the message count threshold for warnings.
96
+ Default: 100 (or JUNO_SESSION_COUNTER_THRESHOLD env var)
97
+
98
+ --reset
99
+ Reset the counter for the current session to 0.
100
+ Reads session_id from stdin JSON.
101
+
102
+ --status
103
+ Show current counter status without incrementing.
104
+ Useful for debugging and monitoring.
105
+
106
+ --help, -h
107
+ Show this help message.
108
+
109
+ ENVIRONMENT VARIABLES
110
+ JUNO_SESSION_COUNTER_THRESHOLD
111
+ Default threshold value. Default: 100
112
+
113
+ JUNO_SESSION_COUNTER_DIR
114
+ Directory for state files. Default: /tmp/juno_session_counters
115
+
116
+ JUNO_DEBUG
117
+ Set to any value to enable debug logging to stderr.
118
+
119
+ HOOK CONFIGURATION
120
+ Claude Code settings files (in order of precedence, highest first):
121
+
122
+ 1. Local settings: $PROJECT_DIR/.claude/settings.local.json
123
+ - User-specific overrides, NOT checked into version control
124
+ - Best for personal preferences that shouldn't affect team
125
+
126
+ 2. Project settings: $PROJECT_DIR/.claude/settings.json
127
+ - Shared project settings, checked into version control
128
+ - Best for team-wide hooks and configurations
129
+
130
+ 3. Global settings: ~/.claude/settings.json
131
+ - Applies to all projects for this user
132
+ - Best for user preferences across all projects
133
+
134
+ Add this hook configuration to any of the above files:
135
+
136
+ {
137
+ "hooks": {
138
+ "PreToolUse": [
139
+ {
140
+ "hooks": [
141
+ {
142
+ "type": "command",
143
+ "command": "\"$CLAUDE_PROJECT_DIR\"/.juno_task/scripts/hooks/session_counter.sh --threshold 100"
144
+ }
145
+ ]
146
+ }
147
+ ]
148
+ }
149
+ }
150
+
151
+ Note: PreToolUse fires before each tool invocation, providing more
152
+ granular tracking than UserPromptSubmit (which fires per user message).
153
+
154
+ MANUAL TESTING
155
+ # Test with mock input
156
+ echo '{"session_id":"test123","prompt":"hello"}' | ./session_counter.sh -t 5
157
+
158
+ # Check status
159
+ echo '{"session_id":"test123"}' | ./session_counter.sh --status
160
+
161
+ # Reset counter
162
+ echo '{"session_id":"test123"}' | ./session_counter.sh --reset
163
+
164
+ EXIT CODES
165
+ Always exits 0 to ensure the hook never blocks Claude Code.
166
+ Errors are logged to stderr but don't affect exit status.
167
+
168
+ OUTPUT BEHAVIOR
169
+ Under threshold: No output (silent counting)
170
+ At/over threshold: JSON with additionalContext warning message
171
+
172
+ The warning message instructs Claude to:
173
+ 1. Save remaining tasks to kanban (./.juno_task/scripts/kanban.sh)
174
+ 2. Update plan.md with progress
175
+ 3. Commit completed work
176
+ 4. Update CLAUDE.md with learnings
177
+ 5. Finish current task and stop
178
+
179
+ VERSION
180
+ 1.0.0
181
+
182
+ SEE ALSO
183
+ Claude Code hooks: https://code.claude.com/docs/en/hooks
184
+ HELPEOF
185
+ }
186
+
187
+ # Parse arguments
188
+ while [[ $# -gt 0 ]]; do
189
+ case $1 in
190
+ --threshold|-t)
191
+ if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then
192
+ THRESHOLD="$2"
193
+ shift 2
194
+ else
195
+ echo "Error: --threshold requires a numeric value" >&2
196
+ exit 0
197
+ fi
198
+ ;;
199
+ --reset)
200
+ RESET_MODE=true
201
+ shift
202
+ ;;
203
+ --status)
204
+ STATUS_MODE=true
205
+ shift
206
+ ;;
207
+ --help|-h)
208
+ show_help
209
+ exit 0
210
+ ;;
211
+ --version)
212
+ echo "session_counter.sh version $VERSION"
213
+ exit 0
214
+ ;;
215
+ *)
216
+ # Unknown option, skip silently for hook compatibility
217
+ shift
218
+ ;;
219
+ esac
220
+ done
221
+
222
+ # Ensure counter directory exists
223
+ mkdir -p "$COUNTER_DIR" 2>/dev/null || true
224
+
225
+ # Read JSON input from stdin (Claude Code hook input)
226
+ INPUT_JSON=""
227
+ if [[ ! -t 0 ]]; then
228
+ INPUT_JSON=$(cat)
229
+ fi
230
+
231
+ # Extract session_id from hook input using multiple methods for robustness
232
+ SESSION_ID=""
233
+ if [[ -n "$INPUT_JSON" ]]; then
234
+ # Try jq first (most reliable)
235
+ if command -v jq &>/dev/null; then
236
+ SESSION_ID=$(echo "$INPUT_JSON" | jq -r '.session_id // empty' 2>/dev/null || true)
237
+ fi
238
+
239
+ # Fallback to grep/sed if jq didn't work
240
+ if [[ -z "$SESSION_ID" ]]; then
241
+ SESSION_ID=$(echo "$INPUT_JSON" | grep -o '"session_id"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"//' | sed 's/"$//' || true)
242
+ fi
243
+ fi
244
+
245
+ # Fallback to environment variable if no session_id in input
246
+ if [[ -z "$SESSION_ID" ]]; then
247
+ SESSION_ID="${CLAUDE_SESSION_ID:-unknown}"
248
+ fi
249
+
250
+ # Create a safe filename from session_id
251
+ SAFE_SESSION_ID=$(echo "$SESSION_ID" | tr -cd '[:alnum:]_-')
252
+ COUNTER_FILE="$COUNTER_DIR/session_${SAFE_SESSION_ID}.count"
253
+
254
+ # Handle reset mode
255
+ if [[ "$RESET_MODE" == "true" ]]; then
256
+ if [[ -f "$COUNTER_FILE" ]]; then
257
+ rm "$COUNTER_FILE"
258
+ echo "Counter reset for session: $SESSION_ID" >&2
259
+ else
260
+ echo "No counter found for session: $SESSION_ID" >&2
261
+ fi
262
+ exit 0
263
+ fi
264
+
265
+ # Read current counter
266
+ CURRENT_COUNT=0
267
+ if [[ -f "$COUNTER_FILE" ]]; then
268
+ CURRENT_COUNT=$(cat "$COUNTER_FILE" 2>/dev/null || echo "0")
269
+ # Ensure it's a valid number
270
+ if ! [[ "$CURRENT_COUNT" =~ ^[0-9]+$ ]]; then
271
+ CURRENT_COUNT=0
272
+ fi
273
+ fi
274
+
275
+ # Handle status mode (don't increment)
276
+ if [[ "$STATUS_MODE" == "true" ]]; then
277
+ echo "Session: $SESSION_ID" >&2
278
+ echo "Message count: $CURRENT_COUNT" >&2
279
+ echo "Threshold: $THRESHOLD" >&2
280
+ if [[ $CURRENT_COUNT -ge $THRESHOLD ]]; then
281
+ echo "Status: THRESHOLD EXCEEDED" >&2
282
+ else
283
+ REMAINING=$((THRESHOLD - CURRENT_COUNT))
284
+ echo "Status: OK ($REMAINING messages until warning)" >&2
285
+ fi
286
+ exit 0
287
+ fi
288
+
289
+ # Increment counter
290
+ NEW_COUNT=$((CURRENT_COUNT + 1))
291
+ echo "$NEW_COUNT" > "$COUNTER_FILE"
292
+
293
+ # Check if threshold exceeded
294
+ if [[ $NEW_COUNT -ge $THRESHOLD ]]; then
295
+ # Calculate how much over threshold
296
+ OVER_BY=$((NEW_COUNT - THRESHOLD))
297
+
298
+ # Determine severity based on how far over threshold
299
+ SEVERITY="WARNING"
300
+ if [[ $OVER_BY -ge $((THRESHOLD / 2)) ]]; then
301
+ SEVERITY="CRITICAL"
302
+ elif [[ $OVER_BY -ge 10 ]]; then
303
+ SEVERITY="HIGH"
304
+ fi
305
+
306
+ # Create the warning message - this will be injected as context for Claude
307
+ WARNING_MESSAGE="SESSION_LENGTH_WARNING [$SEVERITY]: This session has reached $NEW_COUNT tool calls (threshold: $THRESHOLD). Long sessions reduce performance and increase costs. Please complete your current work as soon as possible: 1) Save any remaining tasks to kanban using './.juno_task/scripts/kanban.sh' 2) Update plan.md with current progress 3) Commit any completed work 4) Update CLAUDE.md with important learnings 5) Finish the current task and stop. A new session can continue where this one left off."
308
+
309
+ # Output JSON for Claude to see via additionalContext
310
+ # This format is recognized by Claude Code's PreToolUse hook handler
311
+ cat << EOF
312
+ {
313
+ "hookSpecificOutput": {
314
+ "hookEventName": "PreToolUse",
315
+ "additionalContext": "$WARNING_MESSAGE"
316
+ }
317
+ }
318
+ EOF
319
+ else
320
+ # Under threshold - no output needed
321
+ # Debug logging if enabled
322
+ if [[ -n "${JUNO_DEBUG:-}" ]]; then
323
+ echo "[session_counter] Session $SESSION_ID: message $NEW_COUNT of $THRESHOLD" >&2
324
+ fi
325
+ fi
326
+
327
+ # Always exit 0 - hooks should not block Claude Code
328
+ exit 0
@@ -260,15 +260,33 @@ main() {
260
260
  fi
261
261
 
262
262
  # Execute juno-kanban with normalized arguments from project root
263
- # Close stdin (redirect from /dev/null) to prevent hanging when called from tools
264
- # that don't provide stdin (similar to Issue #42 hook fix)
265
263
  # Build the command properly preserving argument quoting
266
264
  log_info "Executing juno-kanban with normalized arguments"
267
265
 
268
266
  # Execute with proper array expansion to preserve quoting
269
267
  # Use ${arr[@]+"${arr[@]}"} pattern to handle empty arrays with set -u
270
- juno-kanban ${NORMALIZED_GLOBAL_FLAGS[@]+"${NORMALIZED_GLOBAL_FLAGS[@]}"} \
271
- ${NORMALIZED_COMMAND_ARGS[@]+"${NORMALIZED_COMMAND_ARGS[@]}"} < /dev/null
268
+ #
269
+ # Stdin handling:
270
+ # Detect the type of stdin to determine whether to pass it through or redirect from /dev/null:
271
+ # - 'p' (pipe): Pass through - user is piping data (e.g., echo "..." | kanban.sh create)
272
+ # - '-' (regular file): Pass through - user is using heredoc (kanban.sh create << 'EOF')
273
+ # - 'c' (character device) or other: Redirect from /dev/null to prevent hanging
274
+ # when called from tools that don't provide stdin (Issue #42, #60)
275
+ #
276
+ # The first character of `ls -la /dev/fd/0` indicates the file type:
277
+ # p = pipe, - = regular file, c = character device, l = symlink, etc.
278
+ local stdin_type
279
+ stdin_type=$(ls -la /dev/fd/0 2>/dev/null | cut -c1)
280
+
281
+ if [[ "$stdin_type" == "p" || "$stdin_type" == "-" ]]; then
282
+ # stdin is a pipe or regular file (heredoc) - pass it through
283
+ juno-kanban ${NORMALIZED_GLOBAL_FLAGS[@]+"${NORMALIZED_GLOBAL_FLAGS[@]}"} \
284
+ ${NORMALIZED_COMMAND_ARGS[@]+"${NORMALIZED_COMMAND_ARGS[@]}"}
285
+ else
286
+ # stdin is a character device or unknown - redirect from /dev/null to prevent hanging
287
+ juno-kanban ${NORMALIZED_GLOBAL_FLAGS[@]+"${NORMALIZED_GLOBAL_FLAGS[@]}"} \
288
+ ${NORMALIZED_COMMAND_ARGS[@]+"${NORMALIZED_COMMAND_ARGS[@]}"} < /dev/null
289
+ fi
272
290
  }
273
291
 
274
292
  # Run main function with all arguments