@couch-kit/cli 0.3.10 → 0.3.11

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 (3) hide show
  1. package/README.md +3 -3
  2. package/dist/index.js +57 -67
  3. package/package.json +3 -2
package/README.md CHANGED
@@ -47,11 +47,11 @@ android/app/src/main/assets/www/
47
47
  Spawns headless WebSocket bots to simulate players (useful for load testing and quick iteration).
48
48
 
49
49
  ```bash
50
- # Default: 4 bots, ws://localhost:8082
50
+ # Default: 4 bots, ws://localhost:8082/ws
51
51
  bunx couch-kit simulate
52
52
 
53
- # Custom host + count
54
- bunx couch-kit simulate --url ws://192.168.1.99:8082 --count 8
53
+ # Custom host + count (the host serves WebSockets on the /ws path)
54
+ bunx couch-kit simulate --url ws://192.168.1.99:8082/ws --count 8
55
55
 
56
56
  # Action interval (ms)
57
57
  bunx couch-kit simulate --interval 250
package/dist/index.js CHANGED
@@ -1,19 +1,15 @@
1
1
  #!/usr/bin/env node
2
- var __defProp = Object.defineProperty;
3
- var __returnValue = (v) => v;
4
- function __exportSetter(name, newValue) {
5
- this[name] = __returnValue.bind(null, newValue);
6
- }
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, {
10
- get: all[name],
11
- enumerable: true,
12
- configurable: true,
13
- set: __exportSetter.bind(all, name)
14
- });
2
+ var __esm = (fn, res, err) => () => {
3
+ if (fn)
4
+ try {
5
+ res = fn(fn = 0);
6
+ } catch (e) {
7
+ err = [e];
8
+ }
9
+ if (err)
10
+ throw err[0];
11
+ return res;
15
12
  };
16
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
13
 
18
14
  // ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/error.js
19
15
  var CommanderError, InvalidArgumentError;
@@ -129,7 +125,7 @@ class Help {
129
125
  this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80;
130
126
  }
131
127
  visibleCommands(cmd) {
132
- const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden);
128
+ const visibleCommands = cmd.commands.filter((cmd) => !cmd._hidden);
133
129
  const helpCommand = cmd._getHelpCommand();
134
130
  if (helpCommand && !helpCommand._hidden) {
135
131
  visibleCommands.push(helpCommand);
@@ -602,8 +598,8 @@ class DualOptions {
602
598
  }
603
599
  }
604
600
  function camelcase(str) {
605
- return str.split("-").reduce((str2, word) => {
606
- return str2 + word[0].toUpperCase() + word.slice(1);
601
+ return str.split("-").reduce((str, word) => {
602
+ return str + word[0].toUpperCase() + word.slice(1);
607
603
  });
608
604
  }
609
605
  function splitOptionFlags(flags) {
@@ -1767,18 +1763,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
1767
1763
  this.error(message, { code: "commander.missingMandatoryOptionValue" });
1768
1764
  }
1769
1765
  _conflictingOption(option, conflictingOption) {
1770
- const findBestOptionFromValue = (option2) => {
1771
- const optionKey = option2.attributeName();
1766
+ const findBestOptionFromValue = (option) => {
1767
+ const optionKey = option.attributeName();
1772
1768
  const optionValue = this.getOptionValue(optionKey);
1773
1769
  const negativeOption = this.options.find((target) => target.negate && optionKey === target.attributeName());
1774
1770
  const positiveOption = this.options.find((target) => !target.negate && optionKey === target.attributeName());
1775
1771
  if (negativeOption && (negativeOption.presetArg === undefined && optionValue === false || negativeOption.presetArg !== undefined && optionValue === negativeOption.presetArg)) {
1776
1772
  return negativeOption;
1777
1773
  }
1778
- return positiveOption || option2;
1774
+ return positiveOption || option;
1779
1775
  };
1780
- const getErrorMessage = (option2) => {
1781
- const bestOption = findBestOptionFromValue(option2);
1776
+ const getErrorMessage = (option) => {
1777
+ const bestOption = findBestOptionFromValue(option);
1782
1778
  const optionKey = bestOption.attributeName();
1783
1779
  const source = this.getOptionValueSource(optionKey);
1784
1780
  if (source === "env") {
@@ -2116,7 +2112,7 @@ function generateId() {
2116
2112
  if (typeof globalThis.crypto !== "undefined" && typeof globalThis.crypto.getRandomValues === "function") {
2117
2113
  const bytes = new Uint8Array(16);
2118
2114
  globalThis.crypto.getRandomValues(bytes);
2119
- return Array.from(bytes).map((b2) => b2.toString(16).padStart(2, "0")).join("");
2115
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
2120
2116
  }
2121
2117
  const a = Math.random().toString(36).substring(2, 15);
2122
2118
  const b = Math.random().toString(36).substring(2, 10);
@@ -2165,11 +2161,14 @@ var init_src = __esm(() => {
2165
2161
  init_middleware();
2166
2162
  });
2167
2163
 
2168
- // src/commands/bundle.ts
2169
- var exports_bundle = {};
2170
- __export(exports_bundle, {
2171
- bundleCommand: () => bundleCommand
2164
+ // src/defaults.ts
2165
+ var DEFAULT_SIMULATE_URL;
2166
+ var init_defaults = __esm(() => {
2167
+ init_src();
2168
+ DEFAULT_SIMULATE_URL = `ws://localhost:${DEFAULT_HTTP_PORT + DEFAULT_WS_PORT_OFFSET}${DEFAULT_WS_PATH}`;
2172
2169
  });
