@walkeros/cli 1.0.0 → 1.0.1

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.
@@ -0,0 +1,247 @@
1
+ # flow-complete.json - Comprehensive walkerOS Flow Example
2
+
3
+ This example demonstrates **ALL JSON-compatible walkerOS features** with
4
+ real-world patterns. It contains two named flows (`web` and `server`) showing a
5
+ complete event tracking architecture.
6
+
7
+ ## Architecture
8
+
9
+ ```
10
+ ┌─────────────────────────────────────────────────────────────────────────────┐
11
+ │ WEB FLOW │
12
+ │ │
13
+ │ Browser Source ─┐ │
14
+ │ DataLayer Source ──▶ [Validator] ──▶ Collector ──▶ GA4 Destination │
15
+ │ Demo Source ────┘ └──▶ API Destination │
16
+ │ │ │
17
+ └──────────────────────────────────────────────────────────────│──────────────┘
18
+
19
+ ┌─────────────────────────────────────────────────────────────────────────────┐
20
+ │ SERVER FLOW │
21
+ │ │
22
+ │ HTTP Request ──▶ Express Source ──▶ Collector ──▶ [Fingerprint] ──────┐ │
23
+ │ │ [Validator] │ │
24
+ │ │ ▼ │
25
+ │ └── ingest: IP, user-agent ────────▶ Meta Destination
26
+ │ language, referer Demo Destination│
27
+ └─────────────────────────────────────────────────────────────────────────────┘
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ ### Run Web Flow
33
+
34
+ ```bash
35
+ cd walkerOS
36
+ npx walkeros serve packages/cli/examples/flow-complete.json --flow web
37
+ # Open http://localhost:3000 - demo events fire automatically
38
+ ```
39
+
40
+ ### Run Server Flow
41
+
42
+ ```bash
43
+ cd walkerOS
44
+ npx walkeros run packages/cli/examples/flow-complete.json --flow server
45
+
46
+ # Test health
47
+ curl http://localhost:8080/health
48
+
49
+ # Send test event
50
+ curl -X POST http://localhost:8080/collect \
51
+ -H "Content-Type: application/json" \
52
+ -d '{
53
+ "name": "order complete",
54
+ "data": {"id": "ORD-999", "total": 99.99, "currency": "EUR"},
55
+ "user": {"email": "test@example.com", "id": "U-123"},
56
+ "nested": [{"entity": "product", "data": {"id": "P1", "name": "Item", "price": 99.99, "quantity": 1}}]
57
+ }'
58
+ ```
59
+
60
+ ### Run Both (Full Pipeline)
61
+
62
+ ```bash
63
+ # Terminal 1: Start server
64
+ npx walkeros run packages/cli/examples/flow-complete.json --flow server
65
+
66
+ # Terminal 2: Start web (sends to server via API destination)
67
+ npx walkeros serve packages/cli/examples/flow-complete.json --flow web
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Feature Inventory
73
+
74
+ ### Features Used (51)
75
+
76
+ #### Mapping - Value Extraction
77
+
78
+ | Feature | Location | Example |
79
+ | ----------------- | ----------------- | ------------------------------------------------------------ |
80
+ | Key extraction | GA4 page_view | `"page_title": "data.title"` |
81
+ | Static value | Meta ViewContent | `"content_type": { "value": "product" }` |
82
+ | Key with fallback | GA4 add_to_cart | `{ "key": "data.currency", "value": "$variables.currency" }` |
83
+ | Nested key (deep) | dataLayer mapping | `"items.0.item_id"` |
84
+
85
+ #### Mapping - Structure
86
+
87
+ | Feature | Location | Example |
88
+ | --------------------- | ------------------ | ----------------------------------------------------------- |
89
+ | Map (object) | GA4 purchase | `"data": { "map": { ... } }` |
90
+ | Loop with "nested" | GA4 purchase items | `{ "loop": ["nested", { "map": {...} }] }` |
91
+ | Loop with "this" | GA4 add_to_cart | `{ "loop": ["this", { "map": {...} }] }` |
92
+ | Set (single value) | Meta ViewContent | `"content_ids": { "set": ["data.id"] }` |
93
+ | Set (multiple values) | Meta settings | `"external_id": { "set": ["user.device", "user.session"] }` |
94
+ | Direct passthrough | Meta PageView | `"data": "data"` |
95
+
96
+ #### Mapping - Control
97
+
98
+ | Feature | Location | Example |
99
+ | -------------------- | ------------------- | ----------------------------------------------------------- |
100
+ | Consent-gated field | API destination | `{ "key": "user.email", "consent": { "marketing": true } }` |
101
+ | Ignore rule | GA4/API test events | `{ "ignore": true }` |
102
+ | Wildcard action (\*) | GA4 test, Meta | `"test": { "*": { "ignore": true } }` |
103
+ | Wildcard entity (\*) | Meta click handler | `"*": { "click": { "name": "CustomEvent" } }` |
104
+
105
+ #### Definitions & Variables
106
+
107
+ | Feature | Location | Example |
108
+ | -------------------- | ------------------ | -------------------------------------------- |
109
+ | Root-level variables | Root | `"currency": "EUR"` |
110
+ | Flow-level variables | server.variables | `"metaPixelId": "${META_PIXEL_ID:...}"` |
111
+ | Environment variable | Variables | `"${GA4_MEASUREMENT_ID:G-DEMO123456}"` |
112
+ | Env with default | Variables | `"${API_URL:http://localhost:8080/collect}"` |
113
+ | $variables reference | GA4 settings | `"$variables.ga4MeasurementId"` |
114
+ | Definition (complex) | Root definitions | `"ga4ItemsLoop": { "loop": [...] }` |
115
+ | $ref reference | GA4 purchase items | `{ "$ref": "#/definitions/ga4ItemsLoop" }` |
116
+
117
+ #### Sources
118
+
119
+ | Feature | Location | Example |
120
+ | -------------------- | --------- | ------------------------------------- |
121
+ | Primary source | browser | `"primary": true` |
122
+ | Multiple sources | web flow | browser + dataLayer + demo |
123
+ | Source-level mapping | dataLayer | `"mapping": { "add_to_cart": {...} }` |
124
+ | Pre-collector chain | dataLayer | `"next": "dataLayerValidator"` |
125
+ | Demo source events | demo | Pre-configured test events |
126
+
127
+ #### Transformers
128
+
129
+ | Feature | Location | Example |
130
+ | ----------------------- | ------------------ | ---------------------------------- |
131
+ | Validator transformer | dataLayerValidator | JSON Schema validation |
132
+ | Fingerprint transformer | server | Hash context fields to `user.hash` |
133
+ | Transformer chaining | server | `"next": "serverValidator"` |
134
+ | Post-collector chain | Meta | `"before": "fingerprint"` |
135
+ | Contract validation | serverValidator | Entity/action schemas |
136
+ | Format option | serverValidator | `"format": true` |
137
+
138
+ #### Destinations
139
+
140
+ | Feature | Location | Example |
141
+ | --------------------- | ---------------- | ---------------------------------- |
142
+ | Destination consent | GA4 | `"consent": { "marketing": true }` |
143
+ | Destination mapping | All destinations | Entity/action to vendor events |
144
+ | Multiple destinations | Both flows | GA4 + API, Meta + Demo |
145
+ | Batch option | API | `"batch": 5` |
146
+
147
+ #### Collector
148
+
149
+ | Feature | Location | Example |
150
+ | ----------------- | --------------- | --------------------------------------- |
151
+ | Tagging | Both collectors | `"tagging": 1` |
152
+ | Consent defaults | Both collectors | `"consent": { "functional": true }` |
153
+ | Globals | Both collectors | `"environment": "demo"` |
154
+ | Custom properties | web collector | `"custom": { "campaign": "flow-demo" }` |
155
+ | User defaults | web collector | `"user": { "id": "anonymous" }` |
156
+
157
+ #### Server-Specific
158
+
159
+ | Feature | Location | Example |
160
+ | -------------------- | ----------- | ----------------------------------------------- |
161
+ | Ingest metadata | http source | `"context.ip": "ip"` |
162
+ | Language header | ingest | `"context.language": "headers.accept-language"` |
163
+ | Policy | Meta | Pre-processing field transformation |
164
+ | Policy consent-gated | Meta | `"user_data.em"` with consent |
165
+ | Policy nested map | Meta | `"custom_data.request_meta": { "map": {...} }` |
166
+
167
+ #### Browser Source
168
+
169
+ | Feature | Location | Example |
170
+ | --------------- | -------- | ---------------------------------- |
171
+ | Prefix | browser | `"prefix": "data-elb"` |
172
+ | Auto pageview | browser | `"pageview": true` |
173
+ | Session consent | browser | `"session": { "consent": {...} }` |
174
+ | ELB binding | browser | `"elb": "elb"`, `"elbLayer": true` |
175
+
176
+ ---
177
+
178
+ ### Features NOT Used (15)
179
+
180
+ #### Requires JavaScript (7)
181
+
182
+ These features cannot be used in pure JSON configurations:
183
+
184
+ | Feature | Reason |
185
+ | --------------------------- | ----------------------------- |
186
+ | `fn:` function | Requires JavaScript callback |
187
+ | `condition:` | Requires JavaScript predicate |
188
+ | Conditional mapping (array) | Requires condition functions |
189
+ | Custom transformer code | Requires JavaScript |
190
+ | Custom source code | Requires JavaScript |
191
+ | Custom destination code | Requires JavaScript |
192
+ | Event handler callbacks | Requires JavaScript |
193
+
194
+ #### Omitted for Clarity (8)
195
+
196
+ These features could be added but were omitted to keep the example focused:
197
+
198
+ | Feature | Why Omitted |
199
+ | ------------------------- | ----------------------------- |
200
+ | Multiple named flows (3+) | Two flows sufficient for demo |
201
+ | Queue config | Advanced batching scenario |
202
+ | Retry config | Advanced error handling |
203
+ | Custom fetch options | API destination advanced |
204
+ | Dynamic routing | Requires condition logic |
205
+ | Transform before send | Covered by policy |
206
+ | Custom headers in API | Would add complexity |
207
+ | Multiple validators | One per flow sufficient |
208
+
209
+ ---
210
+
211
+ ## Data Flow Examples
212
+
213
+ ### Order Complete (Server Flow)
214
+
215
+ 1. **Ingest**: Request metadata extracted (IP, user-agent, referer) to
216
+ `context.*`
217
+ 2. **Policy**: Pre-processes event:
218
+ - `user_data.em` from `user.email` (only if marketing consent)
219
+ - `user_data.external_id` from `user.id`
220
+ - `custom_data.server_processed` = `true`
221
+ - `custom_data.request_meta` = `{ ip, ua }` from context
222
+ 3. **Fingerprint**: Hashes context fields to `user.hash`
223
+ 4. **Validator**: Checks products have `data.id`
224
+ 5. **Mapping**: Transforms to Meta format:
225
+ - `"name": "Purchase"`
226
+ - `value`, `currency`, `order_id` extracted
227
+ - `contents` via `$ref` to definition loop
228
+
229
+ ### Product Add (Web Flow)
230
+
231
+ 1. **DataLayer Source**: Captures `add_to_cart` event
232
+ 2. **Source Mapping**: Transforms to `product add` with walkerOS structure
233
+ 3. **Validator**: Checks `id` and `name` present
234
+ 4. **Collector**: Adds globals, consent, user data
235
+ 5. **GA4 Mapping**: Transforms to `add_to_cart` with items array
236
+ 6. **API Destination**: Batches and sends to server (if batch size reached)
237
+
238
+ ---
239
+
240
+ ## Environment Variables
241
+
242
+ | Variable | Default | Description |
243
+ | -------------------- | ------------------------------- | -------------------------- |
244
+ | `GA4_MEASUREMENT_ID` | `G-DEMO123456` | Google Analytics 4 ID |
245
+ | `API_URL` | `http://localhost:8080/collect` | Server collection endpoint |
246
+ | `META_PIXEL_ID` | `123456789012345` | Meta Pixel ID |
247
+ | `META_ACCESS_TOKEN` | `demo_token` | Meta Conversions API token |
package/dist/index.d.ts CHANGED
@@ -160,11 +160,6 @@ interface GlobalOptions {
160
160
  * @default false
161
161
  */
162
162
  silent?: boolean;
163
- /**
164
- * Preview command without executing
165
- * @default false
166
- */
167
- dryRun?: boolean;
168
163
  }
