sneakoscope 6.0.0 → 6.0.2
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 -1
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/fast-inline.js +0 -40
- package/dist/bin/sks-dispatch.js +0 -16
- package/dist/cli/codex-app-command.js +1 -2
- package/dist/cli/help-fast.js +2 -2
- package/dist/cli/install-helpers.js +26 -21
- package/dist/config/skills-manifest.json +57 -57
- package/dist/core/agents/agent-effort-policy.js +19 -38
- package/dist/core/agents/agent-orchestrator.js +2 -2
- package/dist/core/agents/agent-role-config.js +17 -10
- package/dist/core/agents/agent-roster.js +19 -39
- package/dist/core/agents/agent-scheduler.js +6 -5
- package/dist/core/agents/agent-schema.js +4 -5
- package/dist/core/agents/agent-task-graph.js +1 -1
- package/dist/core/agents/agent-work-partition.js +2 -1
- package/dist/core/agents/native-worker-backend-router.js +1 -1
- package/dist/core/agents/route-collaboration-ledger.js +2 -2
- package/dist/core/auto-review.js +1 -4
- package/dist/core/codex/codex-config-guard.js +11 -9
- package/dist/core/codex-adapter.js +2 -2
- package/dist/core/codex-app/codex-agent-role-sync.js +0 -1
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +7 -4
- package/dist/core/codex-app/codex-app-ui-state-snapshot.js +1 -7
- package/dist/core/codex-app.js +0 -2
- package/dist/core/codex-control/codex-model-capabilities.js +1 -2
- package/dist/core/codex-control/codex-model-metadata.js +13 -6
- package/dist/core/codex-control/codex-sdk-config-policy.js +3 -3
- package/dist/core/codex-control/codex-task-runner.js +2 -3
- package/dist/core/codex-model-guard.js +24 -89
- package/dist/core/commands/basic-cli.js +6 -0
- package/dist/core/commands/loop-command.js +2 -2
- package/dist/core/commands/mad-db-command.js +1 -1
- package/dist/core/commands/naruto-command.js +11 -11
- package/dist/core/commands/profile-command.js +14 -5
- package/dist/core/commands/qa-loop-command.js +2 -2
- package/dist/core/commands/research-command.js +2 -2
- package/dist/core/doctor/doctor-codex-startup-repair.js +0 -3
- package/dist/core/evaluation.js +1 -1
- package/dist/core/feature-fixtures.js +2 -2
- package/dist/core/feature-registry.js +1 -1
- package/dist/core/hooks-runtime.js +7 -45
- package/dist/core/image-ux-review/imagegen-adapter.js +17 -2
- package/dist/core/init/skills.js +6 -7
- package/dist/core/init.js +7 -20
- package/dist/core/loops/loop-concurrency-budget.js +6 -4
- package/dist/core/loops/loop-planner.js +1 -1
- package/dist/core/loops/loop-runtime.js +2 -2
- package/dist/core/loops/loop-scheduler.js +7 -7
- package/dist/core/managed-assets/managed-assets-manifest.js +1 -4
- package/dist/core/naruto/naruto-concurrency-governor.js +20 -17
- package/dist/core/naruto/naruto-loop-mesh.js +3 -3
- package/dist/core/naruto/resource-pressure-monitor.js +5 -2
- package/dist/core/provider/model-router.js +15 -35
- package/dist/core/release/release-gate-batch-runner.js +2 -1
- package/dist/core/release/release-gate-resource-governor.js +12 -12
- package/dist/core/release/resource-class-budget.js +5 -5
- package/dist/core/routes/constants.js +3 -4
- package/dist/core/routes.js +1 -1
- package/dist/core/structured-output-adapter.js +15 -1
- package/dist/core/update/update-migration-state.js +3 -16
- package/dist/core/version.js +1 -1
- package/dist/scripts/agent-backfill-replenishment-check.js +1 -1
- package/dist/scripts/agent-dynamic-pool-check.js +3 -3
- package/dist/scripts/agent-dynamic-pool-fixture.js +1 -1
- package/dist/scripts/agent-goal-mode-propagation-check.js +1 -1
- package/dist/scripts/agent-patch-swarm-gate-lib.js +2 -2
- package/dist/scripts/agent-role-config-repair-check.js +9 -5
- package/dist/scripts/agent-scheduler-proof-check.js +1 -1
- package/dist/scripts/agent-scheduler-proof-hardening-check.js +1 -1
- package/dist/scripts/agent-source-intelligence-propagation-check.js +1 -1
- package/dist/scripts/agent-strategy-to-lease-wiring-check.js +2 -2
- package/dist/scripts/agent-zellij-dynamic-backfill-panes-check.js +1 -1
- package/dist/scripts/codex-app-fast-ui-preservation-check.js +2 -2
- package/dist/scripts/codex-app-ui-preservation-check.js +6 -5
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +4 -4
- package/dist/scripts/codex-lb-gpt55-fast-profile-check.js +3 -2
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +6 -6
- package/dist/scripts/install-update-preserves-config-check.js +3 -3
- package/dist/scripts/loop-hardening-check-lib.js +1 -1
- package/dist/scripts/naruto-parallelism-mode-check.js +2 -1
- package/dist/scripts/naruto-shadow-clone-swarm-check.js +25 -32
- package/dist/scripts/npm-publish-performance-check.js +1 -1
- package/dist/scripts/release-aggressive-resource-governor-check.js +2 -2
- package/dist/scripts/release-parallel-check.js +1 -2
- package/dist/scripts/release-real-check.js +1 -1
- package/dist/scripts/sizecheck.js +3 -3
- package/package.json +3 -2
|
@@ -3,18 +3,9 @@ import { DEFAULT_AGENT_CONCURRENCY, DEFAULT_AGENT_COUNT, DEFAULT_NARUTO_CLONES,
|
|
|
3
3
|
import { defaultAgentPersonas, validatePersonaUniqueness } from './agent-persona.js';
|
|
4
4
|
import { buildAgentEffortPolicy, decideAgentEffort, decideNarutoCloneEffort } from './agent-effort-policy.js';
|
|
5
5
|
import { mapNarutoRoleToAgentRole, narutoRoleAllowsWrite } from '../naruto/naruto-role-policy.js';
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// (network-bound, mostly idle), so the local CPU is never the bottleneck —
|
|
10
|
-
// oversubscribing cores is exactly the point. The real local limit is MEMORY
|
|
11
|
-
// (resident set of N node+codex child processes) plus an absolute clone ceiling
|
|
12
|
-
// (MAX_NARUTO_AGENT_COUNT = 100); the provider rate limit is handled separately by
|
|
13
|
-
// the responses retry/backoff policy. So a capable host can run up to 100 in
|
|
14
|
-
// parallel regardless of core count. Tunables:
|
|
15
|
-
// SKS_NARUTO_MAX_CONCURRENCY hard cap (1..100), wins over everything
|
|
16
|
-
// SKS_NARUTO_GB_PER_WORKER memory budget per heavy worker (default 0.25 GB)
|
|
17
|
-
// SKS_NARUTO_MIN_CONCURRENCY floor so low-free-memory hosts still parallelize
|
|
6
|
+
// The roster may contain many queued clones, but active Codex workers are real
|
|
7
|
+
// Node/Codex processes. Reserve interactive CPU and memory so the desktop stays
|
|
8
|
+
// responsive; environment overrides can lower this cap, never raise it.
|
|
18
9
|
export function systemSafeNarutoConcurrency(opts = {}) {
|
|
19
10
|
const cores = Math.max(1, Number(opts.cores ?? os.cpus()?.length) || 4);
|
|
20
11
|
let freeBytes = 2 * 1024 * 1024 * 1024;
|
|
@@ -31,40 +22,28 @@ export function systemSafeNarutoConcurrency(opts = {}) {
|
|
|
31
22
|
const totalGb = totalBytes / (1024 * 1024 * 1024);
|
|
32
23
|
const backend = String(opts.backend || 'codex-sdk');
|
|
33
24
|
const heavy = backend === 'codex-sdk' || backend === 'zellij' || backend === 'process' || backend === 'ollama';
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const gbPerWorker = positiveEnvNumber('SKS_NARUTO_GB_PER_WORKER', 0.25);
|
|
43
|
-
const byMem = Math.max(1, Math.floor(budgetGb / gbPerWorker));
|
|
44
|
-
const minParallelDefault = totalGb >= 16 ? 16 : totalGb >= 8 ? 8 : totalGb >= 4 ? 4 : 2;
|
|
45
|
-
const minParallel = Math.floor(positiveEnvNumber('SKS_NARUTO_MIN_CONCURRENCY', minParallelDefault));
|
|
46
|
-
cap = Math.min(Math.max(byMem, minParallel), ceiling);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
// In-process / light workers are even cheaper; pack toward the ceiling, and never
|
|
50
|
-
// throttle tighter than the heavy backend (invariant: heavy.cap <= fake.cap).
|
|
51
|
-
const gbPerWorker = positiveEnvNumber('SKS_NARUTO_LIGHT_GB_PER_WORKER', 0.1);
|
|
52
|
-
const byMem = Math.max(2, Math.floor(budgetGb / gbPerWorker));
|
|
53
|
-
cap = Math.min(byMem, ceiling);
|
|
54
|
-
}
|
|
25
|
+
const reserveGb = Math.max(2, totalGb * 0.2);
|
|
26
|
+
const budgetGb = Math.max(0.5, freeGb - reserveGb);
|
|
27
|
+
const gbPerWorker = positiveEnvNumber(heavy ? 'SKS_NARUTO_GB_PER_WORKER' : 'SKS_NARUTO_LIGHT_GB_PER_WORKER', heavy ? 1.5 : 0.5);
|
|
28
|
+
const byMem = Math.max(1, Math.floor(budgetGb / gbPerWorker));
|
|
29
|
+
const byCpu = Math.max(1, Math.min(4, Math.floor(cores * (heavy ? 0.4 : 0.5))));
|
|
30
|
+
const load = Math.max(0, Number(opts.loadAverage ?? os.loadavg()[0]) || 0);
|
|
31
|
+
const byLoad = load >= cores ? 1 : load >= cores * 0.75 ? Math.min(2, byCpu) : byCpu;
|
|
32
|
+
let cap = Math.min(byMem, byCpu, byLoad, 4);
|
|
55
33
|
const override = Number(process.env.SKS_NARUTO_MAX_CONCURRENCY);
|
|
56
34
|
if (Number.isFinite(override) && override >= 1)
|
|
57
|
-
cap = Math.min(Math.floor(override)
|
|
58
|
-
cap = Math.max(1, Math.min(cap,
|
|
35
|
+
cap = Math.min(cap, Math.floor(override));
|
|
36
|
+
cap = Math.max(1, Math.min(cap, 4));
|
|
59
37
|
return {
|
|
60
38
|
cap,
|
|
61
39
|
cores,
|
|
62
40
|
free_gb: Math.round(freeGb * 10) / 10,
|
|
63
41
|
total_gb: Math.round(totalGb * 10) / 10,
|
|
42
|
+
load_average: Math.round(load * 100) / 100,
|
|
64
43
|
backend,
|
|
65
44
|
heavy,
|
|
66
45
|
override_applied: Number.isFinite(override) && override >= 1,
|
|
67
|
-
memory_model: heavy ? '
|
|
46
|
+
memory_model: heavy ? 'reserved_interactive_memory_heavy_worker' : 'reserved_interactive_memory_light_worker'
|
|
68
47
|
};
|
|
69
48
|
}
|
|
70
49
|
function positiveEnvNumber(name, fallback) {
|
|
@@ -87,12 +66,13 @@ export function normalizeAgentCount(value, fallback = DEFAULT_AGENT_COUNT, maxAg
|
|
|
87
66
|
return count;
|
|
88
67
|
}
|
|
89
68
|
export function normalizeAgentConcurrency(value, agents, maxAgentCount = MAX_AGENT_COUNT) {
|
|
90
|
-
const
|
|
69
|
+
const desktopSafeCap = Math.max(1, Math.min(agents, maxAgentCount, DEFAULT_AGENT_CONCURRENCY));
|
|
70
|
+
const parsed = Number(value ?? desktopSafeCap);
|
|
91
71
|
if (!Number.isFinite(parsed) || parsed < 1)
|
|
92
|
-
return
|
|
72
|
+
return desktopSafeCap;
|
|
93
73
|
if (parsed > maxAgentCount)
|
|
94
74
|
throw new Error('Agent concurrency ' + parsed + ' exceeds max ' + maxAgentCount);
|
|
95
|
-
return Math.min(Math.floor(parsed),
|
|
75
|
+
return Math.min(Math.floor(parsed), desktopSafeCap);
|
|
96
76
|
}
|
|
97
77
|
export function buildAgentRoster(opts = {}) {
|
|
98
78
|
const maxAgentCount = resolveMaxAgentCount(opts.maxAgentCount);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { appendJsonl, appendJsonlMany, nowIso, writeJsonAtomic } from '../fsx.js';
|
|
3
|
-
import { MAX_AGENT_COUNT } from './agent-schema.js';
|
|
3
|
+
import { DEFAULT_AGENT_CONCURRENCY, MAX_AGENT_COUNT } from './agent-schema.js';
|
|
4
4
|
import { appendAgentWorkQueueEvent, completeWorkItem, createAgentWorkQueue, enqueueFollowUpWorkItems, leaseNextWorkItem, pendingWorkItems, writeAgentWorkQueue } from './agent-work-queue.js';
|
|
5
5
|
import { closeWorkerSlotsAfterDrain, createAgentWorkerSlots, markWorkerSlotGenerationClosed, openWorkerSlotGeneration, writeAgentWorkerSlots } from './agent-worker-slot.js';
|
|
6
6
|
import { closeAgentSessionGeneration, createAgentSessionGeneration, writeAgentSessionGeneration } from './agent-session-generation.js';
|
|
@@ -9,7 +9,7 @@ export const AGENT_SCHEDULER_SCHEMA = 'sks.agent-scheduler.v1';
|
|
|
9
9
|
export const AGENT_SCHEDULER_EVENT_SCHEMA = 'sks.agent-scheduler-event.v1';
|
|
10
10
|
export async function runAgentScheduler(input) {
|
|
11
11
|
const maxActiveSlots = Number.isFinite(Number(input.maxActiveSlots)) && Number(input.maxActiveSlots) >= 1 ? Math.floor(Number(input.maxActiveSlots)) : MAX_AGENT_COUNT;
|
|
12
|
-
const targetActiveSlots = normalizeTargetActiveSlots(input.targetActiveSlots ?? input.roster?.
|
|
12
|
+
const targetActiveSlots = normalizeTargetActiveSlots(input.targetActiveSlots ?? input.roster?.concurrency ?? input.roster?.agent_count ?? DEFAULT_AGENT_CONCURRENCY, maxActiveSlots);
|
|
13
13
|
let slots = createAgentWorkerSlots(input.roster, targetActiveSlots);
|
|
14
14
|
const queue = createAgentWorkQueue({
|
|
15
15
|
slices: input.partition?.slices || [],
|
|
@@ -344,10 +344,11 @@ export async function runAgentScheduler(input) {
|
|
|
344
344
|
}
|
|
345
345
|
}
|
|
346
346
|
export function normalizeTargetActiveSlots(value, maxActiveSlots = MAX_AGENT_COUNT) {
|
|
347
|
-
const
|
|
348
|
-
const
|
|
347
|
+
const configuredCap = Number.isFinite(Number(maxActiveSlots)) && Number(maxActiveSlots) >= 1 ? Math.floor(Number(maxActiveSlots)) : MAX_AGENT_COUNT;
|
|
348
|
+
const cap = Math.max(1, Math.min(configuredCap, DEFAULT_AGENT_CONCURRENCY));
|
|
349
|
+
const parsed = Number(value ?? DEFAULT_AGENT_CONCURRENCY);
|
|
349
350
|
if (!Number.isFinite(parsed) || parsed < 1)
|
|
350
|
-
return
|
|
351
|
+
return cap;
|
|
351
352
|
return Math.min(cap, Math.floor(parsed));
|
|
352
353
|
}
|
|
353
354
|
function buildState(missionId, targetActiveSlots, queue, slots, active, opts) {
|
|
@@ -8,12 +8,11 @@ export const DEFAULT_AGENT_COUNT = 5;
|
|
|
8
8
|
export const AGENT_COUNT = DEFAULT_AGENT_COUNT;
|
|
9
9
|
export const AGENT_INTAKE_STAGE_ID = 'native_agent_intake';
|
|
10
10
|
export const MAX_AGENT_COUNT = 20;
|
|
11
|
-
export const DEFAULT_AGENT_CONCURRENCY =
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// cap; every other roster/scheduler caller keeps MAX_AGENT_COUNT as the default.
|
|
11
|
+
export const DEFAULT_AGENT_CONCURRENCY = 4;
|
|
12
|
+
// Naruto may queue a large roster, but active workers are governed separately and
|
|
13
|
+
// remain bounded by live CPU, memory, load, and I/O pressure.
|
|
15
14
|
export const MAX_NARUTO_AGENT_COUNT = 100;
|
|
16
|
-
export const DEFAULT_NARUTO_CLONES =
|
|
15
|
+
export const DEFAULT_NARUTO_CLONES = 8;
|
|
17
16
|
export const AGENT_BACKENDS = ['fake', 'process', 'codex-sdk', 'zellij', 'ollama', 'local-llm'];
|
|
18
17
|
export function normalizeAgentBackend(input) {
|
|
19
18
|
const value = String(input || 'codex-sdk');
|
|
@@ -3,7 +3,7 @@ import { nowIso, sha256, writeJsonAtomic } from '../fsx.js';
|
|
|
3
3
|
export const AGENT_TASK_GRAPH_SCHEMA = 'sks.agent-task-graph.v1';
|
|
4
4
|
export function buildAgentTaskGraph(input) {
|
|
5
5
|
const routeType = normalizeRouteType(input.routeType || '$Agent');
|
|
6
|
-
const targetActiveSlots = Math.max(1, Math.floor(Number(input.targetActiveSlots ||
|
|
6
|
+
const targetActiveSlots = Math.max(1, Math.min(4, Math.floor(Number(input.targetActiveSlots || 4))));
|
|
7
7
|
const minimumWorkItems = Math.max(1, Math.floor(Number(input.minimumWorkItems || targetActiveSlots)));
|
|
8
8
|
const desiredWorkItems = Math.max(minimumWorkItems, Math.floor(Number(input.desiredWorkItems || minimumWorkItems)));
|
|
9
9
|
const domainTemplates = routeTemplates(routeType);
|
|
@@ -7,12 +7,13 @@ import { detectAgentLeaseConflicts } from './work-partition/conflict-detector.js
|
|
|
7
7
|
import { buildNoOverlapProof } from './work-partition/no-overlap-proof.js';
|
|
8
8
|
import { buildAgentTaskGraph } from './agent-task-graph.js';
|
|
9
9
|
import { buildIntelligentWorkGraph, enhanceTaskGraphWithIntelligence } from './intelligent-work-graph.js';
|
|
10
|
+
import { DEFAULT_AGENT_CONCURRENCY } from './agent-schema.js';
|
|
10
11
|
export async function buildAgentWorkPartition(root, roster, prompt = '', opts = {}) {
|
|
11
12
|
const inventory = await collectRepoInventory(root);
|
|
12
13
|
const dependency_graph = buildDependencyGraph(inventory);
|
|
13
14
|
const semantic_domain_graph = buildSemanticDomainGraph(inventory);
|
|
14
15
|
const sessions = Object.fromEntries((roster.roster || []).map((agent) => [agent.id, agent.session_id]));
|
|
15
|
-
const targetActiveSlots = Number(opts.targetActiveSlots || roster.
|
|
16
|
+
const targetActiveSlots = Math.max(1, Math.min(DEFAULT_AGENT_CONCURRENCY, Number(opts.targetActiveSlots || roster.concurrency || roster.agent_count || DEFAULT_AGENT_CONCURRENCY)));
|
|
16
17
|
const intelligent_work_graph = await buildIntelligentWorkGraph({
|
|
17
18
|
root,
|
|
18
19
|
inventory,
|
|
@@ -274,7 +274,7 @@ async function resolveWorkerModelRouting(input) {
|
|
|
274
274
|
reasoning: explicitReasoning || normalizeModelReasoning(input.agent?.model_reasoning_effort) || 'medium',
|
|
275
275
|
serviceTier: explicitTier || input.fastModePolicy.service_tier || 'fast'
|
|
276
276
|
}
|
|
277
|
-
: await routeModel(category, { lbHealth });
|
|
277
|
+
: await routeModel(category, { lbHealth, model: input.agent?.model || null });
|
|
278
278
|
return {
|
|
279
279
|
category,
|
|
280
280
|
choice: routed,
|
|
@@ -38,7 +38,7 @@ export async function writeRouteCollaborationArtifacts(root, opts) {
|
|
|
38
38
|
route: opts.route,
|
|
39
39
|
prompt: opts.prompt || routeKey + ' native collaboration fixture',
|
|
40
40
|
agents: opts.agents || 5,
|
|
41
|
-
concurrency: opts.concurrency ||
|
|
41
|
+
concurrency: opts.concurrency || 4,
|
|
42
42
|
backend,
|
|
43
43
|
mock: backend === 'fake',
|
|
44
44
|
readonly: true
|
|
@@ -64,7 +64,7 @@ export async function writeRouteCollaborationArtifacts(root, opts) {
|
|
|
64
64
|
fake_backend_fixture: backend === 'fake',
|
|
65
65
|
real_mode_codex_sdk_backend: {
|
|
66
66
|
supported: true,
|
|
67
|
-
command_pattern: 'sks agent run "<task>" --backend codex-sdk --real --agents <1-20> --concurrency <1-
|
|
67
|
+
command_pattern: 'sks agent run "<task>" --backend codex-sdk --real --agents <1-20> --concurrency <1-4> --json',
|
|
68
68
|
requires_user_runtime: true
|
|
69
69
|
},
|
|
70
70
|
route_specific_personas: ROUTE_PERSONAS[routeKey] || [],
|
package/dist/core/auto-review.js
CHANGED
|
@@ -2,7 +2,6 @@ import os from 'node:os';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { ensureDir, exists, readText, writeTextAtomic } from './fsx.js';
|
|
4
4
|
import { writeCodexConfigGuarded } from './codex/codex-config-guard.js';
|
|
5
|
-
import { REQUIRED_CODEX_MODEL } from './codex-model-guard.js';
|
|
6
5
|
export const AUTO_REVIEW_REVIEWER = 'auto_review';
|
|
7
6
|
export const LEGACY_AUTO_REVIEW_REVIEWER = 'guardian_subagent';
|
|
8
7
|
export const AUTO_REVIEW_PROFILE = 'sks-auto-review';
|
|
@@ -36,7 +35,7 @@ export const REVIEW_NATIVE_AGENT_PLAN = Object.freeze({
|
|
|
36
35
|
}
|
|
37
36
|
],
|
|
38
37
|
safety_personas_read_only_by_default: true,
|
|
39
|
-
manual_agent_count_syntax: 'sks auto-review fixture --json and sks agent run "<review task>" --route $Review --agents 5 --concurrency
|
|
38
|
+
manual_agent_count_syntax: 'sks auto-review fixture --json and sks agent run "<review task>" --route $Review --agents 5 --concurrency 4 --mock --json',
|
|
40
39
|
dynamic_effort: 'parent assigns high effort to safety/integrator lanes and medium or higher to verification lanes when proof risk is present'
|
|
41
40
|
});
|
|
42
41
|
export function codexHome(env = process.env) {
|
|
@@ -119,7 +118,6 @@ export const SKS_CONFIG_PROFILES = [
|
|
|
119
118
|
];
|
|
120
119
|
function sksProfileFileBlock(opts = {}) {
|
|
121
120
|
return [
|
|
122
|
-
`model = "${REQUIRED_CODEX_MODEL}"`,
|
|
123
121
|
`service_tier = "${opts.serviceTier || 'fast'}"`,
|
|
124
122
|
`approval_policy = "${opts.approvalPolicy || 'on-request'}"`,
|
|
125
123
|
...(opts.reviewer ? [`approvals_reviewer = "${opts.reviewer}"`] : []),
|
|
@@ -315,7 +313,6 @@ function profileConfigBlock(opts = {}) {
|
|
|
315
313
|
const approvalPolicy = opts.approvalPolicy || 'on-request';
|
|
316
314
|
const sandboxMode = opts.sandboxMode || 'workspace-write';
|
|
317
315
|
return [
|
|
318
|
-
`model = "${REQUIRED_CODEX_MODEL}"`,
|
|
319
316
|
'service_tier = "fast"',
|
|
320
317
|
`approval_policy = "${approvalPolicy}"`,
|
|
321
318
|
`approvals_reviewer = "${reviewer}"`,
|
|
@@ -2,7 +2,6 @@ import path from 'node:path';
|
|
|
2
2
|
import { appendJsonl, ensureDir, nowIso, readText, sha256, writeTextAtomic } from '../fsx.js';
|
|
3
3
|
import { diffCodexAppUiSnapshots, snapshotCodexAppUiState } from '../codex-app/codex-app-ui-state-snapshot.js';
|
|
4
4
|
import { cleanupCodexConfigBackups, validateCodexConfigRoundTrip } from './codex-config-toml.js';
|
|
5
|
-
import { GPT55_CODEX_MODEL, REQUIRED_CODEX_MODEL } from '../codex-model-guard.js';
|
|
6
5
|
// fast_mode_ui was removed from the [features] schema in the 2026-07 renewal.
|
|
7
6
|
const FAST_FEATURE_KEYS = ['fast_mode'];
|
|
8
7
|
export async function writeCodexConfigGuarded(input) {
|
|
@@ -154,21 +153,24 @@ export function isUnmanagedProjectCodexConfig(root, configPath, text) {
|
|
|
154
153
|
&& !hasSksManagedCodexConfigMarker(text);
|
|
155
154
|
}
|
|
156
155
|
export function removeLegacyTopLevelCodexModeLocks(text = '') {
|
|
157
|
-
const lines = String(text || '').split('\n');
|
|
156
|
+
const lines = String(ensureTrailingNewline(text) || '').split('\n');
|
|
158
157
|
const firstTable = lines.findIndex((x) => /^\s*\[.+\]\s*$/.test(x));
|
|
159
158
|
const end = firstTable === -1 ? lines.length : firstTable;
|
|
160
|
-
const topLevelModel = topLevelTomlString(text, 'model');
|
|
161
|
-
// Current default stamp OR the legacy gpt-5.5 stamp older SKS versions wrote,
|
|
162
|
-
// so upgrades keep cleaning locks written before the 5.6-terra default bump.
|
|
163
|
-
const removeSksOwnedModeLock = topLevelModel === REQUIRED_CODEX_MODEL || topLevelModel === GPT55_CODEX_MODEL;
|
|
164
159
|
return ensureTrailingNewline(lines.filter((line, index) => {
|
|
165
160
|
if (index >= end)
|
|
166
161
|
return true;
|
|
167
|
-
if (
|
|
162
|
+
if (!/^\s*(?:model|model_reasoning_effort)\s*=/.test(line))
|
|
168
163
|
return true;
|
|
169
|
-
return
|
|
164
|
+
return !isSksProvenanceLine(line, lines[index - 1] || '');
|
|
170
165
|
}).join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n'));
|
|
171
166
|
}
|
|
167
|
+
function isSksProvenanceLine(...lines) {
|
|
168
|
+
return lines.some((line) => {
|
|
169
|
+
const trimmed = String(line || '').trim();
|
|
170
|
+
const comment = trimmed.startsWith('#') ? trimmed : trimmed.includes('#') ? trimmed.slice(trimmed.indexOf('#')) : '';
|
|
171
|
+
return /(?:SKS|Sneakoscope|codex-lb|sks fast)/i.test(comment);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
172
174
|
function mergeLostFastUiKeys(before, nextInput) {
|
|
173
175
|
let next = String(nextInput || '');
|
|
174
176
|
const keys = [];
|
|
@@ -189,7 +191,7 @@ function mergeLostFastUiKeys(before, nextInput) {
|
|
|
189
191
|
return { text: ensureTrailingNewline(next), keys };
|
|
190
192
|
}
|
|
191
193
|
function topLevelModeLocks(text) {
|
|
192
|
-
return ['
|
|
194
|
+
return ['model_reasoning_effort'].filter((key) => hasTopLevelTomlKey(text, key));
|
|
193
195
|
}
|
|
194
196
|
function topLevelTomlKeyLine(text, key) {
|
|
195
197
|
const lines = String(text || '').split('\n');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { runProcess } from './fsx.js';
|
|
3
|
-
import {
|
|
3
|
+
import { preserveCodexModelArgs } from './codex-model-guard.js';
|
|
4
4
|
import { managedProxyEnvForChild } from './codex/managed-proxy-env.js';
|
|
5
5
|
import { resolveCodexRuntime } from './codex-runtime/resolve-codex-runtime.js';
|
|
6
6
|
export async function findCodexBinary() {
|
|
@@ -35,7 +35,7 @@ export function buildCodexExecArgs({ root, prompt, outputFile, json = true, prof
|
|
|
35
35
|
args.push('--json');
|
|
36
36
|
if (outputFile)
|
|
37
37
|
args.push('--output-last-message', outputFile);
|
|
38
|
-
args.push(...
|
|
38
|
+
args.push(...preserveCodexModelArgs(extraArgs));
|
|
39
39
|
args.push(prompt);
|
|
40
40
|
return args;
|
|
41
41
|
}
|
|
@@ -87,7 +87,6 @@ function roleToml(role, payload) {
|
|
|
87
87
|
return [
|
|
88
88
|
`name = "${role}"`,
|
|
89
89
|
`description = "SKS managed ${PACKAGE_VERSION} directive role: ${role}"`,
|
|
90
|
-
'model_reasoning_effort = "medium"',
|
|
91
90
|
role.includes('implementer') ? 'sandbox_mode = "workspace-write"' : 'sandbox_mode = "read-only"',
|
|
92
91
|
'approval_policy = "never"',
|
|
93
92
|
'developer_instructions = """',
|
|
@@ -6,7 +6,6 @@ import { assertCodexAppUiMutationAllowed } from './codex-app-ui-clobber-guard.js
|
|
|
6
6
|
import { codexProviderModelUiStatus } from '../codex-app.js';
|
|
7
7
|
export const CODEX_APP_FAST_UI_REPAIR_SCHEMA = 'sks.codex-app-fast-ui-repair.v1';
|
|
8
8
|
const FAST_UI_TOP_LEVEL_RE = /^\s*(?:model|model_reasoning_effort|service_tier)\s*=/;
|
|
9
|
-
const CODEX_APP_MODE_LOCK_TOP_LEVEL_RE = /^\s*(?:model|model_reasoning_effort)\s*=/;
|
|
10
9
|
const FAST_UI_FEATURE_LINE_RE = /^\s*fast_mode\s*=/;
|
|
11
10
|
const FAST_UI_LEGACY_TABLES = new Set(['user.fast_mode', 'profiles.sks-fast-high']);
|
|
12
11
|
const SKS_CAUSED_RE = /(?:SKS|Sneakoscope|codex-lb|sks-mad|sks fast)/i;
|
|
@@ -135,14 +134,18 @@ function stripProjectLocalForbiddenKeys(text) {
|
|
|
135
134
|
});
|
|
136
135
|
}
|
|
137
136
|
function stripSksCausedHostOwnedLines(text) {
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
const topLevel = String(text || '').split(/\n\s*\[/)[0] || '';
|
|
138
|
+
const sksManagedTopLevel = SKS_CAUSED_RE.test(topLevel);
|
|
139
|
+
const sksManagedDocument = SKS_CAUSED_RE.test(String(text || ''));
|
|
140
|
+
const stripped = stripMatchingLines(text, (line, table, previous, next) => {
|
|
140
141
|
const isLegacyFastTable = table ? FAST_UI_LEGACY_TABLES.has(table) : false;
|
|
141
142
|
const isFastUiLine = FAST_UI_TOP_LEVEL_RE.test(line)
|
|
142
143
|
|| (table === 'features' && FAST_UI_FEATURE_LINE_RE.test(line))
|
|
143
144
|
|| isLegacyFastTable;
|
|
144
|
-
|
|
145
|
+
const sksMarked = (!table && sksManagedTopLevel) || (isLegacyFastTable && sksManagedDocument) || SKS_CAUSED_RE.test(line) || SKS_CAUSED_RE.test(previous) || SKS_CAUSED_RE.test(next);
|
|
146
|
+
return isFastUiLine && sksMarked;
|
|
145
147
|
});
|
|
148
|
+
return stripped;
|
|
146
149
|
}
|
|
147
150
|
function stripMatchingLines(text, shouldRemove) {
|
|
148
151
|
const lines = text.split(/\r?\n/);
|
|
@@ -4,16 +4,10 @@ import path from 'node:path';
|
|
|
4
4
|
import { exists, nowIso, readText, sha256, writeJsonAtomic } from '../fsx.js';
|
|
5
5
|
export const CODEX_APP_UI_STATE_SNAPSHOT_SCHEMA = 'sks.codex-app-ui-state-snapshot.v1';
|
|
6
6
|
export const PROJECT_LOCAL_FORBIDDEN_CODEX_KEYS = [
|
|
7
|
-
'model',
|
|
8
|
-
'model_reasoning_effort',
|
|
9
7
|
'openai_base_url',
|
|
10
8
|
'chatgpt_base_url',
|
|
11
9
|
'apps_mcp_product_sku',
|
|
12
|
-
'model_provider',
|
|
13
|
-
'model_providers',
|
|
14
10
|
'notify',
|
|
15
|
-
'profile',
|
|
16
|
-
'profiles',
|
|
17
11
|
'experimental_realtime_ws_base_url',
|
|
18
12
|
'otel'
|
|
19
13
|
];
|
|
@@ -45,7 +39,7 @@ export async function snapshotCodexAppUiState(root = process.cwd(), input = {})
|
|
|
45
39
|
return true;
|
|
46
40
|
if (signal.key_path.startsWith('user.fast_mode') && /hidden|fixed|disabled|false/i.test(signal.value_preview))
|
|
47
41
|
return true;
|
|
48
|
-
if (signal.key_path === 'model' || signal.key_path === 'model_reasoning_effort')
|
|
42
|
+
if ((signal.key_path === 'model' || signal.key_path === 'model_reasoning_effort') && signal.sks_related)
|
|
49
43
|
return true;
|
|
50
44
|
if (signal.key_path === 'service_tier' && signal.sks_related)
|
|
51
45
|
return true;
|
package/dist/core/codex-app.js
CHANGED
|
@@ -858,8 +858,6 @@ async function codexFastModeConfigStatus(opts = {}) {
|
|
|
858
858
|
if (!config.text)
|
|
859
859
|
continue;
|
|
860
860
|
const topLevel = topLevelToml(config.text);
|
|
861
|
-
if (/(^|\n)\s*model\s*=/.test(topLevel))
|
|
862
|
-
blockers.push(`${config.scope}:top_level_model`);
|
|
863
861
|
if (/(^|\n)\s*model_reasoning_effort\s*=/.test(topLevel))
|
|
864
862
|
blockers.push(`${config.scope}:top_level_model_reasoning_effort`);
|
|
865
863
|
if (/(^|\n)\s*fast_default_opt_out\s*=\s*true\s*(?:#.*)?(?=\n|$)/.test(tomlTable(config.text, 'notice')))
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { writeJsonAtomic } from '../fsx.js';
|
|
3
3
|
import { collectCodexModelMetadata } from './codex-model-metadata.js';
|
|
4
|
-
import { REQUIRED_CODEX_MODEL } from '../codex-model-guard.js';
|
|
5
4
|
export const SKS_FALLBACK_EFFORT_ORDER = ['minimal', 'low', 'medium', 'high', 'xhigh'];
|
|
6
5
|
export function codexModelEffortCapability(input = {}) {
|
|
7
6
|
const metadataIsFallback = input.metadata?.source === 'fallback';
|
|
@@ -10,7 +9,7 @@ export function codexModelEffortCapability(input = {}) {
|
|
|
10
9
|
const requestedDefault = input.metadata?.default_effort || input.defaultEffort;
|
|
11
10
|
const defaultEffort = order.includes(String(requestedDefault || '')) ? String(requestedDefault) : order.includes('medium') ? 'medium' : order[0] || 'medium';
|
|
12
11
|
return {
|
|
13
|
-
model: String(input.metadata?.model || input.model || process.env.SKS_CODEX_MODEL || process.env.CODEX_MODEL ||
|
|
12
|
+
model: String(input.metadata?.model || input.model || process.env.SKS_CODEX_MODEL || process.env.CODEX_MODEL || ''),
|
|
14
13
|
advertised_efforts: order,
|
|
15
14
|
default_effort: defaultEffort,
|
|
16
15
|
order_source: advertised.length ? 'model-advertised' : 'sks-fallback',
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { findCodexBinary } from '../codex-adapter.js';
|
|
2
2
|
import { runProcess } from '../fsx.js';
|
|
3
|
-
import { REQUIRED_CODEX_MODEL } from '../codex-model-guard.js';
|
|
4
3
|
const FALLBACK_EFFORT_ORDER = ['minimal', 'low', 'medium', 'high', 'xhigh'];
|
|
5
4
|
export async function collectCodexModelMetadata(input = {}) {
|
|
6
5
|
if (process.env.SKS_CODEX_MODEL_METADATA_FAKE === '1') {
|
|
7
6
|
const advertised = normalizeAdvertisedEfforts(process.env.SKS_CODEX_MODEL_EFFORTS || 'low,medium,high,xhigh');
|
|
8
|
-
return metadata(String(input.model || process.env.SKS_CODEX_MODEL ||
|
|
7
|
+
return metadata(String(input.model || process.env.SKS_CODEX_MODEL || process.env.CODEX_MODEL || ''), advertised, 'medium', 'app-server', []);
|
|
9
8
|
}
|
|
10
|
-
const model = String(input.model || process.env.SKS_CODEX_MODEL || process.env.CODEX_MODEL ||
|
|
9
|
+
const model = String(input.model || process.env.SKS_CODEX_MODEL || process.env.CODEX_MODEL || '').trim();
|
|
11
10
|
const appServer = await readAppServerMetadata(model);
|
|
12
11
|
if (appServer)
|
|
13
12
|
return appServer;
|
|
@@ -58,11 +57,19 @@ async function readCodexCliMetadata(model) {
|
|
|
58
57
|
return null;
|
|
59
58
|
}
|
|
60
59
|
function normalizePayload(payload, fallbackModel, source) {
|
|
61
|
-
const
|
|
62
|
-
|
|
60
|
+
const catalog = Array.isArray(payload?.models) ? payload.models : null;
|
|
61
|
+
const reportedSelection = String(payload?.selected_model || payload?.current_model || payload?.active_model || '').trim();
|
|
62
|
+
const requestedModel = String(fallbackModel || reportedSelection).trim();
|
|
63
|
+
const row = catalog
|
|
64
|
+
? requestedModel
|
|
65
|
+
? catalog.find((candidate) => String(candidate?.id || candidate?.model || candidate?.name || '') === requestedModel) || null
|
|
66
|
+
: null
|
|
63
67
|
: payload?.model_metadata || payload?.metadata || payload;
|
|
68
|
+
if (!row) {
|
|
69
|
+
return metadata(requestedModel, [], 'medium', source, [requestedModel ? 'codex_model_not_found_in_advertised_catalog' : 'codex_model_selection_unknown']);
|
|
70
|
+
}
|
|
64
71
|
const efforts = normalizeAdvertisedEfforts(row?.advertised_efforts || row?.advertisedEfforts || row?.reasoning_efforts || row?.reasoningEfforts || payload?.advertised_efforts);
|
|
65
|
-
return metadata(String(row?.model || row?.id || row?.name ||
|
|
72
|
+
return metadata(String(row?.model || row?.id || row?.name || requestedModel), efforts, row?.default_effort || row?.defaultEffort || payload?.default_effort || 'medium', source, efforts.length ? [] : ['codex_model_metadata_efforts_missing']);
|
|
66
73
|
}
|
|
67
74
|
function metadata(model, efforts, defaultEffort, source, blockers) {
|
|
68
75
|
const advertised = normalizeAdvertisedEfforts(efforts);
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { REQUIRED_CODEX_MODEL } from '../codex-model-guard.js';
|
|
2
1
|
export function buildCodexSdkConfig(input) {
|
|
3
|
-
const model = String(input.model || process.env.SKS_CODEX_MODEL || process.env.CODEX_MODEL ||
|
|
2
|
+
const model = String(input.model || process.env.SKS_CODEX_MODEL || process.env.CODEX_MODEL || '').trim();
|
|
4
3
|
const serviceTier = String(input.serviceTier || process.env.SKS_SERVICE_TIER || 'fast');
|
|
5
4
|
const config = {
|
|
6
|
-
model,
|
|
7
5
|
service_tier: serviceTier === 'standard' ? 'standard' : 'fast',
|
|
8
6
|
model_reasoning_effort: String(input.modelReasoningEffort || input.reasoningEffort || process.env.SKS_CODEX_REASONING || process.env.CODEX_MODEL_REASONING_EFFORT || 'medium'),
|
|
9
7
|
mcp_servers: {},
|
|
@@ -15,6 +13,8 @@ export function buildCodexSdkConfig(input) {
|
|
|
15
13
|
generation_index: Number(input.generationIndex || 0)
|
|
16
14
|
}
|
|
17
15
|
};
|
|
16
|
+
if (model)
|
|
17
|
+
config.model = model;
|
|
18
18
|
if (input.requestedScopeContract?.no_mcp === true) {
|
|
19
19
|
config.mcp_servers = {};
|
|
20
20
|
config.sks = { ...config.sks, no_mcp: true };
|
|
@@ -18,7 +18,6 @@ import { readLocalModelConfig } from '../agents/ollama-worker-config.js';
|
|
|
18
18
|
import { runLocalLlmTask } from '../local-llm/local-llm-control-adapter.js';
|
|
19
19
|
import { detectPythonCodexSdkCapability, runPythonCodexSdkTask } from './python-codex-sdk-adapter.js';
|
|
20
20
|
import { defaultModelCallBudget, withModelCallSlot } from './model-call-concurrency.js';
|
|
21
|
-
import { REQUIRED_CODEX_MODEL } from '../codex-model-guard.js';
|
|
22
21
|
export async function runCodexTask(input) {
|
|
23
22
|
const root = path.resolve(input.mutationLedgerRoot);
|
|
24
23
|
await ensureDir(root);
|
|
@@ -486,9 +485,9 @@ async function ensurePythonCodexLbConfig(env, config) {
|
|
|
486
485
|
const lbBaseUrl = normalizeCodexLbBaseUrl(env.CODEX_LB_BASE_URL);
|
|
487
486
|
if (!codexHome || !lbBaseUrl || !env.CODEX_LB_API_KEY)
|
|
488
487
|
return;
|
|
489
|
-
const model = String(config.model || env.SKS_CODEX_MODEL || env.CODEX_MODEL ||
|
|
488
|
+
const model = String(config.model || env.SKS_CODEX_MODEL || env.CODEX_MODEL || '').trim();
|
|
490
489
|
const text = [
|
|
491
|
-
`model = ${tomlQuote(model)}
|
|
490
|
+
...(model ? [`model = ${tomlQuote(model)}`] : []),
|
|
492
491
|
'model_provider = "codex-lb"',
|
|
493
492
|
'service_tier = "fast"',
|
|
494
493
|
`model_reasoning_effort = ${tomlQuote(String(config.model_reasoning_effort || env.SKS_CODEX_REASONING || env.CODEX_MODEL_REASONING_EFFORT || 'minimal'))}`,
|
|
@@ -1,96 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Codex owns the model catalog. SKS must never maintain a finite allowlist or
|
|
3
|
+
* silently replace a model selected by the user, workspace, or Codex client.
|
|
4
|
+
*
|
|
5
|
+
* Reasoning effort remains an SKS scheduling hint because it is independent of
|
|
6
|
+
* the model identifier and can be ignored by clients that do not advertise it.
|
|
7
|
+
*/
|
|
7
8
|
export const DEFAULT_CODEX_REASONING_EFFORT = 'high';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const input = Array.isArray(args) ? args : [];
|
|
21
|
-
for (let i = 0; i < input.length; i += 1) {
|
|
22
|
-
const arg = String(input[i]);
|
|
23
|
-
if (MODEL_VALUE_FLAGS.has(arg)) {
|
|
24
|
-
i += 1;
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
if (arg.startsWith('--model=') || arg.startsWith('-m='))
|
|
28
|
-
continue;
|
|
29
|
-
if (CONFIG_VALUE_FLAGS.has(arg)) {
|
|
30
|
-
const value = i + 1 < input.length ? String(input[i + 1]) : '';
|
|
31
|
-
if (isModelConfigOverride(value)) {
|
|
32
|
-
i += 1;
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
out.push(arg);
|
|
36
|
-
if (i + 1 < input.length)
|
|
37
|
-
out.push(String(input[++i]));
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
if (arg.startsWith('-c=') || arg.startsWith('--config=')) {
|
|
41
|
-
const value = arg.slice(arg.indexOf('=') + 1);
|
|
42
|
-
if (isModelConfigOverride(value))
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
out.push(arg);
|
|
46
|
-
}
|
|
47
|
-
return out;
|
|
48
|
-
}
|
|
49
|
-
function isSupportedCodexModel(value = '') {
|
|
50
|
-
return SUPPORTED_CODEX_MODELS.includes(String(value || '').trim().toLowerCase());
|
|
51
|
-
}
|
|
52
|
-
// The forced model is REQUIRED_CODEX_MODEL unless the caller explicitly
|
|
53
|
-
// requested another SUPPORTED model (via --model/-m/-c model=... args, or
|
|
54
|
-
// SKS_CODEX_MODEL when no arg is present). Unsupported/forbidden requests are
|
|
55
|
-
// stripped and rewritten to the required default.
|
|
56
|
-
function resolveForcedCodexModel(args = []) {
|
|
57
|
-
const requested = requestedCodexModelFromArgs(args);
|
|
58
|
-
if (isSupportedCodexModel(requested))
|
|
59
|
-
return String(requested).trim().toLowerCase();
|
|
60
|
-
const envModel = String(process.env.SKS_CODEX_MODEL || '').trim().toLowerCase();
|
|
61
|
-
if (!requested && isSupportedCodexModel(envModel))
|
|
62
|
-
return envModel;
|
|
63
|
-
return REQUIRED_CODEX_MODEL;
|
|
64
|
-
}
|
|
65
|
-
function requestedCodexModelFromArgs(args = []) {
|
|
66
|
-
const input = Array.isArray(args) ? args : [];
|
|
67
|
-
for (let i = 0; i < input.length; i += 1) {
|
|
68
|
-
const arg = String(input[i]);
|
|
69
|
-
if (MODEL_VALUE_FLAGS.has(arg))
|
|
70
|
-
return i + 1 < input.length ? String(input[i + 1]) : '';
|
|
71
|
-
if (arg.startsWith('--model=') || arg.startsWith('-m='))
|
|
72
|
-
return arg.slice(arg.indexOf('=') + 1);
|
|
73
|
-
if (CONFIG_VALUE_FLAGS.has(arg)) {
|
|
74
|
-
const value = i + 1 < input.length ? String(input[i + 1]) : '';
|
|
75
|
-
if (isModelConfigOverride(value))
|
|
76
|
-
return value.slice(value.indexOf('=') + 1).trim().replace(/^"|"$/g, '');
|
|
77
|
-
}
|
|
78
|
-
if (arg.startsWith('-c=') || arg.startsWith('--config=')) {
|
|
79
|
-
const value = arg.slice(arg.indexOf('=') + 1);
|
|
80
|
-
if (isModelConfigOverride(value))
|
|
81
|
-
return value.slice(value.indexOf('=') + 1).trim().replace(/^"|"$/g, '');
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return '';
|
|
85
|
-
}
|
|
9
|
+
function copyArgs(args = []) {
|
|
10
|
+
return Array.isArray(args) ? args.map((value) => String(value)) : [];
|
|
11
|
+
}
|
|
12
|
+
/** Return Codex arguments exactly as supplied, including future model IDs. */
|
|
13
|
+
export function preserveCodexModelArgs(args = []) {
|
|
14
|
+
return copyArgs(args);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Backward-compatible aliases for callers compiled against older SKS builds.
|
|
18
|
+
* Despite the historical name, these functions intentionally do not force a
|
|
19
|
+
* model anymore.
|
|
20
|
+
*/
|
|
86
21
|
export function forceRequiredCodexModelArgs(args = []) {
|
|
87
|
-
return
|
|
22
|
+
return preserveCodexModelArgs(args);
|
|
88
23
|
}
|
|
89
24
|
export function forceRequiredCodexModelConfigArgs(args = []) {
|
|
90
|
-
return
|
|
25
|
+
return preserveCodexModelArgs(args);
|
|
91
26
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return
|
|
27
|
+
/** No model is forbidden by SKS; availability is decided by Codex itself. */
|
|
28
|
+
export function isForbiddenCodexModel(_value = '') {
|
|
29
|
+
return false;
|
|
95
30
|
}
|
|
96
31
|
//# sourceMappingURL=codex-model-guard.js.map
|
|
@@ -187,6 +187,8 @@ export async function updateCommand(sub = 'now', args = []) {
|
|
|
187
187
|
process.exitCode = 1;
|
|
188
188
|
}
|
|
189
189
|
export async function setupCommand(args = []) {
|
|
190
|
+
if (flag(args, '--help') || flag(args, '-h'))
|
|
191
|
+
return usageCommand(['setup']);
|
|
190
192
|
const root = await projectRoot();
|
|
191
193
|
const installScope = installScopeFromArgs(args);
|
|
192
194
|
let res = null;
|
|
@@ -221,9 +223,13 @@ export async function setupCommand(args = []) {
|
|
|
221
223
|
console.log(`- ${file}`);
|
|
222
224
|
}
|
|
223
225
|
export async function bootstrapCommand(args = []) {
|
|
226
|
+
if (flag(args, '--help') || flag(args, '-h'))
|
|
227
|
+
return usageCommand(['bootstrap']);
|
|
224
228
|
return setupCommand(['--local-only', ...args]);
|
|
225
229
|
}
|
|
226
230
|
export async function initCommand(args = []) {
|
|
231
|
+
if (flag(args, '--help') || flag(args, '-h'))
|
|
232
|
+
return usageCommand(['init']);
|
|
227
233
|
return setupCommand(args);
|
|
228
234
|
}
|
|
229
235
|
export async function fixPathCommand(args = []) {
|