sneakoscope 6.1.2 → 6.2.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 (64) hide show
  1. package/README.md +11 -4
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/dist/cli/install-helpers.js +8 -3
  5. package/dist/config/skills-manifest.json +58 -58
  6. package/dist/core/agents/agent-effort-policy.js +28 -17
  7. package/dist/core/agents/agent-schema.js +1 -1
  8. package/dist/core/codex/codex-config-guard.js +178 -7
  9. package/dist/core/codex/codex-config-readability.js +21 -8
  10. package/dist/core/codex/codex-config-toml.js +14 -11
  11. package/dist/core/codex-app/mcp-manager.js +679 -0
  12. package/dist/core/codex-app/sks-menubar.js +405 -6
  13. package/dist/core/codex-control/codex-lb-launch-recovery.js +15 -0
  14. package/dist/core/codex-native/core-skill-manifest.js +1 -1
  15. package/dist/core/commands/mad-sks-command.js +44 -3
  16. package/dist/core/commands/menubar-command.js +94 -0
  17. package/dist/core/commands/naruto-command.js +3 -1
  18. package/dist/core/commands/wiki-command.js +11 -5
  19. package/dist/core/fsx.js +1 -0
  20. package/dist/core/hooks-runtime/code-pack-freshness-preflight.js +14 -8
  21. package/dist/core/hooks-runtime/naruto-decision-gate.js +184 -0
  22. package/dist/core/hooks-runtime/stop-repeat-guard.js +89 -0
  23. package/dist/core/hooks-runtime.js +36 -105
  24. package/dist/core/init/skills.js +4 -4
  25. package/dist/core/init.js +1 -1
  26. package/dist/core/managed-assets/managed-assets-manifest.js +178 -29
  27. package/dist/core/preflight/parallel-preflight-engine.js +16 -3
  28. package/dist/core/proof/route-adapter.js +1 -1
  29. package/dist/core/proof/selftest-proof-fixtures.js +3 -5
  30. package/dist/core/provider/model-router.js +15 -6
  31. package/dist/core/release/package-size-budget.js +4 -6
  32. package/dist/core/research/research-plan-markdown.js +123 -0
  33. package/dist/core/research/research-super-search.js +8 -4
  34. package/dist/core/research.js +4 -119
  35. package/dist/core/retention.js +70 -2
  36. package/dist/core/routes/dollar-manifest-lite.js +1 -1
  37. package/dist/core/routes.js +75 -22
  38. package/dist/core/subagents/agent-catalog.js +87 -15
  39. package/dist/core/subagents/model-policy.js +189 -48
  40. package/dist/core/subagents/naruto-help-contract.js +11 -4
  41. package/dist/core/subagents/official-subagent-preparation.js +55 -9
  42. package/dist/core/subagents/official-subagent-prompt.js +45 -23
  43. package/dist/core/subagents/thread-budget.js +1 -1
  44. package/dist/core/subagents/triwiki-attention.js +117 -14
  45. package/dist/core/triwiki/code-pack-head-freshness.js +291 -0
  46. package/dist/core/version.js +1 -1
  47. package/dist/core/zellij/zellij-launcher.js +12 -2
  48. package/dist/core/zellij/zellij-pane-proof.js +9 -1
  49. package/dist/core/zellij/zellij-update.js +14 -1
  50. package/dist/scripts/canonical-test-runner.js +7 -1
  51. package/dist/scripts/codex-lb-fast-mode-truth-check.js +11 -1
  52. package/dist/scripts/codex-lb-fast-ui-preservation-check.js +9 -2
  53. package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +13 -2
  54. package/dist/scripts/codex-native-agent-role-content-check.js +13 -1
  55. package/dist/scripts/codex-sdk-backend-router-check.js +2 -0
  56. package/dist/scripts/lib/codex-sdk-gate-lib.js +4 -0
  57. package/dist/scripts/official-subagent-workflow-check.js +1 -1
  58. package/dist/scripts/packlist-performance-check.js +1 -18
  59. package/dist/scripts/python-codex-sdk-all-pipelines-check.js +8 -0
  60. package/dist/scripts/sks-menubar-install-check.js +6 -1
  61. package/dist/scripts/super-search-provider-interface-check.js +31 -18
  62. package/package.json +3 -1
  63. package/dist/scripts/codex-0139-feature-probes-check.js +0 -30
  64. package/dist/scripts/codex-0139-marketplace-source-check.js +0 -13
@@ -2,8 +2,12 @@ import path from 'node:path';
2
2
  import { readJson, sha256 } from '../fsx.js';
3
3
  import { runCodexTask } from '../codex-control/codex-task-runner.js';
4
4
  import { runSuperSearch } from '../super-search/index.js';
5
- import { DEFAULT_SUBAGENT_MODEL, SUBAGENT_EFFORT } from '../subagents/model-policy.js';
5
+ import { TERRA_SUBAGENT_EFFORT, TERRA_SUBAGENT_MODEL } from '../subagents/model-policy.js';
6
6
  import {} from './research-source-shards.js';
7
+ export const RESEARCH_SOURCE_ACQUISITION_MODEL_POLICY = Object.freeze({
8
+ model: TERRA_SUBAGENT_MODEL,
9
+ model_reasoning_effort: TERRA_SUBAGENT_EFFORT
10
+ });
7
11
  export async function runResearchSuperSearchShard(input) {
8
12
  const missionId = String(input.plan?.mission_id || '');
9
13
  const acquisitionDir = path.join(input.dir, 'research', `cycle-${input.cycle}`, 'source-acquisition', input.layer.id);
@@ -99,9 +103,9 @@ function createCodexSourceSearch(input) {
99
103
  hardTimeoutMs: input.timeoutMs,
100
104
  ...(input.deadlineMs === undefined ? {} : { deadlineEpochMs: input.deadlineMs })
101
105
  },
102
- model: DEFAULT_SUBAGENT_MODEL,
103
- reasoningEffort: SUBAGENT_EFFORT,
104
- modelReasoningEffort: SUBAGENT_EFFORT,
106
+ model: RESEARCH_SOURCE_ACQUISITION_MODEL_POLICY.model,
107
+ reasoningEffort: RESEARCH_SOURCE_ACQUISITION_MODEL_POLICY.model_reasoning_effort,
108
+ modelReasoningEffort: RESEARCH_SOURCE_ACQUISITION_MODEL_POLICY.model_reasoning_effort,
105
109
  serviceTier: 'fast'
106
110
  });
107
111
  const worker = await readJson(result.workerResultPath, null);
