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.
Files changed (36) hide show
  1. package/.agents/skills/async-job-orchestration/SKILL.md +288 -0
  2. package/.agents/skills/implement-review-fix/SKILL.md +154 -0
  3. package/.agents/skills/multi-llm-review/SKILL.md +174 -0
  4. package/.agents/skills/public-demo-session/SKILL.md +100 -0
  5. package/.agents/skills/secure-orchestration/SKILL.md +227 -0
  6. package/.agents/skills/session-workflow/SKILL.md +271 -0
  7. package/CHANGELOG.md +63 -1
  8. package/README.md +86 -27
  9. package/dist/acp/provider-registry.js +6 -6
  10. package/dist/api-provider.d.ts +7 -0
  11. package/dist/api-provider.js +7 -0
  12. package/dist/api-request.js +1 -0
  13. package/dist/async-job-manager.d.ts +11 -1
  14. package/dist/async-job-manager.js +44 -3
  15. package/dist/config.d.ts +2 -0
  16. package/dist/config.js +3 -0
  17. package/dist/index.d.ts +40 -4
  18. package/dist/index.js +611 -158
  19. package/dist/job-store.d.ts +48 -1
  20. package/dist/job-store.js +184 -0
  21. package/dist/provider-codegen.js +3 -0
  22. package/dist/provider-tool-capabilities.d.ts +4 -0
  23. package/dist/provider-tool-capabilities.js +16 -13
  24. package/dist/upstream-contracts.d.ts +1 -0
  25. package/dist/upstream-contracts.js +202 -45
  26. package/dist/validation-orchestrator.d.ts +5 -2
  27. package/dist/validation-orchestrator.js +71 -5
  28. package/dist/validation-receipt.d.ts +68 -0
  29. package/dist/validation-receipt.js +245 -0
  30. package/dist/validation-report.d.ts +4 -2
  31. package/dist/validation-report.js +18 -1
  32. package/dist/validation-tools.js +58 -9
  33. package/npm-shrinkwrap.json +5 -5
  34. package/package.json +10 -4
  35. package/dist/xai-api-provider.d.ts +0 -43
  36. package/dist/xai-api-provider.js +0 -191
