subconscious-cli 0.3.0 → 4.0.0

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.
@@ -50,8 +50,8 @@ set -euo pipefail
50
50
 
51
51
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
52
52
 
53
- # Load shared env from coding-agents/.env (gitignored) or env.example.
54
- SHARED_ENV="${MBTA_ENV_FILE:-${SCRIPT_DIR}/../.env}"
53
+ # Load shared env from SUBC_ENV_FILE, or a sibling .env / env.example.
54
+ SHARED_ENV="${SUBC_ENV_FILE:-${SCRIPT_DIR}/../.env}"
55
55
  [[ -f "$SHARED_ENV" ]] || SHARED_ENV="${SCRIPT_DIR}/../env.example"
56
56
  if [[ -f "$SHARED_ENV" ]]; then set -a; source "$SHARED_ENV"; set +a; fi
57
57
 
@@ -87,38 +87,18 @@ COMMAND="install"
87
87
  usage() {
88
88
  cat <<'EOF'
89
89
  Usage:
90
- install.sh [install] --gateway-url URL --api-key KEY [--model MODEL] [--compact-window N]
91
- install.sh use [-- CLAUDE_ARGS...]
92
- install.sh env
93
- install.sh unset
94
- install.sh uninstall
95
- install.sh status
90
+ subc claude status
91
+ subc claude uninstall
92
+ subc claude help
96
93
 
97
- `install` is the default subcommand and may be omitted.
98
-
99
- Commands:
100
- install Write ~/.claude/subconscious-gateway.env with gateway settings
101
- use Source the env file and exec claude (pass -- followed by claude args)
102
- env Print export lines for sourcing: source <(./install.sh env)
103
- unset Print unset lines for sourcing: source <(./install.sh unset)
104
- uninstall Remove the env file
105
- status Show current configuration
106
-
107
- Options:
108
- --gateway-url URL Gateway origin (e.g. https://gateway.example)
109
- --api-key KEY Gateway API key (sk-gw-...)
110
- --model MODEL Model name (default: subconscious/glm-5.2)
111
- --compact-window N CLAUDE_CODE_AUTO_COMPACT_WINDOW (default: 1000000; Claude Code clamps to 100000–1000000)
112
- See https://code.claude.com/docs/en/env-vars and
113
- https://code.claude.com/docs/en/context-window#set-the-auto-compact-window
114
- --max-context-tokens N CLAUDE_CODE_MAX_CONTEXT_TOKENS (default: 3000000)
115
- See https://code.claude.com/docs/en/env-vars
94
+ Claude Code is launch-only: subc claude. Uninstall removes leftover
95
+ ~/.claude/subconscious-gateway.env from older persistent setup.
116
96
  EOF
117
97
  }
118
98
 
119
99
  while [[ $# -gt 0 ]]; do
120
100
  case "$1" in
121
- install|use|env|unset|uninstall|status)
101
+ install|use|env|unset|uninstall|status|help)
122
102
  COMMAND="$1"
123
103
  shift
124
104
  ;;
@@ -169,7 +149,7 @@ write_env() {
169
149
  mkdir -p "$CLAUDE_DIR"
170
150
  umask 077
171
151
  cat >"$ENV_FILE" <<EOF
172
- # Generated by ol-runbook/coding-agents/claude-code/install.sh — do not commit secrets.
152
+ # Generated by subc — do not commit secrets.
173
153
  export ANTHROPIC_BASE_URL="${effective_gateway_url}"
174
154
  export ANTHROPIC_AUTH_TOKEN="${API_KEY}"
175
155
  export ANTHROPIC_MODEL="${MODEL}"
@@ -205,7 +185,7 @@ EOF
205
185
  print_env_exports() {
206
186
  if [[ ! -f "$ENV_FILE" ]]; then
207
187
  echo "env file not found: $ENV_FILE" >&2
208
- echo "run: ./install.sh --gateway-url URL --api-key KEY" >&2
188
+ echo "Launch Claude with: subc claude" >&2
209
189
  return 1
210
190
  fi
211
191
  cat "$ENV_FILE"
@@ -263,7 +243,7 @@ status() {
263
243
  echo "max context tokens: ${CLAUDE_CODE_MAX_CONTEXT_TOKENS:-unset}"
264
244
  else
265
245
  echo "env file: missing"
266
- echo "run: ./install.sh --gateway-url URL --api-key KEY"
246
+ echo "Launch Claude with: subc claude"
267
247
  fi
268
248
  }
269
249
 
@@ -274,21 +254,13 @@ case "$COMMAND" in
274
254
  exit 1
275
255
  fi
276
256
  write_env
277
- echo "Wrote $ENV_FILE"
278
- echo " gateway: $GATEWAY_URL"
279
- echo " model: $MODEL"
280
- echo ""
281
- echo "Launch claude:"
282
- echo " ./install.sh use"
283
- echo " ./install.sh use -- --continue"
284
- echo ""
285
- echo "Or source env into your current shell:"
286
- echo " source <(./install.sh env)"
257
+ echo "Wrote leftover env file $ENV_FILE"
258
+ echo "Launch Claude with: subc claude"
287
259
  ;;
288
260
  use)
289
261
  if [[ ! -f "$ENV_FILE" ]]; then
290
- echo "env file not found: $ENV_FILE" >&2
291
- echo "run: ./install.sh --gateway-url URL --api-key KEY" >&2
262
+ echo "env file not found: $ENV_FILE" >&2
263
+ echo "Launch Claude with: subc claude" >&2
292
264
  exit 1
293
265
  fi
294
266
  # shellcheck disable=SC1090
@@ -308,9 +280,11 @@ case "$COMMAND" in
308
280
  uninstall)
309
281
  rm -f "$ENV_FILE"
310
282
  echo "Removed $ENV_FILE"
311
- echo "To unset env in your current shell: source <(./install.sh unset)"
312
283
  ;;
313
284
  status)
