@nextclaw/server 0.12.11 → 0.12.13-beta.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 +23 -3
- package/dist/index.js +166 -78
- package/package.json +8 -7
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Config, ConfigActionExecuteRequest as ConfigActionExecuteRequest$1, Con
|
|
|
4
4
|
import { NcpHttpAgentStreamProvider } from "@nextclaw/ncp-http-agent-server";
|
|
5
5
|
import { PluginChannelBinding, PluginUiMetadata } from "@nextclaw/openclaw-compat";
|
|
6
6
|
import { NcpAgentClientEndpoint, NcpMessage, NcpSessionApi, NcpSessionStatus, NcpSessionSummary } from "@nextclaw/ncp";
|
|
7
|
+
import { UpdatePreferences, UpdateSnapshot } from "@nextclaw/kernel/update-contract";
|
|
7
8
|
import { IncomingMessage } from "node:http";
|
|
8
9
|
|
|
9
10
|
//#region src/ui/ncp-attachment.types.d.ts
|
|
@@ -401,6 +402,7 @@ type UiRouterOptions = {
|
|
|
401
402
|
authService?: UiAuthService;
|
|
402
403
|
remoteAccess?: UiRemoteAccessHost;
|
|
403
404
|
runtimeControl?: UiRuntimeControlHost;
|
|
405
|
+
runtimeUpdate?: UiRuntimeUpdateHost;
|
|
404
406
|
getBootstrapStatus?: () => BootstrapStatusView;
|
|
405
407
|
getPluginChannelBindings?: () => PluginChannelBinding[];
|
|
406
408
|
getPluginUiMetadata?: () => PluginUiMetadata[];
|
|
@@ -422,6 +424,14 @@ type UiRuntimeControlHost = {
|
|
|
422
424
|
restartService: () => Promise<RuntimeControlActionResult> | RuntimeControlActionResult;
|
|
423
425
|
stopService: () => Promise<RuntimeControlActionResult> | RuntimeControlActionResult;
|
|
424
426
|
};
|
|
427
|
+
type UiRuntimeUpdateHost = {
|
|
428
|
+
getState: () => Promise<UpdateSnapshot> | UpdateSnapshot;
|
|
429
|
+
checkForUpdates: () => Promise<UpdateSnapshot> | UpdateSnapshot;
|
|
430
|
+
downloadUpdate: () => Promise<UpdateSnapshot> | UpdateSnapshot;
|
|
431
|
+
applyDownloadedUpdate: () => Promise<UpdateSnapshot> | UpdateSnapshot;
|
|
432
|
+
updatePreferences: (preferences: Partial<UpdatePreferences>) => Promise<UpdateSnapshot> | UpdateSnapshot;
|
|
433
|
+
updateChannel: (channel: UpdateSnapshot["channel"]) => Promise<UpdateSnapshot> | UpdateSnapshot;
|
|
434
|
+
};
|
|
425
435
|
//#endregion
|
|
426
436
|
//#region src/ui/chat-session-type.types.d.ts
|
|
427
437
|
type ChatSessionTypeIconView = {
|
|
@@ -935,9 +945,12 @@ type CronScheduleView = {
|
|
|
935
945
|
type CronPayloadView = {
|
|
936
946
|
kind?: "system_event" | "agent_turn";
|
|
937
947
|
message: string;
|
|
948
|
+
agentId?: string | null;
|
|
949
|
+
sessionId?: string | null;
|
|
938
950
|
deliver?: boolean;
|
|
939
951
|
channel?: string | null;
|
|
940
952
|
to?: string | null;
|
|
953
|
+
accountId?: string | null;
|
|
941
954
|
};
|
|
942
955
|
type CronJobStateView = {
|
|
943
956
|
nextRunAt?: string | null;
|
|
@@ -965,6 +978,7 @@ type CronCreateRequest = {
|
|
|
965
978
|
message: string;
|
|
966
979
|
schedule: CronScheduleView;
|
|
967
980
|
agentId?: string | null;
|
|
981
|
+
sessionId?: string | null;
|
|
968
982
|
deliver?: boolean;
|
|
969
983
|
channel?: string | null;
|
|
970
984
|
to?: string | null;
|
|
@@ -985,6 +999,9 @@ type CronActionResult = {
|
|
|
985
999
|
executed?: boolean;
|
|
986
1000
|
};
|
|
987
1001
|
type RuntimeConfigUpdate = {
|
|
1002
|
+
companion?: {
|
|
1003
|
+
enabled?: boolean;
|
|
1004
|
+
};
|
|
988
1005
|
agents?: {
|
|
989
1006
|
defaults?: {
|
|
990
1007
|
contextTokens?: number;
|
|
@@ -1073,6 +1090,9 @@ type UiNcpAgent = {
|
|
|
1073
1090
|
basePath?: string;
|
|
1074
1091
|
};
|
|
1075
1092
|
type ConfigView = {
|
|
1093
|
+
companion?: {
|
|
1094
|
+
enabled?: boolean;
|
|
1095
|
+
};
|
|
1076
1096
|
agents: {
|
|
1077
1097
|
defaults: {
|
|
1078
1098
|
model: string;
|
|
@@ -1090,7 +1110,6 @@ type ConfigView = {
|
|
|
1090
1110
|
bootstrap?: {
|
|
1091
1111
|
files?: string[];
|
|
1092
1112
|
minimalFiles?: string[];
|
|
1093
|
-
heartbeatFiles?: string[];
|
|
1094
1113
|
perFileChars?: number;
|
|
1095
1114
|
totalChars?: number;
|
|
1096
1115
|
};
|
|
@@ -1314,6 +1333,7 @@ type UiServerHandle = {
|
|
|
1314
1333
|
//#region src/ui/server.d.ts
|
|
1315
1334
|
type UiServerStartOptions = UiServerOptions & {
|
|
1316
1335
|
applyLiveConfigReload?: () => Promise<void>;
|
|
1336
|
+
runtimeUpdate?: UiRuntimeUpdateHost;
|
|
1317
1337
|
};
|
|
1318
1338
|
declare function startUiServer(options: UiServerStartOptions): UiServerHandle;
|
|
1319
1339
|
//#endregion
|
|
@@ -1371,7 +1391,7 @@ declare function patchSession(configPath: string, key: string, patch: SessionPat
|
|
|
1371
1391
|
availableSessionTypes?: string[];
|
|
1372
1392
|
}): SessionHistoryView | null;
|
|
1373
1393
|
declare function deleteSession(configPath: string, key: string): boolean;
|
|
1374
|
-
declare function updateRuntime(configPath: string, patch: RuntimeConfigUpdate): Pick<ConfigView, "agents" | "bindings" | "session">;
|
|
1394
|
+
declare function updateRuntime(configPath: string, patch: RuntimeConfigUpdate): Pick<ConfigView, "companion" | "agents" | "bindings" | "session">;
|
|
1375
1395
|
declare function updateSecrets(configPath: string, patch: SecretsConfigUpdate): SecretsView;
|
|
1376
1396
|
//#endregion
|
|
1377
1397
|
//#region src/ui/auth-bridge.d.ts
|
|
@@ -1379,4 +1399,4 @@ declare function getUiBridgeSecretPath(): string;
|
|
|
1379
1399
|
declare function readUiBridgeSecret(): string | null;
|
|
1380
1400
|
declare function ensureUiBridgeSecret(): string;
|
|
1381
1401
|
//#endregion
|
|
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 };
|
|
1402
|
+
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, type UiRuntimeUpdateHost, 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
|
@@ -1332,6 +1332,7 @@ function buildConfigView(config, options) {
|
|
|
1332
1332
|
const providers = {};
|
|
1333
1333
|
for (const [name, provider] of Object.entries(config.providers)) providers[name] = toProviderView(config, provider, name, uiHints, findServerBuiltinProviderByName(name));
|
|
1334
1334
|
return {
|
|
1335
|
+
companion: sanitizePublicConfigValue(config.companion, "companion", uiHints),
|
|
1335
1336
|
agents: sanitizePublicConfigValue(config.agents, "agents", uiHints),
|
|
1336
1337
|
providers,
|
|
1337
1338
|
search: buildSearchView(config),
|
|
@@ -1907,18 +1908,22 @@ function deleteSession(configPath, key) {
|
|
|
1907
1908
|
if (!normalizedKey) return false;
|
|
1908
1909
|
return createSessionManager(loadConfigOrDefault(configPath)).delete(normalizedKey);
|
|
1909
1910
|
}
|
|
1910
|
-
function
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
if (defaultsPatch && Object.prototype.hasOwnProperty.call(defaultsPatch, "contextTokens")) {
|
|
1911
|
+
function applyRuntimeAgentDefaultsPatch(config, defaultsPatch) {
|
|
1912
|
+
if (!defaultsPatch) return;
|
|
1913
|
+
if (Object.prototype.hasOwnProperty.call(defaultsPatch, "contextTokens")) {
|
|
1914
1914
|
const nextContextTokens = defaultsPatch.contextTokens;
|
|
1915
1915
|
if (typeof nextContextTokens === "number" && Number.isFinite(nextContextTokens)) config.agents.defaults.contextTokens = Math.max(1e3, Math.trunc(nextContextTokens));
|
|
1916
1916
|
}
|
|
1917
|
-
if (
|
|
1918
|
-
if (
|
|
1917
|
+
if (Object.prototype.hasOwnProperty.call(defaultsPatch, "engine")) config.agents.defaults.engine = normalizeOptionalString(defaultsPatch.engine) ?? "native";
|
|
1918
|
+
if (Object.prototype.hasOwnProperty.call(defaultsPatch, "engineConfig")) {
|
|
1919
1919
|
const nextEngineConfig = defaultsPatch.engineConfig;
|
|
1920
1920
|
if (nextEngineConfig && typeof nextEngineConfig === "object" && !Array.isArray(nextEngineConfig)) config.agents.defaults.engineConfig = { ...nextEngineConfig };
|
|
1921
1921
|
}
|
|
1922
|
+
}
|
|
1923
|
+
function updateRuntime(configPath, patch) {
|
|
1924
|
+
const config = loadConfigOrDefault(configPath);
|
|
1925
|
+
if (patch.companion && Object.prototype.hasOwnProperty.call(patch.companion, "enabled")) config.companion.enabled = Boolean(patch.companion.enabled);
|
|
1926
|
+
applyRuntimeAgentDefaultsPatch(config, patch.agents?.defaults);
|
|
1922
1927
|
if (patch.agents && Object.prototype.hasOwnProperty.call(patch.agents, "list")) config.agents.list = (patch.agents.list ?? []).map((entry) => {
|
|
1923
1928
|
const normalizedEngine = normalizeOptionalString(entry.engine);
|
|
1924
1929
|
const hasEngineConfig = entry.engineConfig && typeof entry.engineConfig === "object" && !Array.isArray(entry.engineConfig);
|
|
@@ -1939,6 +1944,7 @@ function updateRuntime(configPath, patch) {
|
|
|
1939
1944
|
saveConfig(next, configPath);
|
|
1940
1945
|
const view = buildConfigView(next);
|
|
1941
1946
|
return {
|
|
1947
|
+
companion: view.companion,
|
|
1942
1948
|
agents: view.agents,
|
|
1943
1949
|
bindings: view.bindings ?? [],
|
|
1944
1950
|
session: view.session ?? {}
|
|
@@ -2707,6 +2713,7 @@ var ConfigRoutesController = class {
|
|
|
2707
2713
|
if (body.data.agents?.defaults && Object.prototype.hasOwnProperty.call(body.data.agents.defaults, "engine")) changedPaths.push("agents.defaults.engine");
|
|
2708
2714
|
if (body.data.agents?.defaults && Object.prototype.hasOwnProperty.call(body.data.agents.defaults, "engineConfig")) changedPaths.push("agents.defaults.engineConfig");
|
|
2709
2715
|
if (body.data.agents?.runtimes && Object.prototype.hasOwnProperty.call(body.data.agents.runtimes, "entries")) changedPaths.push("agents.runtimes.entries");
|
|
2716
|
+
if (body.data.companion && Object.prototype.hasOwnProperty.call(body.data.companion, "enabled")) changedPaths.push("companion.enabled");
|
|
2710
2717
|
changedPaths.push("agents.list", "bindings", "session");
|
|
2711
2718
|
await this.publishConfigUpdates(changedPaths);
|
|
2712
2719
|
return c.json(ok(result));
|
|
@@ -2792,6 +2799,7 @@ function readCronCreateParams(input) {
|
|
|
2792
2799
|
message,
|
|
2793
2800
|
schedule,
|
|
2794
2801
|
agentId: readNonEmptyString(input.agentId),
|
|
2802
|
+
sessionId: readNonEmptyString(input.sessionId),
|
|
2795
2803
|
deliver: input.deliver === true,
|
|
2796
2804
|
channel: readNonEmptyString(input.channel),
|
|
2797
2805
|
to: readNonEmptyString(input.to),
|
|
@@ -3206,6 +3214,7 @@ var NcpSessionRoutesController = class {
|
|
|
3206
3214
|
sessionId,
|
|
3207
3215
|
status: session.status ?? "idle",
|
|
3208
3216
|
messages,
|
|
3217
|
+
...session.contextWindow ? { contextWindow: session.contextWindow } : {},
|
|
3209
3218
|
total: messages.length
|
|
3210
3219
|
};
|
|
3211
3220
|
return c.json(ok(payload));
|
|
@@ -4529,6 +4538,64 @@ var RuntimeControlRoutesController = class {
|
|
|
4529
4538
|
};
|
|
4530
4539
|
};
|
|
4531
4540
|
//#endregion
|
|
4541
|
+
//#region src/ui/ui-routes/runtime-update.controller.ts
|
|
4542
|
+
var RuntimeUpdateRoutesController = class {
|
|
4543
|
+
constructor(host) {
|
|
4544
|
+
this.host = host;
|
|
4545
|
+
}
|
|
4546
|
+
getState = async (c) => {
|
|
4547
|
+
try {
|
|
4548
|
+
return c.json(ok(await this.host.getState()));
|
|
4549
|
+
} catch (error) {
|
|
4550
|
+
return c.json(err("RUNTIME_UPDATE_STATE_FAILED", formatUserFacingError(error)), 500);
|
|
4551
|
+
}
|
|
4552
|
+
};
|
|
4553
|
+
checkForUpdates = async (c) => {
|
|
4554
|
+
try {
|
|
4555
|
+
return c.json(ok(await this.host.checkForUpdates()));
|
|
4556
|
+
} catch (error) {
|
|
4557
|
+
return c.json(err("RUNTIME_UPDATE_CHECK_FAILED", formatUserFacingError(error)), 400);
|
|
4558
|
+
}
|
|
4559
|
+
};
|
|
4560
|
+
downloadUpdate = async (c) => {
|
|
4561
|
+
try {
|
|
4562
|
+
return c.json(ok(await this.host.downloadUpdate()));
|
|
4563
|
+
} catch (error) {
|
|
4564
|
+
return c.json(err("RUNTIME_UPDATE_DOWNLOAD_FAILED", formatUserFacingError(error)), 400);
|
|
4565
|
+
}
|
|
4566
|
+
};
|
|
4567
|
+
applyDownloadedUpdate = async (c) => {
|
|
4568
|
+
try {
|
|
4569
|
+
return c.json(ok(await this.host.applyDownloadedUpdate()));
|
|
4570
|
+
} catch (error) {
|
|
4571
|
+
return c.json(err("RUNTIME_UPDATE_APPLY_FAILED", formatUserFacingError(error)), 400);
|
|
4572
|
+
}
|
|
4573
|
+
};
|
|
4574
|
+
updatePreferences = async (c) => {
|
|
4575
|
+
const body = await readJson(c.req.raw);
|
|
4576
|
+
if (!body.ok) return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
4577
|
+
try {
|
|
4578
|
+
return c.json(ok(await this.host.updatePreferences({
|
|
4579
|
+
...typeof body.data.automaticChecks === "boolean" ? { automaticChecks: body.data.automaticChecks } : {},
|
|
4580
|
+
...typeof body.data.autoDownload === "boolean" ? { autoDownload: body.data.autoDownload } : {}
|
|
4581
|
+
})));
|
|
4582
|
+
} catch (error) {
|
|
4583
|
+
return c.json(err("RUNTIME_UPDATE_PREFERENCES_FAILED", formatUserFacingError(error)), 400);
|
|
4584
|
+
}
|
|
4585
|
+
};
|
|
4586
|
+
updateChannel = async (c) => {
|
|
4587
|
+
const body = await readJson(c.req.raw);
|
|
4588
|
+
if (!body.ok) return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
4589
|
+
const channel = body.data.channel;
|
|
4590
|
+
if (channel !== "stable" && channel !== "beta") return c.json(err("INVALID_BODY", "channel must be stable or beta"), 400);
|
|
4591
|
+
try {
|
|
4592
|
+
return c.json(ok(await this.host.updateChannel(channel)));
|
|
4593
|
+
} catch (error) {
|
|
4594
|
+
return c.json(err("RUNTIME_UPDATE_CHANNEL_FAILED", formatUserFacingError(error)), 400);
|
|
4595
|
+
}
|
|
4596
|
+
};
|
|
4597
|
+
};
|
|
4598
|
+
//#endregion
|
|
4532
4599
|
//#region src/ui/server-path/server-path-browse.utils.ts
|
|
4533
4600
|
var ServerPathBrowseError = class extends Error {
|
|
4534
4601
|
constructor(code, message) {
|
|
@@ -4865,7 +4932,17 @@ function registerRuntimeControlRoutes(app, runtimeControlController) {
|
|
|
4865
4932
|
app.post("/api/runtime/control/restart-service", runtimeControlController.restartService);
|
|
4866
4933
|
app.post("/api/runtime/control/stop-service", runtimeControlController.stopService);
|
|
4867
4934
|
}
|
|
4935
|
+
function registerRuntimeUpdateRoutes(app, runtimeUpdateController) {
|
|
4936
|
+
if (!runtimeUpdateController) return;
|
|
4937
|
+
app.get("/api/runtime/update", runtimeUpdateController.getState);
|
|
4938
|
+
app.post("/api/runtime/update/check", runtimeUpdateController.checkForUpdates);
|
|
4939
|
+
app.post("/api/runtime/update/download", runtimeUpdateController.downloadUpdate);
|
|
4940
|
+
app.post("/api/runtime/update/apply", runtimeUpdateController.applyDownloadedUpdate);
|
|
4941
|
+
app.put("/api/runtime/update/preferences", runtimeUpdateController.updatePreferences);
|
|
4942
|
+
app.put("/api/runtime/update/channel", runtimeUpdateController.updateChannel);
|
|
4943
|
+
}
|
|
4868
4944
|
function createUiRouteControllers(options, authService, marketplaceBaseUrl) {
|
|
4945
|
+
const { remoteAccess, runtimeControl, runtimeUpdate } = options;
|
|
4869
4946
|
return {
|
|
4870
4947
|
app: new AppRoutesController(options),
|
|
4871
4948
|
agents: new AgentsRoutesController(options),
|
|
@@ -4875,8 +4952,9 @@ function createUiRouteControllers(options, authService, marketplaceBaseUrl) {
|
|
|
4875
4952
|
ncpSession: new NcpSessionRoutesController(options),
|
|
4876
4953
|
ncpAsset: new NcpAssetRoutesController(options),
|
|
4877
4954
|
serverPath: new ServerPathRoutesController(),
|
|
4878
|
-
remote:
|
|
4879
|
-
runtimeControl:
|
|
4955
|
+
remote: remoteAccess ? new RemoteRoutesController(remoteAccess) : null,
|
|
4956
|
+
runtimeControl: runtimeControl ? new RuntimeControlRoutesController(runtimeControl) : null,
|
|
4957
|
+
runtimeUpdate: runtimeUpdate ? new RuntimeUpdateRoutesController(runtimeUpdate) : null,
|
|
4880
4958
|
pluginMarketplace: new PluginMarketplaceController(options, marketplaceBaseUrl),
|
|
4881
4959
|
skillMarketplace: new SkillMarketplaceController(options, marketplaceBaseUrl),
|
|
4882
4960
|
mcpMarketplace: new McpMarketplaceController(options, marketplaceBaseUrl)
|
|
@@ -4913,6 +4991,7 @@ function createUiRouter(options) {
|
|
|
4913
4991
|
registerCronRoutes(app, controllers.cron);
|
|
4914
4992
|
registerRemoteRoutes(app, controllers.remote);
|
|
4915
4993
|
registerRuntimeControlRoutes(app, controllers.runtimeControl);
|
|
4994
|
+
registerRuntimeUpdateRoutes(app, controllers.runtimeUpdate);
|
|
4916
4995
|
mountMarketplaceRoutes(app, {
|
|
4917
4996
|
plugin: controllers.pluginMarketplace,
|
|
4918
4997
|
skill: controllers.skillMarketplace,
|
|
@@ -4955,11 +5034,66 @@ function applyCorsHeaders(params) {
|
|
|
4955
5034
|
appendVaryHeader(params.headers, "Origin");
|
|
4956
5035
|
appendVaryHeader(params.headers, "Access-Control-Request-Headers");
|
|
4957
5036
|
}
|
|
5037
|
+
function createUiEventPublisher(clients) {
|
|
5038
|
+
return (event) => {
|
|
5039
|
+
const payload = JSON.stringify(event);
|
|
5040
|
+
for (const client of clients) if (client.readyState === WebSocket.OPEN) client.send(payload);
|
|
5041
|
+
};
|
|
5042
|
+
}
|
|
5043
|
+
function mountUiStaticAssets(app, staticDir) {
|
|
5044
|
+
if (!existsSync(join(staticDir, "index.html"))) return;
|
|
5045
|
+
const indexHtml = readFileSync(join(staticDir, "index.html"), "utf-8");
|
|
5046
|
+
app.use("/*", serveStatic({
|
|
5047
|
+
root: staticDir,
|
|
5048
|
+
join,
|
|
5049
|
+
getContent: async (path) => {
|
|
5050
|
+
try {
|
|
5051
|
+
return await readFile(path);
|
|
5052
|
+
} catch {
|
|
5053
|
+
return null;
|
|
5054
|
+
}
|
|
5055
|
+
},
|
|
5056
|
+
isDir: async (path) => {
|
|
5057
|
+
try {
|
|
5058
|
+
return (await stat(path)).isDirectory();
|
|
5059
|
+
} catch {
|
|
5060
|
+
return false;
|
|
5061
|
+
}
|
|
5062
|
+
}
|
|
5063
|
+
}));
|
|
5064
|
+
app.get("*", (c) => {
|
|
5065
|
+
const path = c.req.path;
|
|
5066
|
+
if (path.startsWith("/api") || path.startsWith("/ws") || path.startsWith("/_remote")) return c.notFound();
|
|
5067
|
+
return c.html(indexHtml);
|
|
5068
|
+
});
|
|
5069
|
+
}
|
|
5070
|
+
function attachUiSocketServer(httpServer, authService, clients) {
|
|
5071
|
+
const wss = new WebSocketServer({ noServer: true });
|
|
5072
|
+
httpServer.on("upgrade", (request, socket, head) => {
|
|
5073
|
+
const host = request.headers.host ?? "127.0.0.1";
|
|
5074
|
+
const url = request.url ?? "/";
|
|
5075
|
+
if (new URL(url, `http://${host}`).pathname !== "/ws") return;
|
|
5076
|
+
if (!authService.isSocketAuthenticated(request)) {
|
|
5077
|
+
socket.write("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n");
|
|
5078
|
+
socket.destroy();
|
|
5079
|
+
return;
|
|
5080
|
+
}
|
|
5081
|
+
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
5082
|
+
wss.emit("connection", ws, request);
|
|
5083
|
+
});
|
|
5084
|
+
});
|
|
5085
|
+
wss.on("connection", (socket) => {
|
|
5086
|
+
clients.add(socket);
|
|
5087
|
+
socket.on("close", () => clients.delete(socket));
|
|
5088
|
+
});
|
|
5089
|
+
return wss;
|
|
5090
|
+
}
|
|
4958
5091
|
function startUiServer(options) {
|
|
5092
|
+
const { applyLiveConfigReload, configPath, corsOrigins, cronService, getBootstrapStatus, getPluginChannelBindings, getPluginUiMetadata, host, initializeAgentHomeDirectory, marketplace, ncpAgent, ncpSessionService, port, productVersion, remoteAccess, runtimeControl, runtimeUpdate, staticDir } = options;
|
|
4959
5093
|
const app = new Hono();
|
|
4960
5094
|
app.use("/*", compress());
|
|
4961
|
-
const corsPolicy =
|
|
4962
|
-
const authService = new UiAuthService(
|
|
5095
|
+
const corsPolicy = corsOrigins ?? DEFAULT_CORS_ORIGINS;
|
|
5096
|
+
const authService = new UiAuthService(configPath);
|
|
4963
5097
|
app.use("/api/*", async (c, next) => {
|
|
4964
5098
|
const allowOrigin = resolveAllowedCorsOrigin(readRequestHeader(c.req.raw, "origin"), corsPolicy);
|
|
4965
5099
|
const allowHeaders = readRequestHeader(c.req.raw, "access-control-request-headers");
|
|
@@ -4986,86 +5120,40 @@ function startUiServer(options) {
|
|
|
4986
5120
|
});
|
|
4987
5121
|
});
|
|
4988
5122
|
const clients = /* @__PURE__ */ new Set();
|
|
4989
|
-
const publish = (
|
|
4990
|
-
const payload = JSON.stringify(event);
|
|
4991
|
-
for (const client of clients) if (client.readyState === WebSocket.OPEN) client.send(payload);
|
|
4992
|
-
};
|
|
5123
|
+
const publish = createUiEventPublisher(clients);
|
|
4993
5124
|
app.route("/", createUiRouter({
|
|
4994
|
-
configPath
|
|
4995
|
-
productVersion
|
|
5125
|
+
configPath,
|
|
5126
|
+
productVersion,
|
|
4996
5127
|
publish,
|
|
4997
|
-
applyLiveConfigReload
|
|
4998
|
-
initializeAgentHomeDirectory
|
|
4999
|
-
marketplace
|
|
5000
|
-
cronService
|
|
5001
|
-
ncpAgent
|
|
5002
|
-
ncpSessionService
|
|
5128
|
+
applyLiveConfigReload,
|
|
5129
|
+
initializeAgentHomeDirectory,
|
|
5130
|
+
marketplace,
|
|
5131
|
+
cronService,
|
|
5132
|
+
ncpAgent,
|
|
5133
|
+
ncpSessionService,
|
|
5003
5134
|
authService,
|
|
5004
|
-
remoteAccess
|
|
5005
|
-
runtimeControl
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5135
|
+
remoteAccess,
|
|
5136
|
+
runtimeControl,
|
|
5137
|
+
runtimeUpdate,
|
|
5138
|
+
getBootstrapStatus,
|
|
5139
|
+
getPluginChannelBindings,
|
|
5140
|
+
getPluginUiMetadata
|
|
5009
5141
|
}));
|
|
5010
|
-
|
|
5011
|
-
if (staticDir && existsSync(join(staticDir, "index.html"))) {
|
|
5012
|
-
const indexHtml = readFileSync(join(staticDir, "index.html"), "utf-8");
|
|
5013
|
-
app.use("/*", serveStatic({
|
|
5014
|
-
root: staticDir,
|
|
5015
|
-
join,
|
|
5016
|
-
getContent: async (path) => {
|
|
5017
|
-
try {
|
|
5018
|
-
return await readFile(path);
|
|
5019
|
-
} catch {
|
|
5020
|
-
return null;
|
|
5021
|
-
}
|
|
5022
|
-
},
|
|
5023
|
-
isDir: async (path) => {
|
|
5024
|
-
try {
|
|
5025
|
-
return (await stat(path)).isDirectory();
|
|
5026
|
-
} catch {
|
|
5027
|
-
return false;
|
|
5028
|
-
}
|
|
5029
|
-
}
|
|
5030
|
-
}));
|
|
5031
|
-
app.get("*", (c) => {
|
|
5032
|
-
const path = c.req.path;
|
|
5033
|
-
if (path.startsWith("/api") || path.startsWith("/ws") || path.startsWith("/_remote")) return c.notFound();
|
|
5034
|
-
return c.html(indexHtml);
|
|
5035
|
-
});
|
|
5036
|
-
}
|
|
5142
|
+
if (staticDir) mountUiStaticAssets(app, staticDir);
|
|
5037
5143
|
const server = serve({
|
|
5038
5144
|
fetch: app.fetch,
|
|
5039
|
-
port
|
|
5040
|
-
hostname:
|
|
5041
|
-
});
|
|
5042
|
-
const httpServer = server;
|
|
5043
|
-
const wss = new WebSocketServer({ noServer: true });
|
|
5044
|
-
httpServer.on("upgrade", (request, socket, head) => {
|
|
5045
|
-
const host = request.headers.host ?? "127.0.0.1";
|
|
5046
|
-
const url = request.url ?? "/";
|
|
5047
|
-
if (new URL(url, `http://${host}`).pathname !== "/ws") return;
|
|
5048
|
-
if (!authService.isSocketAuthenticated(request)) {
|
|
5049
|
-
socket.write("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n");
|
|
5050
|
-
socket.destroy();
|
|
5051
|
-
return;
|
|
5052
|
-
}
|
|
5053
|
-
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
5054
|
-
wss.emit("connection", ws, request);
|
|
5055
|
-
});
|
|
5056
|
-
});
|
|
5057
|
-
wss.on("connection", (socket) => {
|
|
5058
|
-
clients.add(socket);
|
|
5059
|
-
socket.on("close", () => clients.delete(socket));
|
|
5145
|
+
port,
|
|
5146
|
+
hostname: host
|
|
5060
5147
|
});
|
|
5148
|
+
const wss = attachUiSocketServer(server, authService, clients);
|
|
5061
5149
|
return {
|
|
5062
|
-
host
|
|
5063
|
-
port
|
|
5150
|
+
host,
|
|
5151
|
+
port,
|
|
5064
5152
|
publish,
|
|
5065
5153
|
close: () => new Promise((resolve) => {
|
|
5066
5154
|
wss.close(() => {
|
|
5067
5155
|
server.close(() => {
|
|
5068
|
-
Promise.resolve(
|
|
5156
|
+
Promise.resolve(ncpAgent?.agentClientEndpoint.stop()).catch(() => void 0).finally(() => resolve());
|
|
5069
5157
|
});
|
|
5070
5158
|
});
|
|
5071
5159
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/server",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.13-beta.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Nextclaw UI/API server.",
|
|
6
6
|
"type": "module",
|
|
@@ -18,12 +18,13 @@
|
|
|
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.
|
|
22
|
-
"@nextclaw/mcp": "0.1.
|
|
23
|
-
"@nextclaw/
|
|
24
|
-
"@nextclaw/ncp
|
|
25
|
-
"@nextclaw/
|
|
26
|
-
"@nextclaw/
|
|
21
|
+
"@nextclaw/core": "0.12.13-beta.1",
|
|
22
|
+
"@nextclaw/mcp": "0.1.78-beta.0",
|
|
23
|
+
"@nextclaw/kernel": "0.1.2-beta.1",
|
|
24
|
+
"@nextclaw/ncp": "0.5.6-beta.0",
|
|
25
|
+
"@nextclaw/runtime": "0.2.45-beta.0",
|
|
26
|
+
"@nextclaw/ncp-http-agent-server": "0.3.18-beta.0",
|
|
27
|
+
"@nextclaw/openclaw-compat": "1.0.13-beta.0"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"@types/node": "^20.17.6",
|