nextclaw 0.4.4 → 0.4.5
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/cli/index.js +158 -60
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -35,7 +35,7 @@ import { startUiServer } from "nextclaw-server";
|
|
|
35
35
|
import {
|
|
36
36
|
closeSync,
|
|
37
37
|
cpSync,
|
|
38
|
-
existsSync as
|
|
38
|
+
existsSync as existsSync4,
|
|
39
39
|
mkdirSync as mkdirSync2,
|
|
40
40
|
openSync,
|
|
41
41
|
readdirSync,
|
|
@@ -43,8 +43,8 @@ import {
|
|
|
43
43
|
rmSync as rmSync2,
|
|
44
44
|
writeFileSync as writeFileSync2
|
|
45
45
|
} from "fs";
|
|
46
|
-
import { dirname, join as
|
|
47
|
-
import { spawn as spawn2, spawnSync as
|
|
46
|
+
import { dirname, join as join4, resolve as resolve4 } from "path";
|
|
47
|
+
import { spawn as spawn2, spawnSync as spawnSync3 } from "child_process";
|
|
48
48
|
import { createInterface } from "readline";
|
|
49
49
|
import { createRequire } from "module";
|
|
50
50
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -98,12 +98,12 @@ async function isPortAvailable(port, host) {
|
|
|
98
98
|
return await canBindPort(port, checkHost);
|
|
99
99
|
}
|
|
100
100
|
async function canBindPort(port, host) {
|
|
101
|
-
return await new Promise((
|
|
101
|
+
return await new Promise((resolve5) => {
|
|
102
102
|
const server = createServer();
|
|
103
103
|
server.unref();
|
|
104
|
-
server.once("error", () =>
|
|
104
|
+
server.once("error", () => resolve5(false));
|
|
105
105
|
server.listen({ port, host }, () => {
|
|
106
|
-
server.close(() =>
|
|
106
|
+
server.close(() => resolve5(true));
|
|
107
107
|
});
|
|
108
108
|
});
|
|
109
109
|
}
|
|
@@ -161,7 +161,7 @@ async function waitForExit(pid, timeoutMs) {
|
|
|
161
161
|
if (!isProcessRunning(pid)) {
|
|
162
162
|
return true;
|
|
163
163
|
}
|
|
164
|
-
await new Promise((
|
|
164
|
+
await new Promise((resolve5) => setTimeout(resolve5, 200));
|
|
165
165
|
}
|
|
166
166
|
return !isProcessRunning(pid);
|
|
167
167
|
}
|
|
@@ -292,8 +292,8 @@ function printAgentResponse(response) {
|
|
|
292
292
|
async function prompt(rl, question) {
|
|
293
293
|
rl.setPrompt(question);
|
|
294
294
|
rl.prompt();
|
|
295
|
-
return new Promise((
|
|
296
|
-
rl.once("line", (line) =>
|
|
295
|
+
return new Promise((resolve5) => {
|
|
296
|
+
rl.once("line", (line) => resolve5(line));
|
|
297
297
|
});
|
|
298
298
|
}
|
|
299
299
|
|
|
@@ -571,6 +571,76 @@ var GatewayControllerImpl = class {
|
|
|
571
571
|
}
|
|
572
572
|
};
|
|
573
573
|
|
|
574
|
+
// src/cli/skills/clawhub.ts
|
|
575
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
576
|
+
import { existsSync as existsSync3 } from "fs";
|
|
577
|
+
import { isAbsolute, join as join3, resolve as resolve3 } from "path";
|
|
578
|
+
async function installClawHubSkill(options) {
|
|
579
|
+
const slug = options.slug.trim();
|
|
580
|
+
if (!slug) {
|
|
581
|
+
throw new Error("Skill slug is required.");
|
|
582
|
+
}
|
|
583
|
+
const workdir = resolve3(options.workdir);
|
|
584
|
+
if (!existsSync3(workdir)) {
|
|
585
|
+
throw new Error(`Workdir does not exist: ${workdir}`);
|
|
586
|
+
}
|
|
587
|
+
const dirName = options.dir?.trim() || "skills";
|
|
588
|
+
const destinationDir = isAbsolute(dirName) ? resolve3(dirName, slug) : resolve3(workdir, dirName, slug);
|
|
589
|
+
const skillFile = join3(destinationDir, "SKILL.md");
|
|
590
|
+
if (!options.force && existsSync3(destinationDir)) {
|
|
591
|
+
if (existsSync3(skillFile)) {
|
|
592
|
+
return {
|
|
593
|
+
slug,
|
|
594
|
+
version: options.version,
|
|
595
|
+
registry: options.registry,
|
|
596
|
+
destinationDir,
|
|
597
|
+
alreadyInstalled: true
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
throw new Error(`Skill directory already exists: ${destinationDir} (use --force)`);
|
|
601
|
+
}
|
|
602
|
+
const args = buildClawHubArgs(slug, options);
|
|
603
|
+
const result = spawnSync2("npx", args, {
|
|
604
|
+
cwd: workdir,
|
|
605
|
+
stdio: "pipe",
|
|
606
|
+
env: process.env
|
|
607
|
+
});
|
|
608
|
+
if (result.error) {
|
|
609
|
+
throw new Error(`Failed to run npx clawhub: ${String(result.error)}`);
|
|
610
|
+
}
|
|
611
|
+
if (result.status !== 0) {
|
|
612
|
+
const stdout = result.stdout ? String(result.stdout).trim() : "";
|
|
613
|
+
const stderr = result.stderr ? String(result.stderr).trim() : "";
|
|
614
|
+
const details = [stderr, stdout].filter(Boolean).join("\n");
|
|
615
|
+
throw new Error(details || `clawhub install failed with code ${result.status ?? 1}`);
|
|
616
|
+
}
|
|
617
|
+
return {
|
|
618
|
+
slug,
|
|
619
|
+
version: options.version,
|
|
620
|
+
registry: options.registry,
|
|
621
|
+
destinationDir
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
function buildClawHubArgs(slug, options) {
|
|
625
|
+
const args = ["--yes", "clawhub", "install", slug];
|
|
626
|
+
if (options.version) {
|
|
627
|
+
args.push("--version", options.version);
|
|
628
|
+
}
|
|
629
|
+
if (options.registry) {
|
|
630
|
+
args.push("--registry", options.registry);
|
|
631
|
+
}
|
|
632
|
+
if (options.workdir) {
|
|
633
|
+
args.push("--workdir", options.workdir);
|
|
634
|
+
}
|
|
635
|
+
if (options.dir) {
|
|
636
|
+
args.push("--dir", options.dir);
|
|
637
|
+
}
|
|
638
|
+
if (options.force) {
|
|
639
|
+
args.push("--force");
|
|
640
|
+
}
|
|
641
|
+
return args;
|
|
642
|
+
}
|
|
643
|
+
|
|
574
644
|
// src/cli/runtime.ts
|
|
575
645
|
var LOGO = "\u{1F916}";
|
|
576
646
|
var EXIT_COMMANDS = /* @__PURE__ */ new Set(["exit", "quit", "/exit", "/quit", ":q"]);
|
|
@@ -699,15 +769,15 @@ var CliRuntime = class {
|
|
|
699
769
|
const force = Boolean(options.force);
|
|
700
770
|
const configPath = getConfigPath();
|
|
701
771
|
let createdConfig = false;
|
|
702
|
-
if (!
|
|
772
|
+
if (!existsSync4(configPath)) {
|
|
703
773
|
const config2 = ConfigSchema2.parse({});
|
|
704
774
|
saveConfig(config2);
|
|
705
775
|
createdConfig = true;
|
|
706
776
|
}
|
|
707
777
|
const config = loadConfig();
|
|
708
778
|
const workspaceSetting = config.agents.defaults.workspace;
|
|
709
|
-
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ?
|
|
710
|
-
const workspaceExisted =
|
|
779
|
+
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join4(getDataDir2(), DEFAULT_WORKSPACE_DIR) : expandHome(workspaceSetting);
|
|
780
|
+
const workspaceExisted = existsSync4(workspacePath);
|
|
711
781
|
mkdirSync2(workspacePath, { recursive: true });
|
|
712
782
|
const templateResult = this.createWorkspaceTemplates(workspacePath, { force });
|
|
713
783
|
if (createdConfig) {
|
|
@@ -871,10 +941,10 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
871
941
|
}
|
|
872
942
|
console.log(`${this.logo} Interactive mode (type exit or Ctrl+C to quit)
|
|
873
943
|
`);
|
|
874
|
-
const historyFile =
|
|
875
|
-
const historyDir =
|
|
944
|
+
const historyFile = join4(getDataDir2(), "history", "cli_history");
|
|
945
|
+
const historyDir = resolve4(historyFile, "..");
|
|
876
946
|
mkdirSync2(historyDir, { recursive: true });
|
|
877
|
-
const history =
|
|
947
|
+
const history = existsSync4(historyFile) ? readFileSync3(historyFile, "utf-8").split("\n").filter(Boolean) : [];
|
|
878
948
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
879
949
|
rl.on("close", () => {
|
|
880
950
|
const merged = history.concat(rl.history ?? []);
|
|
@@ -900,6 +970,27 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
900
970
|
printAgentResponse(response);
|
|
901
971
|
}
|
|
902
972
|
}
|
|
973
|
+
async skillsInstall(options) {
|
|
974
|
+
const workdir = options.workdir ? expandHome(options.workdir) : getWorkspacePath();
|
|
975
|
+
const result = await installClawHubSkill({
|
|
976
|
+
slug: options.slug,
|
|
977
|
+
version: options.version,
|
|
978
|
+
registry: options.registry,
|
|
979
|
+
workdir,
|
|
980
|
+
dir: options.dir,
|
|
981
|
+
force: options.force
|
|
982
|
+
});
|
|
983
|
+
const versionLabel = result.version ?? "latest";
|
|
984
|
+
if (result.alreadyInstalled) {
|
|
985
|
+
console.log(`\u2713 ${result.slug} is already installed`);
|
|
986
|
+
} else {
|
|
987
|
+
console.log(`\u2713 Installed ${result.slug}@${versionLabel}`);
|
|
988
|
+
}
|
|
989
|
+
if (result.registry) {
|
|
990
|
+
console.log(` Registry: ${result.registry}`);
|
|
991
|
+
}
|
|
992
|
+
console.log(` Path: ${result.destinationDir}`);
|
|
993
|
+
}
|
|
903
994
|
channelsStatus() {
|
|
904
995
|
const config = loadConfig();
|
|
905
996
|
console.log("Channel Status");
|
|
@@ -915,13 +1006,13 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
915
1006
|
const bridgeDir = this.getBridgeDir();
|
|
916
1007
|
console.log(`${this.logo} Starting bridge...`);
|
|
917
1008
|
console.log("Scan the QR code to connect.\n");
|
|
918
|
-
const result =
|
|
1009
|
+
const result = spawnSync3("npm", ["start"], { cwd: bridgeDir, stdio: "inherit" });
|
|
919
1010
|
if (result.status !== 0) {
|
|
920
1011
|
console.error(`Bridge failed: ${result.status ?? 1}`);
|
|
921
1012
|
}
|
|
922
1013
|
}
|
|
923
1014
|
cronList(opts) {
|
|
924
|
-
const storePath =
|
|
1015
|
+
const storePath = join4(getDataDir2(), "cron", "jobs.json");
|
|
925
1016
|
const service = new CronService(storePath);
|
|
926
1017
|
const jobs = service.listJobs(Boolean(opts.all));
|
|
927
1018
|
if (!jobs.length) {
|
|
@@ -941,7 +1032,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
941
1032
|
}
|
|
942
1033
|
}
|
|
943
1034
|
cronAdd(opts) {
|
|
944
|
-
const storePath =
|
|
1035
|
+
const storePath = join4(getDataDir2(), "cron", "jobs.json");
|
|
945
1036
|
const service = new CronService(storePath);
|
|
946
1037
|
let schedule = null;
|
|
947
1038
|
if (opts.every) {
|
|
@@ -966,7 +1057,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
966
1057
|
console.log(`\u2713 Added job '${job.name}' (${job.id})`);
|
|
967
1058
|
}
|
|
968
1059
|
cronRemove(jobId) {
|
|
969
|
-
const storePath =
|
|
1060
|
+
const storePath = join4(getDataDir2(), "cron", "jobs.json");
|
|
970
1061
|
const service = new CronService(storePath);
|
|
971
1062
|
if (service.removeJob(jobId)) {
|
|
972
1063
|
console.log(`\u2713 Removed job ${jobId}`);
|
|
@@ -975,7 +1066,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
975
1066
|
}
|
|
976
1067
|
}
|
|
977
1068
|
cronEnable(jobId, opts) {
|
|
978
|
-
const storePath =
|
|
1069
|
+
const storePath = join4(getDataDir2(), "cron", "jobs.json");
|
|
979
1070
|
const service = new CronService(storePath);
|
|
980
1071
|
const job = service.enableJob(jobId, !opts.disable);
|
|
981
1072
|
if (job) {
|
|
@@ -985,7 +1076,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
985
1076
|
}
|
|
986
1077
|
}
|
|
987
1078
|
async cronRun(jobId, opts) {
|
|
988
|
-
const storePath =
|
|
1079
|
+
const storePath = join4(getDataDir2(), "cron", "jobs.json");
|
|
989
1080
|
const service = new CronService(storePath);
|
|
990
1081
|
const ok = await service.runJob(jobId, Boolean(opts.force));
|
|
991
1082
|
console.log(ok ? "\u2713 Job executed" : `Failed to run job ${jobId}`);
|
|
@@ -996,8 +1087,8 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
996
1087
|
const workspace = getWorkspacePath(config.agents.defaults.workspace);
|
|
997
1088
|
console.log(`${this.logo} ${APP_NAME} Status
|
|
998
1089
|
`);
|
|
999
|
-
console.log(`Config: ${configPath} ${
|
|
1000
|
-
console.log(`Workspace: ${workspace} ${
|
|
1090
|
+
console.log(`Config: ${configPath} ${existsSync4(configPath) ? "\u2713" : "\u2717"}`);
|
|
1091
|
+
console.log(`Workspace: ${workspace} ${existsSync4(workspace) ? "\u2713" : "\u2717"}`);
|
|
1001
1092
|
console.log(`Model: ${config.agents.defaults.model}`);
|
|
1002
1093
|
for (const spec of PROVIDERS) {
|
|
1003
1094
|
const provider = config.providers[spec.name];
|
|
@@ -1017,7 +1108,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1017
1108
|
const provider = options.allowMissingProvider === true ? this.makeProvider(config, { allowMissing: true }) : this.makeProvider(config);
|
|
1018
1109
|
const providerManager = provider ? new ProviderManager(provider) : null;
|
|
1019
1110
|
const sessionManager = new SessionManager(getWorkspacePath(config.agents.defaults.workspace));
|
|
1020
|
-
const cronStorePath =
|
|
1111
|
+
const cronStorePath = join4(getDataDir2(), "cron", "jobs.json");
|
|
1021
1112
|
const cron2 = new CronService(cronStorePath);
|
|
1022
1113
|
const uiConfig = resolveUiConfig(config, options.uiOverrides);
|
|
1023
1114
|
const uiStaticDir = options.uiStaticDir === void 0 ? resolveUiStaticDir() : options.uiStaticDir;
|
|
@@ -1182,7 +1273,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1182
1273
|
console.log("Warning: UI frontend not found. Use --frontend to start the dev server.");
|
|
1183
1274
|
}
|
|
1184
1275
|
const logPath = resolveServiceLogPath();
|
|
1185
|
-
const logDir =
|
|
1276
|
+
const logDir = resolve4(logPath, "..");
|
|
1186
1277
|
mkdirSync2(logDir, { recursive: true });
|
|
1187
1278
|
const logFd = openSync(logPath, "a");
|
|
1188
1279
|
const serveArgs = buildServeArgs({
|
|
@@ -1291,12 +1382,12 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1291
1382
|
{ source: "memory/MEMORY.md", target: "memory/MEMORY.md" }
|
|
1292
1383
|
];
|
|
1293
1384
|
for (const entry of templateFiles) {
|
|
1294
|
-
const filePath =
|
|
1295
|
-
if (!force &&
|
|
1385
|
+
const filePath = join4(workspace, entry.target);
|
|
1386
|
+
if (!force && existsSync4(filePath)) {
|
|
1296
1387
|
continue;
|
|
1297
1388
|
}
|
|
1298
|
-
const templatePath =
|
|
1299
|
-
if (!
|
|
1389
|
+
const templatePath = join4(templateDir, entry.source);
|
|
1390
|
+
if (!existsSync4(templatePath)) {
|
|
1300
1391
|
console.warn(`Warning: Template file missing: ${templatePath}`);
|
|
1301
1392
|
continue;
|
|
1302
1393
|
}
|
|
@@ -1306,15 +1397,15 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1306
1397
|
writeFileSync2(filePath, content);
|
|
1307
1398
|
created.push(entry.target);
|
|
1308
1399
|
}
|
|
1309
|
-
const memoryDir =
|
|
1310
|
-
if (!
|
|
1400
|
+
const memoryDir = join4(workspace, "memory");
|
|
1401
|
+
if (!existsSync4(memoryDir)) {
|
|
1311
1402
|
mkdirSync2(memoryDir, { recursive: true });
|
|
1312
|
-
created.push(
|
|
1403
|
+
created.push(join4("memory", ""));
|
|
1313
1404
|
}
|
|
1314
|
-
const skillsDir =
|
|
1315
|
-
if (!
|
|
1405
|
+
const skillsDir = join4(workspace, "skills");
|
|
1406
|
+
if (!existsSync4(skillsDir)) {
|
|
1316
1407
|
mkdirSync2(skillsDir, { recursive: true });
|
|
1317
|
-
created.push(
|
|
1408
|
+
created.push(join4("skills", ""));
|
|
1318
1409
|
}
|
|
1319
1410
|
const seeded = this.seedBuiltinSkills(skillsDir, { force });
|
|
1320
1411
|
if (seeded > 0) {
|
|
@@ -1337,12 +1428,12 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1337
1428
|
if (!entry.isDirectory()) {
|
|
1338
1429
|
continue;
|
|
1339
1430
|
}
|
|
1340
|
-
const src =
|
|
1341
|
-
if (!
|
|
1431
|
+
const src = join4(sourceDir, entry.name);
|
|
1432
|
+
if (!existsSync4(join4(src, "SKILL.md"))) {
|
|
1342
1433
|
continue;
|
|
1343
1434
|
}
|
|
1344
|
-
const dest =
|
|
1345
|
-
if (!force &&
|
|
1435
|
+
const dest = join4(targetDir, entry.name);
|
|
1436
|
+
if (!force && existsSync4(dest)) {
|
|
1346
1437
|
continue;
|
|
1347
1438
|
}
|
|
1348
1439
|
cpSync(src, dest, { recursive: true, force: true });
|
|
@@ -1354,13 +1445,13 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1354
1445
|
try {
|
|
1355
1446
|
const require2 = createRequire(import.meta.url);
|
|
1356
1447
|
const entry = require2.resolve("nextclaw-core");
|
|
1357
|
-
const pkgRoot =
|
|
1358
|
-
const distSkills =
|
|
1359
|
-
if (
|
|
1448
|
+
const pkgRoot = resolve4(dirname(entry), "..");
|
|
1449
|
+
const distSkills = join4(pkgRoot, "dist", "skills");
|
|
1450
|
+
if (existsSync4(distSkills)) {
|
|
1360
1451
|
return distSkills;
|
|
1361
1452
|
}
|
|
1362
|
-
const srcSkills =
|
|
1363
|
-
if (
|
|
1453
|
+
const srcSkills = join4(pkgRoot, "src", "agent", "skills");
|
|
1454
|
+
if (existsSync4(srcSkills)) {
|
|
1364
1455
|
return srcSkills;
|
|
1365
1456
|
}
|
|
1366
1457
|
return null;
|
|
@@ -1373,33 +1464,33 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1373
1464
|
if (override) {
|
|
1374
1465
|
return override;
|
|
1375
1466
|
}
|
|
1376
|
-
const cliDir =
|
|
1377
|
-
const pkgRoot =
|
|
1378
|
-
const candidates = [
|
|
1467
|
+
const cliDir = resolve4(fileURLToPath3(new URL(".", import.meta.url)));
|
|
1468
|
+
const pkgRoot = resolve4(cliDir, "..", "..");
|
|
1469
|
+
const candidates = [join4(pkgRoot, "templates")];
|
|
1379
1470
|
for (const candidate of candidates) {
|
|
1380
|
-
if (
|
|
1471
|
+
if (existsSync4(candidate)) {
|
|
1381
1472
|
return candidate;
|
|
1382
1473
|
}
|
|
1383
1474
|
}
|
|
1384
1475
|
return null;
|
|
1385
1476
|
}
|
|
1386
1477
|
getBridgeDir() {
|
|
1387
|
-
const userBridge =
|
|
1388
|
-
if (
|
|
1478
|
+
const userBridge = join4(getDataDir2(), "bridge");
|
|
1479
|
+
if (existsSync4(join4(userBridge, "dist", "index.js"))) {
|
|
1389
1480
|
return userBridge;
|
|
1390
1481
|
}
|
|
1391
1482
|
if (!which("npm")) {
|
|
1392
1483
|
console.error("npm not found. Please install Node.js >= 18.");
|
|
1393
1484
|
process.exit(1);
|
|
1394
1485
|
}
|
|
1395
|
-
const cliDir =
|
|
1396
|
-
const pkgRoot =
|
|
1397
|
-
const pkgBridge =
|
|
1398
|
-
const srcBridge =
|
|
1486
|
+
const cliDir = resolve4(fileURLToPath3(new URL(".", import.meta.url)));
|
|
1487
|
+
const pkgRoot = resolve4(cliDir, "..", "..");
|
|
1488
|
+
const pkgBridge = join4(pkgRoot, "bridge");
|
|
1489
|
+
const srcBridge = join4(pkgRoot, "..", "..", "bridge");
|
|
1399
1490
|
let source = null;
|
|
1400
|
-
if (
|
|
1491
|
+
if (existsSync4(join4(pkgBridge, "package.json"))) {
|
|
1401
1492
|
source = pkgBridge;
|
|
1402
|
-
} else if (
|
|
1493
|
+
} else if (existsSync4(join4(srcBridge, "package.json"))) {
|
|
1403
1494
|
source = srcBridge;
|
|
1404
1495
|
}
|
|
1405
1496
|
if (!source) {
|
|
@@ -1407,15 +1498,15 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1407
1498
|
process.exit(1);
|
|
1408
1499
|
}
|
|
1409
1500
|
console.log(`${this.logo} Setting up bridge...`);
|
|
1410
|
-
mkdirSync2(
|
|
1411
|
-
if (
|
|
1501
|
+
mkdirSync2(resolve4(userBridge, ".."), { recursive: true });
|
|
1502
|
+
if (existsSync4(userBridge)) {
|
|
1412
1503
|
rmSync2(userBridge, { recursive: true, force: true });
|
|
1413
1504
|
}
|
|
1414
1505
|
cpSync(source, userBridge, {
|
|
1415
1506
|
recursive: true,
|
|
1416
1507
|
filter: (src) => !src.includes("node_modules") && !src.includes("dist")
|
|
1417
1508
|
});
|
|
1418
|
-
const install =
|
|
1509
|
+
const install = spawnSync3("npm", ["install"], { cwd: userBridge, stdio: "pipe" });
|
|
1419
1510
|
if (install.status !== 0) {
|
|
1420
1511
|
console.error(`Bridge install failed: ${install.status ?? 1}`);
|
|
1421
1512
|
if (install.stderr) {
|
|
@@ -1423,7 +1514,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1423
1514
|
}
|
|
1424
1515
|
process.exit(1);
|
|
1425
1516
|
}
|
|
1426
|
-
const build =
|
|
1517
|
+
const build = spawnSync3("npm", ["run", "build"], { cwd: userBridge, stdio: "pipe" });
|
|
1427
1518
|
if (build.status !== 0) {
|
|
1428
1519
|
console.error(`Bridge build failed: ${build.status ?? 1}`);
|
|
1429
1520
|
if (build.stderr) {
|
|
@@ -1448,6 +1539,13 @@ program.command("start").description(`Start the ${APP_NAME2} gateway + UI in the
|
|
|
1448
1539
|
program.command("serve").description(`Run the ${APP_NAME2} gateway + UI in the foreground`).option("--ui-host <host>", "UI host").option("--ui-port <port>", "UI port").option("--frontend", "Start UI frontend dev server").option("--frontend-port <port>", "UI frontend dev server port").option("--open", "Open browser after start", false).action(async (opts) => runtime.serve(opts));
|
|
1449
1540
|
program.command("stop").description(`Stop the ${APP_NAME2} background service`).action(async () => runtime.stop());
|
|
1450
1541
|
program.command("agent").description("Interact with the agent directly").option("-m, --message <message>", "Message to send to the agent").option("-s, --session <session>", "Session ID", "cli:default").option("--no-markdown", "Disable Markdown rendering").action(async (opts) => runtime.agent(opts));
|
|
1542
|
+
var registerClawHubInstall = (cmd) => {
|
|
1543
|
+
cmd.command("install <slug>").description("Install a skill from ClawHub").option("--version <version>", "Skill version (default: latest)").option("--registry <url>", "ClawHub registry base URL").option("--workdir <dir>", "Workspace directory to install into").option("--dir <dir>", "Skills directory name (default: skills)").option("-f, --force", "Overwrite existing skill files", false).action(async (slug, opts) => runtime.skillsInstall({ slug, ...opts }));
|
|
1544
|
+
};
|
|
1545
|
+
var skills = program.command("skills").description("Manage skills");
|
|
1546
|
+
registerClawHubInstall(skills);
|
|
1547
|
+
var clawhub = program.command("clawhub").description("Install skills from ClawHub");
|
|
1548
|
+
registerClawHubInstall(clawhub);
|
|
1451
1549
|
var channels = program.command("channels").description("Manage channels");
|
|
1452
1550
|
channels.command("status").description("Show channel status").action(() => runtime.channelsStatus());
|
|
1453
1551
|
channels.command("login").description("Link device via QR code").action(() => runtime.channelsLogin());
|