sneakoscope 0.9.4 → 0.9.6
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/package.json +1 -1
- package/src/cli/install-helpers.mjs +64 -3
- package/src/cli/main.mjs +5 -0
- package/src/core/fsx.mjs +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.6",
|
|
5
5
|
"description": "Sneakoscope Codex: database-safe Codex CLI/App harness with Team, Goal, AutoResearch, TriWiki, and Honest Mode.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
|
|
@@ -793,8 +793,34 @@ export async function maybePromptCodexLbSetupForLaunch(args = [], opts = {}) {
|
|
|
793
793
|
if (codexLogin.status === 'synced') console.log('codex-lb auth synced with Codex CLI login cache.');
|
|
794
794
|
const chainHealth = await checkCodexLbResponseChain(status, opts);
|
|
795
795
|
if (!chainHealth.ok && chainHealth.chain_unhealthy) {
|
|
796
|
-
|
|
797
|
-
|
|
796
|
+
// `previous_response_not_found` is normal for stateless LB deployments that don't persist
|
|
797
|
+
// Responses across requests. The codex-lb provider still works fine — only the chained
|
|
798
|
+
// health probe fails. Keep codex-lb active and just warn.
|
|
799
|
+
if (chainHealth.status === 'previous_response_not_found') {
|
|
800
|
+
console.log('codex-lb response chain check: previous_response_id not persisted by the load balancer (this is normal for stateless deployments). Keeping codex-lb active.');
|
|
801
|
+
return { status: 'present', ...status, codex_environment: codexEnvironment, codex_login: codexLogin, chain_health: chainHealth };
|
|
802
|
+
}
|
|
803
|
+
// Hard chain failure (auth rejected, timeout, missing base URL, etc.). Don't silently
|
|
804
|
+
// demote a configured codex-lb to ChatGPT OAuth — surface the failure and let the user
|
|
805
|
+
// decide. Default keeps codex-lb (just press Enter).
|
|
806
|
+
console.log(`codex-lb response chain check failed (${chainHealth.status}${chainHealth.error ? `: ${chainHealth.error}` : ''}).`);
|
|
807
|
+
if (process.env.SKS_CODEX_LB_AUTOBYPASS === '1') {
|
|
808
|
+
console.log('SKS_CODEX_LB_AUTOBYPASS=1 set; bypassing codex-lb to ChatGPT OAuth for this launch.');
|
|
809
|
+
return { status: 'chain_unhealthy', ...status, ok: false, codex_environment: codexEnvironment, codex_login: codexLogin, chain_health: chainHealth, bypass_codex_lb: true };
|
|
810
|
+
}
|
|
811
|
+
if (canAskYesNo()) {
|
|
812
|
+
const answer = (await askPostinstallQuestion('Use codex-lb anyway, or fall back to ChatGPT OAuth? [LB/oauth] ')).trim().toLowerCase();
|
|
813
|
+
if (/^(oauth|o|chatgpt|fall ?back|n|no|아니|아니요|ㄴ)$/.test(answer)) {
|
|
814
|
+
console.log('Falling back to ChatGPT OAuth for this launch. Re-enable codex-lb anytime with `sks codex-lb repair`.');
|
|
815
|
+
return { status: 'chain_unhealthy', ...status, ok: false, codex_environment: codexEnvironment, codex_login: codexLogin, chain_health: chainHealth, bypass_codex_lb: true };
|
|
816
|
+
}
|
|
817
|
+
console.log('Keeping codex-lb active. To switch back to ChatGPT OAuth: `sks codex-lb release`.');
|
|
818
|
+
return { status: 'present', ...status, codex_environment: codexEnvironment, codex_login: codexLogin, chain_health: chainHealth };
|
|
819
|
+
}
|
|
820
|
+
// Non-interactive context with no opt-out env var. The user explicitly configured codex-lb,
|
|
821
|
+
// so default to keeping it active rather than silently swapping providers.
|
|
822
|
+
console.log('Non-interactive launch + chain check failure. Keeping codex-lb active. Set SKS_CODEX_LB_AUTOBYPASS=1 to auto-bypass to ChatGPT OAuth.');
|
|
823
|
+
return { status: 'present', ...status, codex_environment: codexEnvironment, codex_login: codexLogin, chain_health: chainHealth };
|
|
798
824
|
}
|
|
799
825
|
return { status: 'present', ...status, codex_environment: codexEnvironment, codex_login: codexLogin, chain_health: chainHealth };
|
|
800
826
|
}
|
|
@@ -1897,7 +1923,42 @@ export async function selftestCodexLb(tmp) {
|
|
|
1897
1923
|
return new Response(JSON.stringify({ error: { type: 'invalid_request_error', code: 'previous_response_not_found', message: 'Previous response not found.', param: 'previous_response_id' } }), { status: 400, headers: { 'content-type': 'application/json' } });
|
|
1898
1924
|
}
|
|
1899
1925
|
});
|
|
1900
|
-
if (nonInteractiveBrokenLaunch.status !== '
|
|
1926
|
+
if (nonInteractiveBrokenLaunch.status !== 'present' || nonInteractiveBrokenLaunch.bypass_codex_lb === true || nonInteractiveBrokenLaunch.chain_health?.status !== 'previous_response_not_found') throw new Error('selftest: previous_response_not_found should keep codex-lb active (stateless LB is normal), not silently bypass to ChatGPT OAuth');
|
|
1927
|
+
// Hard chain failure (e.g. 500) in non-interactive context should still keep codex-lb by default — the user explicitly configured it, so don't silently swap providers.
|
|
1928
|
+
const hardBrokenLaunchCalls = [];
|
|
1929
|
+
const hardBrokenLaunch = await maybePromptCodexLbSetupForLaunch([], {
|
|
1930
|
+
home: codexLbHome,
|
|
1931
|
+
apiKey: 'sk-test',
|
|
1932
|
+
codexBin: path.join(codexLbFakeBin, 'codex'),
|
|
1933
|
+
syncLaunchEnv: false,
|
|
1934
|
+
timeoutMs: 1000,
|
|
1935
|
+
fetch: async (_url, init) => {
|
|
1936
|
+
hardBrokenLaunchCalls.push({ body: JSON.parse(init.body) });
|
|
1937
|
+
if (!hardBrokenLaunchCalls[hardBrokenLaunchCalls.length - 1].body.previous_response_id) return new Response(JSON.stringify({ id: 'resp_hardbroken_first' }), { status: 200, headers: { 'content-type': 'application/json' } });
|
|
1938
|
+
return new Response(JSON.stringify({ error: { type: 'server_error', code: 'internal_error', message: 'simulated upstream failure' } }), { status: 500, headers: { 'content-type': 'application/json' } });
|
|
1939
|
+
}
|
|
1940
|
+
});
|
|
1941
|
+
if (hardBrokenLaunch.status !== 'present' || hardBrokenLaunch.bypass_codex_lb === true || hardBrokenLaunch.chain_health?.status !== 'second_request_failed') throw new Error('selftest: hard codex-lb chain failure in non-interactive launch should default to keeping codex-lb active, not silently bypass');
|
|
1942
|
+
// SKS_CODEX_LB_AUTOBYPASS=1 restores the old silent-bypass behavior for CI/automation.
|
|
1943
|
+
process.env.SKS_CODEX_LB_AUTOBYPASS = '1';
|
|
1944
|
+
let autobypassLaunch;
|
|
1945
|
+
try {
|
|
1946
|
+
autobypassLaunch = await maybePromptCodexLbSetupForLaunch([], {
|
|
1947
|
+
home: codexLbHome,
|
|
1948
|
+
apiKey: 'sk-test',
|
|
1949
|
+
codexBin: path.join(codexLbFakeBin, 'codex'),
|
|
1950
|
+
syncLaunchEnv: false,
|
|
1951
|
+
timeoutMs: 1000,
|
|
1952
|
+
fetch: async (_url, init) => {
|
|
1953
|
+
const body = JSON.parse(init.body);
|
|
1954
|
+
if (!body.previous_response_id) return new Response(JSON.stringify({ id: 'resp_autobypass_first' }), { status: 200, headers: { 'content-type': 'application/json' } });
|
|
1955
|
+
return new Response(JSON.stringify({ error: { type: 'server_error', code: 'internal_error', message: 'simulated upstream failure' } }), { status: 500, headers: { 'content-type': 'application/json' } });
|
|
1956
|
+
}
|
|
1957
|
+
});
|
|
1958
|
+
} finally {
|
|
1959
|
+
delete process.env.SKS_CODEX_LB_AUTOBYPASS;
|
|
1960
|
+
}
|
|
1961
|
+
if (autobypassLaunch.status !== 'chain_unhealthy' || autobypassLaunch.bypass_codex_lb !== true || autobypassLaunch.chain_health?.status !== 'second_request_failed') throw new Error('selftest: SKS_CODEX_LB_AUTOBYPASS=1 should bypass codex-lb on hard chain failure');
|
|
1901
1962
|
await writeTextAtomic(path.join(codexLbHome, '.codex', 'config.toml'), 'model = "gpt-5.5"\nservice_tier = "fast"\n');
|
|
1902
1963
|
await writeTextAtomic(path.join(codexLbHome, '.codex', 'sks-codex-lb.env'), "export CODEX_LB_BASE_URL='https://lb.example.test/backend-api/codex'\nexport CODEX_LB_API_KEY='sk-test'\n");
|
|
1903
1964
|
const missingProviderLaunchCalls = [];
|
package/src/cli/main.mjs
CHANGED
|
@@ -2070,6 +2070,11 @@ function readFlagValue(args, name, fallback) {
|
|
|
2070
2070
|
}
|
|
2071
2071
|
|
|
2072
2072
|
async function selftest() {
|
|
2073
|
+
// Force non-interactive mode for the entire selftest so any in-process call that hits
|
|
2074
|
+
// canAskYesNo() (codex-lb provider-restore prompt, chain-failure prompt, etc.) takes the
|
|
2075
|
+
// non-interactive fallback path instead of bubbling a live readline prompt up to the
|
|
2076
|
+
// user's terminal (e.g. during `npm publish` -> prepublishOnly -> release:check -> selftest).
|
|
2077
|
+
process.env.CI = 'true';
|
|
2073
2078
|
const tmp = tmpdir();
|
|
2074
2079
|
process.chdir(tmp);
|
|
2075
2080
|
await initProject(tmp, {});
|
package/src/core/fsx.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import os from 'node:os';
|
|
|
5
5
|
import crypto from 'node:crypto';
|
|
6
6
|
import { spawn } from 'node:child_process';
|
|
7
7
|
|
|
8
|
-
export const PACKAGE_VERSION = '0.9.
|
|
8
|
+
export const PACKAGE_VERSION = '0.9.6';
|
|
9
9
|
export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
|
|
10
10
|
export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
|
|
11
11
|
|