nextclaw 0.18.12-beta.2 → 0.18.12-beta.21

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 (96) hide show
  1. package/dist/cli/app/index.js +908 -266
  2. package/dist/cli/launcher/index.js +8 -3
  3. package/dist/{npm-runtime-update-state.store-DaF0iDY9.js → npm-runtime-update-state.store-75vzvn0B.js} +200 -30
  4. package/package.json +17 -16
  5. package/resources/USAGE.md +41 -1
  6. package/ui-dist/assets/api-Dai6UR3J.js +15 -0
  7. package/ui-dist/assets/app-manager-provider-BZr5VxCe.js +1 -0
  8. package/ui-dist/assets/app-navigation.config-BjIj_FLm.js +1 -0
  9. package/ui-dist/assets/{book-open-C5p9re7m.js → book-open-DgLqYpNY.js} +1 -1
  10. package/ui-dist/assets/channels-list-page-L6FFtRYn.js +8 -0
  11. package/ui-dist/assets/{chat-a-_X0PmT.js → chat-ZQIVJChB.js} +7 -7
  12. package/ui-dist/assets/chat-page-CR1yI96r.js +1 -0
  13. package/ui-dist/assets/chunk-JZWAC4HX-u4uYphxM.js +3 -0
  14. package/ui-dist/assets/{config-split-page-YB7xRSn7.js → config-split-page-BMRGuCJQ.js} +1 -1
  15. package/ui-dist/assets/{createLucideIcon-D48LQ7_3.js → createLucideIcon-BZkY6emz.js} +1 -1
  16. package/ui-dist/assets/desktop-update-config-AXzb7OEa.js +1 -0
  17. package/ui-dist/assets/{dialog-BNdeIVqc.js → dialog-DgybjpeU.js} +1 -1
  18. package/ui-dist/assets/{dist-BjUfmI6n.js → dist-CxcPOISF.js} +1 -1
  19. package/ui-dist/assets/{doc-browser-CX_BvO6R.js → doc-browser-BUlCkZo2.js} +1 -1
  20. package/ui-dist/assets/{doc-browser-CLdhFEsz.js → doc-browser-CzCV73NJ.js} +1 -1
  21. package/ui-dist/assets/doc-browser-Doh2541x.js +1 -0
  22. package/ui-dist/assets/{doc-browser-context-5mbkyvid.js → doc-browser-context-DfLHAWbG.js} +1 -1
  23. package/ui-dist/assets/{es2015-Db-PtAnL.js → es2015-BVRlEE06.js} +1 -1
  24. package/ui-dist/assets/{external-link-BwNyDSMe.js → external-link-Sw3ah_JD.js} +1 -1
  25. package/ui-dist/assets/{folder-BSLCUICp.js → folder-D7-VTnkz.js} +1 -1
  26. package/ui-dist/assets/{hash-DpL5u6Fu.js → hash-zajSTDXZ.js} +1 -1
  27. package/ui-dist/assets/i18n-C5Mibli1.js +1 -0
  28. package/ui-dist/assets/index-B7RsQ-ne.js +2 -0
  29. package/ui-dist/assets/index-D8MKmXtO.css +1 -0
  30. package/ui-dist/assets/{key-round-BNTFD7Jk.js → key-round-CnI1mc9F.js} +1 -1
  31. package/ui-dist/assets/loader-circle-B5i8oMMY.js +1 -0
  32. package/ui-dist/assets/{logo-badge-a-OsoTKw.js → logo-badge-BQgKnVtz.js} +1 -1
  33. package/ui-dist/assets/{logos--4c27B_Z.js → logos-CqVm0q0W.js} +1 -1
  34. package/ui-dist/assets/marketplace-page-Bj55-6F2.js +1 -0
  35. package/ui-dist/assets/{marketplace-page-PA3qcNzv.js → marketplace-page-ClRW-W3g.js} +2 -2
  36. package/ui-dist/assets/mcp-marketplace-page-DtngnIi0.js +40 -0
  37. package/ui-dist/assets/mcp-marketplace-page-_Wu2VnHy.js +1 -0
  38. package/ui-dist/assets/message-square-D6Z4NwpG.js +1 -0
  39. package/ui-dist/assets/{model-config-C3-m1Sua.js → model-config-D_y8F0j6.js} +1 -1
  40. package/ui-dist/assets/{notice-card-DE4jOEXF.js → notice-card-uzwjFyML.js} +1 -1
  41. package/ui-dist/assets/play-D8WJLnJe.js +1 -0
  42. package/ui-dist/assets/plus-Di0KAkiO.js +1 -0
  43. package/ui-dist/assets/{popover-B6dtrFF5.js → popover-C8tMB7tR.js} +1 -1
  44. package/ui-dist/assets/{provider-scoped-model-input-BkpcdlQB.js → provider-scoped-model-input-ORZutTDv.js} +1 -1
  45. package/ui-dist/assets/{providers-list-EzKC5s0y.js → providers-list-DSc3d8me.js} +1 -1
  46. package/ui-dist/assets/refresh-ccw-Bii4w8aB.js +1 -0
  47. package/ui-dist/assets/refresh-cw-BxojR62w.js +1 -0
  48. package/ui-dist/assets/remote-rWiu3cys.js +1 -0
  49. package/ui-dist/assets/{rotate-cw-CeTNbfMs.js → rotate-cw-1Xqa7LZ8.js} +1 -1
  50. package/ui-dist/assets/runtime-config-page-B4uSax1I.js +1 -0
  51. package/ui-dist/assets/{save-B8Rym7bl.js → save--BVI5wZX.js} +1 -1
  52. package/ui-dist/assets/{search-config-CNh9FS_N.js → search-config-CaqqlsdW.js} +1 -1
  53. package/ui-dist/assets/{search-BUGoDsjN.js → search-vChioOoe.js} +1 -1
  54. package/ui-dist/assets/{secrets-config-Bau56GeM.js → secrets-config-llf5ROde.js} +2 -2
  55. package/ui-dist/assets/{select-BuXrS7g3.js → select-uO-zhYsH.js} +1 -1
  56. package/ui-dist/assets/{sessions-config-page-BDF04GaS.js → sessions-config-page-BqOXte9x.js} +2 -2
  57. package/ui-dist/assets/{setting-row-CifMdz8g.js → setting-row-BIiXR4hx.js} +1 -1
  58. package/ui-dist/assets/settings-CiRChctQ.js +1 -0
  59. package/ui-dist/assets/skeleton-CFQRIUzt.js +1 -0
  60. package/ui-dist/assets/{sparkles-Bo0DxmaB.js → sparkles-D1ZKWdm4.js} +1 -1
  61. package/ui-dist/assets/{status-dot-CS7yRd9c.js → status-dot-Dv_hiUVa.js} +1 -1
  62. package/ui-dist/assets/{tabs-custom-HBN-j_Kn.js → tabs-custom-CsACkVji.js} +1 -1
  63. package/ui-dist/assets/{tag-chip-BZSHb3cE.js → tag-chip-DVbgpsYW.js} +1 -1
  64. package/ui-dist/assets/theme-provider-BU77FNSB.js +1 -0
  65. package/ui-dist/assets/{tooltip-BMz2ki-V.js → tooltip-CvAtG-kT.js} +1 -1
  66. package/ui-dist/assets/{trash-2-gWTb2oNS.js → trash-2-rY9ZteZX.js} +1 -1
  67. package/ui-dist/assets/use-config-D2QgG7qc.js +1 -0
  68. package/ui-dist/assets/{use-confirm-dialog-DLVARUvb.js → use-confirm-dialog-BBClFV8E.js} +1 -1
  69. package/ui-dist/assets/{use-infinite-scroll-loader-BdGMvR3y.js → use-infinite-scroll-loader-CWzpUecQ.js} +1 -1
  70. package/ui-dist/assets/{use-viewport-layout-DOqJ0LPT.js → use-viewport-layout-C6EN0_eq.js} +1 -1
  71. package/ui-dist/assets/x-DpTzXQcX.js +1 -0
  72. package/ui-dist/index.html +40 -36
  73. package/ui-dist/assets/api-BsY-53_V.js +0 -15
  74. package/ui-dist/assets/app-manager-provider-DTrWjVLB.js +0 -1
  75. package/ui-dist/assets/channels-list-page-CZAdoJ3s.js +0 -8
  76. package/ui-dist/assets/chat-page-BCypc4bi.js +0 -1
  77. package/ui-dist/assets/chunk-JZWAC4HX-CD1w8mri.js +0 -3
  78. package/ui-dist/assets/desktop-B9azAgEh.js +0 -2
  79. package/ui-dist/assets/desktop-update-config-Dm_cedSL.js +0 -1
  80. package/ui-dist/assets/doc-browser-eF2QWInq.js +0 -1
  81. package/ui-dist/assets/i18n-jGA3YQz4.js +0 -1
  82. package/ui-dist/assets/index-CUmk8xFK.css +0 -1
  83. package/ui-dist/assets/index-o_M3x0GR.js +0 -2
  84. package/ui-dist/assets/loader-circle-C3XJNZy7.js +0 -1
  85. package/ui-dist/assets/marketplace-page-DvmfPCAY.js +0 -1
  86. package/ui-dist/assets/mcp-marketplace-page-Dl8wdAtD.js +0 -1
  87. package/ui-dist/assets/mcp-marketplace-page-DukryaOq.js +0 -40
  88. package/ui-dist/assets/play-DGBx1fWI.js +0 -1
  89. package/ui-dist/assets/plus-CUuByV8j.js +0 -1
  90. package/ui-dist/assets/remote-Xzy42m-0.js +0 -1
  91. package/ui-dist/assets/runtime-config-page-DAMnv5Xp.js +0 -1
  92. package/ui-dist/assets/settings-COxdZHdu.js +0 -1
  93. package/ui-dist/assets/skeleton-DW5F83p8.js +0 -1
  94. package/ui-dist/assets/use-config-Ds7DyaYQ.js +0 -1
  95. package/ui-dist/assets/x-CxanI1fH.js +0 -1
  96. /package/ui-dist/assets/{config-hints-fDrYfl0l.js → config-hints-MogHYQ8G.js} +0 -0
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { i as NpmRuntimeBundleLayoutStore, n as NpmRuntimeBundleService, o as getPackageVersion$1, t as NpmRuntimeUpdateStateStore } from "../../npm-runtime-update-state.store-DaF0iDY9.js";
2
+ import { c as NpmRuntimeBundleLayoutStore, d as getPackageVersion$1, i as NpmRuntimeBundleService, r as inferDefaultNpmRuntimeReleaseChannel, s as shouldPreferPackagedNpmRuntime, t as NpmRuntimeUpdateStateStore } from "../../npm-runtime-update-state.store-75vzvn0B.js";
3
3
  import { createExternalCommandEnv } from "@nextclaw/core";
