@powerformer/refly-cli 0.1.5 → 0.1.7

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
@@ -4040,30 +4040,15 @@ var OutputFormatter = class {
4040
4040
  }
4041
4041
  // === CLI Status Format (Phase 1: Charm-style cards) ===
4042
4042
  outputStatusPretty(payload) {
4043
- const { cli_version, api_endpoint, auth_status, auth_method, auth_details, user, skill } = payload;
4043
+ const { cli_version, api_endpoint, auth_status, user, skill } = payload;
4044
4044
  const sym = this.useUnicode ? Symbols : AsciiSymbol;
4045
4045
  console.log(`${sym.DIAMOND} ${UI.bold("Refly CLI")} v${cli_version || "?"}`);
4046
4046
  console.log();
4047
4047
  const authOk = auth_status === "valid";
4048
4048
  const userObj = user;
4049
- const authDetailsObj = auth_details;
4050
4049
  const authLines = [];
4051
4050
  if (authOk && userObj?.email) {
4052
4051
  authLines.push({ text: String(userObj.email) });
4053
- const provider = authDetailsObj?.provider || auth_method;
4054
- if (provider) {
4055
- const providerDisplay = String(provider).charAt(0).toUpperCase() + String(provider).slice(1);
4056
- const exp = userObj?.exp;
4057
- let expiryText = "";
4058
- if (exp) {
4059
- expiryText = ` \xB7 ${UI.timeRemaining(exp)}`;
4060
- }
4061
- authLines.push({
4062
- text: `via ${providerDisplay}${expiryText}`,
4063
- indent: true,
4064
- muted: true
4065
- });
4066
- }
4067
4052
  } else if (auth_status === "expired") {
4068
4053
  authLines.push({ text: "Token expired", muted: true });
4069
4054
  } else {
@@ -4377,6 +4362,9 @@ function configureOutput(options) {
4377
4362
  };
4378
4363
  initFormatter(outputConfig);
4379
4364
  }
4365
+ function isPrettyOutput() {
4366
+ return outputConfig.format !== "json";
4367
+ }
4380
4368
  function ok(type, payload) {
4381
4369
  const formatter = getFormatter();
4382
4370
  formatter.success(type, payload);
@@ -4436,6 +4424,7 @@ var ErrorCodes = {
4436
4424
  // Node
4437
4425
  INVALID_NODE_TYPE: "INVALID_NODE_TYPE",
4438
4426
  INVALID_NODE_INPUT: "INVALID_NODE_INPUT",
4427
+ EXECUTION_FAILED: "EXECUTION_FAILED",
4439
4428
  // Network
4440
4429
  NETWORK_ERROR: "NETWORK_ERROR",
4441
4430
  TIMEOUT: "TIMEOUT",
@@ -8559,8 +8548,8 @@ var ConfigSchema = external_exports.object({
8559
8548
  installedAt: external_exports.string().optional()
8560
8549
  }).optional()
8561
8550
  });
8562
- var DEFAULT_API_ENDPOINT = "https://api.refly.ai";
8563
- var DEFAULT_WEB_URL = "https://refly.ai";
8551
+ var DEFAULT_API_ENDPOINT = "https://refly-api.powerformer.net";
8552
+ var DEFAULT_WEB_URL = "https://refly.powerformer.net";
8564
8553
  var DEFAULT_CONFIG = {
8565
8554
  version: 1,
8566
8555
  api: {
@@ -9655,7 +9644,40 @@ async function loginWithDeviceFlow() {
9655
9644
  },
9656
9645
  requireAuth: false
9657
9646
  });
9658
- const { deviceId, expiresAt } = initResponse;
9647
+ const { deviceId, expiresAt, userCode } = initResponse;
9648
+ const cleanup = async (deviceIdToCancel = deviceId) => {
9649
+ try {
9650
+ logger.debug("Cleaning up device session...");
9651
+ await apiRequest("/v1/auth/cli/device/cancel", {
9652
+ method: "POST",
9653
+ body: { device_id: deviceIdToCancel },
9654
+ requireAuth: false
9655
+ });
9656
+ logger.debug("Device session cancelled");
9657
+ } catch (error) {
9658
+ logger.debug("Failed to cancel device session during cleanup:", error);
9659
+ }
9660
+ };
9661
+ process.on("SIGINT", async () => {
9662
+ logger.debug("Received SIGINT, cleaning up...");
9663
+ await cleanup();
9664
+ process.exit(130);
9665
+ });
9666
+ process.on("SIGTERM", async () => {
9667
+ logger.debug("Received SIGTERM, cleaning up...");
9668
+ await cleanup();
9669
+ process.exit(143);
9670
+ });
9671
+ process.on("uncaughtException", async (error) => {
9672
+ logger.debug("Uncaught exception, cleaning up:", error);
9673
+ await cleanup();
9674
+ process.exit(1);
9675
+ });
9676
+ process.on("unhandledRejection", async (reason) => {
9677
+ logger.debug("Unhandled rejection, cleaning up:", reason);
9678
+ await cleanup();
9679
+ process.exit(1);
9680
+ });
9659
9681
  const webUrl = getWebUrl();
9660
9682
  const authUrl = `${webUrl}/cli/auth?device_id=${encodeURIComponent(deviceId)}&cli_version=${encodeURIComponent(CLI_VERSION)}&host=${encodeURIComponent(hostname2)}`;
9661
9683
  process.stderr.write("\n");
@@ -9664,6 +9686,10 @@ async function loginWithDeviceFlow() {
9664
9686
  process.stderr.write(` ${authUrl}
9665
9687
  `);
9666
9688
  process.stderr.write("\n");
9689
+ if (userCode) {
9690
+ process.stderr.write(`Verification Code: ${styled(userCode, Style.TEXT_HIGHLIGHT_BOLD)}
9691
+ `);
9692
+ }
9667
9693
  process.stderr.write(`Device ID: ${deviceId}
9668
9694
  `);
9669
9695
  process.stderr.write(`Expires: ${new Date(expiresAt).toLocaleTimeString()}
@@ -9678,55 +9704,67 @@ async function loginWithDeviceFlow() {
9678
9704
  }
9679
9705
  const pollInterval = 2e3;
9680
9706
  const maxAttempts = 150;
9681
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
9682
- await sleep(pollInterval);
9683
- const statusResponse = await apiRequest("/v1/auth/cli/device/status", {
9684
- method: "GET",
9685
- query: { device_id: deviceId },
9686
- requireAuth: false
9687
- });
9688
- switch (statusResponse.status) {
9689
- case "authorized":
9690
- if (statusResponse.accessToken && statusResponse.refreshToken) {
9691
- const userInfo = await getUserInfoFromToken(statusResponse.accessToken);
9692
- setOAuthTokens({
9693
- accessToken: statusResponse.accessToken,
9694
- refreshToken: statusResponse.refreshToken,
9695
- expiresAt: new Date(Date.now() + 36e5).toISOString(),
9696
- // 1 hour
9697
- provider: "google",
9698
- // Device flow doesn't specify provider, default to google
9699
- user: userInfo
9707
+ try {
9708
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
9709
+ await sleep(pollInterval);
9710
+ const statusResponse = await apiRequest(
9711
+ "/v1/auth/cli/device/status",
9712
+ {
9713
+ method: "GET",
9714
+ query: { device_id: deviceId },
9715
+ requireAuth: false
9716
+ }
9717
+ );
9718
+ switch (statusResponse.status) {
9719
+ case "authorized":
9720
+ if (statusResponse.accessToken && statusResponse.refreshToken) {
9721
+ const userInfo = await getUserInfoFromToken(statusResponse.accessToken);
9722
+ setOAuthTokens({
9723
+ accessToken: statusResponse.accessToken,
9724
+ refreshToken: statusResponse.refreshToken,
9725
+ expiresAt: new Date(Date.now() + 36e5).toISOString(),
9726
+ // 1 hour
9727
+ provider: "google",
9728
+ // Device flow doesn't specify provider, default to google
9729
+ user: userInfo
9730
+ });
9731
+ ok("login", {
9732
+ message: "Successfully authenticated via device authorization",
9733
+ user: userInfo,
9734
+ method: "device"
9735
+ });
9736
+ return true;
9737
+ }
9738
+ break;
9739
+ case "cancelled":
9740
+ printError(ErrorCodes.AUTH_REQUIRED, "Authorization was cancelled", {
9741
+ hint: "The authorization request was cancelled in the browser"
9700
9742
  });
9701
- ok("login", {
9702
- message: "Successfully authenticated via device authorization",
9703
- user: userInfo,
9704
- method: "device"
9743
+ return false;
9744
+ case "expired":
9745
+ printError(ErrorCodes.AUTH_REQUIRED, "Authorization request expired", {
9746
+ hint: "Run `refly login` again to start a new session"
9705
9747
  });
9706
- return true;
9707
- }
9708
- break;
9709
- case "cancelled":
9710
- printError(ErrorCodes.AUTH_REQUIRED, "Authorization was cancelled", {
9711
- hint: "The authorization request was cancelled in the browser"
9712
- });
9713
- return false;
9714
- case "expired":
9715
- printError(ErrorCodes.AUTH_REQUIRED, "Authorization request expired", {
9716
- hint: "Run `refly login` again to start a new session"
9717
- });
9718
- return false;
9719
- case "pending":
9720
- if (attempt % 5 === 0) {
9721
- process.stderr.write(".");
9722
- }
9723
- break;
9748
+ return false;
9749
+ case "pending":
9750
+ if (attempt % 5 === 0) {
9751
+ process.stderr.write(".");
9752
+ }
9753
+ break;
9754
+ }
9724
9755
  }
9756
+ logger.debug("Authorization timeout, updating device status...");
9757
+ await cleanup(deviceId);
9758
+ printError(ErrorCodes.TIMEOUT, "Authorization timeout", {
9759
+ hint: "Complete authorization in the browser within 5 minutes"
9760
+ });
9761
+ return false;
9762
+ } finally {
9763
+ process.removeAllListeners("SIGINT");
9764
+ process.removeAllListeners("SIGTERM");
9765
+ process.removeAllListeners("uncaughtException");
9766
+ process.removeAllListeners("unhandledRejection");
9725
9767
  }
9726
- printError(ErrorCodes.TIMEOUT, "Authorization timeout", {
9727
- hint: "Complete authorization in the browser within 5 minutes"
9728
- });
9729
- return false;
9730
9768
  }
9731
9769
  async function getUserInfoFromToken(accessToken) {
9732
9770
  try {
@@ -9759,15 +9797,66 @@ function sleep(ms) {
9759
9797
  return new Promise((resolve2) => setTimeout(resolve2, ms));
9760
9798
  }
9761
9799
 
9800
+ // src/utils/logo.ts
9801
+ init_cjs_shims();
9802
+ var REFLY_LOGO = `\u2588\u2580\u2588 \u2588\u2580\u2580 \u2588\u2580\u2580 \u2588 \u2588 \u2588 \u2588\u2580\u2588 \u2588
9803
+ \u2588\u2580\u2584 \u2588\u2580\u2580 \u2588\u2580\u2580 \u2588 \u2588\u2584\u2588 \u2580 \u2588\u2580\u2588 \u2588
9804
+ \u2580 \u2580 \u2580\u2580\u2580 \u2580 \u2580\u2580\u2580 \u2580 \u2580 \u2580 \u2580`;
9805
+ function printLogo(options) {
9806
+ const useColor = options?.color ?? shouldUseColor();
9807
+ const tty = isTTY();
9808
+ if (!tty && !options?.force) {
9809
+ return;
9810
+ }
9811
+ if (useColor) {
9812
+ process.stderr.write(`${Style.TEXT_SUCCESS}${REFLY_LOGO}${Style.RESET}
9813
+ `);
9814
+ } else {
9815
+ process.stderr.write(`${REFLY_LOGO}
9816
+ `);
9817
+ }
9818
+ }
9819
+ function printSuccess(message) {
9820
+ process.stderr.write(`${UI.successMsg(message)}
9821
+ `);
9822
+ }
9823
+ function printError2(message) {
9824
+ process.stderr.write(`${UI.errorMsg(message)}
9825
+ `);
9826
+ }
9827
+ function printDim(message) {
9828
+ process.stderr.write(`${UI.dim(message)}
9829
+ `);
9830
+ }
9831
+ function println(message) {
9832
+ process.stderr.write(`${message}
9833
+ `);
9834
+ }
9835
+
9762
9836
  // src/commands/init.ts
9763
- var DEFAULT_API_ENDPOINT2 = "https://api.refly.ai";
9837
+ var DEFAULT_API_ENDPOINT2 = "https://refly-api.powerformer.net";
9764
9838
  var initCommand = new Command("init").description("Initialize Refly CLI, install skill files, and authenticate").option("--force", "Force reinstall even if already installed").option("--host <url>", "API server URL", DEFAULT_API_ENDPOINT2).option("--skip-login", "Skip automatic login after initialization").action(async (options) => {
9765
9839
  try {
9766
9840
  const { force, host, skipLogin } = options;
9767
9841
  const apiEndpoint = host || DEFAULT_API_ENDPOINT2;
9842
+ const pretty = isPrettyOutput();
9843
+ const tty = isTTY();
9844
+ const useColor = shouldUseColor();
9768
9845
  const skillStatus = isSkillInstalled();
9769
9846
  const isAuthenticated2 = !!(getAccessToken() || getApiKey());
9770
9847
  if (skillStatus.installed && skillStatus.upToDate && !force && isAuthenticated2) {
9848
+ if (pretty && tty) {
9849
+ printLogo({ color: useColor });
9850
+ println("");
9851
+ printSuccess("Already initialized and authenticated");
9852
+ const user = getAuthUser();
9853
+ if (user?.email) {
9854
+ printDim(` Logged in as ${user.email}`);
9855
+ }
9856
+ println("");
9857
+ printDim("Run `refly status` for details.");
9858
+ return;
9859
+ }
9771
9860
  return ok("init", {
9772
9861
  message: "Refly CLI already initialized and authenticated",
9773
9862
  configDir: getReflyDir(),
@@ -9777,34 +9866,92 @@ var initCommand = new Command("init").description("Initialize Refly CLI, install
9777
9866
  authenticated: true
9778
9867
  });
9779
9868
  }
9869
+ if (pretty && tty) {
9870
+ printLogo({ color: useColor });
9871
+ println("");
9872
+ println("Initializing Refly CLI...");
9873
+ println("");
9874
+ }
9780
9875
  const config = loadConfig();
9781
9876
  config.api = {
9782
9877
  endpoint: apiEndpoint
9783
9878
  };
9784
9879
  saveConfig(config);
9785
- const result = installSkill();
9786
- print("init", {
9787
- message: "Refly CLI initialized successfully",
9788
- configDir: getReflyDir(),
9789
- apiEndpoint,
9790
- skillInstalled: result.skillInstalled,
9791
- skillPath: result.skillPath,
9792
- commandsInstalled: result.commandsInstalled,
9793
- commandsPath: result.commandsPath,
9794
- version: result.version
9795
- });
9880
+ const installResult = installSkill();
9881
+ if (pretty && tty) {
9882
+ if (installResult.skillInstalled) {
9883
+ printSuccess("Skill files installed");
9884
+ } else {
9885
+ printError2("Skill files installation failed");
9886
+ }
9887
+ if (installResult.commandsInstalled) {
9888
+ printSuccess("Slash commands installed");
9889
+ } else {
9890
+ printError2("Slash commands installation failed");
9891
+ }
9892
+ println("");
9893
+ } else if (!pretty) {
9894
+ print("init", {
9895
+ message: "Refly CLI initialized successfully",
9896
+ configDir: getReflyDir(),
9897
+ apiEndpoint,
9898
+ skillInstalled: installResult.skillInstalled,
9899
+ skillPath: installResult.skillPath,
9900
+ commandsInstalled: installResult.commandsInstalled,
9901
+ commandsPath: installResult.commandsPath,
9902
+ version: installResult.version
9903
+ });
9904
+ }
9796
9905
  if (!skipLogin && !isAuthenticated2) {
9797
- process.stderr.write("\nStarting authentication...\n");
9798
- const loginSuccess = await loginWithDeviceFlow();
9799
- if (!loginSuccess) {
9800
- process.stderr.write(
9801
- "\nAuthentication was not completed. You can login later with `refly login`.\n"
9802
- );
9906
+ if (pretty && tty) {
9907
+ println("Starting authentication...");
9908
+ printDim("A browser window will open for login.");
9909
+ println("");
9910
+ }
9911
+ const loginResult = await loginWithDeviceFlow({ emitOutput: false });
9912
+ if (pretty && tty) {
9913
+ if (loginResult.ok) {
9914
+ printSuccess("Authentication successful");
9915
+ if (loginResult.user?.email) {
9916
+ printDim(` Welcome, ${loginResult.user.email}!`);
9917
+ }
9918
+ } else {
9919
+ printError2("Authentication was not completed");
9920
+ printDim(" Run `refly login` to authenticate later.");
9921
+ }
9922
+ println("");
9923
+ } else if (!pretty && loginResult.ok) {
9924
+ print("login", {
9925
+ message: "Successfully authenticated",
9926
+ user: loginResult.user
9927
+ });
9803
9928
  }
9804
- } else if (isAuthenticated2) {
9805
- process.stderr.write("\nAlready authenticated.\n");
9806
- } else {
9807
- process.stderr.write("\nSkipped login. Run `refly login` to authenticate later.\n");
9929
+ } else if (pretty && tty) {
9930
+ if (isAuthenticated2) {
9931
+ printSuccess("Already authenticated");
9932
+ const user = getAuthUser();
9933
+ if (user?.email) {
9934
+ printDim(` Logged in as ${user.email}`);
9935
+ }
9936
+ } else {
9937
+ printDim("Skipped login. Run `refly login` to authenticate later.");
9938
+ }
9939
+ println("");
9940
+ }
9941
+ if (pretty && tty) {
9942
+ println("Ready to use! Try `refly status` to verify.");
9943
+ return;
9944
+ }
9945
+ if (!pretty) {
9946
+ return ok("init", {
9947
+ message: "Refly CLI initialized successfully",
9948
+ configDir: getReflyDir(),
9949
+ apiEndpoint,
9950
+ skillInstalled: installResult.skillInstalled,
9951
+ commandsInstalled: installResult.commandsInstalled,
9952
+ version: installResult.version,
9953
+ authenticated: !!(getAccessToken() || getApiKey())
9954
+ });
9808
9955
  }
9809
9956
  } catch (error) {
9810
9957
  fail(
@@ -9933,16 +10080,135 @@ var whoamiCommand = new Command("whoami").description("Show current authenticate
9933
10080
 
9934
10081
  // src/commands/upgrade.ts
9935
10082
  init_cjs_shims();
9936
- var upgradeCommand = new Command("upgrade").description("Reinstall or upgrade skill files").action(async () => {
10083
+ var import_node_child_process6 = require("child_process");
10084
+ init_logger();
10085
+ var PACKAGE_NAME = "@powerformer/refly-cli";
10086
+ function getCurrentVersion() {
9937
10087
  try {
9938
- const beforeStatus = isSkillInstalled();
9939
- const result = installSkill();
10088
+ const pkgPath = new URL("../../package.json", importMetaUrl);
10089
+ const pkg = JSON.parse(
10090
+ (0, import_node_child_process6.execSync)(`cat "${pkgPath.pathname}"`, { encoding: "utf-8" })
10091
+ );
10092
+ return pkg.version;
10093
+ } catch {
10094
+ return "0.1.0";
10095
+ }
10096
+ }
10097
+ async function getLatestVersion() {
10098
+ try {
10099
+ const result = (0, import_node_child_process6.execSync)(`npm view ${PACKAGE_NAME} version 2>/dev/null`, {
10100
+ encoding: "utf-8",
10101
+ timeout: 1e4
10102
+ });
10103
+ return result.trim();
10104
+ } catch (error) {
10105
+ logger.debug("Failed to get latest version from npm:", error);
10106
+ return null;
10107
+ }
10108
+ }
10109
+ async function checkVersion() {
10110
+ const current = getCurrentVersion();
10111
+ const latest = await getLatestVersion();
10112
+ return {
10113
+ current,
10114
+ latest,
10115
+ updateAvailable: latest !== null && latest !== current
10116
+ };
10117
+ }
10118
+ function upgradeCli() {
10119
+ try {
10120
+ logger.info("Upgrading CLI via npm...");
10121
+ (0, import_node_child_process6.execSync)(`npm install -g ${PACKAGE_NAME}@latest`, {
10122
+ encoding: "utf-8",
10123
+ stdio: "pipe",
10124
+ timeout: 12e4
10125
+ // 2 minutes
10126
+ });
10127
+ return { success: true };
10128
+ } catch (error) {
10129
+ const message = error instanceof Error ? error.message : "Unknown error";
10130
+ logger.error("Failed to upgrade CLI:", message);
10131
+ return { success: false, error: message };
10132
+ }
10133
+ }
10134
+ var upgradeCommand = new Command("upgrade").description("Upgrade CLI to latest version and reinstall skill files").option("--check", "Only check for updates without installing").option("--skill-only", "Only reinstall skill files without upgrading CLI").option("--cli-only", "Only upgrade CLI without reinstalling skill files").action(async (options) => {
10135
+ try {
10136
+ const { check, skillOnly, cliOnly } = options;
10137
+ const versionInfo = await checkVersion();
10138
+ if (check) {
10139
+ return ok("upgrade.check", {
10140
+ currentVersion: versionInfo.current,
10141
+ latestVersion: versionInfo.latest,
10142
+ updateAvailable: versionInfo.updateAvailable,
10143
+ message: versionInfo.updateAvailable ? `Update available: ${versionInfo.current} \u2192 ${versionInfo.latest}` : "Already on latest version"
10144
+ });
10145
+ }
10146
+ if (skillOnly) {
10147
+ const beforeStatus = isSkillInstalled();
10148
+ const result = installSkill();
10149
+ return ok("upgrade", {
10150
+ message: "Skill files updated successfully",
10151
+ cliUpgraded: false,
10152
+ skillUpdated: true,
10153
+ previousVersion: beforeStatus.currentVersion ?? null,
10154
+ newVersion: result.version,
10155
+ skillPath: result.skillPath,
10156
+ commandsInstalled: result.commandsInstalled
10157
+ });
10158
+ }
10159
+ let cliUpgraded = false;
10160
+ let cliError;
10161
+ if (!cliOnly) {
10162
+ print("upgrade.progress", {
10163
+ step: "checking",
10164
+ currentVersion: versionInfo.current,
10165
+ latestVersion: versionInfo.latest
10166
+ });
10167
+ }
10168
+ if (!skillOnly) {
10169
+ if (versionInfo.updateAvailable) {
10170
+ print("upgrade.progress", {
10171
+ step: "upgrading",
10172
+ from: versionInfo.current,
10173
+ to: versionInfo.latest
10174
+ });
10175
+ const upgradeResult = upgradeCli();
10176
+ cliUpgraded = upgradeResult.success;
10177
+ cliError = upgradeResult.error;
10178
+ if (!cliUpgraded) {
10179
+ return fail(ErrorCodes.INTERNAL_ERROR, "Failed to upgrade CLI", {
10180
+ hint: cliError || "Try running: npm install -g @powerformer/refly-cli@latest"
10181
+ });
10182
+ }
10183
+ } else {
10184
+ logger.info("CLI is already on latest version");
10185
+ }
10186
+ }
10187
+ let skillResult = null;
10188
+ if (!cliOnly) {
10189
+ const beforeStatus = isSkillInstalled();
10190
+ skillResult = installSkill();
10191
+ }
10192
+ const newVersionInfo = await checkVersion();
10193
+ let message;
10194
+ if (cliUpgraded && skillResult) {
10195
+ message = "CLI and skill files updated successfully";
10196
+ } else if (cliUpgraded) {
10197
+ message = "CLI updated successfully";
10198
+ } else if (skillResult) {
10199
+ message = "Skill files updated (CLI already on latest version)";
10200
+ } else {
10201
+ message = "Already on latest version";
10202
+ }
9940
10203
  ok("upgrade", {
9941
- message: "Skill files upgraded successfully",
9942
- previousVersion: beforeStatus.currentVersion ?? null,
9943
- newVersion: result.version,
9944
- skillPath: result.skillPath,
9945
- commandsInstalled: result.commandsInstalled
10204
+ message,
10205
+ cliUpgraded,
10206
+ skillUpdated: !!skillResult,
10207
+ previousVersion: versionInfo.current,
10208
+ currentVersion: newVersionInfo.current,
10209
+ latestVersion: newVersionInfo.latest,
10210
+ skillPath: skillResult?.skillPath ?? null,
10211
+ commandsInstalled: skillResult?.commandsInstalled ?? false
9946
10212
  });
9947
10213
  } catch (error) {
9948
10214
  return fail(
@@ -11465,7 +11731,7 @@ var workflowRunToolcallsCommand = new Command("toolcalls").description("Get all
11465
11731
  });
11466
11732
 
11467
11733
  // src/commands/workflow/run.ts
11468
- var workflowRunCommand = new Command("run").description("Run workflows and get execution results").argument("[workflowId]", "Workflow ID to run").option("--input <json>", "Input variables as JSON", "{}").action(async (workflowId, options) => {
11734
+ var workflowRunCommand = new Command("run").description("Run workflows and get execution results").argument("[workflowId]", "Workflow ID to run").option("--input <json>", "Input variables as JSON", "{}").option("--from-node <nodeId>", "Start workflow execution from a specific node (Run From Here)").action(async (workflowId, options) => {
11469
11735
  if (!workflowId) {
11470
11736
  workflowRunCommand.help();
11471
11737
  return;
@@ -11479,17 +11745,22 @@ var workflowRunCommand = new Command("run").description("Run workflows and get e
11479
11745
  hint: "Ensure the input is valid JSON"
11480
11746
  });
11481
11747
  }
11748
+ const body = { input };
11749
+ if (options.fromNode) {
11750
+ body.startNodes = [options.fromNode];
11751
+ }
11482
11752
  const result = await apiRequest(`/v1/cli/workflow/${workflowId}/run`, {
11483
11753
  method: "POST",
11484
- body: { input }
11754
+ body
11485
11755
  });
11486
11756
  ok("workflow.run", {
11487
- message: "Workflow run started",
11757
+ message: options.fromNode ? `Workflow run started from node ${options.fromNode}` : "Workflow run started",
11488
11758
  runId: result.runId,
11489
11759
  workflowId: result.workflowId,
11490
11760
  status: result.status,
11761
+ startNode: options.fromNode || void 0,
11491
11762
  createdAt: result.createdAt,
11492
- nextStep: `Check status with \`refly workflow run get ${result.runId}\``
11763
+ nextStep: `Check status with \`refly workflow status ${result.runId}\``
11493
11764
  });
11494
11765
  } catch (error) {
11495
11766
  if (error instanceof CLIError) {
@@ -11709,8 +11980,108 @@ var workflowLayoutCommand = new Command("layout").description("Auto-layout workf
11709
11980
  }
11710
11981
  });
