sneakoscope 4.8.6 → 4.8.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.
Files changed (141) hide show
  1. package/README.md +14 -14
  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/cli/command-registry.js +63 -41
  7. package/dist/cli/install-helpers.js +115 -47
  8. package/dist/cli/router.js +58 -2
  9. package/dist/commands/codex-lb.js +4 -4
  10. package/dist/commands/doctor.js +85 -3
  11. package/dist/commands/zellij-monitor-pane.js +25 -0
  12. package/dist/commands/zellij-slot-pane.js +39 -2
  13. package/dist/commands/zellij-viewport-pane.js +56 -0
  14. package/dist/commands/zellij.js +55 -2
  15. package/dist/config/skills-manifest.json +465 -0
  16. package/dist/core/agents/agent-lifecycle.js +86 -35
  17. package/dist/core/agents/agent-orchestrator.js +19 -10
  18. package/dist/core/agents/agent-patch-queue-store.js +14 -3
  19. package/dist/core/agents/agent-patch-queue.js +4 -0
  20. package/dist/core/agents/agent-scheduler.js +2 -3
  21. package/dist/core/agents/native-cli-session-swarm.js +30 -13
  22. package/dist/core/agents/native-cli-worker.js +2 -1
  23. package/dist/core/auto-review.js +25 -4
  24. package/dist/core/codex/agent-config-file-repair.js +15 -2
  25. package/dist/core/codex/codex-config-eperm-repair.js +8 -2
  26. package/dist/core/codex/codex-config-guard.js +289 -0
  27. package/dist/core/codex/codex-config-toml.js +122 -0
  28. package/dist/core/codex/codex-project-config-policy.js +59 -7
  29. package/dist/core/codex-app/sks-menubar.js +767 -122
  30. package/dist/core/codex-control/codex-fake-sdk-adapter.js +6 -4
  31. package/dist/core/codex-control/codex-task-runner.js +32 -14
  32. package/dist/core/codex-control/python-codex-sdk-adapter.js +4 -1
  33. package/dist/core/codex-lb/codex-lb-setup.js +2 -5
  34. package/dist/core/codex-native/skill-registry-ledger.js +24 -5
  35. package/dist/core/commands/command-utils.js +22 -2
  36. package/dist/core/commands/fast-mode-command.js +36 -11
  37. package/dist/core/commands/mad-sks-command.js +18 -5
  38. package/dist/core/commands/menubar-command.js +125 -0
  39. package/dist/core/commands/pipeline-command.js +21 -2
  40. package/dist/core/commands/route-command.js +62 -0
  41. package/dist/core/commands/status-command.js +21 -1
  42. package/dist/core/commands/team-legacy-observe-command.js +221 -3
  43. package/dist/core/commands/uninstall-command.js +298 -0
  44. package/dist/core/db-safety.js +5 -1
  45. package/dist/core/doctor/codex-startup-config-repair.js +14 -3
  46. package/dist/core/doctor/confirm-repair.js +27 -0
  47. package/dist/core/doctor/context7-mcp-repair.js +35 -7
  48. package/dist/core/doctor/doctor-codex-startup-repair.js +10 -3
  49. package/dist/core/doctor/doctor-context7-repair.js +17 -4
  50. package/dist/core/doctor/doctor-dirty-planner.js +27 -9
  51. package/dist/core/doctor/doctor-native-capability-repair.js +12 -2
  52. package/dist/core/doctor/doctor-readiness-matrix.js +27 -2
  53. package/dist/core/doctor/doctor-repair-postcheck.js +4 -0
  54. package/dist/core/doctor/doctor-transaction.js +13 -5
  55. package/dist/core/doctor/supabase-mcp-repair.js +23 -5
  56. package/dist/core/feature-fixtures.js +10 -3
  57. package/dist/core/feature-registry.js +4 -1
  58. package/dist/core/fsx.js +58 -2
  59. package/dist/core/hooks-runtime/skill-reconcile-preflight.js +43 -0
  60. package/dist/core/hooks-runtime.js +86 -46
  61. package/dist/core/init/skills.js +261 -9
  62. package/dist/core/init.js +13 -10
  63. package/dist/core/mad-db/mad-db-coordinator.js +3 -3
  64. package/dist/core/mission.js +138 -5
  65. package/dist/core/naruto/naruto-active-pool.js +69 -26
  66. package/dist/core/naruto/naruto-backpressure.js +5 -1
  67. package/dist/core/naruto/naruto-real-worker-runtime.js +9 -7
  68. package/dist/core/naruto/resource-pressure-monitor.js +33 -15
  69. package/dist/core/pipeline-internals/runtime-core.js +62 -220
  70. package/dist/core/pipeline-internals/runtime-gates.js +113 -24
  71. package/dist/core/questions.js +1 -1
  72. package/dist/core/recallpulse.js +1 -1
  73. package/dist/core/release/gate-manifest.js +2 -2
  74. package/dist/core/release/release-gate-affected-selector.js +3 -10
  75. package/dist/core/release/release-gate-batch-runner.js +4 -2
  76. package/dist/core/release/release-gate-cache-v2.js +27 -14
  77. package/dist/core/release/release-gate-dag.js +6 -1
  78. package/dist/core/release/release-gate-hermetic-env.js +10 -0
  79. package/dist/core/retention.js +89 -4
  80. package/dist/core/routes/diagnostic-allowlist.js +55 -0
  81. package/dist/core/routes.js +18 -15
  82. package/dist/core/skill-forge.js +9 -4
  83. package/dist/core/stop-gate/stop-gate-check.js +10 -3
  84. package/dist/core/stop-gate/stop-gate-resolver.js +19 -3
  85. package/dist/core/stop-gate/stop-gate-writer.js +16 -1
  86. package/dist/core/team-dag.js +12 -465
  87. package/dist/core/team-dashboard-renderer.js +13 -94
  88. package/dist/core/team-live.js +68 -804
  89. package/dist/core/update/update-migration-state.js +20 -30
  90. package/dist/core/update-check.js +28 -2
  91. package/dist/core/version.js +1 -1
  92. package/dist/core/zellij/zellij-layout-builder.js +44 -16
  93. package/dist/core/zellij/zellij-monitor-renderer.js +53 -0
  94. package/dist/core/zellij/zellij-self-heal.js +18 -26
  95. package/dist/core/zellij/zellij-slot-pane-renderer.js +162 -153
  96. package/dist/core/zellij/zellij-slot-telemetry.js +2 -0
  97. package/dist/core/zellij/zellij-theme.js +67 -0
  98. package/dist/core/zellij/zellij-ui-mode.js +16 -0
  99. package/dist/core/zellij/zellij-viewport-binder.js +59 -0
  100. package/dist/core/zellij/zellij-worker-pane-manager.js +53 -5
  101. package/dist/scripts/agent-patch-swarm-gate-lib.js +2 -2
  102. package/dist/scripts/build-dist.js +8 -0
  103. package/dist/scripts/codex-lb-fast-ui-preservation-check.js +106 -0
  104. package/dist/scripts/codex-lb-gpt55-fast-profile-check.js +105 -0
  105. package/dist/scripts/codex-lb-missing-env-regression.js +2 -3
  106. package/dist/scripts/codex-project-config-policy-merge-regression.js +3 -3
  107. package/dist/scripts/concurrent-session-collision-check.js +67 -0
  108. package/dist/scripts/core-skill-integrity-blackbox.js +3 -4
  109. package/dist/scripts/docs-truthfulness-check.js +1 -1
  110. package/dist/scripts/gate-policy-audit-check.js +130 -0
  111. package/dist/scripts/hook-latency-budget-check.js +45 -0
  112. package/dist/scripts/lib/codex-sdk-gate-lib.js +2 -2
  113. package/dist/scripts/lib/real-codex-parallel-gate.js +2 -2
  114. package/dist/scripts/loop-directive-check-lib.js +1 -1
  115. package/dist/scripts/mad-db-real-supabase-e2e.js +2 -2
  116. package/dist/scripts/mad-sks-zellij-default-pane-worker-check.js +3 -2
  117. package/dist/scripts/mad-sks-zellij-launch-check.js +1 -1
  118. package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +7 -7
  119. package/dist/scripts/parallel-claim-enforcement-check.js +14 -5
  120. package/dist/scripts/project-skill-dedupe-check.js +23 -5
  121. package/dist/scripts/release-affected-selector-check.js +2 -2
  122. package/dist/scripts/release-cache-glob-hashing-check.js +1 -0
  123. package/dist/scripts/release-gate-dag-runner-check.js +10 -2
  124. package/dist/scripts/release-gate-dag-runner.js +8 -0
  125. package/dist/scripts/release-readiness-report.js +38 -7
  126. package/dist/scripts/release-stability-report-check.js +12 -8
  127. package/dist/scripts/search-visibility-gate-lib.js +2 -2
  128. package/dist/scripts/skills-manifest-continuity-check.js +46 -0
  129. package/dist/scripts/sks-menubar-install-check.js +87 -21
  130. package/dist/scripts/sks-uninstall-regression-check.js +54 -0
  131. package/dist/scripts/uninstall-inventory-check.js +3 -0
  132. package/dist/scripts/zellij-initial-main-only-blackbox.js +4 -4
  133. package/dist/scripts/zellij-layout-valid-check.js +18 -11
  134. package/dist/scripts/zellij-right-column-geometry-proof.js +2 -4
  135. package/dist/scripts/zellij-slot-pane-renderer-check.js +9 -9
  136. package/dist/scripts/zellij-slot-pane-stale-detection-check.js +3 -4
  137. package/dist/scripts/zellij-slot-pane-telemetry-renderer-check.js +3 -2
  138. package/dist/scripts/zellij-slot-telemetry-renderer-check.js +4 -2
  139. package/dist/scripts/zellij-spawn-on-demand-layout-check.js +8 -2
  140. package/dist/scripts/zellij-viewport-binder-check.js +9 -0
  141. package/package.json +4 -1
