@kbediako/codex-orchestrator 0.1.33 → 0.1.34

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.
@@ -15,6 +15,7 @@ import { buildSelfCheckResult } from '../orchestrator/src/cli/selfCheck.js';
15
15
  import { initCodexTemplates, formatInitSummary } from '../orchestrator/src/cli/init.js';
16
16
  import { runDoctor, runDoctorCloudPreflight, formatDoctorSummary, formatDoctorCloudPreflightSummary } from '../orchestrator/src/cli/doctor.js';
17
17
  import { formatDoctorUsageSummary, runDoctorUsage } from '../orchestrator/src/cli/doctorUsage.js';
18
+ import { formatDoctorIssueLogSummary, writeDoctorIssueLog } from '../orchestrator/src/cli/doctorIssueLog.js';
18
19
  import { formatDevtoolsSetupSummary, runDevtoolsSetup } from '../orchestrator/src/cli/devtoolsSetup.js';
19
20
  import { formatCodexCliSetupSummary, runCodexCliSetup } from '../orchestrator/src/cli/codexCliSetup.js';
20
21
  import { formatDelegationSetupSummary, runDelegationSetup } from '../orchestrator/src/cli/delegationSetup.js';
@@ -25,6 +26,9 @@ import { serveMcp } from '../orchestrator/src/cli/mcp.js';
25
26
  import { formatMcpEnableSummary, runMcpEnable } from '../orchestrator/src/cli/mcpEnable.js';
26
27
  import { startDelegationServer } from '../orchestrator/src/cli/delegationServer.js';
27
28
  import { splitDelegationConfigOverrides } from '../orchestrator/src/cli/config/delegationConfig.js';
