gaunt-sloth 2.0.0-alpha.2 → 2.0.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/README.md +55 -5
  2. package/cli.js +43 -10
  3. package/dist/cli.js +33 -2
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/adkEvalRunner.d.ts +66 -0
  6. package/dist/commands/adkEvalRunner.js +69 -0
  7. package/dist/commands/adkEvalRunner.js.map +1 -0
  8. package/dist/commands/agUiEvalRunner.d.ts +73 -0
  9. package/dist/commands/agUiEvalRunner.js +216 -0
  10. package/dist/commands/agUiEvalRunner.js.map +1 -0
  11. package/dist/commands/askCommand.d.ts +3 -2
  12. package/dist/commands/askCommand.js +26 -7
  13. package/dist/commands/askCommand.js.map +1 -1
  14. package/dist/commands/batchCommand.d.ts +78 -0
  15. package/dist/commands/batchCommand.js +245 -0
  16. package/dist/commands/batchCommand.js.map +1 -0
  17. package/dist/commands/cliOptionParsers.d.ts +12 -0
  18. package/dist/commands/cliOptionParsers.js +18 -0
  19. package/dist/commands/cliOptionParsers.js.map +1 -0
  20. package/dist/commands/commandIntrospection.d.ts +6 -6
  21. package/dist/commands/commandIntrospection.js +12 -12
  22. package/dist/commands/commandIntrospection.js.map +1 -1
  23. package/dist/commands/commandUtils.d.ts +16 -16
  24. package/dist/commands/commandUtils.js +20 -20
  25. package/dist/commands/commandUtils.js.map +1 -1
  26. package/dist/commands/configCommand.d.ts +24 -0
  27. package/dist/commands/configCommand.js +117 -0
  28. package/dist/commands/configCommand.js.map +1 -0
  29. package/dist/commands/configSetup.d.ts +1 -1
  30. package/dist/commands/configSetup.js +17 -2
  31. package/dist/commands/configSetup.js.map +1 -1
  32. package/dist/commands/evalCommand.d.ts +41 -0
  33. package/dist/commands/evalCommand.js +483 -0
  34. package/dist/commands/evalCommand.js.map +1 -0
  35. package/dist/commands/execCommand.js +4 -1
  36. package/dist/commands/execCommand.js.map +1 -1
  37. package/dist/commands/firstRunDialog.d.ts +39 -5
  38. package/dist/commands/firstRunDialog.js +72 -10
  39. package/dist/commands/firstRunDialog.js.map +1 -1
  40. package/dist/commands/getCommand.js +7 -7
  41. package/dist/commands/getCommand.js.map +1 -1
  42. package/dist/commands/historyCommand.d.ts +17 -0
  43. package/dist/commands/historyCommand.js +102 -0
  44. package/dist/commands/historyCommand.js.map +1 -0
  45. package/dist/commands/initCommand.d.ts +3 -0
  46. package/dist/commands/initCommand.js +9 -4
  47. package/dist/commands/initCommand.js.map +1 -1
  48. package/dist/commands/insightsCommand.d.ts +8 -0
  49. package/dist/commands/insightsCommand.js +32 -0
  50. package/dist/commands/insightsCommand.js.map +1 -0
  51. package/dist/commands/modelsCommand.d.ts +25 -0
  52. package/dist/commands/modelsCommand.js +96 -0
  53. package/dist/commands/modelsCommand.js.map +1 -0
  54. package/dist/commands/prCommand.js +14 -15
  55. package/dist/commands/prCommand.js.map +1 -1
  56. package/dist/commands/prDiscovery.d.ts +2 -2
  57. package/dist/commands/prDiscovery.js +27 -29
  58. package/dist/commands/prDiscovery.js.map +1 -1
  59. package/dist/commands/reviewCommand.js +15 -10
  60. package/dist/commands/reviewCommand.js.map +1 -1
  61. package/dist/commands/workflowCommand.d.ts +19 -0
  62. package/dist/commands/workflowCommand.js +77 -0
  63. package/dist/commands/workflowCommand.js.map +1 -0
  64. package/dist/helpers/jira/jiraLogWork.js.map +1 -1
  65. package/dist/modules/startSession.js +9 -7
  66. package/dist/modules/startSession.js.map +1 -1
  67. package/dist/tools/gthJiraLogWorkTool.js +3 -3
  68. package/dist/tools/gthJiraLogWorkTool.js.map +1 -1
  69. package/dist/tui/components/App.js +321 -21
  70. package/dist/tui/components/App.js.map +1 -1
  71. package/dist/tui/components/ApprovalPrompt.d.ts +18 -0
  72. package/dist/tui/components/ApprovalPrompt.js +26 -0
  73. package/dist/tui/components/ApprovalPrompt.js.map +1 -0
  74. package/dist/tui/components/DebugPanel.d.ts +29 -9
  75. package/dist/tui/components/DebugPanel.js +46 -23
  76. package/dist/tui/components/DebugPanel.js.map +1 -1
  77. package/dist/tui/components/FetchProgress.d.ts +36 -0
  78. package/dist/tui/components/FetchProgress.js +39 -0
  79. package/dist/tui/components/FetchProgress.js.map +1 -0
  80. package/dist/tui/components/LiveTurn.d.ts +26 -4
  81. package/dist/tui/components/LiveTurn.js +104 -18
  82. package/dist/tui/components/LiveTurn.js.map +1 -1
  83. package/dist/tui/components/NoticeBar.d.ts +32 -0
  84. package/dist/tui/components/NoticeBar.js +39 -0
  85. package/dist/tui/components/NoticeBar.js.map +1 -0
  86. package/dist/tui/components/PromptInput.d.ts +26 -1
  87. package/dist/tui/components/PromptInput.js +93 -7
  88. package/dist/tui/components/PromptInput.js.map +1 -1
  89. package/dist/tui/components/Rule.js.map +1 -1
  90. package/dist/tui/components/SelectList.d.ts +98 -9
  91. package/dist/tui/components/SelectList.js +209 -26
  92. package/dist/tui/components/SelectList.js.map +1 -1
  93. package/dist/tui/components/SlashCommandMenu.d.ts +20 -0
  94. package/dist/tui/components/SlashCommandMenu.js +28 -0
  95. package/dist/tui/components/SlashCommandMenu.js.map +1 -0
  96. package/dist/tui/components/StatusBar.d.ts +7 -1
  97. package/dist/tui/components/StatusBar.js +7 -3
  98. package/dist/tui/components/StatusBar.js.map +1 -1
  99. package/dist/tui/components/Transcript.js +6 -1
  100. package/dist/tui/components/Transcript.js.map +1 -1
  101. package/dist/tui/debugRender.d.ts +41 -6
  102. package/dist/tui/debugRender.js +126 -12
  103. package/dist/tui/debugRender.js.map +1 -1
  104. package/dist/tui/debugSearch.d.ts +40 -0
  105. package/dist/tui/debugSearch.js +73 -0
  106. package/dist/tui/debugSearch.js.map +1 -0
  107. package/dist/tui/markdown.js +0 -0
  108. package/dist/tui/markdown.js.map +1 -1
  109. package/dist/tui/pasteParser.d.ts +21 -0
  110. package/dist/tui/pasteParser.js +24 -0
  111. package/dist/tui/pasteParser.js.map +1 -0
  112. package/dist/tui/selectCancelled.d.ts +13 -0
  113. package/dist/tui/selectCancelled.js +17 -0
  114. package/dist/tui/selectCancelled.js.map +1 -0
  115. package/dist/tui/slashCommands.d.ts +220 -1
  116. package/dist/tui/slashCommands.js +408 -1
  117. package/dist/tui/slashCommands.js.map +1 -1
  118. package/dist/tui/tuiSessionModule.js +249 -24
  119. package/dist/tui/tuiSessionModule.js.map +1 -1
  120. package/dist/tui/types.d.ts +96 -7
  121. package/dist/tui/viewModel.d.ts +34 -0
  122. package/dist/tui/viewModel.js +67 -0
  123. package/dist/tui/viewModel.js.map +1 -1
  124. package/dist/utils/stdinPolicy.d.ts +31 -0
  125. package/dist/utils/stdinPolicy.js +37 -0
  126. package/dist/utils/stdinPolicy.js.map +1 -0
  127. package/package.json +21 -17
