@nextclaw/server 0.6.13 → 0.8.0

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
@@ -1,6 +1,9 @@
1
1
  import * as NextclawCore from '@nextclaw/core';
2
2
  import { ThinkingLevel, CronService, Config, ConfigActionExecuteRequest as ConfigActionExecuteRequest$1, ConfigActionExecuteResult as ConfigActionExecuteResult$1 } from '@nextclaw/core';
3
+ import { NcpAgentClientEndpoint, NcpSessionApi, NcpSessionSummary, NcpMessage } from '@nextclaw/ncp';
4
+ import { NcpHttpAgentStreamProvider } from '@nextclaw/ncp-http-agent-server';
3
5
  import { Hono } from 'hono';
6
+ import { IncomingMessage } from 'node:http';
4
7
 
5
8
  type ApiError = {
6
9
  code: string;
@@ -133,6 +136,26 @@ type ProviderAuthImportResult = {
133
136
  source: "cli";
134
137
  expiresAt?: string;
135
138
  };
139
+ type AuthStatusView = {
140
+ enabled: boolean;
141
+ configured: boolean;
142
+ authenticated: boolean;
143
+ username?: string;
144
+ };
145
+ type AuthSetupRequest = {
146
+ username: string;
147
+ password: string;
148
+ };
149
+ type AuthLoginRequest = {
150
+ username: string;
151
+ password: string;
152
+ };
153
+ type AuthPasswordUpdateRequest = {
154
+ password: string;
155
+ };
156
+ type AuthEnabledUpdateRequest = {
157
+ enabled: boolean;
158
+ };
136
159
  type AgentProfileView = {
137
160
  id: string;
138
161
  default?: boolean;
@@ -429,6 +452,21 @@ type UiChatRuntime = {
429
452
  listSessionTypes?: () => Promise<ChatSessionTypesView> | ChatSessionTypesView;
430
453
  stopTurn?: (params: ChatTurnStopRequest) => Promise<ChatTurnStopResult> | ChatTurnStopResult;
431
454
  };
455
+ type UiNcpSessionListView = {
456
+ sessions: NcpSessionSummary[];
457
+ total: number;
458
+ };
459
+ type UiNcpSessionMessagesView = {
460
+ sessionId: string;
461
+ messages: NcpMessage[];
462
+ total: number;
463
+ };
464
+ type UiNcpAgent = {
465
+ agentClientEndpoint: NcpAgentClientEndpoint;
466
+ streamProvider?: NcpHttpAgentStreamProvider;
467
+ sessionApi?: NcpSessionApi;
468
+ basePath?: string;
469
+ };
432
470
  type ConfigView = {
433
471
  agents: {
434
472
  defaults: {
@@ -810,6 +848,7 @@ type UiServerOptions = {
810
848
  marketplace?: MarketplaceApiConfig;
811
849
  cronService?: CronService;
812
850
  chatRuntime?: UiChatRuntime;
851
+ ncpAgent?: UiNcpAgent;
813
852
  };
814
853
  type UiServerHandle = {
815
854
  host: string;
@@ -820,6 +859,44 @@ type UiServerHandle = {
820
859
 
821
860
  declare function startUiServer(options: UiServerOptions): UiServerHandle;
822
861
 
862
+ declare class UiAuthService {
863
+ private readonly configPath;
864
+ private readonly sessions;
865
+ constructor(configPath: string);
866
+ private loadCurrentConfig;
867
+ private saveCurrentConfig;
868
+ private readAuthConfig;
869
+ private isConfigured;
870
+ isProtectionEnabled(): boolean;
871
+ private getSessionIdFromCookieHeader;
872
+ private getValidSession;
873
+ isRequestAuthenticated(request: Request): boolean;
874
+ isSocketAuthenticated(request: IncomingMessage): boolean;
875
+ getStatus(request: Request): AuthStatusView;
876
+ private createSession;
877
+ private clearAllSessions;
878
+ private deleteRequestSession;
879
+ private buildLoginCookie;
880
+ buildLogoutCookie(request: Request): string;
881
+ setup(request: Request, payload: AuthSetupRequest): {
882
+ status: AuthStatusView;
883
+ cookie: string;
884
+ };
885
+ login(request: Request, payload: AuthLoginRequest): {
886
+ status: AuthStatusView;
887
+ cookie: string;
888
+ };
889
+ logout(request: Request): void;
890
+ updatePassword(request: Request, payload: AuthPasswordUpdateRequest): {
891
+ status: AuthStatusView;
892
+ cookie?: string;
893
+ };
894
+ updateEnabled(request: Request, payload: AuthEnabledUpdateRequest): {
895
+ status: AuthStatusView;
896
+ cookie?: string;
897
+ };
898
+ }
899
+
823
900
  type UiRouterOptions = {
824
901
  configPath: string;
825
902
  productVersion?: string;
@@ -827,6 +904,8 @@ type UiRouterOptions = {
827
904
  marketplace?: MarketplaceApiConfig;
828
905
  cronService?: InstanceType<typeof NextclawCore.CronService>;
829
906
  chatRuntime?: UiChatRuntime;
907
+ ncpAgent?: UiNcpAgent;
908
+ authService?: UiAuthService;
830
909
  };
831
910
 
832
911
  declare function createUiRouter(options: UiRouterOptions): Hono;
@@ -875,4 +954,4 @@ declare function deleteSession(configPath: string, key: string): boolean;
875
954
  declare function updateRuntime(configPath: string, patch: RuntimeConfigUpdate): Pick<ConfigView, "agents" | "bindings" | "session">;
876
955
  declare function updateSecrets(configPath: string, patch: SecretsConfigUpdate): SecretsView;
877
956
 
878
- export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, type AppMetaView, type BindingPeerView, type BochaFreshnessValue, type ChannelSpecView, type ChatCapabilitiesView, type ChatCommandOptionView, type ChatCommandView, type ChatCommandsView, type ChatRunListView, type ChatRunState, type ChatRunView, type ChatSessionTypeOptionView, type ChatSessionTypesView, type ChatTurnRequest, type ChatTurnResult, type ChatTurnStopRequest, type ChatTurnStopResult, type ChatTurnStreamEvent, type ChatTurnView, type ConfigActionExecuteRequest, type ConfigActionExecuteResult, type ConfigActionManifest, type ConfigActionType, type ConfigMetaView, type ConfigSchemaResponse, type ConfigUiHint, type ConfigUiHints, type ConfigView, type CronActionResult, type CronEnableRequest, type CronJobStateView, type CronJobView, type CronListView, type CronPayloadView, type CronRunRequest, type CronScheduleView, DEFAULT_SESSION_TYPE, type MarketplaceApiConfig, type MarketplaceInstallKind, type MarketplaceInstallSkillParams, type MarketplaceInstallSpec, type MarketplaceInstalledRecord, type MarketplaceInstalledView, type MarketplaceInstaller, type MarketplaceItemSummary, type MarketplaceItemType, type MarketplaceItemView, type MarketplaceListView, type MarketplaceLocalizedTextMap, type MarketplacePluginContentView, type MarketplacePluginInstallKind, type MarketplacePluginInstallRequest, type MarketplacePluginInstallResult, type MarketplacePluginManageAction, type MarketplacePluginManageRequest, type MarketplacePluginManageResult, type MarketplaceRecommendationView, type MarketplaceSkillContentView, type MarketplaceSkillInstallKind, type MarketplaceSkillInstallRequest, type MarketplaceSkillInstallResult, type MarketplaceSkillManageAction, type MarketplaceSkillManageRequest, type MarketplaceSkillManageResult, type MarketplaceSort, type ProviderAuthImportResult, type ProviderAuthPollRequest, type ProviderAuthPollResult, type ProviderAuthStartRequest, type ProviderAuthStartResult, type ProviderConfigUpdate, type ProviderConfigView, type ProviderConnectionTestRequest, type ProviderConnectionTestResult, type ProviderCreateRequest, type ProviderCreateResult, type ProviderDeleteResult, type ProviderSpecView, type RuntimeConfigUpdate, type SearchConfigUpdate, type SearchConfigView, type SearchProviderConfigView, type SearchProviderName, type SearchProviderSpecView, type SecretProviderEnvView, type SecretProviderExecView, type SecretProviderFileView, type SecretProviderView, type SecretRefView, type SecretSourceView, type SecretsConfigUpdate, type SecretsView, type SessionConfigView, type SessionEntryView, type SessionEventView, type SessionHistoryView, type SessionMessageView, type SessionPatchUpdate, SessionPatchValidationError, type SessionsListView, type UiChatRuntime, type UiServerEvent, type UiServerHandle, type UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createCustomProvider, createUiRouter, deleteCustomProvider, deleteSession, executeConfigAction, getSessionHistory, listSessions, loadConfigOrDefault, patchSession, startUiServer, testProviderConnection, updateChannel, updateModel, updateProvider, updateRuntime, updateSearch, updateSecrets };
957
+ export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, type AppMetaView, type AuthEnabledUpdateRequest, type AuthLoginRequest, type AuthPasswordUpdateRequest, type AuthSetupRequest, type AuthStatusView, type BindingPeerView, type BochaFreshnessValue, type ChannelSpecView, type ChatCapabilitiesView, type ChatCommandOptionView, type ChatCommandView, type ChatCommandsView, type ChatRunListView, type ChatRunState, type ChatRunView, type ChatSessionTypeOptionView, type ChatSessionTypesView, type ChatTurnRequest, type ChatTurnResult, type ChatTurnStopRequest, type ChatTurnStopResult, type ChatTurnStreamEvent, type ChatTurnView, type ConfigActionExecuteRequest, type ConfigActionExecuteResult, type ConfigActionManifest, type ConfigActionType, type ConfigMetaView, type ConfigSchemaResponse, type ConfigUiHint, type ConfigUiHints, type ConfigView, type CronActionResult, type CronEnableRequest, type CronJobStateView, type CronJobView, type CronListView, type CronPayloadView, type CronRunRequest, type CronScheduleView, DEFAULT_SESSION_TYPE, type MarketplaceApiConfig, type MarketplaceInstallKind, type MarketplaceInstallSkillParams, type MarketplaceInstallSpec, type MarketplaceInstalledRecord, type MarketplaceInstalledView, type MarketplaceInstaller, type MarketplaceItemSummary, type MarketplaceItemType, type MarketplaceItemView, type MarketplaceListView, type MarketplaceLocalizedTextMap, type MarketplacePluginContentView, type MarketplacePluginInstallKind, type MarketplacePluginInstallRequest, type MarketplacePluginInstallResult, type MarketplacePluginManageAction, type MarketplacePluginManageRequest, type MarketplacePluginManageResult, type MarketplaceRecommendationView, type MarketplaceSkillContentView, type MarketplaceSkillInstallKind, type MarketplaceSkillInstallRequest, type MarketplaceSkillInstallResult, type MarketplaceSkillManageAction, type MarketplaceSkillManageRequest, type MarketplaceSkillManageResult, type MarketplaceSort, type ProviderAuthImportResult, type ProviderAuthPollRequest, type ProviderAuthPollResult, type ProviderAuthStartRequest, type ProviderAuthStartResult, type ProviderConfigUpdate, type ProviderConfigView, type ProviderConnectionTestRequest, type ProviderConnectionTestResult, type ProviderCreateRequest, type ProviderCreateResult, type ProviderDeleteResult, type ProviderSpecView, type RuntimeConfigUpdate, type SearchConfigUpdate, type SearchConfigView, type SearchProviderConfigView, type SearchProviderName, type SearchProviderSpecView, type SecretProviderEnvView, type SecretProviderExecView, type SecretProviderFileView, type SecretProviderView, type SecretRefView, type SecretSourceView, type SecretsConfigUpdate, type SecretsView, type SessionConfigView, type SessionEntryView, type SessionEventView, type SessionHistoryView, type SessionMessageView, type SessionPatchUpdate, SessionPatchValidationError, type SessionsListView, type UiChatRuntime, type UiNcpAgent, type UiNcpSessionListView, type UiNcpSessionMessagesView, type UiServerEvent, type UiServerHandle, type UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createCustomProvider, createUiRouter, deleteCustomProvider, deleteSession, executeConfigAction, getSessionHistory, listSessions, loadConfigOrDefault, patchSession, startUiServer, testProviderConnection, updateChannel, updateModel, updateProvider, updateRuntime, updateSearch, updateSecrets };
package/dist/index.js CHANGED
@@ -8,8 +8,319 @@ import { existsSync, readFileSync } from "fs";
8
8
  import { readFile as readFile2, stat } from "fs/promises";
9
9
  import { join } from "path";
10
10
 
11
+ // src/ui/auth.service.ts
12
+ import { ConfigSchema, loadConfig, saveConfig } from "@nextclaw/core";
13
+ import { randomBytes, randomUUID, scryptSync, timingSafeEqual } from "crypto";
14
+ var SESSION_COOKIE_NAME = "nextclaw_ui_session";
15
+ var PASSWORD_MIN_LENGTH = 8;
16
+ function normalizeUsername(value) {
17
+ return value.trim();
18
+ }
19
+ function parseCookieHeader(rawHeader) {
20
+ if (!rawHeader) {
21
+ return {};
22
+ }
23
+ const cookies = {};
24
+ for (const chunk of rawHeader.split(";")) {
25
+ const [rawKey, ...rawValue] = chunk.split("=");
26
+ const key = rawKey?.trim();
27
+ if (!key) {
28
+ continue;
29
+ }
30
+ cookies[key] = decodeURIComponent(rawValue.join("=").trim());
31
+ }
32
+ return cookies;
33
+ }
34
+ function buildSetCookie(params) {
35
+ const parts = [
36
+ `${SESSION_COOKIE_NAME}=${encodeURIComponent(params.value)}`,
37
+ "Path=/",
38
+ "HttpOnly",
39
+ "SameSite=Lax"
40
+ ];
41
+ if (params.secure) {
42
+ parts.push("Secure");
43
+ }
44
+ if (typeof params.maxAgeSeconds === "number") {
45
+ parts.push(`Max-Age=${Math.max(0, Math.trunc(params.maxAgeSeconds))}`);
46
+ }
47
+ if (params.expires) {
48
+ parts.push(`Expires=${params.expires}`);
49
+ }
50
+ return parts.join("; ");
51
+ }
52
+ function resolveSecureRequest(url, protocolHint) {
53
+ if (protocolHint?.trim().toLowerCase() === "https") {
54
+ return true;
55
+ }
56
+ try {
57
+ return new URL(url).protocol === "https:";
58
+ } catch {
59
+ return false;
60
+ }
61
+ }
62
+ function hashPassword(password, salt) {
63
+ return scryptSync(password, salt, 64).toString("hex");
64
+ }
65
+ function verifyPassword(password, expectedHash, salt) {
66
+ const actualHashBuffer = Buffer.from(hashPassword(password, salt), "hex");
67
+ const expectedHashBuffer = Buffer.from(expectedHash, "hex");
68
+ if (actualHashBuffer.length !== expectedHashBuffer.length) {
69
+ return false;
70
+ }
71
+ return timingSafeEqual(actualHashBuffer, expectedHashBuffer);
72
+ }
73
+ function createPasswordRecord(password) {
74
+ const passwordSalt = randomBytes(16).toString("hex");
75
+ return {
76
+ passwordHash: hashPassword(password, passwordSalt),
77
+ passwordSalt
78
+ };
79
+ }
80
+ function validateUsernameAndPassword(username, password) {
81
+ if (!username) {
82
+ throw new Error("Username is required.");
83
+ }
84
+ if (password.trim().length < PASSWORD_MIN_LENGTH) {
85
+ throw new Error(`Password must be at least ${PASSWORD_MIN_LENGTH} characters.`);
86
+ }
87
+ }
88
+ var UiAuthService = class {
89
+ constructor(configPath) {
90
+ this.configPath = configPath;
91
+ }
92
+ sessions = /* @__PURE__ */ new Map();
93
+ loadCurrentConfig() {
94
+ return loadConfig(this.configPath);
95
+ }
96
+ saveCurrentConfig(config) {
97
+ saveConfig(ConfigSchema.parse(config), this.configPath);
98
+ }
99
+ readAuthConfig() {
100
+ return this.loadCurrentConfig().ui.auth;
101
+ }
102
+ isConfigured(auth) {
103
+ return Boolean(
104
+ normalizeUsername(auth.username).length > 0 && auth.passwordHash.trim().length > 0 && auth.passwordSalt.trim().length > 0
105
+ );
106
+ }
107
+ isProtectionEnabled() {
108
+ const auth = this.readAuthConfig();
109
+ return Boolean(auth.enabled && this.isConfigured(auth));
110
+ }
111
+ getSessionIdFromCookieHeader(rawCookieHeader) {
112
+ const cookies = parseCookieHeader(rawCookieHeader);
113
+ const sessionId = cookies[SESSION_COOKIE_NAME];
114
+ return sessionId?.trim() ? sessionId.trim() : null;
115
+ }
116
+ getValidSession(sessionId, username) {
117
+ if (!sessionId) {
118
+ return null;
119
+ }
120
+ const session = this.sessions.get(sessionId);
121
+ if (!session || session.username !== username) {
122
+ return null;
123
+ }
124
+ return session;
125
+ }
126
+ isRequestAuthenticated(request) {
127
+ const auth = this.readAuthConfig();
128
+ if (!auth.enabled || !this.isConfigured(auth)) {
129
+ return true;
130
+ }
131
+ const username = normalizeUsername(auth.username);
132
+ const sessionId = this.getSessionIdFromCookieHeader(request.headers.get("cookie"));
133
+ return Boolean(this.getValidSession(sessionId, username));
134
+ }
135
+ isSocketAuthenticated(request) {
136
+ const auth = this.readAuthConfig();
137
+ if (!auth.enabled || !this.isConfigured(auth)) {
138
+ return true;
139
+ }
140
+ const username = normalizeUsername(auth.username);
141
+ const rawCookieHeader = Array.isArray(request.headers.cookie) ? request.headers.cookie.join("; ") : request.headers.cookie;
142
+ const sessionId = this.getSessionIdFromCookieHeader(rawCookieHeader);
143
+ return Boolean(this.getValidSession(sessionId, username));
144
+ }
145
+ getStatus(request) {
146
+ const auth = this.readAuthConfig();
147
+ const configured = this.isConfigured(auth);
148
+ const enabled = Boolean(auth.enabled && configured);
149
+ const username = configured ? normalizeUsername(auth.username) : void 0;
150
+ return {
151
+ enabled,
152
+ configured,
153
+ authenticated: enabled ? this.isRequestAuthenticated(request) : false,
154
+ ...username ? { username } : {}
155
+ };
156
+ }
157
+ createSession(username) {
158
+ const sessionId = randomUUID();
159
+ this.sessions.set(sessionId, {
160
+ sessionId,
161
+ username,
162
+ createdAt: Date.now()
163
+ });
164
+ return sessionId;
165
+ }
166
+ clearAllSessions() {
167
+ this.sessions.clear();
168
+ }
169
+ deleteRequestSession(request) {
170
+ const sessionId = this.getSessionIdFromCookieHeader(request.headers.get("cookie"));
171
+ if (!sessionId) {
172
+ return;
173
+ }
174
+ this.sessions.delete(sessionId);
175
+ }
176
+ buildLoginCookie(request, sessionId) {
177
+ return buildSetCookie({
178
+ value: sessionId,
179
+ secure: resolveSecureRequest(request.url, request.headers.get("x-forwarded-proto"))
180
+ });
181
+ }
182
+ buildLogoutCookie(request) {
183
+ return buildSetCookie({
184
+ value: "",
185
+ secure: resolveSecureRequest(request.url, request.headers.get("x-forwarded-proto")),
186
+ maxAgeSeconds: 0,
187
+ expires: (/* @__PURE__ */ new Date(0)).toUTCString()
188
+ });
189
+ }
190
+ setup(request, payload) {
191
+ const config = this.loadCurrentConfig();
192
+ const currentAuth = config.ui.auth;
193
+ if (this.isConfigured(currentAuth)) {
194
+ throw new Error("UI authentication is already configured.");
195
+ }
196
+ const username = normalizeUsername(payload.username);
197
+ const password = payload.password;
198
+ validateUsernameAndPassword(username, password);
199
+ const nextPassword = createPasswordRecord(password);
200
+ config.ui.auth = {
201
+ enabled: true,
202
+ username,
203
+ ...nextPassword
204
+ };
205
+ this.saveCurrentConfig(config);
206
+ this.clearAllSessions();
207
+ const sessionId = this.createSession(username);
208
+ return {
209
+ status: {
210
+ enabled: true,
211
+ configured: true,
212
+ authenticated: true,
213
+ username
214
+ },
215
+ cookie: this.buildLoginCookie(request, sessionId)
216
+ };
217
+ }
218
+ login(request, payload) {
219
+ const auth = this.readAuthConfig();
220
+ if (!auth.enabled || !this.isConfigured(auth)) {
221
+ throw new Error("UI authentication is not enabled.");
222
+ }
223
+ const username = normalizeUsername(payload.username);
224
+ if (username !== normalizeUsername(auth.username) || !verifyPassword(payload.password, auth.passwordHash, auth.passwordSalt)) {
225
+ throw new Error("Invalid username or password.");
226
+ }
227
+ const sessionId = this.createSession(username);
228
+ return {
229
+ status: {
230
+ enabled: true,
231
+ configured: true,
232
+ authenticated: true,
233
+ username
234
+ },
235
+ cookie: this.buildLoginCookie(request, sessionId)
236
+ };
237
+ }
238
+ logout(request) {
239
+ this.deleteRequestSession(request);
240
+ }
241
+ updatePassword(request, payload) {
242
+ const config = this.loadCurrentConfig();
243
+ const auth = config.ui.auth;
244
+ if (!this.isConfigured(auth)) {
245
+ throw new Error("UI authentication is not configured.");
246
+ }
247
+ if (auth.enabled && !this.isRequestAuthenticated(request)) {
248
+ throw new Error("Authentication required.");
249
+ }
250
+ validateUsernameAndPassword(normalizeUsername(auth.username), payload.password);
251
+ const nextPassword = createPasswordRecord(payload.password);
252
+ config.ui.auth = {
253
+ ...auth,
254
+ ...nextPassword
255
+ };
256
+ this.saveCurrentConfig(config);
257
+ this.clearAllSessions();
258
+ if (!auth.enabled) {
259
+ return {
260
+ status: {
261
+ enabled: false,
262
+ configured: true,
263
+ authenticated: false,
264
+ username: normalizeUsername(auth.username)
265
+ }
266
+ };
267
+ }
268
+ const sessionId = this.createSession(normalizeUsername(auth.username));
269
+ return {
270
+ status: {
271
+ enabled: true,
272
+ configured: true,
273
+ authenticated: true,
274
+ username: normalizeUsername(auth.username)
275
+ },
276
+ cookie: this.buildLoginCookie(request, sessionId)
277
+ };
278
+ }
279
+ updateEnabled(request, payload) {
280
+ const config = this.loadCurrentConfig();
281
+ const auth = config.ui.auth;
282
+ const configured = this.isConfigured(auth);
283
+ const currentlyEnabled = Boolean(auth.enabled && configured);
284
+ if (currentlyEnabled && !this.isRequestAuthenticated(request)) {
285
+ throw new Error("Authentication required.");
286
+ }
287
+ if (payload.enabled && !configured) {
288
+ throw new Error("UI authentication must be configured before it can be enabled.");
289
+ }
290
+ config.ui.auth = {
291
+ ...auth,
292
+ enabled: Boolean(payload.enabled)
293
+ };
294
+ this.saveCurrentConfig(config);
295
+ if (!payload.enabled) {
296
+ this.clearAllSessions();
297
+ return {
298
+ status: {
299
+ enabled: false,
300
+ configured,
301
+ authenticated: false,
302
+ ...configured ? { username: normalizeUsername(auth.username) } : {}
303
+ },
304
+ cookie: this.buildLogoutCookie(request)
305
+ };
306
+ }
307
+ const username = normalizeUsername(auth.username);
308
+ const sessionId = this.createSession(username);
309
+ return {
310
+ status: {
311
+ enabled: true,
312
+ configured: true,
313
+ authenticated: true,
314
+ username
315
+ },
316
+ cookie: this.buildLoginCookie(request, sessionId)
317
+ };
318
+ }
319
+ };
320
+
11
321
  // src/ui/router.ts
12
322
  import { Hono } from "hono";
323
+ import { mountNcpHttpAgentRoutes } from "@nextclaw/ncp-http-agent-server";
13
324
 
14
325
  // src/ui/router/response.ts
15
326
  function ok(data) {
@@ -82,14 +393,115 @@ var AppRoutesController = class {
82
393
  appMeta = (c) => c.json(ok(buildAppMetaView(this.options)));
83
394
  };
84
395
 
396
+ // src/ui/router/auth.controller.ts
397
+ function isAuthenticationRequiredError(message) {
398
+ return message === "Authentication required.";
399
+ }
400
+ function isConflictError(message) {
401
+ return message.includes("already configured");
402
+ }
403
+ function setCookieHeader(c, cookie) {
404
+ if (!cookie) {
405
+ return;
406
+ }
407
+ c.header("Set-Cookie", cookie);
408
+ }
409
+ var AuthRoutesController = class {
410
+ constructor(authService) {
411
+ this.authService = authService;
412
+ }
413
+ getStatus = (c) => {
414
+ return c.json(ok(this.authService.getStatus(c.req.raw)));
415
+ };
416
+ setup = async (c) => {
417
+ const body = await readJson(c.req.raw);
418
+ if (!body.ok) {
419
+ return c.json(err("INVALID_BODY", "invalid json body"), 400);
420
+ }
421
+ if (typeof body.data.username !== "string" || typeof body.data.password !== "string") {
422
+ return c.json(err("INVALID_BODY", "username and password are required"), 400);
423
+ }
424
+ try {
425
+ const result = this.authService.setup(c.req.raw, body.data);
426
+ setCookieHeader(c, result.cookie);
427
+ return c.json(ok(result.status), 201);
428
+ } catch (error) {
429
+ const message = error instanceof Error ? error.message : String(error);
430
+ return c.json(err(isConflictError(message) ? "AUTH_ALREADY_CONFIGURED" : "INVALID_BODY", message), isConflictError(message) ? 409 : 400);
431
+ }
432
+ };
433
+ login = async (c) => {
434
+ const body = await readJson(c.req.raw);
435
+ if (!body.ok) {
436
+ return c.json(err("INVALID_BODY", "invalid json body"), 400);
437
+ }
438
+ if (typeof body.data.username !== "string" || typeof body.data.password !== "string") {
439
+ return c.json(err("INVALID_BODY", "username and password are required"), 400);
440
+ }
441
+ try {
442
+ const result = this.authService.login(c.req.raw, body.data);
443
+ setCookieHeader(c, result.cookie);
444
+ return c.json(ok(result.status));
445
+ } catch (error) {
446
+ const message = error instanceof Error ? error.message : String(error);
447
+ const code = message === "Invalid username or password." ? "INVALID_CREDENTIALS" : "AUTH_NOT_ENABLED";
448
+ const status = message === "Invalid username or password." ? 401 : 400;
449
+ return c.json(err(code, message), status);
450
+ }
451
+ };
452
+ logout = (c) => {
453
+ this.authService.logout(c.req.raw);
454
+ setCookieHeader(c, this.authService.buildLogoutCookie(c.req.raw));
455
+ return c.json(ok({ success: true }));
456
+ };
457
+ updatePassword = async (c) => {
458
+ const body = await readJson(c.req.raw);
459
+ if (!body.ok) {
460
+ return c.json(err("INVALID_BODY", "invalid json body"), 400);
461
+ }
462
+ if (typeof body.data.password !== "string") {
463
+ return c.json(err("INVALID_BODY", "password is required"), 400);
464
+ }
465
+ try {
466
+ const result = this.authService.updatePassword(c.req.raw, body.data);
467
+ setCookieHeader(c, result.cookie);
468
+ return c.json(ok(result.status));
469
+ } catch (error) {
470
+ const message = error instanceof Error ? error.message : String(error);
471
+ const status = isAuthenticationRequiredError(message) ? 401 : 400;
472
+ const code = isAuthenticationRequiredError(message) ? "UNAUTHORIZED" : "INVALID_BODY";
473
+ return c.json(err(code, message), status);
474
+ }
475
+ };
476
+ updateEnabled = async (c) => {
477
+ const body = await readJson(c.req.raw);
478
+ if (!body.ok) {
479
+ return c.json(err("INVALID_BODY", "invalid json body"), 400);
480
+ }
481
+ if (typeof body.data.enabled !== "boolean") {
482
+ return c.json(err("INVALID_BODY", "enabled is required"), 400);
483
+ }
484
+ try {
485
+ const result = this.authService.updateEnabled(c.req.raw, body.data);
486
+ setCookieHeader(c, result.cookie);
487
+ return c.json(ok(result.status));
488
+ } catch (error) {
489
+ const message = error instanceof Error ? error.message : String(error);
490
+ const status = isAuthenticationRequiredError(message) ? 401 : 400;
491
+ const code = isAuthenticationRequiredError(message) ? "UNAUTHORIZED" : "INVALID_BODY";
492
+ return c.json(err(code, message), status);
493
+ }
494
+ };
495
+ };
496
+
85
497
  // src/ui/router/chat.controller.ts
86
498
  import * as NextclawCore2 from "@nextclaw/core";
87
499
 
88
500
  // src/ui/config.ts
89
501
  import {
90
- loadConfig,
91
- saveConfig,
92
- ConfigSchema,
502
+ loadConfig as loadConfig2,
503
+ saveConfig as saveConfig2,
504
+ ConfigSchema as ConfigSchema2,
93
505
  probeFeishu,
94
506
  LiteLLMProvider,
95
507
  buildConfigSchema,
@@ -432,7 +844,7 @@ function resolveRuntimeConfig(config, draftConfig) {
432
844
  return config;
433
845
  }
434
846
  const merged = deepMerge(config, draftConfig);
435
- return ConfigSchema.parse(merged);
847
+ return ConfigSchema2.parse(merged);
436
848
  }
437
849
  function getActionById(config, actionId) {
438
850
  const actions = buildConfigSchemaView(config).actions;
@@ -783,15 +1195,15 @@ async function executeConfigAction(configPath, actionId, request) {
783
1195
  };
784
1196
  }
785
1197
  function loadConfigOrDefault(configPath) {
786
- return loadConfig(configPath);
1198
+ return loadConfig2(configPath);
787
1199
  }
788
1200
  function updateModel(configPath, patch) {
789
1201
  const config = loadConfigOrDefault(configPath);
790
1202
  if (typeof patch.model === "string") {
791
1203
  config.agents.defaults.model = patch.model;
792
1204
  }
793
- const next = ConfigSchema.parse(config);
794
- saveConfig(next, configPath);
1205
+ const next = ConfigSchema2.parse(config);
1206
+ saveConfig2(next, configPath);
795
1207
  return buildConfigView(next);
796
1208
  }
797
1209
  function updateSearch(configPath, patch) {
@@ -844,8 +1256,8 @@ function updateSearch(configPath, patch) {
844
1256
  config.search.providers.brave.baseUrl = normalizeOptionalString(bravePatch.baseUrl) ?? "https://api.search.brave.com/res/v1/web/search";
845
1257
  }
846
1258
  }
847
- const next = ConfigSchema.parse(config);
848
- saveConfig(next, configPath);
1259
+ const next = ConfigSchema2.parse(config);
1260
+ saveConfig2(next, configPath);
849
1261
  return buildSearchView(next);
850
1262
  }
851
1263
  function updateProvider(configPath, providerName, patch) {
@@ -878,8 +1290,8 @@ function updateProvider(configPath, providerName, patch) {
878
1290
  if (Object.prototype.hasOwnProperty.call(patch, "modelThinking")) {
879
1291
  provider.modelThinking = normalizeModelThinkingConfig(patch.modelThinking ?? {});
880
1292
  }
881
- const next = ConfigSchema.parse(config);
882
- saveConfig(next, configPath);
1293
+ const next = ConfigSchema2.parse(config);
1294
+ saveConfig2(next, configPath);
883
1295
  const uiHints = buildUiHints(next);
884
1296
  const updated = next.providers[providerName];
885
1297
  return toProviderView(next, updated, providerName, uiHints, spec ?? void 0);
@@ -898,8 +1310,8 @@ function createCustomProvider(configPath, patch = {}) {
898
1310
  models: normalizeModelList(patch.models ?? []),
899
1311
  modelThinking: normalizeModelThinkingConfig(patch.modelThinking ?? {})
900
1312
  };
901
- const next = ConfigSchema.parse(config);
902
- saveConfig(next, configPath);
1313
+ const next = ConfigSchema2.parse(config);
1314
+ saveConfig2(next, configPath);
903
1315
  const uiHints = buildUiHints(next);
904
1316
  const created = next.providers[providerName];
905
1317
  return {
@@ -918,8 +1330,8 @@ function deleteCustomProvider(configPath, providerName) {
918
1330
  }
919
1331
  delete providers[providerName];
920
1332
  clearSecretRefsByPrefix(config, `providers.${providerName}`);
921
- const next = ConfigSchema.parse(config);
922
- saveConfig(next, configPath);
1333
+ const next = ConfigSchema2.parse(config);
1334
+ saveConfig2(next, configPath);
923
1335
  return true;
924
1336
  }
925
1337
  function normalizeOptionalString(value) {
@@ -1069,8 +1481,8 @@ function updateChannel(configPath, channelName, patch) {
1069
1481
  }
1070
1482
  }
1071
1483
  config.channels[channelName] = { ...channel, ...patch };
1072
- const next = ConfigSchema.parse(config);
1073
- saveConfig(next, configPath);
1484
+ const next = ConfigSchema2.parse(config);
1485
+ saveConfig2(next, configPath);
1074
1486
  const uiHints = buildUiHints(next);
1075
1487
  return sanitizePublicConfigValue(
1076
1488
  next.channels[channelName],
@@ -1356,8 +1768,8 @@ function updateRuntime(configPath, patch) {
1356
1768
  agentToAgent: nextAgentToAgent
1357
1769
  };
1358
1770
  }
1359
- const next = ConfigSchema.parse(config);
1360
- saveConfig(next, configPath);
1771
+ const next = ConfigSchema2.parse(config);
1772
+ saveConfig2(next, configPath);
1361
1773
  const view = buildConfigView(next);
1362
1774
  return {
1363
1775
  agents: view.agents,
@@ -1391,8 +1803,8 @@ function updateSecrets(configPath, patch) {
1391
1803
  if (Object.prototype.hasOwnProperty.call(patch, "refs")) {
1392
1804
  config.secrets.refs = patch.refs ?? {};
1393
1805
  }
1394
- const next = ConfigSchema.parse(config);
1395
- saveConfig(next, configPath);
1806
+ const next = ConfigSchema2.parse(config);
1807
+ saveConfig2(next, configPath);
1396
1808
  return {
1397
1809
  enabled: next.secrets.enabled,
1398
1810
  defaults: { ...next.secrets.defaults },
@@ -1998,14 +2410,14 @@ var ChatRoutesController = class {
1998
2410
  };
1999
2411
 
2000
2412
  // src/ui/provider-auth.ts
2001
- import { createHash, randomBytes, randomUUID } from "crypto";
2413
+ import { createHash, randomBytes as randomBytes2, randomUUID as randomUUID2 } from "crypto";
2002
2414
  import { readFile } from "fs/promises";
2003
2415
  import { homedir } from "os";
2004
2416
  import { isAbsolute, resolve } from "path";
2005
2417
  import {
2006
- ConfigSchema as ConfigSchema2,
2007
- loadConfig as loadConfig2,
2008
- saveConfig as saveConfig2
2418
+ ConfigSchema as ConfigSchema3,
2419
+ loadConfig as loadConfig3,
2420
+ saveConfig as saveConfig3
2009
2421
  } from "@nextclaw/core";
2010
2422
  var authSessions = /* @__PURE__ */ new Map();
2011
2423
  var DEFAULT_AUTH_INTERVAL_MS = 2e3;
@@ -2026,7 +2438,7 @@ function toBase64Url(buffer) {
2026
2438
  return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
2027
2439
  }
2028
2440
  function buildPkce() {
2029
- const verifier = toBase64Url(randomBytes(48));
2441
+ const verifier = toBase64Url(randomBytes2(48));
2030
2442
  const challenge = toBase64Url(createHash("sha256").update(verifier).digest());
2031
2443
  return { verifier, challenge };
2032
2444
  }
@@ -2199,7 +2611,7 @@ function readFieldAsString(source, fieldName) {
2199
2611
  return trimmed.length > 0 ? trimmed : null;
2200
2612
  }
2201
2613
  function setProviderApiKey(params) {
2202
- const config = loadConfig2(params.configPath);
2614
+ const config = loadConfig3(params.configPath);
2203
2615
  const providers = config.providers;
2204
2616
  if (!providers[params.provider]) {
2205
2617
  providers[params.provider] = {
@@ -2217,8 +2629,8 @@ function setProviderApiKey(params) {
2217
2629
  if (!target.apiBase && params.defaultApiBase) {
2218
2630
  target.apiBase = params.defaultApiBase;
2219
2631
  }
2220
- const next = ConfigSchema2.parse(config);
2221
- saveConfig2(next, params.configPath);
2632
+ const next = ConfigSchema3.parse(config);
2633
+ saveConfig3(next, params.configPath);
2222
2634
  }
2223
2635
  async function startProviderAuth(configPath, providerName, options) {
2224
2636
  cleanupExpiredAuthSessions();
@@ -2243,7 +2655,7 @@ async function startProviderAuth(configPath, providerName, options) {
2243
2655
  if (!pkce) {
2244
2656
  throw new Error("MiniMax OAuth requires PKCE");
2245
2657
  }
2246
- const state = toBase64Url(randomBytes(16));
2658
+ const state = toBase64Url(randomBytes2(16));
2247
2659
  const body = new URLSearchParams({
2248
2660
  response_type: "code",
2249
2661
  client_id: resolvedMethod.clientId,
@@ -2257,7 +2669,7 @@ async function startProviderAuth(configPath, providerName, options) {
2257
2669
  headers: {
2258
2670
  "Content-Type": "application/x-www-form-urlencoded",
2259
2671
  Accept: "application/json",
2260
- "x-request-id": randomUUID()
2672
+ "x-request-id": randomUUID2()
2261
2673
  },
2262
2674
  body
2263
2675
  });
@@ -2309,7 +2721,7 @@ async function startProviderAuth(configPath, providerName, options) {
2309
2721
  const expiresInSec = normalizePositiveInt(payload.expires_in, 600);
2310
2722
  expiresAtMs = Date.now() + expiresInSec * 1e3;
2311
2723
  }
2312
- const sessionId = randomUUID();
2724
+ const sessionId = randomUUID2();
2313
2725
  authSessions.set(sessionId, {
2314
2726
  sessionId,
2315
2727
  provider: providerName,
@@ -2856,6 +3268,83 @@ var CronRoutesController = class {
2856
3268
  };
2857
3269
  };
2858
3270
 
3271
+ // src/ui/router/ncp-session.controller.ts
3272
+ function readPositiveInt(value) {
3273
+ if (typeof value !== "string") {
3274
+ return void 0;
3275
+ }
3276
+ const parsed = Number.parseInt(value, 10);
3277
+ if (!Number.isFinite(parsed) || parsed <= 0) {
3278
+ return void 0;
3279
+ }
3280
+ return parsed;
3281
+ }
3282
+ var NcpSessionRoutesController = class {
3283
+ constructor(options) {
3284
+ this.options = options;
3285
+ }
3286
+ listSessions = async (c) => {
3287
+ const sessionApi = this.options.ncpAgent?.sessionApi;
3288
+ if (!sessionApi) {
3289
+ return c.json(err("NOT_AVAILABLE", "ncp session api unavailable"), 503);
3290
+ }
3291
+ const sessions = await sessionApi.listSessions({
3292
+ limit: readPositiveInt(c.req.query("limit"))
3293
+ });
3294
+ const payload = {
3295
+ sessions,
3296
+ total: sessions.length
3297
+ };
3298
+ return c.json(ok(payload));
3299
+ };
3300
+ getSession = async (c) => {
3301
+ const sessionApi = this.options.ncpAgent?.sessionApi;
3302
+ if (!sessionApi) {
3303
+ return c.json(err("NOT_AVAILABLE", "ncp session api unavailable"), 503);
3304
+ }
3305
+ const sessionId = decodeURIComponent(c.req.param("sessionId"));
3306
+ const session = await sessionApi.getSession(sessionId);
3307
+ if (!session) {
3308
+ return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
3309
+ }
3310
+ return c.json(ok(session));
3311
+ };
3312
+ listSessionMessages = async (c) => {
3313
+ const sessionApi = this.options.ncpAgent?.sessionApi;
3314
+ if (!sessionApi) {
3315
+ return c.json(err("NOT_AVAILABLE", "ncp session api unavailable"), 503);
3316
+ }
3317
+ const sessionId = decodeURIComponent(c.req.param("sessionId"));
3318
+ const session = await sessionApi.getSession(sessionId);
3319
+ if (!session) {
3320
+ return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
3321
+ }
3322
+ const messages = await sessionApi.listSessionMessages(sessionId, {
3323
+ limit: readPositiveInt(c.req.query("limit"))
3324
+ });
3325
+ const payload = {
3326
+ sessionId,
3327
+ messages,
3328
+ total: messages.length
3329
+ };
3330
+ return c.json(ok(payload));
3331
+ };
3332
+ deleteSession = async (c) => {
3333
+ const sessionApi = this.options.ncpAgent?.sessionApi;
3334
+ if (!sessionApi) {
3335
+ return c.json(err("NOT_AVAILABLE", "ncp session api unavailable"), 503);
3336
+ }
3337
+ const sessionId = decodeURIComponent(c.req.param("sessionId"));
3338
+ const existing = await sessionApi.getSession(sessionId);
3339
+ if (!existing) {
3340
+ return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
3341
+ }
3342
+ await sessionApi.deleteSession(sessionId);
3343
+ this.options.publish({ type: "config.updated", payload: { path: "session" } });
3344
+ return c.json(ok({ deleted: true, sessionId }));
3345
+ };
3346
+ };
3347
+
2859
3348
  // src/ui/router/marketplace/constants.ts
2860
3349
  var DEFAULT_MARKETPLACE_API_BASE = "https://marketplace-api.nextclaw.io";
2861
3350
  var NEXTCLAW_PLUGIN_NPM_PREFIX = "@nextclaw/channel-plugin-";
@@ -4046,16 +4535,38 @@ var SessionRoutesController = class {
4046
4535
  function createUiRouter(options) {
4047
4536
  const app = new Hono();
4048
4537
  const marketplaceBaseUrl = normalizeMarketplaceBaseUrl(options);
4538
+ const authService = options.authService ?? new UiAuthService(options.configPath);
4049
4539
  const appController = new AppRoutesController(options);
4540
+ const authController = new AuthRoutesController(authService);
4050
4541
  const configController = new ConfigRoutesController(options);
4051
4542
  const chatController = new ChatRoutesController(options);
4052
4543
  const sessionController = new SessionRoutesController(options);
4053
4544
  const cronController = new CronRoutesController(options);
4545
+ const ncpSessionController = new NcpSessionRoutesController(options);
4054
4546
  const pluginMarketplaceController = new PluginMarketplaceController(options, marketplaceBaseUrl);
4055
4547
  const skillMarketplaceController = new SkillMarketplaceController(options, marketplaceBaseUrl);
4056
4548
  app.notFound((c) => c.json(err("NOT_FOUND", "endpoint not found"), 404));
4549
+ app.use("/api/*", async (c, next) => {
4550
+ const path = c.req.path;
4551
+ if (path === "/api/health" || path.startsWith("/api/auth/")) {
4552
+ await next();
4553
+ return;
4554
+ }
4555
+ if (!authService.isProtectionEnabled() || authService.isRequestAuthenticated(c.req.raw)) {
4556
+ await next();
4557
+ return;
4558
+ }
4559
+ c.status(401);
4560
+ return c.json(err("UNAUTHORIZED", "Authentication required."), 401);
4561
+ });
4057
4562
  app.get("/api/health", appController.health);
4058
4563
  app.get("/api/app/meta", appController.appMeta);
4564
+ app.get("/api/auth/status", authController.getStatus);
4565
+ app.post("/api/auth/setup", authController.setup);
4566
+ app.post("/api/auth/login", authController.login);
4567
+ app.post("/api/auth/logout", authController.logout);
4568
+ app.put("/api/auth/password", authController.updatePassword);
4569
+ app.put("/api/auth/enabled", authController.updateEnabled);
4059
4570
  app.get("/api/config", configController.getConfig);
4060
4571
  app.get("/api/config/meta", configController.getConfigMeta);
4061
4572
  app.get("/api/config/schema", configController.getConfigSchema);
@@ -4085,6 +4596,17 @@ function createUiRouter(options) {
4085
4596
  app.get("/api/sessions/:key/history", sessionController.getSessionHistory);
4086
4597
  app.put("/api/sessions/:key", sessionController.patchSession);
4087
4598
  app.delete("/api/sessions/:key", sessionController.deleteSession);
4599
+ if (options.ncpAgent) {
4600
+ mountNcpHttpAgentRoutes(app, {
4601
+ basePath: options.ncpAgent.basePath ?? "/api/ncp/agent",
4602
+ agentClientEndpoint: options.ncpAgent.agentClientEndpoint,
4603
+ streamProvider: options.ncpAgent.streamProvider
4604
+ });
4605
+ app.get("/api/ncp/sessions", ncpSessionController.listSessions);
4606
+ app.get("/api/ncp/sessions/:sessionId", ncpSessionController.getSession);
4607
+ app.get("/api/ncp/sessions/:sessionId/messages", ncpSessionController.listSessionMessages);
4608
+ app.delete("/api/ncp/sessions/:sessionId", ncpSessionController.deleteSession);
4609
+ }
4088
4610
  app.get("/api/cron", cronController.listJobs);
4089
4611
  app.delete("/api/cron/:id", cronController.deleteJob);
4090
4612
  app.put("/api/cron/:id/enable", cronController.enableJob);
@@ -4121,7 +4643,8 @@ function startUiServer(options) {
4121
4643
  const app = new Hono2();
4122
4644
  app.use("/*", compress());
4123
4645
  const origin = options.corsOrigins ?? DEFAULT_CORS_ORIGINS;
4124
- app.use("/api/*", cors({ origin }));
4646
+ const authService = new UiAuthService(options.configPath);
4647
+ app.use("/api/*", cors({ origin, credentials: true }));
4125
4648
  const clients = /* @__PURE__ */ new Set();
4126
4649
  const publish = (event) => {
4127
4650
  const payload = JSON.stringify(event);
@@ -4139,7 +4662,9 @@ function startUiServer(options) {
4139
4662
  publish,
4140
4663
  marketplace: options.marketplace,
4141
4664
  cronService: options.cronService,
4142
- chatRuntime: options.chatRuntime
4665
+ chatRuntime: options.chatRuntime,
4666
+ ncpAgent: options.ncpAgent,
4667
+ authService
4143
4668
  })
4144
4669
  );
4145
4670
  const staticDir = options.staticDir;
@@ -4179,9 +4704,23 @@ function startUiServer(options) {
4179
4704
  port: options.port,
4180
4705
  hostname: options.host
4181
4706
  });
4182
- const wss = new WebSocketServer({
4183
- server,
4184
- path: "/ws"
4707
+ const httpServer = server;
4708
+ const wss = new WebSocketServer({ noServer: true });
4709
+ httpServer.on("upgrade", (request, socket, head) => {
4710
+ const host = request.headers.host ?? "127.0.0.1";
4711
+ const url = request.url ?? "/";
4712
+ const pathname = new URL(url, `http://${host}`).pathname;
4713
+ if (pathname !== "/ws") {
4714
+ return;
4715
+ }
4716
+ if (!authService.isSocketAuthenticated(request)) {
4717
+ socket.write("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n");
4718
+ socket.destroy();
4719
+ return;
4720
+ }
4721
+ wss.handleUpgrade(request, socket, head, (ws) => {
4722
+ wss.emit("connection", ws, request);
4723
+ });
4185
4724
  });
4186
4725
  wss.on("connection", (socket) => {
4187
4726
  clients.add(socket);
@@ -4193,7 +4732,9 @@ function startUiServer(options) {
4193
4732
  publish,
4194
4733
  close: () => new Promise((resolve2) => {
4195
4734
  wss.close(() => {
4196
- server.close(() => resolve2());
4735
+ server.close(() => {
4736
+ Promise.resolve(options.ncpAgent?.agentClientEndpoint.stop()).catch(() => void 0).finally(() => resolve2());
4737
+ });
4197
4738
  });
4198
4739
  })
4199
4740
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/server",
3
- "version": "0.6.13",
3
+ "version": "0.8.0",
4
4
  "private": false,
5
5
  "description": "Nextclaw UI/API server.",
6
6
  "type": "module",
@@ -18,9 +18,11 @@
18
18
  "@hono/node-server": "^1.13.3",
19
19
  "hono": "^4.6.2",
20
20
  "ws": "^8.18.0",
21
- "@nextclaw/openclaw-compat": "0.2.6",
22
- "@nextclaw/runtime": "0.1.6",
23
- "@nextclaw/core": "0.7.7"
21
+ "@nextclaw/ncp-http-agent-server": "0.3.0",
22
+ "@nextclaw/openclaw-compat": "0.3.0",
23
+ "@nextclaw/ncp": "0.3.0",
24
+ "@nextclaw/runtime": "0.2.0",
25
+ "@nextclaw/core": "0.9.0"
24
26
  },
25
27
  "devDependencies": {
26
28
  "@types/node": "^20.17.6",