@nbtca/prompt 1.5.0 → 1.5.2

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.
@@ -113,11 +113,10 @@ async function interactiveLogin(isInteractive) {
113
113
  if (!isInteractive) {
114
114
  throw new AuthError('INVALID_CREDENTIALS', 'credentials', 'Interactive login requires a terminal.');
115
115
  }
116
- const username = await runSecretInput({
116
+ const username = await runTextInput({
117
117
  message: trans.studentId,
118
118
  placeholder: trans.studentIdHint,
119
119
  allowEmpty: false,
120
- mask: '•',
121
120
  });
122
121
  if (!username)
123
122
  throw new AuthError('INVALID_CREDENTIALS', 'credentials', 'Student id is required.');
@@ -9,7 +9,7 @@ function formatThemeSummary() {
9
9
  const prefs = loadPreferences();
10
10
  return `${trans.theme.iconMode}: ${prefs.iconMode}, ${trans.theme.colorMode}: ${prefs.colorMode}`;
11
11
  }
12
- export function runThemeCommand(args) {
12
+ export function runThemeCommand(args, options = {}) {
13
13
  const trans = t();
14
14
  const [scope, value] = args;
15
15
  if (!scope) {
@@ -18,7 +18,7 @@ export function runThemeCommand(args) {
18
18
  if (scope === 'reset') {
19
19
  const saved = resetPreferences();
20
20
  resetIconCache();
21
- applyColorModePreference(false);
21
+ applyColorModePreference(options.forcePlain === true);
22
22
  resetCapabilities();
23
23
  const message = saved ? trans.theme.reset : trans.theme.resetSessionOnly;
24
24
  return { ok: true, message };
@@ -39,7 +39,7 @@ export function runThemeCommand(args) {
39
39
  return { ok: false, message: `${trans.theme.invalidValue} auto, on, off` };
40
40
  }
41
41
  const saved = setColorMode(mode);
42
- applyColorModePreference(false);
42
+ applyColorModePreference(options.forcePlain === true);
43
43
  resetCapabilities();
44
44
  return { ok: true, message: saved ? trans.theme.updated : trans.theme.updatedSessionOnly };
45
45
  }
@@ -41,8 +41,8 @@ export async function runUpdateCheck() {
41
41
  const trans = t();
42
42
  const latest = await fetchLatestVersion();
43
43
  if (!latest) {
44
- console.log(chalk.yellow(trans.update.checkFailed));
45
- return;
44
+ console.error(chalk.yellow(trans.update.checkFailed));
45
+ return false;
46
46
  }
47
47
  if (isNewer(APP_INFO.version, latest)) {
48
48
  console.log(chalk.yellow(fmt(trans.update.available, { latest, current: APP_INFO.version })));
@@ -51,4 +51,5 @@ export async function runUpdateCheck() {
51
51
  else {
52
52
  console.log(chalk.green(fmt(trans.update.upToDate, { version: APP_INFO.version })));
53
53
  }
54
+ return true;
54
55
  }
@@ -46,6 +46,7 @@
46
46
  "loading": "Loading event calendar...",
47
47
  "noEvents": "No upcoming events",
48
48
  "error": "Failed to load event calendar",
49
+ "stale": "offline, showing last known",
49
50
  "errorHint": "Please try again later or visit https://nbtca.space",
50
51
  "eventsFound": "events found",
51
52
  "dateTime": "Date & Time",
@@ -113,7 +114,6 @@
113
114
  "opening": "Opening browser...",
114
115
  "browserOpened": "Knowledge base opened in browser",
115
116
  "browserError": "Failed to open browser",
116
- "browserErrorHint": "Please visit manually: https://docs.nbtca.space",
117
117
  "retry": "Retry?",
118
118
  "tocTitle": "Table of Contents",
119
119
  "tableHint": "diagrams and tables render better in browser",
@@ -142,12 +142,14 @@
142
142
  "repair": "Repair Service",
143
143
  "opening": "Opening...",
144
144
  "opened": "Opened in browser",
145
- "error": "Failed to open browser"
145
+ "error": "Failed to open browser",
146
+ "openManually": "Open manually: {url}"
146
147
  },
147
148
  "status": {
148
149
  "checking": "Checking service status...",
149
150
  "summaryOk": "All services are healthy",
150
151
  "summaryFail": "Some services are unavailable",
152
+ "summaryIntranet": "Public services are healthy; intranet availability depends on your network",
151
153
  "service": "Service",
152
154
  "health": "Health",
153
155
  "code": "Code",
@@ -361,6 +363,9 @@
361
363
  "invalidFlagHint": "Run `nbtca --help` to see command usage.",
362
364
  "invalidLang": "Invalid language. Use `zh` or `en`.",
363
365
  "invalidNext": "Invalid --next value. Use --next=<number> (>= 1).",
366
+ "eventsHeatmapConflict": "--heatmap cannot be combined with --today, --week, --month, --next, or --search.",
367
+ "eventsRangeConflict": "Choose only one event range: --today, --week, or --month.",
368
+ "unexpectedArguments": "Unexpected arguments for {command}.",
364
369
  "requiresTty": "Interactive mode requires a TTY terminal.",
365
370
  "requiresTtyHint": "Use `nbtca --help` for command mode."
366
371
  }
@@ -46,6 +46,7 @@
46
46
  "loading": "正在获取活动日历...",
47
47
  "noEvents": "近期暂无活动安排",
48
48
  "error": "无法获取活动日历",
49
+ "stale": "离线,显示上次获取的数据",
49
50
  "errorHint": "请稍后重试或访问 https://nbtca.space",
50
51
  "eventsFound": "个活动",
51
52
  "dateTime": "日期时间",
@@ -113,7 +114,6 @@
113
114
  "opening": "正在打开浏览器...",
114
115
  "browserOpened": "已在浏览器中打开知识库",
115
116
  "browserError": "无法打开浏览器",
116
- "browserErrorHint": "请手动访问: https://docs.nbtca.space",
117
117
  "retry": "是否重试?",
118
118
  "tocTitle": "目录",
119
119
  "tableHint": "图表与表格在浏览器中效果更佳",
@@ -142,12 +142,14 @@
142
142
  "repair": "维修服务",
143
143
  "opening": "正在打开...",
144
144
  "opened": "已在浏览器中打开",
145
- "error": "无法打开浏览器"
145
+ "error": "无法打开浏览器",
146
+ "openManually": "请手动打开: {url}"
146
147
  },
147
148
  "status": {
148
149
  "checking": "正在检查服务状态...",
149
150
  "summaryOk": "所有服务运行正常",
150
151
  "summaryFail": "部分服务不可用",
152
+ "summaryIntranet": "公共服务运行正常;内网可用性取决于当前网络",
151
153
  "service": "服务",
152
154
  "health": "状态",
153
155
  "code": "代码",
@@ -361,6 +363,9 @@
361
363
  "invalidFlagHint": "运行 `nbtca --help` 查看命令用法。",
362
364
  "invalidLang": "无效语言。请使用 `zh` 或 `en`。",
363
365
  "invalidNext": "无效的 --next 值。请使用 --next=<数字>(>= 1)。",
366
+ "eventsHeatmapConflict": "--heatmap 不能与 --today、--week、--month、--next 或 --search 同时使用。",
367
+ "eventsRangeConflict": "活动时间范围只能选择一个: --today、--week 或 --month。",
368
+ "unexpectedArguments": "{command} 不接受多余参数。",
364
369
  "requiresTty": "交互模式需要 TTY 终端。",
365
370
  "requiresTtyHint": "使用 `nbtca --help` 查看命令模式。"
366
371
  }
package/dist/index.js CHANGED
@@ -1,500 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import chalk from 'chalk';
3
- import open from 'open';
4
- import { main } from './main.js';
5
- import { fetchEvents, fetchHeatmapBuckets, renderEventsTable, serializeEvents, } from './features/calendar.js';
6
- import { renderHeatmap } from './features/calendar-heatmap.js';
7
- import { checkServices, countServiceHealth, hasServiceFailures, renderServiceStatusTable, serializeServiceStatus, } from './features/status.js';
8
- import { pickIcon } from './core/icons.js';
9
- import { applyColorModePreference } from './config/preferences.js';
10
- import { openDocsInBrowser } from './features/docs.js';
11
- import { runThemeCommand } from './features/theme.js';
12
- import { saveLanguagePreference, t, fmt } from './i18n/index.js';
13
- import { clearScreen, handleGracefulExit } from './core/ui.js';
14
- import { APP_INFO, URLS } from './config/data.js';
15
- import { runUpdateCheck } from './features/update.js';
16
- import { runStudentTimetableCommand } from './features/student-timetable.js';
17
- import { showAbout } from './features/about.js';
18
- const ACTION_ALIASES = {
19
- events: 'events',
20
- event: 'events',
21
- repair: 'repair',
22
- docs: 'docs',
23
- doc: 'docs',
24
- website: 'website',
25
- web: 'website',
26
- github: 'github',
27
- gh: 'github',
28
- roadmap: 'roadmap',
29
- board: 'roadmap',
30
- about: 'about',
31
- status: 'status',
32
- };
33
- const URL_ACTIONS = {
34
- repair: URLS.repair,
35
- website: URLS.homepage,
36
- github: URLS.github,
37
- roadmap: URLS.roadmap,
38
- };
39
- const KNOWN_FLAGS = new Set([
40
- '--help',
41
- '--version',
42
- '--open',
43
- '--json',
44
- '--plain',
45
- '--no-logo',
46
- '--watch',
47
- '--today',
48
- '--heatmap',
49
- '--week',
50
- '--month',
51
- '--one-shot',
52
- '--no-save',
53
- ]);
54
- const KNOWN_FLAG_PREFIXES = [
55
- '--interval=',
56
- '--timeout=',
57
- '--retries=',
58
- '--next=',
59
- '--search=',
60
- '--term=',
61
- '--output=',
62
- '--week-one=',
63
- ];
64
- const STATUS_WATCH_INTERVAL_MIN = 3;
65
- const STATUS_WATCH_INTERVAL_MAX = 300;
66
- const STATUS_TIMEOUT_MIN = 1000;
67
- const STATUS_TIMEOUT_MAX = 20000;
68
- const STATUS_RETRIES_MIN = 0;
69
- const STATUS_RETRIES_MAX = 5;
70
- function parseArgs(argv) {
71
- const flags = new Set();
72
- const positionals = [];
73
- for (const token of argv) {
74
- if (token.startsWith('--')) {
75
- flags.add(token);
76
- }
77
- else {
78
- positionals.push(token);
79
- }
80
- }
81
- return {
82
- ...(positionals[0] === undefined ? {} : { command: positionals[0].toLowerCase() }),
83
- args: positionals.slice(1),
84
- flags,
85
- };
2
+ if (process.argv.slice(2).includes('--plain')) {
3
+ delete process.env['FORCE_COLOR'];
4
+ process.env['NO_COLOR'] = '1';
86
5
  }
87
- function isTty(value) {
88
- return value === true;
89
- }
90
- function hasInteractiveTerminal() {
91
- return isTty(process.stdin.isTTY) && isTty(process.stdout.isTTY);
92
- }
93
- function getAllowedFlagsFor(command) {
94
- const allowed = new Set(['--help', '--plain']);
95
- if (!command) {
96
- allowed.add('--no-logo');
97
- allowed.add('--version');
98
- return allowed;
99
- }
100
- if (command === 'lang' || command === 'language')
101
- return allowed;
102
- if (command === 'theme')
103
- return allowed;
104
- if (command === 'schedule' || command === 'timetable') {
105
- allowed.add('--one-shot');
106
- allowed.add('--no-save');
107
- return allowed;
108
- }
109
- const action = ACTION_ALIASES[command];
110
- if (!action)
111
- return allowed;
112
- switch (action) {
113
- case 'events':
114
- allowed.add('--json');
115
- allowed.add('--today');
116
- allowed.add('--heatmap');
117
- allowed.add('--week');
118
- allowed.add('--month');
119
- return allowed;
120
- case 'status':
121
- allowed.add('--json');
122
- allowed.add('--watch');
123
- return allowed;
124
- case 'repair':
125
- case 'website':
126
- case 'github':
127
- case 'roadmap':
128
- case 'docs':
129
- allowed.add('--open');
130
- return allowed;
131
- case 'about':
132
- default:
133
- return allowed;
134
- }
135
- }
136
- function getAllowedFlagPrefixesFor(command) {
137
- if (!command)
138
- return [];
139
- if (command === 'schedule' || command === 'timetable') {
140
- return ['--term=', '--output=', '--week-one='];
141
- }
142
- const action = ACTION_ALIASES[command];
143
- if (action === 'events')
144
- return ['--next=', '--search='];
145
- if (action === 'status')
146
- return ['--interval=', '--timeout=', '--retries='];
147
- return [];
148
- }
149
- function validateFlags(command, flags) {
150
- const unknownFlag = Array.from(flags).find((flag) => {
151
- if (KNOWN_FLAGS.has(flag))
152
- return false;
153
- return !KNOWN_FLAG_PREFIXES.some((prefix) => flag.startsWith(prefix));
154
- });
155
- if (unknownFlag) {
156
- const trans0 = t();
157
- console.error(chalk.red(fmt(trans0.cli.unknownFlag, { flag: unknownFlag })));
158
- console.error(chalk.dim(trans0.cli.unknownFlagHint));
159
- process.exit(1);
160
- }
161
- const allowed = getAllowedFlagsFor(command);
162
- const allowedPrefixes = getAllowedFlagPrefixesFor(command);
163
- const disallowedFlag = Array.from(flags).find((flag) => {
164
- if (allowed.has(flag))
165
- return false;
166
- return !allowedPrefixes.some((prefix) => flag.startsWith(prefix));
167
- });
168
- if (disallowedFlag) {
169
- const trans1 = t();
170
- console.error(chalk.red(fmt(trans1.cli.invalidFlag, { flag: disallowedFlag })));
171
- console.error(chalk.dim(trans1.cli.invalidFlagHint));
172
- process.exit(1);
173
- }
174
- }
175
- function printHelp() {
176
- const trans = t();
177
- const c = trans.cli;
178
- console.log(chalk.bold('NBTCA Prompt'));
179
- console.log();
180
- console.log(c.usage);
181
- console.log(` nbtca ${c.interactive}`);
182
- console.log(` nbtca <command> [flags] ${c.runCommand}`);
183
- console.log();
184
- console.log(c.commands);
185
- console.log(` events ${trans.menu.eventsDesc}`);
186
- console.log(` docs ${trans.menu.docsDesc}`);
187
- console.log(` status ${trans.menu.statusDesc}`);
188
- console.log(' schedule <login|logout|status|terms|export>');
189
- console.log(` ${c.cmdSchedule}`);
190
- console.log(` website ${c.cmdWebsite}`);
191
- console.log(` github ${c.cmdGithub}`);
192
- console.log(` roadmap ${c.cmdRoadmap}`);
193
- console.log(` repair ${c.cmdRepair}`);
194
- console.log(` theme ${c.cmdTheme}`);
195
- console.log(` lang <zh|en> ${c.cmdLang}`);
196
- console.log(` update ${c.cmdUpdate}`);
197
- console.log();
198
- console.log(c.flags);
199
- console.log(` --version ${c.flagVersion}`);
200
- console.log(` --help ${c.flagHelp}`);
201
- console.log(` --open ${c.flagOpen}`);
202
- console.log(` --json ${c.flagJson}`);
203
- console.log(` --heatmap ${c.flagHeatmap}`);
204
- console.log(` --today ${c.flagToday}`);
205
- console.log(` --week ${c.flagWeek}`);
206
- console.log(` --month ${c.flagMonth}`);
207
- console.log(` --search=<q> ${c.flagSearch}`);
208
- console.log(` --next=<n> ${c.flagNext}`);
209
- console.log(` --watch ${c.flagWatch}`);
210
- console.log(` --interval=<s> ${c.flagInterval}`);
211
- console.log(` --timeout=<ms> ${c.flagTimeout}`);
212
- console.log(` --retries=<n> ${c.flagRetries}`);
213
- console.log(` --plain ${c.flagPlain}`);
214
- console.log(` --no-logo ${c.flagNoLogo}`);
215
- console.log(` --one-shot ${c.flagOneShot}`);
216
- console.log(` --no-save ${c.flagNoSave}`);
217
- console.log(` --term=<year:code> ${c.flagTerm}`);
218
- console.log(` --output=<path> ${c.flagOutput}`);
219
- console.log(` --week-one=<date> ${c.flagWeekOne}`);
220
- }
221
- async function runEventsCommand(flags) {
222
- if (flags.has('--heatmap')) {
223
- const buckets = await fetchHeatmapBuckets();
224
- if (flags.has('--json')) {
225
- process.stdout.write(JSON.stringify(buckets, null, 2) + '\n');
226
- }
227
- else {
228
- const useColor = !flags.has('--plain') && isTty(process.stdout.isTTY);
229
- console.log(renderHeatmap(buckets, new Date(), { color: useColor }));
230
- }
231
- return;
232
- }
233
- const { weekRange, monthRange } = await import('./features/calendar-query.js');
234
- const { fetchInRange } = await import('./features/calendar.js');
235
- const now0 = new Date();
236
- let events;
237
- if (flags.has('--week')) {
238
- const r = weekRange(now0);
239
- events = await fetchInRange(r.start, r.end);
240
- }
241
- else if (flags.has('--month')) {
242
- const r = monthRange(now0);
243
- events = await fetchInRange(r.start, r.end);
244
- }
245
- else {
246
- events = await fetchEvents();
247
- }
248
- const searchFlag = Array.from(flags).find((f) => f.startsWith('--search='));
249
- if (searchFlag) {
250
- const q = searchFlag.slice('--search='.length).toLowerCase();
251
- events = events.filter((e) => `${e.title} ${e.location}`.toLowerCase().includes(q));
252
- }
253
- if (flags.has('--today')) {
254
- const now = new Date();
255
- events = events.filter((e) => {
256
- const d = e.startDate;
257
- return (d.getFullYear() === now.getFullYear() &&
258
- d.getMonth() === now.getMonth() &&
259
- d.getDate() === now.getDate());
260
- });
261
- }
262
- const nextFlag = Array.from(flags).find((f) => f.startsWith('--next='));
263
- if (nextFlag) {
264
- const n = Number.parseInt(nextFlag.slice('--next='.length), 10);
265
- if (!Number.isInteger(n) || n < 1) {
266
- console.error(chalk.red(t().cli.invalidNext));
267
- process.exit(1);
268
- }
269
- events = events.slice(0, n);
270
- }
271
- if (flags.has('--json')) {
272
- process.stdout.write(JSON.stringify(serializeEvents(events), null, 2) + '\n');
273
- return;
274
- }
275
- const useColor = !flags.has('--plain') && isTty(process.stdout.isTTY);
276
- console.log(renderEventsTable(events, { color: useColor }));
277
- }
278
- async function runStatusCommand(flags) {
279
- const trans = t();
280
- const watch = flags.has('--watch');
281
- const intervalFlag = Array.from(flags).find((flag) => flag.startsWith('--interval='));
282
- const timeoutFlag = Array.from(flags).find((flag) => flag.startsWith('--timeout='));
283
- const retriesFlag = Array.from(flags).find((flag) => flag.startsWith('--retries='));
284
- const intervalSeconds = intervalFlag
285
- ? Number.parseInt(intervalFlag.slice('--interval='.length), 10)
286
- : 10;
287
- const timeoutMs = timeoutFlag
288
- ? Number.parseInt(timeoutFlag.slice('--timeout='.length), 10)
289
- : 6000;
290
- const retries = retriesFlag ? Number.parseInt(retriesFlag.slice('--retries='.length), 10) : 1;
291
- if (!watch && intervalFlag) {
292
- console.error(chalk.red(trans.status.intervalNeedsWatch));
293
- process.exit(1);
294
- }
295
- if (!Number.isInteger(timeoutMs) ||
296
- timeoutMs < STATUS_TIMEOUT_MIN ||
297
- timeoutMs > STATUS_TIMEOUT_MAX) {
298
- console.error(chalk.red(fmt(trans.status.invalidTimeout, { min: STATUS_TIMEOUT_MIN, max: STATUS_TIMEOUT_MAX })));
299
- process.exit(1);
300
- }
301
- if (!Number.isInteger(retries) || retries < STATUS_RETRIES_MIN || retries > STATUS_RETRIES_MAX) {
302
- console.error(chalk.red(fmt(trans.status.invalidRetries, { min: STATUS_RETRIES_MIN, max: STATUS_RETRIES_MAX })));
303
- process.exit(1);
304
- }
305
- if (watch && flags.has('--json')) {
306
- console.error(chalk.red(trans.status.watchJsonConflict));
307
- process.exit(1);
308
- }
309
- if (watch &&
310
- (!Number.isInteger(intervalSeconds) ||
311
- intervalSeconds < STATUS_WATCH_INTERVAL_MIN ||
312
- intervalSeconds > STATUS_WATCH_INTERVAL_MAX)) {
313
- console.error(chalk.red(fmt(trans.status.invalidInterval, {
314
- min: STATUS_WATCH_INTERVAL_MIN,
315
- max: STATUS_WATCH_INTERVAL_MAX,
316
- })));
317
- process.exit(1);
318
- }
319
- if (watch && !hasInteractiveTerminal()) {
320
- console.error(chalk.red(trans.status.watchRequiresTty));
321
- process.exit(1);
322
- }
323
- if (watch) {
324
- const stopController = new AbortController();
325
- const onSigint = () => {
326
- stopController.abort();
327
- };
328
- process.once('SIGINT', onSigint);
329
- console.log(chalk.dim(`${fmt(trans.status.watchStarted, { seconds: intervalSeconds })} | ${trans.status.watchHint}`));
330
- try {
331
- while (!stopController.signal.aborted) {
332
- const services = await checkServices({ timeoutMs, retries });
333
- const hasFailures = hasServiceFailures(services);
334
- const health = countServiceHealth(services);
335
- clearScreen();
336
- console.log(chalk.bold(`${trans.status.watchUpdated}: ${new Date().toLocaleString()}`));
337
- console.log(chalk.dim(`${trans.status.up}: ${health.up} | ${trans.status.down}: ${health.down} | ${trans.status.watchHint}`));
338
- console.log();
339
- const useColor = !flags.has('--plain') && isTty(process.stdout.isTTY);
340
- console.log(renderServiceStatusTable(services, { color: useColor }));
341
- if (hasFailures) {
342
- console.log(chalk.yellow(trans.status.summaryFail));
343
- }
344
- else {
345
- console.log(chalk.green(trans.status.summaryOk));
346
- }
347
- await new Promise((resolve) => {
348
- const stopWait = () => {
349
- clearTimeout(timer);
350
- stopController.signal.removeEventListener('abort', stopWait);
351
- resolve();
352
- };
353
- const timer = setTimeout(stopWait, intervalSeconds * 1000);
354
- stopController.signal.addEventListener('abort', stopWait, { once: true });
355
- if (stopController.signal.aborted)
356
- stopWait();
357
- });
358
- }
359
- }
360
- finally {
361
- process.removeListener('SIGINT', onSigint);
362
- }
363
- console.log();
364
- console.log(chalk.dim(t().common.goodbye));
365
- return true;
366
- }
367
- const services = await checkServices({ timeoutMs, retries });
368
- const hasFailures = hasServiceFailures(services);
369
- if (flags.has('--json')) {
370
- process.stdout.write(JSON.stringify(serializeServiceStatus(services), null, 2) + '\n');
371
- }
372
- else {
373
- const useColor = !flags.has('--plain') && isTty(process.stdout.isTTY);
374
- console.log(renderServiceStatusTable(services, { color: useColor }));
375
- if (hasFailures) {
376
- console.error(chalk.yellow(t().status.summaryFail));
377
- }
378
- else {
379
- console.log(chalk.green(t().status.summaryOk));
380
- }
381
- }
382
- return !hasFailures;
383
- }
384
- function maybeDisableColor(flags) {
385
- applyColorModePreference(flags.has('--plain'));
386
- }
387
- async function runCommandMode(argv) {
388
- const { command, args, flags } = parseArgs(argv);
389
- maybeDisableColor(flags);
390
- if (flags.has('--version') ||
391
- command === '--version' ||
392
- command === '-v' ||
393
- command === 'version') {
394
- console.log(APP_INFO.version);
395
- return;
396
- }
397
- if (flags.has('--help') || command === '--help' || command === '-h' || command === 'help') {
398
- printHelp();
399
- return;
400
- }
401
- validateFlags(command, flags);
402
- if (!command) {
403
- if (!hasInteractiveTerminal()) {
404
- const cliTrans = t().cli;
405
- console.error(chalk.red(cliTrans.requiresTty));
406
- console.error(chalk.dim(cliTrans.requiresTtyHint));
407
- process.exit(1);
408
- }
409
- await main({ skipLogo: flags.has('--no-logo') });
410
- return;
411
- }
412
- if (command === 'lang' || command === 'language') {
413
- const language = (args[0] ?? '').toLowerCase();
414
- if (language !== 'zh' && language !== 'en') {
415
- console.error(chalk.red(t().cli.invalidLang));
416
- process.exit(1);
417
- }
418
- const persisted = saveLanguagePreference(language);
419
- if (persisted) {
420
- console.log(chalk.green(`${pickIcon('✓', 'OK')}: ${t().language.changed}`));
421
- }
422
- else {
423
- console.log(chalk.yellow(`${pickIcon('⚠', 'WARN')}: ${t().language.changedSessionOnly}`));
424
- }
425
- return;
426
- }
427
- if (command === 'theme') {
428
- const result = runThemeCommand(args);
429
- if (!result.ok) {
430
- console.error(chalk.red(result.message));
431
- process.exit(1);
432
- }
433
- if (result.message) {
434
- console.log(chalk.green(`${pickIcon('✓', 'OK')}: ${result.message}`));
435
- }
436
- return;
437
- }
438
- if (command === 'update') {
439
- await runUpdateCheck();
440
- return;
441
- }
442
- if (command === 'schedule' || command === 'timetable') {
443
- if (args.length > 1) {
444
- console.error(chalk.red(t().timetable.invalidArguments));
445
- process.exitCode = 1;
446
- return;
447
- }
448
- const exitCode = await runStudentTimetableCommand(args[0], { flags });
449
- if (exitCode !== 0)
450
- process.exitCode = exitCode;
451
- return;
452
- }
453
- const action = ACTION_ALIASES[command];
454
- if (!action) {
455
- const cliT = t().cli;
456
- console.error(chalk.red(fmt(cliT.unknownCommand, { command })));
457
- console.error(chalk.dim(cliT.unknownCommandHint));
458
- process.exit(1);
459
- }
460
- if (action === 'events') {
461
- await runEventsCommand(flags);
462
- return;
463
- }
464
- if (action === 'status') {
465
- const ok = await runStatusCommand(flags);
466
- if (!ok && !flags.has('--json'))
467
- process.exit(1);
468
- return;
469
- }
470
- if (action === 'docs') {
471
- if (!hasInteractiveTerminal()) {
472
- if (flags.has('--open')) {
473
- await openDocsInBrowser();
474
- }
475
- else {
476
- process.stdout.write(URLS.docs + '\n');
477
- }
478
- }
479
- else {
480
- const { showDocsMenu } = await import('./features/docs.js');
481
- await showDocsMenu();
482
- }
483
- return;
484
- }
485
- if (action === 'about') {
486
- showAbout();
487
- return;
488
- }
489
- const mappedUrl = URL_ACTIONS[action];
490
- if (mappedUrl) {
491
- if (flags.has('--open')) {
492
- await open(mappedUrl);
493
- }
494
- else {
495
- process.stdout.write(mappedUrl + '\n');
496
- }
497
- return;
498
- }
499
- }
500
- runCommandMode(process.argv.slice(2)).catch(handleGracefulExit);
6
+ await import('./cli.js');
7
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nbtca/prompt",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -30,6 +30,7 @@
30
30
  "typecheck": "tsc --project tsconfig.typecheck.json",
31
31
  "test": "vitest run && npm run test:cli",
32
32
  "test:cli": "npm run build && bash scripts/test-cli.sh",
33
+ "precheck:package": "npm run build",
33
34
  "check:package": "node scripts/check-package.mjs",
34
35
  "check": "npm run format:check && npm run lint && npm run typecheck && npm test && npm run check:package && npm audit --audit-level=moderate",
35
36
  "prepublishOnly": "npm run check"