sneakoscope 6.1.0 → 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.
- package/README.md +35 -11
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/fast-inline.js +18 -9
- package/dist/bin/sks-dispatch.js +2 -2
- package/dist/cli/args.js +2 -0
- package/dist/cli/command-manifest-lite.js +2 -3
- package/dist/cli/command-registry.js +3 -4
- package/dist/cli/help-fast.js +1 -1
- package/dist/cli/install-helpers.js +116 -306
- package/dist/cli/install-tool-helpers.js +287 -0
- package/dist/cli/router.js +40 -4
- package/dist/commands/codex-lb.js +51 -20
- package/dist/commands/codex.js +39 -1
- package/dist/commands/doctor.js +242 -20
- package/dist/commands/tmux.js +5 -1
- package/dist/commands/zellij-monitor-pane.js +2 -0
- package/dist/commands/zellij-viewport-pane.js +3 -1
- package/dist/commands/zellij.js +1 -1
- package/dist/config/skills-manifest.json +59 -59
- package/dist/core/agent-bridge/agent-manifest.js +48 -0
- package/dist/core/agents/agent-command-surface.js +2 -1
- package/dist/core/agents/agent-effort-policy.js +38 -35
- package/dist/core/agents/agent-plan.js +100 -21
- package/dist/core/agents/agent-role-config.js +43 -46
- package/dist/core/agents/agent-runner-codex-exec.js +16 -3
- package/dist/core/agents/agent-schema.js +3 -2
- package/dist/core/agents/native-cli-session-swarm.js +1 -1
- package/dist/core/agents/zellij-right-lane-cockpit.js +2 -2
- package/dist/core/codex/agent-config-file-repair.js +94 -193
- package/dist/core/codex/codex-cli-update.js +723 -0
- package/dist/core/codex/codex-config-guard.js +185 -9
- package/dist/core/codex/codex-config-readability.js +21 -8
- package/dist/core/codex/codex-config-toml.js +14 -11
- package/dist/core/codex/codex-project-config-policy.js +3 -6
- package/dist/core/codex/codex-startup-config-postcheck.js +52 -42
- package/dist/core/codex-adapter.js +35 -22
- package/dist/core/codex-app/codex-agent-role-sync.js +13 -54
- package/dist/core/codex-app/codex-app-launcher.js +48 -17
- package/dist/core/codex-app/codex-app-restart.js +23 -2
- package/dist/core/codex-app/mcp-manager.js +679 -0
- package/dist/core/codex-app/sks-menubar.js +533 -8
- package/dist/core/codex-control/codex-0139-image-path-real-probe.js +15 -4
- package/dist/core/codex-control/codex-0139-web-search-probe.js +17 -6
- package/dist/core/codex-control/codex-lb-launch-recovery.js +293 -0
- package/dist/core/codex-control/codex-reliability-shield.js +89 -29
- package/dist/core/codex-control/codex-sdk-adapter.js +44 -8
- package/dist/core/codex-control/codex-task-runner.js +62 -9
- package/dist/core/codex-control/python-codex-sdk-adapter.js +30 -3
- package/dist/core/codex-exec-output-schema.js +35 -6
- package/dist/core/codex-lb/codex-lb-env.js +1 -1
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +291 -0
- package/dist/core/codex-native/codex-native-feature-broker.js +9 -16
- package/dist/core/codex-native/codex-native-repair-transaction.js +1 -1
- package/dist/core/codex-native/core-skill-manifest.js +8 -4
- package/dist/core/codex-runtime/codex-desktop-config-policy.js +2 -3
- package/dist/core/commands/agent-bridge-command.js +23 -2
- package/dist/core/commands/agent-command.js +19 -5
- package/dist/core/commands/basic-cli.js +47 -6
- package/dist/core/commands/command-utils.js +1 -1
- package/dist/core/commands/mad-sks-command.js +76 -10
- package/dist/core/commands/menubar-command.js +94 -0
- package/dist/core/commands/naruto-command.js +645 -1156
- package/dist/core/commands/research-command.js +293 -231
- package/dist/core/commands/run-command.js +100 -23
- package/dist/core/commands/team-command.js +2 -3
- package/dist/core/commands/team-legacy-observe-command.js +94 -359
- package/dist/core/commands/wiki-command.js +11 -5
- package/dist/core/db-safety.js +2 -2
- package/dist/core/decision-lattice.js +6 -6
- package/dist/core/doctor/codex-startup-config-repair.js +8 -3
- package/dist/core/doctor/doctor-codex-startup-repair.js +6 -141
- package/dist/core/feature-fixture-executor.js +71 -7
- package/dist/core/feature-fixture-runner.js +53 -12
- package/dist/core/feature-fixtures.js +47 -14
- package/dist/core/feature-registry.js +28 -27
- package/dist/core/fsx.js +1 -0
- package/dist/core/harness-conflicts.js +18 -9
- package/dist/core/hooks-runtime/code-pack-freshness-preflight.js +14 -8
- package/dist/core/hooks-runtime/hook-io.js +8 -4
- package/dist/core/hooks-runtime/light-turn.js +70 -0
- package/dist/core/hooks-runtime/naruto-decision-gate.js +184 -0
- package/dist/core/hooks-runtime/payload-signals.js +270 -0
- package/dist/core/hooks-runtime/stop-repeat-guard.js +89 -0
- package/dist/core/hooks-runtime/team-digest.js +0 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +93 -0
- package/dist/core/hooks-runtime.js +438 -354
- package/dist/core/init/skills.js +16 -30
- package/dist/core/init.js +144 -36
- package/dist/core/managed-assets/managed-assets-manifest.js +566 -10
- package/dist/core/mission.js +24 -1
- package/dist/core/pipeline-internals/runtime-core.js +570 -177
- package/dist/core/pipeline-internals/runtime-gates.js +174 -48
- package/dist/core/preflight/parallel-preflight-engine.js +66 -4
- package/dist/core/proof/route-adapter.js +1 -1
- package/dist/core/proof/route-proof-gate.js +7 -2
- package/dist/core/proof/selftest-proof-fixtures.js +3 -5
- package/dist/core/proof-field.js +1 -1
- package/dist/core/provider/model-router.js +42 -31
- package/dist/core/recallpulse/policy.js +12 -28
- package/dist/core/recallpulse.js +11 -6
- package/dist/core/release/npm-pack-proof.js +247 -0
- package/dist/core/release/package-dist-snapshot.js +151 -0
- package/dist/core/release/package-size-budget.js +4 -1
- package/dist/core/release/release-authorization-snapshot.js +115 -0
- package/dist/core/release/release-gate-affected-selector.js +14 -2
- package/dist/core/release/release-gate-cache-v2.js +30 -0
- package/dist/core/release/release-gate-contract.js +161 -0
- package/dist/core/release/release-gate-dag.js +1 -0
- package/dist/core/release/release-real-contract.js +90 -10
- package/dist/core/release-parallel-full-coverage.js +31 -143
- package/dist/core/research/claim-evidence-matrix.js +41 -6
- package/dist/core/research/experiment-plan.js +14 -10
- package/dist/core/research/falsification.js +9 -2
- package/dist/core/research/implementation-blueprint-densifier.js +82 -60
- package/dist/core/research/implementation-blueprint.js +32 -26
- package/dist/core/research/mock-result.js +122 -11
- package/dist/core/research/replication-pack.js +15 -8
- package/dist/core/research/research-adversarial-review.js +1068 -0
- package/dist/core/research/research-claim-builder.js +69 -17
- package/dist/core/research/research-claim-synthesizer.js +343 -0
- package/dist/core/research/research-cycle-runner.js +53 -3
- package/dist/core/research/research-falsification-runner.js +176 -0
- package/dist/core/research/research-final-reviewer.js +44 -125
- package/dist/core/research/research-plan-markdown.js +123 -0
- package/dist/core/research/research-realistic-report.js +14 -6
- package/dist/core/research/research-review-artifact-digest.js +66 -0
- package/dist/core/research/research-source-evidence.js +144 -0
- package/dist/core/research/research-source-layer-catalog.js +68 -0
- package/dist/core/research/research-source-ledger-merge.js +250 -12
- package/dist/core/research/research-source-shards.js +26 -70
- package/dist/core/research/research-stage-runner.js +237 -247
- package/dist/core/research/research-super-search.js +188 -0
- package/dist/core/research/research-synthesis-prompt.js +20 -1
- package/dist/core/research/research-synthesis-writer.js +86 -5
- package/dist/core/research/research-work-graph.js +25 -18
- package/dist/core/research/source-quality-report.js +21 -0
- package/dist/core/research.js +424 -390
- package/dist/core/retention.js +70 -2
- package/dist/core/routes/constants.js +1 -1
- package/dist/core/routes/dollar-manifest-lite.js +11 -11
- package/dist/core/routes.js +149 -69
- package/dist/core/runtime/task-profile.js +66 -0
- package/dist/core/runtime/verification-budget.js +12 -0
- package/dist/core/security/high-risk-contracts.js +6 -6
- package/dist/core/stop-gate/stop-gate-check.js +49 -12
- package/dist/core/subagents/agent-catalog.js +287 -0
- package/dist/core/subagents/model-policy.js +259 -0
- package/dist/core/subagents/naruto-help-contract.js +47 -0
- package/dist/core/subagents/official-subagent-config.js +488 -0
- package/dist/core/subagents/official-subagent-preparation.js +297 -0
- package/dist/core/subagents/official-subagent-prompt.js +159 -0
- package/dist/core/subagents/official-subagent-runner.js +129 -0
- package/dist/core/subagents/subagent-evidence.js +663 -0
- package/dist/core/subagents/terminology.js +16 -0
- package/dist/core/subagents/thread-budget.js +21 -0
- package/dist/core/subagents/triwiki-attention.js +168 -0
- package/dist/core/super-search/runtime-helpers.js +173 -19
- package/dist/core/super-search/runtime.js +140 -15
- package/dist/core/super-search/source-records.js +49 -8
- package/dist/core/team-review-policy.js +15 -0
- package/dist/core/triwiki/code-pack-head-freshness.js +291 -0
- package/dist/core/triwiki/triwiki-module-card.js +1 -1
- package/dist/core/triwiki-wrongness/wrongness-ledger.js +9 -2
- package/dist/core/version-manager.js +51 -1
- package/dist/core/version.js +1 -1
- package/dist/core/work-order-ledger.js +40 -1
- package/dist/core/zellij/zellij-fake-adapter.js +3 -1
- package/dist/core/zellij/zellij-launcher.js +49 -10
- package/dist/core/zellij/zellij-layout-builder.js +14 -5
- package/dist/core/zellij/zellij-official-subagent-activity.js +477 -0
- package/dist/core/zellij/zellij-official-subagent-telemetry.js +264 -0
- package/dist/core/zellij/zellij-pane-proof.js +9 -1
- package/dist/core/zellij/zellij-slot-pane-renderer.js +17 -5
- package/dist/core/zellij/zellij-slot-telemetry.js +15 -3
- package/dist/core/zellij/zellij-ui-mode.js +1 -1
- package/dist/core/zellij/zellij-update.js +14 -1
- package/dist/core/zellij/zellij-viewport-binder.js +3 -0
- package/dist/scripts/agent-role-config-repair-check.js +14 -16
- package/dist/scripts/architecture-guard-check.js +8 -1
- package/dist/scripts/canonical-test-runner.js +7 -1
- package/dist/scripts/check-route-modularity.js +0 -1
- package/dist/scripts/check-ts-contracts.js +1 -1
- package/dist/scripts/codex-control-all-pipelines-check.js +7 -3
- package/dist/scripts/codex-control-tool-output-continuity-audit-check.js +27 -0
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +11 -1
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +9 -2
- package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +13 -2
- package/dist/scripts/codex-native-agent-role-content-check.js +27 -7
- package/dist/scripts/codex-native-repair-transaction-check.js +3 -1
- package/dist/scripts/codex-sdk-all-pipelines-check.js +7 -4
- package/dist/scripts/codex-sdk-backend-router-check.js +2 -0
- package/dist/scripts/codex-sdk-research-pipeline-check.js +30 -8
- package/dist/scripts/db-route-materialization-check.js +33 -0
- package/dist/scripts/docs-truthfulness-check.js +3 -1
- package/dist/scripts/doctor-codex-startup-repair-check.js +12 -15
- package/dist/scripts/doctor-fix-production-blackbox.js +12 -2
- package/dist/scripts/doctor-startup-config-repair-blackbox.js +8 -2
- package/dist/scripts/doctor-startup-config-repair-check.js +12 -2
- package/dist/scripts/install-update-preserves-config-check.js +6 -1
- package/dist/scripts/lib/codex-sdk-gate-lib.js +4 -0
- package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +0 -1
- package/dist/scripts/managed-role-manifest-parity-check.js +5 -4
- package/dist/scripts/naruto-codex-e2e-check.js +14 -7
- package/dist/scripts/naruto-shadow-clone-swarm-check.js +4 -201
- package/dist/scripts/npm-publish-performance-check.js +20 -12
- package/dist/scripts/official-subagent-workflow-check.js +145 -0
- package/dist/scripts/package-published-contract-check.js +6 -29
- package/dist/scripts/packlist-performance-check.js +18 -21
- package/dist/scripts/parallel-verification-engine-check.js +2 -2
- package/dist/scripts/prepublish-release-check-or-fast.js +23 -86
- package/dist/scripts/python-codex-sdk-all-pipelines-check.js +8 -0
- package/dist/scripts/release-affected-selector-check.js +74 -1
- package/dist/scripts/release-check-stamp.js +153 -248
- package/dist/scripts/release-dag-full-coverage-check.js +7 -15
- package/dist/scripts/release-dynamic-presets-check.js +2 -1
- package/dist/scripts/release-gate-dag-runner-check.js +0 -1
- package/dist/scripts/release-gate-dag-runner.js +12 -1
- package/dist/scripts/release-gate-existence-audit.js +1 -2
- package/dist/scripts/release-parallel-full-coverage-check.js +12 -6
- package/dist/scripts/release-parallel-speed-budget-check.js +18 -2
- package/dist/scripts/release-real-check.js +26 -4
- package/dist/scripts/release-registry-check.js +61 -16
- package/dist/scripts/research-blueprint-densifier-check.js +2 -2
- package/dist/scripts/research-real-cycle-no-legacy-final-md-check.js +11 -7
- package/dist/scripts/sizecheck.js +2 -2
- package/dist/scripts/sks-3-1-4-directive-check-lib.js +8 -2
- package/dist/scripts/sks-3-1-5-directive-check-lib.js +3 -2
- package/dist/scripts/sks-3-1-6-directive-check-lib.js +5 -3
- package/dist/scripts/sks-menubar-install-check.js +14 -1
- package/dist/scripts/super-search-provider-interface-check.js +31 -18
- package/dist/scripts/trust-fixture-check.js +32 -10
- package/dist/scripts/wrongness-fixture-check.js +1 -1
- package/dist/scripts/zellij-layout-valid-check.js +5 -5
- package/dist/scripts/zellij-spawn-on-demand-layout-check.js +3 -3
- package/docs/demo.tape +1 -1
- package/infra-harness-gates.json +1486 -0
- package/package.json +15 -10
- package/release-gates.v2.json +4060 -0
- package/runtime-required-scripts.json +9 -0
- package/dist/commands/db.js +0 -6
- package/dist/core/commands/db-command.js +0 -146
- package/dist/core/research/prompt.js +0 -15
- package/dist/scripts/codex-0139-feature-probes-check.js +0 -30
- package/dist/scripts/codex-0139-marketplace-source-check.js +0 -13
- package/dist/scripts/codex-control-tool-call-sequence-repair-check.js +0 -14
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { parse } from 'smol-toml';
|
|
5
|
+
import { ensureDir, exists, PACKAGE_VERSION, readText, sha256, writeTextAtomic } from '../fsx.js';
|
|
6
|
+
import { MANAGED_AGENT_ROLES, MANAGED_OFFICIAL_SUBAGENT_ROLES, managedAgentRoleOwnsText, managedOfficialSubagentRoleContent, managedOfficialSubagentRoleOwnsText } from '../managed-assets/managed-assets-manifest.js';
|
|
7
|
+
export const DEFAULT_OFFICIAL_SUBAGENT_MAX_THREADS = 12;
|
|
8
|
+
export const DEFAULT_OFFICIAL_SUBAGENT_MAX_DEPTH = 1;
|
|
9
|
+
export const DEFAULT_OFFICIAL_SUBAGENT_JOB_MAX_RUNTIME_SECONDS = 1200;
|
|
10
|
+
export const DEFAULT_OFFICIAL_SUBAGENT_INTERRUPT_MESSAGE = true;
|
|
11
|
+
export const LEGACY_SKS_MAX_THREAD_VALUES = Object.freeze([4, 5, 6]);
|
|
12
|
+
/**
|
|
13
|
+
* Merge the project-scoped Codex [agents] defaults without overriding explicit
|
|
14
|
+
* project or inherited global values. Legacy 4/5/6 values migrate only when a
|
|
15
|
+
* caller supplies concrete SKS ownership evidence (for example the generated
|
|
16
|
+
* file inventory from the previous project manifest).
|
|
17
|
+
*/
|
|
18
|
+
export function mergeOfficialSubagentConfig(text = '', opts = {}) {
|
|
19
|
+
const source = String(text || '');
|
|
20
|
+
if (!inspectToml(source).ok)
|
|
21
|
+
return source;
|
|
22
|
+
const inherited = parsedToml(opts.inheritedText || '');
|
|
23
|
+
const inheritedAgents = objectValue(inherited?.agents);
|
|
24
|
+
let next = source.trimEnd();
|
|
25
|
+
if (!next.trim())
|
|
26
|
+
next = '# SKS-MANAGED-CODEX-CONFIG';
|
|
27
|
+
if (opts.sksOwned === true)
|
|
28
|
+
next = removeExactLegacyManagedAgentBlocks(next);
|
|
29
|
+
const targetMaxThreads = positiveInteger(opts.defaultMaxThreads) || DEFAULT_OFFICIAL_SUBAGENT_MAX_THREADS;
|
|
30
|
+
const currentMaxThreads = readTomlTableInteger(next, 'agents', 'max_threads');
|
|
31
|
+
if (!hasTomlTableKey(next, 'agents', 'max_threads')) {
|
|
32
|
+
if (!hasOwn(inheritedAgents, 'max_threads')) {
|
|
33
|
+
next = upsertTomlTableKey(next, 'agents', `max_threads = ${targetMaxThreads}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else if (opts.sksOwned === true && LEGACY_SKS_MAX_THREAD_VALUES.includes(currentMaxThreads || 0)) {
|
|
37
|
+
next = upsertTomlTableKey(next, 'agents', `max_threads = ${targetMaxThreads}`);
|
|
38
|
+
}
|
|
39
|
+
next = upsertDefaultUnlessInherited(next, inheritedAgents, 'max_depth', `max_depth = ${DEFAULT_OFFICIAL_SUBAGENT_MAX_DEPTH}`);
|
|
40
|
+
next = upsertDefaultUnlessInherited(next, inheritedAgents, 'job_max_runtime_seconds', `job_max_runtime_seconds = ${DEFAULT_OFFICIAL_SUBAGENT_JOB_MAX_RUNTIME_SECONDS}`);
|
|
41
|
+
next = upsertDefaultUnlessInherited(next, inheritedAgents, 'interrupt_message', `interrupt_message = ${DEFAULT_OFFICIAL_SUBAGENT_INTERRUPT_MESSAGE}`);
|
|
42
|
+
const merged = ensureTrailingNewline(next);
|
|
43
|
+
return inspectToml(merged).ok ? merged : source;
|
|
44
|
+
}
|
|
45
|
+
export async function readOfficialSubagentConfig(root, opts = {}) {
|
|
46
|
+
const projectConfigPath = path.resolve(opts.projectConfigPath || path.join(root, '.codex', 'config.toml'));
|
|
47
|
+
const home = opts.home || process.env.HOME || os.homedir();
|
|
48
|
+
const codexHome = opts.codexHome || process.env.CODEX_HOME || path.join(home, '.codex');
|
|
49
|
+
const candidateGlobalPath = path.resolve(codexHome, 'config.toml');
|
|
50
|
+
const globalConfigPath = candidateGlobalPath === projectConfigPath ? null : candidateGlobalPath;
|
|
51
|
+
const projectText = await readText(projectConfigPath, '');
|
|
52
|
+
const globalText = globalConfigPath ? await readText(globalConfigPath, '') : '';
|
|
53
|
+
const projectLayer = configLayer(projectText, 'project');
|
|
54
|
+
const globalLayer = configLayer(globalText, 'global');
|
|
55
|
+
const blockers = [...projectLayer.blockers, ...globalLayer.blockers];
|
|
56
|
+
const maxThreads = resolveLayeredValue(projectLayer.agents.max_threads, globalLayer.agents.max_threads, DEFAULT_OFFICIAL_SUBAGENT_MAX_THREADS, positiveInteger);
|
|
57
|
+
const maxDepth = resolveLayeredValue(projectLayer.agents.max_depth, globalLayer.agents.max_depth, DEFAULT_OFFICIAL_SUBAGENT_MAX_DEPTH, positiveInteger);
|
|
58
|
+
const jobMaxRuntimeSeconds = resolveLayeredValue(projectLayer.agents.job_max_runtime_seconds, globalLayer.agents.job_max_runtime_seconds, DEFAULT_OFFICIAL_SUBAGENT_JOB_MAX_RUNTIME_SECONDS, positiveInteger);
|
|
59
|
+
const interruptMessage = resolveLayeredValue(projectLayer.agents.interrupt_message, globalLayer.agents.interrupt_message, DEFAULT_OFFICIAL_SUBAGENT_INTERRUPT_MESSAGE, booleanValue);
|
|
60
|
+
const warnings = maxDepth.value > 1
|
|
61
|
+
? [`official_subagent_max_depth_above_one_preserved:${maxDepth.value}:${maxDepth.source}`]
|
|
62
|
+
: [];
|
|
63
|
+
return {
|
|
64
|
+
maxThreads: maxThreads.value,
|
|
65
|
+
maxDepth: maxDepth.value,
|
|
66
|
+
jobMaxRuntimeSeconds: jobMaxRuntimeSeconds.value,
|
|
67
|
+
interruptMessage: interruptMessage.value,
|
|
68
|
+
sources: {
|
|
69
|
+
maxThreads: maxThreads.source,
|
|
70
|
+
maxDepth: maxDepth.source,
|
|
71
|
+
jobMaxRuntimeSeconds: jobMaxRuntimeSeconds.source,
|
|
72
|
+
interruptMessage: interruptMessage.source
|
|
73
|
+
},
|
|
74
|
+
projectConfigPath,
|
|
75
|
+
globalConfigPath,
|
|
76
|
+
blockers,
|
|
77
|
+
warnings
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function officialSubagentConfigWarnings(text = '', inheritedText = '') {
|
|
81
|
+
const project = configLayer(text, 'project');
|
|
82
|
+
const inherited = configLayer(inheritedText, 'global');
|
|
83
|
+
if (project.blockers.length || inherited.blockers.length)
|
|
84
|
+
return [];
|
|
85
|
+
const maxDepth = resolveLayeredValue(project.agents.max_depth, inherited.agents.max_depth, DEFAULT_OFFICIAL_SUBAGENT_MAX_DEPTH, positiveInteger);
|
|
86
|
+
return maxDepth.value > 1
|
|
87
|
+
? [`official_subagent_max_depth_above_one_preserved:${maxDepth.value}:${maxDepth.source}`]
|
|
88
|
+
: [];
|
|
89
|
+
}
|
|
90
|
+
export async function readInheritedOfficialSubagentConfigText(projectConfigPath, opts = {}) {
|
|
91
|
+
const globalConfigPath = resolveInheritedOfficialSubagentConfigPath(projectConfigPath, opts);
|
|
92
|
+
return globalConfigPath ? readText(globalConfigPath, '') : '';
|
|
93
|
+
}
|
|
94
|
+
export function resolveInheritedOfficialSubagentConfigPath(projectConfigPath, opts = {}) {
|
|
95
|
+
const home = opts.home || process.env.HOME || os.homedir();
|
|
96
|
+
const codexHome = opts.codexHome || process.env.CODEX_HOME || path.join(home, '.codex');
|
|
97
|
+
const globalConfigPath = path.resolve(codexHome, 'config.toml');
|
|
98
|
+
return globalConfigPath === path.resolve(projectConfigPath) ? null : globalConfigPath;
|
|
99
|
+
}
|
|
100
|
+
export async function installOfficialSubagentAgentConfigs(root, opts = {}) {
|
|
101
|
+
const apply = opts.apply !== false;
|
|
102
|
+
const agentsDir = path.join(path.resolve(root), '.codex', 'agents');
|
|
103
|
+
const missing = [];
|
|
104
|
+
const existing = [];
|
|
105
|
+
const stale = [];
|
|
106
|
+
const created = [];
|
|
107
|
+
const updated = [];
|
|
108
|
+
const preserved = [];
|
|
109
|
+
const invalid = [];
|
|
110
|
+
const backups = [];
|
|
111
|
+
const legacyStale = [];
|
|
112
|
+
const removedLegacy = [];
|
|
113
|
+
const preservedLegacy = [];
|
|
114
|
+
const manualBlockers = [];
|
|
115
|
+
const generatedFiles = [];
|
|
116
|
+
if (apply)
|
|
117
|
+
await ensureDir(agentsDir);
|
|
118
|
+
for (const role of MANAGED_AGENT_ROLES) {
|
|
119
|
+
const absolute = path.join(agentsDir, role.filename);
|
|
120
|
+
const relative = `.codex/agents/${role.filename}`;
|
|
121
|
+
if (!(await exists(absolute)))
|
|
122
|
+
continue;
|
|
123
|
+
const current = await readText(absolute, '');
|
|
124
|
+
if (!managedAgentRoleOwnsText(current, role)) {
|
|
125
|
+
preserved.push(relative);
|
|
126
|
+
preservedLegacy.push(relative);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
legacyStale.push(relative);
|
|
130
|
+
if (apply) {
|
|
131
|
+
await fs.rm(absolute, { force: true });
|
|
132
|
+
removedLegacy.push(relative);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
for (const role of MANAGED_OFFICIAL_SUBAGENT_ROLES) {
|
|
136
|
+
const absolute = path.join(agentsDir, role.filename);
|
|
137
|
+
const relative = `.codex/agents/${role.filename}`;
|
|
138
|
+
const expected = managedOfficialSubagentRoleContent(role);
|
|
139
|
+
const present = await exists(absolute);
|
|
140
|
+
if (!present) {
|
|
141
|
+
missing.push(role.filename);
|
|
142
|
+
if (apply) {
|
|
143
|
+
await writeTextAtomic(absolute, expected);
|
|
144
|
+
created.push(relative);
|
|
145
|
+
generatedFiles.push(relative);
|
|
146
|
+
}
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const current = await readText(absolute, '');
|
|
150
|
+
const validation = inspectToml(current);
|
|
151
|
+
if (!validation.ok) {
|
|
152
|
+
invalid.push(relative);
|
|
153
|
+
preserved.push(relative);
|
|
154
|
+
manualBlockers.push(`manual_invalid_official_subagent_toml:${relative}`);
|
|
155
|
+
if (apply) {
|
|
156
|
+
const backup = await backupInvalidToml(absolute, current, 'official-subagent-invalid');
|
|
157
|
+
backups.push(path.relative(root, backup));
|
|
158
|
+
}
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (current === expected) {
|
|
162
|
+
existing.push(relative);
|
|
163
|
+
generatedFiles.push(relative);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (managedOfficialSubagentRoleOwnsText(current, role)) {
|
|
167
|
+
stale.push(relative);
|
|
168
|
+
if (apply) {
|
|
169
|
+
await writeTextAtomic(absolute, expected);
|
|
170
|
+
updated.push(relative);
|
|
171
|
+
generatedFiles.push(relative);
|
|
172
|
+
}
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
preserved.push(relative);
|
|
176
|
+
manualBlockers.push(manualCollisionBlocker(relative, current, role));
|
|
177
|
+
}
|
|
178
|
+
const remainingMissing = apply
|
|
179
|
+
? missing.filter((filename) => !created.includes(`.codex/agents/${filename}`))
|
|
180
|
+
: missing;
|
|
181
|
+
return {
|
|
182
|
+
schema: 'sks.official-subagent-agent-install.v1',
|
|
183
|
+
ok: manualBlockers.length === 0 && (apply ? remainingMissing.length === 0 : true),
|
|
184
|
+
apply,
|
|
185
|
+
installed_agents: MANAGED_OFFICIAL_SUBAGENT_ROLES.map((role) => role.codex_name),
|
|
186
|
+
missing,
|
|
187
|
+
existing,
|
|
188
|
+
stale,
|
|
189
|
+
created,
|
|
190
|
+
updated,
|
|
191
|
+
preserved,
|
|
192
|
+
invalid,
|
|
193
|
+
backups,
|
|
194
|
+
legacy_stale: legacyStale,
|
|
195
|
+
removed_legacy: removedLegacy,
|
|
196
|
+
preserved_legacy: preservedLegacy,
|
|
197
|
+
manual_blockers: manualBlockers,
|
|
198
|
+
generated_files: [...new Set(generatedFiles)].sort()
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
export function manifestProvesSksGeneratedPath(manifest, relativePath) {
|
|
202
|
+
const files = objectValue(objectValue(manifest)?.generated_files)?.files;
|
|
203
|
+
return Array.isArray(files) && files.map((entry) => String(entry || '').replaceAll('\\', '/')).includes(relativePath.replaceAll('\\', '/'));
|
|
204
|
+
}
|
|
205
|
+
export function officialSubagentConfigOwnershipProof(input = {}) {
|
|
206
|
+
const text = String(input.text || '');
|
|
207
|
+
const reasons = [];
|
|
208
|
+
if (manifestProvesSksGeneratedPath(input.manifest, '.codex/config.toml')) {
|
|
209
|
+
reasons.push('generated_file_inventory');
|
|
210
|
+
}
|
|
211
|
+
if (hasExactManagedConfigMarker(text))
|
|
212
|
+
reasons.push('managed_marker_or_hash');
|
|
213
|
+
if (migrationReceiptProvesManagedMaxThreads(input.migrationReceipt)) {
|
|
214
|
+
reasons.push('migration_receipt:agents.max_threads');
|
|
215
|
+
}
|
|
216
|
+
const legacyBlockCount = exactLegacyManagedAgentBlockCount(text);
|
|
217
|
+
if (legacyBlockCount >= 3)
|
|
218
|
+
reasons.push(`exact_legacy_managed_blocks:${legacyBlockCount}`);
|
|
219
|
+
return { owned: reasons.length > 0, reasons: uniqueStrings(reasons) };
|
|
220
|
+
}
|
|
221
|
+
export function inspectOfficialSubagentToml(text = '') {
|
|
222
|
+
return inspectToml(text);
|
|
223
|
+
}
|
|
224
|
+
export async function backupInvalidToml(file, text, tag) {
|
|
225
|
+
const safeTag = String(tag || 'invalid').replace(/[^a-z0-9-]+/gi, '-').replace(/^-+|-+$/g, '') || 'invalid';
|
|
226
|
+
const backupPath = `${file}.sks-${safeTag}-${sha256(String(text || '')).slice(0, 16)}.bak`;
|
|
227
|
+
await writeTextAtomic(backupPath, String(text || ''), { mode: 0o600 });
|
|
228
|
+
return backupPath;
|
|
229
|
+
}
|
|
230
|
+
function manualCollisionBlocker(relative, text, role) {
|
|
231
|
+
const markerPresent = String(text || '').includes(role.ownership_marker);
|
|
232
|
+
return markerPresent
|
|
233
|
+
? `manual_modified_official_subagent_config:${relative}`
|
|
234
|
+
: `manual_user_owned_official_subagent_collision:${relative}`;
|
|
235
|
+
}
|
|
236
|
+
function configLayer(text, label) {
|
|
237
|
+
const validation = inspectToml(text);
|
|
238
|
+
if (!validation.ok) {
|
|
239
|
+
return {
|
|
240
|
+
agents: {},
|
|
241
|
+
blockers: [`${label}_official_subagent_config_toml_parse_failed`]
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
agents: objectValue(parsedToml(text)?.agents),
|
|
246
|
+
blockers: []
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function resolveLayeredValue(projectValue, globalValue, fallback, validate) {
|
|
250
|
+
const project = validate(projectValue);
|
|
251
|
+
if (project !== null)
|
|
252
|
+
return { value: project, source: 'project' };
|
|
253
|
+
const global = validate(globalValue);
|
|
254
|
+
if (global !== null)
|
|
255
|
+
return { value: global, source: 'global' };
|
|
256
|
+
return { value: fallback, source: 'default' };
|
|
257
|
+
}
|
|
258
|
+
function positiveInteger(value) {
|
|
259
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
260
|
+
}
|
|
261
|
+
function booleanValue(value) {
|
|
262
|
+
return typeof value === 'boolean' ? value : null;
|
|
263
|
+
}
|
|
264
|
+
function inspectToml(text) {
|
|
265
|
+
try {
|
|
266
|
+
parse(String(text || ''));
|
|
267
|
+
return { ok: true, error: null };
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function parsedToml(text) {
|
|
274
|
+
try {
|
|
275
|
+
return parse(String(text || ''));
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function objectValue(value) {
|
|
282
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
283
|
+
}
|
|
284
|
+
function hasExactManagedConfigMarker(text) {
|
|
285
|
+
return /^(?:#\s*SKS-MANAGED-CODEX-CONFIG\b|#\s*SKS managed Codex config\b|#\s*sks_managed_(?:body_)?sha256\s*=\s*["'][a-f0-9]{64}["'])/mi.test(text);
|
|
286
|
+
}
|
|
287
|
+
function migrationReceiptProvesManagedMaxThreads(value) {
|
|
288
|
+
const root = objectValue(value);
|
|
289
|
+
if (root.schema !== 'sks.project-migration-receipt.v2')
|
|
290
|
+
return false;
|
|
291
|
+
if (root.status !== 'current' || root.sks_version !== PACKAGE_VERSION)
|
|
292
|
+
return false;
|
|
293
|
+
if (typeof root.installation_epoch_sha256 !== 'string' || !root.installation_epoch_sha256.trim())
|
|
294
|
+
return false;
|
|
295
|
+
if (!Array.isArray(root.blockers) || root.blockers.length > 0)
|
|
296
|
+
return false;
|
|
297
|
+
if (root.required_blockers !== undefined && (!Array.isArray(root.required_blockers) || root.required_blockers.length > 0))
|
|
298
|
+
return false;
|
|
299
|
+
if (root.doctor !== undefined && root.doctor !== null && objectValue(root.doctor).ok !== true)
|
|
300
|
+
return false;
|
|
301
|
+
if (root.retention_cleanup !== undefined && root.retention_cleanup !== null && objectValue(root.retention_cleanup).ok === false)
|
|
302
|
+
return false;
|
|
303
|
+
const stages = [
|
|
304
|
+
...(Array.isArray(root.update_stages) ? root.update_stages : []),
|
|
305
|
+
...(Array.isArray(root.legacy_migration_stages) ? root.legacy_migration_stages : [])
|
|
306
|
+
];
|
|
307
|
+
if (!stages.length || stages.some((stage) => migrationStageFailed(stage)))
|
|
308
|
+
return false;
|
|
309
|
+
return stages.some((stage) => migrationStageSucceeded(stage) && migrationStageProvesManagedMaxThreads(stage));
|
|
310
|
+
}
|
|
311
|
+
function migrationStageSucceeded(value) {
|
|
312
|
+
const stage = objectValue(value);
|
|
313
|
+
if (stage.ok !== true)
|
|
314
|
+
return false;
|
|
315
|
+
const status = String(stage.status || '').trim();
|
|
316
|
+
return Boolean(status) && !/(?:fail|block|error|skip|pending|partial|cancel|timeout|unavailable|unknown)/i.test(status);
|
|
317
|
+
}
|
|
318
|
+
function migrationStageFailed(value) {
|
|
319
|
+
const stage = objectValue(value);
|
|
320
|
+
const status = String(stage.status || '').trim();
|
|
321
|
+
return stage.ok === false || /(?:fail|block|error|cancel|timeout)/i.test(status);
|
|
322
|
+
}
|
|
323
|
+
function migrationStageProvesManagedMaxThreads(value) {
|
|
324
|
+
const queue = [value];
|
|
325
|
+
const seen = new Set();
|
|
326
|
+
while (queue.length) {
|
|
327
|
+
const current = queue.shift();
|
|
328
|
+
if (!current || seen.has(current))
|
|
329
|
+
continue;
|
|
330
|
+
seen.add(current);
|
|
331
|
+
if (Array.isArray(current)) {
|
|
332
|
+
queue.push(...current);
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (typeof current === 'string') {
|
|
336
|
+
if (/\bagents\.max_threads\b/i.test(current) && /\b(?:set|write|wrote|written|upsert|update|updated|migrat(?:e|ed|ion)|manage(?:d)?|apply|applied|repair|repaired)\b/i.test(current))
|
|
337
|
+
return true;
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
if (typeof current !== 'object')
|
|
341
|
+
continue;
|
|
342
|
+
const row = current;
|
|
343
|
+
if (row.ok === false || /(?:fail|block|error|cancel|timeout)/i.test(String(row.status || '')))
|
|
344
|
+
continue;
|
|
345
|
+
for (const key of ['managed_keys', 'written_keys', 'migrated_keys', 'config_keys', 'keys_written']) {
|
|
346
|
+
const entries = row[key];
|
|
347
|
+
if (Array.isArray(entries) && entries.some((entry) => String(entry || '').trim() === 'agents.max_threads'))
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
if (String(row.key || row.config_key || '').trim() === 'agents.max_threads')
|
|
351
|
+
return true;
|
|
352
|
+
for (const key of ['actions', 'detail', 'changes', 'writes', 'result', 'summary']) {
|
|
353
|
+
if (row[key] !== undefined)
|
|
354
|
+
queue.push(row[key]);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
function exactLegacyManagedAgentBlockCount(text) {
|
|
360
|
+
const agents = objectValue(parsedToml(text)?.agents);
|
|
361
|
+
return LEGACY_SKS_AGENT_TABLE_SPECS.filter((spec) => exactLegacyManagedAgentRow(agents[spec.name], spec)).length;
|
|
362
|
+
}
|
|
363
|
+
function removeExactLegacyManagedAgentBlocks(text) {
|
|
364
|
+
const agents = objectValue(parsedToml(text)?.agents);
|
|
365
|
+
let next = String(text || '');
|
|
366
|
+
for (const spec of LEGACY_SKS_AGENT_TABLE_SPECS) {
|
|
367
|
+
if (!exactLegacyManagedAgentRow(agents[spec.name], spec))
|
|
368
|
+
continue;
|
|
369
|
+
next = removeTomlTable(next, `agents.${spec.name}`);
|
|
370
|
+
}
|
|
371
|
+
return next;
|
|
372
|
+
}
|
|
373
|
+
function exactLegacyManagedAgentRow(value, spec) {
|
|
374
|
+
const row = objectValue(value);
|
|
375
|
+
const keys = Object.keys(row).sort();
|
|
376
|
+
const configFile = String(row.config_file || '');
|
|
377
|
+
const configFilename = configFile.replaceAll('\\', '/').split('/').pop() || '';
|
|
378
|
+
return JSON.stringify(keys) === JSON.stringify(['config_file', 'description', 'nickname_candidates'])
|
|
379
|
+
&& row.description === spec.description
|
|
380
|
+
&& configFilename === spec.filename
|
|
381
|
+
&& Array.isArray(row.nickname_candidates)
|
|
382
|
+
&& JSON.stringify(row.nickname_candidates) === JSON.stringify(spec.nicknames);
|
|
383
|
+
}
|
|
384
|
+
function removeTomlTable(text, table) {
|
|
385
|
+
const lines = String(text || '').split('\n');
|
|
386
|
+
const header = new RegExp(`^\\s*\\[${escapeRegExp(table)}\\]\\s*(?:#.*)?$`);
|
|
387
|
+
const start = lines.findIndex((line) => header.test(line));
|
|
388
|
+
if (start === -1)
|
|
389
|
+
return text;
|
|
390
|
+
let end = lines.length;
|
|
391
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
392
|
+
if (/^\s*\[.+\]\s*(?:#.*)?$/.test(lines[index] || '')) {
|
|
393
|
+
end = index;
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
lines.splice(start, end - start);
|
|
398
|
+
return lines.join('\n').replace(/\n{3,}/g, '\n\n').trimEnd();
|
|
399
|
+
}
|
|
400
|
+
function hasOwn(value, key) {
|
|
401
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
402
|
+
}
|
|
403
|
+
function upsertDefaultUnlessInherited(text, inheritedAgents, key, line) {
|
|
404
|
+
if (hasTomlTableKey(text, 'agents', key) || hasOwn(inheritedAgents, key))
|
|
405
|
+
return text;
|
|
406
|
+
return upsertTomlTableKey(text, 'agents', line);
|
|
407
|
+
}
|
|
408
|
+
function readTomlTableInteger(text, table, key) {
|
|
409
|
+
const line = tomlTableKeyLine(text, table, key);
|
|
410
|
+
const match = line?.match(/^\s*[^=]+\s*=\s*([0-9]+)\s*(?:#.*)?$/);
|
|
411
|
+
if (!match?.[1])
|
|
412
|
+
return null;
|
|
413
|
+
const value = Number(match[1]);
|
|
414
|
+
return Number.isSafeInteger(value) ? value : null;
|
|
415
|
+
}
|
|
416
|
+
function hasTomlTableKey(text, table, key) {
|
|
417
|
+
return tomlTableKeyLine(text, table, key) !== null;
|
|
418
|
+
}
|
|
419
|
+
function tomlTableKeyLine(text, table, key) {
|
|
420
|
+
const lines = String(text || '').split('\n');
|
|
421
|
+
const start = lines.findIndex((line) => isTomlTableHeader(line, table));
|
|
422
|
+
if (start === -1)
|
|
423
|
+
return null;
|
|
424
|
+
const pattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`);
|
|
425
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
426
|
+
const line = lines[index] || '';
|
|
427
|
+
if (/^\s*\[.+\]\s*(?:#.*)?$/.test(line))
|
|
428
|
+
break;
|
|
429
|
+
if (pattern.test(line))
|
|
430
|
+
return line;
|
|
431
|
+
}
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
function upsertTomlTableKey(text, table, line) {
|
|
435
|
+
const key = String(line).split('=')[0]?.trim() || '';
|
|
436
|
+
let lines = String(text || '').trimEnd().split('\n');
|
|
437
|
+
if (lines.length === 1 && lines[0] === '')
|
|
438
|
+
lines = [];
|
|
439
|
+
const header = `[${table}]`;
|
|
440
|
+
const start = lines.findIndex((entry) => isTomlTableHeader(entry, table));
|
|
441
|
+
if (start === -1) {
|
|
442
|
+
const firstChild = lines.findIndex((entry) => entry.trim().startsWith(`[${table}.`));
|
|
443
|
+
const block = [header, line, ''];
|
|
444
|
+
if (firstChild >= 0) {
|
|
445
|
+
lines.splice(firstChild, 0, ...block);
|
|
446
|
+
return lines.join('\n').replace(/\n{3,}/g, '\n\n').trimEnd();
|
|
447
|
+
}
|
|
448
|
+
return [...lines, ...(lines.length ? [''] : []), header, line].join('\n').replace(/\n{3,}/g, '\n\n');
|
|
449
|
+
}
|
|
450
|
+
let end = lines.length;
|
|
451
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
452
|
+
if (/^\s*\[.+\]\s*(?:#.*)?$/.test(lines[index] || '')) {
|
|
453
|
+
end = index;
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
const pattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`);
|
|
458
|
+
for (let index = start + 1; index < end; index += 1) {
|
|
459
|
+
if (pattern.test(lines[index] || '')) {
|
|
460
|
+
lines[index] = line;
|
|
461
|
+
return lines.join('\n').replace(/\n{3,}/g, '\n\n');
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
lines.splice(end, 0, line);
|
|
465
|
+
return lines.join('\n').replace(/\n{3,}/g, '\n\n');
|
|
466
|
+
}
|
|
467
|
+
function ensureTrailingNewline(text) {
|
|
468
|
+
const value = String(text || '').trimEnd();
|
|
469
|
+
return value ? `${value}\n` : '';
|
|
470
|
+
}
|
|
471
|
+
function isTomlTableHeader(line, table) {
|
|
472
|
+
return new RegExp(`^\\s*\\[${escapeRegExp(table)}\\]\\s*(?:#.*)?$`).test(String(line || ''));
|
|
473
|
+
}
|
|
474
|
+
function uniqueStrings(values) {
|
|
475
|
+
return [...new Set(values)];
|
|
476
|
+
}
|
|
477
|
+
function escapeRegExp(value) {
|
|
478
|
+
return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
479
|
+
}
|
|
480
|
+
const LEGACY_SKS_AGENT_TABLE_SPECS = [
|
|
481
|
+
{ name: 'analysis_scout', filename: 'analysis-scout.toml', description: 'SKS scout with bounded write capability.', nicknames: ['Scout', 'Mapper'] },
|
|
482
|
+
{ name: 'native_agent', filename: 'native-agent-intake.toml', description: 'SKS native agent with bounded write capability.', nicknames: ['Analysis', 'Mapper'] },
|
|
483
|
+
{ name: 'team_consensus', filename: 'team-consensus.toml', description: 'SKS planning/debate agent with bounded write capability.', nicknames: ['Consensus', 'Atlas'] },
|
|
484
|
+
{ name: 'implementation_worker', filename: 'implementation-worker.toml', description: 'SKS bounded implementation worker.', nicknames: ['Builder', 'Mason'] },
|
|
485
|
+
{ name: 'db_safety_reviewer', filename: 'db-safety-reviewer.toml', description: 'DB safety reviewer with bounded write capability.', nicknames: ['Sentinel', 'Ledger'] },
|
|
486
|
+
{ name: 'qa_reviewer', filename: 'qa-reviewer.toml', description: 'QA reviewer with bounded write capability.', nicknames: ['Verifier', 'Reviewer'] }
|
|
487
|
+
];
|
|
488
|
+
//# sourceMappingURL=official-subagent-config.js.map
|