@powerformer/refly-cli 0.1.15 → 0.1.17
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 +1814 -803
- package/dist/bin/refly.js.map +1 -1
- package/dist/index.d.ts +32 -3
- package/dist/index.js +616 -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 path22 = 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 = path22.resolve(baseDir, baseName);
|
|
1926
|
+
if (fs27.existsSync(localBin)) return localBin;
|
|
1927
|
+
if (sourceExt.includes(path22.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 = path22.resolve(
|
|
1946
|
+
path22.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 = path22.basename(
|
|
1954
1954
|
this._scriptPath,
|
|
1955
|
-
|
|
1955
|
+
path22.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(path22.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 = path22.basename(filename, path22.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(path23) {
|
|
2821
|
+
if (path23 === void 0) return this._executableDir;
|
|
2822
|
+
this._executableDir = path23;
|
|
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,356 @@ 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) {
|
|
3396
|
+
const skillDir = getReflyDomainSkillDir(skillName);
|
|
3397
|
+
try {
|
|
3398
|
+
ensureReflySkillsDir();
|
|
3399
|
+
if (fs4.existsSync(skillDir)) {
|
|
3400
|
+
return {
|
|
3401
|
+
success: false,
|
|
3402
|
+
skillName,
|
|
3403
|
+
reflyPath: skillDir,
|
|
3404
|
+
claudePath: getClaudeSkillSymlinkPath(skillName),
|
|
3405
|
+
error: `Skill directory already exists: ${skillDir}`
|
|
3406
|
+
};
|
|
3407
|
+
}
|
|
3408
|
+
fs4.mkdirSync(skillDir, { recursive: true, mode: 493 });
|
|
3409
|
+
const skillMdPath = path4.join(skillDir, "SKILL.md");
|
|
3410
|
+
fs4.writeFileSync(skillMdPath, skillMdContent, { encoding: "utf-8", mode: 420 });
|
|
3411
|
+
logger.debug(`Created SKILL.md: ${skillMdPath}`);
|
|
3412
|
+
return createSkillSymlink(skillName);
|
|
3413
|
+
} catch (err) {
|
|
3414
|
+
return {
|
|
3415
|
+
success: false,
|
|
3416
|
+
skillName,
|
|
3417
|
+
reflyPath: skillDir,
|
|
3418
|
+
claudePath: getClaudeSkillSymlinkPath(skillName),
|
|
3419
|
+
error: err.message
|
|
3420
|
+
};
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
function deleteDomainSkillWithSymlink(skillName) {
|
|
3424
|
+
const symlinkRemoved = removeSkillSymlink(skillName);
|
|
3425
|
+
const skillDir = getReflyDomainSkillDir(skillName);
|
|
3426
|
+
let directoryRemoved = false;
|
|
3427
|
+
try {
|
|
3428
|
+
if (fs4.existsSync(skillDir)) {
|
|
3429
|
+
fs4.rmSync(skillDir, { recursive: true, force: true });
|
|
3430
|
+
directoryRemoved = true;
|
|
3431
|
+
logger.info(`Removed skill directory: ${skillDir}`);
|
|
3432
|
+
}
|
|
3433
|
+
} catch (err) {
|
|
3434
|
+
logger.error(`Failed to remove skill directory ${skillDir}:`, err);
|
|
3435
|
+
}
|
|
3436
|
+
return { symlinkRemoved, directoryRemoved };
|
|
3437
|
+
}
|
|
3438
|
+
function listSkillSymlinks() {
|
|
3439
|
+
const claudeSkillsDir = getClaudeSkillsDir();
|
|
3440
|
+
const results = [];
|
|
3441
|
+
if (!fs4.existsSync(claudeSkillsDir)) {
|
|
3442
|
+
return results;
|
|
3443
|
+
}
|
|
3444
|
+
try {
|
|
3445
|
+
const entries = fs4.readdirSync(claudeSkillsDir, { withFileTypes: true });
|
|
3446
|
+
for (const entry of entries) {
|
|
3447
|
+
const fullPath = path4.join(claudeSkillsDir, entry.name);
|
|
3448
|
+
try {
|
|
3449
|
+
const stat = fs4.lstatSync(fullPath);
|
|
3450
|
+
if (stat.isSymbolicLink()) {
|
|
3451
|
+
const target = fs4.readlinkSync(fullPath);
|
|
3452
|
+
const resolvedTarget = path4.resolve(path4.dirname(fullPath), target);
|
|
3453
|
+
const isValid2 = fs4.existsSync(resolvedTarget);
|
|
3454
|
+
results.push({
|
|
3455
|
+
name: entry.name,
|
|
3456
|
+
claudePath: fullPath,
|
|
3457
|
+
target: resolvedTarget,
|
|
3458
|
+
isValid: isValid2
|
|
3459
|
+
});
|
|
3460
|
+
}
|
|
3461
|
+
} catch {
|
|
3462
|
+
}
|
|
3463
|
+
}
|
|
3464
|
+
} catch {
|
|
3465
|
+
}
|
|
3466
|
+
return results;
|
|
3467
|
+
}
|
|
3468
|
+
function generateReflySkillMd(options) {
|
|
3469
|
+
const {
|
|
3470
|
+
name,
|
|
3471
|
+
displayName,
|
|
3472
|
+
description,
|
|
3473
|
+
skillId,
|
|
3474
|
+
workflowId,
|
|
3475
|
+
installationId,
|
|
3476
|
+
triggers = [],
|
|
3477
|
+
tags = [],
|
|
3478
|
+
version = "1.0.0",
|
|
3479
|
+
inputSchema,
|
|
3480
|
+
outputSchema
|
|
3481
|
+
} = options;
|
|
3482
|
+
const frontmatterLines = ["---", `name: ${name}`];
|
|
3483
|
+
frontmatterLines.push(`description: ${description}`);
|
|
3484
|
+
if (tags.length > 0) {
|
|
3485
|
+
frontmatterLines.push("tags:");
|
|
3486
|
+
frontmatterLines.push(...tags.map((t) => ` - ${t}`));
|
|
3487
|
+
}
|
|
3488
|
+
frontmatterLines.push(`version: ${version}`);
|
|
3489
|
+
frontmatterLines.push(`skillId: ${skillId}`);
|
|
3490
|
+
frontmatterLines.push(`workflowId: ${workflowId}`);
|
|
3491
|
+
if (installationId) {
|
|
3492
|
+
frontmatterLines.push(`installationId: ${installationId}`);
|
|
3493
|
+
}
|
|
3494
|
+
if (triggers.length > 0) {
|
|
3495
|
+
frontmatterLines.push("triggers:");
|
|
3496
|
+
frontmatterLines.push(...triggers.map((t) => ` - ${t}`));
|
|
3497
|
+
}
|
|
3498
|
+
frontmatterLines.push("---");
|
|
3499
|
+
const title = displayName || name.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
3500
|
+
const inputExample = inputSchema ? JSON.stringify(inputSchema, null, 2) : `{
|
|
3501
|
+
"query": "your input here"
|
|
3502
|
+
}`;
|
|
3503
|
+
const runCommand = installationId ? `refly skill run ${installationId} --input '${inputSchema ? JSON.stringify(inputSchema) : "{}"}'` : `refly workflow run ${workflowId} --input '${inputSchema ? JSON.stringify(inputSchema) : "{}"}'`;
|
|
3504
|
+
const outputSection = outputSchema ? `The skill returns:
|
|
3505
|
+
|
|
3506
|
+
\`\`\`json
|
|
3507
|
+
${JSON.stringify(outputSchema, null, 2)}
|
|
3508
|
+
\`\`\`` : "The skill returns the workflow execution result.";
|
|
3509
|
+
const content = `
|
|
3510
|
+
|
|
3511
|
+
# ${title}
|
|
3512
|
+
|
|
3513
|
+
${description}
|
|
3514
|
+
|
|
3515
|
+
## Usage
|
|
3516
|
+
|
|
3517
|
+
This skill is executed via Refly CLI:
|
|
3518
|
+
|
|
3519
|
+
\`\`\`bash
|
|
3520
|
+
${runCommand}
|
|
3521
|
+
\`\`\`
|
|
3522
|
+
|
|
3523
|
+
## Input
|
|
3524
|
+
|
|
3525
|
+
Provide input as JSON:
|
|
3526
|
+
|
|
3527
|
+
\`\`\`json
|
|
3528
|
+
${inputExample}
|
|
3529
|
+
\`\`\`
|
|
3530
|
+
|
|
3531
|
+
## Output
|
|
3532
|
+
|
|
3533
|
+
${outputSection}
|
|
3534
|
+
|
|
3535
|
+
## Rules
|
|
3536
|
+
|
|
3537
|
+
For workflow operations, refer to the base skill rules:
|
|
3538
|
+
- Workflow: \`~/.claude/skills/refly/rules/workflow.md\`
|
|
3539
|
+
- Node: \`~/.claude/skills/refly/rules/node.md\`
|
|
3540
|
+
- File: \`~/.claude/skills/refly/rules/file.md\`
|
|
3541
|
+
`;
|
|
3542
|
+
return frontmatterLines.join("\n") + content;
|
|
3543
|
+
}
|
|
3544
|
+
function parseReflySkillMd(content) {
|
|
3545
|
+
const frontmatterRegex = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/;
|
|
3546
|
+
const match = content.match(frontmatterRegex);
|
|
3547
|
+
if (!match) {
|
|
3548
|
+
throw new Error("Invalid SKILL.md format: missing frontmatter");
|
|
3549
|
+
}
|
|
3550
|
+
const [, frontmatterStr, body] = match;
|
|
3551
|
+
const meta = {};
|
|
3552
|
+
const lines = frontmatterStr.split("\n");
|
|
3553
|
+
let currentKey = null;
|
|
3554
|
+
let currentArray = [];
|
|
3555
|
+
for (const line of lines) {
|
|
3556
|
+
const trimmed = line.trim();
|
|
3557
|
+
if (trimmed.startsWith("- ")) {
|
|
3558
|
+
if (currentKey) {
|
|
3559
|
+
currentArray.push(trimmed.slice(2).trim());
|
|
3560
|
+
}
|
|
3561
|
+
continue;
|
|
3562
|
+
}
|
|
3563
|
+
if (currentKey && currentArray.length > 0) {
|
|
3564
|
+
meta[currentKey] = currentArray;
|
|
3565
|
+
currentArray = [];
|
|
3566
|
+
currentKey = null;
|
|
3567
|
+
}
|
|
3568
|
+
const colonIndex = trimmed.indexOf(":");
|
|
3569
|
+
if (colonIndex > 0) {
|
|
3570
|
+
const key = trimmed.slice(0, colonIndex).trim();
|
|
3571
|
+
const value = trimmed.slice(colonIndex + 1).trim();
|
|
3572
|
+
if (value === "") {
|
|
3573
|
+
currentKey = key;
|
|
3574
|
+
currentArray = [];
|
|
3575
|
+
} else {
|
|
3576
|
+
meta[key] = value;
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3580
|
+
if (currentKey && currentArray.length > 0) {
|
|
3581
|
+
meta[currentKey] = currentArray;
|
|
3582
|
+
}
|
|
3583
|
+
if (!meta.name) {
|
|
3584
|
+
throw new Error('Invalid SKILL.md: missing required field "name"');
|
|
3585
|
+
}
|
|
3586
|
+
if (!meta.description) {
|
|
3587
|
+
throw new Error('Invalid SKILL.md: missing required field "description"');
|
|
3588
|
+
}
|
|
3589
|
+
if (!meta.skillId) {
|
|
3590
|
+
throw new Error('Invalid SKILL.md: missing required field "skillId"');
|
|
3591
|
+
}
|
|
3592
|
+
if (!meta.workflowId) {
|
|
3593
|
+
throw new Error('Invalid SKILL.md: missing required field "workflowId"');
|
|
3594
|
+
}
|
|
3595
|
+
return {
|
|
3596
|
+
meta,
|
|
3597
|
+
body: body.trim(),
|
|
3598
|
+
raw: content
|
|
3599
|
+
};
|
|
3600
|
+
}
|
|
3601
|
+
var fs4, path4;
|
|
3602
|
+
var init_symlink = __esm({
|
|
3603
|
+
"src/skill/symlink.ts"() {
|
|
3604
|
+
"use strict";
|
|
3605
|
+
init_cjs_shims();
|
|
3606
|
+
fs4 = __toESM(require("fs"));
|
|
3607
|
+
path4 = __toESM(require("path"));
|
|
3608
|
+
init_paths();
|
|
3609
|
+
init_logger();
|
|
3610
|
+
}
|
|
3611
|
+
});
|
|
3612
|
+
|
|
3229
3613
|
// src/bin/refly.ts
|
|
3230
3614
|
init_cjs_shims();
|
|
3231
3615
|
|
|
@@ -4023,6 +4407,10 @@ var OutputFormatter = class {
|
|
|
4023
4407
|
if (error.code) {
|
|
4024
4408
|
console.log(UI.keyValue("Code", UI.dim(error.code)));
|
|
4025
4409
|
}
|
|
4410
|
+
if (error.recoverable !== void 0) {
|
|
4411
|
+
const recoverableText = error.recoverable ? "\u{1F504} Recoverable: Fix the parameter and retry the SAME command" : "\u274C Not recoverable: Consider a different approach";
|
|
4412
|
+
console.log(UI.dim(` ${recoverableText}`));
|
|
4413
|
+
}
|
|
4026
4414
|
if (error.details && Object.keys(error.details).length > 0) {
|
|
4027
4415
|
console.log();
|
|
4028
4416
|
console.log(UI.indent(UI.dim("Details:")));
|
|
@@ -4040,6 +4428,13 @@ var OutputFormatter = class {
|
|
|
4040
4428
|
console.log();
|
|
4041
4429
|
console.log(UI.dim(` \u{1F4A1} Hint: ${error.hint}`));
|
|
4042
4430
|
}
|
|
4431
|
+
if (error.suggestedFix && Object.keys(error.suggestedFix).length > 0) {
|
|
4432
|
+
console.log();
|
|
4433
|
+
console.log(UI.dim(" \u2705 Suggested fix:"));
|
|
4434
|
+
console.log(
|
|
4435
|
+
UI.indent(this.formatObject(error.suggestedFix, 2), 4)
|
|
4436
|
+
);
|
|
4437
|
+
}
|
|
4043
4438
|
console.log();
|
|
4044
4439
|
}
|
|
4045
4440
|
// === Workflow List Format (Phase 2: Docker-style table) ===
|
|
@@ -4265,6 +4660,9 @@ var OutputFormatter = class {
|
|
|
4265
4660
|
if (error.hint) {
|
|
4266
4661
|
console.log(UI.dim(` ${error.hint}`));
|
|
4267
4662
|
}
|
|
4663
|
+
if (error.suggestedFix) {
|
|
4664
|
+
console.log(UI.dim(` fix: ${this.formatValue(error.suggestedFix)}`));
|
|
4665
|
+
}
|
|
4268
4666
|
}
|
|
4269
4667
|
// === Plain Format ===
|
|
4270
4668
|
outputPlain(type, payload) {
|
|
@@ -4282,6 +4680,9 @@ var OutputFormatter = class {
|
|
|
4282
4680
|
if (error.hint) {
|
|
4283
4681
|
console.log(` hint: ${error.hint}`);
|
|
4284
4682
|
}
|
|
4683
|
+
if (error.suggestedFix) {
|
|
4684
|
+
console.log(` suggestedFix: ${this.formatValue(error.suggestedFix)}`);
|
|
4685
|
+
}
|
|
4285
4686
|
}
|
|
4286
4687
|
// === Helper Methods ===
|
|
4287
4688
|
humanizeType(type) {
|
|
@@ -4403,13 +4804,29 @@ function print(type, payload) {
|
|
|
4403
4804
|
const formatter = getFormatter();
|
|
4404
4805
|
formatter.success(type, payload);
|
|
4405
4806
|
}
|
|
4807
|
+
function isRecoverableError(code, hasSuggestedFix) {
|
|
4808
|
+
const recoverableCodes = [
|
|
4809
|
+
"INVALID_INPUT",
|
|
4810
|
+
"VALIDATION_ERROR",
|
|
4811
|
+
"INVALID_NODE_INPUT",
|
|
4812
|
+
"TIMEOUT",
|
|
4813
|
+
// Can retry
|
|
4814
|
+
"RATE_LIMIT"
|
|
4815
|
+
// Can retry after waiting
|
|
4816
|
+
];
|
|
4817
|
+
if (hasSuggestedFix) return true;
|
|
4818
|
+
return recoverableCodes.includes(code);
|
|
4819
|
+
}
|
|
4406
4820
|
function fail(code, message, options) {
|
|
4407
4821
|
const formatter = getFormatter();
|
|
4822
|
+
const recoverable = options?.recoverable ?? isRecoverableError(code, !!options?.suggestedFix);
|
|
4408
4823
|
formatter.error({
|
|
4409
4824
|
code,
|
|
4410
4825
|
message,
|
|
4411
4826
|
details: options?.details,
|
|
4412
|
-
hint: options?.hint
|
|
4827
|
+
hint: options?.hint,
|
|
4828
|
+
suggestedFix: options?.suggestedFix,
|
|
4829
|
+
recoverable
|
|
4413
4830
|
});
|
|
4414
4831
|
process.exit(options?.exitCode ?? getExitCode(code));
|
|
4415
4832
|
}
|
|
@@ -4419,7 +4836,8 @@ function printError(code, message, options) {
|
|
|
4419
4836
|
code,
|
|
4420
4837
|
message,
|
|
4421
4838
|
details: options?.details,
|
|
4422
|
-
hint: options?.hint
|
|
4839
|
+
hint: options?.hint,
|
|
4840
|
+
suggestedFix: options?.suggestedFix
|
|
4423
4841
|
});
|
|
4424
4842
|
}
|
|
4425
4843
|
function getExitCode(code) {
|
|
@@ -4467,8 +4885,8 @@ var ErrorCodes = {
|
|
|
4467
4885
|
};
|
|
4468
4886
|
|
|
4469
4887
|
// src/bin/refly.ts
|
|
4470
|
-
var
|
|
4471
|
-
var
|
|
4888
|
+
var fs26 = __toESM(require("fs"));
|
|
4889
|
+
var path21 = __toESM(require("path"));
|
|
4472
4890
|
|
|
4473
4891
|
// src/commands/init.ts
|
|
4474
4892
|
init_cjs_shims();
|
|
@@ -4973,8 +5391,8 @@ function getErrorMap() {
|
|
|
4973
5391
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
4974
5392
|
init_cjs_shims();
|
|
4975
5393
|
var makeIssue = (params) => {
|
|
4976
|
-
const { data, path:
|
|
4977
|
-
const fullPath = [...
|
|
5394
|
+
const { data, path: path22, errorMaps, issueData } = params;
|
|
5395
|
+
const fullPath = [...path22, ...issueData.path || []];
|
|
4978
5396
|
const fullIssue = {
|
|
4979
5397
|
...issueData,
|
|
4980
5398
|
path: fullPath
|
|
@@ -5094,11 +5512,11 @@ var errorUtil;
|
|
|
5094
5512
|
|
|
5095
5513
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
5096
5514
|
var ParseInputLazyPath = class {
|
|
5097
|
-
constructor(parent, value,
|
|
5515
|
+
constructor(parent, value, path22, key) {
|
|
5098
5516
|
this._cachedPath = [];
|
|
5099
5517
|
this.parent = parent;
|
|
5100
5518
|
this.data = value;
|
|
5101
|
-
this._path =
|
|
5519
|
+
this._path = path22;
|
|
5102
5520
|
this._key = key;
|
|
5103
5521
|
}
|
|
5104
5522
|
get path() {
|
|
@@ -8571,8 +8989,8 @@ var ConfigSchema = external_exports.object({
|
|
|
8571
8989
|
installedAt: external_exports.string().optional()
|
|
8572
8990
|
}).optional()
|
|
8573
8991
|
});
|
|
8574
|
-
var DEFAULT_API_ENDPOINT = "https://api.
|
|
8575
|
-
var DEFAULT_WEB_URL = "https://refly.
|
|
8992
|
+
var DEFAULT_API_ENDPOINT = "https://refly-api.powerformer.net";
|
|
8993
|
+
var DEFAULT_WEB_URL = "https://refly.powerformer.net";
|
|
8576
8994
|
var DEFAULT_CONFIG = {
|
|
8577
8995
|
version: 1,
|
|
8578
8996
|
api: {
|
|
@@ -8706,23 +9124,41 @@ init_paths();
|
|
|
8706
9124
|
|
|
8707
9125
|
// src/skill/installer.ts
|
|
8708
9126
|
init_cjs_shims();
|
|
8709
|
-
var
|
|
8710
|
-
var
|
|
9127
|
+
var fs5 = __toESM(require("fs"));
|
|
9128
|
+
var path5 = __toESM(require("path"));
|
|
8711
9129
|
init_paths();
|
|
8712
9130
|
init_logger();
|
|
9131
|
+
init_symlink();
|
|
9132
|
+
function removeOldSkillDirectory() {
|
|
9133
|
+
const claudeSkillPath = getClaudeSkillSymlinkPath("refly");
|
|
9134
|
+
if (!fs5.existsSync(claudeSkillPath)) {
|
|
9135
|
+
return;
|
|
9136
|
+
}
|
|
9137
|
+
try {
|
|
9138
|
+
const stat = fs5.lstatSync(claudeSkillPath);
|
|
9139
|
+
if (stat.isSymbolicLink()) {
|
|
9140
|
+
fs5.unlinkSync(claudeSkillPath);
|
|
9141
|
+
} else if (stat.isDirectory()) {
|
|
9142
|
+
fs5.rmSync(claudeSkillPath, { recursive: true, force: true });
|
|
9143
|
+
logger.info("Removed old skill directory");
|
|
9144
|
+
}
|
|
9145
|
+
} catch (err) {
|
|
9146
|
+
logger.warn("Failed to remove old directory:", err);
|
|
9147
|
+
}
|
|
9148
|
+
}
|
|
8713
9149
|
function getPackageSkillDir() {
|
|
8714
9150
|
const possiblePaths = [
|
|
8715
|
-
|
|
9151
|
+
path5.join(__dirname, "..", "..", "skill"),
|
|
8716
9152
|
// Built package: dist/bin/../../skill
|
|
8717
|
-
|
|
9153
|
+
path5.join(__dirname, "..", "..", "..", "skill"),
|
|
8718
9154
|
// Development: dist/bin/../../../skill
|
|
8719
|
-
|
|
9155
|
+
path5.join(__dirname, "..", "skill")
|
|
8720
9156
|
// Alternative: dist/../skill
|
|
8721
9157
|
];
|
|
8722
9158
|
logger.debug("Looking for skill files, __dirname:", __dirname);
|
|
8723
9159
|
for (const p of possiblePaths) {
|
|
8724
|
-
const resolved =
|
|
8725
|
-
const exists =
|
|
9160
|
+
const resolved = path5.resolve(p);
|
|
9161
|
+
const exists = fs5.existsSync(resolved);
|
|
8726
9162
|
logger.debug(` Checking path: ${resolved} - exists: ${exists}`);
|
|
8727
9163
|
if (exists) {
|
|
8728
9164
|
return resolved;
|
|
@@ -8734,42 +9170,52 @@ function installSkill() {
|
|
|
8734
9170
|
const result = {
|
|
8735
9171
|
skillInstalled: false,
|
|
8736
9172
|
skillPath: null,
|
|
9173
|
+
symlinkPath: null,
|
|
8737
9174
|
commandsInstalled: false,
|
|
8738
9175
|
commandsPath: null,
|
|
8739
9176
|
version: getSkillVersion()
|
|
8740
9177
|
};
|
|
8741
9178
|
const sourceDir = getPackageSkillDir();
|
|
8742
9179
|
logger.debug("Source skill directory:", sourceDir);
|
|
8743
|
-
|
|
9180
|
+
ensureReflySkillsDir();
|
|
9181
|
+
const targetDir = getReflyBaseSkillDir();
|
|
8744
9182
|
logger.debug("Target skill directory:", targetDir);
|
|
8745
9183
|
try {
|
|
8746
9184
|
ensureDir(targetDir);
|
|
8747
|
-
ensureDir(
|
|
9185
|
+
ensureDir(path5.join(targetDir, "rules"));
|
|
8748
9186
|
logger.debug("Created target directories");
|
|
8749
9187
|
} catch (err) {
|
|
8750
9188
|
logger.error("Failed to create target directories:", err);
|
|
8751
9189
|
throw err;
|
|
8752
9190
|
}
|
|
8753
|
-
const skillSource =
|
|
8754
|
-
const skillTarget =
|
|
9191
|
+
const skillSource = path5.join(sourceDir, "SKILL.md");
|
|
9192
|
+
const skillTarget = path5.join(targetDir, "SKILL.md");
|
|
8755
9193
|
logger.debug(`Copying SKILL.md: ${skillSource} -> ${skillTarget}`);
|
|
8756
|
-
if (
|
|
8757
|
-
|
|
9194
|
+
if (fs5.existsSync(skillSource)) {
|
|
9195
|
+
fs5.copyFileSync(skillSource, skillTarget);
|
|
8758
9196
|
result.skillInstalled = true;
|
|
8759
9197
|
result.skillPath = targetDir;
|
|
8760
9198
|
logger.debug("SKILL.md copied successfully");
|
|
8761
9199
|
} else {
|
|
8762
9200
|
logger.warn("SKILL.md source not found:", skillSource);
|
|
8763
9201
|
}
|
|
8764
|
-
const refsSource =
|
|
8765
|
-
const
|
|
8766
|
-
if (
|
|
8767
|
-
const files =
|
|
8768
|
-
logger.debug(`Copying ${files.length}
|
|
9202
|
+
const refsSource = path5.join(sourceDir, "references");
|
|
9203
|
+
const rulesTarget = path5.join(targetDir, "rules");
|
|
9204
|
+
if (fs5.existsSync(refsSource)) {
|
|
9205
|
+
const files = fs5.readdirSync(refsSource);
|
|
9206
|
+
logger.debug(`Copying ${files.length} rule files`);
|
|
8769
9207
|
for (const file of files) {
|
|
8770
|
-
|
|
9208
|
+
fs5.copyFileSync(path5.join(refsSource, file), path5.join(rulesTarget, file));
|
|
8771
9209
|
}
|
|
8772
9210
|
}
|
|
9211
|
+
removeOldSkillDirectory();
|
|
9212
|
+
const symlinkResult = createSkillSymlink("refly");
|
|
9213
|
+
if (symlinkResult.success) {
|
|
9214
|
+
result.symlinkPath = symlinkResult.claudePath;
|
|
9215
|
+
logger.info(`Created symlink: ${symlinkResult.claudePath} -> ${symlinkResult.reflyPath}`);
|
|
9216
|
+
} else {
|
|
9217
|
+
logger.warn(`Failed to create symlink: ${symlinkResult.error}`);
|
|
9218
|
+
}
|
|
8773
9219
|
const commandsDir = getClaudeCommandsDir();
|
|
8774
9220
|
logger.debug("Commands directory:", commandsDir);
|
|
8775
9221
|
ensureDir(commandsDir);
|
|
@@ -8781,20 +9227,21 @@ function installSkill() {
|
|
|
8781
9227
|
updateSkillInfo(result.version);
|
|
8782
9228
|
logger.info("Skill installation complete:", {
|
|
8783
9229
|
skillInstalled: result.skillInstalled,
|
|
9230
|
+
symlinkPath: result.symlinkPath,
|
|
8784
9231
|
commandsInstalled: result.commandsInstalled
|
|
8785
9232
|
});
|
|
8786
9233
|
return result;
|
|
8787
9234
|
}
|
|
8788
9235
|
function installSlashCommands(sourceDir, targetDir) {
|
|
8789
|
-
const commandsSource =
|
|
8790
|
-
if (!
|
|
9236
|
+
const commandsSource = path5.join(sourceDir, "..", "commands");
|
|
9237
|
+
if (!fs5.existsSync(commandsSource)) {
|
|
8791
9238
|
return false;
|
|
8792
9239
|
}
|
|
8793
9240
|
try {
|
|
8794
|
-
const files =
|
|
9241
|
+
const files = fs5.readdirSync(commandsSource);
|
|
8795
9242
|
for (const file of files) {
|
|
8796
9243
|
if (file.endsWith(".md")) {
|
|
8797
|
-
|
|
9244
|
+
fs5.copyFileSync(path5.join(commandsSource, file), path5.join(targetDir, file));
|
|
8798
9245
|
}
|
|
8799
9246
|
}
|
|
8800
9247
|
return files.length > 0;
|
|
@@ -8804,8 +9251,8 @@ function installSlashCommands(sourceDir, targetDir) {
|
|
|
8804
9251
|
}
|
|
8805
9252
|
function getSkillVersion() {
|
|
8806
9253
|
try {
|
|
8807
|
-
const skillPath =
|
|
8808
|
-
const content =
|
|
9254
|
+
const skillPath = path5.join(getPackageSkillDir(), "SKILL.md");
|
|
9255
|
+
const content = fs5.readFileSync(skillPath, "utf-8");
|
|
8809
9256
|
const versionMatch = content.match(/version:\s*(\d+\.\d+\.\d+)/);
|
|
8810
9257
|
if (versionMatch) {
|
|
8811
9258
|
return versionMatch[1];
|
|
@@ -8813,23 +9260,26 @@ function getSkillVersion() {
|
|
|
8813
9260
|
} catch {
|
|
8814
9261
|
}
|
|
8815
9262
|
try {
|
|
8816
|
-
const pkgPath =
|
|
8817
|
-
const pkg = JSON.parse(
|
|
9263
|
+
const pkgPath = path5.join(__dirname, "..", "..", "package.json");
|
|
9264
|
+
const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
|
|
8818
9265
|
return pkg.version;
|
|
8819
9266
|
} catch {
|
|
8820
9267
|
return "0.1.0";
|
|
8821
9268
|
}
|
|
8822
9269
|
}
|
|
8823
9270
|
function isSkillInstalled() {
|
|
8824
|
-
const skillPath =
|
|
8825
|
-
if (!
|
|
9271
|
+
const skillPath = path5.join(getReflyBaseSkillDir(), "SKILL.md");
|
|
9272
|
+
if (!fs5.existsSync(skillPath)) {
|
|
8826
9273
|
return { installed: false, upToDate: false };
|
|
8827
9274
|
}
|
|
8828
9275
|
const currentVersion = getSkillVersion();
|
|
9276
|
+
const { isSkillSymlinkValid: isSkillSymlinkValid2 } = (init_symlink(), __toCommonJS(symlink_exports));
|
|
9277
|
+
const symlinkStatus = isSkillSymlinkValid2("refly");
|
|
8829
9278
|
return {
|
|
8830
9279
|
installed: true,
|
|
8831
9280
|
upToDate: true,
|
|
8832
|
-
currentVersion
|
|
9281
|
+
currentVersion,
|
|
9282
|
+
symlinkValid: symlinkStatus.isValid
|
|
8833
9283
|
};
|
|
8834
9284
|
}
|
|
8835
9285
|
|
|
@@ -9314,14 +9764,14 @@ var baseOpen = async (options) => {
|
|
|
9314
9764
|
}
|
|
9315
9765
|
const subprocess = import_node_child_process5.default.spawn(command, cliArguments, childProcessOptions);
|
|
9316
9766
|
if (options.wait) {
|
|
9317
|
-
return new Promise((
|
|
9767
|
+
return new Promise((resolve7, reject) => {
|
|
9318
9768
|
subprocess.once("error", reject);
|
|
9319
9769
|
subprocess.once("close", (exitCode) => {
|
|
9320
9770
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
9321
9771
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
9322
9772
|
return;
|
|
9323
9773
|
}
|
|
9324
|
-
|
|
9774
|
+
resolve7(subprocess);
|
|
9325
9775
|
});
|
|
9326
9776
|
});
|
|
9327
9777
|
}
|
|
@@ -9397,19 +9847,20 @@ var open_default = open;
|
|
|
9397
9847
|
|
|
9398
9848
|
// src/api/client.ts
|
|
9399
9849
|
init_cjs_shims();
|
|
9400
|
-
var
|
|
9850
|
+
var fs11 = __toESM(require("fs"));
|
|
9401
9851
|
var import_node_fs4 = require("fs");
|
|
9402
|
-
var
|
|
9852
|
+
var path7 = __toESM(require("path"));
|
|
9403
9853
|
var import_mime = __toESM(require("mime"));
|
|
9404
9854
|
|
|
9405
9855
|
// src/utils/errors.ts
|
|
9406
9856
|
init_cjs_shims();
|
|
9407
9857
|
var CLIError = class extends Error {
|
|
9408
|
-
constructor(code, message, details, hint) {
|
|
9858
|
+
constructor(code, message, details, hint, suggestedFix) {
|
|
9409
9859
|
super(message);
|
|
9410
9860
|
this.code = code;
|
|
9411
9861
|
this.details = details;
|
|
9412
9862
|
this.hint = hint;
|
|
9863
|
+
this.suggestedFix = suggestedFix;
|
|
9413
9864
|
this.name = "CLIError";
|
|
9414
9865
|
}
|
|
9415
9866
|
};
|
|
@@ -9427,10 +9878,10 @@ var NetworkError = class extends CLIError {
|
|
|
9427
9878
|
// src/api/client.ts
|
|
9428
9879
|
init_logger();
|
|
9429
9880
|
var DEFAULT_TIMEOUT = 3e4;
|
|
9430
|
-
async function apiRequest(
|
|
9881
|
+
async function apiRequest(path22, options = {}) {
|
|
9431
9882
|
const { method = "GET", body, query, timeout = DEFAULT_TIMEOUT, requireAuth = true } = options;
|
|
9432
9883
|
const endpoint = getApiEndpoint();
|
|
9433
|
-
let url = `${endpoint}${
|
|
9884
|
+
let url = `${endpoint}${path22}`;
|
|
9434
9885
|
if (query && Object.keys(query).length > 0) {
|
|
9435
9886
|
const params = new URLSearchParams(query);
|
|
9436
9887
|
url = `${url}?${params.toString()}`;
|
|
@@ -9468,7 +9919,7 @@ async function apiRequest(path16, options = {}) {
|
|
|
9468
9919
|
const controller = new AbortController();
|
|
9469
9920
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
9470
9921
|
try {
|
|
9471
|
-
logger.debug(`API Request: ${method} ${
|
|
9922
|
+
logger.debug(`API Request: ${method} ${path22}`);
|
|
9472
9923
|
const response = await fetch(url, {
|
|
9473
9924
|
method,
|
|
9474
9925
|
headers,
|
|
@@ -9560,7 +10011,8 @@ function mapAPIError(status, response) {
|
|
|
9560
10011
|
cliError.code || "UNKNOWN",
|
|
9561
10012
|
cliError.message || "Unknown error",
|
|
9562
10013
|
void 0,
|
|
9563
|
-
cliError.hint
|
|
10014
|
+
cliError.hint,
|
|
10015
|
+
cliError.suggestedFix
|
|
9564
10016
|
);
|
|
9565
10017
|
}
|
|
9566
10018
|
const errCode = response.errCode ?? response.error ?? "UNKNOWN";
|
|
@@ -9582,10 +10034,10 @@ function mapAPIError(status, response) {
|
|
|
9582
10034
|
}
|
|
9583
10035
|
return new CLIError(errCode, errMsg);
|
|
9584
10036
|
}
|
|
9585
|
-
async function apiRequestStream(
|
|
10037
|
+
async function apiRequestStream(path22, options = {}) {
|
|
9586
10038
|
const { timeout = 3e5 } = options;
|
|
9587
10039
|
const endpoint = getApiEndpoint();
|
|
9588
|
-
const url = `${endpoint}${
|
|
10040
|
+
const url = `${endpoint}${path22}`;
|
|
9589
10041
|
const headers = {
|
|
9590
10042
|
"User-Agent": "refly-cli/0.1.0"
|
|
9591
10043
|
};
|
|
@@ -9616,7 +10068,7 @@ async function apiRequestStream(path16, options = {}) {
|
|
|
9616
10068
|
const controller = new AbortController();
|
|
9617
10069
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
9618
10070
|
try {
|
|
9619
|
-
logger.debug(`API Stream Request: GET ${
|
|
10071
|
+
logger.debug(`API Stream Request: GET ${path22}`);
|
|
9620
10072
|
const response = await fetch(url, {
|
|
9621
10073
|
method: "GET",
|
|
9622
10074
|
headers,
|
|
@@ -9711,7 +10163,7 @@ async function uploadToPresignedUrl(presignedUrl, filePath, contentType, retryCo
|
|
|
9711
10163
|
const controller = new AbortController();
|
|
9712
10164
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
9713
10165
|
try {
|
|
9714
|
-
const fileBuffer = await
|
|
10166
|
+
const fileBuffer = await fs11.promises.readFile(filePath);
|
|
9715
10167
|
const response = await fetch(presignedUrl, {
|
|
9716
10168
|
method: "PUT",
|
|
9717
10169
|
headers: {
|
|
@@ -9769,7 +10221,7 @@ async function apiGetWorkflow(workflowId) {
|
|
|
9769
10221
|
return apiRequest(`/v1/cli/workflow/${workflowId}`);
|
|
9770
10222
|
}
|
|
9771
10223
|
async function apiUploadDriveFile(filePath, canvasId, options) {
|
|
9772
|
-
const filename =
|
|
10224
|
+
const filename = path7.basename(filePath);
|
|
9773
10225
|
const mimeType = getMimeType(filePath);
|
|
9774
10226
|
const fileStats = (0, import_node_fs4.statSync)(filePath);
|
|
9775
10227
|
logger.debug(`Starting presigned upload: ${filename} (${fileStats.size} bytes)`);
|
|
@@ -10016,11 +10468,11 @@ async function getUserInfoFromToken(accessToken) {
|
|
|
10016
10468
|
};
|
|
10017
10469
|
}
|
|
10018
10470
|
function sleep(ms) {
|
|
10019
|
-
return new Promise((
|
|
10471
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
10020
10472
|
}
|
|
10021
10473
|
|
|
10022
10474
|
// src/commands/init.ts
|
|
10023
|
-
var DEFAULT_API_ENDPOINT2 = "https://api.
|
|
10475
|
+
var DEFAULT_API_ENDPOINT2 = "https://refly-api.powerformer.net";
|
|
10024
10476
|
var initCommand = new Command("init").description("Initialize Refly CLI, install skill files, and authenticate").option("--force", "Force reinstall even if already installed").option("--host <url>", "API server URL", DEFAULT_API_ENDPOINT2).option("--skip-login", "Skip automatic login after initialization").action(async (options) => {
|
|
10025
10477
|
try {
|
|
10026
10478
|
const { force, host, skipLogin } = options;
|
|
@@ -10083,6 +10535,7 @@ var initCommand = new Command("init").description("Initialize Refly CLI, install
|
|
|
10083
10535
|
apiEndpoint,
|
|
10084
10536
|
skillInstalled: installResult.skillInstalled,
|
|
10085
10537
|
skillPath: installResult.skillPath,
|
|
10538
|
+
symlinkPath: installResult.symlinkPath,
|
|
10086
10539
|
commandsInstalled: installResult.commandsInstalled,
|
|
10087
10540
|
commandsPath: installResult.commandsPath,
|
|
10088
10541
|
version: installResult.version
|
|
@@ -10135,7 +10588,10 @@ var initCommand = new Command("init").description("Initialize Refly CLI, install
|
|
|
10135
10588
|
configDir: getReflyDir(),
|
|
10136
10589
|
apiEndpoint,
|
|
10137
10590
|
skillInstalled: installResult.skillInstalled,
|
|
10591
|
+
skillPath: installResult.skillPath,
|
|
10592
|
+
symlinkPath: installResult.symlinkPath,
|
|
10138
10593
|
commandsInstalled: installResult.commandsInstalled,
|
|
10594
|
+
commandsPath: installResult.commandsPath,
|
|
10139
10595
|
version: installResult.version,
|
|
10140
10596
|
authenticated: !!(getAccessToken() || getApiKey())
|
|
10141
10597
|
});
|
|
@@ -10270,8 +10726,8 @@ var import_node_child_process6 = require("child_process");
|
|
|
10270
10726
|
var import_node_fs5 = __toESM(require("fs"));
|
|
10271
10727
|
init_logger();
|
|
10272
10728
|
init_paths();
|
|
10273
|
-
var CLI_VERSION = "0.1.
|
|
10274
|
-
var NPM_TAG = "
|
|
10729
|
+
var CLI_VERSION = "0.1.17";
|
|
10730
|
+
var NPM_TAG = "test";
|
|
10275
10731
|
function compareSemver(a, b) {
|
|
10276
10732
|
const parseVersion = (v) => {
|
|
10277
10733
|
const parts = v.replace(/^v/, "").split("-")[0].split(".");
|
|
@@ -10526,16 +10982,16 @@ configCommand.action(() => {
|
|
|
10526
10982
|
};
|
|
10527
10983
|
ok("config", safeConfig);
|
|
10528
10984
|
});
|
|
10529
|
-
function getNestedValue(obj,
|
|
10530
|
-
return
|
|
10985
|
+
function getNestedValue(obj, path22) {
|
|
10986
|
+
return path22.split(".").reduce((current, key) => {
|
|
10531
10987
|
if (current && typeof current === "object" && key in current) {
|
|
10532
10988
|
return current[key];
|
|
10533
10989
|
}
|
|
10534
10990
|
return void 0;
|
|
10535
10991
|
}, obj);
|
|
10536
10992
|
}
|
|
10537
|
-
function setNestedValue(obj,
|
|
10538
|
-
const keys =
|
|
10993
|
+
function setNestedValue(obj, path22, value) {
|
|
10994
|
+
const keys = path22.split(".");
|
|
10539
10995
|
const lastKey = keys.pop();
|
|
10540
10996
|
let current = obj;
|
|
10541
10997
|
for (const key of keys) {
|
|
@@ -10640,14 +11096,25 @@ var workflowCreateCommand = new Command("create").description("Create a workflow
|
|
|
10640
11096
|
spec = Array.isArray(parsed) ? { nodes: parsed } : parsed;
|
|
10641
11097
|
} catch {
|
|
10642
11098
|
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --spec", {
|
|
10643
|
-
hint: "
|
|
11099
|
+
hint: `Spec format: '[{"id": "node1", "type": "skill", "query": "task description", "toolsetKeys": ["web_search"]}]'
|
|
11100
|
+
Or full format: '{"nodes": [...], "edges": [...]}'`,
|
|
11101
|
+
suggestedFix: {
|
|
11102
|
+
field: "--spec",
|
|
11103
|
+
format: "json-array | json-object",
|
|
11104
|
+
example: '[{"id": "node1", "type": "skill", "query": "task description", "toolsetKeys": ["web_search"]}]'
|
|
11105
|
+
}
|
|
10644
11106
|
});
|
|
10645
11107
|
return;
|
|
10646
11108
|
}
|
|
10647
11109
|
const validationError = validateSimplifiedSpec(spec);
|
|
10648
11110
|
if (validationError) {
|
|
10649
11111
|
fail(ErrorCodes.INVALID_INPUT, validationError, {
|
|
10650
|
-
hint: 'Use simplified format: [{"id":"node1","type":"skill","query":"...","toolsetKeys":["tool_name"],"dependsOn":["other_node"]}]'
|
|
11112
|
+
hint: 'Use simplified format: [{"id":"node1","type":"skill","query":"...","toolsetKeys":["tool_name"],"dependsOn":["other_node"]}]',
|
|
11113
|
+
suggestedFix: {
|
|
11114
|
+
field: "--spec",
|
|
11115
|
+
format: "json-array",
|
|
11116
|
+
example: '[{"id":"node1","type":"skill","query":"...","toolsetKeys":["tool_name"],"dependsOn":["other_node"]}]'
|
|
11117
|
+
}
|
|
10651
11118
|
});
|
|
10652
11119
|
return;
|
|
10653
11120
|
}
|
|
@@ -10667,7 +11134,11 @@ var workflowCreateCommand = new Command("create").description("Create a workflow
|
|
|
10667
11134
|
});
|
|
10668
11135
|
} catch (error) {
|
|
10669
11136
|
if (error instanceof CLIError) {
|
|
10670
|
-
fail(error.code, error.message, {
|
|
11137
|
+
fail(error.code, error.message, {
|
|
11138
|
+
details: error.details,
|
|
11139
|
+
hint: error.hint,
|
|
11140
|
+
suggestedFix: error.suggestedFix
|
|
11141
|
+
});
|
|
10671
11142
|
return;
|
|
10672
11143
|
}
|
|
10673
11144
|
fail(
|
|
@@ -10729,7 +11200,13 @@ var workflowGenerateCommand = new Command("generate").description("Generate a wo
|
|
|
10729
11200
|
variables = JSON.parse(options.variables);
|
|
10730
11201
|
} catch {
|
|
10731
11202
|
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --variables", {
|
|
10732
|
-
hint: "
|
|
11203
|
+
hint: `Variables format: '[{"name": "varName", "variableType": "string", "description": "desc", "required": true}]'
|
|
11204
|
+
Variable types: "string" (text input) or "resource" (file input)`,
|
|
11205
|
+
suggestedFix: {
|
|
11206
|
+
field: "--variables",
|
|
11207
|
+
format: "json-array",
|
|
11208
|
+
example: '[{"name": "varName", "variableType": "string", "description": "desc", "required": true}]'
|
|
11209
|
+
}
|
|
10733
11210
|
});
|
|
10734
11211
|
}
|
|
10735
11212
|
}
|
|
@@ -10782,7 +11259,8 @@ var workflowGenerateCommand = new Command("generate").description("Generate a wo
|
|
|
10782
11259
|
if (error instanceof CLIError) {
|
|
10783
11260
|
fail(error.code, error.message, {
|
|
10784
11261
|
details: { ...error.details, cleanedUp: cleanupResult?.deleted },
|
|
10785
|
-
hint: error.hint
|
|
11262
|
+
hint: error.hint,
|
|
11263
|
+
suggestedFix: error.suggestedFix
|
|
10786
11264
|
});
|
|
10787
11265
|
}
|
|
10788
11266
|
fail(
|
|
@@ -10820,7 +11298,11 @@ var workflowListCommand = new Command("list").description("List all workflows").
|
|
|
10820
11298
|
});
|
|
10821
11299
|
} catch (error) {
|
|
10822
11300
|
if (error instanceof CLIError) {
|
|
10823
|
-
fail(error.code, error.message, {
|
|
11301
|
+
fail(error.code, error.message, {
|
|
11302
|
+
details: error.details,
|
|
11303
|
+
hint: error.hint,
|
|
11304
|
+
suggestedFix: error.suggestedFix
|
|
11305
|
+
});
|
|
10824
11306
|
}
|
|
10825
11307
|
fail(
|
|
10826
11308
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -10837,133 +11319,15 @@ var workflowGetCommand = new Command("get").description("Get workflow details").
|
|
|
10837
11319
|
ok("workflow.get", result);
|
|
10838
11320
|
} catch (error) {
|
|
10839
11321
|
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"
|
|
11322
|
+
fail(error.code, error.message, {
|
|
11323
|
+
details: error.details,
|
|
11324
|
+
hint: error.hint,
|
|
11325
|
+
suggestedFix: error.suggestedFix
|
|
10939
11326
|
});
|
|
10940
11327
|
}
|
|
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
11328
|
fail(
|
|
10965
11329
|
ErrorCodes.INTERNAL_ERROR,
|
|
10966
|
-
error instanceof Error ? error.message : "Failed to
|
|
11330
|
+
error instanceof Error ? error.message : "Failed to get workflow"
|
|
10967
11331
|
);
|
|
10968
11332
|
}
|
|
10969
11333
|
});
|
|
@@ -10981,7 +11345,11 @@ var workflowDeleteCommand = new Command("delete").description("Delete a workflow
|
|
|
10981
11345
|
});
|
|
10982
11346
|
} catch (error) {
|
|
10983
11347
|
if (error instanceof CLIError) {
|
|
10984
|
-
fail(error.code, error.message, {
|
|
11348
|
+
fail(error.code, error.message, {
|
|
11349
|
+
details: error.details,
|
|
11350
|
+
hint: error.hint,
|
|
11351
|
+
suggestedFix: error.suggestedFix
|
|
11352
|
+
});
|
|
10985
11353
|
}
|
|
10986
11354
|
fail(
|
|
10987
11355
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -10994,14 +11362,14 @@ var workflowDeleteCommand = new Command("delete").description("Delete a workflow
|
|
|
10994
11362
|
init_cjs_shims();
|
|
10995
11363
|
var readline2 = __toESM(require("readline/promises"));
|
|
10996
11364
|
var import_node_process8 = require("process");
|
|
10997
|
-
var
|
|
11365
|
+
var path10 = __toESM(require("path"));
|
|
10998
11366
|
|
|
10999
11367
|
// src/utils/prompt.ts
|
|
11000
11368
|
init_cjs_shims();
|
|
11001
11369
|
var readline = __toESM(require("readline/promises"));
|
|
11002
11370
|
var import_node_process7 = require("process");
|
|
11003
|
-
var
|
|
11004
|
-
var
|
|
11371
|
+
var fs13 = __toESM(require("fs"));
|
|
11372
|
+
var path8 = __toESM(require("path"));
|
|
11005
11373
|
function isInteractive() {
|
|
11006
11374
|
return process.stdin?.isTTY ?? false;
|
|
11007
11375
|
}
|
|
@@ -11025,12 +11393,12 @@ async function promptForFilePath(variableName, resourceTypes, isRequired) {
|
|
|
11025
11393
|
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
|
11026
11394
|
resolvedPath = resolvedPath.replace("~", homeDir);
|
|
11027
11395
|
}
|
|
11028
|
-
resolvedPath =
|
|
11029
|
-
if (!
|
|
11396
|
+
resolvedPath = path8.resolve(resolvedPath);
|
|
11397
|
+
if (!fs13.existsSync(resolvedPath)) {
|
|
11030
11398
|
console.log(` File not found: ${resolvedPath}`);
|
|
11031
11399
|
continue;
|
|
11032
11400
|
}
|
|
11033
|
-
const stats =
|
|
11401
|
+
const stats = fs13.statSync(resolvedPath);
|
|
11034
11402
|
if (!stats.isFile()) {
|
|
11035
11403
|
console.log(` Not a file: ${resolvedPath}`);
|
|
11036
11404
|
continue;
|
|
@@ -11044,12 +11412,12 @@ async function promptForFilePath(variableName, resourceTypes, isRequired) {
|
|
|
11044
11412
|
|
|
11045
11413
|
// src/utils/file-type.ts
|
|
11046
11414
|
init_cjs_shims();
|
|
11047
|
-
var
|
|
11415
|
+
var path9 = __toESM(require("path"));
|
|
11048
11416
|
var IMAGE_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "ico", "tiff", "tif"];
|
|
11049
11417
|
var VIDEO_EXTENSIONS = ["mp4", "webm", "mov", "avi", "mkv", "flv", "wmv", "m4v"];
|
|
11050
11418
|
var AUDIO_EXTENSIONS = ["mp3", "wav", "ogg", "flac", "m4a", "aac", "wma", "opus"];
|
|
11051
11419
|
function determineFileType(filePath, mimeType) {
|
|
11052
|
-
const ext =
|
|
11420
|
+
const ext = path9.extname(filePath).slice(1).toLowerCase();
|
|
11053
11421
|
if (IMAGE_EXTENSIONS.includes(ext)) {
|
|
11054
11422
|
return "image";
|
|
11055
11423
|
}
|
|
@@ -11104,12 +11472,12 @@ async function pollToolsStatus(workflowId, maxWaitTime = 15 * 60 * 1e3, pollInte
|
|
|
11104
11472
|
);
|
|
11105
11473
|
previousRemainingCount = remainingCount;
|
|
11106
11474
|
}
|
|
11107
|
-
await new Promise((
|
|
11475
|
+
await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
|
|
11108
11476
|
} catch (error) {
|
|
11109
11477
|
console.log(`
|
|
11110
11478
|
\u26A0\uFE0F Failed to check authorization status: ${error.message}`);
|
|
11111
11479
|
console.log("Continuing to wait...");
|
|
11112
|
-
await new Promise((
|
|
11480
|
+
await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
|
|
11113
11481
|
}
|
|
11114
11482
|
}
|
|
11115
11483
|
console.log("\n\u23F0 Timeout waiting for tool authorization.");
|
|
@@ -11149,24 +11517,57 @@ async function collectFileVariables(workflowId, existingInput, noPrompt) {
|
|
|
11149
11517
|
if (resourceVars.length === 0) {
|
|
11150
11518
|
return [];
|
|
11151
11519
|
}
|
|
11152
|
-
const
|
|
11153
|
-
const providedNames = new Set(existingInput.map((v) => v.name).filter(Boolean));
|
|
11520
|
+
const invalidFormatVars = [];
|
|
11154
11521
|
const missingVars = resourceVars.filter((v) => {
|
|
11155
|
-
|
|
11156
|
-
|
|
11157
|
-
|
|
11522
|
+
const provided = existingInput.find(
|
|
11523
|
+
(input3) => v.variableId && input3.variableId === v.variableId || v.name && input3.name === v.name
|
|
11524
|
+
);
|
|
11525
|
+
if (!provided) {
|
|
11526
|
+
return true;
|
|
11527
|
+
}
|
|
11528
|
+
const values = provided.value;
|
|
11529
|
+
if (!Array.isArray(values) || values.length === 0) {
|
|
11530
|
+
invalidFormatVars.push({
|
|
11531
|
+
name: v.name,
|
|
11532
|
+
reason: "value must be an array with at least one file"
|
|
11533
|
+
});
|
|
11534
|
+
return true;
|
|
11535
|
+
}
|
|
11536
|
+
const hasValidFileId = values.some((val) => {
|
|
11537
|
+
const fileId = val?.resource?.fileId || val?.fileId;
|
|
11538
|
+
return typeof fileId === "string" && fileId.length > 0;
|
|
11539
|
+
});
|
|
11540
|
+
if (!hasValidFileId) {
|
|
11541
|
+
invalidFormatVars.push({
|
|
11542
|
+
name: v.name,
|
|
11543
|
+
reason: "no valid fileId found in value"
|
|
11544
|
+
});
|
|
11545
|
+
return true;
|
|
11546
|
+
}
|
|
11547
|
+
return false;
|
|
11158
11548
|
});
|
|
11159
11549
|
if (missingVars.length === 0) {
|
|
11160
11550
|
return [];
|
|
11161
11551
|
}
|
|
11162
11552
|
if (noPrompt || !isInteractive()) {
|
|
11163
|
-
const
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11553
|
+
const missingNames = missingVars.map((v) => v.name);
|
|
11554
|
+
const formatIssues = invalidFormatVars.filter((f) => missingNames.includes(f.name));
|
|
11555
|
+
let message;
|
|
11556
|
+
let hint;
|
|
11557
|
+
if (formatIssues.length > 0) {
|
|
11558
|
+
const details = formatIssues.map((f) => ` - ${f.name}: ${f.reason}`).join("\n");
|
|
11559
|
+
message = `Invalid format for file variables:
|
|
11560
|
+
${details}`;
|
|
11561
|
+
hint = `For file variables, use format: '{"varName": "df-fileId"}' or '{"varName": [{"fileId": "df-xxx"}]}'`;
|
|
11562
|
+
} else {
|
|
11563
|
+
message = `Missing required file variables: ${missingNames.join(", ")}`;
|
|
11564
|
+
hint = "Provide files via --input or run interactively without --no-prompt";
|
|
11565
|
+
}
|
|
11566
|
+
throw new CLIError(ErrorCodes.INVALID_INPUT, message, void 0, hint, {
|
|
11567
|
+
field: "--input",
|
|
11568
|
+
format: "json-object",
|
|
11569
|
+
example: '{"fileVar": "df-fileId"}'
|
|
11570
|
+
});
|
|
11170
11571
|
}
|
|
11171
11572
|
console.log("");
|
|
11172
11573
|
console.log("This workflow requires file inputs:");
|
|
@@ -11180,7 +11581,7 @@ async function collectFileVariables(workflowId, existingInput, noPrompt) {
|
|
|
11180
11581
|
if (!filePath) {
|
|
11181
11582
|
continue;
|
|
11182
11583
|
}
|
|
11183
|
-
const filename =
|
|
11584
|
+
const filename = path10.basename(filePath);
|
|
11184
11585
|
process.stdout.write(` Uploading ${filename}...`);
|
|
11185
11586
|
try {
|
|
11186
11587
|
const uploadResult = await apiUploadDriveFile(filePath, workflowId);
|
|
@@ -11216,18 +11617,79 @@ async function collectFileVariables(workflowId, existingInput, noPrompt) {
|
|
|
11216
11617
|
console.log("");
|
|
11217
11618
|
return uploadedVars;
|
|
11218
11619
|
}
|
|
11219
|
-
|
|
11220
|
-
|
|
11221
|
-
|
|
11222
|
-
const
|
|
11620
|
+
function convertKeyValueToVariables(obj, workflow) {
|
|
11621
|
+
const variables = [];
|
|
11622
|
+
for (const [name, rawValue] of Object.entries(obj)) {
|
|
11623
|
+
const varDef = workflow?.variables?.find((v) => v.name === name || v.variableId === name);
|
|
11624
|
+
const isResourceVar = varDef?.variableType === "resource";
|
|
11625
|
+
const looksLikeFileId = typeof rawValue === "string" && rawValue.startsWith("df-");
|
|
11626
|
+
const looksLikeFileArray = Array.isArray(rawValue) && rawValue.length > 0 && typeof rawValue[0] === "object" && rawValue[0] !== null && ("fileId" in rawValue[0] || "type" in rawValue[0]);
|
|
11627
|
+
if (isResourceVar || looksLikeFileId || looksLikeFileArray) {
|
|
11628
|
+
let fileValues = [];
|
|
11629
|
+
if (typeof rawValue === "string") {
|
|
11630
|
+
fileValues = [
|
|
11631
|
+
{
|
|
11632
|
+
type: "resource",
|
|
11633
|
+
resource: { fileId: rawValue }
|
|
11634
|
+
}
|
|
11635
|
+
];
|
|
11636
|
+
} else if (Array.isArray(rawValue)) {
|
|
11637
|
+
fileValues = rawValue.map((item) => ({
|
|
11638
|
+
type: "resource",
|
|
11639
|
+
resource: { fileId: item.fileId || item.resource?.fileId || "" }
|
|
11640
|
+
}));
|
|
11641
|
+
}
|
|
11642
|
+
variables.push({
|
|
11643
|
+
variableId: varDef?.variableId,
|
|
11644
|
+
name,
|
|
11645
|
+
variableType: "resource",
|
|
11646
|
+
value: fileValues,
|
|
11647
|
+
required: varDef?.required
|
|
11648
|
+
});
|
|
11649
|
+
} else {
|
|
11650
|
+
let value = [];
|
|
11651
|
+
if (typeof rawValue === "string") {
|
|
11652
|
+
value = [{ type: "text", text: rawValue }];
|
|
11653
|
+
} else if (Array.isArray(rawValue)) {
|
|
11654
|
+
value = rawValue;
|
|
11655
|
+
}
|
|
11656
|
+
variables.push({
|
|
11657
|
+
variableId: varDef?.variableId,
|
|
11658
|
+
name,
|
|
11659
|
+
variableType: "string",
|
|
11660
|
+
value,
|
|
11661
|
+
required: varDef?.required
|
|
11662
|
+
});
|
|
11663
|
+
}
|
|
11664
|
+
}
|
|
11665
|
+
return variables;
|
|
11666
|
+
}
|
|
11667
|
+
async function runWorkflow(workflowId, options) {
|
|
11668
|
+
let workflow;
|
|
11669
|
+
try {
|
|
11670
|
+
workflow = await apiGetWorkflow(workflowId);
|
|
11671
|
+
} catch {
|
|
11672
|
+
}
|
|
11673
|
+
let inputVars = [];
|
|
11674
|
+
try {
|
|
11675
|
+
const parsed = JSON.parse(options?.input ?? "{}");
|
|
11223
11676
|
if (Array.isArray(parsed)) {
|
|
11224
11677
|
inputVars = parsed;
|
|
11225
11678
|
} else if (parsed.variables && Array.isArray(parsed.variables)) {
|
|
11226
11679
|
inputVars = parsed.variables;
|
|
11680
|
+
} else if (typeof parsed === "object" && parsed !== null && Object.keys(parsed).length > 0) {
|
|
11681
|
+
inputVars = convertKeyValueToVariables(parsed, workflow);
|
|
11227
11682
|
}
|
|
11228
11683
|
} catch {
|
|
11229
11684
|
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --input", {
|
|
11230
|
-
hint:
|
|
11685
|
+
hint: `Ensure the input is valid JSON. Supported formats:
|
|
11686
|
+
- Simple: '{"varName": "value", "fileVar": "df-xxx"}'
|
|
11687
|
+
- Array: '[{"name": "varName", "value": [...]}]'`,
|
|
11688
|
+
suggestedFix: {
|
|
11689
|
+
field: "--input",
|
|
11690
|
+
format: "json-object | json-array",
|
|
11691
|
+
example: '{"varName": "value", "fileVar": "df-xxx"}'
|
|
11692
|
+
}
|
|
11231
11693
|
});
|
|
11232
11694
|
return;
|
|
11233
11695
|
}
|
|
@@ -11322,7 +11784,11 @@ var workflowRunCommand = new Command("run").description("Start a workflow execut
|
|
|
11322
11784
|
await runWorkflow(workflowId, options);
|
|
11323
11785
|
} catch (error) {
|
|
11324
11786
|
if (error instanceof CLIError) {
|
|
11325
|
-
fail(error.code, error.message, {
|
|
11787
|
+
fail(error.code, error.message, {
|
|
11788
|
+
details: error.details,
|
|
11789
|
+
hint: error.hint,
|
|
11790
|
+
suggestedFix: error.suggestedFix
|
|
11791
|
+
});
|
|
11326
11792
|
}
|
|
11327
11793
|
fail(
|
|
11328
11794
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11365,7 +11831,11 @@ var workflowRunsCommand = new Command("runs").description("List workflow executi
|
|
|
11365
11831
|
});
|
|
11366
11832
|
} catch (error) {
|
|
11367
11833
|
if (error instanceof CLIError) {
|
|
11368
|
-
fail(error.code, error.message, {
|
|
11834
|
+
fail(error.code, error.message, {
|
|
11835
|
+
details: error.details,
|
|
11836
|
+
hint: error.hint,
|
|
11837
|
+
suggestedFix: error.suggestedFix
|
|
11838
|
+
});
|
|
11369
11839
|
}
|
|
11370
11840
|
fail(
|
|
11371
11841
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11387,7 +11857,11 @@ var workflowAbortCommand = new Command("abort").description("Abort a running wor
|
|
|
11387
11857
|
});
|
|
11388
11858
|
} catch (error) {
|
|
11389
11859
|
if (error instanceof CLIError) {
|
|
11390
|
-
fail(error.code, error.message, {
|
|
11860
|
+
fail(error.code, error.message, {
|
|
11861
|
+
details: error.details,
|
|
11862
|
+
hint: error.hint,
|
|
11863
|
+
suggestedFix: error.suggestedFix
|
|
11864
|
+
});
|
|
11391
11865
|
}
|
|
11392
11866
|
fail(
|
|
11393
11867
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11471,7 +11945,7 @@ var workflowStatusCommand = new Command("status").description("Get detailed work
|
|
|
11471
11945
|
});
|
|
11472
11946
|
prevStatus = status;
|
|
11473
11947
|
while (status.status === "init" || status.status === "executing") {
|
|
11474
|
-
await new Promise((
|
|
11948
|
+
await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
|
|
11475
11949
|
status = await fetchStatus();
|
|
11476
11950
|
if (options.full || hasStatusChanged(prevStatus, status)) {
|
|
11477
11951
|
if (options.full) {
|
|
@@ -11507,7 +11981,11 @@ var workflowStatusCommand = new Command("status").description("Get detailed work
|
|
|
11507
11981
|
}
|
|
11508
11982
|
} catch (error) {
|
|
11509
11983
|
if (error instanceof CLIError) {
|
|
11510
|
-
fail(error.code, error.message, {
|
|
11984
|
+
fail(error.code, error.message, {
|
|
11985
|
+
details: error.details,
|
|
11986
|
+
hint: error.hint,
|
|
11987
|
+
suggestedFix: error.suggestedFix
|
|
11988
|
+
});
|
|
11511
11989
|
}
|
|
11512
11990
|
fail(
|
|
11513
11991
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11580,7 +12058,11 @@ var workflowDetailCommand = new Command("detail").description("Get detailed work
|
|
|
11580
12058
|
});
|
|
11581
12059
|
} catch (error) {
|
|
11582
12060
|
if (error instanceof CLIError) {
|
|
11583
|
-
fail(error.code, error.message, {
|
|
12061
|
+
fail(error.code, error.message, {
|
|
12062
|
+
details: error.details,
|
|
12063
|
+
hint: error.hint,
|
|
12064
|
+
suggestedFix: error.suggestedFix
|
|
12065
|
+
});
|
|
11584
12066
|
}
|
|
11585
12067
|
fail(
|
|
11586
12068
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11632,7 +12114,11 @@ var workflowToolcallsCommand = new Command("toolcalls").description("Get all too
|
|
|
11632
12114
|
});
|
|
11633
12115
|
} catch (error) {
|
|
11634
12116
|
if (error instanceof CLIError) {
|
|
11635
|
-
fail(error.code, error.message, {
|
|
12117
|
+
fail(error.code, error.message, {
|
|
12118
|
+
details: error.details,
|
|
12119
|
+
hint: error.hint,
|
|
12120
|
+
suggestedFix: error.suggestedFix
|
|
12121
|
+
});
|
|
11636
12122
|
}
|
|
11637
12123
|
fail(
|
|
11638
12124
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11664,7 +12150,11 @@ var workflowToolsetKeysCommand = new Command("toolset-keys").description("List a
|
|
|
11664
12150
|
});
|
|
11665
12151
|
} catch (error) {
|
|
11666
12152
|
if (error instanceof CLIError) {
|
|
11667
|
-
fail(error.code, error.message, {
|
|
12153
|
+
fail(error.code, error.message, {
|
|
12154
|
+
details: error.details,
|
|
12155
|
+
hint: error.hint,
|
|
12156
|
+
suggestedFix: error.suggestedFix
|
|
12157
|
+
});
|
|
11668
12158
|
}
|
|
11669
12159
|
fail(
|
|
11670
12160
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11704,7 +12194,11 @@ var workflowLayoutCommand = new Command("layout").description("Auto-layout workf
|
|
|
11704
12194
|
});
|
|
11705
12195
|
} catch (error) {
|
|
11706
12196
|
if (error instanceof CLIError) {
|
|
11707
|
-
fail(error.code, error.message, {
|
|
12197
|
+
fail(error.code, error.message, {
|
|
12198
|
+
details: error.details,
|
|
12199
|
+
hint: error.hint,
|
|
12200
|
+
suggestedFix: error.suggestedFix
|
|
12201
|
+
});
|
|
11708
12202
|
}
|
|
11709
12203
|
fail(
|
|
11710
12204
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11751,7 +12245,11 @@ var workflowNodesCommand = new Command("nodes").description("List all nodes in a
|
|
|
11751
12245
|
ok("workflow.nodes", output3);
|
|
11752
12246
|
} catch (error) {
|
|
11753
12247
|
if (error instanceof CLIError) {
|
|
11754
|
-
fail(error.code, error.message, {
|
|
12248
|
+
fail(error.code, error.message, {
|
|
12249
|
+
details: error.details,
|
|
12250
|
+
hint: error.hint,
|
|
12251
|
+
suggestedFix: error.suggestedFix
|
|
12252
|
+
});
|
|
11755
12253
|
}
|
|
11756
12254
|
fail(
|
|
11757
12255
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11812,7 +12310,11 @@ var workflowNodeGetCommand = new Command("node").description("Get single node in
|
|
|
11812
12310
|
ok("workflow.node", output3);
|
|
11813
12311
|
} catch (error) {
|
|
11814
12312
|
if (error instanceof CLIError) {
|
|
11815
|
-
fail(error.code, error.message, {
|
|
12313
|
+
fail(error.code, error.message, {
|
|
12314
|
+
details: error.details,
|
|
12315
|
+
hint: error.hint,
|
|
12316
|
+
suggestedFix: error.suggestedFix
|
|
12317
|
+
});
|
|
11816
12318
|
}
|
|
11817
12319
|
fail(
|
|
11818
12320
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11821,6 +12323,289 @@ var workflowNodeGetCommand = new Command("node").description("Get single node in
|
|
|
11821
12323
|
}
|
|
11822
12324
|
});
|
|
11823
12325
|
|
|
12326
|
+
// src/commands/workflow/node-add.ts
|
|
12327
|
+
init_cjs_shims();
|
|
12328
|
+
var workflowNodeAddCommand = new Command("node-add").description("Add a node to a workflow").argument("<workflowId>", "Workflow ID (c-xxx)").requiredOption("--type <type>", "Node type (skillResponse, start, document, resource, memo)").option("--id <nodeId>", "Custom node ID (auto-generated if not provided)").option("--query <query>", "Query/prompt for the node").option("--title <title>", "Node title").option("--toolset-keys <keys>", 'Comma-separated toolset keys (e.g., "web_search,execute_code")').option("--position <x,y>", 'Node position as "x,y" (default: 0,0)').option("--connect-from <nodeId>", "Connect from this node (creates edge)").option("--connect-to <nodeId>", "Connect to this node (creates edge)").option("--resolve-toolset-keys", "Resolve toolset keys to full IDs").option("--auto-layout", "Enable auto-layout to prevent overlapping").action(async (workflowId, options) => {
|
|
12329
|
+
if (!workflowId.startsWith("c-")) {
|
|
12330
|
+
fail(ErrorCodes.INVALID_INPUT, `Invalid workflow ID: ${workflowId}`, {
|
|
12331
|
+
hint: 'Workflow ID should start with "c-"',
|
|
12332
|
+
suggestedFix: {
|
|
12333
|
+
field: "<workflowId>",
|
|
12334
|
+
format: "c-<id>",
|
|
12335
|
+
example: "c-123456"
|
|
12336
|
+
}
|
|
12337
|
+
});
|
|
12338
|
+
return;
|
|
12339
|
+
}
|
|
12340
|
+
const validTypes = ["skillResponse", "start", "document", "resource", "memo"];
|
|
12341
|
+
if (!validTypes.includes(options.type)) {
|
|
12342
|
+
fail(ErrorCodes.INVALID_INPUT, `Invalid node type: ${options.type}`, {
|
|
12343
|
+
hint: `Valid types: ${validTypes.join(", ")}`,
|
|
12344
|
+
suggestedFix: {
|
|
12345
|
+
field: "--type",
|
|
12346
|
+
format: "string",
|
|
12347
|
+
example: "skillResponse"
|
|
12348
|
+
}
|
|
12349
|
+
});
|
|
12350
|
+
return;
|
|
12351
|
+
}
|
|
12352
|
+
try {
|
|
12353
|
+
const nodeId = options.id || `node-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
12354
|
+
let position = { x: 0, y: 0 };
|
|
12355
|
+
if (options.position) {
|
|
12356
|
+
const parts = options.position.split(",").map((p) => Number.parseFloat(p.trim()));
|
|
12357
|
+
if (parts.length === 2 && !Number.isNaN(parts[0]) && !Number.isNaN(parts[1])) {
|
|
12358
|
+
position = { x: parts[0], y: parts[1] };
|
|
12359
|
+
}
|
|
12360
|
+
}
|
|
12361
|
+
const metadata = {};
|
|
12362
|
+
if (options.query) {
|
|
12363
|
+
metadata.query = options.query;
|
|
12364
|
+
}
|
|
12365
|
+
if (options.title) {
|
|
12366
|
+
metadata.title = options.title;
|
|
12367
|
+
}
|
|
12368
|
+
if (options.toolsetKeys) {
|
|
12369
|
+
metadata.toolsetKeys = options.toolsetKeys.split(",").map((k) => k.trim());
|
|
12370
|
+
}
|
|
12371
|
+
const node = {
|
|
12372
|
+
id: nodeId,
|
|
12373
|
+
type: options.type,
|
|
12374
|
+
position,
|
|
12375
|
+
data: {
|
|
12376
|
+
metadata
|
|
12377
|
+
}
|
|
12378
|
+
};
|
|
12379
|
+
const operations = [
|
|
12380
|
+
{
|
|
12381
|
+
type: "add_node",
|
|
12382
|
+
node
|
|
12383
|
+
}
|
|
12384
|
+
];
|
|
12385
|
+
if (options.connectFrom) {
|
|
12386
|
+
operations.push({
|
|
12387
|
+
type: "add_edge",
|
|
12388
|
+
edge: {
|
|
12389
|
+
id: `edge-${options.connectFrom}-${nodeId}`,
|
|
12390
|
+
source: options.connectFrom,
|
|
12391
|
+
target: nodeId
|
|
12392
|
+
}
|
|
12393
|
+
});
|
|
12394
|
+
}
|
|
12395
|
+
if (options.connectTo) {
|
|
12396
|
+
operations.push({
|
|
12397
|
+
type: "add_edge",
|
|
12398
|
+
edge: {
|
|
12399
|
+
id: `edge-${nodeId}-${options.connectTo}`,
|
|
12400
|
+
source: nodeId,
|
|
12401
|
+
target: options.connectTo
|
|
12402
|
+
}
|
|
12403
|
+
});
|
|
12404
|
+
}
|
|
12405
|
+
const body = { operations };
|
|
12406
|
+
const queryParams = [];
|
|
12407
|
+
if (options.resolveToolsetKeys) queryParams.push("resolveToolsetKeys=true");
|
|
12408
|
+
if (options.autoLayout) queryParams.push("autoLayout=true");
|
|
12409
|
+
const queryString = queryParams.length > 0 ? `?${queryParams.join("&")}` : "";
|
|
12410
|
+
await apiRequest(`/v1/cli/workflow/${workflowId}${queryString}`, {
|
|
12411
|
+
method: "PATCH",
|
|
12412
|
+
body
|
|
12413
|
+
});
|
|
12414
|
+
ok("workflow.node.add", {
|
|
12415
|
+
message: "Node added successfully",
|
|
12416
|
+
workflowId,
|
|
12417
|
+
nodeId,
|
|
12418
|
+
type: options.type,
|
|
12419
|
+
position,
|
|
12420
|
+
...options.query && { query: options.query },
|
|
12421
|
+
...options.toolsetKeys && {
|
|
12422
|
+
toolsetKeys: options.toolsetKeys.split(",").map((k) => k.trim())
|
|
12423
|
+
},
|
|
12424
|
+
...options.connectFrom && { connectedFrom: options.connectFrom },
|
|
12425
|
+
...options.connectTo && { connectedTo: options.connectTo },
|
|
12426
|
+
nextSteps: [
|
|
12427
|
+
`View node: \`refly workflow node ${workflowId} ${nodeId}\``,
|
|
12428
|
+
`List all nodes: \`refly workflow nodes ${workflowId}\``
|
|
12429
|
+
]
|
|
12430
|
+
});
|
|
12431
|
+
} catch (error) {
|
|
12432
|
+
if (error instanceof CLIError) {
|
|
12433
|
+
fail(error.code, error.message, {
|
|
12434
|
+
details: error.details,
|
|
12435
|
+
hint: error.hint,
|
|
12436
|
+
suggestedFix: error.suggestedFix
|
|
12437
|
+
});
|
|
12438
|
+
return;
|
|
12439
|
+
}
|
|
12440
|
+
fail(
|
|
12441
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
12442
|
+
error instanceof Error ? error.message : "Failed to add node"
|
|
12443
|
+
);
|
|
12444
|
+
}
|
|
12445
|
+
});
|
|
12446
|
+
|
|
12447
|
+
// src/commands/workflow/node-update.ts
|
|
12448
|
+
init_cjs_shims();
|
|
12449
|
+
var workflowNodeUpdateCommand = new Command("node-update").description("Update a node in a workflow").argument("<workflowId>", "Workflow ID (c-xxx)").argument("<nodeId>", "Node ID to update").option("--query <query>", "Update the query/prompt for the node").option("--title <title>", "Update the node title").option("--toolset-keys <keys>", 'Comma-separated toolset keys (e.g., "web_search,execute_code")').option("--data <json>", "Full node data as JSON (advanced usage)").option("--resolve-toolset-keys", "Resolve toolset keys to full IDs").action(async (workflowId, nodeId, options) => {
|
|
12450
|
+
if (!workflowId.startsWith("c-")) {
|
|
12451
|
+
fail(ErrorCodes.INVALID_INPUT, `Invalid workflow ID: ${workflowId}`, {
|
|
12452
|
+
hint: 'Workflow ID should start with "c-"',
|
|
12453
|
+
suggestedFix: {
|
|
12454
|
+
field: "<workflowId>",
|
|
12455
|
+
format: "c-<id>",
|
|
12456
|
+
example: "c-123456"
|
|
12457
|
+
}
|
|
12458
|
+
});
|
|
12459
|
+
return;
|
|
12460
|
+
}
|
|
12461
|
+
try {
|
|
12462
|
+
let nodeData = {};
|
|
12463
|
+
if (options.data) {
|
|
12464
|
+
try {
|
|
12465
|
+
nodeData = JSON.parse(options.data);
|
|
12466
|
+
} catch {
|
|
12467
|
+
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON in --data", {
|
|
12468
|
+
hint: `Data format: '{"data": {"metadata": {"query": "...", "toolsetKeys": ["..."]}}}'`,
|
|
12469
|
+
suggestedFix: {
|
|
12470
|
+
field: "--data",
|
|
12471
|
+
format: "json-object",
|
|
12472
|
+
example: '{"data": {"metadata": {"query": "Search for information"}}}'
|
|
12473
|
+
}
|
|
12474
|
+
});
|
|
12475
|
+
return;
|
|
12476
|
+
}
|
|
12477
|
+
}
|
|
12478
|
+
const metadataUpdates = {};
|
|
12479
|
+
if (options.query) {
|
|
12480
|
+
metadataUpdates.query = options.query;
|
|
12481
|
+
}
|
|
12482
|
+
if (options.title) {
|
|
12483
|
+
metadataUpdates.title = options.title;
|
|
12484
|
+
}
|
|
12485
|
+
if (options.toolsetKeys) {
|
|
12486
|
+
const keys = options.toolsetKeys.split(",").map((k) => k.trim());
|
|
12487
|
+
metadataUpdates.toolsetKeys = keys;
|
|
12488
|
+
}
|
|
12489
|
+
if (Object.keys(metadataUpdates).length > 0) {
|
|
12490
|
+
nodeData = {
|
|
12491
|
+
...nodeData,
|
|
12492
|
+
data: {
|
|
12493
|
+
...nodeData.data || {},
|
|
12494
|
+
metadata: {
|
|
12495
|
+
...nodeData.data?.metadata || {},
|
|
12496
|
+
...metadataUpdates
|
|
12497
|
+
}
|
|
12498
|
+
}
|
|
12499
|
+
};
|
|
12500
|
+
}
|
|
12501
|
+
if (Object.keys(nodeData).length === 0) {
|
|
12502
|
+
fail(ErrorCodes.INVALID_INPUT, "No update provided", {
|
|
12503
|
+
hint: "Use --query, --title, --toolset-keys, or --data to specify what to update",
|
|
12504
|
+
suggestedFix: {
|
|
12505
|
+
field: "--query",
|
|
12506
|
+
format: "string",
|
|
12507
|
+
example: '--query "Search for the latest news"'
|
|
12508
|
+
}
|
|
12509
|
+
});
|
|
12510
|
+
return;
|
|
12511
|
+
}
|
|
12512
|
+
const body = {
|
|
12513
|
+
operations: [
|
|
12514
|
+
{
|
|
12515
|
+
type: "update_node",
|
|
12516
|
+
nodeId,
|
|
12517
|
+
data: nodeData
|
|
12518
|
+
}
|
|
12519
|
+
]
|
|
12520
|
+
};
|
|
12521
|
+
const queryParams = options.resolveToolsetKeys ? "?resolveToolsetKeys=true" : "";
|
|
12522
|
+
await apiRequest(`/v1/cli/workflow/${workflowId}${queryParams}`, {
|
|
12523
|
+
method: "PATCH",
|
|
12524
|
+
body
|
|
12525
|
+
});
|
|
12526
|
+
ok("workflow.node.update", {
|
|
12527
|
+
message: "Node updated successfully",
|
|
12528
|
+
workflowId,
|
|
12529
|
+
nodeId,
|
|
12530
|
+
updates: {
|
|
12531
|
+
...options.query && { query: options.query },
|
|
12532
|
+
...options.title && { title: options.title },
|
|
12533
|
+
...options.toolsetKeys && {
|
|
12534
|
+
toolsetKeys: options.toolsetKeys.split(",").map((k) => k.trim())
|
|
12535
|
+
},
|
|
12536
|
+
...options.data && { data: "custom data applied" }
|
|
12537
|
+
},
|
|
12538
|
+
nextSteps: [
|
|
12539
|
+
`View updated node: \`refly workflow node ${workflowId} ${nodeId}\``,
|
|
12540
|
+
`List all nodes: \`refly workflow nodes ${workflowId}\``
|
|
12541
|
+
]
|
|
12542
|
+
});
|
|
12543
|
+
} catch (error) {
|
|
12544
|
+
if (error instanceof CLIError) {
|
|
12545
|
+
fail(error.code, error.message, {
|
|
12546
|
+
details: error.details,
|
|
12547
|
+
hint: error.hint,
|
|
12548
|
+
suggestedFix: error.suggestedFix
|
|
12549
|
+
});
|
|
12550
|
+
return;
|
|
12551
|
+
}
|
|
12552
|
+
fail(
|
|
12553
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
12554
|
+
error instanceof Error ? error.message : "Failed to update node"
|
|
12555
|
+
);
|
|
12556
|
+
}
|
|
12557
|
+
});
|
|
12558
|
+
|
|
12559
|
+
// src/commands/workflow/node-delete.ts
|
|
12560
|
+
init_cjs_shims();
|
|
12561
|
+
var workflowNodeDeleteCommand = new Command("node-delete").description("Delete a node from a workflow").argument("<workflowId>", "Workflow ID (c-xxx)").argument("<nodeId>", "Node ID to delete").action(async (workflowId, nodeId) => {
|
|
12562
|
+
if (!workflowId.startsWith("c-")) {
|
|
12563
|
+
fail(ErrorCodes.INVALID_INPUT, `Invalid workflow ID: ${workflowId}`, {
|
|
12564
|
+
hint: 'Workflow ID should start with "c-"',
|
|
12565
|
+
suggestedFix: {
|
|
12566
|
+
field: "<workflowId>",
|
|
12567
|
+
format: "c-<id>",
|
|
12568
|
+
example: "c-123456"
|
|
12569
|
+
}
|
|
12570
|
+
});
|
|
12571
|
+
return;
|
|
12572
|
+
}
|
|
12573
|
+
try {
|
|
12574
|
+
const body = {
|
|
12575
|
+
operations: [
|
|
12576
|
+
{
|
|
12577
|
+
type: "remove_node",
|
|
12578
|
+
nodeId
|
|
12579
|
+
}
|
|
12580
|
+
]
|
|
12581
|
+
};
|
|
12582
|
+
await apiRequest(`/v1/cli/workflow/${workflowId}`, {
|
|
12583
|
+
method: "PATCH",
|
|
12584
|
+
body
|
|
12585
|
+
});
|
|
12586
|
+
ok("workflow.node.delete", {
|
|
12587
|
+
message: "Node deleted successfully",
|
|
12588
|
+
workflowId,
|
|
12589
|
+
nodeId,
|
|
12590
|
+
note: "Connected edges were also removed",
|
|
12591
|
+
nextSteps: [`List remaining nodes: \`refly workflow nodes ${workflowId}\``]
|
|
12592
|
+
});
|
|
12593
|
+
} catch (error) {
|
|
12594
|
+
if (error instanceof CLIError) {
|
|
12595
|
+
fail(error.code, error.message, {
|
|
12596
|
+
details: error.details,
|
|
12597
|
+
hint: error.hint,
|
|
12598
|
+
suggestedFix: error.suggestedFix
|
|
12599
|
+
});
|
|
12600
|
+
return;
|
|
12601
|
+
}
|
|
12602
|
+
fail(
|
|
12603
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
12604
|
+
error instanceof Error ? error.message : "Failed to delete node"
|
|
12605
|
+
);
|
|
12606
|
+
}
|
|
12607
|
+
});
|
|
12608
|
+
|
|
11824
12609
|
// src/commands/workflow/node-output.ts
|
|
11825
12610
|
init_cjs_shims();
|
|
11826
12611
|
var workflowNodeOutputCommand = new Command("node-output").description("Get node execution output content").argument("<id>", "Workflow ID (c-xxx) or Run ID (we-xxx)").argument("<nodeId>", "Node ID").option("--include-tool-calls", "Include tool call details in output").option("--raw", "Output raw content without formatting").action(async (id, nodeId, options) => {
|
|
@@ -11856,7 +12641,11 @@ var workflowNodeOutputCommand = new Command("node-output").description("Get node
|
|
|
11856
12641
|
});
|
|
11857
12642
|
} catch (error) {
|
|
11858
12643
|
if (error instanceof CLIError) {
|
|
11859
|
-
fail(error.code, error.message, {
|
|
12644
|
+
fail(error.code, error.message, {
|
|
12645
|
+
details: error.details,
|
|
12646
|
+
hint: error.hint,
|
|
12647
|
+
suggestedFix: error.suggestedFix
|
|
12648
|
+
});
|
|
11860
12649
|
}
|
|
11861
12650
|
fail(
|
|
11862
12651
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -11868,30 +12657,51 @@ var workflowNodeOutputCommand = new Command("node-output").description("Get node
|
|
|
11868
12657
|
}
|
|
11869
12658
|
});
|
|
11870
12659
|
|
|
11871
|
-
// src/commands/workflow/
|
|
12660
|
+
// src/commands/workflow/edit.ts
|
|
11872
12661
|
init_cjs_shims();
|
|
11873
|
-
var
|
|
11874
|
-
var
|
|
12662
|
+
var fs14 = __toESM(require("fs"));
|
|
12663
|
+
var workflowEditCommand = new Command("edit").description("Edit a workflow plan using semantic operations").argument("<planId>", "Workflow Plan ID").option("--ops <json>", "Operations array as JSON").option("--ops-file <path>", "Read operations from file").option("--update-title <title>", "Shortcut: update workflow title").option("--delete-task <taskId>", "Shortcut: delete a task").option("--delete-variable <variableId>", "Shortcut: delete a variable").action(async (planId, options) => {
|
|
11875
12664
|
try {
|
|
11876
12665
|
const operations = [];
|
|
12666
|
+
const opsFormatHint = `Operations format: '[{"op": "updateTitle", "title": "New Title"}]'
|
|
12667
|
+
Available ops: updateTitle, createTask, updateTask, deleteTask, createVariable, updateVariable, deleteVariable
|
|
12668
|
+
Examples:
|
|
12669
|
+
- Update title: {"op": "updateTitle", "title": "New Title"}
|
|
12670
|
+
- Delete task: {"op": "deleteTask", "taskId": "task-id"}
|
|
12671
|
+
- Update task: {"op": "updateTask", "taskId": "task-id", "data": {"prompt": "new prompt"}}`;
|
|
11877
12672
|
if (options.opsFile) {
|
|
11878
12673
|
try {
|
|
11879
12674
|
const filePath = options.opsFile;
|
|
11880
|
-
if (!
|
|
12675
|
+
if (!fs14.existsSync(filePath)) {
|
|
11881
12676
|
fail(ErrorCodes.NOT_FOUND, `Operations file not found: ${filePath}`);
|
|
11882
12677
|
}
|
|
11883
|
-
const fileContent =
|
|
12678
|
+
const fileContent = fs14.readFileSync(filePath, "utf-8");
|
|
11884
12679
|
const fileOps = JSON.parse(fileContent);
|
|
11885
12680
|
if (Array.isArray(fileOps)) {
|
|
11886
12681
|
operations.push(...fileOps);
|
|
11887
12682
|
} else {
|
|
11888
|
-
fail(ErrorCodes.INVALID_INPUT, "Operations file must contain a JSON array"
|
|
12683
|
+
fail(ErrorCodes.INVALID_INPUT, "Operations file must contain a JSON array", {
|
|
12684
|
+
hint: opsFormatHint,
|
|
12685
|
+
suggestedFix: {
|
|
12686
|
+
field: "--ops-file",
|
|
12687
|
+
format: "json-array",
|
|
12688
|
+
example: '[{"op": "updateTitle", "title": "New Title"}]'
|
|
12689
|
+
}
|
|
12690
|
+
});
|
|
11889
12691
|
}
|
|
11890
12692
|
} catch (error) {
|
|
11891
12693
|
if (error instanceof CLIError) throw error;
|
|
11892
12694
|
fail(
|
|
11893
12695
|
ErrorCodes.INVALID_INPUT,
|
|
11894
|
-
`Failed to parse operations file: ${error.message}
|
|
12696
|
+
`Failed to parse operations file: ${error.message}`,
|
|
12697
|
+
{
|
|
12698
|
+
hint: opsFormatHint,
|
|
12699
|
+
suggestedFix: {
|
|
12700
|
+
field: "--ops-file",
|
|
12701
|
+
format: "json-array",
|
|
12702
|
+
example: '[{"op": "updateTitle", "title": "New Title"}]'
|
|
12703
|
+
}
|
|
12704
|
+
}
|
|
11895
12705
|
);
|
|
11896
12706
|
}
|
|
11897
12707
|
}
|
|
@@ -11901,11 +12711,23 @@ var workflowPatchCommand = new Command("patch").description("Apply semantic patc
|
|
|
11901
12711
|
if (Array.isArray(jsonOps)) {
|
|
11902
12712
|
operations.push(...jsonOps);
|
|
11903
12713
|
} else {
|
|
11904
|
-
fail(ErrorCodes.INVALID_INPUT, "--ops must be a JSON array"
|
|
12714
|
+
fail(ErrorCodes.INVALID_INPUT, "--ops must be a JSON array", {
|
|
12715
|
+
hint: opsFormatHint,
|
|
12716
|
+
suggestedFix: {
|
|
12717
|
+
field: "--ops",
|
|
12718
|
+
format: "json-array",
|
|
12719
|
+
example: '[{"op": "updateTitle", "title": "New Title"}]'
|
|
12720
|
+
}
|
|
12721
|
+
});
|
|
11905
12722
|
}
|
|
11906
12723
|
} catch (error) {
|
|
11907
12724
|
fail(ErrorCodes.INVALID_INPUT, `Invalid JSON in --ops: ${error.message}`, {
|
|
11908
|
-
hint:
|
|
12725
|
+
hint: opsFormatHint,
|
|
12726
|
+
suggestedFix: {
|
|
12727
|
+
field: "--ops",
|
|
12728
|
+
format: "json-array",
|
|
12729
|
+
example: '[{"op": "updateTitle", "title": "New Title"}]'
|
|
12730
|
+
}
|
|
11909
12731
|
});
|
|
11910
12732
|
}
|
|
11911
12733
|
}
|
|
@@ -11929,7 +12751,12 @@ var workflowPatchCommand = new Command("patch").description("Apply semantic patc
|
|
|
11929
12751
|
}
|
|
11930
12752
|
if (operations.length === 0) {
|
|
11931
12753
|
fail(ErrorCodes.INVALID_INPUT, "No operations provided", {
|
|
11932
|
-
hint: "Use --ops, --ops-file, or shortcut options (--update-title, --delete-task, --delete-variable)"
|
|
12754
|
+
hint: "Use --ops, --ops-file, or shortcut options (--update-title, --delete-task, --delete-variable)",
|
|
12755
|
+
suggestedFix: {
|
|
12756
|
+
field: "--ops",
|
|
12757
|
+
format: "json-array",
|
|
12758
|
+
example: '[{"op": "updateTitle", "title": "New Title"}]'
|
|
12759
|
+
}
|
|
11933
12760
|
});
|
|
11934
12761
|
}
|
|
11935
12762
|
const body = {
|
|
@@ -11941,7 +12768,7 @@ var workflowPatchCommand = new Command("patch").description("Apply semantic patc
|
|
|
11941
12768
|
body
|
|
11942
12769
|
});
|
|
11943
12770
|
const plan = response.data ?? response;
|
|
11944
|
-
ok("workflow.
|
|
12771
|
+
ok("workflow.edit", {
|
|
11945
12772
|
planId,
|
|
11946
12773
|
operationsApplied: operations.length,
|
|
11947
12774
|
plan: {
|
|
@@ -11960,18 +12787,22 @@ var workflowPatchCommand = new Command("patch").description("Apply semantic patc
|
|
|
11960
12787
|
});
|
|
11961
12788
|
} catch (error) {
|
|
11962
12789
|
if (error instanceof CLIError) {
|
|
11963
|
-
fail(error.code, error.message, {
|
|
12790
|
+
fail(error.code, error.message, {
|
|
12791
|
+
details: error.details,
|
|
12792
|
+
hint: error.hint,
|
|
12793
|
+
suggestedFix: error.suggestedFix
|
|
12794
|
+
});
|
|
11964
12795
|
return;
|
|
11965
12796
|
}
|
|
11966
12797
|
fail(
|
|
11967
12798
|
ErrorCodes.INTERNAL_ERROR,
|
|
11968
|
-
error instanceof Error ? error.message : "Failed to
|
|
12799
|
+
error instanceof Error ? error.message : "Failed to edit workflow plan"
|
|
11969
12800
|
);
|
|
11970
12801
|
}
|
|
11971
12802
|
});
|
|
11972
12803
|
|
|
11973
12804
|
// 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(
|
|
12805
|
+
var workflowCommand = new Command("workflow").description("Manage and run workflows").addCommand(workflowCreateCommand).addCommand(workflowGenerateCommand).addCommand(workflowListCommand).addCommand(workflowGetCommand).addCommand(workflowDeleteCommand).addCommand(workflowRunCommand).addCommand(workflowRunsCommand).addCommand(workflowStatusCommand).addCommand(workflowDetailCommand).addCommand(workflowToolcallsCommand).addCommand(workflowAbortCommand).addCommand(workflowToolsetKeysCommand).addCommand(workflowLayoutCommand).addCommand(workflowNodesCommand).addCommand(workflowNodeGetCommand).addCommand(workflowNodeAddCommand).addCommand(workflowNodeUpdateCommand).addCommand(workflowNodeDeleteCommand).addCommand(workflowNodeOutputCommand).addCommand(workflowEditCommand);
|
|
11975
12806
|
|
|
11976
12807
|
// src/commands/tool/index.ts
|
|
11977
12808
|
init_cjs_shims();
|
|
@@ -12003,7 +12834,11 @@ var toolCallsCommand = new Command("calls").description("Get tool execution resu
|
|
|
12003
12834
|
});
|
|
12004
12835
|
} catch (error) {
|
|
12005
12836
|
if (error instanceof CLIError) {
|
|
12006
|
-
fail(error.code, error.message, {
|
|
12837
|
+
fail(error.code, error.message, {
|
|
12838
|
+
details: error.details,
|
|
12839
|
+
hint: error.hint,
|
|
12840
|
+
suggestedFix: error.suggestedFix
|
|
12841
|
+
});
|
|
12007
12842
|
}
|
|
12008
12843
|
fail(
|
|
12009
12844
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -12048,7 +12883,11 @@ var toolGetCommand = new Command("get").description("Get full details for a sing
|
|
|
12048
12883
|
});
|
|
12049
12884
|
} catch (error) {
|
|
12050
12885
|
if (error instanceof CLIError) {
|
|
12051
|
-
fail(error.code, error.message, {
|
|
12886
|
+
fail(error.code, error.message, {
|
|
12887
|
+
details: error.details,
|
|
12888
|
+
hint: error.hint,
|
|
12889
|
+
suggestedFix: error.suggestedFix
|
|
12890
|
+
});
|
|
12052
12891
|
}
|
|
12053
12892
|
fail(
|
|
12054
12893
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -12096,7 +12935,11 @@ var fileListCommand = new Command("list").description("List files").option("--pa
|
|
|
12096
12935
|
});
|
|
12097
12936
|
} catch (error) {
|
|
12098
12937
|
if (error instanceof CLIError) {
|
|
12099
|
-
fail(error.code, error.message, {
|
|
12938
|
+
fail(error.code, error.message, {
|
|
12939
|
+
details: error.details,
|
|
12940
|
+
hint: error.hint,
|
|
12941
|
+
suggestedFix: error.suggestedFix
|
|
12942
|
+
});
|
|
12100
12943
|
}
|
|
12101
12944
|
fail(
|
|
12102
12945
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -12124,7 +12967,11 @@ var fileGetCommand = new Command("get").description("Get file details").argument
|
|
|
12124
12967
|
});
|
|
12125
12968
|
} catch (error) {
|
|
12126
12969
|
if (error instanceof CLIError) {
|
|
12127
|
-
fail(error.code, error.message, {
|
|
12970
|
+
fail(error.code, error.message, {
|
|
12971
|
+
details: error.details,
|
|
12972
|
+
hint: error.hint,
|
|
12973
|
+
suggestedFix: error.suggestedFix
|
|
12974
|
+
});
|
|
12128
12975
|
}
|
|
12129
12976
|
fail(
|
|
12130
12977
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -12135,16 +12982,16 @@ var fileGetCommand = new Command("get").description("Get file details").argument
|
|
|
12135
12982
|
|
|
12136
12983
|
// src/commands/file/download.ts
|
|
12137
12984
|
init_cjs_shims();
|
|
12138
|
-
var
|
|
12139
|
-
var
|
|
12985
|
+
var fs15 = __toESM(require("fs"));
|
|
12986
|
+
var path11 = __toESM(require("path"));
|
|
12140
12987
|
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
12988
|
try {
|
|
12142
12989
|
const { data, filename, contentType, size } = await apiRequestStream(
|
|
12143
12990
|
`/v1/cli/drive/files/${fileId}/download`
|
|
12144
12991
|
);
|
|
12145
12992
|
const outputPath = options.output || filename || `${fileId}`;
|
|
12146
|
-
const resolvedPath =
|
|
12147
|
-
|
|
12993
|
+
const resolvedPath = path11.resolve(outputPath);
|
|
12994
|
+
fs15.writeFileSync(resolvedPath, data);
|
|
12148
12995
|
ok("file.download", {
|
|
12149
12996
|
fileId,
|
|
12150
12997
|
path: resolvedPath,
|
|
@@ -12154,7 +13001,11 @@ var fileDownloadCommand = new Command("download").description("Download file to
|
|
|
12154
13001
|
});
|
|
12155
13002
|
} catch (error) {
|
|
12156
13003
|
if (error instanceof CLIError) {
|
|
12157
|
-
fail(error.code, error.message, {
|
|
13004
|
+
fail(error.code, error.message, {
|
|
13005
|
+
details: error.details,
|
|
13006
|
+
hint: error.hint,
|
|
13007
|
+
suggestedFix: error.suggestedFix
|
|
13008
|
+
});
|
|
12158
13009
|
}
|
|
12159
13010
|
fail(
|
|
12160
13011
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -12165,8 +13016,8 @@ var fileDownloadCommand = new Command("download").description("Download file to
|
|
|
12165
13016
|
|
|
12166
13017
|
// src/commands/file/upload.ts
|
|
12167
13018
|
init_cjs_shims();
|
|
12168
|
-
var
|
|
12169
|
-
var
|
|
13019
|
+
var fs16 = __toESM(require("fs"));
|
|
13020
|
+
var path12 = __toESM(require("path"));
|
|
12170
13021
|
var MAX_FILES = 10;
|
|
12171
13022
|
function formatSize(bytes) {
|
|
12172
13023
|
if (bytes < 1024) return `${bytes}B`;
|
|
@@ -12176,8 +13027,8 @@ function formatSize(bytes) {
|
|
|
12176
13027
|
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
13028
|
const formatter = getFormatter();
|
|
12178
13029
|
try {
|
|
12179
|
-
const resolvedPath =
|
|
12180
|
-
if (!
|
|
13030
|
+
const resolvedPath = path12.resolve(inputPath);
|
|
13031
|
+
if (!fs16.existsSync(resolvedPath)) {
|
|
12181
13032
|
fail(ErrorCodes.NOT_FOUND, `Path not found: ${inputPath}`, {
|
|
12182
13033
|
hint: "Check if the file or directory exists"
|
|
12183
13034
|
});
|
|
@@ -12195,8 +13046,8 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
|
|
|
12195
13046
|
const errors = [];
|
|
12196
13047
|
for (let i = 0; i < files.length; i++) {
|
|
12197
13048
|
const filePath = files[i];
|
|
12198
|
-
const filename =
|
|
12199
|
-
const fileStats =
|
|
13049
|
+
const filename = path12.basename(filePath);
|
|
13050
|
+
const fileStats = fs16.statSync(filePath);
|
|
12200
13051
|
const sizeStr = formatSize(fileStats.size);
|
|
12201
13052
|
let currentStage = "presign";
|
|
12202
13053
|
const updateProgress = () => {
|
|
@@ -12264,7 +13115,11 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
|
|
|
12264
13115
|
});
|
|
12265
13116
|
} catch (error) {
|
|
12266
13117
|
if (error instanceof CLIError) {
|
|
12267
|
-
fail(error.code, error.message, {
|
|
13118
|
+
fail(error.code, error.message, {
|
|
13119
|
+
details: error.details,
|
|
13120
|
+
hint: error.hint,
|
|
13121
|
+
suggestedFix: error.suggestedFix
|
|
13122
|
+
});
|
|
12268
13123
|
}
|
|
12269
13124
|
fail(
|
|
12270
13125
|
ErrorCodes.INTERNAL_ERROR,
|
|
@@ -12273,11 +13128,11 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
|
|
|
12273
13128
|
}
|
|
12274
13129
|
});
|
|
12275
13130
|
function resolveFilesToUpload(inputPath, filter) {
|
|
12276
|
-
const stats =
|
|
13131
|
+
const stats = fs16.statSync(inputPath);
|
|
12277
13132
|
if (stats.isFile()) {
|
|
12278
13133
|
if (filter) {
|
|
12279
13134
|
const filterExts = filter.split(",").map((e) => e.trim().toLowerCase());
|
|
12280
|
-
const ext =
|
|
13135
|
+
const ext = path12.extname(inputPath).slice(1).toLowerCase();
|
|
12281
13136
|
if (!filterExts.includes(ext)) {
|
|
12282
13137
|
return [];
|
|
12283
13138
|
}
|
|
@@ -12285,21 +13140,21 @@ function resolveFilesToUpload(inputPath, filter) {
|
|
|
12285
13140
|
return [inputPath];
|
|
12286
13141
|
}
|
|
12287
13142
|
if (stats.isDirectory()) {
|
|
12288
|
-
const entries =
|
|
13143
|
+
const entries = fs16.readdirSync(inputPath);
|
|
12289
13144
|
const filterExts = filter?.split(",").map((e) => e.trim().toLowerCase());
|
|
12290
|
-
const files = entries.map((e) =>
|
|
13145
|
+
const files = entries.map((e) => path12.join(inputPath, e)).filter((p) => {
|
|
12291
13146
|
try {
|
|
12292
|
-
return
|
|
13147
|
+
return fs16.statSync(p).isFile();
|
|
12293
13148
|
} catch {
|
|
12294
13149
|
return false;
|
|
12295
13150
|
}
|
|
12296
13151
|
}).filter((p) => {
|
|
12297
13152
|
if (!filterExts) return true;
|
|
12298
|
-
const ext =
|
|
13153
|
+
const ext = path12.extname(p).slice(1).toLowerCase();
|
|
12299
13154
|
return filterExts.includes(ext);
|
|
12300
13155
|
}).sort((a, b) => {
|
|
12301
13156
|
try {
|
|
12302
|
-
return
|
|
13157
|
+
return fs16.statSync(a).size - fs16.statSync(b).size;
|
|
12303
13158
|
} catch {
|
|
12304
13159
|
return 0;
|
|
12305
13160
|
}
|
|
@@ -12344,7 +13199,11 @@ var skillListCommand = new Command("list").description("List skill packages").op
|
|
|
12344
13199
|
});
|
|
12345
13200
|
} catch (error) {
|
|
12346
13201
|
if (error instanceof CLIError) {
|
|
12347
|
-
fail(error.code, error.message, {
|
|
13202
|
+
fail(error.code, error.message, {
|
|
13203
|
+
details: error.details,
|
|
13204
|
+
hint: error.hint,
|
|
13205
|
+
suggestedFix: error.suggestedFix
|
|
13206
|
+
});
|
|
12348
13207
|
return;
|
|
12349
13208
|
}
|
|
12350
13209
|
fail(
|
|
@@ -12383,7 +13242,11 @@ var skillGetCommand = new Command("get").description("Get skill package details"
|
|
|
12383
13242
|
});
|
|
12384
13243
|
} catch (error) {
|
|
12385
13244
|
if (error instanceof CLIError) {
|
|
12386
|
-
fail(error.code, error.message, {
|
|
13245
|
+
fail(error.code, error.message, {
|
|
13246
|
+
details: error.details,
|
|
13247
|
+
hint: error.hint,
|
|
13248
|
+
suggestedFix: error.suggestedFix
|
|
13249
|
+
});
|
|
12387
13250
|
return;
|
|
12388
13251
|
}
|
|
12389
13252
|
fail(
|
|
@@ -12395,388 +13258,10 @@ var skillGetCommand = new Command("get").description("Get skill package details"
|
|
|
12395
13258
|
|
|
12396
13259
|
// src/commands/skill/create.ts
|
|
12397
13260
|
init_cjs_shims();
|
|
12398
|
-
|
|
12399
|
-
|
|
12400
|
-
init_cjs_shims();
|
|
12401
|
-
var fs16 = __toESM(require("fs"));
|
|
12402
|
-
var path12 = __toESM(require("path"));
|
|
13261
|
+
var fs17 = __toESM(require("fs"));
|
|
13262
|
+
init_symlink();
|
|
12403
13263
|
init_paths();
|
|
12404
13264
|
init_logger();
|
|
12405
|
-
|
|
12406
|
-
// src/skill/types.ts
|
|
12407
|
-
init_cjs_shims();
|
|
12408
|
-
var SKILL_NAME_REGEX = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
|
|
12409
|
-
var SKILL_NAME_MAX_LENGTH = 64;
|
|
12410
|
-
var SKILL_DESCRIPTION_MAX_LENGTH = 200;
|
|
12411
|
-
var SKILL_TRIGGERS_MIN = 1;
|
|
12412
|
-
var SKILL_TRIGGERS_MAX = 10;
|
|
12413
|
-
var REGISTRY_VERSION = 1;
|
|
12414
|
-
function isSkillRegistry(obj) {
|
|
12415
|
-
return typeof obj === "object" && obj !== null && typeof obj.version === "number" && typeof obj.updatedAt === "string" && Array.isArray(obj.skills);
|
|
12416
|
-
}
|
|
12417
|
-
function isValidSkillName(name) {
|
|
12418
|
-
return typeof name === "string" && name.length >= 1 && name.length <= SKILL_NAME_MAX_LENGTH && SKILL_NAME_REGEX.test(name);
|
|
12419
|
-
}
|
|
12420
|
-
function createSkillError(code, message, options) {
|
|
12421
|
-
return {
|
|
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]
|
|
12474
|
-
});
|
|
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
13265
|
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
13266
|
try {
|
|
12782
13267
|
const hasWorkflowOption = options.workflow || options.workflowIds || options.workflowSpec || options.workflowQuery;
|
|
@@ -12818,25 +13303,36 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
|
|
|
12818
13303
|
body: input3
|
|
12819
13304
|
});
|
|
12820
13305
|
const result = response.payload;
|
|
12821
|
-
let
|
|
13306
|
+
let localPath;
|
|
13307
|
+
let symlinkPath;
|
|
12822
13308
|
if (result.workflowId) {
|
|
12823
13309
|
try {
|
|
12824
13310
|
const localName = options.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
12825
|
-
|
|
13311
|
+
const skillDir = getReflyDomainSkillDir(localName);
|
|
13312
|
+
const symlinkStatus = isSkillSymlinkValid(localName);
|
|
13313
|
+
if (fs17.existsSync(skillDir) || symlinkStatus.exists) {
|
|
12826
13314
|
logger.debug(`Local skill '${localName}' already exists, skipping sync`);
|
|
12827
13315
|
} else {
|
|
12828
|
-
const
|
|
13316
|
+
const skillMdContent = generateReflySkillMd({
|
|
12829
13317
|
name: localName,
|
|
13318
|
+
displayName: options.name,
|
|
12830
13319
|
description: input3.description || `Skill: ${options.name}`,
|
|
13320
|
+
skillId: result.skillId,
|
|
12831
13321
|
workflowId: result.workflowId,
|
|
12832
13322
|
triggers: input3.triggers,
|
|
12833
13323
|
tags: input3.tags,
|
|
12834
13324
|
version: options.version,
|
|
12835
|
-
|
|
13325
|
+
inputSchema: result.inputSchema,
|
|
13326
|
+
outputSchema: result.outputSchema
|
|
12836
13327
|
});
|
|
12837
|
-
|
|
12838
|
-
|
|
12839
|
-
|
|
13328
|
+
const symlinkResult = createReflySkillWithSymlink(localName, skillMdContent);
|
|
13329
|
+
if (symlinkResult.success) {
|
|
13330
|
+
localPath = symlinkResult.reflyPath;
|
|
13331
|
+
symlinkPath = symlinkResult.claudePath;
|
|
13332
|
+
logger.info(`Created local domain skill: ${localName}`);
|
|
13333
|
+
} else {
|
|
13334
|
+
logger.warn(`Failed to create local skill: ${symlinkResult.error}`);
|
|
13335
|
+
}
|
|
12840
13336
|
}
|
|
12841
13337
|
} catch (syncError) {
|
|
12842
13338
|
logger.warn(`Failed to sync to local: ${syncError.message}`);
|
|
@@ -12850,8 +13346,9 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
|
|
|
12850
13346
|
workflowId: result.workflowId,
|
|
12851
13347
|
url: `${getWebUrl()}/skill/${result.skillId}`
|
|
12852
13348
|
};
|
|
12853
|
-
if (
|
|
12854
|
-
payload.
|
|
13349
|
+
if (localPath) {
|
|
13350
|
+
payload.localPath = localPath;
|
|
13351
|
+
payload.symlinkPath = symlinkPath;
|
|
12855
13352
|
}
|
|
12856
13353
|
if (options.verbose) {
|
|
12857
13354
|
payload.workflowIds = result.workflowIds;
|
|
@@ -12860,7 +13357,11 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
|
|
|
12860
13357
|
ok("skill.create", payload);
|
|
12861
13358
|
} catch (error) {
|
|
12862
13359
|
if (error instanceof CLIError) {
|
|
12863
|
-
fail(error.code, error.message, {
|
|
13360
|
+
fail(error.code, error.message, {
|
|
13361
|
+
details: error.details,
|
|
13362
|
+
hint: error.hint,
|
|
13363
|
+
suggestedFix: error.suggestedFix
|
|
13364
|
+
});
|
|
12864
13365
|
return;
|
|
12865
13366
|
}
|
|
12866
13367
|
fail(
|
|
@@ -12870,37 +13371,188 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
|
|
|
12870
13371
|
}
|
|
12871
13372
|
});
|
|
12872
13373
|
|
|
12873
|
-
// src/commands/skill/
|
|
13374
|
+
// src/commands/skill/update.ts
|
|
12874
13375
|
init_cjs_shims();
|
|
12875
|
-
var
|
|
13376
|
+
var fs18 = __toESM(require("fs"));
|
|
13377
|
+
var path13 = __toESM(require("path"));
|
|
13378
|
+
init_paths();
|
|
13379
|
+
init_symlink();
|
|
13380
|
+
var MIN_DESCRIPTION_WORDS = 20;
|
|
13381
|
+
function validateDescription(description, skillName) {
|
|
13382
|
+
if (!description) {
|
|
13383
|
+
return {
|
|
13384
|
+
message: "Skill description is required for Claude Code discovery",
|
|
13385
|
+
hint: `Add a description field with at least ${MIN_DESCRIPTION_WORDS} words to your SKILL.md`,
|
|
13386
|
+
example: generateDescriptionExample(skillName)
|
|
13387
|
+
};
|
|
13388
|
+
}
|
|
13389
|
+
const wordCount = description.trim().split(/\s+/).length;
|
|
13390
|
+
if (wordCount < MIN_DESCRIPTION_WORDS) {
|
|
13391
|
+
return {
|
|
13392
|
+
message: `Description too short (${wordCount} words). Minimum ${MIN_DESCRIPTION_WORDS} words required for Claude Code discovery`,
|
|
13393
|
+
hint: `Expand the description in your SKILL.md to at least ${MIN_DESCRIPTION_WORDS} words`,
|
|
13394
|
+
example: generateDescriptionExample(skillName)
|
|
13395
|
+
};
|
|
13396
|
+
}
|
|
13397
|
+
return null;
|
|
13398
|
+
}
|
|
13399
|
+
function generateDescriptionExample(skillName) {
|
|
13400
|
+
const baseName = skillName.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
13401
|
+
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].`;
|
|
13402
|
+
}
|
|
13403
|
+
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
13404
|
try {
|
|
12877
|
-
|
|
12878
|
-
|
|
12879
|
-
|
|
12880
|
-
|
|
12881
|
-
|
|
12882
|
-
|
|
13405
|
+
const name = options.name;
|
|
13406
|
+
const skillDir = getReflyDomainSkillDir(name);
|
|
13407
|
+
const skillMdPath = path13.join(skillDir, "SKILL.md");
|
|
13408
|
+
if (!fs18.existsSync(skillMdPath)) {
|
|
13409
|
+
const skillsDir = getReflySkillsDir();
|
|
13410
|
+
fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
|
|
13411
|
+
hint: `Make sure the skill '${name}' exists in ${skillsDir}/
|
|
13412
|
+
|
|
13413
|
+
To see installed skills: refly skill list`
|
|
13414
|
+
});
|
|
13415
|
+
return;
|
|
13416
|
+
}
|
|
13417
|
+
const skillContent = fs18.readFileSync(skillMdPath, "utf-8");
|
|
13418
|
+
let meta;
|
|
13419
|
+
try {
|
|
13420
|
+
const parsed = parseReflySkillMd(skillContent);
|
|
13421
|
+
meta = parsed.meta;
|
|
13422
|
+
} catch (parseError) {
|
|
13423
|
+
fail(
|
|
13424
|
+
ErrorCodes.INVALID_INPUT,
|
|
13425
|
+
`Failed to parse SKILL.md: ${parseError.message}`,
|
|
13426
|
+
{
|
|
13427
|
+
hint: "Make sure SKILL.md has valid frontmatter with required fields: name, description, skillId, workflowId"
|
|
13428
|
+
}
|
|
13429
|
+
);
|
|
13430
|
+
return;
|
|
13431
|
+
}
|
|
13432
|
+
const installationId = options.id || meta.installationId;
|
|
13433
|
+
if (!installationId) {
|
|
13434
|
+
fail(ErrorCodes.INVALID_INPUT, "Installation ID not found", {
|
|
13435
|
+
hint: "Provide --id <installationId> or ensure your SKILL.md contains the installationId field"
|
|
13436
|
+
});
|
|
13437
|
+
return;
|
|
13438
|
+
}
|
|
13439
|
+
const skipDescription = options.skipDescription;
|
|
13440
|
+
if (!skipDescription) {
|
|
13441
|
+
const descriptionError = validateDescription(meta.description, name);
|
|
13442
|
+
if (descriptionError) {
|
|
13443
|
+
fail(ErrorCodes.VALIDATION_ERROR, descriptionError.message, {
|
|
13444
|
+
hint: descriptionError.hint,
|
|
13445
|
+
recoverable: true,
|
|
13446
|
+
suggestedFix: {
|
|
13447
|
+
field: "description",
|
|
13448
|
+
format: "[What it does]. Use when [scenarios]: (1) [case1], (2) [case2], or [catch-all].",
|
|
13449
|
+
example: descriptionError.example
|
|
13450
|
+
}
|
|
13451
|
+
});
|
|
13452
|
+
return;
|
|
13453
|
+
}
|
|
13454
|
+
}
|
|
13455
|
+
const updatePayload = {
|
|
13456
|
+
...meta.name && { name: meta.name },
|
|
13457
|
+
...meta.description && { description: meta.description },
|
|
13458
|
+
...meta.workflowId && { workflowId: meta.workflowId },
|
|
13459
|
+
...meta.triggers?.length && { triggers: meta.triggers },
|
|
13460
|
+
...meta.tags?.length && { tags: meta.tags },
|
|
13461
|
+
...meta.version && { version: meta.version }
|
|
13462
|
+
};
|
|
13463
|
+
if (Object.keys(updatePayload).length === 0) {
|
|
13464
|
+
fail(ErrorCodes.INVALID_INPUT, "No updateable fields found in SKILL.md", {
|
|
13465
|
+
hint: "Ensure SKILL.md contains fields like name, description, triggers, tags, or version"
|
|
13466
|
+
});
|
|
13467
|
+
return;
|
|
13468
|
+
}
|
|
13469
|
+
const response = await apiRequest(
|
|
13470
|
+
`/v1/skill-installations/${installationId}`,
|
|
13471
|
+
{
|
|
13472
|
+
method: "PATCH",
|
|
13473
|
+
body: updatePayload
|
|
13474
|
+
}
|
|
13475
|
+
);
|
|
13476
|
+
ok("skill.update", {
|
|
13477
|
+
...response,
|
|
13478
|
+
localName: name,
|
|
13479
|
+
updated: true,
|
|
13480
|
+
fields: Object.keys(updatePayload)
|
|
12883
13481
|
});
|
|
12884
13482
|
} catch (error) {
|
|
12885
13483
|
if (error instanceof CLIError) {
|
|
12886
|
-
fail(error.code, error.message, {
|
|
13484
|
+
fail(error.code, error.message, {
|
|
13485
|
+
details: error.details,
|
|
13486
|
+
hint: error.hint,
|
|
13487
|
+
suggestedFix: error.suggestedFix
|
|
13488
|
+
});
|
|
12887
13489
|
return;
|
|
12888
13490
|
}
|
|
12889
13491
|
fail(
|
|
12890
13492
|
ErrorCodes.INTERNAL_ERROR,
|
|
12891
|
-
error instanceof Error ? error.message : "Failed to
|
|
13493
|
+
error instanceof Error ? error.message : "Failed to update skill installation"
|
|
12892
13494
|
);
|
|
12893
13495
|
}
|
|
12894
13496
|
});
|
|
12895
13497
|
|
|
12896
13498
|
// src/commands/skill/publish.ts
|
|
12897
13499
|
init_cjs_shims();
|
|
12898
|
-
var
|
|
13500
|
+
var fs19 = __toESM(require("fs"));
|
|
13501
|
+
var path14 = __toESM(require("path"));
|
|
13502
|
+
init_symlink();
|
|
13503
|
+
init_paths();
|
|
13504
|
+
var skillPublishCommand = new Command("publish").description("Publish a skill package using local SKILL.md").option("--id <skillId>", "Skill ID (skp-xxx) - overrides ID from SKILL.md").option("--name <name>", "Local skill name (directory in ~/.refly/skills/)").action(async (options) => {
|
|
12899
13505
|
try {
|
|
13506
|
+
const skillsDir = getReflySkillsDir();
|
|
13507
|
+
if (!options.name) {
|
|
13508
|
+
fail(ErrorCodes.INVALID_INPUT, "Missing required option: --name", {
|
|
13509
|
+
hint: `The publish command requires --name to locate the local SKILL.md.
|
|
13510
|
+
|
|
13511
|
+
Usage:
|
|
13512
|
+
refly skill publish --name <name>
|
|
13513
|
+
refly skill publish --name <name> --id <skillId> # override skillId
|
|
13514
|
+
|
|
13515
|
+
To find your skill name:
|
|
13516
|
+
refly skill list
|
|
13517
|
+
ls ${skillsDir}/`
|
|
13518
|
+
});
|
|
13519
|
+
return;
|
|
13520
|
+
}
|
|
13521
|
+
const name = options.name;
|
|
13522
|
+
const skillDir = getReflyDomainSkillDir(name);
|
|
13523
|
+
const skillMdPath = path14.join(skillDir, "SKILL.md");
|
|
13524
|
+
if (!fs19.existsSync(skillMdPath)) {
|
|
13525
|
+
fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
|
|
13526
|
+
hint: `Make sure the skill '${name}' exists in ${skillsDir}/
|
|
13527
|
+
|
|
13528
|
+
To see installed skills: refly skill list
|
|
13529
|
+
To create a new skill: refly skill create --name "${name}" --workflow-query "..."`
|
|
13530
|
+
});
|
|
13531
|
+
return;
|
|
13532
|
+
}
|
|
13533
|
+
const skillContent = fs19.readFileSync(skillMdPath, "utf-8");
|
|
13534
|
+
let parsedSkill;
|
|
13535
|
+
try {
|
|
13536
|
+
parsedSkill = parseReflySkillMd(skillContent);
|
|
13537
|
+
} catch (parseError) {
|
|
13538
|
+
fail(
|
|
13539
|
+
ErrorCodes.INVALID_INPUT,
|
|
13540
|
+
`Failed to parse SKILL.md: ${parseError.message}`,
|
|
13541
|
+
{
|
|
13542
|
+
hint: "Make sure SKILL.md has valid frontmatter with required fields: name, description, skillId, workflowId"
|
|
13543
|
+
}
|
|
13544
|
+
);
|
|
13545
|
+
return;
|
|
13546
|
+
}
|
|
13547
|
+
const { meta } = parsedSkill;
|
|
13548
|
+
const skillId = options.id || meta.skillId;
|
|
12900
13549
|
const result = await apiRequest(
|
|
12901
13550
|
`/v1/skill-packages/${skillId}/publish`,
|
|
12902
13551
|
{
|
|
12903
|
-
method: "POST"
|
|
13552
|
+
method: "POST",
|
|
13553
|
+
body: {
|
|
13554
|
+
skillContent
|
|
13555
|
+
}
|
|
12904
13556
|
}
|
|
12905
13557
|
);
|
|
12906
13558
|
ok("skill.publish", {
|
|
@@ -12910,11 +13562,18 @@ var skillPublishCommand = new Command("publish").description("Publish a skill pa
|
|
|
12910
13562
|
status: result.status,
|
|
12911
13563
|
isPublic: result.isPublic,
|
|
12912
13564
|
shareId: result.shareId,
|
|
12913
|
-
shareUrl: result.shareId ? `https://refly.ai/skill/${result.shareId}` : void 0
|
|
13565
|
+
shareUrl: result.shareId ? `https://refly.ai/skill/${result.shareId}` : void 0,
|
|
13566
|
+
githubPrUrl: result.githubPrUrl,
|
|
13567
|
+
githubPrNumber: result.githubPrNumber,
|
|
13568
|
+
localPath: skillMdPath
|
|
12914
13569
|
});
|
|
12915
13570
|
} catch (error) {
|
|
12916
13571
|
if (error instanceof CLIError) {
|
|
12917
|
-
fail(error.code, error.message, {
|
|
13572
|
+
fail(error.code, error.message, {
|
|
13573
|
+
details: error.details,
|
|
13574
|
+
hint: error.hint,
|
|
13575
|
+
suggestedFix: error.suggestedFix
|
|
13576
|
+
});
|
|
12918
13577
|
return;
|
|
12919
13578
|
}
|
|
12920
13579
|
fail(
|
|
@@ -12926,19 +13585,72 @@ var skillPublishCommand = new Command("publish").description("Publish a skill pa
|
|
|
12926
13585
|
|
|
12927
13586
|
// src/commands/skill/unpublish.ts
|
|
12928
13587
|
init_cjs_shims();
|
|
12929
|
-
var
|
|
13588
|
+
var fs20 = __toESM(require("fs"));
|
|
13589
|
+
var path15 = __toESM(require("path"));
|
|
13590
|
+
init_symlink();
|
|
13591
|
+
init_paths();
|
|
13592
|
+
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
13593
|
try {
|
|
13594
|
+
const skillsDir = getReflySkillsDir();
|
|
13595
|
+
if (!options.id && !options.name) {
|
|
13596
|
+
fail(ErrorCodes.INVALID_INPUT, "Missing required option: --id or --name", {
|
|
13597
|
+
hint: `Usage:
|
|
13598
|
+
refly skill unpublish --name <name>
|
|
13599
|
+
refly skill unpublish --id <skillId>
|
|
13600
|
+
|
|
13601
|
+
To find your skill name:
|
|
13602
|
+
refly skill list
|
|
13603
|
+
ls ${skillsDir}/`
|
|
13604
|
+
});
|
|
13605
|
+
return;
|
|
13606
|
+
}
|
|
13607
|
+
let skillId;
|
|
13608
|
+
let name;
|
|
13609
|
+
if (options.name) {
|
|
13610
|
+
name = options.name;
|
|
13611
|
+
const skillDir = getReflyDomainSkillDir(name);
|
|
13612
|
+
const skillMdPath = path15.join(skillDir, "SKILL.md");
|
|
13613
|
+
if (!fs20.existsSync(skillMdPath)) {
|
|
13614
|
+
fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
|
|
13615
|
+
hint: `Make sure the skill '${name}' exists in ${skillsDir}/
|
|
13616
|
+
|
|
13617
|
+
To see installed skills: refly skill list`
|
|
13618
|
+
});
|
|
13619
|
+
return;
|
|
13620
|
+
}
|
|
13621
|
+
const skillContent = fs20.readFileSync(skillMdPath, "utf-8");
|
|
13622
|
+
try {
|
|
13623
|
+
const { meta } = parseReflySkillMd(skillContent);
|
|
13624
|
+
skillId = options.id || meta.skillId;
|
|
13625
|
+
} catch (parseError) {
|
|
13626
|
+
fail(
|
|
13627
|
+
ErrorCodes.INVALID_INPUT,
|
|
13628
|
+
`Failed to parse SKILL.md: ${parseError.message}`,
|
|
13629
|
+
{
|
|
13630
|
+
hint: "Make sure SKILL.md has valid frontmatter with required fields: name, description, skillId, workflowId"
|
|
13631
|
+
}
|
|
13632
|
+
);
|
|
13633
|
+
return;
|
|
13634
|
+
}
|
|
13635
|
+
} else {
|
|
13636
|
+
skillId = options.id;
|
|
13637
|
+
}
|
|
12931
13638
|
await apiRequest(`/v1/skill-packages/${skillId}/unpublish`, {
|
|
12932
13639
|
method: "POST"
|
|
12933
13640
|
});
|
|
12934
13641
|
ok("skill.unpublish", {
|
|
13642
|
+
name,
|
|
12935
13643
|
skillId,
|
|
12936
13644
|
status: "draft",
|
|
12937
13645
|
isPublic: false
|
|
12938
13646
|
});
|
|
12939
13647
|
} catch (error) {
|
|
12940
13648
|
if (error instanceof CLIError) {
|
|
12941
|
-
fail(error.code, error.message, {
|
|
13649
|
+
fail(error.code, error.message, {
|
|
13650
|
+
details: error.details,
|
|
13651
|
+
hint: error.hint,
|
|
13652
|
+
suggestedFix: error.suggestedFix
|
|
13653
|
+
});
|
|
12942
13654
|
return;
|
|
12943
13655
|
}
|
|
12944
13656
|
fail(
|
|
@@ -12950,18 +13662,94 @@ var skillUnpublishCommand = new Command("unpublish").description("Unpublish a sk
|
|
|
12950
13662
|
|
|
12951
13663
|
// src/commands/skill/run.ts
|
|
12952
13664
|
init_cjs_shims();
|
|
12953
|
-
var
|
|
13665
|
+
var fs21 = __toESM(require("fs"));
|
|
13666
|
+
var path16 = __toESM(require("path"));
|
|
13667
|
+
init_symlink();
|
|
13668
|
+
init_paths();
|
|
13669
|
+
var skillRunCommand = new Command("run").description("Run an installed skill").option("--id <installationId>", "Installation ID (skpi-xxx)").option("--name <name>", "Local skill name (directory in ~/.refly/skills/)").option("--input <json>", "Input JSON for the skill").option("--workflow <skillWorkflowId>", "Run specific workflow only").option("--async", "Run asynchronously").action(async (options) => {
|
|
12954
13670
|
try {
|
|
13671
|
+
const skillsDir = getReflySkillsDir();
|
|
13672
|
+
if (!options.id && !options.name) {
|
|
13673
|
+
fail(ErrorCodes.INVALID_INPUT, "Missing required option: --id or --name", {
|
|
13674
|
+
hint: `Usage:
|
|
13675
|
+
refly skill run --name <name>
|
|
13676
|
+
refly skill run --id <installationId>
|
|
13677
|
+
|
|
13678
|
+
To find your skill name:
|
|
13679
|
+
refly skill list
|
|
13680
|
+
ls ${skillsDir}/`
|
|
13681
|
+
});
|
|
13682
|
+
return;
|
|
13683
|
+
}
|
|
13684
|
+
let installationId;
|
|
13685
|
+
let name;
|
|
13686
|
+
let skillId;
|
|
13687
|
+
if (options.name) {
|
|
13688
|
+
name = options.name;
|
|
13689
|
+
const skillDir = getReflyDomainSkillDir(name);
|
|
13690
|
+
const skillMdPath = path16.join(skillDir, "SKILL.md");
|
|
13691
|
+
if (!fs21.existsSync(skillMdPath)) {
|
|
13692
|
+
fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
|
|
13693
|
+
hint: `Make sure the skill '${name}' exists in ${skillsDir}/
|
|
13694
|
+
|
|
13695
|
+
To see installed skills: refly skill list
|
|
13696
|
+
To install a skill: refly skill install <skillId>`
|
|
13697
|
+
});
|
|
13698
|
+
return;
|
|
13699
|
+
}
|
|
13700
|
+
const skillContent = fs21.readFileSync(skillMdPath, "utf-8");
|
|
13701
|
+
try {
|
|
13702
|
+
const { meta } = parseReflySkillMd(skillContent);
|
|
13703
|
+
skillId = meta.skillId;
|
|
13704
|
+
if (options.id) {
|
|
13705
|
+
installationId = options.id;
|
|
13706
|
+
} else if (meta.installationId) {
|
|
13707
|
+
installationId = meta.installationId;
|
|
13708
|
+
} else {
|
|
13709
|
+
fail(ErrorCodes.INVALID_INPUT, `Skill '${name}' does not have an installationId`, {
|
|
13710
|
+
hint: `This skill may have been created locally but not installed.
|
|
13711
|
+
|
|
13712
|
+
To install: refly skill install ${meta.skillId}`
|
|
13713
|
+
});
|
|
13714
|
+
return;
|
|
13715
|
+
}
|
|
13716
|
+
} catch (parseError) {
|
|
13717
|
+
fail(
|
|
13718
|
+
ErrorCodes.INVALID_INPUT,
|
|
13719
|
+
`Failed to parse SKILL.md: ${parseError.message}`,
|
|
13720
|
+
{
|
|
13721
|
+
hint: "Make sure SKILL.md has valid frontmatter with required fields: name, description, skillId, workflowId"
|
|
13722
|
+
}
|
|
13723
|
+
);
|
|
13724
|
+
return;
|
|
13725
|
+
}
|
|
13726
|
+
} else {
|
|
13727
|
+
installationId = options.id;
|
|
13728
|
+
}
|
|
12955
13729
|
let input3 = {};
|
|
12956
13730
|
if (options.input) {
|
|
12957
13731
|
try {
|
|
12958
13732
|
input3 = JSON.parse(options.input);
|
|
12959
13733
|
if (typeof input3 !== "object" || input3 === null || Array.isArray(input3)) {
|
|
12960
|
-
fail(ErrorCodes.INVALID_INPUT, "Input must be a JSON object"
|
|
13734
|
+
fail(ErrorCodes.INVALID_INPUT, "Input must be a JSON object", {
|
|
13735
|
+
hint: `Use format: '{"varName": "value", "fileVar": "df-fileId"}'`,
|
|
13736
|
+
suggestedFix: {
|
|
13737
|
+
field: "--input",
|
|
13738
|
+
format: "json-object",
|
|
13739
|
+
example: '{"varName": "value", "fileVar": "df-fileId"}'
|
|
13740
|
+
}
|
|
13741
|
+
});
|
|
12961
13742
|
return;
|
|
12962
13743
|
}
|
|
12963
13744
|
} catch {
|
|
12964
|
-
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON input"
|
|
13745
|
+
fail(ErrorCodes.INVALID_INPUT, "Invalid JSON input", {
|
|
13746
|
+
hint: `Ensure the input is valid JSON, e.g., '{"varName": "value"}'`,
|
|
13747
|
+
suggestedFix: {
|
|
13748
|
+
field: "--input",
|
|
13749
|
+
format: "json-object",
|
|
13750
|
+
example: '{"varName": "value"}'
|
|
13751
|
+
}
|
|
13752
|
+
});
|
|
12965
13753
|
return;
|
|
12966
13754
|
}
|
|
12967
13755
|
}
|
|
@@ -12976,6 +13764,8 @@ var skillRunCommand = new Command("run").description("Run an installed skill").a
|
|
|
12976
13764
|
}
|
|
12977
13765
|
);
|
|
12978
13766
|
ok("skill.run", {
|
|
13767
|
+
name,
|
|
13768
|
+
skillId,
|
|
12979
13769
|
executionId: result.executionId,
|
|
12980
13770
|
installationId: result.installationId,
|
|
12981
13771
|
status: result.status,
|
|
@@ -12985,7 +13775,11 @@ var skillRunCommand = new Command("run").description("Run an installed skill").a
|
|
|
12985
13775
|
});
|
|
12986
13776
|
} catch (error) {
|
|
12987
13777
|
if (error instanceof CLIError) {
|
|
12988
|
-
fail(error.code, error.message, {
|
|
13778
|
+
fail(error.code, error.message, {
|
|
13779
|
+
details: error.details,
|
|
13780
|
+
hint: error.hint,
|
|
13781
|
+
suggestedFix: error.suggestedFix
|
|
13782
|
+
});
|
|
12989
13783
|
return;
|
|
12990
13784
|
}
|
|
12991
13785
|
fail(
|
|
@@ -13023,7 +13817,11 @@ var skillSearchCommand = new Command("search").description("Search public skill
|
|
|
13023
13817
|
});
|
|
13024
13818
|
} catch (error) {
|
|
13025
13819
|
if (error instanceof CLIError) {
|
|
13026
|
-
fail(error.code, error.message, {
|
|
13820
|
+
fail(error.code, error.message, {
|
|
13821
|
+
details: error.details,
|
|
13822
|
+
hint: error.hint,
|
|
13823
|
+
suggestedFix: error.suggestedFix
|
|
13824
|
+
});
|
|
13027
13825
|
return;
|
|
13028
13826
|
}
|
|
13029
13827
|
fail(
|
|
@@ -13035,6 +13833,8 @@ var skillSearchCommand = new Command("search").description("Search public skill
|
|
|
13035
13833
|
|
|
13036
13834
|
// src/commands/skill/install.ts
|
|
13037
13835
|
init_cjs_shims();
|
|
13836
|
+
init_symlink();
|
|
13837
|
+
init_logger();
|
|
13038
13838
|
var skillInstallCommand = new Command("install").description("Install a skill package").argument("<skillId>", "Skill package ID to install").option("--version <version>", "Specific version to install").option("--share-id <shareId>", "Share ID for private skills").option("--config <json>", "Installation config JSON").action(async (skillId, options) => {
|
|
13039
13839
|
try {
|
|
13040
13840
|
const body = { skillId };
|
|
@@ -13044,7 +13844,14 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
|
|
|
13044
13844
|
try {
|
|
13045
13845
|
body.config = JSON.parse(options.config);
|
|
13046
13846
|
} catch {
|
|
13047
|
-
fail(ErrorCodes.INVALID_INPUT, "Invalid config JSON"
|
|
13847
|
+
fail(ErrorCodes.INVALID_INPUT, "Invalid config JSON", {
|
|
13848
|
+
hint: `Config must be a valid JSON object, e.g., '{"key": "value"}'`,
|
|
13849
|
+
suggestedFix: {
|
|
13850
|
+
field: "--config",
|
|
13851
|
+
format: "json-object",
|
|
13852
|
+
example: '{"key": "value"}'
|
|
13853
|
+
}
|
|
13854
|
+
});
|
|
13048
13855
|
return;
|
|
13049
13856
|
}
|
|
13050
13857
|
}
|
|
@@ -13055,6 +13862,37 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
|
|
|
13055
13862
|
body
|
|
13056
13863
|
}
|
|
13057
13864
|
);
|
|
13865
|
+
let localPath;
|
|
13866
|
+
let symlinkPath;
|
|
13867
|
+
const skillName = result.skillPackage?.name;
|
|
13868
|
+
const workflowId = result.skillPackage?.workflowId;
|
|
13869
|
+
if (skillName && workflowId) {
|
|
13870
|
+
try {
|
|
13871
|
+
const skillMdContent = generateReflySkillMd({
|
|
13872
|
+
name: skillName,
|
|
13873
|
+
displayName: result.skillPackage?.displayName,
|
|
13874
|
+
description: result.skillPackage?.description || `Skill: ${skillName}`,
|
|
13875
|
+
skillId: result.skillId,
|
|
13876
|
+
workflowId,
|
|
13877
|
+
installationId: result.installationId,
|
|
13878
|
+
triggers: result.skillPackage?.triggers,
|
|
13879
|
+
tags: result.skillPackage?.tags,
|
|
13880
|
+
version: result.installedVersion,
|
|
13881
|
+
inputSchema: result.skillPackage?.inputSchema,
|
|
13882
|
+
outputSchema: result.skillPackage?.outputSchema
|
|
13883
|
+
});
|
|
13884
|
+
const symlinkResult = createReflySkillWithSymlink(skillName, skillMdContent);
|
|
13885
|
+
if (symlinkResult.success) {
|
|
13886
|
+
localPath = symlinkResult.reflyPath;
|
|
13887
|
+
symlinkPath = symlinkResult.claudePath;
|
|
13888
|
+
logger.info(`Created local skill: ${localPath}`);
|
|
13889
|
+
} else {
|
|
13890
|
+
logger.warn(`Failed to create local skill: ${symlinkResult.error}`);
|
|
13891
|
+
}
|
|
13892
|
+
} catch (err) {
|
|
13893
|
+
logger.warn(`Failed to create local skill: ${err.message}`);
|
|
13894
|
+
}
|
|
13895
|
+
}
|
|
13058
13896
|
ok("skill.install", {
|
|
13059
13897
|
installationId: result.installationId,
|
|
13060
13898
|
skillId: result.skillId,
|
|
@@ -13062,11 +13900,17 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
|
|
|
13062
13900
|
skillVersion: result.installedVersion,
|
|
13063
13901
|
status: result.status,
|
|
13064
13902
|
config: result.userConfig,
|
|
13065
|
-
installedAt: result.createdAt
|
|
13903
|
+
installedAt: result.createdAt,
|
|
13904
|
+
localPath,
|
|
13905
|
+
symlinkPath
|
|
13066
13906
|
});
|
|
13067
13907
|
} catch (error) {
|
|
13068
13908
|
if (error instanceof CLIError) {
|
|
13069
|
-
fail(error.code, error.message, {
|
|
13909
|
+
fail(error.code, error.message, {
|
|
13910
|
+
details: error.details,
|
|
13911
|
+
hint: error.hint,
|
|
13912
|
+
suggestedFix: error.suggestedFix
|
|
13913
|
+
});
|
|
13070
13914
|
return;
|
|
13071
13915
|
}
|
|
13072
13916
|
fail(
|
|
@@ -13078,18 +13922,101 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
|
|
|
13078
13922
|
|
|
13079
13923
|
// src/commands/skill/uninstall.ts
|
|
13080
13924
|
init_cjs_shims();
|
|
13081
|
-
var
|
|
13925
|
+
var fs22 = __toESM(require("fs"));
|
|
13926
|
+
var path17 = __toESM(require("path"));
|
|
13927
|
+
init_symlink();
|
|
13928
|
+
init_paths();
|
|
13929
|
+
init_logger();
|
|
13930
|
+
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
13931
|
try {
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
|
|
13932
|
+
const skillsDir = getReflySkillsDir();
|
|
13933
|
+
if (!options.id && !options.name) {
|
|
13934
|
+
fail(ErrorCodes.INVALID_INPUT, "Missing required option: --id or --name", {
|
|
13935
|
+
hint: `Usage:
|
|
13936
|
+
refly skill uninstall --name <name>
|
|
13937
|
+
refly skill uninstall --id <installationId>
|
|
13938
|
+
|
|
13939
|
+
To find your skill name:
|
|
13940
|
+
refly skill list
|
|
13941
|
+
ls ${skillsDir}/`
|
|
13942
|
+
});
|
|
13943
|
+
return;
|
|
13944
|
+
}
|
|
13945
|
+
let installationId;
|
|
13946
|
+
let skillId;
|
|
13947
|
+
let name;
|
|
13948
|
+
if (options.name) {
|
|
13949
|
+
name = options.name;
|
|
13950
|
+
const skillDir = getReflyDomainSkillDir(name);
|
|
13951
|
+
const skillMdPath = path17.join(skillDir, "SKILL.md");
|
|
13952
|
+
if (!fs22.existsSync(skillMdPath)) {
|
|
13953
|
+
fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
|
|
13954
|
+
hint: `Make sure the skill '${name}' exists in ${skillsDir}/
|
|
13955
|
+
|
|
13956
|
+
To see installed skills: refly skill list`
|
|
13957
|
+
});
|
|
13958
|
+
return;
|
|
13959
|
+
}
|
|
13960
|
+
const skillContent = fs22.readFileSync(skillMdPath, "utf-8");
|
|
13961
|
+
try {
|
|
13962
|
+
const { meta } = parseReflySkillMd(skillContent);
|
|
13963
|
+
skillId = meta.skillId;
|
|
13964
|
+
installationId = options.id || meta.installationId;
|
|
13965
|
+
} catch (parseError) {
|
|
13966
|
+
fail(
|
|
13967
|
+
ErrorCodes.INVALID_INPUT,
|
|
13968
|
+
`Failed to parse SKILL.md: ${parseError.message}`,
|
|
13969
|
+
{
|
|
13970
|
+
hint: "Make sure SKILL.md has valid frontmatter with required fields: name, description, skillId, workflowId"
|
|
13971
|
+
}
|
|
13972
|
+
);
|
|
13973
|
+
return;
|
|
13974
|
+
}
|
|
13975
|
+
} else {
|
|
13976
|
+
installationId = options.id;
|
|
13977
|
+
}
|
|
13978
|
+
if (installationId) {
|
|
13979
|
+
try {
|
|
13980
|
+
await apiRequest(`/v1/skill-installations/${installationId}`, {
|
|
13981
|
+
method: "DELETE"
|
|
13982
|
+
});
|
|
13983
|
+
} catch (error) {
|
|
13984
|
+
if (error instanceof CLIError && error.code === "NOT_FOUND") {
|
|
13985
|
+
logger.debug("Installation not found on server, proceeding with local cleanup");
|
|
13986
|
+
} else {
|
|
13987
|
+
throw error;
|
|
13988
|
+
}
|
|
13989
|
+
}
|
|
13990
|
+
}
|
|
13991
|
+
let symlinkRemoved = false;
|
|
13992
|
+
let directoryRemoved = false;
|
|
13993
|
+
if (name && !options.keepLocal) {
|
|
13994
|
+
try {
|
|
13995
|
+
const cleanup = deleteDomainSkillWithSymlink(name);
|
|
13996
|
+
symlinkRemoved = cleanup.symlinkRemoved;
|
|
13997
|
+
directoryRemoved = cleanup.directoryRemoved;
|
|
13998
|
+
logger.info(`Cleaned up local skill: ${name}`);
|
|
13999
|
+
} catch (err) {
|
|
14000
|
+
logger.warn(`Failed to clean up local skill: ${err.message}`);
|
|
14001
|
+
}
|
|
14002
|
+
}
|
|
13086
14003
|
ok("skill.uninstall", {
|
|
14004
|
+
name,
|
|
14005
|
+
skillId,
|
|
13087
14006
|
installationId,
|
|
13088
|
-
uninstalled: true
|
|
14007
|
+
uninstalled: true,
|
|
14008
|
+
localCleanup: {
|
|
14009
|
+
symlinkRemoved,
|
|
14010
|
+
directoryRemoved
|
|
14011
|
+
}
|
|
13089
14012
|
});
|
|
13090
14013
|
} catch (error) {
|
|
13091
14014
|
if (error instanceof CLIError) {
|
|
13092
|
-
fail(error.code, error.message, {
|
|
14015
|
+
fail(error.code, error.message, {
|
|
14016
|
+
details: error.details,
|
|
14017
|
+
hint: error.hint,
|
|
14018
|
+
suggestedFix: error.suggestedFix
|
|
14019
|
+
});
|
|
13093
14020
|
return;
|
|
13094
14021
|
}
|
|
13095
14022
|
fail(
|
|
@@ -13127,7 +14054,11 @@ var skillInstallationsCommand = new Command("installations").description("List i
|
|
|
13127
14054
|
});
|
|
13128
14055
|
} catch (error) {
|
|
13129
14056
|
if (error instanceof CLIError) {
|
|
13130
|
-
fail(error.code, error.message, {
|
|
14057
|
+
fail(error.code, error.message, {
|
|
14058
|
+
details: error.details,
|
|
14059
|
+
hint: error.hint,
|
|
14060
|
+
suggestedFix: error.suggestedFix
|
|
14061
|
+
});
|
|
13131
14062
|
return;
|
|
13132
14063
|
}
|
|
13133
14064
|
fail(
|
|
@@ -13142,8 +14073,114 @@ init_cjs_shims();
|
|
|
13142
14073
|
|
|
13143
14074
|
// src/skill/loader.ts
|
|
13144
14075
|
init_cjs_shims();
|
|
14076
|
+
var fs23 = __toESM(require("fs"));
|
|
14077
|
+
var path18 = __toESM(require("path"));
|
|
13145
14078
|
var import_gray_matter = __toESM(require("gray-matter"));
|
|
13146
14079
|
init_logger();
|
|
14080
|
+
|
|
14081
|
+
// src/skill/types.ts
|
|
14082
|
+
init_cjs_shims();
|
|
14083
|
+
var SKILL_NAME_REGEX = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
|
|
14084
|
+
var SKILL_NAME_MAX_LENGTH = 64;
|
|
14085
|
+
var SKILL_DESCRIPTION_MAX_LENGTH = 200;
|
|
14086
|
+
var SKILL_TRIGGERS_MIN = 1;
|
|
14087
|
+
var SKILL_TRIGGERS_MAX = 10;
|
|
14088
|
+
function isValidSkillName(name) {
|
|
14089
|
+
return typeof name === "string" && name.length >= 1 && name.length <= SKILL_NAME_MAX_LENGTH && SKILL_NAME_REGEX.test(name);
|
|
14090
|
+
}
|
|
14091
|
+
function createSkillError(code, message, options) {
|
|
14092
|
+
return {
|
|
14093
|
+
code,
|
|
14094
|
+
message,
|
|
14095
|
+
details: options?.details,
|
|
14096
|
+
suggestions: options?.suggestions
|
|
14097
|
+
};
|
|
14098
|
+
}
|
|
14099
|
+
function validateCommonSkillFields(data, issues) {
|
|
14100
|
+
if (typeof data.name !== "string") {
|
|
14101
|
+
issues.push({ path: "name", message: "Name is required", value: data.name });
|
|
14102
|
+
} else if (!isValidSkillName(data.name)) {
|
|
14103
|
+
issues.push({
|
|
14104
|
+
path: "name",
|
|
14105
|
+
message: `Name must match pattern ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$ and be 1-${SKILL_NAME_MAX_LENGTH} chars`,
|
|
14106
|
+
value: data.name
|
|
14107
|
+
});
|
|
14108
|
+
}
|
|
14109
|
+
if (typeof data.description !== "string") {
|
|
14110
|
+
issues.push({
|
|
14111
|
+
path: "description",
|
|
14112
|
+
message: "Description is required",
|
|
14113
|
+
value: data.description
|
|
14114
|
+
});
|
|
14115
|
+
} else if (data.description.length > SKILL_DESCRIPTION_MAX_LENGTH) {
|
|
14116
|
+
issues.push({
|
|
14117
|
+
path: "description",
|
|
14118
|
+
message: `Description must be <= ${SKILL_DESCRIPTION_MAX_LENGTH} chars`,
|
|
14119
|
+
value: data.description.length
|
|
14120
|
+
});
|
|
14121
|
+
}
|
|
14122
|
+
if (typeof data.workflowId !== "string" || data.workflowId.trim() === "") {
|
|
14123
|
+
issues.push({ path: "workflowId", message: "WorkflowId is required", value: data.workflowId });
|
|
14124
|
+
}
|
|
14125
|
+
validateTriggers(data.triggers, issues);
|
|
14126
|
+
}
|
|
14127
|
+
function validateTriggers(triggers, issues) {
|
|
14128
|
+
if (!Array.isArray(triggers)) {
|
|
14129
|
+
issues.push({ path: "triggers", message: "Triggers must be an array", value: triggers });
|
|
14130
|
+
return;
|
|
14131
|
+
}
|
|
14132
|
+
if (triggers.length < SKILL_TRIGGERS_MIN || triggers.length > SKILL_TRIGGERS_MAX) {
|
|
14133
|
+
issues.push({
|
|
14134
|
+
path: "triggers",
|
|
14135
|
+
message: `Triggers must have ${SKILL_TRIGGERS_MIN}-${SKILL_TRIGGERS_MAX} items`,
|
|
14136
|
+
value: triggers.length
|
|
14137
|
+
});
|
|
14138
|
+
}
|
|
14139
|
+
for (let i = 0; i < triggers.length; i++) {
|
|
14140
|
+
if (typeof triggers[i] !== "string" || triggers[i].trim() === "") {
|
|
14141
|
+
issues.push({
|
|
14142
|
+
path: `triggers[${i}]`,
|
|
14143
|
+
message: "Each trigger must be a non-empty string",
|
|
14144
|
+
value: triggers[i]
|
|
14145
|
+
});
|
|
14146
|
+
}
|
|
14147
|
+
}
|
|
14148
|
+
}
|
|
14149
|
+
function validateOptionalSkillFields(data, issues) {
|
|
14150
|
+
if (data.tags !== void 0) {
|
|
14151
|
+
if (!Array.isArray(data.tags)) {
|
|
14152
|
+
issues.push({ path: "tags", message: "Tags must be an array if provided", value: data.tags });
|
|
14153
|
+
} else {
|
|
14154
|
+
for (let i = 0; i < data.tags.length; i++) {
|
|
14155
|
+
if (typeof data.tags[i] !== "string") {
|
|
14156
|
+
issues.push({
|
|
14157
|
+
path: `tags[${i}]`,
|
|
14158
|
+
message: "Each tag must be a string",
|
|
14159
|
+
value: data.tags[i]
|
|
14160
|
+
});
|
|
14161
|
+
}
|
|
14162
|
+
}
|
|
14163
|
+
}
|
|
14164
|
+
}
|
|
14165
|
+
if (data.author !== void 0 && typeof data.author !== "string") {
|
|
14166
|
+
issues.push({
|
|
14167
|
+
path: "author",
|
|
14168
|
+
message: "Author must be a string if provided",
|
|
14169
|
+
value: data.author
|
|
14170
|
+
});
|
|
14171
|
+
}
|
|
14172
|
+
if (data.version !== void 0 && typeof data.version !== "string") {
|
|
14173
|
+
issues.push({
|
|
14174
|
+
path: "version",
|
|
14175
|
+
message: "Version must be a string if provided",
|
|
14176
|
+
value: data.version
|
|
14177
|
+
});
|
|
14178
|
+
}
|
|
14179
|
+
}
|
|
14180
|
+
|
|
14181
|
+
// src/skill/loader.ts
|
|
14182
|
+
init_paths();
|
|
14183
|
+
init_symlink();
|
|
13147
14184
|
function parseFrontmatter(content) {
|
|
13148
14185
|
try {
|
|
13149
14186
|
const result = (0, import_gray_matter.default)(content);
|
|
@@ -13185,23 +14222,6 @@ function toSkillFrontmatter(data) {
|
|
|
13185
14222
|
version: data.version
|
|
13186
14223
|
};
|
|
13187
14224
|
}
|
|
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
14225
|
function extractSkillMetadata(content) {
|
|
13206
14226
|
try {
|
|
13207
14227
|
const parsed = parseFrontmatter(content);
|
|
@@ -13234,23 +14254,23 @@ function extractSkillMetadata(content) {
|
|
|
13234
14254
|
|
|
13235
14255
|
// src/commands/skill/validate.ts
|
|
13236
14256
|
init_paths();
|
|
13237
|
-
var
|
|
13238
|
-
var
|
|
14257
|
+
var fs24 = __toESM(require("fs"));
|
|
14258
|
+
var path19 = __toESM(require("path"));
|
|
13239
14259
|
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
14260
|
try {
|
|
13241
14261
|
const results = [];
|
|
13242
14262
|
let targetPath;
|
|
13243
14263
|
if (skillPath) {
|
|
13244
|
-
targetPath =
|
|
14264
|
+
targetPath = path19.resolve(skillPath);
|
|
13245
14265
|
} else {
|
|
13246
14266
|
await ensureSkillsDir();
|
|
13247
14267
|
targetPath = getSkillsDir();
|
|
13248
14268
|
}
|
|
13249
|
-
if (!
|
|
14269
|
+
if (!fs24.existsSync(targetPath)) {
|
|
13250
14270
|
fail(ErrorCodes.NOT_FOUND, `Path not found: ${targetPath}`);
|
|
13251
14271
|
return;
|
|
13252
14272
|
}
|
|
13253
|
-
const stats =
|
|
14273
|
+
const stats = fs24.statSync(targetPath);
|
|
13254
14274
|
if (stats.isFile()) {
|
|
13255
14275
|
const result = validateSkillFile(targetPath);
|
|
13256
14276
|
results.push(result);
|
|
@@ -13283,7 +14303,7 @@ var skillValidateCommand = new Command("validate").description("Validate local s
|
|
|
13283
14303
|
});
|
|
13284
14304
|
function validateSkillFile(filePath) {
|
|
13285
14305
|
try {
|
|
13286
|
-
const content =
|
|
14306
|
+
const content = fs24.readFileSync(filePath, "utf-8");
|
|
13287
14307
|
const { frontmatter, issues } = extractSkillMetadata(content);
|
|
13288
14308
|
const errors = issues.map((i) => `${i.path}: ${i.message}`);
|
|
13289
14309
|
const warnings = [];
|
|
@@ -13309,9 +14329,9 @@ function validateSkillFile(filePath) {
|
|
|
13309
14329
|
}
|
|
13310
14330
|
}
|
|
13311
14331
|
function findSkillFiles(dir, files = []) {
|
|
13312
|
-
const entries =
|
|
14332
|
+
const entries = fs24.readdirSync(dir, { withFileTypes: true });
|
|
13313
14333
|
for (const entry of entries) {
|
|
13314
|
-
const fullPath =
|
|
14334
|
+
const fullPath = path19.join(dir, entry.name);
|
|
13315
14335
|
if (entry.isDirectory()) {
|
|
13316
14336
|
if (!entry.name.startsWith(".")) {
|
|
13317
14337
|
findSkillFiles(fullPath, files);
|
|
@@ -13325,85 +14345,76 @@ function findSkillFiles(dir, files = []) {
|
|
|
13325
14345
|
|
|
13326
14346
|
// src/commands/skill/sync.ts
|
|
13327
14347
|
init_cjs_shims();
|
|
13328
|
-
|
|
14348
|
+
init_symlink();
|
|
14349
|
+
init_paths();
|
|
14350
|
+
var fs25 = __toESM(require("fs"));
|
|
14351
|
+
var path20 = __toESM(require("path"));
|
|
14352
|
+
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
14353
|
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();
|
|
14354
|
+
const symlinks = listSkillSymlinks();
|
|
13337
14355
|
const warnings = [];
|
|
13338
14356
|
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;
|
|
14357
|
+
let valid = 0;
|
|
14358
|
+
let invalid = 0;
|
|
14359
|
+
let repaired = 0;
|
|
14360
|
+
let orphans = 0;
|
|
14361
|
+
for (const symlink of symlinks) {
|
|
14362
|
+
if (symlink.isValid) {
|
|
14363
|
+
valid += 1;
|
|
14364
|
+
} else {
|
|
14365
|
+
invalid += 1;
|
|
14366
|
+
warnings.push(`Invalid symlink: ${symlink.claudePath} -> ${symlink.target}`);
|
|
14367
|
+
if (options.fix && !options.dryRun) {
|
|
14368
|
+
const result = createSkillSymlink(symlink.name);
|
|
14369
|
+
if (result.success) {
|
|
14370
|
+
repaired += 1;
|
|
14371
|
+
} else {
|
|
14372
|
+
errors.push(`Failed to repair ${symlink.name}: ${result.error}`);
|
|
14373
|
+
}
|
|
13374
14374
|
}
|
|
13375
|
-
} catch (err) {
|
|
13376
|
-
errors.push(err instanceof Error ? err.message : "Failed to load skill");
|
|
13377
|
-
skipped += 1;
|
|
13378
14375
|
}
|
|
13379
14376
|
}
|
|
13380
|
-
const
|
|
13381
|
-
|
|
13382
|
-
|
|
13383
|
-
|
|
13384
|
-
|
|
14377
|
+
const skillsDir = getReflySkillsDir();
|
|
14378
|
+
if (fs25.existsSync(skillsDir)) {
|
|
14379
|
+
const entries = fs25.readdirSync(skillsDir, { withFileTypes: true });
|
|
14380
|
+
const symlinkNames = new Set(symlinks.map((s) => s.name));
|
|
14381
|
+
for (const entry of entries) {
|
|
14382
|
+
if (entry.isDirectory() && entry.name !== "base") {
|
|
14383
|
+
if (!symlinkNames.has(entry.name)) {
|
|
14384
|
+
orphans += 1;
|
|
14385
|
+
warnings.push(`Orphan directory (no symlink): ${path20.join(skillsDir, entry.name)}`);
|
|
14386
|
+
if (options.prune && !options.dryRun) {
|
|
14387
|
+
const result = createSkillSymlink(entry.name);
|
|
14388
|
+
if (result.success) {
|
|
14389
|
+
repaired += 1;
|
|
14390
|
+
}
|
|
14391
|
+
}
|
|
14392
|
+
}
|
|
14393
|
+
}
|
|
14394
|
+
}
|
|
13385
14395
|
}
|
|
13386
|
-
const
|
|
13387
|
-
|
|
13388
|
-
|
|
13389
|
-
|
|
13390
|
-
...registry,
|
|
13391
|
-
skills: finalSkills,
|
|
13392
|
-
updatedAt: now
|
|
13393
|
-
});
|
|
14396
|
+
for (const symlink of symlinks) {
|
|
14397
|
+
if (!symlink.isValid && options.prune && !options.dryRun) {
|
|
14398
|
+
removeSkillSymlink(symlink.name);
|
|
14399
|
+
}
|
|
13394
14400
|
}
|
|
13395
14401
|
const summary = {
|
|
13396
|
-
scanned:
|
|
13397
|
-
|
|
13398
|
-
|
|
13399
|
-
|
|
13400
|
-
|
|
13401
|
-
pruned,
|
|
14402
|
+
scanned: symlinks.length,
|
|
14403
|
+
valid,
|
|
14404
|
+
invalid,
|
|
14405
|
+
repaired,
|
|
14406
|
+
orphans,
|
|
13402
14407
|
warnings: warnings.length
|
|
13403
14408
|
};
|
|
13404
14409
|
ok("skill.sync", {
|
|
13405
14410
|
dryRun: Boolean(options.dryRun),
|
|
13406
14411
|
summary,
|
|
14412
|
+
symlinks: symlinks.map((s) => ({
|
|
14413
|
+
name: s.name,
|
|
14414
|
+
claudePath: s.claudePath,
|
|
14415
|
+
target: s.target,
|
|
14416
|
+
valid: s.isValid
|
|
14417
|
+
})),
|
|
13407
14418
|
warnings: warnings.length ? warnings : void 0,
|
|
13408
14419
|
errors: errors.length ? errors : void 0
|
|
13409
14420
|
});
|
|
@@ -13416,13 +14427,13 @@ var skillSyncCommand = new Command("sync").description("Sync local skill registr
|
|
|
13416
14427
|
});
|
|
13417
14428
|
|
|
13418
14429
|
// 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(
|
|
14430
|
+
var skillCommand = new Command("skill").description("Manage skill packages and local skills").addCommand(skillListCommand).addCommand(skillGetCommand).addCommand(skillCreateCommand).addCommand(skillUpdateCommand).addCommand(skillPublishCommand).addCommand(skillUnpublishCommand).addCommand(skillSearchCommand).addCommand(skillInstallCommand).addCommand(skillUninstallCommand).addCommand(skillInstallationsCommand).addCommand(skillRunCommand).addCommand(skillValidateCommand).addCommand(skillSyncCommand);
|
|
13420
14431
|
|
|
13421
14432
|
// src/bin/refly.ts
|
|
13422
14433
|
function getVersion() {
|
|
13423
14434
|
try {
|
|
13424
|
-
const pkgPath =
|
|
13425
|
-
const pkg = JSON.parse(
|
|
14435
|
+
const pkgPath = path21.join(__dirname, "..", "..", "package.json");
|
|
14436
|
+
const pkg = JSON.parse(fs26.readFileSync(pkgPath, "utf-8"));
|
|
13426
14437
|
return pkg.version || "0.1.0";
|
|
13427
14438
|
} catch {
|
|
13428
14439
|
return "0.1.0";
|