@clawtrail/init 1.5.0 → 2.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/dist/index.js +143 -368
- package/package.json +1 -3
package/dist/index.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import inquirer from "inquirer";
|
|
6
5
|
import chalk from "chalk";
|
|
7
6
|
import ora from "ora";
|
|
8
7
|
import fs from "fs/promises";
|
|
@@ -66,107 +65,36 @@ async function downloadSkillFiles(targetDir, staging = false) {
|
|
|
66
65
|
}
|
|
67
66
|
if (failed.length > 0) {
|
|
68
67
|
spinner.warn(
|
|
69
|
-
chalk.yellow(`Downloaded ${succeeded}/${downloads.length}
|
|
68
|
+
chalk.yellow(`Downloaded ${succeeded}/${downloads.length} files (${env}) \u2014 ${failed.join(", ")} unavailable`)
|
|
70
69
|
);
|
|
71
70
|
} else {
|
|
72
71
|
spinner.succeed(
|
|
73
|
-
chalk.green(`Downloaded ${succeeded} skill files
|
|
72
|
+
chalk.green(`Downloaded ${succeeded} skill files (${env})`)
|
|
74
73
|
);
|
|
75
74
|
}
|
|
75
|
+
return { succeeded, failed };
|
|
76
76
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
function getRegistrationErrorHint(message) {
|
|
84
|
-
const lower = message.toLowerCase();
|
|
85
|
-
for (const [pattern, hint] of Object.entries(REGISTRATION_ERROR_HINTS)) {
|
|
86
|
-
if (lower.includes(pattern)) return hint;
|
|
87
|
-
}
|
|
88
|
-
return void 0;
|
|
89
|
-
}
|
|
90
|
-
async function registerAgent(data, staging = false) {
|
|
91
|
-
const apiUrl = staging ? "https://sapi.clawtrail.ai/ct/api" : "https://api.clawtrail.ai/ct/api";
|
|
92
|
-
const spinner = ora("Registering agent with ClawTrail...").start();
|
|
93
|
-
try {
|
|
94
|
-
const response = await fetch(`${apiUrl}/agents/register`, {
|
|
95
|
-
method: "POST",
|
|
96
|
-
headers: {
|
|
97
|
-
"Content-Type": "application/json"
|
|
98
|
-
},
|
|
99
|
-
body: JSON.stringify(data)
|
|
100
|
-
});
|
|
101
|
-
if (!response.ok) {
|
|
102
|
-
const error = await response.json();
|
|
103
|
-
const rawMessage = error.error || "Registration failed";
|
|
104
|
-
const hint = getRegistrationErrorHint(rawMessage);
|
|
105
|
-
throw new Error(hint || rawMessage);
|
|
106
|
-
}
|
|
107
|
-
const result = await response.json();
|
|
108
|
-
spinner.succeed(chalk.green("Agent registered successfully!"));
|
|
109
|
-
return {
|
|
110
|
-
agentId: result.agentId,
|
|
111
|
-
apiKey: result.apiKey,
|
|
112
|
-
verificationCode: result.verificationCode,
|
|
113
|
-
statusUrl: result.statusUrl
|
|
114
|
-
};
|
|
115
|
-
} catch (error) {
|
|
116
|
-
spinner.fail(chalk.red(`Registration failed: ${error.message}`));
|
|
117
|
-
throw error;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
async function checkExistingApiKey() {
|
|
77
|
+
async function copyToOpenClawDirs(targetDir, staging) {
|
|
78
|
+
const skillFolder = staging ? "clawtrail-staging" : "clawtrail";
|
|
79
|
+
const openclawDir = path.join(os.homedir(), ".openclaw");
|
|
80
|
+
const placed = [];
|
|
81
|
+
const workspaceDir = path.join(openclawDir, "workspace");
|
|
82
|
+
await ensureDirectory(workspaceDir);
|
|
121
83
|
try {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return content.includes("CLAWTRAIL_API_KEY=");
|
|
84
|
+
await fs.copyFile(path.join(targetDir, "HEARTBEAT.md"), path.join(workspaceDir, "HEARTBEAT.md"));
|
|
85
|
+
placed.push("~/.openclaw/workspace/HEARTBEAT.md");
|
|
125
86
|
} catch {
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
async function saveToEnv(apiKey) {
|
|
130
|
-
const envPath = path.join(process.cwd(), ".env");
|
|
131
|
-
const envContent = `
|
|
132
|
-
# ClawTrail API Key
|
|
133
|
-
CLAWTRAIL_API_KEY=${apiKey}
|
|
134
|
-
`;
|
|
135
|
-
try {
|
|
136
|
-
let existingContent = "";
|
|
137
|
-
try {
|
|
138
|
-
existingContent = await fs.readFile(envPath, "utf-8");
|
|
139
|
-
} catch {
|
|
140
|
-
}
|
|
141
|
-
if (existingContent.includes("CLAWTRAIL_API_KEY")) {
|
|
142
|
-
console.log(
|
|
143
|
-
chalk.yellow(
|
|
144
|
-
" .env already contains CLAWTRAIL_API_KEY, not overwriting"
|
|
145
|
-
)
|
|
146
|
-
);
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
await fs.appendFile(envPath, envContent);
|
|
150
|
-
console.log(chalk.green(` Saved API key to ${chalk.cyan(".env")}`));
|
|
151
|
-
} catch (error) {
|
|
152
|
-
console.log(
|
|
153
|
-
chalk.yellow(` Could not save to .env: ${error.message}`)
|
|
154
|
-
);
|
|
155
|
-
console.log(
|
|
156
|
-
chalk.gray(" You can manually add it: CLAWTRAIL_API_KEY=<your-key>")
|
|
157
|
-
);
|
|
158
87
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const openClawDir = path.join(os.homedir(), ".openclaw");
|
|
88
|
+
const skillsDir = path.join(openclawDir, "skills", skillFolder);
|
|
89
|
+
await ensureDirectory(skillsDir);
|
|
162
90
|
try {
|
|
163
|
-
await fs.
|
|
164
|
-
|
|
91
|
+
await fs.copyFile(path.join(targetDir, "SKILL.md"), path.join(skillsDir, "SKILL.md"));
|
|
92
|
+
placed.push(`~/.openclaw/skills/${skillFolder}/SKILL.md`);
|
|
165
93
|
} catch {
|
|
166
|
-
return false;
|
|
167
94
|
}
|
|
95
|
+
return placed;
|
|
168
96
|
}
|
|
169
|
-
async function configureOpenClaw(
|
|
97
|
+
async function configureOpenClaw(staging, apiKey) {
|
|
170
98
|
const openClawDir = path.join(os.homedir(), ".openclaw");
|
|
171
99
|
const configPath = path.join(openClawDir, "openclaw.json");
|
|
172
100
|
const apiUrl = staging ? "https://sapi.clawtrail.ai/ct" : "https://api.clawtrail.ai/ct";
|
|
@@ -176,27 +104,13 @@ async function configureOpenClaw(apiKey, staging) {
|
|
|
176
104
|
const existing = await fs.readFile(configPath, "utf-8");
|
|
177
105
|
config = JSON5.parse(existing);
|
|
178
106
|
} catch (err) {
|
|
179
|
-
if (err.code
|
|
180
|
-
} else {
|
|
181
|
-
console.log(
|
|
182
|
-
chalk.yellow(` Could not parse existing openclaw.json \u2014 backing up and starting fresh`)
|
|
183
|
-
);
|
|
107
|
+
if (err.code !== "ENOENT") {
|
|
184
108
|
try {
|
|
185
109
|
await fs.copyFile(configPath, configPath + ".bak");
|
|
186
|
-
console.log(chalk.gray(` Backup saved to ${configPath}.bak`));
|
|
187
110
|
} catch {
|
|
188
111
|
}
|
|
189
112
|
}
|
|
190
113
|
}
|
|
191
|
-
config.plugins ??= {};
|
|
192
|
-
config.plugins.entries ??= {};
|
|
193
|
-
config.plugins.entries.clawtrail = {
|
|
194
|
-
enabled: true,
|
|
195
|
-
config: {
|
|
196
|
-
apiKey,
|
|
197
|
-
apiUrl
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
114
|
config.agents ??= {};
|
|
201
115
|
config.agents.defaults ??= {};
|
|
202
116
|
config.agents.defaults.heartbeat = {
|
|
@@ -208,302 +122,163 @@ async function configureOpenClaw(apiKey, staging) {
|
|
|
208
122
|
config.skills.entries.clawtrail ??= {};
|
|
209
123
|
config.skills.entries.clawtrail.enabled = true;
|
|
210
124
|
config.skills.entries.clawtrail.env ??= {};
|
|
211
|
-
config.skills.entries.clawtrail.env.CLAWTRAIL_API_KEY = apiKey;
|
|
212
125
|
config.skills.entries.clawtrail.env.CLAWTRAIL_API_URL = apiUrl;
|
|
126
|
+
if (apiKey) {
|
|
127
|
+
config.skills.entries.clawtrail.env.CLAWTRAIL_API_KEY = apiKey;
|
|
128
|
+
}
|
|
213
129
|
await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
214
|
-
|
|
215
|
-
|
|
130
|
+
return {
|
|
131
|
+
configPath: "~/.openclaw/openclaw.json",
|
|
132
|
+
heartbeat: "every 30s",
|
|
133
|
+
hasApiKey: !!apiKey
|
|
134
|
+
};
|
|
216
135
|
}
|
|
217
|
-
async function
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
await ensureDirectory(openClawDir);
|
|
221
|
-
let config = {};
|
|
136
|
+
async function registerAgent(name, description, staging, opts = {}) {
|
|
137
|
+
const apiUrl = staging ? "https://sapi.clawtrail.ai/ct/api" : "https://api.clawtrail.ai/ct/api";
|
|
138
|
+
const spinner = ora("Registering agent...").start();
|
|
222
139
|
try {
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
140
|
+
const response = await fetch(`${apiUrl}/agents/register`, {
|
|
141
|
+
method: "POST",
|
|
142
|
+
headers: { "Content-Type": "application/json" },
|
|
143
|
+
body: JSON.stringify({
|
|
144
|
+
name,
|
|
145
|
+
description,
|
|
146
|
+
bio: opts.bio || void 0,
|
|
147
|
+
agentType: opts.agentType || "openclaw",
|
|
148
|
+
framework: opts.framework || void 0,
|
|
149
|
+
skills: opts.skills?.length ? opts.skills : void 0,
|
|
150
|
+
capabilities: opts.capabilities?.length ? opts.capabilities : ["general"]
|
|
151
|
+
})
|
|
152
|
+
});
|
|
153
|
+
if (!response.ok) {
|
|
154
|
+
const error = await response.json();
|
|
155
|
+
throw new Error(error.error || "Registration failed");
|
|
231
156
|
}
|
|
157
|
+
const result = await response.json();
|
|
158
|
+
spinner.succeed(chalk.green("Agent registered"));
|
|
159
|
+
return {
|
|
160
|
+
agentId: result.agentId,
|
|
161
|
+
apiKey: result.apiKey,
|
|
162
|
+
verificationCode: result.verificationCode,
|
|
163
|
+
statusUrl: result.statusUrl
|
|
164
|
+
};
|
|
165
|
+
} catch (error) {
|
|
166
|
+
spinner.fail(chalk.red(`Registration failed: ${error.message}`));
|
|
167
|
+
throw error;
|
|
232
168
|
}
|
|
233
|
-
config.agents ??= {};
|
|
234
|
-
config.agents.defaults ??= {};
|
|
235
|
-
config.agents.defaults.heartbeat = {
|
|
236
|
-
every: "30s",
|
|
237
|
-
target: "last"
|
|
238
|
-
};
|
|
239
|
-
const apiUrl = staging ? "https://sapi.clawtrail.ai/ct" : "https://api.clawtrail.ai/ct";
|
|
240
|
-
config.skills ??= {};
|
|
241
|
-
config.skills.entries ??= {};
|
|
242
|
-
config.skills.entries.clawtrail ??= {};
|
|
243
|
-
config.skills.entries.clawtrail.enabled = true;
|
|
244
|
-
config.skills.entries.clawtrail.env ??= {};
|
|
245
|
-
config.skills.entries.clawtrail.env.CLAWTRAIL_API_URL = apiUrl;
|
|
246
|
-
await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
247
|
-
console.log(chalk.green(` Heartbeat configured: ${chalk.cyan("every 30s")} in ${chalk.cyan("~/.openclaw/openclaw.json")}`));
|
|
248
169
|
}
|
|
249
|
-
async function
|
|
250
|
-
const skillFolder = staging ? "clawtrail-staging" : "clawtrail";
|
|
251
|
-
const openclawDir = path.join(os.homedir(), ".openclaw");
|
|
252
|
-
const workspaceDir = path.join(openclawDir, "workspace");
|
|
253
|
-
await ensureDirectory(workspaceDir);
|
|
254
|
-
try {
|
|
255
|
-
await fs.copyFile(path.join(targetDir, "HEARTBEAT.md"), path.join(workspaceDir, "HEARTBEAT.md"));
|
|
256
|
-
console.log(chalk.green(" HEARTBEAT.md -> ") + chalk.cyan("~/.openclaw/workspace/HEARTBEAT.md"));
|
|
257
|
-
} catch {
|
|
258
|
-
}
|
|
259
|
-
const skillsDir = path.join(openclawDir, "skills", skillFolder);
|
|
260
|
-
await ensureDirectory(skillsDir);
|
|
170
|
+
async function detectOpenClaw() {
|
|
261
171
|
try {
|
|
262
|
-
await fs.
|
|
263
|
-
|
|
172
|
+
await fs.access(path.join(os.homedir(), ".openclaw"));
|
|
173
|
+
return true;
|
|
264
174
|
} catch {
|
|
175
|
+
return false;
|
|
265
176
|
}
|
|
266
177
|
}
|
|
267
178
|
async function main() {
|
|
268
|
-
console.log(
|
|
269
|
-
chalk.cyan.bold("\n ClawTrail Agent Skill Installer\n")
|
|
270
|
-
);
|
|
179
|
+
console.log(chalk.cyan.bold("\n ClawTrail Agent Installer\n"));
|
|
271
180
|
const program = new Command();
|
|
272
|
-
program.name("clawtrail-init").description("
|
|
181
|
+
program.name("clawtrail-init").description("Install ClawTrail skill files, configure heartbeat, and optionally register an agent").version("2.0.0").option("-d, --dir <path>", "Download directory for skill files", "./clawtrail-skills").option("-s, --staging", "Use staging environment", false).option("--name <name>", "Register agent with this name").option("--description <desc>", "Agent description (required with --name)").option("--bio <bio>", "Agent bio").option("--agent-type <type>", "Agent type (openclaw, custom, mcp-server, a2a-agent)", "openclaw").option("--framework <fw>", "Agent framework (e.g., langchain, autogen)").option("--skills <skills>", "Comma-separated skills (e.g., coding,research,dkg)").option("--capabilities <caps>", "Comma-separated capabilities (e.g., research,analysis)").option("--api-key <key>", "Existing API key (skip registration, just configure)").action(async (options) => {
|
|
273
182
|
const targetDir = path.resolve(process.cwd(), options.dir);
|
|
274
183
|
const staging = options.staging;
|
|
184
|
+
const env = staging ? "staging" : "production";
|
|
275
185
|
await downloadSkillFiles(targetDir, staging);
|
|
276
186
|
const hasOpenClaw = await detectOpenClaw();
|
|
187
|
+
let placedFiles = [];
|
|
277
188
|
if (hasOpenClaw) {
|
|
278
|
-
|
|
189
|
+
const spinner = ora("Placing files in OpenClaw directories...").start();
|
|
279
190
|
try {
|
|
280
|
-
await
|
|
281
|
-
|
|
282
|
-
|
|
191
|
+
placedFiles = await copyToOpenClawDirs(targetDir, staging);
|
|
192
|
+
spinner.succeed(chalk.green(`Placed ${placedFiles.length} files in OpenClaw`));
|
|
193
|
+
} catch (err) {
|
|
194
|
+
spinner.warn(chalk.yellow(`Could not place files: ${err.message}`));
|
|
283
195
|
}
|
|
284
196
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
);
|
|
291
|
-
|
|
197
|
+
let apiKey = options.apiKey || void 0;
|
|
198
|
+
let agentId;
|
|
199
|
+
let verificationCode;
|
|
200
|
+
if (options.name) {
|
|
201
|
+
if (!options.description) {
|
|
202
|
+
console.log(chalk.red("\n --description is required when using --name\n"));
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
const result = await registerAgent(
|
|
207
|
+
options.name.trim(),
|
|
208
|
+
options.description.trim(),
|
|
209
|
+
staging,
|
|
292
210
|
{
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
211
|
+
bio: options.bio?.trim(),
|
|
212
|
+
agentType: options.agentType,
|
|
213
|
+
framework: options.framework?.trim(),
|
|
214
|
+
skills: options.skills?.split(",").map((s) => s.trim()).filter(Boolean),
|
|
215
|
+
capabilities: options.capabilities?.split(",").map((s) => s.trim()).filter(Boolean)
|
|
297
216
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
217
|
+
);
|
|
218
|
+
apiKey = result.apiKey;
|
|
219
|
+
agentId = result.agentId;
|
|
220
|
+
verificationCode = result.verificationCode;
|
|
221
|
+
} catch {
|
|
303
222
|
}
|
|
304
223
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
]);
|
|
320
|
-
if (registrationChoice === "bot") {
|
|
321
|
-
console.log(chalk.green("\n Got it! Your bot will register itself.\n"));
|
|
322
|
-
console.log(chalk.gray(" Your bot can register using the SKILL.md instructions."));
|
|
323
|
-
console.log(chalk.gray(" It will call POST /api/agents/register with its own info."));
|
|
324
|
-
if (hasOpenClaw) {
|
|
325
|
-
console.log(chalk.gray(" The ClawTrail skill file has been placed in your OpenClaw workspace."));
|
|
326
|
-
console.log(chalk.gray(" Just start your bot \u2014 it will read the skill and register automatically."));
|
|
327
|
-
const { configureHeartbeat } = await inquirer.prompt([
|
|
328
|
-
{
|
|
329
|
-
type: "confirm",
|
|
330
|
-
name: "configureHeartbeat",
|
|
331
|
-
message: "Configure heartbeat (30s autonomous loop) in OpenClaw?",
|
|
332
|
-
default: true
|
|
333
|
-
}
|
|
334
|
-
]);
|
|
335
|
-
if (configureHeartbeat) {
|
|
336
|
-
try {
|
|
337
|
-
await configureOpenClawHeartbeat(staging);
|
|
338
|
-
} catch (hbErr) {
|
|
339
|
-
console.log(chalk.yellow(` Heartbeat config failed: ${hbErr.message}`));
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
console.log();
|
|
343
|
-
} else {
|
|
344
|
-
console.log(chalk.gray(" Point your agent at the SKILL.md file to get started.\n"));
|
|
345
|
-
}
|
|
346
|
-
} else if (registrationChoice === "manual") {
|
|
347
|
-
const answers = await inquirer.prompt([
|
|
348
|
-
{
|
|
349
|
-
type: "input",
|
|
350
|
-
name: "name",
|
|
351
|
-
message: "Agent name:",
|
|
352
|
-
validate: (input) => {
|
|
353
|
-
if (!input.trim()) return "Name is required";
|
|
354
|
-
if (input.trim().length < 2) return "Name must be at least 2 characters";
|
|
355
|
-
if (input.trim().length > 100) return "Name must be under 100 characters";
|
|
356
|
-
return true;
|
|
357
|
-
}
|
|
358
|
-
},
|
|
359
|
-
{
|
|
360
|
-
type: "input",
|
|
361
|
-
name: "description",
|
|
362
|
-
message: "Agent description:",
|
|
363
|
-
validate: (input) => {
|
|
364
|
-
if (!input.trim()) return "Description is required";
|
|
365
|
-
if (input.trim().length < 10) return "Description must be at least 10 characters";
|
|
366
|
-
return true;
|
|
367
|
-
}
|
|
368
|
-
},
|
|
369
|
-
{
|
|
370
|
-
type: "input",
|
|
371
|
-
name: "bio",
|
|
372
|
-
message: "Short bio (optional):"
|
|
373
|
-
},
|
|
374
|
-
{
|
|
375
|
-
type: "list",
|
|
376
|
-
name: "agentType",
|
|
377
|
-
message: "Agent type:",
|
|
378
|
-
choices: [
|
|
379
|
-
{ name: "OpenClaw Agent", value: "openclaw" },
|
|
380
|
-
{ name: "Custom Agent", value: "custom" },
|
|
381
|
-
{ name: "MCP Server", value: "mcp-server" },
|
|
382
|
-
{ name: "A2A Agent", value: "a2a-agent" },
|
|
383
|
-
{ name: "ERC-8004 Agent", value: "erc8004" }
|
|
384
|
-
],
|
|
385
|
-
default: hasOpenClaw ? "openclaw" : "custom"
|
|
386
|
-
},
|
|
387
|
-
{
|
|
388
|
-
type: "input",
|
|
389
|
-
name: "framework",
|
|
390
|
-
message: "Framework (optional, e.g., langchain, autogen):"
|
|
391
|
-
},
|
|
392
|
-
{
|
|
393
|
-
type: "input",
|
|
394
|
-
name: "skills",
|
|
395
|
-
message: "Skills (optional, comma-separated, e.g., coding,research,dkg):"
|
|
396
|
-
},
|
|
397
|
-
{
|
|
398
|
-
type: "input",
|
|
399
|
-
name: "capabilities",
|
|
400
|
-
message: "Capabilities (optional, comma-separated, e.g., research,analysis,automation):"
|
|
401
|
-
}
|
|
402
|
-
]);
|
|
224
|
+
let ocConfig;
|
|
225
|
+
if (hasOpenClaw) {
|
|
226
|
+
const spinner = ora("Configuring OpenClaw heartbeat...").start();
|
|
227
|
+
try {
|
|
228
|
+
ocConfig = await configureOpenClaw(staging, apiKey);
|
|
229
|
+
spinner.succeed(chalk.green(`Heartbeat configured: ${chalk.cyan("every 30s")}`));
|
|
230
|
+
} catch (err) {
|
|
231
|
+
spinner.warn(chalk.yellow(`Config failed: ${err.message}`));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (apiKey) {
|
|
235
|
+
const envPath = path.join(process.cwd(), ".env");
|
|
236
|
+
try {
|
|
237
|
+
let existing = "";
|
|
403
238
|
try {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
capabilities: answers.capabilities ? answers.capabilities.split(",").map((s) => s.trim()).filter(Boolean) : ["general"]
|
|
413
|
-
},
|
|
414
|
-
staging
|
|
415
|
-
);
|
|
416
|
-
console.log(chalk.green("\n Registration Complete!\n"));
|
|
417
|
-
console.log(chalk.white("Agent ID: ") + chalk.cyan(agentId));
|
|
418
|
-
console.log(
|
|
419
|
-
chalk.white("Verification Code: ") + chalk.yellow(verificationCode)
|
|
420
|
-
);
|
|
421
|
-
console.log(
|
|
422
|
-
chalk.white("DKG Status: ") + chalk.yellow("pending \u2014 minting queued (~30s)")
|
|
423
|
-
);
|
|
424
|
-
console.log(
|
|
425
|
-
chalk.white("Status URL: ") + chalk.blue.underline(statusUrl)
|
|
426
|
-
);
|
|
427
|
-
await saveToEnv(apiKey);
|
|
428
|
-
console.log(chalk.yellow("\n IMPORTANT: Your API key has been saved to .env"));
|
|
429
|
-
console.log(chalk.yellow(" The verification code above will NOT be shown again.\n"));
|
|
430
|
-
if (hasOpenClaw && answers.agentType === "openclaw") {
|
|
431
|
-
const { configureOC } = await inquirer.prompt([
|
|
432
|
-
{
|
|
433
|
-
type: "confirm",
|
|
434
|
-
name: "configureOC",
|
|
435
|
-
message: "Auto-configure ClawTrail in OpenClaw (~/.openclaw/openclaw.json)?",
|
|
436
|
-
default: true
|
|
437
|
-
}
|
|
438
|
-
]);
|
|
439
|
-
if (configureOC) {
|
|
440
|
-
try {
|
|
441
|
-
await configureOpenClaw(apiKey, staging);
|
|
442
|
-
} catch (ocErr) {
|
|
443
|
-
console.log(chalk.yellow(` OpenClaw config failed: ${ocErr.message}`));
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
} catch (error) {
|
|
448
|
-
console.log(
|
|
449
|
-
chalk.red(`
|
|
450
|
-
Registration failed: ${error.message}
|
|
451
|
-
`)
|
|
452
|
-
);
|
|
453
|
-
console.log(
|
|
454
|
-
chalk.gray("You can register later via the ClawTrail API.\n")
|
|
455
|
-
);
|
|
239
|
+
existing = await fs.readFile(envPath, "utf-8");
|
|
240
|
+
} catch {
|
|
241
|
+
}
|
|
242
|
+
if (!existing.includes("CLAWTRAIL_API_KEY")) {
|
|
243
|
+
await fs.appendFile(envPath, `
|
|
244
|
+
# ClawTrail API Key
|
|
245
|
+
CLAWTRAIL_API_KEY=${apiKey}
|
|
246
|
+
`);
|
|
456
247
|
}
|
|
248
|
+
} catch {
|
|
457
249
|
}
|
|
458
250
|
}
|
|
459
|
-
console.log(chalk.cyan.bold("\n
|
|
460
|
-
console.log(
|
|
461
|
-
|
|
462
|
-
)
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
);
|
|
469
|
-
|
|
470
|
-
chalk.white("
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
)
|
|
478
|
-
|
|
479
|
-
if (hasOpenClaw) {
|
|
480
|
-
console.log(
|
|
481
|
-
|
|
482
|
-
);
|
|
483
|
-
console.log(
|
|
484
|
-
chalk.white("6. ") + chalk.gray("(OpenClaw) Config at ") + chalk.cyan("~/.openclaw/openclaw.json")
|
|
485
|
-
);
|
|
486
|
-
console.log(
|
|
487
|
-
chalk.white("7. ") + chalk.gray("(OpenClaw) Skill installed to ") + chalk.cyan("~/.openclaw/skills/")
|
|
488
|
-
);
|
|
251
|
+
console.log(chalk.cyan.bold("\n \u2500\u2500\u2500 Results \u2500\u2500\u2500\n"));
|
|
252
|
+
console.log(chalk.white(" Environment: ") + chalk.cyan(env));
|
|
253
|
+
console.log(chalk.white(" Skill files: ") + chalk.cyan(targetDir));
|
|
254
|
+
if (placedFiles.length > 0) {
|
|
255
|
+
for (const f of placedFiles) {
|
|
256
|
+
console.log(chalk.white(" Placed: ") + chalk.cyan(f));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (ocConfig) {
|
|
260
|
+
console.log(chalk.white(" Heartbeat: ") + chalk.green(ocConfig.heartbeat));
|
|
261
|
+
console.log(chalk.white(" Config: ") + chalk.cyan(ocConfig.configPath));
|
|
262
|
+
console.log(chalk.white(" API key: ") + chalk.cyan(ocConfig.hasApiKey ? "injected" : "not set (bot will self-register)"));
|
|
263
|
+
}
|
|
264
|
+
if (agentId) {
|
|
265
|
+
console.log(chalk.white(" Agent ID: ") + chalk.cyan(agentId));
|
|
266
|
+
}
|
|
267
|
+
if (verificationCode) {
|
|
268
|
+
console.log(chalk.white(" Verify code: ") + chalk.yellow(verificationCode));
|
|
269
|
+
console.log(chalk.gray(" (save this \u2014 shown only once)"));
|
|
270
|
+
}
|
|
271
|
+
if (!hasOpenClaw) {
|
|
272
|
+
console.log(chalk.gray("\n OpenClaw not detected \u2014 skill files saved to ") + chalk.cyan(targetDir));
|
|
273
|
+
console.log(chalk.gray(" Point your agent at SKILL.md to get started."));
|
|
489
274
|
}
|
|
490
|
-
const env = staging ? "staging" : "production";
|
|
491
275
|
const webUrl = staging ? "https://staging.clawtrail.ai" : "https://clawtrail.ai";
|
|
492
276
|
const apiUrl = staging ? "https://sapi.clawtrail.ai/ct/api" : "https://api.clawtrail.ai/ct/api";
|
|
493
|
-
console.log(chalk.cyan("\n
|
|
494
|
-
console.log(
|
|
495
|
-
|
|
496
|
-
);
|
|
497
|
-
console.log(
|
|
498
|
-
chalk.white("API: ") + chalk.blue.underline(apiUrl)
|
|
499
|
-
);
|
|
500
|
-
console.log(
|
|
501
|
-
chalk.white("Docs: ") + chalk.blue.underline("https://docs.clawtrail.ai")
|
|
502
|
-
);
|
|
503
|
-
console.log(
|
|
504
|
-
chalk.white("Environment: ") + chalk.cyan(env)
|
|
505
|
-
);
|
|
506
|
-
console.log(chalk.cyan("\n Happy building with ClawTrail!\n"));
|
|
277
|
+
console.log(chalk.cyan("\n \u2500\u2500\u2500 Links \u2500\u2500\u2500\n"));
|
|
278
|
+
console.log(chalk.white(" Web: ") + chalk.blue.underline(webUrl));
|
|
279
|
+
console.log(chalk.white(" API: ") + chalk.blue.underline(apiUrl));
|
|
280
|
+
console.log(chalk.white(" Docs: ") + chalk.blue.underline("https://docs.clawtrail.ai"));
|
|
281
|
+
console.log(chalk.cyan("\n Ready to go!\n"));
|
|
507
282
|
});
|
|
508
283
|
await program.parseAsync(process.argv);
|
|
509
284
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clawtrail/init",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "CLI installer for ClawTrail AI agent skill files",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -23,14 +23,12 @@
|
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"commander": "^12.0.0",
|
|
26
|
-
"inquirer": "^9.2.15",
|
|
27
26
|
"chalk": "^5.3.0",
|
|
28
27
|
"ora": "^8.0.1",
|
|
29
28
|
"node-fetch": "^3.3.2",
|
|
30
29
|
"json5": "^2.2.3"
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
|
-
"@types/inquirer": "^9.0.7",
|
|
34
32
|
"@types/node": "^22.0.0",
|
|
35
33
|
"tsup": "^8.5.0",
|
|
36
34
|
"typescript": "^5.7.2"
|