169
164
 
170
165
  interface BundleStats {
@@ -185,9 +180,8 @@ interface BundleCommandOptions {
185
180
  json?: boolean;
186
181
  cache?: boolean;
187
182
  verbose?: boolean;
188
- dryRun?: boolean;
189
183
  silent?: boolean;
190
- dockerfile?: boolean;
184
+ dockerfile?: boolean | string;
191
185
  }
192
186
  declare function bundleCommand(options: BundleCommandOptions): Promise<void>;
193
187
  /**
@@ -247,9 +241,9 @@ interface ApiCall {
247
241
  interface SimulateCommandOptions {
248
242
  config: string;
249
243
  event?: string;
244
+ flow?: string;
250
245
  json?: boolean;
251
246
  verbose?: boolean;
252
- dryRun?: boolean;
253
247
  silent?: boolean;
254
248
  platform?: 'web' | 'server';
255
249
  }
@@ -352,8 +346,6 @@ interface RunCommandOptions {
352
346
  json?: boolean;
353
347
  /** Verbose logging */
354
348
  verbose?: boolean;
355
- /** Dry-run mode */
356
- dryRun?: boolean;
357
349
  /** Suppress output */
358
350
  silent?: boolean;
359
351
  }
package/dist/index.js CHANGED
@@ -30,6 +30,7 @@ var VERSION = JSON.parse(findPackageJson()).version;
30
30
  // src/commands/bundle/index.ts
