@powerformer/refly-cli 0.1.17 → 0.1.18

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/dist/bin/refly.js CHANGED
@@ -989,7 +989,7 @@ var require_command = __commonJS({
989
989
  init_cjs_shims();
990
990
  var EventEmitter = require("events").EventEmitter;
991
991
  var childProcess2 = require("child_process");
992
- var path22 = require("path");
992
+ var path23 = require("path");
993
993
  var fs27 = require("fs");
994
994
  var process8 = require("process");
995
995
  var { Argument: Argument2, humanReadableArgName } = require_argument();
@@ -1922,9 +1922,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
1922
1922
  let launchWithNode = false;
1923
1923
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1924
1924
  function findFile(baseDir, baseName) {
1925
- const localBin = path22.resolve(baseDir, baseName);
1925
+ const localBin = path23.resolve(baseDir, baseName);
1926
1926
  if (fs27.existsSync(localBin)) return localBin;
1927
- if (sourceExt.includes(path22.extname(baseName))) return void 0;
1927
+ if (sourceExt.includes(path23.extname(baseName))) return void 0;
1928
1928
  const foundExt = sourceExt.find(
1929
1929
  (ext) => fs27.existsSync(`${localBin}${ext}`)
1930
1930
  );
@@ -1942,17 +1942,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
1942
1942
  } catch (err) {
1943
1943
  resolvedScriptPath = this._scriptPath;
1944
1944
  }
1945
- executableDir = path22.resolve(
1946
- path22.dirname(resolvedScriptPath),
1945
+ executableDir = path23.resolve(
1946
+ path23.dirname(resolvedScriptPath),
1947
1947
  executableDir
1948
1948
  );
1949
1949
  }
1950
1950
  if (executableDir) {
1951
1951
  let localFile = findFile(executableDir, executableFile);
1952
1952
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
1953
- const legacyName = path22.basename(
1953
+ const legacyName = path23.basename(
1954
1954
  this._scriptPath,
1955
- path22.extname(this._scriptPath)
1955
+ path23.extname(this._scriptPath)
1956
1956
  );
1957
1957
  if (legacyName !== this._name) {
1958
1958
  localFile = findFile(
@@ -1963,7 +1963,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1963
1963
  }
1964
1964
  executableFile = localFile || executableFile;
1965
1965
  }
1966
- launchWithNode = sourceExt.includes(path22.extname(executableFile));
1966
+ launchWithNode = sourceExt.includes(path23.extname(executableFile));
1967
1967
  let proc;
1968
1968
  if (process8.platform !== "win32") {
1969
1969
  if (launchWithNode) {
@@ -2803,7 +2803,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2803
2803
  * @return {Command}
2804
2804
  */
2805
2805
  nameFromFilename(filename) {
2806
- this._name = path22.basename(filename, path22.extname(filename));
2806
+ this._name = path23.basename(filename, path23.extname(filename));
2807
2807
  return this;
2808
2808
  }
2809
2809
  /**
@@ -2817,9 +2817,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2817
2817
  * @param {string} [path]
2818
2818
  * @return {(string|null|Command)}
2819
2819
  */
2820
- executableDir(path23) {
2821
- if (path23 === void 0) return this._executableDir;
2822
- this._executableDir = path23;
2820
+ executableDir(path24) {
2821
+ if (path24 === void 0) return this._executableDir;
2822
+ this._executableDir = path24;
2823
2823
  return this;
2824
2824
  }
2825
2825
  /**
@@ -3392,11 +3392,17 @@ function initializeBaseSkillSymlink() {
3392
3392
  ensureDir(path4.join(baseDir, "rules"));
3393
3393
  return createSkillSymlink("refly");
3394
3394
  }
3395
- function createReflySkillWithSymlink(skillName, skillMdContent) {
3395
+ function createReflySkillWithSymlink(skillName, skillMdContent, options) {
3396
3396
  const skillDir = getReflyDomainSkillDir(skillName);
3397
3397
  try {
3398
3398
  ensureReflySkillsDir();
3399
3399
  if (fs4.existsSync(skillDir)) {
3400
+ if (options?.force) {
3401
+ const skillMdPath2 = path4.join(skillDir, "SKILL.md");
3402
+ fs4.writeFileSync(skillMdPath2, skillMdContent, { encoding: "utf-8", mode: 420 });
3403
+ logger.debug(`Updated SKILL.md (force): ${skillMdPath2}`);
3404
+ return createSkillSymlink(skillName);
3405
+ }
3400
3406
  return {
3401
3407
  success: false,
3402
3408
  skillName,
@@ -4881,12 +4887,14 @@ var ErrorCodes = {
4881
4887
  CONFLICT: "CONFLICT",
4882
4888
  PERMISSION_DENIED: "PERMISSION_DENIED",
4883
4889
  INVALID_INPUT: "INVALID_INPUT",
4884
- INTERNAL_ERROR: "INTERNAL_ERROR"
4890
+ INTERNAL_ERROR: "INTERNAL_ERROR",
4891
+ // Variables
4892
+ MISSING_VARIABLES: "MISSING_VARIABLES"
4885
4893
  };
4886
4894
 
4887
4895
  // src/bin/refly.ts
4888
4896
  var fs26 = __toESM(require("fs"));
4889
- var path21 = __toESM(require("path"));
4897
+ var path22 = __toESM(require("path"));
4890
4898
 
4891
4899
  // src/commands/init.ts
4892
4900
  init_cjs_shims();
@@ -5391,8 +5399,8 @@ function getErrorMap() {
5391
5399
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
5392
5400
  init_cjs_shims();
5393
5401
  var makeIssue = (params) => {
5394
- const { data, path: path22, errorMaps, issueData } = params;
5395
- const fullPath = [...path22, ...issueData.path || []];
5402
+ const { data, path: path23, errorMaps, issueData } = params;
5403
+ const fullPath = [...path23, ...issueData.path || []];
5396
5404
  const fullIssue = {
5397
5405
  ...issueData,
5398
5406
  path: fullPath
@@ -5512,11 +5520,11 @@ var errorUtil;
5512
5520
 
5513
5521
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
5514
5522
  var ParseInputLazyPath = class {
5515
- constructor(parent, value, path22, key) {
5523
+ constructor(parent, value, path23, key) {
5516
5524
  this._cachedPath = [];
5517
5525
  this.parent = parent;
5518
5526
  this.data = value;
5519
- this._path = path22;
5527
+ this._path = path23;
5520
5528
  this._key = key;
5521
5529
  }
5522
5530
  get path() {
@@ -9878,10 +9886,10 @@ var NetworkError = class extends CLIError {
9878
9886
  // src/api/client.ts
9879
9887
  init_logger();
9880
9888
  var DEFAULT_TIMEOUT = 3e4;
9881
- async function apiRequest(path22, options = {}) {
9889
+ async function apiRequest(path23, options = {}) {
9882
9890
  const { method = "GET", body, query, timeout = DEFAULT_TIMEOUT, requireAuth = true } = options;
9883
9891
  const endpoint = getApiEndpoint();
9884
- let url = `${endpoint}${path22}`;
9892
+ let url = `${endpoint}${path23}`;
9885
9893
  if (query && Object.keys(query).length > 0) {
9886
9894
  const params = new URLSearchParams(query);
9887
9895
  url = `${url}?${params.toString()}`;
@@ -9919,7 +9927,7 @@ async function apiRequest(path22, options = {}) {
9919
9927
  const controller = new AbortController();
9920
9928
  const timeoutId = setTimeout(() => controller.abort(), timeout);
9921
9929
  try {
9922
- logger.debug(`API Request: ${method} ${path22}`);
9930
+ logger.debug(`API Request: ${method} ${path23}`);
9923
9931
  const response = await fetch(url, {
9924
9932
  method,
9925
9933
  headers,
@@ -10034,10 +10042,10 @@ function mapAPIError(status, response) {
10034
10042
  }
10035
10043
  return new CLIError(errCode, errMsg);
10036
10044
  }
10037
- async function apiRequestStream(path22, options = {}) {
10045
+ async function apiRequestStream(path23, options = {}) {
10038
10046
  const { timeout = 3e5 } = options;
10039
10047
  const endpoint = getApiEndpoint();
10040
- const url = `${endpoint}${path22}`;
10048
+ const url = `${endpoint}${path23}`;
10041
10049
  const headers = {
10042
10050
  "User-Agent": "refly-cli/0.1.0"
10043
10051
  };
@@ -10068,7 +10076,7 @@ async function apiRequestStream(path22, options = {}) {
10068
10076
  const controller = new AbortController();
10069
10077
  const timeoutId = setTimeout(() => controller.abort(), timeout);
10070
10078
  try {
10071
- logger.debug(`API Stream Request: GET ${path22}`);
10079
+ logger.debug(`API Stream Request: GET ${path23}`);
10072
10080
  const response = await fetch(url, {
10073
10081
  method: "GET",
10074
10082
  headers,
@@ -10252,6 +10260,22 @@ async function apiUploadDriveFile(filePath, canvasId, options) {
10252
10260
  throw error;
10253
10261
  }
10254
10262
  }
10263
+ async function apiGetWorkflowVariables(canvasId) {
10264
+ return apiRequest("/v1/canvas/workflow/variables", {
10265
+ query: { canvasId }
10266
+ });
10267
+ }
10268
+ async function apiUpdateWorkflowVariables(canvasId, variables) {
10269
+ return apiRequest("/v1/canvas/workflow/variables", {
10270
+ method: "POST",
10271
+ body: { canvasId, variables }
10272
+ });
10273
+ }
10274
+ async function apiGetActionResult(resultId) {
10275
+ return apiRequest("/v1/cli/action/result", {
10276
+ query: { resultId }
10277
+ });
10278
+ }
10255
10279
 
10256
10280
  // src/commands/login.ts
10257
10281
  init_logger();
@@ -10726,7 +10750,7 @@ var import_node_child_process6 = require("child_process");
10726
10750
  var import_node_fs5 = __toESM(require("fs"));
10727
10751
  init_logger();
10728
10752
  init_paths();
10729
- var CLI_VERSION = "0.1.17";
10753
+ var CLI_VERSION = "0.1.18";
10730
10754
  var NPM_TAG = "test";
10731
10755
  function compareSemver(a, b) {
10732
10756
  const parseVersion = (v) => {
@@ -10982,16 +11006,16 @@ configCommand.action(() => {
10982
11006
  };
10983
11007
  ok("config", safeConfig);
10984
11008
  });
10985
- function getNestedValue(obj, path22) {
10986
- return path22.split(".").reduce((current, key) => {
11009
+ function getNestedValue(obj, path23) {
11010
+ return path23.split(".").reduce((current, key) => {
10987
11011
  if (current && typeof current === "object" && key in current) {
10988
11012
  return current[key];
10989
11013
  }
10990
11014
  return void 0;
10991
11015
  }, obj);
10992
11016
  }
10993
- function setNestedValue(obj, path22, value) {
10994
- const keys = path22.split(".");
11017
+ function setNestedValue(obj, path23, value) {
11018
+ const keys = path23.split(".");
10995
11019
  const lastKey = keys.pop();
10996
11020
  let current = obj;
10997
11021
  for (const key of keys) {
@@ -11441,6 +11465,77 @@ function determineFileType(filePath, mimeType) {
11441
11465
  return "document";
11442
11466
  }
11443
11467
 
11468
+ // src/utils/variable-check.ts
11469
+ init_cjs_shims();
11470
+ function checkRequiredVariables(definitions, providedInput) {
11471
+ const missing = [];
11472
+ const suggestedInput = { ...providedInput };
11473
+ for (const def of definitions) {
11474
+ if (!def.required) continue;
11475
+ const key = def.name;
11476
+ const hasValue = key in providedInput && providedInput[key] !== void 0 && providedInput[key] !== null;
11477
+ if (!hasValue) {
11478
+ missing.push(def);
11479
+ if (def.default !== void 0) {
11480
+ suggestedInput[key] = def.default;
11481
+ } else {
11482
+ suggestedInput[key] = "<value>";
11483
+ }
11484
+ }
11485
+ }
11486
+ return {
11487
+ valid: missing.length === 0,
11488
+ missing,
11489
+ suggestedInput
11490
+ };
11491
+ }
11492
+ function buildMissingVariablesError(commandType, targetId, targetName, result) {
11493
+ const displayName = targetName ? `"${targetName}"` : targetId;
11494
+ const inputJson = JSON.stringify(result.suggestedInput);
11495
+ const suggestedCommand = commandType === "workflow" ? `refly workflow run ${targetId} --input '${inputJson}'` : `refly skill run --name <name> --input '${inputJson}'`;
11496
+ return {
11497
+ code: "MISSING_VARIABLES",
11498
+ message: `Missing required variables for ${commandType} ${displayName}`,
11499
+ details: {
11500
+ missingVariables: result.missing.map((v) => ({
11501
+ name: v.name,
11502
+ type: v.variableType || "string",
11503
+ required: true,
11504
+ default: v.default,
11505
+ description: v.description
11506
+ })),
11507
+ suggestedInput: result.suggestedInput,
11508
+ suggestedCommand
11509
+ },
11510
+ hint: "Provide the missing variables via --input. See suggestedInput for the expected format.",
11511
+ suggestedFix: {
11512
+ field: "--input",
11513
+ format: "json-object",
11514
+ example: inputJson
11515
+ },
11516
+ recoverable: true
11517
+ };
11518
+ }
11519
+ function variablesToObject(variables) {
11520
+ const result = {};
11521
+ for (const v of variables) {
11522
+ if (!v.value || v.value.length === 0) continue;
11523
+ const firstValue = v.value[0];
11524
+ if (typeof firstValue === "object" && firstValue !== null) {
11525
+ if ("resource" in firstValue && typeof firstValue.resource === "object") {
11526
+ result[v.name] = firstValue;
11527
+ } else if ("text" in firstValue) {
11528
+ result[v.name] = firstValue.text;
11529
+ } else {
11530
+ result[v.name] = firstValue;
11531
+ }
11532
+ } else {
11533
+ result[v.name] = firstValue;
11534
+ }
11535
+ }
11536
+ return result;
11537
+ }
11538
+
11444
11539
  // src/commands/workflow/run.ts
11445
11540
  async function confirmAction(question) {
11446
11541
  const rl = readline2.createInterface({ input: import_node_process8.stdin, output: import_node_process8.stdout });
@@ -11511,6 +11606,11 @@ async function collectFileVariables(workflowId, existingInput, noPrompt) {
11511
11606
  } catch (_error) {
11512
11607
  return [];
11513
11608
  }
11609
+ let savedVariables = [];
11610
+ try {
11611
+ savedVariables = await apiGetWorkflowVariables(workflowId);
11612
+ } catch (_error) {
11613
+ }
11514
11614
  const resourceVars = (workflow.variables ?? []).filter(
11515
11615
  (v) => v.variableType === "resource" && v.required === true
11516
11616
  );
@@ -11518,33 +11618,35 @@ async function collectFileVariables(workflowId, existingInput, noPrompt) {
11518
11618
  return [];
11519
11619
  }
11520
11620
  const invalidFormatVars = [];
11621
+ const hasValidFileValue = (variable) => {
11622
+ if (!variable) return false;
11623
+ const values = variable.value;
11624
+ if (!Array.isArray(values) || values.length === 0) return false;
11625
+ return values.some((val) => {
11626
+ const fileId = val?.resource?.fileId || val?.fileId;
11627
+ return typeof fileId === "string" && fileId.length > 0;
11628
+ });
11629
+ };
11521
11630
  const missingVars = resourceVars.filter((v) => {
11522
- const provided = existingInput.find(
11631
+ const providedInInput = existingInput.find(
11523
11632
  (input3) => v.variableId && input3.variableId === v.variableId || v.name && input3.name === v.name
11524
11633
  );
11525
- if (!provided) {
11526
- return true;
11527
- }
11528
- const values = provided.value;
11529
- if (!Array.isArray(values) || values.length === 0) {
11634
+ const savedValue = savedVariables.find(
11635
+ (saved) => v.variableId && saved.variableId === v.variableId || v.name && saved.name === v.name
11636
+ );
11637
+ if (providedInInput) {
11638
+ if (hasValidFileValue(providedInInput)) {
11639
+ return false;
11640
+ }
11530
11641
  invalidFormatVars.push({
11531
11642
  name: v.name,
11532
- reason: "value must be an array with at least one file"
11643
+ reason: "invalid format in --input"
11533
11644
  });
11534
- return true;
11535
11645
  }
11536
- const hasValidFileId = values.some((val) => {
11537
- const fileId = val?.resource?.fileId || val?.fileId;
11538
- return typeof fileId === "string" && fileId.length > 0;
11539
- });
11540
- if (!hasValidFileId) {
11541
- invalidFormatVars.push({
11542
- name: v.name,
11543
- reason: "no valid fileId found in value"
11544
- });
11545
- return true;
11646
+ if (hasValidFileValue(savedValue)) {
11647
+ return false;
11546
11648
  }
11547
- return false;
11649
+ return true;
11548
11650
  });
11549
11651
  if (missingVars.length === 0) {
11550
11652
  return [];
@@ -11693,6 +11795,24 @@ async function runWorkflow(workflowId, options) {
11693
11795
  });
11694
11796
  return;
11695
11797
  }
11798
+ if (options?.noPrompt && workflow?.variables) {
11799
+ const inputObject = variablesToObject(inputVars);
11800
+ const checkResult = checkRequiredVariables(workflow.variables, inputObject);
11801
+ if (!checkResult.valid) {
11802
+ const errorPayload = buildMissingVariablesError(
11803
+ "workflow",
11804
+ workflowId,
11805
+ workflow.name,
11806
+ checkResult
11807
+ );
11808
+ fail(ErrorCodes.MISSING_VARIABLES, errorPayload.message, {
11809
+ details: errorPayload.details,
11810
+ hint: errorPayload.hint,
11811
+ suggestedFix: errorPayload.suggestedFix,
11812
+ recoverable: errorPayload.recoverable
11813
+ });
11814
+ }
11815
+ }
11696
11816
  const uploadedVars = await collectFileVariables(
11697
11817
  workflowId,
11698
11818
  inputVars,
@@ -12659,132 +12779,389 @@ var workflowNodeOutputCommand = new Command("node-output").description("Get node
12659
12779
 
12660
12780
  // src/commands/workflow/edit.ts
12661
12781
  init_cjs_shims();
12662
- var fs14 = __toESM(require("fs"));
12663
- var workflowEditCommand = new Command("edit").description("Edit a workflow plan using semantic operations").argument("<planId>", "Workflow Plan ID").option("--ops <json>", "Operations array as JSON").option("--ops-file <path>", "Read operations from file").option("--update-title <title>", "Shortcut: update workflow title").option("--delete-task <taskId>", "Shortcut: delete a task").option("--delete-variable <variableId>", "Shortcut: delete a variable").action(async (planId, options) => {
12782
+ var workflowEditCommand = new Command("edit").description("Edit a workflow using natural language").argument("<id>", "Canvas ID (c-xxx)").option("--query <text>", "Edit instruction in natural language").option("--session-id <id>", "Session ID (cs-xxx) for context continuity").option("--timeout <ms>", "Timeout for AI processing", "60000").action(async (id, options) => {
12664
12783
  try {
12665
- const operations = [];
12666
- const opsFormatHint = `Operations format: '[{"op": "updateTitle", "title": "New Title"}]'
12667
- Available ops: updateTitle, createTask, updateTask, deleteTask, createVariable, updateVariable, deleteVariable
12668
- Examples:
12669
- - Update title: {"op": "updateTitle", "title": "New Title"}
12670
- - Delete task: {"op": "deleteTask", "taskId": "task-id"}
12671
- - Update task: {"op": "updateTask", "taskId": "task-id", "data": {"prompt": "new prompt"}}`;
12672
- if (options.opsFile) {
12673
- try {
12674
- const filePath = options.opsFile;
12675
- if (!fs14.existsSync(filePath)) {
12676
- fail(ErrorCodes.NOT_FOUND, `Operations file not found: ${filePath}`);
12677
- }
12678
- const fileContent = fs14.readFileSync(filePath, "utf-8");
12679
- const fileOps = JSON.parse(fileContent);
12680
- if (Array.isArray(fileOps)) {
12681
- operations.push(...fileOps);
12682
- } else {
12683
- fail(ErrorCodes.INVALID_INPUT, "Operations file must contain a JSON array", {
12684
- hint: opsFormatHint,
12685
- suggestedFix: {
12686
- field: "--ops-file",
12687
- format: "json-array",
12688
- example: '[{"op": "updateTitle", "title": "New Title"}]'
12689
- }
12690
- });
12784
+ if (!options.query) {
12785
+ fail(ErrorCodes.INVALID_INPUT, "--query is required", {
12786
+ hint: "Provide a natural language description of the edit you want to make",
12787
+ suggestedFix: {
12788
+ field: "--query",
12789
+ format: "string",
12790
+ example: 'refly workflow edit c-xxx --query "\u6DFB\u52A0\u4E00\u4E2A\u7528 nano banana \u751F\u6210\u56FE\u7247\u7684\u4EFB\u52A1"'
12691
12791
  }
12692
- } catch (error) {
12693
- if (error instanceof CLIError) throw error;
12694
- fail(
12695
- ErrorCodes.INVALID_INPUT,
12696
- `Failed to parse operations file: ${error.message}`,
12697
- {
12698
- hint: opsFormatHint,
12699
- suggestedFix: {
12700
- field: "--ops-file",
12701
- format: "json-array",
12702
- example: '[{"op": "updateTitle", "title": "New Title"}]'
12703
- }
12704
- }
12705
- );
12792
+ });
12793
+ }
12794
+ if (!id.startsWith("c-")) {
12795
+ fail(ErrorCodes.INVALID_INPUT, "Only Canvas ID (c-xxx) is supported", {
12796
+ hint: 'Use the Canvas ID format starting with "c-"',
12797
+ suggestedFix: {
12798
+ field: "id",
12799
+ format: "canvas-id",
12800
+ example: "c-abc123"
12801
+ }
12802
+ });
12803
+ }
12804
+ const timeout = Number.parseInt(options.timeout);
12805
+ const response = await apiRequest(
12806
+ "/v1/cli/workflow/edit",
12807
+ {
12808
+ method: "POST",
12809
+ body: {
12810
+ canvasId: id,
12811
+ query: options.query,
12812
+ sessionId: options.sessionId,
12813
+ timeout
12814
+ },
12815
+ timeout: timeout + 5e3
12816
+ // Add buffer for network
12817
+ }
12818
+ );
12819
+ const result = response.data ?? response;
12820
+ ok("workflow.edit", {
12821
+ canvasId: result.canvasId,
12822
+ planId: result.planId,
12823
+ version: result.version,
12824
+ toolUsed: result.toolUsed,
12825
+ sessionId: result.sessionId,
12826
+ plan: {
12827
+ title: result.plan.title,
12828
+ taskCount: result.plan.tasks?.length ?? 0,
12829
+ variableCount: result.plan.variables?.length ?? 0,
12830
+ tasks: result.plan.tasks?.map((t) => ({
12831
+ id: t.id,
12832
+ title: t.title
12833
+ })),
12834
+ variables: result.plan.variables?.map((v) => ({
12835
+ variableId: v.variableId,
12836
+ name: v.name
12837
+ }))
12706
12838
  }
12839
+ });
12840
+ } catch (error) {
12841
+ if (error instanceof CLIError) {
12842
+ fail(error.code, error.message, {
12843
+ details: error.details,
12844
+ hint: error.hint,
12845
+ suggestedFix: error.suggestedFix
12846
+ });
12707
12847
  }
12708
- if (options.ops) {
12709
- try {
12710
- const jsonOps = JSON.parse(options.ops);
12711
- if (Array.isArray(jsonOps)) {
12712
- operations.push(...jsonOps);
12713
- } else {
12714
- fail(ErrorCodes.INVALID_INPUT, "--ops must be a JSON array", {
12715
- hint: opsFormatHint,
12848
+ fail(
12849
+ ErrorCodes.INTERNAL_ERROR,
12850
+ error instanceof Error ? error.message : "Failed to edit workflow"
12851
+ );
12852
+ }
12853
+ });
12854
+
12855
+ // src/commands/workflow/variables.ts
12856
+ init_cjs_shims();
12857
+ function getFileTypeCategory(mimeType) {
12858
+ if (mimeType.startsWith("image/")) return "image";
12859
+ if (mimeType.startsWith("video/")) return "video";
12860
+ if (mimeType.startsWith("audio/")) return "audio";
12861
+ if (mimeType === "application/pdf") return "document";
12862
+ if (mimeType.includes("word") || mimeType.includes("document")) return "document";
12863
+ if (mimeType.includes("sheet") || mimeType.includes("excel")) return "document";
12864
+ if (mimeType.includes("presentation") || mimeType.includes("powerpoint")) return "document";
12865
+ if (mimeType.startsWith("text/")) return "document";
12866
+ return "document";
12867
+ }
12868
+ async function getFileMetadata(fileId) {
12869
+ try {
12870
+ return await apiRequest(`/v1/cli/drive/files/${fileId}?includeContent=false`);
12871
+ } catch {
12872
+ return null;
12873
+ }
12874
+ }
12875
+ function parseVarArgs(varArgs) {
12876
+ const result = {};
12877
+ for (const arg of varArgs) {
12878
+ const eqIndex = arg.indexOf("=");
12879
+ if (eqIndex === -1) {
12880
+ throw new CLIError(
12881
+ ErrorCodes.INVALID_INPUT,
12882
+ `Invalid --var format: "${arg}"`,
12883
+ void 0,
12884
+ "Use format: --var key=value"
12885
+ );
12886
+ }
12887
+ const key = arg.slice(0, eqIndex);
12888
+ const value = arg.slice(eqIndex + 1);
12889
+ result[key] = value;
12890
+ }
12891
+ return result;
12892
+ }
12893
+ function formatVariable(v) {
12894
+ const hasValue = Array.isArray(v.value) && v.value.length > 0;
12895
+ return {
12896
+ name: v.name,
12897
+ variableId: v.variableId,
12898
+ type: v.variableType || "string",
12899
+ required: v.required ?? false,
12900
+ hasValue,
12901
+ value: hasValue ? v.value : void 0,
12902
+ description: v.description
12903
+ };
12904
+ }
12905
+ var variablesListCommand = new Command("list").description("List workflow variables with current values").argument("<workflowId>", "Workflow ID (canvas ID)").action(async (workflowId) => {
12906
+ try {
12907
+ const variables = await apiGetWorkflowVariables(workflowId);
12908
+ const formatted = variables.map(formatVariable);
12909
+ ok("workflow.variables.list", {
12910
+ workflowId,
12911
+ variables: formatted,
12912
+ count: variables.length
12913
+ });
12914
+ } catch (error) {
12915
+ if (error instanceof CLIError) {
12916
+ fail(error.code, error.message, {
12917
+ details: error.details,
12918
+ hint: error.hint,
12919
+ suggestedFix: error.suggestedFix
12920
+ });
12921
+ }
12922
+ fail(
12923
+ ErrorCodes.INTERNAL_ERROR,
12924
+ error instanceof Error ? error.message : "Failed to list variables"
12925
+ );
12926
+ }
12927
+ });
12928
+ var variablesGetCommand = new Command("get").description("Get a single workflow variable by name").argument("<workflowId>", "Workflow ID (canvas ID)").argument("<varName>", "Variable name to get").action(async (workflowId, varName) => {
12929
+ try {
12930
+ const variables = await apiGetWorkflowVariables(workflowId);
12931
+ const variable = variables.find((v) => v.name === varName || v.variableId === varName);
12932
+ if (!variable) {
12933
+ const availableNames = variables.map((v) => v.name).join(", ");
12934
+ fail(ErrorCodes.NOT_FOUND, `Variable not found: ${varName}`, {
12935
+ hint: `Available variables: ${availableNames}`
12936
+ });
12937
+ return;
12938
+ }
12939
+ ok("workflow.variables.get", {
12940
+ workflowId,
12941
+ variable: formatVariable(variable)
12942
+ });
12943
+ } catch (error) {
12944
+ if (error instanceof CLIError) {
12945
+ fail(error.code, error.message, {
12946
+ details: error.details,
12947
+ hint: error.hint,
12948
+ suggestedFix: error.suggestedFix
12949
+ });
12950
+ }
12951
+ fail(
12952
+ ErrorCodes.INTERNAL_ERROR,
12953
+ error instanceof Error ? error.message : "Failed to get variable"
12954
+ );
12955
+ }
12956
+ });
12957
+ var variablesSetCommand = new Command("set").description("Set variable values for a workflow").argument("<workflowId>", "Workflow ID (canvas ID)").option("--var <key=value...>", "Variable value in key=value format (can be repeated)").option("--input <json>", "Variable values as JSON object").option("--clear <name>", "Clear value for a specific variable").action(
12958
+ async (workflowId, options) => {
12959
+ try {
12960
+ const currentVars = await apiGetWorkflowVariables(workflowId);
12961
+ let newValues = {};
12962
+ if (options.input) {
12963
+ try {
12964
+ const parsed = JSON.parse(options.input);
12965
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
12966
+ fail(ErrorCodes.INVALID_INPUT, "Input must be a JSON object", {
12967
+ hint: `Use format: '{"varName": "value"}'`,
12968
+ suggestedFix: {
12969
+ field: "--input",
12970
+ format: "json-object",
12971
+ example: '{"varName": "value"}'
12972
+ }
12973
+ });
12974
+ }
12975
+ newValues = { ...parsed };
12976
+ } catch {
12977
+ fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --input", {
12978
+ hint: "Ensure the input is valid JSON",
12716
12979
  suggestedFix: {
12717
- field: "--ops",
12718
- format: "json-array",
12719
- example: '[{"op": "updateTitle", "title": "New Title"}]'
12980
+ field: "--input",
12981
+ format: "json-object",
12982
+ example: '{"varName": "value"}'
12720
12983
  }
12721
12984
  });
12722
12985
  }
12723
- } catch (error) {
12724
- fail(ErrorCodes.INVALID_INPUT, `Invalid JSON in --ops: ${error.message}`, {
12725
- hint: opsFormatHint,
12726
- suggestedFix: {
12727
- field: "--ops",
12728
- format: "json-array",
12729
- example: '[{"op": "updateTitle", "title": "New Title"}]'
12986
+ }
12987
+ if (options.var && options.var.length > 0) {
12988
+ const varBindings = parseVarArgs(options.var);
12989
+ newValues = { ...newValues, ...varBindings };
12990
+ }
12991
+ if (options.clear) {
12992
+ newValues[options.clear] = null;
12993
+ }
12994
+ if (Object.keys(newValues).length === 0) {
12995
+ fail(ErrorCodes.INVALID_INPUT, "No variables specified", {
12996
+ hint: `Use --var key=value, --input '{"key": "value"}', or --clear <name>`
12997
+ });
12998
+ }
12999
+ const fileIds = Object.values(newValues).filter(
13000
+ (v) => typeof v === "string" && v.startsWith("df-")
13001
+ );
13002
+ const fileMetadataMap = /* @__PURE__ */ new Map();
13003
+ for (const fileId of fileIds) {
13004
+ const metadata = await getFileMetadata(fileId);
13005
+ if (metadata) {
13006
+ fileMetadataMap.set(fileId, metadata);
13007
+ }
13008
+ }
13009
+ const updatedVars = currentVars.map((v) => {
13010
+ const name = v.name;
13011
+ if (name in newValues) {
13012
+ const newValue = newValues[name];
13013
+ if (newValue === null) {
13014
+ return { ...v, value: [] };
12730
13015
  }
13016
+ if (typeof newValue === "string") {
13017
+ if (newValue.startsWith("df-")) {
13018
+ const metadata = fileMetadataMap.get(newValue);
13019
+ return {
13020
+ ...v,
13021
+ value: [
13022
+ {
13023
+ type: "resource",
13024
+ resource: {
13025
+ fileId: newValue,
13026
+ name: metadata?.name || "",
13027
+ fileType: metadata ? getFileTypeCategory(metadata.type) : "document",
13028
+ storageKey: metadata?.storageKey || ""
13029
+ }
13030
+ }
13031
+ ]
13032
+ };
13033
+ }
13034
+ return {
13035
+ ...v,
13036
+ value: [{ type: "text", text: newValue }]
13037
+ };
13038
+ }
13039
+ if (Array.isArray(newValue)) {
13040
+ return { ...v, value: newValue };
13041
+ }
13042
+ return v;
13043
+ }
13044
+ return v;
13045
+ });
13046
+ const definedNames = new Set(currentVars.map((v) => v.name));
13047
+ const unknownVars = Object.keys(newValues).filter((k) => !definedNames.has(k));
13048
+ if (unknownVars.length > 0) {
13049
+ fail(ErrorCodes.INVALID_INPUT, `Unknown variables: ${unknownVars.join(", ")}`, {
13050
+ hint: `Available variables: ${Array.from(definedNames).join(", ")}`
12731
13051
  });
12732
13052
  }
12733
- }
12734
- if (options.updateTitle) {
12735
- operations.push({
12736
- op: "updateTitle",
12737
- title: options.updateTitle
13053
+ const result = await apiUpdateWorkflowVariables(workflowId, updatedVars);
13054
+ ok("workflow.variables.set", {
13055
+ workflowId,
13056
+ updated: Object.keys(newValues),
13057
+ variables: result.map(formatVariable)
12738
13058
  });
13059
+ } catch (error) {
13060
+ if (error instanceof CLIError) {
13061
+ fail(error.code, error.message, {
13062
+ details: error.details,
13063
+ hint: error.hint,
13064
+ suggestedFix: error.suggestedFix
13065
+ });
13066
+ }
13067
+ fail(
13068
+ ErrorCodes.INTERNAL_ERROR,
13069
+ error instanceof Error ? error.message : "Failed to set variables"
13070
+ );
12739
13071
  }
12740
- if (options.deleteTask) {
12741
- operations.push({
12742
- op: "deleteTask",
12743
- taskId: options.deleteTask
12744
- });
13072
+ }
13073
+ );
13074
+ var workflowVariablesCommand = new Command("variables").description("Manage workflow variable values").addCommand(variablesListCommand).addCommand(variablesGetCommand).addCommand(variablesSetCommand);
13075
+
13076
+ // src/commands/workflow/result.ts
13077
+ init_cjs_shims();
13078
+ function formatResult(result, options) {
13079
+ const output3 = {
13080
+ resultId: result.resultId,
13081
+ version: result.version,
13082
+ title: result.title,
13083
+ type: result.type,
13084
+ status: result.status
13085
+ };
13086
+ if (result.workflowExecutionId) {
13087
+ output3.workflowExecutionId = result.workflowExecutionId;
13088
+ }
13089
+ if (result.workflowNodeExecutionId) {
13090
+ output3.workflowNodeExecutionId = result.workflowNodeExecutionId;
13091
+ }
13092
+ output3.timing = {
13093
+ createdAt: result.createdAt,
13094
+ updatedAt: result.updatedAt
13095
+ };
13096
+ if (result.errors && result.errors.length > 0) {
13097
+ output3.errors = result.errors;
13098
+ }
13099
+ if (result.errorType) {
13100
+ output3.errorType = result.errorType;
13101
+ }
13102
+ if (result.outputUrl) {
13103
+ output3.outputUrl = result.outputUrl;
13104
+ }
13105
+ if (result.files && result.files.length > 0) {
13106
+ output3.files = result.files;
13107
+ }
13108
+ if (result.modelInfo) {
13109
+ output3.modelInfo = result.modelInfo;
13110
+ }
13111
+ if (options.includeSteps && result.steps) {
13112
+ if (options.raw) {
13113
+ output3.steps = result.steps;
13114
+ } else {
13115
+ output3.steps = result.steps.map((step) => ({
13116
+ name: step.name,
13117
+ contentPreview: step.content?.substring(0, 200) + (step.content && step.content.length > 200 ? "..." : ""),
13118
+ toolCallsCount: step.toolCalls?.length || 0,
13119
+ ...options.includeToolCalls && step.toolCalls ? {
13120
+ toolCalls: step.toolCalls.map((tc) => ({
13121
+ callId: tc.callId,
13122
+ toolName: tc.toolName,
13123
+ status: tc.status,
13124
+ ...options.raw ? { input: tc.input, output: tc.output } : {},
13125
+ ...tc.error ? { error: tc.error } : {}
13126
+ }))
13127
+ } : {}
13128
+ }));
12745
13129
  }
12746
- if (options.deleteVariable) {
12747
- operations.push({
12748
- op: "deleteVariable",
12749
- variableId: options.deleteVariable
12750
- });
13130
+ }
13131
+ if (options.includeMessages && result.messages) {
13132
+ if (options.raw) {
13133
+ output3.messages = result.messages;
13134
+ } else {
13135
+ output3.messages = result.messages.map((msg) => ({
13136
+ messageId: msg.messageId,
13137
+ type: msg.type,
13138
+ contentPreview: msg.content?.substring(0, 200) + (msg.content && msg.content.length > 200 ? "..." : ""),
13139
+ createdAt: msg.createdAt
13140
+ }));
12751
13141
  }
12752
- if (operations.length === 0) {
12753
- fail(ErrorCodes.INVALID_INPUT, "No operations provided", {
12754
- hint: "Use --ops, --ops-file, or shortcut options (--update-title, --delete-task, --delete-variable)",
13142
+ }
13143
+ return output3;
13144
+ }
13145
+ var workflowResultCommand = new Command("result").description("Get action result by resultId").argument("<resultId>", "Action result ID (ar-xxx)").option("--include-steps", "Include execution steps").option("--include-messages", "Include action messages").option("--include-tool-calls", "Include tool call details (requires --include-steps)").option("--raw", "Show full content without truncation").action(async (resultId, options) => {
13146
+ try {
13147
+ if (!resultId.startsWith("ar-") && !resultId.startsWith("start-")) {
13148
+ return fail(ErrorCodes.INVALID_INPUT, `Invalid resultId format: ${resultId}`, {
13149
+ hint: 'Result ID should start with "ar-" or "start-"',
12755
13150
  suggestedFix: {
12756
- field: "--ops",
12757
- format: "json-array",
12758
- example: '[{"op": "updateTitle", "title": "New Title"}]'
13151
+ field: "resultId",
13152
+ format: "ar-xxx or start-xxx",
13153
+ example: "ar-cq18zd4qr97nbla1tu1rqqmd"
12759
13154
  }
12760
13155
  });
12761
13156
  }
12762
- const body = {
12763
- planId,
12764
- operations
12765
- };
12766
- const response = await apiRequest("/v1/cli/workflow-plan/patch", {
12767
- method: "POST",
12768
- body
12769
- });
12770
- const plan = response.data ?? response;
12771
- ok("workflow.edit", {
12772
- planId,
12773
- operationsApplied: operations.length,
12774
- plan: {
12775
- title: plan.title,
12776
- taskCount: plan.tasks?.length ?? 0,
12777
- variableCount: plan.variables?.length ?? 0,
12778
- tasks: plan.tasks?.map((t) => ({
12779
- id: t.id,
12780
- title: t.title
12781
- })),
12782
- variables: plan.variables?.map((v) => ({
12783
- variableId: v.variableId,
12784
- name: v.name
12785
- }))
12786
- }
13157
+ const result = await apiGetActionResult(resultId);
13158
+ const formattedResult = formatResult(result, {
13159
+ includeSteps: options.includeSteps,
13160
+ includeMessages: options.includeMessages,
13161
+ includeToolCalls: options.includeToolCalls,
13162
+ raw: options.raw
12787
13163
  });
13164
+ ok("workflow.result", formattedResult);
12788
13165
  } catch (error) {
12789
13166
  if (error instanceof CLIError) {
12790
13167
  fail(error.code, error.message, {
@@ -12792,17 +13169,39 @@ Examples:
12792
13169
  hint: error.hint,
12793
13170
  suggestedFix: error.suggestedFix
12794
13171
  });
12795
- return;
12796
13172
  }
12797
13173
  fail(
12798
13174
  ErrorCodes.INTERNAL_ERROR,
12799
- error instanceof Error ? error.message : "Failed to edit workflow plan"
13175
+ error instanceof Error ? error.message : "Failed to get action result"
13176
+ );
13177
+ }
13178
+ });
13179
+
13180
+ // src/commands/workflow/session.ts
13181
+ init_cjs_shims();
13182
+ var workflowSessionCommand = new Command("session").description("Get the latest copilot session for a workflow").argument("<workflowId>", "Workflow ID (canvas ID)").action(async (workflowId) => {
13183
+ try {
13184
+ const result = await apiRequest(
13185
+ `/v1/cli/workflow/${workflowId}/session`
13186
+ );
13187
+ ok("workflow.session", result);
13188
+ } catch (error) {
13189
+ if (error instanceof CLIError) {
13190
+ fail(error.code, error.message, {
13191
+ details: error.details,
13192
+ hint: error.hint,
13193
+ suggestedFix: error.suggestedFix
13194
+ });
13195
+ }
13196
+ fail(
13197
+ ErrorCodes.INTERNAL_ERROR,
13198
+ error instanceof Error ? error.message : "Failed to get workflow session"
12800
13199
  );
12801
13200
  }
12802
13201
  });
12803
13202
 
12804
13203
  // src/commands/workflow/index.ts
12805
- var workflowCommand = new Command("workflow").description("Manage and run workflows").addCommand(workflowCreateCommand).addCommand(workflowGenerateCommand).addCommand(workflowListCommand).addCommand(workflowGetCommand).addCommand(workflowDeleteCommand).addCommand(workflowRunCommand).addCommand(workflowRunsCommand).addCommand(workflowStatusCommand).addCommand(workflowDetailCommand).addCommand(workflowToolcallsCommand).addCommand(workflowAbortCommand).addCommand(workflowToolsetKeysCommand).addCommand(workflowLayoutCommand).addCommand(workflowNodesCommand).addCommand(workflowNodeGetCommand).addCommand(workflowNodeAddCommand).addCommand(workflowNodeUpdateCommand).addCommand(workflowNodeDeleteCommand).addCommand(workflowNodeOutputCommand).addCommand(workflowEditCommand);
13204
+ var workflowCommand = new Command("workflow").description("Manage and run workflows").addCommand(workflowCreateCommand).addCommand(workflowGenerateCommand).addCommand(workflowListCommand).addCommand(workflowGetCommand).addCommand(workflowDeleteCommand).addCommand(workflowRunCommand).addCommand(workflowRunsCommand).addCommand(workflowStatusCommand).addCommand(workflowDetailCommand).addCommand(workflowToolcallsCommand).addCommand(workflowAbortCommand).addCommand(workflowToolsetKeysCommand).addCommand(workflowLayoutCommand).addCommand(workflowNodesCommand).addCommand(workflowNodeGetCommand).addCommand(workflowNodeAddCommand).addCommand(workflowNodeUpdateCommand).addCommand(workflowNodeDeleteCommand).addCommand(workflowNodeOutputCommand).addCommand(workflowEditCommand).addCommand(workflowVariablesCommand).addCommand(workflowSessionCommand).addCommand(workflowResultCommand);
12806
13205
 
12807
13206
  // src/commands/tool/index.ts
12808
13207
  init_cjs_shims();
@@ -12982,7 +13381,7 @@ var fileGetCommand = new Command("get").description("Get file details").argument
12982
13381
 
12983
13382
  // src/commands/file/download.ts
12984
13383
  init_cjs_shims();
12985
- var fs15 = __toESM(require("fs"));
13384
+ var fs14 = __toESM(require("fs"));
12986
13385
  var path11 = __toESM(require("path"));
12987
13386
  var fileDownloadCommand = new Command("download").description("Download file to local filesystem").argument("<fileId>", "File ID").option("-o, --output <path>", "Output file path (defaults to original filename)").action(async (fileId, options) => {
12988
13387
  try {
@@ -12991,7 +13390,7 @@ var fileDownloadCommand = new Command("download").description("Download file to
12991
13390
  );
12992
13391
  const outputPath = options.output || filename || `${fileId}`;
12993
13392
  const resolvedPath = path11.resolve(outputPath);
12994
- fs15.writeFileSync(resolvedPath, data);
13393
+ fs14.writeFileSync(resolvedPath, data);
12995
13394
  ok("file.download", {
12996
13395
  fileId,
12997
13396
  path: resolvedPath,
@@ -13016,7 +13415,7 @@ var fileDownloadCommand = new Command("download").description("Download file to
13016
13415
 
13017
13416
  // src/commands/file/upload.ts
13018
13417
  init_cjs_shims();
13019
- var fs16 = __toESM(require("fs"));
13418
+ var fs15 = __toESM(require("fs"));
13020
13419
  var path12 = __toESM(require("path"));
13021
13420
  var MAX_FILES = 10;
13022
13421
  function formatSize(bytes) {
@@ -13028,7 +13427,7 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
13028
13427
  const formatter = getFormatter();
13029
13428
  try {
13030
13429
  const resolvedPath = path12.resolve(inputPath);
13031
- if (!fs16.existsSync(resolvedPath)) {
13430
+ if (!fs15.existsSync(resolvedPath)) {
13032
13431
  fail(ErrorCodes.NOT_FOUND, `Path not found: ${inputPath}`, {
13033
13432
  hint: "Check if the file or directory exists"
13034
13433
  });
@@ -13047,7 +13446,7 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
13047
13446
  for (let i = 0; i < files.length; i++) {
13048
13447
  const filePath = files[i];
13049
13448
  const filename = path12.basename(filePath);
13050
- const fileStats = fs16.statSync(filePath);
13449
+ const fileStats = fs15.statSync(filePath);
13051
13450
  const sizeStr = formatSize(fileStats.size);
13052
13451
  let currentStage = "presign";
13053
13452
  const updateProgress = () => {
@@ -13128,7 +13527,7 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
13128
13527
  }
13129
13528
  });
13130
13529
  function resolveFilesToUpload(inputPath, filter) {
13131
- const stats = fs16.statSync(inputPath);
13530
+ const stats = fs15.statSync(inputPath);
13132
13531
  if (stats.isFile()) {
13133
13532
  if (filter) {
13134
13533
  const filterExts = filter.split(",").map((e) => e.trim().toLowerCase());
@@ -13140,11 +13539,11 @@ function resolveFilesToUpload(inputPath, filter) {
13140
13539
  return [inputPath];
13141
13540
  }
13142
13541
  if (stats.isDirectory()) {
13143
- const entries = fs16.readdirSync(inputPath);
13542
+ const entries = fs15.readdirSync(inputPath);
13144
13543
  const filterExts = filter?.split(",").map((e) => e.trim().toLowerCase());
13145
13544
  const files = entries.map((e) => path12.join(inputPath, e)).filter((p) => {
13146
13545
  try {
13147
- return fs16.statSync(p).isFile();
13546
+ return fs15.statSync(p).isFile();
13148
13547
  } catch {
13149
13548
  return false;
13150
13549
  }
@@ -13154,7 +13553,7 @@ function resolveFilesToUpload(inputPath, filter) {
13154
13553
  return filterExts.includes(ext);
13155
13554
  }).sort((a, b) => {
13156
13555
  try {
13157
- return fs16.statSync(a).size - fs16.statSync(b).size;
13556
+ return fs15.statSync(a).size - fs15.statSync(b).size;
13158
13557
  } catch {
13159
13558
  return 0;
13160
13559
  }
@@ -13258,7 +13657,7 @@ var skillGetCommand = new Command("get").description("Get skill package details"
13258
13657
 
13259
13658
  // src/commands/skill/create.ts
13260
13659
  init_cjs_shims();
13261
- var fs17 = __toESM(require("fs"));
13660
+ var fs16 = __toESM(require("fs"));
13262
13661
  init_symlink();
13263
13662
  init_paths();
13264
13663
  init_logger();
@@ -13304,13 +13703,13 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
13304
13703
  });
13305
13704
  const result = response.payload;
13306
13705
  let localPath;
13307
- let symlinkPath;
13706
+ let _symlinkPath;
13308
13707
  if (result.workflowId) {
13309
13708
  try {
13310
13709
  const localName = options.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
13311
13710
  const skillDir = getReflyDomainSkillDir(localName);
13312
13711
  const symlinkStatus = isSkillSymlinkValid(localName);
13313
- if (fs17.existsSync(skillDir) || symlinkStatus.exists) {
13712
+ if (fs16.existsSync(skillDir) || symlinkStatus.exists) {
13314
13713
  logger.debug(`Local skill '${localName}' already exists, skipping sync`);
13315
13714
  } else {
13316
13715
  const skillMdContent = generateReflySkillMd({
@@ -13328,7 +13727,7 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
13328
13727
  const symlinkResult = createReflySkillWithSymlink(localName, skillMdContent);
13329
13728
  if (symlinkResult.success) {
13330
13729
  localPath = symlinkResult.reflyPath;
13331
- symlinkPath = symlinkResult.claudePath;
13730
+ _symlinkPath = symlinkResult.claudePath;
13332
13731
  logger.info(`Created local domain skill: ${localName}`);
13333
13732
  } else {
13334
13733
  logger.warn(`Failed to create local skill: ${symlinkResult.error}`);
@@ -13338,18 +13737,16 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
13338
13737
  logger.warn(`Failed to sync to local: ${syncError.message}`);
13339
13738
  }
13340
13739
  }
13740
+ const webUrl = getWebUrl();
13341
13741
  const payload = {
13342
13742
  skillId: result.skillId,
13343
13743
  name: result.name,
13344
13744
  status: result.status,
13345
13745
  createdAt: result.createdAt,
13346
13746
  workflowId: result.workflowId,
13347
- url: `${getWebUrl()}/skill/${result.skillId}`
13747
+ workflowUrl: result.workflowId ? `${webUrl}/workflow/${result.workflowId}` : void 0,
13748
+ localPath
13348
13749
  };
13349
- if (localPath) {
13350
- payload.localPath = localPath;
13351
- payload.symlinkPath = symlinkPath;
13352
- }
13353
13750
  if (options.verbose) {
13354
13751
  payload.workflowIds = result.workflowIds;
13355
13752
  payload.workflows = result.workflows;
@@ -13373,7 +13770,7 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
13373
13770
 
13374
13771
  // src/commands/skill/update.ts
13375
13772
  init_cjs_shims();
13376
- var fs18 = __toESM(require("fs"));
13773
+ var fs17 = __toESM(require("fs"));
13377
13774
  var path13 = __toESM(require("path"));
13378
13775
  init_paths();
13379
13776
  init_symlink();
@@ -13405,7 +13802,7 @@ var skillUpdateCommand = new Command("update").description("Update skill install
13405
13802
  const name = options.name;
13406
13803
  const skillDir = getReflyDomainSkillDir(name);
13407
13804
  const skillMdPath = path13.join(skillDir, "SKILL.md");
13408
- if (!fs18.existsSync(skillMdPath)) {
13805
+ if (!fs17.existsSync(skillMdPath)) {
13409
13806
  const skillsDir = getReflySkillsDir();
13410
13807
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13411
13808
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
@@ -13414,7 +13811,7 @@ To see installed skills: refly skill list`
13414
13811
  });
13415
13812
  return;
13416
13813
  }
13417
- const skillContent = fs18.readFileSync(skillMdPath, "utf-8");
13814
+ const skillContent = fs17.readFileSync(skillMdPath, "utf-8");
13418
13815
  let meta;
13419
13816
  try {
13420
13817
  const parsed = parseReflySkillMd(skillContent);
@@ -13497,7 +13894,7 @@ To see installed skills: refly skill list`
13497
13894
 
13498
13895
  // src/commands/skill/publish.ts
13499
13896
  init_cjs_shims();
13500
- var fs19 = __toESM(require("fs"));
13897
+ var fs18 = __toESM(require("fs"));
13501
13898
  var path14 = __toESM(require("path"));
13502
13899
  init_symlink();
13503
13900
  init_paths();
@@ -13521,7 +13918,7 @@ To find your skill name:
13521
13918
  const name = options.name;
13522
13919
  const skillDir = getReflyDomainSkillDir(name);
13523
13920
  const skillMdPath = path14.join(skillDir, "SKILL.md");
13524
- if (!fs19.existsSync(skillMdPath)) {
13921
+ if (!fs18.existsSync(skillMdPath)) {
13525
13922
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13526
13923
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
13527
13924
 
@@ -13530,7 +13927,7 @@ To create a new skill: refly skill create --name "${name}" --workflow-query "...
13530
13927
  });
13531
13928
  return;
13532
13929
  }
13533
- const skillContent = fs19.readFileSync(skillMdPath, "utf-8");
13930
+ const skillContent = fs18.readFileSync(skillMdPath, "utf-8");
13534
13931
  let parsedSkill;
13535
13932
  try {
13536
13933
  parsedSkill = parseReflySkillMd(skillContent);
@@ -13561,8 +13958,6 @@ To create a new skill: refly skill create --name "${name}" --workflow-query "...
13561
13958
  version: result.version,
13562
13959
  status: result.status,
13563
13960
  isPublic: result.isPublic,
13564
- shareId: result.shareId,
13565
- shareUrl: result.shareId ? `https://refly.ai/skill/${result.shareId}` : void 0,
13566
13961
  githubPrUrl: result.githubPrUrl,
13567
13962
  githubPrNumber: result.githubPrNumber,
13568
13963
  localPath: skillMdPath
@@ -13585,7 +13980,7 @@ To create a new skill: refly skill create --name "${name}" --workflow-query "...
13585
13980
 
13586
13981
  // src/commands/skill/unpublish.ts
13587
13982
  init_cjs_shims();
13588
- var fs20 = __toESM(require("fs"));
13983
+ var fs19 = __toESM(require("fs"));
13589
13984
  var path15 = __toESM(require("path"));
13590
13985
  init_symlink();
13591
13986
  init_paths();
@@ -13610,7 +14005,7 @@ To find your skill name:
13610
14005
  name = options.name;
13611
14006
  const skillDir = getReflyDomainSkillDir(name);
13612
14007
  const skillMdPath = path15.join(skillDir, "SKILL.md");
13613
- if (!fs20.existsSync(skillMdPath)) {
14008
+ if (!fs19.existsSync(skillMdPath)) {
13614
14009
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13615
14010
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
13616
14011
 
@@ -13618,7 +14013,7 @@ To see installed skills: refly skill list`
13618
14013
  });
13619
14014
  return;
13620
14015
  }
13621
- const skillContent = fs20.readFileSync(skillMdPath, "utf-8");
14016
+ const skillContent = fs19.readFileSync(skillMdPath, "utf-8");
13622
14017
  try {
13623
14018
  const { meta } = parseReflySkillMd(skillContent);
13624
14019
  skillId = options.id || meta.skillId;
@@ -13662,11 +14057,11 @@ To see installed skills: refly skill list`
13662
14057
 
13663
14058
  // src/commands/skill/run.ts
13664
14059
  init_cjs_shims();
13665
- var fs21 = __toESM(require("fs"));
14060
+ var fs20 = __toESM(require("fs"));
13666
14061
  var path16 = __toESM(require("path"));
13667
14062
  init_symlink();
13668
14063
  init_paths();
13669
- var skillRunCommand = new Command("run").description("Run an installed skill").option("--id <installationId>", "Installation ID (skpi-xxx)").option("--name <name>", "Local skill name (directory in ~/.refly/skills/)").option("--input <json>", "Input JSON for the skill").option("--workflow <skillWorkflowId>", "Run specific workflow only").option("--async", "Run asynchronously").action(async (options) => {
14064
+ var skillRunCommand = new Command("run").description("Run an installed skill").option("--id <installationId>", "Installation ID (skpi-xxx)").option("--name <name>", "Local skill name (directory in ~/.refly/skills/)").option("--input <json>", "Input JSON for the skill").option("--workflow <skillWorkflowId>", "Run specific workflow only").option("--async", "Run asynchronously").option("--no-prompt", "Disable interactive prompts (fail if required variables are missing)").action(async (options) => {
13670
14065
  try {
13671
14066
  const skillsDir = getReflySkillsDir();
13672
14067
  if (!options.id && !options.name) {
@@ -13684,11 +14079,12 @@ To find your skill name:
13684
14079
  let installationId;
13685
14080
  let name;
13686
14081
  let skillId;
14082
+ let workflowId;
13687
14083
  if (options.name) {
13688
14084
  name = options.name;
13689
- const skillDir = getReflyDomainSkillDir(name);
14085
+ const skillDir = getReflyDomainSkillDir(options.name);
13690
14086
  const skillMdPath = path16.join(skillDir, "SKILL.md");
13691
- if (!fs21.existsSync(skillMdPath)) {
14087
+ if (!fs20.existsSync(skillMdPath)) {
13692
14088
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13693
14089
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
13694
14090
 
@@ -13697,10 +14093,11 @@ To install a skill: refly skill install <skillId>`
13697
14093
  });
13698
14094
  return;
13699
14095
  }
13700
- const skillContent = fs21.readFileSync(skillMdPath, "utf-8");
14096
+ const skillContent = fs20.readFileSync(skillMdPath, "utf-8");
13701
14097
  try {
13702
14098
  const { meta } = parseReflySkillMd(skillContent);
13703
14099
  skillId = meta.skillId;
14100
+ workflowId = meta.workflowId;
13704
14101
  if (options.id) {
13705
14102
  installationId = options.id;
13706
14103
  } else if (meta.installationId) {
@@ -13753,6 +14150,29 @@ To install: refly skill install ${meta.skillId}`
13753
14150
  return;
13754
14151
  }
13755
14152
  }
14153
+ if (options.noPrompt && workflowId) {
14154
+ try {
14155
+ const workflow = await apiGetWorkflow(workflowId);
14156
+ if (workflow?.variables) {
14157
+ const checkResult = checkRequiredVariables(workflow.variables, input3);
14158
+ if (!checkResult.valid) {
14159
+ const errorPayload = buildMissingVariablesError(
14160
+ "skill",
14161
+ name || installationId,
14162
+ name,
14163
+ checkResult
14164
+ );
14165
+ fail(ErrorCodes.MISSING_VARIABLES, errorPayload.message, {
14166
+ details: errorPayload.details,
14167
+ hint: errorPayload.hint,
14168
+ suggestedFix: errorPayload.suggestedFix,
14169
+ recoverable: errorPayload.recoverable
14170
+ });
14171
+ }
14172
+ }
14173
+ } catch {
14174
+ }
14175
+ }
13756
14176
  const body = { input: input3 };
13757
14177
  if (options.workflow) body.workflowId = options.workflow;
13758
14178
  if (options.async) body.async = true;
@@ -13789,6 +14209,87 @@ To install: refly skill install ${meta.skillId}`
13789
14209
  }
13790
14210
  });
13791
14211
 
14212
+ // src/commands/skill/stop.ts
14213
+ init_cjs_shims();
14214
+ var fs21 = __toESM(require("fs"));
14215
+ var path17 = __toESM(require("path"));
14216
+ init_symlink();
14217
+ init_paths();
14218
+ function getLocalSkillNames() {
14219
+ const skillsDir = getReflySkillsDir();
14220
+ if (!fs21.existsSync(skillsDir)) {
14221
+ return [];
14222
+ }
14223
+ return fs21.readdirSync(skillsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
14224
+ }
14225
+ var skillStopCommand = new Command("stop").description("Stop running skill executions").requiredOption("--name <name>", "Local skill name (directory in ~/.refly/skills/)").action(async (options) => {
14226
+ try {
14227
+ const skillsDir = getReflySkillsDir();
14228
+ const name = options.name;
14229
+ const skillDir = getReflyDomainSkillDir(name);
14230
+ const skillMdPath = path17.join(skillDir, "SKILL.md");
14231
+ if (!fs21.existsSync(skillMdPath)) {
14232
+ const availableSkills = getLocalSkillNames();
14233
+ const skillList = availableSkills.length > 0 ? availableSkills.join(", ") : "(no skills installed)";
14234
+ fail(ErrorCodes.NOT_FOUND, `Skill "${name}" not found`, {
14235
+ hint: `Available skills: ${skillList}
14236
+
14237
+ Skills directory: ${skillsDir}`
14238
+ });
14239
+ }
14240
+ const skillContent = fs21.readFileSync(skillMdPath, "utf-8");
14241
+ let installationId;
14242
+ try {
14243
+ const { meta } = parseReflySkillMd(skillContent);
14244
+ if (!meta.installationId) {
14245
+ fail(ErrorCodes.INVALID_INPUT, `Skill "${name}" does not have an installationId`, {
14246
+ hint: `This skill may have been created locally but not installed.
14247
+
14248
+ To install: refly skill install ${meta.skillId}`
14249
+ });
14250
+ }
14251
+ installationId = meta.installationId;
14252
+ } catch (parseError) {
14253
+ fail(
14254
+ ErrorCodes.INVALID_INPUT,
14255
+ `Failed to parse SKILL.md: ${parseError.message}`,
14256
+ {
14257
+ hint: "Make sure SKILL.md has valid frontmatter with required fields"
14258
+ }
14259
+ );
14260
+ }
14261
+ const result = await apiRequest(
14262
+ `/v1/skill-installations/${installationId}/stop`,
14263
+ {
14264
+ method: "POST"
14265
+ }
14266
+ );
14267
+ ok("skill.stop", {
14268
+ name,
14269
+ installationId,
14270
+ message: result.message,
14271
+ stoppedExecutions: result.stoppedExecutions
14272
+ });
14273
+ } catch (error) {
14274
+ if (error instanceof CLIError) {
14275
+ if (error.code === "NOT_FOUND") {
14276
+ fail(ErrorCodes.NOT_FOUND, `No running executions for skill "${options.name}"`, {
14277
+ hint: "The skill is not currently running"
14278
+ });
14279
+ }
14280
+ fail(error.code, error.message, {
14281
+ details: error.details,
14282
+ hint: error.hint,
14283
+ suggestedFix: error.suggestedFix
14284
+ });
14285
+ }
14286
+ fail(
14287
+ ErrorCodes.INTERNAL_ERROR,
14288
+ error instanceof Error ? error.message : "Failed to stop skill"
14289
+ );
14290
+ }
14291
+ });
14292
+
13792
14293
  // src/commands/skill/search.ts
13793
14294
  init_cjs_shims();
13794
14295
  var skillSearchCommand = new Command("search").description("Search public skill packages").argument("<query>", "Search query").option("--tags <tags>", "Filter by tags (comma-separated)").option("--page <number>", "Page number", "1").option("--page-size <number>", "Page size", "20").action(async (query, options) => {
@@ -13835,11 +14336,12 @@ var skillSearchCommand = new Command("search").description("Search public skill
13835
14336
  init_cjs_shims();
13836
14337
  init_symlink();
13837
14338
  init_logger();
13838
- var skillInstallCommand = new Command("install").description("Install a skill package").argument("<skillId>", "Skill package ID to install").option("--version <version>", "Specific version to install").option("--share-id <shareId>", "Share ID for private skills").option("--config <json>", "Installation config JSON").action(async (skillId, options) => {
14339
+ var skillInstallCommand = new Command("install").description("Install a skill package").argument("<skillId>", "Skill package ID to install").option("--version <version>", "Specific version to install").option("--share-id <shareId>", "Share ID for private skills").option("--config <json>", "Installation config JSON").option("--force", "Force reinstall if already installed").action(async (skillId, options) => {
13839
14340
  try {
13840
14341
  const body = { skillId };
13841
14342
  if (options.version) body.version = options.version;
13842
14343
  if (options.shareId) body.shareId = options.shareId;
14344
+ if (options.force) body.force = true;
13843
14345
  if (options.config) {
13844
14346
  try {
13845
14347
  body.config = JSON.parse(options.config);
@@ -13881,7 +14383,9 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
13881
14383
  inputSchema: result.skillPackage?.inputSchema,
13882
14384
  outputSchema: result.skillPackage?.outputSchema
13883
14385
  });
13884
- const symlinkResult = createReflySkillWithSymlink(skillName, skillMdContent);
14386
+ const symlinkResult = createReflySkillWithSymlink(skillName, skillMdContent, {
14387
+ force: options.force
14388
+ });
13885
14389
  if (symlinkResult.success) {
13886
14390
  localPath = symlinkResult.reflyPath;
13887
14391
  symlinkPath = symlinkResult.claudePath;
@@ -13923,7 +14427,7 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
13923
14427
  // src/commands/skill/uninstall.ts
13924
14428
  init_cjs_shims();
13925
14429
  var fs22 = __toESM(require("fs"));
13926
- var path17 = __toESM(require("path"));
14430
+ var path18 = __toESM(require("path"));
13927
14431
  init_symlink();
13928
14432
  init_paths();
13929
14433
  init_logger();
@@ -13948,7 +14452,7 @@ To find your skill name:
13948
14452
  if (options.name) {
13949
14453
  name = options.name;
13950
14454
  const skillDir = getReflyDomainSkillDir(name);
13951
- const skillMdPath = path17.join(skillDir, "SKILL.md");
14455
+ const skillMdPath = path18.join(skillDir, "SKILL.md");
13952
14456
  if (!fs22.existsSync(skillMdPath)) {
13953
14457
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13954
14458
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
@@ -14074,7 +14578,7 @@ init_cjs_shims();
14074
14578
  // src/skill/loader.ts
14075
14579
  init_cjs_shims();
14076
14580
  var fs23 = __toESM(require("fs"));
14077
- var path18 = __toESM(require("path"));
14581
+ var path19 = __toESM(require("path"));
14078
14582
  var import_gray_matter = __toESM(require("gray-matter"));
14079
14583
  init_logger();
14080
14584
 
@@ -14255,13 +14759,13 @@ function extractSkillMetadata(content) {
14255
14759
  // src/commands/skill/validate.ts
14256
14760
  init_paths();
14257
14761
  var fs24 = __toESM(require("fs"));
14258
- var path19 = __toESM(require("path"));
14762
+ var path20 = __toESM(require("path"));
14259
14763
  var skillValidateCommand = new Command("validate").description("Validate local skill files").argument("[skillPath]", "Path to skill file or directory (defaults to ~/.refly/skills)").option("--fix", "Attempt to fix common issues").action(async (skillPath, _options) => {
14260
14764
  try {
14261
14765
  const results = [];
14262
14766
  let targetPath;
14263
14767
  if (skillPath) {
14264
- targetPath = path19.resolve(skillPath);
14768
+ targetPath = path20.resolve(skillPath);
14265
14769
  } else {
14266
14770
  await ensureSkillsDir();
14267
14771
  targetPath = getSkillsDir();
@@ -14331,7 +14835,7 @@ function validateSkillFile(filePath) {
14331
14835
  function findSkillFiles(dir, files = []) {
14332
14836
  const entries = fs24.readdirSync(dir, { withFileTypes: true });
14333
14837
  for (const entry of entries) {
14334
- const fullPath = path19.join(dir, entry.name);
14838
+ const fullPath = path20.join(dir, entry.name);
14335
14839
  if (entry.isDirectory()) {
14336
14840
  if (!entry.name.startsWith(".")) {
14337
14841
  findSkillFiles(fullPath, files);
@@ -14348,7 +14852,7 @@ init_cjs_shims();
14348
14852
  init_symlink();
14349
14853
  init_paths();
14350
14854
  var fs25 = __toESM(require("fs"));
14351
- var path20 = __toESM(require("path"));
14855
+ var path21 = __toESM(require("path"));
14352
14856
  var skillSyncCommand = new Command("sync").description("Validate and repair skill symlinks").option("--dry-run", "Show issues without making changes").option("--fix", "Attempt to repair broken symlinks").option("--prune", "Remove orphan symlinks (symlinks without source directory)").action(async (options) => {
14353
14857
  try {
14354
14858
  const symlinks = listSkillSymlinks();
@@ -14382,7 +14886,7 @@ var skillSyncCommand = new Command("sync").description("Validate and repair skil
14382
14886
  if (entry.isDirectory() && entry.name !== "base") {
14383
14887
  if (!symlinkNames.has(entry.name)) {
14384
14888
  orphans += 1;
14385
- warnings.push(`Orphan directory (no symlink): ${path20.join(skillsDir, entry.name)}`);
14889
+ warnings.push(`Orphan directory (no symlink): ${path21.join(skillsDir, entry.name)}`);
14386
14890
  if (options.prune && !options.dryRun) {
14387
14891
  const result = createSkillSymlink(entry.name);
14388
14892
  if (result.success) {
@@ -14427,12 +14931,12 @@ var skillSyncCommand = new Command("sync").description("Validate and repair skil
14427
14931
  });
14428
14932
 
14429
14933
  // src/commands/skill/index.ts
14430
- var skillCommand = new Command("skill").description("Manage skill packages and local skills").addCommand(skillListCommand).addCommand(skillGetCommand).addCommand(skillCreateCommand).addCommand(skillUpdateCommand).addCommand(skillPublishCommand).addCommand(skillUnpublishCommand).addCommand(skillSearchCommand).addCommand(skillInstallCommand).addCommand(skillUninstallCommand).addCommand(skillInstallationsCommand).addCommand(skillRunCommand).addCommand(skillValidateCommand).addCommand(skillSyncCommand);
14934
+ var skillCommand = new Command("skill").description("Manage skill packages and local skills").addCommand(skillListCommand).addCommand(skillGetCommand).addCommand(skillCreateCommand).addCommand(skillUpdateCommand).addCommand(skillPublishCommand).addCommand(skillUnpublishCommand).addCommand(skillSearchCommand).addCommand(skillInstallCommand).addCommand(skillUninstallCommand).addCommand(skillInstallationsCommand).addCommand(skillRunCommand).addCommand(skillStopCommand).addCommand(skillValidateCommand).addCommand(skillSyncCommand);
14431
14935
 
14432
14936
  // src/bin/refly.ts
14433
14937
  function getVersion() {
14434
14938
  try {
14435
- const pkgPath = path21.join(__dirname, "..", "..", "package.json");
14939
+ const pkgPath = path22.join(__dirname, "..", "..", "package.json");
14436
14940
  const pkg = JSON.parse(fs26.readFileSync(pkgPath, "utf-8"));
14437
14941
  return pkg.version || "0.1.0";
14438
14942
  } catch {