feishu-docs-cli 0.1.0-beta.10
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 +403 -0
- package/README.zh.md +402 -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 +197 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +28 -0
- package/dist/client.js +256 -0
- package/dist/client.js.map +1 -0
- package/dist/commands/authorize.d.ts +12 -0
- package/dist/commands/authorize.js +73 -0
- package/dist/commands/authorize.js.map +1 -0
- package/dist/commands/cat.d.ts +6 -0
- package/dist/commands/cat.js +159 -0
- package/dist/commands/cat.js.map +1 -0
- package/dist/commands/cp.d.ts +9 -0
- package/dist/commands/cp.js +70 -0
- package/dist/commands/cp.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 +91 -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/install-skill.d.ts +5 -0
- package/dist/commands/install-skill.js +28 -0
- package/dist/commands/install-skill.js.map +1 -0
- package/dist/commands/login.d.ts +10 -0
- package/dist/commands/login.js +93 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/ls.d.ts +6 -0
- package/dist/commands/ls.js +79 -0
- package/dist/commands/ls.js.map +1 -0
- package/dist/commands/mkdir.d.ts +6 -0
- package/dist/commands/mkdir.js +49 -0
- package/dist/commands/mkdir.js.map +1 -0
- package/dist/commands/mv.d.ts +9 -0
- package/dist/commands/mv.js +72 -0
- package/dist/commands/mv.js.map +1 -0
- package/dist/commands/read.d.ts +6 -0
- package/dist/commands/read.js +439 -0
- package/dist/commands/read.js.map +1 -0
- package/dist/commands/search.d.ts +7 -0
- package/dist/commands/search.js +92 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/share.d.ts +13 -0
- package/dist/commands/share.js +266 -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 +217 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/wiki.d.ts +6 -0
- package/dist/commands/wiki.js +286 -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 +666 -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/scopes.d.ts +21 -0
- package/dist/scopes.js +48 -0
- package/dist/scopes.js.map +1 -0
- package/dist/services/block-writer.d.ts +29 -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 +8 -0
- package/dist/services/doc-blocks.js +26 -0
- package/dist/services/doc-blocks.js.map +1 -0
- package/dist/services/markdown-convert.d.ts +68 -0
- package/dist/services/markdown-convert.js +217 -0
- package/dist/services/markdown-convert.js.map +1 -0
- package/dist/services/wiki-nodes.d.ts +20 -0
- package/dist/services/wiki-nodes.js +46 -0
- package/dist/services/wiki-nodes.js.map +1 -0
- package/dist/types/index.d.ts +236 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/document-resolver.d.ts +26 -0
- package/dist/utils/document-resolver.js +46 -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 +23 -0
- package/dist/utils/errors.js +114 -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/scope-prompt.d.ts +39 -0
- package/dist/utils/scope-prompt.js +134 -0
- package/dist/utils/scope-prompt.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/dist/utils/version.d.ts +12 -0
- package/dist/utils/version.js +128 -0
- package/dist/utils/version.js.map +1 -0
- package/package.json +53 -0
- package/skills/feishu-docs/SKILL.md +194 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI entry point: declarative command registration + routing.
|
|
3
|
+
* Supports both top-level commands and subcommands (e.g., share list).
|
|
4
|
+
*/
|
|
5
|
+
import { parseArgs } from "node:util";
|
|
6
|
+
import { loginMeta, logoutMeta, whoamiMeta } from "./commands/login.js";
|
|
7
|
+
import { meta as authorizeMeta } from "./commands/authorize.js";
|
|
8
|
+
import { meta as readMeta } from "./commands/read.js";
|
|
9
|
+
import { meta as spaceMeta } from "./commands/spaces.js";
|
|
10
|
+
import { meta as treeMeta } from "./commands/tree.js";
|
|
11
|
+
import { meta as catMeta } from "./commands/cat.js";
|
|
12
|
+
import { meta as searchMeta } from "./commands/search.js";
|
|
13
|
+
import { meta as createMeta } from "./commands/create.js";
|
|
14
|
+
import { meta as updateMeta } from "./commands/update.js";
|
|
15
|
+
import { meta as deleteMeta } from "./commands/delete.js";
|
|
16
|
+
import { meta as shareMeta } from "./commands/share.js";
|
|
17
|
+
import { meta as infoMeta } from "./commands/info.js";
|
|
18
|
+
import { meta as lsMeta } from "./commands/ls.js";
|
|
19
|
+
import { meta as mvMeta } from "./commands/mv.js";
|
|
20
|
+
import { meta as cpMeta } from "./commands/cp.js";
|
|
21
|
+
import { meta as mkdirMeta } from "./commands/mkdir.js";
|
|
22
|
+
import { meta as wikiMeta } from "./commands/wiki.js";
|
|
23
|
+
import { meta as installSkillMeta } from "./commands/install-skill.js";
|
|
24
|
+
import { handleError, CliError } from "./utils/errors.js";
|
|
25
|
+
import { getLocalVersion, checkForUpdates } from "./utils/version.js";
|
|
26
|
+
const HELP_TEXT = `feishu-docs - AI Agent 飞书云文档 CLI 工具
|
|
27
|
+
|
|
28
|
+
用法: feishu-docs <command> [options]
|
|
29
|
+
|
|
30
|
+
认证:
|
|
31
|
+
login [--scope "..."] [--redirect-uri <url>] [--port <port>]
|
|
32
|
+
OAuth 登录(申请基础免审权限)
|
|
33
|
+
authorize [--scope "..."] 申请额外权限(可能需管理员审核)
|
|
34
|
+
logout 清除已保存的凭证
|
|
35
|
+
whoami 查看当前认证身份和模式
|
|
36
|
+
|
|
37
|
+
文档:
|
|
38
|
+
read <url|token> 读取文档,输出 Markdown
|
|
39
|
+
create <title> [options] 创建文档
|
|
40
|
+
update <url|token> [options] 更新文档内容
|
|
41
|
+
delete <url|token> 删除文档
|
|
42
|
+
info <url|token> 查看文档元信息
|
|
43
|
+
|
|
44
|
+
知识库:
|
|
45
|
+
spaces 列出所有知识库
|
|
46
|
+
tree <space_id|url> [--node <token>] 展示知识库节点树
|
|
47
|
+
cat <space_id|url> [--node <token>] 递归读取节点下所有文档
|
|
48
|
+
wiki create-space <name> 创建知识库
|
|
49
|
+
wiki add-member <space_id> <member> 添加知识库成员
|
|
50
|
+
wiki remove-member <space_id> <member> 移除知识库成员
|
|
51
|
+
wiki rename <url> --title <new_title> 重命名节点
|
|
52
|
+
wiki move <url> --to <space_id> 移动节点
|
|
53
|
+
wiki copy <url> --to <space_id> 复制节点
|
|
54
|
+
|
|
55
|
+
搜索:
|
|
56
|
+
search <query> [options] 搜索文档
|
|
57
|
+
|
|
58
|
+
云空间:
|
|
59
|
+
ls [folder_token] 列出文件夹内容
|
|
60
|
+
mv <url|token> <target_folder> 移动文件
|
|
61
|
+
cp <url|token> <target_folder> 复制文件
|
|
62
|
+
mkdir <name> [--parent <folder_token>] 创建文件夹
|
|
63
|
+
|
|
64
|
+
权限:
|
|
65
|
+
share list <url> 查看协作者
|
|
66
|
+
share add <url> <member> --role <role> 添加协作者
|
|
67
|
+
share remove <url> <member> 移除协作者
|
|
68
|
+
share update <url> <member> --role <role> 修改协作者权限
|
|
69
|
+
share set <url> --public <mode> 修改分享设置
|
|
70
|
+
|
|
71
|
+
Agent:
|
|
72
|
+
install-skill 安装 Claude Code Skill
|
|
73
|
+
|
|
74
|
+
全局选项:
|
|
75
|
+
--auth <user|tenant|auto> 认证模式(默认 auto)
|
|
76
|
+
--json 输出 JSON 格式
|
|
77
|
+
--lark 使用海外 Lark 域名
|
|
78
|
+
--help 显示帮助信息
|
|
79
|
+
-v, --version 显示版本号
|
|
80
|
+
`;
|
|
81
|
+
const GLOBAL_OPTIONS = {
|
|
82
|
+
auth: { type: "string", default: "auto" },
|
|
83
|
+
json: { type: "boolean", default: false },
|
|
84
|
+
lark: { type: "boolean", default: false },
|
|
85
|
+
help: { type: "boolean", default: false },
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Command registry: name → meta definition.
|
|
89
|
+
* Each meta has: { handler, options, positionals } or { subcommands }.
|
|
90
|
+
*/
|
|
91
|
+
const COMMANDS = {
|
|
92
|
+
login: loginMeta,
|
|
93
|
+
authorize: authorizeMeta,
|
|
94
|
+
logout: logoutMeta,
|
|
95
|
+
whoami: whoamiMeta,
|
|
96
|
+
read: readMeta,
|
|
97
|
+
spaces: spaceMeta,
|
|
98
|
+
tree: treeMeta,
|
|
99
|
+
cat: catMeta,
|
|
100
|
+
search: searchMeta,
|
|
101
|
+
create: createMeta,
|
|
102
|
+
update: updateMeta,
|
|
103
|
+
delete: deleteMeta,
|
|
104
|
+
share: shareMeta,
|
|
105
|
+
info: infoMeta,
|
|
106
|
+
ls: lsMeta,
|
|
107
|
+
mv: mvMeta,
|
|
108
|
+
cp: cpMeta,
|
|
109
|
+
mkdir: mkdirMeta,
|
|
110
|
+
wiki: wikiMeta,
|
|
111
|
+
"install-skill": installSkillMeta,
|
|
112
|
+
};
|
|
113
|
+
function extractGlobalOpts(values) {
|
|
114
|
+
return {
|
|
115
|
+
auth: values.auth,
|
|
116
|
+
json: values.json,
|
|
117
|
+
lark: values.lark,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Remap hyphenated option keys to camelCase for args.
|
|
122
|
+
*/
|
|
123
|
+
function remapArgs(values, optionDefs) {
|
|
124
|
+
const args = {};
|
|
125
|
+
for (const key of Object.keys(optionDefs)) {
|
|
126
|
+
const camel = key.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
127
|
+
if (values[key] !== undefined) {
|
|
128
|
+
args[camel] = values[key];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return args;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Parse and dispatch a command.
|
|
135
|
+
*/
|
|
136
|
+
function parseAndRun(def, argv) {
|
|
137
|
+
const allOptions = { ...GLOBAL_OPTIONS, ...def.options };
|
|
138
|
+
const { values, positionals } = parseArgs({
|
|
139
|
+
args: argv,
|
|
140
|
+
options: allOptions,
|
|
141
|
+
allowPositionals: def.positionals ?? false,
|
|
142
|
+
strict: false,
|
|
143
|
+
});
|
|
144
|
+
const globalOpts = extractGlobalOpts(values);
|
|
145
|
+
const args = remapArgs(values, def.options);
|
|
146
|
+
if (def.positionals) {
|
|
147
|
+
args.positionals = positionals;
|
|
148
|
+
}
|
|
149
|
+
return { handler: def.handler, args, globalOpts };
|
|
150
|
+
}
|
|
151
|
+
export async function run(argv) {
|
|
152
|
+
if (argv.includes("--version") || argv.includes("-v")) {
|
|
153
|
+
process.stdout.write(`feishu-docs ${getLocalVersion()}\n`);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) {
|
|
157
|
+
process.stdout.write(HELP_TEXT);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// Non-blocking update check (runs in background, never throws)
|
|
161
|
+
const updateCheck = checkForUpdates();
|
|
162
|
+
const command = argv[0];
|
|
163
|
+
const restArgs = argv.slice(1);
|
|
164
|
+
const def = COMMANDS[command];
|
|
165
|
+
if (!def) {
|
|
166
|
+
throw new CliError("INVALID_ARGS", `未知命令: ${command}。运行 feishu-docs --help 查看可用命令`);
|
|
167
|
+
}
|
|
168
|
+
let handler, args, globalOpts;
|
|
169
|
+
if (def.subcommands) {
|
|
170
|
+
const subDef = def;
|
|
171
|
+
const subName = restArgs[0];
|
|
172
|
+
if (!subName ||
|
|
173
|
+
subName === "--help" ||
|
|
174
|
+
subName === "-h" ||
|
|
175
|
+
!subDef.subcommands[subName]) {
|
|
176
|
+
const available = Object.keys(subDef.subcommands).join(", ");
|
|
177
|
+
throw new CliError("INVALID_ARGS", `用法: feishu-docs ${command} <${available}> [options]`);
|
|
178
|
+
}
|
|
179
|
+
const subCmd = subDef.subcommands[subName];
|
|
180
|
+
const subArgs = restArgs.slice(1);
|
|
181
|
+
({ handler, args, globalOpts } = parseAndRun(subCmd, subArgs));
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
({ handler, args, globalOpts } = parseAndRun(def, restArgs));
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
await handler(args, globalOpts);
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
handleError(err, globalOpts.json);
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
// Wait for background update check to complete (never throws)
|
|
194
|
+
await updateCheck;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,IAAI,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,IAAI,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,IAAI,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,IAAI,IAAI,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAQtE,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDjB,CAAC;AAEF,MAAM,cAAc,GAAG;IACrB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE;IACzC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IACzC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IACzC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;CACjC,CAAC;AAEX;;;GAGG;AACH,MAAM,QAAQ,GAAiD;IAC7D,KAAK,EAAE,SAAS;IAChB,SAAS,EAAE,aAAa;IACxB,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,UAAU;IAClB,IAAI,EAAE,QAAQ;IACd,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,QAAQ;IACd,GAAG,EAAE,OAAO;IACZ,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,QAAQ;IACd,EAAE,EAAE,MAAM;IACV,EAAE,EAAE,MAAM;IACV,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,QAAQ;IACd,eAAe,EAAE,gBAAgB;CAClC,CAAC;AAEF,SAAS,iBAAiB,CAAC,MAA+B;IACxD,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAc;QAC3B,IAAI,EAAE,MAAM,CAAC,IAAe;QAC5B,IAAI,EAAE,MAAM,CAAC,IAAe;KAC7B,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAChB,MAA+B,EAC/B,UAAmC;IAEnC,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QAC1E,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;YAC9B,IAAI,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAClB,GAAgB,EAChB,IAAc;IAMd,MAAM,UAAU,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC;IACzD,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;QACxC,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,UAGR;QACD,gBAAgB,EAAE,GAAG,CAAC,WAAW,IAAI,KAAK;QAC1C,MAAM,EAAE,KAAK;KACd,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAiC,CAAC,CAAC;IACxE,MAAM,IAAI,GAAG,SAAS,CAAC,MAAiC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACvE,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACpB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AACpD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAc;IACtC,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,eAAe,EAAE,IAAI,CAAC,CAAC;QAC3D,OAAO;IACT,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACxE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAChC,OAAO;IACT,CAAC;IAED,+DAA+D;IAC/D,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IAEtC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE/B,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC9B,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,QAAQ,CAChB,cAAc,EACd,SAAS,OAAO,+BAA+B,CAChD,CAAC;IACJ,CAAC;IAED,IAAI,OAA+B,EACjC,IAAiB,EACjB,UAAsB,CAAC;IAEzB,IAAK,GAAsB,CAAC,WAAW,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,GAAqB,CAAC;QACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC5B,IACE,CAAC,OAAO;YACR,OAAO,KAAK,QAAQ;YACpB,OAAO,KAAK,IAAI;YAChB,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,EAC5B,CAAC;YACD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7D,MAAM,IAAI,QAAQ,CAChB,cAAc,EACd,mBAAmB,OAAO,KAAK,SAAS,aAAa,CACtD,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACjE,CAAC;SAAM,CAAC;QACN,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,WAAW,CAAC,GAAkB,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC9E,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,WAAW,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;YAAS,CAAC;QACT,8DAA8D;QAC9D,MAAM,WAAW,CAAC;IACpB,CAAC;AACH,CAAC"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth client factory and API utilities.
|
|
3
|
+
*/
|
|
4
|
+
import type { AuthInfo, GlobalOpts, FetchOptions, ApiResponse } from "./types/index.js";
|
|
5
|
+
/**
|
|
6
|
+
* Create auth context for API calls.
|
|
7
|
+
* @param {object} options - { auth: 'user'|'tenant'|'auto', lark: boolean }
|
|
8
|
+
* @returns {{ authInfo: AuthInfo }}
|
|
9
|
+
*/
|
|
10
|
+
export declare function createClient(options?: Partial<GlobalOpts>, _refreshAttempt?: number): Promise<{
|
|
11
|
+
authInfo: AuthInfo;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the API base URL based on whether we're using Lark or Feishu.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getApiBase(authInfo: AuthInfo): string;
|
|
17
|
+
/**
|
|
18
|
+
* Get tenant_access_token for tenant mode API calls.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getTenantToken(authInfo: AuthInfo): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Direct fetch wrapper that correctly passes user/tenant token.
|
|
23
|
+
*/
|
|
24
|
+
export declare function fetchWithAuth(authInfo: AuthInfo, path: string, options?: FetchOptions): Promise<ApiResponse>;
|
|
25
|
+
/**
|
|
26
|
+
* Fetch binary data with auth (for APIs that return file streams).
|
|
27
|
+
*/
|
|
28
|
+
export declare function fetchBinaryWithAuth(authInfo: AuthInfo, path: string): Promise<ArrayBuffer>;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth client factory and API utilities.
|
|
3
|
+
*/
|
|
4
|
+
import { resolveAuth, refreshUserToken, acquireRefreshLock } from "./auth.js";
|
|
5
|
+
import { CliError, mapApiError } from "./utils/errors.js";
|
|
6
|
+
const FEISHU_BASE = "https://open.feishu.cn";
|
|
7
|
+
const LARK_BASE = "https://open.larksuite.com";
|
|
8
|
+
/**
|
|
9
|
+
* Create auth context for API calls.
|
|
10
|
+
* @param {object} options - { auth: 'user'|'tenant'|'auto', lark: boolean }
|
|
11
|
+
* @returns {{ authInfo: AuthInfo }}
|
|
12
|
+
*/
|
|
13
|
+
export async function createClient(options = {}, _refreshAttempt = 0) {
|
|
14
|
+
const authMode = options.auth || "auto";
|
|
15
|
+
const useLark = options.lark || false;
|
|
16
|
+
const resolved = await resolveAuth(authMode);
|
|
17
|
+
const authInfo = { ...resolved, useLark };
|
|
18
|
+
const { appId, appSecret } = authInfo;
|
|
19
|
+
if (!appId || !appSecret) {
|
|
20
|
+
if (authInfo.mode === "user" && authInfo.userToken) {
|
|
21
|
+
// User token from env, no app credentials needed for some APIs
|
|
22
|
+
return { authInfo };
|
|
23
|
+
}
|
|
24
|
+
throw new CliError("AUTH_REQUIRED", "缺少 FEISHU_APP_ID 或 FEISHU_APP_SECRET");
|
|
25
|
+
}
|
|
26
|
+
// Auto-refresh user token if expired
|
|
27
|
+
if (authInfo.mode === "user" && authInfo.expiresAt) {
|
|
28
|
+
if (Date.now() >= authInfo.expiresAt) {
|
|
29
|
+
if (authInfo.refreshToken) {
|
|
30
|
+
try {
|
|
31
|
+
process.stderr.write("feishu-docs: info: token 已过期,正在自动刷新...\n");
|
|
32
|
+
const releaseLock = await acquireRefreshLock();
|
|
33
|
+
if (!releaseLock) {
|
|
34
|
+
if (_refreshAttempt >= 3) {
|
|
35
|
+
throw new CliError("TOKEN_EXPIRED", "等待 token 刷新超时。如果问题持续,请手动删除 ~/.feishu-docs/.refresh.lock 后重试");
|
|
36
|
+
}
|
|
37
|
+
process.stderr.write("feishu-docs: info: 另一个进程正在刷新 token,等待中...\n");
|
|
38
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
39
|
+
return createClient(options, _refreshAttempt + 1);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const newTokens = await refreshUserToken(appId, appSecret, authInfo.refreshToken, { useLark });
|
|
43
|
+
const refreshedAuthInfo = {
|
|
44
|
+
...authInfo,
|
|
45
|
+
userToken: newTokens.user_access_token,
|
|
46
|
+
expiresAt: newTokens.expires_at,
|
|
47
|
+
refreshToken: newTokens.refresh_token,
|
|
48
|
+
};
|
|
49
|
+
return { authInfo: refreshedAuthInfo };
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
await releaseLock();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (refreshErr) {
|
|
56
|
+
const refreshError = refreshErr;
|
|
57
|
+
// In auto mode, fall back to tenant auth instead of failing
|
|
58
|
+
if (authMode === "auto" && appId && appSecret) {
|
|
59
|
+
process.stderr.write(`feishu-docs: info: 自动刷新失败 (${refreshError.message}),回退到 tenant 模式\n`);
|
|
60
|
+
const tenantAuthInfo = {
|
|
61
|
+
...authInfo,
|
|
62
|
+
mode: "tenant",
|
|
63
|
+
userToken: undefined,
|
|
64
|
+
};
|
|
65
|
+
return { authInfo: tenantAuthInfo };
|
|
66
|
+
}
|
|
67
|
+
throw new CliError("TOKEN_EXPIRED", "自动刷新 token 失败,请重新运行 feishu-docs login", {
|
|
68
|
+
recovery: "运行 feishu-docs login 重新认证",
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// In auto mode, fall back to tenant auth instead of failing
|
|
74
|
+
if (authMode === "auto" && appId && appSecret) {
|
|
75
|
+
process.stderr.write("feishu-docs: info: user token 已过期,回退到 tenant 模式\n");
|
|
76
|
+
const tenantAuthInfo = {
|
|
77
|
+
...authInfo,
|
|
78
|
+
mode: "tenant",
|
|
79
|
+
userToken: undefined,
|
|
80
|
+
};
|
|
81
|
+
return { authInfo: tenantAuthInfo };
|
|
82
|
+
}
|
|
83
|
+
throw new CliError("TOKEN_EXPIRED", "token 已过期,请重新运行 feishu-docs login", {
|
|
84
|
+
recovery: "运行 feishu-docs login 重新认证",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return { authInfo };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Resolve the API base URL based on whether we're using Lark or Feishu.
|
|
93
|
+
*/
|
|
94
|
+
export function getApiBase(authInfo) {
|
|
95
|
+
return authInfo.useLark ? LARK_BASE : FEISHU_BASE;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get tenant_access_token for tenant mode API calls.
|
|
99
|
+
*/
|
|
100
|
+
export async function getTenantToken(authInfo) {
|
|
101
|
+
const res = await fetch(`${getApiBase(authInfo)}/open-apis/auth/v3/tenant_access_token/internal`, {
|
|
102
|
+
method: "POST",
|
|
103
|
+
headers: { "Content-Type": "application/json" },
|
|
104
|
+
body: JSON.stringify({
|
|
105
|
+
app_id: authInfo.appId,
|
|
106
|
+
app_secret: authInfo.appSecret,
|
|
107
|
+
}),
|
|
108
|
+
});
|
|
109
|
+
const body = (await res.json());
|
|
110
|
+
if (body.code !== 0) {
|
|
111
|
+
throw new CliError("AUTH_REQUIRED", `获取 tenant_access_token 失败: ${body.msg}`, {
|
|
112
|
+
apiCode: body.code,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
if (!body.tenant_access_token) {
|
|
116
|
+
throw new CliError("AUTH_REQUIRED", "获取 tenant_access_token 失败: API 返回空值");
|
|
117
|
+
}
|
|
118
|
+
return body.tenant_access_token;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Build Authorization header value for any auth mode.
|
|
122
|
+
*/
|
|
123
|
+
async function resolveBearer(authInfo) {
|
|
124
|
+
if (authInfo.mode === "user" && authInfo.userToken) {
|
|
125
|
+
return `Bearer ${authInfo.userToken}`;
|
|
126
|
+
}
|
|
127
|
+
if (authInfo.tenantToken) {
|
|
128
|
+
return `Bearer ${authInfo.tenantToken}`;
|
|
129
|
+
}
|
|
130
|
+
const tenantToken = await getTenantToken(authInfo);
|
|
131
|
+
return `Bearer ${tenantToken}`;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Direct fetch wrapper that correctly passes user/tenant token.
|
|
135
|
+
*/
|
|
136
|
+
export async function fetchWithAuth(authInfo, path, options = {}) {
|
|
137
|
+
const base = getApiBase(authInfo);
|
|
138
|
+
const bearer = await resolveBearer(authInfo);
|
|
139
|
+
const url = new URL(path, base);
|
|
140
|
+
if (options.params) {
|
|
141
|
+
for (const [key, value] of Object.entries(options.params)) {
|
|
142
|
+
if (value === undefined || value === null)
|
|
143
|
+
continue;
|
|
144
|
+
if (Array.isArray(value)) {
|
|
145
|
+
for (const item of value) {
|
|
146
|
+
url.searchParams.append(key, String(item));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
url.searchParams.set(key, String(value));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const fetchOpts = {
|
|
155
|
+
method: options.method || "GET",
|
|
156
|
+
headers: {
|
|
157
|
+
"Content-Type": "application/json",
|
|
158
|
+
...options.headers,
|
|
159
|
+
Authorization: bearer,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
if (options.body) {
|
|
163
|
+
fetchOpts.body = JSON.stringify(options.body);
|
|
164
|
+
}
|
|
165
|
+
const controller = new AbortController();
|
|
166
|
+
const timeoutId = setTimeout(() => controller.abort(), 30_000);
|
|
167
|
+
let res;
|
|
168
|
+
try {
|
|
169
|
+
res = await fetch(url.toString(), {
|
|
170
|
+
...fetchOpts,
|
|
171
|
+
signal: controller.signal,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
const error = err;
|
|
176
|
+
if (error.name === "AbortError") {
|
|
177
|
+
throw new CliError("API_ERROR", "API 请求超时(30秒)", {
|
|
178
|
+
retryable: true,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
throw err;
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
clearTimeout(timeoutId);
|
|
185
|
+
}
|
|
186
|
+
const body = (await res.json());
|
|
187
|
+
if (body.code !== undefined && body.code !== 0) {
|
|
188
|
+
// Scope errors: extract missing scopes from permission_violations
|
|
189
|
+
if (body.code === 99991672 || body.code === 99991679) {
|
|
190
|
+
const scopes = extractScopesFromError(body);
|
|
191
|
+
const scopeStr = scopes.length > 0 ? scopes.join(" ") : "";
|
|
192
|
+
const hint = scopes.length > 0
|
|
193
|
+
? `缺少以下权限: ${scopes.join(", ")}。运行: feishu-docs authorize --scope "${scopeStr}"`
|
|
194
|
+
: body.msg || "权限不足";
|
|
195
|
+
throw new CliError("SCOPE_MISSING", hint, {
|
|
196
|
+
apiCode: body.code,
|
|
197
|
+
missingScopes: scopes,
|
|
198
|
+
recovery: scopes.length > 0
|
|
199
|
+
? `feishu-docs authorize --scope "${scopeStr}"`
|
|
200
|
+
: "检查飞书开发者后台的应用权限配置",
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
throw mapApiError({ code: body.code, msg: body.msg });
|
|
204
|
+
}
|
|
205
|
+
return body;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Extract scope names from Feishu API error response.
|
|
209
|
+
*
|
|
210
|
+
* Newer APIs include `error.permission_violations[].subject` with exact scope names.
|
|
211
|
+
* Older APIs may omit this field entirely — returns empty array in that case.
|
|
212
|
+
*/
|
|
213
|
+
function extractScopesFromError(body) {
|
|
214
|
+
const error = body.error;
|
|
215
|
+
const violations = error?.permission_violations;
|
|
216
|
+
if (!Array.isArray(violations))
|
|
217
|
+
return [];
|
|
218
|
+
return violations
|
|
219
|
+
.map((v) => v.subject)
|
|
220
|
+
.filter((s) => typeof s === "string" && s.length > 0);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Fetch binary data with auth (for APIs that return file streams).
|
|
224
|
+
*/
|
|
225
|
+
export async function fetchBinaryWithAuth(authInfo, path) {
|
|
226
|
+
const base = getApiBase(authInfo);
|
|
227
|
+
const bearer = await resolveBearer(authInfo);
|
|
228
|
+
const url = new URL(path, base);
|
|
229
|
+
const controller = new AbortController();
|
|
230
|
+
const timeoutId = setTimeout(() => controller.abort(), 60_000);
|
|
231
|
+
let res;
|
|
232
|
+
try {
|
|
233
|
+
res = await fetch(url.toString(), {
|
|
234
|
+
method: "GET",
|
|
235
|
+
headers: { Authorization: bearer },
|
|
236
|
+
signal: controller.signal,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
const error = err;
|
|
241
|
+
if (error.name === "AbortError") {
|
|
242
|
+
throw new CliError("API_ERROR", "API 请求超时(60秒)", {
|
|
243
|
+
retryable: true,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
throw err;
|
|
247
|
+
}
|
|
248
|
+
finally {
|
|
249
|
+
clearTimeout(timeoutId);
|
|
250
|
+
}
|
|
251
|
+
if (!res.ok) {
|
|
252
|
+
throw new CliError("API_ERROR", `下载失败: HTTP ${res.status} ${res.statusText}`);
|
|
253
|
+
}
|
|
254
|
+
return res.arrayBuffer();
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* authorize command: Request additional OAuth scopes on-demand.
|
|
3
|
+
*
|
|
4
|
+
* Reads currently stored scopes, merges with the requested ones, and
|
|
5
|
+
* re-runs the OAuth flow so the user grants only what is needed.
|
|
6
|
+
*
|
|
7
|
+
* Scopes to request typically come from API error messages — when a command
|
|
8
|
+
* fails with SCOPE_MISSING, the error includes the exact scope names needed.
|
|
9
|
+
*/
|
|
10
|
+
import { CommandMeta, CommandArgs, GlobalOpts } from "../types/index.js";
|
|
11
|
+
export declare const meta: CommandMeta;
|
|
12
|
+
export declare function authorize(args: CommandArgs, globalOpts: GlobalOpts): Promise<void>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* authorize command: Request additional OAuth scopes on-demand.
|
|
3
|
+
*
|
|
4
|
+
* Reads currently stored scopes, merges with the requested ones, and
|
|
5
|
+
* re-runs the OAuth flow so the user grants only what is needed.
|
|
6
|
+
*
|
|
7
|
+
* Scopes to request typically come from API error messages — when a command
|
|
8
|
+
* fails with SCOPE_MISSING, the error includes the exact scope names needed.
|
|
9
|
+
*/
|
|
10
|
+
import { oauthLogin, loadTokens } from "../auth.js";
|
|
11
|
+
import { CliError } from "../utils/errors.js";
|
|
12
|
+
import { BASE_SCOPES, mergeScopes } from "../scopes.js";
|
|
13
|
+
/** Feishu scope tokens follow the pattern: word:word or word:word:word */
|
|
14
|
+
const SCOPE_TOKEN_RE = /^\w[\w-]*:[\w.:/-]+$/;
|
|
15
|
+
export const meta = {
|
|
16
|
+
options: {
|
|
17
|
+
scope: { type: "string" },
|
|
18
|
+
port: { type: "string" },
|
|
19
|
+
"redirect-uri": { type: "string" },
|
|
20
|
+
},
|
|
21
|
+
positionals: false,
|
|
22
|
+
handler: authorize,
|
|
23
|
+
};
|
|
24
|
+
export async function authorize(args, globalOpts) {
|
|
25
|
+
const appId = process.env.FEISHU_APP_ID;
|
|
26
|
+
const appSecret = process.env.FEISHU_APP_SECRET;
|
|
27
|
+
if (!appId || !appSecret) {
|
|
28
|
+
throw new CliError("AUTH_REQUIRED", "请先设置 FEISHU_APP_ID 和 FEISHU_APP_SECRET 环境变量");
|
|
29
|
+
}
|
|
30
|
+
if (!args.scope) {
|
|
31
|
+
throw new CliError("INVALID_ARGS", `请指定 --scope 参数。\n\n` +
|
|
32
|
+
`示例:\n` +
|
|
33
|
+
` feishu-docs authorize --scope "drive:drive"\n` +
|
|
34
|
+
` feishu-docs authorize --scope "drive:drive contact:contact.base:readonly"\n\n` +
|
|
35
|
+
`提示: 当命令因权限不足失败时,错误信息中会包含所需的 scope 名称。`);
|
|
36
|
+
}
|
|
37
|
+
// Parse and validate scopes
|
|
38
|
+
const rawScopes = args.scope.split(/\s+/).filter(Boolean);
|
|
39
|
+
const extraScopes = [];
|
|
40
|
+
for (const s of rawScopes) {
|
|
41
|
+
if (!SCOPE_TOKEN_RE.test(s)) {
|
|
42
|
+
throw new CliError("INVALID_ARGS", `无效的 scope 格式: "${s}"。scope 应为 "namespace:resource" 或 "namespace:resource:action" 格式`);
|
|
43
|
+
}
|
|
44
|
+
extraScopes.push(s);
|
|
45
|
+
}
|
|
46
|
+
if (extraScopes.length === 0) {
|
|
47
|
+
throw new CliError("INVALID_ARGS", "未指定任何有效的 scope,操作已取消");
|
|
48
|
+
}
|
|
49
|
+
// Merge with currently stored scopes (so we don't lose existing grants).
|
|
50
|
+
const stored = await loadTokens();
|
|
51
|
+
const currentScopes = stored?.tokens?.scope
|
|
52
|
+
? stored.tokens.scope.split(/\s+/).filter(Boolean)
|
|
53
|
+
: BASE_SCOPES;
|
|
54
|
+
const merged = mergeScopes(currentScopes, extraScopes);
|
|
55
|
+
const scopeStr = merged.join(" ");
|
|
56
|
+
process.stderr.write(`\n即将申请以下权限(包含已有权限):\n ${scopeStr}\n\n`);
|
|
57
|
+
const tokens = await oauthLogin(appId, {
|
|
58
|
+
scope: scopeStr,
|
|
59
|
+
appSecret,
|
|
60
|
+
port: args.port,
|
|
61
|
+
redirectUri: args.redirectUri,
|
|
62
|
+
useLark: globalOpts.lark,
|
|
63
|
+
});
|
|
64
|
+
process.stderr.write("feishu-docs: 授权成功!token 已更新。\n");
|
|
65
|
+
if (globalOpts.json) {
|
|
66
|
+
process.stdout.write(JSON.stringify({
|
|
67
|
+
success: true,
|
|
68
|
+
scope: scopeStr,
|
|
69
|
+
expires_at: tokens.expires_at,
|
|
70
|
+
}) + "\n");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=authorize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorize.js","sourceRoot":"","sources":["../../src/commands/authorize.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGxD,0EAA0E;AAC1E,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAE9C,MAAM,CAAC,MAAM,IAAI,GAAgB;IAC/B,OAAO,EAAE;QACP,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACzB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KACnC;IACD,WAAW,EAAE,KAAK;IAClB,OAAO,EAAE,SAAS;CACnB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,IAAiB,EACjB,UAAsB;IAEtB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IACxC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAEhD,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,QAAQ,CAChB,eAAe,EACf,6CAA6C,CAC9C,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,QAAQ,CAChB,cAAc,EACd,qBAAqB;YACnB,OAAO;YACP,iDAAiD;YACjD,iFAAiF;YACjF,uCAAuC,CAC1C,CAAC;IACJ,CAAC;IAED,4BAA4B;IAC5B,MAAM,SAAS,GAAI,IAAI,CAAC,KAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACtE,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,QAAQ,CAChB,cAAc,EACd,kBAAkB,CAAC,kEAAkE,CACtF,CAAC;QACJ,CAAC;QACD,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,QAAQ,CAAC,cAAc,EAAE,sBAAsB,CAAC,CAAC;IAC7D,CAAC;IAED,yEAAyE;IACzE,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,aAAa,GAAG,MAAM,EAAE,MAAM,EAAE,KAAK;QACzC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QAClD,CAAC,CAAC,WAAW,CAAC;IAEhB,MAAM,MAAM,GAAG,WAAW,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAElC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,0BAA0B,QAAQ,MAAM,CACzC,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE;QACrC,KAAK,EAAE,QAAQ;QACf,SAAS;QACT,IAAI,EAAE,IAAI,CAAC,IAA0B;QACrC,WAAW,EAAE,IAAI,CAAC,WAAiC;QACnD,OAAO,EAAE,UAAU,CAAC,IAAI;KACzB,CAAC,CAAC;IAEH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACvD,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;QACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC;YACb,OAAO,EAAE,IAAI;YACb,KAAK,EAAE,QAAQ;YACf,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC,GAAG,IAAI,CACV,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cat command: Recursively read all documents under a knowledge base node.
|
|
3
|
+
*/
|
|
4
|
+
import { CommandMeta, CommandArgs, GlobalOpts } from "../types/index.js";
|
|
5
|
+
export declare const meta: CommandMeta;
|
|
6
|
+
export declare function cat(args: CommandArgs, globalOpts: GlobalOpts): Promise<void>;
|