@nextclaw/server 0.12.19 → 0.12.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.
package/dist/index.d.ts CHANGED
@@ -2,10 +2,9 @@ import * as _$hono from "hono";
2
2
  import { Context, Hono } from "hono";
3
3
  import * as NextclawCore from "@nextclaw/core";
4
4
  import { Config, ConfigActionExecuteRequest as ConfigActionExecuteRequest$1, ConfigActionExecuteResult as ConfigActionExecuteResult$1, ThinkingLevel } from "@nextclaw/core";
5
- import { NcpHttpAgentStreamProvider } from "@nextclaw/ncp-http-agent-server";
6
5
  import { PluginChannelBinding, PluginUiMetadata } from "@nextclaw/openclaw-compat";
7
- import { LlmProviderManager } from "@nextclaw/kernel";
8
- import { NcpAgentClientEndpoint, NcpMessage, NcpSessionApi, NcpSessionStatus, NcpSessionSummary } from "@nextclaw/ncp";
6
+ import { LlmProviderManager, NextclawKernel } from "@nextclaw/kernel";
7
+ import { NcpMessage, NcpSessionApi, NcpSessionStatus, NcpSessionSummary } from "@nextclaw/ncp";
9
8
  import * as _$hono_utils_http_status0 from "hono/utils/http-status";
10
9
  import * as _$hono_utils_types0 from "hono/utils/types";
11
10
  import { IncomingMessage } from "node:http";
@@ -67,23 +66,6 @@ declare class EventBus {
67
66
  private safeInvokeGlobalListener;
68
67
  }
69
68
  //#endregion
70
- //#region ../nextclaw-shared/src/services/ingress.service.d.ts
71
- type IngressEnvelope<TPayload = unknown> = {
72
- type: Key<TPayload>;
73
- payload?: TPayload;
74
- source?: string;
75
- };
76
- type IngressContext = {
77
- source: string;
78
- token?: string | null;
79
- };
80
- type IngressHandler<TPayload = unknown, TResult = unknown> = (envelope: IngressEnvelope<TPayload>, context: IngressContext) => Promise<TResult> | TResult;
81
- declare class Ingress {
82
- private readonly handlers;
83
- readonly addHandler: <TPayload = unknown, TResult = unknown>(type: Key<TPayload>, handler: IngressHandler<TPayload, TResult>) => (() => void);
84
- readonly handle: <TPayload = unknown, TResult = unknown>(envelope: IngressEnvelope<TPayload>, context: IngressContext) => Promise<TResult>;
85
- }
86
- //#endregion
87
69
  //#region ../nextclaw-shared/src/types/update.types.d.ts
88
70
  type UpdateStatus = "idle" | "checking" | "update-available" | "downloading" | "downloaded" | "applying" | "restart-required" | "up-to-date" | "blocked" | "failed";
89
71
  type InstallationKind = "desktop-bundle" | "npm-runtime-bundle" | "npm-global" | "unknown";
