@gaunt-sloth/core 2.0.0-alpha.23 → 2.0.0-alpha.25

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 (154) hide show
  1. package/README.md +43 -18
  2. package/dist/config/colour.d.ts +38 -0
  3. package/dist/config/colour.js +36 -0
  4. package/dist/config/colour.js.map +1 -0
  5. package/dist/config/defaults.d.ts +6 -7
  6. package/dist/config/defaults.js +4 -8
  7. package/dist/config/defaults.js.map +1 -1
  8. package/dist/config/loader.d.ts +50 -3
  9. package/dist/config/loader.js +345 -29
  10. package/dist/config/loader.js.map +1 -1
  11. package/dist/config/mouse.d.ts +50 -0
  12. package/dist/config/mouse.js +44 -0
  13. package/dist/config/mouse.js.map +1 -0
  14. package/dist/config/profiles.d.ts +68 -0
  15. package/dist/config/profiles.js +93 -0
  16. package/dist/config/profiles.js.map +1 -0
  17. package/dist/config/schema.d.ts +2441 -116
  18. package/dist/config/schema.js +930 -19
  19. package/dist/config/schema.js.map +1 -1
  20. package/dist/config/shell-policy.d.ts +466 -116
  21. package/dist/config/shell-policy.js +273 -62
  22. package/dist/config/shell-policy.js.map +1 -1
  23. package/dist/config/tool-descriptions.d.ts +165 -0
  24. package/dist/config/tool-descriptions.js +229 -0
  25. package/dist/config/tool-descriptions.js.map +1 -0
  26. package/dist/config/types.d.ts +139 -6
  27. package/dist/config/types.js.map +1 -1
  28. package/dist/config.d.ts +4 -0
  29. package/dist/config.js +4 -0
  30. package/dist/config.js.map +1 -1
  31. package/dist/core/GthAbstractAgent.d.ts +85 -2
  32. package/dist/core/GthAbstractAgent.js +194 -1
  33. package/dist/core/GthAbstractAgent.js.map +1 -1
  34. package/dist/core/GthAgentRunner.d.ts +341 -58
  35. package/dist/core/GthAgentRunner.js +857 -149
  36. package/dist/core/GthAgentRunner.js.map +1 -1
  37. package/dist/core/GthLangChainAgent.d.ts +99 -0
  38. package/dist/core/GthLangChainAgent.js +388 -3
  39. package/dist/core/GthLangChainAgent.js.map +1 -1
  40. package/dist/core/approvals/annotations.d.ts +122 -0
  41. package/dist/core/approvals/annotations.js +137 -0
  42. package/dist/core/approvals/annotations.js.map +1 -0
  43. package/dist/core/approvals/grants.d.ts +216 -0
  44. package/dist/core/approvals/grants.js +469 -0
  45. package/dist/core/approvals/grants.js.map +1 -0
  46. package/dist/core/approvals/matcher.d.ts +202 -0
  47. package/dist/core/approvals/matcher.js +267 -0
  48. package/dist/core/approvals/matcher.js.map +1 -0
  49. package/dist/core/approvals/mcpSubjects.d.ts +40 -0
  50. package/dist/core/approvals/mcpSubjects.js +99 -0
  51. package/dist/core/approvals/mcpSubjects.js.map +1 -0
  52. package/dist/core/approvals/toolAnnotationSources.d.ts +105 -0
  53. package/dist/core/approvals/toolAnnotationSources.js +277 -0
  54. package/dist/core/approvals/toolAnnotationSources.js.map +1 -0
  55. package/dist/core/approvals/toolHost.d.ts +46 -0
  56. package/dist/core/approvals/toolHost.js +108 -0
  57. package/dist/core/approvals/toolHost.js.map +1 -0
  58. package/dist/core/debugCapture.d.ts +16 -0
  59. package/dist/core/debugCapture.js.map +1 -1
  60. package/dist/core/launchBanner.d.ts +120 -0
  61. package/dist/core/launchBanner.js +399 -0
  62. package/dist/core/launchBanner.js.map +1 -0
  63. package/dist/core/plainToolIndication.js +61 -35
  64. package/dist/core/plainToolIndication.js.map +1 -1
  65. package/dist/core/refusal.d.ts +53 -0
  66. package/dist/core/refusal.js +129 -0
  67. package/dist/core/refusal.js.map +1 -0
  68. package/dist/core/shell/approvalStop.d.ts +75 -0
  69. package/dist/core/shell/approvalStop.js +108 -0
  70. package/dist/core/shell/approvalStop.js.map +1 -0
  71. package/dist/core/shell/arity.d.ts +6 -0
  72. package/dist/core/shell/arity.js +20 -6
  73. package/dist/core/shell/arity.js.map +1 -1
  74. package/dist/core/shell/denylist.d.ts +11 -0
  75. package/dist/core/shell/denylist.js +37 -0
  76. package/dist/core/shell/denylist.js.map +1 -0
  77. package/dist/core/shell/normalize.d.ts +41 -1
  78. package/dist/core/shell/normalize.js +58 -4
  79. package/dist/core/shell/normalize.js.map +1 -1
  80. package/dist/core/shell/openWorld.d.ts +138 -0
  81. package/dist/core/shell/openWorld.js +523 -0
  82. package/dist/core/shell/openWorld.js.map +1 -0
  83. package/dist/core/shell/rater.d.ts +560 -0
  84. package/dist/core/shell/rater.js +895 -0
  85. package/dist/core/shell/rater.js.map +1 -0
  86. package/dist/core/shell/raterModel.d.ts +41 -0
  87. package/dist/core/shell/raterModel.js +51 -0
  88. package/dist/core/shell/raterModel.js.map +1 -0
  89. package/dist/core/shell/rejection.d.ts +66 -0
  90. package/dist/core/shell/rejection.js +38 -0
  91. package/dist/core/shell/rejection.js.map +1 -0
  92. package/dist/core/toolCallRepair/grammar.d.ts +41 -0
  93. package/dist/core/toolCallRepair/grammar.js +116 -0
  94. package/dist/core/toolCallRepair/grammar.js.map +1 -0
  95. package/dist/core/toolCallRepair/index.d.ts +2 -0
  96. package/dist/core/toolCallRepair/index.js +7 -0
  97. package/dist/core/toolCallRepair/index.js.map +1 -0
  98. package/dist/core/toolCallRepair/payload.d.ts +36 -0
  99. package/dist/core/toolCallRepair/payload.js +341 -0
  100. package/dist/core/toolCallRepair/payload.js.map +1 -0
  101. package/dist/core/toolCallRepair/promote.d.ts +45 -0
  102. package/dist/core/toolCallRepair/promote.js +90 -0
  103. package/dist/core/toolCallRepair/promote.js.map +1 -0
  104. package/dist/core/toolDisplay.d.ts +14 -1
  105. package/dist/core/toolDisplay.js +69 -12
  106. package/dist/core/toolDisplay.js.map +1 -1
  107. package/dist/core/toolOutputChannel.d.ts +33 -6
  108. package/dist/core/toolOutputChannel.js +61 -8
  109. package/dist/core/toolOutputChannel.js.map +1 -1
  110. package/dist/core/types.d.ts +71 -9
  111. package/dist/core/types.js.map +1 -1
  112. package/dist/providers/geminiSchemaSanitizer.d.ts +6 -3
  113. package/dist/providers/geminiSchemaSanitizer.js +152 -6
  114. package/dist/providers/geminiSchemaSanitizer.js.map +1 -1
  115. package/dist/providers/modelDiscovery.d.ts +18 -4
  116. package/dist/providers/modelDiscovery.js +67 -17
  117. package/dist/providers/modelDiscovery.js.map +1 -1
  118. package/dist/providers/openai.js +34 -0
  119. package/dist/providers/openai.js.map +1 -1
  120. package/dist/runtime/askStructured.d.ts +8 -7
  121. package/dist/runtime/askStructured.js +8 -7
  122. package/dist/runtime/askStructured.js.map +1 -1
  123. package/dist/runtime/conversation.js +89 -76
  124. package/dist/runtime/conversation.js.map +1 -1
  125. package/dist/runtime/singleShot.js +71 -60
  126. package/dist/runtime/singleShot.js.map +1 -1
  127. package/dist/utils/ProgressIndicator.d.ts +21 -0
  128. package/dist/utils/ProgressIndicator.js +30 -3
  129. package/dist/utils/ProgressIndicator.js.map +1 -1
  130. package/dist/utils/consoleUtils.d.ts +30 -0
  131. package/dist/utils/consoleUtils.js +27 -2
  132. package/dist/utils/consoleUtils.js.map +1 -1
  133. package/dist/utils/crashHandler.d.ts +87 -0
  134. package/dist/utils/crashHandler.js +128 -0
  135. package/dist/utils/crashHandler.js.map +1 -0
  136. package/dist/utils/debugDump.d.ts +58 -0
  137. package/dist/utils/debugDump.js +149 -15
  138. package/dist/utils/debugDump.js.map +1 -1
  139. package/dist/utils/llmUtils.d.ts +22 -8
  140. package/dist/utils/llmUtils.js +48 -8
  141. package/dist/utils/llmUtils.js.map +1 -1
  142. package/dist/utils/redactSecrets.js +68 -20
  143. package/dist/utils/redactSecrets.js.map +1 -1
  144. package/dist/utils/systemUtils.d.ts +17 -0
  145. package/dist/utils/systemUtils.js +17 -0
  146. package/dist/utils/systemUtils.js.map +1 -1
  147. package/package.json +5 -2
  148. package/schema/gsloth-config.schema.json +1484 -466
  149. package/dist/core/shell/allowlist.d.ts +0 -75
  150. package/dist/core/shell/allowlist.js +0 -187
  151. package/dist/core/shell/allowlist.js.map +0 -1
  152. package/dist/core/shell/judge.d.ts +0 -161
  153. package/dist/core/shell/judge.js +0 -261
  154. package/dist/core/shell/judge.js.map +0 -1
