sneakoscope 2.0.15 → 2.0.17
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 +5 -3
- 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 +4 -4
- package/dist/bin/sks.js +1 -1
- package/dist/cli/command-registry.js +1 -1
- package/dist/commands/proof.js +21 -0
- package/dist/commands/zellij-slot-pane.js +7 -1
- package/dist/core/agents/agent-orchestrator.js +68 -3
- package/dist/core/agents/agent-scheduler.js +217 -86
- package/dist/core/agents/agent-schema.js +1 -1
- package/dist/core/agents/native-cli-session-swarm.js +97 -27
- package/dist/core/agents/native-cli-worker.js +56 -7
- package/dist/core/agents/parallel-runtime-proof.js +276 -0
- package/dist/core/agents/runtime-proof-summary.js +75 -0
- package/dist/core/codex-control/codex-task-runner.js +32 -4
- package/dist/core/codex-control/model-call-concurrency.js +106 -0
- package/dist/core/commands/naruto-command.js +65 -8
- package/dist/core/commands/team-command.js +6 -487
- package/dist/core/commands/team-legacy-observe-command.js +182 -0
- package/dist/core/db-safety.js +49 -6
- package/dist/core/feature-registry.js +4 -2
- package/dist/core/fsx.js +1 -1
- package/dist/core/git/git-worktree-capability.js +18 -0
- package/dist/core/git/git-worktree-manager.js +80 -0
- package/dist/core/git/git-worktree-pool.js +4 -0
- package/dist/core/hooks-runtime.js +41 -4
- package/dist/core/init.js +1 -0
- package/dist/core/mad-db/mad-db-capability.js +42 -2
- package/dist/core/mad-db/mad-db-ledger.js +14 -0
- package/dist/core/mad-db/mad-db-policy-resolver.js +2 -0
- package/dist/core/mad-db/mad-db-result-lifecycle.js +136 -0
- package/dist/core/naruto/naruto-concurrency-governor.js +14 -1
- package/dist/core/release/release-gate-affected-selector.js +47 -5
- package/dist/core/release/release-gate-dag.js +5 -1
- package/dist/core/release/release-gate-scheduler.js +2 -1
- package/dist/core/routes.js +3 -1
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-slot-pane-renderer.js +74 -1
- package/dist/core/zellij/zellij-slot-telemetry.js +81 -3
- package/dist/core/zellij/zellij-ui-mode.js +12 -2
- package/dist/scripts/prepublish-release-check-or-fast.js +3 -3
- package/dist/scripts/release-speed-summary.js +23 -1
- package/package.json +38 -3
- package/schemas/agents/parallel-runtime-proof.schema.json +79 -0
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 **2.0.
|
|
19
|
+
SKS **2.0.17** is the micro-hardening release for strict production PID proof, true scheduler active-time utilization, live Zellij slot telemetry freshness, Mad-DB result lifecycle audit, and unified runtime/release proof summaries.
|
|
20
20
|
|
|
21
21
|
What changed:
|
|
22
22
|
|
|
@@ -613,7 +613,9 @@ SKS_HERMES=1 sks status --json
|
|
|
613
613
|
|
|
614
614
|
Use these inside Codex App or another agent prompt. They are prompt commands, not terminal commands.
|
|
615
615
|
|
|
616
|
-
Common prompts: `$Team`, `$From-Chat-IMG`, `$with-local-llm-on`, `$with-local-llm-off`, `$DFix`, `$Answer`, `$SKS`, `$QA-LOOP`, `$PPT`, `$Computer-Use`/`$CU`, `$Goal`, `$Research`, `$AutoResearch`, `$DB`, `$MAD-SKS`, `$GX`, `$Wiki`, and `$Help`.
|
|
616
|
+
Common prompts: `$Team`, `$From-Chat-IMG`, `$with-local-llm-on`, `$with-local-llm-off`, `$DFix`, `$Answer`, `$SKS`, `$QA-LOOP`, `$PPT`, `$Computer-Use`/`$CU`, `$Goal`, `$Research`, `$AutoResearch`, `$DB`, `$MAD-SKS`, `$MAD-DB`, `$GX`, `$Wiki`, and `$Help`.
|
|
617
|
+
|
|
618
|
+
`$MAD-DB` is the prompt-visible Mad-DB alias for one-cycle DB break-glass work. It maps to the same guarded MAD-SKS permission route, while the terminal lifecycle remains `sks mad-db status|enable|revoke`; it is not a permanent DB unlock and catastrophic DB safeguards remain active.
|
|
617
619
|
|
|
618
620
|
## Common Workflows
|
|
619
621
|
|
|
@@ -759,7 +761,7 @@ npm run release:check
|
|
|
759
761
|
npm run publish:dry
|
|
760
762
|
```
|
|
761
763
|
|
|
762
|
-
`release:check` runs the change-aware affected release gate for ordinary local checks. Publish readiness uses `release:check:full`, which runs the full release DAG and writes a source digest stamp under `.sneakoscope/reports/` so publish commands can verify the same source/dist state. The DAG preserves the 1.18 baseline gates and adds Codex 0.136 compatibility, inherited Codex 0.135/0.134 runner truth, patch swarm runtime truth, transaction journaling, serial conflict rebase, strict strategy-to-patch proof, rollback command proof, Native CLI Session Swarm 5/10/20-process proof, Real Worker Backend Router proof, Codex child overlap proof, model-authored patch-envelope separation, Zellij layout/pane/screen/socket-dir proof, no-subagent-scaling proof, Fast mode default/worker/Codex/MAD propagation proof, Appshots attachment provenance, MCP runtime overlap evidence, task graph expansion, schema-bound follow-up work, actual Agent/Team/Research/QA route blackboxes, scheduler proof hardening, Source Intelligence propagation, Goal mode propagation checks, slot telemetry, update notice, MAD-DB, and Naruto SSOT gates. Broader live gates remain explicit scripts such as `release:real-check`; real Codex patch smoke, real Codex parallel worker proof, and real Zellij proof are optional unless their `SKS_REQUIRE_REAL_*` or `SKS_REQUIRE_ZELLIJ=1` environment variables are set. Generate the human-readable registry with `sks features inventory --write-docs`. Plain `npm publish` uses the `latest` dist-tag.
|
|
764
|
+
`release:check` runs the change-aware affected release gate for ordinary local checks. Publish readiness uses `release:check:full`, which runs the full release DAG and writes a source digest stamp under `.sneakoscope/reports/` so publish commands can verify the same source/dist state. The DAG preserves the 1.18 baseline gates and adds Codex 0.136 compatibility, inherited Codex 0.135/0.134 runner truth, patch swarm runtime truth, transaction journaling, serial conflict rebase, strict strategy-to-patch proof, rollback command proof, Native CLI Session Swarm 5/10/20-process proof, Real Worker Backend Router proof, Codex child overlap proof, model-authored patch-envelope separation, Zellij layout/pane/screen/socket-dir proof, no-subagent-scaling proof, Fast mode default/worker/Codex/MAD propagation proof, Appshots attachment provenance, MCP runtime overlap evidence, task graph expansion, schema-bound follow-up work, actual Agent/Team/Research/QA route blackboxes, scheduler proof hardening, Source Intelligence propagation, Goal mode propagation checks, slot telemetry, update notice, MAD-DB, and Naruto SSOT gates. Broader live gates remain explicit scripts such as `release:real-check`; real Codex patch smoke, real Codex parallel worker proof, and real Zellij proof are optional unless their `SKS_REQUIRE_REAL_*` or `SKS_REQUIRE_ZELLIJ=1` environment variables are set. Generate the human-readable registry with `sks features inventory --write-docs`. Plain `npm publish` uses the `latest` dist-tag. `npm run publish:dry` runs `release:check:full`, verifies the fresh stamp, and then performs provenance/registry and npm dry-run checks. npm's `prepublishOnly` uses `prepublish-release-check-or-fast` to accept that current stamp before the real publish; if the stamp is missing or stale, it runs `release:check:full` once before continuing.
|
|
763
765
|
|
|
764
766
|
Version bumps are manual. Run `sks versioning bump` only when preparing release metadata; SKS will not create `.git/hooks/pre-commit` or auto-bump during ordinary commits.
|
|
765
767
|
|
|
@@ -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 2.0.
|
|
7
|
+
Some("--version") => println!("sks-rs 2.0.17"),
|
|
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": "2.0.
|
|
5
|
-
"source_digest": "
|
|
6
|
-
"source_file_count":
|
|
7
|
-
"built_at_source_time":
|
|
4
|
+
"package_version": "2.0.17",
|
|
5
|
+
"source_digest": "1c6ef84350a97acdfd592ae544ec9054e2ee0a997076e725bc99b771c4693cf2",
|
|
6
|
+
"source_file_count": 2201,
|
|
7
|
+
"built_at_source_time": 1780974441836
|
|
8
8
|
}
|
package/dist/bin/sks.js
CHANGED
|
@@ -119,7 +119,7 @@ export const COMMANDS = {
|
|
|
119
119
|
commit: entry('stable', 'Create a simple git commit', 'dist/commands/commit.js', directCommand(() => import('../commands/commit.js'), 'dist/commands/commit.js')),
|
|
120
120
|
'commit-and-push': entry('stable', 'Create a simple git commit and push', 'dist/commands/commit-and-push.js', directCommand(() => import('../commands/commit-and-push.js'), 'dist/commands/commit-and-push.js')),
|
|
121
121
|
dfix: entry('stable', 'Run DFix diagnose/plan/patch/verify loop', 'dist/core/commands/dfix-command.js', commandArgsCommand(() => import('../core/commands/dfix-command.js'), 'dfixCommand', 'dist/core/commands/dfix-command.js')),
|
|
122
|
-
team: entry('beta', '
|
|
122
|
+
team: entry('beta', 'Deprecated alias. New execution redirects to Naruto; legacy observe/watch remains.', 'dist/core/commands/team-command.js', argsCommand(() => import('../core/commands/team-command.js'), 'team', 'dist/core/commands/team-command.js')),
|
|
123
123
|
agent: entry('beta', 'Run native multi-session agent missions', 'dist/core/commands/agent-command.js', argsCommand(() => import('../core/commands/agent-command.js'), 'agentCommand', 'dist/core/commands/agent-command.js')),
|
|
124
124
|
'with-local-llm': entry('beta', 'Enable or inspect local Ollama worker backend', 'dist/core/commands/local-model-command.js', argsCommand(() => import('../core/commands/local-model-command.js'), 'localModelCommand', 'dist/core/commands/local-model-command.js')),
|
|
125
125
|
naruto: entry('labs', 'Run $Naruto shadow-clone swarm (up to 100 parallel sessions)', 'dist/core/commands/naruto-command.js', argsCommand(() => import('../core/commands/naruto-command.js'), 'narutoCommand', 'dist/core/commands/naruto-command.js')),
|
package/dist/commands/proof.js
CHANGED
|
@@ -8,10 +8,20 @@ import { writeRouteCompletionProof } from '../core/proof/route-adapter.js';
|
|
|
8
8
|
import { finalizeRouteWithProof } from '../core/proof/route-finalizer.js';
|
|
9
9
|
import { renderProofMarkdown, writeCompletionProof } from '../core/proof/proof-writer.js';
|
|
10
10
|
import { validateCompletionProof } from '../core/proof/validation.js';
|
|
11
|
+
import { buildRuntimeProofSummary, renderRuntimeProofSummary } from '../core/agents/runtime-proof-summary.js';
|
|
11
12
|
export async function run(_command, args = []) {
|
|
12
13
|
const root = await projectRoot();
|
|
13
14
|
const action = args[0] || 'show';
|
|
14
15
|
const rest = args.slice(1);
|
|
16
|
+
if (action === 'latest' && !flag(args, '--completion')) {
|
|
17
|
+
const runtime = await tryRuntimeProofSummary(root);
|
|
18
|
+
if (runtime) {
|
|
19
|
+
if (flag(args, '--json'))
|
|
20
|
+
return printJson(runtime);
|
|
21
|
+
console.log(renderRuntimeProofSummary(runtime));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
15
25
|
if (action === 'show' || action === 'latest') {
|
|
16
26
|
const proof = await withFreshSummaries(root, await readLatestProof(root));
|
|
17
27
|
if (flag(args, '--json') || action === 'latest')
|
|
@@ -122,6 +132,17 @@ export async function run(_command, args = []) {
|
|
|
122
132
|
console.error('Usage: sks proof show|latest|validate|route <mission-id|latest>|finalize <mission-id|latest> [--route route] [--strict] [--mock] [--json]|export --md|repair latest|smoke [--json]');
|
|
123
133
|
process.exitCode = 1;
|
|
124
134
|
}
|
|
135
|
+
async function tryRuntimeProofSummary(root) {
|
|
136
|
+
try {
|
|
137
|
+
const summary = await buildRuntimeProofSummary(root, 'latest');
|
|
138
|
+
if (summary.blockers.includes('parallel_runtime_proof_missing') && summary.blockers.includes('agent_scheduler_state_missing'))
|
|
139
|
+
return null;
|
|
140
|
+
return summary;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
125
146
|
async function withFreshSummaries(root, proof) {
|
|
126
147
|
const evidence = await collectProofEvidence(root);
|
|
127
148
|
return {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { renderZellijSlotPaneFromArtifacts } from '../core/zellij/zellij-slot-pane-renderer.js';
|
|
1
|
+
import { renderZellijSlotPaneFromArtifacts, renderZellijSlotPaneStatusFromArtifacts } from '../core/zellij/zellij-slot-pane-renderer.js';
|
|
2
2
|
export async function run(_command = 'zellij-slot-pane', args = []) {
|
|
3
3
|
const artifactDir = readOption(args, '--artifact-dir', process.cwd()) || process.cwd();
|
|
4
4
|
const artifactRoot = readOption(args, '--artifact-root', artifactDir) || artifactDir;
|
|
@@ -9,7 +9,13 @@ export async function run(_command = 'zellij-slot-pane', args = []) {
|
|
|
9
9
|
const role = readOption(args, '--role', null);
|
|
10
10
|
const mode = readOption(args, '--mode', 'compact-slots');
|
|
11
11
|
const watch = hasFlag(args, '--watch');
|
|
12
|
+
const json = hasFlag(args, '--json');
|
|
12
13
|
const intervalMs = Math.max(250, Number(readOption(args, '--interval-ms', '1000') || 1000));
|
|
14
|
+
if (json) {
|
|
15
|
+
const status = await renderZellijSlotPaneStatusFromArtifacts({ artifactDir, artifactRoot, missionId, slotId, generationIndex });
|
|
16
|
+
console.log(JSON.stringify(status, null, 2));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
13
19
|
for (;;) {
|
|
14
20
|
const text = await renderZellijSlotPaneFromArtifacts({ artifactDir, artifactRoot, missionId, slotId, generationIndex, backend, role, mode });
|
|
15
21
|
process.stdout.write('\x1Bc' + text + '\n');
|
|
@@ -54,7 +54,7 @@ import { CODEX_AGENT_WORKER_RESULT_SCHEMA_ID, codexAgentWorkerResultSchema } fro
|
|
|
54
54
|
import { resolveLocalCollaborationPolicy, localCollaborationParticipated } from '../local-llm/local-collaboration-policy.js';
|
|
55
55
|
import { runFinalGptReviewStage } from '../pipeline/final-gpt-review-stage.js';
|
|
56
56
|
import { selectFinalGptPatchSource } from '../pipeline/final-gpt-patch-stage.js';
|
|
57
|
-
import { allocateWorkerWorktree } from '../git/git-worktree-manager.js';
|
|
57
|
+
import { allocateWorkerWorktree, allocateWorkerWorktreesBatch } from '../git/git-worktree-manager.js';
|
|
58
58
|
import { exportGitWorktreeDiff } from '../git/git-worktree-diff.js';
|
|
59
59
|
import { buildGitWorktreePatchEnvelope } from '../git/git-worktree-patch-envelope.js';
|
|
60
60
|
import { checkpointWorkerWorktree } from '../git/git-worktree-checkpoint.js';
|
|
@@ -63,6 +63,7 @@ import { createGitIntegrationWorktree } from '../git/git-integration-worktree.js
|
|
|
63
63
|
import { applyGitWorktreeMergeQueue } from '../git/git-worktree-merge-queue.js';
|
|
64
64
|
import { crossRebaseIdleWorktrees } from '../git/git-worktree-cross-rebase.js';
|
|
65
65
|
import { gitOutputLine, runGitCommand } from '../git/git-worktree-runner.js';
|
|
66
|
+
import { writeParallelRuntimeProof } from './parallel-runtime-proof.js';
|
|
66
67
|
export async function runNativeAgentOrchestrator(opts = {}) {
|
|
67
68
|
const root = path.resolve(opts.root || process.cwd());
|
|
68
69
|
const prompt = String(opts.prompt || 'Native agent run');
|
|
@@ -289,9 +290,46 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
289
290
|
diffs: [],
|
|
290
291
|
checkpoints: [],
|
|
291
292
|
cleanup: [],
|
|
293
|
+
prewarmed_allocations: [],
|
|
292
294
|
blockers: []
|
|
293
295
|
};
|
|
294
296
|
await writeJsonAtomic(path.join(ledgerRoot, 'agent-git-worktree-runtime.json'), gitWorktreeRuntime);
|
|
297
|
+
const preparedWorktreeAllocations = new Map();
|
|
298
|
+
if (gitWorktreePolicy?.mode === 'git-worktree') {
|
|
299
|
+
const writeSlices = uniqueWritableSlicesForWorktrees(partition.slices, Math.max(1, targetActiveSlots));
|
|
300
|
+
if (writeSlices.length) {
|
|
301
|
+
const prewarmed = await allocateWorkerWorktreesBatch({
|
|
302
|
+
root: gitWorktreePolicy.main_repo_root || root,
|
|
303
|
+
missionId,
|
|
304
|
+
workers: writeSlices.map((slice, index) => ({
|
|
305
|
+
workerId: String(slice.owner_agent_id || slice.owner || `worker-${index + 1}`),
|
|
306
|
+
slotId: String(slice.owner_agent_id || slice.owner || `slot-${index + 1}`),
|
|
307
|
+
generationIndex: 1
|
|
308
|
+
})),
|
|
309
|
+
maxParallel: Math.min(targetActiveSlots, Number(process.env.SKS_NARUTO_GIT_WORKTREE_CAP || targetActiveSlots))
|
|
310
|
+
}).catch((err) => {
|
|
311
|
+
gitWorktreeRuntime.blockers.push('git_worktree_batch_prewarm_failed:' + (err instanceof Error ? err.message : String(err)));
|
|
312
|
+
gitWorktreeRuntime.ok = false;
|
|
313
|
+
return [];
|
|
314
|
+
});
|
|
315
|
+
gitWorktreeRuntime.prewarmed_allocations = prewarmed.map((allocation) => ({
|
|
316
|
+
worker_id: allocation.worker_id,
|
|
317
|
+
slot_id: allocation.slot_id,
|
|
318
|
+
ok: allocation.ok,
|
|
319
|
+
worktree_path: allocation.worktree_path,
|
|
320
|
+
branch: allocation.branch,
|
|
321
|
+
blockers: allocation.blockers
|
|
322
|
+
}));
|
|
323
|
+
for (const allocation of prewarmed) {
|
|
324
|
+
if (allocation.ok)
|
|
325
|
+
preparedWorktreeAllocations.set(String(allocation.worker_id), allocation);
|
|
326
|
+
else
|
|
327
|
+
gitWorktreeRuntime.blockers.push(...allocation.blockers);
|
|
328
|
+
}
|
|
329
|
+
gitWorktreeRuntime.ok = gitWorktreeRuntime.blockers.length === 0;
|
|
330
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'agent-git-worktree-runtime.json'), gitWorktreeRuntime);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
295
333
|
const nativeCliSwarm = createNativeCliSessionSwarmRecorder(ledgerRoot, {
|
|
296
334
|
missionId,
|
|
297
335
|
requestedAgents: Number(opts.agents || roster.agent_count || targetActiveSlots),
|
|
@@ -329,7 +367,8 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
329
367
|
agent,
|
|
330
368
|
slice,
|
|
331
369
|
policy: gitWorktreePolicy,
|
|
332
|
-
runtime: gitWorktreeRuntime
|
|
370
|
+
runtime: gitWorktreeRuntime,
|
|
371
|
+
preparedAllocation: preparedWorktreeAllocations.get(String(agent.id || '')) || null
|
|
333
372
|
});
|
|
334
373
|
const runtimeAgent = workerWorktree ? { ...agent, worktree: workerWorktree.context } : agent;
|
|
335
374
|
const runtimeSlice = workerWorktree ? { ...slice, worktree: workerWorktree.context } : slice;
|
|
@@ -432,6 +471,15 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
432
471
|
}
|
|
433
472
|
});
|
|
434
473
|
await nativeCliSwarm.finalize();
|
|
474
|
+
const parallelRuntimeProof = await writeParallelRuntimeProof(ledgerRoot, missionId, {
|
|
475
|
+
requestedWorkers: Number(opts.agents || roster.agent_count || targetActiveSlots),
|
|
476
|
+
targetActiveSlots,
|
|
477
|
+
visiblePanes: visualLaneCount,
|
|
478
|
+
expectedWorkerRuntimeMs: targetActiveSlots >= 10 ? 8000 : targetActiveSlots >= 2 ? 2000 : 25,
|
|
479
|
+
minActiveWorkers: Math.min(targetActiveSlots, desiredWorkItemCount),
|
|
480
|
+
proofMode: opts.mock === true ? 'mock-process' : 'production',
|
|
481
|
+
requireWorkerPids: opts.nativeCliSwarm !== false && targetActiveSlots >= 16
|
|
482
|
+
});
|
|
435
483
|
const results = scheduler.results;
|
|
436
484
|
const nativeCliSessionProof = await writeNativeCliSessionProof(ledgerRoot, {
|
|
437
485
|
requestedAgents: Number(opts.agents || roster.agent_count || targetActiveSlots),
|
|
@@ -600,6 +648,7 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
600
648
|
gpt_final_arbiter: gptFinalArbiter,
|
|
601
649
|
final_gpt_patch_stage: finalGptPatchStage,
|
|
602
650
|
patch_swarm: patchSwarm,
|
|
651
|
+
parallel_runtime_proof: parallelRuntimeProof,
|
|
603
652
|
proof
|
|
604
653
|
};
|
|
605
654
|
}
|
|
@@ -620,6 +669,22 @@ function withFinalGptPatchEnvelopes(results, patchEnvelopes = []) {
|
|
|
620
669
|
next[0] = { ...next[0], patch_envelopes: patchEnvelopes };
|
|
621
670
|
return next;
|
|
622
671
|
}
|
|
672
|
+
function uniqueWritableSlicesForWorktrees(slices = [], limit) {
|
|
673
|
+
const selected = [];
|
|
674
|
+
const seenOwners = new Set();
|
|
675
|
+
for (const slice of Array.isArray(slices) ? slices : []) {
|
|
676
|
+
if (!Array.isArray(slice?.write_paths) || slice.write_paths.length === 0)
|
|
677
|
+
continue;
|
|
678
|
+
const owner = String(slice.owner_agent_id || slice.owner || slice.id || '');
|
|
679
|
+
if (!owner || seenOwners.has(owner))
|
|
680
|
+
continue;
|
|
681
|
+
seenOwners.add(owner);
|
|
682
|
+
selected.push(slice);
|
|
683
|
+
if (selected.length >= Math.max(1, limit))
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
686
|
+
return selected;
|
|
687
|
+
}
|
|
623
688
|
function applyNarutoWorkGraphToPartition(partition, graph, roster, targetActiveSlots, parentPrompt = '') {
|
|
624
689
|
const activeRoster = (Array.isArray(roster?.roster) ? roster.roster : []).slice(0, Math.max(1, targetActiveSlots));
|
|
625
690
|
const activeAgentIds = new Set(activeRoster.map((row) => String(row.id || '')).filter(Boolean));
|
|
@@ -873,7 +938,7 @@ async function prepareWorkerGitWorktree(input) {
|
|
|
873
938
|
if (!sliceHasWritePaths && !agentWriteCapable)
|
|
874
939
|
return null;
|
|
875
940
|
const generationIndex = Math.max(1, Math.floor(Number(input.agent.generation_index || 1)));
|
|
876
|
-
const allocation = await allocateWorkerWorktree({
|
|
941
|
+
const allocation = input.preparedAllocation || await allocateWorkerWorktree({
|
|
877
942
|
repoRoot: input.policy.main_repo_root || input.root,
|
|
878
943
|
missionId: input.missionId,
|
|
879
944
|
workerId: String(input.agent.id || input.slice.id || 'worker'),
|