@@ -122,6 +104,7 @@ type UpdateSnapshot = {
122
104
  declare class NcpAssetRoutesController {
123
105
  private readonly options;
124
106
  constructor(options: UiRouterOptions);
107
+ private readonly getAssetApi;
125
108
  readonly putAssets: (c: Context) => Promise<(Response & _$hono.TypedResponse<{
126
109
  ok: boolean;
127
110
  error: {
@@ -1114,21 +1097,15 @@ type SessionTypeDescribeParams = {
1114
1097
  describeMode?: "observation" | "probe";
1115
1098
  };
1116
1099
  type UiNcpSessionService = NcpSessionApi;
1117
- type UiNcpAgent = {
1118
- agentClientEndpoint: NcpAgentClientEndpoint;
1119
- streamProvider?: NcpHttpAgentStreamProvider;
1120
- listSessionTypes?: (params?: SessionTypeDescribeParams) => Promise<ChatSessionTypesView> | ChatSessionTypesView;
1121
- assetApi?: {
1122
- put: (input: {
1123
- fileName: string;
1124
- mimeType?: string | null;
1125
- bytes: Uint8Array;
1126
- createdAt?: Date;
1127
- }) => Promise<UiNcpStoredAssetRecord>;
1128
- stat: (uri: string) => Promise<UiNcpStoredAssetRecord | null> | UiNcpStoredAssetRecord | null;
1129
- resolveContentPath: (uri: string) => string | null;
1130
- };
1131
- basePath?: string;
1100
+ type UiNcpAssetService = {
1101
+ put: (input: {
1102
+ fileName: string;
1103
+ mimeType?: string | null;
1104
+ bytes: Uint8Array;
1105
+ createdAt?: Date;
1106
+ }) => Promise<UiNcpStoredAssetRecord>;
1107
+ stat: (uri: string) => Promise<UiNcpStoredAssetRecord | null> | UiNcpStoredAssetRecord | null;
1108
+ resolveContentPath: (uri: string) => string | null;
1132
1109
  };
1133
1110
  type ConfigView = {
1134
1111
  companion?: {
@@ -1497,7 +1474,6 @@ type RuntimeControlActionResult = {
1497
1474
  //#endregion
1498
1475
  //#region src/app/types/router-options.types.d.ts
1499
1476
  type UiAppEventBus = Pick<EventBus, "emit" | "subscribeAll">;
1500
- type UiIngress = Pick<Ingress, "handle">;
1501
1477
  type UiBootstrapStatusHost = {
1502
1478
  getStatus: () => BootstrapStatusView;
1503
1479
  };
@@ -1505,7 +1481,7 @@ type UiPluginHost = {
1505
1481
  getChannelBindings: () => PluginChannelBinding[];
1506
1482
  getUiMetadata: () => PluginUiMetadata[];
1507
1483
  };
1508
- type UiNcpSessionHost = UiNcpSessionService;
1484
+ type UiKernelHost = Pick<NextclawKernel, "agentRuntimeManager" | "assetStore" | "ingress" | "llmProviders" | "ncpSessionApi" | "sessionRunManager">;
1509
1485
  type UiCronHost = {
1510
1486
  listJobs: (includeDisabled?: boolean) => CronJobEntry[];
1511
1487
  addJob: (params: {
@@ -1525,9 +1501,9 @@ type UiCronHost = {
1525
1501
  runJob: (jobId: string, force?: boolean) => Promise<boolean>;
1526
1502
  };
1527
1503
  type UiRouterOptions = {
1504
+ kernel: UiKernelHost;
1528
1505
  configPath: string;
1529
1506
  appEventBus: UiAppEventBus;
1530
- ingress?: UiIngress;
1531
1507
  uiConfig?: Pick<NextclawCore.Config["ui"], "enabled" | "host" | "open" | "port">;
1532
1508
  uiStaticDir?: string | null;
1533
1509
  corsOrigins?: string[] | "*";
@@ -1536,15 +1512,12 @@ type UiRouterOptions = {
1536
1512
  initializeAgentHomeDirectory?: (homeDirectory: string) => void;
1537
1513
  marketplace?: MarketplaceApiConfig;
1538
1514
  cron?: UiCronHost;
1539
- ncpAgent?: UiNcpAgent;
1540
- sessions?: UiNcpSessionHost;
1541
1515
  authService?: UiAuthService;
1542
1516
  remoteAccess?: UiRemoteAccessHost;
1543
1517
  runtimeControl?: UiRuntimeControlHost;
1544
1518
  runtimeUpdate?: UiRuntimeUpdateHost;
1545
1519
  bootstrapStatus?: UiBootstrapStatusHost;
1546
1520
  plugins?: UiPluginHost;
1547
- providers?: LlmProviderManager;
1548
1521
  };
1549
1522
  type UiRemoteAccessHost = {
1550
1523
  getStatus: () => Promise<RemoteAccessView> | RemoteAccessView;
@@ -2497,4 +2470,4 @@ declare function updateChannel(configPath: string, channelName: string, patch: R
2497
2470
  declare function updateRuntime(configPath: string, patch: RuntimeConfigUpdate): Pick<ConfigView, "companion" | "agents" | "bindings" | "session">;
2498
2471
  declare function updateSecrets(configPath: string, patch: SecretsConfigUpdate): SecretsView;
2499
2472
  //#endregion
2500
- 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, ConfigRoutesController, ConfigSchemaResponse, ConfigUiHint, ConfigUiHints, ConfigView, CronActionResult, CronCreateRequest, CronCreateResult, CronEnableRequest, CronJobStateView, CronJobView, CronListView, CronPayloadView, CronRunRequest, CronScheduleView, MarketplaceApiConfig, MarketplaceInstallKind, MarketplaceInstallRequest, MarketplaceInstallResult, MarketplaceInstallSkillParams, MarketplaceInstallSpec, MarketplaceInstalledRecord, MarketplaceInstalledView, MarketplaceInstaller, MarketplaceItemSummary, MarketplaceItemType, MarketplaceItemView, MarketplaceListView, MarketplaceLocalizedTextMap, MarketplaceManageAction, MarketplaceManageRequest, MarketplaceManageResult, MarketplaceMcpContentView, MarketplaceMcpDoctorResult, MarketplaceMcpInstallKind, MarketplaceMcpInstallRequest, MarketplaceMcpInstallResult, MarketplaceMcpInstallSpec, MarketplaceMcpManageAction, MarketplaceMcpManageRequest, MarketplaceMcpManageResult, MarketplaceMcpTemplateInput, MarketplacePluginContentView, MarketplacePluginInstallKind, MarketplacePluginInstallRequest, MarketplacePluginInstallResult, MarketplacePluginManageAction, MarketplacePluginManageRequest, MarketplacePluginManageResult, MarketplaceRecommendationView, MarketplaceSceneView, MarketplaceScenesView, MarketplaceSkillContentView, MarketplaceSkillInstallKind, MarketplaceSkillInstallRequest, MarketplaceSkillInstallResult, MarketplaceSkillManageAction, MarketplaceSkillManageRequest, MarketplaceSkillManageResult, MarketplaceSort, NcpAssetRoutesController, 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, RuntimeControlRoutesController, 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, SessionSkillEntryView, SessionTypeDescribeParams, SessionsListView, TavilySearchDepthValue, UiNcpAgent, UiNcpAssetPutView, UiNcpAssetView, UiNcpSessionListView, UiNcpSessionMessagesView, UiNcpSessionService, UiNcpStoredAssetRecord, type UiRemoteAccessHost, type UiRouterOptions, type UiRuntimeControlHost, type UiRuntimeUpdateHost, UiServerEvent, UiServerHandle, buildConfigMeta, buildConfigSchemaView, buildConfigView, createCustomProvider, createUiRouter, deleteCustomProvider, ensureUiBridgeSecret, executeConfigAction, getUiBridgeSecretPath, loadConfigOrDefault, readUiBridgeSecret, startUiServer, testProviderConnection, updateChannel, updateModel, updateProvider, updateRuntime, updateSearch, updateSecrets };
2473
+ 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, ConfigRoutesController, ConfigSchemaResponse, ConfigUiHint, ConfigUiHints, ConfigView, CronActionResult, CronCreateRequest, CronCreateResult, CronEnableRequest, CronJobStateView, CronJobView, CronListView, CronPayloadView, CronRunRequest, CronScheduleView, MarketplaceApiConfig, MarketplaceInstallKind, MarketplaceInstallRequest, MarketplaceInstallResult, MarketplaceInstallSkillParams, MarketplaceInstallSpec, MarketplaceInstalledRecord, MarketplaceInstalledView, MarketplaceInstaller, MarketplaceItemSummary, MarketplaceItemType, MarketplaceItemView, MarketplaceListView, MarketplaceLocalizedTextMap, MarketplaceManageAction, MarketplaceManageRequest, MarketplaceManageResult, MarketplaceMcpContentView, MarketplaceMcpDoctorResult, MarketplaceMcpInstallKind, MarketplaceMcpInstallRequest, MarketplaceMcpInstallResult, MarketplaceMcpInstallSpec, MarketplaceMcpManageAction, MarketplaceMcpManageRequest, MarketplaceMcpManageResult, MarketplaceMcpTemplateInput, MarketplacePluginContentView, MarketplacePluginInstallKind, MarketplacePluginInstallRequest, MarketplacePluginInstallResult, MarketplacePluginManageAction, MarketplacePluginManageRequest, MarketplacePluginManageResult, MarketplaceRecommendationView, MarketplaceSceneView, MarketplaceScenesView, MarketplaceSkillContentView, MarketplaceSkillInstallKind, MarketplaceSkillInstallRequest, MarketplaceSkillInstallResult, MarketplaceSkillManageAction, MarketplaceSkillManageRequest, MarketplaceSkillManageResult, MarketplaceSort, NcpAssetRoutesController, 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, RuntimeControlRoutesController, 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, SessionSkillEntryView, SessionTypeDescribeParams, SessionsListView, TavilySearchDepthValue, UiNcpAssetPutView, UiNcpAssetService, UiNcpAssetView, UiNcpSessionListView, UiNcpSessionMessagesView, UiNcpSessionService, UiNcpStoredAssetRecord, type UiRemoteAccessHost, type UiRouterOptions, type UiRuntimeControlHost, type UiRuntimeUpdateHost, UiServerEvent, UiServerHandle, buildConfigMeta, buildConfigSchemaView, buildConfigView, createCustomProvider, createUiRouter, deleteCustomProvider, ensureUiBridgeSecret, executeConfigAction, getUiBridgeSecretPath, loadConfigOrDefault, readUiBridgeSecret, startUiServer, testProviderConnection, updateChannel, updateModel, updateProvider, updateRuntime, updateSearch, updateSecrets };
package/dist/index.js CHANGED
@@ -8,7 +8,6 @@ import path, { dirname, extname, isAbsolute, join, parse, resolve } from "node:p
8
8
  import { createHash, randomBytes, randomUUID, scryptSync, timingSafeEqual } from "node:crypto";
9
9
  import * as NextclawCore from "@nextclaw/core";
10
10
  import { ConfigSchema, DEFAULT_WORKSPACE_PATH, buildConfigSchema, createAgentProfile, expandHome, findEffectiveAgentProfile, getDataDir, getPackageVersion, getProviderName, hasSecretRef, isSensitiveConfigPath, loadConfig, normalizeThinkingLevels, parseThinkingLevel, probeFeishu, readAgentAvatarContent, removeAgentProfile, resolveEffectiveAgentProfiles, saveConfig, updateAgentProfile } from "@nextclaw/core";
11
- import { mountNcpHttpAgentRoutes } from "@nextclaw/ncp-http-agent-server";
12
11
  import { discoverPluginStatusReport, enablePluginInConfig, mergePluginConfigView, toPluginConfigView } from "@nextclaw/openclaw-compat";
13
12
  import { homedir } from "node:os";
14
13
  import { findBuiltinProviderByName, listBuiltinProviders } from "@nextclaw/runtime";
@@ -65,13 +64,13 @@ async function readJson(req) {
65
64
  return { ok: false };
66
65
  }
67
66
  }
68
- function isRecord(value) {
67
+ function isRecord$1(value) {
69
68
  return typeof value === "object" && value !== null && !Array.isArray(value);
70
69
  }
71
70
  function readErrorMessage(value, fallback) {
72
- if (!isRecord(value)) return fallback;
71
+ if (!isRecord$1(value)) return fallback;
73
72
  const maybeError = value.error;
74
- if (!isRecord(maybeError)) return fallback;
73
+ if (!isRecord$1(maybeError)) return fallback;
75
74
  return typeof maybeError.message === "string" && maybeError.message.trim().length > 0 ? maybeError.message : fallback;
76
75
  }
77
76
  function readNonEmptyString(value) {
@@ -441,6 +440,48 @@ var UiAuthService = class {
441
440
  };
442
441
  };
443
442
  //#endregion
443
+ //#region ../nextclaw-shared/src/types/typed-key.types.ts
444
+ function createTypedKey(id) {
445
+ const normalizedId = id.trim();
446
+ if (!normalizedId) throw new Error("typed key id is required");
447
+ return { id: normalizedId };
448
+ }
449
+ //#endregion
450
+ //#region ../nextclaw-shared/src/configs/event-keys.config.ts
451
+ function createAppEventKey(id) {
452
+ return createTypedKey(id);
453
+ }
454
+ const eventKeys = {
455
+ configUpdated: createAppEventKey("config.updated"),
456
+ channelConfigApplyStatus: createAppEventKey("channel.config.apply-status"),
457
+ sessionUpdated: createAppEventKey("session.updated"),
458
+ sessionRunStatus: createAppEventKey("session.run-status"),
459
+ ncpEvent: createAppEventKey("ncp.event"),
460
+ sessionSummaryUpsert: createAppEventKey("session.summary.upsert"),
461
+ sessionSummaryDelete: createAppEventKey("session.summary.delete"),
462
+ configReloadStarted: createAppEventKey("config.reload.started"),
463
+ configReloadFinished: createAppEventKey("config.reload.finished"),
464
+ error: createAppEventKey("error"),
465
+ connectionOpen: createAppEventKey("connection.open"),
466
+ connectionClose: createAppEventKey("connection.close"),
467
+ connectionError: createAppEventKey("connection.error"),
468
+ runtimeUpdateSnapshot: createAppEventKey("runtime.update.snapshot")
469
+ };
470
+ //#endregion
471
+ //#region ../nextclaw-shared/src/configs/ingress-keys.config.ts
472
+ const ingressKeys = {
473
+ extension: {
474
+ channelConfigGet: createTypedKey("extension.channel.config.get"),
475
+ channelMessageSubmit: createTypedKey("extension.channel.message.submit"),
476
+ response: createTypedKey("extension.response")
477
+ },
478
+ agentRun: {
479
+ send: createTypedKey("agent-run.send"),
480
+ abort: createTypedKey("agent-run.abort"),
481
+ sessionMessageRequest: createTypedKey("agent-run.session-message.request")
482
+ }
483
+ };
484
+ //#endregion
444
485
  //#region src/features/agents/stores/agents.store.ts
445
486
  function listAgents(configPath) {
446
487
  const config = loadConfig(configPath);
@@ -515,34 +556,6 @@ function buildAgentAvatarUrl(agentId, avatar) {
515
556
  if (normalized.startsWith("home://")) return `/api/agents/${encodeURIComponent(agentId)}/avatar`;
516
557
  }
517
558
  //#endregion
518
- //#region ../nextclaw-shared/src/types/typed-key.types.ts
519
- function createTypedKey(id) {
520
- const normalizedId = id.trim();
521
- if (!normalizedId) throw new Error("typed key id is required");
522
- return { id: normalizedId };
523
- }
524
- //#endregion
525
- //#region ../nextclaw-shared/src/configs/event-keys.config.ts
526
- function createAppEventKey(id) {
527
- return createTypedKey(id);
528
- }
529
- const eventKeys = {
530
- configUpdated: createAppEventKey("config.updated"),
531
- channelConfigApplyStatus: createAppEventKey("channel.config.apply-status"),
532
- sessionUpdated: createAppEventKey("session.updated"),
533
- sessionRunStatus: createAppEventKey("session.run-status"),
534
- ncpEvent: createAppEventKey("ncp.event"),
535
- sessionSummaryUpsert: createAppEventKey("session.summary.upsert"),
536
- sessionSummaryDelete: createAppEventKey("session.summary.delete"),
537
- configReloadStarted: createAppEventKey("config.reload.started"),
538
- configReloadFinished: createAppEventKey("config.reload.finished"),
539
- error: createAppEventKey("error"),
540
- connectionOpen: createAppEventKey("connection.open"),
541
- connectionClose: createAppEventKey("connection.close"),
542
- connectionError: createAppEventKey("connection.error"),
543
- runtimeUpdateSnapshot: createAppEventKey("runtime.update.snapshot")
544
- };
545
- //#endregion
546
559
  //#region src/shared/utils/app-events.utils.ts
547
560
  function appEventOptions() {
548
561
  return {
@@ -654,7 +667,7 @@ var AppRoutesController = class {
654
667
  health = (c) => c.json(ok({
655
668
  status: "ok",
656
669
  services: {
657
- ncpAgent: this.options.ncpAgent ? "ready" : "unavailable",
670
+ ncpAgent: "ready",
658
671
  cronService: this.options.cron ? "ready" : "unavailable"
659
672
  }
660
673
  }));
@@ -1453,7 +1466,7 @@ var ConfigRoutesController = class {
1453
1466
  const provider = c.req.param("provider");
1454
1467
  const body = await readJson(c.req.raw);
1455
1468
  if (!body.ok) return c.json(err("INVALID_BODY", "invalid json body"), 400);
1456
- const result = await testProviderConnection(this.options.configPath, provider, body.data, this.options.providers);
1469
+ const result = await testProviderConnection(this.options.configPath, provider, body.data, this.options.kernel.llmProviders);
1457
1470
  if (!result) return c.json(err("NOT_FOUND", `unknown provider: ${provider}`), 404);
1458
1471
  return c.json(ok(result));
1459
1472
  };
@@ -2761,8 +2774,17 @@ var NcpAssetRoutesController = class {
2761
2774
  constructor(options) {
2762
2775
  this.options = options;
2763
2776
  }
2777
+ getAssetApi = () => {
2778
+ const kernel = this.options.kernel;
2779
+ if (!kernel) return;
2780
+ return {
2781
+ put: (input) => kernel.assetStore.putBytes(input),
2782
+ stat: kernel.assetStore.statRecord,
2783
+ resolveContentPath: kernel.assetStore.resolveContentPath
2784
+ };
2785
+ };
2764
2786
  putAssets = async (c) => {
2765
- const assetApi = this.options.ncpAgent?.assetApi;
2787
+ const assetApi = this.getAssetApi();
2766
2788
  if (!assetApi) return c.json(err("NOT_AVAILABLE", "ncp asset api unavailable"), 503);
2767
2789
  let formData;
2768
2790
  try {
@@ -2788,7 +2810,7 @@ var NcpAssetRoutesController = class {
2788
2810
  return c.json(ok(payload));
2789
2811
  };
2790
2812
  getAssetContent = async (c) => {
2791
- const assetApi = this.options.ncpAgent?.assetApi;
2813
+ const assetApi = this.getAssetApi();
2792
2814
  if (!assetApi) return c.json(err("NOT_AVAILABLE", "ncp asset api unavailable"), 503);
2793
2815
  const uri = c.req.query("uri")?.trim();
2794
2816
  if (!uri) return c.json(err("INVALID_URI", "asset uri is required"), 400);
@@ -3638,7 +3660,7 @@ async function loadPluginReadmeFromNpm(spec) {
3638
3660
  if (!response.ok) return null;
3639
3661
  const payload = await response.json();
3640
3662
  const readme = typeof payload.readme === "string" ? payload.readme : "";
3641
- const latest = isRecord(payload["dist-tags"]) && typeof payload["dist-tags"].latest === "string" ? payload["dist-tags"].latest : void 0;
3663
+ const latest = isRecord$1(payload["dist-tags"]) && typeof payload["dist-tags"].latest === "string" ? payload["dist-tags"].latest : void 0;
3642
3664
  const metadata = {
3643
3665
  name: typeof payload.name === "string" ? payload.name : spec,
3644
3666
  version: latest,
@@ -4168,19 +4190,13 @@ var NcpSessionRoutesController = class {
4168
4190
  this.options = options;
4169
4191
  this.sessionSkillsViewBuilder = new SessionSkillsViewBuilder(options);
4170
4192
  }
4193
+ getSessionApi = () => this.options.kernel.ncpSessionApi;
4171
4194
  getSessionTypes = async (c) => {
4172
- const listSessionTypes = this.options.ncpAgent?.listSessionTypes;
4173
- const payload = listSessionTypes ? await listSessionTypes({ describeMode: "observation" }) : {
4174
- defaultType: "native",
4175
- options: [{
4176
- value: "native",
4177
- label: "Native"
4178
- }]
4179
- };
4195
+ const payload = await this.options.kernel.agentRuntimeManager.listSessionTypes({ describeMode: "observation" });
4180
4196
  return c.json(ok(payload));
4181
4197
  };
4182
4198
  listSessions = async (c) => {
4183
- const sessionApi = this.options.sessions;
4199
+ const sessionApi = this.getSessionApi();
4184
4200
  if (!sessionApi) return c.json(err("NOT_AVAILABLE", "ncp session api unavailable"), 503);
4185
4201
  const sessions = await sessionApi.listSessions({ limit: readPositiveInt(c.req.query("limit")) });
4186
4202
  const payload = {
@@ -4190,7 +4206,7 @@ var NcpSessionRoutesController = class {
4190
4206
  return c.json(ok(payload));
4191
4207
  };
4192
4208
  getSession = async (c) => {
4193
- const sessionApi = this.options.sessions;
4209
+ const sessionApi = this.getSessionApi();
4194
4210
  if (!sessionApi) return c.json(err("NOT_AVAILABLE", "ncp session api unavailable"), 503);
4195
4211
  const sessionId = decodeURIComponent(c.req.param("sessionId"));
4196
4212
  const session = await sessionApi.getSession(sessionId);
@@ -4198,7 +4214,7 @@ var NcpSessionRoutesController = class {
4198
4214
  return c.json(ok(session));
4199
4215
  };
4200
4216
  listSessionMessages = async (c) => {
4201
- const sessionApi = this.options.sessions;
4217
+ const sessionApi = this.getSessionApi();
4202
4218
  if (!sessionApi) return c.json(err("NOT_AVAILABLE", "ncp session api unavailable"), 503);
4203
4219
  const sessionId = decodeURIComponent(c.req.param("sessionId"));
4204
4220
  const session = await sessionApi.getSession(sessionId);
@@ -4214,7 +4230,7 @@ var NcpSessionRoutesController = class {
4214
4230
  return c.json(ok(payload));
4215
4231
  };
4216
4232
  getSessionSkills = async (c) => {
4217
- const sessionApi = this.options.sessions;
4233
+ const sessionApi = this.getSessionApi();
4218
4234
  if (!sessionApi) return c.json(err("NOT_AVAILABLE", "ncp session api unavailable"), 503);
4219
4235
  const sessionId = decodeURIComponent(c.req.param("sessionId"));
4220
4236
  const query = c.req.query();
@@ -4237,7 +4253,7 @@ var NcpSessionRoutesController = class {
4237
4253
  })));
4238
4254
  };
4239
4255
  patchSession = async (c) => {
4240
- const sessionApi = this.options.sessions;
4256
+ const sessionApi = this.getSessionApi();
4241
4257
  if (!sessionApi) return c.json(err("NOT_AVAILABLE", "ncp session api unavailable"), 503);
4242
4258
  const sessionId = decodeURIComponent(c.req.param("sessionId"));
4243
4259
  const body = await readJson(c.req.raw);
@@ -4261,7 +4277,7 @@ var NcpSessionRoutesController = class {
4261
4277
  return c.json(ok(updated));
4262
4278
  };
4263
4279
  deleteSession = async (c) => {
4264
- const sessionApi = this.options.sessions;
4280
+ const sessionApi = this.getSessionApi();
4265
4281
  if (!sessionApi) return c.json(err("NOT_AVAILABLE", "ncp session api unavailable"), 503);
4266
4282
  const sessionId = decodeURIComponent(c.req.param("sessionId"));
4267
4283
  if (!await sessionApi.getSession(sessionId)) return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
@@ -4726,13 +4742,7 @@ var ServerPathRoutesController = class {
4726
4742
  };
4727
4743
  //#endregion
4728
4744
  //#region src/app/router.ts
4729
- function readBearerToken(request) {
4730
- const authorization = request.headers.get("authorization")?.trim() ?? "";
4731
- return /^Bearer\s+(.+)$/i.exec(authorization)?.[1]?.trim() || null;
4732
- }
4733
- function isValidIngressEnvelope(value) {
4734
- return typeof value.type === "string" && value.type.trim().length > 0;
4735
- }
4745
+ const NCP_AGENT_BASE_PATH = "/api/ncp/agent";
4736
4746
  function createUiRouteControllers(options, authService, marketplaceBaseUrl) {
4737
4747
  const { remoteAccess, runtimeControl, runtimeUpdate } = options;
4738
4748
  return {
@@ -4752,6 +4762,62 @@ function createUiRouteControllers(options, authService, marketplaceBaseUrl) {
4752
4762
  mcpMarketplace: new McpMarketplaceController(options, marketplaceBaseUrl)
4753
4763
  };
4754
4764
  }
4765
+ function isRecord(value) {
4766
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4767
+ }
4768
+ function hasOwn(value, key) {
4769
+ return Object.prototype.hasOwnProperty.call(value, key);
4770
+ }
4771
+ function isValidSendEnvelope(value) {
4772
+ if (!isRecord(value)) return false;
4773
+ if (hasOwn(value, "sessionId") && (typeof value.sessionId !== "string" || value.sessionId.trim().length === 0)) return false;
4774
+ const hasMessage = hasOwn(value, "message");
4775
+ if (hasMessage === hasOwn(value, "content")) return false;
4776
+ return hasMessage ? isRecord(value.message) : Array.isArray(value.content);
4777
+ }
4778
+ function readStreamPayload(url) {
4779
+ const sessionId = new URL(url).searchParams.get("sessionId")?.trim();
4780
+ return sessionId ? { sessionId } : null;
4781
+ }
4782
+ function isAbortPayload(value) {
4783
+ return isRecord(value) && typeof value.sessionId === "string" && value.sessionId.trim().length > 0;
4784
+ }
4785
+ function toSseFrame(eventName, data) {
4786
+ return `event: ${eventName}\ndata: ${JSON.stringify(data)}\n\n`;
4787
+ }
4788
+ function createNcpEventStreamResponse(events, signal) {
4789
+ const encoder = new TextEncoder();
4790
+ const stream = new ReadableStream({ start: async (controller) => {
4791
+ let closed = false;
4792
+ const close = () => {
4793
+ if (!closed) {
4794
+ closed = true;
4795
+ controller.close();
4796
+ }
4797
+ };
4798
+ signal.addEventListener("abort", close, { once: true });
4799
+ try {
4800
+ for await (const event of events) {
4801
+ if (closed || signal.aborted) break;
4802
+ controller.enqueue(encoder.encode(toSseFrame("ncp-event", event)));
4803
+ }
4804
+ } catch (error) {
4805
+ if (!closed && !signal.aborted) controller.enqueue(encoder.encode(toSseFrame("error", {
4806
+ code: "STREAM_SOURCE_FAILED",
4807
+ message: error instanceof Error ? error.message : String(error)
4808
+ })));
4809
+ } finally {
4810
+ signal.removeEventListener("abort", close);
4811
+ close();
4812
+ }
4813
+ } });
4814
+ return new Response(stream, { headers: {
4815
+ "Content-Type": "text/event-stream; charset=utf-8",
4816
+ "Cache-Control": "no-cache, no-transform",
4817
+ Connection: "keep-alive",
4818
+ "X-Accel-Buffering": "no"
4819
+ } });
4820
+ }
4755
4821
  var UiRouteRegistry = class {
4756
4822
  constructor(app, options, controllers) {
4757
4823
  this.app = app;
@@ -4761,6 +4827,40 @@ var UiRouteRegistry = class {
4761
4827
  mountRoutes = (routes) => {
4762
4828
  for (const [method, path, handler] of routes) this.app[method](path, handler);
4763
4829
  };
4830
+ mountNcpAgentRoutes = (kernel, ncpAsset) => {
4831
+ this.app.post(`${NCP_AGENT_BASE_PATH}/send`, async (c) => {
4832
+ const body = await readJson(c.req.raw);
4833
+ if (!body.ok || !isValidSendEnvelope(body.data)) return c.json(err("INVALID_BODY", "Invalid NCP request envelope."), 400);
4834
+ const handle = await kernel.ingress.handle({
4835
+ type: ingressKeys.agentRun.send,
4836
+ payload: body.data
4837
+ }, { source: "ui-http" });
4838
+ return c.json(ok(handle));
4839
+ });
4840
+ this.app.get(`${NCP_AGENT_BASE_PATH}/stream`, (c) => {
4841
+ const payload = readStreamPayload(c.req.raw.url);
4842
+ if (!payload) return c.json(err("INVALID_QUERY", "sessionId is required."), 400);
4843
+ return createNcpEventStreamResponse(kernel.sessionRunManager.streamSessionEvents(payload, { signal: c.req.raw.signal }), c.req.raw.signal);
4844
+ });
4845
+ this.app.post(`${NCP_AGENT_BASE_PATH}/abort`, async (c) => {
4846
+ const body = await readJson(c.req.raw);
4847
+ if (!body.ok || !isAbortPayload(body.data)) return c.json(err("INVALID_BODY", "sessionId is required."), 400);
4848
+ await kernel.ingress.handle({
4849
+ type: ingressKeys.agentRun.abort,
4850
+ payload: body.data
4851
+ }, { source: "ui-http" });
4852
+ return c.json(ok({ accepted: true }));
4853
+ });
4854
+ this.mountRoutes([[
4855
+ "post",
4856
+ "/api/ncp/assets",
4857
+ ncpAsset.putAssets
4858
+ ], [
4859
+ "get",
4860
+ "/api/ncp/assets/content",
4861
+ ncpAsset.getAssetContent
4862
+ ]]);
4863
+ };
4764
4864
  register = () => {
4765
4865
  const { agents, app, auth, config, cron, ncpAsset, ncpSession, remote, runtimeControl, runtimeUpdate, serverPath } = this.controllers;
4766
4866
  this.mountRoutes([
@@ -4979,23 +5079,7 @@ var UiRouteRegistry = class {
4979
5079
  serverPath.read
4980
5080
  ]
4981
5081
  ]);
4982
- const { ingress, ncpAgent } = this.options;
4983
- if (ncpAgent) {
4984
- mountNcpHttpAgentRoutes(this.app, {
4985
- basePath: ncpAgent.basePath ?? "/api/ncp/agent",
4986
- agentClientEndpoint: ncpAgent.agentClientEndpoint,
4987
- streamProvider: ncpAgent.streamProvider
4988
- });
4989
- this.mountRoutes([[
4990
- "post",
4991
- "/api/ncp/assets",
4992
- ncpAsset.putAssets
4993
- ], [
4994
- "get",
4995
- "/api/ncp/assets/content",
4996
- ncpAsset.getAssetContent
4997
- ]]);
4998
- }
5082
+ this.mountNcpAgentRoutes(this.options.kernel, ncpAsset);
4999
5083
  this.mountRoutes([
5000
5084
  [
5001
5085
  "get",
@@ -5125,13 +5209,13 @@ var UiRouteRegistry = class {
5125
5209
  ]
5126
5210
  ]);
5127
5211
  this.app.post("/webhook", async (c) => {
5128
- if (!ingress) return c.json(err("INGRESS_UNAVAILABLE", "ingress is not configured"), 503);
5212
+ const ingress = this.options.kernel.ingress;
5129
5213
  const body = await readJson(c.req.raw);
5130
- if (!body.ok || !isValidIngressEnvelope(body.data)) return c.json(err("INVALID_BODY", "invalid ingress body"), 400);
5214
+ if (!body.ok) return c.json(err("INVALID_BODY", "invalid ingress body"), 400);
5131
5215
  try {
5132
5216
  const result = await ingress.handle(body.data, {
5133
5217
  source: "webhook",
5134
- token: readBearerToken(c.req.raw)
5218
+ token: /^Bearer\s+(.+)$/i.exec(c.req.raw.headers.get("authorization")?.trim() ?? "")?.[1]?.trim() || null
5135
5219
  });
5136
5220
  return c.json(ok(result ?? { accepted: true }));
5137
5221
  } catch (error) {
@@ -5309,9 +5393,7 @@ async function startUiServer(gateway) {
5309
5393
  close: () => new Promise((resolve) => {
5310
5394
  unsubscribeEventBus();
5311
5395
  wss.close(() => {
5312
- server.close(() => {
5313
- Promise.resolve(gateway.ncpAgent?.agentClientEndpoint.stop()).catch(() => void 0).finally(() => resolve());
5314
- });
5396
+ server.close(() => resolve());
5315
5397
  });
5316
5398
  })
5317
5399
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/server",
3
- "version": "0.12.19",
3
+ "version": "0.12.21",
4
4
  "private": false,
5
5
  "description": "Nextclaw UI/API server.",
6
6
  "type": "module",
@@ -18,13 +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.19",
22
- "@nextclaw/kernel": "0.1.8",
23
- "@nextclaw/ncp": "0.5.12",
24
- "@nextclaw/ncp-http-agent-server": "0.3.24",
25
- "@nextclaw/mcp": "0.1.84",
26
- "@nextclaw/openclaw-compat": "1.0.19",
27
- "@nextclaw/runtime": "0.2.51"
21
+ "@nextclaw/core": "0.12.20",
22
+ "@nextclaw/kernel": "0.1.10",
23
+ "@nextclaw/mcp": "0.1.85",
24
+ "@nextclaw/ncp": "0.5.13",
25
+ "@nextclaw/openclaw-compat": "1.0.20",
26
+ "@nextclaw/runtime": "0.2.52"
28
27
  },
29
28
  "devDependencies": {
30
29
  "@types/node": "^20.17.6",