@andrzejchm/notion-cli 0.8.0 → 0.9.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 +31 -4
- package/dist/cli.js +302 -71
- package/dist/cli.js.map +1 -1
- package/docs/FEATURE-PARITY.md +20 -23
- package/docs/README.agents.md +60 -13
- package/docs/skills/using-notion-cli/SKILL.md +0 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { readFileSync } from "fs";
|
|
5
5
|
import { dirname, join as join3 } from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
|
-
import { Command as
|
|
7
|
+
import { Command as Command24 } from "commander";
|
|
8
8
|
|
|
9
9
|
// src/commands/append.ts
|
|
10
10
|
import { Command } from "commander";
|
|
@@ -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;
|
|
@@ -1638,6 +1684,126 @@ function displayDate(date) {
|
|
|
1638
1684
|
if (!date) return "";
|
|
1639
1685
|
return date.end ? `${date.start} \u2192 ${date.end}` : date.start;
|
|
1640
1686
|
}
|
|
1687
|
+
var SIMPLE_PROPERTY_TYPES = /* @__PURE__ */ new Set([
|
|
1688
|
+
"title",
|
|
1689
|
+
"rich_text",
|
|
1690
|
+
"number",
|
|
1691
|
+
"date",
|
|
1692
|
+
"checkbox",
|
|
1693
|
+
"url",
|
|
1694
|
+
"email",
|
|
1695
|
+
"phone_number",
|
|
1696
|
+
"people",
|
|
1697
|
+
"files",
|
|
1698
|
+
"created_time",
|
|
1699
|
+
"last_edited_time"
|
|
1700
|
+
]);
|
|
1701
|
+
var OPTIONS_PROPERTY_TYPES = /* @__PURE__ */ new Set(["select", "multi_select", "status"]);
|
|
1702
|
+
var UNSUPPORTED_PROPERTY_TYPES = {
|
|
1703
|
+
relation: "requires a data_source_id reference",
|
|
1704
|
+
rollup: "requires relation and property references",
|
|
1705
|
+
formula: "requires an expression string",
|
|
1706
|
+
unique_id: "auto-managed by Notion"
|
|
1707
|
+
};
|
|
1708
|
+
function parsePropertyDefinition(defString) {
|
|
1709
|
+
if (!defString) {
|
|
1710
|
+
throw new CliError(
|
|
1711
|
+
ErrorCodes.INVALID_ARG,
|
|
1712
|
+
"Property definition cannot be empty",
|
|
1713
|
+
'Use format: --prop "Name:type" or --prop "Name:type:opt1,opt2"'
|
|
1714
|
+
);
|
|
1715
|
+
}
|
|
1716
|
+
const firstColon = defString.indexOf(":");
|
|
1717
|
+
if (firstColon === -1) {
|
|
1718
|
+
throw new CliError(
|
|
1719
|
+
ErrorCodes.INVALID_ARG,
|
|
1720
|
+
`Invalid property definition: "${defString}"`,
|
|
1721
|
+
'Use format: --prop "Name:type" or --prop "Name:type:opt1,opt2"'
|
|
1722
|
+
);
|
|
1723
|
+
}
|
|
1724
|
+
const name = defString.slice(0, firstColon);
|
|
1725
|
+
const rest = defString.slice(firstColon + 1);
|
|
1726
|
+
const secondColon = rest.indexOf(":");
|
|
1727
|
+
const type = secondColon === -1 ? rest : rest.slice(0, secondColon);
|
|
1728
|
+
const optionsStr = secondColon === -1 ? "" : rest.slice(secondColon + 1);
|
|
1729
|
+
if (type in UNSUPPORTED_PROPERTY_TYPES) {
|
|
1730
|
+
throw new CliError(
|
|
1731
|
+
ErrorCodes.INVALID_ARG,
|
|
1732
|
+
`Property type "${type}" is not supported via CLI \u2014 ${UNSUPPORTED_PROPERTY_TYPES[type]}`,
|
|
1733
|
+
"Supported types: title, rich_text, number, select, multi_select, status, date, checkbox, url, email, phone_number, people, files, created_time, last_edited_time"
|
|
1734
|
+
);
|
|
1735
|
+
}
|
|
1736
|
+
if (SIMPLE_PROPERTY_TYPES.has(type)) {
|
|
1737
|
+
return { name, config: { [type]: {} } };
|
|
1738
|
+
}
|
|
1739
|
+
if (OPTIONS_PROPERTY_TYPES.has(type)) {
|
|
1740
|
+
const options = optionsStr ? optionsStr.split(",").map((opt) => ({ name: opt.trim() })) : [];
|
|
1741
|
+
return { name, config: { [type]: { options } } };
|
|
1742
|
+
}
|
|
1743
|
+
throw new CliError(
|
|
1744
|
+
ErrorCodes.INVALID_ARG,
|
|
1745
|
+
`Unknown property type: "${type}"`,
|
|
1746
|
+
"Supported types: title, rich_text, number, select, multi_select, status, date, checkbox, url, email, phone_number, people, files, created_time, last_edited_time"
|
|
1747
|
+
);
|
|
1748
|
+
}
|
|
1749
|
+
function parsePropertyDefinitions(defStrings) {
|
|
1750
|
+
const properties = {};
|
|
1751
|
+
let hasTitleProperty = false;
|
|
1752
|
+
for (const def of defStrings) {
|
|
1753
|
+
const { name, config } = parsePropertyDefinition(def);
|
|
1754
|
+
if (name in properties) {
|
|
1755
|
+
throw new CliError(
|
|
1756
|
+
ErrorCodes.INVALID_ARG,
|
|
1757
|
+
`Duplicate property name: "${name}"`,
|
|
1758
|
+
"Each property must have a unique name"
|
|
1759
|
+
);
|
|
1760
|
+
}
|
|
1761
|
+
const isTitle = "title" in config;
|
|
1762
|
+
if (isTitle && hasTitleProperty) {
|
|
1763
|
+
throw new CliError(
|
|
1764
|
+
ErrorCodes.INVALID_ARG,
|
|
1765
|
+
"Only one title property is allowed per database",
|
|
1766
|
+
"Remove one of the title property definitions"
|
|
1767
|
+
);
|
|
1768
|
+
}
|
|
1769
|
+
if (isTitle) hasTitleProperty = true;
|
|
1770
|
+
properties[name] = config;
|
|
1771
|
+
}
|
|
1772
|
+
if (!hasTitleProperty) {
|
|
1773
|
+
properties.Name = { title: {} };
|
|
1774
|
+
}
|
|
1775
|
+
return properties;
|
|
1776
|
+
}
|
|
1777
|
+
async function createDatabase(client, parentId, title, properties) {
|
|
1778
|
+
return client.databases.create({
|
|
1779
|
+
parent: { type: "page_id", page_id: parentId },
|
|
1780
|
+
title: [{ type: "text", text: { content: title } }],
|
|
1781
|
+
initial_data_source: {
|
|
1782
|
+
properties
|
|
1783
|
+
}
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
async function resolveDataSourceId(client, idOrUrl) {
|
|
1787
|
+
const id = toUuid(parseNotionId(idOrUrl));
|
|
1788
|
+
try {
|
|
1789
|
+
await client.dataSources.retrieve({ data_source_id: id });
|
|
1790
|
+
return id;
|
|
1791
|
+
} catch {
|
|
1792
|
+
}
|
|
1793
|
+
try {
|
|
1794
|
+
const db = await client.databases.retrieve({
|
|
1795
|
+
database_id: id
|
|
1796
|
+
});
|
|
1797
|
+
if (db.data_sources && db.data_sources.length > 0) {
|
|
1798
|
+
return db.data_sources[0].id;
|
|
1799
|
+
}
|
|
1800
|
+
} catch {
|
|
1801
|
+
}
|
|
1802
|
+
throw new CliError(
|
|
1803
|
+
ErrorCodes.API_NOT_FOUND,
|
|
1804
|
+
`Could not find database or data source: ${id}`
|
|
1805
|
+
);
|
|
1806
|
+
}
|
|
1641
1807
|
function displayPropertyValue(prop) {
|
|
1642
1808
|
switch (prop.type) {
|
|
1643
1809
|
case "title":
|
|
@@ -1873,8 +2039,46 @@ function createPageCommand() {
|
|
|
1873
2039
|
return cmd;
|
|
1874
2040
|
}
|
|
1875
2041
|
|
|
1876
|
-
// src/commands/db/
|
|
2042
|
+
// src/commands/db/create.ts
|
|
1877
2043
|
import { Command as Command10 } from "commander";
|
|
2044
|
+
function collectProps2(val, acc) {
|
|
2045
|
+
acc.push(val);
|
|
2046
|
+
return acc;
|
|
2047
|
+
}
|
|
2048
|
+
function dbCreateCommand() {
|
|
2049
|
+
return new Command10("create").description("Create a new database under a parent page").requiredOption("--parent <id/url>", "parent page ID or URL").requiredOption("--title <title>", "database title").option(
|
|
2050
|
+
"--prop <definition>",
|
|
2051
|
+
'property definition (repeatable): --prop "Name:type:options"',
|
|
2052
|
+
collectProps2,
|
|
2053
|
+
[]
|
|
2054
|
+
).action(
|
|
2055
|
+
withErrorHandling(async (opts) => {
|
|
2056
|
+
const { token, source } = await resolveToken();
|
|
2057
|
+
reportTokenSource(source);
|
|
2058
|
+
const client = createNotionClient(token);
|
|
2059
|
+
const parentUuid = toUuid(parseNotionId(opts.parent));
|
|
2060
|
+
const properties = parsePropertyDefinitions(opts.prop);
|
|
2061
|
+
const response = await createDatabase(
|
|
2062
|
+
client,
|
|
2063
|
+
parentUuid,
|
|
2064
|
+
opts.title,
|
|
2065
|
+
properties
|
|
2066
|
+
);
|
|
2067
|
+
if (getOutputMode() === "json") {
|
|
2068
|
+
process.stdout.write(`${formatJSON(response)}
|
|
2069
|
+
`);
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
if ("url" in response) {
|
|
2073
|
+
process.stdout.write(`${response.url}
|
|
2074
|
+
`);
|
|
2075
|
+
}
|
|
2076
|
+
})
|
|
2077
|
+
);
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
// src/commands/db/query.ts
|
|
2081
|
+
import { Command as Command11 } from "commander";
|
|
1878
2082
|
var SKIP_TYPES_IN_AUTO = /* @__PURE__ */ new Set(["relation", "rich_text", "people"]);
|
|
1879
2083
|
function autoSelectColumns(schema, entries) {
|
|
1880
2084
|
const termWidth = process.stdout.columns || 120;
|
|
@@ -1902,7 +2106,7 @@ function autoSelectColumns(schema, entries) {
|
|
|
1902
2106
|
return selected;
|
|
1903
2107
|
}
|
|
1904
2108
|
function dbQueryCommand() {
|
|
1905
|
-
return new
|
|
2109
|
+
return new Command11("query").description("Query database entries with optional filtering and sorting").argument("<id>", "Notion database ID or URL").option(
|
|
1906
2110
|
"--filter <filter>",
|
|
1907
2111
|
'Filter entries (repeatable): --filter "Status=Done"',
|
|
1908
2112
|
collect,
|
|
@@ -1915,22 +2119,22 @@ function dbQueryCommand() {
|
|
|
1915
2119
|
).option(
|
|
1916
2120
|
"--columns <columns>",
|
|
1917
2121
|
'Comma-separated list of columns to display: --columns "Title,Status"'
|
|
1918
|
-
).
|
|
2122
|
+
).action(
|
|
1919
2123
|
withErrorHandling(
|
|
1920
2124
|
async (id, options) => {
|
|
1921
2125
|
const { token } = await resolveToken();
|
|
1922
2126
|
const client = createNotionClient(token);
|
|
1923
|
-
const
|
|
1924
|
-
const schema = await fetchDatabaseSchema(client,
|
|
2127
|
+
const dsId = await resolveDataSourceId(client, id);
|
|
2128
|
+
const schema = await fetchDatabaseSchema(client, dsId);
|
|
1925
2129
|
const columns = options.columns ? options.columns.split(",").map((c2) => c2.trim()) : void 0;
|
|
1926
2130
|
const filter = options.filter.length ? buildFilter(options.filter, schema) : void 0;
|
|
1927
2131
|
const sorts = options.sort.length ? buildSorts(options.sort) : void 0;
|
|
1928
|
-
const entries = await queryDatabase(client,
|
|
2132
|
+
const entries = await queryDatabase(client, dsId, {
|
|
1929
2133
|
filter,
|
|
1930
2134
|
sorts,
|
|
1931
2135
|
columns
|
|
1932
2136
|
});
|
|
1933
|
-
if (
|
|
2137
|
+
if (getOutputMode() === "json") {
|
|
1934
2138
|
process.stdout.write(`${formatJSON(entries.map((e) => e.raw))}
|
|
1935
2139
|
`);
|
|
1936
2140
|
return;
|
|
@@ -1957,15 +2161,15 @@ function collect(value, previous) {
|
|
|
1957
2161
|
}
|
|
1958
2162
|
|
|
1959
2163
|
// src/commands/db/schema.ts
|
|
1960
|
-
import { Command as
|
|
2164
|
+
import { Command as Command12 } from "commander";
|
|
1961
2165
|
function dbSchemaCommand() {
|
|
1962
|
-
return new
|
|
1963
|
-
withErrorHandling(async (id
|
|
2166
|
+
return new Command12("schema").description("Show database schema (property names, types, and options)").argument("<id>", "Notion database ID or URL").action(
|
|
2167
|
+
withErrorHandling(async (id) => {
|
|
1964
2168
|
const { token } = await resolveToken();
|
|
1965
2169
|
const client = createNotionClient(token);
|
|
1966
|
-
const
|
|
1967
|
-
const schema = await fetchDatabaseSchema(client,
|
|
1968
|
-
if (
|
|
2170
|
+
const dsId = await resolveDataSourceId(client, id);
|
|
2171
|
+
const schema = await fetchDatabaseSchema(client, dsId);
|
|
2172
|
+
if (getOutputMode() === "json") {
|
|
1969
2173
|
process.stdout.write(`${formatJSON(schema)}
|
|
1970
2174
|
`);
|
|
1971
2175
|
return;
|
|
@@ -1983,13 +2187,13 @@ function dbSchemaCommand() {
|
|
|
1983
2187
|
}
|
|
1984
2188
|
|
|
1985
2189
|
// src/commands/edit-page.ts
|
|
1986
|
-
import { Command as
|
|
2190
|
+
import { Command as Command13 } from "commander";
|
|
1987
2191
|
function collect2(val, acc) {
|
|
1988
2192
|
acc.push(val);
|
|
1989
2193
|
return acc;
|
|
1990
2194
|
}
|
|
1991
2195
|
function editPageCommand() {
|
|
1992
|
-
const cmd = new
|
|
2196
|
+
const cmd = new Command13("edit-page");
|
|
1993
2197
|
cmd.description(
|
|
1994
2198
|
"replace a Notion page's content \u2014 full page or a targeted section"
|
|
1995
2199
|
).argument("<id/url>", "Notion page ID or URL").option(
|
|
@@ -2087,7 +2291,7 @@ function editPageCommand() {
|
|
|
2087
2291
|
|
|
2088
2292
|
// src/commands/init.ts
|
|
2089
2293
|
import { confirm, input as input2, password } from "@inquirer/prompts";
|
|
2090
|
-
import { Command as
|
|
2294
|
+
import { Command as Command14 } from "commander";
|
|
2091
2295
|
async function runInitFlow() {
|
|
2092
2296
|
const profileName = await input2({
|
|
2093
2297
|
message: "Profile name:",
|
|
@@ -2167,7 +2371,7 @@ async function runInitFlow() {
|
|
|
2167
2371
|
stderrWrite(dim(" notion auth login"));
|
|
2168
2372
|
}
|
|
2169
2373
|
function initCommand() {
|
|
2170
|
-
const cmd = new
|
|
2374
|
+
const cmd = new Command14("init");
|
|
2171
2375
|
cmd.description("authenticate with Notion and save a profile").action(
|
|
2172
2376
|
withErrorHandling(async () => {
|
|
2173
2377
|
if (!process.stdin.isTTY) {
|
|
@@ -2185,7 +2389,7 @@ function initCommand() {
|
|
|
2185
2389
|
|
|
2186
2390
|
// src/commands/ls.ts
|
|
2187
2391
|
import { isFullPageOrDataSource } from "@notionhq/client";
|
|
2188
|
-
import { Command as
|
|
2392
|
+
import { Command as Command15 } from "commander";
|
|
2189
2393
|
function getTitle(item) {
|
|
2190
2394
|
if (item.object === "data_source") {
|
|
2191
2395
|
return item.title.map((t) => t.plain_text).join("") || "(untitled)";
|
|
@@ -2202,7 +2406,7 @@ function displayType(item) {
|
|
|
2202
2406
|
return item.object === "data_source" ? "database" : item.object;
|
|
2203
2407
|
}
|
|
2204
2408
|
function lsCommand() {
|
|
2205
|
-
const cmd = new
|
|
2409
|
+
const cmd = new Command15("ls");
|
|
2206
2410
|
cmd.description("list accessible Notion pages and databases").option(
|
|
2207
2411
|
"--type <type>",
|
|
2208
2412
|
"filter by object type (page or database)",
|
|
@@ -2212,6 +2416,15 @@ function lsCommand() {
|
|
|
2212
2416
|
}
|
|
2213
2417
|
return val;
|
|
2214
2418
|
}
|
|
2419
|
+
).option(
|
|
2420
|
+
"--sort <direction>",
|
|
2421
|
+
"sort by last edited time (asc or desc)",
|
|
2422
|
+
(val) => {
|
|
2423
|
+
if (val !== "asc" && val !== "desc") {
|
|
2424
|
+
throw new Error('--sort must be "asc" or "desc"');
|
|
2425
|
+
}
|
|
2426
|
+
return val;
|
|
2427
|
+
}
|
|
2215
2428
|
).option(
|
|
2216
2429
|
"--cursor <cursor>",
|
|
2217
2430
|
"start from this pagination cursor (from a previous --next hint)"
|
|
@@ -2225,6 +2438,10 @@ function lsCommand() {
|
|
|
2225
2438
|
reportTokenSource(source);
|
|
2226
2439
|
const notion = createNotionClient(token);
|
|
2227
2440
|
const response = await notion.search({
|
|
2441
|
+
sort: opts.sort ? {
|
|
2442
|
+
timestamp: "last_edited_time",
|
|
2443
|
+
direction: opts.sort === "asc" ? "ascending" : "descending"
|
|
2444
|
+
} : void 0,
|
|
2228
2445
|
start_cursor: opts.cursor,
|
|
2229
2446
|
page_size: 20
|
|
2230
2447
|
});
|
|
@@ -2265,10 +2482,10 @@ function lsCommand() {
|
|
|
2265
2482
|
// src/commands/open.ts
|
|
2266
2483
|
import { exec } from "child_process";
|
|
2267
2484
|
import { promisify } from "util";
|
|
2268
|
-
import { Command as
|
|
2485
|
+
import { Command as Command16 } from "commander";
|
|
2269
2486
|
var execAsync = promisify(exec);
|
|
2270
2487
|
function openCommand() {
|
|
2271
|
-
const cmd = new
|
|
2488
|
+
const cmd = new Command16("open");
|
|
2272
2489
|
cmd.description("open a Notion page in the default browser").argument("<id/url>", "Notion page ID or URL").action(
|
|
2273
2490
|
withErrorHandling(async (idOrUrl) => {
|
|
2274
2491
|
const id = parseNotionId(idOrUrl);
|
|
@@ -2284,9 +2501,9 @@ function openCommand() {
|
|
|
2284
2501
|
}
|
|
2285
2502
|
|
|
2286
2503
|
// src/commands/profile/list.ts
|
|
2287
|
-
import { Command as
|
|
2504
|
+
import { Command as Command17 } from "commander";
|
|
2288
2505
|
function profileListCommand() {
|
|
2289
|
-
const cmd = new
|
|
2506
|
+
const cmd = new Command17("list");
|
|
2290
2507
|
cmd.description("list all authentication profiles").action(
|
|
2291
2508
|
withErrorHandling(async () => {
|
|
2292
2509
|
const config = await readGlobalConfig();
|
|
@@ -2315,9 +2532,9 @@ function profileListCommand() {
|
|
|
2315
2532
|
}
|
|
2316
2533
|
|
|
2317
2534
|
// src/commands/profile/remove.ts
|
|
2318
|
-
import { Command as
|
|
2535
|
+
import { Command as Command18 } from "commander";
|
|
2319
2536
|
function profileRemoveCommand() {
|
|
2320
|
-
const cmd = new
|
|
2537
|
+
const cmd = new Command18("remove");
|
|
2321
2538
|
cmd.description("remove an authentication profile").argument("<name>", "profile name to remove").action(
|
|
2322
2539
|
withErrorHandling(async (name) => {
|
|
2323
2540
|
const config = await readGlobalConfig();
|
|
@@ -2343,9 +2560,9 @@ function profileRemoveCommand() {
|
|
|
2343
2560
|
}
|
|
2344
2561
|
|
|
2345
2562
|
// src/commands/profile/use.ts
|
|
2346
|
-
import { Command as
|
|
2563
|
+
import { Command as Command19 } from "commander";
|
|
2347
2564
|
function profileUseCommand() {
|
|
2348
|
-
const cmd = new
|
|
2565
|
+
const cmd = new Command19("use");
|
|
2349
2566
|
cmd.description("switch the active profile").argument("<name>", "profile name to activate").action(
|
|
2350
2567
|
withErrorHandling(async (name) => {
|
|
2351
2568
|
const config = await readGlobalConfig();
|
|
@@ -2368,7 +2585,7 @@ function profileUseCommand() {
|
|
|
2368
2585
|
}
|
|
2369
2586
|
|
|
2370
2587
|
// src/commands/read.ts
|
|
2371
|
-
import { Command as
|
|
2588
|
+
import { Command as Command20 } from "commander";
|
|
2372
2589
|
|
|
2373
2590
|
// src/output/markdown.ts
|
|
2374
2591
|
import { Chalk as Chalk2 } from "chalk";
|
|
@@ -2508,7 +2725,7 @@ async function fetchPageMarkdown(client, pageId) {
|
|
|
2508
2725
|
|
|
2509
2726
|
// src/commands/read.ts
|
|
2510
2727
|
function readCommand() {
|
|
2511
|
-
return new
|
|
2728
|
+
return new Command20("read").description("Read a Notion page as markdown").argument("<id>", "Notion page ID or URL").action(
|
|
2512
2729
|
withErrorHandling(async (id) => {
|
|
2513
2730
|
const { token } = await resolveToken();
|
|
2514
2731
|
const client = createNotionClient(token);
|
|
@@ -2534,7 +2751,7 @@ function readCommand() {
|
|
|
2534
2751
|
|
|
2535
2752
|
// src/commands/search.ts
|
|
2536
2753
|
import { isFullPageOrDataSource as isFullPageOrDataSource2 } from "@notionhq/client";
|
|
2537
|
-
import { Command as
|
|
2754
|
+
import { Command as Command21 } from "commander";
|
|
2538
2755
|
function getTitle2(item) {
|
|
2539
2756
|
if (item.object === "data_source") {
|
|
2540
2757
|
return item.title.map((t) => t.plain_text).join("") || "(untitled)";
|
|
@@ -2554,7 +2771,7 @@ function displayType2(item) {
|
|
|
2554
2771
|
return item.object === "data_source" ? "database" : item.object;
|
|
2555
2772
|
}
|
|
2556
2773
|
function searchCommand() {
|
|
2557
|
-
const cmd = new
|
|
2774
|
+
const cmd = new Command21("search");
|
|
2558
2775
|
cmd.description("search Notion workspace by keyword").argument("<query>", "search keyword").option(
|
|
2559
2776
|
"--type <type>",
|
|
2560
2777
|
"filter by object type (page or database)",
|
|
@@ -2564,6 +2781,15 @@ function searchCommand() {
|
|
|
2564
2781
|
}
|
|
2565
2782
|
return val;
|
|
2566
2783
|
}
|
|
2784
|
+
).option(
|
|
2785
|
+
"--sort <direction>",
|
|
2786
|
+
"sort by last edited time (asc or desc)",
|
|
2787
|
+
(val) => {
|
|
2788
|
+
if (val !== "asc" && val !== "desc") {
|
|
2789
|
+
throw new Error('--sort must be "asc" or "desc"');
|
|
2790
|
+
}
|
|
2791
|
+
return val;
|
|
2792
|
+
}
|
|
2567
2793
|
).option(
|
|
2568
2794
|
"--cursor <cursor>",
|
|
2569
2795
|
"start from this pagination cursor (from a previous --next hint)"
|
|
@@ -2579,6 +2805,10 @@ function searchCommand() {
|
|
|
2579
2805
|
const response = await notion.search({
|
|
2580
2806
|
query,
|
|
2581
2807
|
filter: opts.type ? { property: "object", value: toSdkFilterValue(opts.type) } : void 0,
|
|
2808
|
+
sort: opts.sort ? {
|
|
2809
|
+
timestamp: "last_edited_time",
|
|
2810
|
+
direction: opts.sort === "asc" ? "ascending" : "descending"
|
|
2811
|
+
} : void 0,
|
|
2582
2812
|
start_cursor: opts.cursor,
|
|
2583
2813
|
page_size: 20
|
|
2584
2814
|
});
|
|
@@ -2612,17 +2842,17 @@ function searchCommand() {
|
|
|
2612
2842
|
}
|
|
2613
2843
|
|
|
2614
2844
|
// src/commands/update.ts
|
|
2615
|
-
import { Command as
|
|
2616
|
-
function
|
|
2845
|
+
import { Command as Command22 } from "commander";
|
|
2846
|
+
function collectProps3(val, acc) {
|
|
2617
2847
|
acc.push(val);
|
|
2618
2848
|
return acc;
|
|
2619
2849
|
}
|
|
2620
2850
|
function updateCommand() {
|
|
2621
|
-
const cmd = new
|
|
2851
|
+
const cmd = new Command22("update");
|
|
2622
2852
|
cmd.description("update properties on a Notion page").argument("<id/url>", "Notion page ID or URL").option(
|
|
2623
2853
|
"--prop <property=value>",
|
|
2624
2854
|
"set a property value (repeatable)",
|
|
2625
|
-
|
|
2855
|
+
collectProps3,
|
|
2626
2856
|
[]
|
|
2627
2857
|
).option("--title <title>", "set the page title").action(
|
|
2628
2858
|
withErrorHandling(async (idOrUrl, opts) => {
|
|
@@ -2676,7 +2906,7 @@ function updateCommand() {
|
|
|
2676
2906
|
}
|
|
2677
2907
|
|
|
2678
2908
|
// src/commands/users.ts
|
|
2679
|
-
import { Command as
|
|
2909
|
+
import { Command as Command23 } from "commander";
|
|
2680
2910
|
function getEmailOrWorkspace(user) {
|
|
2681
2911
|
if (user.type === "person") {
|
|
2682
2912
|
return user.person.email ?? "\u2014";
|
|
@@ -2688,7 +2918,7 @@ function getEmailOrWorkspace(user) {
|
|
|
2688
2918
|
return "\u2014";
|
|
2689
2919
|
}
|
|
2690
2920
|
function usersCommand() {
|
|
2691
|
-
const cmd = new
|
|
2921
|
+
const cmd = new Command23("users");
|
|
2692
2922
|
cmd.description("list all users in the workspace").option("--json", "output as JSON").action(
|
|
2693
2923
|
withErrorHandling(async (opts) => {
|
|
2694
2924
|
if (opts.json) setOutputMode("json");
|
|
@@ -2719,7 +2949,7 @@ var __dirname = dirname(__filename);
|
|
|
2719
2949
|
var pkg = JSON.parse(
|
|
2720
2950
|
readFileSync(join3(__dirname, "../package.json"), "utf-8")
|
|
2721
2951
|
);
|
|
2722
|
-
var program = new
|
|
2952
|
+
var program = new Command24();
|
|
2723
2953
|
program.name("notion").description("Notion CLI \u2014 read Notion pages and databases from the terminal").version(pkg.version);
|
|
2724
2954
|
program.option("--verbose", "show API requests/responses").option("--color", "force color output").option("--json", "force JSON output (overrides TTY detection)").option("--md", "force markdown output for page content");
|
|
2725
2955
|
program.configureOutput({
|
|
@@ -2740,7 +2970,7 @@ program.hook("preAction", (thisCommand) => {
|
|
|
2740
2970
|
setOutputMode("md");
|
|
2741
2971
|
}
|
|
2742
2972
|
});
|
|
2743
|
-
var authCmd = new
|
|
2973
|
+
var authCmd = new Command24("auth").description("manage Notion authentication");
|
|
2744
2974
|
authCmd.action(authDefaultAction(authCmd));
|
|
2745
2975
|
authCmd.addCommand(loginCommand());
|
|
2746
2976
|
authCmd.addCommand(logoutCommand());
|
|
@@ -2750,7 +2980,7 @@ authCmd.addCommand(profileUseCommand());
|
|
|
2750
2980
|
authCmd.addCommand(profileRemoveCommand());
|
|
2751
2981
|
program.addCommand(authCmd);
|
|
2752
2982
|
program.addCommand(initCommand(), { hidden: true });
|
|
2753
|
-
var profileCmd = new
|
|
2983
|
+
var profileCmd = new Command24("profile").description(
|
|
2754
2984
|
"manage authentication profiles"
|
|
2755
2985
|
);
|
|
2756
2986
|
profileCmd.addCommand(profileListCommand());
|
|
@@ -2769,7 +2999,8 @@ program.addCommand(createPageCommand());
|
|
|
2769
2999
|
program.addCommand(editPageCommand());
|
|
2770
3000
|
program.addCommand(updateCommand());
|
|
2771
3001
|
program.addCommand(archiveCommand());
|
|
2772
|
-
var dbCmd = new
|
|
3002
|
+
var dbCmd = new Command24("db").description("Database operations");
|
|
3003
|
+
dbCmd.addCommand(dbCreateCommand());
|
|
2773
3004
|
dbCmd.addCommand(dbSchemaCommand());
|
|
2774
3005
|
dbCmd.addCommand(dbQueryCommand());
|
|
2775
3006
|
program.addCommand(dbCmd);
|