gaunt-sloth 2.0.0-beta.13 → 2.0.0-beta.15

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/dist/cli.js CHANGED
@@ -16,11 +16,11 @@ import { historyCommand } from '#src/commands/historyCommand.js';
16
16
  import { RESUMABLE_COMMANDS, resumeOption, rootResumeRefusalMessage, } from '#src/commands/resumeOption.js';
17
17
  import { insightsCommand } from '#src/commands/insightsCommand.js';
18
18
  import { modelsCommand } from '#src/commands/modelsCommand.js';
19
- import { argv, exit, getSlothVersion, readStdin } from '@gaunt-sloth/core/utils/systemUtils.js';
19
+ import { argv, exit, getSlothVersion, readStdin, willWaitForPipedStdin, } from '@gaunt-sloth/core/utils/systemUtils.js';
20
20
  import { commandSkipsStdin, resolveInvokedCommandName } from '#src/utils/stdinPolicy.js';
21
21
  import { guardProgramConfigErrors } from '#src/utils/configErrorGuard.js';
22
- import { CONFLICTING_CONFIG_SOURCES_MESSAGE } from '@gaunt-sloth/core/config.js';
23
- import { coerceBooleanOrString, displayError } from '@gaunt-sloth/core/utils/consoleUtils.js';
22
+ import { CONFLICTING_CONFIG_SOURCES_MESSAGE, loadConfiguredConsoleLevel, } from '@gaunt-sloth/core/config.js';
23
+ import { coerceBooleanOrString, displayError, setConsoleLevel, } from '@gaunt-sloth/core/utils/consoleUtils.js';
24
24
  import { installCrashHandler } from '@gaunt-sloth/core/utils/crashHandler.js';
25
25
  // GS2-48 — install the process-level crash handler as early as possible, so an uncaughtException /
26
26
  // unhandledRejection anywhere in the run writes a redacted debug snapshot to ~/.gsloth/debug-dumps/
@@ -147,6 +147,40 @@ if (rootResume !== undefined &&
147
147
  displayError(rootResumeRefusalMessage(invokedCommand, rootResume));
148
148
  exit(1);
149
149
  }
150
+ // REL-25 — resolve `consoleLevel` from the config BEFORE the parse, because a piped run writes
151
+ // before the parse. `readStdin` blocks until the pipe closes and draws its `reading STDIN` line
152
+ // while it waits; the level a run finally uses is applied from the merged config inside the command
153
+ // action, i.e. after `program.parseAsync()`. Without this the only level in force when that line is
154
+ // written is the INFO default, so the one progress line a piped run draws was the one line no
155
+ // `consoleLevel` could quieten.
156
+ //
157
+ // **The level is read twice on purpose, and there is only ever one value.** This reads the same key
158
+ // from the same files through the same discovery and the same narrowing as the config load that
159
+ // follows, and sets nothing else. Where that load runs it re-applies the identical value and has
160
+ // the last word (its defaults always carry a `consoleLevel`, so it never leaves the setting alone);
161
+ // where it never runs at all — `insights` and `models` resolve no config, and a `--help`/`--version`
162
+ // run exits before one is built — the value read here is the only one, and it is still the level the
163
+ // user configured. So the two readings cannot hold different answers; one of them can only be
164
+ // absent. That does mean a PIPED `gth insights` now filters its own output by `consoleLevel` while
165
+ // a non-piped one still does not: those surfaces sit outside the config load, not outside the level
166
+ // system, and closing that asymmetry is a change to them rather than to this line.
167
+ //
168
+ // It is also silent: a config it cannot read answers "no level", leaving the run at the default and
169
+ // leaving the report of a broken config where it already is, at the CLI's top-level guard after the
170
+ // parse.
171
+ //
172
+ // Asked only on the branch that writes early, and asked through `readStdin`'s own predicate rather
173
+ // than a restatement of it: a run that will not wait on a pipe gains nothing here, and would pay a
174
+ // config read (and, for a `configure()`-style config, a second module evaluation) for it.
175
+ //
176
+ // It must come after the option-derived overrides above — `-c`, `-g` and `--profile` decide WHICH
177
+ // config this reads — and after the `--no-pipe` implication, which decides whether it is read.
178
+ if (willWaitForPipedStdin(program)) {
179
+ const earlyConsoleLevel = await loadConfiguredConsoleLevel(cliConfigOverrides);
180
+ if (earlyConsoleLevel !== undefined) {
181
+ setConsoleLevel(earlyConsoleLevel);
182
+ }
183
+ }
150
184
  // CFG-35 — the config loader raises a catchable error when a provider has no resolvable API key,
151
185
  // so programmatic callers can classify it. For a person at a terminal there is nothing to classify,
