@runtypelabs/cli 0.2.0 → 0.2.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
@@ -72,6 +72,13 @@ runtype marathon "Code Builder" -m "Refactor the auth module to use JWT tokens"
72
72
  runtype marathon agent_abc123 -m "Write integration tests for the API" \
73
73
  --max-sessions 10 --max-cost 2.50 --name "api-tests"
74
74
 
75
+ # Override the agent's configured model
76
+ runtype marathon "Code Builder" -m "Build a calculator" --model claude-sonnet-4-5
77
+
78
+ # Enable sandboxed code execution tooling for the task (QuickJS or Daytona)
79
+ runtype marathon "Code Builder" -m "Compute totals from this dataset" --sandbox quickjs
80
+ runtype marathon "Code Builder" -m "Generate a script and run it" --sandbox daytona
81
+
75
82
  # Resume an interrupted task (picks up where it left off)
76
83
  runtype marathon "Code Builder" -m "Refactor the auth module to use JWT tokens" \
77
84
  --resume --name "auth-refactor" --debug
package/dist/index.js CHANGED
@@ -2812,6 +2812,205 @@ function saveState(filePath, state) {
2812
2812
  fs3.mkdirSync(dir, { recursive: true });
2813
2813
  fs3.writeFileSync(filePath, JSON.stringify(state, null, 2));
2814
2814
  }
