docz-cli 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -279,6 +279,25 @@ docz-cli wraps the DocSync REST API:
279
279
 
280
280
  Auth: `Authorization: Bearer <token>`. Backend is Git — every write is a commit.
281
281
 
282
+ ## Contributing
283
+
284
+ See [CONTRIBUTING.md](./CONTRIBUTING.md). Quick version:
285
+
286
+ ```bash
287
+ # New branch
288
+ git checkout -b feature-xxx
289
+
290
+ # Code + tests
291
+ pnpm typecheck && pnpm lint && pnpm test && pnpm build
292
+
293
+ # Add a changeset (skipping this means no release)
294
+ pnpm changeset
295
+
296
+ # Open a PR
297
+ ```
298
+
299
+ Once merged into `main`, GitHub Actions automatically bumps the version and publishes to npm — no manual `npm publish`, no tag, no OTP.
300
+
282
301
  ## License
283
302
 
284
303
  MIT
@@ -276,7 +276,8 @@ function readConfig() {
276
276
  }
277
277
  function writeConfig(config) {
278
278
  mkdirSync(CONFIG_DIR, { recursive: true });
279
- writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
279
+ writeFileSync(CONFIG_FILE, `${JSON.stringify(config, null, 2)}
280
+ `);
280
281
  }
