@clawos-dev/clawd 0.2.622 → 0.2.624

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.
@@ -21593,6 +21593,46 @@ var EnvEvidenceSchema = external_exports.object({
21593
21593
  quote: external_exports.string().min(1)
21594
21594
  });
21595
21595
 
21596
+ // ../protocol/src/release-schemas.ts
21597
+ var DEPLOY_ENVIRONMENTS = ["integration", "production"];
21598
+ var DeployEnvironmentSchema = external_exports.enum(DEPLOY_ENVIRONMENTS);
21599
+ var ImageDigestSchema = external_exports.string().regex(/^[a-z0-9.-]+(?::[0-9]+)?\/[a-z0-9._/-]+@sha256:[a-f0-9]{64}$/);
21600
+ var SourceCommitSchema = external_exports.string().regex(/^[a-f0-9]{40}$/);
21601
+ var IntegrationEndpointSchema = external_exports.string().refine((value) => {
21602
+ try {
21603
+ const url = new URL(value);
21604
+ return url.protocol === "https:" && !url.username && !url.password && !url.search && !url.hash && url.pathname === "/" && /(^|[.-])int([.-]|$)/.test(url.hostname);
21605
+ } catch {
21606
+ return false;
21607
+ }
21608
+ }, "\u6D4B\u8BD5\u9A8C\u8BC1\u5730\u5740\u5FC5\u987B\u660E\u786E\u6307\u5411 int HTTPS \u73AF\u5883");
21609
+ var VerificationSchema = external_exports.object({
21610
+ status: external_exports.literal("passed"),
21611
+ fingerprint: external_exports.string().regex(/^[a-f0-9]{64}$/),
21612
+ checks: external_exports.array(external_exports.string().regex(/^[a-z0-9-]+$/)),
21613
+ endpoint: IntegrationEndpointSchema,
21614
+ verifiedAt: external_exports.string().refine((s) => Number.isFinite(Date.parse(s)))
21615
+ }).strict();
21616
+ var VerifiedPersonaReleaseSchema = external_exports.object({
21617
+ version: external_exports.literal(1),
21618
+ environment: external_exports.literal("integration"),
21619
+ component: external_exports.literal("persona"),
21620
+ image: ImageDigestSchema,
21621
+ commit: SourceCommitSchema,
21622
+ baseImage: ImageDigestSchema,
21623
+ pipelineCommit: SourceCommitSchema,
21624
+ repository: external_exports.string().regex(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/),
21625
+ verification: VerificationSchema.refine((v) => v.checks.includes("persona-smoke"))
21626
+ }).strict();
21627
+ var VerifiedBaseReleaseSchema = external_exports.object({
21628
+ version: external_exports.literal(1),
21629
+ environment: external_exports.literal("integration"),
21630
+ component: external_exports.literal("base"),
21631
+ image: ImageDigestSchema,
21632
+ commit: SourceCommitSchema,
21633
+ verification: VerificationSchema.refine((v) => v.checks.includes("base-smoke"))
21634
+ }).strict();
21635
+
21596
21636
  // ../protocol/src/deploy-schemas.ts
