@gestaltrun/dsh-workspace-bundle 0.0.0-stage → 0.1.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 (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.i18n.yaml +37 -0
  3. package/README.md +92 -2
  4. package/README.zh.md +93 -0
  5. package/lib/index.js +2868 -0
  6. package/lib/types/agent-config-contract/agent-configs.d.ts +621 -0
  7. package/lib/types/agent-config-contract/agent-configs.js +68 -0
  8. package/lib/types/agent-config-contract/cs-hosting.d.ts +1333 -0
  9. package/lib/types/agent-config-contract/cs-hosting.js +163 -0
  10. package/lib/types/agent-config-contract/errors.d.ts +224 -0
  11. package/lib/types/agent-config-contract/errors.js +202 -0
  12. package/lib/types/agent-config-contract/ids.d.ts +65 -0
  13. package/lib/types/agent-config-contract/ids.js +35 -0
  14. package/lib/types/agent-config-contract/route.d.ts +56 -0
  15. package/lib/types/agent-config-contract/route.js +1 -0
  16. package/lib/types/agent-config-contract/test-account-claim.d.ts +24 -0
  17. package/lib/types/agent-config-contract/test-account-claim.js +5 -0
  18. package/lib/types/agent-config-format.d.ts +86 -0
  19. package/lib/types/agent-config-format.js +119 -0
  20. package/lib/types/agent-config-observation.d.ts +64 -0
  21. package/lib/types/agent-config-observation.js +448 -0
  22. package/lib/types/agent-config-source.d.ts +78 -0
  23. package/lib/types/agent-config-source.js +411 -0
  24. package/lib/types/agent-config-types.d.ts +67 -0
  25. package/lib/types/agent-config-types.js +1 -0
  26. package/lib/types/bundled-agent-config.d.ts +29 -0
  27. package/lib/types/bundled-agent-config.js +47 -0
  28. package/lib/types/config.d.ts +34 -0
  29. package/lib/types/config.js +53 -0
  30. package/lib/types/definition.d.ts +82 -0
  31. package/lib/types/definition.js +20 -0
  32. package/lib/types/digest.d.ts +38 -0
  33. package/lib/types/digest.js +243 -0
  34. package/lib/types/errors.d.ts +22 -0
  35. package/lib/types/errors.js +26 -0
  36. package/lib/types/filesystem.d.ts +16 -0
  37. package/lib/types/filesystem.js +64 -0
  38. package/lib/types/index.d.ts +28 -0
  39. package/lib/types/index.js +19 -0
  40. package/lib/types/journal.d.ts +51 -0
  41. package/lib/types/journal.js +109 -0
  42. package/lib/types/local-host-identity.d.ts +65 -0
  43. package/lib/types/local-host-identity.js +87 -0
  44. package/lib/types/local-host-replacement.d.ts +49 -0
  45. package/lib/types/local-host-replacement.js +112 -0
  46. package/lib/types/paths.d.ts +26 -0
  47. package/lib/types/paths.js +48 -0
  48. package/lib/types/provider.d.ts +83 -0
  49. package/lib/types/provider.js +560 -0
  50. package/lib/types/session-events.d.ts +23 -0
  51. package/lib/types/session-events.js +14 -0
  52. package/lib/types/types.d.ts +126 -0
  53. package/lib/types/types.js +1 -0
  54. package/locale/en.json +6 -0
  55. package/locale/zh.json +6 -0
  56. package/package.json +69 -3
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Branded identifiers. Each is a UUID string; the brand keeps ids of different entities apart at compile time.
3
+ * @module
4
+ */
5
+ import { z } from 'zod';
6
+ /** Identifier of a user. */
7
+ export declare const UserId: z.core.$ZodBranded<z.ZodUUID, "UserId", "out">;
8
+ /** Identifier of a user. */
9
+ export type UserId = z.infer<typeof UserId>;
10
+ /** Identifier of a tenant. */
11
+ export declare const TenantId: z.core.$ZodBranded<z.ZodUUID, "TenantId", "out">;
12
+ /** Identifier of a tenant. */
13
+ export type TenantId = z.infer<typeof TenantId>;
14
+ /** Identifier of a login attempt. */
15
+ export declare const LoginAttemptId: z.core.$ZodBranded<z.ZodUUID, "LoginAttemptId", "out">;
16
+ /** Identifier of a login attempt. */
17
+ export type LoginAttemptId = z.infer<typeof LoginAttemptId>;
18
+ /** Identifier of a role defined by a tenant. */
19
+ export declare const RoleId: z.core.$ZodBranded<z.ZodUUID, "RoleId", "out">;
20
+ /** Identifier of a role defined by a tenant. */
21
+ export type RoleId = z.infer<typeof RoleId>;
22
+ /** Identifier of a supplier. */
23
+ export declare const SupplierId: z.core.$ZodBranded<z.ZodUUID, "SupplierId", "out">;
24
+ /** Identifier of a supplier. */
25
+ export type SupplierId = z.infer<typeof SupplierId>;
26
+ /** Identifier of a supplier's contact. */
27
+ export declare const ContactId: z.core.$ZodBranded<z.ZodUUID, "ContactId", "out">;
28
+ /** Identifier of a supplier's contact. */
29
+ export type ContactId = z.infer<typeof ContactId>;
30
+ /** Identifier of a contract with a supplier. */
31
+ export declare const ContractId: z.core.$ZodBranded<z.ZodUUID, "ContractId", "out">;
32
+ /** Identifier of a contract with a supplier. */
33
+ export type ContractId = z.infer<typeof ContractId>;
34
+ /** Identifier of a supplier qualification, stable across updates and reordering. */
35
+ export declare const QualificationId: z.core.$ZodBranded<z.ZodUUID, "QualificationId", "out">;
36
+ /** Identifier of a supplier qualification. */
37
+ export type QualificationId = z.infer<typeof QualificationId>;
38
+ /** Identifier of a resource. */
39
+ export declare const ResourceId: z.core.$ZodBranded<z.ZodUUID, "ResourceId", "out">;
40
+ /** Identifier of a resource. */
41
+ export type ResourceId = z.infer<typeof ResourceId>;
42
+ /** Identifier of a sub-resource. */
43
+ export declare const SubResourceId: z.core.$ZodBranded<z.ZodUUID, "SubResourceId", "out">;
44
+ /** Identifier of a sub-resource. */
45
+ export type SubResourceId = z.infer<typeof SubResourceId>;
46
+ /** Identifier of an invite link. */
47
+ export declare const InviteId: z.core.$ZodBranded<z.ZodUUID, "InviteId", "out">;
48
+ /** Identifier of an invite link. */
49
+ export type InviteId = z.infer<typeof InviteId>;
50
+ /** Identifier of a sub-resource price rule. */
51
+ export declare const PriceRuleId: z.core.$ZodBranded<z.ZodUUID, "PriceRuleId", "out">;
52
+ /** Identifier of a price rule. */
53
+ export type PriceRuleId = z.infer<typeof PriceRuleId>;
54
+ /** Identifier of an object-storage file (an asset). */
55
+ export declare const AssetId: z.core.$ZodBranded<z.ZodUUID, "AssetId", "out">;
56
+ /** Identifier of an asset. */
57
+ export type AssetId = z.infer<typeof AssetId>;
58
+ /** Identifier of a source material. */
59
+ export declare const MaterialId: z.core.$ZodBranded<z.ZodUUID, "MaterialId", "out">;
60
+ /** Identifier of a source material. */
61
+ export type MaterialId = z.infer<typeof MaterialId>;
62
+ /** Identifier of a material reference. */
63
+ export declare const MaterialReferenceId: z.core.$ZodBranded<z.ZodUUID, "MaterialReferenceId", "out">;
64
+ /** Identifier of a material reference. */
65
+ export type MaterialReferenceId = z.infer<typeof MaterialReferenceId>;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Branded identifiers. Each is a UUID string; the brand keeps ids of different entities apart at compile time.
3
+ * @module
4
+ */
5
+ import { z } from 'zod';
6
+ /** Identifier of a user. */
7
+ export const UserId = z.uuid().brand();
8
+ /** Identifier of a tenant. */
9
+ export const TenantId = z.uuid().brand();
10
+ /** Identifier of a login attempt. */
11
+ export const LoginAttemptId = z.uuid().brand();
12
+ /** Identifier of a role defined by a tenant. */
13
+ export const RoleId = z.uuid().brand();
14
+ /** Identifier of a supplier. */
15
+ export const SupplierId = z.uuid().brand();
16
+ /** Identifier of a supplier's contact. */
17
+ export const ContactId = z.uuid().brand();
18
+ /** Identifier of a contract with a supplier. */
19
+ export const ContractId = z.uuid().brand();
20
+ /** Identifier of a supplier qualification, stable across updates and reordering. */
21
+ export const QualificationId = z.uuid().brand();
22
+ /** Identifier of a resource. */
23
+ export const ResourceId = z.uuid().brand();
24
+ /** Identifier of a sub-resource. */
25
+ export const SubResourceId = z.uuid().brand();
26
+ /** Identifier of an invite link. */
27
+ export const InviteId = z.uuid().brand();
28
+ /** Identifier of a sub-resource price rule. */
29
+ export const PriceRuleId = z.uuid().brand();
30
+ /** Identifier of an object-storage file (an asset). */
31
+ export const AssetId = z.uuid().brand();
32
+ /** Identifier of a source material. */
33
+ export const MaterialId = z.uuid().brand();
34
+ /** Identifier of a material reference. */
35
+ export const MaterialReferenceId = z.uuid().brand();
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Framework-free route descriptions: the server binds them to handlers, clients read them to build requests.
3
+ * @module
4
+ */
5
+ import type { z } from 'zod';
6
+ import type { ErrorCode } from './errors.ts';
7
+ /** A response of one status code: a JSON body described by `schema`, or no body when `schema` is absent. */
8
+ export interface ResponseDefinition {
9
+ readonly description: string;
10
+ readonly schema?: z.ZodType;
11
+ readonly headers?: Readonly<Record<string, {
12
+ readonly description: string;
13
+ readonly schema: z.ZodType;
14
+ }>>;
15
+ }
16
+ /** Path parameters, query parameters and JSON request body of one endpoint. */
17
+ export interface RequestDefinition {
18
+ readonly params?: z.ZodObject;
19
+ readonly query?: z.ZodObject;
20
+ readonly headers?: z.ZodObject;
21
+ readonly body?: z.ZodType;
22
+ }
23
+ /**
24
+ * Who may call an endpoint. `session`: the request carries `Authorization: Bearer <session token>`,
25
+ * and a missing token answers 401 `SESSION_REQUIRED`, an unknown, expired or revoked one 401
26
+ * `SESSION_EXPIRED`. `tenant`: a `session` route under `/v1/tenants/{tenantId}` that acts in the
27
+ * session's current tenant; after the session checks, the server answers 403 `NO_CURRENT_TENANT`
28
+ * when the session has no current tenant (personal use), 409 `TENANT_NOT_CURRENT` when `tenantId`
29
+ * is not the current tenant (a request sent before the client switched), and 403 `NOT_A_MEMBER`
30
+ * when the user is no longer a member of it. Each of the three means the client's view of the
31
+ * current tenant is stale (a switch in another window, or removal from the tenant, which also
32
+ * clears the session's current tenant): the client reloads `GET /v1/me` and closes pages that no
33
+ * longer apply before it shows anything; for 409 it shows no failure at all. The codes are
34
+ * `TENANT_CONTEXT_CODES`. `none`: callable without a session.
35
+ */
36
+ /** `operator`:独立运维令牌,缺少时 OPERATOR_SESSION_REQUIRED,失效时 OPERATOR_SESSION_EXPIRED;与商家会话互不替代。 */
37
+ /** `service`:server 签发的服务凭据,`Authorization: Bearer`。缺少时 401 `SERVICE_CREDENTIAL_REQUIRED`,不匹配时 401 `SERVICE_CREDENTIAL_REJECTED`。 */
38
+ /** `space`:WeKnora 数据源保存的空间令牌,`Authorization: Bearer`。缺少时 401 `SPACE_TOKEN_REQUIRED`,不匹配时 401 `SPACE_TOKEN_REJECTED`。令牌绑定的主账号没有店铺租户时 403 `SEGMENT_SPACE_FORBIDDEN`。 */
39
+ export type RouteAuth = 'session' | 'tenant' | 'operator' | 'service' | 'space' | 'none';
40
+ /** Method, path, request, success responses and route-specific problem codes of one v1 endpoint. */
41
+ export interface RouteDefinition {
42
+ readonly method: 'get' | 'post' | 'put' | 'patch' | 'delete';
43
+ /** OpenAPI path template, such as `/v1/tenants/{tenantId}`. */
44
+ readonly path: string;
45
+ readonly summary: string;
46
+ readonly auth: RouteAuth;
47
+ readonly request?: RequestDefinition;
48
+ readonly responses: Readonly<Record<number, ResponseDefinition>>;
49
+ /**
50
+ * Problem codes this route answers, by HTTP status, besides the ones every `/v1` route can answer
51
+ * (422 `VALIDATION_FAILED`, 426 `CLIENT_UPGRADE_REQUIRED`, 500 `INTERNAL`).
52
+ */
53
+ /** 错误响应的可选头;请求与响应声明仍由契约包拥有。 */
54
+ readonly problemHeaders?: Readonly<Record<number, NonNullable<ResponseDefinition['headers']>>>;
55
+ readonly problems?: Readonly<Record<number, readonly ErrorCode[]>>;
56
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ /** 测试账号当前占用;不自动过期,Issue 仓库与编号共同标识持有方。 */
2
+ import { z } from 'zod';
3
+ export declare const TestAccountIssue: z.ZodObject<{
4
+ repo: z.ZodDefault<z.ZodString>;
5
+ number: z.ZodNumber;
6
+ }, z.core.$strict>;
7
+ export declare const TestAccountClaim: z.ZodObject<{
8
+ issue: z.ZodObject<{
9
+ repo: z.ZodDefault<z.ZodString>;
10
+ number: z.ZodNumber;
11
+ }, z.core.$strict>;
12
+ demandName: z.ZodString;
13
+ claimedAt: z.ZodISODateTime;
14
+ }, z.core.$strict>;
15
+ export type TestAccountClaim = z.infer<typeof TestAccountClaim>;
16
+ export declare const SandboxUpgradeHold: z.ZodObject<{
17
+ issue: z.ZodObject<{
18
+ repo: z.ZodDefault<z.ZodString>;
19
+ number: z.ZodNumber;
20
+ }, z.core.$strict>;
21
+ demandName: z.ZodString;
22
+ claimedAt: z.ZodISODateTime;
23
+ targetVersion: z.ZodNullable<z.ZodString>;
24
+ }, z.core.$strict>;
@@ -0,0 +1,5 @@
1
+ /** 测试账号当前占用;不自动过期,Issue 仓库与编号共同标识持有方。 */
2
+ import { z } from 'zod';
3
+ export const TestAccountIssue = z.strictObject({ repo: z.string().regex(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/).max(201).default('gestaltrun/deepseek-harness'), number: z.number().int().positive().max(Number.MAX_SAFE_INTEGER) });
4
+ export const TestAccountClaim = z.strictObject({ issue: TestAccountIssue, demandName: z.string().trim().min(1).max(300), claimedAt: z.iso.datetime() }).meta({ id: 'TestAccountClaim' });
5
+ export const SandboxUpgradeHold = TestAccountClaim.extend({ targetVersion: z.string().nullable().describe('当前因占用被跳过的自动升级版本;尚未跳过为 null') }).meta({ id: 'SandboxUpgradeHold' });
@@ -0,0 +1,86 @@
1
+ import { z } from 'zod';
2
+ /** 本 Host 实现的 Agent 配置接口版本;白名单与写操作授权由 Host 保持。 */
3
+ export declare const HOST_AGENT_CONFIG_API_VERSION = "2.0.0";
4
+ /** Agent 配置 SHA-256 的十六进制编码。 */
5
+ export declare const AgentConfigSha256: z.ZodString;
6
+ /** 内置 Workspace 种类;不含路径分隔符。 */
7
+ export declare const WorkspaceKind: z.ZodString;
8
+ /** @param value - 完整 Agent 配置版本。 @returns 是否为保留构建元数据的规范 SemVer;优先级由 semver 按规范比较。 */
9
+ export declare function isAgentConfigVersion(value: string): boolean;
10
+ /** server 分配中可公开的包信息,未携带商家凭据。 */
11
+ export declare const AgentConfigDescriptorSchema: z.ZodObject<{
12
+ workspaceKind: z.ZodString;
13
+ version: z.ZodString;
14
+ sha256: z.ZodString;
15
+ sizeBytes: z.ZodNumber;
16
+ downloadUrl: z.ZodURL;
17
+ hostAgentConfigApiRange: z.ZodString;
18
+ runtimeApiRange: z.ZodOptional<z.ZodString>;
19
+ releaseNotes: z.ZodString;
20
+ }, z.core.$strict>;
21
+ /** 经解析的 server 分配。 */
22
+ export type AgentConfigDescriptor = z.infer<typeof AgentConfigDescriptorSchema>;
23
+ /** 包内逐文件摘要与字节数,文件路径相对版本目录。 */
24
+ export declare const AgentConfigManifestSchema: z.ZodObject<{
25
+ formatVersion: z.ZodLiteral<1>;
26
+ workspaceKind: z.ZodString;
27
+ version: z.ZodString;
28
+ hostAgentConfigApiRange: z.ZodString;
29
+ files: z.ZodArray<z.ZodObject<{
30
+ path: z.ZodString;
31
+ sizeBytes: z.ZodNumber;
32
+ sha256: z.ZodString;
33
+ }, z.core.$strict>>;
34
+ }, z.core.$strict>;
35
+ /** 确定性 gzip JSON Agent 配置:清单和按同序排列的 base64 文件。 */
36
+ export declare const AgentConfigDocumentSchema: z.ZodObject<{
37
+ manifest: z.ZodObject<{
38
+ formatVersion: z.ZodLiteral<1>;
39
+ workspaceKind: z.ZodString;
40
+ version: z.ZodString;
41
+ hostAgentConfigApiRange: z.ZodString;
42
+ files: z.ZodArray<z.ZodObject<{
43
+ path: z.ZodString;
44
+ sizeBytes: z.ZodNumber;
45
+ sha256: z.ZodString;
46
+ }, z.core.$strict>>;
47
+ }, z.core.$strict>;
48
+ files: z.ZodArray<z.ZodObject<{
49
+ path: z.ZodString;
50
+ base64: z.ZodString;
51
+ }, z.core.$strict>>;
52
+ }, z.core.$strict>;
53
+ /** 包内文件清单。 */
54
+ export type AgentConfigManifest = z.infer<typeof AgentConfigManifestSchema>;
55
+ /** 已解码并校验的文件。 */
56
+ export interface AgentConfigFile {
57
+ readonly path: string;
58
+ readonly bytes: Buffer;
59
+ }
60
+ /** 内容更新失败类型;报告不包含下载 URL、响应正文或凭据。 */
61
+ export type AgentConfigErrorCode = 'AGENT_CONFIG_QUERY_FAILED' | 'AGENT_CONFIG_INVALID' | 'AGENT_CONFIG_INCOMPATIBLE' | 'AGENT_CONFIG_DIGEST_MISMATCH' | 'AGENT_CONFIG_DOWNLOAD_FAILED' | 'AGENT_CONFIG_APPLY_FAILED' | 'AGENT_CONFIG_SCOPE_CHANGED';
62
+ /** 有界内容更新的结构化失败。 */
63
+ export declare class AgentConfigError extends Error {
64
+ readonly code: AgentConfigErrorCode;
65
+ /** @param code - 失败类别。 @param disposition - candidate 保留当前版本;blocked 表示已提交内容不可执行。 */
66
+ constructor(code: AgentConfigErrorCode, disposition?: 'candidate' | 'blocked');
67
+ }
68
+ /** @param bytes - 完整文件字节。 @returns SHA-256 小写十六进制编码。 */
69
+ export declare function agentConfigSha256(bytes: Uint8Array): string;
70
+ /**
71
+ * 拒绝无法在各 Host 文件系统安全表达的相对路径。
72
+ * @param path - 包内 POSIX 路径。
73
+ * @returns 原始路径。
74
+ */
75
+ export declare function contentPath(path: string): string;
76
+ /**
77
+ * 同时认证压缩包和逐文件字节,任何失败均发生在版本目录写入前。
78
+ * @param bytes - 下载的完整 gzip 字节。
79
+ * @param descriptor - server 经鉴权查询给出的登记信息。
80
+ * @param maxExpandedBytes - 解压 JSON 和文件总字节上限。
81
+ * @returns 清单和已校验文件。
82
+ */
83
+ export declare function decodeAgentConfig<D extends Pick<AgentConfigDescriptor, 'workspaceKind' | 'version' | 'sha256' | 'sizeBytes' | 'hostAgentConfigApiRange'>>(bytes: Buffer, descriptor: D, maxExpandedBytes: number): {
84
+ readonly manifest: AgentConfigManifest;
85
+ readonly files: readonly AgentConfigFile[];
86
+ };
@@ -0,0 +1,119 @@
1
+ /** 内置 Workspace Agent 配置的文件校验;目录和压缩字节的大小均由部署配置限制。 */
2
+ import { createHash } from 'node:crypto';
3
+ import { gunzipSync } from 'node:zlib';
4
+ import semver from 'semver';
5
+ import { z } from 'zod';
6
+ import { assertTemplateRelativePath } from "./paths.js";
7
+ /** 本 Host 实现的 Agent 配置接口版本;白名单与写操作授权由 Host 保持。 */
8
+ export const HOST_AGENT_CONFIG_API_VERSION = '2.0.0';
9
+ /** Agent 配置 SHA-256 的十六进制编码。 */
10
+ export const AgentConfigSha256 = z.string().regex(/^[a-f0-9]{64}$/u);
11
+ /** 内置 Workspace 种类;不含路径分隔符。 */
12
+ export const WorkspaceKind = z.string().regex(/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u).max(80);
13
+ /** @param value - 完整 Agent 配置版本。 @returns 是否为保留构建元数据的规范 SemVer;优先级由 semver 按规范比较。 */
14
+ export function isAgentConfigVersion(value) {
15
+ const parsed = semver.parse(value);
16
+ return parsed !== null && `${parsed.version}${parsed.build.length === 0 ? '' : `+${parsed.build.join('.')}`}` === value;
17
+ }
18
+ /** server 分配中可公开的包信息,未携带商家凭据。 */
19
+ export const AgentConfigDescriptorSchema = z.strictObject({
20
+ workspaceKind: WorkspaceKind,
21
+ version: z.string().refine(isAgentConfigVersion),
22
+ sha256: AgentConfigSha256,
23
+ sizeBytes: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
24
+ downloadUrl: z.url(),
25
+ hostAgentConfigApiRange: z.string().refine(value => semver.validRange(value) !== null),
26
+ runtimeApiRange: z.string().refine(value => semver.validRange(value) !== null).optional(),
27
+ releaseNotes: z.string().min(1).max(20000),
28
+ });
29
+ /** 包内逐文件摘要与字节数,文件路径相对版本目录。 */
30
+ export const AgentConfigManifestSchema = z.strictObject({
31
+ formatVersion: z.literal(1), workspaceKind: WorkspaceKind,
32
+ version: z.string().refine(isAgentConfigVersion),
33
+ hostAgentConfigApiRange: z.string().refine(value => semver.validRange(value) !== null),
34
+ files: z.array(z.strictObject({ path: z.string(), sizeBytes: z.number().int().nonnegative(), sha256: AgentConfigSha256 })).min(1).max(10000),
35
+ });
36
+ /** 确定性 gzip JSON Agent 配置:清单和按同序排列的 base64 文件。 */
37
+ export const AgentConfigDocumentSchema = z.strictObject({
38
+ manifest: AgentConfigManifestSchema,
39
+ files: z.array(z.strictObject({ path: z.string(), base64: z.string() })).min(1).max(10000),
40
+ });
41
+ /** 有界内容更新的结构化失败。 */
42
+ export class AgentConfigError extends Error {
43
+ code;
44
+ /** @param code - 失败类别。 @param disposition - candidate 保留当前版本;blocked 表示已提交内容不可执行。 */
45
+ constructor(code, disposition = 'candidate') {
46
+ const messages = {
47
+ AGENT_CONFIG_QUERY_FAILED: 'Agent 配置版本查询失败,保留当前版本;请检查服务器连接。',
48
+ AGENT_CONFIG_INVALID: 'Agent 配置文件或清单无效,保留当前版本;请重新打包发布。',
49
+ AGENT_CONFIG_INCOMPATIBLE: 'Agent 配置不兼容当前 Host,保留当前版本;请分配兼容版本或升级客户端。',
50
+ AGENT_CONFIG_DIGEST_MISMATCH: 'Agent 配置摘要不匹配,保留当前版本;请核对发布登记。',
51
+ AGENT_CONFIG_DOWNLOAD_FAILED: 'Agent 配置下载失败,保留当前版本;请检查文件服务连接。',
52
+ AGENT_CONFIG_APPLY_FAILED: 'Agent 配置应用失败;请检查工作区恢复状态后再继续。',
53
+ AGENT_CONFIG_SCOPE_CHANGED: 'Agent 配置版本来源已变更,已丢弃旧候选;保留当前版本并重新查询。',
54
+ };
55
+ super(disposition === 'blocked'
56
+ ? '已提交的 Agent 配置未通过执行校验,自动客服已阻断;保留工作区与缓存,请重新分配兼容且完整的配置版本后再继续。'
57
+ : messages[code]);
58
+ this.code = code;
59
+ this.name = 'AgentConfigError';
60
+ }
61
+ }
62
+ /** @param bytes - 完整文件字节。 @returns SHA-256 小写十六进制编码。 */
63
+ export function agentConfigSha256(bytes) { return createHash('sha256').update(bytes).digest('hex'); }
64
+ /**
65
+ * 拒绝无法在各 Host 文件系统安全表达的相对路径。
66
+ * @param path - 包内 POSIX 路径。
67
+ * @returns 原始路径。
68
+ */
69
+ export function contentPath(path) {
70
+ assertTemplateRelativePath(path);
71
+ if (path === 'manifest.json' || path.split('/').some(part => /[<>:"|?*\x00-\x1f]/u.test(part)
72
+ || /[. ]$/u.test(part) || /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(part)))
73
+ throw new AgentConfigError('AGENT_CONFIG_INVALID');
74
+ return path;
75
+ }
76
+ /**
77
+ * 同时认证压缩包和逐文件字节,任何失败均发生在版本目录写入前。
78
+ * @param bytes - 下载的完整 gzip 字节。
79
+ * @param descriptor - server 经鉴权查询给出的登记信息。
80
+ * @param maxExpandedBytes - 解压 JSON 和文件总字节上限。
81
+ * @returns 清单和已校验文件。
82
+ */
83
+ export function decodeAgentConfig(bytes, descriptor, maxExpandedBytes) {
84
+ if (bytes.length !== descriptor.sizeBytes || agentConfigSha256(bytes) !== descriptor.sha256)
85
+ throw new AgentConfigError('AGENT_CONFIG_DIGEST_MISMATCH');
86
+ if (!semver.satisfies(HOST_AGENT_CONFIG_API_VERSION, descriptor.hostAgentConfigApiRange, { includePrerelease: true }))
87
+ throw new AgentConfigError('AGENT_CONFIG_INCOMPATIBLE');
88
+ let document;
89
+ try {
90
+ document = AgentConfigDocumentSchema.parse(JSON.parse(gunzipSync(bytes, { maxOutputLength: maxExpandedBytes }).toString('utf8')));
91
+ }
92
+ catch (error) {
93
+ throw new AgentConfigError('AGENT_CONFIG_INVALID');
94
+ }
95
+ const { manifest } = document;
96
+ if (manifest.workspaceKind !== descriptor.workspaceKind || manifest.version !== descriptor.version
97
+ || manifest.hostAgentConfigApiRange !== descriptor.hostAgentConfigApiRange || document.files.length !== manifest.files.length)
98
+ throw new AgentConfigError('AGENT_CONFIG_INVALID');
99
+ const seen = new Set();
100
+ let total = 0;
101
+ let previous = '';
102
+ const files = document.files.map((file, index) => {
103
+ const entry = manifest.files[index];
104
+ const path = contentPath(file.path);
105
+ const normalized = path.toLowerCase();
106
+ if (entry.path !== path || path <= previous || seen.has(normalized)
107
+ || [...seen].some(parent => normalized.startsWith(`${parent}/`) || parent.startsWith(`${normalized}/`)))
108
+ throw new AgentConfigError('AGENT_CONFIG_INVALID');
109
+ seen.add(normalized);
110
+ previous = path;
111
+ const data = Buffer.from(file.base64, 'base64');
112
+ total += data.length;
113
+ if (total > maxExpandedBytes || data.toString('base64') !== file.base64 || data.length !== entry.sizeBytes
114
+ || agentConfigSha256(data) !== entry.sha256)
115
+ throw new AgentConfigError('AGENT_CONFIG_DIGEST_MISMATCH');
116
+ return { path, bytes: data };
117
+ });
118
+ return { manifest, files };
119
+ }
@@ -0,0 +1,64 @@
1
+ /** Durable, authenticated module observations independent of tasks and business leases. */
2
+ import type { Context } from '@deepseek-ai/cordis';
3
+ import { type Branded } from '@deepseek-ai/dsh-brand';
4
+ import { type LocalHostReplacement } from './local-host-replacement.ts';
5
+ import type { WorkspaceAgentConfigState } from './agent-config-types.ts';
6
+ import { type AgentConfigModule } from './agent-config-contract/agent-configs.ts';
7
+ declare module '@deepseek-ai/cordis' {
8
+ interface Events {
9
+ /** Explicitly register each composed module for the same authenticated scope. @mode parallel @param revision - merchant scope at the user's click. @param registered - modules whose registration succeeded. */
10
+ 'workspace-bundle/activate-local-host'(revision: number, registered: Set<AgentConfigModule>): Promise<void>;
11
+ /** Resume observations after every module registration succeeded. @mode parallel @param revision - authenticated activation scope. */
12
+ 'workspace-bundle/local-host-activated'(revision: number): Promise<void>;
13
+ /** Re-read each module's installation identity before its next registration. @mode parallel */
14
+ 'workspace-bundle/local-host-identity-changed'(): Promise<void>;
15
+ }
16
+ }
17
+ /** Deployment identity verified against the authenticated sandbox before any registration or report. */
18
+ export interface WorkspaceAgentConfigSandbox {
19
+ readonly sandboxId: Branded<'SandboxId'>;
20
+ readonly instanceId: Branded<'SandboxHostInstanceId'>;
21
+ }
22
+ /** Per-source reporter lifetime. */
23
+ export interface WorkspaceAgentConfigObservation {
24
+ /** This authenticated module is stopped until explicit activation. */
25
+ readonly replaced: boolean;
26
+ /** @returns after the current authenticated report or its contained failure. */
27
+ refresh(): Promise<void>;
28
+ /** Cancel requests and timers, then wait for file and transport work. @returns after no callback can report again. */
29
+ dispose(): Promise<void>;
30
+ }
31
+ /** Persistent identity reused by an installation across module observation runs. */
32
+ export type WorkspaceAgentConfigHostId = Branded<'WorkspaceAgentConfigHostId'>;
33
+ /** Settings resolved by the module owning its persistent Host identity. */
34
+ export interface WorkspaceAgentConfigObservationOptions {
35
+ readonly workspaceKind: AgentConfigModule;
36
+ /** Shared member fence owned by WorkspaceBundles. */
37
+ readonly replacementState: LocalHostReplacement;
38
+ /** Fixed identity or the module's current installation getter; emit local-host-identity-changed after binding changes. */
39
+ readonly hostId: WorkspaceAgentConfigHostId | (() => WorkspaceAgentConfigHostId);
40
+ readonly stateRoot: string;
41
+ readonly runtimeApiVersion: string | null;
42
+ readonly intervalMs: number;
43
+ readonly requestTimeoutMs: number;
44
+ /** Explicit cloud deployment; omission retains installation activation and replacement handling. */
45
+ readonly sandbox?: WorkspaceAgentConfigSandbox;
46
+ /** Notify the owning module when the shared replacement fence is set; omission leaves the status available on the reporter. @param hostId - identity of the rejected run. */
47
+ readonly onReplaced?: (hostId: WorkspaceAgentConfigHostId) => void;
48
+ }
49
+ /**
50
+ * Build the observation owner when its source is registered; the server owns holder attestation.
51
+ * @param ctx - authenticated merchant transport and scope-change events.
52
+ * @param options - module identity, private persistent directory and resolved scheduling limits.
53
+ * @returns factory bound to the source's actual committed state.
54
+ */
55
+ export declare function agentConfigHostObservation(ctx: Context, options: WorkspaceAgentConfigObservationOptions): (read: () => WorkspaceAgentConfigState) => WorkspaceAgentConfigObservation;
56
+ /**
57
+ * Cloud-only factory; importing this export rejects older packages that cannot enforce sandbox identity.
58
+ * @param ctx - Authenticated merchant transport and scope-change events.
59
+ * @param options - Required sandbox deployment identity and private reporter settings.
60
+ * @returns factory whose registrations require authenticated sandbox readback.
61
+ */
62
+ export declare function sandboxAgentConfigHostObservation(ctx: Context, options: WorkspaceAgentConfigObservationOptions & {
63
+ readonly sandbox: WorkspaceAgentConfigSandbox;
64
+ }): (read: () => WorkspaceAgentConfigState) => WorkspaceAgentConfigObservation;