llm-cli-gateway 1.17.4 → 1.17.6

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 (64) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +1 -1
  3. package/dist/approval-manager.js +0 -8
  4. package/dist/async-job-manager.d.ts +0 -113
  5. package/dist/async-job-manager.js +6 -124
  6. package/dist/cache-stats.d.ts +0 -89
  7. package/dist/cache-stats.js +0 -62
  8. package/dist/claude-mcp-config.js +0 -1
  9. package/dist/cli-updater.d.ts +0 -8
  10. package/dist/cli-updater.js +0 -12
  11. package/dist/codex-json-parser.d.ts +0 -20
  12. package/dist/codex-json-parser.js +0 -21
  13. package/dist/config.d.ts +0 -31
  14. package/dist/config.js +2 -72
  15. package/dist/db.d.ts +0 -18
  16. package/dist/db.js +0 -22
  17. package/dist/doctor.d.ts +0 -49
  18. package/dist/doctor.js +0 -47
  19. package/dist/endpoint-exposure.js +0 -1
  20. package/dist/executor.d.ts +0 -19
  21. package/dist/executor.js +3 -38
  22. package/dist/flight-recorder.d.ts +0 -26
  23. package/dist/flight-recorder.js +1 -70
  24. package/dist/gemini-json-parser.d.ts +0 -25
  25. package/dist/gemini-json-parser.js +0 -28
  26. package/dist/health.d.ts +0 -3
  27. package/dist/health.js +0 -3
  28. package/dist/index.d.ts +1 -221
  29. package/dist/index.js +14 -563
  30. package/dist/job-store.d.ts +0 -74
  31. package/dist/job-store.js +1 -73
  32. package/dist/logger.d.ts +0 -7
  33. package/dist/logger.js +0 -6
  34. package/dist/migrate-sessions.d.ts +0 -3
  35. package/dist/migrate-sessions.js +0 -16
  36. package/dist/migrate.js +1 -18
  37. package/dist/mistral-meta-json-parser.js +0 -67
  38. package/dist/model-registry.js +0 -13
  39. package/dist/pricing.d.ts +0 -46
  40. package/dist/pricing.js +0 -47
  41. package/dist/process-monitor.d.ts +0 -15
  42. package/dist/process-monitor.js +2 -31
  43. package/dist/prompt-parts.d.ts +0 -25
  44. package/dist/prompt-parts.js +0 -11
  45. package/dist/provider-status.d.ts +0 -8
  46. package/dist/provider-status.js +0 -11
  47. package/dist/request-helpers.d.ts +0 -334
  48. package/dist/request-helpers.js +1 -229
  49. package/dist/resources.d.ts +0 -20
  50. package/dist/resources.js +1 -34
  51. package/dist/retry.d.ts +0 -45
  52. package/dist/retry.js +3 -40
  53. package/dist/session-manager-pg.d.ts +0 -32
  54. package/dist/session-manager-pg.js +0 -32
  55. package/dist/session-manager.d.ts +0 -21
  56. package/dist/session-manager.js +1 -15
  57. package/dist/stream-json-parser.d.ts +0 -18
  58. package/dist/stream-json-parser.js +0 -22
  59. package/dist/upstream-contracts.d.ts +0 -55
  60. package/dist/upstream-contracts.js +0 -77
  61. package/dist/validation-orchestrator.js +0 -3
  62. package/dist/worktree-manager.d.ts +0 -9
  63. package/dist/worktree-manager.js +0 -21
  64. package/package.json +1 -1
package/dist/retry.js CHANGED
@@ -1,72 +1,35 @@
1
- /**
2
- * A module for adding retry and circuit breaker logic to asynchronous operations.
3
- *
4
- * @module retry
5
- */
6
- /**
7
- * Defines the possible states of the circuit breaker.
8
- */
9
1
  export var CircuitBreakerState;
