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 +1 -1
- package/README.zh.md +1 -1
- package/dist/cli/index.js +280 -74
- package/dist/main.js +893 -31
- package/package.json +1 -1
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.
|
|
11
|
+
**Current release: v0.3.36**
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
package/README.zh.md
CHANGED
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(
|
|
25417
|
-
|
|
25418
|
-
|
|
25419
|
-
|
|
25420
|
-
|
|
25421
|
-
|
|
25422
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
131186
|
-
const 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
|
|
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
|
|
132865
|
+
function searchUserTasklists(profile, query, spawnSyncFn = spawnSync3) {
|
|
132699
132866
|
const result = runLarkCliJson(
|
|
132700
|
-
["task", "
|
|
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
|
-
|
|
132705
|
-
|
|
132706
|
-
|
|
132707
|
-
|
|
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
|
-
|
|
132710
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
132806
|
-
1.
|
|
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\
|
|
132810
|
-
|
|
132811
|
-
|
|
132812
|
-
|
|
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")
|
|
132818
|
-
\
|
|
132819
|
-
--adopt "<\u6E05\u5355\u540D>" \
|
|
132820
|
-
\u76F4\u63A5\u62A5\u9519\u9000\u51FA,\u4E0D\
|
|
132821
|
-
--adopt-guid <guid> \u8DF3\u8FC7\u6309\u540D\u5B57\u67E5\u627E,\u76F4\u63A5
|
|
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
|
|
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 \
|
|
132831
|
-
\
|
|
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
|
-
|
|
132959
|
-
|
|
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({
|
|
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
|
|
132991
|
-
if (
|
|
132992
|
-
|
|
132993
|
-
|
|
132994
|
-
|
|
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(
|
|
133054
|
-
|
|
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 =
|
|
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\
|
|
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}
|