capman 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,55 +1,44 @@
1
- # Capman — Capability Manifest Engine
1
+ # capman
2
2
 
3
- Let AI agents interact with your app **without navigating the UI**.
3
+ **Capability Manifest Engine** — let AI agents interact with your app reliably and explainably.
4
4
 
5
- Instead of an AI blindly clicking through screens to find information,
6
- capman lets your app declare what it can do — and the AI uses that map
7
- to get answers directly.
5
+ Instead of an AI blindly clicking through screens, capman gives it a structured map of what your app can do — and shows you exactly why it made every decision.
6
+
7
+ ```bash
8
+ npm install capman
9
+ ```
8
10
 
9
11
  ---
10
12
 
11
13
  ## The Problem
12
14
 
13
- When an AI agent needs to answer "are there available seats for Friday?",
14
- today it navigates your entire app like a tourist with no map:
15
+ When an AI agent answers *"are there seats available Friday?"*, today it navigates your app like a tourist with no map:
15
16
 
16
17
  ```
17
- AI clicks → Home → Explore → Events → Category → Detail → Availability
18
+ AI clicks → Home → Explore → Events → Category → Availability
18
19
  ```
19
20
 
20
- That's slow, wasteful, and exposes parts of your app the AI shouldn't see.
21
+ Slow. Wasteful. Touches screens it shouldn't.
21
22
 
22
23
  ## The Solution
23
24
 
24
- Your app publishes a **capability manifest** — a machine-readable list of
25
- everything it can do, what API to call, and what data scope is allowed.
26
-
27
- The AI reads the manifest and goes directly to the answer.
25
+ Your app publishes a **capability manifest** — a machine-readable list of everything it can do, what API to call, and what data is allowed. The AI reads the manifest and goes directly to the answer.
28
26
 
29
27
  ```
30
- User query → match capability → resolve via API or nav → done
31
- ```
32
-
33
- ---
34
-
35
- ## Install
36
-
37
- ```bash
38
- npm install capman
28
+ User query → match capability → resolve via API or nav → structured result
39
29
  ```
40
30
 
41
31
  ---
42
32
 
43
33
  ## Quick Start
44
34
 
45
- **1. Create a config file**
35
+ **1. Create your manifest config**
46
36
 
47
37
  ```bash
48
38
  npx capman init
49
39
  ```
50
40
 
51
- This creates a `capman.config.js` in your project. Edit it to define
52
- your app's capabilities.
41
+ Edit `capman.config.js` to define your app's capabilities.
53
42
 
54
43
  **2. Generate the manifest**
55
44
 
@@ -57,122 +46,248 @@ your app's capabilities.
57
46
  npx capman generate
58
47
  ```
59
48
 
60
- This reads your config and outputs a `manifest.json`.
61
-
62
- **3. Use the SDK in your AI agent**
49
+ **3. Use the engine in your AI agent**
63
50
 
64
51
  ```typescript
65
- import { match, resolve, readManifest } from 'capman'
52
+ import { CapmanEngine, readManifest } from 'capman'
66
53
 
67
54
  const manifest = readManifest()
68
55
 
