capman 0.1.0 → 0.3.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.
- package/bin/capman.js +152 -6
- package/dist/cjs/cache.d.ts +42 -0
- package/dist/cjs/cache.d.ts.map +1 -0
- package/dist/cjs/cache.js +181 -0
- package/dist/cjs/cache.js.map +1 -0
- package/dist/cjs/engine.d.ts +82 -0
- package/dist/cjs/engine.d.ts.map +1 -0
- package/dist/cjs/engine.js +154 -0
- package/dist/cjs/engine.js.map +1 -0
- package/dist/cjs/generator.d.ts.map +1 -0
- package/dist/{generator.js → cjs/generator.js} +2 -1
- package/dist/cjs/generator.js.map +1 -0
- package/dist/{index.d.ts → cjs/index.d.ts} +18 -1
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +77 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/learning.d.ts +56 -0
- package/dist/cjs/learning.d.ts.map +1 -0
- package/dist/cjs/learning.js +184 -0
- package/dist/cjs/learning.js.map +1 -0
- package/dist/cjs/logger.d.ts.map +1 -0
- package/dist/cjs/logger.js.map +1 -0
- package/dist/cjs/matcher.d.ts.map +1 -0
- package/dist/{matcher.js → cjs/matcher.js} +27 -5
- package/dist/cjs/matcher.js.map +1 -0
- package/dist/cjs/resolver.d.ts.map +1 -0
- package/dist/{resolver.js → cjs/resolver.js} +36 -4
- package/dist/cjs/resolver.js.map +1 -0
- package/dist/{schema.d.ts → cjs/schema.d.ts} +10 -10
- package/dist/{schema.d.ts.map → cjs/schema.d.ts.map} +1 -1
- package/dist/cjs/schema.js.map +1 -0
- package/dist/{types.d.ts → cjs/types.d.ts} +12 -5
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/version.d.ts +2 -0
- package/dist/cjs/version.d.ts.map +1 -0
- package/dist/cjs/version.js +6 -0
- package/dist/cjs/version.js.map +1 -0
- package/dist/esm/cache.js +141 -0
- package/dist/esm/engine.js +149 -0
- package/dist/esm/generator.js +183 -0
- package/dist/esm/generator.js.map +1 -0
- package/dist/esm/index.js +56 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/learning.js +145 -0
- package/dist/esm/logger.js +47 -0
- package/dist/esm/logger.js.map +1 -0
- package/dist/esm/matcher.js +211 -0
- package/dist/esm/matcher.js.map +1 -0
- package/dist/esm/resolver.js +192 -0
- package/dist/esm/resolver.js.map +1 -0
- package/dist/esm/schema.js +88 -0
- package/dist/esm/schema.js.map +1 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/version.js +2 -0
- package/package.json +27 -11
- package/dist/generator.d.ts.map +0 -1
- package/dist/generator.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -42
- package/dist/index.js.map +0 -1
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/matcher.d.ts.map +0 -1
- package/dist/matcher.js.map +0 -1
- package/dist/resolver.d.ts.map +0 -1
- package/dist/resolver.js.map +0 -1
- package/dist/schema.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- /package/dist/{generator.d.ts → cjs/generator.d.ts} +0 -0
- /package/dist/{logger.d.ts → cjs/logger.d.ts} +0 -0
- /package/dist/{logger.js → cjs/logger.js} +0 -0
- /package/dist/{matcher.d.ts → cjs/matcher.d.ts} +0 -0
- /package/dist/{resolver.d.ts → cjs/resolver.d.ts} +0 -0
- /package/dist/{schema.js → cjs/schema.js} +0 -0
- /package/dist/{types.js → cjs/types.js} +0 -0
package/bin/capman.js
CHANGED
|
@@ -32,23 +32,31 @@ 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}
|
|
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
|
}
|
|
40
41
|
|
|
41
42
|
function requireSrc() {
|
|
42
|
-
const distPath = path.join(__dirname, '..', 'dist', 'index.js')
|
|
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('
|
|
47
|
-
|
|
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
|
-
|
|
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,6 +68,7 @@ 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`)
|
|
63
72
|
console.log()
|
|
64
73
|
console.log(`${c.bold} Options:${c.reset}`)
|
|
65
74
|
console.log(` ${c.gray}--config Path to config file (default: capman.config.js)${c.reset}`)
|
|
@@ -176,11 +185,148 @@ function cmdInspect() {
|
|
|
176
185
|
}
|
|
177
186
|
}
|
|
178
187
|
|
|
188
|
+
function cmdDemo() {
|
|
189
|
+
header()
|
|
190
|
+
const { generate, match, resolve } = requireSrc()
|
|
191
|
+
|
|
192
|
+
console.log(`${c.bold} Live demo — see capman in action${c.reset}`)
|
|
193
|
+
console.log(`${c.gray} ─────────────────────────────────────────${c.reset}\n`)
|
|
194
|
+
|
|
195
|
+
// Demo manifest — generic e-commerce app
|
|
196
|
+
const config = {
|
|
197
|
+
app: 'demo-store',
|
|
198
|
+
baseUrl: 'https://api.demo-store.com',
|
|
199
|
+
capabilities: [
|
|
200
|
+
{
|
|
201
|
+
id: 'check_product_availability',
|
|
202
|
+
name: 'Check product availability',
|
|
203
|
+
description: 'Check stock and pricing for a product by name or ID.',
|
|
204
|
+
examples: [
|
|
205
|
+
'Is the blue jacket in stock?',
|
|
206
|
+
'Check stock for blue jacket',
|
|
207
|
+
'Do you have size M available?',
|
|
208
|
+
'Product availability for jacket',
|
|
209
|
+
'Is jacket available?',
|
|
210
|
+
],
|
|
211
|
+
params: [
|
|
212
|
+
{ name: 'product', description: 'Product name or ID', required: true, source: 'user_query' }
|
|
213
|
+
],
|
|
214
|
+
returns: ['stock', 'price', 'variants'],
|
|
215
|
+
resolver: { type: 'api', endpoints: [{ method: 'GET', path: '/products/{product}/availability' }] },
|
|
216
|
+
privacy: { level: 'public' },
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
id: 'get_order_status',
|
|
220
|
+
name: 'Get order status',
|
|
221
|
+
description: 'Retrieve the current status and tracking info for an order.',
|
|
222
|
+
examples: [
|
|
223
|
+
'Where is my order?',
|
|
224
|
+
'Track order 1234',
|
|
225
|
+
'What is the status of my recent purchase?',
|
|
226
|
+
],
|
|
227
|
+
params: [
|
|
228
|
+
{ name: 'order_id', description: 'Order ID', required: true, source: 'user_query' }
|
|
229
|
+
],
|
|
230
|
+
returns: ['status', 'tracking', 'estimated_delivery'],
|
|
231
|
+
resolver: { type: 'api', endpoints: [{ method: 'GET', path: '/orders/{order_id}' }] },
|
|
232
|
+
privacy: { level: 'user_owned' },
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
id: 'navigate_to_screen',
|
|
236
|
+
name: 'Navigate to screen',
|
|
237
|
+
description: 'Route the user to a specific page in the store.',
|
|
238
|
+
examples: [
|
|
239
|
+
'Take me to cart',
|
|
240
|
+
'Open cart',
|
|
241
|
+
'Go to checkout',
|
|
242
|
+
'Navigate to account',
|
|
243
|
+
'Show homepage',
|
|
244
|
+
],
|
|
245
|
+
params: [
|
|
246
|
+
{ name: 'destination', description: 'Target screen', required: true, source: 'user_query' }
|
|
247
|
+
],
|
|
248
|
+
returns: ['deep_link'],
|
|
249
|
+
resolver: { type: 'nav', destination: '/{destination}' },
|
|
250
|
+
privacy: { level: 'public' },
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const manifest = generate(config)
|
|
256
|
+
|
|
257
|
+
const queries = [
|
|
258
|
+
'Check availability for blue jacket',
|
|
259
|
+
'Track order 1234',
|
|
260
|
+
'Go to cart',
|
|
261
|
+
'Is the website down?',
|
|
262
|
+
]
|
|
263
|
+
|
|
264
|
+
console.log(`${c.gray} App: ${c.reset}${c.bold}${config.app}${c.reset}`)
|
|
265
|
+
console.log(`${c.gray} Capabilities: ${c.reset}${manifest.capabilities.length}`)
|
|
266
|
+
console.log(`${c.gray} Mode: keyword matcher (no LLM required)\n${c.reset}`)
|
|
267
|
+
|
|
268
|
+
let passed = 0
|
|
269
|
+
let outOfScope = 0
|
|
270
|
+
|
|
271
|
+
for (const query of queries) {
|
|
272
|
+
const start = Date.now()
|
|
273
|
+
const result = match(query, manifest)
|
|
274
|
+
const duration = Date.now() - start
|
|
275
|
+
|
|
276
|
+
if (result.capability) {
|
|
277
|
+
passed++
|
|
278
|
+
const resolverColor = result.capability.resolver.type === 'api' ? c.teal :
|
|
279
|
+
result.capability.resolver.type === 'nav' ? c.teal : c.yellow
|
|
280
|
+
|
|
281
|
+
console.log(` ${c.green}✓${c.reset} ${c.bold}"${query}"${c.reset}`)
|
|
282
|
+
console.log(` ${c.gray}→ matched:${c.reset} ${resolverColor}${result.capability.id}${c.reset}`)
|
|
283
|
+
console.log(` ${c.gray}→ intent:${c.reset} ${result.intent}`)
|
|
284
|
+
console.log(` ${c.gray}→ confidence:${c.reset} ${result.confidence}%`)
|
|
285
|
+
|
|
286
|
+
if (Object.keys(result.extractedParams).length > 0) {
|
|
287
|
+
const params = Object.entries(result.extractedParams)
|
|
288
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
289
|
+
.join(', ')
|
|
290
|
+
console.log(` ${c.gray}→ params:${c.reset} ${params}`)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Show what API call would be made
|
|
294
|
+
if (result.capability.resolver.type === 'api') {
|
|
295
|
+
const endpoint = result.capability.resolver.endpoints[0]
|
|
296
|
+
let path = endpoint.path
|
|
297
|
+
for (const [k, v] of Object.entries(result.extractedParams)) {
|
|
298
|
+
if (v) path = path.replace(`{${k}}`, v)
|
|
299
|
+
}
|
|
300
|
+
console.log(` ${c.gray}→ api call:${c.reset} ${endpoint.method} ${config.baseUrl}${path}`)
|
|
301
|
+
} else if (result.capability.resolver.type === 'nav') {
|
|
302
|
+
let dest = result.capability.resolver.destination
|
|
303
|
+
for (const [k, v] of Object.entries(result.extractedParams)) {
|
|
304
|
+
if (v) dest = dest.replace(`{${k}}`, v)
|
|
305
|
+
}
|
|
306
|
+
console.log(` ${c.gray}→ nav target:${c.reset} ${dest}`)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
console.log(` ${c.gray}→ time:${c.reset} ${duration}ms\n`)
|
|
310
|
+
} else {
|
|
311
|
+
outOfScope++
|
|
312
|
+
console.log(` ${c.yellow}○${c.reset} ${c.bold}"${query}"${c.reset}`)
|
|
313
|
+
console.log(` ${c.gray}→ out of scope — no capability handles this\n${c.reset}`)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
console.log(`${c.gray} ─────────────────────────────────────────${c.reset}`)
|
|
318
|
+
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`)
|
|
319
|
+
console.log(` ${c.gray}Try it on your own app:${c.reset}`)
|
|
320
|
+
console.log(` ${c.teal}npx capman init${c.reset} ${c.gray}→ create your manifest${c.reset}`)
|
|
321
|
+
console.log(` ${c.teal}npx capman generate${c.reset} ${c.gray}→ generate manifest.json${c.reset}\n`)
|
|
322
|
+
}
|
|
323
|
+
|
|
179
324
|
switch (command) {
|
|
180
325
|
case 'init': cmdInit(); break
|
|
181
326
|
case 'generate': cmdGenerate(); break
|
|
182
327
|
case 'validate': cmdValidate(); break
|
|
183
328
|
case 'inspect': cmdInspect(); break
|
|
329
|
+
case 'demo': cmdDemo(); break
|
|
184
330
|
case undefined:
|
|
185
331
|
case '--help':
|
|
186
332
|
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;IAI3C,OAAO,CAAC,IAAI;IAcZ,OAAO,CAAC,IAAI;IAWN,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;IAgB9C,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,181 @@
|
|
|
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
|
+
}
|
|
84
|
+
load() {
|
|
85
|
+
if (this.loaded)
|
|
86
|
+
return;
|
|
87
|
+
try {
|
|
88
|
+
if (fs.existsSync(this.filePath)) {
|
|
89
|
+
const raw = JSON.parse(fs.readFileSync(this.filePath, 'utf-8'));
|
|
90
|
+
this.store = new Map(Object.entries(raw));
|
|
91
|
+
logger_1.logger.debug(`File cache loaded: ${this.store.size} entries`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
logger_1.logger.warn(`Failed to load file cache at ${this.filePath}`);
|
|
96
|
+
}
|
|
97
|
+
this.loaded = true;
|
|
98
|
+
}
|
|
99
|
+
save() {
|
|
100
|
+
try {
|
|
101
|
+
const dir = path.dirname(this.filePath);
|
|
102
|
+
if (!fs.existsSync(dir))
|
|
103
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
104
|
+
const obj = Object.fromEntries(this.store);
|
|
105
|
+
fs.writeFileSync(this.filePath, JSON.stringify(obj, null, 2));
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
logger_1.logger.warn(`Failed to save file cache to ${this.filePath}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async get(query) {
|
|
112
|
+
this.load();
|
|
113
|
+
const key = normalizeQuery(query);
|
|
114
|
+
const entry = this.store.get(key);
|
|
115
|
+
if (entry) {
|
|
116
|
+
entry.hits++;
|
|
117
|
+
logger_1.logger.debug(`Cache hit (file): "${query}"`);
|
|
118
|
+
return entry;
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
async set(query, result) {
|
|
123
|
+
this.load();
|
|
124
|
+
const key = normalizeQuery(query);
|
|
125
|
+
this.store.set(key, {
|
|
126
|
+
query,
|
|
127
|
+
result,
|
|
128
|
+
cachedAt: new Date().toISOString(),
|
|
129
|
+
hits: 0,
|
|
130
|
+
});
|
|
131
|
+
this.save();
|
|
132
|
+
logger_1.logger.debug(`Cache set (file): "${query}"`);
|
|
133
|
+
}
|
|
134
|
+
async clear() {
|
|
135
|
+
this.store.clear();
|
|
136
|
+
this.save();
|
|
137
|
+
}
|
|
138
|
+
async size() {
|
|
139
|
+
this.load();
|
|
140
|
+
return this.store.size;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
exports.FileCache = FileCache;
|
|
144
|
+
// ─── Combo Cache (memory first, file fallback) ────────────────────────────────
|
|
145
|
+
class ComboCache {
|
|
146
|
+
constructor(filePath = '.capman/cache.json') {
|
|
147
|
+
this.memory = new MemoryCache();
|
|
148
|
+
this.file = new FileCache(filePath);
|
|
149
|
+
}
|
|
150
|
+
async get(query) {
|
|
151
|
+
// Memory first — fastest
|
|
152
|
+
const memHit = await this.memory.get(query);
|
|
153
|
+
if (memHit)
|
|
154
|
+
return memHit;
|
|
155
|
+
// File fallback — persists across restarts
|
|
156
|
+
const fileHit = await this.file.get(query);
|
|
157
|
+
if (fileHit) {
|
|
158
|
+
// Promote to memory for next time
|
|
159
|
+
await this.memory.set(query, fileHit.result);
|
|
160
|
+
return fileHit;
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
async set(query, result) {
|
|
165
|
+
await Promise.all([
|
|
166
|
+
this.memory.set(query, result),
|
|
167
|
+
this.file.set(query, result),
|
|
168
|
+
]);
|
|
169
|
+
}
|
|
170
|
+
async clear() {
|
|
171
|
+
await Promise.all([
|
|
172
|
+
this.memory.clear(),
|
|
173
|
+
this.file.clear(),
|
|
174
|
+
]);
|
|
175
|
+
}
|
|
176
|
+
async size() {
|
|
177
|
+
return this.file.size();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
exports.ComboCache = ComboCache;
|
|
181
|
+
//# 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 } 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
|
+
/** How the match was resolved */
|
|
36
|
+
resolvedVia: 'cache' | 'keyword' | 'llm';
|
|
37
|
+
/** Total time in milliseconds */
|
|
38
|
+
durationMs: number;
|
|
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,MAAM,SAAS,CAAA;AACnE,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,iCAAiC;IACjC,WAAW,EAAE,OAAO,GAAG,SAAS,GAAG,KAAK,CAAA;IACxC,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAA;CACnB;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;IAsBlC;;;;;;;;;;OAUG;IACG,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,OAAO,CAAC,cAAc,CAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAkFxF;;;OAGG;IACG,QAAQ;IAKd;;OAEG;IACG,kBAAkB,CAAC,KAAK,SAAI;;;;IAKlC;;OAEG;IACG,UAAU;IAMhB,OAAO,CAAC,cAAc;YASR,cAAc;CAgB7B"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CapmanEngine = void 0;
|
|
4
|
+
const matcher_1 = require("./matcher");
|
|
5
|
+
const resolver_1 = require("./resolver");
|
|
6
|
+
const cache_1 = require("./cache");
|
|
7
|
+
const learning_1 = require("./learning");
|
|
8
|
+
const logger_1 = require("./logger");
|
|
9
|
+
// ─── CapmanEngine ─────────────────────────────────────────────────────────────
|
|
10
|
+
class CapmanEngine {
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.manifest = options.manifest;
|
|
13
|
+
this.mode = options.mode ?? 'balanced';
|
|
14
|
+
this.llm = options.llm;
|
|
15
|
+
this.baseUrl = options.baseUrl;
|
|
16
|
+
this.auth = options.auth;
|
|
17
|
+
this.headers = options.headers;
|
|
18
|
+
this.threshold = options.threshold ?? 50;
|
|
19
|
+
// Cache — default ComboCache, or disabled with false
|
|
20
|
+
this.cache = options.cache === false
|
|
21
|
+
? null
|
|
22
|
+
: (options.cache ?? new cache_1.ComboCache());
|
|
23
|
+
// Learning — default FileLearningStore, or disabled with false
|
|
24
|
+
this.learning = options.learning === false
|
|
25
|
+
? null
|
|
26
|
+
: (options.learning ?? new learning_1.FileLearningStore());
|
|
27
|
+
logger_1.logger.info(`CapmanEngine initialized — mode: ${this.mode}, cache: ${this.cache ? 'enabled' : 'disabled'}, learning: ${this.learning ? 'enabled' : 'disabled'}`);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Ask the engine a natural language query.
|
|
31
|
+
* Automatically handles caching, matching, resolution, and learning.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* const engine = new CapmanEngine({ manifest, llm: myLLM })
|
|
35
|
+
* const result = await engine.ask("Check availability for blue jacket")
|
|
36
|
+
* console.log(result.match.capability?.id) // check_product_availability
|
|
37
|
+
* console.log(result.resolution.apiCalls) // [{ url: '...', method: 'GET' }]
|
|
38
|
+
* console.log(result.resolvedVia) // 'keyword' | 'llm' | 'cache'
|
|
39
|
+
*/
|
|
40
|
+
async ask(query, overrides = {}) {
|
|
41
|
+
const start = Date.now();
|
|
42
|
+
// ── Step 1: Check cache ──────────────────────────────────────────────────
|
|
43
|
+
if (this.cache) {
|
|
44
|
+
const cached = await this.cache.get(query);
|
|
45
|
+
if (cached) {
|
|
46
|
+
logger_1.logger.info(`Cache hit for: "${query}"`);
|
|
47
|
+
const resolution = await (0, resolver_1.resolve)(cached.result, cached.result.extractedParams, this.resolveOptions(overrides));
|
|
48
|
+
const result = {
|
|
49
|
+
match: cached.result,
|
|
50
|
+
resolution,
|
|
51
|
+
resolvedVia: 'cache',
|
|
52
|
+
durationMs: Date.now() - start,
|
|
53
|
+
};
|
|
54
|
+
await this.recordLearning(query, cached.result, 'cache');
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// ── Step 2: Match ────────────────────────────────────────────────────────
|
|
59
|
+
let matchResult;
|
|
60
|
+
let resolvedVia = 'keyword';
|
|
61
|
+
switch (this.mode) {
|
|
62
|
+
case 'cheap': {
|
|
63
|
+
matchResult = (0, matcher_1.match)(query, this.manifest);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
case 'accurate': {
|
|
67
|
+
if (this.llm) {
|
|
68
|
+
matchResult = await (0, matcher_1.matchWithLLM)(query, this.manifest, { llm: this.llm });
|
|
69
|
+
resolvedVia = 'llm';
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
logger_1.logger.warn('accurate mode requires llm — falling back to keyword');
|
|
73
|
+
matchResult = (0, matcher_1.match)(query, this.manifest);
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case 'balanced':
|
|
78
|
+
default: {
|
|
79
|
+
const keywordResult = (0, matcher_1.match)(query, this.manifest);
|
|
80
|
+
if (keywordResult.confidence >= this.threshold || !this.llm) {
|
|
81
|
+
matchResult = keywordResult;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
logger_1.logger.info(`Low confidence (${keywordResult.confidence}%) — escalating to LLM`);
|
|
85
|
+
matchResult = await (0, matcher_1.matchWithLLM)(query, this.manifest, { llm: this.llm });
|
|
86
|
+
resolvedVia = 'llm';
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// ── Step 3: Cache the match result ───────────────────────────────────────
|
|
92
|
+
if (this.cache && matchResult.capability) {
|
|
93
|
+
await this.cache.set(query, matchResult);
|
|
94
|
+
}
|
|
95
|
+
// ── Step 4: Resolve ──────────────────────────────────────────────────────
|
|
96
|
+
const resolution = await (0, resolver_1.resolve)(matchResult, matchResult.extractedParams, this.resolveOptions(overrides));
|
|
97
|
+
// ── Step 5: Record learning ──────────────────────────────────────────────
|
|
98
|
+
await this.recordLearning(query, matchResult, resolvedVia);
|
|
99
|
+
return {
|
|
100
|
+
match: matchResult,
|
|
101
|
+
resolution,
|
|
102
|
+
resolvedVia,
|
|
103
|
+
durationMs: Date.now() - start,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get stats from the learning store.
|
|
108
|
+
* Shows which capabilities are most used, LLM vs keyword ratio, cache hit rate.
|
|
109
|
+
*/
|
|
110
|
+
async getStats() {
|
|
111
|
+
if (!this.learning)
|
|
112
|
+
return null;
|
|
113
|
+
return this.learning.getStats();
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get the most frequently matched capabilities.
|
|
117
|
+
*/
|
|
118
|
+
async getTopCapabilities(limit = 5) {
|
|
119
|
+
if (!this.learning)
|
|
120
|
+
return [];
|
|
121
|
+
return this.learning.getTopCapabilities(limit);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Clear the cache.
|
|
125
|
+
*/
|
|
126
|
+
async clearCache() {
|
|
127
|
+
if (this.cache)
|
|
128
|
+
await this.cache.clear();
|
|
129
|
+
}
|
|
130
|
+
// ── Private helpers ────────────────────────────────────────────────────────
|
|
131
|
+
resolveOptions(overrides = {}) {
|
|
132
|
+
return {
|
|
133
|
+
baseUrl: this.baseUrl,
|
|
134
|
+
auth: this.auth,
|
|
135
|
+
headers: this.headers,
|
|
136
|
+
...overrides,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
async recordLearning(query, matchResult, resolvedVia) {
|
|
140
|
+
if (!this.learning)
|
|
141
|
+
return;
|
|
142
|
+
await this.learning.record({
|
|
143
|
+
query,
|
|
144
|
+
capabilityId: matchResult.capability?.id ?? null,
|
|
145
|
+
confidence: matchResult.confidence,
|
|
146
|
+
intent: matchResult.intent,
|
|
147
|
+
extractedParams: matchResult.extractedParams,
|
|
148
|
+
resolvedVia,
|
|
149
|
+
timestamp: new Date().toISOString(),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
exports.CapmanEngine = CapmanEngine;
|
|
154
|
+
//# sourceMappingURL=engine.js.map
|