@datename/fastcode-termux 0.0.0-stage → 0.1.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 (197) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +400 -2
  3. package/bin/fastcode.mjs +59 -0
  4. package/dist/agent/guards.d.ts +35 -0
  5. package/dist/agent/guards.js +74 -0
  6. package/dist/agent/limits.d.ts +24 -0
  7. package/dist/agent/limits.js +71 -0
  8. package/dist/agent/protocol.d.ts +4 -0
  9. package/dist/agent/protocol.js +126 -0
  10. package/dist/agent/tools.d.ts +1 -0
  11. package/dist/agent/tools.js +377 -0
  12. package/dist/app.d.ts +4 -0
  13. package/dist/app.js +476 -0
  14. package/dist/cli.d.ts +1 -0
  15. package/dist/cli.js +518 -0
  16. package/dist/commands/about.d.ts +8 -0
  17. package/dist/commands/about.js +16 -0
  18. package/dist/commands/agent.d.ts +11 -0
  19. package/dist/commands/agent.js +18 -0
  20. package/dist/commands/clear.d.ts +11 -0
  21. package/dist/commands/clear.js +9 -0
  22. package/dist/commands/config.d.ts +7 -0
  23. package/dist/commands/config.js +24 -0
  24. package/dist/commands/cost.d.ts +9 -0
  25. package/dist/commands/cost.js +13 -0
  26. package/dist/commands/cwd.d.ts +7 -0
  27. package/dist/commands/cwd.js +7 -0
  28. package/dist/commands/exit.d.ts +9 -0
  29. package/dist/commands/exit.js +8 -0
  30. package/dist/commands/help.d.ts +6 -0
  31. package/dist/commands/help.js +18 -0
  32. package/dist/commands/index.d.ts +9 -0
  33. package/dist/commands/index.js +58 -0
  34. package/dist/commands/login.d.ts +16 -0
  35. package/dist/commands/login.js +61 -0
  36. package/dist/commands/logout.d.ts +9 -0
  37. package/dist/commands/logout.js +53 -0
  38. package/dist/commands/model.d.ts +11 -0
  39. package/dist/commands/model.js +30 -0
  40. package/dist/commands/plugin.d.ts +11 -0
  41. package/dist/commands/plugin.js +74 -0
  42. package/dist/commands/provider.d.ts +11 -0
  43. package/dist/commands/provider.js +28 -0
  44. package/dist/commands/reset.d.ts +9 -0
  45. package/dist/commands/reset.js +13 -0
  46. package/dist/commands/skills.d.ts +11 -0
  47. package/dist/commands/skills.js +106 -0
  48. package/dist/commands/system.d.ts +11 -0
  49. package/dist/commands/system.js +20 -0
  50. package/dist/commands/theme.d.ts +11 -0
  51. package/dist/commands/theme.js +22 -0
  52. package/dist/commands/tools.d.ts +7 -0
  53. package/dist/commands/tools.js +29 -0
  54. package/dist/commands/whoami.d.ts +9 -0
  55. package/dist/commands/whoami.js +51 -0
  56. package/dist/config/paths.d.ts +4 -0
  57. package/dist/config/paths.js +59 -0
  58. package/dist/config/store.d.ts +69 -0
  59. package/dist/config/store.js +208 -0
  60. package/dist/config/themes.d.ts +73 -0
  61. package/dist/config/themes.js +77 -0
  62. package/dist/config/trust.d.ts +9 -0
  63. package/dist/config/trust.js +67 -0
  64. package/dist/index.d.ts +1 -0
  65. package/dist/index.js +31 -0
  66. package/dist/lib/diagnostics.d.ts +41 -0
  67. package/dist/lib/diagnostics.js +139 -0
  68. package/dist/lib/http.d.ts +13 -0
  69. package/dist/lib/http.js +70 -0
  70. package/dist/lib/markdown.d.ts +1 -0
  71. package/dist/lib/markdown.js +32 -0
  72. package/dist/lib/pkg.d.ts +5 -0
  73. package/dist/lib/pkg.js +27 -0
  74. package/dist/lib/platform.d.ts +7 -0
  75. package/dist/lib/platform.js +57 -0
  76. package/dist/lib/startup.d.ts +6 -0
  77. package/dist/lib/startup.js +25 -0
  78. package/dist/lib/uiMode.d.ts +2 -0
  79. package/dist/lib/uiMode.js +7 -0
  80. package/dist/plugins/manager.d.ts +23 -0
  81. package/dist/plugins/manager.js +101 -0
  82. package/dist/providers/anthropic.d.ts +21 -0
  83. package/dist/providers/anthropic.js +107 -0
  84. package/dist/providers/custom.d.ts +24 -0
  85. package/dist/providers/custom.js +25 -0
  86. package/dist/providers/deepseek.d.ts +24 -0
  87. package/dist/providers/deepseek.js +15 -0
  88. package/dist/providers/google.d.ts +24 -0
  89. package/dist/providers/google.js +19 -0
  90. package/dist/providers/groq.d.ts +24 -0
  91. package/dist/providers/groq.js +20 -0
  92. package/dist/providers/index.d.ts +201 -0
  93. package/dist/providers/index.js +37 -0
  94. package/dist/providers/mistral.d.ts +24 -0
  95. package/dist/providers/mistral.js +19 -0
  96. package/dist/providers/moonshot.d.ts +24 -0
  97. package/dist/providers/moonshot.js +22 -0
  98. package/dist/providers/ollama.d.ts +24 -0
  99. package/dist/providers/ollama.js +22 -0
  100. package/dist/providers/openai.d.ts +24 -0
  101. package/dist/providers/openai.js +25 -0
  102. package/dist/providers/openaiCompatible.d.ts +17 -0
  103. package/dist/providers/openaiCompatible.js +110 -0
  104. package/dist/providers/openrouter.d.ts +24 -0
  105. package/dist/providers/openrouter.js +26 -0
  106. package/dist/providers/qwen.d.ts +24 -0
  107. package/dist/providers/qwen.js +23 -0
  108. package/dist/providers/xai.d.ts +24 -0
  109. package/dist/providers/xai.js +18 -0
  110. package/dist/providers/zhipu.d.ts +24 -0
  111. package/dist/providers/zhipu.js +23 -0
  112. package/dist/session/log.d.ts +29 -0
  113. package/dist/session/log.js +135 -0
  114. package/dist/skills/manager.d.ts +18 -0
  115. package/dist/skills/manager.js +201 -0
  116. package/dist/skills/parser.d.ts +18 -0
  117. package/dist/skills/parser.js +65 -0
  118. package/dist/types.d.ts +146 -0
  119. package/dist/types.js +1 -0
  120. package/dist/ui/Banner.d.ts +5 -0
  121. package/dist/ui/Banner.js +65 -0
  122. package/dist/ui/Message.d.ts +7 -0
  123. package/dist/ui/Message.js +13 -0
  124. package/dist/ui/Prompt.d.ts +10 -0
  125. package/dist/ui/Prompt.js +38 -0
  126. package/dist/ui/Spinner.d.ts +5 -0
  127. package/dist/ui/Spinner.js +33 -0
  128. package/dist/ui/StatusBar.d.ts +10 -0
  129. package/dist/ui/StatusBar.js +19 -0
  130. package/dist/ui/TrustGate.d.ts +5 -0
  131. package/dist/ui/TrustGate.js +26 -0
  132. package/package.json +96 -4
  133. package/src/agent/guards.ts +74 -0
  134. package/src/agent/limits.ts +71 -0
  135. package/src/agent/protocol.ts +126 -0
  136. package/src/agent/tools.ts +377 -0
  137. package/src/app.ts +476 -0
  138. package/src/cli.ts +308 -0
  139. package/src/commands/about.ts +16 -0
  140. package/src/commands/agent.ts +18 -0
  141. package/src/commands/clear.ts +9 -0
  142. package/src/commands/config.ts +24 -0
  143. package/src/commands/cost.ts +13 -0
  144. package/src/commands/cwd.ts +7 -0
  145. package/src/commands/exit.ts +8 -0
  146. package/src/commands/help.ts +18 -0
  147. package/src/commands/index.ts +58 -0
  148. package/src/commands/login.ts +61 -0
  149. package/src/commands/logout.ts +53 -0
  150. package/src/commands/model.ts +30 -0
  151. package/src/commands/plugin.ts +74 -0
  152. package/src/commands/provider.ts +28 -0
  153. package/src/commands/reset.ts +13 -0
  154. package/src/commands/skills.ts +106 -0
  155. package/src/commands/system.ts +20 -0
  156. package/src/commands/theme.ts +22 -0
  157. package/src/commands/tools.ts +29 -0
  158. package/src/commands/whoami.ts +51 -0
  159. package/src/config/paths.ts +59 -0
  160. package/src/config/store.ts +240 -0
  161. package/src/config/themes.ts +77 -0
  162. package/src/config/trust.ts +67 -0
  163. package/src/index.ts +31 -0
  164. package/src/lib/diagnostics.ts +139 -0
  165. package/src/lib/http.ts +70 -0
  166. package/src/lib/markdown.ts +32 -0
  167. package/src/lib/pkg.ts +35 -0
  168. package/src/lib/platform.ts +57 -0
  169. package/src/lib/startup.ts +25 -0
  170. package/src/lib/uiMode.ts +7 -0
  171. package/src/plugins/manager.ts +101 -0
  172. package/src/providers/anthropic.ts +107 -0
  173. package/src/providers/custom.ts +25 -0
  174. package/src/providers/deepseek.ts +15 -0
  175. package/src/providers/google.ts +19 -0
  176. package/src/providers/groq.ts +20 -0
  177. package/src/providers/index.ts +37 -0
  178. package/src/providers/mistral.ts +19 -0
  179. package/src/providers/moonshot.ts +22 -0
  180. package/src/providers/ollama.ts +22 -0
  181. package/src/providers/openai.ts +25 -0
  182. package/src/providers/openaiCompatible.ts +110 -0
  183. package/src/providers/openrouter.ts +26 -0
  184. package/src/providers/qwen.ts +23 -0
  185. package/src/providers/xai.ts +18 -0
  186. package/src/providers/zhipu.ts +23 -0
  187. package/src/session/log.ts +135 -0
  188. package/src/skills/manager.ts +201 -0
  189. package/src/skills/parser.ts +65 -0
  190. package/src/types.ts +143 -0
  191. package/src/ui/Banner.ts +68 -0
  192. package/src/ui/Message.ts +13 -0
  193. package/src/ui/Prompt.ts +38 -0
  194. package/src/ui/Spinner.ts +33 -0
  195. package/src/ui/StatusBar.ts +19 -0
  196. package/src/ui/TrustGate.ts +26 -0
  197. package/tsconfig.json +22 -0