@@ -0,0 +1,68 @@
1
+ import type { AsyncJobManager } from "./async-job-manager.js";
2
+ import type { ValidationRunRecord, ValidationRunStore } from "./job-store.js";
3
+ import { type ValidationReport } from "./validation-report.js";
4
+ export declare const VALIDATION_RECEIPT_SCHEMA_VERSION = "validation-receipt.v1";
5
+ export interface ReceiptDeps {
6
+ asyncJobManager: AsyncJobManager;
7
+ validationRunStore?: ValidationRunStore | null;
8
+ }
9
+ export type ValidationReportV1Content = ValidationReport["structuredContent"];
10
+ export interface ValidationReceipt {
11
+ schemaVersion: string;
12
+ validationId: string;
13
+ ownerPrincipal: string;
14
+ mintedAt: string;
15
+ intent: string;
16
+ models: string[];
17
+ report: ValidationReportV1Content;
18
+ humanReadable: string;
19
+ canonicalSha256: string;
20
+ prevSha256?: string | null;
21
+ seq?: number | null;
22
+ signature?: string | null;
23
+ }
24
+ export interface ValidationRunState {
25
+ validationId: string;
26
+ status: ValidationRunRecord["status"];
27
+ providers: Array<{
28
+ provider: string;
29
+ jobId: string;
30
+ status: string;
31
+ }>;
32
+ judge: {
33
+ provider: string;
34
+ jobId: string;
35
+ status: string;
36
+ } | null;
37
+ }
38
+ export interface RawResponse {
39
+ provider: string;
40
+ jobId: string;
41
+ text: string;
42
+ }
43
+ export type ValidationReceiptResult = {
44
+ status: "minted";
45
+ validationId: string;
46
+ receipt: ValidationReceipt;
47
+ mintedAt: string;
48
+ rawResponses?: RawResponse[];
49
+ } | {
50
+ status: "pending";
51
+ validationId: string;
52
+ run: ValidationRunState;
53
+ } | {
54
+ status: "expired_unminted";
55
+ validationId: string;
56
+ } | {
57
+ status: "not_found";
58
+ validationId: string;
59
+ };
60
+ export declare function canonicalJson(value: unknown): string;
61
+ export declare function computeCanonicalSha256(structuredContent: ValidationReportV1Content): string;
62
+ export declare function resolveValidationReceipt(deps: ReceiptDeps, validationId: string, opts: {
63
+ caller: string;
64
+ includeRawResponses?: boolean;
65
+ }): ValidationReceiptResult;
66
+ export declare function eagerMintFromValidationId(deps: ReceiptDeps, validationId: string): void;
67
+ export declare function eagerMintFromJobId(deps: ReceiptDeps, jobId: string): void;
68
+ export declare function currentCaller(): string;
@@ -0,0 +1,245 @@
1
+ import { createHash } from "node:crypto";
2
+ import { normalizeJobResult, normalizeSkippedProvider } from "./validation-normalizer.js";
3
+ import { buildValidationReport, deriveValidationRunStatus, renderHumanReport, } from "./validation-report.js";
4
+ import { getRequestContext, principalCanAccess, resolveOwnerPrincipal } from "./request-context.js";
5
+ export const VALIDATION_RECEIPT_SCHEMA_VERSION = "validation-receipt.v1";
6
+ const TERMINAL_JOB_STATUSES = new Set(["completed", "failed", "canceled", "orphaned"]);
7
+ export function canonicalJson(value) {
8
+ return JSON.stringify(sortDeep(value));
9
+ }
10
+ function sortDeep(value) {
11
+ if (Array.isArray(value))
12
+ return value.map(sortDeep);
13
+ if (value && typeof value === "object") {
14
+ const out = {};
15
+ for (const key of Object.keys(value).sort()) {
16
+ out[key] = sortDeep(value[key]);
17
+ }
18
+ return out;
19
+ }
20
+ return value;
21
+ }
22
+ export function computeCanonicalSha256(structuredContent) {
23
+ return createHash("sha256").update(canonicalJson(structuredContent), "utf8").digest("hex");
24
+ }
25
+ function isTerminal(status) {
26
+ return TERMINAL_JOB_STATUSES.has(status);
27
+ }
28
+ function parseRequest(requestJson) {
29
+ try {
30
+ const parsed = JSON.parse(requestJson);
31
+ return parsed && typeof parsed === "object" ? parsed : {};
32
+ }
33
+ catch {
34
+ return {};
35
+ }
36
+ }
37
+ function tryMint(deps, run) {
38
+ const store = deps.validationRunStore;
39
+ if (!store)
40
+ return { kind: "pending" };
41
+ const providerResults = [];
42
+ for (const link of run.providerLinks) {
43
+ const jobResult = deps.asyncJobManager.getJobResult(link.jobId);
44
+ if (!jobResult)
45
+ return { kind: "evicted" };
46
+ if (!isTerminal(jobResult.status))
47
+ return { kind: "pending" };
48
+ providerResults.push({ link, result: normalizeJobResult(link.provider, null, jobResult) });
49
+ }
50
+ let judgeStatus = null;
51
+ if (run.judgeLink) {
52
+ const judgeResult = deps.asyncJobManager.getJobResult(run.judgeLink.jobId);
53
+ if (!judgeResult)
54
+ return { kind: "evicted" };
55
+ if (!isTerminal(judgeResult.status))
56
+ return { kind: "pending" };
57
+ judgeStatus = judgeResult.status;
58
+ }
59
+ const request = parseRequest(run.requestJson);
60
+ const requested = Array.isArray(request.modelList) ? request.modelList : [];
61
+ const dispatched = new Set(run.providerLinks.map(link => link.provider));
62
+ const results = providerResults.map(entry => entry.result);
63
+ for (const provider of requested) {
64
+ if (!dispatched.has(provider)) {
65
+ results.push(normalizeSkippedProvider(provider, "Provider was not dispatched for this run."));
66
+ }
67
+ }
68
+ const judgeCompleted = judgeStatus === "completed";
69
+ const synthesis = run.judgeLink
70
+ ? {
71
+ status: judgeCompleted ? "completed" : "skipped",
72
+ judgeModel: run.judgeLink.provider,
73
+ rawJobReference: {
74
+ jobId: run.judgeLink.jobId,
75
+ correlationId: run.judgeLink.correlationId,
76
+ statusTool: "job_status",
77
+ resultTool: "job_result",
78
+ },
79
+ note: judgeCompleted
80
+ ? "Judge synthesis completed."
81
+ : `Judge job ended in '${judgeStatus}' without a synthesis result.`,
82
+ }
83
+ : {
84
+ status: "not_requested",
85
+ judgeModel: null,
86
+ rawJobReference: null,
87
+ note: "No judge synthesis was requested.",
88
+ };
89
+ const modelList = (requested.length > 0 ? requested : Array.from(dispatched));
90
+ const report = buildValidationReport({
91
+ validationId: run.validationId,
92
+ status: deriveValidationRunStatus(results, synthesis.status),
93
+ startedAt: run.createdAt,
94
+ intent: run.intent,
95
+ originalRequest: {
96
+ question: request.question,
97
+ content: request.content,
98
+ focus: request.focus,
99
+ },
100
+ modelList,
101
+ results,
102
+ synthesis,
103
+ });
104
+ const structuredContent = report.structuredContent;
105
+ const record = {
106
+ validationId: run.validationId,
107
+ ownerPrincipal: run.ownerPrincipal,
108
+ mintedAt: new Date().toISOString(),
109
+ schemaVersion: VALIDATION_RECEIPT_SCHEMA_VERSION,
110
+ reportJson: JSON.stringify(structuredContent),
111
+ canonicalSha256: computeCanonicalSha256(structuredContent),
112
+ prevSha256: null,
113
+ seq: null,
114
+ signature: null,
115
+ models: structuredContent.modelList,
116
+ hasMaterialDisagreement: structuredContent.disagreements.hasMaterialDisagreement,
117
+ confidence: structuredContent.confidence,
118
+ };
119
+ store.recordValidationReceipt(record);
120
+ store.setValidationRunStatus(run.validationId, "finalized");
121
+ const stored = store.getValidationReceipt(run.validationId);
122
+ return { kind: "minted", record: stored ?? record };
123
+ }
124
+ function receiptEnvelope(record) {
125
+ const report = JSON.parse(record.reportJson);
126
+ return {
127
+ schemaVersion: record.schemaVersion,
128
+ validationId: record.validationId,
129
+ ownerPrincipal: record.ownerPrincipal,
130
+ mintedAt: record.mintedAt,
131
+ intent: report.intent,
132
+ models: record.models,
133
+ report,
134
+ humanReadable: renderHumanReport(report),
135
+ canonicalSha256: record.canonicalSha256,
136
+ prevSha256: record.prevSha256,
137
+ seq: record.seq,
138
+ signature: record.signature,
139
+ };
140
+ }
141
+ function collectRawResponses(deps, receipt, caller) {
142
+ const out = [];
143
+ const refs = [];
144
+ for (const output of receipt.report.perModelOutputs) {
145
+ if (output.jobId)
146
+ refs.push({ provider: output.provider, jobId: output.jobId });
147
+ }
148
+ const judgeRef = receipt.report.synthesis.rawJobReference;
149
+ if (judgeRef?.jobId) {
150
+ refs.push({ provider: receipt.report.synthesis.judgeModel ?? "judge", jobId: judgeRef.jobId });
151
+ }
152
+ for (const ref of refs) {
153
+ if (!principalCanAccess(deps.asyncJobManager.getJobOwner(ref.jobId), caller))
154
+ continue;
155
+ const jobResult = deps.asyncJobManager.getJobResult(ref.jobId);
156
+ if (jobResult)
157
+ out.push({ provider: ref.provider, jobId: ref.jobId, text: jobResult.stdout });
158
+ }
159
+ return out;
160
+ }
161
+ function mintedResult(deps, record, includeRawResponses, caller) {
162
+ const receipt = receiptEnvelope(record);
163
+ return {
164
+ status: "minted",
165
+ validationId: record.validationId,
166
+ receipt,
167
+ mintedAt: record.mintedAt,
168
+ ...(includeRawResponses ? { rawResponses: collectRawResponses(deps, receipt, caller) } : {}),
169
+ };
170
+ }
171
+ function runStateOf(deps, run) {
172
+ const snapStatus = (jobId) => deps.asyncJobManager.getJobSnapshot(jobId)?.status ?? "evicted";
173
+ return {
174
+ validationId: run.validationId,
175
+ status: run.status,
176
+ providers: run.providerLinks.map(link => ({
177
+ provider: link.provider,
178
+ jobId: link.jobId,
179
+ status: snapStatus(link.jobId),
180
+ })),
181
+ judge: run.judgeLink
182
+ ? {
183
+ provider: run.judgeLink.provider,
184
+ jobId: run.judgeLink.jobId,
185
+ status: snapStatus(run.judgeLink.jobId),
186
+ }
187
+ : null,
188
+ };
189
+ }
190
+ export function resolveValidationReceipt(deps, validationId, opts) {
191
+ const store = deps.validationRunStore;
192
+ if (!store)
193
+ return { status: "not_found", validationId };
194
+ const existing = store.getValidationReceipt(validationId);
195
+ if (existing) {
196
+ if (!principalCanAccess(existing.ownerPrincipal, opts.caller)) {
197
+ return { status: "not_found", validationId };
198
+ }
199
+ return mintedResult(deps, existing, opts.includeRawResponses ?? false, opts.caller);
200
+ }
201
+ const run = store.getValidationRun(validationId);
202
+ if (!run || !principalCanAccess(run.ownerPrincipal, opts.caller)) {
203
+ return { status: "not_found", validationId };
204
+ }
205
+ const outcome = tryMint(deps, run);
206
+ if (outcome.kind === "minted") {
207
+ return mintedResult(deps, outcome.record, opts.includeRawResponses ?? false, opts.caller);
208
+ }
209
+ if (outcome.kind === "evicted") {
210
+ return { status: "expired_unminted", validationId };
211
+ }
212
+ return { status: "pending", validationId, run: runStateOf(deps, run) };
213
+ }
214
+ export function eagerMintFromValidationId(deps, validationId) {
215
+ const store = deps.validationRunStore;
216
+ if (!store)
217
+ return;
218
+ try {
219
+ if (store.getValidationReceipt(validationId))
220
+ return;
221
+ const run = store.getValidationRun(validationId);
222
+ if (!run)
223
+ return;
224
+ tryMint(deps, run);
225
+ }
226
+ catch {
227
+ }
228
+ }
229
+ export function eagerMintFromJobId(deps, jobId) {
230
+ const store = deps.validationRunStore;
231
+ if (!store)
232
+ return;
233
+ let validationId = null;
234
+ try {
235
+ validationId = store.getValidationRunIdByJobId(jobId);
236
+ }
237
+ catch {
238
+ return;
239
+ }
240
+ if (validationId)
241
+ eagerMintFromValidationId(deps, validationId);
242
+ }
243
+ export function currentCaller() {
244
+ return resolveOwnerPrincipal(getRequestContext());
245
+ }
@@ -3,7 +3,7 @@ import type { ValidationIntent } from "./validation-prompts.js";
3
3
  export type ValidationReportConfidence = "none" | "low" | "medium" | "high";
