k0ntext 3.0.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 (239) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +623 -0
  3. package/bin/k0ntext.js +12 -0
  4. package/dist/agents/cleanup-agent.d.ts +39 -0
  5. package/dist/agents/cleanup-agent.d.ts.map +1 -0
  6. package/dist/agents/cleanup-agent.js +56 -0
  7. package/dist/agents/cleanup-agent.js.map +1 -0
  8. package/dist/agents/performance-agent.d.ts +37 -0
  9. package/dist/agents/performance-agent.d.ts.map +1 -0
  10. package/dist/agents/performance-agent.js +91 -0
  11. package/dist/agents/performance-agent.js.map +1 -0
  12. package/dist/analyzer/index.d.ts +5 -0
  13. package/dist/analyzer/index.d.ts.map +1 -0
  14. package/dist/analyzer/index.js +5 -0
  15. package/dist/analyzer/index.js.map +1 -0
  16. package/dist/analyzer/intelligent-analyzer.d.ts +111 -0
  17. package/dist/analyzer/intelligent-analyzer.d.ts.map +1 -0
  18. package/dist/analyzer/intelligent-analyzer.js +537 -0
  19. package/dist/analyzer/intelligent-analyzer.js.map +1 -0
  20. package/dist/cli/commands/cleanup.d.ts +3 -0
  21. package/dist/cli/commands/cleanup.d.ts.map +1 -0
  22. package/dist/cli/commands/cleanup.js +24 -0
  23. package/dist/cli/commands/cleanup.js.map +1 -0
  24. package/dist/cli/commands/export.d.ts +9 -0
  25. package/dist/cli/commands/export.d.ts.map +1 -0
  26. package/dist/cli/commands/export.js +72 -0
  27. package/dist/cli/commands/export.js.map +1 -0
  28. package/dist/cli/commands/import.d.ts +9 -0
  29. package/dist/cli/commands/import.d.ts.map +1 -0
  30. package/dist/cli/commands/import.js +62 -0
  31. package/dist/cli/commands/import.js.map +1 -0
  32. package/dist/cli/commands/performance.d.ts +9 -0
  33. package/dist/cli/commands/performance.d.ts.map +1 -0
  34. package/dist/cli/commands/performance.js +36 -0
  35. package/dist/cli/commands/performance.js.map +1 -0
  36. package/dist/cli/commands/validate.d.ts +9 -0
  37. package/dist/cli/commands/validate.d.ts.map +1 -0
  38. package/dist/cli/commands/validate.js +82 -0
  39. package/dist/cli/commands/validate.js.map +1 -0
  40. package/dist/cli/commands/watch.d.ts +9 -0
  41. package/dist/cli/commands/watch.d.ts.map +1 -0
  42. package/dist/cli/commands/watch.js +72 -0
  43. package/dist/cli/commands/watch.js.map +1 -0
  44. package/dist/cli/generate.d.ts +3 -0
  45. package/dist/cli/generate.d.ts.map +1 -0
  46. package/dist/cli/generate.js +194 -0
  47. package/dist/cli/generate.js.map +1 -0
  48. package/dist/cli/index.d.ts +9 -0
  49. package/dist/cli/index.d.ts.map +1 -0
  50. package/dist/cli/index.js +448 -0
  51. package/dist/cli/index.js.map +1 -0
  52. package/dist/cli/sync.d.ts +26 -0
  53. package/dist/cli/sync.d.ts.map +1 -0
  54. package/dist/cli/sync.js +163 -0
  55. package/dist/cli/sync.js.map +1 -0
  56. package/dist/config/cleanup-config.d.ts +26 -0
  57. package/dist/config/cleanup-config.d.ts.map +1 -0
  58. package/dist/config/cleanup-config.js +21 -0
  59. package/dist/config/cleanup-config.js.map +1 -0
  60. package/dist/db/client.d.ts +284 -0
  61. package/dist/db/client.d.ts.map +1 -0
  62. package/dist/db/client.js +688 -0
  63. package/dist/db/client.js.map +1 -0
  64. package/dist/db/index.d.ts +6 -0
  65. package/dist/db/index.d.ts.map +1 -0
  66. package/dist/db/index.js +6 -0
  67. package/dist/db/index.js.map +1 -0
  68. package/dist/db/schema.d.ts +41 -0
  69. package/dist/db/schema.d.ts.map +1 -0
  70. package/dist/db/schema.js +226 -0
  71. package/dist/db/schema.js.map +1 -0
  72. package/dist/embeddings/index.d.ts +5 -0
  73. package/dist/embeddings/index.d.ts.map +1 -0
  74. package/dist/embeddings/index.js +5 -0
  75. package/dist/embeddings/index.js.map +1 -0
  76. package/dist/embeddings/openrouter.d.ts +133 -0
  77. package/dist/embeddings/openrouter.d.ts.map +1 -0
  78. package/dist/embeddings/openrouter.js +455 -0
  79. package/dist/embeddings/openrouter.js.map +1 -0
  80. package/dist/index.d.ts +14 -0
  81. package/dist/index.d.ts.map +1 -0
  82. package/dist/index.js +18 -0
  83. package/dist/index.js.map +1 -0
  84. package/dist/mcp.d.ts +29 -0
  85. package/dist/mcp.d.ts.map +1 -0
  86. package/dist/mcp.js +257 -0
  87. package/dist/mcp.js.map +1 -0
  88. package/docs/ARCHIVE/MIGRATE_TO_NEW_REPO.md +222 -0
  89. package/docs/ARCHIVE/MIGRATE_TO_UNIFIED.md +220 -0
  90. package/docs/CLEANUP.md +76 -0
  91. package/docs/MCP_QUICKSTART.md +219 -0
  92. package/docs/QUICKSTART.md +119 -0
  93. package/docs/TROUBLESHOOTING.md +611 -0
  94. package/package.json +100 -0
  95. package/skills/context-optimize/SKILL.md +86 -0
  96. package/skills/implement/SKILL.md +150 -0
  97. package/skills/plan/SKILL.md +143 -0
  98. package/skills/research/SKILL.md +103 -0
  99. package/skills/validate/SKILL.md +62 -0
  100. package/skills/verify-docs/SKILL.md +77 -0
  101. package/src/agents/cleanup-agent.ts +96 -0
  102. package/src/agents/performance-agent.ts +117 -0
  103. package/src/analyzer/index.ts +10 -0
  104. package/src/analyzer/intelligent-analyzer.ts +640 -0
  105. package/src/cli/commands/cleanup.ts +26 -0
  106. package/src/cli/commands/export.ts +82 -0
  107. package/src/cli/commands/import.ts +73 -0
  108. package/src/cli/commands/performance.ts +40 -0
  109. package/src/cli/commands/validate.ts +98 -0
  110. package/src/cli/commands/watch.ts +83 -0
  111. package/src/cli/generate.ts +219 -0
  112. package/src/cli/index.ts +510 -0
  113. package/src/cli/sync.ts +194 -0
  114. package/src/config/cleanup-config.ts +42 -0
  115. package/src/db/client.ts +949 -0
  116. package/src/db/index.ts +19 -0
  117. package/src/db/schema.ts +241 -0
  118. package/src/embeddings/index.ts +11 -0
  119. package/src/embeddings/openrouter.ts +592 -0
  120. package/src/index.ts +57 -0
  121. package/src/mcp.ts +354 -0
  122. package/templates/AI_CONTEXT.md.template +245 -0
  123. package/templates/base/README.md +260 -0
  124. package/templates/base/RPI_WORKFLOW_PLAN.md +325 -0
  125. package/templates/base/agents/api-developer.md +76 -0
  126. package/templates/base/agents/context-engineer.md +525 -0
  127. package/templates/base/agents/core-architect.md +76 -0
  128. package/templates/base/agents/database-ops.md +76 -0
  129. package/templates/base/agents/deployment-ops.md +76 -0
  130. package/templates/base/agents/integration-hub.md +76 -0
  131. package/templates/base/analytics/README.md +114 -0
  132. package/templates/base/automation/config.json +58 -0
  133. package/templates/base/automation/generators/code-mapper.js +308 -0
  134. package/templates/base/automation/generators/index-builder.js +321 -0
  135. package/templates/base/automation/hooks/post-commit.sh +83 -0
  136. package/templates/base/automation/hooks/pre-commit.sh +103 -0
  137. package/templates/base/ci-templates/README.md +108 -0
  138. package/templates/base/ci-templates/github-actions/context-check.yml +144 -0
  139. package/templates/base/ci-templates/github-actions/validate-docs.yml +105 -0
  140. package/templates/base/commands/analytics.md +238 -0
  141. package/templates/base/commands/auto-sync.md +172 -0
  142. package/templates/base/commands/collab.md +194 -0
  143. package/templates/base/commands/context-optimize.md +226 -0
  144. package/templates/base/commands/help.md +485 -0
  145. package/templates/base/commands/rpi-implement.md +164 -0
  146. package/templates/base/commands/rpi-plan.md +147 -0
  147. package/templates/base/commands/rpi-research.md +145 -0
  148. package/templates/base/commands/session-resume.md +144 -0
  149. package/templates/base/commands/session-save.md +112 -0
  150. package/templates/base/commands/validate-all.md +77 -0
  151. package/templates/base/commands/verify-docs-current.md +86 -0
  152. package/templates/base/config/base.json +57 -0
  153. package/templates/base/config/environments/development.json +13 -0
  154. package/templates/base/config/environments/production.json +17 -0
  155. package/templates/base/config/environments/staging.json +13 -0
  156. package/templates/base/config/local.json.example +21 -0
  157. package/templates/base/context/.meta/generated-at.json +18 -0
  158. package/templates/base/context/ARCHITECTURE_SNAPSHOT.md +156 -0
  159. package/templates/base/context/CODE_TO_WORKFLOW_MAP.md +94 -0
  160. package/templates/base/context/FILE_OWNERSHIP.md +57 -0
  161. package/templates/base/context/INTEGRATION_POINTS.md +92 -0
  162. package/templates/base/context/KNOWN_GOTCHAS.md +195 -0
  163. package/templates/base/context/TESTING_MAP.md +95 -0
  164. package/templates/base/context/WORKFLOW_INDEX.md +129 -0
  165. package/templates/base/context/workflows/WORKFLOW_TEMPLATE.md +294 -0
  166. package/templates/base/indexes/agents/CAPABILITY_MATRIX.md +255 -0
  167. package/templates/base/indexes/agents/CATEGORY_INDEX.md +44 -0
  168. package/templates/base/indexes/code/CATEGORY_INDEX.md +38 -0
  169. package/templates/base/indexes/routing/CATEGORY_INDEX.md +39 -0
  170. package/templates/base/indexes/search/CATEGORY_INDEX.md +39 -0
  171. package/templates/base/indexes/workflows/CATEGORY_INDEX.md +38 -0
  172. package/templates/base/knowledge/README.md +98 -0
  173. package/templates/base/knowledge/sessions/README.md +88 -0
  174. package/templates/base/knowledge/sessions/TEMPLATE.md +150 -0
  175. package/templates/base/knowledge/shared/decisions/0001-adopt-context-engineering.md +144 -0
  176. package/templates/base/knowledge/shared/decisions/README.md +49 -0
  177. package/templates/base/knowledge/shared/decisions/TEMPLATE.md +123 -0
  178. package/templates/base/knowledge/shared/patterns/README.md +62 -0
  179. package/templates/base/knowledge/shared/patterns/TEMPLATE.md +120 -0
  180. package/templates/base/plans/PLAN_TEMPLATE.md +316 -0
  181. package/templates/base/plans/active/.gitkeep +0 -0
  182. package/templates/base/plans/completed/.gitkeep +0 -0
  183. package/templates/base/research/RESEARCH_TEMPLATE.md +245 -0
  184. package/templates/base/research/active/.gitkeep +0 -0
  185. package/templates/base/research/completed/.gitkeep +0 -0
  186. package/templates/base/schemas/agent.schema.json +141 -0
  187. package/templates/base/schemas/anchors.schema.json +54 -0
  188. package/templates/base/schemas/automation.schema.json +93 -0
  189. package/templates/base/schemas/command.schema.json +134 -0
  190. package/templates/base/schemas/hashes.schema.json +40 -0
  191. package/templates/base/schemas/manifest.schema.json +117 -0
  192. package/templates/base/schemas/plan.schema.json +136 -0
  193. package/templates/base/schemas/research.schema.json +115 -0
  194. package/templates/base/schemas/roles.schema.json +34 -0
  195. package/templates/base/schemas/session.schema.json +77 -0
  196. package/templates/base/schemas/settings.schema.json +244 -0
  197. package/templates/base/schemas/staleness.schema.json +53 -0
  198. package/templates/base/schemas/team-config.schema.json +42 -0
  199. package/templates/base/schemas/workflow.schema.json +126 -0
  200. package/templates/base/session/checkpoints/.gitkeep +2 -0
  201. package/templates/base/session/current/state.json +20 -0
  202. package/templates/base/session/history/.gitkeep +2 -0
  203. package/templates/base/settings.json +3 -0
  204. package/templates/base/standards/COMPATIBILITY.md +219 -0
  205. package/templates/base/standards/EXTENSION_GUIDELINES.md +280 -0
  206. package/templates/base/standards/QUALITY_CHECKLIST.md +211 -0
  207. package/templates/base/standards/README.md +66 -0
  208. package/templates/base/sync/anchors.json +6 -0
  209. package/templates/base/sync/hashes.json +6 -0
  210. package/templates/base/sync/staleness.json +10 -0
  211. package/templates/base/team/README.md +168 -0
  212. package/templates/base/team/config.json +79 -0
  213. package/templates/base/team/roles.json +145 -0
  214. package/templates/base/tools/bin/claude-context.js +151 -0
  215. package/templates/base/tools/lib/anchor-resolver.js +276 -0
  216. package/templates/base/tools/lib/config-loader.js +363 -0
  217. package/templates/base/tools/lib/detector.js +350 -0
  218. package/templates/base/tools/lib/diagnose.js +206 -0
  219. package/templates/base/tools/lib/drift-detector.js +373 -0
  220. package/templates/base/tools/lib/errors.js +199 -0
  221. package/templates/base/tools/lib/index.js +36 -0
  222. package/templates/base/tools/lib/init.js +192 -0
  223. package/templates/base/tools/lib/logger.js +230 -0
  224. package/templates/base/tools/lib/placeholder.js +201 -0
  225. package/templates/base/tools/lib/session-manager.js +354 -0
  226. package/templates/base/tools/lib/validate.js +521 -0
  227. package/templates/base/tools/package.json +49 -0
  228. package/templates/handlebars/aider-config.hbs +146 -0
  229. package/templates/handlebars/antigravity.hbs +377 -0
  230. package/templates/handlebars/claude.hbs +183 -0
  231. package/templates/handlebars/cline.hbs +62 -0
  232. package/templates/handlebars/continue-config.hbs +116 -0
  233. package/templates/handlebars/copilot.hbs +130 -0
  234. package/templates/handlebars/partials/gotcha-list.hbs +11 -0
  235. package/templates/handlebars/partials/header.hbs +3 -0
  236. package/templates/handlebars/partials/workflow-summary.hbs +16 -0
  237. package/templates/handlebars/windsurf-rules.hbs +69 -0
  238. package/templates/hooks/post-commit.hbs +28 -0
  239. package/templates/hooks/pre-commit.hbs +46 -0
