@withone/cli 1.21.0 → 1.23.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
@@ -380,6 +380,17 @@ one config
380
380
 
381
381
  Settings propagate automatically to all installed agent configs.
382
382
 
383
+ #### `one config skills status` / `one config skills sync`
384
+
385
+ `one init` copies the packaged skill files (`SKILL.md`, `references/`) into `~/.agents/skills/one/` and symlinks per-agent paths to that canonical directory. When the CLI self-updates, the skill files in the canonical dir would normally stay frozen at the version that was installed. To prevent stale docs, every CLI command checks a `.one-cli-version` marker in the canonical dir and silently refreshes the skill files if they don't match the running CLI version. No user action required.
386
+
387
+ | Command | What it does |
388
+ |---------|--------------|
389
+ | `one config skills status` | Show installed skill version, current CLI version, and path |
390
+ | `one config skills sync` | Force a re-copy of packaged skill files (for troubleshooting) |
391
+
392
+ Auto-sync refuses to resurrect skills if you opted out of skill installation during `one init` — the canonical dir has to already exist.
393
+
383
394
  ## The workflow
384
395
 
385
396
  The power of One is in the workflow. Every interaction follows the same pattern:
@@ -447,6 +447,22 @@ var execAsync = promisify(exec);
447
447
  function sleep2(ms) {
448
448
  return new Promise((resolve) => setTimeout(resolve, ms));
449
449
  }
450
+ function computeRetryDelay(onError, attempt) {
451
+ const base = onError.retryDelayMs ?? 1e3;
452
+ const max = onError.maxDelayMs ?? 3e4;
453
+ const backoff = onError.backoff ?? "fixed";
454
+ const retryIndex = attempt - 2;
455
+ let delay;
456
+ if (backoff === "exponential" || backoff === "exponential-jitter") {
457
+ delay = Math.min(base * Math.pow(2, retryIndex), max);
458
+ if (backoff === "exponential-jitter") {
459
+ delay = delay * (0.5 + Math.random() * 0.5);
460
+ }
461
+ } else {
462
+ delay = base;
463
+ }
464
+ return Math.round(delay);
465
+ }
450
466
  function resolveSelector(selectorPath, context) {
451
467
  if (!selectorPath.startsWith("$.")) return selectorPath;
452
468
  const parts = selectorPath.slice(2).split(/\.|\[/).map((p) => p.replace(/\]$/, ""));
@@ -474,12 +490,22 @@ function resolveSelector(selectorPath, context) {
474
490
  }
475
491
  return current;
476
492
  }