11711
11982
 
11983
+ // src/commands/workflow/nodes.ts
11984
+ init_cjs_shims();
11985
+ 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) => {
11986
+ try {
11987
+ const result = await apiRequest(`/v1/cli/workflow/${workflowId}`);
11988
+ const nodes = result.nodes.map((node) => {
11989
+ const output2 = {
11990
+ id: node.id,
11991
+ type: node.type,
11992
+ title: node.data?.title || node.data?.metadata?.title || void 0
11993
+ };
11994
+ if (options.includePosition && node.position) {
11995
+ output2.position = node.position;
11996
+ }
11997
+ if (options.includeMetadata && node.data?.metadata) {
11998
+ output2.metadata = node.data.metadata;
11999
+ }
12000
+ return output2;
12001
+ });
12002
+ const output = {
12003
+ workflowId: result.workflowId,
12004
+ workflowName: result.name,
12005
+ nodeCount: nodes.length,
12006
+ nodes
12007
+ };
12008
+ if (options.includeEdges && result.edges?.length) {
12009
+ output.edges = result.edges.map((edge) => ({
12010
+ id: edge.id,
12011
+ source: edge.source,
12012
+ target: edge.target,
12013
+ sourceHandle: edge.sourceHandle,
12014
+ targetHandle: edge.targetHandle
12015
+ }));
12016
+ output.edgeCount = result.edges.length;
12017
+ }
12018
+ ok("workflow.nodes", output);
12019
+ } catch (error) {
12020
+ if (error instanceof CLIError) {
12021
+ fail(error.code, error.message, { details: error.details, hint: error.hint });
12022
+ }
12023
+ fail(
12024
+ ErrorCodes.INTERNAL_ERROR,
12025
+ error instanceof Error ? error.message : "Failed to get workflow nodes"
12026
+ );
12027
+ }
12028
+ });
12029
+
12030
+ // src/commands/workflow/node-get.ts
12031
+ init_cjs_shims();
12032
+ var workflowNodeGetCommand = new Command("node").description("Get single node information from a workflow").argument("<workflowId>", "Workflow ID").argument("<nodeId>", "Node ID").option("--include-connections", "Include incoming and outgoing connections").action(async (workflowId, nodeId, options) => {
12033
+ try {
12034
+ const result = await apiRequest(`/v1/cli/workflow/${workflowId}`);
12035
+ const node = result.nodes.find((n) => n.id === nodeId);
12036
+ if (!node) {
12037
+ fail(ErrorCodes.NODE_NOT_FOUND, `Node ${nodeId} not found in workflow ${workflowId}`, {
12038
+ hint: `Use 'refly workflow nodes ${workflowId}' to list all nodes`
12039
+ });
12040
+ }
12041
+ const output = {
12042
+ workflowId: result.workflowId,
12043
+ workflowName: result.name,
12044
+ node: {
12045
+ id: node.id,
12046
+ type: node.type,
12047
+ title: node.data?.title || node.data?.metadata?.title || void 0,
12048
+ position: node.position,
12049
+ metadata: node.data?.metadata || {},
12050
+ data: node.data
12051
+ }
12052
+ };
12053
+ if (options.includeConnections && result.edges?.length) {
12054
+ const incoming = result.edges.filter((e) => e.target === nodeId).map((e) => ({
12055
+ from: e.source,
12056
+ sourceHandle: e.sourceHandle,
12057
+ targetHandle: e.targetHandle
12058
+ }));
12059
+ const outgoing = result.edges.filter((e) => e.source === nodeId).map((e) => ({
12060
+ to: e.target,
12061
+ sourceHandle: e.sourceHandle,
12062
+ targetHandle: e.targetHandle
12063
+ }));
12064
+ output.connections = {
12065
+ incoming,
12066
+ outgoing,
12067
+ incomingCount: incoming.length,
12068
+ outgoingCount: outgoing.length
12069
+ };
12070
+ }
12071
+ ok("workflow.node", output);
12072
+ } catch (error) {
12073
+ if (error instanceof CLIError) {
12074
+ fail(error.code, error.message, { details: error.details, hint: error.hint });
12075
+ }
12076
+ fail(
12077
+ ErrorCodes.INTERNAL_ERROR,
12078
+ error instanceof Error ? error.message : "Failed to get node information"
12079
+ );
12080
+ }
12081
+ });
12082
+
11712
12083
  // src/commands/workflow/index.ts
