@clawtrail/init 2.4.0 → 2.5.1

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 +169 -14
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -97,6 +97,79 @@ 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("Setting up context-graph provenance...").start();
102
+ const openclawDir = path.join(os.homedir(), ".openclaw");
103
+ const pluginDir = path.join(openclawDir, "plugins", "context-graph");
104
+ await ensureDirectory(pluginDir);
105
+ const apiUrl = staging ? "https://sapi.clawtrail.ai/ct/api" : "https://api.clawtrail.ai/ct/api";
106
+ const cgConfig = {
107
+ submitUrl: `${apiUrl}/context-graph/submit`,
108
+ agentId: agentId || null,
109
+ apiKey: apiKey || null,
110
+ autoSubmit: true,
111
+ environment: staging ? "staging" : "production"
112
+ };
113
+ const configPath = path.join(pluginDir, "config.json");
114
+ await fs.writeFile(configPath, JSON.stringify(cgConfig, null, 2), "utf-8");
115
+ const openclawConfigPath = path.join(openclawDir, "openclaw.json");
116
+ try {
117
+ let config = {};
118
+ try {
119
+ const existing = await fs.readFile(openclawConfigPath, "utf-8");
120
+ config = JSON5.parse(existing);
121
+ } catch {
122
+ }
123
+ config.plugins ??= {};
124
+ config.plugins["context-graph"] = {
125
+ enabled: true,
126
+ configPath: "~/.openclaw/plugins/context-graph/config.json",
127
+ autoSubmit: true
128
+ };
129
+ await fs.writeFile(
130
+ openclawConfigPath,
131
+ JSON.stringify(config, null, 2),
132
+ "utf-8"
133
+ );
134
+ } catch {
135
+ }
136
+ let packagesInstalled = false;
137
+ try {
138
+ execSync(
139
+ `npm install --prefix "${pluginDir}" @clawtrail/context-graph @clawtrail/context-graph-openclaw`,
140
+ { stdio: "pipe", timeout: 12e4 }
141
+ );
142
+ packagesInstalled = true;
143
+ } catch {
144
+ try {
145
+ execSync(
146
+ "npm install -g @clawtrail/context-graph @clawtrail/context-graph-openclaw",
147
+ { stdio: "pipe", timeout: 12e4 }
148
+ );
149
+ packagesInstalled = true;
150
+ } catch {
151
+ }
152
+ }
153
+ if (packagesInstalled) {
154
+ spinner.succeed(
155
+ chalk.green(
156
+ `Context-graph configured \u2192 auto-submit to ${staging ? "staging" : "production"}`
157
+ )
158
+ );
159
+ } else {
160
+ spinner.warn(
161
+ chalk.yellow(
162
+ `Context-graph configured but packages not installed \u2014 run manually:
163
+ npm install -g @clawtrail/context-graph @clawtrail/context-graph-openclaw`
164
+ )
165
+ );
166
+ }
167
+ return {
168
+ installed: true,
169
+ configPath: "~/.openclaw/plugins/context-graph/config.json",
170
+ packagesInstalled
171
+ };
172
+ }
100
173
  async function configureOpenClaw(staging, apiKey) {
101
174
  const openClawDir = path.join(os.homedir(), ".openclaw");
102
175
  const configPath = path.join(openClawDir, "openclaw.json");
@@ -117,7 +190,7 @@ async function configureOpenClaw(staging, apiKey) {
117
190
  config.agents ??= {};
118
191
  config.agents.defaults ??= {};
119
192
  config.agents.defaults.heartbeat = {
120
- every: "5m",
193
+ every: "30m",
121
194
  target: "last"
122
195
  };
123
196
  config.skills ??= {};
@@ -132,7 +205,7 @@ async function configureOpenClaw(staging, apiKey) {
132
205
  await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
133
206
  return {
134
207
  configPath: "~/.openclaw/openclaw.json",
135
- heartbeat: "every 5m",
208
+ heartbeat: "every 30m",
136
209
  hasApiKey: !!apiKey
137
210
  };
138
211
  }
@@ -280,6 +353,26 @@ async function handleUninstall(staging) {
280
353
  } else {
281
354
  spinner1.info(chalk.gray("No skill files found to remove"));
282
355
  }
356
+ const spinner2a = ora("Removing context-graph...").start();
357
+ let cgRemoved = false;
358
+ try {
359
+ const cgPluginDir = path.join(openclawDir, "plugins", "context-graph");
360
+ await fs.rm(cgPluginDir, { recursive: true, force: true });
361
+ cgRemoved = true;
362
+ } catch {
363
+ }
364
+ try {
365
+ execSync(
366
+ "npm uninstall -g @clawtrail/context-graph @clawtrail/context-graph-openclaw",
367
+ { stdio: "pipe", timeout: 3e4 }
368
+ );
369
+ } catch {
370
+ }
371
+ if (cgRemoved) {
372
+ spinner2a.succeed(chalk.green("Removed context-graph plugin"));
373
+ } else {
374
+ spinner2a.info(chalk.gray("No context-graph plugin found"));
375
+ }
283
376
  const spinner2 = ora("Cleaning OpenClaw config...").start();
284
377
  const configPath = path.join(openclawDir, "openclaw.json");
285
378
  let configCleaned = false;
@@ -288,22 +381,31 @@ async function handleUninstall(staging) {
288
381
  const config = JSON5.parse(raw);
289
382
  if (config.agents?.defaults?.heartbeat) {
290
383
  delete config.agents.defaults.heartbeat;
291
- if (Object.keys(config.agents.defaults).length === 0) delete config.agents.defaults;
384
+ if (Object.keys(config.agents.defaults).length === 0)
385
+ delete config.agents.defaults;
292
386
  if (Object.keys(config.agents).length === 0) delete config.agents;
293
387
  }
294
388
  if (config.skills?.entries?.clawtrail) {
295
389
  delete config.skills.entries.clawtrail;
296
- if (Object.keys(config.skills.entries).length === 0) delete config.skills.entries;
390
+ if (Object.keys(config.skills.entries).length === 0)
391
+ delete config.skills.entries;
297
392
  if (Object.keys(config.skills).length === 0) delete config.skills;
298
393
  }
299
394
  if (config.skills?.entries?.["clawtrail-staging"]) {
300
395
  delete config.skills.entries["clawtrail-staging"];
301
- if (Object.keys(config.skills.entries).length === 0) delete config.skills.entries;
396
+ if (Object.keys(config.skills.entries).length === 0)
397
+ delete config.skills.entries;
302
398
  if (Object.keys(config.skills).length === 0) delete config.skills;
303
399
  }
400
+ if (config.plugins?.["context-graph"]) {
401
+ delete config.plugins["context-graph"];
402
+ if (Object.keys(config.plugins).length === 0) delete config.plugins;
403
+ }
304
404
  await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
305
405
  configCleaned = true;
306
- spinner2.succeed(chalk.green("Removed ClawTrail config from openclaw.json"));
406
+ spinner2.succeed(
407
+ chalk.green("Removed ClawTrail config from openclaw.json")
408
+ );
307
409
  } catch {
308
410
  spinner2.info(chalk.gray("No openclaw.json found or nothing to clean"));
309
411
  }
@@ -332,7 +434,9 @@ async function handleUninstall(staging) {
332
434
  chalk.green(`Gateway restarted \u2014 ${cleared} cached sessions cleared`)
333
435
  );
334
436
  } else {
335
- spinner3.warn(chalk.yellow("Gateway killed but may not have restarted"));
437
+ spinner3.warn(
438
+ chalk.yellow("Gateway killed but may not have restarted")
439
+ );
336
440
  }
337
441
  } catch (err) {
338
442
  const message = err instanceof Error ? err.message : String(err);
@@ -345,11 +449,20 @@ async function handleUninstall(staging) {
345
449
  console.log(chalk.white(" Removed: ") + chalk.red(f));
346
450
  }
347
451
  }
