@nextclaw/server 0.12.8 → 0.12.10

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/index.d.ts CHANGED
@@ -360,6 +360,12 @@ type RuntimeActionCapability = {
360
360
  reasonIfUnavailable?: string;
361
361
  };
362
362
  type RuntimeServiceState = "running" | "stopped" | "starting" | "stopping" | "restarting" | "unknown";
363
+ type RuntimePendingRestart = {
364
+ changedPaths: string[];
365
+ message: string;
366
+ reasons: string[];
367
+ requestedAt: string;
368
+ };
363
369
  type RuntimeControlView = {
364
370
  environment: RuntimeControlEnvironment;
365
371
  lifecycle: RuntimeLifecycleState;
@@ -368,6 +374,7 @@ type RuntimeControlView = {
368
374
  canRestartService: RuntimeActionCapability;
369
375
  canStopService: RuntimeActionCapability;
370
376
  canRestartApp: RuntimeActionCapability;
377
+ pendingRestart?: RuntimePendingRestart | null;
371
378
  ownerLabel?: string;
372
379
  managementHint?: string;
373
380
  message?: string;
@@ -417,6 +424,11 @@ type UiRuntimeControlHost = {
417
424
  };
418
425
  //#endregion
419
426
  //#region src/ui/chat-session-type.types.d.ts
427
+ type ChatSessionTypeIconView = {
428
+ kind: "image";
429
+ src: string;
430
+ alt?: string | null;
431
+ };
420
432
  type ChatSessionTypeCtaView = {
421
433
  kind: string;
422
434
  label?: string;
@@ -425,6 +437,7 @@ type ChatSessionTypeCtaView = {
425
437
  type ChatSessionTypeOptionView = {
426
438
  value: string;
427
439
  label: string;
440
+ icon?: ChatSessionTypeIconView | null;
428
441
  ready?: boolean;
429
442
  reason?: string | null;
430
443
  reasonMessage?: string | null;
@@ -460,6 +473,12 @@ type BootstrapRemoteState = "pending" | "ready" | "conflict" | "disabled" | "err
460
473
  type BootstrapStatusView = {
461
474
  phase: BootstrapPhase;
462
475
  shellReadyAt?: string;
476
+ ncpAgent: {
477
+ state: BootstrapStageState;
478
+ startedAt?: string;
479
+ completedAt?: string;
480
+ error?: string;
481
+ };
463
482
  pluginHydration: {
464
483
  state: BootstrapStageState;
465
484
  loadedPluginCount: number;
@@ -801,6 +820,11 @@ type SessionConfigView = {
801
820
  type RuntimeEntryView = {
802
821
  enabled?: boolean;
803
822
  label?: string;
823
+ icon?: {
824
+ kind: "image";
825
+ src: string;
826
+ alt?: string | null;
827
+ } | null;
804
828
  type: string;
805
829
  config?: Record<string, unknown>;
806
830
  };
@@ -1221,6 +1245,13 @@ type UiServerEvent = {
1221
1245
  payload: {
1222
1246
  path: string;
1223
1247
  };
1248
+ } | {
1249
+ type: "channel.config.apply-status";
1250
+ payload: {
1251
+ channel: string;
1252
+ status: "started" | "succeeded" | "failed";
1253
+ message?: string;
1254
+ };
1224
1255
  } | {
1225
1256
  type: "session.updated";
1226
1257
  payload: {
@@ -1348,4 +1379,4 @@ declare function getUiBridgeSecretPath(): string;
1348
1379
  declare function readUiBridgeSecret(): string | null;
1349
1380
  declare function ensureUiBridgeSecret(): string;
1350
1381
  //#endregion
1351
- export { AgentBindingView, AgentCreateRequest, AgentDeleteResult, AgentProfileView, AgentUpdateRequest, ApiError, ApiResponse, AppMetaView, AuthEnabledUpdateRequest, AuthLoginRequest, AuthPasswordUpdateRequest, AuthSetupRequest, AuthStatusView, BindingPeerView, BochaFreshnessValue, BootstrapPhase, BootstrapRemoteState, BootstrapStageState, BootstrapStatusView, ChannelAuthPollRequest, ChannelAuthPollResult, ChannelAuthStartRequest, ChannelAuthStartResult, ChannelSpecView, type ChatSessionTypeCtaView, type ChatSessionTypeOptionView, type ChatSessionTypesView, ConfigActionExecuteRequest, ConfigActionExecuteResult, ConfigActionManifest, ConfigActionType, ConfigMetaView, ConfigSchemaResponse, ConfigUiHint, ConfigUiHints, ConfigView, CronActionResult, CronCreateRequest, CronCreateResult, CronEnableRequest, CronJobStateView, CronJobView, CronListView, CronPayloadView, CronRunRequest, CronScheduleView, DEFAULT_SESSION_TYPE, MarketplaceApiConfig, MarketplaceInstallKind, MarketplaceInstallSkillParams, MarketplaceInstallSpec, MarketplaceInstalledRecord, MarketplaceInstalledView, MarketplaceInstaller, MarketplaceItemSummary, MarketplaceItemType, MarketplaceItemView, MarketplaceListView, MarketplaceLocalizedTextMap, MarketplaceMcpContentView, MarketplaceMcpDoctorResult, MarketplaceMcpInstallKind, MarketplaceMcpInstallRequest, MarketplaceMcpInstallResult, MarketplaceMcpInstallSpec, MarketplaceMcpManageAction, MarketplaceMcpManageRequest, MarketplaceMcpManageResult, MarketplaceMcpTemplateInput, MarketplacePluginContentView, MarketplacePluginInstallKind, MarketplacePluginInstallRequest, MarketplacePluginInstallResult, MarketplacePluginManageAction, MarketplacePluginManageRequest, MarketplacePluginManageResult, MarketplaceRecommendationView, MarketplaceSkillContentView, MarketplaceSkillInstallKind, MarketplaceSkillInstallRequest, MarketplaceSkillInstallResult, MarketplaceSkillManageAction, MarketplaceSkillManageRequest, MarketplaceSkillManageResult, MarketplaceSort, NcpSessionSkillsView, ProviderAuthImportResult, ProviderAuthPollRequest, ProviderAuthPollResult, ProviderAuthStartRequest, ProviderAuthStartResult, ProviderConfigUpdate, ProviderConfigView, ProviderConnectionTestRequest, ProviderConnectionTestResult, ProviderCreateRequest, ProviderCreateResult, ProviderDeleteResult, ProviderSpecView, RemoteAccessView, RemoteAccountProfileUpdateRequest, RemoteAccountView, RemoteBrowserAuthPollRequest, RemoteBrowserAuthPollResult, RemoteBrowserAuthStartRequest, RemoteBrowserAuthStartResult, RemoteDoctorCheckView, RemoteDoctorView, RemoteLoginRequest, RemoteRuntimeView, RemoteServiceAction, RemoteServiceActionResult, RemoteServiceView, RemoteSettingsUpdateRequest, RemoteSettingsView, RuntimeActionCapability, RuntimeActionImpact, RuntimeConfigUpdate, RuntimeControlAction, RuntimeControlActionResult, RuntimeControlEnvironment, RuntimeControlView, RuntimeEntryView, RuntimeLifecycleState, RuntimeServiceState, SearchConfigUpdate, SearchConfigView, SearchProviderConfigView, SearchProviderName, SearchProviderSpecView, SecretProviderEnvView, SecretProviderExecView, SecretProviderFileView, SecretProviderView, SecretRefView, SecretSourceView, SecretsConfigUpdate, SecretsView, ServerPathBreadcrumbView, ServerPathBrowseView, ServerPathEntryView, ServerPathReadView, SessionConfigView, SessionEntryView, SessionEventView, SessionHistoryView, SessionMessageView, SessionPatchUpdate, SessionPatchValidationError, SessionSkillEntryView, SessionTypeDescribeParams, SessionsListView, TavilySearchDepthValue, UiNcpAgent, UiNcpAssetPutView, UiNcpAssetView, UiNcpSessionListView, UiNcpSessionMessagesView, UiNcpSessionService, UiNcpStoredAssetRecord, type UiRemoteAccessHost, type UiRuntimeControlHost, UiServerEvent, UiServerHandle, UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createCustomProvider, createUiRouter, deleteCustomProvider, deleteSession, ensureUiBridgeSecret, executeConfigAction, getSessionHistory, getUiBridgeSecretPath, listSessions, loadConfigOrDefault, patchSession, readUiBridgeSecret, startUiServer, testProviderConnection, updateChannel, updateModel, updateProvider, updateRuntime, updateSearch, updateSecrets };
1382
+ export { AgentBindingView, AgentCreateRequest, AgentDeleteResult, AgentProfileView, AgentUpdateRequest, ApiError, ApiResponse, AppMetaView, AuthEnabledUpdateRequest, AuthLoginRequest, AuthPasswordUpdateRequest, AuthSetupRequest, AuthStatusView, BindingPeerView, BochaFreshnessValue, BootstrapPhase, BootstrapRemoteState, BootstrapStageState, BootstrapStatusView, ChannelAuthPollRequest, ChannelAuthPollResult, ChannelAuthStartRequest, ChannelAuthStartResult, ChannelSpecView, type ChatSessionTypeCtaView, type ChatSessionTypeOptionView, type ChatSessionTypesView, ConfigActionExecuteRequest, ConfigActionExecuteResult, ConfigActionManifest, ConfigActionType, ConfigMetaView, ConfigSchemaResponse, ConfigUiHint, ConfigUiHints, ConfigView, CronActionResult, CronCreateRequest, CronCreateResult, CronEnableRequest, CronJobStateView, CronJobView, CronListView, CronPayloadView, CronRunRequest, CronScheduleView, DEFAULT_SESSION_TYPE, MarketplaceApiConfig, MarketplaceInstallKind, MarketplaceInstallSkillParams, MarketplaceInstallSpec, MarketplaceInstalledRecord, MarketplaceInstalledView, MarketplaceInstaller, MarketplaceItemSummary, MarketplaceItemType, MarketplaceItemView, MarketplaceListView, MarketplaceLocalizedTextMap, MarketplaceMcpContentView, MarketplaceMcpDoctorResult, MarketplaceMcpInstallKind, MarketplaceMcpInstallRequest, MarketplaceMcpInstallResult, MarketplaceMcpInstallSpec, MarketplaceMcpManageAction, MarketplaceMcpManageRequest, MarketplaceMcpManageResult, MarketplaceMcpTemplateInput, MarketplacePluginContentView, MarketplacePluginInstallKind, MarketplacePluginInstallRequest, MarketplacePluginInstallResult, MarketplacePluginManageAction, MarketplacePluginManageRequest, MarketplacePluginManageResult, MarketplaceRecommendationView, MarketplaceSkillContentView, MarketplaceSkillInstallKind, MarketplaceSkillInstallRequest, MarketplaceSkillInstallResult, MarketplaceSkillManageAction, MarketplaceSkillManageRequest, MarketplaceSkillManageResult, MarketplaceSort, NcpSessionSkillsView, ProviderAuthImportResult, ProviderAuthPollRequest, ProviderAuthPollResult, ProviderAuthStartRequest, ProviderAuthStartResult, ProviderConfigUpdate, ProviderConfigView, ProviderConnectionTestRequest, ProviderConnectionTestResult, ProviderCreateRequest, ProviderCreateResult, ProviderDeleteResult, ProviderSpecView, RemoteAccessView, RemoteAccountProfileUpdateRequest, RemoteAccountView, RemoteBrowserAuthPollRequest, RemoteBrowserAuthPollResult, RemoteBrowserAuthStartRequest, RemoteBrowserAuthStartResult, RemoteDoctorCheckView, RemoteDoctorView, RemoteLoginRequest, RemoteRuntimeView, RemoteServiceAction, RemoteServiceActionResult, RemoteServiceView, RemoteSettingsUpdateRequest, RemoteSettingsView, RuntimeActionCapability, RuntimeActionImpact, RuntimeConfigUpdate, RuntimeControlAction, RuntimeControlActionResult, RuntimeControlEnvironment, RuntimeControlView, RuntimeEntryView, RuntimeLifecycleState, RuntimePendingRestart, RuntimeServiceState, SearchConfigUpdate, SearchConfigView, SearchProviderConfigView, SearchProviderName, SearchProviderSpecView, SecretProviderEnvView, SecretProviderExecView, SecretProviderFileView, SecretProviderView, SecretRefView, SecretSourceView, SecretsConfigUpdate, SecretsView, ServerPathBreadcrumbView, ServerPathBrowseView, ServerPathEntryView, ServerPathReadView, SessionConfigView, SessionEntryView, SessionEventView, SessionHistoryView, SessionMessageView, SessionPatchUpdate, SessionPatchValidationError, SessionSkillEntryView, SessionTypeDescribeParams, SessionsListView, TavilySearchDepthValue, UiNcpAgent, UiNcpAssetPutView, UiNcpAssetView, UiNcpSessionListView, UiNcpSessionMessagesView, UiNcpSessionService, UiNcpStoredAssetRecord, type UiRemoteAccessHost, type UiRuntimeControlHost, UiServerEvent, UiServerHandle, UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createCustomProvider, createUiRouter, deleteCustomProvider, deleteSession, ensureUiBridgeSecret, executeConfigAction, getSessionHistory, getUiBridgeSecretPath, listSessions, loadConfigOrDefault, patchSession, readUiBridgeSecret, startUiServer, testProviderConnection, updateChannel, updateModel, updateProvider, updateRuntime, updateSearch, updateSecrets };
package/dist/index.js CHANGED
@@ -478,6 +478,7 @@ function buildAppMetaView(options) {
478
478
  function buildFallbackBootstrapStatus() {
479
479
  return {
480
480
  phase: "kernel-starting",
481
+ ncpAgent: { state: "pending" },
481
482
  pluginHydration: {
482
483
  state: "pending",
483
484
  loadedPluginCount: 0,
@@ -1357,15 +1358,35 @@ function normalizeRuntimeEntries(entries) {
1357
1358
  const entry = rawEntry;
1358
1359
  const type = normalizeOptionalString(entry.type);
1359
1360
  if (!type) continue;
1361
+ const normalizedIcon = normalizeRuntimeEntryIcon(entry.icon);
1360
1362
  normalized[id] = {
1361
1363
  enabled: typeof entry.enabled === "boolean" ? entry.enabled : true,
1362
1364
  ...normalizeOptionalString(entry.label) ? { label: normalizeOptionalString(entry.label) ?? void 0 } : {},
1365
+ ...normalizedIcon ? { icon: normalizedIcon } : {},
1363
1366
  type,
1364
1367
  config: normalizeRuntimeEntryConfig(type, entry.config && typeof entry.config === "object" && !Array.isArray(entry.config) ? entry.config : {})
1365
1368
  };
1366
1369
  }
1367
1370
  return normalized;
1368
1371
  }
1372
+ function normalizeRuntimeEntryIcon(value) {
1373
+ if (typeof value === "string") {
1374
+ const src = value.trim();
1375
+ return src ? {
1376
+ kind: "image",
1377
+ src
1378
+ } : null;
1379
+ }
1380
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
1381
+ const src = normalizeOptionalString(value.src);
1382
+ if (!src) return null;
1383
+ const alt = normalizeOptionalString(value.alt);
1384
+ return {
1385
+ kind: "image",
1386
+ src,
1387
+ ...alt ? { alt } : {}
1388
+ };
1389
+ }
1369
1390
  function normalizeRuntimeEntryConfig(type, config) {
1370
1391
  if (type !== "narp-stdio") return { ...config };
1371
1392
  const command = normalizeOptionalString(config.command);
@@ -2441,22 +2462,64 @@ async function importProviderAuthFromCli(configPath, providerName) {
2441
2462
  //#endregion
2442
2463
  //#region src/ui/ui-routes/config.controller.ts
2443
2464
  var ConfigRoutesController = class {
2465
+ channelConfigApplyTasks = /* @__PURE__ */ new Map();
2444
2466
  constructor(options) {
2445
2467
  this.options = options;
2446
2468
  }
2447
- getPluginConfigOptions() {
2469
+ getPluginConfigOptions = () => {
2448
2470
  return {
2449
2471
  pluginChannelBindings: this.options.getPluginChannelBindings?.() ?? [],
2450
2472
  pluginUiMetadata: this.options.getPluginUiMetadata?.() ?? []
2451
2473
  };
2452
- }
2453
- async publishConfigUpdates(paths) {
2474
+ };
2475
+ publishConfigUpdatedPaths = (paths) => {
2454
2476
  for (const path of paths) this.options.publish({
2455
2477
  type: "config.updated",
2456
2478
  payload: { path }
2457
2479
  });
2480
+ };
2481
+ publishConfigUpdates = async (paths) => {
2482
+ this.publishConfigUpdatedPaths(paths);
2458
2483
  await this.options.applyLiveConfigReload?.();
2459
- }
2484
+ };
2485
+ publishChannelConfigApplyStatus = (params) => {
2486
+ this.options.publish({
2487
+ type: "channel.config.apply-status",
2488
+ payload: params
2489
+ });
2490
+ };
2491
+ enqueueChannelConfigApply = (channel) => {
2492
+ const task = (this.channelConfigApplyTasks.get(channel) ?? Promise.resolve()).catch(() => void 0).then(async () => {
2493
+ this.publishChannelConfigApplyStatus({
2494
+ channel,
2495
+ status: "started"
2496
+ });
2497
+ try {
2498
+ await this.options.applyLiveConfigReload?.();
2499
+ this.publishChannelConfigApplyStatus({
2500
+ channel,
2501
+ status: "succeeded"
2502
+ });
2503
+ } catch (error) {
2504
+ const message = error instanceof Error ? error.message : String(error);
2505
+ this.publishChannelConfigApplyStatus({
2506
+ channel,
2507
+ status: "failed",
2508
+ message
2509
+ });
2510
+ this.options.publish({
2511
+ type: "error",
2512
+ payload: {
2513
+ code: "CHANNEL_CONFIG_APPLY_FAILED",
2514
+ message: `Failed to apply ${channel} channel config: ${message}`
2515
+ }
2516
+ });
2517
+ }
2518
+ }).finally(() => {
2519
+ if (this.channelConfigApplyTasks.get(channel) === task) this.channelConfigApplyTasks.delete(channel);
2520
+ });
2521
+ this.channelConfigApplyTasks.set(channel, task);
2522
+ };
2460
2523
  getConfig = (c) => {
2461
2524
  const config = loadConfigOrDefault(this.options.configPath);
2462
2525
  return c.json(ok(buildConfigView(config, this.getPluginConfigOptions())));
@@ -2582,7 +2645,8 @@ var ConfigRoutesController = class {
2582
2645
  if (!body.ok) return c.json(err("INVALID_BODY", "invalid json body"), 400);
2583
2646
  const result = updateChannel(this.options.configPath, channel, body.data, this.getPluginConfigOptions());
2584
2647
  if (!result) return c.json(err("NOT_FOUND", `unknown channel: ${channel}`), 404);
2585
- await this.publishConfigUpdates([`channels.${channel}`]);
2648
+ this.publishConfigUpdatedPaths([`channels.${channel}`]);
2649
+ this.enqueueChannelConfigApply(channel);
2586
2650
  return c.json(ok(result));
2587
2651
  };
2588
2652
  startChannelAuth = async (c) => {
@@ -2799,6 +2863,29 @@ function buildAssetContentUrl(assetUri) {
2799
2863
  function encodeContentDispositionFileName(fileName) {
2800
2864
  return encodeURIComponent(fileName).replace(/\*/g, "%2A");
2801
2865
  }
2866
+ function inferMimeTypeFromFileName(fileName) {
2867
+ const normalized = fileName.trim().toLowerCase();
2868
+ if (normalized.endsWith(".mp3")) return "audio/mpeg";
2869
+ if (normalized.endsWith(".m4a")) return "audio/mp4";
2870
+ if (normalized.endsWith(".wav")) return "audio/wav";
2871
+ if (normalized.endsWith(".ogg")) return "audio/ogg";
2872
+ if (normalized.endsWith(".opus")) return "audio/opus";
2873
+ if (normalized.endsWith(".flac")) return "audio/flac";
2874
+ if (normalized.endsWith(".aac")) return "audio/aac";
2875
+ if (normalized.endsWith(".weba")) return "audio/webm";
2876
+ if (normalized.endsWith(".mp4") || normalized.endsWith(".m4v")) return "video/mp4";
2877
+ if (normalized.endsWith(".mov")) return "video/quicktime";
2878
+ if (normalized.endsWith(".webm")) return "video/webm";
2879
+ if (normalized.endsWith(".mkv")) return "video/x-matroska";
2880
+ if (normalized.endsWith(".avi")) return "video/x-msvideo";
2881
+ if (normalized.endsWith(".wmv")) return "video/x-ms-wmv";
2882
+ return null;
2883
+ }
2884
+ function resolveResponseMimeType(fileName, mimeType) {
2885
+ const normalized = mimeType.trim().toLowerCase();
2886
+ if (normalized.length > 0 && normalized !== "application/octet-stream") return normalized;
2887
+ return inferMimeTypeFromFileName(fileName) ?? "application/octet-stream";
2888
+ }
2802
2889
  function toAssetView(record) {
2803
2890
  return {
2804
2891
  id: record.id,
@@ -2849,7 +2936,7 @@ var NcpAssetRoutesController = class {
2849
2936
  if (!record || !contentPath) return c.json(err("NOT_FOUND", `asset not found: ${uri}`), 404);
2850
2937
  const body = await readFile(contentPath);
2851
2938
  return new Response(body, { headers: {
2852
- "content-type": record.mimeType || "application/octet-stream",
2939
+ "content-type": resolveResponseMimeType(record.fileName, record.mimeType || "application/octet-stream"),
2853
2940
  "content-disposition": `inline; filename*=UTF-8''${encodeContentDispositionFileName(record.fileName)}`
2854
2941
  } });
2855
2942
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/server",
3
- "version": "0.12.8",
3
+ "version": "0.12.10",
4
4
  "private": false,
5
5
  "description": "Nextclaw UI/API server.",
6
6
  "type": "module",
@@ -18,12 +18,12 @@
18
18
  "@hono/node-server": "^1.13.3",
19
19
  "hono": "^4.6.2",
20
20
  "ws": "^8.18.0",
21
- "@nextclaw/core": "0.12.8",
22
- "@nextclaw/mcp": "0.1.73",
23
- "@nextclaw/ncp": "0.5.2",
24
- "@nextclaw/openclaw-compat": "1.0.8",
25
- "@nextclaw/runtime": "0.2.40",
26
- "@nextclaw/ncp-http-agent-server": "0.3.14"
21
+ "@nextclaw/mcp": "0.1.75",
22
+ "@nextclaw/ncp": "0.5.4",
23
+ "@nextclaw/runtime": "0.2.42",
24
+ "@nextclaw/ncp-http-agent-server": "0.3.16",
25
+ "@nextclaw/core": "0.12.10",
26
+ "@nextclaw/openclaw-compat": "1.0.10"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/node": "^20.17.6",