@andrzejchm/notion-cli 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -4
- package/dist/cli.js +101 -29
- package/dist/cli.js.map +1 -1
- package/docs/FEATURE-PARITY.md +9 -10
- package/docs/README.agents.md +46 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ Fetch and follow instructions from https://raw.githubusercontent.com/andrzejchm/
|
|
|
37
37
|
- **`notion db query`** — filter, sort, and select columns from any database
|
|
38
38
|
- **`notion append`** — append markdown content to an existing page
|
|
39
39
|
- **`notion create-page`** — create a new page with markdown body, prints URL to stdout
|
|
40
|
-
- **`notion comment`** — add a comment to a page
|
|
40
|
+
- **`notion comment`** — add a comment to a page, block, or discussion thread
|
|
41
41
|
- **Agent-friendly** — plain text tables by default; `--json` for machine-readable output
|
|
42
42
|
- **Flexible auth** — interactive setup or `NOTION_API_TOKEN` env var
|
|
43
43
|
- **Accepts URLs** — pass full Notion URLs anywhere an ID is expected
|
|
@@ -70,6 +70,12 @@ my-summarize-command | notion create-page --parent "$PAGE_ID" --title "Auto Summ
|
|
|
70
70
|
# Add a comment to a page
|
|
71
71
|
notion comment "$PAGE_ID" -m "Reviewed and approved."
|
|
72
72
|
|
|
73
|
+
# Reply to an existing discussion thread
|
|
74
|
+
notion comment --reply-to "$DISCUSSION_ID" -m "Agreed, let's proceed."
|
|
75
|
+
|
|
76
|
+
# Comment on a specific block
|
|
77
|
+
notion comment --block "$BLOCK_ID" -m "This section needs revision."
|
|
78
|
+
|
|
73
79
|
# List everything your integration can access
|
|
74
80
|
notion ls
|
|
75
81
|
```
|
|
@@ -85,15 +91,15 @@ notion ls
|
|
|
85
91
|
| `notion auth status` | Show current auth state |
|
|
86
92
|
| `notion auth list` | List all saved profiles |
|
|
87
93
|
| `notion auth use <name>` | Switch the active profile |
|
|
88
|
-
| `notion search <query>` | Search pages and databases by title |
|
|
89
|
-
| `notion ls` | List all accessible pages and databases |
|
|
94
|
+
| `notion search <query>` | Search pages and databases by title (`--sort asc\|desc`) |
|
|
95
|
+
| `notion ls` | List all accessible pages and databases (`--sort asc\|desc`) |
|
|
90
96
|
| `notion open <id\|url>` | Open a page in your browser |
|
|
91
97
|
| `notion read <id\|url>` | Read a page as markdown |
|
|
92
98
|
| `notion db schema <id\|url>` | Show database property schema and valid values |
|
|
93
99
|
| `notion db query <id\|url>` | Query database entries with filtering and sorting |
|
|
94
100
|
| `notion users` | List workspace members |
|
|
95
101
|
| `notion comments <id\|url>` | Read page comments |
|
|
96
|
-
| `notion comment
|
|
102
|
+
| `notion comment [id\|url] -m <text>` | Add a comment to a page, block, or thread |
|
|
97
103
|
| `notion append <id\|url> -m <markdown>` | Append markdown blocks to a page |
|
|
98
104
|
| `notion edit-page <id\|url> --find <old> --replace <new>` | Search-and-replace text on a page |
|
|
99
105
|
| `notion edit-page <id\|url> -m <markdown>` | Replace entire page content |
|
|
@@ -102,6 +108,15 @@ notion ls
|
|
|
102
108
|
| `notion archive <id\|url>` | Archive (trash) a page |
|
|
103
109
|
| `notion completion bash\|zsh\|fish` | Install shell tab completion |
|
|
104
110
|
|
|
111
|
+
### `notion search` / `notion ls` flags
|
|
112
|
+
|
|
113
|
+
| Flag | Example | Description |
|
|
114
|
+
|------|---------|-------------|
|
|
115
|
+
| `--sort` | `--sort desc` | Sort by last edited time (`asc` or `desc`) |
|
|
116
|
+
| `--type` | `--type page` | Filter by object type (`page` or `database`) |
|
|
117
|
+
| `--cursor` | `--cursor <cursor>` | Pagination cursor from a previous `--next` hint |
|
|
118
|
+
| `--json` | `--json` | Force JSON output |
|
|
119
|
+
|
|
105
120
|
### `notion db query` flags
|
|
106
121
|
|
|
107
122
|
| Flag | Example | Description |
|
package/dist/cli.js
CHANGED
|
@@ -543,23 +543,25 @@ function reportTokenSource(source) {
|
|
|
543
543
|
}
|
|
544
544
|
|
|
545
545
|
// src/services/write.service.ts
|
|
546
|
-
async function addComment(client,
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
{
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
code: false,
|
|
559
|
-
color: "default"
|
|
560
|
-
}
|
|
546
|
+
async function addComment(client, target, text, options = {}) {
|
|
547
|
+
const richText = [
|
|
548
|
+
{
|
|
549
|
+
type: "text",
|
|
550
|
+
text: { content: text, link: null },
|
|
551
|
+
annotations: {
|
|
552
|
+
bold: false,
|
|
553
|
+
italic: false,
|
|
554
|
+
strikethrough: false,
|
|
555
|
+
underline: false,
|
|
556
|
+
code: false,
|
|
557
|
+
color: "default"
|
|
561
558
|
}
|
|
562
|
-
|
|
559
|
+
}
|
|
560
|
+
];
|
|
561
|
+
const targetPayload = target.type === "reply" ? { discussion_id: target.discussionId } : target.type === "block" ? { parent: { block_id: target.blockId } } : { parent: { page_id: target.pageId } };
|
|
562
|
+
await client.comments.create({
|
|
563
|
+
...targetPayload,
|
|
564
|
+
rich_text: richText,
|
|
563
565
|
...options.asUser && { display_name: { type: "user" } }
|
|
564
566
|
});
|
|
565
567
|
}
|
|
@@ -1316,20 +1318,50 @@ function statusCommand() {
|
|
|
1316
1318
|
|
|
1317
1319
|
// src/commands/comment-add.ts
|
|
1318
1320
|
import { Command as Command6 } from "commander";
|
|
1321
|
+
function resolveTarget(idOrUrl, opts) {
|
|
1322
|
+
const targetCount = [idOrUrl, opts.replyTo, opts.block].filter(
|
|
1323
|
+
Boolean
|
|
1324
|
+
).length;
|
|
1325
|
+
if (targetCount > 1) {
|
|
1326
|
+
throw new CliError(
|
|
1327
|
+
ErrorCodes.INVALID_ARG,
|
|
1328
|
+
"Provide only one target: a page ID/URL, --reply-to, or --block.",
|
|
1329
|
+
"These options are mutually exclusive"
|
|
1330
|
+
);
|
|
1331
|
+
}
|
|
1332
|
+
if (opts.replyTo) {
|
|
1333
|
+
return { type: "reply", discussionId: opts.replyTo };
|
|
1334
|
+
}
|
|
1335
|
+
if (opts.block) {
|
|
1336
|
+
return { type: "block", blockId: opts.block };
|
|
1337
|
+
}
|
|
1338
|
+
if (idOrUrl) {
|
|
1339
|
+
const id = parseNotionId(idOrUrl);
|
|
1340
|
+
return { type: "page", pageId: toUuid(id) };
|
|
1341
|
+
}
|
|
1342
|
+
throw new CliError(
|
|
1343
|
+
ErrorCodes.INVALID_ARG,
|
|
1344
|
+
"Provide a page ID/URL, --reply-to <discussion-id>, or --block <block-id>."
|
|
1345
|
+
);
|
|
1346
|
+
}
|
|
1319
1347
|
function commentAddCommand() {
|
|
1320
1348
|
const cmd = new Command6("comment");
|
|
1321
|
-
cmd.description("add a comment to a Notion page").argument("
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1349
|
+
cmd.description("add a comment to a Notion page, block, or discussion thread").argument("[id/url]", "Notion page ID or URL").requiredOption("-m, --message <text>", "comment text to post").option(
|
|
1350
|
+
"--reply-to <discussion-id>",
|
|
1351
|
+
"reply to an existing discussion thread"
|
|
1352
|
+
).option("--block <block-id>", "comment on a specific block").action(
|
|
1353
|
+
withErrorHandling(
|
|
1354
|
+
async (idOrUrl, opts) => {
|
|
1355
|
+
const target = resolveTarget(idOrUrl, opts);
|
|
1356
|
+
const { token, source } = await resolveToken();
|
|
1357
|
+
reportTokenSource(source);
|
|
1358
|
+
const client = createNotionClient(token);
|
|
1359
|
+
await addComment(client, target, opts.message, {
|
|
1360
|
+
asUser: source === "oauth"
|
|
1361
|
+
});
|
|
1362
|
+
process.stdout.write("Comment added.\n");
|
|
1363
|
+
}
|
|
1364
|
+
)
|
|
1333
1365
|
);
|
|
1334
1366
|
return cmd;
|
|
1335
1367
|
}
|
|
@@ -1352,6 +1384,14 @@ async function paginateResults(fetcher) {
|
|
|
1352
1384
|
}
|
|
1353
1385
|
|
|
1354
1386
|
// src/commands/comments.ts
|
|
1387
|
+
function formatParent(parent) {
|
|
1388
|
+
switch (parent.type) {
|
|
1389
|
+
case "page_id":
|
|
1390
|
+
return "page";
|
|
1391
|
+
case "block_id":
|
|
1392
|
+
return `block:${parent.block_id.slice(0, 8)}`;
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1355
1395
|
function commentsCommand() {
|
|
1356
1396
|
const cmd = new Command7("comments");
|
|
1357
1397
|
cmd.description("list comments on a Notion page").argument("<id/url>", "Notion page ID or URL").option("--json", "output as JSON").action(
|
|
@@ -1374,10 +1414,16 @@ function commentsCommand() {
|
|
|
1374
1414
|
return [
|
|
1375
1415
|
comment.created_time.split("T")[0],
|
|
1376
1416
|
`${comment.created_by.id.slice(0, 8)}...`,
|
|
1417
|
+
comment.discussion_id.slice(0, 8),
|
|
1418
|
+
formatParent(comment.parent),
|
|
1377
1419
|
text.slice(0, 80) + (text.length > 80 ? "\u2026" : "")
|
|
1378
1420
|
];
|
|
1379
1421
|
});
|
|
1380
|
-
printOutput(
|
|
1422
|
+
printOutput(
|
|
1423
|
+
comments,
|
|
1424
|
+
["DATE", "AUTHOR ID", "DISCUSSION", "PARENT", "COMMENT"],
|
|
1425
|
+
rows
|
|
1426
|
+
);
|
|
1381
1427
|
})
|
|
1382
1428
|
);
|
|
1383
1429
|
return cmd;
|
|
@@ -2212,6 +2258,15 @@ function lsCommand() {
|
|
|
2212
2258
|
}
|
|
2213
2259
|
return val;
|
|
2214
2260
|
}
|
|
2261
|
+
).option(
|
|
2262
|
+
"--sort <direction>",
|
|
2263
|
+
"sort by last edited time (asc or desc)",
|
|
2264
|
+
(val) => {
|
|
2265
|
+
if (val !== "asc" && val !== "desc") {
|
|
2266
|
+
throw new Error('--sort must be "asc" or "desc"');
|
|
2267
|
+
}
|
|
2268
|
+
return val;
|
|
2269
|
+
}
|
|
2215
2270
|
).option(
|
|
2216
2271
|
"--cursor <cursor>",
|
|
2217
2272
|
"start from this pagination cursor (from a previous --next hint)"
|
|
@@ -2225,6 +2280,10 @@ function lsCommand() {
|
|
|
2225
2280
|
reportTokenSource(source);
|
|
2226
2281
|
const notion = createNotionClient(token);
|
|
2227
2282
|
const response = await notion.search({
|
|
2283
|
+
sort: opts.sort ? {
|
|
2284
|
+
timestamp: "last_edited_time",
|
|
2285
|
+
direction: opts.sort === "asc" ? "ascending" : "descending"
|
|
2286
|
+
} : void 0,
|
|
2228
2287
|
start_cursor: opts.cursor,
|
|
2229
2288
|
page_size: 20
|
|
2230
2289
|
});
|
|
@@ -2564,6 +2623,15 @@ function searchCommand() {
|
|
|
2564
2623
|
}
|
|
2565
2624
|
return val;
|
|
2566
2625
|
}
|
|
2626
|
+
).option(
|
|
2627
|
+
"--sort <direction>",
|
|
2628
|
+
"sort by last edited time (asc or desc)",
|
|
2629
|
+
(val) => {
|
|
2630
|
+
if (val !== "asc" && val !== "desc") {
|
|
2631
|
+
throw new Error('--sort must be "asc" or "desc"');
|
|
2632
|
+
}
|
|
2633
|
+
return val;
|
|
2634
|
+
}
|
|
2567
2635
|
).option(
|
|
2568
2636
|
"--cursor <cursor>",
|
|
2569
2637
|
"start from this pagination cursor (from a previous --next hint)"
|
|
@@ -2579,6 +2647,10 @@ function searchCommand() {
|
|
|
2579
2647
|
const response = await notion.search({
|
|
2580
2648
|
query,
|
|
2581
2649
|
filter: opts.type ? { property: "object", value: toSdkFilterValue(opts.type) } : void 0,
|
|
2650
|
+
sort: opts.sort ? {
|
|
2651
|
+
timestamp: "last_edited_time",
|
|
2652
|
+
direction: opts.sort === "asc" ? "ascending" : "descending"
|
|
2653
|
+
} : void 0,
|
|
2582
2654
|
start_cursor: opts.cursor,
|
|
2583
2655
|
page_size: 20
|
|
2584
2656
|
});
|