cli-funnel 0.1.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/data/models/agent.json +51 -0
- package/data/models/antigravity.json +103 -0
- package/data/models/claude.json +93 -0
- package/data/models/codex.json +217 -0
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +164 -0
- package/dist/chunk-2FZ64BNF.js +1653 -0
- package/dist/chunk-GF7JASHO.js +317 -0
- package/dist/chunk-YP5V5YEE.js +15 -0
- package/dist/client/index.d.ts +52 -0
- package/dist/client/index.js +63 -0
- package/dist/funnel-CoOj5wr1.d.ts +264 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +20 -0
- package/dist/server/index.d.ts +34 -0
- package/dist/server/index.js +9 -0
- package/package.json +57 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
type CliProviderId = "claude" | "codex" | "agent" | "antigravity";
|
|
2
|
+
type ApiProviderId = "anthropic-api" | "openai-api";
|
|
3
|
+
type ProviderId = CliProviderId | ApiProviderId;
|
|
4
|
+
/** How much the agent may do on the machine. Providers list the levels they can really enforce. */
|
|
5
|
+
type AccessLevel = "supervised" | "accept-edits" | "auto" | "full";
|
|
6
|
+
declare const ACCESS_LEVELS: readonly AccessLevel[];
|
|
7
|
+
interface EffortOption {
|
|
8
|
+
/** Value passed to the CLI, for example "high". */
|
|
9
|
+
id: string;
|
|
10
|
+
label: string;
|
|
11
|
+
}
|
|
12
|
+
/** One selectable model. `id` is always a concrete, versioned model name. Aliases like "latest" never appear here. */
|
|
13
|
+
interface ModelInfo {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
provider: ProviderId;
|
|
17
|
+
efforts: EffortOption[];
|
|
18
|
+
defaultEffort?: string;
|
|
19
|
+
/** Selectable context sizes in tokens. Empty when the CLI fixes it. */
|
|
20
|
+
contextWindows: number[];
|
|
21
|
+
defaultContextWindow?: number;
|
|
22
|
+
/** True when the model has a faster, higher-usage tier. */
|
|
23
|
+
fast: boolean;
|
|
24
|
+
/** Where this entry came from. */
|
|
25
|
+
source: "manifest" | "cli";
|
|
26
|
+
}
|
|
27
|
+
interface Capabilities {
|
|
28
|
+
/** Access levels this provider can enforce headlessly. `supervised` appears only when approvals can be passed through. Empty means the provider has no machine access (API providers). */
|
|
29
|
+
access: AccessLevel[];
|
|
30
|
+
effort: boolean;
|
|
31
|
+
contextWindow: boolean;
|
|
32
|
+
fast: boolean;
|
|
33
|
+
resume: boolean;
|
|
34
|
+
approvals: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** The whole UI state in one serializable object. Hardcode it or let the UI produce it. */
|
|
37
|
+
interface Selection {
|
|
38
|
+
provider: ProviderId;
|
|
39
|
+
model: string;
|
|
40
|
+
effort?: string;
|
|
41
|
+
contextWindow?: number;
|
|
42
|
+
fast?: boolean;
|
|
43
|
+
/** Absolute project directory the agent works in. */
|
|
44
|
+
cwd: string;
|
|
45
|
+
access: AccessLevel;
|
|
46
|
+
}
|
|
47
|
+
interface Usage {
|
|
48
|
+
inputTokens: number;
|
|
49
|
+
outputTokens: number;
|
|
50
|
+
cachedInputTokens?: number;
|
|
51
|
+
reasoningTokens?: number;
|
|
52
|
+
totalTokens: number;
|
|
53
|
+
/** Set only when the CLI reports it. Subscription runs often do not. */
|
|
54
|
+
costUsd?: number;
|
|
55
|
+
}
|
|
56
|
+
type FinishReason = "stop" | "cancelled" | "error" | "denied";
|
|
57
|
+
interface ApprovalRequest {
|
|
58
|
+
id: string;
|
|
59
|
+
tool: string;
|
|
60
|
+
/** Tool input as the CLI reported it. */
|
|
61
|
+
input: unknown;
|
|
62
|
+
description?: string;
|
|
63
|
+
}
|
|
64
|
+
type ApprovalDecision = "allow" | "deny";
|
|
65
|
+
type FunnelEvent = {
|
|
66
|
+
type: "session";
|
|
67
|
+
sessionId: string;
|
|
68
|
+
model?: string;
|
|
69
|
+
} | {
|
|
70
|
+
type: "text.delta";
|
|
71
|
+
text: string;
|
|
72
|
+
} | {
|
|
73
|
+
type: "reasoning.delta";
|
|
74
|
+
text: string;
|
|
75
|
+
} | {
|
|
76
|
+
type: "tool.start";
|
|
77
|
+
id: string;
|
|
78
|
+
name: string;
|
|
79
|
+
input?: unknown;
|
|
80
|
+
} | {
|
|
81
|
+
type: "tool.end";
|
|
82
|
+
id: string;
|
|
83
|
+
output?: string;
|
|
84
|
+
error?: string;
|
|
85
|
+
}
|
|
86
|
+
/** A provider yields this, then awaits `onApproval` for the answer. */
|
|
87
|
+
| {
|
|
88
|
+
type: "approval.request";
|
|
89
|
+
request: ApprovalRequest;
|
|
90
|
+
} | {
|
|
91
|
+
type: "usage";
|
|
92
|
+
usage: Usage;
|
|
93
|
+
} | {
|
|
94
|
+
type: "done";
|
|
95
|
+
text: string;
|
|
96
|
+
finishReason: FinishReason;
|
|
97
|
+
} | {
|
|
98
|
+
type: "error";
|
|
99
|
+
message: string;
|
|
100
|
+
code?: string;
|
|
101
|
+
};
|
|
102
|
+
/** What `funnel.run()` resolves to. Shaped like an API response. */
|
|
103
|
+
interface RunResult {
|
|
104
|
+
text: string;
|
|
105
|
+
provider: ProviderId;
|
|
106
|
+
model: string;
|
|
107
|
+
sessionId?: string;
|
|
108
|
+
usage?: Usage;
|
|
109
|
+
finishReason: FinishReason;
|
|
110
|
+
/** Tool calls the agent made, in order. */
|
|
111
|
+
toolCalls: {
|
|
112
|
+
id: string;
|
|
113
|
+
name: string;
|
|
114
|
+
input?: unknown;
|
|
115
|
+
error?: string;
|
|
116
|
+
}[];
|
|
117
|
+
/** Tool calls the CLI refused because nobody could approve them. */
|
|
118
|
+
deniedActions: string[];
|
|
119
|
+
}
|
|
120
|
+
interface RunInput {
|
|
121
|
+
selection: Selection;
|
|
122
|
+
prompt: string;
|
|
123
|
+
/** Continue an earlier conversation. Use the `sessionId` from a previous result. */
|
|
124
|
+
sessionId?: string;
|
|
125
|
+
signal?: AbortSignal;
|
|
126
|
+
/** Called for each tool call that needs approval. Required when `selection.access` is "supervised". */
|
|
127
|
+
onApproval?: (request: ApprovalRequest) => Promise<ApprovalDecision> | ApprovalDecision;
|
|
128
|
+
/** Extra environment for the CLI process. */
|
|
129
|
+
env?: Record<string, string>;
|
|
130
|
+
}
|
|
131
|
+
interface Installation {
|
|
132
|
+
installed: boolean;
|
|
133
|
+
path?: string;
|
|
134
|
+
version?: string;
|
|
135
|
+
/** False when the installed version is outside the range this release was tested against. */
|
|
136
|
+
testedRange: {
|
|
137
|
+
min: string;
|
|
138
|
+
maxExclusive?: string;
|
|
139
|
+
};
|
|
140
|
+
withinTestedRange?: boolean;
|
|
141
|
+
}
|
|
142
|
+
interface AuthStatus {
|
|
143
|
+
loggedIn: boolean;
|
|
144
|
+
/** Human label such as "claude.ai" or "ChatGPT". */
|
|
145
|
+
method?: string;
|
|
146
|
+
account?: string;
|
|
147
|
+
plan?: string;
|
|
148
|
+
detail?: string;
|
|
149
|
+
}
|
|
150
|
+
type LoginEvent =
|
|
151
|
+
/** Show this URL to the user. The CLI usually opens it too. */
|
|
152
|
+
{
|
|
153
|
+
type: "open-url";
|
|
154
|
+
url: string;
|
|
155
|
+
}
|
|
156
|
+
/** The CLI waits for a code the user copies from the browser. Answer with `LoginSession.sendCode`. */
|
|
157
|
+
| {
|
|
158
|
+
type: "code-prompt";
|
|
159
|
+
message: string;
|
|
160
|
+
} | {
|
|
161
|
+
type: "log";
|
|
162
|
+
text: string;
|
|
163
|
+
}
|
|
164
|
+
/** The provider has no headless login. Run `command` in a terminal. */
|
|
165
|
+
| {
|
|
166
|
+
type: "needs-terminal";
|
|
167
|
+
command: string[];
|
|
168
|
+
} | {
|
|
169
|
+
type: "done";
|
|
170
|
+
status: AuthStatus;
|
|
171
|
+
} | {
|
|
172
|
+
type: "error";
|
|
173
|
+
message: string;
|
|
174
|
+
};
|
|
175
|
+
interface LoginSession extends AsyncIterable<LoginEvent> {
|
|
176
|
+
sendCode(code: string): void;
|
|
177
|
+
cancel(): void;
|
|
178
|
+
}
|
|
179
|
+
interface UpdateResult {
|
|
180
|
+
from?: string;
|
|
181
|
+
to?: string;
|
|
182
|
+
changed: boolean;
|
|
183
|
+
output: string;
|
|
184
|
+
}
|
|
185
|
+
interface Provider {
|
|
186
|
+
readonly id: ProviderId;
|
|
187
|
+
readonly displayName: string;
|
|
188
|
+
/** Executable name looked up on PATH. */
|
|
189
|
+
readonly binary: string;
|
|
190
|
+
readonly capabilities: Capabilities;
|
|
191
|
+
detect(): Promise<Installation>;
|
|
192
|
+
authStatus(): Promise<AuthStatus>;
|
|
193
|
+
login(options?: {
|
|
194
|
+
signal?: AbortSignal;
|
|
195
|
+
}): LoginSession;
|
|
196
|
+
logout(): Promise<void>;
|
|
197
|
+
update(): Promise<UpdateResult>;
|
|
198
|
+
models(): Promise<ModelInfo[]>;
|
|
199
|
+
run(input: RunInput): AsyncIterable<FunnelEvent>;
|
|
200
|
+
}
|
|
201
|
+
declare class FunnelError extends Error {
|
|
202
|
+
readonly code: "not-installed" | "not-logged-in" | "unsupported" | "invalid-selection" | "cli-failed" | "aborted";
|
|
203
|
+
constructor(message: string, code: "not-installed" | "not-logged-in" | "unsupported" | "invalid-selection" | "cli-failed" | "aborted");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** A manifest entry. Same as ModelInfo minus fields the loader fills in. */
|
|
207
|
+
type ManifestModel = Omit<ModelInfo, "provider" | "source"> & {
|
|
208
|
+
/** Hide the model on CLIs older than this version. */
|
|
209
|
+
minCliVersion?: string;
|
|
210
|
+
};
|
|
211
|
+
interface ModelManifest {
|
|
212
|
+
schemaVersion: 1;
|
|
213
|
+
updated: string;
|
|
214
|
+
providers: Record<CliProviderId, ManifestModel[]>;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Returns the remote manifest when `url` is set and reachable, else the bundled one.
|
|
218
|
+
* The remote copy lets model lists update without an npm release. It is cached for an hour.
|
|
219
|
+
*/
|
|
220
|
+
declare function loadManifest(url?: string): Promise<ModelManifest>;
|
|
221
|
+
|
|
222
|
+
interface FunnelOptions {
|
|
223
|
+
/** URL of a models.json to refresh the bundled model list from. Optional. */
|
|
224
|
+
manifestUrl?: string;
|
|
225
|
+
/** Skip checking the selected model against the catalog. Use for models released after your manifest. */
|
|
226
|
+
allowUnlistedModels?: boolean;
|
|
227
|
+
/** Replace or add providers. Used by tests and by custom providers. */
|
|
228
|
+
providers?: Partial<Record<ProviderId, Provider>>;
|
|
229
|
+
/** API keys for the API providers. Falls back to ANTHROPIC_API_KEY and OPENAI_API_KEY. */
|
|
230
|
+
apiKeys?: {
|
|
231
|
+
anthropic?: string;
|
|
232
|
+
openai?: string;
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
interface ProviderOverview {
|
|
236
|
+
id: ProviderId;
|
|
237
|
+
displayName: string;
|
|
238
|
+
capabilities: Provider["capabilities"];
|
|
239
|
+
installation: Installation;
|
|
240
|
+
auth?: AuthStatus;
|
|
241
|
+
}
|
|
242
|
+
interface RunStream extends AsyncIterable<FunnelEvent> {
|
|
243
|
+
/** Resolves to the API-shaped result once the stream is consumed. */
|
|
244
|
+
result: Promise<RunResult>;
|
|
245
|
+
}
|
|
246
|
+
declare function createFunnel(options?: FunnelOptions): {
|
|
247
|
+
providers: Record<ProviderId, Provider>;
|
|
248
|
+
/** Installed and logged-in state for every provider, for a provider picker. */
|
|
249
|
+
overview(): Promise<ProviderOverview[]>;
|
|
250
|
+
models: (id: ProviderId) => Promise<ModelInfo[]>;
|
|
251
|
+
authStatus: (id: ProviderId) => Promise<AuthStatus>;
|
|
252
|
+
login: (id: ProviderId, opts?: {
|
|
253
|
+
signal?: AbortSignal;
|
|
254
|
+
}) => LoginSession;
|
|
255
|
+
logout: (id: ProviderId) => Promise<void>;
|
|
256
|
+
update: (id: ProviderId) => Promise<UpdateResult>;
|
|
257
|
+
manifest: () => Promise<ModelManifest>;
|
|
258
|
+
stream: (input: RunInput) => RunStream;
|
|
259
|
+
/** Runs one turn and resolves with the final text, usage and tool calls. */
|
|
260
|
+
run(input: RunInput): Promise<RunResult>;
|
|
261
|
+
};
|
|
262
|
+
type Funnel = ReturnType<typeof createFunnel>;
|
|
263
|
+
|
|
264
|
+
export { type AuthStatus as A, type Capabilities as C, type EffortOption as E, type FunnelEvent as F, type Installation as I, type LoginEvent as L, type ModelInfo as M, type ProviderOverview as P, type RunInput as R, type Selection as S, type UpdateResult as U, type ProviderId as a, type ApprovalDecision as b, ACCESS_LEVELS as c, type AccessLevel as d, type ApiProviderId as e, type ApprovalRequest as f, type CliProviderId as g, type FinishReason as h, FunnelError as i, type LoginSession as j, type Provider as k, type RunResult as l, type Usage as m, type Funnel as n, type FunnelOptions as o, type ManifestModel as p, type ModelManifest as q, type RunStream as r, createFunnel as s, loadManifest as t };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { S as Selection, k as Provider, M as ModelInfo, a as ProviderId, e as ApiProviderId } from './funnel-CoOj5wr1.js';
|
|
2
|
+
export { c as ACCESS_LEVELS, d as AccessLevel, b as ApprovalDecision, f as ApprovalRequest, A as AuthStatus, C as Capabilities, g as CliProviderId, E as EffortOption, h as FinishReason, n as Funnel, i as FunnelError, F as FunnelEvent, o as FunnelOptions, I as Installation, L as LoginEvent, j as LoginSession, p as ManifestModel, q as ModelManifest, P as ProviderOverview, R as RunInput, l as RunResult, r as RunStream, U as UpdateResult, m as Usage, s as createFunnel, t as loadManifest } from './funnel-CoOj5wr1.js';
|
|
3
|
+
|
|
4
|
+
/** Throws FunnelError("invalid-selection") when the selection asks for something the provider cannot do. */
|
|
5
|
+
declare function validateSelection(selection: Selection, provider: Provider, models?: ModelInfo[]): void;
|
|
6
|
+
|
|
7
|
+
declare const PROVIDERS: Record<ProviderId, Provider>;
|
|
8
|
+
|
|
9
|
+
declare const createApiProviders: (keys?: {
|
|
10
|
+
anthropic?: string;
|
|
11
|
+
openai?: string;
|
|
12
|
+
}) => Record<ApiProviderId, Provider>;
|
|
13
|
+
|
|
14
|
+
export { ApiProviderId, ModelInfo, PROVIDERS, Provider, ProviderId, Selection, createApiProviders, validateSelection };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PROVIDERS,
|
|
3
|
+
createApiProviders,
|
|
4
|
+
createFunnel,
|
|
5
|
+
loadManifest,
|
|
6
|
+
validateSelection
|
|
7
|
+
} from "./chunk-2FZ64BNF.js";
|
|
8
|
+
import {
|
|
9
|
+
ACCESS_LEVELS,
|
|
10
|
+
FunnelError
|
|
11
|
+
} from "./chunk-YP5V5YEE.js";
|
|
12
|
+
export {
|
|
13
|
+
ACCESS_LEVELS,
|
|
14
|
+
FunnelError,
|
|
15
|
+
PROVIDERS,
|
|
16
|
+
createApiProviders,
|
|
17
|
+
createFunnel,
|
|
18
|
+
loadManifest,
|
|
19
|
+
validateSelection
|
|
20
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { d as AccessLevel, n as Funnel } from '../funnel-CoOj5wr1.js';
|
|
2
|
+
import { Server } from 'node:http';
|
|
3
|
+
|
|
4
|
+
interface OpenAIDefaults {
|
|
5
|
+
/** Project directory the agent works in. Default: the server's cwd. */
|
|
6
|
+
cwd?: string;
|
|
7
|
+
/** Access level for chat-completions calls. Default "accept-edits". "supervised" is denied here because the wire format has no approve button. */
|
|
8
|
+
access?: AccessLevel;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface HandlerOptions {
|
|
12
|
+
/** Path prefix the routes live under, for example "/api/funnel". Default "". */
|
|
13
|
+
basePath?: string;
|
|
14
|
+
/** Require `Authorization: Bearer <token>` on every request. Set this whenever the server is reachable by anyone but you. */
|
|
15
|
+
token?: string;
|
|
16
|
+
/** Directories the folder picker may browse and runs may use as their project folder. Default: the home directory. */
|
|
17
|
+
fsRoots?: string[];
|
|
18
|
+
/** Defaults for the OpenAI-compatible endpoints, which cannot carry a full Selection. */
|
|
19
|
+
openai?: OpenAIDefaults;
|
|
20
|
+
/** Seconds to wait for an approval before denying it. Default 300. */
|
|
21
|
+
approvalTimeoutSec?: number;
|
|
22
|
+
}
|
|
23
|
+
declare function createHandler(funnel: Funnel, options?: HandlerOptions): (req: Request) => Promise<Response>;
|
|
24
|
+
|
|
25
|
+
/** Serves a fetch-style handler with node:http. Binds to localhost unless told otherwise. */
|
|
26
|
+
declare function serveNode(handler: (req: Request) => Promise<Response>, opts?: {
|
|
27
|
+
port?: number;
|
|
28
|
+
host?: string;
|
|
29
|
+
}): Promise<{
|
|
30
|
+
server: Server;
|
|
31
|
+
url: string;
|
|
32
|
+
}>;
|
|
33
|
+
|
|
34
|
+
export { type HandlerOptions, type OpenAIDefaults, createHandler, serveNode };
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cli-funnel",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Use Claude Code, Codex, Cursor Agent and Antigravity CLIs like an API, on your subscription.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"cli-funnel": "dist/bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./server": {
|
|
16
|
+
"types": "./dist/server/index.d.ts",
|
|
17
|
+
"import": "./dist/server/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./client": {
|
|
20
|
+
"types": "./dist/client/index.d.ts",
|
|
21
|
+
"import": "./dist/client/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"data"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=22"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"typecheck": "tsc --noEmit",
|
|
35
|
+
"prepublishOnly": "npm run build"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/SuperTost100/cli-funnel.git",
|
|
40
|
+
"directory": "packages/cli-funnel"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/SuperTost100/cli-funnel#readme",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/SuperTost100/cli-funnel/issues"
|
|
45
|
+
},
|
|
46
|
+
"keywords": [
|
|
47
|
+
"claude-code",
|
|
48
|
+
"codex",
|
|
49
|
+
"cursor-agent",
|
|
50
|
+
"antigravity",
|
|
51
|
+
"cli",
|
|
52
|
+
"ai",
|
|
53
|
+
"agent",
|
|
54
|
+
"openai-compatible",
|
|
55
|
+
"subscription"
|
|
56
|
+
]
|
|
57
|
+
}
|