sneakoscope 1.21.6 → 1.21.7
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 +12 -26
- 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/native-cli-session-swarm.d.ts +10 -0
- package/dist/core/agents/native-cli-session-swarm.js +238 -1
- package/dist/core/agents/zellij-lane-supervisor.js +1 -1
- 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/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,40 +16,26 @@ 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.7** is a Zellij/Naruto runtime patch. Real Zellij workers now run as pane-bound native CLI sessions: SKS creates or targets the Zellij session, splits a named slot pane, launches the worker inside that pane, and reads `worker-result.json` plus heartbeat/log artifacts back in the parent scheduler.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
What changed:
|
|
22
22
|
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
23
|
+
- `--backend zellij --real` now uses real slot panes for worker sessions instead of only recording synthetic lane artifacts.
|
|
24
|
+
- Pane ids are reconciled from `zellij --session <name> action list-panes --json --all` when `new-pane` does not print one.
|
|
25
|
+
- The parent/worker transport is explicit: `worker-result.json`, `worker-heartbeat.jsonl`, `worker.stdout.log`, and `worker.stderr.log`.
|
|
26
|
+
- Zellij lane supervisor actions target the intended session with `--session`, so pane creation no longer depends on ambient terminal state.
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
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.
|
|
31
|
-
|
|
32
|
-
SKS **1.20.3** added the macOS Zellij launch fallback and project-local Fast mode control. SKS supplies a short per-user `ZELLIJ_SOCKET_DIR` by default, caps generated session names safely, records `*_command_with_env` attach commands, and classifies `IPC socket path is too long` as `zellij_socket_path_too_long` instead of a generic launch failure. It also adds `sks fast-mode on|off|status|clear`, `$Fast-On`, `$Fast-Off`, and `$Fast-Mode`; saved project preferences are used only when no explicit `--fast`, `--no-fast`, or `--service-tier` flag is present. In 1.21.3 and newer, the explicit `on` action also restores Codex App/CLI Fast mode defaults in `~/.codex/config.toml` when they were disabled.
|
|
33
|
-
|
|
34
|
-
It carries forward the **1.20.2** stabilization layer: **Mutation Guard** routes genuinely-risky global/config/permission/package mutations through the Requested-Scope Contract + Mutation Ledger (`safety:mutation-callsite-coverage` fails any unguarded, unallowlisted risky call site); `release:check:dynamic:execute` is the real **caching gate runner** (schema v2, real/heavy gates deferred to `release:real-check`, dynamic-only cannot authorize publish); the **Core Skill** deployed snapshot is read by the route runtime and recorded in `agent-proof-evidence.json` (`selected_core_skill`), with promotions written to the mutation ledger; and `sks doctor` exposes an explicit **`zellij_readiness`** block (`zellij:doctor-readiness`). See `docs/dynamic-release-pipeline.md`.
|
|
35
|
-
|
|
36
|
-
SKS **1.20.1** introduces the **SKS Core Skill Engine** — a SkillOpt-style self-evolving skill layer — while locking the harness into a deploy-ready stable build. Skills are the agent's *external, versioned state* (Core Skill Cards): an optimizer proposes **bounded** add/delete/replace edits to a single skill document under a **textual edit budget**, edits are accepted **only on strict held-out improvement**, rejected edits are buffered so they are never retried, and the **deployed snapshot is immutable**. Critically, the optimizer runs only in training/evaluation — the **deployment/inference path reads the deployed snapshot and never makes an extra model call**, and a skill patch can never mutate code/config/package/global files.
|
|
37
|
-
|
|
38
|
-
1.20.1 also adds a **Requested-Scope Contract + Mutation Ledger** so SKS performs **no side effect the user did not request** (deny-by-default; global/destructive mutations require explicit `--yes`/env opt-in and a backup or no-op reason), and a **dynamic, risk-based release pipeline** (`release:gate-planner` builds `release-gates.json`; `release:check:dynamic` runs only P0 always-on gates plus gates whose files changed; `release:gate-budget` reports the slowest gates) so unrelated heavy gates are skipped during incremental checks while publish never skips a required gate.
|
|
39
|
-
|
|
40
|
-
It carries forward the 1.19.x hardening unchanged: legacy 1.18.x/1.19.x→1.20.1 **zero-break upgrade** (user `model`/`service_tier`/`model_reasoning_effort` and user-disabled Codex App flags never overwritten; existing skill cards preserved), the **migration transaction journal** (`.sneakoscope/reports/migration-1.20.1-journal.jsonl`), **Zellij launch-command truth** + real-session **heartbeat-timeout blocker** + the redesigned **Zellij lane UI**, **packlist/publish-performance** gates, a **postinstall safe-side-effects** gate, and the **TS source-of-truth / Rust optional-accelerator** boundary (publish never compiles Rust). `sks zellij status`/`repair` inspects the Zellij runtime without auto-installing anything.
|
|
41
|
-
|
|
42
|
-
Core release checks:
|
|
28
|
+
Quick checks:
|
|
43
29
|
|
|
44
30
|
```bash
|
|
45
|
-
npm run
|
|
31
|
+
npm run typecheck
|
|
32
|
+
npm run build
|
|
33
|
+
npm run agent:zellij-runtime
|
|
34
|
+
npm run zellij:layout-valid
|
|
46
35
|
npm run zellij:lane-renderer
|
|
47
|
-
npm run mad-sks:zellij-launch
|
|
48
|
-
npm run release:readiness
|
|
49
|
-
npm run release:check
|
|
50
36
|
```
|
|
51
37
|
|
|
52
|
-
Detailed release history
|
|
38
|
+
Broader release checks still live behind `npm run release:check`. Detailed release history is in [CHANGELOG.md](CHANGELOG.md), and release readiness is tracked in [docs/release-readiness.md](docs/release-readiness.md).
|
|
53
39
|
|
|
54
40
|
## Parallelism, UX, And Integrations
|
|
55
41
|
|
|
@@ -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.7"),
|
|
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.7",
|
|
5
|
+
"source_digest": "2c5c05c578c385f3e186f4e94b7387c6122093fbba7235ad2c009d4803e1d6b4",
|
|
6
6
|
"source_file_count": 1771,
|
|
7
|
-
"built_at_source_time":
|
|
7
|
+
"built_at_source_time": 1780395828537
|
|
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.7",
|
|
4
|
+
"package_version": "1.21.7",
|
|
5
5
|
"typescript": true,
|
|
6
6
|
"mjs_runtime_files": 0,
|
|
7
7
|
"compiled_file_count": 1032,
|
|
8
8
|
"compiled_js_count": 516,
|
|
9
9
|
"compiled_dts_count": 516,
|
|
10
|
-
"source_digest": "
|
|
10
|
+
"source_digest": "2c5c05c578c385f3e186f4e94b7387c6122093fbba7235ad2c009d4803e1d6b4",
|
|
11
11
|
"source_file_count": 1771,
|
|
12
12
|
"source_files_hash": "1f79c92a7165654f5ae190c1719e7e8ec89337ed8f265c7a68242ef613848f19",
|
|
13
13
|
"source_list_hash": "1f79c92a7165654f5ae190c1719e7e8ec89337ed8f265c7a68242ef613848f19",
|
|
@@ -15,6 +15,7 @@ declare class NativeCliSessionSwarmRecorder {
|
|
|
15
15
|
private active;
|
|
16
16
|
private maxObserved;
|
|
17
17
|
private writeLock;
|
|
18
|
+
private nextPaneToken;
|
|
18
19
|
constructor(root: string, input: {
|
|
19
20
|
missionId: string;
|
|
20
21
|
requestedAgents: number;
|
|
@@ -29,6 +30,7 @@ declare class NativeCliSessionSwarmRecorder {
|
|
|
29
30
|
slice: any;
|
|
30
31
|
opts: any;
|
|
31
32
|
}): Promise<import("./agent-schema.js").AgentRunnerResult>;
|
|
33
|
+
private launchWorkerInZellijPane;
|
|
32
34
|
finalize(): Promise<{
|
|
33
35
|
schema: string;
|
|
34
36
|
generated_at: string;
|
|
@@ -37,6 +39,7 @@ declare class NativeCliSessionSwarmRecorder {
|
|
|
37
39
|
route: string;
|
|
38
40
|
backend: string;
|
|
39
41
|
scaling_primitive: string;
|
|
42
|
+
zellij_pane_worker_sessions: number;
|
|
40
43
|
requested_agents: number;
|
|
41
44
|
target_active_slots: number;
|
|
42
45
|
spawned_worker_process_count: number;
|
|
@@ -60,5 +63,12 @@ declare class NativeCliSessionSwarmRecorder {
|
|
|
60
63
|
private persist;
|
|
61
64
|
private summary;
|
|
62
65
|
}
|
|
66
|
+
export declare function buildPaneWorkerCommand(input: {
|
|
67
|
+
args: string[];
|
|
68
|
+
stdoutPath: string;
|
|
69
|
+
stderrPath: string;
|
|
70
|
+
heartbeatPath: string;
|
|
71
|
+
env: Record<string, unknown>;
|
|
72
|
+
}): string;
|
|
63
73
|
export {};
|
|
64
74
|
//# sourceMappingURL=native-cli-session-swarm.d.ts.map
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import { ensureDir, exists, nowIso, packageRoot, readJson, writeJsonAtomic } from '../fsx.js';
|
|
4
|
+
import { appendJsonl, ensureDir, exists, nowIso, packageRoot, readJson, writeJsonAtomic } from '../fsx.js';
|
|
5
5
|
import { fastModeEnv } from './fast-mode-policy.js';
|
|
6
6
|
import { validateAgentWorkerResult } from './agent-worker-pipeline.js';
|
|
7
|
+
import { runZellij } from '../zellij/zellij-command.js';
|
|
8
|
+
import { extractZellijPaneIdFromOutput, recordZellijLanePaneId } from '../zellij/zellij-lane-runtime.js';
|
|
7
9
|
export const NATIVE_CLI_SESSION_SWARM_SCHEMA = 'sks.agent-native-cli-session-swarm.v1';
|
|
8
10
|
export function createNativeCliSessionSwarmRecorder(root, input) {
|
|
9
11
|
return new NativeCliSessionSwarmRecorder(root, input);
|
|
@@ -15,6 +17,7 @@ class NativeCliSessionSwarmRecorder {
|
|
|
15
17
|
active = new Set();
|
|
16
18
|
maxObserved = 0;
|
|
17
19
|
writeLock = Promise.resolve();
|
|
20
|
+
nextPaneToken = -1;
|
|
18
21
|
constructor(root, input) {
|
|
19
22
|
this.root = root;
|
|
20
23
|
this.input = input;
|
|
@@ -87,6 +90,20 @@ class NativeCliSessionSwarmRecorder {
|
|
|
87
90
|
};
|
|
88
91
|
const stdout = fs.createWriteStream(path.join(this.root, stdoutRel), { flags: 'a' });
|
|
89
92
|
const stderr = fs.createWriteStream(path.join(this.root, stderrRel), { flags: 'a' });
|
|
93
|
+
if (this.input.backend === 'zellij' && ctx.opts.real === true && ctx.opts.zellijPaneWorker !== false) {
|
|
94
|
+
stdout.end();
|
|
95
|
+
stderr.end();
|
|
96
|
+
return this.launchWorkerInZellijPane({
|
|
97
|
+
ctx,
|
|
98
|
+
record,
|
|
99
|
+
args,
|
|
100
|
+
resultRel,
|
|
101
|
+
stdoutRel,
|
|
102
|
+
stderrRel,
|
|
103
|
+
heartbeatRel,
|
|
104
|
+
workerDirRel
|
|
105
|
+
});
|
|
106
|
+
}
|
|
90
107
|
const child = spawn(process.execPath, args, {
|
|
91
108
|
cwd: ctx.opts.cwd || packageRoot(),
|
|
92
109
|
env: {
|
|
@@ -154,6 +171,159 @@ class NativeCliSessionSwarmRecorder {
|
|
|
154
171
|
await this.record(record);
|
|
155
172
|
return result;
|
|
156
173
|
}
|
|
174
|
+
async launchWorkerInZellijPane(input) {
|
|
175
|
+
const sessionName = String(input.ctx.opts.zellijSessionName || (this.input.missionId ? `sks-${this.input.missionId}` : 'sks-agent-runtime'));
|
|
176
|
+
const slotId = String(input.ctx.agent.slot_id || input.ctx.agent.id || 'slot-001');
|
|
177
|
+
const activeToken = this.nextPaneToken--;
|
|
178
|
+
this.active.add(activeToken);
|
|
179
|
+
this.maxObserved = Math.max(this.maxObserved, this.active.size);
|
|
180
|
+
const workerCommand = buildPaneWorkerCommand({
|
|
181
|
+
args: input.args,
|
|
182
|
+
stdoutPath: path.join(this.root, input.stdoutRel),
|
|
183
|
+
stderrPath: path.join(this.root, input.stderrRel),
|
|
184
|
+
heartbeatPath: path.join(this.root, input.heartbeatRel),
|
|
185
|
+
env: {
|
|
186
|
+
...(input.ctx.opts.env || {}),
|
|
187
|
+
...fastModeEnv(this.input.fastModePolicy),
|
|
188
|
+
SKS_AGENT_WORKER: '1',
|
|
189
|
+
SKS_PIPELINE_MODE: 'agent-worker',
|
|
190
|
+
SKS_DISABLE_ROUTE_RECURSION: '1',
|
|
191
|
+
SKS_PARENT_MISSION_ID: this.input.missionId,
|
|
192
|
+
SKS_AGENT_SESSION_ID: String(input.ctx.agent.session_id || ''),
|
|
193
|
+
SKS_AGENT_SLOT_ID: slotId,
|
|
194
|
+
SKS_AGENT_GENERATION_INDEX: String(input.ctx.agent.generation_index || 1),
|
|
195
|
+
SKS_ZELLIJ_WORKER_PANE: '1',
|
|
196
|
+
SKS_ZELLIJ_SESSION_NAME: sessionName
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
const createSession = await runZellij(['attach', '--create-background', sessionName], {
|
|
200
|
+
cwd: input.ctx.opts.cwd || packageRoot(),
|
|
201
|
+
timeoutMs: 5000,
|
|
202
|
+
optional: false
|
|
203
|
+
});
|
|
204
|
+
const launch = createSession.ok
|
|
205
|
+
? await runZellij(['--session', sessionName, 'action', 'new-pane', '--name', slotId, '--', 'sh', '-lc', workerCommand], {
|
|
206
|
+
cwd: input.ctx.opts.cwd || packageRoot(),
|
|
207
|
+
timeoutMs: 5000,
|
|
208
|
+
optional: false
|
|
209
|
+
})
|
|
210
|
+
: null;
|
|
211
|
+
const stdoutPaneId = launch?.ok ? extractZellijPaneIdFromOutput(launch.stdout_tail) : null;
|
|
212
|
+
const reconciledPane = stdoutPaneId ? null : launch?.ok ? await reconcileZellijWorkerPaneId(sessionName, slotId, path.join(this.root, input.resultRel), input.ctx.opts.cwd || packageRoot()) : null;
|
|
213
|
+
const paneId = stdoutPaneId || reconciledPane?.pane_id || null;
|
|
214
|
+
const paneIdSource = stdoutPaneId ? 'zellij_worker_new_pane_stdout' : reconciledPane?.pane_id ? 'zellij_worker_list_panes' : launch?.ok ? 'zellij_worker_pane_stdout_missing' : 'zellij_worker_pane_launch_failed';
|
|
215
|
+
const launchBlockers = [
|
|
216
|
+
...(createSession.ok ? [] : createSession.blockers.map((blocker) => `zellij_worker_session_${blocker}`)),
|
|
217
|
+
...(launch && !launch.ok ? launch.blockers.map((blocker) => `zellij_worker_pane_${blocker}`) : [])
|
|
218
|
+
];
|
|
219
|
+
input.record.command_line = ['zellij', '--session', sessionName, 'action', 'new-pane', '--name', slotId, '--', 'sh', '-lc', '<native-cli-worker-command>'];
|
|
220
|
+
input.record.zellij_session_name = sessionName;
|
|
221
|
+
input.record.zellij_pane_id = paneId || null;
|
|
222
|
+
input.record.zellij_pane_id_source = paneIdSource;
|
|
223
|
+
input.record.zellij_create_session = createSession;
|
|
224
|
+
input.record.zellij_launch = launch;
|
|
225
|
+
input.record.scaling_primitive = 'native_cli_process_in_zellij_pane';
|
|
226
|
+
input.record.status = launchBlockers.length ? 'failed' : 'running';
|
|
227
|
+
input.record.blockers = launchBlockers;
|
|
228
|
+
await this.record(input.record);
|
|
229
|
+
await appendJsonl(path.join(this.root, 'agent-zellij-pane-launch-ledger.jsonl'), {
|
|
230
|
+
schema: 'sks.agent-zellij-pane-launch.v1',
|
|
231
|
+
generated_at: nowIso(),
|
|
232
|
+
launch_mode: launch?.ok ? 'real_zellij_worker_pane_session' : 'real_zellij_worker_pane_failed',
|
|
233
|
+
agent_id: input.ctx.agent.id,
|
|
234
|
+
slot_id: slotId,
|
|
235
|
+
generation_index: input.ctx.agent.generation_index || null,
|
|
236
|
+
session_id: input.ctx.agent.session_id,
|
|
237
|
+
session_name: sessionName,
|
|
238
|
+
pane_id: paneId || `zellij-pane-${slotId}`,
|
|
239
|
+
pane_id_source: paneIdSource,
|
|
240
|
+
command: '<native-cli-worker-command>',
|
|
241
|
+
worker_artifact_dir: input.workerDirRel,
|
|
242
|
+
worker_result_path: input.resultRel,
|
|
243
|
+
parent_child_transport: 'worker-result-json-and-heartbeat',
|
|
244
|
+
persistent_slot_lane: false,
|
|
245
|
+
blockers: launchBlockers
|
|
246
|
+
});
|
|
247
|
+
await recordZellijLanePaneId(this.root, {
|
|
248
|
+
slotId,
|
|
249
|
+
paneId: paneId || `zellij-pane-${slotId}`,
|
|
250
|
+
source: paneIdSource,
|
|
251
|
+
sessionName,
|
|
252
|
+
command: '<native-cli-worker-command>'
|
|
253
|
+
});
|
|
254
|
+
await writeJsonAtomic(path.join(this.root, input.workerDirRel, 'zellij-worker-pane-launch.json'), {
|
|
255
|
+
schema: 'sks.zellij-worker-pane-launch.v1',
|
|
256
|
+
generated_at: nowIso(),
|
|
257
|
+
ok: launchBlockers.length === 0,
|
|
258
|
+
session_name: sessionName,
|
|
259
|
+
pane_id: paneId || null,
|
|
260
|
+
pane_id_source: paneIdSource,
|
|
261
|
+
slot_id: slotId,
|
|
262
|
+
worker_artifact_dir: input.workerDirRel,
|
|
263
|
+
result_path: input.resultRel,
|
|
264
|
+
stdout_log: input.stdoutRel,
|
|
265
|
+
stderr_log: input.stderrRel,
|
|
266
|
+
parent_child_transport: 'worker-result-json-and-heartbeat',
|
|
267
|
+
create_session: createSession,
|
|
268
|
+
launch,
|
|
269
|
+
pane_reconciliation: reconciledPane,
|
|
270
|
+
blockers: launchBlockers
|
|
271
|
+
});
|
|
272
|
+
if (launchBlockers.length) {
|
|
273
|
+
this.active.delete(activeToken);
|
|
274
|
+
input.record.closed_at = nowIso();
|
|
275
|
+
input.record.status = 'failed';
|
|
276
|
+
await this.record(input.record);
|
|
277
|
+
return validateAgentWorkerResult({
|
|
278
|
+
mission_id: this.input.missionId,
|
|
279
|
+
agent_id: input.ctx.agent.id,
|
|
280
|
+
session_id: input.ctx.agent.session_id,
|
|
281
|
+
persona_id: input.ctx.agent.persona_id || input.ctx.agent.id,
|
|
282
|
+
task_slice_id: input.ctx.slice?.id || '',
|
|
283
|
+
status: 'failed',
|
|
284
|
+
backend: this.input.backend,
|
|
285
|
+
summary: 'Zellij worker pane launch failed.',
|
|
286
|
+
artifacts: [input.stdoutRel, input.stderrRel, path.join(input.workerDirRel, 'zellij-worker-pane-launch.json')],
|
|
287
|
+
blockers: launchBlockers,
|
|
288
|
+
unverified: [],
|
|
289
|
+
writes: [],
|
|
290
|
+
source_intelligence_refs: input.ctx.agent.source_intelligence_refs || null,
|
|
291
|
+
goal_mode_ref: input.ctx.agent.goal_mode_ref || null
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
const parsed = await waitForWorkerResult(path.join(this.root, input.resultRel), Number(process.env.SKS_ZELLIJ_WORKER_RESULT_TIMEOUT_MS || 120000));
|
|
295
|
+
this.active.delete(activeToken);
|
|
296
|
+
input.record.closed_at = nowIso();
|
|
297
|
+
const workerProcessReport = await readJson(path.join(this.root, input.workerDirRel, 'worker-process-report.json'), null).catch(() => null);
|
|
298
|
+
input.record.pid = Number(workerProcessReport?.pid) || null;
|
|
299
|
+
input.record.process_id = input.record.pid;
|
|
300
|
+
input.record.exit_code = parsed ? (parsed.status === 'done' ? 0 : 1) : 1;
|
|
301
|
+
input.record.status = parsed?.status === 'done' ? 'closed' : 'failed';
|
|
302
|
+
input.record.blockers = parsed ? parsed.blockers || [] : ['zellij_worker_result_timeout'];
|
|
303
|
+
await this.record(input.record);
|
|
304
|
+
if (!parsed) {
|
|
305
|
+
return validateAgentWorkerResult({
|
|
306
|
+
mission_id: this.input.missionId,
|
|
307
|
+
agent_id: input.ctx.agent.id,
|
|
308
|
+
session_id: input.ctx.agent.session_id,
|
|
309
|
+
persona_id: input.ctx.agent.persona_id || input.ctx.agent.id,
|
|
310
|
+
task_slice_id: input.ctx.slice?.id || '',
|
|
311
|
+
status: 'failed',
|
|
312
|
+
backend: this.input.backend,
|
|
313
|
+
summary: 'Zellij pane worker result timed out.',
|
|
314
|
+
artifacts: [input.stdoutRel, input.stderrRel, path.join(input.workerDirRel, 'zellij-worker-pane-launch.json')],
|
|
315
|
+
blockers: ['zellij_worker_result_timeout'],
|
|
316
|
+
unverified: [],
|
|
317
|
+
writes: [],
|
|
318
|
+
source_intelligence_refs: input.ctx.agent.source_intelligence_refs || null,
|
|
319
|
+
goal_mode_ref: input.ctx.agent.goal_mode_ref || null
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
return validateAgentWorkerResult({
|
|
323
|
+
...parsed,
|
|
324
|
+
artifacts: [...new Set([...(Array.isArray(parsed.artifacts) ? parsed.artifacts : []), input.stdoutRel, input.stderrRel, path.join(input.workerDirRel, 'zellij-worker-pane-launch.json')])]
|
|
325
|
+
});
|
|
326
|
+
}
|
|
157
327
|
async finalize() {
|
|
158
328
|
await this.persist();
|
|
159
329
|
return this.summary();
|
|
@@ -183,6 +353,7 @@ class NativeCliSessionSwarmRecorder {
|
|
|
183
353
|
route: this.input.route,
|
|
184
354
|
backend: this.input.backend,
|
|
185
355
|
scaling_primitive: 'native_cli_process',
|
|
356
|
+
zellij_pane_worker_sessions: this.records.filter((row) => row.scaling_primitive === 'native_cli_process_in_zellij_pane').length,
|
|
186
357
|
requested_agents: this.input.requestedAgents,
|
|
187
358
|
target_active_slots: this.input.targetActiveSlots,
|
|
188
359
|
spawned_worker_process_count: this.records.length,
|
|
@@ -204,6 +375,69 @@ class NativeCliSessionSwarmRecorder {
|
|
|
204
375
|
};
|
|
205
376
|
}
|
|
206
377
|
}
|
|
378
|
+
export function buildPaneWorkerCommand(input) {
|
|
379
|
+
const envPrefix = Object.entries(input.env)
|
|
380
|
+
.filter(([key, value]) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(key) && value != null)
|
|
381
|
+
.map(([key, value]) => `${key}=${shellQuote(String(value))}`)
|
|
382
|
+
.sort();
|
|
383
|
+
const command = [shellQuote(process.execPath), ...input.args.map(shellQuote)].join(' ');
|
|
384
|
+
const heartbeat = `printf '%s\\n' ${shellQuote(JSON.stringify({ schema: 'sks.zellij-worker-pane-event.v1', event: 'worker_command_exited' }))} >> ${shellQuote(input.heartbeatPath)}`;
|
|
385
|
+
const holdMs = Math.max(0, Number(process.env.SKS_ZELLIJ_WORKER_PANE_HOLD_MS || 1500));
|
|
386
|
+
const hold = holdMs > 0 ? `sleep ${shellQuote(String(Math.min(30, holdMs / 1000)))}` : ':';
|
|
387
|
+
return `${envPrefix.join(' ')} ${command} > ${shellQuote(input.stdoutPath)} 2> ${shellQuote(input.stderrPath)}; code=$?; ${heartbeat}; ${hold}; exit $code`.trim();
|
|
388
|
+
}
|
|
389
|
+
async function waitForWorkerResult(file, timeoutMs) {
|
|
390
|
+
const deadline = Date.now() + Math.max(1000, timeoutMs);
|
|
391
|
+
while (Date.now() < deadline) {
|
|
392
|
+
const result = await readJson(file, null).catch(() => null);
|
|
393
|
+
if (result)
|
|
394
|
+
return result;
|
|
395
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
396
|
+
}
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
async function reconcileZellijWorkerPaneId(sessionName, slotId, resultPath, cwd) {
|
|
400
|
+
const listed = await runZellij(['--session', sessionName, 'action', 'list-panes', '--json', '--all'], {
|
|
401
|
+
cwd,
|
|
402
|
+
timeoutMs: 5000,
|
|
403
|
+
optional: true
|
|
404
|
+
});
|
|
405
|
+
const rows = parsePaneRows(listed.stdout_tail);
|
|
406
|
+
const pane = rows.find((row) => {
|
|
407
|
+
const title = String(row.title || row.name || row.pane_name || '');
|
|
408
|
+
const command = String(row.terminal_command || row.command || row.command_line || row.running_command || '');
|
|
409
|
+
const exited = row.exited === true || row.is_exited === true || row.exit_status != null;
|
|
410
|
+
return !exited && title === slotId && (command.includes(resultPath) || command.includes('SKS_ZELLIJ_WORKER_PANE'));
|
|
411
|
+
}) || rows.find((row) => {
|
|
412
|
+
const title = String(row.title || row.name || row.pane_name || '');
|
|
413
|
+
const exited = row.exited === true || row.is_exited === true || row.exit_status != null;
|
|
414
|
+
return !exited && title === slotId;
|
|
415
|
+
});
|
|
416
|
+
const paneId = pane?.pane_id ?? pane?.paneId ?? pane?.id ?? null;
|
|
417
|
+
return {
|
|
418
|
+
schema: 'sks.zellij-worker-pane-reconciliation.v1',
|
|
419
|
+
ok: Boolean(paneId),
|
|
420
|
+
pane_id: paneId == null ? null : String(paneId),
|
|
421
|
+
listed_count: rows.length,
|
|
422
|
+
command: listed,
|
|
423
|
+
blockers: paneId == null ? ['zellij_worker_pane_id_not_reconciled'] : []
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
function parsePaneRows(text) {
|
|
427
|
+
if (!String(text || '').trim())
|
|
428
|
+
return [];
|
|
429
|
+
try {
|
|
430
|
+
const parsed = JSON.parse(String(text));
|
|
431
|
+
if (Array.isArray(parsed))
|
|
432
|
+
return parsed;
|
|
433
|
+
if (Array.isArray(parsed?.panes))
|
|
434
|
+
return parsed.panes;
|
|
435
|
+
return [];
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
return [];
|
|
439
|
+
}
|
|
440
|
+
}
|
|
207
441
|
async function resolveWorkerCliPath() {
|
|
208
442
|
if (process.env.SKS_NATIVE_WORKER_CLI)
|
|
209
443
|
return process.env.SKS_NATIVE_WORKER_CLI;
|
|
@@ -215,4 +449,7 @@ async function resolveWorkerCliPath() {
|
|
|
215
449
|
function redactWorkerArgs(args) {
|
|
216
450
|
return args.map((arg, index) => index > 0 && args[index - 1] === '--intake' ? '<worker-intake.json>' : arg);
|
|
217
451
|
}
|
|
452
|
+
function shellQuote(value) {
|
|
453
|
+
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
454
|
+
}
|
|
218
455
|
//# sourceMappingURL=native-cli-session-swarm.js.map
|
|
@@ -230,7 +230,7 @@ async function createSupervisorLanes(root, missionId, sessionName, targetActiveS
|
|
|
230
230
|
}
|
|
231
231
|
async function launchPersistentSlotLane(root, lane, missionId) {
|
|
232
232
|
const command = persistentLaneCommandForRoot(root, missionId, lane.slot_id, lane.runtime.session_name);
|
|
233
|
-
const launch = await runZellij(['action', 'new-pane', '--name', lane.slot_id, '--', 'sh', '-lc', command], { cwd: root, timeoutMs: 5000, optional: true });
|
|
233
|
+
const launch = await runZellij(['--session', lane.runtime.session_name, 'action', 'new-pane', '--name', lane.slot_id, '--', 'sh', '-lc', command], { cwd: root, timeoutMs: 5000, optional: true });
|
|
234
234
|
const paneId = launch.ok ? extractZellijPaneIdFromOutput(launch.stdout_tail) : null;
|
|
235
235
|
const nextPaneId = paneId || lane.pane_id;
|
|
236
236
|
const paneIdSource = paneId ? 'zellij_new_pane_stdout' : launch.ok ? 'synthetic_fallback_new_pane_stdout_missing' : lane.pane_id_source;
|
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.7';
|
|
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.7";
|
|
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.7';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
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.7",
|
|
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",
|