452
+ if (cgRemoved) {
453
+ console.log(
454
+ chalk.white(" Removed: ") + chalk.red("~/.openclaw/plugins/context-graph/")
455
+ );
456
+ }
348
457
  if (configCleaned) {
349
- console.log(chalk.white(" Config: ") + chalk.green("cleaned ~/.openclaw/openclaw.json"));
458
+ console.log(
459
+ chalk.white(" Config: ") + chalk.green("cleaned ~/.openclaw/openclaw.json")
460
+ );
350
461
  }
351
462
  if (gatewayRestarted) {
352
- console.log(chalk.white(" Gateway: ") + chalk.green("restarted (ClawTrail skill removed)"));
463
+ console.log(
464
+ chalk.white(" Gateway: ") + chalk.green("restarted (ClawTrail skill removed)")
465
+ );
353
466
  }
354
467
  console.log(chalk.yellow("\n ClawTrail has been uninstalled.\n"));
355
468
  console.log(
@@ -361,7 +474,7 @@ async function main() {
361
474
  const program = new Command();
362
475
  program.name("clawtrail-init").description(
363
476
  "Install ClawTrail skill files, configure heartbeat, and optionally register an agent"
364
- ).version("2.4.0").option(
477
+ ).version("2.5.1").option(
365
478
  "-d, --dir <path>",
366
479
  "Download directory for skill files",
367
480
  "./clawtrail-skills"
@@ -378,7 +491,13 @@ async function main() {
378
491
  ).option(
379
492
  "--api-key <key>",
380
493
  "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) => {
494
+ ).option("--no-restart", "Skip gateway restart after updating files").option(
495
+ "--no-context-graph",
496
+ "Skip context-graph provenance tracking installation"
497
+ ).option(
498
+ "--uninstall",
499
+ "Remove ClawTrail skill files, config, and restart gateway"
500
+ ).action(async (options) => {
382
501
  if (options.uninstall) {
383
502
  await handleUninstall(options.staging);
384
503
  return;
@@ -418,7 +537,9 @@ async function main() {
418
537
  const failedFiles = downloads.filter((_, i) => results[i]?.status === "rejected").map((d) => path.basename(d.dest));
419
538
  if (placedFiles.length === 0) {
420
539
  spinner.fail(
421
- chalk.red("Failed to download skill files \u2014 check your internet connection")
540
+ chalk.red(
541
+ "Failed to download skill files \u2014 check your internet connection"
542
+ )
422
543
  );
423
544
  throw new Error("All downloads failed");
424
545
  } else if (failedFiles.length > 0) {
@@ -429,7 +550,9 @@ async function main() {
429
550
  );
430
551
  } else {
431
552
  spinner.succeed(
432
- chalk.green(`Downloaded ${placedFiles.length} skill files directly to OpenClaw (${env})`)
553
+ chalk.green(
554
+ `Downloaded ${placedFiles.length} skill files directly to OpenClaw (${env})`
555
+ )
433
556
  );
434
557
  }
435
558
  targetDir = path.join(openclawDir, "skills", skillFolder);
@@ -472,12 +595,24 @@ async function main() {
472
595
  try {
473
596
  ocConfig = await configureOpenClaw(staging, apiKey);
474
597
  spinner.succeed(
475
- chalk.green(`Heartbeat configured: ${chalk.cyan("every 5m")}`)
598
+ chalk.green(`Heartbeat configured: ${chalk.cyan("every 30m")}`)
476
599
  );
477
600
  } catch (err) {
478
601
  spinner.warn(chalk.yellow(`Config failed: ${err.message}`));
479
602
  }
480
603
  }
604
+ let cgResult;
605
+ if (options.contextGraph !== false) {
606
+ try {
607
+ cgResult = await installContextGraph(staging, agentId, apiKey);
608
+ } catch (err) {
609
+ console.log(
610
+ chalk.yellow(
611
+ ` Context-graph setup skipped: ${err.message}`
612
+ )
613
+ );
614
+ }
615
+ }
481
616
  let gatewayRestarted = false;
482
617
  if (hasOpenClaw && options.restart !== false) {
483
618
  const newHeartbeatVersion = getHeartbeatVersion(heartbeatPath);
@@ -541,6 +676,26 @@ CLAWTRAIL_API_KEY=${apiKey}
541
676
  chalk.gray(" (save this \u2014 shown only once)")
542
677
  );
543
678
  }
679
+ if (cgResult?.installed) {
680
+ if (cgResult.packagesInstalled) {
681
+ console.log(
682
+ chalk.white(" Provenance: ") + chalk.green("context-graph installed (auto-submit enabled)")
683
+ );
684
+ } else {
685
+ console.log(
686
+ chalk.white(" Provenance: ") + chalk.yellow("configured (packages need manual install)")
687
+ );
688
+ }
689
+ if (cgResult.configPath) {
690
+ console.log(
691
+ chalk.white(" CG config: ") + chalk.cyan(cgResult.configPath)
692
+ );
693
+ }
694
+ } else if (options.contextGraph === false) {
695
+ console.log(
696
+ chalk.white(" Provenance: ") + chalk.gray("skipped (--no-context-graph)")
697
+ );
698
+ }
544
699
  if (gatewayRestarted) {
545
700
  console.log(
546
701
  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.1",
4
4
  "description": "CLI installer for ClawTrail AI agent skill files",
5
5
  "main": "dist/index.js",
6
6
  "bin": {