sneakoscope 4.6.5 → 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.
Files changed (43) hide show
  1. package/README.md +18 -4
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/bin/sks.js +1 -1
  6. package/dist/cli/install-helpers.js +73 -6
  7. package/dist/commands/codex-app.js +34 -3
  8. package/dist/core/agents/agent-effort-policy.js +110 -5
  9. package/dist/core/agents/agent-orchestrator.js +27 -3
  10. package/dist/core/agents/agent-plan.js +2 -2
  11. package/dist/core/agents/agent-roster.js +8 -0
  12. package/dist/core/agents/agent-worker-slot.js +4 -0
  13. package/dist/core/codex/agent-config-file-repair.js +4 -4
  14. package/dist/core/codex-app/glm-model-profile.js +1 -1
  15. package/dist/core/codex-app/glm-profile-installer.js +111 -7
  16. package/dist/core/codex-app/glm-profile-schema.js +21 -2
  17. package/dist/core/codex-control/codex-sdk-config-policy.js +2 -1
  18. package/dist/core/codex-model-guard.js +3 -1
  19. package/dist/core/commands/fast-mode-command.js +5 -2
  20. package/dist/core/commands/glm-command.js +2 -1
  21. package/dist/core/commands/mad-sks-command.js +24 -0
  22. package/dist/core/doctor/doctor-codex-startup-repair.js +111 -9
  23. package/dist/core/feature-registry.js +3 -3
  24. package/dist/core/fsx.js +1 -1
  25. package/dist/core/harness-guard.js +89 -3
  26. package/dist/core/init.js +9 -9
  27. package/dist/core/managed-assets/managed-assets-manifest.js +9 -8
  28. package/dist/core/pipeline-internals/runtime-core.js +3 -3
  29. package/dist/core/providers/glm/glm-52-profile.js +46 -0
  30. package/dist/core/providers/glm/glm-52-request.js +11 -2
  31. package/dist/core/providers/glm/glm-direct-run.js +1 -0
  32. package/dist/core/providers/glm/glm-mad-launch.js +3 -2
  33. package/dist/core/providers/glm/glm-profile-resolver.js +69 -4
  34. package/dist/core/providers/glm/naruto/glm-naruto-command.js +2 -1
  35. package/dist/core/team-live.js +2 -2
  36. package/dist/core/version.js +1 -1
  37. package/dist/scripts/agent-role-config-repair-check.js +5 -3
  38. package/dist/scripts/codex-native-reference-cache-check.js +8 -1
  39. package/dist/scripts/doctor-codex-startup-repair-check.js +21 -0
  40. package/dist/scripts/naruto-shadow-clone-swarm-check.js +11 -3
  41. package/dist/scripts/release-readiness-report.js +1 -1
  42. package/dist/scripts/sks-3-1-6-directive-check-lib.js +11 -0
  43. 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', 'Read-only SKS analysis agent.', './agents/native-agent-intake.toml', ['Analysis', 'Mapper']) },
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', 'Read-only DB safety reviewer.', './agents/db-safety-reviewer.toml', ['Sentinel', 'Ledger']) },
821
- { table: 'agents.qa_reviewer', text: agentConfigBlock('qa_reviewer', 'Read-only QA reviewer.', './agents/qa-reviewer.toml', ['Verifier', '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 = "Read-only SKS analysis scout retained for stale Codex agent-role config repair."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "medium"\nsandbox_mode = "read-only"\ndeveloper_instructions = """\nYou are an SKS read-only analysis scout.\nDo not edit files.\nInspect only the assigned source paths and return concise source-backed findings.\n"""\n`,
1308
- 'native-agent-intake.toml': `name = "native_agent"\ndescription = "Read-only Team native agent. Maps one independent repo/docs/tests/API/risk/user-friction slice and returns TriWiki-ready source-backed findings before debate starts."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "medium"\nsandbox_mode = "read-only"\ndeveloper_instructions = """\nYou are an SKS Team native agent.\nDo not edit files.\nOwn exactly one investigation slice assigned by the parent orchestrator.\nUse the mission roster or worker inbox reasoning_effort when the host exposes it; simple bounded work can use low, tool-heavy runtime work medium, and knowledge/research/safety/release work high or xhigh. Default to medium only when no assignment is visible.\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 and do not implement code.\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. Maps options, constraints, role-persona risks, and proposes the agreed objective before implementation starts."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "read-only"\ndeveloper_instructions = """\nYou are the SKS Team consensus specialist.\nDo not edit files.\nUse the mission roster reasoning_effort when the host exposes it; planning has a medium minimum, with high or xhigh for knowledge, safety, release, research, or recovery work.\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`,
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 = "Read-only database safety reviewer for SQL, migrations, Supabase, RLS, destructive-operation risk, and rollback safety."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "read-only"\ndeveloper_instructions = """\nYou are a database safety reviewer.\nNever modify files or 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 read-only verification reviewer for correctness, regressions, missing tests, user friction, and final evidence."\nmodel = "gpt-5.5"\nmodel_reasoning_effort = "high"\nsandbox_mode = "read-only"\ndeveloper_instructions = """\nYou are an SKS Team strict reviewer.\nDo not edit files.\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`
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.2.0';
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', 'Read-only SKS analysis scout retained for stale Codex agent-role config repair.', 'read-only', ['analysis-scout', 'analysis_scout', 'native_agent']),
7
- role('sks-planner', 'team-consensus.toml', 'team_consensus', 'Planning and debate specialist for SKS Team mode.', 'read-only', ['team-consensus', 'team_consensus']),
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 read-only verification reviewer for correctness, regressions, and final evidence.', 'read-only', ['qa-reviewer', 'qa_reviewer']),
10
- role('sks-release-verifier', 'sks-release-verifier.toml', 'sks_release_verifier', 'Read-only release verifier for repository, docs, tests, API, and risk slices.', 'read-only', ['native-agent-intake', 'native_agent', 'release-verifier']),
11
- role('sks-zellij-ui-verifier', 'sks-zellij-ui-verifier.toml', 'sks_zellij_ui_verifier', 'Read-only Zellij UI verifier for session, pane, layout, and terminal evidence.', 'read-only', ['native-agent-intake', 'native_agent', 'zellij-ui-verifier']),
12
- role('sks-codex-probe-verifier', 'sks-codex-probe-verifier.toml', 'sks_codex_probe_verifier', 'Read-only Codex probe verifier for CLI, App, SDK, MCP, and native capability evidence.', 'read-only', ['native-agent-intake', 'native_agent', 'codex-probe-verifier']),
13
- role('db-safety-reviewer', 'db-safety-reviewer.toml', 'db_safety_reviewer', 'Read-only database safety reviewer for SQL, migrations, Supabase, and rollback safety.', 'read-only', ['db-safety-reviewer', '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 === true))
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} read-only 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.'}`, agents: roster.analysis_team.map((agent) => agent.id), max_parallel_native_sessions: agentSessions, write_policy: 'read-only' },
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} read-only 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, and record source-backed findings.`, agents: roster.analysis_team.map((agent) => agent.id), max_parallel_native_sessions: agentSessions, write_policy: 'read-only' },
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
- ? buildFastReasoningConfig(input.reasoningMeta)
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 = {
@@ -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, 'Read-only native agent: quickly maps one independent slice of repo/docs/tests/API risk, records source paths and evidence, and returns TriWiki-ready findings.', 'analysis', { prompt });
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: 'read-only native analysis', output: 'team-analysis.md' })),
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: [
@@ -1,2 +1,2 @@
1
- export const PACKAGE_VERSION = '4.6.5';
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: fs.readFileSync(analysisScout, 'utf8').includes('model = "gpt-5.5"'),
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
- await fs.writeFile(path.join(root, '.sneakoscope', 'cache', 'codex-native-reference', 'README.md'), 'npx plugin hook agent_type fallback AGENTS.md doctor MCP managed proof\n', 'utf8');
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: 'explain the architecture overview' });
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(toolWrite.reasoning_effort === 'medium' && toolWrite.service_tier === 'fast', 'writing clone (tool use) must be medium + fast', { toolWrite });
49
- assertGate(toolReadCmd.reasoning_effort === 'medium' && toolReadCmd.service_tier === 'fast', 'read-only work with tool/command signals must be medium + fast', { toolReadCmd });
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.6.5",
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",