nextclaw 0.13.9 → 0.13.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.
Files changed (35) hide show
  1. package/dist/cli/index.js +235 -53
  2. package/package.json +22 -21
  3. package/ui-dist/assets/ChannelsList-Byfj2R01.js +1 -0
  4. package/ui-dist/assets/ChatPage-DM1ewbWf.js +38 -0
  5. package/ui-dist/assets/DocBrowser-BLv77lJ0.js +1 -0
  6. package/ui-dist/assets/LogoBadge-D7j1al-w.js +1 -0
  7. package/ui-dist/assets/MarketplacePage-DuskLKYh.js +49 -0
  8. package/ui-dist/assets/McpMarketplacePage-DpMjaD3m.js +40 -0
  9. package/ui-dist/assets/ModelConfig-ubaecweS.js +1 -0
  10. package/ui-dist/assets/ProvidersList-w8MJH2LI.js +1 -0
  11. package/ui-dist/assets/RemoteAccessPage-D79_5Kbn.js +1 -0
  12. package/ui-dist/assets/RuntimeConfig-BbX4yFKy.js +1 -0
  13. package/ui-dist/assets/SearchConfig-BmmmeyJd.js +1 -0
  14. package/ui-dist/assets/SecretsConfig-CWG8J01H.js +3 -0
  15. package/ui-dist/assets/SessionsConfig-D-vg_Lgv.js +2 -0
  16. package/ui-dist/assets/chat-message-CGXiVhyN.js +3 -0
  17. package/ui-dist/assets/config-hints-CApS3K_7.js +1 -0
  18. package/ui-dist/assets/config-layout-BHnOoweL.js +1 -0
  19. package/ui-dist/assets/index-COrhpAdh.css +1 -0
  20. package/ui-dist/assets/index-CeRbsQ90.js +8 -0
  21. package/ui-dist/assets/index-Ct7FQpxN.js +1 -0
  22. package/ui-dist/assets/label-CCSffS1D.js +1 -0
  23. package/ui-dist/assets/marketplace-localization-Dk31LJJJ.js +1 -0
  24. package/ui-dist/assets/page-layout-ud8wZ8gX.js +1 -0
  25. package/ui-dist/assets/popover-Bfoe6YBX.js +1 -0
  26. package/ui-dist/assets/provider-models-D3B_xWXx.js +1 -0
  27. package/ui-dist/assets/security-config-DJJUCMov.js +1 -0
  28. package/ui-dist/assets/skeleton-IOOTmHzP.js +1 -0
  29. package/ui-dist/assets/status-dot-Fz9-eKsl.js +1 -0
  30. package/ui-dist/assets/switch-B-_SrMSL.js +1 -0
  31. package/ui-dist/assets/tabs-custom-6Tm1ZHfS.js +1 -0
  32. package/ui-dist/assets/useConfirmDialog-BeOW2bOI.js +5 -0
  33. package/ui-dist/assets/vendor-CwsIoNvJ.js +442 -0
  34. package/ui-dist/index.html +18 -0
  35. package/LICENSE +0 -21
package/dist/cli/index.js CHANGED
@@ -29,7 +29,7 @@ import {
29
29
  setPluginRuntimeBridge as setPluginRuntimeBridge2
30
30
  } from "@nextclaw/openclaw-compat";
31
31
  import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
32
- import { join as join8, resolve as resolve12 } from "path";
32
+ import { join as join9, resolve as resolve12 } from "path";
33
33
  import { createInterface as createInterface3 } from "readline";
34
34
  import { fileURLToPath as fileURLToPath5 } from "url";
35
35
  import { spawn as spawn4 } from "child_process";
@@ -3001,6 +3001,73 @@ function readLoginPayload(raw) {
3001
3001
  }
3002
3002
  return { token, role };
3003
3003
  }
