llm-cli-gateway 2.9.0 → 2.11.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/CHANGELOG.md +92 -0
- package/README.md +7 -5
- package/dist/acp/event-normalizer.d.ts +42 -0
- package/dist/acp/event-normalizer.js +71 -0
- package/dist/acp/flight-redaction.d.ts +25 -0
- package/dist/acp/flight-redaction.js +40 -0
- package/dist/acp/host-services.d.ts +16 -0
- package/dist/acp/host-services.js +29 -0
- package/dist/acp/permission-bridge.d.ts +15 -0
- package/dist/acp/permission-bridge.js +90 -0
- package/dist/acp/process-manager.js +7 -1
- package/dist/acp/provider-registry.d.ts +1 -1
- package/dist/acp/provider-registry.js +13 -0
- package/dist/acp/runtime.d.ts +35 -0
- package/dist/acp/runtime.js +125 -0
- package/dist/acp/session-map.d.ts +42 -0
- package/dist/acp/session-map.js +67 -0
- package/dist/acp/smoke-harness.d.ts +28 -0
- package/dist/acp/smoke-harness.js +90 -0
- package/dist/api-http.d.ts +18 -0
- package/dist/api-http.js +122 -0
- package/dist/api-provider.d.ts +83 -0
- package/dist/api-provider.js +258 -0
- package/dist/api-request.d.ts +30 -0
- package/dist/api-request.js +51 -0
- package/dist/approval-manager.d.ts +1 -1
- package/dist/approval-manager.js +6 -7
- package/dist/async-job-manager.d.ts +19 -4
- package/dist/async-job-manager.js +211 -35
- package/dist/claude-mcp-config.d.ts +2 -2
- package/dist/claude-mcp-config.js +42 -52
- package/dist/cli-updater.js +16 -1
- package/dist/config.d.ts +20 -0
- package/dist/config.js +93 -35
- package/dist/doctor.d.ts +1 -1
- package/dist/flight-recorder.d.ts +1 -0
- package/dist/flight-recorder.js +11 -0
- package/dist/index.d.ts +56 -5
- package/dist/index.js +670 -48
- package/dist/job-store.d.ts +15 -0
- package/dist/job-store.js +39 -5
- package/dist/mcp-registry.d.ts +17 -0
- package/dist/mcp-registry.js +5 -0
- package/dist/metrics.js +7 -2
- package/dist/model-registry.js +11 -0
- package/dist/prompt-parts.d.ts +6 -6
- package/dist/provider-login-guidance.js +21 -0
- package/dist/provider-status.js +4 -1
- package/dist/provider-tool-capabilities.d.ts +4 -3
- package/dist/provider-tool-capabilities.js +93 -6
- package/dist/request-helpers.d.ts +6 -6
- package/dist/request-helpers.js +1 -4
- package/dist/resources.d.ts +2 -0
- package/dist/resources.js +24 -15
- package/dist/session-manager-pg.js +2 -9
- package/dist/session-manager.d.ts +9 -4
- package/dist/session-manager.js +13 -4
- package/dist/upstream-contracts.js +112 -2
- package/dist/validation-normalizer.d.ts +2 -2
- package/dist/validation-orchestrator.d.ts +2 -0
- package/dist/validation-orchestrator.js +28 -7
- package/dist/validation-tools.d.ts +61 -0
- package/dist/validation-tools.js +36 -21
- package/migrations/005_provider_type_open_api_names.sql +28 -0
- package/npm-shrinkwrap.json +6 -5
- package/package.json +12 -9
package/dist/job-store.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Logger } from "./logger.js";
|
|
2
2
|
import type { PersistenceConfig } from "./config.js";
|
|
3
3
|
export type JobStoreStatus = "running" | "completed" | "failed" | "canceled" | "orphaned";
|
|
4
|
+
export type JobTransport = "process" | "http";
|
|
4
5
|
export interface JobRecord {
|
|
5
6
|
id: string;
|
|
6
7
|
correlationId: string;
|
|
@@ -19,6 +20,9 @@ export interface JobRecord {
|
|
|
19
20
|
pid: number | null;
|
|
20
21
|
expiresAt: string;
|
|
21
22
|
ownerPrincipal: string | null;
|
|
23
|
+
transport: JobTransport;
|
|
24
|
+
httpStatus: number | null;
|
|
25
|
+
payloadJson: string | null;
|
|
22
26
|
}
|
|
23
27
|
export declare function resolveJobStoreDbPath(): string | null;
|
|
24
28
|
export declare function resolveJobRetentionMs(): number;
|
|
@@ -35,6 +39,8 @@ export interface JobStore {
|
|
|
35
39
|
startedAt: string;
|
|
36
40
|
pid: number | null;
|
|
37
41
|
ownerPrincipal?: string | null;
|
|
42
|
+
transport?: JobTransport;
|
|
43
|
+
payloadJson?: string | null;
|
|
38
44
|
}): void;
|
|
39
45
|
recordOutput(id: string, stdout: string, stderr: string, outputTruncated: boolean): void;
|
|
40
46
|
recordComplete(input: {
|
|
@@ -46,6 +52,7 @@ export interface JobStore {
|
|
|
46
52
|
outputTruncated: boolean;
|
|
47
53
|
error: string | null;
|
|
48
54
|
finishedAt: string;
|
|
55
|
+
httpStatus?: number | null;
|
|
49
56
|
}): void;
|
|
50
57
|
getById(id: string): JobRecord | null;
|
|
51
58
|
findByRequestKey(requestKey: string): JobRecord | null;
|
|
@@ -63,6 +70,8 @@ export interface OrphanedJobSnapshot {
|
|
|
63
70
|
stdout: string;
|
|
64
71
|
stderr: string;
|
|
65
72
|
exitCode: number | null;
|
|
73
|
+
transport: JobTransport;
|
|
74
|
+
httpStatus: number | null;
|
|
66
75
|
}
|
|
67
76
|
export declare class SqliteJobStore implements JobStore {
|
|
68
77
|
private logger;
|
|
@@ -91,6 +100,8 @@ export declare class SqliteJobStore implements JobStore {
|
|
|
91
100
|
startedAt: string;
|
|
92
101
|
pid: number | null;
|
|
93
102
|
ownerPrincipal?: string | null;
|
|
103
|
+
transport?: JobTransport;
|
|
104
|
+
payloadJson?: string | null;
|
|
94
105
|
}): void;
|
|
95
106
|
recordOutput(id: string, stdout: string, stderr: string, outputTruncated: boolean): void;
|
|
96
107
|
recordComplete(input: {
|
|
@@ -102,6 +113,7 @@ export declare class SqliteJobStore implements JobStore {
|
|
|
102
113
|
outputTruncated: boolean;
|
|
103
114
|
error: string | null;
|
|
104
115
|
finishedAt: string;
|
|
116
|
+
httpStatus?: number | null;
|
|
105
117
|
}): void;
|
|
106
118
|
getById(id: string): JobRecord | null;
|
|
107
119
|
findByRequestKey(requestKey: string): JobRecord | null;
|
|
@@ -131,6 +143,8 @@ export declare class MemoryJobStore implements JobStore {
|
|
|
131
143
|
startedAt: string;
|
|
132
144
|
pid: number | null;
|
|
133
145
|
ownerPrincipal?: string | null;
|
|
146
|
+
transport?: JobTransport;
|
|
147
|
+
payloadJson?: string | null;
|
|
134
148
|
}): void;
|
|
135
149
|
recordOutput(id: string, stdout: string, stderr: string, outputTruncated: boolean): void;
|
|
136
150
|
recordComplete(input: {
|
|
@@ -142,6 +156,7 @@ export declare class MemoryJobStore implements JobStore {
|
|
|
142
156
|
outputTruncated: boolean;
|
|
143
157
|
error: string | null;
|
|
144
158
|
finishedAt: string;
|
|
159
|
+
httpStatus?: number | null;
|
|
145
160
|
}): void;
|
|
146
161
|
getById(id: string): JobRecord | null;
|
|
147
162
|
findByRequestKey(requestKey: string): JobRecord | null;
|
package/dist/job-store.js
CHANGED
|
@@ -58,6 +58,9 @@ function rowToRecord(row) {
|
|
|
58
58
|
pid: row.pid,
|
|
59
59
|
expiresAt: row.expires_at,
|
|
60
60
|
ownerPrincipal: row.owner_principal ?? null,
|
|
61
|
+
transport: row.transport ?? "process",
|
|
62
|
+
httpStatus: row.http_status ?? null,
|
|
63
|
+
payloadJson: row.payload_json ?? null,
|
|
61
64
|
};
|
|
62
65
|
}
|
|
63
66
|
function ensureJobsOwnerColumn(db) {
|
|
@@ -67,6 +70,19 @@ function ensureJobsOwnerColumn(db) {
|
|
|
67
70
|
db.exec("ALTER TABLE jobs ADD COLUMN owner_principal TEXT");
|
|
68
71
|
}
|
|
69
72
|
}
|
|
73
|
+
function ensureJobsTransportColumns(db) {
|
|
74
|
+
const cols = db.prepare("PRAGMA table_info(jobs)").all();
|
|
75
|
+
const names = new Set(cols.map(col => col?.name));
|
|
76
|
+
if (!names.has("transport")) {
|
|
77
|
+
db.exec("ALTER TABLE jobs ADD COLUMN transport TEXT NOT NULL DEFAULT 'process'");
|
|
78
|
+
}
|
|
79
|
+
if (!names.has("http_status")) {
|
|
80
|
+
db.exec("ALTER TABLE jobs ADD COLUMN http_status INTEGER");
|
|
81
|
+
}
|
|
82
|
+
if (!names.has("payload_json")) {
|
|
83
|
+
db.exec("ALTER TABLE jobs ADD COLUMN payload_json TEXT");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
70
86
|
export class SqliteJobStore {
|
|
71
87
|
logger;
|
|
72
88
|
db;
|
|
@@ -103,7 +119,10 @@ export class SqliteJobStore {
|
|
|
103
119
|
finished_at TEXT,
|
|
104
120
|
pid INTEGER,
|
|
105
121
|
expires_at TEXT NOT NULL,
|
|
106
|
-
owner_principal TEXT
|
|
122
|
+
owner_principal TEXT,
|
|
123
|
+
transport TEXT NOT NULL DEFAULT 'process',
|
|
124
|
+
http_status INTEGER,
|
|
125
|
+
payload_json TEXT
|
|
107
126
|
);
|
|
108
127
|
CREATE INDEX IF NOT EXISTS idx_jobs_request_key ON jobs(request_key);
|
|
109
128
|
CREATE INDEX IF NOT EXISTS idx_jobs_status ON jobs(status);
|
|
@@ -111,6 +130,7 @@ export class SqliteJobStore {
|
|
|
111
130
|
CREATE INDEX IF NOT EXISTS idx_jobs_request_key_finished ON jobs(request_key, finished_at);
|
|
112
131
|
`);
|
|
113
132
|
ensureJobsOwnerColumn(this.db);
|
|
133
|
+
ensureJobsTransportColumns(this.db);
|
|
114
134
|
if (process.platform !== "win32") {
|
|
115
135
|
try {
|
|
116
136
|
chmodSync(dbPath, 0o600);
|
|
@@ -123,10 +143,12 @@ export class SqliteJobStore {
|
|
|
123
143
|
this.insertStmt = this.db.prepare(`
|
|
124
144
|
INSERT INTO jobs (id, correlation_id, request_key, cli, args_json, output_format,
|
|
125
145
|
status, exit_code, stdout, stderr, output_truncated, error,
|
|
126
|
-
started_at, finished_at, pid, expires_at, owner_principal
|
|
146
|
+
started_at, finished_at, pid, expires_at, owner_principal,
|
|
147
|
+
transport, http_status, payload_json)
|
|
127
148
|
VALUES (@id, @correlation_id, @request_key, @cli, @args_json, @output_format,
|
|
128
149
|
@status, @exit_code, @stdout, @stderr, @output_truncated, @error,
|
|
129
|
-
@started_at, @finished_at, @pid, @expires_at, @owner_principal
|
|
150
|
+
@started_at, @finished_at, @pid, @expires_at, @owner_principal,
|
|
151
|
+
@transport, @http_status, @payload_json)
|
|
130
152
|
`);
|
|
131
153
|
this.updateOutputStmt = this.db.prepare(`
|
|
132
154
|
UPDATE jobs SET stdout = @stdout, stderr = @stderr, output_truncated = @output_truncated
|
|
@@ -135,7 +157,8 @@ export class SqliteJobStore {
|
|
|
135
157
|
this.updateCompleteStmt = this.db.prepare(`
|
|
136
158
|
UPDATE jobs SET status = @status, exit_code = @exit_code, stdout = @stdout, stderr = @stderr,
|
|
137
159
|
output_truncated = @output_truncated, error = @error,
|
|
138
|
-
finished_at = @finished_at, expires_at = @expires_at
|
|
160
|
+
finished_at = @finished_at, expires_at = @expires_at,
|
|
161
|
+
http_status = @http_status
|
|
139
162
|
WHERE id = @id
|
|
140
163
|
`);
|
|
141
164
|
this.getByIdStmt = this.db.prepare(`SELECT * FROM jobs WHERE id = ?`);
|
|
@@ -148,7 +171,7 @@ export class SqliteJobStore {
|
|
|
148
171
|
LIMIT 1
|
|
149
172
|
`);
|
|
150
173
|
this.selectRunningOrphansStmt = this.db.prepare(`
|
|
151
|
-
SELECT id, correlation_id, started_at, stdout, stderr, exit_code
|
|
174
|
+
SELECT id, correlation_id, started_at, stdout, stderr, exit_code, transport, http_status
|
|
152
175
|
FROM jobs WHERE status = 'running'
|
|
153
176
|
`);
|
|
154
177
|
this.markOrphanedStmt = this.db.prepare(`
|
|
@@ -180,6 +203,9 @@ export class SqliteJobStore {
|
|
|
180
203
|
pid: input.pid,
|
|
181
204
|
expires_at: FAR_FUTURE_ISO,
|
|
182
205
|
owner_principal: input.ownerPrincipal ?? null,
|
|
206
|
+
transport: input.transport ?? "process",
|
|
207
|
+
http_status: null,
|
|
208
|
+
payload_json: input.payloadJson ?? null,
|
|
183
209
|
});
|
|
184
210
|
}
|
|
185
211
|
recordOutput(id, stdout, stderr, outputTruncated) {
|
|
@@ -202,6 +228,7 @@ export class SqliteJobStore {
|
|
|
202
228
|
error: input.error,
|
|
203
229
|
finished_at: input.finishedAt,
|
|
204
230
|
expires_at: expiresAt,
|
|
231
|
+
http_status: input.httpStatus ?? null,
|
|
205
232
|
});
|
|
206
233
|
}
|
|
207
234
|
getById(id) {
|
|
@@ -224,6 +251,8 @@ export class SqliteJobStore {
|
|
|
224
251
|
stdout: row.stdout ?? "",
|
|
225
252
|
stderr: row.stderr ?? "",
|
|
226
253
|
exitCode: row.exit_code,
|
|
254
|
+
transport: row.transport ?? "process",
|
|
255
|
+
httpStatus: row.http_status ?? null,
|
|
227
256
|
}));
|
|
228
257
|
const result = this.markOrphanedStmt.run(now, expiresAt);
|
|
229
258
|
return { count: Number(result.changes), orphaned };
|
|
@@ -270,6 +299,9 @@ export class MemoryJobStore {
|
|
|
270
299
|
pid: input.pid,
|
|
271
300
|
expiresAt: FAR_FUTURE_ISO,
|
|
272
301
|
ownerPrincipal: input.ownerPrincipal ?? null,
|
|
302
|
+
transport: input.transport ?? "process",
|
|
303
|
+
httpStatus: null,
|
|
304
|
+
payloadJson: input.payloadJson ?? null,
|
|
273
305
|
});
|
|
274
306
|
}
|
|
275
307
|
recordOutput(id, stdout, stderr, outputTruncated) {
|
|
@@ -292,6 +324,8 @@ export class MemoryJobStore {
|
|
|
292
324
|
row.error = input.error;
|
|
293
325
|
row.finishedAt = input.finishedAt;
|
|
294
326
|
row.expiresAt = new Date(Date.parse(input.finishedAt) + this.retentionMs).toISOString();
|
|
327
|
+
if (input.httpStatus !== undefined)
|
|
328
|
+
row.httpStatus = input.httpStatus;
|
|
295
329
|
}
|
|
296
330
|
getById(id) {
|
|
297
331
|
const row = this.rows.get(id);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface ClaudeServerDef {
|
|
2
|
+
command: string;
|
|
3
|
+
args: string[];
|
|
4
|
+
env?: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
export interface RegistryEntry {
|
|
7
|
+
defaultDef: () => ClaudeServerDef;
|
|
8
|
+
forwardEnv?: readonly string[];
|
|
9
|
+
requireEnv?: readonly string[];
|
|
10
|
+
requireCommandOnPath?: boolean;
|
|
11
|
+
approval?: {
|
|
12
|
+
score: number;
|
|
13
|
+
reason: string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export declare const INTERNAL_MCP_REGISTRY: Record<string, RegistryEntry>;
|
|
17
|
+
export declare const CLAUDE_MCP_SERVER_NAMES: readonly string[];
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Stripped at release time by scripts/strip-internal-mcp.mjs.
|
|
2
|
+
// The internal MCP registry is intentionally empty in published builds; the
|
|
3
|
+
// gateway resolves MCP server names from the host's Codex MCP config instead.
|
|
4
|
+
export const INTERNAL_MCP_REGISTRY = {};
|
|
5
|
+
export const CLAUDE_MCP_SERVER_NAMES = [];
|
package/dist/metrics.js
CHANGED
|
@@ -6,7 +6,12 @@ const createEmptyMetrics = () => Object.fromEntries(PROVIDER_TYPES.map(provider
|
|
|
6
6
|
export class PerformanceMetrics {
|
|
7
7
|
metrics = createEmptyMetrics();
|
|
8
8
|
recordRequest(provider, durationMs, success) {
|
|
9
|
-
const metrics = this.metrics[provider]
|
|
9
|
+
const metrics = (this.metrics[provider] ??= {
|
|
10
|
+
requestCount: 0,
|
|
11
|
+
successCount: 0,
|
|
12
|
+
failureCount: 0,
|
|
13
|
+
totalResponseTimeMs: 0,
|
|
14
|
+
});
|
|
10
15
|
metrics.requestCount += 1;
|
|
11
16
|
const normalizedDurationMs = Number.isFinite(durationMs) ? Math.max(0, durationMs) : 0;
|
|
12
17
|
metrics.totalResponseTimeMs += normalizedDurationMs;
|
|
@@ -22,7 +27,7 @@ export class PerformanceMetrics {
|
|
|
22
27
|
let totalRequests = 0;
|
|
23
28
|
let totalSuccesses = 0;
|
|
24
29
|
let totalFailures = 0;
|
|
25
|
-
for (const provider of
|
|
30
|
+
for (const provider of Object.keys(this.metrics)) {
|
|
26
31
|
const metrics = this.metrics[provider];
|
|
27
32
|
const averageResponseTimeMs = metrics.requestCount > 0 ? metrics.totalResponseTimeMs / metrics.requestCount : 0;
|
|
28
33
|
const successRate = metrics.requestCount > 0 ? metrics.successCount / metrics.requestCount : 0;
|
package/dist/model-registry.js
CHANGED
|
@@ -47,6 +47,15 @@ const FALLBACK_INFO = {
|
|
|
47
47
|
},
|
|
48
48
|
modelOrder: ["mistral-medium-3.5", "devstral-small"],
|
|
49
49
|
},
|
|
50
|
+
devin: {
|
|
51
|
+
description: "Cognition's Devin CLI - agentic coding agent that runs in your terminal, multi-model, with handoff to cloud Devin",
|
|
52
|
+
models: {
|
|
53
|
+
opus: "Anthropic Opus frontier model exposed by Devin CLI (e.g. --model opus).",
|
|
54
|
+
"gpt-5.5": "OpenAI GPT frontier model exposed by Devin CLI.",
|
|
55
|
+
"swe-1.6": "Cognition's SWE-1.6 model (also reachable via the /fast slash command).",
|
|
56
|
+
},
|
|
57
|
+
modelOrder: ["opus", "gpt-5.5", "swe-1.6"],
|
|
58
|
+
},
|
|
50
59
|
};
|
|
51
60
|
const MODEL_CACHE_TTL_MS = 2 * 60 * 1000;
|
|
52
61
|
const MAX_GEMINI_HISTORY_FILES = 200;
|
|
@@ -74,6 +83,7 @@ export function getAvailableCliInfo(forceRefresh = false) {
|
|
|
74
83
|
gemini: filterUnverifiedModelHints(info.gemini),
|
|
75
84
|
grok: filterUnverifiedModelHints(info.grok),
|
|
76
85
|
mistral: filterUnverifiedModelHints(info.mistral),
|
|
86
|
+
devin: filterUnverifiedModelHints(info.devin),
|
|
77
87
|
};
|
|
78
88
|
}
|
|
79
89
|
export function clearModelRegistryCache() {
|
|
@@ -111,6 +121,7 @@ function buildCliInfo() {
|
|
|
111
121
|
gemini: cloneInfo(FALLBACK_INFO.gemini),
|
|
112
122
|
grok: cloneInfo(FALLBACK_INFO.grok),
|
|
113
123
|
mistral: cloneInfo(FALLBACK_INFO.mistral),
|
|
124
|
+
devin: cloneInfo(FALLBACK_INFO.devin),
|
|
114
125
|
};
|
|
115
126
|
applyClaudeOverrides(info.claude);
|
|
116
127
|
applyCodexOverrides(info.codex);
|
package/dist/prompt-parts.d.ts
CHANGED
|
@@ -21,32 +21,32 @@ export declare const PromptPartsSchema: z.ZodObject<{
|
|
|
21
21
|
tools: z.ZodOptional<z.ZodBoolean>;
|
|
22
22
|
context: z.ZodOptional<z.ZodBoolean>;
|
|
23
23
|
}, "strict", z.ZodTypeAny, {
|
|
24
|
-
tools?: boolean | undefined;
|
|
25
24
|
system?: boolean | undefined;
|
|
25
|
+
tools?: boolean | undefined;
|
|
26
26
|
context?: boolean | undefined;
|
|
27
27
|
}, {
|
|
28
|
-
tools?: boolean | undefined;
|
|
29
28
|
system?: boolean | undefined;
|
|
29
|
+
tools?: boolean | undefined;
|
|
30
30
|
context?: boolean | undefined;
|
|
31
31
|
}>>;
|
|
32
32
|
}, "strip", z.ZodTypeAny, {
|
|
33
33
|
task: string;
|
|
34
|
-
tools?: string | undefined;
|
|
35
34
|
system?: string | undefined;
|
|
35
|
+
tools?: string | undefined;
|
|
36
36
|
context?: string | undefined;
|
|
37
37
|
cacheControl?: {
|
|
38
|
-
tools?: boolean | undefined;
|
|
39
38
|
system?: boolean | undefined;
|
|
39
|
+
tools?: boolean | undefined;
|
|
40
40
|
context?: boolean | undefined;
|
|
41
41
|
} | undefined;
|
|
42
42
|
}, {
|
|
43
43
|
task: string;
|
|
44
|
-
tools?: string | undefined;
|
|
45
44
|
system?: string | undefined;
|
|
45
|
+
tools?: string | undefined;
|
|
46
46
|
context?: string | undefined;
|
|
47
47
|
cacheControl?: {
|
|
48
|
-
tools?: boolean | undefined;
|
|
49
48
|
system?: boolean | undefined;
|
|
49
|
+
tools?: boolean | undefined;
|
|
50
50
|
context?: boolean | undefined;
|
|
51
51
|
} | undefined;
|
|
52
52
|
}>;
|
|
@@ -94,6 +94,27 @@ const GUIDANCE = {
|
|
|
94
94
|
expected: "Vibe CLI is installed; doctor checks ~/.vibe/config.toml for an explicit session_logging.enabled=false override",
|
|
95
95
|
},
|
|
96
96
|
},
|
|
97
|
+
devin: {
|
|
98
|
+
provider: "devin",
|
|
99
|
+
displayName: "Devin CLI",
|
|
100
|
+
install: {
|
|
101
|
+
summary: "Install Devin CLI using Cognition's current official installer.",
|
|
102
|
+
commands: [
|
|
103
|
+
"curl -fsSL https://cli.devin.ai/install.sh | bash",
|
|
104
|
+
"irm https://static.devin.ai/cli/setup.ps1 | iex",
|
|
105
|
+
],
|
|
106
|
+
documentationUrl: "https://docs.devin.ai/cli",
|
|
107
|
+
},
|
|
108
|
+
login: {
|
|
109
|
+
summary: "Sign in through Devin CLI's official browser OAuth flow.",
|
|
110
|
+
commands: ["devin auth login", "devin auth login --force-manual-token-flow"],
|
|
111
|
+
credentialHandling: "Let Devin store credentials via `devin auth login` (or WINDSURF_API_KEY for ACP). Do not paste Devin tokens or cog_* keys into the gateway or a remote chat.",
|
|
112
|
+
},
|
|
113
|
+
verification: {
|
|
114
|
+
command: "devin auth status",
|
|
115
|
+
expected: "CLI is installed and `devin auth status` reports an authenticated session",
|
|
116
|
+
},
|
|
117
|
+
},
|
|
97
118
|
};
|
|
98
119
|
export function getProviderLoginGuidance(provider) {
|
|
99
120
|
return GUIDANCE[provider];
|
package/dist/provider-status.js
CHANGED
|
@@ -4,13 +4,14 @@ import { join } from "node:path";
|
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
5
|
import { getProviderLoginGuidance } from "./provider-login-guidance.js";
|
|
6
6
|
import { envWithExtendedPath, getExtendedPath, providerCommandName, resolveCommandForSpawn, } from "./executor.js";
|
|
7
|
-
const PROVIDERS = ["claude", "codex", "gemini", "grok", "mistral"];
|
|
7
|
+
const PROVIDERS = ["claude", "codex", "gemini", "grok", "mistral", "devin"];
|
|
8
8
|
const VERSION_ARGS = {
|
|
9
9
|
claude: ["--version"],
|
|
10
10
|
codex: ["--version"],
|
|
11
11
|
gemini: ["--version"],
|
|
12
12
|
grok: ["--version"],
|
|
13
13
|
mistral: ["--version"],
|
|
14
|
+
devin: ["--version"],
|
|
14
15
|
};
|
|
15
16
|
export const PROVIDER_COMMANDS = {
|
|
16
17
|
claude: "claude",
|
|
@@ -18,12 +19,14 @@ export const PROVIDER_COMMANDS = {
|
|
|
18
19
|
gemini: providerCommandName("gemini"),
|
|
19
20
|
grok: "grok",
|
|
20
21
|
mistral: providerCommandName("mistral"),
|
|
22
|
+
devin: providerCommandName("devin"),
|
|
21
23
|
};
|
|
22
24
|
const LOGIN_CHECKS = {
|
|
23
25
|
claude: ["auth", "status", "--json"],
|
|
24
26
|
codex: ["login", "status"],
|
|
25
27
|
grok: ["inspect", "--json"],
|
|
26
28
|
mistral: ["auth", "status"],
|
|
29
|
+
devin: ["auth", "status"],
|
|
27
30
|
};
|
|
28
31
|
export function listProviderRuntimeStatuses() {
|
|
29
32
|
return Object.fromEntries(PROVIDERS.map(provider => [provider, getProviderRuntimeStatus(provider)]));
|
|
@@ -7,7 +7,8 @@ export interface ProviderToolControl {
|
|
|
7
7
|
cliFlag?: string;
|
|
8
8
|
behavior: string;
|
|
9
9
|
}
|
|
10
|
-
export type
|
|
10
|
+
export type KnownProviderCapabilityId = CliType | "grok_api";
|
|
11
|
+
export type ProviderCapabilityId = KnownProviderCapabilityId | (string & {});
|
|
11
12
|
export type ProviderKind = "cli" | "api";
|
|
12
13
|
export type UnsupportedInputBehavior = "reject" | "ignored" | "not_supported" | "approval_tracking_only" | "deprecated";
|
|
13
14
|
export type ProviderToolConfidence = "high" | "medium" | "low";
|
|
@@ -87,7 +88,7 @@ export interface AcpContractMetadata {
|
|
|
87
88
|
adapterSupportIsNotNative: true;
|
|
88
89
|
contractDoc: "docs/acp-contract.md";
|
|
89
90
|
nonGoals: readonly string[];
|
|
90
|
-
providers: Readonly<Record<
|
|
91
|
+
providers: Readonly<Record<KnownProviderCapabilityId, AcpProviderContract>>;
|
|
91
92
|
}
|
|
92
93
|
export declare const ACP_CONTRACT: AcpContractMetadata;
|
|
93
94
|
export interface ProviderToolCapabilities {
|
|
@@ -132,4 +133,4 @@ export type ProviderToolCapabilitiesMap = Partial<Record<ProviderCapabilityId, P
|
|
|
132
133
|
export declare function getProviderToolCapabilities(queryOrCli?: ProviderCapabilityQuery | ProviderCapabilityId): ProviderToolCapabilitiesMap;
|
|
133
134
|
export declare function getOneProviderToolCapabilities(cli: ProviderCapabilityId, queryOrCli?: ProviderCapabilityQuery | ProviderCapabilityId): ProviderToolCapabilities;
|
|
134
135
|
export declare function clearProviderToolCapabilitiesCache(): void;
|
|
135
|
-
export declare function providerCapabilityIds(): readonly
|
|
136
|
+
export declare function providerCapabilityIds(): readonly KnownProviderCapabilityId[];
|
|
@@ -55,6 +55,10 @@ export const ACP_CONTRACT = {
|
|
|
55
55
|
classification: "absent_watchlist",
|
|
56
56
|
summary: "Grok API is an HTTP provider with no ACP process transport; watchlist item only.",
|
|
57
57
|
},
|
|
58
|
+
devin: {
|
|
59
|
+
classification: "native_candidate",
|
|
60
|
+
summary: "Cognition Devin CLI exposes a native ACP server via `devin acp` (stdio); Slice D1 initialize + session/new smoke passed (protocolVersion 1, third runtime pilot). Runtime routing stays config-gated.",
|
|
61
|
+
},
|
|
58
62
|
},
|
|
59
63
|
};
|
|
60
64
|
const ACP_DOCS_REFERENCE = "docs/plans/first-class-acp-gateway-extension.dag.toml";
|
|
@@ -141,6 +145,21 @@ const ACP_CAPABILITIES = {
|
|
|
141
145
|
caveats: ["ACP is a CLI-stdio transport; the HTTP API provider has no ACP surface."],
|
|
142
146
|
docs: ACP_DOCS_REFERENCE,
|
|
143
147
|
},
|
|
148
|
+
devin: {
|
|
149
|
+
status: "native_smoke_passed",
|
|
150
|
+
mediation: "native",
|
|
151
|
+
targetVersion: "devin 2026.5.26-8 (1a388fa9)",
|
|
152
|
+
entrypoint: { command: "devin", args: ["acp"] },
|
|
153
|
+
runtimeEnabled: false,
|
|
154
|
+
smokeSupported: true,
|
|
155
|
+
smokeStatus: "passed",
|
|
156
|
+
caveats: [
|
|
157
|
+
'Native ACP via `devin acp` (stdio JSON-RPC); Slice D1 initialize + session/new smoke passed (protocolVersion 1, agent "Affogato").',
|
|
158
|
+
"Credentials come from `devin auth login` or WINDSURF_API_KEY; empty-env smoke is not expected to pass.",
|
|
159
|
+
"Runtime routing stays disabled until ACP is enabled in gateway config.",
|
|
160
|
+
],
|
|
161
|
+
docs: ACP_DOCS_REFERENCE,
|
|
162
|
+
},
|
|
144
163
|
};
|
|
145
164
|
function cloneAcpCapability(acp) {
|
|
146
165
|
return {
|
|
@@ -151,7 +170,13 @@ function cloneAcpCapability(acp) {
|
|
|
151
170
|
caveats: [...acp.caveats],
|
|
152
171
|
};
|
|
153
172
|
}
|
|
154
|
-
const PROVIDER_CAPABILITY_IDS = [
|
|
173
|
+
const PROVIDER_CAPABILITY_IDS = [
|
|
174
|
+
...CLI_TYPES,
|
|
175
|
+
"grok_api",
|
|
176
|
+
];
|
|
177
|
+
function isKnownProviderCapabilityId(cli) {
|
|
178
|
+
return PROVIDER_CAPABILITY_IDS.includes(cli);
|
|
179
|
+
}
|
|
155
180
|
const KNOWN_PROVIDER_TOOLS = {
|
|
156
181
|
grok: [
|
|
157
182
|
"image_gen",
|
|
@@ -382,7 +407,7 @@ const TOOL_CONTROLS = {
|
|
|
382
407
|
gemini: {
|
|
383
408
|
providerKind: "cli",
|
|
384
409
|
gatewayRequestTools: ["gemini_request", "gemini_request_async"],
|
|
385
|
-
summary: "Antigravity/Gemini owns its runtime tool catalog; this gateway rejects non-empty tool allow-list and MCP
|
|
410
|
+
summary: "Antigravity/Gemini owns its runtime tool catalog and MCP configuration; this gateway rejects non-empty tool allow-list inputs and tracks requested MCP servers for approvals.",
|
|
386
411
|
controls: {
|
|
387
412
|
allowlist: {
|
|
388
413
|
supported: false,
|
|
@@ -396,7 +421,7 @@ const TOOL_CONTROLS = {
|
|
|
396
421
|
mcpServers: {
|
|
397
422
|
supported: false,
|
|
398
423
|
requestField: "mcpServers",
|
|
399
|
-
behavior: "
|
|
424
|
+
behavior: "Accepted for approval tracking only; Antigravity manages its own MCP configuration outside the gateway.",
|
|
400
425
|
},
|
|
401
426
|
nativeSkills: {
|
|
402
427
|
supported: true,
|
|
@@ -438,8 +463,8 @@ const TOOL_CONTROLS = {
|
|
|
438
463
|
},
|
|
439
464
|
{
|
|
440
465
|
input: "mcpServers",
|
|
441
|
-
behavior: "
|
|
442
|
-
details: "
|
|
466
|
+
behavior: "approval_tracking_only",
|
|
467
|
+
details: "Accepted only for gateway approval tracking; Antigravity owns MCP configuration.",
|
|
443
468
|
},
|
|
444
469
|
{
|
|
445
470
|
input: "attachments",
|
|
@@ -594,7 +619,7 @@ const TOOL_CONTROLS = {
|
|
|
594
619
|
permissionMode: {
|
|
595
620
|
supported: true,
|
|
596
621
|
requestField: "permissionMode",
|
|
597
|
-
behavior: "Passes Vibe agent
|
|
622
|
+
behavior: "Passes any Vibe --agent name through (builtins like plan/auto-approve, plus install-gated and custom agents).",
|
|
598
623
|
},
|
|
599
624
|
outputFormat: {
|
|
600
625
|
supported: true,
|
|
@@ -726,6 +751,60 @@ const TOOL_CONTROLS = {
|
|
|
726
751
|
},
|
|
727
752
|
],
|
|
728
753
|
},
|
|
754
|
+
devin: {
|
|
755
|
+
providerKind: "cli",
|
|
756
|
+
gatewayRequestTools: ["devin_request", "devin_request_async"],
|
|
757
|
+
summary: "Cognition Devin CLI runs an agentic coding session; the gateway passes the prompt, model, permission mode, and session resume. Devin owns its own tools, MCP, skills, and rules.",
|
|
758
|
+
controls: {
|
|
759
|
+
allowlist: {
|
|
760
|
+
supported: false,
|
|
761
|
+
behavior: "Devin CLI has no per-request tool allow-list flag; tool gating is via permission modes.",
|
|
762
|
+
},
|
|
763
|
+
denylist: {
|
|
764
|
+
supported: false,
|
|
765
|
+
behavior: "Devin CLI has no per-request tool deny-list flag.",
|
|
766
|
+
},
|
|
767
|
+
mcpServers: {
|
|
768
|
+
supported: false,
|
|
769
|
+
requestField: "mcpServers",
|
|
770
|
+
behavior: "Accepted for approval tracking only; Devin manages its own MCP config via `devin mcp`.",
|
|
771
|
+
},
|
|
772
|
+
nativeSkills: {
|
|
773
|
+
supported: false,
|
|
774
|
+
behavior: "Devin manages its own skills (`devin skills`); the gateway does not discover them.",
|
|
775
|
+
},
|
|
776
|
+
permissionMode: {
|
|
777
|
+
supported: true,
|
|
778
|
+
requestField: "permissionMode",
|
|
779
|
+
cliFlag: "--permission-mode",
|
|
780
|
+
behavior: "Maps to Devin CLI --permission-mode: normal (alias auto) auto-approves read-only tools; dangerous (aliases yolo, bypass) auto-approves all.",
|
|
781
|
+
},
|
|
782
|
+
promptControl: {
|
|
783
|
+
supported: true,
|
|
784
|
+
requestField: "promptFile",
|
|
785
|
+
cliFlag: "--prompt-file",
|
|
786
|
+
behavior: "Loads the initial prompt from a file.",
|
|
787
|
+
},
|
|
788
|
+
session: {
|
|
789
|
+
supported: true,
|
|
790
|
+
requestField: "sessionId/resumeLatest/createNewSession",
|
|
791
|
+
cliFlag: "--resume/--continue",
|
|
792
|
+
behavior: "Resumes a Devin CLI session (--resume <id>) or the most recent in cwd (--continue).",
|
|
793
|
+
},
|
|
794
|
+
},
|
|
795
|
+
features: baseFeatures({
|
|
796
|
+
sessionContinuity: true,
|
|
797
|
+
approvalAndSandboxControls: true,
|
|
798
|
+
promptControl: true,
|
|
799
|
+
}),
|
|
800
|
+
unsupportedInputs: [
|
|
801
|
+
{
|
|
802
|
+
input: "mcpServers",
|
|
803
|
+
behavior: "approval_tracking_only",
|
|
804
|
+
details: "Accepted only for gateway approval tracking; Devin owns MCP config via `devin mcp`.",
|
|
805
|
+
},
|
|
806
|
+
],
|
|
807
|
+
},
|
|
729
808
|
};
|
|
730
809
|
let capabilityCache = new Map();
|
|
731
810
|
export function getProviderToolCapabilities(queryOrCli = {}) {
|
|
@@ -756,6 +835,10 @@ export function providerCapabilityIds() {
|
|
|
756
835
|
}
|
|
757
836
|
function buildOneProviderToolCapabilities(cli, query) {
|
|
758
837
|
const warnings = [];
|
|
838
|
+
if (!isKnownProviderCapabilityId(cli)) {
|
|
839
|
+
throw new Error(`No tool-capability metadata for provider "${cli}". ` +
|
|
840
|
+
`Known providers: ${PROVIDER_CAPABILITY_IDS.join(", ")}.`);
|
|
841
|
+
}
|
|
759
842
|
const definition = TOOL_CONTROLS[cli];
|
|
760
843
|
const discoveredSkills = query.includeSkills && cli !== "grok_api" ? discoverSkills(cli, warnings, query) : [];
|
|
761
844
|
const discoveredProviderTools = query.includeProviderTools
|
|
@@ -837,6 +920,8 @@ function skillRoots(cli) {
|
|
|
837
920
|
];
|
|
838
921
|
case "mistral":
|
|
839
922
|
return [{ path: path.join(home, ".vibe", "skills"), source: "user" }];
|
|
923
|
+
case "devin":
|
|
924
|
+
return [];
|
|
840
925
|
}
|
|
841
926
|
}
|
|
842
927
|
function readSkill(cli, skillPath, fallbackName, source, warnings, query) {
|
|
@@ -989,6 +1074,8 @@ function discoverConfigSurfaces(cli, query, discoveredSkills) {
|
|
|
989
1074
|
case "mistral":
|
|
990
1075
|
addVibeConfigSurfaces(surfaces, query);
|
|
991
1076
|
break;
|
|
1077
|
+
case "devin":
|
|
1078
|
+
break;
|
|
992
1079
|
}
|
|
993
1080
|
return surfaces;
|
|
994
1081
|
}
|
|
@@ -32,8 +32,8 @@ export declare function resolveMistralSessionArgs(opts: {
|
|
|
32
32
|
resumeLatest?: boolean;
|
|
33
33
|
createNewSession?: boolean;
|
|
34
34
|
}): SessionResumeResult;
|
|
35
|
-
export declare const
|
|
36
|
-
export type MistralAgentMode =
|
|
35
|
+
export declare const MISTRAL_BUILTIN_AGENT_MODES: readonly ["default", "plan", "accept-edits", "auto-approve"];
|
|
36
|
+
export type MistralAgentMode = string;
|
|
37
37
|
export declare const MISTRAL_DEFAULT_AGENT_MODE: MistralAgentMode;
|
|
38
38
|
export interface PrepareMistralRequestInput {
|
|
39
39
|
prompt: string;
|
|
@@ -105,7 +105,7 @@ export declare const CLAUDE_HIGH_IMPACT_PARAMS_SCHEMA: z.ZodEffects<z.ZodObject<
|
|
|
105
105
|
appendSystemPrompt?: string | undefined;
|
|
106
106
|
maxBudgetUsd?: number | undefined;
|
|
107
107
|
maxTurns?: number | undefined;
|
|
108
|
-
effort?: "
|
|
108
|
+
effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
|
|
109
109
|
excludeDynamicSystemPromptSections?: boolean | undefined;
|
|
110
110
|
}, {
|
|
111
111
|
agent?: string | undefined;
|
|
@@ -115,7 +115,7 @@ export declare const CLAUDE_HIGH_IMPACT_PARAMS_SCHEMA: z.ZodEffects<z.ZodObject<
|
|
|
115
115
|
appendSystemPrompt?: string | undefined;
|
|
116
116
|
maxBudgetUsd?: number | undefined;
|
|
117
117
|
maxTurns?: number | undefined;
|
|
118
|
-
effort?: "
|
|
118
|
+
effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
|
|
119
119
|
excludeDynamicSystemPromptSections?: boolean | undefined;
|
|
120
120
|
}>, {
|
|
121
121
|
agent?: string | undefined;
|
|
@@ -125,7 +125,7 @@ export declare const CLAUDE_HIGH_IMPACT_PARAMS_SCHEMA: z.ZodEffects<z.ZodObject<
|
|
|
125
125
|
appendSystemPrompt?: string | undefined;
|
|
126
126
|
maxBudgetUsd?: number | undefined;
|
|
127
127
|
maxTurns?: number | undefined;
|
|
128
|
-
effort?: "
|
|
128
|
+
effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
|
|
129
129
|
excludeDynamicSystemPromptSections?: boolean | undefined;
|
|
130
130
|
}, {
|
|
131
131
|
agent?: string | undefined;
|
|
@@ -135,7 +135,7 @@ export declare const CLAUDE_HIGH_IMPACT_PARAMS_SCHEMA: z.ZodEffects<z.ZodObject<
|
|
|
135
135
|
appendSystemPrompt?: string | undefined;
|
|
136
136
|
maxBudgetUsd?: number | undefined;
|
|
137
137
|
maxTurns?: number | undefined;
|
|
138
|
-
effort?: "
|
|
138
|
+
effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
|
|
139
139
|
excludeDynamicSystemPromptSections?: boolean | undefined;
|
|
140
140
|
}>;
|
|
141
141
|
export declare const CLAUDE_AGENT_DEFINITION_SCHEMA: z.ZodObject<{
|
package/dist/request-helpers.js
CHANGED
|
@@ -93,14 +93,11 @@ export function resolveMistralSessionArgs(opts) {
|
|
|
93
93
|
}
|
|
94
94
|
return { resumeArgs: [], effectiveSessionId: undefined, userProvidedSession: false };
|
|
95
95
|
}
|
|
96
|
-
export const
|
|
96
|
+
export const MISTRAL_BUILTIN_AGENT_MODES = [
|
|
97
97
|
"default",
|
|
98
98
|
"plan",
|
|
99
99
|
"accept-edits",
|
|
100
100
|
"auto-approve",
|
|
101
|
-
"chat",
|
|
102
|
-
"explore",
|
|
103
|
-
"lean",
|
|
104
101
|
];
|
|
105
102
|
export const MISTRAL_DEFAULT_AGENT_MODE = "auto-approve";
|
|
106
103
|
export function prepareMistralRequest(input) {
|
package/dist/resources.d.ts
CHANGED
|
@@ -33,5 +33,7 @@ export declare class ResourceProvider {
|
|
|
33
33
|
readCacheStateSession(sessionId: string): SessionCacheStats;
|
|
34
34
|
readCacheStateForPrefix(stablePrefixHash: string): PrefixCacheStats;
|
|
35
35
|
listResources(): ResourceDefinition[];
|
|
36
|
+
private ownedSessions;
|
|
37
|
+
private ownedActiveId;
|
|
36
38
|
readResource(uri: string): Promise<ResourceContents | null>;
|
|
37
39
|
}
|