@nextclaw/ui 0.12.20-beta.0 → 0.12.20-beta.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.
Files changed (85) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/assets/api-BcqDx0tm.js +15 -0
  3. package/dist/assets/app-manager-provider-DVYBjif-.js +1 -0
  4. package/dist/assets/{app-navigation.config-BORqHkbN.js → app-navigation.config-CMoWvFEI.js} +1 -1
  5. package/dist/assets/{channels-list-page-sISO_4Yj.js → channels-list-page-CsoI4OJm.js} +2 -2
  6. package/dist/assets/{chat-ChCu7LQD.js → chat-CA3aRmhx.js} +6 -6
  7. package/dist/assets/chat-page-gdSN6Pr6.js +1 -0
  8. package/dist/assets/chunk-JZWAC4HX-u4uYphxM.js +3 -0
  9. package/dist/assets/{desktop-update-config-BfJ5iSeY.js → desktop-update-config-CD6-2PfI.js} +1 -1
  10. package/dist/assets/{dialog-B-CXiFPZ.js → dialog-csshWetU.js} +1 -1
  11. package/dist/assets/{dist-DYVfg3q5.js → dist-Bl94Ahwx.js} +1 -1
  12. package/dist/assets/{es2015-BXroVnPi.js → es2015-JCM5-KtW.js} +1 -1
  13. package/dist/assets/index-BTDFuKka.js +2 -0
  14. package/dist/assets/marketplace-page-DJGDpTAo.js +1 -0
  15. package/dist/assets/{marketplace-page-C9oZ01rM.js → marketplace-page-DxlxHCFm.js} +2 -2
  16. package/dist/assets/{mcp-marketplace-page-DuEixgSs.js → mcp-marketplace-page-5UjYRWOR.js} +2 -2
  17. package/dist/assets/mcp-marketplace-page-C1XaHZZO.js +1 -0
  18. package/dist/assets/{model-config-mfhqEZBG.js → model-config-PccJ9XyH.js} +1 -1
  19. package/dist/assets/{notice-card-CozHB03G.js → notice-card-CCgk6FvF.js} +1 -1
  20. package/dist/assets/{popover-CPUPma-w.js → popover-YAsxDBhY.js} +1 -1
  21. package/dist/assets/{provider-scoped-model-input-CL9sti2I.js → provider-scoped-model-input-CzpF7cug.js} +1 -1
  22. package/dist/assets/{providers-list-HPmL2akJ.js → providers-list-8qDMER8o.js} +1 -1
  23. package/dist/assets/remote-D4TtLPAp.js +1 -0
  24. package/dist/assets/runtime-config-page-D-4c5H5z.js +1 -0
  25. package/dist/assets/{search-config-Bcnk9VlL.js → search-config-D3a65l3r.js} +1 -1
  26. package/dist/assets/{secrets-config-Dde-5Y1w.js → secrets-config-CoMlR_7i.js} +2 -2
  27. package/dist/assets/{select-BELPuXLW.js → select-DIZrwsKU.js} +1 -1
  28. package/dist/assets/{sessions-config-page-CG49_0Z6.js → sessions-config-page-Cc0TJStn.js} +2 -2
  29. package/dist/assets/{setting-row-D5DtT6Ny.js → setting-row-DiQyrE81.js} +1 -1
  30. package/dist/assets/{tag-chip-D9BWWgYg.js → tag-chip-C3wDBe_-.js} +1 -1
  31. package/dist/assets/{theme-provider-DeBrTglS.js → theme-provider-aOmrJ9J6.js} +1 -1
  32. package/dist/assets/{tooltip-CI0rpNee.js → tooltip-Dq5Xehpk.js} +1 -1
  33. package/dist/assets/use-config-BQJjq1mP.js +1 -0
  34. package/dist/assets/{use-confirm-dialog-hbynwWf2.js → use-confirm-dialog-DBoV5n5P.js} +1 -1
  35. package/dist/assets/{use-infinite-scroll-loader-Cw5qQr3-.js → use-infinite-scroll-loader-JAicqVC5.js} +1 -1
  36. package/dist/assets/{use-viewport-layout-CWHVDC6z.js → use-viewport-layout-BX3XqzJ4.js} +1 -1
  37. package/dist/index.html +16 -16
  38. package/package.json +8 -6
  39. package/src/app/hooks/use-realtime-query-bridge.ts +5 -5
  40. package/src/features/channels/components/config/channel-form.tsx +3 -3
  41. package/src/features/chat/hooks/use-ncp-chat-page-data.ts +7 -6
  42. package/src/features/chat/pages/ncp-chat-page.test.ts +22 -8
  43. package/src/features/chat/utils/chat-session-preference-governance.utils.test.tsx +114 -0
  44. package/src/features/chat/utils/chat-session-preference-governance.utils.ts +30 -36
  45. package/src/shared/lib/api/index.ts +12 -12
  46. package/src/shared/lib/api/ncp-session.test.ts +17 -18
  47. package/src/shared/lib/api/raw-client.utils.ts +3 -126
  48. package/src/shared/lib/api/services/agents.service.ts +18 -0
  49. package/src/shared/lib/api/services/channel-auth.service.ts +21 -0
  50. package/src/shared/lib/api/{client.ts → services/client.service.ts} +45 -1
  51. package/src/shared/lib/api/services/config.service.ts +171 -0
  52. package/src/shared/lib/api/services/marketplace.service.ts +66 -0
  53. package/src/shared/lib/api/services/mcp-marketplace.service.ts +70 -0
  54. package/src/shared/lib/api/services/ncp-attachments.service.ts +14 -0
  55. package/src/shared/lib/api/services/ncp-session.service.ts +39 -0
  56. package/src/shared/lib/api/services/remote.service.ts +50 -0
  57. package/src/shared/lib/api/services/runtime-control.service.ts +18 -0
  58. package/src/shared/lib/api/services/runtime-update.service.ts +26 -0
  59. package/src/shared/lib/api/services/server-path.service.ts +16 -0
  60. package/src/shared/lib/transport/index.ts +1 -0
  61. package/src/shared/lib/transport/local-transport.service.ts +24 -4
  62. package/src/shared/lib/transport/remote-transport.service.ts +1 -1
  63. package/src/shared/lib/transport/request-raw-api-response.utils.ts +133 -0
  64. package/src/shared/lib/transport/transport.types.ts +8 -2
  65. package/dist/assets/api-C412zuay.js +0 -15
  66. package/dist/assets/app-manager-provider-Cm-KiZZG.js +0 -1
  67. package/dist/assets/chat-page-BCaNZJGT.js +0 -1
  68. package/dist/assets/chunk-JZWAC4HX-DvbcIVPf.js +0 -3
  69. package/dist/assets/index-CqPDhosM.js +0 -2
  70. package/dist/assets/marketplace-page-C8uaWkfd.js +0 -1
  71. package/dist/assets/mcp-marketplace-page-rNqr6ZpD.js +0 -1
  72. package/dist/assets/remote-oDlAdgVA.js +0 -1
  73. package/dist/assets/runtime-config-page-BCshTAAE.js +0 -1
  74. package/dist/assets/use-config-CrWZ_TSF.js +0 -1
  75. package/src/shared/lib/api/agents.ts +0 -34
  76. package/src/shared/lib/api/channel-auth.ts +0 -35
  77. package/src/shared/lib/api/config.ts +0 -362
  78. package/src/shared/lib/api/marketplace.ts +0 -156
  79. package/src/shared/lib/api/mcp-marketplace.ts +0 -138
  80. package/src/shared/lib/api/ncp-attachments.ts +0 -41
  81. package/src/shared/lib/api/ncp-session.ts +0 -78
  82. package/src/shared/lib/api/remote.ts +0 -86
  83. package/src/shared/lib/api/runtime-control.ts +0 -34
  84. package/src/shared/lib/api/runtime-update.service.ts +0 -50
  85. package/src/shared/lib/api/server-path.ts +0 -46
