@withone/cli 1.51.0 → 1.52.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.
package/README.md CHANGED
@@ -140,7 +140,7 @@ Supports Claude Code, Claude Desktop, Cursor, Windsurf, Codex, and Kiro.
140
140
 
141
141
  When you run `one` in a project, it uses the project config if one exists and falls back to the global config otherwise. Use `one config path` to see which config is active and the full resolution order.
142
142
 
143
- In a monorepo, the project root is the nearest ancestor with `.one/`, `.git`, or `package.json` — checked in that order. Run `mkdir .one` in a nested subproject to make it its own project root (so the config is keyed by the nested dir's slug instead of the monorepo's).
143
+ In a monorepo, the project root is the nearest ancestor with `.one/`, `.git`, or `package.json` — checked in that order. Run `mkdir .one` in a nested subproject to make it its own project root (so the config is keyed by the nested dir's slug instead of the monorepo's). Your home directory itself is never treated as a project root — `~/.one` is the CLI's own config directory, and a dotfiles `.git` or stray `package.json` in `$HOME` shouldn't turn everything under home into one project. Scope that applies to all of home is the global config.
144
144
 
145
145
  If you've already set up, `one init` shows your current status for the active scope and lets you update your key, install to more agents, or reconfigure.
146
146
 
@@ -3,7 +3,7 @@ import {
3
3
  readConfig,
4
4
  setOpenAiApiKey,
5
5
  writeConfig
6
- } from "./chunk-SO323PZP.js";
6
+ } from "./chunk-RASDPNMJ.js";
7
7
 
8
8
  // src/lib/memory/config.ts
9
9
  var DEFAULT_MEMORY_CONFIG = {
@@ -5,10 +5,10 @@ import {
5
5
  getMemoryConfig,
6
6
  getMemoryConfigOrDefault,
7
7
  updateMemoryConfig
8
- } from "./chunk-C7DWZ7B5.js";
8
+ } from "./chunk-2VDKHGVN.js";
9
9
  import {
10
10
  getOpenAiApiKey
11
- } from "./chunk-SO323PZP.js";
11
+ } from "./chunk-RASDPNMJ.js";
12
12
 
13
13
  // src/lib/memory/schema.ts
14
14
  var SCHEMA_VERSION = "2.3.1";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  getMemoryConfigOrDefault
3
- } from "./chunk-C7DWZ7B5.js";
3
+ } from "./chunk-2VDKHGVN.js";
4
4
  import {
5
5
  getOpenAiApiKey,
6
6
  readConfig
7
- } from "./chunk-SO323PZP.js";
7
+ } from "./chunk-RASDPNMJ.js";
8
8
 
9
9
  // src/lib/output.ts
10
10
  import * as p from "@clack/prompts";
@@ -6,11 +6,11 @@ import {
6
6
  note,
7
7
  okJson,
8
8
  requireMemoryInit
9
- } from "./chunk-CLJFSFFM.js";
9
+ } from "./chunk-I3ODIT2N.js";
10
10
  import {
11
11
  getBackend,
12
12
  upsertRecord
13
- } from "./chunk-Z4KAQGIG.js";
13
+ } from "./chunk-HSKAP73B.js";
14
14
 
15
15
  // src/commands/mem/migrate.ts
16
16
  import fs4 from "fs";
@@ -3,10 +3,10 @@ import {
3
3
  isAgentMode,
4
4
  json,
5
5
  requireMemoryInit
6
- } from "./chunk-CLJFSFFM.js";
6
+ } from "./chunk-I3ODIT2N.js";
7
7
  import {
8
8
  getBackend
9
- } from "./chunk-Z4KAQGIG.js";
9
+ } from "./chunk-HSKAP73B.js";
10
10
 
11
11
  // src/commands/mem/sql.ts
