@funkai/agents 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/.generated/req.txt +1 -0
- package/.turbo/turbo-build.log +21 -0
- package/.turbo/turbo-test$colon$coverage.log +109 -0
- package/.turbo/turbo-test.log +141 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/CHANGELOG.md +16 -0
- package/ISSUES.md +540 -0
- package/LICENSE +21 -0
- package/README.md +128 -0
- package/banner.svg +97 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/core/agents/base/agent.ts.html +1705 -0
- package/coverage/lcov-report/core/agents/base/index.html +146 -0
- package/coverage/lcov-report/core/agents/base/output.ts.html +256 -0
- package/coverage/lcov-report/core/agents/base/utils.ts.html +694 -0
- package/coverage/lcov-report/core/agents/flow/engine.ts.html +928 -0
- package/coverage/lcov-report/core/agents/flow/flow-agent.ts.html +1462 -0
- package/coverage/lcov-report/core/agents/flow/index.html +146 -0
- package/coverage/lcov-report/core/agents/flow/messages.ts.html +508 -0
- package/coverage/lcov-report/core/agents/flow/steps/factory.ts.html +1975 -0
- package/coverage/lcov-report/core/agents/flow/steps/index.html +116 -0
- package/coverage/lcov-report/core/index.html +131 -0
- package/coverage/lcov-report/core/logger.ts.html +541 -0
- package/coverage/lcov-report/core/models/providers/index.html +116 -0
- package/coverage/lcov-report/core/models/providers/openai.ts.html +337 -0
- package/coverage/lcov-report/core/provider/index.html +131 -0
- package/coverage/lcov-report/core/provider/provider.ts.html +346 -0
- package/coverage/lcov-report/core/provider/usage.ts.html +376 -0
- package/coverage/lcov-report/core/tool.ts.html +577 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +221 -0
- package/coverage/lcov-report/lib/hooks.ts.html +262 -0
- package/coverage/lcov-report/lib/index.html +161 -0
- package/coverage/lcov-report/lib/middleware.ts.html +274 -0
- package/coverage/lcov-report/lib/runnable.ts.html +151 -0
- package/coverage/lcov-report/lib/trace.ts.html +520 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/utils/attempt.ts.html +199 -0
- package/coverage/lcov-report/utils/error.ts.html +421 -0
- package/coverage/lcov-report/utils/index.html +176 -0
- package/coverage/lcov-report/utils/resolve.ts.html +208 -0
- package/coverage/lcov-report/utils/result.ts.html +538 -0
- package/coverage/lcov-report/utils/zod.ts.html +178 -0
- package/coverage/lcov.info +1566 -0
- package/dist/index.d.mts +2883 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2312 -0
- package/dist/index.mjs.map +1 -0
- package/docs/core/agent.md +231 -0
- package/docs/core/hooks.md +95 -0
- package/docs/core/overview.md +87 -0
- package/docs/core/step.md +279 -0
- package/docs/core/tools.md +98 -0
- package/docs/core/workflow.md +235 -0
- package/docs/guides/create-agent.md +224 -0
- package/docs/guides/create-tool.md +137 -0
- package/docs/guides/create-workflow.md +374 -0
- package/docs/overview.md +244 -0
- package/docs/provider/models.md +55 -0
- package/docs/provider/overview.md +106 -0
- package/docs/provider/usage.md +100 -0
- package/docs/research/experimental-context.md +167 -0
- package/docs/research/gap-analysis.md +86 -0
- package/docs/research/prepare-step-and-active-tools.md +138 -0
- package/docs/research/sub-agent-model.md +249 -0
- package/docs/troubleshooting.md +60 -0
- package/logo.svg +17 -0
- package/models.config.json +18 -0
- package/package.json +60 -0
- package/scripts/generate-models.ts +324 -0
- package/src/core/agents/base/agent.test.ts +1522 -0
- package/src/core/agents/base/agent.ts +547 -0
- package/src/core/agents/base/output.test.ts +93 -0
- package/src/core/agents/base/output.ts +57 -0
- package/src/core/agents/base/types.test-d.ts +69 -0
- package/src/core/agents/base/types.ts +503 -0
- package/src/core/agents/base/utils.test.ts +397 -0
- package/src/core/agents/base/utils.ts +197 -0
- package/src/core/agents/flow/engine.test.ts +452 -0
- package/src/core/agents/flow/engine.ts +281 -0
- package/src/core/agents/flow/flow-agent.test.ts +1027 -0
- package/src/core/agents/flow/flow-agent.ts +473 -0
- package/src/core/agents/flow/messages.test.ts +198 -0
- package/src/core/agents/flow/messages.ts +141 -0
- package/src/core/agents/flow/steps/agent.test.ts +280 -0
- package/src/core/agents/flow/steps/agent.ts +87 -0
- package/src/core/agents/flow/steps/all.test.ts +300 -0
- package/src/core/agents/flow/steps/all.ts +73 -0
- package/src/core/agents/flow/steps/builder.ts +124 -0
- package/src/core/agents/flow/steps/each.test.ts +257 -0
- package/src/core/agents/flow/steps/each.ts +61 -0
- package/src/core/agents/flow/steps/factory.test-d.ts +50 -0
- package/src/core/agents/flow/steps/factory.test.ts +1025 -0
- package/src/core/agents/flow/steps/factory.ts +645 -0
- package/src/core/agents/flow/steps/map.test.ts +273 -0
- package/src/core/agents/flow/steps/map.ts +75 -0
- package/src/core/agents/flow/steps/race.test.ts +290 -0
- package/src/core/agents/flow/steps/race.ts +59 -0
- package/src/core/agents/flow/steps/reduce.test.ts +310 -0
- package/src/core/agents/flow/steps/reduce.ts +73 -0
- package/src/core/agents/flow/steps/result.ts +27 -0
- package/src/core/agents/flow/steps/step.test.ts +402 -0
- package/src/core/agents/flow/steps/step.ts +51 -0
- package/src/core/agents/flow/steps/while.test.ts +283 -0
- package/src/core/agents/flow/steps/while.ts +75 -0
- package/src/core/agents/flow/types.ts +348 -0
- package/src/core/logger.test.ts +163 -0
- package/src/core/logger.ts +152 -0
- package/src/core/models/index.test.ts +137 -0
- package/src/core/models/index.ts +152 -0
- package/src/core/models/providers/openai.ts +84 -0
- package/src/core/provider/provider.test.ts +128 -0
- package/src/core/provider/provider.ts +99 -0
- package/src/core/provider/types.ts +98 -0
- package/src/core/provider/usage.test.ts +304 -0
- package/src/core/provider/usage.ts +97 -0
- package/src/core/tool.test.ts +65 -0
- package/src/core/tool.ts +164 -0
- package/src/core/types.ts +66 -0
- package/src/index.ts +95 -0
- package/src/lib/context.test.ts +86 -0
- package/src/lib/context.ts +49 -0
- package/src/lib/hooks.test.ts +102 -0
- package/src/lib/hooks.ts +59 -0
- package/src/lib/middleware.test.ts +122 -0
- package/src/lib/middleware.ts +63 -0
- package/src/lib/runnable.test.ts +41 -0
- package/src/lib/runnable.ts +22 -0
- package/src/lib/trace.test.ts +291 -0
- package/src/lib/trace.ts +145 -0
- package/src/models/index.ts +123 -0
- package/src/models/providers/index.ts +15 -0
- package/src/models/providers/openai.ts +84 -0
- package/src/testing/context.ts +32 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/logger.ts +19 -0
- package/src/utils/attempt.test.ts +127 -0
- package/src/utils/attempt.ts +38 -0
- package/src/utils/error.test.ts +179 -0
- package/src/utils/error.ts +112 -0
- package/src/utils/resolve.test.ts +38 -0
- package/src/utils/resolve.ts +41 -0
- package/src/utils/result.test.ts +79 -0
- package/src/utils/result.ts +151 -0
- package/src/utils/zod.test.ts +69 -0
- package/src/utils/zod.ts +31 -0
- package/tsconfig.json +25 -0
- package/tsdown.config.ts +15 -0
- package/vitest.config.ts +46 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/* eslint-disable security/detect-non-literal-fs-filename */
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
import { OpenRouter } from "@openrouter/sdk";
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const PACKAGE_ROOT = join(__dirname, "..");
|
|
10
|
+
const CONFIG_PATH = join(PACKAGE_ROOT, "models.config.json");
|
|
11
|
+
const MODELS_DIR = join(PACKAGE_ROOT, "src", "models");
|
|
12
|
+
const PROVIDERS_DIR = join(MODELS_DIR, "providers");
|
|
13
|
+
const GENERATED_DIR = join(PACKAGE_ROOT, ".generated");
|
|
14
|
+
const REQ_PATH = join(GENERATED_DIR, "req.txt");
|
|
15
|
+
|
|
16
|
+
const STALE_MS = 24 * 60 * 60 * 1000;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Pricing fields we extract from the OpenRouter API.
|
|
20
|
+
* Maps API field name → our camelCase field name.
|
|
21
|
+
*/
|
|
22
|
+
const PRICING_FIELDS: Record<string, string> = {
|
|
23
|
+
prompt: "prompt",
|
|
24
|
+
completion: "completion",
|
|
25
|
+
inputCacheRead: "inputCacheRead",
|
|
26
|
+
inputCacheWrite: "inputCacheWrite",
|
|
27
|
+
webSearch: "webSearch",
|
|
28
|
+
internalReasoning: "internalReasoning",
|
|
29
|
+
image: "image",
|
|
30
|
+
audio: "audio",
|
|
31
|
+
audioOutput: "audioOutput",
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Banner
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
const BANNER = `// ──────────────────────────────────────────────────────────────
|
|
39
|
+
// █████╗ ██████╗ ███████╗███╗ ██╗████████╗███████╗
|
|
40
|
+
// ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝██╔════╝
|
|
41
|
+
// ███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ███████╗
|
|
42
|
+
// ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ╚════██║
|
|
43
|
+
// ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ███████║
|
|
44
|
+
// ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝
|
|
45
|
+
//
|
|
46
|
+
// AUTO-GENERATED — DO NOT EDIT
|
|
47
|
+
// Update: pnpm --filter=@pkg/agent-sdk generate:models
|
|
48
|
+
// ──────────────────────────────────────────────────────────────`;
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Types
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
interface ConfigEntry {
|
|
55
|
+
id: string;
|
|
56
|
+
category: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Helpers
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Convert a provider key to a constant name.
|
|
65
|
+
* e.g. "openai" → "OPENAI_MODELS"
|
|
66
|
+
*/
|
|
67
|
+
function toConstName(provider: string): string {
|
|
68
|
+
return `${provider.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_MODELS`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Build the pricing object string for a model, including only non-zero fields.
|
|
73
|
+
*/
|
|
74
|
+
function buildPricing(apiPricing: Record<string, string | undefined>): string {
|
|
75
|
+
const parts: string[] = [];
|
|
76
|
+
for (const [apiKey, ourKey] of Object.entries(PRICING_FIELDS)) {
|
|
77
|
+
// eslint-disable-next-line security/detect-object-injection -- Key from Object.entries iteration over a static config object
|
|
78
|
+
const raw = apiPricing[apiKey];
|
|
79
|
+
if (!raw) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const value = parseFloat(raw);
|
|
83
|
+
if (value === 0) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
parts.push(`${ourKey}: ${value}`);
|
|
87
|
+
}
|
|
88
|
+
return `{ ${parts.join(", ")} }`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// Staleness check
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
function isFresh(): boolean {
|
|
96
|
+
if (!existsSync(REQ_PATH)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const timestamp = readFileSync(REQ_PATH, "utf-8").trim();
|
|
101
|
+
const lastRun = new Date(timestamp).getTime();
|
|
102
|
+
return Date.now() - lastRun < STALE_MS;
|
|
103
|
+
} catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
// Templates
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Root index.ts — types, helpers, re-exports.
|
|
114
|
+
*/
|
|
115
|
+
function rootIndex(): string {
|
|
116
|
+
return `${BANNER}
|
|
117
|
+
|
|
118
|
+
import { MODELS as GENERATED_MODELS } from './providers/index.js'
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Supported OpenRouter model identifiers, derived from the generated {@link MODELS} array.
|
|
122
|
+
*/
|
|
123
|
+
export type OpenRouterLanguageModelId = (typeof GENERATED_MODELS)[number]['id']
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Model category for classification and filtering.
|
|
127
|
+
*/
|
|
128
|
+
export type ModelCategory = 'chat' | 'coding' | 'reasoning'
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Per-model pricing in USD per token.
|
|
132
|
+
*
|
|
133
|
+
* Field names match the OpenRouter API convention. All values are
|
|
134
|
+
* per-token (or per-unit) rates as numbers. Optional fields are
|
|
135
|
+
* omitted when the provider does not support them.
|
|
136
|
+
*/
|
|
137
|
+
export interface ModelPricing {
|
|
138
|
+
/** Cost per input (prompt) token. */
|
|
139
|
+
prompt: number
|
|
140
|
+
|
|
141
|
+
/** Cost per output (completion) token. */
|
|
142
|
+
completion: number
|
|
143
|
+
|
|
144
|
+
/** Cost per cached input token (read). */
|
|
145
|
+
inputCacheRead?: number
|
|
146
|
+
|
|
147
|
+
/** Cost per cached input token (write). */
|
|
148
|
+
inputCacheWrite?: number
|
|
149
|
+
|
|
150
|
+
/** Cost per web search request. */
|
|
151
|
+
webSearch?: number
|
|
152
|
+
|
|
153
|
+
/** Cost per internal reasoning token. */
|
|
154
|
+
internalReasoning?: number
|
|
155
|
+
|
|
156
|
+
/** Cost per image input token. */
|
|
157
|
+
image?: number
|
|
158
|
+
|
|
159
|
+
/** Cost per audio input second. */
|
|
160
|
+
audio?: number
|
|
161
|
+
|
|
162
|
+
/** Cost per audio output second. */
|
|
163
|
+
audioOutput?: number
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Model definition with metadata and pricing.
|
|
168
|
+
*/
|
|
169
|
+
export interface ModelDefinition {
|
|
170
|
+
/** OpenRouter model identifier (e.g. \`"openai/gpt-5.2-codex"\`). */
|
|
171
|
+
id: string
|
|
172
|
+
|
|
173
|
+
/** Model category for classification. */
|
|
174
|
+
category: ModelCategory
|
|
175
|
+
|
|
176
|
+
/** Token pricing rates. */
|
|
177
|
+
pricing: ModelPricing
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Supported OpenRouter models with pricing data.
|
|
182
|
+
*/
|
|
183
|
+
export const MODELS = GENERATED_MODELS satisfies readonly ModelDefinition[]
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Look up a model definition by its identifier.
|
|
187
|
+
*
|
|
188
|
+
* @param id - The model identifier to look up.
|
|
189
|
+
* @returns The matching model definition.
|
|
190
|
+
* @throws {Error} If no model matches the given ID.
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* \`\`\`typescript
|
|
194
|
+
* const m = model('openai/gpt-5.2-codex')
|
|
195
|
+
* console.log(m.pricing.prompt) // 0.00000175
|
|
196
|
+
* console.log(m.category) // 'coding'
|
|
197
|
+
* \`\`\`
|
|
198
|
+
*/
|
|
199
|
+
export function model(id: OpenRouterLanguageModelId): ModelDefinition {
|
|
200
|
+
const found = MODELS.find((m) => m.id === id)
|
|
201
|
+
if (!found) {
|
|
202
|
+
throw new Error(\`Unknown model: \${id}\`)
|
|
203
|
+
}
|
|
204
|
+
return found
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Return supported model definitions, optionally filtered.
|
|
209
|
+
*
|
|
210
|
+
* @param filter - Optional predicate to filter models.
|
|
211
|
+
* @returns A readonly array of matching model definitions.
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* \`\`\`typescript
|
|
215
|
+
* const all = models()
|
|
216
|
+
* const reasoning = models((m) => m.category === 'reasoning')
|
|
217
|
+
* \`\`\`
|
|
218
|
+
*/
|
|
219
|
+
export function models(filter?: (m: ModelDefinition) => boolean): readonly ModelDefinition[] {
|
|
220
|
+
return filter ? MODELS.filter(filter) : MODELS
|
|
221
|
+
}
|
|
222
|
+
`;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// ---------------------------------------------------------------------------
|
|
226
|
+
// Main
|
|
227
|
+
// ---------------------------------------------------------------------------
|
|
228
|
+
|
|
229
|
+
async function main(): Promise<void> {
|
|
230
|
+
if (isFresh()) {
|
|
231
|
+
console.log("generate-models: skipping — last fetch was less than 24h ago");
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const config: Record<string, ConfigEntry[]> = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
236
|
+
|
|
237
|
+
const providers = Object.keys(config);
|
|
238
|
+
if (providers.length === 0) {
|
|
239
|
+
throw new Error("models.config.json has no providers");
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
console.log("generate-models: fetching models from OpenRouter SDK");
|
|
243
|
+
const client = new OpenRouter();
|
|
244
|
+
const response = await client.models.list();
|
|
245
|
+
const apiModels = response.data ?? [];
|
|
246
|
+
const modelMap = new Map(apiModels.map((m) => [m.id, m]));
|
|
247
|
+
|
|
248
|
+
console.log(`generate-models: ${apiModels.length} models from API`);
|
|
249
|
+
|
|
250
|
+
mkdirSync(GENERATED_DIR, { recursive: true });
|
|
251
|
+
|
|
252
|
+
// Clean and recreate entire models dir (everything is generated)
|
|
253
|
+
rmSync(MODELS_DIR, { recursive: true, force: true });
|
|
254
|
+
mkdirSync(PROVIDERS_DIR, { recursive: true });
|
|
255
|
+
|
|
256
|
+
const providerFiles: { provider: string; constName: string }[] = [];
|
|
257
|
+
|
|
258
|
+
for (const provider of providers) {
|
|
259
|
+
// eslint-disable-next-line security/detect-object-injection -- Provider key from controlled iteration, not user input
|
|
260
|
+
const entries = config[provider];
|
|
261
|
+
const constName = toConstName(provider);
|
|
262
|
+
const lines: string[] = [];
|
|
263
|
+
|
|
264
|
+
for (const entry of entries) {
|
|
265
|
+
const apiModel = modelMap.get(entry.id);
|
|
266
|
+
if (!apiModel) {
|
|
267
|
+
console.warn(` ⚠ ${entry.id} not found in OpenRouter API — skipping`);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const pricing = buildPricing(
|
|
272
|
+
apiModel.pricing as unknown as Record<string, string | undefined>,
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
lines.push(` { id: '${entry.id}', category: '${entry.category}', pricing: ${pricing} },`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const content = `${BANNER}
|
|
279
|
+
|
|
280
|
+
export const ${constName} = [
|
|
281
|
+
${lines.join("\n")}
|
|
282
|
+
] as const
|
|
283
|
+
`;
|
|
284
|
+
|
|
285
|
+
const filePath = join(PROVIDERS_DIR, `${provider}.ts`);
|
|
286
|
+
writeFileSync(filePath, content, "utf-8");
|
|
287
|
+
console.log(` ✓ providers/${provider}.ts (${lines.length} models)`);
|
|
288
|
+
|
|
289
|
+
providerFiles.push({ provider, constName });
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Providers barrel
|
|
293
|
+
const imports = providerFiles
|
|
294
|
+
.map((p) => `import { ${p.constName} } from './${p.provider}.js'`)
|
|
295
|
+
.join("\n");
|
|
296
|
+
|
|
297
|
+
const spreads = providerFiles.map((p) => ` ...${p.constName},`).join("\n");
|
|
298
|
+
|
|
299
|
+
const providersBarrel = `${BANNER}
|
|
300
|
+
|
|
301
|
+
${imports}
|
|
302
|
+
|
|
303
|
+
export const MODELS = [
|
|
304
|
+
${spreads}
|
|
305
|
+
] as const
|
|
306
|
+
`;
|
|
307
|
+
|
|
308
|
+
writeFileSync(join(PROVIDERS_DIR, "index.ts"), providersBarrel, "utf-8");
|
|
309
|
+
console.log(" ✓ providers/index.ts (barrel)");
|
|
310
|
+
|
|
311
|
+
// Root index
|
|
312
|
+
writeFileSync(join(MODELS_DIR, "index.ts"), rootIndex(), "utf-8");
|
|
313
|
+
console.log(" ✓ index.ts (types + helpers)");
|
|
314
|
+
|
|
315
|
+
// Staleness timestamp
|
|
316
|
+
writeFileSync(REQ_PATH, new Date().toISOString(), "utf-8");
|
|
317
|
+
|
|
318
|
+
console.log("generate-models: done");
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
main().catch((err) => {
|
|
322
|
+
console.error("generate-models: fatal error", err);
|
|
323
|
+
process.exit(1);
|
|
324
|
+
});
|