@catafal/notion-cli 5.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.
Files changed (162) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +552 -0
  3. package/bin/dev +17 -0
  4. package/bin/dev.cmd +3 -0
  5. package/bin/run +14 -0
  6. package/bin/run.cmd +3 -0
  7. package/dist/base-command.d.ts +73 -0
  8. package/dist/base-command.js +179 -0
  9. package/dist/base-flags.d.ts +14 -0
  10. package/dist/base-flags.js +59 -0
  11. package/dist/cache.d.ts +84 -0
  12. package/dist/cache.js +351 -0
  13. package/dist/commands/append.d.ts +37 -0
  14. package/dist/commands/append.js +120 -0
  15. package/dist/commands/batch/delete.d.ts +42 -0
  16. package/dist/commands/batch/delete.js +199 -0
  17. package/dist/commands/batch/retrieve.d.ts +43 -0
  18. package/dist/commands/batch/retrieve.js +272 -0
  19. package/dist/commands/block/append.d.ts +42 -0
  20. package/dist/commands/block/append.js +219 -0
  21. package/dist/commands/block/delete.d.ts +30 -0
  22. package/dist/commands/block/delete.js +97 -0
  23. package/dist/commands/block/retrieve/children.d.ts +31 -0
  24. package/dist/commands/block/retrieve/children.js +177 -0
  25. package/dist/commands/block/retrieve.d.ts +30 -0
  26. package/dist/commands/block/retrieve.js +101 -0
  27. package/dist/commands/block/update.d.ts +45 -0
  28. package/dist/commands/block/update.js +242 -0
  29. package/dist/commands/bookmark/list.d.ts +30 -0
  30. package/dist/commands/bookmark/list.js +60 -0
  31. package/dist/commands/bookmark/remove.d.ts +26 -0
  32. package/dist/commands/bookmark/remove.js +47 -0
  33. package/dist/commands/bookmark/set.d.ts +29 -0
  34. package/dist/commands/bookmark/set.js +96 -0
  35. package/dist/commands/browse.d.ts +13 -0
  36. package/dist/commands/browse.js +44 -0
  37. package/dist/commands/cache/info.d.ts +19 -0
  38. package/dist/commands/cache/info.js +145 -0
  39. package/dist/commands/config/set-token.d.ts +22 -0
  40. package/dist/commands/config/set-token.js +137 -0
  41. package/dist/commands/daily/index.d.ts +32 -0
  42. package/dist/commands/daily/index.js +135 -0
  43. package/dist/commands/daily/setup.d.ts +42 -0
  44. package/dist/commands/daily/setup.js +149 -0
  45. package/dist/commands/db/create.d.ts +31 -0
  46. package/dist/commands/db/create.js +124 -0
  47. package/dist/commands/db/query.d.ts +41 -0
  48. package/dist/commands/db/query.js +360 -0
  49. package/dist/commands/db/retrieve.d.ts +33 -0
  50. package/dist/commands/db/retrieve.js +134 -0
  51. package/dist/commands/db/schema.d.ts +32 -0
  52. package/dist/commands/db/schema.js +308 -0
  53. package/dist/commands/db/update.d.ts +31 -0
  54. package/dist/commands/db/update.js +117 -0
  55. package/dist/commands/doctor.d.ts +50 -0
  56. package/dist/commands/doctor.js +420 -0
  57. package/dist/commands/init.d.ts +65 -0
  58. package/dist/commands/init.js +479 -0
  59. package/dist/commands/list.d.ts +29 -0
  60. package/dist/commands/list.js +219 -0
  61. package/dist/commands/open.d.ts +29 -0
  62. package/dist/commands/open.js +100 -0
  63. package/dist/commands/page/create.d.ts +33 -0
  64. package/dist/commands/page/create.js +261 -0
  65. package/dist/commands/page/delete.d.ts +36 -0
  66. package/dist/commands/page/delete.js +107 -0
  67. package/dist/commands/page/export.d.ts +38 -0
  68. package/dist/commands/page/export.js +120 -0
  69. package/dist/commands/page/retrieve/property_item.d.ts +24 -0
  70. package/dist/commands/page/retrieve/property_item.js +75 -0
  71. package/dist/commands/page/retrieve.d.ts +36 -0
  72. package/dist/commands/page/retrieve.js +244 -0
  73. package/dist/commands/page/update.d.ts +34 -0
  74. package/dist/commands/page/update.js +184 -0
  75. package/dist/commands/quick.d.ts +35 -0
  76. package/dist/commands/quick.js +168 -0
  77. package/dist/commands/search.d.ts +43 -0
  78. package/dist/commands/search.js +361 -0
  79. package/dist/commands/stats.d.ts +35 -0
  80. package/dist/commands/stats.js +274 -0
  81. package/dist/commands/sync.d.ts +24 -0
  82. package/dist/commands/sync.js +183 -0
  83. package/dist/commands/template/get.d.ts +28 -0
  84. package/dist/commands/template/get.js +59 -0
  85. package/dist/commands/template/list.d.ts +32 -0
  86. package/dist/commands/template/list.js +62 -0
  87. package/dist/commands/template/remove.d.ts +27 -0
  88. package/dist/commands/template/remove.js +48 -0
  89. package/dist/commands/template/save.d.ts +32 -0
  90. package/dist/commands/template/save.js +92 -0
  91. package/dist/commands/template/use.d.ts +34 -0
  92. package/dist/commands/template/use.js +142 -0
  93. package/dist/commands/user/list.d.ts +27 -0
  94. package/dist/commands/user/list.js +99 -0
  95. package/dist/commands/user/retrieve/bot.d.ts +28 -0
  96. package/dist/commands/user/retrieve/bot.js +96 -0
  97. package/dist/commands/user/retrieve.d.ts +30 -0
  98. package/dist/commands/user/retrieve.js +103 -0
  99. package/dist/commands/whoami.d.ts +19 -0
  100. package/dist/commands/whoami.js +175 -0
  101. package/dist/deduplication.d.ts +41 -0
  102. package/dist/deduplication.js +71 -0
  103. package/dist/envelope.d.ts +169 -0
  104. package/dist/envelope.js +257 -0
  105. package/dist/errors/enhanced-errors.d.ts +168 -0
  106. package/dist/errors/enhanced-errors.js +567 -0
  107. package/dist/errors/index.d.ts +18 -0
  108. package/dist/errors/index.js +33 -0
  109. package/dist/examples/cache-retry-examples.d.ts +64 -0
  110. package/dist/examples/cache-retry-examples.js +375 -0
  111. package/dist/helper.d.ts +102 -0
  112. package/dist/helper.js +885 -0
  113. package/dist/http-agent.d.ts +38 -0
  114. package/dist/http-agent.js +60 -0
  115. package/dist/index.d.ts +1 -0
  116. package/dist/index.js +4 -0
  117. package/dist/interface.d.ts +4 -0
  118. package/dist/interface.js +2 -0
  119. package/dist/notion.d.ts +144 -0
  120. package/dist/notion.js +547 -0
  121. package/dist/retry.d.ts +72 -0
  122. package/dist/retry.js +381 -0
  123. package/dist/utils/bookmarks.d.ts +32 -0
  124. package/dist/utils/bookmarks.js +98 -0
  125. package/dist/utils/daily-config.d.ts +22 -0
  126. package/dist/utils/daily-config.js +60 -0
  127. package/dist/utils/disk-cache.d.ts +80 -0
  128. package/dist/utils/disk-cache.js +291 -0
  129. package/dist/utils/fuzzy.d.ts +36 -0
  130. package/dist/utils/fuzzy.js +69 -0
  131. package/dist/utils/interactive-navigator.d.ts +63 -0
  132. package/dist/utils/interactive-navigator.js +123 -0
  133. package/dist/utils/markdown-to-blocks.d.ts +21 -0
  134. package/dist/utils/markdown-to-blocks.js +333 -0
  135. package/dist/utils/notion-resolver.d.ts +49 -0
  136. package/dist/utils/notion-resolver.js +278 -0
  137. package/dist/utils/notion-url-parser.d.ts +48 -0
  138. package/dist/utils/notion-url-parser.js +121 -0
  139. package/dist/utils/property-expander.d.ts +45 -0
  140. package/dist/utils/property-expander.js +323 -0
  141. package/dist/utils/schema-examples.d.ts +40 -0
  142. package/dist/utils/schema-examples.js +359 -0
  143. package/dist/utils/schema-extractor.d.ts +65 -0
  144. package/dist/utils/schema-extractor.js +235 -0
  145. package/dist/utils/shell-config.d.ts +30 -0
  146. package/dist/utils/shell-config.js +84 -0
  147. package/dist/utils/table-formatter.d.ts +36 -0
  148. package/dist/utils/table-formatter.js +125 -0
  149. package/dist/utils/templates.d.ts +30 -0
  150. package/dist/utils/templates.js +82 -0
  151. package/dist/utils/terminal-banner.d.ts +24 -0
  152. package/dist/utils/terminal-banner.js +34 -0
  153. package/dist/utils/token-validator.d.ts +42 -0
  154. package/dist/utils/token-validator.js +66 -0
  155. package/dist/utils/update-notifier.d.ts +26 -0
  156. package/dist/utils/update-notifier.js +54 -0
  157. package/dist/utils/workspace-cache.d.ts +58 -0
  158. package/dist/utils/workspace-cache.js +185 -0
  159. package/oclif.manifest.json +6471 -0
  160. package/package.json +118 -0
  161. package/scripts/banner.js +38 -0
  162. package/scripts/postinstall.js +44 -0
