sneakoscope 4.8.3 β 4.8.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 +1 -1
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/bin/sks.js +1 -1
- package/dist/core/codex-app/sks-menubar.js +7 -1
- package/dist/core/commands/naruto-command.js +14 -1
- package/dist/core/commands/pipeline-command.js +2 -2
- package/dist/core/commands/status-command.js +3 -2
- package/dist/core/fsx.js +1 -1
- package/dist/core/hooks-runtime.js +8 -4
- package/dist/core/mission.js +41 -4
- package/dist/core/pipeline-internals/runtime-core.js +10 -7
- package/dist/core/pipeline-internals/runtime-gates.js +17 -2
- package/dist/core/routes.js +11 -5
- package/dist/core/stop-gate/stop-gate-resolver.js +3 -0
- package/dist/core/version.js +1 -1
- package/dist/scripts/sks-menubar-install-check.js +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ sks seo-geo-optimizer apply latest --mode seo --apply --json
|
|
|
49
49
|
sks seo-geo-optimizer audit --mode geo --target package --offline --json
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
> π **Current release: `v4.8.
|
|
52
|
+
> π **Current release: `v4.8.5`** β full release history lives in [CHANGELOG.md](CHANGELOG.md). This README documents how Sneakoscope works today, not its version-by-version changes. Release readiness is tracked in [docs/release-readiness.md](docs/release-readiness.md).
|
|
53
53
|
|
|
54
54
|
## π₯ Parallelism, UX, And Integrations
|
|
55
55
|
|
|
@@ -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 4.8.
|
|
7
|
+
Some("--version") => println!("sks-rs 4.8.5"),
|
|
8
8
|
Some("compact-info") => {
|
|
9
9
|
let mut input = String::new();
|
|
10
10
|
let _ = io::stdin().read_to_string(&mut input);
|
package/dist/bin/sks.js
CHANGED
|
@@ -8,6 +8,7 @@ const CONTROL_CENTER_PREFERRED_POSITION = 360;
|
|
|
8
8
|
const MENU_ITEMS = [
|
|
9
9
|
'Use codex-lb',
|
|
10
10
|
'Use ChatGPT OAuth',
|
|
11
|
+
'Set codex-lb Domain and Key',
|
|
11
12
|
'Set OpenRouter Key and GLM Profiles',
|
|
12
13
|
'Fast Check',
|
|
13
14
|
'SKS Version Check',
|
|
@@ -294,7 +295,7 @@ func runInTerminal(_ command: String) {
|
|
|
294
295
|
.replacingOccurrences(of: "\\\\", with: "\\\\\\\\")
|
|
295
296
|
.replacingOccurrences(of: "\\\"", with: "\\\\\\\"")
|
|
296
297
|
let script = "tell application \\"Terminal\\" to activate\\n" +
|
|
297
|
-
"tell application \\"Terminal\\" to do script \\"
|
|
298
|
+
"tell application \\"Terminal\\" to do script \\"\\(escaped)\\""
|
|
298
299
|
runDetached("/usr/bin/osascript", ["-e", script])
|
|
299
300
|
}
|
|
300
301
|
|
|
@@ -313,6 +314,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
|
|
|
313
314
|
let menu = NSMenu()
|
|
314
315
|
add(menu, "Use codex-lb", #selector(useCodexLb))
|
|
315
316
|
add(menu, "Use ChatGPT OAuth", #selector(useChatGptOAuth))
|
|
317
|
+
add(menu, "Set codex-lb Domain and Key", #selector(setCodexLbDomainAndKey))
|
|
316
318
|
menu.addItem(NSMenuItem.separator())
|
|
317
319
|
add(menu, "Set OpenRouter Key and GLM Profiles", #selector(setOpenRouterKey))
|
|
318
320
|
add(menu, "Fast Check", #selector(fastCheck))
|
|
@@ -360,6 +362,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
|
|
|
360
362
|
runSks(["codex-lb", "use-oauth"])
|
|
361
363
|
}
|
|
362
364
|
|
|
365
|
+
@objc func setCodexLbDomainAndKey() {
|
|
366
|
+
runSks(["codex-lb", "setup"])
|
|
367
|
+
}
|
|
368
|
+
|
|
363
369
|
@objc func setOpenRouterKey() {
|
|
364
370
|
let command = "printf 'Paste OpenRouter key, then press Return: '; read -r key; printf '%s\\\\n' \\"$key\\" | \\(shellQuote(actionScript)) codex-app set-openrouter-key --api-key-stdin; \\(shellQuote(actionScript)) codex-app glm-profile install; echo; echo 'OpenRouter/GLM update finished. Restart Codex if the model picker was already open.'"
|
|
365
371
|
runInTerminal(command)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { createMission, findLatestMission, loadMission, setCurrent } from '../mission.js';
|
|
2
|
+
import { createMission, findLatestMission, loadMission, missionExists, setCurrent } from '../mission.js';
|
|
3
3
|
import { nowIso, readJson, sksRoot, writeJsonAtomic } from '../fsx.js';
|
|
4
4
|
import { runNativeAgentOrchestrator } from '../agents/agent-orchestrator.js';
|
|
5
5
|
import { classifyOllamaWorkerSlice } from '../agents/agent-runner-ollama.js';
|
|
@@ -692,18 +692,28 @@ async function narutoStatus(parsed) {
|
|
|
692
692
|
const id = parsed.missionId && parsed.missionId !== 'latest' ? parsed.missionId : await findLatestMission(root);
|
|
693
693
|
if (!id)
|
|
694
694
|
return emit(parsed, { schema: NARUTO_RESULT_SCHEMA, ok: false, action: 'status', status: 'missing_mission' }, () => console.log('No Naruto mission found.'));
|
|
695
|
+
if (!(await missionExists(root, id)))
|
|
696
|
+
return emit(parsed, { schema: NARUTO_RESULT_SCHEMA, ok: false, action: 'status', mission_id: id, status: 'stale_missing_mission' }, () => console.log('Naruto mission is stale or missing: ' + id));
|
|
695
697
|
const { dir } = await loadMission(root, id);
|
|
698
|
+
const gate = await readJson(path.join(dir, 'naruto-gate.json'), null);
|
|
696
699
|
const proof = await readJson(path.join(dir, 'agents', 'agent-proof-evidence.json'), null);
|
|
697
700
|
const scheduler = await readJson(path.join(dir, 'agents', 'agent-scheduler-state.json'), null);
|
|
698
701
|
const roleDistribution = await readJson(path.join(dir, 'agents', 'naruto-role-distribution.json'), null);
|
|
699
702
|
const workGraph = await readJson(path.join(dir, 'agents', 'naruto-work-graph.json'), null);
|
|
700
703
|
const governor = await readJson(path.join(dir, 'agents', 'naruto-concurrency-governor.json'), null);
|
|
704
|
+
const gateBlockers = Array.isArray(gate?.blockers) ? gate.blockers : [];
|
|
705
|
+
const preparedNotStarted = !proof && gateBlockers.includes('naruto_run_not_started');
|
|
701
706
|
const summary = {
|
|
702
707
|
schema: NARUTO_RESULT_SCHEMA,
|
|
703
708
|
ok: proof !== null,
|
|
704
709
|
action: 'status',
|
|
705
710
|
mission_id: id,
|
|
711
|
+
status: preparedNotStarted ? 'prepared_not_started' : (proof ? 'recorded' : 'missing_proof'),
|
|
706
712
|
proof: proof?.status || 'missing',
|
|
713
|
+
gate: gate ? {
|
|
714
|
+
passed: gate.passed === true,
|
|
715
|
+
blockers: gateBlockers
|
|
716
|
+
} : null,
|
|
707
717
|
target_active_slots: scheduler?.target_active_slots ?? null,
|
|
708
718
|
max_active_slots: scheduler?.max_active_slots ?? null,
|
|
709
719
|
completed: scheduler?.completed_count ?? null,
|
|
@@ -719,7 +729,10 @@ async function narutoStatus(parsed) {
|
|
|
719
729
|
};
|
|
720
730
|
return emit(parsed, summary, () => {
|
|
721
731
|
console.log('π₯ Naruto mission: ' + id);
|
|
732
|
+
console.log('Status: ' + summary.status);
|
|
722
733
|
console.log('Proof: ' + summary.proof);
|
|
734
|
+
if (gateBlockers.length)
|
|
735
|
+
console.log('Gate blockers: ' + gateBlockers.join(', '));
|
|
723
736
|
if (summary.target_active_slots !== null)
|
|
724
737
|
console.log('Active clones: ' + summary.target_active_slots + ' / max ' + summary.max_active_slots);
|
|
725
738
|
if (roleDistribution?.entries)
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { projectRoot, readJson } from '../fsx.js';
|
|
3
|
-
import { missionDir, stateFile } from '../mission.js';
|
|
3
|
+
import { missionDir, normalizeCurrentState, stateFile } from '../mission.js';
|
|
4
4
|
import { PIPELINE_PLAN_ARTIFACT, projectGateStatus, writePipelinePlan } from '../pipeline.js';
|
|
5
5
|
import { routePrompt } from '../routes.js';
|
|
6
6
|
import { flag, positionalArgs, readFlagValue, resolveMissionId } from './command-utils.js';
|
|
7
7
|
export async function pipelineCommand(args = []) {
|
|
8
8
|
const root = await projectRoot();
|
|
9
9
|
const action = args[0] || 'status';
|
|
10
|
-
const state = await readJson(stateFile(root), {});
|
|
10
|
+
const state = await normalizeCurrentState(root, await readJson(stateFile(root), {}));
|
|
11
11
|
if (action === 'status') {
|
|
12
12
|
const result = { schema: 'sks.pipeline-status.v1', ok: true, state };
|
|
13
13
|
if (flag(args, '--json'))
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { projectRoot, readJson } from '../fsx.js';
|
|
3
|
-
import { stateFile } from '../mission.js';
|
|
3
|
+
import { normalizeCurrentState, stateFile } from '../mission.js';
|
|
4
4
|
import { readRouteProof } from '../proof/proof-reader.js';
|
|
5
5
|
import { latestTrustReport } from '../trust-kernel/trust-report.js';
|
|
6
6
|
import { flag } from './command-utils.js';
|
|
7
7
|
export async function statusCommand(args = []) {
|
|
8
8
|
const root = await projectRoot();
|
|
9
|
-
const state = await readJson(stateFile(root), {});
|
|
9
|
+
const state = await normalizeCurrentState(root, await readJson(stateFile(root), {}));
|
|
10
10
|
const missionId = state.mission_id || null;
|
|
11
11
|
const proof = missionId ? await readRouteProof(root, missionId) : null;
|
|
12
12
|
const trust = missionId ? await latestTrustReport(root, missionId) : null;
|
|
@@ -22,6 +22,7 @@ export async function statusCommand(args = []) {
|
|
|
22
22
|
agent_status: proof?.evidence?.agents?.status || (state.agents_required === false ? 'not_required' : 'not_recorded'),
|
|
23
23
|
image_voxel_status: proof?.evidence?.image_voxels?.status || 'not_recorded',
|
|
24
24
|
db_safety_status: proof?.evidence?.db || proof?.evidence?.db_safety ? 'recorded' : 'not_recorded',
|
|
25
|
+
stale_mission: state.stale_mission || null,
|
|
25
26
|
next_action: nextAction(state, trust, proof),
|
|
26
27
|
files: missionId ? {
|
|
27
28
|
mission: path.join(root, '.sneakoscope', 'missions', missionId),
|
package/dist/core/fsx.js
CHANGED
|
@@ -5,7 +5,7 @@ import os from 'node:os';
|
|
|
5
5
|
import crypto from 'node:crypto';
|
|
6
6
|
import { spawn } from 'node:child_process';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
8
|
-
export const PACKAGE_VERSION = '4.8.
|
|
8
|
+
export const PACKAGE_VERSION = '4.8.5';
|
|
9
9
|
export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
|
|
10
10
|
export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
|
|
11
11
|
export function nowIso() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { projectRoot, readJson, readText, writeJsonAtomic, appendJsonl, readStdin, nowIso, runProcess, sha256, packageRoot, tmpdir } from './fsx.js';
|
|
3
3
|
import { looksInteractiveCommand, interactiveCommandReason } from './no-question-guard.js';
|
|
4
|
-
import { missionDir, setCurrent, stateFile } from './mission.js';
|
|
4
|
+
import { missionDir, normalizeCurrentState, setCurrent, stateFile } from './mission.js';
|
|
5
5
|
import { checkDbOperation, dbBlockReason, handleMadSksUserConfirmation } from './db-safety.js';
|
|
6
6
|
import { maybeRecordMadDbToolResultFromToolUse } from './mad-db/mad-db-result-lifecycle.js';
|
|
7
7
|
import { checkHarnessModification, harnessGuardBlockReason, isHarnessSourceProject } from './harness-guard.js';
|
|
@@ -11,7 +11,7 @@ import { activeRouteContext, evaluateStop, prepareRoute, promptPipelineContext a
|
|
|
11
11
|
import { localizedFinalizationReason } from './language-preference.js';
|
|
12
12
|
import { classifyToolError } from './evaluation.js';
|
|
13
13
|
import { REQUIRED_CODEX_MODEL, isForbiddenCodexModel } from './codex-model-guard.js';
|
|
14
|
-
import { dollarCommand, routeRequiresSubagents, stripVisibleDecisionAnswerBlocks } from './routes.js';
|
|
14
|
+
import { dollarCommand, looksLikeTeamDefaultWork, routeRequiresSubagents, stripVisibleDecisionAnswerBlocks } from './routes.js';
|
|
15
15
|
import { leanEngineeringCompactText } from './lean-engineering-policy.js';
|
|
16
16
|
import { appendMissionStatus } from './recallpulse.js';
|
|
17
17
|
import { scanAgentTextForRecursion } from './agents/agent-recursion-guard.js';
|
|
@@ -42,7 +42,7 @@ async function loadHookPayload() {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
async function loadState(root) {
|
|
45
|
-
return readJson(stateFile(root), {});
|
|
45
|
+
return normalizeCurrentState(root, await readJson(stateFile(root), {}));
|
|
46
46
|
}
|
|
47
47
|
function isNoQuestionRunning(state) {
|
|
48
48
|
return (state.mode === 'RESEARCH' && state.phase === 'RESEARCH_RUNNING_NO_QUESTIONS')
|
|
@@ -346,6 +346,8 @@ function shouldPrepareFreshRouteOnActivePrompt(prompt, route = null, opts = {})
|
|
|
346
346
|
return false;
|
|
347
347
|
if (looksLikeActiveContinuationPrompt(prompt))
|
|
348
348
|
return false;
|
|
349
|
+
if (route.id === 'SKS' && looksLikeTeamDefaultWork(prompt))
|
|
350
|
+
return true;
|
|
349
351
|
return routeRequiresSubagents(route, prompt);
|
|
350
352
|
}
|
|
351
353
|
function looksLikeActiveContinuationPrompt(prompt = '') {
|
|
@@ -1259,7 +1261,9 @@ function visibleHookMessage(name, text = '') {
|
|
|
1259
1261
|
return 'SKS: native Computer Use lane injected; defer TriWiki/Honest Mode to final closeout.';
|
|
1260
1262
|
if (body.includes('MANDATORY ambiguity-removal gate') || body.includes('VISIBLE RESPONSE CONTRACT') || body.includes('Required questions still pending'))
|
|
1261
1263
|
return 'SKS: stale clarification gate detected; continue from inferred route contract.';
|
|
1262
|
-
if (body.includes('$
|
|
1264
|
+
if (body.includes('$SKS route prepared') || body.includes('SKS skill-first pipeline active. Route: $SKS'))
|
|
1265
|
+
return 'SKS: SKS fast route injected; native sessions optional.';
|
|
1266
|
+
if (body.includes('$Team route prepared') || body.includes('Active Team mission'))
|
|
1263
1267
|
return 'SKS: Team route, live transcript, and native multi-session plan injected.';
|
|
1264
1268
|
if (body.includes('$Research route prepared'))
|
|
1265
1269
|
return 'SKS: Research route, xhigh Eureka agent council, source/debate ledgers, paper output, and falsification gate injected.';
|
package/dist/core/mission.js
CHANGED
|
@@ -10,6 +10,7 @@ export function sineDir(root) { return path.join(root, '.sneakoscope'); }
|
|
|
10
10
|
export function missionsDir(root) { return path.join(sineDir(root), 'missions'); }
|
|
11
11
|
export function missionDir(root, id) { return path.join(missionsDir(root), id); }
|
|
12
12
|
export function stateFile(root) { return path.join(sineDir(root), 'state', 'current.json'); }
|
|
13
|
+
export function missionFile(root, id) { return path.join(missionDir(root, id), 'mission.json'); }
|
|
13
14
|
export async function createMission(root, { mode, prompt }) {
|
|
14
15
|
const id = missionId();
|
|
15
16
|
const dir = missionDir(root, id);
|
|
@@ -33,9 +34,42 @@ export async function createMission(root, { mode, prompt }) {
|
|
|
33
34
|
}
|
|
34
35
|
export async function loadMission(root, id) {
|
|
35
36
|
const dir = missionDir(root, id);
|
|
36
|
-
const mission = await readJson(
|
|
37
|
+
const mission = await readJson(missionFile(root, id));
|
|
37
38
|
return { id, dir, mission };
|
|
38
39
|
}
|
|
40
|
+
export async function missionExists(root, id) {
|
|
41
|
+
return Boolean(id) && await exists(missionFile(root, id));
|
|
42
|
+
}
|
|
43
|
+
export async function normalizeCurrentState(root, state = null, opts = {}) {
|
|
44
|
+
const current = state || await readJson(stateFile(root), {});
|
|
45
|
+
const id = current?.mission_id;
|
|
46
|
+
if (!id || await missionExists(root, id))
|
|
47
|
+
return current || {};
|
|
48
|
+
const detectedAt = nowIso();
|
|
49
|
+
const repaired = {
|
|
50
|
+
mission_id: null,
|
|
51
|
+
mode: null,
|
|
52
|
+
route: null,
|
|
53
|
+
route_command: null,
|
|
54
|
+
phase: 'IDLE',
|
|
55
|
+
stop_gate: null,
|
|
56
|
+
implementation_allowed: false,
|
|
57
|
+
questions_allowed: true,
|
|
58
|
+
updated_at: detectedAt,
|
|
59
|
+
stale_mission: {
|
|
60
|
+
mission_id: id,
|
|
61
|
+
reason: 'mission_json_missing',
|
|
62
|
+
detected_at: detectedAt,
|
|
63
|
+
previous_mode: current.mode || null,
|
|
64
|
+
previous_route: current.route_command || current.route || null,
|
|
65
|
+
previous_phase: current.phase || null,
|
|
66
|
+
previous_stop_gate: current.stop_gate || null
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
if (opts.repair !== false)
|
|
70
|
+
await writeJsonAtomic(stateFile(root), repaired);
|
|
71
|
+
return repaired;
|
|
72
|
+
}
|
|
39
73
|
export async function findLatestMission(root) {
|
|
40
74
|
const dir = missionsDir(root);
|
|
41
75
|
if (!(await exists(dir)))
|
|
@@ -45,8 +79,10 @@ export async function findLatestMission(root) {
|
|
|
45
79
|
const ids = entries.filter((e) => e.isDirectory() && e.name.startsWith('M-')).map((e) => e.name);
|
|
46
80
|
const candidates = await Promise.all(ids.map(async (id) => {
|
|
47
81
|
const dirPath = missionDir(root, id);
|
|
82
|
+
if (!(await missionExists(root, id)))
|
|
83
|
+
return null;
|
|
48
84
|
const stat = await fs.stat(dirPath).catch(() => null);
|
|
49
|
-
const mission = await readJson(
|
|
85
|
+
const mission = await readJson(missionFile(root, id), {}).catch(() => ({}));
|
|
50
86
|
const createdMs = Date.parse(mission.created_at || mission.updated_at || '');
|
|
51
87
|
return {
|
|
52
88
|
id,
|
|
@@ -54,8 +90,9 @@ export async function findLatestMission(root) {
|
|
|
54
90
|
mtimeMs: stat?.mtimeMs || 0
|
|
55
91
|
};
|
|
56
92
|
}));
|
|
57
|
-
|
|
58
|
-
|
|
93
|
+
const present = candidates.filter(Boolean);
|
|
94
|
+
present.sort((a, b) => (a.createdMs - b.createdMs) || (a.mtimeMs - b.mtimeMs) || a.id.localeCompare(b.id));
|
|
95
|
+
return present.at(-1)?.id || null;
|
|
59
96
|
}
|
|
60
97
|
export async function setCurrent(root, patch, opts = {}) {
|
|
61
98
|
const current = opts.replace ? {} : await readJson(stateFile(root), {});
|
|
@@ -2,7 +2,7 @@ import fsp from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { appendJsonl, exists, nowIso, readJson, readText, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
|
|
4
4
|
import { containsUserQuestion, noQuestionContinuationReason } from '../no-question-guard.js';
|
|
5
|
-
import { createMission, missionDir, setCurrent } from '../mission.js';
|
|
5
|
+
import { createMission, missionDir, missionExists, setCurrent } from '../mission.js';
|
|
6
6
|
import { buildQuestionSchemaForRoute, buildRequestIntake, REQUEST_INTAKE_ARTIFACT, writeQuestions } from '../questions.js';
|
|
7
7
|
import { sealContract } from '../decision-contract.js';
|
|
8
8
|
import { scanDbSafety } from '../db-safety.js';
|
|
@@ -26,7 +26,7 @@ import { prepareMadDbMission } from '../mad-db/mad-db-coordinator.js';
|
|
|
26
26
|
import { AGENT_INTAKE_STAGE_ID, AGENT_COUNT } from '../agents/agent-schema.js';
|
|
27
27
|
import { normalizeAgentPolicy, routeRequiresAgentIntake, agentPipelineStage } from '../agents/agent-plan.js';
|
|
28
28
|
import { readAgentGateStatus } from '../agents/agent-gate.js';
|
|
29
|
-
import { CODEX_APP_IMAGE_GENERATION_DOC_URL, CODEX_COMPUTER_USE_EVIDENCE_SOURCE, CODEX_COMPUTER_USE_ONLY_POLICY, CODEX_IMAGEGEN_REQUIRED_POLICY, CODEX_WEB_VERIFICATION_POLICY, FROM_CHAT_IMG_CHECKLIST_ARTIFACT, FROM_CHAT_IMG_COVERAGE_ARTIFACT, FROM_CHAT_IMG_QA_LOOP_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS, SOLUTION_SCOUT_STAGE_ID, chatCaptureIntakeText, context7RequirementText, dollarCommand, evidenceMentionsForbiddenBrowserAutomation, getdesignReferencePolicyText, hasFromChatImgSignal, hasMadSksSignal, imageUxReviewPipelinePolicyText, leanEngineeringCompactText, looksLikeProblemSolvingRequest, pptPipelineAllowlistPolicyText, reflectionRequiredForRoute, reasoningInstruction, routeNeedsContext7, routePrompt, routeReasoning, routeRequiresSubagents, solutionScoutPolicyText, stripDollarCommand, stripMadSksSignal, stripVisibleDecisionAnswerBlocks, subagentExecutionPolicyText, stackCurrentDocsPolicyText, triwikiContextTracking, triwikiContextTrackingText, triwikiStagePolicyText } from '../routes.js';
|
|
29
|
+
import { CODEX_APP_IMAGE_GENERATION_DOC_URL, CODEX_COMPUTER_USE_EVIDENCE_SOURCE, CODEX_COMPUTER_USE_ONLY_POLICY, CODEX_IMAGEGEN_REQUIRED_POLICY, CODEX_WEB_VERIFICATION_POLICY, FROM_CHAT_IMG_CHECKLIST_ARTIFACT, FROM_CHAT_IMG_COVERAGE_ARTIFACT, FROM_CHAT_IMG_QA_LOOP_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS, SOLUTION_SCOUT_STAGE_ID, chatCaptureIntakeText, context7RequirementText, dollarCommand, evidenceMentionsForbiddenBrowserAutomation, getdesignReferencePolicyText, hasFromChatImgSignal, hasMadSksSignal, imageUxReviewPipelinePolicyText, leanEngineeringCompactText, looksLikeProblemSolvingRequest, looksLikeTeamDefaultWork, pptPipelineAllowlistPolicyText, reflectionRequiredForRoute, reasoningInstruction, routeNeedsContext7, routePrompt, routeReasoning, routeRequiresSubagents, solutionScoutPolicyText, stripDollarCommand, stripMadSksSignal, stripVisibleDecisionAnswerBlocks, subagentExecutionPolicyText, stackCurrentDocsPolicyText, triwikiContextTracking, triwikiContextTrackingText, triwikiStagePolicyText } from '../routes.js';
|
|
30
30
|
import { normalizeLeanDecision, validateLeanDecision } from '../lean-engineering-policy.js';
|
|
31
31
|
import { TEAM_DECOMPOSITION_ARTIFACT, TEAM_GRAPH_ARTIFACT, TEAM_INBOX_DIR, TEAM_RUNTIME_TASKS_ARTIFACT, teamRuntimePlanMetadata, teamRuntimeRequiredArtifacts, validateTeamRuntimeArtifacts, writeTeamRuntimeArtifacts } from '../team-dag.js';
|
|
32
32
|
import { formatAgentReasoning, formatRoleCounts, initTeamLive, parseTeamSpecText, teamReasoningPolicy } from '../team-live.js';
|
|
@@ -54,7 +54,7 @@ const HARD_BLOCKER_ARTIFACT = 'hard-blocker.json';
|
|
|
54
54
|
const DEFAULT_COMPLIANCE_LOOP_LIMIT = 3;
|
|
55
55
|
const CLARIFICATION_BYPASS_ROUTES = new Set(['Answer', 'DFix', 'Help', 'Wiki', 'ComputerUse', 'Goal']);
|
|
56
56
|
const QUESTION_GATE_ROUTES = new Set(['QALoop', 'PPT']);
|
|
57
|
-
const LIGHTWEIGHT_ROUTES = new Set(['Answer', 'DFix', 'Help', 'Wiki']);
|
|
57
|
+
const LIGHTWEIGHT_ROUTES = new Set(['Answer', 'DFix', 'Help', 'Wiki', 'SKS']);
|
|
58
58
|
const FULL_ROUTE_STAGES = Object.freeze([
|
|
59
59
|
'route_classification',
|
|
60
60
|
SOLUTION_SCOUT_STAGE_ID,
|
|
@@ -344,7 +344,7 @@ function buildPipelineStages(route, task, ambiguity, lane, context7Required, age
|
|
|
344
344
|
const skipped = skippedByFast || optional.skip;
|
|
345
345
|
if (id === AGENT_INTAKE_STAGE_ID) {
|
|
346
346
|
if (!agentPolicy.required)
|
|
347
|
-
return agentPipelineStage(agentPolicy);
|
|
347
|
+
return { ...agentPipelineStage(agentPolicy), status: 'not_applicable', reason: 'five_agent_intake_not_required_for_route' };
|
|
348
348
|
return { ...agentPipelineStage(agentPolicy), status: skipped ? 'skipped' : 'required', reason: skippedByFast ? 'proof_field_fast_lane' : agentPolicy.reason };
|
|
349
349
|
}
|
|
350
350
|
return {
|
|
@@ -432,10 +432,10 @@ export function promptPipelineContext(prompt, route = null) {
|
|
|
432
432
|
'Route contract: execution routes infer contract answers from the prompt, TriWiki/current-code defaults, and conservative SKS policy. DFix and Answer bypass stateful execution because they do not start implementation.',
|
|
433
433
|
`Wiki-informed request intake: when a mission exists, read ${REQUEST_INTAKE_ARTIFACT} before execution; preserve every source-order requirement, apply TriWiki attention/use_first and hydrate_first context, and execute request_intake.transformed_prompt through the selected route instead of relying on the vague original wording alone.`,
|
|
434
434
|
'Plan-first interaction: when ambiguity questions are truly required, show the user only the missing human decision(s), then seal the decision contract internally and execute/verify.',
|
|
435
|
-
'Question-shaped directive policy: before using Answer, decide whether a question is a real information request or an implicit instruction/complaint about broken behavior. Rhetorical bug reports, mandatory-policy statements, and "why is this not happening?" execution complaints
|
|
435
|
+
'Question-shaped directive policy: before using Answer, decide whether a question is a real information request or an implicit instruction/complaint about broken behavior. Rhetorical bug reports, mandatory-policy statements, and "why is this not happening?" execution complaints route to the parent-owned SKS fast path unless the user explicitly asks for Naruto/parallel agents.',
|
|
436
436
|
'Best-practice prompt shape: extract Goal, Context, Constraints, and Done-when before implementation; keep questions compact and only ask for answers that can change scope, safety, user-facing behavior, or acceptance criteria.',
|
|
437
437
|
chatCaptureIntakeText(),
|
|
438
|
-
'Default execution routing:
|
|
438
|
+
'Default execution routing: ordinary implementation/code-changing prompts use the parent-owned SKS fast path with focused verification and Honest Mode. Promote to Naruto only when the user explicitly asks for Naruto, Team, multi-agent, subagent, parallel-agent, swarm, or fan-out execution, or when a route-specific safety surface requires it.',
|
|
439
439
|
'Stance: infer the user intent aggressively from rough wording, local context, TriWiki, and conservative defaults; do not surface prequestion sheets before work.',
|
|
440
440
|
subagentExecutionPolicyText(route, cleanPrompt),
|
|
441
441
|
solutionScoutPolicyText(cleanPrompt),
|
|
@@ -535,6 +535,7 @@ export async function prepareRoute(root, prompt, state = {}) {
|
|
|
535
535
|
const required = routeNeedsContext7(route, cleanPrompt);
|
|
536
536
|
const reasoning = routeReasoning(route, cleanPrompt);
|
|
537
537
|
const nativeSessionsRequired = routeRequiresSubagents(route, cleanPrompt);
|
|
538
|
+
const replaceActiveWithSksFastRoute = route.id === 'SKS' && Boolean(state?.mission_id) && looksLikeTeamDefaultWork(cleanPrompt);
|
|
538
539
|
if (QUESTION_GATE_ROUTES.has(route.id) || route.id === 'MadSKS')
|
|
539
540
|
return withSkillDreamContext(await prepareClarificationGate(root, route, task, required, { madSksAuthorization }), dreamContext);
|
|
540
541
|
if (route.id === 'Naruto')
|
|
@@ -549,7 +550,7 @@ export async function prepareRoute(root, prompt, state = {}) {
|
|
|
549
550
|
return withSkillDreamContext(await prepareDb(root, route, task, required), dreamContext);
|
|
550
551
|
if (route.id === 'GX')
|
|
551
552
|
return withSkillDreamContext(await prepareGx(root, route, task, required), dreamContext);
|
|
552
|
-
if (explicit || required)
|
|
553
|
+
if (explicit || required || replaceActiveWithSksFastRoute)
|
|
553
554
|
return withSkillDreamContext(await prepareLightRoute(root, route, task, required), dreamContext);
|
|
554
555
|
return withSkillDreamContext({
|
|
555
556
|
route,
|
|
@@ -673,6 +674,8 @@ async function prepareImageUxReview(root, route, task, required) {
|
|
|
673
674
|
export async function activeRouteContext(root, state) {
|
|
674
675
|
if (!state?.route && !state?.mode)
|
|
675
676
|
return '';
|
|
677
|
+
if (state?.mission_id && !(await missionExists(root, state.mission_id)))
|
|
678
|
+
return '';
|
|
676
679
|
const id = state.route || state.mode;
|
|
677
680
|
const reasoningNote = state.reasoning_effort ? ` Temporary reasoning remains ${state.reasoning_effort} (${state.reasoning_profile}); return to the default profile after this route completes.` : '';
|
|
678
681
|
const planNote = await activePipelinePlanNote(root, state);
|
|
@@ -136,7 +136,8 @@ export async function projectGateStatus(root, state = {}) {
|
|
|
136
136
|
});
|
|
137
137
|
}
|
|
138
138
|
if (state?.subagents_required) {
|
|
139
|
-
const
|
|
139
|
+
const alreadyVerified = state.subagents_verified === true || state.native_sessions_verified === true;
|
|
140
|
+
const evidence = alreadyVerified ? { ok: true } : await subagentEvidence(root, state);
|
|
140
141
|
gates.push({
|
|
141
142
|
id: 'native-session-evidence',
|
|
142
143
|
ok: evidence.ok,
|
|
@@ -207,7 +208,7 @@ export async function evaluateStop(root, state, payload, opts = {}) {
|
|
|
207
208
|
if (state?.context7_required && !(await hasContext7DocsEvidence(root, state))) {
|
|
208
209
|
return complianceBlock(root, state, `SKS ${state.route_command || state.mode || 'route'} requires Context7 evidence before completion. Use Context7 resolve-library-id, then query-docs (or legacy get-library-docs), so SKS can record context7-evidence.jsonl.`, { gate: 'context7-evidence' });
|
|
209
210
|
}
|
|
210
|
-
if (state?.subagents_required && !(await hasSubagentEvidence(root, state))) {
|
|
211
|
+
if (state?.subagents_required && state.subagents_verified !== true && state.native_sessions_verified !== true && !(await hasSubagentEvidence(root, state))) {
|
|
211
212
|
return complianceBlock(root, state, `SKS ${state.route_command || state.mode || 'route'} requires native multi-session evidence before completion. Run worker/reviewer native sessions for disjoint code-changing work, or record explicit evidence that native sessions were unavailable or unsafe to split.`, { gate: 'native-session-evidence' });
|
|
212
213
|
}
|
|
213
214
|
if (state?.mission_id && !(await exists(path.join(missionDir(root, state.mission_id), 'completion-proof.json'))) && routeRequiresAgentIntake(routeFromState(state), { task: state.prompt, force: state.forceAgents === true, noAgents: state.agents_required === false })) {
|
|
@@ -390,6 +391,18 @@ async function passedHardBlocker(root, state) {
|
|
|
390
391
|
}
|
|
391
392
|
function missingRequiredGateFields(file, state, gate = {}) {
|
|
392
393
|
const mode = String(state?.mode || '').toUpperCase();
|
|
394
|
+
if (file === 'stop-gate.json' && gate.schema === 'sks.stop-gate.v1') {
|
|
395
|
+
const missing = [];
|
|
396
|
+
if (gate.passed !== true)
|
|
397
|
+
missing.push('passed');
|
|
398
|
+
if (gate.terminal !== true)
|
|
399
|
+
missing.push('terminal');
|
|
400
|
+
if (gate.status !== 'passed')
|
|
401
|
+
missing.push('status');
|
|
402
|
+
if (Array.isArray(gate.blockers) && gate.blockers.length > 0)
|
|
403
|
+
missing.push('blockers');
|
|
404
|
+
return missing;
|
|
405
|
+
}
|
|
393
406
|
if (file === 'team-gate.json' || mode === 'TEAM') {
|
|
394
407
|
const required = ['team_roster_confirmed', 'analysis_artifact', 'triwiki_refreshed', 'triwiki_validated', 'ssot_guard', 'consensus_artifact', 'implementation_team_fresh', 'review_artifact', 'integration_evidence', 'session_cleanup'];
|
|
395
408
|
if (fromChatImgCoverageRequired(state, gate))
|
|
@@ -445,6 +458,8 @@ function missingRequiredGateFields(file, state, gate = {}) {
|
|
|
445
458
|
}
|
|
446
459
|
async function missingRequiredGateArtifacts(root, file, state, gate = {}) {
|
|
447
460
|
const mode = String(state?.mode || '').toUpperCase();
|
|
461
|
+
if (file === 'stop-gate.json' && gate.schema === 'sks.stop-gate.v1')
|
|
462
|
+
return [];
|
|
448
463
|
if (file === 'research-gate.json' || mode === 'RESEARCH') {
|
|
449
464
|
const evaluated = await evaluateResearchGate(missionDir(root, state.mission_id));
|
|
450
465
|
if (evaluated.passed === true)
|
package/dist/core/routes.js
CHANGED
|
@@ -918,7 +918,7 @@ export function routePrompt(prompt) {
|
|
|
918
918
|
return routeById('MadSKS');
|
|
919
919
|
}
|
|
920
920
|
const route = routeByDollarCommand(command) || routeById('SKS');
|
|
921
|
-
if (route?.id === 'SKS' &&
|
|
921
|
+
if (route?.id === 'SKS' && looksLikeExplicitParallelWorkRequest(stripDollarCommand(text)))
|
|
922
922
|
return routeById('Naruto');
|
|
923
923
|
if (route?.id === 'Team' && command === 'TEAM')
|
|
924
924
|
return routeById('Naruto');
|
|
@@ -938,12 +938,12 @@ export function routePrompt(prompt) {
|
|
|
938
938
|
if (looksLikeTinyDirectFix(text))
|
|
939
939
|
return routeById('DFix');
|
|
940
940
|
if (looksLikeQuestionShapedDirective(text))
|
|
941
|
-
return routeById('
|
|
941
|
+
return routeById('SKS');
|
|
942
942
|
if (looksLikeAnswerOnlyRequest(text))
|
|
943
943
|
return routeById('Answer');
|
|
944
944
|
if (/\b(SQL|Supabase|Postgres|migration|RLS|Prisma|Drizzle|Knex|database|DB|execute_sql)\b/i.test(text))
|
|
945
945
|
return routeById('DB');
|
|
946
|
-
if (
|
|
946
|
+
if (looksLikeExplicitParallelWorkRequest(text))
|
|
947
947
|
return routeById('Naruto');
|
|
948
948
|
if (looksLikeChatCaptureRequest(text) && !looksLikeAnswerOnlyRequest(text))
|
|
949
949
|
return routeById('Team');
|
|
@@ -964,7 +964,7 @@ export function routePrompt(prompt) {
|
|
|
964
964
|
if (/\b(GX|vgraph|visual context|render cartridge|wiki coordinate|rgba|trig|llm wiki)\b/i.test(text))
|
|
965
965
|
return routeById('GX');
|
|
966
966
|
if (looksLikeTeamDefaultWork(text))
|
|
967
|
-
return routeById('
|
|
967
|
+
return routeById('SKS');
|
|
968
968
|
return routeById('SKS');
|
|
969
969
|
}
|
|
970
970
|
export function looksLikeComputerUseFastLane(prompt = '') {
|
|
@@ -984,6 +984,12 @@ export function looksLikeTeamDefaultWork(prompt = '') {
|
|
|
984
984
|
return false;
|
|
985
985
|
return looksLikeCodeChangingWork(text) || looksLikeDirectWorkRequest(text);
|
|
986
986
|
}
|
|
987
|
+
export function looksLikeExplicitParallelWorkRequest(prompt = '') {
|
|
988
|
+
const text = String(prompt || '').trim();
|
|
989
|
+
if (!text)
|
|
990
|
+
return false;
|
|
991
|
+
return /\b(?:team|multi-agent|multiagent|subagent|parallel agents?|agent team|shadow\s*clone|naruto|kage\s*bunshin|swarm|fan\s*out)\b|λ³λ ¬|λ©ν°\s*μμ΄μ νΈ|μλΈ\s*μμ΄μ νΈ|ν\s*(?:μΌλ‘|μμ
|리뷰|ꡬμ±|μ€ν)|λ루ν |λΆμ /i.test(text);
|
|
992
|
+
}
|
|
987
993
|
export function looksLikeAnswerOnlyRequest(prompt = '') {
|
|
988
994
|
const text = String(prompt || '').trim();
|
|
989
995
|
if (!text)
|
|
@@ -1045,7 +1051,7 @@ export function routeRequiresSubagents(route, prompt = '') {
|
|
|
1045
1051
|
if (route.id === 'Team' || route.id === 'Naruto')
|
|
1046
1052
|
return true;
|
|
1047
1053
|
if (route.id === 'SKS')
|
|
1048
|
-
return
|
|
1054
|
+
return false;
|
|
1049
1055
|
if (route.id === 'Help' || route.id === 'Answer' || route.id === 'Wiki' || route.id === 'ComputerUse' || route.id === 'Commit' || route.id === 'CommitAndPush')
|
|
1050
1056
|
return false;
|
|
1051
1057
|
if (route.id === 'PPT')
|
|
@@ -68,6 +68,9 @@ export async function resolveStopGate(input) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
+
if (missionId) {
|
|
72
|
+
return makeResolution(root, route, missionId, null, null, checkedPaths, statePath, stateMissionId, 'current_or_explicit_mission_gate_not_found');
|
|
73
|
+
}
|
|
71
74
|
// 4. latest mission fallback
|
|
72
75
|
const latest = await findLatestMission(root);
|
|
73
76
|
if (latest) {
|
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '4.8.
|
|
1
|
+
export const PACKAGE_VERSION = '4.8.5';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -35,12 +35,17 @@ const hasVisibleLabelSource = generatedSource.includes('NSStatusItem.variableLen
|
|
|
35
35
|
// once-dragged item does not jump back behind the notch on the next doctor --fix.
|
|
36
36
|
const hasAutosaveNameSource = generatedSource.includes('statusItem.autosaveName = "com.sneakoscope.sks-menubar"');
|
|
37
37
|
const hasExplicitVisibleSource = generatedSource.includes('statusItem.isVisible = true');
|
|
38
|
+
const terminalCommandLine = generatedSource.split(/\r?\n/)
|
|
39
|
+
.find((line) => line.includes('do script') && line.includes('escaped')) || '';
|
|
40
|
+
const hasTerminalCommandInterpolation = terminalCommandLine.includes(String.raw `\(escaped)`)
|
|
41
|
+
&& !terminalCommandLine.includes(String.raw `\"(escaped)\"`);
|
|
38
42
|
const hasNoUnconditionalKeepAlive = !launchAgentSource.includes('<key>KeepAlive</key>');
|
|
39
43
|
const hasInteractiveProcessType = launchAgentSource.includes('<key>ProcessType</key>')
|
|
40
44
|
&& launchAgentSource.includes('<string>Interactive</string>');
|
|
41
45
|
const expectedMenuItems = [
|
|
42
46
|
'Use codex-lb',
|
|
43
47
|
'Use ChatGPT OAuth',
|
|
48
|
+
'Set codex-lb Domain and Key',
|
|
44
49
|
'Set OpenRouter Key and GLM Profiles',
|
|
45
50
|
'Fast Check',
|
|
46
51
|
'SKS Version Check',
|
|
@@ -75,6 +80,7 @@ const ok = process.platform === 'darwin'
|
|
|
75
80
|
&& hasVisibleLabelSource
|
|
76
81
|
&& hasAutosaveNameSource
|
|
77
82
|
&& hasExplicitVisibleSource
|
|
83
|
+
&& hasTerminalCommandInterpolation
|
|
78
84
|
&& hasNoUnconditionalKeepAlive
|
|
79
85
|
&& hasInteractiveProcessType
|
|
80
86
|
&& launchSkippedForTempHome
|
|
@@ -93,9 +99,11 @@ const report = {
|
|
|
93
99
|
launch_agent_exists: launchAgentExists,
|
|
94
100
|
action_script_exists: actionScriptExists,
|
|
95
101
|
generated_source_path: generatedSourcePath,
|
|
102
|
+
terminal_command_line: terminalCommandLine,
|
|
96
103
|
has_visible_label_source: hasVisibleLabelSource,
|
|
97
104
|
has_autosave_name_source: hasAutosaveNameSource,
|
|
98
105
|
has_explicit_visible_source: hasExplicitVisibleSource,
|
|
106
|
+
has_terminal_command_interpolation: hasTerminalCommandInterpolation,
|
|
99
107
|
has_no_unconditional_keepalive: hasNoUnconditionalKeepAlive,
|
|
100
108
|
has_interactive_process_type: hasInteractiveProcessType,
|
|
101
109
|
launch_skipped_for_temp_home: launchSkippedForTempHome,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "γ
γ
γ
",
|
|
4
|
-
"version": "4.8.
|
|
4
|
+
"version": "4.8.5",
|
|
5
5
|
"description": "Sneakoscope Codex: fast proof-first Codex trust layer with image-based Voxel TriWiki.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
|