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.
Files changed (80) hide show
  1. package/README.md +67 -1
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/bin/sks.js +1 -1
  6. package/dist/build-manifest.json +21 -1
  7. package/dist/cli/install-helpers.d.ts +2 -0
  8. package/dist/cli/install-helpers.js +75 -4
  9. package/dist/commands/codex-lb.js +51 -2
  10. package/dist/commands/image-ux-review.d.ts +320 -1
  11. package/dist/commands/wiki.d.ts +7 -1
  12. package/dist/core/codex-compat/codex-0-132.d.ts +46 -0
  13. package/dist/core/codex-compat/codex-0-132.js +105 -0
  14. package/dist/core/codex-compat/codex-compat-report.d.ts +46 -0
  15. package/dist/core/codex-compat/codex-compat-report.js +19 -3
  16. package/dist/core/codex-compat/codex-schema-snapshot.js +7 -7
  17. package/dist/core/codex-compat/codex-version-policy.d.ts +4 -2
  18. package/dist/core/codex-compat/codex-version-policy.js +5 -3
  19. package/dist/core/codex-exec-output-schema.d.ts +45 -0
  20. package/dist/core/codex-exec-output-schema.js +131 -0
  21. package/dist/core/codex-lb/codex-lb-setup.d.ts +19 -0
  22. package/dist/core/codex-lb/codex-lb-setup.js +58 -0
  23. package/dist/core/commands/computer-use-command.js +19 -3
  24. package/dist/core/commands/image-ux-review-command.d.ts +320 -1
  25. package/dist/core/commands/image-ux-review-command.js +281 -35
  26. package/dist/core/commands/wiki-command.d.ts +8 -2
  27. package/dist/core/commands/wiki-command.js +11 -2
  28. package/dist/core/computer-use-live-evidence.d.ts +109 -0
  29. package/dist/core/computer-use-live-evidence.js +276 -0
  30. package/dist/core/computer-use-status.d.ts +8 -1
  31. package/dist/core/computer-use-status.js +43 -24
  32. package/dist/core/evidence/evidence-router.js +17 -1
  33. package/dist/core/fsx.d.ts +1 -1
  34. package/dist/core/fsx.js +1 -1
  35. package/dist/core/goal-workflow.d.ts +6 -0
  36. package/dist/core/goal-workflow.js +6 -0
  37. package/dist/core/image-ux-review/callout-extraction.d.ts +47 -0
  38. package/dist/core/image-ux-review/callout-extraction.js +106 -0
  39. package/dist/core/image-ux-review/fix-loop.d.ts +31 -0
  40. package/dist/core/image-ux-review/fix-loop.js +35 -0
  41. package/dist/core/image-ux-review/fix-task-planner.d.ts +8 -0
  42. package/dist/core/image-ux-review/fix-task-planner.js +55 -0
  43. package/dist/core/image-ux-review/imagegen-adapter.d.ts +52 -0
  44. package/dist/core/image-ux-review/imagegen-adapter.js +69 -0
  45. package/dist/core/image-ux-review/recapture.d.ts +15 -0
  46. package/dist/core/image-ux-review/recapture.js +25 -0
  47. package/dist/core/image-ux-review.d.ts +270 -52
  48. package/dist/core/image-ux-review.js +318 -101
  49. package/dist/core/loop-blocker.d.ts +41 -0
  50. package/dist/core/loop-blocker.js +42 -0
  51. package/dist/core/memory-summary.d.ts +33 -0
  52. package/dist/core/memory-summary.js +71 -0
  53. package/dist/core/proof/evidence-collector.d.ts +1 -1
  54. package/dist/core/proof/route-adapter.d.ts +50 -0
  55. package/dist/core/proof/route-finalizer.d.ts +50 -0
  56. package/dist/core/proof/route-finalizer.js +29 -2
  57. package/dist/core/proof/selftest-proof-fixtures.d.ts +50 -0
  58. package/dist/core/routes.js +4 -4
  59. package/dist/core/triwiki-wrongness/wrongness-cli.d.ts +14 -2
  60. package/dist/core/triwiki-wrongness/wrongness-cli.js +14 -0
  61. package/dist/core/triwiki-wrongness/wrongness-proof-linker.d.ts +1 -1
  62. package/dist/core/triwiki-wrongness/wrongness-retrieval.d.ts +1 -1
  63. package/dist/core/triwiki-wrongness/wrongness-schema.d.ts +1 -1
  64. package/dist/core/triwiki-wrongness/wrongness-schema.js +27 -1
  65. package/dist/core/trust-kernel/trust-report.d.ts +100 -0
  66. package/dist/core/trust-kernel/trust-report.js +38 -4
  67. package/dist/core/version.d.ts +1 -1
  68. package/dist/core/version.js +1 -1
  69. package/dist/core/wiki-image/image-voxel-ledger.d.ts +5 -0
  70. package/dist/core/wiki-image/image-voxel-ledger.js +28 -1
  71. package/dist/core/wiki-image/validation.js +26 -0
  72. package/dist/core/wiki-image/visual-anchor.d.ts +6 -1
  73. package/dist/core/wiki-image/visual-anchor.js +6 -1
  74. package/package.json +15 -2
  75. package/schemas/codex/completion-proof.schema.json +18 -0
  76. package/schemas/codex/computer-use-live-evidence.schema.json +17 -0
  77. package/schemas/codex/image-ux-issue-ledger.schema.json +71 -0
  78. package/schemas/codex/scout-result.schema.json +14 -0
  79. package/schemas/codex/ux-review-callout-extraction.schema.json +17 -0
  80. 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
- ![Sneakoscope Codex architecture and pipeline](https://raw.githubusercontent.com/mandarange/Sneakoscope-Codex/dev/docs/assets/sneakoscope-architecture-pipeline.jpg)
27
+ ![Sneakoscope Codex Trust Layer](docs/assets/sneakoscope-architecture-pipeline.jpg)
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
 
@@ -76,7 +76,7 @@ dependencies = [
76
76
 
77
77
  [[package]]
78
78
  name = "sks-core"
79
- version = "1.0.6"
79
+ version = "1.0.8"
80
80
  dependencies = [
81
81
  "serde_json",
82
82
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "1.0.6"
3
+ version = "1.0.8"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -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.6"),
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
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const FAST_PACKAGE_VERSION = '1.0.6';
2
+ const FAST_PACKAGE_VERSION = '1.0.8';
3
3
  const args = process.argv.slice(2);
4
4
  try {
5
5
  if (args[0] === '--version' || args[0] === '-v' || args[0] === 'version') {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": "sks.dist-build.v2",
3
- "version": "1.0.6",
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: insecureLocalWarning,
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.envFile === true)
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 ? [] : [