@@ -0,0 +1,50 @@
1
+ /**
2
+ * TUI-C37 — the single place that decides whether the Ink TUI turns on terminal mouse reporting.
3
+ *
4
+ * Shaped exactly like the colour decision in `colour.ts`: everything the answer depends on arrives
5
+ * as an argument, so the ladder is testable rung by rung without touching process globals.
6
+ *
7
+ * Mouse reporting is ON by default, which is what makes the TUI's clickable affordances
8
+ * discoverable at all. The cost is real and is why the off-ramps below exist: while tracking is on
9
+ * the terminal hands drag events to the application, so its own text selection needs a modifier
10
+ * (Shift, or Option on macOS terminals). {@link MOUSE_SELECTION_HINT} is the one wording for that,
11
+ * so `/help` and the `/mouse` feedback cannot drift apart.
12
+ */
13
+ /** Everything the mouse decision depends on. See {@link resolveUseMouse}. */
14
+ export interface UseMouseInput {
15
+ /**
16
+ * Raw `GTH_NO_MOUSE` environment value; `undefined` when the variable is not set at all. Set and
17
+ * non-empty means mouse OFF. This rung outranks config because it is the escape hatch that works
18
+ * WITHOUT editing a config file — the state someone is in when their terminal mishandles tracking
19
+ * and the session is already unpleasant to use.
20
+ */
21
+ noMouse?: string;
22
+ /**
23
+ * `useMouse` as the user actually wrote it — read from the RAW config, BEFORE `DEFAULT_CONFIG` is
24
+ * merged in. `undefined` means the user set nothing. After the default merge an explicit `true` is
25
+ * indistinguishable from the default `true`, so this must be captured pre-merge or the rung
26
+ * collapses (the same trap `explicitUseColour` documents).
27
+ */
28
+ explicitUseMouse?: boolean;
29
+ /** Raw `TERM`; `dumb`, empty or unset describes a terminal that cannot be expected to track. */
30
+ term?: string;
31
+ /** Whether stdout is a terminal. */
32
+ stdoutIsTTY: boolean;
33
+ /** Whether stdin is a terminal — mouse REPORTS arrive on stdin, so both ends must be a TTY. */
34
+ stdinIsTTY: boolean;
35
+ }
36
+ /**
37
+ * The user-facing sentence explaining how to select text while tracking is on. Terminals disagree
38
+ * about which modifier restores native selection, so this names both rather than promising one.
39
+ */
40
+ export declare const MOUSE_SELECTION_HINT = "To select text while the mouse is on, hold Shift (Option in some macOS terminals) while dragging.";
41
+ /**
42
+ * Resolve mouse reporting from the four-rung precedence ladder, highest wins:
43
+ *
44
+ * 1. `GTH_NO_MOUSE` is set and non-empty — mouse OFF, no config file needed.
45
+ * 2. `useMouse` was set explicitly in config — use it verbatim.
46
+ * 3. `TERM` is unset, empty or `dumb` — mouse OFF; nothing useful can be reported.
47
+ * 4. Otherwise — ON when BOTH stdout and stdin are terminals. A piped, redirected or captured run
48
+ * never enables tracking, so its bytes are identical to a run with mouse compiled out.
49
+ */
50
+ export declare function resolveUseMouse(input: UseMouseInput): boolean;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * TUI-C37 — the single place that decides whether the Ink TUI turns on terminal mouse reporting.
3
+ *
4
+ * Shaped exactly like the colour decision in `colour.ts`: everything the answer depends on arrives
5
+ * as an argument, so the ladder is testable rung by rung without touching process globals.
6
+ *
7
+ * Mouse reporting is ON by default, which is what makes the TUI's clickable affordances
8
+ * discoverable at all. The cost is real and is why the off-ramps below exist: while tracking is on
9
+ * the terminal hands drag events to the application, so its own text selection needs a modifier
10
+ * (Shift, or Option on macOS terminals). {@link MOUSE_SELECTION_HINT} is the one wording for that,
11
+ * so `/help` and the `/mouse` feedback cannot drift apart.
12
+ */
13
+ /**
14
+ * The user-facing sentence explaining how to select text while tracking is on. Terminals disagree
15
+ * about which modifier restores native selection, so this names both rather than promising one.
16
+ */
17
+ export const MOUSE_SELECTION_HINT = 'To select text while the mouse is on, hold Shift (Option in some macOS terminals) while dragging.';
18
+ /**
19
+ * Resolve mouse reporting from the four-rung precedence ladder, highest wins:
20
+ *
21
+ * 1. `GTH_NO_MOUSE` is set and non-empty — mouse OFF, no config file needed.
22
+ * 2. `useMouse` was set explicitly in config — use it verbatim.
23
+ * 3. `TERM` is unset, empty or `dumb` — mouse OFF; nothing useful can be reported.
24
+ * 4. Otherwise — ON when BOTH stdout and stdin are terminals. A piped, redirected or captured run
25
+ * never enables tracking, so its bytes are identical to a run with mouse compiled out.
26
+ */
27
+ export function resolveUseMouse(input) {
28
+ // Rung 1 — the no-config escape hatch.
29
+ if (input.noMouse !== undefined && input.noMouse !== '') {
30
+ return false;
31
+ }
32
+ // Rung 2 — the user's own config. Only reachable with an explicit value, never the default.
33
+ if (input.explicitUseMouse !== undefined) {
34
+ return input.explicitUseMouse;
35
+ }
36
+ // Rung 3 — a terminal that cannot track. Checked below config so someone on an unusual TERM that
37
+ // does support tracking can still force it on.
38
+ if (input.term === undefined || input.term === '' || input.term === 'dumb') {
39
+ return false;
40
+ }
41
+ // Rung 4 — default on, but only for a genuine interactive terminal at both ends.
42
+ return input.stdoutIsTTY && input.stdinIsTTY;
43
+ }
44
+ //# sourceMappingURL=mouse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mouse.js","sourceRoot":"","sources":["../../src/config/mouse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA0BH;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAC/B,mGAAmG,CAAC;AAEtG;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,KAAoB;IAClD,uCAAuC;IACvC,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,KAAK,EAAE,EAAE,CAAC;QACxD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,4FAA4F;IAC5F,IAAI,KAAK,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACzC,OAAO,KAAK,CAAC,gBAAgB,CAAC;IAChC,CAAC;IAED,iGAAiG;IACjG,+CAA+C;IAC/C,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,EAAE,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC3E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,iFAAiF;IACjF,OAAO,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,UAAU,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,68 @@
1
+ import type { RawGthConfig } from '#src/config/types.js';
2
+ /**
3
+ * A profile name maps to a single directory segment under `.gsloth-settings/`, so it must be one
4
+ * safe path component: letters, digits, `.`, `_`, `-` only, and never `.`/`..` (which would escape
5
+ * or self-reference the settings dir). This is a create-time guard so a traversal-shaped name
6
+ * (`../evil`, `a/b`) can never write outside the profile tree.
7
+ */
8
+ export declare const PROFILE_NAME_RE: RegExp;
9
+ /** Fallback provider/model for a scaffold seeded from neither a current config nor `--model`. */
10
+ export declare const DEFAULT_SCAFFOLD_PROVIDER = "anthropic";
11
+ export declare const DEFAULT_SCAFFOLD_MODEL = "claude-sonnet-4-5";
12
+ /**
13
+ * Reject a profile name that is empty, `.`/`..`, or contains anything other than
14
+ * `[A-Za-z0-9._-]` (so it can never traverse out of `.gsloth-settings/`). Throws a clear error;
15
+ * returns the trimmed name on success.
16
+ */
17
+ export declare function validateProfileName(nameRaw: string): string;
18
+ /**
19
+ * The on-disk path a named profile's config is written to / discovered at:
20
+ * `<projectDir>/.gsloth/.gsloth-settings/<name>/.gsloth.config.json`. Resolved against
21
+ * {@link getProjectDir} so it matches the loader's read-side resolution.
22
+ */
23
+ export declare function resolveProfileConfigPath(name: string): string;
24
+ /**
25
+ * Options for seeding a scaffold. `seedType`/`seedModel` come from the current effective config
26
+ * (`modelProviderType` / `modelDisplayName`) when one resolves — present for JSON configs, absent
27
+ * for module (JS/MJS/TS) configs, which hand back an already-built LLM with no raw `type`. When
28
+ * neither seed nor {@link modelOverride} is available the scaffold falls back to the template
29
+ * defaults ({@link DEFAULT_SCAFFOLD_PROVIDER} / {@link DEFAULT_SCAFFOLD_MODEL}) so the written
30
+ * profile is always a valid, editable starting point.
31
+ */
32
+ export interface ProfileScaffoldSeed {
33
+ /** Provider `type` of the current config (`modelProviderType`), when resolvable. */
34
+ seedType?: string;
35
+ /** Model id of the current config (`modelDisplayName`), when resolvable. */
36
+ seedModel?: string;
37
+ /** `--model <id>` override — wins over the seeded/template model. */
38
+ modelOverride?: string;
39
+ }
40
+ /**
41
+ * Build a complete, standalone raw profile config: `{ llm: { type, model } }`. The provider `type`
42
+ * comes from the current config's provider when known, else the template default; the model comes
43
+ * from `--model`, else the current config's model, else the template default. Shape-only — the
44
+ * caller validates it against the schema before writing.
45
+ */
46
+ export declare function buildProfileScaffold(seed: ProfileScaffoldSeed): RawGthConfig;
47
+ /** Outcome of {@link createNamedProfile}: the resolved path the profile config was written to. */
48
+ export interface CreateProfileResult {
49
+ /** Absolute path of the written profile config. */
50
+ path: string;
51
+ /** The provider:model the scaffold was seeded with, for a confirmation message. */
52
+ llm: {
53
+ type: string;
54
+ model: string;
55
+ };
56
+ }
57
+ /**
58
+ * Scaffold a new named profile at {@link resolveProfileConfigPath}. Validates the name (no
59
+ * traversal), builds the scaffold ({@link buildProfileScaffold}), validates it against the GS2-1
60
+ * schema BEFORE writing (never writes an invalid profile), and refuses to clobber an existing
61
+ * profile unless `force`. Creates the `.gsloth/.gsloth-settings/<name>/` tree as needed so the
62
+ * loader's profile-discovery convention resolves it afterwards.
63
+ *
64
+ * @throws Error on an invalid name, an invalid scaffold, or an existing file without `force`.
65
+ */
66
+ export declare function createNamedProfile(nameRaw: string, seed: ProfileScaffoldSeed & {
67
+ force?: boolean;
68
+ }): CreateProfileResult;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * GS2-33 — named config profiles. A profile is a `.gsloth/.gsloth-settings/<name>/` config
4
+ * block: the SAME discovery convention the GS2-1 cascade resolves for `--profile` /
5
+ * `--identity-profile` (see `loader.ts` `resolveIdentityProfileConfigPath`). This module is the
6
+ * write side — scaffolding a new, schema-valid profile config — kept separate from the loader's
7
+ * read side so the `gth config profile create` command is a thin wrapper over a pure, testable core.
8
+ *
9
+ * A named profile is NOT a merge on top of a base project config: with a profile selected the
10
+ * loader's first-match walk picks the profile-dir config as THE project-file layer, so the
11
+ * precedence is `CLI flags > profile-dir config > global config > DEFAULT_CONFIG`. The scaffolder
12
+ * therefore writes a complete, standalone config (at minimum a valid `llm` spec), not a fragment.
13
+ */
14
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
15
+ import { resolve } from 'node:path';
16
+ import { GSLOTH_DIR, GSLOTH_SETTINGS_DIR, USER_PROJECT_CONFIG_JSON } from '#src/constants.js';
17
+ import { getProjectDir } from '#src/utils/systemUtils.js';
18
+ import { validateRawGthConfig } from '#src/config/schema.js';
19
+ /**
20
+ * A profile name maps to a single directory segment under `.gsloth-settings/`, so it must be one
21
+ * safe path component: letters, digits, `.`, `_`, `-` only, and never `.`/`..` (which would escape
22
+ * or self-reference the settings dir). This is a create-time guard so a traversal-shaped name
23
+ * (`../evil`, `a/b`) can never write outside the profile tree.
24
+ */
25
+ export const PROFILE_NAME_RE = /^[A-Za-z0-9._-]+$/;
26
+ /** Fallback provider/model for a scaffold seeded from neither a current config nor `--model`. */
27
+ export const DEFAULT_SCAFFOLD_PROVIDER = 'anthropic';
28
+ export const DEFAULT_SCAFFOLD_MODEL = 'claude-sonnet-4-5';
29
+ /**
30
+ * Reject a profile name that is empty, `.`/`..`, or contains anything other than
31
+ * `[A-Za-z0-9._-]` (so it can never traverse out of `.gsloth-settings/`). Throws a clear error;
32
+ * returns the trimmed name on success.
33
+ */
34
+ export function validateProfileName(nameRaw) {
35
+ const name = (nameRaw ?? '').trim();
36
+ if (!name) {
37
+ throw new Error('Profile name must not be empty.');
38
+ }
39
+ if (name === '.' || name === '..') {
40
+ throw new Error(`Invalid profile name "${name}".`);
41
+ }
42
+ if (!PROFILE_NAME_RE.test(name)) {
43
+ throw new Error(`Invalid profile name "${name}": use only letters, digits, '.', '_' or '-' ` +
44
+ '(a profile name is a single directory segment).');
45
+ }
46
+ return name;
47
+ }
48
+ /**
49
+ * The on-disk path a named profile's config is written to / discovered at:
50
+ * `<projectDir>/.gsloth/.gsloth-settings/<name>/.gsloth.config.json`. Resolved against
51
+ * {@link getProjectDir} so it matches the loader's read-side resolution.
52
+ */
53
+ export function resolveProfileConfigPath(name) {
54
+ return resolve(getProjectDir(), GSLOTH_DIR, GSLOTH_SETTINGS_DIR, name, USER_PROJECT_CONFIG_JSON);
55
+ }
56
+ /**
57
+ * Build a complete, standalone raw profile config: `{ llm: { type, model } }`. The provider `type`
58
+ * comes from the current config's provider when known, else the template default; the model comes
59
+ * from `--model`, else the current config's model, else the template default. Shape-only — the
60
+ * caller validates it against the schema before writing.
61
+ */
62
+ export function buildProfileScaffold(seed) {
63
+ const type = seed.seedType ?? DEFAULT_SCAFFOLD_PROVIDER;
64
+ const model = seed.modelOverride ?? seed.seedModel ?? DEFAULT_SCAFFOLD_MODEL;
65
+ return { llm: { type, model } };
66
+ }
67
+ /**
68
+ * Scaffold a new named profile at {@link resolveProfileConfigPath}. Validates the name (no
69
+ * traversal), builds the scaffold ({@link buildProfileScaffold}), validates it against the GS2-1
70
+ * schema BEFORE writing (never writes an invalid profile), and refuses to clobber an existing
71
+ * profile unless `force`. Creates the `.gsloth/.gsloth-settings/<name>/` tree as needed so the
72
+ * loader's profile-discovery convention resolves it afterwards.
73
+ *
74
+ * @throws Error on an invalid name, an invalid scaffold, or an existing file without `force`.
75
+ */
76
+ export function createNamedProfile(nameRaw, seed) {
77
+ const name = validateProfileName(nameRaw);
78
+ const scaffold = buildProfileScaffold(seed);
79
+ // Validate BEFORE writing — a broken scaffold must fail here, never land on disk to be run later.
80
+ const validation = validateRawGthConfig(scaffold);
81
+ if (!validation.ok) {
82
+ throw new Error(`Refusing to write an invalid profile "${name}":\n${validation.errorMessage ?? ''}`);
83
+ }
84
+ const path = resolveProfileConfigPath(name);
85
+ if (existsSync(path) && !seed.force) {
86
+ throw new Error(`Profile "${name}" already exists at ${path}. Pass --force to overwrite it.`);
87
+ }
88
+ mkdirSync(resolve(path, '..'), { recursive: true });
89
+ writeFileSync(path, `${JSON.stringify(scaffold, null, 2)}\n`, 'utf8');
90
+ const llm = scaffold.llm;
91
+ return { path, llm: { type: llm.type, model: llm.model } };
92
+ }
93
+ //# sourceMappingURL=profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.js","sourceRoot":"","sources":["../../src/config/profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC9F,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAG7D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAEnD,iGAAiG;AACjG,MAAM,CAAC,MAAM,yBAAyB,GAAG,WAAW,CAAC;AACrD,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,IAAI,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CACb,yBAAyB,IAAI,+CAA+C;YAC1E,iDAAiD,CACpD,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,OAAO,OAAO,CAAC,aAAa,EAAE,EAAE,UAAU,EAAE,mBAAmB,EAAE,IAAI,EAAE,wBAAwB,CAAC,CAAC;AACnG,CAAC;AAmBD;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAyB;IAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,IAAI,yBAAyB,CAAC;IACxD,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,SAAS,IAAI,sBAAsB,CAAC;IAC7E,OAAO,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAkB,CAAC;AAClD,CAAC;AAUD;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAe,EACf,IAA+C;IAE/C,MAAM,IAAI,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAE5C,kGAAkG;IAClG,MAAM,UAAU,GAAG,oBAAoB,CAAC,QAA8C,CAAC,CAAC;IACxF,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,yCAAyC,IAAI,OAAO,UAAU,CAAC,YAAY,IAAI,EAAE,EAAE,CACpF,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,uBAAuB,IAAI,iCAAiC,CAAC,CAAC;IAChG,CAAC;IAED,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAEtE,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAsC,CAAC;IAC5D,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC;AAC7D,CAAC"}