llm-cli-gateway 1.14.0 → 1.15.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 +225 -46
- package/dist/async-job-manager.js +9 -3
- package/dist/index.d.ts +101 -0
- package/dist/index.js +311 -26
- package/dist/session-manager.d.ts +20 -2
- package/dist/session-manager.js +28 -3
- package/dist/worktree-manager.d.ts +41 -0
- package/dist/worktree-manager.js +214 -0
- package/package.json +1 -1
|
@@ -207,15 +207,21 @@ export class AsyncJobManager {
|
|
|
207
207
|
* (sorted keys → JSON-stringified). This prevents two Mistral requests with the
|
|
208
208
|
* same argv but different `VIBE_ACTIVE_MODEL` from deduping onto each other.
|
|
209
209
|
*/
|
|
210
|
-
buildRequestKey(cli, args, env, stdin) {
|
|
210
|
+
buildRequestKey(cli, args, env, stdin, cwd) {
|
|
211
211
|
// Slice κ: stdin participates in the dedup key. Two Claude requests
|
|
212
212
|
// with identical argv but different cache_control content blocks
|
|
213
213
|
// would otherwise collide on dedup and the second caller would get
|
|
214
214
|
// the wrong response. The legacy "no stdin" code path passes
|
|
215
215
|
// stdin=undefined, which serialises to the same empty marker the
|
|
216
216
|
// previous version emitted — non-κ dedup is unchanged.
|
|
217
|
+
// Slice λ: cwd participates similarly. Two requests with identical
|
|
218
|
+
// argv but different worktrees would otherwise collide on dedup and
|
|
219
|
+
// the second caller would receive a response executed in the wrong
|
|
220
|
+
// worktree. cwd=undefined preserves the pre-λ key shape — non-λ
|
|
221
|
+
// dedup is unchanged.
|
|
217
222
|
const extraEnv = canonicaliseEnvForKey(env);
|
|
218
|
-
const
|
|
223
|
+
const withStdin = stdin === undefined ? extraEnv : `${extraEnv}|stdin:${stdin}`;
|
|
224
|
+
const extra = cwd === undefined ? withStdin : `${withStdin}|cwd:${cwd}`;
|
|
219
225
|
return computeRequestKey(cli, args, extra);
|
|
220
226
|
}
|
|
221
227
|
fireOnComplete(job) {
|
|
@@ -449,7 +455,7 @@ export class AsyncJobManager {
|
|
|
449
455
|
*/
|
|
450
456
|
startJobWithDedup(cli, args, correlationId, opts = {}) {
|
|
451
457
|
const { cwd, idleTimeoutMs, outputFormat, forceRefresh, env: extraEnv, stdin, onComplete, flightRecorderEntry, extractUsage, writeFlightStart, } = opts;
|
|
452
|
-
const requestKey = this.buildRequestKey(cli, args, extraEnv, stdin);
|
|
458
|
+
const requestKey = this.buildRequestKey(cli, args, extraEnv, stdin, cwd);
|
|
453
459
|
if (!forceRefresh && this.store) {
|
|
454
460
|
try {
|
|
455
461
|
const existing = this.store.findByRequestKey(requestKey);
|
package/dist/index.d.ts
CHANGED
|
@@ -67,6 +67,36 @@ type GatewayLogger = typeof logger;
|
|
|
67
67
|
*/
|
|
68
68
|
export declare const MAX_TURNS_SCHEMA: z.ZodNumber;
|
|
69
69
|
export declare const MAX_PRICE_SCHEMA: z.ZodNumber;
|
|
70
|
+
/**
|
|
71
|
+
* Slice λ: shared worktree directive for all 10 `*_request` / `*_request_async`
|
|
72
|
+
* tools. `true` creates a fresh worktree under `<repoRoot>/.worktrees/<uuid>`
|
|
73
|
+
* branched from HEAD. `{ name?, ref? }` lets the caller supply a sanitized
|
|
74
|
+
* name and/or git ref (default ref: HEAD).
|
|
75
|
+
*
|
|
76
|
+
* Lifecycle is gateway-owned: the gateway pre-creates the worktree via
|
|
77
|
+
* `git worktree add`, then spawns the child CLI with `cwd: <worktree-path>`.
|
|
78
|
+
* No `-w` / `--worktree` flag is ever emitted to the underlying CLI. When
|
|
79
|
+
* the request carries a sessionId and the session already has a worktree,
|
|
80
|
+
* that worktree is reused. On session_delete or TTL eviction the gateway
|
|
81
|
+
* runs `git worktree remove --force`.
|
|
82
|
+
*
|
|
83
|
+
* Tool response: when a worktree was used, the successful response stdout
|
|
84
|
+
* is prefixed with `[gateway] worktree=<absolute-path>\n` so callers can
|
|
85
|
+
* parse/use the path without a schema change (slice λ §1.d).
|
|
86
|
+
*
|
|
87
|
+
* NOTE: callers should `.gitignore` the `.worktrees/` directory in their
|
|
88
|
+
* repo (the gateway does NOT auto-gitignore — see slice λ spec Q4).
|
|
89
|
+
*/
|
|
90
|
+
export declare const WORKTREE_SCHEMA: z.ZodUnion<[z.ZodBoolean, z.ZodObject<{
|
|
91
|
+
name: z.ZodOptional<z.ZodString>;
|
|
92
|
+
ref: z.ZodOptional<z.ZodString>;
|
|
93
|
+
}, "strict", z.ZodTypeAny, {
|
|
94
|
+
name?: string | undefined;
|
|
95
|
+
ref?: string | undefined;
|
|
96
|
+
}, {
|
|
97
|
+
name?: string | undefined;
|
|
98
|
+
ref?: string | undefined;
|
|
99
|
+
}>]>;
|
|
70
100
|
export declare const SESSION_PROVIDER_VALUES: readonly ["claude", "codex", "gemini", "grok", "mistral"];
|
|
71
101
|
export declare const SESSION_PROVIDER_ENUM: z.ZodEnum<["claude", "codex", "gemini", "grok", "mistral"]>;
|
|
72
102
|
export type SessionProvider = (typeof SESSION_PROVIDER_VALUES)[number];
|
|
@@ -97,6 +127,57 @@ export interface GatewayServerRuntime {
|
|
|
97
127
|
export declare function resolveGatewayServerRuntime(deps?: GatewayServerDeps, options?: {
|
|
98
128
|
isolateState?: boolean;
|
|
99
129
|
}): GatewayServerRuntime;
|
|
130
|
+
/**
|
|
131
|
+
* Slice λ: shape returned by `resolveWorktreeForRequest`. `cwd` is what
|
|
132
|
+
* the spawn helpers (`executeCli`, `startJobWithDedup`) consume;
|
|
133
|
+
* `worktreePath` is what the tool handler embeds in the response prefix
|
|
134
|
+
* so callers can discover the path.
|
|
135
|
+
*/
|
|
136
|
+
export interface ResolvedWorktree {
|
|
137
|
+
cwd?: string;
|
|
138
|
+
worktreePath?: string;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Slice λ: resolve a request's worktree directive into a spawn cwd.
|
|
142
|
+
*
|
|
143
|
+
* - `worktreeOpt` is the Zod-validated input value (boolean |
|
|
144
|
+
* `{ name?, ref? }` | undefined).
|
|
145
|
+
* - When the request has a session AND the session already has a
|
|
146
|
+
* `metadata.worktreePath`, that path is reused (resume semantics).
|
|
147
|
+
* The reused path is returned without touching git; if the directory
|
|
148
|
+
* was externally removed between requests, the next CLI invocation
|
|
149
|
+
* will surface the error naturally.
|
|
150
|
+
* - When no reusable worktree exists, `createWorktree` runs; on success
|
|
151
|
+
* the new path is written to `session.metadata` (only when a session
|
|
152
|
+
* exists — request-scoped worktrees do NOT persist).
|
|
153
|
+
* - Returns `{}` when `worktreeOpt` is undefined/false (preserves
|
|
154
|
+
* pre-λ behaviour at non-worktree call sites).
|
|
155
|
+
* - Errors propagate as `WorktreeError`/`Error`; the caller wraps them
|
|
156
|
+
* in a `createErrorResponse` envelope. Do NOT swallow.
|
|
157
|
+
*
|
|
158
|
+
* Spec: docs/plans/slice-lambda.spec.md §"Implementation surface to
|
|
159
|
+
* verify" §5.
|
|
160
|
+
*/
|
|
161
|
+
export declare function resolveWorktreeForRequest(worktreeOpt: boolean | {
|
|
162
|
+
name?: string;
|
|
163
|
+
ref?: string;
|
|
164
|
+
} | undefined, sessionId: string | undefined, runtime: GatewayServerRuntime): Promise<ResolvedWorktree>;
|
|
165
|
+
/**
|
|
166
|
+
* Slice λ §1.d: response-envelope shape decision for `worktreePath`.
|
|
167
|
+
*
|
|
168
|
+
* We surface the worktree path inline as a stdout prefix
|
|
169
|
+
* (`[gateway] worktree=<absolute-path>\n`) rather than as a
|
|
170
|
+
* structuredContent field or JSON wrapper. Rationale:
|
|
171
|
+
* - zero schema change across all 10 tools and their downstream parsers
|
|
172
|
+
* - matches how other slice features (session warnings, cache_state
|
|
173
|
+
* aggregates) surface side-channel metadata today
|
|
174
|
+
* - callers that want the path can split on the first newline; callers
|
|
175
|
+
* that don't care see a single ignorable header line
|
|
176
|
+
*
|
|
177
|
+
* Use `formatWorktreePrefix(resolution.worktreePath)` once per tool, at
|
|
178
|
+
* the moment a successful response is constructed.
|
|
179
|
+
*/
|
|
180
|
+
export declare function formatWorktreePrefix(worktreePath?: string): string;
|
|
100
181
|
export declare function extractUsageAndCost(cli: "claude" | "codex" | "gemini" | "grok" | "mistral", output: string, outputFormat?: string,
|
|
101
182
|
/**
|
|
102
183
|
* Optional context for off-stdout telemetry sources. Today only Mistral
|
|
@@ -384,6 +465,11 @@ export interface GeminiRequestParams {
|
|
|
384
465
|
attachments?: string[];
|
|
385
466
|
/** Phase 4 slice γ: emit `--skip-trust` for fresh-workspace headless runs. */
|
|
386
467
|
skipTrust?: boolean;
|
|
468
|
+
/** Slice λ: run this request inside a gateway-owned git worktree. */
|
|
469
|
+
worktree?: boolean | {
|
|
470
|
+
name?: string;
|
|
471
|
+
ref?: string;
|
|
472
|
+
};
|
|
387
473
|
}
|
|
388
474
|
export interface HandlerDeps {
|
|
389
475
|
sessionManager: ISessionManager;
|
|
@@ -436,6 +522,11 @@ export interface GrokRequestParams {
|
|
|
436
522
|
allow?: string[];
|
|
437
523
|
/** Phase 4 slice θ: Grok `--deny <RULE>` (repeatable; one entry per --deny instance). */
|
|
438
524
|
deny?: string[];
|
|
525
|
+
/** Slice λ: run this request inside a gateway-owned git worktree. */
|
|
526
|
+
worktree?: boolean | {
|
|
527
|
+
name?: string;
|
|
528
|
+
ref?: string;
|
|
529
|
+
};
|
|
439
530
|
}
|
|
440
531
|
export declare function handleGrokRequest(deps: HandlerDeps, params: GrokRequestParams): Promise<ExtendedToolResponse>;
|
|
441
532
|
export declare function handleGrokRequestAsync(deps: AsyncHandlerDeps, params: Omit<GrokRequestParams, "optimizeResponse">): Promise<ExtendedToolResponse>;
|
|
@@ -470,6 +561,11 @@ export interface MistralRequestParams {
|
|
|
470
561
|
workingDir?: string;
|
|
471
562
|
/** Phase 4 slice ζ: Vibe `--add-dir <DIR>` repeatable add-dir parity. */
|
|
472
563
|
addDir?: string[];
|
|
564
|
+
/** Slice λ: run this request inside a gateway-owned git worktree. */
|
|
565
|
+
worktree?: boolean | {
|
|
566
|
+
name?: string;
|
|
567
|
+
ref?: string;
|
|
568
|
+
};
|
|
473
569
|
}
|
|
474
570
|
export declare function handleMistralRequest(deps: HandlerDeps, params: MistralRequestParams): Promise<ExtendedToolResponse>;
|
|
475
571
|
export declare function handleMistralRequestAsync(deps: AsyncHandlerDeps, params: Omit<MistralRequestParams, "optimizeResponse">): Promise<ExtendedToolResponse>;
|
|
@@ -504,6 +600,11 @@ export declare function handleCodexRequestAsync(deps: AsyncHandlerDeps, params:
|
|
|
504
600
|
ignoreRules?: boolean;
|
|
505
601
|
workingDir?: string;
|
|
506
602
|
addDir?: string[];
|
|
603
|
+
/** Slice λ: run this request inside a gateway-owned git worktree. */
|
|
604
|
+
worktree?: boolean | {
|
|
605
|
+
name?: string;
|
|
606
|
+
ref?: string;
|
|
607
|
+
};
|
|
507
608
|
}): Promise<ExtendedToolResponse>;
|
|
508
609
|
export declare function createGatewayServer(deps?: GatewayServerDeps): McpServer;
|
|
509
610
|
export {};
|