314
285
  status
315
286
  ;;
287
+ help)
288
+ usage
289
+ ;;
316
290
  esac
@@ -11,7 +11,7 @@
11
11
  # ./run.sh --model subconscious/glm-5.2 -p "hi"
12
12
  #
13
13
  # Config: copy ../env.example to ../.env and edit. .env is gitignored.
14
- # All agents share one coding-agents/.env file.
14
+ # Profile env is injected by subc. A sibling .env is only used when SUBC_ENV_FILE is unset.
15
15
  #
16
16
  # Or source it to just export the env:
17
17
  # source run.sh
@@ -20,8 +20,8 @@ set -euo pipefail
20
20
 
21
21
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
22
22
 
23
- # Load shared env from coding-agents/.env (gitignored) or env.example.
24
- SHARED_ENV="${MBTA_ENV_FILE:-${SCRIPT_DIR}/../.env}"
23
+ # Load shared env from SUBC_ENV_FILE, or a sibling .env / env.example.
24
+ SHARED_ENV="${SUBC_ENV_FILE:-${SCRIPT_DIR}/../.env}"
25
25
  [[ -f "$SHARED_ENV" ]] || SHARED_ENV="${SCRIPT_DIR}/../env.example"
26
26
  if [[ -f "$SHARED_ENV" ]]; then set -a; source "$SHARED_ENV"; set +a; fi
27
27
 
@@ -57,7 +57,7 @@ Usage:
57
57
  run.sh [options] [-- CLAUDE_ARGS...]
58
58
  run.sh [options] CLAUDE_ARGS...
59
59
 
