sneakoscope 4.0.3 → 4.0.5

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 (30) hide show
  1. package/README.md +9 -8
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/bin/sks.js +1 -1
  6. package/dist/core/codex-app/glm-profile-schema.js +5 -1
  7. package/dist/core/commands/glm-command.js +20 -1
  8. package/dist/core/commands/mad-sks-command.js +174 -20
  9. package/dist/core/fsx.js +1 -1
  10. package/dist/core/perf/lru-cache.js +33 -0
  11. package/dist/core/providers/glm/glm-52-profile.js +14 -7
  12. package/dist/core/providers/glm/glm-52-request.js +40 -12
  13. package/dist/core/providers/glm/glm-52-response-guard.js +1 -2
  14. package/dist/core/providers/glm/glm-52-settings.js +50 -8
  15. package/dist/core/providers/glm/glm-bench.js +90 -0
  16. package/dist/core/providers/glm/glm-context-budget.js +15 -0
  17. package/dist/core/providers/glm/glm-context-cache.js +9 -0
  18. package/dist/core/providers/glm/glm-latency-trace.js +40 -0
  19. package/dist/core/providers/glm/glm-mad-launch.js +128 -0
  20. package/dist/core/providers/glm/glm-mad-mode.js +48 -20
  21. package/dist/core/providers/glm/glm-model-meta-cache.js +19 -0
  22. package/dist/core/providers/glm/glm-profile-resolver.js +104 -0
  23. package/dist/core/providers/glm/glm-reasoning-policy.js +15 -0
  24. package/dist/core/providers/glm/glm-request-cache.js +47 -0
  25. package/dist/core/providers/glm/glm-speed-context.js +82 -0
  26. package/dist/core/providers/glm/glm-speed-gate.js +40 -0
  27. package/dist/core/providers/glm/glm-speed-output-parser.js +40 -0
  28. package/dist/core/providers/glm/glm-tool-schema-cache.js +19 -0
  29. package/dist/core/version.js +1 -1
  30. package/package.json +1 -1