281
282
  function getBaseUrl() {
282
283
  return process.env.DOCSYNC_BASE_URL ?? readConfig().base_url ?? "https://docz.zhenguanyu.com";
@@ -323,44 +324,70 @@ function formatSize(bytes) {
323
324
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
324
325
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
325
326
  }
326
- var SHORT_URL_RE = /\/s\/([^/]+)\/f\/([^/?\s]+)/;
327
- var SLUG_ONLY_RE = /\/s\/([^/?\s]+)\/?(?:\?.*)?$/;
328
327
  var SHARE_URL_RE = /\/share\/([^/?\s]+)/;
328
+ async function resolveSlug(client, slug) {
329
+ try {
330
+ const spaces = await client.listSpaces();
331
+ const found = spaces.find((s) => s.slug === slug);
332
+ if (found) return found;
333
+ } catch {
334
+ }
335
+ return client.resolveBySlug(slug);
336
+ }
329
337
  async function resolveUrl(client, input) {
330
- const fileMatch = input.match(SHORT_URL_RE);
338
+ let pathname;
339
+ try {
340
+ pathname = new URL(input).pathname;
341
+ } catch {
342
+ return null;
343
+ }
344
+ const fileMatch = pathname.match(/^\/s\/([^/]+)\/f\/([^/]+)$/);
331
345
  if (fileMatch) {
332
346
  const [, slug, fileId] = fileMatch;
333
347
  const space = await resolveSlug(client, slug);
334
348
  const ref = await client.resolveFileRef(fileId);
335
349
  return { spaceId: space.id, path: ref.path };
336
350
  }
337
- const slugMatch = input.match(SLUG_ONLY_RE);
351
+ const slugMatch = pathname.match(/^\/s\/([^/]+)(\/.*)?$/);
338
352
  if (slugMatch) {
339
- const [, slug] = slugMatch;
353
+ const [, slug, rest] = slugMatch;
340
354
  const space = await resolveSlug(client, slug);
341
- return { spaceId: space.id, path: "" };
355
+ const filePath = rest ? decodeURIComponent(rest.slice(1)) : "";
356
+ return { spaceId: space.id, path: filePath };
342
357
  }
343
- return null;
344
- }
345
- async function resolveSlug(client, slug) {
346
- try {
347
- const spaces = await client.listSpaces();
348
- const found = spaces.find((s) => s.slug === slug);
349
- if (found) return found;
350
- } catch {
358
+ const legacyMatch = pathname.match(/^\/spaces\/([^/]+)(\/.*)?$/);
359
+ if (legacyMatch) {
360
+ const [, spaceId, rest] = legacyMatch;
361
+ const filePath = rest ? decodeURIComponent(rest.slice(1)) : "";
362
+ return { spaceId, path: filePath };
351
363
  }
352
- return client.resolveBySlug(slug);
364
+ return null;
353
365
  }
354
366
  async function resolveTarget(client, args) {
355
367
  const first = args[0];
356
368
  if (first && (first.startsWith("http://") || first.startsWith("https://"))) {
357
369
  const result = await resolveUrl(client, first);
358
370
  if (result) return result;
371
+ throw new Error(
372
+ `Unrecognized DocSync URL: ${first}
373
+ Expected: /s/{slug}[/f/{fileId}], /s/{slug}[/path], or /spaces/{id}[/path]`
374
+ );
359
375
  }
360
376
  const { space, path } = parseTarget(args);
361
377
  const s = await client.resolveSpace(space);
362
378
  return { spaceId: s.id, path };
363
379
  }
380
+ async function resolveSpaceArg(client, input) {
381
+ if (input.startsWith("http://") || input.startsWith("https://")) {
382
+ const result = await resolveUrl(client, input);
383
+ if (result) return { id: result.spaceId };
384
+ throw new Error(
385
+ `Unrecognized DocSync URL: ${input}
386
+ Expected: /s/{slug}[/f/{fileId}], /s/{slug}[/path], or /spaces/{id}[/path]`
387
+ );
388
+ }
389
+ return client.resolveSpace(input);
390
+ }
364
391
  function parseExpires(value) {
365
392
  const match = value.match(/^(\d+)([dh])$/);
366
393
  if (!match)
@@ -454,27 +481,29 @@ function registerCommands(program) {
454
481
  process.stdout.write(content);
455
482
  }
456
483
  });
457
- program.command("upload").description("Upload file \u2014 docz upload <local-file> <space>[:<dir>]").argument("<file>", "Local file to upload").argument("<target...>").action(async (file, args) => {
458
- const { space, path: dir } = parseTarget(args);
484
+ program.command("upload").description(
485
+ "Upload file \u2014 docz upload <local-file> <space>[:<dir>] or <url>"
486
+ ).argument("<file>", "Local file to upload").argument("<target...>").action(async (file, args) => {
459
487
  const client = getClient();
460
- const s = await client.resolveSpace(space);
488
+ const { spaceId, path: dir } = await resolveTarget(client, args);
461
489
  const content = readFileSync2(file);
462
490
  const filename = basename(file);
463
491
  const targetDir = dir || "";
464
- const result = await client.upload(s.id, targetDir, filename, content);
492
+ const result = await client.upload(spaceId, targetDir, filename, content);
465
493
  console.log(`Uploaded: ${result.path}`);
466
494
  });
467
- program.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)").option("--force", "Skip conflict detection").option("-m, --message <msg>", "Custom commit message").action(
495
+ program.command("write").description(
496
+ "Write content to file \u2014 docz write <space>:<path> <content> or <url> <content>"
497
+ ).argument("<target>", "space:dir/filename.md or short URL").argument("<content>", "File content (or - for stdin)").option("--force", "Skip conflict detection").option("-m, --message <msg>", "Custom commit message").action(
468
498
  async (target, content, opts) => {
469
- const { space, path } = parseTarget([target]);
499
+ const client = getClient();
500
+ const { spaceId, path } = await resolveTarget(client, [target]);
470
501
  if (!path) {
471
502
  console.error(
472
503
  "Error: path is required. Usage: docz write <space>:<dir/filename> <content>"
473
504
  );
474
505
  process.exit(1);
475
506
  }
476
- const client = getClient();
477
- const s = await client.resolveSpace(space);
478
507
  const body = content === "-" ? await readStdin() : content;
479
508
  if (Buffer.byteLength(body, "utf-8") > MAX_SAVE_SIZE) {
480
509
  console.error(
@@ -485,7 +514,7 @@ function registerCommands(program) {
485
514
  let baseRef;
486
515
  if (!opts.force) {
487
516
  try {
488
- const existing = await client.catWithRef(s.id, path);
517
+ const existing = await client.catWithRef(spaceId, path);
489
518
  baseRef = existing.ref;
490
519
  } catch (err) {
491
520
  const msg = err instanceof Error ? err.message : "";
@@ -493,7 +522,7 @@ function registerCommands(program) {
493
522
  }
494
523
  }
495
524
  try {
496
- const result = await client.save(s.id, path, body, {
525
+ const result = await client.save(spaceId, path, body, {
497
526
  baseRef,
498
527
  message: opts.message
499
528
  });
@@ -509,37 +538,34 @@ function registerCommands(program) {
509
538
  }
510
539
  }
511
540
  );
512
- program.command("mkdir").description("Create folder \u2014 docz mkdir <space>:<path>").argument("<target...>").action(async (args) => {
513
- const { space, path } = parseTarget(args);
541
+ program.command("mkdir").description("Create folder \u2014 docz mkdir <space>:<path> or <url>").argument("<target...>").action(async (args) => {
542
+ const client = getClient();
543
+ const { spaceId, path } = await resolveTarget(client, args);
514
544
  if (!path) {
515
545
  console.error("Error: path is required.");
516
546
  process.exit(1);
517
547
  }
518
- const client = getClient();
519
- const s = await client.resolveSpace(space);
520
- await client.mkdir(s.id, path);
548
+ await client.mkdir(spaceId, path);
521
549
  console.log(`Created: ${path}`);
522
550
  });
523
- program.command("rm").description("Delete file/folder \u2014 docz rm <space>:<path>").argument("<target...>").action(async (args) => {
524
- const { space, path } = parseTarget(args);
551
+ program.command("rm").description("Delete file/folder \u2014 docz rm <space>:<path> or <url>").argument("<target...>").action(async (args) => {
552
+ const client = getClient();
553
+ const { spaceId, path } = await resolveTarget(client, args);
525
554
  if (!path) {
526
555
  console.error("Error: path is required.");
527
556
  process.exit(1);
528
557
  }
529
- const client = getClient();
530
- const s = await client.resolveSpace(space);
531
- await client.rm(s.id, path);
558
+ await client.rm(spaceId, path);
532
559
  console.log(`Deleted: ${path} (recoverable from trash for 30 days)`);
533
560
  });
534
- program.command("mv").description("Rename/move \u2014 docz mv <space>:<from> <to>").argument("<target>", "space:old-path").argument("<to>", "new-path").action(async (target, to) => {
535
- const { space, path: from } = parseTarget([target]);
561
+ program.command("mv").description("Rename/move \u2014 docz mv <space>:<from> <to> or <url> <to>").argument("<target>", "space:old-path or short URL").argument("<to>", "new-path").action(async (target, to) => {
562
+ const client = getClient();
563
+ const { spaceId, path: from } = await resolveTarget(client, [target]);
536
564
  if (!from) {
537
565
  console.error("Error: source path is required.");
538
566
  process.exit(1);
539
567
  }
540
- const client = getClient();
541
- const s = await client.resolveSpace(space);
542
- await client.mv(s.id, from, to);
568
+ await client.mv(spaceId, from, to);
543
569
  console.log(`Moved: ${from} \u2192 ${to}`);
544
570
  });
545
571
  program.command("log").description("Show change history \u2014 docz log <space>[:<path>] or <url>").argument("<target...>").action(async (args) => {
@@ -555,21 +581,20 @@ function registerCommands(program) {
555
581
  }
556
582
  });
557
583
  program.command("rollback").description(
558
- "Rollback file to a previous version \u2014 docz rollback <space>:<path> <commit>"
559
- ).argument("<target>", "space:path").argument("<commit>", "Commit hash to rollback to").action(async (target, commit) => {
560
- const { space, path } = parseTarget([target]);
584
+ "Rollback file to a previous version \u2014 docz rollback <space>:<path> <commit> or <url> <commit>"
585
+ ).argument("<target>", "space:path or short URL").argument("<commit>", "Commit hash to rollback to").action(async (target, commit) => {
586
+ const client = getClient();
587
+ const { spaceId, path } = await resolveTarget(client, [target]);
561
588
  if (!path) {
562
589
  console.error("Error: file path is required.");
563
590
  process.exit(1);
564
591
  }
565
- const client = getClient();
566
- const s = await client.resolveSpace(space);
567
- await client.rollback(s.id, path, commit);
592
+ await client.rollback(spaceId, path, commit);
568
593
  console.log(`Rolled back: ${path} \u2192 ${commit.substring(0, 7)}`);
569
594
  });
570
595
  program.command("trash").description("Show deleted files \u2014 docz trash <space>").argument("<space>").action(async (spaceName) => {
571
596
  const client = getClient();
572
- const s = await client.resolveSpace(spaceName);
597
+ const s = await resolveSpaceArg(client, spaceName);
573
598
  const items = await client.trash(s.id);
574
599
  if (items.length === 0) {
575
600
  console.log("Trash is empty.");
@@ -582,16 +607,15 @@ function registerCommands(program) {
582
607
  }
583
608
  });
584
609
  program.command("restore").description(
585
- "Restore file from trash \u2014 docz restore <space>:<path> <commit>"
586
- ).argument("<target>", "space:path").argument("<commit>", "Commit hash from trash listing").action(async (target, commit) => {
587
- const { space, path } = parseTarget([target]);
610
+ "Restore file from trash \u2014 docz restore <space>:<path> <commit> or <url> <commit>"
611
+ ).argument("<target>", "space:path or short URL").argument("<commit>", "Commit hash from trash listing").action(async (target, commit) => {
612
+ const client = getClient();
613
+ const { spaceId, path } = await resolveTarget(client, [target]);
588
614
  if (!path) {
589
615
  console.error("Error: path is required.");
590
616
  process.exit(1);
591
617
  }
592
- const client = getClient();
593
- const s = await client.resolveSpace(space);
594
- await client.restore(s.id, path, commit);
618
+ await client.restore(spaceId, path, commit);
595
619
  console.log(`Restored: ${path}`);
596
620
  });
597
621
  const comment = program.command("comment").description("Manage file comments");
@@ -616,58 +640,60 @@ function registerCommands(program) {
616
640
  }
617
641
  }
618
642
  });
619
- comment.command("add").description("Add comment \u2014 docz comment add <space>:<path> <content>").argument("<target>", "space:path").argument("<content>", "Comment text (or - for stdin)").action(async (target, content) => {
620
- const { space, path } = parseTarget([target]);
643
+ comment.command("add").description(
644
+ "Add comment \u2014 docz comment add <space>:<path> <content> or <url> <content>"
645
+ ).argument("<target>", "space:path or short URL").argument("<content>", "Comment text (or - for stdin)").action(async (target, content) => {
646
+ const client = getClient();
647
+ const { spaceId, path } = await resolveTarget(client, [target]);
621
648
  if (!path) {
622
649
  console.error("Error: file path is required.");
623
650
  process.exit(1);
624
651
  }
625
- const client = getClient();
626
- const s = await client.resolveSpace(space);
627
652
  const body = content === "-" ? await readStdin() : content;
628
- const c = await client.createComment(s.id, path, body);
653
+ const c = await client.createComment(spaceId, path, body);
629
654
  console.log(`Comment #${c.id} created.`);
630
655
  });
631
656
  comment.command("reply").description(
632
657
  "Reply to comment \u2014 docz comment reply <space> <commentId> <content>"
633
658
  ).argument("<space>").argument("<commentId>").argument("<content>", "Reply text (or - for stdin)").action(async (spaceName, commentId, content) => {
634
659
  const client = getClient();
635
- const s = await client.resolveSpace(spaceName);
660
+ const s = await resolveSpaceArg(client, spaceName);
636
661
  const body = content === "-" ? await readStdin() : content;
637
662
  const r = await client.replyComment(s.id, Number(commentId), body);
638
663
  console.log(`Reply #${r.id} created.`);
639
664
  });
640
665
  comment.command("close").description("Close comment \u2014 docz comment close <space> <commentId>").argument("<space>").argument("<commentId>").action(async (spaceName, commentId) => {
641
666
  const client = getClient();
642
- const s = await client.resolveSpace(spaceName);
667
+ const s = await resolveSpaceArg(client, spaceName);
643
668
  await client.closeComment(s.id, Number(commentId));
644
669
  console.log(`Comment #${commentId} closed.`);
645
670
  });
646
671
  comment.command("rm").description("Delete comment \u2014 docz comment rm <space> <commentId>").argument("<space>").argument("<commentId>").action(async (spaceName, commentId) => {
647
672
  const client = getClient();
648
- const s = await client.resolveSpace(spaceName);
673
+ const s = await resolveSpaceArg(client, spaceName);
649
674
  await client.deleteComment(s.id, Number(commentId));
650
675
  console.log(`Comment #${commentId} deleted.`);
651
676
  });
652
677
  const share = program.command("share").description("Manage share links");
653
- share.command("create").description("Create share link \u2014 docz share create <space>:<path>").argument("<target>", "space:path").option("--expires <duration>", "Expiry duration (e.g. 7d, 24h)").option("--users <emails>", "Comma-separated user emails or IDs").option("--groups <ids>", "Comma-separated group IDs").action(
678
+ share.command("create").description(
679
+ "Create share link \u2014 docz share create <space>:<path> or <url>"
680
+ ).argument("<target>", "space:path or short URL").option("--expires <duration>", "Expiry duration (e.g. 7d, 24h)").option("--users <emails>", "Comma-separated user emails or IDs").option("--groups <ids>", "Comma-separated group IDs").action(
654
681
  async (target, opts) => {
655
- const { space, path } = parseTarget([target]);
682
+ const client = getClient();
683
+ const { spaceId, path } = await resolveTarget(client, [target]);
656
684
  if (!path) {
657
685
  console.error(
658
686
  "Error: file path is required. Usage: docz share create <space>:<path>"
659
687
  );
660
688
  process.exit(1);
661
689
  }
662
- const client = getClient();
663
- const s = await client.resolveSpace(space);
664
690
  const apiOpts = {};
665
691
  if (opts.expires) apiOpts.expiresAt = parseExpires(opts.expires);
666
692
  if (opts.users)
667
- apiOpts.userIds = opts.users.split(",").map((s2) => s2.trim());
693
+ apiOpts.userIds = opts.users.split(",").map((s) => s.trim());
668
694
  if (opts.groups)
669
- apiOpts.groupIds = opts.groups.split(",").map((s2) => s2.trim());
670
- const link = await client.createShareLink(s.id, path, apiOpts);
695
+ apiOpts.groupIds = opts.groups.split(",").map((s) => s.trim());
696
+ const link = await client.createShareLink(spaceId, path, apiOpts);
671
697
  const baseUrl = getBaseUrl();
672
698
  console.log("Created share link:");
673
699
  console.log(` id: ${link.id}`);
@@ -682,7 +708,7 @@ function registerCommands(program) {
682
708
  );
683
709
  share.command("list").description("List share links \u2014 docz share list <space>").argument("<space>").option("--file <path>", "Filter by file path").action(async (spaceName, opts) => {
684
710
  const client = getClient();
685
- const s = await client.resolveSpace(spaceName);
711
+ const s = await resolveSpaceArg(client, spaceName);
686
712
  const links = await client.listShareLinks(s.id, opts.file);
687
713
  if (links.length === 0) {
688
714
  console.log("No share links.");
@@ -699,7 +725,7 @@ function registerCommands(program) {
699
725
  share.command("update").description("Update share link \u2014 docz share update <space> <link-id>").argument("<space>").argument("<linkId>").option("--expires <duration>", "New expiry duration (e.g. 30d)").option("--users <emails>", "Comma-separated user emails or IDs").option("--groups <ids>", "Comma-separated group IDs").action(
700
726
  async (spaceName, linkId, opts) => {
701
727
  const client = getClient();
702
- const s = await client.resolveSpace(spaceName);
728
+ const s = await resolveSpaceArg(client, spaceName);
703
729
  const apiOpts = {};
704
730
  if (opts.expires) apiOpts.expiresAt = parseExpires(opts.expires);
705
731
  if (opts.users)
@@ -742,7 +768,7 @@ function registerCommands(program) {
742
768
  });
743
769
  share.command("rm").description("Delete share link \u2014 docz share rm <space> <link-id>").argument("<space>").argument("<linkId>").action(async (spaceName, linkId) => {
744
770
  const client = getClient();
745
- const s = await client.resolveSpace(spaceName);
771
+ const s = await resolveSpaceArg(client, spaceName);
746
772
  await client.deleteShareLink(s.id, linkId);
747
773
  console.log(`Deleted share link: ${linkId}`);
748
774
  });
@@ -758,19 +784,20 @@ function registerCommands(program) {
758
784
  const ref = await client.getFileRef(spaceId, path);
759
785
  console.log(ref.url);
760
786
  });
761
- program.command("diff").description("Show changes \u2014 docz diff <space>[:<path>] <commit> [<from>]").argument("<target>", "space or space:path").argument("<to>", "Commit hash").argument("[from]", "From commit hash (default: to^)").action(async (target, to, from) => {
787
+ program.command("diff").description(
788
+ "Show changes \u2014 docz diff <space>[:<path>] <commit> [<from>] or <url> <commit> [<from>]"
789
+ ).argument("<target>", "space or space:path or short URL").argument("<to>", "Commit hash").argument("[from]", "From commit hash (default: to^)").action(async (target, to, from) => {
762
790
  const client = getClient();
763
- const { space, path } = parseTarget([target]);
764
- const s = await client.resolveSpace(space);
791
+ const { spaceId, path } = await resolveTarget(client, [target]);
765
792
  if (path) {
766
- const result = await client.diffFile(s.id, path, to, from);
793
+ const result = await client.diffFile(spaceId, path, to, from);
767
794
  if (result.diff) {
768
795
  process.stdout.write(result.diff);
769
796
  } else {
770
797
  console.log("No changes.");
771
798
  }
772
799
  } else {
773
- const result = await client.diffSummary(s.id, to, from);
800
+ const result = await client.diffSummary(spaceId, to, from);
774
801
  if (result.files.length === 0) {
775
802
  console.log("No changes.");
776
803
  return;
@@ -790,4 +817,4 @@ export {
790
817
  parseExpires,
791
818
  registerCommands
792
819
  };
793
- //# sourceMappingURL=chunk-XUT76ACQ.js.map
820
+ //# sourceMappingURL=chunk-CMQUBTWI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts","../src/config.ts","../src/commands.ts"],"sourcesContent":["/**\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 slug?: 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\nexport interface ShareLink {\n id: string;\n token: string;\n space_id: string;\n file_path: string;\n created_by: string;\n created_by_name?: string;\n created_by_email?: string;\n expires_at: string | null;\n created_at: string;\n user_ids?: string[];\n group_ids?: string[];\n}\n\nexport interface ShareFileInfo {\n file_path: string;\n file_name: string;\n space_name: string;\n created_by_name: string;\n expires_at: string | null;\n}\n\nexport interface DiffResponse {\n from: string;\n to: string;\n path: string;\n diff: string;\n old_body: string;\n new_body: string;\n}\n\nexport interface DiffFileEntry {\n path: string;\n status: string;\n}\n\nexport interface DiffSummary {\n from: string;\n to: string;\n files: DiffFileEntry[];\n}\n\nexport interface FileRef {\n id: string;\n space_id: string;\n path: string;\n}\n\nexport interface CatResult {\n content: string;\n ref: string;\n}\n\nexport interface SaveResult {\n path: string;\n ref: string;\n}\n\nexport interface SaveConflict {\n error: 'conflict';\n current_ref: string;\n path: string;\n}\n\nexport interface Comment {\n id: number;\n space_id: string;\n file_path: string;\n comment_type: string;\n target_type: string;\n target_selector: string;\n target_content: string;\n content: string;\n user_id: string;\n user_name: string;\n user_email: string;\n is_closed: boolean;\n created_at: string;\n updated_at: string;\n replies: CommentReply[];\n}\n\nexport interface CommentReply {\n id: number;\n comment_id: number;\n content: string;\n user_id: string;\n user_name: string;\n user_email: string;\n created_at: string;\n updated_at: string;\n}\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class ConflictError extends Error {\n constructor(public readonly detail: SaveConflict) {\n super(\n 'Conflict: file has been modified by others. Please re-read the latest content and re-apply your changes.'\n );\n this.name = 'ConflictError';\n }\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 async treeFull(spaceId: string): Promise<TreeEntry[]> {\n return this.request(`/api/spaces/${spaceId}/tree/full`);\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 async catWithRef(spaceId: string, filepath: string): Promise<CatResult> {\n const res = await fetch(\n `${this.baseUrl}/api/spaces/${spaceId}/blob/${encodeURIComponent(filepath)}`,\n { headers: { Authorization: `Bearer ${this.token}` } }\n );\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new Error(`${res.status} ${res.statusText}: ${body}`.trim());\n }\n const content = await res.text();\n const ref = res.headers.get('X-Git-Ref') ?? '';\n return { content, ref };\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 save(\n spaceId: string,\n path: string,\n content: string,\n opts?: { baseRef?: string; message?: string }\n ): Promise<SaveResult> {\n const body: Record<string, string> = { path, content };\n if (opts?.baseRef) body.base_ref = opts.baseRef;\n if (opts?.message) body.message = opts.message;\n\n const res = await fetch(\n `${this.baseUrl}/api/spaces/${spaceId}/files/save`,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n }\n );\n\n if (res.status === 409) {\n const data = (await res.json()) as SaveConflict;\n throw new ConflictError(data);\n }\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`${res.status} ${res.statusText}: ${text}`.trim());\n }\n\n return res.json() as Promise<SaveResult>;\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 async rollback(\n spaceId: string,\n filePath: string,\n commitHash: string\n ): Promise<void> {\n await this.request(`/api/spaces/${spaceId}/files/rollback`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ file_path: filePath, commit_hash: commitHash }),\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 async restore(spaceId: string, path: string, commit: string): Promise<void> {\n await this.request(`/api/spaces/${spaceId}/trash/restore`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ path, commit }),\n });\n }\n\n // --- Comments ---\n async listComments(spaceId: string, filePath: string): Promise<Comment[]> {\n return this.request(\n `/api/spaces/${spaceId}/comments?path=${encodeURIComponent(filePath)}`\n );\n }\n\n async createComment(\n spaceId: string,\n filePath: string,\n content: string\n ): Promise<Comment> {\n return this.request(`/api/spaces/${spaceId}/comments`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ file_path: filePath, content }),\n });\n }\n\n async replyComment(\n spaceId: string,\n commentId: number,\n content: string\n ): Promise<CommentReply> {\n return this.request(\n `/api/spaces/${spaceId}/comments/${commentId}/replies`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ content }),\n }\n );\n }\n\n async closeComment(spaceId: string, commentId: number): Promise<Comment> {\n return this.request(`/api/spaces/${spaceId}/comments/${commentId}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ is_closed: true }),\n });\n }\n\n async deleteComment(spaceId: string, commentId: number): Promise<void> {\n await this.request(`/api/spaces/${spaceId}/comments/${commentId}`, {\n method: 'DELETE',\n });\n }\n\n // --- Share Links ---\n async createShareLink(\n spaceId: string,\n filePath: string,\n opts?: { expiresAt?: string; userIds?: string[]; groupIds?: string[] }\n ): Promise<ShareLink> {\n const body: Record<string, unknown> = { file_path: filePath };\n if (opts?.expiresAt) body.expires_at = opts.expiresAt;\n if (opts?.userIds?.length) body.user_ids = opts.userIds;\n if (opts?.groupIds?.length) body.group_ids = opts.groupIds;\n return this.request(`/api/spaces/${spaceId}/share-links`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n }\n\n async listShareLinks(\n spaceId: string,\n filePath?: string\n ): Promise<ShareLink[]> {\n const q = filePath ? `?file_path=${encodeURIComponent(filePath)}` : '';\n return this.request(`/api/spaces/${spaceId}/share-links${q}`);\n }\n\n async updateShareLink(\n spaceId: string,\n linkId: string,\n opts: { expiresAt?: string; userIds?: string[]; groupIds?: string[] }\n ): Promise<ShareLink> {\n const body: Record<string, unknown> = {};\n if (opts.expiresAt !== undefined) body.expires_at = opts.expiresAt;\n if (opts.userIds) body.user_ids = opts.userIds;\n if (opts.groupIds) body.group_ids = opts.groupIds;\n return this.request(`/api/spaces/${spaceId}/share-links/${linkId}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n }\n\n async deleteShareLink(spaceId: string, linkId: string): Promise<void> {\n await this.request(`/api/spaces/${spaceId}/share-links/${linkId}`, {\n method: 'DELETE',\n });\n }\n\n async getSharedFile(token: string): Promise<string> {\n return this.request(`/api/share/${token}`);\n }\n\n async getSharedFileInfo(token: string): Promise<ShareFileInfo> {\n return this.request(`/api/share/${token}/info`);\n }\n\n // --- Diff ---\n async diffFile(\n spaceId: string,\n filePath: string,\n to: string,\n from?: string\n ): Promise<DiffResponse> {\n const params = new URLSearchParams({ to });\n if (from) params.set('from', from);\n return this.request(\n `/api/spaces/${spaceId}/diff/${encodeURIComponent(filePath)}?${params}`\n );\n }\n\n async diffSummary(\n spaceId: string,\n to: string,\n from?: string\n ): Promise<DiffSummary> {\n const params = new URLSearchParams({ to });\n if (from) params.set('from', from);\n return this.request(`/api/spaces/${spaceId}/diff?${params}`);\n }\n\n // --- File Ref ---\n async getFileRef(\n spaceId: string,\n path: string\n ): Promise<{\n id: string;\n space_id: string;\n slug: string;\n path: string;\n is_dir: boolean;\n url: string;\n }> {\n return this.request(\n `/api/spaces/${spaceId}/file-ref?path=${encodeURIComponent(path)}`\n );\n }\n\n // --- Resolve short URLs ---\n async resolveBySlug(slug: string): Promise<Space> {\n return this.request(`/api/spaces/by-slug/${encodeURIComponent(slug)}`);\n }\n\n async resolveFileRef(fileId: string): Promise<FileRef> {\n return this.request(`/api/file-refs/${encodeURIComponent(fileId)}`);\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","/**\n * CLI Commands\n */\n\nimport { readFileSync } from 'node:fs';\nimport { basename } from 'node:path';\nimport type { Command } from 'commander';\nimport { ConflictError, 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 */\nexport function 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// Share URL: /share/{token}\nconst SHARE_URL_RE = /\\/share\\/([^/?\\s]+)/;\n\n/** Resolve slug: try local spaces cache first, then API */\nasync function resolveSlug(\n client: DocSyncClient,\n slug: string\n): Promise<{ id: string }> {\n try {\n const spaces = await client.listSpaces();\n const found = spaces.find((s) => s.slug === slug);\n if (found) return found;\n } catch {\n // fall through to by-slug API\n }\n return client.resolveBySlug(slug);\n}\n\n/**\n * Detect if input is a URL and resolve it to { spaceId, path }.\n * Supports:\n * /s/{slug}/f/{fileId} — short URL with fileId\n * /s/{slug}[/path/to/file] — slug URL with optional path\n * /spaces/{spaceId}[/path/...] — legacy URL\n * Returns null if not a recognized DocSync URL.\n */\nasync function resolveUrl(\n client: DocSyncClient,\n input: string\n): Promise<{ spaceId: string; path: string } | null> {\n let pathname: string;\n try {\n pathname = new URL(input).pathname;\n } catch {\n return null;\n }\n\n // /s/{slug}/f/{fileId}\n const fileMatch = pathname.match(/^\\/s\\/([^/]+)\\/f\\/([^/]+)$/);\n if (fileMatch) {\n const [, slug, fileId] = fileMatch;\n const space = await resolveSlug(client, slug);\n const ref = await client.resolveFileRef(fileId);\n return { spaceId: space.id, path: ref.path };\n }\n\n // /s/{slug}[/path/to/file]\n const slugMatch = pathname.match(/^\\/s\\/([^/]+)(\\/.*)?$/);\n if (slugMatch) {\n const [, slug, rest] = slugMatch;\n const space = await resolveSlug(client, slug);\n const filePath = rest ? decodeURIComponent(rest.slice(1)) : '';\n return { spaceId: space.id, path: filePath };\n }\n\n // /spaces/{spaceId}[/path/to/file] (legacy)\n const legacyMatch = pathname.match(/^\\/spaces\\/([^/]+)(\\/.*)?$/);\n if (legacyMatch) {\n const [, spaceId, rest] = legacyMatch;\n const filePath = rest ? decodeURIComponent(rest.slice(1)) : '';\n return { spaceId, path: filePath };\n }\n\n return null;\n}\n\n/**\n * Resolve target: if it's a URL, resolve it; otherwise use parseTarget + resolveSpace.\n */\nexport async function resolveTarget(\n client: DocSyncClient,\n args: string[]\n): Promise<{ spaceId: string; path: string }> {\n const first = args[0];\n if (first && (first.startsWith('http://') || first.startsWith('https://'))) {\n const result = await resolveUrl(client, first);\n if (result) return result;\n throw new Error(\n `Unrecognized DocSync URL: ${first}\\nExpected: /s/{slug}[/f/{fileId}], /s/{slug}[/path], or /spaces/{id}[/path]`\n );\n }\n const { space, path } = parseTarget(args);\n const s = await client.resolveSpace(space);\n return { spaceId: s.id, path };\n}\n\n/**\n * Resolve a space argument that may be a name, UUID, or URL.\n * For URLs, delegates to resolveUrl and extracts the spaceId.\n */\nexport async function resolveSpaceArg(\n client: DocSyncClient,\n input: string\n): Promise<{ id: string }> {\n if (input.startsWith('http://') || input.startsWith('https://')) {\n const result = await resolveUrl(client, input);\n if (result) return { id: result.spaceId };\n throw new Error(\n `Unrecognized DocSync URL: ${input}\\nExpected: /s/{slug}[/f/{fileId}], /s/{slug}[/path], or /spaces/{id}[/path]`\n );\n }\n return client.resolveSpace(input);\n}\n\n/** Parse relative duration (7d, 24h, 30d) to RFC3339 */\nexport function parseExpires(value: string): string {\n const match = value.match(/^(\\d+)([dh])$/);\n if (!match)\n throw new Error(\n `Invalid expires format: \"${value}\". Use e.g. 7d, 24h, 30d`\n );\n const [, num, unit] = match;\n const ms = unit === 'd' ? Number(num) * 86400000 : Number(num) * 3600000;\n return new Date(Date.now() + ms).toISOString();\n}\n\n/** Extract share token from URL or return as-is */\nfunction extractShareToken(input: string): string {\n const m = input.match(SHARE_URL_RE);\n if (m) return m[1];\n return input;\n}\n\n/** Read all of stdin into a string */\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString('utf-8');\n}\n\nconst MAX_SAVE_SIZE = 2 * 1024 * 1024; // 2MB\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 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>] or <url>')\n .argument('<target...>')\n .option('-R, --recursive', 'Recursively list all files')\n .action(async (args: string[], opts: { recursive?: boolean }) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, args);\n const entries = opts.recursive\n ? await client.treeFull(spaceId)\n : await client.ls(spaceId, 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> or <url>')\n .argument('<target...>')\n .option('--ref', 'Also output Git ref to stderr')\n .action(async (args: string[], opts: { ref?: boolean }) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, 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 if (opts.ref) {\n const result = await client.catWithRef(spaceId, path);\n console.error(`ref: ${result.ref}`);\n process.stdout.write(result.content);\n } else {\n const content = await client.cat(spaceId, path);\n process.stdout.write(content);\n }\n });\n\n // --- upload ---\n program\n .command('upload')\n .description(\n 'Upload file — docz upload <local-file> <space>[:<dir>] or <url>'\n )\n .argument('<file>', 'Local file to upload')\n .argument('<target...>')\n .action(async (file: string, args: string[]) => {\n const client = getClient();\n const { spaceId, path: dir } = await resolveTarget(client, args);\n const content = readFileSync(file);\n const filename = basename(file);\n const targetDir = dir || '';\n const result = await client.upload(spaceId, targetDir, filename, content);\n console.log(`Uploaded: ${result.path}`);\n });\n\n // --- write ---\n program\n .command('write')\n .description(\n 'Write content to file — docz write <space>:<path> <content> or <url> <content>'\n )\n .argument('<target>', 'space:dir/filename.md or short URL')\n .argument('<content>', 'File content (or - for stdin)')\n .option('--force', 'Skip conflict detection')\n .option('-m, --message <msg>', 'Custom commit message')\n .action(\n async (\n target: string,\n content: string,\n opts: { force?: boolean; message?: string }\n ) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, [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 body = content === '-' ? await readStdin() : content;\n\n if (Buffer.byteLength(body, 'utf-8') > MAX_SAVE_SIZE) {\n console.error(\n 'Error: content exceeds 2MB limit. Use `docz upload` for large files.'\n );\n process.exit(1);\n }\n\n let baseRef: string | undefined;\n if (!opts.force) {\n try {\n const existing = await client.catWithRef(spaceId, path);\n baseRef = existing.ref;\n } catch (err) {\n const msg = err instanceof Error ? err.message : '';\n if (!msg.includes('404')) throw err;\n }\n }\n\n try {\n const result = await client.save(spaceId, path, body, {\n baseRef,\n message: opts.message,\n });\n console.log(`Written: ${result.path} (ref: ${result.ref})`);\n } catch (err) {\n if (err instanceof ConflictError) {\n console.error(\n 'Error: file was modified by someone else. Please re-read the latest content and try again.'\n );\n process.exit(1);\n }\n throw err;\n }\n }\n );\n\n // --- mkdir ---\n program\n .command('mkdir')\n .description('Create folder — docz mkdir <space>:<path> or <url>')\n .argument('<target...>')\n .action(async (args: string[]) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, args);\n if (!path) {\n console.error('Error: path is required.');\n process.exit(1);\n }\n await client.mkdir(spaceId, path);\n console.log(`Created: ${path}`);\n });\n\n // --- rm ---\n program\n .command('rm')\n .description('Delete file/folder — docz rm <space>:<path> or <url>')\n .argument('<target...>')\n .action(async (args: string[]) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, args);\n if (!path) {\n console.error('Error: path is required.');\n process.exit(1);\n }\n await client.rm(spaceId, 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> or <url> <to>')\n .argument('<target>', 'space:old-path or short URL')\n .argument('<to>', 'new-path')\n .action(async (target: string, to: string) => {\n const client = getClient();\n const { spaceId, path: from } = await resolveTarget(client, [target]);\n if (!from) {\n console.error('Error: source path is required.');\n process.exit(1);\n }\n await client.mv(spaceId, 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>] or <url>')\n .argument('<target...>')\n .action(async (args: string[]) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, args);\n const logs = await client.log(spaceId, 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} ${l.date} ${l.message}`);\n }\n });\n\n // --- rollback ---\n program\n .command('rollback')\n .description(\n 'Rollback file to a previous version — docz rollback <space>:<path> <commit> or <url> <commit>'\n )\n .argument('<target>', 'space:path or short URL')\n .argument('<commit>', 'Commit hash to rollback to')\n .action(async (target: string, commit: string) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, [target]);\n if (!path) {\n console.error('Error: file path is required.');\n process.exit(1);\n }\n await client.rollback(spaceId, path, commit);\n console.log(`Rolled back: ${path} → ${commit.substring(0, 7)}`);\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 resolveSpaceArg(client, 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 // --- restore ---\n program\n .command('restore')\n .description(\n 'Restore file from trash — docz restore <space>:<path> <commit> or <url> <commit>'\n )\n .argument('<target>', 'space:path or short URL')\n .argument('<commit>', 'Commit hash from trash listing')\n .action(async (target: string, commit: string) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, [target]);\n if (!path) {\n console.error('Error: path is required.');\n process.exit(1);\n }\n await client.restore(spaceId, path, commit);\n console.log(`Restored: ${path}`);\n });\n\n // --- comment ---\n const comment = program\n .command('comment')\n .description('Manage file comments');\n\n comment\n .command('list')\n .description('List comments — docz comment list <space>:<path>')\n .argument('<target...>')\n .action(async (args: string[]) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, args);\n if (!path) {\n console.error('Error: file path is required.');\n process.exit(1);\n }\n const comments = await client.listComments(spaceId, path);\n if (comments.length === 0) {\n console.log('No comments.');\n return;\n }\n for (const c of comments) {\n const status = c.is_closed ? ' [closed]' : '';\n console.log(`#${c.id} ${c.user_name} (${c.created_at})${status}`);\n console.log(` ${c.content}`);\n for (const r of c.replies) {\n console.log(` → ${r.user_name}: ${r.content}`);\n }\n }\n });\n\n comment\n .command('add')\n .description(\n 'Add comment — docz comment add <space>:<path> <content> or <url> <content>'\n )\n .argument('<target>', 'space:path or short URL')\n .argument('<content>', 'Comment text (or - for stdin)')\n .action(async (target: string, content: string) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, [target]);\n if (!path) {\n console.error('Error: file path is required.');\n process.exit(1);\n }\n const body = content === '-' ? await readStdin() : content;\n const c = await client.createComment(spaceId, path, body);\n console.log(`Comment #${c.id} created.`);\n });\n\n comment\n .command('reply')\n .description(\n 'Reply to comment — docz comment reply <space> <commentId> <content>'\n )\n .argument('<space>')\n .argument('<commentId>')\n .argument('<content>', 'Reply text (or - for stdin)')\n .action(async (spaceName: string, commentId: string, content: string) => {\n const client = getClient();\n const s = await resolveSpaceArg(client, spaceName);\n const body = content === '-' ? await readStdin() : content;\n const r = await client.replyComment(s.id, Number(commentId), body);\n console.log(`Reply #${r.id} created.`);\n });\n\n comment\n .command('close')\n .description('Close comment — docz comment close <space> <commentId>')\n .argument('<space>')\n .argument('<commentId>')\n .action(async (spaceName: string, commentId: string) => {\n const client = getClient();\n const s = await resolveSpaceArg(client, spaceName);\n await client.closeComment(s.id, Number(commentId));\n console.log(`Comment #${commentId} closed.`);\n });\n\n comment\n .command('rm')\n .description('Delete comment — docz comment rm <space> <commentId>')\n .argument('<space>')\n .argument('<commentId>')\n .action(async (spaceName: string, commentId: string) => {\n const client = getClient();\n const s = await resolveSpaceArg(client, spaceName);\n await client.deleteComment(s.id, Number(commentId));\n console.log(`Comment #${commentId} deleted.`);\n });\n\n // --- share ---\n const share = program.command('share').description('Manage share links');\n\n share\n .command('create')\n .description(\n 'Create share link — docz share create <space>:<path> or <url>'\n )\n .argument('<target>', 'space:path or short URL')\n .option('--expires <duration>', 'Expiry duration (e.g. 7d, 24h)')\n .option('--users <emails>', 'Comma-separated user emails or IDs')\n .option('--groups <ids>', 'Comma-separated group IDs')\n .action(\n async (\n target: string,\n opts: { expires?: string; users?: string; groups?: string }\n ) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, [target]);\n if (!path) {\n console.error(\n 'Error: file path is required. Usage: docz share create <space>:<path>'\n );\n process.exit(1);\n }\n const apiOpts: {\n expiresAt?: string;\n userIds?: string[];\n groupIds?: string[];\n } = {};\n if (opts.expires) apiOpts.expiresAt = parseExpires(opts.expires);\n if (opts.users)\n apiOpts.userIds = opts.users.split(',').map((s) => s.trim());\n if (opts.groups)\n apiOpts.groupIds = opts.groups.split(',').map((s) => s.trim());\n const link = await client.createShareLink(spaceId, path, apiOpts);\n const baseUrl = getBaseUrl();\n console.log('Created share link:');\n console.log(` id: ${link.id}`);\n console.log(` token: ${link.token}`);\n console.log(` url: ${baseUrl}/share/${link.token}`);\n console.log(` expires: ${link.expires_at ?? 'never'}`);\n if (link.user_ids?.length)\n console.log(` users: ${link.user_ids.join(', ')}`);\n if (link.group_ids?.length)\n console.log(` groups: ${link.group_ids.length}`);\n }\n );\n\n share\n .command('list')\n .description('List share links — docz share list <space>')\n .argument('<space>')\n .option('--file <path>', 'Filter by file path')\n .action(async (spaceName: string, opts: { file?: string }) => {\n const client = getClient();\n const s = await resolveSpaceArg(client, spaceName);\n const links = await client.listShareLinks(s.id, opts.file);\n if (links.length === 0) {\n console.log('No share links.');\n return;\n }\n for (const l of links) {\n const expires = l.expires_at ?? 'never';\n const creator = l.created_by_name ?? l.created_by_email ?? l.created_by;\n console.log(\n `${l.id}\\t${l.token}\\t${l.file_path}\\t${expires}\\t${creator}`\n );\n }\n });\n\n share\n .command('update')\n .description('Update share link — docz share update <space> <link-id>')\n .argument('<space>')\n .argument('<linkId>')\n .option('--expires <duration>', 'New expiry duration (e.g. 30d)')\n .option('--users <emails>', 'Comma-separated user emails or IDs')\n .option('--groups <ids>', 'Comma-separated group IDs')\n .action(\n async (\n spaceName: string,\n linkId: string,\n opts: { expires?: string; users?: string; groups?: string }\n ) => {\n const client = getClient();\n const s = await resolveSpaceArg(client, spaceName);\n const apiOpts: {\n expiresAt?: string;\n userIds?: string[];\n groupIds?: string[];\n } = {};\n if (opts.expires) apiOpts.expiresAt = parseExpires(opts.expires);\n if (opts.users)\n apiOpts.userIds = opts.users.split(',').map((s) => s.trim());\n if (opts.groups)\n apiOpts.groupIds = opts.groups.split(',').map((s) => s.trim());\n await client.updateShareLink(s.id, linkId, apiOpts);\n console.log(`Updated share link: ${linkId}`);\n }\n );\n\n share\n .command('cat')\n .description('Read shared file — docz share cat <token-or-url>')\n .argument('<token>', 'Share token or full URL')\n .option('--raw', 'Output raw content only')\n .action(async (tokenArg: string, opts: { raw?: boolean }) => {\n const client = getClient();\n const token = extractShareToken(tokenArg);\n if (!opts.raw) {\n try {\n const info = await client.getSharedFileInfo(token);\n console.log(`File: ${info.file_path} (${info.space_name})`);\n console.log(\n `Shared by: ${info.created_by_name} | Expires: ${info.expires_at ?? 'never'}`\n );\n console.log('---');\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (!msg.includes('404')) {\n console.error(`Warning: failed to fetch share info: ${msg}`);\n }\n }\n }\n const content = await client.getSharedFile(token);\n process.stdout.write(content);\n });\n\n share\n .command('info')\n .description('Show share link info — docz share info <token-or-url>')\n .argument('<token>', 'Share token or full URL')\n .action(async (tokenArg: string) => {\n const client = getClient();\n const token = extractShareToken(tokenArg);\n const info = await client.getSharedFileInfo(token);\n console.log(`File: ${info.file_path}`);\n console.log(`Space: ${info.space_name}`);\n console.log(`Shared by: ${info.created_by_name}`);\n console.log(`Expires: ${info.expires_at ?? 'never'}`);\n });\n\n share\n .command('rm')\n .description('Delete share link — docz share rm <space> <link-id>')\n .argument('<space>')\n .argument('<linkId>')\n .action(async (spaceName: string, linkId: string) => {\n const client = getClient();\n const s = await resolveSpaceArg(client, spaceName);\n await client.deleteShareLink(s.id, linkId);\n console.log(`Deleted share link: ${linkId}`);\n });\n\n // --- shortlink ---\n program\n .command('shortlink')\n .description('Get short URL — docz shortlink <space>:<path> or <url>')\n .argument('<target...>')\n .action(async (args: string[]) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, args);\n if (!path) {\n console.error(\n 'Error: file path is required. Usage: docz shortlink <space>:<path>'\n );\n process.exit(1);\n }\n const ref = await client.getFileRef(spaceId, path);\n console.log(ref.url);\n });\n\n // --- diff ---\n program\n .command('diff')\n .description(\n 'Show changes — docz diff <space>[:<path>] <commit> [<from>] or <url> <commit> [<from>]'\n )\n .argument('<target>', 'space or space:path or short URL')\n .argument('<to>', 'Commit hash')\n .argument('[from]', 'From commit hash (default: to^)')\n .action(async (target: string, to: string, from?: string) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, [target]);\n if (path) {\n const result = await client.diffFile(spaceId, path, to, from);\n if (result.diff) {\n process.stdout.write(result.diff);\n } else {\n console.log('No changes.');\n }\n } else {\n const result = await client.diffSummary(spaceId, to, from);\n if (result.files.length === 0) {\n console.log('No changes.');\n return;\n }\n for (const f of result.files) {\n console.log(`${f.status} ${f.path}`);\n }\n }\n });\n}\n"],"mappings":";;;AAoJO,IAAM,gBAAN,cAA4B,MAAM;AAAA,EACvC,YAA4B,QAAsB;AAChD;AAAA,MACE;AAAA,IACF;AAH0B;AAI1B,SAAK,OAAO;AAAA,EACd;AACF;AAMO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YACU,SACA,OACR;AAFQ;AACA;AAER,SAAK,UAAU,QAAQ,QAAQ,OAAO,EAAE;AAAA,EAC1C;AAAA,EAEA,MAAc,QAAW,MAAc,MAAgC;AACrE,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI,IAAI;AAAA,MAChD,GAAG;AAAA,MACH,SAAS;AAAA,QACP,eAAe,UAAU,KAAK,KAAK;AAAA,QACnC,GAAG,MAAM;AAAA,MACX;AAAA,IACF,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,YAAM,IAAI,MAAM,GAAG,IAAI,MAAM,IAAI,IAAI,UAAU,KAAK,IAAI,GAAG,KAAK,CAAC;AAAA,IACnE;AAEA,UAAM,KAAK,IAAI,QAAQ,IAAI,cAAc,KAAK;AAC9C,QAAI,GAAG,SAAS,kBAAkB,EAAG,QAAO,IAAI,KAAK;AACrD,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,KAAoB;AACxB,WAAO,KAAK,QAAQ,cAAc;AAAA,EACpC;AAAA;AAAA,EAGA,MAAM,aAA+B;AACnC,WAAO,KAAK,QAAQ,aAAa;AAAA,EACnC;AAAA,EAEA,MAAM,aAAa,UAAkC;AACnD,UAAM,SAAS,MAAM,KAAK,WAAW;AACrC,UAAM,IAAI,OAAO;AAAA,MACf,CAACA,OACCA,GAAE,OAAO,YACTA,GAAE,SAAS,YACXA,GAAE,KAAK,YAAY,MAAM,SAAS,YAAY;AAAA,IAClD;AACA,QAAI,CAAC,GAAG;AACN,YAAM,YAAY,OAAO,IAAI,CAACA,OAAMA,GAAE,IAAI,EAAE,KAAK,IAAI;AACrD,YAAM,IAAI,MAAM,UAAU,QAAQ,2BAA2B,SAAS,EAAE;AAAA,IAC1E;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,GAAG,SAAiB,OAAO,IAA0B;AACzD,WAAO,KAAK;AAAA,MACV,eAAe,OAAO,cAAc,mBAAmB,IAAI,CAAC;AAAA,IAC9D;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,SAAuC;AACpD,WAAO,KAAK,QAAQ,eAAe,OAAO,YAAY;AAAA,EACxD;AAAA;AAAA,EAGA,MAAM,IAAI,SAAiB,UAAmC;AAC5D,WAAO,KAAK;AAAA,MACV,eAAe,OAAO,SAAS,mBAAmB,QAAQ,CAAC;AAAA,IAC7D;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,SAAiB,UAAsC;AACtE,UAAM,MAAM,MAAM;AAAA,MAChB,GAAG,KAAK,OAAO,eAAe,OAAO,SAAS,mBAAmB,QAAQ,CAAC;AAAA,MAC1E,EAAE,SAAS,EAAE,eAAe,UAAU,KAAK,KAAK,GAAG,EAAE;AAAA,IACvD;AACA,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,YAAM,IAAI,MAAM,GAAG,IAAI,MAAM,IAAI,IAAI,UAAU,KAAK,IAAI,GAAG,KAAK,CAAC;AAAA,IACnE;AACA,UAAM,UAAU,MAAM,IAAI,KAAK;AAC/B,UAAM,MAAM,IAAI,QAAQ,IAAI,WAAW,KAAK;AAC5C,WAAO,EAAE,SAAS,IAAI;AAAA,EACxB;AAAA;AAAA,EAGA,MAAM,OACJ,SACA,KACA,UACA,SAC2B;AAC3B,UAAM,OACJ,OAAO,YAAY,WACf,IAAI,KAAK,CAAC,OAAO,GAAG,EAAE,MAAM,2BAA2B,CAAC,IACxD,IAAI,KAAK,CAAC,OAAO,GAAG,EAAE,MAAM,2BAA2B,CAAC;AAC9D,UAAM,OAAO,IAAI,SAAS;AAC1B,SAAK,OAAO,QAAQ,MAAM,QAAQ;AAClC,SAAK,OAAO,QAAQ,GAAG;AACvB,WAAO,KAAK,QAAQ,eAAe,OAAO,iBAAiB;AAAA,MACzD,QAAQ;AAAA,MACR,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,KACJ,SACA,MACA,SACA,MACqB;AACrB,UAAM,OAA+B,EAAE,MAAM,QAAQ;AACrD,QAAI,MAAM,QAAS,MAAK,WAAW,KAAK;AACxC,QAAI,MAAM,QAAS,MAAK,UAAU,KAAK;AAEvC,UAAM,MAAM,MAAM;AAAA,MAChB,GAAG,KAAK,OAAO,eAAe,OAAO;AAAA,MACrC;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,eAAe,UAAU,KAAK,KAAK;AAAA,UACnC,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,KAAK;AACtB,YAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,YAAM,IAAI,cAAc,IAAI;AAAA,IAC9B;AAEA,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,YAAM,IAAI,MAAM,GAAG,IAAI,MAAM,IAAI,IAAI,UAAU,KAAK,IAAI,GAAG,KAAK,CAAC;AAAA,IACnE;AAEA,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA,EAEA,MAAM,MAAM,SAAiB,MAA6B;AACxD,UAAM,KAAK,QAAQ,eAAe,OAAO,gBAAgB;AAAA,MACvD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,KAAK,CAAC;AAAA,IAC/B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,GAAG,SAAiB,MAA6B;AACrD,UAAM,KAAK,QAAQ,eAAe,OAAO,iBAAiB;AAAA,MACxD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,KAAK,CAAC;AAAA,IAC/B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,GAAG,SAAiB,MAAc,IAA2B;AACjE,UAAM,KAAK,QAAQ,eAAe,OAAO,iBAAiB;AAAA,MACxD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,UAAU,MAAM,UAAU,GAAG,CAAC;AAAA,IACvD,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,SACJ,SACA,UACA,YACe;AACf,UAAM,KAAK,QAAQ,eAAe,OAAO,mBAAmB;AAAA,MAC1D,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,WAAW,UAAU,aAAa,WAAW,CAAC;AAAA,IACvE,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,IAAI,SAAiB,UAAwC;AACjE,UAAM,OAAO,WACT,eAAe,OAAO,QAAQ,mBAAmB,QAAQ,CAAC,KAC1D,eAAe,OAAO;AAC1B,WAAO,KAAK,QAAQ,IAAI;AAAA,EAC1B;AAAA;AAAA,EAGA,MAAM,MAAM,SAAwC;AAClD,WAAO,KAAK,QAAQ,eAAe,OAAO,QAAQ;AAAA,EACpD;AAAA,EAEA,MAAM,QAAQ,SAAiB,MAAc,QAA+B;AAC1E,UAAM,KAAK,QAAQ,eAAe,OAAO,kBAAkB;AAAA,MACzD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAAA,IACvC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,aAAa,SAAiB,UAAsC;AACxE,WAAO,KAAK;AAAA,MACV,eAAe,OAAO,kBAAkB,mBAAmB,QAAQ,CAAC;AAAA,IACtE;AAAA,EACF;AAAA,EAEA,MAAM,cACJ,SACA,UACA,SACkB;AAClB,WAAO,KAAK,QAAQ,eAAe,OAAO,aAAa;AAAA,MACrD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,WAAW,UAAU,QAAQ,CAAC;AAAA,IACvD,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,aACJ,SACA,WACA,SACuB;AACvB,WAAO,KAAK;AAAA,MACV,eAAe,OAAO,aAAa,SAAS;AAAA,MAC5C;AAAA,QACE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,QAAQ,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,SAAiB,WAAqC;AACvE,WAAO,KAAK,QAAQ,eAAe,OAAO,aAAa,SAAS,IAAI;AAAA,MAClE,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,IAC1C,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,cAAc,SAAiB,WAAkC;AACrE,UAAM,KAAK,QAAQ,eAAe,OAAO,aAAa,SAAS,IAAI;AAAA,MACjE,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,gBACJ,SACA,UACA,MACoB;AACpB,UAAM,OAAgC,EAAE,WAAW,SAAS;AAC5D,QAAI,MAAM,UAAW,MAAK,aAAa,KAAK;AAC5C,QAAI,MAAM,SAAS,OAAQ,MAAK,WAAW,KAAK;AAChD,QAAI,MAAM,UAAU,OAAQ,MAAK,YAAY,KAAK;AAClD,WAAO,KAAK,QAAQ,eAAe,OAAO,gBAAgB;AAAA,MACxD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,eACJ,SACA,UACsB;AACtB,UAAM,IAAI,WAAW,cAAc,mBAAmB,QAAQ,CAAC,KAAK;AACpE,WAAO,KAAK,QAAQ,eAAe,OAAO,eAAe,CAAC,EAAE;AAAA,EAC9D;AAAA,EAEA,MAAM,gBACJ,SACA,QACA,MACoB;AACpB,UAAM,OAAgC,CAAC;AACvC,QAAI,KAAK,cAAc,OAAW,MAAK,aAAa,KAAK;AACzD,QAAI,KAAK,QAAS,MAAK,WAAW,KAAK;AACvC,QAAI,KAAK,SAAU,MAAK,YAAY,KAAK;AACzC,WAAO,KAAK,QAAQ,eAAe,OAAO,gBAAgB,MAAM,IAAI;AAAA,MAClE,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,gBAAgB,SAAiB,QAA+B;AACpE,UAAM,KAAK,QAAQ,eAAe,OAAO,gBAAgB,MAAM,IAAI;AAAA,MACjE,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,cAAc,OAAgC;AAClD,WAAO,KAAK,QAAQ,cAAc,KAAK,EAAE;AAAA,EAC3C;AAAA,EAEA,MAAM,kBAAkB,OAAuC;AAC7D,WAAO,KAAK,QAAQ,cAAc,KAAK,OAAO;AAAA,EAChD;AAAA;AAAA,EAGA,MAAM,SACJ,SACA,UACA,IACA,MACuB;AACvB,UAAM,SAAS,IAAI,gBAAgB,EAAE,GAAG,CAAC;AACzC,QAAI,KAAM,QAAO,IAAI,QAAQ,IAAI;AACjC,WAAO,KAAK;AAAA,MACV,eAAe,OAAO,SAAS,mBAAmB,QAAQ,CAAC,IAAI,MAAM;AAAA,IACvE;AAAA,EACF;AAAA,EAEA,MAAM,YACJ,SACA,IACA,MACsB;AACtB,UAAM,SAAS,IAAI,gBAAgB,EAAE,GAAG,CAAC;AACzC,QAAI,KAAM,QAAO,IAAI,QAAQ,IAAI;AACjC,WAAO,KAAK,QAAQ,eAAe,OAAO,SAAS,MAAM,EAAE;AAAA,EAC7D;AAAA;AAAA,EAGA,MAAM,WACJ,SACA,MAQC;AACD,WAAO,KAAK;AAAA,MACV,eAAe,OAAO,kBAAkB,mBAAmB,IAAI,CAAC;AAAA,IAClE;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,cAAc,MAA8B;AAChD,WAAO,KAAK,QAAQ,uBAAuB,mBAAmB,IAAI,CAAC,EAAE;AAAA,EACvE;AAAA,EAEA,MAAM,eAAe,QAAkC;AACrD,WAAO,KAAK,QAAQ,kBAAkB,mBAAmB,MAAM,CAAC,EAAE;AAAA,EACpE;AACF;;;ACvfA,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,SAAS,eAAe;AACxB,SAAS,YAAY;AAErB,IAAM,aAAa,KAAK,QAAQ,GAAG,OAAO;AAC1C,IAAM,cAAc,KAAK,YAAY,aAAa;AAOlD,SAAS,aAAqB;AAC5B,MAAI,CAAC,WAAW,WAAW,EAAG,QAAO,CAAC;AACtC,MAAI;AACF,WAAO,KAAK,MAAM,aAAa,aAAa,OAAO,CAAC;AAAA,EACtD,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,YAAY,QAAsB;AACzC,YAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AACzC,gBAAc,aAAa,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,CAAI;AACnE;AAEO,SAAS,aAAqB;AACnC,SACE,QAAQ,IAAI,oBACZ,WAAW,EAAE,YACb;AAEJ;AAEO,SAAS,WAA+B;AAC7C,SAAO,QAAQ,IAAI,qBAAqB,WAAW,EAAE;AACvD;AAEO,SAAS,WAAW,SAAiB,OAAqB;AAC/D,cAAY,EAAE,UAAU,SAAS,MAAM,CAAC;AAC1C;AAEO,SAAS,gBAAwB;AACtC,SAAO;AACT;;;AC9CA,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,gBAAgB;AASzB,SAAS,YAA2B;AAClC,QAAM,QAAQ,SAAS;AACvB,MAAI,CAAC,OAAO;AACV,YAAQ;AAAA,MACN;AAAA,IAEF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO,IAAI,cAAc,WAAW,GAAG,KAAK;AAC9C;AAGO,SAAS,YAAY,MAAiD;AAC3E,MAAI,KAAK,WAAW,GAAG;AACrB,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,QAAQ,KAAK,CAAC;AACpB,MAAI,MAAM,SAAS,GAAG,GAAG;AACvB,UAAM,CAAC,OAAO,GAAG,IAAI,IAAI,MAAM,MAAM,GAAG;AACxC,WAAO,EAAE,OAAO,MAAM,KAAK,KAAK,GAAG,EAAE;AAAA,EACvC;AACA,SAAO,EAAE,OAAO,OAAO,MAAM,KAAK,MAAM,CAAC,EAAE,KAAK,GAAG,EAAE;AACvD;AAEA,SAAS,WAAW,OAAuB;AACzC,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,MAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,CAAC,CAAC;AAC5D,SAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,CAAC,CAAC;AAC9C;AAGA,IAAM,eAAe;AAGrB,eAAe,YACb,QACA,MACyB;AACzB,MAAI;AACF,UAAM,SAAS,MAAM,OAAO,WAAW;AACvC,UAAM,QAAQ,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAChD,QAAI,MAAO,QAAO;AAAA,EACpB,QAAQ;AAAA,EAER;AACA,SAAO,OAAO,cAAc,IAAI;AAClC;AAUA,eAAe,WACb,QACA,OACmD;AACnD,MAAI;AACJ,MAAI;AACF,eAAW,IAAI,IAAI,KAAK,EAAE;AAAA,EAC5B,QAAQ;AACN,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,SAAS,MAAM,4BAA4B;AAC7D,MAAI,WAAW;AACb,UAAM,CAAC,EAAE,MAAM,MAAM,IAAI;AACzB,UAAM,QAAQ,MAAM,YAAY,QAAQ,IAAI;AAC5C,UAAM,MAAM,MAAM,OAAO,eAAe,MAAM;AAC9C,WAAO,EAAE,SAAS,MAAM,IAAI,MAAM,IAAI,KAAK;AAAA,EAC7C;AAGA,QAAM,YAAY,SAAS,MAAM,uBAAuB;AACxD,MAAI,WAAW;AACb,UAAM,CAAC,EAAE,MAAM,IAAI,IAAI;AACvB,UAAM,QAAQ,MAAM,YAAY,QAAQ,IAAI;AAC5C,UAAM,WAAW,OAAO,mBAAmB,KAAK,MAAM,CAAC,CAAC,IAAI;AAC5D,WAAO,EAAE,SAAS,MAAM,IAAI,MAAM,SAAS;AAAA,EAC7C;AAGA,QAAM,cAAc,SAAS,MAAM,4BAA4B;AAC/D,MAAI,aAAa;AACf,UAAM,CAAC,EAAE,SAAS,IAAI,IAAI;AAC1B,UAAM,WAAW,OAAO,mBAAmB,KAAK,MAAM,CAAC,CAAC,IAAI;AAC5D,WAAO,EAAE,SAAS,MAAM,SAAS;AAAA,EACnC;AAEA,SAAO;AACT;AAKA,eAAsB,cACpB,QACA,MAC4C;AAC5C,QAAM,QAAQ,KAAK,CAAC;AACpB,MAAI,UAAU,MAAM,WAAW,SAAS,KAAK,MAAM,WAAW,UAAU,IAAI;AAC1E,UAAM,SAAS,MAAM,WAAW,QAAQ,KAAK;AAC7C,QAAI,OAAQ,QAAO;AACnB,UAAM,IAAI;AAAA,MACR,6BAA6B,KAAK;AAAA;AAAA,IACpC;AAAA,EACF;AACA,QAAM,EAAE,OAAO,KAAK,IAAI,YAAY,IAAI;AACxC,QAAM,IAAI,MAAM,OAAO,aAAa,KAAK;AACzC,SAAO,EAAE,SAAS,EAAE,IAAI,KAAK;AAC/B;AAMA,eAAsB,gBACpB,QACA,OACyB;AACzB,MAAI,MAAM,WAAW,SAAS,KAAK,MAAM,WAAW,UAAU,GAAG;AAC/D,UAAM,SAAS,MAAM,WAAW,QAAQ,KAAK;AAC7C,QAAI,OAAQ,QAAO,EAAE,IAAI,OAAO,QAAQ;AACxC,UAAM,IAAI;AAAA,MACR,6BAA6B,KAAK;AAAA;AAAA,IACpC;AAAA,EACF;AACA,SAAO,OAAO,aAAa,KAAK;AAClC;AAGO,SAAS,aAAa,OAAuB;AAClD,QAAM,QAAQ,MAAM,MAAM,eAAe;AACzC,MAAI,CAAC;AACH,UAAM,IAAI;AAAA,MACR,4BAA4B,KAAK;AAAA,IACnC;AACF,QAAM,CAAC,EAAE,KAAK,IAAI,IAAI;AACtB,QAAM,KAAK,SAAS,MAAM,OAAO,GAAG,IAAI,QAAW,OAAO,GAAG,IAAI;AACjE,SAAO,IAAI,KAAK,KAAK,IAAI,IAAI,EAAE,EAAE,YAAY;AAC/C;AAGA,SAAS,kBAAkB,OAAuB;AAChD,QAAM,IAAI,MAAM,MAAM,YAAY;AAClC,MAAI,EAAG,QAAO,EAAE,CAAC;AACjB,SAAO;AACT;AAGA,eAAe,YAA6B;AAC1C,QAAM,SAAmB,CAAC;AAC1B,mBAAiB,SAAS,QAAQ,OAAO;AACvC,WAAO,KAAK,KAAe;AAAA,EAC7B;AACA,SAAO,OAAO,OAAO,MAAM,EAAE,SAAS,OAAO;AAC/C;AAEA,IAAM,gBAAgB,IAAI,OAAO;AAM1B,SAAS,iBAAiB,SAAwB;AAEvD,UACG,QAAQ,OAAO,EACf,YAAY,+BAA+B,EAC3C,OAAO,mBAAmB,oBAAoB,EAC9C,OAAO,uBAAuB,WAAW,EACzC,OAAO,OAAO,SAAS;AACtB,UAAM,MAAM,KAAK,OAAO,WAAW;AACnC,UAAM,QAAQ,KAAK;AACnB,QAAI,CAAC,OAAO;AACV,cAAQ;AAAA,QACN,8CAEE,MACA;AAAA,MACJ;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,SAAS,IAAI,cAAc,KAAK,KAAK;AAC3C,QAAI;AACF,YAAM,OAAO,MAAM,OAAO,GAAG;AAC7B,iBAAW,KAAK,KAAK;AACrB,cAAQ,IAAI,gBAAgB,KAAK,IAAI,KAAK,KAAK,KAAK,GAAG;AACvD,cAAQ,IAAI,mBAAmB,cAAc,CAAC,EAAE;AAAA,IAClD,SAAS,KAAK;AACZ,cAAQ;AAAA,QACN,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC5D;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,QAAQ,EAChB,YAAY,mBAAmB,EAC/B,OAAO,YAAY;AAClB,UAAM,SAAS,UAAU;AACzB,UAAM,OAAO,MAAM,OAAO,GAAG;AAC7B,YAAQ,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,KAAK,GAAG;AAAA,EAC5C,CAAC;AAGH,UACG,QAAQ,QAAQ,EAChB,YAAY,4BAA4B,EACxC,OAAO,YAAY;AAClB,UAAM,SAAS,UAAU;AACzB,UAAM,SAAS,MAAM,OAAO,WAAW;AACvC,eAAW,KAAK,QAAQ;AACtB,YAAM,MAAM,EAAE,aAAa,YAAY;AACvC,cAAQ,IAAI,GAAG,EAAE,IAAI,IAAK,GAAG,IAAK,EAAE,YAAY,YAAa,EAAE,EAAE,EAAE;AAAA,IACrE;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,IAAI,EACZ,YAAY,qDAAgD,EAC5D,SAAS,aAAa,EACtB,OAAO,mBAAmB,4BAA4B,EACtD,OAAO,OAAO,MAAgB,SAAkC;AAC/D,UAAM,SAAS,UAAU;AACzB,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc,QAAQ,IAAI;AAC1D,UAAM,UAAU,KAAK,YACjB,MAAM,OAAO,SAAS,OAAO,IAC7B,MAAM,OAAO,GAAG,SAAS,IAAI;AACjC,QAAI,QAAQ,WAAW,GAAG;AACxB,cAAQ,IAAI,SAAS;AACrB;AAAA,IACF;AACA,eAAW,KAAK,SAAS;AACvB,UAAI,EAAE,SAAS,QAAQ;AACrB,gBAAQ,IAAI,GAAG,EAAE,IAAI,GAAG;AAAA,MAC1B,OAAO;AACL,gBAAQ,IAAI,GAAG,EAAE,IAAI,IAAK,WAAW,EAAE,IAAI,CAAC,EAAE;AAAA,MAChD;AAAA,IACF;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,KAAK,EACb,YAAY,2DAAsD,EAClE,SAAS,aAAa,EACtB,OAAO,SAAS,+BAA+B,EAC/C,OAAO,OAAO,MAAgB,SAA4B;AACzD,UAAM,SAAS,UAAU;AACzB,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc,QAAQ,IAAI;AAC1D,QAAI,CAAC,MAAM;AACT,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,QAAI,KAAK,KAAK;AACZ,YAAM,SAAS,MAAM,OAAO,WAAW,SAAS,IAAI;AACpD,cAAQ,MAAM,QAAQ,OAAO,GAAG,EAAE;AAClC,cAAQ,OAAO,MAAM,OAAO,OAAO;AAAA,IACrC,OAAO;AACL,YAAM,UAAU,MAAM,OAAO,IAAI,SAAS,IAAI;AAC9C,cAAQ,OAAO,MAAM,OAAO;AAAA,IAC9B;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA,EACF,EACC,SAAS,UAAU,sBAAsB,EACzC,SAAS,aAAa,EACtB,OAAO,OAAO,MAAc,SAAmB;AAC9C,UAAM,SAAS,UAAU;AACzB,UAAM,EAAE,SAAS,MAAM,IAAI,IAAI,MAAM,cAAc,QAAQ,IAAI;AAC/D,UAAM,UAAUC,cAAa,IAAI;AACjC,UAAM,WAAW,SAAS,IAAI;AAC9B,UAAM,YAAY,OAAO;AACzB,UAAM,SAAS,MAAM,OAAO,OAAO,SAAS,WAAW,UAAU,OAAO;AACxE,YAAQ,IAAI,aAAa,OAAO,IAAI,EAAE;AAAA,EACxC,CAAC;AAGH,UACG,QAAQ,OAAO,EACf;AAAA,IACC;AAAA,EACF,EACC,SAAS,YAAY,oCAAoC,EACzD,SAAS,aAAa,+BAA+B,EACrD,OAAO,WAAW,yBAAyB,EAC3C,OAAO,uBAAuB,uBAAuB,EACrD;AAAA,IACC,OACE,QACA,SACA,SACG;AACH,YAAM,SAAS,UAAU;AACzB,YAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc,QAAQ,CAAC,MAAM,CAAC;AAC9D,UAAI,CAAC,MAAM;AACT,gBAAQ;AAAA,UACN;AAAA,QACF;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM,OAAO,YAAY,MAAM,MAAM,UAAU,IAAI;AAEnD,UAAI,OAAO,WAAW,MAAM,OAAO,IAAI,eAAe;AACpD,gBAAQ;AAAA,UACN;AAAA,QACF;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,UAAI;AACJ,UAAI,CAAC,KAAK,OAAO;AACf,YAAI;AACF,gBAAM,WAAW,MAAM,OAAO,WAAW,SAAS,IAAI;AACtD,oBAAU,SAAS;AAAA,QACrB,SAAS,KAAK;AACZ,gBAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,cAAI,CAAC,IAAI,SAAS,KAAK,EAAG,OAAM;AAAA,QAClC;AAAA,MACF;AAEA,UAAI;AACF,cAAM,SAAS,MAAM,OAAO,KAAK,SAAS,MAAM,MAAM;AAAA,UACpD;AAAA,UACA,SAAS,KAAK;AAAA,QAChB,CAAC;AACD,gBAAQ,IAAI,YAAY,OAAO,IAAI,UAAU,OAAO,GAAG,GAAG;AAAA,MAC5D,SAAS,KAAK;AACZ,YAAI,eAAe,eAAe;AAChC,kBAAQ;AAAA,YACN;AAAA,UACF;AACA,kBAAQ,KAAK,CAAC;AAAA,QAChB;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGF,UACG,QAAQ,OAAO,EACf,YAAY,yDAAoD,EAChE,SAAS,aAAa,EACtB,OAAO,OAAO,SAAmB;AAChC,UAAM,SAAS,UAAU;AACzB,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc,QAAQ,IAAI;AAC1D,QAAI,CAAC,MAAM;AACT,cAAQ,MAAM,0BAA0B;AACxC,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,OAAO,MAAM,SAAS,IAAI;AAChC,YAAQ,IAAI,YAAY,IAAI,EAAE;AAAA,EAChC,CAAC;AAGH,UACG,QAAQ,IAAI,EACZ,YAAY,2DAAsD,EAClE,SAAS,aAAa,EACtB,OAAO,OAAO,SAAmB;AAChC,UAAM,SAAS,UAAU;AACzB,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc,QAAQ,IAAI;AAC1D,QAAI,CAAC,MAAM;AACT,cAAQ,MAAM,0BAA0B;AACxC,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,OAAO,GAAG,SAAS,IAAI;AAC7B,YAAQ,IAAI,YAAY,IAAI,uCAAuC;AAAA,EACrE,CAAC;AAGH,UACG,QAAQ,IAAI,EACZ,YAAY,8DAAyD,EACrE,SAAS,YAAY,6BAA6B,EAClD,SAAS,QAAQ,UAAU,EAC3B,OAAO,OAAO,QAAgB,OAAe;AAC5C,UAAM,SAAS,UAAU;AACzB,UAAM,EAAE,SAAS,MAAM,KAAK,IAAI,MAAM,cAAc,QAAQ,CAAC,MAAM,CAAC;AACpE,QAAI,CAAC,MAAM;AACT,cAAQ,MAAM,iCAAiC;AAC/C,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,OAAO,GAAG,SAAS,MAAM,EAAE;AACjC,YAAQ,IAAI,UAAU,IAAI,WAAM,EAAE,EAAE;AAAA,EACtC,CAAC;AAGH,UACG,QAAQ,KAAK,EACb,YAAY,+DAA0D,EACtE,SAAS,aAAa,EACtB,OAAO,OAAO,SAAmB;AAChC,UAAM,SAAS,UAAU;AACzB,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc,QAAQ,IAAI;AAC1D,UAAM,OAAO,MAAM,OAAO,IAAI,SAAS,QAAQ,MAAS;AACxD,QAAI,KAAK,WAAW,GAAG;AACrB,cAAQ,IAAI,aAAa;AACzB;AAAA,IACF;AACA,eAAW,KAAK,MAAM;AACpB,cAAQ,IAAI,GAAG,EAAE,IAAI,KAAK,EAAE,IAAI,KAAK,EAAE,OAAO,EAAE;AAAA,IAClD;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,UAAU,EAClB;AAAA,IACC;AAAA,EACF,EACC,SAAS,YAAY,yBAAyB,EAC9C,SAAS,YAAY,4BAA4B,EACjD,OAAO,OAAO,QAAgB,WAAmB;AAChD,UAAM,SAAS,UAAU;AACzB,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc,QAAQ,CAAC,MAAM,CAAC;AAC9D,QAAI,CAAC,MAAM;AACT,cAAQ,MAAM,+BAA+B;AAC7C,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,OAAO,SAAS,SAAS,MAAM,MAAM;AAC3C,YAAQ,IAAI,gBAAgB,IAAI,WAAM,OAAO,UAAU,GAAG,CAAC,CAAC,EAAE;AAAA,EAChE,CAAC;AAGH,UACG,QAAQ,OAAO,EACf,YAAY,8CAAyC,EACrD,SAAS,SAAS,EAClB,OAAO,OAAO,cAAsB;AACnC,UAAM,SAAS,UAAU;AACzB,UAAM,IAAI,MAAM,gBAAgB,QAAQ,SAAS;AACjD,UAAM,QAAQ,MAAM,OAAO,MAAM,EAAE,EAAE;AACrC,QAAI,MAAM,WAAW,GAAG;AACtB,cAAQ,IAAI,iBAAiB;AAC7B;AAAA,IACF;AACA,eAAW,KAAK,OAAO;AACrB,cAAQ;AAAA,QACN,GAAG,EAAE,IAAI,YAAa,EAAE,UAAU,IAAK,EAAE,OAAO,UAAU,GAAG,CAAC,CAAC;AAAA,MACjE;AAAA,IACF;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,SAAS,EACjB;AAAA,IACC;AAAA,EACF,EACC,SAAS,YAAY,yBAAyB,EAC9C,SAAS,YAAY,gCAAgC,EACrD,OAAO,OAAO,QAAgB,WAAmB;AAChD,UAAM,SAAS,UAAU;AACzB,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc,QAAQ,CAAC,MAAM,CAAC;AAC9D,QAAI,CAAC,MAAM;AACT,cAAQ,MAAM,0BAA0B;AACxC,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,OAAO,QAAQ,SAAS,MAAM,MAAM;AAC1C,YAAQ,IAAI,aAAa,IAAI,EAAE;AAAA,EACjC,CAAC;AAGH,QAAM,UAAU,QACb,QAAQ,SAAS,EACjB,YAAY,sBAAsB;AAErC,UACG,QAAQ,MAAM,EACd,YAAY,uDAAkD,EAC9D,SAAS,aAAa,EACtB,OAAO,OAAO,SAAmB;AAChC,UAAM,SAAS,UAAU;AACzB,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc,QAAQ,IAAI;AAC1D,QAAI,CAAC,MAAM;AACT,cAAQ,MAAM,+BAA+B;AAC7C,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,WAAW,MAAM,OAAO,aAAa,SAAS,IAAI;AACxD,QAAI,SAAS,WAAW,GAAG;AACzB,cAAQ,IAAI,cAAc;AAC1B;AAAA,IACF;AACA,eAAW,KAAK,UAAU;AACxB,YAAM,SAAS,EAAE,YAAY,cAAc;AAC3C,cAAQ,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,KAAK,EAAE,UAAU,IAAI,MAAM,EAAE;AAChE,cAAQ,IAAI,KAAK,EAAE,OAAO,EAAE;AAC5B,iBAAW,KAAK,EAAE,SAAS;AACzB,gBAAQ,IAAI,cAAS,EAAE,SAAS,KAAK,EAAE,OAAO,EAAE;AAAA,MAClD;AAAA,IACF;AAAA,EACF,CAAC;AAEH,UACG,QAAQ,KAAK,EACb;AAAA,IACC;AAAA,EACF,EACC,SAAS,YAAY,yBAAyB,EAC9C,SAAS,aAAa,+BAA+B,EACrD,OAAO,OAAO,QAAgB,YAAoB;AACjD,UAAM,SAAS,UAAU;AACzB,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc,QAAQ,CAAC,MAAM,CAAC;AAC9D,QAAI,CAAC,MAAM;AACT,cAAQ,MAAM,+BAA+B;AAC7C,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,OAAO,YAAY,MAAM,MAAM,UAAU,IAAI;AACnD,UAAM,IAAI,MAAM,OAAO,cAAc,SAAS,MAAM,IAAI;AACxD,YAAQ,IAAI,YAAY,EAAE,EAAE,WAAW;AAAA,EACzC,CAAC;AAEH,UACG,QAAQ,OAAO,EACf;AAAA,IACC;AAAA,EACF,EACC,SAAS,SAAS,EAClB,SAAS,aAAa,EACtB,SAAS,aAAa,6BAA6B,EACnD,OAAO,OAAO,WAAmB,WAAmB,YAAoB;AACvE,UAAM,SAAS,UAAU;AACzB,UAAM,IAAI,MAAM,gBAAgB,QAAQ,SAAS;AACjD,UAAM,OAAO,YAAY,MAAM,MAAM,UAAU,IAAI;AACnD,UAAM,IAAI,MAAM,OAAO,aAAa,EAAE,IAAI,OAAO,SAAS,GAAG,IAAI;AACjE,YAAQ,IAAI,UAAU,EAAE,EAAE,WAAW;AAAA,EACvC,CAAC;AAEH,UACG,QAAQ,OAAO,EACf,YAAY,6DAAwD,EACpE,SAAS,SAAS,EAClB,SAAS,aAAa,EACtB,OAAO,OAAO,WAAmB,cAAsB;AACtD,UAAM,SAAS,UAAU;AACzB,UAAM,IAAI,MAAM,gBAAgB,QAAQ,SAAS;AACjD,UAAM,OAAO,aAAa,EAAE,IAAI,OAAO,SAAS,CAAC;AACjD,YAAQ,IAAI,YAAY,SAAS,UAAU;AAAA,EAC7C,CAAC;AAEH,UACG,QAAQ,IAAI,EACZ,YAAY,2DAAsD,EAClE,SAAS,SAAS,EAClB,SAAS,aAAa,EACtB,OAAO,OAAO,WAAmB,cAAsB;AACtD,UAAM,SAAS,UAAU;AACzB,UAAM,IAAI,MAAM,gBAAgB,QAAQ,SAAS;AACjD,UAAM,OAAO,cAAc,EAAE,IAAI,OAAO,SAAS,CAAC;AAClD,YAAQ,IAAI,YAAY,SAAS,WAAW;AAAA,EAC9C,CAAC;AAGH,QAAM,QAAQ,QAAQ,QAAQ,OAAO,EAAE,YAAY,oBAAoB;AAEvE,QACG,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA,EACF,EACC,SAAS,YAAY,yBAAyB,EAC9C,OAAO,wBAAwB,gCAAgC,EAC/D,OAAO,oBAAoB,oCAAoC,EAC/D,OAAO,kBAAkB,2BAA2B,EACpD;AAAA,IACC,OACE,QACA,SACG;AACH,YAAM,SAAS,UAAU;AACzB,YAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc,QAAQ,CAAC,MAAM,CAAC;AAC9D,UAAI,CAAC,MAAM;AACT,gBAAQ;AAAA,UACN;AAAA,QACF;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM,UAIF,CAAC;AACL,UAAI,KAAK,QAAS,SAAQ,YAAY,aAAa,KAAK,OAAO;AAC/D,UAAI,KAAK;AACP,gBAAQ,UAAU,KAAK,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAC7D,UAAI,KAAK;AACP,gBAAQ,WAAW,KAAK,OAAO,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAC/D,YAAM,OAAO,MAAM,OAAO,gBAAgB,SAAS,MAAM,OAAO;AAChE,YAAM,UAAU,WAAW;AAC3B,cAAQ,IAAI,qBAAqB;AACjC,cAAQ,IAAI,cAAc,KAAK,EAAE,EAAE;AACnC,cAAQ,IAAI,cAAc,KAAK,KAAK,EAAE;AACtC,cAAQ,IAAI,cAAc,OAAO,UAAU,KAAK,KAAK,EAAE;AACvD,cAAQ,IAAI,cAAc,KAAK,cAAc,OAAO,EAAE;AACtD,UAAI,KAAK,UAAU;AACjB,gBAAQ,IAAI,cAAc,KAAK,SAAS,KAAK,IAAI,CAAC,EAAE;AACtD,UAAI,KAAK,WAAW;AAClB,gBAAQ,IAAI,cAAc,KAAK,UAAU,MAAM,EAAE;AAAA,IACrD;AAAA,EACF;AAEF,QACG,QAAQ,MAAM,EACd,YAAY,iDAA4C,EACxD,SAAS,SAAS,EAClB,OAAO,iBAAiB,qBAAqB,EAC7C,OAAO,OAAO,WAAmB,SAA4B;AAC5D,UAAM,SAAS,UAAU;AACzB,UAAM,IAAI,MAAM,gBAAgB,QAAQ,SAAS;AACjD,UAAM,QAAQ,MAAM,OAAO,eAAe,EAAE,IAAI,KAAK,IAAI;AACzD,QAAI,MAAM,WAAW,GAAG;AACtB,cAAQ,IAAI,iBAAiB;AAC7B;AAAA,IACF;AACA,eAAW,KAAK,OAAO;AACrB,YAAM,UAAU,EAAE,cAAc;AAChC,YAAM,UAAU,EAAE,mBAAmB,EAAE,oBAAoB,EAAE;AAC7D,cAAQ;AAAA,QACN,GAAG,EAAE,EAAE,IAAK,EAAE,KAAK,IAAK,EAAE,SAAS,IAAK,OAAO,IAAK,OAAO;AAAA,MAC7D;AAAA,IACF;AAAA,EACF,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,8DAAyD,EACrE,SAAS,SAAS,EAClB,SAAS,UAAU,EACnB,OAAO,wBAAwB,gCAAgC,EAC/D,OAAO,oBAAoB,oCAAoC,EAC/D,OAAO,kBAAkB,2BAA2B,EACpD;AAAA,IACC,OACE,WACA,QACA,SACG;AACH,YAAM,SAAS,UAAU;AACzB,YAAM,IAAI,MAAM,gBAAgB,QAAQ,SAAS;AACjD,YAAM,UAIF,CAAC;AACL,UAAI,KAAK,QAAS,SAAQ,YAAY,aAAa,KAAK,OAAO;AAC/D,UAAI,KAAK;AACP,gBAAQ,UAAU,KAAK,MAAM,MAAM,GAAG,EAAE,IAAI,CAACC,OAAMA,GAAE,KAAK,CAAC;AAC7D,UAAI,KAAK;AACP,gBAAQ,WAAW,KAAK,OAAO,MAAM,GAAG,EAAE,IAAI,CAACA,OAAMA,GAAE,KAAK,CAAC;AAC/D,YAAM,OAAO,gBAAgB,EAAE,IAAI,QAAQ,OAAO;AAClD,cAAQ,IAAI,uBAAuB,MAAM,EAAE;AAAA,IAC7C;AAAA,EACF;AAEF,QACG,QAAQ,KAAK,EACb,YAAY,uDAAkD,EAC9D,SAAS,WAAW,yBAAyB,EAC7C,OAAO,SAAS,yBAAyB,EACzC,OAAO,OAAO,UAAkB,SAA4B;AAC3D,UAAM,SAAS,UAAU;AACzB,UAAM,QAAQ,kBAAkB,QAAQ;AACxC,QAAI,CAAC,KAAK,KAAK;AACb,UAAI;AACF,cAAM,OAAO,MAAM,OAAO,kBAAkB,KAAK;AACjD,gBAAQ,IAAI,SAAS,KAAK,SAAS,KAAK,KAAK,UAAU,GAAG;AAC1D,gBAAQ;AAAA,UACN,cAAc,KAAK,eAAe,eAAe,KAAK,cAAc,OAAO;AAAA,QAC7E;AACA,gBAAQ,IAAI,KAAK;AAAA,MACnB,SAAS,KAAK;AACZ,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAI,CAAC,IAAI,SAAS,KAAK,GAAG;AACxB,kBAAQ,MAAM,wCAAwC,GAAG,EAAE;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AACA,UAAM,UAAU,MAAM,OAAO,cAAc,KAAK;AAChD,YAAQ,OAAO,MAAM,OAAO;AAAA,EAC9B,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,4DAAuD,EACnE,SAAS,WAAW,yBAAyB,EAC7C,OAAO,OAAO,aAAqB;AAClC,UAAM,SAAS,UAAU;AACzB,UAAM,QAAQ,kBAAkB,QAAQ;AACxC,UAAM,OAAO,MAAM,OAAO,kBAAkB,KAAK;AACjD,YAAQ,IAAI,eAAe,KAAK,SAAS,EAAE;AAC3C,YAAQ,IAAI,eAAe,KAAK,UAAU,EAAE;AAC5C,YAAQ,IAAI,eAAe,KAAK,eAAe,EAAE;AACjD,YAAQ,IAAI,eAAe,KAAK,cAAc,OAAO,EAAE;AAAA,EACzD,CAAC;AAEH,QACG,QAAQ,IAAI,EACZ,YAAY,0DAAqD,EACjE,SAAS,SAAS,EAClB,SAAS,UAAU,EACnB,OAAO,OAAO,WAAmB,WAAmB;AACnD,UAAM,SAAS,UAAU;AACzB,UAAM,IAAI,MAAM,gBAAgB,QAAQ,SAAS;AACjD,UAAM,OAAO,gBAAgB,EAAE,IAAI,MAAM;AACzC,YAAQ,IAAI,uBAAuB,MAAM,EAAE;AAAA,EAC7C,CAAC;AAGH,UACG,QAAQ,WAAW,EACnB,YAAY,6DAAwD,EACpE,SAAS,aAAa,EACtB,OAAO,OAAO,SAAmB;AAChC,UAAM,SAAS,UAAU;AACzB,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc,QAAQ,IAAI;AAC1D,QAAI,CAAC,MAAM;AACT,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,MAAM,MAAM,OAAO,WAAW,SAAS,IAAI;AACjD,YAAQ,IAAI,IAAI,GAAG;AAAA,EACrB,CAAC;AAGH,UACG,QAAQ,MAAM,EACd;AAAA,IACC;AAAA,EACF,EACC,SAAS,YAAY,kCAAkC,EACvD,SAAS,QAAQ,aAAa,EAC9B,SAAS,UAAU,iCAAiC,EACpD,OAAO,OAAO,QAAgB,IAAY,SAAkB;AAC3D,UAAM,SAAS,UAAU;AACzB,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,cAAc,QAAQ,CAAC,MAAM,CAAC;AAC9D,QAAI,MAAM;AACR,YAAM,SAAS,MAAM,OAAO,SAAS,SAAS,MAAM,IAAI,IAAI;AAC5D,UAAI,OAAO,MAAM;AACf,gBAAQ,OAAO,MAAM,OAAO,IAAI;AAAA,MAClC,OAAO;AACL,gBAAQ,IAAI,aAAa;AAAA,MAC3B;AAAA,IACF,OAAO;AACL,YAAM,SAAS,MAAM,OAAO,YAAY,SAAS,IAAI,IAAI;AACzD,UAAI,OAAO,MAAM,WAAW,GAAG;AAC7B,gBAAQ,IAAI,aAAa;AACzB;AAAA,MACF;AACA,iBAAW,KAAK,OAAO,OAAO;AAC5B,gBAAQ,IAAI,GAAG,EAAE,MAAM,KAAK,EAAE,IAAI,EAAE;AAAA,MACtC;AAAA,IACF;AAAA,EACF,CAAC;AACL;","names":["s","readFileSync","readFileSync","s"]}
package/dist/index.js CHANGED
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  registerCommands
4
- } from "./chunk-XUT76ACQ.js";
4
+ } from "./chunk-CMQUBTWI.js";
5
5
 
6
6
  // src/index.ts
7
7
  import { Command } from "commander";
8
8
  var program = new Command();
9
- program.name("docz").description("DocSync CLI \u2014 read and write company documents").version("0.6.0");
9
+ program.name("docz").description("DocSync CLI \u2014 read and write company documents").version("0.7.1");
10
10
  registerCommands(program);
11
11
  program.command("mcp").description("Start MCP stdio server for AI agent integration").action(async () => {
12
- const { startMcpServer } = await import("./mcp-OHEL4DCQ.js");
12
+ const { startMcpServer } = await import("./mcp-2GVCCDXP.js");
13
13
  await startMcpServer();
14
14
  });
15
15
  program.parse();
@@ -5,7 +5,7 @@ import {
5
5
  getBaseUrl,
6
6
  getToken,
7
7
  parseExpires
8
- } from "./chunk-XUT76ACQ.js";
8
+ } from "./chunk-CMQUBTWI.js";
9
9
 
10
10
  // src/mcp.ts
11
11
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -682,4 +682,4 @@ Space: ${info.space_name}
682
682
  export {
683
683
  startMcpServer
684
684
  };
685
- //# sourceMappingURL=mcp-OHEL4DCQ.js.map
685
+ //# sourceMappingURL=mcp-2GVCCDXP.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docz-cli",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "DocSync CLI — read and write company documents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -26,22 +26,13 @@
26
26
  "file-sync",
27
27
  "document"
28
28
  ],
29
- "scripts": {
30
- "build": "tsup",
31
- "dev": "tsup --watch",
32
- "typecheck": "tsc --noEmit",
33
- "test": "vitest run",
34
- "test:watch": "vitest",
35
- "lint": "biome check",
36
- "lint:fix": "biome check --write",
37
- "clean": "rm -rf dist node_modules"
38
- },
39
29
  "dependencies": {
40
30
  "@modelcontextprotocol/sdk": "^1.28.0",
41
31
  "commander": "^13.1.0"
42
32
  },
43
33
  "devDependencies": {
44
34
  "@biomejs/biome": "2.2.0",
35
+ "@changesets/cli": "^2.31.0",
45
36
  "@types/node": "^22.15.0",
46
37
  "msw": "^2.8.4",
47
38
  "tsup": "^8.4.0",
@@ -50,5 +41,18 @@
50
41
  },
51
42
  "engines": {
52
43
  "node": ">=22.0.0"
44
+ },
45
+ "scripts": {
46
+ "build": "tsup",
47
+ "dev": "tsup --watch",
48
+ "typecheck": "tsc --noEmit",
49
+ "test": "vitest run",
50
+ "test:watch": "vitest",
51
+ "lint": "biome check",
52
+ "lint:fix": "biome check --write",
53
+ "clean": "rm -rf dist node_modules",
54
+ "changeset": "changeset",
55
+ "version": "changeset version",
56
+ "release": "pnpm build && changeset publish"
53
57
  }
54
- }
58
+ }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/client.ts","../src/config.ts","../src/commands.ts"],"sourcesContent":["/**\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 slug?: 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\nexport interface ShareLink {\n id: string;\n token: string;\n space_id: string;\n file_path: string;\n created_by: string;\n created_by_name?: string;\n created_by_email?: string;\n expires_at: string | null;\n created_at: string;\n user_ids?: string[];\n group_ids?: string[];\n}\n\nexport interface ShareFileInfo {\n file_path: string;\n file_name: string;\n space_name: string;\n created_by_name: string;\n expires_at: string | null;\n}\n\nexport interface DiffResponse {\n from: string;\n to: string;\n path: string;\n diff: string;\n old_body: string;\n new_body: string;\n}\n\nexport interface DiffFileEntry {\n path: string;\n status: string;\n}\n\nexport interface DiffSummary {\n from: string;\n to: string;\n files: DiffFileEntry[];\n}\n\nexport interface FileRef {\n id: string;\n space_id: string;\n path: string;\n}\n\nexport interface CatResult {\n content: string;\n ref: string;\n}\n\nexport interface SaveResult {\n path: string;\n ref: string;\n}\n\nexport interface SaveConflict {\n error: 'conflict';\n current_ref: string;\n path: string;\n}\n\nexport interface Comment {\n id: number;\n space_id: string;\n file_path: string;\n comment_type: string;\n target_type: string;\n target_selector: string;\n target_content: string;\n content: string;\n user_id: string;\n user_name: string;\n user_email: string;\n is_closed: boolean;\n created_at: string;\n updated_at: string;\n replies: CommentReply[];\n}\n\nexport interface CommentReply {\n id: number;\n comment_id: number;\n content: string;\n user_id: string;\n user_name: string;\n user_email: string;\n created_at: string;\n updated_at: string;\n}\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class ConflictError extends Error {\n constructor(public readonly detail: SaveConflict) {\n super(\n 'Conflict: file has been modified by others. Please re-read the latest content and re-apply your changes.'\n );\n this.name = 'ConflictError';\n }\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 async treeFull(spaceId: string): Promise<TreeEntry[]> {\n return this.request(`/api/spaces/${spaceId}/tree/full`);\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 async catWithRef(spaceId: string, filepath: string): Promise<CatResult> {\n const res = await fetch(\n `${this.baseUrl}/api/spaces/${spaceId}/blob/${encodeURIComponent(filepath)}`,\n { headers: { Authorization: `Bearer ${this.token}` } }\n );\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new Error(`${res.status} ${res.statusText}: ${body}`.trim());\n }\n const content = await res.text();\n const ref = res.headers.get('X-Git-Ref') ?? '';\n return { content, ref };\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 save(\n spaceId: string,\n path: string,\n content: string,\n opts?: { baseRef?: string; message?: string }\n ): Promise<SaveResult> {\n const body: Record<string, string> = { path, content };\n if (opts?.baseRef) body.base_ref = opts.baseRef;\n if (opts?.message) body.message = opts.message;\n\n const res = await fetch(\n `${this.baseUrl}/api/spaces/${spaceId}/files/save`,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n }\n );\n\n if (res.status === 409) {\n const data = (await res.json()) as SaveConflict;\n throw new ConflictError(data);\n }\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`${res.status} ${res.statusText}: ${text}`.trim());\n }\n\n return res.json() as Promise<SaveResult>;\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 async rollback(\n spaceId: string,\n filePath: string,\n commitHash: string\n ): Promise<void> {\n await this.request(`/api/spaces/${spaceId}/files/rollback`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ file_path: filePath, commit_hash: commitHash }),\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 async restore(spaceId: string, path: string, commit: string): Promise<void> {\n await this.request(`/api/spaces/${spaceId}/trash/restore`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ path, commit }),\n });\n }\n\n // --- Comments ---\n async listComments(spaceId: string, filePath: string): Promise<Comment[]> {\n return this.request(\n `/api/spaces/${spaceId}/comments?path=${encodeURIComponent(filePath)}`\n );\n }\n\n async createComment(\n spaceId: string,\n filePath: string,\n content: string\n ): Promise<Comment> {\n return this.request(`/api/spaces/${spaceId}/comments`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ file_path: filePath, content }),\n });\n }\n\n async replyComment(\n spaceId: string,\n commentId: number,\n content: string\n ): Promise<CommentReply> {\n return this.request(\n `/api/spaces/${spaceId}/comments/${commentId}/replies`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ content }),\n }\n );\n }\n\n async closeComment(spaceId: string, commentId: number): Promise<Comment> {\n return this.request(`/api/spaces/${spaceId}/comments/${commentId}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ is_closed: true }),\n });\n }\n\n async deleteComment(spaceId: string, commentId: number): Promise<void> {\n await this.request(`/api/spaces/${spaceId}/comments/${commentId}`, {\n method: 'DELETE',\n });\n }\n\n // --- Share Links ---\n async createShareLink(\n spaceId: string,\n filePath: string,\n opts?: { expiresAt?: string; userIds?: string[]; groupIds?: string[] }\n ): Promise<ShareLink> {\n const body: Record<string, unknown> = { file_path: filePath };\n if (opts?.expiresAt) body.expires_at = opts.expiresAt;\n if (opts?.userIds?.length) body.user_ids = opts.userIds;\n if (opts?.groupIds?.length) body.group_ids = opts.groupIds;\n return this.request(`/api/spaces/${spaceId}/share-links`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n }\n\n async listShareLinks(\n spaceId: string,\n filePath?: string\n ): Promise<ShareLink[]> {\n const q = filePath ? `?file_path=${encodeURIComponent(filePath)}` : '';\n return this.request(`/api/spaces/${spaceId}/share-links${q}`);\n }\n\n async updateShareLink(\n spaceId: string,\n linkId: string,\n opts: { expiresAt?: string; userIds?: string[]; groupIds?: string[] }\n ): Promise<ShareLink> {\n const body: Record<string, unknown> = {};\n if (opts.expiresAt !== undefined) body.expires_at = opts.expiresAt;\n if (opts.userIds) body.user_ids = opts.userIds;\n if (opts.groupIds) body.group_ids = opts.groupIds;\n return this.request(`/api/spaces/${spaceId}/share-links/${linkId}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n }\n\n async deleteShareLink(spaceId: string, linkId: string): Promise<void> {\n await this.request(`/api/spaces/${spaceId}/share-links/${linkId}`, {\n method: 'DELETE',\n });\n }\n\n async getSharedFile(token: string): Promise<string> {\n return this.request(`/api/share/${token}`);\n }\n\n async getSharedFileInfo(token: string): Promise<ShareFileInfo> {\n return this.request(`/api/share/${token}/info`);\n }\n\n // --- Diff ---\n async diffFile(\n spaceId: string,\n filePath: string,\n to: string,\n from?: string\n ): Promise<DiffResponse> {\n const params = new URLSearchParams({ to });\n if (from) params.set('from', from);\n return this.request(\n `/api/spaces/${spaceId}/diff/${encodeURIComponent(filePath)}?${params}`\n );\n }\n\n async diffSummary(\n spaceId: string,\n to: string,\n from?: string\n ): Promise<DiffSummary> {\n const params = new URLSearchParams({ to });\n if (from) params.set('from', from);\n return this.request(`/api/spaces/${spaceId}/diff?${params}`);\n }\n\n // --- File Ref ---\n async getFileRef(\n spaceId: string,\n path: string\n ): Promise<{\n id: string;\n space_id: string;\n slug: string;\n path: string;\n is_dir: boolean;\n url: string;\n }> {\n return this.request(\n `/api/spaces/${spaceId}/file-ref?path=${encodeURIComponent(path)}`\n );\n }\n\n // --- Resolve short URLs ---\n async resolveBySlug(slug: string): Promise<Space> {\n return this.request(`/api/spaces/by-slug/${encodeURIComponent(slug)}`);\n }\n\n async resolveFileRef(fileId: string): Promise<FileRef> {\n return this.request(`/api/file-refs/${encodeURIComponent(fileId)}`);\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","/**\n * CLI Commands\n */\n\nimport { readFileSync } from 'node:fs';\nimport { basename } from 'node:path';\nimport type { Command } from 'commander';\nimport { ConflictError, 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// Short URL patterns: /s/{slug}/f/{fileId} or /s/{slug}\nconst SHORT_URL_RE = /\\/s\\/([^/]+)\\/f\\/([^/?\\s]+)/;\nconst SLUG_ONLY_RE = /\\/s\\/([^/?\\s]+)\\/?(?:\\?.*)?$/;\n// Share URL: /share/{token}\nconst SHARE_URL_RE = /\\/share\\/([^/?\\s]+)/;\n\n/**\n * Detect if input is a URL and resolve it to { spaceId, path }.\n * Returns null if not a URL.\n */\nasync function resolveUrl(\n client: DocSyncClient,\n input: string\n): Promise<{ spaceId: string; path: string } | null> {\n // Match /s/{slug}/f/{fileId}\n const fileMatch = input.match(SHORT_URL_RE);\n if (fileMatch) {\n const [, slug, fileId] = fileMatch;\n const space = await resolveSlug(client, slug);\n const ref = await client.resolveFileRef(fileId);\n return { spaceId: space.id, path: ref.path };\n }\n // Match /s/{slug} (directory listing)\n const slugMatch = input.match(SLUG_ONLY_RE);\n if (slugMatch) {\n const [, slug] = slugMatch;\n const space = await resolveSlug(client, slug);\n return { spaceId: space.id, path: '' };\n }\n return null;\n}\n\n/** Resolve slug: try local spaces cache first, then API */\nasync function resolveSlug(\n client: DocSyncClient,\n slug: string\n): Promise<{ id: string }> {\n try {\n const spaces = await client.listSpaces();\n const found = spaces.find((s) => s.slug === slug);\n if (found) return found;\n } catch {\n // fall through to by-slug API\n }\n return client.resolveBySlug(slug);\n}\n\n/**\n * Resolve target: if it's a short URL, resolve it; otherwise use parseTarget + resolveSpace.\n */\nasync function resolveTarget(\n client: DocSyncClient,\n args: string[]\n): Promise<{ spaceId: string; path: string }> {\n const first = args[0];\n if (first && (first.startsWith('http://') || first.startsWith('https://'))) {\n const result = await resolveUrl(client, first);\n if (result) return result;\n }\n const { space, path } = parseTarget(args);\n const s = await client.resolveSpace(space);\n return { spaceId: s.id, path };\n}\n\n/** Parse relative duration (7d, 24h, 30d) to RFC3339 */\nexport function parseExpires(value: string): string {\n const match = value.match(/^(\\d+)([dh])$/);\n if (!match)\n throw new Error(\n `Invalid expires format: \"${value}\". Use e.g. 7d, 24h, 30d`\n );\n const [, num, unit] = match;\n const ms = unit === 'd' ? Number(num) * 86400000 : Number(num) * 3600000;\n return new Date(Date.now() + ms).toISOString();\n}\n\n/** Extract share token from URL or return as-is */\nfunction extractShareToken(input: string): string {\n const m = input.match(SHARE_URL_RE);\n if (m) return m[1];\n return input;\n}\n\n/** Read all of stdin into a string */\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString('utf-8');\n}\n\nconst MAX_SAVE_SIZE = 2 * 1024 * 1024; // 2MB\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 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>] or <url>')\n .argument('<target...>')\n .option('-R, --recursive', 'Recursively list all files')\n .action(async (args: string[], opts: { recursive?: boolean }) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, args);\n const entries = opts.recursive\n ? await client.treeFull(spaceId)\n : await client.ls(spaceId, 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> or <url>')\n .argument('<target...>')\n .option('--ref', 'Also output Git ref to stderr')\n .action(async (args: string[], opts: { ref?: boolean }) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, 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 if (opts.ref) {\n const result = await client.catWithRef(spaceId, path);\n console.error(`ref: ${result.ref}`);\n process.stdout.write(result.content);\n } else {\n const content = await client.cat(spaceId, path);\n process.stdout.write(content);\n }\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 .option('--force', 'Skip conflict detection')\n .option('-m, --message <msg>', 'Custom commit message')\n .action(\n async (\n target: string,\n content: string,\n opts: { force?: boolean; message?: string }\n ) => {\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 body = content === '-' ? await readStdin() : content;\n\n if (Buffer.byteLength(body, 'utf-8') > MAX_SAVE_SIZE) {\n console.error(\n 'Error: content exceeds 2MB limit. Use `docz upload` for large files.'\n );\n process.exit(1);\n }\n\n let baseRef: string | undefined;\n if (!opts.force) {\n try {\n const existing = await client.catWithRef(s.id, path);\n baseRef = existing.ref;\n } catch (err) {\n const msg = err instanceof Error ? err.message : '';\n if (!msg.includes('404')) throw err;\n }\n }\n\n try {\n const result = await client.save(s.id, path, body, {\n baseRef,\n message: opts.message,\n });\n console.log(`Written: ${result.path} (ref: ${result.ref})`);\n } catch (err) {\n if (err instanceof ConflictError) {\n console.error(\n 'Error: file was modified by someone else. Please re-read the latest content and try again.'\n );\n process.exit(1);\n }\n throw err;\n }\n }\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>] or <url>')\n .argument('<target...>')\n .action(async (args: string[]) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, args);\n const logs = await client.log(spaceId, 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} ${l.date} ${l.message}`);\n }\n });\n\n // --- rollback ---\n program\n .command('rollback')\n .description(\n 'Rollback file to a previous version — docz rollback <space>:<path> <commit>'\n )\n .argument('<target>', 'space:path')\n .argument('<commit>', 'Commit hash to rollback to')\n .action(async (target: string, commit: string) => {\n const { space, path } = parseTarget([target]);\n if (!path) {\n console.error('Error: file path is required.');\n process.exit(1);\n }\n const client = getClient();\n const s = await client.resolveSpace(space);\n await client.rollback(s.id, path, commit);\n console.log(`Rolled back: ${path} → ${commit.substring(0, 7)}`);\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 // --- restore ---\n program\n .command('restore')\n .description(\n 'Restore file from trash — docz restore <space>:<path> <commit>'\n )\n .argument('<target>', 'space:path')\n .argument('<commit>', 'Commit hash from trash listing')\n .action(async (target: string, commit: string) => {\n const { space, path } = parseTarget([target]);\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.restore(s.id, path, commit);\n console.log(`Restored: ${path}`);\n });\n\n // --- comment ---\n const comment = program\n .command('comment')\n .description('Manage file comments');\n\n comment\n .command('list')\n .description('List comments — docz comment list <space>:<path>')\n .argument('<target...>')\n .action(async (args: string[]) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, args);\n if (!path) {\n console.error('Error: file path is required.');\n process.exit(1);\n }\n const comments = await client.listComments(spaceId, path);\n if (comments.length === 0) {\n console.log('No comments.');\n return;\n }\n for (const c of comments) {\n const status = c.is_closed ? ' [closed]' : '';\n console.log(`#${c.id} ${c.user_name} (${c.created_at})${status}`);\n console.log(` ${c.content}`);\n for (const r of c.replies) {\n console.log(` → ${r.user_name}: ${r.content}`);\n }\n }\n });\n\n comment\n .command('add')\n .description('Add comment — docz comment add <space>:<path> <content>')\n .argument('<target>', 'space:path')\n .argument('<content>', 'Comment text (or - for stdin)')\n .action(async (target: string, content: string) => {\n const { space, path } = parseTarget([target]);\n if (!path) {\n console.error('Error: file path is required.');\n process.exit(1);\n }\n const client = getClient();\n const s = await client.resolveSpace(space);\n const body = content === '-' ? await readStdin() : content;\n const c = await client.createComment(s.id, path, body);\n console.log(`Comment #${c.id} created.`);\n });\n\n comment\n .command('reply')\n .description(\n 'Reply to comment — docz comment reply <space> <commentId> <content>'\n )\n .argument('<space>')\n .argument('<commentId>')\n .argument('<content>', 'Reply text (or - for stdin)')\n .action(async (spaceName: string, commentId: string, content: string) => {\n const client = getClient();\n const s = await client.resolveSpace(spaceName);\n const body = content === '-' ? await readStdin() : content;\n const r = await client.replyComment(s.id, Number(commentId), body);\n console.log(`Reply #${r.id} created.`);\n });\n\n comment\n .command('close')\n .description('Close comment — docz comment close <space> <commentId>')\n .argument('<space>')\n .argument('<commentId>')\n .action(async (spaceName: string, commentId: string) => {\n const client = getClient();\n const s = await client.resolveSpace(spaceName);\n await client.closeComment(s.id, Number(commentId));\n console.log(`Comment #${commentId} closed.`);\n });\n\n comment\n .command('rm')\n .description('Delete comment — docz comment rm <space> <commentId>')\n .argument('<space>')\n .argument('<commentId>')\n .action(async (spaceName: string, commentId: string) => {\n const client = getClient();\n const s = await client.resolveSpace(spaceName);\n await client.deleteComment(s.id, Number(commentId));\n console.log(`Comment #${commentId} deleted.`);\n });\n\n // --- share ---\n const share = program.command('share').description('Manage share links');\n\n share\n .command('create')\n .description('Create share link — docz share create <space>:<path>')\n .argument('<target>', 'space:path')\n .option('--expires <duration>', 'Expiry duration (e.g. 7d, 24h)')\n .option('--users <emails>', 'Comma-separated user emails or IDs')\n .option('--groups <ids>', 'Comma-separated group IDs')\n .action(\n async (\n target: string,\n opts: { expires?: string; users?: string; groups?: string }\n ) => {\n const { space, path } = parseTarget([target]);\n if (!path) {\n console.error(\n 'Error: file path is required. Usage: docz share create <space>:<path>'\n );\n process.exit(1);\n }\n const client = getClient();\n const s = await client.resolveSpace(space);\n const apiOpts: {\n expiresAt?: string;\n userIds?: string[];\n groupIds?: string[];\n } = {};\n if (opts.expires) apiOpts.expiresAt = parseExpires(opts.expires);\n if (opts.users)\n apiOpts.userIds = opts.users.split(',').map((s) => s.trim());\n if (opts.groups)\n apiOpts.groupIds = opts.groups.split(',').map((s) => s.trim());\n const link = await client.createShareLink(s.id, path, apiOpts);\n const baseUrl = getBaseUrl();\n console.log('Created share link:');\n console.log(` id: ${link.id}`);\n console.log(` token: ${link.token}`);\n console.log(` url: ${baseUrl}/share/${link.token}`);\n console.log(` expires: ${link.expires_at ?? 'never'}`);\n if (link.user_ids?.length)\n console.log(` users: ${link.user_ids.join(', ')}`);\n if (link.group_ids?.length)\n console.log(` groups: ${link.group_ids.length}`);\n }\n );\n\n share\n .command('list')\n .description('List share links — docz share list <space>')\n .argument('<space>')\n .option('--file <path>', 'Filter by file path')\n .action(async (spaceName: string, opts: { file?: string }) => {\n const client = getClient();\n const s = await client.resolveSpace(spaceName);\n const links = await client.listShareLinks(s.id, opts.file);\n if (links.length === 0) {\n console.log('No share links.');\n return;\n }\n for (const l of links) {\n const expires = l.expires_at ?? 'never';\n const creator = l.created_by_name ?? l.created_by_email ?? l.created_by;\n console.log(\n `${l.id}\\t${l.token}\\t${l.file_path}\\t${expires}\\t${creator}`\n );\n }\n });\n\n share\n .command('update')\n .description('Update share link — docz share update <space> <link-id>')\n .argument('<space>')\n .argument('<linkId>')\n .option('--expires <duration>', 'New expiry duration (e.g. 30d)')\n .option('--users <emails>', 'Comma-separated user emails or IDs')\n .option('--groups <ids>', 'Comma-separated group IDs')\n .action(\n async (\n spaceName: string,\n linkId: string,\n opts: { expires?: string; users?: string; groups?: string }\n ) => {\n const client = getClient();\n const s = await client.resolveSpace(spaceName);\n const apiOpts: {\n expiresAt?: string;\n userIds?: string[];\n groupIds?: string[];\n } = {};\n if (opts.expires) apiOpts.expiresAt = parseExpires(opts.expires);\n if (opts.users)\n apiOpts.userIds = opts.users.split(',').map((s) => s.trim());\n if (opts.groups)\n apiOpts.groupIds = opts.groups.split(',').map((s) => s.trim());\n await client.updateShareLink(s.id, linkId, apiOpts);\n console.log(`Updated share link: ${linkId}`);\n }\n );\n\n share\n .command('cat')\n .description('Read shared file — docz share cat <token-or-url>')\n .argument('<token>', 'Share token or full URL')\n .option('--raw', 'Output raw content only')\n .action(async (tokenArg: string, opts: { raw?: boolean }) => {\n const client = getClient();\n const token = extractShareToken(tokenArg);\n if (!opts.raw) {\n try {\n const info = await client.getSharedFileInfo(token);\n console.log(`File: ${info.file_path} (${info.space_name})`);\n console.log(\n `Shared by: ${info.created_by_name} | Expires: ${info.expires_at ?? 'never'}`\n );\n console.log('---');\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (!msg.includes('404')) {\n console.error(`Warning: failed to fetch share info: ${msg}`);\n }\n }\n }\n const content = await client.getSharedFile(token);\n process.stdout.write(content);\n });\n\n share\n .command('info')\n .description('Show share link info — docz share info <token-or-url>')\n .argument('<token>', 'Share token or full URL')\n .action(async (tokenArg: string) => {\n const client = getClient();\n const token = extractShareToken(tokenArg);\n const info = await client.getSharedFileInfo(token);\n console.log(`File: ${info.file_path}`);\n console.log(`Space: ${info.space_name}`);\n console.log(`Shared by: ${info.created_by_name}`);\n console.log(`Expires: ${info.expires_at ?? 'never'}`);\n });\n\n share\n .command('rm')\n .description('Delete share link — docz share rm <space> <link-id>')\n .argument('<space>')\n .argument('<linkId>')\n .action(async (spaceName: string, linkId: string) => {\n const client = getClient();\n const s = await client.resolveSpace(spaceName);\n await client.deleteShareLink(s.id, linkId);\n console.log(`Deleted share link: ${linkId}`);\n });\n\n // --- shortlink ---\n program\n .command('shortlink')\n .description('Get short URL — docz shortlink <space>:<path> or <url>')\n .argument('<target...>')\n .action(async (args: string[]) => {\n const client = getClient();\n const { spaceId, path } = await resolveTarget(client, args);\n if (!path) {\n console.error(\n 'Error: file path is required. Usage: docz shortlink <space>:<path>'\n );\n process.exit(1);\n }\n const ref = await client.getFileRef(spaceId, path);\n console.log(ref.url);\n });\n\n // --- diff ---\n program\n .command('diff')\n .description('Show changes — docz diff <space>[:<path>] <commit> [<from>]')\n .argument('<target>', 'space or space:path')\n .argument('<to>', 'Commit hash')\n .argument('[from]', 'From commit hash (default: to^)')\n .action(async (target: string, to: string, from?: string) => {\n const client = getClient();\n const { space, path } = parseTarget([target]);\n const s = await client.resolveSpace(space);\n if (path) {\n const result = await client.diffFile(s.id, path, to, from);\n if (result.diff) {\n process.stdout.write(result.diff);\n } else {\n console.log('No changes.');\n }\n } else {\n const result = await client.diffSummary(s.id, to, from);\n if (result.files.length === 0) {\n console.log('No changes.');\n return;\n }\n for (const f of result.files) {\n console.log(`${f.status} ${f.path}`);\n }\n }\n });\n}\n"],"mappings":"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","names":["s","readFileSync","readFileSync","s"]}