@hypercli/gen 0.1.1

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 (306) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +24 -0
  3. package/dist/actions/communication.d.ts +201 -0
  4. package/dist/actions/communication.d.ts.map +1 -0
  5. package/dist/actions/communication.js +515 -0
  6. package/dist/actions/communication.js.map +1 -0
  7. package/dist/actions/decorator.d.ts +22 -0
  8. package/dist/actions/decorator.d.ts.map +1 -0
  9. package/dist/actions/decorator.js +110 -0
  10. package/dist/actions/decorator.js.map +1 -0
  11. package/dist/actions/executor.d.ts +85 -0
  12. package/dist/actions/executor.d.ts.map +1 -0
  13. package/dist/actions/executor.js +289 -0
  14. package/dist/actions/executor.js.map +1 -0
  15. package/dist/actions/index.d.ts +14 -0
  16. package/dist/actions/index.d.ts.map +1 -0
  17. package/dist/actions/index.js +15 -0
  18. package/dist/actions/index.js.map +1 -0
  19. package/dist/actions/parameter-resolver.d.ts +54 -0
  20. package/dist/actions/parameter-resolver.d.ts.map +1 -0
  21. package/dist/actions/parameter-resolver.js +300 -0
  22. package/dist/actions/parameter-resolver.js.map +1 -0
  23. package/dist/actions/registry.d.ts +78 -0
  24. package/dist/actions/registry.d.ts.map +1 -0
  25. package/dist/actions/registry.js +221 -0
  26. package/dist/actions/registry.js.map +1 -0
  27. package/dist/actions/types.d.ts +109 -0
  28. package/dist/actions/types.d.ts.map +1 -0
  29. package/dist/actions/types.js +31 -0
  30. package/dist/actions/types.js.map +1 -0
  31. package/dist/actions/utils.d.ts +42 -0
  32. package/dist/actions/utils.d.ts.map +1 -0
  33. package/dist/actions/utils.js +144 -0
  34. package/dist/actions/utils.js.map +1 -0
  35. package/dist/ai/ai-collector.d.ts +52 -0
  36. package/dist/ai/ai-collector.d.ts.map +1 -0
  37. package/dist/ai/ai-collector.js +64 -0
  38. package/dist/ai/ai-collector.js.map +1 -0
  39. package/dist/ai/ai-config.d.ts +230 -0
  40. package/dist/ai/ai-config.d.ts.map +1 -0
  41. package/dist/ai/ai-config.js +8 -0
  42. package/dist/ai/ai-config.js.map +1 -0
  43. package/dist/ai/ai-service.d.ts +66 -0
  44. package/dist/ai/ai-service.d.ts.map +1 -0
  45. package/dist/ai/ai-service.js +198 -0
  46. package/dist/ai/ai-service.js.map +1 -0
  47. package/dist/ai/ai-variable-resolver.d.ts +59 -0
  48. package/dist/ai/ai-variable-resolver.d.ts.map +1 -0
  49. package/dist/ai/ai-variable-resolver.js +219 -0
  50. package/dist/ai/ai-variable-resolver.js.map +1 -0
  51. package/dist/ai/context-collector.d.ts +30 -0
  52. package/dist/ai/context-collector.d.ts.map +1 -0
  53. package/dist/ai/context-collector.js +158 -0
  54. package/dist/ai/context-collector.js.map +1 -0
  55. package/dist/ai/cost-tracker.d.ts +41 -0
  56. package/dist/ai/cost-tracker.d.ts.map +1 -0
  57. package/dist/ai/cost-tracker.js +131 -0
  58. package/dist/ai/cost-tracker.js.map +1 -0
  59. package/dist/ai/env.d.ts +36 -0
  60. package/dist/ai/env.d.ts.map +1 -0
  61. package/dist/ai/env.js +100 -0
  62. package/dist/ai/env.js.map +1 -0
  63. package/dist/ai/index.d.ts +17 -0
  64. package/dist/ai/index.d.ts.map +1 -0
  65. package/dist/ai/index.js +25 -0
  66. package/dist/ai/index.js.map +1 -0
  67. package/dist/ai/model-router.d.ts +32 -0
  68. package/dist/ai/model-router.d.ts.map +1 -0
  69. package/dist/ai/model-router.js +113 -0
  70. package/dist/ai/model-router.js.map +1 -0
  71. package/dist/ai/output-validator.d.ts +24 -0
  72. package/dist/ai/output-validator.d.ts.map +1 -0
  73. package/dist/ai/output-validator.js +279 -0
  74. package/dist/ai/output-validator.js.map +1 -0
  75. package/dist/ai/prompt-assembler.d.ts +30 -0
  76. package/dist/ai/prompt-assembler.d.ts.map +1 -0
  77. package/dist/ai/prompt-assembler.js +93 -0
  78. package/dist/ai/prompt-assembler.js.map +1 -0
  79. package/dist/ai/prompt-pipeline.d.ts +63 -0
  80. package/dist/ai/prompt-pipeline.d.ts.map +1 -0
  81. package/dist/ai/prompt-pipeline.js +119 -0
  82. package/dist/ai/prompt-pipeline.js.map +1 -0
  83. package/dist/ai/prompt-template.jig +88 -0
  84. package/dist/ai/transports/api-transport.d.ts +12 -0
  85. package/dist/ai/transports/api-transport.d.ts.map +1 -0
  86. package/dist/ai/transports/api-transport.js +86 -0
  87. package/dist/ai/transports/api-transport.js.map +1 -0
  88. package/dist/ai/transports/command-transport.d.ts +20 -0
  89. package/dist/ai/transports/command-transport.d.ts.map +1 -0
  90. package/dist/ai/transports/command-transport.js +203 -0
  91. package/dist/ai/transports/command-transport.js.map +1 -0
  92. package/dist/ai/transports/index.d.ts +11 -0
  93. package/dist/ai/transports/index.d.ts.map +1 -0
  94. package/dist/ai/transports/index.js +10 -0
  95. package/dist/ai/transports/index.js.map +1 -0
  96. package/dist/ai/transports/resolve-transport.d.ts +15 -0
  97. package/dist/ai/transports/resolve-transport.d.ts.map +1 -0
  98. package/dist/ai/transports/resolve-transport.js +96 -0
  99. package/dist/ai/transports/resolve-transport.js.map +1 -0
  100. package/dist/ai/transports/stdout-transport.d.ts +14 -0
  101. package/dist/ai/transports/stdout-transport.d.ts.map +1 -0
  102. package/dist/ai/transports/stdout-transport.js +27 -0
  103. package/dist/ai/transports/stdout-transport.js.map +1 -0
  104. package/dist/ai/transports/types.d.ts +77 -0
  105. package/dist/ai/transports/types.d.ts.map +1 -0
  106. package/dist/ai/transports/types.js +8 -0
  107. package/dist/ai/transports/types.js.map +1 -0
  108. package/dist/commands/cookbook/info.d.ts +22 -0
  109. package/dist/commands/cookbook/info.d.ts.map +1 -0
  110. package/dist/commands/cookbook/info.js +217 -0
  111. package/dist/commands/cookbook/info.js.map +1 -0
  112. package/dist/commands/cookbook/list.d.ts +20 -0
  113. package/dist/commands/cookbook/list.d.ts.map +1 -0
  114. package/dist/commands/cookbook/list.js +133 -0
  115. package/dist/commands/cookbook/list.js.map +1 -0
  116. package/dist/commands/gen.d.ts +65 -0
  117. package/dist/commands/gen.d.ts.map +1 -0
  118. package/dist/commands/gen.js +478 -0
  119. package/dist/commands/gen.js.map +1 -0
  120. package/dist/commands/recipe/info.d.ts +18 -0
  121. package/dist/commands/recipe/info.d.ts.map +1 -0
  122. package/dist/commands/recipe/info.js +89 -0
  123. package/dist/commands/recipe/info.js.map +1 -0
  124. package/dist/commands/recipe/list.d.ts +29 -0
  125. package/dist/commands/recipe/list.d.ts.map +1 -0
  126. package/dist/commands/recipe/list.js +215 -0
  127. package/dist/commands/recipe/list.js.map +1 -0
  128. package/dist/commands/recipe/run.d.ts +44 -0
  129. package/dist/commands/recipe/run.d.ts.map +1 -0
  130. package/dist/commands/recipe/run.js +239 -0
  131. package/dist/commands/recipe/run.js.map +1 -0
  132. package/dist/commands/recipe/validate.d.ts +19 -0
  133. package/dist/commands/recipe/validate.d.ts.map +1 -0
  134. package/dist/commands/recipe/validate.js +66 -0
  135. package/dist/commands/recipe/validate.js.map +1 -0
  136. package/dist/discovery/generator-discovery.d.ts +130 -0
  137. package/dist/discovery/generator-discovery.d.ts.map +1 -0
  138. package/dist/discovery/generator-discovery.js +674 -0
  139. package/dist/discovery/generator-discovery.js.map +1 -0
  140. package/dist/discovery/index.d.ts +8 -0
  141. package/dist/discovery/index.d.ts.map +1 -0
  142. package/dist/discovery/index.js +7 -0
  143. package/dist/discovery/index.js.map +1 -0
  144. package/dist/hooks/command-not-found.d.ts +18 -0
  145. package/dist/hooks/command-not-found.d.ts.map +1 -0
  146. package/dist/hooks/command-not-found.js +182 -0
  147. package/dist/hooks/command-not-found.js.map +1 -0
  148. package/dist/hooks/suggest.d.ts +13 -0
  149. package/dist/hooks/suggest.d.ts.map +1 -0
  150. package/dist/hooks/suggest.js +28 -0
  151. package/dist/hooks/suggest.js.map +1 -0
  152. package/dist/index.d.ts +2 -0
  153. package/dist/index.d.ts.map +1 -0
  154. package/dist/index.js +3 -0
  155. package/dist/index.js.map +1 -0
  156. package/dist/lib/base-command.d.ts +26 -0
  157. package/dist/lib/base-command.d.ts.map +1 -0
  158. package/dist/lib/base-command.js +24 -0
  159. package/dist/lib/base-command.js.map +1 -0
  160. package/dist/lib/flags.d.ts +33 -0
  161. package/dist/lib/flags.d.ts.map +1 -0
  162. package/dist/lib/flags.js +64 -0
  163. package/dist/lib/flags.js.map +1 -0
  164. package/dist/ops/add.d.ts +4 -0
  165. package/dist/ops/add.d.ts.map +1 -0
  166. package/dist/ops/add.js +85 -0
  167. package/dist/ops/add.js.map +1 -0
  168. package/dist/ops/inject.d.ts +4 -0
  169. package/dist/ops/inject.d.ts.map +1 -0
  170. package/dist/ops/inject.js +28 -0
  171. package/dist/ops/inject.js.map +1 -0
  172. package/dist/ops/injector.d.ts +4 -0
  173. package/dist/ops/injector.d.ts.map +1 -0
  174. package/dist/ops/injector.js +68 -0
  175. package/dist/ops/injector.js.map +1 -0
  176. package/dist/ops/result.d.ts +3 -0
  177. package/dist/ops/result.d.ts.map +1 -0
  178. package/dist/ops/result.js +8 -0
  179. package/dist/ops/result.js.map +1 -0
  180. package/dist/prompts/interactive-prompts.d.ts +152 -0
  181. package/dist/prompts/interactive-prompts.d.ts.map +1 -0
  182. package/dist/prompts/interactive-prompts.js +574 -0
  183. package/dist/prompts/interactive-prompts.js.map +1 -0
  184. package/dist/recipe-engine/group-executor.d.ts +97 -0
  185. package/dist/recipe-engine/group-executor.d.ts.map +1 -0
  186. package/dist/recipe-engine/group-executor.js +293 -0
  187. package/dist/recipe-engine/group-executor.js.map +1 -0
  188. package/dist/recipe-engine/index.d.ts +112 -0
  189. package/dist/recipe-engine/index.d.ts.map +1 -0
  190. package/dist/recipe-engine/index.js +223 -0
  191. package/dist/recipe-engine/index.js.map +1 -0
  192. package/dist/recipe-engine/output-evaluator.d.ts +28 -0
  193. package/dist/recipe-engine/output-evaluator.d.ts.map +1 -0
  194. package/dist/recipe-engine/output-evaluator.js +78 -0
  195. package/dist/recipe-engine/output-evaluator.js.map +1 -0
  196. package/dist/recipe-engine/recipe-engine.d.ts +227 -0
  197. package/dist/recipe-engine/recipe-engine.d.ts.map +1 -0
  198. package/dist/recipe-engine/recipe-engine.js +1036 -0
  199. package/dist/recipe-engine/recipe-engine.js.map +1 -0
  200. package/dist/recipe-engine/step-executor.d.ts +172 -0
  201. package/dist/recipe-engine/step-executor.d.ts.map +1 -0
  202. package/dist/recipe-engine/step-executor.js +802 -0
  203. package/dist/recipe-engine/step-executor.js.map +1 -0
  204. package/dist/recipe-engine/tools/action-tool.d.ts +103 -0
  205. package/dist/recipe-engine/tools/action-tool.d.ts.map +1 -0
  206. package/dist/recipe-engine/tools/action-tool.js +473 -0
  207. package/dist/recipe-engine/tools/action-tool.js.map +1 -0
  208. package/dist/recipe-engine/tools/ai-tool.d.ts +26 -0
  209. package/dist/recipe-engine/tools/ai-tool.d.ts.map +1 -0
  210. package/dist/recipe-engine/tools/ai-tool.js +233 -0
  211. package/dist/recipe-engine/tools/ai-tool.js.map +1 -0
  212. package/dist/recipe-engine/tools/base.d.ts +214 -0
  213. package/dist/recipe-engine/tools/base.d.ts.map +1 -0
  214. package/dist/recipe-engine/tools/base.js +397 -0
  215. package/dist/recipe-engine/tools/base.js.map +1 -0
  216. package/dist/recipe-engine/tools/codemod-tool.d.ts +130 -0
  217. package/dist/recipe-engine/tools/codemod-tool.d.ts.map +1 -0
  218. package/dist/recipe-engine/tools/codemod-tool.js +786 -0
  219. package/dist/recipe-engine/tools/codemod-tool.js.map +1 -0
  220. package/dist/recipe-engine/tools/ensure-dirs-tool.d.ts +21 -0
  221. package/dist/recipe-engine/tools/ensure-dirs-tool.d.ts.map +1 -0
  222. package/dist/recipe-engine/tools/ensure-dirs-tool.js +130 -0
  223. package/dist/recipe-engine/tools/ensure-dirs-tool.js.map +1 -0
  224. package/dist/recipe-engine/tools/index.d.ts +126 -0
  225. package/dist/recipe-engine/tools/index.d.ts.map +1 -0
  226. package/dist/recipe-engine/tools/index.js +290 -0
  227. package/dist/recipe-engine/tools/index.js.map +1 -0
  228. package/dist/recipe-engine/tools/install-tool.d.ts +20 -0
  229. package/dist/recipe-engine/tools/install-tool.d.ts.map +1 -0
  230. package/dist/recipe-engine/tools/install-tool.js +194 -0
  231. package/dist/recipe-engine/tools/install-tool.js.map +1 -0
  232. package/dist/recipe-engine/tools/parallel-tool.d.ts +21 -0
  233. package/dist/recipe-engine/tools/parallel-tool.d.ts.map +1 -0
  234. package/dist/recipe-engine/tools/parallel-tool.js +134 -0
  235. package/dist/recipe-engine/tools/parallel-tool.js.map +1 -0
  236. package/dist/recipe-engine/tools/patch-tool.d.ts +21 -0
  237. package/dist/recipe-engine/tools/patch-tool.d.ts.map +1 -0
  238. package/dist/recipe-engine/tools/patch-tool.js +248 -0
  239. package/dist/recipe-engine/tools/patch-tool.js.map +1 -0
  240. package/dist/recipe-engine/tools/prompt-tool.d.ts +25 -0
  241. package/dist/recipe-engine/tools/prompt-tool.d.ts.map +1 -0
  242. package/dist/recipe-engine/tools/prompt-tool.js +162 -0
  243. package/dist/recipe-engine/tools/prompt-tool.js.map +1 -0
  244. package/dist/recipe-engine/tools/query-tool.d.ts +21 -0
  245. package/dist/recipe-engine/tools/query-tool.d.ts.map +1 -0
  246. package/dist/recipe-engine/tools/query-tool.js +249 -0
  247. package/dist/recipe-engine/tools/query-tool.js.map +1 -0
  248. package/dist/recipe-engine/tools/recipe-tool.d.ts +103 -0
  249. package/dist/recipe-engine/tools/recipe-tool.d.ts.map +1 -0
  250. package/dist/recipe-engine/tools/recipe-tool.js +617 -0
  251. package/dist/recipe-engine/tools/recipe-tool.js.map +1 -0
  252. package/dist/recipe-engine/tools/registry.d.ts +151 -0
  253. package/dist/recipe-engine/tools/registry.d.ts.map +1 -0
  254. package/dist/recipe-engine/tools/registry.js +244 -0
  255. package/dist/recipe-engine/tools/registry.js.map +1 -0
  256. package/dist/recipe-engine/tools/sequence-tool.d.ts +22 -0
  257. package/dist/recipe-engine/tools/sequence-tool.d.ts.map +1 -0
  258. package/dist/recipe-engine/tools/sequence-tool.js +122 -0
  259. package/dist/recipe-engine/tools/sequence-tool.js.map +1 -0
  260. package/dist/recipe-engine/tools/shell-tool.d.ts +25 -0
  261. package/dist/recipe-engine/tools/shell-tool.d.ts.map +1 -0
  262. package/dist/recipe-engine/tools/shell-tool.js +149 -0
  263. package/dist/recipe-engine/tools/shell-tool.js.map +1 -0
  264. package/dist/recipe-engine/tools/template-tool.d.ts +88 -0
  265. package/dist/recipe-engine/tools/template-tool.d.ts.map +1 -0
  266. package/dist/recipe-engine/tools/template-tool.js +613 -0
  267. package/dist/recipe-engine/tools/template-tool.js.map +1 -0
  268. package/dist/recipe-engine/types.d.ts +963 -0
  269. package/dist/recipe-engine/types.d.ts.map +1 -0
  270. package/dist/recipe-engine/types.js +94 -0
  271. package/dist/recipe-engine/types.js.map +1 -0
  272. package/dist/template-engines/ai-tags.d.ts +26 -0
  273. package/dist/template-engines/ai-tags.d.ts.map +1 -0
  274. package/dist/template-engines/ai-tags.js +233 -0
  275. package/dist/template-engines/ai-tags.js.map +1 -0
  276. package/dist/template-engines/index.d.ts +8 -0
  277. package/dist/template-engines/index.d.ts.map +1 -0
  278. package/dist/template-engines/index.js +8 -0
  279. package/dist/template-engines/index.js.map +1 -0
  280. package/dist/template-engines/jig-engine.d.ts +47 -0
  281. package/dist/template-engines/jig-engine.d.ts.map +1 -0
  282. package/dist/template-engines/jig-engine.js +173 -0
  283. package/dist/template-engines/jig-engine.js.map +1 -0
  284. package/dist/utils/coerce-value.d.ts +7 -0
  285. package/dist/utils/coerce-value.d.ts.map +1 -0
  286. package/dist/utils/coerce-value.js +18 -0
  287. package/dist/utils/coerce-value.js.map +1 -0
  288. package/dist/utils/diff.d.ts +8 -0
  289. package/dist/utils/diff.d.ts.map +1 -0
  290. package/dist/utils/diff.js +10 -0
  291. package/dist/utils/diff.js.map +1 -0
  292. package/dist/utils/global-packages.d.ts +11 -0
  293. package/dist/utils/global-packages.d.ts.map +1 -0
  294. package/dist/utils/global-packages.js +88 -0
  295. package/dist/utils/global-packages.js.map +1 -0
  296. package/dist/utils/pager.d.ts +6 -0
  297. package/dist/utils/pager.d.ts.map +1 -0
  298. package/dist/utils/pager.js +41 -0
  299. package/dist/utils/pager.js.map +1 -0
  300. package/help/cookbook/info.md +35 -0
  301. package/help/cookbook/list.md +37 -0
  302. package/help/gen.md +26 -0
  303. package/help/recipe/run.md +52 -0
  304. package/help/recipe/validate.md +51 -0
  305. package/oclif.manifest.json +580 -0
  306. package/package.json +120 -0