4
4
  export interface ValidationReportInput {
5
5
  validationId: string;
6
- status: "running" | "partial" | "not_started";
6
+ status: "running" | "partial" | "not_started" | "completed";
7
7
  startedAt: string;
8
8
  intent: ValidationIntent;
9
9
  originalRequest: {
@@ -14,7 +14,7 @@ export interface ValidationReportInput {
14
14
  modelList: ValidationProvider[];
15
15
  results: NormalizedValidationResult[];
16
16
  synthesis: {
17
- status: "not_requested" | "waiting_for_provider_results" | "running" | "skipped";
17
+ status: "not_requested" | "waiting_for_provider_results" | "running" | "skipped" | "completed";
18
18
  judgeModel: ValidationProvider | null;
19
19
  rawJobReference: NormalizedValidationResult["rawJobReference"];
20
20
  note: string;
@@ -55,3 +55,5 @@ export interface ValidationReport {
55
55
  };
56
56
  }
57
57
  export declare function buildValidationReport(input: ValidationReportInput): ValidationReport;
58
+ export declare function deriveValidationRunStatus(results: NormalizedValidationResult[], synthesisStatus: ValidationReportInput["synthesis"]["status"]): ValidationReportInput["status"];
59
+ export declare function renderHumanReport(content: ValidationReport["structuredContent"]): string;
@@ -37,6 +37,23 @@ export function buildValidationReport(input) {
37
37
  structuredContent,
38
38
  };
39
39
  }
40
+ export function deriveValidationRunStatus(results, synthesisStatus) {
41
+ if (results.length === 0)
42
+ return "not_started";
43
+ const dispatched = results.filter(result => result.status !== "skipped");
44
+ if (dispatched.length === 0)
45
+ return "not_started";
46
+ const allDispatchedTerminal = dispatched.every(result => result.status === "completed" ||
47
+ result.status === "failed" ||
48
+ result.status === "canceled" ||
49
+ result.status === "orphaned");
50
+ const hasSkipped = results.some(result => result.status === "skipped");
51
+ const judgePending = synthesisStatus === "running" || synthesisStatus === "waiting_for_provider_results";
52
+ if (!allDispatchedTerminal || judgePending) {
53
+ return hasSkipped ? "partial" : "running";
54
+ }
55
+ return "completed";
56
+ }
40
57
  function summarizeDisagreement(results) {
41
58
  const completed = results.filter(result => result.status === "completed");
42
59
  const terminalProblems = results.filter(result => ["failed", "canceled", "orphaned", "skipped"].includes(result.status));
@@ -102,7 +119,7 @@ function recommendationFor(results, hasMaterialDisagreement) {
102
119
  }
103
120
  return "Completed provider outputs show no normalized verdict disagreement; review rationales and risks before acting.";
104
121
  }
105
- function renderHumanReport(content) {
122
+ export function renderHumanReport(content) {
106
123
  const lines = [
107
124
  `Validation report ${content.validationId}`,
108
125
  `Status: ${content.status}`,
@@ -2,6 +2,8 @@ import { z } from "zod/v3";
2
2
  import { CLI_TYPES } from "./session-manager.js";
3
3
  import { getAvailableCliInfo } from "./model-registry.js";
4
4
  import { apiProviderCatalogEntry } from "./api-request.js";
5
+ import { getRequestContext, principalCanAccess, resolveOwnerPrincipal } from "./request-context.js";
6
+ import { currentCaller, eagerMintFromJobId, eagerMintFromValidationId, resolveValidationReceipt, } from "./validation-receipt.js";
5
7
  import { collectValidationJobResult, startJudgeSynthesis, startValidationRun, } from "./validation-orchestrator.js";
6
8
  export function buildValidationSchemas(deps) {
7
9
  const apiNames = (deps.apiProviders ?? []).map(p => p.name);
@@ -194,22 +196,32 @@ export function registerValidationTools(server, deps) {
194
196
  .min(1)
195
197
  .describe("Terminal normalized provider results from job_result."),
196
198
  judgeModel: providerSchema.default("codex").describe("Provider to run the judge synthesis."),
199
+ validationId: z
200
+ .string()
201
+ .optional()
202
+ .describe("Optional run id (from the kickoff response) to link this judge job back into the durable validation run."),
197
203
  }, {
198
204
  title: "Synthesize validation",
199
205
  readOnlyHint: false,
200
206
  destructiveHint: true,
201
207
  idempotentHint: false,
202
208
  openWorldHint: true,
203
- }, async ({ question, providerResults, judgeModel }) => textResponse({
204
- success: true,
205
- tool: "synthesize_validation",
206
- readMostly: true,
207
- synthesis: startJudgeSynthesis(deps, {
209
+ }, async ({ question, providerResults, judgeModel, validationId }) => {
210
+ const synthesis = startJudgeSynthesis(deps, {
208
211
  question,
209
212
  providerResults,
210
213
  judgeProvider: judgeModel,
211
- }),
212
- }));
214
+ validationId,
215
+ });
216
+ if (validationId)
217
+ eagerMintFromValidationId(deps, validationId);
218
+ return textResponse({
219
+ success: true,
220
+ tool: "synthesize_validation",
221
+ readMostly: true,
222
+ synthesis,
223
+ });
224
+ });
213
225
  server.tool("list_available_models", "List models and capabilities for every available provider CLI (takes no arguments; complements per-provider list_models).", {}, {
214
226
  title: "All provider models",
215
227
  readOnlyHint: true,
@@ -234,7 +246,8 @@ export function registerValidationTools(server, deps) {
234
246
  openWorldHint: false,
235
247
  }, async ({ jobId }) => {
236
248
  const job = deps.asyncJobManager.getJobSnapshot(jobId);
237
- if (!job) {
249
+ const caller = resolveOwnerPrincipal(getRequestContext());
250
+ if (!job || !principalCanAccess(deps.asyncJobManager.getJobOwner(jobId), caller)) {
238
251
  return textResponse({ success: false, error: "Job not found", jobId });
239
252
  }
240
253
  return textResponse({ success: true, job });
@@ -259,9 +272,11 @@ export function registerValidationTools(server, deps) {
259
272
  openWorldHint: false,
260
273
  }, async ({ jobId, provider, maxChars }) => {
261
274
  const result = deps.asyncJobManager.getJobResult(jobId, maxChars);
262
- if (!result) {
275
+ const caller = resolveOwnerPrincipal(getRequestContext());
276
+ if (!result || !principalCanAccess(deps.asyncJobManager.getJobOwner(jobId), caller)) {
263
277
  return textResponse({ success: false, error: "Job not found", jobId });
264
278
  }
279
+ eagerMintFromJobId(deps, jobId);
265
280
  return textResponse({
266
281
  success: true,
267
282
  result,
@@ -270,4 +285,38 @@ export function registerValidationTools(server, deps) {
270
285
  : null,
271
286
  });
272
287
  });
288
+ if (deps.validationRunStore) {
289
+ server.tool("validation_receipt", "Retrieve the immutable receipt of a terminal cross-LLM validation run by validationId. Returns minted | pending | expired_unminted | not_found (own-or-not-found).", {
290
+ validationId: z
291
+ .string()
292
+ .min(1)
293
+ .describe("The run-level validationId from a validation kickoff response (not a job/correlation id)."),
294
+ format: z
295
+ .enum(["json", "markdown"])
296
+ .default("json")
297
+ .describe("Response format. markdown returns the human-readable rendering (derived on read, never stored or hashed)."),
298
+ includeRawResponses: z
299
+ .boolean()
300
+ .default(false)
301
+ .describe("Inline full provider answer text (read-time only; pulled live per job under the same owner check; never persisted or hashed)."),
302
+ }, {
303
+ title: "Validation receipt",
304
+ readOnlyHint: true,
305
+ destructiveHint: false,
306
+ idempotentHint: true,
307
+ openWorldHint: false,
308
+ }, async ({ validationId, format, includeRawResponses }) => {
309
+ const result = resolveValidationReceipt(deps, validationId, {
310
+ caller: currentCaller(),
311
+ includeRawResponses,
312
+ });
313
+ if (format === "markdown" && result.status === "minted") {
314
+ return {
315
+ content: [{ type: "text", text: result.receipt.humanReadable }],
316
+ structuredContent: result,
317
+ };
318
+ }
319
+ return textResponse(result);
320
+ });
321
+ }
273
322
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "llm-cli-gateway",
3
- "version": "2.10.0",
3
+ "version": "2.12.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "llm-cli-gateway",
9
- "version": "2.10.0",
9
+ "version": "2.12.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@modelcontextprotocol/sdk": "^1.29.0",
@@ -1066,9 +1066,9 @@
1066
1066
  }
1067
1067
  },
1068
1068
  "node_modules/smol-toml": {
1069
- "version": "1.6.1",
1070
- "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz",
1071
- "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==",
1069
+ "version": "1.7.0",
1070
+ "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.0.tgz",
1071
+ "integrity": "sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ==",
1072
1072
  "license": "BSD-3-Clause",
1073
1073
  "engines": {
1074
1074
  "node": ">= 18"
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "llm-cli-gateway",
3
- "version": "2.11.0",
3
+ "version": "2.12.0",
4
4
  "mcpName": "io.github.verivus-oss/llm-cli-gateway",
5
- "description": "MCP server providing unified access to Claude Code, Codex, Gemini, Grok, and Mistral Vibe CLIs with session management, retry logic, async job orchestration, durable job results, and cross-LLM validation.",
5
+ "description": "MCP server providing unified access to Claude Code, Codex, Gemini, Grok, Mistral Vibe, and Devin CLIs with session management, retry logic, async job orchestration, durable job results, and cross-LLM validation.",
6
6
  "license": "MIT",
7
7
  "author": "VerivusAI Labs (https://github.com/verivus-oss)",
8
8
  "repository": {
@@ -52,7 +52,13 @@
52
52
  "README.md",
53
53
  "CHANGELOG.md",
54
54
  "socket.yml",
55
- "LICENSE"
55
+ "LICENSE",
56
+ ".agents/skills/async-job-orchestration/SKILL.md",
57
+ ".agents/skills/multi-llm-review/SKILL.md",
58
+ ".agents/skills/session-workflow/SKILL.md",
59
+ ".agents/skills/secure-orchestration/SKILL.md",
60
+ ".agents/skills/implement-review-fix/SKILL.md",
61
+ ".agents/skills/public-demo-session/SKILL.md"
56
62
  ],
57
63
  "scripts": {
58
64
  "build": "tsc -p tsconfig.build.json",
@@ -105,7 +111,7 @@
105
111
  "devDependencies": {
106
112
  "@eslint/js": "^10.0.1",
107
113
  "@types/better-sqlite3": "^7.6.0",
108
- "@types/node": "^25.9.3",
114
+ "@types/node": "^26.0.0",
109
115
  "@types/pg": "^8.11.10",
110
116
  "@typescript-eslint/eslint-plugin": "^8.61.1",
111
117
  "@typescript-eslint/parser": "^8.59.4",
@@ -1,43 +0,0 @@
1
- import type { Logger } from "./logger.js";
2
- export type XaiResponsesRole = "system" | "user" | "assistant";
3
- export type XaiReasoningEffort = "none" | "low" | "medium" | "high";
4
- export interface XaiResponsesInputMessage {
5
- role: XaiResponsesRole;
6
- content: string;
7
- }
8
- export interface XaiResponsesRequest {
9
- baseUrl: string;
10
- apiKey: string;
11
- model: string;
12
- input: string | XaiResponsesInputMessage[];
13
- instructions?: string;
14
- previousResponseId?: string;
15
- maxOutputTokens?: number;
16
- temperature?: number;
17
- topP?: number;
18
- reasoningEffort?: XaiReasoningEffort;
19
- timeoutMs?: number;
20
- }
21
- export interface XaiResponsesUsage {
22
- inputTokens?: number;
23
- outputTokens?: number;
24
- cacheReadTokens?: number;
25
- costUsd?: number;
26
- raw?: unknown;
27
- }
28
- export interface XaiResponsesResult {
29
- responseId: string | null;
30
- model: string;
31
- status: string | null;
32
- text: string;
33
- usage: XaiResponsesUsage;
34
- raw: unknown;
35
- httpStatus: number;
36
- }
37
- export declare class XaiApiError extends Error {
38
- readonly status: number | null;
39
- readonly responseText: string;
40
- readonly code?: string | undefined;
41
- constructor(message: string, status?: number | null, responseText?: string, code?: string | undefined);
42
- }
43
- export declare function createXaiResponse(params: XaiResponsesRequest, logger?: Logger): Promise<XaiResponsesResult>;