10
2
  (function (CircuitBreakerState) {
11
- /** The circuit is closed and allows operations to execute. */
12
3
  CircuitBreakerState["CLOSED"] = "CLOSED";
13
- /** The circuit is open and fails operations immediately. */
14
4
  CircuitBreakerState["OPEN"] = "OPEN";
15
- /** The circuit is half-open and allows a single trial operation. */
16
5
  CircuitBreakerState["HALF_OPEN"] = "HALF_OPEN";
17
6
  })(CircuitBreakerState || (CircuitBreakerState = {}));
18
- /**
19
- * Default function to determine if an error is transient.
20
- * Retries on timeout (exit code 124) and common network errors.
21
- * Does not retry on file-not-found (ENOENT) or other errors.
22
- * @param error The error object.
23
- * @returns True if the error is considered transient.
24
- */
25
7
  const isDefaultTransient = (error) => {
26
8
  if (!error) {
27
9
  return false;
28
10
  }
29
- // Shell command-related errors
30
11
  if (error.code === 124) {
31
- // wall-clock timeout (explicit, caller-set) — transient
32
12
  return true;
33
13
  }
34
- // Note: exit code 125 = idle timeout (stuck process) — intentionally non-transient
35
14
  if (error.code === "ENOENT") {
36
- // command not found
37
15
  return false;
38
16
  }
39
- // Node.js network errors
40
17
  const transientErrorCodes = ["ECONNRESET", "ETIMEDOUT", "ECONNREFUSED", "EPIPE"];
41
18
  if (transientErrorCodes.includes(error.code)) {
42
19
  return true;
43
20
  }
44
21
  return false;
45
22
  };
46
- /**
47
- * Creates a new CircuitBreaker instance with default settings.
48
- * @param options Partial options to override defaults.
49
- * @returns A new CircuitBreaker instance.
50
- */
51
23
  export function createCircuitBreaker(options) {
52
24
  return {
53
25
  state: CircuitBreakerState.CLOSED,
54
26
  failures: 0,
55
27
  lastFailureTime: null,
56
- resetTimeout: options?.resetTimeout ?? 60000, // 60 seconds
28
+ resetTimeout: options?.resetTimeout ?? 60000,
57
29
  failureThreshold: options?.failureThreshold ?? 5,
58
30
  onStateChange: options?.onStateChange,
59
31
  };
60
32
  }