@@ -17,6 +17,7 @@ import { RESEARCH_WORK_GRAPH_ARTIFACT, writeResearchWorkGraph } from './research
17
17
  import { buildResearchReviewArtifactDigest, validateResearchReviewArtifactDigest } from './research/research-review-artifact-digest.js';
18
18
  import { RESEARCH_SOURCE_LAYER_IDS, RESEARCH_SOURCE_LAYERS } from './research/research-source-layer-catalog.js';
19
19
  import { eligibleResearchSourceIdSet } from './research/research-source-evidence.js';
20
+ import { renderResearchPlanMarkdown, renderResearchSourceSkillMarkdown } from './research/research-plan-markdown.js';
20
21
  import { resolveCodexAppExecutionProfile } from './codex-app/codex-app-execution-profile.js';
21
22
  import { resolveCodexNativeInvocationPlan } from './codex-native/codex-native-invocation-router.js';
22
23
  import { SUBAGENT_EVIDENCE_FILENAME, SUBAGENT_PARENT_SUMMARY_FILENAME, buildSubagentEvidence, normalizeSubagentParentSummary, readSubagentEvents } from './subagents/subagent-evidence.js';
@@ -208,7 +209,7 @@ export function createResearchPlan(prompt, opts = {}) {
208
209
  required_model: 'gpt-5.6-sol',
209
210
  required_effort: 'max',
210
211
  applies_to: 'every_official_adversarial_reviewer',
211
- rule: 'Every adversarial reviewer uses the verified research_reviewer custom agent configuration with GPT-5.6 Sol Max. Bounded source extraction may use Luna Max; synthesis, falsification, and review use Sol Max.'
212
+ rule: 'Every adversarial reviewer uses the verified research_reviewer custom agent configuration with GPT-5.6 Sol Max. Long-context and source-tool acquisition uses Terra Medium; synthesis, falsification, and review use Sol Max.'
212
213
  },
213
214
  eureka_policy: {
214
215
  exclamation: 'Eureka!',
@@ -329,126 +330,10 @@ export function createResearchPlan(prompt, opts = {}) {
329
330
  };
330
331
  }
331
332
  export function researchPlanMarkdown(plan) {
332
- const lines = [];
333
- lines.push('# SKS Research Plan');
334
- lines.push('');
335
- lines.push(`Prompt: ${plan.prompt}`);
336
- lines.push(`Depth: ${plan.depth}`);
337
- lines.push(`Methodology: ${plan.methodology}`);
338
- lines.push(`Research paper: ${researchPaperArtifactForPlan(plan)}`);
339
- if (plan.codex_app_execution_profile) {
340
- lines.push(`Execution profile: ${plan.codex_app_execution_profile.mode}; agent role strategy ${plan.codex_app_execution_profile.agent_role_strategy}`);
341
- }
342
- if (plan.execution_policy) {
343
- lines.push(`Execution: ${plan.execution_policy.normal_run}; default cycle timeout ${plan.execution_policy.default_cycle_timeout_minutes} minutes`);
344
- if (plan.execution_policy.default_max_cycles)
345
- lines.push(`Adversarial review loop: run three independent official research_reviewer threads, revise on any objection, then run a fresh three-thread cycle; default safety cap ${plan.execution_policy.default_max_cycles} cycles`);
346
- lines.push(`Mock policy: ${plan.execution_policy.mock_policy}`);
347
- }
348
- if (plan.mutation_policy)
349
- lines.push(`Mutation policy: ${plan.mutation_policy.rule}`);
350
- lines.push('');
351
- if (plan.quality_contract) {
352
- const contract = plan.quality_contract;
353
- lines.push('## Quality Contract');
354
- lines.push(`- minimum sources: ${contract.min_sources_total}`);
355
- lines.push(`- minimum source layers covered: ${contract.min_source_layers_covered}`);
356
- lines.push(`- minimum counterevidence sources: ${contract.min_counterevidence_sources}`);
357
- lines.push(`- minimum key claims: ${contract.min_key_claims}`);
358
- lines.push(`- minimum triangulated claims: ${contract.min_trianguled_claims}`);
359
- lines.push(`- minimum blueprint sections: ${contract.min_implementation_blueprint_sections}`);
360
- lines.push(`- minimum falsification cases: ${contract.min_falsification_cases}`);
361
- lines.push(`- minimum experiment steps: ${contract.min_experiment_steps}`);
362
- lines.push(`- minimum report words: ${contract.min_report_words}`);
363
- lines.push('');
364
- }
365
- if (plan.native_agent_plan) {
366
- lines.push('## Official Subagent Review Plan');
367
- lines.push(`Backend: ${plan.native_agent_plan.backend}`);
368
- lines.push(`Sessions: ${plan.native_agent_plan.session_count}`);
369
- lines.push(`AutoResearch batches: ${plan.native_agent_plan.autoresearch_cycle_policy?.uses_agent_batches ? 'enabled' : 'disabled'}`);
370
- for (const persona of plan.native_agent_plan.personas || []) {
371
- lines.push(`- ${persona.id}: ${persona.role}; outputs ${(persona.outputs || []).join(', ')}`);
372
- }
373
- for (const batch of plan.native_agent_plan.batches || []) {
374
- lines.push(`- batch ${batch.id}: ${(batch.agents || []).join(', ')} -> ${(batch.outputs || []).join(', ')}`);
375
- }
376
- lines.push('');
377
- }
378
- lines.push('## Rules');
379
- for (const rule of plan.rules)
380
- lines.push(`- ${rule}`);
381
- lines.push('');
382
- if (plan.research_council?.agents?.length) {
383
- lines.push('## Genius Agent Council');
384
- lines.push(`Policy: ${plan.research_council.policy}`);
385
- for (const agent of plan.research_council.agents)
386
- lines.push(`- ${researchAgentAgentName(agent)}: ${agent.persona || agent.role} - ${agent.mandate} (${agent.persona_boundary || 'persona-inspired lens only'})`);
387
- lines.push('');
388
- }
389
- if (plan.web_research_policy) {
390
- lines.push('## Web Research Policy');
391
- lines.push(`Mode: ${plan.web_research_policy.mode}`);
392
- lines.push(`Requirement: ${plan.web_research_policy.requirement}`);
393
- if (plan.web_research_policy.source_tool_routing)
394
- lines.push(`Source tool routing: ${plan.web_research_policy.source_tool_routing.mode}`);
395
- for (const querySet of plan.web_research_policy.query_sets || [])
396
- lines.push(`- query set: ${querySet}`);
397
- if (plan.web_research_policy.skill_creator?.artifact)
398
- lines.push(`- source skill artifact: ${plan.web_research_policy.skill_creator.artifact}`);
399
- for (const layer of plan.web_research_policy.source_layers || []) {
400
- lines.push(`- layer ${layer.id}: ${layer.purpose}`);
401
- }
402
- lines.push('');
403
- }
404
- lines.push('## Outcome Rubric');
405
- for (const item of plan.outcome_rubric || [])
406
- lines.push(`- ${item.id}: ${item.description}`);
407
- lines.push('');
408
- lines.push('## Phases');
409
- for (const phase of plan.phases)
410
- lines.push(`- ${phase.id}: ${phase.goal}`);
411
- lines.push('');
412
- lines.push('## Required Artifacts');
413
- for (const artifact of plan.required_artifacts)
414
- lines.push(`- ${artifact}`);
415
- lines.push('');
416
- return `${lines.join('\n')}\n`;
333
+ return renderResearchPlanMarkdown(plan, { researchPaperArtifactForPlan, researchAgentAgentName });
417
334
  }
