sneakoscope 4.2.0 → 4.3.0
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 +35 -8
- 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 +3 -1
- package/dist/cli/ultra-search-command.js +163 -0
- package/dist/cli/xai-command.js +28 -168
- package/dist/core/agents/agent-codex-cockpit.js +3 -3
- package/dist/core/agents/agent-runner-ollama.js +2 -0
- package/dist/core/agents/agent-wrongness.js +1 -1
- package/dist/core/agents/native-worker-backend-router.js +3 -0
- package/dist/core/bench.js +115 -0
- package/dist/core/code-structure.js +399 -11
- package/dist/core/codex-control/codex-app-server-v2-client.js +86 -2
- package/dist/core/codex-control/codex-fake-sdk-adapter.js +67 -9
- package/dist/core/codex-control/codex-reliability-shield.js +26 -5
- package/dist/core/codex-control/codex-task-runner.js +7 -1
- package/dist/core/codex-control/gpt-final-arbiter.js +4 -1
- package/dist/core/codex-control/gpt-final-review-schema.js +58 -0
- package/dist/core/codex-control/model-call-concurrency.js +1 -1
- package/dist/core/codex-native/core-skill-manifest.js +23 -0
- package/dist/core/commands/bench-command.js +11 -2
- package/dist/core/commands/code-structure-command.js +34 -2
- package/dist/core/commands/qa-loop-command.js +23 -7
- package/dist/core/commands/run-command.js +92 -2
- package/dist/core/commands/seo-command.js +130 -0
- package/dist/core/feature-fixtures.js +6 -0
- package/dist/core/feature-registry.js +3 -1
- package/dist/core/fsx.js +1 -1
- package/dist/core/hooks-runtime.js +9 -1
- package/dist/core/init.js +8 -6
- package/dist/core/lean-engineering-policy.js +159 -0
- package/dist/core/pipeline-internals/runtime-core.js +15 -5
- package/dist/core/proof/auto-finalize.js +3 -2
- package/dist/core/proof/proof-schema.js +2 -1
- package/dist/core/proof/proof-writer.js +1 -0
- package/dist/core/proof/route-adapter.js +4 -2
- package/dist/core/proof/route-finalizer.js +35 -3
- package/dist/core/qa-loop/qa-app-server-driver.js +134 -0
- package/dist/core/qa-loop/qa-contract-v2.js +231 -0
- package/dist/core/qa-loop/qa-gate-v2.js +132 -0
- package/dist/core/qa-loop/qa-runtime-artifacts.js +53 -0
- package/dist/core/qa-loop/qa-surface-router.js +114 -0
- package/dist/core/qa-loop/qa-types.js +18 -0
- package/dist/core/qa-loop.js +83 -26
- package/dist/core/release/gate-manifest.js +1 -0
- package/dist/core/release/sla-scheduler.js +1 -1
- package/dist/core/release-parallel-full-coverage.js +1 -1
- package/dist/core/routes.js +96 -14
- package/dist/core/search-visibility/adapter-registry.js +26 -0
- package/dist/core/search-visibility/adapters/next-app.js +6 -0
- package/dist/core/search-visibility/adapters/next-pages.js +6 -0
- package/dist/core/search-visibility/adapters/static-site.js +6 -0
- package/dist/core/search-visibility/analyzers.js +377 -0
- package/dist/core/search-visibility/artifacts.js +183 -0
- package/dist/core/search-visibility/discovery.js +347 -0
- package/dist/core/search-visibility/index.js +199 -0
- package/dist/core/search-visibility/mission.js +67 -0
- package/dist/core/search-visibility/mutation.js +314 -0
- package/dist/core/search-visibility/types.js +2 -0
- package/dist/core/search-visibility/verifier.js +60 -0
- package/dist/core/source-intelligence/source-intelligence-policy.js +45 -26
- package/dist/core/source-intelligence/source-intelligence-proof.js +10 -16
- package/dist/core/source-intelligence/source-intelligence-runner.js +56 -42
- package/dist/core/triwiki/triwiki-affected-graph.js +3 -2
- package/dist/core/trust-kernel/trust-report.js +3 -5
- package/dist/core/ultra-search/index.js +3 -0
- package/dist/core/ultra-search/runtime.js +502 -0
- package/dist/core/ultra-search/types.js +3 -0
- package/dist/core/version.js +1 -1
- package/dist/scripts/agent-visual-consistency-check.js +1 -1
- package/dist/scripts/check-architecture.js +40 -7
- package/dist/scripts/check-command-module-budget.js +43 -5
- package/dist/scripts/check-pipeline-budget.js +17 -30
- package/dist/scripts/check-publish-tag.js +33 -6
- package/dist/scripts/check-route-modularity.js +25 -33
- package/dist/scripts/check-runtime-schemas.js +22 -0
- package/dist/scripts/codex-control-all-pipelines-check.js +1 -0
- package/dist/scripts/codex-control-model-capacity-fallback-check.js +53 -0
- package/dist/scripts/config-managed-merge-callsite-coverage-check.js +7 -1
- package/dist/scripts/core-skill-immutable-sync-check.js +3 -2
- package/dist/scripts/core-skill-integrity-blackbox.js +3 -2
- package/dist/scripts/core-skill-manifest-check.js +7 -2
- package/dist/scripts/geo-claim-evidence-check.js +18 -0
- package/dist/scripts/geo-cli-blackbox-check.js +18 -0
- package/dist/scripts/geo-crawler-policy-check.js +16 -0
- package/dist/scripts/geo-llms-txt-optional-check.js +19 -0
- package/dist/scripts/gpt-final-arbiter-check.js +4 -1
- package/dist/scripts/loop-directive-check-lib.js +78 -1
- package/dist/scripts/qa-loop-app-server-driver-check.js +74 -0
- package/dist/scripts/qa-loop-surface-router-check.js +49 -0
- package/dist/scripts/release-check-dynamic-execute.js +1 -1
- package/dist/scripts/release-metadata-1-19-check.js +2 -2
- package/dist/scripts/release-parallel-check.js +17 -2
- package/dist/scripts/release-parallel-full-coverage-check.js +1 -1
- package/dist/scripts/release-readiness-report.js +6 -6
- package/dist/scripts/release-registry-check.js +33 -14
- package/dist/scripts/runtime-ts-rust-boundary-check.js +1 -1
- package/dist/scripts/search-visibility-gate-lib.js +124 -0
- package/dist/scripts/seo-audit-fixture-check.js +16 -0
- package/dist/scripts/seo-canonical-locale-check.js +19 -0
- package/dist/scripts/seo-cli-blackbox-check.js +18 -0
- package/dist/scripts/seo-geo-feature-fixture-quality-check.js +18 -0
- package/dist/scripts/seo-geo-geo-disambiguation-check.js +12 -0
- package/dist/scripts/seo-geo-no-unsupported-ranking-claims-check.js +18 -0
- package/dist/scripts/seo-geo-route-identity-check.js +12 -0
- package/dist/scripts/seo-geo-skill-rich-content-check.js +22 -0
- package/dist/scripts/seo-mutation-rollback-check.js +23 -0
- package/dist/scripts/seo-no-mutation-by-default-check.js +17 -0
- package/dist/scripts/seo-structured-data-visible-content-check.js +19 -0
- package/dist/scripts/sks-1-18-gate-lib.js +2 -2
- package/dist/scripts/sks-3-1-5-directive-check-lib.js +10 -1
- package/dist/scripts/source-intelligence-all-modes-check.js +9 -19
- package/dist/scripts/source-intelligence-policy-check.js +6 -6
- package/dist/scripts/triwiki-affected-graph-check.js +2 -2
- package/dist/scripts/ultra-search-provider-interface-check.js +27 -0
- package/package.json +26 -5
- package/schemas/search-visibility/finding-ledger.schema.json +36 -0
- package/schemas/search-visibility/gate.schema.json +22 -0
- package/schemas/search-visibility/mutation-plan.schema.json +27 -0
- package/schemas/search-visibility/site-inventory.schema.json +21 -0
- package/schemas/search-visibility/verification-report.schema.json +23 -0
- package/dist/core/mcp/xai-mcp-detector.js +0 -157
- package/dist/core/mcp/xai-search-adapter.js +0 -100
- package/dist/scripts/xai-mcp-capability-check.js +0 -14
|
@@ -8,10 +8,12 @@ export class CodexAppServerV2Client {
|
|
|
8
8
|
cwd;
|
|
9
9
|
timeoutMs;
|
|
10
10
|
currentTimeProvider;
|
|
11
|
+
approvalPolicy;
|
|
11
12
|
child = null;
|
|
12
13
|
nextId = 1;
|
|
13
14
|
pending = new Map();
|
|
14
15
|
notifications = [];
|
|
16
|
+
listeners = new Set();
|
|
15
17
|
stdoutBuffer = '';
|
|
16
18
|
stderr = '';
|
|
17
19
|
constructor(options) {
|
|
@@ -21,6 +23,7 @@ export class CodexAppServerV2Client {
|
|
|
21
23
|
this.cwd = options.cwd || process.cwd();
|
|
22
24
|
this.timeoutMs = Number(options.timeoutMs || 20_000);
|
|
23
25
|
this.currentTimeProvider = options.currentTimeProvider || (() => new Date());
|
|
26
|
+
this.approvalPolicy = options.approvalPolicy || {};
|
|
24
27
|
}
|
|
25
28
|
async initialize() {
|
|
26
29
|
this.start();
|
|
@@ -36,18 +39,58 @@ export class CodexAppServerV2Client {
|
|
|
36
39
|
optOutNotificationMethods: []
|
|
37
40
|
}
|
|
38
41
|
});
|
|
39
|
-
this.notify('
|
|
42
|
+
this.notify('initialized', {});
|
|
40
43
|
return result;
|
|
41
44
|
}
|
|
42
45
|
async listThreads(params = {}) {
|
|
43
46
|
return await this.request('thread/list', normalizeThreadListParams(params));
|
|
44
47
|
}
|
|
48
|
+
async startThread(params = {}) {
|
|
49
|
+
return await this.request('thread/start', params);
|
|
50
|
+
}
|
|
51
|
+
async resumeThread(params = {}) {
|
|
52
|
+
return await this.request('thread/resume', params);
|
|
53
|
+
}
|
|
45
54
|
async searchThreads(searchTerm, params = {}) {
|
|
46
55
|
return await this.listThreads({ ...params, searchTerm });
|
|
47
56
|
}
|
|
48
57
|
async readThread(threadId, includeTurns = false) {
|
|
49
58
|
return await this.request('thread/read', { threadId, includeTurns });
|
|
50
59
|
}
|
|
60
|
+
async startTurn(params = {}) {
|
|
61
|
+
return await this.request('turn/start', params);
|
|
62
|
+
}
|
|
63
|
+
async steerTurn(params = {}) {
|
|
64
|
+
return await this.request('turn/steer', params);
|
|
65
|
+
}
|
|
66
|
+
async interruptTurn(params = {}) {
|
|
67
|
+
return await this.request('turn/interrupt', params);
|
|
68
|
+
}
|
|
69
|
+
onEvent(listener) {
|
|
70
|
+
this.listeners.add(listener);
|
|
71
|
+
return () => this.listeners.delete(listener);
|
|
72
|
+
}
|
|
73
|
+
waitForNotification(methods, timeoutMs = this.timeoutMs) {
|
|
74
|
+
const expected = new Set(Array.isArray(methods) ? methods.map(String) : [String(methods)]);
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
const timer = setTimeout(() => {
|
|
77
|
+
dispose();
|
|
78
|
+
reject(new Error(`Timed out waiting for app-server notification: ${Array.from(expected).join(', ')}`));
|
|
79
|
+
}, timeoutMs);
|
|
80
|
+
timer.unref?.();
|
|
81
|
+
const dispose = this.onEvent((event) => {
|
|
82
|
+
if (event && expected.has(String(event.method || ''))) {
|
|
83
|
+
clearTimeout(timer);
|
|
84
|
+
dispose();
|
|
85
|
+
resolve(event);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
async waitForTurnCompletion(threadId, turnId, timeoutMs = this.timeoutMs) {
|
|
91
|
+
const expected = turnId ? ['turn/completed', 'thread/closed', 'thread/status/changed'] : ['turn/completed', 'thread/closed'];
|
|
92
|
+
return await this.waitForNotification(expected, timeoutMs);
|
|
93
|
+
}
|
|
51
94
|
start() {
|
|
52
95
|
if (this.child)
|
|
53
96
|
return;
|
|
@@ -107,7 +150,14 @@ export class CodexAppServerV2Client {
|
|
|
107
150
|
void this.respondToServerRequest(message);
|
|
108
151
|
}
|
|
109
152
|
else {
|
|
110
|
-
|
|
153
|
+
const event = { ...message, received_at: nowIso() };
|
|
154
|
+
this.notifications.push(event);
|
|
155
|
+
for (const listener of this.listeners) {
|
|
156
|
+
try {
|
|
157
|
+
listener(event);
|
|
158
|
+
}
|
|
159
|
+
catch { }
|
|
160
|
+
}
|
|
111
161
|
}
|
|
112
162
|
}
|
|
113
163
|
}
|
|
@@ -119,6 +169,38 @@ export class CodexAppServerV2Client {
|
|
|
119
169
|
this.write({ jsonrpc: '2.0', id, result: currentTimeResponse(this.currentTimeProvider()) });
|
|
120
170
|
return;
|
|
121
171
|
}
|
|
172
|
+
if (method === 'item/commandExecution/requestApproval' || method === 'commandExecution/requestApproval') {
|
|
173
|
+
this.write({ jsonrpc: '2.0', id, result: this.approvalPolicy.commandExecution?.(message.params) || { decision: 'cancel' } });
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (method === 'item/fileChange/requestApproval' || method === 'fileChange/requestApproval') {
|
|
177
|
+
this.write({ jsonrpc: '2.0', id, result: this.approvalPolicy.fileChange?.(message.params) || { decision: 'cancel' } });
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (method === 'item/permissions/requestApproval' || method === 'permissions/requestApproval') {
|
|
181
|
+
this.write({ jsonrpc: '2.0', id, result: this.approvalPolicy.permissions?.(message.params) || { permissions: { network: { enabled: false }, fileSystem: { read: [], write: [], entries: [] } }, scope: 'turn', strictAutoReview: true } });
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (method === 'item/tool/requestUserInput') {
|
|
185
|
+
this.write({ jsonrpc: '2.0', id, result: this.approvalPolicy.toolRequestUserInput?.(message.params) || { answers: {} } });
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (method === 'item/tool/call') {
|
|
189
|
+
this.write({ jsonrpc: '2.0', id, result: this.approvalPolicy.dynamicToolCall?.(message.params) || { contentItems: [], success: false } });
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (method === 'mcpServer/elicitation/request') {
|
|
193
|
+
this.write({ jsonrpc: '2.0', id, result: this.approvalPolicy.mcpElicitation?.(message.params) || { contentItems: [], success: false } });
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (method === 'attestation/generate') {
|
|
197
|
+
this.write({ jsonrpc: '2.0', id, result: this.approvalPolicy.attestation?.(message.params) || { decision: 'cancel' } });
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (method === 'account/chatgptAuthTokens/refresh') {
|
|
201
|
+
this.write({ jsonrpc: '2.0', id, result: this.approvalPolicy.chatgptAuthTokensRefresh?.(message.params) || { ok: false } });
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
122
204
|
this.write({
|
|
123
205
|
jsonrpc: '2.0',
|
|
124
206
|
id,
|
|
@@ -182,6 +264,8 @@ export async function createCodexAppServerV2Client(options = {}) {
|
|
|
182
264
|
clientOptions.timeoutMs = options.timeoutMs;
|
|
183
265
|
if (options.currentTimeProvider !== undefined)
|
|
184
266
|
clientOptions.currentTimeProvider = options.currentTimeProvider;
|
|
267
|
+
if (options.approvalPolicy !== undefined)
|
|
268
|
+
clientOptions.approvalPolicy = options.approvalPolicy;
|
|
185
269
|
return {
|
|
186
270
|
client: new CodexAppServerV2Client(clientOptions),
|
|
187
271
|
runtimeIdentity: runtime.identity
|
|
@@ -27,22 +27,44 @@ export async function runFakeCodexSdkTask(input) {
|
|
|
27
27
|
}
|
|
28
28
|
function fakeStructuredOutput(input) {
|
|
29
29
|
if (input.outputSchemaId === GPT_FINAL_ARBITER_RESULT_SCHEMA_ID) {
|
|
30
|
-
const
|
|
30
|
+
const prompt = String(input.prompt || '');
|
|
31
|
+
const leanEnabled = /\b(Lean review|Lean Engineering Policy|sks\.lean-engineering-policy)\b/i.test(prompt);
|
|
32
|
+
const unsafe = /\b(truncate|delete all|drop table|credential|delete validation|validation removed|path traversal|sql injection|secret leak)\b/i.test(prompt);
|
|
33
|
+
const overbuild = leanEnabled ? classifyLeanOverbuild(prompt) : null;
|
|
34
|
+
const status = unsafe ? 'rejected' : overbuild ? 'needs_more_work' : 'approved';
|
|
35
|
+
const leanStatus = unsafe ? 'rejected' : overbuild ? 'needs_more_work' : 'pass';
|
|
36
|
+
const blockers = unsafe ? ['unsafe_candidate_patch'] : overbuild?.blockers || [];
|
|
37
|
+
const findings = unsafe
|
|
38
|
+
? [{ id: 'unsafe-candidate', severity: 'high', summary: 'unsafe candidate rejected' }]
|
|
39
|
+
: overbuild ? overbuild.findings : [];
|
|
31
40
|
return {
|
|
32
41
|
schema: GPT_FINAL_ARBITER_RESULT_SCHEMA_ID,
|
|
33
|
-
status
|
|
42
|
+
status,
|
|
34
43
|
summary: unsafe
|
|
35
44
|
? 'Fake Codex SDK GPT final arbiter rejected an unsafe candidate for hermetic verification.'
|
|
36
|
-
:
|
|
37
|
-
|
|
38
|
-
|
|
45
|
+
: overbuild
|
|
46
|
+
? 'Fake Codex SDK GPT final arbiter requested a leaner candidate for hermetic verification.'
|
|
47
|
+
: 'Fake Codex SDK GPT final arbiter approved the candidate for hermetic verification.',
|
|
48
|
+
gpt_review_findings: findings,
|
|
49
|
+
accepted_patch_envelopes: status === 'approved' ? [] : [],
|
|
39
50
|
modified_patch_envelopes: [],
|
|
40
|
-
rejected_patch_envelopes:
|
|
41
|
-
required_followup_work:
|
|
51
|
+
rejected_patch_envelopes: status === 'rejected' ? [{ id: blockers[0] || 'rejected-candidate', summary: blockers[0] || 'rejected candidate', patch_envelope_json: '{}' }] : [],
|
|
52
|
+
required_followup_work: blockers.map((blocker) => ({ id: blocker, severity: unsafe ? 'high' : 'medium', summary: blocker })),
|
|
42
53
|
verification_plan: ['schema validation', 'local collaboration final gate'],
|
|
43
54
|
rollback_notes: [],
|
|
44
|
-
blockers
|
|
45
|
-
|
|
55
|
+
blockers,
|
|
56
|
+
lean_review: {
|
|
57
|
+
status: leanStatus,
|
|
58
|
+
selected_rung: unsafe ? 'unknown' : overbuild?.selected_rung || 'minimal-custom',
|
|
59
|
+
unnecessary_files: [],
|
|
60
|
+
unnecessary_dependencies: overbuild?.unnecessary_dependencies || [],
|
|
61
|
+
unnecessary_abstractions: overbuild?.unnecessary_abstractions || [],
|
|
62
|
+
fallback_findings: unsafe ? ['unsafe_candidate_patch'] : overbuild?.fallback_findings || [],
|
|
63
|
+
root_cause_review: overbuild?.root_cause_review || [],
|
|
64
|
+
verification_minimum_present: !unsafe && !/\b(missing runnable check|no runnable check)\b/i.test(prompt),
|
|
65
|
+
net_lines: null
|
|
66
|
+
},
|
|
67
|
+
confidence: unsafe || overbuild ? 'medium' : 'high'
|
|
46
68
|
};
|
|
47
69
|
}
|
|
48
70
|
return {
|
|
@@ -56,4 +78,40 @@ function fakeStructuredOutput(input) {
|
|
|
56
78
|
blockers: []
|
|
57
79
|
};
|
|
58
80
|
}
|
|
81
|
+
function classifyLeanOverbuild(prompt) {
|
|
82
|
+
if (/\b(existing helper reimplementation|same helper reimplementation|reimplement existing helper)\b/i.test(prompt)) {
|
|
83
|
+
return leanFinding('reuse_existing_helper', 'reuse-existing', 'Candidate reimplements an existing helper instead of reusing the repository authority.', {
|
|
84
|
+
root_cause_review: ['reuse existing helper or fix the common helper once']
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if (/\b(new dependency|dependency bloat|native platform instead of dependency)\b/i.test(prompt)) {
|
|
88
|
+
return leanFinding('unnecessary_dependency', 'stdlib', 'Candidate adds a dependency where stdlib or platform support is sufficient.', {
|
|
89
|
+
unnecessary_dependencies: ['unjustified dependency']
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (/\b(one implementation factory|single implementation factory|one implementation interface)\b/i.test(prompt)) {
|
|
93
|
+
return leanFinding('single_impl_abstraction', 'minimal-custom', 'Candidate adds an abstraction without a second implementation or real variation axis.', {
|
|
94
|
+
unnecessary_abstractions: ['single implementation factory/interface']
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (/\b(hidden mock fallback|silent mock fallback|fixture fallback)\b/i.test(prompt)) {
|
|
98
|
+
return leanFinding('hidden_fallback', 'minimal-custom', 'Candidate hides a production failure behind a mock or fixture fallback.', {
|
|
99
|
+
fallback_findings: ['hidden mock fallback']
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (/\b(caller duplicate guard|duplicate caller guard|symptom patch)\b/i.test(prompt)) {
|
|
103
|
+
return leanFinding('root_cause_missing', 'minimal-custom', 'Candidate patches a caller symptom instead of the shared root cause.', {
|
|
104
|
+
root_cause_review: ['move duplicated guard to the shared root-cause helper']
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
function leanFinding(id, selectedRung, summary, extra = {}) {
|
|
110
|
+
return {
|
|
111
|
+
selected_rung: selectedRung,
|
|
112
|
+
blockers: [id],
|
|
113
|
+
findings: [{ id, severity: 'medium', summary }],
|
|
114
|
+
...extra
|
|
115
|
+
};
|
|
116
|
+
}
|
|
59
117
|
//# sourceMappingURL=codex-fake-sdk-adapter.js.map
|
|
@@ -37,6 +37,7 @@ export async function runWithCodexReliabilityShield(input, runAttempt) {
|
|
|
37
37
|
break;
|
|
38
38
|
}
|
|
39
39
|
const blockers = attempts.flatMap((attempt) => attempt.blockers);
|
|
40
|
+
const modelCapacityRetryCount = attempts.filter((attempt) => attempt.model_capacity_error && attempt.retryable).length;
|
|
40
41
|
const report = {
|
|
41
42
|
schema: CODEX_RELIABILITY_SHIELD_SCHEMA,
|
|
42
43
|
generated_at: nowIso(),
|
|
@@ -52,6 +53,8 @@ export async function runWithCodexReliabilityShield(input, runAttempt) {
|
|
|
52
53
|
heartbeat_count: attempts.reduce((sum, attempt) => sum + attempt.heartbeat_count, 0),
|
|
53
54
|
repaired_tool_result_count: attempts.reduce((sum, attempt) => sum + attempt.repaired_tool_result_count, 0),
|
|
54
55
|
no_duplicate_streamed_output: attempts.slice(0, -1).every((attempt) => attempt.meaningful_event_count === 0),
|
|
56
|
+
model_capacity_retry_count: modelCapacityRetryCount,
|
|
57
|
+
selected_model_capacity_fallback: selectedAttempt > 1 && modelCapacityRetryCount > 0,
|
|
55
58
|
blockers
|
|
56
59
|
};
|
|
57
60
|
return {
|
|
@@ -61,24 +64,27 @@ export async function runWithCodexReliabilityShield(input, runAttempt) {
|
|
|
61
64
|
}
|
|
62
65
|
export function evaluateCodexReliabilityAttempt(result, events, policy, attempt) {
|
|
63
66
|
const meaningful = events.filter(isMeaningfulEvent);
|
|
64
|
-
const
|
|
67
|
+
const modelCapacity = isCodexModelCapacityError(result, events);
|
|
68
|
+
const fatal = !modelCapacity && hasFatalError(result, events);
|
|
65
69
|
const idle = hasIdleTimeout(events, policy.idleTimeoutMs);
|
|
66
70
|
const empty = events.length === 0 || (!String(result.finalResponse || '').trim() && meaningful.length === 0);
|
|
67
71
|
const partial = meaningful.length > 0 && !result.structuredOutput;
|
|
68
72
|
const blockers = [];
|
|
69
73
|
let retryable = false;
|
|
70
74
|
let retryReason = null;
|
|
71
|
-
if (
|
|
75
|
+
if (modelCapacity)
|
|
76
|
+
blockers.push('codex_model_capacity_unavailable');
|
|
77
|
+
if (!modelCapacity && idle && partial)
|
|
72
78
|
blockers.push('codex_reliability_idle_after_partial_output');
|
|
73
|
-
if (partial && !idle)
|
|
79
|
+
if (!modelCapacity && partial && !idle)
|
|
74
80
|
blockers.push('codex_reliability_partial_output_without_structured_result');
|
|
75
81
|
if (fatal)
|
|
76
82
|
blockers.push('codex_reliability_fatal_error_no_retry');
|
|
77
|
-
if (!fatal && idle && meaningful.length === 0) {
|
|
83
|
+
if (!modelCapacity && !fatal && idle && meaningful.length === 0) {
|
|
78
84
|
retryable = true;
|
|
79
85
|
retryReason = 'stream_idle_before_meaningful_event';
|
|
80
86
|
}
|
|
81
|
-
else if (!fatal && empty) {
|
|
87
|
+
else if (!modelCapacity && !fatal && empty) {
|
|
82
88
|
retryable = true;
|
|
83
89
|
retryReason = 'empty_sdk_result_before_meaningful_event';
|
|
84
90
|
}
|
|
@@ -92,11 +98,26 @@ export function evaluateCodexReliabilityAttempt(result, events, policy, attempt)
|
|
|
92
98
|
retry_reason: retryReason,
|
|
93
99
|
idle_timeout: idle,
|
|
94
100
|
fatal_error: fatal,
|
|
101
|
+
model_capacity_error: modelCapacity,
|
|
102
|
+
capacity_fallback_hint: null,
|
|
95
103
|
repaired_tool_result_count: 0,
|
|
96
104
|
heartbeat_count: 0,
|
|
97
105
|
blockers
|
|
98
106
|
};
|
|
99
107
|
}
|
|
108
|
+
export function isCodexModelCapacityError(result, events) {
|
|
109
|
+
const text = [
|
|
110
|
+
String(result.finalResponse || ''),
|
|
111
|
+
...(Array.isArray(result.blockers) ? result.blockers : []),
|
|
112
|
+
...events.map((event) => [
|
|
113
|
+
event?.error?.message,
|
|
114
|
+
event?.message,
|
|
115
|
+
event?.item?.text,
|
|
116
|
+
event?.raw?.failed_event?.error?.message
|
|
117
|
+
].filter(Boolean).join('\n'))
|
|
118
|
+
].join('\n');
|
|
119
|
+
return /selected model is at capacity|model(?:\s+[\w.-]+)?\s+is\s+at\s+capacity|try a different model|capacity(?:\s+is)?\s+exhausted|temporarily at capacity/i.test(text);
|
|
120
|
+
}
|
|
100
121
|
export function repairToolCallSequence(events) {
|
|
101
122
|
const repaired = [...events];
|
|
102
123
|
const openToolCalls = new Set();
|
|
@@ -118,6 +118,8 @@ export async function runCodexTask(input) {
|
|
|
118
118
|
patchEnvelopePath,
|
|
119
119
|
blockers: finalBlockers,
|
|
120
120
|
reliabilityShield: adapterResult?.reliabilityShield || null,
|
|
121
|
+
capacityFallback: adapterResult?.reliabilityShield?.selected_model_capacity_fallback === true,
|
|
122
|
+
modelCapacityRetryCount: Number(adapterResult?.reliabilityShield?.model_capacity_retry_count || 0),
|
|
121
123
|
ultraRouterDecision: routerDecision,
|
|
122
124
|
outputSchemaId: task.outputSchemaId,
|
|
123
125
|
finalResponse: adapterResult?.finalResponse || '',
|
|
@@ -146,7 +148,11 @@ export async function runCodexTask(input) {
|
|
|
146
148
|
result,
|
|
147
149
|
capability: capability,
|
|
148
150
|
sandbox,
|
|
149
|
-
envProof:
|
|
151
|
+
envProof: {
|
|
152
|
+
...runtime.env.proof,
|
|
153
|
+
capacity_fallback_selected: result.capacityFallback === true,
|
|
154
|
+
model_capacity_retry_count: result.modelCapacityRetryCount
|
|
155
|
+
},
|
|
150
156
|
config: runtime.config,
|
|
151
157
|
reliabilityShield: adapterResult?.reliabilityShield || null,
|
|
152
158
|
routerDecision: routerDecision,
|
|
@@ -5,6 +5,7 @@ import { evaluateLocalCollaborationFinalGate, resolveLocalCollaborationPolicy }
|
|
|
5
5
|
import { runCodexTask } from './codex-control-plane.js';
|
|
6
6
|
import { GPT_FINAL_ARBITER_INPUT_SCHEMA, GPT_FINAL_ARBITER_RESULT_SCHEMA_ID, gptFinalArbiterResultSchema, normalizeGptFinalArbiterResult } from './gpt-final-review-schema.js';
|
|
7
7
|
import { compressGptFinalContext } from './gpt-final-context-compressor.js';
|
|
8
|
+
import { leanEngineeringCompactText } from '../lean-engineering-policy.js';
|
|
8
9
|
export const GPT_FINAL_ARBITER_RUN_SCHEMA = 'sks.gpt-final-arbiter-run.v1';
|
|
9
10
|
export async function runGptFinalArbiter(input, opts = {}) {
|
|
10
11
|
const started = Date.now();
|
|
@@ -145,7 +146,9 @@ function buildArbiterPrompt(input, compressed) {
|
|
|
145
146
|
return [
|
|
146
147
|
'You are the GPT Final Arbiter for an SKS local collaboration run.',
|
|
147
148
|
'Local model outputs are drafts only. Review the proof pack, candidate diff, patch envelopes, verification results, side effects, mutation ledger, and rollback plan.',
|
|
148
|
-
|
|
149
|
+
leanEngineeringCompactText(),
|
|
150
|
+
'Lean review: check for reused helpers before reimplementation, unjustified dependencies, one-implementation factories/interfaces, hidden mock or provider fallbacks, duplicated caller guards instead of root-cause fixes, forwarding-only files, missing runnable checks for non-trivial logic, and safety/validation removal disguised as simplification.',
|
|
151
|
+
'Approve or modify only when the candidate is safe, supported, and no more complex than the request requires. Reject unsafe local patches. Return only the requested structured JSON schema.',
|
|
149
152
|
JSON.stringify({
|
|
150
153
|
route: input.route,
|
|
151
154
|
mission_id: input.mission_id,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LEAN_SOLUTION_RUNGS } from '../lean-engineering-policy.js';
|
|
1
2
|
export const GPT_FINAL_ARBITER_RESULT_SCHEMA_ID = 'sks.gpt-final-arbiter-result.v1';
|
|
2
3
|
export const GPT_FINAL_ARBITER_INPUT_SCHEMA = 'sks.gpt-final-arbiter-input.v1';
|
|
3
4
|
const reviewItemSchema = {
|
|
@@ -20,6 +21,32 @@ const patchDecisionSchema = {
|
|
|
20
21
|
},
|
|
21
22
|
additionalProperties: false
|
|
22
23
|
};
|
|
24
|
+
const leanReviewSchema = {
|
|
25
|
+
type: 'object',
|
|
26
|
+
required: [
|
|
27
|
+
'status',
|
|
28
|
+
'selected_rung',
|
|
29
|
+
'unnecessary_files',
|
|
30
|
+
'unnecessary_dependencies',
|
|
31
|
+
'unnecessary_abstractions',
|
|
32
|
+
'fallback_findings',
|
|
33
|
+
'root_cause_review',
|
|
34
|
+
'verification_minimum_present',
|
|
35
|
+
'net_lines'
|
|
36
|
+
],
|
|
37
|
+
properties: {
|
|
38
|
+
status: { enum: ['pass', 'modified', 'rejected', 'needs_more_work'] },
|
|
39
|
+
selected_rung: { enum: [...LEAN_SOLUTION_RUNGS, 'unknown'] },
|
|
40
|
+
unnecessary_files: { type: 'array', items: { type: 'string' } },
|
|
41
|
+
unnecessary_dependencies: { type: 'array', items: { type: 'string' } },
|
|
42
|
+
unnecessary_abstractions: { type: 'array', items: { type: 'string' } },
|
|
43
|
+
fallback_findings: { type: 'array', items: { type: 'string' } },
|
|
44
|
+
root_cause_review: { type: 'array', items: { type: 'string' } },
|
|
45
|
+
verification_minimum_present: { type: 'boolean' },
|
|
46
|
+
net_lines: { type: ['number', 'null'] }
|
|
47
|
+
},
|
|
48
|
+
additionalProperties: false
|
|
49
|
+
};
|
|
23
50
|
export const gptFinalArbiterResultSchema = {
|
|
24
51
|
type: 'object',
|
|
25
52
|
required: [
|
|
@@ -34,6 +61,7 @@ export const gptFinalArbiterResultSchema = {
|
|
|
34
61
|
'verification_plan',
|
|
35
62
|
'rollback_notes',
|
|
36
63
|
'blockers',
|
|
64
|
+
'lean_review',
|
|
37
65
|
'confidence'
|
|
38
66
|
],
|
|
39
67
|
properties: {
|
|
@@ -48,6 +76,7 @@ export const gptFinalArbiterResultSchema = {
|
|
|
48
76
|
verification_plan: { type: 'array', items: { type: 'string' } },
|
|
49
77
|
rollback_notes: { type: 'array', items: { type: 'string' } },
|
|
50
78
|
blockers: { type: 'array', items: { type: 'string' } },
|
|
79
|
+
lean_review: leanReviewSchema,
|
|
51
80
|
confidence: { enum: ['low', 'medium', 'high'] }
|
|
52
81
|
},
|
|
53
82
|
additionalProperties: false
|
|
@@ -66,6 +95,7 @@ export function normalizeGptFinalArbiterResult(value) {
|
|
|
66
95
|
verification_plan: stringArray(value?.verification_plan),
|
|
67
96
|
rollback_notes: stringArray(value?.rollback_notes),
|
|
68
97
|
blockers: stringArray(value?.blockers),
|
|
98
|
+
lean_review: normalizeLeanReview(value?.lean_review, status),
|
|
69
99
|
confidence: normalizeConfidence(value?.confidence)
|
|
70
100
|
};
|
|
71
101
|
}
|
|
@@ -107,6 +137,34 @@ function patchDecisionItems(value) {
|
|
|
107
137
|
function stringArray(value) {
|
|
108
138
|
return Array.isArray(value) ? value.map((entry) => String(entry || '').trim()).filter(Boolean) : [];
|
|
109
139
|
}
|
|
140
|
+
function normalizeLeanReview(value, arbiterStatus) {
|
|
141
|
+
const raw = typeof value === 'object' && value !== null ? value : {};
|
|
142
|
+
return {
|
|
143
|
+
status: normalizeLeanReviewStatus(raw.status, arbiterStatus),
|
|
144
|
+
selected_rung: normalizeLeanRung(raw.selected_rung),
|
|
145
|
+
unnecessary_files: stringArray(raw.unnecessary_files),
|
|
146
|
+
unnecessary_dependencies: stringArray(raw.unnecessary_dependencies),
|
|
147
|
+
unnecessary_abstractions: stringArray(raw.unnecessary_abstractions),
|
|
148
|
+
fallback_findings: stringArray(raw.fallback_findings),
|
|
149
|
+
root_cause_review: stringArray(raw.root_cause_review),
|
|
150
|
+
verification_minimum_present: typeof raw.verification_minimum_present === 'boolean' ? raw.verification_minimum_present : arbiterStatus === 'approved' || arbiterStatus === 'modified',
|
|
151
|
+
net_lines: Number.isFinite(Number(raw.net_lines)) ? Number(raw.net_lines) : null
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function normalizeLeanReviewStatus(value, arbiterStatus) {
|
|
155
|
+
if (value === 'pass' || value === 'modified' || value === 'rejected' || value === 'needs_more_work')
|
|
156
|
+
return value;
|
|
157
|
+
if (arbiterStatus === 'approved')
|
|
158
|
+
return 'pass';
|
|
159
|
+
if (arbiterStatus === 'modified')
|
|
160
|
+
return 'modified';
|
|
161
|
+
if (arbiterStatus === 'rejected')
|
|
162
|
+
return 'rejected';
|
|
163
|
+
return 'needs_more_work';
|
|
164
|
+
}
|
|
165
|
+
function normalizeLeanRung(value) {
|
|
166
|
+
return typeof value === 'string' && [...LEAN_SOLUTION_RUNGS, 'unknown'].includes(value) ? value : 'unknown';
|
|
167
|
+
}
|
|
110
168
|
function normalizeSeverity(value) {
|
|
111
169
|
return value === 'low' || value === 'medium' || value === 'high' ? value : 'medium';
|
|
112
170
|
}
|
|
@@ -56,7 +56,7 @@ export function defaultModelCallBudget(provider) {
|
|
|
56
56
|
const text = String(provider || '');
|
|
57
57
|
if (text === 'local-llm' || text === 'ollama')
|
|
58
58
|
return envInt('SKS_LOCAL_LLM_MAX_PARALLEL_REQUESTS', 4);
|
|
59
|
-
return envInt('SKS_REMOTE_API_PARALLEL_BUDGET',
|
|
59
|
+
return envInt('SKS_REMOTE_API_PARALLEL_BUDGET', 3);
|
|
60
60
|
}
|
|
61
61
|
class ModelCallSemaphoreImpl {
|
|
62
62
|
provider;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PACKAGE_VERSION, nowIso, sha256 } from '../fsx.js';
|
|
2
|
+
import { leanPolicyReference } from '../lean-engineering-policy.js';
|
|
2
3
|
import { canonicalSkillName } from './skill-name-canonicalizer.js';
|
|
3
4
|
export const CORE_SKILL_TEMPLATE_VERSION = 'sks-core-skill-template.v1';
|
|
4
5
|
export const CORE_SKILL_MANAGED_BEGIN = '<!-- BEGIN SKS IMMUTABLE CORE SKILL -->';
|
|
@@ -83,6 +84,26 @@ const CORE_SKILL_DEFINITIONS = [
|
|
|
83
84
|
when: 'Use when deeper local context or directory-specific recall is required.',
|
|
84
85
|
evidence: '.sneakoscope/context/AGENTS.generated.md and managed memory artifacts.',
|
|
85
86
|
fallback: 'Preserve user content and skip directories that cannot be safely updated.'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: 'sks-core-search-visibility-core',
|
|
90
|
+
canonical_name: 'search-visibility-core',
|
|
91
|
+
display_name: 'search-visibility-core',
|
|
92
|
+
route: '$SEO-GEO-OPTIMIZER',
|
|
93
|
+
purpose: 'provide the shared search-visibility kernel for SEO and GEO audit, plan, explicit apply, verify, rollback, and Completion Proof without ranking, traffic, or citation guarantees.',
|
|
94
|
+
when: 'Use when $SEO-GEO-OPTIMIZER or sks seo-geo-optimizer needs typed mode-specific evidence, gates, artifacts, or safe mutation planning.',
|
|
95
|
+
evidence: 'search-visibility artifacts, seo-gate.json or geo-gate.json, mutation-plan.json, rollback-manifest.json, verification-report.json, and completion-proof.json.',
|
|
96
|
+
fallback: 'Keep unsupported frameworks plan-only, record unverified production/browser/Search Console/AI citation outcomes, and never invent guarantee evidence.'
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'sks-core-seo-geo-optimizer',
|
|
100
|
+
canonical_name: 'seo-geo-optimizer',
|
|
101
|
+
display_name: 'seo-geo-optimizer',
|
|
102
|
+
route: '$SEO-GEO-OPTIMIZER',
|
|
103
|
+
purpose: 'run the unified SEO/GEO optimizer route for Search Engine Optimization and Generative Engine Optimization, not geolocation or GeoIP, with no ranking, traffic, indexing, rich-result, answer inclusion, or AI citation guarantee.',
|
|
104
|
+
when: 'Use the CLI entrypoint: sks seo-geo-optimizer doctor|audit|plan|apply|verify|status|rollback|fixture --mode seo|geo for SEO and GEO visibility work.',
|
|
105
|
+
evidence: 'site inventory, route graph, seo-findings.json or geo-findings.json, claim-evidence-ledger.json, ai-crawler-policy.json, llms-txt-plan.json, verification report, route gate, and Completion Proof.',
|
|
106
|
+
fallback: 'Do not auto-allow training crawlers or fabricate AI answer visibility; mark missing live outcomes unverified and keep recovery on the unified optimizer route.'
|
|
86
107
|
}
|
|
87
108
|
];
|
|
88
109
|
export function coreSkillDefinitions() {
|
|
@@ -97,6 +118,7 @@ export function renderCoreSkillTemplate(name) {
|
|
|
97
118
|
const skill = CORE_SKILL_DEFINITIONS.find((entry) => entry.canonical_name === canonical);
|
|
98
119
|
if (!skill)
|
|
99
120
|
throw new Error(`Unknown SKS core skill: ${name}`);
|
|
121
|
+
const lean = leanPolicyReference();
|
|
100
122
|
return [
|
|
101
123
|
'---',
|
|
102
124
|
`name: ${skill.display_name}`,
|
|
@@ -117,6 +139,7 @@ export function renderCoreSkillTemplate(name) {
|
|
|
117
139
|
`Command: ${skill.route}`,
|
|
118
140
|
`Purpose: ${skill.purpose}`,
|
|
119
141
|
`Use when: ${skill.when}`,
|
|
142
|
+
`Lean policy: ${lean.policy_id}/${lean.policy_hash}`,
|
|
120
143
|
`Proof paths: ${skill.evidence}`,
|
|
121
144
|
'Safety rules: preserve user-authored skills, keep route state bounded, and stop on hard blockers instead of fabricating fallback behavior.',
|
|
122
145
|
`Failure recovery: ${skill.fallback}`,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TRUST_VALIDATE_BENCH_COMMAND, benchRoot, runCoreBench } from '../bench.js';
|
|
1
|
+
import { TRUST_VALIDATE_BENCH_COMMAND, benchRoot, runCoreBench, runLeanPolicyBench } from '../bench.js';
|
|
2
2
|
import { runProcess } from '../fsx.js';
|
|
3
3
|
import { flag, readFlagValue } from './command-utils.js';
|
|
4
4
|
export async function benchCommand(args = []) {
|
|
@@ -18,9 +18,18 @@ export async function benchCommand(args = []) {
|
|
|
18
18
|
}
|
|
19
19
|
if (action === 'route-fixtures')
|
|
20
20
|
return commandBench('sks.route-fixture-bench.v1', ['all-features', 'selftest', '--mock', '--execute-fixtures', '--strict-artifacts', '--json'], args);
|
|
21
|
+
if (action === 'lean-policy') {
|
|
22
|
+
const report = await runLeanPolicyBench(root);
|
|
23
|
+
if (!report.ok)
|
|
24
|
+
process.exitCode = 1;
|
|
25
|
+
if (flag(args, '--json'))
|
|
26
|
+
return console.log(JSON.stringify(report, null, 2));
|
|
27
|
+
console.log(`lean-policy: ${report.ok ? 'pass' : 'blocked'}`);
|
|
28
|
+
return report;
|
|
29
|
+
}
|
|
21
30
|
if (action === 'blackbox')
|
|
22
31
|
return commandBench('sks.blackbox-bench.v1', ['blackbox-matrix-placeholder'], args);
|
|
23
|
-
console.error('Usage: sks bench core|route-fixtures|blackbox|trust-kernel [--json] [--iterations N]');
|
|
32
|
+
console.error('Usage: sks bench core|route-fixtures|lean-policy|blackbox|trust-kernel [--json] [--iterations N]');
|
|
24
33
|
process.exitCode = 2;
|
|
25
34
|
}
|
|
26
35
|
async function commandBench(schema, commandArgs, args = []) {
|
|
@@ -4,18 +4,50 @@ import { flag } from './command-utils.js';
|
|
|
4
4
|
export async function codeStructureCommand(sub, args = []) {
|
|
5
5
|
const action = sub || 'scan';
|
|
6
6
|
if (action !== 'scan') {
|
|
7
|
-
console.error('Usage: sks code-structure scan [--json]');
|
|
7
|
+
console.error('Usage: sks code-structure scan [--json] [--all] [--changed [ref|file[,file]]] [--changed-since <ref>]');
|
|
8
8
|
process.exitCode = 1;
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
11
11
|
const root = await sksRoot();
|
|
12
|
-
const
|
|
12
|
+
const changedArg = valueAfter(args, '--changed');
|
|
13
|
+
const changedSince = valueAfter(args, '--changed-since');
|
|
14
|
+
const changedArgLooksLikeFiles = Boolean(changedArg && (changedArg.includes(',')
|
|
15
|
+
|| changedArg.includes('/')
|
|
16
|
+
|| changedArg.includes('\\')
|
|
17
|
+
|| /\.(js|ts|tsx|jsx|mjs|cjs|json|md|rs|toml)$/i.test(changedArg)));
|
|
18
|
+
const changedFiles = changedArg && changedArgLooksLikeFiles
|
|
19
|
+
? changedArg.split(',').map((file) => file.trim()).filter(Boolean)
|
|
20
|
+
: [];
|
|
21
|
+
const report = await scanCodeStructure(root, {
|
|
22
|
+
includeOk: flag(args, '--all'),
|
|
23
|
+
changed: flag(args, '--changed') ? (changedFiles.length ? true : changedArg || true) : false,
|
|
24
|
+
changedSince,
|
|
25
|
+
changedFiles
|
|
26
|
+
});
|
|
13
27
|
if (flag(args, '--json'))
|
|
14
28
|
return console.log(JSON.stringify(report, null, 2));
|
|
15
29
|
console.log('SKS Code Structure');
|
|
30
|
+
if (report.changed_scope?.mode !== 'full') {
|
|
31
|
+
console.log(`Changed scope: ${report.changed_scope.changed_files.length} files, ${report.changed_scope.net_lines} net lines`);
|
|
32
|
+
console.log(`Lean semantic review: ${report.semantic_review?.status || 'unknown'}`);
|
|
33
|
+
}
|
|
16
34
|
for (const file of report.files.slice(0, 20))
|
|
17
35
|
console.log(`${file.status} ${file.line_count} ${file.path}`);
|
|
18
36
|
if (report.remaining_risks.length)
|
|
19
37
|
console.log(`Risks: ${report.remaining_risks.join(', ')}`);
|
|
38
|
+
if (report.semantic_review?.findings?.length) {
|
|
39
|
+
for (const finding of report.semantic_review.findings.slice(0, 8)) {
|
|
40
|
+
console.log(`Lean ${finding.severity}: ${finding.file ? `${finding.file}: ` : ''}${finding.summary}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function valueAfter(args, name) {
|
|
45
|
+
const index = args.indexOf(name);
|
|
46
|
+
if (index === -1)
|
|
47
|
+
return null;
|
|
48
|
+
const value = args[index + 1];
|
|
49
|
+
if (!value || String(value).startsWith('--'))
|
|
50
|
+
return null;
|
|
51
|
+
return String(value);
|
|
20
52
|
}
|
|
21
53
|
//# sourceMappingURL=code-structure-command.js.map
|