61
- /**
62
- * Wraps an asynchronous operation with retry and circuit breaker logic.
63
- *
64
- * @template T The return type of the operation.
65
- * @param {() => Promise<T>} operation The asynchronous operation to execute.
66
- * @param {CircuitBreaker} circuitBreaker The circuit breaker instance to use.
67
- * @param {Partial<RetryOptions>} [retryOptions] Options for retry behavior.
68
- * @returns {Promise<T>} A promise that resolves with the result of the operation.
69
- */
70
33
  export async function withRetry(operation, circuitBreaker, retryOptions, logger) {
71
34
  const wrapError = (message, error) => {
72
35
  const wrapped = new Error(message);
@@ -82,8 +45,8 @@ export async function withRetry(operation, circuitBreaker, retryOptions, logger)
82
45
  return wrapped;
83
46
  };
84
47
  const options = {
85
- initialDelay: 1000, // 1s
86
- maxDelay: 30000, // 30s
48
+ initialDelay: 1000,
49
+ maxDelay: 30000,
87
50
  factor: 2,
88
51
  isTransient: isDefaultTransient,
89
52
  onRetry: (error, attempt, delay) => {
@@ -1,48 +1,16 @@
1
1
  import type { Pool } from "pg";
2
2
  import { Session, CliType } from "./session-manager.js";
3
3
  export type { Logger } from "./logger.js";
4
- /**
5
- * PostgreSQL-backed session manager. PostgreSQL is the source of truth and
6
- * the only required service for this backend.
7
- */
8
4
  export declare class PostgreSQLSessionManager {
9
5
  private pool;
10
6
  constructor(pool: Pool);
11
- /**
12
- * Create a new session.
13
- */
14
7
  createSession(cli: CliType, description?: string, sessionId?: string): Promise<Session>;
15
- /**
16
- * Get session by ID.
17
- */
18
8
  getSession(sessionId: string): Promise<Session | null>;
19
- /**
20
- * List all sessions, optionally filtered by CLI.
21
- */
22
9
  listSessions(cli?: CliType): Promise<Session[]>;
23
- /**
24
- * Delete a session.
25
- */
26
10
  deleteSession(sessionId: string): Promise<boolean>;
27
- /**
28
- * Set active session for a CLI. The row-level update is serialized by
29
- * PostgreSQL and the session FK keeps stale IDs from being recorded.
30
- */
31
11
  setActiveSession(cli: CliType, sessionId: string | null): Promise<boolean>;
32
- /**
33
- * Get active session for a CLI.
34
- */
35
12
  getActiveSession(cli: CliType): Promise<Session | null>;
36
- /**
37
- * Update session usage timestamp.
38
- */
39
13
  updateSessionUsage(sessionId: string): Promise<void>;
40
- /**
41
- * Update session metadata using PostgreSQL's atomic JSONB merge.
42
- */
43
14
  updateSessionMetadata(sessionId: string, metadata: Record<string, any>): Promise<boolean>;
44
- /**
45
- * Clear all sessions, optionally filtered by CLI.
46
- */
47
15
  clearAllSessions(cli?: CliType): Promise<number>;
48
16
  }
@@ -6,18 +6,11 @@ const DEFAULT_SESSION_DESCRIPTIONS = {
6
6
  grok: "Grok Session",
7
7
  mistral: "Mistral Session",
8
8
  };
9
- /**
10
- * PostgreSQL-backed session manager. PostgreSQL is the source of truth and
11
- * the only required service for this backend.
12
- */
13
9
  export class PostgreSQLSessionManager {
14
10
  pool;
15
11
  constructor(pool) {
16
12
  this.pool = pool;
17
13
  }
18
- /**
19
- * Create a new session.
20
- */
21
14
  async createSession(cli, description, sessionId) {
22
15
  const id = sessionId || randomUUID();
23
16
  const sessionDescription = description ?? DEFAULT_SESSION_DESCRIPTIONS[cli];
@@ -47,18 +40,12 @@ export class PostgreSQLSessionManager {
47
40
  client.release();
48
41
  }
49
42
  }
50
- /**
51
- * Get session by ID.
52
- */
53
43
  async getSession(sessionId) {
54
44
  const result = await this.pool.query(`SELECT id, cli, description, metadata, created_at AS "createdAt", last_used_at AS "lastUsedAt"
55
45
  FROM sessions
56
46
  WHERE id = $1`, [sessionId]);
57
47
  return result.rows[0] ?? null;
58
48
  }
59
- /**
60
- * List all sessions, optionally filtered by CLI.
61
- */
62
49
  async listSessions(cli) {
63
50
  const query = cli
64
51
  ? `SELECT id, cli, description, metadata, created_at AS "createdAt", last_used_at AS "lastUsedAt"
@@ -73,9 +60,6 @@ export class PostgreSQLSessionManager {
73
60
  : await this.pool.query(query);
74
61
  return result.rows;
75
62
  }
76
- /**
77
- * Delete a session.
78
- */
79
63
  async deleteSession(sessionId) {
80
64
  const session = await this.getSession(sessionId);
81
65
  if (!session) {
@@ -84,10 +68,6 @@ export class PostgreSQLSessionManager {
84
68
  const result = await this.pool.query("DELETE FROM sessions WHERE id = $1", [sessionId]);
85
69
  return result.rowCount !== 0;
86
70
  }
87
- /**
88
- * Set active session for a CLI. The row-level update is serialized by
89
- * PostgreSQL and the session FK keeps stale IDs from being recorded.
90
- */
91
71
  async setActiveSession(cli, sessionId) {
92
72
  if (sessionId !== null) {
93
73
  const session = await this.getSession(sessionId);
@@ -101,9 +81,6 @@ export class PostgreSQLSessionManager {
101
81
  ON CONFLICT (cli) DO UPDATE SET session_id = $2, updated_at = $3`, [cli, sessionId, now]);
102
82
  return true;
103
83
  }
104
- /**
105
- * Get active session for a CLI.
106
- */
107
84
  async getActiveSession(cli) {
108
85
  const result = await this.pool.query("SELECT session_id FROM active_sessions WHERE cli = $1", [cli]);
109
86
  const sessionId = result.rows[0]?.session_id;
@@ -112,16 +89,10 @@ export class PostgreSQLSessionManager {
112
89
  }
113
90
  return await this.getSession(sessionId);
114
91
  }
115
- /**
116
- * Update session usage timestamp.
117
- */
118
92
  async updateSessionUsage(sessionId) {
119
93
  const now = new Date().toISOString();
120
94
  await this.pool.query("UPDATE sessions SET last_used_at = $1 WHERE id = $2", [now, sessionId]);
121
95
  }
122
- /**
123
- * Update session metadata using PostgreSQL's atomic JSONB merge.
124
- */
125
96
  async updateSessionMetadata(sessionId, metadata) {
126
97
  const result = await this.pool.query(`UPDATE sessions
127
98
  SET metadata = COALESCE(metadata, '{}'::jsonb) || $1::jsonb
@@ -129,9 +100,6 @@ export class PostgreSQLSessionManager {
129
100
  RETURNING id`, [JSON.stringify(metadata), sessionId]);
130
101
  return result.rowCount !== 0;
131
102
  }
132
- /**
133
- * Clear all sessions, optionally filtered by CLI.
134
- */
135
103
  async clearAllSessions(cli) {
136
104
  const query = cli ? "DELETE FROM sessions WHERE cli = $1" : "DELETE FROM sessions";
137
105
  const result = cli ? await this.pool.query(query, [cli]) : await this.pool.query(query);
@@ -15,15 +15,6 @@ export interface SessionStorage {
15
15
  sessions: Record<string, Session>;
16
16
  activeSession: Record<CliType, string | null>;
17
17
  }
18
- /**
19
- * Slice λ: callback invoked before a session record is removed (whether via
20
- * explicit `deleteSession`, TTL eviction, or `clearAllSessions`). Used to
21
- * tear down per-session resources owned by the gateway — currently git
22
- * worktrees registered on `session.metadata.worktreePath`. The hook
23
- * receives the path; promise failures are logged but do not block session
24
- * removal (gateway-owned-lifecycle invariant: `session_delete` must always
25
- * succeed for the caller).
26
- */
27
18
  export type SessionCleanupHook = (session: Session) => void | Promise<void>;
28
19
  export declare class FileSessionManager {
29
20
  private storagePath;
@@ -52,11 +43,6 @@ export declare class FileSessionManager {
52
43
  clearAllSessions(cli?: CliType): number;
53
44
  }
54
45
  export declare const SessionManager: typeof FileSessionManager;
55
- /**
56
- * Session manager interface supporting both sync (file) and async (PostgreSQL) backends.
57
- * Methods return T | Promise<T> so both backends satisfy the contract.
58
- * Callers must always use `await` for uniform handling.
59
- */
60
46
  export interface ISessionManager {
61
47
  createSession(cli: CliType, description?: string, sessionId?: string): Session | Promise<Session>;
62
48
  getSession(sessionId: string): Session | null | Promise<Session | null>;
@@ -68,13 +54,6 @@ export interface ISessionManager {
68
54
  updateSessionMetadata(sessionId: string, metadata: Record<string, any>): boolean | Promise<boolean>;
69
55
  clearAllSessions(cli?: CliType): number | Promise<number>;
70
56
  }
71
- /**
72
- * Factory function to create session manager
73
- * Returns PostgreSQLSessionManager if config present, otherwise FileSessionManager
74
- * @param config - Configuration object
75
- * @param db - Optional pre-existing DatabaseConnection (avoids creating duplicate connections)
76
- * @param logger - Logger instance for structured logging
77
- */
78
57
  export declare function createSessionManager(config?: Config, db?: DatabaseConnection, logger?: Logger, opts?: {
79
58
  cleanupHook?: SessionCleanupHook;
80
59
  }): Promise<ISessionManager>;
@@ -45,7 +45,7 @@ export class FileSessionManager {
45
45
  isExpired(session) {
46
46
  const ts = new Date(session.lastUsedAt).getTime();
47
47
  if (!Number.isFinite(ts))
48
- return true; // malformed → expired
48
+ return true;
49
49
  return Date.now() - ts > this.sessionTtlMs;
50
50
  }
51
51
  evictExpiredSessions() {
@@ -77,7 +77,6 @@ export class FileSessionManager {
77
77
  this.storage = JSON.parse(data);
78
78
  }
79
79
  catch {
80
- // If file is corrupted, start fresh
81
80
  this.storage = { sessions: {}, activeSession: createEmptyActiveSessions() };
82
81
  }
83
82
  }
@@ -113,7 +112,6 @@ export class FileSessionManager {
113
112
  description: sessionDescription,
114
113
  };
115
114
  this.storage.sessions[id] = session;
116
- // Set as active session if none exists for this CLI
117
115
  if (!this.storage.activeSession[cli]) {
118
116
  this.storage.activeSession[cli] = id;
119
117
  }
@@ -145,7 +143,6 @@ export class FileSessionManager {
145
143
  const session = this.storage.sessions[sessionId];
146
144
  this.invokeCleanupHook(session);
147
145
  delete this.storage.sessions[sessionId];
148
- // If this was the active session, clear it
149
146
  if (this.storage.activeSession[session.cli] === sessionId) {
150
147
  this.storage.activeSession[session.cli] = null;
151
148
  }
@@ -220,20 +217,10 @@ export class FileSessionManager {
220
217
  return sessionsToDelete.length;
221
218
  }
222
219
  }
223
- // Maintain backward compatibility
224
220
  export const SessionManager = FileSessionManager;
225
- /**
226
- * Factory function to create session manager
227
- * Returns PostgreSQLSessionManager if config present, otherwise FileSessionManager
228
- * @param config - Configuration object
229
- * @param db - Optional pre-existing DatabaseConnection (avoids creating duplicate connections)
230
- * @param logger - Logger instance for structured logging
231
- */
232
221
  export async function createSessionManager(config, db, logger, opts) {
233
222
  if (config?.database) {
234
- // Import dynamically to avoid loading pg if not needed.
235
223
  const { PostgreSQLSessionManager } = await import("./session-manager-pg.js");
236
- // Use provided db connection or create new one
237
224
  if (!db) {
238
225
  const { createDatabaseConnection } = await import("./db.js");
239
226
  db = await createDatabaseConnection(config, logger);
@@ -241,7 +228,6 @@ export async function createSessionManager(config, db, logger, opts) {
241
228
  return new PostgreSQLSessionManager(db.getPool());
242
229
  }
243
230
  else {
244
- // Use file-based storage with TTL from config
245
231
  const sessionTtlMs = config?.sessionTtl
246
232
  ? config.sessionTtl * 1000
247
233
  : DEFAULT_SESSION_TTL_SECONDS * 1000;
@@ -1,9 +1,3 @@
1
- /**
2
- * NDJSON parser for Claude `--output-format stream-json --include-partial-messages`.
3
- *
4
- * Each line of stdout is a complete JSON object. This parser extracts the
5
- * final result text, cost, usage, and metadata from the stream.
6
- */
7
1
  export interface StreamJsonUsage {
8
2
  inputTokens: number;
9
3
  outputTokens: number;
@@ -20,16 +14,4 @@ export interface StreamJsonResult {
20
14
  isError: boolean;
21
15
  numTurns: number | null;
22
16
  }
23
- /**
24
- * Parse completed NDJSON stdout from `claude --output-format stream-json --include-partial-messages`.
25
- *
26
- * Parsing strategy:
27
- * 1. Split by newlines, filter empty lines
28
- * 2. JSON.parse each line, skip malformed lines
29
- * 3. Find the `type=result` event — contains final text, cost, usage
30
- * 4. Fall back to the last `type=assistant` event if no result event
31
- * 5. Extract `model` from `type=system` (init) event
32
- *
33
- * No rawEvents stored — the stdout buffer is already in memory.
34
- */
35
17
  export declare function parseStreamJson(stdout: string): StreamJsonResult;
@@ -1,9 +1,3 @@
1
- /**
2
- * NDJSON parser for Claude `--output-format stream-json --include-partial-messages`.
3
- *
4
- * Each line of stdout is a complete JSON object. This parser extracts the
5
- * final result text, cost, usage, and metadata from the stream.
6
- */
7
1
  function stringOrNull(value) {
8
2
  return typeof value === "string" ? value : null;
9
3
  }
@@ -13,18 +7,6 @@ function numberOrNull(value) {
13
7
  function numberOrZero(value) {
14
8
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
15
9
  }
16
- /**
17
- * Parse completed NDJSON stdout from `claude --output-format stream-json --include-partial-messages`.
18
- *
19
- * Parsing strategy:
20
- * 1. Split by newlines, filter empty lines
21
- * 2. JSON.parse each line, skip malformed lines
22
- * 3. Find the `type=result` event — contains final text, cost, usage
23
- * 4. Fall back to the last `type=assistant` event if no result event
24
- * 5. Extract `model` from `type=system` (init) event
25
- *
26
- * No rawEvents stored — the stdout buffer is already in memory.
27
- */
28
10
  export function parseStreamJson(stdout) {
29
11
  const lines = stdout.split("\n").filter(line => line.trim().length > 0);
30
12
  let resultEvent = null;
@@ -36,7 +18,6 @@ export function parseStreamJson(stdout) {
36
18
  parsed = JSON.parse(line);
37
19
  }
38
20
  catch {
39
- // Skip malformed lines
40
21
  continue;
41
22
  }
42
23
  if (!parsed || typeof parsed !== "object") {
@@ -52,7 +33,6 @@ export function parseStreamJson(stdout) {
52
33
  systemEvent = parsed;
53
34
  }
54
35
  }
55
- // Extract from result event (preferred)
56
36
  if (resultEvent) {
57
37
  const usage = resultEvent.usage
58
38
  ? {
@@ -73,7 +53,6 @@ export function parseStreamJson(stdout) {
73
53
  numTurns: numberOrNull(resultEvent.num_turns),
74
54
  };
75
55
  }
76
- // Fallback: extract text from assistant event
77
56
  if (assistantEvent) {
78
57
  const message = assistantEvent.message;
79
58
  let text = "";
@@ -97,7 +76,6 @@ export function parseStreamJson(stdout) {
97
76
  numTurns: null,
98
77
  };
99
78
  }
100
- // No result or assistant event found — return empty
101
79
  return {
102
80
  text: "",
103
81
  costUsd: null,
@@ -1,11 +1,4 @@
1
1
  import type { CliType } from "./session-manager.js";
2
- /**
3
- * `optional` (slice κ): consumes the next token as the flag's value
4
- * ONLY if that token does not start with `-`. Used for Claude's
5
- * `-p`/`--print`, which is a no-arg switch in claude-code 2.x but
6
- * also doubles as the legacy `-p <prompt>` positional shorthand that
7
- * the gateway has emitted since v0.x.
8
- */
9
2
  export type CliFlagArity = "none" | "one" | "optional" | "variadic";
10
3
  export interface CliFlagContract {
11
4
  arity: CliFlagArity;
@@ -13,41 +6,12 @@ export interface CliFlagContract {
13
6
  pattern?: RegExp;
14
7
  description: string;
15
8
  }
16
- /**
17
- * Pure upstream-tracking metadata for a provider CLI.
18
- *
19
- * IMPORTANT — non-duplication invariant: nothing here encodes mechanical
20
- * behaviour. Flags, output modes, session/resume rules, permission modes,
21
- * forbidden flags, env contracts, and positional limits live ONLY in the
22
- * surrounding {@link CliContract} and are validated ONLY by
23
- * {@link validateUpstreamCliArgs} / {@link validateUpstreamCliEnv}. The fields
24
- * below are descriptive pointers used by the upstream changelog scanner
25
- * (`scripts/upstream-scan.mjs`) and surfaced in the contract report — they
26
- * never drive argv/env enforcement.
27
- *
28
- * `docs/upstream/provider-sources.dag.toml` mirrors `sourceUrls` and
29
- * `watchCategories` for the scanner's offline scan plan; a unit test
30
- * (`upstream-sources.test.ts`) asserts the TOML stays in sync with these
31
- * fields so the two cannot drift. The TypeScript values here are authoritative;
32
- * the TOML is scanner input only and is never consulted for contract
33
- * enforcement.
34
- */
35
9
  export interface CliUpstreamMetadata {
36
- /** Canonical changelog / release-notes URLs the scanner retrieves with --live. */
37
10
  sourceUrls: readonly string[];
38
- /** Distribution package identifier (npm package name, PyPI project, …). */
39
11
  packageName?: string;
40
- /** Source repository URL, when distinct from the changelog source. */
41
12
  repo?: string;
42
- /** Human-facing install / getting-started docs. */
43
13
  installDocsUrl?: string;
44
- /** Distribution channel the gateway expects the CLI to ship through. */
45
14
  releaseChannel?: "npm" | "pypi" | "github-release" | "vendor";
46
- /**
47
- * Contract surfaces worth watching in upstream release notes (e.g. "flags",
48
- * "output-formats", "session-resume"). Descriptive labels for the scanner and
49
- * report ONLY — never a validation input.
50
- */
51
15
  watchCategories: readonly string[];
52
16
  }
53
17
  export interface CliContract {
@@ -68,7 +32,6 @@ export interface CliContract {
68
32
  resumeMaxPositionals?: number;
69
33
  resumeOnlyFlags?: readonly string[];
70
34
  resumeForbiddenFlags?: readonly string[];
71
- /** Non-mechanical upstream-tracking metadata. See {@link CliUpstreamMetadata}. */
72
35
  upstreamMetadata?: CliUpstreamMetadata;
73
36
  }
74
37
  export interface CliContractFixture {
@@ -93,19 +56,6 @@ export declare function validateUpstreamCliArgs(cli: CliType, args: readonly str
93
56
  export declare function assertUpstreamCliArgs(cli: CliType, args: readonly string[]): void;
94
57
  export declare function validateUpstreamCliEnv(cli: CliType, env: Record<string, string> | undefined): ContractValidationResult;
95
58
  export declare function assertUpstreamCliEnv(cli: CliType, env: Record<string, string> | undefined): void;
96
- /**
97
- * Best-effort, advisory-only extraction of long-form flags from raw --help text.
98
- * Returns a sorted array of unique `--foo-bar` style flags discovered in the output.
99
- *
100
- * Heuristics:
101
- * - Matches common option declaration lines emitted by clap, yargs, commander, custom TUIs, etc.
102
- * - Lowercases for stable comparison against our contract keys.
103
- * - Intentionally conservative: ignores obvious noise (URLs, prose in descriptions).
104
- *
105
- * This powers the bidirectional drift detector (extra flags the installed binary
106
- * advertises that our contract does not yet allow). It is NEVER used for argv
107
- * validation — only for the upstream scanner and `upstream_contracts` probe reports.
108
- */
109
59
  export declare function extractDiscoveredFlags(helpText: string): readonly string[];
110
60
  export interface InstalledCliContractProbe {
111
61
  cli: CliType;
@@ -115,15 +65,10 @@ export interface InstalledCliContractProbe {
115
65
  available: boolean;
116
66
  checkedHelpCommands: string[][];
117
67
  missingFlags: string[];
118
- /** Flags present in the installed binary's --help but absent from the declared contract. */
119
68
  extraFlags: readonly string[];
120
- /** Sorted list of long flags discovered in the help text (for snapshot diffing). */
121
69
  discoveredFlags: readonly string[];
122
- /** Stable hash of the concatenated help output (detects subtle text changes even if flag set is stable). */
123
70
  helpHash?: string;
124
- /** Best-effort version string scraped from the help/version output (if present). */
125
71
  versionHint?: string;
126
- /** ISO timestamp when this probe was performed. */
127
72
  probedAt: string;
128
73
  warnings: string[];
129
74
  }