@powerformer/refly-cli 0.1.16 → 0.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/refly.js +2394 -879
- package/dist/bin/refly.js.map +1 -1
- package/dist/index.d.ts +33 -3
- package/dist/index.js +624 -150
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/skill/SKILL.md +21 -19
- package/skill/references/skill.md +29 -64
- package/skill/registry.json +0 -15
package/dist/bin/refly.js
CHANGED
|
@@ -34,10 +34,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
34
34
|
));
|
|
35
35
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
36
36
|
|
|
37
|
-
// ../../node_modules/.pnpm/tsup@8.5.1_@swc+core@1.12.14_@swc+helpers@0.5.17__jiti@2.
|
|
37
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_@swc+core@1.12.14_@swc+helpers@0.5.17__jiti@2.6.1_postcss@8.5.6_tsx@4.20.6_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/assets/cjs_shims.js
|
|
38
38
|
var getImportMetaUrl, importMetaUrl;
|
|
39
39
|
var init_cjs_shims = __esm({
|
|
40
|
-
"../../node_modules/.pnpm/tsup@8.5.1_@swc+core@1.12.14_@swc+helpers@0.5.17__jiti@2.
|
|
40
|
+
"../../node_modules/.pnpm/tsup@8.5.1_@swc+core@1.12.14_@swc+helpers@0.5.17__jiti@2.6.1_postcss@8.5.6_tsx@4.20.6_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/assets/cjs_shims.js"() {
|
|
41
41
|
"use strict";
|
|
42
42
|
getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
43
43
|
importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
@@ -989,8 +989,8 @@ var require_command = __commonJS({
|
|
|
989
989
|
init_cjs_shims();
|
|
990
990
|
var EventEmitter = require("events").EventEmitter;
|
|
991
991
|
var childProcess2 = require("child_process");
|
|
992
|
-
var
|
|
993
|
-
var
|
|
992
|
+
var path23 = require("path");
|
|
993
|
+
var fs27 = require("fs");
|
|
994
994
|
var process8 = require("process");
|
|
995
995
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
996
996
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1922,11 +1922,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1922
1922
|
let launchWithNode = false;
|
|
1923
1923
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1924
1924
|
function findFile(baseDir, baseName) {
|
|
1925
|
-
const localBin =
|
|
1926
|
-
if (
|
|
1927
|
-
if (sourceExt.includes(
|
|
1925
|
+
const localBin = path23.resolve(baseDir, baseName);
|
|
1926
|
+
if (fs27.existsSync(localBin)) return localBin;
|
|
1927
|
+
if (sourceExt.includes(path23.extname(baseName))) return void 0;
|
|
1928
1928
|
const foundExt = sourceExt.find(
|
|
1929
|
-
(ext) =>
|
|
1929
|
+
(ext) => fs27.existsSync(`${localBin}${ext}`)
|
|
1930
1930
|
);
|
|
1931
1931
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1932
1932
|
return void 0;
|
|
@@ -1938,21 +1938,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1938
1938
|
if (this._scriptPath) {
|
|
1939
1939
|
let resolvedScriptPath;
|
|
1940
1940
|
try {
|
|
1941
|
-
resolvedScriptPath =
|
|
1941
|
+
resolvedScriptPath = fs27.realpathSync(this._scriptPath);
|
|
1942
1942
|
} catch (err) {
|
|
1943
1943
|
resolvedScriptPath = this._scriptPath;
|
|
1944
1944
|
}
|
|
1945
|
-
executableDir =
|
|
1946
|
-
|
|
1945
|
+
executableDir = path23.resolve(
|
|
1946
|
+
path23.dirname(resolvedScriptPath),
|
|
1947
1947
|
executableDir
|
|
1948
1948
|
);
|
|
1949
1949
|
}
|
|
1950
1950
|
if (executableDir) {
|
|
1951
1951
|
let localFile = findFile(executableDir, executableFile);
|
|
1952
1952
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1953
|
-
const legacyName =
|
|
1953
|
+
const legacyName = path23.basename(
|
|
1954
1954
|
this._scriptPath,
|
|
1955
|
-
|
|
1955
|
+
path23.extname(this._scriptPath)
|
|
1956
1956
|
);
|
|
1957
1957
|
if (legacyName !== this._name) {
|
|
1958
1958
|
localFile = findFile(
|
|
@@ -1963,7 +1963,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1963
1963
|
}
|
|
1964
1964
|
executableFile = localFile || executableFile;
|
|
1965
1965
|
}
|
|
1966
|
-
launchWithNode = sourceExt.includes(
|
|
1966
|
+
launchWithNode = sourceExt.includes(path23.extname(executableFile));
|
|
1967
1967
|
let proc;
|
|
1968
1968
|
if (process8.platform !== "win32") {
|
|
1969
1969
|
if (launchWithNode) {
|
|
@@ -2803,7 +2803,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2803
2803
|
* @return {Command}
|
|
2804
2804
|
*/
|
|
2805
2805
|
nameFromFilename(filename) {
|
|
2806
|
-
this._name =
|
|
2806
|
+
this._name = path23.basename(filename, path23.extname(filename));
|
|
2807
2807
|
return this;
|
|
2808
2808
|
}
|
|
2809
2809
|
/**
|
|
@@ -2817,9 +2817,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2817
2817
|
* @param {string} [path]
|
|
2818
2818
|
* @return {(string|null|Command)}
|
|
2819
2819
|
*/
|
|
2820
|
-
executableDir(
|
|
2821
|
-
if (
|
|
2822
|
-
this._executableDir =
|
|
2820
|
+
executableDir(path24) {
|
|
2821
|
+
if (path24 === void 0) return this._executableDir;
|
|
2822
|
+
this._executableDir = path24;
|
|
2823
2823
|
return this;
|
|
2824
2824
|
}
|
|
2825
2825
|
/**
|
|
@@ -3055,15 +3055,22 @@ var require_commander = __commonJS({
|
|
|
3055
3055
|
var paths_exports = {};
|
|
3056
3056
|
__export(paths_exports, {
|
|
3057
3057
|
claudeDirectoriesExist: () => claudeDirectoriesExist,
|
|
3058
|
+
ensureClaudeSkillsDir: () => ensureClaudeSkillsDir,
|
|
3058
3059
|
ensureDir: () => ensureDir,
|
|
3060
|
+
ensureReflySkillsDir: () => ensureReflySkillsDir,
|
|
3059
3061
|
ensureSkillsDir: () => ensureSkillsDir,
|
|
3060
3062
|
getCacheDir: () => getCacheDir,
|
|
3061
3063
|
getClaudeCommandsDir: () => getClaudeCommandsDir,
|
|
3062
3064
|
getClaudeSkillDir: () => getClaudeSkillDir,
|
|
3065
|
+
getClaudeSkillSymlinkPath: () => getClaudeSkillSymlinkPath,
|
|
3066
|
+
getClaudeSkillsDir: () => getClaudeSkillsDir,
|
|
3063
3067
|
getCliVersion: () => getCliVersion,
|
|
3064
3068
|
getConfigPath: () => getConfigPath,
|
|
3065
3069
|
getLegacyBuilderDir: () => getLegacyBuilderDir,
|
|
3070
|
+
getReflyBaseSkillDir: () => getReflyBaseSkillDir,
|
|
3066
3071
|
getReflyDir: () => getReflyDir,
|
|
3072
|
+
getReflyDomainSkillDir: () => getReflyDomainSkillDir,
|
|
3073
|
+
getReflySkillsDir: () => getReflySkillsDir,
|
|
3067
3074
|
getSkillsDir: () => getSkillsDir
|
|
3068
3075
|
});
|
|
3069
3076
|
function getCliVersion() {
|
|
@@ -3119,6 +3126,33 @@ async function ensureSkillsDir() {
|
|
|
3119
3126
|
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3120
3127
|
}
|
|
3121
3128
|
}
|
|
3129
|
+
function getReflySkillsDir() {
|
|
3130
|
+
return path.join(getReflyDir(), "skills");
|
|
3131
|
+
}
|
|
3132
|
+
function getReflyBaseSkillDir() {
|
|
3133
|
+
return path.join(getReflySkillsDir(), "base");
|
|
3134
|
+
}
|
|
3135
|
+
function getReflyDomainSkillDir(skillName) {
|
|
3136
|
+
return path.join(getReflySkillsDir(), skillName);
|
|
3137
|
+
}
|
|
3138
|
+
function getClaudeSkillsDir() {
|
|
3139
|
+
return path.join(os.homedir(), ".claude", "skills");
|
|
3140
|
+
}
|
|
3141
|
+
function getClaudeSkillSymlinkPath(skillName) {
|
|
3142
|
+
return path.join(getClaudeSkillsDir(), skillName);
|
|
3143
|
+
}
|
|
3144
|
+
function ensureReflySkillsDir() {
|
|
3145
|
+
const dir = getReflySkillsDir();
|
|
3146
|
+
if (!fs.existsSync(dir)) {
|
|
3147
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
function ensureClaudeSkillsDir() {
|
|
3151
|
+
const dir = getClaudeSkillsDir();
|
|
3152
|
+
if (!fs.existsSync(dir)) {
|
|
3153
|
+
fs.mkdirSync(dir, { recursive: true, mode: 493 });
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3122
3156
|
var os, path, fs;
|
|
3123
3157
|
var init_paths = __esm({
|
|
3124
3158
|
"src/config/paths.ts"() {
|
|
@@ -3226,6 +3260,362 @@ var init_logger = __esm({
|
|
|
3226
3260
|
}
|
|
3227
3261
|
});
|
|
3228
3262
|
|
|
3263
|
+
// src/skill/symlink.ts
|
|
3264
|
+
var symlink_exports = {};
|
|
3265
|
+
__export(symlink_exports, {
|
|
3266
|
+
createReflySkillWithSymlink: () => createReflySkillWithSymlink,
|
|
3267
|
+
createSkillSymlink: () => createSkillSymlink,
|
|
3268
|
+
deleteDomainSkillWithSymlink: () => deleteDomainSkillWithSymlink,
|
|
3269
|
+
generateReflySkillMd: () => generateReflySkillMd,
|
|
3270
|
+
initializeBaseSkillSymlink: () => initializeBaseSkillSymlink,
|
|
3271
|
+
isSkillSymlinkValid: () => isSkillSymlinkValid,
|
|
3272
|
+
listSkillSymlinks: () => listSkillSymlinks,
|
|
3273
|
+
parseReflySkillMd: () => parseReflySkillMd,
|
|
3274
|
+
removeSkillSymlink: () => removeSkillSymlink
|
|
3275
|
+
});
|
|
3276
|
+
function createSkillSymlink(skillName) {
|
|
3277
|
+
const reflyPath = skillName === "refly" ? getReflyBaseSkillDir() : getReflyDomainSkillDir(skillName);
|
|
3278
|
+
const claudePath = getClaudeSkillSymlinkPath(skillName);
|
|
3279
|
+
try {
|
|
3280
|
+
ensureReflySkillsDir();
|
|
3281
|
+
ensureClaudeSkillsDir();
|
|
3282
|
+
if (!fs4.existsSync(reflyPath)) {
|
|
3283
|
+
return {
|
|
3284
|
+
success: false,
|
|
3285
|
+
skillName,
|
|
3286
|
+
reflyPath,
|
|
3287
|
+
claudePath,
|
|
3288
|
+
error: `Source skill directory does not exist: ${reflyPath}`
|
|
3289
|
+
};
|
|
3290
|
+
}
|
|
3291
|
+
if (fs4.existsSync(claudePath) || fs4.lstatSync(claudePath).isSymbolicLink()) {
|
|
3292
|
+
const stat = fs4.lstatSync(claudePath);
|
|
3293
|
+
if (stat.isSymbolicLink()) {
|
|
3294
|
+
fs4.unlinkSync(claudePath);
|
|
3295
|
+
logger.debug(`Removed existing symlink: ${claudePath}`);
|
|
3296
|
+
} else if (stat.isDirectory()) {
|
|
3297
|
+
logger.warn(`Cannot create symlink: ${claudePath} is a directory, not a symlink`);
|
|
3298
|
+
return {
|
|
3299
|
+
success: false,
|
|
3300
|
+
skillName,
|
|
3301
|
+
reflyPath,
|
|
3302
|
+
claudePath,
|
|
3303
|
+
error: `Target path is a directory, not a symlink: ${claudePath}`
|
|
3304
|
+
};
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
fs4.symlinkSync(reflyPath, claudePath, "dir");
|
|
3308
|
+
logger.info(`Created symlink: ${claudePath} -> ${reflyPath}`);
|
|
3309
|
+
return {
|
|
3310
|
+
success: true,
|
|
3311
|
+
skillName,
|
|
3312
|
+
reflyPath,
|
|
3313
|
+
claudePath
|
|
3314
|
+
};
|
|
3315
|
+
} catch (err) {
|
|
3316
|
+
if (err.code === "ENOENT") {
|
|
3317
|
+
try {
|
|
3318
|
+
fs4.symlinkSync(reflyPath, claudePath, "dir");
|
|
3319
|
+
logger.info(`Created symlink: ${claudePath} -> ${reflyPath}`);
|
|
3320
|
+
return {
|
|
3321
|
+
success: true,
|
|
3322
|
+
skillName,
|
|
3323
|
+
reflyPath,
|
|
3324
|
+
claudePath
|
|
3325
|
+
};
|
|
3326
|
+
} catch (innerErr) {
|
|
3327
|
+
return {
|
|
3328
|
+
success: false,
|
|
3329
|
+
skillName,
|
|
3330
|
+
reflyPath,
|
|
3331
|
+
claudePath,
|
|
3332
|
+
error: innerErr.message
|
|
3333
|
+
};
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
return {
|
|
3337
|
+
success: false,
|
|
3338
|
+
skillName,
|
|
3339
|
+
reflyPath,
|
|
3340
|
+
claudePath,
|
|
3341
|
+
error: err.message
|
|
3342
|
+
};
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
function removeSkillSymlink(skillName) {
|
|
3346
|
+
const claudePath = getClaudeSkillSymlinkPath(skillName);
|
|
3347
|
+
try {
|
|
3348
|
+
if (!fs4.existsSync(claudePath)) {
|
|
3349
|
+
logger.debug(`Symlink not found: ${claudePath}`);
|
|
3350
|
+
return false;
|
|
3351
|
+
}
|
|
3352
|
+
const stat = fs4.lstatSync(claudePath);
|
|
3353
|
+
if (!stat.isSymbolicLink()) {
|
|
3354
|
+
logger.warn(`Not a symlink: ${claudePath}`);
|
|
3355
|
+
return false;
|
|
3356
|
+
}
|
|
3357
|
+
fs4.unlinkSync(claudePath);
|
|
3358
|
+
logger.info(`Removed symlink: ${claudePath}`);
|
|
3359
|
+
return true;
|
|
3360
|
+
} catch (err) {
|
|
3361
|
+
logger.error(`Failed to remove symlink ${claudePath}:`, err);
|
|
3362
|
+
return false;
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
function isSkillSymlinkValid(skillName) {
|
|
3366
|
+
const claudePath = getClaudeSkillSymlinkPath(skillName);
|
|
3367
|
+
const expectedTarget = skillName === "refly" ? getReflyBaseSkillDir() : getReflyDomainSkillDir(skillName);
|
|
3368
|
+
try {
|
|
3369
|
+
if (!fs4.existsSync(claudePath)) {
|
|
3370
|
+
return { exists: false, isSymlink: false, isValid: false };
|
|
3371
|
+
}
|
|
3372
|
+
const stat = fs4.lstatSync(claudePath);
|
|
3373
|
+
if (!stat.isSymbolicLink()) {
|
|
3374
|
+
return { exists: true, isSymlink: false, isValid: false };
|
|
3375
|
+
}
|
|
3376
|
+
const target = fs4.readlinkSync(claudePath);
|
|
3377
|
+
const resolvedTarget = path4.resolve(path4.dirname(claudePath), target);
|
|
3378
|
+
const isValid2 = resolvedTarget === expectedTarget && fs4.existsSync(resolvedTarget);
|
|
3379
|
+
return {
|
|
3380
|
+
exists: true,
|
|
3381
|
+
isSymlink: true,
|
|
3382
|
+
isValid: isValid2,
|
|
3383
|
+
target: resolvedTarget
|
|
3384
|
+
};
|
|
3385
|
+
} catch {
|
|
3386
|
+
return { exists: false, isSymlink: false, isValid: false };
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3389
|
+
function initializeBaseSkillSymlink() {
|
|
3390
|
+
const baseDir = getReflyBaseSkillDir();
|
|
3391
|
+
ensureDir(baseDir);
|
|
3392
|
+
ensureDir(path4.join(baseDir, "rules"));
|
|
3393
|
+
return createSkillSymlink("refly");
|
|
3394
|
+
}
|
|
3395
|
+
function createReflySkillWithSymlink(skillName, skillMdContent, options) {
|
|
3396
|
+
const skillDir = getReflyDomainSkillDir(skillName);
|
|
3397
|
+
try {
|
|
3398
|
+
ensureReflySkillsDir();
|
|
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
|
+
}
|
|
3406
|
+
return {
|
|
3407
|
+
success: false,
|
|
3408
|
+
skillName,
|
|
3409
|
+
reflyPath: skillDir,
|
|
3410
|
+
claudePath: getClaudeSkillSymlinkPath(skillName),
|
|
3411
|
+
error: `Skill directory already exists: ${skillDir}`
|
|
3412
|
+
};
|
|
3413
|
+
}
|
|
3414
|
+
fs4.mkdirSync(skillDir, { recursive: true, mode: 493 });
|
|
3415
|
+
const skillMdPath = path4.join(skillDir, "SKILL.md");
|
|
3416
|
+
fs4.writeFileSync(skillMdPath, skillMdContent, { encoding: "utf-8", mode: 420 });
|
|
3417
|
+
logger.debug(`Created SKILL.md: ${skillMdPath}`);
|
|
3418
|
+
return createSkillSymlink(skillName);
|
|
3419
|
+
} catch (err) {
|
|
3420
|
+
return {
|
|
3421
|
+
success: false,
|
|
3422
|
+
skillName,
|
|
3423
|
+
reflyPath: skillDir,
|
|
3424
|
+
claudePath: getClaudeSkillSymlinkPath(skillName),
|
|
3425
|
+
error: err.message
|
|
3426
|
+
};
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
function deleteDomainSkillWithSymlink(skillName) {
|
|
3430
|
+
const symlinkRemoved = removeSkillSymlink(skillName);
|
|
3431
|
+
const skillDir = getReflyDomainSkillDir(skillName);
|
|
3432
|
+
let directoryRemoved = false;
|
|
3433
|
+
try {
|
|
3434
|
+
if (fs4.existsSync(skillDir)) {
|
|
3435
|
+
fs4.rmSync(skillDir, { recursive: true, force: true });
|
|
3436
|
+
directoryRemoved = true;
|
|
3437
|
+
logger.info(`Removed skill directory: ${skillDir}`);
|
|
3438
|
+
}
|
|
3439
|
+
} catch (err) {
|
|
3440
|
+
logger.error(`Failed to remove skill directory ${skillDir}:`, err);
|
|
3441
|
+
}
|
|
3442
|
+
return { symlinkRemoved, directoryRemoved };
|
|
3443
|
+
}
|
|
3444
|
+
function listSkillSymlinks() {
|
|
3445
|
+
const claudeSkillsDir = getClaudeSkillsDir();
|
|
3446
|
+
const results = [];
|
|
3447
|
+
if (!fs4.existsSync(claudeSkillsDir)) {
|
|
3448
|
+
return results;
|
|
3449
|
+
}
|
|
3450
|
+
try {
|
|
3451
|
+
const entries = fs4.readdirSync(claudeSkillsDir, { withFileTypes: true });
|
|
3452
|
+
for (const entry of entries) {
|
|
3453
|
+
const fullPath = path4.join(claudeSkillsDir, entry.name);
|
|
3454
|
+
try {
|
|
3455
|
+
const stat = fs4.lstatSync(fullPath);
|
|
3456
|
+
if (stat.isSymbolicLink()) {
|
|
3457
|
+
const target = fs4.readlinkSync(fullPath);
|
|
3458
|
+
const resolvedTarget = path4.resolve(path4.dirname(fullPath), target);
|
|
3459
|
+
const isValid2 = fs4.existsSync(resolvedTarget);
|
|
3460
|
+
results.push({
|
|
3461
|
+
name: entry.name,
|
|
3462
|
+
claudePath: fullPath,
|
|
3463
|
+
target: resolvedTarget,
|
|
3464
|
+
isValid: isValid2
|
|
3465
|
+
});
|
|
3466
|
+
}
|
|
3467
|
+
} catch {
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3470
|
+
} catch {
|
|
3471
|
+
}
|
|
3472
|
+
return results;
|
|
3473
|
+
}
|
|
3474
|
+
function generateReflySkillMd(options) {
|
|
3475
|
+
const {
|
|
3476
|
+
name,
|
|
3477
|
+
displayName,
|
|
3478
|
+
description,
|
|
3479
|
+
skillId,
|
|
3480
|
+
workflowId,
|
|
3481
|
+
installationId,
|
|
3482
|
+
triggers = [],
|
|
3483
|
+
tags = [],
|
|
3484
|
+
version = "1.0.0",
|
|
3485
|
+
inputSchema,
|
|
3486
|
+
outputSchema
|
|
3487
|
+
} = options;
|
|
3488
|
+
const frontmatterLines = ["---", `name: ${name}`];
|
|
3489
|
+
frontmatterLines.push(`description: ${description}`);
|
|
3490
|
+
if (tags.length > 0) {
|
|
3491
|
+
frontmatterLines.push("tags:");
|
|
3492
|
+
frontmatterLines.push(...tags.map((t) => ` - ${t}`));
|
|
3493
|
+
}
|
|
3494
|
+
frontmatterLines.push(`version: ${version}`);
|
|
3495
|
+
frontmatterLines.push(`skillId: ${skillId}`);
|
|
3496
|
+
frontmatterLines.push(`workflowId: ${workflowId}`);
|
|
3497
|
+
if (installationId) {
|
|
3498
|
+
frontmatterLines.push(`installationId: ${installationId}`);
|
|
3499
|
+
}
|
|
3500
|
+
if (triggers.length > 0) {
|
|
3501
|
+
frontmatterLines.push("triggers:");
|
|
3502
|
+
frontmatterLines.push(...triggers.map((t) => ` - ${t}`));
|
|
3503
|
+
}
|
|
3504
|
+
frontmatterLines.push("---");
|
|
3505
|
+
const title = displayName || name.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
3506
|
+
const inputExample = inputSchema ? JSON.stringify(inputSchema, null, 2) : `{
|
|
3507
|
+
"query": "your input here"
|
|
3508
|
+
}`;
|
|
3509
|
+
const runCommand = installationId ? `refly skill run ${installationId} --input '${inputSchema ? JSON.stringify(inputSchema) : "{}"}'` : `refly workflow run ${workflowId} --input '${inputSchema ? JSON.stringify(inputSchema) : "{}"}'`;
|
|
3510
|
+
const outputSection = outputSchema ? `The skill returns:
|
|
3511
|
+
|
|
3512
|
+
\`\`\`json
|
|
3513
|
+
${JSON.stringify(outputSchema, null, 2)}
|
|
3514
|
+
\`\`\`` : "The skill returns the workflow execution result.";
|
|
3515
|
+
const content = `
|
|
3516
|
+
|
|
3517
|
+
# ${title}
|
|
3518
|
+
|
|
3519
|
+
${description}
|
|
3520
|
+
|
|
3521
|
+
## Usage
|
|
3522
|
+
|
|
3523
|
+
This skill is executed via Refly CLI:
|
|
3524
|
+
|
|
3525
|
+
\`\`\`bash
|
|
3526
|
+
${runCommand}
|
|
3527
|
+
\`\`\`
|
|
3528
|
+
|
|
3529
|
+
## Input
|
|
3530
|
+
|
|
3531
|
+
Provide input as JSON:
|
|
3532
|
+
|
|
3533
|
+
\`\`\`json
|
|
3534
|
+
${inputExample}
|
|
3535
|
+
\`\`\`
|
|
3536
|
+
|
|
3537
|
+
## Output
|
|
3538
|
+
|
|
3539
|
+
${outputSection}
|
|
3540
|
+
|
|
3541
|
+
## Rules
|
|
3542
|
+
|
|
3543
|
+
For workflow operations, refer to the base skill rules:
|
|
3544
|
+
- Workflow: \`~/.claude/skills/refly/rules/workflow.md\`
|
|
3545
|
+
- Node: \`~/.claude/skills/refly/rules/node.md\`
|
|
3546
|
+
- File: \`~/.claude/skills/refly/rules/file.md\`
|
|
3547
|
+
`;
|
|
3548
|
+
return frontmatterLines.join("\n") + content;
|
|
3549
|
+
}
|
|
3550
|
+
function parseReflySkillMd(content) {
|
|
3551
|
+
const frontmatterRegex = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/;
|
|
3552
|
+
const match = content.match(frontmatterRegex);
|
|
3553
|
+
if (!match) {
|
|
3554
|
+
throw new Error("Invalid SKILL.md format: missing frontmatter");
|
|
3555
|
+
}
|
|
3556
|
+
const [, frontmatterStr, body] = match;
|
|
3557
|
+
const meta = {};
|
|
3558
|
+
const lines = frontmatterStr.split("\n");
|
|
3559
|
+
let currentKey = null;
|
|
3560
|
+
let currentArray = [];
|
|
3561
|
+
for (const line of lines) {
|
|
3562
|
+
const trimmed = line.trim();
|
|
3563
|
+
if (trimmed.startsWith("- ")) {
|
|
3564
|
+
if (currentKey) {
|
|
3565
|
+
currentArray.push(trimmed.slice(2).trim());
|
|
3566
|
+
}
|
|
3567
|
+
continue;
|
|
3568
|
+
}
|
|
3569
|
+
if (currentKey && currentArray.length > 0) {
|
|
3570
|
+
meta[currentKey] = currentArray;
|
|
3571
|
+
currentArray = [];
|
|
3572
|
+
currentKey = null;
|
|
3573
|
+
}
|
|
3574
|
+
const colonIndex = trimmed.indexOf(":");
|
|
3575
|
+
if (colonIndex > 0) {
|
|
3576
|
+
const key = trimmed.slice(0, colonIndex).trim();
|
|
3577
|
+
const value = trimmed.slice(colonIndex + 1).trim();
|
|
3578
|
+
if (value === "") {
|
|
3579
|
+
currentKey = key;
|
|
3580
|
+
currentArray = [];
|
|
3581
|
+
} else {
|
|
3582
|
+
meta[key] = value;
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
if (currentKey && currentArray.length > 0) {
|
|
3587
|
+
meta[currentKey] = currentArray;
|
|
3588
|
+
}
|
|
3589
|
+
if (!meta.name) {
|
|
3590
|
+
throw new Error('Invalid SKILL.md: missing required field "name"');
|
|
3591
|
+
}
|
|
3592
|
+
if (!meta.description) {
|
|
3593
|
+
throw new Error('Invalid SKILL.md: missing required field "description"');
|
|
3594
|
+
}
|
|
3595
|
+
if (!meta.skillId) {
|
|
3596
|
+
throw new Error('Invalid SKILL.md: missing required field "skillId"');
|
|
3597
|
+
}
|
|
3598
|
+
if (!meta.workflowId) {
|
|
3599
|
+
throw new Error('Invalid SKILL.md: missing required field "workflowId"');
|
|
3600
|
+
}
|
|
3601
|
+
return {
|
|
3602
|
+
meta,
|
|
3603
|
+
body: body.trim(),
|
|
3604
|
+
raw: content
|
|
3605
|
+
};
|
|
3606
|
+
}
|
|
3607
|
+
var fs4, path4;
|
|
3608
|
+
var init_symlink = __esm({
|
|
3609
|
+
"src/skill/symlink.ts"() {
|
|
3610
|
+
"use strict";
|
|
3611
|
+
init_cjs_shims();
|
|
3612
|
+
fs4 = __toESM(require("fs"));
|
|
3613
|
+
path4 = __toESM(require("path"));
|
|
3614
|
+
init_paths();
|
|
3615
|
+
init_logger();
|
|
3616
|
+
}
|
|
3617
|
+
});
|
|
3618
|
+
|
|
3229
3619
|
// src/bin/refly.ts
|
|
3230
3620
|
init_cjs_shims();
|
|
3231
3621
|
|
|
@@ -4023,6 +4413,10 @@ var OutputFormatter = class {
|
|
|
4023
4413
|
if (error.code) {
|
|
4024
4414
|
console.log(UI.keyValue("Code", UI.dim(error.code)));
|
|
4025
4415
|
}
|
|
4416
|
+
if (error.recoverable !== void 0) {
|
|
4417
|
+
const recoverableText = error.recoverable ? "\u{1F504} Recoverable: Fix the parameter and retry the SAME command" : "\u274C Not recoverable: Consider a different approach";
|
|
4418
|
+
console.log(UI.dim(` ${recoverableText}`));
|
|
4419
|
+
}
|
|
4026
4420
|
if (error.details && Object.keys(error.details).length > 0) {
|
|
4027
4421
|
console.log();
|
|
4028
4422
|
console.log(UI.indent(UI.dim("Details:")));
|
|
@@ -4040,6 +4434,13 @@ var OutputFormatter = class {
|
|
|
4040
4434
|
console.log();
|
|
4041
4435
|
console.log(UI.dim(` \u{1F4A1} Hint: ${error.hint}`));
|
|
4042
4436
|
}
|
|
4437
|
+
if (error.suggestedFix && Object.keys(error.suggestedFix).length > 0) {
|
|
4438
|
+
console.log();
|
|
4439
|
+
console.log(UI.dim(" \u2705 Suggested fix:"));
|
|
4440
|
+
console.log(
|
|
4441
|
+
UI.indent(this.formatObject(error.suggestedFix, 2), 4)
|
|
4442
|
+
);
|
|
4443
|
+
}
|
|
4043
4444
|
console.log();
|
|
4044
4445
|
}
|
|
4045
4446
|
// === Workflow List Format (Phase 2: Docker-style table) ===
|
|
@@ -4265,6 +4666,9 @@ var OutputFormatter = class {
|
|
|
4265
4666
|
if (error.hint) {
|
|
4266
4667
|
console.log(UI.dim(` ${error.hint}`));
|
|
4267
4668
|
}
|
|
4669
|
+
if (error.suggestedFix) {
|
|
4670
|
+
console.log(UI.dim(` fix: ${this.formatValue(error.suggestedFix)}`));
|
|
4671
|
+
}
|
|
4268
4672
|
}
|
|
4269
4673
|
// === Plain Format ===
|
|
4270
4674
|
outputPlain(type, payload) {
|
|
@@ -4282,6 +4686,9 @@ var OutputFormatter = class {
|
|
|
4282
4686
|
if (error.hint) {
|
|
4283
4687
|
console.log(` hint: ${error.hint}`);
|
|
4284
4688
|
}
|
|
4689
|
+
if (error.suggestedFix) {
|
|
4690
|
+
console.log(` suggestedFix: ${this.formatValue(error.suggestedFix)}`);
|
|
4691
|
+
}
|
|
4285
4692
|
}
|
|
4286
4693
|
// === Helper Methods ===
|
|
4287
4694
|
humanizeType(type) {
|
|
@@ -4403,13 +4810,29 @@ function print(type, payload) {
|
|
|
4403
4810
|
const formatter = getFormatter();
|
|
4404
4811
|
formatter.success(type, payload);
|
|
4405
4812
|
}
|
|
4813
|
+
function isRecoverableError(code, hasSuggestedFix) {
|
|
4814
|
+
const recoverableCodes = [
|
|
4815
|
+
"INVALID_INPUT",
|
|
4816
|
+
"VALIDATION_ERROR",
|
|
4817
|
+
"INVALID_NODE_INPUT",
|
|
4818
|
+
"TIMEOUT",
|
|
4819
|
+
// Can retry
|
|
4820
|
+
"RATE_LIMIT"
|
|
4821
|
+
// Can retry after waiting
|
|
4822
|
+
];
|
|
4823
|
+
if (hasSuggestedFix) return true;
|
|
4824
|
+
return recoverableCodes.includes(code);
|
|
4825
|
+
}
|
|
4406
4826
|
function fail(code, message, options) {
|
|
4407
4827
|
const formatter = getFormatter();
|
|
4828
|
+
const recoverable = options?.recoverable ?? isRecoverableError(code, !!options?.suggestedFix);
|
|
4408
4829
|
formatter.error({
|
|
4409
4830
|
code,
|
|
4410
4831
|
message,
|
|
4411
4832
|
details: options?.details,
|
|
4412
|
-
hint: options?.hint
|
|
4833
|
+
hint: options?.hint,
|
|
4834
|
+
suggestedFix: options?.suggestedFix,
|
|
4835
|
+
recoverable
|
|
4413
4836
|
});
|
|
4414
4837
|
process.exit(options?.exitCode ?? getExitCode(code));
|
|
4415
4838
|
}
|
|
@@ -4419,7 +4842,8 @@ function printError(code, message, options) {
|
|
|
4419
4842
|
code,
|
|
4420
4843
|
message,
|
|
4421
4844
|
details: options?.details,
|
|
4422
|
-
hint: options?.hint
|
|
4845
|
+
hint: options?.hint,
|
|
4846
|
+
suggestedFix: options?.suggestedFix
|
|
4423
4847
|
});
|
|
4424
4848
|
}
|
|
4425
4849
|
function getExitCode(code) {
|
|
@@ -4463,12 +4887,14 @@ var ErrorCodes = {
|
|
|
4463
4887
|
CONFLICT: "CONFLICT",
|
|
4464
4888
|
PERMISSION_DENIED: "PERMISSION_DENIED",
|
|
4465
4889
|
INVALID_INPUT: "INVALID_INPUT",
|
|
4466
|
-
INTERNAL_ERROR: "INTERNAL_ERROR"
|
|
4890
|
+
INTERNAL_ERROR: "INTERNAL_ERROR",
|
|
4891
|
+
// Variables
|
|
4892
|
+
MISSING_VARIABLES: "MISSING_VARIABLES"
|
|
4467
4893
|
};
|
|
4468
4894
|
|
|
4469
4895
|
// src/bin/refly.ts
|
|
4470
|
-
var
|
|
4471
|
-
var
|
|
4896
|
+
var fs26 = __toESM(require("fs"));
|
|
4897
|
+
var path22 = __toESM(require("path"));
|
|
4472
4898
|
|
|
4473
4899
|
// src/commands/init.ts
|
|
4474
4900
|
init_cjs_shims();
|
|
@@ -4973,8 +5399,8 @@ function getErrorMap() {
|
|
|
4973
5399
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
4974
5400
|
init_cjs_shims();
|
|
4975
5401
|
var makeIssue = (params) => {
|
|
4976
|
-
const { data, path:
|
|
4977
|
-
const fullPath = [...
|
|
5402
|
+
const { data, path: path23, errorMaps, issueData } = params;
|
|
5403
|
+
const fullPath = [...path23, ...issueData.path || []];
|
|
4978
5404
|
const fullIssue = {
|
|
4979
5405
|
...issueData,
|
|
4980
5406
|
path: fullPath
|
|
@@ -5094,11 +5520,11 @@ var errorUtil;
|
|
|
5094
5520
|
|
|
5095
5521
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
5096
5522
|
var ParseInputLazyPath = class {
|
|
5097
|
-
constructor(parent, value,
|
|
5523
|
+
constructor(parent, value, path23, key) {
|
|
5098
5524
|
this._cachedPath = [];
|
|
5099
5525
|
this.parent = parent;
|
|
5100
5526
|
this.data = value;
|
|
5101
|
-
this._path =
|
|
5527
|
+
this._path = path23;
|
|
5102
5528
|
this._key = key;
|
|
5103
5529
|
}
|
|
5104
5530
|
get path() {
|
|
@@ -8706,23 +9132,41 @@ init_paths();
|
|
|
8706
9132
|
|
|
8707
9133
|
// src/skill/installer.ts
|
|
8708
9134
|
init_cjs_shims();
|
|
8709
|
-
var
|
|
8710
|
-
var
|
|
9135
|
+
var fs5 = __toESM(require("fs"));
|
|
9136
|
+
var path5 = __toESM(require("path"));
|
|
8711
9137
|
init_paths();
|
|
8712
9138
|
init_logger();
|
|
9139
|
+
init_symlink();
|
|
9140
|
+
function removeOldSkillDirectory() {
|
|
9141
|
+
const claudeSkillPath = getClaudeSkillSymlinkPath("refly");
|
|
9142
|
+
if (!fs5.existsSync(claudeSkillPath)) {
|
|
9143
|
+
return;
|
|
9144
|
+
}
|
|
9145
|
+
try {
|
|
9146
|
+
const stat = fs5.lstatSync(claudeSkillPath);
|
|
9147
|
+
if (stat.isSymbolicLink()) {
|
|
9148
|
+
fs5.unlinkSync(claudeSkillPath);
|
|
9149
|
+
} else if (stat.isDirectory()) {
|
|
9150
|
+
fs5.rmSync(claudeSkillPath, { recursive: true, force: true });
|
|
9151
|
+
logger.info("Removed old skill directory");
|
|
9152
|
+
}
|
|
9153
|
+
} catch (err) {
|
|
9154
|
+
logger.warn("Failed to remove old directory:", err);
|
|
9155
|
+
}
|
|
9156
|
+
}
|
|
8713
9157
|
function getPackageSkillDir() {
|
|
8714
9158
|
const possiblePaths = [
|
|
8715
|
-
|
|
9159
|
+
path5.join(__dirname, "..", "..", "skill"),
|
|
8716
9160
|
// Built package: dist/bin/../../skill
|
|
8717
|
-
|
|
9161
|
+
path5.join(__dirname, "..", "..", "..", "skill"),
|
|
8718
9162
|
// Development: dist/bin/../../../skill
|
|
8719
|
-
|
|
9163
|
+
path5.join(__dirname, "..", "skill")
|
|
8720
9164
|
// Alternative: dist/../skill
|
|
8721
9165
|
];
|
|
8722
9166
|
logger.debug("Looking for skill files, __dirname:", __dirname);
|
|
8723
9167
|
for (const p of possiblePaths) {
|
|
8724
|
-
const resolved =
|
|
8725
|
-
const exists =
|
|
9168
|
+
const resolved = path5.resolve(p);
|
|
9169
|
+
const exists = fs5.existsSync(resolved);
|
|
8726
9170
|
logger.debug(` Checking path: ${resolved} - exists: ${exists}`);
|
|
8727
9171
|
if (exists) {
|
|
8728
9172
|
return resolved;
|
|
@@ -8734,42 +9178,52 @@ function installSkill() {
|
|
|
8734
9178
|
const result = {
|
|
8735
9179
|
skillInstalled: false,
|
|
8736
9180
|
skillPath: null,
|
|
9181
|
+
symlinkPath: null,
|
|
8737
9182
|
commandsInstalled: false,
|
|
8738
9183
|
commandsPath: null,
|
|
8739
9184
|
version: getSkillVersion()
|
|
8740
9185
|
};
|
|
8741
9186
|
const sourceDir = getPackageSkillDir();
|
|
8742
9187
|
logger.debug("Source skill directory:", sourceDir);
|
|
8743
|
-
|
|
9188
|
+
ensureReflySkillsDir();
|
|
9189
|
+
const targetDir = getReflyBaseSkillDir();
|
|
8744
9190
|
logger.debug("Target skill directory:", targetDir);
|
|
8745
9191
|
try {
|
|
8746
9192
|
ensureDir(targetDir);
|
|
8747
|
-
ensureDir(
|
|
9193
|
+
ensureDir(path5.join(targetDir, "rules"));
|
|
8748
9194
|
logger.debug("Created target directories");
|
|
8749
9195
|
} catch (err) {
|
|
8750
9196
|
logger.error("Failed to create target directories:", err);
|
|
8751
9197
|
throw err;
|
|
8752
9198
|
}
|
|
8753
|
-
const skillSource =
|
|
8754
|
-
const skillTarget =
|
|
9199
|
+
const skillSource = path5.join(sourceDir, "SKILL.md");
|
|
9200
|
+
const skillTarget = path5.join(targetDir, "SKILL.md");
|
|
8755
9201
|
logger.debug(`Copying SKILL.md: ${skillSource} -> ${skillTarget}`);
|
|
8756
|
-
if (
|
|
8757
|
-
|
|
9202
|
+
if (fs5.existsSync(skillSource)) {
|
|
9203
|
+
fs5.copyFileSync(skillSource, skillTarget);
|
|
8758
9204
|
result.skillInstalled = true;
|
|
8759
9205
|
result.skillPath = targetDir;
|
|
8760
9206
|
logger.debug("SKILL.md copied successfully");
|
|
8761
9207
|
} else {
|
|
8762
9208
|
logger.warn("SKILL.md source not found:", skillSource);
|
|
8763
9209
|
}
|
|
8764
|
-
const refsSource =
|
|
8765
|
-
const
|
|
8766
|
-
if (
|
|
8767
|
-
const files =
|
|
8768
|
-
logger.debug(`Copying ${files.length}
|
|
9210
|
+
const refsSource = path5.join(sourceDir, "references");
|
|
9211
|
+
const rulesTarget = path5.join(targetDir, "rules");
|
|
9212
|
+
if (fs5.existsSync(refsSource)) {
|
|
9213
|
+
const files = fs5.readdirSync(refsSource);
|
|
9214
|
+
logger.debug(`Copying ${files.length} rule files`);
|
|
8769
9215
|
for (const file of files) {
|
|
8770
|
-
|
|
9216
|
+
fs5.copyFileSync(path5.join(refsSource, file), path5.join(rulesTarget, file));
|
|
8771
9217
|
}
|
|
8772
9218
|
}
|
|
9219
|
+
removeOldSkillDirectory();
|
|
9220
|
+
const symlinkResult = createSkillSymlink("refly");
|
|
9221
|
+
if (symlinkResult.success) {
|
|
9222
|
+
result.symlinkPath = symlinkResult.claudePath;
|
|
9223
|
+
logger.info(`Created symlink: ${symlinkResult.claudePath} -> ${symlinkResult.reflyPath}`);
|
|
9224
|
+
} else {
|
|
9225
|
+
logger.warn(`Failed to create symlink: ${symlinkResult.error}`);
|
|
9226
|
+
}
|
|
8773
9227
|
const commandsDir = getClaudeCommandsDir();
|
|
8774
9228
|
logger.debug("Commands directory:", commandsDir);
|
|
8775
9229
|
ensureDir(commandsDir);
|
|
@@ -8781,20 +9235,21 @@ function installSkill() {
|
|
|
8781
9235
|
updateSkillInfo(result.version);
|
|
8782
9236
|
logger.info("Skill installation complete:", {
|
|
8783
9237
|
skillInstalled: result.skillInstalled,
|
|
9238
|
+
symlinkPath: result.symlinkPath,
|
|
8784
9239
|
commandsInstalled: result.commandsInstalled
|
|
8785
9240
|
});
|
|
8786
9241
|
return result;
|
|
8787
9242
|
}
|
|
8788
9243
|
function installSlashCommands(sourceDir, targetDir) {
|
|
8789
|
-
const commandsSource =
|
|
8790
|
-
if (!
|
|
9244
|
+
const commandsSource = path5.join(sourceDir, "..", "commands");
|
|
9245
|
+
if (!fs5.existsSync(commandsSource)) {
|
|
8791
9246
|
return false;
|
|
8792
9247
|
}
|
|
8793
9248
|
try {
|
|
8794
|
-
const files =
|
|
9249
|
+
const files = fs5.readdirSync(commandsSource);
|
|
8795
9250
|
for (const file of files) {
|
|
8796
9251
|
if (file.endsWith(".md")) {
|
|
8797
|
-
|
|
9252
|
+
fs5.copyFileSync(path5.join(commandsSource, file), path5.join(targetDir, file));
|
|
8798
9253
|
}
|
|
8799
9254
|
}
|
|
8800
9255
|
return files.length > 0;
|
|
@@ -8804,8 +9259,8 @@ function installSlashCommands(sourceDir, targetDir) {
|
|
|
8804
9259
|
}
|
|
8805
9260
|
function getSkillVersion() {
|
|
8806
9261
|
try {
|
|
8807
|
-
const skillPath =
|
|
8808
|
-
const content =
|
|
9262
|
+
const skillPath = path5.join(getPackageSkillDir(), "SKILL.md");
|
|
9263
|
+
const content = fs5.readFileSync(skillPath, "utf-8");
|
|
8809
9264
|
const versionMatch = content.match(/version:\s*(\d+\.\d+\.\d+)/);
|
|
8810
9265
|
if (versionMatch) {
|
|
8811
9266
|
return versionMatch[1];
|
|
@@ -8813,23 +9268,26 @@ function getSkillVersion() {
|
|
|
8813
9268
|
} catch {
|
|
8814
9269
|
}
|
|
8815
9270
|
try {
|
|
8816
|
-
const pkgPath =
|
|
8817
|
-
const pkg = JSON.parse(
|
|
9271
|
+
const pkgPath = path5.join(__dirname, "..", "..", "package.json");
|
|
9272
|
+
const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
|
|
8818
9273
|
return pkg.version;
|
|
8819
9274
|
} catch {
|
|
8820
9275
|
return "0.1.0";
|
|
8821
9276
|
}
|
|
8822
9277
|
}
|
|
8823
9278
|
function isSkillInstalled() {
|
|
8824
|
-
const skillPath =
|
|
8825
|
-
if (!
|
|
9279
|
+
const skillPath = path5.join(getReflyBaseSkillDir(), "SKILL.md");
|
|
9280
|
+
if (!fs5.existsSync(skillPath)) {
|
|
8826
9281
|
return { installed: false, upToDate: false };
|
|
8827
9282
|
}
|
|
8828
9283
|
const currentVersion = getSkillVersion();
|
|
9284
|
+
const { isSkillSymlinkValid: isSkillSymlinkValid2 } = (init_symlink(), __toCommonJS(symlink_exports));
|
|
9285
|
+
const symlinkStatus = isSkillSymlinkValid2("refly");
|
|
8829
9286
|
return {
|
|
8830
9287
|
installed: true,
|
|
8831
9288
|
upToDate: true,
|
|
8832
|
-
currentVersion
|
|
9289
|
+
currentVersion,
|
|
9290
|
+
symlinkValid: symlinkStatus.isValid
|
|
8833
9291
|
};
|
|
8834
9292
|
}
|
|
8835
9293
|
|
|
@@ -9314,14 +9772,14 @@ var baseOpen = async (options) => {
|
|
|
9314
9772
|
}
|
|
9315
9773
|
const subprocess = import_node_child_process5.default.spawn(command, cliArguments, childProcessOptions);
|
|
9316
9774
|
if (options.wait) {
|
|
9317
|
-
return new Promise((
|
|
9775
|
+
return new Promise((resolve7, reject) => {
|
|
9318
9776
|
subprocess.once("error", reject);
|
|
9319
9777
|
subprocess.once("close", (exitCode) => {
|
|
9320
9778
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
9321
9779
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
9322
9780
|
return;
|
|
9323
9781
|
}
|
|
9324
|
-
|
|
9782
|
+
resolve7(subprocess);
|
|
9325
9783
|
});
|
|
9326
9784
|
});
|
|
9327
9785
|
}
|
|
@@ -9397,19 +9855,20 @@ var open_default = open;
|
|
|
9397
9855
|
|
|
9398
9856
|
// src/api/client.ts
|
|
9399
9857
|
init_cjs_shims();
|
|
9400
|
-
var
|
|
9858
|
+
var fs11 = __toESM(require("fs"));
|
|
9401
9859
|
var import_node_fs4 = require("fs");
|
|
9402
|
-
var
|
|
9860
|
+
var path7 = __toESM(require("path"));
|
|
9403
9861
|
var import_mime = __toESM(require("mime"));
|
|
9404
9862
|
|
|
9405
9863
|
// src/utils/errors.ts
|
|
9406
9864
|
init_cjs_shims();
|
|
9407
9865
|
var CLIError = class extends Error {
|
|
9408
|
-
constructor(code, message, details, hint) {
|
|
9866
|
+
constructor(code, message, details, hint, suggestedFix) {
|
|
9409
9867
|
super(message);
|
|
9410
9868
|
this.code = code;
|
|
9411
9869
|
this.details = details;
|
|
9412
9870
|
this.hint = hint;
|
|
9871
|
+
this.suggestedFix = suggestedFix;
|
|
9413
9872
|
this.name = "CLIError";
|
|
9414
9873
|
}
|
|
9415
9874
|
};
|
|
@@ -9427,10 +9886,10 @@ var NetworkError = class extends CLIError {
|
|
|
9427
9886
|
// src/api/client.ts
|
|
9428
9887
|
init_logger();
|
|
9429
9888
|
var DEFAULT_TIMEOUT = 3e4;
|
|
9430
|
-
async function apiRequest(
|
|
9889
|
+
async function apiRequest(path23, options = {}) {
|
|
9431
9890
|
const { method = "GET", body, query, timeout = DEFAULT_TIMEOUT, requireAuth = true } = options;
|
|
9432
9891
|
const endpoint = getApiEndpoint();
|
|
9433
|
-
let url = `${endpoint}${
|
|
9892
|
+
let url = `${endpoint}${path23}`;
|
|
9434
9893
|
if (query && Object.keys(query).length > 0) {
|
|
9435
9894
|
const params = new URLSearchParams(query);
|
|
9436
9895
|
url = `${url}?${params.toString()}`;
|
|
@@ -9468,7 +9927,7 @@ async function apiRequest(path16, options = {}) {
|
|
|
9468
9927
|
const controller = new AbortController();
|
|
9469
9928
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
9470
9929
|
try {
|
|
9471
|
-
logger.debug(`API Request: ${method} ${
|
|
9930
|
+
logger.debug(`API Request: ${method} ${path23}`);
|
|
9472
9931
|
const response = await fetch(url, {
|
|
9473
9932
|
method,
|
|
9474
9933
|
headers,
|
|
@@ -9560,7 +10019,8 @@ function mapAPIError(status, response) {
|
|
|
9560
10019
|
cliError.code || "UNKNOWN",
|
|
9561
10020
|
cliError.message || "Unknown error",
|
|
9562
10021
|
void 0,
|
|
9563
|
-
cliError.hint
|
|
10022
|
+
cliError.hint,
|
|
10023
|
+
cliError.suggestedFix
|
|
9564
10024
|
);
|
|
9565
10025
|
}
|
|
9566
10026
|
const errCode = response.errCode ?? response.error ?? "UNKNOWN";
|
|
@@ -9582,10 +10042,10 @@ function mapAPIError(status, response) {
|
|
|
9582
10042
|
}
|
|
9583
10043
|
return new CLIError(errCode, errMsg);
|
|
9584
10044
|
}
|
|
9585
|
-
async function apiRequestStream(
|
|
10045
|
+
async function apiRequestStream(path23, options = {}) {
|
|
9586
10046
|
const { timeout = 3e5 } = options;
|
|
9587
10047
|
const endpoint = getApiEndpoint();
|
|
9588
|
-
const url = `${endpoint}${
|
|
10048
|
+
const url = `${endpoint}${path23}`;
|
|
9589
10049
|
const headers = {
|
|
9590
10050
|
"User-Agent": "refly-cli/0.1.0"
|
|
9591
10051
|
};
|
|
@@ -9616,7 +10076,7 @@ async function apiRequestStream(path16, options = {}) {
|
|
|
9616
10076
|
const controller = new AbortController();
|
|
9617
10077
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
9618
10078
|
try {
|
|
9619
|
-
logger.debug(`API Stream Request: GET ${
|
|
10079
|
+
logger.debug(`API Stream Request: GET ${path23}`);
|
|
9620
10080
|
const response = await fetch(url, {
|
|
9621
10081
|
method: "GET",
|
|
9622
10082
|
headers,
|
|
@@ -9711,7 +10171,7 @@ async function uploadToPresignedUrl(presignedUrl, filePath, contentType, retryCo
|
|
|
9711
10171
|
const controller = new AbortController();
|
|
9712
10172
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
9713
10173
|
try {
|
|
9714
|
-
const fileBuffer = await
|
|
10174
|
+
const fileBuffer = await fs11.promises.readFile(filePath);
|
|
9715
10175
|
const response = await fetch(presignedUrl, {
|
|
9716
10176
|
method: "PUT",
|
|
9717
10177
|
headers: {
|
|
@@ -9769,7 +10229,7 @@ async function apiGetWorkflow(workflowId) {
|
|
|
9769
10229
|
return apiRequest(`/v1/cli/workflow/${workflowId}`);
|
|
9770
10230
|
}
|
|
9771
10231
|
async function apiUploadDriveFile(filePath, canvasId, options) {
|
|
9772
|
-
const filename =
|
|
10232
|
+
const filename = path7.basename(filePath);
|
|
9773
10233
|
const mimeType = getMimeType(filePath);
|
|
9774
10234
|
const fileStats = (0, import_node_fs4.statSync)(filePath);
|
|
9775
10235
|
logger.debug(`Starting presigned upload: ${filename} (${fileStats.size} bytes)`);
|
|
@@ -9800,6 +10260,22 @@ async function apiUploadDriveFile(filePath, canvasId, options) {
|
|
|
9800
10260
|
throw error;
|
|
9801
10261
|
}
|
|
9802
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
|
+
}
|
|
9803
10279
|
|
|
9804
10280
|
// src/commands/login.ts
|
|
9805
10281
|
init_logger();
|
|
@@ -10016,7 +10492,7 @@ async function getUserInfoFromToken(accessToken) {
|
|
|
10016
10492
|
};
|
|
10017
10493
|
}
|
|
10018
10494
|
function sleep(ms) {
|
|
10019
|
-
return new Promise((
|
|
10495
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
10020
10496
|
}
|
|
10021
10497
|
|
|
10022
10498
|
// src/commands/init.ts
|
|
@@ -10083,6 +10559,7 @@ var initCommand = new Command("init").description("Initialize Refly CLI, install
|
|
|
10083
10559
|
apiEndpoint,
|
|
10084
10560
|
skillInstalled: installResult.skillInstalled,
|
|
10085
10561
|
skillPath: installResult.skillPath,
|
|
10562
|
+
symlinkPath: installResult.symlinkPath,
|
|
10086
10563
|
commandsInstalled: installResult.commandsInstalled,
|
|
10087
10564
|
commandsPath: installResult.commandsPath,
|
|
10088
10565
|
version: installResult.version
|
|
@@ -10135,7 +10612,10 @@ var initCommand = new Command("init").description("Initialize Refly CLI, install
|
|
|
10135
10612
|
configDir: getReflyDir(),
|
|
10136
10613
|
apiEndpoint,
|
|
10137
10614
|
skillInstalled: installResult.skillInstalled,
|
|
10615
|
+
skillPath: installResult.skillPath,
|
|
10616
|
+
symlinkPath: installResult.symlinkPath,
|
|
10138
10617
|
commandsInstalled: installResult.commandsInstalled,
|
|
10618
|
+
commandsPath: installResult.commandsPath,
|
|
10139
10619
|
version: installResult.version,
|
|
10140
10620
|
authenticated: !!(getAccessToken() || getApiKey())
|
|
10141
10621
|
});
|
|
@@ -10270,7 +10750,7 @@ var import_node_child_process6 = require("child_process");
|
|
|
10270
10750
|
var import_node_fs5 = __toESM(require("fs"));
|
|
10271
10751
|
init_logger();
|
|
10272
10752
|
init_paths();
|
|
10273
|
-
var CLI_VERSION = "0.1.
|
|
10753
|
+
var CLI_VERSION = "0.1.18";
|
|
10274
10754
|
var NPM_TAG = "test";
|
|
10275
10755
|
function compareSemver(a, b) {
|
|
10276
10756
|
const parseVersion = (v) => {
|
|
@@ -10526,16 +11006,16 @@ configCommand.action(() => {
|
|
|
10526
11006
|
};
|
|
10527
11007
|
ok("config", safeConfig);
|
|
10528
11008
|
});
|
|
10529
|
-
function getNestedValue(obj,
|
|
10530
|
-
return
|
|
11009
|
+
function getNestedValue(obj, path23) {
|
|
11010
|
+
return path23.split(".").reduce((current, key) => {
|
|
10531
11011
|
if (current && typeof current === "object" && key in current) {
|
|
10532
11012
|
return current[key];
|
|
10533
11013
|
}
|
|
10534
11014
|
return void 0;
|
|
10535
11015
|
}, obj);
|
|
10536
11016
|
}
|
|
10537
|
-
function setNestedValue(obj,
|
|
10538
|
-
const keys =
|
|
11017
|
+
function setNestedValue(obj, path23, value) {
|
|
11018
|
+
const keys = path23.split(".");
|
|
10539
11019
|
const lastKey = keys.pop();
|
|
10540
11020
|
let current = obj;
|
|
10541
11021
|
for (const key of keys) {
|
|
@@ -10640,14 +11120,25 @@ var workflowCreateCommand = new Command("create").description("Create a workflow
|
|
|
10640
11120
|
spec = Array.isArray(parsed) ? { nodes: parsed } : parsed;
|
|
10641
11121
|
} catch {
|
|
10642
11122
|
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --spec", {
|
|
10643
|
-
hint: "
|
|
11123
|
+
hint: `Spec format: '[{"id": "node1", "type": "skill", "query": "task description", "toolsetKeys": ["web_search"]}]'
|
|
11124
|
+
Or full format: '{"nodes": [...], "edges": [...]}'`,
|
|
11125
|
+
suggestedFix: {
|
|
11126
|
+
field: "--spec",
|
|
11127
|
+
format: "json-array | json-object",
|
|
11128
|
+
example: '[{"id": "node1", "type": "skill", "query": "task description", "toolsetKeys": ["web_search"]}]'
|
|
11129
|
+
}
|
|
10644
11130
|
});
|
|
10645
11131
|
return;
|
|
10646
11132
|
}
|
|
10647
11133
|
const validationError = validateSimplifiedSpec(spec);
|
|
10648
11134
|
if (validationError) {
|
|
10649
11135
|
fail(ErrorCodes.INVALID_INPUT, validationError, {
|
|
10650
|
-
hint: 'Use simplified format: [{"id":"node1","type":"skill","query":"...","toolsetKeys":["tool_name"],"dependsOn":["other_node"]}]'
|
|
11136
|
+
hint: 'Use simplified format: [{"id":"node1","type":"skill","query":"...","toolsetKeys":["tool_name"],"dependsOn":["other_node"]}]',
|
|
11137
|
+
suggestedFix: {
|
|
11138
|
+
field: "--spec",
|
|
11139
|
+
format: "json-array",
|
|
11140
|
+
example: '[{"id":"node1","type":"skill","query":"...","toolsetKeys":["tool_name"],"dependsOn":["other_node"]}]'
|
|
11141
|
+
}
|
|
10651
11142
|
});
|
|
10652
11143
|
return;
|
|
10653
11144
|
}
|
|
@@ -10667,7 +11158,11 @@ var workflowCreateCommand = new Command("create").description("Create a workflow
|
|
|
10667
11158
|
});
|
|
10668
11159
|
} catch (error) {
|
|
10669
11160
|
if (error instanceof CLIError) {
|
|
10670
|
-
fail(error.code, error.message, {
|
|
11161
|
+
fail(error.code, error.message, {
|
|
11162
|
+
details: error.details,
|
|
11163
|
+
hint: error.hint,
|
|
11164
|
+
suggestedFix: error.suggestedFix
|
|
11165
|
+
});
|
|
10671
11166
|
return;
|
|
10672
11167
|
}
|
|
10673
11168
|
fail(
|
|
@@ -10729,7 +11224,13 @@ var workflowGenerateCommand = new Command("generate").description("Generate a wo
|
|
|
10729
11224
|
variables = JSON.parse(options.variables);
|
|
10730
11225
|
} catch {
|
|
10731
11226
|
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --variables", {
|
|
10732
|
-
hint: "
|
|
11227
|
+
hint: `Variables format: '[{"name": "varName", "variableType": "string", "description": "desc", "required": true}]'
|
|
11228
|
+
Variable types: "string" (text input) or "resource" (file input)`,
|
|
11229
|
+
suggestedFix: {
|
|
11230
|
+
field: "--variables",
|
|
11231
|
+
format: "json-array",
|
|
11232
|
+
example: '[{"name": "varName", "variableType": "string", "description": "desc", "required": true}]'
|
|
11233
|
+
}
|
|
10733
11234
|
});
|
|
10734
11235
|
}
|
|
10735
11236
|
}
|
|
@@ -10782,7 +11283,8 @@ var workflowGenerateCommand = new Command("generate").description("Generate a wo
|
|
|
10782
11283
|
if (error instanceof CLIError) {
|
|
10783
11284
|
fail(error.code, error.message, {
|
|
10784
11285
|
details: { ...error.details, cleanedUp: cleanupResult?.deleted },
|
|
10785
|
-
hint: error.hint
|
|
11286
|
+
hint: error.hint,
|
|
11287
|
+
suggestedFix: error.suggestedFix
|
|
10786
11288
|
});
|
|
10787
11289
|
}
|
|
10788
11290
|
fail(
|
|
@@ -10820,7 +11322,11 @@ var workflowListCommand = new Command("list").description("List all workflows").
|
|
|
10820
11322
|
});
|
|
10821
11323
|
} catch (error) {
|
|
10822
11324
|
if (error instanceof CLIError) {
|
|
10823
|
-
fail(error.code, error.message, {
|
|
11325
|
+
fail(error.code, error.message, {
|
|
11326
|
+
details: error.details,
|
|
11327
|
+
hint: error.hint,
|
|
11328
|
+
suggestedFix: error.suggestedFix
|
|
11329
|
+
});
|
|
10824
11330
|
}
|
|
10825
11331
|
fail(
|
|
10826
11332
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -10837,133 +11343,15 @@ var workflowGetCommand = new Command("get").description("Get workflow details").
|
|
|
10837
11343
|
ok("workflow.get", result);
|
|
10838
11344
|
} catch (error) {
|
|
10839
11345
|
if (error instanceof CLIError) {
|
|
10840
|
-
fail(error.code, error.message, {
|
|
10841
|
-
|
|
10842
|
-
|
|
10843
|
-
|
|
10844
|
-
error instanceof Error ? error.message : "Failed to get workflow"
|
|
10845
|
-
);
|
|
10846
|
-
}
|
|
10847
|
-
});
|
|
10848
|
-
|
|
10849
|
-
// src/commands/workflow/edit.ts
|
|
10850
|
-
init_cjs_shims();
|
|
10851
|
-
function transformOperations(ops) {
|
|
10852
|
-
const opMapping = {
|
|
10853
|
-
add: "add_node",
|
|
10854
|
-
remove: "remove_node",
|
|
10855
|
-
update: "update_node",
|
|
10856
|
-
addEdge: "add_edge",
|
|
10857
|
-
removeEdge: "remove_edge",
|
|
10858
|
-
// Also support direct backend format
|
|
10859
|
-
add_node: "add_node",
|
|
10860
|
-
remove_node: "remove_node",
|
|
10861
|
-
update_node: "update_node",
|
|
10862
|
-
add_edge: "add_edge",
|
|
10863
|
-
remove_edge: "remove_edge"
|
|
10864
|
-
};
|
|
10865
|
-
return ops.map((op) => {
|
|
10866
|
-
const { op: opType, ...rest } = op;
|
|
10867
|
-
const backendType = opMapping[opType];
|
|
10868
|
-
if (!backendType) {
|
|
10869
|
-
throw new Error(`Unknown operation type: ${opType}`);
|
|
10870
|
-
}
|
|
10871
|
-
return {
|
|
10872
|
-
type: backendType,
|
|
10873
|
-
...rest
|
|
10874
|
-
};
|
|
10875
|
-
});
|
|
10876
|
-
}
|
|
10877
|
-
var workflowEditCommand = new Command("edit").description("Edit an existing workflow").argument("<workflowId>", "Workflow ID or URL").option("--name <name>", "New workflow name").option("--ops <json>", "Node/edge operations as JSON array").option("--variables <json>", "Workflow variables as JSON array").option("--toolsets <keys>", 'Toolset inventory keys (comma-separated, e.g., "tavily,fal_audio")').option("--auto-layout", "Enable auto-layout to prevent node overlapping").action(async (workflowIdOrUrl, options) => {
|
|
10878
|
-
try {
|
|
10879
|
-
let workflowId = workflowIdOrUrl;
|
|
10880
|
-
if (workflowIdOrUrl.includes("/workflow/")) {
|
|
10881
|
-
const match = workflowIdOrUrl.match(/\/workflow\/(c-[a-z0-9]+)/);
|
|
10882
|
-
if (match) {
|
|
10883
|
-
workflowId = match[1];
|
|
10884
|
-
}
|
|
10885
|
-
}
|
|
10886
|
-
const body = {};
|
|
10887
|
-
if (options.name) {
|
|
10888
|
-
body.name = options.name;
|
|
10889
|
-
}
|
|
10890
|
-
let toolsetKeys;
|
|
10891
|
-
if (options.toolsets) {
|
|
10892
|
-
toolsetKeys = options.toolsets.split(",").map((k) => k.trim()).filter((k) => k.length > 0);
|
|
10893
|
-
}
|
|
10894
|
-
if (options.ops) {
|
|
10895
|
-
try {
|
|
10896
|
-
const rawOps = JSON.parse(options.ops);
|
|
10897
|
-
body.operations = transformOperations(rawOps);
|
|
10898
|
-
if (toolsetKeys && toolsetKeys.length > 0 && body.operations) {
|
|
10899
|
-
body.operations = body.operations.map((op) => {
|
|
10900
|
-
if (op.type === "add_node" && op.node) {
|
|
10901
|
-
const node = op.node;
|
|
10902
|
-
const data = node.data || {};
|
|
10903
|
-
const metadata = data.metadata || {};
|
|
10904
|
-
return {
|
|
10905
|
-
...op,
|
|
10906
|
-
node: {
|
|
10907
|
-
...node,
|
|
10908
|
-
data: {
|
|
10909
|
-
...data,
|
|
10910
|
-
metadata: {
|
|
10911
|
-
...metadata,
|
|
10912
|
-
toolsetKeys
|
|
10913
|
-
}
|
|
10914
|
-
}
|
|
10915
|
-
}
|
|
10916
|
-
};
|
|
10917
|
-
}
|
|
10918
|
-
return op;
|
|
10919
|
-
});
|
|
10920
|
-
}
|
|
10921
|
-
} catch (error) {
|
|
10922
|
-
fail(ErrorCodes.INVALID_INPUT, `Invalid operations: ${error.message}`, {
|
|
10923
|
-
hint: "Ensure the operations are a valid JSON array with correct op types"
|
|
10924
|
-
});
|
|
10925
|
-
}
|
|
10926
|
-
}
|
|
10927
|
-
if (options.variables) {
|
|
10928
|
-
try {
|
|
10929
|
-
body.variables = JSON.parse(options.variables);
|
|
10930
|
-
} catch {
|
|
10931
|
-
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --variables", {
|
|
10932
|
-
hint: "Ensure the variables are a valid JSON array"
|
|
10933
|
-
});
|
|
10934
|
-
}
|
|
10935
|
-
}
|
|
10936
|
-
if (!options.name && !options.ops && !options.variables) {
|
|
10937
|
-
fail(ErrorCodes.INVALID_INPUT, "No update options provided", {
|
|
10938
|
-
hint: "Use --name, --ops, --variables, or --toolsets to specify what to update"
|
|
11346
|
+
fail(error.code, error.message, {
|
|
11347
|
+
details: error.details,
|
|
11348
|
+
hint: error.hint,
|
|
11349
|
+
suggestedFix: error.suggestedFix
|
|
10939
11350
|
});
|
|
10940
11351
|
}
|
|
10941
|
-
let endpoint = `/v1/cli/workflow/${workflowId}`;
|
|
10942
|
-
const queryParams = [];
|
|
10943
|
-
if (toolsetKeys && toolsetKeys.length > 0) {
|
|
10944
|
-
queryParams.push("resolveToolsetKeys=true");
|
|
10945
|
-
}
|
|
10946
|
-
if (options.autoLayout) {
|
|
10947
|
-
queryParams.push("autoLayout=true");
|
|
10948
|
-
}
|
|
10949
|
-
if (queryParams.length > 0) {
|
|
10950
|
-
endpoint += `?${queryParams.join("&")}`;
|
|
10951
|
-
}
|
|
10952
|
-
await apiRequest(endpoint, {
|
|
10953
|
-
method: "PATCH",
|
|
10954
|
-
body
|
|
10955
|
-
});
|
|
10956
|
-
ok("workflow.edit", {
|
|
10957
|
-
message: "Workflow updated successfully",
|
|
10958
|
-
workflowId
|
|
10959
|
-
});
|
|
10960
|
-
} catch (error) {
|
|
10961
|
-
if (error instanceof CLIError) {
|
|
10962
|
-
fail(error.code, error.message, { details: error.details, hint: error.hint });
|
|
10963
|
-
}
|
|
10964
11352
|
fail(
|
|
10965
11353
|
ErrorCodes.INTERNAL_ERROR,
|
|
10966
|
-
error instanceof Error ? error.message : "Failed to
|
|
11354
|
+
error instanceof Error ? error.message : "Failed to get workflow"
|
|
10967
11355
|
);
|
|
10968
11356
|
}
|
|
10969
11357
|
});
|
|
@@ -10981,7 +11369,11 @@ var workflowDeleteCommand = new Command("delete").description("Delete a workflow
|
|
|
10981
11369
|
});
|
|
10982
11370
|
} catch (error) {
|
|
10983
11371
|
if (error instanceof CLIError) {
|
|
10984
|
-
fail(error.code, error.message, {
|
|
11372
|
+
fail(error.code, error.message, {
|
|
11373
|
+
details: error.details,
|
|
11374
|
+
hint: error.hint,
|
|
11375
|
+
suggestedFix: error.suggestedFix
|
|
11376
|
+
});
|
|
10985
11377
|
}
|
|
10986
11378
|
fail(
|
|
10987
11379
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -10994,14 +11386,14 @@ var workflowDeleteCommand = new Command("delete").description("Delete a workflow
|
|
|
10994
11386
|
init_cjs_shims();
|
|
10995
11387
|
var readline2 = __toESM(require("readline/promises"));
|
|
10996
11388
|
var import_node_process8 = require("process");
|
|
10997
|
-
var
|
|
11389
|
+
var path10 = __toESM(require("path"));
|
|
10998
11390
|
|
|
10999
11391
|
// src/utils/prompt.ts
|
|
11000
11392
|
init_cjs_shims();
|
|
11001
11393
|
var readline = __toESM(require("readline/promises"));
|
|
11002
11394
|
var import_node_process7 = require("process");
|
|
11003
|
-
var
|
|
11004
|
-
var
|
|
11395
|
+
var fs13 = __toESM(require("fs"));
|
|
11396
|
+
var path8 = __toESM(require("path"));
|
|
11005
11397
|
function isInteractive() {
|
|
11006
11398
|
return process.stdin?.isTTY ?? false;
|
|
11007
11399
|
}
|
|
@@ -11025,12 +11417,12 @@ async function promptForFilePath(variableName, resourceTypes, isRequired) {
|
|
|
11025
11417
|
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
|
11026
11418
|
resolvedPath = resolvedPath.replace("~", homeDir);
|
|
11027
11419
|
}
|
|
11028
|
-
resolvedPath =
|
|
11029
|
-
if (!
|
|
11420
|
+
resolvedPath = path8.resolve(resolvedPath);
|
|
11421
|
+
if (!fs13.existsSync(resolvedPath)) {
|
|
11030
11422
|
console.log(` File not found: ${resolvedPath}`);
|
|
11031
11423
|
continue;
|
|
11032
11424
|
}
|
|
11033
|
-
const stats =
|
|
11425
|
+
const stats = fs13.statSync(resolvedPath);
|
|
11034
11426
|
if (!stats.isFile()) {
|
|
11035
11427
|
console.log(` Not a file: ${resolvedPath}`);
|
|
11036
11428
|
continue;
|
|
@@ -11044,12 +11436,12 @@ async function promptForFilePath(variableName, resourceTypes, isRequired) {
|
|
|
11044
11436
|
|
|
11045
11437
|
// src/utils/file-type.ts
|
|
11046
11438
|
init_cjs_shims();
|
|
11047
|
-
var
|
|
11439
|
+
var path9 = __toESM(require("path"));
|
|
11048
11440
|
var IMAGE_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "ico", "tiff", "tif"];
|
|
11049
11441
|
var VIDEO_EXTENSIONS = ["mp4", "webm", "mov", "avi", "mkv", "flv", "wmv", "m4v"];
|
|
11050
11442
|
var AUDIO_EXTENSIONS = ["mp3", "wav", "ogg", "flac", "m4a", "aac", "wma", "opus"];
|
|
11051
11443
|
function determineFileType(filePath, mimeType) {
|
|
11052
|
-
const ext =
|
|
11444
|
+
const ext = path9.extname(filePath).slice(1).toLowerCase();
|
|
11053
11445
|
if (IMAGE_EXTENSIONS.includes(ext)) {
|
|
11054
11446
|
return "image";
|
|
11055
11447
|
}
|
|
@@ -11073,13 +11465,84 @@ function determineFileType(filePath, mimeType) {
|
|
|
11073
11465
|
return "document";
|
|
11074
11466
|
}
|
|
11075
11467
|
|
|
11076
|
-
// src/
|
|
11077
|
-
|
|
11078
|
-
|
|
11079
|
-
|
|
11080
|
-
|
|
11081
|
-
|
|
11082
|
-
|
|
11468
|
+
// src/utils/variable-check.ts
|
|
11469
|
+
init_cjs_shims();
|
|
11470
|
+
function checkRequiredVariables(definitions, providedInput) {
|
|
11471
|
+
const missing = [];
|
|
11472
|
+
const suggestedInput = { ...providedInput };
|
|
11473
|
+
for (const def of definitions) {
|
|
11474
|
+
if (!def.required) continue;
|
|
11475
|
+
const key = def.name;
|
|
11476
|
+
const hasValue = key in providedInput && providedInput[key] !== void 0 && providedInput[key] !== null;
|
|
11477
|
+
if (!hasValue) {
|
|
11478
|
+
missing.push(def);
|
|
11479
|
+
if (def.default !== void 0) {
|
|
11480
|
+
suggestedInput[key] = def.default;
|
|
11481
|
+
} else {
|
|
11482
|
+
suggestedInput[key] = "<value>";
|
|
11483
|
+
}
|
|
11484
|
+
}
|
|
11485
|
+
}
|
|
11486
|
+
return {
|
|
11487
|
+
valid: missing.length === 0,
|
|
11488
|
+
missing,
|
|
11489
|
+
suggestedInput
|
|
11490
|
+
};
|
|
11491
|
+
}
|
|
11492
|
+
function buildMissingVariablesError(commandType, targetId, targetName, result) {
|
|
11493
|
+
const displayName = targetName ? `"${targetName}"` : targetId;
|
|
11494
|
+
const inputJson = JSON.stringify(result.suggestedInput);
|
|
11495
|
+
const suggestedCommand = commandType === "workflow" ? `refly workflow run ${targetId} --input '${inputJson}'` : `refly skill run --name <name> --input '${inputJson}'`;
|
|
11496
|
+
return {
|
|
11497
|
+
code: "MISSING_VARIABLES",
|
|
11498
|
+
message: `Missing required variables for ${commandType} ${displayName}`,
|
|
11499
|
+
details: {
|
|
11500
|
+
missingVariables: result.missing.map((v) => ({
|
|
11501
|
+
name: v.name,
|
|
11502
|
+
type: v.variableType || "string",
|
|
11503
|
+
required: true,
|
|
11504
|
+
default: v.default,
|
|
11505
|
+
description: v.description
|
|
11506
|
+
})),
|
|
11507
|
+
suggestedInput: result.suggestedInput,
|
|
11508
|
+
suggestedCommand
|
|
11509
|
+
},
|
|
11510
|
+
hint: "Provide the missing variables via --input. See suggestedInput for the expected format.",
|
|
11511
|
+
suggestedFix: {
|
|
11512
|
+
field: "--input",
|
|
11513
|
+
format: "json-object",
|
|
11514
|
+
example: inputJson
|
|
11515
|
+
},
|
|
11516
|
+
recoverable: true
|
|
11517
|
+
};
|
|
11518
|
+
}
|
|
11519
|
+
function variablesToObject(variables) {
|
|
11520
|
+
const result = {};
|
|
11521
|
+
for (const v of variables) {
|
|
11522
|
+
if (!v.value || v.value.length === 0) continue;
|
|
11523
|
+
const firstValue = v.value[0];
|
|
11524
|
+
if (typeof firstValue === "object" && firstValue !== null) {
|
|
11525
|
+
if ("resource" in firstValue && typeof firstValue.resource === "object") {
|
|
11526
|
+
result[v.name] = firstValue;
|
|
11527
|
+
} else if ("text" in firstValue) {
|
|
11528
|
+
result[v.name] = firstValue.text;
|
|
11529
|
+
} else {
|
|
11530
|
+
result[v.name] = firstValue;
|
|
11531
|
+
}
|
|
11532
|
+
} else {
|
|
11533
|
+
result[v.name] = firstValue;
|
|
11534
|
+
}
|
|
11535
|
+
}
|
|
11536
|
+
return result;
|
|
11537
|
+
}
|
|
11538
|
+
|
|
11539
|
+
// src/commands/workflow/run.ts
|
|
11540
|
+
async function confirmAction(question) {
|
|
11541
|
+
const rl = readline2.createInterface({ input: import_node_process8.stdin, output: import_node_process8.stdout });
|
|
11542
|
+
try {
|
|
11543
|
+
const answer = await rl.question(`${question} (y/N): `);
|
|
11544
|
+
return answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
|
|
11545
|
+
} finally {
|
|
11083
11546
|
rl.close();
|
|
11084
11547
|
}
|
|
11085
11548
|
}
|
|
@@ -11104,12 +11567,12 @@ async function pollToolsStatus(workflowId, maxWaitTime = 15 * 60 * 1e3, pollInte
|
|
|
11104
11567
|
);
|
|
11105
11568
|
previousRemainingCount = remainingCount;
|
|
11106
11569
|
}
|
|
11107
|
-
await new Promise((
|
|
11570
|
+
await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
|
|
11108
11571
|
} catch (error) {
|
|
11109
11572
|
console.log(`
|
|
11110
11573
|
\u26A0\uFE0F Failed to check authorization status: ${error.message}`);
|
|
11111
11574
|
console.log("Continuing to wait...");
|
|
11112
|
-
await new Promise((
|
|
11575
|
+
await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
|
|
11113
11576
|
}
|
|
11114
11577
|
}
|
|
11115
11578
|
console.log("\n\u23F0 Timeout waiting for tool authorization.");
|
|
@@ -11143,30 +11606,70 @@ async function collectFileVariables(workflowId, existingInput, noPrompt) {
|
|
|
11143
11606
|
} catch (_error) {
|
|
11144
11607
|
return [];
|
|
11145
11608
|
}
|
|
11609
|
+
let savedVariables = [];
|
|
11610
|
+
try {
|
|
11611
|
+
savedVariables = await apiGetWorkflowVariables(workflowId);
|
|
11612
|
+
} catch (_error) {
|
|
11613
|
+
}
|
|
11146
11614
|
const resourceVars = (workflow.variables ?? []).filter(
|
|
11147
11615
|
(v) => v.variableType === "resource" && v.required === true
|
|
11148
11616
|
);
|
|
11149
11617
|
if (resourceVars.length === 0) {
|
|
11150
11618
|
return [];
|
|
11151
11619
|
}
|
|
11152
|
-
const
|
|
11153
|
-
const
|
|
11620
|
+
const invalidFormatVars = [];
|
|
11621
|
+
const hasValidFileValue = (variable) => {
|
|
11622
|
+
if (!variable) return false;
|
|
11623
|
+
const values = variable.value;
|
|
11624
|
+
if (!Array.isArray(values) || values.length === 0) return false;
|
|
11625
|
+
return values.some((val) => {
|
|
11626
|
+
const fileId = val?.resource?.fileId || val?.fileId;
|
|
11627
|
+
return typeof fileId === "string" && fileId.length > 0;
|
|
11628
|
+
});
|
|
11629
|
+
};
|
|
11154
11630
|
const missingVars = resourceVars.filter((v) => {
|
|
11155
|
-
|
|
11156
|
-
|
|
11631
|
+
const providedInInput = existingInput.find(
|
|
11632
|
+
(input3) => v.variableId && input3.variableId === v.variableId || v.name && input3.name === v.name
|
|
11633
|
+
);
|
|
11634
|
+
const savedValue = savedVariables.find(
|
|
11635
|
+
(saved) => v.variableId && saved.variableId === v.variableId || v.name && saved.name === v.name
|
|
11636
|
+
);
|
|
11637
|
+
if (providedInInput) {
|
|
11638
|
+
if (hasValidFileValue(providedInInput)) {
|
|
11639
|
+
return false;
|
|
11640
|
+
}
|
|
11641
|
+
invalidFormatVars.push({
|
|
11642
|
+
name: v.name,
|
|
11643
|
+
reason: "invalid format in --input"
|
|
11644
|
+
});
|
|
11645
|
+
}
|
|
11646
|
+
if (hasValidFileValue(savedValue)) {
|
|
11647
|
+
return false;
|
|
11648
|
+
}
|
|
11157
11649
|
return true;
|
|
11158
11650
|
});
|
|
11159
11651
|
if (missingVars.length === 0) {
|
|
11160
11652
|
return [];
|
|
11161
11653
|
}
|
|
11162
11654
|
if (noPrompt || !isInteractive()) {
|
|
11163
|
-
const
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11655
|
+
const missingNames = missingVars.map((v) => v.name);
|
|
11656
|
+
const formatIssues = invalidFormatVars.filter((f) => missingNames.includes(f.name));
|
|
11657
|
+
let message;
|
|
11658
|
+
let hint;
|
|
11659
|
+
if (formatIssues.length > 0) {
|
|
11660
|
+
const details = formatIssues.map((f) => ` - ${f.name}: ${f.reason}`).join("\n");
|
|
11661
|
+
message = `Invalid format for file variables:
|
|
11662
|
+
${details}`;
|
|
11663
|
+
hint = `For file variables, use format: '{"varName": "df-fileId"}' or '{"varName": [{"fileId": "df-xxx"}]}'`;
|
|
11664
|
+
} else {
|
|
11665
|
+
message = `Missing required file variables: ${missingNames.join(", ")}`;
|
|
11666
|
+
hint = "Provide files via --input or run interactively without --no-prompt";
|
|
11667
|
+
}
|
|
11668
|
+
throw new CLIError(ErrorCodes.INVALID_INPUT, message, void 0, hint, {
|
|
11669
|
+
field: "--input",
|
|
11670
|
+
format: "json-object",
|
|
11671
|
+
example: '{"fileVar": "df-fileId"}'
|
|
11672
|
+
});
|
|
11170
11673
|
}
|
|
11171
11674
|
console.log("");
|
|
11172
11675
|
console.log("This workflow requires file inputs:");
|
|
@@ -11180,7 +11683,7 @@ async function collectFileVariables(workflowId, existingInput, noPrompt) {
|
|
|
11180
11683
|
if (!filePath) {
|
|
11181
11684
|
continue;
|
|
11182
11685
|
}
|
|
11183
|
-
const filename =
|
|
11686
|
+
const filename = path10.basename(filePath);
|
|
11184
11687
|
process.stdout.write(` Uploading ${filename}...`);
|
|
11185
11688
|
try {
|
|
11186
11689
|
const uploadResult = await apiUploadDriveFile(filePath, workflowId);
|
|
@@ -11216,7 +11719,59 @@ async function collectFileVariables(workflowId, existingInput, noPrompt) {
|
|
|
11216
11719
|
console.log("");
|
|
11217
11720
|
return uploadedVars;
|
|
11218
11721
|
}
|
|
11722
|
+
function convertKeyValueToVariables(obj, workflow) {
|
|
11723
|
+
const variables = [];
|
|
11724
|
+
for (const [name, rawValue] of Object.entries(obj)) {
|
|
11725
|
+
const varDef = workflow?.variables?.find((v) => v.name === name || v.variableId === name);
|
|
11726
|
+
const isResourceVar = varDef?.variableType === "resource";
|
|
11727
|
+
const looksLikeFileId = typeof rawValue === "string" && rawValue.startsWith("df-");
|
|
11728
|
+
const looksLikeFileArray = Array.isArray(rawValue) && rawValue.length > 0 && typeof rawValue[0] === "object" && rawValue[0] !== null && ("fileId" in rawValue[0] || "type" in rawValue[0]);
|
|
11729
|
+
if (isResourceVar || looksLikeFileId || looksLikeFileArray) {
|
|
11730
|
+
let fileValues = [];
|
|
11731
|
+
if (typeof rawValue === "string") {
|
|
11732
|
+
fileValues = [
|
|
11733
|
+
{
|
|
11734
|
+
type: "resource",
|
|
11735
|
+
resource: { fileId: rawValue }
|
|
11736
|
+
}
|
|
11737
|
+
];
|
|
11738
|
+
} else if (Array.isArray(rawValue)) {
|
|
11739
|
+
fileValues = rawValue.map((item) => ({
|
|
11740
|
+
type: "resource",
|
|
11741
|
+
resource: { fileId: item.fileId || item.resource?.fileId || "" }
|
|
11742
|
+
}));
|
|
11743
|
+
}
|
|
11744
|
+
variables.push({
|
|
11745
|
+
variableId: varDef?.variableId,
|
|
11746
|
+
name,
|
|
11747
|
+
variableType: "resource",
|
|
11748
|
+
value: fileValues,
|
|
11749
|
+
required: varDef?.required
|
|
11750
|
+
});
|
|
11751
|
+
} else {
|
|
11752
|
+
let value = [];
|
|
11753
|
+
if (typeof rawValue === "string") {
|
|
11754
|
+
value = [{ type: "text", text: rawValue }];
|
|
11755
|
+
} else if (Array.isArray(rawValue)) {
|
|
11756
|
+
value = rawValue;
|
|
11757
|
+
}
|
|
11758
|
+
variables.push({
|
|
11759
|
+
variableId: varDef?.variableId,
|
|
11760
|
+
name,
|
|
11761
|
+
variableType: "string",
|
|
11762
|
+
value,
|
|
11763
|
+
required: varDef?.required
|
|
11764
|
+
});
|
|
11765
|
+
}
|
|
11766
|
+
}
|
|
11767
|
+
return variables;
|
|
11768
|
+
}
|
|
11219
11769
|
async function runWorkflow(workflowId, options) {
|
|
11770
|
+
let workflow;
|
|
11771
|
+
try {
|
|
11772
|
+
workflow = await apiGetWorkflow(workflowId);
|
|
11773
|
+
} catch {
|
|
11774
|
+
}
|
|
11220
11775
|
let inputVars = [];
|
|
11221
11776
|
try {
|
|
11222
11777
|
const parsed = JSON.parse(options?.input ?? "{}");
|
|
@@ -11224,13 +11779,40 @@ async function runWorkflow(workflowId, options) {
|
|
|
11224
11779
|
inputVars = parsed;
|
|
11225
11780
|
} else if (parsed.variables && Array.isArray(parsed.variables)) {
|
|
11226
11781
|
inputVars = parsed.variables;
|
|
11782
|
+
} else if (typeof parsed === "object" && parsed !== null && Object.keys(parsed).length > 0) {
|
|
11783
|
+
inputVars = convertKeyValueToVariables(parsed, workflow);
|
|
11227
11784
|
}
|
|
11228
11785
|
} catch {
|
|
11229
11786
|
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --input", {
|
|
11230
|
-
hint:
|
|
11787
|
+
hint: `Ensure the input is valid JSON. Supported formats:
|
|
11788
|
+
- Simple: '{"varName": "value", "fileVar": "df-xxx"}'
|
|
11789
|
+
- Array: '[{"name": "varName", "value": [...]}]'`,
|
|
11790
|
+
suggestedFix: {
|
|
11791
|
+
field: "--input",
|
|
11792
|
+
format: "json-object | json-array",
|
|
11793
|
+
example: '{"varName": "value", "fileVar": "df-xxx"}'
|
|
11794
|
+
}
|
|
11231
11795
|
});
|
|
11232
11796
|
return;
|
|
11233
11797
|
}
|
|
11798
|
+
if (options?.noPrompt && workflow?.variables) {
|
|
11799
|
+
const inputObject = variablesToObject(inputVars);
|
|
11800
|
+
const checkResult = checkRequiredVariables(workflow.variables, inputObject);
|
|
11801
|
+
if (!checkResult.valid) {
|
|
11802
|
+
const errorPayload = buildMissingVariablesError(
|
|
11803
|
+
"workflow",
|
|
11804
|
+
workflowId,
|
|
11805
|
+
workflow.name,
|
|
11806
|
+
checkResult
|
|
11807
|
+
);
|
|
11808
|
+
fail(ErrorCodes.MISSING_VARIABLES, errorPayload.message, {
|
|
11809
|
+
details: errorPayload.details,
|
|
11810
|
+
hint: errorPayload.hint,
|
|
11811
|
+
suggestedFix: errorPayload.suggestedFix,
|
|
11812
|
+
recoverable: errorPayload.recoverable
|
|
11813
|
+
});
|
|
11814
|
+
}
|
|
11815
|
+
}
|
|
11234
11816
|
const uploadedVars = await collectFileVariables(
|
|
11235
11817
|
workflowId,
|
|
11236
11818
|
inputVars,
|
|
@@ -11322,7 +11904,11 @@ var workflowRunCommand = new Command("run").description("Start a workflow execut
|
|
|
11322
11904
|
await runWorkflow(workflowId, options);
|
|
11323
11905
|
} catch (error) {
|
|
11324
11906
|
if (error instanceof CLIError) {
|
|
11325
|
-
fail(error.code, error.message, {
|
|
11907
|
+
fail(error.code, error.message, {
|
|
11908
|
+
details: error.details,
|
|
11909
|
+
hint: error.hint,
|
|
11910
|
+
suggestedFix: error.suggestedFix
|
|
11911
|
+
});
|
|
11326
11912
|
}
|
|
11327
11913
|
fail(
|
|
11328
11914
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11365,7 +11951,11 @@ var workflowRunsCommand = new Command("runs").description("List workflow executi
|
|
|
11365
11951
|
});
|
|
11366
11952
|
} catch (error) {
|
|
11367
11953
|
if (error instanceof CLIError) {
|
|
11368
|
-
fail(error.code, error.message, {
|
|
11954
|
+
fail(error.code, error.message, {
|
|
11955
|
+
details: error.details,
|
|
11956
|
+
hint: error.hint,
|
|
11957
|
+
suggestedFix: error.suggestedFix
|
|
11958
|
+
});
|
|
11369
11959
|
}
|
|
11370
11960
|
fail(
|
|
11371
11961
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11387,7 +11977,11 @@ var workflowAbortCommand = new Command("abort").description("Abort a running wor
|
|
|
11387
11977
|
});
|
|
11388
11978
|
} catch (error) {
|
|
11389
11979
|
if (error instanceof CLIError) {
|
|
11390
|
-
fail(error.code, error.message, {
|
|
11980
|
+
fail(error.code, error.message, {
|
|
11981
|
+
details: error.details,
|
|
11982
|
+
hint: error.hint,
|
|
11983
|
+
suggestedFix: error.suggestedFix
|
|
11984
|
+
});
|
|
11391
11985
|
}
|
|
11392
11986
|
fail(
|
|
11393
11987
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11471,7 +12065,7 @@ var workflowStatusCommand = new Command("status").description("Get detailed work
|
|
|
11471
12065
|
});
|
|
11472
12066
|
prevStatus = status;
|
|
11473
12067
|
while (status.status === "init" || status.status === "executing") {
|
|
11474
|
-
await new Promise((
|
|
12068
|
+
await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
|
|
11475
12069
|
status = await fetchStatus();
|
|
11476
12070
|
if (options.full || hasStatusChanged(prevStatus, status)) {
|
|
11477
12071
|
if (options.full) {
|
|
@@ -11507,7 +12101,11 @@ var workflowStatusCommand = new Command("status").description("Get detailed work
|
|
|
11507
12101
|
}
|
|
11508
12102
|
} catch (error) {
|
|
11509
12103
|
if (error instanceof CLIError) {
|
|
11510
|
-
fail(error.code, error.message, {
|
|
12104
|
+
fail(error.code, error.message, {
|
|
12105
|
+
details: error.details,
|
|
12106
|
+
hint: error.hint,
|
|
12107
|
+
suggestedFix: error.suggestedFix
|
|
12108
|
+
});
|
|
11511
12109
|
}
|
|
11512
12110
|
fail(
|
|
11513
12111
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11580,7 +12178,11 @@ var workflowDetailCommand = new Command("detail").description("Get detailed work
|
|
|
11580
12178
|
});
|
|
11581
12179
|
} catch (error) {
|
|
11582
12180
|
if (error instanceof CLIError) {
|
|
11583
|
-
fail(error.code, error.message, {
|
|
12181
|
+
fail(error.code, error.message, {
|
|
12182
|
+
details: error.details,
|
|
12183
|
+
hint: error.hint,
|
|
12184
|
+
suggestedFix: error.suggestedFix
|
|
12185
|
+
});
|
|
11584
12186
|
}
|
|
11585
12187
|
fail(
|
|
11586
12188
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11632,7 +12234,11 @@ var workflowToolcallsCommand = new Command("toolcalls").description("Get all too
|
|
|
11632
12234
|
});
|
|
11633
12235
|
} catch (error) {
|
|
11634
12236
|
if (error instanceof CLIError) {
|
|
11635
|
-
fail(error.code, error.message, {
|
|
12237
|
+
fail(error.code, error.message, {
|
|
12238
|
+
details: error.details,
|
|
12239
|
+
hint: error.hint,
|
|
12240
|
+
suggestedFix: error.suggestedFix
|
|
12241
|
+
});
|
|
11636
12242
|
}
|
|
11637
12243
|
fail(
|
|
11638
12244
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11664,7 +12270,11 @@ var workflowToolsetKeysCommand = new Command("toolset-keys").description("List a
|
|
|
11664
12270
|
});
|
|
11665
12271
|
} catch (error) {
|
|
11666
12272
|
if (error instanceof CLIError) {
|
|
11667
|
-
fail(error.code, error.message, {
|
|
12273
|
+
fail(error.code, error.message, {
|
|
12274
|
+
details: error.details,
|
|
12275
|
+
hint: error.hint,
|
|
12276
|
+
suggestedFix: error.suggestedFix
|
|
12277
|
+
});
|
|
11668
12278
|
}
|
|
11669
12279
|
fail(
|
|
11670
12280
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11704,7 +12314,11 @@ var workflowLayoutCommand = new Command("layout").description("Auto-layout workf
|
|
|
11704
12314
|
});
|
|
11705
12315
|
} catch (error) {
|
|
11706
12316
|
if (error instanceof CLIError) {
|
|
11707
|
-
fail(error.code, error.message, {
|
|
12317
|
+
fail(error.code, error.message, {
|
|
12318
|
+
details: error.details,
|
|
12319
|
+
hint: error.hint,
|
|
12320
|
+
suggestedFix: error.suggestedFix
|
|
12321
|
+
});
|
|
11708
12322
|
}
|
|
11709
12323
|
fail(
|
|
11710
12324
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11751,7 +12365,11 @@ var workflowNodesCommand = new Command("nodes").description("List all nodes in a
|
|
|
11751
12365
|
ok("workflow.nodes", output3);
|
|
11752
12366
|
} catch (error) {
|
|
11753
12367
|
if (error instanceof CLIError) {
|
|
11754
|
-
fail(error.code, error.message, {
|
|
12368
|
+
fail(error.code, error.message, {
|
|
12369
|
+
details: error.details,
|
|
12370
|
+
hint: error.hint,
|
|
12371
|
+
suggestedFix: error.suggestedFix
|
|
12372
|
+
});
|
|
11755
12373
|
}
|
|
11756
12374
|
fail(
|
|
11757
12375
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11812,7 +12430,11 @@ var workflowNodeGetCommand = new Command("node").description("Get single node in
|
|
|
11812
12430
|
ok("workflow.node", output3);
|
|
11813
12431
|
} catch (error) {
|
|
11814
12432
|
if (error instanceof CLIError) {
|
|
11815
|
-
fail(error.code, error.message, {
|
|
12433
|
+
fail(error.code, error.message, {
|
|
12434
|
+
details: error.details,
|
|
12435
|
+
hint: error.hint,
|
|
12436
|
+
suggestedFix: error.suggestedFix
|
|
12437
|
+
});
|
|
11816
12438
|
}
|
|
11817
12439
|
fail(
|
|
11818
12440
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11821,6 +12443,289 @@ var workflowNodeGetCommand = new Command("node").description("Get single node in
|
|
|
11821
12443
|
}
|
|
11822
12444
|
});
|
|
11823
12445
|
|
|
12446
|
+
// src/commands/workflow/node-add.ts
|
|
12447
|
+
init_cjs_shims();
|
|
12448
|
+
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) => {
|
|
12449
|
+
if (!workflowId.startsWith("c-")) {
|
|
12450
|
+
fail(ErrorCodes.INVALID_INPUT, `Invalid workflow ID: ${workflowId}`, {
|
|
12451
|
+
hint: 'Workflow ID should start with "c-"',
|
|
12452
|
+
suggestedFix: {
|
|
12453
|
+
field: "<workflowId>",
|
|
12454
|
+
format: "c-<id>",
|
|
12455
|
+
example: "c-123456"
|
|
12456
|
+
}
|
|
12457
|
+
});
|
|
12458
|
+
return;
|
|
12459
|
+
}
|
|
12460
|
+
const validTypes = ["skillResponse", "start", "document", "resource", "memo"];
|
|
12461
|
+
if (!validTypes.includes(options.type)) {
|
|
12462
|
+
fail(ErrorCodes.INVALID_INPUT, `Invalid node type: ${options.type}`, {
|
|
12463
|
+
hint: `Valid types: ${validTypes.join(", ")}`,
|
|
12464
|
+
suggestedFix: {
|
|
12465
|
+
field: "--type",
|
|
12466
|
+
format: "string",
|
|
12467
|
+
example: "skillResponse"
|
|
12468
|
+
}
|
|
12469
|
+
});
|
|
12470
|
+
return;
|
|
12471
|
+
}
|
|
12472
|
+
try {
|
|
12473
|
+
const nodeId = options.id || `node-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
12474
|
+
let position = { x: 0, y: 0 };
|
|
12475
|
+
if (options.position) {
|
|
12476
|
+
const parts = options.position.split(",").map((p) => Number.parseFloat(p.trim()));
|
|
12477
|
+
if (parts.length === 2 && !Number.isNaN(parts[0]) && !Number.isNaN(parts[1])) {
|
|
12478
|
+
position = { x: parts[0], y: parts[1] };
|
|
12479
|
+
}
|
|
12480
|
+
}
|
|
12481
|
+
const metadata = {};
|
|
12482
|
+
if (options.query) {
|
|
12483
|
+
metadata.query = options.query;
|
|
12484
|
+
}
|
|
12485
|
+
if (options.title) {
|
|
12486
|
+
metadata.title = options.title;
|
|
12487
|
+
}
|
|
12488
|
+
if (options.toolsetKeys) {
|
|
12489
|
+
metadata.toolsetKeys = options.toolsetKeys.split(",").map((k) => k.trim());
|
|
12490
|
+
}
|
|
12491
|
+
const node = {
|
|
12492
|
+
id: nodeId,
|
|
12493
|
+
type: options.type,
|
|
12494
|
+
position,
|
|
12495
|
+
data: {
|
|
12496
|
+
metadata
|
|
12497
|
+
}
|
|
12498
|
+
};
|
|
12499
|
+
const operations = [
|
|
12500
|
+
{
|
|
12501
|
+
type: "add_node",
|
|
12502
|
+
node
|
|
12503
|
+
}
|
|
12504
|
+
];
|
|
12505
|
+
if (options.connectFrom) {
|
|
12506
|
+
operations.push({
|
|
12507
|
+
type: "add_edge",
|
|
12508
|
+
edge: {
|
|
12509
|
+
id: `edge-${options.connectFrom}-${nodeId}`,
|
|
12510
|
+
source: options.connectFrom,
|
|
12511
|
+
target: nodeId
|
|
12512
|
+
}
|
|
12513
|
+
});
|
|
12514
|
+
}
|
|
12515
|
+
if (options.connectTo) {
|
|
12516
|
+
operations.push({
|
|
12517
|
+
type: "add_edge",
|
|
12518
|
+
edge: {
|
|
12519
|
+
id: `edge-${nodeId}-${options.connectTo}`,
|
|
12520
|
+
source: nodeId,
|
|
12521
|
+
target: options.connectTo
|
|
12522
|
+
}
|
|
12523
|
+
});
|
|
12524
|
+
}
|
|
12525
|
+
const body = { operations };
|
|
12526
|
+
const queryParams = [];
|
|
12527
|
+
if (options.resolveToolsetKeys) queryParams.push("resolveToolsetKeys=true");
|
|
12528
|
+
if (options.autoLayout) queryParams.push("autoLayout=true");
|
|
12529
|
+
const queryString = queryParams.length > 0 ? `?${queryParams.join("&")}` : "";
|
|
12530
|
+
await apiRequest(`/v1/cli/workflow/${workflowId}${queryString}`, {
|
|
12531
|
+
method: "PATCH",
|
|
12532
|
+
body
|
|
12533
|
+
});
|
|
12534
|
+
ok("workflow.node.add", {
|
|
12535
|
+
message: "Node added successfully",
|
|
12536
|
+
workflowId,
|
|
12537
|
+
nodeId,
|
|
12538
|
+
type: options.type,
|
|
12539
|
+
position,
|
|
12540
|
+
...options.query && { query: options.query },
|
|
12541
|
+
...options.toolsetKeys && {
|
|
12542
|
+
toolsetKeys: options.toolsetKeys.split(",").map((k) => k.trim())
|
|
12543
|
+
},
|
|
12544
|
+
...options.connectFrom && { connectedFrom: options.connectFrom },
|
|
12545
|
+
...options.connectTo && { connectedTo: options.connectTo },
|
|
12546
|
+
nextSteps: [
|
|
12547
|
+
`View node: \`refly workflow node ${workflowId} ${nodeId}\``,
|
|
12548
|
+
`List all nodes: \`refly workflow nodes ${workflowId}\``
|
|
12549
|
+
]
|
|
12550
|
+
});
|
|
12551
|
+
} catch (error) {
|
|
12552
|
+
if (error instanceof CLIError) {
|
|
12553
|
+
fail(error.code, error.message, {
|
|
12554
|
+
details: error.details,
|
|
12555
|
+
hint: error.hint,
|
|
12556
|
+
suggestedFix: error.suggestedFix
|
|
12557
|
+
});
|
|
12558
|
+
return;
|
|
12559
|
+
}
|
|
12560
|
+
fail(
|
|
12561
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
12562
|
+
error instanceof Error ? error.message : "Failed to add node"
|
|
12563
|
+
);
|
|
12564
|
+
}
|
|
12565
|
+
});
|
|
12566
|
+
|
|
12567
|
+
// src/commands/workflow/node-update.ts
|
|
12568
|
+
init_cjs_shims();
|
|
12569
|
+
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) => {
|
|
12570
|
+
if (!workflowId.startsWith("c-")) {
|
|
12571
|
+
fail(ErrorCodes.INVALID_INPUT, `Invalid workflow ID: ${workflowId}`, {
|
|
12572
|
+
hint: 'Workflow ID should start with "c-"',
|
|
12573
|
+
suggestedFix: {
|
|
12574
|
+
field: "<workflowId>",
|
|
12575
|
+
format: "c-<id>",
|
|
12576
|
+
example: "c-123456"
|
|
12577
|
+
}
|
|
12578
|
+
});
|
|
12579
|
+
return;
|
|
12580
|
+
}
|
|
12581
|
+
try {
|
|
12582
|
+
let nodeData = {};
|
|
12583
|
+
if (options.data) {
|
|
12584
|
+
try {
|
|
12585
|
+
nodeData = JSON.parse(options.data);
|
|
12586
|
+
} catch {
|
|
12587
|
+
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --data", {
|
|
12588
|
+
hint: `Data format: '{"data": {"metadata": {"query": "...", "toolsetKeys": ["..."]}}}'`,
|
|
12589
|
+
suggestedFix: {
|
|
12590
|
+
field: "--data",
|
|
12591
|
+
format: "json-object",
|
|
12592
|
+
example: '{"data": {"metadata": {"query": "Search for information"}}}'
|
|
12593
|
+
}
|
|
12594
|
+
});
|
|
12595
|
+
return;
|
|
12596
|
+
}
|
|
12597
|
+
}
|
|
12598
|
+
const metadataUpdates = {};
|
|
12599
|
+
if (options.query) {
|
|
12600
|
+
metadataUpdates.query = options.query;
|
|
12601
|
+
}
|
|
12602
|
+
if (options.title) {
|
|
12603
|
+
metadataUpdates.title = options.title;
|
|
12604
|
+
}
|
|
12605
|
+
if (options.toolsetKeys) {
|
|
12606
|
+
const keys = options.toolsetKeys.split(",").map((k) => k.trim());
|
|
12607
|
+
metadataUpdates.toolsetKeys = keys;
|
|
12608
|
+
}
|
|
12609
|
+
if (Object.keys(metadataUpdates).length > 0) {
|
|
12610
|
+
nodeData = {
|
|
12611
|
+
...nodeData,
|
|
12612
|
+
data: {
|
|
12613
|
+
...nodeData.data || {},
|
|
12614
|
+
metadata: {
|
|
12615
|
+
...nodeData.data?.metadata || {},
|
|
12616
|
+
...metadataUpdates
|
|
12617
|
+
}
|
|
12618
|
+
}
|
|
12619
|
+
};
|
|
12620
|
+
}
|
|
12621
|
+
if (Object.keys(nodeData).length === 0) {
|
|
12622
|
+
fail(ErrorCodes.INVALID_INPUT, "No update provided", {
|
|
12623
|
+
hint: "Use --query, --title, --toolset-keys, or --data to specify what to update",
|
|
12624
|
+
suggestedFix: {
|
|
12625
|
+
field: "--query",
|
|
12626
|
+
format: "string",
|
|
12627
|
+
example: '--query "Search for the latest news"'
|
|
12628
|
+
}
|
|
12629
|
+
});
|
|
12630
|
+
return;
|
|
12631
|
+
}
|
|
12632
|
+
const body = {
|
|
12633
|
+
operations: [
|
|
12634
|
+
{
|
|
12635
|
+
type: "update_node",
|
|
12636
|
+
nodeId,
|
|
12637
|
+
data: nodeData
|
|
12638
|
+
}
|
|
12639
|
+
]
|
|
12640
|
+
};
|
|
12641
|
+
const queryParams = options.resolveToolsetKeys ? "?resolveToolsetKeys=true" : "";
|
|
12642
|
+
await apiRequest(`/v1/cli/workflow/${workflowId}${queryParams}`, {
|
|
12643
|
+
method: "PATCH",
|
|
12644
|
+
body
|
|
12645
|
+
});
|
|
12646
|
+
ok("workflow.node.update", {
|
|
12647
|
+
message: "Node updated successfully",
|
|
12648
|
+
workflowId,
|
|
12649
|
+
nodeId,
|
|
12650
|
+
updates: {
|
|
12651
|
+
...options.query && { query: options.query },
|
|
12652
|
+
...options.title && { title: options.title },
|
|
12653
|
+
...options.toolsetKeys && {
|
|
12654
|
+
toolsetKeys: options.toolsetKeys.split(",").map((k) => k.trim())
|
|
12655
|
+
},
|
|
12656
|
+
...options.data && { data: "custom data applied" }
|
|
12657
|
+
},
|
|
12658
|
+
nextSteps: [
|
|
12659
|
+
`View updated node: \`refly workflow node ${workflowId} ${nodeId}\``,
|
|
12660
|
+
`List all nodes: \`refly workflow nodes ${workflowId}\``
|
|
12661
|
+
]
|
|
12662
|
+
});
|
|
12663
|
+
} catch (error) {
|
|
12664
|
+
if (error instanceof CLIError) {
|
|
12665
|
+
fail(error.code, error.message, {
|
|
12666
|
+
details: error.details,
|
|
12667
|
+
hint: error.hint,
|
|
12668
|
+
suggestedFix: error.suggestedFix
|
|
12669
|
+
});
|
|
12670
|
+
return;
|
|
12671
|
+
}
|
|
12672
|
+
fail(
|
|
12673
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
12674
|
+
error instanceof Error ? error.message : "Failed to update node"
|
|
12675
|
+
);
|
|
12676
|
+
}
|
|
12677
|
+
});
|
|
12678
|
+
|
|
12679
|
+
// src/commands/workflow/node-delete.ts
|
|
12680
|
+
init_cjs_shims();
|
|
12681
|
+
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) => {
|
|
12682
|
+
if (!workflowId.startsWith("c-")) {
|
|
12683
|
+
fail(ErrorCodes.INVALID_INPUT, `Invalid workflow ID: ${workflowId}`, {
|
|
12684
|
+
hint: 'Workflow ID should start with "c-"',
|
|
12685
|
+
suggestedFix: {
|
|
12686
|
+
field: "<workflowId>",
|
|
12687
|
+
format: "c-<id>",
|
|
12688
|
+
example: "c-123456"
|
|
12689
|
+
}
|
|
12690
|
+
});
|
|
12691
|
+
return;
|
|
12692
|
+
}
|
|
12693
|
+
try {
|
|
12694
|
+
const body = {
|
|
12695
|
+
operations: [
|
|
12696
|
+
{
|
|
12697
|
+
type: "remove_node",
|
|
12698
|
+
nodeId
|
|
12699
|
+
}
|
|
12700
|
+
]
|
|
12701
|
+
};
|
|
12702
|
+
await apiRequest(`/v1/cli/workflow/${workflowId}`, {
|
|
12703
|
+
method: "PATCH",
|
|
12704
|
+
body
|
|
12705
|
+
});
|
|
12706
|
+
ok("workflow.node.delete", {
|
|
12707
|
+
message: "Node deleted successfully",
|
|
12708
|
+
workflowId,
|
|
12709
|
+
nodeId,
|
|
12710
|
+
note: "Connected edges were also removed",
|
|
12711
|
+
nextSteps: [`List remaining nodes: \`refly workflow nodes ${workflowId}\``]
|
|
12712
|
+
});
|
|
12713
|
+
} catch (error) {
|
|
12714
|
+
if (error instanceof CLIError) {
|
|
12715
|
+
fail(error.code, error.message, {
|
|
12716
|
+
details: error.details,
|
|
12717
|
+
hint: error.hint,
|
|
12718
|
+
suggestedFix: error.suggestedFix
|
|
12719
|
+
});
|
|
12720
|
+
return;
|
|
12721
|
+
}
|
|
12722
|
+
fail(
|
|
12723
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
12724
|
+
error instanceof Error ? error.message : "Failed to delete node"
|
|
12725
|
+
);
|
|
12726
|
+
}
|
|
12727
|
+
});
|
|
12728
|
+
|
|
11824
12729
|
// src/commands/workflow/node-output.ts
|
|
11825
12730
|
init_cjs_shims();
|
|
11826
12731
|
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) => {
|
|
@@ -11856,7 +12761,11 @@ var workflowNodeOutputCommand = new Command("node-output").description("Get node
|
|
|
11856
12761
|
});
|
|
11857
12762
|
} catch (error) {
|
|
11858
12763
|
if (error instanceof CLIError) {
|
|
11859
|
-
fail(error.code, error.message, {
|
|
12764
|
+
fail(error.code, error.message, {
|
|
12765
|
+
details: error.details,
|
|
12766
|
+
hint: error.hint,
|
|
12767
|
+
suggestedFix: error.suggestedFix
|
|
12768
|
+
});
|
|
11860
12769
|
}
|
|
11861
12770
|
fail(
|
|
11862
12771
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11868,91 +12777,61 @@ var workflowNodeOutputCommand = new Command("node-output").description("Get node
|
|
|
11868
12777
|
}
|
|
11869
12778
|
});
|
|
11870
12779
|
|
|
11871
|
-
// src/commands/workflow/
|
|
12780
|
+
// src/commands/workflow/edit.ts
|
|
11872
12781
|
init_cjs_shims();
|
|
11873
|
-
var
|
|
11874
|
-
var workflowPatchCommand = new Command("patch").description("Apply semantic patch operations to a workflow plan").argument("<planId>", "Workflow Plan ID").option("--ops <json>", "Operations array as JSON").option("--ops-file <path>", "Read operations from file").option("--update-title <title>", "Shortcut: update workflow title").option("--delete-task <taskId>", "Shortcut: delete a task").option("--delete-variable <variableId>", "Shortcut: delete a variable").action(async (planId, options) => {
|
|
12782
|
+
var workflowEditCommand = new Command("edit").description("Edit a workflow using natural language").argument("<id>", "Canvas ID (c-xxx)").option("--query <text>", "Edit instruction in natural language").option("--session-id <id>", "Session ID (cs-xxx) for context continuity").option("--timeout <ms>", "Timeout for AI processing", "60000").action(async (id, options) => {
|
|
11875
12783
|
try {
|
|
11876
|
-
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
const fileContent = fs13.readFileSync(filePath, "utf-8");
|
|
11884
|
-
const fileOps = JSON.parse(fileContent);
|
|
11885
|
-
if (Array.isArray(fileOps)) {
|
|
11886
|
-
operations.push(...fileOps);
|
|
11887
|
-
} else {
|
|
11888
|
-
fail(ErrorCodes.INVALID_INPUT, "Operations file must contain a JSON array");
|
|
11889
|
-
}
|
|
11890
|
-
} catch (error) {
|
|
11891
|
-
if (error instanceof CLIError) throw error;
|
|
11892
|
-
fail(
|
|
11893
|
-
ErrorCodes.INVALID_INPUT,
|
|
11894
|
-
`Failed to parse operations file: ${error.message}`
|
|
11895
|
-
);
|
|
11896
|
-
}
|
|
11897
|
-
}
|
|
11898
|
-
if (options.ops) {
|
|
11899
|
-
try {
|
|
11900
|
-
const jsonOps = JSON.parse(options.ops);
|
|
11901
|
-
if (Array.isArray(jsonOps)) {
|
|
11902
|
-
operations.push(...jsonOps);
|
|
11903
|
-
} else {
|
|
11904
|
-
fail(ErrorCodes.INVALID_INPUT, "--ops must be a JSON array");
|
|
12784
|
+
if (!options.query) {
|
|
12785
|
+
fail(ErrorCodes.INVALID_INPUT, "--query is required", {
|
|
12786
|
+
hint: "Provide a natural language description of the edit you want to make",
|
|
12787
|
+
suggestedFix: {
|
|
12788
|
+
field: "--query",
|
|
12789
|
+
format: "string",
|
|
12790
|
+
example: 'refly workflow edit c-xxx --query "\u6DFB\u52A0\u4E00\u4E2A\u7528 nano banana \u751F\u6210\u56FE\u7247\u7684\u4EFB\u52A1"'
|
|
11905
12791
|
}
|
|
11906
|
-
} catch (error) {
|
|
11907
|
-
fail(ErrorCodes.INVALID_INPUT, `Invalid JSON in --ops: ${error.message}`, {
|
|
11908
|
-
hint: "Ensure the operations are a valid JSON array"
|
|
11909
|
-
});
|
|
11910
|
-
}
|
|
11911
|
-
}
|
|
11912
|
-
if (options.updateTitle) {
|
|
11913
|
-
operations.push({
|
|
11914
|
-
op: "updateTitle",
|
|
11915
|
-
title: options.updateTitle
|
|
11916
|
-
});
|
|
11917
|
-
}
|
|
11918
|
-
if (options.deleteTask) {
|
|
11919
|
-
operations.push({
|
|
11920
|
-
op: "deleteTask",
|
|
11921
|
-
taskId: options.deleteTask
|
|
11922
12792
|
});
|
|
11923
12793
|
}
|
|
11924
|
-
if (
|
|
11925
|
-
|
|
11926
|
-
|
|
11927
|
-
|
|
11928
|
-
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
|
|
11932
|
-
hint: "Use --ops, --ops-file, or shortcut options (--update-title, --delete-task, --delete-variable)"
|
|
12794
|
+
if (!id.startsWith("c-")) {
|
|
12795
|
+
fail(ErrorCodes.INVALID_INPUT, "Only Canvas ID (c-xxx) is supported", {
|
|
12796
|
+
hint: 'Use the Canvas ID format starting with "c-"',
|
|
12797
|
+
suggestedFix: {
|
|
12798
|
+
field: "id",
|
|
12799
|
+
format: "canvas-id",
|
|
12800
|
+
example: "c-abc123"
|
|
12801
|
+
}
|
|
11933
12802
|
});
|
|
11934
12803
|
}
|
|
11935
|
-
const
|
|
11936
|
-
|
|
11937
|
-
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
|
|
11941
|
-
|
|
11942
|
-
|
|
11943
|
-
|
|
11944
|
-
|
|
11945
|
-
|
|
11946
|
-
|
|
12804
|
+
const timeout = Number.parseInt(options.timeout);
|
|
12805
|
+
const response = await apiRequest(
|
|
12806
|
+
"/v1/cli/workflow/edit",
|
|
12807
|
+
{
|
|
12808
|
+
method: "POST",
|
|
12809
|
+
body: {
|
|
12810
|
+
canvasId: id,
|
|
12811
|
+
query: options.query,
|
|
12812
|
+
sessionId: options.sessionId,
|
|
12813
|
+
timeout
|
|
12814
|
+
},
|
|
12815
|
+
timeout: timeout + 5e3
|
|
12816
|
+
// Add buffer for network
|
|
12817
|
+
}
|
|
12818
|
+
);
|
|
12819
|
+
const result = response.data ?? response;
|
|
12820
|
+
ok("workflow.edit", {
|
|
12821
|
+
canvasId: result.canvasId,
|
|
12822
|
+
planId: result.planId,
|
|
12823
|
+
version: result.version,
|
|
12824
|
+
toolUsed: result.toolUsed,
|
|
12825
|
+
sessionId: result.sessionId,
|
|
11947
12826
|
plan: {
|
|
11948
|
-
title: plan.title,
|
|
11949
|
-
taskCount: plan.tasks?.length ?? 0,
|
|
11950
|
-
variableCount: plan.variables?.length ?? 0,
|
|
11951
|
-
tasks: plan.tasks?.map((t) => ({
|
|
12827
|
+
title: result.plan.title,
|
|
12828
|
+
taskCount: result.plan.tasks?.length ?? 0,
|
|
12829
|
+
variableCount: result.plan.variables?.length ?? 0,
|
|
12830
|
+
tasks: result.plan.tasks?.map((t) => ({
|
|
11952
12831
|
id: t.id,
|
|
11953
12832
|
title: t.title
|
|
11954
12833
|
})),
|
|
11955
|
-
variables: plan.variables?.map((v) => ({
|
|
12834
|
+
variables: result.plan.variables?.map((v) => ({
|
|
11956
12835
|
variableId: v.variableId,
|
|
11957
12836
|
name: v.name
|
|
11958
12837
|
}))
|
|
@@ -11960,18 +12839,369 @@ var workflowPatchCommand = new Command("patch").description("Apply semantic patc
|
|
|
11960
12839
|
});
|
|
11961
12840
|
} catch (error) {
|
|
11962
12841
|
if (error instanceof CLIError) {
|
|
11963
|
-
fail(error.code, error.message, {
|
|
11964
|
-
|
|
11965
|
-
|
|
12842
|
+
fail(error.code, error.message, {
|
|
12843
|
+
details: error.details,
|
|
12844
|
+
hint: error.hint,
|
|
12845
|
+
suggestedFix: error.suggestedFix
|
|
12846
|
+
});
|
|
12847
|
+
}
|
|
12848
|
+
fail(
|
|
12849
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
12850
|
+
error instanceof Error ? error.message : "Failed to edit workflow"
|
|
12851
|
+
);
|
|
12852
|
+
}
|
|
12853
|
+
});
|
|
12854
|
+
|
|
12855
|
+
// src/commands/workflow/variables.ts
|
|
12856
|
+
init_cjs_shims();
|
|
12857
|
+
function getFileTypeCategory(mimeType) {
|
|
12858
|
+
if (mimeType.startsWith("image/")) return "image";
|
|
12859
|
+
if (mimeType.startsWith("video/")) return "video";
|
|
12860
|
+
if (mimeType.startsWith("audio/")) return "audio";
|
|
12861
|
+
if (mimeType === "application/pdf") return "document";
|
|
12862
|
+
if (mimeType.includes("word") || mimeType.includes("document")) return "document";
|
|
12863
|
+
if (mimeType.includes("sheet") || mimeType.includes("excel")) return "document";
|
|
12864
|
+
if (mimeType.includes("presentation") || mimeType.includes("powerpoint")) return "document";
|
|
12865
|
+
if (mimeType.startsWith("text/")) return "document";
|
|
12866
|
+
return "document";
|
|
12867
|
+
}
|
|
12868
|
+
async function getFileMetadata(fileId) {
|
|
12869
|
+
try {
|
|
12870
|
+
return await apiRequest(`/v1/cli/drive/files/${fileId}?includeContent=false`);
|
|
12871
|
+
} catch {
|
|
12872
|
+
return null;
|
|
12873
|
+
}
|
|
12874
|
+
}
|
|
12875
|
+
function parseVarArgs(varArgs) {
|
|
12876
|
+
const result = {};
|
|
12877
|
+
for (const arg of varArgs) {
|
|
12878
|
+
const eqIndex = arg.indexOf("=");
|
|
12879
|
+
if (eqIndex === -1) {
|
|
12880
|
+
throw new CLIError(
|
|
12881
|
+
ErrorCodes.INVALID_INPUT,
|
|
12882
|
+
`Invalid --var format: "${arg}"`,
|
|
12883
|
+
void 0,
|
|
12884
|
+
"Use format: --var key=value"
|
|
12885
|
+
);
|
|
12886
|
+
}
|
|
12887
|
+
const key = arg.slice(0, eqIndex);
|
|
12888
|
+
const value = arg.slice(eqIndex + 1);
|
|
12889
|
+
result[key] = value;
|
|
12890
|
+
}
|
|
12891
|
+
return result;
|
|
12892
|
+
}
|
|
12893
|
+
function formatVariable(v) {
|
|
12894
|
+
const hasValue = Array.isArray(v.value) && v.value.length > 0;
|
|
12895
|
+
return {
|
|
12896
|
+
name: v.name,
|
|
12897
|
+
variableId: v.variableId,
|
|
12898
|
+
type: v.variableType || "string",
|
|
12899
|
+
required: v.required ?? false,
|
|
12900
|
+
hasValue,
|
|
12901
|
+
value: hasValue ? v.value : void 0,
|
|
12902
|
+
description: v.description
|
|
12903
|
+
};
|
|
12904
|
+
}
|
|
12905
|
+
var variablesListCommand = new Command("list").description("List workflow variables with current values").argument("<workflowId>", "Workflow ID (canvas ID)").action(async (workflowId) => {
|
|
12906
|
+
try {
|
|
12907
|
+
const variables = await apiGetWorkflowVariables(workflowId);
|
|
12908
|
+
const formatted = variables.map(formatVariable);
|
|
12909
|
+
ok("workflow.variables.list", {
|
|
12910
|
+
workflowId,
|
|
12911
|
+
variables: formatted,
|
|
12912
|
+
count: variables.length
|
|
12913
|
+
});
|
|
12914
|
+
} catch (error) {
|
|
12915
|
+
if (error instanceof CLIError) {
|
|
12916
|
+
fail(error.code, error.message, {
|
|
12917
|
+
details: error.details,
|
|
12918
|
+
hint: error.hint,
|
|
12919
|
+
suggestedFix: error.suggestedFix
|
|
12920
|
+
});
|
|
12921
|
+
}
|
|
12922
|
+
fail(
|
|
12923
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
12924
|
+
error instanceof Error ? error.message : "Failed to list variables"
|
|
12925
|
+
);
|
|
12926
|
+
}
|
|
12927
|
+
});
|
|
12928
|
+
var variablesGetCommand = new Command("get").description("Get a single workflow variable by name").argument("<workflowId>", "Workflow ID (canvas ID)").argument("<varName>", "Variable name to get").action(async (workflowId, varName) => {
|
|
12929
|
+
try {
|
|
12930
|
+
const variables = await apiGetWorkflowVariables(workflowId);
|
|
12931
|
+
const variable = variables.find((v) => v.name === varName || v.variableId === varName);
|
|
12932
|
+
if (!variable) {
|
|
12933
|
+
const availableNames = variables.map((v) => v.name).join(", ");
|
|
12934
|
+
fail(ErrorCodes.NOT_FOUND, `Variable not found: ${varName}`, {
|
|
12935
|
+
hint: `Available variables: ${availableNames}`
|
|
12936
|
+
});
|
|
12937
|
+
return;
|
|
12938
|
+
}
|
|
12939
|
+
ok("workflow.variables.get", {
|
|
12940
|
+
workflowId,
|
|
12941
|
+
variable: formatVariable(variable)
|
|
12942
|
+
});
|
|
12943
|
+
} catch (error) {
|
|
12944
|
+
if (error instanceof CLIError) {
|
|
12945
|
+
fail(error.code, error.message, {
|
|
12946
|
+
details: error.details,
|
|
12947
|
+
hint: error.hint,
|
|
12948
|
+
suggestedFix: error.suggestedFix
|
|
12949
|
+
});
|
|
12950
|
+
}
|
|
12951
|
+
fail(
|
|
12952
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
12953
|
+
error instanceof Error ? error.message : "Failed to get variable"
|
|
12954
|
+
);
|
|
12955
|
+
}
|
|
12956
|
+
});
|
|
12957
|
+
var variablesSetCommand = new Command("set").description("Set variable values for a workflow").argument("<workflowId>", "Workflow ID (canvas ID)").option("--var <key=value...>", "Variable value in key=value format (can be repeated)").option("--input <json>", "Variable values as JSON object").option("--clear <name>", "Clear value for a specific variable").action(
|
|
12958
|
+
async (workflowId, options) => {
|
|
12959
|
+
try {
|
|
12960
|
+
const currentVars = await apiGetWorkflowVariables(workflowId);
|
|
12961
|
+
let newValues = {};
|
|
12962
|
+
if (options.input) {
|
|
12963
|
+
try {
|
|
12964
|
+
const parsed = JSON.parse(options.input);
|
|
12965
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
12966
|
+
fail(ErrorCodes.INVALID_INPUT, "Input must be a JSON object", {
|
|
12967
|
+
hint: `Use format: '{"varName": "value"}'`,
|
|
12968
|
+
suggestedFix: {
|
|
12969
|
+
field: "--input",
|
|
12970
|
+
format: "json-object",
|
|
12971
|
+
example: '{"varName": "value"}'
|
|
12972
|
+
}
|
|
12973
|
+
});
|
|
12974
|
+
}
|
|
12975
|
+
newValues = { ...parsed };
|
|
12976
|
+
} catch {
|
|
12977
|
+
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --input", {
|
|
12978
|
+
hint: "Ensure the input is valid JSON",
|
|
12979
|
+
suggestedFix: {
|
|
12980
|
+
field: "--input",
|
|
12981
|
+
format: "json-object",
|
|
12982
|
+
example: '{"varName": "value"}'
|
|
12983
|
+
}
|
|
12984
|
+
});
|
|
12985
|
+
}
|
|
12986
|
+
}
|
|
12987
|
+
if (options.var && options.var.length > 0) {
|
|
12988
|
+
const varBindings = parseVarArgs(options.var);
|
|
12989
|
+
newValues = { ...newValues, ...varBindings };
|
|
12990
|
+
}
|
|
12991
|
+
if (options.clear) {
|
|
12992
|
+
newValues[options.clear] = null;
|
|
12993
|
+
}
|
|
12994
|
+
if (Object.keys(newValues).length === 0) {
|
|
12995
|
+
fail(ErrorCodes.INVALID_INPUT, "No variables specified", {
|
|
12996
|
+
hint: `Use --var key=value, --input '{"key": "value"}', or --clear <name>`
|
|
12997
|
+
});
|
|
12998
|
+
}
|
|
12999
|
+
const fileIds = Object.values(newValues).filter(
|
|
13000
|
+
(v) => typeof v === "string" && v.startsWith("df-")
|
|
13001
|
+
);
|
|
13002
|
+
const fileMetadataMap = /* @__PURE__ */ new Map();
|
|
13003
|
+
for (const fileId of fileIds) {
|
|
13004
|
+
const metadata = await getFileMetadata(fileId);
|
|
13005
|
+
if (metadata) {
|
|
13006
|
+
fileMetadataMap.set(fileId, metadata);
|
|
13007
|
+
}
|
|
13008
|
+
}
|
|
13009
|
+
const updatedVars = currentVars.map((v) => {
|
|
13010
|
+
const name = v.name;
|
|
13011
|
+
if (name in newValues) {
|
|
13012
|
+
const newValue = newValues[name];
|
|
13013
|
+
if (newValue === null) {
|
|
13014
|
+
return { ...v, value: [] };
|
|
13015
|
+
}
|
|
13016
|
+
if (typeof newValue === "string") {
|
|
13017
|
+
if (newValue.startsWith("df-")) {
|
|
13018
|
+
const metadata = fileMetadataMap.get(newValue);
|
|
13019
|
+
return {
|
|
13020
|
+
...v,
|
|
13021
|
+
value: [
|
|
13022
|
+
{
|
|
13023
|
+
type: "resource",
|
|
13024
|
+
resource: {
|
|
13025
|
+
fileId: newValue,
|
|
13026
|
+
name: metadata?.name || "",
|
|
13027
|
+
fileType: metadata ? getFileTypeCategory(metadata.type) : "document",
|
|
13028
|
+
storageKey: metadata?.storageKey || ""
|
|
13029
|
+
}
|
|
13030
|
+
}
|
|
13031
|
+
]
|
|
13032
|
+
};
|
|
13033
|
+
}
|
|
13034
|
+
return {
|
|
13035
|
+
...v,
|
|
13036
|
+
value: [{ type: "text", text: newValue }]
|
|
13037
|
+
};
|
|
13038
|
+
}
|
|
13039
|
+
if (Array.isArray(newValue)) {
|
|
13040
|
+
return { ...v, value: newValue };
|
|
13041
|
+
}
|
|
13042
|
+
return v;
|
|
13043
|
+
}
|
|
13044
|
+
return v;
|
|
13045
|
+
});
|
|
13046
|
+
const definedNames = new Set(currentVars.map((v) => v.name));
|
|
13047
|
+
const unknownVars = Object.keys(newValues).filter((k) => !definedNames.has(k));
|
|
13048
|
+
if (unknownVars.length > 0) {
|
|
13049
|
+
fail(ErrorCodes.INVALID_INPUT, `Unknown variables: ${unknownVars.join(", ")}`, {
|
|
13050
|
+
hint: `Available variables: ${Array.from(definedNames).join(", ")}`
|
|
13051
|
+
});
|
|
13052
|
+
}
|
|
13053
|
+
const result = await apiUpdateWorkflowVariables(workflowId, updatedVars);
|
|
13054
|
+
ok("workflow.variables.set", {
|
|
13055
|
+
workflowId,
|
|
13056
|
+
updated: Object.keys(newValues),
|
|
13057
|
+
variables: result.map(formatVariable)
|
|
13058
|
+
});
|
|
13059
|
+
} catch (error) {
|
|
13060
|
+
if (error instanceof CLIError) {
|
|
13061
|
+
fail(error.code, error.message, {
|
|
13062
|
+
details: error.details,
|
|
13063
|
+
hint: error.hint,
|
|
13064
|
+
suggestedFix: error.suggestedFix
|
|
13065
|
+
});
|
|
13066
|
+
}
|
|
13067
|
+
fail(
|
|
13068
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
13069
|
+
error instanceof Error ? error.message : "Failed to set variables"
|
|
13070
|
+
);
|
|
13071
|
+
}
|
|
13072
|
+
}
|
|
13073
|
+
);
|
|
13074
|
+
var workflowVariablesCommand = new Command("variables").description("Manage workflow variable values").addCommand(variablesListCommand).addCommand(variablesGetCommand).addCommand(variablesSetCommand);
|
|
13075
|
+
|
|
13076
|
+
// src/commands/workflow/result.ts
|
|
13077
|
+
init_cjs_shims();
|
|
13078
|
+
function formatResult(result, options) {
|
|
13079
|
+
const output3 = {
|
|
13080
|
+
resultId: result.resultId,
|
|
13081
|
+
version: result.version,
|
|
13082
|
+
title: result.title,
|
|
13083
|
+
type: result.type,
|
|
13084
|
+
status: result.status
|
|
13085
|
+
};
|
|
13086
|
+
if (result.workflowExecutionId) {
|
|
13087
|
+
output3.workflowExecutionId = result.workflowExecutionId;
|
|
13088
|
+
}
|
|
13089
|
+
if (result.workflowNodeExecutionId) {
|
|
13090
|
+
output3.workflowNodeExecutionId = result.workflowNodeExecutionId;
|
|
13091
|
+
}
|
|
13092
|
+
output3.timing = {
|
|
13093
|
+
createdAt: result.createdAt,
|
|
13094
|
+
updatedAt: result.updatedAt
|
|
13095
|
+
};
|
|
13096
|
+
if (result.errors && result.errors.length > 0) {
|
|
13097
|
+
output3.errors = result.errors;
|
|
13098
|
+
}
|
|
13099
|
+
if (result.errorType) {
|
|
13100
|
+
output3.errorType = result.errorType;
|
|
13101
|
+
}
|
|
13102
|
+
if (result.outputUrl) {
|
|
13103
|
+
output3.outputUrl = result.outputUrl;
|
|
13104
|
+
}
|
|
13105
|
+
if (result.files && result.files.length > 0) {
|
|
13106
|
+
output3.files = result.files;
|
|
13107
|
+
}
|
|
13108
|
+
if (result.modelInfo) {
|
|
13109
|
+
output3.modelInfo = result.modelInfo;
|
|
13110
|
+
}
|
|
13111
|
+
if (options.includeSteps && result.steps) {
|
|
13112
|
+
if (options.raw) {
|
|
13113
|
+
output3.steps = result.steps;
|
|
13114
|
+
} else {
|
|
13115
|
+
output3.steps = result.steps.map((step) => ({
|
|
13116
|
+
name: step.name,
|
|
13117
|
+
contentPreview: step.content?.substring(0, 200) + (step.content && step.content.length > 200 ? "..." : ""),
|
|
13118
|
+
toolCallsCount: step.toolCalls?.length || 0,
|
|
13119
|
+
...options.includeToolCalls && step.toolCalls ? {
|
|
13120
|
+
toolCalls: step.toolCalls.map((tc) => ({
|
|
13121
|
+
callId: tc.callId,
|
|
13122
|
+
toolName: tc.toolName,
|
|
13123
|
+
status: tc.status,
|
|
13124
|
+
...options.raw ? { input: tc.input, output: tc.output } : {},
|
|
13125
|
+
...tc.error ? { error: tc.error } : {}
|
|
13126
|
+
}))
|
|
13127
|
+
} : {}
|
|
13128
|
+
}));
|
|
13129
|
+
}
|
|
13130
|
+
}
|
|
13131
|
+
if (options.includeMessages && result.messages) {
|
|
13132
|
+
if (options.raw) {
|
|
13133
|
+
output3.messages = result.messages;
|
|
13134
|
+
} else {
|
|
13135
|
+
output3.messages = result.messages.map((msg) => ({
|
|
13136
|
+
messageId: msg.messageId,
|
|
13137
|
+
type: msg.type,
|
|
13138
|
+
contentPreview: msg.content?.substring(0, 200) + (msg.content && msg.content.length > 200 ? "..." : ""),
|
|
13139
|
+
createdAt: msg.createdAt
|
|
13140
|
+
}));
|
|
13141
|
+
}
|
|
13142
|
+
}
|
|
13143
|
+
return output3;
|
|
13144
|
+
}
|
|
13145
|
+
var workflowResultCommand = new Command("result").description("Get action result by resultId").argument("<resultId>", "Action result ID (ar-xxx)").option("--include-steps", "Include execution steps").option("--include-messages", "Include action messages").option("--include-tool-calls", "Include tool call details (requires --include-steps)").option("--raw", "Show full content without truncation").action(async (resultId, options) => {
|
|
13146
|
+
try {
|
|
13147
|
+
if (!resultId.startsWith("ar-") && !resultId.startsWith("start-")) {
|
|
13148
|
+
return fail(ErrorCodes.INVALID_INPUT, `Invalid resultId format: ${resultId}`, {
|
|
13149
|
+
hint: 'Result ID should start with "ar-" or "start-"',
|
|
13150
|
+
suggestedFix: {
|
|
13151
|
+
field: "resultId",
|
|
13152
|
+
format: "ar-xxx or start-xxx",
|
|
13153
|
+
example: "ar-cq18zd4qr97nbla1tu1rqqmd"
|
|
13154
|
+
}
|
|
13155
|
+
});
|
|
13156
|
+
}
|
|
13157
|
+
const result = await apiGetActionResult(resultId);
|
|
13158
|
+
const formattedResult = formatResult(result, {
|
|
13159
|
+
includeSteps: options.includeSteps,
|
|
13160
|
+
includeMessages: options.includeMessages,
|
|
13161
|
+
includeToolCalls: options.includeToolCalls,
|
|
13162
|
+
raw: options.raw
|
|
13163
|
+
});
|
|
13164
|
+
ok("workflow.result", formattedResult);
|
|
13165
|
+
} catch (error) {
|
|
13166
|
+
if (error instanceof CLIError) {
|
|
13167
|
+
fail(error.code, error.message, {
|
|
13168
|
+
details: error.details,
|
|
13169
|
+
hint: error.hint,
|
|
13170
|
+
suggestedFix: error.suggestedFix
|
|
13171
|
+
});
|
|
13172
|
+
}
|
|
13173
|
+
fail(
|
|
13174
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
13175
|
+
error instanceof Error ? error.message : "Failed to get action result"
|
|
13176
|
+
);
|
|
13177
|
+
}
|
|
13178
|
+
});
|
|
13179
|
+
|
|
13180
|
+
// src/commands/workflow/session.ts
|
|
13181
|
+
init_cjs_shims();
|
|
13182
|
+
var workflowSessionCommand = new Command("session").description("Get the latest copilot session for a workflow").argument("<workflowId>", "Workflow ID (canvas ID)").action(async (workflowId) => {
|
|
13183
|
+
try {
|
|
13184
|
+
const result = await apiRequest(
|
|
13185
|
+
`/v1/cli/workflow/${workflowId}/session`
|
|
13186
|
+
);
|
|
13187
|
+
ok("workflow.session", result);
|
|
13188
|
+
} catch (error) {
|
|
13189
|
+
if (error instanceof CLIError) {
|
|
13190
|
+
fail(error.code, error.message, {
|
|
13191
|
+
details: error.details,
|
|
13192
|
+
hint: error.hint,
|
|
13193
|
+
suggestedFix: error.suggestedFix
|
|
13194
|
+
});
|
|
13195
|
+
}
|
|
11966
13196
|
fail(
|
|
11967
13197
|
ErrorCodes.INTERNAL_ERROR,
|
|
11968
|
-
error instanceof Error ? error.message : "Failed to
|
|
13198
|
+
error instanceof Error ? error.message : "Failed to get workflow session"
|
|
11969
13199
|
);
|
|
11970
13200
|
}
|
|
11971
13201
|
});
|
|
11972
13202
|
|
|
11973
13203
|
// src/commands/workflow/index.ts
|
|
11974
|
-
var workflowCommand = new Command("workflow").description("Manage and run workflows").addCommand(workflowCreateCommand).addCommand(workflowGenerateCommand).addCommand(workflowListCommand).addCommand(workflowGetCommand).addCommand(
|
|
13204
|
+
var workflowCommand = new Command("workflow").description("Manage and run workflows").addCommand(workflowCreateCommand).addCommand(workflowGenerateCommand).addCommand(workflowListCommand).addCommand(workflowGetCommand).addCommand(workflowDeleteCommand).addCommand(workflowRunCommand).addCommand(workflowRunsCommand).addCommand(workflowStatusCommand).addCommand(workflowDetailCommand).addCommand(workflowToolcallsCommand).addCommand(workflowAbortCommand).addCommand(workflowToolsetKeysCommand).addCommand(workflowLayoutCommand).addCommand(workflowNodesCommand).addCommand(workflowNodeGetCommand).addCommand(workflowNodeAddCommand).addCommand(workflowNodeUpdateCommand).addCommand(workflowNodeDeleteCommand).addCommand(workflowNodeOutputCommand).addCommand(workflowEditCommand).addCommand(workflowVariablesCommand).addCommand(workflowSessionCommand).addCommand(workflowResultCommand);
|
|
11975
13205
|
|
|
11976
13206
|
// src/commands/tool/index.ts
|
|
11977
13207
|
init_cjs_shims();
|
|
@@ -12003,7 +13233,11 @@ var toolCallsCommand = new Command("calls").description("Get tool execution resu
|
|
|
12003
13233
|
});
|
|
12004
13234
|
} catch (error) {
|
|
12005
13235
|
if (error instanceof CLIError) {
|
|
12006
|
-
fail(error.code, error.message, {
|
|
13236
|
+
fail(error.code, error.message, {
|
|
13237
|
+
details: error.details,
|
|
13238
|
+
hint: error.hint,
|
|
13239
|
+
suggestedFix: error.suggestedFix
|
|
13240
|
+
});
|
|
12007
13241
|
}
|
|
12008
13242
|
fail(
|
|
12009
13243
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -12048,7 +13282,11 @@ var toolGetCommand = new Command("get").description("Get full details for a sing
|
|
|
12048
13282
|
});
|
|
12049
13283
|
} catch (error) {
|
|
12050
13284
|
if (error instanceof CLIError) {
|
|
12051
|
-
fail(error.code, error.message, {
|
|
13285
|
+
fail(error.code, error.message, {
|
|
13286
|
+
details: error.details,
|
|
13287
|
+
hint: error.hint,
|
|
13288
|
+
suggestedFix: error.suggestedFix
|
|
13289
|
+
});
|
|
12052
13290
|
}
|
|
12053
13291
|
fail(
|
|
12054
13292
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -12096,7 +13334,11 @@ var fileListCommand = new Command("list").description("List files").option("--pa
|
|
|
12096
13334
|
});
|
|
12097
13335
|
} catch (error) {
|
|
12098
13336
|
if (error instanceof CLIError) {
|
|
12099
|
-
fail(error.code, error.message, {
|
|
13337
|
+
fail(error.code, error.message, {
|
|
13338
|
+
details: error.details,
|
|
13339
|
+
hint: error.hint,
|
|
13340
|
+
suggestedFix: error.suggestedFix
|
|
13341
|
+
});
|
|
12100
13342
|
}
|
|
12101
13343
|
fail(
|
|
12102
13344
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -12124,7 +13366,11 @@ var fileGetCommand = new Command("get").description("Get file details").argument
|
|
|
12124
13366
|
});
|
|
12125
13367
|
} catch (error) {
|
|
12126
13368
|
if (error instanceof CLIError) {
|
|
12127
|
-
fail(error.code, error.message, {
|
|
13369
|
+
fail(error.code, error.message, {
|
|
13370
|
+
details: error.details,
|
|
13371
|
+
hint: error.hint,
|
|
13372
|
+
suggestedFix: error.suggestedFix
|
|
13373
|
+
});
|
|
12128
13374
|
}
|
|
12129
13375
|
fail(
|
|
12130
13376
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -12136,14 +13382,14 @@ var fileGetCommand = new Command("get").description("Get file details").argument
|
|
|
12136
13382
|
// src/commands/file/download.ts
|
|
12137
13383
|
init_cjs_shims();
|
|
12138
13384
|
var fs14 = __toESM(require("fs"));
|
|
12139
|
-
var
|
|
13385
|
+
var path11 = __toESM(require("path"));
|
|
12140
13386
|
var fileDownloadCommand = new Command("download").description("Download file to local filesystem").argument("<fileId>", "File ID").option("-o, --output <path>", "Output file path (defaults to original filename)").action(async (fileId, options) => {
|
|
12141
13387
|
try {
|
|
12142
13388
|
const { data, filename, contentType, size } = await apiRequestStream(
|
|
12143
13389
|
`/v1/cli/drive/files/${fileId}/download`
|
|
12144
13390
|
);
|
|
12145
13391
|
const outputPath = options.output || filename || `${fileId}`;
|
|
12146
|
-
const resolvedPath =
|
|
13392
|
+
const resolvedPath = path11.resolve(outputPath);
|
|
12147
13393
|
fs14.writeFileSync(resolvedPath, data);
|
|
12148
13394
|
ok("file.download", {
|
|
12149
13395
|
fileId,
|
|
@@ -12154,7 +13400,11 @@ var fileDownloadCommand = new Command("download").description("Download file to
|
|
|
12154
13400
|
});
|
|
12155
13401
|
} catch (error) {
|
|
12156
13402
|
if (error instanceof CLIError) {
|
|
12157
|
-
fail(error.code, error.message, {
|
|
13403
|
+
fail(error.code, error.message, {
|
|
13404
|
+
details: error.details,
|
|
13405
|
+
hint: error.hint,
|
|
13406
|
+
suggestedFix: error.suggestedFix
|
|
13407
|
+
});
|
|
12158
13408
|
}
|
|
12159
13409
|
fail(
|
|
12160
13410
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -12166,7 +13416,7 @@ var fileDownloadCommand = new Command("download").description("Download file to
|
|
|
12166
13416
|
// src/commands/file/upload.ts
|
|
12167
13417
|
init_cjs_shims();
|
|
12168
13418
|
var fs15 = __toESM(require("fs"));
|
|
12169
|
-
var
|
|
13419
|
+
var path12 = __toESM(require("path"));
|
|
12170
13420
|
var MAX_FILES = 10;
|
|
12171
13421
|
function formatSize(bytes) {
|
|
12172
13422
|
if (bytes < 1024) return `${bytes}B`;
|
|
@@ -12176,7 +13426,7 @@ function formatSize(bytes) {
|
|
|
12176
13426
|
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) => {
|
|
12177
13427
|
const formatter = getFormatter();
|
|
12178
13428
|
try {
|
|
12179
|
-
const resolvedPath =
|
|
13429
|
+
const resolvedPath = path12.resolve(inputPath);
|
|
12180
13430
|
if (!fs15.existsSync(resolvedPath)) {
|
|
12181
13431
|
fail(ErrorCodes.NOT_FOUND, `Path not found: ${inputPath}`, {
|
|
12182
13432
|
hint: "Check if the file or directory exists"
|
|
@@ -12195,7 +13445,7 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
|
|
|
12195
13445
|
const errors = [];
|
|
12196
13446
|
for (let i = 0; i < files.length; i++) {
|
|
12197
13447
|
const filePath = files[i];
|
|
12198
|
-
const filename =
|
|
13448
|
+
const filename = path12.basename(filePath);
|
|
12199
13449
|
const fileStats = fs15.statSync(filePath);
|
|
12200
13450
|
const sizeStr = formatSize(fileStats.size);
|
|
12201
13451
|
let currentStage = "presign";
|
|
@@ -12264,7 +13514,11 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
|
|
|
12264
13514
|
});
|
|
12265
13515
|
} catch (error) {
|
|
12266
13516
|
if (error instanceof CLIError) {
|
|
12267
|
-
fail(error.code, error.message, {
|
|
13517
|
+
fail(error.code, error.message, {
|
|
13518
|
+
details: error.details,
|
|
13519
|
+
hint: error.hint,
|
|
13520
|
+
suggestedFix: error.suggestedFix
|
|
13521
|
+
});
|
|
12268
13522
|
}
|
|
12269
13523
|
fail(
|
|
12270
13524
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -12277,7 +13531,7 @@ function resolveFilesToUpload(inputPath, filter) {
|
|
|
12277
13531
|
if (stats.isFile()) {
|
|
12278
13532
|
if (filter) {
|
|
12279
13533
|
const filterExts = filter.split(",").map((e) => e.trim().toLowerCase());
|
|
12280
|
-
const ext =
|
|
13534
|
+
const ext = path12.extname(inputPath).slice(1).toLowerCase();
|
|
12281
13535
|
if (!filterExts.includes(ext)) {
|
|
12282
13536
|
return [];
|
|
12283
13537
|
}
|
|
@@ -12287,7 +13541,7 @@ function resolveFilesToUpload(inputPath, filter) {
|
|
|
12287
13541
|
if (stats.isDirectory()) {
|
|
12288
13542
|
const entries = fs15.readdirSync(inputPath);
|
|
12289
13543
|
const filterExts = filter?.split(",").map((e) => e.trim().toLowerCase());
|
|
12290
|
-
const files = entries.map((e) =>
|
|
13544
|
+
const files = entries.map((e) => path12.join(inputPath, e)).filter((p) => {
|
|
12291
13545
|
try {
|
|
12292
13546
|
return fs15.statSync(p).isFile();
|
|
12293
13547
|
} catch {
|
|
@@ -12295,7 +13549,7 @@ function resolveFilesToUpload(inputPath, filter) {
|
|
|
12295
13549
|
}
|
|
12296
13550
|
}).filter((p) => {
|
|
12297
13551
|
if (!filterExts) return true;
|
|
12298
|
-
const ext =
|
|
13552
|
+
const ext = path12.extname(p).slice(1).toLowerCase();
|
|
12299
13553
|
return filterExts.includes(ext);
|
|
12300
13554
|
}).sort((a, b) => {
|
|
12301
13555
|
try {
|
|
@@ -12344,7 +13598,11 @@ var skillListCommand = new Command("list").description("List skill packages").op
|
|
|
12344
13598
|
});
|
|
12345
13599
|
} catch (error) {
|
|
12346
13600
|
if (error instanceof CLIError) {
|
|
12347
|
-
fail(error.code, error.message, {
|
|
13601
|
+
fail(error.code, error.message, {
|
|
13602
|
+
details: error.details,
|
|
13603
|
+
hint: error.hint,
|
|
13604
|
+
suggestedFix: error.suggestedFix
|
|
13605
|
+
});
|
|
12348
13606
|
return;
|
|
12349
13607
|
}
|
|
12350
13608
|
fail(
|
|
@@ -12383,7 +13641,11 @@ var skillGetCommand = new Command("get").description("Get skill package details"
|
|
|
12383
13641
|
});
|
|
12384
13642
|
} catch (error) {
|
|
12385
13643
|
if (error instanceof CLIError) {
|
|
12386
|
-
fail(error.code, error.message, {
|
|
13644
|
+
fail(error.code, error.message, {
|
|
13645
|
+
details: error.details,
|
|
13646
|
+
hint: error.hint,
|
|
13647
|
+
suggestedFix: error.suggestedFix
|
|
13648
|
+
});
|
|
12387
13649
|
return;
|
|
12388
13650
|
}
|
|
12389
13651
|
fail(
|
|
@@ -12395,407 +13657,29 @@ var skillGetCommand = new Command("get").description("Get skill package details"
|
|
|
12395
13657
|
|
|
12396
13658
|
// src/commands/skill/create.ts
|
|
12397
13659
|
init_cjs_shims();
|
|
12398
|
-
|
|
12399
|
-
// src/skill/storage.ts
|
|
12400
|
-
init_cjs_shims();
|
|
12401
13660
|
var fs16 = __toESM(require("fs"));
|
|
12402
|
-
|
|
13661
|
+
init_symlink();
|
|
12403
13662
|
init_paths();
|
|
12404
13663
|
init_logger();
|
|
12405
|
-
|
|
12406
|
-
|
|
12407
|
-
|
|
12408
|
-
|
|
12409
|
-
|
|
12410
|
-
|
|
12411
|
-
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
|
|
12415
|
-
|
|
12416
|
-
|
|
12417
|
-
|
|
12418
|
-
|
|
12419
|
-
|
|
12420
|
-
|
|
12421
|
-
|
|
12422
|
-
code,
|
|
12423
|
-
message,
|
|
12424
|
-
details: options?.details,
|
|
12425
|
-
suggestions: options?.suggestions
|
|
12426
|
-
};
|
|
12427
|
-
}
|
|
12428
|
-
function validateCommonSkillFields(data, issues) {
|
|
12429
|
-
if (typeof data.name !== "string") {
|
|
12430
|
-
issues.push({ path: "name", message: "Name is required", value: data.name });
|
|
12431
|
-
} else if (!isValidSkillName(data.name)) {
|
|
12432
|
-
issues.push({
|
|
12433
|
-
path: "name",
|
|
12434
|
-
message: `Name must match pattern ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$ and be 1-${SKILL_NAME_MAX_LENGTH} chars`,
|
|
12435
|
-
value: data.name
|
|
12436
|
-
});
|
|
12437
|
-
}
|
|
12438
|
-
if (typeof data.description !== "string") {
|
|
12439
|
-
issues.push({
|
|
12440
|
-
path: "description",
|
|
12441
|
-
message: "Description is required",
|
|
12442
|
-
value: data.description
|
|
12443
|
-
});
|
|
12444
|
-
} else if (data.description.length > SKILL_DESCRIPTION_MAX_LENGTH) {
|
|
12445
|
-
issues.push({
|
|
12446
|
-
path: "description",
|
|
12447
|
-
message: `Description must be <= ${SKILL_DESCRIPTION_MAX_LENGTH} chars`,
|
|
12448
|
-
value: data.description.length
|
|
12449
|
-
});
|
|
12450
|
-
}
|
|
12451
|
-
if (typeof data.workflowId !== "string" || data.workflowId.trim() === "") {
|
|
12452
|
-
issues.push({ path: "workflowId", message: "WorkflowId is required", value: data.workflowId });
|
|
12453
|
-
}
|
|
12454
|
-
validateTriggers(data.triggers, issues);
|
|
12455
|
-
}
|
|
12456
|
-
function validateTriggers(triggers, issues) {
|
|
12457
|
-
if (!Array.isArray(triggers)) {
|
|
12458
|
-
issues.push({ path: "triggers", message: "Triggers must be an array", value: triggers });
|
|
12459
|
-
return;
|
|
12460
|
-
}
|
|
12461
|
-
if (triggers.length < SKILL_TRIGGERS_MIN || triggers.length > SKILL_TRIGGERS_MAX) {
|
|
12462
|
-
issues.push({
|
|
12463
|
-
path: "triggers",
|
|
12464
|
-
message: `Triggers must have ${SKILL_TRIGGERS_MIN}-${SKILL_TRIGGERS_MAX} items`,
|
|
12465
|
-
value: triggers.length
|
|
12466
|
-
});
|
|
12467
|
-
}
|
|
12468
|
-
for (let i = 0; i < triggers.length; i++) {
|
|
12469
|
-
if (typeof triggers[i] !== "string" || triggers[i].trim() === "") {
|
|
12470
|
-
issues.push({
|
|
12471
|
-
path: `triggers[${i}]`,
|
|
12472
|
-
message: "Each trigger must be a non-empty string",
|
|
12473
|
-
value: triggers[i]
|
|
13664
|
+
var skillCreateCommand = new Command("create").description("Create a new skill package with workflow").requiredOption("--name <name>", "Skill package name").option("--version <version>", "Semantic version", "1.0.0").option("--description <description>", "Skill description").option("--triggers <triggers>", "Trigger phrases (comma-separated)").option("--tags <tags>", "Category tags (comma-separated)").option("--workflow <workflowId>", "Bind existing workflow ID").option("--workflow-ids <workflowIds>", "Bind multiple workflow IDs (comma-separated)").option("--workflow-spec <json>", "Workflow spec JSON (structured)").option("--workflow-query <query>", "Natural language workflow description (be specific)").option("--verbose", "Include workflow details in output").action(async (options) => {
|
|
13665
|
+
try {
|
|
13666
|
+
const hasWorkflowOption = options.workflow || options.workflowIds || options.workflowSpec || options.workflowQuery;
|
|
13667
|
+
if (!hasWorkflowOption) {
|
|
13668
|
+
ok("skill.create.needs_workflow", {
|
|
13669
|
+
status: "pending",
|
|
13670
|
+
name: options.name,
|
|
13671
|
+
message: "Skill requires a workflow definition. Please provide more details.",
|
|
13672
|
+
questions: [
|
|
13673
|
+
"What should this skill do? Please describe the workflow functionality in detail.",
|
|
13674
|
+
"Or do you have an existing workflow ID to bind to this skill?"
|
|
13675
|
+
],
|
|
13676
|
+
options: {
|
|
13677
|
+
bindExisting: "--workflow <workflowId>",
|
|
13678
|
+
generateNew: '--workflow-query "<detailed description>"'
|
|
13679
|
+
},
|
|
13680
|
+
example: 'refly skill create --name "web-search" --workflow-query "Search the web for a given topic using Exa, then summarize the top 5 results into a markdown document"'
|
|
12474
13681
|
});
|
|
12475
|
-
|
|
12476
|
-
}
|
|
12477
|
-
}
|
|
12478
|
-
function validateOptionalSkillFields(data, issues) {
|
|
12479
|
-
if (data.tags !== void 0) {
|
|
12480
|
-
if (!Array.isArray(data.tags)) {
|
|
12481
|
-
issues.push({ path: "tags", message: "Tags must be an array if provided", value: data.tags });
|
|
12482
|
-
} else {
|
|
12483
|
-
for (let i = 0; i < data.tags.length; i++) {
|
|
12484
|
-
if (typeof data.tags[i] !== "string") {
|
|
12485
|
-
issues.push({
|
|
12486
|
-
path: `tags[${i}]`,
|
|
12487
|
-
message: "Each tag must be a string",
|
|
12488
|
-
value: data.tags[i]
|
|
12489
|
-
});
|
|
12490
|
-
}
|
|
12491
|
-
}
|
|
12492
|
-
}
|
|
12493
|
-
}
|
|
12494
|
-
if (data.author !== void 0 && typeof data.author !== "string") {
|
|
12495
|
-
issues.push({
|
|
12496
|
-
path: "author",
|
|
12497
|
-
message: "Author must be a string if provided",
|
|
12498
|
-
value: data.author
|
|
12499
|
-
});
|
|
12500
|
-
}
|
|
12501
|
-
if (data.version !== void 0 && typeof data.version !== "string") {
|
|
12502
|
-
issues.push({
|
|
12503
|
-
path: "version",
|
|
12504
|
-
message: "Version must be a string if provided",
|
|
12505
|
-
value: data.version
|
|
12506
|
-
});
|
|
12507
|
-
}
|
|
12508
|
-
}
|
|
12509
|
-
|
|
12510
|
-
// src/skill/storage.ts
|
|
12511
|
-
function getDomainSkillsDir() {
|
|
12512
|
-
return path12.join(getClaudeSkillDir(), "domain-skills");
|
|
12513
|
-
}
|
|
12514
|
-
function getSkillDir(name) {
|
|
12515
|
-
if (!isValidSkillName(name)) {
|
|
12516
|
-
throw createSkillError("INVALID_NAME" /* INVALID_NAME */, `Invalid skill name: ${name}`, {
|
|
12517
|
-
suggestions: [
|
|
12518
|
-
"Skill name must match pattern ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$",
|
|
12519
|
-
"Use lowercase letters, numbers, and hyphens only",
|
|
12520
|
-
"Name must be 1-64 characters"
|
|
12521
|
-
]
|
|
12522
|
-
});
|
|
12523
|
-
}
|
|
12524
|
-
return path12.join(getDomainSkillsDir(), name);
|
|
12525
|
-
}
|
|
12526
|
-
function getSkillFilePath(name) {
|
|
12527
|
-
return path12.join(getSkillDir(name), "skill.md");
|
|
12528
|
-
}
|
|
12529
|
-
function getSkillRelativePath(name) {
|
|
12530
|
-
return `domain-skills/${name}`;
|
|
12531
|
-
}
|
|
12532
|
-
function skillExists(name) {
|
|
12533
|
-
try {
|
|
12534
|
-
const skillDir = getSkillDir(name);
|
|
12535
|
-
return fs16.existsSync(skillDir);
|
|
12536
|
-
} catch {
|
|
12537
|
-
return false;
|
|
12538
|
-
}
|
|
12539
|
-
}
|
|
12540
|
-
function createSkillDir(name) {
|
|
12541
|
-
const skillDir = getSkillDir(name);
|
|
12542
|
-
const domainSkillsDir = getDomainSkillsDir();
|
|
12543
|
-
ensureDir(domainSkillsDir);
|
|
12544
|
-
if (fs16.existsSync(skillDir)) {
|
|
12545
|
-
throw createSkillError("SKILL_EXISTS" /* SKILL_EXISTS */, `Skill directory already exists: ${name}`, {
|
|
12546
|
-
suggestions: ["Choose a different name or delete the existing skill first"]
|
|
12547
|
-
});
|
|
12548
|
-
}
|
|
12549
|
-
fs16.mkdirSync(skillDir, { recursive: true, mode: 493 });
|
|
12550
|
-
logger.debug(`Created skill directory: ${skillDir}`);
|
|
12551
|
-
return skillDir;
|
|
12552
|
-
}
|
|
12553
|
-
function writeSkillFile(name, content) {
|
|
12554
|
-
const skillDir = getSkillDir(name);
|
|
12555
|
-
const skillFile = getSkillFilePath(name);
|
|
12556
|
-
if (!fs16.existsSync(skillDir)) {
|
|
12557
|
-
createSkillDir(name);
|
|
12558
|
-
}
|
|
12559
|
-
fs16.writeFileSync(skillFile, content, { encoding: "utf-8", mode: 420 });
|
|
12560
|
-
logger.debug(`Wrote skill file: ${skillFile}`);
|
|
12561
|
-
return skillFile;
|
|
12562
|
-
}
|
|
12563
|
-
function readSkillFile(name) {
|
|
12564
|
-
const skillFile = getSkillFilePath(name);
|
|
12565
|
-
if (!fs16.existsSync(skillFile)) {
|
|
12566
|
-
throw createSkillError("SKILL_DIR_NOT_FOUND" /* SKILL_DIR_NOT_FOUND */, `Skill file not found: ${name}`, {
|
|
12567
|
-
details: { path: skillFile },
|
|
12568
|
-
suggestions: [
|
|
12569
|
-
"Check if the skill exists with `refly skill list`",
|
|
12570
|
-
"Create a new skill with `refly skill create`"
|
|
12571
|
-
]
|
|
12572
|
-
});
|
|
12573
|
-
}
|
|
12574
|
-
return fs16.readFileSync(skillFile, "utf-8");
|
|
12575
|
-
}
|
|
12576
|
-
function listSkillDirectories() {
|
|
12577
|
-
const domainSkillsDir = getDomainSkillsDir();
|
|
12578
|
-
if (!fs16.existsSync(domainSkillsDir)) {
|
|
12579
|
-
return [];
|
|
12580
|
-
}
|
|
12581
|
-
const entries = fs16.readdirSync(domainSkillsDir, { withFileTypes: true });
|
|
12582
|
-
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => isValidSkillName(name));
|
|
12583
|
-
}
|
|
12584
|
-
function generateSkillTemplate(options) {
|
|
12585
|
-
const { name, description, workflowId, triggers, tags, author, version } = options;
|
|
12586
|
-
const frontmatterLines = [
|
|
12587
|
-
"---",
|
|
12588
|
-
`name: ${name}`,
|
|
12589
|
-
`description: ${description}`,
|
|
12590
|
-
`workflowId: ${workflowId}`,
|
|
12591
|
-
"triggers:",
|
|
12592
|
-
...triggers.map((t) => ` - ${t}`)
|
|
12593
|
-
];
|
|
12594
|
-
if (tags && tags.length > 0) {
|
|
12595
|
-
frontmatterLines.push("tags:");
|
|
12596
|
-
frontmatterLines.push(...tags.map((t) => ` - ${t}`));
|
|
12597
|
-
}
|
|
12598
|
-
if (author) {
|
|
12599
|
-
frontmatterLines.push(`author: ${author}`);
|
|
12600
|
-
}
|
|
12601
|
-
if (version) {
|
|
12602
|
-
frontmatterLines.push(`version: ${version}`);
|
|
12603
|
-
}
|
|
12604
|
-
frontmatterLines.push("---");
|
|
12605
|
-
const titleName = name.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
12606
|
-
const content = `
|
|
12607
|
-
# ${titleName}
|
|
12608
|
-
|
|
12609
|
-
## Overview
|
|
12610
|
-
|
|
12611
|
-
${description}
|
|
12612
|
-
|
|
12613
|
-
## Quick Start
|
|
12614
|
-
|
|
12615
|
-
\`\`\`bash
|
|
12616
|
-
refly skill run ${name} --input '{}'
|
|
12617
|
-
\`\`\`
|
|
12618
|
-
|
|
12619
|
-
## Workflow
|
|
12620
|
-
|
|
12621
|
-
This skill executes workflow \`${workflowId}\`.
|
|
12622
|
-
|
|
12623
|
-
## Input
|
|
12624
|
-
|
|
12625
|
-
Provide input as JSON:
|
|
12626
|
-
|
|
12627
|
-
\`\`\`json
|
|
12628
|
-
{
|
|
12629
|
-
// Add your input parameters here
|
|
12630
|
-
}
|
|
12631
|
-
\`\`\`
|
|
12632
|
-
|
|
12633
|
-
## Output
|
|
12634
|
-
|
|
12635
|
-
The skill returns the workflow execution result.
|
|
12636
|
-
`;
|
|
12637
|
-
return frontmatterLines.join("\n") + content;
|
|
12638
|
-
}
|
|
12639
|
-
function syncCloudSkillToLocal(options) {
|
|
12640
|
-
const { name, description, workflowId, triggers = [], tags, version, skillId } = options;
|
|
12641
|
-
const finalTriggers = triggers.length > 0 ? triggers : [name];
|
|
12642
|
-
const content = generateSkillTemplate({
|
|
12643
|
-
name,
|
|
12644
|
-
description: description || `Skill: ${name}`,
|
|
12645
|
-
workflowId,
|
|
12646
|
-
triggers: finalTriggers,
|
|
12647
|
-
tags,
|
|
12648
|
-
version
|
|
12649
|
-
});
|
|
12650
|
-
const filePath = writeSkillFile(name, content);
|
|
12651
|
-
const registryEntry = {
|
|
12652
|
-
name,
|
|
12653
|
-
description: description || `Skill: ${name}`,
|
|
12654
|
-
workflowId,
|
|
12655
|
-
triggers: finalTriggers,
|
|
12656
|
-
path: getSkillRelativePath(name),
|
|
12657
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12658
|
-
source: "refly-cloud",
|
|
12659
|
-
tags,
|
|
12660
|
-
version,
|
|
12661
|
-
skillId
|
|
12662
|
-
};
|
|
12663
|
-
logger.info(`Synced cloud skill '${name}' to local: ${filePath}`);
|
|
12664
|
-
return { filePath, registryEntry };
|
|
12665
|
-
}
|
|
12666
|
-
|
|
12667
|
-
// src/skill/registry.ts
|
|
12668
|
-
init_cjs_shims();
|
|
12669
|
-
var fs17 = __toESM(require("fs"));
|
|
12670
|
-
var path13 = __toESM(require("path"));
|
|
12671
|
-
var crypto2 = __toESM(require("crypto"));
|
|
12672
|
-
init_paths();
|
|
12673
|
-
init_logger();
|
|
12674
|
-
function getRegistryPath() {
|
|
12675
|
-
return path13.join(getClaudeSkillDir(), "registry.json");
|
|
12676
|
-
}
|
|
12677
|
-
function createEmptyRegistry() {
|
|
12678
|
-
return {
|
|
12679
|
-
version: REGISTRY_VERSION,
|
|
12680
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12681
|
-
skills: []
|
|
12682
|
-
};
|
|
12683
|
-
}
|
|
12684
|
-
function readRegistry() {
|
|
12685
|
-
const registryPath = getRegistryPath();
|
|
12686
|
-
if (!fs17.existsSync(registryPath)) {
|
|
12687
|
-
logger.debug("Registry file not found, returning empty registry");
|
|
12688
|
-
return createEmptyRegistry();
|
|
12689
|
-
}
|
|
12690
|
-
try {
|
|
12691
|
-
const content = fs17.readFileSync(registryPath, "utf-8");
|
|
12692
|
-
const data = JSON.parse(content);
|
|
12693
|
-
if (!isSkillRegistry(data)) {
|
|
12694
|
-
throw createSkillError("REGISTRY_CORRUPTED" /* REGISTRY_CORRUPTED */, "Registry structure is invalid", {
|
|
12695
|
-
suggestions: ["Run `refly skill validate --fix` to repair the registry"]
|
|
12696
|
-
});
|
|
12697
|
-
}
|
|
12698
|
-
logger.debug(`Registry loaded with ${data.skills.length} skills`);
|
|
12699
|
-
return data;
|
|
12700
|
-
} catch (err) {
|
|
12701
|
-
if (err instanceof SyntaxError) {
|
|
12702
|
-
throw createSkillError("REGISTRY_CORRUPTED" /* REGISTRY_CORRUPTED */, "Registry JSON is malformed", {
|
|
12703
|
-
details: { error: err.message },
|
|
12704
|
-
suggestions: ["Run `refly skill validate --fix` to repair the registry"]
|
|
12705
|
-
});
|
|
12706
|
-
}
|
|
12707
|
-
throw err;
|
|
12708
|
-
}
|
|
12709
|
-
}
|
|
12710
|
-
function writeRegistry(registry) {
|
|
12711
|
-
const registryPath = getRegistryPath();
|
|
12712
|
-
const registryDir = path13.dirname(registryPath);
|
|
12713
|
-
ensureDir(registryDir);
|
|
12714
|
-
registry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
12715
|
-
const content = JSON.stringify(registry, null, 2);
|
|
12716
|
-
const tempPath = path13.join(registryDir, `.registry-${crypto2.randomUUID()}.tmp`);
|
|
12717
|
-
try {
|
|
12718
|
-
fs17.writeFileSync(tempPath, content, { encoding: "utf-8", mode: 384 });
|
|
12719
|
-
fs17.renameSync(tempPath, registryPath);
|
|
12720
|
-
logger.debug(`Registry saved with ${registry.skills.length} skills`);
|
|
12721
|
-
} catch (err) {
|
|
12722
|
-
try {
|
|
12723
|
-
if (fs17.existsSync(tempPath)) {
|
|
12724
|
-
fs17.unlinkSync(tempPath);
|
|
12725
|
-
}
|
|
12726
|
-
} catch {
|
|
12727
|
-
}
|
|
12728
|
-
throw err;
|
|
12729
|
-
}
|
|
12730
|
-
}
|
|
12731
|
-
function findSkill(name) {
|
|
12732
|
-
const registry = readRegistry();
|
|
12733
|
-
return registry.skills.find((s) => s.name === name) ?? null;
|
|
12734
|
-
}
|
|
12735
|
-
function addSkill(entry) {
|
|
12736
|
-
const registry = readRegistry();
|
|
12737
|
-
if (registry.skills.some((s) => s.name === entry.name)) {
|
|
12738
|
-
throw createSkillError("SKILL_EXISTS" /* SKILL_EXISTS */, `Skill '${entry.name}' already exists`, {
|
|
12739
|
-
suggestions: ["Choose a different name or use `refly skill delete` first"]
|
|
12740
|
-
});
|
|
12741
|
-
}
|
|
12742
|
-
const validationErrors = validateSkillEntry(entry);
|
|
12743
|
-
if (validationErrors.length > 0) {
|
|
12744
|
-
throw createSkillError("VALIDATION_ERROR" /* VALIDATION_ERROR */, "Invalid skill entry", {
|
|
12745
|
-
details: { errors: validationErrors },
|
|
12746
|
-
suggestions: validationErrors.map((e) => e.message)
|
|
12747
|
-
});
|
|
12748
|
-
}
|
|
12749
|
-
registry.skills.push(entry);
|
|
12750
|
-
writeRegistry(registry);
|
|
12751
|
-
logger.info(`Skill '${entry.name}' added to registry`);
|
|
12752
|
-
}
|
|
12753
|
-
function validateSkillEntry(entry) {
|
|
12754
|
-
const issues = [];
|
|
12755
|
-
if (!entry || typeof entry !== "object") {
|
|
12756
|
-
issues.push({ path: "", message: "Entry must be an object", value: entry });
|
|
12757
|
-
return issues;
|
|
12758
|
-
}
|
|
12759
|
-
const e = entry;
|
|
12760
|
-
validateCommonSkillFields(e, issues);
|
|
12761
|
-
if (typeof e.path !== "string" || e.path.trim() === "") {
|
|
12762
|
-
issues.push({ path: "path", message: "Path is required", value: e.path });
|
|
12763
|
-
}
|
|
12764
|
-
if (typeof e.createdAt !== "string") {
|
|
12765
|
-
issues.push({ path: "createdAt", message: "CreatedAt is required", value: e.createdAt });
|
|
12766
|
-
}
|
|
12767
|
-
if (e.source !== "local" && e.source !== "refly-cloud") {
|
|
12768
|
-
issues.push({
|
|
12769
|
-
path: "source",
|
|
12770
|
-
message: "Source must be 'local' or 'refly-cloud'",
|
|
12771
|
-
value: e.source
|
|
12772
|
-
});
|
|
12773
|
-
}
|
|
12774
|
-
validateOptionalSkillFields(e, issues);
|
|
12775
|
-
return issues;
|
|
12776
|
-
}
|
|
12777
|
-
|
|
12778
|
-
// src/commands/skill/create.ts
|
|
12779
|
-
init_logger();
|
|
12780
|
-
var skillCreateCommand = new Command("create").description("Create a new skill package with workflow").requiredOption("--name <name>", "Skill package name").option("--version <version>", "Semantic version", "1.0.0").option("--description <description>", "Skill description").option("--triggers <triggers>", "Trigger phrases (comma-separated)").option("--tags <tags>", "Category tags (comma-separated)").option("--workflow <workflowId>", "Bind existing workflow ID").option("--workflow-ids <workflowIds>", "Bind multiple workflow IDs (comma-separated)").option("--workflow-spec <json>", "Workflow spec JSON (structured)").option("--workflow-query <query>", "Natural language workflow description (be specific)").option("--verbose", "Include workflow details in output").action(async (options) => {
|
|
12781
|
-
try {
|
|
12782
|
-
const hasWorkflowOption = options.workflow || options.workflowIds || options.workflowSpec || options.workflowQuery;
|
|
12783
|
-
if (!hasWorkflowOption) {
|
|
12784
|
-
ok("skill.create.needs_workflow", {
|
|
12785
|
-
status: "pending",
|
|
12786
|
-
name: options.name,
|
|
12787
|
-
message: "Skill requires a workflow definition. Please provide more details.",
|
|
12788
|
-
questions: [
|
|
12789
|
-
"What should this skill do? Please describe the workflow functionality in detail.",
|
|
12790
|
-
"Or do you have an existing workflow ID to bind to this skill?"
|
|
12791
|
-
],
|
|
12792
|
-
options: {
|
|
12793
|
-
bindExisting: "--workflow <workflowId>",
|
|
12794
|
-
generateNew: '--workflow-query "<detailed description>"'
|
|
12795
|
-
},
|
|
12796
|
-
example: 'refly skill create --name "web-search" --workflow-query "Search the web for a given topic using Exa, then summarize the top 5 results into a markdown document"'
|
|
12797
|
-
});
|
|
12798
|
-
return;
|
|
13682
|
+
return;
|
|
12799
13683
|
}
|
|
12800
13684
|
const input3 = {
|
|
12801
13685
|
name: options.name,
|
|
@@ -12818,41 +13702,51 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
|
|
|
12818
13702
|
body: input3
|
|
12819
13703
|
});
|
|
12820
13704
|
const result = response.payload;
|
|
12821
|
-
let
|
|
13705
|
+
let localPath;
|
|
13706
|
+
let _symlinkPath;
|
|
12822
13707
|
if (result.workflowId) {
|
|
12823
13708
|
try {
|
|
12824
13709
|
const localName = options.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
12825
|
-
|
|
13710
|
+
const skillDir = getReflyDomainSkillDir(localName);
|
|
13711
|
+
const symlinkStatus = isSkillSymlinkValid(localName);
|
|
13712
|
+
if (fs16.existsSync(skillDir) || symlinkStatus.exists) {
|
|
12826
13713
|
logger.debug(`Local skill '${localName}' already exists, skipping sync`);
|
|
12827
13714
|
} else {
|
|
12828
|
-
const
|
|
13715
|
+
const skillMdContent = generateReflySkillMd({
|
|
12829
13716
|
name: localName,
|
|
13717
|
+
displayName: options.name,
|
|
12830
13718
|
description: input3.description || `Skill: ${options.name}`,
|
|
13719
|
+
skillId: result.skillId,
|
|
12831
13720
|
workflowId: result.workflowId,
|
|
12832
13721
|
triggers: input3.triggers,
|
|
12833
13722
|
tags: input3.tags,
|
|
12834
13723
|
version: options.version,
|
|
12835
|
-
|
|
13724
|
+
inputSchema: result.inputSchema,
|
|
13725
|
+
outputSchema: result.outputSchema
|
|
12836
13726
|
});
|
|
12837
|
-
|
|
12838
|
-
|
|
12839
|
-
|
|
13727
|
+
const symlinkResult = createReflySkillWithSymlink(localName, skillMdContent);
|
|
13728
|
+
if (symlinkResult.success) {
|
|
13729
|
+
localPath = symlinkResult.reflyPath;
|
|
13730
|
+
_symlinkPath = symlinkResult.claudePath;
|
|
13731
|
+
logger.info(`Created local domain skill: ${localName}`);
|
|
13732
|
+
} else {
|
|
13733
|
+
logger.warn(`Failed to create local skill: ${symlinkResult.error}`);
|
|
13734
|
+
}
|
|
12840
13735
|
}
|
|
12841
13736
|
} catch (syncError) {
|
|
12842
13737
|
logger.warn(`Failed to sync to local: ${syncError.message}`);
|
|
12843
13738
|
}
|
|
12844
13739
|
}
|
|
13740
|
+
const webUrl = getWebUrl();
|
|
12845
13741
|
const payload = {
|
|
12846
13742
|
skillId: result.skillId,
|
|
12847
13743
|
name: result.name,
|
|
12848
13744
|
status: result.status,
|
|
12849
13745
|
createdAt: result.createdAt,
|
|
12850
13746
|
workflowId: result.workflowId,
|
|
12851
|
-
|
|
13747
|
+
workflowUrl: result.workflowId ? `${webUrl}/workflow/${result.workflowId}` : void 0,
|
|
13748
|
+
localPath
|
|
12852
13749
|
};
|
|
12853
|
-
if (localSkillPath) {
|
|
12854
|
-
payload.localSkillPath = localSkillPath;
|
|
12855
|
-
}
|
|
12856
13750
|
if (options.verbose) {
|
|
12857
13751
|
payload.workflowIds = result.workflowIds;
|
|
12858
13752
|
payload.workflows = result.workflows;
|
|
@@ -12860,7 +13754,11 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
|
|
|
12860
13754
|
ok("skill.create", payload);
|
|
12861
13755
|
} catch (error) {
|
|
12862
13756
|
if (error instanceof CLIError) {
|
|
12863
|
-
fail(error.code, error.message, {
|
|
13757
|
+
fail(error.code, error.message, {
|
|
13758
|
+
details: error.details,
|
|
13759
|
+
hint: error.hint,
|
|
13760
|
+
suggestedFix: error.suggestedFix
|
|
13761
|
+
});
|
|
12864
13762
|
return;
|
|
12865
13763
|
}
|
|
12866
13764
|
fail(
|
|
@@ -12870,37 +13768,188 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
|
|
|
12870
13768
|
}
|
|
12871
13769
|
});
|
|
12872
13770
|
|
|
12873
|
-
// src/commands/skill/
|
|
13771
|
+
// src/commands/skill/update.ts
|
|
12874
13772
|
init_cjs_shims();
|
|
12875
|
-
var
|
|
13773
|
+
var fs17 = __toESM(require("fs"));
|
|
13774
|
+
var path13 = __toESM(require("path"));
|
|
13775
|
+
init_paths();
|
|
13776
|
+
init_symlink();
|
|
13777
|
+
var MIN_DESCRIPTION_WORDS = 20;
|
|
13778
|
+
function validateDescription(description, skillName) {
|
|
13779
|
+
if (!description) {
|
|
13780
|
+
return {
|
|
13781
|
+
message: "Skill description is required for Claude Code discovery",
|
|
13782
|
+
hint: `Add a description field with at least ${MIN_DESCRIPTION_WORDS} words to your SKILL.md`,
|
|
13783
|
+
example: generateDescriptionExample(skillName)
|
|
13784
|
+
};
|
|
13785
|
+
}
|
|
13786
|
+
const wordCount = description.trim().split(/\s+/).length;
|
|
13787
|
+
if (wordCount < MIN_DESCRIPTION_WORDS) {
|
|
13788
|
+
return {
|
|
13789
|
+
message: `Description too short (${wordCount} words). Minimum ${MIN_DESCRIPTION_WORDS} words required for Claude Code discovery`,
|
|
13790
|
+
hint: `Expand the description in your SKILL.md to at least ${MIN_DESCRIPTION_WORDS} words`,
|
|
13791
|
+
example: generateDescriptionExample(skillName)
|
|
13792
|
+
};
|
|
13793
|
+
}
|
|
13794
|
+
return null;
|
|
13795
|
+
}
|
|
13796
|
+
function generateDescriptionExample(skillName) {
|
|
13797
|
+
const baseName = skillName.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
13798
|
+
return `${baseName} automation and processing. Use when Claude needs to: (1) [describe primary use case], (2) [describe secondary use case], or [general catch-all scenario].`;
|
|
13799
|
+
}
|
|
13800
|
+
var skillUpdateCommand = new Command("update").description("Update skill installation from local SKILL.md").requiredOption("--name <name>", "Local skill name (directory in ~/.refly/skills/)").option("--id <installationId>", "Override installation ID (default: from SKILL.md)").option("--skip-description", "Skip description validation").action(async (options) => {
|
|
12876
13801
|
try {
|
|
12877
|
-
|
|
12878
|
-
|
|
12879
|
-
|
|
12880
|
-
|
|
12881
|
-
|
|
12882
|
-
|
|
13802
|
+
const name = options.name;
|
|
13803
|
+
const skillDir = getReflyDomainSkillDir(name);
|
|
13804
|
+
const skillMdPath = path13.join(skillDir, "SKILL.md");
|
|
13805
|
+
if (!fs17.existsSync(skillMdPath)) {
|
|
13806
|
+
const skillsDir = getReflySkillsDir();
|
|
13807
|
+
fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
|
|
13808
|
+
hint: `Make sure the skill '${name}' exists in ${skillsDir}/
|
|
13809
|
+
|
|
13810
|
+
To see installed skills: refly skill list`
|
|
13811
|
+
});
|
|
13812
|
+
return;
|
|
13813
|
+
}
|
|
13814
|
+
const skillContent = fs17.readFileSync(skillMdPath, "utf-8");
|
|
13815
|
+
let meta;
|
|
13816
|
+
try {
|
|
13817
|
+
const parsed = parseReflySkillMd(skillContent);
|
|
13818
|
+
meta = parsed.meta;
|
|
13819
|
+
} catch (parseError) {
|
|
13820
|
+
fail(
|
|
13821
|
+
ErrorCodes.INVALID_INPUT,
|
|
13822
|
+
`Failed to parse SKILL.md: ${parseError.message}`,
|
|
13823
|
+
{
|
|
13824
|
+
hint: "Make sure SKILL.md has valid frontmatter with required fields: name, description, skillId, workflowId"
|
|
13825
|
+
}
|
|
13826
|
+
);
|
|
13827
|
+
return;
|
|
13828
|
+
}
|
|
13829
|
+
const installationId = options.id || meta.installationId;
|
|
13830
|
+
if (!installationId) {
|
|
13831
|
+
fail(ErrorCodes.INVALID_INPUT, "Installation ID not found", {
|
|
13832
|
+
hint: "Provide --id <installationId> or ensure your SKILL.md contains the installationId field"
|
|
13833
|
+
});
|
|
13834
|
+
return;
|
|
13835
|
+
}
|
|
13836
|
+
const skipDescription = options.skipDescription;
|
|
13837
|
+
if (!skipDescription) {
|
|
13838
|
+
const descriptionError = validateDescription(meta.description, name);
|
|
13839
|
+
if (descriptionError) {
|
|
13840
|
+
fail(ErrorCodes.VALIDATION_ERROR, descriptionError.message, {
|
|
13841
|
+
hint: descriptionError.hint,
|
|
13842
|
+
recoverable: true,
|
|
13843
|
+
suggestedFix: {
|
|
13844
|
+
field: "description",
|
|
13845
|
+
format: "[What it does]. Use when [scenarios]: (1) [case1], (2) [case2], or [catch-all].",
|
|
13846
|
+
example: descriptionError.example
|
|
13847
|
+
}
|
|
13848
|
+
});
|
|
13849
|
+
return;
|
|
13850
|
+
}
|
|
13851
|
+
}
|
|
13852
|
+
const updatePayload = {
|
|
13853
|
+
...meta.name && { name: meta.name },
|
|
13854
|
+
...meta.description && { description: meta.description },
|
|
13855
|
+
...meta.workflowId && { workflowId: meta.workflowId },
|
|
13856
|
+
...meta.triggers?.length && { triggers: meta.triggers },
|
|
13857
|
+
...meta.tags?.length && { tags: meta.tags },
|
|
13858
|
+
...meta.version && { version: meta.version }
|
|
13859
|
+
};
|
|
13860
|
+
if (Object.keys(updatePayload).length === 0) {
|
|
13861
|
+
fail(ErrorCodes.INVALID_INPUT, "No updateable fields found in SKILL.md", {
|
|
13862
|
+
hint: "Ensure SKILL.md contains fields like name, description, triggers, tags, or version"
|
|
13863
|
+
});
|
|
13864
|
+
return;
|
|
13865
|
+
}
|
|
13866
|
+
const response = await apiRequest(
|
|
13867
|
+
`/v1/skill-installations/${installationId}`,
|
|
13868
|
+
{
|
|
13869
|
+
method: "PATCH",
|
|
13870
|
+
body: updatePayload
|
|
13871
|
+
}
|
|
13872
|
+
);
|
|
13873
|
+
ok("skill.update", {
|
|
13874
|
+
...response,
|
|
13875
|
+
localName: name,
|
|
13876
|
+
updated: true,
|
|
13877
|
+
fields: Object.keys(updatePayload)
|
|
12883
13878
|
});
|
|
12884
13879
|
} catch (error) {
|
|
12885
13880
|
if (error instanceof CLIError) {
|
|
12886
|
-
fail(error.code, error.message, {
|
|
13881
|
+
fail(error.code, error.message, {
|
|
13882
|
+
details: error.details,
|
|
13883
|
+
hint: error.hint,
|
|
13884
|
+
suggestedFix: error.suggestedFix
|
|
13885
|
+
});
|
|
12887
13886
|
return;
|
|
12888
13887
|
}
|
|
12889
13888
|
fail(
|
|
12890
13889
|
ErrorCodes.INTERNAL_ERROR,
|
|
12891
|
-
error instanceof Error ? error.message : "Failed to
|
|
13890
|
+
error instanceof Error ? error.message : "Failed to update skill installation"
|
|
12892
13891
|
);
|
|
12893
13892
|
}
|
|
12894
13893
|
});
|
|
12895
13894
|
|
|
12896
13895
|
// src/commands/skill/publish.ts
|
|
12897
13896
|
init_cjs_shims();
|
|
12898
|
-
var
|
|
13897
|
+
var fs18 = __toESM(require("fs"));
|
|
13898
|
+
var path14 = __toESM(require("path"));
|
|
13899
|
+
init_symlink();
|
|
13900
|
+
init_paths();
|
|
13901
|
+
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) => {
|
|
12899
13902
|
try {
|
|
13903
|
+
const skillsDir = getReflySkillsDir();
|
|
13904
|
+
if (!options.name) {
|
|
13905
|
+
fail(ErrorCodes.INVALID_INPUT, "Missing required option: --name", {
|
|
13906
|
+
hint: `The publish command requires --name to locate the local SKILL.md.
|
|
13907
|
+
|
|
13908
|
+
Usage:
|
|
13909
|
+
refly skill publish --name <name>
|
|
13910
|
+
refly skill publish --name <name> --id <skillId> # override skillId
|
|
13911
|
+
|
|
13912
|
+
To find your skill name:
|
|
13913
|
+
refly skill list
|
|
13914
|
+
ls ${skillsDir}/`
|
|
13915
|
+
});
|
|
13916
|
+
return;
|
|
13917
|
+
}
|
|
13918
|
+
const name = options.name;
|
|
13919
|
+
const skillDir = getReflyDomainSkillDir(name);
|
|
13920
|
+
const skillMdPath = path14.join(skillDir, "SKILL.md");
|
|
13921
|
+
if (!fs18.existsSync(skillMdPath)) {
|
|
13922
|
+
fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
|
|
13923
|
+
hint: `Make sure the skill '${name}' exists in ${skillsDir}/
|
|
13924
|
+
|
|
13925
|
+
To see installed skills: refly skill list
|
|
13926
|
+
To create a new skill: refly skill create --name "${name}" --workflow-query "..."`
|
|
13927
|
+
});
|
|
13928
|
+
return;
|
|
13929
|
+
}
|
|
13930
|
+
const skillContent = fs18.readFileSync(skillMdPath, "utf-8");
|
|
13931
|
+
let parsedSkill;
|
|
13932
|
+
try {
|
|
13933
|
+
parsedSkill = parseReflySkillMd(skillContent);
|
|
13934
|
+
} catch (parseError) {
|
|
13935
|
+
fail(
|
|
13936
|
+
ErrorCodes.INVALID_INPUT,
|
|
13937
|
+
`Failed to parse SKILL.md: ${parseError.message}`,
|
|
13938
|
+
{
|
|
13939
|
+
hint: "Make sure SKILL.md has valid frontmatter with required fields: name, description, skillId, workflowId"
|
|
13940
|
+
}
|
|
13941
|
+
);
|
|
13942
|
+
return;
|
|
13943
|
+
}
|
|
13944
|
+
const { meta } = parsedSkill;
|
|
13945
|
+
const skillId = options.id || meta.skillId;
|
|
12900
13946
|
const result = await apiRequest(
|
|
12901
13947
|
`/v1/skill-packages/${skillId}/publish`,
|
|
12902
13948
|
{
|
|
12903
|
-
method: "POST"
|
|
13949
|
+
method: "POST",
|
|
13950
|
+
body: {
|
|
13951
|
+
skillContent
|
|
13952
|
+
}
|
|
12904
13953
|
}
|
|
12905
13954
|
);
|
|
12906
13955
|
ok("skill.publish", {
|
|
@@ -12909,12 +13958,17 @@ var skillPublishCommand = new Command("publish").description("Publish a skill pa
|
|
|
12909
13958
|
version: result.version,
|
|
12910
13959
|
status: result.status,
|
|
12911
13960
|
isPublic: result.isPublic,
|
|
12912
|
-
|
|
12913
|
-
|
|
13961
|
+
githubPrUrl: result.githubPrUrl,
|
|
13962
|
+
githubPrNumber: result.githubPrNumber,
|
|
13963
|
+
localPath: skillMdPath
|
|
12914
13964
|
});
|
|
12915
13965
|
} catch (error) {
|
|
12916
13966
|
if (error instanceof CLIError) {
|
|
12917
|
-
fail(error.code, error.message, {
|
|
13967
|
+
fail(error.code, error.message, {
|
|
13968
|
+
details: error.details,
|
|
13969
|
+
hint: error.hint,
|
|
13970
|
+
suggestedFix: error.suggestedFix
|
|
13971
|
+
});
|
|
12918
13972
|
return;
|
|
12919
13973
|
}
|
|
12920
13974
|
fail(
|
|
@@ -12926,19 +13980,72 @@ var skillPublishCommand = new Command("publish").description("Publish a skill pa
|
|
|
12926
13980
|
|
|
12927
13981
|
// src/commands/skill/unpublish.ts
|
|
12928
13982
|
init_cjs_shims();
|
|
12929
|
-
var
|
|
13983
|
+
var fs19 = __toESM(require("fs"));
|
|
13984
|
+
var path15 = __toESM(require("path"));
|
|
13985
|
+
init_symlink();
|
|
13986
|
+
init_paths();
|
|
13987
|
+
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) => {
|
|
12930
13988
|
try {
|
|
13989
|
+
const skillsDir = getReflySkillsDir();
|
|
13990
|
+
if (!options.id && !options.name) {
|
|
13991
|
+
fail(ErrorCodes.INVALID_INPUT, "Missing required option: --id or --name", {
|
|
13992
|
+
hint: `Usage:
|
|
13993
|
+
refly skill unpublish --name <name>
|
|
13994
|
+
refly skill unpublish --id <skillId>
|
|
13995
|
+
|
|
13996
|
+
To find your skill name:
|
|
13997
|
+
refly skill list
|
|
13998
|
+
ls ${skillsDir}/`
|
|
13999
|
+
});
|
|
14000
|
+
return;
|
|
14001
|
+
}
|
|
14002
|
+
let skillId;
|
|
14003
|
+
let name;
|
|
14004
|
+
if (options.name) {
|
|
14005
|
+
name = options.name;
|
|
14006
|
+
const skillDir = getReflyDomainSkillDir(name);
|
|
14007
|
+
const skillMdPath = path15.join(skillDir, "SKILL.md");
|
|
14008
|
+
if (!fs19.existsSync(skillMdPath)) {
|
|
14009
|
+
fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
|
|
14010
|
+
hint: `Make sure the skill '${name}' exists in ${skillsDir}/
|
|
14011
|
+
|
|
14012
|
+
To see installed skills: refly skill list`
|
|
14013
|
+
});
|
|
14014
|
+
return;
|
|
14015
|
+
}
|
|
14016
|
+
const skillContent = fs19.readFileSync(skillMdPath, "utf-8");
|
|
14017
|
+
try {
|
|
14018
|
+
const { meta } = parseReflySkillMd(skillContent);
|
|
14019
|
+
skillId = options.id || meta.skillId;
|
|
14020
|
+
} catch (parseError) {
|
|
14021
|
+
fail(
|
|
14022
|
+
ErrorCodes.INVALID_INPUT,
|
|
14023
|
+
`Failed to parse SKILL.md: ${parseError.message}`,
|
|
14024
|
+
{
|
|
14025
|
+
hint: "Make sure SKILL.md has valid frontmatter with required fields: name, description, skillId, workflowId"
|
|
14026
|
+
}
|
|
14027
|
+
);
|
|
14028
|
+
return;
|
|
14029
|
+
}
|
|
14030
|
+
} else {
|
|
14031
|
+
skillId = options.id;
|
|
14032
|
+
}
|
|
12931
14033
|
await apiRequest(`/v1/skill-packages/${skillId}/unpublish`, {
|
|
12932
14034
|
method: "POST"
|
|
12933
14035
|
});
|
|
12934
14036
|
ok("skill.unpublish", {
|
|
14037
|
+
name,
|
|
12935
14038
|
skillId,
|
|
12936
14039
|
status: "draft",
|
|
12937
14040
|
isPublic: false
|
|
12938
14041
|
});
|
|
12939
14042
|
} catch (error) {
|
|
12940
14043
|
if (error instanceof CLIError) {
|
|
12941
|
-
fail(error.code, error.message, {
|
|
14044
|
+
fail(error.code, error.message, {
|
|
14045
|
+
details: error.details,
|
|
14046
|
+
hint: error.hint,
|
|
14047
|
+
suggestedFix: error.suggestedFix
|
|
14048
|
+
});
|
|
12942
14049
|
return;
|
|
12943
14050
|
}
|
|
12944
14051
|
fail(
|
|
@@ -12950,21 +14057,122 @@ var skillUnpublishCommand = new Command("unpublish").description("Unpublish a sk
|
|
|
12950
14057
|
|
|
12951
14058
|
// src/commands/skill/run.ts
|
|
12952
14059
|
init_cjs_shims();
|
|
12953
|
-
var
|
|
14060
|
+
var fs20 = __toESM(require("fs"));
|
|
14061
|
+
var path16 = __toESM(require("path"));
|
|
14062
|
+
init_symlink();
|
|
14063
|
+
init_paths();
|
|
14064
|
+
var skillRunCommand = new Command("run").description("Run an installed skill").option("--id <installationId>", "Installation ID (skpi-xxx)").option("--name <name>", "Local skill name (directory in ~/.refly/skills/)").option("--input <json>", "Input JSON for the skill").option("--workflow <skillWorkflowId>", "Run specific workflow only").option("--async", "Run asynchronously").option("--no-prompt", "Disable interactive prompts (fail if required variables are missing)").action(async (options) => {
|
|
12954
14065
|
try {
|
|
14066
|
+
const skillsDir = getReflySkillsDir();
|
|
14067
|
+
if (!options.id && !options.name) {
|
|
14068
|
+
fail(ErrorCodes.INVALID_INPUT, "Missing required option: --id or --name", {
|
|
14069
|
+
hint: `Usage:
|
|
14070
|
+
refly skill run --name <name>
|
|
14071
|
+
refly skill run --id <installationId>
|
|
14072
|
+
|
|
14073
|
+
To find your skill name:
|
|
14074
|
+
refly skill list
|
|
14075
|
+
ls ${skillsDir}/`
|
|
14076
|
+
});
|
|
14077
|
+
return;
|
|
14078
|
+
}
|
|
14079
|
+
let installationId;
|
|
14080
|
+
let name;
|
|
14081
|
+
let skillId;
|
|
14082
|
+
let workflowId;
|
|
14083
|
+
if (options.name) {
|
|
14084
|
+
name = options.name;
|
|
14085
|
+
const skillDir = getReflyDomainSkillDir(options.name);
|
|
14086
|
+
const skillMdPath = path16.join(skillDir, "SKILL.md");
|
|
14087
|
+
if (!fs20.existsSync(skillMdPath)) {
|
|
14088
|
+
fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
|
|
14089
|
+
hint: `Make sure the skill '${name}' exists in ${skillsDir}/
|
|
14090
|
+
|
|
14091
|
+
To see installed skills: refly skill list
|
|
14092
|
+
To install a skill: refly skill install <skillId>`
|
|
14093
|
+
});
|
|
14094
|
+
return;
|
|
14095
|
+
}
|
|
14096
|
+
const skillContent = fs20.readFileSync(skillMdPath, "utf-8");
|
|
14097
|
+
try {
|
|
14098
|
+
const { meta } = parseReflySkillMd(skillContent);
|
|
14099
|
+
skillId = meta.skillId;
|
|
14100
|
+
workflowId = meta.workflowId;
|
|
14101
|
+
if (options.id) {
|
|
14102
|
+
installationId = options.id;
|
|
14103
|
+
} else if (meta.installationId) {
|
|
14104
|
+
installationId = meta.installationId;
|
|
14105
|
+
} else {
|
|
14106
|
+
fail(ErrorCodes.INVALID_INPUT, `Skill '${name}' does not have an installationId`, {
|
|
14107
|
+
hint: `This skill may have been created locally but not installed.
|
|
14108
|
+
|
|
14109
|
+
To install: refly skill install ${meta.skillId}`
|
|
14110
|
+
});
|
|
14111
|
+
return;
|
|
14112
|
+
}
|
|
14113
|
+
} catch (parseError) {
|
|
14114
|
+
fail(
|
|
14115
|
+
ErrorCodes.INVALID_INPUT,
|
|
14116
|
+
`Failed to parse SKILL.md: ${parseError.message}`,
|
|
14117
|
+
{
|
|
14118
|
+
hint: "Make sure SKILL.md has valid frontmatter with required fields: name, description, skillId, workflowId"
|
|
14119
|
+
}
|
|
14120
|
+
);
|
|
14121
|
+
return;
|
|
14122
|
+
}
|
|
14123
|
+
} else {
|
|
14124
|
+
installationId = options.id;
|
|
14125
|
+
}
|
|
12955
14126
|
let input3 = {};
|
|
12956
14127
|
if (options.input) {
|
|
12957
14128
|
try {
|
|
12958
14129
|
input3 = JSON.parse(options.input);
|
|
12959
14130
|
if (typeof input3 !== "object" || input3 === null || Array.isArray(input3)) {
|
|
12960
|
-
fail(ErrorCodes.INVALID_INPUT, "Input must be a JSON object"
|
|
14131
|
+
fail(ErrorCodes.INVALID_INPUT, "Input must be a JSON object", {
|
|
14132
|
+
hint: `Use format: '{"varName": "value", "fileVar": "df-fileId"}'`,
|
|
14133
|
+
suggestedFix: {
|
|
14134
|
+
field: "--input",
|
|
14135
|
+
format: "json-object",
|
|
14136
|
+
example: '{"varName": "value", "fileVar": "df-fileId"}'
|
|
14137
|
+
}
|
|
14138
|
+
});
|
|
12961
14139
|
return;
|
|
12962
14140
|
}
|
|
12963
14141
|
} catch {
|
|
12964
|
-
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON input"
|
|
14142
|
+
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON input", {
|
|
14143
|
+
hint: `Ensure the input is valid JSON, e.g., '{"varName": "value"}'`,
|
|
14144
|
+
suggestedFix: {
|
|
14145
|
+
field: "--input",
|
|
14146
|
+
format: "json-object",
|
|
14147
|
+
example: '{"varName": "value"}'
|
|
14148
|
+
}
|
|
14149
|
+
});
|
|
12965
14150
|
return;
|
|
12966
14151
|
}
|
|
12967
14152
|
}
|
|
14153
|
+
if (options.noPrompt && workflowId) {
|
|
14154
|
+
try {
|
|
14155
|
+
const workflow = await apiGetWorkflow(workflowId);
|
|
14156
|
+
if (workflow?.variables) {
|
|
14157
|
+
const checkResult = checkRequiredVariables(workflow.variables, input3);
|
|
14158
|
+
if (!checkResult.valid) {
|
|
14159
|
+
const errorPayload = buildMissingVariablesError(
|
|
14160
|
+
"skill",
|
|
14161
|
+
name || installationId,
|
|
14162
|
+
name,
|
|
14163
|
+
checkResult
|
|
14164
|
+
);
|
|
14165
|
+
fail(ErrorCodes.MISSING_VARIABLES, errorPayload.message, {
|
|
14166
|
+
details: errorPayload.details,
|
|
14167
|
+
hint: errorPayload.hint,
|
|
14168
|
+
suggestedFix: errorPayload.suggestedFix,
|
|
14169
|
+
recoverable: errorPayload.recoverable
|
|
14170
|
+
});
|
|
14171
|
+
}
|
|
14172
|
+
}
|
|
14173
|
+
} catch {
|
|
14174
|
+
}
|
|
14175
|
+
}
|
|
12968
14176
|
const body = { input: input3 };
|
|
12969
14177
|
if (options.workflow) body.workflowId = options.workflow;
|
|
12970
14178
|
if (options.async) body.async = true;
|
|
@@ -12976,6 +14184,8 @@ var skillRunCommand = new Command("run").description("Run an installed skill").a
|
|
|
12976
14184
|
}
|
|
12977
14185
|
);
|
|
12978
14186
|
ok("skill.run", {
|
|
14187
|
+
name,
|
|
14188
|
+
skillId,
|
|
12979
14189
|
executionId: result.executionId,
|
|
12980
14190
|
installationId: result.installationId,
|
|
12981
14191
|
status: result.status,
|
|
@@ -12985,7 +14195,11 @@ var skillRunCommand = new Command("run").description("Run an installed skill").a
|
|
|
12985
14195
|
});
|
|
12986
14196
|
} catch (error) {
|
|
12987
14197
|
if (error instanceof CLIError) {
|
|
12988
|
-
fail(error.code, error.message, {
|
|
14198
|
+
fail(error.code, error.message, {
|
|
14199
|
+
details: error.details,
|
|
14200
|
+
hint: error.hint,
|
|
14201
|
+
suggestedFix: error.suggestedFix
|
|
14202
|
+
});
|
|
12989
14203
|
return;
|
|
12990
14204
|
}
|
|
12991
14205
|
fail(
|
|
@@ -12995,6 +14209,87 @@ var skillRunCommand = new Command("run").description("Run an installed skill").a
|
|
|
12995
14209
|
}
|
|
12996
14210
|
});
|
|
12997
14211
|
|
|
14212
|
+
// src/commands/skill/stop.ts
|
|
14213
|
+
init_cjs_shims();
|
|
14214
|
+
var fs21 = __toESM(require("fs"));
|
|
14215
|
+
var path17 = __toESM(require("path"));
|
|
14216
|
+
init_symlink();
|
|
14217
|
+
init_paths();
|
|
14218
|
+
function getLocalSkillNames() {
|
|
14219
|
+
const skillsDir = getReflySkillsDir();
|
|
14220
|
+
if (!fs21.existsSync(skillsDir)) {
|
|
14221
|
+
return [];
|
|
14222
|
+
}
|
|
14223
|
+
return fs21.readdirSync(skillsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
14224
|
+
}
|
|
14225
|
+
var skillStopCommand = new Command("stop").description("Stop running skill executions").requiredOption("--name <name>", "Local skill name (directory in ~/.refly/skills/)").action(async (options) => {
|
|
14226
|
+
try {
|
|
14227
|
+
const skillsDir = getReflySkillsDir();
|
|
14228
|
+
const name = options.name;
|
|
14229
|
+
const skillDir = getReflyDomainSkillDir(name);
|
|
14230
|
+
const skillMdPath = path17.join(skillDir, "SKILL.md");
|
|
14231
|
+
if (!fs21.existsSync(skillMdPath)) {
|
|
14232
|
+
const availableSkills = getLocalSkillNames();
|
|
14233
|
+
const skillList = availableSkills.length > 0 ? availableSkills.join(", ") : "(no skills installed)";
|
|
14234
|
+
fail(ErrorCodes.NOT_FOUND, `Skill "${name}" not found`, {
|
|
14235
|
+
hint: `Available skills: ${skillList}
|
|
14236
|
+
|
|
14237
|
+
Skills directory: ${skillsDir}`
|
|
14238
|
+
});
|
|
14239
|
+
}
|
|
14240
|
+
const skillContent = fs21.readFileSync(skillMdPath, "utf-8");
|
|
14241
|
+
let installationId;
|
|
14242
|
+
try {
|
|
14243
|
+
const { meta } = parseReflySkillMd(skillContent);
|
|
14244
|
+
if (!meta.installationId) {
|
|
14245
|
+
fail(ErrorCodes.INVALID_INPUT, `Skill "${name}" does not have an installationId`, {
|
|
14246
|
+
hint: `This skill may have been created locally but not installed.
|
|
14247
|
+
|
|
14248
|
+
To install: refly skill install ${meta.skillId}`
|
|
14249
|
+
});
|
|
14250
|
+
}
|
|
14251
|
+
installationId = meta.installationId;
|
|
14252
|
+
} catch (parseError) {
|
|
14253
|
+
fail(
|
|
14254
|
+
ErrorCodes.INVALID_INPUT,
|
|
14255
|
+
`Failed to parse SKILL.md: ${parseError.message}`,
|
|
14256
|
+
{
|
|
14257
|
+
hint: "Make sure SKILL.md has valid frontmatter with required fields"
|
|
14258
|
+
}
|
|
14259
|
+
);
|
|
14260
|
+
}
|
|
14261
|
+
const result = await apiRequest(
|
|
14262
|
+
`/v1/skill-installations/${installationId}/stop`,
|
|
14263
|
+
{
|
|
14264
|
+
method: "POST"
|
|
14265
|
+
}
|
|
14266
|
+
);
|
|
14267
|
+
ok("skill.stop", {
|
|
14268
|
+
name,
|
|
14269
|
+
installationId,
|
|
14270
|
+
message: result.message,
|
|
14271
|
+
stoppedExecutions: result.stoppedExecutions
|
|
14272
|
+
});
|
|
14273
|
+
} catch (error) {
|
|
14274
|
+
if (error instanceof CLIError) {
|
|
14275
|
+
if (error.code === "NOT_FOUND") {
|
|
14276
|
+
fail(ErrorCodes.NOT_FOUND, `No running executions for skill "${options.name}"`, {
|
|
14277
|
+
hint: "The skill is not currently running"
|
|
14278
|
+
});
|
|
14279
|
+
}
|
|
14280
|
+
fail(error.code, error.message, {
|
|
14281
|
+
details: error.details,
|
|
14282
|
+
hint: error.hint,
|
|
14283
|
+
suggestedFix: error.suggestedFix
|
|
14284
|
+
});
|
|
14285
|
+
}
|
|
14286
|
+
fail(
|
|
14287
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
14288
|
+
error instanceof Error ? error.message : "Failed to stop skill"
|
|
14289
|
+
);
|
|
14290
|
+
}
|
|
14291
|
+
});
|
|
14292
|
+
|
|
12998
14293
|
// src/commands/skill/search.ts
|
|
12999
14294
|
init_cjs_shims();
|
|
13000
14295
|
var skillSearchCommand = new Command("search").description("Search public skill packages").argument("<query>", "Search query").option("--tags <tags>", "Filter by tags (comma-separated)").option("--page <number>", "Page number", "1").option("--page-size <number>", "Page size", "20").action(async (query, options) => {
|
|
@@ -13023,7 +14318,11 @@ var skillSearchCommand = new Command("search").description("Search public skill
|
|
|
13023
14318
|
});
|
|
13024
14319
|
} catch (error) {
|
|
13025
14320
|
if (error instanceof CLIError) {
|
|
13026
|
-
fail(error.code, error.message, {
|
|
14321
|
+
fail(error.code, error.message, {
|
|
14322
|
+
details: error.details,
|
|
14323
|
+
hint: error.hint,
|
|
14324
|
+
suggestedFix: error.suggestedFix
|
|
14325
|
+
});
|
|
13027
14326
|
return;
|
|
13028
14327
|
}
|
|
13029
14328
|
fail(
|
|
@@ -13035,16 +14334,26 @@ var skillSearchCommand = new Command("search").description("Search public skill
|
|
|
13035
14334
|
|
|
13036
14335
|
// src/commands/skill/install.ts
|
|
13037
14336
|
init_cjs_shims();
|
|
13038
|
-
|
|
14337
|
+
init_symlink();
|
|
14338
|
+
init_logger();
|
|
14339
|
+
var skillInstallCommand = new Command("install").description("Install a skill package").argument("<skillId>", "Skill package ID to install").option("--version <version>", "Specific version to install").option("--share-id <shareId>", "Share ID for private skills").option("--config <json>", "Installation config JSON").option("--force", "Force reinstall if already installed").action(async (skillId, options) => {
|
|
13039
14340
|
try {
|
|
13040
14341
|
const body = { skillId };
|
|
13041
14342
|
if (options.version) body.version = options.version;
|
|
13042
14343
|
if (options.shareId) body.shareId = options.shareId;
|
|
14344
|
+
if (options.force) body.force = true;
|
|
13043
14345
|
if (options.config) {
|
|
13044
14346
|
try {
|
|
13045
14347
|
body.config = JSON.parse(options.config);
|
|
13046
14348
|
} catch {
|
|
13047
|
-
fail(ErrorCodes.INVALID_INPUT, "Invalid config JSON"
|
|
14349
|
+
fail(ErrorCodes.INVALID_INPUT, "Invalid config JSON", {
|
|
14350
|
+
hint: `Config must be a valid JSON object, e.g., '{"key": "value"}'`,
|
|
14351
|
+
suggestedFix: {
|
|
14352
|
+
field: "--config",
|
|
14353
|
+
format: "json-object",
|
|
14354
|
+
example: '{"key": "value"}'
|
|
14355
|
+
}
|
|
14356
|
+
});
|
|
13048
14357
|
return;
|
|
13049
14358
|
}
|
|
13050
14359
|
}
|
|
@@ -13055,6 +14364,39 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
|
|
|
13055
14364
|
body
|
|
13056
14365
|
}
|
|
13057
14366
|
);
|
|
14367
|
+
let localPath;
|
|
14368
|
+
let symlinkPath;
|
|
14369
|
+
const skillName = result.skillPackage?.name;
|
|
14370
|
+
const workflowId = result.skillPackage?.workflowId;
|
|
14371
|
+
if (skillName && workflowId) {
|
|
14372
|
+
try {
|
|
14373
|
+
const skillMdContent = generateReflySkillMd({
|
|
14374
|
+
name: skillName,
|
|
14375
|
+
displayName: result.skillPackage?.displayName,
|
|
14376
|
+
description: result.skillPackage?.description || `Skill: ${skillName}`,
|
|
14377
|
+
skillId: result.skillId,
|
|
14378
|
+
workflowId,
|
|
14379
|
+
installationId: result.installationId,
|
|
14380
|
+
triggers: result.skillPackage?.triggers,
|
|
14381
|
+
tags: result.skillPackage?.tags,
|
|
14382
|
+
version: result.installedVersion,
|
|
14383
|
+
inputSchema: result.skillPackage?.inputSchema,
|
|
14384
|
+
outputSchema: result.skillPackage?.outputSchema
|
|
14385
|
+
});
|
|
14386
|
+
const symlinkResult = createReflySkillWithSymlink(skillName, skillMdContent, {
|
|
14387
|
+
force: options.force
|
|
14388
|
+
});
|
|
14389
|
+
if (symlinkResult.success) {
|
|
14390
|
+
localPath = symlinkResult.reflyPath;
|
|
14391
|
+
symlinkPath = symlinkResult.claudePath;
|
|
14392
|
+
logger.info(`Created local skill: ${localPath}`);
|
|
14393
|
+
} else {
|
|
14394
|
+
logger.warn(`Failed to create local skill: ${symlinkResult.error}`);
|
|
14395
|
+
}
|
|
14396
|
+
} catch (err) {
|
|
14397
|
+
logger.warn(`Failed to create local skill: ${err.message}`);
|
|
14398
|
+
}
|
|
14399
|
+
}
|
|
13058
14400
|
ok("skill.install", {
|
|
13059
14401
|
installationId: result.installationId,
|
|
13060
14402
|
skillId: result.skillId,
|
|
@@ -13062,11 +14404,17 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
|
|
|
13062
14404
|
skillVersion: result.installedVersion,
|
|
13063
14405
|
status: result.status,
|
|
13064
14406
|
config: result.userConfig,
|
|
13065
|
-
installedAt: result.createdAt
|
|
14407
|
+
installedAt: result.createdAt,
|
|
14408
|
+
localPath,
|
|
14409
|
+
symlinkPath
|
|
13066
14410
|
});
|
|
13067
14411
|
} catch (error) {
|
|
13068
14412
|
if (error instanceof CLIError) {
|
|
13069
|
-
fail(error.code, error.message, {
|
|
14413
|
+
fail(error.code, error.message, {
|
|
14414
|
+
details: error.details,
|
|
14415
|
+
hint: error.hint,
|
|
14416
|
+
suggestedFix: error.suggestedFix
|
|
14417
|
+
});
|
|
13070
14418
|
return;
|
|
13071
14419
|
}
|
|
13072
14420
|
fail(
|
|
@@ -13078,18 +14426,101 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
|
|
|
13078
14426
|
|
|
13079
14427
|
// src/commands/skill/uninstall.ts
|
|
13080
14428
|
init_cjs_shims();
|
|
13081
|
-
var
|
|
14429
|
+
var fs22 = __toESM(require("fs"));
|
|
14430
|
+
var path18 = __toESM(require("path"));
|
|
14431
|
+
init_symlink();
|
|
14432
|
+
init_paths();
|
|
14433
|
+
init_logger();
|
|
14434
|
+
var skillUninstallCommand = new Command("uninstall").description("Uninstall a skill").option("--id <installationId>", "Installation ID (skpi-xxx)").option("--name <name>", "Local skill name (directory in ~/.refly/skills/)").option("--force", "Skip confirmation").option("--keep-local", "Keep local skill files and symlink").action(async (options) => {
|
|
13082
14435
|
try {
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
|
|
14436
|
+
const skillsDir = getReflySkillsDir();
|
|
14437
|
+
if (!options.id && !options.name) {
|
|
14438
|
+
fail(ErrorCodes.INVALID_INPUT, "Missing required option: --id or --name", {
|
|
14439
|
+
hint: `Usage:
|
|
14440
|
+
refly skill uninstall --name <name>
|
|
14441
|
+
refly skill uninstall --id <installationId>
|
|
14442
|
+
|
|
14443
|
+
To find your skill name:
|
|
14444
|
+
refly skill list
|
|
14445
|
+
ls ${skillsDir}/`
|
|
14446
|
+
});
|
|
14447
|
+
return;
|
|
14448
|
+
}
|
|
14449
|
+
let installationId;
|
|
14450
|
+
let skillId;
|
|
14451
|
+
let name;
|
|
14452
|
+
if (options.name) {
|
|
14453
|
+
name = options.name;
|
|
14454
|
+
const skillDir = getReflyDomainSkillDir(name);
|
|
14455
|
+
const skillMdPath = path18.join(skillDir, "SKILL.md");
|
|
14456
|
+
if (!fs22.existsSync(skillMdPath)) {
|
|
14457
|
+
fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
|
|
14458
|
+
hint: `Make sure the skill '${name}' exists in ${skillsDir}/
|
|
14459
|
+
|
|
14460
|
+
To see installed skills: refly skill list`
|
|
14461
|
+
});
|
|
14462
|
+
return;
|
|
14463
|
+
}
|
|
14464
|
+
const skillContent = fs22.readFileSync(skillMdPath, "utf-8");
|
|
14465
|
+
try {
|
|
14466
|
+
const { meta } = parseReflySkillMd(skillContent);
|
|
14467
|
+
skillId = meta.skillId;
|
|
14468
|
+
installationId = options.id || meta.installationId;
|
|
14469
|
+
} catch (parseError) {
|
|
14470
|
+
fail(
|
|
14471
|
+
ErrorCodes.INVALID_INPUT,
|
|
14472
|
+
`Failed to parse SKILL.md: ${parseError.message}`,
|
|
14473
|
+
{
|
|
14474
|
+
hint: "Make sure SKILL.md has valid frontmatter with required fields: name, description, skillId, workflowId"
|
|
14475
|
+
}
|
|
14476
|
+
);
|
|
14477
|
+
return;
|
|
14478
|
+
}
|
|
14479
|
+
} else {
|
|
14480
|
+
installationId = options.id;
|
|
14481
|
+
}
|
|
14482
|
+
if (installationId) {
|
|
14483
|
+
try {
|
|
14484
|
+
await apiRequest(`/v1/skill-installations/${installationId}`, {
|
|
14485
|
+
method: "DELETE"
|
|
14486
|
+
});
|
|
14487
|
+
} catch (error) {
|
|
14488
|
+
if (error instanceof CLIError && error.code === "NOT_FOUND") {
|
|
14489
|
+
logger.debug("Installation not found on server, proceeding with local cleanup");
|
|
14490
|
+
} else {
|
|
14491
|
+
throw error;
|
|
14492
|
+
}
|
|
14493
|
+
}
|
|
14494
|
+
}
|
|
14495
|
+
let symlinkRemoved = false;
|
|
14496
|
+
let directoryRemoved = false;
|
|
14497
|
+
if (name && !options.keepLocal) {
|
|
14498
|
+
try {
|
|
14499
|
+
const cleanup = deleteDomainSkillWithSymlink(name);
|
|
14500
|
+
symlinkRemoved = cleanup.symlinkRemoved;
|
|
14501
|
+
directoryRemoved = cleanup.directoryRemoved;
|
|
14502
|
+
logger.info(`Cleaned up local skill: ${name}`);
|
|
14503
|
+
} catch (err) {
|
|
14504
|
+
logger.warn(`Failed to clean up local skill: ${err.message}`);
|
|
14505
|
+
}
|
|
14506
|
+
}
|
|
13086
14507
|
ok("skill.uninstall", {
|
|
14508
|
+
name,
|
|
14509
|
+
skillId,
|
|
13087
14510
|
installationId,
|
|
13088
|
-
uninstalled: true
|
|
14511
|
+
uninstalled: true,
|
|
14512
|
+
localCleanup: {
|
|
14513
|
+
symlinkRemoved,
|
|
14514
|
+
directoryRemoved
|
|
14515
|
+
}
|
|
13089
14516
|
});
|
|
13090
14517
|
} catch (error) {
|
|
13091
14518
|
if (error instanceof CLIError) {
|
|
13092
|
-
fail(error.code, error.message, {
|
|
14519
|
+
fail(error.code, error.message, {
|
|
14520
|
+
details: error.details,
|
|
14521
|
+
hint: error.hint,
|
|
14522
|
+
suggestedFix: error.suggestedFix
|
|
14523
|
+
});
|
|
13093
14524
|
return;
|
|
13094
14525
|
}
|
|
13095
14526
|
fail(
|
|
@@ -13127,7 +14558,11 @@ var skillInstallationsCommand = new Command("installations").description("List i
|
|
|
13127
14558
|
});
|
|
13128
14559
|
} catch (error) {
|
|
13129
14560
|
if (error instanceof CLIError) {
|
|
13130
|
-
fail(error.code, error.message, {
|
|
14561
|
+
fail(error.code, error.message, {
|
|
14562
|
+
details: error.details,
|
|
14563
|
+
hint: error.hint,
|
|
14564
|
+
suggestedFix: error.suggestedFix
|
|
14565
|
+
});
|
|
13131
14566
|
return;
|
|
13132
14567
|
}
|
|
13133
14568
|
fail(
|
|
@@ -13142,8 +14577,114 @@ init_cjs_shims();
|
|
|
13142
14577
|
|
|
13143
14578
|
// src/skill/loader.ts
|
|
13144
14579
|
init_cjs_shims();
|
|
14580
|
+
var fs23 = __toESM(require("fs"));
|
|
14581
|
+
var path19 = __toESM(require("path"));
|
|
13145
14582
|
var import_gray_matter = __toESM(require("gray-matter"));
|
|
13146
14583
|
init_logger();
|
|
14584
|
+
|
|
14585
|
+
// src/skill/types.ts
|
|
14586
|
+
init_cjs_shims();
|
|
14587
|
+
var SKILL_NAME_REGEX = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
|
|
14588
|
+
var SKILL_NAME_MAX_LENGTH = 64;
|
|
14589
|
+
var SKILL_DESCRIPTION_MAX_LENGTH = 200;
|
|
14590
|
+
var SKILL_TRIGGERS_MIN = 1;
|
|
14591
|
+
var SKILL_TRIGGERS_MAX = 10;
|
|
14592
|
+
function isValidSkillName(name) {
|
|
14593
|
+
return typeof name === "string" && name.length >= 1 && name.length <= SKILL_NAME_MAX_LENGTH && SKILL_NAME_REGEX.test(name);
|
|
14594
|
+
}
|
|
14595
|
+
function createSkillError(code, message, options) {
|
|
14596
|
+
return {
|
|
14597
|
+
code,
|
|
14598
|
+
message,
|
|
14599
|
+
details: options?.details,
|
|
14600
|
+
suggestions: options?.suggestions
|
|
14601
|
+
};
|
|
14602
|
+
}
|
|
14603
|
+
function validateCommonSkillFields(data, issues) {
|
|
14604
|
+
if (typeof data.name !== "string") {
|
|
14605
|
+
issues.push({ path: "name", message: "Name is required", value: data.name });
|
|
14606
|
+
} else if (!isValidSkillName(data.name)) {
|
|
14607
|
+
issues.push({
|
|
14608
|
+
path: "name",
|
|
14609
|
+
message: `Name must match pattern ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$ and be 1-${SKILL_NAME_MAX_LENGTH} chars`,
|
|
14610
|
+
value: data.name
|
|
14611
|
+
});
|
|
14612
|
+
}
|
|
14613
|
+
if (typeof data.description !== "string") {
|
|
14614
|
+
issues.push({
|
|
14615
|
+
path: "description",
|
|
14616
|
+
message: "Description is required",
|
|
14617
|
+
value: data.description
|
|
14618
|
+
});
|
|
14619
|
+
} else if (data.description.length > SKILL_DESCRIPTION_MAX_LENGTH) {
|
|
14620
|
+
issues.push({
|
|
14621
|
+
path: "description",
|
|
14622
|
+
message: `Description must be <= ${SKILL_DESCRIPTION_MAX_LENGTH} chars`,
|
|
14623
|
+
value: data.description.length
|
|
14624
|
+
});
|
|
14625
|
+
}
|
|
14626
|
+
if (typeof data.workflowId !== "string" || data.workflowId.trim() === "") {
|
|
14627
|
+
issues.push({ path: "workflowId", message: "WorkflowId is required", value: data.workflowId });
|
|
14628
|
+
}
|
|
14629
|
+
validateTriggers(data.triggers, issues);
|
|
14630
|
+
}
|
|
14631
|
+
function validateTriggers(triggers, issues) {
|
|
14632
|
+
if (!Array.isArray(triggers)) {
|
|
14633
|
+
issues.push({ path: "triggers", message: "Triggers must be an array", value: triggers });
|
|
14634
|
+
return;
|
|
14635
|
+
}
|
|
14636
|
+
if (triggers.length < SKILL_TRIGGERS_MIN || triggers.length > SKILL_TRIGGERS_MAX) {
|
|
14637
|
+
issues.push({
|
|
14638
|
+
path: "triggers",
|
|
14639
|
+
message: `Triggers must have ${SKILL_TRIGGERS_MIN}-${SKILL_TRIGGERS_MAX} items`,
|
|
14640
|
+
value: triggers.length
|
|
14641
|
+
});
|
|
14642
|
+
}
|
|
14643
|
+
for (let i = 0; i < triggers.length; i++) {
|
|
14644
|
+
if (typeof triggers[i] !== "string" || triggers[i].trim() === "") {
|
|
14645
|
+
issues.push({
|
|
14646
|
+
path: `triggers[${i}]`,
|
|
14647
|
+
message: "Each trigger must be a non-empty string",
|
|
14648
|
+
value: triggers[i]
|
|
14649
|
+
});
|
|
14650
|
+
}
|
|
14651
|
+
}
|
|
14652
|
+
}
|
|
14653
|
+
function validateOptionalSkillFields(data, issues) {
|
|
14654
|
+
if (data.tags !== void 0) {
|
|
14655
|
+
if (!Array.isArray(data.tags)) {
|
|
14656
|
+
issues.push({ path: "tags", message: "Tags must be an array if provided", value: data.tags });
|
|
14657
|
+
} else {
|
|
14658
|
+
for (let i = 0; i < data.tags.length; i++) {
|
|
14659
|
+
if (typeof data.tags[i] !== "string") {
|
|
14660
|
+
issues.push({
|
|
14661
|
+
path: `tags[${i}]`,
|
|
14662
|
+
message: "Each tag must be a string",
|
|
14663
|
+
value: data.tags[i]
|
|
14664
|
+
});
|
|
14665
|
+
}
|
|
14666
|
+
}
|
|
14667
|
+
}
|
|
14668
|
+
}
|
|
14669
|
+
if (data.author !== void 0 && typeof data.author !== "string") {
|
|
14670
|
+
issues.push({
|
|
14671
|
+
path: "author",
|
|
14672
|
+
message: "Author must be a string if provided",
|
|
14673
|
+
value: data.author
|
|
14674
|
+
});
|
|
14675
|
+
}
|
|
14676
|
+
if (data.version !== void 0 && typeof data.version !== "string") {
|
|
14677
|
+
issues.push({
|
|
14678
|
+
path: "version",
|
|
14679
|
+
message: "Version must be a string if provided",
|
|
14680
|
+
value: data.version
|
|
14681
|
+
});
|
|
14682
|
+
}
|
|
14683
|
+
}
|
|
14684
|
+
|
|
14685
|
+
// src/skill/loader.ts
|
|
14686
|
+
init_paths();
|
|
14687
|
+
init_symlink();
|
|
13147
14688
|
function parseFrontmatter(content) {
|
|
13148
14689
|
try {
|
|
13149
14690
|
const result = (0, import_gray_matter.default)(content);
|
|
@@ -13185,23 +14726,6 @@ function toSkillFrontmatter(data) {
|
|
|
13185
14726
|
version: data.version
|
|
13186
14727
|
};
|
|
13187
14728
|
}
|
|
13188
|
-
function loadSkill(name) {
|
|
13189
|
-
logger.debug(`Loading skill: ${name}`);
|
|
13190
|
-
const content = readSkillFile(name);
|
|
13191
|
-
const filePath = getSkillFilePath(name);
|
|
13192
|
-
const parsed = parseFrontmatter(content);
|
|
13193
|
-
const frontmatter = toSkillFrontmatter(parsed.data);
|
|
13194
|
-
if (frontmatter.name !== name) {
|
|
13195
|
-
logger.warn(
|
|
13196
|
-
`Skill name mismatch: file path says '${name}', frontmatter says '${frontmatter.name}'`
|
|
13197
|
-
);
|
|
13198
|
-
}
|
|
13199
|
-
return {
|
|
13200
|
-
frontmatter,
|
|
13201
|
-
content: parsed.content,
|
|
13202
|
-
filePath
|
|
13203
|
-
};
|
|
13204
|
-
}
|
|
13205
14729
|
function extractSkillMetadata(content) {
|
|
13206
14730
|
try {
|
|
13207
14731
|
const parsed = parseFrontmatter(content);
|
|
@@ -13234,23 +14758,23 @@ function extractSkillMetadata(content) {
|
|
|
13234
14758
|
|
|
13235
14759
|
// src/commands/skill/validate.ts
|
|
13236
14760
|
init_paths();
|
|
13237
|
-
var
|
|
13238
|
-
var
|
|
14761
|
+
var fs24 = __toESM(require("fs"));
|
|
14762
|
+
var path20 = __toESM(require("path"));
|
|
13239
14763
|
var skillValidateCommand = new Command("validate").description("Validate local skill files").argument("[skillPath]", "Path to skill file or directory (defaults to ~/.refly/skills)").option("--fix", "Attempt to fix common issues").action(async (skillPath, _options) => {
|
|
13240
14764
|
try {
|
|
13241
14765
|
const results = [];
|
|
13242
14766
|
let targetPath;
|
|
13243
14767
|
if (skillPath) {
|
|
13244
|
-
targetPath =
|
|
14768
|
+
targetPath = path20.resolve(skillPath);
|
|
13245
14769
|
} else {
|
|
13246
14770
|
await ensureSkillsDir();
|
|
13247
14771
|
targetPath = getSkillsDir();
|
|
13248
14772
|
}
|
|
13249
|
-
if (!
|
|
14773
|
+
if (!fs24.existsSync(targetPath)) {
|
|
13250
14774
|
fail(ErrorCodes.NOT_FOUND, `Path not found: ${targetPath}`);
|
|
13251
14775
|
return;
|
|
13252
14776
|
}
|
|
13253
|
-
const stats =
|
|
14777
|
+
const stats = fs24.statSync(targetPath);
|
|
13254
14778
|
if (stats.isFile()) {
|
|
13255
14779
|
const result = validateSkillFile(targetPath);
|
|
13256
14780
|
results.push(result);
|
|
@@ -13283,7 +14807,7 @@ var skillValidateCommand = new Command("validate").description("Validate local s
|
|
|
13283
14807
|
});
|
|
13284
14808
|
function validateSkillFile(filePath) {
|
|
13285
14809
|
try {
|
|
13286
|
-
const content =
|
|
14810
|
+
const content = fs24.readFileSync(filePath, "utf-8");
|
|
13287
14811
|
const { frontmatter, issues } = extractSkillMetadata(content);
|
|
13288
14812
|
const errors = issues.map((i) => `${i.path}: ${i.message}`);
|
|
13289
14813
|
const warnings = [];
|
|
@@ -13309,9 +14833,9 @@ function validateSkillFile(filePath) {
|
|
|
13309
14833
|
}
|
|
13310
14834
|
}
|
|
13311
14835
|
function findSkillFiles(dir, files = []) {
|
|
13312
|
-
const entries =
|
|
14836
|
+
const entries = fs24.readdirSync(dir, { withFileTypes: true });
|
|
13313
14837
|
for (const entry of entries) {
|
|
13314
|
-
const fullPath =
|
|
14838
|
+
const fullPath = path20.join(dir, entry.name);
|
|
13315
14839
|
if (entry.isDirectory()) {
|
|
13316
14840
|
if (!entry.name.startsWith(".")) {
|
|
13317
14841
|
findSkillFiles(fullPath, files);
|
|
@@ -13325,85 +14849,76 @@ function findSkillFiles(dir, files = []) {
|
|
|
13325
14849
|
|
|
13326
14850
|
// src/commands/skill/sync.ts
|
|
13327
14851
|
init_cjs_shims();
|
|
13328
|
-
|
|
14852
|
+
init_symlink();
|
|
14853
|
+
init_paths();
|
|
14854
|
+
var fs25 = __toESM(require("fs"));
|
|
14855
|
+
var path21 = __toESM(require("path"));
|
|
14856
|
+
var skillSyncCommand = new Command("sync").description("Validate and repair skill symlinks").option("--dry-run", "Show issues without making changes").option("--fix", "Attempt to repair broken symlinks").option("--prune", "Remove orphan symlinks (symlinks without source directory)").action(async (options) => {
|
|
13329
14857
|
try {
|
|
13330
|
-
const
|
|
13331
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
13332
|
-
const existingLocal = new Map(
|
|
13333
|
-
registry.skills.filter((s) => s.source === "local").map((s) => [s.name, s])
|
|
13334
|
-
);
|
|
13335
|
-
const nonLocal = registry.skills.filter((s) => s.source !== "local");
|
|
13336
|
-
const skillDirs = listSkillDirectories();
|
|
14858
|
+
const symlinks = listSkillSymlinks();
|
|
13337
14859
|
const warnings = [];
|
|
13338
14860
|
const errors = [];
|
|
13339
|
-
|
|
13340
|
-
let
|
|
13341
|
-
let
|
|
13342
|
-
let
|
|
13343
|
-
|
|
13344
|
-
|
|
13345
|
-
|
|
13346
|
-
|
|
13347
|
-
|
|
13348
|
-
|
|
13349
|
-
|
|
13350
|
-
|
|
13351
|
-
|
|
13352
|
-
|
|
13353
|
-
|
|
13354
|
-
|
|
13355
|
-
|
|
13356
|
-
description: frontmatter.description,
|
|
13357
|
-
workflowId: frontmatter.workflowId,
|
|
13358
|
-
triggers: frontmatter.triggers,
|
|
13359
|
-
path: getSkillRelativePath(frontmatter.name),
|
|
13360
|
-
createdAt: prev?.createdAt ?? now,
|
|
13361
|
-
updatedAt: now,
|
|
13362
|
-
source: "local",
|
|
13363
|
-
tags: frontmatter.tags,
|
|
13364
|
-
author: frontmatter.author,
|
|
13365
|
-
version: frontmatter.version
|
|
13366
|
-
};
|
|
13367
|
-
updatedLocal.push(entry);
|
|
13368
|
-
if (!prev) {
|
|
13369
|
-
added += 1;
|
|
13370
|
-
} else if (prev.description !== entry.description || prev.workflowId !== entry.workflowId || JSON.stringify(prev.triggers) !== JSON.stringify(entry.triggers) || JSON.stringify(prev.tags ?? []) !== JSON.stringify(entry.tags ?? []) || prev.author !== entry.author || prev.version !== entry.version || prev.path !== entry.path) {
|
|
13371
|
-
updated += 1;
|
|
13372
|
-
} else {
|
|
13373
|
-
unchanged += 1;
|
|
14861
|
+
let valid = 0;
|
|
14862
|
+
let invalid = 0;
|
|
14863
|
+
let repaired = 0;
|
|
14864
|
+
let orphans = 0;
|
|
14865
|
+
for (const symlink of symlinks) {
|
|
14866
|
+
if (symlink.isValid) {
|
|
14867
|
+
valid += 1;
|
|
14868
|
+
} else {
|
|
14869
|
+
invalid += 1;
|
|
14870
|
+
warnings.push(`Invalid symlink: ${symlink.claudePath} -> ${symlink.target}`);
|
|
14871
|
+
if (options.fix && !options.dryRun) {
|
|
14872
|
+
const result = createSkillSymlink(symlink.name);
|
|
14873
|
+
if (result.success) {
|
|
14874
|
+
repaired += 1;
|
|
14875
|
+
} else {
|
|
14876
|
+
errors.push(`Failed to repair ${symlink.name}: ${result.error}`);
|
|
14877
|
+
}
|
|
13374
14878
|
}
|
|
13375
|
-
} catch (err) {
|
|
13376
|
-
errors.push(err instanceof Error ? err.message : "Failed to load skill");
|
|
13377
|
-
skipped += 1;
|
|
13378
14879
|
}
|
|
13379
14880
|
}
|
|
13380
|
-
const
|
|
13381
|
-
|
|
13382
|
-
|
|
13383
|
-
|
|
13384
|
-
|
|
14881
|
+
const skillsDir = getReflySkillsDir();
|
|
14882
|
+
if (fs25.existsSync(skillsDir)) {
|
|
14883
|
+
const entries = fs25.readdirSync(skillsDir, { withFileTypes: true });
|
|
14884
|
+
const symlinkNames = new Set(symlinks.map((s) => s.name));
|
|
14885
|
+
for (const entry of entries) {
|
|
14886
|
+
if (entry.isDirectory() && entry.name !== "base") {
|
|
14887
|
+
if (!symlinkNames.has(entry.name)) {
|
|
14888
|
+
orphans += 1;
|
|
14889
|
+
warnings.push(`Orphan directory (no symlink): ${path21.join(skillsDir, entry.name)}`);
|
|
14890
|
+
if (options.prune && !options.dryRun) {
|
|
14891
|
+
const result = createSkillSymlink(entry.name);
|
|
14892
|
+
if (result.success) {
|
|
14893
|
+
repaired += 1;
|
|
14894
|
+
}
|
|
14895
|
+
}
|
|
14896
|
+
}
|
|
14897
|
+
}
|
|
14898
|
+
}
|
|
13385
14899
|
}
|
|
13386
|
-
const
|
|
13387
|
-
|
|
13388
|
-
|
|
13389
|
-
|
|
13390
|
-
...registry,
|
|
13391
|
-
skills: finalSkills,
|
|
13392
|
-
updatedAt: now
|
|
13393
|
-
});
|
|
14900
|
+
for (const symlink of symlinks) {
|
|
14901
|
+
if (!symlink.isValid && options.prune && !options.dryRun) {
|
|
14902
|
+
removeSkillSymlink(symlink.name);
|
|
14903
|
+
}
|
|
13394
14904
|
}
|
|
13395
14905
|
const summary = {
|
|
13396
|
-
scanned:
|
|
13397
|
-
|
|
13398
|
-
|
|
13399
|
-
|
|
13400
|
-
|
|
13401
|
-
pruned,
|
|
14906
|
+
scanned: symlinks.length,
|
|
14907
|
+
valid,
|
|
14908
|
+
invalid,
|
|
14909
|
+
repaired,
|
|
14910
|
+
orphans,
|
|
13402
14911
|
warnings: warnings.length
|
|
13403
14912
|
};
|
|
13404
14913
|
ok("skill.sync", {
|
|
13405
14914
|
dryRun: Boolean(options.dryRun),
|
|
13406
14915
|
summary,
|
|
14916
|
+
symlinks: symlinks.map((s) => ({
|
|
14917
|
+
name: s.name,
|
|
14918
|
+
claudePath: s.claudePath,
|
|
14919
|
+
target: s.target,
|
|
14920
|
+
valid: s.isValid
|
|
14921
|
+
})),
|
|
13407
14922
|
warnings: warnings.length ? warnings : void 0,
|
|
13408
14923
|
errors: errors.length ? errors : void 0
|
|
13409
14924
|
});
|
|
@@ -13416,13 +14931,13 @@ var skillSyncCommand = new Command("sync").description("Sync local skill registr
|
|
|
13416
14931
|
});
|
|
13417
14932
|
|
|
13418
14933
|
// src/commands/skill/index.ts
|
|
13419
|
-
var skillCommand = new Command("skill").description("Manage skill packages and local skills").addCommand(skillListCommand).addCommand(skillGetCommand).addCommand(skillCreateCommand).addCommand(
|
|
14934
|
+
var skillCommand = new Command("skill").description("Manage skill packages and local skills").addCommand(skillListCommand).addCommand(skillGetCommand).addCommand(skillCreateCommand).addCommand(skillUpdateCommand).addCommand(skillPublishCommand).addCommand(skillUnpublishCommand).addCommand(skillSearchCommand).addCommand(skillInstallCommand).addCommand(skillUninstallCommand).addCommand(skillInstallationsCommand).addCommand(skillRunCommand).addCommand(skillStopCommand).addCommand(skillValidateCommand).addCommand(skillSyncCommand);
|
|
13420
14935
|
|
|
13421
14936
|
// src/bin/refly.ts
|
|
13422
14937
|
function getVersion() {
|
|
13423
14938
|
try {
|
|
13424
|
-
const pkgPath =
|
|
13425
|
-
const pkg = JSON.parse(
|
|
14939
|
+
const pkgPath = path22.join(__dirname, "..", "..", "package.json");
|
|
14940
|
+
const pkg = JSON.parse(fs26.readFileSync(pkgPath, "utf-8"));
|
|
13426
14941
|
return pkg.version || "0.1.0";
|
|
13427
14942
|
} catch {
|
|
13428
14943
|
return "0.1.0";
|