@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.
- package/dist/index.js +156 -14
- 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: "
|
|
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
|
|
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)
|
|
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)
|
|
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)
|
|
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(
|
|
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(
|
|
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(
|
|
451
|
+
console.log(
|
|
452
|
+
chalk.white(" Config: ") + chalk.green("cleaned ~/.openclaw/openclaw.json")
|
|
453
|
+
);
|
|
350
454
|
}
|
|
351
455
|
if (gatewayRestarted) {
|
|
352
|
-
console.log(
|
|
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.
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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)")
|