sneakoscope 4.6.4 → 4.7.0
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 -4
- 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/bin/sks.js +1 -1
- package/dist/cli/install-helpers.js +73 -6
- package/dist/commands/codex-app.js +34 -3
- package/dist/commands/doctor.js +6 -1
- package/dist/core/agents/agent-effort-policy.js +110 -5
- package/dist/core/agents/agent-orchestrator.js +27 -3
- package/dist/core/agents/agent-plan.js +2 -2
- package/dist/core/agents/agent-roster.js +8 -0
- package/dist/core/agents/agent-worker-slot.js +4 -0
- package/dist/core/codex/agent-config-file-repair.js +4 -4
- package/dist/core/codex-app/glm-model-profile.js +1 -1
- package/dist/core/codex-app/glm-profile-installer.js +111 -7
- package/dist/core/codex-app/glm-profile-schema.js +21 -2
- package/dist/core/codex-control/codex-sdk-config-policy.js +2 -1
- package/dist/core/codex-model-guard.js +3 -1
- package/dist/core/commands/fast-mode-command.js +5 -2
- package/dist/core/commands/glm-command.js +2 -1
- package/dist/core/commands/mad-sks-command.js +24 -0
- package/dist/core/doctor/doctor-codex-startup-repair.js +111 -9
- package/dist/core/feature-registry.js +3 -3
- package/dist/core/fsx.js +1 -1
- package/dist/core/harness-guard.js +89 -3
- package/dist/core/init.js +9 -9
- package/dist/core/managed-assets/managed-assets-manifest.js +9 -8
- package/dist/core/pipeline-internals/runtime-core.js +3 -3
- package/dist/core/providers/glm/glm-52-profile.js +46 -0
- package/dist/core/providers/glm/glm-52-request.js +11 -2
- package/dist/core/providers/glm/glm-direct-run.js +1 -0
- package/dist/core/providers/glm/glm-mad-launch.js +3 -2
- package/dist/core/providers/glm/glm-profile-resolver.js +69 -4
- package/dist/core/providers/glm/naruto/glm-naruto-command.js +2 -1
- package/dist/core/team-live.js +2 -2
- package/dist/core/version.js +1 -1
- package/dist/scripts/agent-role-config-repair-check.js +5 -3
- package/dist/scripts/codex-native-reference-cache-check.js +8 -1
- package/dist/scripts/doctor-codex-startup-repair-check.js +21 -0
- package/dist/scripts/naruto-shadow-clone-swarm-check.js +11 -3
- package/dist/scripts/release-readiness-report.js +1 -1
- package/dist/scripts/sks-3-1-6-directive-check-lib.js +11 -0
- package/package.json +1 -1
package/dist/core/init.js
CHANGED
|
@@ -814,11 +814,11 @@ export async function initProject(root, opts = {}) {
|
|
|
814
814
|
// with `url is not supported for stdio`. Remote is also the transport the doctor
|
|
815
815
|
// migrates everyone to (local stdio can block interactive Codex launch).
|
|
816
816
|
{ table: 'mcp_servers.context7', text: context7ConfigToml('remote').trim(), preserveExisting: true },
|
|
817
|
-
{ table: 'agents.native_agent', text: agentConfigBlock('native_agent', '
|
|
818
|
-
{ table: 'agents.team_consensus', text: agentConfigBlock('team_consensus', 'SKS planning/debate agent.', './agents/team-consensus.toml', ['Consensus', 'Atlas']) },
|
|
817
|
+
{ table: 'agents.native_agent', text: agentConfigBlock('native_agent', 'SKS native agent with bounded write capability.', './agents/native-agent-intake.toml', ['Analysis', 'Mapper']) },
|
|
818
|
+
{ table: 'agents.team_consensus', text: agentConfigBlock('team_consensus', 'SKS planning/debate agent with bounded write capability.', './agents/team-consensus.toml', ['Consensus', 'Atlas']) },
|
|
819
819
|
{ table: 'agents.implementation_worker', text: agentConfigBlock('implementation_worker', 'SKS bounded implementation worker.', './agents/implementation-worker.toml', ['Builder', 'Mason']) },
|
|
820
|
-
{ table: 'agents.db_safety_reviewer', text: agentConfigBlock('db_safety_reviewer', '
|
|
821
|
-
{ table: 'agents.qa_reviewer', text: agentConfigBlock('qa_reviewer', '
|
|
820
|
+
{ table: 'agents.db_safety_reviewer', text: agentConfigBlock('db_safety_reviewer', 'DB safety reviewer with bounded write capability.', './agents/db-safety-reviewer.toml', ['Sentinel', 'Ledger']) },
|
|
821
|
+
{ table: 'agents.qa_reviewer', text: agentConfigBlock('qa_reviewer', 'QA reviewer with bounded write capability.', './agents/qa-reviewer.toml', ['Verifier', 'Reviewer']) },
|
|
822
822
|
// NOTE: SKS config profiles are NO LONGER emitted as `[profiles.sks-*]` tables.
|
|
823
823
|
// Codex 0.134+ deprecated config-profile tables / the `profile=` selector (warns at
|
|
824
824
|
// startup) in favor of per-file `$CODEX_HOME/<name>.config.toml` overlays loaded by
|
|
@@ -1304,12 +1304,12 @@ async function removeDirIfEmpty(dir) {
|
|
|
1304
1304
|
}
|
|
1305
1305
|
async function installCodexAgents(root) {
|
|
1306
1306
|
const agents = {
|
|
1307
|
-
'analysis-scout.toml': `name = "analysis_scout"\ndescription = "
|
|
1308
|
-
'native-agent-intake.toml': `name = "native_agent"\ndescription = "
|
|
1309
|
-
'team-consensus.toml': `name = "team_consensus"\ndescription = "Planning and debate specialist for SKS Team mode. Maps options, constraints, role-persona risks, and proposes the agreed objective before implementation starts."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "
|
|
1307
|
+
'analysis-scout.toml': `name = "analysis_scout"\ndescription = "SKS analysis scout with bounded write capability retained for stale Codex agent-role config repair."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "low"\nsandbox_mode = "workspace-write"\ndeveloper_instructions = """\nYou are an SKS analysis scout.\nOnly edit bounded files assigned by the parent orchestrator; otherwise inspect only and return concise source-backed findings.\n"""\n`,
|
|
1308
|
+
'native-agent-intake.toml': `name = "native_agent"\ndescription = "Team native agent with bounded write capability. Maps one independent repo/docs/tests/API/risk/user-friction slice and can produce patch-envelope work when assigned."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "low"\nsandbox_mode = "workspace-write"\ndeveloper_instructions = """\nYou are an SKS Team native agent.\nOnly edit bounded files assigned by the parent orchestrator.\nOwn exactly one investigation or implementation slice assigned by the parent orchestrator.\nUse the mission roster or worker inbox model and model_reasoning_effort when the host exposes it: simple bounded work may use gpt-5.4-mini, ordinary tool work uses gpt-5.5 low, and knowledge/research/safety/release work uses gpt-5.5 high.\nMap relevant source files, docs, tests, APIs, DB or safety risks, UX friction, and likely implementation boundaries.\nReturn concise source-backed claims suitable for team-analysis.md and TriWiki ingestion: claim, source path, evidence hash or quoted anchor, risk, confidence, and recommended implementation slice.\nDo not debate the final plan. Implement only when the assigned slice includes write paths.\nAlso return a concise LIVE_EVENT line that the parent can record with sks team event.\n"""\n`,
|
|
1309
|
+
'team-consensus.toml': `name = "team_consensus"\ndescription = "Planning and debate specialist for SKS Team mode with bounded write capability. Maps options, constraints, role-persona risks, and proposes the agreed objective before implementation starts."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "workspace-write"\ndeveloper_instructions = """\nYou are the SKS Team consensus specialist.\nOnly edit bounded files assigned by the parent orchestrator.\nUse the mission roster model and model_reasoning_effort when the host exposes them; planning normally uses gpt-5.5 low or high depending on risk.\nMap the affected code paths, viable approaches, constraints, risks, and acceptance criteria.\nRun the debate as role-persona synthesis: final users are low-context, self-interested, stubborn, and inconvenience-averse; executors are capable developers; reviewers are strict.\nArgue for the smallest coherent objective that can be handed to a fresh executor_N development team.\nPlan for at least ${MIN_TEAM_REVIEWER_LANES} independent reviewer/QA validation lanes before integration or final.\nReturn: recommended objective, rejected alternatives, implementation slices, required reviewers, user-friction risks, and unresolved risks.\nAlso return a concise LIVE_EVENT line that the parent can record with sks team event.\n"""\n`,
|
|
1310
1310
|
'implementation-worker.toml': `name = "implementation_worker"\ndescription = "Implementation specialist for SKS Team mode. Owns one bounded write set and coordinates with other executor_N workers."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "medium"\nsandbox_mode = "workspace-write"\ndeveloper_instructions = """\nYou are an SKS Team executor/developer in the fresh development bundle.\nYou are not alone in the codebase. Other executor_N workers may be editing disjoint files.\nUse the mission roster or worker inbox reasoning_effort when the host exposes it; simple bounded changes can use low, tool-heavy implementation medium, and safety/release/DB work high.\nOnly edit the files or module slice assigned to you.\nDo not revert or overwrite edits made by others.\nRead local patterns first, make the smallest correct change, avoid adding user friction, run focused verification for your slice, and report changed paths plus evidence.\nDo not create fallback implementation code, substitute behavior, mock behavior, or compatibility shims unless the user or sealed decision contract explicitly requested them.\nRespect all SKS hooks, DB safety rules, no-question run rules, and H-Proof completion gates.\nAlso return concise LIVE_EVENT lines for started, blocked, changed files, verification, and final result so the parent can record them.\n"""\n`,
|
|
1311
|
-
'db-safety-reviewer.toml': `name = "db_safety_reviewer"\ndescription = "
|
|
1312
|
-
'qa-reviewer.toml': `name = "qa_reviewer"\ndescription = "Strict
|
|
1311
|
+
'db-safety-reviewer.toml': `name = "db_safety_reviewer"\ndescription = "Database safety reviewer with bounded write capability for SQL, migrations, Supabase, RLS, destructive-operation risk, and rollback safety."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "workspace-write"\ndeveloper_instructions = """\nYou are a database safety reviewer.\nOnly edit bounded files assigned by the parent orchestrator. Never execute destructive commands.\nReview migrations, SQL, Supabase RLS, transaction boundaries, rollback safety, and MCP database tool usage.\nBlock DROP, TRUNCATE, mass DELETE/UPDATE, db reset, db push, project deletion, branch reset/merge/delete, RLS disabling, and live execute_sql writes.\nReturn concrete risks, exact file references, and required fixes.\nAlso return a concise LIVE_EVENT line that the parent can record with sks team event.\n"""\n`,
|
|
1312
|
+
'qa-reviewer.toml': `name = "qa_reviewer"\ndescription = "Strict verification reviewer with bounded write capability for correctness, regressions, missing tests, user friction, and final evidence."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "workspace-write"\ndeveloper_instructions = """\nYou are an SKS Team strict reviewer.\nOnly edit bounded files assigned by the parent orchestrator.\nReview correctness, edge cases, regression risk, missing tests, unsupported claims, and whether the final evidence proves the claimed outcome.\nTeam review must cover at least ${MIN_TEAM_REVIEWER_LANES} independent reviewer/QA validation lanes before integration or final; flag missing review lane evidence.\nAlso evaluate practical friction from the viewpoint of a stubborn, low-context final user who dislikes inconvenience.\nPrioritize concrete findings with file references and focused verification suggestions.\nFlag any unrequested fallback implementation code, substitute behavior, mock behavior, or compatibility shim as a blocking finding unless the user or sealed decision contract explicitly requested it.\nReturn no findings if the implementation is sound, and clearly list residual test gaps.\nAlso return a concise LIVE_EVENT line that the parent can record with sks team event.\n"""\n`
|
|
1313
1313
|
};
|
|
1314
1314
|
const dir = path.join(root, '.codex', 'agents');
|
|
1315
1315
|
await ensureDir(dir);
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { REQUIRED_CODEX_MODEL } from '../codex-model-guard.js';
|
|
2
2
|
export const MANAGED_ASSET_SCHEMA_VERSION = 1;
|
|
3
|
-
export const MANAGED_ASSET_VERSION = '4.
|
|
3
|
+
export const MANAGED_ASSET_VERSION = '4.7.0';
|
|
4
4
|
export const MANAGED_ASSET_MARKER = 'SKS-MANAGED-ASSET';
|
|
5
5
|
export const MANAGED_AGENT_ROLES = Object.freeze([
|
|
6
|
-
role('sks-explorer', 'analysis-scout.toml', 'analysis_scout', '
|
|
7
|
-
role('sks-
|
|
6
|
+
role('sks-explorer', 'analysis-scout.toml', 'analysis_scout', 'SKS analysis scout for bounded read/write slices retained for stale Codex agent-role config repair.', 'workspace-write', ['analysis-scout', 'analysis_scout']),
|
|
7
|
+
role('sks-native-agent', 'native-agent-intake.toml', 'native_agent', 'SKS native agent for bounded read/write intake slices.', 'workspace-write', ['native-agent-intake', 'native_agent']),
|
|
8
|
+
role('sks-planner', 'team-consensus.toml', 'team_consensus', 'Planning and debate specialist for bounded SKS Team mode write sets.', 'workspace-write', ['team-consensus', 'team_consensus']),
|
|
8
9
|
role('sks-implementer', 'implementation-worker.toml', 'implementation_worker', 'Implementation specialist for bounded SKS Team write sets.', 'workspace-write', ['implementation-worker', 'implementation_worker']),
|
|
9
|
-
role('sks-checker', 'qa-reviewer.toml', 'qa_reviewer', 'Strict
|
|
10
|
-
role('sks-release-verifier', 'sks-release-verifier.toml', 'sks_release_verifier', '
|
|
11
|
-
role('sks-zellij-ui-verifier', 'sks-zellij-ui-verifier.toml', 'sks_zellij_ui_verifier', '
|
|
12
|
-
role('sks-codex-probe-verifier', 'sks-codex-probe-verifier.toml', 'sks_codex_probe_verifier', '
|
|
13
|
-
role('db-safety-reviewer', 'db-safety-reviewer.toml', 'db_safety_reviewer', '
|
|
10
|
+
role('sks-checker', 'qa-reviewer.toml', 'qa_reviewer', 'Strict verification reviewer for correctness, regressions, and final evidence with bounded write capability.', 'workspace-write', ['qa-reviewer', 'qa_reviewer']),
|
|
11
|
+
role('sks-release-verifier', 'sks-release-verifier.toml', 'sks_release_verifier', 'Release verifier for repository, docs, tests, API, and risk slices with bounded write capability.', 'workspace-write', ['release-verifier']),
|
|
12
|
+
role('sks-zellij-ui-verifier', 'sks-zellij-ui-verifier.toml', 'sks_zellij_ui_verifier', 'Zellij UI verifier for session, pane, layout, and terminal evidence with bounded write capability.', 'workspace-write', ['zellij-ui-verifier']),
|
|
13
|
+
role('sks-codex-probe-verifier', 'sks-codex-probe-verifier.toml', 'sks_codex_probe_verifier', 'Codex probe verifier for CLI, App, SDK, MCP, and native capability evidence with bounded write capability.', 'workspace-write', ['codex-probe-verifier']),
|
|
14
|
+
role('db-safety-reviewer', 'db-safety-reviewer.toml', 'db_safety_reviewer', 'Database safety reviewer for SQL, migrations, Supabase, and rollback safety with bounded write capability.', 'workspace-write', ['db-safety-reviewer', 'db_safety_reviewer'])
|
|
14
15
|
]);
|
|
15
16
|
export const MANAGED_SKILLS = Object.freeze([
|
|
16
17
|
'loop',
|
|
@@ -213,7 +213,7 @@ export function validatePipelinePlan(plan = {}) {
|
|
|
213
213
|
issues.push('ssot_guard_stage');
|
|
214
214
|
if (!plan.next_actions?.length)
|
|
215
215
|
issues.push('next_actions');
|
|
216
|
-
if (plan.agent_intake?.required && !plan.stages?.some((stage) => stage.id === AGENT_INTAKE_STAGE_ID && stage.agent_count === AGENT_COUNT && stage.read_only ===
|
|
216
|
+
if (plan.agent_intake?.required && !plan.stages?.some((stage) => stage.id === AGENT_INTAKE_STAGE_ID && stage.agent_count === AGENT_COUNT && stage.read_only === false && /bounded workspace-write/i.test(String(stage.write_policy || '')) && /lease/i.test(String(stage.write_policy || ''))))
|
|
217
217
|
issues.push('agent_intake_stage');
|
|
218
218
|
return { ok: issues.length === 0, issues };
|
|
219
219
|
}
|
|
@@ -970,7 +970,7 @@ async function materializeAutoSealedTeam(root, id, dir, route, task, contractHas
|
|
|
970
970
|
team_runtime: teamRuntimePlanMetadata(),
|
|
971
971
|
phases: [
|
|
972
972
|
{ id: 'team_roster_confirmation', goal: `Materialize the Team roster from default SKS counts or explicit user counts, write team-roster.json, and surface role counts ${formatRoleCounts(roleCounts)}.`, agents: ['parent_orchestrator'], output: 'team-roster.json' },
|
|
973
|
-
{ id: 'native_agent_intake', goal: `Read TriWiki context, then run exactly ${roster.bundle_size}
|
|
973
|
+
{ id: 'native_agent_intake', goal: `Read TriWiki context, then run exactly ${roster.bundle_size} bounded workspace-write native_agent_N sessions in parallel. ${fromChatImgRequired ? `From-Chat-IMG active: ${CODEX_COMPUTER_USE_ONLY_POLICY}` : 'From-Chat-IMG inactive: do not assume ordinary images are chat captures.'} Native agents may edit only parent-assigned lease paths and parent integration owns final changes.`, agents: roster.analysis_team.map((agent) => agent.id), max_parallel_native_sessions: agentSessions, write_policy: 'bounded workspace-write leases; parent-owned integration' },
|
|
974
974
|
{ id: 'triwiki_refresh', goal: `Refresh or pack TriWiki and run ${triwikiContextTracking().validate_command}.`, agents: ['parent_orchestrator'], output: '.sneakoscope/wiki/context-pack.json' },
|
|
975
975
|
{ id: 'ssot_guard', goal: ssotGuardPolicyText(), agents: ['parent_orchestrator'], output: SSOT_GUARD_ARTIFACT },
|
|
976
976
|
{ id: 'planning_debate', goal: 'Run read-only planning debate, map constraints and implementation slices, then seal one objective.', agents: roster.debate_team.map((agent) => agent.id) },
|
|
@@ -1063,7 +1063,7 @@ async function prepareTeam(root, route, task, required, opts = {}) {
|
|
|
1063
1063
|
team_runtime: teamRuntimePlanMetadata(),
|
|
1064
1064
|
phases: [
|
|
1065
1065
|
{ id: 'team_roster_confirmation', goal: `Before any implementation, materialize the Team roster from default SKS counts or explicit user counts, write team-roster.json, and surface role counts ${formatRoleCounts(roleCounts)}. Implementation cannot be considered complete unless team-gate.json has team_roster_confirmed=true.`, agents: ['parent_orchestrator'], output: 'team-roster.json' },
|
|
1066
|
-
{ id: 'native_agent_intake', goal: `Before native agent intake, read TriWiki context. ${fromChatImgRequired ? `From-Chat-IMG active: for web/browser/webapp targets require Codex Chrome Extension readiness first; for native Mac/non-web surfaces use Codex Computer Use visual inspection when available. List every visible customer request, match every screenshot image region to attachments, write ${FROM_CHAT_IMG_COVERAGE_ARTIFACT}, ${FROM_CHAT_IMG_CHECKLIST_ARTIFACT}, and ${FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT}, then require scoped QA-LOOP evidence in ${FROM_CHAT_IMG_QA_LOOP_ARTIFACT} after the customer-request work is done. ${CODEX_WEB_VERIFICATION_POLICY} ${CODEX_COMPUTER_USE_ONLY_POLICY}` : `From-Chat-IMG inactive: do not assume ordinary images are chat captures. ${CODEX_WEB_VERIFICATION_POLICY} ${CODEX_COMPUTER_USE_ONLY_POLICY}`} Run exactly ${roster.bundle_size}
|
|
1066
|
+
{ id: 'native_agent_intake', goal: `Before native agent intake, read TriWiki context. ${fromChatImgRequired ? `From-Chat-IMG active: for web/browser/webapp targets require Codex Chrome Extension readiness first; for native Mac/non-web surfaces use Codex Computer Use visual inspection when available. List every visible customer request, match every screenshot image region to attachments, write ${FROM_CHAT_IMG_COVERAGE_ARTIFACT}, ${FROM_CHAT_IMG_CHECKLIST_ARTIFACT}, and ${FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT}, then require scoped QA-LOOP evidence in ${FROM_CHAT_IMG_QA_LOOP_ARTIFACT} after the customer-request work is done. ${CODEX_WEB_VERIFICATION_POLICY} ${CODEX_COMPUTER_USE_ONLY_POLICY}` : `From-Chat-IMG inactive: do not assume ordinary images are chat captures. ${CODEX_WEB_VERIFICATION_POLICY} ${CODEX_COMPUTER_USE_ONLY_POLICY}`} Run exactly ${roster.bundle_size} bounded workspace-write native_agent_N sessions in parallel, using the full available session budget without exceeding ${agentSessions}. Split repo/docs/tests/API/user-flow/risk investigation into independent slices, hydrate relevant low-trust claims from source, record source-backed findings, and edit only parent-assigned lease paths.`, agents: roster.analysis_team.map((agent) => agent.id), max_parallel_native_sessions: agentSessions, write_policy: 'bounded workspace-write leases; parent-owned integration' },
|
|
1067
1067
|
{ id: 'triwiki_refresh', goal: `Parent orchestrator updates Team analysis artifacts, then runs ${triwikiContextTracking().refresh_command} or ${triwikiContextTracking().pack_command}, prunes with ${triwikiContextTracking().prune_command} when stale/oversized wiki state would pollute handoffs, and runs ${triwikiContextTracking().validate_command} so the next stage uses current TriWiki context.`, agents: ['parent_orchestrator'], output: '.sneakoscope/wiki/context-pack.json' },
|
|
1068
1068
|
{ id: 'ssot_guard', goal: ssotGuardPolicyText(), agents: ['parent_orchestrator'], output: SSOT_GUARD_ARTIFACT },
|
|
1069
1069
|
{ id: 'planning_debate', goal: `Before debate, read the refreshed TriWiki pack. Debate team of exactly ${roster.bundle_size} participants maps user inconvenience, options, constraints, affected files, DB/test risk, and tradeoffs while applying compact Hyperplan-derived lenses: challenge framing, subtract surface, demand evidence, test integration risk, and consider one simpler alternative. Hydrate low-trust claims from source.`, agents: roster.debate_team.map((agent) => agent.id) },
|
|
@@ -2,6 +2,48 @@ import { GLM_52_OPENROUTER_MODEL, GLM_MAD_MODE } from './glm-52-settings.js';
|
|
|
2
2
|
import { profileFromConst } from './glm-profile-resolver.js';
|
|
3
3
|
export const GLM_CODEX_APP_PROFILE_ID = 'sks/glm-5.2-mad';
|
|
4
4
|
export const GLM_CODEX_APP_PROFILE_LABEL = 'GLM 5.2 (MAD Speed / OpenRouter)';
|
|
5
|
+
export const GLM_CODEX_CONFIG_PROVIDER_ID = 'openrouter';
|
|
6
|
+
export const GLM_CODEX_CONFIG_PROFILE_ID = 'sks-glm-52-mad';
|
|
7
|
+
export const GLM_CODEX_SELECTABLE_REASONING_EFFORTS = [
|
|
8
|
+
'none',
|
|
9
|
+
'minimal',
|
|
10
|
+
'low',
|
|
11
|
+
'medium',
|
|
12
|
+
'high',
|
|
13
|
+
'xhigh',
|
|
14
|
+
];
|
|
15
|
+
export const GLM_CODEX_CONFIG_REASONING_PROFILES = [
|
|
16
|
+
{
|
|
17
|
+
id: GLM_CODEX_CONFIG_PROFILE_ID,
|
|
18
|
+
label: 'GLM 5.2 MAD Speed',
|
|
19
|
+
reasoning_effort: 'none',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: 'sks-glm-52-minimal',
|
|
23
|
+
label: 'GLM 5.2 Minimal',
|
|
24
|
+
reasoning_effort: 'minimal',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'sks-glm-52-low',
|
|
28
|
+
label: 'GLM 5.2 Low',
|
|
29
|
+
reasoning_effort: 'low',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'sks-glm-52-medium',
|
|
33
|
+
label: 'GLM 5.2 Medium',
|
|
34
|
+
reasoning_effort: 'medium',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'sks-glm-52-high',
|
|
38
|
+
label: 'GLM 5.2 High',
|
|
39
|
+
reasoning_effort: 'high',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: 'sks-glm-52-xhigh',
|
|
43
|
+
label: 'GLM 5.2 XHigh',
|
|
44
|
+
reasoning_effort: 'xhigh',
|
|
45
|
+
},
|
|
46
|
+
];
|
|
5
47
|
export function buildGlmCodexAppModelProfile() {
|
|
6
48
|
const speed = profileFromConst('speed');
|
|
7
49
|
return {
|
|
@@ -10,6 +52,10 @@ export function buildGlmCodexAppModelProfile() {
|
|
|
10
52
|
label: GLM_CODEX_APP_PROFILE_LABEL,
|
|
11
53
|
provider: 'openrouter',
|
|
12
54
|
model: GLM_52_OPENROUTER_MODEL,
|
|
55
|
+
codexConfigProvider: GLM_CODEX_CONFIG_PROVIDER_ID,
|
|
56
|
+
codexConfigProfile: GLM_CODEX_CONFIG_PROFILE_ID,
|
|
57
|
+
supportedReasoningEfforts: GLM_CODEX_SELECTABLE_REASONING_EFFORTS,
|
|
58
|
+
reasoningProfiles: GLM_CODEX_CONFIG_REASONING_PROFILES,
|
|
13
59
|
mode: GLM_MAD_MODE,
|
|
14
60
|
strictModelLock: true,
|
|
15
61
|
gptFallbackAllowed: false,
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { GLM_52_DEFAULT_REQUEST_SETTINGS, GLM_52_OPENROUTER_MODEL, clampGlm52MaxTokens } from './glm-52-settings.js';
|
|
2
2
|
import { buildDeepReasoningConfig, buildFastReasoningConfig } from './glm-reasoning-policy.js';
|
|
3
|
-
import { profileFromConst, resolveGlmProfileFromArgs } from './glm-profile-resolver.js';
|
|
3
|
+
import { profileFromConst, reasoningEffortFromGlmSlashModelArgs, resolveGlmProfileFromArgs } from './glm-profile-resolver.js';
|
|
4
4
|
export function buildGlm52Request(input) {
|
|
5
5
|
const profile = resolveInputProfile(input.profile, input.args, input.reasoningEffort);
|
|
6
6
|
if (profile.blockers.length) {
|
|
7
7
|
throw new Error(`GLM request profile blocked: ${profile.blockers.join(', ')}`);
|
|
8
8
|
}
|
|
9
9
|
const strictOrDeepEffort = profile.reasoning_effort || (input.reasoningEffort === 'high' || input.reasoningEffort === 'xhigh' ? input.reasoningEffort : undefined);
|
|
10
|
+
const selectedReasoningEffort = input.reasoningEffort || (input.args ? reasoningEffortFromGlmSlashModelArgs(input.args) || undefined : undefined);
|
|
10
11
|
const reasoning = profile.name === 'speed'
|
|
11
|
-
?
|
|
12
|
+
? buildSpeedReasoningConfig(selectedReasoningEffort, input.reasoningMeta)
|
|
12
13
|
: buildDeepReasoningConfig(strictOrDeepEffort || 'high');
|
|
13
14
|
if (profile.name === 'speed' && (reasoning.effort === 'high' || reasoning.effort === 'xhigh')) {
|
|
14
15
|
throw new Error(`GLM speed profile invariant violated: forbidden reasoning effort ${reasoning.effort}`);
|
|
@@ -62,4 +63,12 @@ function resolveInputProfile(profile, args, reasoningEffort) {
|
|
|
62
63
|
return profileFromConst('deep');
|
|
63
64
|
return profileFromConst(GLM_52_DEFAULT_REQUEST_SETTINGS.mode === 'mad-glm-speed' ? 'speed' : 'speed');
|
|
64
65
|
}
|
|
66
|
+
function buildSpeedReasoningConfig(reasoningEffort, reasoningMeta) {
|
|
67
|
+
if (reasoningEffort === 'none')
|
|
68
|
+
return { exclude: true };
|
|
69
|
+
if (reasoningEffort === 'minimal' || reasoningEffort === 'low' || reasoningEffort === 'medium') {
|
|
70
|
+
return { effort: reasoningEffort, exclude: true };
|
|
71
|
+
}
|
|
72
|
+
return buildFastReasoningConfig(reasoningMeta);
|
|
73
|
+
}
|
|
65
74
|
//# sourceMappingURL=glm-52-request.js.map
|
|
@@ -39,6 +39,7 @@ export async function runGlmDirectSpeedRun(input) {
|
|
|
39
39
|
controller.transition('request');
|
|
40
40
|
const request = buildGlm52Request({
|
|
41
41
|
profile: 'speed',
|
|
42
|
+
...(input.args ? { args: input.args } : {}),
|
|
42
43
|
messages: [
|
|
43
44
|
{ role: 'system', content: 'Return only <sks_patch>, <sks_need_context>, or <sks_blocked>. Use unified diff for patches.' },
|
|
44
45
|
{ role: 'user', content: JSON.stringify({ task: input.task, context }) }
|
|
@@ -45,7 +45,8 @@ export function buildMadGlmLaunchProfileNoWrite(args = []) {
|
|
|
45
45
|
model_reasoning_effort: effort,
|
|
46
46
|
service_tier: 'fast',
|
|
47
47
|
gpt_fallback_allowed: false,
|
|
48
|
-
writes_user_codex_config: false
|
|
48
|
+
writes_user_codex_config: false,
|
|
49
|
+
blockers: profile.blockers
|
|
49
50
|
};
|
|
50
51
|
}
|
|
51
52
|
export async function resolveMadGlmLaunchKey(env = process.env) {
|
|
@@ -111,7 +112,7 @@ export function buildMadGlmLaunchArtifact(input) {
|
|
|
111
112
|
real_codex_bin: input.wrapper.real_codex_bin,
|
|
112
113
|
raw_key_written_to_wrapper: false,
|
|
113
114
|
codex_args: profile.launch_args,
|
|
114
|
-
blockers: input.keyResolution.key ? [] : input.keyResolution.blockers,
|
|
115
|
+
blockers: [...profile.blockers, ...(input.keyResolution.key ? [] : input.keyResolution.blockers)],
|
|
115
116
|
warnings: input.keyResolution.warnings || []
|
|
116
117
|
};
|
|
117
118
|
}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { readOption } from '../../../cli/args.js';
|
|
2
|
-
import { GLM_DEEP_MODE, GLM_DEEP_PROFILE, GLM_SPEED_MODE, GLM_SPEED_PROFILE, GLM_STRICT_MODE, GLM_STRICT_PROFILE, GLM_XHIGH_MODE, GLM_XHIGH_PROFILE } from './glm-52-settings.js';
|
|
2
|
+
import { GLM_DEEP_MODE, GLM_DEEP_PROFILE, GLM_52_OPENROUTER_MODEL, GLM_SPEED_MODE, GLM_SPEED_PROFILE, GLM_STRICT_MODE, GLM_STRICT_PROFILE, GLM_XHIGH_MODE, GLM_XHIGH_PROFILE } from './glm-52-settings.js';
|
|
3
3
|
export function resolveGlmProfileFromArgs(args = []) {
|
|
4
4
|
const list = args.map(String);
|
|
5
5
|
const exactProvider = readOption(list, '--exact-provider', null);
|
|
6
|
+
const slashSelection = parseGlmSlashModelSelection(list);
|
|
6
7
|
const providerBlockers = exactProvider && !isValidOpenRouterProviderSlug(exactProvider)
|
|
7
8
|
? [`invalid_openrouter_provider_slug:${exactProvider}`]
|
|
8
9
|
: [];
|
|
9
|
-
const base = list.includes('--xhigh')
|
|
10
|
+
const base = slashSelection.reasoning_effort === 'xhigh' || list.includes('--xhigh')
|
|
10
11
|
? profileFromConst('xhigh')
|
|
11
12
|
: list.includes('--strict')
|
|
12
13
|
? profileFromConst('strict')
|
|
13
|
-
: list.includes('--deep')
|
|
14
|
+
: slashSelection.reasoning_effort === 'high' || list.includes('--deep')
|
|
14
15
|
? profileFromConst('deep')
|
|
15
16
|
: profileFromConst('speed');
|
|
16
17
|
const provider = exactProvider && !providerBlockers.length
|
|
@@ -29,7 +30,64 @@ export function resolveGlmProfileFromArgs(args = []) {
|
|
|
29
30
|
return {
|
|
30
31
|
...base,
|
|
31
32
|
provider,
|
|
32
|
-
blockers: providerBlockers
|
|
33
|
+
blockers: [...providerBlockers, ...slashSelection.blockers]
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function reasoningEffortFromGlmSlashModelArgs(args = []) {
|
|
37
|
+
return parseGlmSlashModelSelection(args).reasoning_effort;
|
|
38
|
+
}
|
|
39
|
+
export function stripGlmSlashModelArgs(args = []) {
|
|
40
|
+
const consumed = new Set(parseGlmSlashModelSelection(args).consumed_indexes);
|
|
41
|
+
return args.map(String).filter((_arg, index) => !consumed.has(index));
|
|
42
|
+
}
|
|
43
|
+
export function parseGlmSlashModelSelection(args = []) {
|
|
44
|
+
const list = args.map(String);
|
|
45
|
+
const consumed = new Set();
|
|
46
|
+
const values = [];
|
|
47
|
+
for (let i = 0; i < list.length; i += 1) {
|
|
48
|
+
const arg = list[i] || '';
|
|
49
|
+
if (arg === '/model') {
|
|
50
|
+
consumed.add(i);
|
|
51
|
+
for (let j = i + 1; j < list.length && values.length < 2; j += 1) {
|
|
52
|
+
const candidate = list[j] || '';
|
|
53
|
+
if (candidate.startsWith('--') || candidate.startsWith('/'))
|
|
54
|
+
break;
|
|
55
|
+
consumed.add(j);
|
|
56
|
+
values.push(candidate);
|
|
57
|
+
if (values.length === 1 && isSelectableGlmReasoningEffort(candidate.trim().toLowerCase()))
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
const inline = arg.match(/^\/model(?::|=)(.+)$/)?.[1];
|
|
63
|
+
if (inline) {
|
|
64
|
+
consumed.add(i);
|
|
65
|
+
values.push(...inline.split(/[,:]/).map((value) => value.trim()).filter(Boolean).slice(0, 2));
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
let model = null;
|
|
70
|
+
let reasoning = null;
|
|
71
|
+
const blockers = [];
|
|
72
|
+
for (const value of values) {
|
|
73
|
+
const normalized = value.trim().toLowerCase();
|
|
74
|
+
if (isSelectableGlmReasoningEffort(normalized)) {
|
|
75
|
+
reasoning = normalized;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (!model) {
|
|
79
|
+
model = value;
|
|
80
|
+
if (!isAllowedGlmSlashModel(value))
|
|
81
|
+
blockers.push(`glm_slash_model_mismatch:${value}`);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
blockers.push(`glm_slash_model_unrecognized:${value}`);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
model,
|
|
88
|
+
reasoning_effort: reasoning,
|
|
89
|
+
consumed_indexes: [...consumed].sort((a, b) => a - b),
|
|
90
|
+
blockers
|
|
33
91
|
};
|
|
34
92
|
}
|
|
35
93
|
export function profileFromConst(name) {
|
|
@@ -101,4 +159,11 @@ export function profileFromConst(name) {
|
|
|
101
159
|
export function isValidOpenRouterProviderSlug(value) {
|
|
102
160
|
return /^(?!.*(?:^|\/)\.\.?(?:\/|$))[a-z0-9][a-z0-9._-]{0,63}(?:\/[a-z0-9][a-z0-9._-]{0,63}){0,3}$/i.test(value);
|
|
103
161
|
}
|
|
162
|
+
function isSelectableGlmReasoningEffort(value) {
|
|
163
|
+
return value === 'none' || value === 'minimal' || value === 'low' || value === 'medium' || value === 'high' || value === 'xhigh';
|
|
164
|
+
}
|
|
165
|
+
function isAllowedGlmSlashModel(value) {
|
|
166
|
+
const normalized = value.trim().toLowerCase();
|
|
167
|
+
return normalized === GLM_52_OPENROUTER_MODEL || normalized === 'glm-5.2' || normalized === 'glm5.2';
|
|
168
|
+
}
|
|
104
169
|
//# sourceMappingURL=glm-profile-resolver.js.map
|
|
@@ -2,6 +2,7 @@ import { flag, readOption, positionalArgs } from '../../../../cli/args.js';
|
|
|
2
2
|
import { printJson } from '../../../../cli/output.js';
|
|
3
3
|
import { runGlmNarutoMission } from './glm-naruto-orchestrator.js';
|
|
4
4
|
import { runGlmNarutoBench } from './glm-naruto-bench.js';
|
|
5
|
+
import { stripGlmSlashModelArgs } from '../glm-profile-resolver.js';
|
|
5
6
|
export async function glmNarutoCommand(args = []) {
|
|
6
7
|
if (flag(args, '--bench')) {
|
|
7
8
|
// --compare is an alias; the benchmark always compares direct vs Naruto.
|
|
@@ -24,7 +25,7 @@ export async function glmNarutoCommand(args = []) {
|
|
|
24
25
|
}
|
|
25
26
|
return result;
|
|
26
27
|
}
|
|
27
|
-
const positional = positionalArgs(args).map(String);
|
|
28
|
+
const positional = positionalArgs(stripGlmSlashModelArgs(args)).map(String);
|
|
28
29
|
const task = positional.join(' ').trim();
|
|
29
30
|
if (!task && !flag(args, '--repair') && !flag(args, '--status')) {
|
|
30
31
|
const result = {
|
package/dist/core/team-live.js
CHANGED
|
@@ -417,14 +417,14 @@ export function buildTeamRoster(roleCounts = DEFAULT_TEAM_ROLE_COUNTS, opts = {}
|
|
|
417
417
|
const debateReviewers = numberedAgents('debate_reviewer', counts.reviewer, 'Strict debate reviewer: applies validator/researcher lenses to correctness, safety, DB risk, tests, regressions, and unsupported assumptions.', 'reviewer', { prompt });
|
|
418
418
|
const debateExecutorPool = numberedAgents('debate_executor', bundleSize, 'Capable developer voice in debate: applies skeptic/architect lenses to implementation shape, ownership boundaries, dependencies, coupling, and risks before coding starts.', 'executor', { prompt });
|
|
419
419
|
const debateTeam = composeDebateTeam({ users: debateUsers, planners: debatePlanners, reviewers: debateReviewers, executors: debateExecutorPool, bundleSize });
|
|
420
|
-
const nativeAgents = numberedAgents('native_agent', bundleSize, '
|
|
420
|
+
const nativeAgents = numberedAgents('native_agent', bundleSize, 'Bounded native agent: quickly maps one independent slice of repo/docs/tests/API risk, records source paths and evidence, returns TriWiki-ready findings, and edits only parent-assigned lease paths.', 'analysis', { prompt });
|
|
421
421
|
const developmentExecutors = numberedAgents('executor', bundleSize, 'Capable developer executor: owns one disjoint implementation slice and coordinates without reverting others.', 'executor', { prompt });
|
|
422
422
|
const validationReviewers = numberedAgents('reviewer', counts.reviewer, 'Strict reviewer: adversarial about correctness, safety, DB risk, tests, regressions, and unsupported claims.', 'reviewer', { prompt });
|
|
423
423
|
const validationUsers = numberedAgents('user', counts.user, 'Impatient final user acceptance persona: low-context, self-interested, stubborn, dislikes inconvenience, rejects clever work that feels annoying.', 'user', { prompt });
|
|
424
424
|
return {
|
|
425
425
|
role_counts: counts,
|
|
426
426
|
bundle_size: bundleSize,
|
|
427
|
-
analysis_team: nativeAgents.map((agent) => ({ ...agent, write_policy: '
|
|
427
|
+
analysis_team: nativeAgents.map((agent) => ({ ...agent, write_policy: 'bounded workspace-write native analysis lease', output: 'team-analysis.md' })),
|
|
428
428
|
debate_team: debateTeam,
|
|
429
429
|
development_team: developmentExecutors.map((agent) => ({ ...agent, write_policy: 'workspace-write with explicit ownership' })),
|
|
430
430
|
validation_team: [
|
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '4.
|
|
1
|
+
export const PACKAGE_VERSION = '4.7.0';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -16,18 +16,20 @@ fs.writeFileSync(path.join(staleRoot, '.codex', 'agents', 'analysis-scout.toml')
|
|
|
16
16
|
const stalePlan = await mod.repairAgentRoleConfigs({ root: staleRoot, apply: false, codexHome: path.join(staleRoot, 'codex-home') });
|
|
17
17
|
const staleRepair = await mod.repairAgentRoleConfigs({ root: staleRoot, apply: true, codexHome: path.join(staleRoot, 'codex-home') });
|
|
18
18
|
const repairedText = fs.readFileSync(path.join(staleRoot, '.codex', 'agents', 'analysis-scout.toml'), 'utf8');
|
|
19
|
+
const createdText = fs.readFileSync(analysisScout, 'utf8');
|
|
19
20
|
const report = {
|
|
20
21
|
schema: 'sks.agent-role-config-repair-check.v1',
|
|
21
22
|
plan_ok: plan.ok === true && plan.missing.includes('analysis-scout.toml'),
|
|
22
23
|
repair_ok: repair.ok === true,
|
|
23
24
|
analysis_scout_created: fs.existsSync(analysisScout),
|
|
24
|
-
created_matches_model:
|
|
25
|
+
created_matches_model: createdText.includes('model = "gpt-5.5"'),
|
|
26
|
+
created_write_capable: createdText.includes('sandbox_mode = "workspace-write"') && !createdText.includes('Do not edit files.'),
|
|
25
27
|
stale_detected: stalePlan.stale.includes('analysis-scout.toml'),
|
|
26
|
-
stale_repaired: staleRepair.repaired.includes('.codex/agents/analysis-scout.toml') && repairedText.includes('name = "analysis_scout"') && repairedText.includes('model = "gpt-5.5"'),
|
|
28
|
+
stale_repaired: staleRepair.repaired.includes('.codex/agents/analysis-scout.toml') && repairedText.includes('name = "analysis_scout"') && repairedText.includes('model = "gpt-5.5"') && repairedText.includes('sandbox_mode = "workspace-write"'),
|
|
27
29
|
warnings_suppressed: repair.warnings_suppressed === true,
|
|
28
30
|
artifact_written: fs.existsSync(path.join(root, '.sneakoscope', 'reports', 'agent-role-config-repair.json'))
|
|
29
31
|
};
|
|
30
|
-
const ok = report.plan_ok && report.repair_ok && report.analysis_scout_created && report.created_matches_model && report.stale_detected && report.stale_repaired && report.warnings_suppressed && report.artifact_written;
|
|
32
|
+
const ok = report.plan_ok && report.repair_ok && report.analysis_scout_created && report.created_matches_model && report.created_write_capable && report.stale_detected && report.stale_repaired && report.warnings_suppressed && report.artifact_written;
|
|
31
33
|
assertGate(ok, 'doctor --fix must repair missing SKS-owned agent role configs', report);
|
|
32
34
|
emitGate('agent:role-config-repair', report);
|
|
33
35
|
//# sourceMappingURL=agent-role-config-repair-check.js.map
|
|
@@ -2,14 +2,21 @@
|
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
5
6
|
import { ensureCodexNativeReferenceSnapshot } from '../core/codex-native/codex-native-reference-cache.js';
|
|
7
|
+
const currentRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
6
8
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-reference-cache-check-'));
|
|
7
9
|
await fs.mkdir(path.join(root, '.sneakoscope', 'cache', 'codex-native-reference'), { recursive: true });
|
|
8
|
-
|
|
10
|
+
const seedText = 'npx optional tooling no global install. plugin install enable marketplace lifecycle. hook approval trust. skill command picker slash command $Loop. agent_type fallback. AGENTS.md directory-local project memory. plan work proof. continuation resume stop hook. doctor readiness matrix. MCP tool candidate server candidate. non-clobber managed preserve user checksum.\n';
|
|
11
|
+
await fs.writeFile(path.join(root, '.sneakoscope', 'cache', 'codex-native-reference', 'README.md'), seedText, 'utf8');
|
|
9
12
|
const report = await ensureCodexNativeReferenceSnapshot({ root, offline: true });
|
|
10
13
|
assertGate(report.schema === 'sks.codex-native-reference-cache.v1', 'reference cache schema mismatch', report);
|
|
11
14
|
assertGate(report.ok === true && report.offline === true && report.refreshed === false, 'offline cache reuse should pass', report);
|
|
12
15
|
assertGate(report.source_url_hash === null, 'offline cache check should not invent source URL hash', report);
|
|
16
|
+
await fs.mkdir(path.join(currentRoot, '.sneakoscope', 'cache', 'codex-native-reference'), { recursive: true });
|
|
17
|
+
await fs.writeFile(path.join(currentRoot, '.sneakoscope', 'cache', 'codex-native-reference', 'README.md'), seedText, 'utf8');
|
|
18
|
+
const currentReport = await ensureCodexNativeReferenceSnapshot({ root: currentRoot, offline: true });
|
|
19
|
+
assertGate(currentReport.ok === true, 'current reference cache report should be generated', currentReport);
|
|
13
20
|
emitGate('codex-native:reference-cache', { cache_dir: report.cache_dir });
|
|
14
21
|
function assertGate(condition, message, detail = {}) {
|
|
15
22
|
if (condition)
|
|
@@ -22,6 +22,17 @@ const staleConfig = [
|
|
|
22
22
|
'config_file = "/Users/alfredo/.codex/agents/analysis-scout.toml"',
|
|
23
23
|
'nickname_candidates = ["Scout", "Mapper"]',
|
|
24
24
|
'',
|
|
25
|
+
'[agents.analysis_scout]',
|
|
26
|
+
'description = "SKS scout with bounded write capability."',
|
|
27
|
+
'config_file = "./agents/analysis-scout.toml"',
|
|
28
|
+
'nickname_candidates = ["Scout", "Mapper"]',
|
|
29
|
+
'',
|
|
30
|
+
'[mcp_servers.context7]',
|
|
31
|
+
'url = "https://custom.context7.example/mcp"',
|
|
32
|
+
'',
|
|
33
|
+
'[mcp_servers.context7]',
|
|
34
|
+
'url = "https://mcp.context7.com/mcp"',
|
|
35
|
+
'',
|
|
25
36
|
'[mcp_servers.node_repl]',
|
|
26
37
|
'command = "/definitely/missing/node_repl"',
|
|
27
38
|
'args = []',
|
|
@@ -54,22 +65,32 @@ const repaired = await mod.runDoctorCodexStartupRepair({ root: tmp, codexHome, f
|
|
|
54
65
|
const projectText = await fs.readFile(path.join(tmp, '.codex', 'config.toml'), 'utf8');
|
|
55
66
|
const globalText = await fs.readFile(path.join(codexHome, 'config.toml'), 'utf8');
|
|
56
67
|
const checkerText = await fs.readFile(path.join(codexHome, 'agents', 'sks-checker.toml'), 'utf8');
|
|
68
|
+
const projectScoutText = await fs.readFile(path.join(tmp, '.codex', 'agents', 'analysis-scout.toml'), 'utf8');
|
|
69
|
+
const globalScoutText = await fs.readFile(path.join(codexHome, 'agents', 'analysis-scout.toml'), 'utf8');
|
|
57
70
|
for (const [scope, text, expectedDir] of [
|
|
58
71
|
['project', projectText, path.join(tmp, '.codex', 'agents')],
|
|
59
72
|
['global', globalText, path.join(codexHome, 'agents')]
|
|
60
73
|
]) {
|
|
61
74
|
assertGate(!text.includes('/Users/alfredo/'), `${scope} config must drop stale home path`, text);
|
|
62
75
|
assertGate(text.includes(`config_file = "${path.join(expectedDir, 'analysis-scout.toml').replace(/\\/g, '\\\\')}"`), `${scope} config_file must point at an existing absolute role file`, text);
|
|
76
|
+
assertGate(text.includes('description = "SKS scout with bounded write capability."'), `${scope} managed agent description must be write-capable`, text);
|
|
63
77
|
assertGate(!text.includes('[mcp_servers.node_repl]'), `${scope} stale node_repl MCP block must be removed`, text);
|
|
64
78
|
assertGate(!text.includes('[mcp_servers.node_repl.env]'), `${scope} stale node_repl child MCP block must be removed`, text);
|
|
79
|
+
assertGate((text.match(/\[mcp_servers\.context7\]/g) || []).length === 1, `${scope} duplicate context7 MCP block must be deduped`, text);
|
|
80
|
+
assertGate(text.includes('url = "https://custom.context7.example/mcp"'), `${scope} original context7 MCP settings must be preserved`, text);
|
|
65
81
|
assertGate(text.includes('[mcp_servers.supabase_sauron]'), `${scope} optional sauron MCP block must be preserved`, text);
|
|
66
82
|
assertGate(text.includes('[features]') && text.includes('hooks = true'), `${scope} unrelated tables must be preserved`, text);
|
|
67
83
|
}
|
|
84
|
+
for (const [scope, text] of [['project', projectScoutText], ['global', globalScoutText]]) {
|
|
85
|
+
assertGate(text.includes('sandbox_mode = "workspace-write"'), `${scope} agent role file must be workspace-write`, text);
|
|
86
|
+
assertGate(!text.includes('Do not edit files.'), `${scope} agent role file must not preserve stale read-only instruction`, text);
|
|
87
|
+
}
|
|
68
88
|
assertGate(!checkerText.includes('message_role_prefix'), 'managed directive agent role must remove unsupported message_role_prefix', checkerText);
|
|
69
89
|
assertGate(repaired.ok === true, 'startup repair must pass when only optional sauron remains', repaired);
|
|
70
90
|
assertGate(repaired.configs.every((entry) => entry.changed === true && entry.backup_path), 'startup repair must back up changed configs', repaired);
|
|
71
91
|
assertGate(repaired.agent_role_files.created.length >= 10, 'startup repair must create missing project/global role configs', repaired);
|
|
72
92
|
assertGate(repaired.configs.every((entry) => !entry.warnings.some((warning) => warning.includes('agent_config_file_stale'))), 'startup repair must not keep stale agent config warnings after repair', repaired);
|
|
93
|
+
assertGate(repaired.configs.every((entry) => entry.duplicate_toml_blocks_removed.includes('agents.analysis_scout') && entry.duplicate_toml_blocks_removed.includes('mcp_servers.context7')), 'startup repair must record duplicate managed/external table dedupe without rewriting preserved MCP values', repaired);
|
|
73
94
|
const tmpCandidate = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-codex-startup-node-repl-'));
|
|
74
95
|
const codexHomeCandidate = path.join(tmpCandidate, 'codex-home');
|
|
75
96
|
const fakeNodeRepl = path.join(tmpCandidate, 'Codex.app', 'Contents', 'Resources', 'cua_node', 'bin', 'node_repl');
|
|
@@ -34,19 +34,27 @@ assertGate(overCap.agent_count === 100, 'clones above the ceiling clamp to 100',
|
|
|
34
34
|
// A neutral/no-tool prompt yields a low/medium MIX: read-only personas -> low, writers -> medium.
|
|
35
35
|
const effortRoster = roster.buildNarutoCloneRoster({ clones: 24, prompt: 'review and summarize the current findings', maxAgentCount: schema.MAX_NARUTO_AGENT_COUNT });
|
|
36
36
|
const efforts = new Set(effortRoster.roster.map((row) => row.reasoning_effort));
|
|
37
|
+
const modelTiers = new Set(effortRoster.roster.map((row) => row.model_tier));
|
|
38
|
+
const modelEfforts = new Set(effortRoster.roster.map((row) => row.model_reasoning_effort));
|
|
37
39
|
const tiers = new Set(effortRoster.roster.map((row) => row.service_tier));
|
|
38
40
|
const fastFlags = new Set(effortRoster.roster.map((row) => row.fast_mode));
|
|
39
41
|
assertGate([...efforts].every((e) => e === 'low' || e === 'medium'), 'naruto clone efforts must be only low/medium (never high/xhigh)', { efforts: [...efforts] });
|
|
40
42
|
assertGate(efforts.has('low') && efforts.has('medium'), 'naruto effort must be dynamic: a no-tool prompt must yield both low and medium clones', { efforts: [...efforts] });
|
|
43
|
+
assertGate([...modelTiers].every((tier) => tier === 'gpt-5.4-mini' || tier === 'gpt-5.5-low'), 'ordinary naruto clone model tiers must be mini or gpt-5.5-low', { modelTiers: [...modelTiers] });
|
|
44
|
+
assertGate(modelTiers.has('gpt-5.4-mini') && modelTiers.has('gpt-5.5-low'), 'naruto model allocation must dynamically mix gpt-5.4-mini and gpt-5.5-low', { modelTiers: [...modelTiers] });
|
|
45
|
+
assertGate([...modelEfforts].length === 1 && modelEfforts.has('low'), 'ordinary naruto clone model reasoning must stay at low', { modelEfforts: [...modelEfforts] });
|
|
41
46
|
assertGate([...tiers].length === 1 && tiers.has('fast'), 'every naruto clone must be fast service tier', { tiers: [...tiers] });
|
|
42
47
|
assertGate([...fastFlags].length === 1 && fastFlags.has(true), 'every naruto clone must have fast_mode=true', { fastFlags: [...fastFlags] });
|
|
43
48
|
// 4c) Unit rule: no tool use -> low; any tool use -> medium; always fast.
|
|
44
|
-
const simple = effortPolicy.decideNarutoCloneEffort({ readonly: true, prompt: '
|
|
49
|
+
const simple = effortPolicy.decideNarutoCloneEffort({ readonly: true, prompt: 'simple docs overview' });
|
|
45
50
|
const toolWrite = effortPolicy.decideNarutoCloneEffort({ readonly: false, prompt: 'add a feature' });
|
|
46
51
|
const toolReadCmd = effortPolicy.decideNarutoCloneEffort({ readonly: true, prompt: 'run the build and apply the migration' });
|
|
52
|
+
const simpleWrite = effortPolicy.decideNarutoCloneEffort({ readonly: false, prompt: 'simple one-line typo fix' });
|
|
47
53
|
assertGate(simple.reasoning_effort === 'low' && simple.service_tier === 'fast', 'no-tool read-only work must be low + fast', { simple });
|
|
48
|
-
assertGate(
|
|
49
|
-
assertGate(
|
|
54
|
+
assertGate(simple.model === 'gpt-5.4-mini' && simple.model_reasoning_effort === 'low', 'no-tool read-only work must downshift to gpt-5.4-mini', { simple });
|
|
55
|
+
assertGate(toolWrite.reasoning_effort === 'medium' && toolWrite.service_tier === 'fast' && toolWrite.model === 'gpt-5.5' && toolWrite.model_reasoning_effort === 'low', 'writing clone (tool use) must be medium + gpt-5.5 low', { toolWrite });
|
|
56
|
+
assertGate(simpleWrite.model === 'gpt-5.4-mini' && simpleWrite.model_reasoning_effort === 'low', 'simple write work must downshift native workers to gpt-5.4-mini', { simpleWrite });
|
|
57
|
+
assertGate(toolReadCmd.reasoning_effort === 'medium' && toolReadCmd.service_tier === 'fast' && toolReadCmd.model_reasoning_effort === 'high', 'risky read-only command/migration work must escalate model reasoning to high', { toolReadCmd });
|
|
50
58
|
// 5) System-safe concurrency: never spawn the whole count at once; throttle to host capacity.
|
|
51
59
|
const fakeSafe = roster.systemSafeNarutoConcurrency({ backend: 'fake' });
|
|
52
60
|
const heavySafe = roster.systemSafeNarutoConcurrency({ backend: 'codex-sdk' });
|
|
@@ -1089,7 +1089,7 @@ function readJson(rel, fallback) {
|
|
|
1089
1089
|
}
|
|
1090
1090
|
function scriptContains(name, needle) {
|
|
1091
1091
|
if (name === 'release:check:parallel') {
|
|
1092
|
-
return String(pkg.scripts?.[name] || '').includes(needle) || releaseParallelCheckSource.includes(needle);
|
|
1092
|
+
return String(pkg.scripts?.[name] || '').includes(needle) || releaseParallelCheckSource.includes(needle) || releaseGateIds.has(needle);
|
|
1093
1093
|
}
|
|
1094
1094
|
if (name === 'release:check') {
|
|
1095
1095
|
return String(pkg.scripts?.[name] || '').includes(needle) || releaseParallelCheckSource.includes(needle) || releaseGateIds.has(needle);
|
|
@@ -229,6 +229,9 @@ async function referenceEvidence(id) {
|
|
|
229
229
|
const report = await mod.analyzeCodexNativeReferenceSource({ root: tmp, sourceDir, writeReport: true });
|
|
230
230
|
assertGate(report.schema === 'sks.codex-native-reference-evidence.v1' && report.evidence.length >= 4, 'reference evidence report incomplete', report);
|
|
231
231
|
assertGate(!JSON.stringify(report).includes('secret-reference-token'), 'reference evidence should store hashes only', report);
|
|
232
|
+
await ensureCurrentReferenceSeed();
|
|
233
|
+
const currentReport = await mod.analyzeCodexNativeReferenceSource({ root, writeReport: true });
|
|
234
|
+
assertGate(currentReport.schema === 'sks.codex-native-reference-evidence.v1' && currentReport.evidence.length >= 4, 'current reference evidence report incomplete', currentReport);
|
|
232
235
|
}
|
|
233
236
|
finally {
|
|
234
237
|
restoreEnv(previous);
|
|
@@ -241,8 +244,16 @@ async function patternAnalysis(id) {
|
|
|
241
244
|
const mod = await importDist('core/codex-native/codex-native-pattern-analysis.js');
|
|
242
245
|
const report = await mod.writeCodexNativePatternAnalysis(tmp, { sourceDir });
|
|
243
246
|
assertGate(report.schema === 'sks.codex-native-pattern-analysis.v1' && report.patterns.length >= 12, 'pattern analysis incomplete', report);
|
|
247
|
+
await ensureCurrentReferenceSeed();
|
|
248
|
+
const currentReport = await mod.writeCodexNativePatternAnalysis(root);
|
|
249
|
+
assertGate(currentReport.schema === 'sks.codex-native-pattern-analysis.v1' && currentReport.patterns.length >= 12, 'current pattern analysis incomplete', currentReport);
|
|
244
250
|
emitGate(id, { patterns: report.patterns.length });
|
|
245
251
|
}
|
|
252
|
+
async function ensureCurrentReferenceSeed() {
|
|
253
|
+
const cacheDir = path.join(root, '.sneakoscope', 'cache', 'codex-native-reference');
|
|
254
|
+
await fsp.mkdir(cacheDir, { recursive: true });
|
|
255
|
+
await fsp.writeFile(path.join(cacheDir, 'README.md'), 'npx optional tooling no global install. plugin install enable marketplace lifecycle. hook approval trust. skill command picker slash command $Loop. agent_type fallback. AGENTS.md directory-local project memory. plan work proof. continuation resume stop hook. doctor readiness matrix. MCP tool candidate server candidate. non-clobber managed preserve user checksum.\n', 'utf8');
|
|
256
|
+
}
|
|
246
257
|
async function patternAnalysisBlackbox(id) {
|
|
247
258
|
await patternAnalysis(id);
|
|
248
259
|
await brandZeroLeakage('brand-neutrality:zero-leakage');
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.7.0",
|
|
5
5
|
"description": "Sneakoscope Codex: fast proof-first Codex trust layer with image-based Voxel TriWiki.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
|