21597
21637
  var DeployFileSchema = external_exports.object({
21598
21638
  version: external_exports.literal(1),
@@ -21621,15 +21661,44 @@ var DeployScanSchema = external_exports.object({
21621
21661
  error: external_exports.string().optional()
21622
21662
  }).strict();
21623
21663
  var DeployReleasedSchema = external_exports.object({
21664
+ /** Legacy wire records can omit these; file migration always materializes them. */
21665
+ id: external_exports.string().min(1).optional(),
21666
+ environment: DeployEnvironmentSchema.optional(),
21667
+ legacy: external_exports.boolean().optional(),
21624
21668
  head: external_exports.string().min(1),
21625
21669
  contentHead: external_exports.string().min(1),
21626
21670
  scanId: external_exports.string().min(1),
21627
- at: external_exports.number()
21671
+ at: external_exports.number(),
21672
+ pushed: external_exports.boolean().optional(),
21673
+ runId: external_exports.number().int().positive().optional(),
21674
+ runAttempt: external_exports.number().int().positive().optional(),
21675
+ artifactId: external_exports.number().int().positive().optional(),
21676
+ verified: VerifiedPersonaReleaseSchema.optional(),
21677
+ confirmation: external_exports.object({
21678
+ fingerprint: external_exports.string().regex(/^[a-f0-9]{64}$/),
21679
+ runId: external_exports.number().int().positive(),
21680
+ runAttempt: external_exports.number().int().positive(),
21681
+ at: external_exports.number()
21682
+ }).strict().optional()
21683
+ }).strict();
21684
+ var DEPLOY_PROMOTION_PHASES = ["prepared", "main-pushed", "dispatching", "dispatched", "completed", "failed"];
21685
+ var DeployPromotionSchema = external_exports.object({
21686
+ id: external_exports.string().min(1),
21687
+ releaseId: external_exports.string().min(1),
21688
+ at: external_exports.number(),
21689
+ /** Artifact fixed when the user authorizes this action; int reruns cannot replace it. */
21690
+ verified: VerifiedPersonaReleaseSchema.optional(),
21691
+ phase: external_exports.enum(DEPLOY_PROMOTION_PHASES),
21692
+ expectedMain: external_exports.string().optional(),
21693
+ runId: external_exports.number().int().positive().optional(),
21694
+ runAttempt: external_exports.number().int().positive().optional(),
21695
+ error: external_exports.string().optional()
21628
21696
  }).strict();
21629
21697
  var DeployScanFileSchema = external_exports.object({
21630
- version: external_exports.literal(3),
21698
+ version: external_exports.literal(4),
21631
21699
  scans: external_exports.array(DeployScanSchema),
21632
- releases: external_exports.array(DeployReleasedSchema)
21700
+ releases: external_exports.array(DeployReleasedSchema),
21701
+ promotions: external_exports.array(DeployPromotionSchema).default([])
21633
21702
  }).strict();
21634
21703
  var DeployRepoSchema = external_exports.object({
21635
21704
  url: external_exports.string().min(1),
@@ -21663,7 +21732,13 @@ var DeployRunSchema = external_exports.object({
21663
21732
  status: external_exports.enum(["queued", "running", "completed"]),
21664
21733
  htmlUrl: external_exports.string().min(1),
21665
21734
  /** run 刚入队时可能一条都还没有 */
21666
- jobs: external_exports.array(DeployJobSchema)
21735
+ jobs: external_exports.array(DeployJobSchema),
21736
+ environment: DeployEnvironmentSchema.optional(),
21737
+ branch: external_exports.string().optional(),
21738
+ event: external_exports.string().optional(),
21739
+ runAttempt: external_exports.number().int().positive().optional(),
21740
+ conclusion: external_exports.enum(["success", "failure"]).optional(),
21741
+ promotionId: external_exports.string().optional()
21667
21742
  }).strict();
21668
21743
  var DeployUnpublishRunSchema = external_exports.object({
21669
21744
  runId: external_exports.number(),
@@ -21678,6 +21753,23 @@ var DeployStateSchema = external_exports.object({
21678
21753
  repo: DeployRepoSchema.optional(),
21679
21754
  scans: external_exports.array(DeployScanSchema).default([]),
21680
21755
  releases: external_exports.array(DeployReleasedSchema).default([]),
21756
+ promotions: external_exports.array(DeployPromotionSchema).optional(),
21757
+ targets: external_exports.object({
21758
+ integration: external_exports.object({
21759
+ run: DeployRunSchema.optional(),
21760
+ secrets: external_exports.array(DeploySecretPresenceSchema).optional(),
21761
+ online: external_exports.boolean().optional(),
21762
+ image: ImageDigestSchema.optional(),
21763
+ unpublish: DeployUnpublishRunSchema.optional()
21764
+ }).strict().optional(),
21765
+ production: external_exports.object({
21766
+ run: DeployRunSchema.optional(),
21767
+ secrets: external_exports.array(DeploySecretPresenceSchema).optional(),
21768
+ online: external_exports.boolean().optional(),
21769
+ image: ImageDigestSchema.optional(),
21770
+ unpublish: DeployUnpublishRunSchema.optional()
21771
+ }).strict().optional()
21772
+ }).strict().optional(),
21681
21773
  /** 没仓库时缺席(查不了) */
21682
21774
  secrets: external_exports.array(DeploySecretPresenceSchema).optional(),
21683
21775
  /**
@@ -21704,13 +21796,16 @@ var DeployUnpublishResultSchema = external_exports.object({
21704
21796
  var DeployPatchResultSchema = DeployStateSchema.pick({ scans: true });
21705
21797
  var DeployReleaseResultSchema = external_exports.object({
21706
21798
  sha: external_exports.string().min(1),
21707
- actionsUrl: external_exports.string().min(1)
21799
+ actionsUrl: external_exports.string().min(1),
21800
+ releaseId: external_exports.string().optional()
21708
21801
  }).strict();
21709
21802
  var DeployPersonaArgsSchema = external_exports.object({
21710
21803
  personaId: external_exports.string().min(1)
21711
21804
  }).strict();
21712
21805
  var DeployGetArgsSchema = DeployPersonaArgsSchema.extend({
21713
- releaseHead: external_exports.string().min(1).optional()
21806
+ releaseHead: external_exports.string().min(1).optional(),
21807
+ releaseId: external_exports.string().min(1).optional(),
21808
+ environment: DeployEnvironmentSchema.optional()
21714
21809
  }).strict();
21715
21810
  var DeployScanArgsSchema = DeployPersonaArgsSchema.extend({
21716
21811
  scanBase: ScanBaseKindSchema.optional()
@@ -21718,6 +21813,13 @@ var DeployScanArgsSchema = DeployPersonaArgsSchema.extend({
21718
21813
  var DeployReleaseArgsSchema = DeployPersonaArgsSchema.extend({
21719
21814
  scanId: external_exports.string().min(1)
21720
21815
  }).strict();
21816
+ var DeployConfirmTestArgsSchema = DeployPersonaArgsSchema.extend({ releaseId: external_exports.string().min(1) }).strict();
21817
+ var DeployPromoteArgsSchema = DeployConfirmTestArgsSchema;
21818
+ var DeployOpenTestArgsSchema = DeployConfirmTestArgsSchema;
21819
+ var DeployEnvironmentArgsSchema = DeployPersonaArgsSchema.extend({ environment: DeployEnvironmentSchema.default("production") }).strict();
21820
+ var DeployConfirmTestResultSchema = external_exports.object({ confirmation: DeployReleasedSchema.shape.confirmation.unwrap() }).strict();
21821
+ var DeployPromoteResultSchema = external_exports.object({ promotion: DeployPromotionSchema }).strict();
21822
+ var DeployOpenTestResultSchema = external_exports.object({ personaId: external_exports.string().min(1), expectedImage: ImageDigestSchema }).strict();
21721
21823
  var DeployPatchArgsSchema = external_exports.object({
21722
21824
  personaId: external_exports.string().min(1),
21723
21825
  scanId: external_exports.string().min(1),
@@ -21733,6 +21835,7 @@ var DeployPatchArgsSchema = external_exports.object({
21733
21835
  }).strict();
21734
21836
  var DeployPutSecretArgsSchema = external_exports.object({
21735
21837
  personaId: external_exports.string().min(1),
21838
+ environment: DeployEnvironmentSchema.default("production"),
21736
21839
  /** 按哪次扫描的清单校验凭据名 / env 名。值本身是仓库级的(GitHub Secrets),跟扫描无关 */
21737
21840
  scanId: external_exports.string().min(1),
21738
21841
  name: external_exports.string().min(1),
@@ -21741,6 +21844,7 @@ var DeployPutSecretArgsSchema = external_exports.object({
21741
21844
  }).strict();
21742
21845
  var DeploySetEngineAuthArgsSchema = external_exports.object({
21743
21846
  personaId: external_exports.string().min(1),
21847
+ environment: DeployEnvironmentSchema.default("production"),
21744
21848
  channelId: external_exports.string().min(1).optional(),
21745
21849
  auth: external_exports.object({ baseUrl: external_exports.string(), apiKey: external_exports.string() }).strict().nullable().optional()
21746
21850
  }).strict().refine((data) => data.channelId !== void 0 || data.auth !== void 0, {
@@ -21748,6 +21852,8 @@ var DeploySetEngineAuthArgsSchema = external_exports.object({
21748
21852
  });
21749
21853
  var DeployRerunJobArgsSchema = external_exports.object({
21750
21854
  personaId: external_exports.string().min(1),
21855
+ environment: DeployEnvironmentSchema.default("production"),
21856
+ releaseId: external_exports.string().optional(),
21751
21857
  jobId: external_exports.number()
21752
21858
  }).strict();
21753
21859
  var DeployReportFindingArgsSchema = external_exports.object({
@@ -21769,6 +21875,99 @@ var DeployFinishScanArgsSchema = external_exports.object({
21769
21875
  notes: external_exports.array(external_exports.string()).default([])
21770
21876
  }).strict();
21771
21877
 
21878
+ // ../protocol/src/feishu-auth.ts
21879
+ var AuthEnvironmentArgsSchema = external_exports.object({ environment: DeployEnvironmentSchema.default("production") }).strict();
21880
+ var DeviceEntrySchema = external_exports.object({
21881
+ /**
21882
+ * 设备标识(决策 #15:daemon 本地生成的 dev-<uuid>,与人的身份 unionId 无关)。
21883
+ * 中心 server clawd_devices 注册表仅作服务发现(url 下发 + 目录),不在安全路径上。
21884
+ */
21885
+ deviceId: external_exports.string().min(1),
21886
+ name: external_exports.string().min(1),
21887
+ url: external_exports.string().min(1)
21888
+ });
21889
+ var DeviceListResponseSchema = external_exports.object({
21890
+ type: external_exports.literal("device:list:ok"),
21891
+ devices: external_exports.array(DeviceEntrySchema)
21892
+ });
21893
+ var DeviceConnectArgsSchema = external_exports.object({
21894
+ deviceId: external_exports.string().min(1),
21895
+ /**
21896
+ * 目标设备的 ws/tunnel 地址(可选):
21897
+ * - 公开目录点击:带 url(device:list 已下发,省一次 server 查询)
21898
+ * - 凭 deviceId 连接:缺省 url → daemon exchange 时由中心 server 下发该设备上报的 url
21899
+ * - 注册表不在安全路径上:知道对方 url 时显式传入即可连接(不依赖中心 server 服务发现)
21900
+ */
21901
+ url: external_exports.string().min(1).optional(),
21902
+ /** Optional display name; otherwise populate it from the handshake acknowledgement. */
21903
+ name: external_exports.string().optional()
21904
+ });
21905
+ var DeviceConnectResponseSchema = external_exports.object({
21906
+ type: external_exports.literal("device:connect:ok"),
21907
+ deviceId: external_exports.string(),
21908
+ name: external_exports.string(),
21909
+ url: external_exports.string()
21910
+ });
21911
+ var FeishuIdentitySchema = external_exports.object({
21912
+ /** 归属人 id(决策 #16:TTC unique_id,取代飞书 union_id;跨登录方式稳定) */
21913
+ ownerId: external_exports.string().min(1),
21914
+ /** 身份来源:'ttc'(飞书/手机/邮箱登入 TTC)| 'google' | ...(决策 #16,拓展用) */
21915
+ provider: external_exports.string().min(1),
21916
+ displayName: external_exports.string().min(1),
21917
+ /** TTC user_info 接口 data.avatar_url,可缺省 */
21918
+ avatarUrl: external_exports.string().optional(),
21919
+ /** TTC user_info 接口 data.union_id(飞书 union_id;dataclaw 可信入口 X-User-UnionId 用),可缺省 */
21920
+ unionId: external_exports.string().optional()
21921
+ });
21922
+ var AuthLoginStartResponseSchema = external_exports.object({
21923
+ type: external_exports.literal("auth:login:start:ok"),
21924
+ environment: DeployEnvironmentSchema.optional(),
21925
+ authUrl: external_exports.string().min(1),
21926
+ /** 防 CSRF 的一次性 nonce;回调时 daemon 校验 */
21927
+ state: external_exports.string().min(1)
21928
+ });
21929
+ var AuthGetIdentityResponseSchema = external_exports.object({
21930
+ type: external_exports.literal("auth:getIdentity:ok"),
21931
+ /** null = 未登录 */
21932
+ identity: FeishuIdentitySchema.nullable(),
21933
+ /** Stable device identifier independent of login, used for the shareable device link. */
21934
+ deviceId: external_exports.string().min(1)
21935
+ });
21936
+ var AuthLogoutResponseSchema = external_exports.object({
21937
+ type: external_exports.literal("auth:logout:ok")
21938
+ });
21939
+ var GatewayUrl = external_exports.string().nullable();
21940
+ var AuthApiKeyGetResponseSchema = external_exports.object({
21941
+ type: external_exports.literal("auth:apiKey:get:ok"),
21942
+ /** null = 还没发过。**发过就能一直看到** —— 中心存的是明文,设置页据此展示 */
21943
+ apiKey: external_exports.string().nullable(),
21944
+ /** ISO 时间;apiKey 为 null 时同为 null */
21945
+ createdAt: external_exports.string().nullable(),
21946
+ gatewayUrl: GatewayUrl
21947
+ });
21948
+ var AuthApiKeyRegenerateResponseSchema = external_exports.object({
21949
+ type: external_exports.literal("auth:apiKey:regenerate:ok"),
21950
+ /** 新发的那把。**旧的当场失效** —— 一人一把,按 union_id 覆盖 */
21951
+ apiKey: external_exports.string().min(1),
21952
+ createdAt: external_exports.string().min(1),
21953
+ gatewayUrl: GatewayUrl
21954
+ });
21955
+ var AuthApiKeyRevokeResponseSchema = external_exports.object({
21956
+ type: external_exports.literal("auth:apiKey:revoke:ok"),
21957
+ /** 之前有没有那把——没发过也算成功(幂等) */
21958
+ revoked: external_exports.boolean()
21959
+ });
21960
+ var AuthLoginDoneEventSchema = external_exports.object({
21961
+ type: external_exports.literal("auth:login:done"),
21962
+ environment: DeployEnvironmentSchema.optional(),
21963
+ identity: FeishuIdentitySchema
21964
+ });
21965
+ var AuthLoginFailedEventSchema = external_exports.object({
21966
+ type: external_exports.literal("auth:login:failed"),
21967
+ environment: DeployEnvironmentSchema.optional(),
21968
+ reason: external_exports.string()
21969
+ });
21970
+
21772
21971
  // ../protocol/src/contact-remote-access.ts
21773
21972
  var ContactSetRemoteAccessArgsSchema = external_exports.object({
21774
21973
  deviceId: external_exports.string().min(1),
@@ -21886,95 +22085,6 @@ var ContactPinnedFrameSchema = external_exports.object({
21886
22085
  pinnedAt: external_exports.number().int().nullable()
21887
22086
  }).strict();
21888
22087
 
21889
- // ../protocol/src/feishu-auth.ts
21890
- var DeviceEntrySchema = external_exports.object({
21891
- /**
21892
- * 设备标识(决策 #15:daemon 本地生成的 dev-<uuid>,与人的身份 unionId 无关)。
21893
- * 中心 server clawd_devices 注册表仅作服务发现(url 下发 + 目录),不在安全路径上。
21894
- */
21895
- deviceId: external_exports.string().min(1),
21896
- name: external_exports.string().min(1),
21897
- url: external_exports.string().min(1)
21898
- });
21899
- var DeviceListResponseSchema = external_exports.object({
21900
- type: external_exports.literal("device:list:ok"),
21901
- devices: external_exports.array(DeviceEntrySchema)
21902
- });
21903
- var DeviceConnectArgsSchema = external_exports.object({
21904
- deviceId: external_exports.string().min(1),
21905
- /**
21906
- * 目标设备的 ws/tunnel 地址(可选):
21907
- * - 公开目录点击:带 url(device:list 已下发,省一次 server 查询)
21908
- * - 凭 deviceId 连接:缺省 url → daemon exchange 时由中心 server 下发该设备上报的 url
21909
- * - 注册表不在安全路径上:知道对方 url 时显式传入即可连接(不依赖中心 server 服务发现)
21910
- */
21911
- url: external_exports.string().min(1).optional(),
21912
- /** Optional display name; otherwise populate it from the handshake acknowledgement. */
21913
- name: external_exports.string().optional()
21914
- });
21915
- var DeviceConnectResponseSchema = external_exports.object({
21916
- type: external_exports.literal("device:connect:ok"),
21917
- deviceId: external_exports.string(),
21918
- name: external_exports.string(),
21919
- url: external_exports.string()
21920
- });
21921
- var FeishuIdentitySchema = external_exports.object({
21922
- /** 归属人 id(决策 #16:TTC unique_id,取代飞书 union_id;跨登录方式稳定) */
21923
- ownerId: external_exports.string().min(1),
21924
- /** 身份来源:'ttc'(飞书/手机/邮箱登入 TTC)| 'google' | ...(决策 #16,拓展用) */
21925
- provider: external_exports.string().min(1),
21926
- displayName: external_exports.string().min(1),
21927
- /** TTC user_info 接口 data.avatar_url,可缺省 */
21928
- avatarUrl: external_exports.string().optional(),
21929
- /** TTC user_info 接口 data.union_id(飞书 union_id;dataclaw 可信入口 X-User-UnionId 用),可缺省 */
21930
- unionId: external_exports.string().optional()
21931
- });
21932
- var AuthLoginStartResponseSchema = external_exports.object({
21933
- type: external_exports.literal("auth:login:start:ok"),
21934
- authUrl: external_exports.string().min(1),
21935
- /** 防 CSRF 的一次性 nonce;回调时 daemon 校验 */
21936
- state: external_exports.string().min(1)
21937
- });
21938
- var AuthGetIdentityResponseSchema = external_exports.object({
21939
- type: external_exports.literal("auth:getIdentity:ok"),
21940
- /** null = 未登录 */
21941
- identity: FeishuIdentitySchema.nullable(),
21942
- /** Stable device identifier independent of login, used for the shareable device link. */
21943
- deviceId: external_exports.string().min(1)
21944
- });
21945
- var AuthLogoutResponseSchema = external_exports.object({
21946
- type: external_exports.literal("auth:logout:ok")
21947
- });
21948
- var GatewayUrl = external_exports.string().nullable();
21949
- var AuthApiKeyGetResponseSchema = external_exports.object({
21950
- type: external_exports.literal("auth:apiKey:get:ok"),
21951
- /** null = 还没发过。**发过就能一直看到** —— 中心存的是明文,设置页据此展示 */
21952
- apiKey: external_exports.string().nullable(),
21953
- /** ISO 时间;apiKey 为 null 时同为 null */
21954
- createdAt: external_exports.string().nullable(),
21955
- gatewayUrl: GatewayUrl
21956
- });
21957
- var AuthApiKeyRegenerateResponseSchema = external_exports.object({
21958
- type: external_exports.literal("auth:apiKey:regenerate:ok"),
21959
- /** 新发的那把。**旧的当场失效** —— 一人一把,按 union_id 覆盖 */
21960
- apiKey: external_exports.string().min(1),
21961
- createdAt: external_exports.string().min(1),
21962
- gatewayUrl: GatewayUrl
21963
- });
21964
- var AuthApiKeyRevokeResponseSchema = external_exports.object({
21965
- type: external_exports.literal("auth:apiKey:revoke:ok"),
21966
- /** 之前有没有那把——没发过也算成功(幂等) */
21967
- revoked: external_exports.boolean()
21968
- });
21969
- var AuthLoginDoneEventSchema = external_exports.object({
21970
- type: external_exports.literal("auth:login:done"),
21971
- identity: FeishuIdentitySchema
21972
- });
21973
- var AuthLoginFailedEventSchema = external_exports.object({
21974
- type: external_exports.literal("auth:login:failed"),
21975
- reason: external_exports.string()
21976
- });
21977
-
21978
22088
  // ../protocol/src/dispatch.ts
21979
22089
  var DispatchOutcomeSchema = external_exports.discriminatedUnion("kind", [
21980
22090
  external_exports.object({
@@ -22778,7 +22888,14 @@ var PersonaFileSchema = external_exports.object({
22778
22888
  createdAt: external_exports.number(),
22779
22889
  updatedAt: external_exports.number(),
22780
22890
  /** Registry-only cloud entry, with no local persona directory. Local key adds -cloud; gateway paths use cloud.personaId and the registered engine determines the cloud tool id. */
22781
- cloud: external_exports.object({ gatewayUrl: external_exports.string().min(1), personaId: external_exports.string().min(1), publishedByMe: external_exports.boolean().optional() }).strict().optional()
22891
+ cloud: external_exports.object({
22892
+ gatewayUrl: external_exports.string().min(1),
22893
+ personaId: external_exports.string().min(1),
22894
+ publishedByMe: external_exports.boolean().optional(),
22895
+ environment: DeployEnvironmentSchema.optional(),
22896
+ expectedImage: ImageDigestSchema.optional(),
22897
+ testReleaseId: external_exports.string().optional()
22898
+ }).strict().optional()
22782
22899
  }).strict();
22783
22900
  var PersonaSkillSummarySchema = external_exports.object({
22784
22901
  // 目录名作为 skill name(对齐 CC:frontmatter `name:` 仅作 displayName 用)
@@ -23012,6 +23129,9 @@ var AllowRuleSchema = external_exports.object({
23012
23129
  createdAt: external_exports.string().min(1).optional()
23013
23130
  });
23014
23131
  var SessionFileSchema = external_exports.object({
23132
+ cloudEnvironment: DeployEnvironmentSchema.optional(),
23133
+ cloudExpectedImage: ImageDigestSchema.optional(),
23134
+ testReleaseId: external_exports.string().optional(),
23015
23135
  sessionId: external_exports.string().min(1),
23016
23136
  /** New gateway execution identity after session:new; defaults to sessionId for the first execution. */
23017
23137
  cloudExecutionId: external_exports.string().min(1).optional(),
@@ -23888,9 +24008,21 @@ var METHOD_DOCS = {
23888
24008
  summary: "\u539F\u6837\u91CD\u8DD1\u6700\u65B0\u90A3\u6761\u6D41\u6C34\u7EBF\u91CC\u5931\u8D25\u7684\u67D0\u4E00\u6BB5\uFF08GitHub REST rerun job\uFF09\u3002**\u540C\u4E00\u4E2A commit\u3001\u540C\u4E00\u4EFD\u8F93\u5165**\uFF0C\u4E0D\u4EA7\u751F\u65B0\u63D0\u4EA4\u2014\u2014\u6539\u4E86 persona \u5185\u5BB9\u8981 deploy:scan \u518D deploy:release\u3002jobId \u5FC5\u987B\u5C5E\u4E8E\u6700\u65B0\u90A3\u6761 run\uFF1Bowner-only",
23889
24009
  args: DeployRerunJobArgsSchema
23890
24010
  },
24011
+ "deploy:confirmTest": {
24012
+ summary: "\u786E\u8BA4\u6240\u9009\u6D4B\u8BD5\u7248\u901A\u8FC7\u5B9E\u9645\u8BD5\u7528\uFF1B\u6309\u5DF2\u4FDD\u5B58\u5236\u54C1\u548C\u6D4B\u8BD5\u767B\u8BB0\u6821\u9A8C\uFF0Cowner-only\u3001human-only",
24013
+ args: DeployConfirmTestArgsSchema
24014
+ },
24015
+ "deploy:promote": {
24016
+ summary: "\u5C06\u5DF2\u786E\u8BA4\u6D4B\u8BD5\u7248\u7684\u63D0\u4EA4\u63A8\u8FDB main \u5E76\u4E0A\u7EBF\u76F8\u540C\u955C\u50CF\uFF1B\u6062\u590D\u4E2D\u65AD\u7684\u540C\u4E00\u6B21\u664B\u7EA7\uFF0Cowner-only\u3001human-only",
24017
+ args: DeployPromoteArgsSchema
24018
+ },
24019
+ "deploy:openTest": {
24020
+ summary: "\u51C6\u5907\u5F53\u524D\u6D4B\u8BD5\u7248\u7684\u4E91 Persona \u4F1A\u8BDD\u5165\u53E3\uFF0C\u9501\u5B9A\u73AF\u5883\u548C\u5DF2\u6D4B\u955C\u50CF\uFF0Cowner-only\u3001human-only",
24021
+ args: DeployOpenTestArgsSchema
24022
+ },
23891
24023
  "deploy:unpublish": {
23892
24024
  summary: "\u4E0B\u7EBF\uFF1A\u89E6\u53D1 persona \u4ED3\u5E93\u91CC\u7684 clawd-unpublish.yml\uFF08workflow_dispatch\uFF09\uFF0C\u7531\u6D41\u6C34\u7EBF\u5728 gateway \u64A4\u6389\u6B63\u5F0F\u767B\u8BB0\u2014\u2014\u522B\u4EBA\u770B\u4E0D\u5230\u3001\u7528\u4E0D\u4E86\uFF1B\u4ED3\u5E93 / \u955C\u50CF / \u672C\u673A\u4E0A\u4E91\u8BB0\u5F55\u90FD\u4E0D\u52A8\uFF0C\u91CD\u65B0\u53D1\u5E03\u5C31\u56DE\u6765\u3002\u6700\u540E\u4E00\u6B21\u53D1\u5E03\u7684 commit \u91CC\u6CA1\u6709\u8FD9\u4EFD workflow\uFF08\u65E7\u6A21\u677F\uFF09\u65F6\u62D2\uFF0C\u8981\u5148\u91CD\u65B0\u53D1\u5E03\u4E00\u6B21\u3002\u56DE { before }\uFF1A\u89E6\u53D1\u4E4B\u524D\u73B0\u67E5\u7684\u6700\u65B0\u4E0B\u7EBF run id\uFF08\u6CA1\u4E0B\u7EBF\u8FC7 = null\uFF09\uFF0C\u9875\u9762\u62FF\u5B83\u8BA4\u65B0 run\uFF1Bowner-only\u3001human-only",
23893
- args: DeployPersonaArgsSchema
24025
+ args: DeployEnvironmentArgsSchema
23894
24026
  },
23895
24027
  "githubAuth:get": {
23896
24028
  summary: "\u672C\u673A\u7684 GitHub \u8EAB\u4EFD\uFF1Aauthorized\uFF08@login\uFF0C\u6765\u81EA git \u51ED\u636E\u5B58\u50A8 / \u672C\u673A\u51ED\u636E\u8868\uFF09/ missing / invalid\uFF08GitHub \u4E0D\u8BA4\uFF09/ pending\uFF08\u7B49 GitHub \u8DF3\u56DE\u4E2D\u5FC3\uFF09\u3002\u8BBE\u7F6E\u9875\u300C\u8D26\u53F7\u300D\u3001\u4E0A\u4E91\u9875\u9876\u4E0A\u90A3\u5F20\u5361\u3001PR \u6536\u4EF6\u7BB1\u90FD\u770B\u5B83\uFF1Bpending \u671F\u9875\u9762\u6BCF 2 \u79D2\u8F6E\u8BE2\uFF0Cdaemon \u987A\u624B\u5411\u4E2D\u5FC3\u9886 token\u3002\u65E0\u53C2\u6570",
@@ -24312,7 +24444,7 @@ var METHOD_DOCS = {
24312
24444
  },
24313
24445
  "auth:login:start": {
24314
24446
  summary: "\u8D77\u98DE\u4E66\u767B\u5F55\u6D41\u7A0B\uFF1A\u751F\u6210 state \u5E76\u8FD4\u56DE\u6388\u6743 URL\uFF0C\u56DE\u8C03\u8D70 HTTP /auth/callback \u843D\u76D8\u3002owner-only",
24315
- args: NO_ARGS
24447
+ args: AuthEnvironmentArgsSchema
24316
24448
  },
24317
24449
  "auth:getIdentity": {
24318
24450
  summary: "\u53D6\u672C\u673A owner \u7684\u98DE\u4E66\u8EAB\u4EFD\uFF08ownerId / provider / displayName / unionId\uFF09+ **\u672C\u673A deviceId**\uFF08\u8BBE\u5907\u5C5E\u6027\uFF0C\u4E0E\u767B\u5F55\u6001\u65E0\u5173\uFF1Bdevice:connect / contact:* / inbox:* \u7684\u4E3B\u952E\u90FD\u662F\u5B83\uFF09\uFF1B\u7EDD\u4E0D\u8FD4\u56DE\u767B\u5F55\u7968",
@@ -24324,15 +24456,15 @@ var METHOD_DOCS = {
24324
24456
  },
24325
24457
  "auth:apiKey:get": {
24326
24458
  summary: "\u8BFB\u56DE\u81EA\u5DF1\u90A3\u628A\u4E91 persona \u8C03\u7528 key\uFF08\u6CA1\u53D1\u8FC7 \u2192 apiKey:null\uFF09\u3002daemon \u62FF\u672C\u673A\u767B\u5F55\u51ED\u8BC1\u5411\u4E2D\u5FC3\u4EE3\u53D6\uFF0C\u51ED\u8BC1\u4E0D\u51FA ws\u3002owner-only",
24327
- args: NO_ARGS
24459
+ args: AuthEnvironmentArgsSchema
24328
24460
  },
24329
24461
  "auth:apiKey:regenerate": {
24330
24462
  summary: "\u6362\u4E00\u628A\u65B0\u7684\u4E91 persona \u8C03\u7528 key\uFF0C**\u65E7\u7684\u5F53\u573A\u5931\u6548**\uFF08\u4E00\u4EBA\u4E00\u628A\uFF0C\u4E2D\u5FC3\u6309 union_id \u8986\u76D6\uFF09\u3002owner-only",
24331
- args: NO_ARGS
24463
+ args: AuthEnvironmentArgsSchema
24332
24464
  },
24333
24465
  "auth:apiKey:revoke": {
24334
24466
  summary: "\u64A4\u9500\u81EA\u5DF1\u7684\u4E91 persona \u8C03\u7528 key\uFF1A\u4E2D\u5FC3\u5220\u6389\u90A3\u4E00\u884C\u3001**\u4E0D\u53D1\u65B0\u7684**\u3002gateway \u53EA\u5728\u5F00\u4F1A\u8BDD\u548C\u6BCF\u6B21\u4E0A\u884C\u65F6\u9A8C key\uFF0C\u6240\u4EE5\u5F00\u7740\u7684\u4E91\u4F1A\u8BDD\u4E0B\u4E00\u6761\u6D88\u606F\u624D\u53D1\u4E0D\u51FA\u53BB\u3001\u6B63\u5728\u8DD1\u7684\u90A3\u4E00\u8F6E\u4F1A\u8DD1\u5B8C\u3002\u6CA1\u53D1\u8FC7\u4E5F\u56DE ok\uFF08revoked:false\uFF09\u3002owner-only",
24335
- args: NO_ARGS
24467
+ args: AuthEnvironmentArgsSchema
24336
24468
  },
24337
24469
  "device:list": {
24338
24470
  summary: "\u5217\u51FA\u516C\u5171\u8BBE\u5907\u76EE\u5F55\u91CC\u53EF\u8FDE\u63A5\u7684\u8BBE\u5907\uFF08daemon \u4EE3\u7406\u4E2D\u5FC3 server\uFF09\u3002owner-only",
@@ -24467,10 +24599,242 @@ var DEPLOY_FILE = import_node_path3.default.join(".clawd", "deploy.json");
24467
24599
  var SCAN_FILE = import_node_path3.default.join(".clawd", "deploy-scan.json");
24468
24600
  var z1 = DeployScanSchema.omit({ id: true, manifest: true }).extend({ releasedHead: DeployScanSchema.shape.head }).strict();
24469
24601
  var z2 = external_exports.object({ version: external_exports.literal(2), scans: external_exports.array(DeployScanSchema), released: DeployReleasedSchema.optional() }).strict();
24602
+ var z3 = external_exports.object({ version: external_exports.literal(3), scans: external_exports.array(DeployScanSchema), releases: external_exports.array(DeployReleasedSchema) }).strict();
24470
24603
  var PackageFindingSchema = EnvPackageSchema.omit({ localVersion: true, artifact: true, aptMissing: true, aptVersion: true }).extend({
24471
24604
  artifact: external_exports.object({ url: external_exports.string().url(), bin: external_exports.string() }).strict().optional()
24472
24605
  });
24473
24606
 
24607
+ // src/deploy/release-workflow.ts
24608
+ function renderDeployWorkflow(config2) {
24609
+ const identity = [
24610
+ " - name: Select pinned source identities",
24611
+ " env:",
24612
+ " RELEASE_JSON: ${{ inputs.release_json }}",
24613
+ " run: |",
24614
+ " node --input-type=module <<'NODE'",
24615
+ ' import fs from "node:fs"',
24616
+ ' const file = "candidate-release.json"',
24617
+ ' const r = fs.existsSync(file) ? JSON.parse(fs.readFileSync(file, "utf8")) : process.env.RELEASE_JSON ? JSON.parse(process.env.RELEASE_JSON) : undefined',
24618
+ ' if (r && (!/^[a-f0-9]{40}$/.test(r.commit) || !/^[a-f0-9]{40}$/.test(r.pipelineCommit) || r.repository !== process.env.GITHUB_REPOSITORY)) throw new Error("invalid Persona release identity")',
24619
+ ' if (process.env.DEPLOY_ENVIRONMENT === "production" && (!r || process.env.GITHUB_REF_NAME !== "main" || process.env.GITHUB_SHA !== r.commit)) throw new Error("production main must equal tested commit")',
24620
+ ' fs.appendFileSync(process.env.GITHUB_ENV, "SOURCE_COMMIT=" + (r?.commit ?? process.env.GITHUB_SHA) + "\\nPIPELINE_COMMIT=" + (r?.pipelineCommit ?? process.env.CLAWOS_REF) + "\\n")',
24621
+ " NODE",
24622
+ ""
24623
+ ];
24624
+ const contract = [
24625
+ ...identity,
24626
+ " - name: Checkout persona",
24627
+ " uses: actions/checkout@v4",
24628
+ " with:",
24629
+ " path: persona",
24630
+ " ref: ${{ env.SOURCE_COMMIT }}",
24631
+ " sparse-checkout: .clawd",
24632
+ "",
24633
+ " - name: Checkout pinned pipeline",
24634
+ " uses: actions/checkout@v4",
24635
+ " with:",
24636
+ " repository: ${{ env.CLAWOS_REPO }}",
24637
+ " ref: ${{ env.PIPELINE_COMMIT }}",
24638
+ " token: ${{ secrets.CLAWOS_READ_TOKEN }}",
24639
+ " path: clawos",
24640
+ " sparse-checkout: |",
24641
+ " cloud-host/pipeline",
24642
+ " cloud-host/k8s",
24643
+ "",
24644
+ " - name: \u8BFB\u90E8\u7F72\u6587\u4EF6",
24645
+ " id: plan",
24646
+ " run: |",
24647
+ " node clawos/cloud-host/pipeline/deploy-file.mjs \\",
24648
+ " --persona-dir persona \\",
24649
+ " --repo-name '${{ github.event.repository.name }}' \\",
24650
+ ' --sha "$SOURCE_COMMIT" >> "$GITHUB_OUTPUT"',
24651
+ "",
24652
+ " - name: Bind pipeline source",
24653
+ ' run: echo "PIPELINE_COMMIT=$(git -C clawos rev-parse HEAD)" >> "$GITHUB_ENV"',
24654
+ "",
24655
+ " - name: Select integration credentials",
24656
+ " if: inputs.environment != 'production'",
24657
+ " env:",
24658
+ " CLAWD_INT_GATEWAY_URL: ${{ vars.CLAWD_INT_GATEWAY_URL }}",
24659
+ " CLAWD_INT_GATEWAY_ADMIN_KEY: ${{ secrets.CLAWD_INT_GATEWAY_ADMIN_KEY }}",
24660
+ " CLAWD_INT_PERSONA_SECRETS_JSON: ${{ toJSON(secrets) }}",
24661
+ " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
24662
+ " run: node clawos/cloud-host/pipeline/persona-candidate.mjs env",
24663
+ "",
24664
+ " - name: Select production credentials",
24665
+ " if: inputs.environment == 'production'",
24666
+ " env:",
24667
+ " CLAWD_GATEWAY_URL: ${{ vars.CLAWD_GATEWAY_URL }}",
24668
+ " CLAWD_GATEWAY_ADMIN_KEY: ${{ secrets.CLAWD_GATEWAY_ADMIN_KEY }}",
24669
+ " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
24670
+ " run: node clawos/cloud-host/pipeline/persona-candidate.mjs env",
24671
+ "",
24672
+ " - name: Check required credentials",
24673
+ " env:",
24674
+ " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
24675
+ " run: node clawos/cloud-host/pipeline/check-secrets.mjs",
24676
+ ""
24677
+ ];
24678
+ const download = (name) => [
24679
+ " - uses: actions/download-artifact@v4",
24680
+ " with:",
24681
+ ` name: ${name}`,
24682
+ ""
24683
+ ];
24684
+ const upload = (name) => [
24685
+ " - uses: actions/upload-artifact@v4",
24686
+ ...name.startsWith("persona-verified") ? [" if: inputs.environment != 'production'"] : [],
24687
+ " with:",
24688
+ ` name: ${name}`,
24689
+ " path: candidate-release.json",
24690
+ " overwrite: true",
24691
+ ""
24692
+ ];
24693
+ const runtime = (script) => [
24694
+ ` - name: ${script === "smoke" ? "Run real int smoke" : "Register the verified image"}`,
24695
+ " env:",
24696
+ " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
24697
+ " run: |",
24698
+ ` IMAGE_REF=$(node clawos/cloud-host/pipeline/release.mjs validate --file candidate-release.json --component persona${script === "register" ? " --production" : ""})`,
24699
+ ...script === "register" ? [" node clawos/cloud-host/pipeline/persona-candidate.mjs check-source"] : [],
24700
+ ` node clawos/cloud-host/pipeline/${script}.mjs \\`,
24701
+ ' --image "$IMAGE_REF" \\',
24702
+ " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
24703
+ " --model '${{ steps.plan.outputs.model }}' \\",
24704
+ " --effort '${{ steps.plan.outputs.effort }}' \\",
24705
+ " --size '${{ steps.plan.outputs.size }}' \\",
24706
+ " --task-concurrency '${{ steps.plan.outputs.task_concurrency }}' \\",
24707
+ " --engine '${{ steps.plan.outputs.engine }}' \\",
24708
+ " --connectors '${{ steps.plan.outputs.connectors }}' \\",
24709
+ " --run-number '${{ github.run_number }}'",
24710
+ ""
24711
+ ];
24712
+ const job = (name) => [
24713
+ ` ${name}:`,
24714
+ ` name: ${name}`,
24715
+ " runs-on: ubuntu-latest",
24716
+ " environment: ${{ inputs.environment || 'integration' }}",
24717
+ " timeout-minutes: 40"
24718
+ ];
24719
+ return [
24720
+ "name: clawd deploy",
24721
+ "run-name: ${{ inputs.environment == 'production' && format('persona-production-{0}', inputs.promotion_id) || 'persona-integration' }}",
24722
+ "# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\u3002push \u6784\u5EFA int \u5019\u9009\uFF1Bproduction \u624B\u52A8\u664B\u7EA7\u5DF2\u9A8C\u6536\u5236\u54C1\u3002",
24723
+ "on:",
24724
+ " push:",
24725
+ " branches: [integration]",
24726
+ " workflow_dispatch:",
24727
+ " inputs:",
24728
+ " environment:",
24729
+ " type: choice",
24730
+ " options: [integration, production]",
24731
+ " default: integration",
24732
+ " promotion_id:",
24733
+ " type: string",
24734
+ " required: false",
24735
+ " release_json:",
24736
+ " description: Verified Persona release JSON for production promotion",
24737
+ " type: string",
24738
+ " required: false",
24739
+ "",
24740
+ "concurrency:",
24741
+ " group: persona-cloud-${{ github.repository }}",
24742
+ " queue: max",
24743
+ " cancel-in-progress: false",
24744
+ "",
24745
+ "env:",
24746
+ ` REGISTRY: ${config2.registry}`,
24747
+ ` VPC_REGISTRY: ${config2.vpcRegistry}`,
24748
+ ` ACR_NAMESPACE: ${config2.namespace}`,
24749
+ ` CLAWOS_REPO: ${config2.repository}`,
24750
+ " CLAWOS_REF: ${{ vars.CLAWD_PIPELINE_REF || '" + config2.ref + "' }}",
24751
+ " DEPLOY_ENVIRONMENT: ${{ inputs.environment || 'integration' }}",
24752
+ "",
24753
+ "permissions:",
24754
+ " contents: read",
24755
+ "",
24756
+ "jobs:",
24757
+ ...job("build"),
24758
+ " steps:",
24759
+ ...contract,
24760
+ " - name: Dockerfile matches Persona directory",
24761
+ " if: inputs.environment != 'production'",
24762
+ " run: |",
24763
+ " test -f persona/Dockerfile",
24764
+ " grep -qF '/clawd/personas/${{ steps.plan.outputs.persona_id }}/' persona/Dockerfile",
24765
+ "",
24766
+ " - name: Install aliyun CLI",
24767
+ " if: inputs.environment != 'production'",
24768
+ " env:",
24769
+ " GH_TOKEN: ${{ github.token }}",
24770
+ " run: |",
24771
+ " TAGNAME=$(gh release view --repo aliyun/aliyun-cli --json tagName -q .tagName)",
24772
+ ' VER=$(printf %s "$TAGNAME" | sed s/^v//)',
24773
+ ' curl -fsSL -o /tmp/aliyun-cli.tgz "https://github.com/aliyun/aliyun-cli/releases/download/$TAGNAME/aliyun-cli-linux-$VER-amd64.tgz"',
24774
+ " sudo tar -xzf /tmp/aliyun-cli.tgz -C /usr/local/bin",
24775
+ "",
24776
+ " - name: Login to ACR",
24777
+ " if: inputs.environment != 'production'",
24778
+ " uses: aliyun/acr-login@v1",
24779
+ " with:",
24780
+ " login-server: ${{ env.REGISTRY }}",
24781
+ " username: ${{ secrets.ALI_DOCKER_USERNAME }}",
24782
+ " password: ${{ secrets.ALI_DOCKER_PASSWORD }}",
24783
+ "",
24784
+ " - name: Select candidate or promote without rebuilding",
24785
+ " env:",
24786
+ " ALIBABA_CLOUD_ACCESS_KEY_ID: ${{ secrets.ALI_ACS_ACCESS_KEY_ID }}",
24787
+ " ALIBABA_CLOUD_ACCESS_KEY_SECRET: ${{ secrets.ALI_ACS_ACCESS_KEY_SECRET }}",
24788
+ " RELEASE_JSON: ${{ inputs.release_json }}",
24789
+ " run: node clawos/cloud-host/pipeline/persona-candidate.mjs",
24790
+ "",
24791
+ ...upload("persona-candidate"),
24792
+ ...job("smoke"),
24793
+ " needs: build",
24794
+ " if: inputs.environment != 'production'",
24795
+ " steps:",
24796
+ ...download("persona-candidate"),
24797
+ ...contract,
24798
+ ...runtime("smoke"),
24799
+ " - name: Attest successful int runtime smoke",
24800
+ ' run: node clawos/cloud-host/pipeline/release.mjs attest --file candidate-release.json --endpoint "$CLAWD_GATEWAY_URL" --checks persona-smoke --out candidate-release.json',
24801
+ "",
24802
+ ...upload("persona-smoked"),
24803
+ ...job("deploy"),
24804
+ " needs: [build, smoke]",
24805
+ " if: always() && needs.build.result == 'success' && (needs.smoke.result == 'success' || needs.smoke.result == 'skipped')",
24806
+ " steps:",
24807
+ ...download("${{ inputs.environment == 'production' && 'persona-candidate' || 'persona-smoked' }}"),
24808
+ ...contract,
24809
+ ...runtime("register"),
24810
+ ...upload("persona-verified-${{ github.run_attempt }}")
24811
+ ].join("\n");
24812
+ }
24813
+
24814
+ // src/deploy/templates.ts
24815
+ var import_node_crypto2 = require("crypto");
24816
+
24817
+ // src/deploy/default-base-release.json
24818
+ var default_base_release_default = {
24819
+ version: 1,
24820
+ environment: "integration",
24821
+ component: "base",
24822
+ image: "registry-vpc.cn-hangzhou.aliyuncs.com/ttc-prod/clawd-persona-base@sha256:9a0952c6bc94a6595374da7db125b5089b476d0bd88f280bd981757d9f572c22",
24823
+ commit: "8dfab2c57781e9f9600e3f99a79adcfbef455f2e",
24824
+ verification: {
24825
+ status: "passed",
24826
+ fingerprint: "d7b03abb9d2bf3a4d7f6f88ac43a2d33d6ec7a7c94ae816f7dae11d67d338194",
24827
+ checks: [
24828
+ "base-smoke",
24829
+ "codex-smoke",
24830
+ "pi-smoke",
24831
+ "workspace-persistence"
24832
+ ],
24833
+ endpoint: "https://persona-int.clawos.chat",
24834
+ verifiedAt: "2026-10-08T09:34:53.131Z"
24835
+ }
24836
+ };
24837
+
24474
24838
  // src/deploy/templates.ts
24475
24839
  var CLAWOS_REPO = "ottin4ttc/clawos";
24476
24840
  var CLAWOS_REF = "release";
@@ -24481,7 +24845,17 @@ var UNPUBLISH_WORKFLOW_PATH = `.github/workflows/${UNPUBLISH_WORKFLOW_FILE}`;
24481
24845
  var ACR_REGISTRY = "registry.cn-hangzhou.aliyuncs.com";
24482
24846
  var ACR_VPC_REGISTRY = "registry-vpc.cn-hangzhou.aliyuncs.com";
24483
24847
  var ACR_NAMESPACE = "ttc-prod";
24484
- var BASE_IMAGE = `${ACR_REGISTRY}/${ACR_NAMESPACE}/clawd-persona-base:release`;
24848
+ var acceptedBase = VerifiedBaseReleaseSchema.parse(default_base_release_default);
24849
+ var baseFingerprint = (0, import_node_crypto2.createHash)("sha256").update(JSON.stringify({
24850
+ component: acceptedBase.component,
24851
+ image: acceptedBase.image,
24852
+ commit: acceptedBase.commit,
24853
+ baseImage: null,
24854
+ pipelineCommit: null,
24855
+ repository: null
24856
+ })).digest("hex");
24857
+ if (baseFingerprint !== acceptedBase.verification.fingerprint) throw new Error("\u5E73\u53F0\u9ED8\u8BA4\u5E95\u5EA7\u4E0E\u5DF2\u9A8C\u6536\u5236\u54C1\u4E0D\u4E00\u81F4");
24858
+ var BASE_IMAGE = acceptedBase.image.replace(`${ACR_VPC_REGISTRY}/`, `${ACR_REGISTRY}/`);
24485
24859
  var DOCKERIGNORE_TEMPLATE = [
24486
24860
  "# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\uFF08\u540C Dockerfile\uFF09\u3002",
24487
24861
  ".git",
@@ -24520,170 +24894,8 @@ var CONTRACT_STEPS = [
24520
24894
  "",
24521
24895
  ...PLAN_STEP
24522
24896
  ];
24523
- var ACR_LOGIN_STEPS = [
24524
- " - name: Login to ACR\uFF08\u89E3\u6790\u955C\u50CF digest \u8981 docker \u51ED\u636E\uFF09",
24525
- " uses: aliyun/acr-login@v1",
24526
- " with:",
24527
- " login-server: ${{ env.REGISTRY }}",
24528
- ' username: "${{ secrets.ALI_DOCKER_USERNAME }}"',
24529
- ' password: "${{ secrets.ALI_DOCKER_PASSWORD }}"',
24530
- ""
24531
- ];
24532
- var IMAGE_LATEST = '"$REGISTRY/$ACR_NAMESPACE/${{ steps.plan.outputs.persona_id }}:latest"';
24533
- var RESOLVE_LINE = ` IMAGE_REF=$(node clawos/cloud-host/pipeline/acr.mjs resolve --image ${IMAGE_LATEST} --vpc-registry "$VPC_REGISTRY")`;
24534
24897
  var CONCURRENCY_GROUP = " group: persona-cloud-${{ github.repository }}";
24535
- var L = [
24536
- "name: clawd deploy",
24537
- "",
24538
- "# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\uFF1A\u6BCF\u6B21\u300C\u53D1\u5E03\u300D\u90FD\u4F1A\u7528\u5F53\u524D\u6A21\u677F\u91CD\u5199\u8FD9\u4EFD\u6587\u4EF6\u518D\u63D0\u4EA4\uFF0C\u624B\u6539\u4F1A\u88AB\u76D6\u6389\u3002",
24539
- "# \u4E09\u6BB5\uFF1Abuild \u8BA9 ACR \u4ECE\u8FD9\u4E2A\u4ED3\u5E93\u6784 persona \u955C\u50CF\uFF08Dockerfile \u4E5F\u662F clawd \u5199\u7684\uFF09\u2192 smoke \u5728\u96C6\u7FA4\u4E0A\u771F\u8D77\u4E00\u6B21 \u2192 deploy \u5728 gateway \u767B\u8BB0\u6210\u6B63\u5F0F\u3002",
24540
- "# \u955C\u50CF\u4E0D\u5728 runner \u4E0A\u6784\u3001\u4E5F\u4E0D\u4ECE runner \u63A8\uFF1AACR \u4E2A\u4EBA\u7248\u4ED3\u5E93 ttc-prod/<persona_id> \u6302\u7740\u8FD9\u4E2A GitHub \u4ED3\u5E93\u5F53\u4EE3\u7801\u6E90\uFF08\u9996\u6B21\u53D1\u5E03\u65F6\u81EA\u5EFA\uFF09\uFF0C",
24541
- "# build \u6BB5\u53EA\u662F\u300C\u89E6\u53D1 \u2192 \u7B49\u5B83\u6784\u51FA\u672C\u6B21 commit\u300D\uFF1Bsmoke / deploy \u5404\u81EA\u628A :latest \u89E3\u6790\u6210 digest \u518D\u7528\u3002\u6D41\u6C34\u7EBF\u811A\u672C\u5728 ottin4ttc/clawos \u4ED3\u5E93\u91CC\u3002",
24542
- "#",
24543
- "# \u8981\u7684\u7EC4\u7EC7\u7EA7 Secrets\uFF1AALI_ACS_ACCESS_KEY_ID / ALI_ACS_ACCESS_KEY_SECRET\uFF08ACR OpenAPI\uFF1A\u5EFA\u4ED3\u5E93 / \u89E6\u53D1 / \u67E5\u6784\u5EFA\u8BB0\u5F55\uFF09\u3001",
24544
- "# ALI_DOCKER_USERNAME / ALI_DOCKER_PASSWORD\uFF08\u89E3\u6790\u955C\u50CF digest\uFF09\u3001CLAWOS_READ_TOKEN\uFF08\u8BFB clawos \u4ED3\u5E93\uFF09\u3001CLAWD_GATEWAY_ADMIN_KEY\uFF1B",
24545
- "# \u7EC4\u7EC7\u7EA7 Variable\uFF1ACLAWD_GATEWAY_URL\u3002",
24546
- "# \u4ED3\u5E93\u7EA7\u540C\u540D\u914D\u7F6E\u4F1A\u76D6\u8FC7\u7EC4\u7EC7\u7EA7\u2014\u2014\u67D0\u4E2A persona \u8981\u6307\u5230\u53E6\u4E00\u53F0 gateway\uFF0C\u5728\u81EA\u5DF1\u4ED3\u5E93\u91CC\u914D\u5373\u53EF\u3002",
24547
- "",
24548
- "on:",
24549
- " push:",
24550
- " branches: [main]",
24551
- " workflow_dispatch:",
24552
- "",
24553
- "concurrency:",
24554
- " # \u540C\u4E00\u4E2A\u4ED3\u5E93\u7684\u53D1\u5E03\u6392\u961F\u8DD1\uFF0C\u4E0D\u53D6\u6D88\uFF1A\u4E0A\u4E00\u6B21\u53EF\u80FD\u5DF2\u7ECF\u5728\u767B\u8BB0\u6B63\u5F0F\u4E86",
24555
- CONCURRENCY_GROUP,
24556
- "",
24557
- "env:",
24558
- ` REGISTRY: ${ACR_REGISTRY}`,
24559
- ` VPC_REGISTRY: ${ACR_VPC_REGISTRY}`,
24560
- ` ACR_NAMESPACE: ${ACR_NAMESPACE}`,
24561
- ` CLAWOS_REPO: ${CLAWOS_REPO}`,
24562
- ` CLAWOS_REF: ${CLAWOS_REF}`,
24563
- "",
24564
- "permissions:",
24565
- " contents: read",
24566
- "",
24567
- "jobs:",
24568
- " build:",
24569
- // jobs API 只返 name 不返 key,故 name 必须用段 key。
24570
- " name: build",
24571
- " runs-on: ubuntu-latest",
24572
- // ACR 账号内串行构建,需给其他镜像排队留时间。
24573
- " timeout-minutes: 40",
24574
- " steps:",
24575
- ...CONTRACT_STEPS,
24576
- " - name: \u51ED\u636E\u9F50\u4E0D\u9F50\uFF08\u7F3A\u54EA\u51E0\u4E2A\u540D\u5B57\u4E00\u6B21\u5217\u5168\uFF09",
24577
- " env:",
24578
- " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
24579
- " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
24580
- " run: node clawos/cloud-host/pipeline/check-secrets.mjs",
24581
- "",
24582
- " - name: Dockerfile \u5728\u3001\u4E14\u62F7\u5230\u7684\u662F\u8FD9\u4E2A persona \u7684\u76EE\u5F55",
24583
- " # Dockerfile \u7531 clawd \u53D1\u5E03\u65F6\u5199\uFF08\u540C\u8FD9\u4EFD workflow\uFF09\uFF0CACR \u6309\u5B83\u6784\u3002\u76EE\u5F55\u540D\u90A3\u4E00\u6BB5\u8981\u4E0E deploy-file \u7B97\u51FA\u7684 persona_id \u4E00\u81F4\uFF1A",
24584
- " # \u4E24\u8FB9\u5404\u6709\u4E00\u4EFD\u540C\u6837\u7684\u540D\u5B57\u6E05\u6D17\uFF0C\u8FD9\u91CC\u662F\u5B83\u4EEC\u552F\u4E00\u7684\u4EA4\u6C47\u70B9\u3002",
24585
- " run: |",
24586
- " test -f persona/Dockerfile \\",
24587
- ' || { echo "\u2717 \u4ED3\u5E93\u91CC\u6CA1\u6709 Dockerfile\uFF1A\u8FD9\u6B21\u63A8\u9001\u4E0D\u662F clawd \u53D1\u5E03\u7684\uFF08\u6216 clawd \u592A\u65E7\uFF09\uFF1B\u56DE clawd \u7684\u4E0A\u4E91\u9875\u9762\u91CD\u65B0\u53D1\u5E03" >&2; exit 1; }',
24588
- " grep -qF '/clawd/personas/${{ steps.plan.outputs.persona_id }}/' persona/Dockerfile \\",
24589
- ' || { echo "\u2717 Dockerfile \u62F7\u5230\u7684\u76EE\u5F55\u4E0D\u662F /clawd/personas/${{ steps.plan.outputs.persona_id }}/" >&2; exit 1; }',
24590
- "",
24591
- " - name: \u88C5 aliyun CLI\uFF08ACR OpenAPI\uFF1A\u5EFA\u4ED3\u5E93 / \u89E6\u53D1 / \u67E5\u6784\u5EFA\u8BB0\u5F55\uFF09",
24592
- " env:",
24593
- " GH_TOKEN: ${{ github.token }}",
24594
- " run: |",
24595
- " TAGNAME=$(gh release view --repo aliyun/aliyun-cli --json tagName -q .tagName)",
24596
- // 不用 ${TAGNAME#v} 这种带花括号的展开:这份模板里 `${` 只许出现在 GitHub 表达式里(spec 守着)
24597
- ' VER=$(printf %s "$TAGNAME" | sed s/^v//)',
24598
- ' curl -fsSL -o /tmp/aliyun-cli.tgz "https://github.com/aliyun/aliyun-cli/releases/download/$TAGNAME/aliyun-cli-linux-$VER-amd64.tgz"',
24599
- " sudo tar -xzf /tmp/aliyun-cli.tgz -C /usr/local/bin",
24600
- " aliyun version",
24601
- "",
24602
- " - name: \u8BA9 ACR \u4ECE\u672C\u4ED3\u5E93\u6784\uFF08\u9996\u6B21\u53D1\u5E03\u5148\u5EFA ACR \u4ED3\u5E93\u4E0E\u89C4\u5219\uFF1B\u7B49\u5B83\u6784\u51FA\u672C\u6B21 commit\uFF09",
24603
- " # ACR \u6784\u7684\u662F main \u5F53\u524D\u7684 tip\u3001\u4E0D\u662F github.sha\uFF1Atip \u5DF2\u7ECF\u4E0D\u662F\u672C\u6B21 commit \u65F6\u76F4\u63A5\u7EA2\uFF0C\u8BA9\u66F4\u65B0\u7684\u90A3\u6B21 run \u53BB\u6784\u3001\u53BB\u767B\u8BB0\u3002",
24604
- " # \u81EA\u52A8\u6784\u5EFA\u5173\u7740\uFF1A\u53EA\u6709\u8FD9\u91CC\u89E6\u53D1\u3001webhook \u4E0D\u6784\uFF0C\u300C\u6784 \u2192 \u5192\u70DF \u2192 \u767B\u8BB0\u300D\u624D\u662F\u4E00\u6761\u6709\u5E8F\u7684\u94FE\u3002",
24605
- " # \u6784\u51FA\u7684\u662F\u54EA\u4E2A commit \u7531 acr.mjs wait \u6309\u6784\u5EFA\u8BB0\u5F55 + \u65E5\u5FD7\u91CC\u7684 commit \u6838\uFF0C\u4E0D\u770B\u955C\u50CF\u7684\u65F6\u95F4\uFF08\u7F13\u5B58\u547D\u4E2D\u65F6\u90A3\u662F\u8001\u7684\uFF09\u3002",
24606
- " env:",
24607
- " ALIBABA_CLOUD_ACCESS_KEY_ID: ${{ secrets.ALI_ACS_ACCESS_KEY_ID }}",
24608
- " ALIBABA_CLOUD_ACCESS_KEY_SECRET: ${{ secrets.ALI_ACS_ACCESS_KEY_SECRET }}",
24609
- " run: |",
24610
- // pipefail 让 ls-remote 失败正确传播,避免被 cut 的成功状态掩盖。
24611
- " set -eo pipefail",
24612
- ' REPO="$ACR_NAMESPACE/${{ steps.plan.outputs.persona_id }}"',
24613
- ' node clawos/cloud-host/pipeline/acr.mjs ensure-repo --repo "$REPO" \\',
24614
- " --source '${{ github.repository }}' --location / --dockerfile Dockerfile --branch main --tag latest \\",
24615
- " --summary 'clawd persona ${{ github.event.repository.name }}'",
24616
- " TIP=$(git -C persona ls-remote origin refs/heads/main | cut -f1)",
24617
- ` [ "$TIP" = '\${{ github.sha }}' ] \\`,
24618
- ' || { echo "\u2717 main \u5DF2\u7ECF\u63A8\u8FDB\u5230 $TIP\uFF0C\u672C\u6B21 ${{ github.sha }} \u4E0D\u518D\u6784\uFF1B\u7B49\u65B0\u7684\u90A3\u6B21 run" >&2; exit 1; }',
24619
- ' node clawos/cloud-host/pipeline/acr.mjs trigger --repo "$REPO" --tag latest',
24620
- ` node clawos/cloud-host/pipeline/acr.mjs wait --repo "$REPO" --tag latest --commit '\${{ github.sha }}' --timeout-sec 1800`,
24621
- "",
24622
- ...ACR_LOGIN_STEPS,
24623
- " - name: \u955C\u50CF = \u672C\u6B21 commit \u6784\u51FA\u7684\u90A3\u4EFD\uFF08digest\uFF1B\u53EA\u6253\u65E5\u5FD7\uFF0Csmoke / deploy \u5404\u81EA\u518D\u89E3\u6790\u4E00\u6B21\uFF09",
24624
- ` run: node clawos/cloud-host/pipeline/acr.mjs resolve --image ${IMAGE_LATEST} --vpc-registry "$VPC_REGISTRY"`,
24625
- "",
24626
- " smoke:",
24627
- " name: smoke",
24628
- " needs: build",
24629
- " runs-on: ubuntu-latest",
24630
- " timeout-minutes: 20",
24631
- " steps:",
24632
- ...CONTRACT_STEPS,
24633
- ...ACR_LOGIN_STEPS,
24634
- " - name: \u4E34\u65F6\u767B\u8BB0 \u2192 \u8D77\u4E00\u6B21 Pod \u2192 \u64A4\u9500",
24635
- " # \u767B\u8BB0\u6B63\u5F0F\u53EA\u662F\u5F80 gateway \u5199\u4E00\u884C\uFF0Cgateway \u4E0D\u78B0\u955C\u50CF\uFF1B\u96C6\u7FA4\u62C9\u955C\u50CF\u53D1\u751F\u5728\u7B2C\u4E00\u4E2A\u4EFB\u52A1\u5230\u6765\u65F6\u3002",
24636
- " # \u6CA1\u6709\u8FD9\u4E00\u6B65\uFF0C\u6D41\u6C34\u7EBF\u7EFF\u4E86\u53EA\u4EE3\u8868\u300C\u767B\u8BB0\u4E86\u300D\u3002\u955C\u50CF\u7528 digest\uFF08\u96C6\u7FA4 Job \u662F IfNotPresent\uFF0C\u79FB\u52A8 tag \u4F1A\u4E00\u76F4\u8DD1\u65E7\u7684\uFF09\u3002",
24637
- // smoke 与正式发布用同份模型/档位/连接器;deploy-file.mjs 拒绝单引号/换行等危险值,方可单引号拼参。
24638
- " env:",
24639
- " CLAWD_GATEWAY_URL: ${{ vars.CLAWD_GATEWAY_URL }}",
24640
- " CLAWD_GATEWAY_ADMIN_KEY: ${{ secrets.CLAWD_GATEWAY_ADMIN_KEY }}",
24641
- " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
24642
- " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
24643
- " run: |",
24644
- " set -e",
24645
- RESOLVE_LINE,
24646
- " node clawos/cloud-host/pipeline/smoke.mjs \\",
24647
- ' --image "$IMAGE_REF" \\',
24648
- " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
24649
- " --model '${{ steps.plan.outputs.model }}' \\",
24650
- " --effort '${{ steps.plan.outputs.effort }}' \\",
24651
- " --size '${{ steps.plan.outputs.size }}' \\",
24652
- " --task-concurrency '${{ steps.plan.outputs.task_concurrency }}' \\",
24653
- " --engine '${{ steps.plan.outputs.engine }}' \\",
24654
- " --connectors '${{ steps.plan.outputs.connectors }}' \\",
24655
- " --run-number '${{ github.run_number }}'",
24656
- "",
24657
- " deploy:",
24658
- " name: deploy",
24659
- " needs: [build, smoke]",
24660
- " runs-on: ubuntu-latest",
24661
- " # \u4ED3\u5E93\u914D\u4E86 production \u73AF\u5883\u7684\u300C\u987B\u5BA1\u6838\u4EBA\u6279\u51C6\u300D\uFF0Cjob \u5C31\u505C\u5728\u8FD9\u91CC\u7B49\u4EBA\u70B9\uFF1B\u6CA1\u914D\u5C31\u76F4\u63A5\u8FC7\u3002",
24662
- " environment: production",
24663
- " steps:",
24664
- ...CONTRACT_STEPS,
24665
- ...ACR_LOGIN_STEPS,
24666
- " - name: \u767B\u8BB0\u6B63\u5F0F",
24667
- " env:",
24668
- " CLAWD_GATEWAY_URL: ${{ vars.CLAWD_GATEWAY_URL }}",
24669
- " CLAWD_GATEWAY_ADMIN_KEY: ${{ secrets.CLAWD_GATEWAY_ADMIN_KEY }}",
24670
- " CLAWD_SECRETS_JSON: ${{ toJSON(secrets) }}",
24671
- " CLAWD_ENV_NAMES: ${{ steps.plan.outputs.env_names }}",
24672
- " run: |",
24673
- " set -e",
24674
- RESOLVE_LINE,
24675
- " node clawos/cloud-host/pipeline/register.mjs \\",
24676
- ' --image "$IMAGE_REF" \\',
24677
- " --persona-id '${{ steps.plan.outputs.persona_id }}' \\",
24678
- " --model '${{ steps.plan.outputs.model }}' \\",
24679
- " --effort '${{ steps.plan.outputs.effort }}' \\",
24680
- " --size '${{ steps.plan.outputs.size }}' \\",
24681
- " --task-concurrency '${{ steps.plan.outputs.task_concurrency }}' \\",
24682
- " --engine '${{ steps.plan.outputs.engine }}' \\",
24683
- " --connectors '${{ steps.plan.outputs.connectors }}'",
24684
- ""
24685
- ];
24686
- var WORKFLOW_TEMPLATE = L.join("\n");
24898
+ var WORKFLOW_TEMPLATE = renderDeployWorkflow({ registry: ACR_REGISTRY, vpcRegistry: ACR_VPC_REGISTRY, namespace: ACR_NAMESPACE, repository: CLAWOS_REPO, ref: CLAWOS_REF });
24687
24899
  var U = [
24688
24900
  "name: clawd unpublish",
24689
24901
  "",
@@ -24695,10 +24907,17 @@ var U = [
24695
24907
  "",
24696
24908
  "on:",
24697
24909
  " workflow_dispatch:",
24910
+ " inputs:",
24911
+ " environment:",
24912
+ " type: choice",
24913
+ " options: [integration, production]",
24914
+ " default: production",
24698
24915
  "",
24699
24916
  "concurrency:",
24700
- " # \u4E0E\u53D1\u5E03\u540C\u4E00\u7EC4\uFF1A\u53D1\u5E03\u5728\u8DD1\u65F6\u70B9\u4E0B\u7EBF\uFF0C\u6392\u5728\u5B83\u540E\u9762\uFF1B\u540E\u70B9\u7684\u9876\u6389\u5148\u70B9\u7684",
24917
+ " # \u4E0E\u53D1\u5E03\u540C\u4E00\u7EC4\u4E32\u884C\u7B49\u5F85\uFF0C\u65B0\u7684\u4EFB\u52A1\u4E0D\u4F1A\u66FF\u6362\u7B49\u5F85\u4E2D\u7684\u4EFB\u52A1",
24701
24918
  CONCURRENCY_GROUP,
24919
+ " queue: max",
24920
+ " cancel-in-progress: false",
24702
24921
  "",
24703
24922
  "env:",
24704
24923
  ` CLAWOS_REPO: ${CLAWOS_REPO}`,
@@ -24711,14 +24930,23 @@ var U = [
24711
24930
  " unpublish:",
24712
24931
  " name: unpublish",
24713
24932
  " runs-on: ubuntu-latest",
24933
+ " environment: ${{ inputs.environment || 'integration' }}",
24714
24934
  " timeout-minutes: 10",
24715
24935
  " steps:",
24716
24936
  ...CONTRACT_STEPS,
24717
- " - name: \u64A4\u767B\u8BB0",
24937
+ " - name: \u64A4 production \u767B\u8BB0",
24938
+ " if: inputs.environment == 'production'",
24718
24939
  " env:",
24719
24940
  " CLAWD_GATEWAY_URL: ${{ vars.CLAWD_GATEWAY_URL }}",
24720
24941
  " CLAWD_GATEWAY_ADMIN_KEY: ${{ secrets.CLAWD_GATEWAY_ADMIN_KEY }}",
24721
24942
  " run: node clawos/cloud-host/pipeline/unregister.mjs --persona-id '${{ steps.plan.outputs.persona_id }}'",
24943
+ " - name: \u64A4 int \u767B\u8BB0",
24944
+ " if: inputs.environment != 'production'",
24945
+ " env:",
24946
+ " CLAWD_GATEWAY_URL: ${{ vars.CLAWD_INT_GATEWAY_URL }}",
24947
+ " CLAWD_GATEWAY_ADMIN_KEY: ${{ secrets.CLAWD_INT_GATEWAY_ADMIN_KEY }}",
24948
+ " run: node clawos/cloud-host/pipeline/unregister.mjs --persona-id '${{ steps.plan.outputs.persona_id }}'",
24949
+ "",
24722
24950
  ""
24723
24951
  ];
24724
24952
  var UNPUBLISH_WORKFLOW_TEMPLATE = U.join("\n");