@@ -0,0 +1,483 @@
1
+ import { readdirSync, statSync } from 'node:fs';
2
+ import { basename, extname, join, resolve } from 'node:path';
3
+ import { initConfig, resolveIdentityProfileConfigPath, } from '@gaunt-sloth/core/config.js';
4
+ import { getAskSystemPrompt } from '#src/commands/commandIntrospection.js';
5
+ import { buildProductionRunCell, buildProductionRunConversation, } from '#src/commands/batchCommand.js';
6
+ import { parseIntOption } from '#src/commands/cliOptionParsers.js';
7
+ import { displayError, displaySuccess, displayWarning, } from '@gaunt-sloth/core/utils/consoleUtils.js';
8
+ import { getProjectDir, setExitCode } from '@gaunt-sloth/core/utils/systemUtils.js';
9
+ import { fileSafeLocalDate, getGslothFilePath, importExternalFile, readFileFromProjectDir, } from '@gaunt-sloth/core/utils/fileUtils.js';
10
+ /** Split each collected `--reporter` value on `,`, flatten, trim, drop blanks, and de-duplicate
11
+ * (order-preserving), so `-r junit,text` and `-r junit -r text` both yield `['junit','text']`. */
12
+ export function normalizeReporterNames(collected) {
13
+ const seen = new Set();
14
+ const out = [];
15
+ for (const raw of collected) {
16
+ for (const name of raw.split(',').map((n) => n.trim())) {
17
+ if (name && !seen.has(name)) {
18
+ seen.add(name);
19
+ out.push(name);
20
+ }
21
+ }
22
+ }
23
+ return out;
24
+ }
25
+ /**
26
+ * Build the `custom` reporter-factory map handed to `resolveReporters`. It always registers the
27
+ * BUNDLED JUnit reporter through the SAME public `custom` seam a user reporter uses (the point: it
28
+ * proves the plug-in contract from an out-of-core package), then overlays any config-declared
29
+ * reporters. A config reporter may reuse a built-in/bundled name — config wins on a collision, so it
30
+ * is added last.
31
+ *
32
+ * A config reporter's module path is resolved relative to the PROJECT dir (the same base
33
+ * `readFileFromProjectDir` uses) and imported via {@link importExternalFile} (which turns it into a
34
+ * `file://` URL and supports `.ts` through jiti). Its DEFAULT export must be an `EvalReporterFactory`
35
+ * (`() => EvalReporter`); a missing file, a failed import, or a non-function default export THROWS —
36
+ * caught by the command's outer try/catch → exit 2 (harness error). It is the user's own trusted
37
+ * config (already arbitrary JS), so nothing is sandboxed.
38
+ */
39
+ async function buildCustomReporterFactories(config) {
40
+ const custom = {};
41
+ const { createJUnitReporter, JUNIT_REPORTER_NAME } = await import('@gaunt-sloth/eval-reporter-junit/index.js');
42
+ custom[JUNIT_REPORTER_NAME] = createJUnitReporter;
43
+ for (const [name, modulePath] of Object.entries(config.reporters ?? {})) {
44
+ const absPath = resolve(getProjectDir(), modulePath);
45
+ let mod;
46
+ try {
47
+ mod = await importExternalFile(absPath);
48
+ }
49
+ catch (error) {
50
+ throw new Error(`failed to load config reporter "${name}" from "${modulePath}" (${absPath}): ` +
51
+ (error instanceof Error ? error.message : String(error)));
52
+ }
53
+ const factory = mod.default;
54
+ if (typeof factory !== 'function') {
55
+ throw new Error(`config reporter "${name}" (${modulePath}) must export a default function ` +
56
+ `(an EvalReporterFactory: () => EvalReporter); got ${typeof factory}.`);
57
+ }
58
+ custom[name] = factory;
59
+ }
60
+ return custom;
61
+ }
62
+ /** Default output dir when `-o/--output` is omitted: a timestamped dir next to other gth reports —
63
+ * same convention as `defaultBatchOutputDir` in `batchCommand.ts`, `_EVAL` suffix instead. */
64
+ export function defaultEvalOutputDir() {
65
+ return getGslothFilePath(`gth_${fileSafeLocalDate()}_EVAL`);
66
+ }
67
+ /** `basename(path)` with its extension removed — the per-suite output subdir name and the JUnit
68
+ * `<testsuites>` name. `eval/authz-matrix.yaml` → `authz-matrix`. */
69
+ function suiteStem(path) {
70
+ const base = basename(path);
71
+ const ext = extname(base);
72
+ return ext ? base.slice(0, -ext.length) : base;
73
+ }
74
+ /**
75
+ * Deterministically resolve the CLI `<suites...>` args into the ordered list of suites to run
76
+ * (BATCH-19 Task B, Deliverable 1):
77
+ * - A **file** (or a path that doesn't exist on disk — its read is deferred so a missing suite
78
+ * surfaces as that suite's own harness error, keeping the single-suite behavior byte-for-byte) →
79
+ * that one suite, read by the exact CLI string given.
80
+ * - A **directory** → its **direct-child** `*.yaml`/`*.yml` files only (NON-recursive), sorted
81
+ * lexicographically. An empty / no-match directory yields no suites and one harness `error` (the
82
+ * caller folds it into the aggregate exit → 2) instead of throwing, so any GOOD sibling inputs
83
+ * still run.
84
+ *
85
+ * The given arg order is preserved and each directory is expanded in place; suites are
86
+ * de-duplicated by **resolved absolute path** (the same file named twice, directly or via a
87
+ * directory, runs once).
88
+ */
89
+ function resolveEvalSuiteInputs(inputs) {
90
+ const projectDir = getProjectDir();
91
+ const suites = [];
92
+ const errors = [];
93
+ const seen = new Set();
94
+ const push = (readPath, absPath) => {
95
+ if (seen.has(absPath))
96
+ return;
97
+ seen.add(absPath);
98
+ suites.push({ readPath, absPath });
99
+ };
100
+ for (const input of inputs) {
101
+ const abs = resolve(projectDir, input);
102
+ let isDirectory = false;
103
+ try {
104
+ isDirectory = statSync(abs).isDirectory();
105
+ }
106
+ catch {
107
+ // Non-existent path: treat as a file suite and let its read fail as that suite's own harness
108
+ // error (single-suite behavior preserved; a real file mock/read is keyed on the CLI string).
109
+ isDirectory = false;
110
+ }
111
+ if (!isDirectory) {
112
+ push(input, abs);
113
+ continue;
114
+ }
115
+ const yamlChildren = readdirSync(abs)
116
+ .filter((name) => {
117
+ const ext = extname(name).toLowerCase();
118
+ return ext === '.yaml' || ext === '.yml';
119
+ })
120
+ .sort();
121
+ if (yamlChildren.length === 0) {
122
+ errors.push(`eval suite directory "${input}" contains no .yaml/.yml files`);
123
+ continue;
124
+ }
125
+ for (const name of yamlChildren) {
126
+ const childAbs = resolve(abs, name);
127
+ push(childAbs, childAbs);
128
+ }
129
+ }
130
+ return { suites, errors };
131
+ }
132
+ /**
133
+ * Build the production {@link JudgeFn}: grades one case's answer with `judgeEvalCase` against
134
+ * `config.llm`. The caller chooses *which* config this is (BATCH-10 Task 2): by default it's the
135
+ * SUT's own config (judge shares the SUT model, the original behavior), but when a judge identity
136
+ * profile is resolved (`--judge <profile>` or the suite's `judge_profile`) the action passes a
137
+ * *separate* `initConfig({ …, identityProfile })` here, so the judge runs under its own model — a
138
+ * different model can catch blind spots the SUT model shares. This function stays agnostic to that
139
+ * choice; it just grades against whatever `config.llm` it's handed.
140
+ */
141
+ function buildProductionJudge(config) {
142
+ return async (answer, rubric) => {
143
+ const { judgeEvalCase } = await import('@gaunt-sloth/batch/judge.js');
144
+ return judgeEvalCase(answer, rubric, config.llm);
145
+ };
146
+ }
147
+ /**
148
+ * Pure resolver for the judge identity profile — kept small and side-effect-free so it's unit
149
+ * testable in isolation. Precedence (highest first): CLI `--judge <profile>` > suite-level
150
+ * `judge_profile` > none. A blank/whitespace-only value at either level counts as absent (falls
151
+ * through to the next level). `undefined` means "no separate judge — grade with the SUT's config".
152
+ */
153
+ export function resolveJudgeProfile(cliJudge, suiteJudgeProfile) {
154
+ const cli = cliJudge?.trim();
155
+ if (cli)
156
+ return cli;
157
+ const suite = suiteJudgeProfile?.trim();
158
+ if (suite)
159
+ return suite;
160
+ return undefined;
161
+ }
162
+ /** Best-effort model name for the self-describing judge line. `BaseChatModel` doesn't standardize a
163
+ * public model-name field, so read `model` then `modelName`; return `undefined` if neither is a
164
+ * usable string (the profile name alone still describes the run). */
165
+ function judgeModelName(config) {
166
+ const llm = config.llm;
167
+ const name = typeof llm.model === 'string' ? llm.model : llm.modelName;
168
+ return typeof name === 'string' && name.length > 0 ? name : undefined;
169
+ }
170
+ /**
171
+ * Adds the `eval` command to the program.
172
+ *
173
+ * `gth eval <suite.yaml> [-j 8] [-o out/]` — grades a suite of cases (deterministic checks and/or
174
+ * an LLM judge) against the SUT agent, the way `review` grades a diff. See
175
+ * docs/batch-eval-cli-surface.md and docs/batch-eval-user-requirements.md for the design; this
176
+ * command implements the single-`prompt`, `gth-agent`-target, `config.llm`-as-judge subset — see
177
+ * the BATCH-2 Task 2 brief's "Not in scope" list for what's deliberately deferred.
178
+ *
179
+ * Exit-code contract (BATCH-11 / #405 his #6 — a distinct three-way code so CI can tell a product
180
+ * regression from a broken harness):
181
+ * - `0` — every case passed (mirrors `review`; unchanged contract).
182
+ * - `1` — the suite **ran** but ≥1 case FAILED (a deterministic check or the judge fell below
183
+ * threshold). A *product* signal: real, gradeable results, some below the bar.
184
+ * - `2` — **harness error**: the suite couldn't be meaningfully evaluated — the suite file failed
185
+ * to load/parse, config failed to build, or **every** case's SUT run failed (`sutOk:false`, e.g.
186
+ * a transport/auth/config failure produced no answer to grade). An *environment* signal.
187
+ *
188
+ * The suite-vs-harness split is anchored on `sutOk` (see `classifyEvalExit`), not the verdict: a
189
+ * case that ran (`sutOk:true`) but whose judge errored, or whose answer failed a check, is still a
190
+ * real result → exit `1`, never `2`. Unlike `batch`, which exits 0 regardless of per-cell quality.
191
+ *
192
+ * @param program - The commander program
193
+ * @param commandLineConfigOverrides - command line config overrides
194
+ */
195
+ export function evalCommand(program, commandLineConfigOverrides) {
196
+ program
197
+ .command('eval')
198
+ .description('Grade a suite of cases against the SUT agent with deterministic checks and/or an LLM ' +
199
+ 'judge ("pytest for prompts"). Exit code: 0 = all cases passed, 1 = a case failed, ' +
200
+ '2 = harness error (bad suite/config, or the SUT could not run).')
201
+ .argument('<suites...>', 'Eval suite YAML file(s) or directory(ies). A directory runs its direct-child *.yaml/*.yml ' +
202
+ 'suites (non-recursive, sorted). Multiple suites report ONE aggregate exit code; each ' +
203
+ 'writes into its own <output>/<suite-name>/ subdir (a single suite writes into <output> directly).')
204
+ .option('-j, --concurrency <n>', 'Max in-flight cases', parseIntOption)
205
+ .option('-o, --output <dir>', 'Directory to write structured per-case JSON + results.json summary to ' +
206
+ '(default: a timestamped dir alongside other gth reports)')
207
+ .option('--judge <profile>', 'Identity profile whose model judges the cases (defaults to the SUT model). ' +
208
+ 'Overrides the suite-level judge_profile.')
209
+ .option('-r, --reporter <names>', 'Reporter(s) to render the run through (repeatable; comma-separated). Built-in: "text" ' +
210
+ '(default), "junit" (writes results.xml). REPLACES the default, so "--reporter junit" is ' +
211
+ 'JUnit only. The always-on results.json + per-cell JSON are written regardless.', (value, previous = []) => [...previous, value])
212
+ .addHelpText('after', '\n' +
213
+ 'Reporters:\n' +
214
+ ' text (default) a human-readable PASS/FAIL summary on the console\n' +
215
+ ' junit an Ant-JUnit results.xml (for TeamCity / CI JUnit readers)\n' +
216
+ ' Custom reporters are declared in config under `reporters: { <name>: <module path> }`.\n' +
217
+ ' --reporter REPLACES the default set (it does not add to it); pass every reporter you\n' +
218
+ ' want, e.g. `--reporter text,junit`. results.json is always written, regardless.\n' +
219
+ '\n' +
220
+ 'Examples:\n' +
221
+ ' $ gsloth eval eval/js-basics.yaml\n' +
222
+ ' $ gsloth eval eval/js-basics.yaml --judge strict-judge\n' +
223
+ ' $ gsloth eval eval/authz-matrix.yaml -j 8 -o eval/out/authz\n' +
224
+ ' $ gsloth eval eval/js-basics.yaml eval/authz-matrix.yaml # many suites, one exit\n' +
225
+ ' $ gsloth eval eval/ -o eval/out --reporter junit # a whole directory\n' +
226
+ ' $ gsloth eval eval/js-basics.yaml --reporter junit\n' +
227
+ ' $ gsloth eval eval/js-basics.yaml --reporter text,junit\n')
228
+ .action(async (suitePaths, options) => {
229
+ try {
230
+ // Specific `.js` subpaths (not the bare package root), matching batchCommand.ts's
231
+ // convention — vitest's workspace-import resolver recognizes these and resolves straight to
232
+ // source, so specs exercise live `packages/batch/src` rather than a `dist/` build.
233
+ const { parseEvalSuite } = await import('@gaunt-sloth/batch/evalSuite.js');
234
+ const { runEvalSuite, classifyEvalExit } = await import('@gaunt-sloth/batch/evalRunner.js');
235
+ const { writeEvalOutput } = await import('@gaunt-sloth/batch/evalOutput.js');
236
+ const { resolveReporters } = await import('@gaunt-sloth/batch/reporters/registry.js');
237
+ const { driveReporters } = await import('@gaunt-sloth/batch/reporters/drive.js');
238
+ // The reporter selection (`--reporter`, else the default `['text']`) and the output ROOT are
239
+ // invocation-level — the same for every suite. REPLACES the default: the `--reporter` value
240
+ // when given, else `['text']`.
241
+ const reporterNames = options.reporter
242
+ ? normalizeReporterNames(options.reporter)
243
+ : ['text'];
244
+ const outputRoot = options.output ?? defaultEvalOutputDir();
245
+ // BATCH-19 Task B: run ONE whole suite — parse, precondition-check its identities, build its
246
+ // configs/reporters, run, write its structured output, and drive its reporters — RETURNING
247
+ // its summary. THROWS on this suite's own harness error (parse/config/reporter/precondition
248
+ // failure), which the caller catches per suite so one bad suite never aborts the good ones.
249
+ //
250
+ // Task B, Deliverable 2 — the `-i` papercut: a MATRIX suite (declares `identities:`) must run
251
+ // with NO base `-i`. The per-identity configs come from the suite's `identities:` list (each
252
+ // pre-validated by the precondition below), so the base config used for reporters + the
253
+ // default judge is the FIRST identity's already-built config — the matrix path NEVER calls
254
+ // `initConfig` without an `identityProfile`. That is the fix: the old top-level
255
+ // `initConfig(overrides)` demanded a resolvable base config (a matrix-only project has none),
256
+ // and its terminal `exit(1)` is uncatchable, so it can't be reached at all on this path. The
257
+ // NON-matrix path is unchanged — the base config is still `initConfig(overrides)`. (Configs
258
+ // are built per suite, not cached across suites — a documented non-goal.)
259
+ const runOneSuite = async (suite, suiteOutputDir) => {
260
+ const suiteText = readFileFromProjectDir(suite.readPath);
261
+ const parsedSuite = parseEvalSuite(suiteText, suite.readPath);
262
+ // BATCH-12 PRECONDITION — trustworthy loads (no false-green): every suite-declared identity
263
+ // must resolve to its OWN config (`.gsloth-settings/<name>/`), not the global/plain
264
+ // fallback. Verify ALL of them with GS2-62's PURE, catchable helper BEFORE building any
265
+ // per-identity config, because handing a bad profile to `initConfig({ …, identityProfile })`
266
+ // would hit its uncatchable `exit(1)` and collapse the harness-vs-product (2-vs-1) exit-code
267
+ // distinction. A silent wrong-identity run is the worst failure for an auth matrix — so an
268
+ // unresolved identity throws here → per-suite catch → exit 2, and NOTHING runs.
269
+ const suiteIdentities = parsedSuite.identities ?? [];
270
+ const unresolvedIdentities = suiteIdentities.filter((identity) => !resolveIdentityProfileConfigPath(identity));
271
+ if (unresolvedIdentities.length > 0) {
272
+ throw new Error(`identity profile(s) not found: ${unresolvedIdentities.join(', ')} — each suite ` +
273
+ '`identities` entry must have its own config file in ' +
274
+ '.gsloth/.gsloth-settings/<name>/. No cases were run.');
275
+ }
276
+ const runCellOptions = {
277
+ command: 'ask',
278
+ sourcePrefix: 'EVAL',
279
+ wrapBlockPrefix: 'message',
280
+ wrapPrefix: 'user message',
281
+ };
282
+ // Build the SUT run function(s), selected by `target.type`, AND resolve the base config
283
+ // used for the reporters + the default (SUT-model) judge. The eval runner is
284
+ // target-agnostic — it just consumes an injected single-turn `runCell` and multi-turn
285
+ // `runConversation` — so the target only changes which builders produce them.
286
+ let runCell;
287
+ let runConversation;
288
+ let runCellByIdentity;
289
+ let runConversationByIdentity;
290
+ let baseConfig;
291
+ if (suiteIdentities.length > 0 && parsedSuite.target.type === 'gth-agent') {
292
+ // MATRIX (gth-agent): one runCell per identity, each from a fresh
293
+ // `initConfig({ …, identityProfile })` (mirrors `gth batch --models`' per-model
294
+ // construction — a genuinely fresh `.llm`, never a structural clone), built ONCE per
295
+ // identity and reused across cases by the runner. An identity profile's manual
296
+ // `mcpServers.<n>.headers.Authorization` (CFG-4) flows through as-is. The base config for
297
+ // reporters + the default judge is the FIRST identity's config (reused, not rebuilt) — so
298
+ // this path makes NO `initConfig` call without an `identityProfile` (Deliverable 2).
299
+ runCellByIdentity = new Map();
300
+ runConversationByIdentity = new Map();
301
+ let firstIdentityConfig;
302
+ for (const identity of suiteIdentities) {
303
+ const identityConfig = await initConfig({
304
+ ...commandLineConfigOverrides,
305
+ identityProfile: identity,
306
+ });
307
+ if (!firstIdentityConfig)
308
+ firstIdentityConfig = identityConfig;
309
+ const identityPreamble = getAskSystemPrompt(identityConfig);
310
+ runCellByIdentity.set(identity, await buildProductionRunCell(identityConfig, identityPreamble, commandLineConfigOverrides, runCellOptions));
311
+ runConversationByIdentity.set(identity, await buildProductionRunConversation(identityConfig, identityPreamble, runCellOptions));
312
+ }
313
+ // `firstIdentityConfig` is always set here (suiteIdentities is non-empty).
314
+ baseConfig = firstIdentityConfig;
315
+ }
316
+ else if (parsedSuite.target.type === 'adk-agent') {
317
+ // BATCH-14: drive an EXTERNAL Google ADK agent over A2A. The agent runs out-of-process
318
+ // (its own model/tools/auth), so there is no per-identity gth config — the `identities`
319
+ // matrix is rejected for this target at parse time, leaving only the single-run path. The
320
+ // judge still grades via the local gth config, so build it from `initConfig(overrides)`.
321
+ baseConfig = await initConfig(commandLineConfigOverrides);
322
+ const { buildAdkRunCell, buildAdkRunConversation } = await import('#src/commands/adkEvalRunner.js');
323
+ runCell = buildAdkRunCell(parsedSuite.target);
324
+ runConversation = buildAdkRunConversation(parsedSuite.target);
325
+ }
326
+ else if (parsedSuite.target.type === 'ag-ui') {
327
+ // BATCH-15: drive an EXTERNAL AG-UI agent over HTTP/SSE. Like the ADK target, the agent
328
+ // runs out-of-process (its own model/tools/auth), so there is no per-identity gth config —
329
+ // the `identities` matrix is rejected for this target at parse time. Unlike ADK, the AG-UI
330
+ // wire streams tool calls, so the runner captures them and `must_call`/`must_not_call`
331
+ // grade normally. The judge still grades via the local gth `initConfig(overrides)` config.
332
+ baseConfig = await initConfig(commandLineConfigOverrides);
333
+ const { buildAgUiRunCell, buildAgUiRunConversation } = await import('#src/commands/agUiEvalRunner.js');
334
+ runCell = buildAgUiRunCell(parsedSuite.target);
335
+ runConversation = buildAgUiRunConversation(parsedSuite.target);
336
+ }
337
+ else {
338
+ // gth-agent, NO identities (unchanged): one runCell/runConversation under the invoked
339
+ // profile, from the single `initConfig(overrides)` base config (byte-for-byte as before).
340
+ baseConfig = await initConfig(commandLineConfigOverrides);
341
+ const preamble = getAskSystemPrompt(baseConfig);
342
+ runCell = await buildProductionRunCell(baseConfig, preamble, commandLineConfigOverrides, runCellOptions);
343
+ runConversation = await buildProductionRunConversation(baseConfig, preamble, runCellOptions);
344
+ }
345
+ // BATCH-19 A2: resolve the reporter selection — BEFORE the suite runs and before any output
346
+ // is written — so an unknown `--reporter` name (or a broken config-reporter module) fails
347
+ // fast → this suite's harness error (exit 2) with NOTHING run and no misleading partial
348
+ // output. The bundled JUnit reporter and any config-declared reporters are registered
349
+ // through the ONE public `custom` seam `resolveReporters` exposes (config wins on a name
350
+ // collision). Reporters are re-resolved per suite so each suite gets fresh reporter state
351
+ // (e.g. its own JUnit document). An unknown name throws (message lists the available
352
+ // reporters) → per-suite catch → exit 2.
353
+ const customReporterFactories = await buildCustomReporterFactories(baseConfig);
354
+ const reporters = resolveReporters(reporterNames, customReporterFactories);
355
+ // BATCH-10 Task 2: resolve the judge identity profile (CLI `--judge` > suite `judge_profile`
356
+ // > none). When set, build a SEPARATE config for it — the same supported
357
+ // `initConfig({ …overrides, identityProfile })` path `gth batch --models` uses to
358
+ // reconstruct a fresh `.llm` — so the judge runs under its own model. When unset, the judge
359
+ // shares the base config (the SUT's for a single run; the FIRST identity's for a matrix).
360
+ const judgeProfile = resolveJudgeProfile(options.judge, parsedSuite.judgeProfile);
361
+ if (judgeProfile && !resolveIdentityProfileConfigPath(judgeProfile)) {
362
+ // GS2-62 (BATCH-10 review Minor 1): pre-check the requested judge profile with the PURE
363
+ // helper and throw our OWN catchable error. Without this, `initConfig({ …, identityProfile
364
+ // })` would silently fall back to the global (or plain) config on a bad profile and the
365
+ // self-describing notice below would print `Judge: profile "<typo>" (model: <global>)` —
366
+ // asserting a profile that never loaded. The throw is caught per suite → exit 2 (harness
367
+ // error). We can't lean on initConfig's own hard-error here: that path calls the
368
+ // uncatchable `exit(1)`, which would end the process with code 1 and collapse the
369
+ // harness-vs-product (2-vs-1) exit-code distinction.
370
+ throw new Error(`judge profile "${judgeProfile}" not found: no config file in ` +
371
+ `.gsloth/.gsloth-settings/${judgeProfile}/`);
372
+ }
373
+ const judgeConfig = judgeProfile
374
+ ? await initConfig({ ...commandLineConfigOverrides, identityProfile: judgeProfile })
375
+ : baseConfig;
376
+ const judge = buildProductionJudge(judgeConfig);
377
+ const summary = await runEvalSuite(parsedSuite, {
378
+ runCell,
379
+ runCellByIdentity,
380
+ runConversation,
381
+ runConversationByIdentity,
382
+ judge,
383
+ concurrency: options.concurrency,
384
+ });
385
+ writeEvalOutput(suiteOutputDir, summary);
386
+ // BATCH-19: render the run through the reporters resolved above (A1 seam + A2 selection).
387
+ // `writeEvalOutput` (results.json + per-cell JSON) is always-on core output, independent of
388
+ // any reporter — a JUnit run writes results.xml IN ADDITION, never instead. Reporters are an
389
+ // additional rendering layer, driven here in lifecycle order, with THIS suite's dir + path.
390
+ await driveReporters(reporters, summary, {
391
+ suitePath: suite.readPath,
392
+ outputDir: suiteOutputDir,
393
+ judgeNotice: judgeProfile
394
+ ? { profile: judgeProfile, model: judgeModelName(judgeConfig) }
395
+ : undefined,
396
+ });
397
+ return summary;
398
+ };
399
+ // Deliverable 1: resolve the CLI args into the ordered, de-duplicated suite list (files as
400
+ // given; directories → their sorted direct-child *.yaml/*.yml). A no-match directory records
401
+ // a harness error but does not abort the good inputs.
402
+ const { suites, errors: resolutionErrors } = resolveEvalSuiteInputs(suitePaths);
403
+ let anyHarnessError = false;
404
+ for (const message of resolutionErrors) {
405
+ displayError(`eval harness error: ${message}`);
406
+ anyHarnessError = true;
407
+ }
408
+ // Exactly one resolved suite → write DIRECTLY into the output dir (byte-for-byte with the
409
+ // single-suite contract). Multiple → each suite writes into `<output>/<suiteStem>/`, so a CI
410
+ // glob collects them and suites never clobber. On a stem collision across resolved suites,
411
+ // disambiguate deterministically (`-2`, `-3`, … in resolved order) and WARN — never silently
412
+ // overwrite.
413
+ const single = suites.length === 1;
414
+ const usedStems = new Map();
415
+ const combinedCases = [];
416
+ for (const suite of suites) {
417
+ let suiteOutputDir = outputRoot;
418
+ if (!single) {
419
+ const stem = suiteStem(suite.readPath);
420
+ const priorCount = usedStems.get(stem) ?? 0;
421
+ usedStems.set(stem, priorCount + 1);
422
+ const dirName = priorCount === 0 ? stem : `${stem}-${priorCount + 1}`;
423
+ if (priorCount > 0) {
424
+ displayWarning(`eval: two suites share the output name "${stem}"; writing "${suite.readPath}" ` +
425
+ `output to "${dirName}/" so it does not clobber the earlier one.`);
426
+ }
427
+ suiteOutputDir = join(outputRoot, dirName);
428
+ }
429
+ try {
430
+ const summary = await runOneSuite(suite, suiteOutputDir);
431
+ combinedCases.push(...summary.cases);
432
+ }
433
+ catch (error) {
434
+ // A harness-level error for THIS suite (parse/config/reporter/precondition/unexpected).
435
+ // A harness error in ANY suite dominates the aggregate exit → 2 (a partial run can't be
436
+ // trusted), but the good suites still ran and wrote their output.
437
+ displayError(`eval harness error${single ? '' : ` in ${suite.readPath}`}: ` +
438
+ (error instanceof Error ? error.message : String(error)));
439
+ anyHarnessError = true;
440
+ }
441
+ }
442
+ // Aggregate three-way exit: concatenate every successful suite's cases into ONE combined
443
+ // summary and call `classifyEvalExit` ONCE. A harness error in ANY suite dominates → exit 2.
444
+ // For N=1 this reproduces the single-suite exit EXACTLY (one summary, or one harness error →
445
+ // 2); `classifyEvalExit`'s own empty/all-`!sutOk` rule also yields 2 when nothing gradeable
446
+ // ran anywhere.
447
+ const passed = combinedCases.filter((result) => result.verdict === 'PASS').length;
448
+ const combined = {
449
+ total: combinedCases.length,
450
+ passed,
451
+ failed: combinedCases.length - passed,
452
+ cases: combinedCases,
453
+ };
454
+ // Multi-suite only: one aggregate total line AFTER every suite's own per-suite output. For
455
+ // N=1 print NOTHING extra — the single suite's text reporter already printed its verdict, so
456
+ // the output stays byte-for-byte identical to the single-suite contract.
457
+ if (suites.length > 1) {
458
+ const totalLine = `EVAL TOTAL: ${combined.passed}/${combined.total} across ${suites.length} suites, ` +
459
+ `${combined.failed} failed`;
460
+ if (combined.failed === 0 && !anyHarnessError) {
461
+ displaySuccess(totalLine);
462
+ }
463
+ else {
464
+ displayWarning(totalLine);
465
+ }
466
+ }
467
+ const exitCode = anyHarnessError ? 2 : classifyEvalExit(combined);
468
+ if (exitCode !== 0) {
469
+ setExitCode(exitCode);
470
+ }
471
+ }
472
+ catch (error) {
473
+ // BATCH-11: an invocation-level harness error the run never recovered from (e.g. a failed
474
+ // dynamic import) — distinct from a per-suite error (caught in the loop). The suites couldn't
475
+ // be meaningfully evaluated, so this is an *environment* signal (exit 2). Surface the reason;
476
+ // do NOT rethrow — an uncaught throw would surface as a generic exit 1 via the entry point,
477
+ // collapsing the 1-vs-2 distinction.
478
+ displayError(`eval harness error: ${error instanceof Error ? error.message : String(error)}`);
479
+ setExitCode(2);
480
+ }
481
+ });
482
+ }
483
+ //# sourceMappingURL=evalCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evalCommand.js","sourceRoot":"","sources":["../../src/commands/evalCommand.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAEL,UAAU,EACV,gCAAgC,GACjC,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EACL,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EACL,YAAY,EACZ,cAAc,EACd,cAAc,GACf,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AACpF,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,sCAAsC,CAAC;AAwB9C;kGACkG;AAClG,MAAM,UAAU,sBAAsB,CAAC,SAAmB;IACxD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACvD,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACf,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,KAAK,UAAU,4BAA4B,CACzC,MAAiB;IAEjB,MAAM,MAAM,GAAwC,EAAE,CAAC;IAEvD,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,GAChD,MAAM,MAAM,CAAC,2CAA2C,CAAC,CAAC;IAC5D,MAAM,CAAC,mBAAmB,CAAC,GAAG,mBAAmB,CAAC;IAElD,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,EAAE,CAAC;QACxE,MAAM,OAAO,GAAG,OAAO,CAAC,aAAa,EAAE,EAAE,UAAU,CAAC,CAAC;QACrD,IAAI,GAA4B,CAAC;QACjC,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,mCAAmC,IAAI,WAAW,UAAU,MAAM,OAAO,KAAK;gBAC5E,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAC3D,CAAC;QACJ,CAAC;QACD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QAC5B,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CACb,oBAAoB,IAAI,MAAM,UAAU,mCAAmC;gBACzE,qDAAqD,OAAO,OAAO,GAAG,CACzE,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,GAAG,OAA8B,CAAC;IAChD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;8FAC8F;AAC9F,MAAM,UAAU,oBAAoB;IAClC,OAAO,iBAAiB,CAAC,OAAO,iBAAiB,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AAWD;qEACqE;AACrE,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAS,sBAAsB,CAAC,MAAgB;IAI9C,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,MAAM,GAAwB,EAAE,CAAC;IACvC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,MAAM,IAAI,GAAG,CAAC,QAAgB,EAAE,OAAe,EAAQ,EAAE;QACvD,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,OAAO;QAC9B,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACrC,CAAC,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QACvC,IAAI,WAAW,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC;YACH,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,6FAA6F;YAC7F,6FAA6F;YAC7F,WAAW,GAAG,KAAK,CAAC;QACtB,CAAC;QAED,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACjB,SAAS;QACX,CAAC;QAED,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,CAAC;aAClC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;YACf,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YACxC,OAAO,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,MAAM,CAAC;QAC3C,CAAC,CAAC;aACD,IAAI,EAAE,CAAC;QACV,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,yBAAyB,KAAK,gCAAgC,CAAC,CAAC;YAC5E,SAAS;QACX,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;YAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,oBAAoB,CAAC,MAAiB;IAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;QAC9B,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,6BAA6B,CAAC,CAAC;QACtE,OAAO,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IACnD,CAAC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAA4B,EAC5B,iBAAqC;IAErC,MAAM,GAAG,GAAG,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC7B,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC;IACpB,MAAM,KAAK,GAAG,iBAAiB,EAAE,IAAI,EAAE,CAAC;IACxC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;qEAEqE;AACrE,SAAS,cAAc,CAAC,MAAiB;IACvC,MAAM,GAAG,GAAG,MAAM,CAAC,GAA+C,CAAC;IACnE,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC;IACvE,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACxE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,WAAW,CACzB,OAAgB,EAChB,0BAAsD;IAEtD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CACV,uFAAuF;QACrF,oFAAoF;QACpF,iEAAiE,CACpE;SACA,QAAQ,CACP,aAAa,EACb,4FAA4F;QAC1F,uFAAuF;QACvF,mGAAmG,CACtG;SACA,MAAM,CAAC,uBAAuB,EAAE,qBAAqB,EAAE,cAAc,CAAC;SACtE,MAAM,CACL,oBAAoB,EACpB,wEAAwE;QACtE,0DAA0D,CAC7D;SACA,MAAM,CACL,mBAAmB,EACnB,6EAA6E;QAC3E,0CAA0C,CAC7C;SACA,MAAM,CACL,wBAAwB,EACxB,wFAAwF;QACtF,0FAA0F;QAC1F,gFAAgF,EAClF,CAAC,KAAa,EAAE,QAAQ,GAAa,EAAE,EAAE,EAAE,CAAC,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,CACjE;SACA,WAAW,CACV,OAAO,EACP,IAAI;QACF,cAAc;QACd,uEAAuE;QACvE,gFAAgF;QAChF,2FAA2F;QAC3F,0FAA0F;QAC1F,qFAAqF;QACrF,IAAI;QACJ,aAAa;QACb,uCAAuC;QACvC,4DAA4D;QAC5D,iEAAiE;QACjE,wFAAwF;QACxF,oFAAoF;QACpF,wDAAwD;QACxD,6DAA6D,CAChE;SACA,MAAM,CAAC,KAAK,EAAE,UAAoB,EAAE,OAA2B,EAAE,EAAE;QAClE,IAAI,CAAC;YACH,kFAAkF;YAClF,4FAA4F;YAC5F,mFAAmF;YACnF,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,iCAAiC,CAAC,CAAC;YAC3E,MAAM,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAC;YAC5F,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAC;YAC7E,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,0CAA0C,CAAC,CAAC;YACtF,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,uCAAuC,CAAC,CAAC;YAEjF,6FAA6F;YAC7F,4FAA4F;YAC5F,+BAA+B;YAC/B,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ;gBACpC,CAAC,CAAC,sBAAsB,CAAC,OAAO,CAAC,QAAQ,CAAC;gBAC1C,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YACb,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,IAAI,oBAAoB,EAAE,CAAC;YAE5D,6FAA6F;YAC7F,2FAA2F;YAC3F,4FAA4F;YAC5F,4FAA4F;YAC5F,EAAE;YACF,8FAA8F;YAC9F,6FAA6F;YAC7F,wFAAwF;YACxF,2FAA2F;YAC3F,gFAAgF;YAChF,8FAA8F;YAC9F,6FAA6F;YAC7F,4FAA4F;YAC5F,0EAA0E;YAC1E,MAAM,WAAW,GAAG,KAAK,EACvB,KAAwB,EACxB,cAAsB,EACK,EAAE;gBAC7B,MAAM,SAAS,GAAG,sBAAsB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACzD,MAAM,WAAW,GAAG,cAAc,CAAC,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;gBAE9D,4FAA4F;gBAC5F,oFAAoF;gBACpF,wFAAwF;gBACxF,6FAA6F;gBAC7F,6FAA6F;gBAC7F,2FAA2F;gBAC3F,gFAAgF;gBAChF,MAAM,eAAe,GAAG,WAAW,CAAC,UAAU,IAAI,EAAE,CAAC;gBACrD,MAAM,oBAAoB,GAAG,eAAe,CAAC,MAAM,CACjD,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,gCAAgC,CAAC,QAAQ,CAAC,CAC1D,CAAC;gBACF,IAAI,oBAAoB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACpC,MAAM,IAAI,KAAK,CACb,kCAAkC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB;wBAC/E,sDAAsD;wBACtD,sDAAsD,CACzD,CAAC;gBACJ,CAAC;gBAED,MAAM,cAAc,GAAG;oBACrB,OAAO,EAAE,KAAK;oBACd,YAAY,EAAE,MAAM;oBACpB,eAAe,EAAE,SAAS;oBAC1B,UAAU,EAAE,cAAc;iBAClB,CAAC;gBAEX,wFAAwF;gBACxF,6EAA6E;gBAC7E,sFAAsF;gBACtF,8EAA8E;gBAC9E,IAAI,OAA8B,CAAC;gBACnC,IAAI,eAA8C,CAAC;gBACnD,IAAI,iBAAqD,CAAC;gBAC1D,IAAI,yBAAqE,CAAC;gBAC1E,IAAI,UAAqB,CAAC;gBAC1B,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBAC1E,kEAAkE;oBAClE,gFAAgF;oBAChF,qFAAqF;oBACrF,+EAA+E;oBAC/E,0FAA0F;oBAC1F,0FAA0F;oBAC1F,qFAAqF;oBACrF,iBAAiB,GAAG,IAAI,GAAG,EAAE,CAAC;oBAC9B,yBAAyB,GAAG,IAAI,GAAG,EAAE,CAAC;oBACtC,IAAI,mBAA0C,CAAC;oBAC/C,KAAK,MAAM,QAAQ,IAAI,eAAe,EAAE,CAAC;wBACvC,MAAM,cAAc,GAAG,MAAM,UAAU,CAAC;4BACtC,GAAG,0BAA0B;4BAC7B,eAAe,EAAE,QAAQ;yBAC1B,CAAC,CAAC;wBACH,IAAI,CAAC,mBAAmB;4BAAE,mBAAmB,GAAG,cAAc,CAAC;wBAC/D,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;wBAC5D,iBAAiB,CAAC,GAAG,CACnB,QAAQ,EACR,MAAM,sBAAsB,CAC1B,cAAc,EACd,gBAAgB,EAChB,0BAA0B,EAC1B,cAAc,CACf,CACF,CAAC;wBACF,yBAAyB,CAAC,GAAG,CAC3B,QAAQ,EACR,MAAM,8BAA8B,CAClC,cAAc,EACd,gBAAgB,EAChB,cAAc,CACf,CACF,CAAC;oBACJ,CAAC;oBACD,2EAA2E;oBAC3E,UAAU,GAAG,mBAAoB,CAAC;gBACpC,CAAC;qBAAM,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBACnD,uFAAuF;oBACvF,wFAAwF;oBACxF,0FAA0F;oBAC1F,yFAAyF;oBACzF,UAAU,GAAG,MAAM,UAAU,CAAC,0BAA0B,CAAC,CAAC;oBAC1D,MAAM,EAAE,eAAe,EAAE,uBAAuB,EAAE,GAChD,MAAM,MAAM,CAAC,gCAAgC,CAAC,CAAC;oBACjD,OAAO,GAAG,eAAe,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;oBAC9C,eAAe,GAAG,uBAAuB,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;gBAChE,CAAC;qBAAM,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC/C,wFAAwF;oBACxF,2FAA2F;oBAC3F,2FAA2F;oBAC3F,uFAAuF;oBACvF,2FAA2F;oBAC3F,UAAU,GAAG,MAAM,UAAU,CAAC,0BAA0B,CAAC,CAAC;oBAC1D,MAAM,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,GAClD,MAAM,MAAM,CAAC,iCAAiC,CAAC,CAAC;oBAClD,OAAO,GAAG,gBAAgB,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;oBAC/C,eAAe,GAAG,wBAAwB,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;gBACjE,CAAC;qBAAM,CAAC;oBACN,sFAAsF;oBACtF,0FAA0F;oBAC1F,UAAU,GAAG,MAAM,UAAU,CAAC,0BAA0B,CAAC,CAAC;oBAC1D,MAAM,QAAQ,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;oBAChD,OAAO,GAAG,MAAM,sBAAsB,CACpC,UAAU,EACV,QAAQ,EACR,0BAA0B,EAC1B,cAAc,CACf,CAAC;oBACF,eAAe,GAAG,MAAM,8BAA8B,CACpD,UAAU,EACV,QAAQ,EACR,cAAc,CACf,CAAC;gBACJ,CAAC;gBAED,4FAA4F;gBAC5F,0FAA0F;gBAC1F,wFAAwF;gBACxF,sFAAsF;gBACtF,yFAAyF;gBACzF,0FAA0F;gBAC1F,qFAAqF;gBACrF,yCAAyC;gBACzC,MAAM,uBAAuB,GAAG,MAAM,4BAA4B,CAAC,UAAU,CAAC,CAAC;gBAC/E,MAAM,SAAS,GAAG,gBAAgB,CAAC,aAAa,EAAE,uBAAuB,CAAC,CAAC;gBAE3E,6FAA6F;gBAC7F,yEAAyE;gBACzE,kFAAkF;gBAClF,4FAA4F;gBAC5F,0FAA0F;gBAC1F,MAAM,YAAY,GAAG,mBAAmB,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;gBAClF,IAAI,YAAY,IAAI,CAAC,gCAAgC,CAAC,YAAY,CAAC,EAAE,CAAC;oBACpE,wFAAwF;oBACxF,2FAA2F;oBAC3F,wFAAwF;oBACxF,yFAAyF;oBACzF,yFAAyF;oBACzF,iFAAiF;oBACjF,kFAAkF;oBAClF,qDAAqD;oBACrD,MAAM,IAAI,KAAK,CACb,kBAAkB,YAAY,iCAAiC;wBAC7D,4BAA4B,YAAY,GAAG,CAC9C,CAAC;gBACJ,CAAC;gBACD,MAAM,WAAW,GAAG,YAAY;oBAC9B,CAAC,CAAC,MAAM,UAAU,CAAC,EAAE,GAAG,0BAA0B,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;oBACpF,CAAC,CAAC,UAAU,CAAC;gBACf,MAAM,KAAK,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;gBAEhD,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,WAAW,EAAE;oBAC9C,OAAO;oBACP,iBAAiB;oBACjB,eAAe;oBACf,yBAAyB;oBACzB,KAAK;oBACL,WAAW,EAAE,OAAO,CAAC,WAAW;iBACjC,CAAC,CAAC;gBAEH,eAAe,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;gBAEzC,0FAA0F;gBAC1F,4FAA4F;gBAC5F,6FAA6F;gBAC7F,4FAA4F;gBAC5F,MAAM,cAAc,CAAC,SAAS,EAAE,OAAO,EAAE;oBACvC,SAAS,EAAE,KAAK,CAAC,QAAQ;oBACzB,SAAS,EAAE,cAAc;oBACzB,WAAW,EAAE,YAAY;wBACvB,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,CAAC,WAAW,CAAC,EAAE;wBAC/D,CAAC,CAAC,SAAS;iBACd,CAAC,CAAC;gBAEH,OAAO,OAAO,CAAC;YACjB,CAAC,CAAC;YAEF,2FAA2F;YAC3F,6FAA6F;YAC7F,sDAAsD;YACtD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;YAChF,IAAI,eAAe,GAAG,KAAK,CAAC;YAC5B,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;gBACvC,YAAY,CAAC,uBAAuB,OAAO,EAAE,CAAC,CAAC;gBAC/C,eAAe,GAAG,IAAI,CAAC;YACzB,CAAC;YAED,0FAA0F;YAC1F,6FAA6F;YAC7F,2FAA2F;YAC3F,6FAA6F;YAC7F,aAAa;YACb,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;YACnC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;YAC5C,MAAM,aAAa,GAAqB,EAAE,CAAC;YAC3C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,IAAI,cAAc,GAAG,UAAU,CAAC;gBAChC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;oBACvC,MAAM,UAAU,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC5C,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;oBACpC,MAAM,OAAO,GAAG,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;oBACtE,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;wBACnB,cAAc,CACZ,2CAA2C,IAAI,eAAe,KAAK,CAAC,QAAQ,IAAI;4BAC9E,cAAc,OAAO,4CAA4C,CACpE,CAAC;oBACJ,CAAC;oBACD,cAAc,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;gBAC7C,CAAC;gBAED,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;oBACzD,aAAa,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;gBACvC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,wFAAwF;oBACxF,wFAAwF;oBACxF,kEAAkE;oBAClE,YAAY,CACV,qBAAqB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,QAAQ,EAAE,IAAI;wBAC5D,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAC3D,CAAC;oBACF,eAAe,GAAG,IAAI,CAAC;gBACzB,CAAC;YACH,CAAC;YAED,yFAAyF;YACzF,6FAA6F;YAC7F,6FAA6F;YAC7F,4FAA4F;YAC5F,gBAAgB;YAChB,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;YAClF,MAAM,QAAQ,GAAqB;gBACjC,KAAK,EAAE,aAAa,CAAC,MAAM;gBAC3B,MAAM;gBACN,MAAM,EAAE,aAAa,CAAC,MAAM,GAAG,MAAM;gBACrC,KAAK,EAAE,aAAa;aACrB,CAAC;YAEF,2FAA2F;YAC3F,6FAA6F;YAC7F,yEAAyE;YACzE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,SAAS,GACb,eAAe,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,KAAK,WAAW,MAAM,CAAC,MAAM,WAAW;oBACnF,GAAG,QAAQ,CAAC,MAAM,SAAS,CAAC;gBAC9B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;oBAC9C,cAAc,CAAC,SAAS,CAAC,CAAC;gBAC5B,CAAC;qBAAM,CAAC;oBACN,cAAc,CAAC,SAAS,CAAC,CAAC;gBAC5B,CAAC;YACH,CAAC;YAED,MAAM,QAAQ,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAClE,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;gBACnB,WAAW,CAAC,QAAQ,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,0FAA0F;YAC1F,8FAA8F;YAC9F,8FAA8F;YAC9F,4FAA4F;YAC5F,qCAAqC;YACrC,YAAY,CACV,uBAAuB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAChF,CAAC;YACF,WAAW,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -94,9 +94,12 @@ export function execCommand(program, commandLineConfigOverrides) {
94
94
  const execConfig = buildExecConfig(config, options);
