juno-code 1.0.37 → 1.0.40
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 +93 -0
- package/dist/bin/cli.js +54 -9
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +54 -9
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/templates/scripts/__pycache__/github.cpython-38.pyc +0 -0
- package/dist/templates/scripts/github.py +2383 -0
- package/dist/templates/scripts/install_requirements.sh +270 -1
- package/dist/templates/scripts/kanban.sh +3 -1
- package/dist/templates/scripts/run_until_completion.sh +44 -4
- package/dist/templates/scripts/slack_fetch.py +1 -1
- package/dist/templates/scripts/slack_respond.py +7 -5
- package/package.json +1 -1
|
@@ -23,6 +23,22 @@
|
|
|
23
23
|
|
|
24
24
|
set -euo pipefail # Exit on error, undefined variable, or pipe failure
|
|
25
25
|
|
|
26
|
+
# Handle --help early (before any debug output)
|
|
27
|
+
for arg in "$@"; do
|
|
28
|
+
if [[ "$arg" == "-h" ]] || [[ "$arg" == "--help" ]]; then
|
|
29
|
+
echo "Usage: install_requirements.sh [OPTIONS]"
|
|
30
|
+
echo ""
|
|
31
|
+
echo "Options:"
|
|
32
|
+
echo " --check-updates Only check for updates without installing"
|
|
33
|
+
echo " --force-update Force update check and upgrade packages"
|
|
34
|
+
echo " -h, --help Show this help message"
|
|
35
|
+
echo ""
|
|
36
|
+
echo "Environment Variables:"
|
|
37
|
+
echo " VERSION_CHECK_INTERVAL_HOURS Hours between automatic update checks (default: 24)"
|
|
38
|
+
exit 0
|
|
39
|
+
fi
|
|
40
|
+
done
|
|
41
|
+
|
|
26
42
|
# DEBUG OUTPUT: Show that install_requirements.sh is being executed
|
|
27
43
|
# User feedback: "Add a one line printing from .sh file as well so we could debug it"
|
|
28
44
|
echo "[DEBUG] install_requirements.sh is being executed from: $(pwd)" >&2
|
|
@@ -41,6 +57,12 @@ REQUIRED_PACKAGES=("juno-kanban" "roundtable-ai")
|
|
|
41
57
|
# Slack integration dependencies (optional, only installed when Slack scripts are used)
|
|
42
58
|
SLACK_PACKAGES=("slack_sdk" "python-dotenv")
|
|
43
59
|
|
|
60
|
+
# Version check cache configuration
|
|
61
|
+
# This ensures we don't check PyPI on every run (performance optimization per Task RTafs5)
|
|
62
|
+
VERSION_CHECK_CACHE_DIR="${HOME}/.juno_code"
|
|
63
|
+
VERSION_CHECK_CACHE_FILE="${VERSION_CHECK_CACHE_DIR}/.version_check_cache"
|
|
64
|
+
VERSION_CHECK_INTERVAL_HOURS=24 # Check for updates once per day
|
|
65
|
+
|
|
44
66
|
# Logging functions
|
|
45
67
|
log_info() {
|
|
46
68
|
echo -e "${BLUE}[INFO]${NC} $1"
|
|
@@ -70,6 +92,205 @@ check_package_installed() {
|
|
|
70
92
|
return 1 # Package not installed
|
|
71
93
|
}
|
|
72
94
|
|
|
95
|
+
# Function to get installed version of a package
|
|
96
|
+
get_installed_version() {
|
|
97
|
+
local package_name="$1"
|
|
98
|
+
local version=""
|
|
99
|
+
|
|
100
|
+
# Try python3 first, then python
|
|
101
|
+
version=$(python3 -m pip show "$package_name" 2>/dev/null | grep -i "^Version:" | awk '{print $2}')
|
|
102
|
+
if [ -z "$version" ]; then
|
|
103
|
+
version=$(python -m pip show "$package_name" 2>/dev/null | grep -i "^Version:" | awk '{print $2}')
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
echo "$version"
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
# Function to get latest version from PyPI
|
|
110
|
+
get_pypi_latest_version() {
|
|
111
|
+
local package_name="$1"
|
|
112
|
+
local version=""
|
|
113
|
+
|
|
114
|
+
# Use curl to fetch from PyPI JSON API (lightweight and fast)
|
|
115
|
+
if command -v curl &>/dev/null; then
|
|
116
|
+
version=$(curl -s --max-time 5 "https://pypi.org/pypi/${package_name}/json" 2>/dev/null | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4)
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
echo "$version"
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# Function to check if version check cache is stale
|
|
123
|
+
is_version_check_stale() {
|
|
124
|
+
# Ensure cache directory exists
|
|
125
|
+
if [ ! -d "$VERSION_CHECK_CACHE_DIR" ]; then
|
|
126
|
+
mkdir -p "$VERSION_CHECK_CACHE_DIR"
|
|
127
|
+
return 0 # No cache, needs check
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# Check if cache file exists
|
|
131
|
+
if [ ! -f "$VERSION_CHECK_CACHE_FILE" ]; then
|
|
132
|
+
return 0 # No cache file, needs check
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
# Get cache file modification time and current time
|
|
136
|
+
local cache_mtime
|
|
137
|
+
local current_time
|
|
138
|
+
local age_hours
|
|
139
|
+
|
|
140
|
+
# Cross-platform way to get file age
|
|
141
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
142
|
+
# macOS
|
|
143
|
+
cache_mtime=$(stat -f %m "$VERSION_CHECK_CACHE_FILE" 2>/dev/null || echo 0)
|
|
144
|
+
else
|
|
145
|
+
# Linux and others
|
|
146
|
+
cache_mtime=$(stat -c %Y "$VERSION_CHECK_CACHE_FILE" 2>/dev/null || echo 0)
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
current_time=$(date +%s)
|
|
150
|
+
age_hours=$(( (current_time - cache_mtime) / 3600 ))
|
|
151
|
+
|
|
152
|
+
if [ "$age_hours" -ge "$VERSION_CHECK_INTERVAL_HOURS" ]; then
|
|
153
|
+
return 0 # Cache is stale, needs check
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
return 1 # Cache is fresh, no check needed
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# Function to update version check cache
|
|
160
|
+
update_version_check_cache() {
|
|
161
|
+
local package_name="$1"
|
|
162
|
+
local installed_version="$2"
|
|
163
|
+
local latest_version="$3"
|
|
164
|
+
|
|
165
|
+
# Ensure cache directory exists
|
|
166
|
+
mkdir -p "$VERSION_CHECK_CACHE_DIR"
|
|
167
|
+
|
|
168
|
+
# Update cache file with package info
|
|
169
|
+
local cache_line="${package_name}=${installed_version}:${latest_version}"
|
|
170
|
+
|
|
171
|
+
# Remove old entry for this package if exists, then add new entry
|
|
172
|
+
if [ -f "$VERSION_CHECK_CACHE_FILE" ]; then
|
|
173
|
+
grep -v "^${package_name}=" "$VERSION_CHECK_CACHE_FILE" > "${VERSION_CHECK_CACHE_FILE}.tmp" 2>/dev/null || true
|
|
174
|
+
mv "${VERSION_CHECK_CACHE_FILE}.tmp" "$VERSION_CHECK_CACHE_FILE"
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
echo "$cache_line" >> "$VERSION_CHECK_CACHE_FILE"
|
|
178
|
+
|
|
179
|
+
# Touch the file to update modification time
|
|
180
|
+
touch "$VERSION_CHECK_CACHE_FILE"
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
# Function to check and upgrade a single package if needed
|
|
184
|
+
check_and_upgrade_package() {
|
|
185
|
+
local package_name="$1"
|
|
186
|
+
local force_check="${2:-false}"
|
|
187
|
+
|
|
188
|
+
# Only check if cache is stale or force_check is true
|
|
189
|
+
if [ "$force_check" != "true" ] && ! is_version_check_stale; then
|
|
190
|
+
log_info "Version check cache is fresh (checked within ${VERSION_CHECK_INTERVAL_HOURS}h)"
|
|
191
|
+
return 0
|
|
192
|
+
fi
|
|
193
|
+
|
|
194
|
+
log_info "Checking for updates for: $package_name"
|
|
195
|
+
|
|
196
|
+
local installed_version
|
|
197
|
+
local latest_version
|
|
198
|
+
|
|
199
|
+
installed_version=$(get_installed_version "$package_name")
|
|
200
|
+
|
|
201
|
+
if [ -z "$installed_version" ]; then
|
|
202
|
+
log_warning "$package_name is not installed"
|
|
203
|
+
return 1 # Package not installed
|
|
204
|
+
fi
|
|
205
|
+
|
|
206
|
+
latest_version=$(get_pypi_latest_version "$package_name")
|
|
207
|
+
|
|
208
|
+
if [ -z "$latest_version" ]; then
|
|
209
|
+
log_warning "Could not fetch latest version for $package_name from PyPI"
|
|
210
|
+
return 0 # Can't check, assume OK
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
# Update cache
|
|
214
|
+
update_version_check_cache "$package_name" "$installed_version" "$latest_version"
|
|
215
|
+
|
|
216
|
+
if [ "$installed_version" = "$latest_version" ]; then
|
|
217
|
+
log_success "$package_name is up-to-date (v$installed_version)"
|
|
218
|
+
return 0
|
|
219
|
+
fi
|
|
220
|
+
|
|
221
|
+
log_warning "$package_name update available: $installed_version -> $latest_version"
|
|
222
|
+
return 2 # Update available
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
# Function to upgrade packages
|
|
226
|
+
upgrade_packages() {
|
|
227
|
+
local packages_to_upgrade=("$@")
|
|
228
|
+
|
|
229
|
+
if [ ${#packages_to_upgrade[@]} -eq 0 ]; then
|
|
230
|
+
return 0
|
|
231
|
+
fi
|
|
232
|
+
|
|
233
|
+
log_info "Upgrading packages: ${packages_to_upgrade[*]}"
|
|
234
|
+
|
|
235
|
+
# Determine which package manager to use (prefer uv for speed)
|
|
236
|
+
if command -v uv &>/dev/null; then
|
|
237
|
+
for package in "${packages_to_upgrade[@]}"; do
|
|
238
|
+
log_info "Upgrading $package with uv..."
|
|
239
|
+
if uv pip install --upgrade "$package" --quiet 2>/dev/null; then
|
|
240
|
+
log_success "Upgraded: $package"
|
|
241
|
+
else
|
|
242
|
+
log_warning "Failed to upgrade $package with uv, trying pip..."
|
|
243
|
+
python3 -m pip install --upgrade "$package" --quiet 2>/dev/null || true
|
|
244
|
+
fi
|
|
245
|
+
done
|
|
246
|
+
elif command -v pipx &>/dev/null && is_externally_managed_python && ! is_in_virtualenv; then
|
|
247
|
+
for package in "${packages_to_upgrade[@]}"; do
|
|
248
|
+
log_info "Upgrading $package with pipx..."
|
|
249
|
+
if pipx upgrade "$package" 2>/dev/null; then
|
|
250
|
+
log_success "Upgraded: $package"
|
|
251
|
+
else
|
|
252
|
+
log_warning "Failed to upgrade $package"
|
|
253
|
+
fi
|
|
254
|
+
done
|
|
255
|
+
else
|
|
256
|
+
for package in "${packages_to_upgrade[@]}"; do
|
|
257
|
+
log_info "Upgrading $package with pip..."
|
|
258
|
+
if python3 -m pip install --upgrade "$package" --quiet 2>/dev/null; then
|
|
259
|
+
log_success "Upgraded: $package"
|
|
260
|
+
else
|
|
261
|
+
log_warning "Failed to upgrade $package"
|
|
262
|
+
fi
|
|
263
|
+
done
|
|
264
|
+
fi
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
# Function to check all packages for updates (periodic check)
|
|
268
|
+
check_all_for_updates() {
|
|
269
|
+
local force_check="${1:-false}"
|
|
270
|
+
local packages_needing_upgrade=()
|
|
271
|
+
|
|
272
|
+
# Skip check if cache is fresh and not forcing
|
|
273
|
+
if [ "$force_check" != "true" ] && ! is_version_check_stale; then
|
|
274
|
+
return 0
|
|
275
|
+
fi
|
|
276
|
+
|
|
277
|
+
log_info "Performing periodic version check..."
|
|
278
|
+
|
|
279
|
+
for package in "${REQUIRED_PACKAGES[@]}"; do
|
|
280
|
+
check_and_upgrade_package "$package" "true"
|
|
281
|
+
local result=$?
|
|
282
|
+
if [ $result -eq 2 ]; then
|
|
283
|
+
packages_needing_upgrade+=("$package")
|
|
284
|
+
fi
|
|
285
|
+
done
|
|
286
|
+
|
|
287
|
+
if [ ${#packages_needing_upgrade[@]} -gt 0 ]; then
|
|
288
|
+
upgrade_packages "${packages_needing_upgrade[@]}"
|
|
289
|
+
else
|
|
290
|
+
log_success "All packages are up-to-date"
|
|
291
|
+
fi
|
|
292
|
+
}
|
|
293
|
+
|
|
73
294
|
# Function to check if all requirements are satisfied
|
|
74
295
|
check_all_requirements_satisfied() {
|
|
75
296
|
local all_satisfied=true
|
|
@@ -366,10 +587,52 @@ install_with_pip() {
|
|
|
366
587
|
|
|
367
588
|
# Main installation logic
|
|
368
589
|
main() {
|
|
590
|
+
local force_update=false
|
|
591
|
+
local check_updates_only=false
|
|
592
|
+
|
|
593
|
+
# Parse command line arguments (--help is handled early, before debug output)
|
|
594
|
+
while [[ $# -gt 0 ]]; do
|
|
595
|
+
case $1 in
|
|
596
|
+
--force-update)
|
|
597
|
+
force_update=true
|
|
598
|
+
shift
|
|
599
|
+
;;
|
|
600
|
+
--check-updates)
|
|
601
|
+
check_updates_only=true
|
|
602
|
+
shift
|
|
603
|
+
;;
|
|
604
|
+
*)
|
|
605
|
+
shift
|
|
606
|
+
;;
|
|
607
|
+
esac
|
|
608
|
+
done
|
|
609
|
+
|
|
369
610
|
echo ""
|
|
370
611
|
log_info "=== Python Requirements Installation ==="
|
|
371
612
|
echo ""
|
|
372
613
|
|
|
614
|
+
# Handle --check-updates: just check and report, don't install
|
|
615
|
+
if [ "$check_updates_only" = true ]; then
|
|
616
|
+
log_info "Checking for updates..."
|
|
617
|
+
for package in "${REQUIRED_PACKAGES[@]}"; do
|
|
618
|
+
local installed_ver
|
|
619
|
+
local latest_ver
|
|
620
|
+
installed_ver=$(get_installed_version "$package")
|
|
621
|
+
latest_ver=$(get_pypi_latest_version "$package")
|
|
622
|
+
|
|
623
|
+
if [ -z "$installed_ver" ]; then
|
|
624
|
+
log_warning "$package is not installed"
|
|
625
|
+
elif [ -z "$latest_ver" ]; then
|
|
626
|
+
log_info "$package: v$installed_ver (could not check PyPI)"
|
|
627
|
+
elif [ "$installed_ver" = "$latest_ver" ]; then
|
|
628
|
+
log_success "$package: v$installed_ver (up-to-date)"
|
|
629
|
+
else
|
|
630
|
+
log_warning "$package: v$installed_ver -> v$latest_ver (update available)"
|
|
631
|
+
fi
|
|
632
|
+
done
|
|
633
|
+
exit 0
|
|
634
|
+
fi
|
|
635
|
+
|
|
373
636
|
# Step 1: Check if all requirements are already satisfied
|
|
374
637
|
log_info "Checking if requirements are already satisfied..."
|
|
375
638
|
|
|
@@ -378,9 +641,15 @@ main() {
|
|
|
378
641
|
echo ""
|
|
379
642
|
log_info "Installed packages:"
|
|
380
643
|
for package in "${REQUIRED_PACKAGES[@]}"; do
|
|
381
|
-
|
|
644
|
+
local ver
|
|
645
|
+
ver=$(get_installed_version "$package")
|
|
646
|
+
echo " ✓ $package (v$ver)"
|
|
382
647
|
done
|
|
383
648
|
echo ""
|
|
649
|
+
|
|
650
|
+
# Step 1b: Periodic update check (only when cache is stale, or forced)
|
|
651
|
+
# This ensures dependencies stay up-to-date without degrading performance
|
|
652
|
+
check_all_for_updates "$force_update"
|
|
384
653
|
exit 0
|
|
385
654
|
fi
|
|
386
655
|
|
|
@@ -183,8 +183,10 @@ main() {
|
|
|
183
183
|
log_success "Python environment ready!"
|
|
184
184
|
|
|
185
185
|
# Execute juno-kanban with all passed arguments from project root
|
|
186
|
+
# Close stdin (redirect from /dev/null) to prevent hanging when called from tools
|
|
187
|
+
# that don't provide stdin (similar to Issue #42 hook fix)
|
|
186
188
|
log_info "Executing juno-kanban: $*"
|
|
187
|
-
|
|
189
|
+
juno-kanban "$@" < /dev/null
|
|
188
190
|
}
|
|
189
191
|
|
|
190
192
|
# Run main function with all arguments
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
# Example: ./.juno_task/scripts/run_until_completion.sh -b shell -s claude -m :opus
|
|
16
16
|
# Example: ./.juno_task/scripts/run_until_completion.sh --pre-run "./slack/sync.sh" -s claude -i 5
|
|
17
17
|
# Example: ./.juno_task/scripts/run_until_completion.sh --pre-run-hook START_ITERATION -s claude -i 5
|
|
18
|
+
# Example: ./.juno_task/scripts/run_until_completion.sh --pre-run-hook "SYNC_SLACK,VALIDATE" -s claude -i 5
|
|
19
|
+
# Example: ./.juno_task/scripts/run_until_completion.sh --pre-run-hook "HOOK1|HOOK2|HOOK3" -s claude -i 5
|
|
18
20
|
#
|
|
19
21
|
# Options (for run_until_completion.sh):
|
|
20
22
|
# --pre-run <cmd> - Execute command before entering the main loop
|
|
@@ -27,7 +29,10 @@
|
|
|
27
29
|
# The hook should be defined in config.json under "hooks"
|
|
28
30
|
# with a "commands" array. All commands in the hook are
|
|
29
31
|
# executed before the main loop.
|
|
30
|
-
#
|
|
32
|
+
# Multiple hooks can be specified by:
|
|
33
|
+
# - Using the flag multiple times: --pre-run-hook A --pre-run-hook B
|
|
34
|
+
# - Comma-separated: --pre-run-hook "A,B,C"
|
|
35
|
+
# - Pipe-separated: --pre-run-hook "A|B|C"
|
|
31
36
|
#
|
|
32
37
|
# All other arguments are forwarded to juno-code.
|
|
33
38
|
# The script shows all stdout/stderr from juno-code in real-time.
|
|
@@ -86,7 +91,24 @@ parse_arguments() {
|
|
|
86
91
|
echo "[ERROR] $1 requires a hook name argument" >&2
|
|
87
92
|
exit 1
|
|
88
93
|
fi
|
|
89
|
-
|
|
94
|
+
# Support multiple hooks via comma or pipe separator
|
|
95
|
+
# e.g., --pre-run-hook "HOOK1,HOOK2" or --pre-run-hook "HOOK1|HOOK2"
|
|
96
|
+
local hook_value="$2"
|
|
97
|
+
if [[ "$hook_value" == *","* ]] || [[ "$hook_value" == *"|"* ]]; then
|
|
98
|
+
# Replace pipes with commas, then split on commas
|
|
99
|
+
local normalized="${hook_value//|/,}"
|
|
100
|
+
IFS=',' read -ra hook_names <<< "$normalized"
|
|
101
|
+
for hook_name in "${hook_names[@]}"; do
|
|
102
|
+
# Trim whitespace
|
|
103
|
+
hook_name="${hook_name#"${hook_name%%[![:space:]]*}"}"
|
|
104
|
+
hook_name="${hook_name%"${hook_name##*[![:space:]]}"}"
|
|
105
|
+
if [[ -n "$hook_name" ]]; then
|
|
106
|
+
PRE_RUN_HOOKS+=("$hook_name")
|
|
107
|
+
fi
|
|
108
|
+
done
|
|
109
|
+
else
|
|
110
|
+
PRE_RUN_HOOKS+=("$hook_value")
|
|
111
|
+
fi
|
|
90
112
|
shift 2
|
|
91
113
|
;;
|
|
92
114
|
*)
|
|
@@ -103,9 +125,27 @@ parse_arguments() {
|
|
|
103
125
|
fi
|
|
104
126
|
|
|
105
127
|
# Also check JUNO_PRE_RUN_HOOK environment variable
|
|
128
|
+
# Supports comma or pipe separated hooks: JUNO_PRE_RUN_HOOK="HOOK1,HOOK2|HOOK3"
|
|
106
129
|
if [[ -n "${JUNO_PRE_RUN_HOOK:-}" ]]; then
|
|
107
|
-
|
|
108
|
-
|
|
130
|
+
local env_hooks=()
|
|
131
|
+
local hook_value="${JUNO_PRE_RUN_HOOK}"
|
|
132
|
+
if [[ "$hook_value" == *","* ]] || [[ "$hook_value" == *"|"* ]]; then
|
|
133
|
+
# Replace pipes with commas, then split on commas
|
|
134
|
+
local normalized="${hook_value//|/,}"
|
|
135
|
+
IFS=',' read -ra hook_names <<< "$normalized"
|
|
136
|
+
for hook_name in "${hook_names[@]}"; do
|
|
137
|
+
# Trim whitespace
|
|
138
|
+
hook_name="${hook_name#"${hook_name%%[![:space:]]*}"}"
|
|
139
|
+
hook_name="${hook_name%"${hook_name##*[![:space:]]}"}"
|
|
140
|
+
if [[ -n "$hook_name" ]]; then
|
|
141
|
+
env_hooks+=("$hook_name")
|
|
142
|
+
fi
|
|
143
|
+
done
|
|
144
|
+
else
|
|
145
|
+
env_hooks+=("$hook_value")
|
|
146
|
+
fi
|
|
147
|
+
# Prepend env var hooks (runs first)
|
|
148
|
+
PRE_RUN_HOOKS=("${env_hooks[@]}" "${PRE_RUN_HOOKS[@]}")
|
|
109
149
|
fi
|
|
110
150
|
}
|
|
111
151
|
|
|
@@ -493,7 +493,7 @@ Generating a Slack Bot Token:
|
|
|
493
493
|
Full tutorial: """ + SLACK_TOKEN_DOCS_URL + """
|
|
494
494
|
|
|
495
495
|
Example .env file:
|
|
496
|
-
SLACK_BOT_TOKEN=xoxb-
|
|
496
|
+
SLACK_BOT_TOKEN=xoxb-YOUR-BOT-TOKEN-HERE
|
|
497
497
|
SLACK_CHANNEL=bug-reports
|
|
498
498
|
CHECK_INTERVAL_SECONDS=120
|
|
499
499
|
LOG_LEVEL=INFO
|
|
@@ -71,7 +71,8 @@ def setup_logging(verbose: bool = False) -> None:
|
|
|
71
71
|
def get_kanban_tasks(
|
|
72
72
|
kanban_script: str,
|
|
73
73
|
tag: Optional[str] = None,
|
|
74
|
-
status: Optional[str] = None
|
|
74
|
+
status: Optional[str] = None,
|
|
75
|
+
limit: int = 10000
|
|
75
76
|
) -> List[Dict[str, Any]]:
|
|
76
77
|
"""
|
|
77
78
|
Get kanban tasks from the kanban.sh script.
|
|
@@ -80,11 +81,12 @@ def get_kanban_tasks(
|
|
|
80
81
|
kanban_script: Path to kanban.sh script
|
|
81
82
|
tag: Optional tag to filter by
|
|
82
83
|
status: Optional status to filter by
|
|
84
|
+
limit: Maximum number of tasks to retrieve (default: 10000 to ensure all tasks)
|
|
83
85
|
|
|
84
86
|
Returns:
|
|
85
87
|
List of task dicts
|
|
86
88
|
"""
|
|
87
|
-
cmd = [kanban_script, 'list']
|
|
89
|
+
cmd = [kanban_script, 'list', '--limit', str(limit)]
|
|
88
90
|
|
|
89
91
|
if tag:
|
|
90
92
|
cmd.extend(['--tag', tag])
|
|
@@ -328,7 +330,7 @@ def send_slack_response(
|
|
|
328
330
|
Response message timestamp if sent, None if failed
|
|
329
331
|
"""
|
|
330
332
|
# Format the response with task ID
|
|
331
|
-
formatted_response = f"**
|
|
333
|
+
formatted_response = f"**[task_id]{task_id}[/task_id]**\n\n{response_text}"
|
|
332
334
|
|
|
333
335
|
if dry_run:
|
|
334
336
|
logger.info(f"[DRY RUN] Would send to channel {channel_id}, thread {thread_ts}:")
|
|
@@ -460,7 +462,7 @@ Generating a Slack Bot Token:
|
|
|
460
462
|
Full tutorial: """ + SLACK_TOKEN_DOCS_URL + """
|
|
461
463
|
|
|
462
464
|
Example .env file:
|
|
463
|
-
SLACK_BOT_TOKEN=xoxb-
|
|
465
|
+
SLACK_BOT_TOKEN=xoxb-YOUR-BOT-TOKEN-HERE
|
|
464
466
|
LOG_LEVEL=INFO
|
|
465
467
|
""")
|
|
466
468
|
print("=" * 70 + "\n")
|
|
@@ -650,7 +652,7 @@ Environment Variables:
|
|
|
650
652
|
Notes:
|
|
651
653
|
- Only sends responses for tasks with non-empty agent_response
|
|
652
654
|
- Matches tasks to Slack messages by task_id or body text
|
|
653
|
-
- Responses are prefixed with "**
|
|
655
|
+
- Responses are prefixed with "**[task_id]{id}[/task_id]**"
|
|
654
656
|
- Tracks sent responses in .juno_task/slack/responses_sent.ndjson
|
|
655
657
|
"""
|
|
656
658
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "juno-code",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.40",
|
|
4
4
|
"description": "Ralph Wiggum meet Kanban! Ralph style execution for [Claude Code, Codex, Gemini, Cursor]. One task per iteration, automatic progress tracking, and git commits. Set it and let it run.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ralph",
|