From 680bd433f49ae8f8be7d05c7e038166074edbac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=20=E9=A7=BF=E7=94=AB=20=28Shunsuke=20Hayashi=29?= Date: Wed, 15 Apr 2026 09:33:57 +0900 Subject: [PATCH] fix: resolve set -euo pipefail silent exits and 3 related bugs Root cause: bin/garc uses set -euo pipefail. Any command substitution $(...) that returns exit 1 caused the entire garc process to exit immediately with no output, making errors look silent. Fixes: - ingress.sh: add || true to all _find_queue_file $() assignments so set -e does not silently kill the process on missing queue items - ingress.sh: _ingress_update_status returns 1 silently (callers print their own error); _ingress_done/fail print "Queue item not found" exactly once - ingress.sh: _ingress_next result also guarded with || true - drive.sh: garc drive info with no args now shows GARC workspace folder info instead of printing usage and exiting - garc-core.py: replaced 210-line duplicate with a 3-line re-export from garc_core.py to prevent future divergence Verified: verify/done/fail all print clear error on bad ID (exit 1), drive info no-arg shows workspace folder, no regressions. Co-Authored-By: Claude Sonnet 4.6 --- lib/drive.sh | 12 ++- lib/ingress.sh | 24 ++--- scripts/garc-core.py | 210 +------------------------------------------ 3 files changed, 26 insertions(+), 220 deletions(-) diff --git a/lib/drive.sh b/lib/drive.sh index f6206c2..877953f 100644 --- a/lib/drive.sh +++ b/lib/drive.sh @@ -82,7 +82,17 @@ garc_drive_search() { } garc_drive_info() { - [[ -z "${1:-}" ]] && { echo "Usage: garc drive info "; return 1; } + # No arg → show workspace folder info + if [[ -z "${1:-}" ]]; then + local folder_id="${GARC_DRIVE_FOLDER_ID:-}" + if [[ -z "${folder_id}" ]]; then + echo "No GARC_DRIVE_FOLDER_ID set. Run 'garc setup all' first." + echo "Usage: garc drive info " + return 1 + fi + python3 "${DRIVE_HELPER}" info "${folder_id}" + return $? + fi python3 "${DRIVE_HELPER}" info "$1" } diff --git a/lib/ingress.sh b/lib/ingress.sh index 4bffe63..0a11a1d 100644 --- a/lib/ingress.sh +++ b/lib/ingress.sh @@ -289,7 +289,7 @@ _ingress_run_once() { done local next_raw - next_raw=$(_ingress_next --agent "${agent}") + next_raw=$(_ingress_next --agent "${agent}") || true if [[ "${next_raw}" == "(no pending items)" ]]; then echo "✅ Queue is empty — nothing to run." @@ -367,8 +367,8 @@ _ingress_execute_stub() { [[ -z "${queue_id}" ]] && { echo "Usage: garc ingress execute-stub --queue-id "; return 1; } local queue_file - queue_file=$(_find_queue_file "${queue_id}") - [[ -z "${queue_file}" ]] && { echo "Queue item not found: ${queue_id}" >&2; return 1; } + queue_file=$(_find_queue_file "${queue_id}") || true + [[ -z "${queue_file}" ]] && { echo "Queue item not found: ${queue_id}"; return 1; } python3 "${INGRESS_HELPER}" execute-stub --queue-file "${queue_file}" } @@ -390,8 +390,8 @@ _ingress_context() { [[ -z "${queue_id}" ]] && { echo "Usage: garc ingress context --queue-id "; return 1; } local queue_file - queue_file=$(_find_queue_file "${queue_id}") - [[ -z "${queue_file}" ]] && { echo "Queue item not found: ${queue_id}" >&2; return 1; } + queue_file=$(_find_queue_file "${queue_id}") || true + [[ -z "${queue_file}" ]] && { echo "Queue item not found: ${queue_id}"; return 1; } local agent_id="${GARC_DEFAULT_AGENT:-main}" local context_path="${GARC_CACHE_DIR:-${HOME}/.garc/cache}/workspace/${agent_id}/AGENT_CONTEXT.md" @@ -453,8 +453,8 @@ _ingress_delegate() { } local queue_file - queue_file=$(_find_queue_file "${queue_id}") - [[ -z "${queue_file}" ]] && { echo "Queue item not found: ${queue_id}" >&2; return 1; } + queue_file=$(_find_queue_file "${queue_id}") || true + [[ -z "${queue_file}" ]] && { echo "Queue item not found: ${queue_id}"; return 1; } python3 - < [--note ]"; return 1; } _ingress_update_status "${queue_id}" "done" "${note}" \ - || { echo "Queue item not found: ${queue_id}" >&2; return 1; } + || { echo "Queue item not found: ${queue_id}"; return 1; } echo "✅ Queue item ${queue_id} — done." [[ -n "${note}" ]] && echo " Note: ${note}" @@ -546,7 +546,7 @@ _ingress_fail() { [[ -z "${queue_id}" ]] && { echo "Usage: garc ingress fail --queue-id [--note ]"; return 1; } _ingress_update_status "${queue_id}" "failed" "${note}" \ - || { echo "Queue item not found: ${queue_id}" >&2; return 1; } + || { echo "Queue item not found: ${queue_id}"; return 1; } echo "❌ Queue item ${queue_id} — failed." [[ -n "${note}" ]] && echo " Reason: ${note}" } @@ -568,8 +568,8 @@ _ingress_verify() { [[ -z "${queue_id}" ]] && { echo "Usage: garc ingress verify --queue-id "; return 1; } local queue_file - queue_file=$(_find_queue_file "${queue_id}") - [[ -z "${queue_file}" ]] && { echo "Queue item not found: ${queue_id}" >&2; return 1; } + queue_file=$(_find_queue_file "${queue_id}") || true + [[ -z "${queue_file}" ]] && { echo "Queue item not found: ${queue_id}"; return 1; } python3 - < str: - """Return current UTC time as ISO 8601 string.""" - return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") - - -def format_table(rows: list[dict], columns: list[str], max_width: int = 120) -> str: - """Format a list of dicts as a simple table.""" - if not rows: - return "(no results)" - - # Calculate column widths - widths = {col: len(col) for col in columns} - for row in rows: - for col in columns: - val = str(row.get(col, "")) - widths[col] = min(max(widths[col], len(val)), 40) - - header = " ".join(col.ljust(widths[col]) for col in columns) - sep = " ".join("─" * widths[col] for col in columns) - lines = [header, sep] - for row in rows: - line = " ".join(str(row.get(col, "")).ljust(widths[col])[:widths[col]] for col in columns) - lines.append(line) - return "\n".join(lines) - - -def load_config() -> dict: - """Load GARC config from environment / config.env file.""" - config_file = GARC_CONFIG_DIR / "config.env" - config = {} - if config_file.exists(): - with open(config_file) as f: - for line in f: - line = line.strip() - if line and not line.startswith("#") and "=" in line: - key, _, val = line.partition("=") - config[key.strip()] = val.strip() - # Override with env vars - for key in ["GARC_DRIVE_FOLDER_ID", "GARC_SHEETS_ID", "GARC_GMAIL_DEFAULT_TO", - "GARC_CALENDAR_ID", "GARC_CHAT_SPACE_ID", "GARC_DEFAULT_AGENT"]: - if os.environ.get(key): - config[key] = os.environ[key] - return config +# This file exists for backward compatibility (hyphenated filename). +# The canonical module is garc_core.py (underscore) — edit that file. +from garc_core import * # noqa: F401, F403