paseo-plugin-zcode-provider 0.2.0 → 0.4.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.
Files changed (80) hide show
  1. package/NOTICE.md +3 -3
  2. package/README.md +15 -15
  3. package/client/runtime.tsx +1 -1
  4. package/package.json +7 -6
  5. package/server/account.ts +10 -0
  6. package/server/build-info.ts +1 -1
  7. package/server/discovery/manifest.ts +2 -2
  8. package/server/host/bridge.ts +2 -0
  9. package/server/mapping.ts +31 -0
  10. package/server/provider.ts +5 -18
  11. package/server/runtime/pins.ts +7 -5
  12. package/server/session.ts +9 -10
  13. package/server/unsupported-capabilities.ts +21 -0
  14. package/server/vendor/zcode/NOTICE.md +4 -1
  15. package/server/vendor/zcode/packages/rpc/src/channelClient.ts +1 -0
  16. package/server/vendor/zcode/packages/rpc/src/channelServer.ts +2 -0
  17. package/server/vendor/zcode/packages/rpc/src/channels.shared.ts +1 -0
  18. package/server/vendor/zcode/packages/rpc/src/protocol.ts +3 -2
  19. package/server/vendor/zcode/packages/shared/src/app-runtime-preferences.ts +18 -0
  20. package/server/vendor/zcode/packages/shared/src/attachment-source.ts +5 -0
  21. package/server/vendor/zcode/packages/shared/src/bots.ts +385 -2
  22. package/server/vendor/zcode/packages/shared/src/browser-use/commands.ts +3 -1
  23. package/server/vendor/zcode/packages/shared/src/channel-mention.ts +131 -0
  24. package/server/vendor/zcode/packages/shared/src/conversationSelection.ts +37 -0
  25. package/server/vendor/zcode/packages/shared/src/dynamic-workflow-feature.ts +137 -0
  26. package/server/vendor/zcode/packages/shared/src/env.ts +15 -11
  27. package/server/vendor/zcode/packages/shared/src/highspeed.ts +232 -0
  28. package/server/vendor/zcode/packages/shared/src/mcp-apps/appTools.ts +148 -0
  29. package/server/vendor/zcode/packages/shared/src/mcp-apps/contract.ts +262 -0
  30. package/server/vendor/zcode/packages/shared/src/mcp-apps/instance.ts +12 -0
  31. package/server/vendor/zcode/packages/shared/src/mcp-apps/resourceMime.ts +73 -0
  32. package/server/vendor/zcode/packages/shared/src/mcp-apps/sampling.ts +117 -0
  33. package/server/vendor/zcode/packages/shared/src/mcp-apps/schemas.ts +90 -0
  34. package/server/vendor/zcode/packages/shared/src/model-execution.ts +58 -1
  35. package/server/vendor/zcode/packages/shared/src/oauth.ts +3 -0
  36. package/server/vendor/zcode/packages/shared/src/off-peak-execution.ts +73 -0
  37. package/server/vendor/zcode/packages/shared/src/protocol.ts +78 -4
  38. package/server/vendor/zcode/packages/shared/src/remoteTarget.ts +65 -0
  39. package/server/vendor/zcode/packages/shared/src/request-security-edition/verification-policy.ts +46 -0
  40. package/server/vendor/zcode/packages/shared/src/server-remote.ts +93 -0
  41. package/server/vendor/zcode/packages/shared/src/source-server/compatibility.ts +115 -0
  42. package/server/vendor/zcode/packages/shared/src/source-server/contracts.ts +426 -0
  43. package/server/vendor/zcode/packages/shared/src/source-server/errorCodes.ts +74 -0
  44. package/server/vendor/zcode/packages/shared/src/sqlite-migrations/contract.ts +83 -0
  45. package/server/vendor/zcode/packages/shared/src/subagent-profile.ts +62 -0
  46. package/server/vendor/zcode/packages/shared/src/subagent-runtime-config.ts +51 -0
  47. package/server/vendor/zcode/packages/shared/src/subagents-types.ts +164 -0
  48. package/server/vendor/zcode/packages/shared/src/usage-stats.ts +14 -0
  49. package/server/vendor/zcode/packages/shared/src/validationAppSettings.ts +136 -3
  50. package/server/vendor/zcode/packages/shared/src/version.ts +13 -0
  51. package/server/vendor/zcode/packages/shared/src/zcode-agent-policy.ts +24 -1
  52. package/server/vendor/zcode/packages/shared/src/zcode-protocol/index.ts +697 -36
  53. package/server/vendor/zcode/packages/shared/src/zcode-protocol/trace.ts +11 -0
  54. package/server/vendor/zcode/packages/shared/src/zcode-protocol-legacy-types.ts +14 -2
  55. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/apply.ts +28 -9
  56. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/attachment-ref.ts +3 -0
  57. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/command.ts +73 -53
  58. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/create-session-config.ts +15 -0
  59. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/create-workflow-display.ts +47 -1
  60. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/delta.ts +58 -2
  61. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/input-intent.ts +31 -0
  62. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/rows.ts +28 -13
  63. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/sessions-index-workflow-activity.ts +37 -3
  64. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/sessions-index.ts +36 -0
  65. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/snapshot.ts +21 -0
  66. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/submission.ts +1 -1
  67. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/toolDisplay.ts +32 -4
  68. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/transport.ts +31 -6
  69. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-assembler.ts +4 -1
  70. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-fault.ts +4 -1
  71. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-artifacts.ts +62 -4
  72. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-command-rejections.ts +30 -0
  73. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-row-meta.ts +40 -3
  74. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-run-settings-command.ts +2 -2
  75. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-runs-delta.ts +6 -5
  76. package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-runs.ts +103 -26
  77. package/server/vendor/zcode/packages/shared/src/zcode-task-mode-schema.ts +13 -1
  78. package/server/vendor/zcode/packages/shared/src/zcode-task-types-core.ts +31 -2
  79. package/server/vendor/zcode/packages/shared/src/zcodeEndpoint.ts +188 -73
  80. package/server/vendor/zcode/provenance.json +189 -80
