sneakoscope 2.0.4 → 2.0.6
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 +18 -11
- 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/build-manifest.json +78 -8
- package/dist/cli/install-helpers.js +23 -0
- package/dist/commands/codex-app.js +25 -3
- package/dist/commands/doctor.js +33 -4
- package/dist/commands/mad-sks.js +2 -2
- package/dist/core/agents/agent-orchestrator.js +22 -3
- package/dist/core/agents/agent-proof-evidence.js +59 -2
- package/dist/core/agents/agent-roster.js +35 -6
- package/dist/core/agents/agent-schema.js +1 -1
- package/dist/core/agents/agent-worker-pipeline.js +9 -1
- package/dist/core/agents/native-worker-backend-router.js +50 -10
- package/dist/core/agents/ollama-worker-config.js +164 -15
- package/dist/core/codex/codex-0-137-compat.js +119 -0
- package/dist/core/codex-app.js +124 -2
- package/dist/core/codex-control/codex-control-proof.js +4 -1
- package/dist/core/codex-control/codex-sdk-capability.js +1 -1
- package/dist/core/codex-control/codex-task-runner.js +329 -5
- package/dist/core/codex-control/python-codex-sdk-adapter.js +197 -0
- package/dist/core/codex-control/python-codex-sdk-event-translator.js +14 -0
- package/dist/core/commands/local-model-command.js +65 -19
- package/dist/core/commands/naruto-command.js +124 -8
- package/dist/core/commands/run-command.js +1 -1
- package/dist/core/doctor/doctor-readiness-matrix.js +21 -2
- package/dist/core/fsx.js +1 -1
- package/dist/core/hooks-runtime.js +2 -233
- package/dist/core/init.js +8 -8
- package/dist/core/local-llm/local-llm-backpressure.js +20 -0
- package/dist/core/local-llm/local-llm-capability.js +29 -0
- package/dist/core/local-llm/local-llm-client.js +100 -0
- package/dist/core/local-llm/local-llm-config.js +6 -1
- package/dist/core/local-llm/local-llm-context-cache.js +21 -0
- package/dist/core/local-llm/local-llm-control-adapter.js +101 -0
- package/dist/core/local-llm/local-llm-json-repair.js +52 -0
- package/dist/core/local-llm/local-llm-metrics.js +42 -0
- package/dist/core/local-llm/local-llm-ollama-client.js +67 -0
- package/dist/core/local-llm/local-llm-openai-compatible-client.js +30 -0
- package/dist/core/local-llm/local-llm-prompt-cache.js +12 -0
- package/dist/core/local-llm/local-llm-scheduler.js +29 -0
- package/dist/core/local-llm/local-llm-schema-enforcer.js +15 -0
- package/dist/core/local-llm/local-llm-smoke.js +83 -0
- package/dist/core/local-llm/local-llm-warmup.js +20 -0
- package/dist/core/local-llm/local-worker-eligibility.js +27 -0
- package/dist/core/naruto/hardware-capacity-probe.js +36 -0
- package/dist/core/naruto/naruto-active-pool.js +134 -0
- package/dist/core/naruto/naruto-backpressure.js +13 -0
- package/dist/core/naruto/naruto-concurrency-governor.js +65 -0
- package/dist/core/naruto/naruto-finalizer.js +18 -0
- package/dist/core/naruto/naruto-generation-scheduler.js +18 -0
- package/dist/core/naruto/naruto-gpt-final-pack.js +49 -0
- package/dist/core/naruto/naruto-parallel-patch-apply.js +95 -0
- package/dist/core/naruto/naruto-patch-transaction-batch.js +42 -0
- package/dist/core/naruto/naruto-role-policy.js +107 -0
- package/dist/core/naruto/naruto-verification-dag.js +42 -0
- package/dist/core/naruto/naruto-verification-pool.js +18 -0
- package/dist/core/naruto/naruto-work-graph.js +198 -0
- package/dist/core/naruto/naruto-work-item.js +40 -0
- package/dist/core/naruto/naruto-work-stealing.js +11 -0
- package/dist/core/naruto/resource-pressure-monitor.js +32 -0
- package/dist/core/pipeline/finalize-pipeline-result.js +58 -0
- package/dist/core/pipeline/gpt-final-required.js +12 -0
- package/dist/core/pipeline-internals/runtime-core.js +1 -1
- package/dist/core/ppt.js +31 -8
- package/dist/core/product-design-app-server.js +410 -0
- package/dist/core/product-design-plugin.js +139 -0
- package/dist/core/prompt/prompt-placeholder-guard.js +30 -0
- package/dist/core/router/capability-card.js +13 -0
- package/dist/core/router/route-cache.js +3 -0
- package/dist/core/router/ultra-router.js +2 -1
- package/dist/core/routes.js +12 -12
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-lane-runtime.js +2 -2
- package/dist/core/zellij/zellij-naruto-dashboard.js +36 -0
- package/dist/core/zellij/zellij-worker-pane-manager.js +4 -4
- package/dist/scripts/blackbox-command-import-smoke.js +10 -1
- package/dist/scripts/check-package-boundary.js +12 -3
- package/dist/scripts/codex-0-137-compat-check.js +27 -0
- package/dist/scripts/codex-environment-scoped-approvals-check.js +10 -0
- package/dist/scripts/codex-plugin-list-json-check.js +8 -0
- package/dist/scripts/codex-thread-runtime-choice-check.js +10 -0
- package/dist/scripts/local-collab-all-pipelines-final-gpt-check.js +21 -0
- package/dist/scripts/local-llm-all-pipelines-check.js +11 -0
- package/dist/scripts/local-llm-cache-performance-check.js +10 -0
- package/dist/scripts/local-llm-capability-check.js +14 -0
- package/dist/scripts/local-llm-smoke-check.js +23 -0
- package/dist/scripts/local-llm-structured-output-check.js +11 -0
- package/dist/scripts/local-llm-throughput-check.js +10 -0
- package/dist/scripts/local-llm-tool-call-repair-check.js +10 -0
- package/dist/scripts/local-llm-warmup-check.js +11 -0
- package/dist/scripts/naruto-active-pool-check.js +39 -0
- package/dist/scripts/naruto-concurrency-governor-check.js +52 -0
- package/dist/scripts/naruto-gpt-final-pack-check.js +34 -0
- package/dist/scripts/naruto-parallel-patch-apply-check.js +41 -0
- package/dist/scripts/naruto-readonly-routing-check.js +116 -0
- package/dist/scripts/naruto-real-local-gpt-final-smoke.js +16 -0
- package/dist/scripts/naruto-role-distribution-check.js +23 -0
- package/dist/scripts/naruto-shadow-clone-swarm-check.js +13 -0
- package/dist/scripts/naruto-verification-pool-check.js +36 -0
- package/dist/scripts/naruto-work-graph-check.js +24 -0
- package/dist/scripts/naruto-zellij-massive-ui-check.js +23 -0
- package/dist/scripts/product-design-auto-install-check.js +119 -0
- package/dist/scripts/product-design-plugin-routing-check.js +101 -0
- package/dist/scripts/prompt-placeholder-guard-check.js +33 -0
- package/dist/scripts/python-codex-sdk-all-pipelines-check.js +47 -0
- package/dist/scripts/python-codex-sdk-capability-check.js +75 -0
- package/dist/scripts/python-codex-sdk-sandbox-policy-check.js +10 -0
- package/dist/scripts/python-codex-sdk-stream-bridge-check.js +12 -0
- package/dist/scripts/release-parallel-check.js +16 -2
- package/dist/scripts/release-provenance-check.js +21 -0
- package/dist/scripts/release-real-check.js +5 -0
- package/dist/scripts/zellij-worker-pane-manager-check.js +1 -1
- package/package.json +36 -4
- package/schemas/local-llm/local-model-config.schema.json +74 -0
- package/schemas/naruto/naruto-concurrency-governor.schema.json +21 -0
- package/schemas/naruto/naruto-work-graph.schema.json +22 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { resolveOllamaWorkerConfig, writeLocalModelConfig, readLocalModelConfig } from '../agents/ollama-worker-config.js';
|
|
1
|
+
import { applyLocalLlmSmokeResult, normalizeProvider, resolveOllamaWorkerConfig, writeLocalModelConfig, readLocalModelConfig } from '../agents/ollama-worker-config.js';
|
|
2
|
+
import { detectInstalledLocalModelCandidate, probeLocalLlmEndpoint } from '../local-llm/local-llm-client.js';
|
|
3
|
+
import { runLocalLlmGenerationSmoke, localLlmSmokeSchema } from '../local-llm/local-llm-smoke.js';
|
|
2
4
|
export async function localModelCommand(args = []) {
|
|
3
5
|
const action = normalizeLocalModelAction(args[0]);
|
|
4
6
|
if (action === 'enable')
|
|
@@ -28,16 +30,62 @@ function normalizeLocalModelAction(value) {
|
|
|
28
30
|
async function enable(args) {
|
|
29
31
|
const model = readOption(args, '--model', firstPositional(args) || '');
|
|
30
32
|
const baseUrl = readOption(args, '--base-url', '');
|
|
33
|
+
const provider = readOption(args, '--provider', '');
|
|
31
34
|
const think = readBoolFlag(args, '--think', '--no-think');
|
|
32
|
-
const
|
|
35
|
+
const skipSmoke = args.includes('--skip-smoke') || process.env.SKS_LOCAL_LLM_TOGGLE_ONLY === '1';
|
|
36
|
+
const patch = { enabled: true, status: 'enabled_unverified' };
|
|
37
|
+
const explicitConfig = Boolean(model || baseUrl || provider);
|
|
38
|
+
let detection = null;
|
|
39
|
+
if (!explicitConfig) {
|
|
40
|
+
detection = await detectInstalledLocalModelCandidate();
|
|
41
|
+
if (!detection) {
|
|
42
|
+
const config = await writeLocalModelConfig({ enabled: false, blockers: ['local_model_not_found'] });
|
|
43
|
+
process.exitCode = 1;
|
|
44
|
+
return {
|
|
45
|
+
schema: 'sks.local-model-command.v1',
|
|
46
|
+
ok: false,
|
|
47
|
+
action: 'enable',
|
|
48
|
+
message: '확인해보니 로컬 모델이 존재하지 않아 실행할 수 없습니다.',
|
|
49
|
+
config,
|
|
50
|
+
detection: null,
|
|
51
|
+
blockers: ['local_model_not_found']
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
patch.provider = detection.provider;
|
|
55
|
+
patch.model = detection.model;
|
|
56
|
+
patch.base_url = detection.base_url;
|
|
57
|
+
patch.endpoint = detection.endpoint;
|
|
58
|
+
}
|
|
59
|
+
if (provider)
|
|
60
|
+
patch.provider = normalizeProvider(provider);
|
|
33
61
|
if (model)
|
|
34
62
|
patch.model = model;
|
|
35
|
-
if (baseUrl)
|
|
63
|
+
if (baseUrl) {
|
|
36
64
|
patch.base_url = baseUrl;
|
|
65
|
+
patch.endpoint = baseUrl;
|
|
66
|
+
}
|
|
37
67
|
if (think !== null)
|
|
38
68
|
patch.think = think;
|
|
39
69
|
const config = await writeLocalModelConfig(patch);
|
|
40
|
-
|
|
70
|
+
const smoke = skipSmoke
|
|
71
|
+
? { ok: false, skipped: true, status: 'enabled_unverified', reason: 'operator_skip_smoke', schema_valid: false, blockers: ['operator_skip_smoke'] }
|
|
72
|
+
: await runLocalLlmGenerationSmoke(config, {
|
|
73
|
+
prompt: 'Return strict JSON: {"status":"ok","summary":"local smoke passed"}',
|
|
74
|
+
schema: localLlmSmokeSchema,
|
|
75
|
+
timeoutMs: 20_000
|
|
76
|
+
});
|
|
77
|
+
const next = await writeLocalModelConfig(applyLocalLlmSmokeResult(config, smoke));
|
|
78
|
+
if (!skipSmoke && smoke.ok !== true)
|
|
79
|
+
process.exitCode = 1;
|
|
80
|
+
return {
|
|
81
|
+
schema: 'sks.local-model-command.v1',
|
|
82
|
+
ok: skipSmoke ? true : smoke.ok === true,
|
|
83
|
+
action: 'enable',
|
|
84
|
+
config: next,
|
|
85
|
+
detection,
|
|
86
|
+
smoke,
|
|
87
|
+
blockers: next.blockers
|
|
88
|
+
};
|
|
41
89
|
}
|
|
42
90
|
async function disable() {
|
|
43
91
|
const config = await writeLocalModelConfig({ enabled: false });
|
|
@@ -55,37 +103,35 @@ async function setModel(args) {
|
|
|
55
103
|
async function status() {
|
|
56
104
|
const config = await readLocalModelConfig();
|
|
57
105
|
const resolved = await resolveOllamaWorkerConfig();
|
|
58
|
-
const api = await
|
|
106
|
+
const api = await probeLocalLlmEndpoint(resolved);
|
|
59
107
|
return { schema: 'sks.local-model-command.v1', ok: true, action: 'status', config, resolved, api };
|
|
60
108
|
}
|
|
61
|
-
async function probeOllama(baseUrl) {
|
|
62
|
-
try {
|
|
63
|
-
const response = await fetch(`${baseUrl}/api/version`, { signal: AbortSignal.timeout(3000) });
|
|
64
|
-
const text = await response.text();
|
|
65
|
-
return { ok: response.ok, status: response.status, data: response.ok ? JSON.parse(text) : null };
|
|
66
|
-
}
|
|
67
|
-
catch (error) {
|
|
68
|
-
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
109
|
function emit(result, args) {
|
|
72
110
|
if (args.includes('--json')) {
|
|
73
111
|
console.log(JSON.stringify(result, null, 2));
|
|
74
112
|
return result;
|
|
75
113
|
}
|
|
76
114
|
if (result.ok !== true) {
|
|
115
|
+
if (result.message)
|
|
116
|
+
console.log(result.message);
|
|
77
117
|
console.log(`Local model: blocked (${(result.blockers || []).join(', ') || 'unknown'})`);
|
|
78
118
|
return result;
|
|
79
119
|
}
|
|
80
120
|
const config = result.config || result.resolved || {};
|
|
81
121
|
console.log(`Local model: ${config.enabled ? 'enabled' : 'disabled'}`);
|
|
82
|
-
console.log(`Provider:
|
|
122
|
+
console.log(`Provider: ${config.provider || 'unknown'}`);
|
|
83
123
|
console.log(`Model: ${config.model || 'unknown'}`);
|
|
84
124
|
console.log(`Base URL: ${config.base_url || config.baseUrl || 'unknown'}`);
|
|
125
|
+
if (config.status)
|
|
126
|
+
console.log(`Status: ${config.status}`);
|
|
127
|
+
if (result.detection)
|
|
128
|
+
console.log(`Detected: ${result.detection.source}`);
|
|
129
|
+
if (config.last_smoke?.result_path)
|
|
130
|
+
console.log(`Smoke: ${config.last_smoke.ok ? 'ok' : 'failed'} ${config.last_smoke.result_path}`);
|
|
85
131
|
if (typeof config.think === 'boolean')
|
|
86
132
|
console.log(`Think: ${config.think ? 'enabled' : 'disabled'}`);
|
|
87
133
|
if (result.api)
|
|
88
|
-
console.log(`
|
|
134
|
+
console.log(`Local model API: ${result.api.ok ? 'ok' : 'not reachable'}`);
|
|
89
135
|
return result;
|
|
90
136
|
}
|
|
91
137
|
function readOption(args, name, fallback) {
|
|
@@ -105,12 +151,12 @@ function readBoolFlag(args, trueName, falseName) {
|
|
|
105
151
|
function firstPositional(args = []) {
|
|
106
152
|
for (let i = 0; i < args.length; i += 1) {
|
|
107
153
|
const arg = String(args[i] || '');
|
|
108
|
-
if (arg === '--model' || arg === '--base-url') {
|
|
154
|
+
if (arg === '--model' || arg === '--base-url' || arg === '--provider') {
|
|
109
155
|
if (args[i + 1] && !String(args[i + 1]).startsWith('--'))
|
|
110
156
|
i += 1;
|
|
111
157
|
continue;
|
|
112
158
|
}
|
|
113
|
-
if (arg.startsWith('--model=') || arg.startsWith('--base-url='))
|
|
159
|
+
if (arg.startsWith('--model=') || arg.startsWith('--base-url=') || arg.startsWith('--provider='))
|
|
114
160
|
continue;
|
|
115
161
|
if (!arg.startsWith('--'))
|
|
116
162
|
return arg;
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { createMission, findLatestMission, loadMission } from '../mission.js';
|
|
3
|
-
import { readJson, sksRoot } from '../fsx.js';
|
|
3
|
+
import { readJson, sksRoot, writeJsonAtomic } from '../fsx.js';
|
|
4
4
|
import { runNativeAgentOrchestrator } from '../agents/agent-orchestrator.js';
|
|
5
5
|
import { classifyOllamaWorkerSlice } from '../agents/agent-runner-ollama.js';
|
|
6
6
|
import { buildNarutoCloneRoster, systemSafeNarutoConcurrency } from '../agents/agent-roster.js';
|
|
7
7
|
import { DEFAULT_NARUTO_CLONES, MAX_NARUTO_AGENT_COUNT } from '../agents/agent-schema.js';
|
|
8
8
|
import { resolveOllamaWorkerConfig } from '../agents/ollama-worker-config.js';
|
|
9
9
|
import { attachZellijSessionInteractive, launchZellijLayout } from '../zellij/zellij-launcher.js';
|
|
10
|
+
import { buildNarutoWorkGraph } from '../naruto/naruto-work-graph.js';
|
|
11
|
+
import { buildNarutoRoleDistribution } from '../naruto/naruto-role-policy.js';
|
|
12
|
+
import { decideNarutoConcurrency } from '../naruto/naruto-concurrency-governor.js';
|
|
13
|
+
import { simulateNarutoActivePool } from '../naruto/naruto-active-pool.js';
|
|
14
|
+
import { buildNarutoVerificationDag } from '../naruto/naruto-verification-dag.js';
|
|
15
|
+
import { buildNarutoGptFinalPack } from '../naruto/naruto-gpt-final-pack.js';
|
|
16
|
+
import { planNarutoZellijDashboard } from '../zellij/zellij-naruto-dashboard.js';
|
|
17
|
+
import { checkPromptPlaceholders } from '../prompt/prompt-placeholder-guard.js';
|
|
10
18
|
const NARUTO_RESULT_SCHEMA = 'sks.naruto-command-result.v1';
|
|
11
19
|
const NARUTO_ROUTE = '$Naruto';
|
|
12
20
|
// $Naruto — Shadow Clone Swarm (影分身 / Kage Bunshin no Jutsu).
|
|
@@ -25,6 +33,28 @@ export async function narutoCommand(commandOrArgs = 'naruto', maybeArgs = []) {
|
|
|
25
33
|
}
|
|
26
34
|
async function narutoRun(parsed) {
|
|
27
35
|
const root = await sksRoot();
|
|
36
|
+
const writeCapable = parsed.readonly !== true && parsed.writeMode !== 'off';
|
|
37
|
+
const patchEnvelopeBasePath = '.sneakoscope/naruto/patch-envelopes';
|
|
38
|
+
const placeholderGuard = checkPromptPlaceholders({
|
|
39
|
+
prompt: parsed.prompt,
|
|
40
|
+
writeCapable,
|
|
41
|
+
targetPaths: writeCapable ? [patchEnvelopeBasePath] : []
|
|
42
|
+
});
|
|
43
|
+
if (!placeholderGuard.ok) {
|
|
44
|
+
return emit(parsed, {
|
|
45
|
+
schema: NARUTO_RESULT_SCHEMA,
|
|
46
|
+
ok: false,
|
|
47
|
+
mode: 'NARUTO',
|
|
48
|
+
action: 'run',
|
|
49
|
+
status: 'blocked',
|
|
50
|
+
prompt_placeholder_guard: placeholderGuard,
|
|
51
|
+
blockers: placeholderGuard.blockers
|
|
52
|
+
}, () => {
|
|
53
|
+
console.log('$Naruto blocked before work graph creation: unresolved prompt placeholder or empty write target path.');
|
|
54
|
+
for (const blocker of placeholderGuard.blockers)
|
|
55
|
+
console.log('- ' + blocker);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
28
58
|
const roster = buildNarutoCloneRoster({
|
|
29
59
|
clones: parsed.clones,
|
|
30
60
|
prompt: parsed.prompt,
|
|
@@ -37,9 +67,52 @@ async function narutoRun(parsed) {
|
|
|
37
67
|
const localWorker = await resolveNarutoLocalWorkerMode(parsed);
|
|
38
68
|
const schedulerBackend = localWorker.auto_select_eligible ? 'ollama' : parsed.backend;
|
|
39
69
|
const safe = systemSafeNarutoConcurrency({ backend: schedulerBackend });
|
|
40
|
-
const
|
|
70
|
+
const workGraph = buildNarutoWorkGraph({
|
|
71
|
+
prompt: parsed.prompt,
|
|
72
|
+
requestedClones: roster.agent_count,
|
|
73
|
+
totalWorkItems: parsed.workItems,
|
|
74
|
+
readonly: parsed.readonly,
|
|
75
|
+
writeCapable,
|
|
76
|
+
leaseBasePath: patchEnvelopeBasePath,
|
|
77
|
+
maxActiveWorkers: parsed.concurrency || safe.cap
|
|
78
|
+
});
|
|
79
|
+
const roleDistribution = buildNarutoRoleDistribution(workGraph.work_items, { readonly: parsed.readonly });
|
|
80
|
+
const governor = decideNarutoConcurrency({
|
|
81
|
+
requestedClones: roster.agent_count,
|
|
82
|
+
totalWorkItems: workGraph.total_work_items,
|
|
83
|
+
pendingWorkQueueSize: workGraph.total_work_items,
|
|
84
|
+
backend: schedulerBackend
|
|
85
|
+
});
|
|
86
|
+
const backendMinimum = schedulerBackend === 'fake' ? roster.agent_count : Math.min(roster.agent_count, 2);
|
|
87
|
+
const activeSlots = Math.max(1, Math.min(roster.agent_count, parsed.concurrency || Math.max(governor.safe_active_workers, backendMinimum), safe.cap));
|
|
88
|
+
const zellijVisiblePanes = Math.max(1, Math.min(activeSlots, governor.safe_zellij_visible_panes));
|
|
89
|
+
const activePool = simulateNarutoActivePool({ graph: workGraph, governor: { ...governor, safe_active_workers: activeSlots } });
|
|
90
|
+
const verificationDag = buildNarutoVerificationDag(workGraph, { cwd: root });
|
|
91
|
+
const gptFinalPack = buildNarutoGptFinalPack({
|
|
92
|
+
missionId: 'pending',
|
|
93
|
+
graph: workGraph,
|
|
94
|
+
roleDistribution,
|
|
95
|
+
localLlmMetrics: localWorker
|
|
96
|
+
});
|
|
97
|
+
const zellijDashboard = planNarutoZellijDashboard({
|
|
98
|
+
targetActiveWorkers: activeSlots,
|
|
99
|
+
visiblePaneCap: governor.safe_zellij_visible_panes,
|
|
100
|
+
backpressure: governor.backpressure,
|
|
101
|
+
roles: roleDistribution.work_item_roles.map((row) => row.role),
|
|
102
|
+
backend: schedulerBackend
|
|
103
|
+
});
|
|
41
104
|
const mission = await createMission(root, { mode: 'naruto', prompt: parsed.prompt });
|
|
42
105
|
const ledgerRoot = path.join(mission.dir, 'agents');
|
|
106
|
+
await writeNarutoArtifacts(ledgerRoot, {
|
|
107
|
+
workGraph,
|
|
108
|
+
roleDistribution,
|
|
109
|
+
governor,
|
|
110
|
+
activePool,
|
|
111
|
+
verificationDag,
|
|
112
|
+
gptFinalPack: { ...gptFinalPack, mission_id: mission.id },
|
|
113
|
+
zellijDashboard,
|
|
114
|
+
placeholderGuard
|
|
115
|
+
});
|
|
43
116
|
let liveZellij = null;
|
|
44
117
|
if (!parsed.json && !parsed.mock && !parsed.noOpenZellij) {
|
|
45
118
|
liveZellij = await launchZellijLayout({
|
|
@@ -47,12 +120,12 @@ async function narutoRun(parsed) {
|
|
|
47
120
|
missionId: mission.id,
|
|
48
121
|
ledgerRoot,
|
|
49
122
|
kind: 'naruto',
|
|
50
|
-
slotCount:
|
|
123
|
+
slotCount: zellijVisiblePanes,
|
|
51
124
|
dryRun: false,
|
|
52
125
|
attach: false
|
|
53
126
|
});
|
|
54
127
|
if (liveZellij?.ok && liveZellij.capability?.status === 'ok') {
|
|
55
|
-
console.log('Zellij: prepared ' +
|
|
128
|
+
console.log('Zellij: prepared ' + zellijVisiblePanes + ' visible active clone lane(s) in ' + liveZellij.session_name + ' with ' + Math.max(0, activeSlots - zellijVisiblePanes) + ' headless active worker(s). Attach with: ' + (liveZellij.attach_command_with_env || liveZellij.attach_command));
|
|
56
129
|
if (parsed.attach)
|
|
57
130
|
attachZellijSessionInteractive(liveZellij.session_name, { cwd: process.cwd(), configPath: liveZellij.clipboard_config_path });
|
|
58
131
|
}
|
|
@@ -73,7 +146,7 @@ async function narutoRun(parsed) {
|
|
|
73
146
|
agents: roster.agent_count,
|
|
74
147
|
concurrency: activeSlots,
|
|
75
148
|
targetActiveSlots: activeSlots,
|
|
76
|
-
visualLaneCount:
|
|
149
|
+
visualLaneCount: zellijVisiblePanes,
|
|
77
150
|
desiredWorkItemCount: parsed.workItems,
|
|
78
151
|
maxAgentCount: MAX_NARUTO_AGENT_COUNT,
|
|
79
152
|
narutoMode: true,
|
|
@@ -91,7 +164,7 @@ async function narutoRun(parsed) {
|
|
|
91
164
|
fastMode: true,
|
|
92
165
|
serviceTier: 'fast',
|
|
93
166
|
noFast: false,
|
|
94
|
-
|
|
167
|
+
writeMode: writeCapable ? parsed.writeMode || 'parallel' : 'off',
|
|
95
168
|
json: parsed.json
|
|
96
169
|
});
|
|
97
170
|
const clones = result.roster?.agent_count ?? roster.agent_count;
|
|
@@ -109,6 +182,22 @@ async function narutoRun(parsed) {
|
|
|
109
182
|
target_active_slots: result.target_active_slots ?? activeSlots,
|
|
110
183
|
concurrency_capped: clones > (result.target_active_slots ?? activeSlots),
|
|
111
184
|
system: { cores: safe.cores, free_gb: safe.free_gb, safe_concurrency: safe.cap, heavy_backend: safe.heavy },
|
|
185
|
+
work_graph: {
|
|
186
|
+
total_work_items: workGraph.total_work_items,
|
|
187
|
+
mixed_work_kinds: workGraph.mixed_work_kinds,
|
|
188
|
+
write_allowed_count: workGraph.write_allowed_count,
|
|
189
|
+
active_wave_count: workGraph.active_waves.length,
|
|
190
|
+
parallel_write_wave_count: workGraph.active_waves.filter((wave) => wave.write_paths.length > 1).length,
|
|
191
|
+
ok: workGraph.ok
|
|
192
|
+
},
|
|
193
|
+
role_distribution: roleDistribution,
|
|
194
|
+
concurrency_governor: governor,
|
|
195
|
+
active_pool: {
|
|
196
|
+
ok: activePool.ok,
|
|
197
|
+
max_observed_active_workers: activePool.max_observed_active_workers,
|
|
198
|
+
refill_events: activePool.refill_events,
|
|
199
|
+
completed_count: activePool.completed_count
|
|
200
|
+
},
|
|
112
201
|
local_worker: localWorkerSummary,
|
|
113
202
|
proof: result.proof?.status || 'missing',
|
|
114
203
|
run: result,
|
|
@@ -120,9 +209,10 @@ async function narutoRun(parsed) {
|
|
|
120
209
|
console.log('Mission: ' + result.mission_id);
|
|
121
210
|
console.log('Clones: ' + summary.clones + ' / max ' + MAX_NARUTO_AGENT_COUNT + ', running ' + summary.target_active_slots + ' at a time' + (summary.concurrency_capped ? ` (throttled to host capacity: ${safe.cores} cores, ${safe.free_gb} GB free)` : ''));
|
|
122
211
|
console.log('Backend: ' + result.backend);
|
|
212
|
+
console.log('Roles: ' + roleDistribution.entries.map((entry) => `${entry.role}:${entry.count}`).join(', '));
|
|
123
213
|
console.log('Proof: ' + summary.proof);
|
|
124
214
|
if (summary.zellij?.ok && summary.zellij.capability?.status === 'ok')
|
|
125
|
-
console.log('Zellij: prepared ' +
|
|
215
|
+
console.log('Zellij: prepared ' + zellijVisiblePanes + ' visible active clone lane(s) in ' + summary.zellij.session_name + '; dashboard tracks ' + Math.max(0, activeSlots - zellijVisiblePanes) + ' headless active worker(s)');
|
|
126
216
|
else if (summary.zellij?.ok)
|
|
127
217
|
console.log('Zellij: optional live panes unavailable (' + ((summary.zellij.warnings || []).join('; ') || summary.zellij.capability?.status || 'unknown') + ')');
|
|
128
218
|
});
|
|
@@ -148,6 +238,9 @@ async function narutoStatus(parsed) {
|
|
|
148
238
|
const { dir } = await loadMission(root, id);
|
|
149
239
|
const proof = await readJson(path.join(dir, 'agents', 'agent-proof-evidence.json'), null);
|
|
150
240
|
const scheduler = await readJson(path.join(dir, 'agents', 'agent-scheduler-state.json'), null);
|
|
241
|
+
const roleDistribution = await readJson(path.join(dir, 'agents', 'naruto-role-distribution.json'), null);
|
|
242
|
+
const workGraph = await readJson(path.join(dir, 'agents', 'naruto-work-graph.json'), null);
|
|
243
|
+
const governor = await readJson(path.join(dir, 'agents', 'naruto-concurrency-governor.json'), null);
|
|
151
244
|
const summary = {
|
|
152
245
|
schema: NARUTO_RESULT_SCHEMA,
|
|
153
246
|
ok: proof !== null,
|
|
@@ -156,13 +249,24 @@ async function narutoStatus(parsed) {
|
|
|
156
249
|
proof: proof?.status || 'missing',
|
|
157
250
|
target_active_slots: scheduler?.target_active_slots ?? null,
|
|
158
251
|
max_active_slots: scheduler?.max_active_slots ?? null,
|
|
159
|
-
completed: scheduler?.completed_count ?? null
|
|
252
|
+
completed: scheduler?.completed_count ?? null,
|
|
253
|
+
role_distribution: roleDistribution,
|
|
254
|
+
work_graph: workGraph ? {
|
|
255
|
+
total_work_items: workGraph.total_work_items,
|
|
256
|
+
mixed_work_kinds: workGraph.mixed_work_kinds,
|
|
257
|
+
write_allowed_count: workGraph.write_allowed_count,
|
|
258
|
+
active_wave_count: Array.isArray(workGraph.active_waves) ? workGraph.active_waves.length : null,
|
|
259
|
+
parallel_write_wave_count: Array.isArray(workGraph.active_waves) ? workGraph.active_waves.filter((wave) => Array.isArray(wave.write_paths) && wave.write_paths.length > 1).length : null
|
|
260
|
+
} : null,
|
|
261
|
+
concurrency_governor: governor
|
|
160
262
|
};
|
|
161
263
|
return emit(parsed, summary, () => {
|
|
162
264
|
console.log('🍥 Naruto mission: ' + id);
|
|
163
265
|
console.log('Proof: ' + summary.proof);
|
|
164
266
|
if (summary.target_active_slots !== null)
|
|
165
267
|
console.log('Active clones: ' + summary.target_active_slots + ' / max ' + summary.max_active_slots);
|
|
268
|
+
if (roleDistribution?.entries)
|
|
269
|
+
console.log('Roles: ' + roleDistribution.entries.map((entry) => `${entry.role}:${entry.count}`).join(', '));
|
|
166
270
|
});
|
|
167
271
|
}
|
|
168
272
|
async function narutoHelp(parsed) {
|
|
@@ -186,6 +290,8 @@ async function narutoHelp(parsed) {
|
|
|
186
290
|
});
|
|
187
291
|
}
|
|
188
292
|
function parseNarutoArgs(args = []) {
|
|
293
|
+
if (hasFlag(args, '--help') || hasFlag(args, '-h'))
|
|
294
|
+
args = ['help', ...args.filter((arg) => arg !== '--help' && arg !== '-h')];
|
|
189
295
|
const first = args[0] && !String(args[0]).startsWith('--') ? String(args[0]) : '';
|
|
190
296
|
const actions = new Set(['run', 'status', 'help']);
|
|
191
297
|
const action = (actions.has(first) ? first : 'run');
|
|
@@ -213,6 +319,16 @@ function parseNarutoArgs(args = []) {
|
|
|
213
319
|
const prompt = positionalArgs(rest, valueFlags).join(' ').trim() || 'Naruto shadow clone swarm run';
|
|
214
320
|
return { action, prompt, clones, workItems, concurrency, backend, backendExplicit, mock, real, readonly, ollamaEnabled: useOllama && !noOllama, noOllama, ollamaModel, ollamaBaseUrl, writeMode, json, missionId, noOpenZellij, attach };
|
|
215
321
|
}
|
|
322
|
+
async function writeNarutoArtifacts(ledgerRoot, artifacts) {
|
|
323
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'naruto-work-graph.json'), artifacts.workGraph);
|
|
324
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'naruto-role-distribution.json'), artifacts.roleDistribution);
|
|
325
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'naruto-concurrency-governor.json'), artifacts.governor);
|
|
326
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'naruto-active-pool.json'), artifacts.activePool);
|
|
327
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'naruto-verification-dag.json'), artifacts.verificationDag);
|
|
328
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'naruto-gpt-final-pack.json'), artifacts.gptFinalPack);
|
|
329
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'naruto-zellij-dashboard.json'), artifacts.zellijDashboard);
|
|
330
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'prompt-placeholder-guard.json'), artifacts.placeholderGuard);
|
|
331
|
+
}
|
|
216
332
|
function clampClones(value) {
|
|
217
333
|
if (!Number.isFinite(value) || value < 1)
|
|
218
334
|
return DEFAULT_NARUTO_CLONES;
|
|
@@ -290,7 +290,7 @@ async function runSks(root, commandArgs) {
|
|
|
290
290
|
cwd: root,
|
|
291
291
|
timeoutMs: 180_000,
|
|
292
292
|
maxOutputBytes: 512 * 1024,
|
|
293
|
-
env: { SKS_SKIP_NPM_FRESHNESS_CHECK: '1', CI: 'true' },
|
|
293
|
+
env: { SKS_SKIP_NPM_FRESHNESS_CHECK: '1', SKS_LOCAL_LLM_TOGGLE_ONLY: '1', CI: 'true' },
|
|
294
294
|
});
|
|
295
295
|
}
|
|
296
296
|
function routeExecutionResult(route, command, result, options = {}) {
|
|
@@ -54,6 +54,14 @@ export function buildDoctorReadinessMatrix(input = {}) {
|
|
|
54
54
|
warnings.add('codex_app_fast_selector_repaired_restart_app_if_needed');
|
|
55
55
|
if (input.codex_lb?.ok === false)
|
|
56
56
|
warnings.add(`codex_lb_${input.codex_lb?.circuit?.state || 'blocked'}`);
|
|
57
|
+
const localModel = input.local_model || {};
|
|
58
|
+
const localStatus = String(localModel.status || (localModel.enabled ? 'enabled_unverified' : 'disabled'));
|
|
59
|
+
if (localModel.enabled === true && localStatus === 'enabled_unverified')
|
|
60
|
+
warnings.add('local_llm_enabled_unverified');
|
|
61
|
+
if (localModel.enabled === true && localStatus === 'degraded')
|
|
62
|
+
warnings.add('local_llm_degraded');
|
|
63
|
+
if (localModel.enabled === true && localStatus === 'blocked')
|
|
64
|
+
warnings.add('local_llm_blocked_worker_tier_disabled');
|
|
57
65
|
const localCollaborationPolicy = resolveLocalCollaborationPolicy({ mode: input.local_collaboration?.mode || null });
|
|
58
66
|
const gptFinalAvailable = input.local_collaboration?.gpt_final_arbiter_available === undefined
|
|
59
67
|
? codexBinOk
|
|
@@ -101,12 +109,23 @@ export function buildDoctorReadinessMatrix(input = {}) {
|
|
|
101
109
|
codex_app_required_for_cli: false,
|
|
102
110
|
local_collaboration: {
|
|
103
111
|
mode: localCollaborationPolicy.mode,
|
|
104
|
-
local_backend: input.local_collaboration?.local_backend ||
|
|
105
|
-
local_model: input.local_collaboration?.local_model ||
|
|
112
|
+
local_backend: input.local_collaboration?.local_backend || localModel.provider || 'ollama',
|
|
113
|
+
local_model: input.local_collaboration?.local_model || localModel.model || null,
|
|
106
114
|
final_arbiter: gptFinalAvailable ? 'GPT available' : 'missing',
|
|
107
115
|
final_apply_allowed: localCollaborationPolicy.gpt_final_required ? gptFinalAvailable : localCollaborationPolicy.mode === 'disabled',
|
|
108
116
|
blockers: localCollaborationPolicy.gpt_final_required && !gptFinalAvailable ? ['gpt_final_arbiter_unavailable'] : localCollaborationPolicy.blockers
|
|
109
117
|
},
|
|
118
|
+
local_llm: {
|
|
119
|
+
enabled: localModel.enabled === true,
|
|
120
|
+
status: localStatus,
|
|
121
|
+
provider: localModel.provider || 'ollama',
|
|
122
|
+
model: localModel.model || null,
|
|
123
|
+
endpoint: localModel.endpoint || localModel.base_url || null,
|
|
124
|
+
last_smoke: localModel.last_smoke || null,
|
|
125
|
+
final_arbiter: 'GPT required',
|
|
126
|
+
worker_tier_enabled: localModel.enabled === true && localStatus === 'verified',
|
|
127
|
+
blockers: normalizeList(localModel.blockers)
|
|
128
|
+
},
|
|
110
129
|
ready: blockers.size === 0 && cliReady,
|
|
111
130
|
primary_blocker: [...blockers][0] || null,
|
|
112
131
|
blockers: [...blockers],
|
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 = '2.0.
|
|
8
|
+
export const PACKAGE_VERSION = '2.0.6';
|
|
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() {
|