@gaunt-sloth/core 2.0.0-alpha.8 → 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
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @module utils/untrustedText
3
+ *
4
+ * **The structural delimiters gsloth wraps untrusted text in, and the one function that neutralizes
5
+ * a forged one.**
6
+ *
7
+ * Text that arrived from outside this process — an MCP server's discovery `instructions`, a command
8
+ * string the model composed from an issue body or a fetched page — is quoted into the model's
9
+ * context in several places. Wherever it is, the same two things have to be true:
10
+ *
11
+ * 1. the quoted text is visibly fenced, so the model can tell data from first-party instruction; and
12
+ * 2. **the quoted text cannot forge the fence** and escape it.
13
+ *
14
+ * (2) is the load-bearing half, and it is why the delimiters and the defang live together in one
15
+ * module rather than beside each consumer. A second defang written for a second consumer is how one
16
+ * of them comes to know about a delimiter the other emits: a forged `[END …]` token that the
17
+ * emitting site happens not to defang closes its fence early and the attacker's lines land OUTSIDE
18
+ * the boundary, reading as first-party text. {@link defangUntrustedDelimiters} knows **every**
19
+ * delimiter we emit, so every consumer is protected by every arm.
20
+ *
21
+ * **Defang BEFORE wrapping, always.** That ordering is the whole mechanism; wrapping first and
22
+ * sanitizing after would sanitize a string that already contains the real delimiters.
23
+ */
24
+ /** The MCP discovery-instructions fence (EXT-32), emitted by `utils/systemPromptNotes.ts`. */
25
+ export declare const MCP_FENCE_BEGIN = "[BEGIN MCP SERVER-PROVIDED CONTEXT]";
26
+ export declare const MCP_FENCE_END = "[END MCP SERVER-PROVIDED CONTEXT]";
27
+ /**
28
+ * EXT-65 — the fence a refused command is quoted back inside, emitted by
29
+ * `core/shell/abstention.ts`. A command the gate could not parse is frequently a command the model
30
+ * assembled out of text it read somewhere, so quoting it back for the model to rewrite is quoting
31
+ * untrusted bytes into the model's context.
32
+ */
33
+ export declare const QUOTED_COMMAND_FENCE_BEGIN = "[BEGIN QUOTED COMMAND TEXT]";
34
+ export declare const QUOTED_COMMAND_FENCE_END = "[END QUOTED COMMAND TEXT]";
35
+ /** How much of a refused command is quoted back. Generous; a realistic command is far shorter. */
36
+ export declare const QUOTED_COMMAND_MAX_CHARS = 2000;
37
+ /** Appended when {@link QUOTED_COMMAND_MAX_CHARS} actually clipped the quoted command. */
38
+ export declare const QUOTED_COMMAND_TRUNCATION_MARKER = "\u2026 [truncated]";
39
+ /**
40
+ * [[EXT-46]] — the fence the ACP server quotes a prompt's non-text content blocks inside, emitted by
41
+ * `@gaunt-sloth/agent`'s `modules/acp/acpAgentApp.ts`.
42
+ *
43
+ * An ACP client attaches content blocks to a prompt, and the ones that are not the user's own typed
44
+ * text carry values the user did not author: a resource link's `name`, `uri` and `description` come
45
+ * from the editor, the filesystem or an MCP server, and a block's `type` is an arbitrary client
46
+ * string by the v2 schema. The agent has to tell the model that something was attached — dropping it
47
+ * silently is worse — so those values are quoted into the same message as the user's words, which is
48
+ * the situation this module exists for.
49
+ */
50
+ export declare const ACP_ATTACHMENT_FENCE_BEGIN = "[BEGIN CLIENT-PROVIDED ATTACHMENT]";
51
+ export declare const ACP_ATTACHMENT_FENCE_END = "[END CLIENT-PROVIDED ATTACHMENT]";
52
+ /**
53
+ * How much of one attachment FIELD is quoted. These are metadata (a file name, a URI, a one-line
54
+ * description), not documents, so this is generous rather than a limit anything real should reach.
55
+ */
56
+ export declare const ACP_ATTACHMENT_FIELD_MAX_CHARS = 1000;
57
+ /** Appended when {@link ACP_ATTACHMENT_FIELD_MAX_CHARS} actually clipped a field. */
58
+ export declare const ACP_ATTACHMENT_TRUNCATION_MARKER = "\u2026 [truncated]";
59
+ /**
60
+ * Neutralize every structural delimiter this codebase emits, inside UNTRUSTED text.
61
+ *
62
+ * The text is fully attacker-influenceable, so it may forge:
63
+ * - any fence's tokens (`[BEGIN|END MCP SERVER-PROVIDED CONTEXT]`,
64
+ * `[BEGIN|END QUOTED COMMAND TEXT]`, `[BEGIN|END CLIENT-PROVIDED ATTACHMENT]`) — the bracket run
65
+ * is collapsed so they can no longer be read as the real delimiter, while staying legible to a
66
+ * reader who wants to see what was attempted; and
67
+ * - a per-server label line `--- Server: …` (EXT-32) — the leading `---` run is broken so it
68
+ * cannot masquerade as one of ours.
69
+ *
70
+ * After this, the ONLY real delimiters in a composed block are the ones the caller emits. Names we
71
+ * put in our OWN labels come from trusted config keys and are not sanitized — only the untrusted
72
+ * CONTENT is.
73
+ *
74
+ * Whitespace-tolerant (`\s+`, optional bracket padding, `-{3,}`) so trivial spacing variants cannot
75
+ * slip a delimiter through, and case-insensitive so neither can a lowercase one.
76
+ */
77
+ export declare function defangUntrustedDelimiters(text: string): string;
78
+ /**
79
+ * Truncate untrusted text at `maxChars`, SURROGATE-SAFE, appending `marker` only when text was
80
+ * actually clipped.
81
+ *
82
+ * A naive `slice(0, N)` can split a surrogate pair (e.g. an emoji) at the boundary and emit a lone
83
+ * half-code-unit. If the cut would land between a high and a low surrogate, back off one code unit
84
+ * so the pair is kept whole (dropped entirely rather than split).
85
+ */
86
+ export declare function capUntrustedText(text: string, maxChars: number, marker: string): string;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * @module utils/untrustedText
3
+ *
4
+ * **The structural delimiters gsloth wraps untrusted text in, and the one function that neutralizes
5
+ * a forged one.**
6
+ *
7
+ * Text that arrived from outside this process — an MCP server's discovery `instructions`, a command
8
+ * string the model composed from an issue body or a fetched page — is quoted into the model's
9
+ * context in several places. Wherever it is, the same two things have to be true:
10
+ *
11
+ * 1. the quoted text is visibly fenced, so the model can tell data from first-party instruction; and
12
+ * 2. **the quoted text cannot forge the fence** and escape it.
13
+ *
14
+ * (2) is the load-bearing half, and it is why the delimiters and the defang live together in one
15
+ * module rather than beside each consumer. A second defang written for a second consumer is how one
16
+ * of them comes to know about a delimiter the other emits: a forged `[END …]` token that the
17
+ * emitting site happens not to defang closes its fence early and the attacker's lines land OUTSIDE
18
+ * the boundary, reading as first-party text. {@link defangUntrustedDelimiters} knows **every**
19
+ * delimiter we emit, so every consumer is protected by every arm.
20
+ *
21
+ * **Defang BEFORE wrapping, always.** That ordering is the whole mechanism; wrapping first and
22
+ * sanitizing after would sanitize a string that already contains the real delimiters.
23
+ */
24
+ /** The MCP discovery-instructions fence (EXT-32), emitted by `utils/systemPromptNotes.ts`. */
25
+ export const MCP_FENCE_BEGIN = '[BEGIN MCP SERVER-PROVIDED CONTEXT]';
26
+ export const MCP_FENCE_END = '[END MCP SERVER-PROVIDED CONTEXT]';
27
+ /**
28
+ * EXT-65 — the fence a refused command is quoted back inside, emitted by
29
+ * `core/shell/abstention.ts`. A command the gate could not parse is frequently a command the model
30
+ * assembled out of text it read somewhere, so quoting it back for the model to rewrite is quoting
31
+ * untrusted bytes into the model's context.
32
+ */
33
+ export const QUOTED_COMMAND_FENCE_BEGIN = '[BEGIN QUOTED COMMAND TEXT]';
34
+ export const QUOTED_COMMAND_FENCE_END = '[END QUOTED COMMAND TEXT]';
35
+ /** How much of a refused command is quoted back. Generous; a realistic command is far shorter. */
36
+ export const QUOTED_COMMAND_MAX_CHARS = 2000;
37
+ /** Appended when {@link QUOTED_COMMAND_MAX_CHARS} actually clipped the quoted command. */
38
+ export const QUOTED_COMMAND_TRUNCATION_MARKER = '… [truncated]';
39
+ /**
40
+ * [[EXT-46]] — the fence the ACP server quotes a prompt's non-text content blocks inside, emitted by
41
+ * `@gaunt-sloth/agent`'s `modules/acp/acpAgentApp.ts`.
42
+ *
43
+ * An ACP client attaches content blocks to a prompt, and the ones that are not the user's own typed
44
+ * text carry values the user did not author: a resource link's `name`, `uri` and `description` come
45
+ * from the editor, the filesystem or an MCP server, and a block's `type` is an arbitrary client
46
+ * string by the v2 schema. The agent has to tell the model that something was attached — dropping it
47
+ * silently is worse — so those values are quoted into the same message as the user's words, which is
48
+ * the situation this module exists for.
49
+ */
50
+ export const ACP_ATTACHMENT_FENCE_BEGIN = '[BEGIN CLIENT-PROVIDED ATTACHMENT]';
51
+ export const ACP_ATTACHMENT_FENCE_END = '[END CLIENT-PROVIDED ATTACHMENT]';
52
+ /**
53
+ * How much of one attachment FIELD is quoted. These are metadata (a file name, a URI, a one-line
54
+ * description), not documents, so this is generous rather than a limit anything real should reach.
55
+ */
56
+ export const ACP_ATTACHMENT_FIELD_MAX_CHARS = 1000;
57
+ /** Appended when {@link ACP_ATTACHMENT_FIELD_MAX_CHARS} actually clipped a field. */
58
+ export const ACP_ATTACHMENT_TRUNCATION_MARKER = '… [truncated]';
59
+ /**
60
+ * Neutralize every structural delimiter this codebase emits, inside UNTRUSTED text.
61
+ *
62
+ * The text is fully attacker-influenceable, so it may forge:
63
+ * - any fence's tokens (`[BEGIN|END MCP SERVER-PROVIDED CONTEXT]`,
64
+ * `[BEGIN|END QUOTED COMMAND TEXT]`, `[BEGIN|END CLIENT-PROVIDED ATTACHMENT]`) — the bracket run
65
+ * is collapsed so they can no longer be read as the real delimiter, while staying legible to a
66
+ * reader who wants to see what was attempted; and
67
+ * - a per-server label line `--- Server: …` (EXT-32) — the leading `---` run is broken so it
68
+ * cannot masquerade as one of ours.
69
+ *
70
+ * After this, the ONLY real delimiters in a composed block are the ones the caller emits. Names we
71
+ * put in our OWN labels come from trusted config keys and are not sanitized — only the untrusted
72
+ * CONTENT is.
73
+ *
74
+ * Whitespace-tolerant (`\s+`, optional bracket padding, `-{3,}`) so trivial spacing variants cannot
75
+ * slip a delimiter through, and case-insensitive so neither can a lowercase one.
76
+ */
77
+ export function defangUntrustedDelimiters(text) {
78
+ return text
79
+ .replace(/\[\s*(BEGIN|END)\s+MCP\s+SERVER-PROVIDED\s+CONTEXT\s*\]/gi, (_m, kw) => `(server text: ${kw.toUpperCase()} MCP SERVER-PROVIDED CONTEXT)`)
80
+ .replace(/\[\s*(BEGIN|END)\s+QUOTED\s+COMMAND\s+TEXT\s*\]/gi, (_m, kw) => `(quoted text: ${kw.toUpperCase()} QUOTED COMMAND TEXT)`)
81
+ .replace(/\[\s*(BEGIN|END)\s+CLIENT-PROVIDED\s+ATTACHMENT\s*\]/gi, (_m, kw) => `(client text: ${kw.toUpperCase()} CLIENT-PROVIDED ATTACHMENT)`)
82
+ .replace(/-{3,}(\s*Server\s*:)/gi, '- - -$1');
83
+ }
84
+ /**
85
+ * Truncate untrusted text at `maxChars`, SURROGATE-SAFE, appending `marker` only when text was
86
+ * actually clipped.
87
+ *
88
+ * A naive `slice(0, N)` can split a surrogate pair (e.g. an emoji) at the boundary and emit a lone
89
+ * half-code-unit. If the cut would land between a high and a low surrogate, back off one code unit
90
+ * so the pair is kept whole (dropped entirely rather than split).
91
+ */
92
+ export function capUntrustedText(text, maxChars, marker) {
93
+ if (text.length <= maxChars)
94
+ return text;
95
+ let end = maxChars;
96
+ const code = text.charCodeAt(end - 1);
97
+ if (code >= 0xd800 && code <= 0xdbff)
98
+ end -= 1; // don't split a surrogate pair
99
+ return `${text.slice(0, end).trimEnd()}\n${marker}`;
100
+ }
101
+ //# sourceMappingURL=untrustedText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"untrustedText.js","sourceRoot":"","sources":["../../src/utils/untrustedText.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,8FAA8F;AAC9F,MAAM,CAAC,MAAM,eAAe,GAAG,qCAAqC,CAAC;AACrE,MAAM,CAAC,MAAM,aAAa,GAAG,mCAAmC,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,6BAA6B,CAAC;AACxE,MAAM,CAAC,MAAM,wBAAwB,GAAG,2BAA2B,CAAC;AAEpE,kGAAkG;AAClG,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAE7C,0FAA0F;AAC1F,MAAM,CAAC,MAAM,gCAAgC,GAAG,eAAe,CAAC;AAEhE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,oCAAoC,CAAC;AAC/E,MAAM,CAAC,MAAM,wBAAwB,GAAG,kCAAkC,CAAC;AAE3E;;;GAGG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,IAAI,CAAC;AAEnD,qFAAqF;AACrF,MAAM,CAAC,MAAM,gCAAgC,GAAG,eAAe,CAAC;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,yBAAyB,CAAC,IAAY;IACpD,OAAO,IAAI;SACR,OAAO,CACN,2DAA2D,EAC3D,CAAC,EAAE,EAAE,EAAU,EAAE,EAAE,CAAC,iBAAiB,EAAE,CAAC,WAAW,EAAE,+BAA+B,CACrF;SACA,OAAO,CACN,mDAAmD,EACnD,CAAC,EAAE,EAAE,EAAU,EAAE,EAAE,CAAC,iBAAiB,EAAE,CAAC,WAAW,EAAE,uBAAuB,CAC7E;SACA,OAAO,CACN,wDAAwD,EACxD,CAAC,EAAE,EAAE,EAAU,EAAE,EAAE,CAAC,iBAAiB,EAAE,CAAC,WAAW,EAAE,8BAA8B,CACpF;SACA,OAAO,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,QAAgB,EAAE,MAAc;IAC7E,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACtC,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM;QAAE,GAAG,IAAI,CAAC,CAAC,CAAC,+BAA+B;IAC/E,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;AACtD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gaunt-sloth/core",
3
- "version": "2.0.0-alpha.8",
3
+ "version": "2.0.0-beta.0",
4
4
  "description": "Core utilities and types for Gaunt Sloth",
