@warlock.js/ai 4.3.0 → 4.5.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 (541) hide show
  1. package/CHANGELOG.md +52 -48
  2. package/cjs/index.cjs +221 -14144
  3. package/cjs/src-C02yzsLs.cjs +22991 -0
  4. package/cjs/src-C02yzsLs.cjs.map +1 -0
  5. package/cjs/src-DFibP2FQ.cjs +30 -0
  6. package/esm/agent/agent-config.type.d.mts +90 -1
  7. package/esm/agent/agent-config.type.d.mts.map +1 -1
  8. package/esm/agent/agent-input-builder.mjs +27 -6
  9. package/esm/agent/agent-input-builder.mjs.map +1 -1
  10. package/esm/agent/agent.d.mts +40 -1
  11. package/esm/agent/agent.d.mts.map +1 -1
  12. package/esm/agent/agent.mjs +203 -30
  13. package/esm/agent/agent.mjs.map +1 -1
  14. package/esm/agent/index.d.mts +2 -1
  15. package/esm/agent/index.mjs +1 -0
  16. package/esm/agent/judge-config.type.d.mts +33 -0
  17. package/esm/agent/judge-config.type.d.mts.map +1 -0
  18. package/esm/agent/judge-config.type.mjs +13 -0
  19. package/esm/agent/judge-config.type.mjs.map +1 -0
  20. package/esm/ai-openai/src/embedder.mjs +4 -0
  21. package/esm/ai-openai/src/index.mjs +4 -0
  22. package/esm/ai-openai/src/model.mjs +5 -0
  23. package/esm/ai-openai/src/sdk.mjs +6 -0
  24. package/esm/ai-openai/src/utils/index.mjs +4 -0
  25. package/esm/ai-openai/src/utils/to-openai-tools.mjs +3 -0
  26. package/esm/ai-openai/src/utils/wrap-openai-error.mjs +4 -0
  27. package/esm/ai.d.mts +119 -53
  28. package/esm/ai.d.mts.map +1 -1
  29. package/esm/ai.mjs +43 -8
  30. package/esm/ai.mjs.map +1 -1
  31. package/esm/batch/batch.d.mts.map +1 -1
  32. package/esm/batch/batch.mjs +21 -1
  33. package/esm/batch/batch.mjs.map +1 -1
  34. package/esm/batch/batch.type.d.mts +11 -4
  35. package/esm/batch/batch.type.d.mts.map +1 -1
  36. package/esm/config.d.mts +39 -3
  37. package/esm/config.d.mts.map +1 -1
  38. package/esm/config.mjs +26 -2
  39. package/esm/config.mjs.map +1 -1
  40. package/esm/contracts/agent/agent-options.type.d.mts +11 -3
  41. package/esm/contracts/agent/agent-options.type.d.mts.map +1 -1
  42. package/esm/contracts/agent/eval.type.d.mts +43 -2
  43. package/esm/contracts/agent/eval.type.d.mts.map +1 -1
  44. package/esm/contracts/attachment-policy.type.d.mts +51 -0
  45. package/esm/contracts/attachment-policy.type.d.mts.map +1 -0
  46. package/esm/contracts/attachment.type.d.mts +16 -7
  47. package/esm/contracts/attachment.type.d.mts.map +1 -1
  48. package/esm/contracts/content-part.type.d.mts +14 -5
  49. package/esm/contracts/content-part.type.d.mts.map +1 -1
  50. package/esm/contracts/events/supervisor-events.type.d.mts.map +1 -1
  51. package/esm/contracts/index.d.mts +6 -4
  52. package/esm/contracts/model.contract.d.mts +11 -8
  53. package/esm/contracts/model.contract.d.mts.map +1 -1
  54. package/esm/contracts/orchestrator/index.d.mts +1 -0
  55. package/esm/contracts/orchestrator/orchestrator-config.type.d.mts +31 -2
  56. package/esm/contracts/orchestrator/orchestrator-config.type.d.mts.map +1 -1
  57. package/esm/contracts/orchestrator/session-lock.contract.d.mts +47 -0
  58. package/esm/contracts/orchestrator/session-lock.contract.d.mts.map +1 -0
  59. package/esm/contracts/planner/index.d.mts +1 -1
  60. package/esm/contracts/planner/planner-config.type.d.mts +31 -0
  61. package/esm/contracts/planner/planner-config.type.d.mts.map +1 -1
  62. package/esm/contracts/planner/planner-execute-options.type.d.mts +48 -1
  63. package/esm/contracts/planner/planner-execute-options.type.d.mts.map +1 -1
  64. package/esm/contracts/planner/planner-result.type.d.mts +19 -5
  65. package/esm/contracts/planner/planner-result.type.d.mts.map +1 -1
  66. package/esm/contracts/planner/planner.contract.d.mts +1 -1
  67. package/esm/contracts/result/agent-result.type.d.mts +6 -4
  68. package/esm/contracts/result/agent-result.type.d.mts.map +1 -1
  69. package/esm/contracts/result/base-report.type.d.mts +21 -3
  70. package/esm/contracts/result/base-report.type.d.mts.map +1 -1
  71. package/esm/contracts/result/base-report.type.mjs.map +1 -1
  72. package/esm/contracts/result/execution-report.type.d.mts +53 -1
  73. package/esm/contracts/result/execution-report.type.d.mts.map +1 -1
  74. package/esm/contracts/result/orchestrator-result.type.d.mts +15 -11
  75. package/esm/contracts/result/orchestrator-result.type.d.mts.map +1 -1
  76. package/esm/contracts/result/supervisor-result.type.d.mts +13 -1
  77. package/esm/contracts/result/supervisor-result.type.d.mts.map +1 -1
  78. package/esm/contracts/result/tool-call.type.d.mts +2 -2
  79. package/esm/contracts/result/tool-call.type.d.mts.map +1 -1
  80. package/esm/contracts/result/workflow-result.type.d.mts +1 -0
  81. package/esm/contracts/result/workflow-result.type.d.mts.map +1 -1
  82. package/esm/contracts/supervisor/supervisor-config.type.d.mts +29 -0
  83. package/esm/contracts/supervisor/supervisor-config.type.d.mts.map +1 -1
  84. package/esm/contracts/system-prompt.contract.d.mts +103 -1
  85. package/esm/contracts/system-prompt.contract.d.mts.map +1 -1
  86. package/esm/contracts/team/index.d.mts +1 -0
  87. package/esm/contracts/team/team-config.type.d.mts +127 -0
  88. package/esm/contracts/team/team-config.type.d.mts.map +1 -0
  89. package/esm/contracts/tool.contract.d.mts +4 -2
  90. package/esm/contracts/tool.contract.d.mts.map +1 -1
  91. package/esm/contracts/workflow/step.contract.d.mts +30 -5
  92. package/esm/contracts/workflow/step.contract.d.mts.map +1 -1
  93. package/esm/contracts/workflow/workflow.contract.d.mts +16 -0
  94. package/esm/contracts/workflow/workflow.contract.d.mts.map +1 -1
  95. package/esm/errors/error-code.type.d.mts +1 -1
  96. package/esm/errors/index.d.mts +1 -0
  97. package/esm/errors/index.mjs +1 -0
  98. package/esm/errors/outbound-policy-error.d.mts +27 -0
  99. package/esm/errors/outbound-policy-error.d.mts.map +1 -0
  100. package/esm/errors/outbound-policy-error.mjs +32 -0
  101. package/esm/errors/outbound-policy-error.mjs.map +1 -0
  102. package/esm/eval/dataset.d.mts +28 -0
  103. package/esm/eval/dataset.d.mts.map +1 -0
  104. package/esm/eval/dataset.mjs +112 -0
  105. package/esm/eval/dataset.mjs.map +1 -0
  106. package/esm/eval/dataset.type.d.mts +53 -0
  107. package/esm/eval/dataset.type.d.mts.map +1 -0
  108. package/esm/eval/eval-runner.d.mts.map +1 -1
  109. package/esm/eval/eval-runner.mjs +16 -2
  110. package/esm/eval/eval-runner.mjs.map +1 -1
  111. package/esm/eval/index.d.mts +20 -1
  112. package/esm/eval/index.d.mts.map +1 -1
  113. package/esm/eval/index.mjs +20 -2
  114. package/esm/eval/index.mjs.map +1 -1
  115. package/esm/eval/regression.d.mts +30 -0
  116. package/esm/eval/regression.d.mts.map +1 -0
  117. package/esm/eval/regression.mjs +51 -0
  118. package/esm/eval/regression.mjs.map +1 -0
  119. package/esm/eval/report-json.d.mts +30 -0
  120. package/esm/eval/report-json.d.mts.map +1 -0
  121. package/esm/eval/report-json.mjs +33 -0
  122. package/esm/eval/report-json.mjs.map +1 -0
  123. package/esm/eval/report-junit.d.mts +22 -0
  124. package/esm/eval/report-junit.d.mts.map +1 -0
  125. package/esm/eval/report-junit.mjs +60 -0
  126. package/esm/eval/report-junit.mjs.map +1 -0
  127. package/esm/guard/contracts/guard-options.type.d.mts +165 -0
  128. package/esm/guard/contracts/guard-options.type.d.mts.map +1 -0
  129. package/esm/guard/contracts/guardrail.contract.d.mts +78 -0
  130. package/esm/guard/contracts/guardrail.contract.d.mts.map +1 -0
  131. package/esm/guard/contracts/index.d.mts +4 -0
  132. package/esm/guard/contracts/openai-client.contract.d.mts +51 -0
  133. package/esm/guard/contracts/openai-client.contract.d.mts.map +1 -0
  134. package/esm/guard/contracts/verdict.type.d.mts +76 -0
  135. package/esm/guard/contracts/verdict.type.d.mts.map +1 -0
  136. package/esm/guard/detectors/index.d.mts +4 -0
  137. package/esm/guard/detectors/index.mjs +6 -0
  138. package/esm/guard/detectors/injection.d.mts +34 -0
  139. package/esm/guard/detectors/injection.d.mts.map +1 -0
  140. package/esm/guard/detectors/injection.mjs +254 -0
  141. package/esm/guard/detectors/injection.mjs.map +1 -0
  142. package/esm/guard/detectors/moderation.d.mts +32 -0
  143. package/esm/guard/detectors/moderation.d.mts.map +1 -0
  144. package/esm/guard/detectors/moderation.mjs +134 -0
  145. package/esm/guard/detectors/moderation.mjs.map +1 -0
  146. package/esm/guard/detectors/pii.d.mts +41 -0
  147. package/esm/guard/detectors/pii.d.mts.map +1 -0
  148. package/esm/guard/detectors/pii.mjs +199 -0
  149. package/esm/guard/detectors/pii.mjs.map +1 -0
  150. package/esm/guard/detectors/topic.d.mts +29 -0
  151. package/esm/guard/detectors/topic.d.mts.map +1 -0
  152. package/esm/guard/detectors/topic.mjs +99 -0
  153. package/esm/guard/detectors/topic.mjs.map +1 -0
  154. package/esm/guard/errors.d.mts +12 -0
  155. package/esm/guard/errors.d.mts.map +1 -0
  156. package/esm/guard/errors.mjs +18 -0
  157. package/esm/guard/errors.mjs.map +1 -0
  158. package/esm/guard/guard.d.mts +67 -0
  159. package/esm/guard/guard.d.mts.map +1 -0
  160. package/esm/guard/guard.mjs +209 -0
  161. package/esm/guard/guard.mjs.map +1 -0
  162. package/esm/guard/guardrail.d.mts +39 -0
  163. package/esm/guard/guardrail.d.mts.map +1 -0
  164. package/esm/guard/guardrail.mjs +22 -0
  165. package/esm/guard/guardrail.mjs.map +1 -0
  166. package/esm/human/contracts/approval.type.d.mts +154 -0
  167. package/esm/human/contracts/approval.type.d.mts.map +1 -0
  168. package/esm/human/contracts/human-approval.type.d.mts +38 -0
  169. package/esm/human/contracts/human-approval.type.d.mts.map +1 -0
  170. package/esm/human/contracts/index.d.mts +4 -0
  171. package/esm/human/contracts/interrupt-store.contract.d.mts +112 -0
  172. package/esm/human/contracts/interrupt-store.contract.d.mts.map +1 -0
  173. package/esm/human/contracts/resume.type.d.mts +77 -0
  174. package/esm/human/contracts/resume.type.d.mts.map +1 -0
  175. package/esm/human/errors.d.mts +84 -0
  176. package/esm/human/errors.d.mts.map +1 -0
  177. package/esm/human/errors.mjs +60 -0
  178. package/esm/human/errors.mjs.map +1 -0
  179. package/esm/human/human-approval.d.mts +57 -0
  180. package/esm/human/human-approval.d.mts.map +1 -0
  181. package/esm/human/human-approval.mjs +170 -0
  182. package/esm/human/human-approval.mjs.map +1 -0
  183. package/esm/human/policy.d.mts +55 -0
  184. package/esm/human/policy.d.mts.map +1 -0
  185. package/esm/human/policy.mjs +67 -0
  186. package/esm/human/policy.mjs.map +1 -0
  187. package/esm/human/register.mjs +37 -0
  188. package/esm/human/register.mjs.map +1 -0
  189. package/esm/human/resume-seed.mjs +53 -0
  190. package/esm/human/resume-seed.mjs.map +1 -0
  191. package/esm/human/resume.d.mts +54 -0
  192. package/esm/human/resume.d.mts.map +1 -0
  193. package/esm/human/resume.mjs +121 -0
  194. package/esm/human/resume.mjs.map +1 -0
  195. package/esm/human/stores/index.mjs +5 -0
  196. package/esm/human/stores/memory.d.mts +30 -0
  197. package/esm/human/stores/memory.d.mts.map +1 -0
  198. package/esm/human/stores/memory.mjs +91 -0
  199. package/esm/human/stores/memory.mjs.map +1 -0
  200. package/esm/human/stores/pg.d.mts +59 -0
  201. package/esm/human/stores/pg.d.mts.map +1 -0
  202. package/esm/human/stores/pg.mjs +220 -0
  203. package/esm/human/stores/pg.mjs.map +1 -0
  204. package/esm/human/stores/redis.d.mts +56 -0
  205. package/esm/human/stores/redis.d.mts.map +1 -0
  206. package/esm/human/stores/redis.mjs +201 -0
  207. package/esm/human/stores/redis.mjs.map +1 -0
  208. package/esm/index.d.mts +113 -22
  209. package/esm/index.mjs +82 -11
  210. package/esm/middleware/builtins/budget.mjs +6 -2
  211. package/esm/middleware/builtins/budget.mjs.map +1 -1
  212. package/esm/middleware/utils/extract-user-text.d.mts +8 -1
  213. package/esm/middleware/utils/extract-user-text.d.mts.map +1 -1
  214. package/esm/middleware/utils/extract-user-text.mjs +8 -1
  215. package/esm/middleware/utils/extract-user-text.mjs.map +1 -1
  216. package/esm/object-stream/index.d.mts +2 -0
  217. package/esm/object-stream/index.mjs +4 -0
  218. package/esm/object-stream/parse-partial-json.d.mts +22 -0
  219. package/esm/object-stream/parse-partial-json.d.mts.map +1 -0
  220. package/esm/object-stream/parse-partial-json.mjs +78 -0
  221. package/esm/object-stream/parse-partial-json.mjs.map +1 -0
  222. package/esm/object-stream/stream-object.d.mts +68 -0
  223. package/esm/object-stream/stream-object.d.mts.map +1 -0
  224. package/esm/object-stream/stream-object.mjs +104 -0
  225. package/esm/object-stream/stream-object.mjs.map +1 -0
  226. package/esm/observe/index.mjs +4 -0
  227. package/esm/observe/observer-registry.d.mts +30 -0
  228. package/esm/observe/observer-registry.d.mts.map +1 -0
  229. package/esm/observe/observer-registry.mjs +51 -0
  230. package/esm/observe/observer-registry.mjs.map +1 -0
  231. package/esm/observe/observer.contract.d.mts +40 -0
  232. package/esm/observe/observer.contract.d.mts.map +1 -0
  233. package/esm/observe/resolve-observers.d.mts +40 -0
  234. package/esm/observe/resolve-observers.d.mts.map +1 -0
  235. package/esm/observe/resolve-observers.mjs +73 -0
  236. package/esm/observe/resolve-observers.mjs.map +1 -0
  237. package/esm/orchestrator/execution.d.mts.map +1 -1
  238. package/esm/orchestrator/execution.mjs +5 -2
  239. package/esm/orchestrator/execution.mjs.map +1 -1
  240. package/esm/orchestrator/index.d.mts +1 -0
  241. package/esm/orchestrator/index.mjs +1 -0
  242. package/esm/orchestrator/orchestrator.d.mts.map +1 -1
  243. package/esm/orchestrator/orchestrator.mjs +39 -6
  244. package/esm/orchestrator/orchestrator.mjs.map +1 -1
  245. package/esm/orchestrator/session-lock.d.mts +25 -0
  246. package/esm/orchestrator/session-lock.d.mts.map +1 -0
  247. package/esm/orchestrator/session-lock.mjs +83 -0
  248. package/esm/orchestrator/session-lock.mjs.map +1 -0
  249. package/esm/planner/dag-scheduler.mjs +97 -0
  250. package/esm/planner/dag-scheduler.mjs.map +1 -0
  251. package/esm/planner/plan-prompt.d.mts +1 -1
  252. package/esm/planner/plan-prompt.d.mts.map +1 -1
  253. package/esm/planner/plan-prompt.mjs +2 -1
  254. package/esm/planner/plan-prompt.mjs.map +1 -1
  255. package/esm/planner/plan-schema.mjs +17 -14
  256. package/esm/planner/plan-schema.mjs.map +1 -1
  257. package/esm/planner/planner-run.d.mts.map +1 -1
  258. package/esm/planner/planner-run.mjs +300 -29
  259. package/esm/planner/planner-run.mjs.map +1 -1
  260. package/esm/planner/planner.mjs +1 -1
  261. package/esm/planner/planner.mjs.map +1 -1
  262. package/esm/prompt/errors.d.mts +57 -0
  263. package/esm/prompt/errors.d.mts.map +1 -0
  264. package/esm/prompt/errors.mjs +73 -0
  265. package/esm/prompt/errors.mjs.map +1 -0
  266. package/esm/prompt/index.d.mts +3 -0
  267. package/esm/prompt/index.mjs +4 -0
  268. package/esm/prompt/prompt-langfuse-sync.mjs +104 -0
  269. package/esm/prompt/prompt-langfuse-sync.mjs.map +1 -0
  270. package/esm/prompt/prompt-langfuse-sync.type.d.mts +32 -0
  271. package/esm/prompt/prompt-langfuse-sync.type.d.mts.map +1 -0
  272. package/esm/prompt/prompt-validate.mjs +170 -0
  273. package/esm/prompt/prompt-validate.mjs.map +1 -0
  274. package/esm/prompt/prompt.d.mts +54 -0
  275. package/esm/prompt/prompt.d.mts.map +1 -0
  276. package/esm/prompt/prompt.mjs +218 -0
  277. package/esm/prompt/prompt.mjs.map +1 -0
  278. package/esm/prompt/prompt.type.d.mts +174 -0
  279. package/esm/prompt/prompt.type.d.mts.map +1 -0
  280. package/esm/prompts/index.d.mts +3 -0
  281. package/esm/prompts/index.mjs +3 -0
  282. package/esm/prompts/prompts-manager.contract.d.mts +154 -0
  283. package/esm/prompts/prompts-manager.contract.d.mts.map +1 -0
  284. package/esm/prompts/prompts-manager.d.mts +38 -0
  285. package/esm/prompts/prompts-manager.d.mts.map +1 -0
  286. package/esm/prompts/prompts-manager.mjs +410 -0
  287. package/esm/prompts/prompts-manager.mjs.map +1 -0
  288. package/esm/prompts/prompts-manager.type.d.mts +172 -0
  289. package/esm/prompts/prompts-manager.type.d.mts.map +1 -0
  290. package/esm/prompts/prompts-validate.mjs +200 -0
  291. package/esm/prompts/prompts-validate.mjs.map +1 -0
  292. package/esm/rag/as-tool.mjs +48 -0
  293. package/esm/rag/as-tool.mjs.map +1 -0
  294. package/esm/rag/chunk/chunk.d.mts +24 -0
  295. package/esm/rag/chunk/chunk.d.mts.map +1 -0
  296. package/esm/rag/chunk/chunk.mjs +44 -0
  297. package/esm/rag/chunk/chunk.mjs.map +1 -0
  298. package/esm/rag/chunk/fixed.mjs +32 -0
  299. package/esm/rag/chunk/fixed.mjs.map +1 -0
  300. package/esm/rag/chunk/markdown.mjs +75 -0
  301. package/esm/rag/chunk/markdown.mjs.map +1 -0
  302. package/esm/rag/chunk/recursive.mjs +132 -0
  303. package/esm/rag/chunk/recursive.mjs.map +1 -0
  304. package/esm/rag/chunk/sentence.mjs +73 -0
  305. package/esm/rag/chunk/sentence.mjs.map +1 -0
  306. package/esm/rag/contracts/chunk-options.type.d.mts +35 -0
  307. package/esm/rag/contracts/chunk-options.type.d.mts.map +1 -0
  308. package/esm/rag/contracts/citation.type.d.mts +35 -0
  309. package/esm/rag/contracts/citation.type.d.mts.map +1 -0
  310. package/esm/rag/contracts/index.d.mts +4 -0
  311. package/esm/rag/contracts/rag-config.type.d.mts +68 -0
  312. package/esm/rag/contracts/rag-config.type.d.mts.map +1 -0
  313. package/esm/rag/contracts/rag-document.type.d.mts +21 -0
  314. package/esm/rag/contracts/rag-document.type.d.mts.map +1 -0
  315. package/esm/rag/hybrid/bm25.d.mts +23 -0
  316. package/esm/rag/hybrid/bm25.d.mts.map +1 -0
  317. package/esm/rag/hybrid/bm25.mjs +51 -0
  318. package/esm/rag/hybrid/bm25.mjs.map +1 -0
  319. package/esm/rag/hybrid/hybrid-rank.d.mts +33 -0
  320. package/esm/rag/hybrid/hybrid-rank.d.mts.map +1 -0
  321. package/esm/rag/hybrid/hybrid-rank.mjs +29 -0
  322. package/esm/rag/hybrid/hybrid-rank.mjs.map +1 -0
  323. package/esm/rag/hybrid/rrf.d.mts +25 -0
  324. package/esm/rag/hybrid/rrf.d.mts.map +1 -0
  325. package/esm/rag/hybrid/rrf.mjs +30 -0
  326. package/esm/rag/hybrid/rrf.mjs.map +1 -0
  327. package/esm/rag/index.d.mts +15 -0
  328. package/esm/rag/index.mjs +11 -0
  329. package/esm/rag/rag.d.mts +38 -0
  330. package/esm/rag/rag.d.mts.map +1 -0
  331. package/esm/rag/rag.mjs +126 -0
  332. package/esm/rag/rag.mjs.map +1 -0
  333. package/esm/rag/rerank/keyword-reranker.d.mts +32 -0
  334. package/esm/rag/rerank/keyword-reranker.d.mts.map +1 -0
  335. package/esm/rag/rerank/keyword-reranker.mjs +58 -0
  336. package/esm/rag/rerank/keyword-reranker.mjs.map +1 -0
  337. package/esm/rag/rerank/llm-reranker.d.mts +36 -0
  338. package/esm/rag/rerank/llm-reranker.d.mts.map +1 -0
  339. package/esm/rag/rerank/llm-reranker.mjs +85 -0
  340. package/esm/rag/rerank/llm-reranker.mjs.map +1 -0
  341. package/esm/rag/rerank/reranker.contract.d.mts +28 -0
  342. package/esm/rag/rerank/reranker.contract.d.mts.map +1 -0
  343. package/esm/rag/retrieve.mjs +68 -0
  344. package/esm/rag/retrieve.mjs.map +1 -0
  345. package/esm/rag/store/cache-vector-store.d.mts +27 -0
  346. package/esm/rag/store/cache-vector-store.d.mts.map +1 -0
  347. package/esm/rag/store/cache-vector-store.mjs +48 -0
  348. package/esm/rag/store/cache-vector-store.mjs.map +1 -0
  349. package/esm/rag/store/vector-store.contract.d.mts +38 -0
  350. package/esm/rag/store/vector-store.contract.d.mts.map +1 -0
  351. package/esm/rag/transforms/multi-query.d.mts +27 -0
  352. package/esm/rag/transforms/multi-query.d.mts.map +1 -0
  353. package/esm/rag/transforms/multi-query.mjs +41 -0
  354. package/esm/rag/transforms/multi-query.mjs.map +1 -0
  355. package/esm/security/index.mjs +5 -0
  356. package/esm/security/outbound-policy.d.mts +46 -0
  357. package/esm/security/outbound-policy.d.mts.map +1 -0
  358. package/esm/security/outbound-policy.mjs +187 -0
  359. package/esm/security/outbound-policy.mjs.map +1 -0
  360. package/esm/security/outbound-policy.type.d.mts +74 -0
  361. package/esm/security/outbound-policy.type.d.mts.map +1 -0
  362. package/esm/security/private-ip.d.mts +15 -0
  363. package/esm/security/private-ip.d.mts.map +1 -0
  364. package/esm/security/private-ip.mjs +48 -0
  365. package/esm/security/private-ip.mjs.map +1 -0
  366. package/esm/security/redact.d.mts +59 -0
  367. package/esm/security/redact.d.mts.map +1 -0
  368. package/esm/security/redact.mjs +122 -0
  369. package/esm/security/redact.mjs.map +1 -0
  370. package/esm/serve/serve.d.mts +50 -0
  371. package/esm/serve/serve.d.mts.map +1 -0
  372. package/esm/serve/serve.mjs +90 -0
  373. package/esm/serve/serve.mjs.map +1 -0
  374. package/esm/serve/sse.d.mts +20 -0
  375. package/esm/serve/sse.d.mts.map +1 -0
  376. package/esm/serve/sse.mjs +25 -0
  377. package/esm/serve/sse.mjs.map +1 -0
  378. package/esm/serve/stream-to-sse.d.mts +29 -0
  379. package/esm/serve/stream-to-sse.d.mts.map +1 -0
  380. package/esm/serve/stream-to-sse.mjs +37 -0
  381. package/esm/serve/stream-to-sse.mjs.map +1 -0
  382. package/esm/skills/catalog.d.mts +49 -0
  383. package/esm/skills/catalog.d.mts.map +1 -0
  384. package/esm/skills/catalog.mjs +140 -0
  385. package/esm/skills/catalog.mjs.map +1 -0
  386. package/esm/skills/contracts/skill-record.type.d.mts +37 -0
  387. package/esm/skills/contracts/skill-record.type.d.mts.map +1 -0
  388. package/esm/skills/contracts/skills-config.type.d.mts +108 -0
  389. package/esm/skills/contracts/skills-config.type.d.mts.map +1 -0
  390. package/esm/skills/contracts/skills-store.contract.d.mts +28 -0
  391. package/esm/skills/contracts/skills-store.contract.d.mts.map +1 -0
  392. package/esm/skills/contracts/skills.contract.d.mts +43 -0
  393. package/esm/skills/contracts/skills.contract.d.mts.map +1 -0
  394. package/esm/skills/index.d.mts +16 -0
  395. package/esm/skills/index.mjs +14 -0
  396. package/esm/skills/load-skill-tool.d.mts +38 -0
  397. package/esm/skills/load-skill-tool.d.mts.map +1 -0
  398. package/esm/skills/load-skill-tool.mjs +65 -0
  399. package/esm/skills/load-skill-tool.mjs.map +1 -0
  400. package/esm/skills/review-gate.d.mts +33 -0
  401. package/esm/skills/review-gate.d.mts.map +1 -0
  402. package/esm/skills/review-gate.mjs +60 -0
  403. package/esm/skills/review-gate.mjs.map +1 -0
  404. package/esm/skills/save-skill-tool.d.mts +39 -0
  405. package/esm/skills/save-skill-tool.d.mts.map +1 -0
  406. package/esm/skills/save-skill-tool.mjs +65 -0
  407. package/esm/skills/save-skill-tool.mjs.map +1 -0
  408. package/esm/skills/skills.d.mts +33 -0
  409. package/esm/skills/skills.d.mts.map +1 -0
  410. package/esm/skills/skills.mjs +109 -0
  411. package/esm/skills/skills.mjs.map +1 -0
  412. package/esm/skills/sources/directory-source.d.mts +19 -0
  413. package/esm/skills/sources/directory-source.d.mts.map +1 -0
  414. package/esm/skills/sources/directory-source.mjs +108 -0
  415. package/esm/skills/sources/directory-source.mjs.map +1 -0
  416. package/esm/skills/sources/index.d.mts +18 -0
  417. package/esm/skills/sources/index.d.mts.map +1 -0
  418. package/esm/skills/sources/index.mjs +27 -0
  419. package/esm/skills/sources/index.mjs.map +1 -0
  420. package/esm/skills/sources/parse-frontmatter.d.mts +27 -0
  421. package/esm/skills/sources/parse-frontmatter.d.mts.map +1 -0
  422. package/esm/skills/sources/parse-frontmatter.mjs +46 -0
  423. package/esm/skills/sources/parse-frontmatter.mjs.map +1 -0
  424. package/esm/skills/sources/store-source.d.mts +14 -0
  425. package/esm/skills/sources/store-source.d.mts.map +1 -0
  426. package/esm/skills/sources/store-source.mjs +15 -0
  427. package/esm/skills/sources/store-source.mjs.map +1 -0
  428. package/esm/skills/sources/url-source.d.mts +29 -0
  429. package/esm/skills/sources/url-source.d.mts.map +1 -0
  430. package/esm/skills/sources/url-source.mjs +117 -0
  431. package/esm/skills/sources/url-source.mjs.map +1 -0
  432. package/esm/skills/store/mock-skills-store.d.mts +57 -0
  433. package/esm/skills/store/mock-skills-store.d.mts.map +1 -0
  434. package/esm/skills/store/mock-skills-store.mjs +100 -0
  435. package/esm/skills/store/mock-skills-store.mjs.map +1 -0
  436. package/esm/skills/store/procedural-skill-store.d.mts +30 -0
  437. package/esm/skills/store/procedural-skill-store.d.mts.map +1 -0
  438. package/esm/skills/store/procedural-skill-store.mjs +125 -0
  439. package/esm/skills/store/procedural-skill-store.mjs.map +1 -0
  440. package/esm/supervisor/as-tool.mjs +2 -2
  441. package/esm/supervisor/as-tool.mjs.map +1 -1
  442. package/esm/supervisor/execution.d.mts.map +1 -1
  443. package/esm/supervisor/execution.mjs +31 -28
  444. package/esm/supervisor/execution.mjs.map +1 -1
  445. package/esm/supervisor/supervisor.d.mts.map +1 -1
  446. package/esm/supervisor/supervisor.mjs +8 -3
  447. package/esm/supervisor/supervisor.mjs.map +1 -1
  448. package/esm/system-prompt/index.d.mts +4 -0
  449. package/esm/system-prompt/system-prompt.d.mts +68 -4
  450. package/esm/system-prompt/system-prompt.d.mts.map +1 -1
  451. package/esm/system-prompt/system-prompt.mjs +89 -5
  452. package/esm/system-prompt/system-prompt.mjs.map +1 -1
  453. package/esm/team/gates.mjs +48 -0
  454. package/esm/team/gates.mjs.map +1 -0
  455. package/esm/team/index.d.mts +1 -0
  456. package/esm/team/index.mjs +3 -0
  457. package/esm/team/team.d.mts +42 -0
  458. package/esm/team/team.d.mts.map +1 -0
  459. package/esm/team/team.mjs +94 -0
  460. package/esm/team/team.mjs.map +1 -0
  461. package/esm/tool/executable-as-tool.d.mts.map +1 -1
  462. package/esm/tool/executable-as-tool.mjs +2 -2
  463. package/esm/tool/executable-as-tool.mjs.map +1 -1
  464. package/esm/tool/tool.d.mts.map +1 -1
  465. package/esm/tool/tool.mjs +2 -2
  466. package/esm/tool/tool.mjs.map +1 -1
  467. package/esm/utils/compute-cost.d.mts +17 -1
  468. package/esm/utils/compute-cost.d.mts.map +1 -1
  469. package/esm/utils/compute-cost.mjs +26 -1
  470. package/esm/utils/compute-cost.mjs.map +1 -1
  471. package/esm/utils/extract-json-lenient.d.mts +42 -0
  472. package/esm/utils/extract-json-lenient.d.mts.map +1 -0
  473. package/esm/utils/extract-json-lenient.mjs +97 -0
  474. package/esm/utils/extract-json-lenient.mjs.map +1 -0
  475. package/esm/utils/index.d.mts +4 -2
  476. package/esm/utils/index.mjs +3 -1
  477. package/esm/utils/json-schema.d.mts +1 -1
  478. package/esm/utils/prepare-attachment-part.d.mts +10 -1
  479. package/esm/utils/prepare-attachment-part.d.mts.map +1 -1
  480. package/esm/utils/prepare-attachment-part.mjs +103 -11
  481. package/esm/utils/prepare-attachment-part.mjs.map +1 -1
  482. package/esm/utils/resolve-attachment.d.mts +4 -3
  483. package/esm/utils/resolve-attachment.d.mts.map +1 -1
  484. package/esm/utils/resolve-attachment.mjs +4 -3
  485. package/esm/utils/resolve-attachment.mjs.map +1 -1
  486. package/esm/utils/run-context.d.mts +94 -0
  487. package/esm/utils/run-context.d.mts.map +1 -0
  488. package/esm/utils/run-context.mjs +98 -0
  489. package/esm/utils/run-context.mjs.map +1 -0
  490. package/esm/vcr/cassette-io.mjs +57 -0
  491. package/esm/vcr/cassette-io.mjs.map +1 -0
  492. package/esm/vcr/errors.d.mts +42 -0
  493. package/esm/vcr/errors.d.mts.map +1 -0
  494. package/esm/vcr/errors.mjs +37 -0
  495. package/esm/vcr/errors.mjs.map +1 -0
  496. package/esm/vcr/hash-request.d.mts +28 -0
  497. package/esm/vcr/hash-request.d.mts.map +1 -0
  498. package/esm/vcr/hash-request.mjs +118 -0
  499. package/esm/vcr/hash-request.mjs.map +1 -0
  500. package/esm/vcr/index.d.mts +4 -0
  501. package/esm/vcr/index.mjs +5 -0
  502. package/esm/vcr/vcr.d.mts +32 -0
  503. package/esm/vcr/vcr.d.mts.map +1 -0
  504. package/esm/vcr/vcr.mjs +248 -0
  505. package/esm/vcr/vcr.mjs.map +1 -0
  506. package/esm/vcr/vcr.type.d.mts +118 -0
  507. package/esm/vcr/vcr.type.d.mts.map +1 -0
  508. package/esm/workflow/as-tool.mjs +2 -2
  509. package/esm/workflow/as-tool.mjs.map +1 -1
  510. package/esm/workflow/engine.mjs +1 -0
  511. package/esm/workflow/engine.mjs.map +1 -1
  512. package/esm/workflow/step-runner.mjs +19 -20
  513. package/esm/workflow/step-runner.mjs.map +1 -1
  514. package/esm/workflow/workflow.d.mts.map +1 -1
  515. package/esm/workflow/workflow.mjs +8 -3
  516. package/esm/workflow/workflow.mjs.map +1 -1
  517. package/llms-full.txt +1683 -68
  518. package/llms.txt +16 -4
  519. package/package.json +7 -3
  520. package/skills/README.md +40 -4
  521. package/skills/ai-dx-helpers/SKILL.md +2 -2
  522. package/skills/approve-tool-calls/SKILL.md +134 -0
  523. package/skills/attach-ai-middleware/SKILL.md +1 -1
  524. package/skills/detect-and-redact-pii/SKILL.md +104 -0
  525. package/skills/durable-resume/SKILL.md +128 -0
  526. package/skills/escalate-block-to-human/SKILL.md +85 -0
  527. package/skills/eval-datasets-and-ci/SKILL.md +117 -0
  528. package/skills/guard-input-output/SKILL.md +117 -0
  529. package/skills/manage-prompts/SKILL.md +186 -0
  530. package/skills/observe-ai-flows/SKILL.md +94 -0
  531. package/skills/record-replay-llm/SKILL.md +92 -0
  532. package/skills/run-ai-agent/SKILL.md +26 -1
  533. package/skills/run-ai-rag/SKILL.md +139 -0
  534. package/skills/run-ai-team/SKILL.md +107 -0
  535. package/skills/run-orchestrator/SKILL.md +2 -0
  536. package/skills/run-planner/SKILL.md +73 -8
  537. package/skills/run-supervisor/SKILL.md +20 -1
  538. package/skills/use-runtime-skills/SKILL.md +106 -0
  539. package/skills/write-system-prompt/SKILL.md +30 -1
  540. package/cjs/index.cjs.map +0 -1
  541. package/esm/contracts/result/index.d.mts +0 -15