31
31
  import path9 from "path";
32
32
  import fs8 from "fs-extra";
33
+ import { getPlatform as getPlatform2 } from "@walkeros/core";
33
34
 
34
35
  // src/core/logger.ts
35
36
  import chalk from "chalk";
@@ -1335,10 +1336,6 @@ async function bundleCommand(options) {
1335
1336
  const timer = createTimer();
1336
1337
  timer.start();
1337
1338
  const logger2 = createCommandLogger(options);
1338
- if (options.dryRun) {
1339
- logger2.log(`[DRY-RUN] Would execute bundle with config: ${options.config}`);
1340
- return;
1341
- }
1342
1339
  try {
1343
1340
  if (options.flow && options.all) {
1344
1341
  throw new Error("Cannot use both --flow and --all flags together");
@@ -1385,11 +1382,12 @@ async function bundleCommand(options) {
1385
1382
  displayStats(stats, logger2);
1386
1383
  }
1387
1384
  if (options.dockerfile && !options.all) {
1388
- const dockerfilePath = path9.join(
1389
- path9.dirname(buildOptions.output),
1390
- "Dockerfile"
1391
- );
1392
- await generateDockerfile(dockerfilePath, buildOptions.output, logger2);
1385
+ const platform = getPlatform2(flowConfig);
1386
+ if (platform) {
1387
+ const outputDir = path9.dirname(buildOptions.output);
1388
+ const customFile = typeof options.dockerfile === "string" ? options.dockerfile : void 0;
1389
+ await generateDockerfile(outputDir, platform, logger2, customFile);
1390
+ }
1393
1391
  }
1394
1392
  } catch (error) {
1395
1393
  const errorMessage = getErrorMessage(error);
@@ -1473,26 +1471,34 @@ async function bundle(configOrPath, options = {}) {
1473
1471
  options.stats ?? false
1474
1472
  );
1475
1473
  }
1476
- async function generateDockerfile(dockerfilePath, bundleOutput, logger2) {
1477
- const bundleFilename = path9.basename(bundleOutput);
1474
+ async function generateDockerfile(outputDir, platform, logger2, customFile) {
1475
+ const destPath = path9.join(outputDir, "Dockerfile");
1476
+ if (customFile && await fs8.pathExists(customFile)) {
1477
+ await fs8.copy(customFile, destPath);
1478
+ logger2.log(`Dockerfile: ${destPath} (copied from ${customFile})`);
1479
+ return;
1480
+ }
1481
+ const isWeb = platform === "web";
1482
+ const bundleFile = isWeb ? "walker.js" : "bundle.mjs";
1483
+ const mode = isWeb ? "serve" : "collect";
1478
1484
  const dockerfile = `# Generated by walkeros CLI
1479
1485
  FROM walkeros/flow:latest
1480
1486
 
1481
- COPY ${bundleFilename} /app/flow/bundle.mjs
1487
+ COPY ${bundleFile} /app/flow/${bundleFile}
1482
1488
 
1483
- ENV MODE=collect
1484
- ENV BUNDLE=/app/flow/bundle.mjs
1489
+ ENV MODE=${mode}
1490
+ ENV BUNDLE=/app/flow/${bundleFile}
1485
1491
 
1486
1492
  EXPOSE 8080
1487
1493
  `;
1488
- await fs8.writeFile(dockerfilePath, dockerfile);
1489
- logger2.log(`Dockerfile: ${dockerfilePath}`);
1494
+ await fs8.writeFile(destPath, dockerfile);
1495
+ logger2.log(`Dockerfile: ${destPath}`);
1490
1496
  }
1491
1497
 
1492
1498
  // src/commands/simulate/simulator.ts
1493
1499
  import path10 from "path";
1494
1500
  import fs10 from "fs-extra";
1495
- import { getPlatform as getPlatform2 } from "@walkeros/core";
1501
+ import { getPlatform as getPlatform3 } from "@walkeros/core";
1496
1502
 
1497
1503
  // src/commands/simulate/tracker.ts
1498
1504
  var CallTracker = class {
@@ -1804,6 +1810,7 @@ async function simulateCore(inputPath, event, options = {}) {
1804
1810
  try {
1805
1811
  logger2.debug(`Simulating event: ${JSON.stringify(event)}`);
1806
1812
  const result = await executeSimulation(event, inputPath, options.platform, {
1813
+ flow: options.flow,
1807
1814
  logger: logger2,
1808
1815
  verbose: options.verbose
1809
1816
  });
@@ -1851,7 +1858,8 @@ async function executeSimulation(event, inputPath, platformOverride, options = {
1851
1858
  typedEvent,
1852
1859
  tempDir,
1853
1860
  startTime,
1854
- collectorLoggerConfig
1861
+ collectorLoggerConfig,
1862
+ options.flow
1855
1863
  );
1856
1864
  } else {
1857
1865
  return await executeBundleSimulation(
@@ -1877,9 +1885,11 @@ async function executeSimulation(event, inputPath, platformOverride, options = {
1877
1885
  }
1878
1886
  }
1879
1887
  }
1880
- async function executeConfigSimulation(_content, configPath, typedEvent, tempDir, startTime, loggerConfig2) {
1881
- const { flowConfig, buildOptions } = await loadFlowConfig(configPath);
1882
- const platform = getPlatform2(flowConfig);
1888
+ async function executeConfigSimulation(_content, configPath, typedEvent, tempDir, startTime, loggerConfig2, flowName) {
1889
+ const { flowConfig, buildOptions } = await loadFlowConfig(configPath, {
1890
+ flowName
1891
+ });
1892
+ const platform = getPlatform3(flowConfig);
1883
1893
  const tracker = new CallTracker();
1884
1894
  const tempOutput = path10.join(
1885
1895
  tempDir,
@@ -1979,18 +1989,13 @@ async function executeBundleSimulation(bundleContent, platform, typedEvent, temp
1979
1989
  // src/commands/simulate/index.ts
1980
1990
  async function simulateCommand(options) {
1981
1991
  const logger2 = createCommandLogger(options);
1982
- if (options.dryRun) {
1983
- logger2.log(
1984
- `[DRY-RUN] Would execute simulate with config: ${options.config}`
1985
- );
1986
- return;
1987
- }
1988
1992
  const startTime = Date.now();
1989
1993
  try {
1990
1994
  const event = await loadJsonFromSource(options.event, {
1991
1995
  name: "event"
1992
1996
  });
1993
1997
  const result = await simulateCore(options.config, event, {
1998
+ flow: options.flow,
1994
1999
  json: options.json,
1995
2000
  verbose: options.verbose,
1996
2001
  silent: options.silent
@@ -2041,7 +2046,7 @@ import path11 from "path";
2041
2046
  import { JSDOM as JSDOM2, VirtualConsole as VirtualConsole2 } from "jsdom";
2042
2047
  import fs11 from "fs-extra";
2043
2048
  import {
2044
- getPlatform as getPlatform3
2049
+ getPlatform as getPlatform4
2045
2050
  } from "@walkeros/core";
2046
2051
  import { schemas as schemas2 } from "@walkeros/core/dev";
2047
2052
  async function pushCommand(options) {
@@ -2153,7 +2158,7 @@ async function executeConfigPush(options, validatedEvent, logger2, setTempDir) {
2153
2158
  flowName: options.flow,
2154
2159
  logger: logger2
2155
2160
  });
2156
- const platform = getPlatform3(flowConfig);
2161
+ const platform = getPlatform4(flowConfig);
2157
2162
  logger2.debug("Bundling flow configuration");
2158
2163
  const configDir = buildOptions.configDir || process.cwd();
2159
2164
  const tempDir = path11.join(
@@ -2587,10 +2592,6 @@ async function runCommand(mode, options) {
2587
2592
  logger2.debug("Bundle ready");
2588
2593
  }
2589
2594
  }
2590
- if (options.dryRun) {
2591
- logger2.log(`[DRY-RUN] Would execute locally: run ${mode}`);
2592
- return;
2593
- }
2594
2595
  const modeLabel = mode === "collect" ? "Collector" : "Server";
2595
2596
  logger2.log(`Starting ${modeLabel}...`);
2596
2597
  await executeRunLocal(mode, flowPath, {
@@ -2712,7 +2713,10 @@ program.hook("preAction", (thisCommand, actionCommand) => {
2712
2713
  console.log(`${chalk2.hex("#01b5e2")("walkerOS")} v${VERSION}`);
2713
2714
  }
2714
2715
  });
2715
- program.command("bundle [file]").description("Bundle NPM packages with custom code").option("-f, --flow <name>", "flow to build (for multi-flow configs)").option("--all", "build all flows (for multi-flow configs)").option("-s, --stats", "show bundle statistics").option("--json", "output statistics in JSON format (implies --stats)").option("--no-cache", "disable package caching and download fresh packages").option("-v, --verbose", "verbose output").option("--dry-run", "preview command without executing").option("--silent", "suppress output").option("--dockerfile", "generate Dockerfile alongside bundle").action(async (file, options) => {
2716
+ program.command("bundle [file]").description("Bundle NPM packages with custom code").option("--flow <name>", "flow name for multi-flow configs").option("--all", "build all flows for multi-flow configs").option("--stats", "show bundle statistics").option("--json", "output as JSON (implies --stats)").option("--no-cache", "disable package caching").option("-v, --verbose", "verbose output").option("-s, --silent", "suppress output").option(
2717
+ "--dockerfile [file]",
2718
+ "generate Dockerfile (or copy custom file) to dist/"
2719
+ ).action(async (file, options) => {
2716
2720
  await bundleCommand({
2717
2721
  config: file || "bundle.config.json",
2718
2722
  flow: options.flow,
@@ -2721,29 +2725,28 @@ program.command("bundle [file]").description("Bundle NPM packages with custom co
2721
2725
  json: options.json,
2722
2726
  cache: options.cache,
2723
2727
  verbose: options.verbose,
2724
- dryRun: options.dryRun,
2725
2728
  silent: options.silent,
2726
2729
  dockerfile: options.dockerfile
2727
2730
  });
2728
2731
  });
2729
2732
  program.command("simulate [file]").description("Simulate event processing and capture API calls").option(
2730
2733
  "-e, --event <source>",
2731
- "Event to simulate (JSON string, file path, or URL)"
2732
- ).option("-p, --platform <platform>", "Platform override (web or server)").option("--json", "Output results as JSON").option("-v, --verbose", "Verbose output").option("--dry-run", "preview command without executing").option("--silent", "suppress output").action(async (file, options) => {
2734
+ "event to simulate (JSON string, file path, or URL)"
2735
+ ).option("--flow <name>", "flow name for multi-flow configs").option("-p, --platform <platform>", "platform override (web or server)").option("--json", "output as JSON").option("-v, --verbose", "verbose output").option("-s, --silent", "suppress output").action(async (file, options) => {
2733
2736
  await simulateCommand({
2734
2737
  config: file || "bundle.config.json",
2735
2738
  event: options.event,
2739
+ flow: options.flow,
2736
2740
  platform: options.platform,
2737
2741
  json: options.json,
2738
2742
  verbose: options.verbose,
2739
- dryRun: options.dryRun,
2740
2743
  silent: options.silent
2741
2744
  });
2742
2745
  });
2743
2746
  program.command("push [file]").description("Push an event through the flow with real API execution").requiredOption(
2744
2747
  "-e, --event <source>",
2745
- "Event to push (JSON string, file path, or URL)"
2746
- ).option("--flow <name>", "Flow name (for multi-flow configs)").option("-p, --platform <platform>", "Platform override (web or server)").option("--json", "Output results as JSON").option("-v, --verbose", "Verbose output").option("-s, --silent", "Suppress output").action(async (file, options) => {
2748
+ "event to push (JSON string, file path, or URL)"
2749
+ ).option("--flow <name>", "flow name for multi-flow configs").option("-p, --platform <platform>", "platform override (web or server)").option("--json", "output as JSON").option("-v, --verbose", "verbose output").option("-s, --silent", "suppress output").action(async (file, options) => {
2747
2750
  await pushCommand({
2748
2751
  config: file || "bundle.config.json",
2749
2752
  event: options.event,
@@ -2757,20 +2760,19 @@ program.command("push [file]").description("Push an event through the flow with
2757
2760
  var runCmd = program.command("run").description("Run walkerOS flows in collect or serve mode");
2758
2761
  runCmd.command("collect [file]").description(
2759
2762
  "Run collector mode (event collection endpoint). Defaults to server-collect.mjs if no file specified."
2760
- ).option("-p, --port <number>", "Port to listen on (default: 8080)", parseInt).option("-h, --host <address>", "Host address (default: 0.0.0.0)").option("--json", "Output results as JSON").option("-v, --verbose", "Verbose output").option("--dry-run", "preview command without executing").option("--silent", "suppress output").action(async (file, options) => {
2763
+ ).option("-p, --port <number>", "port to listen on (default: 8080)", parseInt).option("-h, --host <address>", "host address (default: 0.0.0.0)").option("--json", "output as JSON").option("-v, --verbose", "verbose output").option("-s, --silent", "suppress output").action(async (file, options) => {
2761
2764
  await runCommand("collect", {
2762
2765
  config: file || "server-collect.mjs",
2763
2766
  port: options.port,
2764
2767
  host: options.host,
2765
2768
  json: options.json,
2766
2769
  verbose: options.verbose,
2767
- dryRun: options.dryRun,
2768
2770
  silent: options.silent
2769
2771
  });
2770
2772
  });
2771
2773
  runCmd.command("serve [file]").description(
2772
2774
  "Run serve mode (single-file server for browser bundles). Defaults to baked-in web-serve.js if no file specified."
2773
- ).option("-p, --port <number>", "Port to listen on (default: 8080)", parseInt).option("-h, --host <address>", "Host address (default: 0.0.0.0)").option("--name <filename>", "Filename in URL (default: walker.js)").option("--path <directory>", "URL directory path (e.g., libs/v1)").option("--json", "Output results as JSON").option("-v, --verbose", "Verbose output").option("--dry-run", "preview command without executing").option("--silent", "suppress output").action(async (file, options) => {
2775
+ ).option("-p, --port <number>", "port to listen on (default: 8080)", parseInt).option("-h, --host <address>", "host address (default: 0.0.0.0)").option("--name <filename>", "filename in URL (default: walker.js)").option("--path <directory>", "URL directory path (e.g., libs/v1)").option("--json", "output as JSON").option("-v, --verbose", "verbose output").option("-s, --silent", "suppress output").action(async (file, options) => {
2774
2776
  await runCommand("serve", {
2775
2777
  config: file || "web-serve.js",
2776
2778
  port: options.port,
@@ -2779,7 +2781,6 @@ runCmd.command("serve [file]").description(
2779
2781
  servePath: options.path,
2780
2782
  json: options.json,
2781
2783
  verbose: options.verbose,
2782
- dryRun: options.dryRun,
2783
2784
  silent: options.silent
2784
2785
  });
2785
2786
  });