@nextclaw/server 0.10.55 → 0.10.57
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 +39 -2
- package/dist/index.js +115 -21
- package/package.json +7 -7
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,29 @@ import { NcpHttpAgentStreamProvider } from '@nextclaw/ncp-http-agent-server';
|
|
|
6
6
|
import { IncomingMessage } from 'node:http';
|
|
7
7
|
import { Hono } from 'hono';
|
|
8
8
|
|
|
9
|
+
type UiNcpStoredAttachmentRecord = {
|
|
10
|
+
id: string;
|
|
11
|
+
uri: string;
|
|
12
|
+
storageKey: string;
|
|
13
|
+
originalName: string;
|
|
14
|
+
storedName: string;
|
|
15
|
+
mimeType: string;
|
|
16
|
+
sizeBytes: number;
|
|
17
|
+
createdAt: string;
|
|
18
|
+
sha256: string;
|
|
19
|
+
};
|
|
20
|
+
type UiNcpAttachmentView = {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
mimeType: string;
|
|
24
|
+
sizeBytes: number;
|
|
25
|
+
attachmentUri: string;
|
|
26
|
+
url: string;
|
|
27
|
+
};
|
|
28
|
+
type UiNcpAttachmentUploadView = {
|
|
29
|
+
attachments: UiNcpAttachmentView[];
|
|
30
|
+
};
|
|
31
|
+
|
|
9
32
|
type MarketplaceItemType = "plugin" | "skill" | "mcp";
|
|
10
33
|
type MarketplaceSort = "relevance" | "updated";
|
|
11
34
|
type MarketplacePluginInstallKind = "npm";
|
|
@@ -327,6 +350,7 @@ type UiRouterOptions = {
|
|
|
327
350
|
configPath: string;
|
|
328
351
|
productVersion?: string;
|
|
329
352
|
publish: (event: UiServerEvent) => void;
|
|
353
|
+
applyLiveConfigReload?: () => Promise<void>;
|
|
330
354
|
marketplace?: MarketplaceApiConfig;
|
|
331
355
|
cronService?: InstanceType<typeof NextclawCore.CronService>;
|
|
332
356
|
chatRuntime?: UiChatRuntime;
|
|
@@ -942,6 +966,16 @@ type UiNcpAgent = {
|
|
|
942
966
|
streamProvider?: NcpHttpAgentStreamProvider;
|
|
943
967
|
sessionApi?: NcpSessionApi;
|
|
944
968
|
listSessionTypes?: (params?: SessionTypeDescribeParams) => Promise<ChatSessionTypesView> | ChatSessionTypesView;
|
|
969
|
+
attachmentApi?: {
|
|
970
|
+
saveAttachment: (input: {
|
|
971
|
+
fileName: string;
|
|
972
|
+
mimeType?: string | null;
|
|
973
|
+
bytes: Uint8Array;
|
|
974
|
+
createdAt?: Date;
|
|
975
|
+
}) => Promise<UiNcpStoredAttachmentRecord>;
|
|
976
|
+
statAttachment: (uri: string) => Promise<UiNcpStoredAttachmentRecord | null> | UiNcpStoredAttachmentRecord | null;
|
|
977
|
+
resolveContentPath: (uri: string) => string | null;
|
|
978
|
+
};
|
|
945
979
|
basePath?: string;
|
|
946
980
|
};
|
|
947
981
|
type ConfigView = {
|
|
@@ -1159,7 +1193,10 @@ type UiServerHandle = {
|
|
|
1159
1193
|
publish: (event: UiServerEvent) => void;
|
|
1160
1194
|
};
|
|
1161
1195
|
|
|
1162
|
-
|
|
1196
|
+
type UiServerStartOptions = UiServerOptions & {
|
|
1197
|
+
applyLiveConfigReload?: () => Promise<void>;
|
|
1198
|
+
};
|
|
1199
|
+
declare function startUiServer(options: UiServerStartOptions): UiServerHandle;
|
|
1163
1200
|
|
|
1164
1201
|
declare function createUiRouter(options: UiRouterOptions): Hono;
|
|
1165
1202
|
|
|
@@ -1217,4 +1254,4 @@ declare function getUiBridgeSecretPath(): string;
|
|
|
1217
1254
|
declare function readUiBridgeSecret(): string | null;
|
|
1218
1255
|
declare function ensureUiBridgeSecret(): string;
|
|
1219
1256
|
|
|
1220
|
-
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 ChannelAuthPollRequest, type ChannelAuthPollResult, type ChannelAuthStartRequest, type ChannelAuthStartResult, type ChannelSpecView, type ChatCapabilitiesView, type ChatCommandOptionView, type ChatCommandView, type ChatCommandsView, type ChatRunListView, type ChatRunState, type ChatRunView, type ChatSessionTypeCtaView, 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 MarketplaceMcpContentView, type MarketplaceMcpDoctorResult, type MarketplaceMcpInstallKind, type MarketplaceMcpInstallRequest, type MarketplaceMcpInstallResult, type MarketplaceMcpInstallSpec, type MarketplaceMcpManageAction, type MarketplaceMcpManageRequest, type MarketplaceMcpManageResult, type MarketplaceMcpTemplateInput, 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 RemoteAccessView, type RemoteAccountView, type RemoteBrowserAuthPollRequest, type RemoteBrowserAuthPollResult, type RemoteBrowserAuthStartRequest, type RemoteBrowserAuthStartResult, type RemoteDoctorCheckView, type RemoteDoctorView, type RemoteLoginRequest, type RemoteRuntimeView, type RemoteServiceAction, type RemoteServiceActionResult, type RemoteServiceView, type RemoteSettingsUpdateRequest, type RemoteSettingsView, 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 SessionTypeDescribeParams, type SessionsListView, type UiChatRuntime, type UiNcpAgent, type UiNcpSessionListView, type UiNcpSessionMessagesView, type UiRemoteAccessHost, type UiServerEvent, type UiServerHandle, type UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createCustomProvider, createUiRouter, deleteCustomProvider, deleteSession, ensureUiBridgeSecret, executeConfigAction, getSessionHistory, getUiBridgeSecretPath, listSessions, loadConfigOrDefault, patchSession, readUiBridgeSecret, startUiServer, testProviderConnection, updateChannel, updateModel, updateProvider, updateRuntime, updateSearch, updateSecrets };
|
|
1257
|
+
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 ChannelAuthPollRequest, type ChannelAuthPollResult, type ChannelAuthStartRequest, type ChannelAuthStartResult, type ChannelSpecView, type ChatCapabilitiesView, type ChatCommandOptionView, type ChatCommandView, type ChatCommandsView, type ChatRunListView, type ChatRunState, type ChatRunView, type ChatSessionTypeCtaView, 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 MarketplaceMcpContentView, type MarketplaceMcpDoctorResult, type MarketplaceMcpInstallKind, type MarketplaceMcpInstallRequest, type MarketplaceMcpInstallResult, type MarketplaceMcpInstallSpec, type MarketplaceMcpManageAction, type MarketplaceMcpManageRequest, type MarketplaceMcpManageResult, type MarketplaceMcpTemplateInput, 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 RemoteAccessView, type RemoteAccountView, type RemoteBrowserAuthPollRequest, type RemoteBrowserAuthPollResult, type RemoteBrowserAuthStartRequest, type RemoteBrowserAuthStartResult, type RemoteDoctorCheckView, type RemoteDoctorView, type RemoteLoginRequest, type RemoteRuntimeView, type RemoteServiceAction, type RemoteServiceActionResult, type RemoteServiceView, type RemoteSettingsUpdateRequest, type RemoteSettingsView, 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 SessionTypeDescribeParams, type SessionsListView, type UiChatRuntime, type UiNcpAgent, type UiNcpAttachmentUploadView, type UiNcpAttachmentView, type UiNcpSessionListView, type UiNcpSessionMessagesView, type UiNcpStoredAttachmentRecord, type UiRemoteAccessHost, type UiServerEvent, type UiServerHandle, type 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
|
@@ -4,7 +4,7 @@ import { compress } from "hono/compress";
|
|
|
4
4
|
import { serve } from "@hono/node-server";
|
|
5
5
|
import { WebSocketServer, WebSocket } from "ws";
|
|
6
6
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
7
|
-
import { readFile as
|
|
7
|
+
import { readFile as readFile3, stat } from "fs/promises";
|
|
8
8
|
import { join as join2 } from "path";
|
|
9
9
|
|
|
10
10
|
// src/ui/auth.service.ts
|
|
@@ -836,6 +836,7 @@ var PREFERRED_PROVIDER_ORDER = [
|
|
|
836
836
|
"anthropic",
|
|
837
837
|
"gemini",
|
|
838
838
|
"openrouter",
|
|
839
|
+
"dashscope-coding-plan",
|
|
839
840
|
"dashscope",
|
|
840
841
|
"deepseek",
|
|
841
842
|
"minimax",
|
|
@@ -3240,6 +3241,12 @@ var ConfigRoutesController = class {
|
|
|
3240
3241
|
pluginUiMetadata: this.options.getPluginUiMetadata?.() ?? []
|
|
3241
3242
|
};
|
|
3242
3243
|
}
|
|
3244
|
+
async publishConfigUpdates(paths) {
|
|
3245
|
+
for (const path of paths) {
|
|
3246
|
+
this.options.publish({ type: "config.updated", payload: { path } });
|
|
3247
|
+
}
|
|
3248
|
+
await this.options.applyLiveConfigReload?.();
|
|
3249
|
+
}
|
|
3243
3250
|
getConfig = (c) => {
|
|
3244
3251
|
const config = loadConfigOrDefault(this.options.configPath);
|
|
3245
3252
|
return c.json(ok(buildConfigView(config, this.getPluginConfigOptions())));
|
|
@@ -3265,12 +3272,14 @@ var ConfigRoutesController = class {
|
|
|
3265
3272
|
model: body.data.model,
|
|
3266
3273
|
workspace: body.data.workspace
|
|
3267
3274
|
});
|
|
3275
|
+
const changedPaths = [];
|
|
3268
3276
|
if (hasModel) {
|
|
3269
|
-
|
|
3277
|
+
changedPaths.push("agents.defaults.model");
|
|
3270
3278
|
}
|
|
3271
3279
|
if (typeof body.data.workspace === "string") {
|
|
3272
|
-
|
|
3280
|
+
changedPaths.push("agents.defaults.workspace");
|
|
3273
3281
|
}
|
|
3282
|
+
await this.publishConfigUpdates(changedPaths);
|
|
3274
3283
|
return c.json(ok({
|
|
3275
3284
|
model: view.agents.defaults.model,
|
|
3276
3285
|
workspace: view.agents.defaults.workspace
|
|
@@ -3282,7 +3291,7 @@ var ConfigRoutesController = class {
|
|
|
3282
3291
|
return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
3283
3292
|
}
|
|
3284
3293
|
const result = updateSearch(this.options.configPath, body.data);
|
|
3285
|
-
this.
|
|
3294
|
+
await this.publishConfigUpdates(["search"]);
|
|
3286
3295
|
return c.json(ok(result));
|
|
3287
3296
|
};
|
|
3288
3297
|
updateProvider = async (c) => {
|
|
@@ -3295,7 +3304,7 @@ var ConfigRoutesController = class {
|
|
|
3295
3304
|
if (!result) {
|
|
3296
3305
|
return c.json(err("NOT_FOUND", `unknown provider: ${provider}`), 404);
|
|
3297
3306
|
}
|
|
3298
|
-
this.
|
|
3307
|
+
await this.publishConfigUpdates([`providers.${provider}`]);
|
|
3299
3308
|
return c.json(ok(result));
|
|
3300
3309
|
};
|
|
3301
3310
|
createProvider = async (c) => {
|
|
@@ -3307,7 +3316,7 @@ var ConfigRoutesController = class {
|
|
|
3307
3316
|
this.options.configPath,
|
|
3308
3317
|
body.data
|
|
3309
3318
|
);
|
|
3310
|
-
this.
|
|
3319
|
+
await this.publishConfigUpdates([`providers.${result.name}`]);
|
|
3311
3320
|
return c.json(ok({
|
|
3312
3321
|
name: result.name,
|
|
3313
3322
|
provider: result.provider
|
|
@@ -3319,7 +3328,7 @@ var ConfigRoutesController = class {
|
|
|
3319
3328
|
if (result === null) {
|
|
3320
3329
|
return c.json(err("NOT_FOUND", `custom provider not found: ${provider}`), 404);
|
|
3321
3330
|
}
|
|
3322
|
-
this.
|
|
3331
|
+
await this.publishConfigUpdates([`providers.${provider}`]);
|
|
3323
3332
|
return c.json(ok({
|
|
3324
3333
|
deleted: true,
|
|
3325
3334
|
provider
|
|
@@ -3385,7 +3394,7 @@ var ConfigRoutesController = class {
|
|
|
3385
3394
|
return c.json(err("NOT_FOUND", "provider auth session not found"), 404);
|
|
3386
3395
|
}
|
|
3387
3396
|
if (result.status === "authorized") {
|
|
3388
|
-
this.
|
|
3397
|
+
await this.publishConfigUpdates([`providers.${provider}`]);
|
|
3389
3398
|
}
|
|
3390
3399
|
return c.json(ok(result));
|
|
3391
3400
|
};
|
|
@@ -3396,7 +3405,7 @@ var ConfigRoutesController = class {
|
|
|
3396
3405
|
if (!result) {
|
|
3397
3406
|
return c.json(err("NOT_SUPPORTED", `provider cli auth import is not supported: ${provider}`), 404);
|
|
3398
3407
|
}
|
|
3399
|
-
this.
|
|
3408
|
+
await this.publishConfigUpdates([`providers.${provider}`]);
|
|
3400
3409
|
return c.json(ok(result));
|
|
3401
3410
|
} catch (error) {
|
|
3402
3411
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -3413,7 +3422,7 @@ var ConfigRoutesController = class {
|
|
|
3413
3422
|
if (!result) {
|
|
3414
3423
|
return c.json(err("NOT_FOUND", `unknown channel: ${channel}`), 404);
|
|
3415
3424
|
}
|
|
3416
|
-
this.
|
|
3425
|
+
await this.publishConfigUpdates([`channels.${channel}`]);
|
|
3417
3426
|
return c.json(ok(result));
|
|
3418
3427
|
};
|
|
3419
3428
|
startChannelAuth = async (c) => {
|
|
@@ -3466,7 +3475,7 @@ var ConfigRoutesController = class {
|
|
|
3466
3475
|
return c.json(err("NOT_FOUND", "channel auth session not found"), 404);
|
|
3467
3476
|
}
|
|
3468
3477
|
if (result.status === "authorized") {
|
|
3469
|
-
this.
|
|
3478
|
+
await this.publishConfigUpdates([`channels.${channel}`]);
|
|
3470
3479
|
}
|
|
3471
3480
|
return c.json(ok(result));
|
|
3472
3481
|
};
|
|
@@ -3476,7 +3485,7 @@ var ConfigRoutesController = class {
|
|
|
3476
3485
|
return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
3477
3486
|
}
|
|
3478
3487
|
const result = updateSecrets(this.options.configPath, body.data);
|
|
3479
|
-
this.
|
|
3488
|
+
await this.publishConfigUpdates(["secrets"]);
|
|
3480
3489
|
return c.json(ok(result));
|
|
3481
3490
|
};
|
|
3482
3491
|
updateRuntime = async (c) => {
|
|
@@ -3485,18 +3494,18 @@ var ConfigRoutesController = class {
|
|
|
3485
3494
|
return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
3486
3495
|
}
|
|
3487
3496
|
const result = updateRuntime(this.options.configPath, body.data);
|
|
3497
|
+
const changedPaths = [];
|
|
3488
3498
|
if (body.data.agents?.defaults && Object.prototype.hasOwnProperty.call(body.data.agents.defaults, "contextTokens")) {
|
|
3489
|
-
|
|
3499
|
+
changedPaths.push("agents.defaults.contextTokens");
|
|
3490
3500
|
}
|
|
3491
3501
|
if (body.data.agents?.defaults && Object.prototype.hasOwnProperty.call(body.data.agents.defaults, "engine")) {
|
|
3492
|
-
|
|
3502
|
+
changedPaths.push("agents.defaults.engine");
|
|
3493
3503
|
}
|
|
3494
3504
|
if (body.data.agents?.defaults && Object.prototype.hasOwnProperty.call(body.data.agents.defaults, "engineConfig")) {
|
|
3495
|
-
|
|
3505
|
+
changedPaths.push("agents.defaults.engineConfig");
|
|
3496
3506
|
}
|
|
3497
|
-
|
|
3498
|
-
this.
|
|
3499
|
-
this.options.publish({ type: "config.updated", payload: { path: "session" } });
|
|
3507
|
+
changedPaths.push("agents.list", "bindings", "session");
|
|
3508
|
+
await this.publishConfigUpdates(changedPaths);
|
|
3500
3509
|
return c.json(ok(result));
|
|
3501
3510
|
};
|
|
3502
3511
|
executeAction = async (c) => {
|
|
@@ -3612,6 +3621,87 @@ var CronRoutesController = class {
|
|
|
3612
3621
|
};
|
|
3613
3622
|
};
|
|
3614
3623
|
|
|
3624
|
+
// src/ui/router/ncp-attachment.controller.ts
|
|
3625
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
3626
|
+
var ATTACHMENT_CONTENT_BASE_PATH = "/api/ncp/attachments/content";
|
|
3627
|
+
function buildAttachmentContentUrl(attachmentUri) {
|
|
3628
|
+
const query = new URLSearchParams({ uri: attachmentUri });
|
|
3629
|
+
return `${ATTACHMENT_CONTENT_BASE_PATH}?${query.toString()}`;
|
|
3630
|
+
}
|
|
3631
|
+
function encodeContentDispositionFileName(fileName) {
|
|
3632
|
+
return encodeURIComponent(fileName).replace(/\*/g, "%2A");
|
|
3633
|
+
}
|
|
3634
|
+
function toAttachmentView(record) {
|
|
3635
|
+
return {
|
|
3636
|
+
id: record.id,
|
|
3637
|
+
name: record.originalName,
|
|
3638
|
+
mimeType: record.mimeType,
|
|
3639
|
+
sizeBytes: record.sizeBytes,
|
|
3640
|
+
attachmentUri: record.uri,
|
|
3641
|
+
url: buildAttachmentContentUrl(record.uri)
|
|
3642
|
+
};
|
|
3643
|
+
}
|
|
3644
|
+
var NcpAttachmentRoutesController = class {
|
|
3645
|
+
constructor(options) {
|
|
3646
|
+
this.options = options;
|
|
3647
|
+
}
|
|
3648
|
+
uploadAttachments = async (c) => {
|
|
3649
|
+
const attachmentApi = this.options.ncpAgent?.attachmentApi;
|
|
3650
|
+
if (!attachmentApi) {
|
|
3651
|
+
return c.json(err("NOT_AVAILABLE", "ncp attachment api unavailable"), 503);
|
|
3652
|
+
}
|
|
3653
|
+
let formData;
|
|
3654
|
+
try {
|
|
3655
|
+
formData = await c.req.raw.formData();
|
|
3656
|
+
} catch {
|
|
3657
|
+
return c.json(err("INVALID_BODY", "invalid multipart body"), 400);
|
|
3658
|
+
}
|
|
3659
|
+
const files = Array.from(formData.values()).reduce((result, value) => {
|
|
3660
|
+
if (typeof value !== "string") {
|
|
3661
|
+
result.push(value);
|
|
3662
|
+
}
|
|
3663
|
+
return result;
|
|
3664
|
+
}, []);
|
|
3665
|
+
if (files.length === 0) {
|
|
3666
|
+
return c.json(err("INVALID_BODY", "no files provided"), 400);
|
|
3667
|
+
}
|
|
3668
|
+
const attachments = [];
|
|
3669
|
+
for (const file of files) {
|
|
3670
|
+
const record = await attachmentApi.saveAttachment({
|
|
3671
|
+
fileName: file.name,
|
|
3672
|
+
mimeType: file.type || null,
|
|
3673
|
+
bytes: new Uint8Array(await file.arrayBuffer())
|
|
3674
|
+
});
|
|
3675
|
+
attachments.push(toAttachmentView(record));
|
|
3676
|
+
}
|
|
3677
|
+
const payload = { attachments };
|
|
3678
|
+
return c.json(ok(payload));
|
|
3679
|
+
};
|
|
3680
|
+
getAttachmentContent = async (c) => {
|
|
3681
|
+
const attachmentApi = this.options.ncpAgent?.attachmentApi;
|
|
3682
|
+
if (!attachmentApi) {
|
|
3683
|
+
return c.json(err("NOT_AVAILABLE", "ncp attachment api unavailable"), 503);
|
|
3684
|
+
}
|
|
3685
|
+
const uri = c.req.query("uri")?.trim();
|
|
3686
|
+
if (!uri) {
|
|
3687
|
+
return c.json(err("INVALID_URI", "attachment uri is required"), 400);
|
|
3688
|
+
}
|
|
3689
|
+
const record = await attachmentApi.statAttachment(uri);
|
|
3690
|
+
const contentPath = attachmentApi.resolveContentPath(uri);
|
|
3691
|
+
if (!record || !contentPath) {
|
|
3692
|
+
return c.json(err("NOT_FOUND", `attachment not found: ${uri}`), 404);
|
|
3693
|
+
}
|
|
3694
|
+
const body = await readFile2(contentPath);
|
|
3695
|
+
return new Response(body, {
|
|
3696
|
+
headers: {
|
|
3697
|
+
"content-length": String(body.byteLength),
|
|
3698
|
+
"content-type": record.mimeType || "application/octet-stream",
|
|
3699
|
+
"content-disposition": `inline; filename*=UTF-8''${encodeContentDispositionFileName(record.originalName)}`
|
|
3700
|
+
}
|
|
3701
|
+
});
|
|
3702
|
+
};
|
|
3703
|
+
};
|
|
3704
|
+
|
|
3615
3705
|
// src/ui/router/ncp-session.controller.ts
|
|
3616
3706
|
function readPositiveInt(value) {
|
|
3617
3707
|
if (typeof value !== "string") {
|
|
@@ -5388,7 +5478,7 @@ function registerSessionRoutes(app, sessionController) {
|
|
|
5388
5478
|
app.put("/api/sessions/:key", sessionController.patchSession);
|
|
5389
5479
|
app.delete("/api/sessions/:key", sessionController.deleteSession);
|
|
5390
5480
|
}
|
|
5391
|
-
function registerNcpRoutes(app, options, ncpSessionController) {
|
|
5481
|
+
function registerNcpRoutes(app, options, ncpSessionController, ncpAttachmentController) {
|
|
5392
5482
|
if (!options.ncpAgent) {
|
|
5393
5483
|
return;
|
|
5394
5484
|
}
|
|
@@ -5403,6 +5493,8 @@ function registerNcpRoutes(app, options, ncpSessionController) {
|
|
|
5403
5493
|
app.put("/api/ncp/sessions/:sessionId", ncpSessionController.patchSession);
|
|
5404
5494
|
app.get("/api/ncp/sessions/:sessionId/messages", ncpSessionController.listSessionMessages);
|
|
5405
5495
|
app.delete("/api/ncp/sessions/:sessionId", ncpSessionController.deleteSession);
|
|
5496
|
+
app.post("/api/ncp/attachments", ncpAttachmentController.uploadAttachments);
|
|
5497
|
+
app.get("/api/ncp/attachments/content", ncpAttachmentController.getAttachmentContent);
|
|
5406
5498
|
}
|
|
5407
5499
|
function registerCronRoutes(app, cronController) {
|
|
5408
5500
|
app.get("/api/cron", cronController.listJobs);
|
|
@@ -5434,6 +5526,7 @@ function createUiRouter(options) {
|
|
|
5434
5526
|
const sessionController = new SessionRoutesController(options);
|
|
5435
5527
|
const cronController = new CronRoutesController(options);
|
|
5436
5528
|
const ncpSessionController = new NcpSessionRoutesController(options);
|
|
5529
|
+
const ncpAttachmentController = new NcpAttachmentRoutesController(options);
|
|
5437
5530
|
const remoteController = options.remoteAccess ? new RemoteRoutesController(options.remoteAccess) : null;
|
|
5438
5531
|
const pluginMarketplaceController = new PluginMarketplaceController(options, marketplaceBaseUrl);
|
|
5439
5532
|
const skillMarketplaceController = new SkillMarketplaceController(options, marketplaceBaseUrl);
|
|
@@ -5458,7 +5551,7 @@ function createUiRouter(options) {
|
|
|
5458
5551
|
registerConfigRoutes(app, configController);
|
|
5459
5552
|
registerChatRoutes(app, chatController);
|
|
5460
5553
|
registerSessionRoutes(app, sessionController);
|
|
5461
|
-
registerNcpRoutes(app, options, ncpSessionController);
|
|
5554
|
+
registerNcpRoutes(app, options, ncpSessionController, ncpAttachmentController);
|
|
5462
5555
|
registerCronRoutes(app, cronController);
|
|
5463
5556
|
registerRemoteRoutes(app, remoteController);
|
|
5464
5557
|
mountMarketplaceRoutes(app, {
|
|
@@ -5564,6 +5657,7 @@ function startUiServer(options) {
|
|
|
5564
5657
|
configPath: options.configPath,
|
|
5565
5658
|
productVersion: options.productVersion,
|
|
5566
5659
|
publish,
|
|
5660
|
+
applyLiveConfigReload: options.applyLiveConfigReload,
|
|
5567
5661
|
marketplace: options.marketplace,
|
|
5568
5662
|
cronService: options.cronService,
|
|
5569
5663
|
chatRuntime: options.chatRuntime,
|
|
@@ -5584,7 +5678,7 @@ function startUiServer(options) {
|
|
|
5584
5678
|
join: join2,
|
|
5585
5679
|
getContent: async (path) => {
|
|
5586
5680
|
try {
|
|
5587
|
-
return await
|
|
5681
|
+
return await readFile3(path);
|
|
5588
5682
|
} catch {
|
|
5589
5683
|
return null;
|
|
5590
5684
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/server",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.57",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Nextclaw UI/API server.",
|
|
6
6
|
"type": "module",
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
"@hono/node-server": "^1.13.3",
|
|
19
19
|
"hono": "^4.6.2",
|
|
20
20
|
"ws": "^8.18.0",
|
|
21
|
-
"@nextclaw/mcp": "0.1.
|
|
22
|
-
"@nextclaw/ncp": "0.3.
|
|
23
|
-
"@nextclaw/ncp
|
|
24
|
-
"@nextclaw/runtime": "0.2.
|
|
25
|
-
"@nextclaw/
|
|
26
|
-
"@nextclaw/
|
|
21
|
+
"@nextclaw/mcp": "0.1.51",
|
|
22
|
+
"@nextclaw/ncp-http-agent-server": "0.3.3",
|
|
23
|
+
"@nextclaw/ncp": "0.3.3",
|
|
24
|
+
"@nextclaw/runtime": "0.2.16",
|
|
25
|
+
"@nextclaw/core": "0.11.2",
|
|
26
|
+
"@nextclaw/openclaw-compat": "0.3.33"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "^20.17.6",
|