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.
- package/README.md +1 -1
- package/dist/bin/cli.js +658 -50
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +658 -50
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -4
- package/dist/index.mjs.map +1 -1
- package/dist/templates/scripts/__pycache__/attachment_downloader.cpython-38.pyc +0 -0
- package/dist/templates/scripts/__pycache__/github.cpython-38.pyc +0 -0
- package/dist/templates/scripts/__pycache__/slack_fetch.cpython-38.pyc +0 -0
- package/dist/templates/scripts/__pycache__/slack_state.cpython-38.pyc +0 -0
- package/dist/templates/scripts/attachment_downloader.py +405 -0
- package/dist/templates/scripts/github.py +282 -7
- package/dist/templates/scripts/hooks/session_counter.sh +328 -0
- package/dist/templates/scripts/kanban.sh +22 -4
- package/dist/templates/scripts/log_scanner.sh +790 -0
- package/dist/templates/scripts/slack_fetch.py +232 -20
- package/dist/templates/services/claude.py +50 -1
- package/dist/templates/services/codex.py +5 -4
- package/dist/templates/skills/claude/.gitkeep +0 -0
- package/dist/templates/skills/claude/plan-kanban-tasks/SKILL.md +25 -0
- package/dist/templates/skills/claude/ralph-loop/SKILL.md +43 -0
- package/dist/templates/skills/claude/ralph-loop/references/first_check.md +20 -0
- package/dist/templates/skills/claude/ralph-loop/references/implement.md +99 -0
- package/dist/templates/skills/claude/ralph-loop/scripts/kanban.sh +293 -0
- package/dist/templates/skills/claude/understand-project/SKILL.md +39 -0
- package/dist/templates/skills/codex/.gitkeep +0 -0
- package/dist/templates/skills/codex/ralph-loop/SKILL.md +43 -0
- package/dist/templates/skills/codex/ralph-loop/references/first_check.md +20 -0
- package/dist/templates/skills/codex/ralph-loop/references/implement.md +99 -0
- package/dist/templates/skills/codex/ralph-loop/scripts/kanban.sh +293 -0
- 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
|
-
|
|
271
|
-
|
|
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
|