agents-reverse-engineer 0.3.6 → 0.4.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 (156) hide show
  1. package/dist/ai/backends/claude.d.ts +92 -0
  2. package/dist/ai/backends/claude.d.ts.map +1 -0
  3. package/dist/ai/backends/claude.js +213 -0
  4. package/dist/ai/backends/claude.js.map +1 -0
  5. package/dist/ai/backends/gemini.d.ts +53 -0
  6. package/dist/ai/backends/gemini.d.ts.map +1 -0
  7. package/dist/ai/backends/gemini.js +66 -0
  8. package/dist/ai/backends/gemini.js.map +1 -0
  9. package/dist/ai/backends/opencode.d.ts +53 -0
  10. package/dist/ai/backends/opencode.d.ts.map +1 -0
  11. package/dist/ai/backends/opencode.js +66 -0
  12. package/dist/ai/backends/opencode.js.map +1 -0
  13. package/dist/ai/index.d.ts +39 -0
  14. package/dist/ai/index.d.ts.map +1 -0
  15. package/dist/ai/index.js +54 -0
  16. package/dist/ai/index.js.map +1 -0
  17. package/dist/ai/pricing.d.ts +84 -0
  18. package/dist/ai/pricing.d.ts.map +1 -0
  19. package/dist/ai/pricing.js +149 -0
  20. package/dist/ai/pricing.js.map +1 -0
  21. package/dist/ai/pricing.test.d.ts +2 -0
  22. package/dist/ai/pricing.test.d.ts.map +1 -0
  23. package/dist/ai/pricing.test.js +164 -0
  24. package/dist/ai/pricing.test.js.map +1 -0
  25. package/dist/ai/registry.d.ts +128 -0
  26. package/dist/ai/registry.d.ts.map +1 -0
  27. package/dist/ai/registry.js +192 -0
  28. package/dist/ai/registry.js.map +1 -0
  29. package/dist/ai/retry.d.ts +77 -0
  30. package/dist/ai/retry.d.ts.map +1 -0
  31. package/dist/ai/retry.js +100 -0
  32. package/dist/ai/retry.js.map +1 -0
  33. package/dist/ai/service.d.ts +124 -0
  34. package/dist/ai/service.d.ts.map +1 -0
  35. package/dist/ai/service.js +239 -0
  36. package/dist/ai/service.js.map +1 -0
  37. package/dist/ai/subprocess.d.ts +45 -0
  38. package/dist/ai/subprocess.d.ts.map +1 -0
  39. package/dist/ai/subprocess.js +90 -0
  40. package/dist/ai/subprocess.js.map +1 -0
  41. package/dist/ai/telemetry/cleanup.d.ts +30 -0
  42. package/dist/ai/telemetry/cleanup.d.ts.map +1 -0
  43. package/dist/ai/telemetry/cleanup.js +56 -0
  44. package/dist/ai/telemetry/cleanup.js.map +1 -0
  45. package/dist/ai/telemetry/logger.d.ts +76 -0
  46. package/dist/ai/telemetry/logger.d.ts.map +1 -0
  47. package/dist/ai/telemetry/logger.js +130 -0
  48. package/dist/ai/telemetry/logger.js.map +1 -0
  49. package/dist/ai/telemetry/run-log.d.ts +29 -0
  50. package/dist/ai/telemetry/run-log.d.ts.map +1 -0
  51. package/dist/ai/telemetry/run-log.js +43 -0
  52. package/dist/ai/telemetry/run-log.js.map +1 -0
  53. package/dist/ai/types.d.ts +235 -0
  54. package/dist/ai/types.d.ts.map +1 -0
  55. package/dist/ai/types.js +34 -0
  56. package/dist/ai/types.js.map +1 -0
  57. package/dist/cli/discover.d.ts.map +1 -1
  58. package/dist/cli/discover.js +0 -2
  59. package/dist/cli/discover.js.map +1 -1
  60. package/dist/cli/generate.d.ts +22 -14
  61. package/dist/cli/generate.d.ts.map +1 -1
  62. package/dist/cli/generate.js +91 -50
  63. package/dist/cli/generate.js.map +1 -1
  64. package/dist/cli/index.js +12 -3
  65. package/dist/cli/index.js.map +1 -1
  66. package/dist/cli/update.d.ts +13 -4
  67. package/dist/cli/update.d.ts.map +1 -1
  68. package/dist/cli/update.js +93 -131
  69. package/dist/cli/update.js.map +1 -1
  70. package/dist/config/defaults.d.ts +2 -2
  71. package/dist/config/defaults.d.ts.map +1 -1
  72. package/dist/config/defaults.js +2 -0
  73. package/dist/config/defaults.js.map +1 -1
  74. package/dist/config/schema.d.ts +175 -1
  75. package/dist/config/schema.d.ts.map +1 -1
  76. package/dist/config/schema.js +36 -1
  77. package/dist/config/schema.js.map +1 -1
  78. package/dist/generation/executor.d.ts.map +1 -1
  79. package/dist/generation/executor.js +2 -5
  80. package/dist/generation/executor.js.map +1 -1
  81. package/dist/generation/prompts/builder.d.ts +10 -0
  82. package/dist/generation/prompts/builder.d.ts.map +1 -1
  83. package/dist/generation/prompts/builder.js +77 -1
  84. package/dist/generation/prompts/builder.js.map +1 -1
  85. package/dist/generation/prompts/index.d.ts +1 -1
  86. package/dist/generation/prompts/index.d.ts.map +1 -1
  87. package/dist/generation/prompts/index.js +1 -1
  88. package/dist/generation/prompts/index.js.map +1 -1
  89. package/dist/generation/prompts/templates.d.ts +5 -0
  90. package/dist/generation/prompts/templates.d.ts.map +1 -1
  91. package/dist/generation/prompts/templates.js +94 -7
  92. package/dist/generation/prompts/templates.js.map +1 -1
  93. package/dist/generation/prompts/types.d.ts +2 -2
  94. package/dist/generation/prompts/types.js +1 -1
  95. package/dist/generation/writers/agents-md.d.ts +3 -59
  96. package/dist/generation/writers/agents-md.d.ts.map +1 -1
  97. package/dist/generation/writers/agents-md.js +11 -249
  98. package/dist/generation/writers/agents-md.js.map +1 -1
  99. package/dist/generation/writers/index.d.ts +1 -1
  100. package/dist/generation/writers/index.d.ts.map +1 -1
  101. package/dist/generation/writers/index.js +1 -1
  102. package/dist/generation/writers/index.js.map +1 -1
  103. package/dist/orchestration/index.d.ts +27 -0
  104. package/dist/orchestration/index.d.ts.map +1 -0
  105. package/dist/orchestration/index.js +34 -0
  106. package/dist/orchestration/index.js.map +1 -0
  107. package/dist/orchestration/pool.d.ts +62 -0
  108. package/dist/orchestration/pool.d.ts.map +1 -0
  109. package/dist/orchestration/pool.js +75 -0
  110. package/dist/orchestration/pool.js.map +1 -0
  111. package/dist/orchestration/progress.d.ts +124 -0
  112. package/dist/orchestration/progress.d.ts.map +1 -0
  113. package/dist/orchestration/progress.js +214 -0
  114. package/dist/orchestration/progress.js.map +1 -0
  115. package/dist/orchestration/runner.d.ts +76 -0
  116. package/dist/orchestration/runner.d.ts.map +1 -0
  117. package/dist/orchestration/runner.js +494 -0
  118. package/dist/orchestration/runner.js.map +1 -0
  119. package/dist/orchestration/types.d.ts +123 -0
  120. package/dist/orchestration/types.d.ts.map +1 -0
  121. package/dist/orchestration/types.js +11 -0
  122. package/dist/orchestration/types.js.map +1 -0
  123. package/dist/quality/density/validator.d.ts +38 -0
  124. package/dist/quality/density/validator.d.ts.map +1 -0
  125. package/dist/quality/density/validator.js +61 -0
  126. package/dist/quality/density/validator.js.map +1 -0
  127. package/dist/quality/inconsistency/code-vs-code.d.ts +26 -0
  128. package/dist/quality/inconsistency/code-vs-code.d.ts.map +1 -0
  129. package/dist/quality/inconsistency/code-vs-code.js +51 -0
  130. package/dist/quality/inconsistency/code-vs-code.js.map +1 -0
  131. package/dist/quality/inconsistency/code-vs-doc.d.ts +35 -0
  132. package/dist/quality/inconsistency/code-vs-doc.d.ts.map +1 -0
  133. package/dist/quality/inconsistency/code-vs-doc.js +59 -0
  134. package/dist/quality/inconsistency/code-vs-doc.js.map +1 -0
  135. package/dist/quality/inconsistency/code-vs-doc.test.d.ts +2 -0
  136. package/dist/quality/inconsistency/code-vs-doc.test.d.ts.map +1 -0
  137. package/dist/quality/inconsistency/code-vs-doc.test.js +196 -0
  138. package/dist/quality/inconsistency/code-vs-doc.test.js.map +1 -0
  139. package/dist/quality/inconsistency/reporter.d.ts +49 -0
  140. package/dist/quality/inconsistency/reporter.d.ts.map +1 -0
  141. package/dist/quality/inconsistency/reporter.js +99 -0
  142. package/dist/quality/inconsistency/reporter.js.map +1 -0
  143. package/dist/quality/index.d.ts +15 -0
  144. package/dist/quality/index.d.ts.map +1 -0
  145. package/dist/quality/index.js +25 -0
  146. package/dist/quality/index.js.map +1 -0
  147. package/dist/quality/types.d.ts +63 -0
  148. package/dist/quality/types.d.ts.map +1 -0
  149. package/dist/quality/types.js +5 -0
  150. package/dist/quality/types.js.map +1 -0
  151. package/dist/update/orchestrator.d.ts.map +1 -1
  152. package/dist/update/orchestrator.js +2 -1
  153. package/dist/update/orchestrator.js.map +1 -1
  154. package/dist/update/orphan-cleaner.js +1 -1
  155. package/dist/update/orphan-cleaner.js.map +1 -1
  156. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAkBH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAEvB,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE9D,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Cost estimation engine with pricing table, prefix matching, and format helpers.