@@ -0,0 +1,27 @@
1
+ import { ModelContract } from "../../contracts/model.contract.mjs";
2
+
3
+ //#region ../@warlock.js/ai/src/rag/transforms/multi-query.d.ts
4
+ /** Options for {@link multiQuery}. */
5
+ type MultiQueryOptions = {
6
+ /** How many alternative phrasings to request. Default 3. */n?: number; /** Include the original query in the returned list. Default true. */
7
+ includeOriginal?: boolean;
8
+ };
9
+ /**
10
+ * Multi-query expansion (A4) — ask a model for several alternative
11
+ * phrasings of `query`, so retrieval covers vocabulary the original
12
+ * wording missed (synonyms, specificity, rephrasings). Pair the variants
13
+ * with {@link hybridRank} / a vector search and fuse the per-variant hits.
14
+ *
15
+ * Deterministic, dependency-light parsing: the model is asked for one
16
+ * query per line; bullets / numbering are stripped, blanks dropped, and
17
+ * the set is de-duplicated. Returns the original (unless opted out) plus
18
+ * up to `n` variants.
19
+ *
20
+ * @example
21
+ * const queries = await multiQuery(model, "how do I cancel?", { n: 3 });
22
+ * // → ["how do I cancel?", "cancel my subscription", "end my plan", ...]
23
+ */
24
+ declare function multiQuery(model: ModelContract, query: string, options?: MultiQueryOptions): Promise<string[]>;
25
+ //#endregion
26
+ export { MultiQueryOptions, multiQuery };
27
+ //# sourceMappingURL=multi-query.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-query.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/rag/transforms/multi-query.ts"],"mappings":";;;;KAGY,iBAAA;EAAA,4DAEV,CAAA;EAEA,eAAe;AAAA;AAkBjB;;;;;;;;;;;;;;;AAAA,iBAAsB,UAAA,CACpB,KAAA,EAAO,aAAA,EACP,KAAA,UACA,OAAA,GAAS,iBAAA,GACR,OAAA"}
@@ -0,0 +1,41 @@
1
+ //#region ../@warlock.js/ai/src/rag/transforms/multi-query.ts
2
+ /**
3
+ * Multi-query expansion (A4) — ask a model for several alternative
4
+ * phrasings of `query`, so retrieval covers vocabulary the original
5
+ * wording missed (synonyms, specificity, rephrasings). Pair the variants
6
+ * with {@link hybridRank} / a vector search and fuse the per-variant hits.
7
+ *
8
+ * Deterministic, dependency-light parsing: the model is asked for one
9
+ * query per line; bullets / numbering are stripped, blanks dropped, and
10
+ * the set is de-duplicated. Returns the original (unless opted out) plus
11
+ * up to `n` variants.
12
+ *
13
+ * @example
14
+ * const queries = await multiQuery(model, "how do I cancel?", { n: 3 });
15
+ * // → ["how do I cancel?", "cancel my subscription", "end my plan", ...]
16
+ */
17
+ async function multiQuery(model, query, options = {}) {
18
+ const n = options.n ?? 3;
19
+ const includeOriginal = options.includeOriginal ?? true;
20
+ const prompt = `Rewrite the following search query into ${n} alternative phrasings that would retrieve relevant documents. Output ONE query per line, no numbering or commentary.\n\nQuery: ${query}`;
21
+ const variants = (await model.complete([{
22
+ role: "user",
23
+ content: prompt
24
+ }])).content.split("\n").map((line) => line.replace(/^\s*(?:[-*•]|\d+[.)])\s*/, "").trim()).filter(Boolean);
25
+ const seen = /* @__PURE__ */ new Set();
26
+ const out = [];
27
+ const add = (q) => {
28
+ const key = q.toLowerCase();
29
+ if (!seen.has(key)) {
30
+ seen.add(key);
31
+ out.push(q);
32
+ }
33
+ };
34
+ if (includeOriginal) add(query);
35
+ for (const variant of variants.slice(0, n)) add(variant);
36
+ return out;
37
+ }
38
+
39
+ //#endregion
40
+ export { multiQuery };
41
+ //# sourceMappingURL=multi-query.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-query.mjs","names":[],"sources":["../../../../../../../../@warlock.js/ai/src/rag/transforms/multi-query.ts"],"sourcesContent":["import type { ModelContract } from \"../../contracts/model.contract\";\n\n/** Options for {@link multiQuery}. */\nexport type MultiQueryOptions = {\n /** How many alternative phrasings to request. Default 3. */\n n?: number;\n /** Include the original query in the returned list. Default true. */\n includeOriginal?: boolean;\n};\n\n/**\n * Multi-query expansion (A4) — ask a model for several alternative\n * phrasings of `query`, so retrieval covers vocabulary the original\n * wording missed (synonyms, specificity, rephrasings). Pair the variants\n * with {@link hybridRank} / a vector search and fuse the per-variant hits.\n *\n * Deterministic, dependency-light parsing: the model is asked for one\n * query per line; bullets / numbering are stripped, blanks dropped, and\n * the set is de-duplicated. Returns the original (unless opted out) plus\n * up to `n` variants.\n *\n * @example\n * const queries = await multiQuery(model, \"how do I cancel?\", { n: 3 });\n * // → [\"how do I cancel?\", \"cancel my subscription\", \"end my plan\", ...]\n */\nexport async function multiQuery(\n model: ModelContract,\n query: string,\n options: MultiQueryOptions = {},\n): Promise<string[]> {\n const n = options.n ?? 3;\n const includeOriginal = options.includeOriginal ?? true;\n\n const prompt =\n `Rewrite the following search query into ${n} alternative phrasings that would ` +\n `retrieve relevant documents. Output ONE query per line, no numbering or commentary.\\n\\n` +\n `Query: ${query}`;\n\n const response = await model.complete([{ role: \"user\", content: prompt }]);\n\n const variants = response.content\n .split(\"\\n\")\n .map(line => line.replace(/^\\s*(?:[-*•]|\\d+[.)])\\s*/, \"\").trim())\n .filter(Boolean);\n\n const seen = new Set<string>();\n const out: string[] = [];\n\n const add = (q: string) => {\n const key = q.toLowerCase();\n if (!seen.has(key)) {\n seen.add(key);\n out.push(q);\n }\n };\n\n if (includeOriginal) add(query);\n for (const variant of variants.slice(0, n)) add(variant);\n\n return out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAyBA,eAAsB,WACpB,OACA,OACA,UAA6B,CAAC,GACX;CACnB,MAAM,IAAI,QAAQ,KAAK;CACvB,MAAM,kBAAkB,QAAQ,mBAAmB;CAEnD,MAAM,SACJ,2CAA2C,EAAE,kIAEnC;CAIZ,MAAM,YAAW,MAFM,MAAM,SAAS,CAAC;EAAE,MAAM;EAAQ,SAAS;CAAO,CAAC,CAAC,EAEhD,CAAC,QACvB,MAAM,IAAI,CAAC,CACX,KAAI,SAAQ,KAAK,QAAQ,4BAA4B,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAChE,OAAO,OAAO;CAEjB,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,MAAgB,CAAC;CAEvB,MAAM,OAAO,MAAc;EACzB,MAAM,MAAM,EAAE,YAAY;EAC1B,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG;GAClB,KAAK,IAAI,GAAG;GACZ,IAAI,KAAK,CAAC;EACZ;CACF;CAEA,IAAI,iBAAiB,IAAI,KAAK;CAC9B,KAAK,MAAM,WAAW,SAAS,MAAM,GAAG,CAAC,GAAG,IAAI,OAAO;CAEvD,OAAO;AACT"}
@@ -0,0 +1,5 @@
1
+ import { isPrivateOrReservedIp } from "./private-ip.mjs";
2
+ import { assertUrlAllowed, fetchTextWithPolicy, guardedFetch, readTextCapped, resolveOutboundPolicy } from "./outbound-policy.mjs";
3
+ import { DEFAULT_SENSITIVE_KEYS, SENSITIVE_HEADERS, redact, redactError, redactHeaders, scrubSecrets } from "./redact.mjs";
4
+
5
+ export { };
@@ -0,0 +1,46 @@
1
+ import { OutboundPolicy, ResolvedOutboundPolicy } from "./outbound-policy.type.mjs";
2
+
3
+ //#region ../@warlock.js/ai/src/security/outbound-policy.d.ts
4
+ /**
5
+ * Fill an {@link OutboundPolicy} with strict defaults: https-only,
6
+ * private-IP deny on, 10s timeout, 5 MiB cap, global `fetch`. Idempotent
7
+ * — resolving an already-resolved policy yields the same shape.
8
+ */
9
+ declare function resolveOutboundPolicy(policy?: OutboundPolicy): ResolvedOutboundPolicy;
10
+ /**
11
+ * Validate a URL against the policy BEFORE any network call: scheme
12
+ * allowlist, host allowlist, and (when enabled) a DNS resolution that
13
+ * rejects private / loopback / link-local / metadata addresses — the SSRF
14
+ * guard. Returns the parsed `URL` on success; throws
15
+ * {@link OutboundPolicyError} otherwise.
16
+ */
17
+ declare function assertUrlAllowed(rawUrl: string, policy: ResolvedOutboundPolicy): Promise<URL>;
18
+ /**
19
+ * Policy-guarded `fetch`: validates the URL ({@link assertUrlAllowed}),
20
+ * then performs the request with the policy's timeout and (optional)
21
+ * caller signal merged. Returns the raw `Response` — read its body via
22
+ * {@link readTextCapped} to enforce `maxBytes`. Throws
23
+ * {@link OutboundPolicyError} on a policy violation or timeout.
24
+ */
25
+ declare function guardedFetch(rawUrl: string, policyInput: OutboundPolicy, init?: RequestInit): Promise<Response>;
26
+ /**
27
+ * Read a response body as UTF-8 text with a hard byte cap. A declared
28
+ * `content-length` over the cap fails fast; otherwise the stream is read
29
+ * chunk-by-chunk and aborted the moment the running total exceeds
30
+ * `maxBytes`. Throws {@link OutboundPolicyError} on overflow.
31
+ */
32
+ declare function readTextCapped(response: Response, maxBytes: number): Promise<string>;
33
+ /**
34
+ * Convenience: {@link guardedFetch} + {@link readTextCapped}. Returns the
35
+ * response status alongside the (capped) body text so callers can shape
36
+ * their own not-OK error. The body is only read when the response is OK.
37
+ */
38
+ declare function fetchTextWithPolicy(rawUrl: string, policyInput: OutboundPolicy, init?: RequestInit): Promise<{
39
+ ok: boolean;
40
+ status: number;
41
+ statusText: string;
42
+ text: string;
43
+ }>;
44
+ //#endregion
45
+ export { assertUrlAllowed, fetchTextWithPolicy, guardedFetch, readTextCapped, resolveOutboundPolicy };
46
+ //# sourceMappingURL=outbound-policy.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbound-policy.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai/src/security/outbound-policy.ts"],"mappings":";;;;;AAmBA;;;iBAAgB,qBAAA,CACd,MAAA,GAAQ,cAAA,GACP,sBAAsB;;;;;AAAA;AAiCzB;;iBAAsB,gBAAA,CACpB,MAAA,UACA,MAAA,EAAQ,sBAAA,GACP,OAAA,CAAQ,GAAA;;;;;;;;iBAiGW,YAAA,CACpB,MAAA,UACA,WAAA,EAAa,cAAA,EACb,IAAA,GAAO,WAAA,GACN,OAAA,CAAQ,QAAA;;;;AArGG;AAiGd;;iBAkCsB,cAAA,CACpB,QAAA,EAAU,QAAA,EACV,QAAA,WACC,OAAO;;;;;;iBAgDY,mBAAA,CACpB,MAAA,UACA,WAAA,EAAa,cAAA,EACb,IAAA,GAAO,WAAA,GACN,OAAA;EAAU,EAAA;EAAa,MAAA;EAAgB,UAAA;EAAoB,IAAA;AAAA"}
@@ -0,0 +1,187 @@
1
+ import { OutboundPolicyError } from "../errors/outbound-policy-error.mjs";
2
+ import "../errors/index.mjs";
3
+ import { isPrivateOrReservedIp } from "./private-ip.mjs";
4
+ import { lookup } from "node:dns/promises";
5
+ import { isIP } from "node:net";
6
+
7
+ //#region ../@warlock.js/ai/src/security/outbound-policy.ts
8
+ /** 5 MiB — default cap on an outbound response body. */
9
+ const DEFAULT_MAX_BYTES = 5 * 1024 * 1024;
10
+ /** 10s — default per-request timeout. */
11
+ const DEFAULT_TIMEOUT_MS = 1e4;
12
+ /**
13
+ * Fill an {@link OutboundPolicy} with strict defaults: https-only,
14
+ * private-IP deny on, 10s timeout, 5 MiB cap, global `fetch`. Idempotent
15
+ * — resolving an already-resolved policy yields the same shape.
16
+ */
17
+ function resolveOutboundPolicy(policy = {}) {
18
+ return {
19
+ allowedSchemes: policy.allowedSchemes ?? ["https"],
20
+ hostAllowlist: policy.hostAllowlist,
21
+ denyPrivateIPsAfterDNS: policy.denyPrivateIPsAfterDNS ?? true,
22
+ maxBytes: policy.maxBytes ?? DEFAULT_MAX_BYTES,
23
+ timeoutMs: policy.timeoutMs ?? DEFAULT_TIMEOUT_MS,
24
+ signal: policy.signal,
25
+ fetch: policy.fetch ?? globalThis.fetch
26
+ };
27
+ }
28
+ /** Strip the `[ ]` IPv6 brackets `URL.hostname` keeps. */
29
+ function stripBrackets(host) {
30
+ return host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
31
+ }
32
+ /** Whether `host` equals or is a subdomain of any allowlist entry. */
33
+ function hostAllowed(host, allowlist) {
34
+ const lower = host.toLowerCase();
35
+ return allowlist.some((entry) => {
36
+ const e = entry.toLowerCase();
37
+ return lower === e || lower.endsWith(`.${e}`);
38
+ });
39
+ }
40
+ /**
41
+ * Validate a URL against the policy BEFORE any network call: scheme
42
+ * allowlist, host allowlist, and (when enabled) a DNS resolution that
43
+ * rejects private / loopback / link-local / metadata addresses — the SSRF
44
+ * guard. Returns the parsed `URL` on success; throws
45
+ * {@link OutboundPolicyError} otherwise.
46
+ */
47
+ async function assertUrlAllowed(rawUrl, policy) {
48
+ let url;
49
+ try {
50
+ url = new URL(rawUrl);
51
+ } catch {
52
+ throw new OutboundPolicyError(`outbound request blocked — invalid URL: ${rawUrl}`, { context: { url: rawUrl } });
53
+ }
54
+ const scheme = url.protocol.replace(/:$/, "").toLowerCase();
55
+ if (!policy.allowedSchemes.some((s) => s.toLowerCase() === scheme)) throw new OutboundPolicyError(`outbound request blocked — scheme "${scheme}" is not allowed (allowed: ${policy.allowedSchemes.join(", ")})`, { context: {
56
+ url: rawUrl,
57
+ scheme
58
+ } });
59
+ const host = stripBrackets(url.hostname);
60
+ if (policy.hostAllowlist && !hostAllowed(host, policy.hostAllowlist)) throw new OutboundPolicyError(`outbound request blocked — host "${host}" is not in the allowlist`, { context: {
61
+ url: rawUrl,
62
+ host
63
+ } });
64
+ if (policy.denyPrivateIPsAfterDNS) await assertHostNotPrivate(host, rawUrl);
65
+ return url;
66
+ }
67
+ /**
68
+ * Reject when `host` is — or resolves to — a private / reserved address.
69
+ * IP literals are checked directly; hostnames are resolved via DNS and
70
+ * every returned address is checked (a public name pointing inward is
71
+ * caught). A resolution failure fails closed.
72
+ */
73
+ async function assertHostNotPrivate(host, rawUrl) {
74
+ if (isIP(host) !== 0) {
75
+ if (isPrivateOrReservedIp(host)) throw new OutboundPolicyError(`outbound request blocked — "${host}" is a private/reserved address`, { context: {
76
+ url: rawUrl,
77
+ address: host
78
+ } });
79
+ return;
80
+ }
81
+ let addresses;
82
+ try {
83
+ addresses = await lookup(host, { all: true });
84
+ } catch (cause) {
85
+ throw new OutboundPolicyError(`outbound request blocked — could not resolve host "${host}" to verify it is public`, {
86
+ cause,
87
+ context: {
88
+ url: rawUrl,
89
+ host
90
+ }
91
+ });
92
+ }
93
+ for (const { address } of addresses) if (isPrivateOrReservedIp(address)) throw new OutboundPolicyError(`outbound request blocked — host "${host}" resolves to a private/reserved address (${address})`, { context: {
94
+ url: rawUrl,
95
+ host,
96
+ address
97
+ } });
98
+ }
99
+ /** Merge the internal timeout signal with an optional caller signal. */
100
+ function mergeSignals(timeout, external) {
101
+ if (!external) return timeout;
102
+ const controller = new AbortController();
103
+ const abort = (from) => controller.abort(from.reason);
104
+ if (timeout.aborted) abort(timeout);
105
+ else timeout.addEventListener("abort", () => abort(timeout), { once: true });
106
+ if (external.aborted) abort(external);
107
+ else external.addEventListener("abort", () => abort(external), { once: true });
108
+ return controller.signal;
109
+ }
110
+ /**
111
+ * Policy-guarded `fetch`: validates the URL ({@link assertUrlAllowed}),
112
+ * then performs the request with the policy's timeout and (optional)
113
+ * caller signal merged. Returns the raw `Response` — read its body via
114
+ * {@link readTextCapped} to enforce `maxBytes`. Throws
115
+ * {@link OutboundPolicyError} on a policy violation or timeout.
116
+ */
117
+ async function guardedFetch(rawUrl, policyInput, init) {
118
+ const policy = resolveOutboundPolicy(policyInput);
119
+ const url = await assertUrlAllowed(rawUrl, policy);
120
+ const timeoutController = new AbortController();
121
+ const timer = setTimeout(() => {
122
+ timeoutController.abort(new OutboundPolicyError(`outbound request timed out after ${policy.timeoutMs}ms`, { context: {
123
+ url: rawUrl,
124
+ timeoutMs: policy.timeoutMs
125
+ } }));
126
+ }, policy.timeoutMs);
127
+ try {
128
+ return await policy.fetch(url, {
129
+ ...init,
130
+ signal: mergeSignals(timeoutController.signal, policy.signal)
131
+ });
132
+ } finally {
133
+ clearTimeout(timer);
134
+ }
135
+ }
136
+ /**
137
+ * Read a response body as UTF-8 text with a hard byte cap. A declared
138
+ * `content-length` over the cap fails fast; otherwise the stream is read
139
+ * chunk-by-chunk and aborted the moment the running total exceeds
140
+ * `maxBytes`. Throws {@link OutboundPolicyError} on overflow.
141
+ */
142
+ async function readTextCapped(response, maxBytes) {
143
+ const declared = Number(response.headers.get("content-length"));
144
+ if (Number.isFinite(declared) && declared > maxBytes) throw new OutboundPolicyError(`outbound response body too large — declared ${declared} bytes exceeds the ${maxBytes}-byte cap`, { context: {
145
+ declared,
146
+ maxBytes
147
+ } });
148
+ if (!response.body) {
149
+ const text = await response.text();
150
+ if (Buffer.byteLength(text) > maxBytes) throw new OutboundPolicyError(`outbound response body exceeded the ${maxBytes}-byte cap`, { context: { maxBytes } });
151
+ return text;
152
+ }
153
+ const reader = response.body.getReader();
154
+ const chunks = [];
155
+ let total = 0;
156
+ for (;;) {
157
+ const { done, value } = await reader.read();
158
+ if (done) break;
159
+ if (!value) continue;
160
+ total += value.byteLength;
161
+ if (total > maxBytes) {
162
+ await reader.cancel();
163
+ throw new OutboundPolicyError(`outbound response body exceeded the ${maxBytes}-byte cap`, { context: { maxBytes } });
164
+ }
165
+ chunks.push(value);
166
+ }
167
+ return Buffer.concat(chunks).toString("utf8");
168
+ }
169
+ /**
170
+ * Convenience: {@link guardedFetch} + {@link readTextCapped}. Returns the
171
+ * response status alongside the (capped) body text so callers can shape
172
+ * their own not-OK error. The body is only read when the response is OK.
173
+ */
174
+ async function fetchTextWithPolicy(rawUrl, policyInput, init) {
175
+ const policy = resolveOutboundPolicy(policyInput);
176
+ const response = await guardedFetch(rawUrl, policy, init);
177
+ return {
178
+ ok: response.ok,
179
+ status: response.status,
180
+ statusText: response.statusText,
181
+ text: response.ok ? await readTextCapped(response, policy.maxBytes) : ""
182
+ };
183
+ }
184
+
185
+ //#endregion
186
+ export { assertUrlAllowed, fetchTextWithPolicy, guardedFetch, readTextCapped, resolveOutboundPolicy };
187
+ //# sourceMappingURL=outbound-policy.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbound-policy.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai/src/security/outbound-policy.ts"],"sourcesContent":["import { lookup } from \"node:dns/promises\";\nimport { isIP } from \"node:net\";\nimport { OutboundPolicyError } from \"../errors\";\nimport { isPrivateOrReservedIp } from \"./private-ip\";\nimport type {\n OutboundPolicy,\n ResolvedOutboundPolicy,\n} from \"./outbound-policy.type\";\n\n/** 5 MiB — default cap on an outbound response body. */\nconst DEFAULT_MAX_BYTES = 5 * 1024 * 1024;\n/** 10s — default per-request timeout. */\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\n/**\n * Fill an {@link OutboundPolicy} with strict defaults: https-only,\n * private-IP deny on, 10s timeout, 5 MiB cap, global `fetch`. Idempotent\n * — resolving an already-resolved policy yields the same shape.\n */\nexport function resolveOutboundPolicy(\n policy: OutboundPolicy = {},\n): ResolvedOutboundPolicy {\n return {\n allowedSchemes: policy.allowedSchemes ?? [\"https\"],\n hostAllowlist: policy.hostAllowlist,\n denyPrivateIPsAfterDNS: policy.denyPrivateIPsAfterDNS ?? true,\n maxBytes: policy.maxBytes ?? DEFAULT_MAX_BYTES,\n timeoutMs: policy.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n signal: policy.signal,\n fetch: policy.fetch ?? globalThis.fetch,\n };\n}\n\n/** Strip the `[ ]` IPv6 brackets `URL.hostname` keeps. */\nfunction stripBrackets(host: string): string {\n return host.startsWith(\"[\") && host.endsWith(\"]\") ? host.slice(1, -1) : host;\n}\n\n/** Whether `host` equals or is a subdomain of any allowlist entry. */\nfunction hostAllowed(host: string, allowlist: string[]): boolean {\n const lower = host.toLowerCase();\n return allowlist.some(entry => {\n const e = entry.toLowerCase();\n return lower === e || lower.endsWith(`.${e}`);\n });\n}\n\n/**\n * Validate a URL against the policy BEFORE any network call: scheme\n * allowlist, host allowlist, and (when enabled) a DNS resolution that\n * rejects private / loopback / link-local / metadata addresses — the SSRF\n * guard. Returns the parsed `URL` on success; throws\n * {@link OutboundPolicyError} otherwise.\n */\nexport async function assertUrlAllowed(\n rawUrl: string,\n policy: ResolvedOutboundPolicy,\n): Promise<URL> {\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n throw new OutboundPolicyError(`outbound request blocked — invalid URL: ${rawUrl}`, {\n context: { url: rawUrl },\n });\n }\n\n const scheme = url.protocol.replace(/:$/, \"\").toLowerCase();\n if (!policy.allowedSchemes.some(s => s.toLowerCase() === scheme)) {\n throw new OutboundPolicyError(\n `outbound request blocked — scheme \"${scheme}\" is not allowed (allowed: ${policy.allowedSchemes.join(\", \")})`,\n { context: { url: rawUrl, scheme } },\n );\n }\n\n const host = stripBrackets(url.hostname);\n\n if (policy.hostAllowlist && !hostAllowed(host, policy.hostAllowlist)) {\n throw new OutboundPolicyError(\n `outbound request blocked — host \"${host}\" is not in the allowlist`,\n { context: { url: rawUrl, host } },\n );\n }\n\n if (policy.denyPrivateIPsAfterDNS) {\n await assertHostNotPrivate(host, rawUrl);\n }\n\n return url;\n}\n\n/**\n * Reject when `host` is — or resolves to — a private / reserved address.\n * IP literals are checked directly; hostnames are resolved via DNS and\n * every returned address is checked (a public name pointing inward is\n * caught). A resolution failure fails closed.\n */\nasync function assertHostNotPrivate(host: string, rawUrl: string): Promise<void> {\n if (isIP(host) !== 0) {\n if (isPrivateOrReservedIp(host)) {\n throw new OutboundPolicyError(\n `outbound request blocked — \"${host}\" is a private/reserved address`,\n { context: { url: rawUrl, address: host } },\n );\n }\n return;\n }\n\n let addresses: Array<{ address: string }>;\n try {\n addresses = await lookup(host, { all: true });\n } catch (cause) {\n throw new OutboundPolicyError(\n `outbound request blocked — could not resolve host \"${host}\" to verify it is public`,\n { cause, context: { url: rawUrl, host } },\n );\n }\n\n for (const { address } of addresses) {\n if (isPrivateOrReservedIp(address)) {\n throw new OutboundPolicyError(\n `outbound request blocked — host \"${host}\" resolves to a private/reserved address (${address})`,\n { context: { url: rawUrl, host, address } },\n );\n }\n }\n}\n\n/** Merge the internal timeout signal with an optional caller signal. */\nfunction mergeSignals(\n timeout: AbortSignal,\n external?: AbortSignal,\n): AbortSignal {\n if (!external) return timeout;\n\n const controller = new AbortController();\n const abort = (from: AbortSignal) => controller.abort(from.reason);\n\n if (timeout.aborted) abort(timeout);\n else timeout.addEventListener(\"abort\", () => abort(timeout), { once: true });\n\n if (external.aborted) abort(external);\n else external.addEventListener(\"abort\", () => abort(external), { once: true });\n\n return controller.signal;\n}\n\n/**\n * Policy-guarded `fetch`: validates the URL ({@link assertUrlAllowed}),\n * then performs the request with the policy's timeout and (optional)\n * caller signal merged. Returns the raw `Response` — read its body via\n * {@link readTextCapped} to enforce `maxBytes`. Throws\n * {@link OutboundPolicyError} on a policy violation or timeout.\n */\nexport async function guardedFetch(\n rawUrl: string,\n policyInput: OutboundPolicy,\n init?: RequestInit,\n): Promise<Response> {\n const policy = resolveOutboundPolicy(policyInput);\n const url = await assertUrlAllowed(rawUrl, policy);\n\n const timeoutController = new AbortController();\n const timer = setTimeout(() => {\n timeoutController.abort(\n new OutboundPolicyError(\n `outbound request timed out after ${policy.timeoutMs}ms`,\n { context: { url: rawUrl, timeoutMs: policy.timeoutMs } },\n ),\n );\n }, policy.timeoutMs);\n\n try {\n return await policy.fetch(url, {\n ...init,\n signal: mergeSignals(timeoutController.signal, policy.signal),\n });\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Read a response body as UTF-8 text with a hard byte cap. A declared\n * `content-length` over the cap fails fast; otherwise the stream is read\n * chunk-by-chunk and aborted the moment the running total exceeds\n * `maxBytes`. Throws {@link OutboundPolicyError} on overflow.\n */\nexport async function readTextCapped(\n response: Response,\n maxBytes: number,\n): Promise<string> {\n const declared = Number(response.headers.get(\"content-length\"));\n if (Number.isFinite(declared) && declared > maxBytes) {\n throw new OutboundPolicyError(\n `outbound response body too large — declared ${declared} bytes exceeds the ${maxBytes}-byte cap`,\n { context: { declared, maxBytes } },\n );\n }\n\n if (!response.body) {\n const text = await response.text();\n if (Buffer.byteLength(text) > maxBytes) {\n throw new OutboundPolicyError(\n `outbound response body exceeded the ${maxBytes}-byte cap`,\n { context: { maxBytes } },\n );\n }\n return text;\n }\n\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!value) continue;\n\n total += value.byteLength;\n if (total > maxBytes) {\n await reader.cancel();\n throw new OutboundPolicyError(\n `outbound response body exceeded the ${maxBytes}-byte cap`,\n { context: { maxBytes } },\n );\n }\n chunks.push(value);\n }\n\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\n/**\n * Convenience: {@link guardedFetch} + {@link readTextCapped}. Returns the\n * response status alongside the (capped) body text so callers can shape\n * their own not-OK error. The body is only read when the response is OK.\n */\nexport async function fetchTextWithPolicy(\n rawUrl: string,\n policyInput: OutboundPolicy,\n init?: RequestInit,\n): Promise<{ ok: boolean; status: number; statusText: string; text: string }> {\n const policy = resolveOutboundPolicy(policyInput);\n const response = await guardedFetch(rawUrl, policy, init);\n\n return {\n ok: response.ok,\n status: response.status,\n statusText: response.statusText,\n text: response.ok ? await readTextCapped(response, policy.maxBytes) : \"\",\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ //#region ../@warlock.js/ai/src/security/outbound-policy.type.d.ts
2
+ /**
3
+ * One shared policy for every server-side outbound request the framework
4
+ * makes on a user's behalf — attachment fetches (S1), URL skill manifests
5
+ * (S3), RAG document loaders (A4), and any future HTTP helper. Centralizing
6
+ * the controls here means a single, audited SSRF / resource-exhaustion
7
+ * guard instead of six ad-hoc `fetch()` call sites.
8
+ *
9
+ * Every field is optional; {@link resolveOutboundPolicy} fills safe
10
+ * defaults. The defaults are deliberately strict (https-only, private-IP
11
+ * deny on, 10s timeout, 5 MiB cap) so a caller that opts into outbound
12
+ * fetch without tuning still gets a hardened request.
13
+ *
14
+ * @example
15
+ * const policy: OutboundPolicy = {
16
+ * allowedSchemes: ["https"],
17
+ * hostAllowlist: ["cdn.example.com"],
18
+ * maxBytes: 1_000_000,
19
+ * timeoutMs: 5_000,
20
+ * };
21
+ */
22
+ type OutboundPolicy = {
23
+ /**
24
+ * URL schemes permitted for the request. Compared case-insensitively
25
+ * against the URL's protocol (without the trailing colon). Default
26
+ * `["https"]` — `http` must be opted in explicitly.
27
+ */
28
+ allowedSchemes?: string[];
29
+ /**
30
+ * Host allowlist. When set, the request host must equal one of these
31
+ * entries or be a subdomain of one (`cdn.example.com` allows
32
+ * `a.cdn.example.com`). When omitted, any host passes the allowlist
33
+ * check — but the private-IP guard below still applies.
34
+ */
35
+ hostAllowlist?: string[];
36
+ /**
37
+ * Resolve the host through DNS and reject when it maps to a private,
38
+ * loopback, link-local, unique-local, or cloud-metadata
39
+ * (`169.254.169.254`) address — the core SSRF guard. Catches a public
40
+ * hostname that resolves inward. Default `true`.
41
+ */
42
+ denyPrivateIPsAfterDNS?: boolean;
43
+ /**
44
+ * Maximum response body size in bytes. A declared `content-length`
45
+ * over this fails fast; otherwise the body is read with a running cap
46
+ * and aborted on overflow. Default `5_242_880` (5 MiB).
47
+ */
48
+ maxBytes?: number; /** Per-request timeout in milliseconds. Default `10_000`. */
49
+ timeoutMs?: number;
50
+ /**
51
+ * Caller `AbortSignal`, merged with the internal timeout — whichever
52
+ * fires first aborts the request.
53
+ */
54
+ signal?: AbortSignal;
55
+ /**
56
+ * Injected `fetch` implementation (for tests, proxies, or a wrapper
57
+ * that already enforces app-level SSRF rules). Defaults to the global
58
+ * `fetch`.
59
+ */
60
+ fetch?: typeof fetch;
61
+ };
62
+ /** {@link OutboundPolicy} with every default resolved — never partial. */
63
+ type ResolvedOutboundPolicy = {
64
+ allowedSchemes: string[];
65
+ hostAllowlist?: string[];
66
+ denyPrivateIPsAfterDNS: boolean;
67
+ maxBytes: number;
68
+ timeoutMs: number;
69
+ signal?: AbortSignal;
70
+ fetch: typeof fetch;
71
+ };
72
+ //#endregion
73
+ export { OutboundPolicy, ResolvedOutboundPolicy };
74
+ //# sourceMappingURL=outbound-policy.type.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbound-policy.type.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai/src/security/outbound-policy.type.ts"],"mappings":";;AAoBA;;;;;;;;;;;;;;AAuCsB;AAItB;;;;KA3CY,cAAA;EA6CV;;;;;EAvCA,cAAA;EA4CA;;;AAAmB;;;EArCnB,aAAA;;;;;;;EAOA,sBAAA;;;;;;EAMA,QAAA;EAEA,SAAA;;;;;EAKA,MAAA,GAAS,WAAA;;;;;;EAMT,KAAA,UAAe,KAAK;AAAA;;KAIV,sBAAA;EACV,cAAA;EACA,aAAA;EACA,sBAAA;EACA,QAAA;EACA,SAAA;EACA,MAAA,GAAS,WAAA;EACT,KAAA,SAAc,KAAK;AAAA"}
@@ -0,0 +1,15 @@
1
+ //#region ../@warlock.js/ai/src/security/private-ip.d.ts
2
+ /**
3
+ * True when `ip` is a private, loopback, link-local, unique-local,
4
+ * carrier-grade-NAT, unspecified, or otherwise non-public address — the
5
+ * set an SSRF guard must refuse. Accepts IPv4 and IPv6 literals (including
6
+ * IPv4-mapped IPv6 like `::ffff:169.254.169.254`). A non-IP string returns
7
+ * `false` (the caller resolves hostnames via DNS first).
8
+ *
9
+ * The cloud-metadata endpoint `169.254.169.254` is covered by the IPv4
10
+ * link-local range `169.254.0.0/16`.
11
+ */
12
+ declare function isPrivateOrReservedIp(ip: string): boolean;
13
+ //#endregion
14
+ export { isPrivateOrReservedIp };
15
+ //# sourceMappingURL=private-ip.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"private-ip.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai/src/security/private-ip.ts"],"mappings":";;AAYA;;;;AAAgD;;;;;iBAAhC,qBAAA,CAAsB,EAAU"}
@@ -0,0 +1,48 @@
1
+ import { isIP } from "node:net";
2
+
3
+ //#region ../@warlock.js/ai/src/security/private-ip.ts
4
+ /**
5
+ * True when `ip` is a private, loopback, link-local, unique-local,
6
+ * carrier-grade-NAT, unspecified, or otherwise non-public address — the
7
+ * set an SSRF guard must refuse. Accepts IPv4 and IPv6 literals (including
8
+ * IPv4-mapped IPv6 like `::ffff:169.254.169.254`). A non-IP string returns
9
+ * `false` (the caller resolves hostnames via DNS first).
10
+ *
11
+ * The cloud-metadata endpoint `169.254.169.254` is covered by the IPv4
12
+ * link-local range `169.254.0.0/16`.
13
+ */
14
+ function isPrivateOrReservedIp(ip) {
15
+ const family = isIP(ip);
16
+ if (family === 4) return isPrivateIpv4(ip);
17
+ if (family === 6) return isPrivateIpv6(ip);
18
+ return false;
19
+ }
20
+ /** Parse a dotted-quad into four octets, or `null` if malformed. */
21
+ function parseIpv4(ip) {
22
+ const parts = ip.split(".");
23
+ if (parts.length !== 4) return null;
24
+ const octets = parts.map((part) => Number(part));
25
+ if (octets.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return null;
26
+ return octets;
27
+ }
28
+ function isPrivateIpv4(ip) {
29
+ const octets = parseIpv4(ip);
30
+ if (!octets) return true;
31
+ const [a, b] = octets;
32
+ return a === 0 || a === 10 || a === 127 || a === 100 && b >= 64 && b <= 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 192 && b === 0 || a === 198 && (b === 18 || b === 19) || a === 198 && b === 51 || a === 203 && b === 0 || a >= 224;
33
+ }
34
+ function isPrivateIpv6(ip) {
35
+ const normalized = ip.toLowerCase().split("%")[0];
36
+ const v4 = normalized.match(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
37
+ if (v4) return isPrivateIpv4(v4[1]);
38
+ if (normalized === "::1" || normalized === "::") return true;
39
+ const firstGroup = normalized.split(":")[0];
40
+ const head = firstGroup === "" ? 0 : Number.parseInt(firstGroup, 16);
41
+ if ((head & 65024) === 64512) return true;
42
+ if ((head & 65472) === 65152) return true;
43
+ return false;
44
+ }
45
+
46
+ //#endregion
47
+ export { isPrivateOrReservedIp };
48
+ //# sourceMappingURL=private-ip.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"private-ip.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai/src/security/private-ip.ts"],"sourcesContent":["import { isIP } from \"node:net\";\n\n/**\n * True when `ip` is a private, loopback, link-local, unique-local,\n * carrier-grade-NAT, unspecified, or otherwise non-public address — the\n * set an SSRF guard must refuse. Accepts IPv4 and IPv6 literals (including\n * IPv4-mapped IPv6 like `::ffff:169.254.169.254`). A non-IP string returns\n * `false` (the caller resolves hostnames via DNS first).\n *\n * The cloud-metadata endpoint `169.254.169.254` is covered by the IPv4\n * link-local range `169.254.0.0/16`.\n */\nexport function isPrivateOrReservedIp(ip: string): boolean {\n const family = isIP(ip);\n if (family === 4) return isPrivateIpv4(ip);\n if (family === 6) return isPrivateIpv6(ip);\n return false;\n}\n\n/** Parse a dotted-quad into four octets, or `null` if malformed. */\nfunction parseIpv4(ip: string): [number, number, number, number] | null {\n const parts = ip.split(\".\");\n if (parts.length !== 4) return null;\n\n const octets = parts.map(part => Number(part));\n if (octets.some(n => !Number.isInteger(n) || n < 0 || n > 255)) return null;\n\n return octets as [number, number, number, number];\n}\n\nfunction isPrivateIpv4(ip: string): boolean {\n const octets = parseIpv4(ip);\n if (!octets) return true; // unparseable → refuse, fail closed\n\n const [a, b] = octets;\n\n return (\n a === 0 || // 0.0.0.0/8 \"this network\"\n a === 10 || // 10.0.0.0/8 private\n a === 127 || // 127.0.0.0/8 loopback\n (a === 100 && b >= 64 && b <= 127) || // 100.64.0.0/10 CGNAT\n (a === 169 && b === 254) || // 169.254.0.0/16 link-local + metadata\n (a === 172 && b >= 16 && b <= 31) || // 172.16.0.0/12 private\n (a === 192 && b === 168) || // 192.168.0.0/16 private\n (a === 192 && b === 0) || // 192.0.0.0/24 + 192.0.2.0/24 (IETF/test)\n (a === 198 && (b === 18 || b === 19)) || // 198.18.0.0/15 benchmarking\n (a === 198 && b === 51) || // 198.51.100.0/24 test-net-2\n (a === 203 && b === 0) || // 203.0.113.0/24 test-net-3\n a >= 224 // 224.0.0.0/4 multicast + 240.0.0.0/4 reserved + 255.255.255.255\n );\n}\n\nfunction isPrivateIpv6(ip: string): boolean {\n const normalized = ip.toLowerCase().split(\"%\")[0]; // drop zone id\n\n // IPv4-mapped / -embedded (::ffff:a.b.c.d, ::a.b.c.d) — defer to the v4\n // check on the trailing dotted-quad so an inward-mapped address is caught.\n const v4 = normalized.match(/(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$/);\n if (v4) {\n return isPrivateIpv4(v4[1]);\n }\n\n if (normalized === \"::1\" || normalized === \"::\") {\n return true; // loopback / unspecified\n }\n\n // Expand only the leading group enough to classify the reserved blocks.\n const firstGroup = normalized.split(\":\")[0];\n const head = firstGroup === \"\" ? 0 : Number.parseInt(firstGroup, 16);\n\n // fc00::/7 unique-local (fc.. / fd..)\n if ((head & 0xfe00) === 0xfc00) return true;\n // fe80::/10 link-local\n if ((head & 0xffc0) === 0xfe80) return true;\n\n return false;\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAgB,sBAAsB,IAAqB;CACzD,MAAM,SAAS,KAAK,EAAE;CACtB,IAAI,WAAW,GAAG,OAAO,cAAc,EAAE;CACzC,IAAI,WAAW,GAAG,OAAO,cAAc,EAAE;CACzC,OAAO;AACT;;AAGA,SAAS,UAAU,IAAqD;CACtE,MAAM,QAAQ,GAAG,MAAM,GAAG;CAC1B,IAAI,MAAM,WAAW,GAAG,OAAO;CAE/B,MAAM,SAAS,MAAM,KAAI,SAAQ,OAAO,IAAI,CAAC;CAC7C,IAAI,OAAO,MAAK,MAAK,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,KAAK,IAAI,GAAG,GAAG,OAAO;CAEvE,OAAO;AACT;AAEA,SAAS,cAAc,IAAqB;CAC1C,MAAM,SAAS,UAAU,EAAE;CAC3B,IAAI,CAAC,QAAQ,OAAO;CAEpB,MAAM,CAAC,GAAG,KAAK;CAEf,OACE,MAAM,KACN,MAAM,MACN,MAAM,OACL,MAAM,OAAO,KAAK,MAAM,KAAK,OAC7B,MAAM,OAAO,MAAM,OACnB,MAAM,OAAO,KAAK,MAAM,KAAK,MAC7B,MAAM,OAAO,MAAM,OACnB,MAAM,OAAO,MAAM,KACnB,MAAM,QAAQ,MAAM,MAAM,MAAM,OAChC,MAAM,OAAO,MAAM,MACnB,MAAM,OAAO,MAAM,KACpB,KAAK;AAET;AAEA,SAAS,cAAc,IAAqB;CAC1C,MAAM,aAAa,GAAG,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;CAI/C,MAAM,KAAK,WAAW,MAAM,uCAAuC;CACnE,IAAI,IACF,OAAO,cAAc,GAAG,EAAE;CAG5B,IAAI,eAAe,SAAS,eAAe,MACzC,OAAO;CAIT,MAAM,aAAa,WAAW,MAAM,GAAG,CAAC,CAAC;CACzC,MAAM,OAAO,eAAe,KAAK,IAAI,OAAO,SAAS,YAAY,EAAE;CAGnE,KAAK,OAAO,WAAY,OAAQ,OAAO;CAEvC,KAAK,OAAO,WAAY,OAAQ,OAAO;CAEvC,OAAO;AACT"}
@@ -0,0 +1,59 @@
1
+ //#region ../@warlock.js/ai/src/security/redact.d.ts
2
+ /**
3
+ * Default set of sensitive key fragments (matched case-insensitively as
4
+ * substrings of an object key). Covers the secrets that leak through
5
+ * recorded requests, error causes, and trace payloads: auth headers, API
6
+ * keys, cookies, tokens, passwords, and private keys.
7
+ */
8
+ declare const DEFAULT_SENSITIVE_KEYS: readonly string[];
9
+ /** HTTP header names always stripped from a serialized error/cause. */
10
+ declare const SENSITIVE_HEADERS: readonly string[];
11
+ type RedactOptions = {
12
+ /** Extra key fragments to redact, merged with {@link DEFAULT_SENSITIVE_KEYS}. */keys?: string[]; /** Replacement for a redacted value. Default `"[redacted]"`. */
13
+ placeholder?: string; /** Maximum recursion depth before bailing out. Default `8`. */
14
+ maxDepth?: number;
15
+ };
16
+ /**
17
+ * Deep-copy `value` with any property whose KEY matches a sensitive
18
+ * fragment replaced by the placeholder. Arrays are walked element-wise;
19
+ * circular references and over-deep trees collapse to the placeholder.
20
+ * Primitives pass through untouched (redaction is key-driven, not
21
+ * value-driven — it never guesses at a bare string being a secret).
22
+ *
23
+ * Shared by VCR cassettes (S2), Panoptic content capture, and the error /
24
+ * cause serializer (S4) so there is ONE redaction policy, not three.
25
+ */
26
+ declare function redact<T>(value: T, options?: RedactOptions): T;
27
+ /**
28
+ * Strip sensitive HTTP headers from a `Headers` instance or a plain
29
+ * header record, returning a redacted plain object. Header names are
30
+ * matched case-insensitively against {@link SENSITIVE_HEADERS}.
31
+ */
32
+ declare function redactHeaders(headers: Headers | Record<string, unknown> | undefined, placeholder?: string): Record<string, unknown>;
33
+ /**
34
+ * Scrub secrets that appear in free-form text — error messages, stack
35
+ * traces, exported log lines. Complements {@link redact} (which is key-
36
+ * driven and can't see a token embedded in a string). Used by the trace /
37
+ * error serializer (S4) before a message or stack is stored or exported.
38
+ */
39
+ declare function scrubSecrets(text: string): string;
40
+ /**
41
+ * Serialized, secret-free view of an error. `stack` is omitted by default
42
+ * (it can embed local paths, endpoints, and tokens); pass
43
+ * `includeStack: true` only for a trusted local sink. The retained
44
+ * `cause` is deep-redacted via {@link redact}, so a raw provider SDK error
45
+ * carrying `Authorization` / `x-api-key` on `cause.headers` is sanitized.
46
+ */
47
+ type RedactedError = {
48
+ name: string;
49
+ message: string;
50
+ code?: string;
51
+ cause?: unknown;
52
+ stack?: string;
53
+ };
54
+ declare function redactError(error: unknown, options?: {
55
+ includeStack?: boolean;
56
+ } & RedactOptions): RedactedError;
57
+ //#endregion
58
+ export { DEFAULT_SENSITIVE_KEYS, RedactOptions, RedactedError, SENSITIVE_HEADERS, redact, redactError, redactHeaders, scrubSecrets };
59
+ //# sourceMappingURL=redact.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai/src/security/redact.ts"],"mappings":";;AAMA;;;;AAgBC;cAhBY,sBAAA;;cAmBA,iBAAA;AAAA,KASD,aAAA;EAFX,iFAIC,IAAA,aAFuB;EAIvB,WAAA,WAJuB;EAMvB,QAAA;AAAA;;;AAAQ;AAqBV;;;;;;;iBAAgB,MAAA,IAAU,KAAA,EAAO,CAAA,EAAG,OAAA,GAAS,aAAA,GAAqB,CAAA;;;;;;iBAsClD,aAAA,CACd,OAAA,EAAS,OAAA,GAAU,MAAA,+BACnB,WAAA,YACC,MAAA;;AAzCgE;AAsCnE;;;;iBAuCgB,YAAA,CAAa,IAAY;;;;;;;;KAe7B,aAAA;EACV,IAAA;EACA,OAAA;EACA,IAAA;EACA,KAAA;EACA,KAAA;AAAA;AAAA,iBAGc,WAAA,CACd,KAAA,WACA,OAAA;EAAW,YAAA;AAAA,IAA2B,aAAA,GACrC,aAAa"}