@@ -0,0 +1,73 @@
1
+ import { z } from "zod";
2
+ import { modelExecutionSchema } from "./model-execution.js";
3
+
4
+ const identity = { executionId: z.string().min(1), offPeakTaskId: z.string().min(1) };
5
+ export const offPeakLifecycleStateSchema = z.enum([
6
+ "running_idle",
7
+ "waiting_background",
8
+ "waiting_ticket",
9
+ "running_user",
10
+ "completed",
11
+ "cancelled",
12
+ ]);
13
+ export const offPeakOutcomeSchema = z.enum(["succeeded", "failed", "stopped"]);
14
+ export const offPeakLifecycleEventSchema = z.discriminatedUnion("type", [
15
+ z
16
+ .object({ ...identity, type: z.literal("state_changed"), state: offPeakLifecycleStateSchema })
17
+ .strict(),
18
+ z.object({ ...identity, type: z.literal("user_takeover") }).strict(),
19
+ z
20
+ .object({
21
+ ...identity,
22
+ type: z.literal("ticket_needed"),
23
+ renewalId: z.number().int().positive(),
24
+ expiredTicketId: z.string().min(1),
25
+ })
26
+ .strict(),
27
+ z
28
+ .object({ ...identity, type: z.literal("ticket_released"), ticketId: z.string().min(1) })
29
+ .strict(),
30
+ z.object({ ...identity, type: z.literal("completed"), outcome: offPeakOutcomeSchema }).strict(),
31
+ ]);
32
+ const notificationOptions = offPeakLifecycleEventSchema.options.map((schema) =>
33
+ schema.extend({ sessionId: z.string().min(1) }),
34
+ );
35
+ export const offPeakLifecycleNotificationSchema = z.discriminatedUnion("type", [
36
+ notificationOptions[0]!,
37
+ ...notificationOptions.slice(1),
38
+ ]);
39
+ export const offPeakControlParamsSchema = z.discriminatedUnion("action", [
40
+ z
41
+ .object({
42
+ sessionId: z.string().min(1),
43
+ executionId: z.string().min(1),
44
+ action: z.literal("replace_ticket"),
45
+ renewalId: z.number().int().positive(),
46
+ ticketId: z.string().min(1),
47
+ requestAuth: modelExecutionSchema.shape.requestAuth.unwrap(),
48
+ })
49
+ .strict(),
50
+ z
51
+ .object({
52
+ sessionId: z.string().min(1),
53
+ executionId: z.string().min(1),
54
+ action: z.literal("cancel"),
55
+ })
56
+ .strict(),
57
+ ]);
58
+ export const offPeakControlResultSchema = z.object({ accepted: z.boolean() }).strict();
59
+ export type OffPeakLifecycleEvent = z.infer<typeof offPeakLifecycleEventSchema>;
60
+ export type OffPeakLifecycleNotification = z.infer<typeof offPeakLifecycleNotificationSchema>;
61
+ export type OffPeakLifecycleState = z.infer<typeof offPeakLifecycleStateSchema>;
62
+ export type OffPeakOutcome = z.infer<typeof offPeakOutcomeSchema>;
63
+ export type OffPeakControlParams = z.infer<typeof offPeakControlParamsSchema>;
64
+ export type OffPeakControlResult = z.infer<typeof offPeakControlResultSchema>;
65
+ /** 闲时允许 Agent/Bash/SendMessage;工作流运行器和递归派发尚不归本票据管理。 */
66
+ export const OFF_PEAK_EXECUTION_TOOL_DENYLIST = [
67
+ "OffPeakCreate",
68
+ "Workflow",
69
+ "CreateWorkflow",
70
+ "AmendWorkflow",
71
+ "ResumeWorkflowRun",
72
+ "EvalWorkflowSnippet",
73
+ ] as const;
@@ -4,7 +4,9 @@ import type { ProviderFamilyDomain } from "./model-provider-family.js";
4
4
  import type { ProviderFamilyConnectionSelectionSettings } from "./provider-family-connection-selection.js";