60
- Options (same as install.sh; override coding-agents/.env for this run):
60
+ Options (same as install.sh; flags override env for this run):
61
61
  --gateway-url URL Gateway origin (e.g. https://gateway.example)
62
62
  --api-key KEY Gateway API key (sk-gw-...)
63
63
  --model MODEL Model name (default: subconscious/glm-5.2)
@@ -125,18 +125,18 @@ EFFECTIVE_GATEWAY_URL="${CLAUDE_GATEWAY_URL:-$GATEWAY_URL}"
125
125
 
126
126
  export ANTHROPIC_BASE_URL="$EFFECTIVE_GATEWAY_URL"
127
127
  export ANTHROPIC_AUTH_TOKEN="$API_KEY"
128
- export ANTHROPIC_MODEL="$MODEL"
129
- export ANTHROPIC_SMALL_FAST_MODEL="$MODEL"
130
- export ANTHROPIC_DEFAULT_OPUS_MODEL="$OPUS_MODEL"
131
- export ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="$OPUS_MODEL_NAME"
132
- export ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION="$OPUS_MODEL_DESCRIPTION"
133
- export ANTHROPIC_DEFAULT_SONNET_MODEL="$SONNET_MODEL"
134
- export ANTHROPIC_DEFAULT_SONNET_MODEL_NAME="$SONNET_MODEL_NAME"
135
- export ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION="$SONNET_MODEL_DESCRIPTION"
136
- export ANTHROPIC_DEFAULT_HAIKU_MODEL="$HAIKU_MODEL"
137
- export ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME="$HAIKU_MODEL_NAME"
138
- export ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION="$HAIKU_MODEL_DESCRIPTION"
139
- export CLAUDE_CODE_SUBAGENT_MODEL="$MODEL"
128
+ export ANTHROPIC_MODEL="${ANTHROPIC_MODEL:-$MODEL}"
129
+ export ANTHROPIC_SMALL_FAST_MODEL="${ANTHROPIC_SMALL_FAST_MODEL:-$MODEL}"
130
+ export ANTHROPIC_DEFAULT_OPUS_MODEL="${ANTHROPIC_DEFAULT_OPUS_MODEL:-$OPUS_MODEL}"
131
+ export ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="${ANTHROPIC_DEFAULT_OPUS_MODEL_NAME:-$OPUS_MODEL_NAME}"
132
+ export ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION:-$OPUS_MODEL_DESCRIPTION}"
133
+ export ANTHROPIC_DEFAULT_SONNET_MODEL="${ANTHROPIC_DEFAULT_SONNET_MODEL:-$SONNET_MODEL}"
134
+ export ANTHROPIC_DEFAULT_SONNET_MODEL_NAME="${ANTHROPIC_DEFAULT_SONNET_MODEL_NAME:-$SONNET_MODEL_NAME}"
135
+ export ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION:-$SONNET_MODEL_DESCRIPTION}"
136
+ export ANTHROPIC_DEFAULT_HAIKU_MODEL="${ANTHROPIC_DEFAULT_HAIKU_MODEL:-$HAIKU_MODEL}"
137
+ export ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME="${ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME:-$HAIKU_MODEL_NAME}"
138
+ export ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION:-$HAIKU_MODEL_DESCRIPTION}"
139
+ export CLAUDE_CODE_SUBAGENT_MODEL="${CLAUDE_CODE_SUBAGENT_MODEL:-$MODEL}"
140
140
  export CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS="${MAX_CONCURRENT_SUBAGENTS}"
141
141
  export CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH="${MAX_SUBAGENT_SPAWN_DEPTH}"
142
142
  export CLAUDE_CODE_AUTO_COMPACT_WINDOW="${COMPACT_WINDOW}"
@@ -145,13 +145,13 @@ export CLAUDE_CODE_MAX_CONTEXT_TOKENS="${MAX_CONTEXT_TOKENS}"
145
145
  # (not a general logs API). Docs:
146
146
  # https://code.claude.com/docs/en/monitoring-usage#api-request-event
147
147
  # Requires Claude Code >= 2.1.152.
148
- export CLAUDE_CODE_ENABLE_TELEMETRY=1
149
- export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
150
- export OTEL_LOGS_EXPORTER=otlp
151
- export OTEL_EXPORTER_OTLP_PROTOCOL=http/json
148
+ export CLAUDE_CODE_ENABLE_TELEMETRY="${CLAUDE_CODE_ENABLE_TELEMETRY:-1}"
149
+ export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC="${CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:-1}"
150
+ export OTEL_LOGS_EXPORTER="${OTEL_LOGS_EXPORTER:-otlp}"
151
+ export OTEL_EXPORTER_OTLP_PROTOCOL="${OTEL_EXPORTER_OTLP_PROTOCOL:-http/json}"
152
152
  export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT="${EFFECTIVE_GATEWAY_URL%/}/v1/logs"
153
153
  export OTEL_EXPORTER_OTLP_HEADERS="x-api-key=${API_KEY}"
