trickle-cli 0.1.0 → 0.1.2

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.
@@ -309,7 +309,10 @@ async function executeSingleRun(instrumentedCommand, env, opts, singleFile, loca
309
309
  }
310
310
  // Start live type generation for backend mode
311
311
  let liveStop = null;
312
- if (singleFile && !opts.stubs) {
312
+ if (opts.stubs) {
313
+ liveStop = startLiveStubsGeneration(opts.stubs);
314
+ }
315
+ else if (singleFile) {
313
316
  liveStop = startLiveBackendTypes(singleFile);
314
317
  }
315
318
  // Run the instrumented command
@@ -499,6 +502,43 @@ function startLiveBackendTypes(sourceFile) {
499
502
  clearInterval(interval);
500
503
  };
501
504
  }
505
+ // ── Live stubs generation during run ──
506
+ function startLiveStubsGeneration(stubsDir) {
507
+ let lastTotal = 0;
508
+ let stopped = false;
509
+ const poll = async () => {
510
+ if (stopped)
511
+ return;
512
+ try {
513
+ const { stubsCommand } = await Promise.resolve().then(() => __importStar(require("./stubs")));
514
+ const result = await stubsCommand(stubsDir, { silent: true });
515
+ // Count .d.ts files in the stubs dir to track progress
516
+ const files = fs.readdirSync(stubsDir).filter(f => f.endsWith('.d.ts'));
517
+ let funcCount = 0;
518
+ for (const f of files) {
519
+ const content = fs.readFileSync(path.join(stubsDir, f), 'utf-8');
520
+ funcCount += (content.match(/export declare function/g) || []).length;
521
+ }
522
+ if (funcCount > lastTotal) {
523
+ const newCount = funcCount - lastTotal;
524
+ const ts = new Date().toLocaleTimeString("en-US", { hour12: false });
525
+ console.log(chalk_1.default.gray(` [${ts}]`) +
526
+ chalk_1.default.green(` +${newCount} type(s)`) +
527
+ chalk_1.default.gray(` → ${stubsDir}`) +
528
+ chalk_1.default.gray(` (${funcCount} total)`));
529
+ lastTotal = funcCount;
530
+ }
531
+ }
532
+ catch {
533
+ // Never crash — background helper
534
+ }
535
+ };
536
+ const interval = setInterval(poll, 3000);
537
+ return () => {
538
+ stopped = true;
539
+ clearInterval(interval);
540
+ };
541
+ }
502
542
  // ── Auto-generate sidecar type file ──
503
543
  async function autoGenerateSidecar(filePath) {
504
544
  try {
package/dist/index.js CHANGED
@@ -65,7 +65,7 @@ program
65
65
  });
66
66
  // trickle run <command>
67
67
  program
68
- .command("run [command]")
68
+ .command("run [command...]")
69
69
  .description("Run any command or file with universal type observation — zero code changes needed")
70
70
  .option("--module <name>", "Module name for captured functions")
71
71
  .option("--include <patterns>", "Comma-separated substrings — only observe matching modules")
@@ -73,7 +73,9 @@ program
73
73
  .option("--stubs <dir>", "Auto-generate .d.ts/.pyi type stubs in this directory after the run")
74
74
  .option("--annotate <path>", "Auto-annotate this file or directory with types after the run")
75
75
  .option("-w, --watch", "Watch source files and re-run on changes")
76
- .action(async (command, opts) => {
76
+ .allowUnknownOption()
77
+ .action(async (commandParts, opts) => {
78
+ const command = commandParts.length > 0 ? commandParts.join(" ") : undefined;
77
79
  await (0, run_1.runCommand)(command, opts);
78
80
  });
79
81
  // trickle functions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trickle-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "CLI for trickle runtime type observability",
5
5
  "bin": {
6
6
  "trickle": "dist/index.js"
@@ -350,7 +350,9 @@ async function executeSingleRun(
350
350
 
351
351
  // Start live type generation for backend mode
352
352
  let liveStop: (() => void) | null = null;
353
- if (singleFile && !opts.stubs) {
353
+ if (opts.stubs) {
354
+ liveStop = startLiveStubsGeneration(opts.stubs);
355
+ } else if (singleFile) {
354
356
  liveStop = startLiveBackendTypes(singleFile);
355
357
  }
356
358
 
@@ -573,6 +575,49 @@ function startLiveBackendTypes(sourceFile: string): () => void {
573
575
  };
574
576
  }
575
577
 
578
+ // ── Live stubs generation during run ──
579
+
580
+ function startLiveStubsGeneration(stubsDir: string): () => void {
581
+ let lastTotal = 0;
582
+ let stopped = false;
583
+
584
+ const poll = async () => {
585
+ if (stopped) return;
586
+ try {
587
+ const { stubsCommand } = await import("./stubs");
588
+ const result = await stubsCommand(stubsDir, { silent: true });
589
+
590
+ // Count .d.ts files in the stubs dir to track progress
591
+ const files = fs.readdirSync(stubsDir).filter(f => f.endsWith('.d.ts'));
592
+ let funcCount = 0;
593
+ for (const f of files) {
594
+ const content = fs.readFileSync(path.join(stubsDir, f), 'utf-8');
595
+ funcCount += (content.match(/export declare function/g) || []).length;
596
+ }
597
+
598
+ if (funcCount > lastTotal) {
599
+ const newCount = funcCount - lastTotal;
600
+ const ts = new Date().toLocaleTimeString("en-US", { hour12: false });
601
+ console.log(
602
+ chalk.gray(` [${ts}]`) +
603
+ chalk.green(` +${newCount} type(s)`) +
604
+ chalk.gray(` → ${stubsDir}`) +
605
+ chalk.gray(` (${funcCount} total)`),
606
+ );
607
+ lastTotal = funcCount;
608
+ }
609
+ } catch {
610
+ // Never crash — background helper
611
+ }
612
+ };
613
+
614
+ const interval = setInterval(poll, 3000);
615
+ return () => {
616
+ stopped = true;
617
+ clearInterval(interval);
618
+ };
619
+ }
620
+
576
621
  // ── Auto-generate sidecar type file ──
577
622
 
578
623
  async function autoGenerateSidecar(filePath: string): Promise<void> {
package/src/index.ts CHANGED
@@ -66,7 +66,7 @@ program
66
66
 
67
67
  // trickle run <command>
68
68
  program
69
- .command("run [command]")
69
+ .command("run [command...]")
70
70
  .description("Run any command or file with universal type observation — zero code changes needed")
71
71
  .option("--module <name>", "Module name for captured functions")
72
72
  .option("--include <patterns>", "Comma-separated substrings — only observe matching modules")
@@ -74,7 +74,9 @@ program
74
74
  .option("--stubs <dir>", "Auto-generate .d.ts/.pyi type stubs in this directory after the run")
75
75
  .option("--annotate <path>", "Auto-annotate this file or directory with types after the run")
76
76
  .option("-w, --watch", "Watch source files and re-run on changes")
77
- .action(async (command: string | undefined, opts) => {
77
+ .allowUnknownOption()
78
+ .action(async (commandParts: string[], opts) => {
79
+ const command = commandParts.length > 0 ? commandParts.join(" ") : undefined;
78
80
  await runCommand(command, opts);
79
81
  });
80
82