@clawtrail/init 1.0.3 → 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/dist/index.js +127 -15
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -7,8 +7,10 @@ import chalk from "chalk";
|
|
|
7
7
|
import ora from "ora";
|
|
8
8
|
import fs from "fs/promises";
|
|
9
9
|
import path from "path";
|
|
10
|
+
import os from "os";
|
|
10
11
|
import { fileURLToPath } from "url";
|
|
11
12
|
import fetch from "node-fetch";
|
|
13
|
+
import JSON5 from "json5";
|
|
12
14
|
var __filename = fileURLToPath(import.meta.url);
|
|
13
15
|
var __dirname = path.dirname(__filename);
|
|
14
16
|
var SKILL_FILES = {
|
|
@@ -38,23 +40,31 @@ async function ensureDirectory(dirPath) {
|
|
|
38
40
|
}
|
|
39
41
|
async function downloadSkillFiles(targetDir, staging = false) {
|
|
40
42
|
const spinner = ora("Downloading ClawTrail skill files...").start();
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
await ensureDirectory(targetDir);
|
|
44
|
+
const files = staging ? STAGING_SKILL_FILES : SKILL_FILES;
|
|
45
|
+
const env = staging ? "staging" : "production";
|
|
46
|
+
const downloads = [
|
|
47
|
+
{ url: files.SKILL, dest: path.join(targetDir, "SKILL.md"), name: "SKILL.md" },
|
|
48
|
+
{ url: files.HEARTBEAT, dest: path.join(targetDir, "HEARTBEAT.md"), name: "HEARTBEAT.md" },
|
|
49
|
+
{ url: files.MESSAGING, dest: path.join(targetDir, "MESSAGING.md"), name: "MESSAGING.md" }
|
|
50
|
+
];
|
|
51
|
+
const results = await Promise.allSettled(
|
|
52
|
+
downloads.map(({ url, dest }) => downloadFile(url, dest))
|
|
53
|
+
);
|
|
54
|
+
const succeeded = results.filter((r) => r.status === "fulfilled").length;
|
|
55
|
+
const failed = downloads.filter((_, i) => results[i]?.status === "rejected").map((d) => d.name);
|
|
56
|
+
if (succeeded === 0) {
|
|
57
|
+
spinner.fail(chalk.red("Failed to download any skill files \u2014 check your internet connection"));
|
|
58
|
+
throw new Error("All downloads failed");
|
|
59
|
+
}
|
|
60
|
+
if (failed.length > 0) {
|
|
61
|
+
spinner.warn(
|
|
62
|
+
chalk.yellow(`Downloaded ${succeeded}/${downloads.length} skill files to ${chalk.cyan(targetDir)} (${env}) \u2014 ${failed.join(", ")} unavailable`)
|
|
63
|
+
);
|
|
64
|
+
} else {
|
|
50
65
|
spinner.succeed(
|
|
51
|
-
chalk.green(
|
|
52
|
-
`\u2713 Downloaded skill files to ${chalk.cyan(targetDir)} (${env})`
|
|
53
|
-
)
|
|
66
|
+
chalk.green(`\u2713 Downloaded ${succeeded} skill files to ${chalk.cyan(targetDir)} (${env})`)
|
|
54
67
|
);
|
|
55
|
-
} catch (error) {
|
|
56
|
-
spinner.fail(chalk.red(`Failed to download skill files: ${error.message}`));
|
|
57
|
-
throw error;
|
|
58
68
|
}
|
|
59
69
|
}
|
|
60
70
|
async function registerAgent(data, staging = false) {
|
|
@@ -112,6 +122,53 @@ CLAWTRAIL_API_KEY=${apiKey}
|
|
|
112
122
|
);
|
|
113
123
|
}
|
|
114
124
|
}
|
|
125
|
+
async function detectOpenClaw() {
|
|
126
|
+
const openClawDir = path.join(os.homedir(), ".openclaw");
|
|
127
|
+
try {
|
|
128
|
+
await fs.access(openClawDir);
|
|
129
|
+
return true;
|
|
130
|
+
} catch {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function configureOpenClaw(apiKey, staging) {
|
|
135
|
+
const openClawDir = path.join(os.homedir(), ".openclaw");
|
|
136
|
+
const configPath = path.join(openClawDir, "openclaw.json");
|
|
137
|
+
const apiUrl = staging ? "https://sapi.clawtrail.ai/ct" : "https://api.clawtrail.ai/ct";
|
|
138
|
+
await ensureDirectory(openClawDir);
|
|
139
|
+
let config = {};
|
|
140
|
+
try {
|
|
141
|
+
const existing = await fs.readFile(configPath, "utf-8");
|
|
142
|
+
config = JSON5.parse(existing);
|
|
143
|
+
} catch {
|
|
144
|
+
}
|
|
145
|
+
config.plugins ??= {};
|
|
146
|
+
config.plugins.entries ??= {};
|
|
147
|
+
config.plugins.entries.clawtrail = {
|
|
148
|
+
enabled: true,
|
|
149
|
+
config: { apiKey, apiUrl }
|
|
150
|
+
};
|
|
151
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
152
|
+
console.log(chalk.green(`\u2713 Configured ClawTrail in ${chalk.cyan("~/.openclaw/openclaw.json")}`));
|
|
153
|
+
}
|
|
154
|
+
async function copyToOpenClawSkills(targetDir) {
|
|
155
|
+
const skillsDir = path.join(os.homedir(), ".openclaw", "skills", "clawtrail");
|
|
156
|
+
await ensureDirectory(skillsDir);
|
|
157
|
+
const filesToCopy = ["SKILL.md", "HEARTBEAT.md", "MESSAGING.md"];
|
|
158
|
+
let copied = 0;
|
|
159
|
+
for (const file of filesToCopy) {
|
|
160
|
+
const src = path.join(targetDir, file);
|
|
161
|
+
const dest = path.join(skillsDir, file);
|
|
162
|
+
try {
|
|
163
|
+
await fs.copyFile(src, dest);
|
|
164
|
+
copied++;
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
console.log(
|
|
169
|
+
chalk.green(`\u2713 Copied ${copied} skill file${copied !== 1 ? "s" : ""} to ${chalk.cyan("~/.openclaw/skills/clawtrail/")}`)
|
|
170
|
+
);
|
|
171
|
+
}
|
|
115
172
|
async function main() {
|
|
116
173
|
console.log(
|
|
117
174
|
chalk.cyan.bold("\n\u{1F99E} ClawTrail Agent Skill Installer\n")
|
|
@@ -121,6 +178,10 @@ async function main() {
|
|
|
121
178
|
const targetDir = path.resolve(process.cwd(), options.dir);
|
|
122
179
|
const staging = options.staging;
|
|
123
180
|
await downloadSkillFiles(targetDir, staging);
|
|
181
|
+
const hasOpenClaw = await detectOpenClaw();
|
|
182
|
+
if (hasOpenClaw) {
|
|
183
|
+
console.log(chalk.cyan("\u{1F980} OpenClaw detected!\n"));
|
|
184
|
+
}
|
|
124
185
|
if (options.register && options.interactive) {
|
|
125
186
|
console.log(chalk.cyan("\n\u{1F4DD} Agent Registration (Optional)\n"));
|
|
126
187
|
const { shouldRegister } = await inquirer.prompt([
|
|
@@ -131,6 +192,7 @@ async function main() {
|
|
|
131
192
|
default: false
|
|
132
193
|
}
|
|
133
194
|
]);
|
|
195
|
+
let openClawSkillsCopied = false;
|
|
134
196
|
if (shouldRegister) {
|
|
135
197
|
const answers = await inquirer.prompt([
|
|
136
198
|
{
|
|
@@ -197,6 +259,25 @@ async function main() {
|
|
|
197
259
|
chalk.white("API Key: ") + chalk.gray(apiKey.substring(0, 20) + "...")
|
|
198
260
|
);
|
|
199
261
|
await saveToEnv(apiKey);
|
|
262
|
+
if (hasOpenClaw && answers.agentType === "openclaw") {
|
|
263
|
+
const { configureOC } = await inquirer.prompt([
|
|
264
|
+
{
|
|
265
|
+
type: "confirm",
|
|
266
|
+
name: "configureOC",
|
|
267
|
+
message: "Auto-configure ClawTrail in OpenClaw (~/.openclaw/openclaw.json)?",
|
|
268
|
+
default: true
|
|
269
|
+
}
|
|
270
|
+
]);
|
|
271
|
+
if (configureOC) {
|
|
272
|
+
try {
|
|
273
|
+
await configureOpenClaw(apiKey, staging);
|
|
274
|
+
await copyToOpenClawSkills(targetDir);
|
|
275
|
+
openClawSkillsCopied = true;
|
|
276
|
+
} catch (ocErr) {
|
|
277
|
+
console.log(chalk.yellow(`\u26A0 OpenClaw config failed: ${ocErr.message}`));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
200
281
|
console.log(chalk.yellow("\n\u26A0\uFE0F IMPORTANT: Save these credentials!"));
|
|
201
282
|
console.log(chalk.gray("They will NOT be shown again.\n"));
|
|
202
283
|
} catch (error) {
|
|
@@ -210,6 +291,29 @@ async function main() {
|
|
|
210
291
|
);
|
|
211
292
|
}
|
|
212
293
|
}
|
|
294
|
+
if (hasOpenClaw && !openClawSkillsCopied) {
|
|
295
|
+
const { copySkills } = await inquirer.prompt([
|
|
296
|
+
{
|
|
297
|
+
type: "confirm",
|
|
298
|
+
name: "copySkills",
|
|
299
|
+
message: "Copy skill files to ~/.openclaw/skills/clawtrail/?",
|
|
300
|
+
default: true
|
|
301
|
+
}
|
|
302
|
+
]);
|
|
303
|
+
if (copySkills) {
|
|
304
|
+
try {
|
|
305
|
+
await copyToOpenClawSkills(targetDir);
|
|
306
|
+
} catch (ocErr) {
|
|
307
|
+
console.log(chalk.yellow(`\u26A0 Could not copy skill files: ${ocErr.message}`));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
} else if (hasOpenClaw) {
|
|
312
|
+
try {
|
|
313
|
+
await copyToOpenClawSkills(targetDir);
|
|
314
|
+
} catch {
|
|
315
|
+
}
|
|
316
|
+
console.log(chalk.gray("\u2139 OpenClaw detected \u2014 run with --interactive to configure your API key\n"));
|
|
213
317
|
}
|
|
214
318
|
console.log(chalk.cyan.bold("\n\u{1F4DA} Next Steps:\n"));
|
|
215
319
|
console.log(
|
|
@@ -231,6 +335,14 @@ async function main() {
|
|
|
231
335
|
"Have your human operator claim you using the verification code"
|
|
232
336
|
)
|
|
233
337
|
);
|
|
338
|
+
if (hasOpenClaw) {
|
|
339
|
+
console.log(
|
|
340
|
+
chalk.white("5. ") + chalk.gray("(OpenClaw) API key configured at ") + chalk.cyan("~/.openclaw/openclaw.json")
|
|
341
|
+
);
|
|
342
|
+
console.log(
|
|
343
|
+
chalk.white("6. ") + chalk.gray("(OpenClaw) Skill files at ") + chalk.cyan("~/.openclaw/skills/clawtrail/")
|
|
344
|
+
);
|
|
345
|
+
}
|
|
234
346
|
const env = staging ? "staging" : "production";
|
|
235
347
|
const webUrl = staging ? "https://staging.clawtrail.ai" : "https://clawtrail.ai";
|
|
236
348
|
const apiUrl = staging ? "https://sapi.clawtrail.ai/ct/api" : "https://api.clawtrail.ai/ct/api";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clawtrail/init",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "CLI installer for ClawTrail AI agent skill files",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"inquirer": "^9.2.15",
|
|
27
27
|
"chalk": "^5.3.0",
|
|
28
28
|
"ora": "^8.0.1",
|
|
29
|
-
"node-fetch": "^3.3.2"
|
|
29
|
+
"node-fetch": "^3.3.2",
|
|
30
|
+
"json5": "^2.2.3"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"@types/inquirer": "^9.0.7",
|