capman 0.2.0 → 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 (42) hide show
  1. package/bin/capman.js +221 -5
  2. package/dist/cjs/cache.d.ts +42 -0
  3. package/dist/cjs/cache.d.ts.map +1 -0
  4. package/dist/cjs/cache.js +179 -0
  5. package/dist/cjs/cache.js.map +1 -0
  6. package/dist/cjs/engine.d.ts +82 -0
  7. package/dist/cjs/engine.d.ts.map +1 -0
  8. package/dist/cjs/engine.js +233 -0
  9. package/dist/cjs/engine.js.map +1 -0
  10. package/dist/cjs/generator.js +2 -1
  11. package/dist/cjs/generator.js.map +1 -1
  12. package/dist/cjs/index.d.ts +7 -1
  13. package/dist/cjs/index.d.ts.map +1 -1
  14. package/dist/cjs/index.js +13 -1
  15. package/dist/cjs/index.js.map +1 -1
  16. package/dist/cjs/learning.d.ts +56 -0
  17. package/dist/cjs/learning.d.ts.map +1 -0
  18. package/dist/cjs/learning.js +155 -0
  19. package/dist/cjs/learning.js.map +1 -0
  20. package/dist/cjs/matcher.d.ts.map +1 -1
  21. package/dist/cjs/matcher.js +38 -5
  22. package/dist/cjs/matcher.js.map +1 -1
  23. package/dist/cjs/resolver.d.ts +4 -1
  24. package/dist/cjs/resolver.d.ts.map +1 -1
  25. package/dist/cjs/resolver.js +51 -21
  26. package/dist/cjs/resolver.js.map +1 -1
  27. package/dist/cjs/schema.d.ts +10 -10
  28. package/dist/cjs/types.d.ts +38 -5
  29. package/dist/cjs/types.d.ts.map +1 -1
  30. package/dist/cjs/version.d.ts +2 -0
  31. package/dist/cjs/version.d.ts.map +1 -0
  32. package/dist/cjs/version.js +6 -0
  33. package/dist/cjs/version.js.map +1 -0
  34. package/dist/esm/cache.js +139 -0
  35. package/dist/esm/engine.js +228 -0
  36. package/dist/esm/generator.js +2 -1
  37. package/dist/esm/index.js +6 -0
  38. package/dist/esm/learning.js +116 -0
  39. package/dist/esm/matcher.js +38 -5
  40. package/dist/esm/resolver.js +51 -21
  41. package/dist/esm/version.js +2 -0
  42. package/package.json +18 -12
package/bin/capman.js CHANGED
@@ -32,8 +32,9 @@ const log = {
32
32
  }
33
33
 
34
34
  function header() {
35
+ const pkg = require(path.join(__dirname, '..', 'package.json'))
35
36
  console.log()
36
- console.log(`${c.bold}${c.teal} capman${c.reset} ${c.gray}v0.1.0 — Capability Manifest Engine${c.reset}`)
37
+ console.log(`${c.bold}${c.teal} capman${c.reset} ${c.gray}v${pkg.version} — Capability Manifest Engine${c.reset}`)
37
38
  console.log(`${c.gray} ─────────────────────────────────────────${c.reset}`)
38
39
  console.log()
39
40
  }
@@ -42,13 +43,20 @@ function requireSrc() {
42
43
  const distPath = path.join(__dirname, '..', 'dist', 'cjs', 'index.js')
43
44
  if (fs.existsSync(distPath)) return require(distPath)
44
45
 
46
+ // dist not built — try to build automatically
47
+ log.info('dist/cjs not found — running build...')
45
48
  try {
46
- require('ts-node/register')
47
- return require(path.join(__dirname, '..', 'src', 'index.ts'))
49
+ require('child_process').execSync('npm run build', {
50
+ cwd: path.join(__dirname, '..'),
51
+ stdio: 'inherit'
52
+ })
53
+ if (fs.existsSync(distPath)) return require(distPath)
48
54
  } catch {
49
- log.error('Cannot find dist/cjs/. Run: pnpm run build')
50
- process.exit(1)
55
+ // build failed
51
56
  }
57
+
58
+ log.error('Cannot find dist/cjs/. Run: pnpm run build')
59
+ process.exit(1)
52
60
  }
53
61
 
