@aisa-one/cli 0.3.0 → 0.5.1

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 (103) hide show
  1. package/CHANGELOG.md +165 -1
  2. package/LICENSE +21 -0
  3. package/README.md +164 -170
  4. package/dist/api.d.ts +10 -0
  5. package/dist/api.js +14 -3
  6. package/dist/catalog.d.ts +1 -18
  7. package/dist/catalog.js +1 -24
  8. package/dist/cli-error.d.ts +17 -0
  9. package/dist/cli-error.js +25 -0
  10. package/dist/cli-guidance.d.ts +14 -0
  11. package/dist/cli-guidance.js +55 -0
  12. package/dist/commands/account.d.ts +17 -0
  13. package/dist/commands/account.js +45 -1
  14. package/dist/commands/api.d.ts +0 -11
  15. package/dist/commands/api.js +6 -175
  16. package/dist/commands/auth.d.ts +2 -1
  17. package/dist/commands/auth.js +45 -11
  18. package/dist/commands/brand-logos.d.ts +6 -0
  19. package/dist/commands/brand-logos.js +21 -0
  20. package/dist/commands/configCmd.js +8 -3
  21. package/dist/commands/connect-shared.d.ts +136 -0
  22. package/dist/commands/connect-shared.js +143 -0
  23. package/dist/commands/connect-t2.d.ts +18 -0
  24. package/dist/commands/connect-t2.js +1599 -0
  25. package/dist/commands/connect-terminal.d.ts +65 -0
  26. package/dist/commands/connect-terminal.js +822 -0
  27. package/dist/commands/connect.d.ts +31 -0
  28. package/dist/commands/connect.js +3181 -0
  29. package/dist/commands/flow.d.ts +685 -0
  30. package/dist/commands/flow.js +697 -0
  31. package/dist/commands/install.d.ts +91 -0
  32. package/dist/commands/install.js +258 -0
  33. package/dist/commands/llm-config.d.ts +103 -0
  34. package/dist/commands/llm-config.js +452 -0
  35. package/dist/commands/manifest.d.ts +68 -0
  36. package/dist/commands/manifest.js +90 -0
  37. package/dist/commands/mcp.d.ts +59 -0
  38. package/dist/commands/mcp.js +122 -44
  39. package/dist/commands/oauth-login.d.ts +33 -0
  40. package/dist/commands/oauth-login.js +333 -0
  41. package/dist/commands/prompt.d.ts +96 -0
  42. package/dist/commands/prompt.js +397 -0
  43. package/dist/commands/serve-results.d.ts +61 -0
  44. package/dist/commands/serve-results.js +245 -0
  45. package/dist/commands/serve-signin.d.ts +28 -0
  46. package/dist/commands/serve-signin.js +90 -0
  47. package/dist/commands/signin-page.d.ts +49 -0
  48. package/dist/commands/signin-page.js +250 -0
  49. package/dist/commands/skills.js +87 -50
  50. package/dist/commands/tool-help.d.ts +69 -0
  51. package/dist/commands/tool-help.js +189 -0
  52. package/dist/commands/tool-input.d.ts +22 -0
  53. package/dist/commands/tool-input.js +220 -0
  54. package/dist/commands/tools.d.ts +12 -0
  55. package/dist/commands/tools.js +306 -0
  56. package/dist/commands/update.d.ts +11 -0
  57. package/dist/commands/update.js +92 -0
  58. package/dist/commands/vscode.d.ts +65 -0
  59. package/dist/commands/vscode.js +173 -0
  60. package/dist/commands/wrappers.d.ts +23 -0
  61. package/dist/commands/wrappers.js +102 -0
  62. package/dist/completion.js +3 -80
  63. package/dist/config.d.ts +3 -0
  64. package/dist/config.js +80 -3
  65. package/dist/constants.d.ts +51 -38
  66. package/dist/constants.js +53 -109
  67. package/dist/index.js +152 -355
  68. package/dist/json-text.d.ts +12 -0
  69. package/dist/json-text.js +60 -0
  70. package/dist/router.d.ts +39 -0
  71. package/dist/router.js +59 -0
  72. package/dist/skills-registry.js +12 -3
  73. package/dist/utils/banner.d.ts +9 -0
  74. package/dist/utils/banner.js +41 -0
  75. package/dist/utils/browser.d.ts +19 -0
  76. package/dist/utils/browser.js +31 -0
  77. package/dist/utils/exec.d.ts +43 -0
  78. package/dist/utils/exec.js +61 -0
  79. package/dist/utils/http.d.ts +53 -0
  80. package/dist/utils/http.js +124 -0
  81. package/dist/utils/install-method.d.ts +36 -0
  82. package/dist/utils/install-method.js +48 -0
  83. package/dist/utils/journal.d.ts +57 -0
  84. package/dist/utils/journal.js +188 -0
  85. package/dist/utils/key-check.d.ts +20 -0
  86. package/dist/utils/key-check.js +24 -0
  87. package/dist/utils/update-check.d.ts +23 -0
  88. package/dist/utils/update-check.js +116 -0
  89. package/dist/utils/width.d.ts +32 -0
  90. package/dist/utils/width.js +73 -0
  91. package/package.json +8 -4
  92. package/vscode-extension/README.md +6 -0
  93. package/vscode-extension/aisa-vscode.vsix +0 -0
  94. package/dist/commands/finance.d.ts +0 -17
  95. package/dist/commands/finance.js +0 -342
  96. package/dist/commands/run.d.ts +0 -28
  97. package/dist/commands/run.js +0 -182
  98. package/dist/commands/search.d.ts +0 -9
  99. package/dist/commands/search.js +0 -81
  100. package/dist/commands/twitter.d.ts +0 -138
  101. package/dist/commands/twitter.js +0 -374
  102. package/dist/commands/video.d.ts +0 -49
  103. package/dist/commands/video.js +0 -311
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Installing a coding agent on the user's behalf.
3
+ *
4
+ * Two rules decide everything here:
5
+ *
6
+ * 1. **Never sudo.** A CLI that escalates on a user's machine is a CLI nobody
7
+ * should trust, and there is no terminal to type a password into anyway.
8
+ * Where a global npm prefix is not writable we print the command and let
9
+ * the user run it — the flow resumes on a re-check rather than failing.
10
+ * 2. **Prefer the vendor's own user-space installer.** Claude Code's script
11
+ * lands in ~/.local/bin, so the permission question never arises. npm is
12
+ * the fallback, and the one place rule 1 gets exercised.
13
+ *
14
+ * Windows is deliberately out of scope for now: the installers differ
15
+ * (PowerShell, winget) and nothing here has been tested there. `supported()`
16
+ * says so rather than half-working.
17
+ */
18
+ export interface Installer {
19
+ id: string;
20
+ label: string;
21
+ /** The binary that must appear on PATH once installed. */
22
+ binary: string;
23
+ /** Preferred command, shown verbatim before it runs. */
24
+ command: string;
25
+ /** Where the preferred command puts things, for the "not on PATH" hint. */
26
+ installDir?: string;
27
+ /** Set when the command is an npm install; enables the broken-install retry. */
28
+ npmPackage?: string;
29
+ /** For a curl installer: the URL it depends on, probed (3s) before use.
30
+ * The npm-registry probe cannot stand in for this — the two hosts can be
31
+ * blocked independently, and a blackholed curl would otherwise sit at the
32
+ * full install timeout before the npm fallback even started. */
33
+ probeUrl?: string;
34
+ }
35
+ export declare const INSTALLERS: Record<string, Installer>;
36
+ export declare function supported(): boolean;
37
+ export type NpmChannel =
38
+ /** The user's npm already points somewhere non-default — use it as is. */
39
+ {
40
+ kind: "user";
41
+ }
42
+ /** The official registry answers — no flag needed. */
43
+ | {
44
+ kind: "official";
45
+ }
46
+ /** Official unreachable, the mirror answers — pass --registry once. */
47
+ | {
48
+ kind: "mirror";
49
+ registry: string;
50
+ }
51
+ /** Nothing answers — let the install fail with its own network error. */
52
+ | {
53
+ kind: "offline";
54
+ };
55
+ /**
56
+ * Decide which npm registry an install should use, by probing the channel
57
+ * itself rather than guessing at geography. An IP-location lookup answers
58
+ * the wrong question (an IP inside a firewall says nothing about whether a
59
+ * corporate proxy reaches the official registry, and the lookup service is
60
+ * one more thing to be unreachable); a HEAD request for the exact package
61
+ * we are about to install answers the right one. Worst case adds one fixed
62
+ * timeout, instead of the minutes-long install failure it replaces.
63
+ *
64
+ * The mirror is used only as a fallback, never by preference: it is a third
65
+ * party in the supply chain, trusted widely but still one more link.
66
+ */
67
+ export declare function pickNpmChannel(pkg: string, probe?: (url: string) => Promise<boolean>, userRegistry?: () => string | null): Promise<NpmChannel>;
68
+ /** Is the binary already on PATH and able to start? */
69
+ export declare function isInstalled(binary: string): boolean;
70
+ /**
71
+ * Can we write to npm's global prefix? Asked before running an npm install so
72
+ * the failure is a printed command rather than a wall of EACCES.
73
+ */
74
+ export declare function npmPrefixWritable(): boolean;
75
+ export type InstallOutcome = {
76
+ ok: true;
77
+ alreadyInstalled: boolean;
78
+ } | {
79
+ ok: false;
80
+ reason: "unsupported-platform" | "needs-manual";
81
+ command: string;
82
+ detail: string;
83
+ };
84
+ /**
85
+ * Install one agent, or explain what the user should run instead.
86
+ *
87
+ * Never throws for an install failure: the caller reports it and the rest of
88
+ * the run continues, because a failed install must not cost the user the MCP
89
+ * servers they also asked for.
90
+ */
91
+ export declare function installAgent(id: string): Promise<InstallOutcome>;
@@ -0,0 +1,258 @@
1
+ import { accessSync, constants, existsSync } from "node:fs";
2
+ import { runShell, runSync, QUICK_TIMEOUT_MS } from "../utils/exec.js";
3
+ export const INSTALLERS = {
4
+ "claude-code": {
5
+ id: "claude-code",
6
+ label: "Claude Code",
7
+ binary: "claude",
8
+ // The vendor installer, which needs no elevated permissions. The npm
9
+ // package (also published by Anthropic) is the fallback channel — it is
10
+ // what makes the mirror path below work where claude.ai is unreachable.
11
+ // Curl gets its own timeouts: a blackholed connection must fail in
12
+ // seconds, not sit until the overall install deadline.
13
+ command: "curl -fsSL --connect-timeout 10 --max-time 180 https://claude.ai/install.sh | bash",
14
+ installDir: "~/.local/bin",
15
+ npmPackage: "@anthropic-ai/claude-code",
16
+ probeUrl: "https://claude.ai/install.sh",
17
+ },
18
+ codex: {
19
+ id: "codex",
20
+ label: "Codex",
21
+ binary: "codex",
22
+ command: "npm install -g @openai/codex",
23
+ npmPackage: "@openai/codex",
24
+ },
25
+ opencode: {
26
+ id: "opencode",
27
+ label: "opencode",
28
+ binary: "opencode",
29
+ command: "npm install -g opencode-ai",
30
+ npmPackage: "opencode-ai",
31
+ },
32
+ // The CLI itself. connect usually runs via npx, which installs nothing —
33
+ // without this step the user walks away with no `aisa` command for
34
+ // balance, top-up or key rotation, and has to rediscover npx every time.
35
+ "aisa-cli": {
36
+ id: "aisa-cli",
37
+ label: "AIsa CLI",
38
+ binary: "aisa",
39
+ command: "npm install -g @aisa-one/cli",
40
+ npmPackage: "@aisa-one/cli",
41
+ },
42
+ };
43
+ export function supported() {
44
+ return process.platform === "darwin" || process.platform === "linux";
45
+ }
46
+ // ── registry channel ────────────────────────────────────────────────────────
47
+ const NPM_OFFICIAL = "https://registry.npmjs.org";
48
+ const NPM_MIRROR = "https://registry.npmmirror.com";
49
+ /**
50
+ * Decide which npm registry an install should use, by probing the channel
51
+ * itself rather than guessing at geography. An IP-location lookup answers
52
+ * the wrong question (an IP inside a firewall says nothing about whether a
53
+ * corporate proxy reaches the official registry, and the lookup service is
54
+ * one more thing to be unreachable); a HEAD request for the exact package
55
+ * we are about to install answers the right one. Worst case adds one fixed
56
+ * timeout, instead of the minutes-long install failure it replaces.
57
+ *
58
+ * The mirror is used only as a fallback, never by preference: it is a third
59
+ * party in the supply chain, trusted widely but still one more link.
60
+ */
61
+ export async function pickNpmChannel(pkg, probe = headOk, userRegistry = npmConfiguredRegistry) {
62
+ const configured = userRegistry();
63
+ if (configured && !configured.startsWith(NPM_OFFICIAL))
64
+ return { kind: "user" };
65
+ const path = `/${pkg.replace("/", "%2f")}`;
66
+ if (await probe(NPM_OFFICIAL + path))
67
+ return { kind: "official" };
68
+ if (await probe(NPM_MIRROR + path))
69
+ return { kind: "mirror", registry: NPM_MIRROR };
70
+ return { kind: "offline" };
71
+ }
72
+ async function headOk(url) {
73
+ try {
74
+ const res = await fetch(url, { method: "HEAD", signal: AbortSignal.timeout(3_000) });
75
+ return res.ok;
76
+ }
77
+ catch {
78
+ return false;
79
+ }
80
+ }
81
+ function npmConfiguredRegistry() {
82
+ try {
83
+ const r = runSync("npm", ["config", "get", "registry"], { timeout: QUICK_TIMEOUT_MS });
84
+ return r.status === 0 ? r.stdout.trim() || null : null;
85
+ }
86
+ catch {
87
+ return null;
88
+ }
89
+ }
90
+ /**
91
+ * Run the binary and report what actually happened, because "not working"
92
+ * has two very different causes with two very different fixes: absent from
93
+ * PATH (fix the PATH) versus present but failing to start (fix the install —
94
+ * seen live when npm's optional-dependency bug installed codex without its
95
+ * platform binary and every invocation threw "Missing optional dependency").
96
+ * The timeout is generous: macOS Gatekeeper can stall a binary's first run.
97
+ */
98
+ function probeBinary(binary) {
99
+ const res = runSync(binary, ["--version"]);
100
+ if (res.status === 0)
101
+ return { ok: true };
102
+ if (res.error?.code === "ENOENT") {
103
+ return { ok: false, onPath: false, reason: "not on PATH" };
104
+ }
105
+ const line = (res.stderr || res.stdout || "")
106
+ .split("\n")
107
+ .map((l) => l.trim())
108
+ .find((l) => l.includes("Error") || l.length > 0) ?? `exit status ${res.status}`;
109
+ return { ok: false, onPath: true, reason: line.slice(0, 160) };
110
+ }
111
+ /** Is the binary already on PATH and able to start? */
112
+ export function isInstalled(binary) {
113
+ return probeBinary(binary).ok;
114
+ }
115
+ /**
116
+ * Can we write to npm's global prefix? Asked before running an npm install so
117
+ * the failure is a printed command rather than a wall of EACCES.
118
+ */
119
+ export function npmPrefixWritable() {
120
+ try {
121
+ const r = runSync("npm", ["config", "get", "prefix"], { timeout: QUICK_TIMEOUT_MS });
122
+ const prefix = r.status === 0 ? r.stdout.trim() : "";
123
+ if (!prefix || !existsSync(prefix))
124
+ return false;
125
+ accessSync(prefix, constants.W_OK);
126
+ return true;
127
+ }
128
+ catch {
129
+ return false;
130
+ }
131
+ }
132
+ /**
133
+ * Install one agent, or explain what the user should run instead.
134
+ *
135
+ * Never throws for an install failure: the caller reports it and the rest of
136
+ * the run continues, because a failed install must not cost the user the MCP
137
+ * servers they also asked for.
138
+ */
139
+ export async function installAgent(id) {
140
+ const installer = INSTALLERS[id];
141
+ if (!installer) {
142
+ return { ok: false, reason: "needs-manual", command: "", detail: `unknown agent ${id}` };
143
+ }
144
+ if (isInstalled(installer.binary))
145
+ return { ok: true, alreadyInstalled: true };
146
+ if (!supported()) {
147
+ return {
148
+ ok: false,
149
+ reason: "unsupported-platform",
150
+ command: installer.command,
151
+ detail: "automatic install is macOS/Linux only for now",
152
+ };
153
+ }
154
+ // Pick the registry channel before running anything: one fixed 3s probe
155
+ // replaces the minutes-long hang a firewalled user would otherwise sit
156
+ // through before the fallback even started.
157
+ const channel = installer.npmPackage
158
+ ? await pickNpmChannel(installer.npmPackage)
159
+ : { kind: "official" };
160
+ const flag = channel.kind === "mirror" ? ` --registry=${channel.registry}` : "";
161
+ const npmCommand = installer.npmPackage
162
+ ? `npm install -g ${installer.npmPackage}${flag}`
163
+ : undefined;
164
+ // A curl installer needs its vendor host reachable — a fact the registry
165
+ // probe cannot vouch for, so it gets its own 3s probe. Unreachable (or the
166
+ // whole official channel is): go straight to the npm channel, which
167
+ // carries the same vendor-published package.
168
+ const isNpmInstaller = installer.command.startsWith("npm ");
169
+ const vendorReachable = isNpmInstaller || channel.kind === "mirror" || !installer.probeUrl
170
+ ? true
171
+ : await headOk(installer.probeUrl);
172
+ const command = isNpmInstaller
173
+ ? npmCommand
174
+ : (channel.kind === "mirror" || !vendorReachable) && npmCommand
175
+ ? npmCommand
176
+ : installer.command;
177
+ if (command.startsWith("npm ") && !npmPrefixWritable()) {
178
+ return {
179
+ ok: false,
180
+ reason: "needs-manual",
181
+ command,
182
+ detail: "npm's global prefix is not writable by this user",
183
+ };
184
+ }
185
+ // Shell, because the vendor installer is a pipeline. The command is
186
+ // printed by the caller before this runs; nothing is installed silently.
187
+ const first = await runShell(command);
188
+ // The installer may have succeeded even when the command reported an error
189
+ // (a killed pipe, a noisy postinstall): believe the binary, not the exit
190
+ // code, before spending a retry.
191
+ if (!first.ok && probeBinary(installer.binary).ok) {
192
+ return { ok: true, alreadyInstalled: false };
193
+ }
194
+ if (!first.ok) {
195
+ // A failed install gets exactly one more chance. Curl channel: retry over
196
+ // npm (same vendor package, different transport). npm channel: a clean
197
+ // uninstall + reinstall — npm's optional-dependency bug can fail the
198
+ // install itself (seen live with opencode: the platform binary gets
199
+ // "reify mark deleted" and the postinstall exits 1), and the reinstall
200
+ // is the remedy that works by hand.
201
+ const fallback = npmCommand && command !== npmCommand
202
+ ? npmCommand
203
+ : installer.npmPackage
204
+ // Retry over the top, never after removing what is there. See the
205
+ // note further down: the uninstall half of this cost a user their
206
+ // working install when the reinstall could not reach the registry.
207
+ ? npmCommand ?? command
208
+ : undefined;
209
+ if (!fallback) {
210
+ return {
211
+ ok: false,
212
+ reason: "needs-manual",
213
+ command,
214
+ detail: first.detail,
215
+ };
216
+ }
217
+ const second = await runShell(fallback);
218
+ if (!second.ok && !probeBinary(installer.binary).ok) {
219
+ return {
220
+ ok: false,
221
+ reason: "needs-manual",
222
+ command: npmCommand ?? command,
223
+ detail: second.detail,
224
+ };
225
+ }
226
+ }
227
+ let probe = probeBinary(installer.binary);
228
+ if (!probe.ok && probe.onPath && installer.npmPackage) {
229
+ // The binary exists but did not start. npm's optional-dependency bug
230
+ // leaves exactly this — package installed, platform binary missing — and
231
+ // reinstalling over the top fixes it.
232
+ //
233
+ // 🔴 What this must never do again is uninstall first. `probeBinary`
234
+ // reports a timeout the same way it reports a broken install, so a slow
235
+ // start on a loaded machine was enough to condemn a working tool; the
236
+ // uninstall then succeeded, the reinstall failed on a flaky download, and
237
+ // the user was left with nothing where their agent used to be. Observed
238
+ // on 2026-08-25 against a working `claude`, more than once.
239
+ //
240
+ // Installing over an existing copy is what npm does anyway. If it fails,
241
+ // the user still has what they had.
242
+ await runShell(npmCommand ?? command);
243
+ probe = probeBinary(installer.binary);
244
+ }
245
+ if (!probe.ok) {
246
+ return {
247
+ ok: false,
248
+ reason: "needs-manual",
249
+ command: installer.command,
250
+ detail: !probe.onPath
251
+ ? installer.installDir
252
+ ? `installed, but ${installer.binary} is not on PATH — add ${installer.installDir} to it`
253
+ : `install reported success but ${installer.binary} is not on PATH`
254
+ : `installed, but ${installer.binary} fails to start: ${probe.reason}`,
255
+ };
256
+ }
257
+ return { ok: true, alreadyInstalled: false };
258
+ }
@@ -0,0 +1,103 @@
1
+ export interface ModelChoice {
2
+ /** The workhorse model (Claude Code's sonnet/opus tiers, Codex's default). */
3
+ model: string;
4
+ /** The cheap model Claude Code reaches for on small tasks. */
5
+ smallModel: string;
6
+ /** Context window in tokens. Codex needs it declared; without it the CLI
7
+ * warns "Model metadata not found" and falls back to defaults that
8
+ * degrade its behaviour. */
9
+ contextWindow: number;
10
+ }
11
+ /**
12
+ * Defaults follow the agent, not our preference.
13
+ *
14
+ * Each coding agent is tuned around a model family: its system prompt, tool
15
+ * schemas and patch format were written and evaluated against one. Codex is
16
+ * OpenAI's, and `gpt-5.3-codex` is the model trained for it; Claude Code is
17
+ * Anthropic's. Sending either somewhere else works — the gateway speaks both
18
+ * protocols — but it is not the pairing the agent was built for, and it is
19
+ * not what a user installing that agent expects. Both remain switchable.
20
+ */
21
+ export declare const DEFAULT_MODELS: ModelChoice;
22
+ export declare const CODEX_DEFAULT_MODELS: ModelChoice;
23
+ /** The default pairing for one agent. */
24
+ export declare function defaultModelsFor(client: string): ModelChoice;
25
+ export type ConfigResult = {
26
+ ok: true;
27
+ path: string;
28
+ } | {
29
+ ok: false;
30
+ reason: string;
31
+ };
32
+ export declare function writeClaudeCodeLLM(apiKey: string, models?: ModelChoice): ConfigResult;
33
+ export declare function removeClaudeCodeLLM(): ConfigResult;
34
+ /**
35
+ * Codex talks the Responses API, not Chat Completions, so its base URL is the
36
+ * `/v1` root our gateway serves `/v1/responses` from — hence the separate
37
+ * constant and `wire_api = "responses"`.
38
+ */
39
+ export declare function writeCodexLLM(apiKey: string, models?: ModelChoice): ConfigResult;
40
+ export declare function removeCodexLLM(): ConfigResult;
41
+ /**
42
+ * Codex keeps MCP servers in the same config.toml. Note `http_headers`, not
43
+ * `headers` — Codex's field name, and getting it wrong fails silently at the
44
+ * first authenticated call rather than at load.
45
+ */
46
+ export declare function writeCodexMCP(servers: Array<{
47
+ slug: string;
48
+ endpoint: string;
49
+ }>, apiKey: string | undefined): ConfigResult;
50
+ /**
51
+ * Swap an entry's env-var token reference for the literal Authorization header.
52
+ *
53
+ * `codex mcp add --bearer-token-env-var` is the official way to add a keyed
54
+ * entry without triggering the OAuth flow, but it records only the variable
55
+ * NAME — at runtime Codex reads the token from its own process environment,
56
+ * and nothing guarantees the user's shell exports it. `http_headers` is the
57
+ * field Codex accepts for a literal header (`bearer_token` is explicitly
58
+ * rejected by its config loader), and it matches what the Claude Code path
59
+ * already stores via --header. The env-var reference is removed so the entry
60
+ * has exactly one source of credentials.
61
+ */
62
+ export declare function patchCodexMCPAuth(name: string, apiKey: string): ConfigResult;
63
+ /**
64
+ * Register AIsa as a custom provider and point the default models at it.
65
+ *
66
+ * `@ai-sdk/anthropic` is the runtime (opencode loads providers as Vercel AI
67
+ * SDK packages): our gateway's /v1/messages face is live and verified with a
68
+ * real Claude Code session, and the anthropic SDK is the pairing that face
69
+ * was built for. Models are declared explicitly — a custom provider has no
70
+ * models.dev entry to inherit from.
71
+ */
72
+ export declare function writeOpencodeLLM(apiKey: string, models?: ModelChoice): ConfigResult;
73
+ export declare function removeOpencodeLLM(): ConfigResult;
74
+ /**
75
+ * Write the MCP entries. With a key the entry carries the literal
76
+ * Authorization header; without one, `oauth: {}` tells opencode to run its
77
+ * own MCP OAuth (dynamic client registration per its schema).
78
+ */
79
+ export declare function writeOpencodeMCP(servers: Array<{
80
+ slug: string;
81
+ endpoint: string;
82
+ }>, apiKey: string | undefined): ConfigResult;
83
+ /**
84
+ * Codex backup: provider + catalog in the base config, top-level defaults
85
+ * untouched, and a standalone aisa.config.toml that `codex --profile aisa`
86
+ * (or the codex-aisa wrapper) layers on top of it.
87
+ *
88
+ * That standalone file is Codex ≥0.149's replacement for the old
89
+ * `[profiles.aisa]` table — `--profile <name>` now means "layer
90
+ * `$CODEX_HOME/<name>.config.toml`", and Codex refuses to start at all if
91
+ * the legacy table for that name still exists in config.toml alongside it
92
+ * (hit live 2026-08-24, codex-cli 0.149.1: "cannot be used while
93
+ * config.toml contains legacy `profile = \"aisa\"` or `[profiles.aisa]`").
94
+ * A machine still carrying that table from an earlier version of this
95
+ * writer gets it removed here — a one-time, one-way migration; nothing a
96
+ * user typed into it themselves would collide with a section this narrow.
97
+ */
98
+ export declare function writeCodexAisaProfile(apiKey: string, models?: ModelChoice): ConfigResult;
99
+ /**
100
+ * opencode backup: provider declared, `model`/`small_model` left alone — the
101
+ * user picks aisa/<model> in the TUI whenever they want it.
102
+ */
103
+ export declare function writeOpencodeAisaBackup(apiKey: string, models?: ModelChoice): ConfigResult;