418
335
  export function researchSourceSkillMarkdown(plan) {
419
- const layers = plan?.web_research_policy?.source_layers?.length ? plan.web_research_policy.source_layers : RESEARCH_SOURCE_LAYERS;
420
- const lines = [];
421
- lines.push('# Research Source Layer Skill');
422
- lines.push('');
423
- lines.push('Status: route-local candidate skill. Use it inside this research mission before agent synthesis. Do not install or edit generated .agents/skills from this artifact.');
424
- lines.push('Real-run policy: collect live sources for as long as needed within the mission timeout; mock or fixture evidence is valid only for explicit --mock selftests.');
425
- lines.push('');
426
- lines.push('## Trigger');
427
- lines.push('- Any `$Research` run that must collect broad public evidence before synthesis, adversarial review, falsification, or paper writing.');
428
- lines.push('');
429
- lines.push('## Source Layers');
430
- for (const layer of layers) {
431
- lines.push(`- ${layer.id}: ${layer.purpose}`);
432
- lines.push(` Examples: ${(layer.examples || []).join(', ')}`);
433
- lines.push(` Query templates: ${(layer.query_templates || []).join(' | ')}`);
434
- }
435
- lines.push('');
436
- lines.push('## Output Contract');
437
- lines.push('- Fill source-ledger.json with `source_layers`, `sources[].layer`, `counterevidence_sources[].layer`, `citation_coverage`, `triangulation.cross_layer_checks`, and `blockers`.');
438
- lines.push('- Each source entry should record title, locator/URL, publisher or author when known, published_at when known, accessed_at, layer, reliability, credibility, stance, supports or undermines, and notes.');
439
- lines.push('- Public discourse sources such as X/Twitter or Reddit are signals and edge cases, not truth. They must be triangulated with formal, official, practitioner, or counterevidence layers.');
440
- lines.push('- If a layer cannot be searched with the available runtime or credentials, record the blocker and keep research-gate.json unpassed.');
441
- lines.push('- Do not modify repository source code or generated harness files during Research; write only route-local mission artifacts.');
442
- lines.push('');
443
- lines.push('## Official Reviewer Use');
444
- lines.push('- Only source-ledger ids with correlated verified-content Super Search proof may support a real-run reviewer finding or Eureka idea.');
445
- lines.push('- Run exactly three independent official `research_reviewer` threads on GPT-5.6 Sol Max: Einstein, von Neumann, and Skeptic composite lenses.');
446
- lines.push('- The skeptic lens must challenge the strongest claim using counterevidence or source-quality downgrades.');
447
- lines.push('- Any objection triggers a mission-local `research_synthesizer` revision followed by a fresh three-thread review cycle; do not launch a custom scheduler or debate pool.');
448
- lines.push('- `agent-ledger.json` and `debate-ledger.json` are compatibility projections from official reviewer outcomes. Canonical convergence requires three trustworthy parent outcomes and zero unresolved objections.');
449
- lines.push('- Synthesis keeps only claims that survive cross-layer triangulation and falsification.');
450
- lines.push('');
451
- return `${lines.join('\n')}\n`;
336
+ return renderResearchSourceSkillMarkdown(plan, RESEARCH_SOURCE_LAYERS);
452
337
  }
