larkway 0.3.34 → 0.3.36

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.
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  You @ the bot in a Feishu thread. It runs on your machine — reading your real codebase, executing commands, opening MRs — and posts the result back. You define what the agent knows and what it can do. Larkway just carries the messages.
10
10
 
11
- **Current release: v0.3.34**
11
+ **Current release: v0.3.36**
12
12
 
13
13
  ---
14
14
 
package/README.zh.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  你在飞书话题里 @ bot,它在你的机器上运行——读真实代码库、执行命令、开 MR——把结果贴回飞书。你定义 agent 知道什么、能做什么。Larkway 只负责传递消息。
10
10
 
11
- **当前版本:v0.3.34**
11
+ **当前版本:v0.3.36**
12
12
 
13
13
  ---
14
14
 
package/dist/cli/index.js CHANGED
@@ -25413,13 +25413,13 @@ var require_lib2 = __commonJS({
25413
25413
  Domain[Domain["Lark"] = 1] = "Lark";
25414
25414
  })(exports.Domain || (exports.Domain = {}));
25415
25415
  exports.LoggerLevel = void 0;
25416
- (function(LoggerLevel) {
25417
- LoggerLevel[LoggerLevel["fatal"] = 0] = "fatal";
25418
- LoggerLevel[LoggerLevel["error"] = 1] = "error";
25419
- LoggerLevel[LoggerLevel["warn"] = 2] = "warn";
25420
- LoggerLevel[LoggerLevel["info"] = 3] = "info";
25421
- LoggerLevel[LoggerLevel["debug"] = 4] = "debug";
25422
- LoggerLevel[LoggerLevel["trace"] = 5] = "trace";
25416
+ (function(LoggerLevel2) {
25417
+ LoggerLevel2[LoggerLevel2["fatal"] = 0] = "fatal";
25418
+ LoggerLevel2[LoggerLevel2["error"] = 1] = "error";
25419
+ LoggerLevel2[LoggerLevel2["warn"] = 2] = "warn";
25420
+ LoggerLevel2[LoggerLevel2["info"] = 3] = "info";
25421
+ LoggerLevel2[LoggerLevel2["debug"] = 4] = "debug";
25422
+ LoggerLevel2[LoggerLevel2["trace"] = 5] = "trace";
25423
25423
  })(exports.LoggerLevel || (exports.LoggerLevel = {}));
25424
25424
  var CEventType = /* @__PURE__ */ Symbol("event-type");
25425
25425
  var CTenantKey = /* @__PURE__ */ Symbol("tenant-key");
@@ -112381,6 +112381,125 @@ var init_channelPostClient = __esm({
112381
112381
  }
112382
112382
  });
112383
112383
 
112384
+ // src/lark/channelCotClient.ts
112385
+ async function withTimeout(p, ms, label) {
112386
+ let timer;
112387
+ const timeout = new Promise((_resolve, reject) => {
112388
+ timer = setTimeout(
112389
+ () => reject(new Error(`[channel.cot] ${label} timed out after ${ms}ms`)),
112390
+ ms
112391
+ );
112392
+ timer.unref?.();
112393
+ });
112394
+ try {
112395
+ return await Promise.race([p, timeout]);
112396
+ } finally {
112397
+ if (timer) clearTimeout(timer);
112398
+ }
112399
+ }
112400
+ function assertOk(res, label) {
112401
+ if (res.code !== void 0 && res.code !== 0) {
112402
+ throw new Error(
112403
+ `[channel.cot] ${label} failed: code=${res.code} msg=${res.msg ?? "<no msg>"}`
112404
+ );
112405
+ }
112406
+ }
112407
+ function stringField(data, key) {
112408
+ const value = data?.[key];
112409
+ return typeof value === "string" ? value : void 0;
112410
+ }
112411
+ var COT_REQUEST_TIMEOUT_MS, ChannelCotClient;
112412
+ var init_channelCotClient = __esm({
112413
+ "src/lark/channelCotClient.ts"() {
112414
+ "use strict";
112415
+ COT_REQUEST_TIMEOUT_MS = 8e3;
112416
+ ChannelCotClient = class {
112417
+ resolveChannel;
112418
+ constructor(opts) {
112419
+ this.resolveChannel = opts.resolveChannel;
112420
+ }
112421
+ channel() {
112422
+ const ch = this.resolveChannel();
112423
+ if (!ch) {
112424
+ throw new Error("[channel.cot] outbound called before the Channel SDK connected");
112425
+ }
112426
+ return ch;
112427
+ }
112428
+ /** Every COT call goes through here, so all get the same hard timeout. */
112429
+ request(opts) {
112430
+ return withTimeout(
112431
+ this.channel().rawClient.request(opts),
112432
+ COT_REQUEST_TIMEOUT_MS,
112433
+ `${opts.method} ${opts.url}`
112434
+ );
112435
+ }
112436
+ async create(target) {
112437
+ const receiveIdType = target.threadId ? "thread_id" : "chat_id";
112438
+ const receiveId = target.threadId ?? target.chatId;
112439
+ const res = await this.request({
112440
+ url: "/open-apis/im/v1/message_cot",
112441
+ method: "POST",
112442
+ params: { receive_id_type: receiveIdType },
112443
+ data: {
112444
+ receive_id: receiveId,
112445
+ // origin_message_id only anchors non-thread bubbles; harmless if set,
112446
+ // but omitted for topic threads where the thread id already anchors.
112447
+ ...!target.threadId && target.originMessageId ? { origin_message_id: target.originMessageId } : {}
112448
+ }
112449
+ });
112450
+ assertOk(res, "create");
112451
+ const cotId = stringField(res.data, "cot_id");
112452
+ const messageId = stringField(res.data, "message_id");
112453
+ if (!cotId || !messageId) {
112454
+ throw new Error(
112455
+ `[channel.cot] create returned no cot_id/message_id (${JSON.stringify(res.data ?? {}).slice(0, 200)})`
112456
+ );
112457
+ }
112458
+ return { cotId, messageId };
112459
+ }
112460
+ async update(ref, events) {
112461
+ if (events.length === 0) return;
112462
+ const res = await this.request({
112463
+ url: "/open-apis/im/v1/message_cot",
112464
+ method: "PUT",
112465
+ data: { cot_id: ref.cotId, message_id: ref.messageId, events: [...events] }
112466
+ });
112467
+ assertOk(res, "update");
112468
+ }
112469
+ async complete(ref, reason) {
112470
+ const res = await this.request({
112471
+ url: `/open-apis/im/v1/message_cot/complete/${encodeURIComponent(ref.cotId)}`,
112472
+ method: "POST",
112473
+ params: { message_id: ref.messageId, reason }
112474
+ });
112475
+ assertOk(res, "complete");
112476
+ }
112477
+ async resolveThreadId(messageId) {
112478
+ try {
112479
+ const res = await this.request({
112480
+ url: `/open-apis/im/v1/messages/${encodeURIComponent(messageId)}`,
112481
+ method: "GET"
112482
+ });
112483
+ if (res.code !== void 0 && res.code !== 0) return void 0;
112484
+ const items = res.data?.["items"];
112485
+ if (!Array.isArray(items)) return void 0;
112486
+ for (const item of items) {
112487
+ if (item && typeof item === "object") {
112488
+ const threadId = item["thread_id"];
112489
+ if (typeof threadId === "string" && threadId.startsWith("omt_")) {
112490
+ return threadId;
112491
+ }
112492
+ }
112493
+ }
112494
+ return void 0;
112495
+ } catch {
112496
+ return void 0;
112497
+ }
112498
+ }
112499
+ };
112500
+ }
112501
+ });
112502
+
112384
112503
  // src/lark/channelClient.ts
112385
112504
  var channelClient_exports = {};
112386
112505
  __export(channelClient_exports, {
@@ -112431,13 +112550,13 @@ function arrayField(obj, key) {
112431
112550
  const value = obj[key];
112432
112551
  return Array.isArray(value) ? value : null;
112433
112552
  }
112434
- function stringField(obj, key) {
112553
+ function stringField2(obj, key) {
112435
112554
  if (!obj || typeof obj !== "object") return void 0;
112436
112555
  const value = obj[key];
112437
112556
  return typeof value === "string" ? value : void 0;
112438
112557
  }
112439
112558
  function nonEmptyStringField(obj, key) {
112440
- const value = stringField(obj, key);
112559
+ const value = stringField2(obj, key);
112441
112560
  return value && value.length > 0 ? value : void 0;
112442
112561
  }
112443
112562
  function parseLarkCliMessages(stdout2) {
@@ -112540,6 +112659,7 @@ var init_channelClient = __esm({
112540
112659
  init_channelCardClient();
112541
112660
  init_channelCardKitClient();
112542
112661
  init_channelPostClient();
112662
+ init_channelCotClient();
112543
112663
  execFile4 = promisify4(execFileCallback);
112544
112664
  LEARNED_CHATS_LIMIT = 100;
112545
112665
  SEEN_MESSAGES_LIMIT = 1e3;
@@ -112675,6 +112795,8 @@ var init_channelClient = __esm({
112675
112795
  cardKitClient = null;
112676
112796
  /** Lazily built and only requested by main.ts when post outbound gates are configured. */
112677
112797
  postClient = null;
112798
+ /** Lazily built COT (思维链) client; only requested when a bot enables cot != off. */
112799
+ cotClient = null;
112678
112800
  constructor(opts) {
112679
112801
  if (!opts.appId || !opts.appSecret) {
112680
112802
  throw new Error(
@@ -112940,6 +113062,22 @@ var init_channelClient = __esm({
112940
113062
  }
112941
113063
  return this.cardKitClient;
112942
113064
  }
113065
+ /**
113066
+ * Return an OutboundCotClient bound to this client's channel handle.
113067
+ *
113068
+ * main.ts only calls this when the bot's `cot` config is not "off". The COT
113069
+ * bubble uses the SDK's generic rawClient.request() (tenant token auto-
113070
+ * injected via the same token manager as every other outbound call), so it
113071
+ * adds no auth surface. Resolves the live channel lazily at call time.
113072
+ */
113073
+ outboundCotClient() {
113074
+ if (!this.cotClient) {
113075
+ this.cotClient = new ChannelCotClient({
113076
+ resolveChannel: () => this.channel
113077
+ });
113078
+ }
113079
+ return this.cotClient;
113080
+ }
112943
113081
  /**
112944
113082
  * Return an OutboundPostClient bound to this client's channel handle.
112945
113083
  *
@@ -113243,7 +113381,7 @@ var init_channelClient = __esm({
113243
113381
  const chats = parseLarkCliMessages(stdout2) ?? [];
113244
113382
  fetched += chats.length;
113245
113383
  for (const raw of chats) {
113246
- const chatId = stringField(raw, "chat_id");
113384
+ const chatId = stringField2(raw, "chat_id");
113247
113385
  if (!chatId?.startsWith("oc_")) continue;
113248
113386
  discoveredChatIds.add(chatId);
113249
113387
  const before = this.recentlySeenChatIds.size;
@@ -113257,7 +113395,7 @@ var init_channelClient = __esm({
113257
113395
  const hasMore = Boolean(
113258
113396
  (data && typeof data === "object" && data["has_more"]) ?? (parsed && typeof parsed === "object" && parsed["has_more"])
113259
113397
  );
113260
- pageToken = stringField(data, "page_token") ?? stringField(parsed, "page_token") ?? "";
113398
+ pageToken = stringField2(data, "page_token") ?? stringField2(parsed, "page_token") ?? "";
113261
113399
  if (!hasMore || !pageToken) break;
113262
113400
  }
113263
113401
  if (newlyLearned > 0) {
@@ -113571,7 +113709,7 @@ function isTaskRequestTimeoutError(err2) {
113571
113709
  if (err2 instanceof TaskApiError && err2.cause instanceof TaskRequestTimeoutError) return true;
113572
113710
  return false;
113573
113711
  }
113574
- function withTimeout(promise, ms, label) {
113712
+ function withTimeout2(promise, ms, label) {
113575
113713
  let timer;
113576
113714
  const timeout = new Promise((_, reject) => {
113577
113715
  timer = setTimeout(() => reject(new TaskRequestTimeoutError(`${label} timed out after ${ms}ms`)), ms);
@@ -113615,7 +113753,7 @@ var init_client = __esm({
113615
113753
  }
113616
113754
  /** Single choke point for every outbound call — applies the timeout race uniformly. */
113617
113755
  #request(config, label) {
113618
- return withTimeout(this.#requester.request(config), this.#timeoutMs, label);
113756
+ return withTimeout2(this.#requester.request(config), this.#timeoutMs, label);
113619
113757
  }
113620
113758
  async getTask(taskGuid) {
113621
113759
  let resp;
@@ -125718,6 +125856,31 @@ var BotConfigSchema = external_exports.object({
125718
125856
  * @default "claude"
125719
125857
  */
125720
125858
  backend: external_exports.string().min(1).default("claude"),
125859
+ /**
125860
+ * COT (思维链) 气泡:把 agent 的 thinking 思考过程 + 工具调用摘要实时推到飞书
125861
+ * 原生的可折叠思维链气泡(与最终答案卡片互不干扰,最终答案永远只走卡片)。
125862
+ *
125863
+ * - "off":完全不调用 message_cot API(零网络、零副作用)。
125864
+ * - "brief"(默认):思考过程 + 工具名摘要。
125865
+ * - "detailed":额外推工具入参(TOOL_CALL_ARGS)与截断后的工具结果。
125866
+ *
125867
+ * message_cot 是无公开文档的 API —— 任何一步失败都会在本次会话内自动降级、
125868
+ * 只记 warn,绝不影响卡片和最终答案(见 src/bridge/cotProgress.ts)。
125869
+ */
125870
+ cot: external_exports.enum(["off", "brief", "detailed"]).default("brief"),
125871
+ /**
125872
+ * COT 展示形态。`cot` 管密度(off/brief/detailed),这个管落点:
125873
+ * - "bubble"(默认):走飞书原生 message_cot 思维链气泡(src/bridge/cotProgress.ts)——
125874
+ * 客户端原生渲染(工具图标列表 + 可折叠头),真机体验最好。已知限制:话题内
125875
+ * 锚定不可用(气泡落群顶层,本租户 thread 通道判死),收尾 bug 已在 main 修复。
125876
+ * - "card":思考过程内嵌进答案卡片里的 collapsible_panel(懒创建、答案上方)。
125877
+ * ⚠️ 实验选项 —— 2026-07-05 真机实测:飞书客户端**不渲染 collapsible_panel 的
125878
+ * 折叠交互**(API 全 code=0,但面板被拍平成普通文本、无折叠箭头、终态也不可折叠;
125879
+ * CardKit 无 GET 读回、只能真机人眼验)。故 card 形态目前仅作纯文本内嵌展示用,
125880
+ * 体验不如气泡,不建议作默认。见 memory feishu-message-cot-api。
125881
+ * cot="off" 时本字段无意义(两种形态都不产出)。
125882
+ */
125883
+ cotSurface: external_exports.enum(["card", "bubble"]).default("bubble"),
125721
125884
  /**
125722
125885
  * 话题 ↔ 飞书任务句柄(docs/task-handle.md,v2)。省略此字段不代表关闭,但也
125723
125886
  * 不会触发任何自动建清单——main.ts 在 startup 时只做只读解析(yaml 里的
@@ -127196,6 +127359,8 @@ async function runCreateBot(ctx, creds, basics) {
127196
127359
  response_surface_prototype: DEFAULT_RESPONSE_SURFACE_PROTOTYPE,
127197
127360
  runtime: "agent_workspace",
127198
127361
  backend: basics.backend,
127362
+ cot: "brief",
127363
+ cotSurface: "bubble",
127199
127364
  memory_file: memoryFile,
127200
127365
  ...basics.gitlabTokenEnv ? { gitlab_token_env: basics.gitlabTokenEnv } : {},
127201
127366
  ...basics.gitName && basics.gitEmail ? { git_identity: { name: basics.gitName, email: basics.gitEmail } } : {}
@@ -127864,9 +128029,9 @@ async function checkWsConnectivity(ctx, opts) {
127864
128029
  }
127865
128030
  async function probeTaskScope(appId, appSecret, tasklistGuid) {
127866
128031
  try {
127867
- const { Client: LarkSdkClient2 } = await Promise.resolve().then(() => __toESM(require_lib2(), 1));
128032
+ const { Client: LarkSdkClient2, LoggerLevel: LoggerLevel2 } = await Promise.resolve().then(() => __toESM(require_lib2(), 1));
127868
128033
  const { TaskListClient: TaskListClient2 } = await Promise.resolve().then(() => (init_client(), client_exports));
127869
- const sdkClient = new LarkSdkClient2({ appId, appSecret });
128034
+ const sdkClient = new LarkSdkClient2({ appId, appSecret, loggerLevel: LoggerLevel2.fatal });
127870
128035
  const taskClient = new TaskListClient2({
127871
128036
  request: (config) => sdkClient.request(config)
127872
128037
  });
@@ -130650,6 +130815,8 @@ async function createBotFromCreds(opts) {
130650
130815
  response_surface_prototype: DEFAULT_RESPONSE_SURFACE_PROTOTYPE,
130651
130816
  runtime: "agent_workspace",
130652
130817
  backend: form.backend && form.backend.trim() ? form.backend.trim() : "codex",
130818
+ cot: "brief",
130819
+ cotSurface: "bubble",
130653
130820
  // Persist the Feishu avatar URL so the Web 管理面 can show an avatar before
130654
130821
  // the bridge writes status.json (pre-bridge / central roster). Best-effort:
130655
130822
  // only set when resolveBotIdentity returned a valid url.
@@ -131182,8 +131349,8 @@ async function loadChatNameMap(profile) {
131182
131349
  try {
131183
131350
  const { stdout: stdout2 } = await eventExecFile("lark-cli", args, { timeout: 8e3 });
131184
131351
  for (const chat of extractLarkCliChats(stdout2)) {
131185
- const chatId = stringField2(chat, "chat_id");
131186
- const name = stringField2(chat, "name");
131352
+ const chatId = stringField3(chat, "chat_id");
131353
+ const name = stringField3(chat, "name");
131187
131354
  if (chatId && name) names.set(chatId, name);
131188
131355
  }
131189
131356
  } catch {
@@ -131210,7 +131377,7 @@ function extractLarkCliChats(stdout2) {
131210
131377
  function isLarkOpenChatId(value) {
131211
131378
  return typeof value === "string" && value.startsWith("oc_");
131212
131379
  }
131213
- function stringField2(value, key) {
131380
+ function stringField3(value, key) {
131214
131381
  if (!value || typeof value !== "object") return void 0;
131215
131382
  const out = value[key];
131216
131383
  return typeof out === "string" ? out : void 0;
@@ -132695,27 +132862,50 @@ function runLarkCliJson(args, spawnSyncFn) {
132695
132862
  }
132696
132863
  return { ok: true, data: parsed };
132697
132864
  }
132698
- function listUserTasklists(profile, spawnSyncFn = spawnSync3) {
132865
+ function searchUserTasklists(profile, query, spawnSyncFn = spawnSync3) {
132699
132866
  const result = runLarkCliJson(
132700
- ["task", "tasklists", "list", "--as", "user", "--profile", profile, "--page-all", "--json"],
132867
+ ["task", "+tasklist-search", "--as", "user", "--profile", profile, "--query", query, "--page-all", "--json"],
132701
132868
  spawnSyncFn
132702
132869
  );
132703
132870
  if (!result.ok) return result;
132704
- const data = result.data;
132705
- const items = typeof data === "object" && data !== null ? data["items"] : void 0;
132706
- if (!Array.isArray(items)) {
132707
- return { ok: false, error: `lark-cli \u8FD4\u56DE\u7684\u6E05\u5355\u5217\u8868\u5F62\u72B6\u4E0D\u5BF9(\u7F3A\u5C11 items \u6570\u7EC4):${JSON.stringify(data).slice(0, 300)}` };
132871
+ return extractTasklistSummaries(result.data);
132872
+ }
132873
+ function extractTasklistSummaries(data) {
132874
+ const rec = typeof data === "object" && data !== null ? data : {};
132875
+ const nested = typeof rec["data"] === "object" && rec["data"] !== null ? rec["data"] : {};
132876
+ let arr;
132877
+ for (const candidate of [
132878
+ data,
132879
+ rec["items"],
132880
+ rec["tasklists"],
132881
+ rec["results"],
132882
+ nested["items"],
132883
+ nested["tasklists"],
132884
+ nested["results"]
132885
+ ]) {
132886
+ if (Array.isArray(candidate)) {
132887
+ arr = candidate;
132888
+ break;
132889
+ }
132708
132890
  }
132709
- const tasklists = [];
132710
- for (const raw of items) {
132891
+ if (!arr) {
132892
+ return {
132893
+ ok: false,
132894
+ error: `lark-cli +tasklist-search \u8FD4\u56DE\u7684\u5F62\u72B6\u65E0\u6CD5\u8BC6\u522B(\u627E\u4E0D\u5230\u6E05\u5355\u6570\u7EC4):${JSON.stringify(data).slice(0, 300)}`
132895
+ };
132896
+ }
132897
+ const out = [];
132898
+ const seen = /* @__PURE__ */ new Set();
132899
+ for (const raw of arr) {
132711
132900
  if (typeof raw !== "object" || raw === null) continue;
132712
132901
  const guid = raw["guid"];
132713
132902
  const name = raw["name"];
132714
- if (typeof guid === "string" && guid.length > 0) {
132715
- tasklists.push({ guid, name: typeof name === "string" ? name : "(\u65E0\u6807\u9898)" });
132903
+ if (typeof guid === "string" && guid.length > 0 && !seen.has(guid)) {
132904
+ seen.add(guid);
132905
+ out.push({ guid, name: typeof name === "string" ? name : "(\u65E0\u6807\u9898)" });
132716
132906
  }
132717
132907
  }
132718
- return { ok: true, data: tasklists };
132908
+ return { ok: true, data: out };
132719
132909
  }
132720
132910
  function addTasklistMembersAsUser(profile, tasklistGuid, members, spawnSyncFn = spawnSync3) {
132721
132911
  const dataJson = JSON.stringify({ members });
@@ -132802,33 +132992,41 @@ var USAGE2 = `larkway tasklist-init [--team <bot1,bot2,\u2026>] [--name <\u6E05\
132802
132992
  \u5E2E\u52A9\u7684 agent,\u7B2C\u4E00\u6B65\u5FC5\u7136\u4F1A\u8DD1 \`larkway tasklist-init --help\`(\u5C31\u662F\u4F60\u6B63\u5728\u770B\u7684\u8FD9\u6BB5),
132803
132993
  \u4ECE\u8FD9\u91CC\u5C31\u80FD\u5B66\u4F1A\u600E\u4E48\u628A\u672C\u673A\u6240\u6709\u5DF2\u914D\u7F6E\u7684 bot \u90FD\u914D\u6210\u6E05\u5355\u6210\u5458,\u4E0D\u9700\u8981\u4F60\u518D\u624B\u52A8\u4F20\u4EFB\u4F55\u53C2\u6570\u3002
132804
132994
 
132805
- \u96F6\u53C2\u6570\u4E09\u6B65 Quickstart:
132806
- 1. (\u53EF\u9009)\u5148\u5728\u98DE\u4E66\u4EFB\u52A1\u4E2D\u5FC3\u624B\u52A8\u5EFA\u4E00\u4E2A\u6E05\u5355,\u540D\u5B57\u968F\u4FBF\u53D6,\u6BD4\u5982 "Agent Team"\u3002
132807
- 2. \u8DD1:larkway tasklist-init
132995
+ \u96F6\u53C2\u6570 Quickstart:
132996
+ 1. \u8DD1:larkway tasklist-init
132808
132997
  \u2014\u2014 \u4F1A\u81EA\u52A8:--team = \u672C\u673A bots/ \u76EE\u5F55\u4E0B\u5168\u90E8\u5DF2\u914D\u7F6E bot;--name = "Agent Team";
132809
- \u7528\u4F60\u7684 lark-cli \u7528\u6237\u8EAB\u4EFD\u6309\u540D\u5B57\u67E5\u4E00\u904D\u80FD\u770B\u5230\u7684\u6E05\u5355 \u2014\u2014 \u67E5\u5230\u540C\u540D\u7684\u5C31 adopt(\u628A\u8FD9\u4E9B
132810
- bot \u52A0\u4E3A editor);\u67E5\u4E0D\u5230(\u6216\u6CA1\u767B\u5F55/\u7F3A scope)\u5C31\u9759\u9ED8\u56DE\u9000\u5230\u65E7\u7684\u521B\u5EFA\u8DEF\u5F84(\u7528\u7B2C\u4E00\u4E2A
132811
- bot \u7684 app \u8EAB\u4EFD\u65B0\u5EFA\u4E00\u4E2A\u6E05\u5355,\u5E76\u81EA\u52A8\u628A\u4F60\u52A0\u4E3A owner)\u3002
132812
- 3. \u53BB\u98DE\u4E66\u4EFB\u52A1\u4E2D\u5FC3\u786E\u8BA4\u8FD9\u4E2A\u6E05\u5355\u5728\u4F60\u7684\u5217\u8868\u91CC\u53EF\u89C1,\u4E4B\u540E\u53F3\u952E\u8BDD\u9898\u6D88\u606F\u9009"\u8F6C\u4EFB\u52A1"\u5373\u53EF\u3002
132998
+ \u7528\u7B2C\u4E00\u4E2A bot \u7684 app \u8EAB\u4EFD**\u65B0\u5EFA**\u4E00\u4E2A\u6E05\u5355(\u6E05\u5355 owner = \u8BE5 bot app),\u5E76\u628A\u4F60
132999
+ \u52A0\u4E3A editor \u6210\u5458(\u65B9\u4FBF\u5728\u4EFB\u52A1\u4E2D\u5FC3\u770B\u5230\u5E76\u7F16\u8F91)\u3002\u96F6\u53C2\u6570**\u4E0D\u4F1A**\u81EA\u52A8\u53BB\u8BA4\u9886\u540C\u540D\u6E05\u5355\u3002
133000
+ 2. \u53BB\u98DE\u4E66\u4EFB\u52A1\u4E2D\u5FC3\u786E\u8BA4\u8FD9\u4E2A\u6E05\u5355\u5728\u4F60\u7684\u5217\u8868\u91CC\u53EF\u89C1,\u4E4B\u540E\u53F3\u952E\u8BDD\u9898\u6D88\u606F\u9009"\u8F6C\u4EFB\u52A1"\u5373\u53EF\u3002
133001
+
133002
+ \u60F3\u8BA9\u6E05\u5355\u5F52**\u4F60\u81EA\u5DF1**\u6240\u6709(\u800C\u4E0D\u662F bot app)?\u5148\u5728\u4EFB\u52A1\u4E2D\u5FC3\u81EA\u5DF1\u5EFA\u4E00\u4E2A,\u518D\u7528
133003
+ \`--adopt "<\u6E05\u5355\u540D>"\` \u8BA4\u9886(\u89C1\u4E0B)\u3002\u591A\u5957 Larkway \u90E8\u7F72\u65F6,\u7ED9\u6BCF\u5957\u7528 --name \u6539\u4E2A\u4E0D\u540C
133004
+ \u540D\u5B57\u505A\u9694\u79BB,\u907F\u514D\u6DF7\u7528\u3002
132813
133005
 
132814
133006
  \u4EE5\u4E0A\u5168\u90E8\u662F\u7F3A\u7701\u884C\u4E3A,\u4EE5\u4E0B flag \u4EC5\u7528\u4E8E\u8986\u76D6:
132815
133007
 
132816
133008
  --team <bot1,bot2,\u2026> \u663E\u5F0F\u6307\u5B9A\u8981\u52A0\u5165\u6E05\u5355\u7684 bot(\u9ED8\u8BA4 = \u5168\u90E8\u5DF2\u914D\u7F6E bot)
132817
- --name <\u6E05\u5355\u540D> \u663E\u5F0F\u6307\u5B9A\u6E05\u5355\u540D(\u9ED8\u8BA4 "Agent Team"),\u4EC5\u5728\u81EA\u52A8/\u663E\u5F0F create
132818
- \u8DEF\u5F84\u91CC\u751F\u6548;--adopt/--adopt-guid \u4F1A\u5FFD\u7565\u5B83,\u6309\u540D\u5B57/guid \u67E5
132819
- --adopt "<\u6E05\u5355\u540D>" \u5F3A\u5236\u8D70 adopt \u6A21\u5F0F\u5E76\u7528\u8FD9\u4E2A\u540D\u5B57\u67E5\u627E\u2014\u2014\u67E5\u4E0D\u5230/\u67E5\u51FA\u591A\u4E2A\u90FD\u4F1A
132820
- \u76F4\u63A5\u62A5\u9519\u9000\u51FA,\u4E0D\u4F1A\u9759\u9ED8\u56DE\u9000\u5230\u521B\u5EFA\u8DEF\u5F84(\u4F60\u5DF2\u7ECF\u660E\u786E\u8981 adopt\u4E86)
132821
- --adopt-guid <guid> \u8DF3\u8FC7\u6309\u540D\u5B57\u67E5\u627E,\u76F4\u63A5 adopt \u8FD9\u4E2A guid \u7684\u6E05\u5355(\u5355\u72EC\u4F7F\u7528\u4E5F
132822
- \u7B49\u4EF7\u4E8E\u5F3A\u5236 adopt \u6A21\u5F0F);\u591A\u4E2A\u540C\u540D\u6E05\u5355\u65F6\u7528\u5B83\u6D88\u6B67
133009
+ --name <\u6E05\u5355\u540D> \u663E\u5F0F\u6307\u5B9A\u8981\u521B\u5EFA/\u590D\u7528\u7684\u6E05\u5355\u540D(\u9ED8\u8BA4 "Agent Team");\u591A\u56E2\u961F
133010
+ \u90E8\u7F72\u7528\u5B83\u9694\u79BB\u3002--adopt/--adopt-guid \u4F1A\u5FFD\u7565\u5B83,\u6309\u540D\u5B57/guid \u67E5
133011
+ --adopt "<\u6E05\u5355\u540D>" \u8BA4\u9886\u4F60\u81EA\u5DF1\u5728\u4EFB\u52A1\u4E2D\u5FC3\u5EFA\u597D\u7684\u540C\u540D\u6E05\u5355(\u628A\u8FD9\u4E9B bot \u52A0\u4E3A editor)\u2014\u2014
133012
+ \u67E5\u4E0D\u5230/\u67E5\u51FA\u591A\u4E2A\u90FD\u76F4\u63A5\u62A5\u9519\u9000\u51FA,\u7EDD\u4E0D\u9759\u9ED8\u56DE\u9000\u5230\u521B\u5EFA\u8DEF\u5F84
133013
+ --adopt-guid <guid> \u8DF3\u8FC7\u6309\u540D\u5B57\u67E5\u627E,\u76F4\u63A5\u8BA4\u9886\u8FD9\u4E2A guid \u7684\u6E05\u5355;\u591A\u4E2A\u540C\u540D\u6E05\u5355\u65F6\u6D88\u6B67
132823
133014
  --owner <open_id> \u663E\u5F0F\u6307\u5B9A\u4EBA\u7C7B owner(\u4EC5\u521B\u5EFA\u8DEF\u5F84\u7528\u5230,adopt \u6A21\u5F0F\u4E0B\u4F60\u672C\u6765\u5C31\u662F
132824
133015
  owner,\u4E0D\u9700\u8981\u8FD9\u4E2A)
132825
133016
  --force \u8986\u76D6\u5171\u4EAB\u6CE8\u518C\u6587\u4EF6\u91CC\u5DF2\u6709\u7684 guid(\u9ED8\u8BA4\u4E0D\u8986\u76D6,\u907F\u514D\u8BEF\u64CD\u4F5C\u628A
132826
133017
  \u6574\u4E2A\u56E2\u961F\u5207\u5230\u4E00\u4E2A\u65B0\u677F)
132827
133018
 
132828
- \u2500\u2500 adopt \u6A21\u5F0F\u5185\u90E8\u6B65\u9AA4(\u81EA\u52A8\u9009\u4E2D,\u6216\u663E\u5F0F --adopt/--adopt-guid \u89E6\u53D1)\u2500\u2500
133019
+ \u2500\u2500 \u5220\u9664/\u6E05\u7406(\u6682\u65E0\u81EA\u52A8\u5B50\u547D\u4EE4)\u2500\u2500
133020
+ \u96F6\u53C2\u6570\u521B\u5EFA\u7684\u6E05\u5355 owner \u662F bot app,\u4F60\u7684\u7528\u6237\u8EAB\u4EFD\u5220\u4E0D\u6389\u5B83\u3002\u8981\u5220\u9664\u672C\u673A\u6CE8\u518C\u7684\u6E05\u5355:
133021
+ \u7528\u521B\u5EFA\u5B83\u7684 bot \u7684 app \u51ED\u8BC1(bridge \u81EA\u5DF1\u7528\u7684\u90A3\u5957,tenant_access_token)\u8C03
133022
+ \`DELETE /open-apis/task/v2/tasklists/{guid}\`(guid \u89C1 <LARKWAY_HOME>/task-team.json),
133023
+ \u518D\u5220\u6389\u672C\u673A\u72B6\u6001\u6587\u4EF6:task-team.json\u3001candidate-alerts-<guid>.json\u3001\u5404 bot \u7684
133024
+ task-handles.json \u91CC\u5BF9\u5E94\u8BB0\u5F55\u3002(\u81EA\u52A8 --delete \u5B50\u547D\u4EE4\u6309\u9700\u518D\u52A0\u3002)
133025
+
133026
+ \u2500\u2500 adopt \u6A21\u5F0F\u5185\u90E8\u6B65\u9AA4(\u4EC5\u663E\u5F0F --adopt/--adopt-guid \u89E6\u53D1)\u2500\u2500
132829
133027
  1. \u4EE5\u4F60(\u64CD\u4F5C\u8005)\u7684\u7528\u6237\u8EAB\u4EFD\u6309\u540D\u5B57\u7CBE\u786E\u5339\u914D\u4F60\u80FD\u770B\u5230\u7684\u6E05\u5355(\u91CD\u540D \u2192 \u62A5\u9519\u5217\u51FA\u5168\u90E8
132830
- guid,\u8BA9\u4F60\u52A0 --adopt-guid <guid> \u6D88\u6B67\u91CD\u8DD1;\u4E00\u4E2A\u90FD\u627E\u4E0D\u5230 \u2192 \u81EA\u52A8\u6A21\u5F0F\u4E0B\u9759\u9ED8\u56DE\u9000
132831
- \u521B\u5EFA\u8DEF\u5F84,\u663E\u5F0F --adopt \u4E0B\u62A5\u9519\u63D0\u793A\u5148\u53BB\u4EFB\u52A1\u4E2D\u5FC3\u5EFA\u4E00\u4E2A)
133028
+ guid,\u8BA9\u4F60\u52A0 --adopt-guid <guid> \u6D88\u6B67\u91CD\u8DD1;\u4E00\u4E2A\u90FD\u627E\u4E0D\u5230 \u2192 \u62A5\u9519\u63D0\u793A\u5148\u53BB\u4EFB\u52A1
133029
+ \u4E2D\u5FC3\u5EFA\u4E00\u4E2A,\u7EDD\u4E0D\u9759\u9ED8\u521B\u5EFA)
132832
133030
  2. \u628A\u6BCF\u4E2A bot \u7684 app \u52A0\u4E3A\u6E05\u5355\u6210\u5458(role=editor,\u5E42\u7B49,\u5DF2\u662F\u6210\u5458\u7684\u8DF3\u8FC7/\u65E0\u5BB3\u91CD\u590D)
132833
133031
  3. \u5199\u5165\u5171\u4EAB\u6CE8\u518C\u6587\u4EF6 <LARKWAY_HOME>/task-team.json(\u4E0E\u521B\u5EFA\u8DEF\u5F84\u540C\u4E00\u5957
132834
133032
  first-writer-wins / --force \u8986\u76D6\u8BED\u4E49)
@@ -132938,25 +133136,12 @@ async function run10(ctx, args) {
132938
133136
  loginHint
132939
133137
  });
132940
133138
  }
132941
- const autoTarget = resolveAdoptTarget(creatorProfile, name, void 0, loginHint);
132942
- if (autoTarget.ok) {
132943
- return runAdoptWithGuid(ctx, {
132944
- guid: autoTarget.guid,
132945
- matchedName: autoTarget.matchedName,
132946
- bots,
132947
- force,
132948
- creatorProfile,
132949
- loginHint
132950
- });
132951
- }
132952
- if (autoTarget.reason === "ambiguous") {
132953
- if (ctx.flags.json) ctx.ui.emitJson({ ok: false, error: autoTarget.message });
132954
- else ctx.ui.failure(autoTarget.message);
132955
- return 1;
132956
- }
132957
133139
  if (!ctx.flags.json) {
132958
- const why = autoTarget.reason === "list-failed" ? "\u65E0\u6CD5\u4EE5\u4F60\u7684\u7528\u6237\u8EAB\u4EFD\u67E5\u8BE2\u6E05\u5355" : `\u6CA1\u627E\u5230\u540C\u540D\u6E05\u5355 "${name}"`;
132959
- ctx.ui.print(ctx.ui.dim(`(${why},\u56DE\u9000\u5230\u7528 bot app \u8EAB\u4EFD\u521B\u5EFA/\u590D\u7528\u6E05\u5355\u2014\u2014\u5982\u9700\u5F3A\u5236 adopt \u89C1 --adopt)`));
133140
+ ctx.ui.print(
133141
+ ctx.ui.dim(
133142
+ `(\u7528 bot app \u8EAB\u4EFD\u521B\u5EFA/\u590D\u7528\u6E05\u5355 "${name}"\u3002\u60F3\u8BA4\u9886\u4F60\u81EA\u5DF1\u5728\u4EFB\u52A1\u4E2D\u5FC3\u5EFA\u7684\u6E05\u5355\u8BF7\u7528 --adopt "<\u6E05\u5355\u540D>" / --adopt-guid <guid>;\u591A\u56E2\u961F\u90E8\u7F72\u5EFA\u8BAE\u7528 --name \u6539\u540D\u9694\u79BB\u3002)`
133143
+ )
133144
+ );
132960
133145
  }
132961
133146
  const ownerOpenId = explicitOwner ?? resolveOwnerOpenId(creatorProfile);
132962
133147
  if (!ownerOpenId) {
@@ -132968,7 +133153,11 @@ async function run10(ctx, args) {
132968
133153
  }
132969
133154
  return 1;
132970
133155
  }
132971
- const sdkClient = new import_node_sdk2.Client({ appId: creator.app_id, appSecret: creator.appSecret });
133156
+ const sdkClient = new import_node_sdk2.Client({
133157
+ appId: creator.app_id,
133158
+ appSecret: creator.appSecret,
133159
+ loggerLevel: import_node_sdk2.LoggerLevel.fatal
133160
+ });
132972
133161
  const requester = {
132973
133162
  request: (config) => sdkClient.request(config)
132974
133163
  };
@@ -132987,13 +133176,22 @@ async function run10(ctx, args) {
132987
133176
  try {
132988
133177
  await taskClient.addTasklistMembers(tasklistGuid, members);
132989
133178
  } catch (err2) {
132990
- const msg = `\u590D\u7528\u5DF2\u6709\u6E05\u5355 ${tasklistGuid} \u65F6\u8865\u5145\u6210\u5458\u5931\u8D25: ${err2 instanceof Error ? err2.message : String(err2)}`;
132991
- if (ctx.flags.json) ctx.ui.emitJson({ ok: false, error: msg });
132992
- else {
132993
- ctx.ui.failure(msg);
132994
- ctx.ui.print("\u5E38\u89C1\u539F\u56E0:app \u672A\u5728\u5F00\u653E\u5E73\u53F0\u540E\u53F0\u52FE\u9009 task:tasklist:write / task:task:write scope(\u89C1 docs/task-handle.md \xA77)\u3002");
133179
+ const errMsg = err2 instanceof Error ? err2.message : String(err2);
133180
+ if (isMembersEndpoint404(err2)) {
133181
+ if (!ctx.flags.json) {
133182
+ ctx.ui.warning(
133183
+ `\u590D\u7528\u6E05\u5355 ${tasklistGuid} \u65F6 add_members \u8FD4\u56DE 404(app \u7C7B\u578B\u6210\u5458\u7AEF\u70B9\u4E0D\u652F\u6301\u81EA\u52A9\u52A0\u5165,bot \u901A\u5E38\u5DF2\u7ECF\u662F\u6210\u5458)\u2014\u2014\u5DF2\u5FFD\u7565,\u4E0D\u5F71\u54CD\u4F7F\u7528(\u4E0E bridge \u542F\u52A8\u7684\u81EA\u52A9\u52A0\u5165\u540C\u6B3E\u964D\u7EA7)\u3002`
133184
+ );
133185
+ }
133186
+ } else {
133187
+ const msg = `\u590D\u7528\u5DF2\u6709\u6E05\u5355 ${tasklistGuid} \u65F6\u8865\u5145\u6210\u5458\u5931\u8D25: ${errMsg}`;
133188
+ if (ctx.flags.json) ctx.ui.emitJson({ ok: false, error: msg });
133189
+ else {
133190
+ ctx.ui.failure(msg);
133191
+ ctx.ui.print("\u5E38\u89C1\u539F\u56E0:app \u672A\u5728\u5F00\u653E\u5E73\u53F0\u540E\u53F0\u52FE\u9009 task:tasklist:write / task:task:write scope(\u89C1 docs/task-handle.md \xA77)\u3002");
133192
+ }
133193
+ return 1;
132995
133194
  }
132996
- return 1;
132997
133195
  }
132998
133196
  } else {
132999
133197
  reused = false;
@@ -133050,8 +133248,10 @@ async function run10(ctx, args) {
133050
133248
  } else {
133051
133249
  ctx.ui.success(`\u6E05\u5355 "${name}" \u5DF2\u521B\u5EFA: ${tasklistGuid}`);
133052
133250
  }
133053
- ctx.ui.print(`owner \u6210\u5458: ${ownerOpenId}${explicitOwner ? "" : "(\u4ECE lark-cli \u5F53\u524D\u767B\u5F55\u7528\u6237\u81EA\u52A8\u89E3\u6790)"}`);
133054
- ctx.ui.print(`\u5DF2\u52A0\u5165\u6210\u5458(editor): ${bots.map((b) => b.id).join(", ")}`);
133251
+ ctx.ui.print(
133252
+ `\u4F60(${ownerOpenId})\u5DF2\u4F5C\u4E3A editor \u52A0\u5165${explicitOwner ? "" : "(open_id \u4ECE lark-cli \u5F53\u524D\u767B\u5F55\u7528\u6237\u81EA\u52A8\u89E3\u6790)"} \u2014\u2014 \u6E05\u5355 owner \u662F\u521B\u5EFA\u5B83\u7684 bot app;\u4F60\u662F editor \u6210\u5458(\u53EF\u5728\u4EFB\u52A1\u4E2D\u5FC3\u770B\u5230\u5E76\u7F16\u8F91)\u3002`
133253
+ );
133254
+ ctx.ui.print(`\u5DF2\u52A0\u5165(editor)\u7684 bot: ${bots.map((b) => b.id).join(", ")}`);
133055
133255
  ctx.ui.print("");
133056
133256
  if (!reused) {
133057
133257
  ctx.ui.print(
@@ -133070,16 +133270,22 @@ async function run10(ctx, args) {
133070
133270
  );
133071
133271
  return 0;
133072
133272
  }
133273
+ function isMembersEndpoint404(err2) {
133274
+ if (err2 instanceof TaskApiError) {
133275
+ return err2.status === 404 && err2.code === void 0;
133276
+ }
133277
+ return /page not found/i.test(err2 instanceof Error ? err2.message : String(err2));
133278
+ }
133073
133279
  function resolveAdoptTarget(creatorProfile, name, explicitGuid, loginHint) {
133074
133280
  if (explicitGuid) {
133075
133281
  return { ok: true, guid: explicitGuid, matchedName: name };
133076
133282
  }
133077
- const listResult = listUserTasklists(creatorProfile);
133283
+ const listResult = searchUserTasklists(creatorProfile, name);
133078
133284
  if (!listResult.ok) {
133079
133285
  return {
133080
133286
  ok: false,
133081
133287
  reason: "list-failed",
133082
- message: `\u65E0\u6CD5\u4EE5\u4F60\u7684\u7528\u6237\u8EAB\u4EFD\u5217\u51FA\u6E05\u5355:${listResult.error}
133288
+ message: `\u65E0\u6CD5\u4EE5\u4F60\u7684\u7528\u6237\u8EAB\u4EFD\u67E5\u8BE2\u6E05\u5355:${listResult.error}
133083
133289
 
133084
133290
  \u8BF7\u5148\u786E\u8BA4\u5DF2\u7528\u8FD9\u4E2A profile \u767B\u5F55\u8FC7\u7528\u6237\u8EAB\u4EFD\u3001\u4E14\u7533\u8BF7\u4E86 task \u57DF\u6743\u9650:
133085
133291
  ${loginHint}