llm-cli-gateway 2.11.0 → 2.12.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/.agents/skills/async-job-orchestration/SKILL.md +288 -0
- package/.agents/skills/implement-review-fix/SKILL.md +154 -0
- package/.agents/skills/multi-llm-review/SKILL.md +174 -0
- package/.agents/skills/public-demo-session/SKILL.md +100 -0
- package/.agents/skills/secure-orchestration/SKILL.md +227 -0
- package/.agents/skills/session-workflow/SKILL.md +271 -0
- package/CHANGELOG.md +63 -1
- package/README.md +86 -27
- package/dist/acp/provider-registry.js +6 -6
- package/dist/api-provider.d.ts +7 -0
- package/dist/api-provider.js +7 -0
- package/dist/api-request.js +1 -0
- package/dist/async-job-manager.d.ts +11 -1
- package/dist/async-job-manager.js +44 -3
- package/dist/config.d.ts +2 -0
- package/dist/config.js +3 -0
- package/dist/index.d.ts +40 -4
- package/dist/index.js +611 -158
- package/dist/job-store.d.ts +48 -1
- package/dist/job-store.js +184 -0
- package/dist/provider-codegen.js +3 -0
- package/dist/provider-tool-capabilities.d.ts +4 -0
- package/dist/provider-tool-capabilities.js +16 -13
- package/dist/upstream-contracts.d.ts +1 -0
- package/dist/upstream-contracts.js +202 -45
- package/dist/validation-orchestrator.d.ts +5 -2
- package/dist/validation-orchestrator.js +71 -5
- package/dist/validation-receipt.d.ts +68 -0
- package/dist/validation-receipt.js +245 -0
- package/dist/validation-report.d.ts +4 -2
- package/dist/validation-report.js +18 -1
- package/dist/validation-tools.js +58 -9
- package/npm-shrinkwrap.json +5 -5
- package/package.json +10 -4
- package/dist/xai-api-provider.d.ts +0 -43
- package/dist/xai-api-provider.js +0 -191
package/dist/job-store.d.ts
CHANGED
|
@@ -73,7 +73,46 @@ export interface OrphanedJobSnapshot {
|
|
|
73
73
|
transport: JobTransport;
|
|
74
74
|
httpStatus: number | null;
|
|
75
75
|
}
|
|
76
|
-
export
|
|
76
|
+
export interface ValidationRunLink {
|
|
77
|
+
provider: string;
|
|
78
|
+
jobId: string;
|
|
79
|
+
correlationId: string;
|
|
80
|
+
}
|
|
81
|
+
export interface ValidationRunRecord {
|
|
82
|
+
validationId: string;
|
|
83
|
+
ownerPrincipal: string;
|
|
84
|
+
intent: string;
|
|
85
|
+
createdAt: string;
|
|
86
|
+
requestJson: string;
|
|
87
|
+
providerLinks: ValidationRunLink[];
|
|
88
|
+
judgeLink: ValidationRunLink | null;
|
|
89
|
+
status: "running" | "finalized";
|
|
90
|
+
}
|
|
91
|
+
export interface ValidationReceiptRecord {
|
|
92
|
+
validationId: string;
|
|
93
|
+
ownerPrincipal: string;
|
|
94
|
+
mintedAt: string;
|
|
95
|
+
schemaVersion: string;
|
|
96
|
+
reportJson: string;
|
|
97
|
+
canonicalSha256: string;
|
|
98
|
+
prevSha256: string | null;
|
|
99
|
+
seq: number | null;
|
|
100
|
+
signature: string | null;
|
|
101
|
+
models: string[];
|
|
102
|
+
hasMaterialDisagreement: boolean;
|
|
103
|
+
confidence: string;
|
|
104
|
+
}
|
|
105
|
+
export interface ValidationRunStore {
|
|
106
|
+
recordValidationRun(run: ValidationRunRecord): void;
|
|
107
|
+
getValidationRun(validationId: string): ValidationRunRecord | null;
|
|
108
|
+
setValidationJudgeLink(validationId: string, judgeLink: ValidationRunLink): void;
|
|
109
|
+
setValidationRunStatus(validationId: string, status: ValidationRunRecord["status"]): void;
|
|
110
|
+
getValidationRunIdByJobId(jobId: string): string | null;
|
|
111
|
+
recordValidationReceipt(receipt: ValidationReceiptRecord): void;
|
|
112
|
+
getValidationReceipt(validationId: string): ValidationReceiptRecord | null;
|
|
113
|
+
}
|
|
114
|
+
export declare function isValidationRunStore(store: unknown): store is ValidationRunStore;
|
|
115
|
+
export declare class SqliteJobStore implements JobStore, ValidationRunStore {
|
|
77
116
|
private logger;
|
|
78
117
|
private db;
|
|
79
118
|
private retentionMs;
|
|
@@ -122,6 +161,14 @@ export declare class SqliteJobStore implements JobStore {
|
|
|
122
161
|
orphaned: Array<OrphanedJobSnapshot>;
|
|
123
162
|
};
|
|
124
163
|
evictExpired(): number;
|
|
164
|
+
recordValidationRun(run: ValidationRunRecord): void;
|
|
165
|
+
private linkRunJob;
|
|
166
|
+
getValidationRunIdByJobId(jobId: string): string | null;
|
|
167
|
+
getValidationRun(validationId: string): ValidationRunRecord | null;
|
|
168
|
+
setValidationJudgeLink(validationId: string, judgeLink: ValidationRunLink): void;
|
|
169
|
+
setValidationRunStatus(validationId: string, status: ValidationRunRecord["status"]): void;
|
|
170
|
+
recordValidationReceipt(receipt: ValidationReceiptRecord): void;
|
|
171
|
+
getValidationReceipt(validationId: string): ValidationReceiptRecord | null;
|
|
125
172
|
close(): void;
|
|
126
173
|
}
|
|
127
174
|
export declare const JobStoreClass: typeof SqliteJobStore;
|
package/dist/job-store.js
CHANGED
|
@@ -83,6 +83,13 @@ function ensureJobsTransportColumns(db) {
|
|
|
83
83
|
db.exec("ALTER TABLE jobs ADD COLUMN payload_json TEXT");
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
+
export function isValidationRunStore(store) {
|
|
87
|
+
return (typeof store === "object" &&
|
|
88
|
+
store !== null &&
|
|
89
|
+
typeof store.recordValidationRun === "function" &&
|
|
90
|
+
typeof store.getValidationRun === "function" &&
|
|
91
|
+
typeof store.recordValidationReceipt === "function");
|
|
92
|
+
}
|
|
86
93
|
export class SqliteJobStore {
|
|
87
94
|
logger;
|
|
88
95
|
db;
|
|
@@ -128,6 +135,42 @@ export class SqliteJobStore {
|
|
|
128
135
|
CREATE INDEX IF NOT EXISTS idx_jobs_status ON jobs(status);
|
|
129
136
|
CREATE INDEX IF NOT EXISTS idx_jobs_expires_at ON jobs(expires_at);
|
|
130
137
|
CREATE INDEX IF NOT EXISTS idx_jobs_request_key_finished ON jobs(request_key, finished_at);
|
|
138
|
+
`);
|
|
139
|
+
this.db.exec(`
|
|
140
|
+
CREATE TABLE IF NOT EXISTS validation_runs (
|
|
141
|
+
validation_id TEXT PRIMARY KEY,
|
|
142
|
+
owner_principal TEXT NOT NULL,
|
|
143
|
+
intent TEXT NOT NULL,
|
|
144
|
+
created_at TEXT NOT NULL,
|
|
145
|
+
request_json TEXT NOT NULL,
|
|
146
|
+
provider_links TEXT NOT NULL,
|
|
147
|
+
judge_link TEXT,
|
|
148
|
+
status TEXT NOT NULL
|
|
149
|
+
);
|
|
150
|
+
CREATE INDEX IF NOT EXISTS idx_validation_runs_owner ON validation_runs(owner_principal);
|
|
151
|
+
`);
|
|
152
|
+
this.db.exec(`
|
|
153
|
+
CREATE TABLE IF NOT EXISTS validation_run_jobs (
|
|
154
|
+
job_id TEXT PRIMARY KEY,
|
|
155
|
+
validation_id TEXT NOT NULL,
|
|
156
|
+
role TEXT NOT NULL
|
|
157
|
+
);
|
|
158
|
+
CREATE INDEX IF NOT EXISTS idx_validation_run_jobs_run ON validation_run_jobs(validation_id);
|
|
159
|
+
CREATE TABLE IF NOT EXISTS validation_receipts (
|
|
160
|
+
validation_id TEXT PRIMARY KEY,
|
|
161
|
+
owner_principal TEXT NOT NULL,
|
|
162
|
+
minted_at TEXT NOT NULL,
|
|
163
|
+
schema_version TEXT NOT NULL,
|
|
164
|
+
report_json TEXT NOT NULL,
|
|
165
|
+
canonical_sha256 TEXT NOT NULL,
|
|
166
|
+
prev_sha256 TEXT,
|
|
167
|
+
seq INTEGER,
|
|
168
|
+
signature TEXT,
|
|
169
|
+
models TEXT NOT NULL,
|
|
170
|
+
has_material_disagreement INTEGER NOT NULL,
|
|
171
|
+
confidence TEXT NOT NULL
|
|
172
|
+
);
|
|
173
|
+
CREATE INDEX IF NOT EXISTS idx_validation_receipts_owner ON validation_receipts(owner_principal);
|
|
131
174
|
`);
|
|
132
175
|
ensureJobsOwnerColumn(this.db);
|
|
133
176
|
ensureJobsTransportColumns(this.db);
|
|
@@ -262,6 +305,86 @@ export class SqliteJobStore {
|
|
|
262
305
|
const result = this.deleteExpiredStmt.run(now);
|
|
263
306
|
return Number(result.changes);
|
|
264
307
|
}
|
|
308
|
+
recordValidationRun(run) {
|
|
309
|
+
this.db
|
|
310
|
+
.prepare(`INSERT OR IGNORE INTO validation_runs
|
|
311
|
+
(validation_id, owner_principal, intent, created_at, request_json,
|
|
312
|
+
provider_links, judge_link, status)
|
|
313
|
+
VALUES (@validation_id, @owner_principal, @intent, @created_at, @request_json,
|
|
314
|
+
@provider_links, @judge_link, @status)`)
|
|
315
|
+
.run({
|
|
316
|
+
validation_id: run.validationId,
|
|
317
|
+
owner_principal: run.ownerPrincipal,
|
|
318
|
+
intent: run.intent,
|
|
319
|
+
created_at: run.createdAt,
|
|
320
|
+
request_json: run.requestJson,
|
|
321
|
+
provider_links: JSON.stringify(run.providerLinks),
|
|
322
|
+
judge_link: run.judgeLink ? JSON.stringify(run.judgeLink) : null,
|
|
323
|
+
status: run.status,
|
|
324
|
+
});
|
|
325
|
+
for (const link of run.providerLinks) {
|
|
326
|
+
this.linkRunJob(run.validationId, link.jobId, "provider");
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
linkRunJob(validationId, jobId, role) {
|
|
330
|
+
this.db
|
|
331
|
+
.prepare(`INSERT OR IGNORE INTO validation_run_jobs (job_id, validation_id, role)
|
|
332
|
+
VALUES (?, ?, ?)`)
|
|
333
|
+
.run(jobId, validationId, role);
|
|
334
|
+
}
|
|
335
|
+
getValidationRunIdByJobId(jobId) {
|
|
336
|
+
const row = this.db
|
|
337
|
+
.prepare(`SELECT validation_id FROM validation_run_jobs WHERE job_id = ?`)
|
|
338
|
+
.get(jobId);
|
|
339
|
+
return row?.validation_id ?? null;
|
|
340
|
+
}
|
|
341
|
+
getValidationRun(validationId) {
|
|
342
|
+
const row = this.db
|
|
343
|
+
.prepare(`SELECT * FROM validation_runs WHERE validation_id = ?`)
|
|
344
|
+
.get(validationId);
|
|
345
|
+
return row ? rowToValidationRunRecord(row) : null;
|
|
346
|
+
}
|
|
347
|
+
setValidationJudgeLink(validationId, judgeLink) {
|
|
348
|
+
this.db
|
|
349
|
+
.prepare(`UPDATE validation_runs SET judge_link = ? WHERE validation_id = ?`)
|
|
350
|
+
.run(JSON.stringify(judgeLink), validationId);
|
|
351
|
+
this.linkRunJob(validationId, judgeLink.jobId, "judge");
|
|
352
|
+
}
|
|
353
|
+
setValidationRunStatus(validationId, status) {
|
|
354
|
+
this.db
|
|
355
|
+
.prepare(`UPDATE validation_runs SET status = ? WHERE validation_id = ?`)
|
|
356
|
+
.run(status, validationId);
|
|
357
|
+
}
|
|
358
|
+
recordValidationReceipt(receipt) {
|
|
359
|
+
this.db
|
|
360
|
+
.prepare(`INSERT OR IGNORE INTO validation_receipts
|
|
361
|
+
(validation_id, owner_principal, minted_at, schema_version, report_json,
|
|
362
|
+
canonical_sha256, prev_sha256, seq, signature, models,
|
|
363
|
+
has_material_disagreement, confidence)
|
|
364
|
+
VALUES (@validation_id, @owner_principal, @minted_at, @schema_version, @report_json,
|
|
365
|
+
@canonical_sha256, @prev_sha256, @seq, @signature, @models,
|
|
366
|
+
@has_material_disagreement, @confidence)`)
|
|
367
|
+
.run({
|
|
368
|
+
validation_id: receipt.validationId,
|
|
369
|
+
owner_principal: receipt.ownerPrincipal,
|
|
370
|
+
minted_at: receipt.mintedAt,
|
|
371
|
+
schema_version: receipt.schemaVersion,
|
|
372
|
+
report_json: receipt.reportJson,
|
|
373
|
+
canonical_sha256: receipt.canonicalSha256,
|
|
374
|
+
prev_sha256: receipt.prevSha256,
|
|
375
|
+
seq: receipt.seq,
|
|
376
|
+
signature: receipt.signature,
|
|
377
|
+
models: JSON.stringify(receipt.models),
|
|
378
|
+
has_material_disagreement: receipt.hasMaterialDisagreement ? 1 : 0,
|
|
379
|
+
confidence: receipt.confidence,
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
getValidationReceipt(validationId) {
|
|
383
|
+
const row = this.db
|
|
384
|
+
.prepare(`SELECT * FROM validation_receipts WHERE validation_id = ?`)
|
|
385
|
+
.get(validationId);
|
|
386
|
+
return row ? rowToValidationReceiptRecord(row) : null;
|
|
387
|
+
}
|
|
265
388
|
close() {
|
|
266
389
|
try {
|
|
267
390
|
this.db.close();
|
|
@@ -271,6 +394,67 @@ export class SqliteJobStore {
|
|
|
271
394
|
}
|
|
272
395
|
}
|
|
273
396
|
}
|
|
397
|
+
function rowToValidationRunRecord(row) {
|
|
398
|
+
return {
|
|
399
|
+
validationId: row.validation_id,
|
|
400
|
+
ownerPrincipal: row.owner_principal,
|
|
401
|
+
intent: row.intent,
|
|
402
|
+
createdAt: row.created_at,
|
|
403
|
+
requestJson: row.request_json,
|
|
404
|
+
providerLinks: parseLinks(row.provider_links) ?? [],
|
|
405
|
+
judgeLink: parseLink(row.judge_link),
|
|
406
|
+
status: row.status,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
function rowToValidationReceiptRecord(row) {
|
|
410
|
+
return {
|
|
411
|
+
validationId: row.validation_id,
|
|
412
|
+
ownerPrincipal: row.owner_principal,
|
|
413
|
+
mintedAt: row.minted_at,
|
|
414
|
+
schemaVersion: row.schema_version,
|
|
415
|
+
reportJson: row.report_json,
|
|
416
|
+
canonicalSha256: row.canonical_sha256,
|
|
417
|
+
prevSha256: row.prev_sha256 ?? null,
|
|
418
|
+
seq: row.seq ?? null,
|
|
419
|
+
signature: row.signature ?? null,
|
|
420
|
+
models: parseStringArray(row.models),
|
|
421
|
+
hasMaterialDisagreement: Boolean(row.has_material_disagreement),
|
|
422
|
+
confidence: row.confidence,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
function parseLinks(value) {
|
|
426
|
+
if (typeof value !== "string" || value.length === 0)
|
|
427
|
+
return null;
|
|
428
|
+
try {
|
|
429
|
+
const parsed = JSON.parse(value);
|
|
430
|
+
return Array.isArray(parsed) ? parsed : null;
|
|
431
|
+
}
|
|
432
|
+
catch {
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
function parseStringArray(value) {
|
|
437
|
+
if (typeof value !== "string" || value.length === 0)
|
|
438
|
+
return [];
|
|
439
|
+
try {
|
|
440
|
+
const parsed = JSON.parse(value);
|
|
441
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
442
|
+
}
|
|
443
|
+
catch {
|
|
444
|
+
return [];
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
function parseLink(value) {
|
|
448
|
+
if (typeof value !== "string" || value.length === 0)
|
|
449
|
+
return null;
|
|
450
|
+
try {
|
|
451
|
+
const parsed = JSON.parse(value);
|
|
452
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
274
458
|
export const JobStoreClass = SqliteJobStore;
|
|
275
459
|
export class MemoryJobStore {
|
|
276
460
|
rows = new Map();
|
package/dist/provider-codegen.js
CHANGED
|
@@ -133,4 +133,8 @@ export type ProviderToolCapabilitiesMap = Partial<Record<ProviderCapabilityId, P
|
|
|
133
133
|
export declare function getProviderToolCapabilities(queryOrCli?: ProviderCapabilityQuery | ProviderCapabilityId): ProviderToolCapabilitiesMap;
|
|
134
134
|
export declare function getOneProviderToolCapabilities(cli: ProviderCapabilityId, queryOrCli?: ProviderCapabilityQuery | ProviderCapabilityId): ProviderToolCapabilities;
|
|
135
135
|
export declare function clearProviderToolCapabilitiesCache(): void;
|
|
136
|
+
export declare function _getCapabilityCacheForTest(): Map<string, {
|
|
137
|
+
loadedAt: number;
|
|
138
|
+
value: ProviderToolCapabilities;
|
|
139
|
+
}>;
|
|
136
140
|
export declare function providerCapabilityIds(): readonly KnownProviderCapabilityId[];
|
|
@@ -49,7 +49,7 @@ export const ACP_CONTRACT = {
|
|
|
49
49
|
},
|
|
50
50
|
gemini: {
|
|
51
51
|
classification: "absent_watchlist",
|
|
52
|
-
summary: "Google Antigravity agy 1.0.
|
|
52
|
+
summary: "Google Antigravity agy 1.0.13 has no ACP surface; watchlist item only.",
|
|
53
53
|
},
|
|
54
54
|
grok_api: {
|
|
55
55
|
classification: "absent_watchlist",
|
|
@@ -66,7 +66,7 @@ const ACP_CAPABILITIES = {
|
|
|
66
66
|
mistral: {
|
|
67
67
|
status: "native_smoke_passed",
|
|
68
68
|
mediation: "native",
|
|
69
|
-
targetVersion: "vibe 2.
|
|
69
|
+
targetVersion: "vibe 2.17.1",
|
|
70
70
|
entrypoint: { command: "vibe-acp", args: [] },
|
|
71
71
|
runtimeEnabled: false,
|
|
72
72
|
smokeSupported: true,
|
|
@@ -80,7 +80,7 @@ const ACP_CAPABILITIES = {
|
|
|
80
80
|
grok: {
|
|
81
81
|
status: "native_smoke_passed",
|
|
82
82
|
mediation: "native",
|
|
83
|
-
targetVersion: "grok 0.2.
|
|
83
|
+
targetVersion: "grok 0.2.73 (9ff14c43bb)",
|
|
84
84
|
entrypoint: { command: "grok", args: ["agent", "stdio"] },
|
|
85
85
|
runtimeEnabled: false,
|
|
86
86
|
smokeSupported: true,
|
|
@@ -95,7 +95,7 @@ const ACP_CAPABILITIES = {
|
|
|
95
95
|
codex: {
|
|
96
96
|
status: "adapter_mediated_deferred",
|
|
97
97
|
mediation: "adapter_mediated",
|
|
98
|
-
targetVersion: "codex-cli 0.
|
|
98
|
+
targetVersion: "codex-cli 0.142.4",
|
|
99
99
|
entrypoint: null,
|
|
100
100
|
runtimeEnabled: false,
|
|
101
101
|
smokeSupported: false,
|
|
@@ -109,7 +109,7 @@ const ACP_CAPABILITIES = {
|
|
|
109
109
|
claude: {
|
|
110
110
|
status: "adapter_mediated_deferred",
|
|
111
111
|
mediation: "adapter_mediated",
|
|
112
|
-
targetVersion: "claude 2.1.
|
|
112
|
+
targetVersion: "claude 2.1.195",
|
|
113
113
|
entrypoint: null,
|
|
114
114
|
runtimeEnabled: false,
|
|
115
115
|
smokeSupported: false,
|
|
@@ -123,13 +123,13 @@ const ACP_CAPABILITIES = {
|
|
|
123
123
|
gemini: {
|
|
124
124
|
status: "absent_watchlist",
|
|
125
125
|
mediation: "none",
|
|
126
|
-
targetVersion: "agy 1.0.
|
|
126
|
+
targetVersion: "agy 1.0.13",
|
|
127
127
|
entrypoint: null,
|
|
128
128
|
runtimeEnabled: false,
|
|
129
129
|
smokeSupported: false,
|
|
130
130
|
smokeStatus: "unsupported",
|
|
131
131
|
caveats: [
|
|
132
|
-
"Antigravity agy 1.0.
|
|
132
|
+
"Antigravity agy 1.0.13 has no ACP flag or subcommand.",
|
|
133
133
|
"Legacy Gemini CLI ACP evidence does not transfer to agy; kept on the upstream drift watchlist.",
|
|
134
134
|
],
|
|
135
135
|
docs: ACP_DOCS_REFERENCE,
|
|
@@ -148,7 +148,7 @@ const ACP_CAPABILITIES = {
|
|
|
148
148
|
devin: {
|
|
149
149
|
status: "native_smoke_passed",
|
|
150
150
|
mediation: "native",
|
|
151
|
-
targetVersion: "devin 2026.
|
|
151
|
+
targetVersion: "devin 2026.8.18 (16737566)",
|
|
152
152
|
entrypoint: { command: "devin", args: ["acp"] },
|
|
153
153
|
runtimeEnabled: false,
|
|
154
154
|
smokeSupported: true,
|
|
@@ -777,7 +777,7 @@ const TOOL_CONTROLS = {
|
|
|
777
777
|
supported: true,
|
|
778
778
|
requestField: "permissionMode",
|
|
779
779
|
cliFlag: "--permission-mode",
|
|
780
|
-
behavior: "Maps to Devin CLI --permission-mode:
|
|
780
|
+
behavior: "Maps to Devin CLI --permission-mode: auto auto-approves read-only tools; smart additionally auto-runs actions a fast model judges safe; dangerous auto-approves all.",
|
|
781
781
|
},
|
|
782
782
|
promptControl: {
|
|
783
783
|
supported: true,
|
|
@@ -806,7 +806,7 @@ const TOOL_CONTROLS = {
|
|
|
806
806
|
],
|
|
807
807
|
},
|
|
808
808
|
};
|
|
809
|
-
|
|
809
|
+
const CAPABILITY_CACHE = new Map();
|
|
810
810
|
export function getProviderToolCapabilities(queryOrCli = {}) {
|
|
811
811
|
const query = normalizeQuery(queryOrCli);
|
|
812
812
|
const providers = query.cli ? [query.cli] : PROVIDER_CAPABILITY_IDS;
|
|
@@ -819,16 +819,19 @@ export function getProviderToolCapabilities(queryOrCli = {}) {
|
|
|
819
819
|
export function getOneProviderToolCapabilities(cli, queryOrCli = {}) {
|
|
820
820
|
const query = normalizeQuery(typeof queryOrCli === "string" ? { cli: queryOrCli } : queryOrCli);
|
|
821
821
|
const cacheKey = capabilityCacheKey(cli, query);
|
|
822
|
-
const cached =
|
|
822
|
+
const cached = CAPABILITY_CACHE.get(cacheKey);
|
|
823
823
|
if (!query.refresh && cached && Date.now() - cached.loadedAt < CAPABILITY_CACHE_TTL_MS) {
|
|
824
824
|
return cached.value;
|
|
825
825
|
}
|
|
826
826
|
const value = buildOneProviderToolCapabilities(cli, query);
|
|
827
|
-
|
|
827
|
+
CAPABILITY_CACHE.set(cacheKey, { loadedAt: Date.now(), value });
|
|
828
828
|
return value;
|
|
829
829
|
}
|
|
830
830
|
export function clearProviderToolCapabilitiesCache() {
|
|
831
|
-
|
|
831
|
+
CAPABILITY_CACHE.clear();
|
|
832
|
+
}
|
|
833
|
+
export function _getCapabilityCacheForTest() {
|
|
834
|
+
return CAPABILITY_CACHE;
|
|
832
835
|
}
|
|
833
836
|
export function providerCapabilityIds() {
|
|
834
837
|
return PROVIDER_CAPABILITY_IDS;
|