95
95
  const { runSingleShot } = await import('@gaunt-sloth/core/runtime/singleShot.js');
96
96
  const { createResolvers } = await import('@gaunt-sloth/agent/resolvers.js');
97
+ const { resolveAgentFactory } = await import('@gaunt-sloth/agent/core/resolveAgentFactory.js');
97
98
  let ok = false;
98
99
  try {
99
- ok = await runSingleShot('EXEC', getExecSystemPrompt(execConfig), content.join('\n'), execConfig, createResolvers(), 'exec');
100
+ ({ ok } = await runSingleShot('EXEC', getExecSystemPrompt(execConfig), content.join('\n'), execConfig, createResolvers(), 'exec',
101
+ // exec defaults to the lean backend; an explicit config.agent.backend overrides it.
102
+ resolveAgentFactory(execConfig, 'lean')));
100
103
  }
101
104
  catch (error) {
102
105
  displayError(error instanceof Error ? error.message : String(error));
@@ -1 +1 @@
1
- {"version":3,"file":"execCommand.js","sourceRoot":"","sources":["../../src/commands/execCommand.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"execCommand.js","sourceRoot":"","sources":["../../src/commands/execCommand.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { detectProviders, listModels, type DetectedProvider, type ModelInfo, type ProviderId } from '@gaunt-sloth/core/providers/modelDiscovery.js';
1
+ import { detectProviders, type DetectedProvider, type ModelDiscoveryResult, type ModelInfo, type ProviderId } from '@gaunt-sloth/core/providers/modelDiscovery.js';
2
2
  import { ensureGslothDir, writeProjectReviewPreamble } from '#src/commands/configSetup.js';
3
3
  /**
4
4
  * Where the first-run dialog (CFG-2) persists the chosen provider/model config.
@@ -22,10 +22,29 @@ export type SelectFn = (title: string, options: string[], defaultIndex: number)
22
22
  */
23
23
  export interface FirstRunDialogDeps {
24
24
  detectProviders: typeof detectProviders;
25
- listModels: typeof listModels;
25
+ /**
26
+ * CFG-21 — fetches the chosen provider's model list WITH its {@link ModelDiscoveryResult}
27
+ * provenance, baking in the generous interactive timeout by default. Returns `{ models, status }`
28
+ * so the dialog can surface an honest degrade notice when a live fetch was attempted and failed
29
+ * (`status: 'fallback'`) rather than silently swapping in a by-design curated list (`'curated'`).
30
+ */
31
+ fetchModels: (providerId: ProviderId) => Promise<ModelDiscoveryResult>;
32
+ /**
33
+ * CFG-21 — runs `run` while a visible "working" indicator is shown (an Ink spinner on an
34
+ * interactive TTY, a plain printed line otherwise), clearing it when `run` settles. The model
35
+ * fetch is routed through this seam so the wait is never silent and a test can assert it fired.
36
+ */
37
+ withProgress: <T>(label: string, run: () => Promise<T>) => Promise<T>;
26
38
  ensureGslothDir: typeof ensureGslothDir;
27
39
  writeProjectReviewPreamble: typeof writeProjectReviewPreamble;
28
- /** Writes the config content to the scope's path and returns that path. */
40
+ /** Resolves the config file path for the chosen scope (does not write). */
41
+ resolveConfigPath: (scope: ConfigScope) => string;
42
+ /** True when a config file already exists at `path`. */
43
+ configExists: (path: string) => boolean;
44
+ /**
45
+ * (Over)writes the config content at the scope's path and returns that path. The dialog only
46
+ * calls this once it has decided to write, so this always writes (never a silent no-clobber skip).
47
+ */
29
48
  writeConfig: (scope: ConfigScope, content: string) => string;
30
49
  /** Prompts the user and resolves with their (untrimmed) answer. */
31
50
  ask: AskFn;
@@ -44,7 +63,14 @@ export declare function orderProviders(providers: DetectedProvider[]): DetectedP
44
63
  export declare function parseMenuSelection(answer: string, count: number): number | null;
45
64
  /** The index of the first ⭐ preferred model, or 0 when none are flagged. */
46
65
  export declare function defaultModelIndex(models: ModelInfo[]): number;
47
- /** Builds the `.gsloth.config.json` body for a chosen provider + model. */
66
+ /**
67
+ * Builds the `.gsloth.config.json` body for a chosen provider + model. Delegates to the shared
68
+ * {@link buildInitConfigContent} so the interactive first-run path stamps the same `$schema`
69
+ * pointer (GS2-1) as the per-provider template writers. Previously this local builder omitted
70
+ * `$schema`, so a config created through the first-run dialog got no editor autocomplete/validation.
71
+ * First-run always has an explicit model chosen, so it is written into the config (unlike a bare
72
+ * `init <provider>` template, which omits the model to track the curated fallback, CFG-14).
73
+ */
48
74
  export declare function buildConfigContent(providerId: ProviderId, model: string): string;
49
75
  /** Resolves the config write path for the chosen scope (CFG-3 layering). */
50
76
  export declare function resolveConfigWritePath(scope: ConfigScope): string;
@@ -53,6 +79,14 @@ export declare function resolveConfigWritePath(scope: ConfigScope): string;
53
79
  * `✓`/blank mark read like a selection checkbox; this spells the state out instead.
54
80
  */
55
81
  export declare function providerReadinessLabel(provider: DetectedProvider): string;
82
+ /**
83
+ * CFG-21 — the default {@link FirstRunDialogDeps.withProgress}: an Ink spinner while `run` is in
84
+ * flight when the environment can drive interactive Ink (the same activation policy as
85
+ * {@link makeDefaultSelect}), otherwise a plain printed line via {@link displayInfo} on the
86
+ * readline / non-TTY path. Either way the wait is visible, never silent. The Ink module is
87
+ * imported lazily so a readline-only run never loads React/Ink.
88
+ */
89
+ export declare function makeDefaultProgress(): <T>(label: string, run: () => Promise<T>) => Promise<T>;
56
90
  /**
57
91
  * CFG-2 — the first-run configuration dialog.
58
92
  *
@@ -62,5 +96,5 @@ export declare function providerReadinessLabel(provider: DetectedProvider): stri
62
96
  * globally (CFG-3). Writes a minimal `{ llm: { type, model } }` config and, for
63
97
  * the project scope, scaffolds the review/guidelines preamble.
64
98
  */
65
- export declare function runFirstRunDialog(overrides?: Partial<FirstRunDialogDeps>): Promise<void>;
99
+ export declare function runFirstRunDialog(overrides?: Partial<FirstRunDialogDeps>, force?: boolean): Promise<void>;
66
100
  export {};