trickle-cli 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/dist/api-client.d.ts +208 -0
- package/dist/api-client.js +237 -0
- package/dist/commands/annotate.d.ts +6 -0
- package/dist/commands/annotate.js +433 -0
- package/dist/commands/audit.d.ts +7 -0
- package/dist/commands/audit.js +82 -0
- package/dist/commands/auto.d.ts +8 -0
- package/dist/commands/auto.js +268 -0
- package/dist/commands/capture.d.ts +14 -0
- package/dist/commands/capture.js +271 -0
- package/dist/commands/check.d.ts +6 -0
- package/dist/commands/check.js +408 -0
- package/dist/commands/codegen.d.ts +21 -0
- package/dist/commands/codegen.js +129 -0
- package/dist/commands/coverage.d.ts +13 -0
- package/dist/commands/coverage.js +126 -0
- package/dist/commands/dashboard.d.ts +1 -0
- package/dist/commands/dashboard.js +83 -0
- package/dist/commands/dev.d.ts +14 -0
- package/dist/commands/dev.js +319 -0
- package/dist/commands/diff.d.ts +7 -0
- package/dist/commands/diff.js +79 -0
- package/dist/commands/docs.d.ts +13 -0
- package/dist/commands/docs.js +383 -0
- package/dist/commands/errors.d.ts +7 -0
- package/dist/commands/errors.js +180 -0
- package/dist/commands/export.d.ts +18 -0
- package/dist/commands/export.js +238 -0
- package/dist/commands/functions.d.ts +6 -0
- package/dist/commands/functions.js +71 -0
- package/dist/commands/infer.d.ts +14 -0
- package/dist/commands/infer.js +275 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.js +395 -0
- package/dist/commands/mock.d.ts +5 -0
- package/dist/commands/mock.js +232 -0
- package/dist/commands/openapi.d.ts +8 -0
- package/dist/commands/openapi.js +82 -0
- package/dist/commands/overview.d.ts +11 -0
- package/dist/commands/overview.js +266 -0
- package/dist/commands/pack.d.ts +11 -0
- package/dist/commands/pack.js +133 -0
- package/dist/commands/proxy.d.ts +13 -0
- package/dist/commands/proxy.js +312 -0
- package/dist/commands/replay.d.ts +14 -0
- package/dist/commands/replay.js +289 -0
- package/dist/commands/run.d.ts +17 -0
- package/dist/commands/run.js +997 -0
- package/dist/commands/sample.d.ts +13 -0
- package/dist/commands/sample.js +260 -0
- package/dist/commands/search.d.ts +5 -0
- package/dist/commands/search.js +80 -0
- package/dist/commands/stubs.d.ts +6 -0
- package/dist/commands/stubs.js +187 -0
- package/dist/commands/tail.d.ts +4 -0
- package/dist/commands/tail.js +76 -0
- package/dist/commands/test-gen.d.ts +13 -0
- package/dist/commands/test-gen.js +237 -0
- package/dist/commands/trace.d.ts +14 -0
- package/dist/commands/trace.js +417 -0
- package/dist/commands/types.d.ts +7 -0
- package/dist/commands/types.js +128 -0
- package/dist/commands/unpack.d.ts +11 -0
- package/dist/commands/unpack.js +166 -0
- package/dist/commands/validate.d.ts +13 -0
- package/dist/commands/validate.js +310 -0
- package/dist/commands/watch.d.ts +9 -0
- package/dist/commands/watch.js +267 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +66 -0
- package/dist/formatters/diff-formatter.d.ts +5 -0
- package/dist/formatters/diff-formatter.js +43 -0
- package/dist/formatters/type-formatter.d.ts +22 -0
- package/dist/formatters/type-formatter.js +135 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +419 -0
- package/dist/local-codegen.d.ts +22 -0
- package/dist/local-codegen.js +762 -0
- package/dist/ui/badges.d.ts +16 -0
- package/dist/ui/badges.js +71 -0
- package/dist/ui/helpers.d.ts +13 -0
- package/dist/ui/helpers.js +85 -0
- package/package.json +23 -0
- package/src/api-client.ts +407 -0
- package/src/commands/annotate.ts +450 -0
- package/src/commands/audit.ts +103 -0
- package/src/commands/auto.ts +268 -0
- package/src/commands/capture.ts +257 -0
- package/src/commands/check.ts +437 -0
- package/src/commands/codegen.ts +128 -0
- package/src/commands/coverage.ts +170 -0
- package/src/commands/dashboard.ts +46 -0
- package/src/commands/dev.ts +323 -0
- package/src/commands/diff.ts +99 -0
- package/src/commands/docs.ts +392 -0
- package/src/commands/errors.ts +205 -0
- package/src/commands/export.ts +287 -0
- package/src/commands/functions.ts +81 -0
- package/src/commands/infer.ts +260 -0
- package/src/commands/init.ts +419 -0
- package/src/commands/mock.ts +220 -0
- package/src/commands/openapi.ts +53 -0
- package/src/commands/overview.ts +310 -0
- package/src/commands/pack.ts +139 -0
- package/src/commands/proxy.ts +314 -0
- package/src/commands/replay.ts +356 -0
- package/src/commands/run.ts +1190 -0
- package/src/commands/sample.ts +259 -0
- package/src/commands/search.ts +107 -0
- package/src/commands/stubs.ts +211 -0
- package/src/commands/tail.ts +94 -0
- package/src/commands/test-gen.ts +236 -0
- package/src/commands/trace.ts +440 -0
- package/src/commands/types.ts +161 -0
- package/src/commands/unpack.ts +179 -0
- package/src/commands/validate.ts +368 -0
- package/src/commands/watch.ts +277 -0
- package/src/config.ts +38 -0
- package/src/formatters/diff-formatter.ts +51 -0
- package/src/formatters/type-formatter.ts +161 -0
- package/src/index.ts +454 -0
- package/src/local-codegen.ts +859 -0
- package/src/ui/badges.ts +66 -0
- package/src/ui/helpers.ts +80 -0
- package/tsconfig.json +8 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { functionsCommand } from "./commands/functions";
|
|
6
|
+
import { typesCommand } from "./commands/types";
|
|
7
|
+
import { errorsCommand } from "./commands/errors";
|
|
8
|
+
import { tailCommand } from "./commands/tail";
|
|
9
|
+
import { codegenCommand } from "./commands/codegen";
|
|
10
|
+
import { mockCommand } from "./commands/mock";
|
|
11
|
+
import { initCommand } from "./commands/init";
|
|
12
|
+
import { diffCommand } from "./commands/diff";
|
|
13
|
+
import { openapiCommand } from "./commands/openapi";
|
|
14
|
+
import { checkCommand } from "./commands/check";
|
|
15
|
+
import { devCommand } from "./commands/dev";
|
|
16
|
+
import { testGenCommand } from "./commands/test-gen";
|
|
17
|
+
import { dashboardCommand } from "./commands/dashboard";
|
|
18
|
+
import { proxyCommand } from "./commands/proxy";
|
|
19
|
+
import { exportCommand } from "./commands/export";
|
|
20
|
+
import { coverageCommand } from "./commands/coverage";
|
|
21
|
+
import { replayCommand } from "./commands/replay";
|
|
22
|
+
import { docsCommand } from "./commands/docs";
|
|
23
|
+
import { sampleCommand } from "./commands/sample";
|
|
24
|
+
import { auditCommand } from "./commands/audit";
|
|
25
|
+
import { captureCommand } from "./commands/capture";
|
|
26
|
+
import { searchCommand } from "./commands/search";
|
|
27
|
+
import { autoCommand } from "./commands/auto";
|
|
28
|
+
import { validateCommand } from "./commands/validate";
|
|
29
|
+
import { watchCommand } from "./commands/watch";
|
|
30
|
+
import { inferCommand } from "./commands/infer";
|
|
31
|
+
import { overviewCommand } from "./commands/overview";
|
|
32
|
+
import { traceCommand } from "./commands/trace";
|
|
33
|
+
import { packCommand } from "./commands/pack";
|
|
34
|
+
import { unpackCommand } from "./commands/unpack";
|
|
35
|
+
import { runCommand } from "./commands/run";
|
|
36
|
+
import { annotateCommand } from "./commands/annotate";
|
|
37
|
+
import { stubsCommand } from "./commands/stubs";
|
|
38
|
+
|
|
39
|
+
const program = new Command();
|
|
40
|
+
|
|
41
|
+
program
|
|
42
|
+
.name("trickle")
|
|
43
|
+
.description("CLI for trickle runtime type observability")
|
|
44
|
+
.version("0.1.0");
|
|
45
|
+
|
|
46
|
+
// trickle init
|
|
47
|
+
program
|
|
48
|
+
.command("init")
|
|
49
|
+
.description("Set up trickle in your project — configures types, tsconfig, and npm scripts")
|
|
50
|
+
.option("--dir <path>", "Project directory (defaults to current directory)")
|
|
51
|
+
.option("--python", "Set up for a Python project")
|
|
52
|
+
.action(async (opts) => {
|
|
53
|
+
await initCommand(opts);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// trickle dev [command]
|
|
57
|
+
program
|
|
58
|
+
.command("dev [command]")
|
|
59
|
+
.description("Start your app with auto-instrumentation and live type generation")
|
|
60
|
+
.option("-o, --out <path>", "Types output path (default: .trickle/types.d.ts)")
|
|
61
|
+
.option("--client", "Also generate typed API client (.trickle/api-client.ts)")
|
|
62
|
+
.option("--python", "Generate Python type stubs instead of TypeScript")
|
|
63
|
+
.action(async (command: string | undefined, opts) => {
|
|
64
|
+
await devCommand(command, opts);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// trickle run <command>
|
|
68
|
+
program
|
|
69
|
+
.command("run [command]")
|
|
70
|
+
.description("Run any command or file with universal type observation — zero code changes needed")
|
|
71
|
+
.option("--module <name>", "Module name for captured functions")
|
|
72
|
+
.option("--include <patterns>", "Comma-separated substrings — only observe matching modules")
|
|
73
|
+
.option("--exclude <patterns>", "Comma-separated substrings — skip matching modules")
|
|
74
|
+
.option("--stubs <dir>", "Auto-generate .d.ts/.pyi type stubs in this directory after the run")
|
|
75
|
+
.option("--annotate <path>", "Auto-annotate this file or directory with types after the run")
|
|
76
|
+
.option("-w, --watch", "Watch source files and re-run on changes")
|
|
77
|
+
.action(async (command: string | undefined, opts) => {
|
|
78
|
+
await runCommand(command, opts);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// trickle functions
|
|
82
|
+
program
|
|
83
|
+
.command("functions")
|
|
84
|
+
.description("List observed functions")
|
|
85
|
+
.option("--env <env>", "Filter by environment")
|
|
86
|
+
.option("--lang <lang>", "Filter by language")
|
|
87
|
+
.option("--search <query>", "Search by function name")
|
|
88
|
+
.action(async (opts) => {
|
|
89
|
+
await functionsCommand(opts);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// trickle types <function-name>
|
|
93
|
+
program
|
|
94
|
+
.command("types <function-name>")
|
|
95
|
+
.description("Show type snapshots for a function")
|
|
96
|
+
.option("--env <env>", "Filter by environment")
|
|
97
|
+
.option("--diff", "Show diff between latest two snapshots")
|
|
98
|
+
.option("--env1 <env>", "First environment for cross-env diff")
|
|
99
|
+
.option("--env2 <env>", "Second environment for cross-env diff")
|
|
100
|
+
.action(async (functionName: string, opts) => {
|
|
101
|
+
await typesCommand(functionName, opts);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// trickle errors [id]
|
|
105
|
+
program
|
|
106
|
+
.command("errors [id]")
|
|
107
|
+
.description("List errors or show error detail")
|
|
108
|
+
.option("--env <env>", "Filter by environment")
|
|
109
|
+
.option("--since <timeframe>", "Show errors since (e.g., 2d, 5m, 1h)")
|
|
110
|
+
.option("--function <name>", "Filter by function name")
|
|
111
|
+
.option("--limit <n>", "Limit number of results")
|
|
112
|
+
.action(async (id: string | undefined, opts) => {
|
|
113
|
+
await errorsCommand(id, opts);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// trickle tail
|
|
117
|
+
program
|
|
118
|
+
.command("tail")
|
|
119
|
+
.description("Stream live events from the backend")
|
|
120
|
+
.option("--filter <pattern>", "Filter by function name pattern")
|
|
121
|
+
.action(async (opts) => {
|
|
122
|
+
await tailCommand(opts);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// trickle codegen [function-name]
|
|
126
|
+
program
|
|
127
|
+
.command("codegen [function-name]")
|
|
128
|
+
.description("Generate TypeScript (or Python) type definitions from observed runtime types")
|
|
129
|
+
.option("-o, --out <path>", "Write output to a file instead of stdout")
|
|
130
|
+
.option("--env <env>", "Filter by environment")
|
|
131
|
+
.option("--python", "Generate Python type stubs (.pyi) instead of TypeScript")
|
|
132
|
+
.option("--client", "Generate a typed fetch-based API client from observed routes")
|
|
133
|
+
.option("--handlers", "Generate typed Express handler types for route handlers")
|
|
134
|
+
.option("--zod", "Generate Zod validation schemas with inferred types")
|
|
135
|
+
.option("--react-query", "Generate typed TanStack React Query hooks")
|
|
136
|
+
.option("--guards", "Generate runtime type guard functions")
|
|
137
|
+
.option("--middleware", "Generate Express request validation middleware")
|
|
138
|
+
.option("--msw", "Generate Mock Service Worker (MSW) request handlers")
|
|
139
|
+
.option("--json-schema", "Generate JSON Schema definitions from observed types")
|
|
140
|
+
.option("--swr", "Generate typed SWR data-fetching hooks")
|
|
141
|
+
.option("--pydantic", "Generate Pydantic BaseModel classes (Python)")
|
|
142
|
+
.option("--class-validator", "Generate class-validator DTOs for NestJS")
|
|
143
|
+
.option("--graphql", "Generate GraphQL SDL schema from observed routes")
|
|
144
|
+
.option("--trpc", "Generate typed tRPC router from observed routes")
|
|
145
|
+
.option("--axios", "Generate typed Axios client from observed routes")
|
|
146
|
+
.option("--watch", "Watch mode: re-generate when new types are observed")
|
|
147
|
+
.action(async (functionName: string | undefined, opts) => {
|
|
148
|
+
await codegenCommand(functionName, opts);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// trickle diff
|
|
152
|
+
program
|
|
153
|
+
.command("diff")
|
|
154
|
+
.description("Show type drift across all functions — what changed and where")
|
|
155
|
+
.option("--since <timeframe>", "Show changes since (e.g., 1h, 2d, 1w)")
|
|
156
|
+
.option("--env <env>", "Filter by environment")
|
|
157
|
+
.option("--env1 <env>", "First environment for cross-env comparison")
|
|
158
|
+
.option("--env2 <env>", "Second environment for cross-env comparison")
|
|
159
|
+
.action(async (opts) => {
|
|
160
|
+
await diffCommand(opts);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// trickle openapi
|
|
164
|
+
program
|
|
165
|
+
.command("openapi")
|
|
166
|
+
.description("Generate an OpenAPI 3.0 spec from runtime-observed API routes")
|
|
167
|
+
.option("-o, --out <path>", "Write spec to a file (JSON)")
|
|
168
|
+
.option("--env <env>", "Filter by environment")
|
|
169
|
+
.option("--title <title>", "API title in the spec", "API")
|
|
170
|
+
.option("--api-version <version>", "API version in the spec", "1.0.0")
|
|
171
|
+
.option("--server <url>", "Server URL to include in the spec")
|
|
172
|
+
.action(async (opts) => {
|
|
173
|
+
await openapiCommand(opts);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// trickle check
|
|
177
|
+
program
|
|
178
|
+
.command("check")
|
|
179
|
+
.description("Detect breaking API changes by comparing against a saved baseline")
|
|
180
|
+
.option("--save <file>", "Save current types as a baseline snapshot")
|
|
181
|
+
.option("--against <file>", "Check current types against a baseline (exit 1 on breaking changes)")
|
|
182
|
+
.option("--env <env>", "Filter by environment")
|
|
183
|
+
.action(async (opts) => {
|
|
184
|
+
await checkCommand(opts);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// trickle mock
|
|
188
|
+
program
|
|
189
|
+
.command("mock")
|
|
190
|
+
.description("Start a mock API server from runtime-observed routes and sample data")
|
|
191
|
+
.option("-p, --port <port>", "Port to listen on", "3000")
|
|
192
|
+
.option("--no-cors", "Disable CORS headers")
|
|
193
|
+
.action(async (opts) => {
|
|
194
|
+
await mockCommand(opts);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// trickle test --generate
|
|
198
|
+
program
|
|
199
|
+
.command("test")
|
|
200
|
+
.description("Generate API test files from runtime-observed routes and sample data")
|
|
201
|
+
.option("--generate", "Generate test file from observed routes")
|
|
202
|
+
.option("-o, --out <path>", "Write tests to a file")
|
|
203
|
+
.option("--framework <name>", "Test framework: vitest or jest (default: vitest)")
|
|
204
|
+
.option("--base-url <url>", "Base URL for API requests (default: http://localhost:3000)")
|
|
205
|
+
.action(async (opts) => {
|
|
206
|
+
if (!opts.generate) {
|
|
207
|
+
console.log(chalk.gray("\n Usage: trickle test --generate [--out tests.ts] [--framework vitest|jest]\n"));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
await testGenCommand(opts);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// trickle dashboard
|
|
214
|
+
program
|
|
215
|
+
.command("dashboard")
|
|
216
|
+
.description("Open the trickle web dashboard to explore observed types visually")
|
|
217
|
+
.action(async () => {
|
|
218
|
+
await dashboardCommand();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// trickle proxy
|
|
222
|
+
program
|
|
223
|
+
.command("proxy")
|
|
224
|
+
.description("Transparent reverse proxy that captures API types without any backend code changes")
|
|
225
|
+
.requiredOption("-t, --target <url>", "Target server URL to proxy to (e.g. http://localhost:3000)")
|
|
226
|
+
.option("-p, --port <port>", "Port for the proxy server", "4000")
|
|
227
|
+
.action(async (opts) => {
|
|
228
|
+
await proxyCommand(opts);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// trickle export
|
|
232
|
+
program
|
|
233
|
+
.command("export")
|
|
234
|
+
.description("Generate all output formats into a .trickle/ directory at once")
|
|
235
|
+
.option("-d, --dir <path>", "Output directory (default: .trickle)")
|
|
236
|
+
.option("--env <env>", "Filter by environment")
|
|
237
|
+
.action(async (opts) => {
|
|
238
|
+
await exportCommand(opts);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// trickle coverage
|
|
242
|
+
program
|
|
243
|
+
.command("coverage")
|
|
244
|
+
.description("Type observation health report — coverage, staleness, variants, and overall score")
|
|
245
|
+
.option("--env <env>", "Filter by environment")
|
|
246
|
+
.option("--json", "Output raw JSON (for CI integration)")
|
|
247
|
+
.option("--fail-under <score>", "Exit 1 if health score is below this threshold (0-100)")
|
|
248
|
+
.option("--stale-hours <hours>", "Hours before a function is considered stale (default: 24)")
|
|
249
|
+
.action(async (opts) => {
|
|
250
|
+
await coverageCommand(opts);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// trickle replay
|
|
254
|
+
program
|
|
255
|
+
.command("replay")
|
|
256
|
+
.description("Replay captured API requests as regression tests — verify response shapes match")
|
|
257
|
+
.option("-t, --target <url>", "Target server URL (default: http://localhost:3000)")
|
|
258
|
+
.option("--strict", "Compare exact values instead of just shapes")
|
|
259
|
+
.option("--json", "Output JSON results (for CI)")
|
|
260
|
+
.option("--fail-fast", "Stop on first failure")
|
|
261
|
+
.action(async (opts) => {
|
|
262
|
+
await replayCommand(opts);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// trickle docs
|
|
266
|
+
program
|
|
267
|
+
.command("docs")
|
|
268
|
+
.description("Generate API documentation from observed runtime types and sample data")
|
|
269
|
+
.option("-o, --out <path>", "Write docs to a file instead of stdout")
|
|
270
|
+
.option("--html", "Generate self-contained HTML instead of Markdown")
|
|
271
|
+
.option("--env <env>", "Filter by environment")
|
|
272
|
+
.option("--title <title>", "Documentation title", "API Documentation")
|
|
273
|
+
.action(async (opts) => {
|
|
274
|
+
await docsCommand(opts);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// trickle sample [route]
|
|
278
|
+
program
|
|
279
|
+
.command("sample [route]")
|
|
280
|
+
.description("Generate test fixtures and factory functions from observed runtime data")
|
|
281
|
+
.option("-f, --format <format>", "Output format: json, ts, or factory (default: json)")
|
|
282
|
+
.option("-o, --out <path>", "Write fixtures to a file")
|
|
283
|
+
.action(async (route: string | undefined, opts) => {
|
|
284
|
+
await sampleCommand(route, opts);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// trickle audit
|
|
288
|
+
program
|
|
289
|
+
.command("audit")
|
|
290
|
+
.description("Analyze observed API types for quality issues — sensitive data, naming, complexity")
|
|
291
|
+
.option("--env <env>", "Filter by environment")
|
|
292
|
+
.option("--json", "Output raw JSON (for CI integration)")
|
|
293
|
+
.option("--fail-on-error", "Exit 1 if any errors are found")
|
|
294
|
+
.option("--fail-on-warning", "Exit 1 if any errors or warnings are found")
|
|
295
|
+
.action(async (opts) => {
|
|
296
|
+
await auditCommand(opts);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// trickle capture <method> <url>
|
|
300
|
+
program
|
|
301
|
+
.command("capture <method> <url>")
|
|
302
|
+
.description("Capture types from a live API endpoint — no instrumentation needed")
|
|
303
|
+
.option("-H, --header <header...>", "HTTP headers (e.g. -H 'Authorization: Bearer token')")
|
|
304
|
+
.option("-d, --body <body>", "Request body (JSON string)")
|
|
305
|
+
.option("--env <env>", "Environment label (default: development)")
|
|
306
|
+
.option("--module <module>", "Module label (default: capture)")
|
|
307
|
+
.action(async (method: string, url: string, opts) => {
|
|
308
|
+
await captureCommand(method, url, opts);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// trickle search <query>
|
|
312
|
+
program
|
|
313
|
+
.command("search <query>")
|
|
314
|
+
.description("Search across all observed types — find functions by field names, types, or patterns")
|
|
315
|
+
.option("--env <env>", "Filter by environment")
|
|
316
|
+
.option("--json", "Output raw JSON")
|
|
317
|
+
.action(async (query: string, opts) => {
|
|
318
|
+
await searchCommand(query, opts);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// trickle auto
|
|
322
|
+
program
|
|
323
|
+
.command("auto")
|
|
324
|
+
.description("Auto-detect project dependencies and generate only the relevant type files")
|
|
325
|
+
.option("-d, --dir <path>", "Output directory (default: .trickle)")
|
|
326
|
+
.option("--env <env>", "Filter by environment")
|
|
327
|
+
.action(async (opts) => {
|
|
328
|
+
await autoCommand(opts);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// trickle validate <method> <url>
|
|
332
|
+
program
|
|
333
|
+
.command("validate <method> <url>")
|
|
334
|
+
.description("Validate a live API response against previously observed types")
|
|
335
|
+
.option("-H, --header <header...>", "HTTP headers")
|
|
336
|
+
.option("-d, --body <body>", "Request body (JSON string)")
|
|
337
|
+
.option("--env <env>", "Filter by environment")
|
|
338
|
+
.option("--strict", "Treat extra fields as errors (not just warnings)")
|
|
339
|
+
.action(async (method: string, url: string, opts) => {
|
|
340
|
+
await validateCommand(method, url, opts);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// trickle watch
|
|
344
|
+
program
|
|
345
|
+
.command("watch")
|
|
346
|
+
.description("Watch for new type observations and auto-regenerate type files")
|
|
347
|
+
.option("-d, --dir <path>", "Output directory (default: .trickle)")
|
|
348
|
+
.option("--env <env>", "Filter by environment")
|
|
349
|
+
.option("--interval <interval>", "Poll interval (e.g., 3s, 500ms, 1m)", "3s")
|
|
350
|
+
.action(async (opts) => {
|
|
351
|
+
await watchCommand(opts);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
// trickle infer [file]
|
|
355
|
+
program
|
|
356
|
+
.command("infer [file]")
|
|
357
|
+
.description("Infer types from a JSON file or stdin — no live API needed")
|
|
358
|
+
.requiredOption("-n, --name <name>", "Function/route name (e.g., 'GET /api/users')")
|
|
359
|
+
.option("--env <env>", "Environment label (default: development)")
|
|
360
|
+
.option("--module <module>", "Module label (default: infer)")
|
|
361
|
+
.option("--request-body <json>", "Example request body JSON (for documenting input types)")
|
|
362
|
+
.action(async (file: string | undefined, opts) => {
|
|
363
|
+
await inferCommand(file, opts);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
// trickle overview
|
|
367
|
+
program
|
|
368
|
+
.command("overview")
|
|
369
|
+
.description("Compact API overview — all routes with inline type signatures")
|
|
370
|
+
.option("--env <env>", "Filter by environment")
|
|
371
|
+
.option("--json", "Output raw JSON")
|
|
372
|
+
.action(async (opts) => {
|
|
373
|
+
await overviewCommand(opts);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// trickle trace <method> <url>
|
|
377
|
+
program
|
|
378
|
+
.command("trace <method> <url>")
|
|
379
|
+
.description("Make an HTTP request and show the response with inline type annotations")
|
|
380
|
+
.option("-H, --header <header...>", "HTTP headers")
|
|
381
|
+
.option("-d, --body <body>", "Request body (JSON string)")
|
|
382
|
+
.option("--save", "Save inferred types to the backend")
|
|
383
|
+
.option("--env <env>", "Environment label (default: development)")
|
|
384
|
+
.option("--module <module>", "Module label (default: trace)")
|
|
385
|
+
.action(async (method: string, url: string, opts) => {
|
|
386
|
+
await traceCommand(method, url, opts);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// trickle pack
|
|
390
|
+
program
|
|
391
|
+
.command("pack")
|
|
392
|
+
.description("Export all observed types as a portable bundle")
|
|
393
|
+
.option("-o, --out <file>", "Write bundle to a file (otherwise stdout)")
|
|
394
|
+
.option("--env <env>", "Filter by environment")
|
|
395
|
+
.action(async (opts) => {
|
|
396
|
+
await packCommand(opts);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// trickle unpack <file>
|
|
400
|
+
program
|
|
401
|
+
.command("unpack <file>")
|
|
402
|
+
.description("Import types from a packed bundle into the backend")
|
|
403
|
+
.option("--env <env>", "Override environment for all imported types")
|
|
404
|
+
.option("--dry-run", "List contents without importing")
|
|
405
|
+
.action(async (file: string, opts) => {
|
|
406
|
+
await unpackCommand(file, opts);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// trickle stubs <dir>
|
|
410
|
+
program
|
|
411
|
+
.command("stubs <dir>")
|
|
412
|
+
.description("Generate .d.ts and .pyi sidecar type stubs next to source files — IDEs pick them up automatically")
|
|
413
|
+
.option("--env <env>", "Filter by environment")
|
|
414
|
+
.option("--dry-run", "Preview which files would be created without writing them")
|
|
415
|
+
.action(async (dir: string, opts) => {
|
|
416
|
+
await stubsCommand(dir, opts);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// trickle annotate <file>
|
|
420
|
+
program
|
|
421
|
+
.command("annotate <file>")
|
|
422
|
+
.description("Add runtime-observed type annotations directly into source files")
|
|
423
|
+
.option("--env <env>", "Filter by environment")
|
|
424
|
+
.option("--dry-run", "Preview changes without modifying the file")
|
|
425
|
+
.option("--jsdoc", "Force JSDoc comments (default for .js files)")
|
|
426
|
+
.action(async (file: string, opts) => {
|
|
427
|
+
await annotateCommand(file, opts);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// Handle unhandled rejections
|
|
431
|
+
process.on("unhandledRejection", (err) => {
|
|
432
|
+
if (err instanceof Error) {
|
|
433
|
+
console.error(chalk.red(`\n Error: ${err.message}\n`));
|
|
434
|
+
} else {
|
|
435
|
+
console.error(chalk.red("\n An unexpected error occurred.\n"));
|
|
436
|
+
}
|
|
437
|
+
process.exit(1);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// ── Direct file execution shorthand ──
|
|
441
|
+
// `trickle app.js` → `trickle run app.js`
|
|
442
|
+
// `trickle script.py --watch` → `trickle run script.py --watch`
|
|
443
|
+
const CODE_EXTENSIONS = /\.(js|ts|tsx|jsx|mjs|cjs|mts|py)$/i;
|
|
444
|
+
const firstArg = process.argv[2];
|
|
445
|
+
if (
|
|
446
|
+
firstArg &&
|
|
447
|
+
!firstArg.startsWith("-") &&
|
|
448
|
+
CODE_EXTENSIONS.test(firstArg)
|
|
449
|
+
) {
|
|
450
|
+
// Inject "run" before the file argument
|
|
451
|
+
process.argv.splice(2, 0, "run");
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
program.parse();
|