sneakoscope 1.0.6 → 1.0.8
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 +67 -1
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/bin/sks.js +1 -1
- package/dist/build-manifest.json +21 -1
- package/dist/cli/install-helpers.d.ts +2 -0
- package/dist/cli/install-helpers.js +75 -4
- package/dist/commands/codex-lb.js +51 -2
- package/dist/commands/image-ux-review.d.ts +320 -1
- package/dist/commands/wiki.d.ts +7 -1
- package/dist/core/codex-compat/codex-0-132.d.ts +46 -0
- package/dist/core/codex-compat/codex-0-132.js +105 -0
- package/dist/core/codex-compat/codex-compat-report.d.ts +46 -0
- package/dist/core/codex-compat/codex-compat-report.js +19 -3
- package/dist/core/codex-compat/codex-schema-snapshot.js +7 -7
- package/dist/core/codex-compat/codex-version-policy.d.ts +4 -2
- package/dist/core/codex-compat/codex-version-policy.js +5 -3
- package/dist/core/codex-exec-output-schema.d.ts +45 -0
- package/dist/core/codex-exec-output-schema.js +131 -0
- package/dist/core/codex-lb/codex-lb-setup.d.ts +19 -0
- package/dist/core/codex-lb/codex-lb-setup.js +58 -0
- package/dist/core/commands/computer-use-command.js +19 -3
- package/dist/core/commands/image-ux-review-command.d.ts +320 -1
- package/dist/core/commands/image-ux-review-command.js +281 -35
- package/dist/core/commands/wiki-command.d.ts +8 -2
- package/dist/core/commands/wiki-command.js +11 -2
- package/dist/core/computer-use-live-evidence.d.ts +109 -0
- package/dist/core/computer-use-live-evidence.js +276 -0
- package/dist/core/computer-use-status.d.ts +8 -1
- package/dist/core/computer-use-status.js +43 -24
- package/dist/core/evidence/evidence-router.js +17 -1
- package/dist/core/fsx.d.ts +1 -1
- package/dist/core/fsx.js +1 -1
- package/dist/core/goal-workflow.d.ts +6 -0
- package/dist/core/goal-workflow.js +6 -0
- package/dist/core/image-ux-review/callout-extraction.d.ts +47 -0
- package/dist/core/image-ux-review/callout-extraction.js +106 -0
- package/dist/core/image-ux-review/fix-loop.d.ts +31 -0
- package/dist/core/image-ux-review/fix-loop.js +35 -0
- package/dist/core/image-ux-review/fix-task-planner.d.ts +8 -0
- package/dist/core/image-ux-review/fix-task-planner.js +55 -0
- package/dist/core/image-ux-review/imagegen-adapter.d.ts +52 -0
- package/dist/core/image-ux-review/imagegen-adapter.js +69 -0
- package/dist/core/image-ux-review/recapture.d.ts +15 -0
- package/dist/core/image-ux-review/recapture.js +25 -0
- package/dist/core/image-ux-review.d.ts +270 -52
- package/dist/core/image-ux-review.js +318 -101
- package/dist/core/loop-blocker.d.ts +41 -0
- package/dist/core/loop-blocker.js +42 -0
- package/dist/core/memory-summary.d.ts +33 -0
- package/dist/core/memory-summary.js +71 -0
- package/dist/core/proof/evidence-collector.d.ts +1 -1
- package/dist/core/proof/route-adapter.d.ts +50 -0
- package/dist/core/proof/route-finalizer.d.ts +50 -0
- package/dist/core/proof/route-finalizer.js +29 -2
- package/dist/core/proof/selftest-proof-fixtures.d.ts +50 -0
- package/dist/core/routes.js +4 -4
- package/dist/core/triwiki-wrongness/wrongness-cli.d.ts +14 -2
- package/dist/core/triwiki-wrongness/wrongness-cli.js +14 -0
- package/dist/core/triwiki-wrongness/wrongness-proof-linker.d.ts +1 -1
- package/dist/core/triwiki-wrongness/wrongness-retrieval.d.ts +1 -1
- package/dist/core/triwiki-wrongness/wrongness-schema.d.ts +1 -1
- package/dist/core/triwiki-wrongness/wrongness-schema.js +27 -1
- package/dist/core/trust-kernel/trust-report.d.ts +100 -0
- package/dist/core/trust-kernel/trust-report.js +38 -4
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/wiki-image/image-voxel-ledger.d.ts +5 -0
- package/dist/core/wiki-image/image-voxel-ledger.js +28 -1
- package/dist/core/wiki-image/validation.js +26 -0
- package/dist/core/wiki-image/visual-anchor.d.ts +6 -1
- package/dist/core/wiki-image/visual-anchor.js +6 -1
- package/package.json +15 -2
- package/schemas/codex/completion-proof.schema.json +18 -0
- package/schemas/codex/computer-use-live-evidence.schema.json +17 -0
- package/schemas/codex/image-ux-issue-ledger.schema.json +71 -0
- package/schemas/codex/scout-result.schema.json +14 -0
- package/schemas/codex/ux-review-callout-extraction.schema.json +17 -0
- package/schemas/codex/wrongness-record.schema.json +17 -0
package/README.md
CHANGED
|
@@ -4,6 +4,10 @@ Fast legacy-free proof-first Codex trust layer with image-based Voxel TriWiki.
|
|
|
4
4
|
|
|
5
5
|
Sneakoscope Codex (`sks`) is a Codex CLI/App harness that makes repeatable Codex work auditable.
|
|
6
6
|
|
|
7
|
+
SKS **1.0.8** is the Codex 0.132 UX-Review Seal: Codex CLI `rust-v0.132.0` compatibility is explicit, `codex exec resume --output-schema` is the preferred structured-output path, and `$UX-Review this screenshot with gpt-image-2 callouts, then fix the issues` is a real visual trust loop from source screenshot fidelity to generated callout ingestion, issue ledger extraction, bounded safe fixes, recapture/re-review, Image Voxel relations, Wrongness, Completion Proof, and Trust Report gates.
|
|
8
|
+
|
|
9
|
+
SKS **1.0.7** is the Ultimate Final Completion seal for the Codex trust harness: Computer Use live evidence is an opt-in, local-only macOS evidence path with explicit `probe_only`, `live_capture_attempted`, `live_capture_success`, and `live_capture_blocked` modes; `codex-lb setup` reports durable persistence versus `process_only_ephemeral` honestly; and docs/release readiness checks block mock/probe/live overclaims.
|
|
10
|
+
|
|
7
11
|
SKS **1.0.6** is the final precision polish for the Codex trust harness: hook compatibility is classified as upstream schema plus an SKS zero-warning strict subset, `sks codex-lb setup` previews and applies the exact choices the user selected, and Computer Use has an optional live smoke surface for macOS capability/evidence status.
|
|
8
12
|
|
|
9
13
|
SKS **1.0.5** sealed the prior trust harness: hook outputs were validated against both vendored OpenAI Codex CLI `rust-v0.131.0` schemas and runtime semantic parser rules, codex-lb setup survived macOS user-session launches through env-file/Keychain/launchctl-aware repair surfaces, and Computer Use became the preferred macOS visual evidence capability when available.
|
|
@@ -20,8 +24,70 @@ Hybrid-free **`1.0.1`** already delivered the CLI entrypoint/router/registry/Tru
|
|
|
20
24
|
|
|
21
25
|
SKS does not try to clone every other harness. It focuses on one thing: making Codex work auditable, visual-evidence-bound, safety-gated, and reproducible through Completion Proof.
|
|
22
26
|
|
|
23
|
-

