@dewtech/dare-cli 3.11.0 → 3.12.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 (308) hide show
  1. package/README.md +2 -0
  2. package/dist/__tests__/ensure-skills.test.js +5 -0
  3. package/dist/__tests__/ensure-skills.test.js.map +1 -1
  4. package/dist/__tests__/ide-command-parity.test.js +1 -0
  5. package/dist/__tests__/ide-command-parity.test.js.map +1 -1
  6. package/dist/__tests__/project-generator.test.js +17 -0
  7. package/dist/__tests__/project-generator.test.js.map +1 -1
  8. package/dist/__tests__/reverse-facts.test.js +1 -0
  9. package/dist/__tests__/reverse-facts.test.js.map +1 -1
  10. package/dist/__tests__/terminal-parity-regression.test.d.ts +2 -0
  11. package/dist/__tests__/terminal-parity-regression.test.d.ts.map +1 -0
  12. package/dist/__tests__/terminal-parity-regression.test.js +116 -0
  13. package/dist/__tests__/terminal-parity-regression.test.js.map +1 -0
  14. package/dist/__tests__/terminal-parity.test.d.ts +2 -0
  15. package/dist/__tests__/terminal-parity.test.d.ts.map +1 -0
  16. package/dist/__tests__/terminal-parity.test.js +81 -0
  17. package/dist/__tests__/terminal-parity.test.js.map +1 -0
  18. package/dist/agent/__tests__/antigravity-driver.test.d.ts +2 -0
  19. package/dist/agent/__tests__/antigravity-driver.test.d.ts.map +1 -0
  20. package/dist/agent/__tests__/antigravity-driver.test.js +52 -0
  21. package/dist/agent/__tests__/antigravity-driver.test.js.map +1 -0
  22. package/dist/agent/__tests__/codex-driver.test.d.ts +2 -0
  23. package/dist/agent/__tests__/codex-driver.test.d.ts.map +1 -0
  24. package/dist/agent/__tests__/codex-driver.test.js +68 -0
  25. package/dist/agent/__tests__/codex-driver.test.js.map +1 -0
  26. package/dist/agent/__tests__/cursor-driver.test.d.ts +2 -0
  27. package/dist/agent/__tests__/cursor-driver.test.d.ts.map +1 -0
  28. package/dist/agent/__tests__/cursor-driver.test.js +52 -0
  29. package/dist/agent/__tests__/cursor-driver.test.js.map +1 -0
  30. package/dist/agent/driver.d.ts +1 -1
  31. package/dist/agent/driver.d.ts.map +1 -1
  32. package/dist/agent/drivers/antigravity.d.ts +8 -0
  33. package/dist/agent/drivers/antigravity.d.ts.map +1 -0
  34. package/dist/agent/drivers/antigravity.js +99 -0
  35. package/dist/agent/drivers/antigravity.js.map +1 -0
  36. package/dist/agent/drivers/codex.d.ts +12 -0
  37. package/dist/agent/drivers/codex.d.ts.map +1 -0
  38. package/dist/agent/drivers/codex.js +137 -0
  39. package/dist/agent/drivers/codex.js.map +1 -0
  40. package/dist/agent/drivers/cursor.d.ts +8 -0
  41. package/dist/agent/drivers/cursor.d.ts.map +1 -0
  42. package/dist/agent/drivers/cursor.js +99 -0
  43. package/dist/agent/drivers/cursor.js.map +1 -0
  44. package/dist/ai/__tests__/ai-core.test.d.ts +2 -0
  45. package/dist/ai/__tests__/ai-core.test.d.ts.map +1 -0
  46. package/dist/ai/__tests__/ai-core.test.js +41 -0
  47. package/dist/ai/__tests__/ai-core.test.js.map +1 -0
  48. package/dist/ai/__tests__/parity.test.d.ts +2 -0
  49. package/dist/ai/__tests__/parity.test.d.ts.map +1 -0
  50. package/dist/ai/__tests__/parity.test.js +36 -0
  51. package/dist/ai/__tests__/parity.test.js.map +1 -0
  52. package/dist/ai/__tests__/pipeline.test.d.ts +2 -0
  53. package/dist/ai/__tests__/pipeline.test.d.ts.map +1 -0
  54. package/dist/ai/__tests__/pipeline.test.js +147 -0
  55. package/dist/ai/__tests__/pipeline.test.js.map +1 -0
  56. package/dist/ai/__tests__/refine-bridge.test.d.ts +2 -0
  57. package/dist/ai/__tests__/refine-bridge.test.d.ts.map +1 -0
  58. package/dist/ai/__tests__/refine-bridge.test.js +17 -0
  59. package/dist/ai/__tests__/refine-bridge.test.js.map +1 -0
  60. package/dist/ai/__tests__/resolve.test.d.ts +2 -0
  61. package/dist/ai/__tests__/resolve.test.d.ts.map +1 -0
  62. package/dist/ai/__tests__/resolve.test.js +42 -0
  63. package/dist/ai/__tests__/resolve.test.js.map +1 -0
  64. package/dist/ai/capabilities.d.ts +3 -0
  65. package/dist/ai/capabilities.d.ts.map +1 -0
  66. package/dist/ai/capabilities.js +11 -0
  67. package/dist/ai/capabilities.js.map +1 -0
  68. package/dist/ai/command-options.d.ts +10 -0
  69. package/dist/ai/command-options.d.ts.map +1 -0
  70. package/dist/ai/command-options.js +15 -0
  71. package/dist/ai/command-options.js.map +1 -0
  72. package/dist/ai/config.d.ts +27 -0
  73. package/dist/ai/config.d.ts.map +1 -0
  74. package/dist/ai/config.js +89 -0
  75. package/dist/ai/config.js.map +1 -0
  76. package/dist/ai/parity.d.ts +13 -0
  77. package/dist/ai/parity.d.ts.map +1 -0
  78. package/dist/ai/parity.js +87 -0
  79. package/dist/ai/parity.js.map +1 -0
  80. package/dist/ai/parse-json-output.d.ts +5 -0
  81. package/dist/ai/parse-json-output.d.ts.map +1 -0
  82. package/dist/ai/parse-json-output.js +25 -0
  83. package/dist/ai/parse-json-output.js.map +1 -0
  84. package/dist/ai/pipeline.d.ts +20 -0
  85. package/dist/ai/pipeline.d.ts.map +1 -0
  86. package/dist/ai/pipeline.js +303 -0
  87. package/dist/ai/pipeline.js.map +1 -0
  88. package/dist/ai/prompts.d.ts +6 -0
  89. package/dist/ai/prompts.d.ts.map +1 -0
  90. package/dist/ai/prompts.js +49 -0
  91. package/dist/ai/prompts.js.map +1 -0
  92. package/dist/ai/providers.d.ts +63 -0
  93. package/dist/ai/providers.d.ts.map +1 -0
  94. package/dist/ai/providers.js +297 -0
  95. package/dist/ai/providers.js.map +1 -0
  96. package/dist/ai/refine-bridge.d.ts +5 -0
  97. package/dist/ai/refine-bridge.d.ts.map +1 -0
  98. package/dist/ai/refine-bridge.js +14 -0
  99. package/dist/ai/refine-bridge.js.map +1 -0
  100. package/dist/ai/registry.d.ts +12 -0
  101. package/dist/ai/registry.d.ts.map +1 -0
  102. package/dist/ai/registry.js +43 -0
  103. package/dist/ai/registry.js.map +1 -0
  104. package/dist/ai/resolve.d.ts +28 -0
  105. package/dist/ai/resolve.d.ts.map +1 -0
  106. package/dist/ai/resolve.js +83 -0
  107. package/dist/ai/resolve.js.map +1 -0
  108. package/dist/ai/schemas.d.ts +175 -0
  109. package/dist/ai/schemas.d.ts.map +1 -0
  110. package/dist/ai/schemas.js +199 -0
  111. package/dist/ai/schemas.js.map +1 -0
  112. package/dist/ai/types.d.ts +52 -0
  113. package/dist/ai/types.d.ts.map +1 -0
  114. package/dist/ai/types.js +8 -0
  115. package/dist/ai/types.js.map +1 -0
  116. package/dist/bin/dare.js +2 -0
  117. package/dist/bin/dare.js.map +1 -1
  118. package/dist/commands/__tests__/ai-command.test.d.ts +2 -0
  119. package/dist/commands/__tests__/ai-command.test.d.ts.map +1 -0
  120. package/dist/commands/__tests__/ai-command.test.js +68 -0
  121. package/dist/commands/__tests__/ai-command.test.js.map +1 -0
  122. package/dist/commands/__tests__/execute-agent.test.js +82 -0
  123. package/dist/commands/__tests__/execute-agent.test.js.map +1 -1
  124. package/dist/commands/ai.d.ts +3 -0
  125. package/dist/commands/ai.d.ts.map +1 -0
  126. package/dist/commands/ai.js +141 -0
  127. package/dist/commands/ai.js.map +1 -0
  128. package/dist/commands/blueprint.d.ts.map +1 -1
  129. package/dist/commands/blueprint.js +17 -3
  130. package/dist/commands/blueprint.js.map +1 -1
  131. package/dist/commands/design.d.ts.map +1 -1
  132. package/dist/commands/design.js +21 -2
  133. package/dist/commands/design.js.map +1 -1
  134. package/dist/commands/discover.d.ts.map +1 -1
  135. package/dist/commands/discover.js +9 -1
  136. package/dist/commands/discover.js.map +1 -1
  137. package/dist/commands/dna.d.ts.map +1 -1
  138. package/dist/commands/dna.js +23 -3
  139. package/dist/commands/dna.js.map +1 -1
  140. package/dist/commands/execute.d.ts +11 -0
  141. package/dist/commands/execute.d.ts.map +1 -1
  142. package/dist/commands/execute.js +111 -4
  143. package/dist/commands/execute.js.map +1 -1
  144. package/dist/commands/init.d.ts.map +1 -1
  145. package/dist/commands/init.js +1 -0
  146. package/dist/commands/init.js.map +1 -1
  147. package/dist/commands/migrate.d.ts.map +1 -1
  148. package/dist/commands/migrate.js +14 -2
  149. package/dist/commands/migrate.js.map +1 -1
  150. package/dist/commands/patterns.d.ts.map +1 -1
  151. package/dist/commands/patterns.js +14 -2
  152. package/dist/commands/patterns.js.map +1 -1
  153. package/dist/commands/refine.d.ts.map +1 -1
  154. package/dist/commands/refine.js +23 -2
  155. package/dist/commands/refine.js.map +1 -1
  156. package/dist/commands/reverse.d.ts.map +1 -1
  157. package/dist/commands/reverse.js +28 -3
  158. package/dist/commands/reverse.js.map +1 -1
  159. package/dist/commands/review.d.ts.map +1 -1
  160. package/dist/commands/review.js +25 -3
  161. package/dist/commands/review.js.map +1 -1
  162. package/dist/core/types/project.d.ts +1 -1
  163. package/dist/core/types/project.d.ts.map +1 -1
  164. package/dist/dag-runner/run_dag.d.ts +1 -1
  165. package/dist/dag-runner/run_dag.d.ts.map +1 -1
  166. package/dist/exec/safe-spawn.d.ts.map +1 -1
  167. package/dist/exec/safe-spawn.js +6 -1
  168. package/dist/exec/safe-spawn.js.map +1 -1
  169. package/dist/skills/bundled.d.ts +5 -0
  170. package/dist/skills/bundled.d.ts.map +1 -0
  171. package/dist/skills/bundled.js +34 -0
  172. package/dist/skills/bundled.js.map +1 -0
  173. package/dist/skills/commands/add.d.ts +1 -3
  174. package/dist/skills/commands/add.d.ts.map +1 -1
  175. package/dist/skills/commands/add.js +20 -3
  176. package/dist/skills/commands/add.js.map +1 -1
  177. package/dist/skills/tests/bundled.spec.d.ts +2 -0
  178. package/dist/skills/tests/bundled.spec.d.ts.map +1 -0
  179. package/dist/skills/tests/bundled.spec.js +24 -0
  180. package/dist/skills/tests/bundled.spec.js.map +1 -0
  181. package/dist/types/UpdateManifest.types.d.ts +1 -1
  182. package/dist/types/UpdateManifest.types.d.ts.map +1 -1
  183. package/dist/utils/dag-converter.js +1 -1
  184. package/dist/utils/dag-converter.js.map +1 -1
  185. package/dist/utils/project-detector.d.ts +1 -0
  186. package/dist/utils/project-detector.d.ts.map +1 -1
  187. package/dist/utils/project-detector.js +8 -0
  188. package/dist/utils/project-detector.js.map +1 -1
  189. package/dist/utils/project-generator.d.ts +1 -1
  190. package/dist/utils/project-generator.d.ts.map +1 -1
  191. package/dist/utils/project-generator.js +23 -2
  192. package/dist/utils/project-generator.js.map +1 -1
  193. package/dist/utils/templates.d.ts +2 -0
  194. package/dist/utils/templates.d.ts.map +1 -1
  195. package/dist/utils/templates.js +74 -0
  196. package/dist/utils/templates.js.map +1 -1
  197. package/dist/verification/__tests__/safe-spawn.test.js +12 -0
  198. package/dist/verification/__tests__/safe-spawn.test.js.map +1 -1
  199. package/package.json +2 -1
  200. package/skills/dare-ax/generator.ts +325 -0
  201. package/skills/dare-ax/index.ts +19 -0
  202. package/skills/dare-ax/metrics.ts +352 -0
  203. package/skills/dare-ax/package-lock.json +1855 -0
  204. package/skills/dare-ax/package.json +50 -0
  205. package/skills/dare-ax/secret-detector.ts +123 -0
  206. package/skills/dare-ax/skill.yml +19 -0
  207. package/skills/dare-ax/templates/llms.txt.jinja2 +80 -0
  208. package/skills/dare-ax/tests/generator.spec.ts +193 -0
  209. package/skills/dare-ax/tests/metrics.spec.ts +394 -0
  210. package/skills/dare-ax/tests/validator.spec.ts +298 -0
  211. package/skills/dare-ax/tsconfig.json +18 -0
  212. package/skills/dare-ax/types.ts +79 -0
  213. package/skills/dare-ax/validator.ts +238 -0
  214. package/skills/dare-frontend-design/generator.ts +616 -0
  215. package/skills/dare-frontend-design/index.ts +25 -0
  216. package/skills/dare-frontend-design/linter.ts +227 -0
  217. package/skills/dare-frontend-design/metrics.ts +82 -0
  218. package/skills/dare-frontend-design/package-lock.json +1855 -0
  219. package/skills/dare-frontend-design/package.json +43 -0
  220. package/skills/dare-frontend-design/skill.yml +20 -0
  221. package/skills/dare-frontend-design/tests/frontend_design.spec.ts +435 -0
  222. package/skills/dare-frontend-design/tsconfig.json +18 -0
  223. package/skills/dare-frontend-design/types.ts +62 -0
  224. package/skills/dare-layered-design/generator.ts +740 -0
  225. package/skills/dare-layered-design/index.ts +17 -0
  226. package/skills/dare-layered-design/linter.ts +462 -0
  227. package/skills/dare-layered-design/metrics.ts +409 -0
  228. package/skills/dare-layered-design/package-lock.json +1855 -0
  229. package/skills/dare-layered-design/package.json +50 -0
  230. package/skills/dare-layered-design/skill.yml +35 -0
  231. package/skills/dare-layered-design/tests/generator.spec.ts +156 -0
  232. package/skills/dare-layered-design/tests/linter.spec.ts +255 -0
  233. package/skills/dare-layered-design/tests/metrics.spec.ts +286 -0
  234. package/skills/dare-layered-design/tsconfig.json +18 -0
  235. package/skills/dare-layered-design/types.ts +48 -0
  236. package/skills/dare-llm-integration/cache/llm_cache.ts +122 -0
  237. package/skills/dare-llm-integration/index.ts +49 -0
  238. package/skills/dare-llm-integration/metrics.ts +107 -0
  239. package/skills/dare-llm-integration/package-lock.json +1855 -0
  240. package/skills/dare-llm-integration/package.json +49 -0
  241. package/skills/dare-llm-integration/prompts/prompt_loader.ts +258 -0
  242. package/skills/dare-llm-integration/providers/anthropic_provider.ts +159 -0
  243. package/skills/dare-llm-integration/providers/dummy_provider.ts +113 -0
  244. package/skills/dare-llm-integration/providers/llm_provider.ts +6 -0
  245. package/skills/dare-llm-integration/providers/openai_provider.ts +215 -0
  246. package/skills/dare-llm-integration/rate_limit/token_bucket.ts +86 -0
  247. package/skills/dare-llm-integration/skill.yml +23 -0
  248. package/skills/dare-llm-integration/tests/fixtures/greet_v1.jinja2 +1 -0
  249. package/skills/dare-llm-integration/tests/fixtures/summarize_v1.jinja2 +1 -0
  250. package/skills/dare-llm-integration/tests/fixtures/summarize_v2.jinja2 +3 -0
  251. package/skills/dare-llm-integration/tests/llm_integration.spec.ts +657 -0
  252. package/skills/dare-llm-integration/tsconfig.json +23 -0
  253. package/skills/dare-llm-integration/types.ts +91 -0
  254. package/skills/dare-llm-integration/validators/output_validator.ts +200 -0
  255. package/skills/dare-quality-telemetry/collect.ts +134 -0
  256. package/skills/dare-quality-telemetry/collectors/dare_ax_collector.ts +301 -0
  257. package/skills/dare-quality-telemetry/collectors/dare_layered_design_collector.ts +406 -0
  258. package/skills/dare-quality-telemetry/collectors/index.ts +24 -0
  259. package/skills/dare-quality-telemetry/github_actions_template.ts +25 -0
  260. package/skills/dare-quality-telemetry/index.ts +18 -0
  261. package/skills/dare-quality-telemetry/metrics.ts +137 -0
  262. package/skills/dare-quality-telemetry/package-lock.json +1855 -0
  263. package/skills/dare-quality-telemetry/package.json +48 -0
  264. package/skills/dare-quality-telemetry/regression.ts +60 -0
  265. package/skills/dare-quality-telemetry/reporter.ts +132 -0
  266. package/skills/dare-quality-telemetry/skill.yml +18 -0
  267. package/skills/dare-quality-telemetry/tests/quality_telemetry.spec.ts +885 -0
  268. package/skills/dare-quality-telemetry/tsconfig.json +19 -0
  269. package/skills/dare-quality-telemetry/types.ts +41 -0
  270. package/skills/dare-realtime/event_registry.ts +101 -0
  271. package/skills/dare-realtime/index.ts +30 -0
  272. package/skills/dare-realtime/metrics.ts +84 -0
  273. package/skills/dare-realtime/package-lock.json +1855 -0
  274. package/skills/dare-realtime/package.json +43 -0
  275. package/skills/dare-realtime/reconnect_strategy.ts +85 -0
  276. package/skills/dare-realtime/schema_validator.ts +80 -0
  277. package/skills/dare-realtime/skill.yml +21 -0
  278. package/skills/dare-realtime/subscription_manager.ts +106 -0
  279. package/skills/dare-realtime/tests/realtime.spec.ts +482 -0
  280. package/skills/dare-realtime/tsconfig.json +18 -0
  281. package/skills/dare-realtime/types.ts +51 -0
  282. package/templates/ide/antigravity/.agents/skills/dare-ai/SKILL.md +17 -0
  283. package/templates/ide/antigravity/.agents/skills/dare-blueprint/SKILL.md +2 -0
  284. package/templates/ide/antigravity/.agents/skills/dare-design/SKILL.md +2 -0
  285. package/templates/ide/antigravity/.agents/skills/dare-dna/SKILL.md +3 -0
  286. package/templates/ide/antigravity/.agents/skills/dare-migrate/SKILL.md +3 -0
  287. package/templates/ide/antigravity/.agents/skills/dare-patterns/SKILL.md +3 -0
  288. package/templates/ide/antigravity/.agents/skills/dare-refine/SKILL.md +3 -0
  289. package/templates/ide/antigravity/.agents/skills/dare-reverse/SKILL.md +3 -0
  290. package/templates/ide/antigravity/.agents/skills/dare-review/SKILL.md +3 -0
  291. package/templates/ide/claude/.claude/commands/dare-ai.md +17 -0
  292. package/templates/ide/claude/.claude/commands/dare-blueprint.md +2 -0
  293. package/templates/ide/claude/.claude/commands/dare-design.md +2 -0
  294. package/templates/ide/claude/.claude/commands/dare-dna.md +2 -0
  295. package/templates/ide/claude/.claude/commands/dare-migrate.md +2 -0
  296. package/templates/ide/claude/.claude/commands/dare-patterns.md +3 -0
  297. package/templates/ide/claude/.claude/commands/dare-refine.md +3 -0
  298. package/templates/ide/claude/.claude/commands/dare-reverse.md +2 -0
  299. package/templates/ide/claude/.claude/commands/dare-review.md +3 -0
  300. package/templates/ide/cursor/.cursor/commands/dare-ai.md +17 -0
  301. package/templates/ide/cursor/.cursor/commands/dare-blueprint.md +3 -0
  302. package/templates/ide/cursor/.cursor/commands/dare-design.md +3 -0
  303. package/templates/ide/cursor/.cursor/commands/dare-dna.md +2 -0
  304. package/templates/ide/cursor/.cursor/commands/dare-migrate.md +2 -0
  305. package/templates/ide/cursor/.cursor/commands/dare-patterns.md +3 -0
  306. package/templates/ide/cursor/.cursor/commands/dare-refine.md +3 -0
  307. package/templates/ide/cursor/.cursor/commands/dare-reverse.md +2 -0
  308. package/templates/ide/cursor/.cursor/commands/dare-review.md +3 -0
