sneakoscope 4.1.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -3
- 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/cli/command-registry.js +1 -1
- package/dist/cli/router.js +6 -1
- package/dist/commands/doctor.js +272 -127
- package/dist/core/auto-review.js +1 -1
- package/dist/core/codex/agent-config-file-repair.js +43 -2
- package/dist/core/codex-app/codex-agent-role-sync.js +4 -4
- package/dist/core/codex-control/codex-0142-capability.js +51 -6
- package/dist/core/codex-control/codex-app-server-v2-client.js +2 -2
- package/dist/core/codex-native/codex-native-feature-broker.js +50 -0
- package/dist/core/codex-native/native-capability-postcheck.js +59 -16
- package/dist/core/codex-native/native-capability-repair-matrix.js +77 -13
- package/dist/core/commands/mad-db-command.js +146 -51
- package/dist/core/commands/mad-sks-command.js +51 -61
- package/dist/core/db-safety.js +35 -37
- package/dist/core/doctor/doctor-dirty-planner.js +9 -4
- package/dist/core/doctor/doctor-native-capability-repair.js +42 -7
- package/dist/core/doctor/doctor-readiness-matrix.js +9 -5
- package/dist/core/doctor/doctor-repair-postcheck.js +10 -1
- package/dist/core/doctor/doctor-transaction.js +1 -1
- package/dist/core/doctor/supabase-mcp-repair.js +2 -2
- package/dist/core/feature-registry.js +1 -1
- package/dist/core/fsx.js +1 -1
- package/dist/core/init.js +5 -4
- package/dist/core/mad-db/mad-db-capability.js +203 -74
- package/dist/core/mad-db/mad-db-coordinator.js +287 -0
- package/dist/core/mad-db/mad-db-executor.js +156 -0
- package/dist/core/mad-db/mad-db-ledger.js +1 -1
- package/dist/core/mad-db/mad-db-lock.js +40 -0
- package/dist/core/mad-db/mad-db-operation-store.js +140 -0
- package/dist/core/mad-db/mad-db-policy-resolver.js +42 -22
- package/dist/core/mad-db/mad-db-policy.js +195 -0
- package/dist/core/mad-db/mad-db-postconditions.js +30 -0
- package/dist/core/mad-db/mad-db-recovery.js +27 -0
- package/dist/core/mad-db/mad-db-result-lifecycle.js +31 -102
- package/dist/core/mad-db/mad-db-runtime-profile.js +121 -0
- package/dist/core/mad-db/mad-db-target.js +64 -0
- package/dist/core/managed-assets/managed-assets-manifest.js +14 -4
- package/dist/core/pipeline-internals/runtime-core.js +40 -0
- package/dist/core/providers/glm/bench/glm-benchmark-runner.js +4 -3
- package/dist/core/providers/glm/bench/glm-benchmark-types.js +1 -1
- package/dist/core/release/release-gate-dag.js +6 -5
- package/dist/core/routes.js +23 -8
- package/dist/core/update/update-migration-state.js +265 -50
- package/dist/core/update-check.js +6 -6
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-launcher.js +17 -5
- package/dist/core/zellij/zellij-slot-column-anchor.js +5 -1
- package/dist/scripts/check-dist-runtime.js +3 -2
- package/dist/scripts/codex-0142-manifest-check.js +2 -1
- package/dist/scripts/config-managed-merge-callsite-coverage-check.js +6 -0
- package/dist/scripts/doctor-dirty-plan-check.js +1 -1
- package/dist/scripts/doctor-transaction-engine-check.js +1 -0
- package/dist/scripts/doctor-warning-only-not-blocker-check.js +18 -1
- package/dist/scripts/loop-directive-check-lib.js +2 -1
- package/dist/scripts/mad-db-capability-check.js +13 -2
- package/dist/scripts/mad-db-command-check.js +7 -5
- package/dist/scripts/mad-db-hook-idempotency-check.js +21 -0
- package/dist/scripts/mad-db-ledger-check.js +2 -1
- package/dist/scripts/mad-db-lifecycle-hook-decision-check.js +5 -4
- package/dist/scripts/mad-db-mad-command-check.js +29 -16
- package/dist/scripts/mad-db-mcp-result-lifecycle-check.js +11 -10
- package/dist/scripts/mad-db-one-cycle-bounded-check.js +15 -18
- package/dist/scripts/mad-db-one-cycle-consumption-check.js +3 -3
- package/dist/scripts/mad-db-operation-lifecycle-blackbox.js +9 -9
- package/dist/scripts/mad-db-operation-lifecycle-ledger-check.js +6 -6
- package/dist/scripts/mad-db-parallel-lifecycle-check.js +24 -0
- package/dist/scripts/mad-db-policy-v2-check.js +20 -0
- package/dist/scripts/mad-db-priority-resolver-check.js +5 -5
- package/dist/scripts/mad-db-real-supabase-e2e.js +166 -0
- package/dist/scripts/mad-db-route-identity-check.js +28 -0
- package/dist/scripts/mad-db-runtime-profile-lifecycle-check.js +24 -0
- package/dist/scripts/mad-db-safety-conflict-matrix-check.js +3 -3
- package/dist/scripts/mad-db-skill-policy-snapshot-check.js +15 -0
- package/dist/scripts/mad-sks-zellij-launch-check.js +7 -1
- package/dist/scripts/managed-role-manifest-parity-check.js +4 -1
- package/dist/scripts/naruto-real-parallelism-blackbox.js +17 -4
- package/dist/scripts/native-capability-postcheck-check.js +1 -0
- package/dist/scripts/native-capability-repair-matrix-check.js +2 -0
- package/dist/scripts/native-chrome-web-review-repair-check.js +1 -0
- package/dist/scripts/native-computer-use-repair-check.js +1 -0
- package/dist/scripts/release-dag-full-coverage-check.js +6 -0
- package/dist/scripts/release-triwiki-first-runner-blackbox.js +5 -1
- package/dist/scripts/sks-3-1-5-directive-check-lib.js +1 -1
- package/dist/scripts/sks-401-all-feature-regression-blackbox.js +1 -1
- package/dist/scripts/update-concurrent-lock-check.js +1 -0
- package/dist/scripts/update-first-command-migration-check.js +4 -3
- package/package.json +13 -2
- package/schemas/mad-db/mad-db-capability.schema.json +92 -19
- package/schemas/update-migration.schema.json +13 -1
|
@@ -1,98 +1,178 @@
|
|
|
1
|
-
import { initProject } from '../init.js';
|
|
2
|
-
import { createMission, findLatestMission, setCurrent } from '../mission.js';
|
|
3
|
-
import { exists, sksRoot } from '../fsx.js';
|
|
4
1
|
import path from 'node:path';
|
|
5
|
-
import {
|
|
2
|
+
import { initProject } from '../init.js';
|
|
3
|
+
import { findLatestMission, setCurrent } from '../mission.js';
|
|
4
|
+
import { exists, readText, sksRoot } from '../fsx.js';
|
|
5
|
+
import { closeMadDbCycle, isMadDbCapabilityActive, MAD_DB_ACK, readMadDbCapability, resolveMadDbMissionId, revokeMadDbCapability } from '../mad-db/mad-db-capability.js';
|
|
6
|
+
import { closeMadDbRuntimeProfile, verifyReadOnlyRestored } from '../mad-db/mad-db-runtime-profile.js';
|
|
7
|
+
import { runMadDbCycle } from '../mad-db/mad-db-coordinator.js';
|
|
8
|
+
import { resolveMadDbTarget } from '../mad-db/mad-db-target.js';
|
|
9
|
+
import { quarantineStaleMadDbRuntimeProfiles } from '../mad-db/mad-db-recovery.js';
|
|
10
|
+
import { sha256 } from '../fsx.js';
|
|
6
11
|
export async function madDbCommand(args = []) {
|
|
7
12
|
const action = String(args[0] && !String(args[0]).startsWith('--') ? args[0] : 'status');
|
|
8
13
|
const rest = action === args[0] ? args.slice(1) : args;
|
|
9
14
|
const root = await sksRoot();
|
|
10
15
|
if (!(await exists(path.join(root, '.sneakoscope'))))
|
|
11
16
|
await initProject(root, {});
|
|
17
|
+
if (action === 'run')
|
|
18
|
+
return runMadDb(root, rest);
|
|
19
|
+
if (action === 'exec')
|
|
20
|
+
return execMadDb(root, rest);
|
|
21
|
+
if (action === 'apply-migration')
|
|
22
|
+
return applyMigrationMadDb(root, rest);
|
|
23
|
+
if (action === 'doctor')
|
|
24
|
+
return doctorMadDb(root, rest);
|
|
25
|
+
if (action === 'close')
|
|
26
|
+
return closeMadDb(root, rest);
|
|
12
27
|
if (action === 'enable')
|
|
13
28
|
return enableMadDb(root, rest);
|
|
14
29
|
if (action === 'revoke')
|
|
15
30
|
return revokeMadDb(root, rest);
|
|
16
31
|
if (action === 'status')
|
|
17
32
|
return statusMadDb(root, rest);
|
|
18
|
-
console.error('Usage: sks mad-db
|
|
33
|
+
console.error('Usage: sks mad-db run "<task-or-sql>" | exec --sql "<SQL>" | apply-migration --name <name> --file <sql-file> | doctor|status|close|revoke [--json]');
|
|
19
34
|
process.exitCode = 1;
|
|
20
35
|
}
|
|
36
|
+
async function runMadDb(root, args) {
|
|
37
|
+
const task = positionalText(args) || readOption(args, '--task', '');
|
|
38
|
+
const sql = readOption(args, '--sql', '');
|
|
39
|
+
const result = await runMadDbCycle({
|
|
40
|
+
root,
|
|
41
|
+
action: 'run',
|
|
42
|
+
task,
|
|
43
|
+
sql: sql || null,
|
|
44
|
+
verifySql: readOption(args, '--verify-sql', '') || null,
|
|
45
|
+
args
|
|
46
|
+
});
|
|
47
|
+
return printResult(result, args);
|
|
48
|
+
}
|
|
49
|
+
async function execMadDb(root, args) {
|
|
50
|
+
const sql = readOption(args, '--sql', '') || positionalText(args);
|
|
51
|
+
const result = await runMadDbCycle({
|
|
52
|
+
root,
|
|
53
|
+
action: 'exec',
|
|
54
|
+
task: sql || 'sks mad-db exec',
|
|
55
|
+
sql: sql || null,
|
|
56
|
+
verifySql: readOption(args, '--verify-sql', '') || null,
|
|
57
|
+
args
|
|
58
|
+
});
|
|
59
|
+
return printResult(result, args);
|
|
60
|
+
}
|
|
61
|
+
async function applyMigrationMadDb(root, args) {
|
|
62
|
+
const file = readOption(args, '--file', '');
|
|
63
|
+
const sql = readOption(args, '--sql', '') || (file ? await readText(path.resolve(file), '') : '');
|
|
64
|
+
const result = await runMadDbCycle({
|
|
65
|
+
root,
|
|
66
|
+
action: 'apply-migration',
|
|
67
|
+
task: `apply migration ${readOption(args, '--name', 'mad_db_migration')}`,
|
|
68
|
+
sql: sql || null,
|
|
69
|
+
migrationName: readOption(args, '--name', `mad_db_${Date.now()}`),
|
|
70
|
+
migrationFile: file || null,
|
|
71
|
+
verifySql: readOption(args, '--verify-sql', '') || null,
|
|
72
|
+
args
|
|
73
|
+
});
|
|
74
|
+
return printResult(result, args);
|
|
75
|
+
}
|
|
76
|
+
async function doctorMadDb(root, args) {
|
|
77
|
+
const target = await resolveMadDbTarget(root, { args });
|
|
78
|
+
const recovery = await quarantineStaleMadDbRuntimeProfiles(root);
|
|
79
|
+
const restoration = await verifyReadOnlyRestored(root, null);
|
|
80
|
+
const result = {
|
|
81
|
+
schema: 'sks.mad-db-doctor.v1',
|
|
82
|
+
ok: target.blockers.length === 0 && restoration.persistent_supabase_read_only,
|
|
83
|
+
target: { ...target, project_ref: target.project_ref ? `<hash:${target.project_ref_hash}>` : null },
|
|
84
|
+
stale_recovery: recovery,
|
|
85
|
+
read_only_restoration: restoration,
|
|
86
|
+
execute_sql_apply_migration_inventory_checked: false,
|
|
87
|
+
note: 'doctor does not open write transport; run/exec/apply-migration verifies tool inventory inside a bound cycle'
|
|
88
|
+
};
|
|
89
|
+
return printJsonOrText(result, args, result.ok ? 'MadDB doctor passed local checks.' : `MadDB doctor found blockers: ${[...target.blockers, ...restoration.blockers].join(', ')}`);
|
|
90
|
+
}
|
|
21
91
|
async function enableMadDb(root, args) {
|
|
22
92
|
const json = hasFlag(args, '--json');
|
|
23
93
|
const ack = readOption(args, '--ack', '');
|
|
24
94
|
if (ack !== MAD_DB_ACK) {
|
|
25
|
-
const result = { schema: 'sks.mad-db-command.
|
|
95
|
+
const result = { schema: 'sks.mad-db-command.v2', ok: false, action: 'enable', reason: 'deprecated_enable_no_capability', required_ack: MAD_DB_ACK, token_only: true };
|
|
26
96
|
if (json)
|
|
27
97
|
return console.log(JSON.stringify(result, null, 2));
|
|
28
|
-
console.error(`
|
|
98
|
+
console.error(`MadDB enable is deprecated and does not create a capability. Use sks mad-db run|exec|apply-migration for an executable cycle. Legacy ack was ${JSON.stringify(MAD_DB_ACK)}.`);
|
|
29
99
|
process.exitCode = 2;
|
|
30
100
|
return result;
|
|
31
101
|
}
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
ack,
|
|
41
|
-
cwd: process.cwd(),
|
|
42
|
-
ttlMs: Number(readOption(args, '--ttl-ms', String(2 * 60 * 60 * 1000)))
|
|
43
|
-
});
|
|
44
|
-
await setCurrent(root, {
|
|
45
|
-
mission_id: missionId,
|
|
46
|
-
route: 'MadDB',
|
|
47
|
-
route_command: '$MAD-DB',
|
|
48
|
-
mode: 'MADDB',
|
|
49
|
-
phase: 'MADDB_ONE_CYCLE_CAPABILITY_ACTIVE',
|
|
50
|
-
mad_db_active: true,
|
|
51
|
-
mad_db_cycle_id: capability.cycle_id,
|
|
52
|
-
mad_db_capability_file: 'mad-db-capability.json',
|
|
53
|
-
mad_db_ack_phrase: 'accepted',
|
|
54
|
-
stop_gate: 'mad-db-capability.json'
|
|
55
|
-
});
|
|
56
|
-
const result = { schema: 'sks.mad-db-command.v1', ok: true, action: 'enable', mission_id: missionId, capability };
|
|
102
|
+
const result = {
|
|
103
|
+
schema: 'sks.mad-db-command.v2',
|
|
104
|
+
ok: false,
|
|
105
|
+
action: 'enable',
|
|
106
|
+
reason: 'deprecated_enable_no_capability',
|
|
107
|
+
token_only: true,
|
|
108
|
+
executable_commands: ['sks mad-db run', 'sks mad-db exec', 'sks mad-db apply-migration']
|
|
109
|
+
};
|
|
57
110
|
if (json)
|
|
58
111
|
return console.log(JSON.stringify(result, null, 2));
|
|
59
|
-
console.
|
|
112
|
+
console.error('MadDB enable no longer creates a capability. Use sks mad-db run|exec|apply-migration to create the bound mission/profile/capability and execute SQL.');
|
|
113
|
+
process.exitCode = 2;
|
|
60
114
|
return result;
|
|
61
115
|
}
|
|
62
116
|
async function statusMadDb(root, args) {
|
|
63
|
-
const json = hasFlag(args, '--json');
|
|
64
117
|
const missionId = await resolveMadDbMissionId(root, {}, readOption(args, '--mission', 'latest'));
|
|
65
118
|
const capability = missionId ? await readMadDbCapability(root, missionId) : null;
|
|
66
119
|
const result = {
|
|
67
|
-
schema: 'sks.mad-db-
|
|
120
|
+
schema: 'sks.mad-db-status.v2',
|
|
68
121
|
ok: true,
|
|
69
122
|
action: 'status',
|
|
70
123
|
mission_id: missionId,
|
|
71
124
|
active: isMadDbCapabilityActive(capability),
|
|
72
|
-
capability
|
|
125
|
+
capability: capability ? redactCapability(capability) : null
|
|
73
126
|
};
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
127
|
+
return printJsonOrText(result, args, !missionId || !capability ? 'MadDB: no capability found.' : `MadDB: ${result.active ? 'active' : 'inactive'} for ${missionId}; status=${capability.status}; expires=${capability.expires_at}.`);
|
|
128
|
+
}
|
|
129
|
+
async function closeMadDb(root, args) {
|
|
130
|
+
const missionId = await resolveMadDbMissionId(root, {}, readOption(args, '--mission', 'latest')) || await findLatestMission(root);
|
|
131
|
+
const capability = missionId ? await readMadDbCapability(root, missionId) : null;
|
|
132
|
+
const restoration = missionId ? await closeMadDbRuntimeProfile({ root, missionId, reason: 'operator_close' }) : null;
|
|
133
|
+
const closed = missionId && capability ? await closeMadDbCycle(root, missionId, capability.cycle_id, 'operator_close') : null;
|
|
134
|
+
if (missionId)
|
|
135
|
+
await setCurrent(root, { mad_db_active: false, phase: 'MADDB_CLOSED' });
|
|
136
|
+
const result = { schema: 'sks.mad-db-close.v2', ok: Boolean(closed), action: 'close', mission_id: missionId, capability: closed ? redactCapability(closed) : null, read_only_restoration: restoration };
|
|
137
|
+
return printJsonOrText(result, args, closed ? `MadDB cycle closed for ${missionId}.` : 'MadDB: no capability to close.');
|
|
81
138
|
}
|
|
82
139
|
async function revokeMadDb(root, args) {
|
|
83
|
-
const json = hasFlag(args, '--json');
|
|
84
140
|
const missionId = await resolveMadDbMissionId(root, {}, readOption(args, '--mission', 'latest')) || await findLatestMission(root);
|
|
85
141
|
const revoked = missionId ? await revokeMadDbCapability(root, missionId, readOption(args, '--reason', 'operator_revoked')) : null;
|
|
142
|
+
const restoration = missionId ? await closeMadDbRuntimeProfile({ root, missionId, reason: 'operator_revoke' }) : null;
|
|
86
143
|
await setCurrent(root, { mad_db_active: false, phase: 'MADDB_REVOKED' });
|
|
87
|
-
const result = { schema: 'sks.mad-db-command.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
144
|
+
const result = { schema: 'sks.mad-db-command.v2', ok: Boolean(revoked), action: 'revoke', mission_id: missionId, capability: revoked ? redactCapability(revoked) : null, read_only_restoration: restoration };
|
|
145
|
+
return printJsonOrText(result, args, revoked ? `MadDB capability revoked for ${missionId}.` : 'MadDB: no capability to revoke.');
|
|
146
|
+
}
|
|
147
|
+
function printResult(result, args) {
|
|
148
|
+
if (hasFlag(args, '--json')) {
|
|
149
|
+
console.log(JSON.stringify(result, null, 2));
|
|
150
|
+
}
|
|
151
|
+
else if (result.ok) {
|
|
152
|
+
console.log(`MadDB complete: mission=${result.mission_id} cycle=${result.cycle_id} execution=${result.execution?.ok ? 'succeeded' : 'unknown'} verification=${result.read_back?.ok === true ? 'passed' : 'not-requested'} read-only-restored=${result.read_only_restoration?.ok === true}`);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
console.error(`MadDB failed: mission=${result.mission_id} blockers=${(result.blockers || []).join(', ') || 'unknown'} read-only-restored=${result.read_only_restoration?.ok === true}`);
|
|
156
|
+
process.exitCode = 1;
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
function printJsonOrText(result, args, text) {
|
|
161
|
+
if (hasFlag(args, '--json'))
|
|
162
|
+
console.log(JSON.stringify(result, null, 2));
|
|
92
163
|
else
|
|
93
|
-
console.log(
|
|
164
|
+
console.log(text);
|
|
165
|
+
if (result.ok === false)
|
|
166
|
+
process.exitCode = process.exitCode || 1;
|
|
94
167
|
return result;
|
|
95
168
|
}
|
|
169
|
+
function redactCapability(capability) {
|
|
170
|
+
return {
|
|
171
|
+
...capability,
|
|
172
|
+
project_ref: capability.project_ref ? `<hash:${sha256(capability.project_ref).slice(0, 16)}>` : null,
|
|
173
|
+
transport: capability.transport ? { ...capability.transport, server_url_redacted: capability.transport.server_url_redacted || '<redacted>' } : null
|
|
174
|
+
};
|
|
175
|
+
}
|
|
96
176
|
function hasFlag(args, flag) {
|
|
97
177
|
return args.includes(flag);
|
|
98
178
|
}
|
|
@@ -100,7 +180,22 @@ function readOption(args, name, fallback) {
|
|
|
100
180
|
const index = args.indexOf(name);
|
|
101
181
|
if (index >= 0 && args[index + 1] && !String(args[index + 1]).startsWith('--'))
|
|
102
182
|
return String(args[index + 1]);
|
|
103
|
-
const prefixed = args.find((arg) => String(arg).startsWith(name
|
|
183
|
+
const prefixed = args.find((arg) => String(arg).startsWith(`${name}=`));
|
|
104
184
|
return prefixed ? prefixed.slice(name.length + 1) : fallback;
|
|
105
185
|
}
|
|
186
|
+
function positionalText(args) {
|
|
187
|
+
const out = [];
|
|
188
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
189
|
+
const arg = args[index];
|
|
190
|
+
if (!arg)
|
|
191
|
+
continue;
|
|
192
|
+
if (arg.startsWith('--')) {
|
|
193
|
+
if (!arg.includes('=') && args[index + 1] && !String(args[index + 1]).startsWith('--'))
|
|
194
|
+
index += 1;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
out.push(arg);
|
|
198
|
+
}
|
|
199
|
+
return out.join(' ').trim();
|
|
200
|
+
}
|
|
106
201
|
//# sourceMappingURL=mad-db-command.js.map
|
|
@@ -19,7 +19,6 @@ import { repairCodexConfigEperm } from '../codex/codex-config-eperm-repair.js';
|
|
|
19
19
|
import { runCodexLaunchPreflight } from '../preflight/parallel-preflight-engine.js';
|
|
20
20
|
import { diffCodexAppUiSnapshots, writeCodexAppUiSnapshot } from '../codex-app/codex-app-ui-state-snapshot.js';
|
|
21
21
|
import { checkSksUpdateNotice } from '../update/update-notice.js';
|
|
22
|
-
import { createMadDbCapability, MAD_DB_ACK } from '../mad-db/mad-db-capability.js';
|
|
23
22
|
import { writeCodex0138CapabilityArtifacts } from '../codex-control/codex-0138-capability.js';
|
|
24
23
|
import { writeCodex0139CapabilityArtifacts } from '../codex-control/codex-0139-capability.js';
|
|
25
24
|
import { resolveCodexNativeInvocationPlan } from '../codex-native/codex-native-invocation-router.js';
|
|
@@ -100,7 +99,7 @@ export async function madHighCommand(args = [], deps = {}) {
|
|
|
100
99
|
}
|
|
101
100
|
return report;
|
|
102
101
|
}
|
|
103
|
-
const codexUpdate =
|
|
102
|
+
const codexUpdate = { status: 'deferred_background', reason: 'update_prompt_deferred_until_after_mad_ui' };
|
|
104
103
|
if (codexUpdate.status === 'failed' || codexUpdate.status === 'updated_not_reflected') {
|
|
105
104
|
console.error(`Codex CLI update failed: ${codexUpdate.error || 'updated version was not visible on PATH'}`);
|
|
106
105
|
process.exitCode = 1;
|
|
@@ -147,14 +146,15 @@ export async function madHighCommand(args = [], deps = {}) {
|
|
|
147
146
|
}
|
|
148
147
|
const lb = glmMadLaunch
|
|
149
148
|
? { status: 'skipped_glm_openrouter', ok: false, reason: 'glm_mad_uses_openrouter_directly' }
|
|
150
|
-
:
|
|
149
|
+
: { status: 'deferred_until_provider_route', ok: true, reason: 'codex_lb_setup_prompt_deferred_until_provider_route' };
|
|
151
150
|
if (!glmMadLaunch && lb.status === 'missing_api_key') {
|
|
152
151
|
process.exitCode = 1;
|
|
153
152
|
return;
|
|
154
153
|
}
|
|
155
154
|
const profile = buildMadHighLaunchProfileNoWrite();
|
|
156
155
|
const uiSnapshotId = Date.now().toString(36);
|
|
157
|
-
const
|
|
156
|
+
const strictUiSnapshot = process.env.SKS_MAD_STRICT_UI_SNAPSHOT === '1';
|
|
157
|
+
const beforeUi = strictUiSnapshot ? await writeCodexAppUiSnapshot(launchRoot, `mad-before-${uiSnapshotId}`).catch(() => null) : null;
|
|
158
158
|
// launchFast skips the redundant live-`codex exec` config probe (up to ~20s, run
|
|
159
159
|
// up to 3x via repair re-inspections): the real codex profile is exercised moments
|
|
160
160
|
// later when the Zellij session opens. All filesystem/permission/EPERM/symlink/ACL
|
|
@@ -202,64 +202,48 @@ export async function madHighCommand(args = [], deps = {}) {
|
|
|
202
202
|
process.exitCode = 1;
|
|
203
203
|
return glmRuntime;
|
|
204
204
|
}
|
|
205
|
-
|
|
206
|
-
? await createMadDbCapability(madLaunch.root, { missionId: madLaunch.mission_id, ack: madDbGrant.ack, cwd: process.cwd() })
|
|
207
|
-
: null;
|
|
208
|
-
if (madDbCapability) {
|
|
205
|
+
if (madDbGrant.requested) {
|
|
209
206
|
const grantReport = {
|
|
210
|
-
schema: 'sks.mad-sks-launch-grants.
|
|
207
|
+
schema: 'sks.mad-sks-launch-grants.v2',
|
|
211
208
|
generated_at: nowIso(),
|
|
212
209
|
mission_id: madLaunch.mission_id,
|
|
213
210
|
mad_sks_active: true,
|
|
214
|
-
mad_db_active:
|
|
215
|
-
mad_db_default_grant:
|
|
211
|
+
mad_db_active: false,
|
|
212
|
+
mad_db_default_grant: false,
|
|
216
213
|
mad_db_grant_source: madDbGrant.source,
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
mad_db_expires_at: madDbCapability.expires_at,
|
|
214
|
+
mad_db_requires_first_class_route: true,
|
|
215
|
+
mad_db_cli: 'sks mad-db run|exec|apply-migration',
|
|
216
|
+
mad_db_capability_file: null,
|
|
221
217
|
standalone_mad_db_enable_still_requires_ack: true
|
|
222
218
|
};
|
|
223
219
|
await writeJsonAtomic(path.join(madLaunch.dir, 'mad-sks-launch-grants.json'), grantReport);
|
|
224
|
-
await
|
|
225
|
-
mission_id: madLaunch.mission_id,
|
|
226
|
-
mad_db_active: true,
|
|
227
|
-
mad_db_cycle_id: madDbCapability.cycle_id,
|
|
228
|
-
mad_db_capability_file: 'mad-db-capability.json',
|
|
229
|
-
mad_db_break_glass: true,
|
|
230
|
-
mad_db_default_grant: madDbGrant.source === 'sks_mad_default',
|
|
231
|
-
mad_db_grant_source: madDbGrant.source,
|
|
232
|
-
mad_db_one_cycle_only: true,
|
|
233
|
-
mad_db_priority_override_active: true,
|
|
234
|
-
mad_sks_launch_grants_file: 'mad-sks-launch-grants.json'
|
|
235
|
-
});
|
|
236
|
-
await appendJsonlBounded(path.join(madLaunch.dir, 'events.jsonl'), { ts: nowIso(), type: 'mad_db.capability_created', grant_source: madDbGrant.source, cycle_id: madDbCapability.cycle_id, expires_at: madDbCapability.expires_at });
|
|
220
|
+
await appendJsonlBounded(path.join(madLaunch.dir, 'events.jsonl'), { ts: nowIso(), type: 'mad_db.first_class_route_required', grant_source: madDbGrant.source, cli: grantReport.mad_db_cli });
|
|
237
221
|
}
|
|
238
|
-
const updateNotice =
|
|
239
|
-
packageName: deps.packageName || 'sneakoscope',
|
|
240
|
-
currentVersion: deps.packageVersion || PACKAGE_VERSION,
|
|
241
|
-
missionDir: madLaunch.dir
|
|
242
|
-
}).catch((err) => ({
|
|
222
|
+
const updateNotice = {
|
|
243
223
|
schema: 'sks.update-notice.v1',
|
|
244
224
|
checked_at: nowIso(),
|
|
245
225
|
package_name: deps.packageName || 'sneakoscope',
|
|
246
226
|
current_version: deps.packageVersion || PACKAGE_VERSION,
|
|
247
227
|
latest_version: null,
|
|
248
228
|
update_available: false,
|
|
249
|
-
source: '
|
|
229
|
+
source: 'deferred_background',
|
|
250
230
|
cache_ttl_ms: 0,
|
|
251
|
-
message: 'SKS update notice
|
|
252
|
-
|
|
253
|
-
|
|
231
|
+
message: 'SKS update notice refresh deferred until after MAD UI launch.'
|
|
232
|
+
};
|
|
233
|
+
void checkSksUpdateNotice({
|
|
234
|
+
packageName: deps.packageName || 'sneakoscope',
|
|
235
|
+
currentVersion: deps.packageVersion || PACKAGE_VERSION,
|
|
236
|
+
missionDir: madLaunch.dir
|
|
237
|
+
}).then((notice) => appendJsonlBounded(path.join(madLaunch.dir, 'events.jsonl'), { ts: nowIso(), type: 'mad_sks.update_notice_refreshed_background', non_blocking: true, update_available: notice.update_available === true, source: notice.source })).catch((err) => appendJsonlBounded(path.join(madLaunch.dir, 'events.jsonl'), { ts: nowIso(), type: 'mad_sks.update_notice_background_failed', error: err?.message || String(err) }));
|
|
254
238
|
await appendJsonlBounded(path.join(madLaunch.dir, 'events.jsonl'), { ts: nowIso(), type: 'mad_sks.update_notice_checked', non_blocking: true, update_available: updateNotice.update_available === true, source: updateNotice.source });
|
|
255
239
|
console.log(`SKS MAD ready: ${glmRuntime?.profile?.profile_name || madHighProfileName()} | gate ${madLaunch.mission_id}`);
|
|
256
240
|
if (glmRuntime?.profile)
|
|
257
241
|
console.log(`GLM MAD launch active: ${glmRuntime.profile.model} via OpenRouter; GPT fallback blocked.`);
|
|
258
|
-
if (
|
|
259
|
-
console.log(
|
|
242
|
+
if (madDbGrant.requested)
|
|
243
|
+
console.log('MAD-DB flag observed; use the first-class route: sks mad-db run|exec|apply-migration.');
|
|
260
244
|
if (updateNotice.update_available === true)
|
|
261
245
|
console.log(`SKS update notice: ${updateNotice.latest_version} available (non-blocking).`);
|
|
262
|
-
console.log('Scoped high-power maintenance authority active; add explicit --allow-* flags for packages, services, network, browser/Computer Use, generated assets, file permissions, or system/admin scopes. MAD-DB
|
|
246
|
+
console.log('Scoped high-power maintenance authority active; add explicit --allow-* flags for packages, services, network, browser/Computer Use, generated assets, file permissions, or system/admin scopes. MAD-DB SQL-plane execution is not active in MAD-SKS; use the first-class MadDB route for DROP/TRUNCATE/all-row SQL-plane work.');
|
|
263
247
|
const launchLb = lb.status === 'present' ? { ...lb, status: 'configured' } : lb;
|
|
264
248
|
const madSksEnv = {
|
|
265
249
|
SKS_PROTECTED_CORE_POLICY: madLaunch.gate.protected_core_policy,
|
|
@@ -311,7 +295,7 @@ export async function madHighCommand(args = [], deps = {}) {
|
|
|
311
295
|
worker_panes_created: 0,
|
|
312
296
|
right_column_mode: 'spawn-on-first-worker'
|
|
313
297
|
});
|
|
314
|
-
const
|
|
298
|
+
const madNativeSwarmPromise = startMadNativeSwarm(madLaunch.root, madLaunch, args, launchProfile, {
|
|
315
299
|
env: {
|
|
316
300
|
...madSksEnv,
|
|
317
301
|
...(launch.session_name ? { SKS_ZELLIJ_SESSION_NAME: launch.session_name } : {})
|
|
@@ -320,7 +304,8 @@ export async function madHighCommand(args = [], deps = {}) {
|
|
|
320
304
|
zellijSessionName: launch.session_name || null,
|
|
321
305
|
workerPlacement: headlessZellij ? 'process' : shouldAutoAttachZellij(args) ? 'zellij-pane' : 'process',
|
|
322
306
|
zellijVisiblePaneCap: Number(process.env.SKS_ZELLIJ_VISIBLE_PANE_CAP || 8)
|
|
323
|
-
});
|
|
307
|
+
}).catch((err) => appendJsonlBounded(path.join(madLaunch.dir, 'events.jsonl'), { ts: nowIso(), type: 'mad_sks.native_swarm_background_failed', error: err?.message || String(err) }));
|
|
308
|
+
void madNativeSwarmPromise;
|
|
324
309
|
// The launcher only creates a detached background session. In an interactive
|
|
325
310
|
// terminal, immediately attach so the session actually opens for the user
|
|
326
311
|
// instead of leaving them to copy/paste the attach command by hand.
|
|
@@ -409,10 +394,11 @@ function buildGlmMadLaunchOpts(cleanArgs = [], opts = {}) {
|
|
|
409
394
|
}
|
|
410
395
|
export function resolveMadLaunchMadDbGrant(args = []) {
|
|
411
396
|
const list = (args || []).map((arg) => String(arg));
|
|
397
|
+
const requested = list.includes('--mad-db');
|
|
412
398
|
return {
|
|
413
|
-
enabled:
|
|
414
|
-
|
|
415
|
-
|
|
399
|
+
enabled: false,
|
|
400
|
+
requested,
|
|
401
|
+
source: requested ? 'mad_db_first_class_route_required' : 'not_requested',
|
|
416
402
|
one_cycle_only: true
|
|
417
403
|
};
|
|
418
404
|
}
|
|
@@ -646,16 +632,7 @@ async function activateMadZellijPermissionState(cwd = process.cwd(), args = [])
|
|
|
646
632
|
const has = (scope) => allowedScopes.has(scope);
|
|
647
633
|
const dbWriteAllowed = has('db_write');
|
|
648
634
|
const { id, dir } = await createMission(root, { mode: 'mad-sks', prompt: `${activatedBy} Zellij scoped high-power maintenance session` });
|
|
649
|
-
|
|
650
|
-
await writeCodex0139CapabilityArtifacts(root, { missionId: id }).catch(() => null);
|
|
651
|
-
const codexNativeInvocation = await resolveCodexNativeInvocationPlan({
|
|
652
|
-
root,
|
|
653
|
-
missionId: id,
|
|
654
|
-
route: '$MAD',
|
|
655
|
-
desiredCapability: 'hook-evidence'
|
|
656
|
-
}).catch(() => null);
|
|
657
|
-
if (codexNativeInvocation)
|
|
658
|
-
await writeJsonAtomic(path.join(dir, 'mad-codex-native-invocation.json'), codexNativeInvocation).catch(() => undefined);
|
|
635
|
+
void refreshMadNativeLaunchArtifacts(root, id, dir).catch((err) => appendJsonlBounded(path.join(dir, 'events.jsonl'), { ts: nowIso(), type: 'mad_sks.native_artifact_background_failed', error: err?.message || String(err) }));
|
|
659
636
|
const protectedCore = resolveProtectedCore({ packageRoot: packageRoot(), targetRoot: cwd });
|
|
660
637
|
// The interactive launch 'before' snapshot is only persisted (env + policy json)
|
|
661
638
|
// and is never compared against an 'after' snapshot during the session, so the
|
|
@@ -699,13 +676,13 @@ async function activateMadZellijPermissionState(cwd = process.cwd(), args = [])
|
|
|
699
676
|
protected_core_policy: protectedCorePolicyPath,
|
|
700
677
|
protected_core_before: protectedCoreBeforePath,
|
|
701
678
|
protected_core_digest: protectedCoreBefore.digest,
|
|
702
|
-
codex_native_invocation_plan:
|
|
703
|
-
selected_strategy:
|
|
704
|
-
hook_evidence_policy:
|
|
705
|
-
blockers:
|
|
706
|
-
warnings:
|
|
679
|
+
codex_native_invocation_plan: {
|
|
680
|
+
selected_strategy: 'message-role-fallback',
|
|
681
|
+
hook_evidence_policy: 'background-verification-do-not-count-until-refreshed',
|
|
682
|
+
blockers: [],
|
|
683
|
+
warnings: ['native_invocation_plan_deferred_until_after_ui'],
|
|
707
684
|
artifact_path: 'mad-codex-native-invocation.json'
|
|
708
|
-
}
|
|
685
|
+
},
|
|
709
686
|
activated_by: activatedBy,
|
|
710
687
|
cwd: path.resolve(cwd || process.cwd())
|
|
711
688
|
};
|
|
@@ -740,6 +717,19 @@ async function activateMadZellijPermissionState(cwd = process.cwd(), args = [])
|
|
|
740
717
|
});
|
|
741
718
|
return { mission_id: id, dir, gate, root };
|
|
742
719
|
}
|
|
720
|
+
async function refreshMadNativeLaunchArtifacts(root, missionId, dir) {
|
|
721
|
+
await writeCodex0138CapabilityArtifacts(root, { missionId }).catch(() => null);
|
|
722
|
+
await writeCodex0139CapabilityArtifacts(root, { missionId }).catch(() => null);
|
|
723
|
+
const codexNativeInvocation = await resolveCodexNativeInvocationPlan({
|
|
724
|
+
root,
|
|
725
|
+
missionId,
|
|
726
|
+
route: '$MAD',
|
|
727
|
+
desiredCapability: 'hook-evidence'
|
|
728
|
+
}).catch(() => null);
|
|
729
|
+
if (codexNativeInvocation)
|
|
730
|
+
await writeJsonAtomic(path.join(dir, 'mad-codex-native-invocation.json'), codexNativeInvocation).catch(() => undefined);
|
|
731
|
+
await appendJsonlBounded(path.join(dir, 'events.jsonl'), { ts: nowIso(), type: 'mad_sks.native_artifacts_refreshed_background', ok: Boolean(codexNativeInvocation) });
|
|
732
|
+
}
|
|
743
733
|
function baseMadLaunchOnlyFlags() {
|
|
744
734
|
return new Set([
|
|
745
735
|
'--mad',
|
package/dist/core/db-safety.js
CHANGED
|
@@ -3,9 +3,10 @@ import { exists, readJson, writeJsonAtomic, readText, nowIso, appendJsonlBounded
|
|
|
3
3
|
import { missionDir, setCurrent } from './mission.js';
|
|
4
4
|
import { evaluateMadSksPermissionGate, isMadSksRouteState } from './permission-gates.js';
|
|
5
5
|
import { resolveMadDbMutationPolicy } from './mad-db/mad-db-policy-resolver.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { appendMadDbLedgerEvent } from './mad-db/mad-db-ledger.js';
|
|
7
|
+
import { lifecycleHookFromUnknown } from './mad-db/mad-db-result-lifecycle.js';
|
|
8
|
+
import { extractCanonicalToolCallId, reserveMadDbOperation, transitionMadDbOperation } from './mad-db/mad-db-operation-store.js';
|
|
9
|
+
import { madDbOperationClassesFromClassification } from './mad-db/mad-db-policy.js';
|
|
9
10
|
export const DEFAULT_DB_SAFETY_POLICY = Object.freeze({
|
|
10
11
|
schema_version: 1,
|
|
11
12
|
mode: 'read_only_default',
|
|
@@ -511,19 +512,29 @@ export async function checkDbOperation(root, state, payload, { duringNoQuestion
|
|
|
511
512
|
const madDb = await resolveMadDbMutationPolicy(root, state, classification);
|
|
512
513
|
if (madDb.allowed === true && state?.mission_id) {
|
|
513
514
|
const madDbDecision = madDb;
|
|
514
|
-
const
|
|
515
|
-
const sqlHash =
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
515
|
+
const sqlText = classification.sql?.statements?.length ? String(classification.sql.statements.join('\n')) : null;
|
|
516
|
+
const sqlHash = sqlText ? sha256(sqlText) : null;
|
|
517
|
+
const toolCallId = extractCanonicalToolCallId(payload) || `payload-${sha256(JSON.stringify({ tool: classification.toolName || '', sqlHash, level: classification.level })).slice(0, 16)}`;
|
|
518
|
+
const operationClasses = madDbDecision.operation_classes?.length ? madDbDecision.operation_classes : madDbOperationClassesFromClassification(classification);
|
|
519
|
+
const reservation = await reserveMadDbOperation({
|
|
520
|
+
root,
|
|
521
|
+
missionId: String(state.mission_id),
|
|
522
|
+
capability: madDbDecision.capability,
|
|
523
|
+
toolCallId,
|
|
524
|
+
toolName: classification.toolName || 'unknown_database_tool',
|
|
525
|
+
sql: sqlText,
|
|
526
|
+
operationClasses
|
|
527
|
+
});
|
|
528
|
+
await transitionMadDbOperation({
|
|
529
|
+
root,
|
|
530
|
+
missionId: String(state.mission_id),
|
|
531
|
+
toolCallId,
|
|
532
|
+
state: 'started'
|
|
523
533
|
});
|
|
524
534
|
const lifecycleHook = {
|
|
525
535
|
mission_id: String(state.mission_id),
|
|
526
|
-
operation_id:
|
|
536
|
+
operation_id: reservation.operation.operation_id,
|
|
537
|
+
tool_call_id: toolCallId,
|
|
527
538
|
cycle_id: madDbDecision.cycle_id || null,
|
|
528
539
|
tool_name: classification.toolName || null,
|
|
529
540
|
sql_hash: sqlHash,
|
|
@@ -538,35 +549,22 @@ export async function checkDbOperation(root, state, payload, { duringNoQuestion
|
|
|
538
549
|
mad_db: {
|
|
539
550
|
active: true,
|
|
540
551
|
priority: 'highest',
|
|
552
|
+
capability_schema: 'sks.mad-db-capability.v2',
|
|
541
553
|
one_cycle_only: true,
|
|
542
554
|
cycle_id: madDbDecision.cycle_id,
|
|
543
555
|
capability_file: 'mad-db-capability.json',
|
|
544
|
-
|
|
545
|
-
operation_id:
|
|
556
|
+
status: reservation.capability.status,
|
|
557
|
+
operation_id: reservation.operation.operation_id,
|
|
558
|
+
tool_call_id: toolCallId,
|
|
559
|
+
tool_call_id_missing: extractCanonicalToolCallId(payload) === null,
|
|
546
560
|
lifecycle_result_pending: true,
|
|
547
561
|
ledger_result_hook: lifecycleHook,
|
|
548
|
-
|
|
549
|
-
|
|
562
|
+
operation_classes: operationClasses,
|
|
563
|
+
counters: reservation.capability.counters,
|
|
564
|
+
idempotent_reservation_reused: reservation.reused
|
|
550
565
|
}
|
|
551
566
|
};
|
|
552
|
-
await appendMadDbLedgerEvent(root, state.mission_id, { type: 'db_mutation.allowed', cycle_id: madDbDecision.cycle_id, mode: madDbDecision.mode, classification, operation_id:
|
|
553
|
-
await appendMadDbOperationLifecycle(root, state.mission_id, {
|
|
554
|
-
type: 'db_operation.allowed',
|
|
555
|
-
operationId,
|
|
556
|
-
cycleId: madDbDecision.cycle_id,
|
|
557
|
-
toolName: classification.toolName || null,
|
|
558
|
-
sqlHash,
|
|
559
|
-
destructive: classification.level === 'destructive',
|
|
560
|
-
resultStatus: 'unknown_pending_tool_result'
|
|
561
|
-
});
|
|
562
|
-
const updatedCapability = await recordMadDbOperation(root, state.mission_id, {
|
|
563
|
-
operationId,
|
|
564
|
-
...(classification.toolName ? { toolName: classification.toolName } : {}),
|
|
565
|
-
...(sqlHash ? { sqlHash } : {})
|
|
566
|
-
});
|
|
567
|
-
decision.mad_db.consumed = updatedCapability?.consumed === true;
|
|
568
|
-
decision.mad_db.operation_count = updatedCapability?.operation_count ?? decision.mad_db.operation_count;
|
|
569
|
-
await recordPendingMadDbLifecycleHook(root, state.mission_id, lifecycleHook);
|
|
567
|
+
await appendMadDbLedgerEvent(root, state.mission_id, { type: 'db_mutation.allowed', cycle_id: madDbDecision.cycle_id, mode: madDbDecision.mode, classification, operation_id: reservation.operation.operation_id, tool_call_id: toolCallId });
|
|
570
568
|
await appendJsonlBounded(path.join(missionDir(root, state.mission_id), 'db-safety.jsonl'), { ts: nowIso(), decision });
|
|
571
569
|
return decision;
|
|
572
570
|
}
|
|
@@ -605,8 +603,8 @@ export function dbBlockReason(decision) {
|
|
|
605
603
|
return [
|
|
606
604
|
'Sneakoscope Codex Database Safety Gate blocked this operation.',
|
|
607
605
|
`Reasons: ${(decision.reasons || []).join(', ') || 'unknown'}.`,
|
|
608
|
-
'
|
|
609
|
-
'Use read-only/project-scoped Supabase MCP URLs
|
|
606
|
+
'Default DB mode is read-only. Destructive SQL-plane operations require an explicit active MadDB v2 capability opened by $MAD-DB or sks mad-db run|exec|apply-migration.',
|
|
607
|
+
'Use read-only/project-scoped Supabase MCP URLs outside MadDB. Supabase project/account/billing/credential control-plane operations remain denied even in MadDB.'
|
|
610
608
|
].join(' ');
|
|
611
609
|
}
|
|
612
610
|
export async function scanDbSafety(root, opts = {}) {
|
|
@@ -3,7 +3,6 @@ import path from 'node:path';
|
|
|
3
3
|
import { MANAGED_ASSET_VERSION } from '../managed-assets/managed-assets-manifest.js';
|
|
4
4
|
import { PACKAGE_VERSION, packageRoot, sha256 } from '../fsx.js';
|
|
5
5
|
import { hashJson } from '../triwiki/triwiki-cache-key.js';
|
|
6
|
-
import { triWikiProofBankDir } from '../triwiki/triwiki-proof-bank.js';
|
|
7
6
|
export const DOCTOR_DIRTY_PLAN_SCHEMA = 'sks.doctor-dirty-plan.v2';
|
|
8
7
|
export function planDoctorDirtyRepair(root, phaseIds) {
|
|
9
8
|
const phases = phaseIds.map((id) => {
|
|
@@ -205,10 +204,16 @@ function proofExists(root, proofId) {
|
|
|
205
204
|
const transaction = path.join(root, '.sneakoscope', 'reports', 'doctor-fix-transaction.json');
|
|
206
205
|
if (fs.existsSync(transaction) && fs.readFileSync(transaction, 'utf8').includes(proofId))
|
|
207
206
|
return true;
|
|
208
|
-
const
|
|
209
|
-
if (!fs.existsSync(
|
|
207
|
+
const index = path.join(root, '.sneakoscope', 'cache', 'proof-index.json');
|
|
208
|
+
if (!fs.existsSync(index))
|
|
210
209
|
return false;
|
|
211
|
-
|
|
210
|
+
try {
|
|
211
|
+
const text = fs.readFileSync(index, 'utf8');
|
|
212
|
+
return text.includes(`"${proofId}"`) || text.includes(proofId);
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
212
217
|
}
|
|
213
218
|
function phaseRequiresPostcheck(id) {
|
|
214
219
|
return /zellij|context7|startup|supabase|native|secret/i.test(id);
|