@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,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const bookmarks_1 = require("../../utils/bookmarks");
5
+ const table_formatter_1 = require("../../utils/table-formatter");
6
+ const base_flags_1 = require("../../base-flags");
7
+ /**
8
+ * List all saved bookmarks.
9
+ * Shows name, type, ID, and which one is the default.
10
+ */
11
+ class BookmarkList extends core_1.Command {
12
+ async run() {
13
+ const { flags } = await this.parse(BookmarkList);
14
+ const data = await (0, bookmarks_1.loadBookmarks)();
15
+ const entries = Object.entries(data.bookmarks);
16
+ if (flags.json) {
17
+ this.log(JSON.stringify({
18
+ success: true,
19
+ data: { bookmarks: data.bookmarks, default: data.default },
20
+ timestamp: new Date().toISOString()
21
+ }, null, 2));
22
+ process.exit(0);
23
+ return;
24
+ }
25
+ if (entries.length === 0) {
26
+ this.log('No bookmarks saved yet.');
27
+ this.log('Create one with: notion-cli bookmark set <name> <ID_OR_URL>');
28
+ process.exit(0);
29
+ return;
30
+ }
31
+ // Build rows for table display
32
+ const rows = entries.map(([name, bm]) => ({
33
+ name,
34
+ type: bm.type,
35
+ id: bm.id,
36
+ default: name === data.default ? '*' : '',
37
+ }));
38
+ const columns = {
39
+ name: {},
40
+ type: {},
41
+ id: {},
42
+ default: {},
43
+ };
44
+ (0, table_formatter_1.formatTable)(rows, columns, { printLine: this.log.bind(this), ...flags });
45
+ process.exit(0);
46
+ }
47
+ }
48
+ BookmarkList.description = 'List all saved bookmarks';
49
+ BookmarkList.aliases = ['bm:ls'];
50
+ BookmarkList.examples = [
51
+ {
52
+ description: 'List bookmarks',
53
+ command: '$ notion-cli bookmark list',
54
+ },
55
+ ];
56
+ BookmarkList.flags = {
57
+ ...table_formatter_1.tableFlags,
58
+ ...base_flags_1.AutomationFlags,
59
+ };
60
+ exports.default = BookmarkList;
@@ -0,0 +1,26 @@
1
+ import { Command } from '@oclif/core';
2
+ /**
3
+ * Remove a saved bookmark by name.
4
+ * If the removed bookmark was the default, the default is cleared.
5
+ */
6
+ export default class BookmarkRemove extends Command {
7
+ static description: string;
8
+ static aliases: string[];
9
+ static examples: {
10
+ description: string;
11
+ command: string;
12
+ }[];
13
+ static args: {
14
+ name: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
15
+ };
16
+ static flags: {
17
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
18
+ 'page-size': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
19
+ retry: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
20
+ timeout: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
21
+ 'no-cache': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
22
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
23
+ minimal: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
24
+ };
25
+ run(): Promise<void>;
26
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const bookmarks_1 = require("../../utils/bookmarks");
5
+ const base_flags_1 = require("../../base-flags");
6
+ /**
7
+ * Remove a saved bookmark by name.
8
+ * If the removed bookmark was the default, the default is cleared.
9
+ */
10
+ class BookmarkRemove extends core_1.Command {
11
+ async run() {
12
+ const { args, flags } = await this.parse(BookmarkRemove);
13
+ const existed = await (0, bookmarks_1.removeBookmark)(args.name);
14
+ if (flags.json) {
15
+ this.log(JSON.stringify({
16
+ success: existed,
17
+ data: { name: args.name, removed: existed },
18
+ timestamp: new Date().toISOString()
19
+ }, null, 2));
20
+ process.exit(0);
21
+ return;
22
+ }
23
+ if (existed) {
24
+ this.log(`Removed bookmark "${args.name}"`);
25
+ }
26
+ else {
27
+ this.log(`Bookmark "${args.name}" not found.`);
28
+ this.log('Run `notion-cli bookmark list` to see saved bookmarks.');
29
+ }
30
+ process.exit(0);
31
+ }
32
+ }
33
+ BookmarkRemove.description = 'Remove a saved bookmark';
34
+ BookmarkRemove.aliases = ['bm:rm'];
35
+ BookmarkRemove.examples = [
36
+ {
37
+ description: 'Remove a bookmark',
38
+ command: '$ notion-cli bookmark remove inbox',
39
+ },
40
+ ];
41
+ BookmarkRemove.args = {
42
+ name: core_1.Args.string({ required: true, description: 'Bookmark name to remove' }),
43
+ };
44
+ BookmarkRemove.flags = {
45
+ ...base_flags_1.AutomationFlags,
46
+ };
47
+ exports.default = BookmarkRemove;
@@ -0,0 +1,29 @@
1
+ import { Command } from '@oclif/core';
2
+ /**
3
+ * Save a bookmark — a named shortcut to a Notion page or database.
4
+ * Once saved, the name works anywhere an ID or URL does.
5
+ */
6
+ export default class BookmarkSet extends Command {
7
+ static description: string;
8
+ static aliases: string[];
9
+ static examples: {
10
+ description: string;
11
+ command: string;
12
+ }[];
13
+ static args: {
14
+ name: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
15
+ target: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
16
+ };
17
+ static flags: {
18
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
19
+ 'page-size': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
20
+ retry: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
21
+ timeout: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
22
+ 'no-cache': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
23
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
24
+ minimal: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
25
+ type: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
26
+ default: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
27
+ };
28
+ run(): Promise<void>;
29
+ }
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const bookmarks_1 = require("../../utils/bookmarks");
5
+ const notion_resolver_1 = require("../../utils/notion-resolver");
6
+ const notion = require("../../notion");
7
+ const base_flags_1 = require("../../base-flags");
8
+ const errors_1 = require("../../errors");
9
+ /**
10
+ * Save a bookmark — a named shortcut to a Notion page or database.
11
+ * Once saved, the name works anywhere an ID or URL does.
12
+ */
13
+ class BookmarkSet extends core_1.Command {
14
+ async run() {
15
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
16
+ const { args, flags } = await this.parse(BookmarkSet);
17
+ const resourceType = flags.type;
18
+ try {
19
+ // Resolve target to a valid Notion ID (validates it exists)
20
+ const resolvedId = await (0, notion_resolver_1.resolveNotionId)(args.target, resourceType);
21
+ // Fetch resource to confirm access and get title for display
22
+ let title = 'Untitled';
23
+ if (resourceType === 'database') {
24
+ const db = await notion.retrieveDataSource(resolvedId);
25
+ title = ((_b = (_a = db.title) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.plain_text) || 'Untitled';
26
+ }
27
+ else {
28
+ const page = await notion.retrievePage({ page_id: resolvedId });
29
+ title = ((_f = (_e = (_d = (_c = page.properties) === null || _c === void 0 ? void 0 : _c.title) === null || _d === void 0 ? void 0 : _d.title) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.plain_text) ||
30
+ ((_k = (_j = (_h = (_g = page.properties) === null || _g === void 0 ? void 0 : _g.Name) === null || _h === void 0 ? void 0 : _h.title) === null || _j === void 0 ? void 0 : _j[0]) === null || _k === void 0 ? void 0 : _k.plain_text) || 'Untitled';
31
+ }
32
+ // Save bookmark
33
+ await (0, bookmarks_1.setBookmark)(args.name, resolvedId, resourceType);
34
+ // Set as default if requested
35
+ if (flags.default) {
36
+ await (0, bookmarks_1.setDefaultBookmark)(args.name);
37
+ }
38
+ if (flags.json) {
39
+ this.log(JSON.stringify({
40
+ success: true,
41
+ data: { name: args.name, id: resolvedId, type: resourceType, title, default: flags.default },
42
+ timestamp: new Date().toISOString()
43
+ }, null, 2));
44
+ }
45
+ else {
46
+ this.log(`Saved bookmark "${args.name}" → ${title} (${resourceType})`);
47
+ if (flags.default) {
48
+ this.log(`Set as default bookmark for quick capture.`);
49
+ }
50
+ }
51
+ process.exit(0);
52
+ }
53
+ catch (error) {
54
+ const cliError = error instanceof errors_1.NotionCLIError
55
+ ? error
56
+ : (0, errors_1.wrapNotionError)(error, { endpoint: 'bookmark.set', resourceType });
57
+ if (flags.json) {
58
+ this.log(JSON.stringify(cliError.toJSON(), null, 2));
59
+ }
60
+ else {
61
+ this.error(cliError.toHumanString());
62
+ }
63
+ process.exit(1);
64
+ }
65
+ }
66
+ }
67
+ BookmarkSet.description = 'Save a named shortcut to a Notion page or database';
68
+ BookmarkSet.aliases = ['bm:set'];
69
+ BookmarkSet.examples = [
70
+ {
71
+ description: 'Bookmark a database as "inbox" and set it as default',
72
+ command: '$ notion-cli bookmark set inbox DB_ID_OR_URL --default',
73
+ },
74
+ {
75
+ description: 'Bookmark a page',
76
+ command: '$ notion-cli bookmark set notes PAGE_URL --type page',
77
+ },
78
+ ];
79
+ BookmarkSet.args = {
80
+ name: core_1.Args.string({ required: true, description: 'Bookmark name (e.g. "inbox", "tasks")' }),
81
+ target: core_1.Args.string({ required: true, description: 'Notion ID, URL, or database name' }),
82
+ };
83
+ BookmarkSet.flags = {
84
+ type: core_1.Flags.string({
85
+ char: 't',
86
+ description: 'Resource type',
87
+ options: ['database', 'page'],
88
+ default: 'database',
89
+ }),
90
+ default: core_1.Flags.boolean({
91
+ description: 'Also set as the default bookmark (used by `quick` command)',
92
+ default: false,
93
+ }),
94
+ ...base_flags_1.AutomationFlags,
95
+ };
96
+ exports.default = BookmarkSet;
@@ -0,0 +1,13 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Browse 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
+ run(): Promise<void>;
13
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const notion_resolver_1 = require("../utils/notion-resolver");
5
+ const errors_1 = require("../errors");
6
+ const interactive_navigator_1 = require("../utils/interactive-navigator");
7
+ class Browse extends core_1.Command {
8
+ async run() {
9
+ const { args } = await this.parse(Browse);
10
+ try {
11
+ const pageId = await (0, notion_resolver_1.resolveNotionId)(args.page_id, 'page');
12
+ await (0, interactive_navigator_1.startNavigator)(pageId, this.log.bind(this));
13
+ }
14
+ catch (error) {
15
+ const cliError = error instanceof errors_1.NotionCLIError
16
+ ? error
17
+ : (0, errors_1.wrapNotionError)(error, {
18
+ resourceType: 'page',
19
+ attemptedId: args.page_id,
20
+ endpoint: 'browse',
21
+ });
22
+ this.error(cliError.toHumanString());
23
+ }
24
+ }
25
+ }
26
+ Browse.description = 'Interactively navigate a Notion page tree with arrow keys';
27
+ Browse.aliases = ['nav'];
28
+ Browse.examples = [
29
+ {
30
+ description: 'Browse a page by ID',
31
+ command: '$ notion-cli browse PAGE_ID',
32
+ },
33
+ {
34
+ description: 'Browse a page by URL',
35
+ command: '$ notion-cli browse https://notion.so/My-Page-abc123',
36
+ },
37
+ ];
38
+ Browse.args = {
39
+ page_id: core_1.Args.string({
40
+ required: true,
41
+ description: 'Page ID, URL, or name to start browsing from',
42
+ }),
43
+ };
44
+ exports.default = Browse;
@@ -0,0 +1,19 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class CacheInfo extends Command {
3
+ static description: string;
4
+ static aliases: string[];
5
+ static examples: {
6
+ description: string;
7
+ command: string;
8
+ }[];
9
+ static flags: {
10
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
+ 'page-size': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ retry: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
+ timeout: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
14
+ 'no-cache': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
16
+ minimal: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
17
+ };
18
+ run(): Promise<void>;
19
+ }
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_flags_1 = require("../../base-flags");
5
+ const workspace_cache_1 = require("../../utils/workspace-cache");
6
+ const cache_1 = require("../../cache");
7
+ const errors_1 = require("../../errors");
8
+ class CacheInfo extends core_1.Command {
9
+ async run() {
10
+ const { flags } = await this.parse(CacheInfo);
11
+ try {
12
+ // Get workspace cache
13
+ const workspaceCache = await (0, workspace_cache_1.loadCache)();
14
+ const cachePath = await (0, workspace_cache_1.getCachePath)();
15
+ // Get in-memory cache stats
16
+ const inMemoryStats = cache_1.cacheManager.getStats();
17
+ const hitRate = cache_1.cacheManager.getHitRate();
18
+ // Calculate workspace cache age if available
19
+ let workspaceInfo = null;
20
+ if (workspaceCache) {
21
+ const lastSyncTime = new Date(workspaceCache.lastSync);
22
+ const cacheAgeMs = Date.now() - lastSyncTime.getTime();
23
+ const cacheAgeHours = cacheAgeMs / (1000 * 60 * 60);
24
+ const isStale = cacheAgeHours > 24;
25
+ workspaceInfo = {
26
+ databases_cached: workspaceCache.databases.length,
27
+ last_sync: workspaceCache.lastSync,
28
+ cache_age_ms: cacheAgeMs,
29
+ cache_age_hours: parseFloat(cacheAgeHours.toFixed(2)),
30
+ is_stale: isStale,
31
+ stale_threshold_hours: 24,
32
+ cache_version: workspaceCache.version,
33
+ cache_location: cachePath,
34
+ };
35
+ }
36
+ // Build comprehensive cache info
37
+ const cacheInfo = {
38
+ in_memory: {
39
+ enabled: cache_1.cacheManager.isEnabled(),
40
+ stats: {
41
+ size: inMemoryStats.size,
42
+ hits: inMemoryStats.hits,
43
+ misses: inMemoryStats.misses,
44
+ sets: inMemoryStats.sets,
45
+ evictions: inMemoryStats.evictions,
46
+ hit_rate: parseFloat((hitRate * 100).toFixed(2)),
47
+ },
48
+ ttls_ms: {
49
+ data_source: parseInt(process.env.NOTION_CLI_CACHE_DS_TTL || '600000', 10),
50
+ page: parseInt(process.env.NOTION_CLI_CACHE_PAGE_TTL || '60000', 10),
51
+ user: parseInt(process.env.NOTION_CLI_CACHE_USER_TTL || '3600000', 10),
52
+ block: parseInt(process.env.NOTION_CLI_CACHE_BLOCK_TTL || '30000', 10),
53
+ },
54
+ max_size: parseInt(process.env.NOTION_CLI_CACHE_MAX_SIZE || '1000', 10),
55
+ },
56
+ workspace: workspaceInfo,
57
+ recommendations: {
58
+ sync_interval_hours: 24,
59
+ next_sync: workspaceCache ?
60
+ new Date(new Date(workspaceCache.lastSync).getTime() + 24 * 60 * 60 * 1000).toISOString() :
61
+ null,
62
+ action_needed: !workspaceCache ? 'Run "notion-cli sync" to initialize cache' :
63
+ (workspaceInfo && workspaceInfo.is_stale) ? 'Cache is stale, run "notion-cli sync"' :
64
+ 'Cache is fresh',
65
+ },
66
+ };
67
+ // JSON output
68
+ if (flags.json) {
69
+ this.log(JSON.stringify({
70
+ success: true,
71
+ data: cacheInfo,
72
+ metadata: {
73
+ timestamp: new Date().toISOString(),
74
+ command: 'cache:info',
75
+ },
76
+ }, null, 2));
77
+ process.exit(0);
78
+ }
79
+ // Human-readable output
80
+ this.log('Cache Configuration');
81
+ this.log('='.repeat(60));
82
+ this.log('\nIn-Memory Cache:');
83
+ this.log(` Enabled: ${cacheInfo.in_memory.enabled ? 'Yes' : 'No'}`);
84
+ this.log(` Size: ${inMemoryStats.size} / ${cacheInfo.in_memory.max_size}`);
85
+ this.log(` Hits: ${inMemoryStats.hits}`);
86
+ this.log(` Misses: ${inMemoryStats.misses}`);
87
+ this.log(` Hit Rate: ${(hitRate * 100).toFixed(1)}%`);
88
+ this.log(` Evictions: ${inMemoryStats.evictions}`);
89
+ this.log('\n TTLs (milliseconds):');
90
+ this.log(` Data Sources: ${cacheInfo.in_memory.ttls_ms.data_source} (${(cacheInfo.in_memory.ttls_ms.data_source / 60000).toFixed(0)} min)`);
91
+ this.log(` Pages: ${cacheInfo.in_memory.ttls_ms.page} (${(cacheInfo.in_memory.ttls_ms.page / 1000).toFixed(0)} sec)`);
92
+ this.log(` Users: ${cacheInfo.in_memory.ttls_ms.user} (${(cacheInfo.in_memory.ttls_ms.user / 60000).toFixed(0)} min)`);
93
+ this.log(` Blocks: ${cacheInfo.in_memory.ttls_ms.block} (${(cacheInfo.in_memory.ttls_ms.block / 1000).toFixed(0)} sec)`);
94
+ this.log('\nWorkspace Cache:');
95
+ if (workspaceInfo) {
96
+ this.log(` Databases: ${workspaceInfo.databases_cached}`);
97
+ this.log(` Last Sync: ${new Date(workspaceInfo.last_sync).toLocaleString()}`);
98
+ this.log(` Age: ${workspaceInfo.cache_age_hours} hours`);
99
+ this.log(` Status: ${workspaceInfo.is_stale ? '⚠️ STALE' : '✓ Fresh'}`);
100
+ this.log(` Location: ${workspaceInfo.cache_location}`);
101
+ }
102
+ else {
103
+ this.log(` Status: Not initialized`);
104
+ this.log(` Action: Run "notion-cli sync"`);
105
+ }
106
+ this.log('\nRecommendations:');
107
+ this.log(` Sync Interval: Every ${cacheInfo.recommendations.sync_interval_hours} hours`);
108
+ if (cacheInfo.recommendations.next_sync) {
109
+ this.log(` Next Sync: ${new Date(cacheInfo.recommendations.next_sync).toLocaleString()}`);
110
+ }
111
+ this.log(` Action: ${cacheInfo.recommendations.action_needed}`);
112
+ process.exit(0);
113
+ }
114
+ catch (error) {
115
+ const cliError = error instanceof errors_1.NotionCLIError
116
+ ? error
117
+ : (0, errors_1.wrapNotionError)(error instanceof Error ? error : new Error(String(error)), {
118
+ endpoint: 'cache.info'
119
+ });
120
+ if (flags.json) {
121
+ this.log(JSON.stringify(cliError.toJSON(), null, 2));
122
+ }
123
+ else {
124
+ this.error(cliError.toHumanString());
125
+ }
126
+ process.exit(1);
127
+ }
128
+ }
129
+ }
130
+ CacheInfo.description = 'Show cache statistics and configuration';
131
+ CacheInfo.aliases = ['cache:stats', 'cache:status'];
132
+ CacheInfo.examples = [
133
+ {
134
+ description: 'Show cache info in JSON format',
135
+ command: 'notion-cli cache:info --json',
136
+ },
137
+ {
138
+ description: 'Show cache statistics',
139
+ command: 'notion-cli cache:info',
140
+ },
141
+ ];
142
+ CacheInfo.flags = {
143
+ ...base_flags_1.AutomationFlags,
144
+ };
145
+ exports.default = CacheInfo;
@@ -0,0 +1,22 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class ConfigSetToken extends Command {
3
+ static description: string;
4
+ static aliases: string[];
5
+ static examples: {
6
+ description: string;
7
+ command: string;
8
+ }[];
9
+ static args: {
10
+ token: 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
+ };
21
+ run(): Promise<void>;
22
+ }
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const readline = require("readline");
5
+ const base_flags_1 = require("../../base-flags");
6
+ const errors_1 = require("../../errors");
7
+ const shell_config_1 = require("../../utils/shell-config");
8
+ const token_validator_1 = require("../../utils/token-validator");
9
+ class ConfigSetToken extends core_1.Command {
10
+ async run() {
11
+ const { args, flags } = await this.parse(ConfigSetToken);
12
+ try {
13
+ // Get token from args or prompt
14
+ let token = args.token;
15
+ if (!token) {
16
+ if (flags.json) {
17
+ throw new errors_1.NotionCLIError(errors_1.NotionCLIErrorCode.TOKEN_MISSING, 'Token required in JSON mode', [
18
+ {
19
+ description: 'Provide the token as an argument',
20
+ command: 'notion-cli config set-token ntn_your_token_here --json'
21
+ }
22
+ ]);
23
+ }
24
+ // Interactive prompt
25
+ const rl = readline.createInterface({
26
+ input: process.stdin,
27
+ output: process.stdout,
28
+ });
29
+ token = await new Promise((resolve) => {
30
+ rl.question('Enter your Notion integration token: ', (answer) => {
31
+ rl.close();
32
+ resolve(answer.trim());
33
+ });
34
+ });
35
+ }
36
+ // Validate token format — Notion tokens start with "secret_" (legacy) or "ntn_" (current)
37
+ if (!token || (!token.startsWith('secret_') && !token.startsWith('ntn_'))) {
38
+ throw new errors_1.NotionCLIError(errors_1.NotionCLIErrorCode.TOKEN_INVALID, 'Invalid token format - Notion tokens must start with "secret_" or "ntn_"', [
39
+ {
40
+ description: 'Get your integration token from Notion',
41
+ link: 'https://developers.notion.com/docs/create-a-notion-integration'
42
+ },
43
+ {
44
+ description: 'Tokens should look like: ntn_abc123... or secret_abc123...',
45
+ }
46
+ ], {
47
+ userInput: (0, token_validator_1.maskToken)(token),
48
+ metadata: { tokenFormat: 'invalid' }
49
+ });
50
+ }
51
+ // Persist token to shell rc file (~/.zshrc, ~/.bashrc, etc.)
52
+ const { rcFile, shell } = await (0, shell_config_1.persistToken)(token);
53
+ if (flags.json) {
54
+ this.log(JSON.stringify({
55
+ success: true,
56
+ message: 'Token saved successfully',
57
+ rcFile,
58
+ shell,
59
+ nextSteps: [
60
+ `Reload your shell: source ${rcFile}`,
61
+ 'Run: notion-cli sync',
62
+ ],
63
+ }, null, 2));
64
+ }
65
+ else {
66
+ this.log(`\n✓ Token saved to ${rcFile}`);
67
+ this.log('\nNext steps:');
68
+ this.log(` 1. Reload your shell: source ${rcFile}`);
69
+ this.log(` 2. Or restart your terminal`);
70
+ this.log(` 3. Run: notion-cli sync`);
71
+ this.log('\nWould you like to sync your workspace now? (y/n)');
72
+ const rl = readline.createInterface({
73
+ input: process.stdin,
74
+ output: process.stdout,
75
+ });
76
+ const answer = await new Promise((resolve) => {
77
+ rl.question('> ', (answer) => {
78
+ rl.close();
79
+ resolve(answer.trim().toLowerCase());
80
+ });
81
+ });
82
+ if (answer === 'y' || answer === 'yes') {
83
+ // Set token in current process
84
+ process.env.NOTION_TOKEN = token;
85
+ // Run sync command - dynamic import to avoid circular dependencies
86
+ this.log('\nRunning sync...\n');
87
+ const { default: Sync } = await Promise.resolve().then(() => require('../sync.js'));
88
+ await Sync.run([]);
89
+ }
90
+ else {
91
+ this.log('\nSkipping sync. You can run it manually with: notion-cli sync');
92
+ }
93
+ }
94
+ process.exit(0);
95
+ }
96
+ catch (error) {
97
+ const cliError = error instanceof errors_1.NotionCLIError
98
+ ? error
99
+ : (0, errors_1.wrapNotionError)(error instanceof Error ? error : new Error(String(error)), {
100
+ endpoint: 'config.set-token'
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
+ ConfigSetToken.description = 'Set NOTION_TOKEN in your shell configuration file';
113
+ ConfigSetToken.aliases = ['config:token'];
114
+ ConfigSetToken.examples = [
115
+ {
116
+ description: 'Set Notion token interactively',
117
+ command: 'notion-cli config set-token',
118
+ },
119
+ {
120
+ description: 'Set Notion token directly',
121
+ command: 'notion-cli config set-token ntn_abc123...',
122
+ },
123
+ {
124
+ description: 'Set token with JSON output',
125
+ command: 'notion-cli config set-token ntn_abc123... --json',
126
+ },
127
+ ];
128
+ ConfigSetToken.args = {
129
+ token: core_1.Args.string({
130
+ description: 'Notion integration token (starts with secret_ or ntn_)',
131
+ required: false,
132
+ }),
133
+ };
134
+ ConfigSetToken.flags = {
135
+ ...base_flags_1.AutomationFlags,
136
+ };
137
+ exports.default = ConfigSetToken;