@clawos-dev/clawd 0.2.489 → 0.2.490

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.
@@ -21317,10 +21317,22 @@ var EnvSecretSchema = external_exports.object({
21317
21317
  var EnvAssetSchema = external_exports.object({
21318
21318
  name: external_exports.string().min(1)
21319
21319
  });
21320
+ var ConnectorNameSchema = external_exports.string().regex(/^[a-z0-9-]+$/, "\u8FDE\u63A5\u5668\u540D\u53EA\u80FD\u662F\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u77ED\u6A2A\u7EBF");
21321
+ var EnvConnectorSchema = external_exports.object({ name: ConnectorNameSchema });
21320
21322
  var MANIFEST_BODY = {
21321
21323
  clis: external_exports.array(EnvCliSchema),
21322
21324
  secrets: external_exports.array(EnvSecretSchema),
21323
- assets: external_exports.array(EnvAssetSchema)
21325
+ assets: external_exports.array(EnvAssetSchema),
21326
+ /**
21327
+ * 装了哪些连接器(design 2026-09-09-cloud-connector-credentials §7.1)。**字符串数组**,
21328
+ * 是四段里唯一不是 `{name}` 对象数组的一段:连接器没有任何附加属性,包一层对象只是多一层壳。
21329
+ *
21330
+ * 不复用 secrets:那段说的是「需要一份值,由部署者填」,这里没有值要填;
21331
+ * 不从 clis 推断:lark-cli 在底座里,每个 persona 都有它,推不出任何东西。
21332
+ *
21333
+ * **缺省空而不是必填**:本机上已有的单据不用为此重扫一遍;没声明就是没装,扫描器照样会报。
21334
+ */
21335
+ connectors: external_exports.array(ConnectorNameSchema).default([])
21324
21336
  };
21325
21337
  var EnvManifestBodySchema = external_exports.object(MANIFEST_BODY);
21326
21338
  var EnvironmentManifestSchema = external_exports.object({
@@ -21453,8 +21465,9 @@ var DeployRerunJobArgsSchema = external_exports.object({
21453
21465
  }).strict();
21454
21466
  var DeployReportFindingArgsSchema = external_exports.object({
21455
21467
  personaId: external_exports.string().min(1),
21456
- kind: external_exports.enum(["cli", "secret", "asset"]),
21468
+ kind: external_exports.enum(["cli", "secret", "asset", "connector"]),
21457
21469
  // 该条目在 manifest 对应数组里的内容(形状随 kind 变,handler 按 kind 收窄校验)
21470
+ // connector 的 item 只有 name,落进清单时只留名字(manifest.connectors 是字符串数组)
21458
21471
  item: external_exports.record(external_exports.string(), external_exports.unknown()),
21459
21472
  // 这条发现的来历(一句人话 + 原文出处),形状同 EnvEvidence,target 由 handler 从 kind+name 派生
21460
21473
  evidence: external_exports.object({
@@ -21750,6 +21763,16 @@ var DispatchRecordSchema = external_exports.object({
21750
21763
  sourceSessionId: external_exports.string().min(1),
21751
21764
  sourcePersonaId: external_exports.string().min(1).optional(),
21752
21765
  targetPersonaId: external_exports.string().min(1),
21766
+ /**
21767
+ * 跨设备派活时 B 所在的设备(`DispatchRunArgs.targetDeviceId`),A 端台账记「我派给了谁的机器」。
21768
+ *
21769
+ * **缺省即本机**,与入参侧用 `undefined` 表示本机是同一条口径——不引第二种表示法。
21770
+ * 存量台账行没有这个字段,消费方(dispatch 卡片的归属带)据此只显示 persona、不显示设备。
21771
+ *
21772
+ * B 端自己的台账行**不会**有它:peer-forward 转发时故意 strip 掉(B 据此判定本地执行),
21773
+ * 那条行记的是 B 视角的本地 dispatch。
21774
+ */
21775
+ targetDeviceId: external_exports.string().min(1).optional(),
21753
21776
  /** B 的 sessionId;registerBSession 后回填 */
21754
21777
  workerSessionId: external_exports.string().min(1).optional(),
21755
21778
  /** 任务摘要;截断(≤500 字符)在 daemon store.add 处保证 */
@@ -21776,7 +21799,17 @@ var DispatchRecordSchema = external_exports.object({
21776
21799
  deliveredAt: external_exports.string().min(1).optional()
21777
21800
  });
21778
21801
  var DispatchListArgsSchema = external_exports.object({
21779
- sourceSessionId: external_exports.string().min(1).optional()
21802
+ sourceSessionId: external_exports.string().min(1).optional(),
21803
+ /**
21804
+ * 「**这条会话卷入的**所有台账行」:`sourceSessionId === it || workerSessionId === it`。
21805
+ *
21806
+ * 为什么不复用 `sourceSessionId`:一条会话既可能是派活方(在自己这儿看回报卡),也可能是
21807
+ * 干活方(在 worker 会话里看任务包),后者用 sourceSessionId 过滤一条也查不到。UI 的
21808
+ * dispatch 卡片要的正是「跟我这条会话有关的全部 dispatch」,一次调用答完,不必拉全量再本地筛。
21809
+ *
21810
+ * 与 `sourceSessionId` 同时给时两个条件都要满足(AND),但调用方没有这么用的场景。
21811
+ */
21812
+ relatedSessionId: external_exports.string().min(1).optional()
21780
21813
  });
21781
21814
  var DispatchListResultSchema = external_exports.object({
21782
21815
  records: external_exports.array(DispatchRecordSchema)
package/dist/cli.cjs CHANGED
@@ -5951,7 +5951,7 @@ var init_contact_handshake = __esm({
5951
5951
  });
5952
5952
 
5953
5953
  // ../protocol/src/environment-schemas.ts
5954
- var EnvCliSchema, EnvSecretSchema, EnvAssetSchema, MANIFEST_BODY, EnvManifestBodySchema, EnvironmentManifestSchema, EnvEvidenceSchema;
5954
+ var EnvCliSchema, EnvSecretSchema, EnvAssetSchema, ConnectorNameSchema, EnvConnectorSchema, MANIFEST_BODY, EnvManifestBodySchema, EnvironmentManifestSchema, EnvEvidenceSchema;
5955
5955
  var init_environment_schemas = __esm({
5956
5956
  "../protocol/src/environment-schemas.ts"() {
5957
5957
  "use strict";
@@ -5993,10 +5993,22 @@ var init_environment_schemas = __esm({
5993
5993
  EnvAssetSchema = external_exports.object({
5994
5994
  name: external_exports.string().min(1)
5995
5995
  });
5996
+ ConnectorNameSchema = external_exports.string().regex(/^[a-z0-9-]+$/, "\u8FDE\u63A5\u5668\u540D\u53EA\u80FD\u662F\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u77ED\u6A2A\u7EBF");
5997
+ EnvConnectorSchema = external_exports.object({ name: ConnectorNameSchema });
5996
5998
  MANIFEST_BODY = {
5997
5999
  clis: external_exports.array(EnvCliSchema),
5998
6000
  secrets: external_exports.array(EnvSecretSchema),
5999
- assets: external_exports.array(EnvAssetSchema)
6001
+ assets: external_exports.array(EnvAssetSchema),
6002
+ /**
6003
+ * 装了哪些连接器(design 2026-09-09-cloud-connector-credentials §7.1)。**字符串数组**,
6004
+ * 是四段里唯一不是 `{name}` 对象数组的一段:连接器没有任何附加属性,包一层对象只是多一层壳。
6005
+ *
6006
+ * 不复用 secrets:那段说的是「需要一份值,由部署者填」,这里没有值要填;
6007
+ * 不从 clis 推断:lark-cli 在底座里,每个 persona 都有它,推不出任何东西。
6008
+ *
6009
+ * **缺省空而不是必填**:本机上已有的单据不用为此重扫一遍;没声明就是没装,扫描器照样会报。
6010
+ */
6011
+ connectors: external_exports.array(ConnectorNameSchema).default([])
6000
6012
  };
6001
6013
  EnvManifestBodySchema = external_exports.object(MANIFEST_BODY);
6002
6014
  EnvironmentManifestSchema = external_exports.object({
@@ -6148,8 +6160,9 @@ var init_deploy_schemas = __esm({
6148
6160
  }).strict();
6149
6161
  DeployReportFindingArgsSchema = external_exports.object({
6150
6162
  personaId: external_exports.string().min(1),
6151
- kind: external_exports.enum(["cli", "secret", "asset"]),
6163
+ kind: external_exports.enum(["cli", "secret", "asset", "connector"]),
6152
6164
  // 该条目在 manifest 对应数组里的内容(形状随 kind 变,handler 按 kind 收窄校验)
6165
+ // connector 的 item 只有 name,落进清单时只留名字(manifest.connectors 是字符串数组)
6153
6166
  item: external_exports.record(external_exports.string(), external_exports.unknown()),
6154
6167
  // 这条发现的来历(一句人话 + 原文出处),形状同 EnvEvidence,target 由 handler 从 kind+name 派生
6155
6168
  evidence: external_exports.object({
@@ -6494,6 +6507,16 @@ var init_dispatch = __esm({
6494
6507
  sourceSessionId: external_exports.string().min(1),
6495
6508
  sourcePersonaId: external_exports.string().min(1).optional(),
6496
6509
  targetPersonaId: external_exports.string().min(1),
6510
+ /**
6511
+ * 跨设备派活时 B 所在的设备(`DispatchRunArgs.targetDeviceId`),A 端台账记「我派给了谁的机器」。
6512
+ *
6513
+ * **缺省即本机**,与入参侧用 `undefined` 表示本机是同一条口径——不引第二种表示法。
6514
+ * 存量台账行没有这个字段,消费方(dispatch 卡片的归属带)据此只显示 persona、不显示设备。
6515
+ *
6516
+ * B 端自己的台账行**不会**有它:peer-forward 转发时故意 strip 掉(B 据此判定本地执行),
6517
+ * 那条行记的是 B 视角的本地 dispatch。
6518
+ */
6519
+ targetDeviceId: external_exports.string().min(1).optional(),
6497
6520
  /** B 的 sessionId;registerBSession 后回填 */
6498
6521
  workerSessionId: external_exports.string().min(1).optional(),
6499
6522
  /** 任务摘要;截断(≤500 字符)在 daemon store.add 处保证 */
@@ -6520,7 +6543,17 @@ var init_dispatch = __esm({
6520
6543
  deliveredAt: external_exports.string().min(1).optional()
6521
6544
  });
6522
6545
  DispatchListArgsSchema = external_exports.object({
6523
- sourceSessionId: external_exports.string().min(1).optional()
6546
+ sourceSessionId: external_exports.string().min(1).optional(),
6547
+ /**
6548
+ * 「**这条会话卷入的**所有台账行」:`sourceSessionId === it || workerSessionId === it`。
6549
+ *
6550
+ * 为什么不复用 `sourceSessionId`:一条会话既可能是派活方(在自己这儿看回报卡),也可能是
6551
+ * 干活方(在 worker 会话里看任务包),后者用 sourceSessionId 过滤一条也查不到。UI 的
6552
+ * dispatch 卡片要的正是「跟我这条会话有关的全部 dispatch」,一次调用答完,不必拉全量再本地筛。
6553
+ *
6554
+ * 与 `sourceSessionId` 同时给时两个条件都要满足(AND),但调用方没有这么用的场景。
6555
+ */
6556
+ relatedSessionId: external_exports.string().min(1).optional()
6524
6557
  });
6525
6558
  DispatchListResultSchema = external_exports.object({
6526
6559
  records: external_exports.array(DispatchRecordSchema)
@@ -53667,6 +53700,7 @@ var PersonaDispatchManager = class {
53667
53700
  sourceSessionId: args.sourceSessionId,
53668
53701
  ...args.sourcePersonaId ? { sourcePersonaId: args.sourcePersonaId } : {},
53669
53702
  targetPersonaId: args.targetPersona,
53703
+ ...args.targetDeviceId ? { targetDeviceId: args.targetDeviceId } : {},
53670
53704
  taskText: args.taskText,
53671
53705
  ...args.taskBrief ? { taskBrief: args.taskBrief } : {},
53672
53706
  ...args.meta ? { meta: args.meta } : {}
@@ -53784,6 +53818,7 @@ function createDispatchStore(deps) {
53784
53818
  sourceSessionId: input.sourceSessionId,
53785
53819
  ...input.sourcePersonaId ? { sourcePersonaId: input.sourcePersonaId } : {},
53786
53820
  targetPersonaId: input.targetPersonaId,
53821
+ ...input.targetDeviceId ? { targetDeviceId: input.targetDeviceId } : {},
53787
53822
  taskText: input.taskText.slice(0, TASK_TEXT_MAX),
53788
53823
  ...input.taskBrief ? { taskBrief: input.taskBrief } : {},
53789
53824
  // 新开 dispatch = 第 1 轮;续派在 handler 里 +1
@@ -53805,7 +53840,9 @@ function createDispatchStore(deps) {
53805
53840
  return merged;
53806
53841
  }
53807
53842
  function list(filter) {
53808
- return records.filter((r) => !filter?.sourceSessionId || r.sourceSessionId === filter.sourceSessionId).slice().sort((a, b2) => a.createdAt < b2.createdAt ? 1 : a.createdAt > b2.createdAt ? -1 : 0);
53843
+ return records.filter((r) => !filter?.sourceSessionId || r.sourceSessionId === filter.sourceSessionId).filter(
53844
+ (r) => !filter?.relatedSessionId || r.sourceSessionId === filter.relatedSessionId || r.workerSessionId === filter.relatedSessionId
53845
+ ).slice().sort((a, b2) => a.createdAt < b2.createdAt ? 1 : a.createdAt > b2.createdAt ? -1 : 0);
53809
53846
  }
53810
53847
  function markInterruptedAsFailed(nowIso3) {
53811
53848
  let touched = false;
@@ -54993,11 +55030,16 @@ async function writeScan(dir, scan) {
54993
55030
  await writeJson(import_node_path31.default.join(dir, SCAN_FILE), DeployScanSchema.parse(scan));
54994
55031
  }
54995
55032
  function emptyDeployFile() {
54996
- return { version: 1, manifest: { version: 1, clis: [], secrets: [], assets: [] } };
55033
+ return { version: 1, manifest: { version: 1, clis: [], secrets: [], assets: [], connectors: [] } };
54997
55034
  }
55035
+ var FINDING_SCHEMAS = {
55036
+ cli: EnvCliSchema,
55037
+ secret: EnvSecretSchema,
55038
+ asset: EnvAssetSchema,
55039
+ connector: EnvConnectorSchema
55040
+ };
54998
55041
  function parseFinding(kind, item) {
54999
- const schema = kind === "cli" ? EnvCliSchema : kind === "secret" ? EnvSecretSchema : EnvAssetSchema;
55000
- const parsed = schema.safeParse(item);
55042
+ const parsed = FINDING_SCHEMAS[kind].safeParse(item);
55001
55043
  if (!parsed.success) {
55002
55044
  const first = parsed.error.issues[0];
55003
55045
  throw new Error(`${kind} \u6761\u76EE\u4E0D\u5408\u6CD5\uFF1A${first ? `${first.path.join(".")} ${first.message}` : ""}`);
@@ -55005,6 +55047,11 @@ function parseFinding(kind, item) {
55005
55047
  return parsed.data;
55006
55048
  }
55007
55049
  function upsertFinding(file, kind, item) {
55050
+ if (kind === "connector") {
55051
+ const have = file.manifest.connectors;
55052
+ const connectors = have.includes(item.name) ? have : [...have, item.name];
55053
+ return { ...file, manifest: { ...file.manifest, connectors } };
55054
+ }
55008
55055
  const key = kind === "cli" ? "clis" : kind === "secret" ? "secrets" : "assets";
55009
55056
  const list = [...file.manifest[key]];
55010
55057
  const idx = list.findIndex((x) => x.name === item.name);
@@ -55091,6 +55138,10 @@ var L = [
55091
55138
  // smoke 与 deploy 都要:smoke 得用正式那份模型探活,否则验的不是将要上线的东西。
55092
55139
  " model: ${{ steps.plan.outputs.model }}",
55093
55140
  " effort: ${{ steps.plan.outputs.effort }}",
55141
+ // 装了哪些连接器(JSON 数组)。gateway 按它决定要不要为任务签工牌、把授权链接拼进 prompt
55142
+ //(design 2026-09-09-cloud-connector-credentials)。名字形状在 deploy-file.mjs 卡死成 [a-z0-9-],
55143
+ // 所以下面单引号包住直接拼进命令行是安全的。
55144
+ " connectors: ${{ steps.plan.outputs.connectors }}",
55094
55145
  " steps:",
55095
55146
  " - name: Checkout persona",
55096
55147
  " uses: actions/checkout@v4",
@@ -55213,6 +55264,7 @@ var L = [
55213
55264
  " --persona-id '${{ needs.build.outputs.persona_id }}' \\",
55214
55265
  " --model '${{ needs.build.outputs.model }}' \\",
55215
55266
  " --effort '${{ needs.build.outputs.effort }}' \\",
55267
+ " --connectors '${{ needs.build.outputs.connectors }}' \\",
55216
55268
  " --run-number '${{ github.run_number }}'",
55217
55269
  "",
55218
55270
  " deploy:",
@@ -55242,7 +55294,8 @@ var L = [
55242
55294
  " --image '${{ needs.build.outputs.image }}' \\",
55243
55295
  " --persona-id '${{ needs.build.outputs.persona_id }}' \\",
55244
55296
  " --model '${{ needs.build.outputs.model }}' \\",
55245
- " --effort '${{ needs.build.outputs.effort }}'",
55297
+ " --effort '${{ needs.build.outputs.effort }}' \\",
55298
+ " --connectors '${{ needs.build.outputs.connectors }}'",
55246
55299
  ""
55247
55300
  ];
55248
55301
  var WORKFLOW_TEMPLATE = L.join("\n");
@@ -56848,9 +56901,10 @@ function canAccessPersona(grants, personaId2, action) {
56848
56901
 
56849
56902
  // src/handlers/persona-dispatch.ts
56850
56903
  init_claude();
56851
- function buildFollowUpTaskPack(dispatchId, prompt, round) {
56904
+ function buildFollowUpTaskPack(dispatchId, prompt, round, from) {
56852
56905
  return formatDispatchTaskEnvelope({
56853
56906
  dispatchId,
56907
+ ...from ? { from } : {},
56854
56908
  round,
56855
56909
  detail: [
56856
56910
  `[Follow-up instruction for dispatch ${dispatchId}]`,
@@ -56876,6 +56930,7 @@ function buildPersonaDispatchHandlers(deps) {
56876
56930
  });
56877
56931
  }
56878
56932
  const args = DispatchRunArgsSchema.parse(rest);
56933
+ const sourcePersonaId = deps.getSessionPersonaId?.(sourceSessionId);
56879
56934
  if (args.tool !== void 0 && ctx?.principal.kind === "guest") {
56880
56935
  throw new ClawdError(
56881
56936
  ERROR_CODES.UNAUTHORIZED,
@@ -56931,7 +56986,14 @@ function buildPersonaDispatchHandlers(deps) {
56931
56986
  });
56932
56987
  const ok = deps.sendFollowUp(
56933
56988
  rec4.workerSessionId,
56934
- buildFollowUpTaskPack(args.dispatchId, args.prompt, nextRound),
56989
+ buildFollowUpTaskPack(
56990
+ args.dispatchId,
56991
+ args.prompt,
56992
+ nextRound,
56993
+ // 台账行里有就用台账的(本机派活一律有),没有再现查一次:老台账行是在
56994
+ // sourcePersonaId 有写入点之前落的,那些行只能靠现查补上。
56995
+ rec4.sourcePersonaId ?? deps.getSessionPersonaId?.(sourceSessionId)
56996
+ ),
56935
56997
  // 来源分型(L2):续派并进 dispatch-task;realtime 侧靠这个 meta 打标,
56936
56998
  // history 侧靠 classifyUserMessage 从信封解出同值。
56937
56999
  "dispatch-task"
@@ -56997,6 +57059,10 @@ function buildPersonaDispatchHandlers(deps) {
56997
57059
  const { dispatchId: dispatchId2 } = mgr.start({
56998
57060
  sourceSessionId,
56999
57061
  targetPersona,
57062
+ ...sourcePersonaId ? { sourcePersonaId } : {},
57063
+ // A 端台账记「我派给了谁的机器」:worker 会话在对端,本机点不进去,卡片的归属带
57064
+ // 靠这个字段说出「在哪台机器上」而不是干瞪眼(design §4 跨设备那一行)。
57065
+ targetDeviceId: args.targetDeviceId,
57000
57066
  taskText: args.prompt,
57001
57067
  ...args.brief ? { taskBrief: args.brief } : {},
57002
57068
  ...args.meta ? { meta: args.meta } : {}
@@ -57070,6 +57136,9 @@ function buildPersonaDispatchHandlers(deps) {
57070
57136
  const { dispatchId } = mgr.start({
57071
57137
  sourceSessionId,
57072
57138
  targetPersona,
57139
+ // 「这活谁派的」的真源。schema 里早就有这个字段,本次之前没有任何写入点——
57140
+ // 于是 worker 会话的 dispatch 卡片永远查不到派活方(归属带只能退回信封)。
57141
+ ...sourcePersonaId ? { sourcePersonaId } : {},
57073
57142
  taskText: args.prompt,
57074
57143
  ...args.brief ? { taskBrief: args.brief } : {},
57075
57144
  ...args.meta ? { meta: args.meta } : {}
@@ -57136,9 +57205,10 @@ function buildPersonaDispatchHandlers(deps) {
57136
57205
  const list = async (frame) => {
57137
57206
  const { type: _t, requestId: _r, ...rest } = frame;
57138
57207
  const args = DispatchListArgsSchema.parse(rest);
57139
- const records = deps.store.list(
57140
- args.sourceSessionId ? { sourceSessionId: args.sourceSessionId } : void 0
57141
- );
57208
+ const records = deps.store.list({
57209
+ ...args.sourceSessionId ? { sourceSessionId: args.sourceSessionId } : {},
57210
+ ...args.relatedSessionId ? { relatedSessionId: args.relatedSessionId } : {}
57211
+ });
57142
57212
  return {
57143
57213
  response: { type: "personaDispatch:list:ok", records }
57144
57214
  };
@@ -65464,7 +65534,7 @@ function computeMethodAccess(args) {
65464
65534
  }
65465
65535
 
65466
65536
  // src/version.ts
65467
- var version = "0.2.489".length > 0 ? "0.2.489" : "dev";
65537
+ var version = "0.2.490".length > 0 ? "0.2.490" : "dev";
65468
65538
 
65469
65539
  // src/cli-probe/probe.ts
65470
65540
  var fs72 = __toESM(require("fs"), 1);
@@ -70582,6 +70652,9 @@ async function startDaemon(config) {
70582
70652
  },
70583
70653
  // 续派(spec 2026-07-21):任务包注入 worker session,复用投递同款注入路径。
70584
70654
  sendFollowUp: (workerSessionId, text, meta) => manager.injectIntoSession(workerSessionId, text, meta),
70655
+ // 「这活是谁派的」:台账 sourcePersonaId + 续派包信封 from 都吃它。与首发任务包在
70656
+ // SessionManager 那侧的反查(buildDispatchTaskPack 的 from)是同一个字段、同一个查法。
70657
+ getSessionPersonaId: (sessionId) => manager.findOwnedSession(sessionId)?.ownerPersonaId,
70585
70658
  logger,
70586
70659
  spawnB: async (args) => {
70587
70660
  logger.info("dispatch.spawnB.start", {
@@ -21310,10 +21310,22 @@ var EnvSecretSchema = external_exports.object({
21310
21310
  var EnvAssetSchema = external_exports.object({
21311
21311
  name: external_exports.string().min(1)
21312
21312
  });
21313
+ var ConnectorNameSchema = external_exports.string().regex(/^[a-z0-9-]+$/, "\u8FDE\u63A5\u5668\u540D\u53EA\u80FD\u662F\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u77ED\u6A2A\u7EBF");
21314
+ var EnvConnectorSchema = external_exports.object({ name: ConnectorNameSchema });
21313
21315
  var MANIFEST_BODY = {
21314
21316
  clis: external_exports.array(EnvCliSchema),
21315
21317
  secrets: external_exports.array(EnvSecretSchema),
21316
- assets: external_exports.array(EnvAssetSchema)
21318
+ assets: external_exports.array(EnvAssetSchema),
21319
+ /**
21320
+ * 装了哪些连接器(design 2026-09-09-cloud-connector-credentials §7.1)。**字符串数组**,
21321
+ * 是四段里唯一不是 `{name}` 对象数组的一段:连接器没有任何附加属性,包一层对象只是多一层壳。
21322
+ *
21323
+ * 不复用 secrets:那段说的是「需要一份值,由部署者填」,这里没有值要填;
21324
+ * 不从 clis 推断:lark-cli 在底座里,每个 persona 都有它,推不出任何东西。
21325
+ *
21326
+ * **缺省空而不是必填**:本机上已有的单据不用为此重扫一遍;没声明就是没装,扫描器照样会报。
21327
+ */
21328
+ connectors: external_exports.array(ConnectorNameSchema).default([])
21317
21329
  };
21318
21330
  var EnvManifestBodySchema = external_exports.object(MANIFEST_BODY);
21319
21331
  var EnvironmentManifestSchema = external_exports.object({
@@ -21446,8 +21458,9 @@ var DeployRerunJobArgsSchema = external_exports.object({
21446
21458
  }).strict();
21447
21459
  var DeployReportFindingArgsSchema = external_exports.object({
21448
21460
  personaId: external_exports.string().min(1),
21449
- kind: external_exports.enum(["cli", "secret", "asset"]),
21461
+ kind: external_exports.enum(["cli", "secret", "asset", "connector"]),
21450
21462
  // 该条目在 manifest 对应数组里的内容(形状随 kind 变,handler 按 kind 收窄校验)
21463
+ // connector 的 item 只有 name,落进清单时只留名字(manifest.connectors 是字符串数组)
21451
21464
  item: external_exports.record(external_exports.string(), external_exports.unknown()),
21452
21465
  // 这条发现的来历(一句人话 + 原文出处),形状同 EnvEvidence,target 由 handler 从 kind+name 派生
21453
21466
  evidence: external_exports.object({
@@ -21743,6 +21756,16 @@ var DispatchRecordSchema = external_exports.object({
21743
21756
  sourceSessionId: external_exports.string().min(1),
21744
21757
  sourcePersonaId: external_exports.string().min(1).optional(),
21745
21758
  targetPersonaId: external_exports.string().min(1),
21759
+ /**
21760
+ * 跨设备派活时 B 所在的设备(`DispatchRunArgs.targetDeviceId`),A 端台账记「我派给了谁的机器」。
21761
+ *
21762
+ * **缺省即本机**,与入参侧用 `undefined` 表示本机是同一条口径——不引第二种表示法。
21763
+ * 存量台账行没有这个字段,消费方(dispatch 卡片的归属带)据此只显示 persona、不显示设备。
21764
+ *
21765
+ * B 端自己的台账行**不会**有它:peer-forward 转发时故意 strip 掉(B 据此判定本地执行),
21766
+ * 那条行记的是 B 视角的本地 dispatch。
21767
+ */
21768
+ targetDeviceId: external_exports.string().min(1).optional(),
21746
21769
  /** B 的 sessionId;registerBSession 后回填 */
21747
21770
  workerSessionId: external_exports.string().min(1).optional(),
21748
21771
  /** 任务摘要;截断(≤500 字符)在 daemon store.add 处保证 */
@@ -21769,7 +21792,17 @@ var DispatchRecordSchema = external_exports.object({
21769
21792
  deliveredAt: external_exports.string().min(1).optional()
21770
21793
  });
21771
21794
  var DispatchListArgsSchema = external_exports.object({
21772
- sourceSessionId: external_exports.string().min(1).optional()
21795
+ sourceSessionId: external_exports.string().min(1).optional(),
21796
+ /**
21797
+ * 「**这条会话卷入的**所有台账行」:`sourceSessionId === it || workerSessionId === it`。
21798
+ *
21799
+ * 为什么不复用 `sourceSessionId`:一条会话既可能是派活方(在自己这儿看回报卡),也可能是
21800
+ * 干活方(在 worker 会话里看任务包),后者用 sourceSessionId 过滤一条也查不到。UI 的
21801
+ * dispatch 卡片要的正是「跟我这条会话有关的全部 dispatch」,一次调用答完,不必拉全量再本地筛。
21802
+ *
21803
+ * 与 `sourceSessionId` 同时给时两个条件都要满足(AND),但调用方没有这么用的场景。
21804
+ */
21805
+ relatedSessionId: external_exports.string().min(1).optional()
21773
21806
  });
21774
21807
  var DispatchListResultSchema = external_exports.object({
21775
21808
  records: external_exports.array(DispatchRecordSchema)
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: scan-persona-for-deploy
3
- description: 老板要把某个 persona 发布到云上时触发——把这个 persona 读一遍,弄清它挪到一台干净的云上机器要预备什么(命令行工具、凭据、随行资产),边查边填进它的部署文件。收到形如「扫描 persona-xxx 的部署环境,personaId=persona-xxx」的任务时使用。只负责扫,不负责部署。
3
+ description: 老板要把某个 persona 发布到云上时触发——把这个 persona 读一遍,弄清它挪到一台干净的云上机器要预备什么(命令行工具、凭据、随行资产、连接器),边查边填进它的部署文件。收到形如「扫描 persona-xxx 的部署环境,personaId=persona-xxx」的任务时使用。只负责扫,不负责部署。
4
4
  ---
5
5
 
6
6
  # 扫 persona 的上云环境
@@ -35,7 +35,7 @@ description: 老板要把某个 persona 发布到云上时触发——把这个
35
35
  ```
36
36
  call({ method: "deploy:reportFinding", args: {
37
37
  personaId: "<任务里给的>",
38
- kind: "cli" | "secret" | "asset",
38
+ kind: "cli" | "secret" | "asset" | "connector",
39
39
  item: { ... }, // 见下面各类的字段
40
40
  evidence: { reason: "...", file: "...", quote: "..." }
41
41
  }})
@@ -99,6 +99,18 @@ call({ method: "deploy:reportFinding", args: {
99
99
  - 判据往往落在「这个动作在云上由谁提供」。persona 在本机走 daemon 提供的 MCP 干的活,
100
100
  云上容器里没有 daemon,靠的就是那份随行资产。
101
101
 
102
+ ### kind: "connector" —— 以用户本人身份操作的第三方
103
+
104
+ `item` 字段只有 `name`(小写字母、数字、短横线)。目前能声明的只有 `feishu`。
105
+
106
+ 判据:**persona 里出现「以用户本人身份操作某个第三方」的动作**就报——查他的日程、发他的消息、
107
+ 读他的文档,这类活在云上要先拿到他本人的授权,授权由云上的连接器完成,不是部署者填一份凭据就能代替的。
108
+
109
+ - 跟 `secret` 的区别:`secret` 是「部署者出一份值,全体使用者共用」;`connector` 是「每个使用者各自授权一次」。
110
+ 一个 persona 用 `lark-cli … --as user` 操作飞书,报的是 `connector: feishu`,**不要**再给它报一条飞书的 `secret`。
111
+ - 跟 `cli` 的区别:`lark-cli` 这个工具本身在底座镜像里,不用报 `cli`;报 `connector` 说的是「它要用谁的身份」。
112
+ - `evidence.quote` 引 skill 里带 `--as user` 的那类命令行就够。
113
+
102
114
  ### evidence —— 每条的来历
103
115
 
104
116
  - `reason`:**一句人话**,说清「为什么需要它 + 你从哪看出来的」,写给不熟悉这个 persona 的人看。