@gaunt-sloth/core 2.0.0-alpha.9 → 2.0.0-beta.0

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 (275) hide show
  1. package/.gsloth.review.md +2 -0
  2. package/README.md +71 -20
  3. package/dist/config/colour.d.ts +38 -0
  4. package/dist/config/colour.js +36 -0
  5. package/dist/config/colour.js.map +1 -0
  6. package/dist/config/configDiscovery.d.ts +79 -0
  7. package/dist/config/configDiscovery.js +80 -0
  8. package/dist/config/configDiscovery.js.map +1 -0
  9. package/dist/config/defaults.d.ts +20 -20
  10. package/dist/config/defaults.js +10 -8
  11. package/dist/config/defaults.js.map +1 -1
  12. package/dist/config/filesystem-tools.d.ts +41 -0
  13. package/dist/config/filesystem-tools.js +56 -0
  14. package/dist/config/filesystem-tools.js.map +1 -0
  15. package/dist/config/loader.d.ts +171 -19
  16. package/dist/config/loader.js +1054 -144
  17. package/dist/config/loader.js.map +1 -1
  18. package/dist/config/mouse.d.ts +50 -0
  19. package/dist/config/mouse.js +44 -0
  20. package/dist/config/mouse.js.map +1 -0
  21. package/dist/config/profiles.d.ts +68 -0
  22. package/dist/config/profiles.js +93 -0
  23. package/dist/config/profiles.js.map +1 -0
  24. package/dist/config/providerKeys.d.ts +69 -0
  25. package/dist/config/providerKeys.js +69 -0
  26. package/dist/config/providerKeys.js.map +1 -0
  27. package/dist/config/schema.d.ts +2671 -138
  28. package/dist/config/schema.js +1361 -85
  29. package/dist/config/schema.js.map +1 -1
  30. package/dist/config/shell-policy.d.ts +899 -111
  31. package/dist/config/shell-policy.js +800 -70
  32. package/dist/config/shell-policy.js.map +1 -1
  33. package/dist/config/tool-descriptions.d.ts +211 -0
  34. package/dist/config/tool-descriptions.js +272 -0
  35. package/dist/config/tool-descriptions.js.map +1 -0
  36. package/dist/config/types.d.ts +352 -41
  37. package/dist/config/types.js +1 -0
  38. package/dist/config/types.js.map +1 -1
  39. package/dist/config.d.ts +35 -1
  40. package/dist/config.js +16 -1
  41. package/dist/config.js.map +1 -1
  42. package/dist/constants.d.ts +28 -1
  43. package/dist/constants.js +28 -1
  44. package/dist/constants.js.map +1 -1
  45. package/dist/core/GthAbstractAgent.d.ts +166 -11
  46. package/dist/core/GthAbstractAgent.js +484 -45
  47. package/dist/core/GthAbstractAgent.js.map +1 -1
  48. package/dist/core/GthAgentRunner.d.ts +543 -57
  49. package/dist/core/GthAgentRunner.js +1494 -140
  50. package/dist/core/GthAgentRunner.js.map +1 -1
  51. package/dist/core/GthLangChainAgent.d.ts +117 -2
  52. package/dist/core/GthLangChainAgent.js +602 -29
  53. package/dist/core/GthLangChainAgent.js.map +1 -1
  54. package/dist/core/approvals/annotations.d.ts +122 -0
  55. package/dist/core/approvals/annotations.js +137 -0
  56. package/dist/core/approvals/annotations.js.map +1 -0
  57. package/dist/core/approvals/grants.d.ts +216 -0
  58. package/dist/core/approvals/grants.js +469 -0
  59. package/dist/core/approvals/grants.js.map +1 -0
  60. package/dist/core/approvals/matcher.d.ts +202 -0
  61. package/dist/core/approvals/matcher.js +267 -0
  62. package/dist/core/approvals/matcher.js.map +1 -0
  63. package/dist/core/approvals/mcpSubjects.d.ts +40 -0
  64. package/dist/core/approvals/mcpSubjects.js +99 -0
  65. package/dist/core/approvals/mcpSubjects.js.map +1 -0
  66. package/dist/core/approvals/promptHeader.d.ts +28 -0
  67. package/dist/core/approvals/promptHeader.js +62 -0
  68. package/dist/core/approvals/promptHeader.js.map +1 -0
  69. package/dist/core/approvals/toolAnnotationSources.d.ts +105 -0
  70. package/dist/core/approvals/toolAnnotationSources.js +277 -0
  71. package/dist/core/approvals/toolAnnotationSources.js.map +1 -0
  72. package/dist/core/approvals/toolHost.d.ts +46 -0
  73. package/dist/core/approvals/toolHost.js +108 -0
  74. package/dist/core/approvals/toolHost.js.map +1 -0
  75. package/dist/core/debugCapture.d.ts +74 -0
  76. package/dist/core/debugCapture.js +100 -0
  77. package/dist/core/debugCapture.js.map +1 -0
  78. package/dist/core/gthLeanAgentFactory.d.ts +4 -4
  79. package/dist/core/gthLeanAgentFactory.js +4 -4
  80. package/dist/core/launchBanner.d.ts +127 -0
  81. package/dist/core/launchBanner.js +414 -0
  82. package/dist/core/launchBanner.js.map +1 -0
  83. package/dist/core/modelLabel.d.ts +19 -0
  84. package/dist/core/modelLabel.js +26 -0
  85. package/dist/core/modelLabel.js.map +1 -0
  86. package/dist/core/plainToolIndication.d.ts +15 -0
  87. package/dist/core/plainToolIndication.js +174 -0
  88. package/dist/core/plainToolIndication.js.map +1 -0
  89. package/dist/core/reasoningBlocks.d.ts +65 -0
  90. package/dist/core/reasoningBlocks.js +103 -0
  91. package/dist/core/reasoningBlocks.js.map +1 -0
  92. package/dist/core/refusal.d.ts +53 -0
  93. package/dist/core/refusal.js +133 -0
  94. package/dist/core/refusal.js.map +1 -0
  95. package/dist/core/runHeader.d.ts +38 -0
  96. package/dist/core/runHeader.js +42 -0
  97. package/dist/core/runHeader.js.map +1 -0
  98. package/dist/core/runStats.d.ts +14 -3
  99. package/dist/core/runStats.js +48 -3
  100. package/dist/core/runStats.js.map +1 -1
  101. package/dist/core/shell/ShellCommandFailedError.d.ts +3 -4
  102. package/dist/core/shell/ShellCommandFailedError.js +3 -4
  103. package/dist/core/shell/ShellCommandFailedError.js.map +1 -1
  104. package/dist/core/shell/abstention.d.ts +88 -0
  105. package/dist/core/shell/abstention.js +184 -0
  106. package/dist/core/shell/abstention.js.map +1 -0
  107. package/dist/core/shell/approvalCapture.d.ts +271 -0
  108. package/dist/core/shell/approvalCapture.js +108 -0
  109. package/dist/core/shell/approvalCapture.js.map +1 -0
  110. package/dist/core/shell/approvalStop.d.ts +123 -0
  111. package/dist/core/shell/approvalStop.js +269 -0
  112. package/dist/core/shell/approvalStop.js.map +1 -0
  113. package/dist/core/shell/arity.d.ts +6 -0
  114. package/dist/core/shell/arity.js +20 -6
  115. package/dist/core/shell/arity.js.map +1 -1
  116. package/dist/core/shell/denylist.d.ts +11 -0
  117. package/dist/core/shell/denylist.js +37 -0
  118. package/dist/core/shell/denylist.js.map +1 -0
  119. package/dist/core/shell/escalationSeverity.d.ts +141 -0
  120. package/dist/core/shell/escalationSeverity.js +89 -0
  121. package/dist/core/shell/escalationSeverity.js.map +1 -0
  122. package/dist/core/shell/framing.d.ts +190 -0
  123. package/dist/core/shell/framing.js +633 -0
  124. package/dist/core/shell/framing.js.map +1 -0
  125. package/dist/core/shell/hardline.d.ts +103 -0
  126. package/dist/core/shell/hardline.js +780 -0
  127. package/dist/core/shell/hardline.js.map +1 -0
  128. package/dist/core/shell/negotiation.d.ts +328 -0
  129. package/dist/core/shell/negotiation.js +488 -0
  130. package/dist/core/shell/negotiation.js.map +1 -0
  131. package/dist/core/shell/normalize.d.ts +44 -4
  132. package/dist/core/shell/normalize.js +61 -7
  133. package/dist/core/shell/normalize.js.map +1 -1
  134. package/dist/core/shell/openWorld.d.ts +263 -0
  135. package/dist/core/shell/openWorld.js +1188 -0
  136. package/dist/core/shell/openWorld.js.map +1 -0
  137. package/dist/core/shell/rater.d.ts +873 -0
  138. package/dist/core/shell/rater.js +1454 -0
  139. package/dist/core/shell/rater.js.map +1 -0
  140. package/dist/core/shell/raterModel.d.ts +41 -0
  141. package/dist/core/shell/raterModel.js +51 -0
  142. package/dist/core/shell/raterModel.js.map +1 -0
  143. package/dist/core/shell/raterVocabulary.d.ts +121 -0
  144. package/dist/core/shell/raterVocabulary.js +116 -0
  145. package/dist/core/shell/raterVocabulary.js.map +1 -0
  146. package/dist/core/shell/rejection.d.ts +69 -0
  147. package/dist/core/shell/rejection.js +38 -0
  148. package/dist/core/shell/rejection.js.map +1 -0
  149. package/dist/core/toolCallRepair/grammar.d.ts +41 -0
  150. package/dist/core/toolCallRepair/grammar.js +116 -0
  151. package/dist/core/toolCallRepair/grammar.js.map +1 -0
  152. package/dist/core/toolCallRepair/index.d.ts +2 -0
  153. package/dist/core/toolCallRepair/index.js +7 -0
  154. package/dist/core/toolCallRepair/index.js.map +1 -0
  155. package/dist/core/toolCallRepair/payload.d.ts +36 -0
  156. package/dist/core/toolCallRepair/payload.js +341 -0
  157. package/dist/core/toolCallRepair/payload.js.map +1 -0
  158. package/dist/core/toolCallRepair/promote.d.ts +45 -0
  159. package/dist/core/toolCallRepair/promote.js +90 -0
  160. package/dist/core/toolCallRepair/promote.js.map +1 -0
  161. package/dist/core/toolDisplay.d.ts +123 -0
  162. package/dist/core/toolDisplay.js +451 -0
  163. package/dist/core/toolDisplay.js.map +1 -0
  164. package/dist/core/toolOutputChannel.d.ts +95 -0
  165. package/dist/core/toolOutputChannel.js +165 -0
  166. package/dist/core/toolOutputChannel.js.map +1 -0
  167. package/dist/core/types.d.ts +349 -16
  168. package/dist/core/types.js.map +1 -1
  169. package/dist/history/historyFormat.d.ts +12 -3
  170. package/dist/history/historyFormat.js +50 -8
  171. package/dist/history/historyFormat.js.map +1 -1
  172. package/dist/history/historyStore.d.ts +77 -0
  173. package/dist/history/historyStore.js +173 -6
  174. package/dist/history/historyStore.js.map +1 -1
  175. package/dist/history/recordSession.d.ts +10 -1
  176. package/dist/history/recordSession.js +27 -0
  177. package/dist/history/recordSession.js.map +1 -1
  178. package/dist/providers/anthropic.js +12 -0
  179. package/dist/providers/anthropic.js.map +1 -1
  180. package/dist/providers/configurationPassthrough.d.ts +107 -0
  181. package/dist/providers/configurationPassthrough.js +148 -0
  182. package/dist/providers/configurationPassthrough.js.map +1 -0
  183. package/dist/providers/geminiSchemaSanitizer.d.ts +55 -0
  184. package/dist/providers/geminiSchemaSanitizer.js +347 -0
  185. package/dist/providers/geminiSchemaSanitizer.js.map +1 -0
  186. package/dist/providers/geminiThinking.d.ts +60 -0
  187. package/dist/providers/geminiThinking.js +92 -0
  188. package/dist/providers/geminiThinking.js.map +1 -0
  189. package/dist/providers/google-genai.js +18 -1
  190. package/dist/providers/google-genai.js.map +1 -1
  191. package/dist/providers/groq.js +12 -0
  192. package/dist/providers/groq.js.map +1 -1
  193. package/dist/providers/huggingface.d.ts +25 -0
  194. package/dist/providers/huggingface.js +69 -0
  195. package/dist/providers/huggingface.js.map +1 -0
  196. package/dist/providers/modelCatalog.d.ts +109 -0
  197. package/dist/providers/modelCatalog.js +245 -0
  198. package/dist/providers/modelCatalog.js.map +1 -0
  199. package/dist/providers/modelDiscovery.d.ts +99 -5
  200. package/dist/providers/modelDiscovery.js +191 -35
  201. package/dist/providers/modelDiscovery.js.map +1 -1
  202. package/dist/providers/ollama.d.ts +18 -4
  203. package/dist/providers/ollama.js +67 -37
  204. package/dist/providers/ollama.js.map +1 -1
  205. package/dist/providers/openai.js +34 -0
  206. package/dist/providers/openai.js.map +1 -1
  207. package/dist/providers/openrouter.d.ts +26 -4
  208. package/dist/providers/openrouter.js +83 -26
  209. package/dist/providers/openrouter.js.map +1 -1
  210. package/dist/providers/vertexai.js +19 -1
  211. package/dist/providers/vertexai.js.map +1 -1
  212. package/dist/providers/xai.js +20 -0
  213. package/dist/providers/xai.js.map +1 -1
  214. package/dist/runtime/askStructured.d.ts +105 -0
  215. package/dist/runtime/askStructured.js +120 -0
  216. package/dist/runtime/askStructured.js.map +1 -0
  217. package/dist/runtime/conversation.d.ts +64 -0
  218. package/dist/runtime/conversation.js +171 -0
  219. package/dist/runtime/conversation.js.map +1 -0
  220. package/dist/runtime/singleShot.d.ts +37 -6
  221. package/dist/runtime/singleShot.js +113 -67
  222. package/dist/runtime/singleShot.js.map +1 -1
  223. package/dist/runtime/structuredOutput.d.ts +104 -0
  224. package/dist/runtime/structuredOutput.js +393 -0
  225. package/dist/runtime/structuredOutput.js.map +1 -0
  226. package/dist/utils/ProgressIndicator.d.ts +21 -0
  227. package/dist/utils/ProgressIndicator.js +30 -3
  228. package/dist/utils/ProgressIndicator.js.map +1 -1
  229. package/dist/utils/aiignoreUtils.js.map +1 -1
  230. package/dist/utils/binaryOutputUtils.js.map +1 -1
  231. package/dist/utils/consoleUtils.d.ts +95 -0
  232. package/dist/utils/consoleUtils.js +112 -2
  233. package/dist/utils/consoleUtils.js.map +1 -1
  234. package/dist/utils/crashHandler.d.ts +87 -0
  235. package/dist/utils/crashHandler.js +128 -0
  236. package/dist/utils/crashHandler.js.map +1 -0
  237. package/dist/utils/debugDump.d.ts +134 -0
  238. package/dist/utils/debugDump.js +381 -0
  239. package/dist/utils/debugDump.js.map +1 -0
  240. package/dist/utils/debugUtils.d.ts +13 -4
  241. package/dist/utils/debugUtils.js +36 -13
  242. package/dist/utils/debugUtils.js.map +1 -1
  243. package/dist/utils/displayWidth.d.ts +53 -0
  244. package/dist/utils/displayWidth.js +195 -0
  245. package/dist/utils/displayWidth.js.map +1 -0
  246. package/dist/utils/fileUtils.js.map +1 -1
  247. package/dist/utils/globalConfigUtils.d.ts +14 -2
  248. package/dist/utils/globalConfigUtils.js +22 -4
  249. package/dist/utils/globalConfigUtils.js.map +1 -1
  250. package/dist/utils/llmUtils.d.ts +39 -8
  251. package/dist/utils/llmUtils.js +76 -8
  252. package/dist/utils/llmUtils.js.map +1 -1
  253. package/dist/utils/redactSecrets.d.ts +63 -0
  254. package/dist/utils/redactSecrets.js +286 -0
  255. package/dist/utils/redactSecrets.js.map +1 -0
  256. package/dist/utils/systemPromptNotes.d.ts +222 -0
  257. package/dist/utils/systemPromptNotes.js +338 -0
  258. package/dist/utils/systemPromptNotes.js.map +1 -0
  259. package/dist/utils/systemUtils.d.ts +18 -1
  260. package/dist/utils/systemUtils.js +38 -3
  261. package/dist/utils/systemUtils.js.map +1 -1
  262. package/dist/utils/toolMatching.d.ts +30 -0
  263. package/dist/utils/toolMatching.js +44 -0
  264. package/dist/utils/toolMatching.js.map +1 -0
  265. package/dist/utils/untrustedText.d.ts +86 -0
  266. package/dist/utils/untrustedText.js +101 -0
  267. package/dist/utils/untrustedText.js.map +1 -0
  268. package/package.json +21 -7
  269. package/schema/gsloth-config.schema.json +1921 -326
  270. package/dist/core/shell/allowlist.d.ts +0 -75
  271. package/dist/core/shell/allowlist.js +0 -187
  272. package/dist/core/shell/allowlist.js.map +0 -1
  273. package/dist/core/shell/judge.d.ts +0 -161
  274. package/dist/core/shell/judge.js +0 -261
  275. package/dist/core/shell/judge.js.map +0 -1
