@withone/cli 1.33.0 → 1.34.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/README.md CHANGED
@@ -98,7 +98,7 @@ one flow validate welcome-customer
98
98
  one flow execute welcome-customer -i email=jane@example.com
99
99
  ```
100
100
 
101
- Workflows live under `.one/flows/<key>/flow.json` with an optional `lib/` subfolder for `.mjs` code modules — create new flows in this folder layout. (The legacy single-file layout `.one/flows/<key>.flow.json` is deprecated but still loads for backward compatibility.) Flows support conditions, loops, while loops, parallel steps, transforms, sub-flows, pagination, bash steps, and external `.mjs` code modules. Run `one guide flows` for the full reference.
101
+ Workflows live under `.one/flows/<key>/flow.json` with an optional `lib/` subfolder for `.mjs` code modules — create new flows in this folder layout. Flows can be organized into subdirectory groups: `.one/flows/<group>/<key>/flow.json`. Reference them as `group/key` or just the bare key if unique. (The legacy single-file layout `.one/flows/<key>.flow.json` is deprecated but still loads for backward compatibility.) Flows support conditions, loops, while loops, parallel steps, transforms, sub-flows, pagination, bash steps, and external `.mjs` code modules. Run `one guide flows` for the full reference.
102
102
 
103
103
  ## How it works
104
104
 
@@ -357,12 +357,15 @@ In agent mode (`--agent`), the JSON response includes the guide content and an `
357
357
 
358
358
  ### `one flow create [key]`
359
359
 
360
- Create a workflow from a JSON definition. New workflows are always saved to the folder layout at `.one/flows/<key>/flow.json` (with a `lib/` subfolder scaffolded for code modules). The legacy `.one/flows/<key>.flow.json` single-file layout is deprecated; existing legacy files continue to load and run unchanged for backward compatibility.
360
+ Create a workflow from a JSON definition. New workflows are always saved to the folder layout at `.one/flows/<key>/flow.json` (with a `lib/` subfolder scaffolded for code modules). Use `group/key` to place flows in a subdirectory group (e.g. `.one/flows/research/company-research/flow.json`). The legacy `.one/flows/<key>.flow.json` single-file layout is deprecated; existing legacy files continue to load and run unchanged for backward compatibility.
361
361
 