|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## 1.0.8 Codex 0.132 UX-Review Seal
|
|
31
|
+
|
|
32
|
+
1.0.8 makes UX-Review the representative SKS visual trust harness rather than a policy-only fixture. The CLI/App route now records source screenshot original-resolution metadata, requires real `gpt-image-2` generated callout images before verified UX claims, extracts visible callouts into `schemas/codex/image-ux-issue-ledger.schema.json`, plans bounded P0/P1-first fixes, and requires recapture/re-review before visual fix verification.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
sks codex compatibility --json
|
|
36
|
+
sks ux-review run --image ./screenshot.png --fix --json
|
|
37
|
+
sks ux-review callouts --image ./screenshot.png --json
|
|
38
|
+
sks ux-review extract-issues --generated-image ./generated-callouts.png --json
|
|
39
|
+
sks ux-review fix latest --json
|
|
40
|
+
sks ux-review recapture latest --json
|
|
41
|
+
sks ux-review recheck latest --json
|
|
42
|
+
sks ux-review status latest --json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Release checks now include:
|
|
46
|
+
|
|
47
|
+
- `npm run codex:0.132-compat`
|
|
48
|
+
- `npm run codex:output-schema-fixture`
|
|
49
|
+
- `npm run image-fidelity:check`
|
|
50
|
+
- `npm run ux-review:real-loop-fixture`
|
|
51
|
+
- `npm run ux-review:no-text-fallback`
|
|
52
|
+
- `npm run ux-review:image-voxel-relations`
|
|
53
|
+
- `npm run memory-summary:rebuild-check`
|
|
54
|
+
- `npm run loop-blocker:check`
|
|
55
|
+
|
|
56
|
+
`gpt-image-2` output is local-only by default. Text-only critique is blocked, mock fixtures stay `verified_partial` or lower, screenshot binaries are not automatically published to shared TriWiki, and unavailable Codex/App image-generation capability is recorded as a blocker instead of being faked.
|
|
57
|
+
|
|
58
|
+
## 1.0.7 Ultimate Final Completion
|
|
59
|
+
|
|
60
|
+
1.0.7 does not add a new route, skill, or competing harness. It closes the last trust gaps around live visual evidence, persistence truth, and release documentation.
|
|
61
|
+
|
|
62
|
+
Computer Use live evidence stays optional and explicit:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
sks computer-use smoke --json
|
|
66
|
+
sks computer-use smoke --real --capture-screenshot --json
|
|
67
|
+
sks computer-use smoke --real --require-real --json
|
|
68
|
+
npm run computer-use:live-evidence
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Default smoke is `probe_only` and never attempts screen capture. Real mode records `live_capture_attempted`, `live_capture_success`, or `live_capture_blocked`; if Codex App, macOS permission, or the official Computer Use capture surface is unavailable, SKS writes a structured blocker instead of fabricated evidence. Browser Use evidence and manual screenshots remain separate sources. Computer Use screenshots are local-only by default, carry SHA-256 metadata, and link to Image Voxel only when a mission-local anchor can be made.
|
|
72
|
+
|
|
73
|
+
codex-lb setup now reports the exact persistence truth:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
sks codex-lb setup --host lb.example.com --api-key-stdin --plan --json
|
|
77
|
+
sks codex-lb setup --host lb.example.com --api-key-stdin --yes --no-env-file --no-keychain --no-launchctl --shell-profile skip --json
|
|
78
|
+
npm run codex-lb:persistence-truth
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Durable modes are `durable_env_file`, `durable_keychain`, `durable_launchctl`, and `shell_profile`. If all durable modes are disabled, setup is classified as `process_only_ephemeral`, emits `next_shell_requires_setup_or_env`, and warns that Codex App GUI launches may not see credentials. Use `sks codex-lb setup --write-env-file --keychain --launchctl` to recover durable persistence.
|
|
82
|
+
|
|
83
|
+
Documentation truthfulness is now a release invariant:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm run docs:truthfulness
|
|
87
|
+
npm run release:readiness
|
|
88
|
+
```
|
|
24
89
|
|
|
90
|
+
The hook compatibility surface remains the upstream schema plus the SKS zero-warning strict subset; SKS does not claim to mirror every upstream runtime parser rule or guarantee universal Computer Use availability.
|
|
25
91
|
|
|
26
92
|
## 1.0.6 Final Precision Polish
|
|
27
93
|
|
|
@@ -4,7 +4,7 @@ use std::io::{self, Read, Seek, SeekFrom};
|
|
|
4
4
|
fn main() {
|
|
5
5
|
let mut args = std::env::args().skip(1);
|
|
6
6
|
match args.next().as_deref() {
|
|
7
|
-
Some("--version") => println!("sks-rs 1.0.
|
|
7
|
+
Some("--version") => println!("sks-rs 1.0.8"),
|
|
8
8
|
Some("compact-info") => {
|
|
9
9
|
let mut input = String::new();
|
|
10
10
|
let _ = io::stdin().read_to_string(&mut input);
|
package/dist/bin/sks.js
CHANGED
package/dist/build-manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "sks.dist-build.v2",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"typescript": true,
|
|
5
5
|
"mjs_runtime_files": 0,
|
|
6
6
|
"files": [
|
|
@@ -184,6 +184,8 @@
|
|
|
184
184
|
"core/codex-adapter.js",
|
|
185
185
|
"core/codex-app.d.ts",
|
|
186
186
|
"core/codex-app.js",
|
|
187
|
+
"core/codex-compat/codex-0-132.d.ts",
|
|
188
|
+
"core/codex-compat/codex-0-132.js",
|
|
187
189
|
"core/codex-compat/codex-compat-report.d.ts",
|
|
188
190
|
"core/codex-compat/codex-compat-report.js",
|
|
189
191
|
"core/codex-compat/codex-config-policy.d.ts",
|
|
@@ -206,6 +208,8 @@
|
|
|
206
208
|
"core/codex-compat/codex-version-policy.js",
|
|
207
209
|
"core/codex-compat/codex-version.d.ts",
|
|
208
210
|
"core/codex-compat/codex-version.js",
|
|
211
|
+
"core/codex-exec-output-schema.d.ts",
|
|
212
|
+
"core/codex-exec-output-schema.js",
|
|
209
213
|
"core/codex-lb-circuit.d.ts",
|
|
210
214
|
"core/codex-lb-circuit.js",
|
|
211
215
|
"core/codex-lb/codex-lb-env.d.ts",
|
|
@@ -286,6 +290,8 @@
|
|
|
286
290
|
"core/commands/wiki-command.js",
|
|
287
291
|
"core/commands/wrongness-command.d.ts",
|
|
288
292
|
"core/commands/wrongness-command.js",
|
|
293
|
+
"core/computer-use-live-evidence.d.ts",
|
|
294
|
+
"core/computer-use-live-evidence.js",
|
|
289
295
|
"core/computer-use-status.d.ts",
|
|
290
296
|
"core/computer-use-status.js",
|
|
291
297
|
"core/context7-client.d.ts",
|
|
@@ -368,14 +374,28 @@
|
|
|
368
374
|
"core/hproof.js",
|
|
369
375
|
"core/image-ux-review.d.ts",
|
|
370
376
|
"core/image-ux-review.js",
|
|
377
|
+
"core/image-ux-review/callout-extraction.d.ts",
|
|
378
|
+
"core/image-ux-review/callout-extraction.js",
|
|
379
|
+
"core/image-ux-review/fix-loop.d.ts",
|
|
380
|
+
"core/image-ux-review/fix-loop.js",
|
|
381
|
+
"core/image-ux-review/fix-task-planner.d.ts",
|
|
382
|
+
"core/image-ux-review/fix-task-planner.js",
|
|
383
|
+
"core/image-ux-review/imagegen-adapter.d.ts",
|
|
384
|
+
"core/image-ux-review/imagegen-adapter.js",
|
|
385
|
+
"core/image-ux-review/recapture.d.ts",
|
|
386
|
+
"core/image-ux-review/recapture.js",
|
|
371
387
|
"core/init.d.ts",
|
|
372
388
|
"core/init.js",
|
|
373
389
|
"core/language-preference.d.ts",
|
|
374
390
|
"core/language-preference.js",
|
|
391
|
+
"core/loop-blocker.d.ts",
|
|
392
|
+
"core/loop-blocker.js",
|
|
375
393
|
"core/managed-paths.d.ts",
|
|
376
394
|
"core/managed-paths.js",
|
|
377
395
|
"core/memory-governor.d.ts",
|
|
378
396
|
"core/memory-governor.js",
|
|
397
|
+
"core/memory-summary.d.ts",
|
|
398
|
+
"core/memory-summary.js",
|
|
379
399
|
"core/mission.d.ts",
|
|
380
400
|
"core/mission.js",
|
|
381
401
|
"core/mistake-memory.d.ts",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CodexLbPersistenceSummary } from '../core/codex-lb/codex-lb-setup.js';
|
|
1
2
|
type CodexLbStatusSnapshot = Awaited<ReturnType<typeof codexLbStatus>>;
|
|
2
3
|
/** Install-time shim reconciliation; fields vary by `status`. */
|
|
3
4
|
export type SksPostinstallShimResult = {
|
|
@@ -59,6 +60,7 @@ export type ConfigureCodexLbResult = {
|
|
|
59
60
|
plan?: Record<string, unknown>;
|
|
60
61
|
applied_actions?: Array<Record<string, unknown>>;
|
|
61
62
|
drift?: string[];
|
|
63
|
+
persistence?: CodexLbPersistenceSummary;
|
|
62
64
|
config_path?: string;
|
|
63
65
|
env_path?: string;
|
|
64
66
|
metadata_path?: string;
|
|
@@ -12,7 +12,7 @@ import { codexLaunchCommand, platformTmuxInstallHint, tmuxReadiness, tmuxReadine
|
|
|
12
12
|
import { reconcileCodexAppUpgradeProcesses } from '../core/codex-app.js';
|
|
13
13
|
import { recordCodexLbHealthEvent } from '../core/codex-lb-circuit.js';
|
|
14
14
|
import { loadCodexLbEnv, writeCodexLbKeychain, codexLbMetadataPath } from '../core/codex-lb/codex-lb-env.js';
|
|
15
|
-
import { buildCodexLbSetupPlan, installCodexLbShellProfileSnippet } from '../core/codex-lb/codex-lb-setup.js';
|
|
15
|
+
import { buildCodexLbSetupPlan, codexLbPersistenceSummary, installCodexLbShellProfileSnippet, selectedCodexLbPersistenceModes } from '../core/codex-lb/codex-lb-setup.js';
|
|
16
16
|
const DEFAULT_CODEX_APP_PLUGINS = [
|
|
17
17
|
['browser', 'openai-bundled'],
|
|
18
18
|
['chrome', 'openai-bundled'],
|
|
@@ -324,6 +324,7 @@ export async function configureCodexLb(opts = {}) {
|
|
|
324
324
|
run_health_check: opts.runHealth === true,
|
|
325
325
|
allow_insecure_localhost: opts.allowInsecureHttp === true || opts.allowInsecureLocalhost === true
|
|
326
326
|
};
|
|
327
|
+
const selectedPersistenceModes = selectedCodexLbPersistenceModes(setupAnswers);
|
|
327
328
|
const plan = buildCodexLbSetupPlan(setupAnswers, {
|
|
328
329
|
home,
|
|
329
330
|
configPath,
|
|
@@ -341,6 +342,7 @@ export async function configureCodexLb(opts = {}) {
|
|
|
341
342
|
const insecureLocalWarning = /^http:\/\//i.test(baseUrl) && !/^http:\/\/(?:localhost|127\.0\.0\.1|\[::1\])(?::|\/|$)/i.test(baseUrl) && !opts.allowInsecureHttp
|
|
342
343
|
? ['codex-lb base URL uses http outside localhost; prefer https or pass an explicit allow flag in the calling surface.']
|
|
343
344
|
: [];
|
|
345
|
+
const beforeState = await captureCodexLbSetupWriteState({ home, configPath, envPath, shellProfile });
|
|
344
346
|
const appliedActions = [];
|
|
345
347
|
await ensureDir(path.dirname(configPath));
|
|
346
348
|
const current = await readText(configPath, '');
|
|
@@ -381,6 +383,7 @@ export async function configureCodexLb(opts = {}) {
|
|
|
381
383
|
const authReconcile = await reconcileCodexLbAuthConflict({ ...opts, home, status: codexLb }).catch((err) => ({ status: 'failed', reason: 'exception', error: err.message }));
|
|
382
384
|
const finalCodexLb = await codexLbStatus({ ...opts, home, configPath, envPath });
|
|
383
385
|
const ok = Boolean(codexEnvironment.ok && codexLogin.ok);
|
|
386
|
+
const afterState = await captureCodexLbSetupWriteState({ home, configPath, envPath, shellProfile });
|
|
384
387
|
const drift = detectCodexLbSetupDrift({
|
|
385
388
|
useDefaultProvider,
|
|
386
389
|
writeEnvFile,
|
|
@@ -391,21 +394,41 @@ export async function configureCodexLb(opts = {}) {
|
|
|
391
394
|
envFile: finalCodexLb.env_file,
|
|
392
395
|
keychain,
|
|
393
396
|
codexEnvironment,
|
|
394
|
-
shellProfileResult
|
|
397
|
+
shellProfileResult,
|
|
398
|
+
beforeState,
|
|
399
|
+
afterState
|
|
395
400
|
});
|
|
401
|
+
const appliedPersistenceModes = appliedCodexLbPersistenceModes({
|
|
402
|
+
writeEnvFile,
|
|
403
|
+
storeKeychain,
|
|
404
|
+
syncLaunchctl,
|
|
405
|
+
shellProfile,
|
|
406
|
+
envFile: finalCodexLb.env_file,
|
|
407
|
+
keychain,
|
|
408
|
+
codexEnvironment,
|
|
409
|
+
shellProfileResult,
|
|
410
|
+
apiKeySource: finalCodexLb.env_loader?.api_key?.source || null
|
|
411
|
+
});
|
|
412
|
+
const persistence = codexLbPersistenceSummary({
|
|
413
|
+
selectedModes: selectedPersistenceModes,
|
|
414
|
+
appliedModes: appliedPersistenceModes,
|
|
415
|
+
processOnly: appliedPersistenceModes.includes('process_only_ephemeral')
|
|
416
|
+
});
|
|
417
|
+
const warnings = [...insecureLocalWarning, ...persistence.warnings];
|
|
396
418
|
return {
|
|
397
419
|
ok: ok && drift.length === 0,
|
|
398
420
|
status: ok && drift.length === 0 ? 'configured' : drift.length ? 'setup_choice_drift' : (codexEnvironment.status || codexLogin.status),
|
|
399
421
|
plan: plan,
|
|
400
422
|
applied_actions: appliedActions,
|
|
401
423
|
drift,
|
|
424
|
+
persistence,
|
|
402
425
|
config_path: configPath,
|
|
403
426
|
env_path: envPath,
|
|
404
427
|
metadata_path: metadataPath,
|
|
405
428
|
base_url: baseUrl,
|
|
406
429
|
env_key: 'CODEX_LB_API_KEY',
|
|
407
430
|
keychain,
|
|
408
|
-
warnings
|
|
431
|
+
warnings,
|
|
409
432
|
auth_reconcile: authReconcile,
|
|
410
433
|
codex_lb: finalCodexLb,
|
|
411
434
|
codex_environment: codexEnvironment,
|
|
@@ -1339,7 +1362,9 @@ function detectCodexLbSetupDrift(state = {}) {
|
|
|
1339
1362
|
drift.push('default_provider_selected_despite_no_default_provider');
|
|
1340
1363
|
if (state.writeEnvFile && state.envFile !== true)
|
|
1341
1364
|
drift.push('env_file_not_written');
|
|
1342
|
-
if (!state.writeEnvFile && state.
|
|
1365
|
+
if (!state.writeEnvFile && state.beforeState && state.afterState && state.beforeState.envHash !== state.afterState.envHash)
|
|
1366
|
+
drift.push('env_file_changed_despite_no_env_file');
|
|
1367
|
+
if (!state.writeEnvFile && !state.beforeState && state.envFile === true)
|
|
1343
1368
|
drift.push('env_file_written_despite_no_env_file');
|
|
1344
1369
|
if (!state.storeKeychain && state.keychain?.status && state.keychain.status !== 'skipped')
|
|
1345
1370
|
drift.push('keychain_touched_despite_no_keychain');
|
|
@@ -1347,8 +1372,54 @@ function detectCodexLbSetupDrift(state = {}) {
|
|
|
1347
1372
|
drift.push('launchctl_synced_despite_no_launchctl');
|
|
1348
1373
|
if (state.shellProfile === 'skip' && state.shellProfileResult?.status === 'installed')
|
|
1349
1374
|
drift.push('shell_profile_written_despite_skip');
|
|
1375
|
+
if (state.shellProfile === 'skip' && state.beforeState && state.afterState && state.beforeState.profileHash !== state.afterState.profileHash)
|
|
1376
|
+
drift.push('shell_profile_changed_despite_skip');
|
|
1350
1377
|
return drift;
|
|
1351
1378
|
}
|
|
1379
|
+
async function captureCodexLbSetupWriteState({ home, configPath, envPath, shellProfile } = {}) {
|
|
1380
|
+
const profileFiles = profileFilesForDrift(home, shellProfile);
|
|
1381
|
+
return {
|
|
1382
|
+
configHash: await fileHashOrMissing(configPath),
|
|
1383
|
+
envHash: await fileHashOrMissing(envPath),
|
|
1384
|
+
profileHash: (await Promise.all(profileFiles.map((file) => fileHashOrMissing(file)))).join('|')
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
async function fileHashOrMissing(file) {
|
|
1388
|
+
const text = await readText(file, null).catch(() => null);
|
|
1389
|
+
return text === null ? 'missing' : await sha256Text(String(text));
|
|
1390
|
+
}
|
|
1391
|
+
function profileFilesForDrift(home, shellProfile) {
|
|
1392
|
+
const targets = {
|
|
1393
|
+
zsh: path.join(home, '.zshrc'),
|
|
1394
|
+
bash: path.join(home, '.bashrc'),
|
|
1395
|
+
fish: path.join(home, '.config', 'fish', 'config.fish')
|
|
1396
|
+
};
|
|
1397
|
+
if (shellProfile === 'zsh')
|
|
1398
|
+
return [targets.zsh];
|
|
1399
|
+
if (shellProfile === 'bash')
|
|
1400
|
+
return [targets.bash];
|
|
1401
|
+
if (shellProfile === 'fish')
|
|
1402
|
+
return [targets.fish];
|
|
1403
|
+
if (shellProfile === 'all')
|
|
1404
|
+
return [targets.zsh, targets.bash, targets.fish];
|
|
1405
|
+
return [targets.zsh, targets.bash, targets.fish];
|
|
1406
|
+
}
|
|
1407
|
+
function appliedCodexLbPersistenceModes(state = {}) {
|
|
1408
|
+
const modes = [];
|
|
1409
|
+
if (state.writeEnvFile && state.envFile === true)
|
|
1410
|
+
modes.push('durable_env_file');
|
|
1411
|
+
if (state.storeKeychain && state.keychain?.ok === true)
|
|
1412
|
+
modes.push('durable_keychain');
|
|
1413
|
+
if (state.syncLaunchctl && state.codexEnvironment?.launch_environment?.status === 'synced')
|
|
1414
|
+
modes.push('durable_launchctl');
|
|
1415
|
+
if (state.shellProfile !== 'skip' && state.shellProfileResult?.status === 'installed')
|
|
1416
|
+
modes.push('shell_profile');
|
|
1417
|
+
if (!modes.length && state.apiKeySource === 'process.env')
|
|
1418
|
+
modes.push('process_only_ephemeral');
|
|
1419
|
+
if (!modes.length)
|
|
1420
|
+
modes.push('none');
|
|
1421
|
+
return modes;
|
|
1422
|
+
}
|
|
1352
1423
|
export async function ensureGlobalCodexFastModeDuringInstall(opts = {}) {
|
|
1353
1424
|
if (process.env.SKS_SKIP_CODEX_FAST_MODE_REPAIR === '1')
|
|
1354
1425
|
return { status: 'skipped', reason: 'SKS_SKIP_CODEX_FAST_MODE_REPAIR=1' };
|
|
@@ -6,7 +6,7 @@ import { flag, readOption } from '../cli/args.js';
|
|
|
6
6
|
import { printJson } from '../cli/output.js';
|
|
7
7
|
import { codexLbMetrics, readCodexLbCircuit, recordCodexLbHealthEvent, resetCodexLbCircuit, codexLbProofEvidence } from '../core/codex-lb-circuit.js';
|
|
8
8
|
import { checkCodexLbResponseChain, codexLbStatus, configureCodexLb, formatCodexLbStatusText, releaseCodexLbAuthHold, repairCodexLbAuth, unselectCodexLbProvider } from '../cli/install-helpers.js';
|
|
9
|
-
import { buildCodexLbSetupPlan, renderCodexLbSetupPlan } from '../core/codex-lb/codex-lb-setup.js';
|
|
9
|
+
import { buildCodexLbSetupPlan, codexLbPersistenceSummary, renderCodexLbSetupPlan } from '../core/codex-lb/codex-lb-setup.js';
|
|
10
10
|
export async function run(command, args = []) {
|
|
11
11
|
const root = await projectRoot();
|
|
12
12
|
const action = args[0] || 'status';
|
|
@@ -111,7 +111,7 @@ export async function run(command, args = []) {
|
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
113
|
if (flag(args, '--plan')) {
|
|
114
|
-
const result = { schema: 'sks.codex-lb-setup-plan-result.v1', ok: plan.blockers.length === 0, plan, writes: false };
|
|
114
|
+
const result = { schema: 'sks.codex-lb-setup-plan-result.v1', ok: plan.blockers.length === 0, plan, writes: false, expected_actions: plan.expected_actions, persistence: plan.persistence };
|
|
115
115
|
if (flag(args, '--json'))
|
|
116
116
|
return printJson(result);
|
|
117
117
|
process.stdout.write(renderCodexLbSetupPlan(plan));
|
|
@@ -119,6 +119,7 @@ export async function run(command, args = []) {
|
|
|
119
119
|
process.exitCode = 1;
|
|
120
120
|
return;
|
|
121
121
|
}
|
|
122
|
+
const processOnly = plan.persistence.effective_mode === 'process_only_ephemeral';
|
|
122
123
|
if (options.interactive && !options.yes) {
|
|
123
124
|
process.stdout.write(renderCodexLbSetupPlan(plan));
|
|
124
125
|
const confirm = (await ask('Apply this codex-lb setup plan? [y/N] ')).trim();
|
|
@@ -130,6 +131,39 @@ export async function run(command, args = []) {
|
|
|
130
131
|
process.exitCode = 1;
|
|
131
132
|
return;
|
|
132
133
|
}
|
|
134
|
+
if (processOnly) {
|
|
135
|
+
const confirmProcessOnly = (await ask('This setup keeps credentials only in the current process. Type process-only to continue: ')).trim();
|
|
136
|
+
if (confirmProcessOnly !== 'process-only') {
|
|
137
|
+
const result = { schema: 'sks.codex-lb-setup.v1', ok: false, status: 'process_only_cancelled', plan, applied_actions: [], persistence: plan.persistence };
|
|
138
|
+
if (flag(args, '--json')) {
|
|
139
|
+
printJson(result);
|
|
140
|
+
process.exitCode = 1;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
console.log('codex-lb setup cancelled: process-only ephemeral setup was not confirmed.');
|
|
144
|
+
process.exitCode = 1;
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else if (processOnly && !options.yes) {
|
|
150
|
+
const result = {
|
|
151
|
+
schema: 'sks.codex-lb-setup.v1',
|
|
152
|
+
ok: false,
|
|
153
|
+
status: 'process_only_requires_yes',
|
|
154
|
+
plan,
|
|
155
|
+
applied_actions: [],
|
|
156
|
+
persistence: plan.persistence,
|
|
157
|
+
guidance: ['Pass --yes to acknowledge process_only_ephemeral setup, or enable --write-env-file, --keychain, --launchctl, or --shell-profile.']
|
|
158
|
+
};
|
|
159
|
+
if (flag(args, '--json')) {
|
|
160
|
+
printJson(result);
|
|
161
|
+
process.exitCode = 1;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
console.error('codex-lb setup would be process-only ephemeral. Pass --yes to acknowledge, or enable a durable persistence mode.');
|
|
165
|
+
process.exitCode = 1;
|
|
166
|
+
return;
|
|
133
167
|
}
|
|
134
168
|
const result = await configureCodexLb({
|
|
135
169
|
host: options.host,
|
|
@@ -152,6 +186,8 @@ export async function run(command, args = []) {
|
|
|
152
186
|
if (flag(args, '--json'))
|
|
153
187
|
return printJson(shaped);
|
|
154
188
|
console.log(`codex-lb configured: ${result.base_url || result.status}`);
|
|
189
|
+
if (shaped.persistence?.warning)
|
|
190
|
+
console.log(`warning: ${shaped.persistence.warning}`);
|
|
155
191
|
if (!result.ok)
|
|
156
192
|
process.exitCode = 1;
|
|
157
193
|
return;
|
|
@@ -190,6 +226,18 @@ export async function run(command, args = []) {
|
|
|
190
226
|
process.exitCode = 1;
|
|
191
227
|
}
|
|
192
228
|
function shapeCodexLbStatus(status = {}) {
|
|
229
|
+
const mode = status.env_loader?.api_key?.source === 'env-file'
|
|
230
|
+
? 'durable_env_file'
|
|
231
|
+
: status.env_loader?.api_key?.source === 'keychain'
|
|
232
|
+
? 'durable_keychain'
|
|
233
|
+
: status.env_loader?.api_key?.source === 'process.env'
|
|
234
|
+
? 'process_only_ephemeral'
|
|
235
|
+
: 'none';
|
|
236
|
+
const persistence = codexLbPersistenceSummary({
|
|
237
|
+
selectedModes: mode === 'none' ? [] : [mode],
|
|
238
|
+
appliedModes: mode === 'none' ? ['none'] : [mode],
|
|
239
|
+
processOnly: mode === 'process_only_ephemeral'
|
|
240
|
+
});
|
|
193
241
|
return {
|
|
194
242
|
schema: 'sks.codex-lb-status.v1',
|
|
195
243
|
...status,
|
|
@@ -201,6 +249,7 @@ function shapeCodexLbStatus(status = {}) {
|
|
|
201
249
|
source: status.env_loader?.api_key?.source || null,
|
|
202
250
|
redacted: true
|
|
203
251
|
},
|
|
252
|
+
persistence,
|
|
204
253
|
env_loader: status.env_loader || null,
|
|
205
254
|
env_auto_load: Boolean(status.env_file && status.env_key_configured),
|
|
206
255
|
guidance: status.ok ? [] : [
|