@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,420 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const notion_1 = require("../notion");
|
|
5
|
+
const workspace_cache_1 = require("../utils/workspace-cache");
|
|
6
|
+
const fs = require("fs/promises");
|
|
7
|
+
const https = require("https");
|
|
8
|
+
class Doctor extends core_1.Command {
|
|
9
|
+
async run() {
|
|
10
|
+
const { flags } = await this.parse(Doctor);
|
|
11
|
+
const checks = [];
|
|
12
|
+
// Run all health checks
|
|
13
|
+
await this.checkNodeVersion(checks);
|
|
14
|
+
await this.checkTokenSet(checks);
|
|
15
|
+
await this.checkTokenFormat(checks);
|
|
16
|
+
await this.checkNetworkConnectivity(checks);
|
|
17
|
+
await this.checkApiConnection(checks);
|
|
18
|
+
await this.checkCacheExists(checks);
|
|
19
|
+
await this.checkCacheFreshness(checks);
|
|
20
|
+
// Calculate summary
|
|
21
|
+
const summary = {
|
|
22
|
+
total: checks.length,
|
|
23
|
+
passed: checks.filter(c => c.passed).length,
|
|
24
|
+
failed: checks.filter(c => !c.passed).length,
|
|
25
|
+
};
|
|
26
|
+
const result = {
|
|
27
|
+
success: summary.failed === 0,
|
|
28
|
+
checks,
|
|
29
|
+
summary,
|
|
30
|
+
};
|
|
31
|
+
// Output results
|
|
32
|
+
if (flags.json) {
|
|
33
|
+
this.log(JSON.stringify(result, null, 2));
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
this.printHumanReadable(result);
|
|
37
|
+
}
|
|
38
|
+
// Exit with appropriate code
|
|
39
|
+
process.exit(result.success ? 0 : 1);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Check Node.js version meets requirement (>=18.0.0)
|
|
43
|
+
*/
|
|
44
|
+
async checkNodeVersion(checks) {
|
|
45
|
+
try {
|
|
46
|
+
const version = process.version;
|
|
47
|
+
const major = parseInt(version.split('.')[0].replace('v', ''));
|
|
48
|
+
const passed = major >= 18;
|
|
49
|
+
checks.push({
|
|
50
|
+
name: 'nodejs_version',
|
|
51
|
+
passed,
|
|
52
|
+
value: version,
|
|
53
|
+
message: passed ? undefined : 'Node.js version must be >= 18.0.0',
|
|
54
|
+
recommendation: passed ? undefined : 'Please upgrade Node.js to version 18 or higher',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
checks.push({
|
|
59
|
+
name: 'nodejs_version',
|
|
60
|
+
passed: false,
|
|
61
|
+
message: 'Failed to check Node.js version',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Check if NOTION_TOKEN environment variable is set
|
|
67
|
+
*/
|
|
68
|
+
async checkTokenSet(checks) {
|
|
69
|
+
const tokenSet = !!process.env.NOTION_TOKEN;
|
|
70
|
+
checks.push({
|
|
71
|
+
name: 'token_set',
|
|
72
|
+
passed: tokenSet,
|
|
73
|
+
message: tokenSet ? undefined : 'NOTION_TOKEN environment variable is not set',
|
|
74
|
+
recommendation: tokenSet ? undefined : "Run 'notion-cli config set-token' or 'notion-cli init'",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Check if token format is valid
|
|
79
|
+
* Accepts both "secret_" prefix (internal integrations) and "ntn_" prefix (OAuth tokens)
|
|
80
|
+
*/
|
|
81
|
+
async checkTokenFormat(checks) {
|
|
82
|
+
const token = process.env.NOTION_TOKEN;
|
|
83
|
+
if (!token) {
|
|
84
|
+
// Skip if token not set (already handled by checkTokenSet)
|
|
85
|
+
checks.push({
|
|
86
|
+
name: 'token_format',
|
|
87
|
+
passed: false,
|
|
88
|
+
message: 'Cannot check format - token not set',
|
|
89
|
+
});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// Check for valid token formats
|
|
93
|
+
// Internal integrations: secret_*
|
|
94
|
+
// OAuth tokens: ntn_*
|
|
95
|
+
// Also accept tokens that look like valid base64 or hex strings (length >= 32)
|
|
96
|
+
const isValidFormat = token.startsWith('secret_') ||
|
|
97
|
+
token.startsWith('ntn_') ||
|
|
98
|
+
(token.length >= 32 && /^[A-Za-z0-9_-]+$/.test(token));
|
|
99
|
+
if (!isValidFormat) {
|
|
100
|
+
checks.push({
|
|
101
|
+
name: 'token_format',
|
|
102
|
+
passed: false,
|
|
103
|
+
message: 'Token format appears invalid',
|
|
104
|
+
recommendation: 'Notion tokens typically start with "secret_" or "ntn_". Please verify your token.',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
checks.push({
|
|
109
|
+
name: 'token_format',
|
|
110
|
+
passed: true,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Check network connectivity to api.notion.com
|
|
116
|
+
*/
|
|
117
|
+
async checkNetworkConnectivity(checks) {
|
|
118
|
+
try {
|
|
119
|
+
await this.checkHttpsConnection('api.notion.com', 443);
|
|
120
|
+
checks.push({
|
|
121
|
+
name: 'network_connectivity',
|
|
122
|
+
passed: true,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
checks.push({
|
|
127
|
+
name: 'network_connectivity',
|
|
128
|
+
passed: false,
|
|
129
|
+
message: 'Cannot reach api.notion.com',
|
|
130
|
+
recommendation: 'Check your internet connection and firewall settings',
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Check if can connect to Notion API (whoami check)
|
|
136
|
+
*/
|
|
137
|
+
async checkApiConnection(checks) {
|
|
138
|
+
const token = process.env.NOTION_TOKEN;
|
|
139
|
+
if (!token) {
|
|
140
|
+
// Skip if token not set
|
|
141
|
+
checks.push({
|
|
142
|
+
name: 'api_connection',
|
|
143
|
+
passed: false,
|
|
144
|
+
message: 'Cannot test API - token not set',
|
|
145
|
+
});
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
const user = await notion_1.client.users.me({});
|
|
150
|
+
let botName = 'Unknown Bot';
|
|
151
|
+
let workspaceName;
|
|
152
|
+
if (user.type === 'bot') {
|
|
153
|
+
const botUser = user;
|
|
154
|
+
botName = user.name || 'Unnamed Bot';
|
|
155
|
+
if (botUser.bot && typeof botUser.bot === 'object' && 'workspace_name' in botUser.bot) {
|
|
156
|
+
workspaceName = botUser.bot.workspace_name;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
checks.push({
|
|
160
|
+
name: 'api_connection',
|
|
161
|
+
passed: true,
|
|
162
|
+
bot_name: botName,
|
|
163
|
+
workspace_name: workspaceName,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
let message = 'Failed to connect to Notion API';
|
|
168
|
+
let recommendation = 'Verify your NOTION_TOKEN is valid and active';
|
|
169
|
+
if (error.code === 'unauthorized' || error.status === 401) {
|
|
170
|
+
message = 'Authentication failed - invalid token';
|
|
171
|
+
recommendation = "Run 'notion-cli config set-token' to update your token";
|
|
172
|
+
}
|
|
173
|
+
else if (error.code === 'ENOTFOUND' || error.code === 'ETIMEDOUT') {
|
|
174
|
+
message = 'Network error - cannot reach Notion API';
|
|
175
|
+
recommendation = 'Check your internet connection';
|
|
176
|
+
}
|
|
177
|
+
checks.push({
|
|
178
|
+
name: 'api_connection',
|
|
179
|
+
passed: false,
|
|
180
|
+
message,
|
|
181
|
+
recommendation,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Check if workspace cache exists
|
|
187
|
+
*/
|
|
188
|
+
async checkCacheExists(checks) {
|
|
189
|
+
try {
|
|
190
|
+
const cachePath = await (0, workspace_cache_1.getCachePath)();
|
|
191
|
+
try {
|
|
192
|
+
await fs.access(cachePath);
|
|
193
|
+
checks.push({
|
|
194
|
+
name: 'cache_exists',
|
|
195
|
+
passed: true,
|
|
196
|
+
value: cachePath,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
checks.push({
|
|
201
|
+
name: 'cache_exists',
|
|
202
|
+
passed: false,
|
|
203
|
+
message: 'Workspace cache does not exist',
|
|
204
|
+
recommendation: "Run 'notion-cli sync' to create cache",
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
checks.push({
|
|
210
|
+
name: 'cache_exists',
|
|
211
|
+
passed: false,
|
|
212
|
+
message: 'Failed to check cache existence',
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Check if cache is fresh (< 24 hours old) or needs sync
|
|
218
|
+
*/
|
|
219
|
+
async checkCacheFreshness(checks) {
|
|
220
|
+
try {
|
|
221
|
+
const cache = await (0, workspace_cache_1.loadCache)();
|
|
222
|
+
if (!cache || !cache.lastSync) {
|
|
223
|
+
checks.push({
|
|
224
|
+
name: 'cache_fresh',
|
|
225
|
+
passed: false,
|
|
226
|
+
message: 'Cache is empty or corrupted',
|
|
227
|
+
recommendation: "Run 'notion-cli sync' to rebuild cache",
|
|
228
|
+
});
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const lastSyncTime = new Date(cache.lastSync).getTime();
|
|
232
|
+
const now = Date.now();
|
|
233
|
+
const ageMs = now - lastSyncTime;
|
|
234
|
+
const ageHours = ageMs / (1000 * 60 * 60);
|
|
235
|
+
const ageDays = Math.floor(ageHours / 24);
|
|
236
|
+
const remainingHours = Math.floor(ageHours % 24);
|
|
237
|
+
const isFresh = ageHours < 24;
|
|
238
|
+
let ageString;
|
|
239
|
+
if (ageDays === 0) {
|
|
240
|
+
ageString = `${Math.floor(ageHours)} hours ago`;
|
|
241
|
+
}
|
|
242
|
+
else if (ageDays === 1) {
|
|
243
|
+
ageString = remainingHours === 0 ? '1 day ago' : `1 day, ${remainingHours} hours ago`;
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
ageString = remainingHours === 0 ? `${ageDays} days ago` : `${ageDays} days, ${remainingHours} hours ago`;
|
|
247
|
+
}
|
|
248
|
+
checks.push({
|
|
249
|
+
name: 'cache_fresh',
|
|
250
|
+
passed: isFresh,
|
|
251
|
+
age_hours: Math.round(ageHours * 10) / 10,
|
|
252
|
+
value: ageString,
|
|
253
|
+
message: isFresh ? undefined : `Cache is outdated (last sync: ${ageString})`,
|
|
254
|
+
recommendation: isFresh ? undefined : "Run 'notion-cli sync' to refresh",
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
checks.push({
|
|
259
|
+
name: 'cache_fresh',
|
|
260
|
+
passed: false,
|
|
261
|
+
message: 'Failed to check cache freshness',
|
|
262
|
+
recommendation: "Run 'notion-cli sync' to refresh cache",
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Test HTTPS connection to a host
|
|
268
|
+
*/
|
|
269
|
+
async checkHttpsConnection(host, port) {
|
|
270
|
+
return new Promise((resolve, reject) => {
|
|
271
|
+
const options = {
|
|
272
|
+
host,
|
|
273
|
+
port,
|
|
274
|
+
method: 'GET',
|
|
275
|
+
path: '/',
|
|
276
|
+
timeout: 5000,
|
|
277
|
+
};
|
|
278
|
+
const req = https.request(options, () => {
|
|
279
|
+
resolve();
|
|
280
|
+
});
|
|
281
|
+
req.on('error', (error) => {
|
|
282
|
+
reject(error);
|
|
283
|
+
});
|
|
284
|
+
req.on('timeout', () => {
|
|
285
|
+
req.destroy();
|
|
286
|
+
reject(new Error('Connection timeout'));
|
|
287
|
+
});
|
|
288
|
+
req.end();
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Print human-readable output
|
|
293
|
+
*/
|
|
294
|
+
printHumanReadable(result) {
|
|
295
|
+
this.log('\nNotion CLI Health Check');
|
|
296
|
+
this.log('━'.repeat(50));
|
|
297
|
+
this.log('');
|
|
298
|
+
// Print each check
|
|
299
|
+
for (const check of result.checks) {
|
|
300
|
+
const icon = check.passed ? '✓' : '✗';
|
|
301
|
+
const color = check.passed ? '\x1b[32m' : '\x1b[31m'; // Green or Red
|
|
302
|
+
const reset = '\x1b[0m';
|
|
303
|
+
switch (check.name) {
|
|
304
|
+
case 'nodejs_version':
|
|
305
|
+
if (check.passed) {
|
|
306
|
+
this.log(`${color}${icon}${reset} Node.js version: ${check.value}`);
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
this.log(`${color}${icon}${reset} Node.js version: ${check.value || 'unknown'} (${check.message})`);
|
|
310
|
+
}
|
|
311
|
+
break;
|
|
312
|
+
case 'token_set':
|
|
313
|
+
if (check.passed) {
|
|
314
|
+
this.log(`${color}${icon}${reset} NOTION_TOKEN is set`);
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
this.log(`${color}${icon}${reset} NOTION_TOKEN is not set`);
|
|
318
|
+
}
|
|
319
|
+
break;
|
|
320
|
+
case 'token_format':
|
|
321
|
+
if (check.passed) {
|
|
322
|
+
this.log(`${color}${icon}${reset} Token format is valid`);
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
this.log(`${color}${icon}${reset} Token format is invalid (${check.message})`);
|
|
326
|
+
}
|
|
327
|
+
break;
|
|
328
|
+
case 'network_connectivity':
|
|
329
|
+
if (check.passed) {
|
|
330
|
+
this.log(`${color}${icon}${reset} Network connectivity to api.notion.com`);
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
this.log(`${color}${icon}${reset} Cannot reach api.notion.com`);
|
|
334
|
+
}
|
|
335
|
+
break;
|
|
336
|
+
case 'api_connection':
|
|
337
|
+
if (check.passed) {
|
|
338
|
+
this.log(`${color}${icon}${reset} API connection successful`);
|
|
339
|
+
if (check.bot_name) {
|
|
340
|
+
const workspaceInfo = check.workspace_name ? ` (${check.workspace_name})` : '';
|
|
341
|
+
this.log(`${color}${icon}${reset} Connected as: ${check.bot_name}${workspaceInfo}`);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
this.log(`${color}${icon}${reset} API connection failed (${check.message})`);
|
|
346
|
+
}
|
|
347
|
+
break;
|
|
348
|
+
case 'cache_exists':
|
|
349
|
+
if (check.passed) {
|
|
350
|
+
this.log(`${color}${icon}${reset} Workspace cache exists`);
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
this.log(`${color}${icon}${reset} Workspace cache does not exist`);
|
|
354
|
+
}
|
|
355
|
+
break;
|
|
356
|
+
case 'cache_fresh':
|
|
357
|
+
if (check.passed) {
|
|
358
|
+
this.log(`${color}${icon}${reset} Cache is fresh (last sync: ${check.value})`);
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
if (check.value) {
|
|
362
|
+
const warningIcon = '⚠';
|
|
363
|
+
const warningColor = '\x1b[33m'; // Yellow
|
|
364
|
+
this.log(`${warningColor}${warningIcon}${reset} Cache is outdated (last sync: ${check.value})`);
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
this.log(`${color}${icon}${reset} ${check.message}`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// Print recommendations for failed checks
|
|
374
|
+
const failedChecks = result.checks.filter(c => !c.passed && c.recommendation);
|
|
375
|
+
if (failedChecks.length > 0) {
|
|
376
|
+
this.log('');
|
|
377
|
+
const infoColor = '\x1b[36m'; // Cyan
|
|
378
|
+
const reset = '\x1b[0m';
|
|
379
|
+
for (const check of failedChecks) {
|
|
380
|
+
if (check.recommendation) {
|
|
381
|
+
this.log(`${infoColor}ℹ${reset} ${check.recommendation}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
// Print summary
|
|
386
|
+
this.log('');
|
|
387
|
+
this.log('━'.repeat(50));
|
|
388
|
+
if (result.success) {
|
|
389
|
+
const greenColor = '\x1b[32m';
|
|
390
|
+
const reset = '\x1b[0m';
|
|
391
|
+
this.log(`${greenColor}Overall: All ${result.summary.total} checks passed${reset}`);
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
const redColor = '\x1b[31m';
|
|
395
|
+
const reset = '\x1b[0m';
|
|
396
|
+
this.log(`${redColor}Overall: ${result.summary.passed}/${result.summary.total} checks passed${reset}`);
|
|
397
|
+
}
|
|
398
|
+
this.log('');
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
Doctor.description = 'Run health checks and diagnostics for Notion CLI';
|
|
402
|
+
Doctor.aliases = ['diagnose', 'healthcheck'];
|
|
403
|
+
Doctor.examples = [
|
|
404
|
+
{
|
|
405
|
+
description: 'Run all health checks',
|
|
406
|
+
command: '$ notion-cli doctor',
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
description: 'Run health checks with JSON output',
|
|
410
|
+
command: '$ notion-cli doctor --json',
|
|
411
|
+
},
|
|
412
|
+
];
|
|
413
|
+
Doctor.flags = {
|
|
414
|
+
json: core_1.Flags.boolean({
|
|
415
|
+
char: 'j',
|
|
416
|
+
description: 'Output as JSON',
|
|
417
|
+
default: false,
|
|
418
|
+
}),
|
|
419
|
+
};
|
|
420
|
+
exports.default = Doctor;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
/**
|
|
3
|
+
* Interactive first-time setup wizard for Notion CLI
|
|
4
|
+
*
|
|
5
|
+
* Guides new users through:
|
|
6
|
+
* 1. Token configuration
|
|
7
|
+
* 2. Connection testing
|
|
8
|
+
* 3. Workspace synchronization
|
|
9
|
+
*
|
|
10
|
+
* Designed to provide a welcoming, educational experience that sets users up for success.
|
|
11
|
+
*/
|
|
12
|
+
export default class Init extends Command {
|
|
13
|
+
static description: string;
|
|
14
|
+
static args: {
|
|
15
|
+
token: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
16
|
+
};
|
|
17
|
+
static examples: {
|
|
18
|
+
description: string;
|
|
19
|
+
command: string;
|
|
20
|
+
}[];
|
|
21
|
+
static flags: {
|
|
22
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
23
|
+
'page-size': import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
24
|
+
retry: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
25
|
+
timeout: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
26
|
+
'no-cache': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
28
|
+
minimal: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
29
|
+
};
|
|
30
|
+
private isJsonMode;
|
|
31
|
+
run(): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Check if user already has a configured token
|
|
34
|
+
*/
|
|
35
|
+
private checkExistingSetup;
|
|
36
|
+
/**
|
|
37
|
+
* Prompt user if they want to reconfigure
|
|
38
|
+
*/
|
|
39
|
+
private promptReconfigure;
|
|
40
|
+
/**
|
|
41
|
+
* Show welcome message
|
|
42
|
+
*/
|
|
43
|
+
private showWelcome;
|
|
44
|
+
/**
|
|
45
|
+
* Step 1: Setup token
|
|
46
|
+
* Accepts an optional token argument — if provided, skips interactive prompt.
|
|
47
|
+
*/
|
|
48
|
+
private setupToken;
|
|
49
|
+
/**
|
|
50
|
+
* Prompt user for token via interactive readline
|
|
51
|
+
*/
|
|
52
|
+
private promptForToken;
|
|
53
|
+
/**
|
|
54
|
+
* Step 2: Test connection
|
|
55
|
+
*/
|
|
56
|
+
private testConnection;
|
|
57
|
+
/**
|
|
58
|
+
* Step 3: Sync workspace
|
|
59
|
+
*/
|
|
60
|
+
private syncWorkspace;
|
|
61
|
+
/**
|
|
62
|
+
* Show success summary
|
|
63
|
+
*/
|
|
64
|
+
private showSuccess;
|
|
65
|
+
}
|