sneakoscope 4.0.8 → 4.0.10
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/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/bin/sks.js +1 -1
- package/dist/cli/command-registry.js +1 -0
- package/dist/core/commands/naruto-command.js +25 -0
- package/dist/core/commands/stop-gate-command.js +63 -0
- package/dist/core/fsx.js +1 -1
- package/dist/core/pipeline-internals/runtime-gates.js +31 -4
- package/dist/core/providers/glm/glm-bench.js +4 -4
- package/dist/core/providers/glm/glm-direct-run.js +1 -1
- package/dist/core/providers/glm/glm-latency-trace.js +1 -1
- package/dist/core/providers/glm/glm-request-cache.js +9 -4
- package/dist/core/providers/glm/naruto/glm-naruto-bench.js +47 -12
- package/dist/core/providers/glm/naruto/glm-naruto-combined-patch.js +49 -0
- package/dist/core/providers/glm/naruto/glm-naruto-conflict-graph.js +7 -1
- package/dist/core/providers/glm/naruto/glm-naruto-hunk-conflict.js +16 -0
- package/dist/core/providers/glm/naruto/glm-naruto-hunk-parser.js +36 -0
- package/dist/core/providers/glm/naruto/glm-naruto-judge.js +1 -1
- package/dist/core/providers/glm/naruto/glm-naruto-orchestrator.js +77 -13
- package/dist/core/providers/glm/naruto/glm-naruto-patch-candidate-gate.js +42 -0
- package/dist/core/providers/glm/naruto/glm-naruto-patch-candidate-parser.js +62 -0
- package/dist/core/providers/glm/naruto/glm-naruto-secret-audit.js +39 -0
- package/dist/core/providers/glm/naruto/glm-naruto-trace.js +41 -1
- package/dist/core/providers/glm/naruto/glm-naruto-verifier-output.js +26 -0
- package/dist/core/providers/glm/naruto/glm-naruto-worker-artifacts.js +42 -0
- package/dist/core/providers/glm/naruto/glm-naruto-worker-pool.js +30 -11
- package/dist/core/providers/glm/naruto/glm-naruto-worker-runtime.js +170 -16
- package/dist/core/providers/openrouter/openrouter-stream.js +46 -6
- package/dist/core/stop-gate/stop-gate-check.js +220 -0
- package/dist/core/stop-gate/stop-gate-diagnostics.js +4 -0
- package/dist/core/stop-gate/stop-gate-resolver.js +122 -0
- package/dist/core/stop-gate/stop-gate-types.js +2 -0
- package/dist/core/stop-gate/stop-gate-writer.js +126 -0
- package/dist/core/version.js +1 -1
- package/package.json +1 -1
|
@@ -2,10 +2,10 @@ import path from 'node:path';
|
|
|
2
2
|
import { nowIso, writeJsonAtomic } from '../../../fsx.js';
|
|
3
3
|
import { GLM_52_OPENROUTER_MODEL } from '../glm-52-settings.js';
|
|
4
4
|
import { resolveOpenRouterApiKey } from '../../openrouter/openrouter-secret-store.js';
|
|
5
|
-
import { checkAndApplyGlmPatch } from '../glm-patch-apply.js';
|
|
6
5
|
import { decomposeTask, validateWorkGraph } from './glm-naruto-decomposer.js';
|
|
7
6
|
import { planShardCandidates, computeInitialLaneMix } from './glm-naruto-shard-planner.js';
|
|
8
7
|
import { runPatchWorkerPool } from './glm-naruto-worker-pool.js';
|
|
8
|
+
import { runVerifierWorker } from './glm-naruto-worker-runtime.js';
|
|
9
9
|
import { buildConflictGraph } from './glm-naruto-conflict-graph.js';
|
|
10
10
|
import { planMerge } from './glm-naruto-merge-planner.js';
|
|
11
11
|
import { finalizeMergePlan } from './glm-naruto-finalizer.js';
|
|
@@ -14,6 +14,9 @@ import { createBudget, checkBudget, recordRequest } from './glm-naruto-budget.js
|
|
|
14
14
|
import { createProviderHealthTracker } from '../../openrouter/openrouter-provider-health.js';
|
|
15
15
|
import { createMissionTrace, recordWorkerTrace, writeMissionArtifacts, buildMissionSummary } from './glm-naruto-trace.js';
|
|
16
16
|
import { runGlmJudge } from './glm-naruto-judge.js';
|
|
17
|
+
import { writeFinalStopGate } from '../../../stop-gate/stop-gate-writer.js';
|
|
18
|
+
import { checkAndApplyCombinedGlmNarutoPatch } from './glm-naruto-combined-patch.js';
|
|
19
|
+
import { auditGlmNarutoArtifactsForSecrets } from './glm-naruto-secret-audit.js';
|
|
17
20
|
import { GLM_NARUTO_LIMITS } from './glm-naruto-types.js';
|
|
18
21
|
export async function runGlmNarutoMission(input) {
|
|
19
22
|
const missionId = input.missionId || `glm-naruto-${nowIso().replace(/[:.]/g, '-')}`;
|
|
@@ -93,8 +96,38 @@ export async function runGlmNarutoMission(input) {
|
|
|
93
96
|
failedShardIds = [...failedShardIds, ...repairPool.failedShardIds];
|
|
94
97
|
}
|
|
95
98
|
}
|
|
99
|
+
// 4.0.9: Verifier wave — run parallel verifier workers over gate-passed candidates.
|
|
100
|
+
let passedEnvelopes = envelopes.filter((e) => e.status === 'gate_passed');
|
|
101
|
+
if (passedEnvelopes.length > 0 && !input.noApply) {
|
|
102
|
+
const verifyApiKey = key.key;
|
|
103
|
+
const verifyResults = await Promise.allSettled(passedEnvelopes.map((env) => runVerifierWorker({
|
|
104
|
+
apiKey: verifyApiKey,
|
|
105
|
+
missionId,
|
|
106
|
+
workerId: env.worker_id,
|
|
107
|
+
envelope: env,
|
|
108
|
+
timeoutMs: 120_000,
|
|
109
|
+
})));
|
|
110
|
+
const verifiedEnvelopes = [];
|
|
111
|
+
for (let vi = 0; vi < passedEnvelopes.length; vi++) {
|
|
112
|
+
const env = passedEnvelopes[vi];
|
|
113
|
+
const res = verifyResults[vi];
|
|
114
|
+
if (res.status === 'fulfilled' && res.value.ok) {
|
|
115
|
+
verifiedEnvelopes.push({ ...env, verification_passed: true, status: 'gate_passed' });
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
verifiedEnvelopes.push({ ...env, verification_passed: false, status: 'verification_failed' });
|
|
119
|
+
}
|
|
120
|
+
if (res.status === 'fulfilled') {
|
|
121
|
+
traceState = recordWorkerTrace(traceState, res.value.trace);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
envelopes = envelopes.map((e) => {
|
|
125
|
+
const verified = verifiedEnvelopes.find((v) => v.worker_id === e.worker_id);
|
|
126
|
+
return verified ?? e;
|
|
127
|
+
});
|
|
128
|
+
passedEnvelopes = envelopes.filter((e) => e.status === 'gate_passed');
|
|
129
|
+
}
|
|
96
130
|
// Build conflict graph and merge plan
|
|
97
|
-
const passedEnvelopes = envelopes.filter((e) => e.status === 'gate_passed');
|
|
98
131
|
const nodes = passedEnvelopes.map((env) => ({
|
|
99
132
|
patch_id: env.worker_id,
|
|
100
133
|
shard_id: env.shard_id,
|
|
@@ -124,16 +157,14 @@ export async function runGlmNarutoMission(input) {
|
|
|
124
157
|
let appliedPatches = 0;
|
|
125
158
|
let applyResult = null;
|
|
126
159
|
if (!input.noApply && mergePlan.selected_patches.length > 0) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
applyResult = { ok: appliedPatches > 0, applied: mergePlan.selected_patches };
|
|
160
|
+
const combinedApply = await checkAndApplyCombinedGlmNarutoPatch({
|
|
161
|
+
cwd,
|
|
162
|
+
envelopes,
|
|
163
|
+
selectedPatchIds: mergePlan.selected_patches,
|
|
164
|
+
apply: true
|
|
165
|
+
});
|
|
166
|
+
appliedPatches = combinedApply.ok ? combinedApply.applied.length : 0;
|
|
167
|
+
applyResult = { ok: combinedApply.ok, applied: combinedApply.applied, ...(combinedApply.blocker ? { blocker: combinedApply.blocker } : {}) };
|
|
137
168
|
}
|
|
138
169
|
const terminalState = appliedPatches > 0 ? 'completed' : passedEnvelopes.length > 0 ? 'partial_candidates' : 'blocked';
|
|
139
170
|
const terminationReason = appliedPatches > 0 ? 'completed_merge_applied' : passedEnvelopes.length > 0 ? 'partial_no_apply' : 'no_gate_passed_candidates';
|
|
@@ -181,8 +212,41 @@ export async function runGlmNarutoMission(input) {
|
|
|
181
212
|
termination: { schema: 'sks.glm-naruto-termination.v1', mission_id: missionId, terminal_state: terminalState, reason: terminationReason, wall_clock_ms: summary.wall_clock_ms },
|
|
182
213
|
...(applyResult ? { applyResult: { ...applyResult, schema: 'sks.glm-naruto-apply-result.v1' } } : {}),
|
|
183
214
|
verificationSummary: { schema: 'sks.glm-naruto-verification.v1', verified: passedEnvelopes.length, total: envelopes.length },
|
|
184
|
-
missionResult: result
|
|
215
|
+
missionResult: result,
|
|
216
|
+
envelopes
|
|
185
217
|
});
|
|
218
|
+
const secretAudit = await auditGlmNarutoArtifactsForSecrets(path.join(cwd, '.sneakoscope', 'glm-naruto', missionId)).catch((err) => ({
|
|
219
|
+
schema: 'sks.glm-naruto-secret-audit.v1',
|
|
220
|
+
ok: false,
|
|
221
|
+
root: path.join(cwd, '.sneakoscope', 'glm-naruto', missionId),
|
|
222
|
+
scanned_files: 0,
|
|
223
|
+
findings: [`audit_failed:${err instanceof Error ? err.message : String(err)}`]
|
|
224
|
+
}));
|
|
225
|
+
await writeJsonAtomic(path.join(artifactDir, 'secret-audit.json'), secretAudit).catch(() => undefined);
|
|
226
|
+
// 4.0.9: Write canonical stop-gate artifacts for hook resolution.
|
|
227
|
+
await writeFinalStopGate({
|
|
228
|
+
root: cwd,
|
|
229
|
+
missionId,
|
|
230
|
+
route: 'GLM_NARUTO',
|
|
231
|
+
routeCommand: '$Naruto',
|
|
232
|
+
status: result.ok && secretAudit.ok ? 'passed' : (terminalState === 'blocked' || !secretAudit.ok ? 'blocked' : 'failed'),
|
|
233
|
+
terminal: terminalState === 'completed' || terminalState === 'blocked',
|
|
234
|
+
terminalState,
|
|
235
|
+
evidence: {
|
|
236
|
+
build_passed: result.ok,
|
|
237
|
+
tests_passed: result.ok,
|
|
238
|
+
route_evidence_passed: result.ok,
|
|
239
|
+
per_worker_artifacts: true,
|
|
240
|
+
verifier_wave_run: true,
|
|
241
|
+
model_guard_enforced: true,
|
|
242
|
+
proof_required: false,
|
|
243
|
+
proof_passed: true,
|
|
244
|
+
reflection_required: false,
|
|
245
|
+
reflection_passed: 'not_required',
|
|
246
|
+
},
|
|
247
|
+
blockers: secretAudit.ok ? (result.blockers || []) : ['glm_naruto_secret_leak_detected'],
|
|
248
|
+
nativeGateFile: 'termination.json',
|
|
249
|
+
}).catch(() => null);
|
|
186
250
|
return { ...result, artifact_dir: artifactDir };
|
|
187
251
|
}
|
|
188
252
|
function missionResult(missionId, task, status, reason, patchCandidates, startedMs, envelopes, traces, blockers, warnings) {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { checkAndApplyGlmPatch } from '../glm-patch-apply.js';
|
|
2
|
+
import { parseGlmNarutoPatchCandidate } from './glm-naruto-patch-candidate-parser.js';
|
|
3
|
+
const PROTECTED_PATH = /(^|\/)(\.github|dist|node_modules)(\/|$)/;
|
|
4
|
+
const SECRET_PATTERN = /\b(?:Bearer\s+[A-Za-z0-9._~+/-]+|sk-(?:or-)?[A-Za-z0-9_-]{12,}|OPENROUTER_API_KEY|SKS_OPENROUTER_API_KEY)\b/;
|
|
5
|
+
export async function evaluateGlmNarutoPatchCandidateGate(input) {
|
|
6
|
+
const checks = [];
|
|
7
|
+
const parsed = parseGlmNarutoPatchCandidate(input.envelope.patch);
|
|
8
|
+
checks.push(check('candidate_parse', parsed.ok, parsed.blockers.join(',') || undefined));
|
|
9
|
+
checks.push(check('patch_section', Boolean(parsed.patch), parsed.patch ? undefined : 'missing_patch_section'));
|
|
10
|
+
checks.push(check('unified_diff', /^diff --git /m.test(parsed.patch), parsed.patch ? undefined : 'no_diff_git'));
|
|
11
|
+
const blockedPath = parsed.touched_paths.find((file) => PROTECTED_PATH.test(file));
|
|
12
|
+
checks.push(check('protected_path_guard', !blockedPath, blockedPath));
|
|
13
|
+
const secretLeak = SECRET_PATTERN.test(parsed.patch);
|
|
14
|
+
checks.push(check('secret_leakage_guard', !secretLeak, secretLeak ? 'secret_like_content' : undefined));
|
|
15
|
+
if (parsed.ok && !blockedPath && !secretLeak) {
|
|
16
|
+
const applyCheck = await checkAndApplyGlmPatch({
|
|
17
|
+
cwd: input.cwd,
|
|
18
|
+
patch: parsed.patch,
|
|
19
|
+
apply: input.apply === true
|
|
20
|
+
});
|
|
21
|
+
checks.push(check('git_apply_check', applyCheck.ok, applyCheck.ok ? undefined : applyCheck.error.code));
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
checks.push({ id: 'git_apply_check', ok: false, reason: 'skipped_due_to_prior_blocker', ms: 0 });
|
|
25
|
+
}
|
|
26
|
+
const blockers = checks.filter((row) => !row.ok).map((row) => row.reason || row.id);
|
|
27
|
+
return {
|
|
28
|
+
schema: 'sks.glm-naruto-patch-candidate-gate.v1',
|
|
29
|
+
ok: blockers.length === 0,
|
|
30
|
+
worker_id: input.envelope.worker_id,
|
|
31
|
+
shard_id: input.envelope.shard_id,
|
|
32
|
+
patch_id: input.envelope.patch_sha256,
|
|
33
|
+
extracted_patch: parsed.patch,
|
|
34
|
+
touched_paths: parsed.touched_paths,
|
|
35
|
+
checks,
|
|
36
|
+
blockers
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function check(id, ok, reason) {
|
|
40
|
+
return { id, ok, ...(reason ? { reason } : {}), ms: 0 };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=glm-naruto-patch-candidate-gate.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { parseUnifiedDiffPatch } from '../glm-patch-parser.js';
|
|
2
|
+
const CANDIDATE_OPEN = '<sks_patch_candidate>';
|
|
3
|
+
const CANDIDATE_CLOSE = '</sks_patch_candidate>';
|
|
4
|
+
const LEGACY_PATCH_OPEN = '<sks_patch>';
|
|
5
|
+
export function parseGlmNarutoPatchCandidate(text) {
|
|
6
|
+
const blockers = [];
|
|
7
|
+
if (text.includes(LEGACY_PATCH_OPEN) && !text.includes(CANDIDATE_OPEN)) {
|
|
8
|
+
return failed(text, ['legacy_sks_patch_envelope_rejected']);
|
|
9
|
+
}
|
|
10
|
+
const body = unwrapCandidateBody(text);
|
|
11
|
+
if (!body.ok)
|
|
12
|
+
return failed(text, body.blockers);
|
|
13
|
+
const extracted = extractPatchSection(body.body);
|
|
14
|
+
if (!extracted.ok)
|
|
15
|
+
return failed(body.body, extracted.blockers);
|
|
16
|
+
const parsed = parseUnifiedDiffPatch(extracted.patch);
|
|
17
|
+
if (parsed.empty)
|
|
18
|
+
blockers.push('patch_missing_unified_diff');
|
|
19
|
+
return {
|
|
20
|
+
ok: blockers.length === 0,
|
|
21
|
+
body: body.body,
|
|
22
|
+
patch: extracted.patch,
|
|
23
|
+
touched_paths: parsed.touchedPaths,
|
|
24
|
+
blockers
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function unwrapCandidateBody(text) {
|
|
28
|
+
const start = text.indexOf(CANDIDATE_OPEN);
|
|
29
|
+
const end = text.indexOf(CANDIDATE_CLOSE);
|
|
30
|
+
if (start >= 0 || end >= 0) {
|
|
31
|
+
if (start < 0 || end <= start)
|
|
32
|
+
return { ok: false, blockers: ['malformed_patch_candidate_envelope'] };
|
|
33
|
+
return { ok: true, body: text.slice(start + CANDIDATE_OPEN.length, end).trim() };
|
|
34
|
+
}
|
|
35
|
+
if (/^\s*patch\s*:/im.test(text))
|
|
36
|
+
return { ok: true, body: text.trim() };
|
|
37
|
+
return { ok: false, blockers: ['missing_patch_candidate_envelope'] };
|
|
38
|
+
}
|
|
39
|
+
function extractPatchSection(body) {
|
|
40
|
+
const lines = body.split(/\r?\n/);
|
|
41
|
+
const patchLine = lines.findIndex((line) => /^\s*patch\s*:/i.test(line));
|
|
42
|
+
if (patchLine < 0)
|
|
43
|
+
return { ok: false, blockers: ['missing_patch_section'] };
|
|
44
|
+
const firstLine = lines[patchLine] || '';
|
|
45
|
+
const inline = firstLine.replace(/^\s*patch\s*:\s*/i, '');
|
|
46
|
+
const tail = inline.trim() ? [inline, ...lines.slice(patchLine + 1)] : lines.slice(patchLine + 1);
|
|
47
|
+
const raw = tail.join('\n').replace(/^\s*```(?:diff|patch)?\s*/i, '').replace(/\s*```\s*$/i, '').trim();
|
|
48
|
+
const diffIndex = raw.search(/^diff --git /m);
|
|
49
|
+
if (diffIndex < 0)
|
|
50
|
+
return { ok: false, blockers: ['patch_missing_diff_git'] };
|
|
51
|
+
return { ok: true, patch: raw.slice(diffIndex).trimEnd() + '\n' };
|
|
52
|
+
}
|
|
53
|
+
function failed(body, blockers) {
|
|
54
|
+
return {
|
|
55
|
+
ok: false,
|
|
56
|
+
body,
|
|
57
|
+
patch: '',
|
|
58
|
+
touched_paths: [],
|
|
59
|
+
blockers
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=glm-naruto-patch-candidate-parser.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import fsp from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const SECRET_PATTERN = /\b(?:Bearer\s+[A-Za-z0-9._~+/-]+|sk-(?:or-)?[A-Za-z0-9_-]{12,}|OPENROUTER_API_KEY|SKS_OPENROUTER_API_KEY)\b/;
|
|
4
|
+
export async function auditGlmNarutoArtifactsForSecrets(root) {
|
|
5
|
+
const findings = [];
|
|
6
|
+
let scanned = 0;
|
|
7
|
+
await scan(root, async (file) => {
|
|
8
|
+
if (!/\.(json|jsonl|md|txt)$/i.test(file))
|
|
9
|
+
return;
|
|
10
|
+
scanned++;
|
|
11
|
+
const content = await fsp.readFile(file, 'utf8').catch(() => '');
|
|
12
|
+
if (SECRET_PATTERN.test(content))
|
|
13
|
+
findings.push(path.relative(root, file));
|
|
14
|
+
});
|
|
15
|
+
return {
|
|
16
|
+
schema: 'sks.glm-naruto-secret-audit.v1',
|
|
17
|
+
ok: findings.length === 0,
|
|
18
|
+
root,
|
|
19
|
+
scanned_files: scanned,
|
|
20
|
+
findings
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async function scan(dir, visit) {
|
|
24
|
+
let entries;
|
|
25
|
+
try {
|
|
26
|
+
entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
const p = path.join(dir, String(entry.name));
|
|
33
|
+
if (entry.isDirectory())
|
|
34
|
+
await scan(p, visit);
|
|
35
|
+
else if (entry.isFile())
|
|
36
|
+
await visit(p);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=glm-naruto-secret-audit.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { nowIso, writeJsonAtomic } from '../../../fsx.js';
|
|
2
|
+
import { ensureDir, nowIso, writeJsonAtomic } from '../../../fsx.js';
|
|
3
3
|
export function createMissionTrace(missionId) {
|
|
4
4
|
return {
|
|
5
5
|
missionId,
|
|
@@ -12,6 +12,7 @@ export function recordWorkerTrace(state, trace) {
|
|
|
12
12
|
}
|
|
13
13
|
export async function writeMissionArtifacts(input) {
|
|
14
14
|
const dir = path.join(input.root, '.sneakoscope', 'glm-naruto', input.missionId);
|
|
15
|
+
await ensureDir(dir);
|
|
15
16
|
if (input.workGraph)
|
|
16
17
|
await writeJsonAtomic(path.join(dir, 'work-graph.json'), input.workGraph);
|
|
17
18
|
if (input.conflictGraph)
|
|
@@ -32,6 +33,45 @@ export async function writeMissionArtifacts(input) {
|
|
|
32
33
|
await writeJsonAtomic(path.join(dir, 'verification-summary.json'), input.verificationSummary);
|
|
33
34
|
if (input.missionResult)
|
|
34
35
|
await writeJsonAtomic(path.join(dir, 'mission-result.json'), input.missionResult);
|
|
36
|
+
// 4.0.9: Write per-worker patch envelope / request-summary / stream-trace / gate-result artifacts.
|
|
37
|
+
if (input.envelopes && input.envelopes.length > 0) {
|
|
38
|
+
const workersDir = path.join(dir, 'workers');
|
|
39
|
+
await ensureDir(workersDir);
|
|
40
|
+
for (const env of input.envelopes) {
|
|
41
|
+
const workerId = String(env.worker_id || env.shard_id || 'unknown');
|
|
42
|
+
const workerDir = path.join(workersDir, workerId);
|
|
43
|
+
await ensureDir(workerDir);
|
|
44
|
+
await writeJsonAtomic(path.join(workerDir, 'patch-envelope.json'), env);
|
|
45
|
+
await writeJsonAtomic(path.join(workerDir, 'request-summary.json'), {
|
|
46
|
+
schema: 'sks.glm-naruto-worker-request-summary.v1',
|
|
47
|
+
worker_id: workerId,
|
|
48
|
+
shard_id: env.shard_id,
|
|
49
|
+
model: env.model || null,
|
|
50
|
+
provider: 'openrouter',
|
|
51
|
+
request_body_size: env.request_body_size ?? null,
|
|
52
|
+
cached: env.cached ?? false,
|
|
53
|
+
created_at: nowIso(),
|
|
54
|
+
});
|
|
55
|
+
await writeJsonAtomic(path.join(workerDir, 'stream-trace.json'), {
|
|
56
|
+
schema: 'sks.glm-naruto-worker-stream-trace.v1',
|
|
57
|
+
worker_id: workerId,
|
|
58
|
+
ttft_ms: env.ttft_ms ?? null,
|
|
59
|
+
chunk_count: env.chunk_count ?? null,
|
|
60
|
+
real_stream: env.real_stream ?? true,
|
|
61
|
+
idle_timeout_ms: env.idle_timeout_ms ?? null,
|
|
62
|
+
created_at: nowIso(),
|
|
63
|
+
});
|
|
64
|
+
await writeJsonAtomic(path.join(workerDir, 'gate-result.json'), {
|
|
65
|
+
schema: 'sks.glm-naruto-worker-gate-result.v1',
|
|
66
|
+
worker_id: workerId,
|
|
67
|
+
shard_id: env.shard_id,
|
|
68
|
+
status: env.status,
|
|
69
|
+
gate_passed: env.status === 'gate_passed',
|
|
70
|
+
verification_passed: env.verification_passed ?? (env.status === 'gate_passed'),
|
|
71
|
+
created_at: nowIso(),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
35
75
|
return dir;
|
|
36
76
|
}
|
|
37
77
|
export function buildMissionSummary(input) {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function parseGlmNarutoVerifierOutput(content) {
|
|
2
|
+
try {
|
|
3
|
+
const parsed = JSON.parse(stripJsonFences(content));
|
|
4
|
+
const issues = [];
|
|
5
|
+
if (parsed.schema !== 'sks.glm-naruto-verifier-output.v1')
|
|
6
|
+
issues.push('schema');
|
|
7
|
+
if (typeof parsed.ok !== 'boolean')
|
|
8
|
+
issues.push('ok');
|
|
9
|
+
if (!Array.isArray(parsed.issues) || parsed.issues.some((issue) => typeof issue !== 'string'))
|
|
10
|
+
issues.push('issues');
|
|
11
|
+
if (typeof parsed.risk_score !== 'number' || parsed.risk_score < 0 || parsed.risk_score > 1)
|
|
12
|
+
issues.push('risk_score');
|
|
13
|
+
if (typeof parsed.confidence !== 'number' || parsed.confidence < 0 || parsed.confidence > 1)
|
|
14
|
+
issues.push('confidence');
|
|
15
|
+
if (issues.length)
|
|
16
|
+
return { ok: false, issues: issues.map((issue) => `invalid_${issue}`) };
|
|
17
|
+
return { ok: true, output: parsed, issues: [] };
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return { ok: false, issues: ['malformed_json'] };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function stripJsonFences(content) {
|
|
24
|
+
return content.trim().replace(/^```(?:json)?\s*/i, '').replace(/\s*```\s*$/i, '').trim();
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=glm-naruto-verifier-output.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { ensureDir, nowIso, writeJsonAtomic } from '../../../fsx.js';
|
|
3
|
+
export async function writeGlmNarutoWorkerArtifacts(input) {
|
|
4
|
+
const dir = path.join(input.root, '.sneakoscope', 'glm-naruto', input.missionId, 'workers', input.workerId);
|
|
5
|
+
await ensureDir(dir);
|
|
6
|
+
if (input.requestSummary) {
|
|
7
|
+
await writeJsonAtomic(path.join(dir, 'request-summary.json'), sanitizeArtifact({
|
|
8
|
+
schema: 'sks.glm-naruto-worker-request-summary.v1',
|
|
9
|
+
worker_id: input.workerId,
|
|
10
|
+
shard_id: input.shardId,
|
|
11
|
+
created_at: nowIso(),
|
|
12
|
+
...input.requestSummary
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
if (input.streamTrace)
|
|
16
|
+
await writeJsonAtomic(path.join(dir, 'stream-trace.json'), sanitizeArtifact(input.streamTrace));
|
|
17
|
+
if (input.patchEnvelope)
|
|
18
|
+
await writeJsonAtomic(path.join(dir, 'patch-envelope.json'), sanitizeArtifact(input.patchEnvelope));
|
|
19
|
+
if (input.gateResult)
|
|
20
|
+
await writeJsonAtomic(path.join(dir, 'gate-result.json'), sanitizeArtifact(input.gateResult));
|
|
21
|
+
if (input.termination) {
|
|
22
|
+
await writeJsonAtomic(path.join(dir, 'termination.json'), sanitizeArtifact({
|
|
23
|
+
schema: 'sks.glm-naruto-worker-termination.v1',
|
|
24
|
+
worker_id: input.workerId,
|
|
25
|
+
shard_id: input.shardId,
|
|
26
|
+
created_at: nowIso(),
|
|
27
|
+
...input.termination
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
return dir;
|
|
31
|
+
}
|
|
32
|
+
function sanitizeArtifact(value) {
|
|
33
|
+
return JSON.parse(JSON.stringify(value, (_key, raw) => {
|
|
34
|
+
if (typeof raw !== 'string')
|
|
35
|
+
return raw;
|
|
36
|
+
return raw
|
|
37
|
+
.replace(/Bearer\s+[A-Za-z0-9._~+/-]+/g, 'Bearer [REDACTED]')
|
|
38
|
+
.replace(/sk-or-[A-Za-z0-9_-]+/g, 'sk-or-[REDACTED]')
|
|
39
|
+
.replace(/sk-[A-Za-z0-9_-]{12,}/g, 'sk-[REDACTED]');
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=glm-naruto-worker-artifacts.js.map
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { runPatchWorker } from './glm-naruto-worker-runtime.js';
|
|
2
|
-
import { checkAndApplyGlmPatch } from '../glm-patch-apply.js';
|
|
3
|
-
import { evaluateGlmSpeedGate } from '../glm-speed-gate.js';
|
|
4
2
|
import { decideConcurrency } from './glm-naruto-concurrency-governor.js';
|
|
5
3
|
import { planFileLeases } from './glm-naruto-file-lease.js';
|
|
4
|
+
import { evaluateGlmNarutoPatchCandidateGate } from './glm-naruto-patch-candidate-gate.js';
|
|
5
|
+
import { createPatchEnvelope } from './glm-naruto-patch-envelope.js';
|
|
6
|
+
import { writeGlmNarutoWorkerArtifacts } from './glm-naruto-worker-artifacts.js';
|
|
6
7
|
export async function runPatchWorkerPool(input) {
|
|
7
8
|
const envelopes = [];
|
|
8
9
|
const traces = [];
|
|
@@ -34,6 +35,7 @@ export async function runPatchWorkerPool(input) {
|
|
|
34
35
|
apiKey: input.apiKey,
|
|
35
36
|
missionId: input.missionId,
|
|
36
37
|
workerId,
|
|
38
|
+
root: input.cwd,
|
|
37
39
|
shard: shardWithStrategy,
|
|
38
40
|
contextSummary: input.contextSummary,
|
|
39
41
|
timeoutMs: input.workerTimeoutMs
|
|
@@ -43,25 +45,42 @@ export async function runPatchWorkerPool(input) {
|
|
|
43
45
|
const results = await Promise.allSettled(workerTasks);
|
|
44
46
|
for (const result of results) {
|
|
45
47
|
if (result.status === 'fulfilled' && result.value.ok && result.value.envelope) {
|
|
46
|
-
const gate =
|
|
48
|
+
const gate = await evaluateGlmNarutoPatchCandidateGate({
|
|
49
|
+
cwd: input.cwd,
|
|
50
|
+
envelope: result.value.envelope,
|
|
51
|
+
apply: false
|
|
52
|
+
});
|
|
47
53
|
let envelope = result.value.envelope;
|
|
48
54
|
if (gate.ok) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
envelope = createPatchEnvelope({
|
|
56
|
+
missionId: envelope.mission_id,
|
|
57
|
+
workerId: envelope.worker_id,
|
|
58
|
+
shardId: envelope.shard_id,
|
|
59
|
+
baseDigest: envelope.base_digest,
|
|
60
|
+
patch: gate.extracted_patch,
|
|
61
|
+
strategy: envelope.strategy,
|
|
62
|
+
reasoningEffort: envelope.reasoning_effort,
|
|
63
|
+
status: 'gate_passed',
|
|
64
|
+
warnings: envelope.warnings
|
|
53
65
|
});
|
|
54
|
-
envelope = applyCheck.ok
|
|
55
|
-
? { ...envelope, status: 'gate_passed' }
|
|
56
|
-
: { ...envelope, status: 'gate_failed', blockers: [applyCheck.error.code] };
|
|
57
66
|
}
|
|
58
67
|
else {
|
|
59
68
|
envelope = {
|
|
60
69
|
...envelope,
|
|
61
70
|
status: 'gate_failed',
|
|
62
|
-
blockers: gate.
|
|
71
|
+
blockers: gate.blockers
|
|
63
72
|
};
|
|
64
73
|
}
|
|
74
|
+
await writeGlmNarutoWorkerArtifacts({
|
|
75
|
+
root: input.cwd,
|
|
76
|
+
missionId: input.missionId,
|
|
77
|
+
workerId: envelope.worker_id,
|
|
78
|
+
shardId: envelope.shard_id,
|
|
79
|
+
patchEnvelope: envelope,
|
|
80
|
+
gateResult: gate,
|
|
81
|
+
streamTrace: result.value.trace,
|
|
82
|
+
termination: { status: envelope.status, ok: gate.ok, blockers: envelope.blockers }
|
|
83
|
+
}).catch(() => undefined);
|
|
65
84
|
envelopes.push(envelope);
|
|
66
85
|
traces.push(result.value.trace);
|
|
67
86
|
}
|