@kbediako/codex-orchestrator 0.1.15 → 0.1.16

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 CHANGED
@@ -80,6 +80,11 @@ codex -c 'mcp_servers.delegation.enabled=true' ...
80
80
  ```
81
81
  `delegate-server` is the canonical name; `delegation-server` is supported as an alias (older docs may use it).
82
82
 
83
+ Delegation guard profile:
84
+ - `CODEX_ORCHESTRATOR_GUARD_PROFILE=auto` (default): strict in CO-style repos, warn in lightweight repos.
85
+ - Set `CODEX_ORCHESTRATOR_GUARD_PROFILE=warn` for ad-hoc/no-task-id runs.
86
+ - Set `CODEX_ORCHESTRATOR_GUARD_PROFILE=strict` to enforce full delegation evidence checks.
87
+
83
88
  ## Delegation + RLM flow
84
89
 
85
90
  RLM (Recursive Language Model) is the long-horizon loop used by the `rlm` pipeline (`codex-orchestrator rlm "<goal>"` or `codex-orchestrator start rlm --goal "<goal>"`). Delegated runs only enter RLM when the child is launched with the `rlm` pipeline (or the rlm runner directly). In auto mode it resolves to symbolic when delegated, when `RLM_CONTEXT_PATH` is set, or when the context exceeds `RLM_SYMBOLIC_MIN_BYTES`; otherwise it stays iterative. The runner writes state to `.runs/<task-id>/cli/<run-id>/rlm/state.json` and stops when the validator passes or budgets are exhausted.
@@ -40,6 +40,7 @@ const CONFIRMATION_ERROR_CODES = new Set([
40
40
  'nonce_already_consumed'
41
41
  ]);
42
42
  const TOOL_PROFILE_ENTRY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
43
+ const TERMINAL_RUN_STATUSES = new Set(['succeeded', 'failed', 'cancelled', 'canceled']);
43
44
  export async function startDelegationServer(options) {
44
45
  const repoRoot = resolve(options.repoRoot);
45
46
  const configFiles = await loadDelegationConfigFiles({ repoRoot });
@@ -272,7 +273,9 @@ async function handleDelegateStatus(input, allowedRoots, allowedHosts) {
272
273
  const raw = await readFile(manifestPath, 'utf8');
273
274
  const manifest = JSON.parse(raw);
274
275
  const eventsPath = resolve(dirname(manifestPath), 'events.jsonl');
275
- await assertControlEndpoint(manifestPath, allowedHosts);
276
+ if (!TERMINAL_RUN_STATUSES.has(manifest.status)) {
277
+ await assertControlEndpoint(manifestPath, allowedHosts);
278
+ }
276
279
  return {
277
280
  run_id: manifest.run_id,
278
281
  task_id: manifest.task_id,
@@ -153,6 +153,7 @@ export async function runCommandStage(context, hooks = {}) {
153
153
  const baseEnv = {
154
154
  ...process.env,
155
155
  ...(envOverrides ?? {}),
156
+ MCP_RUNNER_TASK_ID: manifest.task_id,
156
157
  CODEX_ORCHESTRATOR_TASK_ID: manifest.task_id,
157
158
  CODEX_ORCHESTRATOR_RUN_ID: manifest.run_id,
158
159
  CODEX_ORCHESTRATOR_PIPELINE_ID: manifest.pipeline_id,
@@ -0,0 +1,80 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import process from 'node:process';
5
+ import { pathToFileURL } from 'node:url';
6
+ import { logger } from '../../logger.js';
7
+ import { resolveEnvironmentPaths } from '../../../../scripts/lib/run-manifests.js';
8
+ const DEFAULT_PROFILE = 'auto';
9
+ const REPO_STRICT_MARKERS = ['AGENTS.md', join('tasks', 'index.json'), join('docs', 'TASKS.md')];
10
+ export function parseGuardProfile(raw) {
11
+ const normalized = String(raw ?? '').trim().toLowerCase();
12
+ if (normalized === 'strict' || normalized === 'warn' || normalized === 'auto') {
13
+ return normalized;
14
+ }
15
+ return DEFAULT_PROFILE;
16
+ }
17
+ export function hasRepoStrictMarkers(repoRoot, fileExists = existsSync) {
18
+ return REPO_STRICT_MARKERS.every((marker) => fileExists(join(repoRoot, marker)));
19
+ }
20
+ export function resolveEffectiveGuardProfile(repoRoot, env = process.env, fileExists = existsSync) {
21
+ const requested = parseGuardProfile(env.CODEX_ORCHESTRATOR_GUARD_PROFILE ?? env.CODEX_GUARD_PROFILE);
22
+ if (requested === 'strict' || requested === 'warn') {
23
+ return requested;
24
+ }
25
+ return hasRepoStrictMarkers(repoRoot, fileExists) ? 'strict' : 'warn';
26
+ }
27
+ export function buildDelegationGuardEnv(env, profile) {
28
+ const taskId = (env.MCP_RUNNER_TASK_ID ?? '').trim();
29
+ const existingOverride = (env.DELEGATION_GUARD_OVERRIDE_REASON ?? '').trim();
30
+ if (profile !== 'warn' || taskId || existingOverride) {
31
+ return { ...env };
32
+ }
33
+ return {
34
+ ...env,
35
+ DELEGATION_GUARD_OVERRIDE_REASON: 'No MCP_RUNNER_TASK_ID provided (warn profile): delegation evidence check bypassed.'
36
+ };
37
+ }
38
+ export async function runDelegationGuardRunner(argv = process.argv.slice(2)) {
39
+ const { repoRoot } = resolveEnvironmentPaths();
40
+ const guardPath = join(repoRoot, 'scripts', 'delegation-guard.mjs');
41
+ const profile = resolveEffectiveGuardProfile(repoRoot);
42
+ if (!existsSync(guardPath)) {
43
+ if (profile === 'strict') {
44
+ logger.error(`[delegation-guard] failed: ${guardPath} not found (strict profile)`);
45
+ process.exit(1);
46
+ return;
47
+ }
48
+ logger.warn(`[delegation-guard] skipped: ${guardPath} not found (warn profile)`);
49
+ process.exit(0);
50
+ return;
51
+ }
52
+ const child = spawn(process.execPath, [guardPath, ...argv], {
53
+ stdio: 'inherit',
54
+ env: buildDelegationGuardEnv(process.env, profile)
55
+ });
56
+ child.on('error', (error) => {
57
+ logger.error(`[delegation-guard] failed: ${error.message}`);
58
+ process.exit(1);
59
+ });
60
+ child.on('exit', (code, signal) => {
61
+ if (typeof code === 'number') {
62
+ process.exit(code);
63
+ return;
64
+ }
65
+ if (signal) {
66
+ logger.error(`[delegation-guard] exited with signal ${signal}`);
67
+ }
68
+ process.exit(1);
69
+ });
70
+ }
71
+ function isDirectExecution() {
72
+ const entry = process.argv[1];
73
+ if (!entry) {
74
+ return false;
75
+ }
76
+ return import.meta.url === pathToFileURL(entry).href;
77
+ }
78
+ if (isDirectExecution()) {
79
+ void runDelegationGuardRunner();
80
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kbediako/codex-orchestrator",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,7 +24,9 @@ Use this skill when a task can be split into parallel streams or when the main c
24
24
  ## Required conventions
25
25
  - Use `MCP_RUNNER_TASK_ID=<task-id>-<stream>` for subagents.
26
26
  - Record manifest paths and summarize findings in the main run.
27
- - Run `node scripts/delegation-guard.mjs` before review handoff to verify delegation evidence.
27
+ - Before review handoff, run the delegation guard stage via the packaged runner:
28
+ `node "$CODEX_ORCHESTRATOR_PACKAGE_ROOT/dist/orchestrator/src/cli/utils/delegationGuardRunner.js"`.
29
+ For ad-hoc runs without task IDs, set `CODEX_ORCHESTRATOR_GUARD_PROFILE=warn`.
28
30
 
29
31
  ## Minimal delegation workflow
30
32
  1) Name streams and write 1–2 sentence goals for each.