@powerformer/refly-cli 0.1.17 → 0.1.19

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
@@ -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,7 +4887,9 @@ 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
@@ -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.19";
10730
10754
  var NPM_TAG = "test";
10731
10755
  function compareSemver(a, b) {
10732
10756
  const parseVersion = (v) => {
@@ -11362,7 +11386,7 @@ var workflowDeleteCommand = new Command("delete").description("Delete a workflow
11362
11386
  init_cjs_shims();
11363
11387
  var readline2 = __toESM(require("readline/promises"));
11364
11388
  var import_node_process8 = require("process");
11365
- var path10 = __toESM(require("path"));
11389
+ var path9 = __toESM(require("path"));
11366
11390
 
11367
11391
  // src/utils/prompt.ts
11368
11392
  init_cjs_shims();
@@ -11412,33 +11436,157 @@ async function promptForFilePath(variableName, resourceTypes, isRequired) {
11412
11436
 
11413
11437
  // src/utils/file-type.ts
11414
11438
  init_cjs_shims();
11415
- var path9 = __toESM(require("path"));
11439
+ var CODE_FILE_EXTENSIONS = [
11440
+ // TypeScript/JavaScript
11441
+ "ts",
11442
+ "tsx",
11443
+ "js",
11444
+ "jsx",
11445
+ "mjs",
11446
+ "cjs",
11447
+ // Web
11448
+ "css",
11449
+ "scss",
11450
+ "sass",
11451
+ "less",
11452
+ // Other programming languages
11453
+ "py",
11454
+ "java",
11455
+ "c",
11456
+ "cpp",
11457
+ "h",
11458
+ "hpp",
11459
+ "cs",
11460
+ "go",
11461
+ "rs",
11462
+ "rb",
11463
+ "php",
11464
+ "swift",
11465
+ "kt",
11466
+ "scala",
11467
+ "sh",
11468
+ "bash",
11469
+ "zsh",
11470
+ // Config files
11471
+ "json",
11472
+ "yaml",
11473
+ "yml",
11474
+ "toml",
11475
+ "xml",
11476
+ "ini",
11477
+ "env",
11478
+ // Text and document files
11479
+ "txt",
11480
+ "md",
11481
+ "markdown"
11482
+ ];
11416
11483
  var IMAGE_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "ico", "tiff", "tif"];
11417
11484
  var VIDEO_EXTENSIONS = ["mp4", "webm", "mov", "avi", "mkv", "flv", "wmv", "m4v"];
11418
- var AUDIO_EXTENSIONS = ["mp3", "wav", "ogg", "flac", "m4a", "aac", "wma", "opus"];
11419
- function determineFileType(filePath, mimeType) {
11420
- const ext = path9.extname(filePath).slice(1).toLowerCase();
11421
- if (IMAGE_EXTENSIONS.includes(ext)) {
11422
- return "image";
11423
- }
11424
- if (VIDEO_EXTENSIONS.includes(ext)) {
11425
- return "video";
11426
- }
11427
- if (AUDIO_EXTENSIONS.includes(ext)) {
11428
- return "audio";
11429
- }
11485
+ var AUDIO_EXTENSIONS = ["mp3", "wav", "ogg", "flac", "m4a", "aac", "wma", "opus", "mpga"];
11486
+ function getFileExtension(filename) {
11487
+ const lastDotIndex = filename.lastIndexOf(".");
11488
+ if (lastDotIndex === -1 || lastDotIndex === filename.length - 1) {
11489
+ return "";
11490
+ }
11491
+ return filename.slice(lastDotIndex + 1).toLowerCase();
11492
+ }
11493
+ function getFileCategoryByName(filename, mimeType) {
11494
+ const extension = getFileExtension(filename);
11495
+ if (CODE_FILE_EXTENSIONS.includes(extension)) {
11496
+ return "document";
11497
+ }
11498
+ if (IMAGE_EXTENSIONS.includes(extension)) return "image";
11499
+ if (VIDEO_EXTENSIONS.includes(extension)) return "video";
11500
+ if (AUDIO_EXTENSIONS.includes(extension)) return "audio";
11430
11501
  if (mimeType) {
11431
- if (mimeType.startsWith("image/")) {
11432
- return "image";
11433
- }
11434
- if (mimeType.startsWith("video/")) {
11435
- return "video";
11502
+ const mimeTypePrefix = mimeType.split("/")[0].toLowerCase();
11503
+ if (mimeTypePrefix === "image") return "image";
11504
+ if (mimeTypePrefix === "audio") return "audio";
11505
+ if (mimeTypePrefix === "video") return "video";
11506
+ }
11507
+ return "document";
11508
+ }
11509
+ function getFileCategoryByMimeType(mimeType) {
11510
+ if (mimeType.startsWith("image/")) return "image";
11511
+ if (mimeType.startsWith("video/")) return "video";
11512
+ if (mimeType.startsWith("audio/")) return "audio";
11513
+ if (mimeType === "application/pdf") return "document";
11514
+ if (mimeType.includes("word") || mimeType.includes("document")) return "document";
11515
+ if (mimeType.includes("sheet") || mimeType.includes("excel")) return "document";
11516
+ if (mimeType.includes("presentation") || mimeType.includes("powerpoint")) return "document";
11517
+ if (mimeType.startsWith("text/")) return "document";
11518
+ return "document";
11519
+ }
11520
+
11521
+ // src/utils/variable-check.ts
11522
+ init_cjs_shims();
11523
+ function checkRequiredVariables(definitions, providedInput) {
11524
+ const missing = [];
11525
+ const suggestedInput = { ...providedInput };
11526
+ for (const def of definitions) {
11527
+ if (!def.required) continue;
11528
+ const key = def.name;
11529
+ const hasValue = key in providedInput && providedInput[key] !== void 0 && providedInput[key] !== null;
11530
+ if (!hasValue) {
11531
+ missing.push(def);
11532
+ if (def.default !== void 0) {
11533
+ suggestedInput[key] = def.default;
11534
+ } else {
11535
+ suggestedInput[key] = "<value>";
11536
+ }
11436
11537
  }
11437
- if (mimeType.startsWith("audio/")) {
11438
- return "audio";
11538
+ }
11539
+ return {
11540
+ valid: missing.length === 0,
11541
+ missing,
11542
+ suggestedInput
11543
+ };
11544
+ }
11545
+ function buildMissingVariablesError(commandType, targetId, targetName, result) {
11546
+ const displayName = targetName ? `"${targetName}"` : targetId;
11547
+ const inputJson = JSON.stringify(result.suggestedInput);
11548
+ const suggestedCommand = commandType === "workflow" ? `refly workflow run ${targetId} --input '${inputJson}'` : `refly skill run --name <name> --input '${inputJson}'`;
11549
+ return {
11550
+ code: "MISSING_VARIABLES",
11551
+ message: `Missing required variables for ${commandType} ${displayName}`,
11552
+ details: {
11553
+ missingVariables: result.missing.map((v) => ({
11554
+ name: v.name,
11555
+ type: v.variableType || "string",
11556
+ required: true,
11557
+ default: v.default,
11558
+ description: v.description
11559
+ })),
11560
+ suggestedInput: result.suggestedInput,
11561
+ suggestedCommand
11562
+ },
11563
+ hint: "Provide the missing variables via --input. See suggestedInput for the expected format.",
11564
+ suggestedFix: {
11565
+ field: "--input",
11566
+ format: "json-object",
11567
+ example: inputJson
11568
+ },
11569
+ recoverable: true
11570
+ };
11571
+ }
11572
+ function variablesToObject(variables) {
11573
+ const result = {};
11574
+ for (const v of variables) {
11575
+ if (!v.value || v.value.length === 0) continue;
11576
+ const firstValue = v.value[0];
11577
+ if (typeof firstValue === "object" && firstValue !== null) {
11578
+ if ("resource" in firstValue && typeof firstValue.resource === "object") {
11579
+ result[v.name] = firstValue;
11580
+ } else if ("text" in firstValue) {
11581
+ result[v.name] = firstValue.text;
11582
+ } else {
11583
+ result[v.name] = firstValue;
11584
+ }
11585
+ } else {
11586
+ result[v.name] = firstValue;
11439
11587
  }
11440
11588
  }
11441
- return "document";
11589
+ return result;
11442
11590
  }
11443
11591
 
11444
11592
  // src/commands/workflow/run.ts
@@ -11511,6 +11659,11 @@ async function collectFileVariables(workflowId, existingInput, noPrompt) {
11511
11659
  } catch (_error) {
11512
11660
  return [];
11513
11661
  }
11662
+ let savedVariables = [];
11663
+ try {
11664
+ savedVariables = await apiGetWorkflowVariables(workflowId);
11665
+ } catch (_error) {
11666
+ }
11514
11667
  const resourceVars = (workflow.variables ?? []).filter(
11515
11668
  (v) => v.variableType === "resource" && v.required === true
11516
11669
  );
@@ -11518,33 +11671,35 @@ async function collectFileVariables(workflowId, existingInput, noPrompt) {
11518
11671
  return [];
11519
11672
  }
11520
11673
  const invalidFormatVars = [];
11674
+ const hasValidFileValue = (variable) => {
11675
+ if (!variable) return false;
11676
+ const values = variable.value;
11677
+ if (!Array.isArray(values) || values.length === 0) return false;
11678
+ return values.some((val) => {
11679
+ const fileId = val?.resource?.fileId || val?.fileId;
11680
+ return typeof fileId === "string" && fileId.length > 0;
11681
+ });
11682
+ };
11521
11683
  const missingVars = resourceVars.filter((v) => {
11522
- const provided = existingInput.find(
11684
+ const providedInInput = existingInput.find(
11523
11685
  (input3) => v.variableId && input3.variableId === v.variableId || v.name && input3.name === v.name
11524
11686
  );
11525
- if (!provided) {
11526
- return true;
11527
- }
11528
- const values = provided.value;
11529
- if (!Array.isArray(values) || values.length === 0) {
11687
+ const savedValue = savedVariables.find(
11688
+ (saved) => v.variableId && saved.variableId === v.variableId || v.name && saved.name === v.name
11689
+ );
11690
+ if (providedInInput) {
11691
+ if (hasValidFileValue(providedInInput)) {
11692
+ return false;
11693
+ }
11530
11694
  invalidFormatVars.push({
11531
11695
  name: v.name,
11532
- reason: "value must be an array with at least one file"
11696
+ reason: "invalid format in --input"
11533
11697
  });
11534
- return true;
11535
11698
  }
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;
11699
+ if (hasValidFileValue(savedValue)) {
11700
+ return false;
11546
11701
  }
11547
- return false;
11702
+ return true;
11548
11703
  });
11549
11704
  if (missingVars.length === 0) {
11550
11705
  return [];
@@ -11581,7 +11736,7 @@ ${details}`;
11581
11736
  if (!filePath) {
11582
11737
  continue;
11583
11738
  }
11584
- const filename = path10.basename(filePath);
11739
+ const filename = path9.basename(filePath);
11585
11740
  process.stdout.write(` Uploading ${filename}...`);
11586
11741
  try {
11587
11742
  const uploadResult = await apiUploadDriveFile(filePath, workflowId);
@@ -11590,7 +11745,7 @@ ${details}`;
11590
11745
  type: "resource",
11591
11746
  resource: {
11592
11747
  name: uploadResult.name,
11593
- fileType: determineFileType(filePath, uploadResult.type),
11748
+ fileType: getFileCategoryByName(filePath, uploadResult.type),
11594
11749
  fileId: uploadResult.fileId,
11595
11750
  storageKey: uploadResult.storageKey
11596
11751
  }
@@ -11641,7 +11796,7 @@ function convertKeyValueToVariables(obj, workflow) {
11641
11796
  }
11642
11797
  variables.push({
11643
11798
  variableId: varDef?.variableId,
11644
- name,
11799
+ name: varDef?.name || name,
11645
11800
  variableType: "resource",
11646
11801
  value: fileValues,
11647
11802
  required: varDef?.required
@@ -11655,7 +11810,7 @@ function convertKeyValueToVariables(obj, workflow) {
11655
11810
  }
11656
11811
  variables.push({
11657
11812
  variableId: varDef?.variableId,
11658
- name,
11813
+ name: varDef?.name || name,
11659
11814
  variableType: "string",
11660
11815
  value,
11661
11816
  required: varDef?.required
@@ -11693,6 +11848,24 @@ async function runWorkflow(workflowId, options) {
11693
11848
  });
11694
11849
  return;
11695
11850
  }
11851
+ if (options?.noPrompt && workflow?.variables) {
11852
+ const inputObject = variablesToObject(inputVars);
11853
+ const checkResult = checkRequiredVariables(workflow.variables, inputObject);
11854
+ if (!checkResult.valid) {
11855
+ const errorPayload = buildMissingVariablesError(
11856
+ "workflow",
11857
+ workflowId,
11858
+ workflow.name,
11859
+ checkResult
11860
+ );
11861
+ fail(ErrorCodes.MISSING_VARIABLES, errorPayload.message, {
11862
+ details: errorPayload.details,
11863
+ hint: errorPayload.hint,
11864
+ suggestedFix: errorPayload.suggestedFix,
11865
+ recoverable: errorPayload.recoverable
11866
+ });
11867
+ }
11868
+ }
11696
11869
  const uploadedVars = await collectFileVariables(
11697
11870
  workflowId,
11698
11871
  inputVars,
@@ -12207,9 +12380,12 @@ var workflowLayoutCommand = new Command("layout").description("Auto-layout workf
12207
12380
  }
12208
12381
  });
12209
12382
 
12210
- // src/commands/workflow/nodes.ts
12383
+ // src/commands/workflow/node/index.ts
12211
12384
  init_cjs_shims();
12212
- var workflowNodesCommand = new Command("nodes").description("List all nodes in a workflow").argument("<workflowId>", "Workflow ID").option("--include-edges", "Include edge/connection information").option("--include-position", "Include node position coordinates").option("--include-metadata", "Include full node metadata").action(async (workflowId, options) => {
12385
+
12386
+ // src/commands/workflow/node/list.ts
12387
+ init_cjs_shims();
12388
+ var nodeListCommand = new Command("list").description("List all nodes in a workflow").argument("<workflowId>", "Workflow ID").option("--include-edges", "Include edge/connection information").option("--include-position", "Include node position coordinates").option("--include-metadata", "Include full node metadata").action(async (workflowId, options) => {
12213
12389
  try {
12214
12390
  const result = await apiRequest(`/v1/cli/workflow/${workflowId}`);
12215
12391
  const nodes = result.nodes.map((node) => {
@@ -12242,12 +12418,13 @@ var workflowNodesCommand = new Command("nodes").description("List all nodes in a
12242
12418
  }));
12243
12419
  output3.edgeCount = result.edges.length;
12244
12420
  }
12245
- ok("workflow.nodes", output3);
12421
+ ok("workflow.node.list", output3);
12246
12422
  } catch (error) {
12247
12423
  if (error instanceof CLIError) {
12424
+ const hint = error.hint?.replace(/<workflowId>/g, workflowId);
12248
12425
  fail(error.code, error.message, {
12249
12426
  details: error.details,
12250
- hint: error.hint,
12427
+ hint,
12251
12428
  suggestedFix: error.suggestedFix
12252
12429
  });
12253
12430
  }
@@ -12258,9 +12435,9 @@ var workflowNodesCommand = new Command("nodes").description("List all nodes in a
12258
12435
  }
12259
12436
  });
12260
12437
 
12261
- // src/commands/workflow/node-get.ts
12438
+ // src/commands/workflow/node/get.ts
12262
12439
  init_cjs_shims();
12263
- var workflowNodeGetCommand = new Command("node").description("Get single node information from a workflow").argument("<id>", "Workflow ID (c-xxx) or Run ID (we-xxx)").argument("<nodeId>", "Node ID").option("--include-connections", "Include incoming and outgoing connections").action(async (id, nodeId, options) => {
12440
+ var nodeGetCommand = new Command("get").description("Get single node information from a workflow").argument("<id>", "Workflow ID (c-xxx) or Run ID (we-xxx)").argument("<nodeId>", "Node ID").option("--include-connections", "Include incoming and outgoing connections").action(async (id, nodeId, options) => {
12264
12441
  try {
12265
12442
  const idType = detectIdType2(id);
12266
12443
  let workflowId = id;
@@ -12272,7 +12449,7 @@ var workflowNodeGetCommand = new Command("node").description("Get single node in
12272
12449
  const node = result.nodes.find((n) => n.id === nodeId);
12273
12450
  if (!node) {
12274
12451
  fail(ErrorCodes.NODE_NOT_FOUND, `Node ${nodeId} not found in workflow ${workflowId}`, {
12275
- hint: `Use 'refly workflow nodes ${id}' to list all nodes`
12452
+ hint: `Use 'refly workflow node list ${id}' to list all nodes`
12276
12453
  });
12277
12454
  }
12278
12455
  const output3 = {
@@ -12307,12 +12484,13 @@ var workflowNodeGetCommand = new Command("node").description("Get single node in
12307
12484
  outgoingCount: outgoing.length
12308
12485
  };
12309
12486
  }
12310
- ok("workflow.node", output3);
12487
+ ok("workflow.node.get", output3);
12311
12488
  } catch (error) {
12312
12489
  if (error instanceof CLIError) {
12490
+ const hint = error.hint?.replace(/<workflowId>/g, id).replace(/<id>/g, id).replace(/<nodeId>/g, nodeId);
12313
12491
  fail(error.code, error.message, {
12314
12492
  details: error.details,
12315
- hint: error.hint,
12493
+ hint,
12316
12494
  suggestedFix: error.suggestedFix
12317
12495
  });
12318
12496
  }
@@ -12323,9 +12501,9 @@ var workflowNodeGetCommand = new Command("node").description("Get single node in
12323
12501
  }
12324
12502
  });
12325
12503
 
12326
- // src/commands/workflow/node-add.ts
12504
+ // src/commands/workflow/node/add.ts
12327
12505
  init_cjs_shims();
12328
- var workflowNodeAddCommand = new Command("node-add").description("Add a node to a workflow").argument("<workflowId>", "Workflow ID (c-xxx)").requiredOption("--type <type>", "Node type (skillResponse, start, document, resource, memo)").option("--id <nodeId>", "Custom node ID (auto-generated if not provided)").option("--query <query>", "Query/prompt for the node").option("--title <title>", "Node title").option("--toolset-keys <keys>", 'Comma-separated toolset keys (e.g., "web_search,execute_code")').option("--position <x,y>", 'Node position as "x,y" (default: 0,0)').option("--connect-from <nodeId>", "Connect from this node (creates edge)").option("--connect-to <nodeId>", "Connect to this node (creates edge)").option("--resolve-toolset-keys", "Resolve toolset keys to full IDs").option("--auto-layout", "Enable auto-layout to prevent overlapping").action(async (workflowId, options) => {
12506
+ var nodeAddCommand = new Command("add").description("Add a node to a workflow").argument("<workflowId>", "Workflow ID (c-xxx)").requiredOption("--type <type>", "Node type (skillResponse, start, document, resource, memo)").option("--id <nodeId>", "Custom node ID (auto-generated if not provided)").option("--query <query>", "Query/prompt for the node").option("--title <title>", "Node title").option("--toolset-keys <keys>", 'Comma-separated toolset keys (e.g., "web_search,execute_code")').option("--position <x,y>", 'Node position as "x,y" (default: 0,0)').option("--connect-from <nodeId>", "Connect from this node (creates edge)").option("--connect-to <nodeId>", "Connect to this node (creates edge)").option("--resolve-toolset-keys", "Resolve toolset keys to full IDs").option("--auto-layout", "Enable auto-layout to prevent overlapping").action(async (workflowId, options) => {
12329
12507
  if (!workflowId.startsWith("c-")) {
12330
12508
  fail(ErrorCodes.INVALID_INPUT, `Invalid workflow ID: ${workflowId}`, {
12331
12509
  hint: 'Workflow ID should start with "c-"',
@@ -12424,15 +12602,16 @@ var workflowNodeAddCommand = new Command("node-add").description("Add a node to
12424
12602
  ...options.connectFrom && { connectedFrom: options.connectFrom },
12425
12603
  ...options.connectTo && { connectedTo: options.connectTo },
12426
12604
  nextSteps: [
12427
- `View node: \`refly workflow node ${workflowId} ${nodeId}\``,
12428
- `List all nodes: \`refly workflow nodes ${workflowId}\``
12605
+ `View node: \`refly workflow node get ${workflowId} ${nodeId}\``,
12606
+ `List all nodes: \`refly workflow node list ${workflowId}\``
12429
12607
  ]
12430
12608
  });
12431
12609
  } catch (error) {
12432
12610
  if (error instanceof CLIError) {
12611
+ const hint = error.hint?.replace(/<workflowId>/g, workflowId);
12433
12612
  fail(error.code, error.message, {
12434
12613
  details: error.details,
12435
- hint: error.hint,
12614
+ hint,
12436
12615
  suggestedFix: error.suggestedFix
12437
12616
  });
12438
12617
  return;
@@ -12444,9 +12623,9 @@ var workflowNodeAddCommand = new Command("node-add").description("Add a node to
12444
12623
  }
12445
12624
  });
12446
12625
 
12447
- // src/commands/workflow/node-update.ts
12626
+ // src/commands/workflow/node/update.ts
12448
12627
  init_cjs_shims();
12449
- var workflowNodeUpdateCommand = new Command("node-update").description("Update a node in a workflow").argument("<workflowId>", "Workflow ID (c-xxx)").argument("<nodeId>", "Node ID to update").option("--query <query>", "Update the query/prompt for the node").option("--title <title>", "Update the node title").option("--toolset-keys <keys>", 'Comma-separated toolset keys (e.g., "web_search,execute_code")').option("--data <json>", "Full node data as JSON (advanced usage)").option("--resolve-toolset-keys", "Resolve toolset keys to full IDs").action(async (workflowId, nodeId, options) => {
12628
+ var nodeUpdateCommand = new Command("update").description("Update a node in a workflow").argument("<workflowId>", "Workflow ID (c-xxx)").argument("<nodeId>", "Node ID to update").option("--query <query>", "Update the query/prompt for the node").option("--title <title>", "Update the node title").option("--toolset-keys <keys>", 'Comma-separated toolset keys (e.g., "web_search,execute_code")').option("--data <json>", "Full node data as JSON (advanced usage)").option("--resolve-toolset-keys", "Resolve toolset keys to full IDs").action(async (workflowId, nodeId, options) => {
12450
12629
  if (!workflowId.startsWith("c-")) {
12451
12630
  fail(ErrorCodes.INVALID_INPUT, `Invalid workflow ID: ${workflowId}`, {
12452
12631
  hint: 'Workflow ID should start with "c-"',
@@ -12536,15 +12715,16 @@ var workflowNodeUpdateCommand = new Command("node-update").description("Update a
12536
12715
  ...options.data && { data: "custom data applied" }
12537
12716
  },
12538
12717
  nextSteps: [
12539
- `View updated node: \`refly workflow node ${workflowId} ${nodeId}\``,
12540
- `List all nodes: \`refly workflow nodes ${workflowId}\``
12718
+ `View updated node: \`refly workflow node get ${workflowId} ${nodeId}\``,
12719
+ `List all nodes: \`refly workflow node list ${workflowId}\``
12541
12720
  ]
12542
12721
  });
12543
12722
  } catch (error) {
12544
12723
  if (error instanceof CLIError) {
12724
+ const hint = error.hint?.replace(/<workflowId>/g, workflowId).replace(/<nodeId>/g, nodeId);
12545
12725
  fail(error.code, error.message, {
12546
12726
  details: error.details,
12547
- hint: error.hint,
12727
+ hint,
12548
12728
  suggestedFix: error.suggestedFix
12549
12729
  });
12550
12730
  return;
@@ -12556,9 +12736,9 @@ var workflowNodeUpdateCommand = new Command("node-update").description("Update a
12556
12736
  }
12557
12737
  });
12558
12738
 
12559
- // src/commands/workflow/node-delete.ts
12739
+ // src/commands/workflow/node/delete.ts
12560
12740
  init_cjs_shims();
12561
- var workflowNodeDeleteCommand = new Command("node-delete").description("Delete a node from a workflow").argument("<workflowId>", "Workflow ID (c-xxx)").argument("<nodeId>", "Node ID to delete").action(async (workflowId, nodeId) => {
12741
+ var nodeDeleteCommand = new Command("delete").description("Delete a node from a workflow").argument("<workflowId>", "Workflow ID (c-xxx)").argument("<nodeId>", "Node ID to delete").action(async (workflowId, nodeId) => {
12562
12742
  if (!workflowId.startsWith("c-")) {
12563
12743
  fail(ErrorCodes.INVALID_INPUT, `Invalid workflow ID: ${workflowId}`, {
12564
12744
  hint: 'Workflow ID should start with "c-"',
@@ -12588,13 +12768,14 @@ var workflowNodeDeleteCommand = new Command("node-delete").description("Delete a
12588
12768
  workflowId,
12589
12769
  nodeId,
12590
12770
  note: "Connected edges were also removed",
12591
- nextSteps: [`List remaining nodes: \`refly workflow nodes ${workflowId}\``]
12771
+ nextSteps: [`List remaining nodes: \`refly workflow node list ${workflowId}\``]
12592
12772
  });
12593
12773
  } catch (error) {
12594
12774
  if (error instanceof CLIError) {
12775
+ const hint = error.hint?.replace(/<workflowId>/g, workflowId).replace(/<nodeId>/g, nodeId);
12595
12776
  fail(error.code, error.message, {
12596
12777
  details: error.details,
12597
- hint: error.hint,
12778
+ hint,
12598
12779
  suggestedFix: error.suggestedFix
12599
12780
  });
12600
12781
  return;
@@ -12606,9 +12787,9 @@ var workflowNodeDeleteCommand = new Command("node-delete").description("Delete a
12606
12787
  }
12607
12788
  });
12608
12789
 
12609
- // src/commands/workflow/node-output.ts
12790
+ // src/commands/workflow/node/output.ts
12610
12791
  init_cjs_shims();
12611
- var workflowNodeOutputCommand = new Command("node-output").description("Get node execution output content").argument("<id>", "Workflow ID (c-xxx) or Run ID (we-xxx)").argument("<nodeId>", "Node ID").option("--include-tool-calls", "Include tool call details in output").option("--raw", "Output raw content without formatting").action(async (id, nodeId, options) => {
12792
+ var nodeOutputCommand = new Command("output").description("Get node execution output content").argument("<id>", "Workflow ID (c-xxx) or Run ID (we-xxx)").argument("<nodeId>", "Node ID").option("--include-tool-calls", "Include tool call details in output").option("--raw", "Output raw content without formatting").action(async (id, nodeId, options) => {
12612
12793
  try {
12613
12794
  const params = new URLSearchParams();
12614
12795
  if (options.includeToolCalls) {
@@ -12620,7 +12801,7 @@ var workflowNodeOutputCommand = new Command("node-output").description("Get node
12620
12801
  const idType = detectIdType2(id);
12621
12802
  const url = buildWorkflowApiUrl(id, `node/${nodeId}/output`, params);
12622
12803
  const result = await apiRequest(url);
12623
- ok("workflow.nodeOutput", {
12804
+ ok("workflow.node.output", {
12624
12805
  runId: result.runId,
12625
12806
  workflowId: result.workflowId,
12626
12807
  idType,
@@ -12641,9 +12822,10 @@ var workflowNodeOutputCommand = new Command("node-output").description("Get node
12641
12822
  });
12642
12823
  } catch (error) {
12643
12824
  if (error instanceof CLIError) {
12825
+ const hint = error.hint?.replace(/<workflowId>/g, id).replace(/<id>/g, id);
12644
12826
  fail(error.code, error.message, {
12645
12827
  details: error.details,
12646
- hint: error.hint,
12828
+ hint,
12647
12829
  suggestedFix: error.suggestedFix
12648
12830
  });
12649
12831
  }
@@ -12651,140 +12833,412 @@ var workflowNodeOutputCommand = new Command("node-output").description("Get node
12651
12833
  ErrorCodes.INTERNAL_ERROR,
12652
12834
  error instanceof Error ? error.message : "Failed to get node output",
12653
12835
  {
12654
- hint: "Ensure the node has completed execution. Use `refly workflow status <id>` to check."
12836
+ hint: `Ensure the node has completed execution. Use \`refly workflow status ${id}\` to check.`
12655
12837
  }
12656
12838
  );
12657
12839
  }
12658
12840
  });
12659
12841
 
12842
+ // src/commands/workflow/node/index.ts
12843
+ var workflowNodeCommand = new Command("node").description("Manage workflow nodes").addCommand(nodeListCommand).addCommand(nodeGetCommand).addCommand(nodeAddCommand).addCommand(nodeUpdateCommand).addCommand(nodeDeleteCommand).addCommand(nodeOutputCommand);
12844
+
12660
12845
  // src/commands/workflow/edit.ts
12661
12846
  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) => {
12847
+ 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
12848
  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
- });
12849
+ if (!options.query) {
12850
+ fail(ErrorCodes.INVALID_INPUT, "--query is required", {
12851
+ hint: "Provide a natural language description of the edit you want to make",
12852
+ suggestedFix: {
12853
+ field: "--query",
12854
+ format: "string",
12855
+ example: 'refly workflow edit c-xxx --query "\u6DFB\u52A0\u4E00\u4E2A\u7528 nano banana \u751F\u6210\u56FE\u7247\u7684\u4EFB\u52A1"'
12691
12856
  }
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
- );
12857
+ });
12858
+ }
12859
+ if (!id.startsWith("c-")) {
12860
+ fail(ErrorCodes.INVALID_INPUT, "Only Canvas ID (c-xxx) is supported", {
12861
+ hint: 'Use the Canvas ID format starting with "c-"',
12862
+ suggestedFix: {
12863
+ field: "id",
12864
+ format: "canvas-id",
12865
+ example: "c-abc123"
12866
+ }
12867
+ });
12868
+ }
12869
+ const timeout = Number.parseInt(options.timeout);
12870
+ const response = await apiRequest(
12871
+ "/v1/cli/workflow/edit",
12872
+ {
12873
+ method: "POST",
12874
+ body: {
12875
+ canvasId: id,
12876
+ query: options.query,
12877
+ sessionId: options.sessionId,
12878
+ timeout
12879
+ },
12880
+ timeout: timeout + 5e3
12881
+ // Add buffer for network
12882
+ }
12883
+ );
12884
+ const result = response.data ?? response;
12885
+ ok("workflow.edit", {
12886
+ canvasId: result.canvasId,
12887
+ planId: result.planId,
12888
+ version: result.version,
12889
+ toolUsed: result.toolUsed,
12890
+ sessionId: result.sessionId,
12891
+ plan: {
12892
+ title: result.plan.title,
12893
+ taskCount: result.plan.tasks?.length ?? 0,
12894
+ variableCount: result.plan.variables?.length ?? 0,
12895
+ tasks: result.plan.tasks?.map((t) => ({
12896
+ id: t.id,
12897
+ title: t.title
12898
+ })),
12899
+ variables: result.plan.variables?.map((v) => ({
12900
+ variableId: v.variableId,
12901
+ name: v.name
12902
+ }))
12706
12903
  }
12904
+ });
12905
+ } catch (error) {
12906
+ if (error instanceof CLIError) {
12907
+ fail(error.code, error.message, {
12908
+ details: error.details,
12909
+ hint: error.hint,
12910
+ suggestedFix: error.suggestedFix
12911
+ });
12707
12912
  }
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,
12913
+ fail(
12914
+ ErrorCodes.INTERNAL_ERROR,
12915
+ error instanceof Error ? error.message : "Failed to edit workflow"
12916
+ );
12917
+ }
12918
+ });
12919
+
12920
+ // src/commands/workflow/variables.ts
12921
+ init_cjs_shims();
12922
+ async function getFileMetadata(fileId) {
12923
+ try {
12924
+ return await apiRequest(`/v1/cli/drive/files/${fileId}?includeContent=false`);
12925
+ } catch {
12926
+ return null;
12927
+ }
12928
+ }
12929
+ function parseVarArgs(varArgs) {
12930
+ const result = {};
12931
+ for (const arg of varArgs) {
12932
+ const eqIndex = arg.indexOf("=");
12933
+ if (eqIndex === -1) {
12934
+ throw new CLIError(
12935
+ ErrorCodes.INVALID_INPUT,
12936
+ `Invalid --var format: "${arg}"`,
12937
+ void 0,
12938
+ "Use format: --var key=value"
12939
+ );
12940
+ }
12941
+ const key = arg.slice(0, eqIndex);
12942
+ const value = arg.slice(eqIndex + 1);
12943
+ result[key] = value;
12944
+ }
12945
+ return result;
12946
+ }
12947
+ function formatVariable(v) {
12948
+ const hasValue = Array.isArray(v.value) && v.value.length > 0;
12949
+ return {
12950
+ name: v.name,
12951
+ variableId: v.variableId,
12952
+ type: v.variableType || "string",
12953
+ required: v.required ?? false,
12954
+ hasValue,
12955
+ value: hasValue ? v.value : void 0,
12956
+ description: v.description
12957
+ };
12958
+ }
12959
+ var variablesListCommand = new Command("list").description("List workflow variables with current values").argument("<workflowId>", "Workflow ID (canvas ID)").action(async (workflowId) => {
12960
+ try {
12961
+ const variables = await apiGetWorkflowVariables(workflowId);
12962
+ const formatted = variables.map(formatVariable);
12963
+ ok("workflow.variables.list", {
12964
+ workflowId,
12965
+ variables: formatted,
12966
+ count: variables.length
12967
+ });
12968
+ } catch (error) {
12969
+ if (error instanceof CLIError) {
12970
+ fail(error.code, error.message, {
12971
+ details: error.details,
12972
+ hint: error.hint,
12973
+ suggestedFix: error.suggestedFix
12974
+ });
12975
+ }
12976
+ fail(
12977
+ ErrorCodes.INTERNAL_ERROR,
12978
+ error instanceof Error ? error.message : "Failed to list variables"
12979
+ );
12980
+ }
12981
+ });
12982
+ 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) => {
12983
+ try {
12984
+ const variables = await apiGetWorkflowVariables(workflowId);
12985
+ const variable = variables.find((v) => v.name === varName || v.variableId === varName);
12986
+ if (!variable) {
12987
+ const availableNames = variables.map((v) => v.name).join(", ");
12988
+ fail(ErrorCodes.NOT_FOUND, `Variable not found: ${varName}`, {
12989
+ hint: `Available variables: ${availableNames}`
12990
+ });
12991
+ return;
12992
+ }
12993
+ ok("workflow.variables.get", {
12994
+ workflowId,
12995
+ variable: formatVariable(variable)
12996
+ });
12997
+ } catch (error) {
12998
+ if (error instanceof CLIError) {
12999
+ fail(error.code, error.message, {
13000
+ details: error.details,
13001
+ hint: error.hint,
13002
+ suggestedFix: error.suggestedFix
13003
+ });
13004
+ }
13005
+ fail(
13006
+ ErrorCodes.INTERNAL_ERROR,
13007
+ error instanceof Error ? error.message : "Failed to get variable"
13008
+ );
13009
+ }
13010
+ });
13011
+ 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(
13012
+ async (workflowId, options) => {
13013
+ try {
13014
+ const currentVars = await apiGetWorkflowVariables(workflowId);
13015
+ let newValues = {};
13016
+ if (options.input) {
13017
+ try {
13018
+ const parsed = JSON.parse(options.input);
13019
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
13020
+ fail(ErrorCodes.INVALID_INPUT, "Input must be a JSON object", {
13021
+ hint: `Use format: '{"varName": "value"}'`,
13022
+ suggestedFix: {
13023
+ field: "--input",
13024
+ format: "json-object",
13025
+ example: '{"varName": "value"}'
13026
+ }
13027
+ });
13028
+ }
13029
+ newValues = { ...parsed };
13030
+ } catch {
13031
+ fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --input", {
13032
+ hint: "Ensure the input is valid JSON",
12716
13033
  suggestedFix: {
12717
- field: "--ops",
12718
- format: "json-array",
12719
- example: '[{"op": "updateTitle", "title": "New Title"}]'
13034
+ field: "--input",
13035
+ format: "json-object",
13036
+ example: '{"varName": "value"}'
12720
13037
  }
12721
13038
  });
12722
13039
  }
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"}]'
13040
+ }
13041
+ if (options.var && options.var.length > 0) {
13042
+ const varBindings = parseVarArgs(options.var);
13043
+ newValues = { ...newValues, ...varBindings };
13044
+ }
13045
+ if (options.clear) {
13046
+ newValues[options.clear] = null;
13047
+ }
13048
+ if (Object.keys(newValues).length === 0) {
13049
+ fail(ErrorCodes.INVALID_INPUT, "No variables specified", {
13050
+ hint: `Use --var key=value, --input '{"key": "value"}', or --clear <name>`
13051
+ });
13052
+ }
13053
+ const fileIds = Object.values(newValues).filter(
13054
+ (v) => typeof v === "string" && v.startsWith("df-")
13055
+ );
13056
+ const fileMetadataMap = /* @__PURE__ */ new Map();
13057
+ for (const fileId of fileIds) {
13058
+ const metadata = await getFileMetadata(fileId);
13059
+ if (metadata) {
13060
+ fileMetadataMap.set(fileId, metadata);
13061
+ }
13062
+ }
13063
+ const updatedVars = currentVars.map((v) => {
13064
+ const name = v.name;
13065
+ if (name in newValues) {
13066
+ const newValue = newValues[name];
13067
+ if (newValue === null) {
13068
+ return { ...v, value: [] };
13069
+ }
13070
+ if (typeof newValue === "string") {
13071
+ if (newValue.startsWith("df-")) {
13072
+ const metadata = fileMetadataMap.get(newValue);
13073
+ return {
13074
+ ...v,
13075
+ value: [
13076
+ {
13077
+ type: "resource",
13078
+ resource: {
13079
+ fileId: newValue,
13080
+ name: metadata?.name || "",
13081
+ fileType: metadata ? getFileCategoryByMimeType(metadata.type) : "document",
13082
+ storageKey: metadata?.storageKey || ""
13083
+ }
13084
+ }
13085
+ ]
13086
+ };
13087
+ }
13088
+ return {
13089
+ ...v,
13090
+ value: [{ type: "text", text: newValue }]
13091
+ };
13092
+ }
13093
+ if (Array.isArray(newValue)) {
13094
+ return { ...v, value: newValue };
12730
13095
  }
13096
+ return v;
13097
+ }
13098
+ return v;
13099
+ });
13100
+ const definedNames = new Set(currentVars.map((v) => v.name));
13101
+ const unknownVars = Object.keys(newValues).filter((k) => !definedNames.has(k));
13102
+ if (unknownVars.length > 0) {
13103
+ fail(ErrorCodes.INVALID_INPUT, `Unknown variables: ${unknownVars.join(", ")}`, {
13104
+ hint: `Available variables: ${Array.from(definedNames).join(", ")}`
12731
13105
  });
12732
13106
  }
12733
- }
12734
- if (options.updateTitle) {
12735
- operations.push({
12736
- op: "updateTitle",
12737
- title: options.updateTitle
13107
+ const result = await apiUpdateWorkflowVariables(workflowId, updatedVars);
13108
+ ok("workflow.variables.set", {
13109
+ workflowId,
13110
+ updated: Object.keys(newValues),
13111
+ variables: result.map(formatVariable)
12738
13112
  });
13113
+ } catch (error) {
13114
+ if (error instanceof CLIError) {
13115
+ fail(error.code, error.message, {
13116
+ details: error.details,
13117
+ hint: error.hint,
13118
+ suggestedFix: error.suggestedFix
13119
+ });
13120
+ }
13121
+ fail(
13122
+ ErrorCodes.INTERNAL_ERROR,
13123
+ error instanceof Error ? error.message : "Failed to set variables"
13124
+ );
12739
13125
  }
12740
- if (options.deleteTask) {
12741
- operations.push({
12742
- op: "deleteTask",
12743
- taskId: options.deleteTask
12744
- });
13126
+ }
13127
+ );
13128
+ var workflowVariablesCommand = new Command("variables").description("Manage workflow variable values").addCommand(variablesListCommand).addCommand(variablesGetCommand).addCommand(variablesSetCommand);
13129
+
13130
+ // src/commands/workflow/result.ts
13131
+ init_cjs_shims();
13132
+ function formatResult(result, options) {
13133
+ const output3 = {
13134
+ resultId: result.resultId,
13135
+ version: result.version,
13136
+ title: result.title,
13137
+ type: result.type,
13138
+ status: result.status
13139
+ };
13140
+ if (result.workflowExecutionId) {
13141
+ output3.workflowExecutionId = result.workflowExecutionId;
13142
+ }
13143
+ if (result.workflowNodeExecutionId) {
13144
+ output3.workflowNodeExecutionId = result.workflowNodeExecutionId;
13145
+ }
13146
+ output3.timing = {
13147
+ createdAt: result.createdAt,
13148
+ updatedAt: result.updatedAt
13149
+ };
13150
+ if (result.errors && result.errors.length > 0) {
13151
+ output3.errors = result.errors;
13152
+ }
13153
+ if (result.errorType) {
13154
+ output3.errorType = result.errorType;
13155
+ }
13156
+ if (result.outputUrl) {
13157
+ output3.outputUrl = result.outputUrl;
13158
+ }
13159
+ if (result.files && result.files.length > 0) {
13160
+ output3.files = result.files;
13161
+ }
13162
+ if (result.modelInfo) {
13163
+ output3.modelInfo = result.modelInfo;
13164
+ }
13165
+ if (options.includeSteps && result.steps) {
13166
+ if (options.raw) {
13167
+ output3.steps = result.steps;
13168
+ } else {
13169
+ output3.steps = result.steps.map((step) => ({
13170
+ name: step.name,
13171
+ contentPreview: step.content?.substring(0, 200) + (step.content && step.content.length > 200 ? "..." : ""),
13172
+ toolCallsCount: step.toolCalls?.length || 0,
13173
+ ...options.includeToolCalls && step.toolCalls ? {
13174
+ toolCalls: step.toolCalls.map((tc) => ({
13175
+ callId: tc.callId,
13176
+ toolName: tc.toolName,
13177
+ status: tc.status,
13178
+ ...options.raw ? { input: tc.input, output: tc.output } : {},
13179
+ ...tc.error ? { error: tc.error } : {}
13180
+ }))
13181
+ } : {}
13182
+ }));
12745
13183
  }
12746
- if (options.deleteVariable) {
12747
- operations.push({
12748
- op: "deleteVariable",
12749
- variableId: options.deleteVariable
12750
- });
13184
+ }
13185
+ if (options.includeMessages && result.messages) {
13186
+ if (options.raw) {
13187
+ output3.messages = result.messages;
13188
+ } else {
13189
+ output3.messages = result.messages.map((msg) => ({
13190
+ messageId: msg.messageId,
13191
+ type: msg.type,
13192
+ contentPreview: msg.content?.substring(0, 200) + (msg.content && msg.content.length > 200 ? "..." : ""),
13193
+ createdAt: msg.createdAt
13194
+ }));
12751
13195
  }
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)",
13196
+ }
13197
+ return output3;
13198
+ }
13199
+ 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) => {
13200
+ try {
13201
+ if (!resultId.startsWith("ar-") && !resultId.startsWith("start-")) {
13202
+ return fail(ErrorCodes.INVALID_INPUT, `Invalid resultId format: ${resultId}`, {
13203
+ hint: 'Result ID should start with "ar-" or "start-"',
12755
13204
  suggestedFix: {
12756
- field: "--ops",
12757
- format: "json-array",
12758
- example: '[{"op": "updateTitle", "title": "New Title"}]'
13205
+ field: "resultId",
13206
+ format: "ar-xxx or start-xxx",
13207
+ example: "ar-cq18zd4qr97nbla1tu1rqqmd"
12759
13208
  }
12760
13209
  });
12761
13210
  }
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
- }
13211
+ const result = await apiGetActionResult(resultId);
13212
+ const formattedResult = formatResult(result, {
13213
+ includeSteps: options.includeSteps,
13214
+ includeMessages: options.includeMessages,
13215
+ includeToolCalls: options.includeToolCalls,
13216
+ raw: options.raw
12787
13217
  });
13218
+ ok("workflow.result", formattedResult);
13219
+ } catch (error) {
13220
+ if (error instanceof CLIError) {
13221
+ fail(error.code, error.message, {
13222
+ details: error.details,
13223
+ hint: error.hint,
13224
+ suggestedFix: error.suggestedFix
13225
+ });
13226
+ }
13227
+ fail(
13228
+ ErrorCodes.INTERNAL_ERROR,
13229
+ error instanceof Error ? error.message : "Failed to get action result"
13230
+ );
13231
+ }
13232
+ });
13233
+
13234
+ // src/commands/workflow/session.ts
13235
+ init_cjs_shims();
13236
+ var workflowSessionCommand = new Command("session").description("Get the latest copilot session for a workflow").argument("<workflowId>", "Workflow ID (canvas ID)").action(async (workflowId) => {
13237
+ try {
13238
+ const result = await apiRequest(
13239
+ `/v1/cli/workflow/${workflowId}/session`
13240
+ );
13241
+ ok("workflow.session", result);
12788
13242
  } catch (error) {
12789
13243
  if (error instanceof CLIError) {
12790
13244
  fail(error.code, error.message, {
@@ -12792,17 +13246,16 @@ Examples:
12792
13246
  hint: error.hint,
12793
13247
  suggestedFix: error.suggestedFix
12794
13248
  });
12795
- return;
12796
13249
  }
12797
13250
  fail(
12798
13251
  ErrorCodes.INTERNAL_ERROR,
12799
- error instanceof Error ? error.message : "Failed to edit workflow plan"
13252
+ error instanceof Error ? error.message : "Failed to get workflow session"
12800
13253
  );
12801
13254
  }
12802
13255
  });
12803
13256
 
12804
13257
  // 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);
13258
+ 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(workflowNodeCommand).addCommand(workflowEditCommand).addCommand(workflowVariablesCommand).addCommand(workflowSessionCommand).addCommand(workflowResultCommand);
12806
13259
 
12807
13260
  // src/commands/tool/index.ts
12808
13261
  init_cjs_shims();
@@ -12982,16 +13435,16 @@ var fileGetCommand = new Command("get").description("Get file details").argument
12982
13435
 
12983
13436
  // src/commands/file/download.ts
12984
13437
  init_cjs_shims();
12985
- var fs15 = __toESM(require("fs"));
12986
- var path11 = __toESM(require("path"));
13438
+ var fs14 = __toESM(require("fs"));
13439
+ var path10 = __toESM(require("path"));
12987
13440
  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
13441
  try {
12989
13442
  const { data, filename, contentType, size } = await apiRequestStream(
12990
13443
  `/v1/cli/drive/files/${fileId}/download`
12991
13444
  );
12992
13445
  const outputPath = options.output || filename || `${fileId}`;
12993
- const resolvedPath = path11.resolve(outputPath);
12994
- fs15.writeFileSync(resolvedPath, data);
13446
+ const resolvedPath = path10.resolve(outputPath);
13447
+ fs14.writeFileSync(resolvedPath, data);
12995
13448
  ok("file.download", {
12996
13449
  fileId,
12997
13450
  path: resolvedPath,
@@ -13016,8 +13469,8 @@ var fileDownloadCommand = new Command("download").description("Download file to
13016
13469
 
13017
13470
  // src/commands/file/upload.ts
13018
13471
  init_cjs_shims();
13019
- var fs16 = __toESM(require("fs"));
13020
- var path12 = __toESM(require("path"));
13472
+ var fs15 = __toESM(require("fs"));
13473
+ var path11 = __toESM(require("path"));
13021
13474
  var MAX_FILES = 10;
13022
13475
  function formatSize(bytes) {
13023
13476
  if (bytes < 1024) return `${bytes}B`;
@@ -13027,8 +13480,8 @@ function formatSize(bytes) {
13027
13480
  var fileUploadCommand = new Command("upload").description("Upload file(s) to a canvas").argument("<path>", "File or directory path").requiredOption("--canvas-id <id>", "Canvas ID (required)").option("--filter <extensions>", "Filter by extensions (e.g., pdf,docx,png)").action(async (inputPath, options) => {
13028
13481
  const formatter = getFormatter();
13029
13482
  try {
13030
- const resolvedPath = path12.resolve(inputPath);
13031
- if (!fs16.existsSync(resolvedPath)) {
13483
+ const resolvedPath = path11.resolve(inputPath);
13484
+ if (!fs15.existsSync(resolvedPath)) {
13032
13485
  fail(ErrorCodes.NOT_FOUND, `Path not found: ${inputPath}`, {
13033
13486
  hint: "Check if the file or directory exists"
13034
13487
  });
@@ -13046,8 +13499,8 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
13046
13499
  const errors = [];
13047
13500
  for (let i = 0; i < files.length; i++) {
13048
13501
  const filePath = files[i];
13049
- const filename = path12.basename(filePath);
13050
- const fileStats = fs16.statSync(filePath);
13502
+ const filename = path11.basename(filePath);
13503
+ const fileStats = fs15.statSync(filePath);
13051
13504
  const sizeStr = formatSize(fileStats.size);
13052
13505
  let currentStage = "presign";
13053
13506
  const updateProgress = () => {
@@ -13128,11 +13581,11 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
13128
13581
  }
13129
13582
  });
13130
13583
  function resolveFilesToUpload(inputPath, filter) {
13131
- const stats = fs16.statSync(inputPath);
13584
+ const stats = fs15.statSync(inputPath);
13132
13585
  if (stats.isFile()) {
13133
13586
  if (filter) {
13134
13587
  const filterExts = filter.split(",").map((e) => e.trim().toLowerCase());
13135
- const ext = path12.extname(inputPath).slice(1).toLowerCase();
13588
+ const ext = path11.extname(inputPath).slice(1).toLowerCase();
13136
13589
  if (!filterExts.includes(ext)) {
13137
13590
  return [];
13138
13591
  }
@@ -13140,21 +13593,21 @@ function resolveFilesToUpload(inputPath, filter) {
13140
13593
  return [inputPath];
13141
13594
  }
13142
13595
  if (stats.isDirectory()) {
13143
- const entries = fs16.readdirSync(inputPath);
13596
+ const entries = fs15.readdirSync(inputPath);
13144
13597
  const filterExts = filter?.split(",").map((e) => e.trim().toLowerCase());
13145
- const files = entries.map((e) => path12.join(inputPath, e)).filter((p) => {
13598
+ const files = entries.map((e) => path11.join(inputPath, e)).filter((p) => {
13146
13599
  try {
13147
- return fs16.statSync(p).isFile();
13600
+ return fs15.statSync(p).isFile();
13148
13601
  } catch {
13149
13602
  return false;
13150
13603
  }
13151
13604
  }).filter((p) => {
13152
13605
  if (!filterExts) return true;
13153
- const ext = path12.extname(p).slice(1).toLowerCase();
13606
+ const ext = path11.extname(p).slice(1).toLowerCase();
13154
13607
  return filterExts.includes(ext);
13155
13608
  }).sort((a, b) => {
13156
13609
  try {
13157
- return fs16.statSync(a).size - fs16.statSync(b).size;
13610
+ return fs15.statSync(a).size - fs15.statSync(b).size;
13158
13611
  } catch {
13159
13612
  return 0;
13160
13613
  }
@@ -13258,7 +13711,7 @@ var skillGetCommand = new Command("get").description("Get skill package details"
13258
13711
 
13259
13712
  // src/commands/skill/create.ts
13260
13713
  init_cjs_shims();
13261
- var fs17 = __toESM(require("fs"));
13714
+ var fs16 = __toESM(require("fs"));
13262
13715
  init_symlink();
13263
13716
  init_paths();
13264
13717
  init_logger();
@@ -13304,13 +13757,13 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
13304
13757
  });
13305
13758
  const result = response.payload;
13306
13759
  let localPath;
13307
- let symlinkPath;
13760
+ let _symlinkPath;
13308
13761
  if (result.workflowId) {
13309
13762
  try {
13310
13763
  const localName = options.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
13311
13764
  const skillDir = getReflyDomainSkillDir(localName);
13312
13765
  const symlinkStatus = isSkillSymlinkValid(localName);
13313
- if (fs17.existsSync(skillDir) || symlinkStatus.exists) {
13766
+ if (fs16.existsSync(skillDir) || symlinkStatus.exists) {
13314
13767
  logger.debug(`Local skill '${localName}' already exists, skipping sync`);
13315
13768
  } else {
13316
13769
  const skillMdContent = generateReflySkillMd({
@@ -13328,7 +13781,7 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
13328
13781
  const symlinkResult = createReflySkillWithSymlink(localName, skillMdContent);
13329
13782
  if (symlinkResult.success) {
13330
13783
  localPath = symlinkResult.reflyPath;
13331
- symlinkPath = symlinkResult.claudePath;
13784
+ _symlinkPath = symlinkResult.claudePath;
13332
13785
  logger.info(`Created local domain skill: ${localName}`);
13333
13786
  } else {
13334
13787
  logger.warn(`Failed to create local skill: ${symlinkResult.error}`);
@@ -13338,18 +13791,17 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
13338
13791
  logger.warn(`Failed to sync to local: ${syncError.message}`);
13339
13792
  }
13340
13793
  }
13794
+ const webUrl = getWebUrl();
13341
13795
  const payload = {
13342
13796
  skillId: result.skillId,
13797
+ installationId: result.installationId,
13343
13798
  name: result.name,
13344
13799
  status: result.status,
13345
13800
  createdAt: result.createdAt,
13346
13801
  workflowId: result.workflowId,
13347
- url: `${getWebUrl()}/skill/${result.skillId}`
13802
+ workflowUrl: result.workflowId ? `${webUrl}/workflow/${result.workflowId}` : void 0,
13803
+ localPath
13348
13804
  };
13349
- if (localPath) {
13350
- payload.localPath = localPath;
13351
- payload.symlinkPath = symlinkPath;
13352
- }
13353
13805
  if (options.verbose) {
13354
13806
  payload.workflowIds = result.workflowIds;
13355
13807
  payload.workflows = result.workflows;
@@ -13373,8 +13825,8 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
13373
13825
 
13374
13826
  // src/commands/skill/update.ts
13375
13827
  init_cjs_shims();
13376
- var fs18 = __toESM(require("fs"));
13377
- var path13 = __toESM(require("path"));
13828
+ var fs17 = __toESM(require("fs"));
13829
+ var path12 = __toESM(require("path"));
13378
13830
  init_paths();
13379
13831
  init_symlink();
13380
13832
  var MIN_DESCRIPTION_WORDS = 20;
@@ -13404,8 +13856,8 @@ var skillUpdateCommand = new Command("update").description("Update skill install
13404
13856
  try {
13405
13857
  const name = options.name;
13406
13858
  const skillDir = getReflyDomainSkillDir(name);
13407
- const skillMdPath = path13.join(skillDir, "SKILL.md");
13408
- if (!fs18.existsSync(skillMdPath)) {
13859
+ const skillMdPath = path12.join(skillDir, "SKILL.md");
13860
+ if (!fs17.existsSync(skillMdPath)) {
13409
13861
  const skillsDir = getReflySkillsDir();
13410
13862
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13411
13863
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
@@ -13414,7 +13866,7 @@ To see installed skills: refly skill list`
13414
13866
  });
13415
13867
  return;
13416
13868
  }
13417
- const skillContent = fs18.readFileSync(skillMdPath, "utf-8");
13869
+ const skillContent = fs17.readFileSync(skillMdPath, "utf-8");
13418
13870
  let meta;
13419
13871
  try {
13420
13872
  const parsed = parseReflySkillMd(skillContent);
@@ -13497,31 +13949,17 @@ To see installed skills: refly skill list`
13497
13949
 
13498
13950
  // src/commands/skill/publish.ts
13499
13951
  init_cjs_shims();
13500
- var fs19 = __toESM(require("fs"));
13501
- var path14 = __toESM(require("path"));
13952
+ var fs18 = __toESM(require("fs"));
13953
+ var path13 = __toESM(require("path"));
13502
13954
  init_symlink();
13503
13955
  init_paths();
13504
- var skillPublishCommand = new Command("publish").description("Publish a skill package using local SKILL.md").option("--id <skillId>", "Skill ID (skp-xxx) - overrides ID from SKILL.md").option("--name <name>", "Local skill name (directory in ~/.refly/skills/)").action(async (options) => {
13956
+ var skillPublishCommand = new Command("publish").description("Publish a skill package using local SKILL.md").requiredOption("--name <name>", "Local skill name (directory in ~/.refly/skills/)").action(async (options) => {
13505
13957
  try {
13506
13958
  const skillsDir = getReflySkillsDir();
13507
- if (!options.name) {
13508
- fail(ErrorCodes.INVALID_INPUT, "Missing required option: --name", {
13509
- hint: `The publish command requires --name to locate the local SKILL.md.
13510
-
13511
- Usage:
13512
- refly skill publish --name <name>
13513
- refly skill publish --name <name> --id <skillId> # override skillId
13514
-
13515
- To find your skill name:
13516
- refly skill list
13517
- ls ${skillsDir}/`
13518
- });
13519
- return;
13520
- }
13521
13959
  const name = options.name;
13522
13960
  const skillDir = getReflyDomainSkillDir(name);
13523
- const skillMdPath = path14.join(skillDir, "SKILL.md");
13524
- if (!fs19.existsSync(skillMdPath)) {
13961
+ const skillMdPath = path13.join(skillDir, "SKILL.md");
13962
+ if (!fs18.existsSync(skillMdPath)) {
13525
13963
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13526
13964
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
13527
13965
 
@@ -13530,22 +13968,31 @@ To create a new skill: refly skill create --name "${name}" --workflow-query "...
13530
13968
  });
13531
13969
  return;
13532
13970
  }
13533
- const skillContent = fs19.readFileSync(skillMdPath, "utf-8");
13971
+ const skillContent = fs18.readFileSync(skillMdPath, "utf-8");
13534
13972
  let parsedSkill;
13535
13973
  try {
13536
13974
  parsedSkill = parseReflySkillMd(skillContent);
13537
13975
  } catch (parseError) {
13538
- fail(
13539
- ErrorCodes.INVALID_INPUT,
13540
- `Failed to parse SKILL.md: ${parseError.message}`,
13541
- {
13542
- hint: "Make sure SKILL.md has valid frontmatter with required fields: name, description, skillId, workflowId"
13543
- }
13544
- );
13976
+ const errorMessage = parseError.message;
13977
+ if (errorMessage.includes("skillId")) {
13978
+ fail(ErrorCodes.INVALID_INPUT, "SKILL.md is missing skillId", {
13979
+ hint: `The skill "${name}" has no skillId. This may happen if the skill was created manually.
13980
+
13981
+ To fix this:
13982
+ 1. Reinstall the skill: refly skill install <skillId> --force
13983
+ 2. Or create a new skill: refly skill create --name "${name}" --workflow <workflowId>
13984
+
13985
+ To find available skills: refly skill list`
13986
+ });
13987
+ return;
13988
+ }
13989
+ fail(ErrorCodes.INVALID_INPUT, `Failed to parse SKILL.md: ${errorMessage}`, {
13990
+ hint: "Make sure SKILL.md has valid frontmatter with required fields: name, description, skillId, workflowId"
13991
+ });
13545
13992
  return;
13546
13993
  }
13547
13994
  const { meta } = parsedSkill;
13548
- const skillId = options.id || meta.skillId;
13995
+ const skillId = meta.skillId;
13549
13996
  const result = await apiRequest(
13550
13997
  `/v1/skill-packages/${skillId}/publish`,
13551
13998
  {
@@ -13561,8 +14008,6 @@ To create a new skill: refly skill create --name "${name}" --workflow-query "...
13561
14008
  version: result.version,
13562
14009
  status: result.status,
13563
14010
  isPublic: result.isPublic,
13564
- shareId: result.shareId,
13565
- shareUrl: result.shareId ? `https://refly.ai/skill/${result.shareId}` : void 0,
13566
14011
  githubPrUrl: result.githubPrUrl,
13567
14012
  githubPrNumber: result.githubPrNumber,
13568
14013
  localPath: skillMdPath
@@ -13585,8 +14030,8 @@ To create a new skill: refly skill create --name "${name}" --workflow-query "...
13585
14030
 
13586
14031
  // src/commands/skill/unpublish.ts
13587
14032
  init_cjs_shims();
13588
- var fs20 = __toESM(require("fs"));
13589
- var path15 = __toESM(require("path"));
14033
+ var fs19 = __toESM(require("fs"));
14034
+ var path14 = __toESM(require("path"));
13590
14035
  init_symlink();
13591
14036
  init_paths();
13592
14037
  var skillUnpublishCommand = new Command("unpublish").description("Unpublish a skill package to make it private").option("--id <skillId>", "Skill ID (skp-xxx)").option("--name <name>", "Local skill name (directory in ~/.refly/skills/)").action(async (options) => {
@@ -13608,9 +14053,21 @@ To find your skill name:
13608
14053
  let name;
13609
14054
  if (options.name) {
13610
14055
  name = options.name;
14056
+ if (!name) {
14057
+ fail(ErrorCodes.INVALID_INPUT, "Skill name cannot be empty", {
14058
+ hint: `Usage:
14059
+ refly skill unpublish --name <name>
14060
+ refly skill unpublish --id <skillId>
14061
+
14062
+ To find your skill name:
14063
+ refly skill list
14064
+ ls ${skillsDir}/`
14065
+ });
14066
+ return;
14067
+ }
13611
14068
  const skillDir = getReflyDomainSkillDir(name);
13612
- const skillMdPath = path15.join(skillDir, "SKILL.md");
13613
- if (!fs20.existsSync(skillMdPath)) {
14069
+ const skillMdPath = path14.join(skillDir, "SKILL.md");
14070
+ if (!fs19.existsSync(skillMdPath)) {
13614
14071
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13615
14072
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
13616
14073
 
@@ -13618,7 +14075,7 @@ To see installed skills: refly skill list`
13618
14075
  });
13619
14076
  return;
13620
14077
  }
13621
- const skillContent = fs20.readFileSync(skillMdPath, "utf-8");
14078
+ const skillContent = fs19.readFileSync(skillMdPath, "utf-8");
13622
14079
  try {
13623
14080
  const { meta } = parseReflySkillMd(skillContent);
13624
14081
  skillId = options.id || meta.skillId;
@@ -13662,11 +14119,11 @@ To see installed skills: refly skill list`
13662
14119
 
13663
14120
  // src/commands/skill/run.ts
13664
14121
  init_cjs_shims();
13665
- var fs21 = __toESM(require("fs"));
13666
- var path16 = __toESM(require("path"));
14122
+ var fs20 = __toESM(require("fs"));
14123
+ var path15 = __toESM(require("path"));
13667
14124
  init_symlink();
13668
14125
  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) => {
14126
+ 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
14127
  try {
13671
14128
  const skillsDir = getReflySkillsDir();
13672
14129
  if (!options.id && !options.name) {
@@ -13684,11 +14141,12 @@ To find your skill name:
13684
14141
  let installationId;
13685
14142
  let name;
13686
14143
  let skillId;
14144
+ let workflowId;
13687
14145
  if (options.name) {
13688
14146
  name = options.name;
13689
- const skillDir = getReflyDomainSkillDir(name);
13690
- const skillMdPath = path16.join(skillDir, "SKILL.md");
13691
- if (!fs21.existsSync(skillMdPath)) {
14147
+ const skillDir = getReflyDomainSkillDir(options.name);
14148
+ const skillMdPath = path15.join(skillDir, "SKILL.md");
14149
+ if (!fs20.existsSync(skillMdPath)) {
13692
14150
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13693
14151
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
13694
14152
 
@@ -13697,10 +14155,11 @@ To install a skill: refly skill install <skillId>`
13697
14155
  });
13698
14156
  return;
13699
14157
  }
13700
- const skillContent = fs21.readFileSync(skillMdPath, "utf-8");
14158
+ const skillContent = fs20.readFileSync(skillMdPath, "utf-8");
13701
14159
  try {
13702
14160
  const { meta } = parseReflySkillMd(skillContent);
13703
14161
  skillId = meta.skillId;
14162
+ workflowId = meta.workflowId;
13704
14163
  if (options.id) {
13705
14164
  installationId = options.id;
13706
14165
  } else if (meta.installationId) {
@@ -13753,6 +14212,29 @@ To install: refly skill install ${meta.skillId}`
13753
14212
  return;
13754
14213
  }
13755
14214
  }
14215
+ if (options.noPrompt && workflowId) {
14216
+ try {
14217
+ const workflow = await apiGetWorkflow(workflowId);
14218
+ if (workflow?.variables) {
14219
+ const checkResult = checkRequiredVariables(workflow.variables, input3);
14220
+ if (!checkResult.valid) {
14221
+ const errorPayload = buildMissingVariablesError(
14222
+ "skill",
14223
+ name || installationId,
14224
+ name,
14225
+ checkResult
14226
+ );
14227
+ fail(ErrorCodes.MISSING_VARIABLES, errorPayload.message, {
14228
+ details: errorPayload.details,
14229
+ hint: errorPayload.hint,
14230
+ suggestedFix: errorPayload.suggestedFix,
14231
+ recoverable: errorPayload.recoverable
14232
+ });
14233
+ }
14234
+ }
14235
+ } catch {
14236
+ }
14237
+ }
13756
14238
  const body = { input: input3 };
13757
14239
  if (options.workflow) body.workflowId = options.workflow;
13758
14240
  if (options.async) body.async = true;
@@ -13789,6 +14271,87 @@ To install: refly skill install ${meta.skillId}`
13789
14271
  }
13790
14272
  });
13791
14273
 
14274
+ // src/commands/skill/stop.ts
14275
+ init_cjs_shims();
14276
+ var fs21 = __toESM(require("fs"));
14277
+ var path16 = __toESM(require("path"));
14278
+ init_symlink();
14279
+ init_paths();
14280
+ function getLocalSkillNames() {
14281
+ const skillsDir = getReflySkillsDir();
14282
+ if (!fs21.existsSync(skillsDir)) {
14283
+ return [];
14284
+ }
14285
+ return fs21.readdirSync(skillsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
14286
+ }
14287
+ var skillStopCommand = new Command("stop").description("Stop running skill executions").requiredOption("--name <name>", "Local skill name (directory in ~/.refly/skills/)").action(async (options) => {
14288
+ try {
14289
+ const skillsDir = getReflySkillsDir();
14290
+ const name = options.name;
14291
+ const skillDir = getReflyDomainSkillDir(name);
14292
+ const skillMdPath = path16.join(skillDir, "SKILL.md");
14293
+ if (!fs21.existsSync(skillMdPath)) {
14294
+ const availableSkills = getLocalSkillNames();
14295
+ const skillList = availableSkills.length > 0 ? availableSkills.join(", ") : "(no skills installed)";
14296
+ fail(ErrorCodes.NOT_FOUND, `Skill "${name}" not found`, {
14297
+ hint: `Available skills: ${skillList}
14298
+
14299
+ Skills directory: ${skillsDir}`
14300
+ });
14301
+ }
14302
+ const skillContent = fs21.readFileSync(skillMdPath, "utf-8");
14303
+ let installationId;
14304
+ try {
14305
+ const { meta } = parseReflySkillMd(skillContent);
14306
+ if (!meta.installationId) {
14307
+ fail(ErrorCodes.INVALID_INPUT, `Skill "${name}" does not have an installationId`, {
14308
+ hint: `This skill may have been created locally but not installed.
14309
+
14310
+ To install: refly skill install ${meta.skillId}`
14311
+ });
14312
+ }
14313
+ installationId = meta.installationId;
14314
+ } catch (parseError) {
14315
+ fail(
14316
+ ErrorCodes.INVALID_INPUT,
14317
+ `Failed to parse SKILL.md: ${parseError.message}`,
14318
+ {
14319
+ hint: "Make sure SKILL.md has valid frontmatter with required fields"
14320
+ }
14321
+ );
14322
+ }
14323
+ const result = await apiRequest(
14324
+ `/v1/skill-installations/${installationId}/stop`,
14325
+ {
14326
+ method: "POST"
14327
+ }
14328
+ );
14329
+ ok("skill.stop", {
14330
+ name,
14331
+ installationId,
14332
+ message: result.message,
14333
+ stoppedExecutions: result.stoppedExecutions
14334
+ });
14335
+ } catch (error) {
14336
+ if (error instanceof CLIError) {
14337
+ if (error.code === "NOT_FOUND") {
14338
+ fail(ErrorCodes.NOT_FOUND, `No running executions for skill "${options.name}"`, {
14339
+ hint: "The skill is not currently running"
14340
+ });
14341
+ }
14342
+ fail(error.code, error.message, {
14343
+ details: error.details,
14344
+ hint: error.hint,
14345
+ suggestedFix: error.suggestedFix
14346
+ });
14347
+ }
14348
+ fail(
14349
+ ErrorCodes.INTERNAL_ERROR,
14350
+ error instanceof Error ? error.message : "Failed to stop skill"
14351
+ );
14352
+ }
14353
+ });
14354
+
13792
14355
  // src/commands/skill/search.ts
13793
14356
  init_cjs_shims();
13794
14357
  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 +14398,12 @@ var skillSearchCommand = new Command("search").description("Search public skill
13835
14398
  init_cjs_shims();
13836
14399
  init_symlink();
13837
14400
  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) => {
14401
+ 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
14402
  try {
13840
14403
  const body = { skillId };
13841
14404
  if (options.version) body.version = options.version;
13842
14405
  if (options.shareId) body.shareId = options.shareId;
14406
+ if (options.force) body.force = true;
13843
14407
  if (options.config) {
13844
14408
  try {
13845
14409
  body.config = JSON.parse(options.config);
@@ -13881,7 +14445,9 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
13881
14445
  inputSchema: result.skillPackage?.inputSchema,
13882
14446
  outputSchema: result.skillPackage?.outputSchema
13883
14447
  });
13884
- const symlinkResult = createReflySkillWithSymlink(skillName, skillMdContent);
14448
+ const symlinkResult = createReflySkillWithSymlink(skillName, skillMdContent, {
14449
+ force: options.force
14450
+ });
13885
14451
  if (symlinkResult.success) {
13886
14452
  localPath = symlinkResult.reflyPath;
13887
14453
  symlinkPath = symlinkResult.claudePath;
@@ -13947,6 +14513,18 @@ To find your skill name:
13947
14513
  let name;
13948
14514
  if (options.name) {
13949
14515
  name = options.name;
14516
+ if (!name) {
14517
+ fail(ErrorCodes.INVALID_INPUT, "Skill name cannot be empty", {
14518
+ hint: `Usage:
14519
+ refly skill uninstall --name <name>
14520
+ refly skill uninstall --id <installationId>
14521
+
14522
+ To find your skill name:
14523
+ refly skill list
14524
+ ls ${skillsDir}/`
14525
+ });
14526
+ return;
14527
+ }
13950
14528
  const skillDir = getReflyDomainSkillDir(name);
13951
14529
  const skillMdPath = path17.join(skillDir, "SKILL.md");
13952
14530
  if (!fs22.existsSync(skillMdPath)) {
@@ -14427,7 +15005,7 @@ var skillSyncCommand = new Command("sync").description("Validate and repair skil
14427
15005
  });
14428
15006
 
14429
15007
  // 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);
15008
+ 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
15009
 
14432
15010
  // src/bin/refly.ts
14433
15011
  function getVersion() {