@@ -12,6 +12,12 @@ import type { CommandLineConfigOverrides, ConsoleLevelInput, GthConfig, RawGthCo
12
12
  *
13
13
  * A `customConfigPath` override wins outright (no walking).
14
14
  *
15
+ * NOTE (identity profile): with an `identityProfile` set, each dir's per-format resolver
16
+ * ({@link resolveConfigPath}) tries the profile path `.gsloth/.gsloth-settings/<profile>/<file>`
17
+ * but FALLS BACK to the plain `<dir>/<file>` when the profile file is absent. So a match here does
18
+ * NOT prove the named profile itself has a config — it may be a plain (non-profile) config. Use
19
+ * {@link resolveIdentityProfileConfigPath} when you need to know a profile specifically resolved.
20
+ *
15
21
  * @returns the matched `{ dir, path }`, or `undefined` when no project config exists within the
16
22
  * boundary.
17
23
  */
@@ -19,6 +25,34 @@ export declare function findProjectConfigPath(commandLineConfigOverrides: Comman
19
25
  dir: string;
20
26
  path: string;
21
27
  } | undefined;
28
+ /**
29
+ * STRICT existence check for an EXPLICITLY-named identity profile: does
30
+ * `.gsloth/.gsloth-settings/<identityProfile>/<config>` resolve to a real config file anywhere in
31
+ * the same up-tree search {@link findProjectConfigPath} walks? Returns the resolved profile config
32
+ * path (nearest dir, then format precedence) when the profile has its OWN config, `undefined`
33
+ * otherwise.
34
+ *
35
+ * Unlike {@link findProjectConfigPath}, it matches ONLY the profile-specific path — it NEVER falls
36
+ * through to a plain `<dir>/<config>` and NEVER falls back to the global config. That strictness is
37
+ * the whole point: it lets a caller distinguish "this named profile really exists" from "a bare
38
+ * config happens to be present / a global config exists," a distinction the loader's fall-through
39
+ * deliberately blurs.
40
+ *
41
+ * PURE PREDICATE — never throws, never calls `exit`, so it can be asked the question without
42
+ * committing to an outcome. {@link initConfig} uses it to enforce that an explicitly-named profile
43
+ * really exists (raising a catchable {@link ConfigDiscoveryError} when it does not), and callers
44
+ * that want to CLASSIFY rather than fail — BATCH-12's identity matrix checks every declared identity
45
+ * up front so one message can name them all — ask it directly. A blank/whitespace-only name counts
46
+ * as "no profile" → `undefined`.
47
+ *
48
+ * @param identityProfile The explicitly-requested identity profile name.
49
+ * @param options CFG-56 — `globalOnly` searches `~/.gsloth/.gsloth-settings/<name>/` INSTEAD of
50
+ * the up-tree project walk, for a `--global` run.
51
+ * @returns The resolved profile config path, or `undefined` when the profile has no config.
52
+ */
53
+ export declare function resolveIdentityProfileConfigPath(identityProfile: string, options?: {
54
+ globalOnly?: boolean;
55
+ }): string | undefined;
22
56
  /**
23
57
  * Loads the global gsloth config (if present) from the global `~/.gsloth` folder.
24
58
  *
@@ -27,16 +61,58 @@ export declare function findProjectConfigPath(commandLineConfigOverrides: Comman
27
61
  * user-controlled layer (still above {@link DEFAULT_CONFIG}).
28
62
  *
29
63
  * Lookup order within the global folder, first match wins:
30
- * `.gsloth.config.json` -> `.gsloth.config.js` -> `.gsloth.config.mjs`
64
+ * `.gsloth.config.json` -> `.gsloth.config.jsonc` -> `.gsloth.config.js` -> `.gsloth.config.mjs`
31
65
  *
32
66
  * Absence of every variant is a no-op: returns `undefined` so behaviour is unchanged.
33
67
  *
34
68
  * NOTE: secrets (API keys) may live in this file; this function must never log its
35
69
  * contents. Only non-sensitive diagnostics (the resolved path / parse failure) are emitted.
36
70
  *
71
+ * @param options CFG-56 — `identityProfile` relocates the lookup to
72
+ * `~/.gsloth/.gsloth-settings/<name>/` and `globalOnly` scopes the profile names this layer refers
73
+ * to. Both are set ONLY for a `--global` run; see {@link globalLayerProfile}.
37
74
  * @returns The raw global config object, or `undefined` when no global config exists.
38
75
  */
39
- export declare function loadGlobalRawConfig(): Promise<Partial<RawGthConfig> | undefined>;
76
+ export declare function loadGlobalRawConfig(options?: {
77
+ identityProfile?: string;
78
+ globalOnly?: boolean;
79
+ }): Promise<Partial<RawGthConfig> | undefined>;
80
+ /**
81
+ * GS2-41 — resolve a named profile's `extends` inheritance into a single composed raw config,
82
+ * riding the SAME GS2-1 deep-merge the config LAYERS use (NO second merge engine). When the given
83
+ * profile config declares `extends: "<base>"`, the base profile's config resolves FIRST
84
+ * (recursively — a base may itself extend another, so base-of-base resolves first), then this
85
+ * profile's own fields merge on top with last-wins semantics: the child overrides the base, nested
86
+ * objects merge, arrays REPLACE except the additive-array fields (`allowDirs`, `aiignore.patterns`
87
+ * and the three `approvals` rule lists, see {@link isAdditiveArrayField}) which accumulate
88
+ * base+child. The `extends` key itself is consumed and never leaks into the composed output.
89
+ *
90
+ * A config WITHOUT `extends` is returned UNCHANGED — every non-inheriting config (the vast
91
+ * majority) is untouched and behaves exactly as before.
92
+ *
93
+ * Composition is CONFINED to the profile-dir layer: it produces the single raw config that then
94
+ * acts as the project-file layer the global config underlays and CLI flags overlay, preserving
95
+ * GS2-33's outer precedence `CLI flags > profile (base+child composed) > global > defaults`. It is
96
+ * therefore invoked in {@link initConfig} on the loaded project/profile config BEFORE
97
+ * {@link applyGlobalConfigBase}.
98
+ *
99
+ * The base profile is discovered with {@link resolveIdentityProfileConfigPath} (the SAME strict
100
+ * up-tree profile walk `--profile` uses), so `extends` names a profile exactly as a user selects
101
+ * one; a name with no config dir is a hard, clearly-named error.
102
+ *
103
+ * CYCLE GUARD: the chain of profile NAMES is tracked (seeded with the selected profile's own name);
104
+ * because `extends` is single-valued the chain is linear, so a repeated name — `A extends B extends
105
+ * A`, or a self-extend — is an unambiguous cycle and fails fast with a clear error NAMING the cycle,
106
+ * never infinite-looping / stack-overflowing. A hard {@link MAX_EXTENDS_CHAIN_DEPTH} cap backstops
107
+ * it regardless of how the base path was derived.
108
+ *
109
+ * @param rawConfig the just-loaded, schema-validated raw config that MAY declare `extends`.
110
+ * @param profileLabel the selected profile's own name (for cycle detection + messages); undefined
111
+ * for a plain (non-profile) project config.
112
+ */
113
+ export declare function resolveConfigExtends(rawConfig: Record<string, unknown>, profileLabel: string | undefined, options?: {
114
+ globalOnly?: boolean;
115
+ }): Promise<Record<string, unknown>>;
40
116
  /**
41
117
  * ORDERING INVARIANT (GS2-11): detection ({@link hasProjectConfig}/{@link hasAnyConfig}) MUST run
42
118
  * before {@link initConfig} in a given process. Both resolve cwd-level candidates via
@@ -48,7 +124,7 @@ export declare function loadGlobalRawConfig(): Promise<Partial<RawGthConfig> | u
48
124
  * order is ever introduced, decouple discovery's cwd-branch from `getProjectDir()`.
49
125
  */
50
126
  /**
51
- * Returns true when a project-level config file (json/js/mjs) exists for the given
127
+ * Returns true when a project-level config file (json/jsonc/js/mjs) exists for the given
52
128
  * overrides. Honours `customConfigPath` and the active identity profile so the check
53
129
  * matches exactly what {@link initConfig} would attempt to load.
54
130
  *
@@ -58,12 +134,42 @@ export declare function loadGlobalRawConfig(): Promise<Partial<RawGthConfig> | u
58
134
  export declare function hasProjectConfig(commandLineConfigOverrides: CommandLineConfigOverrides): boolean;
59
135
  /**
60
136
  * CFG-10 — true when ANY usable configuration is present, either a project config file
61
- * (json/js/mjs) or a standalone global config (`~/.gsloth/.gsloth.config.*`). When this
137
+ * (json/jsonc/js/mjs) or a standalone global config (`~/.gsloth/.gsloth.config.*`). When this
62
138
  * returns false the caller should run the first-run dialog instead of erroring.
63
139
  *
64
140
  * Reuses CFG-8's project + global detection so the two paths can never disagree.
65
141
  */
66
142
  export declare function hasAnyConfig(commandLineConfigOverrides: CommandLineConfigOverrides): Promise<boolean>;
143
+ /**
144
+ * CFG-37 — the layered value of the top-level `tui` config key, read BEFORE a session picks its
145
+ * surface. `chat`/`code` choose between the Ink TUI and the readline session in the app's
146
+ * `startSession` dispatcher, and each surface then loads its own config via {@link initConfig} — so
147
+ * at the moment of the choice there is no resolved {@link GthConfig} to consult, and this is the
148
+ * seam that supplies the one key the choice needs.
149
+ *
150
+ * Layering matches a run: the discovered PROJECT layer wins over the GLOBAL one, and a layer that
151
+ * does not set `tui` defers to the next rather than overriding it with `undefined`. A scalar needs
152
+ * no deep merge, so this reads the two layers and picks — it does not fork the merge engine.
153
+ *
154
+ * QUIET and fail-soft for the layers it reads ITSELF: it does not validate them and does not
155
+ * `exit` on a malformed one, because the caller runs moments before {@link initConfig}, which
156
+ * validates every layer and reports the very same problem — warning twice about one file is worse
157
+ * than not warning here. A failed read resolves to `undefined`, i.e. "nobody set it", and the
158
+ * surface auto-detects exactly as it does for a run with no config.
159
+ *
160
+ * ONE EXCEPTION, and it is deliberate: a `tui` may be INHERITED through a GS2-41 profile `extends`
161
+ * chain, so this walks that chain via the SHARED {@link resolveConfigExtends} rather than forking
162
+ * it — and that traversal owns its own reporting. It validates each base layer (so a base's own
163
+ * unknown-key warning can appear here as well as from `initConfig`) and hard-`exit`s on a cycle, a
164
+ * missing base or a malformed base. What the user sees is unchanged — `initConfig` exits on the
165
+ * same chain with the same message a moment later — but it now happens EARLIER, at surface
166
+ * selection rather than at config load. Forking the walk to silence it would mean a second
167
+ * inheritance engine; ignoring `extends` would mean silently dropping an inherited `tui`.
168
+ *
169
+ * Ordering: this is DETECTION, so per the GS2-11 invariant above it must run before any
170
+ * {@link initConfig} in the process — as it does, alongside {@link hasAnyConfig} in `startSession`.
171
+ */
172
+ export declare function loadConfiguredTui(commandLineConfigOverrides: CommandLineConfigOverrides): Promise<boolean | undefined>;
67
173
  /**
68
174
  * Initialize configuration by loading from available config files
69
175
  * @returns The loaded GthConfig
@@ -78,32 +184,78 @@ export declare function initConfig(commandLineConfigOverrides: CommandLineConfig
78
184
  export declare function tryJsonConfig(jsonConfig: RawGthConfig, commandLineConfigOverrides: CommandLineConfigOverrides): Promise<GthConfig>;
79
185
  /**
80
186
  * Resolve a fully-merged {@link GthConfig} from a partial config + CLI overrides WITHOUT
81
- * any global side effects (a pure transform). It deep-merges defaults, applies CLI overrides,
82
- * resolves the numeric `consoleLevel` (warning + defaulting to INFO on an invalid value), and
83
- * computes `canInterruptInferenceWithEsc`. The process-global setters (`setUseColour` /
187
+ * any global side effects. It deep-merges defaults, applies CLI overrides, resolves the numeric
188
+ * `consoleLevel` (warning + defaulting to INFO on an invalid value), and computes
189
+ * `canInterruptInferenceWithEsc` and `useColour`. The process-global setters (`setUseColour` /
84
190
  * `setConsoleLevel`) are applied separately by {@link mergeConfig}, so this function can be
85
191
  * reasoned about and reused without touching global state.
192
+ *
193
+ * It WRITES nothing globally, but it does READ the environment: `canInterruptInferenceWithEsc`
194
+ * consults stdin's TTY status, and (CFG-30) `useColour` consults `FORCE_COLOR`, `NO_COLOR` and
195
+ * stdout's TTY status. So it is deterministic for a given environment rather than a pure function
196
+ * of its arguments — a test that pins a resolved config should declare the terminal and the colour
197
+ * environment it expects in its setup. The ladder itself is a pure helper
198
+ * ({@link resolveUseColour}) so it can be tested rung by rung without process globals.
86
199
  */
87
200
  export declare function resolveConfig(partialConfig: Omit<Partial<GthConfig>, 'consoleLevel'> & {
88
201
  consoleLevel?: ConsoleLevelInput;
89
202
  }, commandLineConfigOverrides: CommandLineConfigOverrides): GthConfig;
90
203
  /**
91
- * The outcome of `gth config validate`: whether a config was found, where, and whether it
92
- * validates. Pure/read-side it neither builds an LLM nor mutates process globals, so it can
93
- * report a verdict without the run-path's side effects. The command layer turns this into
94
- * console output + an exit code.
204
+ * One config LAYER's validation outcome inside a {@link ConfigValidationReport}: the pure
205
+ * read-side result ({@link validateRawGthConfig}) plus the source label so a consumer can name
206
+ * WHICH file carried a warning/error (the project path, or `"<name> (global)"`).
95
207
  */
96
- export interface ConfigValidationReport extends RawConfigValidationResult {
97
- /** False when no project or global config exists within the discovery boundary. */
208
+ export interface ConfigLayerValidationReport extends RawConfigValidationResult {
209
+ /** The resolved config path (project layer) or `"<name> (global)"` (global layer). */
210
+ sourceLabel: string;
211
+ }
212
+ /**
213
+ * The outcome of `gth config validate`: whether any config was found, and the per-layer verdict
214
+ * for EVERY layer a run would validate. Pure/read-side — it neither builds an LLM nor mutates
215
+ * process globals, so it can report a verdict without the run-path's side effects. The command
216
+ * layer turns this into console output + an exit code.
217
+ *
218
+ * GS2-29 — `validateConfig` mirrors the layer set `initConfig` validates: the discovered PROJECT
219
+ * layer (if any) AND the GLOBAL layer (if any). A run validates both and exits(1) if EITHER
220
+ * carries a problem, so a removed shape in the global config (with a clean project config) shows
221
+ * up here exactly as the run would reject it. Both layers are kept in {@link layers} (in run
222
+ * order) so the offending file is always identifiable.
223
+ */
224
+ export interface ConfigValidationReport {
225
+ /** False when neither a project nor a global config exists within the discovery boundary. */
98
226
  found: boolean;
99
- /** The resolved config path (or `"<name> (global)"`) when one was found. */
100
- sourceLabel?: string;
227
+ /** True only when a config was found AND every present layer validates OK. */
228
+ ok: boolean;
229
+ /**
230
+ * Each config layer a run would load + validate, in run order: the discovered PROJECT layer
231
+ * (if any) first, then the GLOBAL layer (if any). Empty when `found` is false.
232
+ */
233
+ layers: ConfigLayerValidationReport[];
101
234
  }
102
235
  /**
103
236
  * Locate and validate the effective raw config against the schema WITHOUT building the LLM
104
- * or merging defaults (the read-side of GS2-1). Honours `--config`, up-tree discovery, and
105
- * the identity profile via {@link findProjectConfigPath}, falling back to a standalone global
106
- * config (CFG-8 order) when no project config exists. A JSONC/module parse failure is thrown
107
- * to the caller (surfaced as a clear "invalid config" error + non-zero exit).
237
+ * or merging defaults (the read-side of GS2-1). Honours `--config`, up-tree discovery, and the
238
+ * identity profile via {@link findProjectConfigPath}.
239
+ *
240
+ * GS2-29 — validates the SAME layer set a real run does: the discovered PROJECT layer (if any)
241
+ * AND the GLOBAL layer (if any), mirroring `initConfig`'s `validateRawConfigLayer(project)` +
242
+ * `applyGlobalConfigBase` → `loadGlobalRawConfig(global)`. Each present layer is validated
243
+ * independently ({@link validateRawGthConfig}) and its outcome recorded in {@link
244
+ * ConfigValidationReport.layers}, so a removed shape in EITHER file is reported (labelled with
245
+ * its source) rather than under-reported.
246
+ *
247
+ * A PROJECT-layer JSONC/module parse failure is thrown to the caller (surfaced as a clear
248
+ * "invalid config" error + non-zero exit). A GLOBAL-layer parse failure is treated as an absent
249
+ * global (no layer added) but is surfaced with a `displayWarning` — exactly as a run does (it
250
+ * warns the user while ignoring the broken global's value) — see {@link
251
+ * loadGlobalRawConfigUnvalidated}.
252
+ *
253
+ * GS2-73 — for the PROJECT layer it also walks the GS2-41 profile `extends` chain (via the SAME
254
+ * {@link composeExtends}/{@link resolveExtendsChain} the run path uses), so a cycle or a missing
255
+ * base — which fail a real run — is reported here as a not-ok layer instead of passing OK and only
256
+ * failing at run time. The GLOBAL layer is walked on exactly the branch a run walks it: when NO
257
+ * project layer was discovered, so the global config is what `initConfig` loads and resolves
258
+ * `extends` on. With a project layer present the run underlays the raw global config
259
+ * ({@link applyGlobalConfigBase}) and never resolves its `extends`, so neither does this.
108
260
  */
109
261
  export declare function validateConfig(commandLineConfigOverrides: CommandLineConfigOverrides): Promise<ConfigValidationReport>;