@@ -0,0 +1,592 @@
1
+ /**
2
+ * OpenRouter Client
3
+ *
4
+ * Client for OpenRouter API supporting both embeddings and chat completions.
5
+ * Used for intelligent initialization and context understanding.
6
+ */
7
+
8
+ import { createHash } from 'crypto';
9
+
10
+ /**
11
+ * OpenRouter API endpoints
12
+ */
13
+ const OPENROUTER_EMBEDDINGS_URL = 'https://openrouter.ai/api/v1/embeddings';
14
+ const OPENROUTER_CHAT_URL = 'https://openrouter.ai/api/v1/chat/completions';
15
+
16
+ /**
17
+ * Default models
18
+ */
19
+ const DEFAULT_EMBEDDING_MODEL = 'openai/text-embedding-3-small';
20
+ const DEFAULT_CHAT_MODEL = 'anthropic/claude-3-haiku';
21
+ const EMBEDDING_DIMENSION = 1536;
22
+
23
+ /**
24
+ * Embedding response from OpenRouter
25
+ */
26
+ interface EmbeddingResponse {
27
+ data: Array<{
28
+ embedding: number[];
29
+ index: number;
30
+ }>;
31
+ model: string;
32
+ usage: {
33
+ prompt_tokens: number;
34
+ total_tokens: number;
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Chat completion response from OpenRouter
40
+ */
41
+ interface ChatResponse {
42
+ id: string;
43
+ choices: Array<{
44
+ message: {
45
+ role: string;
46
+ content: string;
47
+ };
48
+ finish_reason: string;
49
+ }>;
50
+ model: string;
51
+ usage: {
52
+ prompt_tokens: number;
53
+ completion_tokens: number;
54
+ total_tokens: number;
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Message for chat completion
60
+ */
61
+ export interface ChatMessage {
62
+ role: 'system' | 'user' | 'assistant';
63
+ content: string;
64
+ }
65
+
66
+ /**
67
+ * Configuration for OpenRouter client
68
+ */
69
+ export interface OpenRouterConfig {
70
+ apiKey: string;
71
+ embeddingModel?: string;
72
+ chatModel?: string;
73
+ siteUrl?: string;
74
+ siteName?: string;
75
+ minRequestInterval?: number; // ms between requests for rate limiting
76
+ requestTimeout?: number; // ms timeout for requests
77
+ }
78
+
79
+ /**
80
+ * OpenRouter-specific error types
81
+ */
82
+ export class OpenRouterError extends Error {
83
+ constructor(message: string, public code?: string) {
84
+ super(message);
85
+ this.name = 'OpenRouterError';
86
+ }
87
+ }
88
+
89
+ export class OpenRouterRateLimitError extends OpenRouterError {
90
+ constructor(message: string, public retryAfter?: number) {
91
+ super(message, 'RATE_LIMIT');
92
+ this.name = 'OpenRouterRateLimitError';
93
+ }
94
+ }
95
+
96
+ export class OpenRouterAuthError extends OpenRouterError {
97
+ constructor(message: string) {
98
+ super(message, 'AUTH_ERROR');
99
+ this.name = 'OpenRouterAuthError';
100
+ }
101
+ }
102
+
103
+ export class OpenRouterTimeoutError extends OpenRouterError {
104
+ constructor(message: string) {
105
+ super(message, 'TIMEOUT');
106
+ this.name = 'OpenRouterTimeoutError';
107
+ }
108
+ }
109
+
110
+ /**
111
+ * OpenRouter client for embeddings and chat
112
+ */
113
+ export class OpenRouterClient {
114
+ private apiKey: string;
115
+ private embeddingModel: string;
116
+ private chatModel: string;
117
+ private siteUrl: string;
118
+ private siteName: string;
119
+ private embeddingCache: Map<string, number[]> = new Map();
120
+
121
+ /**
122
+ * Retry configuration
123
+ */
124
+ private maxRetries = 3;
125
+ private baseRetryDelay = 1000; // ms
126
+
127
+ /**
128
+ * Rate limiting configuration
129
+ */
130
+ private minRequestInterval: number;
131
+ private lastRequestTime = 0;
132
+
133
+ /**
134
+ * Timeout configuration
135
+ */
136
+ private requestTimeout: number;
137
+
138
+ /**
139
+ * Sleep for specified milliseconds
140
+ */
141
+ private sleep(ms: number): Promise<void> {
142
+ return new Promise(resolve => setTimeout(resolve, ms));
143
+ }
144
+
145
+ /**
146
+ * Create a timeout promise that rejects after specified milliseconds
147
+ */
148
+ private createTimeoutPromise(ms: number): Promise<never> {
149
+ return new Promise((_, reject) => {
150
+ setTimeout(() => {
151
+ reject(new OpenRouterTimeoutError(`Request timed out after ${ms}ms`));
152
+ }, ms);
153
+ });
154
+ }
155
+
156
+ /**
157
+ * Wrap a fetch promise with timeout
158
+ */
159
+ private async fetchWithTimeout(url: string, options: RequestInit, timeout: number): Promise<Response> {
160
+ return Promise.race([
161
+ fetch(url, options),
162
+ this.createTimeoutPromise(timeout)
163
+ ]);
164
+ }
165
+
166
+ /**
167
+ * Apply rate limiting before API requests
168
+ */
169
+ private async applyRateLimit(): Promise<void> {
170
+ const now = Date.now();
171
+ const timeSinceLastRequest = now - this.lastRequestTime;
172
+
173
+ if (timeSinceLastRequest < this.minRequestInterval) {
174
+ const waitTime = this.minRequestInterval - timeSinceLastRequest;
175
+ await this.sleep(waitTime);
176
+ }
177
+
178
+ this.lastRequestTime = Date.now();
179
+ }
180
+
181
+ constructor(config: OpenRouterConfig) {
182
+ if (!config.apiKey) {
183
+ throw new Error('OPENROUTER_API_KEY is required');
184
+ }
185
+
186
+ this.apiKey = config.apiKey;
187
+ this.embeddingModel = config.embeddingModel || DEFAULT_EMBEDDING_MODEL;
188
+ this.chatModel = config.chatModel || DEFAULT_CHAT_MODEL;
189
+ this.siteUrl = config.siteUrl || 'https://github.com/SireJeff/claude-context-engineering-template';
190
+ this.siteName = config.siteName || 'AI Context';
191
+ this.minRequestInterval = config.minRequestInterval || 100; // ms between requests
192
+ this.requestTimeout = config.requestTimeout || 30000; // 30 seconds default
193
+ this.lastRequestTime = 0;
194
+ }
195
+
196
+ /**
197
+ * Generate embedding for a single text
198
+ */
199
+ async embed(text: string): Promise<number[]> {
200
+ // Check cache
201
+ const cacheKey = this.hashText(text);
202
+ if (this.embeddingCache.has(cacheKey)) {
203
+ return this.embeddingCache.get(cacheKey)!;
204
+ }
205
+
206
+ let lastError: Error | null = null;
207
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
208
+ try {
209
+ // Apply rate limiting before each attempt
210
+ await this.applyRateLimit();
211
+
212
+ const response = await this.fetchWithTimeout(OPENROUTER_EMBEDDINGS_URL, {
213
+ method: 'POST',
214
+ headers: {
215
+ 'Authorization': `Bearer ${this.apiKey}`,
216
+ 'Content-Type': 'application/json',
217
+ 'HTTP-Referer': this.siteUrl,
218
+ 'X-Title': this.siteName
219
+ },
220
+ body: JSON.stringify({
221
+ model: this.embeddingModel,
222
+ input: text
223
+ })
224
+ }, this.requestTimeout);
225
+
226
+ if (!response.ok) {
227
+ const error = await response.text();
228
+ // Don't retry auth errors
229
+ if (response.status === 401 || response.status === 403) {
230
+ throw new OpenRouterAuthError(`Authentication failed: ${error}`);
231
+ }
232
+ // Rate limit errors - check for retry-after header
233
+ if (response.status === 429) {
234
+ const retryAfter = response.headers.get('Retry-After');
235
+ throw new OpenRouterRateLimitError(
236
+ `Rate limit exceeded: ${error}`,
237
+ retryAfter ? parseInt(retryAfter, 10) : undefined
238
+ );
239
+ }
240
+ throw new OpenRouterError(`OpenRouter API error (${response.status}): ${error}`);
241
+ }
242
+
243
+ const data = await response.json() as EmbeddingResponse;
244
+
245
+ if (
246
+ !data ||
247
+ !Array.isArray(data.data) ||
248
+ data.data.length === 0 ||
249
+ !data.data[0] ||
250
+ !Array.isArray(data.data[0].embedding)
251
+ ) {
252
+ throw new OpenRouterError('OpenRouter API error: no embedding data returned in response', 'NO_DATA');
253
+ }
254
+
255
+ const embedding = data.data[0].embedding;
256
+
257
+ // Cache the result
258
+ this.embeddingCache.set(cacheKey, embedding);
259
+
260
+ return embedding;
261
+ } catch (error) {
262
+ // Don't retry auth errors - they'll be thrown as OpenRouterAuthError
263
+ if (error instanceof OpenRouterAuthError) {
264
+ throw error;
265
+ }
266
+ // Don't retry rate limit errors with explicit retry-after
267
+ if (error instanceof OpenRouterRateLimitError && error.retryAfter) {
268
+ throw error;
269
+ }
270
+ lastError = error instanceof Error ? error : new Error(String(error));
271
+
272
+ // Don't retry if it's the last attempt or certain error types
273
+ if (attempt === this.maxRetries) {
274
+ break;
275
+ }
276
+
277
+ // Exponential backoff: wait longer with each attempt
278
+ const delay = this.baseRetryDelay * Math.pow(2, attempt);
279
+ await this.sleep(delay);
280
+ }
281
+ }
282
+
283
+ throw lastError || new OpenRouterError('OpenRouter API error: max retries exceeded', 'MAX_RETRIES');
284
+ }
285
+
286
+ /**
287
+ * Generate embeddings for multiple texts (batch)
288
+ */
289
+ async embedBatch(texts: string[]): Promise<number[][]> {
290
+ // Check cache for all texts
291
+ const uncachedTexts: string[] = [];
292
+ const uncachedIndices: number[] = [];
293
+ const results: (number[] | null)[] = texts.map((text, index) => {
294
+ const cacheKey = this.hashText(text);
295
+ if (this.embeddingCache.has(cacheKey)) {
296
+ return this.embeddingCache.get(cacheKey)!;
297
+ }
298
+ uncachedTexts.push(text);
299
+ uncachedIndices.push(index);
300
+ return null;
301
+ });
302
+
303
+ // If all cached, return immediately
304
+ if (uncachedTexts.length === 0) {
305
+ return results as number[][];
306
+ }
307
+
308
+ // Batch request to OpenRouter with retry
309
+ let lastError: Error | null = null;
310
+ let data: EmbeddingResponse | null = null;
311
+
312
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
313
+ try {
314
+ // Apply rate limiting before each attempt
315
+ await this.applyRateLimit();
316
+
317
+ const response = await this.fetchWithTimeout(OPENROUTER_EMBEDDINGS_URL, {
318
+ method: 'POST',
319
+ headers: {
320
+ 'Authorization': `Bearer ${this.apiKey}`,
321
+ 'Content-Type': 'application/json',
322
+ 'HTTP-Referer': this.siteUrl,
323
+ 'X-Title': this.siteName
324
+ },
325
+ body: JSON.stringify({
326
+ model: this.embeddingModel,
327
+ input: uncachedTexts
328
+ })
329
+ }, this.requestTimeout);
330
+
331
+ if (!response.ok) {
332
+ const error = await response.text();
333
+ // Don't retry auth errors
334
+ if (response.status === 401 || response.status === 403) {
335
+ throw new OpenRouterAuthError(`Authentication failed: ${error}`);
336
+ }
337
+ // Rate limit errors
338
+ if (response.status === 429) {
339
+ const retryAfter = response.headers.get('Retry-After');
340
+ throw new OpenRouterRateLimitError(
341
+ `Rate limit exceeded: ${error}`,
342
+ retryAfter ? parseInt(retryAfter, 10) : undefined
343
+ );
344
+ }
345
+ throw new OpenRouterError(`OpenRouter API error (${response.status}): ${error}`);
346
+ }
347
+
348
+ data = await response.json() as EmbeddingResponse;
349
+ break; // Success, exit retry loop
350
+ } catch (error) {
351
+ // Don't retry auth errors - they'll be thrown as OpenRouterAuthError
352
+ if (error instanceof OpenRouterAuthError) {
353
+ throw error;
354
+ }
355
+ // Don't retry rate limit errors with explicit retry-after
356
+ if (error instanceof OpenRouterRateLimitError && error.retryAfter) {
357
+ throw error;
358
+ }
359
+ lastError = error instanceof Error ? error : new Error(String(error));
360
+
361
+ if (attempt === this.maxRetries) {
362
+ break;
363
+ }
364
+
365
+ const delay = this.baseRetryDelay * Math.pow(2, attempt);
366
+ await this.sleep(delay);
367
+ }
368
+ }
369
+
370
+ if (!data) {
371
+ throw lastError || new OpenRouterError('OpenRouter API error: max retries exceeded', 'MAX_RETRIES');
372
+ }
373
+
374
+ // Fill in results and cache
375
+ for (let i = 0; i < data.data.length; i++) {
376
+ const embedding = data.data[i].embedding;
377
+ const originalIndex = uncachedIndices[i];
378
+ const text = uncachedTexts[i];
379
+
380
+ results[originalIndex] = embedding;
381
+ this.embeddingCache.set(this.hashText(text), embedding);
382
+ }
383
+
384
+ return results as number[][];
385
+ }
386
+
387
+ /**
388
+ * Chat completion - for intelligent context understanding
389
+ */
390
+ async chat(messages: ChatMessage[], options?: {
391
+ temperature?: number;
392
+ maxTokens?: number;
393
+ model?: string;
394
+ }): Promise<string> {
395
+ let lastError: Error | null = null;
396
+ let data: ChatResponse | null = null;
397
+
398
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
399
+ try {
400
+ // Apply rate limiting before each attempt
401
+ await this.applyRateLimit();
402
+
403
+ const response = await this.fetchWithTimeout(OPENROUTER_CHAT_URL, {
404
+ method: 'POST',
405
+ headers: {
406
+ 'Authorization': `Bearer ${this.apiKey}`,
407
+ 'Content-Type': 'application/json',
408
+ 'HTTP-Referer': this.siteUrl,
409
+ 'X-Title': this.siteName
410
+ },
411
+ body: JSON.stringify({
412
+ model: options?.model || this.chatModel,
413
+ messages,
414
+ temperature: options?.temperature ?? 0.3,
415
+ max_tokens: options?.maxTokens ?? 4096
416
+ })
417
+ }, this.requestTimeout);
418
+
419
+ if (!response.ok) {
420
+ const error = await response.text();
421
+ // Don't retry auth errors
422
+ if (response.status === 401 || response.status === 403) {
423
+ throw new OpenRouterAuthError(`Authentication failed: ${error}`);
424
+ }
425
+ // Rate limit errors
426
+ if (response.status === 429) {
427
+ const retryAfter = response.headers.get('Retry-After');
428
+ throw new OpenRouterRateLimitError(
429
+ `Rate limit exceeded: ${error}`,
430
+ retryAfter ? parseInt(retryAfter, 10) : undefined
431
+ );
432
+ }
433
+ throw new OpenRouterError(`OpenRouter Chat API error (${response.status}): ${error}`);
434
+ }
435
+
436
+ data = await response.json() as ChatResponse;
437
+ break; // Success, exit retry loop
438
+ } catch (error) {
439
+ // Don't retry auth errors - they'll be thrown as OpenRouterAuthError
440
+ if (error instanceof OpenRouterAuthError) {
441
+ throw error;
442
+ }
443
+ // Don't retry rate limit errors with explicit retry-after
444
+ if (error instanceof OpenRouterRateLimitError && error.retryAfter) {
445
+ throw error;
446
+ }
447
+ lastError = error instanceof Error ? error : new Error(String(error));
448
+
449
+ if (attempt === this.maxRetries) {
450
+ break;
451
+ }
452
+
453
+ const delay = this.baseRetryDelay * Math.pow(2, attempt);
454
+ await this.sleep(delay);
455
+ }
456
+ }
457
+
458
+ if (!data) {
459
+ throw lastError || new OpenRouterError('OpenRouter Chat API error: max retries exceeded', 'MAX_RETRIES');
460
+ }
461
+
462
+ const firstChoice = data?.choices && Array.isArray(data.choices) ? data.choices[0] : undefined;
463
+ const content = firstChoice?.message?.content;
464
+
465
+ if (typeof content !== 'string' || content.trim().length === 0) {
466
+ throw new Error('OpenRouter Chat API returned an unexpected response structure: missing or empty message content.');
467
+ }
468
+
469
+ return content;
470
+ }
471
+
472
+ /**
473
+ * Analyze codebase content intelligently
474
+ */
475
+ async analyzeContent(content: string, analysisType: 'summarize' | 'extract_workflows' | 'extract_architecture' | 'suggest_context'): Promise<string> {
476
+ const systemPrompts: Record<string, string> = {
477
+ summarize: `You are an expert code analyzer. Provide a concise summary of the given code or documentation.
478
+ Focus on: purpose, key functionality, dependencies, and important patterns.
479
+ Keep the summary under 500 words.`,
480
+
481
+ extract_workflows: `You are an expert at analyzing codebases to identify workflows.
482
+ Extract the main workflows from the given code. For each workflow, identify:
483
+ 1. Entry points (API routes, CLI commands, event handlers)
484
+ 2. Key processing steps
485
+ 3. Dependencies and integrations
486
+ 4. Data flow
487
+ Output as structured markdown with file:line references where possible.`,
488
+
489
+ extract_architecture: `You are an expert software architect.
490
+ Analyze the given code to extract the architecture patterns:
491
+ 1. Project structure and organization
492
+ 2. Design patterns used
493
+ 3. Key components and their responsibilities
494
+ 4. Integration points
495
+ 5. Technology stack
496
+ Output as structured markdown.`,
497
+
498
+ suggest_context: `You are an AI context engineering expert.
499
+ Analyze the given codebase content and suggest:
500
+ 1. Key context files that should be created
501
+ 2. Important workflows to document
502
+ 3. Agent configurations needed
503
+ 4. Commands that would be useful
504
+ 5. Knowledge base entries to capture
505
+ Be specific and actionable in your suggestions.`
506
+ };
507
+
508
+ return this.chat([
509
+ { role: 'system', content: systemPrompts[analysisType] },
510
+ { role: 'user', content }
511
+ ]);
512
+ }
513
+
514
+ /**
515
+ * Calculate cosine similarity between two embeddings
516
+ */
517
+ static cosineSimilarity(a: number[], b: number[]): number {
518
+ if (a.length !== b.length) {
519
+ throw new Error('Embeddings must have the same dimension');
520
+ }
521
+
522
+ let dotProduct = 0;
523
+ let normA = 0;
524
+ let normB = 0;
525
+
526
+ for (let i = 0; i < a.length; i++) {
527
+ dotProduct += a[i] * b[i];
528
+ normA += a[i] * a[i];
529
+ normB += b[i] * b[i];
530
+ }
531
+
532
+ const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
533
+ if (magnitude === 0) return 0;
534
+
535
+ return dotProduct / magnitude;
536
+ }
537
+
538
+ /**
539
+ * Get embedding dimension
540
+ */
541
+ getDimension(): number {
542
+ return EMBEDDING_DIMENSION;
543
+ }
544
+
545
+ /**
546
+ * Clear embedding cache
547
+ */
548
+ clearCache(): void {
549
+ this.embeddingCache.clear();
550
+ }
551
+
552
+ /**
553
+ * Get cache size
554
+ */
555
+ getCacheSize(): number {
556
+ return this.embeddingCache.size;
557
+ }
558
+
559
+ /**
560
+ * Hash text for caching
561
+ */
562
+ private hashText(text: string): string {
563
+ return createHash('md5').update(text).digest('hex');
564
+ }
565
+ }
566
+
567
+ /**
568
+ * Create OpenRouter client from environment
569
+ */
570
+ export function createOpenRouterClient(): OpenRouterClient {
571
+ const apiKey = process.env.OPENROUTER_API_KEY;
572
+
573
+ if (!apiKey) {
574
+ throw new Error(
575
+ 'OPENROUTER_API_KEY environment variable is required.\n' +
576
+ 'Get your API key at: https://openrouter.ai/keys'
577
+ );
578
+ }
579
+
580
+ return new OpenRouterClient({
581
+ apiKey,
582
+ embeddingModel: process.env.OPENROUTER_EMBEDDING_MODEL,
583
+ chatModel: process.env.OPENROUTER_CHAT_MODEL
584
+ });
585
+ }
586
+
587
+ /**
588
+ * Check if OpenRouter API key is available
589
+ */
590
+ export function hasOpenRouterKey(): boolean {
591
+ return !!process.env.OPENROUTER_API_KEY;
592
+ }
package/src/index.ts ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * AI Context
3
+ *
4
+ * Unified AI Context Engineering package.
5
+ * Provides intelligent context for all AI coding assistants.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+
10
+ // Database
11
+ export {
12
+ DatabaseClient,
13
+ type ContextItem,
14
+ type GraphEdge,
15
+ type GitCommit,
16
+ type SyncState,
17
+ type AIToolConfig,
18
+ type SearchResult
19
+ } from './db/client.js';
20
+
21
+ export {
22
+ SCHEMA_VERSION,
23
+ RELATION_TYPES,
24
+ CONTEXT_TYPES,
25
+ SYNC_STATUSES,
26
+ AI_TOOLS,
27
+ AI_TOOL_FOLDERS,
28
+ type RelationType,
29
+ type ContextType,
30
+ type SyncStatus,
31
+ type AITool
32
+ } from './db/schema.js';
33
+
34
+ // OpenRouter / Embeddings
35
+ export {
36
+ OpenRouterClient,
37
+ createOpenRouterClient,
38
+ hasOpenRouterKey,
39
+ type OpenRouterConfig,
40
+ type ChatMessage
41
+ } from './embeddings/openrouter.js';
42
+
43
+ // Analyzer
44
+ export {
45
+ IntelligentAnalyzer,
46
+ createIntelligentAnalyzer,
47
+ type DiscoveredFile,
48
+ type AnalysisResult
49
+ } from './analyzer/intelligent-analyzer.js';
50
+
51
+ // MCP Server
52
+ export {
53
+ createServer,
54
+ startServer,
55
+ main as startMcpServer,
56
+ type ServerConfig
57
+ } from './mcp.js';