5
5
  import type { ZCodeProvider } from "./zcode-task-types-core.js";
6
6
  import type { WorkspacePurpose } from "./workspacePurpose.js";
7
+ import type { DynamicWorkflowMode } from "./dynamic-workflow-feature.js";
7
8
  import type { EmbeddedBrowserViewportPreference } from "./browser-use/command-metadata.js";
9
+ import type { AppToolSearchMode } from "./app-runtime-preferences.js";
8
10
 
9
11
  // ── Domain types ──
10
12
 
@@ -156,14 +158,30 @@ export interface DockerRemoteTargetSnapshot {
156
158
  container: string;
157
159
  }
158
160
 
161
+ export interface ServerRemoteTargetSnapshot {
162
+ kind: "server";
163
+ url: string;
164
+ name?: string;
165
+ workspacePath?: string;
166
+ serverId?: string;
167
+ /**
168
+ * Server token 不写入 setting.json。
169
+ * 这里只保存 credentialService 的键名,恢复时再读取真实 token。
170
+ */
171
+ tokenCredentialKey?: string;
172
+ }
173
+
159
174
  export type RemoteTargetSnapshot =
160
175
  | SSHRemoteTargetSnapshot
161
176
  | WSLRemoteTargetSnapshot
162
- | DockerRemoteTargetSnapshot;
177
+ | DockerRemoteTargetSnapshot
178
+ | ServerRemoteTargetSnapshot;
163
179
 
