clawflowbang 1.0.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/.eslintrc.json +38 -0
- package/README.md +1 -0
- package/__tests__/config-manager.test.js +52 -0
- package/__tests__/cron-format.test.js +26 -0
- package/__tests__/cron-manager.local.test.js +65 -0
- package/__tests__/openclaw-cli.test.js +51 -0
- package/bin/clawflowhub.js +125 -0
- package/docs/clawhub-package-format.md +179 -0
- package/examples/npm-package-example/package.json +53 -0
- package/package.json +45 -0
- package/src/commands/cron.js +123 -0
- package/src/commands/init.js +112 -0
- package/src/commands/install.js +38 -0
- package/src/commands/list.js +77 -0
- package/src/commands/remove.js +27 -0
- package/src/commands/search.js +61 -0
- package/src/commands/status.js +68 -0
- package/src/core/ConfigManager.js +295 -0
- package/src/core/CronFormat.js +68 -0
- package/src/core/CronManager.js +512 -0
- package/src/core/Installer.js +352 -0
- package/src/core/NPMRegistry.js +285 -0
- package/src/core/OpenClawCLI.js +265 -0
- package/src/core/PackageResolver.js +94 -0
- package/src/core/Registry.js +400 -0
- package/src/index.js +91 -0
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"root": true,
|
|
3
|
+
"env": {
|
|
4
|
+
"node": true,
|
|
5
|
+
"es2021": true
|
|
6
|
+
},
|
|
7
|
+
"extends": [
|
|
8
|
+
"eslint:recommended"
|
|
9
|
+
],
|
|
10
|
+
"parserOptions": {
|
|
11
|
+
"ecmaVersion": 12
|
|
12
|
+
},
|
|
13
|
+
"ignorePatterns": [
|
|
14
|
+
"node_modules/",
|
|
15
|
+
"coverage/"
|
|
16
|
+
],
|
|
17
|
+
"rules": {
|
|
18
|
+
"no-console": "off",
|
|
19
|
+
"no-unused-vars": [
|
|
20
|
+
"warn",
|
|
21
|
+
{
|
|
22
|
+
"argsIgnorePattern": "^_",
|
|
23
|
+
"varsIgnorePattern": "^_"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"overrides": [
|
|
28
|
+
{
|
|
29
|
+
"files": [
|
|
30
|
+
"**/*.test.js",
|
|
31
|
+
"__tests__/**/*.js"
|
|
32
|
+
],
|
|
33
|
+
"env": {
|
|
34
|
+
"jest": true
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# ClawFlow
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const ConfigManager = require('../src/core/ConfigManager');
|
|
5
|
+
|
|
6
|
+
function makeTempDir(prefix) {
|
|
7
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
describe('ConfigManager', () => {
|
|
11
|
+
test('applies path and bin overrides into openclaw config', () => {
|
|
12
|
+
const configDir = makeTempDir('cfh-config-');
|
|
13
|
+
const skillsPath = path.join(configDir, 'custom-skills');
|
|
14
|
+
const cronJobsFile = path.join(configDir, 'custom-cron', 'jobs.json');
|
|
15
|
+
|
|
16
|
+
const manager = new ConfigManager(configDir, {
|
|
17
|
+
skillsPath,
|
|
18
|
+
cronJobsFile,
|
|
19
|
+
openclawBin: '/usr/local/bin/openclaw',
|
|
20
|
+
clawhubBin: '/usr/local/bin/clawhub',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const config = manager.getConfig();
|
|
24
|
+
expect(config.openclaw.skillsPath).toBe(skillsPath);
|
|
25
|
+
expect(config.openclaw.cronJobsFile).toBe(cronJobsFile);
|
|
26
|
+
expect(config.openclaw.cliBin).toBe('/usr/local/bin/openclaw');
|
|
27
|
+
expect(config.openclaw.clawhubBin).toBe('/usr/local/bin/clawhub');
|
|
28
|
+
expect(manager.getCronJobsFilePath()).toBe(cronJobsFile);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('addCron preserves provided id and updateCron mutates fields', () => {
|
|
32
|
+
const configDir = makeTempDir('cfh-config-');
|
|
33
|
+
const manager = new ConfigManager(configDir);
|
|
34
|
+
|
|
35
|
+
manager.addCron({
|
|
36
|
+
id: 'job-123',
|
|
37
|
+
skill: 'crypto-price',
|
|
38
|
+
schedule: '*/5 * * * *',
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const updated = manager.updateCron('job-123', {
|
|
42
|
+
schedule: '0 * * * *',
|
|
43
|
+
description: 'hourly',
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
expect(updated).toBeTruthy();
|
|
47
|
+
expect(updated.id).toBe('job-123');
|
|
48
|
+
expect(updated.schedule).toBe('0 * * * *');
|
|
49
|
+
expect(updated.description).toBe('hourly');
|
|
50
|
+
expect(updated.updatedAt).toBeTruthy();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const { normalizeCronExpression } = require('../src/core/CronFormat');
|
|
2
|
+
|
|
3
|
+
describe('CronFormat.normalizeCronExpression', () => {
|
|
4
|
+
test('accepts valid cron expressions as-is', () => {
|
|
5
|
+
expect(normalizeCronExpression('*/5 * * * *')).toBe('*/5 * * * *');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
test('normalizes preset aliases', () => {
|
|
9
|
+
expect(normalizeCronExpression('@daily')).toBe('0 0 * * *');
|
|
10
|
+
expect(normalizeCronExpression('@hourly')).toBe('0 * * * *');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test('normalizes shorthand durations', () => {
|
|
14
|
+
expect(normalizeCronExpression('15m')).toBe('*/15 * * * *');
|
|
15
|
+
expect(normalizeCronExpression('every 2h')).toBe('0 */2 * * *');
|
|
16
|
+
expect(normalizeCronExpression('1d')).toBe('0 0 */1 * *');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('throws on invalid cron expressions', () => {
|
|
20
|
+
expect(() => normalizeCronExpression('abc def')).toThrow(/ไม่ถูกต้อง/);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('throws on unsupported duration shorthands', () => {
|
|
24
|
+
expect(() => normalizeCronExpression('70m')).toThrow(/ไม่รองรับ/);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const ConfigManager = require('../src/core/ConfigManager');
|
|
5
|
+
const CronManager = require('../src/core/CronManager');
|
|
6
|
+
|
|
7
|
+
function makeTempDir(prefix) {
|
|
8
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('CronManager local mode', () => {
|
|
12
|
+
test('add/edit/list/remove lifecycle works with normalized schedules', async () => {
|
|
13
|
+
const root = makeTempDir('cfh-cron-');
|
|
14
|
+
const configPath = path.join(root, 'config');
|
|
15
|
+
const cronJobsFile = path.join(root, 'cron', 'jobs.json');
|
|
16
|
+
|
|
17
|
+
const configManager = new ConfigManager(configPath, {
|
|
18
|
+
cronJobsFile,
|
|
19
|
+
openclawBin: 'notfound-openclaw',
|
|
20
|
+
});
|
|
21
|
+
const cronManager = new CronManager(configManager);
|
|
22
|
+
|
|
23
|
+
expect(cronManager.useOpenClawCron).toBe(false);
|
|
24
|
+
|
|
25
|
+
const added = await cronManager.add('smoke-skill', 'every 15m', { foo: 'bar' }, 'demo');
|
|
26
|
+
expect(added.id).toBeTruthy();
|
|
27
|
+
expect(added.schedule).toBe('*/15 * * * *');
|
|
28
|
+
|
|
29
|
+
const listed = cronManager.list();
|
|
30
|
+
expect(listed).toHaveLength(1);
|
|
31
|
+
expect(listed[0].schedule).toBe('*/15 * * * *');
|
|
32
|
+
|
|
33
|
+
const edited = await cronManager.edit(added.id, {
|
|
34
|
+
schedule: '@daily',
|
|
35
|
+
description: 'daily run',
|
|
36
|
+
params: { foo: 'baz' },
|
|
37
|
+
});
|
|
38
|
+
expect(edited.schedule).toBe('0 0 * * *');
|
|
39
|
+
expect(edited.description).toBe('daily run');
|
|
40
|
+
expect(edited.params).toEqual({ foo: 'baz' });
|
|
41
|
+
|
|
42
|
+
const listedAfterEdit = cronManager.list();
|
|
43
|
+
expect(listedAfterEdit).toHaveLength(1);
|
|
44
|
+
expect(listedAfterEdit[0].schedule).toBe('0 0 * * *');
|
|
45
|
+
|
|
46
|
+
await cronManager.remove(added.id);
|
|
47
|
+
expect(cronManager.list()).toEqual([]);
|
|
48
|
+
|
|
49
|
+
cronManager.stopAll();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('rejects invalid schedules', async () => {
|
|
53
|
+
const root = makeTempDir('cfh-cron-');
|
|
54
|
+
const configPath = path.join(root, 'config');
|
|
55
|
+
const cronJobsFile = path.join(root, 'cron', 'jobs.json');
|
|
56
|
+
|
|
57
|
+
const configManager = new ConfigManager(configPath, {
|
|
58
|
+
cronJobsFile,
|
|
59
|
+
openclawBin: 'notfound-openclaw',
|
|
60
|
+
});
|
|
61
|
+
const cronManager = new CronManager(configManager);
|
|
62
|
+
|
|
63
|
+
await expect(cronManager.add('smoke-skill', 'wrong schedule', {})).rejects.toThrow(/ไม่ถูกต้อง/);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const OpenClawCLI = require('../src/core/OpenClawCLI');
|
|
2
|
+
|
|
3
|
+
function createCli() {
|
|
4
|
+
return new OpenClawCLI({
|
|
5
|
+
getConfig() {
|
|
6
|
+
return {
|
|
7
|
+
openclaw: {
|
|
8
|
+
cliBin: 'openclaw',
|
|
9
|
+
clawhubBin: 'clawhub',
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
describe('OpenClawCLI git fallback helpers', () => {
|
|
17
|
+
test('resolveGitRepository from explicit fields', () => {
|
|
18
|
+
const cli = createCli();
|
|
19
|
+
expect(
|
|
20
|
+
cli.resolveGitRepository({
|
|
21
|
+
name: 'crypto-price',
|
|
22
|
+
repository: 'https://github.com/acme/crypto-price.git',
|
|
23
|
+
}),
|
|
24
|
+
).toBe('https://github.com/acme/crypto-price.git');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('resolveGitRepository from github source + owner/repo name', () => {
|
|
28
|
+
const cli = createCli();
|
|
29
|
+
expect(
|
|
30
|
+
cli.resolveGitRepository({
|
|
31
|
+
source: 'github',
|
|
32
|
+
name: 'acme/my-skill',
|
|
33
|
+
}),
|
|
34
|
+
).toBe('https://github.com/acme/my-skill.git');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('resolveSkillDirName from url and scoped names', () => {
|
|
38
|
+
const cli = createCli();
|
|
39
|
+
expect(
|
|
40
|
+
cli.resolveSkillDirName({
|
|
41
|
+
name: 'https://github.com/acme/skill-x.git',
|
|
42
|
+
}),
|
|
43
|
+
).toBe('skill-x');
|
|
44
|
+
|
|
45
|
+
expect(
|
|
46
|
+
cli.resolveSkillDirName({
|
|
47
|
+
name: 'acme/skill-y',
|
|
48
|
+
}),
|
|
49
|
+
).toBe('skill-y');
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const pkg = require('../package.json');
|
|
6
|
+
|
|
7
|
+
// Import commands
|
|
8
|
+
const installCommand = require('../src/commands/install');
|
|
9
|
+
const listCommand = require('../src/commands/list');
|
|
10
|
+
const removeCommand = require('../src/commands/remove');
|
|
11
|
+
const cronCommand = require('../src/commands/cron');
|
|
12
|
+
const statusCommand = require('../src/commands/status');
|
|
13
|
+
const initCommand = require('../src/commands/init');
|
|
14
|
+
const searchCommand = require('../src/commands/search');
|
|
15
|
+
|
|
16
|
+
// Banner
|
|
17
|
+
console.log(chalk.cyan.bold(`
|
|
18
|
+
╔══════════════════════════════════════════════════════════╗
|
|
19
|
+
║ ║
|
|
20
|
+
║ 🐾 ${chalk.white.bold('ClawFlow')} - Skill & Cron Installer for OpenClaw ║
|
|
21
|
+
║ ║
|
|
22
|
+
║ ${chalk.gray('ติดตั้ง skill พร้อมตั้งค่าใช้งานทันที')} ║
|
|
23
|
+
║ ║
|
|
24
|
+
╚══════════════════════════════════════════════════════════╝
|
|
25
|
+
`));
|
|
26
|
+
|
|
27
|
+
program
|
|
28
|
+
.name('clawflow')
|
|
29
|
+
.description('ติดตั้ง OpenClaw skills พร้อม cronjob ให้พร้อมใช้งาน')
|
|
30
|
+
.version(pkg.version, '-v, --version', 'แสดงเวอร์ชัน');
|
|
31
|
+
|
|
32
|
+
// Install command
|
|
33
|
+
program
|
|
34
|
+
.command('install <package>')
|
|
35
|
+
.alias('i')
|
|
36
|
+
.description('ติดตั้ง package พร้อม skills และ cronjobs')
|
|
37
|
+
.option('-g, --global', 'ติดตั้งแบบ global')
|
|
38
|
+
.option('-c, --config <path>', 'ระบุ path ของ config file')
|
|
39
|
+
.option('--skills-path <path>', 'ระบุ path ของ OpenClaw workspace skills')
|
|
40
|
+
.option('--cron-jobs <path>', 'ระบุ path ของ OpenClaw cron jobs.json')
|
|
41
|
+
.option('--openclaw-bin <path>', 'ระบุ binary ของ openclaw CLI')
|
|
42
|
+
.option('--clawhub-bin <path>', 'ระบุ binary ของ clawhub CLI')
|
|
43
|
+
.option('--no-cron', 'ติดตั้ง skill โดยไม่ตั้ง cronjob')
|
|
44
|
+
.option('--dry-run', 'แสดงว่าจะทำอะไรบ้างโดยไม่ติดตั้งจริง')
|
|
45
|
+
.action(installCommand);
|
|
46
|
+
|
|
47
|
+
// List command
|
|
48
|
+
program
|
|
49
|
+
.command('list')
|
|
50
|
+
.alias('ls')
|
|
51
|
+
.description('แสดงรายการ packages และ skills ที่ติดตั้ง')
|
|
52
|
+
.option('-a, --available', 'แสดง packages ที่สามารถติดตั้งได้')
|
|
53
|
+
.option('-i, --installed', 'แสดง packages ที่ติดตั้งแล้ว (default)')
|
|
54
|
+
.option('--npm', 'รวม packages จาก npm registry (ใช้กับ --available)')
|
|
55
|
+
.action(listCommand);
|
|
56
|
+
|
|
57
|
+
// Search command
|
|
58
|
+
program
|
|
59
|
+
.command('search <query>')
|
|
60
|
+
.alias('find')
|
|
61
|
+
.description('ค้นหา packages ใน registry')
|
|
62
|
+
.option('--no-npm', 'ไม่รวมผลลัพธ์จาก npm registry')
|
|
63
|
+
.action(searchCommand);
|
|
64
|
+
|
|
65
|
+
// Remove command
|
|
66
|
+
program
|
|
67
|
+
.command('remove <package>')
|
|
68
|
+
.alias('rm')
|
|
69
|
+
.description('ถอนการติดตั้ง package')
|
|
70
|
+
.option('-g, --global', 'ถอนการติดตั้งแบบ global')
|
|
71
|
+
.option('--keep-config', 'เก็บ config file ไว้')
|
|
72
|
+
.action(removeCommand);
|
|
73
|
+
|
|
74
|
+
// Cron command group
|
|
75
|
+
program
|
|
76
|
+
.command('cron-list')
|
|
77
|
+
.description('แสดงรายการ cronjobs ทั้งหมด')
|
|
78
|
+
.action(cronCommand.list);
|
|
79
|
+
|
|
80
|
+
program
|
|
81
|
+
.command('cron-add <skill>')
|
|
82
|
+
.description('เพิ่ม cronjob สำหรับ skill')
|
|
83
|
+
.option('-s, --schedule <expression>', 'cron schedule expression', '*/5 * * * *')
|
|
84
|
+
.option('-e, --every <duration>', 'รูปแบบย่อ เช่น 5m, 1h, 2d')
|
|
85
|
+
.option('-d, --description <text>', 'คำอธิบาย cronjob')
|
|
86
|
+
.option('-p, --params <json>', 'parameters สำหรับ skill')
|
|
87
|
+
.action(cronCommand.add);
|
|
88
|
+
|
|
89
|
+
program
|
|
90
|
+
.command('cron-edit <id>')
|
|
91
|
+
.description('แก้ไข cronjob')
|
|
92
|
+
.option('-s, --schedule <expression>', 'cron schedule expression ใหม่')
|
|
93
|
+
.option('-e, --every <duration>', 'รูปแบบย่อ เช่น 5m, 1h, 2d')
|
|
94
|
+
.option('-d, --description <text>', 'คำอธิบายใหม่')
|
|
95
|
+
.option('-p, --params <json>', 'parameters ใหม่ของ skill')
|
|
96
|
+
.action(cronCommand.edit);
|
|
97
|
+
|
|
98
|
+
program
|
|
99
|
+
.command('cron-remove <id>')
|
|
100
|
+
.description('ลบ cronjob')
|
|
101
|
+
.action(cronCommand.remove);
|
|
102
|
+
|
|
103
|
+
// Status command
|
|
104
|
+
program
|
|
105
|
+
.command('status')
|
|
106
|
+
.description('แสดงสถานะระบบ')
|
|
107
|
+
.action(statusCommand);
|
|
108
|
+
|
|
109
|
+
// Init command
|
|
110
|
+
program
|
|
111
|
+
.command('init')
|
|
112
|
+
.description('เริ่มต้นใช้งาน ClawFlow ในตำแหน่งปัจจุบัน')
|
|
113
|
+
.option('-f, --force', 'เขียนทับ config เดิม')
|
|
114
|
+
.action(initCommand);
|
|
115
|
+
|
|
116
|
+
// Global error handler
|
|
117
|
+
process.on('unhandledRejection', (err) => {
|
|
118
|
+
console.error(chalk.red('\n❌ เกิดข้อผิดพลาด:'), err.message);
|
|
119
|
+
if (process.env.DEBUG) {
|
|
120
|
+
console.error(err.stack);
|
|
121
|
+
}
|
|
122
|
+
process.exit(1);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
program.parse();
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# ClawFlow Package Format
|
|
2
|
+
|
|
3
|
+
Packages สำหรับ ClawFlow สามารถ publish ขึ้น npm registry ได้โดยมีรูปแบบดังนี้:
|
|
4
|
+
|
|
5
|
+
## 1. การระบุว่าเป็น ClawFlow Package
|
|
6
|
+
|
|
7
|
+
มี 3 วิธี:
|
|
8
|
+
|
|
9
|
+
### วิธีที่ 1: ใช้ Scope `@clawflow/`
|
|
10
|
+
```json
|
|
11
|
+
{
|
|
12
|
+
"name": "@clawflow/trading-kit"
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### วิธีที่ 2: ใช้ Keyword
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"name": "my-awesome-kit",
|
|
20
|
+
"keywords": ["clawflow", "trading", "crypto"]
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### วิธีที่ 3: ใช้ Field `clawflow` ใน package.json
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"name": "my-awesome-kit",
|
|
28
|
+
"clawflow": {
|
|
29
|
+
"skills": [...],
|
|
30
|
+
"crons": [...]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 2. Package Structure
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
my-package/
|
|
39
|
+
├── package.json # ต้องมี keyword "clawflow" หรือ field clawflow
|
|
40
|
+
├── clawflow.json # (optional) แยก config ออกมา
|
|
41
|
+
├── README.md
|
|
42
|
+
└── (other files)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 3. clawflow.json Format
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"$schema": "https://clawflowhub.dev/schema/v1.json",
|
|
50
|
+
"skills": [
|
|
51
|
+
{
|
|
52
|
+
"name": "binance-pro",
|
|
53
|
+
"version": "^1.0.0",
|
|
54
|
+
"source": "openclaw",
|
|
55
|
+
"repository": "https://github.com/owner/binance-pro-skill.git",
|
|
56
|
+
"description": "Binance trading skill"
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"crons": [
|
|
60
|
+
{
|
|
61
|
+
"skill": "crypto-price",
|
|
62
|
+
"schedule": "*/5 * * * *",
|
|
63
|
+
"params": {
|
|
64
|
+
"symbols": ["BTC", "ETH", "SOL"]
|
|
65
|
+
},
|
|
66
|
+
"description": "เช็คราคาคริปโตทุก 5 นาที",
|
|
67
|
+
"enabled": true
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"config": {
|
|
71
|
+
"binance-pro": {
|
|
72
|
+
"apiKey": {
|
|
73
|
+
"env": "BINANCE_API_KEY",
|
|
74
|
+
"required": true,
|
|
75
|
+
"description": "Binance API Key"
|
|
76
|
+
},
|
|
77
|
+
"secretKey": {
|
|
78
|
+
"env": "BINANCE_SECRET_KEY",
|
|
79
|
+
"required": true,
|
|
80
|
+
"description": "Binance Secret Key"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"postInstall": "กรุณาตั้งค่า BINANCE_API_KEY และ BINANCE_SECRET_KEY ใน environment variables"
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 4. Field Descriptions
|
|
89
|
+
|
|
90
|
+
### skills
|
|
91
|
+
รายการ skills ที่จะติดตั้ง
|
|
92
|
+
|
|
93
|
+
| Field | Type | Required | Description |
|
|
94
|
+
|-------|------|----------|-------------|
|
|
95
|
+
| `name` | string | Yes | ชื่อ skill |
|
|
96
|
+
| `version` | string | No | เวอร์ชัน (semver) |
|
|
97
|
+
| `source` | string | No | แหล่งที่มา (openclaw, npm, github) |
|
|
98
|
+
| `repository`/`repo`/`git` | string | No | Git URL สำหรับ fallback เมื่อหา skill ใน clawhub ไม่เจอ |
|
|
99
|
+
| `branch`/`tag`/`ref` | string | No | branch/tag/ref สำหรับ git clone |
|
|
100
|
+
| `description` | string | No | คำอธิบาย |
|
|
101
|
+
|
|
102
|
+
### crons
|
|
103
|
+
รายการ cronjobs ที่จะสร้าง
|
|
104
|
+
|
|
105
|
+
| Field | Type | Required | Description |
|
|
106
|
+
|-------|------|----------|-------------|
|
|
107
|
+
| `skill` | string | Yes | ชื่อ skill ที่จะรัน |
|
|
108
|
+
| `schedule` | string | Yes | Cron expression |
|
|
109
|
+
| `params` | object | No | Parameters ที่ส่งให้ skill |
|
|
110
|
+
| `description` | string | No | คำอธิบาย |
|
|
111
|
+
| `enabled` | boolean | No | เปิดใช้งานหรือไม่ (default: true) |
|
|
112
|
+
|
|
113
|
+
### config
|
|
114
|
+
Schema สำหรับการตั้งค่า package
|
|
115
|
+
|
|
116
|
+
| Field | Type | Required | Description |
|
|
117
|
+
|-------|------|----------|-------------|
|
|
118
|
+
| `env` | string | No | ชื่อ environment variable |
|
|
119
|
+
| `required` | boolean | No | บังคับต้องมีหรือไม่ |
|
|
120
|
+
| `default` | any | No | ค่า default |
|
|
121
|
+
| `description` | string | No | คำอธิบาย |
|
|
122
|
+
| `type` | string | No | ประเภท (string, number, array, object) |
|
|
123
|
+
|
|
124
|
+
## 5. ตัวอย่าง package.json สมบูรณ์
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"name": "@clawflowhub/trading-kit",
|
|
129
|
+
"version": "1.0.0",
|
|
130
|
+
"description": "ชุดเครื่องมือสำหรับเทรดคริปโต",
|
|
131
|
+
"keywords": ["clawflowhub", "trading", "crypto", "binance"],
|
|
132
|
+
"author": "Your Name",
|
|
133
|
+
"license": "MIT",
|
|
134
|
+
"clawflowhub": {
|
|
135
|
+
"skills": [
|
|
136
|
+
{ "name": "binance-pro", "version": "^1.0.0", "source": "openclaw" },
|
|
137
|
+
{ "name": "crypto-price", "version": "^1.0.0", "source": "openclaw" }
|
|
138
|
+
],
|
|
139
|
+
"crons": [
|
|
140
|
+
{
|
|
141
|
+
"skill": "crypto-price",
|
|
142
|
+
"schedule": "*/5 * * * *",
|
|
143
|
+
"params": { "symbols": ["BTC", "ETH"] },
|
|
144
|
+
"description": "เช็คราคาทุก 5 นาที"
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
"config": {
|
|
148
|
+
"binance-pro": {
|
|
149
|
+
"apiKey": { "env": "BINANCE_API_KEY", "required": true }
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 6. Publishing
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Publish ขึ้น npm
|
|
160
|
+
npm publish --access public
|
|
161
|
+
|
|
162
|
+
# ถ้าเป็น scoped package (@clawflowhub/xxx)
|
|
163
|
+
npm publish --access public
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## 7. การติดตั้ง
|
|
167
|
+
|
|
168
|
+
หลังจาก publish แล้ว ผู้ใช้สามารถติดตั้งได้โดย:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# ติดตั้งจาก npm
|
|
172
|
+
clawflowhub install @clawflowhub/trading-kit
|
|
173
|
+
|
|
174
|
+
# หรือ
|
|
175
|
+
clawflowhub install my-awesome-kit
|
|
176
|
+
|
|
177
|
+
# ติดตั้งเวอร์ชันเฉพาะ
|
|
178
|
+
clawflowhub install @clawflowhub/trading-kit@1.0.0
|
|
179
|
+
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@clawflow/example-kit",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "ตัวอย่าง ClawFlow Package สำหรับ npm registry",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"clawflow",
|
|
7
|
+
"example",
|
|
8
|
+
"demo"
|
|
9
|
+
],
|
|
10
|
+
"author": "ClawFlow Team",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/clawflow/example-kit.git"
|
|
15
|
+
},
|
|
16
|
+
"clawflow": {
|
|
17
|
+
"skills": [
|
|
18
|
+
{
|
|
19
|
+
"name": "hello-world",
|
|
20
|
+
"version": "^1.0.0",
|
|
21
|
+
"source": "openclaw",
|
|
22
|
+
"description": "พูดว่า Hello World"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "time-logger",
|
|
26
|
+
"version": "^1.0.0",
|
|
27
|
+
"source": "openclaw",
|
|
28
|
+
"description": "บันทึกเวลาปัจจุบัน"
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"crons": [
|
|
32
|
+
{
|
|
33
|
+
"skill": "time-logger",
|
|
34
|
+
"schedule": "0 * * * *",
|
|
35
|
+
"params": {
|
|
36
|
+
"format": "ISO"
|
|
37
|
+
},
|
|
38
|
+
"description": "บันทึกเวลาทุกชั่วโมง",
|
|
39
|
+
"enabled": true
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"config": {
|
|
43
|
+
"time-logger": {
|
|
44
|
+
"timezone": {
|
|
45
|
+
"default": "Asia/Bangkok",
|
|
46
|
+
"type": "string",
|
|
47
|
+
"description": "Timezone สำหรับการบันทึกเวลา"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"postInstall": "ตัวอย่าง Package ติดตั้งสำเร็จแล้ว! ลองตั้งค่า timezone ได้ใน config"
|
|
52
|
+
}
|
|
53
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clawflowbang",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Skill + Cron Installer for OpenClaw - ติดตั้ง skill พร้อมตั้งค่าใช้งานทันที",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"clawflow": "bin/clawflowhub.js",
|
|
8
|
+
"clawflowhub": "bin/clawflowhub.js",
|
|
9
|
+
"cfh": "bin/clawflowhub.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"start": "node bin/clawflowhub.js",
|
|
13
|
+
"test": "jest",
|
|
14
|
+
"lint": "eslint src/ bin/"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"openclaw",
|
|
18
|
+
"skill",
|
|
19
|
+
"cron",
|
|
20
|
+
"installer",
|
|
21
|
+
"automation",
|
|
22
|
+
"clawhub",
|
|
23
|
+
"clawflow"
|
|
24
|
+
],
|
|
25
|
+
"author": "ClawFlow Team",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"commander": "^11.0.0",
|
|
29
|
+
"chalk": "^4.1.2",
|
|
30
|
+
"ora": "^5.4.1",
|
|
31
|
+
"inquirer": "^8.2.6",
|
|
32
|
+
"fs-extra": "^11.1.1",
|
|
33
|
+
"node-cron": "^3.0.3",
|
|
34
|
+
"axios": "^1.5.0",
|
|
35
|
+
"yaml": "^2.3.2",
|
|
36
|
+
"semver": "^7.5.4"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"jest": "^29.6.4",
|
|
40
|
+
"eslint": "^8.47.0"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=16.0.0"
|
|
44
|
+
}
|
|
45
|
+
}
|