493
+ function shellQuote(value) {
494
+ return `'${value.replace(/'/g, `'\\''`)}'`;
495
+ }
477
496
  function interpolateString(str, context) {
478
- return str.replace(/\{\{(\$\.[^}]+)\}\}/g, (_match, selector) => {
497
+ return str.replace(/\{\{\s*(q\s+)?(\$\.[^}\s]+)\s*\}\}/g, (_match, qFlag, selector) => {
479
498
  const value = resolveSelector(selector, context);
480
- if (value === void 0 || value === null) return "";
481
- if (typeof value === "object") return JSON.stringify(value);
482
- return String(value);
499
+ if (value === void 0 || value === null) return qFlag ? `''` : "";
500
+ if (typeof value === "object") {
501
+ console.warn(
502
+ `[flow] WARNING: Handlebars expression "{{${qFlag ? "q " : ""}${selector}}}" resolved to ${Array.isArray(value) ? "an array" : "an object"} and was stringified as JSON. To pass objects/arrays as native values, use a direct selector without {{ }}: "${selector}"`
503
+ );
504
+ const json = JSON.stringify(value);
505
+ return qFlag ? shellQuote(json) : json;
506
+ }
507
+ const str2 = String(value);
508
+ return qFlag ? shellQuote(str2) : str2;
483
509
  });
484
510
  }
485
511
  function resolveValue(value, context) {
@@ -487,7 +513,7 @@ function resolveValue(value, context) {
487
513
  if (value.startsWith("$.") && !value.includes("{{")) {
488
514
  return resolveSelector(value, context);
489
515
  }
490
- if (value.includes("{{$.")) {
516
+ if (value.includes("{{$.") || /\{\{\s*q\s+\$\./.test(value)) {
491
517
  return interpolateString(value, context);
492
518
  }
493
519
  return value;
@@ -609,8 +635,8 @@ function executeTransformStep(step, context) {
609
635
  async function executeCodeStep(step, context, options) {
610
636
  const config = step.code;
611
637
  if (config.module) {
612
- const output2 = await executeCodeModule(step.id, config.module, context, options);
613
- return { status: "success", output: output2, response: output2 };
638
+ const output = await executeCodeModule(step.id, config.module, context, options);
639
+ return { status: "success", output, response: output };
614
640
  }
615
641
  if (typeof config.source !== "string") {
616
642
  throw new Error(`Code step "${step.id}" must define either "source" or "module"`);
@@ -618,9 +644,41 @@ async function executeCodeStep(step, context, options) {
618
644
  const AsyncFunction = Object.getPrototypeOf(async function() {
619
645
  }).constructor;
620
646
  const sandboxedRequire = createSandboxedRequire();
621
- const fn = new AsyncFunction("$", "require", config.source);
622
- const output = await fn(context, sandboxedRequire);
623
- return { status: "success", output, response: output };
647
+ const sourceURL = `code:${step.id}`;
648
+ const taggedSource = `${config.source}
649
+ //# sourceURL=${sourceURL}`;
650
+ const fn = new AsyncFunction("$", "require", taggedSource);
651
+ try {
652
+ const output = await fn(context, sandboxedRequire);
653
+ return { status: "success", output, response: output };
654
+ } catch (err) {
655
+ throw rewriteCodeStepError(err, step.id, config.source, sourceURL);
656
+ }
657
+ }
658
+ function rewriteCodeStepError(err, stepId, source, sourceURL) {
659
+ if (!(err instanceof Error)) return new Error(String(err));
660
+ const WRAPPER_LINE_OFFSET = 2;
661
+ const sourceLines = source.split("\n");
662
+ const stack = err.stack || "";
663
+ const re = new RegExp(`${sourceURL.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")}:(\\d+):(\\d+)`);
664
+ const match = stack.match(re);
665
+ if (!match) {
666
+ err.message = `Code step "${stepId}" failed: ${err.message}`;
667
+ return err;
668
+ }
669
+ const wrappedLine = parseInt(match[1], 10);
670
+ const col = parseInt(match[2], 10);
671
+ const userLine = wrappedLine - WRAPPER_LINE_OFFSET;
672
+ const lineContent = sourceLines[userLine - 1] ?? "";
673
+ const trimmed = lineContent.trim();
674
+ err.message = `Code step "${stepId}" failed at line ${userLine}:${col}
675
+ ${trimmed}
676
+ ${err.message}`;
677
+ err.stack = stack.replace(
678
+ new RegExp(`(${sourceURL.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")}:)(\\d+)`, "g"),
679
+ (_m, prefix, l) => `${prefix}${parseInt(l, 10) - WRAPPER_LINE_OFFSET}`
680
+ );
681
+ return err;
624
682
  }
