sneakoscope 10.5.3 → 10.5.5
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 +6 -1
- package/config/skills-hash-ledger.v1.json +1 -0
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/commands/bridge.js +8 -3
- package/dist/commands/doctor-console.js +6 -0
- package/dist/commands/doctor.js +30 -2
- package/dist/config/skills-manifest.json +3 -2
- package/dist/core/agent-guidance/harness-maintenance.js +185 -0
- package/dist/core/agent-guidance/official-guidance-client.js +82 -0
- package/dist/core/agents/native-worker-backend-router.js +20 -12
- package/dist/core/codex/deprecated-config.js +255 -0
- package/dist/core/codex-lb/desktop-controller-v3/openrouter-only-commands.js +71 -7
- package/dist/core/codex-lb/desktop-controller-v3.js +1 -1
- package/dist/core/codex-native/core-skill-manifest.js +5 -5
- package/dist/core/commands/align-command.js +13 -4
- package/dist/core/decisions/child-model-choice.js +2 -1
- package/dist/core/decisions/cli.js +9 -2
- package/dist/core/doctor/codex-config-syntax-repair.js +43 -19
- package/dist/core/doctor/doctor-codex-startup-repair.js +0 -8
- package/dist/core/doctor/supabase-mcp-repair.js +56 -38
- package/dist/core/hooks-runtime/hook-context.js +4 -4
- package/dist/core/hooks-runtime/jev-spawn-routing.js +8 -8
- package/dist/core/hooks-runtime/spawn-role-pin-heal.js +1 -1
- package/dist/core/hooks-runtime/subagent-context.js +3 -3
- package/dist/core/hooks-runtime/subagent-spawn-policy.js +18 -11
- package/dist/core/hooks-runtime.js +1 -1
- package/dist/core/init.js +18 -51
- package/dist/core/routes.js +3 -3
- package/dist/core/subagents/child-model-allowlist.js +107 -8
- package/dist/core/subagents/child-model-plan.js +18 -27
- package/dist/core/subagents/model-tiers.js +45 -19
- package/dist/core/subagents/naruto-host-credentials.js +24 -5
- package/dist/core/subagents/official-subagent-config.js +6 -6
- package/dist/core/subagents/official-subagent-preparation.js +8 -6
- package/dist/core/subagents/official-subagent-prompt.js +11 -12
- package/dist/core/subagents/official-subagent-runner.js +3 -3
- package/dist/core/subagents/read-only-list-role.js +27 -6
- package/dist/core/subagents/role-model-preferences.js +21 -8
- package/dist/core/update/update-migration-state/simple-stages.js +9 -0
- package/dist/core/update/update-migration-state.js +6 -1
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/OpenRouterOnlyState.swift +20 -4
- package/dist/native/sks-menubar/Sources/SubagentModelsModels.swift +66 -11
- package/dist/native/sks-menubar/Sources/SubagentModelsViewController.swift +43 -22
- package/package.json +1 -1
- package/dist/core/doctor/stale-subagent-default.js +0 -30
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
Sneakoscope Codex (`sks`) is an open-source trust layer for Codex CLI and ChatGPT Desktop. It coordinates bounded AI coding agents, records machine-verifiable evidence, preserves project memory, and blocks release claims that are not supported by current tests or artifacts. Search visibility outcomes are measured separately; SKS does not promise rankings or traffic.
|
|
18
18
|
<!-- END SKS SEARCH VISIBILITY MARKETING -->
|
|
19
19
|
|
|
20
|
-
Current package: **SKS 10.5.
|
|
20
|
+
Current package: **SKS 10.5.5**. Install the latest stable release from npm.
|
|
21
21
|
|
|
22
22
|
Sneakoscope Codex (`sks`) is a local trust layer for Codex CLI and ChatGPT Desktop. It keeps agent work bounded, preserves project context, records machine-verifiable evidence, and prevents release claims that current tests or artifacts cannot support.
|
|
23
23
|
|
|
@@ -66,6 +66,11 @@ The installer resolves the latest npm release, installs `sks`, runs setup and Do
|
|
|
66
66
|
| Recover safely | Doctor and update flows report a concrete recovery action when a check needs attention. |
|
|
67
67
|
| Operate locally | The CLI works without a hosted control plane; macOS users can also use SKS Center. |
|
|
68
68
|
|
|
69
|
+
`$sks-align` refreshes the thin managed guidance against current official Codex
|
|
70
|
+
references and rebuilds TriWiki. Update and user-run `sks doctor --fix` share
|
|
71
|
+
that maintenance and repair known ignored configuration settings. User text
|
|
72
|
+
and model choices are preserved. See [harness maintenance](docs/align-modernization.md).
|
|
73
|
+
|
|
69
74
|
## Everyday commands
|
|
70
75
|
|
|
71
76
|
Inside a Codex conversation:
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
{
|
|
16
16
|
"canonical_name": "sks-align",
|
|
17
17
|
"trusted_sha256": [
|
|
18
|
+
"c3073b4a10203e642dd1236902b01772ecff6a3a7464cdecde0aad21e3c12b80",
|
|
18
19
|
"9eef36214be7e07a963eb36bb1df2c025cd0578b7419ddf4fd307081a2b62093",
|
|
19
20
|
"b9db40d6e1dd2fc6e4665a2b30738d370da955cd4d6e86c88bd85059c7faa08c",
|
|
20
21
|
"c485f39d4873adb9793672f7dcf4e956595ffb9dcbb032b3ffb0515b5857d31d",
|
package/dist/commands/bridge.js
CHANGED
|
@@ -40,7 +40,8 @@ export function usage(command = 'bridge') {
|
|
|
40
40
|
'',
|
|
41
41
|
'Provider secrets are accepted only through --api-key-stdin. Readiness changes the exit code only with --strict or --require-ready.',
|
|
42
42
|
'OpenRouter Only Mode and Codex-LB authentication priority are mutually exclusive; turning one on turns the other off.',
|
|
43
|
-
'subagent-models set reads {"subagent_models":[{"model","criteria","reasoning_effort","default"}]} (max 16) from stdin.'
|
|
43
|
+
'subagent-models set reads {"profile":"codex_lb|openai|openrouter_only","subagent_models":[{"model","criteria","reasoning_effort","default"}]} (max 16) from stdin.',
|
|
44
|
+
'The profile must match the current connection. Omitting profile preserves the legacy OpenRouter-list staging behavior.'
|
|
44
45
|
].join('\n');
|
|
45
46
|
}
|
|
46
47
|
export async function run(_command, args = []) {
|
|
@@ -152,7 +153,7 @@ async function parseInvocation(args, io) {
|
|
|
152
153
|
...base,
|
|
153
154
|
request: {
|
|
154
155
|
operation: 'subagent-models.set',
|
|
155
|
-
|
|
156
|
+
...subagentModelsFromStdin(await io.readStdin()),
|
|
156
157
|
no_restart: parsed.flags.has('--no-restart')
|
|
157
158
|
},
|
|
158
159
|
label: 'Subagent model list update'
|
|
@@ -376,7 +377,11 @@ function subagentModelsFromStdin(text) {
|
|
|
376
377
|
: undefined;
|
|
377
378
|
if (!Array.isArray(models))
|
|
378
379
|
throw new BridgeCliError('bridge_subagent_models_stdin_invalid', 'retry_with_stdin');
|
|
379
|
-
|
|
380
|
+
const profile = parsed.profile;
|
|
381
|
+
if (profile !== undefined && profile !== 'openrouter_only' && profile !== 'codex_lb' && profile !== 'openai') {
|
|
382
|
+
throw new BridgeCliError('bridge_subagent_models_profile_invalid', 'retry_with_stdin');
|
|
383
|
+
}
|
|
384
|
+
return { subagent_models: models, ...(profile === undefined ? {} : { profile }) };
|
|
380
385
|
}
|
|
381
386
|
function rejectSecretArgv(args) {
|
|
382
387
|
for (const arg of args) {
|
|
@@ -84,6 +84,12 @@ export function renderDoctorConsoleReport(result, extras) {
|
|
|
84
84
|
for (const warning of codexConfigSyntaxRepair.warnings || [])
|
|
85
85
|
line(` warning: ${warning}`);
|
|
86
86
|
}
|
|
87
|
+
if (result.harness_maintenance) {
|
|
88
|
+
const guidance = result.harness_maintenance;
|
|
89
|
+
line(`Official harness guidance: ${guidance.guidance_status}${guidance.fetched_at ? ` (${guidance.fetched_at})` : ''}`);
|
|
90
|
+
for (const warning of guidance.warnings || [])
|
|
91
|
+
line(` warning: ${warning}`);
|
|
92
|
+
}
|
|
87
93
|
line(` codex doctor: ${formatCodexDoctorConsoleStatus(result.codex_doctor)}`);
|
|
88
94
|
line(`Rust acc.: ${rust.mode || (rust.available ? 'rust_accelerated' : 'js_fallback')} ${rust.version || rust.status || ''}`);
|
|
89
95
|
line(`Codex App: ${codexApp.skipped === true ? DOCTOR_CONSOLE_NOT_MEASURED : ready.codex_app_ready ? 'ok' : 'optional_missing'}`);
|
package/dist/commands/doctor.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os from 'node:os';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { projectRoot, exists, formatBytes, nowIso, writeJsonAtomic } from '../core/fsx.js';
|
|
3
|
+
import { projectRoot, exists, ensureDir, formatBytes, nowIso, writeJsonAtomic } from '../core/fsx.js';
|
|
4
4
|
import { flag } from '../cli/args.js';
|
|
5
5
|
import { printJson } from '../cli/output.js';
|
|
6
6
|
import { ui as cliUi } from '../cli/cli-theme.js';
|
|
@@ -27,6 +27,7 @@ import { detectImagegenCapability } from '../core/imagegen/imagegen-capability.j
|
|
|
27
27
|
import { formatHarnessConflictReport, scanHarnessConflicts } from '../core/harness-conflicts.js';
|
|
28
28
|
import { doctorArgWarnings as baseDoctorArgWarnings, doctorGlobalOnlySelection, doctorMenuBarInstallPolicy, doctorPhaseIdsForProfile, doctorProfileFromArgs, doctorProfileRequiresDesktopBridgeReadiness } from './doctor-profile.js';
|
|
29
29
|
import { renderDoctorConsoleReport } from './doctor-console.js';
|
|
30
|
+
import { isVerificationTestHarness } from '../core/verification-profile.js';
|
|
30
31
|
import { buildCodexAppUiDiagnosticFailure, buildRuntimeReadiness, captureCodexConfigSnapshot, deferredNativeRepair, fallbackCodexNativeFeatureMatrix, formatCodexDoctorConsoleStatus, installScopeFromArgs, isMigrationUserOwnedProjectConfigBlocker, mergeObservedCodexStartupWarnings, readOption, rebootstrapSksMenuBarLaunchdForDoctorFix, sksMenuBarRunningVersionConsoleLines, writeFixMigrationJournal, writeJsonReportFile } from './doctor-helpers.js';
|
|
31
32
|
export { doctorMenuBarInstallPolicy, doctorProfileFromArgs, doctorProfileRequiresDesktopBridgeReadiness } from './doctor-profile.js';
|
|
32
33
|
export { buildCodexAppUiDiagnosticFailure, buildRuntimeReadiness, formatCodexDoctorConsoleStatus, rebootstrapSksMenuBarLaunchdForDoctorFix, sksMenuBarRunningVersionConsoleLines };
|
|
@@ -202,6 +203,10 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
|
|
|
202
203
|
error: err?.message || String(err)
|
|
203
204
|
}));
|
|
204
205
|
const doctorProfile = doctorProfileFromArgs(args, true);
|
|
206
|
+
const syntaxRepair = await (await import('../core/doctor/codex-config-syntax-repair.js')).runCodexConfigSyntaxRepair({
|
|
207
|
+
root: home, fix: true, codexHome: doctorEnv.CODEX_HOME || path.join(home, '.codex')
|
|
208
|
+
});
|
|
209
|
+
const harnessMaintenance = await doctorHarnessMaintenance(path.resolve(deps.globalRuntimeRoot || doctorEnv.SKS_GLOBAL_ROOT || path.join(home, '.sneakoscope-global')), doctorProfile, doctorEnv, deps);
|
|
205
210
|
const menuBarPolicy = doctorMenuBarInstallPolicy(args, true, doctorEnv);
|
|
206
211
|
const menuBar = menuBarPolicy.phase_enabled
|
|
207
212
|
? await installMenuBarImpl({
|
|
@@ -248,6 +253,8 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
|
|
|
248
253
|
&& globalFastMode?.ok !== false;
|
|
249
254
|
const menuBarReady = menuBar?.ok !== false;
|
|
250
255
|
const migrationScopeBlockers = [...new Set([
|
|
256
|
+
...syntaxRepair.blockers,
|
|
257
|
+
...(harnessMaintenance?.blockers || []),
|
|
251
258
|
...(!globalSkillsReady ? [`global_skills_reconcile_failed:${globalSkills?.error || 'core_skill_integrity'}`] : []),
|
|
252
259
|
...(currentSurface?.ok !== true ? (currentSurface?.blockers || ['global_current_surface_reconcile_failed']) : []),
|
|
253
260
|
...(!globalFastModeReady ? [`global_fast_mode_repair_failed:${globalFastMode?.error || globalFastMode?.status || 'unknown'}`] : [])
|
|
@@ -291,6 +298,8 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
|
|
|
291
298
|
...migrationReceiptBlockers
|
|
292
299
|
].map(String).filter(Boolean))];
|
|
293
300
|
const warnings = [...new Set([
|
|
301
|
+
...syntaxRepair.warnings,
|
|
302
|
+
...(harnessMaintenance?.warnings || []),
|
|
294
303
|
...(!bridgeReadinessRequired ? bridgeBlockers.map((blocker) => `migration_optional_blocker:${blocker}`) : []),
|
|
295
304
|
...(desktopBridgeRepair?.warnings || []),
|
|
296
305
|
...(desktopBridge?.warnings || [])
|
|
@@ -321,6 +330,8 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
|
|
|
321
330
|
],
|
|
322
331
|
skills: { global: globalSkills, project: { skipped: true, reason: 'global_only_doctor' } },
|
|
323
332
|
current_public_surface: currentSurface,
|
|
333
|
+
codex_config_syntax_repair: syntaxRepair,
|
|
334
|
+
harness_maintenance: harnessMaintenance,
|
|
324
335
|
codex_app_fast_mode: globalFastMode,
|
|
325
336
|
openrouter_provider: desktopBridge.providers?.openrouter || null,
|
|
326
337
|
sks_menubar: menuBar,
|
|
@@ -569,6 +580,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
|
|
|
569
580
|
actions: []
|
|
570
581
|
})) : { ok: true, skipped: true, reason: 'doctor_without_fix', actions: [] };
|
|
571
582
|
const doctorProfile = doctorProfileFromArgs(args, doctorFix);
|
|
583
|
+
const harnessMaintenance = doctorFix ? await doctorHarnessMaintenance(root, doctorProfile, process.env, deps) : null;
|
|
572
584
|
const machineOnly = flag(args, '--machine-only');
|
|
573
585
|
const reportFile = readOption(args, '--report-file', null);
|
|
574
586
|
const argWarnings = doctorArgWarnings(args);
|
|
@@ -1467,6 +1479,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
|
|
|
1467
1479
|
}
|
|
1468
1480
|
const runtimeReadiness = buildRuntimeReadiness(codexNativeFeatureMatrix);
|
|
1469
1481
|
const resultBlockers = [
|
|
1482
|
+
...(harnessMaintenance?.blockers || []),
|
|
1470
1483
|
...(ready.ready
|
|
1471
1484
|
? []
|
|
1472
1485
|
: (Array.isArray(ready.blockers) && ready.blockers.length
|
|
@@ -1511,7 +1524,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
|
|
|
1511
1524
|
root,
|
|
1512
1525
|
arg_warnings: argWarnings,
|
|
1513
1526
|
blockers: [...new Set(resultBlockers.map(String))],
|
|
1514
|
-
warnings: [...oauthCallbackPortDiagnostic.warnings, ...(desktopBridge.warnings || [])],
|
|
1527
|
+
warnings: [...oauthCallbackPortDiagnostic.warnings, ...(desktopBridge.warnings || []), ...(harnessMaintenance?.warnings || [])],
|
|
1515
1528
|
operator_actions: [...new Set([
|
|
1516
1529
|
...oauthCallbackOperatorActions,
|
|
1517
1530
|
...(desktopBridge.ok === false ? desktopBridge.recovery_actions || [] : []),
|
|
@@ -1542,6 +1555,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
|
|
|
1542
1555
|
codex_startup_repair: codexStartupRepair,
|
|
1543
1556
|
startup_config_repair: startupConfigRepair,
|
|
1544
1557
|
codex_config_syntax_repair: codexConfigSyntaxRepair,
|
|
1558
|
+
harness_maintenance: harnessMaintenance,
|
|
1545
1559
|
context7_mcp_repair: context7McpRepair,
|
|
1546
1560
|
supabase_mcp_repair: supabaseMcpRepair,
|
|
1547
1561
|
doctor_fix_transaction: doctorFixTransaction,
|
|
@@ -1616,3 +1630,17 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
|
|
|
1616
1630
|
if (!result.ok)
|
|
1617
1631
|
process.exitCode = 1;
|
|
1618
1632
|
}
|
|
1633
|
+
async function doctorHarnessMaintenance(root, profile, env, deps) {
|
|
1634
|
+
const duringUpdate = env.SKS_UPDATE_DEFER_MENUBAR_RESTART === '1';
|
|
1635
|
+
if (profile === 'migration' && !duringUpdate)
|
|
1636
|
+
return null;
|
|
1637
|
+
await ensureDir(root);
|
|
1638
|
+
const maintain = deps.maintainHarnessGuidanceImpl
|
|
1639
|
+
|| (await import('../core/agent-guidance/harness-maintenance.js')).maintainHarnessGuidance;
|
|
1640
|
+
const codexHome = deps.codexHome || deps.env?.CODEX_HOME
|
|
1641
|
+
|| (deps.home ? path.join(deps.home, '.codex') : !isVerificationTestHarness() ? env.CODEX_HOME : undefined);
|
|
1642
|
+
return maintain({
|
|
1643
|
+
root, trigger: duringUpdate ? 'update' : 'doctor', reuseRecent: duringUpdate,
|
|
1644
|
+
...(codexHome ? { codexHome } : {})
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "sks.skills-manifest.v1",
|
|
3
|
-
"package_version": "10.5.
|
|
3
|
+
"package_version": "10.5.5",
|
|
4
4
|
"skills": [
|
|
5
5
|
{
|
|
6
6
|
"canonical_name": "sks",
|
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
{
|
|
19
19
|
"canonical_name": "sks-align",
|
|
20
20
|
"type": "core",
|
|
21
|
-
"content_sha256": "
|
|
21
|
+
"content_sha256": "c3073b4a10203e642dd1236902b01772ecff6a3a7464cdecde0aad21e3c12b80",
|
|
22
22
|
"hash_history": [
|
|
23
|
+
"9eef36214be7e07a963eb36bb1df2c025cd0578b7419ddf4fd307081a2b62093",
|
|
23
24
|
"b9db40d6e1dd2fc6e4665a2b30738d370da955cd4d6e86c88bd85059c7faa08c",
|
|
24
25
|
"c485f39d4873adb9793672f7dcf4e956595ffb9dcbb032b3ffb0515b5857d31d",
|
|
25
26
|
"e98e1b67e228bec5c37d00c0206a2e01d2da698a83c80b527105bf04a19c136a"
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { readText, writeTextAtomic, writeJsonAtomic, mergeManagedBlock } from '../fsx.js';
|
|
5
|
+
import { ensureConfinedDirectory, inspectConfinedPath } from '../managed-path-safety.js';
|
|
6
|
+
import { withFileLock } from '../locks/file-lock.js';
|
|
7
|
+
import { isVerificationTestHarness } from '../verification-profile.js';
|
|
8
|
+
import { reconcileManagedProjectPromptGuidance } from '../doctor/current-project-guidance.js';
|
|
9
|
+
import { globalAgentsBlockText, GLOBAL_AGENTS_MARKER } from '../codex-hooks/codex-global-hooks.js';
|
|
10
|
+
export async function maintainHarnessGuidance(input) {
|
|
11
|
+
const root = path.resolve(input.root);
|
|
12
|
+
const codexHome = path.resolve(input.codexHome || process.env.CODEX_HOME || path.join(process.env.HOME || os.homedir(), '.codex'));
|
|
13
|
+
const dir = path.join(root, '.sneakoscope', 'guidance');
|
|
14
|
+
const report = {
|
|
15
|
+
schema: 'sks.harness-maintenance.v1', ok: true, trigger: input.trigger,
|
|
16
|
+
guidance_status: 'unavailable', fetched_at: null, source_urls: [], prompt_hints_updated: false, changed_files: [], warnings: [], blockers: [],
|
|
17
|
+
report_path: path.join(root, '.sneakoscope', 'reports', 'harness-maintenance.json')
|
|
18
|
+
};
|
|
19
|
+
try {
|
|
20
|
+
for (const file of [path.join(root, 'AGENTS.md'), path.join(root, '.codex', 'SNEAKOSCOPE.md')]) {
|
|
21
|
+
if ((await inspectConfinedPath(root, file)).leafSymlink)
|
|
22
|
+
throw new Error('managed_guidance_unsafe_path');
|
|
23
|
+
}
|
|
24
|
+
const refreshed = await reconcileManagedProjectPromptGuidance(root);
|
|
25
|
+
report.changed_files.push(...refreshed.refreshed.map(file => path.join(root, file)));
|
|
26
|
+
if (refreshed.errors)
|
|
27
|
+
report.blockers.push('managed_project_guidance_refresh_failed');
|
|
28
|
+
const globalFile = path.join(codexHome, 'AGENTS.md');
|
|
29
|
+
const codexHomeExists = await fs.lstat(codexHome).then(() => true).catch((error) => {
|
|
30
|
+
if (error.code === 'ENOENT')
|
|
31
|
+
return false;
|
|
32
|
+
throw error;
|
|
33
|
+
});
|
|
34
|
+
const useGlobal = codexHomeExists && (!isVerificationTestHarness() || input.codexHome !== undefined);
|
|
35
|
+
const globalPath = useGlobal ? await inspectConfinedPath(codexHome, globalFile) : null;
|
|
36
|
+
if (globalPath?.exists && !globalPath.leafSymlink && globalPath.stat?.isFile()) {
|
|
37
|
+
const before = await readText(globalFile, '');
|
|
38
|
+
if (before.includes(`<!-- BEGIN ${GLOBAL_AGENTS_MARKER} -->`)) {
|
|
39
|
+
const body = globalAgentsBlockText().trim();
|
|
40
|
+
const marker = `<!-- BEGIN ${GLOBAL_AGENTS_MARKER} -->`;
|
|
41
|
+
const end = `<!-- END ${GLOBAL_AGENTS_MARKER} -->`;
|
|
42
|
+
if (!before.includes(end))
|
|
43
|
+
throw new Error('global_guidance_managed_block_incomplete');
|
|
44
|
+
const current = before.slice(before.indexOf(marker) + marker.length, before.indexOf(end)).trim();
|
|
45
|
+
if (current !== body) {
|
|
46
|
+
await mergeManagedBlock(globalFile, GLOBAL_AGENTS_MARKER, globalAgentsBlockText());
|
|
47
|
+
report.changed_files.push(globalFile);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else if (globalPath?.exists)
|
|
52
|
+
report.blockers.push('global_guidance_unsafe_path');
|
|
53
|
+
await ensureConfinedDirectory(root, dir);
|
|
54
|
+
const cacheFile = path.join(dir, 'official-sources.json');
|
|
55
|
+
const readerFile = path.join(dir, 'current-codex.md');
|
|
56
|
+
const sharedDir = useGlobal ? path.join(codexHome, 'sks', 'official-guidance') : dir;
|
|
57
|
+
if (useGlobal)
|
|
58
|
+
await ensureConfinedDirectory(codexHome, sharedDir);
|
|
59
|
+
const sharedFile = path.join(sharedDir, 'official-sources.json');
|
|
60
|
+
if (useGlobal && (await inspectConfinedPath(codexHome, sharedFile)).leafSymlink)
|
|
61
|
+
throw new Error('official_guidance_cache_unsafe_path');
|
|
62
|
+
for (const file of [cacheFile, readerFile]) {
|
|
63
|
+
if ((await inspectConfinedPath(root, file)).leafSymlink)
|
|
64
|
+
throw new Error('official_guidance_unsafe_path');
|
|
65
|
+
}
|
|
66
|
+
await withFileLock({ lockPath: path.join(sharedDir, 'refresh.lock'), timeoutMs: 25_000, staleMs: 60_000 }, async () => {
|
|
67
|
+
const { retrieveOfficialGuidance, validOfficialGuidance } = await import('./official-guidance-client.js');
|
|
68
|
+
let snapshot = null;
|
|
69
|
+
try {
|
|
70
|
+
const cached = JSON.parse(await fs.readFile(sharedFile, 'utf8'));
|
|
71
|
+
if (validOfficialGuidance(cached))
|
|
72
|
+
snapshot = cached;
|
|
73
|
+
}
|
|
74
|
+
catch { }
|
|
75
|
+
const previousSnapshot = snapshot;
|
|
76
|
+
const recent = snapshot && Date.now() - Date.parse(snapshot.fetched_at) >= 0
|
|
77
|
+
&& Date.now() - Date.parse(snapshot.fetched_at) < 10 * 60_000;
|
|
78
|
+
if (input.reuseRecent && recent)
|
|
79
|
+
report.guidance_status = 'cached';
|
|
80
|
+
else if (!input.retrieve && isVerificationTestHarness()) {
|
|
81
|
+
report.warnings.push('official_guidance_network_not_requested_by_test_harness');
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
try {
|
|
85
|
+
const fetched = await (input.retrieve || retrieveOfficialGuidance)();
|
|
86
|
+
if (!validOfficialGuidance(fetched))
|
|
87
|
+
throw new Error('official_guidance_snapshot_invalid');
|
|
88
|
+
snapshot = fetched;
|
|
89
|
+
report.guidance_status = 'refreshed';
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
report.warnings.push(`official_guidance_refresh_unavailable:${error instanceof Error ? error.message.slice(0, 200) : 'unknown'}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (!snapshot)
|
|
96
|
+
return;
|
|
97
|
+
report.fetched_at = snapshot.fetched_at;
|
|
98
|
+
report.source_urls = snapshot.sources.map(source => source.url);
|
|
99
|
+
if (report.guidance_status === 'unavailable')
|
|
100
|
+
return;
|
|
101
|
+
const hints = officialPromptHints(snapshot);
|
|
102
|
+
if (!hints) {
|
|
103
|
+
report.guidance_status = 'unavailable';
|
|
104
|
+
report.fetched_at = previousSnapshot?.fetched_at || null;
|
|
105
|
+
report.source_urls = previousSnapshot?.sources.map(source => source.url) || [];
|
|
106
|
+
report.warnings.push('official_prompt_sections_changed_previous_hints_preserved');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const json = `${JSON.stringify(snapshot, null, 2)}\n`;
|
|
110
|
+
const markdown = renderGuidanceReference(snapshot);
|
|
111
|
+
const writes = new Map([[sharedFile, json], [cacheFile, json], [readerFile, markdown]]);
|
|
112
|
+
for (const [file, content] of writes) {
|
|
113
|
+
if (await readText(file, '') !== content) {
|
|
114
|
+
await writeTextAtomic(file, content);
|
|
115
|
+
report.changed_files.push(file);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
for (const file of [path.join(root, 'AGENTS.md'), ...(useGlobal ? [globalFile] : [])]) {
|
|
119
|
+
const before = await readText(file, '');
|
|
120
|
+
if (!/<!-- BEGIN Sneakoscope Codex (?:GX|GLOBAL) MANAGED BLOCK -->/.test(before))
|
|
121
|
+
continue;
|
|
122
|
+
const marker = 'SKS CURRENT OFFICIAL GUIDANCE';
|
|
123
|
+
const begin = `<!-- BEGIN ${marker} -->`, end = `<!-- END ${marker} -->`;
|
|
124
|
+
if (before.includes(begin) && !before.includes(end))
|
|
125
|
+
throw new Error('official_prompt_block_incomplete');
|
|
126
|
+
const current = before.includes(begin) ? before.slice(before.indexOf(begin) + begin.length, before.indexOf(end)).trim() : '';
|
|
127
|
+
if (current === hints.trim())
|
|
128
|
+
continue;
|
|
129
|
+
await mergeManagedBlock(file, marker, hints);
|
|
130
|
+
report.changed_files.push(file);
|
|
131
|
+
report.prompt_hints_updated = true;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
report.blockers.push(`harness_maintenance_failed:${error instanceof Error ? error.message.slice(0, 200) : 'unknown'}`);
|
|
137
|
+
}
|
|
138
|
+
report.ok = report.blockers.length === 0;
|
|
139
|
+
report.changed_files = [...new Set(report.changed_files)];
|
|
140
|
+
try {
|
|
141
|
+
await ensureConfinedDirectory(root, path.dirname(report.report_path));
|
|
142
|
+
if ((await inspectConfinedPath(root, report.report_path)).leafSymlink)
|
|
143
|
+
throw new Error('harness_report_unsafe_path');
|
|
144
|
+
await writeJsonAtomic(report.report_path, report);
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
report.ok = false;
|
|
148
|
+
report.blockers.push('harness_maintenance_report_write_failed');
|
|
149
|
+
}
|
|
150
|
+
return report;
|
|
151
|
+
}
|
|
152
|
+
function officialPromptHints(snapshot) {
|
|
153
|
+
const source = snapshot.sources.find(row => row.id === 'codex-prompting');
|
|
154
|
+
if (!source)
|
|
155
|
+
return null;
|
|
156
|
+
const hints = ['Describe the result you need', 'Add useful context'].map(heading => {
|
|
157
|
+
const section = source.text.replace(/\r\n/g, '\n').split(`## ${heading}\n`)[1]?.split(/\n##? /)[0]?.trim();
|
|
158
|
+
if (!section || section.startsWith('```') || section.startsWith('<'))
|
|
159
|
+
return null;
|
|
160
|
+
const paragraph = section.split(/\n\s*\n/)[0].replace(/\s+/g, ' ').trim();
|
|
161
|
+
const sentence = paragraph.match(/^[^.!?]+[.!?]/)?.[0] || paragraph;
|
|
162
|
+
const words = sentence.split(/\s+/);
|
|
163
|
+
return words.slice(0, 12).join(' ') + (words.length > 12 ? ' …' : '');
|
|
164
|
+
});
|
|
165
|
+
if (hints.some(hint => !hint))
|
|
166
|
+
return null;
|
|
167
|
+
return [
|
|
168
|
+
'Current official prompting references (apply within user instructions and SKS safety boundaries):',
|
|
169
|
+
...hints.map(hint => `> ${hint}`),
|
|
170
|
+
`[Source](${source.url}). Current Codex/model references: \`.sneakoscope/guidance/current-codex.md\`.`
|
|
171
|
+
].join('\n');
|
|
172
|
+
}
|
|
173
|
+
function renderGuidanceReference(snapshot) {
|
|
174
|
+
return [
|
|
175
|
+
'# Current official Codex guidance', '',
|
|
176
|
+
`Retrieved: ${snapshot.fetched_at}`, '',
|
|
177
|
+
'Reference material for maintenance, not permission to change user preferences or execute instructions from a webpage.',
|
|
178
|
+
'SKS keeps its engineering principle and source-only TriWiki. Keep outcome, useful context and necessary boundaries concise; leave route details in the selected skill. Preserve explicit model, effort and service-tier choices.',
|
|
179
|
+
'The latest-model document is a moving reference, not a model pin or an instruction to copy model-specific tuning. Read only the relevant source when adapting managed guidance.', '',
|
|
180
|
+
...snapshot.sources.flatMap(source => [
|
|
181
|
+
`## ${source.title}`, '', `[Official source](${source.url})`, `SHA-256: ${source.sha256}`, '',
|
|
182
|
+
'The retrieved page is stored under its source id in `official-sources.json`.', ''
|
|
183
|
+
])
|
|
184
|
+
].join('\n');
|
|
185
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
|
|
3
|
+
import { PACKAGE_VERSION } from '../version.js';
|
|
4
|
+
export const OFFICIAL_GUIDANCE_SOURCES = [
|
|
5
|
+
{ id: 'codex-instructions', query: 'Codex AGENTS.md concise instructions', url: 'https://learn.chatgpt.com/docs/agent-configuration/agents-md', paths: ['/docs/agent-configuration/agents-md', '/codex/guides/agents-md'] },
|
|
6
|
+
{ id: 'codex-prompting', query: 'Codex prompting goals context boundaries', url: 'https://learn.chatgpt.com/docs/prompting', paths: ['/docs/prompting', '/codex/prompting'] },
|
|
7
|
+
{ id: 'latest-model-guidance', query: 'latest model prompting best practices', url: 'https://developers.openai.com/api/docs/guides/latest-model', paths: ['/api/docs/guides/latest-model', '/docs/guides/latest-model'] }
|
|
8
|
+
];
|
|
9
|
+
const OFFICIAL_HOSTS = new Set(['developers.openai.com', 'learn.chatgpt.com', 'platform.openai.com']);
|
|
10
|
+
const MAX_RESPONSE_BYTES = 1024 * 1024;
|
|
11
|
+
export async function retrieveOfficialGuidance() {
|
|
12
|
+
const client = new Client({ name: 'sneakoscope-official-guidance', version: PACKAGE_VERSION }, {
|
|
13
|
+
versionNegotiation: { mode: 'auto', probe: { timeoutMs: 6000, maxRetries: 0 } },
|
|
14
|
+
inputRequired: { autoFulfill: false }
|
|
15
|
+
});
|
|
16
|
+
try {
|
|
17
|
+
await client.connect(new StreamableHTTPClientTransport(new URL('https://developers.openai.com/mcp')), { timeout: 6000 });
|
|
18
|
+
const selected = await Promise.all(OFFICIAL_GUIDANCE_SOURCES.map(async (source) => {
|
|
19
|
+
const search = await client.callTool({ name: 'search_openai_docs', arguments: { query: source.query, limit: 5 } }, { timeout: 6000 });
|
|
20
|
+
const result = JSON.parse(toolText(search));
|
|
21
|
+
if (!Array.isArray(result.hits))
|
|
22
|
+
throw new Error(`official_guidance_search_invalid:${source.id}`);
|
|
23
|
+
const hit = result.hits.find((row) => sourceUrlAllowed(source.id, row?.url));
|
|
24
|
+
const url = new URL(hit?.url || source.url);
|
|
25
|
+
url.hash = '';
|
|
26
|
+
url.search = '';
|
|
27
|
+
return {
|
|
28
|
+
source, url: url.toString(), discovered_via_search: Boolean(hit),
|
|
29
|
+
search_result_urls: result.hits.slice(0, 5).map((row) => String(row?.url || '').slice(0, 2048))
|
|
30
|
+
};
|
|
31
|
+
}));
|
|
32
|
+
const sources = await Promise.all(selected.map(async ({ source, url, discovered_via_search, search_result_urls }) => {
|
|
33
|
+
const fetched = await client.callTool({ name: 'fetch_openai_doc', arguments: { url } }, { timeout: 6000 });
|
|
34
|
+
const text = toolText(fetched);
|
|
35
|
+
if (text.length < 100 || Buffer.byteLength(text) > 256 * 1024)
|
|
36
|
+
throw new Error(`official_guidance_document_invalid:${source.id}`);
|
|
37
|
+
const title = (text.match(/^#\s+(.+)$/m)?.[1] || source.id).replace(/[\r\n`]/g, ' ').slice(0, 160);
|
|
38
|
+
return { id: source.id, query: source.query, url, title, discovered_via_search, search_result_urls, text, sha256: digest(text) };
|
|
39
|
+
}));
|
|
40
|
+
return { schema: 'sks.official-guidance.v1', fetched_at: new Date().toISOString(), sources };
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
await client.close();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function validOfficialGuidance(value) {
|
|
47
|
+
const row = value;
|
|
48
|
+
return row?.schema === 'sks.official-guidance.v1'
|
|
49
|
+
&& Number.isFinite(Date.parse(row.fetched_at))
|
|
50
|
+
&& Array.isArray(row.sources) && row.sources.length === OFFICIAL_GUIDANCE_SOURCES.length
|
|
51
|
+
&& OFFICIAL_GUIDANCE_SOURCES.every(expected => row.sources.filter(source => source.id === expected.id).length === 1)
|
|
52
|
+
&& row.sources.every(source => sourceUrlAllowed(source.id, source.url)
|
|
53
|
+
&& typeof source.discovered_via_search === 'boolean'
|
|
54
|
+
&& Array.isArray(source.search_result_urls) && source.search_result_urls.length <= 5
|
|
55
|
+
&& typeof source.text === 'string' && source.text.length >= 100
|
|
56
|
+
&& Buffer.byteLength(source.text) <= 256 * 1024
|
|
57
|
+
&& source.sha256 === digest(source.text));
|
|
58
|
+
}
|
|
59
|
+
function sourceUrlAllowed(id, value) {
|
|
60
|
+
if (typeof value !== 'string')
|
|
61
|
+
return false;
|
|
62
|
+
try {
|
|
63
|
+
const url = new URL(value);
|
|
64
|
+
const source = OFFICIAL_GUIDANCE_SOURCES.find(row => row.id === id);
|
|
65
|
+
const pathname = url.pathname.replace(/\/$/, '');
|
|
66
|
+
return url.protocol === 'https:' && OFFICIAL_HOSTS.has(url.hostname) && !url.port && !url.username && !url.password
|
|
67
|
+
&& Boolean(source?.paths.some(path => pathname === path));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function toolText(result) {
|
|
74
|
+
const row = result;
|
|
75
|
+
if (row?.isError || !Array.isArray(row?.content))
|
|
76
|
+
throw new Error('official_guidance_tool_failed');
|
|
77
|
+
const text = row.content.filter(item => item.type === 'text' && typeof item.text === 'string').map(item => item.text).join('\n');
|
|
78
|
+
if (!text || Buffer.byteLength(text) > MAX_RESPONSE_BYTES)
|
|
79
|
+
throw new Error('official_guidance_response_invalid');
|
|
80
|
+
return text;
|
|
81
|
+
}
|
|
82
|
+
function digest(text) { return createHash('sha256').update(text).digest('hex'); }
|
|
@@ -14,7 +14,7 @@ import { decideSubagentModel } from '../subagents/model-policy.js';
|
|
|
14
14
|
import { latestTierModelSet } from '../subagents/model-tiers.js';
|
|
15
15
|
import { consultJevTurnModel } from '../decisions/integration.js';
|
|
16
16
|
import { chooseChildModel, fallbackChildModel } from '../decisions/child-model-choice.js';
|
|
17
|
-
import {
|
|
17
|
+
import { allowlistedChildModel, effectiveChildModelAllowlist, childModelListProfile, listChildModelEffort, isSubagentModelEffort } from '../subagents/child-model-allowlist.js';
|
|
18
18
|
export const NATIVE_WORKER_BACKEND_ROUTER_SCHEMA = 'sks.native-worker-backend-router.v1';
|
|
19
19
|
export async function runNativeWorkerBackendRouter(input) {
|
|
20
20
|
const root = path.resolve(input.agentRoot);
|
|
@@ -93,8 +93,10 @@ export async function runNativeWorkerBackendRouter(input) {
|
|
|
93
93
|
cwd: String(input.intake.cwd || root),
|
|
94
94
|
prompt: buildWorkerPrompt(input.slice),
|
|
95
95
|
model: modelRouting.choice.model,
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
...(modelRouting.choice.reasoning ? {
|
|
97
|
+
reasoningEffort: modelRouting.choice.reasoning,
|
|
98
|
+
modelReasoningEffort: modelRouting.choice.reasoning
|
|
99
|
+
} : {}),
|
|
98
100
|
serviceTier: modelRouting.choice.serviceTier,
|
|
99
101
|
inputFiles: input.intake.input_files || [],
|
|
100
102
|
inputImages: input.intake.input_images || [],
|
|
@@ -232,7 +234,7 @@ export async function resolveWorkerModelRouting(input, deps = {}) {
|
|
|
232
234
|
const category = categoryForWorkerRole(String(input.agent?.role || 'executor'), taskKindText);
|
|
233
235
|
const env = deps.env || process.env;
|
|
234
236
|
const allowlist = effectiveChildModelAllowlist({ env });
|
|
235
|
-
if (allowlist.mode
|
|
237
|
+
if (allowlist.mode !== 'tiers') {
|
|
236
238
|
return resolveOpenRouterOnlyWorkerRouting(input, deps, { allowlist, category, env, taskKindText, riskText });
|
|
237
239
|
}
|
|
238
240
|
const lbCatalog = narutoOnly
|
|
@@ -306,11 +308,12 @@ export async function resolveWorkerModelRouting(input, deps = {}) {
|
|
|
306
308
|
}
|
|
307
309
|
async function resolveOpenRouterOnlyWorkerRouting(input, deps, ctx) {
|
|
308
310
|
const { allowlist, category, env } = ctx;
|
|
309
|
-
const state = {
|
|
311
|
+
const state = { subagent_models: allowlist.entries };
|
|
310
312
|
const explicitModel = String(env.SKS_WORKER_MODEL || env.SKS_AGENT_MODEL || '').trim();
|
|
311
|
-
const
|
|
313
|
+
const rawEffort = env.SKS_WORKER_REASONING || env.SKS_WORKER_MODEL_REASONING;
|
|
314
|
+
const explicitReasoning = allowlist.mode === 'openrouter_only' ? listReasoning(rawEffort) : normalizeModelReasoning(rawEffort);
|
|
312
315
|
const explicitTier = normalizeServiceTier(String(env.SKS_WORKER_SERVICE_TIER || env.SKS_SERVICE_TIER || '').trim());
|
|
313
|
-
const planned = /^
|
|
316
|
+
const planned = /^(openrouter_only|configured_list)_/.test(String(input.agent?.routed_model_policy || ''))
|
|
314
317
|
? allowlistedChildModel(input.agent?.routed_model, allowlist)
|
|
315
318
|
: null;
|
|
316
319
|
const requested = String(input.agent?.routed_model || input.agent?.model || '').trim() || null;
|
|
@@ -322,18 +325,23 @@ async function resolveOpenRouterOnlyWorkerRouting(input, deps, ctx) {
|
|
|
322
325
|
? fallbackChildModel(state, planned, 'planned')
|
|
323
326
|
: deps.consultJev === false || !task
|
|
324
327
|
? fallbackChildModel(state, requested, deps.consultJev === false ? 'jev_skipped' : 'empty_task')
|
|
325
|
-
: await chooseChildModel({ root: deps.root || process.cwd(), task, role: input.agent?.role || null, requestedModel: requested, state, env })
|
|
328
|
+
: await chooseChildModel({ root: deps.root || process.cwd(), task, role: input.agent?.role || null, requestedModel: requested, state, env, profile: childModelListProfile(allowlist) })
|
|
326
329
|
.catch(() => fallbackChildModel(state, requested, 'consult_failed'));
|
|
327
330
|
const taskPolicy = decideSubagentModel({ title: ctx.taskKindText, description: ctx.riskText, role: input.agent?.role });
|
|
328
331
|
const choiceModel = choice?.entry.model || '';
|
|
329
332
|
const routed = {
|
|
330
333
|
model: choiceModel,
|
|
331
|
-
reasoning:
|
|
334
|
+
reasoning: allowlist.mode === 'openrouter_only'
|
|
335
|
+
? explicitReasoning || choice?.entry.reasoning_effort || listReasoning(taskPolicy.modelReasoningEffort) || 'medium'
|
|
336
|
+
: explicitReasoning || (choice ? listChildModelEffort(choice.entry, null) : null),
|
|
332
337
|
serviceTier: explicitTier || input.fastModePolicy.service_tier || 'fast'
|
|
333
338
|
};
|
|
334
339
|
const blockers = [
|
|
335
|
-
...(!allowlist.entries.length ? ['openrouter_only_subagent_list_empty'] : []),
|
|
336
|
-
...(explicitModel && !explicitListed ? ['openrouter_only_subagent_model_not_listed'] : []),
|
|
340
|
+
...(!allowlist.entries.length ? [allowlist.mode === 'openrouter_only' ? 'openrouter_only_subagent_list_empty' : 'configured_subagent_list_unavailable'] : []),
|
|
341
|
+
...(explicitModel && !explicitListed ? [allowlist.mode === 'openrouter_only' ? 'openrouter_only_subagent_model_not_listed' : 'configured_subagent_model_not_listed'] : []),
|
|
342
|
+
...(allowlist.mode === 'configured' && rawEffort
|
|
343
|
+
&& (!explicitReasoning || !choice?.entry.supported_reasoning_efforts?.includes(explicitReasoning))
|
|
344
|
+
? ['configured_subagent_effort_unsupported'] : []),
|
|
337
345
|
...(!choiceModel ? ['naruto_worker_model_unavailable'] : [])
|
|
338
346
|
];
|
|
339
347
|
const why = choice ? `${choice.source}${choice.reason === 'applied' ? '' : `:${choice.reason}`}` : 'blocked';
|
|
@@ -343,7 +351,7 @@ async function resolveOpenRouterOnlyWorkerRouting(input, deps, ctx) {
|
|
|
343
351
|
explicit: Boolean(explicitModel),
|
|
344
352
|
lb_catalog: null,
|
|
345
353
|
blockers: [...new Set(blockers)],
|
|
346
|
-
reason: `${category}->${choiceModel || 'blocked'}@${routed.reasoning} (openrouter only list: ${why})`
|
|
354
|
+
reason: `${category}->${choiceModel || 'blocked'}@${routed.reasoning || 'default'} (${allowlist.mode === 'openrouter_only' ? 'openrouter only' : allowlist.profile} list: ${why})`
|
|
347
355
|
};
|
|
348
356
|
}
|
|
349
357
|
function listReasoning(value) {
|