nextclaw 0.4.3 → 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.
Files changed (2) hide show
  1. package/dist/cli/index.js +158 -60
  2. package/package.json +2 -2
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 existsSync3,
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 join3, resolve as resolve3 } from "path";
47
- import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
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((resolve4) => {
101
+ return await new Promise((resolve5) => {
102
102
  const server = createServer();
103
103
  server.unref();
104
- server.once("error", () => resolve4(false));
104
+ server.once("error", () => resolve5(false));
105
105
  server.listen({ port, host }, () => {
106
- server.close(() => resolve4(true));
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((resolve4) => setTimeout(resolve4, 200));
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((resolve4) => {
296
- rl.once("line", (line) => resolve4(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 (!existsSync3(configPath)) {
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 ? join3(getDataDir2(), DEFAULT_WORKSPACE_DIR) : expandHome(workspaceSetting);
710
- const workspaceExisted = existsSync3(workspacePath);
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 = join3(getDataDir2(), "history", "cli_history");
875
- const historyDir = resolve3(historyFile, "..");
944
+ const historyFile = join4(getDataDir2(), "history", "cli_history");
945
+ const historyDir = resolve4(historyFile, "..");
876
946
  mkdirSync2(historyDir, { recursive: true });
877
- const history = existsSync3(historyFile) ? readFileSync3(historyFile, "utf-8").split("\n").filter(Boolean) : [];
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 = spawnSync2("npm", ["start"], { cwd: bridgeDir, stdio: "inherit" });
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 = join3(getDataDir2(), "cron", "jobs.json");
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 = join3(getDataDir2(), "cron", "jobs.json");
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 = join3(getDataDir2(), "cron", "jobs.json");
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 = join3(getDataDir2(), "cron", "jobs.json");
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 = join3(getDataDir2(), "cron", "jobs.json");
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} ${existsSync3(configPath) ? "\u2713" : "\u2717"}`);
1000
- console.log(`Workspace: ${workspace} ${existsSync3(workspace) ? "\u2713" : "\u2717"}`);
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 = join3(getDataDir2(), "cron", "jobs.json");
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 = resolve3(logPath, "..");
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 = join3(workspace, entry.target);
1295
- if (!force && existsSync3(filePath)) {
1385
+ const filePath = join4(workspace, entry.target);
1386
+ if (!force && existsSync4(filePath)) {
1296
1387
  continue;
1297
1388
  }
1298
- const templatePath = join3(templateDir, entry.source);
1299
- if (!existsSync3(templatePath)) {
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 = join3(workspace, "memory");
1310
- if (!existsSync3(memoryDir)) {
1400
+ const memoryDir = join4(workspace, "memory");
1401
+ if (!existsSync4(memoryDir)) {
1311
1402
  mkdirSync2(memoryDir, { recursive: true });
1312
- created.push(join3("memory", ""));
1403
+ created.push(join4("memory", ""));
1313
1404
  }
1314
- const skillsDir = join3(workspace, "skills");
1315
- if (!existsSync3(skillsDir)) {
1405
+ const skillsDir = join4(workspace, "skills");
1406
+ if (!existsSync4(skillsDir)) {
1316
1407
  mkdirSync2(skillsDir, { recursive: true });
1317
- created.push(join3("skills", ""));
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 = join3(sourceDir, entry.name);
1341
- if (!existsSync3(join3(src, "SKILL.md"))) {
1431
+ const src = join4(sourceDir, entry.name);
1432
+ if (!existsSync4(join4(src, "SKILL.md"))) {
1342
1433
  continue;
1343
1434
  }
1344
- const dest = join3(targetDir, entry.name);
1345
- if (!force && existsSync3(dest)) {
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 = resolve3(dirname(entry), "..");
1358
- const distSkills = join3(pkgRoot, "dist", "skills");
1359
- if (existsSync3(distSkills)) {
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 = join3(pkgRoot, "src", "agent", "skills");
1363
- if (existsSync3(srcSkills)) {
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 = resolve3(fileURLToPath3(new URL(".", import.meta.url)));
1377
- const pkgRoot = resolve3(cliDir, "..", "..");
1378
- const candidates = [join3(pkgRoot, "templates")];
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 (existsSync3(candidate)) {
1471
+ if (existsSync4(candidate)) {
1381
1472
  return candidate;
1382
1473
  }
1383
1474
  }
1384
1475
  return null;
1385
1476
  }
1386
1477
  getBridgeDir() {
1387
- const userBridge = join3(getDataDir2(), "bridge");
1388
- if (existsSync3(join3(userBridge, "dist", "index.js"))) {
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 = resolve3(fileURLToPath3(new URL(".", import.meta.url)));
1396
- const pkgRoot = resolve3(cliDir, "..", "..");
1397
- const pkgBridge = join3(pkgRoot, "bridge");
1398
- const srcBridge = join3(pkgRoot, "..", "..", "bridge");
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 (existsSync3(join3(pkgBridge, "package.json"))) {
1491
+ if (existsSync4(join4(pkgBridge, "package.json"))) {
1401
1492
  source = pkgBridge;
1402
- } else if (existsSync3(join3(srcBridge, "package.json"))) {
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(resolve3(userBridge, ".."), { recursive: true });
1411
- if (existsSync3(userBridge)) {
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 = spawnSync2("npm", ["install"], { cwd: userBridge, stdio: "pipe" });
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 = spawnSync2("npm", ["run", "build"], { cwd: userBridge, stdio: "pipe" });
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());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextclaw",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "Lightweight personal AI assistant with CLI, multi-provider routing, and channel integrations.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -38,7 +38,7 @@
38
38
  "dependencies": {
39
39
  "chokidar": "^3.6.0",
40
40
  "commander": "^12.1.0",
41
- "nextclaw-core": "^0.4.3",
41
+ "nextclaw-core": "^0.4.4",
42
42
  "nextclaw-server": "^0.3.2"
43
43
  },
44
44
  "devDependencies": {