sneakoscope 1.0.6 → 1.0.7
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 +37 -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 +3 -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/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/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 +10 -0
- package/dist/core/fsx.d.ts +1 -1
- package/dist/core/fsx.js +1 -1
- package/dist/core/proof/route-finalizer.js +27 -2
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ 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.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.
|
|
8
|
+
|
|
7
9
|
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
10
|
|
|
9
11
|
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 +22,42 @@ Hybrid-free **`1.0.1`** already delivered the CLI entrypoint/router/registry/Tru
|
|
|
20
22
|
|
|
21
23
|
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
24
|
|
|
23
|
-

|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## 1.0.7 Ultimate Final Completion
|
|
29
|
+
|
|
30
|
+
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.
|
|
31
|
+
|
|
32
|
+
Computer Use live evidence stays optional and explicit:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
sks computer-use smoke --json
|
|
36
|
+
sks computer-use smoke --real --capture-screenshot --json
|
|
37
|
+
sks computer-use smoke --real --require-real --json
|
|
38
|
+
npm run computer-use:live-evidence
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
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.
|
|
42
|
+
|
|
43
|
+
codex-lb setup now reports the exact persistence truth:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
sks codex-lb setup --host lb.example.com --api-key-stdin --plan --json
|
|
47
|
+
sks codex-lb setup --host lb.example.com --api-key-stdin --yes --no-env-file --no-keychain --no-launchctl --shell-profile skip --json
|
|
48
|
+
npm run codex-lb:persistence-truth
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
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.
|
|
52
|
+
|
|
53
|
+
Documentation truthfulness is now a release invariant:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm run docs:truthfulness
|
|
57
|
+
npm run release:readiness
|
|
58
|
+
```
|
|
24
59
|
|
|
60
|
+
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
61
|
|
|
26
62
|
## 1.0.6 Final Precision Polish
|
|
27
63
|
|
|
@@ -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.7"),
|
|
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.7",
|
|
4
4
|
"typescript": true,
|
|
5
5
|
"mjs_runtime_files": 0,
|
|
6
6
|
"files": [
|
|
@@ -286,6 +286,8 @@
|
|
|
286
286
|
"core/commands/wiki-command.js",
|
|
287
287
|
"core/commands/wrongness-command.d.ts",
|
|
288
288
|
"core/commands/wrongness-command.js",
|
|
289
|
+
"core/computer-use-live-evidence.d.ts",
|
|
290
|
+
"core/computer-use-live-evidence.js",
|
|
289
291
|
"core/computer-use-status.d.ts",
|
|
290
292
|
"core/computer-use-status.js",
|
|
291
293
|
"core/context7-client.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 ? [] : [
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export type CodexLbApiKeySource = 'hidden_prompt' | 'stdin' | 'cli_option' | 'keychain_existing';
|
|
2
2
|
export type CodexLbShellProfileChoice = 'zsh' | 'bash' | 'fish' | 'all' | 'skip';
|
|
3
|
+
export type CodexLbPersistenceMode = 'durable_env_file' | 'durable_keychain' | 'durable_launchctl' | 'shell_profile' | 'process_only_ephemeral' | 'none';
|
|
3
4
|
export type CodexLbSetupActionType = 'write_config_provider' | 'select_default_provider' | 'write_env_file' | 'store_keychain' | 'sync_launchctl' | 'install_shell_profile_snippet' | 'run_health_check' | 'write_metadata';
|
|
4
5
|
export interface CodexLbSetupAnswers {
|
|
5
6
|
host_or_base_url: string;
|
|
@@ -22,9 +23,21 @@ export interface CodexLbSetupPlan {
|
|
|
22
23
|
schema: 'sks.codex-lb-setup-plan.v1';
|
|
23
24
|
base_url: string;
|
|
24
25
|
actions: CodexLbSetupAction[];
|
|
26
|
+
expected_actions: CodexLbSetupAction[];
|
|
27
|
+
selected_persistence_modes: CodexLbPersistenceMode[];
|
|
28
|
+
persistence: CodexLbPersistenceSummary;
|
|
25
29
|
redactions: string[];
|
|
30
|
+
warnings: string[];
|
|
26
31
|
blockers: string[];
|
|
27
32
|
}
|
|
33
|
+
export interface CodexLbPersistenceSummary {
|
|
34
|
+
selected_modes: CodexLbPersistenceMode[];
|
|
35
|
+
applied_modes: CodexLbPersistenceMode[];
|
|
36
|
+
effective_mode: CodexLbPersistenceMode;
|
|
37
|
+
durable: boolean;
|
|
38
|
+
warning: string | null;
|
|
39
|
+
warnings: string[];
|
|
40
|
+
}
|
|
28
41
|
export declare function buildCodexLbSetupPlan(answers: CodexLbSetupAnswers, opts?: {
|
|
29
42
|
home?: string;
|
|
30
43
|
configPath?: string;
|
|
@@ -43,4 +56,10 @@ export declare function installCodexLbShellProfileSnippet(opts: {
|
|
|
43
56
|
skipped?: boolean;
|
|
44
57
|
reason?: string;
|
|
45
58
|
}>;
|
|
59
|
+
export declare function selectedCodexLbPersistenceModes(answers: Pick<CodexLbSetupAnswers, 'write_env_file' | 'store_keychain' | 'sync_launchctl' | 'install_shell_profile'>): CodexLbPersistenceMode[];
|
|
60
|
+
export declare function codexLbPersistenceSummary({ selectedModes, appliedModes, processOnly }?: {
|
|
61
|
+
selectedModes?: CodexLbPersistenceMode[];
|
|
62
|
+
appliedModes?: CodexLbPersistenceMode[];
|
|
63
|
+
processOnly?: boolean;
|
|
64
|
+
}): CodexLbPersistenceSummary;
|
|
46
65
|
//# sourceMappingURL=codex-lb-setup.d.ts.map
|
|
@@ -35,11 +35,21 @@ export function buildCodexLbSetupPlan(answers, opts = {}) {
|
|
|
35
35
|
actions.push({ type: 'run_health_check', target: 'codex-lb response chain', effect: 'run codex-lb health check after apply' });
|
|
36
36
|
}
|
|
37
37
|
actions.push({ type: 'write_metadata', target: metadataPath, effect: 'write redacted setup metadata and key fingerprint with chmod 0600' });
|
|
38
|
+
const selectedModes = selectedCodexLbPersistenceModes(answers);
|
|
39
|
+
const persistence = codexLbPersistenceSummary({
|
|
40
|
+
selectedModes,
|
|
41
|
+
appliedModes: selectedModes.length ? [] : ['process_only_ephemeral'],
|
|
42
|
+
processOnly: selectedModes.length === 0
|
|
43
|
+
});
|
|
38
44
|
return {
|
|
39
45
|
schema: 'sks.codex-lb-setup-plan.v1',
|
|
40
46
|
base_url: baseUrl,
|
|
41
47
|
actions,
|
|
48
|
+
expected_actions: actions,
|
|
49
|
+
selected_persistence_modes: selectedModes.length ? selectedModes : ['process_only_ephemeral'],
|
|
50
|
+
persistence,
|
|
42
51
|
redactions: ['CODEX_LB_API_KEY', 'api_key', 'sk-*', 'sk-clb-*'],
|
|
52
|
+
warnings: persistence.warnings,
|
|
43
53
|
blockers
|
|
44
54
|
};
|
|
45
55
|
}
|
|
@@ -51,6 +61,8 @@ export function renderCodexLbSetupPlan(plan) {
|
|
|
51
61
|
];
|
|
52
62
|
for (const action of plan.actions)
|
|
53
63
|
lines.push(`- ${action.type}: ${action.target} (${action.effect})`);
|
|
64
|
+
if (plan.persistence.warning)
|
|
65
|
+
lines.push(`warning: ${plan.persistence.warning}`);
|
|
54
66
|
if (plan.blockers.length) {
|
|
55
67
|
lines.push('blockers:');
|
|
56
68
|
for (const blocker of plan.blockers)
|
|
@@ -74,6 +86,52 @@ export async function installCodexLbShellProfileSnippet(opts) {
|
|
|
74
86
|
}
|
|
75
87
|
return { ok: true, status: 'installed', files };
|
|
76
88
|
}
|
|
89
|
+
export function selectedCodexLbPersistenceModes(answers) {
|
|
90
|
+
const modes = [];
|
|
91
|
+
if (answers.write_env_file)
|
|
92
|
+
modes.push('durable_env_file');
|
|
93
|
+
if (answers.store_keychain)
|
|
94
|
+
modes.push('durable_keychain');
|
|
95
|
+
if (answers.sync_launchctl)
|
|
96
|
+
modes.push('durable_launchctl');
|
|
97
|
+
if (answers.install_shell_profile !== 'skip')
|
|
98
|
+
modes.push('shell_profile');
|
|
99
|
+
return modes;
|
|
100
|
+
}
|
|
101
|
+
export function codexLbPersistenceSummary({ selectedModes = [], appliedModes = [], processOnly = false } = {}) {
|
|
102
|
+
const selected = normalizePersistenceModes(selectedModes);
|
|
103
|
+
const applied = normalizePersistenceModes(appliedModes);
|
|
104
|
+
const effective = applied.find((mode) => mode !== 'process_only_ephemeral' && mode !== 'none')
|
|
105
|
+
|| selected.find((mode) => mode !== 'process_only_ephemeral' && mode !== 'none')
|
|
106
|
+
|| (processOnly || applied.includes('process_only_ephemeral') || selected.length === 0 ? 'process_only_ephemeral' : 'none');
|
|
107
|
+
const durable = ['durable_env_file', 'durable_keychain', 'durable_launchctl', 'shell_profile'].some((mode) => applied.includes(mode) || selected.includes(mode));
|
|
108
|
+
const warnings = effective === 'process_only_ephemeral'
|
|
109
|
+
? [
|
|
110
|
+
'process_only_ephemeral',
|
|
111
|
+
'next_shell_requires_setup_or_env',
|
|
112
|
+
'Codex App GUI launch may not see credentials'
|
|
113
|
+
]
|
|
114
|
+
: [];
|
|
115
|
+
return {
|
|
116
|
+
selected_modes: selected.length ? selected : ['process_only_ephemeral'],
|
|
117
|
+
applied_modes: applied.length ? applied : (effective === 'none' ? ['none'] : [effective]),
|
|
118
|
+
effective_mode: effective,
|
|
119
|
+
durable,
|
|
120
|
+
warning: warnings[0] || null,
|
|
121
|
+
warnings
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function normalizePersistenceModes(modes = []) {
|
|
125
|
+
const allowed = new Set([
|
|
126
|
+
'durable_env_file',
|
|
127
|
+
'durable_keychain',
|
|
128
|
+
'durable_launchctl',
|
|
129
|
+
'shell_profile',
|
|
130
|
+
'process_only_ephemeral',
|
|
131
|
+
'none'
|
|
132
|
+
]);
|
|
133
|
+
return [...new Set(modes.filter((mode) => allowed.has(mode)))];
|
|
134
|
+
}
|
|
77
135
|
function profileTargets(home, choice) {
|
|
78
136
|
const targets = {
|
|
79
137
|
zsh: path.join(home, '.zshrc'),
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { nowIso, projectRoot, writeJsonAtomic } from '../fsx.js';
|
|
3
3
|
import { createMission, findLatestMission } from '../mission.js';
|
|
4
|
-
import { flag } from '../../cli/args.js';
|
|
4
|
+
import { flag, readOption } from '../../cli/args.js';
|
|
5
5
|
import { printJson } from '../../cli/output.js';
|
|
6
6
|
import { maybeFinalizeRoute } from '../proof/auto-finalize.js';
|
|
7
7
|
import { computerUseLiveSmoke, computerUseStatusReport } from '../computer-use-status.js';
|
|
8
|
+
import { computerUseLiveEvidencePath } from '../computer-use-live-evidence.js';
|
|
8
9
|
export async function computerUseCommand(command, args = []) {
|
|
9
10
|
const root = await projectRoot();
|
|
10
11
|
const action = args[0] || 'import';
|
|
@@ -21,18 +22,33 @@ export async function computerUseCommand(command, args = []) {
|
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
23
24
|
if (action === 'smoke') {
|
|
24
|
-
const
|
|
25
|
+
const missionArg = readOption(args, '--mission', null);
|
|
26
|
+
const missionId = missionArg === 'latest' ? await findLatestMission(root) : missionArg;
|
|
27
|
+
const route = readOption(args, '--route', null);
|
|
28
|
+
const evidencePath = computerUseLiveEvidencePath(root, { missionId });
|
|
25
29
|
const result = await computerUseLiveSmoke({
|
|
30
|
+
root,
|
|
26
31
|
real: flag(args, '--real'),
|
|
27
32
|
requireReal: flag(args, '--require-real'),
|
|
33
|
+
captureScreenshot: flag(args, '--capture-screenshot'),
|
|
28
34
|
allowAction: flag(args, '--allow-action'),
|
|
35
|
+
route,
|
|
36
|
+
missionId,
|
|
29
37
|
evidencePath
|
|
30
38
|
});
|
|
31
39
|
if (flag(args, '--json')) {
|
|
32
40
|
printJson(result);
|
|
33
41
|
}
|
|
34
42
|
else {
|
|
35
|
-
console.log(`Computer Use smoke: ${result.status}`);
|
|
43
|
+
console.log(`Computer Use smoke: ${result.status} (${result.evidence_mode})`);
|
|
44
|
+
if (result.live_evidence_path)
|
|
45
|
+
console.log(`Live evidence: ${result.live_evidence_path}`);
|
|
46
|
+
if (result.blockers?.length)
|
|
47
|
+
for (const blocker of result.blockers)
|
|
48
|
+
console.log(`- blocker: ${blocker}`);
|
|
49
|
+
if (result.warnings?.length)
|
|
50
|
+
for (const warning of result.warnings)
|
|
51
|
+
console.log(`- warning: ${warning}`);
|
|
36
52
|
if (result.guidance?.length)
|
|
37
53
|
for (const line of result.guidance)
|
|
38
54
|
console.log(`- ${line}`);
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { ComputerUseStatus } from './computer-use-status.js';
|
|
2
|
+
export type ComputerUseEvidenceMode = 'probe_only' | 'live_capture_attempted' | 'live_capture_success' | 'live_capture_blocked';
|
|
3
|
+
export type ComputerUseCaptureStatus = 'not_attempted' | 'captured' | 'blocked' | 'failed' | 'redacted' | 'local_only';
|
|
4
|
+
export interface ComputerUseLiveEvidence {
|
|
5
|
+
schema: 'sks.computer-use-live-evidence.v1';
|
|
6
|
+
generated_at: string;
|
|
7
|
+
route: string | null;
|
|
8
|
+
mission_id: string | null;
|
|
9
|
+
mode: ComputerUseEvidenceMode;
|
|
10
|
+
status: ComputerUseStatus;
|
|
11
|
+
platform: string;
|
|
12
|
+
mock: false;
|
|
13
|
+
capability: {
|
|
14
|
+
codex_app_installed: boolean;
|
|
15
|
+
capability_detected: boolean;
|
|
16
|
+
external_capability_blocked: boolean;
|
|
17
|
+
blocker: ComputerUseStatus | null;
|
|
18
|
+
};
|
|
19
|
+
capture: {
|
|
20
|
+
screenshot: {
|
|
21
|
+
attempted: boolean;
|
|
22
|
+
status: ComputerUseCaptureStatus;
|
|
23
|
+
path: string | null;
|
|
24
|
+
sha256: string | null;
|
|
25
|
+
redacted: boolean;
|
|
26
|
+
local_only: boolean;
|
|
27
|
+
};
|
|
28
|
+
action: {
|
|
29
|
+
attempted: boolean;
|
|
30
|
+
status: ComputerUseCaptureStatus;
|
|
31
|
+
actions: unknown[];
|
|
32
|
+
redacted: boolean;
|
|
33
|
+
local_only: boolean;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
image_voxel: {
|
|
37
|
+
linked: boolean;
|
|
38
|
+
ledger_path: string | null;
|
|
39
|
+
anchor_ids: string[];
|
|
40
|
+
reason: string | null;
|
|
41
|
+
};
|
|
42
|
+
privacy: {
|
|
43
|
+
shared_triwiki_publish_allowed: false;
|
|
44
|
+
contains_screen_content: boolean;
|
|
45
|
+
redaction_required: boolean;
|
|
46
|
+
};
|
|
47
|
+
blockers: string[];
|
|
48
|
+
warnings: string[];
|
|
49
|
+
}
|
|
50
|
+
export interface ComputerUseScreenshotCaptureAdapter {
|
|
51
|
+
captureScreenshot: (opts: {
|
|
52
|
+
root: string;
|
|
53
|
+
route: string | null;
|
|
54
|
+
missionId: string | null;
|
|
55
|
+
outputPath: string;
|
|
56
|
+
}) => Promise<{
|
|
57
|
+
ok: boolean;
|
|
58
|
+
path?: string | null;
|
|
59
|
+
data?: Buffer | Uint8Array | string | null;
|
|
60
|
+
blocker?: string | null;
|
|
61
|
+
warning?: string | null;
|
|
62
|
+
redacted?: boolean;
|
|
63
|
+
localOnly?: boolean;
|
|
64
|
+
}>;
|
|
65
|
+
}
|
|
66
|
+
export interface CodexAppComputerUseCapabilityAdapter {
|
|
67
|
+
detect: () => Promise<{
|
|
68
|
+
codex_app_installed: boolean;
|
|
69
|
+
capability_detected: boolean;
|
|
70
|
+
external_capability_blocked?: boolean;
|
|
71
|
+
blocker?: ComputerUseStatus | null;
|
|
72
|
+
}>;
|
|
73
|
+
}
|
|
74
|
+
export interface BuildComputerUseLiveEvidenceOptions {
|
|
75
|
+
root?: string;
|
|
76
|
+
route?: string | null;
|
|
77
|
+
missionId?: string | null;
|
|
78
|
+
statusReport: Record<string, any>;
|
|
79
|
+
realOptIn?: boolean;
|
|
80
|
+
captureScreenshot?: boolean;
|
|
81
|
+
allowAction?: boolean;
|
|
82
|
+
screenshotAdapter?: ComputerUseScreenshotCaptureAdapter | null;
|
|
83
|
+
capabilityAdapter?: CodexAppComputerUseCapabilityAdapter | null;
|
|
84
|
+
evidencePath?: string | null;
|
|
85
|
+
}
|
|
86
|
+
export declare function computerUseLiveEvidencePath(root?: string, opts?: {
|
|
87
|
+
missionId?: string | null;
|
|
88
|
+
}): string;
|
|
89
|
+
export declare function readComputerUseLiveEvidence(root?: string, opts?: {
|
|
90
|
+
missionId?: string | null;
|
|
91
|
+
path?: string | null;
|
|
92
|
+
}): Promise<{
|
|
93
|
+
ok: boolean;
|
|
94
|
+
path: string;
|
|
95
|
+
evidence: ComputerUseLiveEvidence;
|
|
96
|
+
} | {
|
|
97
|
+
ok: boolean;
|
|
98
|
+
path: null;
|
|
99
|
+
evidence: null;
|
|
100
|
+
}>;
|
|
101
|
+
export declare function writeComputerUseLiveEvidence(file: string, evidence: ComputerUseLiveEvidence): Promise<{
|
|
102
|
+
ok: boolean;
|
|
103
|
+
path: string;
|
|
104
|
+
evidence: ComputerUseLiveEvidence;
|
|
105
|
+
}>;
|
|
106
|
+
export declare function buildComputerUseLiveEvidence(opts: BuildComputerUseLiveEvidenceOptions): Promise<ComputerUseLiveEvidence>;
|
|
107
|
+
export declare function isComputerUseLiveEvidence(value: unknown): value is ComputerUseLiveEvidence;
|
|
108
|
+
export declare function isComputerUseEvidenceMode(value: unknown): value is ComputerUseEvidenceMode;
|
|
109
|
+
//# sourceMappingURL=computer-use-live-evidence.d.ts.map
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import fsp from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ensureDir, exists, nowIso, packageRoot, readJson, rel, sha256, writeJsonAtomic } from './fsx.js';
|
|
4
|
+
import { addVisualAnchor, ingestImage, missionImageLedgerPath } from './wiki-image/image-voxel-ledger.js';
|
|
5
|
+
export function computerUseLiveEvidencePath(root = packageRoot(), opts = {}) {
|
|
6
|
+
if (opts.missionId) {
|
|
7
|
+
return path.join(root, '.sneakoscope', 'missions', opts.missionId, 'computer-use-live-evidence.json');
|
|
8
|
+
}
|
|
9
|
+
return path.join(root, '.sneakoscope', 'reports', 'computer-use-live-evidence.json');
|
|
10
|
+
}
|
|
11
|
+
export async function readComputerUseLiveEvidence(root = packageRoot(), opts = {}) {
|
|
12
|
+
const candidates = [
|
|
13
|
+
opts.path || null,
|
|
14
|
+
opts.missionId ? computerUseLiveEvidencePath(root, { missionId: opts.missionId }) : null,
|
|
15
|
+
computerUseLiveEvidencePath(root)
|
|
16
|
+
].filter(Boolean);
|
|
17
|
+
for (const file of candidates) {
|
|
18
|
+
const parsed = await readJson(file, null).catch(() => null);
|
|
19
|
+
if (isComputerUseLiveEvidence(parsed))
|
|
20
|
+
return { ok: true, path: file, evidence: parsed };
|
|
21
|
+
}
|
|
22
|
+
return { ok: false, path: null, evidence: null };
|
|
23
|
+
}
|
|
24
|
+
export async function writeComputerUseLiveEvidence(file, evidence) {
|
|
25
|
+
await ensureDir(path.dirname(file));
|
|
26
|
+
await writeJsonAtomic(file, evidence);
|
|
27
|
+
return { ok: true, path: file, evidence };
|
|
28
|
+
}
|
|
29
|
+
export async function buildComputerUseLiveEvidence(opts) {
|
|
30
|
+
const root = opts.root || packageRoot();
|
|
31
|
+
const status = normalizeComputerUseStatus(opts.statusReport?.status);
|
|
32
|
+
const realOptIn = opts.realOptIn === true;
|
|
33
|
+
const route = opts.route || null;
|
|
34
|
+
const missionId = opts.missionId || null;
|
|
35
|
+
const warnings = [];
|
|
36
|
+
const blockers = [];
|
|
37
|
+
const capability = await detectCapability(opts);
|
|
38
|
+
const platform = String(opts.statusReport?.platform || process.platform);
|
|
39
|
+
let mode = realOptIn && status !== 'not_macos' ? 'live_capture_attempted' : 'probe_only';
|
|
40
|
+
const evidence = {
|
|
41
|
+
schema: 'sks.computer-use-live-evidence.v1',
|
|
42
|
+
generated_at: nowIso(),
|
|
43
|
+
route,
|
|
44
|
+
mission_id: missionId,
|
|
45
|
+
mode,
|
|
46
|
+
status,
|
|
47
|
+
platform,
|
|
48
|
+
mock: false,
|
|
49
|
+
capability,
|
|
50
|
+
capture: {
|
|
51
|
+
screenshot: {
|
|
52
|
+
attempted: false,
|
|
53
|
+
status: 'not_attempted',
|
|
54
|
+
path: null,
|
|
55
|
+
sha256: null,
|
|
56
|
+
redacted: false,
|
|
57
|
+
local_only: true
|
|
58
|
+
},
|
|
59
|
+
action: {
|
|
60
|
+
attempted: false,
|
|
61
|
+
status: 'not_attempted',
|
|
62
|
+
actions: [],
|
|
63
|
+
redacted: false,
|
|
64
|
+
local_only: true
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
image_voxel: {
|
|
68
|
+
linked: false,
|
|
69
|
+
ledger_path: missionId ? rel(root, missionImageLedgerPath(root, missionId)) : null,
|
|
70
|
+
anchor_ids: [],
|
|
71
|
+
reason: null
|
|
72
|
+
},
|
|
73
|
+
privacy: {
|
|
74
|
+
shared_triwiki_publish_allowed: false,
|
|
75
|
+
contains_screen_content: false,
|
|
76
|
+
redaction_required: false
|
|
77
|
+
},
|
|
78
|
+
blockers,
|
|
79
|
+
warnings
|
|
80
|
+
};
|
|
81
|
+
if (!realOptIn) {
|
|
82
|
+
evidence.image_voxel.reason = 'probe_only_no_live_capture_attempted';
|
|
83
|
+
return evidence;
|
|
84
|
+
}
|
|
85
|
+
if (status === 'not_macos') {
|
|
86
|
+
blockers.push('not_macos');
|
|
87
|
+
evidence.mode = 'probe_only';
|
|
88
|
+
evidence.image_voxel.reason = 'not_macos';
|
|
89
|
+
return evidence;
|
|
90
|
+
}
|
|
91
|
+
if (status !== 'available') {
|
|
92
|
+
blockers.push(status);
|
|
93
|
+
evidence.mode = 'live_capture_blocked';
|
|
94
|
+
evidence.capture.screenshot.status = opts.captureScreenshot ? 'blocked' : 'not_attempted';
|
|
95
|
+
evidence.capture.screenshot.attempted = opts.captureScreenshot === true;
|
|
96
|
+
evidence.image_voxel.reason = status;
|
|
97
|
+
return evidence;
|
|
98
|
+
}
|
|
99
|
+
if (opts.captureScreenshot) {
|
|
100
|
+
await attemptScreenshotCapture(root, evidence, opts);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
evidence.image_voxel.reason = 'capture_screenshot_not_requested';
|
|
104
|
+
}
|
|
105
|
+
if (opts.allowAction) {
|
|
106
|
+
evidence.capture.action.attempted = true;
|
|
107
|
+
evidence.capture.action.status = 'blocked';
|
|
108
|
+
blockers.push('computer_use_action_adapter_missing');
|
|
109
|
+
warnings.push('Computer Use smoke never runs click/type actions without an official non-destructive Codex App adapter.');
|
|
110
|
+
}
|
|
111
|
+
if (evidence.capture.screenshot.status === 'captured') {
|
|
112
|
+
evidence.mode = 'live_capture_success';
|
|
113
|
+
evidence.privacy.contains_screen_content = true;
|
|
114
|
+
}
|
|
115
|
+
else if (blockers.length) {
|
|
116
|
+
evidence.mode = 'live_capture_blocked';
|
|
117
|
+
}
|
|
118
|
+
return evidence;
|
|
119
|
+
}
|
|
120
|
+
export function isComputerUseLiveEvidence(value) {
|
|
121
|
+
if (!value || typeof value !== 'object')
|
|
122
|
+
return false;
|
|
123
|
+
const evidence = value;
|
|
124
|
+
return evidence.schema === 'sks.computer-use-live-evidence.v1'
|
|
125
|
+
&& isComputerUseEvidenceMode(evidence.mode)
|
|
126
|
+
&& evidence.mock === false
|
|
127
|
+
&& typeof evidence.capture === 'object'
|
|
128
|
+
&& typeof evidence.privacy === 'object';
|
|
129
|
+
}
|
|
130
|
+
export function isComputerUseEvidenceMode(value) {
|
|
131
|
+
return value === 'probe_only'
|
|
132
|
+
|| value === 'live_capture_attempted'
|
|
133
|
+
|| value === 'live_capture_success'
|
|
134
|
+
|| value === 'live_capture_blocked';
|
|
135
|
+
}
|
|
136
|
+
async function detectCapability(opts) {
|
|
137
|
+
if (opts.capabilityAdapter) {
|
|
138
|
+
const detected = await opts.capabilityAdapter.detect();
|
|
139
|
+
return {
|
|
140
|
+
codex_app_installed: Boolean(detected.codex_app_installed),
|
|
141
|
+
capability_detected: Boolean(detected.capability_detected),
|
|
142
|
+
external_capability_blocked: detected.external_capability_blocked === true,
|
|
143
|
+
blocker: detected.blocker || null
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const status = normalizeComputerUseStatus(opts.statusReport?.status);
|
|
147
|
+
const installed = Boolean(opts.statusReport?.app?.app?.installed);
|
|
148
|
+
const available = status === 'available';
|
|
149
|
+
return {
|
|
150
|
+
codex_app_installed: installed,
|
|
151
|
+
capability_detected: available,
|
|
152
|
+
external_capability_blocked: status !== 'available',
|
|
153
|
+
blocker: available ? null : status
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
async function attemptScreenshotCapture(root, evidence, opts) {
|
|
157
|
+
evidence.capture.screenshot.attempted = true;
|
|
158
|
+
const outputPath = screenshotArtifactPath(root, opts);
|
|
159
|
+
const adapter = opts.screenshotAdapter || null;
|
|
160
|
+
if (!adapter) {
|
|
161
|
+
evidence.capture.screenshot.status = 'blocked';
|
|
162
|
+
evidence.blockers.push('codex_app_capability_missing');
|
|
163
|
+
evidence.warnings.push('Official Codex App Computer Use screenshot adapter is not exposed to this CLI process.');
|
|
164
|
+
evidence.image_voxel.reason = 'computer_use_capture_adapter_missing';
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
const result = await adapter.captureScreenshot({
|
|
169
|
+
root,
|
|
170
|
+
route: opts.route || null,
|
|
171
|
+
missionId: opts.missionId || null,
|
|
172
|
+
outputPath
|
|
173
|
+
});
|
|
174
|
+
if (!result.ok) {
|
|
175
|
+
evidence.capture.screenshot.status = 'blocked';
|
|
176
|
+
evidence.blockers.push(redactCaptureMessage(result.blocker || 'external_capability_blocked'));
|
|
177
|
+
if (result.warning)
|
|
178
|
+
evidence.warnings.push(redactCaptureMessage(result.warning));
|
|
179
|
+
evidence.image_voxel.reason = result.blocker || 'screenshot_capture_blocked';
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const capturedPath = await materializeScreenshot(result, outputPath);
|
|
183
|
+
const data = await fsp.readFile(capturedPath);
|
|
184
|
+
evidence.capture.screenshot.status = result.localOnly === false ? 'captured' : 'captured';
|
|
185
|
+
evidence.capture.screenshot.path = rel(root, capturedPath);
|
|
186
|
+
evidence.capture.screenshot.sha256 = sha256(data);
|
|
187
|
+
evidence.capture.screenshot.redacted = result.redacted === true;
|
|
188
|
+
evidence.capture.screenshot.local_only = result.localOnly !== false;
|
|
189
|
+
evidence.privacy.redaction_required = result.redacted === true;
|
|
190
|
+
await linkScreenshotToImageVoxel(root, evidence, capturedPath, opts);
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
evidence.capture.screenshot.status = 'failed';
|
|
194
|
+
evidence.blockers.push('screenshot_capture_failed');
|
|
195
|
+
evidence.image_voxel.reason = redactCaptureMessage(err instanceof Error ? err.message : String(err));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async function materializeScreenshot(result, outputPath) {
|
|
199
|
+
if (result.path && await exists(result.path))
|
|
200
|
+
return path.resolve(result.path);
|
|
201
|
+
if (result.data === undefined || result.data === null)
|
|
202
|
+
throw new Error('screenshot_capture_returned_no_path_or_data');
|
|
203
|
+
await ensureDir(path.dirname(outputPath));
|
|
204
|
+
const bytes = typeof result.data === 'string' ? Buffer.from(result.data, 'base64') : Buffer.from(result.data);
|
|
205
|
+
await fsp.writeFile(outputPath, bytes);
|
|
206
|
+
return outputPath;
|
|
207
|
+
}
|
|
208
|
+
async function linkScreenshotToImageVoxel(root, evidence, screenshotPath, opts) {
|
|
209
|
+
if (!opts.missionId) {
|
|
210
|
+
evidence.image_voxel.reason = 'mission_id_missing';
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (!evidence.capture.screenshot.sha256) {
|
|
214
|
+
evidence.image_voxel.reason = 'screenshot_sha256_missing';
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const relative = rel(root, screenshotPath);
|
|
218
|
+
if (relative.startsWith('..')) {
|
|
219
|
+
evidence.image_voxel.reason = 'screenshot_path_outside_project';
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
const imageId = evidence.capture.screenshot.sha256;
|
|
224
|
+
const ingested = await ingestImage(root, relative, {
|
|
225
|
+
missionId: opts.missionId,
|
|
226
|
+
source: 'computer_use_live_screenshot',
|
|
227
|
+
id: imageId,
|
|
228
|
+
capturedAt: evidence.generated_at
|
|
229
|
+
});
|
|
230
|
+
const image = ingested.image;
|
|
231
|
+
const anchorId = `computer-use-${imageId.slice(0, 16)}-screen`;
|
|
232
|
+
const anchor = await addVisualAnchor(root, {
|
|
233
|
+
id: anchorId,
|
|
234
|
+
missionId: opts.missionId,
|
|
235
|
+
imageId,
|
|
236
|
+
bbox: [0, 0, image.width || 1, image.height || 1],
|
|
237
|
+
label: 'Computer Use live screenshot',
|
|
238
|
+
source: 'computer_use_live_screenshot',
|
|
239
|
+
evidencePath: relative,
|
|
240
|
+
route: opts.route || '$Computer-Use',
|
|
241
|
+
trustScore: 0.86
|
|
242
|
+
});
|
|
243
|
+
evidence.image_voxel.linked = Boolean(anchor.ok);
|
|
244
|
+
evidence.image_voxel.ledger_path = rel(root, missionImageLedgerPath(root, opts.missionId));
|
|
245
|
+
evidence.image_voxel.anchor_ids = anchor.ok ? [anchorId] : [];
|
|
246
|
+
evidence.image_voxel.reason = anchor.ok ? null : (anchor.validation?.issues || ['image_voxel_anchor_failed']).join(',');
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
evidence.image_voxel.reason = redactCaptureMessage(err instanceof Error ? err.message : String(err));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function screenshotArtifactPath(root, opts) {
|
|
253
|
+
if (opts.missionId) {
|
|
254
|
+
return path.join(root, '.sneakoscope', 'missions', opts.missionId, 'computer-use-live-screenshot.png');
|
|
255
|
+
}
|
|
256
|
+
return path.join(root, '.sneakoscope', 'reports', 'computer-use-live-screenshot.png');
|
|
257
|
+
}
|
|
258
|
+
function normalizeComputerUseStatus(value) {
|
|
259
|
+
const allowed = [
|
|
260
|
+
'available',
|
|
261
|
+
'codex_app_missing',
|
|
262
|
+
'macos_permission_missing',
|
|
263
|
+
'codex_app_capability_missing',
|
|
264
|
+
'external_capability_blocked',
|
|
265
|
+
'not_macos',
|
|
266
|
+
'unknown'
|
|
267
|
+
];
|
|
268
|
+
return allowed.includes(value) ? value : 'unknown';
|
|
269
|
+
}
|
|
270
|
+
function redactCaptureMessage(value) {
|
|
271
|
+
return String(value || 'unknown')
|
|
272
|
+
.replace(/sk-[A-Za-z0-9_-]+/g, '[redacted]')
|
|
273
|
+
.replace(/CODEX_LB_API_KEY=([^\s]+)/g, 'CODEX_LB_API_KEY=[redacted]')
|
|
274
|
+
.slice(0, 500);
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=computer-use-live-evidence.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export type { ComputerUseCaptureStatus, ComputerUseEvidenceMode, ComputerUseLiveEvidence } from './computer-use-live-evidence.js';
|
|
1
2
|
export type ComputerUseStatus = 'available' | 'codex_app_missing' | 'macos_permission_missing' | 'codex_app_capability_missing' | 'external_capability_blocked' | 'not_macos' | 'unknown';
|
|
2
3
|
export declare function computerUseStatusReport(opts?: any): Promise<any>;
|
|
3
4
|
export declare function computerUseEvidenceSkeleton(status?: ComputerUseStatus): {
|
|
@@ -11,7 +12,8 @@ export declare function computerUseEvidenceSkeleton(status?: ComputerUseStatus):
|
|
|
11
12
|
export declare function computerUseLiveSmoke(opts?: any): Promise<{
|
|
12
13
|
schema: string;
|
|
13
14
|
ok: boolean;
|
|
14
|
-
mode:
|
|
15
|
+
mode: import("./computer-use-live-evidence.js").ComputerUseEvidenceMode;
|
|
16
|
+
evidence_mode: import("./computer-use-live-evidence.js").ComputerUseEvidenceMode;
|
|
15
17
|
status: any;
|
|
16
18
|
platform: any;
|
|
17
19
|
codex_app: {
|
|
@@ -22,12 +24,17 @@ export declare function computerUseLiveSmoke(opts?: any): Promise<{
|
|
|
22
24
|
screen_recording: any;
|
|
23
25
|
accessibility: string;
|
|
24
26
|
};
|
|
27
|
+
live_evidence_path: any;
|
|
28
|
+
image_voxel_linked: boolean;
|
|
29
|
+
blockers: string[];
|
|
30
|
+
warnings: string[];
|
|
25
31
|
evidence: {
|
|
26
32
|
screenshot_captured: boolean;
|
|
27
33
|
action_captured: boolean;
|
|
28
34
|
image_voxel_linked: boolean;
|
|
29
35
|
evidence_path: any;
|
|
30
36
|
};
|
|
37
|
+
live_evidence: import("./computer-use-live-evidence.js").ComputerUseLiveEvidence | null;
|
|
31
38
|
external_capability_blocked: boolean;
|
|
32
39
|
mock: boolean;
|
|
33
40
|
guidance: any;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { codexAppIntegrationStatus } from './codex-app.js';
|
|
2
|
+
import { buildComputerUseLiveEvidence, computerUseLiveEvidencePath, writeComputerUseLiveEvidence } from './computer-use-live-evidence.js';
|
|
2
3
|
export async function computerUseStatusReport(opts = {}) {
|
|
3
4
|
if (process.platform !== 'darwin' && !opts.forceMacos) {
|
|
4
5
|
return baseReport('not_macos', {
|
|
@@ -54,47 +55,65 @@ export function computerUseEvidenceSkeleton(status = 'unknown') {
|
|
|
54
55
|
export async function computerUseLiveSmoke(opts = {}) {
|
|
55
56
|
const realOptIn = opts.real === true || process.env.SKS_TEST_REAL_COMPUTER_USE === '1';
|
|
56
57
|
const requireReal = opts.requireReal === true;
|
|
58
|
+
const captureScreenshot = opts.captureScreenshot === true || requireReal;
|
|
57
59
|
const status = await computerUseStatusReport(opts);
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
const
|
|
60
|
+
const root = opts.root || process.cwd();
|
|
61
|
+
const evidencePath = opts.evidencePath || (realOptIn ? computerUseLiveEvidencePath(root, { missionId: opts.missionId || null }) : null);
|
|
62
|
+
const liveEvidence = realOptIn
|
|
63
|
+
? await buildComputerUseLiveEvidence({
|
|
64
|
+
root,
|
|
65
|
+
route: opts.route || null,
|
|
66
|
+
missionId: opts.missionId || null,
|
|
67
|
+
statusReport: status,
|
|
68
|
+
realOptIn,
|
|
69
|
+
captureScreenshot,
|
|
70
|
+
allowAction: opts.allowAction === true,
|
|
71
|
+
screenshotAdapter: opts.screenshotAdapter || null,
|
|
72
|
+
capabilityAdapter: opts.capabilityAdapter || null,
|
|
73
|
+
evidencePath
|
|
74
|
+
})
|
|
75
|
+
: null;
|
|
76
|
+
if (liveEvidence && evidencePath)
|
|
77
|
+
await writeComputerUseLiveEvidence(evidencePath, liveEvidence);
|
|
78
|
+
const evidenceMode = liveEvidence?.mode || 'probe_only';
|
|
79
|
+
const liveCaptureSuccess = evidenceMode === 'live_capture_success';
|
|
80
|
+
const blockers = [...(liveEvidence?.blockers || [])];
|
|
81
|
+
if (!realOptIn && status.status === 'not_macos')
|
|
82
|
+
blockers.push('not_macos');
|
|
83
|
+
const warnings = [...(liveEvidence?.warnings || [])];
|
|
84
|
+
const ok = requireReal ? liveCaptureSuccess : true;
|
|
61
85
|
const smoke = {
|
|
62
|
-
schema: 'sks.computer-use-live-smoke.
|
|
63
|
-
ok
|
|
64
|
-
mode:
|
|
86
|
+
schema: 'sks.computer-use-live-smoke.v2',
|
|
87
|
+
ok,
|
|
88
|
+
mode: evidenceMode,
|
|
89
|
+
evidence_mode: evidenceMode,
|
|
65
90
|
status: status.status,
|
|
66
91
|
platform: status.platform || process.platform,
|
|
67
92
|
codex_app: {
|
|
68
93
|
installed: Boolean(status.app?.app?.installed),
|
|
69
|
-
capability_detected: available
|
|
94
|
+
capability_detected: status.status === 'available'
|
|
70
95
|
},
|
|
71
96
|
permission: {
|
|
72
97
|
screen_recording: status.permission_status || 'unknown',
|
|
73
98
|
accessibility: 'unknown'
|
|
74
99
|
},
|
|
100
|
+
live_evidence_path: liveEvidence && evidencePath ? evidencePath : null,
|
|
101
|
+
image_voxel_linked: liveEvidence?.image_voxel?.linked === true,
|
|
102
|
+
blockers,
|
|
103
|
+
warnings,
|
|
75
104
|
evidence: {
|
|
76
|
-
screenshot_captured:
|
|
77
|
-
action_captured:
|
|
78
|
-
image_voxel_linked:
|
|
79
|
-
evidence_path: evidencePath
|
|
105
|
+
screenshot_captured: liveEvidence?.capture?.screenshot?.status === 'captured',
|
|
106
|
+
action_captured: liveEvidence?.capture?.action?.status === 'captured',
|
|
107
|
+
image_voxel_linked: liveEvidence?.image_voxel?.linked === true,
|
|
108
|
+
evidence_path: liveEvidence && evidencePath ? evidencePath : null
|
|
80
109
|
},
|
|
110
|
+
live_evidence: liveEvidence,
|
|
81
111
|
external_capability_blocked: status.external_capability_blocked === true || ['codex_app_missing', 'macos_permission_missing', 'codex_app_capability_missing', 'unknown'].includes(status.status),
|
|
82
112
|
mock: false,
|
|
83
|
-
guidance:
|
|
84
|
-
? ['Computer Use capability appears available.
|
|
113
|
+
guidance: status.status === 'available' && realOptIn
|
|
114
|
+
? ['Computer Use capability appears available. SKS records only official, local-only live evidence and does not synthesize screenshots.']
|
|
85
115
|
: status.guidance || []
|
|
86
116
|
};
|
|
87
|
-
if (available && realOptIn && evidencePath) {
|
|
88
|
-
const { writeJsonAtomic } = await import('./fsx.js');
|
|
89
|
-
await writeJsonAtomic(evidencePath, smoke);
|
|
90
|
-
return {
|
|
91
|
-
...smoke,
|
|
92
|
-
evidence: {
|
|
93
|
-
...smoke.evidence,
|
|
94
|
-
evidence_path: evidencePath
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
117
|
return smoke;
|
|
99
118
|
}
|
|
100
119
|
function baseReport(status, extra = {}) {
|
|
@@ -51,6 +51,7 @@ export async function evidenceCandidatesForProof(root, proof = {}, opts = {}) {
|
|
|
51
51
|
addDbCandidates(candidates, proof.evidence?.db || proof.evidence?.db_safety, missionId);
|
|
52
52
|
addTestCandidates(candidates, proof.evidence?.tests, missionId);
|
|
53
53
|
addWrongnessCandidates(candidates, proof.evidence?.wrongness, missionId);
|
|
54
|
+
addComputerUseCandidates(candidates, proof.evidence?.computer_use, missionId);
|
|
54
55
|
if (missionId && routeRequiresImageVoxelAnchors(route)) {
|
|
55
56
|
candidates.push({ kind: 'image_voxel', relPath: `.sneakoscope/missions/${missionId}/image-voxel-ledger.json`, source: proof.evidence?.image_voxels?.mock ? 'mock' : sourceForProof(proof) });
|
|
56
57
|
}
|
|
@@ -140,6 +141,13 @@ function addWrongnessCandidates(candidates, wrongness = null, missionId = null)
|
|
|
140
141
|
if (missionId)
|
|
141
142
|
candidates.push({ kind: 'image_wrongness', relPath: `.sneakoscope/missions/${missionId}/image-wrongness-ledger.json`, source: 'real', optional: true, ignoreStale: true });
|
|
142
143
|
}
|
|
144
|
+
function addComputerUseCandidates(candidates, computerUse = null, missionId = null) {
|
|
145
|
+
const relPath = computerUse?.live_evidence_path || computerUse?.live_evidence?.path || null;
|
|
146
|
+
if (relPath)
|
|
147
|
+
candidates.push({ kind: 'computer_use', relPath: normalizeRelPath(relPath, missionId), source: 'real', ignoreStale: true });
|
|
148
|
+
else if (missionId)
|
|
149
|
+
candidates.push({ kind: 'computer_use', relPath: `.sneakoscope/missions/${missionId}/computer-use-live-evidence.json`, source: 'blocked', optional: true, ignoreStale: true });
|
|
150
|
+
}
|
|
143
151
|
function uniqueCandidates(candidates) {
|
|
144
152
|
const seen = new Set();
|
|
145
153
|
const out = [];
|
|
@@ -200,6 +208,8 @@ function inferKind(relPath = '') {
|
|
|
200
208
|
return 'wrongness';
|
|
201
209
|
if (/image-voxel-ledger\.json$|visual-anchors\.json$|image-assets\.json$/.test(relPath))
|
|
202
210
|
return 'image_voxel';
|
|
211
|
+
if (/computer-use-live-evidence\.json$|computer-use.*evidence/.test(relPath))
|
|
212
|
+
return 'computer_use';
|
|
203
213
|
if (/scout/.test(relPath))
|
|
204
214
|
return 'scout';
|
|
205
215
|
if (/db/.test(relPath))
|
package/dist/core/fsx.d.ts
CHANGED
package/dist/core/fsx.js
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
|
import { fileURLToPath } from 'node:url';
|
|
8
|
-
export const PACKAGE_VERSION = '1.0.
|
|
8
|
+
export const PACKAGE_VERSION = '1.0.7';
|
|
9
9
|
export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
|
|
10
10
|
export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
|
|
11
11
|
export function nowIso() {
|
|
@@ -5,6 +5,7 @@ import { ensureRouteImageEvidence } from '../wiki-image/route-image-evidence.js'
|
|
|
5
5
|
import { readScoutProofEvidence } from '../scouts/scout-proof-evidence.js';
|
|
6
6
|
import { wrongnessProofEvidence } from '../triwiki-wrongness/wrongness-proof-linker.js';
|
|
7
7
|
import { computerUseStatusReport } from '../computer-use-status.js';
|
|
8
|
+
import { readComputerUseLiveEvidence } from '../computer-use-live-evidence.js';
|
|
8
9
|
export async function finalizeRouteWithProof(root, { missionId, route, gateFile = null, gate = null, artifacts = [], visualEvidence = null, dbEvidence = null, testEvidence = null, commandEvidence = null, claims = [], unverified = [], blockers = [], statusHint = 'verified_partial', strict = false, mock = false, fixClaim = false, requireRelation = false, visualClaim = undefined } = {}) {
|
|
9
10
|
const policy = routeFinalizerPolicy(route, { strict, fixClaim, requireRelation, visualClaim });
|
|
10
11
|
const localBlockers = [...blockers];
|
|
@@ -27,13 +28,33 @@ export async function finalizeRouteWithProof(root, { missionId, route, gateFile
|
|
|
27
28
|
const computerUse = policy.requires_image_voxel_anchors
|
|
28
29
|
? await computerUseStatusReport().catch((err) => ({ schema: 'sks.computer-use-status.v1', status: 'unknown', ok: false, guidance: [err.message], evidence: { status: 'unknown' } }))
|
|
29
30
|
: null;
|
|
31
|
+
const computerUseLive = policy.requires_image_voxel_anchors
|
|
32
|
+
? await readComputerUseLiveEvidence(root, { missionId }).catch(() => ({ ok: false, path: null, evidence: null }))
|
|
33
|
+
: null;
|
|
30
34
|
if (computerUse && computerUse.status !== 'available') {
|
|
31
35
|
unverified.push(`Computer Use evidence unavailable: ${computerUse.status}. Visual claim remains verified_partial unless explicit screenshot/image evidence covers it.`);
|
|
32
36
|
}
|
|
37
|
+
if (computerUse && !computerUseLive?.evidence) {
|
|
38
|
+
unverified.push('Computer Use live evidence is missing for this visual route; high-confidence visual claims require live evidence or explicit screenshot/image coverage.');
|
|
39
|
+
if (strict)
|
|
40
|
+
localBlockers.push('computer_use_live_evidence_missing');
|
|
41
|
+
}
|
|
42
|
+
if (computerUseLive?.evidence?.mode === 'probe_only') {
|
|
43
|
+
unverified.push('Computer Use evidence mode is probe_only; visual claim confidence is capped below high confidence.');
|
|
44
|
+
}
|
|
45
|
+
if (computerUseLive?.evidence?.mode === 'live_capture_blocked') {
|
|
46
|
+
unverified.push(`Computer Use live capture blocked: ${(computerUseLive.evidence.blockers || []).join(',') || computerUseLive.evidence.status}.`);
|
|
47
|
+
}
|
|
48
|
+
if (computerUseLive?.evidence && computerUseLive.evidence.image_voxel?.linked !== true && statusHint === 'verified') {
|
|
49
|
+
unverified.push(`Computer Use live evidence is not linked to Image Voxel: ${computerUseLive.evidence.image_voxel?.reason || 'missing_relation'}.`);
|
|
50
|
+
}
|
|
33
51
|
if (Number(wrongnessEvidence?.high_severity_active || 0) > 0) {
|
|
34
52
|
localBlockers.push('active_high_severity_wrongness');
|
|
35
53
|
}
|
|
36
|
-
const visualComputerUseDowngrade = Boolean(computerUse && computerUse.status !== 'available'
|
|
54
|
+
const visualComputerUseDowngrade = Boolean(statusHint === 'verified' && ((computerUse && computerUse.status !== 'available')
|
|
55
|
+
|| !computerUseLive?.evidence
|
|
56
|
+
|| computerUseLive.evidence.mode !== 'live_capture_success'
|
|
57
|
+
|| computerUseLive.evidence.image_voxel?.linked !== true));
|
|
37
58
|
const status = localBlockers.length
|
|
38
59
|
? (strict ? 'blocked' : statusHint === 'verified' ? 'verified_partial' : statusHint)
|
|
39
60
|
: visualComputerUseDowngrade ? 'verified_partial'
|
|
@@ -61,7 +82,11 @@ export async function finalizeRouteWithProof(root, { missionId, route, gateFile
|
|
|
61
82
|
ok: Boolean(computerUse.ok),
|
|
62
83
|
mad_sks_independent: computerUse.mad_sks_independent === true,
|
|
63
84
|
external_capability_blocked: computerUse.external_capability_blocked === true,
|
|
64
|
-
|
|
85
|
+
evidence_mode: computerUseLive?.evidence?.mode || 'missing',
|
|
86
|
+
live_evidence_path: computerUseLive?.path || null,
|
|
87
|
+
image_voxel_linked: computerUseLive?.evidence?.image_voxel?.linked === true,
|
|
88
|
+
evidence: computerUse.evidence || null,
|
|
89
|
+
live_evidence: computerUseLive?.evidence || null
|
|
65
90
|
} } : {}),
|
|
66
91
|
route_gate: gate || (gateFile ? { source: gateFile } : null)
|
|
67
92
|
};
|
package/dist/core/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "1.0.
|
|
1
|
+
export declare const PACKAGE_VERSION = "1.0.7";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '1.0.
|
|
1
|
+
export const PACKAGE_VERSION = '1.0.7';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.7",
|
|
5
5
|
"description": "Sneakoscope Codex: fast proof-first Codex trust layer with image-based Voxel TriWiki.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
|
|
@@ -101,12 +101,16 @@
|
|
|
101
101
|
"hooks:strict-subset-check": "node ./scripts/codex-hook-strict-subset-check.mjs",
|
|
102
102
|
"codex-lb:setup-fixture": "node ./scripts/codex-lb-setup-fixture-check.mjs",
|
|
103
103
|
"codex-lb:setup-truthfulness": "node ./scripts/codex-lb-setup-truthfulness-check.mjs",
|
|
104
|
+
"codex-lb:persistence-truth": "node ./scripts/codex-lb-persistence-truth-check.mjs",
|
|
104
105
|
"codex-lb:missing-env-regression": "node ./scripts/codex-lb-missing-env-regression.mjs",
|
|
105
106
|
"computer-use:policy-check": "node ./scripts/computer-use-policy-check.mjs",
|
|
106
107
|
"computer-use:visual-route-fixture": "node ./scripts/computer-use-visual-route-fixture-check.mjs",
|
|
107
108
|
"computer-use:live-optional": "node ./scripts/computer-use-live-optional-check.mjs",
|
|
109
|
+
"computer-use:live-evidence": "node ./scripts/computer-use-live-evidence-check.mjs",
|
|
110
|
+
"docs:truthfulness": "node ./scripts/docs-truthfulness-check.mjs",
|
|
111
|
+
"release:readiness": "node ./scripts/release-readiness-report.mjs",
|
|
108
112
|
"coverage": "node --experimental-test-coverage --test \"test/**/*.test.mjs\"",
|
|
109
|
-
"release:check": "npm run typecheck:suppressions && npm run build && npm run typecheck && npm run typecheck:contracts && npm run test:types && npm run schema:check && npm run dist:check && npm run codex:compat && npm run hooks:codex-validate && npm run hooks:warning-check && npm run hooks:semantic-check && npm run hooks:strict-subset-check && npm run codex-lb:setup-fixture && npm run codex-lb:setup-truthfulness && npm run codex-lb:missing-env-regression && npm run computer-use:policy-check && npm run computer-use:visual-route-fixture && npm run computer-use:live-optional && npm run package-boundary:check && npm run blackbox:command-import-smoke && npm run test:blackbox && npm run repo-audit && npm run changelog:check && npm run cli-entrypoint:check && npm run legacy-free:check && npm run architecture:check && npm run route-modularity:check && npm run command-budget:check && npm run pipeline-budget:check && npm run pipeline-runtime:check && npm run packcheck && npm run feature:check && npm run feature-quality:check && npm run all-features:selftest && npm run scout-engines:check && npm run scouts:parser-check && npm run scouts:selftest && npm run scouts:check && npm run trust:check && npm run wrongness:fixtures && npm run wrongness:check && npm run git-hygiene:check && npm run git-precommit:fixture && npm run shared-memory:check && npm run git-collaboration:e2e && npm run evidence:check && npm run safety:check && npm run chaos:check && npm run bench:core && npm run feature-fixtures:strict && npm run selftest && npm run test:unit && npm run test:integration:mock && npm run test:e2e:mock && npm run rust:check && npm run rust:smoke && npm run perf:gate && npm run blackbox:matrix && npm run blackbox:check && npm run sizecheck && npm run registry:check && npm run typescript:migration-report && node ./scripts/release-check-stamp.mjs write",
|
|
113
|
+
"release:check": "npm run typecheck:suppressions && npm run build && npm run typecheck && npm run typecheck:contracts && npm run test:types && npm run schema:check && npm run dist:check && npm run codex:compat && npm run hooks:codex-validate && npm run hooks:warning-check && npm run hooks:semantic-check && npm run hooks:strict-subset-check && npm run codex-lb:setup-fixture && npm run codex-lb:setup-truthfulness && npm run codex-lb:persistence-truth && npm run codex-lb:missing-env-regression && npm run computer-use:policy-check && npm run computer-use:visual-route-fixture && npm run computer-use:live-optional && npm run computer-use:live-evidence && npm run docs:truthfulness && npm run release:readiness && npm run package-boundary:check && npm run blackbox:command-import-smoke && npm run test:blackbox && npm run repo-audit && npm run changelog:check && npm run cli-entrypoint:check && npm run legacy-free:check && npm run architecture:check && npm run route-modularity:check && npm run command-budget:check && npm run pipeline-budget:check && npm run pipeline-runtime:check && npm run packcheck && npm run feature:check && npm run feature-quality:check && npm run all-features:selftest && npm run scout-engines:check && npm run scouts:parser-check && npm run scouts:selftest && npm run scouts:check && npm run trust:check && npm run wrongness:fixtures && npm run wrongness:check && npm run git-hygiene:check && npm run git-precommit:fixture && npm run shared-memory:check && npm run git-collaboration:e2e && npm run evidence:check && npm run safety:check && npm run chaos:check && npm run bench:core && npm run feature-fixtures:strict && npm run selftest && npm run test:unit && npm run test:integration:mock && npm run test:e2e:mock && npm run rust:check && npm run rust:smoke && npm run perf:gate && npm run blackbox:matrix && npm run blackbox:check && npm run sizecheck && npm run registry:check && npm run typescript:migration-report && node ./scripts/release-check-stamp.mjs write && npm run release:readiness",
|
|
110
114
|
"release:publish": "npm run publish:npm",
|
|
111
115
|
"publish:dry": "npm --cache /tmp/sks-npm-cache publish --dry-run --registry https://registry.npmjs.org/ --access public",
|
|
112
116
|
"publish:npm": "npm --cache /tmp/sks-npm-cache publish --registry https://registry.npmjs.org/ --access public",
|