subconscious-cli 6.3.0 → 7.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.
package/bin/cli.js CHANGED
@@ -35,6 +35,7 @@ import {
35
35
  } from './harness-manifest.js';
36
36
  import { headlessPromptIndex } from './headless-args.js';
37
37
  import { resolveModelCatalog } from './models.js';
38
+ import { ensureSystemCa, refuseUnsupportedSystemCa } from './network.js';
38
39
  import {
39
40
  configCommand,
40
41
  DEFAULT_PROFILE,
@@ -44,6 +45,7 @@ import {
44
45
  printConfigHelp,
45
46
  RUNBOOK_DEFAULTS,
46
47
  resolvedModelSetting,
48
+ systemCaEnabledFor,
47
49
  updatePlatformUrlCommand,
48
50
  updateUrlCommand,
49
51
  validateProfileName,
@@ -58,6 +60,23 @@ function isHelpArg(arg) {
58
60
  return arg === 'help' || arg === '-h' || arg === '--help';
59
61
  }
60
62
 
63
+ // Commands that never make a network request.
64
+ const OFFLINE_COMMANDS = new Set([
65
+ '--help',
66
+ '-h',
67
+ 'help',
68
+ 'config',
69
+ 'update-key',
70
+ 'logout',
71
+ 'setup',
72
+ 'settings',
73
+ 'cursor',
74
+ ]);
75
+
76
+ function needsNetwork(args) {
77
+ return !OFFLINE_COMMANDS.has(args[0]) && !isHelpArg(args[1]);
78
+ }
79
+
61
80
  function printHelp() {
62
81
  const agents = agentList()
63
82
  .map(
@@ -122,6 +141,9 @@ ${agents}
122
141
  ${c.dim}$${c.reset} subc codex headless "fix the failing test"
123
142
  ${c.dim}$${c.reset} subc -p staging codex
124
143
 
144
+ ${c.bold}Network${c.reset}
145
+ Behind a proxy or a TLS-inspecting firewall? Run ${c.cyan}subc login help${c.reset}.
146
+
125
147
  ${c.dim}Use subc <command> help for command-specific usage.${c.reset}
126
148
  `);
127
149
  }
@@ -136,6 +158,16 @@ Usage:
136
158
  Authenticate and save an API key to the selected profile.
137
159
  Opens a browser to a one-time login link. If the browser does not open, use the URL printed in the terminal.
138
160
  To sign in without a browser, copy an API key from the dashboard and run subc update-key <your-api-key>.
161
+
162
+ Behind a proxy or firewall:
163
+ If login fails with ENOTFOUND, ECONNREFUSED or a timeout, the network may require a proxy.
164
+ Set HTTPS_PROXY=http://host:port (or http://user:pass@host:port) and retry.
165
+ NO_PROXY=host1,.example.com lists hosts to reach directly, not through the proxy.
166
+ If the error names a certificate (SELF_SIGNED_CERT_IN_CHAIN, UNABLE_TO_VERIFY_LEAF_SIGNATURE),
167
+ the proxy re-signs TLS traffic. Ask IT for its root certificate, then either:
168
+ export NODE_EXTRA_CA_CERTS=/path/to/corporate-root-ca.pem
169
+ or set SYSTEM_CA=on in the profile (subc config edit) to trust the OS certificate store. Needs Node 22.15 or newer.
170
+ If nothing works, subc update-key <your-api-key> saves a key without any network request.
139
171
  `,
140
172
  logout: `
141
173
  Usage:
@@ -369,6 +401,16 @@ async function main() {
369
401
  return;
370
402
  }
371
403
 
404
+ // Trust the OS certificate store before any request when the profile opts in.
405
+ // Node reads --use-system-ca at startup, so this re-execs once. Commands that
406
+ // make no request skip it, so help and config edit still work on old Node.
407
+ if (needsNetwork(args)) {
408
+ const profile = await loadProfile(profileName);
409
+ const systemCaEnabled = systemCaEnabledFor(profile);
410
+ if (refuseUnsupportedSystemCa(systemCaEnabled, profile.path)) return;
411
+ if (systemCaEnabled && (await ensureSystemCa())) return;
412
+ }
413
+
372
414
  const launchTui =
373
415
  !command &&
374
416
  process.stdin.isTTY === true &&
package/bin/feedback.js CHANGED
@@ -12,6 +12,7 @@ import { createInterface } from 'node:readline/promises';
12
12
  import { getApiKey, getPlatformUrl } from './auth.js';
13
13
  import { imageContentType, readClipboardImage } from './clipboard-image.js';
14
14
  import { c } from './colors.js';
15
+ import { proxyAwareFetch } from './network.js';
15
16
  import { DEFAULT_PROFILE } from './profiles.js';
16
17
 
17
18
  export const FEEDBACK_API_PATH = '/api/cli/feedback';
@@ -111,7 +112,7 @@ export async function submitFeedback(
111
112
  apiKey,
112
113
  platformUrl,
113
114
  payload,
114
- fetchImpl = fetch,
115
+ fetchImpl = proxyAwareFetch,
115
116
  ) {
116
117
  const res = await fetchImpl(
117
118
  `${platformUrl.replace(/\/$/, '')}${FEEDBACK_API_PATH}`,
package/bin/models.js CHANGED
@@ -7,6 +7,8 @@
7
7
  * when the gateway is offline or returns nothing usable.
8
8
  */
9
9
 
10
+ import { proxyAwareFetch } from './network.js';
11
+
10
12
  const MODEL_ID_PATTERN = /^[-A-Za-z0-9._:/+]+$/;
11
13
  export const DEFAULT_MODEL_FETCH_TIMEOUT_MS = 3000;
12
14
  export const AVAILABLE_MODELS_PATH = '/v1/models/available';
@@ -72,7 +74,7 @@ export async function fetchGatewayModels({
72
74
  baseUrl,
73
75
  apiKey,
74
76
  path = PUBLIC_MODELS_PATH,
75
- fetchImpl = globalThis.fetch,
77
+ fetchImpl = proxyAwareFetch,
76
78
  timeoutMs = DEFAULT_MODEL_FETCH_TIMEOUT_MS,
77
79
  signal,
78
80
  }) {
@@ -176,7 +178,7 @@ export async function resolveModelCatalog({
176
178
  selectedModel,
177
179
  fallbackModels = [],
178
180
  pinnedModels,
179
- fetchImpl = globalThis.fetch,
181
+ fetchImpl = proxyAwareFetch,
180
182
  timeoutMs = DEFAULT_MODEL_FETCH_TIMEOUT_MS,
181
183
  signal,
182
184
  }) {
Binary file
Binary file
Binary file
Binary file