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
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "pi",
|
|
3
|
+
"command": "pi",
|
|
4
|
+
"aliases": [],
|
|
5
|
+
"name": "Pi",
|
|
6
|
+
"description": "Refresh Pi with the live Subconscious model catalog and launch the active profile model.",
|
|
7
|
+
"protocol": "openai",
|
|
8
|
+
"homepage": "https://pi.dev",
|
|
9
|
+
"install": {
|
|
10
|
+
"commands": null,
|
|
11
|
+
"url": "https://pi.dev",
|
|
12
|
+
"method": null,
|
|
13
|
+
"package": null,
|
|
14
|
+
"version": null,
|
|
15
|
+
"minimum_version": null,
|
|
16
|
+
"verified": false,
|
|
17
|
+
"note": "No install command is defined; subc expects pi on PATH."
|
|
18
|
+
},
|
|
19
|
+
"runbook": {
|
|
20
|
+
"mode": "launch",
|
|
21
|
+
"script": "run.sh",
|
|
22
|
+
"setup_script": "install.sh",
|
|
23
|
+
"setup_actions": ["install", "status", "uninstall"],
|
|
24
|
+
"after_install": "Start a fresh session with subc pi."
|
|
25
|
+
},
|
|
26
|
+
"help": {
|
|
27
|
+
"usage": "subc [-p NAME] pi [help|install|status|uninstall] [Pi arguments...]",
|
|
28
|
+
"behavior": "Refreshes the persistent Subconscious provider from the live catalog, then launches Pi.",
|
|
29
|
+
"options": [
|
|
30
|
+
["help", "Show this help"],
|
|
31
|
+
["install", "Refresh the Subconscious provider without launching Pi"],
|
|
32
|
+
["status", "Inspect the persistent Pi provider"],
|
|
33
|
+
["uninstall", "Remove only the Subconscious Pi provider and extension"],
|
|
34
|
+
["--model MODEL", "Override the profile model for this launch"]
|
|
35
|
+
],
|
|
36
|
+
"args": ["ARGS...", "Pass arguments directly to Pi"]
|
|
37
|
+
},
|
|
38
|
+
"sessions": { "key": "pi", "portable": true },
|
|
39
|
+
"prerequisites": [
|
|
40
|
+
{
|
|
41
|
+
"command": "jq",
|
|
42
|
+
"needed_for": "install and every launch",
|
|
43
|
+
"required": true
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"launch": {
|
|
47
|
+
"argv": [
|
|
48
|
+
"pi",
|
|
49
|
+
"--provider",
|
|
50
|
+
"subconscious",
|
|
51
|
+
"--model",
|
|
52
|
+
"{model}",
|
|
53
|
+
"{args}"
|
|
54
|
+
],
|
|
55
|
+
"headless_argv": [
|
|
56
|
+
"pi",
|
|
57
|
+
"--provider",
|
|
58
|
+
"subconscious",
|
|
59
|
+
"--model",
|
|
60
|
+
"{model}",
|
|
61
|
+
"--print",
|
|
62
|
+
"{args}"
|
|
63
|
+
],
|
|
64
|
+
"headless_stdin": "{prompt}",
|
|
65
|
+
"headless_platforms": ["darwin", "linux"],
|
|
66
|
+
"resume": ["--session", "{sessionFile}"],
|
|
67
|
+
"handoff": ["{prompt}"],
|
|
68
|
+
"persistent_setup": true,
|
|
69
|
+
"note": "Each launch first runs install.sh install, which rewrites the persistent files below."
|
|
70
|
+
},
|
|
71
|
+
"inputs": [
|
|
72
|
+
{
|
|
73
|
+
"name": "PI_API_KEY",
|
|
74
|
+
"label": "Pi API key",
|
|
75
|
+
"description": "Pi-specific credential override; blank uses API_KEY.",
|
|
76
|
+
"type": "secret"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"name": "PI_CONTEXT_WINDOW",
|
|
80
|
+
"default": 5000000,
|
|
81
|
+
"label": "Context window",
|
|
82
|
+
"description": "Pi context window used to determine compaction.",
|
|
83
|
+
"type": "integer",
|
|
84
|
+
"min": 1
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"name": "PI_MAX_TOKENS",
|
|
88
|
+
"default": 65536,
|
|
89
|
+
"label": "Maximum output tokens",
|
|
90
|
+
"description": "Maximum output tokens advertised to Pi.",
|
|
91
|
+
"type": "integer",
|
|
92
|
+
"min": 1
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
"env": [],
|
|
96
|
+
"config": [
|
|
97
|
+
{
|
|
98
|
+
"kind": "file",
|
|
99
|
+
"path": "~/.pi/agent/models.json",
|
|
100
|
+
"lifetime": "persistent",
|
|
101
|
+
"value": {
|
|
102
|
+
"providers.subconscious.baseUrl": "{baseUrlV1}",
|
|
103
|
+
"providers.subconscious.api": "openai-completions",
|
|
104
|
+
"providers.subconscious.apiKey": "{apiKey}",
|
|
105
|
+
"providers.subconscious.headers": {
|
|
106
|
+
"x-subconscious-client": "pi"
|
|
107
|
+
},
|
|
108
|
+
"providers.subconscious.models[].contextWindow": "${PI_CONTEXT_WINDOW}",
|
|
109
|
+
"providers.subconscious.models[].maxTokens": "${PI_MAX_TOKENS}",
|
|
110
|
+
"providers.subconscious.models[].compat": {
|
|
111
|
+
"sendSessionAffinityHeaders": true,
|
|
112
|
+
"sessionAffinityFormat": "openai-nosession"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"description": "Subconscious provider, written by install.sh and merged in; other providers are kept. Mode 600; holds the key in plain text."
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"kind": "file",
|
|
119
|
+
"path": "~/.pi/agent/subconscious.env",
|
|
120
|
+
"lifetime": "persistent",
|
|
121
|
+
"description": "SUBCONSCIOUS_GATEWAY_URL and SUBCONSCIOUS_API_KEY for the compaction extension (mode 600)."
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"kind": "file",
|
|
125
|
+
"path": "~/.pi/agent/extensions/subconscious-compaction.ts",
|
|
126
|
+
"lifetime": "persistent",
|
|
127
|
+
"description": "Compaction reporting extension."
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"kind": "dir",
|
|
131
|
+
"path": "~/.pi/agent/extensions/subconscious-image-window",
|
|
132
|
+
"lifetime": "persistent",
|
|
133
|
+
"description": "Extension that keeps requests to the newest 30 images."
|
|
134
|
+
}
|
|
135
|
+
],
|
|
136
|
+
"capabilities": {
|
|
137
|
+
"compaction": {
|
|
138
|
+
"default": "on",
|
|
139
|
+
"on": {
|
|
140
|
+
"set_by_subc": true,
|
|
141
|
+
"kind": "config-field",
|
|
142
|
+
"name": "providers.subconscious.models[].contextWindow",
|
|
143
|
+
"value": "${PI_CONTEXT_WINDOW}",
|
|
144
|
+
"verified": false,
|
|
145
|
+
"note": "subc sets contextWindow. That Pi compacts relative to it comes only from the profile setting description.",
|
|
146
|
+
"config": "~/.pi/agent/models.json"
|
|
147
|
+
},
|
|
148
|
+
"off": {
|
|
149
|
+
"set_by_subc": false,
|
|
150
|
+
"kind": "config-field",
|
|
151
|
+
"name": "compaction.enabled",
|
|
152
|
+
"value": false,
|
|
153
|
+
"verified": false,
|
|
154
|
+
"note": "Upstream Pi setting. subc never sets it, and this repo does not confirm its location or behaviour.",
|
|
155
|
+
"config": "Pi settings (location unverified)"
|
|
156
|
+
},
|
|
157
|
+
"threshold": {
|
|
158
|
+
"set_by_subc": true,
|
|
159
|
+
"kind": "config-field",
|
|
160
|
+
"name": "providers.subconscious.models[].contextWindow",
|
|
161
|
+
"value": "${PI_CONTEXT_WINDOW}",
|
|
162
|
+
"verified": false,
|
|
163
|
+
"note": "subc sets contextWindow. That Pi compacts relative to it comes only from the profile setting description. Pi's reserveTokens also moves the trigger; subc never sets it.",
|
|
164
|
+
"semantics": "window",
|
|
165
|
+
"config": "~/.pi/agent/models.json"
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
"mcp": {
|
|
169
|
+
"configured_by_subc": false,
|
|
170
|
+
"transports": null,
|
|
171
|
+
"verified": false,
|
|
172
|
+
"note": "subc configures no MCP servers."
|
|
173
|
+
},
|
|
174
|
+
"headers": [
|
|
175
|
+
{
|
|
176
|
+
"name": "x-subconscious-client",
|
|
177
|
+
"value": "pi",
|
|
178
|
+
"on": "model requests",
|
|
179
|
+
"set_by_subc": true,
|
|
180
|
+
"verified": true
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"name": "x-session-affinity",
|
|
184
|
+
"value": "session ID",
|
|
185
|
+
"on": "model requests",
|
|
186
|
+
"set_by_subc": true,
|
|
187
|
+
"verified": false,
|
|
188
|
+
"note": "Enabled by compat.sendSessionAffinityHeaders; the header name comes from an install.sh comment."
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"name": "Authorization",
|
|
192
|
+
"value": "Bearer {apiKey}",
|
|
193
|
+
"on": "extension POSTs to {baseUrl}/v1/agent-hooks",
|
|
194
|
+
"set_by_subc": true,
|
|
195
|
+
"verified": true
|
|
196
|
+
}
|
|
197
|
+
],
|
|
198
|
+
"hooks": [
|
|
199
|
+
{
|
|
200
|
+
"event": "session_before_compact",
|
|
201
|
+
"posts": "conversation_compaction phase=start",
|
|
202
|
+
"endpoint": "{baseUrl}/v1/agent-hooks",
|
|
203
|
+
"config": "~/.pi/agent/extensions/subconscious-compaction.ts",
|
|
204
|
+
"installed_by": ["launch", "install"],
|
|
205
|
+
"verified": true
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"event": "session_compact",
|
|
209
|
+
"posts": "conversation_compaction phase=end",
|
|
210
|
+
"endpoint": "{baseUrl}/v1/agent-hooks",
|
|
211
|
+
"config": "~/.pi/agent/extensions/subconscious-compaction.ts",
|
|
212
|
+
"installed_by": ["launch", "install"],
|
|
213
|
+
"verified": true
|
|
214
|
+
}
|
|
215
|
+
]
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -47,26 +47,21 @@
|
|
|
47
47
|
set -euo pipefail
|
|
48
48
|
|
|
49
49
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
50
|
-
source "${SCRIPT_DIR}/../
|
|
50
|
+
source "${SCRIPT_DIR}/../lib.sh"
|
|
51
51
|
EXTENSION_SRC="${SCRIPT_DIR}/subconscious-compaction.ts"
|
|
52
|
-
|
|
53
|
-
# Load shared env from SUBC_ENV_FILE, or a sibling .env / env.example.
|
|
54
|
-
SHARED_ENV="${SUBC_ENV_FILE:-${SCRIPT_DIR}/../.env}"
|
|
55
|
-
[[ -f "$SHARED_ENV" ]] || SHARED_ENV="${SCRIPT_DIR}/../env.example"
|
|
56
|
-
if [[ -f "$SHARED_ENV" ]]; then set -a; source "$SHARED_ENV"; set +a; fi
|
|
52
|
+
IMAGE_WINDOW_SRC="${SCRIPT_DIR}/../image-window"
|
|
57
53
|
|
|
58
54
|
COMMAND="install"
|
|
59
55
|
GATEWAY_URL="${GATEWAY_URL:-}"
|
|
60
56
|
API_KEY="${PI_API_KEY:-${API_KEY:-}}"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
MAX_TOKENS="${PI_MAX_TOKENS:-65536}"
|
|
57
|
+
CONTEXT_WINDOW="${PI_CONTEXT_WINDOW:-}"
|
|
58
|
+
MAX_TOKENS="${PI_MAX_TOKENS:-}"
|
|
64
59
|
|
|
65
60
|
usage() {
|
|
66
61
|
cat <<'EOF'
|
|
67
62
|
Usage:
|
|
68
|
-
subc pi install [--gateway-url URL] [--api-key KEY] [--
|
|
69
|
-
[--
|
|
63
|
+
subc pi install [--gateway-url URL] [--api-key KEY] [--context-window N]
|
|
64
|
+
[--max-tokens N]
|
|
70
65
|
subc pi uninstall
|
|
71
66
|
subc pi status
|
|
72
67
|
|
|
@@ -91,10 +86,6 @@ while [[ $# -gt 0 ]]; do
|
|
|
91
86
|
API_KEY="${2:-}"
|
|
92
87
|
shift 2
|
|
93
88
|
;;
|
|
94
|
-
--model)
|
|
95
|
-
MODEL="${2:-}"
|
|
96
|
-
shift 2
|
|
97
|
-
;;
|
|
98
89
|
--context-window)
|
|
99
90
|
CONTEXT_WINDOW="${2:-}"
|
|
100
91
|
shift 2
|
|
@@ -115,35 +106,8 @@ while [[ $# -gt 0 ]]; do
|
|
|
115
106
|
esac
|
|
116
107
|
done
|
|
117
108
|
|
|
118
|
-
DEFAULT_SUBCONSCIOUS_MODELS="subconscious/glm-5.3-marathon
|
|
119
|
-
subconscious/glm-5.2
|
|
120
|
-
subconscious/tim-qwen3.6-27b
|
|
121
|
-
subconscious/deepseek-v4-flash-marathon
|
|
122
|
-
subconscious/deepseek-v4.1-flash-marathon"
|
|
123
|
-
SUPPORTED_MODELS=()
|
|
124
|
-
|
|
125
|
-
add_supported_model() {
|
|
126
|
-
local model_id="$1" existing
|
|
127
|
-
[[ -n "$model_id" ]] || return 0
|
|
128
|
-
if [[ ! "$model_id" =~ ^[-A-Za-z0-9._:/+]+$ ]]; then
|
|
129
|
-
echo "error: invalid model id: $model_id" >&2
|
|
130
|
-
exit 1
|
|
131
|
-
fi
|
|
132
|
-
if [[ "${#SUPPORTED_MODELS[@]}" -gt 0 ]]; then
|
|
133
|
-
for existing in "${SUPPORTED_MODELS[@]}"; do
|
|
134
|
-
[[ "$existing" == "$model_id" ]] && return 0
|
|
135
|
-
done
|
|
136
|
-
fi
|
|
137
|
-
SUPPORTED_MODELS+=("$model_id")
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
add_supported_model "$MODEL"
|
|
141
|
-
while IFS= read -r model_id; do
|
|
142
|
-
add_supported_model "$model_id"
|
|
143
|
-
done <<< "${SUBCONSCIOUS_MODELS:-$DEFAULT_SUBCONSCIOUS_MODELS}"
|
|
144
|
-
|
|
145
109
|
MODEL_ENTRIES_JSON=""
|
|
146
|
-
|
|
110
|
+
while IFS= read -r model_id; do
|
|
147
111
|
vision_fields=""
|
|
148
112
|
if subc_model_supports_vision "$model_id"; then
|
|
149
113
|
vision_fields=',"input":["text","image"]'
|
|
@@ -154,12 +118,14 @@ for model_id in "${SUPPORTED_MODELS[@]}"; do
|
|
|
154
118
|
else
|
|
155
119
|
MODEL_ENTRIES_JSON="$model_json"
|
|
156
120
|
fi
|
|
157
|
-
done
|
|
121
|
+
done <<< "${SUBC_MODEL_IDS:-}"
|
|
158
122
|
|
|
159
123
|
PI_DIR="${PI_CODING_AGENT_DIR:-${HOME}/.pi/agent}"
|
|
160
124
|
MODELS_JSON="${PI_DIR}/models.json"
|
|
161
125
|
EXTENSIONS_DIR="${PI_DIR}/extensions"
|
|
162
126
|
EXTENSION_DST="${EXTENSIONS_DIR}/subconscious-compaction.ts"
|
|
127
|
+
# Keeps requests at the newest 30 images so a long session's upload stops growing.
|
|
128
|
+
IMAGE_WINDOW_DST="${EXTENSIONS_DIR}/subconscious-image-window"
|
|
163
129
|
ENV_FILE="${PI_DIR}/subconscious.env"
|
|
164
130
|
MARKER='x-subconscious-client'
|
|
165
131
|
|
|
@@ -222,6 +188,8 @@ write_extension() {
|
|
|
222
188
|
fi
|
|
223
189
|
mkdir -p "$EXTENSIONS_DIR"
|
|
224
190
|
cp "$EXTENSION_SRC" "$EXTENSION_DST"
|
|
191
|
+
rm -rf "$IMAGE_WINDOW_DST"
|
|
192
|
+
cp -R "$IMAGE_WINDOW_SRC" "$IMAGE_WINDOW_DST"
|
|
225
193
|
}
|
|
226
194
|
|
|
227
195
|
uninstall_config() {
|
|
@@ -235,6 +203,7 @@ uninstall_config() {
|
|
|
235
203
|
echo "No Pi models.json at $MODELS_JSON"
|
|
236
204
|
fi
|
|
237
205
|
rm -f "$EXTENSION_DST" "$ENV_FILE"
|
|
206
|
+
rm -rf "$IMAGE_WINDOW_DST"
|
|
238
207
|
}
|
|
239
208
|
|
|
240
209
|
status() {
|
|
@@ -253,6 +222,11 @@ status() {
|
|
|
253
222
|
else
|
|
254
223
|
echo "compaction extension: not installed"
|
|
255
224
|
fi
|
|
225
|
+
if [[ -d "$IMAGE_WINDOW_DST" ]]; then
|
|
226
|
+
echo "image window extension: $IMAGE_WINDOW_DST (installed)"
|
|
227
|
+
else
|
|
228
|
+
echo "image window extension: not installed"
|
|
229
|
+
fi
|
|
256
230
|
if [[ -f "$ENV_FILE" ]]; then
|
|
257
231
|
echo "env: $ENV_FILE (present)"
|
|
258
232
|
else
|
package/bin/runbook/pi/run.sh
CHANGED
|
@@ -1,25 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Refresh the Subconscious provider from the live catalog, then
|
|
3
|
-
# Other providers in models.json are preserved.
|
|
2
|
+
# Refresh the Subconscious provider from the live catalog, then start the pi
|
|
3
|
+
# argv subc built. Other providers in models.json are preserved.
|
|
4
4
|
|
|
5
5
|
set -euo pipefail
|
|
6
6
|
|
|
7
7
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
-
|
|
9
|
-
API_KEY="${PI_API_KEY:-${API_KEY:-}}"
|
|
10
|
-
MODEL="${MODEL:-subconscious/glm-5.3-marathon}"
|
|
11
|
-
PI_DIR="${PI_CODING_AGENT_DIR:-${HOME}/.pi/agent}"
|
|
12
|
-
MODELS_JSON="${PI_DIR}/models.json"
|
|
8
|
+
source "${SCRIPT_DIR}/../lib.sh"
|
|
13
9
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
exit 1
|
|
17
|
-
fi
|
|
10
|
+
# stdin can hold a headless prompt, which belongs to Pi.
|
|
11
|
+
"${SCRIPT_DIR}/install.sh" install </dev/null >/dev/null
|
|
18
12
|
|
|
19
|
-
"
|
|
20
|
-
--gateway-url "$GATEWAY_URL" \
|
|
21
|
-
--api-key "$API_KEY" \
|
|
22
|
-
--model "$MODEL" \
|
|
23
|
-
>/dev/null
|
|
24
|
-
|
|
25
|
-
exec pi --provider subconscious --model "$MODEL" "$@"
|
|
13
|
+
subc_exec -- "$@"
|
|
@@ -51,7 +51,9 @@ function loadSubconsciousEnvFile(): void {
|
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
53
|
try {
|
|
54
|
-
const
|
|
54
|
+
const directory =
|
|
55
|
+
process.env.PI_CODING_AGENT_DIR || join(homedir(), '.pi', 'agent');
|
|
56
|
+
const path = join(directory, 'subconscious.env');
|
|
55
57
|
const text = readFileSync(path, 'utf8');
|
|
56
58
|
for (const line of text.split('\n')) {
|
|
57
59
|
const trimmed = line.trim();
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"agents": [
|
|
3
|
+
"opencode",
|
|
4
|
+
"claude-code",
|
|
5
|
+
"codex",
|
|
6
|
+
"cursor",
|
|
7
|
+
"copilot",
|
|
8
|
+
"pi",
|
|
9
|
+
"deepseek-harness"
|
|
10
|
+
],
|
|
11
|
+
"defaults": {
|
|
12
|
+
"model": "subconscious/glm-5.3-marathon",
|
|
13
|
+
"models": [
|
|
14
|
+
"subconscious/glm-5.3-marathon",
|
|
15
|
+
"subconscious/glm-5.2",
|
|
16
|
+
"subconscious/tim-qwen3.6-27b",
|
|
17
|
+
"subconscious/deepseek-v4-flash-marathon",
|
|
18
|
+
"subconscious/deepseek-v4.1-flash-marathon"
|
|
19
|
+
],
|
|
20
|
+
"baseUrl": "https://api.subconscious.dev"
|
|
21
|
+
},
|
|
22
|
+
"model_capabilities": {
|
|
23
|
+
"subconscious/deepseek-v4.1-flash-marathon": { "vision": true }
|
|
24
|
+
},
|
|
25
|
+
"inputs": [
|
|
26
|
+
{
|
|
27
|
+
"name": "GATEWAY_URL",
|
|
28
|
+
"group": "shared",
|
|
29
|
+
"label": "Gateway URL",
|
|
30
|
+
"description": "Subconscious gateway origin shared by every integration.",
|
|
31
|
+
"type": "url",
|
|
32
|
+
"required": true
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "API_KEY",
|
|
36
|
+
"group": "shared",
|
|
37
|
+
"label": "Shared API key",
|
|
38
|
+
"description": "Default credential used when an agent-specific key is blank.",
|
|
39
|
+
"type": "secret"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "MODEL",
|
|
43
|
+
"group": "shared",
|
|
44
|
+
"label": "Default model",
|
|
45
|
+
"description": "Initial model used by coding-agent launches and setup. UNSET uses the first live catalog model.",
|
|
46
|
+
"type": "model"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "MAX_CONCURRENT_SUBAGENTS",
|
|
50
|
+
"default": 4,
|
|
51
|
+
"label": "Concurrent subagents",
|
|
52
|
+
"description": "Maximum concurrent Claude/Codex subagent threads.",
|
|
53
|
+
"type": "integer",
|
|
54
|
+
"min": 1
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
package/bin/sessions.js
CHANGED
|
@@ -2,6 +2,7 @@ import { spawnSync } from 'node:child_process';
|
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { AGENTS, agentById, agentCommandName } from './agent-data.js';
|
|
5
6
|
import { resolveAgent, runAgent } from './agents.js';
|
|
6
7
|
|
|
7
8
|
import { c } from './colors.js';
|
|
@@ -14,15 +15,25 @@ const MAX_INDEX_BYTES = 4 * 1024 * 1024;
|
|
|
14
15
|
const MAX_HANDOFF_MESSAGES = 24;
|
|
15
16
|
const MAX_HANDOFF_CHARS = 24_000;
|
|
16
17
|
const MAX_MESSAGE_CHARS = 4_000;
|
|
17
|
-
const SESSION_KEY_PATTERN =
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
const SESSION_KEY_PATTERN = new RegExp(
|
|
19
|
+
`^(${AGENTS.filter((agent) => agent.sessions)
|
|
20
|
+
.map((agent) => agent.sessions.key)
|
|
21
|
+
.join('|')}):[-A-Za-z0-9._]+$`,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export const SESSION_HARNESSES = Object.freeze(
|
|
25
|
+
Object.fromEntries(
|
|
26
|
+
AGENTS.filter((agent) => agent.sessions).map((agent) => [
|
|
27
|
+
agent.sessions.key,
|
|
28
|
+
Object.freeze({
|
|
29
|
+
name: agent.name,
|
|
30
|
+
command: agentCommandName(agent),
|
|
31
|
+
portable: agent.sessions.portable,
|
|
32
|
+
agentId: agent.id,
|
|
33
|
+
}),
|
|
34
|
+
]),
|
|
35
|
+
),
|
|
36
|
+
);
|
|
26
37
|
|
|
27
38
|
function cleanText(value) {
|
|
28
39
|
return String(value || '')
|
|
@@ -56,7 +67,10 @@ function parseLines(text) {
|
|
|
56
67
|
for (const line of text.split('\n')) {
|
|
57
68
|
if (!line.trim()) continue;
|
|
58
69
|
try {
|
|
59
|
-
|
|
70
|
+
const record = JSON.parse(line);
|
|
71
|
+
if (record && typeof record === 'object' && !Array.isArray(record)) {
|
|
72
|
+
records.push(record);
|
|
73
|
+
}
|
|
60
74
|
} catch {
|
|
61
75
|
// Session writers can leave a partial final line after an interrupted run.
|
|
62
76
|
}
|
|
@@ -217,14 +231,6 @@ function piMessages(records) {
|
|
|
217
231
|
});
|
|
218
232
|
}
|
|
219
233
|
|
|
220
|
-
function scMessages(records) {
|
|
221
|
-
return records.flatMap((record) => {
|
|
222
|
-
if (!['user', 'assistant'].includes(record.type)) return [];
|
|
223
|
-
const text = cleanText(record.text ?? record.content);
|
|
224
|
-
return text ? [{ role: record.type, text }] : [];
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
|
|
228
234
|
async function parseFileSession(entry, harness) {
|
|
229
235
|
const records = parseLines(await readBounded(entry.file, MAX_METADATA_BYTES));
|
|
230
236
|
if (!records.length) return null;
|
|
@@ -290,19 +296,6 @@ async function parseFileSession(entry, harness) {
|
|
|
290
296
|
});
|
|
291
297
|
}
|
|
292
298
|
|
|
293
|
-
if (harness === 'sc') {
|
|
294
|
-
const meta = records[0] || {};
|
|
295
|
-
const messages = scMessages(records);
|
|
296
|
-
const id = String(meta.id || filename).replace(/^session-/, '');
|
|
297
|
-
return sessionRecord(harness, id, {
|
|
298
|
-
title: messages.find((message) => message.role === 'user')?.text,
|
|
299
|
-
cwd: meta.cwd,
|
|
300
|
-
model: meta.model,
|
|
301
|
-
updated: entry.updated,
|
|
302
|
-
sourcePath: entry.file,
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
|
|
306
299
|
return null;
|
|
307
300
|
}
|
|
308
301
|
|
|
@@ -466,7 +459,6 @@ export async function discoverSessions(options = {}) {
|
|
|
466
459
|
claude: path.join(home, '.claude', 'projects'),
|
|
467
460
|
codex: path.join(home, '.codex', 'sessions'),
|
|
468
461
|
pi: path.join(home, '.pi', 'agent', 'sessions'),
|
|
469
|
-
sc: path.join(home, '.sc', 'sessions'),
|
|
470
462
|
};
|
|
471
463
|
const indexes =
|
|
472
464
|
options.indexes ||
|
|
@@ -486,7 +478,6 @@ export async function discoverSessions(options = {}) {
|
|
|
486
478
|
codex || discoverFileSessions(roots.codex, 'codex', max),
|
|
487
479
|
Promise.resolve(discoverOpenCodeSessions(execute, max)),
|
|
488
480
|
discoverFileSessions(roots.pi, 'pi', max),
|
|
489
|
-
discoverFileSessions(roots.sc, 'sc', max),
|
|
490
481
|
]);
|
|
491
482
|
const seen = new Set();
|
|
492
483
|
return groups
|
|
@@ -541,7 +532,6 @@ export async function readSessionMessages(session, options = {}) {
|
|
|
541
532
|
if (session.harness === 'claude') return claudeMessages(records);
|
|
542
533
|
if (session.harness === 'codex') return codexMessages(records);
|
|
543
534
|
if (session.harness === 'pi') return piMessages(records);
|
|
544
|
-
if (session.harness === 'sc') return scMessages(records);
|
|
545
535
|
return [];
|
|
546
536
|
}
|
|
547
537
|
|
|
@@ -594,22 +584,38 @@ export function buildHandoffPrompt(session, messages) {
|
|
|
594
584
|
.join('\n\n');
|
|
595
585
|
}
|
|
596
586
|
|
|
587
|
+
function sessionLaunch(harness) {
|
|
588
|
+
return agentById(SESSION_HARNESSES[harness]?.agentId)?.launch ?? {};
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// One pass, so a prompt that mentions a placeholder is passed unchanged.
|
|
592
|
+
function fillWords(words, values) {
|
|
593
|
+
return words.map((word) =>
|
|
594
|
+
word.replace(/\{(sessionId|sessionFile|prompt)\}/g, (_, name) =>
|
|
595
|
+
String(values[name]),
|
|
596
|
+
),
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
|
|
597
600
|
export function nativeResumeArgs(session) {
|
|
598
|
-
|
|
599
|
-
if (
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
601
|
+
const { resume } = sessionLaunch(session.harness);
|
|
602
|
+
if (!resume)
|
|
603
|
+
throw new Error(
|
|
604
|
+
`Native resume is not supported for ${session.harnessName}.`,
|
|
605
|
+
);
|
|
606
|
+
return fillWords(resume, {
|
|
607
|
+
sessionId: session.id,
|
|
608
|
+
sessionFile: session.sourcePath || session.id,
|
|
609
|
+
});
|
|
605
610
|
}
|
|
606
611
|
|
|
607
612
|
export function handoffLaunchArgs(targetHarness, prompt) {
|
|
608
|
-
|
|
609
|
-
if (
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
+
const { handoff } = sessionLaunch(targetHarness);
|
|
614
|
+
if (!handoff)
|
|
615
|
+
throw new Error(
|
|
616
|
+
`${SESSION_HARNESSES[targetHarness]?.name || targetHarness} cannot start an interactive handoff yet.`,
|
|
617
|
+
);
|
|
618
|
+
return fillWords(handoff, { prompt });
|
|
613
619
|
}
|
|
614
620
|
|
|
615
621
|
function sessionByKey(sessions, key) {
|
|
@@ -665,8 +671,7 @@ export async function sessionsCommand(argv, options = {}) {
|
|
|
665
671
|
const harnessIndex = argv.indexOf('--harness');
|
|
666
672
|
const requestedHarness =
|
|
667
673
|
harnessIndex >= 0 ? argv[harnessIndex + 1] : session.harness;
|
|
668
|
-
const targetHarness =
|
|
669
|
-
requestedHarness === 'marathon' ? 'sc' : requestedHarness;
|
|
674
|
+
const targetHarness = requestedHarness;
|
|
670
675
|
const target = SESSION_HARNESSES[targetHarness];
|
|
671
676
|
if (!target) throw new Error(`Unknown destination harness: ${targetHarness}`);
|
|
672
677
|
|
package/bin/tui.js
CHANGED
|
@@ -422,6 +422,19 @@ function spawnAndWait(command, args, options = {}) {
|
|
|
422
422
|
}
|
|
423
423
|
|
|
424
424
|
export async function runTui(options = {}) {
|
|
425
|
+
for (;;) {
|
|
426
|
+
const result = await runTuiOnce(options);
|
|
427
|
+
if (result?.args?.length !== 2 || result.args[0] !== '-p') return result;
|
|
428
|
+
options = {
|
|
429
|
+
...options,
|
|
430
|
+
profileName: result.args[1],
|
|
431
|
+
profile: undefined,
|
|
432
|
+
state: undefined,
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
async function runTuiOnce(options) {
|
|
425
438
|
const executable = await resolveTuiExecutable(options);
|
|
426
439
|
if (!executable) return null;
|
|
427
440
|
|