package/README.md CHANGED
@@ -35,15 +35,16 @@ Set up this agent project with Sneakoscope Codex. Use [[mandarange/Sneakoscope-C
35
35
 
36
36
  ## 🚀 Current Release
37
37
 
38
- SKS **4.0.3** adds a GLM 5.2-only MAD mode through OpenRouter while preserving the proof-first SKS pipeline. `sks --mad --glm` resolves the GLM profile, keeps GPT/OpenAI fallback disabled, and records model-lock proof; `sks --mad --glm --repair` rotates the OpenRouter API key outside project files.
38
+ SKS **4.0.5** tunes only the GLM 5.2 MAD path: `sks --mad --glm` now defaults to an xhigh reasoning profile while recovering speed through compact GLM context, disabled default tools, streaming, request/schema caches, and redacted bench/trace artifacts. Ordinary `sks --mad`, Naruto/Team, and non-GLM Codex paths keep their existing defaults.
39
39
 
40
- What changed in 4.0.3:
40
+ What changed in 4.0.5:
41
41
 
42
- - **GLM 5.2 MAD mode.** `sks --mad --glm` enters a `mad-glm` profile using OpenRouter model `z-ai/glm-5.2`.
43
- - **No GPT fallback.** GLM requests use `provider.allow_fallbacks: false`, omit fallback `models`, and reject non-GLM response model ids before mutation.
44
- - **OpenRouter key lifecycle.** Keys resolve from `OPENROUTER_API_KEY`, `SKS_OPENROUTER_API_KEY`, or the user SKS secret store; stored keys use private permissions and redacted metadata.
45
- - **Codex App profile.** `sks codex-app glm-profile install` writes the `sks/glm-5.2-mad` profile metadata for Codex App selection.
46
- - **Codex 0.141 alignment.** SKS delegates remote relay, cwd/shell/path preservation, selected plugin MCP activation, App/MCP dedupe, bounded prompt-image cache, bounded feedback upload, and terminal resize behavior to Codex-native semantics where available.
42
+ - **GLM-only xhigh speed profile.** `sks --mad --glm` keeps OpenRouter locked to `z-ai/glm-5.2`, uses `reasoning.effort: xhigh`, and bounds the default completion budget to the speed profile instead of changing global SKS reasoning defaults.
43
+ - **Compact GLM request shape.** The GLM speed profile uses streaming, `tool_choice: none`, no fallback `models`, `provider.allow_fallbacks: false`, `provider.require_parameters: true`, and throughput/latency provider preferences.
44
+ - **Opt-in GLM depth controls.** `--deep`, `--xhigh`, `--strict`, `--ttft`, and `--exact-provider` select explicit GLM profiles without affecting non-GLM routes.
45
+ - **GLM speed infrastructure.** GLM-only context budgeting, encoded request cache, tool schema cache, model metadata cache, output envelope parsing, deterministic patch gating, latency traces, and `--bench` dry-run diagnostics are covered by tests.
46
+ - **No GPT fallback panes.** GLM MAD keeps the existing GPT/codex-sdk native swarm disabled by default until a GLM worker backend exists, preserving the no-fallback guarantee.
47
+ - **4.0.4 GLM launch proof remains.** Each GLM MAD launch still writes `mad-glm-launch.json` with provider/model/profile/wrapper evidence and keeps OpenRouter keys out of layout artifacts.
47
48
 
48
49
  SKS **3.1.16** was a launch-reliability patch on the 3.1.15 doctor-reliability release. It made `sks --mad` self-bootstrap a fresh project instead of dead-ending on a missing Codex config.
49
50
 
@@ -395,7 +396,7 @@ sks team open-zellij latest
395
396
  sks team attach-zellij latest
396
397
  ```
397
398
 
398
- Interactive SKS sessions use Zellij layouts. By default SKS launches Codex in Fast service tier with `--model gpt-5.5`, `-c service_tier="fast"`, the selected `model_reasoning_effort`, and `--no-alt-screen` for Zellij-backed interactive panes so terminal scrollback captures the conversation transcript. SKS always forces the model to `gpt-5.5`; `SKS_CODEX_MODEL` and `SKS_CODEX_FAST_HIGH=0` cannot downgrade or remove that model pin. You can still set `SKS_CODEX_REASONING` to change reasoning effort, and `SKS_ZELLIJ_CODEX_ALT_SCREEN=1` restores Codex's alternate-screen UI for the next launch. Use `sks --mad --workspace <name>` for an explicit MAD session and `sks help` for CLI help.
399
+ Interactive SKS sessions use Zellij layouts. By default SKS launches Codex in Fast service tier with `--model gpt-5.5`, `-c service_tier="fast"`, the selected `model_reasoning_effort`, and `--no-alt-screen` for Zellij-backed interactive panes so terminal scrollback captures the conversation transcript. Non-GLM SKS sessions force the model to `gpt-5.5`; `sks --mad --glm` is the OpenRouter GLM 5.2 exception. `SKS_CODEX_MODEL` and `SKS_CODEX_FAST_HIGH=0` cannot downgrade or remove the non-GLM model pin. You can still set `SKS_CODEX_REASONING` to change reasoning effort, and `SKS_ZELLIJ_CODEX_ALT_SCREEN=1` restores Codex's alternate-screen UI for the next launch. Use `sks --mad --workspace <name>` for an explicit MAD session and `sks help` for CLI help.
399
400
 
400
401
  Before opening the interactive runtime, SKS checks the installed Codex CLI against npm `@openai/codex@latest`. If a newer version exists, it asks `Y/n`; answering `y` updates automatically with `npm i -g @openai/codex@latest` and then opens the runtime with the updated Codex CLI.
401
402
 
@@ -76,7 +76,7 @@ dependencies = [
76
76
 
77
77
  [[package]]
78
78
  name = "sks-core"
79
- version = "4.0.3"
79
+ version = "4.0.5"
80
80
  dependencies = [
81
81
  "serde_json",
82
82
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "4.0.3"
3
+ version = "4.0.5"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -4,7 +4,7 @@ use std::io::{self, Read, Seek, SeekFrom};
4
4
  fn main() {
5
5
  let mut args = std::env::args().skip(1);
6
6
  match args.next().as_deref() {
7
- Some("--version") => println!("sks-rs 4.0.3"),
7
+ Some("--version") => println!("sks-rs 4.0.5"),
8
8
  Some("compact-info") => {
9
9
  let mut input = String::new();
10
10
  let _ = io::stdin().read_to_string(&mut input);
package/dist/bin/sks.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const FAST_PACKAGE_VERSION = '4.0.3';
2
+ const FAST_PACKAGE_VERSION = '4.0.5';
3
3
  const args = process.argv.slice(2);
4
4
  try {
5
5
  if (args[0] === '--agent' && args[1] === 'worker') {
@@ -13,7 +13,11 @@ export function validateGlmCodexAppModelProfile(value) {
13
13
  profile.model === GLM_52_OPENROUTER_MODEL ? null : 'glm_codex_app_profile_invalid_model',
14
14
  profile.mode === GLM_MAD_MODE ? null : 'glm_codex_app_profile_invalid_mode',
15
15
  profile.strictModelLock === true ? null : 'glm_codex_app_profile_not_strict',
16
- profile.gptFallbackAllowed === false ? null : 'glm_codex_app_profile_allows_gpt_fallback'
16
+ profile.gptFallbackAllowed === false ? null : 'glm_codex_app_profile_allows_gpt_fallback',
17
+ profile.defaultProfile === 'speed' ? null : 'glm_codex_app_profile_default_not_speed',
18
+ profile.defaultSettings?.tool_choice === 'none' ? null : 'glm_codex_app_profile_default_tools_not_omitted',
19
+ profile.defaultSettings?.provider_require_parameters === true ? null : 'glm_codex_app_profile_default_does_not_require_parameters',
20
+ profile.defaultSettings?.provider_allow_fallbacks === false ? null : 'glm_codex_app_profile_allows_provider_fallback'
17
21
  ].filter((item) => Boolean(item));
18
22
  return {
19
23
  ok: blockers.length === 0,
@@ -1,5 +1,24 @@
1
1
  import { runMadGlmMode } from '../providers/glm/glm-mad-mode.js';
2
+ import { flag } from '../../cli/args.js';
3
+ import { madHighCommand } from './mad-sks-command.js';
4
+ import { runGlmBench } from '../providers/glm/glm-bench.js';
5
+ import { printJson } from '../../cli/output.js';
2
6
  export async function glmCommand(args = []) {
3
- return runMadGlmMode(args);
7
+ if (flag(args, '--bench')) {
8
+ const result = await runGlmBench(process.cwd(), args);
9
+ if (result.status === 'blocked')
10
+ process.exitCode = 1;
11
+ if (flag(args, '--json'))
12
+ printJson(result);
13
+ else if (result.status === 'blocked')
14
+ console.error(`GLM bench blocked: ${result.warnings.join(', ')}`);
15
+ else
16
+ console.log(`GLM bench: dry-run p50=${result.summary.speed_p50_total_ms}ms ratio=${result.summary.speed_vs_deep_ratio}`);
17
+ return result;
18
+ }
19
+ const result = await runMadGlmMode(args);
20
+ if (!result.ok || flag(args, '--repair') || flag(args, '--json'))
21
+ return result;
22
+ return madHighCommand(['--glm', ...args], { glmReadiness: result, glmArgs: args });
4
23
  }
5
24
  //# sourceMappingURL=glm-command.js.map
@@ -24,16 +24,37 @@ import { writeCodex0138CapabilityArtifacts } from '../codex-control/codex-0138-c
24
24
  import { writeCodex0139CapabilityArtifacts } from '../codex-control/codex-0139-capability.js';
25
25
  import { resolveCodexNativeInvocationPlan } from '../codex-native/codex-native-invocation-router.js';
26
26
  import { repairZellijForSks } from '../zellij/zellij-self-heal.js';
27
+ import { buildMadGlmLaunchArtifact, buildMadGlmLaunchProfileNoWrite, resolveMadGlmLaunchKey, writeMadGlmCodexWrapper } from '../providers/glm/glm-mad-launch.js';
28
+ import { GLM_MAD_MODE } from '../providers/glm/glm-52-settings.js';
27
29
  export async function madHighCommand(args = [], deps = {}) {
28
30
  const subcommand = firstSubcommand(args);
29
31
  if (subcommand)
30
32
  return madSksSubcommand(subcommand, args.filter((arg) => String(arg) !== subcommand));
31
- const cleanArgs = stripMadLaunchOnlyArgs(args);
32
33
  const rawArgs = (args || []).map((arg) => String(arg));
34
+ const glmMadLaunch = isMadGlmLaunch(rawArgs, deps);
35
+ const glmOnlyFlagBlockers = findGlmOnlyMadFlagBlockers(rawArgs, glmMadLaunch);
36
+ if (glmOnlyFlagBlockers.length) {
37
+ const result = {
38
+ ok: false,
39
+ status: 'blocked',
40
+ blockers: glmOnlyFlagBlockers,
41
+ hint: 'GLM profile and diagnostics flags require sks --mad --glm.'
42
+ };
43
+ if (rawArgs.includes('--json'))
44
+ console.log(JSON.stringify(result, null, 2));
45
+ else {
46
+ console.error('SKS MAD launch blocked: GLM-only flags require --glm.');
47
+ for (const blocker of glmOnlyFlagBlockers)
48
+ console.error(`- ${blocker}`);
49
+ }
50
+ process.exitCode = 1;
51
+ return result;
52
+ }
53
+ const cleanArgs = stripMadLaunchOnlyArgs(args, { includeGlmFlags: glmMadLaunch });
33
54
  const madDbGrant = resolveMadLaunchMadDbGrant(rawArgs);
34
55
  const dryRun = rawArgs.includes('--dry-run');
35
- if (args.includes('--json') && !dryRun) {
36
- const profile = buildMadHighLaunchProfileNoWrite();
56
+ if (rawArgs.includes('--json') && !dryRun) {
57
+ const profile = glmMadLaunch ? buildMadGlmLaunchProfileNoWrite(rawArgs) : buildMadHighLaunchProfileNoWrite();
37
58
  return console.log(JSON.stringify(profile, null, 2));
38
59
  }
39
60
  const update = { status: 'notice_only', non_blocking: true };
@@ -76,7 +97,7 @@ export async function madHighCommand(args = [], deps = {}) {
76
97
  }
77
98
  return report;
78
99
  }
79
- const codexUpdate = deps.maybePromptCodexUpdateForLaunch ? await deps.maybePromptCodexUpdateForLaunch(args, { label: 'MAD launch' }) : { status: 'skipped' };
100
+ const codexUpdate = deps.maybePromptCodexUpdateForLaunch ? await deps.maybePromptCodexUpdateForLaunch(args, { label: glmMadLaunch ? 'GLM MAD launch' : 'MAD launch' }) : { status: 'skipped' };
80
101
  if (codexUpdate.status === 'failed' || codexUpdate.status === 'updated_not_reflected') {
81
102
  console.error(`Codex CLI update failed: ${codexUpdate.error || 'updated version was not visible on PATH'}`);
82
103
  process.exitCode = 1;
@@ -86,7 +107,7 @@ export async function madHighCommand(args = [], deps = {}) {
86
107
  ? { status: 'skipped', command: 'sks doctor --fix --yes' }
87
108
  : deps.maybePromptZellijUpdateForLaunch
88
109
  ? await deps.maybePromptZellijUpdateForLaunch(args, {
89
- label: 'MAD launch',
110
+ label: glmMadLaunch ? 'GLM MAD launch' : 'MAD launch',
90
111
  root: launchRoot,
91
112
  selfHealOnMissing: true,
92
113
  autoApprove: rawArgs.includes('--yes') || rawArgs.includes('-y'),
@@ -121,8 +142,10 @@ export async function madHighCommand(args = [], deps = {}) {
121
142
  process.exitCode = 1;
122
143
  return;
123
144
  }
124
- const lb = deps.maybePromptCodexLbSetupForLaunch ? await deps.maybePromptCodexLbSetupForLaunch(args) : { status: 'skipped' };
125
- if (lb.status === 'missing_api_key') {
145
+ const lb = glmMadLaunch
146
+ ? { status: 'skipped_glm_openrouter', ok: false, reason: 'glm_mad_uses_openrouter_directly' }
147
+ : deps.maybePromptCodexLbSetupForLaunch ? await deps.maybePromptCodexLbSetupForLaunch(args) : { status: 'skipped' };
148
+ if (!glmMadLaunch && lb.status === 'missing_api_key') {
126
149
  process.exitCode = 1;
127
150
  return;
128
151
  }
@@ -171,6 +194,11 @@ export async function madHighCommand(args = [], deps = {}) {
171
194
  return launchPreflight;
172
195
  }
173
196
  const madLaunch = await activateMadZellijPermissionState(process.cwd(), args);
197
+ const glmRuntime = glmMadLaunch ? await prepareMadGlmLaunchRuntime(madLaunch, { ...deps, glmArgs: deps?.glmArgs || rawArgs }) : null;
198
+ if (glmMadLaunch && !glmRuntime?.ok) {
199
+ process.exitCode = 1;
200
+ return glmRuntime;
201
+ }
174
202
  const madDbCapability = madDbGrant.enabled
175
203
  ? await createMadDbCapability(madLaunch.root, { missionId: madLaunch.mission_id, ack: madDbGrant.ack, cwd: process.cwd() })
176
204
  : null;
@@ -221,7 +249,9 @@ export async function madHighCommand(args = [], deps = {}) {
221
249
  error: err?.message || String(err)
222
250
  }));
223
251
  await appendJsonlBounded(path.join(madLaunch.dir, 'events.jsonl'), { ts: nowIso(), type: 'mad_sks.update_notice_checked', non_blocking: true, update_available: updateNotice.update_available === true, source: updateNotice.source });
224
- console.log(`SKS MAD ready: ${madHighProfileName()} | gate ${madLaunch.mission_id}`);
252
+ console.log(`SKS MAD ready: ${glmRuntime?.profile?.profile_name || madHighProfileName()} | gate ${madLaunch.mission_id}`);
253
+ if (glmRuntime?.profile)
254
+ console.log(`GLM MAD launch active: ${glmRuntime.profile.model} via OpenRouter; GPT fallback blocked.`);
225
255
  if (madDbCapability)
226
256
  console.log(`MAD-DB one-cycle capability active (${madDbGrant.source}); expires ${madDbCapability.expires_at}.`);
227
257
  if (updateNotice.update_available === true)
@@ -233,8 +263,18 @@ export async function madHighCommand(args = [], deps = {}) {
233
263
  SKS_MAD_SKS_TARGET_ROOT: madLaunch.gate.cwd,
234
264
  SKS_MAD_SKS_PROTECTED_CORE_DIGEST: madLaunch.gate.protected_core_digest
235
265
  };
236
- const launchOpts = codexLbImmediateLaunchOpts(cleanArgs, launchLb, { codexArgs: profile.launch_args, conciseBlockers: true, madSksEnv, launchEnv: madSksEnv });
237
266
  const explicitWorkspace = readOption(cleanArgs, '--workspace', readOption(cleanArgs, '--session', null));
267
+ const launchProfile = glmRuntime?.profile || profile;
268
+ const launchOpts = glmRuntime
269
+ ? buildGlmMadLaunchOpts(cleanArgs, {
270
+ codexArgs: launchProfile.launch_args,
271
+ conciseBlockers: true,
272
+ madSksEnv,
273
+ launchEnv: madSksEnv,
274
+ codexBin: glmRuntime.wrapper.wrapper_path,
275
+ explicitWorkspace
276
+ })
277
+ : codexLbImmediateLaunchOpts(cleanArgs, launchLb, { codexArgs: launchProfile.launch_args, conciseBlockers: true, madSksEnv, launchEnv: madSksEnv });
238
278
  // Only the auto-derived stable `sks-mad-<cwd>` name accumulates panes across
239
279
  // runs; when the user names a session explicitly (or codex-lb already minted a
240
280
  // fresh unique session) respect it and skip the reset.
@@ -268,11 +308,12 @@ export async function madHighCommand(args = [], deps = {}) {
268
308
  worker_panes_created: 0,
269
309
  right_column_mode: 'spawn-on-first-worker'
270
310
  });
271
- const madNativeSwarm = await startMadNativeSwarm(madLaunch.root, madLaunch, args, profile, {
311
+ const madNativeSwarm = await startMadNativeSwarm(madLaunch.root, madLaunch, args, launchProfile, {
272
312
  env: {
273
313
  ...madSksEnv,
274
314
  ...(launch.session_name ? { SKS_ZELLIJ_SESSION_NAME: launch.session_name } : {})
275
315
  },
316
+ glmLaunch: glmRuntime ? { provider: glmRuntime.profile.provider, model: glmRuntime.profile.model } : null,
276
317
  zellijSessionName: launch.session_name || null,
277
318
  workerPlacement: headlessZellij ? 'process' : shouldAutoAttachZellij(args) ? 'zellij-pane' : 'process',
278
319
  zellijVisiblePaneCap: Number(process.env.SKS_ZELLIJ_VISIBLE_PANE_CAP || 8)
@@ -296,6 +337,73 @@ export async function madHighCommand(args = [], deps = {}) {
296
337
  console.log('MAD launch running headless: live_panes=false.');
297
338
  return launch;
298
339
  }
340
+ function isMadGlmLaunch(args = [], deps = {}) {
341
+ const list = (args || []).map((arg) => String(arg));
342
+ return list.includes('--glm') || deps?.glmReadiness?.mode === GLM_MAD_MODE;
343
+ }
344
+ async function prepareMadGlmLaunchRuntime(madLaunch, deps = {}) {
345
+ const keyResolution = await resolveMadGlmLaunchKey(process.env);
346
+ const profile = buildMadGlmLaunchProfileNoWrite(deps?.glmArgs || []);
347
+ if (!keyResolution.key) {
348
+ const blocked = {
349
+ schema: 'sks.glm-mad-launch.v1',
350
+ ok: false,
351
+ status: 'blocked',
352
+ mission_id: madLaunch.mission_id,
353
+ provider: profile.provider,
354
+ model: profile.model,
355
+ glm_profile: profile.glm_profile,
356
+ glm_mode: profile.glm_mode,
357
+ model_reasoning_effort: profile.model_reasoning_effort,
358
+ gpt_fallback_allowed: false,
359
+ blockers: keyResolution.blockers,
360
+ warnings: keyResolution.warnings
361
+ };
362
+ await writeJsonAtomic(path.join(madLaunch.dir, 'mad-glm-launch.json'), blocked);
363
+ await appendJsonlBounded(path.join(madLaunch.dir, 'events.jsonl'), {
364
+ ts: nowIso(),
365
+ type: 'mad_sks.glm_launch_blocked',
366
+ blockers: keyResolution.blockers
367
+ });
368
+ console.error('SKS GLM MAD launch blocked: OpenRouter API key is missing.');
369
+ console.error('Run: sks --mad --glm --repair');
370
+ return blocked;
371
+ }
372
+ const wrapper = await writeMadGlmCodexWrapper({
373
+ missionDir: madLaunch.dir,
374
+ realCodexBin: process.env.SKS_CODEX_BIN || null
375
+ });
376
+ const report = {
377
+ ...buildMadGlmLaunchArtifact({
378
+ missionId: madLaunch.mission_id,
379
+ keyResolution,
380
+ wrapper,
381
+ profile
382
+ }),
383
+ readiness_status: deps?.glmReadiness?.status || null
384
+ };
385
+ await writeJsonAtomic(path.join(madLaunch.dir, 'mad-glm-launch.json'), report);
386
+ await appendJsonlBounded(path.join(madLaunch.dir, 'events.jsonl'), {
387
+ ts: nowIso(),
388
+ type: 'mad_sks.glm_launch_profile_ready',
389
+ provider: profile.provider,
390
+ model: profile.model,
391
+ glm_profile: profile.glm_profile,
392
+ glm_mode: profile.glm_mode,
393
+ model_reasoning_effort: profile.model_reasoning_effort,
394
+ key_source: keyResolution.source || null,
395
+ gpt_fallback_allowed: false
396
+ });
397
+ return { ok: true, profile, wrapper, report };
398
+ }
399
+ function buildGlmMadLaunchOpts(cleanArgs = [], opts = {}) {
400
+ if (opts.explicitWorkspace)
401
+ return opts;
402
+ const root = readOption(cleanArgs, '--root', process.cwd());
403
+ const session = sanitizeZellijSessionName(`sks-glm-${Date.now().toString(36)}-${path.basename(root) || 'project'}`);
404
+ console.log(`Using fresh GLM Zellij session: ${session}`);
405
+ return { ...opts, session, glmMadLaunch: true };
406
+ }
299
407
  export function resolveMadLaunchMadDbGrant(args = []) {
300
408
  const list = (args || []).map((arg) => String(arg));
301
409
  return {
@@ -319,6 +427,9 @@ export async function startMadNativeSwarm(root, madLaunch, args = [], profile =
319
427
  status: 'disabled',
320
428
  reason: swarm.disabled_reason,
321
429
  mission_id: madLaunch.mission_id,
430
+ model_provider: opts.glmLaunch?.provider || null,
431
+ model: opts.glmLaunch?.model || null,
432
+ gpt_fallback_allowed: opts.glmLaunch ? false : null,
322
433
  lane_count: 1,
323
434
  ledger_root: path.relative(root, ledgerRoot)
324
435
  };
@@ -381,6 +492,9 @@ export async function startMadNativeSwarm(root, madLaunch, args = [], profile =
381
492
  zellij_session_name: opts.zellijSessionName || null,
382
493
  worker_placement: opts.workerPlacement || (swarm.backend === 'zellij' ? 'zellij-pane' : 'process'),
383
494
  zellij_visible_pane_cap: opts.zellijVisiblePaneCap || null,
495
+ model_provider: opts.glmLaunch?.provider || null,
496
+ model: opts.glmLaunch?.model || null,
497
+ gpt_fallback_allowed: opts.glmLaunch ? false : null,
384
498
  readonly: true,
385
499
  command,
386
500
  stdout_log: path.relative(root, stdoutLog),
@@ -430,13 +544,18 @@ export async function startMadNativeSwarm(root, madLaunch, args = [], profile =
430
544
  }
431
545
  export function resolveMadNativeSwarmOptions(args = [], profile = {}, opts = {}) {
432
546
  const list = (args || []).map((arg) => String(arg));
433
- const disabled = list.includes('--no-swarm') || list.includes('--no-mad-swarm') || process.env.SKS_MAD_NATIVE_SWARM === '0';
547
+ const operatorDisabled = list.includes('--no-swarm') || list.includes('--no-mad-swarm') || process.env.SKS_MAD_NATIVE_SWARM === '0';
548
+ const glmRequested = list.includes('--glm') || opts.glmLaunch?.provider === 'openrouter';
549
+ const glmNativeSwarmDisabled = glmRequested && process.env.SKS_GLM_MAD_ALLOW_GPT_SWARM !== '1';
550
+ const disabled = operatorDisabled || glmNativeSwarmDisabled;
434
551
  const agents = clampInt(readOption(list, '--mad-agents', readOption(list, '--mad-swarm-agents', process.env.SKS_MAD_SWARM_AGENTS || opts.agents || 5)), 1, 20);
435
552
  const workItems = clampInt(readOption(list, '--mad-swarm-work-items', process.env.SKS_MAD_SWARM_WORK_ITEMS || opts.workItems || agents), agents, 100);
436
553
  const backend = defaultMadSwarmBackend(list, opts);
437
554
  return {
438
555
  enabled: !disabled,
439
- disabled_reason: disabled ? 'operator_disabled_mad_native_swarm' : null,
556
+ disabled_reason: operatorDisabled
557
+ ? 'operator_disabled_mad_native_swarm'
558
+ : glmNativeSwarmDisabled ? 'glm_mad_native_swarm_disabled_to_block_gpt_fallback' : null,
440
559
  agents,
441
560
  workItems,
442
561
  backend,
@@ -516,12 +635,14 @@ async function activateMadZellijPermissionState(cwd = process.cwd(), args = [])
516
635
  const root = await sksRoot();
517
636
  if (!(await exists(path.join(root, '.sneakoscope'))))
518
637
  await initProject(root, {});
638
+ const rawArgs = (args || []).map((arg) => String(arg));
639
+ const activatedBy = rawArgs.includes('--glm') ? 'sks --mad --glm' : 'sks --mad';
519
640
  const flags = parseMadSksFlags(['--mad-sks', ...args].filter(Boolean));
520
- const permission = buildMadSksPermissionModel({ targetRoot: cwd, userIntent: 'sks --mad Zellij scoped high-power maintenance session', flags });
641
+ const permission = buildMadSksPermissionModel({ targetRoot: cwd, userIntent: `${activatedBy} Zellij scoped high-power maintenance session`, flags });
521
642
  const allowedScopes = new Set(permission.allowed_scopes || []);
522
643
  const has = (scope) => allowedScopes.has(scope);
523
644
  const dbWriteAllowed = has('db_write');
524
- const { id, dir } = await createMission(root, { mode: 'mad-sks', prompt: 'sks --mad Zellij scoped high-power maintenance session' });
645
+ const { id, dir } = await createMission(root, { mode: 'mad-sks', prompt: `${activatedBy} Zellij scoped high-power maintenance session` });
525
646
  await writeCodex0138CapabilityArtifacts(root, { missionId: id }).catch(() => null);
526
647
  await writeCodex0139CapabilityArtifacts(root, { missionId: id }).catch(() => null);
527
648
  const codexNativeInvocation = await resolveCodexNativeInvocationPlan({
@@ -582,7 +703,7 @@ async function activateMadZellijPermissionState(cwd = process.cwd(), args = [])
582
703
  warnings: codexNativeInvocation.warnings,
583
704
  artifact_path: 'mad-codex-native-invocation.json'
584
705
  } : null,
585
- activated_by: 'sks --mad',
706
+ activated_by: activatedBy,
586
707
  cwd: path.resolve(cwd || process.cwd())
587
708
  };
588
709
  await writeJsonAtomic(path.join(dir, 'mad-sks-gate.json'), gate);
@@ -616,11 +737,12 @@ async function activateMadZellijPermissionState(cwd = process.cwd(), args = [])
616
737
  });
617
738
  return { mission_id: id, dir, gate, root };
618
739
  }
619
- function madLaunchOnlyFlags() {
740
+ function baseMadLaunchOnlyFlags() {
620
741
  return new Set([
621
742
  '--mad',
622
743
  '--MAD',
623
744
  '--mad-sks',
745
+ '--glm',
624
746
  '--high',
625
747
  '--attach',
626
748
  '--no-attach',
@@ -662,8 +784,26 @@ function madLaunchOnlyFlags() {
662
784
  '--ack'
663
785
  ]);
664
786
  }
665
- function madLaunchValueFlags() {
787
+ function glmMadLaunchOnlyFlags() {
666
788
  return new Set([
789
+ '--deep',
790
+ '--xhigh',
791
+ '--strict',
792
+ '--trace',
793
+ '--ttft',
794
+ '--exact-provider'
795
+ ]);
796
+ }
797
+ function madLaunchOnlyFlags(includeGlmFlags = false) {
798
+ const flags = baseMadLaunchOnlyFlags();
799
+ if (includeGlmFlags) {
800
+ for (const flag of glmMadLaunchOnlyFlags())
801
+ flags.add(flag);
802
+ }
803
+ return flags;
804
+ }
805
+ function madLaunchValueFlags(includeGlmFlags = false) {
806
+ const flags = new Set([
667
807
  '--mad-agents',
668
808
  '--mad-swarm-agents',
669
809
  '--mad-swarm-work-items',
@@ -671,6 +811,20 @@ function madLaunchValueFlags() {
671
811
  '--mad-swarm-prompt',
672
812
  '--ack'
673
813
  ]);
814
+ if (includeGlmFlags)
815
+ flags.add('--exact-provider');
816
+ return flags;
817
+ }
818
+ export function findGlmOnlyMadFlagBlockers(args = [], glmMadLaunch = false) {
819
+ if (glmMadLaunch)
820
+ return [];
821
+ const blockers = [];
822
+ const glmOnly = new Set([...glmMadLaunchOnlyFlags(), '--bench']);
823
+ for (const arg of args) {
824
+ if (glmOnly.has(String(arg)))
825
+ blockers.push(`glm_flag_requires_--glm:${arg}`);
826
+ }
827
+ return blockers;
674
828
  }
675
829
  export function defaultMadSwarmBackend(args = [], opts = {}) {
676
830
  const list = (args || []).map((arg) => String(arg));
@@ -687,9 +841,9 @@ export function defaultMadSwarmBackend(args = [], opts = {}) {
687
841
  return 'codex-sdk';
688
842
  return 'zellij';
689
843
  }
690
- function stripMadLaunchOnlyArgs(args = []) {
691
- const flags = madLaunchOnlyFlags();
692
- const valueFlags = madLaunchValueFlags();
844
+ export function stripMadLaunchOnlyArgs(args = [], opts = {}) {
845
+ const flags = madLaunchOnlyFlags(Boolean(opts.includeGlmFlags));
846
+ const valueFlags = madLaunchValueFlags(Boolean(opts.includeGlmFlags));
693
847
  const out = [];
694
848
  for (let i = 0; i < args.length; i += 1) {
695
849
  const arg = String(args[i]);
package/dist/core/fsx.js CHANGED
@@ -5,7 +5,7 @@ import os from 'node:os';
5
5
  import crypto from 'node:crypto';
6
6
  import { spawn } from 'node:child_process';
7
7
  import { fileURLToPath } from 'node:url';
8
- export const PACKAGE_VERSION = '4.0.3';
8
+ export const PACKAGE_VERSION = '4.0.5';
9
9
  export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
10
10
  export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
11
11
  export function nowIso() {
@@ -0,0 +1,33 @@
1
+ export class SksLruCache {
2
+ maxEntries;
3
+ map = new Map();
4
+ constructor(maxEntries = 128) {
5
+ this.maxEntries = Math.max(1, Math.floor(maxEntries));
6
+ }
7
+ get size() {
8
+ return this.map.size;
9
+ }
10
+ get(key) {
11
+ const entry = this.map.get(key);
12
+ if (!entry)
13
+ return null;
14
+ this.map.delete(key);
15
+ this.map.set(key, entry);
16
+ return entry.value;
17
+ }
18
+ set(key, value, createdAt = Date.now()) {
19
+ if (this.map.has(key))
20
+ this.map.delete(key);
21
+ this.map.set(key, { key, value, createdAt });
22
+ while (this.map.size > this.maxEntries) {
23
+ const oldest = this.map.keys().next().value;
24
+ if (!oldest)
25
+ break;
26
+ this.map.delete(oldest);
27
+ }
28
+ }
29
+ clear() {
30
+ this.map.clear();
31
+ }
32
+ }
33
+ //# sourceMappingURL=lru-cache.js.map
@@ -1,7 +1,9 @@
1
- import { GLM_52_DEFAULT_REQUEST_SETTINGS, GLM_52_OPENROUTER_MODEL, GLM_MAD_MODE } from './glm-52-settings.js';
1
+ import { GLM_52_OPENROUTER_MODEL, GLM_MAD_MODE } from './glm-52-settings.js';
2
+ import { profileFromConst } from './glm-profile-resolver.js';
2
3
  export const GLM_CODEX_APP_PROFILE_ID = 'sks/glm-5.2-mad';
3
- export const GLM_CODEX_APP_PROFILE_LABEL = 'GLM 5.2 (MAD / OpenRouter)';
4
+ export const GLM_CODEX_APP_PROFILE_LABEL = 'GLM 5.2 (MAD XHigh Speed / OpenRouter)';
4
5
  export function buildGlmCodexAppModelProfile() {
6
+ const speed = profileFromConst('speed');
5
7
  return {
6
8
  schema: 'sks.codex-app-model-profile.v1',
7
9
  id: GLM_CODEX_APP_PROFILE_ID,
@@ -12,12 +14,17 @@ export function buildGlmCodexAppModelProfile() {
12
14
  strictModelLock: true,
13
15
  gptFallbackAllowed: false,
14
16
  requiresSecret: 'openrouter-api-key',
17
+ defaultProfile: 'speed',
15
18
  defaultSettings: {
16
- temperature: GLM_52_DEFAULT_REQUEST_SETTINGS.temperature,
17
- top_p: GLM_52_DEFAULT_REQUEST_SETTINGS.top_p,
18
- reasoning_effort: 'high',
19
- tool_choice: 'auto',
20
- parallel_tool_calls: false
19
+ temperature: speed.temperature,
20
+ top_p: speed.top_p,
21
+ reasoning_effort: 'xhigh',
22
+ tool_choice: speed.tool_choice,
23
+ parallel_tool_calls: speed.parallel_tool_calls,
24
+ max_tokens: speed.max_tokens,
25
+ provider_sort: speed.provider.sort || 'throughput',
26
+ provider_allow_fallbacks: false,
27
+ provider_require_parameters: speed.provider.require_parameters
21
28
  },
22
29
  codexCompatibility: {
23
30
  target: 'rust-v0.141.0',
@@ -1,34 +1,62 @@
1
1
  import { GLM_52_DEFAULT_REQUEST_SETTINGS, GLM_52_OPENROUTER_MODEL, clampGlm52MaxTokens } from './glm-52-settings.js';
2
+ import { buildDeepReasoningConfig } from './glm-reasoning-policy.js';
3
+ import { profileFromConst, resolveGlmProfileFromArgs } from './glm-profile-resolver.js';
2
4
  export function buildGlm52Request(input) {
5
+ const profile = resolveInputProfile(input.profile, input.args, input.reasoningEffort);
6
+ if (profile.blockers.length) {
7
+ throw new Error(`GLM request profile blocked: ${profile.blockers.join(', ')}`);
8
+ }
9
+ const strictOrDeepEffort = profile.reasoning_effort || (input.reasoningEffort === 'high' || input.reasoningEffort === 'xhigh' ? input.reasoningEffort : undefined);
10
+ const reasoning = profile.name === 'speed'
11
+ ? buildDeepReasoningConfig('xhigh')
12
+ : buildDeepReasoningConfig(strictOrDeepEffort || 'high');
3
13
  const request = {
4
14
  model: GLM_52_OPENROUTER_MODEL,
5
15
  messages: input.messages,
6
- stream: input.stream ?? GLM_52_DEFAULT_REQUEST_SETTINGS.stream,
7
- temperature: GLM_52_DEFAULT_REQUEST_SETTINGS.temperature,
8
- top_p: GLM_52_DEFAULT_REQUEST_SETTINGS.top_p,
9
- reasoning: { effort: input.reasoningEffort ?? 'high' },
10
- max_tokens: clampGlm52MaxTokens(input.maxTokens),
11
- tool_choice: input.toolChoice ?? 'auto',
12
- parallel_tool_calls: input.parallelToolCalls ?? false,
16
+ stream: input.stream ?? profile.stream,
17
+ temperature: profile.temperature,
18
+ top_p: profile.top_p,
19
+ ...(reasoning ? { reasoning } : {}),
20
+ max_tokens: clampGlm52MaxTokens(input.maxTokens ?? profile.max_tokens),
21
+ tool_choice: input.toolChoice ?? profile.tool_choice,
22
+ parallel_tool_calls: input.parallelToolCalls ?? profile.parallel_tool_calls,
23
+ ...(profile.stop && profile.name === 'speed' ? { stop: profile.stop } : {}),
13
24
  provider: {
14
25
  allow_fallbacks: false,
15
- require_parameters: true,
16
- sort: input.providerSort ?? 'throughput'
17
- }
26
+ require_parameters: profile.provider.require_parameters,
27
+ ...(profile.provider.sort || input.providerSort ? { sort: input.providerSort ?? profile.provider.sort } : {}),
28
+ ...(profile.provider.preferred_min_throughput ? { preferred_min_throughput: profile.provider.preferred_min_throughput } : {}),
29
+ ...(profile.provider.preferred_max_latency ? { preferred_max_latency: profile.provider.preferred_max_latency } : {}),
30
+ ...(profile.provider.order ? { order: profile.provider.order } : {})
31
+ },
32
+ ...(input.responseFormat || profile.response_format ? { response_format: input.responseFormat ?? profile.response_format } : {})
18
33
  };
19
34
  return {
20
35
  ...request,
21
- ...(input.tools ? { tools: input.tools } : {}),
22
- ...(input.responseFormat ? { response_format: input.responseFormat } : {})
36
+ ...(input.tools && request.tool_choice !== 'none' ? { tools: input.tools } : {})
23
37
  };
24
38
  }
25
39
  export function buildGlm52KeyValidationRequest() {
26
40
  return buildGlm52Request({
27
41
  messages: [{ role: 'user', content: 'Reply with OK.' }],
42
+ profile: 'speed',
28
43
  stream: false,
29
44
  maxTokens: 1,
30
45
  toolChoice: 'none',
31
46
  parallelToolCalls: false
32
47
  });
33
48
  }
49
+ function resolveInputProfile(profile, args, reasoningEffort) {
50
+ if (profile && typeof profile === 'object')
51
+ return profile;
52
+ if (profile)
53
+ return profileFromConst(profile);
54
+ if (args)
55
+ return resolveGlmProfileFromArgs(args);
56
+ if (reasoningEffort === 'xhigh')
57
+ return profileFromConst('xhigh');
58
+ if (reasoningEffort === 'high')
59
+ return profileFromConst('deep');
60
+ return profileFromConst(GLM_52_DEFAULT_REQUEST_SETTINGS.mode === 'mad-glm-speed' ? 'speed' : 'speed');
61
+ }
34
62
  //# sourceMappingURL=glm-52-request.js.map
@@ -11,8 +11,7 @@ export function assertGlm52ActualModel(responseModel) {
11
11
  }
12
12
  const normalized = responseModel.toLowerCase();
13
13
  if (normalized === GLM_52_OPENROUTER_MODEL ||
14
- normalized.startsWith(`${GLM_52_OPENROUTER_MODEL}-`) ||
15
- normalized.includes('glm-5.2')) {
14
+ normalized.startsWith(`${GLM_52_OPENROUTER_MODEL}-`)) {
16
15
  return {
17
16
  ok: true,
18
17
  code: 'ok',