3
+ *
4
+ * Provides hardcoded per-model pricing for major AI providers (Claude, GPT, Gemini)
5
+ * and utility functions for estimating, looking up, and formatting costs.
6
+ *
7
+ * @module
8
+ */
9
+ /** Per-model pricing rates in cost per million tokens. */
10
+ export interface ModelPricing {
11
+ /** Cost in USD per 1 million input tokens */
12
+ inputCostPerMTok: number;
13
+ /** Cost in USD per 1 million output tokens */
14
+ outputCostPerMTok: number;
15
+ }
16
+ /** Source of a cost estimate. */
17
+ export type CostSource = 'cli-reported' | 'estimated' | 'unavailable';
18
+ /** Result of a cost estimation with provenance tracking. */
19
+ export interface CostEstimate {
20
+ /** Estimated cost in USD (0 when unavailable) */
21
+ costUsd: number;
22
+ /** How the cost was determined */
23
+ source: CostSource;
24
+ }
25
+ /**
26
+ * Hardcoded pricing for major AI models.
27
+ *
28
+ * Keys are model ID prefixes. Models with date suffixes (e.g.
29
+ * `claude-opus-4-5-20251101`) are matched via prefix lookup against these keys.
30
+ *
31
+ * Prices are in USD per million tokens, verified as of 2026-02-07.
32
+ */
33
+ export declare const DEFAULT_MODEL_PRICING: Record<string, ModelPricing>;
34
+ /**
35
+ * Look up pricing for a model ID, with optional config overrides.
36
+ *
37
+ * Resolution order:
38
+ * 1. Exact match in merged table (overrides spread over defaults)
39
+ * 2. Prefix match with longest-key-first ordering to avoid ambiguity
40
+ * 3. `undefined` if no match found
41
+ *
42
+ * @param model - Model identifier (e.g. `"claude-opus-4-5-20251101"`)
43
+ * @param overrides - Optional pricing overrides from user config
44
+ * @returns Pricing rates or `undefined` for unknown models
45
+ */
46
+ export declare function lookupPricing(model: string, overrides?: Record<string, ModelPricing>): ModelPricing | undefined;
47
+ /**
48
+ * Estimate the cost of an AI call.
49
+ *
50
+ * Resolution order:
51
+ * 1. CLI-reported cost (when available and > 0)
52
+ * 2. Pricing table estimate (input + output token costs)
53
+ * 3. Unavailable (unknown model, no CLI cost)
54
+ *
55
+ * All costs are rounded to 4 decimal places.
56
+ *
57
+ * @param model - Model identifier
58
+ * @param inputTokens - Number of input tokens consumed
59
+ * @param outputTokens - Number of output tokens generated
60
+ * @param cliReportedCost - Cost reported by the CLI (if available)
61
+ * @param overrides - Optional pricing overrides from user config
62
+ * @returns Cost estimate with source provenance
63
+ */
64
+ export declare function estimateCost(model: string, inputTokens: number, outputTokens: number, cliReportedCost?: number, overrides?: Record<string, ModelPricing>): CostEstimate;
65
+ /**
66
+ * Format a cost value for display.
67
+ *
68
+ * @param costUsd - Cost in USD
69
+ * @param available - Whether the cost is available (false returns "N/A")
70
+ * @returns Formatted cost string (e.g. `"$0.1234"` or `"N/A"`)
71
+ */
72
+ export declare function formatCost(costUsd: number, available: boolean): string;
73
+ /**
74
+ * Format a token count for display with appropriate suffix.
75
+ *
76
+ * - >= 1,000,000: `"1.5M"`
77
+ * - >= 1,000: `"42K"`
78
+ * - < 1,000: `"500"`
79
+ *
80
+ * @param count - Number of tokens
81
+ * @returns Formatted token count string
82
+ */
83
+ export declare function formatTokens(count: number): string;
84
+ //# sourceMappingURL=pricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/ai/pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,0DAA0D;AAC1D,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,gBAAgB,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,iCAAiC;AACjC,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,WAAW,GAAG,aAAa,CAAC;AAEtE,4DAA4D;AAC5D,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,MAAM,EAAE,UAAU,CAAC;CACpB;AAMD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAqB9D,CAAC;AAMF;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GACvC,YAAY,GAAG,SAAS,CAoB1B;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,eAAe,CAAC,EAAE,MAAM,EACxB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GACvC,YAAY,CAoBd;AAMD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAKtE;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWlD"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Cost estimation engine with pricing table, prefix matching, and format helpers.
3
+ *
4
+ * Provides hardcoded per-model pricing for major AI providers (Claude, GPT, Gemini)
5
+ * and utility functions for estimating, looking up, and formatting costs.
6
+ *
7
+ * @module
8
+ */
9
+ // ---------------------------------------------------------------------------
10
+ // Default pricing table
11
+ // ---------------------------------------------------------------------------
12
+ /**
13
+ * Hardcoded pricing for major AI models.
14
+ *
15
+ * Keys are model ID prefixes. Models with date suffixes (e.g.
16
+ * `claude-opus-4-5-20251101`) are matched via prefix lookup against these keys.
17
+ *
18
+ * Prices are in USD per million tokens, verified as of 2026-02-07.
19
+ */
20
+ export const DEFAULT_MODEL_PRICING = {
21
+ // Claude (Anthropic) - verified 2026-02-07
22
+ 'claude-opus-4-6': { inputCostPerMTok: 5, outputCostPerMTok: 25 },
23
+ 'claude-opus-4-5': { inputCostPerMTok: 5, outputCostPerMTok: 25 },
24
+ 'claude-opus-4-1': { inputCostPerMTok: 15, outputCostPerMTok: 75 },
25
+ 'claude-opus-4': { inputCostPerMTok: 15, outputCostPerMTok: 75 },
26
+ 'claude-sonnet-4-5': { inputCostPerMTok: 3, outputCostPerMTok: 15 },
27
+ 'claude-sonnet-4': { inputCostPerMTok: 3, outputCostPerMTok: 15 },
28
+ 'claude-haiku-4-5': { inputCostPerMTok: 1, outputCostPerMTok: 5 },
29
+ 'claude-haiku-3-5': { inputCostPerMTok: 0.80, outputCostPerMTok: 4 },
30
+ 'claude-haiku-3': { inputCostPerMTok: 0.25, outputCostPerMTok: 1.25 },
31
+ // OpenAI GPT - from web search 2026-02-07
32
+ 'gpt-4o': { inputCostPerMTok: 2.50, outputCostPerMTok: 10 },
33
+ 'gpt-4o-mini': { inputCostPerMTok: 0.15, outputCostPerMTok: 0.60 },
34
+ 'gpt-4': { inputCostPerMTok: 30, outputCostPerMTok: 60 },
35
+ // Google Gemini - from web search 2026-02-07
36
+ 'gemini-2.5-flash': { inputCostPerMTok: 0.15, outputCostPerMTok: 0.60 },
37
+ 'gemini-2.5-pro': { inputCostPerMTok: 1.25, outputCostPerMTok: 10 },
38
+ 'gemini-3-flash': { inputCostPerMTok: 0.50, outputCostPerMTok: 3 },
39
+ };
40
+ // ---------------------------------------------------------------------------
41
+ // Lookup
42
+ // ---------------------------------------------------------------------------
43
+ /**
44
+ * Look up pricing for a model ID, with optional config overrides.
45
+ *
46
+ * Resolution order:
47
+ * 1. Exact match in merged table (overrides spread over defaults)
48
+ * 2. Prefix match with longest-key-first ordering to avoid ambiguity
49
+ * 3. `undefined` if no match found
50
+ *
51
+ * @param model - Model identifier (e.g. `"claude-opus-4-5-20251101"`)
52
+ * @param overrides - Optional pricing overrides from user config
53
+ * @returns Pricing rates or `undefined` for unknown models
54
+ */
55
+ export function lookupPricing(model, overrides) {
56
+ const table = {
57
+ ...DEFAULT_MODEL_PRICING,
58
+ ...overrides,
59
+ };
60
+ // Exact match
61
+ if (table[model] !== undefined) {
62
+ return table[model];
63
+ }
64
+ // Prefix match: sort keys longest-first so longer prefixes win
65
+ const keys = Object.keys(table).sort((a, b) => b.length - a.length);
66
+ for (const key of keys) {
67
+ if (model.startsWith(key)) {
68
+ return table[key];
69
+ }
70
+ }
71
+ return undefined;
72
+ }
73
+ // ---------------------------------------------------------------------------
74
+ // Cost estimation
75
+ // ---------------------------------------------------------------------------
76
+ /**
77
+ * Estimate the cost of an AI call.
78
+ *
79
+ * Resolution order:
80
+ * 1. CLI-reported cost (when available and > 0)
81
+ * 2. Pricing table estimate (input + output token costs)
82
+ * 3. Unavailable (unknown model, no CLI cost)
83
+ *
84
+ * All costs are rounded to 4 decimal places.
85
+ *
86
+ * @param model - Model identifier
87
+ * @param inputTokens - Number of input tokens consumed
88
+ * @param outputTokens - Number of output tokens generated
89
+ * @param cliReportedCost - Cost reported by the CLI (if available)
90
+ * @param overrides - Optional pricing overrides from user config
91
+ * @returns Cost estimate with source provenance
92
+ */
93
+ export function estimateCost(model, inputTokens, outputTokens, cliReportedCost, overrides) {
94
+ // CLI-reported cost takes precedence when available and non-zero
95
+ if (cliReportedCost !== undefined && cliReportedCost > 0) {
96
+ return {
97
+ costUsd: Number(cliReportedCost.toFixed(4)),
98
+ source: 'cli-reported',
99
+ };
100
+ }
101
+ // Fall back to pricing table
102
+ const pricing = lookupPricing(model, overrides);
103
+ if (pricing === undefined) {
104
+ return { costUsd: 0, source: 'unavailable' };
105
+ }
106
+ const inputCost = (pricing.inputCostPerMTok * inputTokens) / 1_000_000;
107
+ const outputCost = (pricing.outputCostPerMTok * outputTokens) / 1_000_000;
108
+ const totalCost = Number((inputCost + outputCost).toFixed(4));
109
+ return { costUsd: totalCost, source: 'estimated' };
110
+ }
111
+ // ---------------------------------------------------------------------------
112
+ // Formatting helpers
113
+ // ---------------------------------------------------------------------------
114
+ /**
115
+ * Format a cost value for display.
116
+ *
117
+ * @param costUsd - Cost in USD
118
+ * @param available - Whether the cost is available (false returns "N/A")
119
+ * @returns Formatted cost string (e.g. `"$0.1234"` or `"N/A"`)
120
+ */
121
+ export function formatCost(costUsd, available) {
122
+ if (!available) {
123
+ return 'N/A';
124
+ }
125
+ return `$${costUsd.toFixed(4)}`;
126
+ }
127
+ /**
128
+ * Format a token count for display with appropriate suffix.
129
+ *
130
+ * - >= 1,000,000: `"1.5M"`
131
+ * - >= 1,000: `"42K"`
132
+ * - < 1,000: `"500"`
133
+ *
134
+ * @param count - Number of tokens
135
+ * @returns Formatted token count string
136
+ */
137
+ export function formatTokens(count) {
138
+ if (count >= 1_000_000) {
139
+ const millions = count / 1_000_000;
140
+ // Remove trailing zeros: 1.0 -> 1, 1.5 -> 1.5
141
+ return `${parseFloat(millions.toFixed(1))}M`;
142
+ }
143
+ if (count >= 1_000) {
144
+ const thousands = count / 1_000;
145
+ return `${parseFloat(thousands.toFixed(1))}K`;
146
+ }
147
+ return `${count}`;
148
+ }
149
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../../src/ai/pricing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pricing.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.test.d.ts","sourceRoot":"","sources":["../../src/ai/pricing.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,164 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { DEFAULT_MODEL_PRICING, lookupPricing, estimateCost, formatCost, formatTokens, } from './pricing.js';
3
+ // ---------------------------------------------------------------------------
4
+ // DEFAULT_MODEL_PRICING
5
+ // ---------------------------------------------------------------------------
6
+ describe('DEFAULT_MODEL_PRICING', () => {
7
+ it('contains 15 models across Claude, GPT, and Gemini families', () => {
8
+ const keys = Object.keys(DEFAULT_MODEL_PRICING);
9
+ expect(keys).toHaveLength(15);
10
+ const claudeKeys = keys.filter((k) => k.startsWith('claude-'));
11
+ const gptKeys = keys.filter((k) => k.startsWith('gpt-'));
12
+ const geminiKeys = keys.filter((k) => k.startsWith('gemini-'));
13
+ expect(claudeKeys.length).toBe(9);
14
+ expect(gptKeys.length).toBe(3);
15
+ expect(geminiKeys.length).toBe(3);
16
+ });
17
+ it('has correct pricing for claude-sonnet-4', () => {
18
+ const pricing = DEFAULT_MODEL_PRICING['claude-sonnet-4'];
19
+ expect(pricing).toBeDefined();
20
+ expect(pricing.inputCostPerMTok).toBe(3);
21
+ expect(pricing.outputCostPerMTok).toBe(15);
22
+ });
23
+ it('has correct pricing for gpt-4o', () => {
24
+ const pricing = DEFAULT_MODEL_PRICING['gpt-4o'];
25
+ expect(pricing).toBeDefined();
26
+ expect(pricing.inputCostPerMTok).toBe(2.5);
27
+ expect(pricing.outputCostPerMTok).toBe(10);
28
+ });
29
+ it('has correct pricing for gemini-2.5-pro', () => {
30
+ const pricing = DEFAULT_MODEL_PRICING['gemini-2.5-pro'];
31
+ expect(pricing).toBeDefined();
32
+ expect(pricing.inputCostPerMTok).toBe(1.25);
33
+ expect(pricing.outputCostPerMTok).toBe(10);
34
+ });
35
+ });
36
+ // ---------------------------------------------------------------------------
37
+ // lookupPricing
38
+ // ---------------------------------------------------------------------------
39
+ describe('lookupPricing', () => {
40
+ it('returns exact match for known model', () => {
41
+ const result = lookupPricing('claude-opus-4-5');
42
+ expect(result).toBeDefined();
43
+ expect(result.inputCostPerMTok).toBe(5);
44
+ expect(result.outputCostPerMTok).toBe(25);
45
+ });
46
+ it('returns prefix match for model with date suffix', () => {
47
+ const result = lookupPricing('claude-opus-4-5-20251101');
48
+ expect(result).toBeDefined();
49
+ expect(result.inputCostPerMTok).toBe(5);
50
+ expect(result.outputCostPerMTok).toBe(25);
51
+ });
52
+ it('prefers longer prefix key over shorter one', () => {
53
+ // 'claude-opus-4-5' should match before 'claude-opus-4'
54
+ const result = lookupPricing('claude-opus-4-5-20251101');
55
+ expect(result).toBeDefined();
56
+ // claude-opus-4-5 has input=5, claude-opus-4 has input=15
57
+ expect(result.inputCostPerMTok).toBe(5);
58
+ });
59
+ it('returns undefined for unknown model', () => {
60
+ const result = lookupPricing('custom-model');
61
+ expect(result).toBeUndefined();
62
+ });
63
+ it('uses config overrides over defaults', () => {
64
+ const overrides = {
65
+ 'my-model': { inputCostPerMTok: 1, outputCostPerMTok: 5 },
66
+ };
67
+ const result = lookupPricing('my-model', overrides);
68
+ expect(result).toBeDefined();
69
+ expect(result.inputCostPerMTok).toBe(1);
70
+ expect(result.outputCostPerMTok).toBe(5);
71
+ });
72
+ it('config overrides take precedence over hardcoded defaults', () => {
73
+ const overrides = {
74
+ 'claude-sonnet-4': { inputCostPerMTok: 99, outputCostPerMTok: 99 },
75
+ };
76
+ const result = lookupPricing('claude-sonnet-4', overrides);
77
+ expect(result).toBeDefined();
78
+ expect(result.inputCostPerMTok).toBe(99);
79
+ expect(result.outputCostPerMTok).toBe(99);
80
+ });
81
+ });
82
+ // ---------------------------------------------------------------------------
83
+ // estimateCost
84
+ // ---------------------------------------------------------------------------
85
+ describe('estimateCost', () => {
86
+ it('returns CLI-reported cost when available and non-zero', () => {
87
+ const result = estimateCost('claude-sonnet-4', 1000, 100, 0.018);
88
+ expect(result.costUsd).toBe(0.018);
89
+ expect(result.source).toBe('cli-reported');
90
+ });
91
+ it('falls back to pricing table when CLI cost is zero', () => {
92
+ // claude-sonnet-4: input=3, output=15
93
+ // cost = (3 * 1_000_000 / 1_000_000) + (15 * 100_000 / 1_000_000) = 3 + 1.5 = 4.5
94
+ const result = estimateCost('claude-sonnet-4', 1_000_000, 100_000, 0);
95
+ expect(result.costUsd).toBe(4.5);
96
+ expect(result.source).toBe('estimated');
97
+ });
98
+ it('falls back to pricing table when CLI cost is undefined', () => {
99
+ const result = estimateCost('claude-sonnet-4', 1_000_000, 100_000);
100
+ expect(result.costUsd).toBe(4.5);
101
+ expect(result.source).toBe('estimated');
102
+ });
103
+ it('returns unavailable source when model is not in pricing table', () => {
104
+ const result = estimateCost('unknown-model', 1000, 100);
105
+ expect(result.costUsd).toBe(0);
106
+ expect(result.source).toBe('unavailable');
107
+ });
108
+ it('uses 4-decimal precision for estimated costs', () => {
109
+ // claude-haiku-3-5: input=0.80, output=4
110
+ // cost = (0.80 * 1234 / 1_000_000) + (4 * 567 / 1_000_000)
111
+ // = 0.0009872 + 0.002268 = 0.0032552
112
+ // rounded to 4 decimals = 0.0033
113
+ const result = estimateCost('claude-haiku-3-5', 1234, 567);
114
+ expect(result.costUsd).toBe(0.0033);
115
+ expect(result.source).toBe('estimated');
116
+ });
117
+ it('passes overrides to lookupPricing', () => {
118
+ const overrides = {
119
+ 'my-custom': { inputCostPerMTok: 10, outputCostPerMTok: 20 },
120
+ };
121
+ // cost = (10 * 1_000_000 / 1_000_000) + (20 * 500_000 / 1_000_000) = 10 + 10 = 20
122
+ const result = estimateCost('my-custom', 1_000_000, 500_000, undefined, overrides);
123
+ expect(result.costUsd).toBe(20);
124
+ expect(result.source).toBe('estimated');
125
+ });
126
+ });
127
+ // ---------------------------------------------------------------------------
128
+ // formatCost
129
+ // ---------------------------------------------------------------------------
130
+ describe('formatCost', () => {
131
+ it('returns $X.XXXX with 4-decimal precision for available costs', () => {
132
+ expect(formatCost(0.1234, true)).toBe('$0.1234');
133
+ });
134
+ it('returns N/A when cost is unavailable', () => {
135
+ expect(formatCost(0, false)).toBe('N/A');
136
+ });
137
+ it('pads to 4 decimal places', () => {
138
+ expect(formatCost(1.5, true)).toBe('$1.5000');
139
+ });
140
+ it('rounds to 4 decimal places', () => {
141
+ expect(formatCost(0.123456, true)).toBe('$0.1235');
142
+ });
143
+ });
144
+ // ---------------------------------------------------------------------------
145
+ // formatTokens
146
+ // ---------------------------------------------------------------------------
147
+ describe('formatTokens', () => {
148
+ it('formats millions with M suffix', () => {
149
+ expect(formatTokens(1_500_000)).toBe('1.5M');
150
+ });
151
+ it('formats thousands with K suffix', () => {
152
+ expect(formatTokens(42_000)).toBe('42K');
153
+ });
154
+ it('formats small numbers without suffix', () => {
155
+ expect(formatTokens(500)).toBe('500');
156
+ });
157
+ it('formats exact million', () => {
158
+ expect(formatTokens(1_000_000)).toBe('1M');
159
+ });
160
+ it('formats exact thousand', () => {
161
+ expect(formatTokens(1_000)).toBe('1K');
162
+ });
163
+ });
164
+ //# sourceMappingURL=pricing.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.test.js","sourceRoot":"","sources":["../../src/ai/pricing.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Backend registry, factory, and auto-detection.
3
+ *
4
+ * Manages the set of registered AI CLI backends, selects the appropriate
5
+ * backend at runtime via auto-detection or explicit request, and provides
6
+ * actionable error messages when no CLI is found.
7
+ *
8
+ * @module
9
+ */
10
+ import type { AIBackend } from './types.js';
11
+ /**
12
+ * Registry of available AI CLI backends.
13
+ *
14
+ * Stores backends in insertion order, which determines the priority for
15
+ * auto-detection. Use {@link createBackendRegistry} to get a pre-populated
16
+ * registry with all supported backends.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const registry = createBackendRegistry();
21
+ * const claude = registry.get('claude');
22
+ * const all = registry.getAll(); // [ClaudeBackend, GeminiBackend, OpenCodeBackend]
23
+ * ```
24
+ */
25
+ export declare class BackendRegistry {
26
+ private readonly backends;
27
+ /**
28
+ * Register a backend adapter.
29
+ *
30
+ * @param backend - The backend to register (keyed by its `name` property)
31
+ */
32
+ register(backend: AIBackend): void;
33
+ /**
34
+ * Get a specific backend by name.
35
+ *
36
+ * @param name - The backend name (e.g., "claude", "gemini", "opencode")
37
+ * @returns The backend, or `undefined` if not registered
38
+ */
39
+ get(name: string): AIBackend | undefined;
40
+ /**
41
+ * Get all registered backends in priority order.
42
+ *
43
+ * @returns Array of all registered backends
44
+ */
45
+ getAll(): AIBackend[];
46
+ }
47
+ /**
48
+ * Create a new backend registry pre-populated with all supported backends.
49
+ *
50
+ * Registration order determines auto-detection priority:
51
+ * 1. Claude (recommended, fully implemented)
52
+ * 2. Gemini (experimental, stub)
53
+ * 3. OpenCode (experimental, stub)
54
+ *
55
+ * @returns A populated {@link BackendRegistry}
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const registry = createBackendRegistry();
60
+ * const backend = await detectBackend(registry);
61
+ * ```
62
+ */
63
+ export declare function createBackendRegistry(): BackendRegistry;
64
+ /**
65
+ * Detect the first available backend on PATH in priority order.
66
+ *
67
+ * Iterates all registered backends and calls `isAvailable()` on each.
68
+ * Returns the first backend whose CLI is found, or `null` if none are
69
+ * available.
70
+ *
71
+ * Priority order is determined by registration order in
72
+ * {@link createBackendRegistry}: Claude > Gemini > OpenCode.
73
+ *
74
+ * @param registry - The backend registry to search
75
+ * @returns The first available backend, or `null` if none found
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * const registry = createBackendRegistry();
80
+ * const backend = await detectBackend(registry);
81
+ * if (backend) {
82
+ * console.log(`Using ${backend.name} backend`);
83
+ * }
84
+ * ```
85
+ */
86
+ export declare function detectBackend(registry: BackendRegistry): Promise<AIBackend | null>;
87
+ /**
88
+ * Get formatted install instructions for all registered backends.
89
+ *
90
+ * Returns a multi-line string suitable for error messages when no CLI
91
+ * is found. Matches the error message template from RESEARCH.md.
92
+ *
93
+ * @param registry - The backend registry
94
+ * @returns Formatted install instructions string
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * const instructions = getInstallInstructions(registry);
99
+ * console.error(`No AI CLI found.\n\nInstall one of the following:\n\n${instructions}`);
100
+ * ```
101
+ */
102
+ export declare function getInstallInstructions(registry: BackendRegistry): string;
103
+ /**
104
+ * Resolve a backend by name or auto-detect the best available one.
105
+ *
106
+ * - If `requested` is `'auto'`: runs {@link detectBackend} and throws with
107
+ * install instructions if nothing is found.
108
+ * - If `requested` is a specific name: looks it up in the registry, checks
109
+ * availability, and throws if not found or not available.
110
+ *
111
+ * @param registry - The backend registry
112
+ * @param requested - Backend name or `'auto'` for auto-detection
113
+ * @returns The resolved backend adapter
114
+ * @throws {AIServiceError} With code `CLI_NOT_FOUND` if no backend is available
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * const registry = createBackendRegistry();
119
+ *
120
+ * // Auto-detect
121
+ * const backend = await resolveBackend(registry, 'auto');
122
+ *
123
+ * // Explicit selection
124
+ * const claude = await resolveBackend(registry, 'claude');
125
+ * ```
126
+ */
127
+ export declare function resolveBackend(registry: BackendRegistry, requested: string | 'auto'): Promise<AIBackend>;
128
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/ai/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAU5C;;;;;;;;;;;;;GAaG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;IAEzD;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI;IAIlC;;;;;OAKG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIxC;;;;OAIG;IACH,MAAM,IAAI,SAAS,EAAE;CAGtB;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CAMvD;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAOxF;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAKxE;AAMD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,eAAe,EACzB,SAAS,EAAE,MAAM,GAAG,MAAM,GACzB,OAAO,CAAC,SAAS,CAAC,CAmCpB"}