@ttfw/envoi 1.0.7 → 1.0.8

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
@@ -83,11 +83,14 @@ envoi start
83
83
  `envoi start` handles onboarding end-to-end:
84
84
  1. asks `Tour` vs `Setup`,
85
85
  2. captures PRD/context (`--prd-file`, stdin, discovered file, editor, or inline paste),
86
- 3. configures mode (`task|milestone|autonomous`) and builder (`cursor|claude_code`),
87
- 4. optionally enables reviewer (`none|codex`),
88
- 5. runs role connectivity checks,
89
- 6. writes `ROADMAP.json` from the planner snapshot,
90
- 7. asks whether to start execution now.
86
+ 3. configures mode (`milestone|autonomous|task`) and builder (`cursor|claude_code`),
87
+ 4. chooses planner provider (`claude_code|chatgpt`) and assigns planner model automatically,
88
+ 5. optionally configures builder model when builder is `claude_code` (`sonnet|haiku`),
89
+ 6. configures reviewer (`codex|none`, default recommended: `codex`),
90
+ 7. auto-initializes git (`git init`) when no repository exists,
91
+ 8. runs role connectivity checks,
92
+ 9. writes `ROADMAP.json` from the planner snapshot,
93
+ 10. asks whether to start execution now.
91
94
 
92
95
  Non-TTY (agent-run) onboarding:
93
96
  - Envoi emits exactly one next question per run (`envoi.onboarding.next_question.v1`) and returns exit code `0` by default (to avoid noisy error wrappers in agent CLIs).
@@ -98,6 +101,7 @@ Non-TTY (agent-run) onboarding:
98
101
  - `--verbose-onboarding` (human + pretty JSON)
99
102
  - `--onboarding-output compact|json|verbose`
100
103
  - Use `--strict-exit` to return exit code `20` when onboarding still needs input.
104
+ - Use `--reconfigure` to force a fresh questionnaire after onboarding is already marked complete.
101
105
  - Resume with either:
102
106
  - `envoi start --answers-json '<json>'`
103
107
  - `envoi start --answers-file <path>`
