@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,84 @@
1
+ "use strict";
2
+ /**
3
+ * Shell Configuration Utility
4
+ *
5
+ * Detects the user's shell and persists environment variables (e.g., NOTION_TOKEN)
6
+ * to the appropriate rc file (.zshrc, .bashrc, etc.).
7
+ *
8
+ * Used by both `config set-token` and `init` commands to avoid duplicating
9
+ * shell detection and rc file writing logic.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.detectShell = detectShell;
13
+ exports.getRcFilePath = getRcFilePath;
14
+ exports.persistToken = persistToken;
15
+ const fs = require("fs/promises");
16
+ const path = require("path");
17
+ const os = require("os");
18
+ /**
19
+ * Detect the current shell from the SHELL environment variable.
20
+ * Falls back to bash on Unix, powershell on Windows.
21
+ */
22
+ function detectShell() {
23
+ const shell = process.env.SHELL || '';
24
+ if (shell.includes('zsh'))
25
+ return 'zsh';
26
+ if (shell.includes('bash'))
27
+ return 'bash';
28
+ if (shell.includes('fish'))
29
+ return 'fish';
30
+ return process.platform === 'win32' ? 'powershell' : 'bash';
31
+ }
32
+ /**
33
+ * Resolve the path to the shell's rc/config file.
34
+ */
35
+ function getRcFilePath(shell) {
36
+ const home = os.homedir();
37
+ switch (shell) {
38
+ case 'zsh':
39
+ return path.join(home, '.zshrc');
40
+ case 'bash':
41
+ return path.join(home, '.bashrc');
42
+ case 'fish':
43
+ return path.join(home, '.config', 'fish', 'config.fish');
44
+ case 'powershell':
45
+ return path.join(home, 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1');
46
+ default:
47
+ return path.join(home, '.bashrc');
48
+ }
49
+ }
50
+ /**
51
+ * Persist a Notion token to the user's shell rc file.
52
+ *
53
+ * Reads the rc file, checks if NOTION_TOKEN already exists (replaces it if so),
54
+ * otherwise appends a new export line. Creates the file if it doesn't exist.
55
+ *
56
+ * Returns the shell name and rc file path so callers can inform the user.
57
+ */
58
+ async function persistToken(token) {
59
+ const shell = detectShell();
60
+ const rcFile = getRcFilePath(shell);
61
+ // Read existing rc file (create if missing)
62
+ let rcContent = '';
63
+ try {
64
+ rcContent = await fs.readFile(rcFile, 'utf-8');
65
+ }
66
+ catch (error) {
67
+ if (error && typeof error === 'object' && 'code' in error && error.code !== 'ENOENT') {
68
+ throw error;
69
+ }
70
+ // File doesn't exist — will be created on write
71
+ }
72
+ // Upsert the NOTION_TOKEN export line
73
+ const tokenLineRegex = /^export\s+NOTION_TOKEN=.*/gm;
74
+ const newTokenLine = `export NOTION_TOKEN="${token}"`;
75
+ let updatedContent;
76
+ if (tokenLineRegex.test(rcContent)) {
77
+ updatedContent = rcContent.replace(tokenLineRegex, newTokenLine);
78
+ }
79
+ else {
80
+ updatedContent = rcContent.trim() + '\n\n# Notion CLI Token\n' + newTokenLine + '\n';
81
+ }
82
+ await fs.writeFile(rcFile, updatedContent, 'utf-8');
83
+ return { rcFile, shell };
84
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Table formatting utility to replace oclif v2's ux.table
3
+ * Provides backward-compatible table flags and formatting
4
+ */
5
+ /**
6
+ * Table flags compatible with oclif v2's ux.table.flags()
7
+ */
8
+ export declare const tableFlags: {
9
+ columns: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ sort: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ filter: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ csv: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
+ extended: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
14
+ 'no-truncate': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
+ 'no-header': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
16
+ };
17
+ export interface ColumnOptions<T> {
18
+ header?: string;
19
+ get?: (row: T) => any;
20
+ extended?: boolean;
21
+ minWidth?: number;
22
+ }
23
+ export interface TableOptions {
24
+ columns?: string;
25
+ sort?: string;
26
+ filter?: string;
27
+ csv?: boolean;
28
+ extended?: boolean;
29
+ 'no-truncate'?: boolean;
30
+ 'no-header'?: boolean;
31
+ printLine?: (s: string) => void;
32
+ }
33
+ /**
34
+ * Format and display a table (compatible with oclif v2's ux.table)
35
+ */
36
+ export declare function formatTable<T extends Record<string, any>>(data: T[], columns: Record<string, ColumnOptions<T>>, options?: TableOptions): void;
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ /**
3
+ * Table formatting utility to replace oclif v2's ux.table
4
+ * Provides backward-compatible table flags and formatting
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.tableFlags = void 0;
8
+ exports.formatTable = formatTable;
9
+ const core_1 = require("@oclif/core");
10
+ const Table = require("cli-table3");
11
+ /**
12
+ * Table flags compatible with oclif v2's ux.table.flags()
13
+ */
14
+ exports.tableFlags = {
15
+ columns: core_1.Flags.string({
16
+ description: 'Only show provided columns (comma-separated)',
17
+ exclusive: ['extended'],
18
+ }),
19
+ sort: core_1.Flags.string({
20
+ description: 'Property to sort by (prepend with - for descending)',
21
+ }),
22
+ filter: core_1.Flags.string({
23
+ description: 'Filter property by substring match',
24
+ }),
25
+ csv: core_1.Flags.boolean({
26
+ description: 'Output in CSV format',
27
+ exclusive: ['no-truncate'],
28
+ }),
29
+ extended: core_1.Flags.boolean({
30
+ char: 'x',
31
+ description: 'Show extra columns',
32
+ }),
33
+ 'no-truncate': core_1.Flags.boolean({
34
+ description: 'Do not truncate output to fit screen',
35
+ exclusive: ['csv'],
36
+ }),
37
+ 'no-header': core_1.Flags.boolean({
38
+ description: 'Hide table header from output',
39
+ }),
40
+ };
41
+ /**
42
+ * Format and display a table (compatible with oclif v2's ux.table)
43
+ */
44
+ function formatTable(data, columns, options = {}) {
45
+ if (data.length === 0) {
46
+ return;
47
+ }
48
+ const printLine = options.printLine || console.log;
49
+ // Filter columns based on options
50
+ let selectedColumns = Object.keys(columns);
51
+ if (options.columns) {
52
+ const requestedCols = options.columns.split(',').map(c => c.trim());
53
+ selectedColumns = selectedColumns.filter(col => requestedCols.includes(col));
54
+ }
55
+ if (!options.extended) {
56
+ selectedColumns = selectedColumns.filter(col => !columns[col].extended);
57
+ }
58
+ // Filter rows
59
+ let filteredData = data;
60
+ if (options.filter) {
61
+ const [filterCol, filterVal] = options.filter.split('=');
62
+ if (filterVal) {
63
+ filteredData = data.filter(row => {
64
+ var _a;
65
+ const val = ((_a = columns[filterCol]) === null || _a === void 0 ? void 0 : _a.get) ? columns[filterCol].get(row) : row[filterCol];
66
+ return String(val).includes(filterVal);
67
+ });
68
+ }
69
+ }
70
+ // Sort data
71
+ if (options.sort) {
72
+ const descending = options.sort.startsWith('-');
73
+ const sortCol = descending ? options.sort.slice(1) : options.sort;
74
+ filteredData = [...filteredData].sort((a, b) => {
75
+ var _a, _b;
76
+ const aVal = ((_a = columns[sortCol]) === null || _a === void 0 ? void 0 : _a.get) ? columns[sortCol].get(a) : a[sortCol];
77
+ const bVal = ((_b = columns[sortCol]) === null || _b === void 0 ? void 0 : _b.get) ? columns[sortCol].get(b) : b[sortCol];
78
+ const comparison = String(aVal).localeCompare(String(bVal));
79
+ return descending ? -comparison : comparison;
80
+ });
81
+ }
82
+ // Output as CSV
83
+ if (options.csv) {
84
+ if (!options['no-header']) {
85
+ const headers = selectedColumns.map(col => columns[col].header || col);
86
+ printLine(headers.join(','));
87
+ }
88
+ filteredData.forEach(row => {
89
+ const values = selectedColumns.map(col => {
90
+ const val = columns[col].get ? columns[col].get(row) : row[col];
91
+ const str = String(val || '');
92
+ // Escape CSV values
93
+ return str.includes(',') || str.includes('"') ? `"${str.replace(/"/g, '""')}"` : str;
94
+ });
95
+ printLine(values.join(','));
96
+ });
97
+ return;
98
+ }
99
+ // Output as table
100
+ const headers = selectedColumns.map(col => columns[col].header || col);
101
+ // Respect NO_COLOR standard (https://no-color.org) — disables ANSI codes for
102
+ // CI/CD logs, screen readers, piped output, and AI agent consumption
103
+ const useColor = !process.env.NO_COLOR;
104
+ const table = new Table({
105
+ head: options['no-header'] ? [] : headers,
106
+ style: {
107
+ head: useColor ? ['cyan'] : [],
108
+ border: useColor ? ['gray'] : [],
109
+ },
110
+ wordWrap: !options['no-truncate'],
111
+ colWidths: selectedColumns.map(col => {
112
+ if (options['no-truncate'])
113
+ return undefined;
114
+ return columns[col].minWidth || undefined;
115
+ }),
116
+ });
117
+ filteredData.forEach(row => {
118
+ const values = selectedColumns.map(col => {
119
+ const val = columns[col].get ? columns[col].get(row) : row[col];
120
+ return String(val !== undefined && val !== null ? val : '');
121
+ });
122
+ table.push(values);
123
+ });
124
+ printLine(table.toString());
125
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Templates Utility
3
+ *
4
+ * Reusable page presets — a named set of properties, optional body content,
5
+ * and optional icon. Templates are NOT tied to a specific database; properties
6
+ * are stored in simple format and expanded against the target schema at runtime.
7
+ *
8
+ * Stored at ~/.notion-cli/templates.json alongside bookmarks and daily config.
9
+ */
10
+ export interface Template {
11
+ properties?: Record<string, any>;
12
+ content?: string;
13
+ icon?: string;
14
+ }
15
+ export interface TemplatesData {
16
+ version: string;
17
+ templates: Record<string, Template>;
18
+ }
19
+ /** Load templates from disk. Returns empty structure if file doesn't exist. */
20
+ export declare function loadTemplates(): Promise<TemplatesData>;
21
+ /** Save templates to disk (atomic write via tmp + rename). */
22
+ export declare function saveTemplates(data: TemplatesData): Promise<void>;
23
+ /** Get a single template by name. Returns null if not found. */
24
+ export declare function getTemplate(name: string): Promise<Template | null>;
25
+ /** Save or update a template. */
26
+ export declare function setTemplate(name: string, template: Template): Promise<void>;
27
+ /** Remove a template. Returns true if it existed. */
28
+ export declare function removeTemplate(name: string): Promise<boolean>;
29
+ /** List all template names. */
30
+ export declare function listTemplateNames(): Promise<string[]>;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ /**
3
+ * Templates Utility
4
+ *
5
+ * Reusable page presets — a named set of properties, optional body content,
6
+ * and optional icon. Templates are NOT tied to a specific database; properties
7
+ * are stored in simple format and expanded against the target schema at runtime.
8
+ *
9
+ * Stored at ~/.notion-cli/templates.json alongside bookmarks and daily config.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.loadTemplates = loadTemplates;
13
+ exports.saveTemplates = saveTemplates;
14
+ exports.getTemplate = getTemplate;
15
+ exports.setTemplate = setTemplate;
16
+ exports.removeTemplate = removeTemplate;
17
+ exports.listTemplateNames = listTemplateNames;
18
+ const fs = require("fs/promises");
19
+ const path = require("path");
20
+ const workspace_cache_1 = require("./workspace-cache");
21
+ // -- Constants --
22
+ const TEMPLATES_FILE = 'templates.json';
23
+ const TEMPLATES_VERSION = '1.0.0';
24
+ function getTemplatesPath() {
25
+ return path.join((0, workspace_cache_1.getCacheDir)(), TEMPLATES_FILE);
26
+ }
27
+ // -- Core operations --
28
+ /** Load templates from disk. Returns empty structure if file doesn't exist. */
29
+ async function loadTemplates() {
30
+ try {
31
+ const content = await fs.readFile(getTemplatesPath(), 'utf-8');
32
+ const data = JSON.parse(content);
33
+ if (!data.version || typeof data.templates !== 'object') {
34
+ return createEmpty();
35
+ }
36
+ return data;
37
+ }
38
+ catch (error) {
39
+ if (error.code === 'ENOENT')
40
+ return createEmpty();
41
+ return createEmpty();
42
+ }
43
+ }
44
+ /** Save templates to disk (atomic write via tmp + rename). */
45
+ async function saveTemplates(data) {
46
+ await (0, workspace_cache_1.ensureCacheDir)();
47
+ const filePath = getTemplatesPath();
48
+ const tmpPath = `${filePath}.tmp`;
49
+ await fs.writeFile(tmpPath, JSON.stringify(data, null, 2), { encoding: 'utf-8', mode: 0o600 });
50
+ await fs.rename(tmpPath, filePath);
51
+ }
52
+ /** Get a single template by name. Returns null if not found. */
53
+ async function getTemplate(name) {
54
+ var _a;
55
+ const data = await loadTemplates();
56
+ return (_a = data.templates[name.toLowerCase()]) !== null && _a !== void 0 ? _a : null;
57
+ }
58
+ /** Save or update a template. */
59
+ async function setTemplate(name, template) {
60
+ const data = await loadTemplates();
61
+ data.templates[name.toLowerCase()] = template;
62
+ await saveTemplates(data);
63
+ }
64
+ /** Remove a template. Returns true if it existed. */
65
+ async function removeTemplate(name) {
66
+ const data = await loadTemplates();
67
+ const key = name.toLowerCase();
68
+ if (!(key in data.templates))
69
+ return false;
70
+ delete data.templates[key];
71
+ await saveTemplates(data);
72
+ return true;
73
+ }
74
+ /** List all template names. */
75
+ async function listTemplateNames() {
76
+ const data = await loadTemplates();
77
+ return Object.keys(data.templates);
78
+ }
79
+ // -- Helpers --
80
+ function createEmpty() {
81
+ return { version: TEMPLATES_VERSION, templates: {} };
82
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Terminal banner and color utilities for consistent branding
3
+ * Used across postinstall script and init command
4
+ */
5
+ /**
6
+ * ANSI color codes for cross-platform terminal compatibility
7
+ */
8
+ export declare const colors: {
9
+ readonly reset: "\u001B[0m";
10
+ readonly bright: "\u001B[1m";
11
+ readonly dim: "\u001B[2m";
12
+ readonly green: "\u001B[32m";
13
+ readonly blue: "\u001B[34m";
14
+ readonly cyan: "\u001B[36m";
15
+ readonly gray: "\u001B[90m";
16
+ readonly yellow: "\u001B[33m";
17
+ readonly magenta: "\u001B[35m";
18
+ };
19
+ /**
20
+ * ASCII art banner for Notion CLI
21
+ * Displayed during install and setup
22
+ * Uses terminal's default color (black/white depending on theme)
23
+ */
24
+ export declare const ASCII_BANNER = "\n\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\n\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\n\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\n\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\n\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551\n\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D\n";
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ /**
3
+ * Terminal banner and color utilities for consistent branding
4
+ * Used across postinstall script and init command
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ASCII_BANNER = exports.colors = void 0;
8
+ /**
9
+ * ANSI color codes for cross-platform terminal compatibility
10
+ */
11
+ exports.colors = {
12
+ reset: '\x1b[0m',
13
+ bright: '\x1b[1m',
14
+ dim: '\x1b[2m',
15
+ green: '\x1b[32m',
16
+ blue: '\x1b[34m',
17
+ cyan: '\x1b[36m',
18
+ gray: '\x1b[90m',
19
+ yellow: '\x1b[33m',
20
+ magenta: '\x1b[35m',
21
+ };
22
+ /**
23
+ * ASCII art banner for Notion CLI
24
+ * Displayed during install and setup
25
+ * Uses terminal's default color (black/white depending on theme)
26
+ */
27
+ exports.ASCII_BANNER = `
28
+ ███╗ ██╗ ██████╗ ████████╗██╗ ██████╗ ███╗ ██╗ ██████╗██╗ ██╗
29
+ ████╗ ██║██╔═══██╗╚══██╔══╝██║██╔═══██╗████╗ ██║ ██╔════╝██║ ██║
30
+ ██╔██╗ ██║██║ ██║ ██║ ██║██║ ██║██╔██╗ ██║ ██║ ██║ ██║
31
+ ██║╚██╗██║██║ ██║ ██║ ██║██║ ██║██║╚██╗██║ ██║ ██║ ██║
32
+ ██║ ╚████║╚██████╔╝ ██║ ██║╚██████╔╝██║ ╚████║ ╚██████╗███████╗██║
33
+ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝╚══════╝╚═╝
34
+ `;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Token Validation Utility
3
+ *
4
+ * Provides consistent token validation across all commands that interact with the Notion API.
5
+ * This ensures users get helpful, actionable error messages before attempting API calls.
6
+ */
7
+ /**
8
+ * Masks a Notion token for safe display in logs and console output
9
+ *
10
+ * Shows only the prefix and last 3 characters to prevent token leakage
11
+ * in screen recordings, terminal sharing, or logs.
12
+ *
13
+ * @param token - The token to mask
14
+ * @returns Masked token string (e.g., "secret_***...***abc")
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const token = "secret_1234567890abcdef"
19
+ * const masked = maskToken(token)
20
+ * // Returns: "secret_***...***def"
21
+ * ```
22
+ */
23
+ export declare function maskToken(token: string): string;
24
+ /**
25
+ * Validates that NOTION_TOKEN environment variable is set
26
+ *
27
+ * @throws {NotionCLIError} If token is not set, throws with helpful suggestions
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * import { validateNotionToken } from '../utils/token-validator'
32
+ *
33
+ * // In your command's run() method:
34
+ * async run() {
35
+ * const { flags } = await this.parse(MyCommand)
36
+ * validateNotionToken() // Throws if token not set
37
+ *
38
+ * // Continue with API calls...
39
+ * }
40
+ * ```
41
+ */
42
+ export declare function validateNotionToken(): void;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ /**
3
+ * Token Validation Utility
4
+ *
5
+ * Provides consistent token validation across all commands that interact with the Notion API.
6
+ * This ensures users get helpful, actionable error messages before attempting API calls.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.maskToken = maskToken;
10
+ exports.validateNotionToken = validateNotionToken;
11
+ const errors_1 = require("../errors");
12
+ /**
13
+ * Masks a Notion token for safe display in logs and console output
14
+ *
15
+ * Shows only the prefix and last 3 characters to prevent token leakage
16
+ * in screen recordings, terminal sharing, or logs.
17
+ *
18
+ * @param token - The token to mask
19
+ * @returns Masked token string (e.g., "secret_***...***abc")
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const token = "secret_1234567890abcdef"
24
+ * const masked = maskToken(token)
25
+ * // Returns: "secret_***...***def"
26
+ * ```
27
+ */
28
+ function maskToken(token) {
29
+ if (!token)
30
+ return '';
31
+ if (token.length <= 10) {
32
+ // Token too short to safely mask, obscure completely
33
+ // Threshold: 10 chars ensures at least 3 chars are masked after prefix+suffix
34
+ return '***';
35
+ }
36
+ // Show prefix (secret_ or ntn_) and last 3 chars
37
+ // For unknown prefixes: use max 4 chars to ensure at least 4 chars are masked
38
+ const prefix = token.startsWith('secret_') ? 'secret_' :
39
+ token.startsWith('ntn_') ? 'ntn_' :
40
+ token.slice(0, Math.min(4, token.length - 7));
41
+ const suffix = token.slice(-3);
42
+ return `${prefix}***...***${suffix}`;
43
+ }
44
+ /**
45
+ * Validates that NOTION_TOKEN environment variable is set
46
+ *
47
+ * @throws {NotionCLIError} If token is not set, throws with helpful suggestions
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * import { validateNotionToken } from '../utils/token-validator'
52
+ *
53
+ * // In your command's run() method:
54
+ * async run() {
55
+ * const { flags } = await this.parse(MyCommand)
56
+ * validateNotionToken() // Throws if token not set
57
+ *
58
+ * // Continue with API calls...
59
+ * }
60
+ * ```
61
+ */
62
+ function validateNotionToken() {
63
+ if (!process.env.NOTION_TOKEN) {
64
+ throw errors_1.NotionCLIErrorFactory.tokenMissing();
65
+ }
66
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Update notifier utility
3
+ * Checks for new versions of notion-cli and notifies users non-intrusively
4
+ *
5
+ * Runs asynchronously in background, doesn't block CLI execution
6
+ * Caches results for 1 day to avoid unnecessary npm registry checks
7
+ * Respects NO_UPDATE_NOTIFIER environment variable and CI environments
8
+ */
9
+ /**
10
+ * Check for updates and notify user if a new version is available
11
+ *
12
+ * This runs asynchronously and won't block CLI execution.
13
+ * Checks are cached for 1 day by default.
14
+ *
15
+ * Set DEBUG=1 environment variable to see error messages if update check fails.
16
+ *
17
+ * @example
18
+ * ```bash
19
+ * # Silent mode (default)
20
+ * notion-cli --version
21
+ *
22
+ * # Debug mode
23
+ * DEBUG=1 notion-cli --version
24
+ * ```
25
+ */
26
+ export declare function checkForUpdates(): void;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ /**
3
+ * Update notifier utility
4
+ * Checks for new versions of notion-cli and notifies users non-intrusively
5
+ *
6
+ * Runs asynchronously in background, doesn't block CLI execution
7
+ * Caches results for 1 day to avoid unnecessary npm registry checks
8
+ * Respects NO_UPDATE_NOTIFIER environment variable and CI environments
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.checkForUpdates = checkForUpdates;
12
+ /**
13
+ * Check for updates and notify user if a new version is available
14
+ *
15
+ * This runs asynchronously and won't block CLI execution.
16
+ * Checks are cached for 1 day by default.
17
+ *
18
+ * Set DEBUG=1 environment variable to see error messages if update check fails.
19
+ *
20
+ * @example
21
+ * ```bash
22
+ * # Silent mode (default)
23
+ * notion-cli --version
24
+ *
25
+ * # Debug mode
26
+ * DEBUG=1 notion-cli --version
27
+ * ```
28
+ */
29
+ function checkForUpdates() {
30
+ try {
31
+ // Load dependencies dynamically to avoid rootDir issues
32
+ const updateNotifier = require('update-notifier').default || require('update-notifier');
33
+ const packageJson = require('../../package.json');
34
+ // Initialize update notifier with package info
35
+ const notifier = updateNotifier({
36
+ pkg: packageJson,
37
+ updateCheckInterval: 1000 * 60 * 60 * 24, // Check once per day
38
+ });
39
+ // Show notification if update is available
40
+ // This displays a yellow-bordered box with update info
41
+ notifier.notify({
42
+ defer: true, // Show notification after command completes (non-intrusive)
43
+ isGlobal: true, // This is a global CLI tool
44
+ });
45
+ }
46
+ catch (error) {
47
+ // Silently fail - don't break CLI if update check fails
48
+ // This could happen if npm registry is unreachable, network issues, etc.
49
+ // Debug mode: Show error details for troubleshooting
50
+ if (process.env.DEBUG) {
51
+ console.error('Update check failed:', error instanceof Error ? error.message : error);
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Workspace Cache Utility
3
+ *
4
+ * Manages persistent caching of workspace databases for fast name-to-ID resolution.
5
+ * Cache is stored at ~/.notion-cli/databases.json
6
+ */
7
+ import { GetDataSourceResponse, DataSourceObjectResponse } from '@notionhq/client/build/src/api-endpoints';
8
+ export interface CachedDatabase {
9
+ id: string;
10
+ title: string;
11
+ titleNormalized: string;
12
+ aliases: string[];
13
+ url?: string;
14
+ lastEditedTime?: string;
15
+ properties?: Record<string, any>;
16
+ }
17
+ export interface WorkspaceCache {
18
+ version: string;
19
+ lastSync: string;
20
+ databases: CachedDatabase[];
21
+ }
22
+ /**
23
+ * Get the cache directory path
24
+ */
25
+ export declare function getCacheDir(): string;
26
+ /**
27
+ * Get the cache file path
28
+ */
29
+ export declare function getCachePath(): Promise<string>;
30
+ /**
31
+ * Ensure cache directory exists
32
+ */
33
+ export declare function ensureCacheDir(): Promise<void>;
34
+ /**
35
+ * Load cache from disk
36
+ * Returns null if cache doesn't exist or is corrupted
37
+ */
38
+ export declare function loadCache(): Promise<WorkspaceCache | null>;
39
+ /**
40
+ * Save cache to disk (atomic write)
41
+ */
42
+ export declare function saveCache(data: WorkspaceCache): Promise<void>;
43
+ /**
44
+ * Generate search aliases from a database title
45
+ *
46
+ * @example
47
+ * generateAliases('Tasks Database')
48
+ * // Returns: ['tasks database', 'tasks', 'task', 'tasks db', 'task db', 'td']
49
+ */
50
+ export declare function generateAliases(title: string): string[];
51
+ /**
52
+ * Build a cached database entry from a data source response
53
+ */
54
+ export declare function buildCacheEntry(dataSource: GetDataSourceResponse | DataSourceObjectResponse): CachedDatabase;
55
+ /**
56
+ * Create an empty cache
57
+ */
58
+ export declare function createEmptyCache(): WorkspaceCache;