@gaunt-sloth/core 2.0.0-alpha.29 → 2.0.0-alpha.30

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 (76) hide show
  1. package/dist/config/schema.d.ts +48 -48
  2. package/dist/config/schema.js +55 -29
  3. package/dist/config/schema.js.map +1 -1
  4. package/dist/config/shell-policy.d.ts +241 -26
  5. package/dist/config/shell-policy.js +353 -52
  6. package/dist/config/shell-policy.js.map +1 -1
  7. package/dist/config/tool-descriptions.d.ts +78 -32
  8. package/dist/config/tool-descriptions.js +72 -29
  9. package/dist/config/tool-descriptions.js.map +1 -1
  10. package/dist/config/types.d.ts +9 -4
  11. package/dist/config/types.js.map +1 -1
  12. package/dist/core/GthAbstractAgent.d.ts +13 -5
  13. package/dist/core/GthAbstractAgent.js +42 -13
  14. package/dist/core/GthAbstractAgent.js.map +1 -1
  15. package/dist/core/GthAgentRunner.d.ts +203 -9
  16. package/dist/core/GthAgentRunner.js +646 -39
  17. package/dist/core/GthAgentRunner.js.map +1 -1
  18. package/dist/core/GthLangChainAgent.js +58 -17
  19. package/dist/core/GthLangChainAgent.js.map +1 -1
  20. package/dist/core/reasoningBlocks.d.ts +60 -0
  21. package/dist/core/reasoningBlocks.js +98 -0
  22. package/dist/core/reasoningBlocks.js.map +1 -0
  23. package/dist/core/refusal.js +6 -2
  24. package/dist/core/refusal.js.map +1 -1
  25. package/dist/core/shell/approvalCapture.d.ts +271 -0
  26. package/dist/core/shell/approvalCapture.js +108 -0
  27. package/dist/core/shell/approvalCapture.js.map +1 -0
  28. package/dist/core/shell/approvalStop.d.ts +16 -7
  29. package/dist/core/shell/approvalStop.js +18 -7
  30. package/dist/core/shell/approvalStop.js.map +1 -1
  31. package/dist/core/shell/escalationSeverity.d.ts +141 -0
  32. package/dist/core/shell/escalationSeverity.js +89 -0
  33. package/dist/core/shell/escalationSeverity.js.map +1 -0
  34. package/dist/core/shell/framing.d.ts +190 -0
  35. package/dist/core/shell/framing.js +633 -0
  36. package/dist/core/shell/framing.js.map +1 -0
  37. package/dist/core/shell/hardline.d.ts +81 -0
  38. package/dist/core/shell/hardline.js +607 -0
  39. package/dist/core/shell/hardline.js.map +1 -0
  40. package/dist/core/shell/negotiation.d.ts +249 -0
  41. package/dist/core/shell/negotiation.js +355 -0
  42. package/dist/core/shell/negotiation.js.map +1 -0
  43. package/dist/core/shell/normalize.d.ts +5 -5
  44. package/dist/core/shell/normalize.js +5 -5
  45. package/dist/core/shell/rater.d.ts +353 -18
  46. package/dist/core/shell/rater.js +556 -39
  47. package/dist/core/shell/rater.js.map +1 -1
  48. package/dist/core/shell/rejection.d.ts +1 -1
  49. package/dist/core/types.d.ts +97 -4
  50. package/dist/providers/geminiThinking.d.ts +52 -0
  51. package/dist/providers/geminiThinking.js +72 -0
  52. package/dist/providers/geminiThinking.js.map +1 -0
  53. package/dist/providers/google-genai.js +4 -1
  54. package/dist/providers/google-genai.js.map +1 -1
  55. package/dist/providers/vertexai.js +4 -1
  56. package/dist/providers/vertexai.js.map +1 -1
  57. package/dist/runtime/askStructured.d.ts +45 -3
  58. package/dist/runtime/askStructured.js +46 -5
  59. package/dist/runtime/askStructured.js.map +1 -1
  60. package/dist/runtime/conversation.d.ts +2 -1
  61. package/dist/runtime/conversation.js +2 -1
  62. package/dist/runtime/conversation.js.map +1 -1
  63. package/dist/runtime/singleShot.d.ts +3 -2
  64. package/dist/runtime/singleShot.js +3 -2
  65. package/dist/runtime/singleShot.js.map +1 -1
  66. package/dist/utils/debugDump.d.ts +19 -0
  67. package/dist/utils/debugDump.js +11 -0
  68. package/dist/utils/debugDump.js.map +1 -1
  69. package/dist/utils/displayWidth.d.ts +23 -0
  70. package/dist/utils/displayWidth.js +61 -6
  71. package/dist/utils/displayWidth.js.map +1 -1
  72. package/dist/utils/systemPromptNotes.d.ts +12 -1
  73. package/dist/utils/systemPromptNotes.js +24 -2
  74. package/dist/utils/systemPromptNotes.js.map +1 -1
  75. package/package.json +1 -1
  76. package/schema/gsloth-config.schema.json +48 -48