2170
+
2171
+ // src/commands/bundle.ts
2173
2172
  import fs2 from "node:fs";
2174
2173
  import path2 from "node:path";
2175
2174
  import { execSync } from "node:child_process";
@@ -2250,15 +2249,12 @@ var init_bundle = __esm(() => {
2250
2249
  });
2251
2250
 
2252
2251
  // src/commands/simulate.ts
2253
- var exports_simulate = {};
2254
- __export(exports_simulate, {
2255
- simulateCommand: () => simulateCommand
2256
- });
2257
2252
  var simulateCommand;
2258
2253
  var init_simulate = __esm(() => {
2259
2254
  init_commander();
2260
2255
  init_src();
2261
- simulateCommand = new Command("simulate").description("Spawns headless bots to simulate players").option("-n, --count <number>", "Number of bots", "4").option("-u, --url <url>", "WebSocket URL of host", `ws://localhost:${DEFAULT_HTTP_PORT + DEFAULT_WS_PORT_OFFSET}${DEFAULT_WS_PATH}`).option("-i, --interval <ms>", "Action interval in ms", "1000").action(async (options) => {
2256
+ init_defaults();
2257
+ simulateCommand = new Command("simulate").description("Spawns headless bots to simulate players").option("-n, --count <number>", "Number of bots", "4").option("-u, --url <url>", "WebSocket URL of host", DEFAULT_SIMULATE_URL).option("-i, --interval <ms>", "Action interval in ms", "1000").action(async (options) => {
2262
2258
  const count = parseInt(options.count);
2263
2259
  const url = options.url;
2264
2260
  const interval = parseInt(options.interval);
@@ -2315,10 +2311,6 @@ Stopping bots...`);
2315
2311
  });
2316
2312
 
2317
2313
  // src/commands/init.ts
2318
- var exports_init = {};
2319
- __export(exports_init, {
2320
- initCommand: () => initCommand
2321
- });
2322
2314
  import fs3 from "node:fs";
2323
2315
  import path3 from "node:path";
2324
2316
  function detectPackageManager2() {
@@ -2358,14 +2350,15 @@ var init_init = __esm(() => {
2358
2350
  dependencies: {
2359
2351
  react: "^19.0.0",
2360
2352
  "react-dom": "^19.0.0",
2361
- "@couch-kit/client": "^0.8.0"
2353
+ "@couch-kit/client": "latest",
2354
+ "@couch-kit/core": "latest"
2362
2355
  },
2363
2356
  devDependencies: {
2364
2357
  "@types/react": "^19.0.0",
2365
2358
  "@types/react-dom": "^19.0.0",
2366
2359
  "@vitejs/plugin-react": "^6.0.0",
2367
2360
  typescript: "^5.7.0",
2368
- vite: "^6.0.0"
2361
+ vite: "^8.0.0"
2369
2362
  }
2370
2363
  };
2371
2364
  fs3.writeFileSync(path3.join(targetDir, "package.json"), JSON.stringify(packageJson, null, 2) + `
@@ -2526,11 +2519,10 @@ Next steps:
2526
2519
  });
2527
2520
 
2528
2521
  // src/commands/replay.ts
2529
- var exports_replay = {};
2530
- __export(exports_replay, {
2531
- replay: () => replay2
2532
- });
2522
+ import { existsSync } from "node:fs";
2523
+ import { readFile } from "node:fs/promises";
2533
2524
  import { resolve } from "node:path";
2525
+ import { pathToFileURL } from "node:url";
2534
2526
  var replay2;
2535
2527
  var init_replay = __esm(() => {
2536
2528
  init_commander();
@@ -2538,25 +2530,23 @@ var init_replay = __esm(() => {
2538
2530
  replay2 = new Command("replay").description("Replay a recorded game session against a reducer").argument("<recording>", "Path to recording JSON file").argument("<reducer>", "Path to reducer module (must export default or named 'reducer')").option("--snapshots", "Output intermediate state snapshots", false).option("--json", "Output as formatted JSON", false).action(async (recordingPath, reducerPath, options) => {
2539
2531
  try {
2540
2532
  const resolvedRecordingPath = resolve(recordingPath);
2541
- const recordingFile = Bun.file(resolvedRecordingPath);
2542
- const exists = await recordingFile.exists();
2543
- if (!exists) {
2533
+ if (!existsSync(resolvedRecordingPath)) {
2544
2534
  console.error(`Error: Recording file not found: ${recordingPath}`);
2545
2535
  process.exit(1);
2546
2536
  }
2547
- const recording = await recordingFile.json();
2537
+ const recording = JSON.parse(await readFile(resolvedRecordingPath, "utf-8"));
2548
2538
  if (!recording.initialState || !Array.isArray(recording.actions)) {
2549
2539
  console.error("Error: Invalid recording format. Expected { initialState, actions[] }");
2550
2540
  process.exit(1);
2551
2541
  }
2552
2542
  const resolvedReducerPath = resolve(reducerPath);
2553
- const reducerModule = await import(resolvedReducerPath);
2554
- const reducer2 = reducerModule.default ?? reducerModule.reducer;
2555
- if (typeof reducer2 !== "function") {
2543
+ const reducerModule = await import(pathToFileURL(resolvedReducerPath).href);
2544
+ const reducer = reducerModule.default ?? reducerModule.reducer;
2545
+ if (typeof reducer !== "function") {
2556
2546
  console.error("Error: Reducer module must export a default function or named 'reducer' export");
2557
2547
  process.exit(1);
2558
2548
  }
2559
- const result = replayActions(recording, reducer2);
2549
+ const result = replayActions(recording, reducer);
2560
2550
  if (options.json) {
2561
2551
  const output = options.snapshots ? result : {
2562
2552
  finalState: result.finalState,
@@ -2587,10 +2577,6 @@ Snapshots (${result.snapshots.length}):`);
2587
2577
  });
2588
2578
 
2589
2579
  // src/commands/dev.ts
2590
- var exports_dev = {};
2591
- __export(exports_dev, {
2592
- dev: () => dev
2593
- });
2594
2580
  import { resolve as resolve2 } from "node:path";
2595
2581
  import { networkInterfaces } from "node:os";
2596
2582
  function getLanIp() {
@@ -2654,36 +2640,37 @@ var init_dev = __esm(() => {
2654
2640
 
2655
2641
  // src/index.ts
2656
2642
  init_commander();
2643
+ init_defaults();
2657
2644
  import { createRequire } from "node:module";
2658
2645
  var require2 = createRequire(import.meta.url);
2659
2646
  var { version } = require2("../package.json");
2660
2647
  var program2 = new Command;
2661
2648
  program2.name("couch-kit").description("CLI for Couch Kit").version(version);
2662
2649
  program2.command("bundle").description("Bundles the web controller into the Android assets directory").option("-s, --source <path>", "Source directory of web controller", "./web-controller").option("-o, --output <path>", "Android assets directory", "./android/app/src/main/assets/www").option("--no-build", "Skip build step (just copy)").option("-m, --manifest <path>", "Also write manifest to this path for import in app source").action(async (_options, command) => {
2663
- const { bundleCommand: bundleCommand2 } = await Promise.resolve().then(() => (init_bundle(), exports_bundle));
2664
- await bundleCommand2.parseAsync(reconstructArgs(command), {
2650
+ await Promise.resolve().then(() => init_bundle());
2651
+ await bundleCommand.parseAsync(reconstructArgs(command), {
2665
2652
  from: "user"
2666
2653
  });
2667
2654
  });
2668
- program2.command("simulate").description("Spawns headless bots to simulate players").option("-n, --count <number>", "Number of bots", "4").option("-u, --url <url>", "WebSocket URL of host", "ws://localhost:8082").option("-i, --interval <ms>", "Action interval in ms", "1000").action(async (_options, command) => {
2669
- const { simulateCommand: simulateCommand2 } = await Promise.resolve().then(() => (init_simulate(), exports_simulate));
2670
- await simulateCommand2.parseAsync(reconstructArgs(command), {
2655
+ program2.command("simulate").description("Spawns headless bots to simulate players").option("-n, --count <number>", "Number of bots", "4").option("-u, --url <url>", "WebSocket URL of host", DEFAULT_SIMULATE_URL).option("-i, --interval <ms>", "Action interval in ms", "1000").action(async (_options, command) => {
2656
+ await Promise.resolve().then(() => init_simulate());
2657
+ await simulateCommand.parseAsync(reconstructArgs(command), {
2671
2658
  from: "user"
2672
2659
  });
2673
2660
  });
2674
2661
  program2.command("init").description("Scaffolds a new web controller project").argument("[name]", "Project name", "web-controller").action(async (name) => {
2675
- const { initCommand: initCommand2 } = await Promise.resolve().then(() => (init_init(), exports_init));
2676
- await initCommand2.parseAsync([name], { from: "user" });
2662
+ await Promise.resolve().then(() => init_init());
2663
+ await initCommand.parseAsync([name], { from: "user" });
2677
2664
  });
2678
- program2.command("replay").description("Replay a recorded game session against a reducer").argument("<recording>", "Path to recording JSON file").argument("<reducer>", "Path to reducer module").option("--snapshots", "Output intermediate state snapshots").option("--json", "Output as formatted JSON").action(async (recording, reducer2, _options, command) => {
2679
- const { replay: replay3 } = await Promise.resolve().then(() => (init_replay(), exports_replay));
2680
- await replay3.parseAsync([recording, reducer2, ...reconstructArgs(command)], {
2665
+ program2.command("replay").description("Replay a recorded game session against a reducer").argument("<recording>", "Path to recording JSON file").argument("<reducer>", "Path to reducer module").option("--snapshots", "Output intermediate state snapshots").option("--json", "Output as formatted JSON").action(async (recording, reducer, _options, command) => {
2666
+ await Promise.resolve().then(() => init_replay());
2667
+ await replay2.parseAsync([recording, reducer, ...reconstructArgs(command)], {
2681
2668
  from: "user"
2682
2669
  });
2683
2670
  });
2684
2671
  program2.command("dev").description("Start development server with LAN access").option("-p, --port <port>", "Port number", "5173").option("--host", "Expose to LAN").option("--open", "Open browser automatically").action(async (_options, command) => {
2685
- const { dev: dev2 } = await Promise.resolve().then(() => (init_dev(), exports_dev));
2686
- await dev2.parseAsync(reconstructArgs(command), {
2672
+ await Promise.resolve().then(() => init_dev());
2673
+ await dev.parseAsync(reconstructArgs(command), {
2687
2674
  from: "user"
2688
2675
  });
2689
2676
  });
@@ -2691,9 +2678,12 @@ function reconstructArgs(command) {
2691
2678
  const args = [];
2692
2679
  const opts = command.opts();
2693
2680
  for (const option of command.options) {
2694
- const value = opts[option.attributeName()];
2681
+ const name = option.attributeName();
2682
+ const value = opts[name];
2695
2683
  if (value === undefined)
2696
2684
  continue;
2685
+ if (command.getOptionValueSource(name) === "default")
2686
+ continue;
2697
2687
  if (option.negate) {
2698
2688
  if (value === false)
2699
2689
  args.push(option.long ?? option.short ?? "");
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@couch-kit/cli",
3
- "version": "0.3.10",
3
+ "version": "0.3.11",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "provenance": true
7
7
  },
8
8
  "description": "CLI tools for Couch Kit party games — bundle web controllers, simulate clients, and scaffold projects",
9
9
  "license": "MIT",
10
+ "type": "module",
10
11
  "engines": {
11
- "node": ">=18.0.0"
12
+ "node": ">=22.0.0"
12
13
  },
13
14
  "repository": {
14
15
  "type": "git",