Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions autoplan/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,7 @@ elif ! _gstack_codex_auth_probe >/dev/null; then
_CODEX_AVAILABLE=false
else
_gstack_codex_version_check # non-blocking warn if known-bad
_gstack_codex_update_check # non-blocking INFO if npm 'latest' is ahead
_CODEX_AVAILABLE=true
fi
```
Expand Down
1 change: 1 addition & 0 deletions autoplan/SKILL.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ elif ! _gstack_codex_auth_probe >/dev/null; then
_CODEX_AVAILABLE=false
else
_gstack_codex_version_check # non-blocking warn if known-bad
_gstack_codex_update_check # non-blocking INFO if npm 'latest' is ahead
_CODEX_AVAILABLE=true
fi
```
Expand Down
43 changes: 42 additions & 1 deletion bin/gstack-codex-probe
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# Functions (all prefixed with _gstack_codex_ for namespace hygiene):
# _gstack_codex_auth_probe — multi-signal auth check (env + file)
# _gstack_codex_version_check — warn on known-bad Codex CLI versions
# _gstack_codex_update_check — INFO when an npm `latest` is available (24h cache)
# _gstack_codex_timeout_wrapper — gtimeout -> timeout -> unwrapped fallback
# _gstack_codex_log_event — telemetry emission to ~/.gstack/analytics/
#
Expand Down Expand Up @@ -49,6 +50,46 @@ _gstack_codex_version_check() {
fi
}

# --- Update check -----------------------------------------------------------