@@ -240,30 +240,38 @@ export declare function getShellMaxOutputBytes(devTools: GthDevToolsConfig | und
240
240
  export declare function getEffectiveDevToolsConfig(config: Pick<GthConfig, 'commands' | 'builtInTools' | 'askWriteMode'> | undefined, command: GthCommand | undefined): GthDevToolsConfig | undefined;
241
241
  /**
242
242
  * CFG-27 (spec §1, §2) — **the ladder**. There is ONE approvals setting and it is a single ordered
243
- * ladder of five rungs; each rung fully determines behaviour. There are no severity thresholds, no
244
- * strictness levels and no independent rater on/off switch.
243
+ * ladder; each rung fully determines behaviour. There are no severity thresholds, no strictness
244
+ * levels and no independent rater on/off switch.
245
245
  *
246
246
  * | # | Rung | Rater | LLM cost |
247
247
  * |---|---|---|---|
248
- * | 1 | `read-only` | no | none |
248
+ * | 1 | `manual` | no | none |
249
249
  * | 2 | `write` | no | none |
250
- * | 3 | `auto-safe` | yes | 1 call per gated call |
251
- * | 4 | `full-auto` | yes | 1–2 calls per gated call |
250
+ * | 3 | `assisted` | yes | 1 call per gated call |
251
+ * | 4 | `auto` | yes | 1–2 calls per gated call |
252
252
  * | 5 | `bypass` | no | none |
253
253
  *
254
254
  * Rungs 1, 2 and 5 are fully deterministic: no model is consulted, so behaviour is reproducible
255
255
  * and costs nothing.
256
256
  *
257
- * **`bypass` is NOT a higher-autonomy rung than `full-auto`** (§2.5). Both let the agent act
257
+ * **CFG-39 four postures plus one modifier, not five peers.** `write` is not a rung on a trust
258
+ * ladder: it is the same posture as `manual` with a different auto-granted set. The four postures
259
+ * a user chooses between are {@link APPROVAL_POSTURES} (`manual` → `assisted` → `auto`, plus
260
+ * `bypass`), and that ordering is legible in the names themselves. `write` remains fully settable
261
+ * — via `/approvals write` and via config — and simply does not occupy a row in quick access.
262
+ * This constant keeps ALL FIVE members: it is the type's domain, the set
263
+ * {@link resolveInterruptToolNames} unions over, and what makes `write` settable at all.
264
+ *
265
+ * **`bypass` is NOT a higher-autonomy rung than `auto`** (§2.5). Both let the agent act
258
266
  * without asking; `bypass` is the same autonomy with the checks removed. The ordering below is the
259
- * order the rungs are *offered* in, and must never be presented as though `full-auto` were an
267
+ * order the rungs are *offered* in, and must never be presented as though `auto` were an
260
268
  * incomplete `bypass`.
261
269
  *
262
- * Identifiers are kebab-case (§9.1) because the same token must work as a config value, a
263
- * slash-command argument and a CLI flag — a space breaks the last two. Display names keep their
264
- * spaces; see {@link APPROVAL_RUNG_LABELS}.
270
+ * Identifiers are lower-case single words (§9.1) because the same token must work as a config
271
+ * value, a slash-command argument and a CLI flag — a space breaks the last two. Display names are
272
+ * capitalised; see {@link APPROVAL_RUNG_LABELS}.
265
273
  */
266
- export declare const APPROVAL_RUNGS: readonly ['read-only', 'write', 'auto-safe', 'full-auto', 'bypass'];
274
+ export declare const APPROVAL_RUNGS: readonly ['manual', 'write', 'assisted', 'auto', 'bypass'];
267
275
  /** One rung of {@link APPROVAL_RUNGS}. */
268
276
  export type ApprovalRung = (typeof APPROVAL_RUNGS)[number];
269
277
  /**
@@ -273,22 +281,224 @@ export type ApprovalRung = (typeof APPROVAL_RUNGS)[number];
273
281
  */
274
282
  export declare const APPROVAL_RUNG_LABELS: Record<ApprovalRung, string>;
275
283
  /**
276
- * §10 — the one sentence shown wherever a rung is chosen or displayed. **Copied verbatim from the
277
- * specification**; the wording is constrained by four normative rules there (state what the rung
278
- * PERMITS, state the allow-list carve-out, never claim safety this system cannot deliver, use the
279
- * display spelling) plus §8.1 (the hardline floor is real but is NEVER advertised descriptions
280
- * cite only protections the user can inspect and extend, i.e. the deny list). Do not "improve"
281
- * these: `auto-safe` in particular MUST keep the sentence saying files are still rewritten and
282
- * deleted without asking.
284
+ * CFG-39**the four postures**, in the order they are offered: the rows `/approvals` presents
285
+ * when it asks the user to choose one.
286
+ *
287
+ * `write` is deliberately absent, and its absence is the whole point of the reframe. It is not a
288
+ * rung on a trust ladder it is `manual`'s posture with a different auto-granted set, so listing
289
+ * it as a fifth peer is what made a four-point ladder read as five indistinguishable ones. It stays
290
+ * fully settable via `/approvals write` and via config; it simply leaves quick access.
283
291
  *
284
- * The only departure from the source text is that §10's markdown emphasis markers (`**not**` in
285
- * *Full auto*) are dropped, since these strings are rendered as plain terminal copy.
292
+ * **This is a presentation list, never a policy one.** Every predicate, every `Record<ApprovalRung,
293
+ * …>` and the interrupt set are built from {@link APPROVAL_RUNGS}, which keeps all five. Using this
294
+ * constant to decide behaviour would silently un-settle `write`.
295
+ */
296
+ export declare const APPROVAL_POSTURES: readonly ["manual", "assisted", "auto", "bypass"];
297
+ /**
298
+ * CFG-39 — the one-line note that `write` exists, shown as picker CHROME beside the `manual` row.
299
+ *
300
+ * It lives here rather than appended to {@link APPROVAL_RUNG_DESCRIPTIONS}`.manual` on purpose: the
301
+ * descriptions are one surface's copy shared by six, so a sentence about quick-access mechanics
302
+ * would follow the mode into the status display and the tool-description layer, where it means
303
+ * nothing.
304
+ */
305
+ export declare const APPROVAL_WRITE_MODIFIER_HINT: string;
306
+ /**
307
+ * §10 — what each mode is **for**, in at most two sentences, shown wherever a mode is chosen or
308
+ * displayed.
309
+ *
310
+ * **The first sentence is load-bearing and must stand alone.** The `/approvals` picker, the text
311
+ * fallback and the usage hint all render one line per mode through `firstSentence`, so sentence
312
+ * one has to answer "what is this mode for" on its own and sentence two carries the qualification.
313
+ * Keep it short enough to read as a menu row.
314
+ *
315
+ * **Say what the mode is for, not only what it permits.** A description that lists permissions
316
+ * invites the category error these modes actually suffer: Manual reads as "the safe one", so it
317
+ * gets picked for a long unattended run — where the deciding is done by a human, and a human is the
318
+ * fastest-degrading decider in the system. Manual and Write are bounded-volume tools and their copy
319
+ * says so.
320
+ *
321
+ * The wording is constrained by four normative rules (state what the mode PERMITS, state the
322
+ * allow-list carve-out, never claim safety this system cannot deliver, use the display spelling)
323
+ * plus §8.1 — the hardline floor is real but is NEVER advertised, so descriptions cite only
324
+ * protections the user can inspect and extend, i.e. the deny list. Five further constraints bind
325
+ * every edit here:
326
+ *
327
+ * 1. **No description may imply containment.** The gate protects against accidents, not intent, and
328
+ * a working-folder claim collapses the moment the agent has a shell — `write_file` refuses a
329
+ * path that `touch` then writes. The narrow true form (the built-in file *tools* are confined)
330
+ * is stated once, on `write`, alongside the fact that the shell is not confined that way.
331
+ * 2. **Claims are scoped to the session the user is in.** These strings render on terminal surfaces
332
+ * only; a sentence whose subject is "Gaunt Sloth" and whose claim is that it always asks would
333
+ * be false over the AG-UI and ACP servers, which never drain an approval interrupt ([[EXT-94]]).
334
+ * 3. **`assisted` MUST keep the sentence saying files are still rewritten and deleted without
335
+ * asking** — it sounds safer than it is, and that clause is the correction.
336
+ * 4. **A qualification may not live in the second sentence alone.** The picker, the text fallback
337
+ * and the usage hint all render `firstSentence` and nothing else, so the opener is the whole
338
+ * message on the three surfaces a user reads while *choosing* a mode. An opener that sells a
339
+ * behavioural difference the product does not have is not rescued by a sentence two those
340
+ * surfaces never print — check a wording by rendering it, not by reading the constant.
341
+ * 5. **`auto` is the mode a reader most wants to hear is quiet, and it is not.** It settles some
342
+ * risky commands with the rater instead of interrupting — that difference is real and may be
343
+ * stated — but the copy MUST also say that a bounded exchange ends at the user, and MUST NOT
344
+ * promise the user watches it happen. The rounds reach a person at the escalation, all of them
345
+ * at once, and nothing renders them before that ([[TUI-C26]]), so a sentence implying a live
346
+ * commentary would be describing a screen that does not exist.
347
+ *
348
+ * Everything these two sentences cannot hold lives at {@link APPROVAL_PROTECTION_DOCS_URL}, which
349
+ * the surfaces print beside the copy rather than each description repeating it.
286
350
  */
287
351
  export declare const APPROVAL_RUNG_DESCRIPTIONS: Record<ApprovalRung, string>;
352
+ /**
353
+ * The page that carries what these modes do and do NOT protect you from — the reasoning the
354
+ * two-sentence descriptions deliberately do not hold.
355
+ *
356
+ * **A GitHub blob URL, matching the one other user-facing runtime doc link in this package** (the
357
+ * 2.0 migration pointer in `config/schema.ts`). The docs site publishes the same page at
358
+ * `https://gauntsloth.app/docs/guides/what-approvals-protect-you-from/`; move this constant there
359
+ * once that path serves the page, and nothing else changes.
360
+ */
361
+ export declare const APPROVAL_PROTECTION_DOCS_URL = "https://github.com/pukeko-robotics/gaunt-sloth/blob/main/docs/guides/what-approvals-protect-you-from.md";
362
+ /**
363
+ * The docs pointer as the surfaces print it: **label and URL as two separate lines**, never one
364
+ * joined string. Every notice surface takes `lines: string[]` and renders one line each, so a bare
365
+ * URL on its own line is the only form that survives a narrow pane without the break landing
366
+ * mid-path — and it is what lets a terminal that linkifies URLs pick the whole thing up.
367
+ *
368
+ * It lives beside the descriptions rather than inside them for {@link APPROVAL_WRITE_MODIFIER_HINT}'s
369
+ * reason: one line about where to read more, repeated into all five descriptions, would follow each
370
+ * mode into the tool-description layer and the status display, where it is noise.
371
+ */
372
+ export declare const APPROVAL_PROTECTION_DOCS_LINES: readonly string[];
288
373
  /** Narrowing type guard for a raw string that may name a rung. */
289
374
  export declare function isApprovalRung(value: unknown): value is ApprovalRung;
290
375
  /** The rungs at which every gated call is rated by the model (§2.3, §2.4). */
291
376
  export declare function isRatedRung(rung: ApprovalRung): boolean;
377
+ /**
378
+ * [[EXT-29]] (§5) — the rung at which a `destructive` rating opens a **negotiation** with the rater
379
+ * instead of going to the human: the agent may revise the command or justify it, the rater re-rates
380
+ * with the exchange in view, and only a spent bound reaches a person.
381
+ *
382
+ * **This is the one predicate that separates `auto` from `assisted`, and it is deliberately ONE.**
383
+ * Three places have to agree about it — the decision mapping
384
+ * ({@link import('../core/shell/rater.js').mapVerdictToAction}, which returns `reject` here and
385
+ * `escalate` at `assisted`), the rating prompt (§5.2's wording rules are addressed to the agent, so
386
+ * they are turned on by this and not by whether a transcript happens to exist yet), and the runner
387
+ * that counts the rounds. Two of them agreeing and the third not is exactly how the two rated rungs
388
+ * would drift back into being the same posture with different names.
389
+ *
390
+ * Written as a `=== 'auto'` test rather than as "rated but not assisted" so that a sixth rung has to
391
+ * be classified deliberately rather than inheriting a negotiation by omission.
392
+ */
393
+ export declare function isNegotiatingRung(rung: ApprovalRung): boolean;
394
+ /**
395
+ * The rungs that decide a gated call **without a model** — `manual` and `write` (§2.1, §2.2).
396
+ * Everything they do not auto-grant goes to the human, so these are the two rungs a user picks in
397
+ * order to read and approve every tool call themselves.
398
+ *
399
+ * The complement of {@link isRatedRung} plus `bypass`; written out rather than negated so that a
400
+ * sixth rung would have to be classified deliberately instead of defaulting into this set.
401
+ */
402
+ export declare function isDeterministicRung(rung: ApprovalRung): boolean;
403
+ /**
404
+ * **The one rule: does `rung` gate this tool — i.e. must this call be decided rather than simply
405
+ * run?** Everything else in this area is a projection of this predicate over a set of names.
406
+ *
407
+ * - The shell is gated whenever the shell gate is on, at EVERY rung (`bypass` included, so §2.5's
408
+ * deny list can still fire — see the `bypass` arm of `GthAgentRunner.decideToolApproval`).
409
+ * - At the two **deterministic** rungs, a tool is gated when the rung's own grant does not cover its
410
+ * access class ({@link isAccessClassGrantedAtRung}). At `manual` that leaves only the built-in
411
+ * READ tools free; at `write`, the built-in read and write tools. The write built-ins, the shell,
412
+ * deepagents' `execute`, MCP tools and custom/agent-authored tools all escalate to the human.
413
+ * - At `assisted`, `auto` and `bypass` nothing but the shell is gated. **That split is
414
+ * deliberate and load-bearing, not tidiness.** At a rated rung a gated non-shell call reaches the
415
+ * `subject.kind !== 'shell'` arm of `GthAgentRunner.decideToolApproval`, which floors it at
416
+ * `destructive` and sends it to the human *with no rating call*, because §4.3 keeps the rater on
417
+ * the shell until [[EXT-30]]. Gating there would silently turn every MCP call at `assisted` into
418
+ * a human prompt — a UX change belonging to EXT-30, not to the two rungs whose published
419
+ * descriptions this predicate makes true.
420
+ *
421
+ * `gateShell` only ever WIDENS the result. At a deterministic rung the shell is gated by its own
422
+ * (absent) access class if it is bound at all, so `gateShell: false` does not exempt it — an
423
+ * exemption keyed to one tool NAME is the defect class this predicate exists to remove. In practice
424
+ * a disabled shell tool is never bound, so the two agree.
425
+ *
426
+ * **This takes no bound toolset**, which is what lets `GthAgentRunner` ask it about a single
427
+ * arriving call: the runner sees the names the graph registered, and on the deep backend that list
428
+ * omits tools deepagents registers itself. A decision that consulted a bound list would grant
429
+ * `execute` at `manual` purely because the runner could not see it.
430
+ */
431
+ export declare function isToolGatedAtRung(options: {
432
+ toolName: string;
433
+ rung: ApprovalRung;
434
+ gateShell: boolean;
435
+ }): boolean;
436
+ /**
437
+ * **The LIVE gated set: which bound tools the rung in force actually gates.** What a decision is
438
+ * measured against — the tool descriptions the model reads (§4.5) and the rater's granted-tools
439
+ * summary (§4.4) are both built from this, so neither can tell the model a tool is free while the
440
+ * gate escalates it.
441
+ *
442
+ * **It is NOT what the backends wire into the interrupt.** That is
443
+ * {@link resolveInterruptToolNames}, and the two are different sets on purpose: the interrupt is
444
+ * installed once, at agent init, while `/approvals <rung>` moves the rung underneath it for the rest
445
+ * of the session. A set that carried the rung would be frozen at the rung the session started on —
446
+ * and since the default is `assisted`, typing `/approvals manual` would leave exactly the write
447
+ * tools this design escalates ungated. So the interrupt is wired rung-independently and
448
+ * `GthAgentRunner.decideToolApproval` consults {@link isToolGatedAtRung} against the LIVE rung.
449
+ *
450
+ * **Derived from the bound toolset, never a hand-written list.** A static list of built-ins would
451
+ * leave MCP, custom and agent-authored tools out — the exact tools with no access class and so the
452
+ * exact tools the deterministic rungs must escalate. `boundToolNames` must therefore be the FINAL
453
+ * toolset the graph is handed, including tools the graph builder registers itself (deepagents'
454
+ * filesystem tools, `execute`, `task` and `write_todos` never appear in the array gsloth passes it).
455
+ *
456
+ * Order is stable: the shell first, then bound order. Duplicates are collapsed, so a caller may pass
457
+ * overlapping name sources without deduplicating first.
458
+ */
459
+ export declare function resolveGatedToolNames(options: {
460
+ rung: ApprovalRung;
461
+ gateShell: boolean;
462
+ boundToolNames: readonly string[];
463
+ }): readonly string[];
464
+ /**
465
+ * {@link COMMAND_ANSWERS_APPROVALS} as a predicate. An unset command is a session driven by
466
+ * `GthAgentRunner` (nothing else leaves it unset), so it answers approvals.
467
+ *
468
+ * **`?? true` is the fail-safe default, not defensive noise.** The lookup yields `undefined` for a
469
+ * value outside {@link GthCommand}, and `undefined` is falsy — which would tell the caller to
470
+ * install NO approval interrupt, the one direction this predicate must never fail in. TypeScript
471
+ * makes that unreachable from inside this repo, but the function is re-exported from the public
472
+ * `@gaunt-sloth/core/config.js` barrel, so an untyped consumer can reach it. The coalesce restores
473
+ * runtime totality without weakening the compile-time totality the record already gives.
474
+ */
475
+ export declare function commandAnswersApprovals(command: GthCommand | undefined): boolean;
476
+ /**
477
+ * **The interrupt set: which tool names the backends wire into the approval interrupt.** Every bound
478
+ * tool that ANY rung could gate — the union of {@link resolveGatedToolNames} over
479
+ * {@link APPROVAL_RUNGS}, which in practice is the shell plus every bound tool that is not a
480
+ * built-in READ tool.
481
+ *
482
+ * One derivation for both backends, for the same reason {@link resolveShellApprovalGate} is one: the
483
+ * lean backend installs `humanInTheLoopMiddleware` directly and the deep backend installs the very
484
+ * same middleware through deepagents' `interruptOn`, and a set computed twice is a set that drifts.
485
+ *
486
+ * **Deliberately rung-independent.** The interrupt is installed once, when the agent is built, and
487
+ * `/approvals <rung>` then moves the rung for the rest of the session without rebuilding it. Only a
488
+ * set that covers every rung can survive that: the interrupt fires and
489
+ * `GthAgentRunner.decideToolApproval` decides on the rung in force, which is where the rung has
490
+ * always been read. **Wiring wider does not gate wider** — a call the live rung does not gate is
491
+ * approved there with no rating call and no prompt, so `assisted`, `auto` and `bypass` behave
492
+ * exactly as they do when the interrupt holds the shell alone.
493
+ *
494
+ * **Only for a command that answers approvals** ({@link commandAnswersApprovals}). A surface that
495
+ * drains nothing gets the shell-gate set instead, because a rung-independent set there parks tool
496
+ * calls nobody can reach.
497
+ */
498
+ export declare function resolveInterruptToolNames(options: {
499
+ gateShell: boolean;
500
+ boundToolNames: readonly string[];
501
+ }): readonly string[];
292
502
  /**
293
503
  * EXT-71 §3.1 — the **subject** axis of a rule entry, and only that. The schema twin is
294
504
  * `APPROVAL_ENTRY_TYPES` in `config/schema.ts`. What holds the two together is
@@ -572,7 +782,7 @@ export interface McpAnnotationTrustChange extends McpServerAnnotationTrust {
572
782
  invalidates: string[];
573
783
  }
574
784
  /**
575
- * §1.1 — **the default rung is `auto-safe`, everywhere.** It is the default in every interactive
785
+ * §1.1 — **the default rung is `assisted`, everywhere.** It is the default in every interactive
576
786
  * context, it does NOT vary with the configured model, and there is no separate non-interactive
577
787
  * default. What changes without a human is what an escalation *does* (§6.2: an immediate non-zero
578
788
  * exit, never an approval), not which rung the session starts on. A context-dependent default
@@ -582,7 +792,7 @@ export declare const DEFAULT_APPROVAL_RUNG: ApprovalRung;
582
792
  /**
583
793
  * CFG-27 — resolve the effective {@link ResolvedApprovals} for the active command.
584
794
  *
585
- * There is no defaults *matrix*: §1.1 makes `auto-safe` the default in every context, so this
795
+ * There is no defaults *matrix*: §1.1 makes `assisted` the default in every context, so this
586
796
  * resolver neither detects nor accepts a "context". Precedence is the only thing it decides, and
587
797
  * §9.1 splits it in two:
588
798
  *
@@ -667,10 +877,15 @@ export interface ShellApprovalGateDecision {
667
877
  *
668
878
  * What each rung then does is decided in `decideToolApproval`, not here:
669
879
  * • `bypass` — deny list, then approve without prompting or rating.
670
- * • `read-only`/`write` — deny list, allow-list, else escalate to the human.
671
- * • `auto-safe`/`full-auto` — deny list, allow-list, then the rater.
672
- * • With the shell tool disabled — or on a non-dev-tools command (chat/api/…) — nothing is gated
673
- * and nothing is announced.
880
+ * • `manual`/`write` — deny list, allow-list, else escalate to the human.
881
+ * • `assisted`/`auto` — deny list, allow-list, then the rater.
882
+ *
883
+ * **This decides the SHELL's gating only, and it is not the whole gated set.** With the shell tool
884
+ * disabled — or on a non-dev-tools command (chat/api/…) — nothing about the shell is gated and
885
+ * nothing is announced, but at `manual` and `write` {@link resolveGatedToolNames} still gates
886
+ * every bound tool the rung does not auto-grant, so an MCP call in a plain `chat` session is
887
+ * escalated there. Read `gateShell` as "does the shell need the interrupt", never as "is the
888
+ * interrupt needed at all".
674
889
  *
675
890
  * Shell enablement itself is resolved through {@link getEffectiveDevToolsConfig} +
676
891
  * {@link isShellToolEnabled}, so the gate stays in lockstep with where `GthDevToolkit` actually