sneakoscope 10.3.0 → 10.3.2
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 +1 -1
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/cli/install-helpers-codex-lb-config.js +14 -4
- package/dist/config/skills-manifest.json +1 -1
- package/dist/core/codex-lb/desktop-controller-v3/provider-commands.js +9 -0
- package/dist/core/decisions/integration.js +48 -1
- package/dist/core/decisions/policy.js +11 -1
- package/dist/core/decisions/questions.js +14 -0
- package/dist/core/decisions/types.js +1 -0
- package/dist/core/hooks-runtime/hook-io.js +3 -1
- package/dist/core/hooks-runtime/jev-spawn-routing.js +50 -0
- package/dist/core/hooks-runtime.js +39 -5
- package/dist/core/routes.js +3 -0
- package/dist/core/subagents/official-subagent-preparation.js +8 -1
- package/dist/core/subagents/official-subagent-prompt.js +2 -0
- package/dist/core/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
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.
|
|
17
17
|
<!-- END SKS SEARCH VISIBILITY MARKETING -->
|
|
18
18
|
|
|
19
|
-
Current package: **SKS 10.3.
|
|
19
|
+
Current package: **SKS 10.3.2**. Install the latest stable release from npm.
|
|
20
20
|
|
|
21
21
|
[Quick start](#install-in-one-command) · [Commands](#everyday-commands) · [SKS Center](#sks-center-macos) · [Documentation](#documentation) · [Changelog](CHANGELOG.md)
|
|
22
22
|
|
|
@@ -4,6 +4,14 @@ import { escapeRegExp } from '../core/text/regex.js';
|
|
|
4
4
|
export const DESKTOP_BRIDGE_MANAGED_MARKER = '# sks-desktop-bridge-managed';
|
|
5
5
|
export const DESKTOP_BRIDGE_MANAGED_BASE_URL_MARKER = '# sks-desktop-bridge-managed-base-url';
|
|
6
6
|
export const DESKTOP_BRIDGE_MANAGED_MODEL_CATALOG_MARKER = '# sks-desktop-bridge-managed-model-catalog';
|
|
7
|
+
export function bindCodexClientProvider(text, provider) {
|
|
8
|
+
const selected = topLevelTomlString(text, 'model_provider');
|
|
9
|
+
if (selected && selected !== 'openai' && selected !== 'codex-lb')
|
|
10
|
+
return text;
|
|
11
|
+
if (selected === provider)
|
|
12
|
+
return text;
|
|
13
|
+
return upsertTopLevelTomlString(String(text || ''), 'model_provider', provider);
|
|
14
|
+
}
|
|
7
15
|
export function upsertDesktopBridgeManagedConfig(text, input) {
|
|
8
16
|
const bridgeBaseUrl = normalizeManagedBridgeBaseUrl(input.bridgeBaseUrl);
|
|
9
17
|
const combinedCatalogPath = String(input.combinedCatalogPath || '').trim();
|
|
@@ -16,7 +24,8 @@ export function upsertDesktopBridgeManagedConfig(text, input) {
|
|
|
16
24
|
const orphanCleanup = removeDesktopBridgeOrphanManagedMarkers(String(text || ''));
|
|
17
25
|
let next = orphanCleanup.text;
|
|
18
26
|
const selectedProvider = topLevelTomlString(next, 'model_provider');
|
|
19
|
-
|
|
27
|
+
const managedProvider = selectedProvider === 'codex-lb' || selectedProvider === 'openai';
|
|
28
|
+
if (selectedProvider && (!managedProvider
|
|
20
29
|
|| !topLevelHasLine(next, DESKTOP_BRIDGE_MANAGED_MARKER))) {
|
|
21
30
|
throw new Error('historical_user_owned_config_conflict:model_provider');
|
|
22
31
|
}
|
|
@@ -30,8 +39,9 @@ export function upsertDesktopBridgeManagedConfig(text, input) {
|
|
|
30
39
|
if (existingCatalog && !catalogOwned) {
|
|
31
40
|
throw new Error('historical_user_owned_config_conflict:model_catalog_json');
|
|
32
41
|
}
|
|
42
|
+
const keepCodexLb = selectedProvider === 'codex-lb';
|
|
33
43
|
next = removeManagedBridgeTopLevelBindings(next);
|
|
34
|
-
next = upsertTopLevelTomlString(next, 'model_provider', 'openai');
|
|
44
|
+
next = upsertTopLevelTomlString(next, 'model_provider', keepCodexLb ? 'codex-lb' : 'openai');
|
|
35
45
|
next = addTopLevelMarkerBeforeKey(next, 'model_provider', DESKTOP_BRIDGE_MANAGED_MARKER);
|
|
36
46
|
next = upsertTopLevelTomlString(next, 'openai_base_url', bridgeBaseUrl);
|
|
37
47
|
next = addTopLevelMarkerBeforeKey(next, 'openai_base_url', DESKTOP_BRIDGE_MANAGED_BASE_URL_MARKER);
|
|
@@ -45,7 +55,7 @@ export function removeDesktopBridgeManagedConfig(text) {
|
|
|
45
55
|
const baseUrl = topLevelTomlString(next, 'openai_base_url');
|
|
46
56
|
const catalog = topLevelTomlString(next, 'model_catalog_json');
|
|
47
57
|
const owned = [
|
|
48
|
-
[DESKTOP_BRIDGE_MANAGED_MARKER, 'model_provider', selectedProvider === 'openai'],
|
|
58
|
+
[DESKTOP_BRIDGE_MANAGED_MARKER, 'model_provider', selectedProvider === 'openai' || selectedProvider === 'codex-lb'],
|
|
49
59
|
[DESKTOP_BRIDGE_MANAGED_BASE_URL_MARKER, 'openai_base_url', Boolean(baseUrl)],
|
|
50
60
|
[DESKTOP_BRIDGE_MANAGED_MODEL_CATALOG_MARKER, 'model_catalog_json', Boolean(catalog)]
|
|
51
61
|
];
|
|
@@ -67,7 +77,7 @@ export function removeDesktopBridgeOrphanManagedMarkers(text) {
|
|
|
67
77
|
const source = String(text || '');
|
|
68
78
|
const selectedProvider = topLevelTomlString(source, 'model_provider');
|
|
69
79
|
const markerTargets = [
|
|
70
|
-
[DESKTOP_BRIDGE_MANAGED_MARKER, selectedProvider === 'openai'],
|
|
80
|
+
[DESKTOP_BRIDGE_MANAGED_MARKER, selectedProvider === 'openai' || selectedProvider === 'codex-lb'],
|
|
71
81
|
[DESKTOP_BRIDGE_MANAGED_BASE_URL_MARKER, Boolean(topLevelTomlString(source, 'openai_base_url'))],
|
|
72
82
|
[DESKTOP_BRIDGE_MANAGED_MODEL_CATALOG_MARKER, Boolean(topLevelTomlString(source, 'model_catalog_json'))]
|
|
73
83
|
];
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { bindCodexClientProvider } from '../../../cli/install-helpers-codex-lb-config.js';
|
|
2
|
+
import { safeWriteCodexConfigToml } from '../../codex-runtime/codex-desktop-config-policy.js';
|
|
3
|
+
import { readText } from '../../fsx.js';
|
|
1
4
|
import { testOpenRouterConnection } from '../../providers/openrouter/openrouter-account.js';
|
|
2
5
|
import { openRouterSecretPaths } from '../../providers/openrouter/openrouter-secret-store.js';
|
|
3
6
|
import { codexLbEnvPath, codexLbMetadataPath, readCodexLbModelCatalog } from '../codex-lb-env.js';
|
|
@@ -108,6 +111,12 @@ export async function setProviderState(providerId, enabled, operation, options)
|
|
|
108
111
|
});
|
|
109
112
|
}
|
|
110
113
|
}
|
|
114
|
+
if (providerId === 'codex-lb') {
|
|
115
|
+
const current = await readText(paths.configPath, '');
|
|
116
|
+
const next = bindCodexClientProvider(current, enabled ? 'codex-lb' : 'openai');
|
|
117
|
+
if (next !== current)
|
|
118
|
+
await safeWriteCodexConfigToml(paths.configPath, current, next, 'codex-lb-client-provider');
|
|
119
|
+
}
|
|
111
120
|
const status = await desktopBridgeStatusV3(options);
|
|
112
121
|
return commandResult(operation, true, status, { provider_id: providerId, enabled }, [], options);
|
|
113
122
|
}
|
|
@@ -8,7 +8,7 @@ import { applyRecoveryEffect, listProductionRecoveryCandidates } from './recover
|
|
|
8
8
|
import { assembleRoutingSelection, buildRoutingCandidates } from './routing.js';
|
|
9
9
|
import { buildDecisionReceipt } from './receipt.js';
|
|
10
10
|
import { applyOptionalContextSelection, graphFileDigest, hydrateContextCandidates, sourceSnapshotDigest } from './state.js';
|
|
11
|
-
import { DESIGN_DEFAULTS, POLICY_REVISION, UNKNOWN_USAGE } from './types.js';
|
|
11
|
+
import { DESIGN_DEFAULTS, POLICY_REVISION, UNKNOWN_USAGE, sealedRoutingModel } from './types.js';
|
|
12
12
|
let testOverrides = null;
|
|
13
13
|
const appliedEffects = new Set();
|
|
14
14
|
export function setDecisionTestOverrides(overrides) {
|
|
@@ -101,6 +101,7 @@ async function decideOfficialSubagentPreparationInner(input, started) {
|
|
|
101
101
|
selectedPlan: null,
|
|
102
102
|
selectedRouting: null,
|
|
103
103
|
selectedContextIds: null,
|
|
104
|
+
omittedRoutingRoles: [],
|
|
104
105
|
consumptionEvidence: null
|
|
105
106
|
};
|
|
106
107
|
const receipt = buildDecisionReceipt({
|
|
@@ -122,12 +123,51 @@ async function decideOfficialSubagentPreparationInner(input, started) {
|
|
|
122
123
|
selectedPlan: applied.selectedPlan,
|
|
123
124
|
selectedRouting: applied.selectedRouting,
|
|
124
125
|
selectedContextIds: applied.selectedContextIds,
|
|
126
|
+
omittedRoutingRoles: applied.omittedRoutingRoles,
|
|
125
127
|
llmRejudgeCalls: 0,
|
|
126
128
|
bundle
|
|
127
129
|
};
|
|
128
130
|
overrides?.observe?.({ mode: config.mode, eligible: true, compiled, receipt });
|
|
129
131
|
return result;
|
|
130
132
|
}
|
|
133
|
+
export async function consultJevTurnModel(input) {
|
|
134
|
+
const overrides = activeOverrides();
|
|
135
|
+
const env = input.env || process.env;
|
|
136
|
+
const config = overrides?.config ?? await readDecisionConfig(env);
|
|
137
|
+
const none = (reason) => ({ called: false, model: null, effort: null, reason });
|
|
138
|
+
if (!jevEnabled(config))
|
|
139
|
+
return none('off');
|
|
140
|
+
const resolved = await resolveOpenRouterApiKey({ env });
|
|
141
|
+
if (!resolved.key)
|
|
142
|
+
return none('missing_key');
|
|
143
|
+
const prompt = String(input.prompt || '').trim();
|
|
144
|
+
if (!prompt)
|
|
145
|
+
return none('empty_prompt');
|
|
146
|
+
const roleId = input.roleId === 'spawn' ? 'spawn' : 'turn';
|
|
147
|
+
const bundle = buildDecisionBundle({
|
|
148
|
+
projectId: sha256(input.root).slice(0, 32),
|
|
149
|
+
workflowRunId: roleId,
|
|
150
|
+
workflowRevision: roleId,
|
|
151
|
+
sourceDigest: roleId,
|
|
152
|
+
graphDigest: null,
|
|
153
|
+
goal: prompt,
|
|
154
|
+
routingCandidates: [{ id: roleId, summary: prompt.slice(0, 240) }]
|
|
155
|
+
});
|
|
156
|
+
const transport = await requestOpenRouterDecision(bundle, {
|
|
157
|
+
env,
|
|
158
|
+
deadlineMs: DESIGN_DEFAULTS.deadlineMs,
|
|
159
|
+
...(overrides?.fetchImpl ? { fetchImpl: overrides.fetchImpl } : {})
|
|
160
|
+
});
|
|
161
|
+
if (!transport.ok)
|
|
162
|
+
return { called: true, model: null, effort: null, reason: transport.reason };
|
|
163
|
+
const compiled = compileDecision(bundle, transport.response);
|
|
164
|
+
if (compiled.kind !== 'apply')
|
|
165
|
+
return { called: true, model: null, effort: null, reason: compiled.reason };
|
|
166
|
+
const selected = assembleRoutingSelection(compiled.effects.flatMap((effect) => (effect.kind === 'select_routing' ? [{ roleId: effect.roleId, model: effect.model }] : [])));
|
|
167
|
+
const model = selected?.models[roleId] || null;
|
|
168
|
+
const sealed = model ? sealedRoutingModel(model) : null;
|
|
169
|
+
return { called: true, model: sealed?.id || null, effort: sealed?.effort || null, reason: sealed ? 'applied' : 'keep_baseline' };
|
|
170
|
+
}
|
|
131
171
|
export function effectAlreadyConsumed(identity) {
|
|
132
172
|
return appliedEffects.has(identity);
|
|
133
173
|
}
|
|
@@ -157,6 +197,7 @@ function applyEffects(attention, contextCandidates, planCandidates, compiled) {
|
|
|
157
197
|
let selectedContextIds = null;
|
|
158
198
|
const evidence = [];
|
|
159
199
|
const routingEffects = [];
|
|
200
|
+
const omittedRoutingRoles = [];
|
|
160
201
|
for (const effect of compiled.effects) {
|
|
161
202
|
if (effect.kind === 'select_optional_context') {
|
|
162
203
|
nextAttention = applyOptionalContextSelection(attention, contextCandidates, effect.keepIds);
|
|
@@ -171,6 +212,10 @@ function applyEffects(attention, contextCandidates, planCandidates, compiled) {
|
|
|
171
212
|
if (effect.kind === 'select_routing') {
|
|
172
213
|
routingEffects.push({ roleId: effect.roleId, model: effect.model });
|
|
173
214
|
}
|
|
215
|
+
if (effect.kind === 'omit_role') {
|
|
216
|
+
omittedRoutingRoles.push(effect.roleId);
|
|
217
|
+
evidence.push(`omit:${effect.roleId}`);
|
|
218
|
+
}
|
|
174
219
|
}
|
|
175
220
|
const selectedRouting = assembleRoutingSelection(routingEffects);
|
|
176
221
|
if (selectedRouting) {
|
|
@@ -181,6 +226,7 @@ function applyEffects(attention, contextCandidates, planCandidates, compiled) {
|
|
|
181
226
|
selectedPlan,
|
|
182
227
|
selectedRouting,
|
|
183
228
|
selectedContextIds,
|
|
229
|
+
omittedRoutingRoles,
|
|
184
230
|
consumptionEvidence: evidence.length ? evidence.join('|') : null
|
|
185
231
|
};
|
|
186
232
|
}
|
|
@@ -256,6 +302,7 @@ function keep(input, reason, started) {
|
|
|
256
302
|
selectedPlan: null,
|
|
257
303
|
selectedRouting: null,
|
|
258
304
|
selectedContextIds: null,
|
|
305
|
+
omittedRoutingRoles: [],
|
|
259
306
|
llmRejudgeCalls: 0,
|
|
260
307
|
bundle: null
|
|
261
308
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CHOICE_MIN_CONFIDENCE, CHOICE_MIN_PROBABILITY, CONTEXT_DROP_NOUL_MAX, DISTRIBUTION_SUM_TOLERANCE, KEEP_BASELINE_CHOICE, NEEDS_EVIDENCE_CHOICE, POLICY_REVISION, ROUTING_RISK_NOUL_MIN, UNKNOWN_USAGE, sealedRoutingModel } from './types.js';
|
|
1
|
+
import { CHOICE_MIN_CONFIDENCE, CHOICE_MIN_PROBABILITY, CONTEXT_DROP_NOUL_MAX, DISTRIBUTION_SUM_TOLERANCE, KEEP_BASELINE_CHOICE, NEEDS_EVIDENCE_CHOICE, POLICY_REVISION, ROUTING_RISK_NOUL_MIN, ROUTING_ROLE_OMIT_NOUL_MAX, UNKNOWN_USAGE, sealedRoutingModel } from './types.js';
|
|
2
2
|
export function compileDecision(bundle, response) {
|
|
3
3
|
const usage = usageFromWire(response.usage);
|
|
4
4
|
const decoded = decodeWireResponse(bundle, response);
|
|
@@ -151,6 +151,16 @@ function compileRouting(bundle, answers) {
|
|
|
151
151
|
else if (!reason)
|
|
152
152
|
reason = compiled.reason;
|
|
153
153
|
}
|
|
154
|
+
for (const [questionId, binding] of Object.entries(bundle.questionBindings)) {
|
|
155
|
+
if (binding.kind !== 'routing_needed')
|
|
156
|
+
continue;
|
|
157
|
+
const answer = answers[questionId];
|
|
158
|
+
if (!answer || answer.type !== 'noul')
|
|
159
|
+
continue;
|
|
160
|
+
if (answer.noul <= ROUTING_ROLE_OMIT_NOUL_MAX) {
|
|
161
|
+
effects.push({ kind: 'omit_role', roleId: binding.roleId });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
154
164
|
return { effects, reason };
|
|
155
165
|
}
|
|
156
166
|
function compileRoleRouting(bundle, answers, roleId) {
|
|
@@ -210,6 +210,20 @@ function appendRoutingSpeculation(roles, questions, bindings, recoverySlot) {
|
|
|
210
210
|
}
|
|
211
211
|
};
|
|
212
212
|
bindings[riskId] = { kind: 'routing_risk', roleId: role.id };
|
|
213
|
+
if (questionRoom(questions, recoverySlot) < 1)
|
|
214
|
+
break;
|
|
215
|
+
const neededId = `needed_${role.id}`;
|
|
216
|
+
const neededInstructions = redactDecisionText(`Does state.task require routing.roles.${role.id} as its own child agent? Omit the role when another listed role already covers the work.`);
|
|
217
|
+
assertIndependentQuestion(neededInstructions);
|
|
218
|
+
questions[neededId] = {
|
|
219
|
+
type: 'noul',
|
|
220
|
+
instructions: neededInstructions,
|
|
221
|
+
criteria: {
|
|
222
|
+
true: 'This role must be spawned to finish the task.',
|
|
223
|
+
false: 'This role is unnecessary. The parent should not spawn it.'
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
bindings[neededId] = { kind: 'routing_needed', roleId: role.id };
|
|
213
227
|
}
|
|
214
228
|
}
|
|
215
229
|
export { QUESTION_REVISION };
|
|
@@ -27,6 +27,7 @@ export const ROUTING_DIFFICULTY_RUBRIC = Object.freeze([
|
|
|
27
27
|
'Judgment, architecture, ambiguity, security, or other high-stakes work.'
|
|
28
28
|
]);
|
|
29
29
|
export const ROUTING_RISK_NOUL_MIN = 0.70;
|
|
30
|
+
export const ROUTING_ROLE_OMIT_NOUL_MAX = 0.35;
|
|
30
31
|
export function sealedRoutingModel(model) {
|
|
31
32
|
const match = SEALED_ROUTING_MODELS.find((row) => row.id === model);
|
|
32
33
|
return match ? { id: match.id, effort: match.effort } : null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IMAGEGEN_MODEL } from '../imagegen/imagegen-model-policy.js';
|
|
2
2
|
import { readStdin } from '../fsx.js';
|
|
3
|
-
import { buildCompactContinue, buildPermissionRequestAllow, buildPermissionRequestDeny, buildPostToolUseBlock, buildPostToolUseContinue, buildPreToolUseContinue, buildPreToolUseDeny, buildSessionStartContinue, buildStopBlock, buildStopContinue, buildSubagentStartContinue, buildSubagentStopBlock, buildSubagentStopContinue, buildUserPromptSubmitBlock, buildUserPromptSubmitContinue } from '../codex-compat/codex-hook-output-builders.js';
|
|
3
|
+
import { buildCompactContinue, buildPermissionRequestAllow, buildPermissionRequestDeny, buildPostToolUseBlock, buildPostToolUseContinue, buildPreToolUseAllowRewrite, buildPreToolUseContinue, buildPreToolUseDeny, buildSessionStartContinue, buildStopBlock, buildStopContinue, buildSubagentStartContinue, buildSubagentStopBlock, buildSubagentStopContinue, buildUserPromptSubmitBlock, buildUserPromptSubmitContinue } from '../codex-compat/codex-hook-output-builders.js';
|
|
4
4
|
export async function loadHookPayload() {
|
|
5
5
|
const raw = await readStdin();
|
|
6
6
|
try {
|
|
@@ -33,6 +33,8 @@ export function normalizeHookResult(name, result = {}) {
|
|
|
33
33
|
if (out.decision === 'block' || out.permissionDecision === 'deny' || out.decision === 'deny') {
|
|
34
34
|
return buildPreToolUseDeny(reason, { systemMessage });
|
|
35
35
|
}
|
|
36
|
+
if (out.updatedInput)
|
|
37
|
+
return buildPreToolUseAllowRewrite(out.updatedInput, { systemMessage });
|
|
36
38
|
return buildPreToolUseContinue({ additionalContext: out.additionalContext, systemMessage });
|
|
37
39
|
}
|
|
38
40
|
if (eventName === 'PermissionRequest') {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { consultJevTurnModel } from '../decisions/integration.js';
|
|
2
|
+
import { readRoleModelPreferences } from '../subagents/role-model-preferences.js';
|
|
3
|
+
const SPAWN_TOOLS = new Set(['spawn_agent', 'collaboration.spawn_agent', 'functions.spawn_agent']);
|
|
4
|
+
function spawnInput(payload) {
|
|
5
|
+
const name = String(payload?.tool_name || payload?.toolName || payload?.tool?.name || '');
|
|
6
|
+
if (!SPAWN_TOOLS.has(name))
|
|
7
|
+
return null;
|
|
8
|
+
const input = payload?.tool_input || payload?.toolInput || payload?.tool?.input;
|
|
9
|
+
if (!input || typeof input !== 'object' || Array.isArray(input))
|
|
10
|
+
return null;
|
|
11
|
+
return { ...input };
|
|
12
|
+
}
|
|
13
|
+
function narutoParent(state) {
|
|
14
|
+
const mode = String(state?.mode || '').toUpperCase();
|
|
15
|
+
const route = String(state?.route || state?.route_command || '').replace(/^\$/, '').toUpperCase();
|
|
16
|
+
return mode === 'NARUTO' || route === 'NARUTO' || state?.subagents_required === true;
|
|
17
|
+
}
|
|
18
|
+
function spawnTask(input) {
|
|
19
|
+
return [input.message, input.prompt, input.task, input.agent_type, input.agentType]
|
|
20
|
+
.map((value) => String(value || '').trim())
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
.join('\n')
|
|
23
|
+
.slice(0, 1200);
|
|
24
|
+
}
|
|
25
|
+
export async function jevSpawnModelRewrite(root, state, payload) {
|
|
26
|
+
if (!narutoParent(state))
|
|
27
|
+
return null;
|
|
28
|
+
const input = spawnInput(payload);
|
|
29
|
+
if (!input)
|
|
30
|
+
return null;
|
|
31
|
+
const agent = String(input.agent_type || input.agentType || '').trim();
|
|
32
|
+
if (agent) {
|
|
33
|
+
const preferences = await readRoleModelPreferences().catch(() => null);
|
|
34
|
+
if (preferences?.store.roles[agent])
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const task = spawnTask(input);
|
|
38
|
+
if (!task)
|
|
39
|
+
return null;
|
|
40
|
+
const decision = await consultJevTurnModel({ root, prompt: task, roleId: 'spawn' }).catch(() => null);
|
|
41
|
+
if (!decision?.model || !decision.effort)
|
|
42
|
+
return null;
|
|
43
|
+
if (input.model === decision.model && input.reasoning_effort === decision.effort)
|
|
44
|
+
return null;
|
|
45
|
+
return {
|
|
46
|
+
...input,
|
|
47
|
+
model: decision.model,
|
|
48
|
+
reasoning_effort: decision.effort
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -22,6 +22,7 @@ import { codePackFreshnessNote } from './hooks-runtime/code-pack-freshness-prefl
|
|
|
22
22
|
import { claimHookInvocation } from './hooks-runtime/hook-invocation-dedupe.js';
|
|
23
23
|
import { armLightTurnStopBypass, clearLightTurnStopBypass, consumeLightTurnStopBypass, hasMatchingLightTurnStopBypass } from './hooks-runtime/light-turn.js';
|
|
24
24
|
import { evaluateHookNarutoDecisionGate, looksLikeActiveContinuationPrompt } from './hooks-runtime/naruto-decision-gate.js';
|
|
25
|
+
import { consultJevTurnModel } from './decisions/integration.js';
|
|
25
26
|
import { ensureOfficialSubagentArtifactDirConfined, inspectActiveOfficialSubagentWorkflow, recordOfficialSubagentLifecycleCaptureFailure, officialSubagentArtifactDir, recordAndRefreshSubagentEvidence, refreshOfficialSubagentCompletionArtifacts } from './hooks-runtime/official-subagent-lifecycle.js';
|
|
26
27
|
import { finalizationRepeatDecision } from './hooks-runtime/stop-repeat-guard.js';
|
|
27
28
|
import { armCodexGitActionStopBypass, consumeCodexGitActionStopBypass, consumeLightRouteStop, hasCompletionSummary, hasDfixLightCompletion, hasHonestMode, hasHonestModeUnresolvedGap, honestModeLoopbackBudgetExhausted, recordHonestModeLoopback, recordHonestModeTerminalUnverified, resolveHonestModeLoopback, shouldLoopBackAfterHonestMode, successfulAppNarutoStopNeedsVisibleSummary } from './hooks-runtime/stop-finalization.js';
|
|
@@ -29,6 +30,7 @@ import { activeNarutoParentLaunchMissionId, claimStandaloneParentHostCapabilityR
|
|
|
29
30
|
import { classifyTaskProfile } from './runtime/task-profile.js';
|
|
30
31
|
import { resolveSubagentThreadBudget } from './subagents/thread-budget.js';
|
|
31
32
|
import { readOfficialSubagentConfig } from './subagents/official-subagent-config.js';
|
|
33
|
+
import { jevSpawnModelRewrite } from './hooks-runtime/jev-spawn-routing.js';
|
|
32
34
|
import { subagentSpawnPolicyBlockReason } from './hooks-runtime/subagent-spawn-policy.js';
|
|
33
35
|
import { withFileLock } from './locks/file-lock.js';
|
|
34
36
|
import { ensureConfinedDirectory, inspectConfinedPath, removeManagedPathVerified } from './managed-path-safety.js';
|
|
@@ -120,7 +122,8 @@ export async function evaluateHookPayload(name, payload = {}, opts = {}) {
|
|
|
120
122
|
const withNarutoDecision = (result) => ({ ...result, sksNarutoDecision });
|
|
121
123
|
if (name === 'user-prompt-submit') {
|
|
122
124
|
const result = await hookUserPrompt(root, state, payload, noQuestion, sessionKey);
|
|
123
|
-
const
|
|
125
|
+
const withJev = await attachJevTurnRouting(root, payload, result);
|
|
126
|
+
const withSkillContext = await attachAuthoritativeSksSkillContext(root, state, payload, withJev);
|
|
124
127
|
return withNarutoDecision(attachOfficialSubagentSpawnCompatibilityContext(state, payload, withSkillContext));
|
|
125
128
|
}
|
|
126
129
|
if (name === 'session-start' || name === 'pre-compact' || name === 'post-compact') {
|
|
@@ -233,6 +236,28 @@ async function hookSubagentStart(root, state, payload = {}, sessionKey = null) {
|
|
|
233
236
|
const additionalContext = [coreEngineeringDirectiveReferenceText(), resourceGuard, routingContext, active, skillContext].filter(Boolean).join('\n\n');
|
|
234
237
|
return { continue: true, additionalContext, ...(skillBlockers.length ? { silent: true } : {}) };
|
|
235
238
|
}
|
|
239
|
+
async function attachJevTurnRouting(root, payload, result) {
|
|
240
|
+
if (!result || result.decision === 'block')
|
|
241
|
+
return result;
|
|
242
|
+
const prompt = stripVisibleDecisionAnswerBlocks(extractUserPrompt(payload));
|
|
243
|
+
if (!String(prompt || '').trim())
|
|
244
|
+
return result;
|
|
245
|
+
const decision = await consultJevTurnModel({ root, prompt }).catch(() => null);
|
|
246
|
+
if (!decision?.called)
|
|
247
|
+
return result;
|
|
248
|
+
const line = decision.model
|
|
249
|
+
? `Jev sealed this turn to ${decision.model}. Use that sealed model and do not reclassify it.`
|
|
250
|
+
: '';
|
|
251
|
+
if (!line)
|
|
252
|
+
return { ...result, jev_turn: decision };
|
|
253
|
+
const additionalContext = [result.additionalContext, line].filter(Boolean).join('\n\n');
|
|
254
|
+
return {
|
|
255
|
+
...result,
|
|
256
|
+
additionalContext,
|
|
257
|
+
jev_turn: decision,
|
|
258
|
+
...(result.systemMessage ? { systemMessage: visibleHookMessage('user-prompt-submit', additionalContext) } : {})
|
|
259
|
+
};
|
|
260
|
+
}
|
|
236
261
|
async function hookUserPrompt(root, state, payload, noQuestion, sessionKey = null) {
|
|
237
262
|
await clearLightTurnStopBypass(root, { sessionKey }).catch(() => undefined);
|
|
238
263
|
const submittedPrompt = stripVisibleDecisionAnswerBlocks(extractUserPrompt(payload));
|
|
@@ -572,7 +597,11 @@ async function consumeActiveOfficialWorkflowQueue(root, missionId, workflowRunId
|
|
|
572
597
|
}
|
|
573
598
|
}
|
|
574
599
|
async function hookPreTool(root, state, payload, noQuestion, sessionKey = null) {
|
|
575
|
-
const
|
|
600
|
+
const jevSpawnInput = await jevSpawnModelRewrite(root, state, payload).catch(() => null);
|
|
601
|
+
const spawnPayload = jevSpawnInput
|
|
602
|
+
? { ...payload, tool_input: jevSpawnInput, toolInput: jevSpawnInput }
|
|
603
|
+
: payload;
|
|
604
|
+
const spawnPolicyBlock = subagentSpawnPolicyBlockReason(spawnPayload);
|
|
576
605
|
if (spawnPolicyBlock)
|
|
577
606
|
return { decision: 'block', permissionDecision: 'deny', reason: spawnPolicyBlock };
|
|
578
607
|
const artifactDir = officialSubagentArtifactDir(root, state, sessionKey);
|
|
@@ -641,15 +670,20 @@ async function hookPreTool(root, state, payload, noQuestion, sessionKey = null)
|
|
|
641
670
|
const waveGuidance = await parentWaveGuidanceContext(root, state, sessionKey).catch(() => '');
|
|
642
671
|
const additionalContext = [skillRefresh.context, waveGuidance].filter(Boolean).join('\n\n');
|
|
643
672
|
if (additionalContext) {
|
|
644
|
-
return {
|
|
673
|
+
return withJevSpawnRewrite({
|
|
645
674
|
continue: true,
|
|
646
675
|
additionalContext,
|
|
647
676
|
...(waveGuidance
|
|
648
677
|
? { systemMessage: visibleHookMessage('pre-tool', 'SKS Naruto wave lifecycle requires root-parent follow-up.') }
|
|
649
678
|
: { silent: true })
|
|
650
|
-
};
|
|
679
|
+
}, jevSpawnInput);
|
|
651
680
|
}
|
|
652
|
-
return { continue: true };
|
|
681
|
+
return withJevSpawnRewrite({ continue: true }, jevSpawnInput);
|
|
682
|
+
}
|
|
683
|
+
function withJevSpawnRewrite(result, updatedInput) {
|
|
684
|
+
if (!updatedInput || result?.decision === 'block' || result?.permissionDecision === 'deny')
|
|
685
|
+
return result;
|
|
686
|
+
return { ...result, permissionDecision: 'allow', updatedInput };
|
|
653
687
|
}
|
|
654
688
|
async function parentWaveGuidanceContext(root, state = {}, sessionKey = null) {
|
|
655
689
|
if (!state?.mission_id && !state?.official_subagent_run_id)
|
package/dist/core/routes.js
CHANGED
|
@@ -1211,6 +1211,9 @@ export function narutoDecisionForRoute(route, prompt = '', profile = classifyTas
|
|
|
1211
1211
|
return narutoRouteDecision('none', routeId, profile, `task_profile_${profile}_bypass`, true);
|
|
1212
1212
|
}
|
|
1213
1213
|
if (profile === 'bounded-work') {
|
|
1214
|
+
if (routeId === 'Naruto') {
|
|
1215
|
+
return narutoRouteDecision('generic_naruto', routeId, profile, 'naruto_parent_orchestrates', false);
|
|
1216
|
+
}
|
|
1214
1217
|
return narutoRouteDecision('none', routeId, profile, 'task_profile_bounded_work_parent_owned', false);
|
|
1215
1218
|
}
|
|
1216
1219
|
if (profile === 'parallel-read' || profile === 'parallel-write' || profile === 'high-risk') {
|
|
@@ -461,6 +461,12 @@ function applyOfficialSubagentDecision(derived, decided) {
|
|
|
461
461
|
: { ...derived.fanoutPolicy };
|
|
462
462
|
if (selectedRouting)
|
|
463
463
|
fanoutPolicy = { ...fanoutPolicy, jev_selected_routing: selectedRouting.id };
|
|
464
|
+
const omitted = new Set(decided.omittedRoutingRoles || []);
|
|
465
|
+
if (omitted.size)
|
|
466
|
+
fanoutPolicy = { ...fanoutPolicy, jev_omitted_roles: [...omitted] };
|
|
467
|
+
const recommendedAgents = omitted.size > 0 && derived.suggestedAgents.some((name) => !omitted.has(name))
|
|
468
|
+
? derived.suggestedAgents.filter((name) => !omitted.has(name))
|
|
469
|
+
: derived.suggestedAgents;
|
|
464
470
|
const routingPreferences = selectedRouting
|
|
465
471
|
? Object.fromEntries(Object.entries(selectedRouting.efforts)
|
|
466
472
|
.filter(([name]) => !derived.roleModelPreferences.store.roles[name])
|
|
@@ -483,7 +489,7 @@ function applyOfficialSubagentDecision(derived, decided) {
|
|
|
483
489
|
waveCount: budget.waveCount,
|
|
484
490
|
capacity: budget.capacity,
|
|
485
491
|
triwikiAttention: attention,
|
|
486
|
-
recommendedAgents
|
|
492
|
+
recommendedAgents,
|
|
487
493
|
roleModelPreferences: {
|
|
488
494
|
...derived.roleModelPreferences.store.roles,
|
|
489
495
|
...routingPreferences
|
|
@@ -519,6 +525,7 @@ function applyOfficialSubagentDecision(derived, decided) {
|
|
|
519
525
|
}),
|
|
520
526
|
triwiki_attention: attention,
|
|
521
527
|
agents,
|
|
528
|
+
suggested_agents: recommendedAgents,
|
|
522
529
|
fanout_policy: fanoutPolicy,
|
|
523
530
|
capacity_controller: budget.capacity,
|
|
524
531
|
jev_decision: decided.receipt,
|
|
@@ -53,6 +53,8 @@ export function buildOfficialSubagentPrompt(input) {
|
|
|
53
53
|
const spawnModelRouting = renderSpawnModelRouting(narutoChildren);
|
|
54
54
|
const childModelRules = narutoChildren
|
|
55
55
|
? [
|
|
56
|
+
'- the parent orchestrates only: decompose the goal, assign disjoint slices, spawn children, and integrate their results',
|
|
57
|
+
'- do not implement the assigned slice work in the parent thread',
|
|
56
58
|
'- use the model and reasoning_effort named in each slice spawn contract',
|
|
57
59
|
'- sealed child models are gpt-5.6-luna, gpt-5.6-sol, gpt-5.6-terra, and gpt-6-astra',
|
|
58
60
|
'- keep a stored user role-model preference for that role'
|
package/dist/core/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '10.3.
|
|
1
|
+
export const PACKAGE_VERSION = '10.3.2';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "10.3.
|
|
4
|
+
"version": "10.3.2",
|
|
5
5
|
"description": "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.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
|