12
12
  async function memSqlCommand(sql) {
@@ -15,8 +15,9 @@ function projectsDir() {
15
15
  function getProjectRoot(cwd = process.cwd()) {
16
16
  let dir = path.resolve(cwd);
17
17
  const root = path.parse(dir).root;
18
+ const home = os.homedir();
18
19
  while (dir !== root) {
19
- if (fs.existsSync(path.join(dir, ".one")) || fs.existsSync(path.join(dir, ".git")) || fs.existsSync(path.join(dir, "package.json"))) {
20
+ if (dir !== home && (fs.existsSync(path.join(dir, ".one")) || fs.existsSync(path.join(dir, ".git")) || fs.existsSync(path.join(dir, "package.json")))) {
20
21
  return dir;
21
22
  }
22
23
  dir = path.dirname(dir);
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-44CV5IMX.js";
5
5
  import {
6
6
  getCacheTtl
7
- } from "./chunk-SO323PZP.js";
7
+ } from "./chunk-RASDPNMJ.js";
8
8
 
9
9
  // src/lib/flow-runner.ts
10
10
  import fs3 from "fs";
@@ -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-ZZEJ6CZI.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,
@@ -2,8 +2,8 @@ import {
2
2
  defaultSearchableText,
3
3
  embed,
4
4
  embedBatch
5
- } from "./chunk-C7DWZ7B5.js";
6
- import "./chunk-SO323PZP.js";
5
+ } from "./chunk-2VDKHGVN.js";
6
+ import "./chunk-RASDPNMJ.js";
7
7
  export {
8
8
  defaultSearchableText,
9
9
  embed,
@@ -12,9 +12,9 @@ import {
12
12
  stripStepsAlias,
13
13
  summarizeFlowInputs,
14
14
  walkSteps
15
- } from "./chunk-D6W756DN.js";
15
+ } from "./chunk-RKQXOFTX.js";
16
16
  import "./chunk-44CV5IMX.js";
17
- import "./chunk-SO323PZP.js";
17
+ import "./chunk-RASDPNMJ.js";
18
18
  export {
19
19
  FlowRunner,
20
20
  collectStepTypes,
package/dist/index.js CHANGED
@@ -32,10 +32,10 @@ import {
32
32
  validateActionInput,
33
33
  walkSteps,
34
34
  writeCache
35
- } from "./chunk-D6W756DN.js";
35
+ } from "./chunk-RKQXOFTX.js";
36
36
  import {
37
37
  memSqlCommand
38
- } from "./chunk-UV4YYDF3.js";
38
+ } from "./chunk-PQQAMG2S.js";
39
39
  import {
40
40
  collectIdentityKeys,
41
41
  countRecords,
@@ -65,7 +65,7 @@ import {
65
65
  writeDraftProfile,
66
66
  writePageToMemory,
67
67
  writeProfile
68
- } from "./chunk-ZOJW6IMU.js";
68
+ } from "./chunk-P5KRUMV3.js";
69
69
  import {
70
70
  getByDotPath
71
71
  } from "./chunk-44CV5IMX.js";
@@ -89,7 +89,7 @@ import {
89
89
  semanticSearchUpgradeLine,
90
90
  setAgentMode,
91
91
  silenceWarningsInAgentMode
92
- } from "./chunk-CLJFSFFM.js";
92
+ } from "./chunk-I3ODIT2N.js";
93
93
  import {
94
94
  SCHEMA_VERSION,
95
95
  addRecord,
@@ -99,7 +99,7 @@ import {
99
99
  listBackendPlugins,
100
100
  loadBackendFromConfig,
101
101
  updateRecord
102
- } from "./chunk-Z4KAQGIG.js";
102
+ } from "./chunk-HSKAP73B.js";
103
103
  import {
104
104
  DEFAULT_MEMORY_CONFIG,
105
105
  defaultSearchableText,
@@ -109,7 +109,7 @@ import {
109
109
  memoryConfigExists,
110
110
  setOpenAiApiKey,
111
111
  updateMemoryConfig
112
- } from "./chunk-C7DWZ7B5.js";
112
+ } from "./chunk-2VDKHGVN.js";
113
113
  import {
114
114
  appendAnalyticsQueue,
115
115
  appendUsageLog,
@@ -144,7 +144,7 @@ import {
144
144
  writeConfig,
145
145
  writeUsageLog,
146
146
  writeUsageState
147
- } from "./chunk-SO323PZP.js";
147
+ } from "./chunk-RASDPNMJ.js";
148
148
 
149
149
  // src/cli.ts
150
150
  import { createRequire as createRequire3 } from "module";
@@ -6053,7 +6053,7 @@ async function syncModel(api, profile, options) {
6053
6053
  updateModelState(platform, model, { status: "failed", pagesProcessed, lastCursor }),
6054
6054
  (async () => {
6055
6055
  try {
6056
- const { getBackend: getBackend2 } = await import("./runtime-HDZCBTWH.js");
6056
+ const { getBackend: getBackend2 } = await import("./runtime-LBDMRCH2.js");
6057
6057
  const backend = await getBackend2();
6058
6058
  await Promise.race([
6059
6059
  backend.close(),
@@ -6419,7 +6419,7 @@ async function syncModel(api, profile, options) {
6419
6419
  db.exec(`DROP TABLE IF EXISTS _seen_ids`);
6420
6420
  }
6421
6421
  if (options.toMemory !== false) {
6422
- const backend = await (await import("./runtime-HDZCBTWH.js")).getBackend();
6422
+ const backend = await (await import("./runtime-LBDMRCH2.js")).getBackend();
6423
6423
  const type = `${platform}/${model}`;
6424
6424
  const existing = await backend.listKeysByType(type);
6425
6425
  const sourcePrefix = `${type}:`;
@@ -6505,7 +6505,7 @@ async function syncModel(api, profile, options) {
6505
6505
  let statusCounts;
6506
6506
  if (options.toMemory !== false) {
6507
6507
  try {
6508
- const backend = await (await import("./runtime-HDZCBTWH.js")).getBackend();
6508
+ const backend = await (await import("./runtime-LBDMRCH2.js")).getBackend();
6509
6509
  const typeName = `${platform}/${model}`;
6510
6510
  const [active, archived] = await Promise.all([
6511
6511
  backend.count(typeName, { status: "active" }),
@@ -8194,7 +8194,7 @@ ${result.total} results`);
8194
8194
  }
8195
8195
  }
8196
8196
  async function syncSqlCommand(platformModel, sql) {
8197
- const { syncSqlCommand: runSyncSql } = await import("./sql-AZDCMY7G.js");
8197
+ const { syncSqlCommand: runSyncSql } = await import("./sql-YVDVJK7L.js");
8198
8198
  await runSyncSql(platformModel, sql);
8199
8199
  }
8200
8200
  async function syncDeleteCommand(platformModel, options) {
@@ -8272,7 +8272,7 @@ async function syncDeleteCommand(platformModel, options) {
8272
8272
  async function maybeAutoMigrateLegacy(platform, models) {
8273
8273
  const dbSize = getDatabaseSize(platform);
8274
8274
  if (!dbSize || dbSize === "0 B") return;
8275
- const { getBackend: getBackend2 } = await import("./runtime-HDZCBTWH.js");
8275
+ const { getBackend: getBackend2 } = await import("./runtime-LBDMRCH2.js");
8276
8276
  const backend = await getBackend2();
8277
8277
  let memoryHasData = false;
8278
8278
  for (const model of models) {
@@ -8288,7 +8288,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
8288
8288
  ` detected legacy .one/sync/data/${platform}.db (${dbSize}) \u2014 auto-migrating into memory before sync.
8289
8289
  `
8290
8290
  );
8291
- const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-LXDIZMXH.js");
8291
+ const { memMigrateCommand: memMigrateCommand3 } = await import("./migrate-SOHPYWUU.js");
8292
8292
  await memMigrateCommand3({ platform, yes: true });
8293
8293
  return;
8294
8294
  }
@@ -8297,7 +8297,7 @@ async function maybeAutoMigrateLegacy(platform, models) {
8297
8297
  initialValue: true
8298
8298
  });
8299
8299
  if (p7.isCancel(shouldMigrate) || !shouldMigrate) return;
8300
- const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-LXDIZMXH.js");
8300
+ const { memMigrateCommand: memMigrateCommand2 } = await import("./migrate-SOHPYWUU.js");
8301
8301
  await memMigrateCommand2({ platform, yes: true });
8302
8302
  }
8303
8303
  async function syncSuggestSearchableCommand(platformModel, options = {}) {
@@ -8358,7 +8358,7 @@ async function syncSuggestSearchableCommand(platformModel, options = {}) {
8358
8358
  async function syncListCommand(platform) {
8359
8359
  const profiles = listProfiles(platform);
8360
8360
  const state = await readSyncState();
8361
- const { getBackend: getBackend2 } = await import("./runtime-HDZCBTWH.js");
8361
+ const { getBackend: getBackend2 } = await import("./runtime-LBDMRCH2.js");
8362
8362
  const backend = await getBackend2();
8363
8363
  const syncs = await Promise.all(profiles.map(async (p10) => {
8364
8364
  const modelState = state[p10.platform]?.[p10.model];
@@ -8633,7 +8633,7 @@ function registerSyncSubcommands(sync) {
8633
8633
  await syncSqlCommand(platformModel, sql);
8634
8634
  });
8635
8635
  sync.command("schema <platform/model>").description("Inspect the JSON structure of synced records (field paths, types, examples) \u2014 useful before writing `sync sql` queries").action(async (platformModel) => {
8636
- const { syncSchemaCommand } = await import("./schema-SYMG6SRC.js");
8636
+ const { syncSchemaCommand } = await import("./schema-GKS6MF25.js");
8637
8637
  await syncSchemaCommand(platformModel);
8638
8638
  });
8639
8639
  sync.command("delete <platform/model>").description('Delete records from local sync data (e.g. one sync delete notion/pages --id "abc-123")').option("--id <value>", "Delete record by ID").option("--where <conditions>", 'Delete records matching conditions (e.g. "status=archived")').option("--where-sql <predicate>", `Delete using a raw SQL WHERE clause (e.g. "json_extract(data, '$.type') = 'promotion'")`).option("--yes", "Skip confirmation prompt").action(async (platformModel, options) => {
@@ -9410,7 +9410,7 @@ async function memDoctorCommand() {
9410
9410
  }
9411
9411
  if (cfg.embedding.provider === "openai") {
9412
9412
  try {
9413
- const { embed: embed2 } = await import("./embedding-2YB6CGBA.js");
9413
+ const { embed: embed2 } = await import("./embedding-AVBSB7SG.js");
9414
9414
  const result = await embed2("connectivity check");
9415
9415
  checks.push({
9416
9416
  name: "OpenAI embedding provider reachable",
@@ -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\`
@@ -3,12 +3,12 @@ import {
3
3
  dotPathToJsonbExpr,
4
4
  memMigrateCommand,
5
5
  reviveStringifiedJson
6
- } from "./chunk-ZOJW6IMU.js";
6
+ } from "./chunk-P5KRUMV3.js";
7
7
  import "./chunk-44CV5IMX.js";
8
- import "./chunk-CLJFSFFM.js";
9
- import "./chunk-Z4KAQGIG.js";
10
- import "./chunk-C7DWZ7B5.js";
11
- import "./chunk-SO323PZP.js";
8
+ import "./chunk-I3ODIT2N.js";
9
+ import "./chunk-HSKAP73B.js";
10
+ import "./chunk-2VDKHGVN.js";
11
+ import "./chunk-RASDPNMJ.js";
12
12
  export {
13
13
  buildIdentityMap,
14
14
  dotPathToJsonbExpr,
@@ -5,9 +5,9 @@ import {
5
5
  resetBackendSingleton,
6
6
  updateRecord,
7
7
  upsertRecord
8
- } from "./chunk-Z4KAQGIG.js";
9
- import "./chunk-C7DWZ7B5.js";
10
- import "./chunk-SO323PZP.js";
8
+ } from "./chunk-HSKAP73B.js";
9
+ import "./chunk-2VDKHGVN.js";
10
+ import "./chunk-RASDPNMJ.js";
11
11
  export {
12
12
  addRecord,
13
13
  closeBackendIfCached,
@@ -3,12 +3,12 @@ import {
3
3
  note,
4
4
  okJson,
5
5
  requireMemoryInit
6
- } from "./chunk-CLJFSFFM.js";
6
+ } from "./chunk-I3ODIT2N.js";
7
7
  import {
8
8
  getBackend
9
- } from "./chunk-Z4KAQGIG.js";
10
- import "./chunk-C7DWZ7B5.js";
11
- import "./chunk-SO323PZP.js";
9
+ } from "./chunk-HSKAP73B.js";
10
+ import "./chunk-2VDKHGVN.js";
11
+ import "./chunk-RASDPNMJ.js";
12
12
 
13
13
  // src/lib/memory/sync/schema.ts
14
14
  import pc from "picocolors";
@@ -0,0 +1,12 @@
1
+ import {
2
+ memSqlCommand,
3
+ syncSqlCommand
4
+ } from "./chunk-PQQAMG2S.js";
5
+ import "./chunk-I3ODIT2N.js";
6
+ import "./chunk-HSKAP73B.js";
7
+ import "./chunk-2VDKHGVN.js";
8
+ import "./chunk-RASDPNMJ.js";
9
+ export {
10
+ memSqlCommand,
11
+ syncSqlCommand
12
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withone/cli",
3
- "version": "1.51.0",
3
+ "version": "1.52.1",
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
 
@@ -5,7 +5,7 @@ The One CLI can be configured at two scopes:
5
5
  - **Global** — `~/.one/config.json`. Applies everywhere the user runs `one`.
6
6
  - **Project** — `~/.one/projects/<slug>/config.json`, where `<slug>` is the project root path with path separators (and any character Windows forbids in a path component) replaced by dashes (e.g. `/Users/jane/acme` → `-Users-jane-acme`; on Windows, `C:\Users\jane\acme` → `C--Users-jane-acme`). Only applies when running `one` from inside that project folder.
7
7
 
8
- **Detecting the project root.** The CLI walks up from cwd looking for `.one`, `.git`, or `package.json` and treats the nearest hit as the project root — `.one` is checked first so a monorepo subproject can opt into being its own root with `mkdir .one`. Without a `.one` opt-in, every cwd under a parent `.git`/`package.json` shares one project config keyed by that parent.
8
+ **Detecting the project root.** The CLI walks up from cwd looking for `.one`, `.git`, or `package.json` and treats the nearest hit as the project root — `.one` is checked first so a monorepo subproject can opt into being its own root with `mkdir .one`. Without a `.one` opt-in, every cwd under a parent `.git`/`package.json` shares one project config keyed by that parent. Exception: `$HOME` itself is never a project root — `~/.one` is the CLI's own config directory (not an opt-in marker), and a dotfiles `.git` or stray `package.json` in home must not shadow the global config for every directory under it. If a marker-less dir should be its own project, `mkdir .one` inside it before picking project scope.
9
9
 
10
10
  **Resolution order:** env vars → `.onerc` in cwd → project config → global config. The project lookup walks from cwd up — the nearest ancestor that has a config under `~/.one/projects/<slug>/config.json` wins, so cwd's own slug is checked before any parent's.
11
11
 
@@ -1,12 +0,0 @@
1
- import {
2
- memSqlCommand,
3
- syncSqlCommand
4
- } from "./chunk-UV4YYDF3.js";
5
- import "./chunk-CLJFSFFM.js";
6
- import "./chunk-Z4KAQGIG.js";
7
- import "./chunk-C7DWZ7B5.js";
8
- import "./chunk-SO323PZP.js";
9
- export {
10
- memSqlCommand,
11
- syncSqlCommand
12
- };