3004
+ function persistPlatformToken(params) {
3005
+ params.nextclawProvider.apiBase = params.v1Base;
3006
+ params.nextclawProvider.apiKey = params.token;
3007
+ params.providers.nextclaw = params.nextclawProvider;
3008
+ saveConfig6(params.config, params.configPath);
3009
+ }
3010
+ function parseJsonText(raw) {
3011
+ try {
3012
+ return JSON.parse(raw);
3013
+ } catch {
3014
+ return null;
3015
+ }
3016
+ }
3017
+ function readPlatformErrorMessage(raw, fallbackStatus) {
3018
+ const parsed = parseJsonText(raw);
3019
+ return typeof parsed === "object" && parsed && "error" in parsed && typeof parsed.error?.message === "string" ? parsed.error.message : raw || `Request failed (${fallbackStatus})`;
3020
+ }
3021
+ function readBrowserAuthStartPayload(raw) {
3022
+ const parsed = parseJsonText(raw);
3023
+ const data = typeof parsed === "object" && parsed && "data" in parsed ? parsed.data : null;
3024
+ const sessionId = typeof data?.sessionId === "string" ? data.sessionId.trim() : "";
3025
+ const verificationUri = typeof data?.verificationUri === "string" ? data.verificationUri.trim() : "";
3026
+ const expiresAt = typeof data?.expiresAt === "string" ? data.expiresAt.trim() : "";
3027
+ const intervalMs = typeof data?.intervalMs === "number" && Number.isFinite(data.intervalMs) ? Math.max(1e3, Math.trunc(data.intervalMs)) : 1500;
3028
+ if (!sessionId || !verificationUri || !expiresAt) {
3029
+ throw new Error("Browser authorization session payload is incomplete.");
3030
+ }
3031
+ return {
3032
+ sessionId,
3033
+ verificationUri,
3034
+ expiresAt,
3035
+ intervalMs
3036
+ };
3037
+ }
3038
+ function readBrowserAuthPollPayload(raw) {
3039
+ const parsed = parseJsonText(raw);
3040
+ const data = typeof parsed === "object" && parsed && "data" in parsed ? parsed.data : null;
3041
+ const status = typeof data?.status === "string" ? data.status.trim() : "";
3042
+ if (status === "pending") {
3043
+ return {
3044
+ status,
3045
+ nextPollMs: typeof data?.nextPollMs === "number" && Number.isFinite(data.nextPollMs) ? Math.max(1e3, Math.trunc(data.nextPollMs)) : 1500
3046
+ };
3047
+ }
3048
+ if (status === "expired") {
3049
+ return {
3050
+ status,
3051
+ message: typeof data?.message === "string" && data.message.trim() ? data.message.trim() : "Authorization session expired."
3052
+ };
3053
+ }
3054
+ if (status !== "authorized") {
3055
+ throw new Error("Unexpected browser authorization status.");
3056
+ }
3057
+ const token = typeof data?.token === "string" ? data.token.trim() : "";
3058
+ const user = typeof data?.user === "object" && data.user ? data.user : null;
3059
+ const role = typeof user?.role === "string" ? user.role.trim() : "user";
3060
+ const email = typeof user?.email === "string" ? user.email.trim() : "";
3061
+ if (!token || !email) {
3062
+ throw new Error("Authorized browser login payload is incomplete.");
3063
+ }
3064
+ return {
3065
+ status,
3066
+ token,
3067
+ role,
3068
+ email
3069
+ };
3070
+ }
3004
3071
  var PlatformAuthCommands = class {
3005
3072
  async loginResult(opts = {}) {
3006
3073
  const { configPath, config: config2, providers, nextclawProvider, platformBase, v1Base, inputApiBase } = resolveProviderConfig(opts);
@@ -3015,20 +3082,17 @@ var PlatformAuthCommands = class {
3015
3082
  });
3016
3083
  const raw = await response.text();
3017
3084
  if (!response.ok) {
3018
- let parsed = null;
3019
- try {
3020
- parsed = JSON.parse(raw);
3021
- } catch {
3022
- parsed = null;
3023
- }
3024
- const maybeMessage = typeof parsed === "object" && parsed && "error" in parsed && typeof parsed.error?.message === "string" ? parsed.error.message : raw || `Request failed (${response.status})`;
3025
- throw new Error(buildPlatformApiBaseErrorMessage(inputApiBase, maybeMessage));
3085
+ throw new Error(buildPlatformApiBaseErrorMessage(inputApiBase, readPlatformErrorMessage(raw, response.status)));
3026
3086
  }
3027
3087
  const { token, role } = readLoginPayload(raw);
3028
- nextclawProvider.apiBase = v1Base;
3029
- nextclawProvider.apiKey = token;
3030
- providers.nextclaw = nextclawProvider;
3031
- saveConfig6(config2, configPath);
3088
+ persistPlatformToken({
3089
+ configPath,
3090
+ config: config2,
3091
+ providers,
3092
+ nextclawProvider,
3093
+ v1Base,
3094
+ token
3095
+ });
3032
3096
  return {
3033
3097
  token,
3034
3098
  role,
@@ -3037,6 +3101,73 @@ var PlatformAuthCommands = class {
3037
3101
  v1Base
3038
3102
  };
3039
3103
  }
3104
+ async startBrowserAuth(opts = {}) {
3105
+ const { platformBase, v1Base, inputApiBase } = resolveProviderConfig(opts);
3106
+ const response = await fetch(`${platformBase}/platform/auth/browser/start`, {
3107
+ method: "POST",
3108
+ headers: {
3109
+ "Content-Type": "application/json"
3110
+ },
3111
+ body: JSON.stringify({})
3112
+ });
3113
+ const raw = await response.text();
3114
+ if (!response.ok) {
3115
+ throw new Error(buildPlatformApiBaseErrorMessage(inputApiBase, readPlatformErrorMessage(raw, response.status)));
3116
+ }
3117
+ const result = readBrowserAuthStartPayload(raw);
3118
+ return {
3119
+ ...result,
3120
+ platformBase,
3121
+ v1Base
3122
+ };
3123
+ }
3124
+ async pollBrowserAuth(params) {
3125
+ const { configPath, config: config2, providers, nextclawProvider, platformBase, v1Base, inputApiBase } = resolveProviderConfig({
3126
+ apiBase: params.apiBase
3127
+ });
3128
+ const response = await fetch(`${platformBase}/platform/auth/browser/poll`, {
3129
+ method: "POST",
3130
+ headers: {
3131
+ "Content-Type": "application/json"
3132
+ },
3133
+ body: JSON.stringify({
3134
+ sessionId: params.sessionId
3135
+ })
3136
+ });
3137
+ const raw = await response.text();
3138
+ if (!response.ok) {
3139
+ throw new Error(buildPlatformApiBaseErrorMessage(inputApiBase, readPlatformErrorMessage(raw, response.status)));
3140
+ }
3141
+ const result = readBrowserAuthPollPayload(raw);
3142
+ if (result.status === "pending") {
3143
+ return {
3144
+ status: "pending",
3145
+ nextPollMs: result.nextPollMs ?? 1500
3146
+ };
3147
+ }
3148
+ if (result.status === "expired") {
3149
+ return {
3150
+ status: "expired",
3151
+ message: result.message ?? "Authorization session expired."
3152
+ };
3153
+ }
3154
+ persistPlatformToken({
3155
+ configPath,
3156
+ config: config2,
3157
+ providers,
3158
+ nextclawProvider,
3159
+ v1Base,
3160
+ token: result.token ?? ""
3161
+ });
3162
+ return {
3163
+ status: "authorized",
3164
+ token: result.token ?? "",
3165
+ role: result.role ?? "user",
3166
+ email: result.email ?? "",
3167
+ platformBase,
3168
+ v1Base
3169
+ };
3170
+ }
3040
3171
  async login(opts = {}) {
3041
3172
  const result = await this.loginResult(opts);
3042
3173
  console.log(`\u2713 Logged in to NextClaw platform (${result.platformBase})`);
@@ -3130,6 +3261,9 @@ function normalizeOptionalString3(value) {
3130
3261
  const trimmed = value.trim();
3131
3262
  return trimmed.length > 0 ? trimmed : void 0;
3132
3263
  }
3264
+ function isPlatformSessionToken(value) {
3265
+ return typeof value === "string" && value.startsWith("nca.");
3266
+ }
3133
3267
  function resolveConfiguredLocalOrigin(config2) {
3134
3268
  const state = readServiceState();
3135
3269
  if (state && isProcessRunning(state.pid) && Number.isFinite(state.uiPort)) {
@@ -3240,8 +3374,8 @@ var RemoteCommands = class {
3240
3374
  },
3241
3375
  {
3242
3376
  name: "platform-token",
3243
- ok: Boolean(token),
3244
- detail: token ? "token configured" : 'run "nextclaw login" first'
3377
+ ok: isPlatformSessionToken(token),
3378
+ detail: isPlatformSessionToken(token) ? "platform session token configured" : 'run remote browser login or "nextclaw login" first'
3245
3379
  },
3246
3380
  {
3247
3381
  name: "platform-api-base",
@@ -3281,7 +3415,7 @@ var RemoteCommands = class {
3281
3415
  // src/cli/commands/diagnostics.ts
3282
3416
  import { createServer as createNetServer } from "net";
3283
3417
  import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
3284
- import { resolve as resolve8 } from "path";
3418
+ import { join as join4, resolve as resolve8 } from "path";
3285
3419
  import {
3286
3420
  APP_NAME as APP_NAME2,
3287
3421
  getConfigPath as getConfigPath5,
@@ -3422,6 +3556,11 @@ var DiagnosticsCommands = class {
3422
3556
  status: report.workspaceExists ? "pass" : "warn",
3423
3557
  detail: report.workspacePath
3424
3558
  },
3559
+ {
3560
+ name: "ui-assets",
3561
+ status: report.uiAssets.indexHtmlPresent ? "pass" : "fail",
3562
+ detail: report.uiAssets.resolvedStaticDir ? `${report.uiAssets.resolvedStaticDir} (${report.uiAssets.indexHtmlPresent ? "index.html found" : "index.html missing"})` : "no UI static directory resolved"
3563
+ },
3425
3564
  {
3426
3565
  name: "service-state",
3427
3566
  status: report.process.staleState ? "fail" : report.process.running ? "pass" : "warn",
@@ -3490,6 +3629,8 @@ var DiagnosticsCommands = class {
3490
3629
  const configuredUi = resolveUiConfig(config2, { enabled: true, host: config2.ui.host, port: config2.ui.port });
3491
3630
  const configuredUiUrl = resolveUiApiBase(configuredUi.host, configuredUi.port);
3492
3631
  const configuredApiUrl = `${configuredUiUrl}/api`;
3632
+ const resolvedStaticDir = serviceState?.uiStaticDir ?? resolveUiStaticDir();
3633
+ const indexHtmlPresent = Boolean(resolvedStaticDir && existsSync6(join4(resolvedStaticDir, "index.html")));
3493
3634
  const managedUiUrl = serviceState?.uiUrl ?? null;
3494
3635
  const managedApiUrl = serviceState?.apiUrl ?? null;
3495
3636
  const managedHealth = running && managedApiUrl ? await this.probeApiHealth(`${managedApiUrl}/health`) : { state: "unreachable", detail: "service not running" };
@@ -3524,6 +3665,10 @@ var DiagnosticsCommands = class {
3524
3665
  providers,
3525
3666
  serviceStatePath,
3526
3667
  serviceStateExists: existsSync6(serviceStatePath),
3668
+ uiAssets: {
3669
+ resolvedStaticDir,
3670
+ indexHtmlPresent
3671
+ },
3527
3672
  fixActions,
3528
3673
  process: {
3529
3674
  managedByState,
@@ -3623,7 +3768,11 @@ var DiagnosticsCommands = class {
3623
3768
  params.issues.push("A service appears healthy on configured API endpoint, but state is missing/stale.");
3624
3769
  params.recommendations.push("Another process may be occupying the UI port; stop it or use --ui-port with a free port.");
3625
3770
  }
3626
- if (!params.providers.some((provider) => provider.configured)) {
3771
+ if (params.running && !params.serviceState?.uiStaticDir) {
3772
+ params.issues.push("Managed service did not record a resolved UI static asset directory.");
3773
+ params.recommendations.push(`Check logs at ${params.serviceState?.logPath ?? resolveServiceLogPath()} and verify packaged ui-dist assets exist.`);
3774
+ }
3775
+ if (!params.running && !params.providers.some((provider) => provider.configured)) {
3627
3776
  params.recommendations.push("Configure at least one provider API key in UI or config before expecting agent replies.");
3628
3777
  }
3629
3778
  }
@@ -3673,7 +3822,7 @@ import {
3673
3822
  } from "@nextclaw/openclaw-compat";
3674
3823
  import { startUiServer } from "@nextclaw/server";
3675
3824
  import { appendFileSync, closeSync, cpSync as cpSync2, existsSync as existsSync10, mkdirSync as mkdirSync5, openSync } from "fs";
3676
- import { dirname as dirname2, join as join6, resolve as resolve10 } from "path";
3825
+ import { dirname as dirname2, join as join7, resolve as resolve10 } from "path";
3677
3826
  import { spawn as spawn3 } from "child_process";
3678
3827
  import { request as httpRequest } from "http";
3679
3828
  import { request as httpsRequest } from "https";
@@ -4154,7 +4303,7 @@ var MissingProvider = class extends LLMProvider {
4154
4303
  // src/cli/commands/service-marketplace-installer.ts
4155
4304
  import { getWorkspacePath as getWorkspacePath5, loadConfig as loadConfig12 } from "@nextclaw/core";
4156
4305
  import { existsSync as existsSync8, rmSync as rmSync4 } from "fs";
4157
- import { join as join4 } from "path";
4306
+ import { join as join5 } from "path";
4158
4307
 
4159
4308
  // src/cli/commands/service-marketplace-helpers.ts
4160
4309
  var containsAbsoluteFsPath = (line) => {
@@ -4357,7 +4506,7 @@ var ServiceMarketplaceInstaller = class {
4357
4506
  }
4358
4507
  async uninstallSkill(slug) {
4359
4508
  const workspace = getWorkspacePath5(loadConfig12().agents.defaults.workspace);
4360
- const targetDir = join4(workspace, "skills", slug);
4509
+ const targetDir = join5(workspace, "skills", slug);
4361
4510
  if (!existsSync8(targetDir)) {
4362
4511
  throw new Error(`Skill not installed in workspace: ${slug}`);
4363
4512
  }
@@ -6350,7 +6499,7 @@ async function createUiNcpAgent(params) {
6350
6499
  // src/cli/commands/service-remote-runtime.ts
6351
6500
  import { RemoteServiceModule } from "@nextclaw/remote";
6352
6501
  function createManagedRemoteModule(params) {
6353
- if (!params.config.ui.enabled) {
6502
+ if (!params.uiEnabled) {
6354
6503
  return null;
6355
6504
  }
6356
6505
  return new RemoteServiceModule({
@@ -6374,6 +6523,7 @@ function writeInitialManagedServiceState(params) {
6374
6523
  uiHost: params.snapshot.uiHost,
6375
6524
  uiPort: params.snapshot.uiPort,
6376
6525
  logPath: params.snapshot.logPath,
6526
+ uiStaticDir: params.snapshot.uiStaticDir ?? null,
6377
6527
  startupLastProbeError: null,
6378
6528
  startupTimeoutMs: params.readinessTimeoutMs,
6379
6529
  startupCheckedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -6390,6 +6540,7 @@ function writeReadyManagedServiceState(params) {
6390
6540
  uiHost: params.snapshot.uiHost,
6391
6541
  uiPort: params.snapshot.uiPort,
6392
6542
  logPath: params.snapshot.logPath,
6543
+ uiStaticDir: params.snapshot.uiStaticDir ?? currentState?.uiStaticDir ?? null,
6393
6544
  startupState: params.readiness.ready ? "ready" : "degraded",
6394
6545
  startupLastProbeError: params.readiness.lastProbeError,
6395
6546
  startupTimeoutMs: params.readinessTimeoutMs,
@@ -6424,6 +6575,9 @@ function decodeJwtPayload(token) {
6424
6575
  return null;
6425
6576
  }
6426
6577
  }
6578
+ function isPlatformSessionToken2(token) {
6579
+ return typeof token === "string" && token.startsWith("nca.");
6580
+ }
6427
6581
  function toRemoteRuntimeView(runtime2) {
6428
6582
  if (!runtime2) {
6429
6583
  return null;
@@ -6480,6 +6634,32 @@ var RemoteAccessHost = class {
6480
6634
  await this.deps.platformAuthCommands.loginResult(input);
6481
6635
  return this.getStatus();
6482
6636
  }
6637
+ async startBrowserAuth(input) {
6638
+ const result = await this.deps.platformAuthCommands.startBrowserAuth({
6639
+ apiBase: input.apiBase
6640
+ });
6641
+ return {
6642
+ sessionId: result.sessionId,
6643
+ verificationUri: result.verificationUri,
6644
+ expiresAt: result.expiresAt,
6645
+ intervalMs: result.intervalMs
6646
+ };
6647
+ }
6648
+ async pollBrowserAuth(input) {
6649
+ const config2 = loadConfig13(getConfigPath6());
6650
+ const result = await this.deps.platformAuthCommands.pollBrowserAuth({
6651
+ apiBase: normalizeOptionalString5(input.apiBase) ?? normalizeOptionalString5(config2.remote.platformApiBase) ?? normalizeOptionalString5(config2.providers.nextclaw?.apiBase) ?? void 0,
6652
+ sessionId: input.sessionId
6653
+ });
6654
+ if (result.status !== "authorized") {
6655
+ return result;
6656
+ }
6657
+ return {
6658
+ status: "authorized",
6659
+ email: result.email,
6660
+ role: result.role
6661
+ };
6662
+ }
6483
6663
  logout() {
6484
6664
  this.deps.platformAuthCommands.logout();
6485
6665
  return this.getStatus();
@@ -6592,7 +6772,7 @@ var RemoteAccessHost = class {
6592
6772
  };
6593
6773
  }
6594
6774
  readAccountView(params) {
6595
- if (!params.token) {
6775
+ if (!isPlatformSessionToken2(params.token)) {
6596
6776
  return {
6597
6777
  loggedIn: false,
6598
6778
  apiBase: params.apiBase,
@@ -6692,13 +6872,13 @@ function createRemoteAccessHost(params) {
6692
6872
 
6693
6873
  // src/cli/commands/ui-chat-run-coordinator.ts
6694
6874
  import { existsSync as existsSync9, mkdirSync as mkdirSync4, readdirSync as readdirSync2, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
6695
- import { join as join5 } from "path";
6875
+ import { join as join6 } from "path";
6696
6876
  import {
6697
6877
  getDataDir as getDataDir6,
6698
6878
  parseAgentScopedSessionKey as parseAgentScopedSessionKey2,
6699
6879
  safeFilename
6700
6880
  } from "@nextclaw/core";
6701
- var RUNS_DIR = join5(getDataDir6(), "runs");
6881
+ var RUNS_DIR = join6(getDataDir6(), "runs");
6702
6882
  var NON_TERMINAL_STATES = /* @__PURE__ */ new Set(["queued", "running"]);
6703
6883
  var DEFAULT_SESSION_TYPE = "native";
6704
6884
  var SESSION_TYPE_METADATA_KEY = "session_type";
@@ -7224,7 +7404,7 @@ var UiChatRunCoordinator = class {
7224
7404
  };
7225
7405
  }
7226
7406
  getRunPath(runId) {
7227
- return join5(RUNS_DIR, `${safeFilename(runId)}.json`);
7407
+ return join6(RUNS_DIR, `${safeFilename(runId)}.json`);
7228
7408
  }
7229
7409
  persistRun(run) {
7230
7410
  const persisted = {
@@ -7253,7 +7433,7 @@ var UiChatRunCoordinator = class {
7253
7433
  if (!entry.isFile() || !entry.name.endsWith(".json")) {
7254
7434
  continue;
7255
7435
  }
7256
- const path2 = join5(RUNS_DIR, entry.name);
7436
+ const path2 = join6(RUNS_DIR, entry.name);
7257
7437
  try {
7258
7438
  const parsed = JSON.parse(readFileSync8(path2, "utf-8"));
7259
7439
  const runId = readOptionalString(parsed.runId);
@@ -7359,7 +7539,7 @@ var ServiceCommands = class {
7359
7539
  });
7360
7540
  const sessionManager = new SessionManager(workspace);
7361
7541
  let pluginGatewayHandles = [];
7362
- const cronStorePath = join6(getDataDir7(), "cron", "jobs.json");
7542
+ const cronStorePath = join7(getDataDir7(), "cron", "jobs.json");
7363
7543
  const cron2 = new CronService2(cronStorePath);
7364
7544
  const uiConfig = resolveUiConfig(config2, options.uiOverrides);
7365
7545
  const uiStaticDir = options.uiStaticDir === void 0 ? resolveUiStaticDir() : options.uiStaticDir;
@@ -7542,7 +7722,7 @@ var ServiceCommands = class {
7542
7722
  accountId
7543
7723
  })
7544
7724
  );
7545
- const remoteModule = createManagedRemoteModule({ config: config2, localOrigin });
7725
+ const remoteModule = createManagedRemoteModule({ config: config2, uiEnabled: uiConfig.enabled, localOrigin });
7546
7726
  await startGatewaySupportServices({
7547
7727
  cronJobs: cron2.status().jobs,
7548
7728
  remoteModule,
@@ -7755,6 +7935,8 @@ var ServiceCommands = class {
7755
7935
  if (existing) {
7756
7936
  clearServiceState();
7757
7937
  }
7938
+ const staticDirDescription = staticDir ? `staticDir=${staticDir}` : "staticDir=<missing>";
7939
+ this.appendStartupStage(logPath, `ui asset resolution: ${staticDirDescription}`);
7758
7940
  if (!staticDir) {
7759
7941
  console.log("Warning: UI frontend not found in package assets.");
7760
7942
  }
@@ -7805,7 +7987,7 @@ var ServiceCommands = class {
7805
7987
  writeInitialManagedServiceState({
7806
7988
  config: config2,
7807
7989
  readinessTimeoutMs,
7808
- snapshot: { pid: child.pid, uiUrl, apiUrl, uiHost: uiConfig.host, uiPort: uiConfig.port, logPath }
7990
+ snapshot: { pid: child.pid, uiUrl, apiUrl, uiHost: uiConfig.host, uiPort: uiConfig.port, logPath, uiStaticDir: staticDir }
7809
7991
  });
7810
7992
  this.appendStartupStage(logPath, `health probe started: ${healthUrl} (phase=quick, timeoutMs=${quickPhaseTimeoutMs})`);
7811
7993
  let readiness = await this.waitForBackgroundServiceReady({
@@ -8333,8 +8515,8 @@ var ServiceCommands = class {
8333
8515
  }
8334
8516
  installBuiltinMarketplaceSkill(slug, force) {
8335
8517
  const workspace = getWorkspacePath9(loadConfig14().agents.defaults.workspace);
8336
- const destination = join6(workspace, "skills", slug);
8337
- const destinationSkillFile = join6(destination, "SKILL.md");
8518
+ const destination = join7(workspace, "skills", slug);
8519
+ const destinationSkillFile = join7(destination, "SKILL.md");
8338
8520
  if (existsSync10(destinationSkillFile) && !force) {
8339
8521
  return {
8340
8522
  message: `${slug} is already installed`
@@ -8350,7 +8532,7 @@ var ServiceCommands = class {
8350
8532
  }
8351
8533
  return null;
8352
8534
  }
8353
- mkdirSync5(join6(workspace, "skills"), { recursive: true });
8535
+ mkdirSync5(join7(workspace, "skills"), { recursive: true });
8354
8536
  cpSync2(dirname2(builtin.path), destination, { recursive: true, force: true });
8355
8537
  return {
8356
8538
  message: `Installed skill: ${slug}`
@@ -8412,7 +8594,7 @@ ${stderr}`.trim();
8412
8594
  // src/cli/workspace.ts
8413
8595
  import { cpSync as cpSync3, existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync9, readdirSync as readdirSync3, rmSync as rmSync5, writeFileSync as writeFileSync5 } from "fs";
8414
8596
  import { createRequire as createRequire2 } from "module";
8415
- import { dirname as dirname3, join as join7, resolve as resolve11 } from "path";
8597
+ import { dirname as dirname3, join as join8, resolve as resolve11 } from "path";
8416
8598
  import { fileURLToPath as fileURLToPath4 } from "url";
8417
8599
  import { APP_NAME as APP_NAME4, getDataDir as getDataDir8 } from "@nextclaw/core";
8418
8600
  import { spawnSync as spawnSync3 } from "child_process";
@@ -8442,11 +8624,11 @@ var WorkspaceManager = class {
8442
8624
  { source: "memory/MEMORY.md", target: "memory/MEMORY.md" }
8443
8625
  ];
8444
8626
  for (const entry of templateFiles) {
8445
- const filePath = join7(workspace, entry.target);
8627
+ const filePath = join8(workspace, entry.target);
8446
8628
  if (!force && existsSync11(filePath)) {
8447
8629
  continue;
8448
8630
  }
8449
- const templatePath = join7(templateDir, entry.source);
8631
+ const templatePath = join8(templateDir, entry.source);
8450
8632
  if (!existsSync11(templatePath)) {
8451
8633
  console.warn(`Warning: Template file missing: ${templatePath}`);
8452
8634
  continue;
@@ -8457,15 +8639,15 @@ var WorkspaceManager = class {
8457
8639
  writeFileSync5(filePath, content);
8458
8640
  created.push(entry.target);
8459
8641
  }
8460
- const memoryDir = join7(workspace, "memory");
8642
+ const memoryDir = join8(workspace, "memory");
8461
8643
  if (!existsSync11(memoryDir)) {
8462
8644
  mkdirSync6(memoryDir, { recursive: true });
8463
- created.push(join7("memory", ""));
8645
+ created.push(join8("memory", ""));
8464
8646
  }
8465
- const skillsDir = join7(workspace, "skills");
8647
+ const skillsDir = join8(workspace, "skills");
8466
8648
  if (!existsSync11(skillsDir)) {
8467
8649
  mkdirSync6(skillsDir, { recursive: true });
8468
- created.push(join7("skills", ""));
8650
+ created.push(join8("skills", ""));
8469
8651
  }
8470
8652
  const seeded = this.seedBuiltinSkills(skillsDir, { force });
8471
8653
  if (seeded > 0) {
@@ -8484,11 +8666,11 @@ var WorkspaceManager = class {
8484
8666
  if (!entry.isDirectory()) {
8485
8667
  continue;
8486
8668
  }
8487
- const src = join7(sourceDir, entry.name);
8488
- if (!existsSync11(join7(src, "SKILL.md"))) {
8669
+ const src = join8(sourceDir, entry.name);
8670
+ if (!existsSync11(join8(src, "SKILL.md"))) {
8489
8671
  continue;
8490
8672
  }
8491
- const dest = join7(targetDir, entry.name);
8673
+ const dest = join8(targetDir, entry.name);
8492
8674
  if (!force && existsSync11(dest)) {
8493
8675
  continue;
8494
8676
  }
@@ -8507,11 +8689,11 @@ var WorkspaceManager = class {
8507
8689
  const require3 = createRequire2(import.meta.url);
8508
8690
  const entry = require3.resolve("@nextclaw/core");
8509
8691
  const pkgRoot = resolve11(dirname3(entry), "..");
8510
- const distSkills = join7(pkgRoot, "dist", "skills");
8692
+ const distSkills = join8(pkgRoot, "dist", "skills");
8511
8693
  if (existsSync11(distSkills)) {
8512
8694
  return distSkills;
8513
8695
  }
8514
- const srcSkills = join7(pkgRoot, "src", "agent", "skills");
8696
+ const srcSkills = join8(pkgRoot, "src", "agent", "skills");
8515
8697
  if (existsSync11(srcSkills)) {
8516
8698
  return srcSkills;
8517
8699
  }
@@ -8527,7 +8709,7 @@ var WorkspaceManager = class {
8527
8709
  }
8528
8710
  const cliDir = resolve11(fileURLToPath4(new URL(".", import.meta.url)));
8529
8711
  const pkgRoot = resolve11(cliDir, "..", "..");
8530
- const candidates = [join7(pkgRoot, "templates")];
8712
+ const candidates = [join8(pkgRoot, "templates")];
8531
8713
  for (const candidate of candidates) {
8532
8714
  if (existsSync11(candidate)) {
8533
8715
  return candidate;
@@ -8536,8 +8718,8 @@ var WorkspaceManager = class {
8536
8718
  return null;
8537
8719
  }
8538
8720
  getBridgeDir() {
8539
- const userBridge = join7(getDataDir8(), "bridge");
8540
- if (existsSync11(join7(userBridge, "dist", "index.js"))) {
8721
+ const userBridge = join8(getDataDir8(), "bridge");
8722
+ if (existsSync11(join8(userBridge, "dist", "index.js"))) {
8541
8723
  return userBridge;
8542
8724
  }
8543
8725
  if (!which("npm")) {
@@ -8546,12 +8728,12 @@ var WorkspaceManager = class {
8546
8728
  }
8547
8729
  const cliDir = resolve11(fileURLToPath4(new URL(".", import.meta.url)));
8548
8730
  const pkgRoot = resolve11(cliDir, "..", "..");
8549
- const pkgBridge = join7(pkgRoot, "bridge");
8550
- const srcBridge = join7(pkgRoot, "..", "..", "bridge");
8731
+ const pkgBridge = join8(pkgRoot, "bridge");
8732
+ const srcBridge = join8(pkgRoot, "..", "..", "bridge");
8551
8733
  let source = null;
8552
- if (existsSync11(join7(pkgBridge, "package.json"))) {
8734
+ if (existsSync11(join8(pkgBridge, "package.json"))) {
8553
8735
  source = pkgBridge;
8554
- } else if (existsSync11(join7(srcBridge, "package.json"))) {
8736
+ } else if (existsSync11(join8(srcBridge, "package.json"))) {
8555
8737
  source = srcBridge;
8556
8738
  }
8557
8739
  if (!source) {
@@ -8846,7 +9028,7 @@ var CliRuntime = class {
8846
9028
  }
8847
9029
  const config2 = loadConfig15();
8848
9030
  const workspaceSetting = config2.agents.defaults.workspace;
8849
- const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join8(getDataDir9(), DEFAULT_WORKSPACE_DIR) : expandHome2(workspaceSetting);
9031
+ const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join9(getDataDir9(), DEFAULT_WORKSPACE_DIR) : expandHome2(workspaceSetting);
8850
9032
  const workspaceExisted = existsSync12(workspacePath);
8851
9033
  mkdirSync7(workspacePath, { recursive: true });
8852
9034
  const templateResult = this.workspaceManager.createWorkspaceTemplates(
@@ -9039,7 +9221,7 @@ ${this.logo} ${APP_NAME5} is ready! (${source})`);
9039
9221
  `${this.logo} Interactive mode (type exit or Ctrl+C to quit)
9040
9222
  `
9041
9223
  );
9042
- const historyFile = join8(getDataDir9(), "history", "cli_history");
9224
+ const historyFile = join9(getDataDir9(), "history", "cli_history");
9043
9225
  const historyDir = resolve12(historyFile, "..");
9044
9226
  mkdirSync7(historyDir, { recursive: true });
9045
9227
  const history = existsSync12(historyFile) ? readFileSync10(historyFile, "utf-8").split("\n").filter(Boolean) : [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextclaw",
3
- "version": "0.13.9",
3
+ "version": "0.13.11",
4
4
  "description": "Lightweight personal AI assistant with CLI, multi-provider routing, and channel integrations.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -35,20 +35,30 @@
35
35
  "ui-dist",
36
36
  "templates"
37
37
  ],
38
+ "scripts": {
39
+ "dev": "tsx watch --tsconfig tsconfig.json src/cli/index.ts",
40
+ "dev:build": "tsx src/cli/index.ts",
41
+ "build": "node scripts/sync-usage-template.mjs && tsup src/index.ts src/cli/index.ts --format esm --dts --out-dir dist && node scripts/copy-ui-dist.mjs",
42
+ "prepack": "pnpm run build",
43
+ "start": "node dist/cli.js",
44
+ "lint": "eslint .",
45
+ "tsc": "tsc -p tsconfig.json",
46
+ "test": "vitest"
47
+ },
38
48
  "dependencies": {
39
49
  "chokidar": "^3.6.0",
40
50
  "commander": "^12.1.0",
41
51
  "yaml": "^2.8.1",
42
- "@nextclaw/core": "0.9.5",
43
- "@nextclaw/mcp": "0.1.9",
44
- "@nextclaw/ncp": "0.3.1",
45
- "@nextclaw/ncp-agent-runtime": "0.2.1",
46
- "@nextclaw/ncp-mcp": "0.1.9",
47
- "@nextclaw/ncp-toolkit": "0.4.1",
48
- "@nextclaw/runtime": "0.2.5",
49
- "@nextclaw/server": "0.10.9",
50
- "@nextclaw/openclaw-compat": "0.3.8",
51
- "@nextclaw/remote": "0.1.5"
52
+ "@nextclaw/core": "workspace:*",
53
+ "@nextclaw/mcp": "workspace:*",
54
+ "@nextclaw/ncp": "workspace:*",
55
+ "@nextclaw/ncp-agent-runtime": "workspace:*",
56
+ "@nextclaw/ncp-mcp": "workspace:*",
57
+ "@nextclaw/ncp-toolkit": "workspace:*",
58
+ "@nextclaw/remote": "workspace:*",
59
+ "@nextclaw/runtime": "workspace:*",
60
+ "@nextclaw/server": "workspace:*",
61
+ "@nextclaw/openclaw-compat": "workspace:*"
52
62
  },
53
63
  "devDependencies": {
54
64
  "@types/node": "^20.17.6",
@@ -57,14 +67,5 @@
57
67
  "tsx": "^4.19.2",
58
68
  "typescript": "^5.6.3",
59
69
  "vitest": "^2.1.2"
60
- },
61
- "scripts": {
62
- "dev": "tsx watch --tsconfig tsconfig.json src/cli/index.ts",
63
- "dev:build": "tsx src/cli/index.ts",
64
- "build": "node scripts/sync-usage-template.mjs && tsup src/index.ts src/cli/index.ts --format esm --dts --out-dir dist && node scripts/copy-ui-dist.mjs",
65
- "start": "node dist/cli.js",
66
- "lint": "eslint .",
67
- "tsc": "tsc -p tsconfig.json",
68
- "test": "vitest"
69
70
  }
70
- }
71
+ }