@withone/cli 1.51.0 → 1.52.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.
@@ -1039,6 +1039,7 @@ var FLOW_SCHEMA = {
1039
1039
  command: { type: "string", required: true, description: "Shell command to execute (supports selectors)" },
1040
1040
  timeout: { type: "number", required: false, description: "Timeout in ms (default: 30000)" },
1041
1041
  parseJson: { type: "boolean", required: false, description: "Parse stdout as JSON (default: false). When true, $.steps.<id>.output is the parsed object/array; when false, it is the trimmed stdout string." },
1042
+ parseEnvelope: { type: "boolean", required: false, description: "Unwrap a `claude --print --output-format json` envelope: extract .result, strip code fences + preamble, parse the inner JSON as $.steps.<id>.output. Use this (instead of parseJson) for claude --print steps. Fails the step if the unwrapped payload isn't valid JSON." },
1042
1043
  cwd: { type: "string", required: false, description: "Working directory (supports selectors)" },
1043
1044
  env: { type: "object", required: false, description: "Additional environment variables" }
1044
1045
  },
@@ -1049,7 +1050,7 @@ var FLOW_SCHEMA = {
1049
1050
  bash: {
1050
1051
  command: "cat /tmp/data.json | claude --print 'Analyze this data' --output-format json",
1051
1052
  timeout: 18e4,
1052
- parseJson: true
1053
+ parseEnvelope: true
1053
1054
  }
1054
1055
  }
1055
1056
  }
@@ -1986,6 +1987,40 @@ function stripCodeFences(text) {
1986
1987
  const match = trimmed.match(/^```(?:\w*)\s*\n([\s\S]*?)\n\s*```\s*$/);
1987
1988
  return match ? match[1].trim() : trimmed;
1988
1989
  }