453
338
  export function countResearchPaperSections(text = '') {
454
339
  const headings = String(text || '').toLowerCase().split(/\n/).filter((line) => /^#{1,3}\s+/.test(line));
@@ -1,7 +1,7 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import os from 'node:os';
4
- import { exists, readJson, writeJsonAtomic, ensureDir, dirSize, fileSize, formatBytes, rmrf, nowIso, appendJsonlBounded, listFilesRecursive, managedSksTmpRoot, sha256 } from './fsx.js';
4
+ import { exists, readJson, writeJsonAtomic, ensureDir, dirSize, fileSize, formatBytes, rmrf, nowIso, appendJsonlBounded, listFilesRecursive, managedSksTmpRoot, sha256, SKS_TEMP_LEASE_FILE } from './fsx.js';
5
5
  import { FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS } from './routes.js';
6
6
  export const DEFAULT_RETENTION_POLICY = Object.freeze({
7
7
  schema_version: 1,
@@ -487,6 +487,44 @@ function currentProcessOwns(stat) {
487
487
  function sharedTempEntryMatchesProject(entryName, projectHash) {
488
488
  return entryName === `sks-${projectHash}` || entryName.startsWith(`sks-${projectHash}-`);
489
489
  }
490
+ function activeTempEnvironmentKey(target) {
491
+ const resolvedTarget = path.resolve(target);
492
+ for (const key of ['SKS_TMP_DIR', 'TMPDIR', 'TMP', 'TEMP']) {
493
+ const raw = process.env[key];
494
+ if (!raw)
495
+ continue;
496
+ const activePath = path.resolve(raw);
497
+ if (isWithin(resolvedTarget, activePath))
498
+ return key;
499
+ }
500
+ return null;
501
+ }
502
+ async function liveTempLease(target) {
503
+ const leasePath = path.join(target, SKS_TEMP_LEASE_FILE);
504
+ const stat = await fs.lstat(leasePath).catch(() => null);
505
+ if (!stat?.isFile() || stat.isSymbolicLink() || !currentProcessOwns(stat))
506
+ return null;
507
+ const lease = await readJson(leasePath, null).catch(() => null);
508
+ const pid = Number(lease?.pid);
509
+ if (lease?.schema !== 'sks.temp-lease.v1' || !processIdAlive(pid))
510
+ return null;
511
+ return {
512
+ path: leasePath,
513
+ pid,
514
+ kind: lease?.kind ? String(lease.kind) : null
515
+ };
516
+ }
517
+ function processIdAlive(pid) {
518
+ if (!Number.isSafeInteger(pid) || pid <= 0)
519
+ return false;
520
+ try {
521
+ process.kill(pid, 0);
522
+ return true;
523
+ }
524
+ catch (error) {
525
+ return error?.code === 'EPERM';
526
+ }
527
+ }
490
528
  async function pruneTmp(root, policy, dryRun, actions) {
491
529
  const tmp = path.join(root, '.sneakoscope', 'tmp');
492
530
  if (!(await exists(tmp)))
@@ -1138,6 +1176,28 @@ export async function sweepSksTempDirs(root, opts = {}) {
1138
1176
  const stat = await fs.lstat(target).catch(() => null);
1139
1177
  if (!stat || stat.isSymbolicLink() || !currentProcessOwns(stat))
1140
1178
  continue;
1179
+ const environmentKey = activeTempEnvironmentKey(target);
1180
+ if (environmentKey) {
1181
+ actions.push({
1182
+ action: 'retain_active_sks_temp',
1183
+ path: target,
1184
+ reason: 'active_temp_environment',
1185
+ environment_key: environmentKey
1186
+ });
1187
+ continue;
1188
+ }
1189
+ const lease = stat.isDirectory() ? await liveTempLease(target) : null;
1190
+ if (lease) {
1191
+ actions.push({
1192
+ action: 'retain_active_sks_temp',
1193
+ path: target,
1194
+ reason: 'active_temp_lease',
1195
+ lease_path: lease.path,
1196
+ owner_pid: lease.pid,
1197
+ lease_kind: lease.kind
1198
+ });
1199
+ continue;
1200
+ }
1141
1201
  const inspected = await inspectTempPath(target);
1142
1202
  if (!inspected.complete) {
1143
1203
  actions.push({ action: 'skip_unsafe_temp_entry', path: target, reason: inspected.blockers.join(',') });
@@ -1561,7 +1621,15 @@ export async function enforceRetention(root, opts = {}) {
1561
1621
  await rotateLargeJsonl(root, policy, dryRun, actions);
1562
1622
  await pruneDisposableReportLogs(root, policy, dryRun, actions, opts);
1563
1623
  await pruneSessionStateFiles(root, policy, dryRun, actions);
1564
- await sweepSksTempDirs(root, { dryRun, actions, maxAgeHours: opts.sksTempMaxAgeHours ?? policy.max_tmp_age_hours ?? 0 });
1624
+ if (opts.skipSksTempSweep === true) {
1625
+ actions.push({
1626
+ action: 'skip_sks_temp_sweep',
1627
+ reason: opts.afterRoute ? 'post_route_global_temp_isolation' : 'explicit_temp_sweep_skip'
1628
+ });
1629
+ }
1630
+ else {
1631
+ await sweepSksTempDirs(root, { dryRun, actions, maxAgeHours: opts.sksTempMaxAgeHours ?? policy.max_tmp_age_hours ?? 0 });
1632
+ }
1565
1633
  if (opts.pruneWikiArtifacts || policy.prune_wiki_artifacts)
1566
1634
  await pruneWikiArtifacts(root, { policy, dryRun, actions, lowTrust: opts.pruneWikiLowTrust });
1567
1635
  let report = boundedMode || opts.skipStorageReport === true ? await lightweightStorageReport(root) : await storageReport(root);
@@ -1,4 +1,4 @@
1
- const NARUTO_DESCRIPTION = '$Naruto is the lightweight Codex official subagent workflow. The Sol Max parent uses one child by default, two for explicit parallel work or independent risk domains, and at most three for critical multi-domain risk; explicit --agents remains authoritative. It delegates only defensible independent slices, reuses bounded TriWiki attention anchors, and requires official lifecycle events plus a trustworthy structured parent summary.';
1
+ const NARUTO_DESCRIPTION = '$Naruto is the lightweight Codex official subagent workflow. The Sol Max parent uses two independent children for non-trivial work and at most three for critical multi-domain risk; explicit --agents remains authoritative. Child routing is fixed to Luna Max mechanical, Sol High implementation, Sol Max judgment, and Terra Medium long-context/Computer Use/Browser/ImageGen execution. It delegates only defensible independent slices, reuses bounded query-aware TriWiki attention anchors, and requires official lifecycle events plus a trustworthy structured parent summary.';
2
2
  const COMPUTER_USE_DESCRIPTION = 'Maximum-speed Codex Computer Use lane for native macOS, desktop-app, OS-settings, and non-web visual tasks only. Browser, localhost, website, webapp, and web-based app verification must route through Codex Chrome Extension readiness first.';
3
3
  export const DOLLAR_COMMANDS_LITE = [
4
4
  { command: '$DFix', route: 'fast direct fix', description: 'Tiny simple direct edits such as copy, labels, typos, wording, spacing, colors, or clearly scoped one-line changes. Bypasses the general SKS pipeline and runs an ultralight, no-record task-list path.' },
@@ -273,7 +273,7 @@ export const ROUTES = [
273
273
  command: '$Naruto',
274
274
  mode: 'NARUTO',
275
275
  route: 'Codex official subagent workflow',
276
- description: '$Naruto prepares a lightweight Codex official subagent workflow. The Sol Max parent owns decomposition, delegates only defensible direct-child slices, reuses bounded TriWiki attention anchors, waits for every requested thread, integrates the results, and reports scoped verification. Automatic fan-out is one by default, two for explicit parallel work or independent risk domains, and at most three for critical multi-domain risk; explicit --agents remains authoritative.',
276
+ description: '$Naruto prepares a lightweight Codex official subagent workflow. The Sol Max parent owns decomposition, delegates only defensible direct-child slices, reuses bounded query-aware TriWiki attention anchors, waits for every requested thread, integrates the results, and reports scoped verification. Automatic fan-out is two for non-trivial work and at most three for critical multi-domain risk; explicit --agents remains authoritative.',
277
277
  requiredSkills: ['naruto', 'pipeline-runner', 'prompt-pipeline', 'honest-mode'],
278
278
  dollarAliases: ['$ShadowClone', '$Kagebunshin', '$Work', '$Swarm'],
279
279
  appSkillAliases: ['shadow-clone', 'kage-bunshin', 'work', 'swarm'],
@@ -671,7 +671,7 @@ export const COMMAND_CATALOG = [
671
671
  { name: 'memory', usage: 'sks memory build [--json] | sks memory gc [--dry-run]', description: 'Project TriWiki context-pack memory into managed AGENTS.md blocks or run bounded memory cleanup.' },
672
672
  { name: 'hproof', usage: 'sks hproof check [mission-id|latest]', description: 'Evaluate the H-Proof done gate for a mission.' },
673
673
  { name: 'agent', usage: 'sks agent run|status|close|cleanup <mission-id|latest> [--agents N] [--work-items N] [--target-active-slots N] [--mock] [--apply|--dry-run] [--drain] [--stale-ms N] [--json] | sks agent rollback-patches [mission-id|latest] [--patch-entry-id id] [--dry-run|--apply] [--json]', description: 'Run, inspect, close, clean, or roll back Codex subagent missions with an explicit requested-agent/thread budget, disjoint work ownership, official event evidence, and parent-owned integration.' },
674
- { name: 'naruto', usage: 'sks naruto run \"task\" [--agents N] [--max-threads N] [--json] | sks naruto status|subagents|proof [latest|M-...] [--json]', description: 'Run or inspect the Codex official subagent workflow with a Sol Max parent, Luna Max bounded workers, Sol Max experts, max_depth=1, and structured parent-thread completion evidence.' },
674
+ { name: 'naruto', usage: 'sks naruto run \"task\" [--agents N] [--max-threads N] [--json] | sks naruto status|subagents|proof [latest|M-...] [--json]', description: 'Run or inspect the Codex official subagent workflow with a Sol Max parent and fixed Luna Max mechanical, Sol High implementation, Sol Max judgment, and Terra Medium long-context/tool profiles, max_depth=1, and structured parent-thread completion evidence.' },
675
675
  { name: 'team', usage: 'sks team \"task\" | sks team log|tail|watch|lane|status ...', description: 'Deprecated compatibility command: new tasks redirect to Naruto; only read-only observation subcommands remain for old Team missions.' },
676
676
  { name: 'reasoning', usage: 'sks reasoning ["prompt"] [--json]', description: 'Show SKS temporary reasoning-effort routing: medium for simple tasks, high for logic, xhigh for research.' },
677
677
  { name: 'gx', usage: 'sks gx init|render|validate|drift|snapshot [name]', description: 'Create and verify deterministic SVG/HTML visual context cartridges.' },
@@ -1084,27 +1084,80 @@ export function routeNeedsContext7(route, prompt = '') {
1084
1084
  return false;
1085
1085
  return /\b(package|library|framework|SDK|API|MCP|Supabase|React|Next|Vue|Svelte|Vite|Prisma|Drizzle|Knex|Postgres|npm|node_modules|docs?|documentation)\b/i.test(String(prompt || ''));
1086
1086
  }
1087
+ const NARUTO_GATE_BYPASS_ROUTE_IDS = new Set([
1088
+ 'Answer',
1089
+ 'DFix',
1090
+ 'Help',
1091
+ 'Wiki',
1092
+ 'ComputerUse',
1093
+ 'Goal',
1094
+ 'Commit',
1095
+ 'CommitAndPush',
1096
+ 'FastMode',
1097
+ 'LocalModel',
1098
+ 'Planner'
1099
+ ]);
1100
+ const NARUTO_GATE_ROUTE_OWNED_IDS = new Set([
1101
+ 'Research',
1102
+ 'AutoResearch',
1103
+ 'QALoop'
1104
+ ]);
1105
+ const NARUTO_GATE_SPECIALIZED_PARALLEL_ROUTE_IDS = new Set([
1106
+ 'Review',
1107
+ 'ReleaseReview',
1108
+ 'PPT',
1109
+ 'ImageUXReview',
1110
+ 'SuperSearch',
1111
+ 'SEOGEOOptimizer',
1112
+ 'DB',
1113
+ 'MadDB',
1114
+ 'MadSKS',
1115
+ 'GX'
1116
+ ]);
1117
+ export function narutoDecisionForRoute(route, prompt = '', profile = classifyTaskProfile(prompt)) {
1118
+ const routeId = route?.id ? String(route.id) : null;
1119
+ if (!routeId) {
1120
+ return narutoRouteDecision('none', null, profile, 'no_route_or_task_context', true);
1121
+ }
1122
+ if (NARUTO_GATE_ROUTE_OWNED_IDS.has(routeId)) {
1123
+ // These routes already own their orchestration lifecycle. The common
1124
+ // Naruto gate records that fact but must not add a second generic fanout.
1125
+ return narutoRouteDecision('route_owned', routeId, profile, `route_owned_orchestration:${routeId}`, false);
1126
+ }
1127
+ if (NARUTO_GATE_BYPASS_ROUTE_IDS.has(routeId)) {
1128
+ return narutoRouteDecision('none', routeId, profile, `lightweight_route_bypass:${routeId}`, true);
1129
+ }
1130
+ if ((routeId === 'Team' || routeId === 'Naruto') && route.explicit_invocation !== false) {
1131
+ return narutoRouteDecision('generic_naruto', routeId, profile, 'explicit_official_subagent_route', false);
1132
+ }
1133
+ if (/(?:^|\s)--(?:agents|clones)(?:=|\s+)\d+\b/i.test(String(prompt || ''))) {
1134
+ return narutoRouteDecision('generic_naruto', routeId, profile, 'explicit_subagent_count', false);
1135
+ }
1136
+ if (NARUTO_GATE_SPECIALIZED_PARALLEL_ROUTE_IDS.has(routeId)) {
1137
+ return narutoRouteDecision('generic_naruto', routeId, profile, `specialized_route_default_parallel:${routeId}`, false);
1138
+ }
1139
+ if (profile === 'passthrough' || profile === 'answer' || profile === 'tiny-change') {
1140
+ return narutoRouteDecision('none', routeId, profile, `task_profile_${profile}_bypass`, true);
1141
+ }
1142
+ if (profile === 'bounded-work' || profile === 'parallel-read' || profile === 'parallel-write' || profile === 'high-risk') {
1143
+ return narutoRouteDecision('generic_naruto', routeId, profile, `task_profile_${profile}_default_parallel`, false);
1144
+ }
1145
+ return narutoRouteDecision('none', routeId, profile, `task_profile_${profile}_bypass`, true);
1146
+ }
1087
1147
  export function routeRequiresSubagents(route, prompt = '', profile = classifyTaskProfile(prompt)) {
1088
- if (!route)
1089
- return false;
1090
- if (['Answer', 'DFix', 'Help', 'Wiki', 'ComputerUse'].includes(String(route.id || '')))
1091
- return false;
1092
- // QA-Loop retains one route-owned native execution engine. Do not also
1093
- // materialize an official-subagent overlay for the same mission.
1094
- if (route.id === 'QALoop')
1095
- return false;
1096
- if ((route.id === 'Team' || route.id === 'Naruto') && route.explicit_invocation !== false)
1097
- return true;
1098
- if (/(?:^|\s)--(?:agents|clones)(?:=|\s+)\d+\b/i.test(String(prompt || '')))
1099
- return true;
1100
- if (profile === 'passthrough' || profile === 'answer' || profile === 'tiny-change' || profile === 'bounded-work')
1101
- return false;
1102
- if (profile === 'parallel-read' || profile === 'parallel-write')
1103
- return true;
1104
- return profile === 'high-risk' && explicitlyParallelizable(prompt);
1148
+ return narutoDecisionForRoute(route, prompt, profile).mode === 'generic_naruto';
1105
1149
  }
1106
- function explicitlyParallelizable(prompt = '') {
1107
- return /(?:^|\s)--(?:agents|clones)(?:=|\s+)\d+\b|\b(parallel|subagents?|one agent per|fan out|independent slices?|multiple files|audit all)\b|병렬|하위\s*에이전트|서브\s*에이전트|독립\s*(?:작업|범위)|분담|여러\s*파일|전체\s*검토/i.test(String(prompt || ''));
1150
+ function narutoRouteDecision(mode, routeId, profile, reason, trivial) {
1151
+ const required = mode === 'generic_naruto';
1152
+ return {
1153
+ mode,
1154
+ required,
1155
+ route_id: routeId,
1156
+ task_profile: profile,
1157
+ reason,
1158
+ trivial,
1159
+ default_parallel: required
1160
+ };
1108
1161
  }
1109
1162
  export function simpleGitOnlyRouteId(prompt = '') {
1110
1163
  const text = stripVisibleDecisionAnswerBlocks(String(prompt || '')).trim();
@@ -1158,7 +1211,7 @@ export function subagentExecutionPolicyText(route, prompt = '') {
1158
1211
  return [
1159
1212
  'Codex subagent workflow: required for this explicit Naruto or parallel task.',
1160
1213
  'The parent agent owns decomposition, integration, scoped verification, and the final answer.',
1161
- 'Delegate only genuinely independent slices. Use worker for clear bounded work and expert for review, debugging, planning, architecture, integration, or risk-sensitive judgment.',
1214
+ 'Delegate only genuinely independent slices. Use Luna Max only for tiny short-context mechanical work, Sol High for ordinary implementation, Sol Max for review/debug/planning/architecture/integration/risk judgment, and Terra Medium for long-context or Computer Use, Browser/Chrome, and image-generation execution.',
1162
1215
  'Parallel writes require disjoint paths; serialize overlapping paths, prohibit nested delegation, avoid duplicate work, wait for all requested agent threads, and close completed threads after collecting results.',
1163
1216
  'Completion evidence comes from official SubagentStart/SubagentStop events plus the parent integration summary, not process counts or PID evidence.',
1164
1217
  noUnrequestedFallbackCodePolicyText()
@@ -1,15 +1,37 @@
1
- import { MANAGED_OFFICIAL_SUBAGENT_ROLES } from '../managed-assets/managed-assets-manifest.js';
2
- export const DEFAULT_AUTOMATIC_SUBAGENT_COUNT = 1;
1
+ import { MANAGED_OFFICIAL_SUBAGENT_ROLES, managedOfficialSubagentRoleByName } from '../managed-assets/managed-assets-manifest.js';
2
+ export const DEFAULT_AUTOMATIC_SUBAGENT_COUNT = 2;
3
3
  export const MAX_AUTOMATIC_SUBAGENT_COUNT = 3;
4
4
  export const MAX_AUTOMATIC_REVIEWER_COUNT = 2;
5
+ export const MAX_ON_DEMAND_SUBAGENT_ROLE_COUNT = MAX_AUTOMATIC_SUBAGENT_COUNT;
5
6
  export function officialSubagentRoleCatalog() {
6
- return MANAGED_OFFICIAL_SUBAGENT_ROLES.map((role) => ({
7
+ return MANAGED_OFFICIAL_SUBAGENT_ROLES.map(roleSummary);
8
+ }
9
+ export function officialSubagentOnDemandRoleCatalog(roleNames) {
10
+ const selected = [];
11
+ const seen = new Set();
12
+ for (const name of roleNames) {
13
+ const role = managedOfficialSubagentRoleByName(String(name || ''));
14
+ if (!role || seen.has(role.codex_name))
15
+ continue;
16
+ seen.add(role.codex_name);
17
+ selected.push(role);
18
+ if (selected.length >= MAX_ON_DEMAND_SUBAGENT_ROLE_COUNT)
19
+ break;
20
+ }
21
+ return selected.map(roleSummary);
22
+ }
23
+ export function officialSubagentOnDemandRolePlan(roleNames) {
24
+ return Object.fromEntries(officialSubagentOnDemandRoleCatalog(roleNames).map(({ name, ...config }) => [name, config]));
25
+ }
26
+ function roleSummary(role) {
27
+ return {
7
28
  name: role.codex_name,
8
29
  description: role.description,
30
+ model_policy: role.model_policy,
9
31
  model: role.model,
10
32
  model_reasoning_effort: role.model_reasoning_effort,
11
33
  sandbox_mode: role.sandbox || 'inherit'
12
- }));
34
+ };
13
35
  }
14
36
  export function officialSubagentRolePlan() {
15
37
  return Object.fromEntries(officialSubagentRoleCatalog().map(({ name, ...config }) => [name, config]));
@@ -26,11 +48,10 @@ export function recommendOfficialSubagentRoles(input = {}) {
26
48
  const scored = MANAGED_OFFICIAL_SUBAGENT_ROLES
27
49
  .map((role, index) => ({ role, index, score: roleScore(role, text, input) }))
28
50
  .filter((row) => input.readOnly !== true || row.role.sandbox === 'read-only');
29
- const solSpecialistMatched = scored.some((row) => row.score > 0
30
- && row.role.model === 'gpt-5.6-sol'
51
+ const narrowSpecialistMatched = scored.some((row) => row.score > 0
31
52
  && !['worker', 'expert'].includes(row.role.codex_name));
32
53
  const ranked = scored
33
- .filter((row) => !(solSpecialistMatched && row.role.codex_name === 'worker'))
54
+ .filter((row) => !(narrowSpecialistMatched && row.role.codex_name === 'worker'))
34
55
  .filter((row) => row.score > 0)
35
56
  .sort((left, right) => right.score - left.score || left.index - right.index)
36
57
  .map((row) => row.role.codex_name);
@@ -46,7 +67,12 @@ export function selectOfficialSubagentRole(input = {}) {
46
67
  return recommendOfficialSubagentRoles({ ...input, limit: 1 })[0] || 'expert';
47
68
  }
48
69
  export function officialSubagentFanoutPolicy(input = {}) {
49
- const explicit = input.requestedExplicit === true;
70
+ const countSource = input.requestedSource === 'route_contract'
71
+ ? 'route_contract'
72
+ : input.requestedExplicit === true || input.requestedSource === 'operator'
73
+ ? 'operator'
74
+ : 'automatic';
75
+ const explicit = countSource !== 'automatic';
50
76
  const explicitRequested = Number.isFinite(Number(input.requestedSubagents))
51
77
  ? Math.max(1, Math.floor(Number(input.requestedSubagents)))
52
78
  : DEFAULT_AUTOMATIC_SUBAGENT_COUNT;
@@ -60,13 +86,22 @@ export function officialSubagentFanoutPolicy(input = {}) {
60
86
  ? MAX_AUTOMATIC_SUBAGENT_COUNT
61
87
  : MAX_AUTOMATIC_REVIEWER_COUNT;
62
88
  return {
63
- mode: explicit ? 'explicit_operator_count' : 'parent_owned_risk_based',
89
+ mode: countSource === 'operator'
90
+ ? 'explicit_operator_count'
91
+ : countSource === 'route_contract'
92
+ ? 'route_owned_contract_count'
93
+ : 'parent_owned_risk_based',
94
+ count_source: countSource,
64
95
  requested_subagents: requested,
65
96
  default_subagents: DEFAULT_AUTOMATIC_SUBAGENT_COUNT,
66
97
  automatic_selected: explicit ? null : automatic.count,
67
98
  automatic_ceiling: automatic.ceiling,
68
99
  automatic_reviewer_ceiling: automaticReviewerCeiling,
69
- selection_reason: explicit ? 'explicit_operator_count_preserved' : automatic.reason,
100
+ selection_reason: countSource === 'operator'
101
+ ? 'explicit_operator_count_preserved'
102
+ : countSource === 'route_contract'
103
+ ? 'route_owned_contract_count_preserved'
104
+ : automatic.reason,
70
105
  risk_domains: automatic.riskDomains,
71
106
  critical_multi_domain: automatic.criticalMultiDomain,
72
107
  requires_independent_non_overlapping_slices: true,
@@ -113,7 +148,7 @@ function automaticSubagentFanout(input) {
113
148
  return {
114
149
  count: DEFAULT_AUTOMATIC_SUBAGENT_COUNT,
115
150
  ceiling: DEFAULT_AUTOMATIC_SUBAGENT_COUNT,
116
- reason: 'single_bounded_or_single_domain_task',
151
+ reason: 'non_trivial_default_parallel',
117
152
  riskDomains,
118
153
  criticalMultiDomain: false
119
154
  };
@@ -137,6 +172,10 @@ function roleScore(role, text, input) {
137
172
  if (semanticScore <= 0)
138
173
  return 0;
139
174
  let score = semanticScore;
175
+ if (ROLE_PRIORITY_PATTERNS[role.codex_name]?.test(text))
176
+ score += 8;
177
+ if (JUDGMENT_PRIORITY_RE.test(text) && role.model_policy === 'sol_max_judgment')
178
+ score += 10;
140
179
  if (input.readOnly === true)
141
180
  score += role.sandbox === 'read-only' ? 2 : role.sandbox ? -3 : 0;
142
181
  if (input.requiresWrite === true)
@@ -159,7 +198,9 @@ function keywordScore(text, keyword) {
159
198
  return normalized.includes(' ') ? 4 : 3;
160
199
  }
161
200
  function looksClearBounded(text) {
162
- return /\b(bounded|mechanical|repeatable|exact|single[- ](?:file|step|change)|rename|format|copy|fixture)\b|정해진|명확한|기계적|반복적|단일\s*파일/i.test(text);
201
+ const tinyMechanical = /\b(tiny|trivial|mechanical|repeatable|one[- ]line|single[- ]file|exact (?:rename|copy|replace|format)|typo|format only)\b|한\s*줄|단일\s*파일|극단적으로\s*단순|기계적|반복적|오타|이름\s*변경/i.test(text);
202
+ const longOrRisky = /\b(long[- ]context|large[- ](?:file|document|codebase|repository)|repository[- ]wide|browser|chrome|computer[- ]use|imagegen|review|debug|security|architecture|research)\b|긴\s*컨텍스트|장문|대규모|브라우저|컴퓨터\s*유즈|이미지\s*생성|리뷰|디버깅|보안|아키텍처|연구/i.test(text);
203
+ return tinyMechanical && !longOrRisky;
163
204
  }
164
205
  function normalizeText(values) {
165
206
  return values
@@ -186,6 +227,11 @@ const ROLE_LANGUAGE_HINTS = {
186
227
  debugger: ['디버깅', '원인', '실패', '재현', '회귀'],
187
228
  test_engineer: ['테스트', '회귀 테스트', '검증', '픽스처', '커버리지'],
188
229
  ui_implementer: ['화면', '터미널', '젤리', '패널', '팬', '레이아웃', '사용성'],
230
+ native_app_specialist: ['네이티브 앱', '메뉴바', '앱킷', '스위프트', '맥os', '데스크톱', 'tcc'],
231
+ toolchain_specialist: ['툴체인', '의존성', '패키지 매니저', '빌드', '설치', '닥터', '업데이트', 'ci 자동화'],
232
+ protocol_reviewer: ['프로토콜', '계약', '스키마', '직렬화', 'api', 'sdk', 'cli', 'mcp', '하위 호환'],
233
+ runtime_reliability_reviewer: ['런타임 신뢰성', '훅', '세션', '락', '데몬', '프로세스 정리', '멱등성', '복구', '경쟁 상태', '교착'],
234
+ triwiki_evidence_reviewer: ['트라이위키', '컨텍스트 팩', '출처 계보', '신뢰 앵커', '증명 아티팩트', 'wrongness', '소스 하이드레이션'],
189
235
  architecture_reviewer: ['아키텍처', '설계', '수명주기', '결합도', '리팩터'],
190
236
  security_reviewer: ['보안', '권한', '인증', '비밀', '신뢰 경계'],
191
237
  database_reviewer: ['데이터베이스', '디비', '마이그레이션', '롤백', '스키마'],
@@ -194,8 +240,26 @@ const ROLE_LANGUAGE_HINTS = {
194
240
  release_reviewer: ['배포', '릴리스', '출시', '퍼블리시', '버전'],
195
241
  docs_maintainer: ['문서', '리드미', '변경로그', '마이그레이션 가이드'],
196
242
  integration_reviewer: ['통합', '병합', '리베이스', '호환성', '엔드투엔드'],
197
- performance_analyst: ['성능', '지연', '벤치마크', '동시성', '토큰', '메모리']
243
+ performance_analyst: ['성능', '지연', '벤치마크', '동시성', '토큰', '메모리'],
244
+ long_context_analyst: ['롱 컨텍스트', '긴 컨텍스트', '장문', '대규모 파일', '여러 문서', '긴 로그', '컨텍스트 압축'],
245
+ computer_use_operator: ['컴퓨터 유즈', '데스크톱 조작', '맥os 점검', '시스템 설정', '네이티브 앱 점검'],
246
+ browser_use_operator: ['브라우저 유즈', '브라우저', '크롬', '웹사이트', '웹앱', '로컬호스트', '플레이라이트'],
247
+ image_generation_operator: ['이미지 생성', '이미지젠', 'gpt image', 'gpt-image-2', '비주얼 에셋']
248
+ };
249
+ const ROLE_PRIORITY_PATTERNS = {
250
+ debugger: /\b(?:debug|diagnos|root cause|failure|flaky|regression)\b|디버깅|진단|원인|실패|회귀/i,
251
+ architecture_reviewer: /\b(?:architecture|architect|refactor|state ownership|coupling)\b|아키텍처|리팩터|결합도/i,
252
+ security_reviewer: /\b(?:security|permission|secret|auth|trust boundary|abuse)\b|보안|권한|인증|비밀|신뢰\s*경계/i,
253
+ database_reviewer: /\b(?:database|db|sql|migration|rls|rollback)\b|데이터베이스|디비|마이그레이션|롤백/i,
254
+ release_reviewer: /\b(?:release|publish|deploy|distribution|versioning)\b|릴리스|배포|출시|퍼블리시/i,
255
+ research_reviewer: /\b(?:research review|paper review|methodology|falsification|reproducibility)\b|논문\s*검토|방법론|반증|재현성/i,
256
+ browser_use_operator: /\b(?:browser|chrome|playwright|selenium|puppeteer|website|webapp|localhost)\b|브라우저|크롬|웹사이트|웹앱|로컬호스트/i,
257
+ computer_use_operator: /\b(?:computer[- ]use|desktop interaction|system settings|native app inspection)\b|컴퓨터\s*유즈|데스크톱\s*조작|시스템\s*설정/i,
258
+ image_generation_operator: /\b(?:imagegen|image generation|gpt[- ]image(?:-2)?|generate image|edit image)\b|이미지\s*생성|이미지젠/i,
259
+ long_context_analyst: /\b(?:long[- ]context|large[- ](?:file|document|codebase)|multi[- ]document|extensive logs|context compression)\b|긴\s*컨텍스트|장문|대규모|여러\s*문서|긴\s*로그/i,
260
+ triwiki_evidence_reviewer: /\b(?:triwiki|context pack|provenance|trust anchor|wrongness memory|source hydration)\b|트라이위키|컨텍스트\s*팩|출처\s*계보|신뢰\s*앵커/i
198
261
  };
262
+ const JUDGMENT_PRIORITY_RE = /\b(?:review|audit|debug|diagnos|root cause|planning|strategy|architecture|security|database|research|release|risk|judgment|ambiguous)\b|리뷰|검토|감사|디버깅|진단|원인|기획|전략|아키텍처|보안|데이터베이스|연구|릴리스|위험|판단|모호/i;
199
263
  const CRITICAL_RISK_RE = /\b(?:critical|catastrophic|production|data loss|security incident|breaking release)\b|치명|중대|운영|데이터\s*손실|보안\s*사고/i;
200
264
  const RISK_DOMAIN_PATTERNS = [
201
265
  ['database', /\b(?:database|db|sql|postgres|supabase|migration|rls)\b|데이터베이스|디비|마이그레이션/i],
@@ -203,13 +267,21 @@ const RISK_DOMAIN_PATTERNS = [
203
267
  ['release', /\b(?:release|publish|deploy|distribution|package registry|production rollout)\b|릴리스|배포|출시|퍼블리시/i],
204
268
  ['payment', /\b(?:payment|billing|checkout|transaction)\b|결제|청구|트랜잭션/i],
205
269
  ['performance', /\b(?:performance|latency|throughput|concurrency|resource usage)\b|성능|지연|처리량|동시성/i],
206
- ['integration', /\b(?:integration|compatibility|cross-module|end-to-end)\b|통합|호환성|엔드투엔드/i]
270
+ ['integration', /\b(?:integration|compatibility|cross-module|end-to-end)\b|통합|호환성|엔드투엔드/i],
271
+ ['protocol', /\b(?:protocol|mcp|sdk|api contract|schema|serialization|wire format)\b|프로토콜|계약|스키마|직렬화/i],
272
+ ['runtime', /\b(?:hook|session|lock|daemon|process cleanup|idempotency|recovery|race condition|deadlock)\b|훅|세션|락|데몬|프로세스\s*정리|멱등성|복구|경쟁\s*상태|교착/i],
273
+ ['toolchain', /\b(?:toolchain|dependency upgrade|runtime upgrade|package manager|build script|install flow|doctor flow|update flow|ci automation)\b|툴체인|의존성|패키지\s*매니저|빌드|설치|닥터|업데이트/i],
274
+ ['evidence', /\b(?:triwiki|context pack|provenance|trust anchor|proof artifact|wrongness memory)\b|트라이위키|컨텍스트\s*팩|출처|신뢰\s*앵커|증거|증명/i]
207
275
  ];
208
276
  const ROLE_RISK_DOMAINS = {
209
277
  security_reviewer: 'security',
210
278
  database_reviewer: 'database',
211
279
  release_reviewer: 'release',
212
280
  performance_analyst: 'performance',
213
- integration_reviewer: 'integration'
281
+ integration_reviewer: 'integration',
282
+ protocol_reviewer: 'protocol',
283
+ runtime_reliability_reviewer: 'runtime',
284
+ toolchain_specialist: 'toolchain',
285
+ triwiki_evidence_reviewer: 'evidence'
214
286
  };
215
287
  //# sourceMappingURL=agent-catalog.js.map