@openlife/cli 1.7.11 → 1.7.12
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/dist/cli/ChatBanner.js +112 -0
- package/dist/cli/ChatTui.js +316 -0
- package/dist/cli/ConfigTui.js +418 -0
- package/dist/cli/MatrixRain.js +141 -0
- package/dist/cli/MatrixTheme.js +86 -0
- package/dist/cli/ProviderSelector.js +178 -0
- package/dist/index.js +40 -1
- package/dist/orchestrator/Brain.js +17 -11
- package/dist/orchestrator/Gateway.js +64 -0
- package/dist/test_chat_tui.js +116 -0
- package/dist/test_config_tui.js +116 -0
- package/dist/test_matrix_rain.js +69 -0
- package/package.json +5 -2
- package/scripts/reauth-providers.sh +205 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openlife/cli",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.12",
|
|
4
4
|
"description": "OPEN-LIFE Córtex Orquestrador Dual-Core",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -159,8 +159,11 @@
|
|
|
159
159
|
"test:status-command": "npm run build && node dist/test_status_command.js",
|
|
160
160
|
"test:logs-command": "npm run build && node dist/test_logs_command.js",
|
|
161
161
|
"test:agent-creator": "npm run build && node dist/test_agent_creator.js",
|
|
162
|
+
"test:matrix-rain": "npm run build && node dist/test_matrix_rain.js",
|
|
163
|
+
"test:chat-tui": "npm run build && node dist/test_chat_tui.js",
|
|
164
|
+
"test:config-tui": "npm run build && node dist/test_config_tui.js",
|
|
162
165
|
"pretest:all": "node scripts/clean-test-pollution.js",
|
|
163
|
-
"test:all": "npm run build && node dist/test_distribution_installability.js && node dist/test_orchestration_assets_lifecycle.js && node dist/test_openlife_runtime_source_truth.js && node dist/test_openlife_evolution_surface.js && node dist/test_openlife_routing_surface.js && node dist/test_openlife_auto_creator_routing.js && node dist/test_openlife_gatekeeper_routing.js && node dist/test_enterprise_agentic_core.js && node dist/test_admin_teams_networks.js && node dist/test_agent_team_skill_network.js && node dist/test_benchmark_engine.js && node dist/test_cli_service_commands.js && node dist/test_consequence_forecaster.js && node dist/test_conversation_memory.js && node dist/test_create_entities.js && node dist/test_designmd_import_registry.js && node dist/test_designmd_mode.js && node dist/test_designmd_mode_workspace.js && node dist/test_dream_organizer.js && node dist/test_dual_mode.js && node dist/test_governance.js && node dist/test_governance_advanced.js && node dist/test_install_flow.js && node dist/test_job_lifecycle.js && node dist/test_memory_orchestrator.js && node dist/test_memory_promotion.js && node dist/test_memory_retention.js && node dist/test_operating_system.js && node dist/test_optimization_loop.js && node dist/test_outcome_simulator.js && node dist/test_performance_scorecard.js && node dist/test_phase6_board.js && node dist/test_phase6_cadence.js && node dist/test_phase6_ops.js && node dist/test_release_gate.js && node dist/test_reversa_contracts_e2e.js && node dist/test_reversa_export_and_strict.js && node dist/test_reversa_full_execution.js && node dist/test_reversa_lite.js && node dist/test_runtime_policy.js && node dist/test_runtime_probe.js && node dist/test_runtime_registry.js && node dist/test_security_download_guard.js && node dist/test_service_command_surface.js && node dist/test_service_completion_policy.js && node dist/test_service_guardrails_delete.js && node dist/test_sources_import_ref.js && node dist/test_sources_scaffold.js && node dist/test_teammate_learning.js && node dist/test_telegram_delete_guardrail.js && node dist/test_daemon_sigterm.js && node dist/test_ask_exit.js && node dist/test_brain_error_diagnostics.js && node dist/test_cli_doc_parity.js && node dist/test_trigger_basic_auth.js && node dist/test_brain_fallback_chain.js && node dist/test_cli_help_surface.js && node dist/test_cli_diagnostics.js && node dist/test_cli_crud_roundtrip.js && node dist/test_subsystems_routing_governance.js && node dist/test_subsystems_org_state.js && node dist/test_subsystems_promotion_memory_assets.js && node dist/test_phase1_check_exit.js && node dist/test_install_flow_host_validation.js && node dist/test_dist_templates_layout.js && node dist/test_host_installer.js && node dist/test_host_uninstaller.js && node dist/test_install_wizard.js && node dist/test_multi_host_docs_parity.js && node dist/test_host_install_e2e.js && node dist/test_runtime_profile_oauth_only.js && node dist/test_atomic_writer.js && node dist/test_mission_checkpoint.js && node dist/test_workflow_parser.js && node dist/test_workflow_engine.js && node dist/test_workflow_e2e.js && node dist/test_distributed_lock.js && node dist/test_watchdog_heartbeat.js && node dist/test_runtime_health_backoff.js && node dist/test_queue_scheduler.js && node dist/test_squad_skill_creator.js && node dist/test_aiobuilder_cli_parity.js && node dist/test_catalog_quality.js && node dist/test_royal_stack_golden.js && node dist/test_capability_pack_schema.js && node dist/test_capability_genesis_engine.js && node dist/test_workflow_schema_backward_compat.js && node dist/test_service_mode_explicit_only.js && node dist/test_deep_research_capability.js && node dist/test_guided_creator_cli.js && node dist/test_governance_v13_policies.js && node dist/test_gateway_telegram_guardrails.js && node dist/test_cron_manager.js && node dist/test_profile_toolset_mcp.js && node dist/test_squad_skill_design_llm.js && node dist/test_workflow_condition_parser.js && node dist/test_security_download_and_scan.js && node dist/test_host_installers_gemini_codex.js && node dist/test_toolset_enforcement.js && node dist/test_creator_placeholders_completed.js && node dist/test_performance_latency.js && node dist/test_post_mission_evaluation.js && node dist/test_governance_scope_ledger.js && node dist/test_consequence_forecast_brain.js && node dist/test_remote_publish.js && node dist/test_process_sandbox.js && node dist/test_v15_e2e_integration.js && node dist/test_doctor_sandbox_check.js && node dist/test_task_executor_sandbox_optin.js && node dist/test_forecast_brain_wiring.js && node dist/test_status_command.js && node dist/test_logs_command.js && node dist/test_agent_creator.js",
|
|
166
|
+
"test:all": "npm run build && node dist/test_distribution_installability.js && node dist/test_orchestration_assets_lifecycle.js && node dist/test_openlife_runtime_source_truth.js && node dist/test_openlife_evolution_surface.js && node dist/test_openlife_routing_surface.js && node dist/test_openlife_auto_creator_routing.js && node dist/test_openlife_gatekeeper_routing.js && node dist/test_enterprise_agentic_core.js && node dist/test_admin_teams_networks.js && node dist/test_agent_team_skill_network.js && node dist/test_benchmark_engine.js && node dist/test_cli_service_commands.js && node dist/test_consequence_forecaster.js && node dist/test_conversation_memory.js && node dist/test_create_entities.js && node dist/test_designmd_import_registry.js && node dist/test_designmd_mode.js && node dist/test_designmd_mode_workspace.js && node dist/test_dream_organizer.js && node dist/test_dual_mode.js && node dist/test_governance.js && node dist/test_governance_advanced.js && node dist/test_install_flow.js && node dist/test_job_lifecycle.js && node dist/test_memory_orchestrator.js && node dist/test_memory_promotion.js && node dist/test_memory_retention.js && node dist/test_operating_system.js && node dist/test_optimization_loop.js && node dist/test_outcome_simulator.js && node dist/test_performance_scorecard.js && node dist/test_phase6_board.js && node dist/test_phase6_cadence.js && node dist/test_phase6_ops.js && node dist/test_release_gate.js && node dist/test_reversa_contracts_e2e.js && node dist/test_reversa_export_and_strict.js && node dist/test_reversa_full_execution.js && node dist/test_reversa_lite.js && node dist/test_runtime_policy.js && node dist/test_runtime_probe.js && node dist/test_runtime_registry.js && node dist/test_security_download_guard.js && node dist/test_service_command_surface.js && node dist/test_service_completion_policy.js && node dist/test_service_guardrails_delete.js && node dist/test_sources_import_ref.js && node dist/test_sources_scaffold.js && node dist/test_teammate_learning.js && node dist/test_telegram_delete_guardrail.js && node dist/test_daemon_sigterm.js && node dist/test_ask_exit.js && node dist/test_brain_error_diagnostics.js && node dist/test_cli_doc_parity.js && node dist/test_trigger_basic_auth.js && node dist/test_brain_fallback_chain.js && node dist/test_cli_help_surface.js && node dist/test_cli_diagnostics.js && node dist/test_cli_crud_roundtrip.js && node dist/test_subsystems_routing_governance.js && node dist/test_subsystems_org_state.js && node dist/test_subsystems_promotion_memory_assets.js && node dist/test_phase1_check_exit.js && node dist/test_install_flow_host_validation.js && node dist/test_dist_templates_layout.js && node dist/test_host_installer.js && node dist/test_host_uninstaller.js && node dist/test_install_wizard.js && node dist/test_multi_host_docs_parity.js && node dist/test_host_install_e2e.js && node dist/test_runtime_profile_oauth_only.js && node dist/test_atomic_writer.js && node dist/test_mission_checkpoint.js && node dist/test_workflow_parser.js && node dist/test_workflow_engine.js && node dist/test_workflow_e2e.js && node dist/test_distributed_lock.js && node dist/test_watchdog_heartbeat.js && node dist/test_runtime_health_backoff.js && node dist/test_queue_scheduler.js && node dist/test_squad_skill_creator.js && node dist/test_aiobuilder_cli_parity.js && node dist/test_catalog_quality.js && node dist/test_royal_stack_golden.js && node dist/test_capability_pack_schema.js && node dist/test_capability_genesis_engine.js && node dist/test_workflow_schema_backward_compat.js && node dist/test_service_mode_explicit_only.js && node dist/test_deep_research_capability.js && node dist/test_guided_creator_cli.js && node dist/test_governance_v13_policies.js && node dist/test_gateway_telegram_guardrails.js && node dist/test_cron_manager.js && node dist/test_profile_toolset_mcp.js && node dist/test_squad_skill_design_llm.js && node dist/test_workflow_condition_parser.js && node dist/test_security_download_and_scan.js && node dist/test_host_installers_gemini_codex.js && node dist/test_toolset_enforcement.js && node dist/test_creator_placeholders_completed.js && node dist/test_performance_latency.js && node dist/test_post_mission_evaluation.js && node dist/test_governance_scope_ledger.js && node dist/test_consequence_forecast_brain.js && node dist/test_remote_publish.js && node dist/test_process_sandbox.js && node dist/test_v15_e2e_integration.js && node dist/test_doctor_sandbox_check.js && node dist/test_task_executor_sandbox_optin.js && node dist/test_forecast_brain_wiring.js && node dist/test_status_command.js && node dist/test_logs_command.js && node dist/test_agent_creator.js && node dist/test_matrix_rain.js && node dist/test_chat_tui.js && node dist/test_config_tui.js",
|
|
164
167
|
"prepublishOnly": "npm run test:all",
|
|
165
168
|
"test:no-automatic-messages": "npm run build && node dist/test_no_automatic_messages.js",
|
|
166
169
|
"test:gateway-fast-ack": "npm run build && node dist/test_gateway_fast_ack.js"
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# scripts/reauth-providers.sh
|
|
3
|
+
# Guided re-authentication for OpenLife LLM providers: Codex (gpt-5.5), Gemini, Anthropic.
|
|
4
|
+
# Idempotent. Per-provider menu (reauth/skip/edit-key). Validates each via real API call.
|
|
5
|
+
# Restarts daemon if running. Final status table.
|
|
6
|
+
|
|
7
|
+
set -u
|
|
8
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
9
|
+
cd "$ROOT"
|
|
10
|
+
|
|
11
|
+
# Matrix-green ANSI palette (matches the new TUI theme)
|
|
12
|
+
GREEN=$'\033[38;5;46m'
|
|
13
|
+
GREEN_HI=$'\033[38;5;82m\033[1m'
|
|
14
|
+
GREEN_DIM=$'\033[38;5;22m'
|
|
15
|
+
RED=$'\033[38;5;196m'
|
|
16
|
+
YELLOW=$'\033[38;5;226m'
|
|
17
|
+
RESET=$'\033[0m'
|
|
18
|
+
|
|
19
|
+
say() { printf '%s%s%s\n' "$GREEN" "$*" "$RESET"; }
|
|
20
|
+
hi() { printf '%s%s%s\n' "$GREEN_HI" "$*" "$RESET"; }
|
|
21
|
+
warn() { printf '%s%s%s\n' "$YELLOW" "$*" "$RESET"; }
|
|
22
|
+
err() { printf '%s%s%s\n' "$RED" "$*" "$RESET" 1>&2; }
|
|
23
|
+
hr() { printf '%s' "$GREEN_DIM"; printf '─%.0s' $(seq 1 60); printf '%s\n' "$RESET"; }
|
|
24
|
+
|
|
25
|
+
# ─────────────────────────────────────────────────────────────
|
|
26
|
+
# Probe — current credential state
|
|
27
|
+
# ─────────────────────────────────────────────────────────────
|
|
28
|
+
probe_codex() {
|
|
29
|
+
command -v codex >/dev/null 2>&1 || { echo "missing"; return; }
|
|
30
|
+
if codex login status 2>/dev/null | grep -qi 'logged in'; then
|
|
31
|
+
# Cached status doesn't guarantee the refresh token is valid. Do a 8s probe.
|
|
32
|
+
if timeout 8 codex exec --model gpt-5.5 --skip-git-repo-check 'OK' >/dev/null 2>&1; then
|
|
33
|
+
echo "ok"
|
|
34
|
+
else
|
|
35
|
+
echo "stale"
|
|
36
|
+
fi
|
|
37
|
+
else
|
|
38
|
+
echo "logged-out"
|
|
39
|
+
fi
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
probe_gemini() {
|
|
43
|
+
command -v gemini >/dev/null 2>&1 || { echo "missing"; return; }
|
|
44
|
+
if gemini login status 2>/dev/null | grep -qi 'logged in'; then
|
|
45
|
+
echo "ok"
|
|
46
|
+
else
|
|
47
|
+
echo "logged-out"
|
|
48
|
+
fi
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
probe_anthropic() {
|
|
52
|
+
local key
|
|
53
|
+
key="$(grep -E '^ANTHROPIC_API_KEY=' "$ROOT/.env" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
|
|
54
|
+
if [[ -z "$key" ]]; then echo "missing"; return; fi
|
|
55
|
+
local code
|
|
56
|
+
code="$(curl -sS -o /dev/null -w '%{http_code}' --max-time 8 \
|
|
57
|
+
-H "x-api-key: $key" -H "anthropic-version: 2023-06-01" \
|
|
58
|
+
-H "content-type: application/json" \
|
|
59
|
+
-d '{"model":"claude-haiku-4-5","max_tokens":4,"messages":[{"role":"user","content":"ok"}]}' \
|
|
60
|
+
https://api.anthropic.com/v1/messages 2>/dev/null || echo 000)"
|
|
61
|
+
case "$code" in
|
|
62
|
+
200) echo "ok" ;;
|
|
63
|
+
401|403) echo "auth-bad" ;;
|
|
64
|
+
429) echo "rate-limited" ;;
|
|
65
|
+
*) echo "http-$code" ;;
|
|
66
|
+
esac
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
print_status_table() {
|
|
70
|
+
hr
|
|
71
|
+
printf '%s%-12s %-12s %s%s\n' "$GREEN_HI" "PROVIDER" "STATUS" "DETAIL" "$RESET"
|
|
72
|
+
hr
|
|
73
|
+
printf '%-12s %-12s %s\n' "codex" "$1" "(gpt-5.5 via Codex OAuth)"
|
|
74
|
+
printf '%-12s %-12s %s\n' "gemini" "$2" "(google-genai OAuth)"
|
|
75
|
+
printf '%-12s %-12s %s\n' "anthropic" "$3" "(ANTHROPIC_API_KEY in .env)"
|
|
76
|
+
hr
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# ─────────────────────────────────────────────────────────────
|
|
80
|
+
# Per-provider menus
|
|
81
|
+
# ─────────────────────────────────────────────────────────────
|
|
82
|
+
menu_for() {
|
|
83
|
+
local name="$1" status="$2"
|
|
84
|
+
echo
|
|
85
|
+
hi "── $name ──"
|
|
86
|
+
echo " current status: $status"
|
|
87
|
+
echo " 1) reauth 2) skip 3) edit key (anthropic only)"
|
|
88
|
+
read -r -p " choose [1/2/3]: " choice
|
|
89
|
+
echo "$choice"
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
reauth_codex() {
|
|
93
|
+
say "Logging out of Codex…"
|
|
94
|
+
codex logout 2>/dev/null || true
|
|
95
|
+
hi "Opening Codex login (browser). Complete the flow, then press ENTER here."
|
|
96
|
+
codex login || { err "codex login failed"; return 1; }
|
|
97
|
+
if timeout 12 codex exec --model gpt-5.5 --skip-git-repo-check 'OK' >/dev/null 2>&1; then
|
|
98
|
+
hi "✓ codex gpt-5.5 responding"
|
|
99
|
+
return 0
|
|
100
|
+
fi
|
|
101
|
+
err "codex still failing after login. Inspect: codex login status"
|
|
102
|
+
return 1
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
reauth_gemini() {
|
|
106
|
+
say "Logging out of Gemini…"
|
|
107
|
+
gemini logout 2>/dev/null || true
|
|
108
|
+
hi "Opening Gemini login (device-auth). Follow on-screen URL, then return."
|
|
109
|
+
gemini login --device-auth || { err "gemini login failed"; return 1; }
|
|
110
|
+
hi "✓ gemini login completed (quota state checked on next call)"
|
|
111
|
+
return 0
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
reauth_anthropic_edit_key() {
|
|
115
|
+
echo
|
|
116
|
+
warn "Paste your ANTHROPIC_API_KEY (sk-ant-…). Input is hidden."
|
|
117
|
+
read -r -s -p " key: " newkey
|
|
118
|
+
echo
|
|
119
|
+
[[ -z "$newkey" ]] && { warn "(empty — keeping current key)"; return 0; }
|
|
120
|
+
# Idempotent .env edit: remove existing line then append.
|
|
121
|
+
local envfile="$ROOT/.env"
|
|
122
|
+
touch "$envfile"
|
|
123
|
+
grep -v -E '^ANTHROPIC_API_KEY=' "$envfile" > "$envfile.tmp" 2>/dev/null || true
|
|
124
|
+
mv "$envfile.tmp" "$envfile"
|
|
125
|
+
printf 'ANTHROPIC_API_KEY=%s\n' "$newkey" >> "$envfile"
|
|
126
|
+
say "✓ .env updated"
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
# ─────────────────────────────────────────────────────────────
|
|
130
|
+
# Daemon restart helper
|
|
131
|
+
# ─────────────────────────────────────────────────────────────
|
|
132
|
+
maybe_restart_daemon() {
|
|
133
|
+
local snapshot
|
|
134
|
+
snapshot="$(node bin/openlife.js status 2>/dev/null || echo '{}')"
|
|
135
|
+
if echo "$snapshot" | grep -q '"fresh":true'; then
|
|
136
|
+
say "Daemon is running — restarting to pick up new credentials…"
|
|
137
|
+
node bin/openlife.js restart >/dev/null 2>&1 || true
|
|
138
|
+
nohup node bin/openlife.js start --daemon >/dev/null 2>&1 &
|
|
139
|
+
disown 2>/dev/null || true
|
|
140
|
+
# Give it 3 seconds to boot + revalidate executors
|
|
141
|
+
sleep 3
|
|
142
|
+
say "✓ daemon restarted"
|
|
143
|
+
else
|
|
144
|
+
say "Daemon not running — skipping restart"
|
|
145
|
+
fi
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
# ─────────────────────────────────────────────────────────────
|
|
149
|
+
# Main
|
|
150
|
+
# ─────────────────────────────────────────────────────────────
|
|
151
|
+
hi "╔══════════════════════════════════════════════════════════╗"
|
|
152
|
+
hi "║ OPENLIFE · provider reauth ║"
|
|
153
|
+
hi "╚══════════════════════════════════════════════════════════╝"
|
|
154
|
+
say "Probing current credentials…"
|
|
155
|
+
|
|
156
|
+
CODEX="$(probe_codex)"
|
|
157
|
+
GEMINI="$(probe_gemini)"
|
|
158
|
+
ANTHROPIC="$(probe_anthropic)"
|
|
159
|
+
print_status_table "$CODEX" "$GEMINI" "$ANTHROPIC"
|
|
160
|
+
|
|
161
|
+
# Codex
|
|
162
|
+
case "$CODEX" in ok) say "codex already healthy — skipping menu" ;; *)
|
|
163
|
+
case "$(menu_for codex "$CODEX")" in
|
|
164
|
+
1) reauth_codex && CODEX=ok || CODEX=failed ;;
|
|
165
|
+
2) say "(skipped)" ;;
|
|
166
|
+
*) say "(skipped)" ;;
|
|
167
|
+
esac
|
|
168
|
+
;; esac
|
|
169
|
+
|
|
170
|
+
# Gemini
|
|
171
|
+
case "$GEMINI" in ok) say "gemini already healthy — skipping menu" ;; *)
|
|
172
|
+
case "$(menu_for gemini "$GEMINI")" in
|
|
173
|
+
1) reauth_gemini && GEMINI=ok || GEMINI=failed ;;
|
|
174
|
+
2) say "(skipped)" ;;
|
|
175
|
+
*) say "(skipped)" ;;
|
|
176
|
+
esac
|
|
177
|
+
;; esac
|
|
178
|
+
|
|
179
|
+
# Anthropic
|
|
180
|
+
case "$ANTHROPIC" in ok) say "anthropic already healthy — skipping menu" ;; *)
|
|
181
|
+
case "$(menu_for anthropic "$ANTHROPIC")" in
|
|
182
|
+
1|3) reauth_anthropic_edit_key
|
|
183
|
+
ANTHROPIC="$(probe_anthropic)" ;;
|
|
184
|
+
2) say "(skipped)" ;;
|
|
185
|
+
*) say "(skipped)" ;;
|
|
186
|
+
esac
|
|
187
|
+
;; esac
|
|
188
|
+
|
|
189
|
+
# Final state
|
|
190
|
+
echo
|
|
191
|
+
hi "── final state ──"
|
|
192
|
+
print_status_table "$CODEX" "$GEMINI" "$ANTHROPIC"
|
|
193
|
+
|
|
194
|
+
# Restart daemon if running so executors revalidate
|
|
195
|
+
maybe_restart_daemon
|
|
196
|
+
|
|
197
|
+
# Show status snapshot
|
|
198
|
+
echo
|
|
199
|
+
hi "── openlife status ──"
|
|
200
|
+
node bin/openlife.js status 2>/dev/null \
|
|
201
|
+
| node -e 'let d="";process.stdin.on("data",c=>d+=c).on("end",()=>{try{const j=JSON.parse(d);console.log("heartbeat fresh:",j.heartbeat&&j.heartbeat.fresh);(j.executors||[]).forEach(e=>console.log(` ${e.executor.padEnd(8)} avail=${e.available} reason=${e.reason}`));}catch(e){console.error("status parse failed");}});' \
|
|
202
|
+
2>/dev/null || warn "status command unavailable"
|
|
203
|
+
|
|
204
|
+
# Exit code: 0 if at least one provider is ok
|
|
205
|
+
[[ "$CODEX" == "ok" || "$GEMINI" == "ok" || "$ANTHROPIC" == "ok" ]] && exit 0 || exit 1
|