69
- // Match a user query to a capability
70
- const matchResult = match("show me my account details", manifest)
71
-
72
- // Resolve it
73
- const result = await resolve(matchResult, {}, {
74
- baseUrl: 'https://api.your-app.com'
56
+ const engine = new CapmanEngine({
57
+ manifest,
58
+ baseUrl: 'https://api.your-app.com',
75
59
  })
76
60
 
77
- console.log(result.apiCalls) // [{ method: 'GET', url: '...' }]
78
- console.log(result.navTarget) // '/dashboard/profile'
61
+ const result = await engine.ask('Check availability for blue jacket')
62
+
63
+ console.log(result.match.capability?.id) // 'check_product_availability'
64
+ console.log(result.resolution.apiCalls) // [{ method: 'GET', url: '...' }]
65
+ console.log(result.resolvedVia) // 'keyword' | 'llm' | 'cache'
66
+ console.log(result.trace.reasoning) // ['Matched "check_product_availability" with 100% confidence', ...]
67
+ ```
68
+
69
+ **4. See it live**
70
+
71
+ ```bash
72
+ npx capman demo
79
73
  ```
80
74
 
81
75
  ---
82
76
 
83
- ## CLI Commands
77
+ ## Execution Trace
84
78
 
85
- | Command | What it does |
86
- |---|---|
87
- | `capman init` | Create a starter `capman.config.js` |
88
- | `capman generate` | Generate `manifest.json` from config |
89
- | `capman validate` | Validate your manifest for errors |
90
- | `capman inspect` | Print all capabilities in the manifest |
79
+ Every `engine.ask()` call returns a full execution trace — so you always know why the AI did what it did.
80
+
81
+ ```typescript
82
+ const result = await engine.ask('Check availability for blue jacket')
83
+
84
+ console.log(result.trace)
85
+ // {
86
+ // query: 'Check availability for blue jacket',
87
+ // candidates: [
88
+ // { capabilityId: 'check_product_availability', score: 100, matched: true },
89
+ // { capabilityId: 'get_order_status', score: 12, matched: false },
90
+ // { capabilityId: 'navigate_to_screen', score: 0, matched: false },
91
+ // ],
92
+ // reasoning: [
93
+ // 'Matched "check_product_availability" with 100% confidence',
94
+ // 'Rejected: get_order_status (12%)',
95
+ // 'Resolved via: keyword',
96
+ // 'Extracted params: product=blue-jacket',
97
+ // ],
98
+ // steps: [
99
+ // { type: 'cache_check', status: 'miss', durationMs: 0 },
100
+ // { type: 'keyword_match', status: 'pass', durationMs: 1, detail: 'confidence: 100%' },
101
+ // { type: 'privacy_check', status: 'pass', durationMs: 0, detail: 'level: public' },
102
+ // { type: 'resolve', status: 'pass', durationMs: 2, detail: 'via api' },
103
+ // ],
104
+ // resolvedVia: 'keyword',
105
+ // totalMs: 4,
106
+ // }
107
+ ```
108
+
109
+ Debug any query from the CLI:
110
+
111
+ ```bash
112
+ npx capman run "check availability for blue jacket" --debug
113
+ ```
114
+
115
+ ```
116
+ ✓ Matched: check_product_availability
117
+ Intent: retrieval
118
+ Confidence: 100%
119
+ Resolver: api
120
+ Params: product=blue-jacket
121
+
122
+ ── All candidates:
123
+ ✓ check_product_availability: 100%
124
+ ○ get_order_status: 12%
125
+ ○ navigate_to_screen: 0%
126
+ ```
91
127
 
92
128
  ---
93
129
 
94
- ## SDK Reference
130
+ ## Matching Modes
95
131
 
96
- ### `match(query, manifest)`
97
- Matches a user query to the best capability using keyword scoring.
98
- Returns a `MatchResult` with the capability, confidence score, and intent.
132
+ Control the cost/accuracy tradeoff with three matching modes:
99
133
 
100
- ### `matchWithLLM(query, manifest, { llm })`
101
- Same as `match()` but uses an LLM for higher accuracy on ambiguous queries.
102
- Pass in any LLM function — works with Anthropic, OpenAI, or any local model.
134
+ ```typescript
135
+ // cheap keyword only, no LLM, free
136
+ const engine = new CapmanEngine({ manifest, mode: 'cheap' })
137
+
138
+ // balanced — keyword first, LLM fallback if confidence < 50% (default)
139
+ const engine = new CapmanEngine({ manifest, mode: 'balanced', llm: myLLM })
140
+
141
+ // accurate — LLM first, keyword fallback
142
+ const engine = new CapmanEngine({ manifest, mode: 'accurate', llm: myLLM })
143
+ ```
144
+
145
+ Pass any LLM function — works with Anthropic, OpenAI, or any model:
103
146
 
104
147
  ```typescript
105
- const result = await matchWithLLM("find me something", manifest, {
148
+ import Anthropic from '@anthropic-ai/sdk'
149
+ const anthropic = new Anthropic()
150
+
151
+ const engine = new CapmanEngine({
152
+ manifest,
153
+ mode: 'balanced',
106
154
  llm: async (prompt) => {
107
155
  const res = await anthropic.messages.create({
108
156
  model: 'claude-sonnet-4-20250514',
109
157
  max_tokens: 500,
110
- messages: [{ role: 'user', content: prompt }]
158
+ messages: [{ role: 'user', content: prompt }],
111
159
  })
112
160
  return res.content[0].text
113
- }
161
+ },
114
162
  })
115
163
  ```
116
164
 
117
- ### `resolve(matchResult, params, options)`
118
- Executes a matched capability via API call, navigation, or both.
165
+ ---
119
166
 
120
- ### `ask(query, manifest, options)`
121
- Convenience function — match + resolve in one call.
167
+ ## Caching + Learning
122
168
 
123
169
  ```typescript
124
- const { match, resolution } = await ask("go to settings", manifest)
170
+ import { CapmanEngine, FileCache, FileLearningStore } from 'capman'
171
+
172
+ const engine = new CapmanEngine({
173
+ manifest,
174
+ // Default: MemoryCache (fast, resets on restart)
175
+ // For persistence across restarts:
176
+ cache: new FileCache('.capman/cache.json'),
177
+ learning: new FileLearningStore('.capman/learning.json'),
178
+ })
179
+
180
+ // After real usage, see what's happening
181
+ const stats = await engine.getStats()
182
+ console.log(stats)
183
+ // {
184
+ // totalQueries: 142,
185
+ // llmQueries: 18,
186
+ // cacheHits: 67,
187
+ // outOfScope: 3,
188
+ // index: { 'availability': { 'check_product_availability': 34 }, ... }
189
+ // }
190
+
191
+ const top = await engine.getTopCapabilities(3)
192
+ // [
193
+ // { id: 'check_product_availability', hits: 58 },
194
+ // { id: 'navigate_to_screen', hits: 41 },
195
+ // { id: 'get_order_status', hits: 28 },
196
+ // ]
197
+ ```
198
+
199
+ ---
200
+
201
+ ## Privacy + Auth
202
+
203
+ Privacy scope is enforced **per capability**, before resolution happens:
204
+
205
+ ```typescript
206
+ const engine = new CapmanEngine({
207
+ manifest,
208
+ baseUrl: 'https://api.your-app.com',
209
+ auth: {
210
+ isAuthenticated: true,
211
+ role: 'user',
212
+ userId: 'user-123', // auto-injected into session params
213
+ },
214
+ })
215
+
216
+ // user_owned capabilities require auth — blocked without it
217
+ // admin capabilities require role: 'admin' — blocked for regular users
218
+ // session params like {user_id} are auto-replaced from auth.userId
219
+ ```
220
+
221
+ ---
222
+
223
+ ## Resolver Hardening
224
+
225
+ Configure retries and timeouts per call:
226
+
227
+ ```typescript
228
+ const result = await engine.ask('show my orders', {
229
+ retries: 2, // retry failed requests (default: 0)
230
+ timeoutMs: 3000, // abort after 3 seconds (default: 5000)
231
+ })
125
232
  ```
126
233
 
127
234
  ---
128
235
 
129
236
  ## Capability Config
130
237
 
131
- Each capability in your `capman.config.js` looks like this:
238
+ Each capability in `capman.config.js`:
132
239
 
133
240
  ```javascript
134
- {
135
- id: 'get_resource',
136
- name: 'Get a resource',
137
- description: 'Fetch a resource by ID or name.', // used for matching
138
- examples: [ // improves accuracy
139
- 'Show me resource details',
140
- 'Find resource by ID',
141
- ],
142
- params: [
241
+ module.exports = {
242
+ app: 'your-app',
243
+ baseUrl: 'https://api.your-app.com',
244
+ capabilities: [
143
245
  {
144
- name: 'resource_id',
145
- description: 'The resource ID',
146
- required: true,
147
- source: 'user_query', // or 'session', 'context', 'static'
148
- }
246
+ id: 'check_product_availability',
247
+ name: 'Check product availability',
248
+ description: 'Check stock and pricing for a product by name or ID.',
249
+ examples: [
250
+ 'Is the blue jacket available?',
251
+ 'Check availability for product 42',
252
+ 'Do you have size M in stock?',
253
+ ],
254
+ params: [
255
+ {
256
+ name: 'product',
257
+ description: 'Product name or ID',
258
+ required: true,
259
+ source: 'user_query', // extracted from the query
260
+ },
261
+ ],
262
+ returns: ['stock', 'price', 'variants'],
263
+ resolver: {
264
+ type: 'api', // 'api' | 'nav' | 'hybrid'
265
+ endpoints: [
266
+ { method: 'GET', path: '/products/{product}/availability' },
267
+ ],
268
+ },
269
+ privacy: {
270
+ level: 'public', // 'public' | 'user_owned' | 'admin'
271
+ note: 'No auth required',
272
+ },
273
+ },
149
274
  ],
150
- returns: ['resource', 'metadata'],
151
- resolver: {
152
- type: 'api', // 'api', 'nav', or 'hybrid'
153
- endpoints: [
154
- { method: 'GET', path: '/resources/{resource_id}' }
155
- ],
156
- },
157
- privacy: {
158
- level: 'public', // 'public', 'user_owned', or 'admin'
159
- note: 'No auth required'
160
- }
161
275
  }
162
276
  ```
163
277
 
164
278
  ---
165
279
 
166
- ## Privacy Scopes
280
+ ## CLI Commands
167
281
 
168
- | Level | Meaning |
282
+ | Command | What it does |
169
283
  |---|---|
170
- | `public` | No auth required |
171
- | `user_owned` | Requires auth, scoped to current user only |
172
- | `admin` | Restricted to admin roles |
173
-
174
- Privacy scope is declared **per capability** the AI is scoped to only
175
- what each capability allows, before resolution happens.
284
+ | `capman init` | Create a starter `capman.config.js` |
285
+ | `capman generate` | Generate `manifest.json` from config |
286
+ | `capman validate` | Validate your manifest for errors |
287
+ | `capman inspect` | Print all capabilities in the manifest |
288
+ | `capman run "query"` | Run a query against your manifest |
289
+ | `capman run "query" --debug` | Run with full candidate scoring |
290
+ | `capman demo` | Live demo with a sample app |
176
291
 
177
292
  ---
178
293
 
@@ -186,23 +301,45 @@ what each capability allows, before resolution happens.
186
301
 
187
302
  ---
188
303
 
304
+ ## Privacy Scopes
305
+
306
+ | Level | Meaning |
307
+ |---|---|
308
+ | `public` | No auth required |
309
+ | `user_owned` | Requires auth, scoped to current user only |
310
+ | `admin` | Restricted to admin roles |
311
+
312
+ ---
313
+
314
+ ## Param Sources
315
+
316
+ | Source | Meaning |
317
+ |---|---|
318
+ | `user_query` | Extracted from the user's query |
319
+ | `session` | Injected from `auth.userId` automatically |
320
+ | `context` | Provided by the caller |
321
+ | `static` | Fixed value, never changes |
322
+
323
+ ---
324
+
189
325
  ## Honest Limits
190
326
 
191
327
  **Works well:**
192
328
  - Structured data retrieval via APIs
193
329
  - Navigating to known app screens
194
330
  - Multi-endpoint aggregation
195
- - Privacy scoping per capability
196
- - Auto-updating on deploy
331
+ - Privacy enforcement per capability
332
+ - Caching repeated queries
333
+ - Full execution tracing and debugging
197
334
 
198
335
  **Current limits:**
199
336
  - Real-time infra status (is the server down?)
200
337
  - UI-only state with no API backing
201
- - Cross-app orchestration
202
- - Very ambiguous queries without LLM matcher
338
+ - Very ambiguous queries — use `mode: 'accurate'` with an LLM
339
+ - Cross-app orchestration (planned)
203
340
 
204
341
  ---
205
342
 
206
343
  ## License
207
344
 
208
- MIT
345
+ MIT — [github.com/Hobbydefiningdoctory/capman](https://github.com/Hobbydefiningdoctory/capman)
package/bin/capman.js CHANGED
File without changes
@@ -6,15 +6,23 @@ export interface CacheEntry {
6
6
  hits: number;
7
7
  }
8
8
  export interface CacheStore {
9
- get(query: string): Promise<CacheEntry | null>;
10
- set(query: string, result: MatchResult): Promise<void>;
9
+ get(key: string): Promise<CacheEntry | null>;
10
+ set(key: string, result: MatchResult): Promise<void>;
11
11
  clear(): Promise<void>;
12
12
  size(): Promise<number>;
13
13
  }
14
+ export declare function normalizeQuery(query: string): string;
15
+ /**
16
+ * Build a smarter cache key based on matched capability + extracted params.
17
+ * Two different queries that resolve to the same capability with the same params
18
+ * will share a cache entry — dramatically improving hit rate.
19
+ * Falls back to normalized query if no capability matched.
20
+ */
21
+ export declare function buildCacheKey(query: string, capabilityId: string | null, extractedParams: Record<string, string | null>): string;
14
22
  export declare class MemoryCache implements CacheStore {
15
23
  private store;
16
- get(query: string): Promise<CacheEntry | null>;
17
- set(query: string, result: MatchResult): Promise<void>;
24
+ get(key: string): Promise<CacheEntry | null>;
25
+ set(key: string, result: MatchResult): Promise<void>;
18
26
  clear(): Promise<void>;
19
27
  size(): Promise<number>;
20
28
  }
@@ -25,8 +33,8 @@ export declare class FileCache implements CacheStore {
25
33
  constructor(filePath?: string);
26
34
  private load;
27
35
  private save;
28
- get(query: string): Promise<CacheEntry | null>;
29
- set(query: string, result: MatchResult): Promise<void>;
36
+ get(key: string): Promise<CacheEntry | null>;
37
+ set(key: string, result: MatchResult): Promise<void>;
30
38
  clear(): Promise<void>;
31
39
  size(): Promise<number>;
32
40
  }
@@ -34,8 +42,8 @@ export declare class ComboCache implements CacheStore {
34
42
  private memory;
35
43
  private file;
36
44
  constructor(filePath?: string);
37
- get(query: string): Promise<CacheEntry | null>;
38
- set(query: string, result: MatchResult): Promise<void>;
45
+ get(key: string): Promise<CacheEntry | null>;
46
+ set(key: string, result: MatchResult): Promise<void>;
39
47
  clear(): Promise<void>;
40
48
  size(): Promise<number>;
41
49
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAK1C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,WAAW,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;CACb;AAID,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAA;IAC9C,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACtD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;CACxB;AAUD,qBAAa,WAAY,YAAW,UAAU;IAC5C,OAAO,CAAC,KAAK,CAAgC;IAEvC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAW9C,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAWtD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;CAG9B;AAID,qBAAa,SAAU,YAAW,UAAU;IAC1C,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,MAAM,CAAQ;gBAEV,QAAQ,SAAuB;YAK7B,IAAI;YAYJ,IAAI;IAaZ,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAY9C,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAatD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;CAI9B;AAID,qBAAa,UAAW,YAAW,UAAU;IAC3C,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,IAAI,CAAW;gBAEX,QAAQ,SAAuB;IAKrC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAiB9C,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAOtD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;CAG9B"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAK1C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,WAAW,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;CACb;AAID,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAA;IAC5C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;CACxB;AAID,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;;GAKG;AAEH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,GAC7C,MAAM,CAQR;AAMD,qBAAa,WAAY,YAAW,UAAU;IAC5C,OAAO,CAAC,KAAK,CAAgC;IAEvC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAU5C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAepD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IACtB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;CAC9B;AAID,qBAAa,SAAU,YAAW,UAAU;IAC1C,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,MAAM,CAAQ;gBAEV,QAAQ,SAAuB;YAK7B,IAAI;YAYJ,IAAI;IAaZ,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAW5C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAYpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;CAI9B;AAID,qBAAa,UAAW,YAAW,UAAU;IAC3C,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,IAAI,CAAW;gBAEX,QAAQ,SAAuB;IAKrC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAY5C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAOpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;CAG9B"}
package/dist/cjs/cache.js CHANGED
@@ -34,6 +34,8 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.ComboCache = exports.FileCache = exports.MemoryCache = void 0;
37
+ exports.normalizeQuery = normalizeQuery;
38
+ exports.buildCacheKey = buildCacheKey;
37
39
  const fs = __importStar(require("fs"));
38
40
  const path = __importStar(require("path"));
39
41
  const logger_1 = require("./logger");
@@ -41,37 +43,54 @@ const logger_1 = require("./logger");
41
43
  function normalizeQuery(query) {
42
44
  return query.toLowerCase().trim().replace(/\s+/g, ' ');
43
45
  }
46
+ /**
47
+ * Build a smarter cache key based on matched capability + extracted params.
48
+ * Two different queries that resolve to the same capability with the same params
49
+ * will share a cache entry — dramatically improving hit rate.
50
+ * Falls back to normalized query if no capability matched.
51
+ */
52
+ function buildCacheKey(query, capabilityId, extractedParams) {
53
+ if (!capabilityId)
54
+ return `query:${normalizeQuery(query)}`;
55
+ const paramStr = Object.entries(extractedParams)
56
+ .filter(([, v]) => v !== null)
57
+ .sort(([a], [b]) => a.localeCompare(b))
58
+ .map(([k, v]) => `${k}=${v}`)
59
+ .join('&');
60
+ return `cap:${capabilityId}${paramStr ? `:${paramStr}` : ''}`;
61
+ }
44
62
  // ─── Memory Cache ─────────────────────────────────────────────────────────────
63
+ const MEMORY_CACHE_MAX = 512;
45
64
  class MemoryCache {
46
65
  constructor() {
47
66
  this.store = new Map();
48
67
  }
49
- async get(query) {
50
- const key = normalizeQuery(query);
68
+ async get(key) {
51
69
  const entry = this.store.get(key);
52
70
  if (entry) {
53
71
  entry.hits++;
54
- logger_1.logger.debug(`Cache hit (memory): "${query}"`);
72
+ logger_1.logger.debug(`Cache hit (memory): "${key}"`);
55
73
  return entry;
56
74
  }
57
75
  return null;
58
76
  }
59
- async set(query, result) {
60
- const key = normalizeQuery(query);
77
+ async set(key, result) {
78
+ if (this.store.size >= MEMORY_CACHE_MAX) {
79
+ const oldest = this.store.keys().next().value;
80
+ if (oldest !== undefined)
81
+ this.store.delete(oldest);
82
+ logger_1.logger.debug(`Cache evicted oldest entry (max size ${MEMORY_CACHE_MAX} reached)`);
83
+ }
61
84
  this.store.set(key, {
62
- query,
85
+ query: key,
63
86
  result,
64
87
  cachedAt: new Date().toISOString(),
65
88
  hits: 0,
66
89
  });
67
- logger_1.logger.debug(`Cache set (memory): "${query}"`);
68
- }
69
- async clear() {
70
- this.store.clear();
71
- }
72
- async size() {
73
- return this.store.size;
90
+ logger_1.logger.debug(`Cache set (memory): "${key}"`);
74
91
  }
92
+ async clear() { this.store.clear(); }
93
+ async size() { return this.store.size; }
75
94
  }
76
95
  exports.MemoryCache = MemoryCache;
77
96
  // ─── File Cache ───────────────────────────────────────────────────────────────
@@ -105,28 +124,26 @@ class FileCache {
105
124
  logger_1.logger.warn(`Failed to save file cache to ${this.filePath}`);
106
125
  }
107
126
  }
108
- async get(query) {
127
+ async get(key) {
109
128
  await this.load();
110
- const key = normalizeQuery(query);
111
129
  const entry = this.store.get(key);
112
130
  if (entry) {
113
131
  entry.hits++;
114
- logger_1.logger.debug(`Cache hit (file): "${query}"`);
132
+ logger_1.logger.debug(`Cache hit (file): "${key}"`);
115
133
  return entry;
116
134
  }
117
135
  return null;
118
136
  }
119
- async set(query, result) {
137
+ async set(key, result) {
120
138
  await this.load();
121
- const key = normalizeQuery(query);
122
139
  this.store.set(key, {
123
- query,
140
+ query: key,
124
141
  result,
125
142
  cachedAt: new Date().toISOString(),
126
143
  hits: 0,
127
144
  });
128
145
  await this.save();
129
- logger_1.logger.debug(`Cache set (file): "${query}"`);
146
+ logger_1.logger.debug(`Cache set (file): "${key}"`);
130
147
  }
131
148
  async clear() {
132
149
  this.store.clear();
@@ -144,25 +161,22 @@ class ComboCache {
144
161
  this.memory = new MemoryCache();
145
162
  this.file = new FileCache(filePath);
146
163
  }
147
- async get(query) {
148
- // Memory first fastest
149
- const memHit = await this.memory.get(query);
164
+ async get(key) {
165
+ const memHit = await this.memory.get(key);
150
166
  if (memHit)
151
167
  return memHit;
152
- // File fallback persists across restarts
153
- const fileHit = await this.file.get(query);
168
+ const fileHit = await this.file.get(key);
154
169
  if (fileHit) {
155
- // Promote to memory for next time
156
- await this.memory.set(query, fileHit.result);
157
- logger_1.logger.debug(`Cache promoted to memory: "${query}"`);
170
+ await this.memory.set(key, fileHit.result);
171
+ logger_1.logger.debug(`Cache promoted to memory: "${key}"`);
158
172
  return fileHit;
159
173
  }
160
174
  return null;
161
175
  }
162
- async set(query, result) {
176
+ async set(key, result) {
163
177
  await Promise.all([
164
- this.memory.set(query, result),
165
- this.file.set(query, result),
178
+ this.memory.set(key, result),
179
+ this.file.set(key, result),
166
180
  ]);
167
181
  }
168
182
  async clear() {
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"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"}