@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,359 @@
1
+ "use strict";
2
+ /**
3
+ * Property Example Generator for Notion API
4
+ *
5
+ * Generates copy-pastable property payload examples based on database schema.
6
+ * Helps AI agents understand the correct format for create/update operations.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.generatePropertyExamples = generatePropertyExamples;
10
+ exports.formatExamplesForConsole = formatExamplesForConsole;
11
+ exports.groupExamplesByWritability = groupExamplesByWritability;
12
+ /**
13
+ * Generate property examples for all properties in a data source schema
14
+ *
15
+ * @param properties - Properties object from GetDataSourceResponse
16
+ * @returns Array of property examples
17
+ */
18
+ function generatePropertyExamples(properties) {
19
+ const examples = [];
20
+ for (const [propName, propDef] of Object.entries(properties)) {
21
+ const example = generateExampleForType(propName, propDef);
22
+ if (example) {
23
+ examples.push(example);
24
+ }
25
+ }
26
+ return examples;
27
+ }
28
+ /**
29
+ * Generate example for a single property based on its type
30
+ *
31
+ * @param name - Property name
32
+ * @param propDef - Property definition from Notion API
33
+ * @returns Property example or null if unsupported
34
+ */
35
+ function generateExampleForType(name, propDef) {
36
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
37
+ if (!propDef || !propDef.type) {
38
+ return null;
39
+ }
40
+ const type = propDef.type;
41
+ switch (type) {
42
+ case 'title':
43
+ return {
44
+ property_name: name,
45
+ property_type: 'title',
46
+ simple_value: 'My Page Title',
47
+ notion_payload: {
48
+ [name]: {
49
+ title: [{ text: { content: 'My Page Title' } }]
50
+ }
51
+ },
52
+ description: 'Main title of the page (required for new pages)'
53
+ };
54
+ case 'rich_text':
55
+ return {
56
+ property_name: name,
57
+ property_type: 'rich_text',
58
+ simple_value: 'Some text content',
59
+ notion_payload: {
60
+ [name]: {
61
+ rich_text: [{ text: { content: 'Some text content' } }]
62
+ }
63
+ },
64
+ description: 'Multi-line text with optional formatting'
65
+ };
66
+ case 'number': {
67
+ const numberFormat = ((_a = propDef.number) === null || _a === void 0 ? void 0 : _a.format) || 'number';
68
+ return {
69
+ property_name: name,
70
+ property_type: 'number',
71
+ simple_value: 42,
72
+ notion_payload: {
73
+ [name]: { number: 42 }
74
+ },
75
+ description: `Numeric value (format: ${numberFormat})`
76
+ };
77
+ }
78
+ case 'checkbox':
79
+ return {
80
+ property_name: name,
81
+ property_type: 'checkbox',
82
+ simple_value: true,
83
+ notion_payload: {
84
+ [name]: { checkbox: true }
85
+ },
86
+ description: 'Boolean true/false value'
87
+ };
88
+ case 'select': {
89
+ const selectOptions = ((_b = propDef.select) === null || _b === void 0 ? void 0 : _b.options) || [];
90
+ const firstOption = ((_c = selectOptions[0]) === null || _c === void 0 ? void 0 : _c.name) || 'Option Name';
91
+ const selectOptionsList = selectOptions.map((o) => o.name).join(', ');
92
+ return {
93
+ property_name: name,
94
+ property_type: 'select',
95
+ simple_value: firstOption,
96
+ notion_payload: {
97
+ [name]: { select: { name: firstOption } }
98
+ },
99
+ description: selectOptions.length > 0
100
+ ? `Single selection from: ${selectOptionsList}`
101
+ : 'Single selection (no options defined yet)'
102
+ };
103
+ }
104
+ case 'multi_select': {
105
+ const multiOptions = ((_d = propDef.multi_select) === null || _d === void 0 ? void 0 : _d.options) || [];
106
+ const exampleOptions = multiOptions.slice(0, 2).map((o) => o.name);
107
+ const multiOptionsList = multiOptions.map((o) => o.name).join(', ');
108
+ return {
109
+ property_name: name,
110
+ property_type: 'multi_select',
111
+ simple_value: exampleOptions,
112
+ notion_payload: {
113
+ [name]: {
114
+ multi_select: exampleOptions.map((n) => ({ name: n }))
115
+ }
116
+ },
117
+ description: multiOptions.length > 0
118
+ ? `Multiple selections from: ${multiOptionsList}`
119
+ : 'Multiple selections (no options defined yet)'
120
+ };
121
+ }
122
+ case 'status': {
123
+ const statusOptions = ((_e = propDef.status) === null || _e === void 0 ? void 0 : _e.options) || [];
124
+ const firstStatus = ((_f = statusOptions[0]) === null || _f === void 0 ? void 0 : _f.name) || 'Status Name';
125
+ const statusOptionsList = statusOptions.map((o) => o.name).join(', ');
126
+ return {
127
+ property_name: name,
128
+ property_type: 'status',
129
+ simple_value: firstStatus,
130
+ notion_payload: {
131
+ [name]: { status: { name: firstStatus } }
132
+ },
133
+ description: statusOptions.length > 0
134
+ ? `Status from: ${statusOptionsList}`
135
+ : 'Status value (no options defined yet)'
136
+ };
137
+ }
138
+ case 'date':
139
+ return {
140
+ property_name: name,
141
+ property_type: 'date',
142
+ simple_value: '2025-12-31',
143
+ notion_payload: {
144
+ [name]: { date: { start: '2025-12-31' } }
145
+ },
146
+ description: 'ISO date (YYYY-MM-DD) or date range with end property'
147
+ };
148
+ case 'url':
149
+ return {
150
+ property_name: name,
151
+ property_type: 'url',
152
+ simple_value: 'https://example.com',
153
+ notion_payload: {
154
+ [name]: { url: 'https://example.com' }
155
+ },
156
+ description: 'Valid URL starting with http:// or https://'
157
+ };
158
+ case 'email':
159
+ return {
160
+ property_name: name,
161
+ property_type: 'email',
162
+ simple_value: 'user@example.com',
163
+ notion_payload: {
164
+ [name]: { email: 'user@example.com' }
165
+ },
166
+ description: 'Valid email address'
167
+ };
168
+ case 'phone_number':
169
+ return {
170
+ property_name: name,
171
+ property_type: 'phone_number',
172
+ simple_value: '+1-555-123-4567',
173
+ notion_payload: {
174
+ [name]: { phone_number: '+1-555-123-4567' }
175
+ },
176
+ description: 'Phone number (any format)'
177
+ };
178
+ case 'people':
179
+ return {
180
+ property_name: name,
181
+ property_type: 'people',
182
+ simple_value: ['user-id-1', 'user-id-2'],
183
+ notion_payload: {
184
+ [name]: {
185
+ people: [
186
+ { id: 'user-id-1' },
187
+ { id: 'user-id-2' }
188
+ ]
189
+ }
190
+ },
191
+ description: 'Array of Notion user IDs (use workspace users list to get IDs)'
192
+ };
193
+ case 'files':
194
+ return {
195
+ property_name: name,
196
+ property_type: 'files',
197
+ simple_value: 'https://example.com/file.pdf',
198
+ notion_payload: {
199
+ [name]: {
200
+ files: [
201
+ {
202
+ name: 'file.pdf',
203
+ type: 'external',
204
+ external: { url: 'https://example.com/file.pdf' }
205
+ }
206
+ ]
207
+ }
208
+ },
209
+ description: 'External file URLs (Notion-hosted files cannot be set via API)'
210
+ };
211
+ case 'relation': {
212
+ const relatedDbId = ((_g = propDef.relation) === null || _g === void 0 ? void 0 : _g.database_id) || 'related-database-id';
213
+ return {
214
+ property_name: name,
215
+ property_type: 'relation',
216
+ simple_value: ['page-id-1', 'page-id-2'],
217
+ notion_payload: {
218
+ [name]: {
219
+ relation: [
220
+ { id: 'page-id-1' },
221
+ { id: 'page-id-2' }
222
+ ]
223
+ }
224
+ },
225
+ description: `Array of page IDs from related database (${relatedDbId})`
226
+ };
227
+ }
228
+ // Read-only property types (cannot be set via API)
229
+ case 'created_time':
230
+ return {
231
+ property_name: name,
232
+ property_type: 'created_time',
233
+ simple_value: null,
234
+ notion_payload: {},
235
+ description: 'Read-only: Automatically set when page is created'
236
+ };
237
+ case 'created_by':
238
+ return {
239
+ property_name: name,
240
+ property_type: 'created_by',
241
+ simple_value: null,
242
+ notion_payload: {},
243
+ description: 'Read-only: Automatically set to user who created the page'
244
+ };
245
+ case 'last_edited_time':
246
+ return {
247
+ property_name: name,
248
+ property_type: 'last_edited_time',
249
+ simple_value: null,
250
+ notion_payload: {},
251
+ description: 'Read-only: Automatically updated when page is edited'
252
+ };
253
+ case 'last_edited_by':
254
+ return {
255
+ property_name: name,
256
+ property_type: 'last_edited_by',
257
+ simple_value: null,
258
+ notion_payload: {},
259
+ description: 'Read-only: Automatically set to user who last edited the page'
260
+ };
261
+ case 'formula': {
262
+ const expression = ((_h = propDef.formula) === null || _h === void 0 ? void 0 : _h.expression) || 'unknown';
263
+ return {
264
+ property_name: name,
265
+ property_type: 'formula',
266
+ simple_value: null,
267
+ notion_payload: {},
268
+ description: `Read-only: Computed formula (${expression})`
269
+ };
270
+ }
271
+ case 'rollup': {
272
+ const rollupFunc = ((_j = propDef.rollup) === null || _j === void 0 ? void 0 : _j.function) || 'unknown';
273
+ return {
274
+ property_name: name,
275
+ property_type: 'rollup',
276
+ simple_value: null,
277
+ notion_payload: {},
278
+ description: `Read-only: Rollup aggregation (${rollupFunc})`
279
+ };
280
+ }
281
+ case 'unique_id':
282
+ return {
283
+ property_name: name,
284
+ property_type: 'unique_id',
285
+ simple_value: null,
286
+ notion_payload: {},
287
+ description: 'Read-only: Auto-incrementing unique ID'
288
+ };
289
+ case 'verification':
290
+ return {
291
+ property_name: name,
292
+ property_type: 'verification',
293
+ simple_value: null,
294
+ notion_payload: {},
295
+ description: 'Read-only: Verification status'
296
+ };
297
+ default:
298
+ // Unsupported or unknown type
299
+ return {
300
+ property_name: name,
301
+ property_type: type,
302
+ simple_value: null,
303
+ notion_payload: {},
304
+ description: `Unsupported property type: ${type}`
305
+ };
306
+ }
307
+ }
308
+ /**
309
+ * Format examples for human-readable console output
310
+ *
311
+ * @param examples - Array of property examples
312
+ * @returns Formatted string
313
+ */
314
+ function formatExamplesForConsole(examples) {
315
+ const lines = [];
316
+ lines.push('');
317
+ lines.push('📋 Property Examples');
318
+ lines.push('='.repeat(80));
319
+ for (const example of examples) {
320
+ lines.push('');
321
+ lines.push(`${example.property_name} (${example.property_type})`);
322
+ lines.push(` ${example.description}`);
323
+ if (example.simple_value !== null) {
324
+ lines.push('');
325
+ lines.push(' Simple value:');
326
+ lines.push(` ${JSON.stringify(example.simple_value)}`);
327
+ lines.push('');
328
+ lines.push(' Notion API payload:');
329
+ const payload = JSON.stringify(example.notion_payload, null, 2);
330
+ const indentedPayload = payload.split('\n').map(line => ` ${line}`).join('\n');
331
+ lines.push(indentedPayload);
332
+ }
333
+ else {
334
+ lines.push('');
335
+ lines.push(' ⚠️ This property is read-only and cannot be set via API');
336
+ }
337
+ lines.push('-'.repeat(80));
338
+ }
339
+ return lines.join('\n');
340
+ }
341
+ /**
342
+ * Group examples by writability (writable vs read-only)
343
+ *
344
+ * @param examples - Array of property examples
345
+ * @returns Grouped examples
346
+ */
347
+ function groupExamplesByWritability(examples) {
348
+ const writable = [];
349
+ const readOnly = [];
350
+ for (const example of examples) {
351
+ if (example.simple_value === null && Object.keys(example.notion_payload).length === 0) {
352
+ readOnly.push(example);
353
+ }
354
+ else {
355
+ writable.push(example);
356
+ }
357
+ }
358
+ return { writable, readOnly };
359
+ }
@@ -0,0 +1,65 @@
1
+ import { GetDataSourceResponse } from '@notionhq/client/build/src/api-endpoints';
2
+ /**
3
+ * Property schema for AI agents - simplified and easy to parse
4
+ */
5
+ export interface PropertySchema {
6
+ name: string;
7
+ type: string;
8
+ description?: string;
9
+ required?: boolean;
10
+ options?: string[];
11
+ config?: Record<string, any>;
12
+ }
13
+ /**
14
+ * Database schema in AI-friendly format
15
+ */
16
+ export interface DataSourceSchema {
17
+ id: string;
18
+ title: string;
19
+ description?: string;
20
+ properties: PropertySchema[];
21
+ url?: string;
22
+ }
23
+ /**
24
+ * Extract clean, AI-parseable schema from Notion data source response
25
+ *
26
+ * This transforms the complex nested Notion API structure into a flat,
27
+ * easy-to-understand format that AI agents can work with directly.
28
+ *
29
+ * @param dataSource - Raw Notion data source response
30
+ * @returns Simplified schema object
31
+ */
32
+ export declare function extractSchema(dataSource: GetDataSourceResponse): DataSourceSchema;
33
+ /**
34
+ * Filter properties by names
35
+ *
36
+ * @param schema - Full schema
37
+ * @param propertyNames - Array of property names to include
38
+ * @returns Filtered schema
39
+ */
40
+ export declare function filterProperties(schema: DataSourceSchema, propertyNames: string[]): DataSourceSchema;
41
+ /**
42
+ * Format schema as human-readable table data
43
+ *
44
+ * @param schema - Schema to format
45
+ * @returns Array of objects for table display
46
+ */
47
+ export declare function formatSchemaForTable(schema: DataSourceSchema): Array<Record<string, string>>;
48
+ /**
49
+ * Format schema as markdown documentation
50
+ *
51
+ * @param schema - Schema to format
52
+ * @returns Markdown string
53
+ */
54
+ export declare function formatSchemaAsMarkdown(schema: DataSourceSchema): string;
55
+ /**
56
+ * Validate that a data object matches the schema
57
+ *
58
+ * @param schema - Schema to validate against
59
+ * @param data - Data object to validate
60
+ * @returns Validation result with errors
61
+ */
62
+ export declare function validateAgainstSchema(schema: DataSourceSchema, data: Record<string, any>): {
63
+ valid: boolean;
64
+ errors: string[];
65
+ };
@@ -0,0 +1,235 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractSchema = extractSchema;
4
+ exports.filterProperties = filterProperties;
5
+ exports.formatSchemaForTable = formatSchemaForTable;
6
+ exports.formatSchemaAsMarkdown = formatSchemaAsMarkdown;
7
+ exports.validateAgainstSchema = validateAgainstSchema;
8
+ /**
9
+ * Extract clean, AI-parseable schema from Notion data source response
10
+ *
11
+ * This transforms the complex nested Notion API structure into a flat,
12
+ * easy-to-understand format that AI agents can work with directly.
13
+ *
14
+ * @param dataSource - Raw Notion data source response
15
+ * @returns Simplified schema object
16
+ */
17
+ function extractSchema(dataSource) {
18
+ const properties = [];
19
+ // Extract title from data source
20
+ const title = extractTitle(dataSource);
21
+ // Extract description if available
22
+ const description = extractDescription(dataSource);
23
+ // Process each property in the data source
24
+ if (dataSource.properties) {
25
+ for (const [propName, propConfig] of Object.entries(dataSource.properties)) {
26
+ const schema = extractPropertySchema(propName, propConfig);
27
+ if (schema) {
28
+ properties.push(schema);
29
+ }
30
+ }
31
+ }
32
+ return {
33
+ id: dataSource.id,
34
+ title,
35
+ description,
36
+ properties,
37
+ url: 'url' in dataSource ? dataSource.url : undefined,
38
+ };
39
+ }
40
+ /**
41
+ * Extract title from data source
42
+ */
43
+ function extractTitle(dataSource) {
44
+ if ('title' in dataSource && Array.isArray(dataSource.title)) {
45
+ return dataSource.title
46
+ .map((t) => t.plain_text || '')
47
+ .join('')
48
+ .trim() || 'Untitled';
49
+ }
50
+ return 'Untitled';
51
+ }
52
+ /**
53
+ * Extract description from data source
54
+ */
55
+ function extractDescription(dataSource) {
56
+ if ('description' in dataSource && Array.isArray(dataSource.description)) {
57
+ const desc = dataSource.description
58
+ .map((d) => d.plain_text || '')
59
+ .join('')
60
+ .trim();
61
+ return desc || undefined;
62
+ }
63
+ return undefined;
64
+ }
65
+ /**
66
+ * Extract individual property schema
67
+ */
68
+ function extractPropertySchema(name, config) {
69
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
70
+ if (!config || !config.type) {
71
+ return null;
72
+ }
73
+ const schema = {
74
+ name,
75
+ type: config.type,
76
+ };
77
+ // Handle select and multi-select with options
78
+ if (config.type === 'select' && ((_a = config.select) === null || _a === void 0 ? void 0 : _a.options)) {
79
+ schema.options = config.select.options.map((opt) => opt.name);
80
+ schema.description = `Select one: ${schema.options.join(', ')}`;
81
+ }
82
+ if (config.type === 'multi_select' && ((_b = config.multi_select) === null || _b === void 0 ? void 0 : _b.options)) {
83
+ schema.options = config.multi_select.options.map((opt) => opt.name);
84
+ schema.description = `Select multiple: ${schema.options.join(', ')}`;
85
+ }
86
+ // Handle status property (similar to select)
87
+ if (config.type === 'status' && ((_c = config.status) === null || _c === void 0 ? void 0 : _c.options)) {
88
+ schema.options = config.status.options.map((opt) => opt.name);
89
+ schema.description = `Status: ${schema.options.join(', ')}`;
90
+ }
91
+ // Handle formula properties
92
+ if (config.type === 'formula' && ((_d = config.formula) === null || _d === void 0 ? void 0 : _d.expression)) {
93
+ schema.config = {
94
+ expression: config.formula.expression,
95
+ };
96
+ schema.description = `Formula: ${config.formula.expression}`;
97
+ }
98
+ // Handle rollup properties
99
+ if (config.type === 'rollup') {
100
+ schema.config = {
101
+ relation_property: (_e = config.rollup) === null || _e === void 0 ? void 0 : _e.relation_property_name,
102
+ rollup_property: (_f = config.rollup) === null || _f === void 0 ? void 0 : _f.rollup_property_name,
103
+ function: (_g = config.rollup) === null || _g === void 0 ? void 0 : _g.function,
104
+ };
105
+ schema.description = 'Rollup from related database';
106
+ }
107
+ // Handle relation properties
108
+ if (config.type === 'relation') {
109
+ schema.config = {
110
+ database_id: (_h = config.relation) === null || _h === void 0 ? void 0 : _h.database_id,
111
+ type: (_j = config.relation) === null || _j === void 0 ? void 0 : _j.type,
112
+ };
113
+ schema.description = 'Relation to another database';
114
+ }
115
+ // Handle number properties with format
116
+ if (config.type === 'number' && ((_k = config.number) === null || _k === void 0 ? void 0 : _k.format)) {
117
+ schema.config = {
118
+ format: config.number.format,
119
+ };
120
+ schema.description = `Number (${config.number.format})`;
121
+ }
122
+ // Mark title property as required
123
+ if (config.type === 'title') {
124
+ schema.required = true;
125
+ schema.description = 'Title (required)';
126
+ }
127
+ return schema;
128
+ }
129
+ /**
130
+ * Filter properties by names
131
+ *
132
+ * @param schema - Full schema
133
+ * @param propertyNames - Array of property names to include
134
+ * @returns Filtered schema
135
+ */
136
+ function filterProperties(schema, propertyNames) {
137
+ const lowerNames = propertyNames.map(n => n.toLowerCase());
138
+ return {
139
+ ...schema,
140
+ properties: schema.properties.filter(p => lowerNames.includes(p.name.toLowerCase())),
141
+ };
142
+ }
143
+ /**
144
+ * Format schema as human-readable table data
145
+ *
146
+ * @param schema - Schema to format
147
+ * @returns Array of objects for table display
148
+ */
149
+ function formatSchemaForTable(schema) {
150
+ return schema.properties.map(prop => {
151
+ var _a;
152
+ return ({
153
+ name: prop.name,
154
+ type: prop.type,
155
+ required: prop.required ? 'Yes' : 'No',
156
+ options: ((_a = prop.options) === null || _a === void 0 ? void 0 : _a.join(', ')) || '-',
157
+ description: prop.description || '-',
158
+ });
159
+ });
160
+ }
161
+ /**
162
+ * Format schema as markdown documentation
163
+ *
164
+ * @param schema - Schema to format
165
+ * @returns Markdown string
166
+ */
167
+ function formatSchemaAsMarkdown(schema) {
168
+ var _a;
169
+ const lines = [];
170
+ lines.push(`# ${schema.title}`);
171
+ lines.push('');
172
+ if (schema.description) {
173
+ lines.push(schema.description);
174
+ lines.push('');
175
+ }
176
+ lines.push(`**Database ID:** \`${schema.id}\``);
177
+ if (schema.url) {
178
+ lines.push(`**URL:** ${schema.url}`);
179
+ }
180
+ lines.push('');
181
+ lines.push('## Properties');
182
+ lines.push('');
183
+ lines.push('| Name | Type | Required | Options/Details |');
184
+ lines.push('|------|------|----------|-----------------|');
185
+ for (const prop of schema.properties) {
186
+ const required = prop.required ? '✓' : '';
187
+ const details = ((_a = prop.options) === null || _a === void 0 ? void 0 : _a.join(', ')) || prop.description || '';
188
+ lines.push(`| ${prop.name} | ${prop.type} | ${required} | ${details} |`);
189
+ }
190
+ return lines.join('\n');
191
+ }
192
+ /**
193
+ * Validate that a data object matches the schema
194
+ *
195
+ * @param schema - Schema to validate against
196
+ * @param data - Data object to validate
197
+ * @returns Validation result with errors
198
+ */
199
+ function validateAgainstSchema(schema, data) {
200
+ const errors = [];
201
+ // Check required properties
202
+ for (const prop of schema.properties) {
203
+ if (prop.required && !(prop.name in data)) {
204
+ errors.push(`Missing required property: ${prop.name}`);
205
+ }
206
+ }
207
+ // Check property types and options
208
+ for (const [key, value] of Object.entries(data)) {
209
+ const propSchema = schema.properties.find(p => p.name === key);
210
+ if (!propSchema) {
211
+ errors.push(`Unknown property: ${key}`);
212
+ continue;
213
+ }
214
+ // Validate select/multi-select options
215
+ if (propSchema.options && propSchema.options.length > 0) {
216
+ if (propSchema.type === 'select') {
217
+ if (typeof value === 'string' && !propSchema.options.includes(value)) {
218
+ errors.push(`Invalid option for ${key}: ${value}. Must be one of: ${propSchema.options.join(', ')}`);
219
+ }
220
+ }
221
+ if (propSchema.type === 'multi_select') {
222
+ if (Array.isArray(value)) {
223
+ const invalidOptions = value.filter(v => !propSchema.options.includes(v));
224
+ if (invalidOptions.length > 0) {
225
+ errors.push(`Invalid options for ${key}: ${invalidOptions.join(', ')}`);
226
+ }
227
+ }
228
+ }
229
+ }
230
+ }
231
+ return {
232
+ valid: errors.length === 0,
233
+ errors,
234
+ };
235
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Shell Configuration Utility
3
+ *
4
+ * Detects the user's shell and persists environment variables (e.g., NOTION_TOKEN)
5
+ * to the appropriate rc file (.zshrc, .bashrc, etc.).
6
+ *
7
+ * Used by both `config set-token` and `init` commands to avoid duplicating
8
+ * shell detection and rc file writing logic.
9
+ */
10
+ /**
11
+ * Detect the current shell from the SHELL environment variable.
12
+ * Falls back to bash on Unix, powershell on Windows.
13
+ */
14
+ export declare function detectShell(): string;
15
+ /**
16
+ * Resolve the path to the shell's rc/config file.
17
+ */
18
+ export declare function getRcFilePath(shell: string): string;
19
+ /**
20
+ * Persist a Notion token to the user's shell rc file.
21
+ *
22
+ * Reads the rc file, checks if NOTION_TOKEN already exists (replaces it if so),
23
+ * otherwise appends a new export line. Creates the file if it doesn't exist.
24
+ *
25
+ * Returns the shell name and rc file path so callers can inform the user.
26
+ */
27
+ export declare function persistToken(token: string): Promise<{
28
+ rcFile: string;
29
+ shell: string;
30
+ }>;