feishu-docs-cli 0.1.0-beta.2
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/LICENSE +21 -0
- package/README.md +333 -0
- package/README.zh.md +332 -0
- package/bin/feishu-docs.js +8 -0
- package/dist/auth.d.ts +76 -0
- package/dist/auth.js +512 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +166 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +42 -0
- package/dist/client.js +269 -0
- package/dist/client.js.map +1 -0
- package/dist/commands/cat.d.ts +6 -0
- package/dist/commands/cat.js +151 -0
- package/dist/commands/cat.js.map +1 -0
- package/dist/commands/create.d.ts +6 -0
- package/dist/commands/create.js +120 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/delete.d.ts +6 -0
- package/dist/commands/delete.js +89 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/info.d.ts +6 -0
- package/dist/commands/info.js +69 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/login.d.ts +10 -0
- package/dist/commands/login.js +90 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/ls.d.ts +6 -0
- package/dist/commands/ls.js +76 -0
- package/dist/commands/ls.js.map +1 -0
- package/dist/commands/read.d.ts +6 -0
- package/dist/commands/read.js +404 -0
- package/dist/commands/read.js.map +1 -0
- package/dist/commands/search.d.ts +7 -0
- package/dist/commands/search.js +87 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/share.d.ts +13 -0
- package/dist/commands/share.js +210 -0
- package/dist/commands/share.js.map +1 -0
- package/dist/commands/spaces.d.ts +6 -0
- package/dist/commands/spaces.js +43 -0
- package/dist/commands/spaces.js.map +1 -0
- package/dist/commands/tree.d.ts +6 -0
- package/dist/commands/tree.js +101 -0
- package/dist/commands/tree.js.map +1 -0
- package/dist/commands/update.d.ts +9 -0
- package/dist/commands/update.js +211 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/wiki.d.ts +6 -0
- package/dist/commands/wiki.js +284 -0
- package/dist/commands/wiki.js.map +1 -0
- package/dist/parser/block-types.d.ts +141 -0
- package/dist/parser/block-types.js +167 -0
- package/dist/parser/block-types.js.map +1 -0
- package/dist/parser/blocks-to-md.d.ts +26 -0
- package/dist/parser/blocks-to-md.js +576 -0
- package/dist/parser/blocks-to-md.js.map +1 -0
- package/dist/parser/text-elements.d.ts +13 -0
- package/dist/parser/text-elements.js +91 -0
- package/dist/parser/text-elements.js.map +1 -0
- package/dist/services/block-writer.d.ts +30 -0
- package/dist/services/block-writer.js +131 -0
- package/dist/services/block-writer.js.map +1 -0
- package/dist/services/doc-blocks.d.ts +9 -0
- package/dist/services/doc-blocks.js +30 -0
- package/dist/services/doc-blocks.js.map +1 -0
- package/dist/services/markdown-convert.d.ts +51 -0
- package/dist/services/markdown-convert.js +109 -0
- package/dist/services/markdown-convert.js.map +1 -0
- package/dist/services/wiki-nodes.d.ts +21 -0
- package/dist/services/wiki-nodes.js +47 -0
- package/dist/services/wiki-nodes.js.map +1 -0
- package/dist/types/index.d.ts +234 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/document-resolver.d.ts +28 -0
- package/dist/utils/document-resolver.js +47 -0
- package/dist/utils/document-resolver.js.map +1 -0
- package/dist/utils/drive-types.d.ts +4 -0
- package/dist/utils/drive-types.js +16 -0
- package/dist/utils/drive-types.js.map +1 -0
- package/dist/utils/errors.d.ts +21 -0
- package/dist/utils/errors.js +110 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/member.d.ts +11 -0
- package/dist/utils/member.js +30 -0
- package/dist/utils/member.js.map +1 -0
- package/dist/utils/url-parser.d.ts +5 -0
- package/dist/utils/url-parser.js +55 -0
- package/dist/utils/url-parser.js.map +1 -0
- package/dist/utils/validate.d.ts +8 -0
- package/dist/utils/validate.js +15 -0
- package/dist/utils/validate.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* share command: Manage document permissions (list/add/set).
|
|
3
|
+
*/
|
|
4
|
+
import { createClient, fetchWithAuth } from "../client.js";
|
|
5
|
+
import { CliError } from "../utils/errors.js";
|
|
6
|
+
import { resolveDocument } from "../utils/document-resolver.js";
|
|
7
|
+
import { validateMemberId, detectMemberType } from "../utils/member.js";
|
|
8
|
+
import { mapToDriveType } from "../utils/drive-types.js";
|
|
9
|
+
export const meta = {
|
|
10
|
+
subcommands: {
|
|
11
|
+
list: {
|
|
12
|
+
options: {},
|
|
13
|
+
positionals: true,
|
|
14
|
+
handler: list,
|
|
15
|
+
},
|
|
16
|
+
add: {
|
|
17
|
+
options: {
|
|
18
|
+
role: { type: "string", default: "view" },
|
|
19
|
+
},
|
|
20
|
+
positionals: true,
|
|
21
|
+
handler: add,
|
|
22
|
+
},
|
|
23
|
+
set: {
|
|
24
|
+
options: {
|
|
25
|
+
public: { type: "string" },
|
|
26
|
+
},
|
|
27
|
+
positionals: true,
|
|
28
|
+
handler: set,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Map user-friendly role name to API perm value.
|
|
34
|
+
*/
|
|
35
|
+
export function mapRole(role) {
|
|
36
|
+
const map = {
|
|
37
|
+
view: "view",
|
|
38
|
+
edit: "edit",
|
|
39
|
+
manage: "full_access",
|
|
40
|
+
};
|
|
41
|
+
const mapped = map[role];
|
|
42
|
+
if (!mapped) {
|
|
43
|
+
throw new CliError("INVALID_ARGS", `无效的角色: ${role}。可选值: view, edit, manage`);
|
|
44
|
+
}
|
|
45
|
+
return mapped;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Map public mode string to link_share_entity value.
|
|
49
|
+
*/
|
|
50
|
+
export function mapPublicMode(mode, role = "view") {
|
|
51
|
+
if (mode === "closed")
|
|
52
|
+
return "closed";
|
|
53
|
+
if (mode === "tenant" && role === "view")
|
|
54
|
+
return "tenant_readable";
|
|
55
|
+
if (mode === "tenant" && role === "edit")
|
|
56
|
+
return "tenant_editable";
|
|
57
|
+
if (mode === "open" && role === "view")
|
|
58
|
+
return "anyone_readable";
|
|
59
|
+
if (mode === "open" && role === "edit")
|
|
60
|
+
return "anyone_editable";
|
|
61
|
+
// Default: treat as tenant_readable for "tenant", anyone_readable for "open"
|
|
62
|
+
if (mode === "tenant")
|
|
63
|
+
return "tenant_readable";
|
|
64
|
+
if (mode === "open")
|
|
65
|
+
return "anyone_readable";
|
|
66
|
+
throw new CliError("INVALID_ARGS", `无效的公开模式: ${mode}。可选值: closed, tenant, open`);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check if an API error indicates missing OAuth scope.
|
|
70
|
+
*/
|
|
71
|
+
function isScopeError(err) {
|
|
72
|
+
const code = err?.apiCode ||
|
|
73
|
+
err?.code;
|
|
74
|
+
return code === 99991668 || code === 99991671;
|
|
75
|
+
}
|
|
76
|
+
async function resolveDocForShare(client, authInfo, input) {
|
|
77
|
+
const doc = await resolveDocument(client, authInfo, input);
|
|
78
|
+
// For wiki nodes, use the node_token with type "wiki" for permission APIs
|
|
79
|
+
const token = doc.spaceId ? doc.parsed.token : doc.objToken;
|
|
80
|
+
const type = doc.spaceId ? "wiki" : mapToDriveType(doc.objType);
|
|
81
|
+
return { token, type, doc };
|
|
82
|
+
}
|
|
83
|
+
async function list(args, globalOpts) {
|
|
84
|
+
const input = args.positionals[0];
|
|
85
|
+
if (!input) {
|
|
86
|
+
throw new CliError("INVALID_ARGS", "缺少文档 URL 或 token。用法: feishu-docs share list <url>");
|
|
87
|
+
}
|
|
88
|
+
const { client, authInfo } = await createClient(globalOpts);
|
|
89
|
+
let token, type;
|
|
90
|
+
try {
|
|
91
|
+
({ token, type } = await resolveDocForShare(client, authInfo, input));
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
if (isScopeError(err)) {
|
|
95
|
+
throw new CliError("AUTH_REQUIRED", "缺少权限 scope: drive:drive:permission。请运行 feishu-docs login 重新授权");
|
|
96
|
+
}
|
|
97
|
+
throw err;
|
|
98
|
+
}
|
|
99
|
+
const res = await fetchWithAuth(authInfo, `/open-apis/drive/v1/permissions/${encodeURIComponent(token)}/members`, { params: { type } });
|
|
100
|
+
const shareResData = res?.data;
|
|
101
|
+
const members = (shareResData?.members || []);
|
|
102
|
+
if (globalOpts.json) {
|
|
103
|
+
process.stdout.write(JSON.stringify({ success: true, members }, null, 2) + "\n");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (members.length === 0) {
|
|
107
|
+
process.stdout.write("没有协作者\n");
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
for (const m of members) {
|
|
111
|
+
const name = m.member_name || m.member_id || "(未知)";
|
|
112
|
+
const perm = m.perm || "unknown";
|
|
113
|
+
const memberType = m.member_type || "";
|
|
114
|
+
process.stdout.write(` ${name} [${perm}] (${memberType}: ${m.member_id})\n`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function add(args, globalOpts) {
|
|
118
|
+
const input = args.positionals[0];
|
|
119
|
+
const memberId = args.positionals[1];
|
|
120
|
+
if (!input || !memberId) {
|
|
121
|
+
throw new CliError("INVALID_ARGS", "用法: feishu-docs share add <url> <member> --role <role>");
|
|
122
|
+
}
|
|
123
|
+
validateMemberId(memberId);
|
|
124
|
+
const { client, authInfo } = await createClient(globalOpts);
|
|
125
|
+
const { token, type } = await resolveDocForShare(client, authInfo, input);
|
|
126
|
+
const memberType = detectMemberType(memberId);
|
|
127
|
+
const perm = mapRole(args.role || "view");
|
|
128
|
+
try {
|
|
129
|
+
await fetchWithAuth(authInfo, `/open-apis/drive/v1/permissions/${encodeURIComponent(token)}/members`, {
|
|
130
|
+
method: "POST",
|
|
131
|
+
params: { type },
|
|
132
|
+
body: { member_type: memberType, member_id: memberId, perm },
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
// Error 1201003: member already exists → fallback to update
|
|
137
|
+
const code = err?.apiCode ||
|
|
138
|
+
err?.code;
|
|
139
|
+
if (code === 1201003) {
|
|
140
|
+
await fetchWithAuth(authInfo, `/open-apis/drive/v1/permissions/${encodeURIComponent(token)}/members/${encodeURIComponent(memberId)}`, {
|
|
141
|
+
method: "PUT",
|
|
142
|
+
params: { type },
|
|
143
|
+
body: { member_type: memberType, perm },
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
else if (isScopeError(err)) {
|
|
147
|
+
throw new CliError("AUTH_REQUIRED", "缺少权限 scope: drive:drive:permission。请运行 feishu-docs login 重新授权");
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
throw err;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (globalOpts.json) {
|
|
154
|
+
process.stdout.write(JSON.stringify({
|
|
155
|
+
success: true,
|
|
156
|
+
member_id: memberId,
|
|
157
|
+
member_type: memberType,
|
|
158
|
+
perm,
|
|
159
|
+
}) + "\n");
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
process.stdout.write(`已添加协作者 ${memberId} (${perm})\n`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function set(args, globalOpts) {
|
|
166
|
+
const input = args.positionals[0];
|
|
167
|
+
if (!input) {
|
|
168
|
+
throw new CliError("INVALID_ARGS", "用法: feishu-docs share set <url> --public <closed|tenant|open>");
|
|
169
|
+
}
|
|
170
|
+
if (!args.public) {
|
|
171
|
+
throw new CliError("INVALID_ARGS", "缺少 --public 参数。可选值: closed, tenant, open");
|
|
172
|
+
}
|
|
173
|
+
const { client, authInfo } = await createClient(globalOpts);
|
|
174
|
+
const { token, type } = await resolveDocForShare(client, authInfo, input);
|
|
175
|
+
// Extract optional role from --public value like "tenant:edit"
|
|
176
|
+
let mode = args.public;
|
|
177
|
+
let shareRole = "view";
|
|
178
|
+
if (mode.includes(":")) {
|
|
179
|
+
const parts = mode.split(":");
|
|
180
|
+
mode = parts[0];
|
|
181
|
+
shareRole = parts[1] || "view";
|
|
182
|
+
}
|
|
183
|
+
if (shareRole !== "view" && shareRole !== "edit") {
|
|
184
|
+
throw new CliError("INVALID_ARGS", `无效的分享角色: ${shareRole}。可选值: view, edit(如 tenant:edit)`);
|
|
185
|
+
}
|
|
186
|
+
const linkShareEntity = mapPublicMode(mode, shareRole);
|
|
187
|
+
try {
|
|
188
|
+
await fetchWithAuth(authInfo, `/open-apis/drive/v1/permissions/${encodeURIComponent(token)}/public`, {
|
|
189
|
+
method: "PATCH",
|
|
190
|
+
params: { type },
|
|
191
|
+
body: { link_share_entity: linkShareEntity },
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
if (isScopeError(err)) {
|
|
196
|
+
throw new CliError("AUTH_REQUIRED", "缺少权限 scope: drive:drive:permission。请运行 feishu-docs login 重新授权");
|
|
197
|
+
}
|
|
198
|
+
throw err;
|
|
199
|
+
}
|
|
200
|
+
if (globalOpts.json) {
|
|
201
|
+
process.stdout.write(JSON.stringify({
|
|
202
|
+
success: true,
|
|
203
|
+
link_share_entity: linkShareEntity,
|
|
204
|
+
}) + "\n");
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
process.stdout.write(`已修改分享设置为 ${linkShareEntity}\n`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=share.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share.js","sourceRoot":"","sources":["../../src/commands/share.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spaces command: List all knowledge bases.
|
|
3
|
+
*/
|
|
4
|
+
import { createClient, fetchWithAuth } from "../client.js";
|
|
5
|
+
export const meta = {
|
|
6
|
+
options: {},
|
|
7
|
+
positionals: false,
|
|
8
|
+
handler: spaces,
|
|
9
|
+
};
|
|
10
|
+
export async function spaces(_args, globalOpts) {
|
|
11
|
+
const { authInfo } = await createClient(globalOpts);
|
|
12
|
+
const allSpaces = [];
|
|
13
|
+
let pageToken;
|
|
14
|
+
do {
|
|
15
|
+
const params = {
|
|
16
|
+
page_size: 50,
|
|
17
|
+
};
|
|
18
|
+
if (pageToken)
|
|
19
|
+
params.page_token = pageToken;
|
|
20
|
+
const res = await fetchWithAuth(authInfo, "/open-apis/wiki/v2/spaces", {
|
|
21
|
+
params,
|
|
22
|
+
});
|
|
23
|
+
const data = res?.data;
|
|
24
|
+
if (data?.items) {
|
|
25
|
+
allSpaces.push(...data.items);
|
|
26
|
+
}
|
|
27
|
+
pageToken = data?.has_more ? data.page_token : undefined;
|
|
28
|
+
} while (pageToken);
|
|
29
|
+
if (globalOpts.json) {
|
|
30
|
+
process.stdout.write(JSON.stringify({ success: true, spaces: allSpaces }, null, 2) + "\n");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (allSpaces.length === 0) {
|
|
34
|
+
process.stdout.write("没有找到知识库\n");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
for (const space of allSpaces) {
|
|
38
|
+
const name = space.name || "(未命名)";
|
|
39
|
+
const desc = space.description ? ` — ${space.description}` : "";
|
|
40
|
+
process.stdout.write(`${space.space_id} ${name}${desc}\n`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=spaces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spaces.js","sourceRoot":"","sources":["../../src/commands/spaces.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG3D,MAAM,CAAC,MAAM,IAAI,GAAgB;IAC/B,OAAO,EAAE,EAAE;IACX,WAAW,EAAE,KAAK;IAClB,OAAO,EAAE,MAAM;CAChB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,KAAkB,EAClB,UAAsB;IAEtB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,CAAC;IAEpD,MAAM,SAAS,GAAc,EAAE,CAAC;IAChC,IAAI,SAA6B,CAAC;IAElC,GAAG,CAAC;QACF,MAAM,MAAM,GAAgD;YAC1D,SAAS,EAAE,EAAE;SACd,CAAC;QACF,IAAI,SAAS;YAAE,MAAM,CAAC,UAAU,GAAG,SAAS,CAAC;QAE7C,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,2BAA2B,EAAE;YACrE,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,GAAG,EAAE,IAA2C,CAAC;QAC9D,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC;YAChB,SAAS,CAAC,IAAI,CAAC,GAAI,IAAI,CAAC,KAAmB,CAAC,CAAC;QAC/C,CAAC;QACD,SAAS,GAAG,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAE,IAAI,CAAC,UAAqB,CAAC,CAAC,CAAC,SAAS,CAAC;IACvE,CAAC,QAAQ,SAAS,EAAE;IAEpB,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;QACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CACrE,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAClC,OAAO;IACT,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,SAA0C,EAAE,CAAC;QAC/D,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC;QACnC,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,QAAQ,KAAK,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tree command: Display knowledge base node tree.
|
|
3
|
+
*/
|
|
4
|
+
import { createClient, fetchWithAuth } from "../client.js";
|
|
5
|
+
import { fetchChildren } from "../services/wiki-nodes.js";
|
|
6
|
+
import { CliError } from "../utils/errors.js";
|
|
7
|
+
import { validateToken } from "../utils/validate.js";
|
|
8
|
+
/**
|
|
9
|
+
* Recursively build the tree structure.
|
|
10
|
+
*/
|
|
11
|
+
async function buildNodeTree(authInfo, spaceId, parentNodeToken, currentDepth, maxDepth) {
|
|
12
|
+
if (maxDepth !== undefined && currentDepth >= maxDepth)
|
|
13
|
+
return [];
|
|
14
|
+
const children = await fetchChildren(authInfo, spaceId, parentNodeToken);
|
|
15
|
+
const result = [];
|
|
16
|
+
for (const node of children) {
|
|
17
|
+
const entry = {
|
|
18
|
+
title: node.title || "(无标题)",
|
|
19
|
+
nodeToken: node.node_token,
|
|
20
|
+
objType: node.obj_type || "unknown",
|
|
21
|
+
hasChild: node.has_child,
|
|
22
|
+
children: [],
|
|
23
|
+
};
|
|
24
|
+
if (node.has_child) {
|
|
25
|
+
entry.children = await buildNodeTree(authInfo, spaceId, node.node_token, currentDepth + 1, maxDepth);
|
|
26
|
+
}
|
|
27
|
+
result.push(entry);
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Render tree to text output.
|
|
33
|
+
*/
|
|
34
|
+
function renderTree(nodes, prefix = "") {
|
|
35
|
+
const lines = [];
|
|
36
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
37
|
+
const node = nodes[i];
|
|
38
|
+
const last = i === nodes.length - 1;
|
|
39
|
+
const connector = last ? "└── " : "├── ";
|
|
40
|
+
const childPrefix = last ? " " : "│ ";
|
|
41
|
+
lines.push(`${prefix}${connector}${node.title} (${node.objType}, ${node.nodeToken})`);
|
|
42
|
+
if (node.children.length > 0) {
|
|
43
|
+
const childLines = renderTree(node.children, prefix + childPrefix);
|
|
44
|
+
lines.push(...childLines);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return lines;
|
|
48
|
+
}
|
|
49
|
+
export const meta = {
|
|
50
|
+
options: {
|
|
51
|
+
node: { type: "string" },
|
|
52
|
+
depth: { type: "string" },
|
|
53
|
+
},
|
|
54
|
+
positionals: true,
|
|
55
|
+
handler: tree,
|
|
56
|
+
};
|
|
57
|
+
export async function tree(args, globalOpts) {
|
|
58
|
+
const spaceId = args.positionals[0];
|
|
59
|
+
if (!spaceId) {
|
|
60
|
+
throw new CliError("INVALID_ARGS", "缺少知识库 ID。用法: feishu-docs tree <space_id> [--node <token>]");
|
|
61
|
+
}
|
|
62
|
+
validateToken(spaceId, "space_id");
|
|
63
|
+
const { authInfo } = await createClient(globalOpts);
|
|
64
|
+
const parentNode = args.node || undefined;
|
|
65
|
+
if (parentNode)
|
|
66
|
+
validateToken(parentNode, "node_token");
|
|
67
|
+
const maxDepth = args.depth !== undefined ? Number(args.depth) : undefined;
|
|
68
|
+
// Get space info for root label
|
|
69
|
+
let spaceName = spaceId;
|
|
70
|
+
if (!parentNode) {
|
|
71
|
+
try {
|
|
72
|
+
const res = await fetchWithAuth(authInfo, `/open-apis/wiki/v2/spaces/${encodeURIComponent(spaceId)}`);
|
|
73
|
+
const data = res?.data;
|
|
74
|
+
spaceName =
|
|
75
|
+
data?.space?.name || spaceId;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// ignore, use spaceId as name
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const nodes = await buildNodeTree(authInfo, spaceId, parentNode, 0, maxDepth);
|
|
82
|
+
if (globalOpts.json) {
|
|
83
|
+
process.stdout.write(JSON.stringify({ success: true, space_id: spaceId, nodes }, null, 2) +
|
|
84
|
+
"\n");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (parentNode) {
|
|
88
|
+
process.stdout.write(`节点 ${parentNode} (space: ${spaceId})\n`);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
process.stdout.write(`${spaceName} (space: ${spaceId})\n`);
|
|
92
|
+
}
|
|
93
|
+
const lines = renderTree(nodes);
|
|
94
|
+
for (const line of lines) {
|
|
95
|
+
process.stdout.write(line + "\n");
|
|
96
|
+
}
|
|
97
|
+
if (nodes.length === 0) {
|
|
98
|
+
process.stdout.write("(空)\n");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../../src/commands/tree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* update command: Update existing documents (append, overwrite, restore).
|
|
3
|
+
*
|
|
4
|
+
* Uses Convert + Descendant API for writing new content.
|
|
5
|
+
* Restore uses the old children API (backup data is raw blocks, not markdown).
|
|
6
|
+
*/
|
|
7
|
+
import { CommandMeta, CommandArgs, GlobalOpts } from "../types/index.js";
|
|
8
|
+
export declare const meta: CommandMeta;
|
|
9
|
+
export declare function update(args: CommandArgs, globalOpts: GlobalOpts): Promise<void>;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* update command: Update existing documents (append, overwrite, restore).
|
|
3
|
+
*
|
|
4
|
+
* Uses Convert + Descendant API for writing new content.
|
|
5
|
+
* Restore uses the old children API (backup data is raw blocks, not markdown).
|
|
6
|
+
*/
|
|
7
|
+
import { readFile } from "node:fs/promises";
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
import { resolve, normalize, sep } from "node:path";
|
|
10
|
+
import { randomUUID } from "node:crypto";
|
|
11
|
+
import { createClient, fetchWithAuth } from "../client.js";
|
|
12
|
+
import { CliError } from "../utils/errors.js";
|
|
13
|
+
import { convertAndWrite } from "../services/markdown-convert.js";
|
|
14
|
+
import { resolveDocument } from "../utils/document-resolver.js";
|
|
15
|
+
import { readBody, getDocumentInfo, clearDocument, backupDocument, sleep, BATCH_SIZE, QPS_DELAY, BACKUPS_DIR, } from "../services/block-writer.js";
|
|
16
|
+
export const meta = {
|
|
17
|
+
options: {
|
|
18
|
+
body: { type: "string" },
|
|
19
|
+
append: { type: "boolean", default: false },
|
|
20
|
+
restore: { type: "string" },
|
|
21
|
+
},
|
|
22
|
+
positionals: true,
|
|
23
|
+
handler: update,
|
|
24
|
+
};
|
|
25
|
+
export async function update(args, globalOpts) {
|
|
26
|
+
const input = args.positionals[0];
|
|
27
|
+
if (!input) {
|
|
28
|
+
throw new CliError("INVALID_ARGS", "缺少文档 URL 或 token。用法: feishu-docs update <url|token> --body <file>");
|
|
29
|
+
}
|
|
30
|
+
const { client, authInfo } = await createClient(globalOpts);
|
|
31
|
+
const doc = await resolveDocument(client, authInfo, input);
|
|
32
|
+
const documentId = doc.objToken;
|
|
33
|
+
if (doc.objType !== "docx") {
|
|
34
|
+
throw new CliError("INVALID_ARGS", `该文档类型 (${doc.objType}) 不支持更新`);
|
|
35
|
+
}
|
|
36
|
+
if (args.restore) {
|
|
37
|
+
return restoreFromBackup(client, authInfo, documentId, args.restore, globalOpts);
|
|
38
|
+
}
|
|
39
|
+
if (!args.body) {
|
|
40
|
+
throw new CliError("INVALID_ARGS", "缺少 --body 参数。用法: feishu-docs update <url|token> --body <file>");
|
|
41
|
+
}
|
|
42
|
+
const bodyContent = await readBody(args.body);
|
|
43
|
+
if (!bodyContent.trim()) {
|
|
44
|
+
throw new CliError("INVALID_ARGS", "文档内容为空,至少需要一行内容");
|
|
45
|
+
}
|
|
46
|
+
if (args.append) {
|
|
47
|
+
return appendToDocument(client, authInfo, documentId, bodyContent, globalOpts);
|
|
48
|
+
}
|
|
49
|
+
return overwriteDocument(client, authInfo, documentId, bodyContent, globalOpts);
|
|
50
|
+
}
|
|
51
|
+
async function appendToDocument(client, authInfo, documentId, bodyContent, globalOpts) {
|
|
52
|
+
const docInfo = await getDocumentInfo(client, authInfo, documentId);
|
|
53
|
+
await convertAndWrite(authInfo, documentId, bodyContent, docInfo.revisionId, -1);
|
|
54
|
+
if (globalOpts.json) {
|
|
55
|
+
process.stdout.write(JSON.stringify({
|
|
56
|
+
success: true,
|
|
57
|
+
document_id: documentId,
|
|
58
|
+
mode: "append",
|
|
59
|
+
}) + "\n");
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
process.stdout.write(`已追加内容到文档 ${documentId}\n`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function overwriteDocument(client, authInfo, documentId, bodyContent, globalOpts) {
|
|
66
|
+
let backupPath;
|
|
67
|
+
try {
|
|
68
|
+
const backup = await backupDocument(client, authInfo, documentId);
|
|
69
|
+
backupPath = backup.filepath;
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
throw new CliError("API_ERROR", `备份失败,操作中止: ${err.message}`);
|
|
73
|
+
}
|
|
74
|
+
const docInfo = await getDocumentInfo(client, authInfo, documentId);
|
|
75
|
+
let rev;
|
|
76
|
+
try {
|
|
77
|
+
rev = await clearDocument(client, authInfo, documentId, docInfo.revisionId);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
process.stderr.write(`feishu-docs: error: 清空文档失败: ${err.message}\n`);
|
|
81
|
+
process.stderr.write(`feishu-docs: info: 备份文件: ${backupPath}\n`);
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
await convertAndWrite(authInfo, documentId, bodyContent, rev);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
process.stderr.write(`feishu-docs: error: 写入新内容失败,尝试从备份恢复...\n`);
|
|
89
|
+
try {
|
|
90
|
+
await restoreFromBackup(client, authInfo, documentId, backupPath, globalOpts);
|
|
91
|
+
process.stderr.write("feishu-docs: info: 已从备份自动恢复\n");
|
|
92
|
+
}
|
|
93
|
+
catch (restoreErr) {
|
|
94
|
+
process.stderr.write(`feishu-docs: error: 自动恢复也失败: ${restoreErr.message}\n`);
|
|
95
|
+
process.stderr.write(`feishu-docs: info: 请手动恢复,备份文件: ${backupPath}\n`);
|
|
96
|
+
process.stderr.write("feishu-docs: info: 也可在飞书客户端中使用版本历史回退\n");
|
|
97
|
+
}
|
|
98
|
+
throw err;
|
|
99
|
+
}
|
|
100
|
+
if (globalOpts.json) {
|
|
101
|
+
process.stdout.write(JSON.stringify({
|
|
102
|
+
success: true,
|
|
103
|
+
document_id: documentId,
|
|
104
|
+
mode: "overwrite",
|
|
105
|
+
backup: backupPath,
|
|
106
|
+
}) + "\n");
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
process.stdout.write(`已覆盖更新文档 ${documentId}\n`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Recursively restore blocks and their descendants from a backup block map.
|
|
114
|
+
* Uses the old children API (backup data is raw blocks, not markdown).
|
|
115
|
+
*/
|
|
116
|
+
const MAX_RESTORE_DEPTH = 20;
|
|
117
|
+
async function restoreChildren(authInfo, documentId, parentBlockId, childIds, blockMap, revisionId, depth = 0) {
|
|
118
|
+
let rev = revisionId;
|
|
119
|
+
if (!childIds || childIds.length === 0)
|
|
120
|
+
return rev;
|
|
121
|
+
if (depth >= MAX_RESTORE_DEPTH) {
|
|
122
|
+
process.stderr.write(`feishu-docs: warning: 恢复深度超过 ${MAX_RESTORE_DEPTH} 层,跳过更深层级\n`);
|
|
123
|
+
return rev;
|
|
124
|
+
}
|
|
125
|
+
for (let i = 0; i < childIds.length; i += BATCH_SIZE) {
|
|
126
|
+
const batchIds = childIds.slice(i, i + BATCH_SIZE);
|
|
127
|
+
const batch = batchIds
|
|
128
|
+
.map((id) => blockMap.get(id))
|
|
129
|
+
.filter(Boolean)
|
|
130
|
+
.map((b) => {
|
|
131
|
+
const { block_id, parent_id, children, ...rest } = b;
|
|
132
|
+
return rest;
|
|
133
|
+
});
|
|
134
|
+
if (batch.length === 0)
|
|
135
|
+
continue;
|
|
136
|
+
if (i > 0)
|
|
137
|
+
await sleep(QPS_DELAY);
|
|
138
|
+
const res = await fetchWithAuth(authInfo, `/open-apis/docx/v1/documents/${encodeURIComponent(documentId)}/blocks/${encodeURIComponent(parentBlockId)}/children`, {
|
|
139
|
+
method: "POST",
|
|
140
|
+
body: { children: batch, index: i },
|
|
141
|
+
params: { document_revision_id: rev, client_token: randomUUID() },
|
|
142
|
+
});
|
|
143
|
+
const resData = res?.data;
|
|
144
|
+
rev = resData?.document_revision_id ?? rev;
|
|
145
|
+
const createdIds = (resData?.children ?? []).map((c) => c.block_id);
|
|
146
|
+
for (let j = 0; j < createdIds.length && j < batchIds.length; j++) {
|
|
147
|
+
const original = blockMap.get(batchIds[j]);
|
|
148
|
+
if (original?.children?.length && original.children.length > 0) {
|
|
149
|
+
await sleep(QPS_DELAY);
|
|
150
|
+
rev = await restoreChildren(authInfo, documentId, createdIds[j], original.children, blockMap, rev, depth + 1);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return rev;
|
|
155
|
+
}
|
|
156
|
+
async function restoreFromBackup(client, authInfo, documentId, backupPath, globalOpts) {
|
|
157
|
+
const resolvedPath = resolve(normalize(backupPath));
|
|
158
|
+
const resolvedBackups = resolve(BACKUPS_DIR);
|
|
159
|
+
if (!resolvedPath.startsWith(resolvedBackups + sep)) {
|
|
160
|
+
throw new CliError("INVALID_ARGS", `备份文件必须位于 ${resolvedBackups} 目录下`, { recovery: `请使用 ${resolvedBackups} 下的备份文件路径` });
|
|
161
|
+
}
|
|
162
|
+
if (!existsSync(resolvedPath)) {
|
|
163
|
+
throw new CliError("FILE_NOT_FOUND", `备份文件不存在: ${resolvedPath}`);
|
|
164
|
+
}
|
|
165
|
+
if (!resolvedPath.endsWith(".json")) {
|
|
166
|
+
throw new CliError("INVALID_ARGS", "备份文件必须是 .json 格式");
|
|
167
|
+
}
|
|
168
|
+
const raw = await readFile(resolvedPath, "utf8");
|
|
169
|
+
let blocks;
|
|
170
|
+
try {
|
|
171
|
+
blocks = JSON.parse(raw);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
throw new CliError("INVALID_ARGS", `备份文件 JSON 格式无效: ${resolvedPath}`);
|
|
175
|
+
}
|
|
176
|
+
if (!Array.isArray(blocks)) {
|
|
177
|
+
throw new CliError("INVALID_ARGS", "备份文件格式无效:期望 JSON 数组");
|
|
178
|
+
}
|
|
179
|
+
const rootBlock = blocks.find((b) => b.block_type === 1);
|
|
180
|
+
if (!rootBlock) {
|
|
181
|
+
throw new CliError("INVALID_ARGS", "备份文件格式无效:未找到根 block");
|
|
182
|
+
}
|
|
183
|
+
const topLevelIds = rootBlock.children || [];
|
|
184
|
+
if (topLevelIds.length === 0) {
|
|
185
|
+
process.stderr.write("feishu-docs: warning: 备份文件中没有可恢复的内容\n");
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const blockMap = new Map(blocks.map((b) => [b.block_id, b]));
|
|
189
|
+
const docInfo = await getDocumentInfo(client, authInfo, documentId);
|
|
190
|
+
let rev = await clearDocument(client, authInfo, documentId, docInfo.revisionId);
|
|
191
|
+
try {
|
|
192
|
+
rev = await restoreChildren(authInfo, documentId, documentId, topLevelIds, blockMap, rev);
|
|
193
|
+
}
|
|
194
|
+
catch (restoreErr) {
|
|
195
|
+
process.stderr.write(`feishu-docs: error: 恢复过程中出错: ${restoreErr.message}\n` +
|
|
196
|
+
` 文档可能处于不完整状态。备份文件路径: ${resolvedPath}\n` +
|
|
197
|
+
` 你可以在飞书客户端中使用版本历史恢复文档。\n`);
|
|
198
|
+
throw restoreErr;
|
|
199
|
+
}
|
|
200
|
+
if (globalOpts.json) {
|
|
201
|
+
process.stdout.write(JSON.stringify({
|
|
202
|
+
success: true,
|
|
203
|
+
document_id: documentId,
|
|
204
|
+
mode: "restore",
|
|
205
|
+
}) + "\n");
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
process.stdout.write(`已从备份恢复文档 ${documentId}\n`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EACL,QAAQ,EACR,eAAe,EACf,aAAa,EACb,cAAc,EACd,KAAK,EACL,UAAU,EACV,SAAS,EACT,WAAW,GACZ,MAAM,6BAA6B,CAAC;AAUrC,MAAM,CAAC,MAAM,IAAI,GAAgB;IAC/B,OAAO,EAAE;QACP,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;QAC3C,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC5B;IACD,WAAW,EAAE,IAAI;IACjB,OAAO,EAAE,MAAM;CAChB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,IAAiB,EACjB,UAAsB;IAEtB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAY,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,QAAQ,CAChB,cAAc,EACd,mEAAmE,CACpE,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,CAAC;IAC5D,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC3D,MAAM,UAAU,GAAG,GAAG,CAAC,QAAQ,CAAC;IAEhC,IAAI,GAAG,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,QAAQ,CAChB,cAAc,EACd,UAAU,GAAG,CAAC,OAAO,SAAS,CAC/B,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,OAAO,iBAAiB,CACtB,MAAM,EACN,QAAQ,EACR,UAAU,EACV,IAAI,CAAC,OAAiB,EACtB,UAAU,CACX,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACf,MAAM,IAAI,QAAQ,CAChB,cAAc,EACd,+DAA+D,CAChE,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC;IACxD,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC;QACxB,MAAM,IAAI,QAAQ,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;IACxD,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,gBAAgB,CACrB,MAAM,EACN,QAAQ,EACR,UAAU,EACV,WAAW,EACX,UAAU,CACX,CAAC;IACJ,CAAC;IAED,OAAO,iBAAiB,CACtB,MAAM,EACN,QAAQ,EACR,UAAU,EACV,WAAW,EACX,UAAU,CACX,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,MAAmB,EACnB,QAAkB,EAClB,UAAkB,EAClB,WAAmB,EACnB,UAAsB;IAEtB,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IAEpE,MAAM,eAAe,CACnB,QAAQ,EACR,UAAU,EACV,WAAW,EACX,OAAO,CAAC,UAAU,EAClB,CAAC,CAAC,CACH,CAAC;IAEF,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;QACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC;YACb,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,UAAU;YACvB,IAAI,EAAE,QAAQ;SACf,CAAC,GAAG,IAAI,CACV,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,UAAU,IAAI,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC9B,MAAmB,EACnB,QAAkB,EAClB,UAAkB,EAClB,WAAmB,EACnB,UAAsB;IAEtB,IAAI,UAAkB,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;QAClE,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,QAAQ,CAChB,WAAW,EACX,cAAe,GAAa,CAAC,OAAO,EAAE,CACvC,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IACpE,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC9E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,+BAAgC,GAAa,CAAC,OAAO,IAAI,CAC1D,CAAC;QACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,UAAU,IAAI,CAAC,CAAC;QACjE,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;IAChE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,0CAA0C,CAC3C,CAAC;QACF,IAAI,CAAC;YACH,MAAM,iBAAiB,CACrB,MAAM,EACN,QAAQ,EACR,UAAU,EACV,UAAU,EACV,UAAU,CACX,CAAC;YACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,UAAU,EAAE,CAAC;YACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gCAAiC,UAAoB,CAAC,OAAO,IAAI,CAClE,CAAC;YACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,kCAAkC,UAAU,IAAI,CACjD,CAAC;YACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,wCAAwC,CACzC,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;QACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC;YACb,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,UAAU;YACvB,IAAI,EAAE,WAAW;YACjB,MAAM,EAAE,UAAU;SACnB,CAAC,GAAG,IAAI,CACV,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,UAAU,IAAI,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAE7B,KAAK,UAAU,eAAe,CAC5B,QAAkB,EAClB,UAAkB,EAClB,aAAqB,EACrB,QAAkB,EAClB,QAA4B,EAC5B,UAAkB,EAClB,QAAgB,CAAC;IAEjB,IAAI,GAAG,GAAG,UAAU,CAAC;IACrB,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IACnD,IAAI,KAAK,IAAI,iBAAiB,EAAE,CAAC;QAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gCAAgC,iBAAiB,aAAa,CAC/D,CAAC;QACF,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC;QACrD,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,QAAQ;aACnB,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;aAC7B,MAAM,CAAC,OAAO,CAAC;aACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,CAAU,CAAC;YAC9D,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QAEL,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACjC,IAAI,CAAC,GAAG,CAAC;YAAE,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC;QAElC,MAAM,GAAG,GAAG,MAAM,aAAa,CAC7B,QAAQ,EACR,gCAAgC,kBAAkB,CAAC,UAAU,CAAC,WAAW,kBAAkB,CAAC,aAAa,CAAC,WAAW,EACrH;YACE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE;YACnC,MAAM,EAAE,EAAE,oBAAoB,EAAE,GAAG,EAAE,YAAY,EAAE,UAAU,EAAE,EAAE;SAClE,CACF,CAAC;QAEF,MAAM,OAAO,GAAG,GAAG,EAAE,IAA2C,CAAC;QACjE,GAAG,GAAI,OAAO,EAAE,oBAA+B,IAAI,GAAG,CAAC;QACvD,MAAM,UAAU,GAAa,CAC1B,OAAO,EAAE,QAA0C,IAAI,EAAE,CAC3D,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAEzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAClE,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,IAAI,QAAQ,EAAE,QAAQ,EAAE,MAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/D,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC;gBACvB,GAAG,GAAG,MAAM,eAAe,CACzB,QAAQ,EACR,UAAU,EACV,UAAU,CAAC,CAAC,CAAC,EACb,QAAQ,CAAC,QAAQ,EACjB,QAAQ,EACR,GAAG,EACH,KAAK,GAAG,CAAC,CACV,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC9B,MAAmB,EACnB,QAAkB,EAClB,UAAkB,EAClB,UAAkB,EAClB,UAAsB;IAEtB,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;IACpD,MAAM,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAE7C,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,eAAe,GAAG,GAAG,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,QAAQ,CAChB,cAAc,EACd,YAAY,eAAe,MAAM,EACjC,EAAE,QAAQ,EAAE,OAAO,eAAe,WAAW,EAAE,CAChD,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,QAAQ,CAAC,gBAAgB,EAAE,YAAY,YAAY,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,QAAQ,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACjD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,QAAQ,CAChB,cAAc,EACd,mBAAmB,YAAY,EAAE,CAClC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC;IACzD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,WAAW,GAAG,SAAS,CAAC,QAAQ,IAAI,EAAE,CAAC;IAC7C,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC9D,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7D,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IACpE,IAAI,GAAG,GAAG,MAAM,aAAa,CAC3B,MAAM,EACN,QAAQ,EACR,UAAU,EACV,OAAO,CAAC,UAAU,CACnB,CAAC;IAEF,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,eAAe,CACzB,QAAQ,EACR,UAAU,EACV,UAAU,EACV,WAAW,EACX,QAAQ,EACR,GAAG,CACJ,CAAC;IACJ,CAAC;IAAC,OAAO,UAAU,EAAE,CAAC;QACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gCAAiC,UAAoB,CAAC,OAAO,IAAI;YAC/D,yBAAyB,YAAY,IAAI;YACzC,2BAA2B,CAC9B,CAAC;QACF,MAAM,UAAU,CAAC;IACnB,CAAC;IAED,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;QACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC;YACb,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,UAAU;YACvB,IAAI,EAAE,SAAS;SAChB,CAAC,GAAG,IAAI,CACV,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,UAAU,IAAI,CAAC,CAAC;IACnD,CAAC;AACH,CAAC"}
|