152
186
  // so the `gth` CLI makes the terminating choice here, once, instead of in every command action.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,wBAAwB,GACzB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AAChG,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACzF,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAE1E,OAAO,EAAE,kCAAkC,EAAE,MAAM,6BAA6B,CAAC;AAEjF,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAC9F,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAE9E,mGAAmG;AACnG,oGAAoG;AACpG,kEAAkE;AAClE,mBAAmB,EAAE,CAAC;AAEtB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,KAAK,CAAC;KACX,WAAW,CAAC,gCAAgC,CAAC;KAC7C,OAAO,CAAC,eAAe,EAAE,CAAC;KAC1B,MAAM,CACL,WAAW,EACX,2CAA2C;IACzC,kEAAkE;IAClE,0EAA0E,CAC7E;KACA,MAAM,CAAC,qBAAqB,EAAE,mCAAmC,CAAC;KAClE,MAAM,CAAC,cAAc,EAAE,+DAA+D,CAAC;KACvF,MAAM,CAAC,mCAAmC,EAAE,gDAAgD,CAAC;KAC7F,MAAM,CACL,kBAAkB,EAClB,kEAAkE;IAChE,qDAAqD,CACxD;KACA,MAAM,CACL,oCAAoC,EACpC,0FAA0F,CAC3F;KACA,MAAM,CACL,OAAO,EACP,uDAAuD;IACrD,4DAA4D,CAC/D;KACA,MAAM,CAAC,UAAU,EAAE,kEAAkE,CAAC;IACvF,4FAA4F;IAC5F,oCAAoC;KACnC,SAAS,CAAC,YAAY,EAAE,CAAC;KACzB,SAAS,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;KAChD,SAAS,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAErD,MAAM,kBAAkB,GAA+B,EAAE,CAAC;AAE1D,mDAAmD;AACnD,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;AAC3B,IAAI,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC;IACtC;;;;OAIG;IACH,kBAAkB,CAAC,OAAO,GAAG,IAAI,CAAC;AACpC,CAAC;AACD,IAAI,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;IACrC,2BAA2B;IAC3B,kBAAkB,CAAC,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;AACzE,CAAC;AACD,2FAA2F;AAC3F,gGAAgG;AAChG,gGAAgG;AAChG,+FAA+F;AAC/F,iCAAiC;AACjC,IAAI,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;IACrC,IAAI,kBAAkB,CAAC,gBAAgB,EAAE,CAAC;QACxC,YAAY,CAAC,kCAAkC,CAAC,CAAC;QACjD,IAAI,CAAC,CAAC,CAAC,CAAC;IACV,CAAC;IACD,kBAAkB,CAAC,MAAM,GAAG,IAAI,CAAC;AACnC,CAAC;AACD,qGAAqG;AACrG,sGAAsG;AACtG,6EAA6E;AAC7E,MAAM,kBAAkB,GAAG,OAAO,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;AACrE,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;AACrD,IAAI,kBAAkB,IAAI,UAAU,IAAI,kBAAkB,KAAK,UAAU,EAAE,CAAC;IAC1E,YAAY,CACV,6CAA6C,kBAAkB,oBAAoB,UAAU,KAAK;QAChG,mCAAmC,CACtC,CAAC;IACF,IAAI,CAAC,CAAC,CAAC,CAAC;AACV,CAAC;AACD,IAAI,UAAU,IAAI,kBAAkB,EAAE,CAAC;IACrC,kBAAkB,CAAC,eAAe,GAAG,UAAU,IAAI,kBAAkB,CAAC;AACxE,CAAC;AAED,4FAA4F;AAC5F,4FAA4F;AAC5F,mFAAmF;AACnF,IAAI,OAAO,CAAC,oBAAoB,CAAC,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC;IAClD,kBAAkB,CAAC,GAAG,GAAG,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;AAEhE,qEAAqE;AACrE,oEAAoE;AACpE,6EAA6E;AAC7E,MAAM,OAAO,GAAG,qBAAqB,CAAC,WAAW,CAAC,CAAC;AACnD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;IAC1B,kBAAkB,CAAC,iBAAiB,GAAG,OAAO,CAAC;AACjD,CAAC;AAED,sEAAsE;AACtE,WAAW,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AACzC,aAAa,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAC3C,SAAS,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AACvC,UAAU,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AACxC,WAAW,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AACzC,YAAY,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAC1C,WAAW,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AACzC,eAAe,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAC7C,WAAW,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AACzC,WAAW,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AACzC,UAAU,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AACxC,UAAU,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AACxC,aAAa,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAC3C,mGAAmG;AACnG,gGAAgG;AAChG,kGAAkG;AAClG,6BAA6B;AAC7B,cAAc,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAC5C,eAAe,CAAC,OAAO,CAAC,CAAC;AACzB,oGAAoG;AACpG,2EAA2E;AAC3E,aAAa,CAAC,OAAO,CAAC,CAAC;AAEvB,8FAA8F;AAC9F,kGAAkG;AAClG,mGAAmG;AACnG,6FAA6F;AAC7F,+FAA+F;AAC/F,kGAAkG;AAClG,cAAc;AACd,MAAM,cAAc,GAAG,yBAAyB,CAC9C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EACjD,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,QAAQ,CACpC,CAAC;AACF,IAAI,iBAAiB,CAAC,cAAc,CAAC,EAAE,CAAC;IACtC,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,gGAAgG;AAChG,mGAAmG;AACnG,gGAAgG;AAChG,0FAA0F;AAC1F,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAuB,CAAC;AAC1E,IACE,UAAU,KAAK,SAAS;IACxB,cAAc,KAAK,SAAS;IAC5B,CAAC,kBAAkB,CAAC,GAAG,CAAC,cAAc,CAAC,EACvC,CAAC;IACD,YAAY,CAAC,wBAAwB,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC,CAAC;IACnE,IAAI,CAAC,CAAC,CAAC,CAAC;AACV,CAAC;AAED,iGAAiG;AACjG,oGAAoG;AACpG,gGAAgG;AAChG,MAAM,SAAS,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ import { wrapContent } from '@gaunt-sloth/core/utils/llmUtils.js';
