subconscious-cli 6.0.1 → 6.2.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.
- package/README.md +167 -43
- package/bin/agent-data.js +278 -0
- package/bin/agent-help.js +114 -0
- package/bin/agent-install.js +238 -0
- package/bin/agent-launch.js +199 -0
- package/bin/agent-spawn.js +137 -0
- package/bin/agents.js +236 -931
- package/bin/auth.js +9 -1
- package/bin/claude-picker.js +143 -0
- package/bin/cli.js +62 -2
- package/bin/clipboard-image.js +2 -0
- package/bin/feedback.js +14 -3
- package/bin/harness-manifest.js +286 -0
- package/bin/headless-args.js +35 -0
- package/bin/launch-values.js +25 -0
- package/bin/model-capabilities.js +10 -9
- package/bin/models.js +25 -13
- package/bin/native/subc-tui-darwin-amd64 +0 -0
- package/bin/native/subc-tui-darwin-arm64 +0 -0
- package/bin/native/subc-tui-linux-amd64 +0 -0
- package/bin/native/subc-tui-linux-arm64 +0 -0
- package/bin/native/subc-tui-windows-amd64.exe +0 -0
- package/bin/native/subc-tui-windows-arm64.exe +0 -0
- package/bin/opencode-provider.js +21 -0
- package/bin/profile-settings.js +129 -0
- package/bin/profiles.js +29 -424
- package/bin/runbook/README.md +77 -23
- package/bin/runbook/claude-code/agent.json +300 -0
- package/bin/runbook/claude-code/install.sh +9 -252
- package/bin/runbook/codex/agent.json +462 -0
- package/bin/runbook/codex/hooks-lib.sh +17 -4
- package/bin/runbook/codex/install.sh +0 -4
- package/bin/runbook/codex/run.sh +16 -235
- package/bin/runbook/copilot/agent.json +186 -0
- package/bin/runbook/copilot/install.sh +45 -63
- package/bin/runbook/cursor/agent.json +138 -0
- package/bin/runbook/cursor/install.sh +8 -35
- package/bin/runbook/deepseek-harness/agent.json +164 -0
- package/bin/runbook/deepseek-harness/run.sh +20 -59
- package/bin/runbook/image-window/index.ts +14 -0
- package/bin/runbook/image-window/window.d.ts +19 -0
- package/bin/runbook/image-window/window.js +140 -0
- package/bin/runbook/lib.sh +41 -0
- package/bin/runbook/opencode/agent.json +159 -0
- package/bin/runbook/opencode/install.sh +9 -183
- package/bin/runbook/opencode/opencode-plugin.d.ts +10 -3
- package/bin/runbook/opencode/subconscious-image-window.ts +24 -0
- package/bin/runbook/pi/agent.json +217 -0
- package/bin/runbook/pi/install.sh +18 -44
- package/bin/runbook/pi/run.sh +6 -18
- package/bin/runbook/pi/subconscious-compaction.ts +3 -1
- package/bin/runbook/shared.json +57 -0
- package/bin/sessions.js +53 -48
- package/bin/tui.js +13 -0
- package/bin/update-check.js +35 -1
- package/bin/upgrade.js +27 -34
- package/bin/usage.js +21 -10
- package/bin/windows/agents.js +28 -60
- package/bin/windows/common.js +2 -28
- package/bin/windows/launch.js +252 -231
- package/bin/windows/process.js +12 -1
- package/bin/windows/setup.js +29 -9
- package/package.json +2 -4
- package/bin/registry.generated.json +0 -406
- package/bin/runbook/claude-code/run.sh +0 -254
- package/bin/runbook/model-capabilities.generated.sh +0 -9
- package/bin/runbook/opencode/provider.sh +0 -93
- package/bin/runbook/opencode/run.sh +0 -99
- package/bin/runbook/opencode/subconscious-compaction.ts +0 -100
- package/bin/runbook/subconscious-code/install.sh +0 -154
- package/bin/runbook/subconscious-code/run.sh +0 -21
- package/bin/windows/claude.js +0 -100
- package/bin/windows/install.js +0 -188
package/bin/runbook/codex/run.sh
CHANGED
|
@@ -1,164 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
# Uses `codex -c key=value` overrides so nothing is written to ~/.codex/config.toml.
|
|
5
|
-
# web_search is disabled so Codex doesn't send hosted tools the gateway can't execute.
|
|
6
|
-
# The model catalog (needed to suppress the "model metadata not found" warning)
|
|
7
|
-
# is written to a temp file that is cleaned up on exit.
|
|
8
|
-
#
|
|
9
|
-
# Subagents are ON by default. The per-model `multi_agent_version` catalog
|
|
10
|
-
# field selects WHICH implementation Codex offers, not whether it offers one:
|
|
11
|
-
# "v2" gives the `collaboration` namespace, and an empty value falls back to
|
|
12
|
-
# the older `multi_agent_v1` namespace rather than turning subagents off.
|
|
13
|
-
# Only `agents.enabled=false` actually disables them, so clearing
|
|
14
|
-
# CODEX_MULTI_AGENT_VERSION does both.
|
|
2
|
+
# Write the temporary Codex model catalog and merge the compaction hooks, then
|
|
3
|
+
# start the codex argv subc built. Nothing is written to ~/.codex/config.toml.
|
|
15
4
|
#
|
|
16
5
|
# This needs a gateway that round-trips Codex's namespaced tools. Codex sends
|
|
17
6
|
# them as `type: "namespace"` and resolves an incoming call by namespace plus
|
|
18
7
|
# name, so a gateway that flattens the namespace for the model must restore it
|
|
19
8
|
# on the way back, or every call fails with "unsupported call: spawn_agent".
|
|
20
|
-
#
|
|
21
|
-
# Usage:
|
|
22
|
-
# ./run.sh # uses GATEWAY_URL/API_KEY from ../.env
|
|
23
|
-
# ./run.sh --context-window 5000000 -- --resume
|
|
24
|
-
# ./run.sh --stream-idle-timeout 1800000 # allow a 30min silent think
|
|
25
|
-
# ./run.sh --max-subagents 12 # raise the concurrent-subagent ceiling
|
|
26
|
-
# ./run.sh --subagent-effort low # cheaper subagents than the parent
|
|
27
|
-
# ./run.sh --external-tools # include Codex apps/plugins (may exceed gateway tool limits)
|
|
28
|
-
#
|
|
29
|
-
# Config: copy ../env.example to ../.env and edit. .env is gitignored.
|
|
30
|
-
# Profile env is injected by subc. A sibling .env is only used when SUBC_ENV_FILE is unset.
|
|
31
|
-
#
|
|
32
|
-
# Or source it to just export the env:
|
|
33
|
-
# source run.sh
|
|
34
9
|
|
|
35
10
|
set -euo pipefail
|
|
36
11
|
|
|
37
12
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
38
|
-
source "${SCRIPT_DIR}/../
|
|
39
|
-
|
|
40
|
-
# Load shared env from SUBC_ENV_FILE, or a sibling .env / env.example.
|
|
41
|
-
SHARED_ENV="${SUBC_ENV_FILE:-${SCRIPT_DIR}/../.env}"
|
|
42
|
-
[[ -f "$SHARED_ENV" ]] || SHARED_ENV="${SCRIPT_DIR}/../env.example"
|
|
43
|
-
if [[ -f "$SHARED_ENV" ]]; then set -a; source "$SHARED_ENV"; set +a; fi
|
|
44
|
-
|
|
45
|
-
GATEWAY_URL="${GATEWAY_URL:-}"
|
|
46
|
-
API_KEY="${CODEX_API_KEY:-${API_KEY:-}}"
|
|
47
|
-
MODEL="${MODEL:-subconscious/glm-5.3-marathon}"
|
|
48
|
-
MAX_CONCURRENT_SUBAGENTS="${MAX_CONCURRENT_SUBAGENTS:-}"
|
|
49
|
-
# Effort for spawned agents, independent of the parent's. Empty inherits the
|
|
50
|
-
# Codex default. See the note above SUBAGENT_ARGS for why max is a poor choice.
|
|
51
|
-
#
|
|
52
|
-
# Low rather than medium: the gateway rounds medium up to high for GLM, and at
|
|
53
|
-
# high a subagent handed an open-ended task keeps deliberating without ever
|
|
54
|
-
# writing the closing `</think>`. The turn then comes back as one long block of
|
|
55
|
-
# prose with no tool call, so the agent reports success having produced no
|
|
56
|
-
# files. Measured against the worker on one broad task: low closed and called a
|
|
57
|
-
# tool in ~1.5k characters, high ran past 76k and was still going.
|
|
58
|
-
CODEX_SUBAGENT_REASONING_EFFORT="${CODEX_SUBAGENT_REASONING_EFFORT-low}"
|
|
59
|
-
EXTERNAL_TOOLS="${CODEX_EXTERNAL_TOOLS:-false}"
|
|
60
|
-
CODEX_CONTEXT_WINDOW="${CODEX_CONTEXT_WINDOW:-5000000}"
|
|
61
|
-
CODEX_MAX_CONTEXT_WINDOW="${CODEX_MAX_CONTEXT_WINDOW:-}"
|
|
62
|
-
CODEX_AUTO_COMPACT_TOKEN_LIMIT="${CODEX_AUTO_COMPACT_TOKEN_LIMIT:-4500000}"
|
|
63
|
-
CODEX_REASONING_EFFORT="${CODEX_REASONING_EFFORT:-max}"
|
|
64
|
-
# How long Codex waits on a silent stream before giving up. The marathon models
|
|
65
|
-
# at max reasoning effort routinely think for longer than five minutes without
|
|
66
|
-
# emitting a token, and a subagent's turn is one uninterrupted think with no
|
|
67
|
-
# visible progress, so the old 300s ceiling cut off work that was still running.
|
|
68
|
-
CODEX_STREAM_IDLE_TIMEOUT_MS="${CODEX_STREAM_IDLE_TIMEOUT_MS:-900000}"
|
|
69
|
-
# Codex gates its subagent tools on this per-model catalog field. Only "v2" is
|
|
70
|
-
# honored by current releases; "v1" registers nothing. Set to empty to opt out.
|
|
71
|
-
# Unset defaults to v2; an explicitly empty value opts out, so use `-` not `:-`.
|
|
72
|
-
CODEX_MULTI_AGENT_VERSION="${CODEX_MULTI_AGENT_VERSION-v2}"
|
|
73
|
-
|
|
74
|
-
# Parse args (only when executed, not sourced)
|
|
75
|
-
PASSTHRU=()
|
|
76
|
-
if [[ "${BASH_SOURCE[0]:-$0}" == "${0}" ]]; then
|
|
77
|
-
while [[ $# -gt 0 ]]; do
|
|
78
|
-
case "$1" in
|
|
79
|
-
--context-window)
|
|
80
|
-
CODEX_CONTEXT_WINDOW="${2:-}"
|
|
81
|
-
shift 2
|
|
82
|
-
;;
|
|
83
|
-
--max-context-window)
|
|
84
|
-
CODEX_MAX_CONTEXT_WINDOW="${2:-}"
|
|
85
|
-
shift 2
|
|
86
|
-
;;
|
|
87
|
-
--auto-compact-token-limit)
|
|
88
|
-
CODEX_AUTO_COMPACT_TOKEN_LIMIT="${2:-}"
|
|
89
|
-
shift 2
|
|
90
|
-
;;
|
|
91
|
-
--reasoning-effort)
|
|
92
|
-
CODEX_REASONING_EFFORT="${2:-}"
|
|
93
|
-
shift 2
|
|
94
|
-
;;
|
|
95
|
-
--stream-idle-timeout)
|
|
96
|
-
CODEX_STREAM_IDLE_TIMEOUT_MS="${2:-}"
|
|
97
|
-
shift 2
|
|
98
|
-
;;
|
|
99
|
-
--max-subagents)
|
|
100
|
-
MAX_CONCURRENT_SUBAGENTS="${2:-}"
|
|
101
|
-
shift 2
|
|
102
|
-
;;
|
|
103
|
-
--subagent-effort)
|
|
104
|
-
CODEX_SUBAGENT_REASONING_EFFORT="${2:-}"
|
|
105
|
-
shift 2
|
|
106
|
-
;;
|
|
107
|
-
--external-tools)
|
|
108
|
-
EXTERNAL_TOOLS=true
|
|
109
|
-
shift
|
|
110
|
-
;;
|
|
111
|
-
--)
|
|
112
|
-
shift
|
|
113
|
-
PASSTHRU+=("$@")
|
|
114
|
-
break
|
|
115
|
-
;;
|
|
116
|
-
*)
|
|
117
|
-
PASSTHRU+=("$1")
|
|
118
|
-
shift
|
|
119
|
-
;;
|
|
120
|
-
esac
|
|
121
|
-
done
|
|
122
|
-
fi
|
|
123
|
-
|
|
124
|
-
CODEX_MAX_CONTEXT_WINDOW="${CODEX_MAX_CONTEXT_WINDOW:-${CODEX_CONTEXT_WINDOW}}"
|
|
125
|
-
case "$CODEX_REASONING_EFFORT" in
|
|
126
|
-
none|low|medium|high|max) ;;
|
|
127
|
-
*)
|
|
128
|
-
echo "error: reasoning effort must be one of: none, low, medium, high, max" >&2
|
|
129
|
-
exit 1
|
|
130
|
-
;;
|
|
131
|
-
esac
|
|
132
|
-
|
|
133
|
-
DEFAULT_SUBCONSCIOUS_MODELS="subconscious/glm-5.3-marathon
|
|
134
|
-
subconscious/glm-5.2
|
|
135
|
-
subconscious/tim-qwen3.6-27b
|
|
136
|
-
subconscious/deepseek-v4-flash-marathon
|
|
137
|
-
subconscious/deepseek-v4.1-flash-marathon"
|
|
138
|
-
SUPPORTED_MODELS=()
|
|
139
|
-
|
|
140
|
-
add_supported_model() {
|
|
141
|
-
local model_id="$1" existing
|
|
142
|
-
[[ -n "$model_id" ]] || return 0
|
|
143
|
-
if [[ ! "$model_id" =~ ^[-A-Za-z0-9._:/+]+$ ]]; then
|
|
144
|
-
echo "error: invalid model id: $model_id" >&2
|
|
145
|
-
exit 1
|
|
146
|
-
fi
|
|
147
|
-
if [[ "${#SUPPORTED_MODELS[@]}" -gt 0 ]]; then
|
|
148
|
-
for existing in "${SUPPORTED_MODELS[@]}"; do
|
|
149
|
-
[[ "$existing" == "$model_id" ]] && return 0
|
|
150
|
-
done
|
|
151
|
-
fi
|
|
152
|
-
SUPPORTED_MODELS+=("$model_id")
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
# Keep the requested model first while exposing the complete Subconscious
|
|
156
|
-
# catalog in Codex's /model picker. The CLI supplies the live gateway catalog;
|
|
157
|
-
# the packaged fallback keeps the vendored runbook useful on its own.
|
|
158
|
-
add_supported_model "$MODEL"
|
|
159
|
-
while IFS= read -r model_id; do
|
|
160
|
-
add_supported_model "$model_id"
|
|
161
|
-
done <<< "${SUBCONSCIOUS_MODELS:-$DEFAULT_SUBCONSCIOUS_MODELS}"
|
|
13
|
+
source "${SCRIPT_DIR}/../lib.sh"
|
|
162
14
|
|
|
163
15
|
write_model_catalog() {
|
|
164
16
|
local catalog_file="$1" model_id vision_fields index=0 multi_agent_json="null"
|
|
@@ -167,8 +19,11 @@ write_model_catalog() {
|
|
|
167
19
|
fi
|
|
168
20
|
{
|
|
169
21
|
printf '{\n "models": [\n'
|
|
170
|
-
|
|
171
|
-
|
|
22
|
+
# The requested model comes first; the rest fill Codex's /model picker.
|
|
23
|
+
while IFS= read -r model_id; do
|
|
24
|
+
# Codex assumes ["text", "image"] when the field is missing, so a
|
|
25
|
+
# text-only model must say so or Codex sends it images anyway.
|
|
26
|
+
vision_fields=', "input_modalities": ["text"]'
|
|
172
27
|
if subc_model_supports_vision "$model_id"; then
|
|
173
28
|
vision_fields=', "input_modalities": ["text", "image"]'
|
|
174
29
|
fi
|
|
@@ -217,66 +72,14 @@ write_model_catalog() {
|
|
|
217
72
|
}
|
|
218
73
|
EOF
|
|
219
74
|
index=$((index + 1))
|
|
220
|
-
done
|
|
75
|
+
done <<< "$SUBC_MODEL_IDS"
|
|
221
76
|
printf '\n ]\n}\n'
|
|
222
77
|
} >"$catalog_file"
|
|
223
78
|
}
|
|
224
79
|
|
|
225
|
-
# The
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
# opt back in with --external-tools if their gateway supports a larger limit.
|
|
229
|
-
EXTERNAL_TOOL_ARGS=()
|
|
230
|
-
if [[ "$EXTERNAL_TOOLS" != "true" ]]; then
|
|
231
|
-
EXTERNAL_TOOL_ARGS=(
|
|
232
|
-
-c features.apps=false
|
|
233
|
-
-c features.plugins=false
|
|
234
|
-
-c apps._default.enabled=false
|
|
235
|
-
)
|
|
236
|
-
fi
|
|
237
|
-
|
|
238
|
-
# Bound the subagent tree when the catalog turns it on. Codex still only spawns
|
|
239
|
-
# a subagent when the user asks for one; these are ceilings, not defaults.
|
|
240
|
-
#
|
|
241
|
-
# Codex documents no nesting-depth limit, so a subagent can spawn its own
|
|
242
|
-
# subagent and the tree can grow deeper than you asked for. Capping concurrency
|
|
243
|
-
# is the only lever available.
|
|
244
|
-
#
|
|
245
|
-
# Subagent reasoning effort is set separately from the parent's on purpose: the
|
|
246
|
-
# marathon models at max effort think for many minutes without emitting a
|
|
247
|
-
# token, and a subagent turn is one uninterrupted think, so inheriting max
|
|
248
|
-
# makes every delegated subtask look like a hang.
|
|
249
|
-
# Applied after argument parsing so --max-subagents can win. Four is a floor
|
|
250
|
-
# rather than a considered limit: Codex's own default is three, and exceeding
|
|
251
|
-
# either one fails the spawn outright rather than queueing it, so a run that
|
|
252
|
-
# wants more should say so instead of collecting retries.
|
|
253
|
-
MAX_CONCURRENT_SUBAGENTS="${MAX_CONCURRENT_SUBAGENTS:-4}"
|
|
254
|
-
|
|
255
|
-
SUBAGENT_ARGS=()
|
|
256
|
-
if [[ -z "$CODEX_MULTI_AGENT_VERSION" ]]; then
|
|
257
|
-
# Clearing the catalog field alone only downgrades Codex to multi-agent v1,
|
|
258
|
-
# whose tools this gateway has never been exercised against. Turn the
|
|
259
|
-
# feature off outright instead.
|
|
260
|
-
SUBAGENT_ARGS=(-c agents.enabled=false)
|
|
261
|
-
else
|
|
262
|
-
SUBAGENT_ARGS=(
|
|
263
|
-
-c agents.max_concurrent_threads_per_session="${MAX_CONCURRENT_SUBAGENTS}"
|
|
264
|
-
-c agents.interrupt_message=true
|
|
265
|
-
)
|
|
266
|
-
if [[ -n "$CODEX_SUBAGENT_REASONING_EFFORT" ]]; then
|
|
267
|
-
SUBAGENT_ARGS+=(
|
|
268
|
-
-c agents.default_subagent_reasoning_effort="${CODEX_SUBAGENT_REASONING_EFFORT}"
|
|
269
|
-
)
|
|
270
|
-
fi
|
|
271
|
-
fi
|
|
272
|
-
|
|
273
|
-
if [[ -z "$GATEWAY_URL" || -z "$API_KEY" ]]; then
|
|
274
|
-
echo "error: GATEWAY_URL and API_KEY must be set in ../.env" >&2
|
|
275
|
-
exit 1
|
|
276
|
-
fi
|
|
277
|
-
|
|
278
|
-
export SUBCONSCIOUS_API_KEY="$API_KEY"
|
|
279
|
-
export SUBCONSCIOUS_GATEWAY_URL="${GATEWAY_URL%/}"
|
|
80
|
+
# The hooks library writes its env file from these two.
|
|
81
|
+
API_KEY="$SUBCONSCIOUS_API_KEY"
|
|
82
|
+
GATEWAY_URL="$SUBCONSCIOUS_GATEWAY_URL"
|
|
280
83
|
|
|
281
84
|
# Merge compaction hooks without replacing ~/.codex/hooks.json or config.toml.
|
|
282
85
|
# `codex_ensure_hooks` returns early when they are already current, so a launch
|
|
@@ -286,33 +89,11 @@ export SUBCONSCIOUS_GATEWAY_URL="${GATEWAY_URL%/}"
|
|
|
286
89
|
HOOK_SRC="${SCRIPT_DIR}/hook.sh"
|
|
287
90
|
# shellcheck source=hooks-lib.sh
|
|
288
91
|
source "${SCRIPT_DIR}/hooks-lib.sh"
|
|
289
|
-
codex_ensure_hooks best-effort || true
|
|
92
|
+
codex_ensure_hooks best-effort >&2 || true
|
|
290
93
|
|
|
291
|
-
#
|
|
292
|
-
#
|
|
94
|
+
# Without a catalog Codex prints "model metadata not found", and a catalog
|
|
95
|
+
# cannot be passed with -c. Codex replaces this shell, so the file outlives it.
|
|
293
96
|
CATALOG_FILE="$(mktemp -t codex-model-catalog.XXXXXX.json)"
|
|
294
|
-
cleanup() { rm -f "$CATALOG_FILE"; }
|
|
295
|
-
trap cleanup EXIT
|
|
296
97
|
write_model_catalog "$CATALOG_FILE"
|
|
297
98
|
|
|
298
|
-
|
|
299
|
-
if [[ "${BASH_SOURCE[0]:-$0}" != "${0}" ]]; then
|
|
300
|
-
export GATEWAY_URL CATALOG_FILE MAX_CONCURRENT_SUBAGENTS CODEX_SUBAGENT_REASONING_EFFORT
|
|
301
|
-
return 0 2>/dev/null || true
|
|
302
|
-
fi
|
|
303
|
-
|
|
304
|
-
# Ephemeral config via -c flags — nothing is written to ~/.codex/config.toml.
|
|
305
|
-
exec codex \
|
|
306
|
-
-c model="${MODEL}" \
|
|
307
|
-
-c model_provider=subconscious \
|
|
308
|
-
-c model_catalog_json="${CATALOG_FILE}" \
|
|
309
|
-
-c model_reasoning_effort="${CODEX_REASONING_EFFORT}" \
|
|
310
|
-
-c web_search=disabled \
|
|
311
|
-
${EXTERNAL_TOOL_ARGS[@]+"${EXTERNAL_TOOL_ARGS[@]}"} \
|
|
312
|
-
${SUBAGENT_ARGS[@]+"${SUBAGENT_ARGS[@]}"} \
|
|
313
|
-
-c model_providers.subconscious.name=Subconscious \
|
|
314
|
-
-c model_providers.subconscious.base_url="${GATEWAY_URL}/v1" \
|
|
315
|
-
-c model_providers.subconscious.wire_api=responses \
|
|
316
|
-
-c model_providers.subconscious.env_key=SUBCONSCIOUS_API_KEY \
|
|
317
|
-
-c model_providers.subconscious.stream_idle_timeout_ms="${CODEX_STREAM_IDLE_TIMEOUT_MS}" \
|
|
318
|
-
${PASSTHRU[@]+"${PASSTHRU[@]}"}
|
|
99
|
+
subc_exec "{tempFile}" "$CATALOG_FILE" -- "$@"
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "copilot",
|
|
3
|
+
"command": "copilot",
|
|
4
|
+
"aliases": ["vscode", "vs-code"],
|
|
5
|
+
"name": "GitHub Copilot (VS Code)",
|
|
6
|
+
"description": "Install the VS Code custom endpoint and Copilot conversation/compaction hooks.",
|
|
7
|
+
"protocol": "openai",
|
|
8
|
+
"homepage": "https://code.visualstudio.com/docs/copilot/overview",
|
|
9
|
+
"install": {
|
|
10
|
+
"commands": null,
|
|
11
|
+
"url": "https://code.visualstudio.com/docs/setup/copilot",
|
|
12
|
+
"method": "user",
|
|
13
|
+
"package": null,
|
|
14
|
+
"version": null,
|
|
15
|
+
"minimum_version": null,
|
|
16
|
+
"verified": true,
|
|
17
|
+
"note": "VS Code installed by the user. The provider API key is entered once in VS Code's Manage Language Models."
|
|
18
|
+
},
|
|
19
|
+
"runbook": {
|
|
20
|
+
"mode": "setup",
|
|
21
|
+
"setup_script": "install.sh",
|
|
22
|
+
"setup_actions": ["install", "status", "uninstall"]
|
|
23
|
+
},
|
|
24
|
+
"help": {
|
|
25
|
+
"usage": "subc [-p NAME] copilot [help|install|status|uninstall]",
|
|
26
|
+
"behavior": "Manages the VS Code model provider and Copilot correlation hooks.",
|
|
27
|
+
"options": [
|
|
28
|
+
["help", "Show this help"],
|
|
29
|
+
["install", "Install or update the provider and hooks (default action)"],
|
|
30
|
+
["status", "Inspect the installed provider and hooks"],
|
|
31
|
+
["uninstall", "Remove the Subconscious provider and hooks"]
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"prerequisites": [
|
|
35
|
+
{ "command": "jq", "needed_for": "install", "required": true },
|
|
36
|
+
{ "command": "curl", "needed_for": "install", "required": true }
|
|
37
|
+
],
|
|
38
|
+
"launch": null,
|
|
39
|
+
"inputs": [
|
|
40
|
+
{
|
|
41
|
+
"name": "COPILOT_API_KEY",
|
|
42
|
+
"label": "Copilot hook API key",
|
|
43
|
+
"description": "Copilot hook credential override; blank uses API_KEY.",
|
|
44
|
+
"type": "secret"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"name": "COPILOT_MAX_INPUT_TOKENS",
|
|
48
|
+
"default": 5000000,
|
|
49
|
+
"label": "Maximum input tokens",
|
|
50
|
+
"description": "Input-token capacity advertised to VS Code.",
|
|
51
|
+
"type": "integer",
|
|
52
|
+
"min": 1
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "COPILOT_MAX_OUTPUT_TOKENS",
|
|
56
|
+
"default": 65536,
|
|
57
|
+
"label": "Maximum output tokens",
|
|
58
|
+
"description": "Output-token capacity advertised to VS Code.",
|
|
59
|
+
"type": "integer",
|
|
60
|
+
"min": 1
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "VSCODE_APP",
|
|
64
|
+
"label": "VS Code application",
|
|
65
|
+
"description": "Optional application override; blank enables auto-detection.",
|
|
66
|
+
"type": "choice",
|
|
67
|
+
"choices": ["", "Code", "Code - Insiders", "VSCodium"]
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"env": [],
|
|
71
|
+
"config": [
|
|
72
|
+
{
|
|
73
|
+
"kind": "file",
|
|
74
|
+
"path": "<VS Code user dir>/chatLanguageModels.json",
|
|
75
|
+
"lifetime": "persistent",
|
|
76
|
+
"value": {
|
|
77
|
+
"name": "Subconscious Gateway",
|
|
78
|
+
"vendor": "customendpoint",
|
|
79
|
+
"apiType": "messages",
|
|
80
|
+
"apiKey": "${input:chat.lm.secret.subconscious-gateway}",
|
|
81
|
+
"models.<id>.url": "{baseUrl}/v1/messages",
|
|
82
|
+
"models.<id>.maxInputTokens": "${COPILOT_MAX_INPUT_TOKENS}",
|
|
83
|
+
"models.<id>.maxOutputTokens": "${COPILOT_MAX_OUTPUT_TOKENS}",
|
|
84
|
+
"models.<id>.requestHeaders": {
|
|
85
|
+
"x-subconscious-client": "copilot"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"description": "Custom Endpoint provider, written by install.sh and merged into the user's list."
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"kind": "file",
|
|
92
|
+
"path": "~/.copilot/hooks/subconscious-hooks.json",
|
|
93
|
+
"lifetime": "persistent",
|
|
94
|
+
"description": "UserPromptSubmit and PreCompact hooks."
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"kind": "file",
|
|
98
|
+
"path": "~/.copilot/hooks/subconscious-hook.sh",
|
|
99
|
+
"lifetime": "persistent",
|
|
100
|
+
"description": "Hook script."
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"kind": "file",
|
|
104
|
+
"path": "~/.copilot/subconscious-hooks.env",
|
|
105
|
+
"lifetime": "persistent",
|
|
106
|
+
"description": "SUBCONSCIOUS_GATEWAY_URL and SUBCONSCIOUS_API_KEY for the hook (mode 600)."
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"kind": "dir",
|
|
110
|
+
"path": "~/.copilot/subconscious-compact-pending",
|
|
111
|
+
"lifetime": "persistent",
|
|
112
|
+
"description": "Pending-compaction markers written by the hook."
|
|
113
|
+
}
|
|
114
|
+
],
|
|
115
|
+
"capabilities": {
|
|
116
|
+
"compaction": {
|
|
117
|
+
"default": "unknown",
|
|
118
|
+
"on": {
|
|
119
|
+
"set_by_subc": false,
|
|
120
|
+
"kind": null,
|
|
121
|
+
"name": null,
|
|
122
|
+
"value": null,
|
|
123
|
+
"verified": false,
|
|
124
|
+
"note": "subc only sets maxInputTokens; whether VS Code compacts from it is not confirmed here."
|
|
125
|
+
},
|
|
126
|
+
"off": {
|
|
127
|
+
"set_by_subc": false,
|
|
128
|
+
"kind": null,
|
|
129
|
+
"name": null,
|
|
130
|
+
"value": null,
|
|
131
|
+
"verified": false,
|
|
132
|
+
"note": "subc does not configure Copilot compaction."
|
|
133
|
+
},
|
|
134
|
+
"threshold": {
|
|
135
|
+
"set_by_subc": true,
|
|
136
|
+
"kind": "config-field",
|
|
137
|
+
"name": "models.<id>.maxInputTokens",
|
|
138
|
+
"value": "${COPILOT_MAX_INPUT_TOKENS}",
|
|
139
|
+
"verified": false,
|
|
140
|
+
"note": "subc sets this capacity; its effect on compaction is not confirmed here.",
|
|
141
|
+
"semantics": "window",
|
|
142
|
+
"config": "<VS Code user dir>/chatLanguageModels.json"
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"mcp": {
|
|
146
|
+
"configured_by_subc": false,
|
|
147
|
+
"transports": null,
|
|
148
|
+
"verified": false,
|
|
149
|
+
"note": "subc configures no MCP servers."
|
|
150
|
+
},
|
|
151
|
+
"headers": [
|
|
152
|
+
{
|
|
153
|
+
"name": "x-subconscious-client",
|
|
154
|
+
"value": "copilot",
|
|
155
|
+
"on": "model requests and hook POSTs",
|
|
156
|
+
"set_by_subc": true,
|
|
157
|
+
"verified": true
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"name": "Authorization",
|
|
161
|
+
"value": "Bearer {apiKey}",
|
|
162
|
+
"on": "hook POSTs to {baseUrl}/v1/agent-hooks",
|
|
163
|
+
"set_by_subc": true,
|
|
164
|
+
"verified": true
|
|
165
|
+
}
|
|
166
|
+
],
|
|
167
|
+
"hooks": [
|
|
168
|
+
{
|
|
169
|
+
"event": "UserPromptSubmit",
|
|
170
|
+
"posts": "conversation_ensure, plus conversation_compaction phase=end when one is pending",
|
|
171
|
+
"endpoint": "{baseUrl}/v1/agent-hooks",
|
|
172
|
+
"config": "~/.copilot/hooks/subconscious-hooks.json",
|
|
173
|
+
"installed_by": ["install"],
|
|
174
|
+
"verified": true
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"event": "PreCompact",
|
|
178
|
+
"posts": "conversation_compaction phase=start",
|
|
179
|
+
"endpoint": "{baseUrl}/v1/agent-hooks",
|
|
180
|
+
"config": "~/.copilot/hooks/subconscious-hooks.json",
|
|
181
|
+
"installed_by": ["install"],
|
|
182
|
+
"verified": true
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -64,23 +64,17 @@
|
|
|
64
64
|
set -euo pipefail
|
|
65
65
|
|
|
66
66
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
67
|
-
source "${SCRIPT_DIR}/../
|
|
67
|
+
source "${SCRIPT_DIR}/../lib.sh"
|
|
68
68
|
HOOK_SRC="${SCRIPT_DIR}/hook.sh"
|
|
69
69
|
HOOKS_TEMPLATE="${SCRIPT_DIR}/hooks.json"
|
|
70
70
|
|
|
71
|
-
# Load shared env from SUBC_ENV_FILE, or a sibling .env / env.example.
|
|
72
|
-
SHARED_ENV="${SUBC_ENV_FILE:-${SCRIPT_DIR}/../.env}"
|
|
73
|
-
[[ -f "$SHARED_ENV" ]] || SHARED_ENV="${SCRIPT_DIR}/../env.example"
|
|
74
|
-
if [[ -f "$SHARED_ENV" ]]; then set -a; source "$SHARED_ENV"; set +a; fi
|
|
75
|
-
|
|
76
71
|
# Default to `install` so `./install.sh --gateway-url URL` works without an
|
|
77
72
|
# explicit `install` subcommand. `status` / `uninstall` still work.
|
|
78
73
|
COMMAND="install"
|
|
79
74
|
GATEWAY_URL="${GATEWAY_URL:-}"
|
|
80
75
|
API_KEY="${COPILOT_API_KEY:-${API_KEY:-}}"
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
MAX_OUTPUT_TOKENS="${COPILOT_MAX_OUTPUT_TOKENS:-65536}"
|
|
76
|
+
MAX_INPUT_TOKENS="${COPILOT_MAX_INPUT_TOKENS:-}"
|
|
77
|
+
MAX_OUTPUT_TOKENS="${COPILOT_MAX_OUTPUT_TOKENS:-}"
|
|
84
78
|
VSCODE_APP="${VSCODE_APP:-}" # auto-detected: Code | Code - Insiders | VSCodium
|
|
85
79
|
|
|
86
80
|
# VS Code's customendpoint provider requires the apiKey to be a
|
|
@@ -101,7 +95,7 @@ MARKER="subconscious-hook.sh"
|
|
|
101
95
|
usage() {
|
|
102
96
|
cat <<'EOF'
|
|
103
97
|
Usage:
|
|
104
|
-
subc copilot install [--gateway-url URL] [--api-key KEY]
|
|
98
|
+
subc copilot install [--gateway-url URL] [--api-key KEY]
|
|
105
99
|
subc copilot uninstall
|
|
106
100
|
subc copilot status
|
|
107
101
|
|
|
@@ -117,15 +111,14 @@ paste the key once via Manage Language Models).
|
|
|
117
111
|
The API key for the hooks is read from the profile env or --api-key and
|
|
118
112
|
stored in ~/.copilot/subconscious-hooks.env (mode 600).
|
|
119
113
|
|
|
120
|
-
Reads GATEWAY_URL, API_KEY,
|
|
121
|
-
|
|
114
|
+
Reads GATEWAY_URL, API_KEY, the model catalog, and the COPILOT_* settings
|
|
115
|
+
from the env subc passes. Restart VS Code after install.
|
|
122
116
|
|
|
123
117
|
Options:
|
|
124
|
-
--gateway-url URL Gateway origin (default: $GATEWAY_URL
|
|
125
|
-
--api-key KEY Gateway API key for hooks (default: $API_KEY
|
|
126
|
-
--
|
|
127
|
-
--max-
|
|
128
|
-
--max-output-tokens N Model max output tokens (default: 65536)
|
|
118
|
+
--gateway-url URL Gateway origin (default: $GATEWAY_URL)
|
|
119
|
+
--api-key KEY Gateway API key for hooks (default: $API_KEY)
|
|
120
|
+
--max-input-tokens N Model context window input tokens (default: COPILOT_MAX_INPUT_TOKENS)
|
|
121
|
+
--max-output-tokens N Model max output tokens (default: COPILOT_MAX_OUTPUT_TOKENS)
|
|
129
122
|
--vscode-app APP Code, Code - Insiders, or VSCodium (auto-detected)
|
|
130
123
|
|
|
131
124
|
Requires: jq, curl. Restart VS Code after install, then enter your model API
|
|
@@ -147,10 +140,6 @@ while [[ $# -gt 0 ]]; do
|
|
|
147
140
|
API_KEY="${2:-}"
|
|
148
141
|
shift 2
|
|
149
142
|
;;
|
|
150
|
-
--model)
|
|
151
|
-
MODEL="${2:-}"
|
|
152
|
-
shift 2
|
|
153
|
-
;;
|
|
154
143
|
--max-input-tokens)
|
|
155
144
|
MAX_INPUT_TOKENS="${2:-}"
|
|
156
145
|
shift 2
|
|
@@ -175,29 +164,6 @@ while [[ $# -gt 0 ]]; do
|
|
|
175
164
|
esac
|
|
176
165
|
done
|
|
177
166
|
|
|
178
|
-
DEFAULT_SUBCONSCIOUS_MODELS="subconscious/glm-5.3-marathon
|
|
179
|
-
subconscious/glm-5.2
|
|
180
|
-
subconscious/tim-qwen3.6-27b
|
|
181
|
-
subconscious/deepseek-v4-flash-marathon
|
|
182
|
-
subconscious/deepseek-v4.1-flash-marathon"
|
|
183
|
-
SUPPORTED_MODELS=()
|
|
184
|
-
|
|
185
|
-
add_supported_model() {
|
|
186
|
-
local model_id="$1" existing
|
|
187
|
-
[[ -n "$model_id" ]] || return 0
|
|
188
|
-
if [[ "${#SUPPORTED_MODELS[@]}" -gt 0 ]]; then
|
|
189
|
-
for existing in "${SUPPORTED_MODELS[@]}"; do
|
|
190
|
-
[[ "$existing" == "$model_id" ]] && return 0
|
|
191
|
-
done
|
|
192
|
-
fi
|
|
193
|
-
SUPPORTED_MODELS+=("$model_id")
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
add_supported_model "$MODEL"
|
|
197
|
-
while IFS= read -r model_id; do
|
|
198
|
-
add_supported_model "$model_id"
|
|
199
|
-
done <<< "${SUBCONSCIOUS_MODELS:-$DEFAULT_SUBCONSCIOUS_MODELS}"
|
|
200
|
-
|
|
201
167
|
PROVIDER_NAME="Subconscious Gateway"
|
|
202
168
|
MARKER='Subconscious Gateway'
|
|
203
169
|
|
|
@@ -274,9 +240,11 @@ strip_subconscious() {
|
|
|
274
240
|
echo "[]"
|
|
275
241
|
return
|
|
276
242
|
fi
|
|
277
|
-
jq --arg name "$PROVIDER_NAME"
|
|
278
|
-
|
|
279
|
-
"
|
|
243
|
+
jq --arg name "$PROVIDER_NAME" '
|
|
244
|
+
if type != "array" then error("model configuration must be an array")
|
|
245
|
+
elif any(.[]; type != "object") then error("model providers must be objects")
|
|
246
|
+
else map(select(.name != $name)) end
|
|
247
|
+
' "$file"
|
|
280
248
|
}
|
|
281
249
|
|
|
282
250
|
write_config() {
|
|
@@ -294,10 +262,13 @@ write_config() {
|
|
|
294
262
|
|
|
295
263
|
mkdir -p "$user_dir"
|
|
296
264
|
local existing
|
|
297
|
-
existing="$(strip_subconscious "$models_json")"
|
|
265
|
+
if ! existing="$(strip_subconscious "$models_json")"; then
|
|
266
|
+
echo "Cannot read $models_json; leaving it unchanged" >&2
|
|
267
|
+
return 1
|
|
268
|
+
fi
|
|
298
269
|
|
|
299
270
|
local provider_models='[]' model_id vision
|
|
300
|
-
|
|
271
|
+
while IFS= read -r model_id; do
|
|
301
272
|
vision=false
|
|
302
273
|
if subc_model_supports_vision "$model_id"; then vision=true; fi
|
|
303
274
|
provider_models=$(jq -cn \
|
|
@@ -319,8 +290,8 @@ write_config() {
|
|
|
319
290
|
thinking: true,
|
|
320
291
|
streaming: true,
|
|
321
292
|
requestHeaders: { "x-subconscious-client": "copilot" }
|
|
322
|
-
}]')
|
|
323
|
-
done
|
|
293
|
+
}]') || return 1
|
|
294
|
+
done <<< "$SUBC_MODEL_IDS"
|
|
324
295
|
|
|
325
296
|
local new_provider
|
|
326
297
|
new_provider=$(jq -n \
|
|
@@ -333,14 +304,17 @@ write_config() {
|
|
|
333
304
|
apiKey: $apiKeyRef,
|
|
334
305
|
apiType: "messages",
|
|
335
306
|
models: $models
|
|
336
|
-
}')
|
|
307
|
+
}') || return 1
|
|
337
308
|
|
|
338
309
|
local merged
|
|
339
|
-
merged=$(echo "$existing" | jq --argjson p "$new_provider" '. + [$p]')
|
|
310
|
+
merged=$(echo "$existing" | jq --argjson p "$new_provider" '. + [$p]') || return 1
|
|
340
311
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
312
|
+
local tmp
|
|
313
|
+
tmp="$(mktemp "${models_json}.XXXXXX")" || return 1
|
|
314
|
+
if ! printf '%s\n' "$merged" >"$tmp" || ! mv "$tmp" "$models_json"; then
|
|
315
|
+
rm -f "$tmp"
|
|
316
|
+
return 1
|
|
317
|
+
fi
|
|
344
318
|
echo "$models_json"
|
|
345
319
|
}
|
|
346
320
|
|
|
@@ -348,13 +322,18 @@ uninstall_config() {
|
|
|
348
322
|
local user_dir="$1"
|
|
349
323
|
local models_json="${user_dir}/chatLanguageModels.json"
|
|
350
324
|
if [[ -f "$models_json" ]]; then
|
|
351
|
-
|
|
325
|
+
local existing
|
|
326
|
+
if ! existing="$(strip_subconscious "$models_json")"; then
|
|
327
|
+
echo "Cannot read $models_json; leaving it unchanged" >&2
|
|
328
|
+
return 1
|
|
329
|
+
fi
|
|
330
|
+
if jq -e --arg name "$PROVIDER_NAME" 'any(.[]; .name == $name)' "$models_json" >/dev/null; then
|
|
352
331
|
local tmp
|
|
353
|
-
tmp="$(mktemp)"
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
332
|
+
tmp="$(mktemp "${models_json}.XXXXXX")"
|
|
333
|
+
if ! printf '%s\n' "$existing" >"$tmp" || ! mv "$tmp" "$models_json"; then
|
|
334
|
+
rm -f "$tmp"
|
|
335
|
+
return 1
|
|
336
|
+
fi
|
|
358
337
|
echo "Removed Subconscious provider from $models_json"
|
|
359
338
|
else
|
|
360
339
|
echo "No Subconscious provider found in $models_json"
|
|
@@ -383,7 +362,10 @@ install_hook_script() {
|
|
|
383
362
|
}
|
|
384
363
|
|
|
385
364
|
write_hooks_json() {
|
|
386
|
-
|
|
365
|
+
local hook_command
|
|
366
|
+
hook_command="$(jq -rn --arg path "$HOOK_DST" '$path | @sh')"
|
|
367
|
+
jq --arg command "$hook_command" '.hooks[][].command = $command' \
|
|
368
|
+
"$HOOKS_TEMPLATE" >"$HOOKS_JSON"
|
|
387
369
|
}
|
|
388
370
|
|
|
389
371
|
uninstall_hooks() {
|