154
- export OTEL_EXPORTER_OTLP_TIMEOUT=2000
154
+ export OTEL_EXPORTER_OTLP_TIMEOUT="${OTEL_EXPORTER_OTLP_TIMEOUT:-2000}"
155
155
  export OTEL_LOGS_EXPORT_INTERVAL="${OTEL_LOGS_EXPORT_INTERVAL:-2000}"
156
156
  # Do not set OTEL_TRACES_EXPORTER / OTEL_METRICS_EXPORTER (including to "none") -
157
157
  # Claude's telemetry init can abort the whole pipeline on unknown exporter types.
@@ -22,7 +22,7 @@ if [[ -f "$CONFIG" ]]; then
22
22
  # shellcheck disable=SC1090
23
23
  source "$CONFIG"
24
24
  fi
25
- # install.sh also writes subconscious.env with the API key for the CLI.
25
+ # Older overwrite-style setup also wrote subconscious.env; keep reading it.
26
26
  if [[ -f "${HOME}/.codex/subconscious.env" ]]; then
27
27
  # shellcheck disable=SC1090
28
28
  source "${HOME}/.codex/subconscious.env"
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env bash
2
+ # Surgical Codex hook merge/unmerge. Sourced by install.sh and run.sh.
3
+ # Never reads, writes, or deletes ~/.codex/config.toml.
4
+
5
+ CODEX_DIR="${CODEX_DIR:-${HOME}/.codex}"
6
+ HOOKS_JSON="${HOOKS_JSON:-${CODEX_DIR}/hooks.json}"
7
+ HOOK_DST="${HOOK_DST:-${CODEX_DIR}/subconscious-hook.sh}"
8
+ HOOKS_ENV_FILE="${HOOKS_ENV_FILE:-${CODEX_DIR}/subconscious-hooks.env}"
9
+ MARKER="${MARKER:-subconscious-hook.sh}"
10
+
11
+ codex_hooks_have_jq() {
12
+ command -v jq >/dev/null 2>&1
13
+ }
14
+
15
+ codex_hooks_json_valid() {
16
+ [[ -f "$HOOKS_JSON" ]] && jq -e . "$HOOKS_JSON" >/dev/null 2>&1
17
+ }
18
+
19
+ codex_strip_hook_entries() {
20
+ local tmp
21
+ tmp="$(mktemp)"
22
+ jq --arg marker "$MARKER" '
23
+ def strip:
24
+ (. // [])
25
+ | map(
26
+ .hooks = ((.hooks // []) | map(select((.command // "") | tostring | contains($marker) | not)))
27
+ )
28
+ | map(select((.hooks | length) > 0));
29
+ .hooks = (.hooks // {})
30
+ | .hooks |= with_entries(.value |= strip)
31
+ ' "$HOOKS_JSON" >"$tmp"
32
+ mv "$tmp" "$HOOKS_JSON"
33
+ }
34
+
35
+ codex_append_hook_groups() {
36
+ local tmp
37
+ tmp="$(mktemp)"
38
+ jq --arg cmd "$HOOK_DST" '
39
+ def group($msg):
40
+ [{ "hooks": [{ "type": "command", "command": $cmd, "timeout": 3, "statusMessage": $msg }] }];
41
+ .hooks = (.hooks // {})
42
+ | .hooks.PreCompact = ((.hooks.PreCompact // []) + group("Reporting compaction start"))
43
+ | .hooks.PostCompact = ((.hooks.PostCompact // []) + group("Reporting compaction end"))
44
+ ' "$HOOKS_JSON" >"$tmp"
45
+ mv "$tmp" "$HOOKS_JSON"
46
+ }
47
+
48
+ codex_write_hook_script() {
49
+ mkdir -p "$CODEX_DIR"
50
+ cp "$HOOK_SRC" "$HOOK_DST"
51
+ chmod +x "$HOOK_DST"
52
+ }
53
+
54
+ codex_write_hooks_env() {
55
+ umask 077
56
+ cat >"$HOOKS_ENV_FILE" <<EOF
57
+ # Generated by subconscious-cli Codex integration — do not commit secrets.
58
+ export SUBCONSCIOUS_GATEWAY_URL='${GATEWAY_URL%/}'
59
+ export SUBCONSCIOUS_API_KEY='${API_KEY}'
60
+ EOF
61
+ chmod 600 "$HOOKS_ENV_FILE"
62
+ }
63
+
64
+ # codex_ensure_hooks [strict|best-effort]
65
+ codex_ensure_hooks() {
66
+ local mode="${1:-strict}"
67
+ if ! codex_hooks_have_jq; then
68
+ echo "warning: jq is required to merge Codex hooks without overwriting ~/.codex/hooks.json" >&2
69
+ if [[ "$mode" == "strict" ]]; then
70
+ echo "missing required command: jq" >&2
71
+ return 1
72
+ fi
73
+ return 0
74
+ fi
75
+ if [[ -z "${GATEWAY_URL:-}" || -z "${API_KEY:-}" ]]; then
76
+ echo "--gateway-url and --api-key are required to install Codex hooks" >&2
77
+ return 1
78
+ fi
79
+ if [[ -z "${HOOK_SRC:-}" || ! -f "$HOOK_SRC" ]]; then
80
+ echo "warning: Codex hook script missing; skipping hooks" >&2
81
+ return 0
82
+ fi
83
+ mkdir -p "$CODEX_DIR"
84
+ if [[ -f "$HOOKS_JSON" ]] && ! codex_hooks_json_valid; then
85
+ echo "warning: ${HOOKS_JSON} is not valid JSON; leaving it unchanged" >&2
86
+ if [[ "$mode" == "strict" ]]; then
87
+ return 1
88
+ fi
89
+ return 0
90
+ fi
91
+ if [[ ! -f "$HOOKS_JSON" ]]; then
92
+ printf '%s\n' '{"hooks":{}}' >"$HOOKS_JSON"
93
+ fi
94
+ codex_write_hook_script
95
+ codex_write_hooks_env
96
+ codex_strip_hook_entries
97
+ codex_append_hook_groups
98
+ echo "Merged Subconscious Codex hooks into $HOOKS_JSON"
99
+ echo "Trust new hooks in Codex with /hooks (or --dangerously-bypass-hook-trust)."
100
+ }
101
+
102
+ codex_uninstall_hooks() {
103
+ if [[ -f "$HOOKS_JSON" ]] && codex_hooks_have_jq && codex_hooks_json_valid; then
104
+ codex_strip_hook_entries
105
+ echo "Removed Subconscious entries from $HOOKS_JSON"
106
+ elif [[ -f "$HOOKS_JSON" ]]; then
107
+ echo "warning: ${HOOKS_JSON} is not valid JSON; leaving it unchanged" >&2
108
+ else
109
+ echo "No Codex hooks.json at $HOOKS_JSON"
110
+ fi
111
+ rm -f "$HOOK_DST" "$HOOKS_ENV_FILE"
112
+ rm -f "${CODEX_DIR}/subconscious.env"
113
+ }
114
+
115
+ codex_hooks_status() {
116
+ echo "scope: user"
117
+ echo "codex dir: $CODEX_DIR"
118
+ echo "hooks.json: $HOOKS_JSON"
119
+ if [[ -f "$HOOKS_JSON" ]] && codex_hooks_have_jq && jq -e --arg m "$MARKER" '
120
+ [.hooks[]?[]?.hooks[]? | select((.command // "") | tostring | contains($m))] | length > 0
121
+ ' "$HOOKS_JSON" >/dev/null 2>&1; then
122
+ echo "hooks: installed"
123
+ else
124
+ echo "hooks: not installed"
125
+ fi
126
+ if [[ -x "$HOOK_DST" ]]; then
127
+ echo "hook script: $HOOK_DST (executable)"
128
+ else
129
+ echo "hook script: missing"
130
+ fi
131
+ if [[ -f "$HOOKS_ENV_FILE" ]]; then
132
+ echo "env: $HOOKS_ENV_FILE (present)"
133
+ else
134
+ echo "env: missing"
135
+ fi
136
+ if [[ -f "${CODEX_DIR}/config.toml" ]] && grep -q 'model_provider = "subconscious"' "${CODEX_DIR}/config.toml" 2>/dev/null; then
137
+ echo "legacy config.toml: contains a Subconscious provider (this CLI no longer manages that file)"
138
+ fi
139
+ }