9
9
  import { runPrDiscovery } from '#src/commands/prDiscovery.js';
10
10
  import { readMultipleFilesFromProjectDir } from '@gaunt-sloth/review/utils/fileUtils.js';
11
11
  import { extractChangedPathsFromDiff } from '@gaunt-sloth/review/utils/diffPaths.js';
12
+ import { writeReviewFailureReport } from '@gaunt-sloth/review/modules/reviewFailureReport.js';
12
13
  export function prCommand(program, commandLineConfigOverrides) {
13
14
  program
14
15
  .command('pr')
@@ -27,6 +28,23 @@ export function prCommand(program, commandLineConfigOverrides) {
27
28
  const content = [];
28
29
  const requirementSource = getEffectiveRequirementSource('pr', config, options.requirementsSource);
29
30
  const contentSource = getEffectiveContentSource('pr', config);
31
+ // REL-20 — the label `review()` would have used, hoisted because the failure report has to
32
+ // land at the same path the successful run would have written.
33
+ const reportSource = prId ? `PR-${prId}` : 'PR-discovery';
34
+ /**
35
+ * REL-20 — every exit from this action that happens BEFORE `review()` runs goes through
36
+ * here, so a caller that asked for a report file gets one saying why there is none of the
37
+ * usual content in it. The exit code is unchanged: the run still failed.
38
+ *
39
+ * This is an enumeration of exits, which is exactly the shape that rots by omission — a new
40
+ * guard added below without this call silently reopens the hole for one more input. Anything
41
+ * here that `return`s before the `review()` call must call this first.
42
+ */
43
+ const failBeforeReview = (message) => {
44
+ displayError(message);
45
+ writeReviewFailureReport(config, reportSource, 'pr', message);
46
+ setExitCode(1);
47
+ };
30
48
  if (options.file) {
31
49
  content.push(readMultipleFilesFromProjectDir(options.file));
32
50
  }
@@ -42,10 +60,9 @@ export function prCommand(program, commandLineConfigOverrides) {
42
60
  const isDiscovery = !prId && !requirementsId;
43
61
  const looksLikeRequirementsOnlyMode = contentSource === 'github' && Boolean(prId) && !requirementsId && !/^\d+$/.test(prId);
44
62
  if (looksLikeRequirementsOnlyMode) {
45
- displayError(`Unsupported PR command arguments: "${prId}" was provided as the pull request ID. ` +
63
+ failBeforeReview(`Unsupported PR command arguments: "${prId}" was provided as the pull request ID. ` +
46
64
  '`gth pr <requirementsId>` requirements-only mode is not supported. ' +
47
65
  'Use `gth pr` with no arguments to discover change requirements automatically, or provide both a numeric PR ID and requirements ID: `gth pr <prId> <requirementsId>`.');
48
- setExitCode(1);
49
66
  return;
50
67
  }
51
68
  // With the GitHub content source, prId ends up interpolated into `gh pr diff <prId>` and
@@ -53,14 +70,12 @@ export function prCommand(program, commandLineConfigOverrides) {
53
70
  // depth), but reject garbage upfront with a clear error instead of a downstream warning.
54
71
  // Non-GitHub content sources (file/text) accept arbitrary content ids and stay untouched.
55
72
  if (contentSource === 'github' && prId && !/^\d+$/.test(prId)) {
56
- displayError(`Invalid pull request ID "${prId}"; expected a numeric PR number, e.g. \`gth pr 42\`.`);
57
- setExitCode(1);
73
+ failBeforeReview(`Invalid pull request ID "${prId}"; expected a numeric PR number, e.g. \`gth pr 42\`.`);
58
74
  return;
59
75
  }
60
76
  if (isDiscovery) {
61
77
  if (config.commands?.pr?.discovery?.enabled === false) {
62
- displayError('Change requirements discovery is disabled. Provide a pull request ID to run `gth pr`.');
63
- setExitCode(1);
78
+ failBeforeReview('Change requirements discovery is disabled. Provide a pull request ID to run `gth pr`.');
64
79
  return;
65
80
  }
66
81
  try {
@@ -69,8 +84,7 @@ export function prCommand(program, commandLineConfigOverrides) {
69
84
  content.push(wrapContent(discoveryResult.requirements, 'discovered-requirements', 'requirements'));
70
85
  }
71
86
  if (!discoveryResult.diff) {
72
- displayError('Change requirements discovery did not produce a diff. Cannot continue with review.');
73
- setExitCode(1);
87
+ failBeforeReview('Change requirements discovery did not produce a diff. Cannot continue with review.');
74
88
  return;
75
89
  }
76
90
  changedPaths = extractChangedPathsFromDiff(discoveryResult.diff);
@@ -85,11 +99,16 @@ export function prCommand(program, commandLineConfigOverrides) {
85
99
  for (const row of approvalStopRows(error.parts, { columns: stdout.columns })) {
86
100
  displayError(row);
87
101
  }
102
+ // REL-20 — the report gets the stop's own message, not the rows above. Those rows are
103
+ // the terminal rendering: a gutter and a wrap computed against this terminal's width,
104
+ // which is meaningless in a file someone posts as a PR comment. The message is already
105
+ // neutralised at construction, so it is safe to write raw.
106
+ writeReviewFailureReport(config, reportSource, 'pr', error.message);
107
+ setExitCode(1);
88
108
  }
89
109
  else {
90
- displayError(error instanceof Error ? error.message : String(error));
110
+ failBeforeReview(error instanceof Error ? error.message : String(error));
91
111
  }
92
- setExitCode(1);
93
112
  return;
94
113
  }
95
114
  }
@@ -106,16 +125,14 @@ export function prCommand(program, commandLineConfigOverrides) {
106
125
  // returns null (with a warning) for an invalid PR number. Without this guard the review
107
126
  // would silently proceed against no diff; fail loudly as the throwing path used to.
108
127
  if (!prContent) {
109
- displayError(`Could not retrieve PR content for "${prId}". Cannot continue with review.`);
110
- setExitCode(1);
128
+ failBeforeReview(`Could not retrieve PR content for "${prId}". Cannot continue with review.`);
111
129
  return;
112
130
  }
113
131
  changedPaths = extractChangedPathsFromDiff(prContent);
114
132
  content.push(prContent);
115
133
  }
116
134
  catch (error) {
117
- displayError(error instanceof Error ? error.message : String(error));
118
- setExitCode(1);
135
+ failBeforeReview(error instanceof Error ? error.message : String(error));
119
136
  return;
120
137
  }
121
138
  }
@@ -124,7 +141,7 @@ export function prCommand(program, commandLineConfigOverrides) {
124
141
  }
125
142
  const { review } = await import('@gaunt-sloth/review/modules/reviewModule.js');
126
143
  const { createResolvers } = await import('@gaunt-sloth/agent/resolvers.js');
127
- await review(prId ? `PR-${prId}` : 'PR-discovery', getReviewSystemPrompt(config), content.join('\n'), config, 'pr', createResolvers(),
144
+ await review(reportSource, getReviewSystemPrompt(config), content.join('\n'), config, 'pr', createResolvers(),
128
145
  // Bind GitHub-only review tools (gth_gh_read_file) to this PR's repo/ref, so they read
129
146
  // the PR under review rather than letting the model guess owner/repo. Undefined prId =
130
147
  // discovery mode (current branch's PR), which `gh pr view` resolves on its own.
@@ -1 +1 @@
1
- {"version":3,"file":"prCommand.js","sourceRoot":"","sources":["../../src/commands/prCommand.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prCommand.js","sourceRoot":"","sources":["../../src/commands/prCommand.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,9 @@ import { readMultipleFilesFromProjectDir } from '@gaunt-sloth/review/utils/fileU
9
9
  // `commands/commandUtils`, and this helper lives only in review's (GS2-45).
10
10
  import { resolvePrIdFromArg } from '@gaunt-sloth/review/commands/commandUtils.js';
11
11
  import { extractChangedPathsFromDiff } from '@gaunt-sloth/review/utils/diffPaths.js';
12
+ import { writeReviewFailureReport } from '@gaunt-sloth/review/modules/reviewFailureReport.js';
13
+ /** The source label this command passes to `review()`, and therefore names its report file with. */
14
+ const REVIEW_SOURCE = 'REVIEW';
12
15
  export function reviewCommand(program, cliConfigOverrides) {
13
16
  program
14
17
  .command('review')
@@ -50,7 +53,12 @@ export function reviewCommand(program, cliConfigOverrides) {
50
53
  providedContent = await getCommandSourceInput('review', 'content', contentId, config, contentSource);
51
54
  }
52
55
  catch (error) {
53
- displayError(error instanceof Error ? error.message : String(error));
56
+ const message = error instanceof Error ? error.message : String(error);
57
+ displayError(message);
58
+ // REL-20 — `gth review` fails before inference the same way `gth pr` does (the git source
59
+ // outside a repository, the GitHub source on a diff too large to fetch), so it owes the
60
+ // same report. The two commands share this exit; they must not diverge on it.
61
+ writeReviewFailureReport(config, REVIEW_SOURCE, 'review', message);
54
62
  setExitCode(1);
55
63
  return;
56
64
  }
@@ -79,7 +87,7 @@ export function reviewCommand(program, cliConfigOverrides) {
79
87
  }
80
88
  const { review } = await import('@gaunt-sloth/review/modules/reviewModule.js');
81
89
  const { createResolvers } = await import('@gaunt-sloth/agent/resolvers.js');
82
- await review('REVIEW', getReviewSystemPrompt(config), content.join('\n'), config, 'review', createResolvers(),
90
+ await review(REVIEW_SOURCE, getReviewSystemPrompt(config), content.join('\n'), config, 'review', createResolvers(),
83
91
  // Bind GitHub-only review tools (gth_gh_read_file) to the pull request this run's DIFF
84
92
  // came from. Without it they resolve the PR from the checked-out branch instead, so a
85
93
  // `gth review 42 --content-source github` reviews PR 42's diff against a different pull
@@ -1 +1 @@
1
- {"version":3,"file":"reviewCommand.js","sourceRoot":"","sources":["../../src/commands/reviewCommand.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reviewCommand.js","sourceRoot":"","sources":["../../src/commands/reviewCommand.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * The two promise-based fan-outs between the runner's human-in-the-loop seams and the mounted Ink
3
+ * `<App>`: the tool-approval prompt, and [[TUI-C68]]'s attack banner.
4
+ *
5
+ * ## Why they live in a module of their own
6
+ *
7
+ * [[EXT-110]] — because `abortPending` is the part of a session nobody can reach from a test while
8
+ * it sits inside `tuiSessionModule`. That module pulls in Ink, `initConfig`, the runner, the
9
+ * history store and the mouse plumbing, so a spec for the teardown answer has to mock a session in
10
+ * order to ask a question about eighty lines of plain TypeScript — and the one spec that tried
11
+ * instead kept a COPY of this bridge beside it and asserted against that. A copy passes whatever
12
+ * the original does, which is exactly how a teardown came to be archived as a human refusal with a
13
+ * green suite either side of it. These are the objects production wires; the specs import them
14
+ * from here.
15
+ *
16
+ * @module
17
+ */
18
+ import type { ApprovalOutcome, PendingAttackHalt, PendingToolInterrupt, ToolApprovalReply, AttackHaltReply } from '@gaunt-sloth/core/core/types.js';
19
+ import type { PendingApproval, PendingAttackBanner } from '#src/tui/types.js';
20
+ /**
21
+ * Fan-out so the runner's tool-approval callback can reach the mounted React app. Modeled on
22
+ * `createStatusBridge`, but promise-based: when the runner suspends on a
23
+ * `run_shell_command` interrupt and calls the approval callback, the bridge creates a pending
24
+ * record (the {@link @gaunt-sloth/core!core/types.PendingToolInterrupt | PendingToolInterrupt} plus a `resolve`), emits it to the subscribed
25
+ * `<App>`, and hands the callback a Promise it awaits until the app resolves a decision.
26
+ *
27
+ * Fail-closed: if the session ends / the app unmounts while an approval is still pending, every
28
+ * outstanding record is answered by `abortPending`, so a suspended run can never hang — and the
29
+ * tool does not run, matching the readline path's "anything not o/s/a → reject" default.
30
+ *
31
+ * [[EXT-150]] — **and the answer comes back the other way.** The runner reports what a decision
32
+ * LANDED as only after the callback above has returned (the write is attempted then), so the
33
+ * decision promise cannot carry it. `report` is wired to `runner.setApprovalOutcomeCallback` and
34
+ * settles a second promise per request, which is what `resolve` hands the App. The two are paired by
35
+ * the `pending` object's identity rather than by arrival order: this bridge holds a SET of
36
+ * outstanding records and the App a queue, so ordering is not a property either of them keeps, and a
37
+ * mis-paired outcome would confirm one call's persistence on another call's dialog.
38
+ */
39
+ export declare function createApprovalBridge(): {
40
+ /** Wired to `runner.setToolApprovalCallback`: returns a Promise the runner awaits. */
41
+ request: (pending: PendingToolInterrupt) => Promise<ToolApprovalReply>;
42
+ /**
43
+ * [[EXT-150]] — wired to `runner.setApprovalOutcomeCallback`: hand the waiting request what its
44
+ * answer actually landed as. An outcome for a request nobody is waiting on (teardown got there
45
+ * first) is dropped, which is why the map entry is removed as it settles.
46
+ */
47
+ report: (outcome: ApprovalOutcome) => void;
48
+ subscribe: (cb: (record: PendingApproval) => void) => () => void;
49
+ /**
50
+ * Answer every still-pending approval on teardown, so a suspended run can never hang.
51
+ *
52
+ * [[EXT-110]] — **and answer it as a teardown, not as a reject.** The call is still refused;
53
+ * what changed is what the archive is told about WHO refused it. This used to send
54
+ * `{ type: 'reject', message: 'Session ended before approval.' }`, which is the same shape a
55
+ * person pressing *reject* sends — so a terminal closed with a prompt on screen was written
56
+ * into the `/debug-dump` archive as a human having looked at that command and said no. That is
57
+ * the strongest statement the archive makes, and it was being made about nobody.
58
+ */
59
+ abortPending: () => void;
60
+ };
61
+ /**
62
+ * [[TUI-C68]] §6.1 — the same fan-out for **attack halts**, so the runner's halt seam can reach the
63
+ * mounted React app and a human can type their way past one.
64
+ *
65
+ * A second bridge rather than a widened approval one: the answers are different types, and keeping
66
+ * them apart is what stops a surface returning an approval `scope` for a halt that must never carry
67
+ * one.
68
+ *
69
+ * Fail-closed the same way: if the session ends while a banner is still up, `abortPending` answers
70
+ * it so the suspended run cannot hang — and it answers with a value that does not run the command.
71
+ */
72
+ export declare function createAttackHaltBridge(): {
73
+ /** Wired to `runner.setAttackHaltCallback`: returns a Promise the runner awaits. */
74
+ request: (halt: PendingAttackHalt) => Promise<AttackHaltReply>;
75
+ subscribe: (cb: (record: PendingAttackBanner) => void) => () => void;
76
+ /**
77
+ * Answer every still-open banner on teardown.
78
+ *
79
+ * [[EXT-110]] — with `teardown` rather than `stop`, for the reason the approval bridge above
80
+ * sends a teardown reply. The run still ends: `run-anyway` is the only value that runs
81
+ * anything, so the §6.1 polarity is untouched and every other value halts. What no longer
82
+ * happens is the archive recording a person as having read an attack banner and refused it
83
+ * when the session had already gone.
84
+ */
85
+ abortPending: () => void;
86
+ };
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Fan-out so the runner's tool-approval callback can reach the mounted React app. Modeled on
3
+ * `createStatusBridge`, but promise-based: when the runner suspends on a
4
+ * `run_shell_command` interrupt and calls the approval callback, the bridge creates a pending
5
+ * record (the {@link @gaunt-sloth/core!core/types.PendingToolInterrupt | PendingToolInterrupt} plus a `resolve`), emits it to the subscribed
6
+ * `<App>`, and hands the callback a Promise it awaits until the app resolves a decision.
7
+ *
8
+ * Fail-closed: if the session ends / the app unmounts while an approval is still pending, every
9
+ * outstanding record is answered by `abortPending`, so a suspended run can never hang — and the
10
+ * tool does not run, matching the readline path's "anything not o/s/a → reject" default.
11
+ *
12
+ * [[EXT-150]] — **and the answer comes back the other way.** The runner reports what a decision
13
+ * LANDED as only after the callback above has returned (the write is attempted then), so the
14
+ * decision promise cannot carry it. `report` is wired to `runner.setApprovalOutcomeCallback` and
15
+ * settles a second promise per request, which is what `resolve` hands the App. The two are paired by
16
+ * the `pending` object's identity rather than by arrival order: this bridge holds a SET of
17
+ * outstanding records and the App a queue, so ordering is not a property either of them keeps, and a
18
+ * mis-paired outcome would confirm one call's persistence on another call's dialog.
19
+ */
20
+ export function createApprovalBridge() {
21
+ const listeners = new Set();
22
+ // Records that have been emitted but not yet resolved (used by abortPending on teardown).
23
+ const outstanding = new Set();
24
+ // [[EXT-150]] — how to settle the outcome promise of a request still waiting to hear one, keyed by
25
+ // the interrupt the runner will name. Cleared as each is settled, so nothing accumulates.
26
+ const awaitingOutcome = new Map();
27
+ return {
28
+ /** Wired to `runner.setToolApprovalCallback`: returns a Promise the runner awaits. */
29
+ request: (pending) => new Promise((resolve) => {
30
+ let settled = false;
31
+ // Created before the record so `resolve` can hand it back; the executor runs synchronously,
32
+ // so `settleOutcome` is the real resolver by the time anything can call it.
33
+ let settleOutcome = () => { };
34
+ const outcome = new Promise((settleIt) => {
35
+ settleOutcome = settleIt;
36
+ });
37
+ awaitingOutcome.set(pending, (reported) => {
38
+ awaitingOutcome.delete(pending);
39
+ settleOutcome(reported);
40
+ });
41
+ const record = {
42
+ pending,
43
+ resolve: (reply) => {
44
+ if (!settled) {
45
+ settled = true;
46
+ outstanding.delete(record);
47
+ resolve(reply);
48
+ }
49
+ // The same promise on every call, so the idempotent second `resolve` of a race is still
50
+ // told the outcome rather than handed one that can never settle.
51
+ return outcome;
52
+ },
53
+ };
54
+ outstanding.add(record);
55
+ for (const l of listeners)
56
+ l(record);
57
+ }),
58
+ /**
59
+ * [[EXT-150]] — wired to `runner.setApprovalOutcomeCallback`: hand the waiting request what its
60
+ * answer actually landed as. An outcome for a request nobody is waiting on (teardown got there
61
+ * first) is dropped, which is why the map entry is removed as it settles.
62
+ */
63
+ report: (outcome) => {
64
+ awaitingOutcome.get(outcome.pending)?.(outcome);
65
+ },
66
+ subscribe: (cb) => {
67
+ listeners.add(cb);
68
+ return () => {
69
+ listeners.delete(cb);
70
+ };
71
+ },
72
+ /**
73
+ * Answer every still-pending approval on teardown, so a suspended run can never hang.
74
+ *
75
+ * [[EXT-110]] — **and answer it as a teardown, not as a reject.** The call is still refused;
76
+ * what changed is what the archive is told about WHO refused it. This used to send
77
+ * `{ type: 'reject', message: 'Session ended before approval.' }`, which is the same shape a
78
+ * person pressing *reject* sends — so a terminal closed with a prompt on screen was written
79
+ * into the `/debug-dump` archive as a human having looked at that command and said no. That is
80
+ * the strongest statement the archive makes, and it was being made about nobody.
81
+ */
82
+ abortPending: () => {
83
+ for (const record of [...outstanding]) {
84
+ record.resolve({ type: 'teardown', message: 'Session ended before approval.' });
85
+ }
86
+ // [[EXT-150]] — and tell everything still waiting that no outcome is coming. Fail-closed here
87
+ // means `null`, which the App renders as *no persistence claim*: a surface that hung waiting
88
+ // would be as bad as one that guessed, and guessing is what this node removes.
89
+ for (const settle of [...awaitingOutcome.values()])
90
+ settle(null);
91
+ },
92
+ };
93
+ }
94
+ /**
95
+ * [[TUI-C68]] §6.1 — the same fan-out for **attack halts**, so the runner's halt seam can reach the
96
+ * mounted React app and a human can type their way past one.
97
+ *
98
+ * A second bridge rather than a widened approval one: the answers are different types, and keeping
99
+ * them apart is what stops a surface returning an approval `scope` for a halt that must never carry
100
+ * one.
101
+ *
102
+ * Fail-closed the same way: if the session ends while a banner is still up, `abortPending` answers
103
+ * it so the suspended run cannot hang — and it answers with a value that does not run the command.
104
+ */
105
+ export function createAttackHaltBridge() {
106
+ const listeners = new Set();
107
+ const outstanding = new Set();
108
+ return {
109
+ /** Wired to `runner.setAttackHaltCallback`: returns a Promise the runner awaits. */
110
+ request: (halt) => new Promise((resolve) => {
111
+ let settled = false;
112
+ const record = {
113
+ halt,
114
+ resolve: (reply) => {
115
+ if (settled)
116
+ return;
117
+ settled = true;
118
+ outstanding.delete(record);
119
+ resolve(reply);
120
+ },
121
+ };
122
+ outstanding.add(record);
123
+ for (const l of listeners)
124
+ l(record);
125
+ }),
126
+ subscribe: (cb) => {
127
+ listeners.add(cb);
128
+ return () => {
129
+ listeners.delete(cb);
130
+ };
131
+ },
132
+ /**
133
+ * Answer every still-open banner on teardown.
134
+ *
135
+ * [[EXT-110]] — with `teardown` rather than `stop`, for the reason the approval bridge above
136
+ * sends a teardown reply. The run still ends: `run-anyway` is the only value that runs
137
+ * anything, so the §6.1 polarity is untouched and every other value halts. What no longer
138
+ * happens is the archive recording a person as having read an attack banner and refused it
139
+ * when the session had already gone.
140
+ */
141
+ abortPending: () => {
142
+ for (const record of [...outstanding])
143
+ record.resolve('teardown');
144
+ },
145
+ };
146
+ }
147
+ //# sourceMappingURL=approvalBridges.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approvalBridges.js","sourceRoot":"","sources":["../../src/tui/approvalBridges.ts"],"names":[],"mappings":"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"}
@@ -1245,6 +1245,10 @@ export function App(props) {
1245
1245
  // TUI-C19 — the actual validation warnings so `/config` renders the details the
1246
1246
  // standing advisory line points at.
1247
1247
  configWarnings: props.advisories,
1248
+ // GS2-88 — the three summaries AND the reason they may be empty, so a command with
1249
+ // nothing to show names the cause the session actually established rather than the
1250
+ // config. Both surfaces pass all four, from the one core builder.
1251
+ historyAvailability: props.historyAvailability,
1248
1252
  historySummary: props.historySummary,
1249
1253
  insightsSummary: props.insightsSummary,
1250
1254
  historySearch: props.historySearch,
@@ -1283,7 +1287,12 @@ export function App(props) {
1283
1287
  // thread intact (the LangGraph checkpointer replays it on the next turn), so the
1284
1288
  // model would still "remember" everything. Reset the agent's thread too so the
1285
1289
  // model context truly matches the now-empty transcript (TUI-C8).
1286
- agent.resetThread?.();
1290
+ //
1291
+ // [[EXT-109]] — and the agent's own record of the conversation goes with it: the
1292
+ // approvals gate's capture log is what the Auto-mode tab above and a later
1293
+ // `/debug-dump` read, and every other pane cleared here would otherwise sit beside one
1294
+ // that still quotes the user's pre-`/clear` messages.
1295
+ agent.clearConversation?.();
1287
1296
  // The status-bar turn counter is part of the conversation state we just wiped, so
1288
1297
  // reset it too — a cleared session starts back at "turns: 0".
1289
1298
  turnCountRef.current = 0;
@@ -1395,7 +1404,7 @@ export function App(props) {
1395
1404
  // path never registers gsloth's readline Esc handler, so Ink owns raw mode cleanly).
1396
1405
  // 3. Tab while the panel is visible and idle → focus/cycle the panel.
1397
1406
  // 4. While the panel is focused → Tab/Shift+Tab cycle sections, ↑/↓ scroll one line,
1398
- // PageUp/PageDown page-step, m maximises, Esc unfocuses.
1407
+ // PageUp/PageDown page-step, m maximises, Esc leaves the pane (restoring a maximised one).
1399
1408
  useInput((input, key) => {
1400
1409
  // [[TUI-C79]] — **Ctrl+C is this app's, not Ink's**, and it is answered here before anything
1401
1410
  // else can claim it. `render()` takes `exitOnCtrlC: false` (`tuiSessionModule.tsx`), which is
@@ -1632,7 +1641,17 @@ export function App(props) {
1632
1641
  }
1633
1642
  return;
1634
1643
  }
1635
- // Esc layering: clear an active search first (less-style), else unfocus the pane.
1644
+ // Esc layering: clear an active search first (less-style), else LEAVE the pane — and leaving
1645
+ // it drops the maximised view as well as focus, in the one press.
1646
+ //
1647
+ // TUI-C107 — focus and maximisation are one state as far as an exit is concerned, so an exit
1648
+ // that dropped only one of them left the user with nothing to press. The prompt is unmounted
1649
+ // while the pane holds focus (the render's `!debugFocused` guard), and a maximised pane takes
1650
+ // the terminal height minus DEBUG_MAX_CHROME_ROWS, so the prompt has no rows to draw in even
1651
+ // once focus is gone: dropping focus alone left the session with no visible prompt, and `m` —
1652
+ // the key that would undo the maximisation — is handled inside this focused-only branch, so
1653
+ // it no longer answered either. Same pairing, and the same reason, as the /debug toggle's
1654
+ // "focus never lingers on a hidden panel" above.
1636
1655
  if (key.escape) {
1637
1656
  if (debugSearchQueryRef.current) {
1638
1657
  clearDebugSearch();
@@ -1640,6 +1659,7 @@ export function App(props) {
1640
1659
  }
1641
1660
  setDebugFocused(false);
1642
1661
  debugFocusedRef.current = false;
1662
+ setDebugMaximized(false);
1643
1663
  return;
1644
1664
  }
1645
1665
  // `/` opens the search input (scoped to pane focus — the seam).