@withone/cli 1.32.1 → 1.33.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.
Files changed (2) hide show
  1. package/dist/index.js +131 -40
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ import {
23
23
 
24
24
  // src/index.ts
25
25
  import { createRequire as createRequire2 } from "module";
26
+ import path16 from "path";
26
27
  import { Command } from "commander";
27
28
 
28
29
  // src/commands/init.ts
@@ -73,6 +74,19 @@ function resolveConfig() {
73
74
  return { config: config2, scope: "project", path: projectPath, projectRoot, projectSlug };
74
75
  }
75
76
  }
77
+ const root = path.parse(process.cwd()).root;
78
+ let dir = path.resolve(process.cwd());
79
+ while (dir !== root) {
80
+ dir = path.dirname(dir);
81
+ const slug = getProjectSlug(dir);
82
+ const configPath = path.join(PROJECTS_DIR, slug, "config.json");
83
+ if (fs.existsSync(configPath)) {
84
+ const config2 = readConfigFile(configPath);
85
+ if (config2) {
86
+ return { config: config2, scope: "project", path: configPath, projectRoot: dir, projectSlug: slug };
87
+ }
88
+ }
89
+ }
76
90
  if (fs.existsSync(CONFIG_FILE)) {
77
91
  const config2 = readConfigFile(CONFIG_FILE);
78
92
  if (config2) {
@@ -2882,32 +2896,32 @@ function validateStepsArray(steps, pathPrefix, errors) {
2882
2896
  const validTypes = FLOW_SCHEMA.stepTypes.map((st) => st.type);
2883
2897
  for (let i = 0; i < steps.length; i++) {
2884
2898
  const step = steps[i];
2885
- const path16 = `${pathPrefix}[${i}]`;
2899
+ const path17 = `${pathPrefix}[${i}]`;
2886
2900
  if (!step || typeof step !== "object" || Array.isArray(step)) {
2887
- errors.push({ path: path16, message: "Step must be an object" });
2901
+ errors.push({ path: path17, message: "Step must be an object" });
2888
2902
  continue;
2889
2903
  }
2890
2904
  const s = step;
2891
2905
  if (!s.id || typeof s.id !== "string") {
2892
- errors.push({ path: `${path16}.id`, message: 'Step must have a string "id"' });
2906
+ errors.push({ path: `${path17}.id`, message: 'Step must have a string "id"' });
2893
2907
  }
2894
2908
  if (!s.name || typeof s.name !== "string") {
2895
- errors.push({ path: `${path16}.name`, message: 'Step must have a string "name"' });
2909
+ errors.push({ path: `${path17}.name`, message: 'Step must have a string "name"' });
2896
2910
  }
2897
2911
  if (!s.type || !validTypes.includes(s.type)) {
2898
- errors.push({ path: `${path16}.type`, message: `Step type must be one of: ${validTypes.join(", ")}` });
2912
+ errors.push({ path: `${path17}.type`, message: `Step type must be one of: ${validTypes.join(", ")}` });
2899
2913
  continue;
2900
2914
  }
2901
2915
  if (s.requires !== void 0) {
2902
2916
  if (!Array.isArray(s.requires)) {
2903
- errors.push({ path: `${path16}.requires`, message: '"requires" must be an array of selector strings (e.g. ["$.steps.foo.output.bar"])' });
2917
+ errors.push({ path: `${path17}.requires`, message: '"requires" must be an array of selector strings (e.g. ["$.steps.foo.output.bar"])' });
2904
2918
  } else {
2905
2919
  for (let r = 0; r < s.requires.length; r++) {
2906
2920
  const sel = s.requires[r];
2907
2921
  if (typeof sel !== "string") {
2908
- errors.push({ path: `${path16}.requires[${r}]`, message: '"requires" entry must be a selector string' });
2922
+ errors.push({ path: `${path17}.requires[${r}]`, message: '"requires" entry must be a selector string' });
2909
2923
  } else if (!sel.startsWith("$.")) {
2910
- errors.push({ path: `${path16}.requires[${r}]`, message: `"requires" entry "${sel}" must be a selector starting with "$." (e.g. "$.steps.foo.output.bar")` });
2924
+ errors.push({ path: `${path17}.requires[${r}]`, message: `"requires" entry "${sel}" must be a selector starting with "$." (e.g. "$.steps.foo.output.bar")` });
2911
2925
  }
2912
2926
  }
2913
2927
  }
@@ -2915,7 +2929,7 @@ function validateStepsArray(steps, pathPrefix, errors) {
2915
2929
  if (s.onError && typeof s.onError === "object") {
2916
2930
  const oe = s.onError;
2917
2931
  if (!FLOW_SCHEMA.errorStrategies.includes(oe.strategy)) {
2918
- errors.push({ path: `${path16}.onError.strategy`, message: `Error strategy must be one of: ${FLOW_SCHEMA.errorStrategies.join(", ")}` });
2932
+ errors.push({ path: `${path17}.onError.strategy`, message: `Error strategy must be one of: ${FLOW_SCHEMA.errorStrategies.join(", ")}` });
2919
2933
  }
2920
2934
  }
2921
2935
  const descriptor = getStepTypeDescriptor(s.type);
@@ -2925,14 +2939,14 @@ function validateStepsArray(steps, pathPrefix, errors) {
2925
2939
  if (!configObj || typeof configObj !== "object") {
2926
2940
  const hint = detectFlatConfigHint(s, descriptor);
2927
2941
  errors.push({
2928
- path: `${path16}.${configKey}`,
2942
+ path: `${path17}.${configKey}`,
2929
2943
  message: `${capitalize(descriptor.type)} step must have a "${configKey}" config object${hint}`
2930
2944
  });
2931
2945
  continue;
2932
2946
  }
2933
2947
  const config2 = configObj;
2934
2948
  for (const [fieldName, fd] of Object.entries(descriptor.fields)) {
2935
- const fieldPath = `${path16}.${configKey}.${fieldName}`;
2949
+ const fieldPath = `${path17}.${configKey}.${fieldName}`;
2936
2950
  const value = config2[fieldName];
2937
2951
  if (fd.required && (value === void 0 || value === null || value === "")) {
2938
2952
  errors.push({ path: fieldPath, message: `${capitalize(descriptor.type)} must have ${fd.type === "string" ? "a string" : fd.type === "array" ? "a" : "a"} "${fieldName}"` });
@@ -2968,24 +2982,24 @@ function validateStepsArray(steps, pathPrefix, errors) {
2968
2982
  const hasSource = typeof config2.source === "string" && config2.source.length > 0;
2969
2983
  const hasModule = typeof config2.module === "string" && config2.module.length > 0;
2970
2984
  if (!hasSource && !hasModule) {
2971
- errors.push({ path: `${path16}.${configKey}`, message: 'Code step must define either "source" (inline JS) or "module" (path to .mjs file)' });
2985
+ errors.push({ path: `${path17}.${configKey}`, message: 'Code step must define either "source" (inline JS) or "module" (path to .mjs file)' });
2972
2986
  } else if (hasSource && hasModule) {
2973
- errors.push({ path: `${path16}.${configKey}`, message: 'Code step cannot define both "source" and "module" \u2014 pick one' });
2987
+ errors.push({ path: `${path17}.${configKey}`, message: 'Code step cannot define both "source" and "module" \u2014 pick one' });
2974
2988
  }
2975
2989
  if (hasModule) {
2976
2990
  const m = config2.module;
2977
2991
  if (m.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(m)) {
2978
- errors.push({ path: `${path16}.${configKey}.module`, message: "Code module path must be relative to the flow folder (no absolute paths)" });
2992
+ errors.push({ path: `${path17}.${configKey}.module`, message: "Code module path must be relative to the flow folder (no absolute paths)" });
2979
2993
  } else if (m.split(/[\\/]/).includes("..")) {
2980
- errors.push({ path: `${path16}.${configKey}.module`, message: 'Code module path must not escape the flow folder ("..")' });
2994
+ errors.push({ path: `${path17}.${configKey}.module`, message: 'Code module path must not escape the flow folder ("..")' });
2981
2995
  } else if (!m.endsWith(".mjs")) {
2982
- errors.push({ path: `${path16}.${configKey}.module`, message: "Code module must be a .mjs file" });
2996
+ errors.push({ path: `${path17}.${configKey}.module`, message: "Code module must be a .mjs file" });
2983
2997
  }
2984
2998
  }
2985
2999
  if (hasSource) {
2986
3000
  const syntaxError = checkCodeSourceSyntax(config2.source);
2987
3001
  if (syntaxError) {
2988
- errors.push({ path: `${path16}.${configKey}.source`, message: `Syntax error in code step: ${syntaxError}` });
3002
+ errors.push({ path: `${path17}.${configKey}.source`, message: `Syntax error in code step: ${syntaxError}` });
2989
3003
  }
2990
3004
  }
2991
3005
  }
@@ -3020,16 +3034,16 @@ function validateStepIds(flow2) {
3020
3034
  function collectIds(steps, pathPrefix) {
3021
3035
  for (let i = 0; i < steps.length; i++) {
3022
3036
  const step = steps[i];
3023
- const path16 = `${pathPrefix}[${i}]`;
3037
+ const path17 = `${pathPrefix}[${i}]`;
3024
3038
  if (seen.has(step.id)) {
3025
- errors.push({ path: `${path16}.id`, message: `Duplicate step ID: "${step.id}"` });
3039
+ errors.push({ path: `${path17}.id`, message: `Duplicate step ID: "${step.id}"` });
3026
3040
  } else {
3027
3041
  seen.add(step.id);
3028
3042
  }
3029
3043
  for (const { configKey, fieldName } of nestedKeys) {
3030
3044
  const config2 = step[configKey];
3031
3045
  if (config2 && Array.isArray(config2[fieldName])) {
3032
- collectIds(config2[fieldName], `${path16}.${configKey}.${fieldName}`);
3046
+ collectIds(config2[fieldName], `${path17}.${configKey}.${fieldName}`);
3033
3047
  }
3034
3048
  }
3035
3049
  }
@@ -3077,7 +3091,7 @@ function validateSelectorReferences(flow2) {
3077
3091
  }
3078
3092
  return selectors;
3079
3093
  }
3080
- function checkSelectors(selectors, path16, precedingStepIds) {
3094
+ function checkSelectors(selectors, path17, precedingStepIds) {
3081
3095
  for (const selector of selectors) {
3082
3096
  const parts = selector.split(".");
3083
3097
  if (parts.length < 3) continue;
@@ -3085,15 +3099,15 @@ function validateSelectorReferences(flow2) {
3085
3099
  if (root === "input") {
3086
3100
  const inputName = parts[2];
3087
3101
  if (!inputNames.has(inputName)) {
3088
- errors.push({ path: path16, message: `Selector "${selector}" references undefined input "${inputName}"` });
3102
+ errors.push({ path: path17, message: `Selector "${selector}" references undefined input "${inputName}"` });
3089
3103
  }
3090
3104
  } else if (root === "steps") {
3091
3105
  const stepId = parts[2].replace(/[\[\]]/g, "").split(/[\[\]]/)[0];
3092
3106
  if (!allStepIds.has(stepId)) {
3093
- errors.push({ path: path16, message: `Selector "${selector}" references undefined step "${stepId}"` });
3107
+ errors.push({ path: path17, message: `Selector "${selector}" references undefined step "${stepId}"` });
3094
3108
  } else if (precedingStepIds && !precedingStepIds.has(stepId)) {
3095
3109
  errors.push({
3096
- path: path16,
3110
+ path: path17,
3097
3111
  message: `Selector "${selector}" references step "${stepId}" which is declared after the current step. Steps execute in declaration order, so this will always resolve to undefined at runtime \u2014 move the dependency earlier in the steps array.`
3098
3112
  });
3099
3113
  }
@@ -3101,20 +3115,20 @@ function validateSelectorReferences(flow2) {
3101
3115
  }
3102
3116
  }
3103
3117
  const EXPRESSION_FIELDS = /* @__PURE__ */ new Set(["condition.expression", "while.condition"]);
3104
- function checkOperatorsInSelectorField(value, path16) {
3118
+ function checkOperatorsInSelectorField(value, path17) {
3105
3119
  if (typeof value === "string" && value.startsWith("$.")) {
3106
3120
  if (value.includes("||")) {
3107
- errors.push({ path: path16, message: `Selector "${value}" contains unsupported operator "||". Selectors in data fields use dot-path resolution, not JS evaluation. Use the "default" field on the input definition instead, or use a "code" step for complex expressions.` });
3121
+ errors.push({ path: path17, message: `Selector "${value}" contains unsupported operator "||". Selectors in data fields use dot-path resolution, not JS evaluation. Use the "default" field on the input definition instead, or use a "code" step for complex expressions.` });
3108
3122
  } else if (value.includes("&&")) {
3109
- errors.push({ path: path16, message: `Selector "${value}" contains unsupported operator "&&". Selectors in data fields use dot-path resolution, not JS evaluation. Use a "condition" step or "code" step for complex expressions.` });
3123
+ errors.push({ path: path17, message: `Selector "${value}" contains unsupported operator "&&". Selectors in data fields use dot-path resolution, not JS evaluation. Use a "condition" step or "code" step for complex expressions.` });
3110
3124
  }
3111
3125
  } else if (value && typeof value === "object" && !Array.isArray(value)) {
3112
3126
  for (const [k, v] of Object.entries(value)) {
3113
- checkOperatorsInSelectorField(v, `${path16}.${k}`);
3127
+ checkOperatorsInSelectorField(v, `${path17}.${k}`);
3114
3128
  }
3115
3129
  } else if (Array.isArray(value)) {
3116
3130
  for (let i = 0; i < value.length; i++) {
3117
- checkOperatorsInSelectorField(value[i], `${path16}[${i}]`);
3131
+ checkOperatorsInSelectorField(value[i], `${path17}[${i}]`);
3118
3132
  }
3119
3133
  }
3120
3134
  }
@@ -3182,10 +3196,10 @@ var VALID_OUTPUT_SCHEMA_TYPES = /* @__PURE__ */ new Set(["string", "number", "bo
3182
3196
  function isOutputSchemaObject(v) {
3183
3197
  return !!v && typeof v === "object" && !Array.isArray(v);
3184
3198
  }
3185
- function walkOutputSchema(schema, path16) {
3199
+ function walkOutputSchema(schema, path17) {
3186
3200
  let current = schema;
3187
- for (let i = 0; i < path16.length; i++) {
3188
- const seg = path16[i];
3201
+ for (let i = 0; i < path17.length; i++) {
3202
+ const seg = path17[i];
3189
3203
  if (typeof current === "string") {
3190
3204
  return current === "unknown" || current === "object" || current === "array" ? "opaque" : "opaque";
3191
3205
  }
@@ -4954,8 +4968,8 @@ function sleep(ms) {
4954
4968
  return new Promise((resolve) => setTimeout(resolve, ms));
4955
4969
  }
4956
4970
  function interpolate(template, record) {
4957
- return template.replace(/\{?\{(\w+(?:\.\w+)*)\}\}?/g, (_, path16) => {
4958
- const parts = path16.split(".");
4971
+ return template.replace(/\{?\{(\w+(?:\.\w+)*)\}\}?/g, (_, path17) => {
4972
+ const parts = path17.split(".");
4959
4973
  let value = record;
4960
4974
  for (const part of parts) {
4961
4975
  if (typeof value !== "object" || value === null) return "";
@@ -4983,8 +4997,8 @@ function deepMerge(target, source) {
4983
4997
  }
4984
4998
  return result;
4985
4999
  }
4986
- function getByDotPath2(obj, path16) {
4987
- const parts = path16.split(".");
5000
+ function getByDotPath2(obj, path17) {
5001
+ const parts = path17.split(".");
4988
5002
  let current = obj;
4989
5003
  for (const part of parts) {
4990
5004
  if (current === null || current === void 0 || typeof current !== "object") return void 0;
@@ -4993,8 +5007,8 @@ function getByDotPath2(obj, path16) {
4993
5007
  return current;
4994
5008
  }
4995
5009
  function stripExcludedFields(obj, paths) {
4996
- for (const path16 of paths) {
4997
- stripOnePath(obj, path16.replace(/\[\]/g, ".*").split("."));
5010
+ for (const path17 of paths) {
5011
+ stripOnePath(obj, path17.replace(/\[\]/g, ".*").split("."));
4998
5012
  }
4999
5013
  }
5000
5014
  function stripOnePath(obj, parts) {
@@ -5300,8 +5314,8 @@ function sleep2(ms) {
5300
5314
  return new Promise((resolve) => setTimeout(resolve, ms));
5301
5315
  }
5302
5316
  function stripFields(record, paths) {
5303
- for (const path16 of paths) {
5304
- stripOnePath2(record, path16.split("."));
5317
+ for (const path17 of paths) {
5318
+ stripOnePath2(record, path17.split("."));
5305
5319
  }
5306
5320
  }
5307
5321
  function stripOnePath2(obj, parts) {
@@ -8828,6 +8842,83 @@ configSkills.command("status").description("Show installed skill version and whe
8828
8842
  console.log(` current: ${status.currentVersion}`);
8829
8843
  console.log(` path: ${status.canonicalPath}`);
8830
8844
  });
8845
+ config.command("reset").description("Remove the project config for the current directory (falls back to global)").option("--global", "Remove the global config instead").action(async (opts) => {
8846
+ const resolved = resolveConfig();
8847
+ if (opts.global) {
8848
+ const globalPath = getGlobalConfigPath();
8849
+ if (!globalConfigExists()) {
8850
+ if (isAgentMode()) {
8851
+ json({ deleted: false, reason: "No global config found" });
8852
+ } else {
8853
+ console.log("No global config found.");
8854
+ }
8855
+ return;
8856
+ }
8857
+ if (!isAgentMode()) {
8858
+ const p8 = await import("@clack/prompts");
8859
+ const confirmed = await p8.confirm({
8860
+ message: "Delete the global config? This removes your API key for all projects without a project config.",
8861
+ initialValue: false
8862
+ });
8863
+ if (p8.isCancel(confirmed) || !confirmed) {
8864
+ console.log("Cancelled.");
8865
+ return;
8866
+ }
8867
+ }
8868
+ const fs17 = await import("fs");
8869
+ fs17.unlinkSync(globalPath);
8870
+ if (isAgentMode()) {
8871
+ json({ deleted: true, scope: "global" });
8872
+ } else {
8873
+ console.log("Global config removed.");
8874
+ }
8875
+ return;
8876
+ }
8877
+ if (resolved.scope !== "project") {
8878
+ if (isAgentMode()) {
8879
+ json({ deleted: false, reason: "No project config found for this directory" });
8880
+ } else {
8881
+ console.log("No project config found for this directory.");
8882
+ console.log(`Currently using: ${resolved.scope ?? "none"}`);
8883
+ }
8884
+ return;
8885
+ }
8886
+ const fs16 = await import("fs");
8887
+ const configContent = fs16.readFileSync(resolved.path, "utf-8");
8888
+ fs16.unlinkSync(resolved.path);
8889
+ const next = resolveConfig();
8890
+ fs16.mkdirSync(path16.dirname(resolved.path), { recursive: true });
8891
+ fs16.writeFileSync(resolved.path, configContent);
8892
+ let fallbackLabel;
8893
+ if (next.scope === "project") {
8894
+ fallbackLabel = `parent project config (${path16.basename(next.projectRoot)})`;
8895
+ } else if (next.scope === "global") {
8896
+ fallbackLabel = "global config";
8897
+ } else {
8898
+ fallbackLabel = "no config";
8899
+ }
8900
+ if (!isAgentMode()) {
8901
+ const p8 = await import("@clack/prompts");
8902
+ const confirmed = await p8.confirm({
8903
+ message: `Delete project config for ${path16.basename(resolved.projectRoot)}? Will fall back to ${fallbackLabel}.`,
8904
+ initialValue: false
8905
+ });
8906
+ if (p8.isCancel(confirmed) || !confirmed) {
8907
+ console.log("Cancelled.");
8908
+ return;
8909
+ }
8910
+ }
8911
+ fs16.unlinkSync(resolved.path);
8912
+ try {
8913
+ fs16.rmdirSync(path16.dirname(resolved.path));
8914
+ } catch {
8915
+ }
8916
+ if (isAgentMode()) {
8917
+ json({ deleted: true, scope: "project", projectRoot: resolved.projectRoot, fallback: next.scope });
8918
+ } else {
8919
+ console.log(`Project config removed. Now using ${fallbackLabel}.`);
8920
+ }
8921
+ });
8831
8922
  var connection = program.command("connection").description("Manage connections");
8832
8923
  connection.command("add [platform]").alias("a").description("Add a new connection").action(async (platform) => {
8833
8924
  await connectionAddCommand(platform);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withone/cli",
3
- "version": "1.32.1",
3
+ "version": "1.33.0",
4
4
  "description": "CLI for managing One",
5
5
  "type": "module",
6
6
  "files": [