clawflowbang 1.0.1 → 1.1.0
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/README.md +164 -49
- package/bin/clawflowhub.js +150 -62
- package/package.json +17 -5
- package/src/commands/create.js +286 -0
- package/src/commands/cron.js +78 -18
- package/src/commands/doctor.js +146 -0
- package/src/commands/explore.js +49 -0
- package/src/commands/init.js +3 -3
- package/src/commands/register.js +83 -0
- package/src/commands/update.js +35 -0
- package/src/core/ConfigManager.js +132 -132
- package/src/core/CronManager.js +245 -245
- package/src/core/Installer.js +226 -109
- package/src/core/OpenClawCLI.js +52 -7
- package/src/core/TerminalUI.js +10 -13
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -35
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -23
- package/.github/pull_request_template.md +0 -19
- package/CODE_OF_CONDUCT.md +0 -29
- package/SECURITY.md +0 -20
- package/SUPPORT.md +0 -21
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register command - Register a local skill or agent via symlink
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require("chalk");
|
|
6
|
+
const fs = require("fs-extra");
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const ClawFlow = require("../index");
|
|
9
|
+
|
|
10
|
+
module.exports = async function registerCommand(targetPath) {
|
|
11
|
+
const hub = new ClawFlow();
|
|
12
|
+
const sourcePath = path.resolve(process.cwd(), targetPath || ".");
|
|
13
|
+
|
|
14
|
+
console.log(chalk.cyan.bold("\n🏷️ ClawFlow Register\n"));
|
|
15
|
+
|
|
16
|
+
// 1. Verify source
|
|
17
|
+
const skillYaml = path.join(sourcePath, "skill.yaml");
|
|
18
|
+
const agentYaml = path.join(sourcePath, "agent.yaml");
|
|
19
|
+
const skillMd = path.join(sourcePath, "SKILL.md");
|
|
20
|
+
|
|
21
|
+
if (
|
|
22
|
+
!fs.existsSync(skillYaml) &&
|
|
23
|
+
!fs.existsSync(agentYaml) &&
|
|
24
|
+
!fs.existsSync(skillMd)
|
|
25
|
+
) {
|
|
26
|
+
console.error(
|
|
27
|
+
chalk.red(
|
|
28
|
+
`❌ Error: No skill.yaml, agent.yaml, or SKILL.md found at ${sourcePath}`,
|
|
29
|
+
),
|
|
30
|
+
);
|
|
31
|
+
console.log(
|
|
32
|
+
chalk.gray(
|
|
33
|
+
" Please make sure you are in the correct directory or provide a path.",
|
|
34
|
+
),
|
|
35
|
+
);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const name = path.basename(sourcePath);
|
|
40
|
+
const skillsPath = hub.config.getSkillsPath();
|
|
41
|
+
const targetPathInWorkspace = path.join(skillsPath, name);
|
|
42
|
+
|
|
43
|
+
// 2. Register via symlink
|
|
44
|
+
try {
|
|
45
|
+
process.stdout.write(chalk.white(` Registering ${chalk.bold(name)}... `));
|
|
46
|
+
|
|
47
|
+
fs.ensureDirSync(path.dirname(targetPathInWorkspace));
|
|
48
|
+
if (fs.existsSync(targetPathInWorkspace)) {
|
|
49
|
+
// Check if it's already a symlink
|
|
50
|
+
const stats = fs.lstatSync(targetPathInWorkspace);
|
|
51
|
+
if (stats.isSymbolicLink()) {
|
|
52
|
+
fs.removeSync(targetPathInWorkspace);
|
|
53
|
+
} else {
|
|
54
|
+
const { overwrite } = await require("inquirer").prompt([
|
|
55
|
+
{
|
|
56
|
+
type: "confirm",
|
|
57
|
+
name: "overwrite",
|
|
58
|
+
message: `\n Directory ${name} already exists in skills workspace. Overwrite with symlink?`,
|
|
59
|
+
default: false,
|
|
60
|
+
},
|
|
61
|
+
]);
|
|
62
|
+
if (!overwrite) {
|
|
63
|
+
console.log(chalk.yellow("\n Aborted."));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
fs.removeSync(targetPathInWorkspace);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fs.ensureSymlinkSync(sourcePath, targetPathInWorkspace, "junction");
|
|
71
|
+
process.stdout.write(chalk.green("✓\n"));
|
|
72
|
+
|
|
73
|
+
// 3. Verification
|
|
74
|
+
console.log(chalk.gray(` Path: ${targetPathInWorkspace}`));
|
|
75
|
+
console.log(chalk.green("\n✅ Successfully registered to OpenClaw!"));
|
|
76
|
+
console.log(chalk.white("\nNext steps:"));
|
|
77
|
+
console.log(chalk.gray(' - Run "clawflow status" to see your skill'));
|
|
78
|
+
console.log(chalk.gray(' - Use "clawflow cron-add" to schedule it\n'));
|
|
79
|
+
} catch (err) {
|
|
80
|
+
console.error(chalk.red("\n❌ Registration failed:"), err.message);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update command - Check for updates
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require("chalk");
|
|
6
|
+
const pkg = require("../../package.json");
|
|
7
|
+
const { execSync } = require("child_process");
|
|
8
|
+
|
|
9
|
+
module.exports = async function updateCommand() {
|
|
10
|
+
console.log(chalk.cyan.bold("\n🔄 Checking for ClawFlow updates...\n"));
|
|
11
|
+
console.log(chalk.gray(` Current version: ${pkg.version}`));
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const latest = execSync(`npm show ${pkg.name} version`, { stdio: "pipe" })
|
|
15
|
+
.toString()
|
|
16
|
+
.trim();
|
|
17
|
+
|
|
18
|
+
if (latest === pkg.version) {
|
|
19
|
+
console.log(chalk.green("✨ You are already using the latest version!"));
|
|
20
|
+
} else {
|
|
21
|
+
console.log(
|
|
22
|
+
chalk.yellow(`🚀 A new version is available: ${chalk.bold(latest)}`),
|
|
23
|
+
);
|
|
24
|
+
console.log(chalk.white("\nTo update, run:"));
|
|
25
|
+
console.log(chalk.cyan(` npm install -g ${pkg.name}`));
|
|
26
|
+
}
|
|
27
|
+
} catch (e) {
|
|
28
|
+
console.log(
|
|
29
|
+
chalk.red(
|
|
30
|
+
"❌ Failed to check for updates. Please check your internet connection.",
|
|
31
|
+
),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
console.log();
|
|
35
|
+
};
|
|
@@ -6,13 +6,13 @@ const fs = require('fs-extra');
|
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const os = require('os');
|
|
8
8
|
|
|
9
|
-
class ConfigManager {
|
|
10
|
-
constructor(configPath = null, options = {}) {
|
|
11
|
-
this.configPath = configPath || this.getDefaultConfigPath();
|
|
12
|
-
this.overrides = options;
|
|
13
|
-
this.config = null;
|
|
14
|
-
this.ensureDirectories();
|
|
15
|
-
}
|
|
9
|
+
class ConfigManager {
|
|
10
|
+
constructor(configPath = null, options = {}) {
|
|
11
|
+
this.configPath = configPath || this.getDefaultConfigPath();
|
|
12
|
+
this.overrides = options;
|
|
13
|
+
this.config = null;
|
|
14
|
+
this.ensureDirectories();
|
|
15
|
+
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* ได้รับ default config path ตาม OS
|
|
@@ -32,55 +32,55 @@ class ConfigManager {
|
|
|
32
32
|
/**
|
|
33
33
|
* สร้างโฟลเดอร์ที่จำเป็น
|
|
34
34
|
*/
|
|
35
|
-
ensureDirectories() {
|
|
36
|
-
const configFile = path.join(this.configPath, 'config.json');
|
|
37
|
-
const defaultConfig = this.getDefaultConfig();
|
|
38
|
-
const existingConfig = fs.existsSync(configFile) ? fs.readJsonSync(configFile) : {};
|
|
39
|
-
const mergedConfig = this.applyOpenClawOverrides({
|
|
40
|
-
...defaultConfig,
|
|
41
|
-
...existingConfig,
|
|
42
|
-
openclaw: {
|
|
43
|
-
...defaultConfig.openclaw,
|
|
44
|
-
...(existingConfig.openclaw || {}),
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
const dirs = [
|
|
49
|
-
this.configPath,
|
|
50
|
-
path.dirname(mergedConfig.openclaw.skillsPath),
|
|
51
|
-
mergedConfig.openclaw.skillsPath,
|
|
52
|
-
path.dirname(mergedConfig.openclaw.cronJobsFile),
|
|
53
|
-
path.join(this.configPath, 'logs'),
|
|
54
|
-
path.join(this.configPath, 'packages'),
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
dirs.forEach((dir) => {
|
|
58
|
-
fs.ensureDirSync(dir);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
if (!fs.existsSync(configFile) || JSON.stringify(existingConfig) !== JSON.stringify(mergedConfig)) {
|
|
62
|
-
fs.writeJsonSync(configFile, mergedConfig, { spaces: 2 });
|
|
63
|
-
}
|
|
64
|
-
}
|
|
35
|
+
ensureDirectories() {
|
|
36
|
+
const configFile = path.join(this.configPath, 'config.json');
|
|
37
|
+
const defaultConfig = this.getDefaultConfig();
|
|
38
|
+
const existingConfig = fs.existsSync(configFile) ? fs.readJsonSync(configFile) : {};
|
|
39
|
+
const mergedConfig = this.applyOpenClawOverrides({
|
|
40
|
+
...defaultConfig,
|
|
41
|
+
...existingConfig,
|
|
42
|
+
openclaw: {
|
|
43
|
+
...defaultConfig.openclaw,
|
|
44
|
+
...(existingConfig.openclaw || {}),
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const dirs = [
|
|
49
|
+
this.configPath,
|
|
50
|
+
path.dirname(mergedConfig.openclaw.skillsPath),
|
|
51
|
+
mergedConfig.openclaw.skillsPath,
|
|
52
|
+
path.dirname(mergedConfig.openclaw.cronJobsFile),
|
|
53
|
+
path.join(this.configPath, 'logs'),
|
|
54
|
+
path.join(this.configPath, 'packages'),
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
dirs.forEach((dir) => {
|
|
58
|
+
fs.ensureDirSync(dir);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (!fs.existsSync(configFile) || JSON.stringify(existingConfig) !== JSON.stringify(mergedConfig)) {
|
|
62
|
+
fs.writeJsonSync(configFile, mergedConfig, { spaces: 2 });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
67
|
* Config เริ่มต้น
|
|
68
68
|
*/
|
|
69
|
-
getDefaultConfig() {
|
|
70
|
-
const openclawHome = path.join(os.homedir(), '.openclaw');
|
|
71
|
-
const workspacePath = path.join(openclawHome, 'workspace');
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
version: '1.0.0',
|
|
75
|
-
openclaw: {
|
|
76
|
-
baseUrl: 'http://localhost:
|
|
77
|
-
apiKey: null,
|
|
78
|
-
cliBin: 'openclaw',
|
|
79
|
-
clawhubBin: 'clawhub',
|
|
80
|
-
workspacePath,
|
|
81
|
-
skillsPath: path.join(workspacePath, 'skills'),
|
|
82
|
-
cronJobsFile: path.join(openclawHome, 'cron', 'jobs.json'),
|
|
83
|
-
},
|
|
69
|
+
getDefaultConfig() {
|
|
70
|
+
const openclawHome = path.join(os.homedir(), '.openclaw');
|
|
71
|
+
const workspacePath = path.join(openclawHome, 'workspace');
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
version: '1.0.0',
|
|
75
|
+
openclaw: {
|
|
76
|
+
baseUrl: 'http://localhost:18789',
|
|
77
|
+
apiKey: null,
|
|
78
|
+
cliBin: 'openclaw',
|
|
79
|
+
clawhubBin: 'clawhub',
|
|
80
|
+
workspacePath,
|
|
81
|
+
skillsPath: path.join(workspacePath, 'skills'),
|
|
82
|
+
cronJobsFile: path.join(openclawHome, 'cron', 'jobs.json'),
|
|
83
|
+
},
|
|
84
84
|
registry: {
|
|
85
85
|
url: 'https://registry.clawflowhub.dev',
|
|
86
86
|
cacheExpiry: 3600, // วินาที
|
|
@@ -93,34 +93,34 @@ class ConfigManager {
|
|
|
93
93
|
installed: {},
|
|
94
94
|
crons: [],
|
|
95
95
|
lastUpdate: null,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
applyOpenClawOverrides(config) {
|
|
100
|
-
return {
|
|
101
|
-
...config,
|
|
102
|
-
openclaw: {
|
|
103
|
-
...(config.openclaw || {}),
|
|
104
|
-
...(this.overrides.skillsPath ? { skillsPath: this.overrides.skillsPath } : {}),
|
|
105
|
-
...(this.overrides.cronJobsFile ? { cronJobsFile: this.overrides.cronJobsFile } : {}),
|
|
106
|
-
...(this.overrides.openclawBin ? { cliBin: this.overrides.openclawBin } : {}),
|
|
107
|
-
...(this.overrides.clawhubBin ? { clawhubBin: this.overrides.clawhubBin } : {}),
|
|
108
|
-
},
|
|
109
|
-
};
|
|
110
|
-
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
applyOpenClawOverrides(config) {
|
|
100
|
+
return {
|
|
101
|
+
...config,
|
|
102
|
+
openclaw: {
|
|
103
|
+
...(config.openclaw || {}),
|
|
104
|
+
...(this.overrides.skillsPath ? { skillsPath: this.overrides.skillsPath } : {}),
|
|
105
|
+
...(this.overrides.cronJobsFile ? { cronJobsFile: this.overrides.cronJobsFile } : {}),
|
|
106
|
+
...(this.overrides.openclawBin ? { cliBin: this.overrides.openclawBin } : {}),
|
|
107
|
+
...(this.overrides.clawhubBin ? { clawhubBin: this.overrides.clawhubBin } : {}),
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
113
|
* โหลด config
|
|
114
114
|
*/
|
|
115
|
-
loadConfig() {
|
|
116
|
-
const configFile = path.join(this.configPath, 'config.json');
|
|
117
|
-
if (fs.existsSync(configFile)) {
|
|
118
|
-
this.config = fs.readJsonSync(configFile);
|
|
119
|
-
} else {
|
|
120
|
-
this.config = this.applyOpenClawOverrides(this.getDefaultConfig());
|
|
121
|
-
}
|
|
122
|
-
return this.config;
|
|
123
|
-
}
|
|
115
|
+
loadConfig() {
|
|
116
|
+
const configFile = path.join(this.configPath, 'config.json');
|
|
117
|
+
if (fs.existsSync(configFile)) {
|
|
118
|
+
this.config = fs.readJsonSync(configFile);
|
|
119
|
+
} else {
|
|
120
|
+
this.config = this.applyOpenClawOverrides(this.getDefaultConfig());
|
|
121
|
+
}
|
|
122
|
+
return this.config;
|
|
123
|
+
}
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
126
|
* บันทึก config
|
|
@@ -172,25 +172,25 @@ class ConfigManager {
|
|
|
172
172
|
/**
|
|
173
173
|
* ดึง path ของ skills
|
|
174
174
|
*/
|
|
175
|
-
getSkillsPath() {
|
|
176
|
-
const config = this.getConfig();
|
|
177
|
-
return config.openclaw?.skillsPath || path.join(this.configPath, 'skills');
|
|
178
|
-
}
|
|
175
|
+
getSkillsPath() {
|
|
176
|
+
const config = this.getConfig();
|
|
177
|
+
return config.openclaw?.skillsPath || path.join(this.configPath, 'skills');
|
|
178
|
+
}
|
|
179
179
|
|
|
180
180
|
/**
|
|
181
181
|
* ดึง path ของ crons
|
|
182
182
|
*/
|
|
183
|
-
getCronsPath() {
|
|
184
|
-
return path.dirname(this.getCronJobsFilePath());
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* ดึง path ของ cron jobs file
|
|
189
|
-
*/
|
|
190
|
-
getCronJobsFilePath() {
|
|
191
|
-
const config = this.getConfig();
|
|
192
|
-
return config.openclaw?.cronJobsFile || path.join(this.configPath, 'crons', 'jobs.json');
|
|
193
|
-
}
|
|
183
|
+
getCronsPath() {
|
|
184
|
+
return path.dirname(this.getCronJobsFilePath());
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* ดึง path ของ cron jobs file
|
|
189
|
+
*/
|
|
190
|
+
getCronJobsFilePath() {
|
|
191
|
+
const config = this.getConfig();
|
|
192
|
+
return config.openclaw?.cronJobsFile || path.join(this.configPath, 'crons', 'jobs.json');
|
|
193
|
+
}
|
|
194
194
|
|
|
195
195
|
/**
|
|
196
196
|
* ดึง path ของ logs
|
|
@@ -235,16 +235,16 @@ class ConfigManager {
|
|
|
235
235
|
/**
|
|
236
236
|
* เพิ่ม cronjob
|
|
237
237
|
*/
|
|
238
|
-
addCron(cronInfo) {
|
|
239
|
-
const config = this.getConfig();
|
|
240
|
-
if (!config.crons) {
|
|
241
|
-
config.crons = [];
|
|
242
|
-
}
|
|
243
|
-
config.crons.push({
|
|
244
|
-
id: cronInfo.id || Date.now().toString(),
|
|
245
|
-
...cronInfo,
|
|
246
|
-
createdAt: new Date().toISOString(),
|
|
247
|
-
});
|
|
238
|
+
addCron(cronInfo) {
|
|
239
|
+
const config = this.getConfig();
|
|
240
|
+
if (!config.crons) {
|
|
241
|
+
config.crons = [];
|
|
242
|
+
}
|
|
243
|
+
config.crons.push({
|
|
244
|
+
id: cronInfo.id || Date.now().toString(),
|
|
245
|
+
...cronInfo,
|
|
246
|
+
createdAt: new Date().toISOString(),
|
|
247
|
+
});
|
|
248
248
|
this.saveConfig();
|
|
249
249
|
return config.crons[config.crons.length - 1];
|
|
250
250
|
}
|
|
@@ -252,37 +252,37 @@ class ConfigManager {
|
|
|
252
252
|
/**
|
|
253
253
|
* ลบ cronjob
|
|
254
254
|
*/
|
|
255
|
-
removeCron(cronId) {
|
|
256
|
-
const config = this.getConfig();
|
|
257
|
-
if (config.crons) {
|
|
258
|
-
config.crons = config.crons.filter(cron => cron.id !== cronId);
|
|
259
|
-
this.saveConfig();
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* แก้ไข cronjob
|
|
265
|
-
*/
|
|
266
|
-
updateCron(cronId, patch = {}) {
|
|
267
|
-
const config = this.getConfig();
|
|
268
|
-
if (!config.crons) {
|
|
269
|
-
return null;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const idx = config.crons.findIndex((c) => c.id === cronId);
|
|
273
|
-
if (idx === -1) {
|
|
274
|
-
return null;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
config.crons[idx] = {
|
|
278
|
-
...config.crons[idx],
|
|
279
|
-
...patch,
|
|
280
|
-
updatedAt: new Date().toISOString(),
|
|
281
|
-
};
|
|
282
|
-
this.saveConfig();
|
|
283
|
-
|
|
284
|
-
return config.crons[idx];
|
|
285
|
-
}
|
|
255
|
+
removeCron(cronId) {
|
|
256
|
+
const config = this.getConfig();
|
|
257
|
+
if (config.crons) {
|
|
258
|
+
config.crons = config.crons.filter(cron => cron.id !== cronId);
|
|
259
|
+
this.saveConfig();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* แก้ไข cronjob
|
|
265
|
+
*/
|
|
266
|
+
updateCron(cronId, patch = {}) {
|
|
267
|
+
const config = this.getConfig();
|
|
268
|
+
if (!config.crons) {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const idx = config.crons.findIndex((c) => c.id === cronId);
|
|
273
|
+
if (idx === -1) {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
config.crons[idx] = {
|
|
278
|
+
...config.crons[idx],
|
|
279
|
+
...patch,
|
|
280
|
+
updatedAt: new Date().toISOString(),
|
|
281
|
+
};
|
|
282
|
+
this.saveConfig();
|
|
283
|
+
|
|
284
|
+
return config.crons[idx];
|
|
285
|
+
}
|
|
286
286
|
|
|
287
287
|
/**
|
|
288
288
|
* ดึงรายการ cronjobs
|