54
62
  function cmdHelp() {
@@ -60,11 +68,14 @@ function cmdHelp() {
60
68
  console.log(` ${c.teal}generate${c.reset} Generate manifest.json from config`)
61
69
  console.log(` ${c.teal}validate${c.reset} Validate an existing manifest.json`)
62
70
  console.log(` ${c.teal}inspect${c.reset} Print all capabilities in manifest`)
71
+ console.log(` ${c.teal}demo${c.reset} Run a live demo with sample queries`)
72
+ console.log(` ${c.teal}run${c.reset} Run a query against your manifest`)
63
73
  console.log()
64
74
  console.log(`${c.bold} Options:${c.reset}`)
65
75
  console.log(` ${c.gray}--config Path to config file (default: capman.config.js)${c.reset}`)
66
76
  console.log(` ${c.gray}--out Output path (default: manifest.json)${c.reset}`)
67
77
  console.log(` ${c.gray}--manifest Manifest to read (default: manifest.json)${c.reset}`)
78
+ console.log(` ${c.gray}Options: --debug (show all candidates)${c.reset}`)
68
79
  console.log()
69
80
  }
70
81
 
@@ -176,11 +187,216 @@ function cmdInspect() {
176
187
  }
177
188
  }
178
189
 
190
+ function cmdDemo() {
191
+ header()
192
+ const { generate, match, resolve } = requireSrc()
193
+
194
+ console.log(`${c.bold} Live demo — see capman in action${c.reset}`)
195
+ console.log(`${c.gray} ─────────────────────────────────────────${c.reset}\n`)
196
+
197
+ // Demo manifest — generic e-commerce app
198
+ const config = {
199
+ app: 'demo-store',
200
+ baseUrl: 'https://api.demo-store.com',
201
+ capabilities: [
202
+ {
203
+ id: 'check_product_availability',
204
+ name: 'Check product availability',
205
+ description: 'Check stock and pricing for a product by name or ID.',
206
+ examples: [
207
+ 'Is the blue jacket in stock?',
208
+ 'Check stock for blue jacket',
209
+ 'Do you have size M available?',
210
+ 'Product availability for jacket',
211
+ 'Is jacket available?',
212
+ ],
213
+ params: [
214
+ { name: 'product', description: 'Product name or ID', required: true, source: 'user_query' }
215
+ ],
216
+ returns: ['stock', 'price', 'variants'],
217
+ resolver: { type: 'api', endpoints: [{ method: 'GET', path: '/products/{product}/availability' }] },
218
+ privacy: { level: 'public' },
219
+ },
220
+ {
221
+ id: 'get_order_status',
222
+ name: 'Get order status',
223
+ description: 'Retrieve the current status and tracking info for an order.',
224
+ examples: [
225
+ 'Where is my order?',
226
+ 'Track order 1234',
227
+ 'What is the status of my recent purchase?',
228
+ ],
229
+ params: [
230
+ { name: 'order_id', description: 'Order ID', required: true, source: 'user_query' }
231
+ ],
232
+ returns: ['status', 'tracking', 'estimated_delivery'],
233
+ resolver: { type: 'api', endpoints: [{ method: 'GET', path: '/orders/{order_id}' }] },
234
+ privacy: { level: 'user_owned' },
235
+ },
236
+ {
237
+ id: 'navigate_to_screen',
238
+ name: 'Navigate to screen',
239
+ description: 'Route the user to a specific page in the store.',
240
+ examples: [
241
+ 'Take me to cart',
242
+ 'Open cart',
243
+ 'Go to checkout',
244
+ 'Navigate to account',
245
+ 'Show homepage',
246
+ ],
247
+ params: [
248
+ { name: 'destination', description: 'Target screen', required: true, source: 'user_query' }
249
+ ],
250
+ returns: ['deep_link'],
251
+ resolver: { type: 'nav', destination: '/{destination}' },
252
+ privacy: { level: 'public' },
253
+ },
254
+ ],
255
+ }
256
+
257
+ const manifest = generate(config)
258
+
259
+ const queries = [
260
+ 'Check availability for blue jacket',
261
+ 'Track order 1234',
262
+ 'Go to cart',
263
+ 'Is the website down?',
264
+ ]
265
+
266
+ console.log(`${c.gray} App: ${c.reset}${c.bold}${config.app}${c.reset}`)
267
+ console.log(`${c.gray} Capabilities: ${c.reset}${manifest.capabilities.length}`)
268
+ console.log(`${c.gray} Mode: keyword matcher (no LLM required)\n${c.reset}`)
269
+
270
+ let passed = 0
271
+ let outOfScope = 0
272
+
273
+ for (const query of queries) {
274
+ const start = Date.now()
275
+ const result = match(query, manifest)
276
+ const duration = Date.now() - start
277
+
278
+ if (result.capability) {
279
+ passed++
280
+ const resolverColor = result.capability.resolver.type === 'api' ? c.teal :
281
+ result.capability.resolver.type === 'nav' ? c.teal : c.yellow
282
+
283
+ console.log(` ${c.green}✓${c.reset} ${c.bold}"${query}"${c.reset}`)
284
+ console.log(` ${c.gray}→ matched:${c.reset} ${resolverColor}${result.capability.id}${c.reset}`)
285
+ console.log(` ${c.gray}→ intent:${c.reset} ${result.intent}`)
286
+ console.log(` ${c.gray}→ confidence:${c.reset} ${result.confidence}%`)
287
+
288
+ if (Object.keys(result.extractedParams).length > 0) {
289
+ const params = Object.entries(result.extractedParams)
290
+ .map(([k, v]) => `${k}=${v}`)
291
+ .join(', ')
292
+ console.log(` ${c.gray}→ params:${c.reset} ${params}`)
293
+ }
294
+
295
+ // Show what API call would be made
296
+ if (result.capability.resolver.type === 'api') {
297
+ const endpoint = result.capability.resolver.endpoints[0]
298
+ let path = endpoint.path
299
+ for (const [k, v] of Object.entries(result.extractedParams)) {
300
+ if (v) path = path.replace(`{${k}}`, v)
301
+ }
302
+ console.log(` ${c.gray}→ api call:${c.reset} ${endpoint.method} ${config.baseUrl}${path}`)
303
+ } else if (result.capability.resolver.type === 'nav') {
304
+ let dest = result.capability.resolver.destination
305
+ for (const [k, v] of Object.entries(result.extractedParams)) {
306
+ if (v) dest = dest.replace(`{${k}}`, v)
307
+ }
308
+ console.log(` ${c.gray}→ nav target:${c.reset} ${dest}`)
309
+ }
310
+
311
+ console.log(` ${c.gray}→ time:${c.reset} ${duration}ms\n`)
312
+ } else {
313
+ outOfScope++
314
+ console.log(` ${c.yellow}○${c.reset} ${c.bold}"${query}"${c.reset}`)
315
+ console.log(` ${c.gray}→ out of scope — no capability handles this\n${c.reset}`)
316
+ }
317
+ }
318
+
319
+ console.log(`${c.gray} ─────────────────────────────────────────${c.reset}`)
320
+ console.log(` ${c.green}${passed} matched${c.reset} ${c.gray}·${c.reset} ${c.yellow}${outOfScope} out of scope${c.reset} ${c.gray}·${c.reset} ${manifest.capabilities.length} capabilities\n`)
321
+ console.log(` ${c.gray}Try it on your own app:${c.reset}`)
322
+ console.log(` ${c.teal}npx capman init${c.reset} ${c.gray}→ create your manifest${c.reset}`)
323
+ console.log(` ${c.teal}npx capman generate${c.reset} ${c.gray}→ generate manifest.json${c.reset}\n`)
324
+ }
325
+
326
+ function cmdRun() {
327
+ header()
328
+ const query = args[1]
329
+ const debug = flags.includes('--debug')
330
+ const manifestPath = getFlag('--manifest') ?? 'manifest.json'
331
+
332
+ if (!query) {
333
+ log.error('Please provide a query. Example: node bin/capman.js run "show me articles"')
334
+ process.exit(1)
335
+ }
336
+
337
+ const { readManifest, match } = requireSrc()
338
+
339
+ let manifest
340
+ try {
341
+ manifest = readManifest(manifestPath)
342
+ } catch (e) {
343
+ log.error(e.message)
344
+ process.exit(1)
345
+ }
346
+
347
+ log.info(`Query: "${query}"`)
348
+ log.blank()
349
+
350
+ const result = match(query, manifest)
351
+
352
+ if (result.capability) {
353
+ console.log(` ${c.green}✓${c.reset} Matched: ${c.bold}${result.capability.id}${c.reset}`)
354
+ console.log(` Intent: ${result.intent}`)
355
+ console.log(` Confidence: ${result.confidence}%`)
356
+ console.log(` Resolver: ${result.capability.resolver.type}`)
357
+
358
+ if (Object.keys(result.extractedParams).length > 0) {
359
+ const params = Object.entries(result.extractedParams)
360
+ .map(([k, v]) => `${k}=${v}`)
361
+ .join(', ')
362
+ console.log(` Params: ${params}`)
363
+ }
364
+
365
+ if (debug && result.candidates?.length) {
366
+ log.blank()
367
+ console.log(` ${c.gray}── All candidates:${c.reset}`)
368
+ result.candidates
369
+ .sort((a, b) => b.score - a.score)
370
+ .forEach(c2 => {
371
+ const marker = c2.matched ? c.green + '✓' : c.gray + '○'
372
+ console.log(` ${marker}${c.reset} ${c2.capabilityId}: ${c2.score}%`)
373
+ })
374
+ }
375
+ } else {
376
+ console.log(` ${c.yellow}○${c.reset} OUT_OF_SCOPE — no capability matched`)
377
+ console.log(` ${c.gray}${result.reasoning}${c.reset}`)
378
+
379
+ if (debug && result.candidates?.length) {
380
+ log.blank()
381
+ console.log(` ${c.gray}── All candidates:${c.reset}`)
382
+ result.candidates
383
+ .sort((a, b) => b.score - a.score)
384
+ .slice(0, 5)
385
+ .forEach(c2 => {
386
+ console.log(` ${c.gray}○ ${c2.capabilityId}: ${c2.score}%${c.reset}`)
387
+ })
388
+ }
389
+ }
390
+ console.log()
391
+ }
392
+
179
393
  switch (command) {
180
394
  case 'init': cmdInit(); break
181
395
  case 'generate': cmdGenerate(); break
182
396
  case 'validate': cmdValidate(); break
183
397
  case 'inspect': cmdInspect(); break
398
+ case 'demo': cmdDemo(); break
399
+ case 'run': cmdRun(); break
184
400
  case undefined:
185
401
  case '--help':
186
402
  case '-h': cmdHelp(); break
@@ -0,0 +1,42 @@
1
+ import type { MatchResult } from './types';
2
+ export interface CacheEntry {
3
+ query: string;
4
+ result: MatchResult;
5
+ cachedAt: string;
6
+ hits: number;
7
+ }
8
+ export interface CacheStore {
9
+ get(query: string): Promise<CacheEntry | null>;
10
+ set(query: string, result: MatchResult): Promise<void>;
11
+ clear(): Promise<void>;
12
+ size(): Promise<number>;
13
+ }
14
+ export declare class MemoryCache implements CacheStore {
15
+ private store;
16
+ get(query: string): Promise<CacheEntry | null>;
17
+ set(query: string, result: MatchResult): Promise<void>;
18
+ clear(): Promise<void>;
19
+ size(): Promise<number>;
20
+ }
21
+ export declare class FileCache implements CacheStore {
22
+ private filePath;
23
+ private store;
24
+ private loaded;
25
+ constructor(filePath?: string);
26
+ private load;
27
+ private save;
28
+ get(query: string): Promise<CacheEntry | null>;
29
+ set(query: string, result: MatchResult): Promise<void>;
30
+ clear(): Promise<void>;
31
+ size(): Promise<number>;
32
+ }
33
+ export declare class ComboCache implements CacheStore {
34
+ private memory;
35
+ private file;
36
+ constructor(filePath?: string);
37
+ get(query: string): Promise<CacheEntry | null>;
38
+ set(query: string, result: MatchResult): Promise<void>;
39
+ clear(): Promise<void>;
40
+ size(): Promise<number>;
41
+ }
42
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ComboCache = exports.FileCache = exports.MemoryCache = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const logger_1 = require("./logger");
40
+ // ─── Normalize query for cache key ────────────────────────────────────────────
41
+ function normalizeQuery(query) {
42
+ return query.toLowerCase().trim().replace(/\s+/g, ' ');
43
+ }
44
+ // ─── Memory Cache ─────────────────────────────────────────────────────────────
45
+ class MemoryCache {
46
+ constructor() {
47
+ this.store = new Map();
48
+ }
49
+ async get(query) {
50
+ const key = normalizeQuery(query);
51
+ const entry = this.store.get(key);
52
+ if (entry) {
53
+ entry.hits++;
54
+ logger_1.logger.debug(`Cache hit (memory): "${query}"`);
55
+ return entry;
56
+ }
57
+ return null;
58
+ }
59
+ async set(query, result) {
60
+ const key = normalizeQuery(query);
61
+ this.store.set(key, {
62
+ query,
63
+ result,
64
+ cachedAt: new Date().toISOString(),
65
+ hits: 0,
66
+ });
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;
74
+ }
75
+ }
76
+ exports.MemoryCache = MemoryCache;
77
+ // ─── File Cache ───────────────────────────────────────────────────────────────
78
+ class FileCache {
79
+ constructor(filePath = '.capman/cache.json') {
80
+ this.store = new Map();
81
+ this.loaded = false;
82
+ this.filePath = path.resolve(process.cwd(), filePath);
83
+ logger_1.logger.info(`FileCache initialized — writing to: ${this.filePath}`);
84
+ }
85
+ async load() {
86
+ if (this.loaded)
87
+ return;
88
+ try {
89
+ const raw = await fs.promises.readFile(this.filePath, 'utf-8');
90
+ this.store = new Map(Object.entries(JSON.parse(raw)));
91
+ logger_1.logger.debug(`File cache loaded: ${this.store.size} entries`);
92
+ }
93
+ catch {
94
+ // File doesn't exist yet — start fresh
95
+ }
96
+ this.loaded = true;
97
+ }
98
+ async save() {
99
+ try {
100
+ const dir = path.dirname(this.filePath);
101
+ await fs.promises.mkdir(dir, { recursive: true });
102
+ await fs.promises.writeFile(this.filePath, JSON.stringify(Object.fromEntries(this.store), null, 2));
103
+ }
104
+ catch {
105
+ logger_1.logger.warn(`Failed to save file cache to ${this.filePath}`);
106
+ }
107
+ }
108
+ async get(query) {
109
+ await this.load();
110
+ const key = normalizeQuery(query);
111
+ const entry = this.store.get(key);
112
+ if (entry) {
113
+ entry.hits++;
114
+ logger_1.logger.debug(`Cache hit (file): "${query}"`);
115
+ return entry;
116
+ }
117
+ return null;
118
+ }
119
+ async set(query, result) {
120
+ await this.load();
121
+ const key = normalizeQuery(query);
122
+ this.store.set(key, {
123
+ query,
124
+ result,
125
+ cachedAt: new Date().toISOString(),
126
+ hits: 0,
127
+ });
128
+ await this.save();
129
+ logger_1.logger.debug(`Cache set (file): "${query}"`);
130
+ }
131
+ async clear() {
132
+ this.store.clear();
133
+ await this.save();
134
+ }
135
+ async size() {
136
+ await this.load();
137
+ return this.store.size;
138
+ }
139
+ }
140
+ exports.FileCache = FileCache;
141
+ // ─── Combo Cache (memory first, file fallback) ────────────────────────────────
142
+ class ComboCache {
143
+ constructor(filePath = '.capman/cache.json') {
144
+ this.memory = new MemoryCache();
145
+ this.file = new FileCache(filePath);
146
+ }
147
+ async get(query) {
148
+ // Memory first — fastest
149
+ const memHit = await this.memory.get(query);
150
+ if (memHit)
151
+ return memHit;
152
+ // File fallback — persists across restarts
153
+ const fileHit = await this.file.get(query);
154
+ 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}"`);
158
+ return fileHit;
159
+ }
160
+ return null;
161
+ }
162
+ async set(query, result) {
163
+ await Promise.all([
164
+ this.memory.set(query, result),
165
+ this.file.set(query, result),
166
+ ]);
167
+ }
168
+ async clear() {
169
+ await Promise.all([
170
+ this.memory.clear(),
171
+ this.file.clear(),
172
+ ]);
173
+ }
174
+ async size() {
175
+ return this.file.size();
176
+ }
177
+ }
178
+ exports.ComboCache = ComboCache;
179
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import type { Manifest, MatchResult, ResolveResult, ExecutionTrace } from './types';
2
+ import type { LLMMatcherOptions } from './matcher';
3
+ import type { ResolveOptions, AuthContext } from './resolver';
4
+ import type { CacheStore } from './cache';
5
+ import type { LearningStore } from './learning';
6
+ import type { MatchMode } from './index';
7
+ export interface EngineOptions {
8
+ /** The capability manifest to use */
9
+ manifest: Manifest;
10
+ /**
11
+ * Matching mode
12
+ * - 'cheap' — keyword only, no LLM
13
+ * - 'balanced' — keyword first, LLM fallback (default)
14
+ * - 'accurate' — LLM first, keyword fallback
15
+ */
16
+ mode?: MatchMode;
17
+ /** LLM function for accurate/balanced matching */
18
+ llm?: LLMMatcherOptions['llm'];
19
+ /** Cache store — defaults to ComboCache (memory + file) */
20
+ cache?: CacheStore | false;
21
+ /** Learning store — defaults to FileLearningStore */
22
+ learning?: LearningStore | false;
23
+ /** Base URL for API resolvers */
24
+ baseUrl?: string;
25
+ /** Auth context for privacy-scoped capabilities */
26
+ auth?: AuthContext;
27
+ /** Custom headers for API calls */
28
+ headers?: Record<string, string>;
29
+ /** Confidence threshold for keyword matcher (default: 50) */
30
+ threshold?: number;
31
+ }
32
+ export interface EngineResult {
33
+ match: MatchResult;
34
+ resolution: ResolveResult;
35
+ resolvedVia: 'cache' | 'keyword' | 'llm';
36
+ durationMs: number;
37
+ /** Full execution trace — always present */
38
+ trace: ExecutionTrace;
39
+ }
40
+ export declare class CapmanEngine {
41
+ private manifest;
42
+ private mode;
43
+ private llm?;
44
+ private cache;
45
+ private learning;
46
+ private baseUrl?;
47
+ private auth?;
48
+ private headers?;
49
+ private threshold;
50
+ constructor(options: EngineOptions);
51
+ /**
52
+ * Ask the engine a natural language query.
53
+ * Automatically handles caching, matching, resolution, and learning.
54
+ *
55
+ * @example
56
+ * const engine = new CapmanEngine({ manifest, llm: myLLM })
57
+ * const result = await engine.ask("Check availability for blue jacket")
58
+ * console.log(result.match.capability?.id) // check_product_availability
59
+ * console.log(result.resolution.apiCalls) // [{ url: '...', method: 'GET' }]
60
+ * console.log(result.resolvedVia) // 'keyword' | 'llm' | 'cache'
61
+ */
62
+ ask(query: string, overrides?: Partial<ResolveOptions>): Promise<EngineResult>;
63
+ /**
64
+ * Get stats from the learning store.
65
+ * Shows which capabilities are most used, LLM vs keyword ratio, cache hit rate.
66
+ */
67
+ getStats(): Promise<import("./learning").KeywordStats | null>;
68
+ /**
69
+ * Get the most frequently matched capabilities.
70
+ */
71
+ getTopCapabilities(limit?: number): Promise<{
72
+ id: string;
73
+ hits: number;
74
+ }[]>;
75
+ /**
76
+ * Clear the cache.
77
+ */
78
+ clearCache(): Promise<void>;
79
+ private resolveOptions;
80
+ private recordLearning;
81
+ }
82
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAa,MAAM,SAAS,CAAA;AAC9F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAA;AAM9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAIxC,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,QAAQ,EAAE,QAAQ,CAAA;IAClB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,kDAAkD;IAClD,GAAG,CAAC,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAA;IAC9B,2DAA2D;IAC3D,KAAK,CAAC,EAAE,UAAU,GAAG,KAAK,CAAA;IAC1B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,aAAa,GAAG,KAAK,CAAA;IAChC,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,mDAAmD;IACnD,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAID,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,WAAW,CAAA;IAClB,UAAU,EAAE,aAAa,CAAA;IACzB,WAAW,EAAE,OAAO,GAAG,SAAS,GAAG,KAAK,CAAA;IACxC,UAAU,EAAE,MAAM,CAAA;IAClB,4CAA4C;IAC5C,KAAK,EAAE,cAAc,CAAA;CACtB;AAID,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,IAAI,CAAgB;IAC5B,OAAO,CAAC,GAAG,CAAC,CAA+B;IAC3C,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,OAAO,CAAC,IAAI,CAAC,CAAiB;IAC9B,OAAO,CAAC,OAAO,CAAC,CAAyB;IACzC,OAAO,CAAC,SAAS,CAAQ;gBAEb,OAAO,EAAE,aAAa;IAwBlC;;;;;;;;;;OAUG;IACG,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,OAAO,CAAC,cAAc,CAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAkKxF;;;OAGG;IACG,QAAQ;IAKd;;OAEG;IACG,kBAAkB,CAAC,KAAK,SAAI;;;;IAKlC;;OAEG;IACG,UAAU;IAMhB,OAAO,CAAC,cAAc;YASR,cAAc;CAgB7B"}