@clawtrail/init 2.4.0 → 2.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 +156 -14
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -97,6 +97,72 @@ async function downloadSkillFiles(targetDir, staging = false) {
97
97
  }
98
98
  return { succeeded, failed };
99
99
  }
100
+ async function installContextGraph(staging, agentId, apiKey) {
101
+ const spinner = ora("Installing context-graph packages...").start();
102
+ try {
103
+ execSync(
104
+ "npm install -g @clawtrail/context-graph @clawtrail/context-graph-openclaw",
105
+ { stdio: "pipe", timeout: 12e4 }
106
+ );
107
+ } catch (err) {
108
+ try {
109
+ execSync(
110
+ "npm install @clawtrail/context-graph @clawtrail/context-graph-openclaw",
111
+ { stdio: "pipe", timeout: 12e4 }
112
+ );
113
+ } catch {
114
+ spinner.warn(
115
+ chalk.yellow(
116
+ "Could not install context-graph packages \u2014 install manually:\n npm install @clawtrail/context-graph @clawtrail/context-graph-openclaw"
117
+ )
118
+ );
119
+ return { installed: false, configPath: null, error: err.message };
120
+ }
121
+ }
122
+ const openclawDir = path.join(os.homedir(), ".openclaw");
123
+ const pluginDir = path.join(openclawDir, "plugins", "context-graph");
124
+ await ensureDirectory(pluginDir);
125
+ const apiUrl = staging ? "https://sapi.clawtrail.ai/ct/api" : "https://api.clawtrail.ai/ct/api";
126
+ const cgConfig = {
127
+ submitUrl: `${apiUrl}/context-graph/submit`,
128
+ agentId: agentId || null,
129
+ apiKey: apiKey || null,
130
+ autoSubmit: true,
131
+ environment: staging ? "staging" : "production"
132
+ };
133
+ const configPath = path.join(pluginDir, "config.json");
134
+ await fs.writeFile(configPath, JSON.stringify(cgConfig, null, 2), "utf-8");
135
+ const openclawConfigPath = path.join(openclawDir, "openclaw.json");
136
+ try {
137
+ let config = {};
138
+ try {
139
+ const existing = await fs.readFile(openclawConfigPath, "utf-8");
140
+ config = JSON5.parse(existing);
141
+ } catch {
142
+ }
143
+ config.plugins ??= {};
144
+ config.plugins["context-graph"] = {
145
+ enabled: true,
146
+ configPath: "~/.openclaw/plugins/context-graph/config.json",
147
+ autoSubmit: true
148
+ };
149
+ await fs.writeFile(
150
+ openclawConfigPath,
151
+ JSON.stringify(config, null, 2),
152
+ "utf-8"
153
+ );
154
+ } catch {
155
+ }
156
+ spinner.succeed(
157
+ chalk.green(
158
+ `Context-graph installed \u2192 auto-submit to ${staging ? "staging" : "production"}`
159
+ )
160
+ );
161
+ return {
162
+ installed: true,
163
+ configPath: "~/.openclaw/plugins/context-graph/config.json"
164
+ };
165
+ }
100
166
  async function configureOpenClaw(staging, apiKey) {
101
167
  const openClawDir = path.join(os.homedir(), ".openclaw");
102
168
  const configPath = path.join(openClawDir, "openclaw.json");
@@ -117,7 +183,7 @@ async function configureOpenClaw(staging, apiKey) {
117
183
  config.agents ??= {};
118
184
  config.agents.defaults ??= {};
119
185
  config.agents.defaults.heartbeat = {
120
- every: "5m",
186
+ every: "30m",
121
187
  target: "last"
122
188
  };
123
189
  config.skills ??= {};
@@ -132,7 +198,7 @@ async function configureOpenClaw(staging, apiKey) {
132
198
  await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
133
199
  return {
134
200
  configPath: "~/.openclaw/openclaw.json",
135
- heartbeat: "every 5m",
201
+ heartbeat: "every 30m",
136
202
  hasApiKey: !!apiKey
137
203
  };
138
204
  }
@@ -280,6 +346,26 @@ async function handleUninstall(staging) {
280
346
  } else {
281
347
  spinner1.info(chalk.gray("No skill files found to remove"));
282
348
  }
349
+ const spinner2a = ora("Removing context-graph...").start();
350
+ let cgRemoved = false;
351
+ try {
352
+ const cgPluginDir = path.join(openclawDir, "plugins", "context-graph");
353
+ await fs.rm(cgPluginDir, { recursive: true, force: true });
354
+ cgRemoved = true;
355
+ } catch {
356
+ }
357
+ try {
358
+ execSync(
359
+ "npm uninstall -g @clawtrail/context-graph @clawtrail/context-graph-openclaw",
360
+ { stdio: "pipe", timeout: 3e4 }
361
+ );
362
+ } catch {
363
+ }
364
+ if (cgRemoved) {
365
+ spinner2a.succeed(chalk.green("Removed context-graph plugin"));
366
+ } else {
367
+ spinner2a.info(chalk.gray("No context-graph plugin found"));
368
+ }
283
369
  const spinner2 = ora("Cleaning OpenClaw config...").start();
284
370
  const configPath = path.join(openclawDir, "openclaw.json");
285
371
  let configCleaned = false;
@@ -288,22 +374,31 @@ async function handleUninstall(staging) {
288
374
  const config = JSON5.parse(raw);
289
375
  if (config.agents?.defaults?.heartbeat) {
290
376
  delete config.agents.defaults.heartbeat;
291
- if (Object.keys(config.agents.defaults).length === 0) delete config.agents.defaults;
377
+ if (Object.keys(config.agents.defaults).length === 0)
378
+ delete config.agents.defaults;
292
379
  if (Object.keys(config.agents).length === 0) delete config.agents;
293
380
  }
294
381
  if (config.skills?.entries?.clawtrail) {
295
382
  delete config.skills.entries.clawtrail;
296
- if (Object.keys(config.skills.entries).length === 0) delete config.skills.entries;
383
+ if (Object.keys(config.skills.entries).length === 0)
384
+ delete config.skills.entries;
297
385
  if (Object.keys(config.skills).length === 0) delete config.skills;
298
386
  }
299
387
  if (config.skills?.entries?.["clawtrail-staging"]) {
300
388
  delete config.skills.entries["clawtrail-staging"];
301
- if (Object.keys(config.skills.entries).length === 0) delete config.skills.entries;
389
+ if (Object.keys(config.skills.entries).length === 0)
390
+ delete config.skills.entries;
302
391
  if (Object.keys(config.skills).length === 0) delete config.skills;
303
392
  }
393
+ if (config.plugins?.["context-graph"]) {
394
+ delete config.plugins["context-graph"];
395
+ if (Object.keys(config.plugins).length === 0) delete config.plugins;
396
+ }
304
397
  await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
305
398
  configCleaned = true;
306
- spinner2.succeed(chalk.green("Removed ClawTrail config from openclaw.json"));
399
+ spinner2.succeed(
400
+ chalk.green("Removed ClawTrail config from openclaw.json")
401
+ );
307
402
  } catch {
308
403
  spinner2.info(chalk.gray("No openclaw.json found or nothing to clean"));
309
404
  }
@@ -332,7 +427,9 @@ async function handleUninstall(staging) {
332
427
  chalk.green(`Gateway restarted \u2014 ${cleared} cached sessions cleared`)
333
428
  );
334
429
  } else {
335
- spinner3.warn(chalk.yellow("Gateway killed but may not have restarted"));
430
+ spinner3.warn(
431
+ chalk.yellow("Gateway killed but may not have restarted")
432
+ );
336
433
  }
337
434
  } catch (err) {
338
435
  const message = err instanceof Error ? err.message : String(err);
@@ -345,11 +442,20 @@ async function handleUninstall(staging) {
345
442
  console.log(chalk.white(" Removed: ") + chalk.red(f));
346
443
  }
347
444
  }
