@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.
- package/LICENSE +21 -0
- package/README.md +552 -0
- package/bin/dev +17 -0
- package/bin/dev.cmd +3 -0
- package/bin/run +14 -0
- package/bin/run.cmd +3 -0
- package/dist/base-command.d.ts +73 -0
- package/dist/base-command.js +179 -0
- package/dist/base-flags.d.ts +14 -0
- package/dist/base-flags.js +59 -0
- package/dist/cache.d.ts +84 -0
- package/dist/cache.js +351 -0
- package/dist/commands/append.d.ts +37 -0
- package/dist/commands/append.js +120 -0
- package/dist/commands/batch/delete.d.ts +42 -0
- package/dist/commands/batch/delete.js +199 -0
- package/dist/commands/batch/retrieve.d.ts +43 -0
- package/dist/commands/batch/retrieve.js +272 -0
- package/dist/commands/block/append.d.ts +42 -0
- package/dist/commands/block/append.js +219 -0
- package/dist/commands/block/delete.d.ts +30 -0
- package/dist/commands/block/delete.js +97 -0
- package/dist/commands/block/retrieve/children.d.ts +31 -0
- package/dist/commands/block/retrieve/children.js +177 -0
- package/dist/commands/block/retrieve.d.ts +30 -0
- package/dist/commands/block/retrieve.js +101 -0
- package/dist/commands/block/update.d.ts +45 -0
- package/dist/commands/block/update.js +242 -0
- package/dist/commands/bookmark/list.d.ts +30 -0
- package/dist/commands/bookmark/list.js +60 -0
- package/dist/commands/bookmark/remove.d.ts +26 -0
- package/dist/commands/bookmark/remove.js +47 -0
- package/dist/commands/bookmark/set.d.ts +29 -0
- package/dist/commands/bookmark/set.js +96 -0
- package/dist/commands/browse.d.ts +13 -0
- package/dist/commands/browse.js +44 -0
- package/dist/commands/cache/info.d.ts +19 -0
- package/dist/commands/cache/info.js +145 -0
- package/dist/commands/config/set-token.d.ts +22 -0
- package/dist/commands/config/set-token.js +137 -0
- package/dist/commands/daily/index.d.ts +32 -0
- package/dist/commands/daily/index.js +135 -0
- package/dist/commands/daily/setup.d.ts +42 -0
- package/dist/commands/daily/setup.js +149 -0
- package/dist/commands/db/create.d.ts +31 -0
- package/dist/commands/db/create.js +124 -0
- package/dist/commands/db/query.d.ts +41 -0
- package/dist/commands/db/query.js +360 -0
- package/dist/commands/db/retrieve.d.ts +33 -0
- package/dist/commands/db/retrieve.js +134 -0
- package/dist/commands/db/schema.d.ts +32 -0
- package/dist/commands/db/schema.js +308 -0
- package/dist/commands/db/update.d.ts +31 -0
- package/dist/commands/db/update.js +117 -0
- package/dist/commands/doctor.d.ts +50 -0
- package/dist/commands/doctor.js +420 -0
- package/dist/commands/init.d.ts +65 -0
- package/dist/commands/init.js +479 -0
- package/dist/commands/list.d.ts +29 -0
- package/dist/commands/list.js +219 -0
- package/dist/commands/open.d.ts +29 -0
- package/dist/commands/open.js +100 -0
- package/dist/commands/page/create.d.ts +33 -0
- package/dist/commands/page/create.js +261 -0
- package/dist/commands/page/delete.d.ts +36 -0
- package/dist/commands/page/delete.js +107 -0
- package/dist/commands/page/export.d.ts +38 -0
- package/dist/commands/page/export.js +120 -0
- package/dist/commands/page/retrieve/property_item.d.ts +24 -0
- package/dist/commands/page/retrieve/property_item.js +75 -0
- package/dist/commands/page/retrieve.d.ts +36 -0
- package/dist/commands/page/retrieve.js +244 -0
- package/dist/commands/page/update.d.ts +34 -0
- package/dist/commands/page/update.js +184 -0
- package/dist/commands/quick.d.ts +35 -0
- package/dist/commands/quick.js +168 -0
- package/dist/commands/search.d.ts +43 -0
- package/dist/commands/search.js +361 -0
- package/dist/commands/stats.d.ts +35 -0
- package/dist/commands/stats.js +274 -0
- package/dist/commands/sync.d.ts +24 -0
- package/dist/commands/sync.js +183 -0
- package/dist/commands/template/get.d.ts +28 -0
- package/dist/commands/template/get.js +59 -0
- package/dist/commands/template/list.d.ts +32 -0
- package/dist/commands/template/list.js +62 -0
- package/dist/commands/template/remove.d.ts +27 -0
- package/dist/commands/template/remove.js +48 -0
- package/dist/commands/template/save.d.ts +32 -0
- package/dist/commands/template/save.js +92 -0
- package/dist/commands/template/use.d.ts +34 -0
- package/dist/commands/template/use.js +142 -0
- package/dist/commands/user/list.d.ts +27 -0
- package/dist/commands/user/list.js +99 -0
- package/dist/commands/user/retrieve/bot.d.ts +28 -0
- package/dist/commands/user/retrieve/bot.js +96 -0
- package/dist/commands/user/retrieve.d.ts +30 -0
- package/dist/commands/user/retrieve.js +103 -0
- package/dist/commands/whoami.d.ts +19 -0
- package/dist/commands/whoami.js +175 -0
- package/dist/deduplication.d.ts +41 -0
- package/dist/deduplication.js +71 -0
- package/dist/envelope.d.ts +169 -0
- package/dist/envelope.js +257 -0
- package/dist/errors/enhanced-errors.d.ts +168 -0
- package/dist/errors/enhanced-errors.js +567 -0
- package/dist/errors/index.d.ts +18 -0
- package/dist/errors/index.js +33 -0
- package/dist/examples/cache-retry-examples.d.ts +64 -0
- package/dist/examples/cache-retry-examples.js +375 -0
- package/dist/helper.d.ts +102 -0
- package/dist/helper.js +885 -0
- package/dist/http-agent.d.ts +38 -0
- package/dist/http-agent.js +60 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -0
- package/dist/interface.d.ts +4 -0
- package/dist/interface.js +2 -0
- package/dist/notion.d.ts +144 -0
- package/dist/notion.js +547 -0
- package/dist/retry.d.ts +72 -0
- package/dist/retry.js +381 -0
- package/dist/utils/bookmarks.d.ts +32 -0
- package/dist/utils/bookmarks.js +98 -0
- package/dist/utils/daily-config.d.ts +22 -0
- package/dist/utils/daily-config.js +60 -0
- package/dist/utils/disk-cache.d.ts +80 -0
- package/dist/utils/disk-cache.js +291 -0
- package/dist/utils/fuzzy.d.ts +36 -0
- package/dist/utils/fuzzy.js +69 -0
- package/dist/utils/interactive-navigator.d.ts +63 -0
- package/dist/utils/interactive-navigator.js +123 -0
- package/dist/utils/markdown-to-blocks.d.ts +21 -0
- package/dist/utils/markdown-to-blocks.js +333 -0
- package/dist/utils/notion-resolver.d.ts +49 -0
- package/dist/utils/notion-resolver.js +278 -0
- package/dist/utils/notion-url-parser.d.ts +48 -0
- package/dist/utils/notion-url-parser.js +121 -0
- package/dist/utils/property-expander.d.ts +45 -0
- package/dist/utils/property-expander.js +323 -0
- package/dist/utils/schema-examples.d.ts +40 -0
- package/dist/utils/schema-examples.js +359 -0
- package/dist/utils/schema-extractor.d.ts +65 -0
- package/dist/utils/schema-extractor.js +235 -0
- package/dist/utils/shell-config.d.ts +30 -0
- package/dist/utils/shell-config.js +84 -0
- package/dist/utils/table-formatter.d.ts +36 -0
- package/dist/utils/table-formatter.js +125 -0
- package/dist/utils/templates.d.ts +30 -0
- package/dist/utils/templates.js +82 -0
- package/dist/utils/terminal-banner.d.ts +24 -0
- package/dist/utils/terminal-banner.js +34 -0
- package/dist/utils/token-validator.d.ts +42 -0
- package/dist/utils/token-validator.js +66 -0
- package/dist/utils/update-notifier.d.ts +26 -0
- package/dist/utils/update-notifier.js +54 -0
- package/dist/utils/workspace-cache.d.ts +58 -0
- package/dist/utils/workspace-cache.js +185 -0
- package/oclif.manifest.json +6471 -0
- package/package.json +118 -0
- package/scripts/banner.js +38 -0
- 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;
|