5
5
  "license": "MIT",
6
6
  "author": "Andrew Kondratev",
@@ -30,19 +30,22 @@
30
30
  "#src/*.js": "./dist/*.js"
31
31
  },
32
32
  "dependencies": {
33
- "@langchain/core": "^1.2.1",
34
- "@langchain/langgraph": "^1.4.7",
33
+ "@langchain/core": "^1.2.5",
34
+ "@langchain/langgraph": "^1.4.9",
35
35
  "jiti": "^2.7.0",
36
36
  "jsonc-parser": "^3.3.1",
37
- "langchain": "^1.5.2",
38
- "zod": "^4.0.0"
37
+ "langchain": "^1.5.5",
38
+ "string-width": "^8.2.2",
39
+ "zod": "^4.4.3"
39
40
  },
40
41
  "peerDependencies": {
41
42
  "@langchain/anthropic": "^1.5.0",
42
43
  "@langchain/deepseek": "^1.1.1",
43
44
  "@langchain/google": "^0.2.0",
44
45
  "@langchain/groq": "^1.3.0",
46
+ "@langchain/ollama": "^1.3.0",
45
47
  "@langchain/openai": "^1.5.1",
48
+ "@langchain/openrouter": "^0.4.5",
46
49
  "@langchain/xai": "^1.4.1"
47
50
  },
48
51
  "peerDependenciesMeta": {
@@ -58,9 +61,15 @@
58
61
  "@langchain/groq": {
59
62
  "optional": true
60
63
  },
64
+ "@langchain/ollama": {
65
+ "optional": true
66
+ },
61
67
  "@langchain/openai": {
62
68
  "optional": true
63
69
  },
70
+ "@langchain/openrouter": {
71
+ "optional": true
72
+ },
64
73
  "@langchain/xai": {
65
74
  "optional": true
66
75
  }
@@ -71,10 +80,15 @@
71
80
  ".gsloth.*.md"
72
81
  ],
73
82
  "publishConfig": {
74
- "tag": "alpha"
83
+ "tag": "beta"
84
+ },
85
+ "devDependencies": {
86
+ "ajv": "8.20.0",
87
+ "typedoc": "^0.28.20"
75
88
  },
76
89
  "scripts": {
77
90
  "build": "tsc",
78
- "schema:generate": "node scripts/generate-config-schema.mjs"
91
+ "schema:generate": "node scripts/generate-config-schema.mjs",
92
+ "surface:generate": "node scripts/generate-type-surface.mjs"
79
93
  }
80
94
  }