@nextclaw/server 0.8.0 → 0.9.1

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
@@ -228,6 +228,7 @@ type SessionHistoryView = {
228
228
  type SessionPatchUpdate = {
229
229
  label?: string | null;
230
230
  preferredModel?: string | null;
231
+ preferredThinking?: ThinkingLevel | null;
231
232
  sessionType?: string | null;
232
233
  clearHistory?: boolean;
233
234
  };
@@ -465,6 +466,7 @@ type UiNcpAgent = {
465
466
  agentClientEndpoint: NcpAgentClientEndpoint;
466
467
  streamProvider?: NcpHttpAgentStreamProvider;
467
468
  sessionApi?: NcpSessionApi;
469
+ listSessionTypes?: () => Promise<ChatSessionTypesView> | ChatSessionTypesView;
468
470
  basePath?: string;
469
471
  };
470
472
  type ConfigView = {
@@ -938,8 +940,8 @@ declare function testProviderConnection(configPath: string, providerName: string
938
940
  declare function updateChannel(configPath: string, channelName: string, patch: Record<string, unknown>): Record<string, unknown> | null;
939
941
  declare const DEFAULT_SESSION_TYPE = "native";
940
942
  declare class SessionPatchValidationError extends Error {
941
- readonly code: "SESSION_TYPE_INVALID" | "SESSION_TYPE_IMMUTABLE" | "SESSION_TYPE_UNAVAILABLE";
942
- constructor(code: "SESSION_TYPE_INVALID" | "SESSION_TYPE_IMMUTABLE" | "SESSION_TYPE_UNAVAILABLE", message: string);
943
+ readonly code: "SESSION_TYPE_INVALID" | "SESSION_TYPE_IMMUTABLE" | "SESSION_TYPE_UNAVAILABLE" | "PREFERRED_THINKING_INVALID";
944
+ constructor(code: "SESSION_TYPE_INVALID" | "SESSION_TYPE_IMMUTABLE" | "SESSION_TYPE_UNAVAILABLE" | "PREFERRED_THINKING_INVALID", message: string);
943
945
  }
944
946
  declare function listSessions(configPath: string, query?: {
945
947
  q?: string;
package/dist/index.js CHANGED
@@ -512,7 +512,7 @@ import {
512
512
  SessionManager,
513
513
  getWorkspacePathFromConfig,
514
514
  normalizeThinkingLevels,
515
- parseThinkingLevel
515
+ parseThinkingLevel as parseThinkingLevel2
516
516
  } from "@nextclaw/core";
517
517
 
518
518
  // src/ui/provider-overrides.ts
@@ -603,6 +603,42 @@ function findServerBuiltinProviderByName(name) {
603
603
  return SERVER_BUILTIN_PROVIDER_OVERRIDE_MAP.get(name) ?? findBuiltinProviderByName(name);
604
604
  }
605
605
 
606
+ // src/ui/session-preference-patch.ts
607
+ import { parseThinkingLevel } from "@nextclaw/core";
608
+ function applySessionPreferencePatch(params) {
609
+ const nextMetadata = params.metadata;
610
+ const { patch } = params;
611
+ if (Object.prototype.hasOwnProperty.call(patch, "label")) {
612
+ const label = typeof patch.label === "string" ? patch.label.trim() : "";
613
+ if (label) {
614
+ nextMetadata.label = label;
615
+ } else {
616
+ delete nextMetadata.label;
617
+ }
618
+ }
619
+ if (Object.prototype.hasOwnProperty.call(patch, "preferredModel")) {
620
+ const preferredModel = typeof patch.preferredModel === "string" ? patch.preferredModel.trim() : "";
621
+ if (preferredModel) {
622
+ nextMetadata.preferred_model = preferredModel;
623
+ } else {
624
+ delete nextMetadata.preferred_model;
625
+ }
626
+ }
627
+ if (Object.prototype.hasOwnProperty.call(patch, "preferredThinking")) {
628
+ const preferredThinking = typeof patch.preferredThinking === "string" ? patch.preferredThinking.trim() : "";
629
+ if (!preferredThinking) {
630
+ delete nextMetadata.preferred_thinking;
631
+ } else {
632
+ const normalizedThinking = parseThinkingLevel(preferredThinking);
633
+ if (!normalizedThinking) {
634
+ throw params.createInvalidThinkingError("preferredThinking must be a supported thinking level");
635
+ }
636
+ nextMetadata.preferred_thinking = normalizedThinking;
637
+ }
638
+ }
639
+ return nextMetadata;
640
+ }
641
+
606
642
  // src/ui/config.ts
607
643
  var MASK_MIN_LENGTH = 8;
608
644
  var EXTRA_SENSITIVE_PATH_PATTERNS = [/authorization/i, /cookie/i, /session/i, /bearer/i];
@@ -955,7 +991,7 @@ function normalizeModelThinkingConfig(input) {
955
991
  if (supported.length === 0) {
956
992
  continue;
957
993
  }
958
- const defaultLevel = parseThinkingLevel(rawValue.default);
994
+ const defaultLevel = parseThinkingLevel2(rawValue.default);
959
995
  if (defaultLevel && supported.includes(defaultLevel)) {
960
996
  normalized[model] = { supported, default: defaultLevel };
961
997
  } else {
@@ -1669,22 +1705,11 @@ function patchSession(configPath, key, patch, options) {
1669
1705
  if (patch.clearHistory) {
1670
1706
  sessionManager.clear(session);
1671
1707
  }
1672
- if (Object.prototype.hasOwnProperty.call(patch, "label")) {
1673
- const label = typeof patch.label === "string" ? patch.label.trim() : "";
1674
- if (label) {
1675
- session.metadata.label = label;
1676
- } else {
1677
- delete session.metadata.label;
1678
- }
1679
- }
1680
- if (Object.prototype.hasOwnProperty.call(patch, "preferredModel")) {
1681
- const preferredModel = typeof patch.preferredModel === "string" ? patch.preferredModel.trim() : "";
1682
- if (preferredModel) {
1683
- session.metadata.preferred_model = preferredModel;
1684
- } else {
1685
- delete session.metadata.preferred_model;
1686
- }
1687
- }
1708
+ applySessionPreferencePatch({
1709
+ metadata: session.metadata,
1710
+ patch,
1711
+ createInvalidThinkingError: (message) => new SessionPatchValidationError("PREFERRED_THINKING_INVALID", message)
1712
+ });
1688
1713
  if (Object.prototype.hasOwnProperty.call(patch, "sessionType")) {
1689
1714
  const normalizedSessionType = normalizeSessionType(patch.sessionType);
1690
1715
  if (!normalizedSessionType) {
@@ -1822,13 +1847,7 @@ function resolveSessionTypeLabel(sessionType) {
1822
1847
  if (sessionType === "native") {
1823
1848
  return "Native";
1824
1849
  }
1825
- if (sessionType === "codex-sdk") {
1826
- return "Codex";
1827
- }
1828
- if (sessionType === "claude-agent-sdk") {
1829
- return "Claude Code";
1830
- }
1831
- return sessionType;
1850
+ return sessionType.trim().split(/[-_]+/g).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ") || sessionType;
1832
1851
  }
1833
1852
  async function buildChatSessionTypesView(chatRuntime) {
1834
1853
  if (!chatRuntime?.listSessionTypes) {
@@ -3283,6 +3302,14 @@ var NcpSessionRoutesController = class {
3283
3302
  constructor(options) {
3284
3303
  this.options = options;
3285
3304
  }
3305
+ getSessionTypes = async (c) => {
3306
+ const listSessionTypes = this.options.ncpAgent?.listSessionTypes;
3307
+ const payload = listSessionTypes ? await listSessionTypes() : {
3308
+ defaultType: "native",
3309
+ options: [{ value: "native", label: "Native" }]
3310
+ };
3311
+ return c.json(ok(payload));
3312
+ };
3286
3313
  listSessions = async (c) => {
3287
3314
  const sessionApi = this.options.ncpAgent?.sessionApi;
3288
3315
  if (!sessionApi) {
@@ -3329,6 +3356,55 @@ var NcpSessionRoutesController = class {
3329
3356
  };
3330
3357
  return c.json(ok(payload));
3331
3358
  };
3359
+ patchSession = async (c) => {
3360
+ const sessionApi = this.options.ncpAgent?.sessionApi;
3361
+ if (!sessionApi) {
3362
+ return c.json(err("NOT_AVAILABLE", "ncp session api unavailable"), 503);
3363
+ }
3364
+ const sessionId = decodeURIComponent(c.req.param("sessionId"));
3365
+ const body = await readJson(c.req.raw);
3366
+ if (!body.ok || !body.data || typeof body.data !== "object") {
3367
+ return c.json(err("INVALID_BODY", "invalid json body"), 400);
3368
+ }
3369
+ const patch = body.data;
3370
+ if (patch.clearHistory) {
3371
+ return c.json(err("UNSUPPORTED_PATCH", "clearHistory is not supported for ncp sessions"), 400);
3372
+ }
3373
+ const existing = await sessionApi.getSession(sessionId);
3374
+ if (!existing) {
3375
+ return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
3376
+ }
3377
+ const metadata = existing.metadata && typeof existing.metadata === "object" && !Array.isArray(existing.metadata) ? existing.metadata : {};
3378
+ let updated;
3379
+ try {
3380
+ const nextMetadata = applySessionPreferencePatch({
3381
+ metadata: structuredClone(metadata),
3382
+ patch,
3383
+ createInvalidThinkingError: () => new Error("PREFERRED_THINKING_INVALID")
3384
+ });
3385
+ if (Object.prototype.hasOwnProperty.call(patch, "sessionType")) {
3386
+ const sessionType = typeof patch.sessionType === "string" ? patch.sessionType.trim() : "";
3387
+ if (sessionType) {
3388
+ nextMetadata.session_type = sessionType;
3389
+ } else {
3390
+ delete nextMetadata.session_type;
3391
+ }
3392
+ }
3393
+ updated = await sessionApi.updateSession(sessionId, {
3394
+ metadata: nextMetadata
3395
+ });
3396
+ } catch (error) {
3397
+ if (error instanceof Error && error.message === "PREFERRED_THINKING_INVALID") {
3398
+ return c.json(err("PREFERRED_THINKING_INVALID", "preferredThinking must be a supported thinking level"), 400);
3399
+ }
3400
+ throw error;
3401
+ }
3402
+ if (!updated) {
3403
+ return c.json(err("NOT_FOUND", `ncp session not found: ${sessionId}`), 404);
3404
+ }
3405
+ this.options.publish({ type: "config.updated", payload: { path: "session" } });
3406
+ return c.json(ok(updated));
3407
+ };
3332
3408
  deleteSession = async (c) => {
3333
3409
  const sessionApi = this.options.ncpAgent?.sessionApi;
3334
3410
  if (!sessionApi) {
@@ -3348,7 +3424,6 @@ var NcpSessionRoutesController = class {
3348
3424
  // src/ui/router/marketplace/constants.ts
3349
3425
  var DEFAULT_MARKETPLACE_API_BASE = "https://marketplace-api.nextclaw.io";
3350
3426
  var NEXTCLAW_PLUGIN_NPM_PREFIX = "@nextclaw/channel-plugin-";
3351
- var CLAWBAY_CHANNEL_PLUGIN_NPM_SPEC = "@clawbay/clawbay-channel";
3352
3427
  var BUILTIN_CHANNEL_PLUGIN_ID_PREFIX = "builtin-channel-";
3353
3428
  var MARKETPLACE_REMOTE_PAGE_SIZE = 100;
3354
3429
  var MARKETPLACE_REMOTE_MAX_PAGES = 20;
@@ -3662,7 +3737,7 @@ function normalizePluginNpmSpec(rawSpec) {
3662
3737
  }
3663
3738
  function isSupportedMarketplacePluginSpec(rawSpec) {
3664
3739
  const spec = normalizePluginNpmSpec(rawSpec);
3665
- return spec.startsWith(NEXTCLAW_PLUGIN_NPM_PREFIX) || spec === CLAWBAY_CHANNEL_PLUGIN_NPM_SPEC;
3740
+ return spec.length > 0;
3666
3741
  }
3667
3742
  function resolvePluginCanonicalSpec(params) {
3668
3743
  const rawInstallSpec = typeof params.installSpec === "string" ? params.installSpec.trim() : "";
@@ -4602,8 +4677,10 @@ function createUiRouter(options) {
4602
4677
  agentClientEndpoint: options.ncpAgent.agentClientEndpoint,
4603
4678
  streamProvider: options.ncpAgent.streamProvider
4604
4679
  });
4680
+ app.get("/api/ncp/session-types", ncpSessionController.getSessionTypes);
4605
4681
  app.get("/api/ncp/sessions", ncpSessionController.listSessions);
4606
4682
  app.get("/api/ncp/sessions/:sessionId", ncpSessionController.getSession);
4683
+ app.put("/api/ncp/sessions/:sessionId", ncpSessionController.patchSession);
4607
4684
  app.get("/api/ncp/sessions/:sessionId/messages", ncpSessionController.listSessionMessages);
4608
4685
  app.delete("/api/ncp/sessions/:sessionId", ncpSessionController.deleteSession);
4609
4686
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/server",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "private": false,
5
5
  "description": "Nextclaw UI/API server.",
6
6
  "type": "module",
@@ -18,11 +18,11 @@
18
18
  "@hono/node-server": "^1.13.3",
19
19
  "hono": "^4.6.2",
20
20
  "ws": "^8.18.0",
21
- "@nextclaw/ncp-http-agent-server": "0.3.0",
22
- "@nextclaw/openclaw-compat": "0.3.0",
23
21
  "@nextclaw/ncp": "0.3.0",
24
- "@nextclaw/runtime": "0.2.0",
25
- "@nextclaw/core": "0.9.0"
22
+ "@nextclaw/ncp-http-agent-server": "0.3.0",
23
+ "@nextclaw/runtime": "0.2.1",
24
+ "@nextclaw/core": "0.9.1",
25
+ "@nextclaw/openclaw-compat": "0.3.2"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^20.17.6",