@@ -0,0 +1,25 @@
1
+ import { resolveApiKey } from "../config/store.js";
2
+ import { getProviderOrThrow } from "../providers/index.js";
3
+ export function createStartupTranscript(config) {
4
+ const messages = [
5
+ `Welcome to FastCode. Provider: **${config.providerId}** · model: **${config.model}**.\n\nType **/help** to list slash commands, or just start chatting.`,
6
+ ];
7
+ const provider = getProviderOrThrow(config.providerId);
8
+ if (provider.authEnv.length > 0) {
9
+ const lookup = resolveApiKey(provider.id, config.model, provider.authEnv);
10
+ if (lookup.status === "unbound") {
11
+ messages.push(`Stored ${provider.label} key isn't bound to a model, so it won't be used. ` +
12
+ `Re-bind it with \`/login ${provider.id} ${config.model} <key>\` (or \`/logout ${provider.id}\` to discard it).`);
13
+ }
14
+ else if (lookup.status === "missing") {
15
+ messages.push(`No API key for ${provider.label} · ${config.model}. ` +
16
+ `Run \`/login ${provider.id} ${config.model} <key>\`, or set ${provider.authEnv[0]} (provider-wide, any model).`);
17
+ }
18
+ }
19
+ return messages.map((content, index) => ({
20
+ id: index + 1,
21
+ role: "system",
22
+ content,
23
+ markdown: true,
24
+ }));
25
+ }
@@ -0,0 +1,2 @@
1
+ export declare function shouldUseStableTerminalUi(platform?: string, env?: NodeJS.ProcessEnv): boolean;
2
+ export declare function shouldUseLiveStreamingUi(platform?: string, env?: NodeJS.ProcessEnv): boolean;
@@ -0,0 +1,7 @@
1
+ import { detectPlatform } from "./platform.js";
2
+ export function shouldUseStableTerminalUi(platform = detectPlatform(), env = process.env) {
3
+ return platform === "termux" || env.FASTCODE_STABLE_UI === "1";
4
+ }
5
+ export function shouldUseLiveStreamingUi(platform = detectPlatform(), env = process.env) {
6
+ return !shouldUseStableTerminalUi(platform, env);
7
+ }
@@ -0,0 +1,23 @@
1
+ export declare function listInstalledPlugins(): {
2
+ name: any;
3
+ description: any;
4
+ path: any;
5
+ body: string;
6
+ skills: any[];
7
+ }[];
8
+ export declare function getPlugin(name: any): {
9
+ name: any;
10
+ description: any;
11
+ path: any;
12
+ body: string;
13
+ skills: any[];
14
+ };
15
+ export declare function importPlugin(source: any, name: any): {
16
+ name: any;
17
+ description: any;
18
+ path: any;
19
+ body: string;
20
+ skills: any[];
21
+ };
22
+ export declare function removePlugin(name: any): boolean;
23
+ export declare function buildPluginsPrompt(enabled: any): string;
@@ -0,0 +1,101 @@
1
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync, } from "node:fs";
2
+ import { basename, join, resolve } from "node:path";
3
+ import { getPaths } from "../config/paths.js";
4
+ export function listInstalledPlugins() {
5
+ const { plugins } = getPaths();
6
+ if (!existsSync(plugins))
7
+ return [];
8
+ return readdirSync(plugins, { withFileTypes: true })
9
+ .filter((entry) => entry.isDirectory())
10
+ .map((entry) => loadPlugin(join(plugins, entry.name), entry.name))
11
+ .filter((plugin) => plugin !== undefined)
12
+ .sort((a, b) => a.name.localeCompare(b.name));
13
+ }
14
+ export function getPlugin(name) {
15
+ return listInstalledPlugins().find((p) => p.name === name || basename(p.path) === name);
16
+ }
17
+ export function importPlugin(source, name) {
18
+ const { plugins } = getPaths();
19
+ const src = resolve(source);
20
+ if (!existsSync(src))
21
+ throw new Error(`Plugin source does not exist: ${source}`);
22
+ if (!statSync(src).isDirectory())
23
+ throw new Error("Plugin source must be a directory");
24
+ const folder = slugify(name ?? basename(src));
25
+ const target = join(plugins, folder);
26
+ if (existsSync(target))
27
+ rmSync(target, { recursive: true, force: true });
28
+ mkdirSync(target, { recursive: true });
29
+ cpSync(src, target, { recursive: true });
30
+ writeFileSync(join(target, ".fastcode-source"), src);
31
+ const loaded = loadPlugin(target, folder);
32
+ if (!loaded)
33
+ throw new Error("Plugin must include PLUGIN.md, README.md, or at least one SKILL.md");
34
+ return loaded;
35
+ }
36
+ export function removePlugin(name) {
37
+ const plugin = getPlugin(name);
38
+ if (!plugin)
39
+ return false;
40
+ rmSync(plugin.path, { recursive: true, force: true });
41
+ return true;
42
+ }
43
+ export function buildPluginsPrompt(enabled) {
44
+ if (enabled.length === 0)
45
+ return "";
46
+ const plugins = enabled.map(getPlugin).filter((p) => p !== undefined);
47
+ if (plugins.length === 0)
48
+ return "";
49
+ const chunks = plugins.map((plugin) => {
50
+ const skills = plugin.skills
51
+ .map((skill) => `<plugin-skill name="${skill.name}">\n${skill.body.trim()}\n</plugin-skill>`)
52
+ .join("\n\n");
53
+ return `<plugin name="${plugin.name}">\n${plugin.body.trim()}\n${skills ? `\n\n${skills}` : ""}\n</plugin>`;
54
+ });
55
+ return [
56
+ "",
57
+ "## Active plugins",
58
+ "The following plugins are always-active behavior packs. Follow them when relevant:",
59
+ "",
60
+ chunks.join("\n\n"),
61
+ ].join("\n");
62
+ }
63
+ function loadPlugin(path, fallbackName) {
64
+ const pluginMd = firstExisting([join(path, "PLUGIN.md"), join(path, "README.md")]);
65
+ const skillsDir = join(path, "skills");
66
+ const rootSkill = join(path, "SKILL.md");
67
+ const skills = [];
68
+ if (existsSync(rootSkill))
69
+ skills.push({ name: "root", body: readFileSync(rootSkill, "utf8") });
70
+ if (existsSync(skillsDir)) {
71
+ for (const entry of readdirSync(skillsDir, { withFileTypes: true })) {
72
+ if (!entry.isDirectory())
73
+ continue;
74
+ const skillPath = join(skillsDir, entry.name, "SKILL.md");
75
+ if (existsSync(skillPath))
76
+ skills.push({ name: entry.name, body: readFileSync(skillPath, "utf8") });
77
+ }
78
+ }
79
+ if (!pluginMd && skills.length === 0)
80
+ return undefined;
81
+ const body = pluginMd ? readFileSync(pluginMd, "utf8") : `Plugin ${fallbackName}`;
82
+ return {
83
+ name: fallbackName,
84
+ description: firstParagraph(body) || `${fallbackName} plugin`,
85
+ path,
86
+ body,
87
+ skills,
88
+ };
89
+ }
90
+ function firstExisting(paths) {
91
+ return paths.find((path) => existsSync(path));
92
+ }
93
+ function firstParagraph(markdown) {
94
+ return markdown
95
+ .split(/\n\s*\n/)
96
+ .map((part) => part.replace(/^#+\s*/, "").trim())
97
+ .find(Boolean);
98
+ }
99
+ function slugify(value) {
100
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "plugin";
101
+ }
@@ -0,0 +1,21 @@
1
+ export declare const anthropicProvider: {
2
+ id: string;
3
+ label: string;
4
+ authEnv: string[];
5
+ baseUrl: string;
6
+ defaultModel: string;
7
+ listModels(apiKey: any): Promise<any>;
8
+ stream(req: any, apiKey: any): AsyncGenerator<{
9
+ delta: any;
10
+ done: boolean;
11
+ usage?: undefined;
12
+ } | {
13
+ delta: string;
14
+ done: boolean;
15
+ usage: {
16
+ inputTokens: number;
17
+ outputTokens: number;
18
+ costUsd: number;
19
+ };
20
+ }, void, unknown>;
21
+ };
@@ -0,0 +1,107 @@
1
+ import { streamSSE } from "../lib/http.js";
2
+ const STATIC_MODELS = [
3
+ { id: "claude-sonnet-5.5", label: "Claude Sonnet 5.5", contextWindow: 1000000, pricing: { inputUsdPerM: 3, outputUsdPerM: 15 } },
4
+ { id: "claude-opus-5.5", label: "Claude Opus 5.5", contextWindow: 1000000, pricing: { inputUsdPerM: 15, outputUsdPerM: 75 } },
5
+ { id: "claude-haiku-5.5", label: "Claude Haiku 5.5", contextWindow: 200000, pricing: { inputUsdPerM: 0.8, outputUsdPerM: 4 } },
6
+ { id: "claude-sonnet-5", label: "Claude Sonnet 5" },
7
+ { id: "claude-opus-5", label: "Claude Opus 5" },
8
+ { id: "claude-sonnet-4.6", label: "Claude Sonnet 4.6" },
9
+ { id: "claude-opus-4.6", label: "Claude Opus 4.6" },
10
+ { id: "claude-haiku-4.5", label: "Claude Haiku 4.5" },
11
+ ];
12
+ const BASE = "https://api.anthropic.com/v1";
13
+ export const anthropicProvider = {
14
+ id: "anthropic",
15
+ label: "Anthropic (Claude)",
16
+ authEnv: ["ANTHROPIC_API_KEY", "CLAUDE_API_KEY"],
17
+ baseUrl: BASE,
18
+ defaultModel: "claude-sonnet-5.5",
19
+ async listModels(apiKey) {
20
+ // Query the live model list; fall back to the built-in list offline.
21
+ if (apiKey) {
22
+ try {
23
+ const res = await fetch(BASE + "/models", {
24
+ headers: { "x-api-key": apiKey, "anthropic-version": "2023-06-01" },
25
+ });
26
+ if (res.ok) {
27
+ const json = await res.json();
28
+ const ids = (json.data ?? [])
29
+ .map((m) => m.id)
30
+ .filter((id) => typeof id === "string" && id.length > 0);
31
+ if (ids.length > 0) {
32
+ const known = new Map(STATIC_MODELS.map((m) => [m.id, m]));
33
+ return ids.map((id) => known.get(id) ?? { id });
34
+ }
35
+ }
36
+ }
37
+ catch {
38
+ // network/auth issue → fall through to the static list
39
+ }
40
+ }
41
+ return STATIC_MODELS;
42
+ },
43
+ async *stream(req, apiKey) {
44
+ if (!apiKey) {
45
+ throw new Error("Missing ANTHROPIC_API_KEY. Bind one with /login anthropic <model> <key>, or set the env var.");
46
+ }
47
+ const messages = req.messages.map((m) => ({ role: m.role, content: m.content }));
48
+ const body = {
49
+ model: req.model,
50
+ messages,
51
+ ...(req.system ? { system: req.system } : {}),
52
+ stream: true,
53
+ max_tokens: req.maxOutputTokens ?? 4096,
54
+ ...(req.temperature !== undefined ? { temperature: req.temperature } : {}),
55
+ };
56
+ const res = await fetch(BASE + "/messages", {
57
+ method: "POST",
58
+ headers: {
59
+ "content-type": "application/json",
60
+ "x-api-key": apiKey,
61
+ "anthropic-version": "2023-06-01",
62
+ accept: "text/event-stream",
63
+ },
64
+ body: JSON.stringify(body),
65
+ signal: req.signal,
66
+ });
67
+ let usageInput = 0;
68
+ let usageOutput = 0;
69
+ for await (const ev of streamSSE(res)) {
70
+ let data;
71
+ try {
72
+ data = JSON.parse(ev.data);
73
+ }
74
+ catch {
75
+ continue;
76
+ }
77
+ const t = data.type;
78
+ if (t === "content_block_delta") {
79
+ const delta = data.delta?.text;
80
+ if (delta)
81
+ yield { delta, done: false };
82
+ }
83
+ else if (t === "message_start") {
84
+ const u = data.message?.usage;
85
+ if (u?.input_tokens)
86
+ usageInput = u.input_tokens;
87
+ }
88
+ else if (t === "message_delta") {
89
+ const u = data.usage;
90
+ if (u?.output_tokens)
91
+ usageOutput = u.output_tokens;
92
+ }
93
+ else if (t === "message_stop") {
94
+ break;
95
+ }
96
+ }
97
+ const cost = priceFor(req.model, usageInput, usageOutput);
98
+ yield { delta: "", done: true, usage: { inputTokens: usageInput, outputTokens: usageOutput, costUsd: cost } };
99
+ },
100
+ };
101
+ function priceFor(modelId, input, output) {
102
+ const m = STATIC_MODELS.find((x) => x.id === modelId);
103
+ const p = m?.pricing;
104
+ if (!p?.inputUsdPerM || !p.outputUsdPerM)
105
+ return undefined;
106
+ return (input / 1000000) * p.inputUsdPerM + (output / 1000000) * p.outputUsdPerM;
107
+ }
@@ -0,0 +1,24 @@
1
+ export declare const customProvider: {
2
+ id: string;
3
+ label: string;
4
+ authEnv: any[];
5
+ readonly baseUrl: string;
6
+ defaultModel: string;
7
+ listModels: () => Promise<any>;
8
+ stream: (req: any) => AsyncGenerator<{
9
+ delta: string;
10
+ done: boolean;
11
+ reasoning?: undefined;
12
+ usage?: undefined;
13
+ } | {
14
+ delta: string;
15
+ done: boolean;
16
+ reasoning: string;
17
+ usage?: undefined;
18
+ } | {
19
+ delta: string;
20
+ done: boolean;
21
+ usage: any;
22
+ reasoning?: undefined;
23
+ }, void, unknown>;
24
+ };
@@ -0,0 +1,25 @@
1
+ import { listModelsHttp, streamChatCompletion } from "./openaiCompatible.js";
2
+ function baseUrl() {
3
+ return (process.env["FASTCODE_BASE_URL"] ?? "").trim().replace(/[/]+$/, "");
4
+ }
5
+ function defaultModel() {
6
+ return (process.env["FASTCODE_MODEL"] ?? "").trim() || "gpt-4o-mini";
7
+ }
8
+ function requireBaseUrl() {
9
+ const base = baseUrl();
10
+ if (!base) {
11
+ throw new Error("FASTCODE_BASE_URL is not set. Example: export FASTCODE_BASE_URL=https://api.example.com/v1");
12
+ }
13
+ return base;
14
+ }
15
+ export const customProvider = {
16
+ id: "custom",
17
+ label: "Custom (OpenAI-compatible)",
18
+ authEnv: [],
19
+ get baseUrl() {
20
+ return baseUrl();
21
+ },
22
+ defaultModel: defaultModel(),
23
+ listModels: () => listModelsHttp({ baseUrl: requireBaseUrl(), apiKey: process.env["FASTCODE_API_KEY"], staticModels: [] }),
24
+ stream: (req) => streamChatCompletion(req, { baseUrl: requireBaseUrl(), apiKey: process.env["FASTCODE_API_KEY"], staticModels: [] }),
25
+ };
@@ -0,0 +1,24 @@
1
+ export declare const deepseekProvider: {
2
+ id: string;
3
+ label: string;
4
+ authEnv: string[];
5
+ baseUrl: string;
6
+ defaultModel: string;
7
+ listModels: (apiKey: any) => Promise<any>;
8
+ stream: (req: any, apiKey: any) => AsyncGenerator<{
9
+ delta: string;
10
+ done: boolean;
11
+ reasoning?: undefined;
12
+ usage?: undefined;
13
+ } | {
14
+ delta: string;
15
+ done: boolean;
16
+ reasoning: string;
17
+ usage?: undefined;
18
+ } | {
19
+ delta: string;
20
+ done: boolean;
21
+ usage: any;
22
+ reasoning?: undefined;
23
+ }, void, unknown>;
24
+ };
@@ -0,0 +1,15 @@
1
+ import { listModelsHttp, streamChatCompletion } from "./openaiCompatible.js";
2
+ const BASE = "https://api.deepseek.com/v1";
3
+ const STATIC = [
4
+ { id: "deepseek-v4-pro", label: "DeepSeek V4 Pro" },
5
+ { id: "deepseek-flash", label: "DeepSeek Flash" },
6
+ ];
7
+ export const deepseekProvider = {
8
+ id: "deepseek",
9
+ label: "DeepSeek",
10
+ authEnv: ["DEEPSEEK_API_KEY"],
11
+ baseUrl: BASE,
12
+ defaultModel: "deepseek-v4-pro",
13
+ listModels: (apiKey) => listModelsHttp({ baseUrl: BASE, apiKey, staticModels: STATIC }),
14
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC }),
15
+ };
@@ -0,0 +1,24 @@
1
+ export declare const googleProvider: {
2
+ id: string;
3
+ label: string;
4
+ authEnv: string[];
5
+ baseUrl: string;
6
+ defaultModel: string;
7
+ listModels: (apiKey: any) => Promise<any>;
8
+ stream: (req: any, apiKey: any) => AsyncGenerator<{
9
+ delta: string;
10
+ done: boolean;
11
+ reasoning?: undefined;
12
+ usage?: undefined;
13
+ } | {
14
+ delta: string;
15
+ done: boolean;
16
+ reasoning: string;
17
+ usage?: undefined;
18
+ } | {
19
+ delta: string;
20
+ done: boolean;
21
+ usage: any;
22
+ reasoning?: undefined;
23
+ }, void, unknown>;
24
+ };
@@ -0,0 +1,19 @@
1
+ import { listModelsHttp, streamChatCompletion } from "./openaiCompatible.js";
2
+ const BASE = "https://generativelanguage.googleapis.com/v1beta/openai";
3
+ const STATIC = [
4
+ { id: "gemini-3.8-flash", label: "Gemini 3.8 Flash" },
5
+ { id: "gemini-3.7-flash", label: "Gemini 3.7 Flash" },
6
+ { id: "gemini-3.5-flash", label: "Gemini 3.5 Flash" },
7
+ { id: "gemini-3.5-flash-lite", label: "Gemini 3.5 Flash Lite" },
8
+ { id: "gemini-3.1-flash-lite", label: "Gemini 3.1 Flash Lite" },
9
+ { id: "gemini-4-argon", label: "Gemini 4 Argon" },
10
+ ];
11
+ export const googleProvider = {
12
+ id: "google",
13
+ label: "Google Gemini",
14
+ authEnv: ["GEMINI_API_KEY", "GOOGLE_API_KEY"],
15
+ baseUrl: BASE,
16
+ defaultModel: "gemini-3.8-flash",
17
+ listModels: (apiKey) => listModelsHttp({ baseUrl: BASE, apiKey, staticModels: STATIC }),
18
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC }),
19
+ };
@@ -0,0 +1,24 @@
1
+ export declare const groqProvider: {
2
+ id: string;
3
+ label: string;
4
+ authEnv: string[];
5
+ baseUrl: string;
6
+ defaultModel: string;
7
+ listModels: (apiKey: any) => Promise<any>;
8
+ stream: (req: any, apiKey: any) => AsyncGenerator<{
9
+ delta: string;
10
+ done: boolean;
11
+ reasoning?: undefined;
12
+ usage?: undefined;
13
+ } | {
14
+ delta: string;
15
+ done: boolean;
16
+ reasoning: string;
17
+ usage?: undefined;
18
+ } | {
19
+ delta: string;
20
+ done: boolean;
21
+ usage: any;
22
+ reasoning?: undefined;
23
+ }, void, unknown>;
24
+ };
@@ -0,0 +1,20 @@
1
+ import { listModelsHttp, streamChatCompletion } from "./openaiCompatible.js";
2
+ const BASE = "https://api.groq.com/openai/v1";
3
+ const STATIC = [
4
+ { id: "llama-3.3-70b-versatile", label: "Llama 3.3 70B" },
5
+ { id: "meta-llama/llama-4-maverick-17b-128e-instruct", label: "Llama 4 Maverick" },
6
+ { id: "meta-llama/llama-4-scout-17b-16e-instruct", label: "Llama 4 Scout" },
7
+ { id: "moonshotai/kimi-k2-instruct", label: "Kimi K2" },
8
+ { id: "openai/gpt-oss-120b", label: "GPT-OSS 120B" },
9
+ { id: "qwen/qwen3-32b", label: "Qwen3 32B" },
10
+ { id: "llama-3.1-8b-instant", label: "Llama 3.1 8B instant" },
11
+ ];
12
+ export const groqProvider = {
13
+ id: "groq",
14
+ label: "Groq",
15
+ authEnv: ["GROQ_API_KEY"],
16
+ baseUrl: BASE,
17
+ defaultModel: "llama-3.3-70b-versatile",
18
+ listModels: (apiKey) => listModelsHttp({ baseUrl: BASE, apiKey, staticModels: STATIC }),
19
+ stream: (req, apiKey) => streamChatCompletion(req, { baseUrl: BASE, apiKey, staticModels: STATIC }),
20
+ };
@@ -0,0 +1,201 @@
1
+ export declare const PROVIDERS: ({
2
+ id: string;
3
+ label: string;
4
+ authEnv: string[];
5
+ baseUrl: string;
6
+ defaultModel: string;
7
+ listModels(apiKey: any): Promise<any>;
8
+ stream(req: any, apiKey: any): AsyncGenerator<{
9
+ delta: any;
10
+ done: boolean;
11
+ usage?: undefined;
12
+ } | {
13
+ delta: string;
14
+ done: boolean;
15
+ usage: {
16
+ inputTokens: number;
17
+ outputTokens: number;
18
+ costUsd: number;
19
+ };
20
+ }, void, unknown>;
21
+ } | {
22
+ id: string;
23
+ label: string;
24
+ authEnv: string[];
25
+ readonly baseUrl: string;
26
+ defaultModel: string;
27
+ listModels: (apiKey: any) => Promise<any>;
28
+ stream: (req: any, apiKey: any) => AsyncGenerator<{
29
+ delta: string;
30
+ done: boolean;
31
+ reasoning?: undefined;
32
+ usage?: undefined;
33
+ } | {
34
+ delta: string;
35
+ done: boolean;
36
+ reasoning: string;
37
+ usage?: undefined;
38
+ } | {
39
+ delta: string;
40
+ done: boolean;
41
+ usage: any;
42
+ reasoning?: undefined;
43
+ }, void, unknown>;
44
+ } | {
45
+ id: string;
46
+ label: string;
47
+ authEnv: any[];
48
+ readonly baseUrl: string;
49
+ defaultModel: string;
50
+ listModels: () => Promise<any>;
51
+ stream: (req: any) => AsyncGenerator<{
52
+ delta: string;
53
+ done: boolean;
54
+ reasoning?: undefined;
55
+ usage?: undefined;
56
+ } | {
57
+ delta: string;
58
+ done: boolean;
59
+ reasoning: string;
60
+ usage?: undefined;
61
+ } | {
62
+ delta: string;
63
+ done: boolean;
64
+ usage: any;
65
+ reasoning?: undefined;
66
+ }, void, unknown>;
67
+ })[];
68
+ export declare function getProvider(id: any): {
69
+ id: string;
70
+ label: string;
71
+ authEnv: string[];
72
+ baseUrl: string;
73
+ defaultModel: string;
74
+ listModels(apiKey: any): Promise<any>;
75
+ stream(req: any, apiKey: any): AsyncGenerator<{
76
+ delta: any;
77
+ done: boolean;
78
+ usage?: undefined;
79
+ } | {
80
+ delta: string;
81
+ done: boolean;
82
+ usage: {
83
+ inputTokens: number;
84
+ outputTokens: number;
85
+ costUsd: number;
86
+ };
87
+ }, void, unknown>;
88
+ } | {
89
+ id: string;
90
+ label: string;
91
+ authEnv: string[];
92
+ readonly baseUrl: string;
93
+ defaultModel: string;
94
+ listModels: (apiKey: any) => Promise<any>;
95
+ stream: (req: any, apiKey: any) => AsyncGenerator<{
96
+ delta: string;
97
+ done: boolean;
98
+ reasoning?: undefined;
99
+ usage?: undefined;
100
+ } | {
101
+ delta: string;
102
+ done: boolean;
103
+ reasoning: string;
104
+ usage?: undefined;
105
+ } | {
106
+ delta: string;
107
+ done: boolean;
108
+ usage: any;
109
+ reasoning?: undefined;
110
+ }, void, unknown>;
111
+ } | {
112
+ id: string;
113
+ label: string;
114
+ authEnv: any[];
115
+ readonly baseUrl: string;
116
+ defaultModel: string;
117
+ listModels: () => Promise<any>;
118
+ stream: (req: any) => AsyncGenerator<{
119
+ delta: string;
120
+ done: boolean;
121
+ reasoning?: undefined;
122
+ usage?: undefined;
123
+ } | {
124
+ delta: string;
125
+ done: boolean;
126
+ reasoning: string;
127
+ usage?: undefined;
128
+ } | {
129
+ delta: string;
130
+ done: boolean;
131
+ usage: any;
132
+ reasoning?: undefined;
133
+ }, void, unknown>;
134
+ };
135
+ export declare function getProviderOrThrow(id: any): {
136
+ id: string;
137
+ label: string;
138
+ authEnv: string[];
139
+ baseUrl: string;
140
+ defaultModel: string;
141
+ listModels(apiKey: any): Promise<any>;
142
+ stream(req: any, apiKey: any): AsyncGenerator<{
143
+ delta: any;
144
+ done: boolean;
145
+ usage?: undefined;
146
+ } | {
147
+ delta: string;
148
+ done: boolean;
149
+ usage: {
150
+ inputTokens: number;
151
+ outputTokens: number;
152
+ costUsd: number;
153
+ };
154
+ }, void, unknown>;
155
+ } | {
156
+ id: string;
157
+ label: string;
158
+ authEnv: string[];
159
+ readonly baseUrl: string;
160
+ defaultModel: string;
161
+ listModels: (apiKey: any) => Promise<any>;
162
+ stream: (req: any, apiKey: any) => AsyncGenerator<{
163
+ delta: string;
164
+ done: boolean;
165
+ reasoning?: undefined;
166
+ usage?: undefined;
167
+ } | {
168
+ delta: string;
169
+ done: boolean;
170
+ reasoning: string;
171
+ usage?: undefined;
172
+ } | {
173
+ delta: string;
174
+ done: boolean;
175
+ usage: any;
176
+ reasoning?: undefined;
177
+ }, void, unknown>;
178
+ } | {
179
+ id: string;
180
+ label: string;
181
+ authEnv: any[];
182
+ readonly baseUrl: string;
183
+ defaultModel: string;
184
+ listModels: () => Promise<any>;
185
+ stream: (req: any) => AsyncGenerator<{
186
+ delta: string;
187
+ done: boolean;
188
+ reasoning?: undefined;
189
+ usage?: undefined;
190
+ } | {
191
+ delta: string;
192
+ done: boolean;
193
+ reasoning: string;
194
+ usage?: undefined;
195
+ } | {
196
+ delta: string;
197
+ done: boolean;
198
+ usage: any;
199
+ reasoning?: undefined;
200
+ }, void, unknown>;
201
+ };