@@ -0,0 +1,25 @@
1
+ import { readZellijSlotTelemetrySnapshot } from '../core/zellij/zellij-slot-telemetry.js';
2
+ import { renderZellijMonitor } from '../core/zellij/zellij-monitor-renderer.js';
3
+ import { projectRoot } from '../core/fsx.js';
4
+ export async function run(_cmd = 'zellij-monitor-pane', args = []) {
5
+ const mission = readOption(args, '--mission', 'latest') || 'latest';
6
+ const root = await projectRoot();
7
+ const intervalMs = Math.max(500, Number(readOption(args, '--interval-ms', String(process.env.SKS_ZELLIJ_REFRESH_MS || '1000')) || 1000));
8
+ const once = !flag(args, '--watch');
9
+ for (;;) {
10
+ const snapshot = await readZellijSlotTelemetrySnapshot(root, mission).catch(() => null);
11
+ const text = renderZellijMonitor({ snapshot, missionId: mission, root });
12
+ process.stdout.write(`\x1b[H${text}\n\x1b[0J`);
13
+ if (once)
14
+ return;
15
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
16
+ }
17
+ }
18
+ function readOption(args, name, fallback) {
19
+ const index = args.indexOf(name);
20
+ return index >= 0 && args[index + 1] ? String(args[index + 1]) : fallback;
21
+ }
22
+ function flag(args, name) {
23
+ return args.includes(name);
24
+ }
25
+ //# sourceMappingURL=zellij-monitor-pane.js.map
@@ -7,6 +7,14 @@ export async function run(_command = 'zellij-slot-pane', args = []) {
7
7
  const generationIndex = Number(readOption(args, '--generation', '1') || 1);
8
8
  const backend = readOption(args, '--backend', null);
9
9
  const role = readOption(args, '--role', null);
10
+ const envDefaults = {
11
+ provider: process.env.SKS_SLOT_PROVIDER || null,
12
+ model: process.env.SKS_SLOT_MODEL || null,
13
+ serviceTier: process.env.SKS_SLOT_TIER || null,
14
+ reasoningEffort: process.env.SKS_SLOT_REASONING || null,
15
+ currentTask: process.env.SKS_SLOT_TASK || null,
16
+ role: process.env.SKS_SLOT_ROLE || role
17
+ };
10
18
  const mode = readOption(args, '--mode', 'compact-slots');
11
19
  const watch = hasFlag(args, '--watch');
12
20
  const json = hasFlag(args, '--json');
@@ -16,8 +24,32 @@ export async function run(_command = 'zellij-slot-pane', args = []) {
16
24
  console.log(JSON.stringify(status, null, 2));
17
25
  return;
18
26
  }
27
+ let staleTicks = 0;
19
28
  for (;;) {
20
- const text = await renderZellijSlotPaneFromArtifacts({ artifactDir, artifactRoot, missionId, slotId, generationIndex, backend, role, mode });
29
+ let text = '';
30
+ let heartbeatAgeMs = null;
31
+ try {
32
+ text = await renderZellijSlotPaneFromArtifacts({
33
+ artifactDir,
34
+ artifactRoot,
35
+ missionId,
36
+ slotId,
37
+ generationIndex,
38
+ backend,
39
+ role: envDefaults.role,
40
+ provider: envDefaults.provider,
41
+ model: envDefaults.model,
42
+ serviceTier: envDefaults.serviceTier,
43
+ reasoningEffort: envDefaults.reasoningEffort,
44
+ currentTask: envDefaults.currentTask,
45
+ mode
46
+ });
47
+ const status = await renderZellijSlotPaneStatusFromArtifacts({ artifactDir, artifactRoot, missionId, slotId, generationIndex }).catch(() => null);
48
+ heartbeatAgeMs = Number.isFinite(Number(status?.telemetry_age_ms)) ? Number(status?.telemetry_age_ms) : null;
49
+ }
50
+ catch (err) {
51
+ text = `render error: ${err?.message || String(err)}`;
52
+ }
21
53
  process.stdout.write(redrawFrame(text));
22
54
  if (!watch)
23
55
  break;
@@ -27,10 +59,15 @@ export async function run(_command = 'zellij-slot-pane', args = []) {
27
59
  const shouldExit = await resolveZellijSlotPaneExit({ artifactDir, artifactRoot, missionId, slotId, generationIndex }).catch(() => false);
28
60
  if (shouldExit) {
29
61
  await new Promise((resolve) => setTimeout(resolve, 5000));
30
- const finalText = await renderZellijSlotPaneFromArtifacts({ artifactDir, artifactRoot, missionId, slotId, generationIndex, backend, role, mode });
62
+ const finalText = await renderZellijSlotPaneFromArtifacts({ artifactDir, artifactRoot, missionId, slotId, generationIndex, backend, role: envDefaults.role, provider: envDefaults.provider, model: envDefaults.model, serviceTier: envDefaults.serviceTier, reasoningEffort: envDefaults.reasoningEffort, currentTask: envDefaults.currentTask, mode });
31
63
  process.stdout.write(redrawFrame(finalText));
32
64
  return;
33
65
  }
66
+ staleTicks = heartbeatAgeMs != null && heartbeatAgeMs > 5 * 60 * 1000 ? staleTicks + 1 : 0;
67
+ if (staleTicks >= 5) {
68
+ process.stdout.write(redrawFrame(`${text}\n⏱ worker heartbeat lost >5m - pane closing (sks pipeline status 로 확인)`));
69
+ return;
70
+ }
34
71
  await new Promise((resolve) => setTimeout(resolve, intervalMs));
35
72
  }
36
73
  }
@@ -0,0 +1,56 @@
1
+ import path from 'node:path';
2
+ import { flag, readOption } from '../cli/args.js';
3
+ import { projectRoot, readJson } from '../core/fsx.js';
4
+ import { readZellijSlotTelemetrySnapshot } from '../core/zellij/zellij-slot-telemetry.js';
5
+ import { bindViewports } from '../core/zellij/zellij-viewport-binder.js';
6
+ import { renderZellijSlotPaneFromArtifacts } from '../core/zellij/zellij-slot-pane-renderer.js';
7
+ import { ANSI_CODES, paint, resolveZellijTheme } from '../core/zellij/zellij-theme.js';
8
+ let previousBindings = [];
9
+ export async function run(_cmd = 'zellij-viewport-pane', args = []) {
10
+ const mission = String(readOption(args, '--mission', 'latest') || 'latest');
11
+ const index = Math.max(1, Number(readOption(args, '--index', '1')) || 1);
12
+ const of = Math.max(index, Number(readOption(args, '--of', '4')) || 4);
13
+ const intervalMs = Math.max(500, Number(process.env.SKS_ZELLIJ_REFRESH_MS || 1000));
14
+ const root = await projectRoot();
15
+ previousBindings = Array.from({ length: of }, () => null);
16
+ const once = !flag(args, '--watch');
17
+ for (;;) {
18
+ const frame = await renderViewportFrame(root, mission, index, of).catch((err) => `viewport render error: ${err?.message || String(err)}`);
19
+ process.stdout.write(`\x1b[H${frame}\n\x1b[0J`);
20
+ if (once)
21
+ return;
22
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
23
+ }
24
+ }
25
+ async function renderViewportFrame(root, mission, index, of) {
26
+ const theme = resolveZellijTheme();
27
+ const snapshot = await readZellijSlotTelemetrySnapshot(root, mission).catch(() => null);
28
+ const missionId = snapshot?.mission_id || mission;
29
+ const pins = await readJson(pinsPath(root, missionId), { pins: [] });
30
+ const bindings = bindViewports({
31
+ snapshot,
32
+ pins: pins.pins || [],
33
+ previous: previousBindings,
34
+ viewportCount: of
35
+ });
36
+ previousBindings = bindings.map((binding) => binding.slotKey);
37
+ const mine = bindings[index - 1] || { slotKey: null, reason: 'idle' };
38
+ const badge = mine.reason === 'pinned' ? 'pinned' : mine.reason === 'kept' ? 'auto' : mine.reason;
39
+ const header = paint(theme, ANSI_CODES.dim, `viewport ${index}/${of} | ${mine.slotKey ?? '-'} (${badge})`);
40
+ if (!mine.slotKey)
41
+ return `${header}\n${paint(theme, ANSI_CODES.dim, `idle - no active worker. Pin: sks zellij pin <slot> --viewport ${index}`)}`;
42
+ const [slotId, rawGen] = mine.slotKey.split(':g');
43
+ const generationIndex = Math.max(1, Number(rawGen || 1) || 1);
44
+ const detail = await renderZellijSlotPaneFromArtifacts({
45
+ artifactRoot: root,
46
+ missionId,
47
+ artifactDir: path.join(root, '.sneakoscope', 'missions', missionId, 'agents', 'sessions', slotId || mine.slotKey, `gen-${generationIndex}`, 'worker'),
48
+ slotId: slotId || mine.slotKey,
49
+ generationIndex
50
+ });
51
+ return `${header}\n${detail}`;
52
+ }
53
+ function pinsPath(root, missionId) {
54
+ return path.join(root, '.sneakoscope', 'missions', missionId, 'zellij', 'viewport-pins.json');
55
+ }
56
+ //# sourceMappingURL=zellij-viewport-pane.js.map
@@ -1,6 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import fs from 'node:fs';
3
- import { projectRoot, readJson } from '../core/fsx.js';
3
+ import { nowIso, projectRoot, readJson, writeJsonAtomic } from '../core/fsx.js';
4
4
  import { flag } from '../cli/args.js';
5
5
  import { printJson } from '../cli/output.js';
6
6
  import { checkZellijCapability } from '../core/zellij/zellij-capability.js';
@@ -8,6 +8,7 @@ import { checkZellijUpdateNotice, upgradeZellijToLatest } from '../core/zellij/z
8
8
  import { runZellij } from '../core/zellij/zellij-command.js';
9
9
  import { appendZellijLaneCommand, normalizeZellijSlot } from '../core/zellij/zellij-lane-runtime.js';
10
10
  import { buildZellijDashboardSnapshot, renderZellijDashboardText } from '../core/zellij/zellij-dashboard-renderer.js';
11
+ import { readZellijSlotTelemetrySnapshot } from '../core/zellij/zellij-slot-telemetry.js';
11
12
  export const ZELLIJ_COMMAND_SCHEMA = 'sks.zellij-command.v1';
12
13
  export const ZELLIJ_REPAIR_SCHEMA = 'sks.zellij-repair.v1';
13
14
  function installHint() {
@@ -37,6 +38,8 @@ export async function run(_command = 'zellij', args = []) {
37
38
  return zellijDashboard(root, args, json);
38
39
  if (sub === 'close-drained')
39
40
  return zellijCloseDrained(root, args, json);
41
+ if (sub === 'pin' || sub === 'unpin')
42
+ return zellijViewportPin(root, sub, args, json);
40
43
  return zellijStatus(root, args, json);
41
44
  }
42
45
  async function zellijStatus(root, args, json) {
@@ -230,6 +233,41 @@ async function zellijCloseDrained(root, args, json) {
230
233
  if (!out.ok)
231
234
  process.exitCode = 1;
232
235
  }
236
+ async function zellijViewportPin(root, action, args, json) {
237
+ const missionId = resolveMissionId(root, readOption(args, '--mission', readOption(args, '--mission-id', 'latest') || 'latest') || 'latest');
238
+ const slotArg = positionalAfter(args, action) || readOption(args, '--slot', '');
239
+ const viewport = Math.max(1, Number(readOption(args, '--viewport', '1')) || 1);
240
+ const file = path.join(root, '.sneakoscope', 'missions', missionId, 'zellij', 'viewport-pins.json');
241
+ const cur = await readJson(file, { pins: [] });
242
+ const slotKey = slotArg ? await resolveLatestGenKey(root, missionId, slotArg) : '';
243
+ const pins = (cur.pins || []).filter((pin) => pin.viewport !== viewport && (!slotKey || pin.slot_key !== slotKey));
244
+ const blockers = slotArg ? [] : ['slot_required'];
245
+ if (action === 'pin' && slotKey && blockers.length === 0)
246
+ pins.push({ viewport, slot_key: slotKey });
247
+ await writeJsonAtomic(file, {
248
+ schema: 'sks.zellij-viewport-pins.v1',
249
+ updated_at: nowIso(),
250
+ pins
251
+ });
252
+ const out = {
253
+ schema: 'sks.zellij-viewport-pin-command.v1',
254
+ ok: blockers.length === 0,
255
+ action,
256
+ mission_id: missionId,
257
+ viewport,
258
+ slot_key: slotKey || null,
259
+ pins,
260
+ blockers
261
+ };
262
+ if (json)
263
+ printJson(out);
264
+ else if (out.ok)
265
+ console.log(action === 'pin' ? `pinned ${slotKey} -> viewport ${viewport}` : `unpinned ${slotKey}`);
266
+ else
267
+ console.log('Usage: sks zellij pin <slot> [--viewport N] [--mission M]');
268
+ if (!out.ok)
269
+ process.exitCode = 1;
270
+ }
233
271
  async function zellijDispatch(root, args, json) {
234
272
  const missionId = readOption(args, '--mission', readOption(args, '--mission-id', 'latest') || 'latest') || 'latest';
235
273
  const slotId = normalizeZellijSlot(readOption(args, '--slot', 'slot-001'));
@@ -320,7 +358,7 @@ function printHelp(json) {
320
358
  schema: ZELLIJ_COMMAND_SCHEMA,
321
359
  subcommand: 'help',
322
360
  ok: true,
323
- usage: 'sks zellij status|update|repair|dispatch|send|focus-worker|worker-logs|dashboard|close-drained [--json]',
361
+ usage: 'sks zellij status|update|repair|dispatch|send|focus-worker|worker-logs|dashboard|pin|unpin|close-drained [--json]',
324
362
  subcommands: {
325
363
  status: 'Report Zellij runtime capability and interactive-route readiness.',
326
364
  update: 'Check the latest stable Zellij release; apply the upgrade with --yes (Homebrew).',
@@ -330,6 +368,8 @@ function printHelp(json) {
330
368
  'focus-worker': 'Focus a visible right-column worker pane by slot.',
331
369
  'worker-logs': 'Print stdout/stderr log paths for worker slots.',
332
370
  dashboard: 'Render the latest dashboard snapshot; --watch prints watch metadata.',
371
+ pin: 'Pin a dynamic worker slot to a viewport.',
372
+ unpin: 'Remove a worker slot pin from a viewport.',
333
373
  'close-drained': 'Close drained right-column panes.',
334
374
  capability: 'Alias for status.'
335
375
  }
@@ -345,6 +385,8 @@ function printHelp(json) {
345
385
  console.log(' sks zellij focus-worker slot-001 [--mission M] [--json]');
346
386
  console.log(' sks zellij worker-logs [slot-001] [--mission M] [--json]');
347
387
  console.log(' sks zellij dashboard [--mission M] [--watch] [--json]');
388
+ console.log(' sks zellij pin slot-001 [--viewport 2] [--mission M] [--json]');
389
+ console.log(' sks zellij unpin slot-001 [--viewport 2] [--mission M] [--json]');
348
390
  console.log(' sks zellij close-drained [--mission M] [--json]');
349
391
  }
350
392
  }
@@ -380,4 +422,15 @@ function resolveMissionId(root, requested) {
380
422
  return 'latest';
381
423
  }
382
424
  }
425
+ async function resolveLatestGenKey(root, missionId, rawSlot) {
426
+ const raw = String(rawSlot || '').trim();
427
+ if (raw.includes(':g'))
428
+ return raw;
429
+ const slotId = normalizeZellijSlot(raw);
430
+ const snapshot = await readZellijSlotTelemetrySnapshot(root, missionId).catch(() => null);
431
+ const candidates = Object.entries(snapshot?.slots || {})
432
+ .filter(([, row]) => normalizeZellijSlot(row.slot_id) === slotId)
433
+ .sort(([, a], [, b]) => Number(b.generation_index || 1) - Number(a.generation_index || 1));
434
+ return candidates[0]?.[0] || `${slotId}:g1`;
435
+ }
383
436
  //# sourceMappingURL=zellij.js.map