164
180
  export interface RemoteWorkspaceSessionSnapshot {
165
181
  /** 远程 workspace 的真实绝对路径 */
166
182
  workspacePath: string;
183
+ /** 用户可见的 workspace 分类;旧远端快照缺失时按 project 兼容读取。 */
184
+ workspacePurpose?: WorkspacePurpose;
167
185
  /** 发起远程连接时的本机 workspace 路径,仅用于 MCP filesystem 路径改写。 */
168
186
  localWorkspacePath?: string;
169
187
  /** 远程 workspace 的稳定身份键(authority + canonicalPath)。 */
@@ -272,16 +290,24 @@ export interface AppSettings {
272
290
  * 关闭后按钮不再渲染,且不因重启或版本更新自愈,仅能在设置页重新开启。
273
291
  */
274
292
  computerUseComposerEntryHidden?: boolean;
275
- /** 自动归档已完成旧任务的总开关 */
293
+ /** 自动归档旧会话的总开关 */
276
294
  taskAutoArchiveEnabled?: boolean;
295
+ /** 自动归档修复后的一次性关闭标记;只用于设置迁移,不参与归档判断。 */
296
+ taskAutoArchiveResetVersion?: 1;
277
297
  /** 自动归档阈值;当任务最后更新时间早于该天数时允许被归档 */
278
298
  taskAutoArchiveOlderThanDays?: number;
279
- /** Windows 桌面端关闭窗口时隐藏到托盘;其它平台忽略 */
299
+ /** 桌面端关闭窗口时隐藏到托盘驻留(Windows/Linux;spec:docs/desktop/linux-close-to-tray.md) */
280
300
  closeToTrayOnWindows?: boolean;
281
301
  /** 存在执行中的闲时任务时阻止系统闲置休眠(手动开关,防不了合盖)。 */
282
302
  keepAwakeWhileRunning?: boolean;
283
303
  /** Windows 关闭到托盘默认值是否已执行过一次性迁移;只用于设置迁移,不参与业务判断。 */
284
304
  closeToTrayOnWindowsMigrationInitialized?: boolean;
305
+ /**
306
+ * Linux 关闭到托盘默认值(关)是否已执行过一次性归位迁移。
307
+ * shared 迁移无平台概念、曾把存量 Linux 用户归为 true,而 Linux 此前无设置入口,
308
+ * main 进程 bootstrap 借此标记把首次启动的 Linux 用户一次性归位为默认关。
309
+ */
310
+ closeToTrayLinuxMigrationInitialized?: boolean;
285
311
  /** 桌面端全局页面缩放档位;用于重启后恢复界面缩放,Web/手机端忽略。 */
286
312
  desktopZoomLevel?: number;
287
313
  /** 桌面主窗口最近一次非最大化宽高及最大化状态;Web/手机端忽略。 */
@@ -311,6 +337,13 @@ export interface AppSettings {
311
337
  askUserQuestionAutoResolutionEnabled?: boolean;
312
338
  /** 是否完整保留 Model I/O;开启后不轮转、不限额重置、不压缩或裁剪,鉴权信息仍会脱敏。 */
313
339
  modelIoFullRetentionEnabled?: boolean;
340
+ /**
341
+ * 用户选的动态工作流模式(docs/dynamic-workflow/launch.md「The user's choice」)。缺席 = 跟随服务端
342
+ * 提供的模式;只在功能已提供时生效。选回提供的模式时删除该字段,未改动的安装继续跟随服务端翻转。
343
+ */
344
+ dynamicWorkflowMode?: DynamicWorkflowMode;
345
+ /** 已启用的内置 Agent CLI;UI 对外仍展示为“Install”,底层语义保持为启用内置能力。 */
346
+ enabledBuiltinAgentCliProviders?: ZCodeProvider[];
314
347
  /** 设置页中每个 Provider Family 当前唯一的结构化连接选择。 */
315
348
  providerFamilyConnectionSelections?: ProviderFamilyConnectionSelectionSettings;
316
349
  /** 用户通过 WelcomeScreen 成功连接后确认的 ZAI / BigModel provider family 运行域。 */
@@ -321,6 +354,8 @@ export interface AppSettings {
321
354
  providerFamilyDomainMigrated?: boolean;
322
355
  /** 新建或冷恢复 Session 是否为 Bash 注入 bfs/ugrep 增强;默认启用。 */
323
356
  nativeSearchEnhancementsEnabled?: boolean;
357
+ /** 新建或冷恢复时读取;已有 Runtime 保持原策略。 */
358
+ toolSearchMode?: AppToolSearchMode;
324
359
  /** 新建或冷恢复 Session 是否启用 Memory;默认关闭。 */
325
360
  memoryEnabled?: boolean;
326
361
  onboardingOccupation?:
@@ -340,8 +375,31 @@ export interface AppSettings {
340
375
  | "other"
341
376
  | null;
342
377
  proactiveSuggestionsEnabled?: boolean;
343
- /** 上次关闭时的完整 workspace 会话(含本地与远端 workspace) */
378
+ /** 新版只保存活动执行目录;不表达项目/连接成员,null 表示明确清空。 */
379
+ lastActiveWorkspace?: PersistedWorkspaceSessionEntry | null;
380
+ /** Host 从项目/本机入口派生,供旧版降级读取;新版不作为入口真相。 */
344
381
  lastWorkspaceSession?: PersistedWorkspaceSessionEntry[];
382
+ /** 每个 Source Server 已解析的 canonical conversation backing workspace。 */
383
+ remoteConversationWorkspaceBySourceServerId?: Record<
384
+ string,
385
+ {
386
+ workspacePath: string;
387
+ lastResolvedAt: number;
388
+ }
389
+ >;
390
+ /** R3 控制端已识别的 Source Server;运行态仍由远端 Server 权威提供。 */
391
+ sourceServers?: import("./source-server/contracts.js").SourceServerRecord[];
392
+ /** R3 到达 Source Server 的线路;只保存 credential key,不保存 secret。 */
393
+ connectionProfiles?: import("./source-server/contracts.js").ConnectionProfile[];
394
+ /** R3 workspace 打开历史;连接线路与 workspace 实体分离。 */
395
+ sourceServerWorkspaceHistory?: import("./source-server/contracts.js").SourceServerWorkspaceHistoryEntry[];
396
+ /** 桌面端启动时是否执行 Source Server 静默重连;缺失按 true 兼容旧设置。 */
397
+ remoteStartupAutoReconnectEnabled?: boolean;
398
+ sourceServerDirectoryMigrationVersion?: 1;
399
+ /** 旧客户端只接受 2;保留回滚兼容,新介绍不使用该字段判断已读。 */
400
+ remoteBoundaryOnboardingVersion?: 2;
401
+ /** 仅表示用户明确确认持续运行介绍。 */
402
+ remoteBoundaryIntroAcknowledgedVersion?: 1;
345
403
  /** 上次关闭时激活的 tab 索引 */
346
404
  lastActiveTabIndex?: number;
347
405
  /** 每个 workspace 的最后活跃 taskId,下次打开自动恢复 */
@@ -364,6 +422,22 @@ export interface AppSettings {
364
422
  skippedElectronUpdateVersions?: Partial<Record<ElectronReleaseChannel, string>>;
365
423
  /** 首次启动设置同步提示是否已消费;只表示弹窗不再出现,不代表导入成功。 */
366
424
  settingsSyncFirstRunPromptHandled?: boolean;
425
+ /** 外部 Web 远控 relay 的非敏感设备身份;passHash 必须存 credentialService。 */
426
+ /** V2 非敏感注册身份;JWT 和一次性 token 不持久化于 AppSettings。 */
427
+ webRemoteControlRelayV2Device?: {
428
+ deviceSid: string;
429
+ userId: string;
430
+ endpointOrigin: string;
431
+ };
432
+ webRemoteControlExternalRelayDevice?: {
433
+ deviceSid: string;
434
+ };
435
+ /** 上次成功开启 Web 远控时的目标;缺失表示用户已明确关闭,不自动恢复。 */
436
+ webRemoteControlLastEnabledContext?: {
437
+ workspacePath: string;
438
+ workspaceIdentity?: string;
439
+ initialTaskId?: string;
440
+ };
367
441
  /** 设置页里的临时 endpoint override;正式/测试默认 base url 由 ZCODE_BASE_URL env 管理。 */
368
442
  zcodeEndpointOrigin?: string;
369
443
  }
@@ -0,0 +1,65 @@
1
+ import type { RemoteAssetInstallMode } from "./remoteAssetInstallMode.js";
2
+ import type { RemoteResourcePackageSelection } from "./remoteResourcePackages.js";
3
+
4
+ export interface SSHConnectOptions {
5
+ kind: "ssh";
6
+ host: string;
7
+ port?: number;
8
+ username: string;
9
+ sshConfigAlias?: string;
10
+ password?: string;
11
+ privateKeyPath?: string;
12
+ privateKeyPassphrase?: string;
13
+ assetInstallMode?: RemoteAssetInstallMode;
14
+ resourcePackages?: RemoteResourcePackageSelection;
15
+ }
16
+
17
+ export interface WSLConnectOptions {
18
+ kind: "wsl";
19
+ distro?: string;
20
+ user?: string;
21
+ }
22
+
23
+ export interface DockerConnectOptions {
24
+ kind: "docker";
25
+ container: string;
26
+ }
27
+
28
+ export interface ServerConnectOptions {
29
+ kind: "server";
30
+ /** 已运行的 zcode-server HTTP(S)/WS(S) 入口。 */
31
+ url: string;
32
+ /** 用户可读名称,仅用于展示。 */
33
+ name?: string;
34
+ /** 临时连接凭据;持久化时必须转成 credential key。 */
35
+ token?: string;
36
+ /** 服务端默认工作区路径,可被连接流程中的 workspacePath 覆盖。 */
37
+ workspacePath?: string;
38
+ /** 远端服务实例稳定标识,用于 workspaceIdentity authority。 */
39
+ serverId?: string;
40
+ }
41
+
42
+ export type RemoteTarget =
43
+ | SSHConnectOptions
44
+ | WSLConnectOptions
45
+ | DockerConnectOptions
46
+ | ServerConnectOptions;
47
+
48
+ /** 删除只应存在于当前连接流程中的 secret,供长期内存状态和跨进程回包使用。 */
49
+ export function stripRemoteTargetSecrets(target: RemoteTarget): RemoteTarget {
50
+ if (target.kind === "ssh") {
51
+ const {
52
+ password: _password,
53
+ privateKeyPassphrase: _privateKeyPassphrase,
54
+ ...sanitized
55
+ } = target;
56
+ return sanitized;
57
+ }
58
+
59
+ if (target.kind === "server") {
60
+ const { token: _token, ...sanitized } = target;
61
+ return sanitized;
62
+ }
63
+
64
+ return target;
65
+ }
@@ -0,0 +1,46 @@
1
+ export type RequestVerificationConfig = Readonly<Record<string, unknown>>;
2
+ export type RequestVerificationProof = Record<never, never>;
3
+ export type RequestVerificationClientConfig = Record<never, never>;
4
+ export const requestVerificationReasons = ["model-request"] as const;
5
+ export type RequestVerificationReason = (typeof requestVerificationReasons)[number];
6
+ export const requestVerificationTimeoutMessage =
7
+ "Provider runtime headers request timed out. Please send your message again.";
8
+ export const REQUEST_VERIFICATION_REQUIRED = "request_verification_unavailable";
9
+ export function readRequestVerificationConfig(
10
+ _configs: RequestVerificationClientConfig | null | undefined,
11
+ ): RequestVerificationConfig | null {
12
+ return null;
13
+ }
14
+ export function requestVerificationClaimHeaders(
15
+ _proof: RequestVerificationProof,
16
+ ): Record<string, string> {
17
+ return {};
18
+ }
19
+ export function withoutRequestVerificationHeaders(
20
+ headers: Record<string, string> | undefined,
21
+ ): Record<string, string> {
22
+ return { ...headers };
23
+ }
24
+ export function allowRequestVerificationHeaders(
25
+ _headers: Record<string, string>,
26
+ ): Record<string, string> {
27
+ return {};
28
+ }
29
+ export function requiresRequestVerification(_access: { mode: string } | undefined): boolean {
30
+ return false;
31
+ }
32
+ export function isRequestVerificationMessage(_message: string): boolean {
33
+ return false;
34
+ }
35
+ export function summarizeRequestVerificationHeaders(
36
+ _headers: Record<string, string>,
37
+ ): Record<string, unknown> {
38
+ return {};
39
+ }
40
+ export function requestVerificationDiagnostics(
41
+ _input: Record<string, unknown>,
42
+ ): Record<string, unknown> {
43
+ return {};
44
+ }
45
+
46
+ export const requestVerificationInteractionAvailable = false;
@@ -0,0 +1,93 @@
1
+ import { z } from "zod";
2
+ import { compatibilityManifestSchema } from "./source-server/compatibility.js";
3
+
4
+ export const SERVER_REMOTE_PROTOCOL_VERSION = 1;
5
+
6
+ const serverRemoteWorkspaceInfoShape = {
7
+ path: z.string().trim().min(1),
8
+ label: z.string().trim().min(1).optional(),
9
+ workspaceIdentity: z.string().trim().min(1).optional(),
10
+ };
11
+
12
+ /** 客户端 wire 解析忽略同 protocolVersion 下新增的 optional 字段。 */
13
+ export const serverRemoteWorkspaceInfoSchema = z.object(serverRemoteWorkspaceInfoShape);
14
+
15
+ /** Server 构造自身出参时使用 strict schema,避免意外泄漏字段。 */
16
+ export const serverRemoteWorkspaceInfoOutputSchema = z
17
+ .object(serverRemoteWorkspaceInfoShape)
18
+ .strict();
19
+
20
+ const serverRemoteInfoBaseShape = {
21
+ serverId: z.string().trim().min(1),
22
+ name: z.string().trim().min(1).optional(),
23
+ version: z.string(),
24
+ protocolVersion: z.literal(SERVER_REMOTE_PROTOCOL_VERSION),
25
+ authRequired: z.boolean(),
26
+ };
27
+
28
+ export const serverRemoteInfoSchema = z.object({
29
+ ...serverRemoteInfoBaseShape,
30
+ workspaces: z.array(serverRemoteWorkspaceInfoSchema),
31
+ compatibility: compatibilityManifestSchema.strip().optional(),
32
+ migration: z.object({ failedPathCount: z.number().int().nonnegative() }).optional(),
33
+ identity: z
34
+ .object({
35
+ osUser: z.string().trim().min(1),
36
+ hostname: z.string().trim().min(1),
37
+ })
38
+ .optional(),
39
+ capabilities: z.object({
40
+ desktopContinuous: z.literal(true),
41
+ websocketRpc: z.literal(true),
42
+ virtualProjects: z.literal(true).optional(),
43
+ // 旧 Server 缺少新增 dynamic event,必须先声明能力再订阅,避免异常打进对端读循环。
44
+ processResourceTelemetry: z.boolean().optional(),
45
+ }),
46
+ });
47
+
48
+ export const serverRemoteInfoOutputSchema = z
49
+ .object({
50
+ ...serverRemoteInfoBaseShape,
51
+ workspaces: z.array(serverRemoteWorkspaceInfoOutputSchema),
52
+ compatibility: compatibilityManifestSchema.optional(),
53
+ migration: z.object({ failedPathCount: z.number().int().nonnegative() }).strict().optional(),
54
+ identity: z
55
+ .object({
56
+ osUser: z.string().trim().min(1),
57
+ hostname: z.string().trim().min(1),
58
+ })
59
+ .strict()
60
+ .optional(),
61
+ capabilities: z
62
+ .object({
63
+ desktopContinuous: z.literal(true),
64
+ websocketRpc: z.literal(true),
65
+ virtualProjects: z.literal(true).optional(),
66
+ // 输入和严格输出保持同一能力合同,否则新 Server 会在监听前被自身 schema 拒绝。
67
+ processResourceTelemetry: z.boolean().optional(),
68
+ })
69
+ .strict(),
70
+ })
71
+ .strict();
72
+
73
+ export const serverRemoteAnonymousInfoSchema = z.object({
74
+ version: z.string(),
75
+ protocolVersion: z.literal(SERVER_REMOTE_PROTOCOL_VERSION),
76
+ authRequired: z.literal(true),
77
+ compatibility: compatibilityManifestSchema.strip().optional(),
78
+ });
79
+
80
+ export type ServerRemoteWorkspaceInfo = z.infer<typeof serverRemoteWorkspaceInfoSchema>;
81
+
82
+ export type ServerRemoteInfo = z.infer<typeof serverRemoteInfoSchema>;
83
+
84
+ export type ServerRemoteAnonymousInfo = z.infer<typeof serverRemoteAnonymousInfoSchema>;
85
+
86
+ export const serverRemoteHostCapabilitySchema = z
87
+ .object({
88
+ capability: z.string().trim().min(1),
89
+ expiresAt: z.number().int().positive(),
90
+ })
91
+ .strict();
92
+
93
+ export type ServerRemoteHostCapability = z.infer<typeof serverRemoteHostCapabilitySchema>;
@@ -0,0 +1,115 @@
1
+ import { z } from "zod";
2
+ import { ZCODE_VERSION } from "../version.js";
3
+
4
+ declare const __ZCODE_MIN_COMPATIBLE_VERSION__: string;
5
+
6
+ export const ZCODE_MIN_COMPATIBLE_VERSION =
7
+ typeof __ZCODE_MIN_COMPATIBLE_VERSION__ !== "undefined"
8
+ ? __ZCODE_MIN_COMPATIBLE_VERSION__
9
+ : ZCODE_VERSION;
10
+
11
+ export const compatibilityManifestSchema = z
12
+ .object({
13
+ schemaVersion: z.literal(1),
14
+ productVersion: z.string().trim().min(1),
15
+ minCompatibleVersion: z.string().trim().min(1),
16
+ })
17
+ .strict();
18
+
19
+ export type CompatibilityManifest = z.infer<typeof compatibilityManifestSchema>;
20
+
21
+ export function createCompatibilityManifest(
22
+ productVersion = ZCODE_VERSION,
23
+ minCompatibleVersion = ZCODE_MIN_COMPATIBLE_VERSION,
24
+ ): CompatibilityManifest {
25
+ return compatibilityManifestSchema.parse({
26
+ schemaVersion: 1,
27
+ productVersion,
28
+ minCompatibleVersion,
29
+ });
30
+ }
31
+
32
+ export const ZCODE_COMPATIBILITY_MANIFEST = Object.freeze(createCompatibilityManifest());
33
+
34
+ interface ParsedVersion {
35
+ major: number;
36
+ minor: number;
37
+ patch: number;
38
+ prerelease: string[];
39
+ }
40
+
41
+ function parseVersion(value: string): ParsedVersion {
42
+ const match = value
43
+ .trim()
44
+ .match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/u);
45
+ if (!match) throw new Error(`Invalid compatibility version: ${value}`);
46
+ return {
47
+ major: Number(match[1]),
48
+ minor: Number(match[2]),
49
+ patch: Number(match[3]),
50
+ prerelease: match[4]?.split(".") ?? [],
51
+ };
52
+ }
53
+
54
+ function compareIdentifier(left: string, right: string): number {
55
+ const leftNumeric = /^\d+$/u.test(left);
56
+ const rightNumeric = /^\d+$/u.test(right);
57
+ if (leftNumeric && rightNumeric) return Number(left) - Number(right);
58
+ if (leftNumeric !== rightNumeric) return leftNumeric ? -1 : 1;
59
+ return left.localeCompare(right);
60
+ }
61
+
62
+ export function compareCompatibilityVersions(left: string, right: string): number {
63
+ const a = parseVersion(left);
64
+ const b = parseVersion(right);
65
+ for (const key of ["major", "minor", "patch"] as const) {
66
+ if (a[key] !== b[key]) return a[key] - b[key];
67
+ }
68
+ if (a.prerelease.length === 0 || b.prerelease.length === 0) {
69
+ return a.prerelease.length === b.prerelease.length ? 0 : a.prerelease.length === 0 ? 1 : -1;
70
+ }
71
+ const length = Math.max(a.prerelease.length, b.prerelease.length);
72
+ for (let index = 0; index < length; index += 1) {
73
+ const leftIdentifier = a.prerelease[index];
74
+ const rightIdentifier = b.prerelease[index];
75
+ if (leftIdentifier === undefined || rightIdentifier === undefined) {
76
+ return leftIdentifier === rightIdentifier ? 0 : leftIdentifier === undefined ? -1 : 1;
77
+ }
78
+ const comparison = compareIdentifier(leftIdentifier, rightIdentifier);
79
+ if (comparison !== 0) return comparison;
80
+ }
81
+ return 0;
82
+ }
83
+
84
+ export interface SourceServerCompatibilityResult {
85
+ compatible: boolean;
86
+ updateAvailable: boolean;
87
+ newerEndpoint: "controller" | "server" | "equal";
88
+ upgradeTarget?: "controller" | "server";
89
+ newerVersion: string;
90
+ olderVersion: string;
91
+ requiredMinimumVersion: string;
92
+ }
93
+
94
+ export function evaluateSourceServerCompatibility(
95
+ controller: CompatibilityManifest,
96
+ server: CompatibilityManifest,
97
+ ): SourceServerCompatibilityResult {
98
+ const comparison = compareCompatibilityVersions(controller.productVersion, server.productVersion);
99
+ const newerEndpoint = comparison > 0 ? "controller" : comparison < 0 ? "server" : "equal";
100
+ const newer = comparison >= 0 ? controller : server;
101
+ const older = comparison >= 0 ? server : controller;
102
+ const compatible =
103
+ compareCompatibilityVersions(older.productVersion, newer.minCompatibleVersion) >= 0;
104
+ return {
105
+ compatible,
106
+ updateAvailable: comparison !== 0,
107
+ newerEndpoint,
108
+ ...(!compatible
109
+ ? { upgradeTarget: comparison >= 0 ? ("server" as const) : ("controller" as const) }
110
+ : {}),
111
+ newerVersion: newer.productVersion,
112
+ olderVersion: older.productVersion,
113
+ requiredMinimumVersion: newer.minCompatibleVersion,
114
+ };
115
+ }