@@ -0,0 +1,215 @@
1
+ /**
2
+ * dare-llm-integration — OpenAIProvider
3
+ * Real implementation using fetch (no external SDK).
4
+ * License: MIT
5
+ */
6
+
7
+ import type {
8
+ LLMProvider,
9
+ CompletionRequest,
10
+ CompletionResponse,
11
+ EmbedRequest,
12
+ EmbeddingResponse,
13
+ } from '../types.js';
14
+ import { LLMCache } from '../cache/llm_cache.js';
15
+ import { TokenBucket } from '../rate_limit/token_bucket.js';
16
+
17
+ export interface OpenAIProviderConfig {
18
+ apiKey: string;
19
+ cache?: LLMCache;
20
+ rateLimiter?: TokenBucket;
21
+ defaultCacheTtlMs?: number;
22
+ defaultTimeoutMs?: number;
23
+ onTokenUsage?: (model: string, input: number, output: number) => void;
24
+ }
25
+
26
+ export class OpenAIProvider implements LLMProvider {
27
+ private readonly apiKey: string;
28
+ private readonly cache: LLMCache | null;
29
+ private readonly rateLimiter: TokenBucket | null;
30
+ private readonly defaultCacheTtlMs: number;
31
+ private readonly defaultTimeoutMs: number;
32
+ private readonly onTokenUsage: ((model: string, input: number, output: number) => void) | null;
33
+
34
+ constructor(config: OpenAIProviderConfig) {
35
+ this.apiKey = config.apiKey;
36
+ this.cache = config.cache ?? null;
37
+ this.rateLimiter = config.rateLimiter ?? null;
38
+ this.defaultCacheTtlMs = config.defaultCacheTtlMs ?? 24 * 60 * 60 * 1000; // 24h
39
+ this.defaultTimeoutMs = config.defaultTimeoutMs ?? 30_000;
40
+ this.onTokenUsage = config.onTokenUsage ?? null;
41
+ }
42
+
43
+ async complete(request: CompletionRequest): Promise<CompletionResponse> {
44
+ const cacheKey = this.buildCacheKey('complete', request.model, request.prompt);
45
+
46
+ // Check cache
47
+ if (this.cache) {
48
+ const cached = this.cache.get(cacheKey);
49
+ if (cached) {
50
+ return cached.value as CompletionResponse;
51
+ }
52
+ }
53
+
54
+ // Rate limit
55
+ if (this.rateLimiter) {
56
+ await this.rateLimiter.acquire();
57
+ }
58
+
59
+ const start = Date.now();
60
+ const response = await this.callCompletionAPI(request);
61
+ const latencyMs = Date.now() - start;
62
+
63
+ const result: CompletionResponse = {
64
+ ...response,
65
+ cached: false,
66
+ latencyMs,
67
+ };
68
+
69
+ // Log token usage
70
+ if (this.onTokenUsage) {
71
+ this.onTokenUsage(request.model, result.tokensUsed.input, result.tokensUsed.output);
72
+ }
73
+
74
+ // Store in cache
75
+ if (this.cache) {
76
+ this.cache.set(cacheKey, result, this.defaultCacheTtlMs);
77
+ }
78
+
79
+ return result;
80
+ }
81
+
82
+ async embed(request: EmbedRequest): Promise<EmbeddingResponse> {
83
+ const inputStr = Array.isArray(request.input) ? request.input.join('|') : request.input;
84
+ const cacheKey = this.buildCacheKey('embed', request.model, inputStr);
85
+
86
+ if (this.cache) {
87
+ const cached = this.cache.get(cacheKey);
88
+ if (cached) {
89
+ return cached.value as EmbeddingResponse;
90
+ }
91
+ }
92
+
93
+ if (this.rateLimiter) {
94
+ await this.rateLimiter.acquire();
95
+ }
96
+
97
+ const result = await this.callEmbedAPI(request);
98
+
99
+ if (this.cache) {
100
+ this.cache.set(cacheKey, result, this.defaultCacheTtlMs);
101
+ }
102
+
103
+ return result;
104
+ }
105
+
106
+ private buildCacheKey(op: string, model: string, content: string): string {
107
+ // Deterministic hash-like key using a simple digest
108
+ const combined = `${op}:${model}:${content}`;
109
+ let hash = 0;
110
+ for (let i = 0; i < combined.length; i++) {
111
+ const char = combined.charCodeAt(i);
112
+ hash = ((hash << 5) - hash) + char;
113
+ hash |= 0;
114
+ }
115
+ return `llm:${op}:${model}:${Math.abs(hash).toString(16)}`;
116
+ }
117
+
118
+ private async callCompletionAPI(request: CompletionRequest): Promise<CompletionResponse> {
119
+ const timeoutMs = request.timeoutMs ?? this.defaultTimeoutMs;
120
+ const controller = new AbortController();
121
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
122
+
123
+ const messages: Array<{ role: string; content: string }> = [];
124
+ if (request.systemPrompt) {
125
+ messages.push({ role: 'system', content: request.systemPrompt });
126
+ }
127
+ messages.push({ role: 'user', content: request.prompt });
128
+
129
+ let data: unknown;
130
+ try {
131
+ const response = await fetch('https://api.openai.com/v1/chat/completions', {
132
+ method: 'POST',
133
+ headers: {
134
+ 'Content-Type': 'application/json',
135
+ Authorization: `Bearer ${this.apiKey}`,
136
+ },
137
+ body: JSON.stringify({
138
+ model: request.model,
139
+ messages,
140
+ temperature: request.temperature ?? 0.7,
141
+ max_tokens: request.maxTokens,
142
+ }),
143
+ signal: controller.signal,
144
+ });
145
+
146
+ if (!response.ok) {
147
+ throw new Error(`OpenAI API error: ${response.status} ${response.statusText}`);
148
+ }
149
+
150
+ data = await response.json();
151
+ } finally {
152
+ clearTimeout(timer);
153
+ }
154
+
155
+ const d = data as {
156
+ choices: Array<{ message: { content: string } }>;
157
+ usage: { prompt_tokens: number; completion_tokens: number; total_tokens: number };
158
+ model: string;
159
+ };
160
+
161
+ return {
162
+ text: d.choices[0].message.content,
163
+ tokensUsed: {
164
+ input: d.usage.prompt_tokens,
165
+ output: d.usage.completion_tokens,
166
+ total: d.usage.total_tokens,
167
+ },
168
+ cached: false,
169
+ model: d.model,
170
+ };
171
+ }
172
+
173
+ private async callEmbedAPI(request: EmbedRequest): Promise<EmbeddingResponse> {
174
+ const timeoutMs = request.timeoutMs ?? this.defaultTimeoutMs;
175
+ const controller = new AbortController();
176
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
177
+
178
+ let data: unknown;
179
+ try {
180
+ const response = await fetch('https://api.openai.com/v1/embeddings', {
181
+ method: 'POST',
182
+ headers: {
183
+ 'Content-Type': 'application/json',
184
+ Authorization: `Bearer ${this.apiKey}`,
185
+ },
186
+ body: JSON.stringify({
187
+ model: request.model,
188
+ input: request.input,
189
+ }),
190
+ signal: controller.signal,
191
+ });
192
+
193
+ if (!response.ok) {
194
+ throw new Error(`OpenAI API error: ${response.status} ${response.statusText}`);
195
+ }
196
+
197
+ data = await response.json();
198
+ } finally {
199
+ clearTimeout(timer);
200
+ }
201
+
202
+ const d = data as {
203
+ data: Array<{ embedding: number[] }>;
204
+ usage: { total_tokens: number };
205
+ model: string;
206
+ };
207
+
208
+ return {
209
+ embeddings: d.data.map((item) => item.embedding),
210
+ tokensUsed: d.usage.total_tokens,
211
+ model: d.model,
212
+ cached: false,
213
+ };
214
+ }
215
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * dare-llm-integration — TokenBucket rate limiter
3
+ * Implements a sliding token bucket for controlling request rate.
4
+ * License: MIT
5
+ */
6
+
7
+ export interface TokenBucketConfig {
8
+ /** Requests per second */
9
+ rps: number;
10
+ /** Maximum burst capacity. Defaults to rps. */
11
+ maxBurst?: number;
12
+ }
13
+
14
+ export class TokenBucket {
15
+ private readonly rps: number;
16
+ private readonly maxBurst: number;
17
+ /** Interval in milliseconds between tokens refilling */
18
+ private readonly refillIntervalMs: number;
19
+ private tokens: number;
20
+ private lastRefillTime: number;
21
+
22
+ constructor(config: TokenBucketConfig) {
23
+ if (config.rps <= 0) {
24
+ throw new Error('TokenBucket: rps must be > 0');
25
+ }
26
+ this.rps = config.rps;
27
+ this.maxBurst = config.maxBurst ?? config.rps;
28
+ this.refillIntervalMs = 1000 / config.rps;
29
+ this.tokens = this.maxBurst;
30
+ this.lastRefillTime = Date.now();
31
+ }
32
+
33
+ /**
34
+ * Blocking acquire: waits until a token is available, then consumes it.
35
+ */
36
+ async acquire(): Promise<void> {
37
+ while (!this.tryAcquire()) {
38
+ // Calculate wait time until next token
39
+ const now = Date.now();
40
+ const elapsed = now - this.lastRefillTime;
41
+ const waitMs = Math.max(1, this.refillIntervalMs - elapsed);
42
+ await delay(waitMs);
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Non-blocking attempt: returns true if a token was consumed, false otherwise.
48
+ */
49
+ tryAcquire(): boolean {
50
+ this.refill();
51
+ if (this.tokens >= 1) {
52
+ this.tokens -= 1;
53
+ return true;
54
+ }
55
+ return false;
56
+ }
57
+
58
+ /**
59
+ * Current available tokens (may be fractional after partial refill).
60
+ */
61
+ get availableTokens(): number {
62
+ this.refill();
63
+ return this.tokens;
64
+ }
65
+
66
+ /**
67
+ * Configured requests per second.
68
+ */
69
+ get requestsPerSecond(): number {
70
+ return this.rps;
71
+ }
72
+
73
+ private refill(): void {
74
+ const now = Date.now();
75
+ const elapsed = now - this.lastRefillTime;
76
+ if (elapsed > 0) {
77
+ const newTokens = (elapsed / 1000) * this.rps;
78
+ this.tokens = Math.min(this.tokens + newTokens, this.maxBurst);
79
+ this.lastRefillTime = now;
80
+ }
81
+ }
82
+ }
83
+
84
+ function delay(ms: number): Promise<void> {
85
+ return new Promise((resolve) => setTimeout(resolve, ms));
86
+ }
@@ -0,0 +1,23 @@
1
+ name: dare-llm-integration
2
+ version: 1.0.0
3
+ license: MIT
4
+ description: >
5
+ Skill transversal DARE para integração com LLMs (Large Language Models).
6
+ Fornece LLMProvider abstraction, caching em memória com TTL, rate limiting
7
+ via token bucket, prompt templates versionados e validação de output via JSON Schema.
8
+ author: Dewtech Technologies
9
+ metrics:
10
+ - id: M-01
11
+ description: 100% de chamadas LLM via LLMProvider injetado
12
+ - id: M-02
13
+ description: 100% de responses LLM cacheadas (cache configurado)
14
+ - id: M-03
15
+ description: 100% de requests LLM com rate limit configurado
16
+ - id: M-04
17
+ description: 100% de respostas LLM validadas contra schema antes usar
18
+ antipatterns:
19
+ - AP-01: LLM SDK direto em Handler
20
+ - AP-02: Sem cache
21
+ - AP-03: Prompt em código
22
+ - AP-04: User input direto em prompt
23
+ - AP-05: Trusting LLM output sem validação
@@ -0,0 +1 @@
1
+ Hello {{ name }}, welcome to {{ service }}!
@@ -0,0 +1 @@
1
+ Summarize the following text in 2-3 sentences: {{ text }}
@@ -0,0 +1,3 @@
1
+ Write a concise summary (max {{ max_words }} words):
2
+
3
+ {{ text }}