@@ -0,0 +1,219 @@
1
+ /**
2
+ * AI Variable Resolver
3
+ *
4
+ * Resolves unresolved recipe variables by batching them into a single AI prompt.
5
+ * Uses the existing AiService/transport infrastructure for the actual LLM call.
6
+ */
7
+ import createDebug from "debug";
8
+ import { AiService } from "./ai-service.js";
9
+ const debug = createDebug("hypergen:ai:variable-resolver");
10
+ /**
11
+ * Batched AI variable resolution.
12
+ *
13
+ * Collects all unresolved variables, builds one prompt, calls the LLM,
14
+ * parses the JSON response, and validates each value.
15
+ */
16
+ export class AiVariableResolver {
17
+ aiConfig;
18
+ constructor(aiConfig) {
19
+ this.aiConfig = aiConfig;
20
+ }
21
+ /**
22
+ * Resolve a batch of variables via a single AI call.
23
+ *
24
+ * @returns Record mapping variable names to AI-resolved values.
25
+ * Variables the AI could not resolve are omitted.
26
+ */
27
+ async resolveBatch(unresolvedVars, resolvedVars, recipeMeta, projectContext) {
28
+ if (unresolvedVars.length === 0)
29
+ return {};
30
+ debug("Resolving %d variables via AI for recipe: %s", unresolvedVars.length, recipeMeta.name);
31
+ const prompt = this.buildPrompt(unresolvedVars, resolvedVars, recipeMeta, projectContext);
32
+ const systemPrompt = this.buildSystemPrompt(unresolvedVars);
33
+ const aiService = AiService.getInstance(this.aiConfig);
34
+ let result;
35
+ try {
36
+ result = await aiService.generate({
37
+ prompt,
38
+ system: systemPrompt,
39
+ temperature: this.aiConfig.temperature ?? 0.2,
40
+ maxTokens: this.aiConfig.maxTokens,
41
+ model: this.aiConfig.model,
42
+ provider: this.aiConfig.provider,
43
+ projectRoot: process.cwd(),
44
+ stepName: "ai-variable-resolver",
45
+ });
46
+ }
47
+ catch (error) {
48
+ debug("AI call failed: %s", error instanceof Error ? error.message : String(error));
49
+ // Return empty — caller decides what to do with still-unresolved vars
50
+ return {};
51
+ }
52
+ return this.parseResponse(result.output, unresolvedVars);
53
+ }
54
+ /**
55
+ * Build the user prompt that describes what variables need values.
56
+ */
57
+ buildPrompt(unresolvedVars, resolvedVars, recipeMeta, projectContext) {
58
+ const lines = [];
59
+ lines.push("# Variable Resolution Request");
60
+ lines.push("");
61
+ lines.push(`**Recipe:** ${recipeMeta.name}`);
62
+ if (recipeMeta.description) {
63
+ lines.push(`**Description:** ${recipeMeta.description}`);
64
+ }
65
+ lines.push("");
66
+ // Already-resolved variables as context
67
+ const resolvedKeys = Object.keys(resolvedVars);
68
+ if (resolvedKeys.length > 0) {
69
+ lines.push("## Already Known Variables");
70
+ lines.push("");
71
+ for (const [name, value] of Object.entries(resolvedVars)) {
72
+ lines.push(`- **${name}**: \`${JSON.stringify(value)}\``);
73
+ }
74
+ lines.push("");
75
+ }
76
+ // Project context
77
+ if (projectContext) {
78
+ lines.push("## Project Context");
79
+ lines.push("");
80
+ lines.push(projectContext);
81
+ lines.push("");
82
+ }
83
+ // Variables that need resolution
84
+ lines.push("## Variables to Resolve");
85
+ lines.push("");
86
+ lines.push("For each variable below, determine the best value based on the recipe context, already-known variables, and any constraints.");
87
+ lines.push("");
88
+ for (const { name, config, defaultValue } of unresolvedVars) {
89
+ lines.push(`### \`${name}\``);
90
+ lines.push(`- **Type:** ${config.type}`);
91
+ if (config.required)
92
+ lines.push("- **Required:** yes");
93
+ if (config.description)
94
+ lines.push(`- **Description:** ${config.description}`);
95
+ if (config.suggestion !== undefined)
96
+ lines.push(`- **Suggestion:** \`${JSON.stringify(config.suggestion)}\``);
97
+ if (defaultValue !== undefined)
98
+ lines.push(`- **Default (skipped):** \`${JSON.stringify(defaultValue)}\``);
99
+ if (config.values)
100
+ lines.push(`- **Allowed values:** ${config.values.map((v) => `\`${v}\``).join(", ")}`);
101
+ if (config.pattern)
102
+ lines.push(`- **Pattern:** \`${config.pattern}\``);
103
+ if (config.min !== undefined)
104
+ lines.push(`- **Min:** ${config.min}`);
105
+ if (config.max !== undefined)
106
+ lines.push(`- **Max:** ${config.max}`);
107
+ lines.push("");
108
+ }
109
+ return lines.join("\n");
110
+ }
111
+ /**
112
+ * Build the system prompt instructing the AI to return JSON.
113
+ */
114
+ buildSystemPrompt(unresolvedVars) {
115
+ const keys = unresolvedVars.map((v) => `"${v.name}"`).join(", ");
116
+ return [
117
+ "You are a code generation configuration assistant.",
118
+ "You MUST respond with ONLY a valid JSON object — no markdown fences, no explanation, no text outside the JSON.",
119
+ `The JSON object must have exactly these keys: ${keys}.`,
120
+ "Each value must match the type and constraints described in the prompt.",
121
+ "For string values, provide the string directly. For numbers, provide a number. For booleans, provide true/false.",
122
+ "For enum values, pick from the allowed values list. For arrays, provide a JSON array. For objects, provide a JSON object.",
123
+ "Use the suggestion or skipped default as a strong hint when available.",
124
+ ].join("\n");
125
+ }
126
+ /**
127
+ * Parse the AI's JSON response and coerce values to expected types.
128
+ */
129
+ parseResponse(raw, unresolvedVars) {
130
+ let text = raw.trim();
131
+ // Strip markdown code fences
132
+ const fenceMatch = text.match(/^```(?:json)?\s*\n?([\s\S]*?)\n?\s*```$/m);
133
+ if (fenceMatch) {
134
+ text = fenceMatch[1].trim();
135
+ }
136
+ let parsed;
137
+ try {
138
+ parsed = JSON.parse(text);
139
+ }
140
+ catch (err) {
141
+ debug("Failed to parse AI response as JSON: %s", text.slice(0, 200));
142
+ return {};
143
+ }
144
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
145
+ debug("AI response is not a JSON object");
146
+ return {};
147
+ }
148
+ const result = {};
149
+ for (const { name, config } of unresolvedVars) {
150
+ if (!(name in parsed)) {
151
+ debug("AI response missing key: %s", name);
152
+ continue;
153
+ }
154
+ const value = parsed[name];
155
+ const coerced = this.coerceValue(value, config);
156
+ if (coerced !== undefined) {
157
+ result[name] = coerced;
158
+ }
159
+ else {
160
+ debug("AI value for %s failed coercion (type: %s, got: %s)", name, config.type, typeof value);
161
+ }
162
+ }
163
+ debug("Parsed %d/%d variables from AI response", Object.keys(result).length, unresolvedVars.length);
164
+ return result;
165
+ }
166
+ /**
167
+ * Coerce a raw AI value to the expected variable type.
168
+ * Returns undefined if coercion fails.
169
+ */
170
+ coerceValue(value, config) {
171
+ if (value === null || value === undefined)
172
+ return undefined;
173
+ switch (config.type) {
174
+ case "string":
175
+ case "file":
176
+ case "directory":
177
+ return typeof value === "string" ? value : String(value);
178
+ case "number": {
179
+ const num = typeof value === "number" ? value : Number(value);
180
+ return Number.isNaN(num) ? undefined : num;
181
+ }
182
+ case "boolean":
183
+ if (typeof value === "boolean")
184
+ return value;
185
+ if (value === "true")
186
+ return true;
187
+ if (value === "false")
188
+ return false;
189
+ return undefined;
190
+ case "enum":
191
+ if (config.values?.includes(String(value))) {
192
+ return String(value);
193
+ }
194
+ // For multi-select enums
195
+ if (Array.isArray(value) && config.values) {
196
+ const filtered = value.map(String).filter((v) => config.values?.includes(v));
197
+ return filtered.length > 0 ? filtered : undefined;
198
+ }
199
+ return undefined;
200
+ case "array":
201
+ if (Array.isArray(value))
202
+ return value;
203
+ if (typeof value === "string") {
204
+ return value
205
+ .split(",")
206
+ .map((s) => s.trim())
207
+ .filter(Boolean);
208
+ }
209
+ return undefined;
210
+ case "object":
211
+ if (typeof value === "object" && !Array.isArray(value))
212
+ return value;
213
+ return undefined;
214
+ default:
215
+ return value;
216
+ }
217
+ }
218
+ }
219
+ //# sourceMappingURL=ai-variable-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-variable-resolver.js","sourceRoot":"","sources":["../../src/ai/ai-variable-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Context Collector
3
+ *
4
+ * Reads files, config, and previous step results to build the context
5
+ * included in AI prompts. Enforces token budgets.
6
+ */
7
+ import type { StepResult } from "#recipe-engine/types";
8
+ import type { AIContextConfig } from "./ai-config.js";
9
+ /**
10
+ * A collected context bundle ready for prompt assembly
11
+ */
12
+ export interface ContextBundle {
13
+ /** Collected file contents keyed by path */
14
+ files: Map<string, string>;
15
+ /** Config file contents keyed by name */
16
+ configs: Map<string, string>;
17
+ /** Previous step outputs keyed by step name */
18
+ stepOutputs: Map<string, string>;
19
+ /** Total estimated token count */
20
+ estimatedTokens: number;
21
+ /** Whether truncation was applied */
22
+ truncated: boolean;
23
+ }
24
+ export declare class ContextCollector {
25
+ /**
26
+ * Collect context files, configs, and step results based on configuration
27
+ */
28
+ collect(config: AIContextConfig | undefined, projectRoot: string, stepResults: Map<string, StepResult>): Promise<ContextBundle>;
29
+ }
30
+ //# sourceMappingURL=context-collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-collector.d.ts","sourceRoot":"","sources":["../../src/ai/context-collector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,4CAA4C;IAC5C,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,yCAAyC;IACzC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,+CAA+C;IAC/C,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,kCAAkC;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,qCAAqC;IACrC,SAAS,EAAE,OAAO,CAAC;CACnB;AA0BD,qBAAa,gBAAgB;IAC5B;;OAEG;IACG,OAAO,CACZ,MAAM,EAAE,eAAe,GAAG,SAAS,EACnC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,GAClC,OAAO,CAAC,aAAa,CAAC;CAqIzB"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Context Collector
3
+ *
4
+ * Reads files, config, and previous step results to build the context
5
+ * included in AI prompts. Enforces token budgets.
6
+ */
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import createDebug from "debug";
10
+ import { glob } from "glob";
11
+ const debug = createDebug("hypergen:ai:context-collector");
12
+ /**
13
+ * Rough token estimation: ~4 characters per token (conservative).
14
+ * This is intentionally simple — real token counting requires the model's tokenizer.
15
+ */
16
+ function estimateTokens(text) {
17
+ return Math.ceil(text.length / 4);
18
+ }
19
+ /**
20
+ * Known project config file names and their typical locations
21
+ */
22
+ const CONFIG_FILE_MAP = {
23
+ tsconfig: ["tsconfig.json", "tsconfig.build.json"],
24
+ "package.json": ["package.json"],
25
+ eslint: [
26
+ ".eslintrc.json",
27
+ ".eslintrc.js",
28
+ ".eslintrc.cjs",
29
+ "eslint.config.js",
30
+ "eslint.config.mjs",
31
+ ],
32
+ ".editorconfig": [".editorconfig"],
33
+ };
34
+ export class ContextCollector {
35
+ /**
36
+ * Collect context files, configs, and step results based on configuration
37
+ */
38
+ async collect(config, projectRoot, stepResults) {
39
+ const bundle = {
40
+ files: new Map(),
41
+ configs: new Map(),
42
+ stepOutputs: new Map(),
43
+ estimatedTokens: 0,
44
+ truncated: false,
45
+ };
46
+ if (!config)
47
+ return bundle;
48
+ const maxTokens = config.maxContextTokens ?? Number.POSITIVE_INFINITY;
49
+ let currentTokens = 0;
50
+ // 1. Project config files (highest priority — smallest, most relevant)
51
+ if (config.projectConfig) {
52
+ const configNames = config.projectConfig === true ? ["tsconfig", "package.json"] : config.projectConfig;
53
+ for (const name of configNames) {
54
+ const candidates = CONFIG_FILE_MAP[name] || [name];
55
+ for (const candidate of candidates) {
56
+ const filePath = path.resolve(projectRoot, candidate);
57
+ if (fs.existsSync(filePath)) {
58
+ const content = fs.readFileSync(filePath, "utf-8");
59
+ const tokens = estimateTokens(content);
60
+ if (currentTokens + tokens > maxTokens) {
61
+ bundle.truncated = true;
62
+ debug("Skipping config %s: would exceed token budget", name);
63
+ break;
64
+ }
65
+ bundle.configs.set(name, content);
66
+ currentTokens += tokens;
67
+ debug("Collected config %s (%d tokens)", name, tokens);
68
+ break; // use first found
69
+ }
70
+ }
71
+ }
72
+ }
73
+ // 2. Previous step results
74
+ if (config.fromSteps) {
75
+ for (const stepName of config.fromSteps) {
76
+ const result = stepResults.get(stepName);
77
+ if (result?.toolResult) {
78
+ // Serialize step result to include in context
79
+ const content = JSON.stringify(result.toolResult, null, 2);
80
+ const tokens = estimateTokens(content);
81
+ if (currentTokens + tokens > maxTokens) {
82
+ bundle.truncated = true;
83
+ debug("Skipping step output %s: would exceed token budget", stepName);
84
+ continue;
85
+ }
86
+ bundle.stepOutputs.set(stepName, content);
87
+ currentTokens += tokens;
88
+ debug("Collected step output %s (%d tokens)", stepName, tokens);
89
+ }
90
+ }
91
+ }
92
+ // 3. Explicit file paths
93
+ if (config.include) {
94
+ for (const filePath of config.include) {
95
+ const resolved = path.resolve(projectRoot, filePath);
96
+ if (fs.existsSync(resolved)) {
97
+ const content = fs.readFileSync(resolved, "utf-8");
98
+ const tokens = estimateTokens(content);
99
+ if (currentTokens + tokens > maxTokens) {
100
+ if (config.overflow === "truncate") {
101
+ const remainingChars = (maxTokens - currentTokens) * 4;
102
+ if (remainingChars > 100) {
103
+ bundle.files.set(filePath, `${content.slice(0, remainingChars)}\n... [truncated]`);
104
+ currentTokens = maxTokens;
105
+ bundle.truncated = true;
106
+ debug("Truncated file %s to fit budget", filePath);
107
+ }
108
+ }
109
+ else if (config.overflow === "error") {
110
+ throw new Error(`Context exceeds token budget (${currentTokens + tokens} > ${maxTokens}). File: ${filePath}`);
111
+ }
112
+ else {
113
+ bundle.truncated = true;
114
+ debug("Skipping file %s: would exceed token budget", filePath);
115
+ }
116
+ continue;
117
+ }
118
+ bundle.files.set(filePath, content);
119
+ currentTokens += tokens;
120
+ debug("Collected file %s (%d tokens)", filePath, tokens);
121
+ }
122
+ else {
123
+ debug("Context file not found: %s", resolved);
124
+ }
125
+ }
126
+ }
127
+ // 4. Glob patterns
128
+ if (config.files) {
129
+ for (const pattern of config.files) {
130
+ const matches = await glob(pattern, {
131
+ cwd: projectRoot,
132
+ absolute: false,
133
+ });
134
+ for (const match of matches) {
135
+ if (bundle.files.has(match))
136
+ continue; // avoid duplicates
137
+ const resolved = path.resolve(projectRoot, match);
138
+ if (!fs.existsSync(resolved) || fs.statSync(resolved).isDirectory())
139
+ continue;
140
+ const content = fs.readFileSync(resolved, "utf-8");
141
+ const tokens = estimateTokens(content);
142
+ if (currentTokens + tokens > maxTokens) {
143
+ bundle.truncated = true;
144
+ debug("Skipping glob match %s: would exceed token budget", match);
145
+ continue;
146
+ }
147
+ bundle.files.set(match, content);
148
+ currentTokens += tokens;
149
+ debug("Collected glob match %s (%d tokens)", match, tokens);
150
+ }
151
+ }
152
+ }
153
+ bundle.estimatedTokens = currentTokens;
154
+ debug("Context collection complete: %d files, %d configs, %d step outputs, ~%d tokens, truncated=%s", bundle.files.size, bundle.configs.size, bundle.stepOutputs.size, currentTokens, bundle.truncated);
155
+ return bundle;
156
+ }
157
+ }
158
+ //# sourceMappingURL=context-collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-collector.js","sourceRoot":"","sources":["../../src/ai/context-collector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Cost Tracker
3
+ *
4
+ * Tracks token usage and estimated costs across AI steps within a recipe execution.
5
+ * Enforces budget limits and provides end-of-run summaries.
6
+ */
7
+ import type { AIBudgetConfig, AICostSummary, AIModelPricing } from "./ai-config.js";
8
+ export declare class CostTracker {
9
+ private readonly budget?;
10
+ private readonly costTable;
11
+ private steps;
12
+ private totalInputTokens;
13
+ private totalOutputTokens;
14
+ private totalCostUsd;
15
+ private budgetWarningTriggered;
16
+ private budgetLimitHit;
17
+ constructor(budget?: AIBudgetConfig | undefined, costTable?: Record<string, AIModelPricing>);
18
+ /**
19
+ * Calculate cost for a given token usage
20
+ */
21
+ calculateCost(model: string, inputTokens: number, outputTokens: number): number;
22
+ /**
23
+ * Record token usage from an AI step
24
+ */
25
+ record(stepName: string, model: string, inputTokens: number, outputTokens: number, retryAttempts?: number): void;
26
+ /**
27
+ * Check if budget allows another AI call.
28
+ * Returns null if OK, or throws if hard limit exceeded.
29
+ * Logs warning if warn threshold crossed.
30
+ */
31
+ checkBudget(): void;
32
+ /**
33
+ * Get cost summary for the entire execution
34
+ */
35
+ getSummary(): AICostSummary;
36
+ /**
37
+ * Format a human-readable cost report
38
+ */
39
+ formatReport(): string;
40
+ }
41
+ //# sourceMappingURL=cost-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-tracker.d.ts","sourceRoot":"","sources":["../../src/ai/cost-tracker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAuBpF,qBAAa,WAAW;IAStB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAT3B,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,sBAAsB,CAAS;IACvC,OAAO,CAAC,cAAc,CAAS;gBAGb,MAAM,CAAC,EAAE,cAAc,YAAA,EACvB,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAM;IAOhE;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAY/E;;OAEG;IACH,MAAM,CACL,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,aAAa,SAAI,GACf,IAAI;IAyBP;;;;OAIG;IACH,WAAW,IAAI,IAAI;IA4CnB;;OAEG;IACH,UAAU,IAAI,aAAa;IAa3B;;OAEG;IACH,YAAY,IAAI,MAAM;CA4BtB"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Cost Tracker
3
+ *
4
+ * Tracks token usage and estimated costs across AI steps within a recipe execution.
5
+ * Enforces budget limits and provides end-of-run summaries.
6
+ */
7
+ import { ErrorCode, ErrorHandler } from "@hypercli/core";
8
+ import createDebug from "debug";
9
+ const debug = createDebug("hypergen:ai:cost-tracker");
10
+ /**
11
+ * Default cost table for common models (USD per 1M tokens)
12
+ */
13
+ const DEFAULT_COST_TABLE = {
14
+ "claude-sonnet-4-5": { inputPer1M: 3, outputPer1M: 15 },
15
+ "claude-haiku-3-5": { inputPer1M: 0.8, outputPer1M: 4 },
16
+ "gpt-4o": { inputPer1M: 2.5, outputPer1M: 10 },
17
+ "gpt-4o-mini": { inputPer1M: 0.15, outputPer1M: 0.6 },
18
+ };
19
+ export class CostTracker {
20
+ budget;
21
+ costTable;
22
+ steps = [];
23
+ totalInputTokens = 0;
24
+ totalOutputTokens = 0;
25
+ totalCostUsd = 0;
26
+ budgetWarningTriggered = false;
27
+ budgetLimitHit = false;
28
+ constructor(budget, costTable = {}) {
29
+ this.budget = budget;
30
+ this.costTable = costTable;
31
+ // Merge user cost table with defaults
32
+ this.costTable = { ...DEFAULT_COST_TABLE, ...costTable };
33
+ debug("CostTracker initialized with budget: %o", budget);
34
+ }
35
+ /**
36
+ * Calculate cost for a given token usage
37
+ */
38
+ calculateCost(model, inputTokens, outputTokens) {
39
+ const pricing = this.costTable[model];
40
+ if (!pricing) {
41
+ debug("No pricing found for model %s, cost will be 0", model);
42
+ return 0;
43
+ }
44
+ return ((inputTokens * pricing.inputPer1M) / 1_000_000 +
45
+ (outputTokens * pricing.outputPer1M) / 1_000_000);
46
+ }
47
+ /**
48
+ * Record token usage from an AI step
49
+ */
50
+ record(stepName, model, inputTokens, outputTokens, retryAttempts = 0) {
51
+ const costUsd = this.calculateCost(model, inputTokens, outputTokens);
52
+ this.steps.push({
53
+ stepName,
54
+ model,
55
+ inputTokens,
56
+ outputTokens,
57
+ costUsd,
58
+ retryAttempts,
59
+ });
60
+ this.totalInputTokens += inputTokens;
61
+ this.totalOutputTokens += outputTokens;
62
+ this.totalCostUsd += costUsd;
63
+ debug('Recorded step "%s": %d in + %d out = $%.4f (total: $%.4f)', stepName, inputTokens, outputTokens, costUsd, this.totalCostUsd);
64
+ }
65
+ /**
66
+ * Check if budget allows another AI call.
67
+ * Returns null if OK, or throws if hard limit exceeded.
68
+ * Logs warning if warn threshold crossed.
69
+ */
70
+ checkBudget() {
71
+ if (!this.budget)
72
+ return;
73
+ // Check token limit
74
+ if (this.budget.maxTotalTokens &&
75
+ this.totalInputTokens + this.totalOutputTokens >= this.budget.maxTotalTokens) {
76
+ this.budgetLimitHit = true;
77
+ throw ErrorHandler.createError(ErrorCode.AI_BUDGET_EXCEEDED, `Token budget exceeded: ${this.totalInputTokens + this.totalOutputTokens} tokens used, limit is ${this.budget.maxTotalTokens}`, {});
78
+ }
79
+ // Check cost limit
80
+ if (this.budget.maxTotalCostUsd && this.totalCostUsd >= this.budget.maxTotalCostUsd) {
81
+ this.budgetLimitHit = true;
82
+ throw ErrorHandler.createError(ErrorCode.AI_BUDGET_EXCEEDED, `Cost budget exceeded: $${this.totalCostUsd.toFixed(4)} spent, limit is $${this.budget.maxTotalCostUsd.toFixed(2)}`, {});
83
+ }
84
+ // Check warning threshold
85
+ if (this.budget.warnAtCostUsd &&
86
+ this.totalCostUsd >= this.budget.warnAtCostUsd &&
87
+ !this.budgetWarningTriggered) {
88
+ this.budgetWarningTriggered = true;
89
+ debug("Budget warning: $%.4f spent (threshold: $%.2f)", this.totalCostUsd, this.budget.warnAtCostUsd);
90
+ console.warn(`[hypergen:ai] Budget warning: $${this.totalCostUsd.toFixed(4)} spent of $${this.budget.maxTotalCostUsd?.toFixed(2) ?? "?"} limit`);
91
+ }
92
+ }
93
+ /**
94
+ * Get cost summary for the entire execution
95
+ */
96
+ getSummary() {
97
+ return {
98
+ totalInputTokens: this.totalInputTokens,
99
+ totalOutputTokens: this.totalOutputTokens,
100
+ totalTokens: this.totalInputTokens + this.totalOutputTokens,
101
+ totalCostUsd: this.totalCostUsd,
102
+ stepCount: this.steps.length,
103
+ steps: [...this.steps],
104
+ budgetWarningTriggered: this.budgetWarningTriggered,
105
+ budgetLimitHit: this.budgetLimitHit,
106
+ };
107
+ }
108
+ /**
109
+ * Format a human-readable cost report
110
+ */
111
+ formatReport() {
112
+ const lines = ["AI Cost Summary:", ""];
113
+ if (this.steps.length === 0) {
114
+ lines.push(" No AI steps executed.");
115
+ return lines.join("\n");
116
+ }
117
+ for (const step of this.steps) {
118
+ lines.push(` ${step.stepName} (${step.model}): ${step.inputTokens} in + ${step.outputTokens} out = $${step.costUsd.toFixed(4)}${step.retryAttempts > 0 ? ` (${step.retryAttempts} retries)` : ""}`);
119
+ }
120
+ lines.push("");
121
+ lines.push(` Total: ${this.totalInputTokens} in + ${this.totalOutputTokens} out = $${this.totalCostUsd.toFixed(4)}`);
122
+ if (this.budgetWarningTriggered) {
123
+ lines.push(" Warning: Budget warning threshold was triggered");
124
+ }
125
+ if (this.budgetLimitHit) {
126
+ lines.push(" Error: Budget limit was exceeded");
127
+ }
128
+ return lines.join("\n");
129
+ }
130
+ }
131
+ //# sourceMappingURL=cost-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-tracker.js","sourceRoot":"","sources":["../../src/ai/cost-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * AI Environment Variable Resolution
3
+ *
4
+ * Centralizes API key resolution from environment variables.
5
+ * Loads .env files via dotenvx on first use.
6
+ */
7
+ /**
8
+ * Well-known environment variable names for each AI provider's API key.
9
+ * These match the defaults used by the Vercel AI SDK provider packages.
10
+ */
11
+ export declare const PROVIDER_API_KEY_ENV_VARS: Record<string, string>;
12
+ /** All well-known env var names (for auto-detection scans) */
13
+ export declare const ALL_KNOWN_API_KEY_VARS: string[];
14
+ /**
15
+ * Ensure .env files are loaded into process.env.
16
+ * Called lazily on first API key resolution.
17
+ */
18
+ export declare function loadDotenv(): void;
19
+ /**
20
+ * Resolve an API key from the environment.
21
+ *
22
+ * @param envVarName Explicit env var name from config (e.g. 'ANTHROPIC_API_KEY')
23
+ * @param provider Provider name, used to infer default env var when envVarName is omitted
24
+ * @returns The API key string, or undefined if not found
25
+ */
26
+ export declare function resolveApiKey(envVarName: string | undefined, provider: string): string | undefined;
27
+ /**
28
+ * Get the env var name that would be used for a provider (for error messages).
29
+ */
30
+ export declare function getExpectedEnvVar(envVarName: string | undefined, provider: string): string;
31
+ /**
32
+ * Check if any API key is available for the given config, without loading it.
33
+ * Used by auto-detection in resolveTransport.
34
+ */
35
+ export declare function hasApiKeyAvailable(envVarName: string | undefined, provider: string | undefined): boolean;
36
+ //# sourceMappingURL=env.d.ts.map