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.
Files changed (105) hide show
  1. package/README.md +2 -2
  2. package/config/perf-budgets.v1.json +1 -2
  3. package/config/skills-hash-ledger.v1.json +7 -2
  4. package/crates/sks-core/Cargo.lock +1 -1
  5. package/crates/sks-core/Cargo.toml +1 -1
  6. package/dist/bin/sks-dispatch.js +6 -3
  7. package/dist/cli/args.js +3 -1
  8. package/dist/cli/command-manifest-lite.js +48 -114
  9. package/dist/cli/command-registry.js +1 -18
  10. package/dist/cli/commands-fast.js +11 -4
  11. package/dist/cli/help-fast.js +11 -22
  12. package/dist/cli/help.js +3 -3
  13. package/dist/cli/install-helpers.js +1 -1
  14. package/dist/cli/router.js +12 -26
  15. package/dist/commands/codex-app.js +2 -2
  16. package/dist/commands/doctor-helpers.js +1 -1
  17. package/dist/commands/mad-sks.js +2 -2
  18. package/dist/config/skills-manifest.json +13 -8
  19. package/dist/core/agent-bridge/async-command.js +2 -2
  20. package/dist/core/agents/agent-recursion-guard.js +0 -2
  21. package/dist/core/auto-review.js +15 -172
  22. package/dist/core/code-structure.js +0 -1
  23. package/dist/core/codex-control/codex-reliability-shield.js +64 -15
  24. package/dist/core/codex-control/codex-sdk-adapter.js +38 -5
  25. package/dist/core/commands/agent-bridge-command.js +1 -1
  26. package/dist/core/commands/basic-cli.js +60 -233
  27. package/dist/core/commands/command-utils.js +1 -1
  28. package/dist/core/commands/gc-command.js +30 -29
  29. package/dist/core/commands/image-ux-review-command.js +1 -1
  30. package/dist/core/commands/install-package-command.js +1 -1
  31. package/dist/core/commands/intent-normalization/normalizer.js +2 -2
  32. package/dist/core/commands/pipeline-command.js +13 -5
  33. package/dist/core/commands/plan-command.js +2 -3
  34. package/dist/core/commands/research-command.js +0 -3
  35. package/dist/core/commands/review-command.js +1 -1
  36. package/dist/core/commands/seo-command.js +27 -20
  37. package/dist/core/commands/status-command.js +8 -2
  38. package/dist/core/doctor/command-alias-cleanup.js +6 -6
  39. package/dist/core/evaluation.js +1 -1
  40. package/dist/core/feature-fixtures.js +9 -43
  41. package/dist/core/feature-registry.js +9 -27
  42. package/dist/core/git-hygiene/shared-memory-publish.js +1 -1
  43. package/dist/core/hooks-runtime/stop-repeat-guard.js +0 -13
  44. package/dist/core/init/skills.js +5 -13
  45. package/dist/core/init.js +0 -9
  46. package/dist/core/install/installed-package-smoke.js +3 -1
  47. package/dist/core/perf/import-graph-budget.js +0 -1
  48. package/dist/core/perf/release-latency-slo.js +2 -30
  49. package/dist/core/pipeline-internals/pipeline-stage-builder.js +2 -4
  50. package/dist/core/pipeline-internals/runtime-core.js +2 -38
  51. package/dist/core/proof/route-proof-policy.js +2 -4
  52. package/dist/core/proof/runtime-truth-matrix.js +2 -2
  53. package/dist/core/proof-field.js +104 -39
  54. package/dist/core/questions.js +11 -7
  55. package/dist/core/release/gate-affected-globs.js +0 -2
  56. package/dist/core/research/research-reviewer-contract.js +34 -0
  57. package/dist/core/research/research-work-graph.js +1 -1
  58. package/dist/core/research.js +1 -1
  59. package/dist/core/routes/constants.js +0 -1
  60. package/dist/core/routes/diagnostic-allowlist.js +1 -3
  61. package/dist/core/routes/light-routes.js +1 -2
  62. package/dist/core/routes.js +1 -1
  63. package/dist/core/safety/command-contract/contracts.js +5 -1
  64. package/dist/core/search-visibility/marketing-truthfulness.js +10 -7
  65. package/dist/core/search-visibility/marketing.js +194 -149
  66. package/dist/core/skill-forge.js +1 -361
  67. package/dist/core/strategy/adhd-orchestrating-gate.js +3 -3
  68. package/dist/core/triwiki/context-graph/extractors/topology/commands.js +2 -6
  69. package/dist/core/triwiki-wrongness/wrongness-cli.js +9 -27
  70. package/dist/core/version.js +1 -1
  71. package/package.json +1 -2
  72. package/release-gates.v2.json +1 -32
  73. package/dist/cli/recallpulse-command.js +0 -144
  74. package/dist/commands/auto-review.js +0 -5
  75. package/dist/commands/codex-native.js +0 -77
  76. package/dist/commands/recallpulse.js +0 -5
  77. package/dist/core/codex-native/codex-native-interop-policy.js +0 -127
  78. package/dist/core/commands/autoresearch-command.js +0 -4
  79. package/dist/core/commands/code-structure-command.js +0 -52
  80. package/dist/core/commands/goal-command.js +0 -43
  81. package/dist/core/commands/recallpulse-command.js +0 -4
  82. package/dist/core/commands/remote-command.js +0 -119
  83. package/dist/core/commands/skill-dream-command.js +0 -43
  84. package/dist/core/commands/wrongness-command.js +0 -2
  85. package/dist/core/goal-workflow.js +0 -80
  86. package/dist/core/mcp/mcp-tool-name-normalizer.js +0 -28
  87. package/dist/core/recallpulse/policy.js +0 -207
  88. package/dist/core/recallpulse.js +0 -947
  89. package/dist/core/remote/audit-idempotency.js +0 -241
  90. package/dist/core/remote/index.js +0 -10
  91. package/dist/core/remote/machine-registry.js +0 -167
  92. package/dist/core/remote/owner-proof.js +0 -216
  93. package/dist/core/remote/protocol.js +0 -249
  94. package/dist/core/remote/readiness.js +0 -156
  95. package/dist/core/remote/session-index.js +0 -61
  96. package/dist/core/remote/session-snapshot.js +0 -197
  97. package/dist/core/remote/ssh-worker-client.js +0 -377
  98. package/dist/core/remote/types.js +0 -10
  99. package/dist/core/remote/worker.js +0 -360
  100. package/dist/core/search/context-graph-seeds.js +0 -15
  101. package/dist/core/verification/context-graph-affected.js +0 -312
  102. package/dist/core/verification/verification-artifact-lock.js +0 -21
  103. package/dist/core/verification/verification-dag.js +0 -89
  104. package/dist/core/verification/verification-result.js +0 -19
  105. 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; attempt <= policy.maxEmptyResultRetries + 1; 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 || attempt > policy.maxEmptyResultRetries)
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: modelCapacityRetryCount,
72
- selected_model_capacity_fallback: selectedAttempt > 1 && modelCapacityRetryCount > 0,
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 (!modelCapacity && !fatal && idle && meaningful.length === 0) {
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 (!modelCapacity && !fatal && empty) {
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
- const text = collectText(result, events);
140
- 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);
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 = collectFatalSignalText(result, events);
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 collectFatalSignalText(result, events) {
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
- throw err;
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.find((event) => event?.type === 'turn.failed' || event?.type === 'error');
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,stats] [--json]',
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 { spawnSync } from 'node:child_process';
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, sksRoot, tmpdir, writeJsonAtomic } from '../fsx.js';
9
- import { DOLLAR_COMMANDS, USAGE_TOPICS, routePrompt, routeReasoning, reasoningInstruction, sksPrefixedDollarCommand } from '../routes.js';
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[0];
24
- if (topic)
25
- return usageCommand([topic]);
26
- console.log(`${sksTextLogo()}\n\nUsage\n`);
27
- console.log(' sks');
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
- console.log('\nThree core promises: Completion Proof for serious routes, Image Voxel TriWiki for visual routes, and release-gated Codex App/Desktop Bridge/hooks/Rust evidence.');
37
- }
38
- export function commandsCommand(args = []) {
39
- const commands = commandRows();
40
- if (flag(args, '--json')) {
41
- return printJson({
42
- schema: 'sks.command-registry.v1',
43
- aliases: ['sks', 'sneakoscope'],
44
- commands
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(`${sksTextLogo()}\n\nCommands\n`);
48
- const width = Math.max(...commands.map((entry) => entry.usage.length));
49
- for (const entry of commands)
50
- console.log(`${entry.usage.padEnd(width)} ${entry.description}`);
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 --local-only
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
- Ask Codex for ordinary work directly; SKS hooks keep it safe. Use $sks-plan to plan, $sks-naruto or $sks-work to split work across child agents, and $sks-help to see every route.`);
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, '--help') || flag(args, '-h'))
299
- return usageCommand(['setup']);
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
- '--legacy-goal-runtime', '--help', '-h', '--quiet'
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();