2815
+ function isRecord(value) {
2816
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2817
+ }
2818
+ function parseSandboxProvider(value) {
2819
+ if (!value) return void 0;
2820
+ const normalized = value.trim().toLowerCase();
2821
+ if (normalized === "quickjs" || normalized === "daytona") return normalized;
2822
+ return void 0;
2823
+ }
2824
+ function parseSandboxLanguage(provider, value) {
2825
+ if (provider === "quickjs") return "javascript";
2826
+ if (typeof value === "string") {
2827
+ const normalized = value.trim().toLowerCase();
2828
+ if (normalized === "javascript" || normalized === "typescript" || normalized === "python") {
2829
+ return normalized;
2830
+ }
2831
+ }
2832
+ return "javascript";
2833
+ }
2834
+ function parseSandboxTimeout(value, provider) {
2835
+ const fallback = provider === "quickjs" ? 5e3 : 3e4;
2836
+ let numericValue;
2837
+ if (typeof value === "number" && Number.isFinite(value)) {
2838
+ numericValue = value;
2839
+ } else if (typeof value === "string" && value.trim() !== "") {
2840
+ const parsed = Number(value);
2841
+ if (Number.isFinite(parsed)) {
2842
+ numericValue = parsed;
2843
+ }
2844
+ }
2845
+ if (numericValue === void 0) return fallback;
2846
+ return Math.max(1, Math.min(3e4, Math.floor(numericValue)));
2847
+ }
2848
+ function parseDaytonaExecutionResult(value) {
2849
+ if (typeof value !== "string") return value;
2850
+ const trimmed = value.trim();
2851
+ if (!trimmed) return "";
2852
+ try {
2853
+ return JSON.parse(trimmed);
2854
+ } catch {
2855
+ const lines = trimmed.split("\n").map((line) => line.trim()).filter(Boolean);
2856
+ const lastLine = lines[lines.length - 1];
2857
+ if (!lastLine) return value;
2858
+ try {
2859
+ return JSON.parse(lastLine);
2860
+ } catch {
2861
+ return value;
2862
+ }
2863
+ }
2864
+ }
2865
+ function createSandboxInstructions(provider) {
2866
+ if (provider === "quickjs") {
2867
+ return [
2868
+ "--- Sandbox Tooling (QuickJS) ---",
2869
+ "You can execute JavaScript snippets with the local tool `run_sandbox_code`.",
2870
+ "Call shape:",
2871
+ '{ "code": "...", "parameters": { ... }, "timeoutMs": 5000 }',
2872
+ "QuickJS rules:",
2873
+ "1. Use JavaScript only (no TypeScript or Python).",
2874
+ "2. Inputs are passed in the `parameters` object (for example: `const x = parameters.x`).",
2875
+ "3. The snippet is wrapped in a function. Use top-level `return ...` to produce the result.",
2876
+ "4. Return JSON-serializable values (object, array, string, number, boolean, null).",
2877
+ "5. No Node/Bun/Deno APIs, imports/require, process, filesystem, or network calls.",
2878
+ "Example:",
2879
+ "const nums = parameters.nums || []",
2880
+ "const sum = nums.reduce((acc, n) => acc + n, 0)",
2881
+ "return { sum, count: nums.length }"
2882
+ ].join("\n");
2883
+ }
2884
+ return [
2885
+ "--- Sandbox Tooling (Daytona) ---",
2886
+ "You can execute code snippets with the local tool `run_sandbox_code`.",
2887
+ "Call shape:",
2888
+ '{ "code": "...", "parameters": { ... }, "language": "javascript|typescript|python", "timeoutMs": 30000 }',
2889
+ "Daytona rules:",
2890
+ "1. Choose one language: javascript, typescript, or python.",
2891
+ "2. Parameters are injected as top-level variables before your code (do not rely on `parameters`).",
2892
+ "3. Your snippet runs as a full program. Do not use top-level `return`.",
2893
+ "4. For structured results, write a single JSON value to stdout as the final output.",
2894
+ "5. JS/TS: `console.log(JSON.stringify({ ... }))`; Python: `import json` then `print(json.dumps({ ... }))`.",
2895
+ "6. Avoid extra logs before the final JSON line, or parsing may fail."
2896
+ ].join("\n");
2897
+ }
2898
+ function buildResumeCommand(agent, message, options, parsedSandbox) {
2899
+ const nameFlag = options.name ? ` --name ${options.name}` : "";
2900
+ const sandboxFlag = parsedSandbox ? ` --sandbox ${parsedSandbox}` : "";
2901
+ return `runtype marathon ${agent} -m "${message}" --resume${nameFlag}${sandboxFlag}`;
2902
+ }
2903
+ function createSandboxLocalTool(client, provider, debugMode) {
2904
+ return {
2905
+ description: provider === "quickjs" ? "Execute JavaScript code in QuickJS sandbox. Inputs are passed via parameters object." : "Execute JavaScript/TypeScript/Python code in Daytona sandbox. Inputs are injected as top-level variables.",
2906
+ parametersSchema: {
2907
+ type: "object",
2908
+ properties: {
2909
+ code: { type: "string", description: "Code snippet to execute" },
2910
+ parameters: {
2911
+ type: "object",
2912
+ description: "Input parameters for the code (JSON object)"
2913
+ },
2914
+ language: {
2915
+ type: "string",
2916
+ enum: provider === "quickjs" ? ["javascript"] : ["javascript", "typescript", "python"],
2917
+ description: provider === "quickjs" ? "QuickJS only accepts javascript" : "Daytona code language"
2918
+ },
2919
+ timeoutMs: { type: "number", description: "Execution timeout in ms (max 30000)" }
2920
+ },
2921
+ required: ["code"]
2922
+ },
2923
+ execute: async (args) => {
2924
+ const rawCode = args.code;
2925
+ const code = typeof rawCode === "string" ? rawCode : "";
2926
+ if (!code.trim()) {
2927
+ return { success: false, error: "code is required" };
2928
+ }
2929
+ const language = parseSandboxLanguage(provider, args.language);
2930
+ const timeout = parseSandboxTimeout(args.timeoutMs, provider);
2931
+ const parameters = isRecord(args.parameters) ? args.parameters : {};
2932
+ const gateDecision = (0, import_sdk5.evaluateGeneratedRuntimeToolProposal)(
2933
+ {
2934
+ name: "run_sandbox_code",
2935
+ description: `Execute code in ${provider}`,
2936
+ toolType: "custom",
2937
+ parametersSchema: { type: "object" },
2938
+ config: {
2939
+ code,
2940
+ timeout,
2941
+ sandboxProvider: provider,
2942
+ language
2943
+ }
2944
+ },
2945
+ {
2946
+ allowedToolTypes: ["custom"],
2947
+ allowedSandboxProviders: [provider],
2948
+ allowedLanguages: provider === "quickjs" ? ["javascript"] : ["javascript", "typescript", "python"],
2949
+ maxTimeoutMs: 3e4,
2950
+ maxCodeLength: 12e3
2951
+ }
2952
+ );
2953
+ if (!gateDecision.approved) {
2954
+ return {
2955
+ success: false,
2956
+ error: gateDecision.reason,
2957
+ violations: gateDecision.violations
2958
+ };
2959
+ }
2960
+ const tempToolName = `marathon_${provider}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
2961
+ let tempToolId;
2962
+ try {
2963
+ const createRequest = {
2964
+ name: tempToolName,
2965
+ description: `Ephemeral ${provider} sandbox execution`,
2966
+ toolType: "custom",
2967
+ parametersSchema: { type: "object", properties: {} },
2968
+ config: {
2969
+ code,
2970
+ timeout,
2971
+ allowedApis: [],
2972
+ sandboxProvider: provider,
2973
+ language
2974
+ }
2975
+ };
2976
+ const created = await client.tools.create(createRequest);
2977
+ tempToolId = created.id;
2978
+ const executeRequest = {
2979
+ toolId: created.id,
2980
+ parameters
2981
+ };
2982
+ const execution = await client.tools.execute(created.id, executeRequest);
2983
+ const parsedResult = provider === "daytona" ? parseDaytonaExecutionResult(execution.result) : execution.result;
2984
+ return {
2985
+ success: execution.status === "success",
2986
+ sandboxProvider: provider,
2987
+ language,
2988
+ result: parsedResult,
2989
+ executionId: execution.executionId,
2990
+ ...execution.errorMessage ? { error: execution.errorMessage } : {}
2991
+ };
2992
+ } catch (error) {
2993
+ const message = error instanceof Error ? error.message : String(error);
2994
+ if (debugMode) {
2995
+ console.log(import_chalk15.default.gray(` [sandbox:${provider}] execution error: ${message}`));
2996
+ }
2997
+ return {
2998
+ success: false,
2999
+ sandboxProvider: provider,
3000
+ language,
3001
+ error: message
3002
+ };
3003
+ } finally {
3004
+ if (tempToolId) {
3005
+ try {
3006
+ await client.tools.delete(tempToolId);
3007
+ } catch {
3008
+ }
3009
+ }
3010
+ }
3011
+ }
3012
+ };
3013
+ }
2815
3014
  async function taskAction(agent, options) {
2816
3015
  const apiKey = await ensureAuth();
2817
3016
  if (!apiKey) return;
@@ -2819,6 +3018,11 @@ async function taskAction(agent, options) {
2819
3018
  apiKey,
2820
3019
  baseUrl: getApiUrl()
2821
3020
  });
3021
+ const parsedSandbox = parseSandboxProvider(options.sandbox);
3022
+ if (options.sandbox && !parsedSandbox) {
3023
+ console.error(import_chalk15.default.red(`Invalid --sandbox value "${options.sandbox}". Use: quickjs or daytona`));
3024
+ process.exit(1);
3025
+ }
2822
3026
  let agentId = agent;
2823
3027
  if (!agent.startsWith("agent_")) {
2824
3028
  const spinner = (0, import_ora10.default)("Looking up agent by name...").start();
@@ -2831,13 +3035,21 @@ async function taskAction(agent, options) {
2831
3035
  agentId = found.id;
2832
3036
  spinner.succeed(`Found agent: ${import_chalk15.default.green(agentId)}`);
2833
3037
  } else {
2834
- spinner.fail(`No agent found with name "${agent}"`);
2835
- console.log(import_chalk15.default.gray(` Create one with: runtype agents create -n "${agent}"`));
2836
- process.exit(1);
3038
+ spinner.text = `Creating agent "${agent}"...`;
3039
+ try {
3040
+ const created = await client.agents.create({ name: agent });
3041
+ agentId = created.id;
3042
+ spinner.succeed(`Created agent: ${import_chalk15.default.green(agentId)}`);
3043
+ } catch (createErr) {
3044
+ spinner.fail(`Failed to create agent "${agent}"`);
3045
+ const errMsg = createErr instanceof Error ? createErr.message : String(createErr);
3046
+ console.error(import_chalk15.default.red(errMsg));
3047
+ process.exit(1);
3048
+ }
2837
3049
  }
2838
3050
  } catch (error) {
2839
- spinner.fail("Failed to look up agent");
2840
- const errMsg = error instanceof Error ? error.message : "Unknown error";
3051
+ spinner.fail("Failed to list agents");
3052
+ const errMsg = error instanceof Error ? error.message : String(error);
2841
3053
  console.error(import_chalk15.default.red(errMsg));
2842
3054
  process.exit(1);
2843
3055
  }
@@ -2881,7 +3093,7 @@ async function taskAction(agent, options) {
2881
3093
  }
2882
3094
  console.log(
2883
3095
  import_chalk15.default.gray(
2884
- ` Resume with: runtype marathon ${agent} -m "${options.message}" --resume${options.name ? ` --name ${options.name}` : ""}`
3096
+ ` Resume with: ${buildResumeCommand(agent, options.message, options, parsedSandbox)}`
2885
3097
  )
2886
3098
  );
2887
3099
  process.exit(0);
@@ -2889,32 +3101,63 @@ async function taskAction(agent, options) {
2889
3101
  process.on("SIGINT", onSigint);
2890
3102
  const remainingSessions = maxSessions - priorSessionCount;
2891
3103
  const remainingCost = maxCost ? maxCost - priorCost : void 0;
3104
+ const sandboxPrompt = parsedSandbox ? createSandboxInstructions(parsedSandbox) : "";
3105
+ const taskMessage = sandboxPrompt ? `${options.message}
3106
+
3107
+ ${sandboxPrompt}` : options.message;
2892
3108
  console.log(import_chalk15.default.cyan(`
2893
3109
  Running task "${taskName}" on ${agentId}`));
2894
3110
  console.log(
2895
3111
  import_chalk15.default.gray(
2896
- ` Sessions: ${priorSessionCount > 0 ? `${priorSessionCount} done, ` : ""}${remainingSessions} remaining${maxCost ? ` | Budget: $${maxCost.toFixed(2)}` : ""}`
3112
+ ` Sessions: ${priorSessionCount > 0 ? `${priorSessionCount} done, ` : ""}${remainingSessions} remaining${maxCost ? ` | Budget: $${maxCost.toFixed(2)}` : ""}${options.model ? ` | Model: ${options.model}` : ""}${parsedSandbox ? ` | Sandbox: ${parsedSandbox}` : ""}`
2897
3113
  )
2898
3114
  );
2899
3115
  console.log(import_chalk15.default.gray(` State: ${filePath}
2900
3116
  `));
2901
3117
  try {
2902
3118
  let currentSession = priorSessionCount;
3119
+ let thinkingSpinner = null;
3120
+ let thinkingChars = 0;
2903
3121
  const streamCallbacks = {
2904
3122
  onAgentStart: () => {
2905
3123
  currentSession++;
2906
3124
  console.log(import_chalk15.default.cyan(`
2907
3125
  \u2500\u2500 Session ${currentSession} \u2500\u2500
2908
3126
  `));
3127
+ thinkingChars = 0;
3128
+ thinkingSpinner = (0, import_ora10.default)({ text: import_chalk15.default.dim("Thinking..."), color: "gray" }).start();
2909
3129
  },
2910
3130
  onTurnDelta: (event) => {
2911
3131
  if (event.contentType === "text") {
3132
+ if (thinkingSpinner) {
3133
+ thinkingSpinner.stop();
3134
+ thinkingSpinner = null;
3135
+ }
2912
3136
  process.stdout.write(event.delta);
2913
- } else if (event.contentType === "thinking" && options.debug) {
2914
- process.stdout.write(import_chalk15.default.dim(event.delta));
3137
+ } else if (event.contentType === "thinking") {
3138
+ thinkingChars += event.delta.length;
3139
+ const approxTokens = Math.round(thinkingChars / 4);
3140
+ const tokenStr = approxTokens.toLocaleString();
3141
+ if (!thinkingSpinner) {
3142
+ thinkingSpinner = (0, import_ora10.default)({
3143
+ text: import_chalk15.default.dim(`Thinking... (~${tokenStr} tokens)`),
3144
+ color: "gray"
3145
+ }).start();
3146
+ } else {
3147
+ thinkingSpinner.text = import_chalk15.default.dim(`Thinking... (~${tokenStr} tokens)`);
3148
+ }
3149
+ if (options.debug) {
3150
+ thinkingSpinner.stop();
3151
+ process.stdout.write(import_chalk15.default.dim(event.delta));
3152
+ thinkingSpinner.start();
3153
+ }
2915
3154
  }
2916
3155
  },
2917
3156
  onToolStart: (event) => {
3157
+ if (thinkingSpinner) {
3158
+ thinkingSpinner.stop();
3159
+ thinkingSpinner = null;
3160
+ }
2918
3161
  if (options.debug) {
2919
3162
  console.log(import_chalk15.default.gray(`
2920
3163
  [tool] ${event.toolName}...`));
@@ -2926,18 +3169,100 @@ Running task "${taskName}" on ${agentId}`));
2926
3169
  console.log(import_chalk15.default.gray(` [tool] ${event.toolName} \u2192 ${status}`));
2927
3170
  }
