docz-cli 0.1.0

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 ADDED
@@ -0,0 +1,118 @@
1
+ # docz-cli
2
+
3
+ DocSync 命令行工具 — 在终端读写公司文档。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ pnpm install && pnpm build
9
+ ```
10
+
11
+ 全局使用:
12
+
13
+ ```bash
14
+ npm link
15
+ # 或直接
16
+ alias docz="node /path/to/docz-cli/dist/index.js"
17
+ ```
18
+
19
+ ## 配置
20
+
21
+ 两种方式任选:
22
+
23
+ ```bash
24
+ # 方式一:环境变量
25
+ export DOCSYNC_API_TOKEN=<your-token>
26
+
27
+ # 方式二:login 命令(保存到 ~/.docz/config.json)
28
+ docz login --token <your-token>
29
+ ```
30
+
31
+ Token 获取方式:
32
+
33
+ 1. 登录 https://docz.zhenguanyu.com(SSO 自动登录)
34
+ 2. 点击左下角用户邮箱旁的 **`···`** 按钮,或直接访问 https://docz.zhenguanyu.com/settings
35
+ 3. 在 **Settings → Account** 页面找到 **API Tokens** 区域
36
+ 4. 点击 **New Token**,输入名称(如 `my-cli`),确认创建
37
+ 5. 复制生成的 token(只会显示一次)
38
+
39
+ ## 使用
40
+
41
+ 所有命令的寻址格式统一为 `<space>:<path>`,Space 支持名称或 ID。
42
+
43
+ ### 浏览
44
+
45
+ ```bash
46
+ docz spaces # 列出所有 Space
47
+ docz ls 研发 # 列出根目录
48
+ docz ls 研发:docs # 列出子目录
49
+ docz cat 研发:docs/guide.md # 读取文件内容
50
+ ```
51
+
52
+ ### 写入
53
+
54
+ ```bash
55
+ # 直接写内容
56
+ docz write 吴鹏飞:notes/todo.md '# TODO List'
57
+
58
+ # 从 stdin 写入
59
+ echo '# Generated Report' | docz write 吴鹏飞:reports/daily.md -
60
+
61
+ # 上传本地文件
62
+ docz upload ./report.pdf 研发:reports
63
+
64
+ # 创建文件夹
65
+ docz mkdir 研发:new-project
66
+ ```
67
+
68
+ ### 管理
69
+
70
+ ```bash
71
+ docz mv 研发:old-name.md new-name.md # 重命名/移动
72
+ docz rm 研发:deprecated.md # 删除(30 天内可从回收站恢复)
73
+ docz log 研发 # Space 操作历史
74
+ docz log 研发:docs/guide.md # 单文件变更历史
75
+ docz trash 研发 # 查看回收站
76
+ ```
77
+
78
+ ### 其他
79
+
80
+ ```bash
81
+ docz whoami # 当前登录用户
82
+ docz --help # 完整帮助
83
+ docz ls --help # 单命令帮助
84
+ ```
85
+
86
+ ## 在 AI Agent 中使用
87
+
88
+ docz-cli 设计为终端原生工具,任何能执行 shell 命令的 AI Agent 都能直接调用:
89
+
90
+ ```
91
+ 用户:帮我看看研发 Space 里有什么文档
92
+ Agent:执行 docz ls 研发
93
+ Agent:研发 Space 下有 3 个文件...
94
+
95
+ 用户:把这份分析报告上传到我的 Space
96
+ Agent:执行 docz write 吴鹏飞:reports/analysis.md '<内容>'
97
+ Agent:已上传到 reports/analysis.md
98
+ ```
99
+
100
+ 环境变量 `DOCSYNC_API_TOKEN` 配置好后,Agent 的 Bash 工具可以直接使用所有命令。
101
+
102
+ ## DocSync API
103
+
104
+ docz-cli 封装了以下 DocSync REST API:
105
+
106
+ | 命令 | API |
107
+ |------|-----|
108
+ | `spaces` | `GET /api/spaces` |
109
+ | `ls` | `GET /api/spaces/{id}/tree?path=` |
110
+ | `cat` | `GET /api/spaces/{id}/blob/{path}` |
111
+ | `upload` / `write` | `POST /api/spaces/{id}/files/upload` (FormData) |
112
+ | `mkdir` | `POST /api/spaces/{id}/files/mkdir` |
113
+ | `rm` | `POST /api/spaces/{id}/files/delete` |
114
+ | `mv` | `POST /api/spaces/{id}/files/rename` |
115
+ | `log` | `GET /api/spaces/{id}/log/[{path}]` |
116
+ | `trash` | `GET /api/spaces/{id}/trash` |
117
+
118
+ 认证统一使用 `Authorization: Bearer <token>`。DocSync 底层基于 Git,所有写操作自动产生 commit,天然有版本历史。
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,341 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/commands.ts
7
+ import { readFileSync as readFileSync2 } from "fs";
8
+ import { basename, dirname } from "path";
9
+
10
+ // src/client.ts
11
+ var DocSyncClient = class {
12
+ constructor(baseUrl, token) {
13
+ this.baseUrl = baseUrl;
14
+ this.token = token;
15
+ this.baseUrl = baseUrl.replace(/\/$/, "");
16
+ }
17
+ async request(path, init) {
18
+ const res = await fetch(`${this.baseUrl}${path}`, {
19
+ ...init,
20
+ headers: {
21
+ Authorization: `Bearer ${this.token}`,
22
+ ...init?.headers
23
+ }
24
+ });
25
+ if (!res.ok) {
26
+ const body = await res.text().catch(() => "");
27
+ throw new Error(`${res.status} ${res.statusText}: ${body}`.trim());
28
+ }
29
+ const ct = res.headers.get("content-type") ?? "";
30
+ if (ct.includes("application/json")) return res.json();
31
+ return res.text();
32
+ }
33
+ // --- Auth ---
34
+ async me() {
35
+ return this.request("/api/auth/me");
36
+ }
37
+ // --- Spaces ---
38
+ async listSpaces() {
39
+ return this.request("/api/spaces");
40
+ }
41
+ async resolveSpace(nameOrId) {
42
+ const spaces = await this.listSpaces();
43
+ const s = spaces.find(
44
+ (s2) => s2.id === nameOrId || s2.name === nameOrId || s2.name.toLowerCase() === nameOrId.toLowerCase()
45
+ );
46
+ if (!s) {
47
+ const available = spaces.map((s2) => s2.name).join(", ");
48
+ throw new Error(`Space "${nameOrId}" not found. Available: ${available}`);
49
+ }
50
+ return s;
51
+ }
52
+ // --- Tree ---
53
+ async ls(spaceId, path = "") {
54
+ return this.request(
55
+ `/api/spaces/${spaceId}/tree?path=${encodeURIComponent(path)}`
56
+ );
57
+ }
58
+ // --- Blob ---
59
+ async cat(spaceId, filepath) {
60
+ return this.request(
61
+ `/api/spaces/${spaceId}/blob/${encodeURIComponent(filepath)}`
62
+ );
63
+ }
64
+ // --- Write ---
65
+ async upload(spaceId, dir, filename, content) {
66
+ const blob = typeof content === "string" ? new Blob([content], { type: "application/octet-stream" }) : new Blob([content], { type: "application/octet-stream" });
67
+ const form = new FormData();
68
+ form.append("file", blob, filename);
69
+ form.append("path", dir);
70
+ return this.request(`/api/spaces/${spaceId}/files/upload`, {
71
+ method: "POST",
72
+ body: form
73
+ });
74
+ }
75
+ async mkdir(spaceId, path) {
76
+ await this.request(`/api/spaces/${spaceId}/files/mkdir`, {
77
+ method: "POST",
78
+ headers: { "Content-Type": "application/json" },
79
+ body: JSON.stringify({ path })
80
+ });
81
+ }
82
+ async rm(spaceId, path) {
83
+ await this.request(`/api/spaces/${spaceId}/files/delete`, {
84
+ method: "POST",
85
+ headers: { "Content-Type": "application/json" },
86
+ body: JSON.stringify({ path })
87
+ });
88
+ }
89
+ async mv(spaceId, from, to) {
90
+ await this.request(`/api/spaces/${spaceId}/files/rename`, {
91
+ method: "POST",
92
+ headers: { "Content-Type": "application/json" },
93
+ body: JSON.stringify({ old_path: from, new_path: to })
94
+ });
95
+ }
96
+ // --- History ---
97
+ async log(spaceId, filepath) {
98
+ const path = filepath ? `/api/spaces/${spaceId}/log/${encodeURIComponent(filepath)}` : `/api/spaces/${spaceId}/log/`;
99
+ return this.request(path);
100
+ }
101
+ // --- Trash ---
102
+ async trash(spaceId) {
103
+ return this.request(`/api/spaces/${spaceId}/trash`);
104
+ }
105
+ };
106
+
107
+ // src/config.ts
108
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
109
+ import { homedir } from "os";
110
+ import { join } from "path";
111
+ var CONFIG_DIR = join(homedir(), ".docz");
112
+ var CONFIG_FILE = join(CONFIG_DIR, "config.json");
113
+ function readConfig() {
114
+ if (!existsSync(CONFIG_FILE)) return {};
115
+ try {
116
+ return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
117
+ } catch {
118
+ return {};
119
+ }
120
+ }
121
+ function writeConfig(config) {
122
+ mkdirSync(CONFIG_DIR, { recursive: true });
123
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
124
+ }
125
+ function getBaseUrl() {
126
+ return process.env.DOCSYNC_BASE_URL ?? readConfig().base_url ?? "https://docz.zhenguanyu.com";
127
+ }
128
+ function getToken() {
129
+ return process.env.DOCSYNC_API_TOKEN ?? readConfig().token;
130
+ }
131
+ function saveConfig(baseUrl, token) {
132
+ writeConfig({ base_url: baseUrl, token });
133
+ }
134
+ function getConfigPath() {
135
+ return CONFIG_FILE;
136
+ }
137
+
138
+ // src/commands.ts
139
+ function getClient() {
140
+ const token = getToken();
141
+ if (!token) {
142
+ console.error(
143
+ "Error: No token configured.\nRun `docz login` or set DOCSYNC_API_TOKEN environment variable."
144
+ );
145
+ process.exit(1);
146
+ }
147
+ return new DocSyncClient(getBaseUrl(), token);
148
+ }
149
+ function parseTarget(args) {
150
+ if (args.length === 0) {
151
+ console.error(
152
+ "Error: space is required. Usage: docz <cmd> <space>[:<path>]"
153
+ );
154
+ process.exit(1);
155
+ }
156
+ const first = args[0];
157
+ if (first.includes(":")) {
158
+ const [space, ...rest] = first.split(":");
159
+ return { space, path: rest.join(":") };
160
+ }
161
+ return { space: first, path: args.slice(1).join(" ") };
162
+ }
163
+ function formatSize(bytes) {
164
+ if (bytes < 1024) return `${bytes} B`;
165
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
166
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
167
+ }
168
+ function registerCommands(program2) {
169
+ program2.command("login").description("Configure DocSync credentials").option("-u, --url <url>", "DocSync server URL").option("-t, --token <token>", "API token").action(async (opts) => {
170
+ const url = opts.url ?? getBaseUrl();
171
+ const token = opts.token;
172
+ if (!token) {
173
+ console.error(
174
+ "Error: --token is required.\nGet one at: " + url + " \u2192 Settings \u2192 API Tokens"
175
+ );
176
+ process.exit(1);
177
+ }
178
+ const client = new DocSyncClient(url, token);
179
+ try {
180
+ const user = await client.me();
181
+ saveConfig(url, token);
182
+ console.log(`Logged in as ${user.name} (${user.email})`);
183
+ console.log(`Config saved to ${getConfigPath()}`);
184
+ } catch (err) {
185
+ console.error(
186
+ `Error: ${err instanceof Error ? err.message : String(err)}`
187
+ );
188
+ process.exit(1);
189
+ }
190
+ });
191
+ program2.command("whoami").description("Show current user").action(async () => {
192
+ const client = getClient();
193
+ const user = await client.me();
194
+ console.log(`${user.name} (${user.email})`);
195
+ });
196
+ program2.command("spaces").description("List all accessible spaces").action(async () => {
197
+ const client = getClient();
198
+ const spaces = await client.listSpaces();
199
+ for (const s of spaces) {
200
+ const tag = s.is_private ? "private" : "team";
201
+ console.log(`${s.name} ${tag} ${s.member_count} members ${s.id}`);
202
+ }
203
+ });
204
+ program2.command("ls").description("List files \u2014 docz ls <space>[:<path>]").argument("<target...>").action(async (args) => {
205
+ const { space, path } = parseTarget(args);
206
+ const client = getClient();
207
+ const s = await client.resolveSpace(space);
208
+ const entries = await client.ls(s.id, path);
209
+ if (entries.length === 0) {
210
+ console.log("(empty)");
211
+ return;
212
+ }
213
+ for (const e of entries) {
214
+ if (e.type === "tree") {
215
+ console.log(`${e.name}/`);
216
+ } else {
217
+ console.log(`${e.name} ${formatSize(e.size)}`);
218
+ }
219
+ }
220
+ });
221
+ program2.command("cat").description("Read file content \u2014 docz cat <space>:<path>").argument("<target...>").action(async (args) => {
222
+ const { space, path } = parseTarget(args);
223
+ if (!path) {
224
+ console.error(
225
+ "Error: file path is required. Usage: docz cat <space>:<path>"
226
+ );
227
+ process.exit(1);
228
+ }
229
+ const client = getClient();
230
+ const s = await client.resolveSpace(space);
231
+ const content = await client.cat(s.id, path);
232
+ process.stdout.write(content);
233
+ });
234
+ program2.command("upload").description("Upload file \u2014 docz upload <local-file> <space>[:<dir>]").argument("<file>", "Local file to upload").argument("<target...>").action(async (file, args) => {
235
+ const { space, path: dir } = parseTarget(args);
236
+ const client = getClient();
237
+ const s = await client.resolveSpace(space);
238
+ const content = readFileSync2(file);
239
+ const filename = basename(file);
240
+ const targetDir = dir || "";
241
+ const result = await client.upload(s.id, targetDir, filename, content);
242
+ console.log(`Uploaded: ${result.path}`);
243
+ });
244
+ program2.command("write").description("Write content to file \u2014 docz write <space>:<path> <content>").argument("<target>", "space:dir/filename.md").argument("<content>", "File content (or - for stdin)").action(async (target, content) => {
245
+ const { space, path } = parseTarget([target]);
246
+ if (!path) {
247
+ console.error(
248
+ "Error: path is required. Usage: docz write <space>:<dir/filename> <content>"
249
+ );
250
+ process.exit(1);
251
+ }
252
+ const client = getClient();
253
+ const s = await client.resolveSpace(space);
254
+ const filename = basename(path);
255
+ const dir = dirname(path);
256
+ let body;
257
+ if (content === "-") {
258
+ const chunks = [];
259
+ for await (const chunk of process.stdin) {
260
+ chunks.push(chunk);
261
+ }
262
+ body = Buffer.concat(chunks).toString("utf-8");
263
+ } else {
264
+ body = content;
265
+ }
266
+ const result = await client.upload(
267
+ s.id,
268
+ dir === "." ? "" : dir,
269
+ filename,
270
+ body
271
+ );
272
+ console.log(`Written: ${result.path}`);
273
+ });
274
+ program2.command("mkdir").description("Create folder \u2014 docz mkdir <space>:<path>").argument("<target...>").action(async (args) => {
275
+ const { space, path } = parseTarget(args);
276
+ if (!path) {
277
+ console.error("Error: path is required.");
278
+ process.exit(1);
279
+ }
280
+ const client = getClient();
281
+ const s = await client.resolveSpace(space);
282
+ await client.mkdir(s.id, path);
283
+ console.log(`Created: ${path}`);
284
+ });
285
+ program2.command("rm").description("Delete file/folder \u2014 docz rm <space>:<path>").argument("<target...>").action(async (args) => {
286
+ const { space, path } = parseTarget(args);
287
+ if (!path) {
288
+ console.error("Error: path is required.");
289
+ process.exit(1);
290
+ }
291
+ const client = getClient();
292
+ const s = await client.resolveSpace(space);
293
+ await client.rm(s.id, path);
294
+ console.log(`Deleted: ${path} (recoverable from trash for 30 days)`);
295
+ });
296
+ program2.command("mv").description("Rename/move \u2014 docz mv <space>:<from> <to>").argument("<target>", "space:old-path").argument("<to>", "new-path").action(async (target, to) => {
297
+ const { space, path: from } = parseTarget([target]);
298
+ if (!from) {
299
+ console.error("Error: source path is required.");
300
+ process.exit(1);
301
+ }
302
+ const client = getClient();
303
+ const s = await client.resolveSpace(space);
304
+ await client.mv(s.id, from, to);
305
+ console.log(`Moved: ${from} \u2192 ${to}`);
306
+ });
307
+ program2.command("log").description("Show change history \u2014 docz log <space>[:<path>]").argument("<target...>").action(async (args) => {
308
+ const { space, path } = parseTarget(args);
309
+ const client = getClient();
310
+ const s = await client.resolveSpace(space);
311
+ const logs = await client.log(s.id, path || void 0);
312
+ if (logs.length === 0) {
313
+ console.log("No history.");
314
+ return;
315
+ }
316
+ for (const l of logs) {
317
+ console.log(`${l.hash.substring(0, 7)} ${l.date} ${l.message}`);
318
+ }
319
+ });
320
+ program2.command("trash").description("Show deleted files \u2014 docz trash <space>").argument("<space>").action(async (spaceName) => {
321
+ const client = getClient();
322
+ const s = await client.resolveSpace(spaceName);
323
+ const items = await client.trash(s.id);
324
+ if (items.length === 0) {
325
+ console.log("Trash is empty.");
326
+ return;
327
+ }
328
+ for (const t of items) {
329
+ console.log(
330
+ `${t.path} deleted ${t.deleted_at} ${t.commit.substring(0, 7)}`
331
+ );
332
+ }
333
+ });
334
+ }
335
+
336
+ // src/index.ts
337
+ var program = new Command();
338
+ program.name("docz").description("DocSync CLI \u2014 read and write company documents").version("0.1.0");
339
+ registerCommands(program);
340
+ program.parse();
341
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/commands.ts","../src/client.ts","../src/config.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { registerCommands } from './commands.js';\n\nconst program = new Command();\n\nprogram\n .name('docz')\n .description('DocSync CLI — read and write company documents')\n .version('0.1.0');\n\nregisterCommands(program);\n\nprogram.parse();\n","/**\n * CLI Commands\n */\n\nimport { readFileSync } from 'node:fs';\nimport { basename, dirname } from 'node:path';\nimport type { Command } from 'commander';\nimport { DocSyncClient } from './client.js';\nimport { getBaseUrl, getConfigPath, getToken, saveConfig } from './config.js';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getClient(): DocSyncClient {\n const token = getToken();\n if (!token) {\n console.error(\n 'Error: No token configured.\\n' +\n 'Run `docz login` or set DOCSYNC_API_TOKEN environment variable.'\n );\n process.exit(1);\n }\n return new DocSyncClient(getBaseUrl(), token);\n}\n\n/** Parse \"space:path\" or \"space path\" format */\nfunction parseTarget(args: string[]): { space: string; path: string } {\n if (args.length === 0) {\n console.error(\n 'Error: space is required. Usage: docz <cmd> <space>[:<path>]'\n );\n process.exit(1);\n }\n const first = args[0];\n if (first.includes(':')) {\n const [space, ...rest] = first.split(':');\n return { space, path: rest.join(':') };\n }\n return { space: first, path: args.slice(1).join(' ') };\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n// ---------------------------------------------------------------------------\n// Commands\n// ---------------------------------------------------------------------------\n\nexport function registerCommands(program: Command): void {\n // --- login ---\n program\n .command('login')\n .description('Configure DocSync credentials')\n .option('-u, --url <url>', 'DocSync server URL')\n .option('-t, --token <token>', 'API token')\n .action(async (opts) => {\n const url = opts.url ?? getBaseUrl();\n const token = opts.token;\n if (!token) {\n console.error(\n 'Error: --token is required.\\n' +\n 'Get one at: ' +\n url +\n ' → Settings → API Tokens'\n );\n process.exit(1);\n }\n // Verify token\n const client = new DocSyncClient(url, token);\n try {\n const user = await client.me();\n saveConfig(url, token);\n console.log(`Logged in as ${user.name} (${user.email})`);\n console.log(`Config saved to ${getConfigPath()}`);\n } catch (err) {\n console.error(\n `Error: ${err instanceof Error ? err.message : String(err)}`\n );\n process.exit(1);\n }\n });\n\n // --- whoami ---\n program\n .command('whoami')\n .description('Show current user')\n .action(async () => {\n const client = getClient();\n const user = await client.me();\n console.log(`${user.name} (${user.email})`);\n });\n\n // --- spaces ---\n program\n .command('spaces')\n .description('List all accessible spaces')\n .action(async () => {\n const client = getClient();\n const spaces = await client.listSpaces();\n for (const s of spaces) {\n const tag = s.is_private ? 'private' : 'team';\n console.log(`${s.name}\\t${tag}\\t${s.member_count} members\\t${s.id}`);\n }\n });\n\n // --- ls ---\n program\n .command('ls')\n .description('List files — docz ls <space>[:<path>]')\n .argument('<target...>')\n .action(async (args: string[]) => {\n const { space, path } = parseTarget(args);\n const client = getClient();\n const s = await client.resolveSpace(space);\n const entries = await client.ls(s.id, path);\n if (entries.length === 0) {\n console.log('(empty)');\n return;\n }\n for (const e of entries) {\n if (e.type === 'tree') {\n console.log(`${e.name}/`);\n } else {\n console.log(`${e.name}\\t${formatSize(e.size)}`);\n }\n }\n });\n\n // --- cat ---\n program\n .command('cat')\n .description('Read file content — docz cat <space>:<path>')\n .argument('<target...>')\n .action(async (args: string[]) => {\n const { space, path } = parseTarget(args);\n if (!path) {\n console.error(\n 'Error: file path is required. Usage: docz cat <space>:<path>'\n );\n process.exit(1);\n }\n const client = getClient();\n const s = await client.resolveSpace(space);\n const content = await client.cat(s.id, path);\n process.stdout.write(content);\n });\n\n // --- upload ---\n program\n .command('upload')\n .description('Upload file — docz upload <local-file> <space>[:<dir>]')\n .argument('<file>', 'Local file to upload')\n .argument('<target...>')\n .action(async (file: string, args: string[]) => {\n const { space, path: dir } = parseTarget(args);\n const client = getClient();\n const s = await client.resolveSpace(space);\n const content = readFileSync(file);\n const filename = basename(file);\n const targetDir = dir || '';\n const result = await client.upload(s.id, targetDir, filename, content);\n console.log(`Uploaded: ${result.path}`);\n });\n\n // --- write ---\n program\n .command('write')\n .description('Write content to file — docz write <space>:<path> <content>')\n .argument('<target>', 'space:dir/filename.md')\n .argument('<content>', 'File content (or - for stdin)')\n .action(async (target: string, content: string) => {\n const { space, path } = parseTarget([target]);\n if (!path) {\n console.error(\n 'Error: path is required. Usage: docz write <space>:<dir/filename> <content>'\n );\n process.exit(1);\n }\n const client = getClient();\n const s = await client.resolveSpace(space);\n const filename = basename(path);\n const dir = dirname(path);\n let body: string;\n if (content === '-') {\n // Read from stdin\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n body = Buffer.concat(chunks).toString('utf-8');\n } else {\n body = content;\n }\n const result = await client.upload(\n s.id,\n dir === '.' ? '' : dir,\n filename,\n body\n );\n console.log(`Written: ${result.path}`);\n });\n\n // --- mkdir ---\n program\n .command('mkdir')\n .description('Create folder — docz mkdir <space>:<path>')\n .argument('<target...>')\n .action(async (args: string[]) => {\n const { space, path } = parseTarget(args);\n if (!path) {\n console.error('Error: path is required.');\n process.exit(1);\n }\n const client = getClient();\n const s = await client.resolveSpace(space);\n await client.mkdir(s.id, path);\n console.log(`Created: ${path}`);\n });\n\n // --- rm ---\n program\n .command('rm')\n .description('Delete file/folder — docz rm <space>:<path>')\n .argument('<target...>')\n .action(async (args: string[]) => {\n const { space, path } = parseTarget(args);\n if (!path) {\n console.error('Error: path is required.');\n process.exit(1);\n }\n const client = getClient();\n const s = await client.resolveSpace(space);\n await client.rm(s.id, path);\n console.log(`Deleted: ${path} (recoverable from trash for 30 days)`);\n });\n\n // --- mv ---\n program\n .command('mv')\n .description('Rename/move — docz mv <space>:<from> <to>')\n .argument('<target>', 'space:old-path')\n .argument('<to>', 'new-path')\n .action(async (target: string, to: string) => {\n const { space, path: from } = parseTarget([target]);\n if (!from) {\n console.error('Error: source path is required.');\n process.exit(1);\n }\n const client = getClient();\n const s = await client.resolveSpace(space);\n await client.mv(s.id, from, to);\n console.log(`Moved: ${from} → ${to}`);\n });\n\n // --- log ---\n program\n .command('log')\n .description('Show change history — docz log <space>[:<path>]')\n .argument('<target...>')\n .action(async (args: string[]) => {\n const { space, path } = parseTarget(args);\n const client = getClient();\n const s = await client.resolveSpace(space);\n const logs = await client.log(s.id, path || undefined);\n if (logs.length === 0) {\n console.log('No history.');\n return;\n }\n for (const l of logs) {\n console.log(`${l.hash.substring(0, 7)} ${l.date} ${l.message}`);\n }\n });\n\n // --- trash ---\n program\n .command('trash')\n .description('Show deleted files — docz trash <space>')\n .argument('<space>')\n .action(async (spaceName: string) => {\n const client = getClient();\n const s = await client.resolveSpace(spaceName);\n const items = await client.trash(s.id);\n if (items.length === 0) {\n console.log('Trash is empty.');\n return;\n }\n for (const t of items) {\n console.log(\n `${t.path}\\tdeleted ${t.deleted_at}\\t${t.commit.substring(0, 7)}`\n );\n }\n });\n}\n","/**\n * DocSync API Client\n *\n * DocSync 底层是 Git 仓库,每个 Space = 一个 Git repo。\n * 认证:Authorization: Bearer {token}(支持 JWT 和永久 API Token)。\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface Space {\n id: string;\n name: string;\n owner_id: string;\n is_private: boolean;\n created_at: string;\n member_count: number;\n}\n\nexport interface TreeEntry {\n name: string;\n type: 'blob' | 'tree';\n size: number;\n}\n\nexport interface LogEntry {\n hash: string;\n author: string;\n message: string;\n date: string;\n num_files: number;\n}\n\nexport interface TrashEntry {\n path: string;\n deleted_by: string;\n deleted_at: string;\n commit: string;\n}\n\nexport interface User {\n id: string;\n email: string;\n name: string;\n is_admin: boolean;\n is_active: boolean;\n created_at: string;\n}\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\nexport class DocSyncClient {\n constructor(\n private baseUrl: string,\n private token: string\n ) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n }\n\n private async request<T>(path: string, init?: RequestInit): Promise<T> {\n const res = await fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: {\n Authorization: `Bearer ${this.token}`,\n ...init?.headers,\n },\n });\n\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new Error(`${res.status} ${res.statusText}: ${body}`.trim());\n }\n\n const ct = res.headers.get('content-type') ?? '';\n if (ct.includes('application/json')) return res.json() as Promise<T>;\n return res.text() as unknown as T;\n }\n\n // --- Auth ---\n async me(): Promise<User> {\n return this.request('/api/auth/me');\n }\n\n // --- Spaces ---\n async listSpaces(): Promise<Space[]> {\n return this.request('/api/spaces');\n }\n\n async resolveSpace(nameOrId: string): Promise<Space> {\n const spaces = await this.listSpaces();\n const s = spaces.find(\n (s) =>\n s.id === nameOrId ||\n s.name === nameOrId ||\n s.name.toLowerCase() === nameOrId.toLowerCase()\n );\n if (!s) {\n const available = spaces.map((s) => s.name).join(', ');\n throw new Error(`Space \"${nameOrId}\" not found. Available: ${available}`);\n }\n return s;\n }\n\n // --- Tree ---\n async ls(spaceId: string, path = ''): Promise<TreeEntry[]> {\n return this.request(\n `/api/spaces/${spaceId}/tree?path=${encodeURIComponent(path)}`\n );\n }\n\n // --- Blob ---\n async cat(spaceId: string, filepath: string): Promise<string> {\n return this.request(\n `/api/spaces/${spaceId}/blob/${encodeURIComponent(filepath)}`\n );\n }\n\n // --- Write ---\n async upload(\n spaceId: string,\n dir: string,\n filename: string,\n content: string | Buffer\n ): Promise<{ path: string }> {\n const blob =\n typeof content === 'string'\n ? new Blob([content], { type: 'application/octet-stream' })\n : new Blob([content], { type: 'application/octet-stream' });\n const form = new FormData();\n form.append('file', blob, filename);\n form.append('path', dir);\n return this.request(`/api/spaces/${spaceId}/files/upload`, {\n method: 'POST',\n body: form,\n });\n }\n\n async mkdir(spaceId: string, path: string): Promise<void> {\n await this.request(`/api/spaces/${spaceId}/files/mkdir`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ path }),\n });\n }\n\n async rm(spaceId: string, path: string): Promise<void> {\n await this.request(`/api/spaces/${spaceId}/files/delete`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ path }),\n });\n }\n\n async mv(spaceId: string, from: string, to: string): Promise<void> {\n await this.request(`/api/spaces/${spaceId}/files/rename`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ old_path: from, new_path: to }),\n });\n }\n\n // --- History ---\n async log(spaceId: string, filepath?: string): Promise<LogEntry[]> {\n const path = filepath\n ? `/api/spaces/${spaceId}/log/${encodeURIComponent(filepath)}`\n : `/api/spaces/${spaceId}/log/`;\n return this.request(path);\n }\n\n // --- Trash ---\n async trash(spaceId: string): Promise<TrashEntry[]> {\n return this.request(`/api/spaces/${spaceId}/trash`);\n }\n}\n","/**\n * 配置管理\n *\n * 优先级:环境变量 > ~/.docz/config.json\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst CONFIG_DIR = join(homedir(), '.docz');\nconst CONFIG_FILE = join(CONFIG_DIR, 'config.json');\n\ninterface Config {\n base_url?: string;\n token?: string;\n}\n\nfunction readConfig(): Config {\n if (!existsSync(CONFIG_FILE)) return {};\n try {\n return JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));\n } catch {\n return {};\n }\n}\n\nfunction writeConfig(config: Config): void {\n mkdirSync(CONFIG_DIR, { recursive: true });\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + '\\n');\n}\n\nexport function getBaseUrl(): string {\n return (\n process.env.DOCSYNC_BASE_URL ??\n readConfig().base_url ??\n 'https://docz.zhenguanyu.com'\n );\n}\n\nexport function getToken(): string | undefined {\n return process.env.DOCSYNC_API_TOKEN ?? readConfig().token;\n}\n\nexport function saveConfig(baseUrl: string, token: string): void {\n writeConfig({ base_url: baseUrl, token });\n}\n\nexport function getConfigPath(): string {\n return CONFIG_FILE;\n}\n"],"mappings":"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","names":["readFileSync","s","program","readFileSync"]}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "docz-cli",
3
+ "version": "0.1.0",
4
+ "description": "DocSync CLI — read and write company documents",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "docz": "./dist/index.js"
10
+ },
11
+ "exports": {
12
+ ".": "./dist/index.js"
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/kanyun-inc/docz-cli"
20
+ },
21
+ "license": "MIT",
22
+ "keywords": [
23
+ "docsync",
24
+ "cli",
25
+ "file-sync",
26
+ "document"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsup",
30
+ "dev": "tsup --watch",
31
+ "typecheck": "tsc --noEmit",
32
+ "test": "vitest run",
33
+ "test:watch": "vitest",
34
+ "lint": "biome check",
35
+ "lint:fix": "biome check --write",
36
+ "clean": "rm -rf dist node_modules"
37
+ },
38
+ "dependencies": {
39
+ "commander": "^13.1.0"
40
+ },
41
+ "devDependencies": {
42
+ "@biomejs/biome": "2.2.0",
43
+ "@types/node": "^22.15.0",
44
+ "msw": "^2.8.4",
45
+ "tsup": "^8.4.0",
46
+ "typescript": "^5.8.2",
47
+ "vitest": "^4.0.4"
48
+ },
49
+ "engines": {
50
+ "node": ">=22.0.0"
51
+ }
52
+ }