sneakoscope 10.6.2 → 10.7.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 +2 -2
- package/config/perf-budgets.v1.json +1 -2
- package/config/skills-hash-ledger.v1.json +7 -2
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/sks-dispatch.js +6 -3
- package/dist/cli/args.js +3 -1
- package/dist/cli/command-manifest-lite.js +48 -114
- package/dist/cli/command-registry.js +1 -18
- package/dist/cli/commands-fast.js +11 -4
- package/dist/cli/help-fast.js +11 -22
- package/dist/cli/help.js +3 -3
- package/dist/cli/install-helpers.js +1 -1
- package/dist/cli/router.js +12 -26
- package/dist/commands/codex-app.js +2 -2
- package/dist/commands/doctor-helpers.js +1 -1
- package/dist/commands/mad-sks.js +2 -2
- package/dist/config/skills-manifest.json +13 -8
- package/dist/core/agent-bridge/async-command.js +2 -2
- package/dist/core/agents/agent-recursion-guard.js +0 -2
- package/dist/core/auto-review.js +15 -172
- package/dist/core/code-structure.js +0 -1
- package/dist/core/codex-control/codex-reliability-shield.js +64 -15
- package/dist/core/codex-control/codex-sdk-adapter.js +38 -5
- package/dist/core/commands/agent-bridge-command.js +1 -1
- package/dist/core/commands/basic-cli.js +60 -233
- package/dist/core/commands/command-utils.js +1 -1
- package/dist/core/commands/gc-command.js +30 -29
- package/dist/core/commands/image-ux-review-command.js +1 -1
- package/dist/core/commands/install-package-command.js +1 -1
- package/dist/core/commands/intent-normalization/normalizer.js +2 -2
- package/dist/core/commands/pipeline-command.js +13 -5
- package/dist/core/commands/plan-command.js +2 -3
- package/dist/core/commands/research-command.js +0 -3
- package/dist/core/commands/review-command.js +1 -1
- package/dist/core/commands/seo-command.js +27 -20
- package/dist/core/commands/status-command.js +8 -2
- package/dist/core/doctor/command-alias-cleanup.js +6 -6
- package/dist/core/evaluation.js +1 -1
- package/dist/core/feature-fixtures.js +9 -43
- package/dist/core/feature-registry.js +9 -27
- package/dist/core/git-hygiene/shared-memory-publish.js +1 -1
- package/dist/core/hooks-runtime/stop-repeat-guard.js +0 -13
- package/dist/core/init/skills.js +5 -13
- package/dist/core/init.js +0 -9
- package/dist/core/install/installed-package-smoke.js +3 -1
- package/dist/core/perf/import-graph-budget.js +0 -1
- package/dist/core/perf/release-latency-slo.js +2 -30
- package/dist/core/pipeline-internals/pipeline-stage-builder.js +2 -4
- package/dist/core/pipeline-internals/runtime-core.js +2 -38
- package/dist/core/proof/route-proof-policy.js +2 -4
- package/dist/core/proof/runtime-truth-matrix.js +2 -2
- package/dist/core/proof-field.js +104 -39
- package/dist/core/questions.js +11 -7
- package/dist/core/release/gate-affected-globs.js +0 -2
- package/dist/core/research/research-reviewer-contract.js +34 -0
- package/dist/core/research/research-work-graph.js +1 -1
- package/dist/core/research.js +1 -1
- package/dist/core/routes/constants.js +0 -1
- package/dist/core/routes/diagnostic-allowlist.js +1 -3
- package/dist/core/routes/light-routes.js +1 -2
- package/dist/core/routes.js +1 -1
- package/dist/core/safety/command-contract/contracts.js +5 -1
- package/dist/core/search-visibility/marketing-truthfulness.js +10 -7
- package/dist/core/search-visibility/marketing.js +194 -149
- package/dist/core/skill-forge.js +1 -361
- package/dist/core/strategy/adhd-orchestrating-gate.js +3 -3
- package/dist/core/triwiki/context-graph/extractors/topology/commands.js +2 -6
- package/dist/core/triwiki-wrongness/wrongness-cli.js +9 -27
- package/dist/core/version.js +1 -1
- package/package.json +1 -2
- package/release-gates.v2.json +1 -32
- package/dist/cli/recallpulse-command.js +0 -144
- package/dist/commands/auto-review.js +0 -5
- package/dist/commands/codex-native.js +0 -77
- package/dist/commands/recallpulse.js +0 -5
- package/dist/core/codex-native/codex-native-interop-policy.js +0 -127
- package/dist/core/commands/autoresearch-command.js +0 -4
- package/dist/core/commands/code-structure-command.js +0 -52
- package/dist/core/commands/goal-command.js +0 -43
- package/dist/core/commands/recallpulse-command.js +0 -4
- package/dist/core/commands/remote-command.js +0 -119
- package/dist/core/commands/skill-dream-command.js +0 -43
- package/dist/core/commands/wrongness-command.js +0 -2
- package/dist/core/goal-workflow.js +0 -80
- package/dist/core/mcp/mcp-tool-name-normalizer.js +0 -28
- package/dist/core/recallpulse/policy.js +0 -207
- package/dist/core/recallpulse.js +0 -947
- package/dist/core/remote/audit-idempotency.js +0 -241
- package/dist/core/remote/index.js +0 -10
- package/dist/core/remote/machine-registry.js +0 -167
- package/dist/core/remote/owner-proof.js +0 -216
- package/dist/core/remote/protocol.js +0 -249
- package/dist/core/remote/readiness.js +0 -156
- package/dist/core/remote/session-index.js +0 -61
- package/dist/core/remote/session-snapshot.js +0 -197
- package/dist/core/remote/ssh-worker-client.js +0 -377
- package/dist/core/remote/types.js +0 -10
- package/dist/core/remote/worker.js +0 -360
- package/dist/core/search/context-graph-seeds.js +0 -15
- package/dist/core/verification/context-graph-affected.js +0 -312
- package/dist/core/verification/verification-artifact-lock.js +0 -21
- package/dist/core/verification/verification-dag.js +0 -89
- package/dist/core/verification/verification-result.js +0 -19
- package/dist/core/verification/verification-worker-pool.js +0 -204
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { nowIso } from '../fsx.js';
|
|
2
2
|
export const CODEX_RELIABILITY_SHIELD_SCHEMA = 'sks.codex-reliability-shield.v1';
|
|
3
|
+
const DEFAULT_CAPACITY_BACKOFF_MS = [15_000, 45_000, 90_000];
|
|
4
|
+
const MODEL_CAPACITY_RE = /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;
|
|
5
|
+
const USAGE_LIMIT_RE = /hit your usage limit|usage limit (?:has been )?reached/i;
|
|
6
|
+
const NON_WORK_ITEM_TYPES = new Set(['error', 'reasoning']);
|
|
3
7
|
export function codexTimeoutClassForRoute(route, fallback = 'standard') {
|
|
4
8
|
return /^\$?naruto$/i.test(String(route || '').trim()) ? 'long' : fallback;
|
|
5
9
|
}
|
|
@@ -7,19 +11,28 @@ export function normalizeCodexReliabilityPolicy(input) {
|
|
|
7
11
|
const policy = input.reliabilityPolicy || {};
|
|
8
12
|
const timeoutClass = codexTimeoutClassForRoute(input.route, policy.timeoutClass || (input.tier === 'orchestrator' ? 'long' : 'standard'));
|
|
9
13
|
const fallbackIdle = timeoutClass === 'short' ? 20_000 : timeoutClass === 'long' ? 180_000 : 60_000;
|
|
14
|
+
const backoff = (Array.isArray(policy.capacityBackoffMs) && policy.capacityBackoffMs.length
|
|
15
|
+
? policy.capacityBackoffMs
|
|
16
|
+
: DEFAULT_CAPACITY_BACKOFF_MS).slice(0, 5).map((wait, index) => clampInt(wait, DEFAULT_CAPACITY_BACKOFF_MS[index] ?? 90_000, 0, 10 * 60_000));
|
|
10
17
|
return {
|
|
11
18
|
maxEmptyResultRetries: clampInt(policy.maxEmptyResultRetries, 1, 0, 3),
|
|
19
|
+
maxCapacityRetries: clampInt(policy.maxCapacityRetries, backoff.length, 0, backoff.length),
|
|
20
|
+
capacityBackoffMs: backoff,
|
|
21
|
+
retryCapacityAfterWork: input.sandboxPolicy === 'read-only',
|
|
12
22
|
idleTimeoutMs: clampInt(policy.idleTimeoutMs, fallbackIdle, 1_000, 15 * 60_000),
|
|
13
23
|
timeoutClass
|
|
14
24
|
};
|
|
15
25
|
}
|
|
16
26
|
export async function runWithCodexReliabilityShield(input, runAttempt) {
|
|
17
27
|
const policy = normalizeCodexReliabilityPolicy(input);
|
|
28
|
+
const deadlineEpochMs = Number(input.reliabilityPolicy?.deadlineEpochMs);
|
|
18
29
|
const attempts = [];
|
|
19
30
|
let selected = null;
|
|
20
31
|
let selectedAttempt = 0;
|
|
32
|
+
let emptyRetries = 0;
|
|
33
|
+
let capacityRetries = 0;
|
|
21
34
|
const controls = {};
|
|
22
|
-
for (let attempt = 1
|
|
35
|
+
for (let attempt = 1;; attempt += 1) {
|
|
23
36
|
const raw = await runAttempt(attempt, controls);
|
|
24
37
|
const continuity = auditToolOutputContinuity(Array.isArray(raw.events) ? raw.events : []);
|
|
25
38
|
const heartbeats = buildKeepaliveHeartbeats(continuity.events);
|
|
@@ -37,6 +50,18 @@ export async function runWithCodexReliabilityShield(input, runAttempt) {
|
|
|
37
50
|
missing_tool_result_count: continuity.missingToolResultCount,
|
|
38
51
|
heartbeat_count: heartbeats.length
|
|
39
52
|
};
|
|
53
|
+
let capacityWaitMs = null;
|
|
54
|
+
if (report.model_capacity_error) {
|
|
55
|
+
capacityWaitMs = report.retryable ? nextCapacityWaitMs(policy, capacityRetries, deadlineEpochMs) : null;
|
|
56
|
+
if (capacityWaitMs === null) {
|
|
57
|
+
report.retryable = false;
|
|
58
|
+
report.retry_reason = null;
|
|
59
|
+
report.blockers = [...report.blockers, 'codex_model_capacity_unavailable'];
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
report.capacity_wait_ms = capacityWaitMs;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
40
65
|
attempts.push(report);
|
|
41
66
|
selected = {
|
|
42
67
|
...raw,
|
|
@@ -47,11 +72,20 @@ export async function runWithCodexReliabilityShield(input, runAttempt) {
|
|
|
47
72
|
selectedAttempt = attempt;
|
|
48
73
|
if (report.retryable && report.mcp_auth_error)
|
|
49
74
|
controls.noMcp = true;
|
|
50
|
-
if (!report.retryable
|
|
75
|
+
if (!report.retryable)
|
|
51
76
|
break;
|
|
77
|
+
if (capacityWaitMs !== null) {
|
|
78
|
+
capacityRetries += 1;
|
|
79
|
+
await new Promise((resolve) => setTimeout(resolve, capacityWaitMs));
|
|
80
|
+
}
|
|
81
|
+
else if (emptyRetries < policy.maxEmptyResultRetries) {
|
|
82
|
+
emptyRetries += 1;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
52
87
|
}
|
|
53
88
|
const blockers = attempts.flatMap((attempt) => attempt.blockers);
|
|
54
|
-
const modelCapacityRetryCount = attempts.filter((attempt) => attempt.model_capacity_error && attempt.retryable).length;
|
|
55
89
|
const report = {
|
|
56
90
|
schema: CODEX_RELIABILITY_SHIELD_SCHEMA,
|
|
57
91
|
generated_at: nowIso(),
|
|
@@ -61,6 +95,7 @@ export async function runWithCodexReliabilityShield(input, runAttempt) {
|
|
|
61
95
|
timeout_class: policy.timeoutClass,
|
|
62
96
|
idle_timeout_ms: policy.idleTimeoutMs,
|
|
63
97
|
max_empty_result_retries: policy.maxEmptyResultRetries,
|
|
98
|
+
max_capacity_retries: policy.maxCapacityRetries,
|
|
64
99
|
attempts,
|
|
65
100
|
selected_attempt: selectedAttempt,
|
|
66
101
|
retry_count: Math.max(0, selectedAttempt - 1),
|
|
@@ -68,8 +103,8 @@ export async function runWithCodexReliabilityShield(input, runAttempt) {
|
|
|
68
103
|
repaired_tool_result_count: attempts.reduce((sum, attempt) => sum + attempt.repaired_tool_result_count, 0),
|
|
69
104
|
missing_tool_result_count: attempts.reduce((sum, attempt) => sum + attempt.missing_tool_result_count, 0),
|
|
70
105
|
no_duplicate_streamed_output: attempts.slice(0, -1).every((attempt) => attempt.meaningful_event_count === 0),
|
|
71
|
-
model_capacity_retry_count:
|
|
72
|
-
selected_model_capacity_fallback:
|
|
106
|
+
model_capacity_retry_count: capacityRetries,
|
|
107
|
+
selected_model_capacity_fallback: capacityRetries > 0 && attempts[attempts.length - 1]?.model_capacity_error === false,
|
|
73
108
|
blockers
|
|
74
109
|
};
|
|
75
110
|
const selectedResult = selected || { ok: false, events: [], blockers: ['codex_sdk_attempt_missing'] };
|
|
@@ -92,8 +127,6 @@ export function evaluateCodexReliabilityAttempt(result, events, policy, attempt)
|
|
|
92
127
|
const blockers = [];
|
|
93
128
|
let retryable = false;
|
|
94
129
|
let retryReason = null;
|
|
95
|
-
if (modelCapacity)
|
|
96
|
-
blockers.push('codex_model_capacity_unavailable');
|
|
97
130
|
if (mcpAuth)
|
|
98
131
|
blockers.push('codex_reliability_mcp_auth_error');
|
|
99
132
|
if (!modelCapacity && idle && partial)
|
|
@@ -108,11 +141,17 @@ export function evaluateCodexReliabilityAttempt(result, events, policy, attempt)
|
|
|
108
141
|
retryable = true;
|
|
109
142
|
retryReason = 'mcp_auth_error_retry_no_mcp';
|
|
110
143
|
}
|
|
111
|
-
else if (
|
|
144
|
+
else if (modelCapacity) {
|
|
145
|
+
if (meaningful.length === 0 || policy.retryCapacityAfterWork) {
|
|
146
|
+
retryable = true;
|
|
147
|
+
retryReason = 'model_capacity_backoff_retry';
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else if (!fatal && idle && meaningful.length === 0) {
|
|
112
151
|
retryable = true;
|
|
113
152
|
retryReason = 'stream_idle_before_meaningful_event';
|
|
114
153
|
}
|
|
115
|
-
else if (!
|
|
154
|
+
else if (!fatal && empty) {
|
|
116
155
|
retryable = true;
|
|
117
156
|
retryReason = 'empty_sdk_result_before_meaningful_event';
|
|
118
157
|
}
|
|
@@ -128,6 +167,7 @@ export function evaluateCodexReliabilityAttempt(result, events, policy, attempt)
|
|
|
128
167
|
fatal_error: fatal,
|
|
129
168
|
mcp_auth_error: mcpAuth,
|
|
130
169
|
model_capacity_error: modelCapacity,
|
|
170
|
+
capacity_wait_ms: null,
|
|
131
171
|
capacity_fallback_hint: null,
|
|
132
172
|
repaired_tool_result_count: 0,
|
|
133
173
|
missing_tool_result_count: 0,
|
|
@@ -136,8 +176,15 @@ export function evaluateCodexReliabilityAttempt(result, events, policy, attempt)
|
|
|
136
176
|
};
|
|
137
177
|
}
|
|
138
178
|
export function isCodexModelCapacityError(result, events) {
|
|
139
|
-
|
|
140
|
-
|
|
179
|
+
return MODEL_CAPACITY_RE.test(collectFailureSignalText(result, events));
|
|
180
|
+
}
|
|
181
|
+
function nextCapacityWaitMs(policy, retriesDone, deadlineEpochMs) {
|
|
182
|
+
const base = policy.capacityBackoffMs[retriesDone];
|
|
183
|
+
if (retriesDone >= policy.maxCapacityRetries || base === undefined)
|
|
184
|
+
return null;
|
|
185
|
+
const wait = Math.round(base * (0.75 + Math.random() * 0.5));
|
|
186
|
+
const hasDeadline = Number.isFinite(deadlineEpochMs) && deadlineEpochMs > 0;
|
|
187
|
+
return hasDeadline && deadlineEpochMs - Date.now() <= wait ? null : wait;
|
|
141
188
|
}
|
|
142
189
|
export function isMissingToolOutputProtocolError(result, events) {
|
|
143
190
|
return /\[No tool output found for (?:custom\s+)?tool call\s+[^\]]+\]/i.test(collectText(result, events));
|
|
@@ -175,8 +222,9 @@ export function buildKeepaliveHeartbeats(events) {
|
|
|
175
222
|
function isMeaningfulEvent(event) {
|
|
176
223
|
const type = String(event?.type || '');
|
|
177
224
|
const itemType = String(event?.item?.type || '');
|
|
225
|
+
if (type === 'item.completed' && !NON_WORK_ITEM_TYPES.has(itemType))
|
|
226
|
+
return true;
|
|
178
227
|
return type === 'turn.completed'
|
|
179
|
-
|| type === 'item.completed'
|
|
180
228
|
|| itemType === 'agent_message'
|
|
181
229
|
|| itemType === 'file_change'
|
|
182
230
|
|| itemType === 'command_execution'
|
|
@@ -185,8 +233,9 @@ function isMeaningfulEvent(event) {
|
|
|
185
233
|
function hasFatalError(result, events) {
|
|
186
234
|
if (isMcpAuthError(result, events))
|
|
187
235
|
return false;
|
|
188
|
-
const text =
|
|
189
|
-
return /\b(?:4\d\d|fatal|unauthorized|forbidden|authrequired|invalid oauth|side-effect applied|partial patch applied)\b/i.test(text)
|
|
236
|
+
const text = collectFailureSignalText(result, events);
|
|
237
|
+
return /\b(?:4\d\d|fatal|unauthorized|forbidden|authrequired|invalid oauth|side-effect applied|partial patch applied)\b/i.test(text)
|
|
238
|
+
|| USAGE_LIMIT_RE.test(text);
|
|
190
239
|
}
|
|
191
240
|
function isMcpAuthError(result, events) {
|
|
192
241
|
const text = collectText(result, events);
|
|
@@ -206,7 +255,7 @@ function collectText(result, events) {
|
|
|
206
255
|
].filter(Boolean).join('\n'))
|
|
207
256
|
].join('\n');
|
|
208
257
|
}
|
|
209
|
-
function
|
|
258
|
+
function collectFailureSignalText(result, events) {
|
|
210
259
|
return [
|
|
211
260
|
...(Array.isArray(result.blockers) ? result.blockers : []),
|
|
212
261
|
...events
|
|
@@ -87,8 +87,24 @@ export async function runRealCodexSdkTask(input, policy) {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
catch (err) {
|
|
90
|
-
if (!timedOut && controller.signal.aborted !== true && String(err?.name || '') !== 'AbortError')
|
|
91
|
-
|
|
90
|
+
if (!timedOut && controller.signal.aborted !== true && String(err?.name || '') !== 'AbortError') {
|
|
91
|
+
const reported = codexReportedFailure(events);
|
|
92
|
+
if (!reported)
|
|
93
|
+
throw err;
|
|
94
|
+
return {
|
|
95
|
+
ok: false,
|
|
96
|
+
sdkThreadId: String(thread.id || events.find((event) => event?.type === 'thread.started')?.thread_id || ''),
|
|
97
|
+
sdkRunId: extractRunId(events),
|
|
98
|
+
events,
|
|
99
|
+
finalResponse,
|
|
100
|
+
structuredOutput: null,
|
|
101
|
+
blockers: [`codex_sdk_run_failed:${reported.message || 'turn_failed'} (${firstLine(err)})`],
|
|
102
|
+
liveEventsWritten,
|
|
103
|
+
runtimeIdentity: runtime.identity,
|
|
104
|
+
executionPolicy,
|
|
105
|
+
raw: { failed_event: reported.event, exec_error: String(err?.message || err) }
|
|
106
|
+
};
|
|
107
|
+
}
|
|
92
108
|
return {
|
|
93
109
|
ok: false,
|
|
94
110
|
sdkThreadId: String(thread.id || events.find((event) => event?.type === 'thread.started')?.thread_id || ''),
|
|
@@ -106,7 +122,7 @@ export async function runRealCodexSdkTask(input, policy) {
|
|
|
106
122
|
finally {
|
|
107
123
|
clearTimeout(timer);
|
|
108
124
|
}
|
|
109
|
-
const failed = events
|
|
125
|
+
const failed = codexReportedFailure(events);
|
|
110
126
|
if (failed) {
|
|
111
127
|
return {
|
|
112
128
|
ok: false,
|
|
@@ -115,11 +131,11 @@ export async function runRealCodexSdkTask(input, policy) {
|
|
|
115
131
|
events,
|
|
116
132
|
finalResponse,
|
|
117
133
|
structuredOutput: null,
|
|
118
|
-
blockers: ['codex_turn_failed'],
|
|
134
|
+
blockers: [failed.message ? `codex_turn_failed:${failed.message}` : 'codex_turn_failed'],
|
|
119
135
|
liveEventsWritten,
|
|
120
136
|
runtimeIdentity: runtime.identity,
|
|
121
137
|
executionPolicy,
|
|
122
|
-
raw: { failed_event: failed }
|
|
138
|
+
raw: { failed_event: failed.event }
|
|
123
139
|
};
|
|
124
140
|
}
|
|
125
141
|
const structuredOutput = parseStructuredOutput(finalResponse, Boolean(input.outputSchema));
|
|
@@ -137,6 +153,23 @@ export async function runRealCodexSdkTask(input, policy) {
|
|
|
137
153
|
raw: { item_count: events.filter((event) => String(event?.type || '').startsWith('item.')).length }
|
|
138
154
|
};
|
|
139
155
|
}
|
|
156
|
+
export function codexReportedFailure(events) {
|
|
157
|
+
let first = null;
|
|
158
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
159
|
+
const event = events[index];
|
|
160
|
+
const type = event?.type;
|
|
161
|
+
if (type !== 'turn.failed' && type !== 'error')
|
|
162
|
+
continue;
|
|
163
|
+
const message = String((type === 'turn.failed' ? event?.error?.message : event?.message) || '').replace(/\s+/g, ' ').trim();
|
|
164
|
+
if (message)
|
|
165
|
+
return { event, message: message.slice(0, 300) };
|
|
166
|
+
first = event;
|
|
167
|
+
}
|
|
168
|
+
return first ? { event: first, message: '' } : null;
|
|
169
|
+
}
|
|
170
|
+
function firstLine(err) {
|
|
171
|
+
return String(err?.message || err).trim().split('\n')[0].trim().slice(0, 200);
|
|
172
|
+
}
|
|
140
173
|
export async function resolveCodexSdkRuntime(_input) {
|
|
141
174
|
return resolveOfficialCodexPackageRuntime({ requestedBy: 'codex-sdk-adapter' });
|
|
142
175
|
}
|
|
@@ -90,7 +90,7 @@ export async function inspectAgentBridgeHostCapabilities(root, dependencies, pro
|
|
|
90
90
|
export function usage() {
|
|
91
91
|
return [
|
|
92
92
|
'Usage: sks agent-bridge setup [--trusted-project] [--json]',
|
|
93
|
-
' sks agent-bridge async --prompt "task" [--tools status,
|
|
93
|
+
' sks agent-bridge async --prompt "task" [--tools status,search] [--json]',
|
|
94
94
|
'',
|
|
95
95
|
'setup: register read-only SKS tools with an external agent host.',
|
|
96
96
|
'async: run native Astra Async tool calling through the registered Codex-LB bridge.',
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import fsp from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
4
|
-
import { COMMAND_MANIFEST_LITE } from '../../cli/command-manifest-lite.js';
|
|
3
|
+
import { COMMAND_ALIASES_LITE, COMMAND_MANIFEST_BY_NAME } from '../../cli/command-manifest-lite.js';
|
|
5
4
|
import { flag } from '../../cli/args.js';
|
|
6
5
|
import { printJson, sksTextLogo } from '../../cli/output.js';
|
|
7
6
|
import { ui as cliUi } from '../../cli/cli-theme.js';
|
|
8
|
-
import { PACKAGE_VERSION, ensureDir, nowIso, projectRoot, readJson, rmrf,
|
|
9
|
-
import { DOLLAR_COMMANDS,
|
|
7
|
+
import { PACKAGE_VERSION, ensureDir, nowIso, projectRoot, readJson, rmrf, tmpdir, writeJsonAtomic } from '../fsx.js';
|
|
8
|
+
import { DOLLAR_COMMANDS, sksPrefixedDollarCommand } from '../routes.js';
|
|
10
9
|
import { DOLLAR_COMMAND_ALIASES_LITE, DOLLAR_COMMANDS_LITE } from '../routes/dollar-manifest-lite.js';
|
|
11
10
|
import { initProject, normalizeInstallScope, sksCommandPrefix } from '../init.js';
|
|
12
11
|
import { buildFeatureRegistry, validateFeatureRegistry } from '../feature-registry.js';
|
|
@@ -18,36 +17,42 @@ import { formatSksUpdateStatusText, runSksUpdateNow, runSksUpdateReview, runSksU
|
|
|
18
17
|
import { persistSksUpdateNoticeFromVersions } from '../update/update-notice.js';
|
|
19
18
|
import { updateStageFailureDiagnostics } from '../update/update-stage-diagnostics.js';
|
|
20
19
|
import { withSecretPreservationGuard } from '../config/config-migration-journal.js';
|
|
21
|
-
const REMOVED_USAGE_TOPICS = new Set(['db', 'ui']);
|
|
22
20
|
export async function helpCommand(args = []) {
|
|
23
|
-
const topic = args
|
|
24
|
-
if (topic)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
console.log(' sks help [topic]');
|
|
29
|
-
console.log(' sks commands [--json]');
|
|
30
|
-
console.log(' sks dollar-commands [--json]');
|
|
31
|
-
console.log(' sks proof show --json');
|
|
32
|
-
console.log('');
|
|
33
|
-
for (const row of commandRows().filter((entry) => entry.maturity !== 'labs')) {
|
|
34
|
-
console.log(` ${row.usage.padEnd(58)} ${row.description}`);
|
|
21
|
+
const topic = args.find((arg) => !arg.startsWith('-'));
|
|
22
|
+
if (!topic) {
|
|
23
|
+
const { helpFast } = await import('../../cli/help-fast.js');
|
|
24
|
+
helpFast();
|
|
25
|
+
return { ok: true, status: 'help' };
|
|
35
26
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
27
|
+
if (topic.startsWith('$')) {
|
|
28
|
+
const wanted = sksPrefixedDollarCommand(topic).toLowerCase();
|
|
29
|
+
const route = DOLLAR_COMMANDS.find((entry) => entry.command.toLowerCase() === wanted);
|
|
30
|
+
if (route) {
|
|
31
|
+
console.log(`${route.command}\n\n${route.route}: ${route.description}`);
|
|
32
|
+
return { ok: true, status: 'help', topic: route.command };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
const name = COMMAND_ALIASES_LITE[topic] || topic;
|
|
37
|
+
const entry = COMMAND_MANIFEST_BY_NAME[name];
|
|
38
|
+
if (entry) {
|
|
39
|
+
const [{ COMMANDS }, { renderManifestHelp }] = await Promise.all([
|
|
40
|
+
import('../../cli/command-registry.js'),
|
|
41
|
+
import('../../cli/help.js')
|
|
42
|
+
]);
|
|
43
|
+
const mod = await COMMANDS[name].lazy();
|
|
44
|
+
console.log(typeof mod.usage === 'function' ? mod.usage(topic) : renderManifestHelp(name, entry));
|
|
45
|
+
return { ok: true, status: 'help', topic: name };
|
|
46
|
+
}
|
|
46
47
|
}
|
|
47
|
-
console.log(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
console.log(`Unknown help topic: ${topic}`);
|
|
49
|
+
console.log('Topics: a command from `sks commands`, or a $ route from `sks dollar-commands` (for example `sks help \'$sks-plan\'`).');
|
|
50
|
+
process.exitCode = 1;
|
|
51
|
+
return { ok: false, status: 'unknown_topic', topic };
|
|
52
|
+
}
|
|
53
|
+
export async function commandsCommand(args = []) {
|
|
54
|
+
const { commandsJsonFast, commandsTextFast } = await import('../../cli/commands-fast.js');
|
|
55
|
+
return flag(args, '--json') ? commandsJsonFast() : commandsTextFast();
|
|
51
56
|
}
|
|
52
57
|
export function dollarCommandsCommand(args = []) {
|
|
53
58
|
const out = { dollar_commands: DOLLAR_COMMANDS_LITE, app_skill_aliases: DOLLAR_COMMAND_ALIASES_LITE };
|
|
@@ -58,67 +63,20 @@ export function dollarCommandsCommand(args = []) {
|
|
|
58
63
|
for (const entry of DOLLAR_COMMANDS_LITE)
|
|
59
64
|
console.log(`${entry.command.padEnd(width)} ${entry.route}: ${entry.description}`);
|
|
60
65
|
console.log(`\nCanonical Codex App picker skills: ${DOLLAR_COMMAND_ALIASES_LITE.map((entry) => entry.app_skill).join(', ')}`);
|
|
61
|
-
|
|
62
|
-
export function aliasesCommand() {
|
|
63
|
-
console.log('Aliases');
|
|
64
|
-
console.log('- sks, sneakoscope');
|
|
65
|
-
console.log('- $ aliases:');
|
|
66
|
-
for (const entry of DOLLAR_COMMAND_ALIASES_LITE)
|
|
67
|
-
console.log(` ${entry.app_skill} -> ${entry.canonical}`);
|
|
68
|
-
}
|
|
69
|
-
export function dfixCommand() {
|
|
70
|
-
console.log(`SKS Direct Fix Mode
|
|
71
|
-
|
|
72
|
-
Prompt command:
|
|
73
|
-
$sks-dfix <tiny direct fix request>
|
|
74
|
-
|
|
75
|
-
Rules:
|
|
76
|
-
Apply only the requested tiny copy/config/docs/labels/spacing/translation/simple mechanical edit.
|
|
77
|
-
Keep verification cheap and explicit.
|
|
78
|
-
Finish with a DFix completion summary and one Honest check line.`);
|
|
79
|
-
}
|
|
80
|
-
export function usageCommand(args = []) {
|
|
81
|
-
const topic = args[0] || 'overview';
|
|
82
|
-
if (topic === 'overview') {
|
|
83
|
-
console.log(`Usage topics: ${USAGE_TOPICS}`);
|
|
84
|
-
console.log('Try: sks usage goal, sks usage naruto, sks usage image-ux-review');
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
if (topic === 'seo-geo-optimizer') {
|
|
88
|
-
console.log('seo-geo-optimizer\n');
|
|
89
|
-
console.log('Usage: sks seo-geo-optimizer [seo|geo] doctor|audit|plan|apply|verify|status|rollback|fixture [mission|latest] [--mode seo|geo] [--root <path>] [--url <origin>] [--target auto|website|docs|package] [--framework auto|next-app|next-pages|static] [--offline] [--strict] [--json]');
|
|
90
|
-
console.log(' sks seo-geo-optimizer apply <mission|latest> --mode seo|geo --apply [--include-llms-txt] [--scope <rule-or-path,...>] [--yes] [--json]');
|
|
91
|
-
console.log(' sks seo-geo-optimizer rollback <mission|latest> --mode seo|geo --apply [--yes] [--json]');
|
|
92
|
-
console.log('Unified SEO/GEO optimizer audit/plan/apply/verify lifecycle on the search-visibility kernel.');
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
const row = commandRows().find((entry) => entry.name === topic);
|
|
96
|
-
if (row) {
|
|
97
|
-
console.log(`${row.name}\n`);
|
|
98
|
-
console.log(`Usage: ${row.usage}`);
|
|
99
|
-
console.log(row.description);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
const route = REMOVED_USAGE_TOPICS.has(String(topic).toLowerCase())
|
|
103
|
-
? null
|
|
104
|
-
: DOLLAR_COMMANDS.find((entry) => entry.command.toLowerCase() === sksPrefixedDollarCommand(topic).toLowerCase());
|
|
105
|
-
if (route) {
|
|
106
|
-
console.log(`${sksPrefixedDollarCommand(route.command)}\n`);
|
|
107
|
-
console.log(`${route.route}: ${route.description}`);
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
console.log(`Unknown usage topic: ${topic}`);
|
|
111
|
-
console.log(`Known topics: ${USAGE_TOPICS}`);
|
|
66
|
+
console.log('Command aliases: sks and sneakoscope are the same CLI.');
|
|
112
67
|
}
|
|
113
68
|
export function quickstartCommand() {
|
|
114
69
|
console.log(`Sneakoscope Codex Quickstart
|
|
115
70
|
|
|
116
|
-
sks setup
|
|
117
|
-
sks doctor
|
|
118
|
-
sks commands
|
|
119
|
-
sks dollar-commands
|
|
71
|
+
sks setup install hooks and skills (then once per project)
|
|
72
|
+
sks doctor check the install; sks doctor --fix repairs it
|
|
73
|
+
sks commands every CLI command
|
|
74
|
+
sks dollar-commands every Codex App $ route
|
|
120
75
|
|
|
121
|
-
|
|
76
|
+
Then ask Codex for work directly: the main agent does ordinary work itself while
|
|
77
|
+
SKS hooks keep it safe. Use $sks-plan to plan without edits, $sks-naruto or
|
|
78
|
+
$sks-work when you want the work split across child agents, and $sks-help for
|
|
79
|
+
the rest.`);
|
|
122
80
|
}
|
|
123
81
|
export async function updateStatusCommand(args = []) {
|
|
124
82
|
const root = await resolveUpdateProjectRoot(args);
|
|
@@ -295,8 +253,21 @@ function applyUpdateCommandExitCode(result) {
|
|
|
295
253
|
process.exitCode = 1;
|
|
296
254
|
}
|
|
297
255
|
export async function setupCommand(args = []) {
|
|
298
|
-
if (flag(args, '--
|
|
299
|
-
|
|
256
|
+
if (flag(args, '--dry-run')) {
|
|
257
|
+
const refused = {
|
|
258
|
+
schema: 'sks.setup.v1',
|
|
259
|
+
ok: false,
|
|
260
|
+
status: 'dry_run_unsupported',
|
|
261
|
+
blockers: ['setup_has_no_dry_run'],
|
|
262
|
+
next_action: '`sks doctor --json` reports what setup would repair without changing anything.'
|
|
263
|
+
};
|
|
264
|
+
process.exitCode = 2;
|
|
265
|
+
if (flag(args, '--json'))
|
|
266
|
+
printJson(refused);
|
|
267
|
+
else
|
|
268
|
+
console.error(`Setup has no dry run; nothing was changed. ${refused.next_action}`);
|
|
269
|
+
return refused;
|
|
270
|
+
}
|
|
300
271
|
const root = await projectRoot();
|
|
301
272
|
const { formatHarnessConflictReport, scanHarnessConflicts } = await import('../harness-conflicts.js');
|
|
302
273
|
const conflictScan = await scanHarnessConflicts(root);
|
|
@@ -378,48 +349,8 @@ export async function setupCommand(args = []) {
|
|
|
378
349
|
return result;
|
|
379
350
|
}
|
|
380
351
|
export async function bootstrapCommand(args = []) {
|
|
381
|
-
if (flag(args, '--help') || flag(args, '-h'))
|
|
382
|
-
return usageCommand(['bootstrap']);
|
|
383
352
|
return setupCommand(['--local-only', ...args]);
|
|
384
353
|
}
|
|
385
|
-
export async function initCommand(args = []) {
|
|
386
|
-
if (flag(args, '--help') || flag(args, '-h'))
|
|
387
|
-
return usageCommand(['init']);
|
|
388
|
-
return setupCommand(args);
|
|
389
|
-
}
|
|
390
|
-
export async function fixPathCommand(args = []) {
|
|
391
|
-
const root = await projectRoot();
|
|
392
|
-
const installScope = installScopeFromArgs(args);
|
|
393
|
-
let res = null;
|
|
394
|
-
await withSecretPreservationGuard(root, 'fix-path-command', async () => {
|
|
395
|
-
res = await initProject(root, { installScope, localOnly: flag(args, '--local-only'), globalCommand: 'sks', force: true });
|
|
396
|
-
});
|
|
397
|
-
const readiness = initProjectInstallReadiness(res);
|
|
398
|
-
const result = {
|
|
399
|
-
schema: 'sks.fix-path.v1',
|
|
400
|
-
ok: readiness.ok,
|
|
401
|
-
status: readiness.status,
|
|
402
|
-
root,
|
|
403
|
-
install_scope: installScope,
|
|
404
|
-
hook_command_prefix: sksCommandPrefix(installScope, { globalCommand: 'sks' }),
|
|
405
|
-
hooks: path.join(root, '.codex', 'hooks.json'),
|
|
406
|
-
skill_install: res?.skill_install,
|
|
407
|
-
blockers: readiness.blockers,
|
|
408
|
-
warnings: readiness.warnings
|
|
409
|
-
};
|
|
410
|
-
if (!result.ok)
|
|
411
|
-
process.exitCode = 1;
|
|
412
|
-
if (flag(args, '--json')) {
|
|
413
|
-
printJson(result);
|
|
414
|
-
return result;
|
|
415
|
-
}
|
|
416
|
-
console.log(`${result.ok ? 'SKS hook path refreshed' : 'SKS hook path refresh blocked'}: ${path.relative(root, result.hooks)}`);
|
|
417
|
-
for (const warning of readiness.warnings)
|
|
418
|
-
console.log(`Warning: ${warning}`);
|
|
419
|
-
for (const blocker of readiness.blockers)
|
|
420
|
-
console.error(`Blocker: ${blocker}`);
|
|
421
|
-
return result;
|
|
422
|
-
}
|
|
423
354
|
function initProjectInstallReadiness(res) {
|
|
424
355
|
const manualBlockers = [
|
|
425
356
|
...(res?.codex_config_install?.manual_blockers || []),
|
|
@@ -458,44 +389,6 @@ function initProjectInstallReadiness(res) {
|
|
|
458
389
|
: 'completed';
|
|
459
390
|
return { ok, status, blockers, warnings };
|
|
460
391
|
}
|
|
461
|
-
export async function depsCommand(sub = 'check', args = []) {
|
|
462
|
-
const action = sub || 'check';
|
|
463
|
-
if (action !== 'check' && action !== 'status') {
|
|
464
|
-
console.error('Usage: sks deps check [--json] [--yes]');
|
|
465
|
-
process.exitCode = 1;
|
|
466
|
-
return;
|
|
467
|
-
}
|
|
468
|
-
const npm = whichSync('npm');
|
|
469
|
-
const nodeOk = Number(process.versions.node.split('.')[0]) >= 20;
|
|
470
|
-
const root = await sksRoot();
|
|
471
|
-
const { ensureRelatedCliTools } = await import('../../cli/install-helpers.js');
|
|
472
|
-
const repairRequested = flag(args, '--yes') || flag(args, '-y');
|
|
473
|
-
const cliTools = await ensureRelatedCliTools(repairRequested ? args : [...args, '--dry-run']);
|
|
474
|
-
const codexReady = cliTools.codex.status === 'present' || cliTools.codex.status === 'installed';
|
|
475
|
-
const result = {
|
|
476
|
-
schema: 'sks.deps-status.v1',
|
|
477
|
-
root,
|
|
478
|
-
ready: Boolean(nodeOk && npm && codexReady),
|
|
479
|
-
node: { ok: nodeOk, version: process.version },
|
|
480
|
-
npm: { ok: Boolean(npm), bin: npm },
|
|
481
|
-
cli_tools: cliTools,
|
|
482
|
-
next_actions: [
|
|
483
|
-
...(!nodeOk ? ['Install Node.js 20.11+.'] : []),
|
|
484
|
-
...(!npm ? ['Install npm or a Node.js distribution that includes npm.'] : []),
|
|
485
|
-
...(!codexReady ? [`Run sks deps check --yes or npm i -g @openai/codex@latest.`] : [])
|
|
486
|
-
]
|
|
487
|
-
};
|
|
488
|
-
if (flag(args, '--json'))
|
|
489
|
-
return printJson(result);
|
|
490
|
-
console.log('SKS Dependencies');
|
|
491
|
-
console.log(`Node: ${result.node.ok ? 'ok' : 'missing'} ${result.node.version}`);
|
|
492
|
-
console.log(`npm: ${result.npm.ok ? 'ok' : 'missing'} ${result.npm.bin || ''}`.trim());
|
|
493
|
-
console.log(`Codex CLI: ${cliTools.codex.status}${cliTools.codex.version ? ` ${cliTools.codex.version}` : ''}`);
|
|
494
|
-
for (const action of result.next_actions)
|
|
495
|
-
console.log(`Next: ${action}`);
|
|
496
|
-
if (!result.ready)
|
|
497
|
-
process.exitCode = 1;
|
|
498
|
-
}
|
|
499
392
|
export async function postinstallCommand(args = []) {
|
|
500
393
|
const { postinstall } = await import('../../cli/install-helpers.js');
|
|
501
394
|
return postinstall({ bootstrap: bootstrapCommand, args });
|
|
@@ -584,65 +477,6 @@ export async function selftestRealCommand(args = []) {
|
|
|
584
477
|
}
|
|
585
478
|
return output;
|
|
586
479
|
}
|
|
587
|
-
export async function reasoningCommand(args = []) {
|
|
588
|
-
const prompt = args.filter((arg) => !String(arg).startsWith('--')).join(' ').trim();
|
|
589
|
-
const route = routePrompt(prompt || '$SKS');
|
|
590
|
-
const info = routeReasoning(route, prompt);
|
|
591
|
-
const result = {
|
|
592
|
-
route: route?.command || '$SKS',
|
|
593
|
-
effort: info.effort,
|
|
594
|
-
profile: info.profile,
|
|
595
|
-
reason: info.reason,
|
|
596
|
-
temporary: true,
|
|
597
|
-
instruction: reasoningInstruction(info)
|
|
598
|
-
};
|
|
599
|
-
if (flag(args, '--json'))
|
|
600
|
-
return printJson(result);
|
|
601
|
-
console.log('SKS Reasoning Route');
|
|
602
|
-
console.log(`Route: ${result.route}`);
|
|
603
|
-
console.log(`Effort: ${result.effort}`);
|
|
604
|
-
console.log(`Profile: ${result.profile}`);
|
|
605
|
-
}
|
|
606
|
-
export async function autoReviewCommand(sub = 'status', args = []) {
|
|
607
|
-
const { autoReviewStatus, enableAutoReview, disableAutoReview } = await import('../auto-review.js');
|
|
608
|
-
const { writeRouteCollaborationArtifacts } = await import('../agents/route-collaboration-ledger.js');
|
|
609
|
-
const action = sub || 'status';
|
|
610
|
-
const result = action === 'fixture'
|
|
611
|
-
? await reviewNativeAgentFixture()
|
|
612
|
-
: action === 'enable' || action === 'start'
|
|
613
|
-
? await enableAutoReview({ high: flag(args, '--high') })
|
|
614
|
-
: action === 'disable'
|
|
615
|
-
? await disableAutoReview()
|
|
616
|
-
: await autoReviewStatus();
|
|
617
|
-
if (flag(args, '--json'))
|
|
618
|
-
return printJson(result);
|
|
619
|
-
console.log(JSON.stringify(result, null, 2));
|
|
620
|
-
async function reviewNativeAgentFixture() {
|
|
621
|
-
const root = await projectRoot();
|
|
622
|
-
const { id } = await createMission(root, { mode: 'review', prompt: 'Review native agent collaboration fixture' });
|
|
623
|
-
const native = await writeRouteCollaborationArtifacts(root, {
|
|
624
|
-
missionId: id,
|
|
625
|
-
route: '$Review',
|
|
626
|
-
routeKey: 'Review',
|
|
627
|
-
prompt: 'Review route approval safety, verification, and integration through the native agent runtime.',
|
|
628
|
-
mode: 'REVIEW'
|
|
629
|
-
});
|
|
630
|
-
return {
|
|
631
|
-
schema: 'sks.review-native-agent-fixture.v1',
|
|
632
|
-
ok: native.ok,
|
|
633
|
-
mission_id: id,
|
|
634
|
-
native_agent_collaboration: native
|
|
635
|
-
};
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
function commandRows() {
|
|
639
|
-
return COMMAND_MANIFEST_LITE.map((entry) => ({
|
|
640
|
-
name: entry.name,
|
|
641
|
-
usage: `sks ${entry.name}`,
|
|
642
|
-
description: entry.summary,
|
|
643
|
-
maturity: entry.maturity
|
|
644
|
-
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
645
|
-
}
|
|
646
480
|
function installScopeFromArgs(args = [], fallback = 'global') {
|
|
647
481
|
if (flag(args, '--project'))
|
|
648
482
|
return 'project';
|
|
@@ -651,13 +485,6 @@ function installScopeFromArgs(args = [], fallback = 'global') {
|
|
|
651
485
|
const index = args.indexOf('--install-scope');
|
|
652
486
|
return normalizeInstallScope(index >= 0 && args[index + 1] ? args[index + 1] : fallback);
|
|
653
487
|
}
|
|
654
|
-
function whichSync(command) {
|
|
655
|
-
const result = spawnSync(process.platform === 'win32' ? 'where' : 'command', process.platform === 'win32' ? [command] : ['-v', command], {
|
|
656
|
-
encoding: 'utf8',
|
|
657
|
-
shell: process.platform !== 'win32'
|
|
658
|
-
});
|
|
659
|
-
return result.status === 0 ? String(result.stdout || '').trim().split(/\r?\n/)[0] : null;
|
|
660
|
-
}
|
|
661
488
|
function valueAfter(args = [], name) {
|
|
662
489
|
const index = args.findIndex((arg) => String(arg) === name);
|
|
663
490
|
if (index < 0)
|
|
@@ -3,7 +3,7 @@ import { DOLLAR_SKILL_NAMES, RECOMMENDED_SKILLS } from '../routes.js';
|
|
|
3
3
|
export const flag = (args = [], name) => args.includes(name);
|
|
4
4
|
const KNOWN_BOOLEAN_FLAGS = new Set([
|
|
5
5
|
'--json', '--mock', '--execute', '--auto', '--visual', '--research', '--db',
|
|
6
|
-
'--
|
|
6
|
+
'--help', '-h', '--quiet'
|
|
7
7
|
]);
|
|
8
8
|
export function promptOf(args = [], knownFlags = KNOWN_BOOLEAN_FLAGS) {
|
|
9
9
|
return args.filter((x) => !knownFlags.has(String(x))).join(' ').trim();
|