sneakoscope 1.21.3 → 1.21.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/.sks-build-stamp.json +3 -3
- package/dist/bin/sks.js +1 -1
- package/dist/build-manifest.json +3 -3
- package/dist/core/agents/agent-roster.d.ts +5 -0
- package/dist/core/agents/agent-roster.js +33 -7
- package/dist/core/agents/zellij-right-lane-cockpit.js +1 -1
- package/dist/core/commands/naruto-command.js +42 -21
- package/dist/core/fsx.d.ts +1 -1
- package/dist/core/fsx.js +1 -1
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-lane-renderer.js +33 -3
- package/dist/core/zellij/zellij-layout-builder.js +10 -2
- package/dist/scripts/release-parallel-check.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Set up this agent project with Sneakoscope Codex. Use [[mandarange/Sneakoscope-C
|
|
|
16
16
|
|
|
17
17
|
## Current Release
|
|
18
18
|
|
|
19
|
-
SKS **1.21.
|
|
19
|
+
SKS **1.21.4** makes Fast mode state and Naruto clone activity directly visible in SKS Zellij lanes. The lane renderer now resolves the project-local `sks fast-mode on|off` preference even before worker scheduler artifacts arrive, and Naruto launches the right-side Zellij lane stack before clone scheduling starts so each clone slot can show live activity. Naruto's host-capacity model also no longer collapses `codex-exec` concurrency to one slot on capable Macs just because `freemem` is low; use `--concurrency` / `--target-active-slots` or `SKS_NARUTO_MAX_CONCURRENCY` for explicit operator control. SKS-launched interactive Codex panes also use `--no-alt-screen` by default so Mac trackpad/wheel gestures scroll the terminal conversation history instead of the prompt textarea/history; set `SKS_ZELLIJ_CODEX_ALT_SCREEN=1` before launch to opt back into alternate-screen mode. It carries forward the 1.21.3 Zellij clipboard, visual lane count, direct-publish stamp repair, and Codex Fast mode repair fixes.
|
|
20
20
|
|
|
21
21
|
SKS **1.20.4** is a targeted `sks --mad` / codex-lb Zellij usability patch: when a background MAD Zellij session launches successfully, SKS now prints the exact `Attach with: ZELLIJ_SOCKET_DIR=... zellij attach ...` command so operators can enter the fresh session without manually reconstructing the socket namespace.
|
|
22
22
|
|
|
@@ -341,7 +341,7 @@ sks team open-zellij latest
|
|
|
341
341
|
sks team attach-zellij latest
|
|
342
342
|
```
|
|
343
343
|
|
|
344
|
-
Interactive SKS sessions use Zellij layouts. By default SKS launches Codex in Fast service tier with `--model gpt-5.5`, `-c service_tier="fast"`,
|
|
344
|
+
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.
|
|
345
345
|
|
|
346
346
|
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.
|
|
347
347
|
|
|
@@ -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 1.21.
|
|
7
|
+
Some("--version") => println!("sks-rs 1.21.4"),
|
|
8
8
|
Some("compact-info") => {
|
|
9
9
|
let mut input = String::new();
|
|
10
10
|
let _ = io::stdin().read_to_string(&mut input);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "sks.dist-build-stamp.v1",
|
|
3
3
|
"package_name": "sneakoscope",
|
|
4
|
-
"package_version": "1.21.
|
|
5
|
-
"source_digest": "
|
|
4
|
+
"package_version": "1.21.4",
|
|
5
|
+
"source_digest": "70780332db02a19044731adecdb06abcf7d9efdc8b128627be712ca33b3c6881",
|
|
6
6
|
"source_file_count": 1755,
|
|
7
|
-
"built_at_source_time":
|
|
7
|
+
"built_at_source_time": 1780318491834
|
|
8
8
|
}
|
package/dist/bin/sks.js
CHANGED
package/dist/build-manifest.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "sks.dist-build.v2",
|
|
3
|
-
"version": "1.21.
|
|
4
|
-
"package_version": "1.21.
|
|
3
|
+
"version": "1.21.4",
|
|
4
|
+
"package_version": "1.21.4",
|
|
5
5
|
"typescript": true,
|
|
6
6
|
"mjs_runtime_files": 0,
|
|
7
7
|
"compiled_file_count": 1022,
|
|
8
8
|
"compiled_js_count": 511,
|
|
9
9
|
"compiled_dts_count": 511,
|
|
10
|
-
"source_digest": "
|
|
10
|
+
"source_digest": "70780332db02a19044731adecdb06abcf7d9efdc8b128627be712ca33b3c6881",
|
|
11
11
|
"source_file_count": 1755,
|
|
12
12
|
"source_files_hash": "e6487058a1a0894c6b8a629b64319d45be1ad9a0658ab422a39969c1e39ad7e3",
|
|
13
13
|
"source_list_hash": "e6487058a1a0894c6b8a629b64319d45be1ad9a0658ab422a39969c1e39ad7e3",
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import type { AgentPersona, AgentRosterEntry } from './agent-schema.js';
|
|
2
2
|
export declare function systemSafeNarutoConcurrency(opts?: {
|
|
3
3
|
backend?: string;
|
|
4
|
+
cores?: number;
|
|
5
|
+
freeBytes?: number;
|
|
6
|
+
totalBytes?: number;
|
|
4
7
|
}): {
|
|
5
8
|
cap: number;
|
|
6
9
|
cores: number;
|
|
7
10
|
free_gb: number;
|
|
11
|
+
total_gb: number;
|
|
8
12
|
backend: string;
|
|
9
13
|
heavy: boolean;
|
|
10
14
|
override_applied: boolean;
|
|
15
|
+
memory_model: string;
|
|
11
16
|
};
|
|
12
17
|
export declare function normalizeAgentCount(value: unknown, fallback?: number, maxAgentCount?: number): number;
|
|
13
18
|
export declare function normalizeAgentConcurrency(value: unknown, agents: number, maxAgentCount?: number): number;
|
|
@@ -7,22 +7,35 @@ import { buildAgentEffortPolicy, decideAgentEffort, decideNarutoCloneEffort } fr
|
|
|
7
7
|
// host can safely sustain — derived from CPU cores and free memory, heavier-bounded for
|
|
8
8
|
// real child-process backends (codex-exec/zellij/process) than for in-process (fake).
|
|
9
9
|
export function systemSafeNarutoConcurrency(opts = {}) {
|
|
10
|
-
const cores = Math.max(1, Number(os.cpus()?.length) || 4);
|
|
10
|
+
const cores = Math.max(1, Number(opts.cores ?? os.cpus()?.length) || 4);
|
|
11
11
|
let freeBytes = 2 * 1024 * 1024 * 1024;
|
|
12
|
+
let totalBytes = 8 * 1024 * 1024 * 1024;
|
|
12
13
|
try {
|
|
13
|
-
freeBytes = os.freemem() || freeBytes;
|
|
14
|
+
freeBytes = Number(opts.freeBytes ?? os.freemem()) || freeBytes;
|
|
15
|
+
}
|
|
16
|
+
catch { /* keep fallback */ }
|
|
17
|
+
try {
|
|
18
|
+
totalBytes = Number(opts.totalBytes ?? os.totalmem()) || totalBytes;
|
|
14
19
|
}
|
|
15
20
|
catch { /* keep fallback */ }
|
|
16
21
|
const freeGb = freeBytes / (1024 * 1024 * 1024);
|
|
22
|
+
const totalGb = totalBytes / (1024 * 1024 * 1024);
|
|
17
23
|
const backend = String(opts.backend || 'codex-exec');
|
|
18
24
|
const heavy = backend === 'codex-exec' || backend === 'zellij' || backend === 'process';
|
|
19
25
|
let cap;
|
|
20
26
|
if (heavy) {
|
|
21
|
-
// Real codex children are
|
|
22
|
-
//
|
|
27
|
+
// Real codex children are heavier than fake workers, but macOS can report
|
|
28
|
+
// very low freemem while reclaimable memory is still available. Use a
|
|
29
|
+
// conservative total-memory floor so Naruto keeps meaningful parallelism
|
|
30
|
+
// instead of collapsing to one slot on otherwise capable machines.
|
|
23
31
|
const byCpu = Math.max(1, cores - 1);
|
|
24
|
-
const
|
|
25
|
-
|
|
32
|
+
const gbPerWorker = positiveEnvNumber('SKS_NARUTO_GB_PER_WORKER', 0.6);
|
|
33
|
+
const reclaimableFloorGb = totalGb >= 16 ? 6 : totalGb >= 8 ? 3 : totalGb >= 4 ? 1.5 : freeGb;
|
|
34
|
+
const budgetGb = Math.max(freeGb, reclaimableFloorGb);
|
|
35
|
+
const byMem = Math.max(1, Math.floor(budgetGb / gbPerWorker));
|
|
36
|
+
const minParallelDefault = totalGb >= 16 ? 8 : totalGb >= 8 ? 4 : totalGb >= 4 ? 2 : 1;
|
|
37
|
+
const minParallel = Math.min(byCpu, Math.floor(positiveEnvNumber('SKS_NARUTO_MIN_CONCURRENCY', minParallelDefault)));
|
|
38
|
+
cap = Math.min(byCpu, Math.max(byMem, minParallel), 16);
|
|
26
39
|
}
|
|
27
40
|
else {
|
|
28
41
|
// In-process / light workers can pack tighter.
|
|
@@ -32,7 +45,20 @@ export function systemSafeNarutoConcurrency(opts = {}) {
|
|
|
32
45
|
if (Number.isFinite(override) && override >= 1)
|
|
33
46
|
cap = Math.min(Math.floor(override), MAX_NARUTO_AGENT_COUNT);
|
|
34
47
|
cap = Math.max(1, Math.min(cap, MAX_NARUTO_AGENT_COUNT));
|
|
35
|
-
return {
|
|
48
|
+
return {
|
|
49
|
+
cap,
|
|
50
|
+
cores,
|
|
51
|
+
free_gb: Math.round(freeGb * 10) / 10,
|
|
52
|
+
total_gb: Math.round(totalGb * 10) / 10,
|
|
53
|
+
backend,
|
|
54
|
+
heavy,
|
|
55
|
+
override_applied: Number.isFinite(override) && override >= 1,
|
|
56
|
+
memory_model: heavy ? 'free_or_reclaimable_floor' : 'light_worker_cpu_bound'
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function positiveEnvNumber(name, fallback) {
|
|
60
|
+
const parsed = Number(process.env[name]);
|
|
61
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
36
62
|
}
|
|
37
63
|
function resolveMaxAgentCount(value) {
|
|
38
64
|
const parsed = Number(value);
|
|
@@ -4,7 +4,7 @@ export const ZELLIJ_RIGHT_LANE_LAYOUT_SCHEMA = 'sks.agent-zellij-right-lane-layo
|
|
|
4
4
|
export const ZELLIJ_RIGHT_LANES_SCHEMA = 'sks.agent-zellij-right-lanes.v1';
|
|
5
5
|
export function buildZellijRightLaneCockpit(input = {}) {
|
|
6
6
|
const agents = input.slots || input.agents || [];
|
|
7
|
-
const maxVisible = input.maxVisibleLanes ||
|
|
7
|
+
const maxVisible = input.maxVisibleLanes || Math.max(agents.length, 1);
|
|
8
8
|
const lanes = agents.map((agent, index) => ({
|
|
9
9
|
lane_index: index + 1,
|
|
10
10
|
slot_id: String(agent.slot_id || agent.id || agent.agent_id || `slot-${String(index + 1).padStart(3, '0')}`),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { findLatestMission, loadMission } from '../mission.js';
|
|
2
|
+
import { createMission, findLatestMission, loadMission } from '../mission.js';
|
|
3
3
|
import { readJson, sksRoot } from '../fsx.js';
|
|
4
4
|
import { runNativeAgentOrchestrator } from '../agents/agent-orchestrator.js';
|
|
5
5
|
import { buildNarutoCloneRoster, systemSafeNarutoConcurrency } from '../agents/agent-roster.js';
|
|
@@ -30,10 +30,37 @@ async function narutoRun(parsed) {
|
|
|
30
30
|
maxAgentCount: MAX_NARUTO_AGENT_COUNT
|
|
31
31
|
});
|
|
32
32
|
// The clone roster is the full work fan-out; live concurrency is throttled to a
|
|
33
|
-
// system-safe number so naruto never spawns the whole count at once
|
|
33
|
+
// system-safe number so naruto never spawns the whole count at once unless an
|
|
34
|
+
// explicit operator override asks for a higher target.
|
|
34
35
|
const safe = systemSafeNarutoConcurrency({ backend: parsed.backend });
|
|
35
|
-
const activeSlots = Math.max(1, Math.min(roster.agent_count, safe.cap));
|
|
36
|
+
const activeSlots = Math.max(1, Math.min(roster.agent_count, parsed.concurrency || safe.cap));
|
|
37
|
+
const mission = await createMission(root, { mode: 'naruto', prompt: parsed.prompt });
|
|
38
|
+
const ledgerRoot = path.join(mission.dir, 'agents');
|
|
39
|
+
let liveZellij = null;
|
|
40
|
+
if (!parsed.json && !parsed.mock && !parsed.noOpenZellij) {
|
|
41
|
+
liveZellij = await launchZellijLayout({
|
|
42
|
+
root,
|
|
43
|
+
missionId: mission.id,
|
|
44
|
+
ledgerRoot,
|
|
45
|
+
kind: 'naruto',
|
|
46
|
+
slotCount: roster.agent_count,
|
|
47
|
+
dryRun: false,
|
|
48
|
+
attach: false
|
|
49
|
+
});
|
|
50
|
+
if (liveZellij?.ok && liveZellij.capability?.status === 'ok') {
|
|
51
|
+
console.log('Zellij: prepared ' + roster.agent_count + ' live clone lane(s) in ' + liveZellij.session_name + '. Attach with: ' + (liveZellij.attach_command_with_env || liveZellij.attach_command));
|
|
52
|
+
if (parsed.attach)
|
|
53
|
+
attachZellijSessionInteractive(liveZellij.session_name, { cwd: process.cwd(), configPath: liveZellij.clipboard_config_path });
|
|
54
|
+
}
|
|
55
|
+
else if (liveZellij?.ok) {
|
|
56
|
+
console.log('Zellij: optional live panes unavailable (' + ((liveZellij.warnings || []).join('; ') || liveZellij.capability?.status || 'unknown') + ')');
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.log('Zellij: blocked (' + Array.from(new Set(liveZellij?.blockers || [])).join('; ') + ')');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
36
62
|
const result = await runNativeAgentOrchestrator({
|
|
63
|
+
missionId: mission.id,
|
|
37
64
|
prompt: parsed.prompt,
|
|
38
65
|
route: NARUTO_ROUTE,
|
|
39
66
|
routeCommand: 'sks naruto run',
|
|
@@ -76,22 +103,7 @@ async function narutoRun(parsed) {
|
|
|
76
103
|
run: result,
|
|
77
104
|
zellij: null
|
|
78
105
|
};
|
|
79
|
-
|
|
80
|
-
const ledgerRoot = result.ledger_root
|
|
81
|
-
? path.join(root, result.ledger_root)
|
|
82
|
-
: path.join(root, '.sneakoscope', 'missions', result.mission_id, 'agents');
|
|
83
|
-
summary.zellij = await launchZellijLayout({
|
|
84
|
-
root,
|
|
85
|
-
missionId: result.mission_id,
|
|
86
|
-
ledgerRoot,
|
|
87
|
-
kind: 'naruto',
|
|
88
|
-
slotCount: summary.clones,
|
|
89
|
-
dryRun: false,
|
|
90
|
-
attach: false
|
|
91
|
-
});
|
|
92
|
-
if (summary.zellij?.ok && summary.zellij.capability?.status === 'ok' && parsed.attach)
|
|
93
|
-
attachZellijSessionInteractive(summary.zellij.session_name, { cwd: process.cwd() });
|
|
94
|
-
}
|
|
106
|
+
summary.zellij = liveZellij;
|
|
95
107
|
return emit(parsed, summary, () => {
|
|
96
108
|
console.log('🍥 Shadow Clone Jutsu — Kage Bunshin no Jutsu');
|
|
97
109
|
console.log('Mission: ' + result.mission_id);
|
|
@@ -158,6 +170,7 @@ function parseNarutoArgs(args = []) {
|
|
|
158
170
|
const requestedClones = Number(readOption(args, '--clones', readOption(args, '--agents', DEFAULT_NARUTO_CLONES)));
|
|
159
171
|
const clones = clampClones(requestedClones);
|
|
160
172
|
const workItems = clampWorkItems(Number(readOption(args, '--work-items', clones)), clones);
|
|
173
|
+
const concurrency = normalizeConcurrency(readOption(args, '--concurrency', readOption(args, '--target-active-slots', null)), clones);
|
|
161
174
|
const backend = String(readOption(args, '--backend', hasFlag(args, '--mock') ? 'fake' : 'codex-exec'));
|
|
162
175
|
const mock = hasFlag(args, '--mock') || backend === 'fake';
|
|
163
176
|
const real = hasFlag(args, '--real');
|
|
@@ -167,9 +180,9 @@ function parseNarutoArgs(args = []) {
|
|
|
167
180
|
const missionId = String(readOption(args, '--mission', readOption(args, '--mission-id', 'latest')));
|
|
168
181
|
const noOpenZellij = hasFlag(args, '--no-open-zellij') || hasFlag(args, '--no-zellij');
|
|
169
182
|
const attach = hasFlag(args, '--attach');
|
|
170
|
-
const valueFlags = new Set(['--clones', '--agents', '--work-items', '--backend', '--write-mode', '--mission', '--mission-id']);
|
|
183
|
+
const valueFlags = new Set(['--clones', '--agents', '--work-items', '--concurrency', '--target-active-slots', '--backend', '--write-mode', '--mission', '--mission-id']);
|
|
171
184
|
const prompt = positionalArgs(rest, valueFlags).join(' ').trim() || 'Naruto shadow clone swarm run';
|
|
172
|
-
return { action, prompt, clones, workItems, backend, mock, real, readonly, writeMode, json, missionId, noOpenZellij, attach };
|
|
185
|
+
return { action, prompt, clones, workItems, concurrency, backend, mock, real, readonly, writeMode, json, missionId, noOpenZellij, attach };
|
|
173
186
|
}
|
|
174
187
|
function clampClones(value) {
|
|
175
188
|
if (!Number.isFinite(value) || value < 1)
|
|
@@ -181,6 +194,14 @@ function clampWorkItems(value, clones) {
|
|
|
181
194
|
return clones;
|
|
182
195
|
return Math.floor(value);
|
|
183
196
|
}
|
|
197
|
+
function normalizeConcurrency(value, clones) {
|
|
198
|
+
if (value == null || value === '')
|
|
199
|
+
return null;
|
|
200
|
+
const parsed = Number(value);
|
|
201
|
+
if (!Number.isFinite(parsed) || parsed < 1)
|
|
202
|
+
return null;
|
|
203
|
+
return Math.min(Math.floor(parsed), clones, MAX_NARUTO_AGENT_COUNT);
|
|
204
|
+
}
|
|
184
205
|
function hasFlag(args, flag) {
|
|
185
206
|
return args.includes(flag);
|
|
186
207
|
}
|
package/dist/core/fsx.d.ts
CHANGED
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 = '1.21.
|
|
8
|
+
export const PACKAGE_VERSION = '1.21.4';
|
|
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() {
|
package/dist/core/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "1.21.
|
|
1
|
+
export declare const PACKAGE_VERSION = "1.21.4";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '1.21.
|
|
1
|
+
export const PACKAGE_VERSION = '1.21.4';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { appendJsonl, ensureDir, exists, nowIso, readJson, readText, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
|
|
3
|
+
import { resolveFastModePolicy } from '../agents/fast-mode-policy.js';
|
|
3
4
|
export const ZELLIJ_LANE_RENDER_SCHEMA = 'sks.zellij-lane-render.v1';
|
|
4
5
|
// Default render width. Zellij panes are commonly 80/100/120 columns; the frame
|
|
5
6
|
// must stay readable (no wraps, no overflow) across that range.
|
|
@@ -289,11 +290,25 @@ async function buildLaneDashboard(root, slot, laneJson) {
|
|
|
289
290
|
swarm?.mode
|
|
290
291
|
]) || 'Agent';
|
|
291
292
|
// Fast service tier.
|
|
292
|
-
const
|
|
293
|
-
const
|
|
293
|
+
const projectRoot = inferProjectRootFromLedgerRoot(root);
|
|
294
|
+
const policy = resolveFastModePolicy({ root: projectRoot });
|
|
295
|
+
const serviceTier = firstString([
|
|
296
|
+
laneJson?.service_tier,
|
|
297
|
+
scheduler?.service_tier,
|
|
298
|
+
swarm?.service_tier,
|
|
299
|
+
proof?.fast_mode_policy?.service_tier,
|
|
300
|
+
policy.service_tier
|
|
301
|
+
]);
|
|
302
|
+
const fastMode = firstDefined([
|
|
303
|
+
laneJson?.fast_mode,
|
|
304
|
+
scheduler?.fast_mode,
|
|
305
|
+
swarm?.fast_mode,
|
|
306
|
+
proof?.fast_mode_policy?.fast_mode,
|
|
307
|
+
policy.fast_mode
|
|
308
|
+
]);
|
|
294
309
|
const fast = serviceTier === 'fast' || fastMode === true
|
|
295
310
|
? `on · service_tier=${serviceTier || 'fast'}`
|
|
296
|
-
:
|
|
311
|
+
: `off · service_tier=${serviceTier || 'standard'}`;
|
|
297
312
|
// Workers: live active/target + (naruto) clone fan-out.
|
|
298
313
|
const cloneTotal = numberOf([scheduler?.clones, scheduler?.clone_count, swarm?.clones]);
|
|
299
314
|
const cloneActive = numberOf([scheduler?.active_clone, scheduler?.active_slot_count]);
|
|
@@ -358,6 +373,21 @@ function firstString(values) {
|
|
|
358
373
|
}
|
|
359
374
|
return null;
|
|
360
375
|
}
|
|
376
|
+
function firstDefined(values) {
|
|
377
|
+
for (const value of values.flat()) {
|
|
378
|
+
if (value !== undefined && value !== null)
|
|
379
|
+
return value;
|
|
380
|
+
}
|
|
381
|
+
return undefined;
|
|
382
|
+
}
|
|
383
|
+
function inferProjectRootFromLedgerRoot(value) {
|
|
384
|
+
const root = path.resolve(value);
|
|
385
|
+
const parts = root.split(path.sep);
|
|
386
|
+
const index = parts.lastIndexOf('.sneakoscope');
|
|
387
|
+
if (index > 0)
|
|
388
|
+
return parts.slice(0, index).join(path.sep) || path.sep;
|
|
389
|
+
return root;
|
|
390
|
+
}
|
|
361
391
|
function numberOf(values) {
|
|
362
392
|
for (const value of values) {
|
|
363
393
|
const n = Number(value);
|
|
@@ -84,8 +84,8 @@ function shellQuote(value) {
|
|
|
84
84
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
85
85
|
}
|
|
86
86
|
function buildMainPaneCommand(input, sksCommand) {
|
|
87
|
-
const
|
|
88
|
-
const shouldLaunchCodex = input.kind === 'mad' ||
|
|
87
|
+
const requestedCodexArgs = (input.codexArgs || []).map((arg) => String(arg)).filter(Boolean);
|
|
88
|
+
const shouldLaunchCodex = input.kind === 'mad' || requestedCodexArgs.length > 0;
|
|
89
89
|
if (!shouldLaunchCodex) {
|
|
90
90
|
const shell = shellQuote(String(process.env.SHELL || '/bin/zsh'));
|
|
91
91
|
return {
|
|
@@ -95,6 +95,7 @@ function buildMainPaneCommand(input, sksCommand) {
|
|
|
95
95
|
launchEnvKeys: []
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
|
+
const codexArgs = withCodexScrollbackArgs(requestedCodexArgs);
|
|
98
99
|
const launchEnv = sanitizeLaunchEnv(input.launchEnv || {});
|
|
99
100
|
const envPrefix = launchEnv.map(([key, value]) => `${key}=${shellQuote(value)}`);
|
|
100
101
|
const codexBin = shellQuote(String(input.codexBin || process.env.SKS_CODEX_BIN || 'codex'));
|
|
@@ -105,6 +106,13 @@ function buildMainPaneCommand(input, sksCommand) {
|
|
|
105
106
|
launchEnvKeys: launchEnv.map(([key]) => key)
|
|
106
107
|
};
|
|
107
108
|
}
|
|
109
|
+
function withCodexScrollbackArgs(args) {
|
|
110
|
+
if (process.env.SKS_ZELLIJ_CODEX_ALT_SCREEN === '1')
|
|
111
|
+
return args;
|
|
112
|
+
if (args.includes('--no-alt-screen'))
|
|
113
|
+
return args;
|
|
114
|
+
return ['--no-alt-screen', ...args];
|
|
115
|
+
}
|
|
108
116
|
function sanitizeLaunchEnv(env) {
|
|
109
117
|
return Object.entries(env)
|
|
110
118
|
.filter(([key, value]) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(key) && value != null && String(value) !== '')
|
|
@@ -267,7 +267,7 @@ const tasks = [
|
|
|
267
267
|
task('docs:truthfulness', 'npm run docs:truthfulness --silent', { dependencies: ['build'] }),
|
|
268
268
|
task('official-docs:compat', 'npm run official-docs:compat --silent', { dependencies: ['build'] }),
|
|
269
269
|
task('blackbox:matrix:contract', 'npm run blackbox:matrix:contract --silent', { dependencies: ['build'] }),
|
|
270
|
-
task('test:blackbox', 'npm run test:blackbox --silent', { dependencies: ['build'] }),
|
|
270
|
+
task('test:blackbox', 'npm run test:blackbox --silent', { dependencies: ['build'], timeout_ms: 20 * 60 * 1000 }),
|
|
271
271
|
task('rust:check', 'npm run rust:check --silent', { dependencies: ['build'] }),
|
|
272
272
|
task('rust:smoke', 'npm run rust:smoke --silent', { dependencies: ['build'] }),
|
|
273
273
|
task('release:dist-freshness', 'npm run release:dist-freshness --silent', { dependencies: ['build'] }),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "1.21.
|
|
4
|
+
"version": "1.21.4",
|
|
5
5
|
"description": "Sneakoscope Codex: fast proof-first Codex trust layer with image-based Voxel TriWiki.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
|