2928
3171
  },
3172
+ onAgentPaused: (event) => {
3173
+ if (thinkingSpinner) {
3174
+ thinkingSpinner.stop();
3175
+ thinkingSpinner = null;
3176
+ }
3177
+ const rawParams = event.parameters;
3178
+ const paramPreview = typeof rawParams === "string" ? `string(${rawParams.length} chars)` : rawParams && typeof rawParams === "object" ? `object(${Object.keys(rawParams).join(", ")})` : typeof rawParams;
3179
+ console.log(
3180
+ import_chalk15.default.cyan(
3181
+ `
3182
+ [local tool] ${event.toolName} called (params: ${paramPreview})`
3183
+ )
3184
+ );
3185
+ if (options.debug) {
3186
+ console.log(import_chalk15.default.gray(` executionId: ${event.executionId}`));
3187
+ console.log(import_chalk15.default.gray(` raw params: ${JSON.stringify(event.parameters).slice(0, 300)}`));
3188
+ }
3189
+ },
2929
3190
  onError: (event) => {
3191
+ if (thinkingSpinner) {
3192
+ thinkingSpinner.stop();
3193
+ thinkingSpinner = null;
3194
+ }
2930
3195
  console.error(import_chalk15.default.red(`
2931
3196
  Error: ${event.error}`));
2932
3197
  }