362
362
  ```bash
363
363
  # From a --definition flag
364
364
  one flow create welcome-customer --definition '{"key":"welcome-customer","name":"Welcome","version":"1","inputs":{},"steps":[]}'
365
365
 
366
+ # Create in a subdirectory group
367
+ one flow create research/company-research --definition @flow.json
368
+
366
369
  # From stdin
367
370
  cat flow.json | one flow create
368
371
 
@@ -1042,7 +1042,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
1042
1042
  if (flowStack.includes(resolvedKey)) {
1043
1043
  throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
1044
1044
  }
1045
- const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-6IFPWOS4.js");
1045
+ const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-TNI7YWVY.js");
1046
1046
  const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
1047
1047
  const subContext = await executeFlow(
1048
1048
  subFlow,
@@ -1847,7 +1847,18 @@ Workflows live in \`.one/flows/\` (relative to your current working directory \u
1847
1847
  - **Folder layout (REQUIRED for new flows)** \u2014 \`.one/flows/<key>/flow.json\`, with an optional \`lib/\` subfolder for JavaScript modules. This is like a skill: the folder groups the JSON spec with any JavaScript modules it needs, so the whole flow is shareable. **Always create new flows in this layout.**
1848
1848
  - **Single-file layout (DEPRECATED)** \u2014 \`.one/flows/<key>.flow.json\`. Still loads and runs for backward compatibility, but is deprecated. Do not create new flows in this layout. When editing an existing single-file flow, migrate it to the folder layout: move \`<key>.flow.json\` to \`<key>/flow.json\` and extract any non-trivial \`code.source\` blocks into \`<key>/lib/*.mjs\` modules.
1849
1849
 
1850
- When resolving a flow by key, the CLI checks the folder layout first, then the deprecated legacy file. The \`loadFlow\` helper in agent integrations behaves the same.
1850
+ **Subdirectory groups** \u2014 Flows can be organized into subdirectories: \`.one/flows/<group>/<key>/flow.json\`. For example:
1851
+ \`\`\`
1852
+ .one/flows/
1853
+ research/
1854
+ company-research/flow.json
1855
+ competitor-research/flow.json
1856
+ deal-ops/
1857
+ deal-log/flow.json
1858
+ \`\`\`
1859
+ Reference grouped flows with \`group/key\` (e.g. \`one flow execute research/company-research\`) or just the bare key if it's unique (e.g. \`one flow execute company-research\`). Create grouped flows with \`one flow create research/company-research --definition ...\`. \`flow list\` shows the group prefix.
1860
+
1861
+ When resolving a flow by key, the CLI checks the folder layout first, then the deprecated legacy file, then scans group subdirectories. The \`loadFlow\` helper in agent integrations behaves the same.
1851
1862
 
1852
1863
  ## Before you execute a flow you did NOT author \u2014 READ THIS
1853
1864
 
@@ -1872,19 +1883,21 @@ A good description is one paragraph. If a flow's description doesn't tell you ho
1872
1883
  ## Commands
1873
1884
 
1874
1885
  \`\`\`bash
1875
- one --agent flow create <key> --definition '<json>' # Create (or --definition @file.json)
1876
- one --agent flow create <key> --definition @flow.json # Create from file
1877
- one --agent flow list # List
1878
- one --agent flow validate <key> # Validate
1879
- one --agent flow execute <key> -i name=value # Execute
1880
- one --agent flow execute <key> --dry-run --mock # Test with mock data
1881
- one --agent flow execute <key> --allow-bash # Enable bash steps
1882
- one --agent flow runs [flowKey] # List past runs
1883
- one --agent flow resume <runId> # Resume failed run
1884
- one --agent flow scaffold [template] # Generate a starter template
1886
+ one --agent flow create <key> --definition '<json>' # Create (or --definition @file.json)
1887
+ one --agent flow create <key> --definition @flow.json # Create from file
1888
+ one --agent flow create <group/key> --definition '<json>' # Create in a subdirectory group
1889
+ one --agent flow list # List (shows group prefixes)
1890
+ one --agent flow validate <key> # Validate
1891
+ one --agent flow execute <key> -i name=value # Execute (bare key)
1892
+ one --agent flow execute <group/key> -i name=value # Execute (namespaced key)
1893
+ one --agent flow execute <key> --dry-run --mock # Test with mock data
1894
+ one --agent flow execute <key> --allow-bash # Enable bash steps
1895
+ one --agent flow runs [flowKey] # List past runs
1896
+ one --agent flow resume <runId> # Resume failed run
1897
+ one --agent flow scaffold [template] # Generate a starter template
1885
1898
  \`\`\`
1886
1899
 
1887
- You can also write the JSON file directly to \`.one/flows/<key>/flow.json\` \u2014 often easier than passing large JSON via --definition. (The legacy \`.one/flows/<key>.flow.json\` single-file location is deprecated; don't use it for new flows.)
1900
+ You can also write the JSON file directly to \`.one/flows/<key>/flow.json\` (or \`.one/flows/<group>/<key>/flow.json\` for grouped flows) \u2014 often easier than passing large JSON via --definition. (The legacy \`.one/flows/<key>.flow.json\` single-file location is deprecated; don't use it for new flows.)
1888
1901
 
1889
1902
  ## Code modules (flow \`lib/\` folder)
1890
1903
 
@@ -2501,13 +2514,31 @@ var FlowRunner = class _FlowRunner {
2501
2514
  }
2502
2515
  };
2503
2516
  function resolveFlowPath(keyOrPath) {
2504
- if (keyOrPath.includes("/") || keyOrPath.includes("\\") || keyOrPath.endsWith(".json")) {
2517
+ if (keyOrPath.endsWith(".json")) {
2518
+ return path2.resolve(keyOrPath);
2519
+ }
2520
+ if (keyOrPath.includes("\\")) {
2505
2521
  return path2.resolve(keyOrPath);
2506
2522
  }
2523
+ if (keyOrPath.includes("/")) {
2524
+ const nestedFolder = path2.resolve(FLOWS_DIR, keyOrPath, "flow.json");
2525
+ if (fs2.existsSync(nestedFolder)) return nestedFolder;
2526
+ const literal = path2.resolve(keyOrPath);
2527
+ if (fs2.existsSync(literal)) return literal;
2528
+ return nestedFolder;
2529
+ }
2507
2530
  const folderPath = path2.resolve(FLOWS_DIR, keyOrPath, "flow.json");
2508
- const legacyPath = path2.resolve(FLOWS_DIR, `${keyOrPath}.flow.json`);
2509
2531
  if (fs2.existsSync(folderPath)) return folderPath;
2532
+ const legacyPath = path2.resolve(FLOWS_DIR, `${keyOrPath}.flow.json`);
2510
2533
  if (fs2.existsSync(legacyPath)) return legacyPath;
2534
+ const flowsDir = path2.resolve(FLOWS_DIR);
2535
+ if (fs2.existsSync(flowsDir)) {
2536
+ for (const entry of fs2.readdirSync(flowsDir, { withFileTypes: true })) {
2537
+ if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
2538
+ const nested = path2.join(flowsDir, entry.name, keyOrPath, "flow.json");
2539
+ if (fs2.existsSync(nested)) return nested;
2540
+ }
2541
+ }
2511
2542
  return folderPath;
2512
2543
  }
2513
2544
  function getFlowRootDir(flowFilePath) {
@@ -2572,12 +2603,13 @@ function listFlows() {
2572
2603
  if (!fs2.existsSync(flowsDir)) return [];
2573
2604
  const flows = [];
2574
2605
  const seenKeys = /* @__PURE__ */ new Set();
2575
- const readFlowFile = (filePath) => {
2606
+ const readFlowFile = (filePath, group) => {
2576
2607
  try {
2577
2608
  const content = fs2.readFileSync(filePath, "utf-8");
2578
2609
  const flow = JSON.parse(content);
2579
- if (seenKeys.has(flow.key)) return;
2580
- seenKeys.add(flow.key);
2610
+ const nsKey = group ? `${group}/${flow.key}` : flow.key;
2611
+ if (seenKeys.has(nsKey)) return;
2612
+ seenKeys.add(nsKey);
2581
2613
  flows.push({
2582
2614
  key: flow.key,
2583
2615
  name: flow.name,
@@ -2586,6 +2618,7 @@ function listFlows() {
2586
2618
  stepCount: flow.steps.length,
2587
2619
  path: filePath,
2588
2620
  layout: path2.basename(filePath) === "flow.json" ? "folder" : "legacy",
2621
+ group,
2589
2622
  stepTypes: collectStepTypes(flow),
2590
2623
  requiresBash: flowRequiresBash(flow),
2591
2624
  usesCodeModules: flowUsesCodeModules(flow),
@@ -2594,26 +2627,44 @@ function listFlows() {
2594
2627
  } catch {
2595
2628
  }
2596
2629
  };
2597
- for (const entry of fs2.readdirSync(flowsDir, { withFileTypes: true })) {
2598
- if (entry.name.startsWith(".")) continue;
2599
- const full = path2.join(flowsDir, entry.name);
2600
- if (entry.isDirectory()) {
2601
- const flowJson = path2.join(full, "flow.json");
2602
- if (fs2.existsSync(flowJson)) readFlowFile(flowJson);
2603
- } else if (entry.isFile() && entry.name.endsWith(".flow.json")) {
2604
- readFlowFile(full);
2630
+ const scanDir = (dir, group) => {
2631
+ for (const entry of fs2.readdirSync(dir, { withFileTypes: true })) {
2632
+ if (entry.name.startsWith(".")) continue;
2633
+ const full = path2.join(dir, entry.name);
2634
+ if (entry.isDirectory()) {
2635
+ const flowJson = path2.join(full, "flow.json");
2636
+ if (fs2.existsSync(flowJson)) {
2637
+ readFlowFile(flowJson, group);
2638
+ } else {
2639
+ if (!group) {
2640
+ scanDir(full, entry.name);
2641
+ }
2642
+ }
2643
+ } else if (entry.isFile() && entry.name.endsWith(".flow.json")) {
2644
+ readFlowFile(full, group);
2645
+ }
2605
2646
  }
2606
- }
2647
+ };
2648
+ scanDir(flowsDir);
2607
2649
  return flows;
2608
2650
  }
2609
- function saveFlow(flow, outputPath) {
2651
+ function saveFlow(flow, outputPath, group) {
2610
2652
  let flowPath;
2611
2653
  if (outputPath) {
2612
2654
  flowPath = path2.resolve(outputPath);
2613
2655
  } else {
2614
- const legacyPath = path2.resolve(FLOWS_DIR, `${flow.key}.flow.json`);
2615
- const folderPath = path2.resolve(FLOWS_DIR, flow.key, "flow.json");
2616
- if (fs2.existsSync(legacyPath) && !fs2.existsSync(folderPath)) {
2656
+ let bareKey = flow.key;
2657
+ let resolvedGroup = group;
2658
+ if (flow.key.includes("/")) {
2659
+ const parts = flow.key.split("/");
2660
+ bareKey = parts.pop();
2661
+ resolvedGroup = resolvedGroup || parts.join("/");
2662
+ flow.key = bareKey;
2663
+ }
2664
+ const basePath = resolvedGroup ? path2.resolve(FLOWS_DIR, resolvedGroup, bareKey) : path2.resolve(FLOWS_DIR, bareKey);
2665
+ const legacyPath = path2.resolve(FLOWS_DIR, `${bareKey}.flow.json`);
2666
+ const folderPath = path2.join(basePath, "flow.json");
2667
+ if (!resolvedGroup && fs2.existsSync(legacyPath) && !fs2.existsSync(folderPath)) {
2617
2668
  flowPath = legacyPath;
2618
2669
  } else {
2619
2670
  flowPath = folderPath;
@@ -11,7 +11,7 @@ import {
11
11
  saveFlow,
12
12
  summarizeFlowInputs,
13
13
  walkSteps
14
- } from "./chunk-T7LTS2IE.js";
14
+ } from "./chunk-HZP7NT4K.js";
15
15
  export {
16
16
  FlowRunner,
17
17
  collectStepTypes,
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  resolveFlowPath,
20
20
  saveFlow,
21
21
  validateActionInput
22
- } from "./chunk-T7LTS2IE.js";
22
+ } from "./chunk-HZP7NT4K.js";
23
23
 
24
24
  // src/index.ts
25
25
  import { createRequire as createRequire2 } from "module";
@@ -3463,8 +3463,15 @@ async function flowCreateCommand(key, options) {
3463
3463
  } else {
3464
3464
  error("Interactive workflow creation not yet supported. Use --definition <json> or pipe JSON via stdin.");
3465
3465
  }
3466
+ let group;
3466
3467
  if (key) {
3467
- flow2.key = key;
3468
+ if (key.includes("/")) {
3469
+ const parts = key.split("/");
3470
+ flow2.key = parts.pop();
3471
+ group = parts.join("/");
3472
+ } else {
3473
+ flow2.key = key;
3474
+ }
3468
3475
  }
3469
3476
  const errors = validateFlow(flow2);
3470
3477
  if (errors.length > 0) {
@@ -3475,7 +3482,7 @@ async function flowCreateCommand(key, options) {
3475
3482
  error(`Validation failed:
3476
3483
  ${errors.map((e) => ` ${e.path}: ${e.message}`).join("\n")}`);
3477
3484
  }
3478
- const flowPath = saveFlow(flow2, options.output);
3485
+ const flowPath = saveFlow(flow2, options.output, group);
3479
3486
  if (isAgentMode()) {
3480
3487
  json({ created: true, key: flow2.key, path: flowPath });
3481
3488
  return;
@@ -3639,7 +3646,7 @@ async function flowListCommand() {
3639
3646
  { key: "flags", label: "Requires" }
3640
3647
  ],
3641
3648
  flows.map((f) => ({
3642
- key: f.key,
3649
+ key: f.group ? `${f.group}/${f.key}` : f.key,
3643
3650
  name: f.name,
3644
3651
  layout: f.layout,
3645
3652
  inputCount: String(f.inputCount),
@@ -7720,7 +7727,7 @@ one --agent flow list # List all workflows
7720
7727
  \`\`\`
7721
7728
 
7722
7729
  **Key concepts:**
7723
- - Workflows live at \`.one/flows/<key>/flow.json\` (folder layout \u2014 REQUIRED for new flows). The legacy \`.one/flows/<key>.flow.json\` single-file layout is DEPRECATED but still loads for backward compatibility
7730
+ - Workflows live at \`.one/flows/<key>/flow.json\` (folder layout \u2014 REQUIRED for new flows). Flows can be organized into subdirectory groups: \`.one/flows/<group>/<key>/flow.json\`. Reference them as \`group/key\` or just the bare key. The legacy \`.one/flows/<key>.flow.json\` single-file layout is DEPRECATED but still loads for backward compatibility
7724
7731
  - Code steps can reference an external \`.mjs\` module under the flow's \`lib/\` folder (stdin JSON in, stdout JSON out) \u2014 keeps JS out of JSON strings and makes flows shareable
7725
7732
  - 12 step types: action, transform, code, condition, loop, parallel, file-read, file-write, while, flow, paginate, bash
7726
7733
  - Data wiring via selectors: \`$.input.param\`, \`$.steps.stepId.response\`, \`$.loop.item\`
@@ -8697,8 +8704,8 @@ program.name("one").option("--agent", "Machine-readable JSON output (no colors,
8697
8704
 
8698
8705
  Workflows (multi-step):
8699
8706
  one flow list List saved workflows
8700
- one flow create [key] Create a workflow from JSON
8701
- one flow execute <key> Execute a workflow
8707
+ one flow create [key] Create a workflow from JSON (key can be group/key)
8708
+ one flow execute <key> Execute a workflow (key can be group/key)
8702
8709
  one flow validate <key> Validate a flow
8703
8710
 
8704
8711
  Data Sync (run "one sync install" first, then "one guide sync" for full reference):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withone/cli",
3
- "version": "1.33.0",
3
+ "version": "1.34.0",
4
4
  "description": "CLI for managing One",
5
5
  "type": "module",
6
6
  "files": [