4
4
  import { dirname, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
@@ -26,14 +26,19 @@ var NpmRuntimeLauncher = class {
26
26
  };
27
27
  resolveRuntimeScriptPath = () => {
28
28
  if (this.env.NEXTCLAW_DISABLE_RUNTIME_BUNDLE_LAUNCHER === "1" || this.env.NEXTCLAW_RUNTIME_BUNDLE_CHILD === "1") return this.resolvePackagedAppEntrypoint();
29
- const stateStore = new NpmRuntimeUpdateStateStore(this.layout.getStatePath());
29
+ const stateStore = new NpmRuntimeUpdateStateStore(this.layout.getStatePath(), { defaultChannel: inferDefaultNpmRuntimeReleaseChannel(getPackageVersion$1()) });
30
30
  const bundleService = new NpmRuntimeBundleService({
31
31
  layout: this.layout,
32
32
  stateStore,
33
33
  launcherVersion: getPackageVersion$1()
34
34
  });
35
35
  try {
36
- return bundleService.resolveCurrentBundle()?.runtimeScriptPath ?? this.resolvePackagedAppEntrypoint();
36
+ const currentBundle = bundleService.resolveCurrentBundle();
37
+ if (currentBundle && shouldPreferPackagedNpmRuntime({
38
+ launcherVersion: getPackageVersion$1(),
39
+ currentBundleVersion: currentBundle.manifest.runtimeVersion ?? currentBundle.manifest.bundleVersion
40
+ })) return this.resolvePackagedAppEntrypoint();
41
+ return currentBundle?.runtimeScriptPath ?? this.resolvePackagedAppEntrypoint();
37
42
  } catch (error) {
38
43
  console.error(`Cannot start current runtime bundle: ${error instanceof Error ? error.message : String(error)}`);
39
44
  console.error("Falling back to the packaged npm launcher runtime.");
@@ -2,7 +2,7 @@ import { createExternalCommandEnv, getDataDir, getLogsPath, getPackageVersion, r
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import { dirname, join, resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { spawn } from "node:child_process";
5
+ import { spawn, spawnSync } from "node:child_process";
6
6
  import { isIP } from "node:net";
7
7
  import { cp, readdir, rename, rm } from "node:fs/promises";
8
8
  //#region src/cli/shared/utils/cli.utils.ts
@@ -71,6 +71,98 @@ async function waitForExit(pid, timeoutMs) {
71
71
  }
72
72
  return !isProcessRunning(pid);
73
73
  }
74
+ function runLookupCommand(command, args) {
75
+ try {
76
+ const result = spawnSync(command, args, {
77
+ encoding: "utf8",
78
+ env: createExternalCommandEnv(process.env)
79
+ });
80
+ if (result.error || result.status !== 0) return {
81
+ ok: false,
82
+ stdout: ""
83
+ };
84
+ return {
85
+ ok: true,
86
+ stdout: result.stdout ?? ""
87
+ };
88
+ } catch {
89
+ return {
90
+ ok: false,
91
+ stdout: ""
92
+ };
93
+ }
94
+ }
95
+ function parseListeningPidFromLsof(raw) {
96
+ for (const line of raw.split("\n")) {
97
+ if (!line.startsWith("p")) continue;
98
+ const pid = Number(line.slice(1));
99
+ if (Number.isFinite(pid) && pid > 0) return pid;
100
+ }
101
+ return null;
102
+ }
103
+ function parseListeningPidFromNetstat(raw, port) {
104
+ const portSuffix = `:${port}`;
105
+ for (const line of raw.split("\n")) {
106
+ const trimmed = line.trim();
107
+ if (!trimmed || !trimmed.includes("LISTEN")) continue;
108
+ const columns = trimmed.split(/\s+/);
109
+ if (columns.length < 5) continue;
110
+ if (!(columns[1] ?? "").endsWith(portSuffix)) continue;
111
+ const pid = Number(columns[4]);
112
+ if (Number.isFinite(pid) && pid > 0) return pid;
113
+ }
114
+ return null;
115
+ }
116
+ function lookupProcessCommandByPid(pid) {
117
+ if (!Number.isFinite(pid) || pid <= 0) return null;
118
+ if (process.platform === "win32") {
119
+ const result = runLookupCommand("powershell", [
120
+ "-NoProfile",
121
+ "-Command",
122
+ `(Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}").CommandLine`
123
+ ]);
124
+ if (!result.ok) return null;
125
+ const command = result.stdout.trim();
126
+ return command.length > 0 ? command : null;
127
+ }
128
+ const result = runLookupCommand("ps", [
129
+ "-p",
130
+ String(pid),
131
+ "-o",
132
+ "command="
133
+ ]);
134
+ if (!result.ok) return null;
135
+ const command = result.stdout.trim();
136
+ return command.length > 0 ? command : null;
137
+ }
138
+ function findListeningProcessByPort(port) {
139
+ if (!Number.isFinite(port) || port <= 0) return null;
140
+ let pid = null;
141
+ if (process.platform === "win32") {
142
+ const result = runLookupCommand("netstat", [
143
+ "-ano",
144
+ "-p",
145
+ "tcp"
146
+ ]);
147
+ if (!result.ok) return null;
148
+ pid = parseListeningPidFromNetstat(result.stdout, port);
149
+ } else {
150
+ const result = runLookupCommand("lsof", [
151
+ "-nP",
152
+ `-iTCP:${port}`,
153
+ "-sTCP:LISTEN",
154
+ "-F",
155
+ "p"
156
+ ]);
157
+ if (!result.ok) return null;
158
+ pid = parseListeningPidFromLsof(result.stdout);
159
+ }
160
+ if (!pid) return null;
161
+ return {
162
+ pid,
163
+ command: lookupProcessCommandByPid(pid)
164
+ };
165
+ }
74
166
  function findNearestPackageManifest(startDir, expectedName) {
75
167
  let current = resolve(startDir);
76
168
  while (current.length > 0) {
@@ -379,53 +471,126 @@ function compareNpmRuntimeVersions(left, right) {
379
471
  }
380
472
  return left.localeCompare(right);
381
473
  }
474
+ function resolveEffectiveNpmRuntimeVersion(params) {
475
+ const launcherVersion = params.launcherVersion?.trim() || null;
476
+ const currentBundleVersion = params.currentBundleVersion?.trim() || null;
477
+ if (!launcherVersion) return currentBundleVersion;
478
+ if (!currentBundleVersion) return launcherVersion;
479
+ return compareNpmRuntimeVersions(launcherVersion, currentBundleVersion) > 0 ? launcherVersion : currentBundleVersion;
480
+ }
481
+ function shouldPreferPackagedNpmRuntime(params) {
482
+ const launcherVersion = params.launcherVersion?.trim() || null;
483
+ const currentBundleVersion = params.currentBundleVersion?.trim() || null;
484
+ if (!launcherVersion || !currentBundleVersion) return false;
485
+ return resolveEffectiveNpmRuntimeVersion(params) === launcherVersion;
486
+ }
382
487
  function parseVersionParts(version) {
383
488
  return version.split(/[.-]/).map((part) => Number(part)).map((part) => Number.isFinite(part) ? part : 0);
384
489
  }
385
490
  //#endregion
386
- //#region src/cli/launcher/npm-runtime-update-state.store.ts
387
- const DEFAULT_NPM_RUNTIME_UPDATE_STATE = {
388
- channel: "stable",
389
- currentVersion: null,
390
- previousVersion: null,
391
- candidateVersion: null,
392
- candidateLaunchCount: 0,
393
- lastKnownGoodVersion: null,
394
- badVersions: [],
395
- lastUpdateCheckAt: null,
396
- downloadedVersion: null,
397
- downloadedReleaseNotesUrl: null,
398
- updatePreferences: {
399
- automaticChecks: true,
400
- autoDownload: false
491
+ //#region src/cli/launcher/npm-runtime-update-source.service.ts
492
+ const DEFAULT_NPM_RUNTIME_UPDATE_BASE_URL = "https://Peiiii.github.io/nextclaw/npm-runtime-updates";
493
+ function normalizeOptionalString$1(value) {
494
+ if (typeof value !== "string") return null;
495
+ const trimmed = value.trim();
496
+ return trimmed ? trimmed : null;
497
+ }
498
+ function normalizeChannel$1(value) {
499
+ return typeof value === "string" && value.trim().toLowerCase() === "beta" ? "beta" : "stable";
500
+ }
501
+ function inferDefaultNpmRuntimeReleaseChannel(launcherVersion) {
502
+ return typeof launcherVersion === "string" && launcherVersion.toLowerCase().includes("-beta") ? "beta" : "stable";
503
+ }
504
+ function resolvePackagedPublicKeyPath() {
505
+ const moduleDir = dirname(fileURLToPath(import.meta.url));
506
+ const candidates = [
507
+ resolve(moduleDir, "..", "resources", "update-bundle-public.pem"),
508
+ resolve(moduleDir, "../../..", "resources", "update-bundle-public.pem"),
509
+ resolve(moduleDir, "../../../..", "resources", "update-bundle-public.pem")
510
+ ];
511
+ return candidates.find((candidate) => existsSync(candidate)) ?? candidates[0];
512
+ }
513
+ var NpmRuntimeUpdateSourceService = class {
514
+ env;
515
+ platform;
516
+ arch;
517
+ constructor(options = {}) {
518
+ this.env = options.env ?? process.env;
519
+ this.platform = options.platform ?? process.platform;
520
+ this.arch = options.arch ?? process.arch;
401
521
  }
522
+ resolveChannel = (explicitChannel, launcherVersion) => {
523
+ if (explicitChannel !== void 0 || this.env.NEXTCLAW_UPDATE_CHANNEL !== void 0) return normalizeChannel$1(explicitChannel ?? this.env.NEXTCLAW_UPDATE_CHANNEL);
524
+ return inferDefaultNpmRuntimeReleaseChannel(launcherVersion);
525
+ };
526
+ resolveManifestUrl = (channel, explicitManifestUrl) => {
527
+ const manifestUrl = normalizeOptionalString$1(explicitManifestUrl) ?? normalizeOptionalString$1(this.env.NEXTCLAW_UPDATE_MANIFEST_URL);
528
+ if (manifestUrl) return manifestUrl;
529
+ const baseUrl = normalizeOptionalString$1(this.env.NEXTCLAW_UPDATE_MANIFEST_BASE_URL) ?? DEFAULT_NPM_RUNTIME_UPDATE_BASE_URL;
530
+ return new URL(`${channel}/manifest-${channel}-${this.platform}-${this.arch}.json`, `${baseUrl.replace(/\/+$/, "")}/`).toString();
531
+ };
532
+ resolveBundlePublicKey = () => {
533
+ const explicitPublicKey = normalizeOptionalString$1(this.env.NEXTCLAW_UPDATE_BUNDLE_PUBLIC_KEY);
534
+ if (explicitPublicKey) return explicitPublicKey;
535
+ const publicKeyPath = normalizeOptionalString$1(this.env.NEXTCLAW_UPDATE_BUNDLE_PUBLIC_KEY_PATH);
536
+ if (!publicKeyPath || !existsSync(publicKeyPath)) {
537
+ const packagedPublicKeyPath = resolvePackagedPublicKeyPath();
538
+ return existsSync(packagedPublicKeyPath) ? readFileSync(packagedPublicKeyPath, "utf8").trim() : null;
539
+ }
540
+ return readFileSync(publicKeyPath, "utf8").trim();
541
+ };
402
542
  };
543
+ //#endregion
544
+ //#region src/cli/launcher/npm-runtime-update-state.store.ts
545
+ function createDefaultState(channel) {
546
+ return {
547
+ channel,
548
+ currentVersion: null,
549
+ previousVersion: null,
550
+ candidateVersion: null,
551
+ candidateLaunchCount: 0,
552
+ lastKnownGoodVersion: null,
553
+ badVersions: [],
554
+ lastUpdateCheckAt: null,
555
+ downloadedVersion: null,
556
+ downloadedReleaseNotesUrl: null,
557
+ updatePreferences: {
558
+ automaticChecks: true,
559
+ autoDownload: true
560
+ }
561
+ };
562
+ }
403
563
  function normalizeOptionalString(value) {
404
564
  if (typeof value !== "string") return null;
405
565
  const trimmed = value.trim();
406
566
  return trimmed ? trimmed : null;
407
567
  }
408
- function normalizeChannel(value) {
409
- return typeof value === "string" && value.trim().toLowerCase() === "beta" ? "beta" : "stable";
568
+ function normalizeChannel(value, fallback) {
569
+ if (typeof value !== "string") return fallback;
570
+ const trimmed = value.trim().toLowerCase();
571
+ if (trimmed === "beta") return "beta";
572
+ if (trimmed === "stable") return "stable";
573
+ return fallback;
410
574
  }
411
575
  function normalizeStringArray(value) {
412
576
  if (!Array.isArray(value)) return [];
413
577
  return [...new Set(value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean))];
414
578
  }
415
579
  function normalizeUpdatePreferences(value) {
416
- if (!value || typeof value !== "object" || Array.isArray(value)) return { ...DEFAULT_NPM_RUNTIME_UPDATE_STATE.updatePreferences };
580
+ const defaultState = createDefaultState("stable");
581
+ if (!value || typeof value !== "object" || Array.isArray(value)) return { ...defaultState.updatePreferences };
417
582
  const record = value;
418
583
  return {
419
- automaticChecks: typeof record.automaticChecks === "boolean" ? record.automaticChecks : DEFAULT_NPM_RUNTIME_UPDATE_STATE.updatePreferences.automaticChecks,
420
- autoDownload: typeof record.autoDownload === "boolean" ? record.autoDownload : DEFAULT_NPM_RUNTIME_UPDATE_STATE.updatePreferences.autoDownload
584
+ automaticChecks: typeof record.automaticChecks === "boolean" ? record.automaticChecks : defaultState.updatePreferences.automaticChecks,
585
+ autoDownload: typeof record.autoDownload === "boolean" ? record.autoDownload : defaultState.updatePreferences.autoDownload
421
586
  };
422
587
  }
423
- function normalizeState(input) {
588
+ function normalizeState(input, defaultChannel) {
424
589
  if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("npm runtime update state must be an object");
425
590
  const record = input;
426
591
  const candidateLaunchCount = Number(record.candidateLaunchCount);
427
592
  return {
428
- channel: normalizeChannel(record.channel),
593
+ channel: normalizeChannel(record.channel, defaultChannel),
429
594
  currentVersion: normalizeOptionalString(record.currentVersion),
430
595
  previousVersion: normalizeOptionalString(record.previousVersion),
431
596
  candidateVersion: normalizeOptionalString(record.candidateVersion),
@@ -439,15 +604,20 @@ function normalizeState(input) {
439
604
  };
440
605
  }
441
606
  var NpmRuntimeUpdateStateStore = class {
442
- constructor(statePath) {
607
+ defaultChannel;
608
+ constructor(statePath, options = {}) {
443
609
  this.statePath = statePath;
610
+ this.defaultChannel = options.defaultChannel ?? "stable";
444
611
  }
445
612
  read = () => {
446
- if (!existsSync(this.statePath)) return {
447
- ...DEFAULT_NPM_RUNTIME_UPDATE_STATE,
448
- updatePreferences: { ...DEFAULT_NPM_RUNTIME_UPDATE_STATE.updatePreferences }
449
- };
450
- return normalizeState(JSON.parse(readFileSync(this.statePath, "utf8")));
613
+ if (!existsSync(this.statePath)) {
614
+ const defaultState = createDefaultState(this.defaultChannel);
615
+ return {
616
+ ...defaultState,
617
+ updatePreferences: { ...defaultState.updatePreferences }
618
+ };
619
+ }
620
+ return normalizeState(JSON.parse(readFileSync(this.statePath, "utf8")), this.defaultChannel);
451
621
  };
452
622
  write = (state) => {
453
623
  mkdirSync(dirname(this.statePath), { recursive: true });
@@ -460,4 +630,4 @@ var NpmRuntimeUpdateStateStore = class {
460
630
  };
461
631
  };
462
632
  //#endregion
463
- export { waitForExit as _, findExecutableOnPath as a, isProcessRunning as c, prompt as d, resolvePublicIp as f, resolveUiStaticDir as g, resolveUiConfig as h, NpmRuntimeBundleLayoutStore as i, openBrowser as l, resolveUiApiBase as m, NpmRuntimeBundleService as n, getPackageVersion$1 as o, resolveServiceLogPath as p, compareNpmRuntimeVersions as r, isLoopbackHost as s, NpmRuntimeUpdateStateStore as t, printAgentResponse as u };
633
+ export { waitForExit as S, resolvePublicIp as _, compareNpmRuntimeVersions as a, resolveUiConfig as b, NpmRuntimeBundleLayoutStore as c, getPackageVersion$1 as d, isLoopbackHost as f, prompt as g, printAgentResponse as h, NpmRuntimeBundleService as i, findExecutableOnPath as l, openBrowser as m, NpmRuntimeUpdateSourceService as n, resolveEffectiveNpmRuntimeVersion as o, isProcessRunning as p, inferDefaultNpmRuntimeReleaseChannel as r, shouldPreferPackagedNpmRuntime as s, NpmRuntimeUpdateStateStore as t, findListeningProcessByPort as u, resolveServiceLogPath as v, resolveUiStaticDir as x, resolveUiApiBase as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextclaw",
3
- "version": "0.18.12-beta.2",
3
+ "version": "0.18.12-beta.21",
4
4
  "description": "Lightweight personal AI assistant with CLI, multi-provider routing, and channel integrations.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -41,20 +41,21 @@
41
41
  "commander": "^12.1.0",
42
42
  "jszip": "^3.10.1",
43
43
  "yaml": "^2.8.1",
44
- "@nextclaw/core": "0.12.13-beta.0",
45
- "@nextclaw/kernel": "0.1.2-beta.0",
46
- "@nextclaw/mcp": "0.1.77",
47
- "@nextclaw/ncp": "0.5.5",
48
- "@nextclaw/ncp-mcp": "0.1.79",
49
- "@nextclaw/remote": "0.1.89",
50
- "@nextclaw/openclaw-compat": "1.0.12",
51
- "@nextclaw/server": "0.12.12",
52
- "@nextclaw/ncp-toolkit": "0.5.10",
53
- "@nextclaw/nextclaw-ncp-runtime-stdio-client": "0.1.5",
54
- "@nextclaw/ncp-agent-runtime": "0.3.15",
55
- "@nextclaw/nextclaw-ncp-runtime-http-client": "0.1.4",
56
- "@nextclaw/nextclaw-hermes-acp-bridge": "0.1.4",
57
- "@nextclaw/runtime": "0.2.44"
44
+ "@nextclaw/companion": "0.1.1-beta.5",
45
+ "@nextclaw/core": "0.12.13-beta.4",
46
+ "@nextclaw/kernel": "0.1.2-beta.5",
47
+ "@nextclaw/mcp": "0.1.78-beta.4",
48
+ "@nextclaw/ncp": "0.5.6-beta.3",
49
+ "@nextclaw/ncp-mcp": "0.1.80-beta.4",
50
+ "@nextclaw/ncp-agent-runtime": "0.3.16-beta.4",
51
+ "@nextclaw/ncp-toolkit": "0.5.11-beta.3",
52
+ "@nextclaw/nextclaw-hermes-acp-bridge": "0.1.5-beta.4",
53
+ "@nextclaw/nextclaw-ncp-runtime-http-client": "0.1.5-beta.4",
54
+ "@nextclaw/nextclaw-ncp-runtime-stdio-client": "0.1.6-beta.4",
55
+ "@nextclaw/openclaw-compat": "1.0.13-beta.5",
56
+ "@nextclaw/remote": "0.1.90-beta.5",
57
+ "@nextclaw/runtime": "0.2.45-beta.3",
58
+ "@nextclaw/server": "0.12.13-beta.5"
58
59
  },
59
60
  "devDependencies": {
60
61
  "@types/node": "^20.17.6",
@@ -62,7 +63,7 @@
62
63
  "tsx": "^4.19.2",
63
64
  "typescript": "^5.6.3",
64
65
  "vitest": "^4.1.2",
65
- "@nextclaw/ui": "0.12.19"
66
+ "@nextclaw/ui": "0.12.20-beta.5"
66
67
  },
67
68
  "scripts": {
68
69
  "dev": "tsx watch --tsconfig tsconfig.json src/cli/app/index.ts",
@@ -189,6 +189,7 @@ When the gateway is already running, config changes from the UI or `nextclaw con
189
189
  - `agents.defaults.model`
190
190
  - `agents.context.*`
191
191
  - `tools.*`
192
+ - `companion.enabled`
192
193
  - `plugins.*` (v1 hot plugin runtime: plugin registry/channel gateways/channels are hot-reloaded)
193
194
 
194
195
  Restart is still required for:
@@ -211,6 +212,40 @@ Useful commands:
211
212
 
212
213
  UI note: **Model** page save persists `agents.defaults.model` only.
213
214
 
215
+ ### Companion feature
216
+
217
+ NextClaw companion is a persistent system feature backed by `companion.enabled`, not just a one-off background process.
218
+
219
+ Recommended control path:
220
+
221
+ - Open the runtime settings page in the UI.
222
+ - Toggle **Companion enabled**.
223
+ - Save the runtime settings.
224
+
225
+ Behavior:
226
+
227
+ - enabling starts the companion immediately when a local runtime is available
228
+ - disabling stops any running companion process
229
+ - if it remains enabled, it auto-starts again after the NextClaw runtime restarts
230
+
231
+ CLI equivalents:
232
+
233
+ ```bash
234
+ nextclaw companion enable
235
+ nextclaw companion disable
236
+ nextclaw companion status --json
237
+ ```
238
+
239
+ Lower-level process controls are also available:
240
+
241
+ ```bash
242
+ nextclaw companion start
243
+ nextclaw companion stop
244
+ ```
245
+
246
+ Use `enable/disable` when you want the feature state to persist in config.
247
+ Use `start/stop` only for direct process control or debugging.
248
+
214
249
  ### Multi-agent routing & session isolation (OpenClaw-aligned)
215
250
 
216
251
  For agent identities themselves, do **not** create them through `Routing & Runtime` or direct `agents.list` edits.
@@ -464,6 +499,11 @@ Skill loading contract:
464
499
  | `nextclaw start` | Start gateway + UI in the background |
465
500
  | `nextclaw restart` | Restart the background service with optional start flags |
466
501
  | `nextclaw stop` | Stop the background service |
502
+ | `nextclaw companion enable` | Persistently enable the companion feature and start it when a local runtime is available |
503
+ | `nextclaw companion disable` | Persistently disable the companion feature and stop any running companion process |
504
+ | `nextclaw companion status` | Show current companion process/config status (`--json`) |
505
+ | `nextclaw companion start` | Start the companion process without changing the persisted feature toggle |
506
+ | `nextclaw companion stop` | Stop the companion process without changing the persisted feature toggle (`--force` supported) |
467
507
  | `nextclaw service install-systemd --user` | Install a user-level Linux `systemd` service for NextClaw |
468
508
  | `sudo nextclaw service install-systemd --system` | Install a system-wide Linux `systemd` service for NextClaw |
469
509
  | `nextclaw service uninstall-systemd --user` | Remove a user-level Linux `systemd` service |
@@ -531,7 +571,7 @@ Autostart notes:
531
571
 
532
572
  - `npm i -g nextclaw` installs the CLI only. It does not register host autostart by itself.
533
573
  - On Linux, use `nextclaw service install-systemd --user` for a user-level login autostart path.
534
- - On macOS, use `nextclaw service install-launch-agent` for a LaunchAgent-based login autostart path.
574
+ - On macOS, use `nextclaw service install-launch-agent` for a LaunchAgent-based login autostart path. The agent runs once at login and does not supervise retries after the runtime exits.
535
575
  - On Windows, use `nextclaw service install-task` for a Scheduled Task based login autostart path.
536
576
  - For machine-wide Linux startup after boot, use `sudo nextclaw service install-systemd --system`.
537
577
  - `nextclaw service autostart status` and `nextclaw service autostart doctor` are read-only inspection commands; add `--user` or `--system` only when you need an explicit Linux `systemd` scope.