@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.
- package/dist/index.js +169 -14
- 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: "
|
|
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
|
|
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)
|
|
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)
|
|
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)
|
|
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(
|
|
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(
|
|
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(
|
|
458
|
+
console.log(
|
|
459
|
+
chalk.white(" Config: ") + chalk.green("cleaned ~/.openclaw/openclaw.json")
|
|
460
|
+
);
|
|
350
461
|
}
|
|
351
462
|
if (gatewayRestarted) {
|
|
352
|
-
console.log(
|
|
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.
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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)")
|