2933
3198
  };
3199
+ const defaultLocalTools = {
3200
+ read_file: {
3201
+ description: "Read the contents of a file at the given path",
3202
+ parametersSchema: {
3203
+ type: "object",
3204
+ properties: { path: { type: "string", description: "File path to read" } },
3205
+ required: ["path"]
3206
+ },
3207
+ execute: async (args) => {
3208
+ const filePath2 = String(args.path || "");
3209
+ if (!filePath2) return "Error: path is required";
3210
+ return fs3.readFileSync(filePath2, "utf-8");
3211
+ }
3212
+ },
3213
+ write_file: {
3214
+ description: "Write content to a file, creating directories as needed",
3215
+ parametersSchema: {
3216
+ type: "object",
3217
+ properties: {
3218
+ path: { type: "string", description: "File path to write" },
3219
+ content: { type: "string", description: "Content to write" }
3220
+ },
3221
+ required: ["path", "content"]
3222
+ },
3223
+ execute: async (args) => {
3224
+ const filePath2 = String(args.path || "");
3225
+ if (!filePath2) return "Error: path is required";
3226
+ const content = String(args.content || "");
3227
+ const dir = path4.dirname(filePath2);
3228
+ fs3.mkdirSync(dir, { recursive: true });
3229
+ fs3.writeFileSync(filePath2, content);
3230
+ return "ok";
3231
+ }
3232
+ },
3233
+ list_directory: {
3234
+ description: "List files and directories at the given path",
3235
+ parametersSchema: {
3236
+ type: "object",
3237
+ properties: { path: { type: "string", description: 'Directory path (defaults to ".")' } }
3238
+ },
3239
+ execute: async (args) => {
3240
+ const dirPath = String(args.path || ".");
3241
+ return fs3.readdirSync(dirPath).join("\n");
3242
+ }
3243
+ }
3244
+ };
3245
+ const enabledLocalTools = {};
3246
+ if (!options.noLocalTools) {
3247
+ Object.assign(enabledLocalTools, defaultLocalTools);
3248
+ }
3249
+ if (parsedSandbox) {
3250
+ enabledLocalTools.run_sandbox_code = createSandboxLocalTool(
3251
+ client,
3252
+ parsedSandbox,
3253
+ options.debug
3254
+ );
3255
+ }
3256
+ const localTools = Object.keys(enabledLocalTools).length > 0 ? enabledLocalTools : void 0;
2934
3257
  const result = await client.agents.runTask(agentId, {
2935
- message: options.message,
3258
+ message: taskMessage,
2936
3259
  maxSessions: remainingSessions,
2937
3260
  maxCost: remainingCost,
3261
+ model: options.model,
2938
3262
  debugMode: options.debug,
2939
3263
  stream: true,
2940
3264
  streamCallbacks,
3265
+ localTools,
2941
3266
  trackProgress: options.track ? taskName : void 0,
2942
3267
  onSession: (state) => {
2943
3268
  const adjustedState = {
@@ -2951,7 +3276,7 @@ Running task "${taskName}" on ${agentId}`));
2951
3276
  if (latest) {
2952
3277
  const total = adjustedState.sessionCount;
2953
3278
  const costStr = import_chalk15.default.yellow(`$${adjustedState.totalCost.toFixed(4)}`);
2954
- const reasonColor = latest.stopReason === "complete" ? import_chalk15.default.green : import_chalk15.default.gray;
3279
+ const reasonColor = latest.stopReason === "complete" ? import_chalk15.default.green : latest.stopReason === "error" ? import_chalk15.default.red : import_chalk15.default.gray;
2955
3280
  console.log(
2956
3281
  `
2957
3282
  ${import_chalk15.default.dim(`[${total}/${maxSessions}]`)} ${reasonColor(latest.stopReason)} | total: ${costStr}`
@@ -2988,7 +3313,7 @@ Running task "${taskName}" on ${agentId}`));
2988
3313
  console.log(
2989
3314
  import_chalk15.default.gray(
2990
3315
  `
2991
- Resume: runtype marathon ${agent} -m "${options.message}" --resume${options.name ? ` --name ${options.name}` : ""}`
3316
+ Resume: ${buildResumeCommand(agent, options.message, options, parsedSandbox)}`
2992
3317
  )
2993
3318
  );
2994
3319
  }
@@ -3011,7 +3336,7 @@ Task failed: ${errMsg}`));
3011
3336
  }
3012
3337
  }