11713
- var workflowCommand = new Command("workflow").description("Manage and run workflows").addCommand(workflowCreateCommand).addCommand(workflowGenerateCommand).addCommand(workflowListCommand).addCommand(workflowGetCommand).addCommand(workflowEditCommand).addCommand(workflowDeleteCommand).addCommand(workflowRunCommand).addCommand(workflowAbortCommand).addCommand(workflowStatusCommand).addCommand(workflowToolsetKeysCommand).addCommand(workflowLayoutCommand);
12084
+ var workflowCommand = new Command("workflow").description("Manage and run workflows").addCommand(workflowCreateCommand).addCommand(workflowGenerateCommand).addCommand(workflowListCommand).addCommand(workflowGetCommand).addCommand(workflowEditCommand).addCommand(workflowDeleteCommand).addCommand(workflowRunCommand).addCommand(workflowAbortCommand).addCommand(workflowStatusCommand).addCommand(workflowToolsetKeysCommand).addCommand(workflowLayoutCommand).addCommand(workflowNodesCommand).addCommand(workflowNodeGetCommand);
11714
12085
 
11715
12086
  // src/commands/node/index.ts
11716
12087
  init_cjs_shims();
@@ -11788,29 +12159,56 @@ async function fetchAndCache() {
11788
12159
 
11789
12160
  // src/commands/node/run.ts
11790
12161
  init_cjs_shims();
11791
- var nodeRunCommand = new Command("run").description("Run a single node for debugging").requiredOption("--type <nodeType>", "Node type to run").requiredOption("--input <json>", "Input data as JSON").action(async (options) => {
12162
+ var nodeRunCommand = new Command("run").description("Run a single node for debugging (currently supports skillResponse only)").requiredOption("--type <nodeType>", 'Node type to run (e.g., "skillResponse")').option("--query <query>", "Query text for skillResponse node").option("--input <json>", "Full input data as JSON (alternative to --query)").option("--config <json>", 'Node configuration as JSON (e.g., {"modelItemId": "..."})').action(async (options) => {
11792
12163
  try {
11793
- let input;
11794
- try {
11795
- input = JSON.parse(options.input);
11796
- } catch {
11797
- fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --input", {
11798
- hint: "Ensure the input is valid JSON"
11799
- });
12164
+ let input = {};
12165
+ if (options.query) {
12166
+ input = { query: options.query };
12167
+ } else if (options.input) {
12168
+ try {
12169
+ input = JSON.parse(options.input);
12170
+ } catch {
12171
+ fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --input", {
12172
+ hint: "Ensure the input is valid JSON"
12173
+ });
12174
+ return;
12175
+ }
12176
+ }
12177
+ let config = {};
12178
+ if (options.config) {
12179
+ try {
12180
+ config = JSON.parse(options.config);
12181
+ } catch {
12182
+ fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --config", {
12183
+ hint: "Ensure the config is valid JSON"
12184
+ });
12185
+ return;
12186
+ }
11800
12187
  }
11801
12188
  const result = await apiRequest("/v1/cli/node/run", {
11802
12189
  method: "POST",
11803
12190
  body: {
11804
- type: options.type,
11805
- input
11806
- }
11807
- });
11808
- ok("node.run", {
11809
- type: options.type,
11810
- result: result.result,
11811
- metrics: result.metrics,
11812
- logs: result.logs ?? []
11813
- });
12191
+ nodeType: options.type,
12192
+ input,
12193
+ config
12194
+ }
12195
+ });
12196
+ if (result.status === "completed") {
12197
+ ok("node.run", {
12198
+ nodeType: result.nodeType,
12199
+ status: result.status,
12200
+ output: result.output,
12201
+ duration: result.duration,
12202
+ tokenUsage: result.tokenUsage
12203
+ });
12204
+ } else {
12205
+ fail(ErrorCodes.EXECUTION_FAILED, result.error || "Node execution failed", {
12206
+ details: {
12207
+ nodeType: result.nodeType,
12208
+ output: result.output
12209
+ }
12210
+ });
12211
+ }
11814
12212
  } catch (error) {
11815
12213
  if (error instanceof CLIError) {
11816
12214
  fail(error.code, error.message, { details: error.details, hint: error.hint });
@@ -11827,24 +12225,65 @@ init_cjs_shims();
11827
12225
  var nodeResultCommand = new Command("result").description("Get node execution result").argument("<resultId>", "Node result ID").option("--include-steps", "Include detailed step information").option("--include-messages", "Include chat messages").option("--include-tool-calls", "Include tool call details").action(async (resultId, options) => {
11828
12226
  try {
11829
12227
  const result = await apiRequest(`/v1/cli/action/result?resultId=${resultId}`);
12228
+ let totalTokenUsage;
12229
+ if (result.steps?.length) {
12230
+ totalTokenUsage = { input: 0, output: 0, reasoning: 0 };
12231
+ for (const step of result.steps) {
12232
+ if (step.tokenUsage?.length) {
12233
+ for (const usage of step.tokenUsage) {
12234
+ totalTokenUsage.input += usage.inputTokens || 0;
12235
+ totalTokenUsage.output += usage.outputTokens || 0;
12236
+ totalTokenUsage.reasoning += usage.reasoningTokens || 0;
12237
+ }
12238
+ }
12239
+ }
12240
+ }
12241
+ const lastStep = result.steps?.[result.steps.length - 1];
12242
+ const content = lastStep?.content;
11830
12243
  const output = {
11831
12244
  resultId: result.resultId,
12245
+ version: result.version,
12246
+ title: result.title,
11832
12247
  status: result.status,
11833
- content: result.content,
11834
- tokenUsage: result.tokenUsage
12248
+ content,
12249
+ tokenUsage: totalTokenUsage,
12250
+ createdAt: result.createdAt,
12251
+ updatedAt: result.updatedAt
11835
12252
  };
11836
12253
  if (options.includeSteps && result.steps) {
11837
- output.steps = result.steps.map((step) => ({
11838
- stepIndex: step.stepIndex,
12254
+ output.steps = result.steps.map((step, index) => ({
12255
+ stepIndex: index,
12256
+ name: step.name,
11839
12257
  content: step.content,
12258
+ reasoningContent: step.reasoningContent,
11840
12259
  toolCallsCount: step.toolCalls?.length ?? 0
11841
12260
  }));
11842
12261
  }
11843
- if (options.includeToolCalls && result.toolCalls) {
11844
- output.toolCalls = result.toolCalls;
12262
+ if (options.includeToolCalls && result.steps) {
12263
+ const allToolCalls = [];
12264
+ for (const step of result.steps) {
12265
+ if (step.toolCalls?.length) {
12266
+ for (const tc of step.toolCalls) {
12267
+ allToolCalls.push({
12268
+ callId: tc.callId,
12269
+ toolName: tc.toolName,
12270
+ status: tc.status,
12271
+ error: tc.error
12272
+ });
12273
+ }
12274
+ }
12275
+ }
12276
+ output.toolCalls = allToolCalls;
11845
12277
  }
11846
12278
  if (options.includeMessages && result.messages) {
11847
- output.messages = result.messages;
12279
+ output.messages = result.messages.map((msg) => ({
12280
+ messageId: msg.messageId,
12281
+ type: msg.type,
12282
+ content: msg.content
12283
+ }));
12284
+ }
12285
+ if (result.errors?.length) {
12286
+ output.errors = result.errors;
11848
12287
  }
11849
12288
  ok("node.result", output);
11850
12289
  } catch (error) {
@@ -11858,8 +12297,35 @@ var nodeResultCommand = new Command("result").description("Get node execution re
11858
12297
  }
11859
12298
  });
11860
12299
 
12300
+ // src/commands/node/abort.ts
12301
+ init_cjs_shims();
12302
+ var nodeAbortCommand = new Command("abort").description("Abort a running node execution").argument("<resultId>", "Node result ID to abort").option("--version <number>", "Specific version to abort", Number.parseInt).action(async (resultId, options) => {
12303
+ try {
12304
+ const body = { resultId };
12305
+ if (options.version !== void 0) {
12306
+ body.version = options.version;
12307
+ }
12308
+ const result = await apiRequest("/v1/cli/action/abort", {
12309
+ method: "POST",
12310
+ body
12311
+ });
12312
+ ok("node.abort", {
12313
+ message: result.message,
12314
+ resultId: result.resultId
12315
+ });
12316
+ } catch (error) {
12317
+ if (error instanceof CLIError) {
12318
+ fail(error.code, error.message, { details: error.details, hint: error.hint });
12319
+ }
12320
+ fail(
12321
+ ErrorCodes.INTERNAL_ERROR,
12322
+ error instanceof Error ? error.message : "Failed to abort node execution"
12323
+ );
12324
+ }
12325
+ });
12326
+
11861
12327
  // src/commands/node/index.ts
11862
- var nodeCommand = new Command("node").description("Node operations: types, run, and execution results").addCommand(nodeTypesCommand).addCommand(nodeRunCommand).addCommand(nodeResultCommand);
12328
+ var nodeCommand = new Command("node").description("Node operations: types, run, abort, and execution results").addCommand(nodeTypesCommand).addCommand(nodeRunCommand).addCommand(nodeResultCommand).addCommand(nodeAbortCommand);
11863
12329
 
11864
12330
  // src/commands/tool/index.ts
11865
12331
  init_cjs_shims();
@@ -11872,7 +12338,7 @@ var toolCallsCommand = new Command("calls").description("Get tool execution resu
11872
12338
  if (options.version) {
11873
12339
  params.set("version", options.version);
11874
12340
  }
11875
- const result = await apiRequest(`/v1/cli/toolcall?${params}`);
12341
+ const result = await apiRequest(`/v1/cli/tool-call?${params}`);
11876
12342
  ok("tool.calls", {
11877
12343
  resultId: options.resultId,
11878
12344
  version: result.version,
@@ -11909,7 +12375,7 @@ var toolGetCommand = new Command("get").description("Get full details for a sing
11909
12375
  params.set("sanitizeForDisplay", "false");
11910
12376
  }
11911
12377
  const queryString = params.toString();
11912
- const url = `/v1/cli/toolcall/${callId}${queryString ? `?${queryString}` : ""}`;
12378
+ const url = `/v1/cli/tool-call/${callId}${queryString ? `?${queryString}` : ""}`;
11913
12379
  const result = await apiRequest(url);
11914
12380
  ok("tool.detail", {
11915
12381
  callId: result.callId,