@@ -0,0 +1,244 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const table_formatter_1 = require("../../utils/table-formatter");
5
+ const notion = require("../../notion");
6
+ const helper_1 = require("../../helper");
7
+ const notion_to_md_1 = require("notion-to-md");
8
+ const base_flags_1 = require("../../base-flags");
9
+ const notion_resolver_1 = require("../../utils/notion-resolver");
10
+ const errors_1 = require("../../errors");
11
+ class PageRetrieve extends core_1.Command {
12
+ async run() {
13
+ const { args, flags } = await this.parse(PageRetrieve);
14
+ try {
15
+ // Resolve ID from URL, direct ID, or name (future)
16
+ const pageId = await (0, notion_resolver_1.resolveNotionId)(args.page_id, 'page');
17
+ // Handle map flag (fast structure discovery with parallel fetching)
18
+ if (flags.map) {
19
+ const mapData = await notion.mapPageStructure(pageId);
20
+ // Handle JSON output for automation (takes precedence)
21
+ if (flags.json) {
22
+ this.log(JSON.stringify({
23
+ success: true,
24
+ data: mapData,
25
+ timestamp: new Date().toISOString()
26
+ }, null, 2));
27
+ process.exit(0);
28
+ return;
29
+ }
30
+ // Handle compact JSON output
31
+ if (flags['compact-json']) {
32
+ (0, helper_1.outputCompactJson)(mapData);
33
+ process.exit(0);
34
+ return;
35
+ }
36
+ // Default: pretty JSON output for map
37
+ this.log(JSON.stringify(mapData, null, 2));
38
+ process.exit(0);
39
+ return;
40
+ }
41
+ // Handle page content as markdown (uses NotionToMarkdown)
42
+ if (flags.markdown) {
43
+ const n2m = new notion_to_md_1.NotionToMarkdown({ notionClient: notion.client });
44
+ const mdBlocks = await n2m.pageToMarkdown(pageId);
45
+ const mdString = n2m.toMarkdownString(mdBlocks);
46
+ console.log(mdString.parent);
47
+ process.exit(0);
48
+ return;
49
+ }
50
+ // Handle recursive fetching
51
+ if (flags.recursive) {
52
+ const recursiveData = await notion.retrievePageRecursive(pageId, 0, flags['max-depth']);
53
+ // Handle JSON output for automation (takes precedence)
54
+ if (flags.json) {
55
+ this.log(JSON.stringify({
56
+ success: true,
57
+ data: recursiveData,
58
+ timestamp: new Date().toISOString()
59
+ }, null, 2));
60
+ process.exit(0);
61
+ return;
62
+ }
63
+ // Handle compact JSON output
64
+ if (flags['compact-json']) {
65
+ (0, helper_1.outputCompactJson)(recursiveData);
66
+ process.exit(0);
67
+ return;
68
+ }
69
+ // Handle raw JSON output
70
+ if (flags.raw) {
71
+ (0, helper_1.outputRawJson)(recursiveData);
72
+ process.exit(0);
73
+ return;
74
+ }
75
+ // For other formats, show a message that they're not supported with recursive
76
+ this.error('Recursive mode only supports --json, --compact-json, or --raw output formats');
77
+ process.exit(1);
78
+ return;
79
+ }
80
+ const pageProps = {
81
+ page_id: pageId,
82
+ };
83
+ let res = await notion.retrievePage(pageProps);
84
+ // Apply minimal flag to strip metadata
85
+ if (flags.minimal) {
86
+ res = (0, helper_1.stripMetadata)(res);
87
+ }
88
+ // Handle JSON output for automation (takes precedence)
89
+ if (flags.json) {
90
+ this.log(JSON.stringify({
91
+ success: true,
92
+ data: res,
93
+ timestamp: new Date().toISOString()
94
+ }, null, 2));
95
+ process.exit(0);
96
+ return;
97
+ }
98
+ // Define columns for table output
99
+ const columns = {
100
+ title: {
101
+ get: (row) => {
102
+ return (0, helper_1.getPageTitle)(row);
103
+ },
104
+ },
105
+ object: {},
106
+ id: {},
107
+ url: {},
108
+ };
109
+ // Handle compact JSON output
110
+ if (flags['compact-json']) {
111
+ (0, helper_1.outputCompactJson)(res);
112
+ process.exit(0);
113
+ return;
114
+ }
115
+ // Handle pretty table output
116
+ if (flags.pretty) {
117
+ (0, helper_1.outputPrettyTable)([res], columns);
118
+ // Show hint after table output
119
+ (0, helper_1.showRawFlagHint)(1, res);
120
+ process.exit(0);
121
+ return;
122
+ }
123
+ // Handle raw JSON output
124
+ if (flags.raw) {
125
+ (0, helper_1.outputRawJson)(res);
126
+ process.exit(0);
127
+ return;
128
+ }
129
+ // Handle table output (default)
130
+ const options = {
131
+ printLine: this.log.bind(this),
132
+ ...flags,
133
+ };
134
+ (0, table_formatter_1.formatTable)([res], columns, options);
135
+ // Show hint after table output to make -r flag discoverable
136
+ (0, helper_1.showRawFlagHint)(1, res);
137
+ }
138
+ catch (error) {
139
+ const cliError = error instanceof errors_1.NotionCLIError
140
+ ? error
141
+ : (0, errors_1.wrapNotionError)(error, {
142
+ resourceType: 'page',
143
+ attemptedId: args.page_id,
144
+ endpoint: 'pages.retrieve'
145
+ });
146
+ if (flags.json) {
147
+ this.log(JSON.stringify(cliError.toJSON(), null, 2));
148
+ }
149
+ else {
150
+ this.error(cliError.toHumanString());
151
+ }
152
+ process.exit(1);
153
+ }
154
+ }
155
+ }
156
+ PageRetrieve.description = 'Retrieve a page';
157
+ PageRetrieve.aliases = ['page:r'];
158
+ PageRetrieve.examples = [
159
+ {
160
+ description: 'Retrieve a page with full data (recommended for AI assistants)',
161
+ command: `$ notion-cli page retrieve PAGE_ID -r`,
162
+ },
163
+ {
164
+ description: 'Fast structure overview (90% faster than full fetch)',
165
+ command: `$ notion-cli page retrieve PAGE_ID --map`,
166
+ },
167
+ {
168
+ description: 'Fast structure overview with compact JSON',
169
+ command: `$ notion-cli page retrieve PAGE_ID --map --compact-json`,
170
+ },
171
+ {
172
+ description: 'Retrieve entire page tree with all nested content (35% token reduction)',
173
+ command: `$ notion-cli page retrieve PAGE_ID --recursive --compact-json`,
174
+ },
175
+ {
176
+ description: 'Retrieve page tree with custom depth limit',
177
+ command: `$ notion-cli page retrieve PAGE_ID -R --max-depth 5 --json`,
178
+ },
179
+ {
180
+ description: 'Retrieve a page and output table',
181
+ command: `$ notion-cli page retrieve PAGE_ID`,
182
+ },
183
+ {
184
+ description: 'Retrieve a page via URL',
185
+ command: `$ notion-cli page retrieve https://notion.so/PAGE_ID`,
186
+ },
187
+ {
188
+ description: 'Retrieve a page and output raw json',
189
+ command: `$ notion-cli page retrieve PAGE_ID -r`,
190
+ },
191
+ {
192
+ description: 'Retrieve a page and output markdown',
193
+ command: `$ notion-cli page retrieve PAGE_ID -m`,
194
+ },
195
+ {
196
+ description: 'Retrieve a page metadata and output as markdown table',
197
+ command: `$ notion-cli page retrieve PAGE_ID --markdown`,
198
+ },
199
+ {
200
+ description: 'Retrieve a page metadata and output as compact JSON',
201
+ command: `$ notion-cli page retrieve PAGE_ID --compact-json`,
202
+ },
203
+ {
204
+ description: 'Retrieve a page and output JSON for automation',
205
+ command: `$ notion-cli page retrieve PAGE_ID --json`,
206
+ },
207
+ ];
208
+ PageRetrieve.args = {
209
+ page_id: core_1.Args.string({
210
+ required: true,
211
+ description: 'Page ID or full Notion URL (e.g., https://notion.so/...)',
212
+ }),
213
+ };
214
+ PageRetrieve.flags = {
215
+ raw: core_1.Flags.boolean({
216
+ char: 'r',
217
+ description: 'output raw json (recommended for AI assistants - returns all fields)',
218
+ }),
219
+ markdown: core_1.Flags.boolean({
220
+ char: 'm',
221
+ description: 'output page content as markdown',
222
+ }),
223
+ map: core_1.Flags.boolean({
224
+ description: 'fast structure discovery (returns minimal info: titles, types, IDs)',
225
+ default: false,
226
+ exclusive: ['raw', 'markdown'],
227
+ }),
228
+ recursive: core_1.Flags.boolean({
229
+ char: 'R',
230
+ description: 'recursively fetch all blocks and nested pages (reduces API calls)',
231
+ default: false,
232
+ }),
233
+ 'max-depth': core_1.Flags.integer({
234
+ description: 'maximum recursion depth for --recursive (default: 3)',
235
+ default: 3,
236
+ min: 1,
237
+ max: 10,
238
+ dependsOn: ['recursive'],
239
+ }),
240
+ ...table_formatter_1.tableFlags,
241
+ ...base_flags_1.OutputFormatFlags,
242
+ ...base_flags_1.AutomationFlags,
243
+ };
244
+ exports.default = PageRetrieve;
@@ -0,0 +1,34 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class PageUpdate extends Command {
3
+ static description: string;
4
+ static aliases: string[];
5
+ static examples: {
6
+ description: string;
7
+ command: string;
8
+ }[];
9
+ static args: {
10
+ page_id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
11
+ };
12
+ static flags: {
13
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
14
+ 'page-size': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
15
+ retry: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
16
+ timeout: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
17
+ 'no-cache': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
18
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
19
+ minimal: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
20
+ columns: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
21
+ sort: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
22
+ filter: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
23
+ csv: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
24
+ extended: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
25
+ 'no-truncate': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
26
+ 'no-header': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
27
+ archived: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
28
+ unarchive: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
29
+ properties: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
30
+ 'simple-properties': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
31
+ raw: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
32
+ };
33
+ run(): Promise<void>;
34
+ }
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const table_formatter_1 = require("../../utils/table-formatter");
5
+ const notion = require("../../notion");
6
+ const helper_1 = require("../../helper");
7
+ const notion_resolver_1 = require("../../utils/notion-resolver");
8
+ const base_flags_1 = require("../../base-flags");
9
+ const errors_1 = require("../../errors");
10
+ const property_expander_1 = require("../../utils/property-expander");
11
+ class PageUpdate extends core_1.Command {
12
+ async run() {
13
+ const { args, flags } = await this.parse(PageUpdate);
14
+ try {
15
+ // Resolve ID from URL, direct ID, or name (future)
16
+ const pageId = await (0, notion_resolver_1.resolveNotionId)(args.page_id, 'page');
17
+ const pageProps = {
18
+ page_id: pageId,
19
+ };
20
+ // Handle archived flags
21
+ if (flags.archived) {
22
+ pageProps.archived = true;
23
+ }
24
+ if (flags.unarchive) {
25
+ pageProps.archived = false;
26
+ }
27
+ // Handle properties update
28
+ if (flags.properties) {
29
+ try {
30
+ const parsedProps = JSON.parse(flags.properties);
31
+ if (flags['simple-properties']) {
32
+ // User provided simple format - expand to Notion format
33
+ // Need to get the page first to find its parent database
34
+ const page = await notion.retrievePage({ page_id: pageId });
35
+ // Check if page is in a database
36
+ if (!('parent' in page) || !('data_source_id' in page.parent)) {
37
+ throw new Error('The --simple-properties flag can only be used with pages in a database. ' +
38
+ 'This page does not have a parent database.');
39
+ }
40
+ // Get the database schema
41
+ const parentDataSourceId = page.parent.data_source_id;
42
+ const dbSchema = await notion.retrieveDataSource(parentDataSourceId);
43
+ // Expand simple properties to Notion format
44
+ pageProps.properties = await (0, property_expander_1.expandSimpleProperties)(parsedProps, dbSchema.properties);
45
+ }
46
+ else {
47
+ // Use raw Notion format
48
+ pageProps.properties = parsedProps;
49
+ }
50
+ }
51
+ catch (error) {
52
+ if (error.message.includes('Unexpected token') || error.message.includes('JSON')) {
53
+ throw new Error(`Invalid JSON in --properties flag: ${error.message}\n` +
54
+ `Example: --properties '{"Status": "Done", "Priority": "High"}'`);
55
+ }
56
+ throw error;
57
+ }
58
+ }
59
+ const res = await notion.updatePageProps(pageProps);
60
+ // Handle JSON output for automation
61
+ if (flags.json) {
62
+ this.log(JSON.stringify({
63
+ success: true,
64
+ data: res,
65
+ timestamp: new Date().toISOString()
66
+ }, null, 2));
67
+ process.exit(0);
68
+ return;
69
+ }
70
+ // Handle raw JSON output (legacy)
71
+ if (flags.raw) {
72
+ (0, helper_1.outputRawJson)(res);
73
+ process.exit(0);
74
+ return;
75
+ }
76
+ // Handle table output
77
+ const columns = {
78
+ title: {
79
+ get: (row) => {
80
+ return (0, helper_1.getPageTitle)(row);
81
+ },
82
+ },
83
+ object: {},
84
+ id: {},
85
+ url: {},
86
+ };
87
+ const options = {
88
+ printLine: this.log.bind(this),
89
+ ...flags,
90
+ };
91
+ (0, table_formatter_1.formatTable)([res], columns, options);
92
+ process.exit(0);
93
+ }
94
+ catch (error) {
95
+ const cliError = error instanceof errors_1.NotionCLIError
96
+ ? error
97
+ : (0, errors_1.wrapNotionError)(error, {
98
+ resourceType: 'page',
99
+ attemptedId: args.page_id,
100
+ endpoint: 'pages.update'
101
+ });
102
+ if (flags.json) {
103
+ this.log(JSON.stringify(cliError.toJSON(), null, 2));
104
+ }
105
+ else {
106
+ this.error(cliError.toHumanString());
107
+ }
108
+ process.exit(1);
109
+ }
110
+ }
111
+ }
112
+ PageUpdate.description = 'Update a page';
113
+ PageUpdate.aliases = ['page:u'];
114
+ PageUpdate.examples = [
115
+ {
116
+ description: 'Update a page and output table',
117
+ command: `$ notion-cli page update PAGE_ID`,
118
+ },
119
+ {
120
+ description: 'Update a page via URL',
121
+ command: `$ notion-cli page update https://notion.so/PAGE_ID -a`,
122
+ },
123
+ {
124
+ description: 'Update page properties with simple format (recommended for AI agents)',
125
+ command: `$ notion-cli page update PAGE_ID -S --properties '{"Status": "Done", "Priority": "High"}'`,
126
+ },
127
+ {
128
+ description: 'Update page properties with relative date',
129
+ command: `$ notion-cli page update PAGE_ID -S --properties '{"Due Date": "tomorrow", "Status": "In Progress"}'`,
130
+ },
131
+ {
132
+ description: 'Update page with multi-select tags',
133
+ command: `$ notion-cli page update PAGE_ID -S --properties '{"Tags": ["urgent", "bug"], "Status": "Done"}'`,
134
+ },
135
+ {
136
+ description: 'Update a page and output raw json',
137
+ command: `$ notion-cli page update PAGE_ID -r`,
138
+ },
139
+ {
140
+ description: 'Update a page and archive',
141
+ command: `$ notion-cli page update PAGE_ID -a`,
142
+ },
143
+ {
144
+ description: 'Update a page and unarchive',
145
+ command: `$ notion-cli page update PAGE_ID -u`,
146
+ },
147
+ {
148
+ description: 'Update a page and archive and output raw json',
149
+ command: `$ notion-cli page update PAGE_ID -a -r`,
150
+ },
151
+ {
152
+ description: 'Update a page and unarchive and output raw json',
153
+ command: `$ notion-cli page update PAGE_ID -u -r`,
154
+ },
155
+ {
156
+ description: 'Update a page and output JSON for automation',
157
+ command: `$ notion-cli page update PAGE_ID -a --json`,
158
+ },
159
+ ];
160
+ PageUpdate.args = {
161
+ page_id: core_1.Args.string({
162
+ required: true,
163
+ description: 'Page ID or full Notion URL (e.g., https://notion.so/...)',
164
+ }),
165
+ };
166
+ PageUpdate.flags = {
167
+ archived: core_1.Flags.boolean({ char: 'a', description: 'Archive the page' }),
168
+ unarchive: core_1.Flags.boolean({ char: 'u', description: 'Unarchive the page' }),
169
+ properties: core_1.Flags.string({
170
+ description: 'Page properties to update as JSON string',
171
+ }),
172
+ 'simple-properties': core_1.Flags.boolean({
173
+ char: 'S',
174
+ description: 'Use simplified property format (flat key-value pairs, recommended for AI agents)',
175
+ default: false,
176
+ }),
177
+ raw: core_1.Flags.boolean({
178
+ char: 'r',
179
+ description: 'output raw json',
180
+ }),
181
+ ...table_formatter_1.tableFlags,
182
+ ...base_flags_1.AutomationFlags,
183
+ };
184
+ exports.default = PageUpdate;
@@ -0,0 +1,35 @@
1
+ import { Command } from '@oclif/core';
2
+ /**
3
+ * Zero-friction page creation for quick thoughts and notes.
4
+ *
5
+ * Uses the default bookmark (or --to flag) to know which database to target.
6
+ * Title is the first line; remaining lines become page body as markdown blocks.
7
+ *
8
+ * Supports stdin piping: echo "notes" | notion-cli quick --title "From pipe"
9
+ */
10
+ export default class Quick extends Command {
11
+ static description: string;
12
+ static aliases: string[];
13
+ static examples: {
14
+ description: string;
15
+ command: string;
16
+ }[];
17
+ static args: {
18
+ content: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
19
+ };
20
+ static flags: {
21
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
22
+ 'page-size': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
23
+ retry: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
24
+ timeout: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
25
+ 'no-cache': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
26
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
27
+ minimal: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
28
+ to: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
29
+ title: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
30
+ template: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
31
+ };
32
+ run(): Promise<void>;
33
+ /** Read all data from stdin (for piped input). */
34
+ private readStdin;
35
+ }
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const notion = require("../notion");
5
+ const notion_resolver_1 = require("../utils/notion-resolver");
6
+ const bookmarks_1 = require("../utils/bookmarks");
7
+ const templates_1 = require("../utils/templates");
8
+ const property_expander_1 = require("../utils/property-expander");
9
+ const markdown_to_blocks_1 = require("../utils/markdown-to-blocks");
10
+ const base_flags_1 = require("../base-flags");
11
+ const errors_1 = require("../errors");
12
+ /**
13
+ * Zero-friction page creation for quick thoughts and notes.
14
+ *
15
+ * Uses the default bookmark (or --to flag) to know which database to target.
16
+ * Title is the first line; remaining lines become page body as markdown blocks.
17
+ *
18
+ * Supports stdin piping: echo "notes" | notion-cli quick --title "From pipe"
19
+ */
20
+ class Quick extends core_1.Command {
21
+ async run() {
22
+ const { args, flags } = await this.parse(Quick);
23
+ try {
24
+ // 1. Get content — from arg or stdin
25
+ let content = args.content || '';
26
+ if (!content && !process.stdin.isTTY) {
27
+ content = await this.readStdin();
28
+ }
29
+ if (!content && !flags.title) {
30
+ this.error('Provide content as argument or pipe via stdin.\n' +
31
+ 'Usage: notion-cli quick "My note"\n' +
32
+ ' or: echo "notes" | notion-cli quick --title "Title"');
33
+ process.exit(1);
34
+ return;
35
+ }
36
+ // 2. Determine target database
37
+ const target = flags.to || await (0, bookmarks_1.getDefaultBookmark)();
38
+ if (!target) {
39
+ this.error('No target database specified and no default bookmark set.\n' +
40
+ 'Set a default: notion-cli bookmark set inbox DB_ID --default\n' +
41
+ ' or specify: notion-cli quick "note" --to DB_NAME_OR_ID');
42
+ process.exit(1);
43
+ return;
44
+ }
45
+ const dbId = await (0, notion_resolver_1.resolveNotionId)(target, 'database');
46
+ // 3. Get database schema to find the title property name
47
+ const schema = await notion.retrieveDataSource(dbId);
48
+ const titlePropName = findTitleProperty(schema);
49
+ // 4. Split content into title + body
50
+ const lines = content.split('\n');
51
+ const pageTitle = flags.title || lines[0].trim();
52
+ const body = flags.title ? content : lines.slice(1).join('\n').trim();
53
+ // 5. Build page properties (merge template properties if provided)
54
+ let properties = {
55
+ [titlePropName]: {
56
+ title: [{ text: { content: pageTitle } }]
57
+ }
58
+ };
59
+ // 5a. If a template is specified, expand its properties and merge
60
+ let templateIcon;
61
+ let templateContent;
62
+ if (flags.template) {
63
+ const tmpl = await (0, templates_1.getTemplate)(flags.template);
64
+ if (!tmpl) {
65
+ this.error(`Template "${flags.template}" not found.\nRun \`notion-cli template list\` to see saved templates.`);
66
+ process.exit(1);
67
+ return;
68
+ }
69
+ if (tmpl.properties && Object.keys(tmpl.properties).length > 0) {
70
+ const merged = { ...tmpl.properties, [titlePropName]: pageTitle };
71
+ properties = await (0, property_expander_1.expandSimpleProperties)(merged, schema.properties);
72
+ }
73
+ templateIcon = tmpl.icon;
74
+ templateContent = tmpl.content;
75
+ }
76
+ // 6. Build children blocks — body from arg takes precedence over template content
77
+ const contentForBlocks = body || templateContent;
78
+ const children = contentForBlocks ? (0, markdown_to_blocks_1.markdownToBlocks)(contentForBlocks) : undefined;
79
+ // 7. Create page
80
+ const res = await notion.createPage({
81
+ parent: { data_source_id: dbId },
82
+ properties,
83
+ ...(children && { children }),
84
+ ...(templateIcon && { icon: { emoji: templateIcon } }),
85
+ });
86
+ // 8. Output
87
+ if (flags.json) {
88
+ this.log(JSON.stringify({
89
+ success: true,
90
+ data: res,
91
+ timestamp: new Date().toISOString()
92
+ }, null, 2));
93
+ }
94
+ else {
95
+ this.log(`Created: ${pageTitle}`);
96
+ this.log(res.url);
97
+ }
98
+ process.exit(0);
99
+ }
100
+ catch (error) {
101
+ const cliError = error instanceof errors_1.NotionCLIError
102
+ ? error
103
+ : (0, errors_1.wrapNotionError)(error, { endpoint: 'pages.create', resourceType: 'page' });
104
+ if (flags.json) {
105
+ this.log(JSON.stringify(cliError.toJSON(), null, 2));
106
+ }
107
+ else {
108
+ this.error(cliError.toHumanString());
109
+ }
110
+ process.exit(1);
111
+ }
112
+ }
113
+ /** Read all data from stdin (for piped input). */
114
+ readStdin() {
115
+ return new Promise((resolve) => {
116
+ const chunks = [];
117
+ process.stdin.on('data', (chunk) => chunks.push(chunk));
118
+ process.stdin.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8').trim()));
119
+ });
120
+ }
121
+ }
122
+ Quick.description = 'Quick-capture a page to a bookmarked database';
123
+ Quick.aliases = ['q'];
124
+ Quick.examples = [
125
+ {
126
+ description: 'Add a quick note to default database',
127
+ command: '$ notion-cli quick "Buy groceries"',
128
+ },
129
+ {
130
+ description: 'Add to a specific bookmark',
131
+ command: '$ notion-cli quick "Fix login bug" --to tasks',
132
+ },
133
+ {
134
+ description: 'Pipe content from stdin',
135
+ command: '$ echo "Meeting notes here" | notion-cli quick --title "Standup"',
136
+ },
137
+ ];
138
+ Quick.args = {
139
+ content: core_1.Args.string({ required: false, description: 'Page content (first line = title, rest = body)' }),
140
+ };
141
+ Quick.flags = {
142
+ to: core_1.Flags.string({
143
+ description: 'Target bookmark name, database name, or ID (defaults to default bookmark)',
144
+ }),
145
+ title: core_1.Flags.string({
146
+ char: 't',
147
+ description: 'Override title (useful with stdin piping)',
148
+ }),
149
+ template: core_1.Flags.string({
150
+ description: 'Apply a saved template (properties and content)',
151
+ }),
152
+ ...base_flags_1.AutomationFlags,
153
+ };
154
+ exports.default = Quick;
155
+ /**
156
+ * Find the title property name in a database schema.
157
+ * Notion databases always have exactly one title property, but its name varies.
158
+ */
159
+ function findTitleProperty(schema) {
160
+ if (schema.properties) {
161
+ for (const [name, prop] of Object.entries(schema.properties)) {
162
+ if (prop.type === 'title')
163
+ return name;
164
+ }
165
+ }
166
+ // Fallback — most common default
167
+ return 'Name';
168
+ }