1990
+ function stripToJson(text) {
1991
+ const s = stripCodeFences(text);
1992
+ const candidates = [s.indexOf("{"), s.indexOf("[")].filter((i) => i >= 0);
1993
+ if (candidates.length === 0) return s;
1994
+ const start = Math.min(...candidates);
1995
+ const end = Math.max(s.lastIndexOf("}"), s.lastIndexOf("]"));
1996
+ return end > start ? s.slice(start, end + 1) : s;
1997
+ }
1998
+ function unwrapClaudeEnvelope(stdout, stepId) {
1999
+ const trimmed = stdout.trim();
2000
+ let envelope;
2001
+ try {
2002
+ envelope = JSON.parse(trimmed);
2003
+ } catch {
2004
+ envelope = trimmed;
2005
+ }
2006
+ let resultText;
2007
+ if (envelope && typeof envelope === "object" && !Array.isArray(envelope) && envelope.type === "result" && typeof envelope.result === "string") {
2008
+ resultText = envelope.result;
2009
+ } else if (typeof envelope === "string") {
2010
+ resultText = envelope;
2011
+ } else {
2012
+ return envelope;
2013
+ }
2014
+ const payload = stripToJson(resultText);
2015
+ try {
2016
+ return JSON.parse(payload);
2017
+ } catch (err) {
2018
+ const snippet = payload.length > 200 ? `${payload.slice(0, 200)}\u2026` : payload;
2019
+ throw new Error(
2020
+ `Bash step "${stepId}" parseEnvelope: claude output was not valid JSON after unwrapping (${err instanceof Error ? err.message : String(err)}). Got: ${snippet}`
2021
+ );
2022
+ }
2023
+ }
1989
2024
  async function executeActionStep(step, context, api, permissions, allowedActionIds, options) {
1990
2025
  const action = step.action;
1991
2026
  const platform = resolveValue(action.platform, context);
@@ -2319,7 +2354,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
2319
2354
  if (flowStack.includes(resolvedKey)) {
2320
2355
  throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
2321
2356
  }
2322
- const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-YDKAYGZW.js");
2357
+ const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-WZIYXW47.js");
2323
2358
  const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
2324
2359
  const subContext = await executeFlow(
2325
2360
  subFlow,
@@ -2464,7 +2499,7 @@ async function executeBashStep(step, context, options) {
2464
2499
  env,
2465
2500
  maxBuffer: 10 * 1024 * 1024
2466
2501
  });
2467
- const output = config.parseJson ? JSON.parse(stripCodeFences(stdout)) : stdout.trim();
2502
+ const output = config.parseEnvelope ? unwrapClaudeEnvelope(stdout, step.id) : config.parseJson ? JSON.parse(stripCodeFences(stdout)) : stdout.trim();
2468
2503
  return {
2469
2504
  status: "success",
2470
2505
  output,
@@ -12,7 +12,7 @@ import {
12
12
  stripStepsAlias,
13
13
  summarizeFlowInputs,
14
14
  walkSteps
15
- } from "./chunk-D6W756DN.js";
15
+ } from "./chunk-K56Z5BTM.js";
16
16
  import "./chunk-44CV5IMX.js";
17
17
  import "./chunk-SO323PZP.js";
18
18
  export {
package/dist/index.js CHANGED
@@ -32,7 +32,7 @@ import {
32
32
  validateActionInput,
33
33
  walkSteps,
34
34
  writeCache
35
- } from "./chunk-D6W756DN.js";
35
+ } from "./chunk-K56Z5BTM.js";
36
36
  import {
37
37
  memSqlCommand
38
38
  } from "./chunk-UV4YYDF3.js";
@@ -9990,7 +9990,7 @@ one --agent flow list # List all workflows
9990
9990
  - 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
9991
9991
  - 12 step types: action, transform, code, condition, loop, parallel, file-read, file-write, while, flow, paginate, bash
9992
9992
  - Data wiring via selectors: \`$.input.param\`, \`$.steps.stepId.response\`, \`$.loop.item\`
9993
- - AI analysis via bash steps: \`claude --print\` with \`parseJson: true\`
9993
+ - AI analysis via bash steps: \`claude --print --output-format json\` with \`parseEnvelope: true\` (unwraps the CLI envelope + fences + preamble into clean parsed JSON; use instead of \`parseJson\` for claude steps)
9994
9994
  - Use \`--allow-bash\` to enable bash steps, \`--mock\` for dry-run with realistic mock responses (uses example data from action schemas)
9995
9995
  - Use \`--skip-validation\` to bypass input validation on action steps
9996
9996
  - Use \`--output-file <path>\` to stream the full result to a file instead of stdout \u2014 for large results that would otherwise be truncated or hit the JSON string-size limit; stdout (and \`--agent\` output) then carries an \`outputFile\` pointer instead of inline \`steps\`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withone/cli",
3
- "version": "1.51.0",
3
+ "version": "1.52.0",
4
4
  "description": "CLI for managing One",
5
5
  "type": "module",
6
6
  "files": [
@@ -478,10 +478,12 @@ e.g. if sub-flow `enrich-customer` has a step `load` that returns `{ TEAM: "acme
478
478
  {
479
479
  "id": "analyze",
480
480
  "type": "bash",
481
- "bash": { "command": "cat /tmp/data.json | claude --print 'Analyze this' --output-format json", "timeout": 180000, "parseJson": true }
481
+ "bash": { "command": "cat /tmp/data.json | claude --print 'Analyze this' --output-format json", "timeout": 180000, "parseEnvelope": true }
482
482
  }
483
483
  ```
484
484
 
485
+ **Parsing output.** `parseJson: true` parses stdout as JSON (and strips outer code fences). For **`claude --print --output-format json`** steps use **`parseEnvelope: true`** instead — `claude` wraps the model's answer in a CLI envelope `{ "type": "result", "result": "```json\n{...}\n```" }`, and `parseEnvelope` unwraps `.result`, strips the inner code fences, drops any preamble/trailer text, and parses the inner JSON as `$.steps.<id>.output`. If the unwrapped payload isn't valid JSON the step fails (no silently-broken data). No more hand-rolled `unwrap()` helpers in code steps.
486
+
485
487
  **Safe interpolation.** Plain `{{$.input.x}}` does string substitution and is **unsafe** for bash — values containing quotes, `$`, backticks, `&`, etc. will break the command (or worse). Use the `q` helper to POSIX-shell-quote the value:
486
488
 
487
489
  ```json
@@ -665,8 +667,8 @@ Each substep inside `parallel.steps` must have the full step schema: `id`, `name
665
667
 
666
668
  When raw data needs analysis, use this pattern:
667
669
  1. `file-write` — save data to temp file (API responses are too large to inline)
668
- 2. `bash` — call `claude --print` to analyze (set timeout to 180000+, use `--output-format json`)
669
- 3. `code` — parse and structure the AI output for downstream steps
670
+ 2. `bash` — call `claude --print` to analyze (set timeout to 180000+, use `--output-format json` and `"parseEnvelope": true` so `$.steps.<id>.output` is the clean parsed JSON)
671
+ 3. `code` — structure the AI output for downstream steps (no manual envelope unwrap needed — `parseEnvelope` already did it)
670
672
 
671
673
  ## CLI Commands
672
674