@@ -0,0 +1,16 @@
1
+ import { nextclawClient } from './client.service';
2
+ import type { ServerPathBrowseView, ServerPathReadView } from '@/shared/lib/api/types';
3
+
4
+ export async function fetchServerPathBrowse(params?: {
5
+ path?: string | null;
6
+ includeFiles?: boolean;
7
+ }): Promise<ServerPathBrowseView> {
8
+ return await nextclawClient.serverPaths.browse(params);
9
+ }
10
+
11
+ export async function fetchServerPathRead(params: {
12
+ path: string;
13
+ basePath?: string | null;
14
+ }): Promise<ServerPathReadView> {
15
+ return await nextclawClient.serverPaths.read(params);
16
+ }
@@ -1,4 +1,5 @@
1
1
  export { appClient } from './app-client.service';
2
+ export { requestRawApiResponse } from './request-raw-api-response.utils';
2
3
  export type {
3
4
  AppEvent,
4
5
  AppTransport,
@@ -1,5 +1,6 @@
1
1
  import { systemStatusManager } from '@/features/system-status';
2
2
  import type { AppEvent, AppTransport, RequestInput, StreamInput, StreamSession } from './transport.types';
3
+ import { requestRawApiResponse } from './request-raw-api-response.utils';
3
4
  import { readSseStreamResult } from './sse-stream.utils';
4
5
  import { resolveTransportWebSocketUrl } from './transport-websocket-url.utils';
5
6
 
@@ -139,13 +140,14 @@ export class LocalAppTransport implements AppTransport {
139
140
  const timeoutId = timeoutMs
140
141
  ? window.setTimeout(() => controller?.abort(`Request timed out after ${timeoutMs}ms: ${input.method} ${input.path}`), timeoutMs)
141
142
  : null;
143
+ const requestBody = normalizeRequestBody(input.body);
142
144
 
143
145
  try {
144
- const { requestRawApiResponse } = await import('@/shared/lib/api');
145
- const response = await requestRawApiResponse<T>(input.path, {
146
+ const response = await requestRawApiResponse<T>(this.apiBase, input.path, {
146
147
  method: input.method,
147
- ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),
148
- ...(controller ? { signal: controller.signal } : {})
148
+ ...(requestBody !== undefined ? { body: requestBody } : {}),
149
+ ...(input.headers ? { headers: input.headers } : {}),
150
+ signal: controller?.signal ?? input.signal
149
151
  });
150
152
  if (!response.ok) {
151
153
  throw createTransportError(response, `Request failed for ${input.method} ${input.path}`);
@@ -228,3 +230,21 @@ export class LocalAppTransport implements AppTransport {
228
230
  return this.realtimeGateway.subscribe(handler);
229
231
  };
230
232
  }
233
+
234
+ function normalizeRequestBody(body: unknown): BodyInit | undefined {
235
+ if (body === undefined) {
236
+ return undefined;
237
+ }
238
+ if (
239
+ body instanceof FormData ||
240
+ body instanceof URLSearchParams ||
241
+ body instanceof Blob ||
242
+ body instanceof ArrayBuffer
243
+ ) {
244
+ return body;
245
+ }
246
+ if (typeof body === 'string') {
247
+ return body;
248
+ }
249
+ return JSON.stringify(body);
250
+ }
@@ -1,4 +1,4 @@
1
- import type { ApiError } from '@/shared/lib/api';
1
+ import type { ApiError } from '@nextclaw/server';
2
2
  import type { AppEvent, AppTransport, RemoteRuntimeInfo, RequestInput, StreamInput, StreamSession } from './transport.types';
3
3
  import { resolveTransportWebSocketUrl } from './transport-websocket-url.utils';
4
4
 
@@ -0,0 +1,133 @@
1
+ import type { ApiResponse } from '@nextclaw/server';
2
+ import { systemStatusManager } from '@/features/system-status';
3
+
4
+ function compactSnippet(text: string) {
5
+ return text.replace(/\s+/g, ' ').trim().slice(0, 200);
6
+ }
7
+
8
+ function inferNonJsonHint(endpoint: string, status: number): string | undefined {
9
+ if (
10
+ status === 404 &&
11
+ endpoint.startsWith('/api/config/providers/') &&
12
+ endpoint.endsWith('/test')
13
+ ) {
14
+ return 'Provider test endpoint is missing. This usually means nextclaw runtime version is outdated.';
15
+ }
16
+ if (status === 401 || status === 403) {
17
+ return 'Authentication failed. Check apiKey and custom headers.';
18
+ }
19
+ if (status === 429) {
20
+ return 'Rate limited by upstream provider. Retry later or switch model/provider.';
21
+ }
22
+ if (status >= 500) {
23
+ return 'Upstream service error. Retry later and inspect server logs if it persists.';
24
+ }
25
+ return undefined;
26
+ }
27
+
28
+ function formatUnknownFetchError(error: unknown): {
29
+ summary: string;
30
+ details: Record<string, unknown>;
31
+ } {
32
+ if (error instanceof Error) {
33
+ const name = error.name?.trim() || 'Error';
34
+ const message = error.message?.trim() || 'Unknown error';
35
+ return {
36
+ summary: `${name}: ${message}`,
37
+ details: {
38
+ errorName: name,
39
+ errorMessage: message,
40
+ ...(error.stack?.trim() ? { errorStack: error.stack.trim() } : {})
41
+ }
42
+ };
43
+ }
44
+ return {
45
+ summary: String(error ?? 'Unknown error'),
46
+ details: {
47
+ errorName: 'NonError',
48
+ errorMessage: String(error ?? 'Unknown error')
49
+ }
50
+ };
51
+ }
52
+
53
+ export async function requestRawApiResponse<T>(
54
+ apiBase: string,
55
+ endpoint: string,
56
+ options: RequestInit = {}
57
+ ): Promise<ApiResponse<T>> {
58
+ const url = `${apiBase}${endpoint}`;
59
+ const method = (options.method || 'GET').toUpperCase();
60
+
61
+ let response: Response;
62
+ try {
63
+ const headers = new Headers(options.headers);
64
+ if (!(options.body instanceof FormData) && !headers.has('Content-Type')) {
65
+ headers.set('Content-Type', 'application/json');
66
+ }
67
+ response = await fetch(url, {
68
+ credentials: 'include',
69
+ headers,
70
+ ...options
71
+ });
72
+ } catch (error) {
73
+ const formatted = formatUnknownFetchError(error);
74
+ systemStatusManager.reportTransportFailure(formatted.summary);
75
+ return {
76
+ ok: false,
77
+ error: {
78
+ code: 'NETWORK_ERROR',
79
+ message: `Fetch failed on ${method} ${endpoint} | ${formatted.summary}`,
80
+ details: {
81
+ method,
82
+ endpoint,
83
+ url,
84
+ ...formatted.details
85
+ }
86
+ }
87
+ };
88
+ }
89
+
90
+ const text = await response.text();
91
+ let data: ApiResponse<T> | null = null;
92
+ if (text) {
93
+ try {
94
+ data = JSON.parse(text) as ApiResponse<T>;
95
+ } catch {
96
+ // fall through to build a synthetic error response
97
+ }
98
+ }
99
+
100
+ if (!data) {
101
+ const snippet = text ? compactSnippet(text) : '';
102
+ const hint = inferNonJsonHint(endpoint, response.status);
103
+ const parts = [`Non-JSON response (${response.status} ${response.statusText}) on ${method} ${endpoint}`];
104
+ if (snippet) {
105
+ parts.push(`body=${snippet}`);
106
+ }
107
+ if (hint) {
108
+ parts.push(`hint=${hint}`);
109
+ }
110
+ return {
111
+ ok: false,
112
+ error: {
113
+ code: 'INVALID_RESPONSE',
114
+ message: parts.join(' | '),
115
+ details: {
116
+ status: response.status,
117
+ statusText: response.statusText,
118
+ method,
119
+ endpoint,
120
+ url,
121
+ bodySnippet: snippet || undefined,
122
+ hint
123
+ }
124
+ }
125
+ };
126
+ }
127
+
128
+ if (!response.ok) {
129
+ return data as ApiResponse<T>;
130
+ }
131
+
132
+ return data as ApiResponse<T>;
133
+ }
@@ -1,4 +1,4 @@
1
- import type { WsEvent } from '@/shared/lib/api';
1
+ import type { UiServerEvent } from '@nextclaw/server';
2
2
 
3
3
  export type RequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
4
4
 
@@ -6,6 +6,8 @@ export type RequestInput = {
6
6
  method: RequestMethod;
7
7
  path: string;
8
8
  body?: unknown;
9
+ headers?: Record<string, string>;
10
+ signal?: AbortSignal;
9
11
  timeoutMs?: number;
10
12
  };
11
13
 
@@ -27,7 +29,11 @@ export type StreamSession<TFinal = unknown> = {
27
29
  cancel: () => void;
28
30
  };
29
31
 
30
- export type AppEvent = WsEvent;
32
+ export type AppEvent =
33
+ | UiServerEvent
34
+ | { type: 'connection.open'; payload?: Record<string, never> }
35
+ | { type: 'connection.close'; payload?: Record<string, never> }
36
+ | { type: 'connection.error'; payload?: { message?: string } };
31
37
 
32
38
  export type AppTransport = {
33
39
  request<T>(input: RequestInput): Promise<T>;