29
+ import { buildCommandPreview } from '../orchestrator/src/cli/utils/commandPreview.js';
30
+ import { REPO_CONFIG_REQUIRED_ENV_KEY } from '../orchestrator/src/cli/config/repoConfigPolicy.js';
31
+ const AUTO_ISSUE_LOG_ENV_KEY = 'CODEX_ORCHESTRATOR_AUTO_ISSUE_LOG';
28
32
  async function main() {
29
33
  const args = process.argv.slice(2);
30
34
  const command = args.shift();
@@ -117,6 +121,7 @@ function parseArgs(raw) {
117
121
  const queue = [...raw];
118
122
  const booleanFlagKeys = new Set([
119
123
  'apply',
124
+ 'auto-issue-log',
120
125
  'cloud',
121
126
  'cloud-preflight',
122
127
  'codex-cli',
@@ -127,8 +132,10 @@ function parseArgs(raw) {
127
132
  'force',
128
133
  'help',
129
134
  'interactive',
135
+ 'issue-log',
130
136
  'multi-agent',
131
137
  'no-interactive',
138
+ 'repo-config-required',
132
139
  'refresh-skills',
133
140
  'ui',
134
141
  'usage',
@@ -327,6 +334,41 @@ function readStringFlag(flags, key) {
327
334
  const trimmed = value.trim();
328
335
  return trimmed.length > 0 ? trimmed : undefined;
329
336
  }
337
+ function parseBooleanSetting(raw, label) {
338
+ if (typeof raw === 'boolean') {
339
+ return raw;
340
+ }
341
+ const normalized = raw.trim().toLowerCase();
342
+ if (['1', 'true', 'yes', 'on'].includes(normalized)) {
343
+ return true;
344
+ }
345
+ if (['0', 'false', 'no', 'off'].includes(normalized)) {
346
+ return false;
347
+ }
348
+ throw new Error(`Invalid ${label} value "${raw}". Expected true|false.`);
349
+ }
350
+ function resolveBooleanOption(flags, key, envKey) {
351
+ const fromFlag = flags[key];
352
+ if (fromFlag !== undefined) {
353
+ return parseBooleanSetting(fromFlag, `--${key}`);
354
+ }
355
+ if (!envKey) {
356
+ return false;
357
+ }
358
+ const fromEnv = process.env[envKey];
359
+ if (typeof fromEnv !== 'string' || fromEnv.trim().length === 0) {
360
+ return false;
361
+ }
362
+ return parseBooleanSetting(fromEnv, envKey);
363
+ }
364
+ function applyRepoConfigRequiredPolicy(flags) {
365
+ const required = resolveBooleanOption(flags, 'repo-config-required', REPO_CONFIG_REQUIRED_ENV_KEY);
366
+ process.env[REPO_CONFIG_REQUIRED_ENV_KEY] = required ? '1' : '0';
367
+ return required;
368
+ }
369
+ function resolveAutoIssueLogEnabled(flags) {
370
+ return resolveBooleanOption(flags, 'auto-issue-log', AUTO_ISSUE_LOG_ENV_KEY);
371
+ }
330
372
  function resolveExecutionModeFlag(flags) {
331
373
  const cloudShortcut = flags['cloud'] === true;
332
374
  const rawMode = readStringFlag(flags, 'execution-mode');
@@ -474,11 +516,66 @@ async function readRlmState(statePath) {
474
516
  return null;
475
517
  }
476
518
  }
519
+ async function maybeCaptureAutoIssueLog(params) {
520
+ if (!params.enabled) {
521
+ return { issueLog: null, issueLogError: null };
522
+ }
523
+ try {
524
+ const issueLog = await writeDoctorIssueLog({
525
+ doctor: runDoctor(),
526
+ issueTitle: params.issueTitle,
527
+ issueNotes: params.issueNotes,
528
+ taskFilter: params.taskFilter
529
+ });
530
+ return { issueLog, issueLogError: null };
531
+ }
532
+ catch (error) {
533
+ const issueLogError = error?.message ?? String(error);
534
+ return { issueLog: null, issueLogError };
535
+ }
536
+ }
537
+ function withAutoIssueLogContext(error, capture) {
538
+ const baseMessage = error?.message ?? String(error);
539
+ const lines = [baseMessage];
540
+ if (capture.issueLog) {
541
+ lines.push(`Auto issue log: saved to ${capture.issueLog.issue_log_path} (bundle: ${capture.issueLog.bundle_path}).`);
542
+ }
543
+ if (capture.issueLogError) {
544
+ lines.push(`Auto issue log: failed (${capture.issueLogError})`);
545
+ }
546
+ return new Error(lines.join('\n'));
547
+ }
548
+ function resolveTaskFilter(preferredTaskId, taskIdOverride) {
549
+ const preferred = preferredTaskId?.trim();
550
+ if (preferred) {
551
+ return preferred;
552
+ }
553
+ const taskOverride = taskIdOverride?.trim();
554
+ if (taskOverride) {
555
+ return taskOverride;
556
+ }
557
+ const mcpTask = process.env.MCP_RUNNER_TASK_ID?.trim();
558
+ if (mcpTask) {
559
+ return mcpTask;
560
+ }
561
+ const taskEnv = process.env.TASK?.trim();
562
+ if (taskEnv) {
563
+ return taskEnv;
564
+ }
565
+ const codexTask = process.env.CODEX_ORCHESTRATOR_TASK_ID?.trim();
566
+ return codexTask && codexTask.length > 0 ? codexTask : null;
567
+ }
477
568
  async function handleStart(orchestrator, rawArgs) {
478
569
  const { positionals, flags } = parseArgs(rawArgs);
570
+ if (isHelpRequest(positionals, flags)) {
571
+ printStartHelp();
572
+ return;
573
+ }
479
574
  const pipelineId = positionals[0];
480
575
  const format = flags['format'] === 'json' ? 'json' : 'text';
481
576
  const executionMode = resolveExecutionModeFlag(flags);
577
+ applyRepoConfigRequiredPolicy(flags);
578
+ const autoIssueLogEnabled = resolveAutoIssueLogEnabled(flags);
482
579
  if (pipelineId === 'rlm') {
483
580
  const goal = readStringFlag(flags, 'goal');
484
581
  const warnLegacyEnvAlias = shouldWarnLegacyMultiAgentEnv(flags, process.env);
@@ -487,31 +584,51 @@ async function handleStart(orchestrator, rawArgs) {
487
584
  console.warn('Warning: RLM_SYMBOLIC_COLLAB is a legacy alias; prefer RLM_SYMBOLIC_MULTI_AGENT.');
488
585
  }
489
586
  }
490
- await withRunUi(flags, format, async (runEvents) => {
491
- let taskIdOverride = typeof flags['task'] === 'string' ? flags['task'] : undefined;
492
- if (pipelineId === 'rlm') {
493
- taskIdOverride = resolveRlmTaskId(taskIdOverride);
494
- process.env.MCP_RUNNER_TASK_ID = taskIdOverride;
495
- if (format !== 'json') {
496
- console.log(`Task: ${taskIdOverride}`);
587
+ let taskIdOverride = typeof flags['task'] === 'string' ? flags['task'] : undefined;
588
+ try {
589
+ await withRunUi(flags, format, async (runEvents) => {
590
+ if (pipelineId === 'rlm') {
591
+ taskIdOverride = resolveRlmTaskId(taskIdOverride);
592
+ process.env.MCP_RUNNER_TASK_ID = taskIdOverride;
593
+ if (format !== 'json') {
594
+ console.log(`Task: ${taskIdOverride}`);
595
+ }
497
596
  }
498
- }
499
- const result = await orchestrator.start({
500
- pipelineId,
501
- taskId: taskIdOverride,
502
- parentRunId: typeof flags['parent-run'] === 'string' ? flags['parent-run'] : undefined,
503
- approvalPolicy: typeof flags['approval-policy'] === 'string' ? flags['approval-policy'] : undefined,
504
- targetStageId: resolveTargetStageId(flags),
505
- executionMode,
506
- runEvents
597
+ const result = await orchestrator.start({
598
+ pipelineId,
599
+ taskId: taskIdOverride,
600
+ parentRunId: typeof flags['parent-run'] === 'string' ? flags['parent-run'] : undefined,
601
+ approvalPolicy: typeof flags['approval-policy'] === 'string' ? flags['approval-policy'] : undefined,
602
+ targetStageId: resolveTargetStageId(flags),
603
+ executionMode,
604
+ runEvents
605
+ });
606
+ const issueLogCapture = result.manifest.status !== 'succeeded'
607
+ ? await maybeCaptureAutoIssueLog({
608
+ enabled: autoIssueLogEnabled,
609
+ issueTitle: `Auto issue log: start ${pipelineId ?? 'diagnostics'} failed`,
610
+ issueNotes: `Automatic failure capture for run ${result.manifest.run_id} (${result.manifest.status}).`,
611
+ taskFilter: resolveTaskFilter(result.manifest.task_id, taskIdOverride)
612
+ })
613
+ : { issueLog: null, issueLogError: null };
614
+ emitRunOutput(result, format, 'Run started', issueLogCapture);
507
615
  });
508
- emitRunOutput(result, format, 'Run started');
509
- });
616
+ }
617
+ catch (error) {
618
+ const issueLogCapture = await maybeCaptureAutoIssueLog({
619
+ enabled: autoIssueLogEnabled,
620
+ issueTitle: `Auto issue log: start ${pipelineId ?? 'diagnostics'} failed before run manifest`,
621
+ issueNotes: 'Automatic failure capture for start setup failure before run manifest creation.',
622
+ taskFilter: resolveTaskFilter(undefined, taskIdOverride)
623
+ });
624
+ throw withAutoIssueLogContext(error, issueLogCapture);
625
+ }
510
626
  }
511
627
  async function handleFrontendTest(orchestrator, rawArgs) {
512
628
  const { positionals, flags } = parseArgs(rawArgs);
513
629
  const format = flags['format'] === 'json' ? 'json' : 'text';
514
630
  const devtools = Boolean(flags['devtools']);
631
+ applyRepoConfigRequiredPolicy(flags);
515
632
  if (positionals.length > 0) {
516
633
  console.error(`[frontend-test] ignoring extra arguments: ${positionals.join(' ')}`);
517
634
  }
@@ -554,75 +671,127 @@ async function handleFlow(orchestrator, rawArgs) {
554
671
  }
555
672
  const format = flags['format'] === 'json' ? 'json' : 'text';
556
673
  const executionMode = resolveExecutionModeFlag(flags);
674
+ applyRepoConfigRequiredPolicy(flags);
675
+ const autoIssueLogEnabled = resolveAutoIssueLogEnabled(flags);
557
676
  const taskId = typeof flags['task'] === 'string' ? flags['task'] : undefined;
558
677
  const parentRunId = typeof flags['parent-run'] === 'string' ? flags['parent-run'] : undefined;
559
678
  const approvalPolicy = typeof flags['approval-policy'] === 'string' ? flags['approval-policy'] : undefined;
560
679
  const targetStageId = resolveTargetStageId(flags);
561
- const { docsReviewTargetStageId, implementationGateTargetStageId } = await resolveFlowTargetStageSelection(orchestrator, taskId, targetStageId);
562
- await withRunUi(flags, format, async (runEvents) => {
563
- const docsReviewResult = await orchestrator.start({
564
- pipelineId: 'docs-review',
565
- taskId,
566
- parentRunId,
567
- approvalPolicy,
568
- targetStageId: docsReviewTargetStageId,
569
- executionMode,
570
- runEvents
571
- });
572
- const docsPayload = toRunOutputPayload(docsReviewResult);
573
- if (format === 'text') {
574
- emitRunOutput(docsReviewResult, format, 'Docs-review run');
575
- }
576
- if (docsReviewResult.manifest.status !== 'succeeded') {
577
- process.exitCode = 1;
680
+ try {
681
+ const { docsReviewTargetStageId, implementationGateTargetStageId } = await resolveFlowTargetStageSelection(orchestrator, taskId, targetStageId);
682
+ await withRunUi(flags, format, async (runEvents) => {
683
+ const docsReviewResult = await orchestrator.start({
684
+ pipelineId: 'docs-review',
685
+ taskId,
686
+ parentRunId,
687
+ approvalPolicy,
688
+ targetStageId: docsReviewTargetStageId,
689
+ executionMode,
690
+ runEvents
691
+ });
692
+ const docsPayload = toRunOutputPayload(docsReviewResult);
693
+ if (format === 'text') {
694
+ emitRunOutput(docsReviewResult, format, 'Docs-review run');
695
+ }
696
+ if (docsReviewResult.manifest.status !== 'succeeded') {
697
+ const issueLogCapture = await maybeCaptureAutoIssueLog({
698
+ enabled: autoIssueLogEnabled,
699
+ issueTitle: 'Auto issue log: flow docs-review failed',
700
+ issueNotes: `Automatic failure capture for docs-review run ${docsReviewResult.manifest.run_id} (${docsReviewResult.manifest.status}).`,
701
+ taskFilter: resolveTaskFilter(docsReviewResult.manifest.task_id, taskId)
702
+ });
703
+ process.exitCode = 1;
704
+ if (format === 'json') {
705
+ const payload = {
706
+ status: docsReviewResult.manifest.status,
707
+ failed_stage: 'docs-review',
708
+ docs_review: docsPayload,
709
+ implementation_gate: null,
710
+ issue_log: issueLogCapture.issueLog,
711
+ issue_log_error: issueLogCapture.issueLogError
712
+ };
713
+ console.log(JSON.stringify(payload, null, 2));
714
+ }
715
+ else {
716
+ console.log('Flow halted: docs-review failed.');
717
+ if (issueLogCapture.issueLog) {
718
+ for (const line of formatDoctorIssueLogSummary(issueLogCapture.issueLog)) {
719
+ console.log(line);
720
+ }
721
+ }
722
+ if (issueLogCapture.issueLogError) {
723
+ console.log(`Auto issue log: failed (${issueLogCapture.issueLogError})`);
724
+ }
725
+ }
726
+ return;
727
+ }
728
+ const implementationGateResult = await orchestrator.start({
729
+ pipelineId: 'implementation-gate',
730
+ taskId,
731
+ parentRunId: docsReviewResult.manifest.run_id,
732
+ approvalPolicy,
733
+ targetStageId: implementationGateTargetStageId,
734
+ executionMode,
735
+ runEvents
736
+ });
737
+ const implementationPayload = toRunOutputPayload(implementationGateResult);
738
+ const issueLogCapture = implementationGateResult.manifest.status !== 'succeeded'
739
+ ? await maybeCaptureAutoIssueLog({
740
+ enabled: autoIssueLogEnabled,
741
+ issueTitle: 'Auto issue log: flow implementation-gate failed',
742
+ issueNotes: `Automatic failure capture for implementation-gate run ${implementationGateResult.manifest.run_id} (${implementationGateResult.manifest.status}).`,
743
+ taskFilter: resolveTaskFilter(implementationGateResult.manifest.task_id, taskId)
744
+ })
745
+ : { issueLog: null, issueLogError: null };
578
746
  if (format === 'json') {
579
747
  const payload = {
580
- status: docsReviewResult.manifest.status,
581
- failed_stage: 'docs-review',
748
+ status: implementationGateResult.manifest.status,
749
+ failed_stage: implementationGateResult.manifest.status === 'succeeded' ? null : 'implementation-gate',
582
750
  docs_review: docsPayload,
583
- implementation_gate: null
751
+ implementation_gate: implementationPayload,
752
+ issue_log: issueLogCapture.issueLog,
753
+ issue_log_error: issueLogCapture.issueLogError
584
754
  };
585
755
  console.log(JSON.stringify(payload, null, 2));
756
+ if (implementationGateResult.manifest.status !== 'succeeded') {
757
+ process.exitCode = 1;
758
+ }
759
+ return;
586
760
  }
587
- else {
588
- console.log('Flow halted: docs-review failed.');
589
- }
590
- return;
591
- }
592
- const implementationGateResult = await orchestrator.start({
593
- pipelineId: 'implementation-gate',
594
- taskId,
595
- parentRunId: docsReviewResult.manifest.run_id,
596
- approvalPolicy,
597
- targetStageId: implementationGateTargetStageId,
598
- executionMode,
599
- runEvents
600
- });
601
- const implementationPayload = toRunOutputPayload(implementationGateResult);
602
- if (format === 'json') {
603
- const payload = {
604
- status: implementationGateResult.manifest.status,
605
- failed_stage: implementationGateResult.manifest.status === 'succeeded' ? null : 'implementation-gate',
606
- docs_review: docsPayload,
607
- implementation_gate: implementationPayload
608
- };
609
- console.log(JSON.stringify(payload, null, 2));
761
+ emitRunOutput(implementationGateResult, format, 'Implementation-gate run');
610
762
  if (implementationGateResult.manifest.status !== 'succeeded') {
611
763
  process.exitCode = 1;
764
+ console.log('Flow halted: implementation-gate failed.');
765
+ if (issueLogCapture.issueLog) {
766
+ for (const line of formatDoctorIssueLogSummary(issueLogCapture.issueLog)) {
767
+ console.log(line);
768
+ }
769
+ }
770
+ if (issueLogCapture.issueLogError) {
771
+ console.log(`Auto issue log: failed (${issueLogCapture.issueLogError})`);
772
+ }
773
+ return;
612
774
  }
613
- return;
614
- }
615
- emitRunOutput(implementationGateResult, format, 'Implementation-gate run');
616
- if (implementationGateResult.manifest.status !== 'succeeded') {
617
- process.exitCode = 1;
618
- console.log('Flow halted: implementation-gate failed.');
619
- return;
620
- }
621
- console.log('Flow complete: docs-review -> implementation-gate.');
622
- });
775
+ console.log('Flow complete: docs-review -> implementation-gate.');
776
+ });
777
+ }
778
+ catch (error) {
779
+ const issueLogCapture = await maybeCaptureAutoIssueLog({
780
+ enabled: autoIssueLogEnabled,
781
+ issueTitle: 'Auto issue log: flow failed before run manifest',
782
+ issueNotes: 'Automatic failure capture for flow setup failure before run manifest creation.',
783
+ taskFilter: resolveTaskFilter(undefined, taskId)
784
+ });
785
+ throw withAutoIssueLogContext(error, issueLogCapture);
786
+ }
623
787
  }
624
788
  async function handlePlan(orchestrator, rawArgs) {
625
789
  const { positionals, flags } = parseArgs(rawArgs);
790
+ if (isHelpRequest(positionals, flags)) {
791
+ printPlanHelp();
792
+ return;
793
+ }
794
+ applyRepoConfigRequiredPolicy(flags);
626
795
  const pipelineId = positionals[0];
627
796
  const format = flags['format'] === 'json' ? 'json' : 'text';
628
797
  const result = await orchestrator.plan({
@@ -642,6 +811,7 @@ async function handleRlm(orchestrator, rawArgs) {
642
811
  printRlmHelp();
643
812
  return;
644
813
  }
814
+ applyRepoConfigRequiredPolicy(flags);
645
815
  const goalFromArgs = positionals.length > 0 ? positionals.join(' ') : undefined;
646
816
  const goal = goalFromArgs ?? readStringFlag(flags, 'goal') ?? process.env.RLM_GOAL?.trim();
647
817
  if (!goal) {
@@ -704,6 +874,7 @@ async function handleResume(orchestrator, rawArgs) {
704
874
  printResumeHelp();
705
875
  return;
706
876
  }
877
+ applyRepoConfigRequiredPolicy(flags);
707
878
  const runId = (flags['run'] ?? positionals[0]);
708
879
  if (!runId) {
709
880
  throw new Error('resume requires --run <run-id>.');
@@ -778,8 +949,8 @@ async function withRunUi(flags, format, action) {
778
949
  runEvents.dispose();
779
950
  }
780
951
  }
781
- function emitRunOutput(result, format, label) {
782
- const payload = toRunOutputPayload(result);
952
+ function emitRunOutput(result, format, label, issueLogCapture = { issueLog: null, issueLogError: null }) {
953
+ const payload = toRunOutputPayload(result, issueLogCapture);
783
954
  if (format === 'json') {
784
955
  console.log(JSON.stringify(payload, null, 2));
785
956
  return;
@@ -797,8 +968,16 @@ function emitRunOutput(result, format, label) {
797
968
  console.log(` ${line}`);
798
969
  }
799
970
  }
971
+ if (payload.issue_log) {
972
+ for (const line of formatDoctorIssueLogSummary(payload.issue_log)) {
973
+ console.log(line);
974
+ }
975
+ }
976
+ if (payload.issue_log_error) {
977
+ console.log(`Auto issue log: failed (${payload.issue_log_error})`);
978
+ }
800
979
  }
801
- function toRunOutputPayload(result) {
980
+ function toRunOutputPayload(result, issueLogCapture = { issueLog: null, issueLogError: null }) {
802
981
  return {
803
982
  run_id: result.manifest.run_id,
804
983
  status: result.manifest.status,
@@ -806,7 +985,9 @@ function toRunOutputPayload(result) {
806
985
  manifest: `${result.manifest.artifact_root}/manifest.json`,
807
986
  log_path: result.manifest.log_path,
808
987
  summary: result.manifest.summary ?? null,
809
- cloud_fallback_reason: result.manifest.cloud_fallback?.reason ?? null
988
+ cloud_fallback_reason: result.manifest.cloud_fallback?.reason ?? null,
989
+ issue_log: issueLogCapture.issueLog,
990
+ issue_log_error: issueLogCapture.issueLogError
810
991
  };
811
992
  }
812
993
  async function handleExec(rawArgs) {
@@ -907,6 +1088,10 @@ async function handleSelfCheck(rawArgs) {
907
1088
  }
908
1089
  async function handleInit(rawArgs) {
909
1090
  const { positionals, flags } = parseArgs(rawArgs);
1091
+ if (isHelpRequest(positionals, flags)) {
1092
+ printInitHelp();
1093
+ return;
1094
+ }
910
1095
  const template = positionals[0];
911
1096
  if (!template) {
912
1097
  throw new Error('init requires a template name (e.g. init codex).');
@@ -965,8 +1150,9 @@ Options:
965
1150
  }
966
1151
  const repoFlag = readStringFlag(flags, 'repo');
967
1152
  const repoRoot = repoFlag ?? process.cwd();
968
- const repoFlagValue = repoFlag ? (/\s/u.test(repoFlag) ? JSON.stringify(repoFlag) : repoFlag) : null;
969
- const delegationRepoArg = repoFlagValue ? ` --repo ${repoFlagValue}` : '';
1153
+ const delegationCommandPreview = repoFlag
1154
+ ? buildCommandPreview('codex-orchestrator', ['delegation', 'setup', '--yes', '--repo', repoFlag])
1155
+ : 'codex-orchestrator delegation setup --yes';
970
1156
  const bundledSkills = await listBundledSkills();
971
1157
  if (bundledSkills.length === 0) {
972
1158
  throw new Error('No bundled skills detected; cannot run setup.');
@@ -1000,7 +1186,7 @@ Options:
1000
1186
  for (const commandLine of payload.steps.skills.commandLines) {
1001
1187
  console.log(` - ${commandLine}`);
1002
1188
  }
1003
- console.log(`- Delegation: codex-orchestrator delegation setup --yes${delegationRepoArg}`);
1189
+ console.log(`- Delegation: ${delegationCommandPreview}`);
1004
1190
  console.log('- DevTools: codex-orchestrator devtools setup --yes');
1005
1191
  for (const line of formatSetupGuidanceSummary(guidance)) {
1006
1192
  console.log(line);
@@ -1063,11 +1249,18 @@ async function handleDoctor(rawArgs) {
1063
1249
  const format = flags['format'] === 'json' ? 'json' : 'text';
1064
1250
  const includeUsage = Boolean(flags['usage']);
1065
1251
  const includeCloudPreflight = Boolean(flags['cloud-preflight']);
1252
+ const includeIssueLog = Boolean(flags['issue-log']);
1066
1253
  const cloudEnvIdOverride = readStringFlag(flags, 'cloud-env-id');
1067
1254
  const cloudBranchOverride = readStringFlag(flags, 'cloud-branch');
1255
+ const issueTitle = readStringFlag(flags, 'issue-title');
1256
+ const issueNotes = readStringFlag(flags, 'issue-notes');
1257
+ const issueLogPath = readStringFlag(flags, 'issue-log-path');
1068
1258
  if (!includeCloudPreflight && (cloudEnvIdOverride || cloudBranchOverride)) {
1069
1259
  throw new Error('--cloud-env-id/--cloud-branch require --cloud-preflight.');
1070
1260
  }
1261
+ if (!includeIssueLog && (issueTitle || issueNotes || issueLogPath)) {
1262
+ throw new Error('--issue-title/--issue-notes/--issue-log-path require --issue-log.');
1263
+ }
1071
1264
  const wantsApply = Boolean(flags['apply']);
1072
1265
  const apply = Boolean(flags['yes']);
1073
1266
  if (wantsApply && format === 'json') {
@@ -1096,6 +1289,17 @@ async function handleDoctor(rawArgs) {
1096
1289
  taskId: taskFilter
1097
1290
  })
1098
1291
  : null;
1292
+ const issueLogResult = includeIssueLog
1293
+ ? await writeDoctorIssueLog({
1294
+ doctor: doctorResult,
1295
+ usage: usageResult,
1296
+ cloudPreflight: cloudPreflightResult,
1297
+ issueTitle,
1298
+ issueNotes,
1299
+ issueLogPath,
1300
+ taskFilter
1301
+ })
1302
+ : null;
1099
1303
  if (format === 'json') {
1100
1304
  const payload = { ...doctorResult };
1101
1305
  if (usageResult) {
@@ -1104,6 +1308,9 @@ async function handleDoctor(rawArgs) {
1104
1308
  if (cloudPreflightResult) {
1105
1309
  payload.cloud_preflight = cloudPreflightResult;
1106
1310
  }
1311
+ if (issueLogResult) {
1312
+ payload.issue_log = issueLogResult;
1313
+ }
1107
1314
  console.log(JSON.stringify(payload, null, 2));
1108
1315
  return;
1109
1316
  }
@@ -1120,6 +1327,11 @@ async function handleDoctor(rawArgs) {
1120
1327
  console.log(line);
1121
1328
  }
1122
1329
  }
1330
+ if (issueLogResult) {
1331
+ for (const line of formatDoctorIssueLogSummary(issueLogResult)) {
1332
+ console.log(line);
1333
+ }
1334
+ }
1123
1335
  if (!wantsApply) {
1124
1336
  return;
1125
1337
  }
@@ -1672,6 +1884,8 @@ Commands:
1672
1884
  --execution-mode <mcp|cloud> Force execution mode for this run and child subpipelines.
1673
1885
  --cloud Shortcut for --execution-mode cloud.
1674
1886
  --target <stage-id> Focus plan/build metadata on a specific stage (alias: --target-stage).
1887
+ --auto-issue-log [true|false] On failure, auto-write doctor issue bundle/log entry.
1888
+ --repo-config-required [true|false] Require repo-local codex.orchestrator.json (no package fallback).
1675
1889
  --goal "<goal>" When pipeline is rlm, set the RLM goal.
1676
1890
  --multi-agent [auto|true|false] Preferred alias for multi-agent collab subagents (implies symbolic mode).
1677
1891
  --collab [auto|true|false] Legacy alias for --multi-agent.
@@ -1684,6 +1898,7 @@ Commands:
1684
1898
 
1685
1899
  rlm "<goal>" Run RLM loop until validator passes.
1686
1900
  --task <id> Override task identifier.
1901
+ --repo-config-required [true|false] Require repo-local codex.orchestrator.json (no package fallback).
1687
1902
  --multi-agent [auto|true|false] Preferred alias for multi-agent collab subagents (implies symbolic mode).
1688
1903
  --collab [auto|true|false] Legacy alias for --multi-agent.
1689
1904
  --validator <cmd|none> Set validator command or disable validation.
@@ -1698,6 +1913,7 @@ Commands:
1698
1913
  frontend-test Run frontend testing pipeline.
1699
1914
  --devtools Enable Chrome DevTools MCP for this run.
1700
1915
  --task <id> Override task identifier (defaults to MCP_RUNNER_TASK_ID).
1916
+ --repo-config-required [true|false] Require repo-local codex.orchestrator.json (no package fallback).
1701
1917
  --parent-run <id> Link run to parent run id.
1702
1918
  --approval-policy <p> Record approval policy metadata.
1703
1919
  --format json Emit machine-readable output.
@@ -1713,6 +1929,8 @@ Commands:
1713
1929
  --execution-mode <mcp|cloud> Force execution mode for both runs.
1714
1930
  --cloud Shortcut for --execution-mode cloud.
1715
1931
  --target <stage-id> Focus plan/build metadata on a specific stage (alias: --target-stage).
1932
+ --auto-issue-log [true|false] On failure, auto-write doctor issue bundle/log entry.
1933
+ --repo-config-required [true|false] Require repo-local codex.orchestrator.json (no package fallback).
1716
1934
  --interactive | --ui Enable read-only HUD when running in a TTY.
1717
1935
  --no-interactive Force disable HUD (default is off unless requested).
1718
1936
 
@@ -1720,6 +1938,7 @@ Commands:
1720
1938
  --task <id> Override task identifier.
1721
1939
  --format json Emit machine-readable output.
1722
1940
  --target <stage-id> Highlight the stage chosen for orchestration (alias: --target-stage).
1941
+ --repo-config-required [true|false] Require repo-local codex.orchestrator.json (no package fallback).
1723
1942
 
1724
1943
  exec [command] Run a one-off command with unified exec runtime.
1725
1944
  --json [compact] Emit final JSON summary (optional compact mode).
@@ -1734,6 +1953,7 @@ Commands:
1734
1953
  --actor <name> Record who resumed the run.
1735
1954
  --reason <text> Record why the run was resumed.
1736
1955
  --target <stage-id> Override stage selection before resuming (alias: --target-stage).
1956
+ --repo-config-required [true|false] Require repo-local codex.orchestrator.json (no package fallback).
1737
1957
  --format json Emit machine-readable output.
1738
1958
  --interactive | --ui Enable read-only HUD when running in a TTY.
1739
1959
  --no-interactive Force disable HUD (default is off unless requested).
@@ -1742,6 +1962,7 @@ Commands:
1742
1962
 
1743
1963
  self-check [--format json]
1744
1964
  init codex [--cwd <path>] [--force]
1965
+ Installs AGENTS.md, mcp-client.json, and codex.orchestrator.json.
1745
1966
  --codex-cli Also run CO-managed Codex CLI setup (plan unless --yes; activate with CODEX_CLI_USE_MANAGED=1).
1746
1967
  --codex-source <path> Build from local Codex repo (or git URL).
1747
1968
  --codex-ref <ref> Git ref (branch/tag/sha) when building from repo.
@@ -1761,6 +1982,10 @@ Commands:
1761
1982
  --cloud-preflight Run cloud readiness preflight checks (env/codex/git/branch).
1762
1983
  --cloud-env-id <id> Override env id for --cloud-preflight (default: CODEX_CLOUD_ENV_ID).
1763
1984
  --cloud-branch <name> Override branch for --cloud-preflight (default: CODEX_CLOUD_BRANCH).
1985
+ --issue-log Append markdown issue entry + JSON bundle for downstream triage.
1986
+ --issue-title <text> Optional title for --issue-log entries.
1987
+ --issue-notes <text> Optional notes for --issue-log entries.
1988
+ --issue-log-path <p> Output markdown path (default: docs/codex-orchestrator-issues.md).
1764
1989
  --apply Plan/apply quick fixes for DevTools + delegation wiring (use with --yes).
1765
1990
  --yes Apply fixes when --apply is set.
1766
1991
  --format json Emit machine-readable output (not supported with --apply).
@@ -1841,6 +2066,7 @@ Options:
1841
2066
  --actor <name> Record who resumed the run.
1842
2067
  --reason <text> Record why the run was resumed.
1843
2068
  --target <stage-id> Override stage selection before resuming.
2069
+ --repo-config-required [true|false] Require repo-local codex.orchestrator.json (no package fallback).
1844
2070
  --format json Emit machine-readable output.
1845
2071
  --interactive | --ui Enable read-only HUD when running in a TTY.
1846
2072
  --no-interactive Force disable HUD.
@@ -1891,6 +2117,7 @@ function printRlmHelp() {
1891
2117
  Options:
1892
2118
  --goal "<goal>" Alternate way to set the goal (positional is preferred).
1893
2119
  --task <id> Override task identifier (defaults to MCP_RUNNER_TASK_ID).
2120
+ --repo-config-required [true|false] Require repo-local codex.orchestrator.json (no package fallback).
1894
2121
  --multi-agent [auto|true|false] Preferred alias for multi-agent collab subagents (implies symbolic mode).
1895
2122
  --collab [auto|true|false] Legacy alias for --multi-agent.
1896
2123
  --validator <cmd|none> Set validator command or disable validation.
@@ -1925,7 +2152,67 @@ Options:
1925
2152
  --execution-mode <mcp|cloud> Force execution mode for both runs.
1926
2153
  --cloud Shortcut for --execution-mode cloud.
1927
2154
  --target <stage-id> Focus plan/build metadata (applies where the stage exists).
2155
+ --auto-issue-log [true|false] On failure, auto-write doctor issue bundle/log entry.
2156
+ --repo-config-required [true|false] Require repo-local codex.orchestrator.json (no package fallback).
1928
2157
  --interactive | --ui Enable read-only HUD when running in a TTY.
1929
2158
  --no-interactive Force disable HUD.
1930
2159
  `);
1931
2160
  }
2161
+ function printStartHelp() {
2162
+ console.log(`Usage: codex-orchestrator start [pipeline] [options]
2163
+
2164
+ Start a new run. If no pipeline is provided, diagnostics is used.
2165
+
2166
+ Options:
2167
+ --task <id> Override task identifier.
2168
+ --parent-run <id> Link run to parent run id.
2169
+ --approval-policy <p> Record approval policy metadata.
2170
+ --format json Emit machine-readable output.
2171
+ --execution-mode <mcp|cloud> Force execution mode for this run.
2172
+ --cloud Shortcut for --execution-mode cloud.
2173
+ --target <stage-id> Focus plan/build metadata on a specific stage.
2174
+ --auto-issue-log [true|false] On failure, auto-write doctor issue bundle/log entry.
2175
+ --repo-config-required [true|false] Require repo-local codex.orchestrator.json (no package fallback).
2176
+ --goal "<goal>" When pipeline is rlm, set the RLM goal.
2177
+ --multi-agent [auto|true|false] Preferred alias for multi-agent collab subagents.
2178
+ --collab [auto|true|false] Legacy alias for --multi-agent.
2179
+ --validator <cmd|none> When pipeline is rlm, set validator command.
2180
+ --max-iterations <n> When pipeline is rlm, override max iterations.
2181
+ --max-minutes <n> When pipeline is rlm, override max minutes.
2182
+ --roles <single|triad> When pipeline is rlm, set role split.
2183
+ --interactive | --ui Enable read-only HUD when running in a TTY.
2184
+ --no-interactive Force disable HUD.
2185
+ `);
2186
+ }
2187
+ function printPlanHelp() {
2188
+ console.log(`Usage: codex-orchestrator plan [pipeline] [options]
2189
+
2190
+ Preview pipeline stages without executing.
2191
+
2192
+ Options:
2193
+ --task <id> Override task identifier.
2194
+ --format json Emit machine-readable output.
2195
+ --target <stage-id> Highlight the stage chosen for orchestration.
2196
+ --repo-config-required [true|false] Require repo-local codex.orchestrator.json (no package fallback).
2197
+ `);
2198
+ }
2199
+ function printInitHelp() {
2200
+ console.log(`Usage: codex-orchestrator init codex [options]
2201
+
2202
+ Install starter templates into the target repository:
2203
+ - AGENTS.md
2204
+ - mcp-client.json
2205
+ - codex.orchestrator.json
2206
+
2207
+ Options:
2208
+ --cwd <path> Target directory (default current directory).
2209
+ --force Overwrite existing template files.
2210
+ --codex-cli Also run CO-managed Codex CLI setup (plan unless --yes).
2211
+ --codex-source <path> Build managed Codex CLI from local repo (or git URL).
2212
+ --codex-ref <ref> Git ref for --codex-source.
2213
+ --codex-download-url <url> Download managed Codex CLI prebuilt binary.
2214
+ --codex-download-sha256 <sha> Expected SHA256 for the prebuilt download.
2215
+ --codex-force Overwrite existing managed Codex CLI binary.
2216
+ --yes Apply managed Codex CLI setup.
2217
+ `);
2218
+ }