445
+ if (cgRemoved) {
446
+ console.log(
447
+ chalk.white(" Removed: ") + chalk.red("~/.openclaw/plugins/context-graph/")
448
+ );
449
+ }
348
450
  if (configCleaned) {
349
- console.log(chalk.white(" Config: ") + chalk.green("cleaned ~/.openclaw/openclaw.json"));
451
+ console.log(
452
+ chalk.white(" Config: ") + chalk.green("cleaned ~/.openclaw/openclaw.json")
453
+ );
350
454
  }
351
455
  if (gatewayRestarted) {
352
- console.log(chalk.white(" Gateway: ") + chalk.green("restarted (ClawTrail skill removed)"));
456
+ console.log(
457
+ chalk.white(" Gateway: ") + chalk.green("restarted (ClawTrail skill removed)")
458
+ );
353
459
  }
354
460
  console.log(chalk.yellow("\n ClawTrail has been uninstalled.\n"));
355
461
  console.log(
@@ -361,7 +467,7 @@ async function main() {
361
467
  const program = new Command();
362
468
  program.name("clawtrail-init").description(
363
469
  "Install ClawTrail skill files, configure heartbeat, and optionally register an agent"
364
- ).version("2.4.0").option(
470
+ ).version("2.5.0").option(
365
471
  "-d, --dir <path>",
366
472
  "Download directory for skill files",
367
473
  "./clawtrail-skills"
@@ -378,7 +484,13 @@ async function main() {
378
484
  ).option(
379
485
  "--api-key <key>",
380
486
  "Existing API key (skip registration, just configure)"
381
- ).option("--no-restart", "Skip gateway restart after updating files").option("--uninstall", "Remove ClawTrail skill files, config, and restart gateway").action(async (options) => {
487
+ ).option("--no-restart", "Skip gateway restart after updating files").option(
488
+ "--no-context-graph",
489
+ "Skip context-graph provenance tracking installation"
490
+ ).option(
491
+ "--uninstall",
492
+ "Remove ClawTrail skill files, config, and restart gateway"
493
+ ).action(async (options) => {
382
494
  if (options.uninstall) {
383
495
  await handleUninstall(options.staging);
384
496
  return;
@@ -418,7 +530,9 @@ async function main() {
418
530
  const failedFiles = downloads.filter((_, i) => results[i]?.status === "rejected").map((d) => path.basename(d.dest));
419
531
  if (placedFiles.length === 0) {
420
532
  spinner.fail(
421
- chalk.red("Failed to download skill files \u2014 check your internet connection")
533
+ chalk.red(
534
+ "Failed to download skill files \u2014 check your internet connection"
535
+ )
422
536
  );
423
537
  throw new Error("All downloads failed");
424
538
  } else if (failedFiles.length > 0) {
@@ -429,7 +543,9 @@ async function main() {
429
543
  );
430
544
  } else {
431
545
  spinner.succeed(
432
- chalk.green(`Downloaded ${placedFiles.length} skill files directly to OpenClaw (${env})`)
546
+ chalk.green(
547
+ `Downloaded ${placedFiles.length} skill files directly to OpenClaw (${env})`
548
+ )
433
549
  );
434
550
  }
435
551
  targetDir = path.join(openclawDir, "skills", skillFolder);
@@ -472,12 +588,24 @@ async function main() {
472
588
  try {
473
589
  ocConfig = await configureOpenClaw(staging, apiKey);
474
590
  spinner.succeed(
475
- chalk.green(`Heartbeat configured: ${chalk.cyan("every 5m")}`)
591
+ chalk.green(`Heartbeat configured: ${chalk.cyan("every 30m")}`)
476
592
  );
477
593
  } catch (err) {
478
594
  spinner.warn(chalk.yellow(`Config failed: ${err.message}`));
479
595
  }
480
596
  }
597
+ let cgResult;
598
+ if (options.contextGraph !== false) {
599
+ try {
600
+ cgResult = await installContextGraph(staging, agentId, apiKey);
601
+ } catch (err) {
602
+ console.log(
603
+ chalk.yellow(
604
+ ` Context-graph setup skipped: ${err.message}`
605
+ )
606
+ );
607
+ }
608
+ }
481
609
  let gatewayRestarted = false;
482
610
  if (hasOpenClaw && options.restart !== false) {
483
611
  const newHeartbeatVersion = getHeartbeatVersion(heartbeatPath);
@@ -541,6 +669,20 @@ CLAWTRAIL_API_KEY=${apiKey}
541
669
  chalk.gray(" (save this \u2014 shown only once)")
542
670
  );
543
671
  }
672
+ if (cgResult?.installed) {
673
+ console.log(
674
+ chalk.white(" Provenance: ") + chalk.green("context-graph installed (auto-submit enabled)")
675
+ );
676
+ if (cgResult.configPath) {
677
+ console.log(
678
+ chalk.white(" CG config: ") + chalk.cyan(cgResult.configPath)
679
+ );
680
+ }
681
+ } else if (options.contextGraph === false) {
682
+ console.log(
683
+ chalk.white(" Provenance: ") + chalk.gray("skipped (--no-context-graph)")
684
+ );
685
+ }
544
686
  if (gatewayRestarted) {
545
687
  console.log(
546
688
  chalk.white(" Gateway: ") + chalk.green("restarted (sessions cleared, new heartbeat active)")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawtrail/init",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "CLI installer for ClawTrail AI agent skill files",
5
5
  "main": "dist/index.js",
6
6
  "bin": {