nextclaw 0.9.10 → 0.9.11

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 CHANGED
@@ -26,7 +26,7 @@ import {
26
26
  resolvePluginChannelMessageToolHints as resolvePluginChannelMessageToolHints2,
27
27
  setPluginRuntimeBridge as setPluginRuntimeBridge2
28
28
  } from "@nextclaw/openclaw-compat";
29
- import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
29
+ import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
30
30
  import { join as join7, resolve as resolve9 } from "path";
31
31
  import { createInterface as createInterface2 } from "readline";
32
32
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -1831,8 +1831,8 @@ import { join as join3 } from "path";
1831
1831
  var CronCommands = class {
1832
1832
  cronList(opts) {
1833
1833
  const storePath = join3(getDataDir3(), "cron", "jobs.json");
1834
- const service2 = new CronService(storePath);
1835
- const jobs = service2.listJobs(Boolean(opts.all));
1834
+ const service = new CronService(storePath);
1835
+ const jobs = service.listJobs(Boolean(opts.all));
1836
1836
  if (!jobs.length) {
1837
1837
  console.log("No scheduled jobs.");
1838
1838
  return;
@@ -1851,7 +1851,7 @@ var CronCommands = class {
1851
1851
  }
1852
1852
  cronAdd(opts) {
1853
1853
  const storePath = join3(getDataDir3(), "cron", "jobs.json");
1854
- const service2 = new CronService(storePath);
1854
+ const service = new CronService(storePath);
1855
1855
  let schedule = null;
1856
1856
  if (opts.every) {
1857
1857
  schedule = { kind: "every", everyMs: Number(opts.every) * 1e3 };
@@ -1864,7 +1864,7 @@ var CronCommands = class {
1864
1864
  console.error("Error: Must specify --every, --cron, or --at");
1865
1865
  return;
1866
1866
  }
1867
- const job = service2.addJob({
1867
+ const job = service.addJob({
1868
1868
  name: opts.name,
1869
1869
  schedule,
1870
1870
  message: opts.message,
@@ -1876,8 +1876,8 @@ var CronCommands = class {
1876
1876
  }
1877
1877
  cronRemove(jobId) {
1878
1878
  const storePath = join3(getDataDir3(), "cron", "jobs.json");
1879
- const service2 = new CronService(storePath);
1880
- if (service2.removeJob(jobId)) {
1879
+ const service = new CronService(storePath);
1880
+ if (service.removeJob(jobId)) {
1881
1881
  console.log(`\u2713 Removed job ${jobId}`);
1882
1882
  } else {
1883
1883
  console.log(`Job ${jobId} not found`);
@@ -1885,8 +1885,8 @@ var CronCommands = class {
1885
1885
  }
1886
1886
  cronEnable(jobId, opts) {
1887
1887
  const storePath = join3(getDataDir3(), "cron", "jobs.json");
1888
- const service2 = new CronService(storePath);
1889
- const job = service2.enableJob(jobId, !opts.disable);
1888
+ const service = new CronService(storePath);
1889
+ const job = service.enableJob(jobId, !opts.disable);
1890
1890
  if (job) {
1891
1891
  console.log(`\u2713 Job '${job.name}' ${opts.disable ? "disabled" : "enabled"}`);
1892
1892
  } else {
@@ -1895,8 +1895,8 @@ var CronCommands = class {
1895
1895
  }
1896
1896
  async cronRun(jobId, opts) {
1897
1897
  const storePath = join3(getDataDir3(), "cron", "jobs.json");
1898
- const service2 = new CronService(storePath);
1899
- const ok = await service2.runJob(jobId, Boolean(opts.force));
1898
+ const service = new CronService(storePath);
1899
+ const ok = await service.runJob(jobId, Boolean(opts.force));
1900
1900
  console.log(ok ? "\u2713 Job executed" : `Failed to run job ${jobId}`);
1901
1901
  }
1902
1902
  };
@@ -2252,12 +2252,12 @@ import {
2252
2252
  stopPluginChannelGateways
2253
2253
  } from "@nextclaw/openclaw-compat";
2254
2254
  import { startUiServer } from "@nextclaw/server";
2255
- import { appendFileSync, closeSync, cpSync, existsSync as existsSync8, mkdirSync as mkdirSync4, openSync, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
2255
+ import { appendFileSync, closeSync, cpSync, existsSync as existsSync8, mkdirSync as mkdirSync4, mkdtempSync, openSync, rmSync as rmSync3 } from "fs";
2256
2256
  import { dirname, isAbsolute as isAbsolute2, join as join5, relative, resolve as resolve7 } from "path";
2257
- import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
2257
+ import { tmpdir } from "os";
2258
+ import { spawn as spawn2 } from "child_process";
2258
2259
  import { request as httpRequest } from "http";
2259
2260
  import { request as httpsRequest } from "https";
2260
- import { homedir, userInfo } from "os";
2261
2261
  import { fileURLToPath as fileURLToPath2 } from "url";
2262
2262
  import chokidar from "chokidar";
2263
2263
 
@@ -4035,85 +4035,6 @@ var ServiceCommands = class {
4035
4035
  clearServiceState();
4036
4036
  console.log(`\u2713 ${APP_NAME2} stopped`);
4037
4037
  }
4038
- async installSystemdService(options) {
4039
- if (process.platform !== "linux") {
4040
- console.error("Error: systemd installation is only supported on Linux.");
4041
- return;
4042
- }
4043
- if (typeof process.getuid === "function" && process.getuid() !== 0) {
4044
- console.error("Error: Run this command as root (for example: sudo nextclaw service install-systemd).");
4045
- return;
4046
- }
4047
- const serviceName = this.resolveSystemdServiceName(options.name);
4048
- const config2 = loadConfig6();
4049
- const uiConfig = resolveUiConfig(config2, { enabled: true, host: "0.0.0.0" });
4050
- const uiPort = this.parseSystemdUiPort(options.uiPort, uiConfig.port);
4051
- if (uiPort === null) {
4052
- console.error("Error: Invalid --ui-port. Provide a positive integer.");
4053
- return;
4054
- }
4055
- const systemctlAvailable = this.runSystemCommand("systemctl", ["--version"]);
4056
- if (!systemctlAvailable.ok) {
4057
- console.error("Error: systemctl is not available on this machine.");
4058
- return;
4059
- }
4060
- const runUser = this.resolveSystemdRunUser();
4061
- const runHome = this.resolveSystemdRunHome(runUser);
4062
- const servicePath = `/etc/systemd/system/${serviceName}.service`;
4063
- const cliPath = fileURLToPath2(new URL("../index.js", import.meta.url));
4064
- const execArgs = [process.execPath, ...process.execArgv, cliPath, "serve", "--ui-port", String(uiPort)];
4065
- const unit = this.buildSystemdUnit({
4066
- runUser,
4067
- runHome,
4068
- execArgs
4069
- });
4070
- writeFileSync4(servicePath, unit, "utf-8");
4071
- const daemonReload = this.runSystemCommand("systemctl", ["daemon-reload"]);
4072
- if (!daemonReload.ok) {
4073
- console.error(`Error: Failed to reload systemd. ${daemonReload.stderr}`.trim());
4074
- return;
4075
- }
4076
- const enableStart = this.runSystemCommand("systemctl", ["enable", "--now", `${serviceName}.service`]);
4077
- if (!enableStart.ok) {
4078
- console.error(`Error: Failed to enable/start ${serviceName}.service. ${enableStart.stderr}`.trim());
4079
- return;
4080
- }
4081
- const active = this.runSystemCommand("systemctl", ["is-active", `${serviceName}.service`]);
4082
- if (!active.ok || active.stdout.trim() !== "active") {
4083
- console.error(`Error: ${serviceName}.service is not active. ${active.stderr || active.stdout}`.trim());
4084
- return;
4085
- }
4086
- console.log(`\u2713 Installed systemd service: ${serviceName}.service`);
4087
- console.log(`Run user: ${runUser}`);
4088
- console.log(`UI port: ${uiPort}`);
4089
- console.log(`Unit file: ${servicePath}`);
4090
- console.log(`Health: http://127.0.0.1:${uiPort}/api/health`);
4091
- console.log(`Logs: journalctl -u ${serviceName}.service -f`);
4092
- }
4093
- async uninstallSystemdService(options) {
4094
- if (process.platform !== "linux") {
4095
- console.error("Error: systemd removal is only supported on Linux.");
4096
- return;
4097
- }
4098
- if (typeof process.getuid === "function" && process.getuid() !== 0) {
4099
- console.error("Error: Run this command as root.");
4100
- return;
4101
- }
4102
- const serviceName = this.resolveSystemdServiceName(options.name);
4103
- const servicePath = `/etc/systemd/system/${serviceName}.service`;
4104
- if (!existsSync8(servicePath)) {
4105
- console.error(`Error: ${servicePath} does not exist.`);
4106
- return;
4107
- }
4108
- this.runSystemCommand("systemctl", ["disable", "--now", `${serviceName}.service`]);
4109
- rmSync3(servicePath, { force: true });
4110
- const daemonReload = this.runSystemCommand("systemctl", ["daemon-reload"]);
4111
- if (!daemonReload.ok) {
4112
- console.error(`Warning: Removed unit file but failed to reload systemd. ${daemonReload.stderr}`.trim());
4113
- return;
4114
- }
4115
- console.log(`\u2713 Removed systemd service: ${serviceName}.service`);
4116
- }
4117
4038
  async waitForBackgroundServiceReady(params) {
4118
4039
  const startedAt = Date.now();
4119
4040
  let lastProbeError = null;
@@ -4144,78 +4065,6 @@ var ServiceCommands = class {
4144
4065
  const resolved = fromOverride ?? fromEnv ?? fallback;
4145
4066
  return Math.max(3e3, resolved);
4146
4067
  }
4147
- resolveSystemdServiceName(rawName) {
4148
- const trimmed = rawName?.trim() || APP_NAME2;
4149
- return trimmed.endsWith(".service") ? trimmed.slice(0, -".service".length) : trimmed;
4150
- }
4151
- parseSystemdUiPort(rawPort, fallbackPort) {
4152
- if (rawPort === void 0 || rawPort === null || rawPort === "") {
4153
- return fallbackPort;
4154
- }
4155
- const parsed = Number(rawPort);
4156
- if (!Number.isInteger(parsed) || parsed <= 0) {
4157
- return null;
4158
- }
4159
- return parsed;
4160
- }
4161
- resolveSystemdRunUser() {
4162
- const sudoUser = process.env.SUDO_USER?.trim();
4163
- if (sudoUser && sudoUser !== "root") {
4164
- return sudoUser;
4165
- }
4166
- return userInfo().username;
4167
- }
4168
- resolveSystemdRunHome(runUser) {
4169
- const passwd = this.runSystemCommand("getent", ["passwd", runUser]);
4170
- if (passwd.ok) {
4171
- const fields = passwd.stdout.trim().split(":");
4172
- if (fields.length >= 6 && fields[5]) {
4173
- return fields[5];
4174
- }
4175
- }
4176
- return process.env.HOME?.trim() || homedir();
4177
- }
4178
- buildSystemdUnit(params) {
4179
- const execStart = params.execArgs.map((arg) => this.escapeSystemdArg(arg)).join(" ");
4180
- return [
4181
- "[Unit]",
4182
- `Description=${APP_NAME2} gateway + UI`,
4183
- "After=network-online.target",
4184
- "Wants=network-online.target",
4185
- "",
4186
- "[Service]",
4187
- "Type=simple",
4188
- `User=${params.runUser}`,
4189
- `WorkingDirectory=${params.runHome}`,
4190
- `Environment=HOME=${params.runHome}`,
4191
- "Environment=NODE_ENV=production",
4192
- `ExecStart=${execStart}`,
4193
- "Restart=always",
4194
- "RestartSec=3",
4195
- "TimeoutStopSec=20",
4196
- "",
4197
- "[Install]",
4198
- "WantedBy=multi-user.target",
4199
- ""
4200
- ].join("\n");
4201
- }
4202
- escapeSystemdArg(value) {
4203
- if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(value)) {
4204
- return value;
4205
- }
4206
- return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
4207
- }
4208
- runSystemCommand(command, args) {
4209
- const result = spawnSync4(command, args, {
4210
- encoding: "utf-8",
4211
- stdio: ["ignore", "pipe", "pipe"]
4212
- });
4213
- return {
4214
- ok: result.status === 0,
4215
- stdout: result.stdout ?? "",
4216
- stderr: result.stderr ?? ""
4217
- };
4218
- }
4219
4068
  appendStartupStage(logPath, message) {
4220
4069
  try {
4221
4070
  appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [startup] ${message}
@@ -4519,54 +4368,107 @@ var ServiceCommands = class {
4519
4368
  if (existsSync8(destination) && params.force) {
4520
4369
  rmSync3(destination, { recursive: true, force: true });
4521
4370
  }
4522
- const skildArgs = ["--yes", "skild", "install", source, "--target", "agents", "--local", "--json", "--skill", skillName];
4523
- if (params.registry) {
4524
- skildArgs.push("--registry", params.registry);
4371
+ const materialized = await this.materializeMarketplaceGitSkillSource({ source, skillName });
4372
+ try {
4373
+ const installSkillFile = join5(materialized.skillDir, "SKILL.md");
4374
+ if (!existsSync8(installSkillFile)) {
4375
+ throw new Error(`git skill source does not contain SKILL.md for ${skillName}`);
4376
+ }
4377
+ mkdirSync4(dirname(destination), { recursive: true });
4378
+ cpSync(materialized.skillDir, destination, { recursive: true, force: true });
4379
+ return {
4380
+ message: `Installed skill: ${skillName}`,
4381
+ output: [
4382
+ `Source: ${source}`,
4383
+ `Materialized skill: ${materialized.skillDir}`,
4384
+ `Workspace target: ${destination}`,
4385
+ materialized.commandOutput
4386
+ ].filter(Boolean).join("\n")
4387
+ };
4388
+ } finally {
4389
+ rmSync3(materialized.tempRoot, { recursive: true, force: true });
4525
4390
  }
4526
- if (params.force) {
4527
- skildArgs.push("--force");
4391
+ }
4392
+ async materializeMarketplaceGitSkillSource(params) {
4393
+ const parsed = this.parseMarketplaceGitSkillSource(params.source);
4394
+ const gitPath = findExecutableOnPath("git");
4395
+ if (!gitPath) {
4396
+ throw new Error("git is required to install marketplace git skills");
4528
4397
  }
4529
- let result = await this.runCommandWithFallback(
4530
- ["npx", "/opt/homebrew/bin/npx", "/usr/local/bin/npx"],
4531
- skildArgs,
4532
- {
4533
- cwd: workspace,
4534
- timeoutMs: 18e4
4398
+ const tempRoot = mkdtempSync(join5(tmpdir(), "nextclaw-marketplace-skill-"));
4399
+ const repoDir = join5(tempRoot, "repo");
4400
+ try {
4401
+ const cloneArgs = ["clone", "--depth", "1", "--filter=blob:none", "--sparse"];
4402
+ if (parsed.ref) {
4403
+ cloneArgs.push("--branch", parsed.ref);
4535
4404
  }
4536
- );
4537
- let payload = this.parseSkildJsonOutput(result.stdout);
4538
- if (!payload) {
4539
- const forceArgs = skildArgs.includes("--force") ? skildArgs : [...skildArgs, "--force"];
4540
- result = await this.runCommandWithFallback(
4541
- ["npx", "/opt/homebrew/bin/npx", "/usr/local/bin/npx"],
4542
- forceArgs,
4543
- {
4544
- cwd: workspace,
4545
- timeoutMs: 18e4
4546
- }
4547
- );
4548
- payload = this.parseSkildJsonOutput(result.stdout);
4405
+ cloneArgs.push(parsed.repoUrl, repoDir);
4406
+ const cloneResult = await this.runCommand(gitPath, cloneArgs, {
4407
+ cwd: tempRoot,
4408
+ timeoutMs: 18e4
4409
+ });
4410
+ const sparseResult = await this.runCommand(gitPath, ["-C", repoDir, "sparse-checkout", "set", parsed.skillPath], {
4411
+ cwd: tempRoot,
4412
+ timeoutMs: 6e4
4413
+ });
4414
+ const skillDir = join5(repoDir, parsed.skillPath);
4415
+ return {
4416
+ tempRoot,
4417
+ skillDir,
4418
+ commandOutput: [
4419
+ `Git repository: ${parsed.repoUrl}`,
4420
+ `Git path: ${parsed.skillPath}`,
4421
+ this.mergeCommandOutput(cloneResult.stdout, cloneResult.stderr),
4422
+ this.mergeCommandOutput(sparseResult.stdout, sparseResult.stderr)
4423
+ ].filter(Boolean).join("\n")
4424
+ };
4425
+ } catch (error) {
4426
+ rmSync3(tempRoot, { recursive: true, force: true });
4427
+ throw error;
4428
+ }
4429
+ }
4430
+ parseMarketplaceGitSkillSource(source) {
4431
+ const trimmed = source.trim();
4432
+ if (!trimmed) {
4433
+ throw new Error("Git skill source is required");
4549
4434
  }
4550
- if (!payload) {
4551
- throw new Error("skild returned null json payload even after force reinstall");
4435
+ if (trimmed.includes("://")) {
4436
+ const parsedUrl = new URL(trimmed);
4437
+ if (parsedUrl.hostname !== "github.com") {
4438
+ throw new Error(`Unsupported git skill source host: ${parsedUrl.hostname}`);
4439
+ }
4440
+ const parts2 = parsedUrl.pathname.split("/").filter(Boolean);
4441
+ if (parts2.length < 5 || parts2[2] !== "tree" && parts2[2] !== "blob") {
4442
+ throw new Error(`Unsupported GitHub skill source URL: ${source}`);
4443
+ }
4444
+ const [owner2, repoRaw, , ref2, ...pathParts2] = parts2;
4445
+ const repo2 = repoRaw.replace(/\.git$/i, "");
4446
+ if (!owner2 || !repo2 || !ref2 || pathParts2.length === 0) {
4447
+ throw new Error(`Unsupported GitHub skill source URL: ${source}`);
4448
+ }
4449
+ return {
4450
+ repoUrl: `https://github.com/${owner2}/${repo2}.git`,
4451
+ skillPath: pathParts2.join("/"),
4452
+ ref: ref2
4453
+ };
4552
4454
  }
4553
- const installDir = typeof payload.installDir === "string" ? payload.installDir.trim() : "";
4554
- const installSkillFile = installDir ? join5(installDir, "SKILL.md") : "";
4555
- if (!installDir || !existsSync8(installSkillFile)) {
4556
- throw new Error(`skild install did not produce a valid skill directory for ${skillName}`);
4455
+ const parts = trimmed.split("/").filter(Boolean);
4456
+ if (parts.length < 3) {
4457
+ throw new Error(`Unsupported git skill source: ${source}`);
4557
4458
  }
4558
- mkdirSync4(dirname(destination), { recursive: true });
4559
- if (resolve7(installDir) !== resolve7(destination)) {
4560
- cpSync(installDir, destination, { recursive: true, force: true });
4459
+ const owner = parts[0] ?? "";
4460
+ const repoWithOptionalRef = parts[1] ?? "";
4461
+ const pathParts = parts.slice(2);
4462
+ const atIndex = repoWithOptionalRef.indexOf("@");
4463
+ const repo = (atIndex >= 0 ? repoWithOptionalRef.slice(0, atIndex) : repoWithOptionalRef).replace(/\.git$/i, "");
4464
+ const ref = atIndex >= 0 ? repoWithOptionalRef.slice(atIndex + 1) : void 0;
4465
+ if (!owner || !repo || pathParts.length === 0) {
4466
+ throw new Error(`Unsupported git skill source: ${source}`);
4561
4467
  }
4562
4468
  return {
4563
- message: `Installed skill: ${skillName}`,
4564
- output: [
4565
- `Source: ${source}`,
4566
- `Installed via skild: ${installDir}`,
4567
- `Workspace target: ${destination}`,
4568
- this.mergeCommandOutput(result.stdout, result.stderr)
4569
- ].filter(Boolean).join("\n")
4469
+ repoUrl: `https://github.com/${owner}/${repo}.git`,
4470
+ skillPath: pathParts.join("/"),
4471
+ ref: ref && ref.trim().length > 0 ? ref.trim() : void 0
4570
4472
  };
4571
4473
  }
4572
4474
  async enableMarketplacePlugin(id) {
@@ -4587,17 +4489,13 @@ var ServiceCommands = class {
4587
4489
  async uninstallMarketplaceSkill(slug) {
4588
4490
  const workspace = getWorkspacePath5(loadConfig6().agents.defaults.workspace);
4589
4491
  const targetDir = join5(workspace, "skills", slug);
4590
- const skildDir = join5(workspace, ".agents", "skills", slug);
4591
- const existingTargets = [targetDir, skildDir].filter((path) => existsSync8(path));
4592
- if (existingTargets.length === 0) {
4492
+ if (!existsSync8(targetDir)) {
4593
4493
  throw new Error(`Skill not installed in workspace: ${slug}`);
4594
4494
  }
4595
- for (const path of existingTargets) {
4596
- rmSync3(path, { recursive: true, force: true });
4597
- }
4495
+ rmSync3(targetDir, { recursive: true, force: true });
4598
4496
  return {
4599
4497
  message: `Uninstalled skill: ${slug}`,
4600
- output: existingTargets.map((path) => `Removed ${path}`).join("\n")
4498
+ output: `Removed ${targetDir}`
4601
4499
  };
4602
4500
  }
4603
4501
  installBuiltinMarketplaceSkill(slug, force) {
@@ -4659,39 +4557,6 @@ var ServiceCommands = class {
4659
4557
  }
4660
4558
  return destination;
4661
4559
  }
4662
- parseSkildJsonOutput(stdout) {
4663
- const trimmed = stdout.trim();
4664
- if (!trimmed) {
4665
- throw new Error("skild returned empty output");
4666
- }
4667
- const maybeJson = (() => {
4668
- const start = trimmed.indexOf("{");
4669
- const end = trimmed.lastIndexOf("}");
4670
- if (start >= 0 && end > start) {
4671
- return trimmed.slice(start, end + 1);
4672
- }
4673
- return trimmed;
4674
- })();
4675
- try {
4676
- const parsed = JSON.parse(maybeJson);
4677
- if (parsed === null) {
4678
- return null;
4679
- }
4680
- if (Array.isArray(parsed)) {
4681
- const firstObject = parsed.find((item) => item && typeof item === "object" && !Array.isArray(item));
4682
- if (firstObject) {
4683
- return firstObject;
4684
- }
4685
- throw new Error("skild json output array does not contain an object");
4686
- }
4687
- if (typeof parsed !== "object") {
4688
- throw new Error("skild json output is not an object");
4689
- }
4690
- return parsed;
4691
- } catch (error) {
4692
- throw new Error(`failed to parse skild --json output: ${String(error)}`);
4693
- }
4694
- }
4695
4560
  mergeCommandOutput(stdout, stderr) {
4696
4561
  return `${stdout}
4697
4562
  ${stderr}`.trim();
@@ -4763,12 +4628,12 @@ ${stderr}`.trim();
4763
4628
  };
4764
4629
 
4765
4630
  // src/cli/workspace.ts
4766
- import { cpSync as cpSync2, existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync7, readdirSync as readdirSync2, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
4631
+ import { cpSync as cpSync2, existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync7, readdirSync as readdirSync2, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "fs";
4767
4632
  import { createRequire } from "module";
4768
4633
  import { dirname as dirname2, join as join6, resolve as resolve8 } from "path";
4769
4634
  import { fileURLToPath as fileURLToPath3 } from "url";
4770
4635
  import { APP_NAME as APP_NAME3, getDataDir as getDataDir7 } from "@nextclaw/core";
4771
- import { spawnSync as spawnSync5 } from "child_process";
4636
+ import { spawnSync as spawnSync4 } from "child_process";
4772
4637
  var WorkspaceManager = class {
4773
4638
  constructor(logo) {
4774
4639
  this.logo = logo;
@@ -4807,7 +4672,7 @@ var WorkspaceManager = class {
4807
4672
  const raw = readFileSync7(templatePath, "utf-8");
4808
4673
  const content = raw.replace(/\$\{APP_NAME\}/g, APP_NAME3);
4809
4674
  mkdirSync5(dirname2(filePath), { recursive: true });
4810
- writeFileSync5(filePath, content);
4675
+ writeFileSync4(filePath, content);
4811
4676
  created.push(entry.target);
4812
4677
  }
4813
4678
  const memoryDir = join6(workspace, "memory");
@@ -4915,7 +4780,7 @@ var WorkspaceManager = class {
4915
4780
  recursive: true,
4916
4781
  filter: (src) => !src.includes("node_modules") && !src.includes("dist")
4917
4782
  });
4918
- const install = spawnSync5("npm", ["install"], { cwd: userBridge, stdio: "pipe" });
4783
+ const install = spawnSync4("npm", ["install"], { cwd: userBridge, stdio: "pipe" });
4919
4784
  if (install.status !== 0) {
4920
4785
  console.error(`Bridge install failed: ${install.status ?? 1}`);
4921
4786
  if (install.stderr) {
@@ -4923,7 +4788,7 @@ var WorkspaceManager = class {
4923
4788
  }
4924
4789
  process.exit(1);
4925
4790
  }
4926
- const build = spawnSync5("npm", ["run", "build"], { cwd: userBridge, stdio: "pipe" });
4791
+ const build = spawnSync4("npm", ["run", "build"], { cwd: userBridge, stdio: "pipe" });
4927
4792
  if (build.status !== 0) {
4928
4793
  console.error(`Bridge build failed: ${build.status ?? 1}`);
4929
4794
  if (build.stderr) {
@@ -5293,12 +5158,6 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
5293
5158
  async stop() {
5294
5159
  await this.serviceCommands.stopService();
5295
5160
  }
5296
- async serviceInstallSystemd(opts) {
5297
- await this.serviceCommands.installSystemdService(opts);
5298
- }
5299
- async serviceUninstallSystemd(opts) {
5300
- await this.serviceCommands.uninstallSystemdService(opts);
5301
- }
5302
5161
  async agent(opts) {
5303
5162
  const configPath = getConfigPath4();
5304
5163
  const config2 = resolveConfigSecrets3(loadConfig7(), { configPath });
@@ -5381,7 +5240,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
5381
5240
  const merged = history.concat(
5382
5241
  rl.history ?? []
5383
5242
  );
5384
- writeFileSync6(historyFile, merged.join("\n"));
5243
+ writeFileSync5(historyFile, merged.join("\n"));
5385
5244
  process.exit(0);
5386
5245
  });
5387
5246
  let running = true;
@@ -5561,9 +5420,6 @@ program.command("start").description(`Start the ${APP_NAME5} gateway + UI in the
5561
5420
  program.command("restart").description(`Restart the ${APP_NAME5} background service`).option("--ui-port <port>", "UI port").option("--start-timeout <ms>", "Maximum wait time for startup readiness in milliseconds").option("--open", "Open browser after restart", false).action(async (opts) => runtime.restart(opts));
5562
5421
  program.command("serve").description(`Run the ${APP_NAME5} gateway + UI in the foreground`).option("--ui-port <port>", "UI port").option("--open", "Open browser after start", false).action(async (opts) => runtime.serve(opts));
5563
5422
  program.command("stop").description(`Stop the ${APP_NAME5} background service`).action(async () => runtime.stop());
5564
- var service = program.command("service").description("Manage OS service integration");
5565
- service.command("install-systemd").description(`Install a systemd unit for ${APP_NAME5} on Linux servers`).option("--name <name>", "Systemd unit name", APP_NAME5).option("--ui-port <port>", "UI port").action(async (opts) => runtime.serviceInstallSystemd(opts));
5566
- service.command("uninstall-systemd").description(`Remove the systemd unit for ${APP_NAME5}`).option("--name <name>", "Systemd unit name", APP_NAME5).action(async (opts) => runtime.serviceUninstallSystemd(opts));
5567
5423
  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("--model <model>", "Session model override for this run").option("--no-markdown", "Disable Markdown rendering").action(async (opts) => runtime.agent(opts));
5568
5424
  program.command("update").description(`Update ${APP_NAME5}`).option("--timeout <ms>", "Update command timeout in milliseconds").action(async (opts) => runtime.update(opts));
5569
5425
  var registerClawHubInstall = (cmd) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextclaw",
3
- "version": "0.9.10",
3
+ "version": "0.9.11",
4
4
  "description": "Lightweight personal AI assistant with CLI, multi-provider routing, and channel integrations.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -418,8 +418,6 @@ Created under the workspace:
418
418
  | `nextclaw start` | Start gateway + UI in the background |
419
419
  | `nextclaw restart` | Restart the background service with optional start flags |
420
420
  | `nextclaw stop` | Stop the background service |
421
- | `sudo nextclaw service install-systemd` | Install a managed Linux `systemd` service for public/server deployment |
422
- | `sudo nextclaw service uninstall-systemd` | Remove the managed Linux `systemd` service |
423
421
  | `nextclaw ui` | Start UI and gateway in the foreground |
424
422
  | `nextclaw gateway` | Start gateway only (for channels) |
425
423
  | `nextclaw serve` | Run gateway + UI in the foreground (no background) |
@@ -460,13 +458,6 @@ Gateway options (when running `nextclaw gateway` or `nextclaw start`):
460
458
 
461
459
  If service is already running, new UI port flags do not hot-apply; use `nextclaw restart ...` to apply them.
462
460
 
463
- Linux server deployment tip:
464
-
465
- - If you put Nginx/Caddy/Traefik in front of NextClaw, do not rely on a one-time `nextclaw start` only.
466
- - `nextclaw start` is a background convenience command, not a crash/reboot supervisor.
467
- - On Linux servers, install a managed unit with `sudo nextclaw service install-systemd` so the UI/API comes back automatically after reboot or unexpected exit.
468
- - Verify with `systemctl status nextclaw`, `journalctl -u nextclaw -f`, and `curl http://127.0.0.1:18791/api/health`.
469
-
470
461
  Status/diagnostics tips:
471
462
 
472
463
  - `nextclaw status` shows runtime truth (process + health + config summary).