625
683
  async function executeCodeModule(stepId, modulePath, context, options) {
626
684
  const rootDir = options.rootDir;
@@ -840,7 +898,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
840
898
  if (flowStack.includes(resolvedKey)) {
841
899
  throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
842
900
  }
843
- const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-CXZ6AWXT.js");
901
+ const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-DFUFU2LM.js");
844
902
  const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
845
903
  const subContext = await executeFlow(
846
904
  subFlow,
@@ -855,7 +913,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
855
913
  return {
856
914
  status: "success",
857
915
  output: subContext.steps,
858
- response: subContext
916
+ response: subContext.steps
859
917
  };
860
918
  }
861
919
  async function executePaginateStep(step, context, api, permissions, allowedActionIds, options) {
@@ -951,13 +1009,14 @@ async function executeSingleStep(step, context, api, permissions, allowedActionI
951
1009
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
952
1010
  try {
953
1011
  if (attempt > 1) {
1012
+ const delay = computeRetryDelay(step.onError, attempt);
954
1013
  options.onEvent?.({
955
1014
  event: "step:retry",
956
1015
  stepId: step.id,
957
1016
  attempt,
958
- maxRetries: step.onError.retries
1017
+ maxRetries: step.onError.retries,
1018
+ delayMs: delay
959
1019
  });
960
- const delay = step.onError?.retryDelayMs || 1e3;
961
1020
  await sleep2(delay);
962
1021
  }
963
1022
  if (options.mock && (step.type === "action" || step.type === "paginate" || step.type === "bash")) {
@@ -1014,7 +1073,14 @@ async function executeSingleStep(step, context, api, permissions, allowedActionI
1014
1073
  throw new Error(`Unknown step type: ${step.type}`);
1015
1074
  }
1016
1075
  result.durationMs = Date.now() - startTime;
1017
- if (attempt > 1) result.retries = attempt - 1;
1076
+ if (attempt > 1) {
1077
+ result.retries = attempt - 1;
1078
+ options.onEvent?.({
1079
+ event: "step:retry-success",
1080
+ stepId: step.id,
1081
+ retries: attempt - 1
1082
+ });
1083
+ }
1018
1084
  context.steps[step.id] = result;
1019
1085
  return result;
1020
1086
  } catch (err) {
@@ -1026,11 +1092,13 @@ async function executeSingleStep(step, context, api, permissions, allowedActionI
1026
1092
  }
1027
1093
  const errorMessage = lastError?.message || "Unknown error";
1028
1094
  const strategy = step.onError?.strategy || "fail";
1095
+ const retriesUsed = Math.max(0, maxAttempts - 1);
1029
1096
  if (strategy === "continue") {
1030
1097
  const result = {
1031
1098
  status: "failed",
1032
1099
  error: errorMessage,
1033
- durationMs: Date.now() - startTime
1100
+ durationMs: Date.now() - startTime,
1101
+ retries: retriesUsed
1034
1102
  };
1035
1103
  context.steps[step.id] = result;
1036
1104
  return result;
@@ -1039,7 +1107,8 @@ async function executeSingleStep(step, context, api, permissions, allowedActionI
1039
1107
  const result = {
1040
1108
  status: "failed",
1041
1109
  error: errorMessage,
1042
- durationMs: Date.now() - startTime
1110
+ durationMs: Date.now() - startTime,
1111
+ retries: retriesUsed
1043
1112
  };
1044
1113
  context.steps[step.id] = result;
1045
1114
  return result;
@@ -1614,7 +1683,7 @@ Every step MUST have \`id\`, \`name\`, and \`type\`. The \`type\` determines whi
1614
1683
  for (const [name, fd] of Object.entries(FLOW_SCHEMA.stepCommonFields)) {
1615
1684
  sections.push(`| \`${name}\` | ${fd.type} | ${fd.required ? "yes" : "no"} | ${fd.description} |`);
1616
1685
  }
1617
- sections.push(`| \`onError\` | object | no | Error handling: \`{ "strategy": "${FLOW_SCHEMA.errorStrategies.join(" | ")}", "retries": 3, "retryDelayMs": 1000 }\` |`);
1686
+ sections.push(`| \`onError\` | object | no | Error handling: \`{ "strategy": "${FLOW_SCHEMA.errorStrategies.join(" | ")}", "retries": 3, "retryDelayMs": 1000, "backoff": "fixed \\| exponential \\| exponential-jitter", "maxDelayMs": 30000 }\` |`);
1618
1687
  sections.push(`
1619
1688
  ## Step Types
1620
1689
 
@@ -11,7 +11,7 @@ import {
11
11
  saveFlow,
12
12
  summarizeFlowInputs,
13
13
  walkSteps
14
- } from "./chunk-KZOFPEHD.js";
14
+ } from "./chunk-Z45IBT5P.js";
15
15
  export {
16
16
  FlowRunner,
17
17
  collectStepTypes,