_gstack_codex_update_check() {
# Compare installed Codex CLI against the npm `latest` tag. Print one INFO
# line when an upgrade is available. Cached for 24h at
# ${GSTACK_HOME:-$HOME/.gstack}/.codex-version-check so /ship invocations
# don't hammer the registry. Best-effort: any failure (no codex, no curl,
# no jq, offline, slow registry, malformed JSON) is silent — never blocks.
local _local _latest _cache _cache_dir _now _mtime _age
_local=$(codex --version 2>/dev/null | head -1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
[ -z "$_local" ] && return 0
_cache_dir="${GSTACK_HOME:-$HOME/.gstack}"
_cache="$_cache_dir/.codex-version-check"
_now=$(date +%s 2>/dev/null || echo 0)
if [ -f "$_cache" ]; then
_mtime=$(stat -c %Y "$_cache" 2>/dev/null || stat -f %m "$_cache" 2>/dev/null || echo 0)
_age=$((_now - _mtime))
if [ "$_age" -lt 86400 ]; then
_latest=$(head -1 "$_cache" 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
fi
fi
if [ -z "$_latest" ]; then
command -v curl >/dev/null 2>&1 || return 0
command -v jq >/dev/null 2>&1 || return 0
_latest=$(curl -fsSL -m 5 https://registry.npmjs.org/@openai/codex/latest 2>/dev/null \
| jq -r '.version' 2>/dev/null \
| grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
[ -z "$_latest" ] && return 0
mkdir -p "$_cache_dir" 2>/dev/null
printf '%s\n' "$_latest" > "$_cache" 2>/dev/null || true
fi
# If local already wins (or ties) sort -V, there's nothing to upgrade to.
local _winner
_winner=$(printf '%s\n%s\n' "$_local" "$_latest" | sort -V 2>/dev/null | tail -1)
if [ -n "$_winner" ] && [ "$_winner" != "$_local" ]; then
echo "INFO: Codex CLI $_local available: $_latest. Upgrade: \`npm install -g @openai/codex@latest\`"
_gstack_codex_log_event "codex_update_available"
fi
}

# --- Timeout wrapper --------------------------------------------------------

_gstack_codex_timeout_wrapper() {
Expand All @@ -72,7 +113,7 @@ _gstack_codex_log_event() {
# Emit a telemetry event to ~/.gstack/analytics/skill-usage.jsonl.
# Gated on $_TEL != "off" (caller sets this from gstack-config).
# Event types: codex_timeout, codex_auth_failed, codex_cli_missing,
# codex_version_warning.
# codex_version_warning, codex_update_available.
# Payload schema: {skill, event, duration_s, ts}. NEVER includes prompt
# content, env var values, or auth tokens.
local _event="$1"
Expand Down
6 changes: 5 additions & 1 deletion codex/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -822,13 +822,17 @@ if ! _gstack_codex_auth_probe >/dev/null; then
echo "AUTH_FAILED"
fi
_gstack_codex_version_check # warns if known-bad, non-blocking
_gstack_codex_update_check # INFO if npm 'latest' is ahead, non-blocking
```

If the output contains `AUTH_FAILED`, stop and tell the user:
"No Codex authentication found. Run `codex login` or set `$CODEX_API_KEY` / `$OPENAI_API_KEY`, then re-run this skill."

If the version check printed a `WARN:` line, pass it through to the user verbatim
(non-blocking — Codex may still work, but the user should upgrade).
(non-blocking — Codex may still work, but the user should upgrade). If
`_gstack_codex_update_check` printed an `INFO:` line, pass that through too — it
means a newer Codex CLI is on npm and the user can run `npm install -g
@openai/codex@latest` to pick it up.

The probe multi-signal auth logic accepts: `$CODEX_API_KEY` set, `$OPENAI_API_KEY`
set, or `${CODEX_HOME:-~/.codex}/auth.json` exists. Avoids false-negatives for
Expand Down
6 changes: 5 additions & 1 deletion codex/SKILL.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,17 @@ if ! _gstack_codex_auth_probe >/dev/null; then
echo "AUTH_FAILED"
fi
_gstack_codex_version_check # warns if known-bad, non-blocking
_gstack_codex_update_check # INFO if npm 'latest' is ahead, non-blocking
```

If the output contains `AUTH_FAILED`, stop and tell the user:
"No Codex authentication found. Run `codex login` or set `$CODEX_API_KEY` / `$OPENAI_API_KEY`, then re-run this skill."

If the version check printed a `WARN:` line, pass it through to the user verbatim
(non-blocking — Codex may still work, but the user should upgrade).
(non-blocking — Codex may still work, but the user should upgrade). If
`_gstack_codex_update_check` printed an `INFO:` line, pass that through too — it
means a newer Codex CLI is on npm and the user can run `npm install -g
@openai/codex@latest` to pick it up.

The probe multi-signal auth logic accepts: `$CODEX_API_KEY` set, `$OPENAI_API_KEY`
set, or `${CODEX_HOME:-~/.codex}/auth.json` exists. Avoids false-negatives for
Expand Down
6 changes: 6 additions & 0 deletions review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -1593,12 +1593,18 @@ DIFF_INS=$(git diff "$DIFF_BASE" --stat | tail -1 | grep -oE '[0-9]+ insertion'
DIFF_DEL=$(git diff "$DIFF_BASE" --stat | tail -1 | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo "0")
DIFF_TOTAL=$((DIFF_INS + DIFF_DEL))
command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
# Surface known-bad versions and any pending npm 'latest' upgrade. Both
# non-blocking — they print one line each, or stay silent on a clean install.
source ~/.claude/skills/gstack/bin/gstack-codex-probe 2>/dev/null \
&& { _gstack_codex_version_check; _gstack_codex_update_check; } || true
# Legacy opt-out — only gates Codex passes, Claude always runs
OLD_CFG=$(~/.claude/skills/gstack/bin/gstack-config get codex_reviews 2>/dev/null || true)
echo "DIFF_SIZE: $DIFF_TOTAL"
echo "OLD_CFG: ${OLD_CFG:-not_set}"
```

If either probe line surfaces (WARN for known-bad, INFO for upgrade-available), pass it through to the user verbatim. Neither blocks the workflow.

If `OLD_CFG` is `disabled`: skip Codex passes only. Claude adversarial subagent still runs (it's free and fast). Jump to the "Claude adversarial subagent" section.

**User override:** If the user explicitly requested "full review", "structured review", or "P1 gate", also run the Codex structured review regardless of diff size.
Expand Down
3 changes: 3 additions & 0 deletions scripts/resolvers/design.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export function generateDesignReviewLite(ctx: TemplateContext): string {

\`\`\`bash
command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
# Surface known-bad versions + pending npm upgrade. Both non-blocking.
source ~/.claude/skills/gstack/bin/gstack-codex-probe 2>/dev/null \\
&& { _gstack_codex_version_check; _gstack_codex_update_check; } || true
\`\`\`

If Codex is available, run a lightweight design check on the diff:
Expand Down
6 changes: 6 additions & 0 deletions scripts/resolvers/review.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,12 +472,18 @@ DIFF_INS=$(git diff "$DIFF_BASE" --stat | tail -1 | grep -oE '[0-9]+ insertion'
DIFF_DEL=$(git diff "$DIFF_BASE" --stat | tail -1 | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo "0")
DIFF_TOTAL=$((DIFF_INS + DIFF_DEL))
command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
# Surface known-bad versions and any pending npm 'latest' upgrade. Both
# non-blocking — they print one line each, or stay silent on a clean install.
source ~/.claude/skills/gstack/bin/gstack-codex-probe 2>/dev/null \\
&& { _gstack_codex_version_check; _gstack_codex_update_check; } || true
# Legacy opt-out — only gates Codex passes, Claude always runs
OLD_CFG=$(~/.claude/skills/gstack/bin/gstack-config get codex_reviews 2>/dev/null || true)
echo "DIFF_SIZE: $DIFF_TOTAL"
echo "OLD_CFG: \${OLD_CFG:-not_set}"
\`\`\`

If either probe line surfaces (WARN for known-bad, INFO for upgrade-available), pass it through to the user verbatim. Neither blocks the workflow.

If \`OLD_CFG\` is \`disabled\`: skip Codex passes only. Claude adversarial subagent still runs (it's free and fast). Jump to the "Claude adversarial subagent" section.

**User override:** If the user explicitly requested "full review", "structured review", or "P1 gate", also run the Codex structured review regardless of diff size.
Expand Down
6 changes: 6 additions & 0 deletions ship/sections/adversarial.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ DIFF_INS=$(git diff "$DIFF_BASE" --stat | tail -1 | grep -oE '[0-9]+ insertion'
DIFF_DEL=$(git diff "$DIFF_BASE" --stat | tail -1 | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo "0")
DIFF_TOTAL=$((DIFF_INS + DIFF_DEL))
command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
# Surface known-bad versions and any pending npm 'latest' upgrade. Both
# non-blocking — they print one line each, or stay silent on a clean install.
source ~/.claude/skills/gstack/bin/gstack-codex-probe 2>/dev/null \
&& { _gstack_codex_version_check; _gstack_codex_update_check; } || true
# Legacy opt-out — only gates Codex passes, Claude always runs
OLD_CFG=$(~/.claude/skills/gstack/bin/gstack-config get codex_reviews 2>/dev/null || true)
echo "DIFF_SIZE: $DIFF_TOTAL"
echo "OLD_CFG: ${OLD_CFG:-not_set}"
```

If either probe line surfaces (WARN for known-bad, INFO for upgrade-available), pass it through to the user verbatim. Neither blocks the workflow.

If `OLD_CFG` is `disabled`: skip Codex passes only. Claude adversarial subagent still runs (it's free and fast). Jump to the "Claude adversarial subagent" section.

**User override:** If the user explicitly requested "full review", "structured review", or "P1 gate", also run the Codex structured review regardless of diff size.
Expand Down
3 changes: 3 additions & 0 deletions ship/sections/review-army.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ Substitute: TIMESTAMP = ISO 8601 datetime, STATUS = "clean" if 0 findings or "is

```bash
command -v codex >/dev/null 2>&1 && echo "CODEX_AVAILABLE" || echo "CODEX_NOT_AVAILABLE"
# Surface known-bad versions + pending npm upgrade. Both non-blocking.
source ~/.claude/skills/gstack/bin/gstack-codex-probe 2>/dev/null \
&& { _gstack_codex_version_check; _gstack_codex_update_check; } || true
```

If Codex is available, run a lightweight design check on the diff:
Expand Down
Loading