@@ -5,6 +5,7 @@ interface InstallOptions {
5
5
  prdFile?: string;
6
6
  mode?: string;
7
7
  builder?: string;
8
+ plannerProvider?: string;
8
9
  reviewer?: string;
9
10
  orchestratorModel?: string;
10
11
  builderModel?: string;
@@ -15,6 +16,7 @@ interface InstallOptions {
15
16
  verboseOnboarding?: boolean;
16
17
  onboardingOutput?: string;
17
18
  strictExit?: boolean;
19
+ reconfigure?: boolean;
18
20
  autoRun?: boolean;
19
21
  globalInstall?: boolean;
20
22
  skipGlobalInstall?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAMA,UAAU,cAAc;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAqCD,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAmE3E"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAMA,UAAU,cAAc;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAqCD,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAqE3E"}
@@ -49,6 +49,7 @@ export async function installCommand(options) {
49
49
  prdFile: options.prdFile,
50
50
  mode: options.mode,
51
51
  builder: options.builder,
52
+ plannerProvider: options.plannerProvider,
52
53
  reviewer: options.reviewer,
53
54
  orchestratorModel: options.orchestratorModel,
54
55
  builderModel: options.builderModel,
@@ -59,6 +60,7 @@ export async function installCommand(options) {
59
60
  verboseOnboarding: options.verboseOnboarding,
60
61
  onboardingOutput: options.onboardingOutput,
61
62
  strictExit: options.strictExit,
63
+ reconfigure: options.reconfigure,
62
64
  showTourPrompt: true,
63
65
  autoRun: options.autoRun,
64
66
  });
@@ -1 +1 @@
1
- {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@
11
11
  */
12
12
  type LoopMode = 'task' | 'milestone' | 'autonomous';
13
13
  type BuilderChoice = 'claude_code' | 'cursor';
14
+ type PlannerProvider = 'claude_code' | 'chatgpt';
14
15
  type ReviewerChoice = 'none' | 'codex';
15
16
  declare const ONBOARDING_REVIEW_PAYLOAD_TYPE = "envoi.onboarding.review.v1";
16
17
  export type OnboardingOutputMode = 'compact' | 'json' | 'verbose';
@@ -39,6 +40,7 @@ interface OnboardingReviewPayload {
39
40
  summary: {
40
41
  mode?: string;
41
42
  builder?: string;
43
+ planner_provider?: string;
42
44
  orchestrator_model?: string;
43
45
  builder_model?: string;
44
46
  reviewer?: string;
@@ -61,6 +63,7 @@ interface OnboardingAnswerPayload {
61
63
  export interface OnboardingQuestionInputs {
62
64
  mode?: LoopMode;
63
65
  builder?: BuilderChoice;
66
+ plannerProvider?: PlannerProvider;
64
67
  orchestratorModel?: string;
65
68
  builderModel?: string;
66
69
  reviewer?: ReviewerChoice;
@@ -69,6 +72,7 @@ export interface OnboardingQuestionInputs {
69
72
  defaults: {
70
73
  mode: LoopMode;
71
74
  builder: BuilderChoice;
75
+ plannerProvider: PlannerProvider;
72
76
  orchestratorModel: string;
73
77
  builderModel: string;
74
78
  reviewer: ReviewerChoice;
@@ -78,6 +82,7 @@ export interface OnboardingQuestionInputs {
78
82
  interface InlineAnswersState {
79
83
  mode?: LoopMode;
80
84
  builder?: BuilderChoice;
85
+ plannerProvider?: PlannerProvider;
81
86
  orchestratorModel?: string;
82
87
  builderModel?: string;
83
88
  reviewer?: ReviewerChoice;
@@ -107,9 +112,11 @@ export declare function extractRoadmapQuestions(prompt: string): string[];
107
112
  export declare function onboardCommand(options: {
108
113
  configPath?: string;
109
114
  forceInit?: boolean;
115
+ reconfigure?: boolean;
110
116
  prdFile?: string;
111
117
  mode?: string;
112
118
  builder?: string;
119
+ plannerProvider?: string;
113
120
  reviewer?: string;
114
121
  orchestratorModel?: string;
115
122
  builderModel?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"onboard.d.ts","sourceRoot":"","sources":["../../src/commands/onboard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"onboard.d.ts","sourceRoot":"","sources":["../../src/commands/onboard.ts"],"names":[],"mappings":"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"}
@@ -34,16 +34,21 @@ const NON_INTERACTIVE_STDIN_PROBE_TIMEOUT_MS = 200;
34
34
  const NON_INTERACTIVE_ANSWER_TIMEOUT_MS = 20_000;
35
35
  const NON_INTERACTIVE_MAX_INVALID_RETRIES = 2;
36
36
  const MODE_CHOICES = [
37
- { value: 'task', label: 'task', desc: 'One bounded cycle each time (lowest drift).' },
38
37
  { value: 'milestone', label: 'milestone', desc: 'Runs until milestone boundary, then pauses.' },
39
38
  { value: 'autonomous', label: 'autonomous', desc: 'Runs continuously until blocked or limited.' },
39
+ { value: 'task', label: 'task', desc: 'One bounded cycle each time (lowest drift).' },
40
40
  ];
41
41
  const BUILDER_CHOICES = [
42
42
  { value: 'cursor', label: 'cursor agent', desc: 'Fast iterative execution, low token pressure.' },
43
43
  { value: 'claude_code', label: 'claude code', desc: 'Single CLI stack with simpler setup.' },
44
44
  ];
45
- const ORCHESTRATOR_MODEL_CHOICES = ['opus', 'sonnet', 'haiku'];
46
- const BUILDER_MODEL_CHOICES = ['sonnet', 'opus', 'haiku'];
45
+ const PLANNER_PROVIDER_CHOICES = [
46
+ { value: 'claude_code', label: 'claude code', desc: 'Claude Code orchestrator runtime.' },
47
+ { value: 'chatgpt', label: 'chatgpt', desc: 'Codex/OpenAI orchestrator runtime.' },
48
+ ];
49
+ const CLAUDE_PLANNER_MODEL = 'opus';
50
+ const CHATGPT_PLANNER_MODEL = 'gpt-5.3';
51
+ const BUILDER_MODEL_CHOICES = ['sonnet', 'haiku'];
47
52
  const REVIEWER_MODEL_CHOICES = ['gpt-5', 'o3', 'gpt-5-mini'];
48
53
  function normalizeLoopMode(value) {
49
54
  if (!value || value.trim() === '')
@@ -62,6 +67,17 @@ function normalizeBuilderChoice(value) {
62
67
  return normalized;
63
68
  throw new Error(`Invalid builder: ${value}. Must be 'cursor' or 'claude_code'.`);
64
69
  }
70
+ function normalizePlannerProvider(value) {
71
+ if (!value || value.trim() === '')
72
+ return undefined;
73
+ const normalized = value.trim().toLowerCase();
74
+ if (normalized === 'claude_code' || normalized === 'chatgpt')
75
+ return normalized;
76
+ throw new Error(`Invalid planner provider: ${value}. Must be 'claude_code' or 'chatgpt'.`);
77
+ }
78
+ function resolvePlannerModel(provider) {
79
+ return provider === 'chatgpt' ? CHATGPT_PLANNER_MODEL : CLAUDE_PLANNER_MODEL;
80
+ }
65
81
  function asNonEmptyString(value) {
66
82
  return typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined;
67
83
  }
@@ -191,17 +207,18 @@ export function buildNonInteractiveQuestions(input) {
191
207
  choices: BUILDER_CHOICES.map((choice) => ({ value: choice.value, label: choice.label, desc: choice.desc })),
192
208
  });
193
209
  }
194
- if (!asNonEmptyString(input.orchestratorModel)) {
210
+ if (!input.plannerProvider) {
195
211
  questions.push({
196
- id: 'orchestrator_model',
197
- label: 'Planner model',
212
+ id: 'planner_provider',
213
+ label: 'Planner provider',
198
214
  type: 'select',
199
215
  required: true,
200
- default: input.defaults.orchestratorModel,
201
- choices: ORCHESTRATOR_MODEL_CHOICES.map((value) => ({ value, label: value })),
216
+ default: input.defaults.plannerProvider,
217
+ choices: PLANNER_PROVIDER_CHOICES.map((choice) => ({ value: choice.value, label: choice.label, desc: choice.desc })),
202
218
  });
203
219
  }
204
- if (!asNonEmptyString(input.builderModel)) {
220
+ const effectiveBuilder = input.builder ?? input.defaults.builder;
221
+ if (effectiveBuilder === 'claude_code' && !asNonEmptyString(input.builderModel)) {
205
222
  questions.push({
206
223
  id: 'builder_model',
207
224
  label: 'Builder model',
@@ -219,13 +236,12 @@ export function buildNonInteractiveQuestions(input) {
219
236
  required: true,
220
237
  default: input.defaults.reviewer,
221
238
  choices: [
222
- { value: 'none', label: 'none', desc: 'Less friction, fastest onboarding.' },
223
239
  { value: 'codex', label: 'codex', desc: 'Adds second-pass checks for risky changes.' },
240
+ { value: 'none', label: 'none', desc: 'Skip reviewer for less friction.' },
224
241
  ],
225
242
  });
226
243
  }
227
- const effectiveReviewer = input.reviewer ?? input.defaults.reviewer;
228
- if (effectiveReviewer === 'codex' && !asNonEmptyString(input.reviewerModel)) {
244
+ if (input.reviewer === 'codex' && !asNonEmptyString(input.reviewerModel)) {
229
245
  questions.push({
230
246
  id: 'reviewer_model',
231
247
  label: 'Reviewer model',
@@ -255,7 +271,7 @@ function buildQuestionPayload(sessionId, questions, workspaceDir, exitCode) {
255
271
  next_action: {
256
272
  command: `${CLI_NAME} start --answers-file ${workspaceDir}/onboarding.answers.json`,
257
273
  examples: [
258
- `${CLI_NAME} start --answers-json '{"mode":"milestone","builder":"cursor","orchestrator_model":"opus","builder_model":"sonnet","reviewer":"none","prd_text":"..."}'`,
274
+ `${CLI_NAME} start --answers-json '{"mode":"milestone","builder":"cursor","planner_provider":"claude_code","reviewer":"codex","prd_text":"..."}'`,
259
275
  `npx -y ${PACKAGE_NAME}@latest start --answers-file ${workspaceDir}/onboarding.answers.json`,
260
276
  ],
261
277
  accepted_inputs: ['--answers-json <json-object>', '--answers-file <path-to-json>'],
@@ -413,6 +429,11 @@ function clearInlineField(state, field) {
413
429
  return;
414
430
  case 'builder':
415
431
  state.builder = undefined;
432
+ state.builderModel = undefined;
433
+ return;
434
+ case 'planner_provider':
435
+ state.plannerProvider = undefined;
436
+ state.orchestratorModel = undefined;
416
437
  return;
417
438
  case 'orchestrator_model':
418
439
  state.orchestratorModel = undefined;
@@ -441,6 +462,15 @@ function applyQuestionValue(state, questionId, value) {
441
462
  return;
442
463
  case 'builder':
443
464
  state.builder = normalizeBuilderChoice(value);
465
+ if (state.builder !== 'claude_code') {
466
+ state.builderModel = undefined;
467
+ }
468
+ return;
469
+ case 'planner_provider':
470
+ state.plannerProvider = normalizePlannerProvider(value);
471
+ if (state.plannerProvider) {
472
+ state.orchestratorModel = resolvePlannerModel(state.plannerProvider);
473
+ }
444
474
  return;
445
475
  case 'orchestrator_model':
446
476
  state.orchestratorModel = value;
@@ -472,6 +502,7 @@ export function buildReviewPayload(sessionId, state) {
472
502
  summary: {
473
503
  mode: state.mode,
474
504
  builder: state.builder,
505
+ planner_provider: state.plannerProvider,
475
506
  orchestrator_model: state.orchestratorModel,
476
507
  builder_model: state.builderModel,
477
508
  reviewer: state.reviewer,
@@ -533,7 +564,7 @@ async function promptInlineReview(sessionId, state, reader, timeoutMs) {
533
564
  // eslint-disable-next-line no-constant-condition
534
565
  while (true) {
535
566
  const payload = buildReviewPayload(sessionId, state);
536
- console.log('Onboarding review: confirm choices or edit one field (mode, builder, orchestrator_model, builder_model, reviewer, reviewer_model, prd_text).');
567
+ console.log('Onboarding review: confirm choices or edit one field (mode, builder, planner_provider, builder_model, reviewer, reviewer_model, prd_text).');
537
568
  console.log(JSON.stringify(payload, null, 2));
538
569
  const response = await reader.nextLine(timeoutMs);
539
570
  if (response.status !== 'line')
@@ -553,6 +584,7 @@ async function promptInlineReview(sessionId, state, reader, timeoutMs) {
553
584
  const field = typeof parsed.field === 'string' ? parsed.field.trim() : '';
554
585
  if (field === 'mode' ||
555
586
  field === 'builder' ||
587
+ field === 'planner_provider' ||
556
588
  field === 'orchestrator_model' ||
557
589
  field === 'builder_model' ||
558
590
  field === 'reviewer' ||
@@ -585,6 +617,7 @@ async function runInlineNonInteractiveWizard(params) {
585
617
  const questions = buildNonInteractiveQuestions({
586
618
  mode: state.mode,
587
619
  builder: state.builder,
620
+ plannerProvider: state.plannerProvider,
588
621
  orchestratorModel: state.orchestratorModel,
589
622
  builderModel: state.builderModel,
590
623
  reviewer: state.reviewer,
@@ -598,6 +631,7 @@ async function runInlineNonInteractiveWizard(params) {
598
631
  const unresolved = buildNonInteractiveQuestions({
599
632
  mode: state.mode,
600
633
  builder: state.builder,
634
+ plannerProvider: state.plannerProvider,
601
635
  orchestratorModel: state.orchestratorModel,
602
636
  builderModel: state.builderModel,
603
637
  reviewer: state.reviewer,
@@ -619,6 +653,7 @@ async function runInlineNonInteractiveWizard(params) {
619
653
  const unresolved = buildNonInteractiveQuestions({
620
654
  mode: state.mode,
621
655
  builder: state.builder,
656
+ plannerProvider: state.plannerProvider,
622
657
  orchestratorModel: state.orchestratorModel,
623
658
  builderModel: state.builderModel,
624
659
  reviewer: state.reviewer,
@@ -651,6 +686,9 @@ async function runInlineNonInteractiveWizard(params) {
651
686
  if (reviewResult.field === 'reviewer') {
652
687
  delete mergedAnswerBag.reviewer_model;
653
688
  }
689
+ if (reviewResult.field === 'planner_provider') {
690
+ delete mergedAnswerBag.orchestrator_model;
691
+ }
654
692
  }
655
693
  }
656
694
  finally {
@@ -710,9 +748,18 @@ function buildReviewQuestion(state) {
710
748
  return undefined;
711
749
  }
712
750
  })();
751
+ const safePlannerProvider = (() => {
752
+ try {
753
+ return normalizePlannerProvider(state.plannerProvider);
754
+ }
755
+ catch {
756
+ return undefined;
757
+ }
758
+ })();
713
759
  const payload = buildReviewPayload('inline-review', {
714
760
  mode: safeMode,
715
761
  builder: safeBuilder,
762
+ plannerProvider: safePlannerProvider,
716
763
  orchestratorModel: state.orchestratorModel,
717
764
  builderModel: state.builderModel,
718
765
  reviewer: safeReviewer,
@@ -723,6 +770,7 @@ function buildReviewQuestion(state) {
723
770
  const reviewHint = [
724
771
  `mode=${summary.mode ?? 'n/a'}`,
725
772
  `builder=${summary.builder ?? 'n/a'}`,
773
+ `planner_provider=${summary.planner_provider ?? 'n/a'}`,
726
774
  `orchestrator_model=${summary.orchestrator_model ?? 'n/a'}`,
727
775
  `builder_model=${summary.builder_model ?? 'n/a'}`,
728
776
  `reviewer=${summary.reviewer ?? 'n/a'}`,
@@ -734,14 +782,20 @@ function buildReviewQuestion(state) {
734
782
  label: 'Review onboarding choices',
735
783
  type: 'text',
736
784
  required: true,
737
- help: `${reviewHint}\nReply with 'confirm', 'confirm_and_start', or 'edit:<field>' (field: mode|builder|orchestrator_model|builder_model|reviewer|reviewer_model|prd_text).`,
785
+ help: `${reviewHint}\nReply with 'confirm', 'confirm_and_start', or 'edit:<field>' (field: mode|builder|planner_provider|builder_model|reviewer|reviewer_model|prd_text).`,
738
786
  };
739
787
  }
740
788
  function clearAnswerByField(answers, field) {
741
789
  if (field === 'mode')
742
790
  delete answers.mode;
743
- if (field === 'builder')
791
+ if (field === 'builder') {
744
792
  delete answers.builder;
793
+ delete answers.builder_model;
794
+ }
795
+ if (field === 'planner_provider') {
796
+ delete answers.planner_provider;
797
+ delete answers.orchestrator_model;
798
+ }
745
799
  if (field === 'orchestrator_model')
746
800
  delete answers.orchestrator_model;
747
801
  if (field === 'builder_model')
@@ -818,6 +872,7 @@ function parseReviewAction(value) {
818
872
  const field = normalized.slice('edit:'.length).trim();
819
873
  if (field === 'mode' ||
820
874
  field === 'builder' ||
875
+ field === 'planner_provider' ||
821
876
  field === 'orchestrator_model' ||
822
877
  field === 'builder_model' ||
823
878
  field === 'reviewer' ||
@@ -902,6 +957,16 @@ async function ensureRepoRootCwd() {
902
957
  process.chdir(top);
903
958
  }
904
959
  }
960
+ async function ensureGitRepoInitialized() {
961
+ if (isGitRepo())
962
+ return;
963
+ const result = spawnSync('git', ['init'], { stdio: 'pipe' });
964
+ if (result.status !== 0) {
965
+ const error = result.stderr?.toString('utf-8').trim() || 'git init failed';
966
+ throw new Error(`Unable to initialize git repository: ${error}`);
967
+ }
968
+ console.log('Initialized git repository for Envoi onboarding.');
969
+ }
905
970
  async function resolveConfigPath(configPath) {
906
971
  if (configPath)
907
972
  return resolve(configPath);
@@ -1320,12 +1385,14 @@ function printRoadmapPreview(roadmap) {
1320
1385
  }
1321
1386
  async function runConnectivityChecks(config) {
1322
1387
  console.log('\nRole connectivity checks:');
1323
- const plannerCli = checkCommandVersion(config.claude_code_cli.command);
1388
+ const plannerProvider = (config.models.orchestrator_provider === 'chatgpt' ? 'chatgpt' : 'claude_code');
1389
+ const plannerCommand = plannerProvider === 'chatgpt' ? 'codex' : config.claude_code_cli.command;
1390
+ const plannerCli = checkCommandVersion(plannerCommand);
1324
1391
  if (plannerCli.available) {
1325
- console.log(`- planner: CLEARED (${config.claude_code_cli.command}${plannerCli.version ? ` ${plannerCli.version}` : ''})`);
1392
+ console.log(`- planner: CLEARED (${plannerCommand}${plannerCli.version ? ` ${plannerCli.version}` : ''})`);
1326
1393
  }
1327
1394
  else {
1328
- console.log(`- planner: BLOCKED (${config.claude_code_cli.command} not available)`);
1395
+ console.log(`- planner: BLOCKED (${plannerCommand} not available)`);
1329
1396
  }
1330
1397
  if (config.builder.default_mode === 'cursor') {
1331
1398
  const cursor = await checkCursorAgent(config);
@@ -1398,17 +1465,27 @@ async function maybeStartRun(config, mode, autoRun) {
1398
1465
  }
1399
1466
  export async function onboardCommand(options) {
1400
1467
  await ensureRepoRootCwd();
1468
+ await ensureGitRepoInitialized();
1401
1469
  await ensureInitialized(Boolean(options.forceInit));
1402
1470
  const configPath = await resolveConfigPath(options.configPath);
1403
1471
  const config = await loadConfig(configPath);
1404
1472
  const raw = await atomicReadJson(configPath);
1405
1473
  const nonInteractive = !input.isTTY;
1474
+ const inferredProviderFromModel = (model) => {
1475
+ if (!model)
1476
+ return undefined;
1477
+ return model.toLowerCase().startsWith('gpt-') ? 'chatgpt' : 'claude_code';
1478
+ };
1479
+ const existingProvider = normalizePlannerProvider(raw.models.orchestrator_provider)
1480
+ ?? inferredProviderFromModel(raw.models.orchestrator_model)
1481
+ ?? 'claude_code';
1406
1482
  const defaults = {
1407
- mode: raw.runner.default_loop_mode ?? 'milestone',
1408
- builder: raw.builder.default_mode === 'cursor' ? 'cursor' : 'claude_code',
1409
- orchestratorModel: raw.models.orchestrator_model || 'opus',
1410
- builderModel: raw.models.builder_model || 'sonnet',
1411
- reviewer: (raw.reviewer?.enabled ? 'codex' : 'none'),
1483
+ mode: 'milestone',
1484
+ builder: 'cursor',
1485
+ plannerProvider: existingProvider,
1486
+ orchestratorModel: resolvePlannerModel(existingProvider),
1487
+ builderModel: 'sonnet',
1488
+ reviewer: 'codex',
1412
1489
  reviewerModel: raw.reviewer?.model || 'gpt-5',
1413
1490
  };
1414
1491
  const incomingAnswers = await loadOnboardingAnswers({
@@ -1423,21 +1500,57 @@ export async function onboardCommand(options) {
1423
1500
  });
1424
1501
  const sessionPath = onboardingSessionPath(config.workspace_dir);
1425
1502
  const existingSession = nonInteractive ? await loadOnboardingSession(sessionPath) : null;
1503
+ const incomingSessionId = asNonEmptyString(incomingAnswers.__session_id);
1504
+ if (nonInteractive &&
1505
+ existingSession?.status === 'waiting_input' &&
1506
+ incomingSessionId &&
1507
+ incomingSessionId !== existingSession.session_id) {
1508
+ throw new Error(`Onboarding session mismatch: expected ${existingSession.session_id}, got ${incomingSessionId}. Resume with the expected session_id or restart with --reconfigure.`);
1509
+ }
1426
1510
  const persistedAnswers = nonInteractive && existingSession?.status === 'waiting_input'
1427
1511
  ? existingSession.answers
1428
1512
  : {};
1429
1513
  const answerBag = { ...persistedAnswers, ...incomingAnswers };
1514
+ const hasExplicitOnboardingInput = Boolean(options.answersJson ||
1515
+ options.answersFile ||
1516
+ options.prdFile ||
1517
+ options.mode ||
1518
+ options.builder ||
1519
+ options.plannerProvider ||
1520
+ options.reviewer ||
1521
+ options.orchestratorModel ||
1522
+ options.builderModel ||
1523
+ options.reviewerModel);
1524
+ if (nonInteractive &&
1525
+ !options.reconfigure &&
1526
+ existingSession?.status === 'completed' &&
1527
+ !hasExplicitOnboardingInput) {
1528
+ console.log(`${PRODUCT_NAME} onboarding already complete.`);
1529
+ const mode = raw.runner.default_loop_mode ?? defaults.mode;
1530
+ const autoRunRequested = options.autoRun ?? false;
1531
+ await maybeStartRun(raw, mode, autoRunRequested);
1532
+ return { needsInput: false };
1533
+ }
1430
1534
  const sessionId = asNonEmptyString(answerBag.__session_id) ??
1431
1535
  existingSession?.session_id ??
1432
1536
  randomUUID();
1433
1537
  let modeSeed = normalizeLoopMode(options.mode ?? asNonEmptyString(answerBag.mode));
1434
1538
  let builderSeed = normalizeBuilderChoice(options.builder ?? asNonEmptyString(answerBag.builder));
1539
+ let plannerProviderSeed = normalizePlannerProvider(options.plannerProvider ??
1540
+ asNonEmptyString(answerBag.planner_provider) ??
1541
+ inferredProviderFromModel(asNonEmptyString(answerBag.orchestrator_model)));
1435
1542
  let reviewerSeed = parseOptionalReviewerChoice(options.reviewer ?? asNonEmptyString(answerBag.reviewer));
1436
1543
  let orchestratorModelSeed = asNonEmptyString(options.orchestratorModel) ?? asNonEmptyString(answerBag.orchestrator_model);
1437
1544
  let builderModelSeed = asNonEmptyString(options.builderModel) ?? asNonEmptyString(answerBag.builder_model);
1438
1545
  let reviewerModelSeed = asNonEmptyString(options.reviewerModel) ?? asNonEmptyString(answerBag.reviewer_model);
1439
1546
  let prdTextSeed = asNonEmptyString(answerBag.prd_text);
1440
1547
  let nonInteractiveStartNow = false;
1548
+ if (!orchestratorModelSeed && plannerProviderSeed) {
1549
+ orchestratorModelSeed = resolvePlannerModel(plannerProviderSeed);
1550
+ }
1551
+ if (!plannerProviderSeed && orchestratorModelSeed) {
1552
+ plannerProviderSeed = inferredProviderFromModel(orchestratorModelSeed);
1553
+ }
1441
1554
  const intent = await promptStartIntentIfNeeded(Boolean(options.showTourPrompt));
1442
1555
  if (intent === 'tour') {
1443
1556
  printTour();
@@ -1453,6 +1566,7 @@ export async function onboardCommand(options) {
1453
1566
  const missingNonPrdQuestions = buildNonInteractiveQuestions({
1454
1567
  mode: modeSeed,
1455
1568
  builder: builderSeed,
1569
+ plannerProvider: plannerProviderSeed,
1456
1570
  orchestratorModel: orchestratorModelSeed,
1457
1571
  builderModel: builderModelSeed,
1458
1572
  reviewer: reviewerSeed,
@@ -1470,6 +1584,7 @@ export async function onboardCommand(options) {
1470
1584
  let pendingQuestions = buildNonInteractiveQuestions({
1471
1585
  mode: modeSeed,
1472
1586
  builder: builderSeed,
1587
+ plannerProvider: plannerProviderSeed,
1473
1588
  orchestratorModel: orchestratorModelSeed,
1474
1589
  builderModel: builderModelSeed,
1475
1590
  reviewer: reviewerSeed,
@@ -1494,6 +1609,7 @@ export async function onboardCommand(options) {
1494
1609
  const reviewQuestion = buildReviewQuestion({
1495
1610
  mode: modeSeed,
1496
1611
  builder: builderSeed,
1612
+ plannerProvider: plannerProviderSeed,
1497
1613
  orchestratorModel: orchestratorModelSeed,
1498
1614
  builderModel: builderModelSeed,
1499
1615
  reviewer: reviewerSeed,
@@ -1516,11 +1632,20 @@ export async function onboardCommand(options) {
1516
1632
  delete answerBag.__review_action;
1517
1633
  modeSeed = normalizeLoopMode(options.mode ?? asNonEmptyString(answerBag.mode));
1518
1634
  builderSeed = normalizeBuilderChoice(options.builder ?? asNonEmptyString(answerBag.builder));
1635
+ plannerProviderSeed = normalizePlannerProvider(options.plannerProvider ??
1636
+ asNonEmptyString(answerBag.planner_provider) ??
1637
+ inferredProviderFromModel(asNonEmptyString(answerBag.orchestrator_model)));
1519
1638
  reviewerSeed = parseOptionalReviewerChoice(options.reviewer ?? asNonEmptyString(answerBag.reviewer));
1520
1639
  orchestratorModelSeed = asNonEmptyString(options.orchestratorModel) ?? asNonEmptyString(answerBag.orchestrator_model);
1521
1640
  builderModelSeed = asNonEmptyString(options.builderModel) ?? asNonEmptyString(answerBag.builder_model);
1522
1641
  reviewerModelSeed = asNonEmptyString(options.reviewerModel) ?? asNonEmptyString(answerBag.reviewer_model);
1523
1642
  prdTextSeed = asNonEmptyString(answerBag.prd_text);
1643
+ if (!orchestratorModelSeed && plannerProviderSeed) {
1644
+ orchestratorModelSeed = resolvePlannerModel(plannerProviderSeed);
1645
+ }
1646
+ if (!plannerProviderSeed && orchestratorModelSeed) {
1647
+ plannerProviderSeed = inferredProviderFromModel(orchestratorModelSeed);
1648
+ }
1524
1649
  prdCapture = {
1525
1650
  text: prdTextSeed ?? '',
1526
1651
  source: isNonEmptyContent(prdTextSeed ?? '') ? 'paste' : 'skip',
@@ -1528,6 +1653,7 @@ export async function onboardCommand(options) {
1528
1653
  pendingQuestions = buildNonInteractiveQuestions({
1529
1654
  mode: modeSeed,
1530
1655
  builder: builderSeed,
1656
+ plannerProvider: plannerProviderSeed,
1531
1657
  orchestratorModel: orchestratorModelSeed,
1532
1658
  builderModel: builderModelSeed,
1533
1659
  reviewer: reviewerSeed,
@@ -1550,6 +1676,7 @@ export async function onboardCommand(options) {
1550
1676
  const reviewQuestion = buildReviewQuestion({
1551
1677
  mode: modeSeed,
1552
1678
  builder: builderSeed,
1679
+ plannerProvider: plannerProviderSeed,
1553
1680
  orchestratorModel: orchestratorModelSeed,
1554
1681
  builderModel: builderModelSeed,
1555
1682
  reviewer: reviewerSeed,
@@ -1586,29 +1713,28 @@ export async function onboardCommand(options) {
1586
1713
  (input.isTTY
1587
1714
  ? (await promptChoice('Which builder should implement code changes?', BUILDER_CHOICES, defaults.builder))
1588
1715
  : defaults.builder);
1589
- // 4) Role model defaults (kept inside currently supported model set)
1590
- const orchestratorModel = orchestratorModelSeed ??
1716
+ // 4) Planner provider and model defaults
1717
+ const plannerProvider = plannerProviderSeed ??
1591
1718
  (input.isTTY
1592
- ? await promptChoice('Planner model?', [
1593
- { value: 'opus', label: 'opus (recommended)', desc: 'Best planning quality.' },
1594
- { value: 'sonnet', label: 'sonnet', desc: 'Balanced speed/cost.' },
1595
- { value: 'haiku', label: 'haiku', desc: 'Fastest/lowest cost.' },
1596
- ], defaults.orchestratorModel)
1597
- : defaults.orchestratorModel);
1598
- const builderModel = builderModelSeed ??
1599
- (builderChoice === 'claude_code'
1600
- ? (input.isTTY
1719
+ ? (await promptChoice('Planner provider?', PLANNER_PROVIDER_CHOICES, defaults.plannerProvider))
1720
+ : defaults.plannerProvider);
1721
+ const orchestratorModel = resolvePlannerModel(plannerProvider);
1722
+ const builderModel = builderChoice === 'claude_code'
1723
+ ? (builderModelSeed ??
1724
+ (input.isTTY
1601
1725
  ? await promptChoice('Builder model?', [
1602
1726
  { value: 'sonnet', label: 'sonnet (recommended)', desc: 'Strong coding throughput.' },
1603
- { value: 'opus', label: 'opus', desc: 'Higher quality, higher cost.' },
1604
1727
  { value: 'haiku', label: 'haiku', desc: 'Lower cost for simpler edits.' },
1605
1728
  ], defaults.builderModel)
1606
- : defaults.builderModel)
1607
- : defaults.builderModel);
1729
+ : defaults.builderModel))
1730
+ : defaults.builderModel;
1608
1731
  raw.models = {
1609
1732
  ...raw.models,
1733
+ orchestrator_provider: plannerProvider,
1610
1734
  orchestrator_model: orchestratorModel,
1611
- orchestrator_fallback_model: raw.models.orchestrator_fallback_model || 'sonnet',
1735
+ orchestrator_fallback_model: plannerProvider === 'chatgpt'
1736
+ ? (raw.models.orchestrator_fallback_model || CHATGPT_PLANNER_MODEL)
1737
+ : (raw.models.orchestrator_fallback_model || 'sonnet'),
1612
1738
  builder_model: builderModel,
1613
1739
  builder_fallback_model: raw.models.builder_fallback_model || 'haiku',
1614
1740
  };
@@ -1635,8 +1761,8 @@ export async function onboardCommand(options) {
1635
1761
  ? reviewerSeed
1636
1762
  : (input.isTTY
1637
1763
  ? normalizeReviewerChoice(await promptChoice('Optional reviewer?', [
1638
- { value: 'none', label: 'No reviewer (recommended to start)', desc: 'Less friction, fastest onboarding.' },
1639
- { value: 'codex', label: 'Use Codex reviewer', desc: 'Adds second-pass checks for risky changes.' },
1764
+ { value: 'codex', label: 'Use Codex reviewer (recommended)', desc: 'Adds second-pass checks for risky changes.' },
1765
+ { value: 'none', label: 'No reviewer', desc: 'Less friction, fastest onboarding.' },
1640
1766
  ], defaults.reviewer))
1641
1767
  : defaults.reviewer);
1642
1768
  if (reviewerChoice === 'codex') {
@@ -1684,6 +1810,7 @@ export async function onboardCommand(options) {
1684
1810
  console.log(`- PRD source: ${prdCapture.source}`);
1685
1811
  console.log(`- Default mode: ${mode}`);
1686
1812
  console.log(`- Builder: ${builderChoice}`);
1813
+ console.log(`- Planner: ${plannerProvider} (${orchestratorModel})`);
1687
1814
  console.log(`- Reviewer: ${raw.reviewer?.enabled ? 'enabled' : 'disabled'}`);
1688
1815
  await runConnectivityChecks(raw);
1689
1816
  const roadmapPath = join(dirname(configPath), 'ROADMAP.json');