fantsec-docmost-cli 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +137 -0
- package/build/__tests__/cli-utils.test.js +287 -0
- package/build/__tests__/client-pagination.test.js +103 -0
- package/build/__tests__/discovery.test.js +40 -0
- package/build/__tests__/envelope.test.js +91 -0
- package/build/__tests__/filters.test.js +235 -0
- package/build/__tests__/integration/comment.test.js +48 -0
- package/build/__tests__/integration/discovery.test.js +24 -0
- package/build/__tests__/integration/file.test.js +33 -0
- package/build/__tests__/integration/group.test.js +48 -0
- package/build/__tests__/integration/helpers/global-setup.js +80 -0
- package/build/__tests__/integration/helpers/run-cli.js +163 -0
- package/build/__tests__/integration/invite.test.js +34 -0
- package/build/__tests__/integration/page.test.js +69 -0
- package/build/__tests__/integration/search.test.js +45 -0
- package/build/__tests__/integration/share.test.js +49 -0
- package/build/__tests__/integration/space.test.js +56 -0
- package/build/__tests__/integration/user.test.js +15 -0
- package/build/__tests__/integration/workspace.test.js +42 -0
- package/build/__tests__/markdown-converter.test.js +445 -0
- package/build/__tests__/mcp-tooling.test.js +58 -0
- package/build/__tests__/page-mentions.test.js +65 -0
- package/build/__tests__/tiptap-extensions.test.js +135 -0
- package/build/client.js +715 -0
- package/build/commands/comment.js +54 -0
- package/build/commands/discovery.js +21 -0
- package/build/commands/file.js +36 -0
- package/build/commands/group.js +91 -0
- package/build/commands/invite.js +67 -0
- package/build/commands/page.js +227 -0
- package/build/commands/search.js +33 -0
- package/build/commands/share.js +65 -0
- package/build/commands/space.js +154 -0
- package/build/commands/user.js +38 -0
- package/build/commands/workspace.js +77 -0
- package/build/index.js +19 -0
- package/build/lib/auth-utils.js +53 -0
- package/build/lib/cli-utils.js +293 -0
- package/build/lib/collaboration.js +126 -0
- package/build/lib/filters.js +137 -0
- package/build/lib/markdown-converter.js +187 -0
- package/build/lib/mcp-tooling.js +295 -0
- package/build/lib/page-mentions.js +162 -0
- package/build/lib/tiptap-extensions.js +86 -0
- package/build/mcp.js +186 -0
- package/build/program.js +60 -0
- package/package.json +64 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ensureOutputSupported, printResult, resolveContentInput, withClient, } from "../lib/cli-utils.js";
|
|
2
|
+
export function register(program) {
|
|
3
|
+
program
|
|
4
|
+
.command("comment-list")
|
|
5
|
+
.description("List comments on a page")
|
|
6
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
7
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
8
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
9
|
+
const result = await client.getComments(options.pageId);
|
|
10
|
+
printResult(result.items, opts, { allowTable: true, hasMore: result.hasMore });
|
|
11
|
+
}));
|
|
12
|
+
program
|
|
13
|
+
.command("comment-info")
|
|
14
|
+
.description("Get comment by ID")
|
|
15
|
+
.requiredOption("--comment-id <id>", "Comment ID")
|
|
16
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
17
|
+
ensureOutputSupported(opts);
|
|
18
|
+
const result = await client.getCommentInfo(options.commentId);
|
|
19
|
+
printResult(result, opts);
|
|
20
|
+
}));
|
|
21
|
+
program
|
|
22
|
+
.command("comment-create")
|
|
23
|
+
.description("Create a comment on a page")
|
|
24
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
25
|
+
.requiredOption("--content <content>", "Content literal, @file, or - for stdin")
|
|
26
|
+
.option("--selection <text>", "Selected text the comment refers to")
|
|
27
|
+
.option("--parent-comment-id <id>", "Parent comment ID for replies")
|
|
28
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
29
|
+
ensureOutputSupported(opts);
|
|
30
|
+
const content = await resolveContentInput(options.content);
|
|
31
|
+
const result = await client.createComment(options.pageId, content, options.selection, options.parentCommentId);
|
|
32
|
+
printResult(result, opts);
|
|
33
|
+
}));
|
|
34
|
+
program
|
|
35
|
+
.command("comment-update")
|
|
36
|
+
.description("Update a comment")
|
|
37
|
+
.requiredOption("--comment-id <id>", "Comment ID")
|
|
38
|
+
.requiredOption("--content <content>", "Content literal, @file, or - for stdin")
|
|
39
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
40
|
+
ensureOutputSupported(opts);
|
|
41
|
+
const content = await resolveContentInput(options.content);
|
|
42
|
+
const result = await client.updateComment(options.commentId, content);
|
|
43
|
+
printResult(result, opts);
|
|
44
|
+
}));
|
|
45
|
+
program
|
|
46
|
+
.command("comment-delete")
|
|
47
|
+
.description("Delete a comment")
|
|
48
|
+
.requiredOption("--comment-id <id>", "Comment ID")
|
|
49
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
50
|
+
ensureOutputSupported(opts);
|
|
51
|
+
const result = await client.deleteComment(options.commentId);
|
|
52
|
+
printResult(result, opts);
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function register(program) {
|
|
2
|
+
program
|
|
3
|
+
.command("commands")
|
|
4
|
+
.description("List all available commands with options (for agent discovery)")
|
|
5
|
+
.action(() => {
|
|
6
|
+
const commands = program.commands
|
|
7
|
+
.filter((cmd) => cmd.name() !== "commands")
|
|
8
|
+
.map((cmd) => ({
|
|
9
|
+
name: cmd.name(),
|
|
10
|
+
description: cmd.description(),
|
|
11
|
+
options: cmd.options.map((opt) => ({
|
|
12
|
+
flags: opt.flags,
|
|
13
|
+
description: opt.description,
|
|
14
|
+
required: opt.required || false,
|
|
15
|
+
...(opt.defaultValue !== undefined && { default: opt.defaultValue }),
|
|
16
|
+
})),
|
|
17
|
+
}));
|
|
18
|
+
const envelope = { ok: true, data: commands, meta: { count: commands.length, hasMore: false } };
|
|
19
|
+
console.log(JSON.stringify(envelope, null, 2));
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { writeFileSync } from "fs";
|
|
2
|
+
import { resolve, relative } from "path";
|
|
3
|
+
import { ensureOutputSupported, printResult, withClient, } from "../lib/cli-utils.js";
|
|
4
|
+
export function register(program) {
|
|
5
|
+
program
|
|
6
|
+
.command("file-upload")
|
|
7
|
+
.description("Upload a file attachment to a page")
|
|
8
|
+
.requiredOption("--file <path>", "File to upload")
|
|
9
|
+
.requiredOption("--page-id <id>", "Page ID to attach file to")
|
|
10
|
+
.option("--attachment-id <id>", "Existing attachment ID to replace")
|
|
11
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
12
|
+
ensureOutputSupported(opts);
|
|
13
|
+
const result = await client.uploadFile(options.file, options.pageId, options.attachmentId);
|
|
14
|
+
printResult(result, opts);
|
|
15
|
+
}));
|
|
16
|
+
program
|
|
17
|
+
.command("file-download")
|
|
18
|
+
.description("Download a file attachment")
|
|
19
|
+
.requiredOption("--file-id <id>", "File ID")
|
|
20
|
+
.requiredOption("--file-name <name>", "File name")
|
|
21
|
+
.option("--output <path>", "Output file path")
|
|
22
|
+
.action((options) => withClient(program, async (client) => {
|
|
23
|
+
const data = await client.downloadFile(options.fileId, options.fileName);
|
|
24
|
+
if (options.output) {
|
|
25
|
+
const resolved = resolve(options.output);
|
|
26
|
+
const rel = relative(process.cwd(), resolved);
|
|
27
|
+
if (rel.startsWith("..") || resolve(rel) !== resolved) {
|
|
28
|
+
process.stderr.write(`Warning: writing to path outside CWD: ${resolved}\n`);
|
|
29
|
+
}
|
|
30
|
+
writeFileSync(resolved, Buffer.from(data));
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
process.stdout.write(Buffer.from(data));
|
|
34
|
+
}
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { CliError, ensureOutputSupported, parseCommaSeparatedIds, printResult, withClient, } from "../lib/cli-utils.js";
|
|
2
|
+
export function register(program) {
|
|
3
|
+
program
|
|
4
|
+
.command("group-list")
|
|
5
|
+
.description("List all available groups")
|
|
6
|
+
.action(() => withClient(program, async (client, opts) => {
|
|
7
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
8
|
+
const result = await client.getGroups();
|
|
9
|
+
printResult(result.items, opts, { allowTable: true, hasMore: result.hasMore });
|
|
10
|
+
}));
|
|
11
|
+
program
|
|
12
|
+
.command("group-info")
|
|
13
|
+
.description("Get group details")
|
|
14
|
+
.requiredOption("--group-id <id>", "Group ID")
|
|
15
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
16
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
17
|
+
const result = await client.getGroupInfo(options.groupId);
|
|
18
|
+
printResult(result, opts, { allowTable: true });
|
|
19
|
+
}));
|
|
20
|
+
program
|
|
21
|
+
.command("group-create")
|
|
22
|
+
.description("Create a new group")
|
|
23
|
+
.requiredOption("--name <name>", "Group name")
|
|
24
|
+
.option("--description <description>", "Group description")
|
|
25
|
+
.option("--user-ids <ids>", "Comma-separated user IDs")
|
|
26
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
27
|
+
ensureOutputSupported(opts);
|
|
28
|
+
const userIds = options.userIds
|
|
29
|
+
? parseCommaSeparatedIds("--user-ids", options.userIds)
|
|
30
|
+
: undefined;
|
|
31
|
+
const result = await client.createGroup(options.name, options.description, userIds);
|
|
32
|
+
printResult(result, opts);
|
|
33
|
+
}));
|
|
34
|
+
program
|
|
35
|
+
.command("group-update")
|
|
36
|
+
.description("Update group settings")
|
|
37
|
+
.requiredOption("--group-id <id>", "Group ID")
|
|
38
|
+
.option("--name <name>", "Group name")
|
|
39
|
+
.option("--description <description>", "Group description")
|
|
40
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
41
|
+
ensureOutputSupported(opts);
|
|
42
|
+
const params = {
|
|
43
|
+
...(options.name !== undefined && { name: options.name }),
|
|
44
|
+
...(options.description !== undefined && { description: options.description }),
|
|
45
|
+
};
|
|
46
|
+
if (Object.keys(params).length === 0) {
|
|
47
|
+
throw new CliError("VALIDATION_ERROR", "At least one update flag is required (--name or --description).");
|
|
48
|
+
}
|
|
49
|
+
const result = await client.updateGroup(options.groupId, params);
|
|
50
|
+
printResult(result, opts);
|
|
51
|
+
}));
|
|
52
|
+
program
|
|
53
|
+
.command("group-delete")
|
|
54
|
+
.description("Delete a group")
|
|
55
|
+
.requiredOption("--group-id <id>", "Group ID")
|
|
56
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
57
|
+
ensureOutputSupported(opts);
|
|
58
|
+
const result = await client.deleteGroup(options.groupId);
|
|
59
|
+
printResult(result, opts);
|
|
60
|
+
}));
|
|
61
|
+
program
|
|
62
|
+
.command("group-member-list")
|
|
63
|
+
.description("List group members")
|
|
64
|
+
.requiredOption("--group-id <id>", "Group ID")
|
|
65
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
66
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
67
|
+
const result = await client.getGroupMembers(options.groupId);
|
|
68
|
+
printResult(result.items, opts, { allowTable: true, hasMore: result.hasMore });
|
|
69
|
+
}));
|
|
70
|
+
program
|
|
71
|
+
.command("group-member-add")
|
|
72
|
+
.description("Add members to a group")
|
|
73
|
+
.requiredOption("--group-id <id>", "Group ID")
|
|
74
|
+
.requiredOption("--user-ids <ids>", "Comma-separated user IDs")
|
|
75
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
76
|
+
ensureOutputSupported(opts);
|
|
77
|
+
const userIds = parseCommaSeparatedIds("--user-ids", options.userIds);
|
|
78
|
+
const result = await client.addGroupMembers(options.groupId, userIds);
|
|
79
|
+
printResult(result, opts);
|
|
80
|
+
}));
|
|
81
|
+
program
|
|
82
|
+
.command("group-member-remove")
|
|
83
|
+
.description("Remove a member from a group")
|
|
84
|
+
.requiredOption("--group-id <id>", "Group ID")
|
|
85
|
+
.requiredOption("--user-id <id>", "User ID to remove")
|
|
86
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
87
|
+
ensureOutputSupported(opts);
|
|
88
|
+
const result = await client.removeGroupMember(options.groupId, options.userId);
|
|
89
|
+
printResult(result, opts);
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Option } from "commander";
|
|
2
|
+
import { ensureOutputSupported, parseCommaSeparatedIds, printResult, withClient, } from "../lib/cli-utils.js";
|
|
3
|
+
export function register(program) {
|
|
4
|
+
program
|
|
5
|
+
.command("invite-list")
|
|
6
|
+
.description("List workspace invitations")
|
|
7
|
+
.action(() => withClient(program, async (client, opts) => {
|
|
8
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
9
|
+
const result = await client.getInvites();
|
|
10
|
+
printResult(result.items, opts, { allowTable: true, hasMore: result.hasMore });
|
|
11
|
+
}));
|
|
12
|
+
program
|
|
13
|
+
.command("invite-info")
|
|
14
|
+
.description("Get invitation details")
|
|
15
|
+
.requiredOption("--invitation-id <id>", "Invitation ID")
|
|
16
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
17
|
+
ensureOutputSupported(opts);
|
|
18
|
+
const result = await client.getInviteInfo(options.invitationId);
|
|
19
|
+
printResult(result, opts);
|
|
20
|
+
}));
|
|
21
|
+
program
|
|
22
|
+
.command("invite-create")
|
|
23
|
+
.description("Create workspace invitation(s)")
|
|
24
|
+
.requiredOption("--emails <emails>", "Comma-separated email addresses")
|
|
25
|
+
.addOption(new Option("--role <role>", "Role for invited users")
|
|
26
|
+
.choices(["owner", "admin", "member"])
|
|
27
|
+
.makeOptionMandatory())
|
|
28
|
+
.option("--group-ids <ids>", "Comma-separated group IDs")
|
|
29
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
30
|
+
ensureOutputSupported(opts);
|
|
31
|
+
const emails = parseCommaSeparatedIds("--emails", options.emails);
|
|
32
|
+
const groupIds = options.groupIds
|
|
33
|
+
? parseCommaSeparatedIds("--group-ids", options.groupIds)
|
|
34
|
+
: undefined;
|
|
35
|
+
const result = await client.createInvite(emails, options.role, groupIds);
|
|
36
|
+
printResult(result, opts);
|
|
37
|
+
}));
|
|
38
|
+
program
|
|
39
|
+
.command("invite-revoke")
|
|
40
|
+
.description("Revoke a workspace invitation")
|
|
41
|
+
.requiredOption("--invitation-id <id>", "Invitation ID")
|
|
42
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
43
|
+
ensureOutputSupported(opts);
|
|
44
|
+
const result = await client.revokeInvite(options.invitationId);
|
|
45
|
+
printResult(result, opts);
|
|
46
|
+
}));
|
|
47
|
+
program
|
|
48
|
+
.command("invite-resend")
|
|
49
|
+
.description("Resend a workspace invitation")
|
|
50
|
+
.requiredOption("--invitation-id <id>", "Invitation ID")
|
|
51
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
52
|
+
ensureOutputSupported(opts);
|
|
53
|
+
const result = await client.resendInvite(options.invitationId);
|
|
54
|
+
printResult(result, opts);
|
|
55
|
+
}));
|
|
56
|
+
program
|
|
57
|
+
.command("invite-link")
|
|
58
|
+
.description("Get invitation link")
|
|
59
|
+
.requiredOption("--invitation-id <id>", "Invitation ID")
|
|
60
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
61
|
+
ensureOutputSupported(opts, { allowText: true });
|
|
62
|
+
const result = await client.getInviteLink(options.invitationId);
|
|
63
|
+
printResult(result, opts, {
|
|
64
|
+
textExtractor: (data) => data?.inviteLink,
|
|
65
|
+
});
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { writeFileSync } from "fs";
|
|
2
|
+
import { resolve, relative } from "path";
|
|
3
|
+
import { Option } from "commander";
|
|
4
|
+
import { CliError, ensureOutputSupported, printResult, resolveContentInput, parseCommaSeparatedIds, withClient, } from "../lib/cli-utils.js";
|
|
5
|
+
export function register(program) {
|
|
6
|
+
program
|
|
7
|
+
.command("page-list")
|
|
8
|
+
.description("List pages")
|
|
9
|
+
.option("-s, --space-id <id>", "Filter by space ID")
|
|
10
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
11
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
12
|
+
const result = await client.listPages(options.spaceId);
|
|
13
|
+
printResult(result.items, opts, { allowTable: true, hasMore: result.hasMore });
|
|
14
|
+
}));
|
|
15
|
+
program
|
|
16
|
+
.command("page-info")
|
|
17
|
+
.description("Get page by ID")
|
|
18
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
19
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
20
|
+
ensureOutputSupported(opts, { allowTable: true, allowText: true });
|
|
21
|
+
const result = await client.getPage(options.pageId);
|
|
22
|
+
printResult(result.data, opts, {
|
|
23
|
+
allowTable: true,
|
|
24
|
+
textExtractor: (data) => {
|
|
25
|
+
return data?.content;
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}));
|
|
29
|
+
program
|
|
30
|
+
.command("page-create")
|
|
31
|
+
.description("Create a new page")
|
|
32
|
+
.requiredOption("--space-id <id>", "Space ID")
|
|
33
|
+
.option("--title <title>", "Page title")
|
|
34
|
+
.option("--icon <icon>", "Page icon")
|
|
35
|
+
.option("--parent-page-id <id>", "Parent page ID")
|
|
36
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
37
|
+
ensureOutputSupported(opts);
|
|
38
|
+
const result = await client.createPage(options.spaceId, options.title, options.icon, options.parentPageId);
|
|
39
|
+
printResult(result, opts);
|
|
40
|
+
}));
|
|
41
|
+
program
|
|
42
|
+
.command("page-update")
|
|
43
|
+
.description("Update page metadata and/or content")
|
|
44
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
45
|
+
.option("--content <content>", "Content literal, @file, or - for stdin")
|
|
46
|
+
.option("--title <title>", "New page title")
|
|
47
|
+
.option("--icon <icon>", "Page icon")
|
|
48
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
49
|
+
ensureOutputSupported(opts);
|
|
50
|
+
if (options.content === undefined && options.title === undefined && options.icon === undefined) {
|
|
51
|
+
throw new CliError("VALIDATION_ERROR", "Provide at least one of --content, --title, or --icon.");
|
|
52
|
+
}
|
|
53
|
+
const content = options.content ? await resolveContentInput(options.content) : undefined;
|
|
54
|
+
const result = await client.updatePage(options.pageId, content, options.title, options.icon);
|
|
55
|
+
printResult(result, opts);
|
|
56
|
+
}));
|
|
57
|
+
program
|
|
58
|
+
.command("page-move")
|
|
59
|
+
.description("Move page to a different parent or to root")
|
|
60
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
61
|
+
.option("--parent-page-id <id>", "Target parent page ID")
|
|
62
|
+
.option("--position <pos>", "Position string", "a00000")
|
|
63
|
+
.option("--root", "Move page to root")
|
|
64
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
65
|
+
ensureOutputSupported(opts);
|
|
66
|
+
if (options.root && options.parentPageId) {
|
|
67
|
+
throw new CliError("VALIDATION_ERROR", "--root and --parent-page-id are mutually exclusive.");
|
|
68
|
+
}
|
|
69
|
+
if (!options.root && !options.parentPageId) {
|
|
70
|
+
throw new CliError("VALIDATION_ERROR", "Specify --parent-page-id <id> or --root.");
|
|
71
|
+
}
|
|
72
|
+
const parentPageId = options.root ? null : (options.parentPageId ?? null);
|
|
73
|
+
const result = await client.movePage(options.pageId, parentPageId, options.position);
|
|
74
|
+
printResult(result, opts);
|
|
75
|
+
}));
|
|
76
|
+
program
|
|
77
|
+
.command("page-delete")
|
|
78
|
+
.description("Delete a page")
|
|
79
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
80
|
+
.option("--permanently-delete", "Permanently delete page (no trash)")
|
|
81
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
82
|
+
ensureOutputSupported(opts);
|
|
83
|
+
const result = await client.deletePage(options.pageId, options.permanentlyDelete);
|
|
84
|
+
printResult(result, opts);
|
|
85
|
+
}));
|
|
86
|
+
program
|
|
87
|
+
.command("page-delete-bulk")
|
|
88
|
+
.description("Delete multiple pages")
|
|
89
|
+
.requiredOption("--page-ids <id1,id2,...>", "Comma-separated page IDs")
|
|
90
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
91
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
92
|
+
const pageIds = parseCommaSeparatedIds("--page-ids", options.pageIds);
|
|
93
|
+
const result = await client.deletePages(pageIds);
|
|
94
|
+
const failed = result.filter((r) => !r.success);
|
|
95
|
+
printResult(result, opts, { allowTable: true });
|
|
96
|
+
if (failed.length > 0) {
|
|
97
|
+
throw new CliError("INTERNAL_ERROR", `Failed to delete ${failed.length} of ${result.length} pages.`);
|
|
98
|
+
}
|
|
99
|
+
}));
|
|
100
|
+
program
|
|
101
|
+
.command("page-history")
|
|
102
|
+
.description("Get page version history")
|
|
103
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
104
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
105
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
106
|
+
const result = await client.getPageHistory(options.pageId, opts.limit, opts.maxItems);
|
|
107
|
+
printResult(result.items, opts, { allowTable: true, hasMore: result.hasMore });
|
|
108
|
+
}));
|
|
109
|
+
program
|
|
110
|
+
.command("page-history-detail")
|
|
111
|
+
.description("Get specific page history entry")
|
|
112
|
+
.requiredOption("--history-id <id>", "History entry ID")
|
|
113
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
114
|
+
ensureOutputSupported(opts, { allowTable: true, allowText: true });
|
|
115
|
+
const result = await client.getPageHistoryDetail(options.historyId);
|
|
116
|
+
printResult(result, opts, {
|
|
117
|
+
allowTable: true,
|
|
118
|
+
textExtractor: (data) => {
|
|
119
|
+
const value = data;
|
|
120
|
+
return value.content;
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
}));
|
|
124
|
+
program
|
|
125
|
+
.command("page-restore")
|
|
126
|
+
.description("Restore page from trash")
|
|
127
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
128
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
129
|
+
ensureOutputSupported(opts);
|
|
130
|
+
const result = await client.restorePage(options.pageId);
|
|
131
|
+
printResult(result, opts);
|
|
132
|
+
}));
|
|
133
|
+
program
|
|
134
|
+
.command("page-trash")
|
|
135
|
+
.description("List deleted pages in a space")
|
|
136
|
+
.requiredOption("--space-id <id>", "Space ID")
|
|
137
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
138
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
139
|
+
const result = await client.getTrash(options.spaceId);
|
|
140
|
+
printResult(result.items, opts, { allowTable: true, hasMore: result.hasMore });
|
|
141
|
+
}));
|
|
142
|
+
program
|
|
143
|
+
.command("page-duplicate")
|
|
144
|
+
.description("Duplicate page")
|
|
145
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
146
|
+
.option("--space-id <id>", "Target space ID")
|
|
147
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
148
|
+
ensureOutputSupported(opts);
|
|
149
|
+
const result = await client.duplicatePage(options.pageId, options.spaceId);
|
|
150
|
+
printResult(result, opts);
|
|
151
|
+
}));
|
|
152
|
+
program
|
|
153
|
+
.command("page-breadcrumbs")
|
|
154
|
+
.description("Get breadcrumb path for page")
|
|
155
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
156
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
157
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
158
|
+
const result = await client.getPageBreadcrumbs(options.pageId);
|
|
159
|
+
printResult(result, opts, { allowTable: true });
|
|
160
|
+
}));
|
|
161
|
+
program
|
|
162
|
+
.command("page-tree")
|
|
163
|
+
.description("Get page tree for a space or page")
|
|
164
|
+
.option("-s, --space-id <id>", "Space ID")
|
|
165
|
+
.option("--page-id <id>", "Page ID")
|
|
166
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
167
|
+
if (!options.spaceId && !options.pageId) {
|
|
168
|
+
throw new CliError("VALIDATION_ERROR", "At least one of --space-id or --page-id is required.");
|
|
169
|
+
}
|
|
170
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
171
|
+
const result = await client.getPageTree(options.spaceId, options.pageId);
|
|
172
|
+
printResult(result, opts, { allowTable: true });
|
|
173
|
+
}));
|
|
174
|
+
program
|
|
175
|
+
.command("page-move-to-space")
|
|
176
|
+
.description("Move page to a different space")
|
|
177
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
178
|
+
.requiredOption("--space-id <id>", "Target space ID")
|
|
179
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
180
|
+
ensureOutputSupported(opts);
|
|
181
|
+
const result = await client.movePageToSpace(options.pageId, options.spaceId);
|
|
182
|
+
printResult(result, opts);
|
|
183
|
+
}));
|
|
184
|
+
program
|
|
185
|
+
.command("page-export")
|
|
186
|
+
.description("Export page content")
|
|
187
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
188
|
+
.addOption(new Option("--export-format <format>", "Export format").choices(["html", "markdown"]).makeOptionMandatory())
|
|
189
|
+
.option("--output <path>", "Output file path")
|
|
190
|
+
.option("--include-children", "Include child pages")
|
|
191
|
+
.option("--include-attachments", "Include attachments")
|
|
192
|
+
.action((options) => withClient(program, async (client) => {
|
|
193
|
+
const data = await client.exportPage(options.pageId, options.exportFormat, options.includeChildren, options.includeAttachments);
|
|
194
|
+
if (options.output) {
|
|
195
|
+
const resolved = resolve(options.output);
|
|
196
|
+
const rel = relative(process.cwd(), resolved);
|
|
197
|
+
if (rel.startsWith("..") || resolve(rel) !== resolved) {
|
|
198
|
+
process.stderr.write(`Warning: writing to path outside CWD: ${resolved}\n`);
|
|
199
|
+
}
|
|
200
|
+
writeFileSync(resolved, Buffer.from(data));
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
process.stdout.write(Buffer.from(data));
|
|
204
|
+
}
|
|
205
|
+
}));
|
|
206
|
+
program
|
|
207
|
+
.command("page-import")
|
|
208
|
+
.description("Import a page from file")
|
|
209
|
+
.requiredOption("--file <path>", "File to import")
|
|
210
|
+
.requiredOption("--space-id <id>", "Space ID")
|
|
211
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
212
|
+
ensureOutputSupported(opts);
|
|
213
|
+
const result = await client.importPage(options.file, options.spaceId);
|
|
214
|
+
printResult(result, opts);
|
|
215
|
+
}));
|
|
216
|
+
program
|
|
217
|
+
.command("page-import-zip")
|
|
218
|
+
.description("Import pages from a zip archive")
|
|
219
|
+
.requiredOption("--file <path>", "Zip file to import")
|
|
220
|
+
.requiredOption("--space-id <id>", "Space ID")
|
|
221
|
+
.addOption(new Option("--source <source>", "Import source").choices(["generic", "notion", "confluence"]).makeOptionMandatory())
|
|
222
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
223
|
+
ensureOutputSupported(opts);
|
|
224
|
+
const result = await client.importZip(options.file, options.spaceId, options.source);
|
|
225
|
+
printResult(result, opts);
|
|
226
|
+
}));
|
|
227
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ensureOutputSupported, printResult, withClient, } from "../lib/cli-utils.js";
|
|
2
|
+
export function register(program) {
|
|
3
|
+
program
|
|
4
|
+
.command("search")
|
|
5
|
+
.description("Search pages and content")
|
|
6
|
+
.requiredOption("--query <q>", "Search query")
|
|
7
|
+
.option("-s, --space-id <id>", "Filter by space ID")
|
|
8
|
+
.option("--creator-id <id>", "Filter by creator ID")
|
|
9
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
10
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
11
|
+
const result = await client.search(options.query, options.spaceId, options.creatorId);
|
|
12
|
+
printResult(result.items, opts, { allowTable: true, hasMore: result.hasMore });
|
|
13
|
+
}));
|
|
14
|
+
program
|
|
15
|
+
.command("search-suggest")
|
|
16
|
+
.description("Get search suggestions")
|
|
17
|
+
.requiredOption("--query <q>", "Search query")
|
|
18
|
+
.option("-s, --space-id <id>", "Filter by space ID")
|
|
19
|
+
.option("--include-users", "Include users in results")
|
|
20
|
+
.option("--include-groups", "Include groups in results")
|
|
21
|
+
.option("--include-pages", "Include pages in results")
|
|
22
|
+
.option("--max-results <n>", "Max results", parseInt)
|
|
23
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
24
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
25
|
+
const result = await client.searchSuggest(options.query, options.spaceId, {
|
|
26
|
+
includeUsers: options.includeUsers,
|
|
27
|
+
includeGroups: options.includeGroups,
|
|
28
|
+
includePages: options.includePages,
|
|
29
|
+
limit: options.maxResults,
|
|
30
|
+
});
|
|
31
|
+
printResult(result, opts, { allowTable: true });
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Option } from "commander";
|
|
2
|
+
import { ensureOutputSupported, printResult, withClient, } from "../lib/cli-utils.js";
|
|
3
|
+
export function register(program) {
|
|
4
|
+
program
|
|
5
|
+
.command("share-list")
|
|
6
|
+
.description("List all shares")
|
|
7
|
+
.action(() => withClient(program, async (client, opts) => {
|
|
8
|
+
ensureOutputSupported(opts, { allowTable: true });
|
|
9
|
+
const result = await client.getShares();
|
|
10
|
+
printResult(result.items, opts, { allowTable: true, hasMore: result.hasMore });
|
|
11
|
+
}));
|
|
12
|
+
program
|
|
13
|
+
.command("share-info")
|
|
14
|
+
.description("Get share details")
|
|
15
|
+
.requiredOption("--share-id <id>", "Share ID")
|
|
16
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
17
|
+
ensureOutputSupported(opts);
|
|
18
|
+
const result = await client.getShareInfo(options.shareId);
|
|
19
|
+
printResult(result, opts);
|
|
20
|
+
}));
|
|
21
|
+
program
|
|
22
|
+
.command("share-for-page")
|
|
23
|
+
.description("Get share for a page")
|
|
24
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
25
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
26
|
+
ensureOutputSupported(opts);
|
|
27
|
+
const result = await client.getShareForPage(options.pageId);
|
|
28
|
+
printResult(result, opts);
|
|
29
|
+
}));
|
|
30
|
+
program
|
|
31
|
+
.command("share-create")
|
|
32
|
+
.description("Create a share for a page")
|
|
33
|
+
.requiredOption("--page-id <id>", "Page ID")
|
|
34
|
+
.addOption(new Option("--include-subpages <bool>", "Include subpages").choices(["true", "false"]))
|
|
35
|
+
.addOption(new Option("--search-indexing <bool>", "Allow search indexing").choices(["true", "false"]))
|
|
36
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
37
|
+
ensureOutputSupported(opts);
|
|
38
|
+
const includeSubPages = options.includeSubpages !== undefined ? options.includeSubpages === "true" : undefined;
|
|
39
|
+
const searchIndexing = options.searchIndexing !== undefined ? options.searchIndexing === "true" : undefined;
|
|
40
|
+
const result = await client.createShare(options.pageId, includeSubPages, searchIndexing);
|
|
41
|
+
printResult(result, opts);
|
|
42
|
+
}));
|
|
43
|
+
program
|
|
44
|
+
.command("share-update")
|
|
45
|
+
.description("Update a share")
|
|
46
|
+
.requiredOption("--share-id <id>", "Share ID")
|
|
47
|
+
.addOption(new Option("--include-subpages <bool>", "Include subpages").choices(["true", "false"]))
|
|
48
|
+
.addOption(new Option("--search-indexing <bool>", "Allow search indexing").choices(["true", "false"]))
|
|
49
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
50
|
+
ensureOutputSupported(opts);
|
|
51
|
+
const includeSubPages = options.includeSubpages !== undefined ? options.includeSubpages === "true" : undefined;
|
|
52
|
+
const searchIndexing = options.searchIndexing !== undefined ? options.searchIndexing === "true" : undefined;
|
|
53
|
+
const result = await client.updateShare(options.shareId, includeSubPages, searchIndexing);
|
|
54
|
+
printResult(result, opts);
|
|
55
|
+
}));
|
|
56
|
+
program
|
|
57
|
+
.command("share-delete")
|
|
58
|
+
.description("Delete a share")
|
|
59
|
+
.requiredOption("--share-id <id>", "Share ID")
|
|
60
|
+
.action((options) => withClient(program, async (client, opts) => {
|
|
61
|
+
ensureOutputSupported(opts);
|
|
62
|
+
const result = await client.deleteShare(options.shareId);
|
|
63
|
+
printResult(result, opts);
|
|
64
|
+
}));
|
|
65
|
+
}
|