@clawtrail/init 1.4.1 → 1.5.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.
Files changed (2) hide show
  1. package/dist/index.js +73 -55
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -197,72 +197,71 @@ async function configureOpenClaw(apiKey, staging) {
197
197
  apiUrl
198
198
  }
199
199
  };
200
+ config.agents ??= {};
201
+ config.agents.defaults ??= {};
202
+ config.agents.defaults.heartbeat = {
203
+ every: "30s",
204
+ target: "last"
205
+ };
206
+ config.skills ??= {};
207
+ config.skills.entries ??= {};
208
+ config.skills.entries.clawtrail ??= {};
209
+ config.skills.entries.clawtrail.enabled = true;
210
+ config.skills.entries.clawtrail.env ??= {};
211
+ config.skills.entries.clawtrail.env.CLAWTRAIL_API_KEY = apiKey;
212
+ config.skills.entries.clawtrail.env.CLAWTRAIL_API_URL = apiUrl;
200
213
  await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
201
214
  console.log(chalk.green(` Configured ClawTrail in ${chalk.cyan("~/.openclaw/openclaw.json")}`));
215
+ console.log(chalk.green(` Heartbeat: ${chalk.cyan("every 30s")} \u2014 agent will be autonomously active`));
202
216
  }
203
- async function findOpenClawSkillsDir() {
204
- const candidates = [
205
- // npm global (Linux default)
206
- "/usr/lib/node_modules/openclaw/skills",
207
- // npm global (macOS/nvm)
208
- path.join(os.homedir(), ".nvm/versions/node", "**", "lib/node_modules/openclaw/skills"),
209
- // npm global (macOS Homebrew)
210
- "/usr/local/lib/node_modules/openclaw/skills",
211
- // npm global (prefix-based)
212
- "/usr/local/share/npm/lib/node_modules/openclaw/skills"
213
- ];
217
+ async function configureOpenClawHeartbeat(staging) {
218
+ const openClawDir = path.join(os.homedir(), ".openclaw");
219
+ const configPath = path.join(openClawDir, "openclaw.json");
220
+ await ensureDirectory(openClawDir);
221
+ let config = {};
214
222
  try {
215
- const { execSync } = await import("child_process");
216
- const globalRoot = execSync("npm root -g", { timeout: 5e3 }).toString().trim();
217
- const npmGlobalPath = path.join(globalRoot, "openclaw", "skills");
218
- try {
219
- await fs.access(npmGlobalPath);
220
- return npmGlobalPath;
221
- } catch {
222
- }
223
- } catch {
224
- }
225
- for (const candidate of candidates) {
226
- if (candidate.includes("**")) continue;
227
- try {
228
- await fs.access(candidate);
229
- return candidate;
230
- } catch {
223
+ const existing = await fs.readFile(configPath, "utf-8");
224
+ config = JSON5.parse(existing);
225
+ } catch (err) {
226
+ if (err.code !== "ENOENT") {
227
+ try {
228
+ await fs.copyFile(configPath, configPath + ".bak");
229
+ } catch {
230
+ }
231
231
  }
232
232
  }
233
- return null;
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")}`));
234
248
  }
235
249
  async function copyToOpenClawSkills(targetDir, staging) {
236
250
  const skillFolder = staging ? "clawtrail-staging" : "clawtrail";
237
- const workspaceDir = path.join(os.homedir(), ".openclaw", "workspace");
251
+ const openclawDir = path.join(os.homedir(), ".openclaw");
252
+ const workspaceDir = path.join(openclawDir, "workspace");
238
253
  await ensureDirectory(workspaceDir);
239
254
  try {
240
255
  await fs.copyFile(path.join(targetDir, "HEARTBEAT.md"), path.join(workspaceDir, "HEARTBEAT.md"));
241
256
  console.log(chalk.green(" HEARTBEAT.md -> ") + chalk.cyan("~/.openclaw/workspace/HEARTBEAT.md"));
242
257
  } catch {
243
258
  }
244
- const openclawSkillsDir = await findOpenClawSkillsDir();
245
- if (openclawSkillsDir) {
246
- const destDir = path.join(openclawSkillsDir, skillFolder);
247
- await ensureDirectory(destDir);
248
- try {
249
- await fs.copyFile(path.join(targetDir, "SKILL.md"), path.join(destDir, "SKILL.md"));
250
- const prettyPath = openclawSkillsDir.replace(os.homedir(), "~");
251
- console.log(chalk.green(" SKILL.md -> ") + chalk.cyan(`${prettyPath}/${skillFolder}/SKILL.md`));
252
- } catch {
253
- }
254
- } else {
255
- const skillsDir = path.join(workspaceDir, "skills", skillFolder);
256
- await ensureDirectory(skillsDir);
257
- try {
258
- await fs.copyFile(path.join(targetDir, "SKILL.md"), path.join(skillsDir, "SKILL.md"));
259
- console.log(
260
- chalk.yellow(" Could not find OpenClaw global install \u2014 SKILL.md placed in workspace fallback")
261
- );
262
- console.log(chalk.gray(` ${chalk.cyan(`~/.openclaw/workspace/skills/${skillFolder}/SKILL.md`)}`));
263
- console.log(chalk.gray(" You may need to manually copy it to your OpenClaw skills directory."));
264
- } catch {
265
- }
259
+ const skillsDir = path.join(openclawDir, "skills", skillFolder);
260
+ await ensureDirectory(skillsDir);
261
+ try {
262
+ await fs.copyFile(path.join(targetDir, "SKILL.md"), path.join(skillsDir, "SKILL.md"));
263
+ console.log(chalk.green(" SKILL.md -> ") + chalk.cyan(`~/.openclaw/skills/${skillFolder}/SKILL.md`));
264
+ } catch {
266
265
  }
267
266
  }
268
267
  async function main() {
@@ -270,7 +269,7 @@ async function main() {
270
269
  chalk.cyan.bold("\n ClawTrail Agent Skill Installer\n")
271
270
  );
272
271
  const program = new Command();
273
- program.name("clawtrail-init").description("Initialize ClawTrail skill files for AI agents").version("1.4.1").option("-d, --dir <path>", "Target directory", "./clawtrail-skills").option("-s, --staging", "Use staging environment", false).option("--no-register", "Skip agent registration").option("--no-interactive", "Skip interactive prompts").action(async (options) => {
272
+ program.name("clawtrail-init").description("Initialize ClawTrail skill files for AI agents").version("1.5.0").option("-d, --dir <path>", "Target directory", "./clawtrail-skills").option("-s, --staging", "Use staging environment", false).option("--no-register", "Skip agent registration").option("--no-interactive", "Skip interactive prompts").action(async (options) => {
274
273
  const targetDir = path.resolve(process.cwd(), options.dir);
275
274
  const staging = options.staging;
276
275
  await downloadSkillFiles(targetDir, staging);
@@ -324,7 +323,23 @@ async function main() {
324
323
  console.log(chalk.gray(" It will call POST /api/agents/register with its own info."));
325
324
  if (hasOpenClaw) {
326
325
  console.log(chalk.gray(" The ClawTrail skill file has been placed in your OpenClaw workspace."));
327
- console.log(chalk.gray(" Just start your bot \u2014 it will read the skill and register automatically.\n"));
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();
328
343
  } else {
329
344
  console.log(chalk.gray(" Point your agent at the SKILL.md file to get started.\n"));
330
345
  }
@@ -463,10 +478,13 @@ async function main() {
463
478
  );
464
479
  if (hasOpenClaw) {
465
480
  console.log(
466
- chalk.white("5. ") + chalk.gray("(OpenClaw) Plugin config at ") + chalk.cyan("~/.openclaw/openclaw.json")
481
+ chalk.white("5. ") + chalk.gray("(OpenClaw) Heartbeat loop: ") + chalk.cyan("every 30s") + chalk.gray(" \u2014 starts on next session")
482
+ );
483
+ console.log(
484
+ chalk.white("6. ") + chalk.gray("(OpenClaw) Config at ") + chalk.cyan("~/.openclaw/openclaw.json")
467
485
  );
468
486
  console.log(
469
- chalk.white("6. ") + chalk.gray("(OpenClaw) Skill installed to OpenClaw skills directory")
487
+ chalk.white("7. ") + chalk.gray("(OpenClaw) Skill installed to ") + chalk.cyan("~/.openclaw/skills/")
470
488
  );
471
489
  }
472
490
  const env = staging ? "staging" : "production";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawtrail/init",
3
- "version": "1.4.1",
3
+ "version": "1.5.0",
4
4
  "description": "CLI installer for ClawTrail AI agent skill files",
5
5
  "main": "dist/index.js",
6
6
  "bin": {