sneakoscope 3.1.6 → 3.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -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/.sks-build-stamp.json +4 -4
- package/dist/bin/sks.js +1 -1
- package/dist/commands/codex-app.js +20 -2
- package/dist/commands/codex-native.js +18 -2
- package/dist/commands/doctor.js +106 -12
- package/dist/core/codex-app/codex-agent-role-sync.js +9 -5
- package/dist/core/codex-app/codex-init-deep.js +6 -2
- package/dist/core/codex-app/codex-skill-sync.js +80 -152
- package/dist/core/codex-control/codex-0138-capability.js +5 -2
- package/dist/core/codex-native/codex-native-feature-broker.js +74 -6
- package/dist/core/codex-native/codex-native-pattern-analysis.js +14 -2
- package/dist/core/codex-native/codex-native-reference-cache.js +98 -0
- package/dist/core/codex-native/codex-native-reference-source.js +50 -11
- package/dist/core/codex-native/codex-native-repair-transaction.js +150 -0
- package/dist/core/codex-native/core-skill-integrity.js +89 -0
- package/dist/core/codex-native/core-skill-manifest.js +156 -0
- package/dist/core/codex-native/native-capability-postcheck.js +35 -0
- package/dist/core/codex-native/native-capability-repair-matrix.js +210 -0
- package/dist/core/codex-native/native-capability-repair.js +47 -0
- package/dist/core/codex-native/native-media-computer-repair.js +5 -0
- package/dist/core/codex-native/project-skill-dedupe.js +109 -0
- package/dist/core/codex-native/skill-name-canonicalizer.js +21 -0
- package/dist/core/codex-native/skill-registry-ledger.js +85 -0
- package/dist/core/codex-plugins/codex-plugin-json.js +5 -2
- package/dist/core/commands/basic-cli.js +15 -9
- package/dist/core/commands/mad-sks-command.js +16 -0
- package/dist/core/config/config-migration-journal.js +27 -0
- package/dist/core/config/managed-config-merge.js +105 -0
- package/dist/core/config/secret-preservation.js +169 -0
- package/dist/core/config/supabase-secret-preservation.js +29 -0
- package/dist/core/doctor/doctor-native-capability-repair.js +48 -0
- package/dist/core/fsx.js +1 -1
- package/dist/core/init.js +5 -1
- package/dist/core/loops/loop-planner.js +1 -1
- package/dist/core/loops/loop-worker-prompts.js +2 -0
- package/dist/core/loops/loop-worker-runtime.js +8 -1
- package/dist/core/version.js +1 -1
- package/dist/scripts/codex-native-runtime-e2e-fixture.js +75 -0
- package/dist/scripts/loop-worker-fixture-child.js +2 -1
- package/dist/scripts/sizecheck.js +8 -2
- package/dist/scripts/sks-3-1-5-directive-check-lib.js +1 -1
- package/dist/scripts/sks-3-1-6-directive-check-lib.js +2 -2
- package/dist/scripts/sks-3-1-7-directive-check-lib.js +58 -0
- package/dist/scripts/sks-3-1-8-check-lib.js +30 -0
- package/package.json +39 -2
package/README.md
CHANGED
|
@@ -35,7 +35,14 @@ Set up this agent project with Sneakoscope Codex. Use [[mandarange/Sneakoscope-C
|
|
|
35
35
|
|
|
36
36
|
## 🚀 Current Release
|
|
37
37
|
|
|
38
|
-
SKS **3.1.
|
|
38
|
+
SKS **3.1.8** hardens update/setup/doctor safety around four operator-facing failure modes: immutable core skills, duplicate project skills, real native capability repair status, and Supabase/secret preservation.
|
|
39
|
+
|
|
40
|
+
What changed in 3.1.8:
|
|
41
|
+
|
|
42
|
+
- **Core SKS skills are content-addressed and immutable.** The eight built-in route skills now have a manifest and no-drift gates; setup/update/doctor may install missing managed copies or restore corrupted managed copies, but they do not overwrite user-authored collisions.
|
|
43
|
+
- **Duplicate skills are detected and repaired safely.** Canonical skill names collapse variants such as `Loop`, `loop`, and `loop/SKILL.md`; SKS-managed duplicates can be quarantined automatically, while user-authored duplicates require explicit confirmation.
|
|
44
|
+
- **`sks doctor --fix` reports native capability truthfully.** Image generation, image follow-up edit paths, Computer Use, Chrome/web review, app screenshots, app handoff, and image path exposure now run through a repair matrix and postcheck instead of capability assumptions.
|
|
45
|
+
- **Supabase keys survive setup/update/doctor.** Protected secret surfaces are fingerprinted before and after guarded operations; reports store only redacted previews and hashes, never raw values.
|
|
39
46
|
|
|
40
47
|
SKS 3.0.0 was the parallel-runtime stabilization release. The whole live-swarm experience — what you actually *see* while 5, 20, or 100 workers run — was rebuilt and proven end-to-end.
|
|
41
48
|
|
|
@@ -79,7 +86,7 @@ npm run runtime:ts-python-boundary
|
|
|
79
86
|
npm run codex-control:all-pipelines
|
|
80
87
|
```
|
|
81
88
|
|
|
82
|
-
|
|
89
|
+
Change-aware release checks live behind `npm run release:check`; publish-authorizing full DAG checks use `npm run release:check:full`. Detailed release history is in [CHANGELOG.md](CHANGELOG.md), and release readiness is tracked in [docs/release-readiness.md](docs/release-readiness.md).
|
|
83
90
|
|
|
84
91
|
## 🍥 Parallelism, UX, And Integrations
|
|
85
92
|
|
|
@@ -622,7 +629,7 @@ TriWiki is intentionally sparse: `sks wiki sweep` records demote, soft-forget, a
|
|
|
622
629
|
|
|
623
630
|
```sh
|
|
624
631
|
sks codex-native status --json
|
|
625
|
-
sks codex-native invocation-plan --route
|
|
632
|
+
sks codex-native invocation-plan --route Loop --capability agent-role --json
|
|
626
633
|
sks codex-native init-deep --apply --directory-local --json
|
|
627
634
|
```
|
|
628
635
|
|
|
@@ -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 3.1.
|
|
7
|
+
Some("--version") => println!("sks-rs 3.1.8"),
|
|
8
8
|
Some("compact-info") => {
|
|
9
9
|
let mut input = String::new();
|
|
10
10
|
let _ = io::stdin().read_to_string(&mut input);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "sks.dist-build-stamp.v1",
|
|
3
3
|
"package_name": "sneakoscope",
|
|
4
|
-
"package_version": "3.1.
|
|
5
|
-
"source_digest": "
|
|
6
|
-
"source_file_count":
|
|
7
|
-
"built_at_source_time":
|
|
4
|
+
"package_version": "3.1.8",
|
|
5
|
+
"source_digest": "94742dc3eb63f280df98aa286ac2a94a14fd140f27c89db85880e4f92c630454",
|
|
6
|
+
"source_file_count": 2602,
|
|
7
|
+
"built_at_source_time": 1781513577024
|
|
8
8
|
}
|
package/dist/bin/sks.js
CHANGED
|
@@ -9,12 +9,15 @@ import { syncCodexAgentRoles } from '../core/codex-app/codex-agent-role-sync.js'
|
|
|
9
9
|
import { runCodexInitDeep } from '../core/codex-app/codex-init-deep.js';
|
|
10
10
|
import { buildCodexHookLifecycle } from '../core/codex-app/codex-hook-lifecycle.js';
|
|
11
11
|
import { resolveCodexAppExecutionProfile } from '../core/codex-app/codex-app-execution-profile.js';
|
|
12
|
+
import { repairCodexNativeManagedAssets } from '../core/codex-native/codex-native-repair-transaction.js';
|
|
12
13
|
export async function run(_command, args = []) {
|
|
13
14
|
const action = args[0] || 'check';
|
|
14
15
|
if (action === 'remote-control' || action === 'remote')
|
|
15
16
|
return codexAppRemoteControlCommand(args.slice(1));
|
|
16
|
-
if (action === 'harness-matrix')
|
|
17
|
-
|
|
17
|
+
if (action === 'harness-matrix') {
|
|
18
|
+
const root = await sksRoot();
|
|
19
|
+
return printCodexAppResult(args, await maybeRepairThenReadOnlyHarness(args, root));
|
|
20
|
+
}
|
|
18
21
|
if (action === 'skill-sync')
|
|
19
22
|
return printCodexAppResult(args, await syncCodexSksSkills({ root: await sksRoot(), apply: flag(args, '--apply') || flag(args, '--fix') }));
|
|
20
23
|
if (action === 'agent-role-sync')
|
|
@@ -103,4 +106,19 @@ function printCodexAppResult(args = [], result) {
|
|
|
103
106
|
if (result?.ok === false)
|
|
104
107
|
process.exitCode = 1;
|
|
105
108
|
}
|
|
109
|
+
async function maybeRepairThenReadOnlyHarness(args = [], root) {
|
|
110
|
+
const wantsRepair = flag(args, '--fix') || flag(args, '--apply') || flag(args, '--repair-codex-native');
|
|
111
|
+
if (!wantsRepair)
|
|
112
|
+
return buildCodexAppHarnessMatrix({ root, mode: 'read-only' });
|
|
113
|
+
const repair = await repairCodexNativeManagedAssets({ root, requestedBy: 'manual', yes: flag(args, '--yes') });
|
|
114
|
+
const matrix = await buildCodexAppHarnessMatrix({ root, mode: 'read-only' });
|
|
115
|
+
return {
|
|
116
|
+
schema: 'sks.codex-app-harness-read-repair-split.v1',
|
|
117
|
+
ok: repair.ok && matrix?.ok !== false,
|
|
118
|
+
repair,
|
|
119
|
+
matrix,
|
|
120
|
+
blockers: [...(repair.blockers || []), ...(matrix?.blockers || [])],
|
|
121
|
+
warnings: [...(repair.warnings || []), 'harness_probe_after_explicit_repair_transaction']
|
|
122
|
+
};
|
|
123
|
+
}
|
|
106
124
|
//# sourceMappingURL=codex-app.js.map
|
|
@@ -12,14 +12,15 @@ import { resolveCodexNativeInvocationPlan } from '../core/codex-native/codex-nat
|
|
|
12
12
|
import { buildCodexNativeInteropPolicy } from '../core/codex-native/codex-native-interop-policy.js';
|
|
13
13
|
import { analyzeCodexNativeReferenceSource } from '../core/codex-native/codex-native-reference-evidence.js';
|
|
14
14
|
import { writeCodexNativePatternAnalysis } from '../core/codex-native/codex-native-pattern-analysis.js';
|
|
15
|
+
import { repairCodexNativeManagedAssets } from '../core/codex-native/codex-native-repair-transaction.js';
|
|
15
16
|
export async function run(_command, args = []) {
|
|
16
17
|
const root = await sksRoot();
|
|
17
18
|
const action = String(args[0] || 'status');
|
|
18
19
|
if (action === 'status' || action === 'check' || action === 'feature-broker' || action === 'feature-matrix') {
|
|
19
|
-
return printCodexNativeResult(args, await
|
|
20
|
+
return printCodexNativeResult(args, await maybeRepairThenReadOnlyMatrix(args, root, () => buildCodexNativeFeatureMatrix({ root, mode: 'read-only' })));
|
|
20
21
|
}
|
|
21
22
|
if (action === 'harness-matrix' || action === 'harness-compat') {
|
|
22
|
-
return printCodexNativeResult(args, await
|
|
23
|
+
return printCodexNativeResult(args, await maybeRepairThenReadOnlyMatrix(args, root, () => buildCodexAppHarnessMatrix({ root, mode: 'read-only' })));
|
|
23
24
|
}
|
|
24
25
|
if (action === 'skill-sync')
|
|
25
26
|
return printCodexNativeResult(args, await syncCodexSksSkills({ root, apply: flag(args, '--apply') || flag(args, '--fix') }));
|
|
@@ -46,6 +47,21 @@ export async function run(_command, args = []) {
|
|
|
46
47
|
console.error('Usage: sks codex-native status|feature-broker|harness-compat|skill-sync|agent-role-sync|init-deep|hook-lifecycle|execution-profile|interop-policy|reference-evidence|pattern-analysis|invocation-plan [--json]');
|
|
47
48
|
process.exitCode = 1;
|
|
48
49
|
}
|
|
50
|
+
async function maybeRepairThenReadOnlyMatrix(args = [], root, matrixFn) {
|
|
51
|
+
const wantsRepair = flag(args, '--fix') || flag(args, '--apply') || flag(args, '--repair-codex-native');
|
|
52
|
+
if (!wantsRepair)
|
|
53
|
+
return matrixFn();
|
|
54
|
+
const repair = await repairCodexNativeManagedAssets({ root, requestedBy: 'manual', yes: flag(args, '--yes') });
|
|
55
|
+
const matrix = await matrixFn();
|
|
56
|
+
return {
|
|
57
|
+
schema: 'sks.codex-native-read-repair-split.v1',
|
|
58
|
+
ok: repair.ok && matrix?.ok !== false,
|
|
59
|
+
repair,
|
|
60
|
+
matrix,
|
|
61
|
+
blockers: [...(repair.blockers || []), ...(matrix?.blockers || [])],
|
|
62
|
+
warnings: [...(repair.warnings || []), 'matrix_probe_after_explicit_repair_transaction']
|
|
63
|
+
};
|
|
64
|
+
}
|
|
49
65
|
function printCodexNativeResult(args = [], result) {
|
|
50
66
|
if (flag(args, '--json')) {
|
|
51
67
|
printJson(result);
|
package/dist/commands/doctor.js
CHANGED
|
@@ -26,6 +26,8 @@ import { writeMcpPluginInventoryArtifacts } from '../core/mcp/mcp-plugin-invento
|
|
|
26
26
|
import { runDoctorZellijRepair, doctorZellijRepairConsoleLine } from '../core/doctor/doctor-zellij-repair.js';
|
|
27
27
|
import { buildCodexAppHarnessMatrix } from '../core/codex-app/codex-app-harness-matrix.js';
|
|
28
28
|
import { buildCodexNativeFeatureMatrix } from '../core/codex-native/codex-native-feature-broker.js';
|
|
29
|
+
import { repairCodexNativeManagedAssets } from '../core/codex-native/codex-native-repair-transaction.js';
|
|
30
|
+
import { runDoctorNativeCapabilityRepair } from '../core/doctor/doctor-native-capability-repair.js';
|
|
29
31
|
export async function run(_command, args = []) {
|
|
30
32
|
const doctorFix = flag(args, '--fix');
|
|
31
33
|
let setupRepair = null;
|
|
@@ -68,6 +70,23 @@ export async function run(_command, args = []) {
|
|
|
68
70
|
};
|
|
69
71
|
}
|
|
70
72
|
const root = await projectRoot();
|
|
73
|
+
const doctorNativeCapabilityRepair = await runDoctorNativeCapabilityRepair({
|
|
74
|
+
root,
|
|
75
|
+
fix: doctorFix || flag(args, '--repair-native-capabilities'),
|
|
76
|
+
yes: flag(args, '--yes') || flag(args, '-y'),
|
|
77
|
+
flags: args.map((arg) => String(arg))
|
|
78
|
+
}).catch((err) => ({
|
|
79
|
+
schema: 'sks.doctor-native-capability-repair.v1',
|
|
80
|
+
ok: false,
|
|
81
|
+
root,
|
|
82
|
+
fix: doctorFix,
|
|
83
|
+
yes: flag(args, '--yes') || flag(args, '-y'),
|
|
84
|
+
core_skills: null,
|
|
85
|
+
skill_dedupe: null,
|
|
86
|
+
native_capabilities: null,
|
|
87
|
+
secret_preservation_guard: '.sneakoscope/reports/secret-preservation-guard.json',
|
|
88
|
+
blockers: [err?.message || String(err)]
|
|
89
|
+
}));
|
|
71
90
|
const codexBin = readOption(args, '--codex-bin', process.env.SKS_DOCTOR_CODEX_BIN || '');
|
|
72
91
|
const configProbeOpts = {
|
|
73
92
|
codexProbe: flag(args, '--fix') || flag(args, '--actual-codex') || Boolean(codexBin),
|
|
@@ -198,7 +217,23 @@ export async function run(_command, args = []) {
|
|
|
198
217
|
const mcpPluginInventory = pluginInventory?.report
|
|
199
218
|
? await writeMcpPluginInventoryArtifacts(root, { inventory: pluginInventory.report }).catch((err) => ({ error: err?.message || String(err), candidates: null }))
|
|
200
219
|
: null;
|
|
201
|
-
const
|
|
220
|
+
const repairCodexNative = doctorFix && flag(args, '--repair-codex-native');
|
|
221
|
+
const codexNativeRepair = repairCodexNative
|
|
222
|
+
? await repairCodexNativeManagedAssets({
|
|
223
|
+
root,
|
|
224
|
+
requestedBy: 'doctor --fix',
|
|
225
|
+
yes: flag(args, '--yes') || flag(args, '-y')
|
|
226
|
+
}).catch((err) => ({
|
|
227
|
+
schema: 'sks.codex-native-repair-transaction.v1',
|
|
228
|
+
ok: false,
|
|
229
|
+
generated_at: new Date().toISOString(),
|
|
230
|
+
requested_by: 'doctor --fix',
|
|
231
|
+
repaired: [],
|
|
232
|
+
blockers: [err?.message || String(err)],
|
|
233
|
+
warnings: []
|
|
234
|
+
}))
|
|
235
|
+
: null;
|
|
236
|
+
const codexAppHarnessMatrix = await buildCodexAppHarnessMatrix({ root, mode: 'read-only' }).catch((err) => ({
|
|
202
237
|
schema: 'sks.codex-app-harness-matrix.v1',
|
|
203
238
|
ok: false,
|
|
204
239
|
codex_cli: { available: false, version: null },
|
|
@@ -207,7 +242,7 @@ export async function run(_command, args = []) {
|
|
|
207
242
|
blockers: [err?.message || String(err)],
|
|
208
243
|
warnings: []
|
|
209
244
|
}));
|
|
210
|
-
const codexNativeFeatureMatrix = await buildCodexNativeFeatureMatrix({ root,
|
|
245
|
+
const codexNativeFeatureMatrix = await buildCodexNativeFeatureMatrix({ root, mode: 'read-only' }).catch((err) => ({
|
|
211
246
|
schema: 'sks.codex-native-feature-matrix.v1',
|
|
212
247
|
ok: false,
|
|
213
248
|
codex_cli: { available: Boolean(codex.bin), version: codex.version || null, bin: codex.bin || null },
|
|
@@ -288,7 +323,7 @@ export async function run(_command, args = []) {
|
|
|
288
323
|
ready,
|
|
289
324
|
sneakoscope: { ok: await exists(`${root}/.sneakoscope`) },
|
|
290
325
|
package: { bytes: pkgBytes, human: formatBytes(pkgBytes) },
|
|
291
|
-
repair: { sks_update: sksUpdate, setup: setupRepair, codex_config: configRepair, migration_journal: migrationJournal, global_sks_installs: globalSksInstallCleanup, agent_role_config: agentRoleConfigRepair, zellij: zellijRepair }
|
|
326
|
+
repair: { sks_update: sksUpdate, setup: setupRepair, codex_config: configRepair, migration_journal: migrationJournal, global_sks_installs: globalSksInstallCleanup, agent_role_config: agentRoleConfigRepair, zellij: zellijRepair, codex_native: codexNativeRepair, doctor_native_capability: doctorNativeCapabilityRepair }
|
|
292
327
|
};
|
|
293
328
|
if (flag(args, '--json')) {
|
|
294
329
|
printJson(result);
|
|
@@ -324,8 +359,32 @@ export async function run(_command, args = []) {
|
|
|
324
359
|
console.log(` Loop Mesh: ${runtimeReadiness.loop_mesh}`);
|
|
325
360
|
console.log(` QA Visual: ${runtimeReadiness.qa_visual}`);
|
|
326
361
|
console.log(` Research Sources: ${runtimeReadiness.research_sources}`);
|
|
327
|
-
|
|
328
|
-
|
|
362
|
+
console.log(` Image Follow-up: ${runtimeReadiness.image_followup}`);
|
|
363
|
+
for (const note of runtimeReadiness.notes)
|
|
364
|
+
console.log(` ${note}`);
|
|
365
|
+
if (runtimeReadiness.repair_actions.length) {
|
|
366
|
+
console.log('Repair actions:');
|
|
367
|
+
for (const action of runtimeReadiness.repair_actions)
|
|
368
|
+
console.log(` - ${action}`);
|
|
369
|
+
}
|
|
370
|
+
const nativeCapabilityRows = Array.isArray(doctorNativeCapabilityRepair?.native_capabilities?.capabilities)
|
|
371
|
+
? doctorNativeCapabilityRepair.native_capabilities.capabilities
|
|
372
|
+
: [];
|
|
373
|
+
console.log('SKS Native Capabilities:');
|
|
374
|
+
console.log(` image generation: ${nativeCapabilityStatus(nativeCapabilityRows, 'image_generation', 'repair_required')}`);
|
|
375
|
+
console.log(` image follow-up edit: ${nativeCapabilityStatus(nativeCapabilityRows, 'image_followup_edit', 'degraded')}`);
|
|
376
|
+
console.log(` computer use: ${nativeCapabilityStatus(nativeCapabilityRows, 'computer_use', 'manual_required')}`);
|
|
377
|
+
console.log(` Chrome/web review: ${nativeCapabilityStatus(nativeCapabilityRows, 'chrome_web_review', 'manual_required')}`);
|
|
378
|
+
console.log(` app screenshot: ${nativeCapabilityStatus(nativeCapabilityRows, 'codex_app_screenshot', 'degraded')}`);
|
|
379
|
+
console.log(` app handoff: ${nativeCapabilityStatus(nativeCapabilityRows, 'app_handoff', 'unavailable')}`);
|
|
380
|
+
console.log(` image path exposure: ${nativeCapabilityStatus(nativeCapabilityRows, 'image_path_exposure', 'fallback')}`);
|
|
381
|
+
console.log('SKS Skills:');
|
|
382
|
+
console.log(` core skills: ${doctorSkillStatus(doctorNativeCapabilityRepair?.core_skills)}`);
|
|
383
|
+
console.log(` duplicate project skills: ${doctorDedupeStatus(doctorNativeCapabilityRepair?.skill_dedupe)}`);
|
|
384
|
+
console.log('Secret preservation:');
|
|
385
|
+
console.log(` Supabase keys: ${doctorNativeCapabilityRepair?.ok === false && String((doctorNativeCapabilityRepair?.blockers || []).join(' ')).includes('secret_preservation_failed') ? 'blocked' : 'preserved'}`);
|
|
386
|
+
console.log(' secret values: redacted');
|
|
387
|
+
console.log(` migration journal: ${doctorNativeCapabilityRepair?.secret_preservation_guard || '.sneakoscope/reports/secret-preservation-guard.json'}`);
|
|
329
388
|
console.log('Codex App Harness:');
|
|
330
389
|
console.log(` plugins: ${codexAppHarnessMatrix.app_features?.plugin_json ? 'ok' : 'degraded'}`);
|
|
331
390
|
console.log(` hook approval: ${codexAppHarnessMatrix.app_features?.hook_approval_state_detectable ? 'ok' : 'unknown'}`);
|
|
@@ -424,14 +483,14 @@ function buildRuntimeReadiness(zellijReadiness, matrix) {
|
|
|
424
483
|
? 'ok'
|
|
425
484
|
: matrix?.codex_cli?.available ? 'degraded' : 'blocked';
|
|
426
485
|
const repairActions = [];
|
|
427
|
-
if (zellijStatus
|
|
428
|
-
repairActions.push('sks doctor --fix --yes');
|
|
486
|
+
if (zellijStatus !== 'ok') {
|
|
487
|
+
repairActions.push('Zellij: sks doctor --fix --yes');
|
|
488
|
+
repairActions.push('Homebrew + Zellij: sks doctor --fix --install-homebrew --yes');
|
|
489
|
+
}
|
|
429
490
|
if (codexNative !== 'ok')
|
|
430
|
-
repairActions.push('sks doctor --fix --repair-codex-native --yes');
|
|
491
|
+
repairActions.push('Codex Native managed assets: sks doctor --fix --repair-codex-native --yes');
|
|
431
492
|
if (matrix?.features?.project_memory?.ok !== true)
|
|
432
|
-
repairActions.push('sks codex-native init-deep --apply --directory-local');
|
|
433
|
-
if (hookPolicy !== 'approved-only')
|
|
434
|
-
repairActions.push('hook-derived evidence will not count until Codex hook approval is approved');
|
|
493
|
+
repairActions.push('Project memory: sks codex-native init-deep --apply --directory-local');
|
|
435
494
|
return {
|
|
436
495
|
schema: 'sks.runtime-readiness-story.v1',
|
|
437
496
|
zellij: zellijStatus,
|
|
@@ -439,6 +498,7 @@ function buildRuntimeReadiness(zellijReadiness, matrix) {
|
|
|
439
498
|
loop_mesh: agentStrategy === 'agent_type' ? 'ok' : 'fallback',
|
|
440
499
|
qa_visual: defaults.qa_visual_review_strategy || 'blocked',
|
|
441
500
|
research_sources: defaults.research_source_strategy || 'local-files',
|
|
501
|
+
image_followup: defaults.image_followup_strategy || 'blocked',
|
|
442
502
|
hook_evidence_policy: hookPolicy,
|
|
443
503
|
agent_role_strategy: agentStrategy,
|
|
444
504
|
notes: [
|
|
@@ -446,9 +506,43 @@ function buildRuntimeReadiness(zellijReadiness, matrix) {
|
|
|
446
506
|
...(hookPolicy !== 'approved-only' ? ['hook-derived evidence will not count'] : []),
|
|
447
507
|
...(agentStrategy !== 'agent_type' ? ['message-role fallback active'] : [])
|
|
448
508
|
],
|
|
449
|
-
repair_actions: repairActions
|
|
509
|
+
repair_actions: [...new Set(repairActions)]
|
|
450
510
|
};
|
|
451
511
|
}
|
|
512
|
+
function nativeCapabilityStatus(rows, id, fallback) {
|
|
513
|
+
const row = rows.find((entry) => entry?.id === id);
|
|
514
|
+
if (!row)
|
|
515
|
+
return fallback;
|
|
516
|
+
if (row.after === 'verified' || row.before === 'verified')
|
|
517
|
+
return 'verified';
|
|
518
|
+
if (row.repairability === 'manual-required')
|
|
519
|
+
return 'manual_required';
|
|
520
|
+
if (row.before === 'degraded' || row.after === 'degraded')
|
|
521
|
+
return 'degraded';
|
|
522
|
+
if (row.repairability === 'doctor-fix')
|
|
523
|
+
return row.after === 'blocked' ? 'blocked' : 'repair_required';
|
|
524
|
+
if (row.repairability === 'unavailable')
|
|
525
|
+
return 'unavailable';
|
|
526
|
+
return fallback;
|
|
527
|
+
}
|
|
528
|
+
function doctorSkillStatus(coreSkills) {
|
|
529
|
+
if (!coreSkills)
|
|
530
|
+
return 'drift_detected';
|
|
531
|
+
if (Array.isArray(coreSkills.restored) && coreSkills.restored.length)
|
|
532
|
+
return 'repaired';
|
|
533
|
+
if (Array.isArray(coreSkills.blockers) && coreSkills.blockers.length)
|
|
534
|
+
return 'drift_detected';
|
|
535
|
+
return 'current';
|
|
536
|
+
}
|
|
537
|
+
function doctorDedupeStatus(skillDedupe) {
|
|
538
|
+
if (!skillDedupe)
|
|
539
|
+
return 'manual_required';
|
|
540
|
+
if (Array.isArray(skillDedupe.actions) && skillDedupe.actions.some((action) => action.action === 'quarantined'))
|
|
541
|
+
return 'repaired';
|
|
542
|
+
if (Array.isArray(skillDedupe.blockers) && skillDedupe.blockers.length)
|
|
543
|
+
return 'manual_required';
|
|
544
|
+
return 'none';
|
|
545
|
+
}
|
|
452
546
|
// Assemble the explicit Zellij readiness block for `doctor --json` from the
|
|
453
547
|
// capability probe + readiness matrix. Proof statuses are availability-derived:
|
|
454
548
|
// `verified` is reserved for a real environment run (SKS_REQUIRE_ZELLIJ=1 gates);
|
|
@@ -56,7 +56,7 @@ export async function syncCodexAgentRoles(input) {
|
|
|
56
56
|
for (const role of DIRECTIVE_ROLES) {
|
|
57
57
|
const file = path.join(targetDir, `${role}.toml`);
|
|
58
58
|
const current = await fs.readFile(file, 'utf8').catch(() => '');
|
|
59
|
-
if (current && !current.includes('SKS managed 3.1.4 directive role') && !current.includes('SKS managed 3.1.5 directive role') && !current.includes('SKS managed 3.1.6 directive role') && !current.includes('SKS managed 3.1.6 bounded role'))
|
|
59
|
+
if (current && !current.includes('SKS managed 3.1.4 directive role') && !current.includes('SKS managed 3.1.5 directive role') && !current.includes('SKS managed 3.1.6 directive role') && !current.includes('SKS managed 3.1.6 bounded role') && !current.includes('SKS managed 3.1.7 directive role'))
|
|
60
60
|
continue;
|
|
61
61
|
await writeTextAtomic(file, roleToml(role, rolePayloads[role]));
|
|
62
62
|
created.push(file);
|
|
@@ -69,6 +69,9 @@ export async function syncCodexAgentRoles(input) {
|
|
|
69
69
|
apply: input.apply === true,
|
|
70
70
|
agent_type_supported: agentTypeProbe.supported,
|
|
71
71
|
fallback: agentTypeProbe.supported ? 'agent_type' : 'message-role',
|
|
72
|
+
strategy: agentTypeProbe.supported ? 'agent_type' : 'message-role',
|
|
73
|
+
probe_artifact_path: '.sneakoscope/reports/codex-agent-type-probe.json',
|
|
74
|
+
clobbered_user_roles: false,
|
|
72
75
|
codex_home: codexHome,
|
|
73
76
|
directive_roles: DIRECTIVE_ROLES,
|
|
74
77
|
role_payloads: rolePayloads,
|
|
@@ -86,21 +89,22 @@ function roleToml(role, payload) {
|
|
|
86
89
|
: `message_role_prefix = "${escapeToml(payload?.message_role_prefix || `Role: ${role}.`)}"`;
|
|
87
90
|
return [
|
|
88
91
|
`name = "${role}"`,
|
|
89
|
-
`description = "SKS managed 3.1.
|
|
92
|
+
`description = "SKS managed 3.1.7 directive role: ${role}"`,
|
|
90
93
|
strategyLine,
|
|
91
94
|
'model_reasoning_effort = "medium"',
|
|
92
95
|
role.includes('implementer') ? 'sandbox_mode = "workspace-write"' : 'sandbox_mode = "read-only"',
|
|
93
96
|
'approval_policy = "never"',
|
|
94
97
|
'developer_instructions = """',
|
|
95
|
-
`You are ${role}. SKS managed 3.1.
|
|
98
|
+
`You are ${role}. SKS managed 3.1.7 directive role with bounded ownership.`,
|
|
96
99
|
'Bounded ownership: use only the assigned owner files/directories and treat memory as guidance, not permission.',
|
|
97
100
|
role.includes('implementer') ? 'Maker/checker separation: implementer may patch only owner scope and cannot self-approve.' : 'Maker/checker separation: checker is read-only and must reject missing gates or missing proof artifacts.',
|
|
101
|
+
role.includes('implementer') ? 'Allowed sandbox: workspace-write only within assigned owner scope.' : 'Allowed sandbox: read-only; checker roles cannot mutate.',
|
|
98
102
|
role.includes('release') ? 'Release verifier: verify version truth, release DAG coverage, package scripts, packlist, and changelog evidence.' : '',
|
|
99
103
|
role.includes('zellij') ? 'UI/Zellij verifier: inspect readiness status, headless fallback, repair_required, pane proof, and slot telemetry without mutating unrelated UI state.' : '',
|
|
100
104
|
role.includes('codex') ? 'Codex native verifier: inspect hook approval, agent_type, skill sync, plugin inventory, MCP candidates, and invocation plan artifacts.' : '',
|
|
101
|
-
'Side
|
|
105
|
+
'Side-effect restrictions: no destructive shell, package publish, global config mutation, database mutation, or external service write unless the sealed route contract explicitly allows it.',
|
|
102
106
|
'Required proof artifacts: cite concrete repo paths, command outputs, and route-local JSON proof before claiming completion.',
|
|
103
|
-
'Final arbiter: parent integration owns final acceptance; this role supplies evidence and cannot override missing gates.',
|
|
107
|
+
'Final arbiter constraints: parent integration owns final acceptance; this role supplies evidence and cannot override missing gates.',
|
|
104
108
|
`Execution role strategy: ${payload?.strategy || 'message-role'}. Probe: ${payload?.probe_artifact_path || '.sneakoscope/reports/codex-agent-type-probe.json'}.`,
|
|
105
109
|
'"""',
|
|
106
110
|
''
|
|
@@ -28,7 +28,7 @@ export async function runCodexInitDeep(input = {}) {
|
|
|
28
28
|
}
|
|
29
29
|
if (existing.trim()) {
|
|
30
30
|
const beforeHash = hashText(existing);
|
|
31
|
-
const backup = `${agentsPath}.sks-backup-${beforeHash.slice(0, 12)}
|
|
31
|
+
const backup = `${agentsPath}.sks-backup-${Date.now()}-${beforeHash.slice(0, 12)}`;
|
|
32
32
|
await fs.copyFile(agentsPath, backup);
|
|
33
33
|
directoryLocalAgents.backup_paths.push(path.relative(root, backup));
|
|
34
34
|
directoryLocalAgents.backups_created += 1;
|
|
@@ -83,9 +83,10 @@ async function pruneBackups(root, agentsPath, keep) {
|
|
|
83
83
|
return [];
|
|
84
84
|
const dir = path.dirname(agentsPath);
|
|
85
85
|
const base = path.basename(agentsPath);
|
|
86
|
+
const backupPattern = new RegExp(`^${escapeRegExp(base)}\\.sks-backup-\\d{13}-[0-9a-f]{8,12}$`);
|
|
86
87
|
const rows = await fs.readdir(dir).catch(() => []);
|
|
87
88
|
const backups = rows
|
|
88
|
-
.filter((name) =>
|
|
89
|
+
.filter((name) => backupPattern.test(name))
|
|
89
90
|
.map((name) => path.join(dir, name))
|
|
90
91
|
.sort();
|
|
91
92
|
const remove = backups.slice(0, Math.max(0, backups.length - keep));
|
|
@@ -99,6 +100,9 @@ async function pruneBackups(root, agentsPath, keep) {
|
|
|
99
100
|
await guardedRm(guard, file, { force: true }).catch(() => undefined);
|
|
100
101
|
return remove;
|
|
101
102
|
}
|
|
103
|
+
function escapeRegExp(value) {
|
|
104
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
105
|
+
}
|
|
102
106
|
function hashText(text) {
|
|
103
107
|
let hash = 2166136261;
|
|
104
108
|
for (let index = 0; index < text.length; index += 1) {
|