sneakoscope 2.0.1 → 2.0.2
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 +26 -5
- 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 +15 -8
- package/dist/cli/command-registry.js +2 -0
- package/dist/commands/doctor.js +29 -3
- package/dist/core/agents/agent-command-surface.js +13 -3
- package/dist/core/agents/agent-orchestrator.js +22 -0
- package/dist/core/agents/agent-output-validator.js +2 -1
- package/dist/core/agents/agent-patch-schema.js +2 -1
- package/dist/core/agents/agent-roster.js +1 -1
- package/dist/core/agents/agent-runner-ollama.js +411 -0
- package/dist/core/agents/agent-schema.js +1 -1
- package/dist/core/agents/intelligent-work-graph.js +45 -3
- package/dist/core/agents/native-cli-session-swarm.js +8 -1
- package/dist/core/agents/native-cli-worker.js +1 -1
- package/dist/core/agents/native-worker-backend-router.js +44 -2
- package/dist/core/agents/ollama-worker-config.js +118 -0
- package/dist/core/auto-review.js +39 -6
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +42 -3
- package/dist/core/commands/basic-cli.js +36 -1
- package/dist/core/commands/local-model-command.js +105 -0
- package/dist/core/commands/mad-sks-command.js +58 -9
- package/dist/core/commands/run-command.js +29 -1
- package/dist/core/commands/team-command.js +31 -2
- package/dist/core/doctor/doctor-readiness-matrix.js +4 -0
- package/dist/core/feature-fixtures.js +1 -0
- package/dist/core/fsx.js +1 -1
- package/dist/core/hooks-runtime.js +1 -1
- package/dist/core/init.js +2 -0
- package/dist/core/provider/provider-context.js +72 -9
- package/dist/core/retention.js +11 -0
- package/dist/core/routes.js +21 -1
- package/dist/core/team-live.js +7 -1
- package/dist/core/update-check.js +156 -1
- package/dist/core/verification/verification-worker-pool.js +12 -0
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-worker-pane-manager.js +19 -2
- package/dist/scripts/agent-ast-aware-work-graph-check.js +1 -1
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +12 -2
- package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +92 -0
- package/dist/scripts/mad-sks-zellij-default-pane-worker-check.js +37 -0
- package/dist/scripts/mad-sks-zellij-launch-check.js +2 -1
- package/dist/scripts/provider-context-config-toml-check.js +63 -0
- package/dist/scripts/release-gate-existence-audit.js +4 -0
- package/dist/scripts/runtime-no-mjs-scripts-check.js +3 -2
- package/dist/scripts/zellij-worker-pane-manager-check.js +3 -0
- package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +39 -0
- package/package.json +7 -3
|
@@ -26,7 +26,11 @@ export async function team(args = []) {
|
|
|
26
26
|
const jsonOutput = flag(args, '--json');
|
|
27
27
|
const mock = flag(args, '--mock');
|
|
28
28
|
const openZellij = !mock && !jsonOutput && !flag(args, '--no-open-zellij') && !flag(args, '--no-zellij');
|
|
29
|
-
const
|
|
29
|
+
const useOllama = flag(args, '--ollama') || flag(args, '--local-model');
|
|
30
|
+
const noOllama = flag(args, '--no-ollama') || flag(args, '--no-local-model');
|
|
31
|
+
const ollamaModel = readFlagValue(args, '--ollama-model', readFlagValue(args, '--local-model-model', '')) || null;
|
|
32
|
+
const ollamaBaseUrl = readFlagValue(args, '--ollama-base-url', readFlagValue(args, '--local-model-base-url', '')) || null;
|
|
33
|
+
const cleanCreateArgs = stripTeamCreateControlArgs(args);
|
|
30
34
|
const opts = parseTeamCreateArgs(cleanCreateArgs);
|
|
31
35
|
const { prompt, agentSessions, roleCounts, roster } = opts;
|
|
32
36
|
const targetActiveSlots = readBoundedIntegerFlag(args, '--target-active-slots', roster.bundle_size, 1, 20);
|
|
@@ -40,7 +44,7 @@ export async function team(args = []) {
|
|
|
40
44
|
const dryRunPatches = flag(args, '--dry-run-patches') || flag(args, '--dryrun-patches');
|
|
41
45
|
const maxWriteAgents = readBoundedIntegerFlag(args, '--max-write-agents', Math.min(roster.bundle_size, 5), 1, 20);
|
|
42
46
|
if (!prompt) {
|
|
43
|
-
console.error('Usage: sks team "task" [20:agents] [executor:5 reviewer:6 user:1] [--agents N] [--work-items N] [--target-active-slots N] [--profile NAME] [--write-mode off|proof-safe|parallel|serial] [--apply-patches] [--no-open-zellij] [--json] [--mock]');
|
|
47
|
+
console.error('Usage: sks team "task" [20:agents] [executor:5 reviewer:6 user:1] [--agents N] [--work-items N] [--target-active-slots N] [--profile NAME] [--write-mode off|proof-safe|parallel|serial] [--apply-patches] [--ollama|--no-ollama] [--no-open-zellij] [--json] [--mock]');
|
|
44
48
|
process.exitCode = 1;
|
|
45
49
|
return;
|
|
46
50
|
}
|
|
@@ -111,6 +115,10 @@ export async function team(args = []) {
|
|
|
111
115
|
applyPatches,
|
|
112
116
|
dryRunPatches,
|
|
113
117
|
maxWriteAgents,
|
|
118
|
+
ollamaEnabled: useOllama && !noOllama,
|
|
119
|
+
noOllama,
|
|
120
|
+
ollamaModel,
|
|
121
|
+
ollamaBaseUrl,
|
|
114
122
|
routeCommand: 'sks team',
|
|
115
123
|
routeBlackboxKind: 'actual_team_command'
|
|
116
124
|
});
|
|
@@ -198,6 +206,27 @@ export function parseTeamCreateArgs(args) {
|
|
|
198
206
|
const normalized = normalizeTeamSpec({ agentSessions: spec.agentSessions, roleCounts: spec.roleCounts, prompt });
|
|
199
207
|
return { prompt, agentSessions: normalized.agentSessions, roleCounts: normalized.roleCounts, roster: normalized.roster };
|
|
200
208
|
}
|
|
209
|
+
function stripTeamCreateControlArgs(args = []) {
|
|
210
|
+
const booleanFlags = new Set([
|
|
211
|
+
'--open-zellij', '--zellij-open', '--no-open-zellij', '--no-zellij', '--no-attach',
|
|
212
|
+
'--mock', '--ollama', '--local-model', '--no-ollama', '--no-local-model'
|
|
213
|
+
]);
|
|
214
|
+
const valueFlags = new Set(['--ollama-model', '--local-model-model', '--ollama-base-url', '--local-model-base-url']);
|
|
215
|
+
const out = [];
|
|
216
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
217
|
+
const arg = String(args[i]);
|
|
218
|
+
if (booleanFlags.has(arg))
|
|
219
|
+
continue;
|
|
220
|
+
if (valueFlags.has(arg)) {
|
|
221
|
+
i += 1;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if ([...valueFlags].some((flagName) => arg.startsWith(flagName + '=')))
|
|
225
|
+
continue;
|
|
226
|
+
out.push(args[i]);
|
|
227
|
+
}
|
|
228
|
+
return out;
|
|
229
|
+
}
|
|
201
230
|
export function buildTeamPlan(id, prompt, opts = {}) {
|
|
202
231
|
const spec = normalizeTeamSpec({ ...opts, prompt });
|
|
203
232
|
const { agentSessions, roleCounts, roster } = spec;
|
|
@@ -47,6 +47,8 @@ export function buildDoctorReadinessMatrix(input = {}) {
|
|
|
47
47
|
warnings.add('codex_app_needs_setup_optional_for_cli');
|
|
48
48
|
if (input.codex_app_ui?.fast_selector === 'manual_action_required')
|
|
49
49
|
warnings.add('codex_app_fast_selector_manual_action_required');
|
|
50
|
+
if (input.codex_app_ui?.requires_confirmation === true)
|
|
51
|
+
blockers.add('codex_app_fast_ui_repair_requires_confirmation');
|
|
50
52
|
if (input.codex_app_ui?.fast_selector === 'repaired')
|
|
51
53
|
warnings.add('codex_app_fast_selector_repaired_restart_app_if_needed');
|
|
52
54
|
if (input.codex_lb?.ok === false)
|
|
@@ -58,6 +60,8 @@ export function buildDoctorReadinessMatrix(input = {}) {
|
|
|
58
60
|
const nextActions = normalizeList(input.operator_actions || codexConfig.operator_actions);
|
|
59
61
|
if (!nextActions.length && blockers.size)
|
|
60
62
|
nextActions.push('Run `sks doctor --fix`, then run `sks mad repair-config --apply` if config-load still fails.');
|
|
63
|
+
if (input.codex_app_ui?.requires_confirmation === true)
|
|
64
|
+
nextActions.push(input.codex_app_ui.next_action || 'Run `sks doctor --fix --repair-codex-app-ui` after reviewing the repair plan.');
|
|
61
65
|
if (!zellijReadyForInteractive)
|
|
62
66
|
nextActions.push('Install Zellij for `sks --mad` and interactive lane UI. On macOS: `brew install zellij`.');
|
|
63
67
|
return {
|
|
@@ -111,6 +111,7 @@ const FIXTURES = Object.freeze({
|
|
|
111
111
|
'route-fast-mode': fixture('execute', 'sks fast-mode status --json', [], 'pass'),
|
|
112
112
|
'route-fast-on': fixture('mock', '$Fast-On covered by hermetic fast-mode blackbox toggle test', [], 'pass'),
|
|
113
113
|
'route-fast-off': fixture('mock', '$Fast-Off covered by hermetic fast-mode blackbox toggle test', [], 'pass'),
|
|
114
|
+
'route-local-model': fixture('execute', 'sks with-local-llm status --json', [], 'pass'),
|
|
114
115
|
'route-help': fixture('mock', '$Help lightweight route', [], 'pass'),
|
|
115
116
|
'route-commit': fixture('mock', '$Commit git route', ['completion-proof.json'], 'pass'),
|
|
116
117
|
'route-commit-and-push': fixture('mock', '$Commit-And-Push git route', ['completion-proof.json'], 'pass'),
|
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.2';
|
|
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() {
|
|
@@ -1036,7 +1036,7 @@ function updateOfferThrottleMs() {
|
|
|
1036
1036
|
return 8 * 60 * 1000;
|
|
1037
1037
|
}
|
|
1038
1038
|
function sksUpdateInstallCommand(version) {
|
|
1039
|
-
return `
|
|
1039
|
+
return `sks update now --version ${version}`;
|
|
1040
1040
|
}
|
|
1041
1041
|
function copyStableUpdateChoiceText(latest, current = null) {
|
|
1042
1042
|
const installed = current ? `installed ${current}, latest ${latest}` : `latest ${latest}`;
|
package/dist/core/init.js
CHANGED
|
@@ -1024,6 +1024,8 @@ export async function installSkills(root) {
|
|
|
1024
1024
|
'fast-mode': `---\nname: fast-mode\ndescription: Dollar-command route for $Fast-Mode, $Fast-On, and $Fast-Off project-local Fast mode toggles.\n---\n\nUse when the user invokes $Fast-Mode, $Fast-On, $Fast-Off, or asks to turn SKS Fast mode on/off for dollar commands. Prefer \`sks fast-mode on|off|status|clear --json\`. The command writes only .sneakoscope/state/fast-mode.json in the active project. Explicit runtime flags still win: \`--fast\`, \`--no-fast\`, and \`--service-tier standard|fast\` override the saved preference for that run. Finish with a short status and Honest Mode; do not start Team or broad implementation for a toggle-only request.\n`,
|
|
1025
1025
|
'fast-on': `---\nname: fast-on\ndescription: Alias for $Fast-On project-local SKS Fast mode enablement.\n---\n\nUse the same rules as fast-mode. Run or instruct \`sks fast-mode on --json\`, then report the active state, state file, and the fact that explicit per-run flags still override the saved preference.\n`,
|
|
1026
1026
|
'fast-off': `---\nname: fast-off\ndescription: Alias for $Fast-Off project-local SKS Fast mode disablement.\n---\n\nUse the same rules as fast-mode. Run or instruct \`sks fast-mode off --json\`, then report the active state, state file, and the fact that explicit per-run flags still override the saved preference.\n`,
|
|
1027
|
+
'with-local-llm-on': `---\nname: with-local-llm-on\ndescription: Dollar-command route for $with-local-llm-on local Ollama worker enablement.\n---\n\nUse when the user invokes $with-local-llm-on or asks to enable the optional local Ollama worker backend. Prefer \`sks with-local-llm on --json\`. The command writes the machine-local config at \`~/.sneakoscope/local-model.json\`. Default off means SKS stays GPT-only until this command enables local workers. Enabled mode only lets policy-eligible simple code patch-envelope or read-only collection worker slices use Ollama; GPT/Codex still owns strategy, planning, design, review, verification, safety, and integration. \`--no-ollama\` and \`SKS_OLLAMA_WORKERS=0\` still force local workers off for a run. Finish with a short status and Honest Mode; do not start Team for a toggle-only request.\n`,
|
|
1028
|
+
'with-local-llm-off': `---\nname: with-local-llm-off\ndescription: Dollar-command route for $with-local-llm-off local Ollama worker disablement.\n---\n\nUse when the user invokes $with-local-llm-off or asks to disable the optional local Ollama worker backend. Prefer \`sks with-local-llm off --json\`. The command writes the machine-local config at \`~/.sneakoscope/local-model.json\`. Disabled mode keeps SKS GPT-only by default. Strategy, planning, design, review, verification, safety, and integration remain GPT/Codex-owned regardless of this toggle. Finish with a short status and Honest Mode; do not start Team for a toggle-only request.\n`,
|
|
1027
1029
|
'wiki': `---\nname: wiki\ndescription: Dollar-command route for $Wiki TriWiki refresh, pack, validate, and prune commands.\n---\n\nUse for $Wiki or Korean wiki-refresh requests. Refresh/update/갱신: run sks wiki refresh, then validate .sneakoscope/wiki/context-pack.json. Pack: run sks wiki pack, then validate. Prune/clean/정리: use sks wiki refresh --prune, or sks wiki prune --dry-run for inspection. Report claims, anchors, trust, attention.use_first/hydrate_first, validation, and blockers. Do not start ambiguity-gated implementation, subagents, or unrelated work.\n`,
|
|
1028
1030
|
'team': `---\nname: team\ndescription: SKS Team orchestration for $Team/code work; $From-Chat-IMG is the explicit chat-image alias.\n---\n\nUse for $Team/code work. Auto-seal the route contract from prompt, TriWiki/current-code defaults, and conservative policy; do not surface a prequestion sheet. Read pipeline-plan.json or run sks pipeline plan to see the runtime lane, kept/skipped stages, and verification before implementation. Write team-roster.json; team-gate.json needs team_roster_confirmed=true. executor:N means N native analysis agents, N debate voices, then fresh N executors. ${MIN_TEAM_REVIEW_POLICY_TEXT} After consensus, compile team-graph.json, team-runtime-tasks.json, team-decomposition-report.json, and team-inbox/ so worker handoff uses concrete runtime task ids with role/path/domain/lane hints. Refresh/validate TriWiki before debate, implementation, review, and final; consume attention.use_first and hydrate attention.hydrate_first before risky decisions. ${outcomeRubricPolicyText()} ${speedLanePolicyText()} ${solutionScoutPolicyText('fix this broken behavior')} ${skillDreamPolicyText()} Log events and use sks team message for bounded inter-agent communication in transcript/lane panes. Color-coded Zellij lanes distinguish overview/native-analysis/planning/execution/review/safety sessions in one Zellij window using split panes when Zellij is available. $Team/$team plus sks --mad uses the MAD-SKS permission gate module: user-authorized target-project scopes such as files, shell, packages, services, network, browser/Computer Use, generated assets, file permissions, migrations, normal DB writes, Supabase MCP writes, direct SQL, and schema cleanup are open only for the active invocation; catastrophic wipe/all-row/project-management, credential exfiltration, persistent security weakening, and unrequested fallback guards remain. End with cleanup-zellij or a cleanup event so follow panes show cleanup and stop; pass team-session-cleanup.json, then reflection and Honest Mode. Parent integrates/verifies.\n\n${chatCaptureIntakeText()}\n`,
|
|
1029
1031
|
'from-chat-img': `---\nname: from-chat-img\ndescription: Explicit $From-Chat-IMG Team alias for chat screenshot plus attachment analysis.\n---\n\nUse only for From-Chat-IMG/$From-Chat-IMG. It enters the normal Team pipeline. Treat uploads as chat screenshot plus originals. For web/browser/webapp targets use Codex Chrome Extension first; for native Mac/non-web app surfaces use Codex Computer Use visual inspection when available. List requirements first, match regions to attachments with confidence, write ${FROM_CHAT_IMG_COVERAGE_ARTIFACT}, ${FROM_CHAT_IMG_CHECKLIST_ARTIFACT}, ${FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT}, and ${FROM_CHAT_IMG_QA_LOOP_ARTIFACT}, then continue Team gates, review, reflection, and Honest Mode. ${CODEX_WEB_VERIFICATION_POLICY} ${CODEX_COMPUTER_USE_ONLY_POLICY} The ledger must account for every visible customer request, screenshot image region, and separate attachment; ${FROM_CHAT_IMG_CHECKLIST_ARTIFACT} must have a checked item for each request, image-region/attachment match, work item, scoped QA-LOOP, and verification step; ${FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT} stores temporary TriWiki-backed session context with expires_after_sessions=${FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS}. ${FROM_CHAT_IMG_QA_LOOP_ARTIFACT} must prove QA-LOOP ran over the exact customer-request work-order range after implementation, with every work item covered, post-fix verification complete, and zero unresolved findings. team-gate.json cannot pass From-Chat-IMG completion until unresolved_items is empty, every checklist box is checked, and scoped_qa_loop_completed=true.\n`,
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { exists, nowIso, readJson, writeJsonAtomic } from '../fsx.js';
|
|
2
|
+
import { exists, nowIso, readJson, readText, writeJsonAtomic } from '../fsx.js';
|
|
3
3
|
export const PROVIDER_CONTEXT_SCHEMA = 'sks.provider-context.v1';
|
|
4
4
|
export async function resolveProviderContext(input = {}) {
|
|
5
5
|
const env = input.env || process.env;
|
|
6
6
|
const root = path.resolve(input.root || process.cwd());
|
|
7
7
|
const codexHome = path.resolve(String(input.codexHome || env.CODEX_HOME || path.join(env.HOME || '', '.codex')));
|
|
8
|
+
const configText = await readText(path.join(codexHome, 'config.toml'), '').catch(() => '');
|
|
9
|
+
const configModelProvider = readTopLevelTomlString(configText, 'model_provider');
|
|
10
|
+
const codexLbProviderBlockPresent = hasCodexLbProviderBlock(configText);
|
|
11
|
+
const codexLbEnvKey = codexLbProviderEnvKey(configText) || (codexLbProviderBlockPresent ? 'CODEX_LB_API_KEY' : null);
|
|
12
|
+
const codexLbRequiresOpenAiAuth = codexLbProviderRequiresOpenAiAuth(configText);
|
|
13
|
+
const codexLbProviderValid = codexLbProviderBlockPresent && (codexLbRequiresOpenAiAuth === false || codexLbRequiresOpenAiAuth == null);
|
|
8
14
|
const openaiKey = Boolean(String(env.OPENAI_API_KEY || '').trim());
|
|
9
|
-
const lbKey = Boolean(String(env.CODEX_LB_API_KEY || '').trim());
|
|
15
|
+
const lbKey = Boolean(String((codexLbEnvKey ? env[codexLbEnvKey] : env.CODEX_LB_API_KEY) || env.CODEX_LB_API_KEY || '').trim());
|
|
10
16
|
const envProvider = String(env.SKS_MODEL_PROVIDER || env.CODEX_MODEL_PROVIDER || env.OPENAI_MODEL_PROVIDER || '').trim();
|
|
11
|
-
const modelProvider = String(input.modelProvider || envProvider || '').trim() || null;
|
|
12
|
-
const
|
|
17
|
+
const modelProvider = String(input.modelProvider || envProvider || configModelProvider || '').trim() || null;
|
|
18
|
+
const envLbExplicit = env.SKS_PROVIDER === 'codex-lb' || env.SKS_USE_CODEX_LB === '1';
|
|
19
|
+
const lbExplicit = modelProvider === 'codex-lb' || envLbExplicit;
|
|
13
20
|
const auth = await readJson(path.join(codexHome, 'auth.json'), null).catch(() => null);
|
|
14
21
|
const appAuthPresent = Boolean(auth) || await exists(path.join(codexHome, 'auth.json'));
|
|
15
22
|
const conflict = (lbKey && openaiKey && !lbExplicit && !modelProvider) || (modelProvider === 'codex-lb' && !lbKey && openaiKey);
|
|
@@ -17,17 +24,23 @@ export async function resolveProviderContext(input = {}) {
|
|
|
17
24
|
let authMode = 'unknown';
|
|
18
25
|
let source = 'unknown';
|
|
19
26
|
let confidence = 'low';
|
|
20
|
-
if (
|
|
27
|
+
if (envLbExplicit && lbKey) {
|
|
21
28
|
provider = 'codex-lb';
|
|
22
29
|
authMode = 'codex_lb_key';
|
|
23
30
|
source = 'codex_lb';
|
|
24
31
|
confidence = 'high';
|
|
25
32
|
}
|
|
26
|
-
else if (modelProvider === 'codex-lb') {
|
|
33
|
+
else if (modelProvider === 'codex-lb' && codexLbProviderValid && lbKey) {
|
|
27
34
|
provider = 'codex-lb';
|
|
28
|
-
authMode =
|
|
35
|
+
authMode = 'codex_lb_key';
|
|
29
36
|
source = 'config';
|
|
30
|
-
confidence =
|
|
37
|
+
confidence = 'high';
|
|
38
|
+
}
|
|
39
|
+
else if (modelProvider === 'codex-lb' && codexLbProviderValid) {
|
|
40
|
+
provider = 'codex-lb';
|
|
41
|
+
authMode = 'unknown';
|
|
42
|
+
source = 'config';
|
|
43
|
+
confidence = 'low';
|
|
31
44
|
}
|
|
32
45
|
else if (openaiKey) {
|
|
33
46
|
provider = 'openai';
|
|
@@ -43,6 +56,7 @@ export async function resolveProviderContext(input = {}) {
|
|
|
43
56
|
}
|
|
44
57
|
const warnings = [
|
|
45
58
|
...(conflict ? ['provider_conflict'] : []),
|
|
59
|
+
...(modelProvider === 'codex-lb' && !codexLbProviderValid && !envLbExplicit ? ['codex_lb_provider_config_missing_or_invalid'] : []),
|
|
46
60
|
...(provider === 'codex-lb' && !lbKey ? ['codex_lb_selected_without_key'] : [])
|
|
47
61
|
];
|
|
48
62
|
return {
|
|
@@ -61,7 +75,11 @@ export async function resolveProviderContext(input = {}) {
|
|
|
61
75
|
codex_lb_key_present: lbKey,
|
|
62
76
|
codex_lb_explicit: lbExplicit,
|
|
63
77
|
codex_app_auth_present: appAuthPresent,
|
|
64
|
-
model_provider: modelProvider
|
|
78
|
+
model_provider: modelProvider,
|
|
79
|
+
codex_lb_provider_block_present: codexLbProviderBlockPresent,
|
|
80
|
+
codex_lb_env_key: codexLbEnvKey,
|
|
81
|
+
codex_lb_requires_openai_auth: codexLbRequiresOpenAiAuth,
|
|
82
|
+
codex_lb_available: codexLbProviderValid && lbKey
|
|
65
83
|
}
|
|
66
84
|
};
|
|
67
85
|
}
|
|
@@ -79,4 +97,49 @@ function normalizeServiceTier(value) {
|
|
|
79
97
|
return 'standard';
|
|
80
98
|
return 'unknown';
|
|
81
99
|
}
|
|
100
|
+
export function readTopLevelTomlString(text, key) {
|
|
101
|
+
const lines = String(text || '').split(/\r?\n/);
|
|
102
|
+
for (const line of lines) {
|
|
103
|
+
if (/^\s*\[/.test(line))
|
|
104
|
+
break;
|
|
105
|
+
const match = line.match(new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]*)"\\s*(?:#.*)?$`));
|
|
106
|
+
if (match?.[1] != null)
|
|
107
|
+
return match[1];
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
export function hasCodexLbProviderBlock(text) {
|
|
112
|
+
return codexLbProviderBody(text) != null;
|
|
113
|
+
}
|
|
114
|
+
export function codexLbProviderEnvKey(text) {
|
|
115
|
+
const body = codexLbProviderBody(text);
|
|
116
|
+
return body == null ? null : readTopLevelTomlString(body, 'env_key');
|
|
117
|
+
}
|
|
118
|
+
export function codexLbProviderRequiresOpenAiAuth(text) {
|
|
119
|
+
const body = codexLbProviderBody(text);
|
|
120
|
+
if (body == null)
|
|
121
|
+
return null;
|
|
122
|
+
const match = body.match(/^\s*requires_openai_auth\s*=\s*(true|false)\s*(?:#.*)?$/m);
|
|
123
|
+
return match?.[1] === 'true' ? true : match?.[1] === 'false' ? false : null;
|
|
124
|
+
}
|
|
125
|
+
function codexLbProviderBody(text) {
|
|
126
|
+
const lines = String(text || '').split(/\r?\n/);
|
|
127
|
+
const out = [];
|
|
128
|
+
let inTable = false;
|
|
129
|
+
for (const line of lines) {
|
|
130
|
+
const table = line.match(/^\s*\[([^\]]+)\]\s*(?:#.*)?$/)?.[1]?.trim();
|
|
131
|
+
if (table) {
|
|
132
|
+
if (inTable)
|
|
133
|
+
break;
|
|
134
|
+
inTable = table === 'model_providers.codex-lb' || table === 'model_providers."codex-lb"' || table === '"model_providers"."codex-lb"';
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (inTable)
|
|
138
|
+
out.push(line);
|
|
139
|
+
}
|
|
140
|
+
return inTable ? out.join('\n') : null;
|
|
141
|
+
}
|
|
142
|
+
function escapeRegExp(value) {
|
|
143
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
144
|
+
}
|
|
82
145
|
//# sourceMappingURL=provider-context.js.map
|
package/dist/core/retention.js
CHANGED
|
@@ -52,6 +52,10 @@ const DISPOSABLE_MISSION_DIRS = Object.freeze([
|
|
|
52
52
|
'research/cycles',
|
|
53
53
|
'research/tmp'
|
|
54
54
|
]);
|
|
55
|
+
const DISPOSABLE_MISSION_FILES = Object.freeze([
|
|
56
|
+
'agents/agent-intelligent-work-graph.json',
|
|
57
|
+
'agents/agent-intelligent-work-graph-v2.json'
|
|
58
|
+
]);
|
|
55
59
|
const MISSION_CLOSE_GATES = Object.freeze([
|
|
56
60
|
'team-gate.json',
|
|
57
61
|
'reflection-gate.json',
|
|
@@ -235,6 +239,9 @@ async function compactClosedMissionWorkdirs(root, policy, dryRun, actions, opts
|
|
|
235
239
|
const target = path.join(mission.path, rel);
|
|
236
240
|
await removePath('remove_closed_mission_workdir', target, dryRun, actions, { mission: mission.id, rel, reason: 'closed_mission_disposable_workdir' });
|
|
237
241
|
}
|
|
242
|
+
for (const rel of DISPOSABLE_MISSION_FILES) {
|
|
243
|
+
await removePath('remove_closed_mission_large_file', path.join(mission.path, rel), dryRun, actions, { mission: mission.id, rel, reason: 'closed_mission_disposable_large_file' });
|
|
244
|
+
}
|
|
238
245
|
await pruneMissionDisposableLogs(mission, dryRun, actions);
|
|
239
246
|
}
|
|
240
247
|
}
|
|
@@ -272,6 +279,9 @@ async function compactOldMissionWithDurableArtifacts(mission, dryRun, actions, r
|
|
|
272
279
|
for (const rel of DISPOSABLE_MISSION_DIRS) {
|
|
273
280
|
await removePath('remove_old_mission_workdir', path.join(mission.path, rel), dryRun, actions, { mission: mission.id, rel, reason });
|
|
274
281
|
}
|
|
282
|
+
for (const rel of DISPOSABLE_MISSION_FILES) {
|
|
283
|
+
await removePath('remove_old_mission_large_file', path.join(mission.path, rel), dryRun, actions, { mission: mission.id, rel, reason });
|
|
284
|
+
}
|
|
275
285
|
await pruneMissionDisposableLogs(mission, dryRun, actions);
|
|
276
286
|
}
|
|
277
287
|
async function canCompactActiveMission(mission, opts = {}) {
|
|
@@ -545,6 +555,7 @@ export async function enforceRetention(root, opts = {}) {
|
|
|
545
555
|
action_count: actions.length,
|
|
546
556
|
protected_durable_context: DURABLE_RETENTION_CLASSES,
|
|
547
557
|
disposable_mission_dirs: DISPOSABLE_MISSION_DIRS,
|
|
558
|
+
disposable_mission_files: DISPOSABLE_MISSION_FILES,
|
|
548
559
|
prune_report_logs: Boolean(opts.pruneReportLogs || policy.prune_disposable_report_logs),
|
|
549
560
|
completed_mission_id: opts.completedMissionId || null,
|
|
550
561
|
actions
|
package/dist/core/routes.js
CHANGED
|
@@ -335,6 +335,22 @@ export const ROUTES = [
|
|
|
335
335
|
cliEntrypoint: 'sks fast-mode on|off|status|clear [--json]',
|
|
336
336
|
examples: ['$Fast-On', '$Fast-Off', '$Fast-Mode status']
|
|
337
337
|
},
|
|
338
|
+
{
|
|
339
|
+
id: 'LocalModel',
|
|
340
|
+
command: '$with-local-llm-on',
|
|
341
|
+
mode: 'LOCAL_MODEL',
|
|
342
|
+
route: 'local Ollama worker toggle',
|
|
343
|
+
description: 'Turn the optional local Ollama worker backend on or off. Default off keeps SKS GPT-only; enabled mode lets eligible simple code/collection worker slices use Ollama while GPT/Codex owns strategy, design, review, verification, and integration.',
|
|
344
|
+
requiredSkills: ['with-local-llm-on', 'honest-mode'],
|
|
345
|
+
dollarAliases: ['$with-local-llm-off'],
|
|
346
|
+
appSkillAliases: ['with-local-llm-off'],
|
|
347
|
+
lifecycle: ['global_local_model_toggle', 'worker_only_policy_status', 'honest_mode'],
|
|
348
|
+
context7Policy: 'not_required',
|
|
349
|
+
reasoningPolicy: 'low',
|
|
350
|
+
stopGate: 'none',
|
|
351
|
+
cliEntrypoint: 'sks with-local-llm on|off|status|set-model [--json]',
|
|
352
|
+
examples: ['$with-local-llm-on', '$with-local-llm-off', 'sks with-local-llm status --json']
|
|
353
|
+
},
|
|
338
354
|
{
|
|
339
355
|
id: 'Team',
|
|
340
356
|
command: '$Team',
|
|
@@ -534,7 +550,7 @@ export const ROUTES = [
|
|
|
534
550
|
requiredSkills: ['mad-sks', 'db-safety-guard', 'pipeline-runner', 'context7-docs', REFLECTION_SKILL_NAME, 'honest-mode'],
|
|
535
551
|
lifecycle: ['explicit_invocation', 'auto_sealed_permission_scope', 'scoped_permission_override', 'catastrophic_guard', 'permission_deactivation', 'post_route_reflection', 'honest_mode'],
|
|
536
552
|
context7Policy: 'required',
|
|
537
|
-
reasoningPolicy: '
|
|
553
|
+
reasoningPolicy: 'xhigh',
|
|
538
554
|
stopGate: 'mad-sks-gate.json',
|
|
539
555
|
cliEntrypoint: 'Codex App prompt route only: $MAD-SKS <task>',
|
|
540
556
|
examples: ['$MAD-SKS $Team target project maintenance with package/service/file and DB scopes', '$DB Supabase 점검 $MAD-SKS']
|
|
@@ -607,6 +623,7 @@ export const COMMAND_CATALOG = [
|
|
|
607
623
|
{ name: 'quickstart', usage: 'sks quickstart', description: 'Show the shortest safe setup and verification flow.' },
|
|
608
624
|
{ name: 'bootstrap', usage: 'sks bootstrap [--install-scope global|project] [--local-only] [--json]', description: 'Initialize the current project, install SKS Codex App files/skills, check Context7/Codex App/Zellij, and print ready true/false.' },
|
|
609
625
|
{ name: 'root', usage: 'sks root [--json]', description: 'Show whether SKS is using a project root or the per-user global SKS runtime root.' },
|
|
626
|
+
{ name: 'update', usage: 'sks update check|now [--version <version>] [--json] [--dry-run]', description: 'Check for SKS updates or install the requested package version through npm global mode.' },
|
|
610
627
|
{ name: 'deps', usage: 'sks deps check [--json] [--yes]', description: 'Check Node/npm, Codex CLI, and Zellij readiness; pass --yes to repair missing Codex CLI/Zellij tooling when supported.' },
|
|
611
628
|
{ name: 'codex', usage: 'sks codex compatibility|version|doctor|schema [--json]', description: 'Check Codex CLI rust-v0.136.0 compatibility, installed version, 0.136 capabilities, inherited 0.135/0.134/0.133 behavior, and vendored hook schema snapshot freshness.' },
|
|
612
629
|
{ name: 'codex-app', usage: 'sks codex-app [check|chrome-extension|pat status|remote-control]', description: 'Check Codex App install, Codex Chrome Extension web verification readiness, PAT-safe status, first-party MCP/plugin readiness, and Codex CLI 0.130.0+ remote-control availability.' },
|
|
@@ -621,6 +638,7 @@ export const COMMAND_CATALOG = [
|
|
|
621
638
|
{ name: 'auto-review', usage: 'sks auto-review status|enable|start [--high] | sks --Auto-review --high', description: 'Enable Codex automatic approval review and launch SKS Zellij with the auto-review profile.' },
|
|
622
639
|
{ name: 'dollar-commands', usage: 'sks dollar-commands [--json]', description: 'List Codex App $ commands such as $DFix and $Team.' },
|
|
623
640
|
{ name: 'fast-mode', usage: 'sks fast-mode on|off|status|clear [--json]', description: 'Toggle the project-local Fast mode default used by $Fast-On, $Fast-Off, and native-agent routes.' },
|
|
641
|
+
{ name: 'with-local-llm', usage: 'sks with-local-llm on|off|status|set-model [--json]', description: 'Toggle the optional local Ollama worker backend used by $with-local-llm-on/$with-local-llm-off and eligible simple worker slices.' },
|
|
624
642
|
{ name: 'commit', usage: 'sks commit [--message "msg"] [--json]', description: 'Stage current changes, summarize them, and create a simple git commit without the full SKS pipeline.' },
|
|
625
643
|
{ name: 'commit-and-push', usage: 'sks commit-and-push [--message "msg"] [--json]', description: 'Stage current changes, create a simple git commit, and push without the full SKS pipeline.' },
|
|
626
644
|
{ name: 'dfix', usage: 'sks dfix', description: 'Explain $DFix ultralight direct-fix mode.' },
|
|
@@ -1007,6 +1025,8 @@ export function routeReasoning(route, prompt = '') {
|
|
|
1007
1025
|
const base = ALLOWED_REASONING_EFFORTS.has(route?.reasoningPolicy) ? route.reasoningPolicy : 'medium';
|
|
1008
1026
|
if (hasFromChatImgSignal(text))
|
|
1009
1027
|
return reasoning('xhigh', 'from_chat_img_image_work_order_analysis');
|
|
1028
|
+
if (/(?:^|\s)sks\s+--mad\b|(?:^|\s)--mad\b|\$MAD-SKS\b|\bmad-sks\b|\bmadsks\b/i.test(text))
|
|
1029
|
+
return reasoning('xhigh', 'mad_sks_or_mad_launch_default');
|
|
1010
1030
|
if (route?.id === 'Team')
|
|
1011
1031
|
return teamRouteReasoning(text);
|
|
1012
1032
|
if (route?.id === 'Research' || route?.id === 'AutoResearch')
|
package/dist/core/team-live.js
CHANGED
|
@@ -360,7 +360,13 @@ export function parseTeamSpecArgs(args = []) {
|
|
|
360
360
|
i++;
|
|
361
361
|
continue;
|
|
362
362
|
}
|
|
363
|
-
if (
|
|
363
|
+
if (/^--(?:ollama-model|local-model-model|ollama-base-url|local-model-base-url)$/.test(arg)) {
|
|
364
|
+
i++;
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
if (/^--(?:ollama-model|local-model-model|ollama-base-url|local-model-base-url)=/.test(arg))
|
|
368
|
+
continue;
|
|
369
|
+
if (arg === '--json' || arg === '--open-zellij' || arg === '--zellij-open' || arg === '--no-open-zellij' || arg === '--no-zellij' || arg === '--no-attach' || arg === '--separate-session' || arg === '--new-session' || arg === '--legacy-team-session' || arg === '--ollama' || arg === '--local-model' || arg === '--no-ollama' || arg === '--no-local-model')
|
|
364
370
|
continue;
|
|
365
371
|
const consumed = consumeTeamSpecText(arg, { roleCounts, explicitExecutor, explicitSession });
|
|
366
372
|
roleCounts = consumed.roleCounts;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import { PACKAGE_VERSION, packageRoot, readJson, runProcess, which } from './fsx.js';
|
|
3
4
|
const DEFAULT_REGISTRY = 'https://registry.npmjs.org/';
|
|
@@ -62,6 +63,132 @@ export async function runSksUpdateCheck(options = {}) {
|
|
|
62
63
|
npmBin
|
|
63
64
|
});
|
|
64
65
|
}
|
|
66
|
+
export async function runSksUpdateNow(options = {}) {
|
|
67
|
+
const packageName = options.packageName || 'sneakoscope';
|
|
68
|
+
const registry = options.registry || DEFAULT_REGISTRY;
|
|
69
|
+
const env = options.env || process.env;
|
|
70
|
+
const npmBin = options.npmBin === undefined ? await which('npm') : options.npmBin;
|
|
71
|
+
const cwd = os.homedir();
|
|
72
|
+
const check = await runSksUpdateCheck({
|
|
73
|
+
...options,
|
|
74
|
+
packageName,
|
|
75
|
+
registry,
|
|
76
|
+
npmBin,
|
|
77
|
+
env
|
|
78
|
+
});
|
|
79
|
+
const requestedVersion = parseVersionText(options.version || '') || null;
|
|
80
|
+
const installVersion = requestedVersion || check.latest;
|
|
81
|
+
const npmArgs = installVersion ? sksGlobalInstallArgs(packageName, installVersion, registry) : [];
|
|
82
|
+
const command = npmBin && npmArgs.length ? [npmBin, ...npmArgs].join(' ') : null;
|
|
83
|
+
const globalRoot = npmBin ? await detectNpmGlobalRoot(npmBin, env, options).catch(() => null) : null;
|
|
84
|
+
if (!npmBin) {
|
|
85
|
+
return buildUpdateNowResult({
|
|
86
|
+
packageName,
|
|
87
|
+
from: check.current,
|
|
88
|
+
latest: check.latest,
|
|
89
|
+
requestedVersion,
|
|
90
|
+
installVersion,
|
|
91
|
+
npmBin: null,
|
|
92
|
+
npmArgs,
|
|
93
|
+
command,
|
|
94
|
+
cwd,
|
|
95
|
+
registry,
|
|
96
|
+
globalRoot,
|
|
97
|
+
status: 'unavailable',
|
|
98
|
+
ok: false,
|
|
99
|
+
installCode: null,
|
|
100
|
+
error: 'npm not found on PATH'
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (!installVersion) {
|
|
104
|
+
return buildUpdateNowResult({
|
|
105
|
+
packageName,
|
|
106
|
+
from: check.current,
|
|
107
|
+
latest: check.latest,
|
|
108
|
+
requestedVersion,
|
|
109
|
+
installVersion,
|
|
110
|
+
npmBin,
|
|
111
|
+
npmArgs,
|
|
112
|
+
command,
|
|
113
|
+
cwd,
|
|
114
|
+
registry,
|
|
115
|
+
globalRoot,
|
|
116
|
+
status: 'unavailable',
|
|
117
|
+
ok: false,
|
|
118
|
+
installCode: null,
|
|
119
|
+
error: check.error || 'latest version unavailable'
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (!requestedVersion && check.latest && !check.update_available) {
|
|
123
|
+
return buildUpdateNowResult({
|
|
124
|
+
packageName,
|
|
125
|
+
from: check.current,
|
|
126
|
+
latest: check.latest,
|
|
127
|
+
requestedVersion,
|
|
128
|
+
installVersion,
|
|
129
|
+
npmBin,
|
|
130
|
+
npmArgs,
|
|
131
|
+
command,
|
|
132
|
+
cwd,
|
|
133
|
+
registry,
|
|
134
|
+
globalRoot,
|
|
135
|
+
status: 'current',
|
|
136
|
+
ok: true,
|
|
137
|
+
installCode: null,
|
|
138
|
+
error: null
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
if (options.dryRun) {
|
|
142
|
+
return buildUpdateNowResult({
|
|
143
|
+
packageName,
|
|
144
|
+
from: check.current,
|
|
145
|
+
latest: check.latest,
|
|
146
|
+
requestedVersion,
|
|
147
|
+
installVersion,
|
|
148
|
+
npmBin,
|
|
149
|
+
npmArgs,
|
|
150
|
+
command,
|
|
151
|
+
cwd,
|
|
152
|
+
registry,
|
|
153
|
+
globalRoot,
|
|
154
|
+
status: 'dry_run',
|
|
155
|
+
ok: true,
|
|
156
|
+
installCode: null,
|
|
157
|
+
error: null
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const install = await runProcess(npmBin, npmArgs, {
|
|
161
|
+
cwd,
|
|
162
|
+
env,
|
|
163
|
+
timeoutMs: options.timeoutMs ?? 10 * 60 * 1000,
|
|
164
|
+
maxOutputBytes: options.maxOutputBytes ?? 128 * 1024
|
|
165
|
+
}).catch((err) => ({
|
|
166
|
+
code: 1,
|
|
167
|
+
stdout: '',
|
|
168
|
+
stderr: err instanceof Error ? err.message : String(err)
|
|
169
|
+
}));
|
|
170
|
+
const ok = install.code === 0;
|
|
171
|
+
return buildUpdateNowResult({
|
|
172
|
+
packageName,
|
|
173
|
+
from: check.current,
|
|
174
|
+
latest: check.latest,
|
|
175
|
+
requestedVersion,
|
|
176
|
+
installVersion,
|
|
177
|
+
npmBin,
|
|
178
|
+
npmArgs,
|
|
179
|
+
command,
|
|
180
|
+
cwd,
|
|
181
|
+
registry,
|
|
182
|
+
globalRoot,
|
|
183
|
+
status: ok ? 'updated' : 'failed',
|
|
184
|
+
ok,
|
|
185
|
+
installCode: install.code,
|
|
186
|
+
error: ok ? null : `${install.stderr || install.stdout || 'npm global install failed'}`.trim()
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
export function sksGlobalInstallArgs(packageName, version, registry = DEFAULT_REGISTRY) {
|
|
190
|
+
return ['install', '--global', `${packageName}@${version}`, '--registry', registry];
|
|
191
|
+
}
|
|
65
192
|
export async function detectEffectiveSksVersion(options = {}) {
|
|
66
193
|
const packageName = options.packageName || 'sneakoscope';
|
|
67
194
|
const env = options.env || process.env;
|
|
@@ -183,12 +310,40 @@ function buildResult(input) {
|
|
|
183
310
|
mode: 'function',
|
|
184
311
|
route_required: false,
|
|
185
312
|
pipeline_required: false,
|
|
186
|
-
command: updateAvailable ? `
|
|
313
|
+
command: updateAvailable ? `sks update now --version ${input.latest}` : null,
|
|
187
314
|
npm_bin: input.npmBin,
|
|
188
315
|
registry: input.registry,
|
|
189
316
|
error: input.error || null
|
|
190
317
|
};
|
|
191
318
|
}
|
|
319
|
+
function buildUpdateNowResult(input) {
|
|
320
|
+
return {
|
|
321
|
+
schema: 'sks.update-now.v1',
|
|
322
|
+
ok: input.ok,
|
|
323
|
+
status: input.status,
|
|
324
|
+
package: input.packageName,
|
|
325
|
+
from: input.from,
|
|
326
|
+
latest: input.latest,
|
|
327
|
+
requested_version: input.requestedVersion,
|
|
328
|
+
install_version: input.installVersion,
|
|
329
|
+
npm_bin: input.npmBin,
|
|
330
|
+
npm_args: input.npmArgs,
|
|
331
|
+
command: input.command,
|
|
332
|
+
cwd: input.cwd,
|
|
333
|
+
registry: input.registry,
|
|
334
|
+
global_root: input.globalRoot,
|
|
335
|
+
install_code: input.installCode,
|
|
336
|
+
error: input.error
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
async function detectNpmGlobalRoot(npmBin, env, opts = {}) {
|
|
340
|
+
const result = await runProcess(npmBin, ['root', '--global', '--silent'], {
|
|
341
|
+
env,
|
|
342
|
+
timeoutMs: opts.timeoutMs ?? 2500,
|
|
343
|
+
maxOutputBytes: opts.maxOutputBytes ?? 4096
|
|
344
|
+
}).catch(() => ({ code: 1, stdout: '', stderr: '' }));
|
|
345
|
+
return result.code === 0 ? String(result.stdout || '').trim().split(/\r?\n/).pop() || null : null;
|
|
346
|
+
}
|
|
192
347
|
function versionOverrideEnvName(packageName) {
|
|
193
348
|
return `SKS_NPM_VIEW_${packageName.replace(/[^A-Za-z0-9]+/g, '_').toUpperCase()}_VERSION`;
|
|
194
349
|
}
|
|
@@ -87,6 +87,7 @@ export async function runVerificationTask(task, opts = {}) {
|
|
|
87
87
|
let timedOut = false;
|
|
88
88
|
const timeoutMs = task.timeout_ms || 10 * 60 * 1000;
|
|
89
89
|
let killTimeout = null;
|
|
90
|
+
let exitFallback = null;
|
|
90
91
|
const finish = (payload) => {
|
|
91
92
|
if (settled)
|
|
92
93
|
return;
|
|
@@ -94,6 +95,8 @@ export async function runVerificationTask(task, opts = {}) {
|
|
|
94
95
|
clearTimeout(timeout);
|
|
95
96
|
if (killTimeout)
|
|
96
97
|
clearTimeout(killTimeout);
|
|
98
|
+
if (exitFallback)
|
|
99
|
+
clearTimeout(exitFallback);
|
|
97
100
|
resolve(payload);
|
|
98
101
|
};
|
|
99
102
|
const timeout = setTimeout(() => {
|
|
@@ -113,6 +116,15 @@ export async function runVerificationTask(task, opts = {}) {
|
|
|
113
116
|
child.on('error', (err) => {
|
|
114
117
|
finish({ code: null, error: err.message });
|
|
115
118
|
});
|
|
119
|
+
child.on('exit', (code) => {
|
|
120
|
+
if (settled)
|
|
121
|
+
return;
|
|
122
|
+
exitFallback = setTimeout(async () => {
|
|
123
|
+
if (timedOut)
|
|
124
|
+
await waitForProcessTreeExit(child.pid, 2_000);
|
|
125
|
+
finish({ code, ...(timedOut ? { error: `timeout:${timeoutMs}` } : {}) });
|
|
126
|
+
}, 1_000);
|
|
127
|
+
});
|
|
116
128
|
child.on('close', async (code) => {
|
|
117
129
|
if (timedOut)
|
|
118
130
|
await waitForProcessTreeExit(child.pid, 2_000);
|
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '2.0.
|
|
1
|
+
export const PACKAGE_VERSION = '2.0.2';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -57,6 +57,8 @@ export function buildWorkerPaneArtifact(input) {
|
|
|
57
57
|
opened_at: now,
|
|
58
58
|
closed_at: null,
|
|
59
59
|
close: null,
|
|
60
|
+
direction_requested: 'right',
|
|
61
|
+
direction_applied: input.directionApplied || 'not_applied',
|
|
60
62
|
sdk_thread_id: input.sdkThreadId || null,
|
|
61
63
|
sdk_run_id: input.sdkRunId || null,
|
|
62
64
|
stream_event_count: Number(input.streamEventCount || 0),
|
|
@@ -81,13 +83,25 @@ export async function openWorkerPane(input) {
|
|
|
81
83
|
optional: false
|
|
82
84
|
});
|
|
83
85
|
const paneName = buildWorkerPaneTitle(input.slotId, input.generationIndex, providerContext, input.serviceTier);
|
|
84
|
-
|
|
85
|
-
? await runZellij(['--session', input.sessionName, 'action', 'new-pane', '--name', paneName, '--', 'sh', '-lc', input.workerCommand], {
|
|
86
|
+
let launch = createSession.ok
|
|
87
|
+
? await runZellij(['--session', input.sessionName, 'action', 'new-pane', '--direction', 'right', '--name', paneName, '--', 'sh', '-lc', input.workerCommand], {
|
|
86
88
|
cwd,
|
|
87
89
|
timeoutMs: 5000,
|
|
88
90
|
optional: false
|
|
89
91
|
})
|
|
90
92
|
: null;
|
|
93
|
+
let directionApplied = launch?.ok ? 'right' : 'not_applied';
|
|
94
|
+
if (createSession.ok && launch && !launch.ok) {
|
|
95
|
+
const fallback = await runZellij(['--session', input.sessionName, 'action', 'new-pane', '--name', paneName, '--', 'sh', '-lc', input.workerCommand], {
|
|
96
|
+
cwd,
|
|
97
|
+
timeoutMs: 5000,
|
|
98
|
+
optional: false
|
|
99
|
+
});
|
|
100
|
+
if (fallback.ok) {
|
|
101
|
+
launch = fallback;
|
|
102
|
+
directionApplied = 'unknown';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
91
105
|
const stdoutPaneId = launch?.ok ? extractZellijPaneIdFromOutput(launch.stdout_tail) : null;
|
|
92
106
|
const reconciledPane = stdoutPaneId ? null : launch?.ok ? await reconcileZellijWorkerPaneId(input.sessionName, paneName, path.join(root, input.resultPath), cwd) : null;
|
|
93
107
|
const paneId = stdoutPaneId || reconciledPane?.pane_id || null;
|
|
@@ -110,6 +124,7 @@ export async function openWorkerPane(input) {
|
|
|
110
124
|
createSession,
|
|
111
125
|
launch,
|
|
112
126
|
paneReconciliation: reconciledPane,
|
|
127
|
+
directionApplied,
|
|
113
128
|
status: blockers.length ? 'failed' : 'running',
|
|
114
129
|
providerContext,
|
|
115
130
|
serviceTier: input.serviceTier || providerContext.service_tier,
|
|
@@ -139,6 +154,8 @@ export async function openWorkerPane(input) {
|
|
|
139
154
|
provider: record.provider,
|
|
140
155
|
service_tier: record.service_tier,
|
|
141
156
|
provider_context: record.provider_context,
|
|
157
|
+
direction_requested: record.direction_requested,
|
|
158
|
+
direction_applied: record.direction_applied,
|
|
142
159
|
command: '<native-cli-worker-command>',
|
|
143
160
|
worker_artifact_dir: input.workerArtifactDir,
|
|
144
161
|
worker_result_path: input.resultPath,
|
|
@@ -20,6 +20,6 @@ assertGate(Object.keys(graph.command_to_module_ownership).length > 0, 'AST-aware
|
|
|
20
20
|
assertGate(graph.test_ownership_confidence >= 0, 'AST-aware work graph must record test ownership confidence', graph);
|
|
21
21
|
assertGate(['proven', 'partial', 'blocked'].includes(graph.proof_level), 'AST-aware work graph must report an honest proof level', graph);
|
|
22
22
|
fs.mkdirSync(path.join(root, '.sneakoscope', 'reports'), { recursive: true });
|
|
23
|
-
fs.writeFileSync(path.join(root, '.sneakoscope', 'reports', `agent-intelligent-work-graph-v2-${releaseVersion}.json`), `${JSON.stringify(graph, null, 2)}\n`);
|
|
23
|
+
fs.writeFileSync(path.join(root, '.sneakoscope', 'reports', `agent-intelligent-work-graph-v2-${releaseVersion}.json`), `${JSON.stringify(graphMod.compactIntelligentWorkGraph(graph), null, 2)}\n`);
|
|
24
24
|
emitGate('agent:ast-aware-work-graph', { score: graph.work_graph_quality_score, ast_coverage: graph.ast_coverage, proof_level: graph.proof_level });
|
|
25
25
|
//# sourceMappingURL=agent-ast-aware-work-graph-check.js.map
|