3013
3338
  function applyTaskOptions(cmd) {
3014
- return cmd.argument("<agent>", "Agent ID or name").requiredOption("-m, --message <text>", "Task message for the agent").option("--max-sessions <n>", "Maximum sessions", "50").option("--max-cost <n>", "Budget in USD").option("--name <name>", "Task name (used for state file, defaults to agent name)").option("--state-dir <path>", "Directory for state files (default: .runtype/tasks/)").option("--resume", "Resume from existing local state").option("--track", "Sync progress to a Runtype record (visible in dashboard)").option("--debug", "Show debug output from each session").option("--json", "Output final result as JSON").action(taskAction);
3339
+ return cmd.argument("<agent>", "Agent ID or name").requiredOption("-m, --message <text>", "Task message for the agent").option("--max-sessions <n>", "Maximum sessions", "50").option("--max-cost <n>", "Budget in USD").option("--model <modelId>", "Model ID to use (overrides agent config)").option("--name <name>", "Task name (used for state file, defaults to agent name)").option("--state-dir <path>", "Directory for state files (default: .runtype/tasks/)").option("--resume", "Resume from existing local state").option("--track", "Sync progress to a Runtype record (visible in dashboard)").option("--debug", "Show debug output from each session").option("--json", "Output final result as JSON").option("--sandbox <provider>", "Enable sandbox code execution tool (quickjs or daytona)").option("--no-local-tools", "Disable built-in local tool execution (read_file, write_file, list_directory)").action(taskAction);
3015
3340
  }
3016
3341
  var taskCommand = applyTaskOptions(
3017
3342
  new import_commander11.Command("task").description("Run a multi-session agent task")
@@ -4095,10 +4420,12 @@ program.addCommand(flowVersionsCommand);
4095
4420
  program.addCommand(createMarathonCommand());
4096
4421
  program.exitOverride();
4097
4422
  try {
4098
- if (!process.argv.slice(2).length) {
4423
+ const userArgs = process.argv.slice(2);
4424
+ const cleanArgs = userArgs[0] === "--" ? userArgs.slice(1) : userArgs;
4425
+ if (!cleanArgs.length) {
4099
4426
  handleNoCommand();
4100
4427
  } else {
4101
- program.parse(process.argv);
4428
+ program.parse(cleanArgs, { from: "user" });
4102
4429
  }
4103
4430
  } catch (error) {
4104
4431
  const commanderError = error;