@tnotesjs/core 0.1.24 → 0.1.25

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 (73) hide show
  1. package/dist/{chunk-BSTQOJVE.js → chunk-4KG6RXFS.js} +113 -130
  2. package/dist/{chunk-O4DCXHOV.js → chunk-AGSL3VZE.js} +1 -4
  3. package/dist/cli/index.js +162 -173
  4. package/dist/index.js +1 -1
  5. package/dist/vitepress/config/index.js +6 -8
  6. package/package.json +4 -1
  7. package/types/config.ts +1 -1
  8. package/types/index.ts +1 -1
  9. package/types/note.ts +1 -1
  10. package/vitepress/assets/icons/index.ts +1 -1
  11. package/vitepress/components/BilibiliOutsidePlayer/BilibiliOutsidePlayer.vue +4 -0
  12. package/vitepress/components/CodeBlockFullscreen/CodeBlockFullscreen.vue +4 -0
  13. package/vitepress/components/CodeBlockFullscreen/index.ts +8 -0
  14. package/vitepress/components/CodeBlockFullscreen/styles.css +4 -0
  15. package/vitepress/components/Discussions/Discussions.vue +4 -0
  16. package/vitepress/components/EnWordList/EnWordList.vue +4 -0
  17. package/vitepress/components/EnWordList/RightClickMenu.vue +4 -0
  18. package/vitepress/components/Footprints/Footprints.vue +4 -0
  19. package/vitepress/components/Layout/AboutModal.vue +4 -0
  20. package/vitepress/components/Layout/AboutPanel.vue +4 -0
  21. package/vitepress/components/Layout/ContentCollapse.vue +4 -0
  22. package/vitepress/components/Layout/CustomSidebar.vue +4 -0
  23. package/vitepress/components/Layout/DocBeforeControls.vue +4 -0
  24. package/vitepress/components/Layout/DocFooter.vue +4 -0
  25. package/vitepress/components/Layout/ImagePreview.vue +4 -0
  26. package/vitepress/components/Layout/Layout.vue +4 -0
  27. package/vitepress/components/Layout/NavBarSettingsTrigger.vue +4 -0
  28. package/vitepress/components/Layout/NoteStatus.vue +4 -0
  29. package/vitepress/components/Layout/SidebarItems.vue +4 -0
  30. package/vitepress/components/Layout/SidebarNavBefore.vue +4 -0
  31. package/vitepress/components/Layout/SidebarResizeHandle.vue +5 -1
  32. package/vitepress/components/Layout/Swiper.vue +4 -0
  33. package/vitepress/components/Layout/ToggleFullContent.vue +4 -0
  34. package/vitepress/components/Layout/ToggleSidebar.vue +4 -1
  35. package/vitepress/components/Layout/composables/useCollapseControl.ts +6 -0
  36. package/vitepress/components/Layout/composables/useNoteConfig.ts +7 -0
  37. package/vitepress/components/Layout/composables/useNoteSave.ts +4 -0
  38. package/vitepress/components/Layout/composables/useNoteValidation.ts +8 -0
  39. package/vitepress/components/Layout/composables/useRedirect.ts +7 -0
  40. package/vitepress/components/Layout/composables/useRenameOverlay.ts +3 -0
  41. package/vitepress/components/Layout/composables/useRenameRedirect.ts +3 -0
  42. package/vitepress/components/Layout/composables/useSidebarLayout.ts +6 -0
  43. package/vitepress/components/Layout/composables/useVSCodeIntegration.ts +6 -0
  44. package/vitepress/components/Layout/homeReadme.data.ts +3 -1
  45. package/vitepress/components/LoadingPage/LoadingPage.vue +4 -0
  46. package/vitepress/components/MarkMap/MarkMap.vue +4 -0
  47. package/vitepress/components/Mermaid/Mermaid.vue +6 -0
  48. package/vitepress/components/NotesTable/NotesTable.vue +4 -0
  49. package/vitepress/components/Settings/Settings.vue +6 -0
  50. package/vitepress/components/Settings/SettingsDialog.vue +6 -0
  51. package/vitepress/components/Settings/composables/useSettingsDialog.ts +3 -0
  52. package/vitepress/components/SidebarCard/MindMapView.vue +4 -0
  53. package/vitepress/components/SidebarCard/NotesTrendChart.vue +4 -0
  54. package/vitepress/components/SidebarCard/SidebarCard.vue +4 -0
  55. package/vitepress/components/Tooltip/Tooltip.vue +6 -0
  56. package/vitepress/components/constants.ts +3 -0
  57. package/vitepress/components/notesConfig.data.ts +7 -1
  58. package/vitepress/components/sidebar.data.ts +1 -1
  59. package/vitepress/components/tnotes-config.data.ts +13 -8
  60. package/vitepress/components/utils.ts +6 -0
  61. package/vitepress/config/index.ts +5 -13
  62. package/vitepress/configs/constants.ts +1 -0
  63. package/vitepress/configs/head.config.ts +1 -0
  64. package/vitepress/configs/index.ts +1 -0
  65. package/vitepress/configs/markdown.config.ts +1 -0
  66. package/vitepress/configs/theme.config.ts +1 -0
  67. package/vitepress/plugins/buildProgressPlugin.ts +1 -1
  68. package/vitepress/plugins/fileWatcherBridgePlugin.ts +2 -1
  69. package/vitepress/plugins/getNoteByConfigIdPlugin.ts +2 -1
  70. package/vitepress/plugins/renameNotePlugin.ts +2 -1
  71. package/vitepress/plugins/sidebarStructurePlugin.ts +3 -2
  72. package/vitepress/plugins/updateConfigPlugin.ts +2 -1
  73. package/vitepress/theme/index.ts +1 -4
package/dist/cli/index.js CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  COMMAND_NAMES,
6
6
  COMMAND_OPTIONS,
7
7
  FileWatcherService,
8
+ GitManager,
8
9
  GitService,
9
10
  NoteIndexCache,
10
11
  NoteManager,
@@ -22,20 +23,18 @@ import {
22
23
  parseArgs,
23
24
  parseReadmeCompletedNotes,
24
25
  runCommand
25
- } from "../chunk-BSTQOJVE.js";
26
+ } from "../chunk-4KG6RXFS.js";
26
27
  import {
27
28
  ConfigManager
28
- } from "../chunk-O4DCXHOV.js";
29
+ } from "../chunk-AGSL3VZE.js";
29
30
 
30
31
  // commands/update/UpdateCommand.ts
31
32
  import { existsSync, readFileSync, writeFileSync } from "fs";
32
33
  import { resolve } from "path";
33
34
  var UpdateCommand = class extends BaseCommand {
34
- readmeService;
35
- noteService;
36
- quiet = false;
37
35
  constructor() {
38
36
  super("update");
37
+ this.quiet = false;
39
38
  this.readmeService = ReadmeService.getInstance();
40
39
  this.noteService = NoteService.getInstance();
41
40
  }
@@ -121,158 +120,18 @@ var UpdateCommand = class extends BaseCommand {
121
120
  }
122
121
  };
123
122
 
124
- // commands/update-completed-count/UpdateCompletedCountCommand.ts
125
- import { execSync } from "child_process";
126
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
127
- var UpdateCompletedCountCommand = class extends BaseCommand {
128
- constructor() {
129
- super("update-completed-count");
130
- }
131
- async run() {
132
- await this.updateCurrentRepo();
133
- }
134
- /**
135
- * 更新当前知识库
136
- */
137
- async updateCurrentRepo() {
138
- const startTime = Date.now();
139
- try {
140
- const configContent = readFileSync2(ROOT_CONFIG_PATH, "utf-8");
141
- const config = JSON.parse(configContent);
142
- this.logger.info("\u5F00\u59CB\u66F4\u65B0\u5B8C\u6210\u7B14\u8BB0\u6570\u91CF\u5386\u53F2\u8BB0\u5F55...");
143
- const completedNotesCountHistory = await this.getCompletedNotesCountHistory(
144
- config.root_item.created_at ?? Date.now()
145
- );
146
- config.root_item = {
147
- ...config.root_item,
148
- completed_notes_count: completedNotesCountHistory
149
- };
150
- writeFileSync2(ROOT_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
151
- const duration = Date.now() - startTime;
152
- const monthKeys = Object.keys(completedNotesCountHistory);
153
- const currentKey = monthKeys[monthKeys.length - 1];
154
- const currentCount = completedNotesCountHistory[currentKey] || 0;
155
- this.logger.success(
156
- `\u5386\u53F2\u6570\u636E\u66F4\u65B0\u5B8C\u6210: \u5171 ${monthKeys.length} \u4E2A\u6708, \u5F53\u524D ${currentKey} \u6708\u5B8C\u6210 ${currentCount} \u7BC7\u7B14\u8BB0 (${duration}ms)`
157
- );
158
- } catch (error) {
159
- this.logger.error(
160
- `\u66F4\u65B0\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
161
- );
162
- throw error;
163
- }
164
- }
165
- /**
166
- * 获取历史每个月的 completed_notes_count(最近12个月)
167
- *
168
- * 逻辑:
169
- * 1. 计算最近12个月的范围(当前月份往前推11个月)
170
- * 2. 遍历这12个月,从 Git 历史中读取 README.md
171
- * 3. 解析 README.md 获取完成笔记数量
172
- * 4. 如果知识库创建时间在这12个月内,之前的月份补0
173
- * 5. 返回对象 { '25.01': 0, '25.02': 1, ..., '25.12': 15 }
174
- */
175
- async getCompletedNotesCountHistory(createdAt) {
176
- try {
177
- const now = /* @__PURE__ */ new Date();
178
- const currentYear = now.getFullYear();
179
- const currentMonth = now.getMonth();
180
- let firstYear = currentYear;
181
- let firstMonth = currentMonth - 11;
182
- if (firstMonth < 0) {
183
- firstYear = currentYear - 1;
184
- firstMonth = 12 + firstMonth;
185
- }
186
- const createdDate = new Date(createdAt);
187
- const createdYear = createdDate.getFullYear();
188
- const createdMonth = createdDate.getMonth();
189
- const result = {};
190
- let prevCount = 0;
191
- for (let i = 0; i < 12; i++) {
192
- const targetYear = firstYear + Math.floor((firstMonth + i) / 12);
193
- const targetMonth = (firstMonth + i) % 12;
194
- const yearShort = String(targetYear).slice(-2);
195
- const monthStr = String(targetMonth + 1).padStart(2, "0");
196
- const key = `${yearShort}.${monthStr}`;
197
- const isBeforeCreation = targetYear < createdYear || targetYear === createdYear && targetMonth < createdMonth;
198
- if (isBeforeCreation) {
199
- result[key] = 0;
200
- prevCount = 0;
201
- this.logger.info(`\u2713 ${key}: 0 \u7BC7\uFF08\u65E9\u4E8E\u521B\u5EFA\u65F6\u95F4\uFF09`);
202
- } else {
203
- try {
204
- const count = await this.getMonthCompletedCount(
205
- targetYear,
206
- targetMonth,
207
- prevCount
208
- );
209
- result[key] = count;
210
- prevCount = count;
211
- this.logger.info(`\u2713 ${key}: ${count} \u7BC7`);
212
- } catch (error) {
213
- result[key] = prevCount;
214
- this.logger.warn(`${key}: \u65E0\u6570\u636E\uFF0C\u4F7F\u7528 ${prevCount}\uFF08\u4E0A\u6708\u503C\uFF09`);
215
- }
216
- }
217
- }
218
- return result;
219
- } catch (error) {
220
- this.logger.error(
221
- `\u83B7\u53D6\u5386\u53F2\u6570\u636E\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
222
- );
223
- return {};
224
- }
225
- }
226
- /**
227
- * 获取指定月份的完成笔记数量
228
- * @param year - 年份
229
- * @param month - 月份 (0-11)
230
- * @param fallbackCount - 回退值(如果该月没有数据)
231
- * @returns 完成笔记数量
232
- */
233
- async getMonthCompletedCount(year, month, fallbackCount = 0) {
234
- const lastDayOfMonth = new Date(year, month + 1, 0, 23, 59, 59);
235
- const yearStr = lastDayOfMonth.getFullYear();
236
- const monthStr = String(lastDayOfMonth.getMonth() + 1).padStart(2, "0");
237
- const dayStr = String(lastDayOfMonth.getDate()).padStart(2, "0");
238
- const untilDate = `${yearStr}-${monthStr}-${dayStr} 23:59:59 +0800`;
239
- const commitHash = execSync(
240
- `git log --until="${untilDate}" --format=%H -1 -- README.md`,
241
- {
242
- cwd: ROOT_DIR_PATH,
243
- encoding: "utf-8"
244
- }
245
- ).trim();
246
- if (!commitHash) {
247
- return fallbackCount;
248
- }
249
- let readmeContent;
250
- try {
251
- readmeContent = execSync(`git show ${commitHash}:README.md`, {
252
- cwd: ROOT_DIR_PATH,
253
- encoding: "utf-8"
254
- });
255
- } catch (error) {
256
- return fallbackCount;
257
- }
258
- const { completedCount } = parseReadmeCompletedNotes(readmeContent);
259
- return completedCount;
260
- }
261
- };
262
-
263
123
  // commands/git/PushCommand.ts
264
124
  var PushCommand = class extends BaseCommand {
265
- gitService;
266
- timestampService;
267
125
  constructor() {
268
126
  super("push");
127
+ this.gitManager = new GitManager(ROOT_DIR_PATH);
269
128
  this.gitService = new GitService();
270
129
  this.timestampService = new TimestampService();
271
130
  }
272
131
  async run() {
273
132
  try {
274
133
  this.logger.info("\u68C0\u67E5\u662F\u5426\u6709\u66F4\u6539...");
275
- const status = await this.gitService.getStatus();
134
+ const status = await this.gitManager.getStatus();
276
135
  const hasPendingCommits = (status.ahead ?? 0) > 0;
277
136
  if (!status.hasChanges && !hasPendingCommits) {
278
137
  this.logger.info("\u6CA1\u6709\u66F4\u6539\u9700\u8981\u63A8\u9001");
@@ -317,7 +176,6 @@ var PushCommand = class extends BaseCommand {
317
176
 
318
177
  // commands/git/PullCommand.ts
319
178
  var PullCommand = class extends BaseCommand {
320
- gitService;
321
179
  constructor() {
322
180
  super("pull");
323
181
  this.gitService = new GitService();
@@ -331,7 +189,6 @@ var PullCommand = class extends BaseCommand {
331
189
 
332
190
  // commands/build/BuildCommand.ts
333
191
  var BuildCommand = class extends BaseCommand {
334
- vitepressService;
335
192
  constructor() {
336
193
  super("build");
337
194
  this.vitepressService = new VitepressService();
@@ -345,7 +202,6 @@ var BuildCommand = class extends BaseCommand {
345
202
 
346
203
  // commands/build/PreviewCommand.ts
347
204
  var PreviewCommand = class extends BaseCommand {
348
- vitepressService;
349
205
  constructor() {
350
206
  super("preview");
351
207
  this.vitepressService = new VitepressService();
@@ -363,23 +219,20 @@ var PreviewCommand = class extends BaseCommand {
363
219
 
364
220
  // commands/dev/DevCommand.ts
365
221
  var DevCommand = class extends BaseCommand {
366
- fileWatcherService;
367
- vitepressService;
368
- noteManager;
369
- noteIndexCache;
370
- configManager;
371
222
  constructor() {
372
223
  super("dev");
224
+ this.configManager = ConfigManager.getInstance();
373
225
  this.fileWatcherService = new FileWatcherService();
374
- this.vitepressService = new VitepressService();
375
- this.noteManager = NoteManager.getInstance();
376
226
  this.noteIndexCache = NoteIndexCache.getInstance();
377
- this.configManager = ConfigManager.getInstance();
227
+ this.noteManager = NoteManager.getInstance();
228
+ this.readmeService = ReadmeService.getInstance();
229
+ this.vitepressService = new VitepressService();
378
230
  }
379
231
  async run() {
380
232
  const notes = this.noteManager.scanNotes();
381
233
  this.logger.info(`\u626B\u63CF\u5230 ${notes.length} \u7BC7\u7B14\u8BB0`);
382
234
  this.noteIndexCache.initialize(notes);
235
+ await this.readmeService.regenerateSidebar(notes);
383
236
  const result = await this.vitepressService.startServer();
384
237
  if (result) {
385
238
  const versionInfo = result.version ? `\uFF08v${result.version}\uFF09` : "";
@@ -390,10 +243,10 @@ var DevCommand = class extends BaseCommand {
390
243
  this.fileWatcherService.start();
391
244
  const watcherElapsed = Date.now() - watcherStart;
392
245
  this.logger.success(`\u6587\u4EF6\u76D1\u542C\u670D\u52A1\u5DF2\u5C31\u7EEA\uFF0C\u8017\u65F6\uFF1A${watcherElapsed} ms`);
393
- const port = this.configManager.get("port") || VitepressService.DEFAULT_DEV_PORT;
394
- const repoName = this.configManager.get("repoName");
246
+ const port2 = this.configManager.get("port") || VitepressService.DEFAULT_DEV_PORT;
247
+ const repoName2 = this.configManager.get("repoName");
395
248
  this.logger.info(
396
- `\u672C\u5730\u5F00\u53D1\u670D\u52A1\u5730\u5740\uFF1Ahttp://localhost:${port}/${repoName}/`
249
+ `\u672C\u5730\u5F00\u53D1\u670D\u52A1\u5730\u5740\uFF1Ahttp://localhost:${port2}/${repoName2}/`
397
250
  );
398
251
  } else {
399
252
  this.logger.error("\u542F\u52A8\u670D\u52A1\u5668\u5931\u8D25");
@@ -403,7 +256,6 @@ var DevCommand = class extends BaseCommand {
403
256
 
404
257
  // commands/maintenance/FixTimestampsCommand.ts
405
258
  var FixTimestampsCommand = class extends BaseCommand {
406
- timestampService;
407
259
  constructor() {
408
260
  super("fix-timestamps");
409
261
  this.timestampService = new TimestampService();
@@ -509,8 +361,6 @@ var HelpCommand = class extends BaseCommand {
509
361
  import { createInterface } from "readline";
510
362
  import { v4 as uuidv4 } from "uuid";
511
363
  var CreateNoteCommand = class extends BaseCommand {
512
- noteService;
513
- readmeService;
514
364
  constructor() {
515
365
  super("create-notes");
516
366
  this.noteService = NoteService.getInstance();
@@ -624,20 +474,159 @@ var CreateNoteCommand = class extends BaseCommand {
624
474
  }
625
475
  };
626
476
 
477
+ // commands/update-completed-count/UpdateCompletedCountCommand.ts
478
+ import { execSync } from "child_process";
479
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
480
+ var UpdateCompletedCountCommand = class extends BaseCommand {
481
+ constructor() {
482
+ super("update-completed-count");
483
+ }
484
+ async run() {
485
+ await this.updateCurrentRepo();
486
+ }
487
+ /**
488
+ * 更新当前知识库
489
+ */
490
+ async updateCurrentRepo() {
491
+ const startTime = Date.now();
492
+ try {
493
+ const configContent = readFileSync2(ROOT_CONFIG_PATH, "utf-8");
494
+ const config = JSON.parse(configContent);
495
+ this.logger.info("\u5F00\u59CB\u66F4\u65B0\u5B8C\u6210\u7B14\u8BB0\u6570\u91CF\u5386\u53F2\u8BB0\u5F55...");
496
+ const completedNotesCountHistory = await this.getCompletedNotesCountHistory(
497
+ config.root_item.created_at ?? Date.now()
498
+ );
499
+ config.root_item = {
500
+ ...config.root_item,
501
+ completed_notes_count: completedNotesCountHistory
502
+ };
503
+ writeFileSync2(ROOT_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
504
+ const duration = Date.now() - startTime;
505
+ const monthKeys = Object.keys(completedNotesCountHistory);
506
+ const currentKey = monthKeys[monthKeys.length - 1];
507
+ const currentCount = completedNotesCountHistory[currentKey] || 0;
508
+ this.logger.success(
509
+ `\u5386\u53F2\u6570\u636E\u66F4\u65B0\u5B8C\u6210: \u5171 ${monthKeys.length} \u4E2A\u6708, \u5F53\u524D ${currentKey} \u6708\u5B8C\u6210 ${currentCount} \u7BC7\u7B14\u8BB0 (${duration}ms)`
510
+ );
511
+ } catch (error) {
512
+ this.logger.error(
513
+ `\u66F4\u65B0\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
514
+ );
515
+ throw error;
516
+ }
517
+ }
518
+ /**
519
+ * 获取历史每个月的 completed_notes_count(最近12个月)
520
+ *
521
+ * 逻辑:
522
+ * 1. 计算最近12个月的范围(当前月份往前推11个月)
523
+ * 2. 遍历这12个月,从 Git 历史中读取 README.md
524
+ * 3. 解析 README.md 获取完成笔记数量
525
+ * 4. 如果知识库创建时间在这12个月内,之前的月份补0
526
+ * 5. 返回对象 { '25.01': 0, '25.02': 1, ..., '25.12': 15 }
527
+ */
528
+ async getCompletedNotesCountHistory(createdAt) {
529
+ try {
530
+ const now = /* @__PURE__ */ new Date();
531
+ const currentYear = now.getFullYear();
532
+ const currentMonth = now.getMonth();
533
+ let firstYear = currentYear;
534
+ let firstMonth = currentMonth - 11;
535
+ if (firstMonth < 0) {
536
+ firstYear = currentYear - 1;
537
+ firstMonth = 12 + firstMonth;
538
+ }
539
+ const createdDate = new Date(createdAt);
540
+ const createdYear = createdDate.getFullYear();
541
+ const createdMonth = createdDate.getMonth();
542
+ const result = {};
543
+ let prevCount = 0;
544
+ for (let i = 0; i < 12; i++) {
545
+ const targetYear = firstYear + Math.floor((firstMonth + i) / 12);
546
+ const targetMonth = (firstMonth + i) % 12;
547
+ const yearShort = String(targetYear).slice(-2);
548
+ const monthStr = String(targetMonth + 1).padStart(2, "0");
549
+ const key = `${yearShort}.${monthStr}`;
550
+ const isBeforeCreation = targetYear < createdYear || targetYear === createdYear && targetMonth < createdMonth;
551
+ if (isBeforeCreation) {
552
+ result[key] = 0;
553
+ prevCount = 0;
554
+ this.logger.info(`\u2713 ${key}: 0 \u7BC7\uFF08\u65E9\u4E8E\u521B\u5EFA\u65F6\u95F4\uFF09`);
555
+ } else {
556
+ try {
557
+ const count = await this.getMonthCompletedCount(
558
+ targetYear,
559
+ targetMonth,
560
+ prevCount
561
+ );
562
+ result[key] = count;
563
+ prevCount = count;
564
+ this.logger.info(`\u2713 ${key}: ${count} \u7BC7`);
565
+ } catch (error) {
566
+ result[key] = prevCount;
567
+ this.logger.warn(`${key}: \u65E0\u6570\u636E\uFF0C\u4F7F\u7528 ${prevCount}\uFF08\u4E0A\u6708\u503C\uFF09`);
568
+ }
569
+ }
570
+ }
571
+ return result;
572
+ } catch (error) {
573
+ this.logger.error(
574
+ `\u83B7\u53D6\u5386\u53F2\u6570\u636E\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
575
+ );
576
+ return {};
577
+ }
578
+ }
579
+ /**
580
+ * 获取指定月份的完成笔记数量
581
+ * @param year - 年份
582
+ * @param month - 月份 (0-11)
583
+ * @param fallbackCount - 回退值(如果该月没有数据)
584
+ * @returns 完成笔记数量
585
+ */
586
+ async getMonthCompletedCount(year, month, fallbackCount = 0) {
587
+ const lastDayOfMonth = new Date(year, month + 1, 0, 23, 59, 59);
588
+ const yearStr = lastDayOfMonth.getFullYear();
589
+ const monthStr = String(lastDayOfMonth.getMonth() + 1).padStart(2, "0");
590
+ const dayStr = String(lastDayOfMonth.getDate()).padStart(2, "0");
591
+ const untilDate = `${yearStr}-${monthStr}-${dayStr} 23:59:59 +0800`;
592
+ const commitHash = execSync(
593
+ `git log --until="${untilDate}" --format=%H -1 -- README.md`,
594
+ {
595
+ cwd: ROOT_DIR_PATH,
596
+ encoding: "utf-8"
597
+ }
598
+ ).trim();
599
+ if (!commitHash) {
600
+ return fallbackCount;
601
+ }
602
+ let readmeContent;
603
+ try {
604
+ readmeContent = execSync(`git show ${commitHash}:README.md`, {
605
+ cwd: ROOT_DIR_PATH,
606
+ encoding: "utf-8"
607
+ });
608
+ } catch (error) {
609
+ return fallbackCount;
610
+ }
611
+ const { completedCount } = parseReadmeCompletedNotes(readmeContent);
612
+ return completedCount;
613
+ }
614
+ };
615
+
627
616
  // commands/registry.ts
628
617
  var commandFactories = {
629
- dev: () => new DevCommand(),
630
- build: () => new BuildCommand(),
631
- preview: () => new PreviewCommand(),
632
- update: () => new UpdateCommand(),
633
- "update-completed-count": () => new UpdateCompletedCountCommand(),
634
- push: () => new PushCommand(),
635
- pull: () => new PullCommand(),
618
+ "build": () => new BuildCommand(),
636
619
  "create-notes": () => new CreateNoteCommand(),
620
+ "dev": () => new DevCommand(),
637
621
  "fix-timestamps": () => new FixTimestampsCommand(),
638
- "update-note-config": () => new UpdateNoteConfigCommand(),
622
+ "help": () => new HelpCommand(),
623
+ "preview": () => new PreviewCommand(),
624
+ "pull": () => new PullCommand(),
625
+ "push": () => new PushCommand(),
639
626
  "rename-note": () => new RenameNoteCommand(),
640
- help: () => new HelpCommand()
627
+ "update-completed-count": () => new UpdateCompletedCountCommand(),
628
+ "update-note-config": () => new UpdateNoteConfigCommand(),
629
+ "update": () => new UpdateCommand()
641
630
  };
642
631
  var commandCache = /* @__PURE__ */ new Map();
643
632
  function getCommand(name) {
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ConfigManager,
3
3
  getConfigManager
4
- } from "./chunk-O4DCXHOV.js";
4
+ } from "./chunk-AGSL3VZE.js";
5
5
  export {
6
6
  ConfigManager,
7
7
  getConfigManager
@@ -7,8 +7,10 @@ import {
7
7
  UpdateNoteConfigCommand,
8
8
  generateAnchor,
9
9
  logger
10
- } from "../../chunk-BSTQOJVE.js";
11
- import "../../chunk-O4DCXHOV.js";
10
+ } from "../../chunk-4KG6RXFS.js";
11
+ import {
12
+ ConfigManager
13
+ } from "../../chunk-AGSL3VZE.js";
12
14
 
13
15
  // vitepress/config/index.ts
14
16
  import fs2 from "fs";
@@ -1066,14 +1068,10 @@ function updateConfigPlugin() {
1066
1068
  }
1067
1069
 
1068
1070
  // vitepress/config/index.ts
1069
- function loadTNotesConfig(rootPath) {
1070
- const configPath = path2.resolve(rootPath, ".tnotes.json");
1071
- const configContent = fs2.readFileSync(configPath, "utf-8");
1072
- return JSON.parse(configContent);
1073
- }
1074
1071
  function defineNotesConfig(overrides = {}) {
1075
1072
  const rootPath = process.cwd();
1076
- const config = loadTNotesConfig(rootPath);
1073
+ ConfigManager.init({ rootPath });
1074
+ const config = ConfigManager.getInstance().getAll();
1077
1075
  const { repoName } = config;
1078
1076
  const IGNORE_LIST = getIgnoreList(config);
1079
1077
  const GITHUB_PAGE_URL = getGithubPageUrl(config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tnotesjs/core",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "description": "TNotes 知识库核心框架 —— 基于 VitePress 的笔记管理系统",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.17.1",
@@ -32,6 +32,8 @@
32
32
  "typecheck": "vue-tsc --noEmit -p tsconfig.build.json",
33
33
  "dev": "tsup --watch",
34
34
  "release": "node scripts/release.mjs",
35
+ "test": "vitest run",
36
+ "test:watch": "vitest",
35
37
  "lint": "eslint . --max-warnings=0",
36
38
  "lint:fix": "eslint . --fix"
37
39
  },
@@ -69,6 +71,7 @@
69
71
  "tsup": "^8.5.1",
70
72
  "typescript": "^5.9.3",
71
73
  "typescript-eslint": "^8.59.1",
74
+ "vitest": "^4.1.6",
72
75
  "vue-eslint-parser": "^10.4.0",
73
76
  "vue-tsc": "^3.2.7"
74
77
  },
package/types/config.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * .vitepress/tnotes/types/config.ts
2
+ * types/config.ts
3
3
  *
4
4
  * 配置相关类型定义
5
5
  */
package/types/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * .vitepress/tnotes/types/index.ts
2
+ * types/index.ts
3
3
  *
4
4
  * 类型定义统一导出
5
5
  */
package/types/note.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * .vitepress/tnotes/types/note.ts
2
+ * types/note.ts
3
3
  *
4
4
  * 笔记相关类型定义
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * .vitepress/tnotes/vitepress/assets/icons/index.ts
2
+ * vitepress/assets/icons/index.ts
3
3
  *
4
4
  * get icons:
5
5
  * https://iconify.design/
@@ -1,3 +1,7 @@
1
+ <!--
2
+ vitepress/components/BilibiliOutsidePlayer/BilibiliOutsidePlayer.vue
3
+ -->
4
+
1
5
  <template>
2
6
  <iframe
3
7
  style="width: 100%; aspect-ratio: 16/9; margin: 1rem 0"
@@ -1,3 +1,7 @@
1
+ <!--
2
+ vitepress/components/CodeBlockFullscreen/CodeBlockFullscreen.vue
3
+ -->
4
+
1
5
  <template>
2
6
  <Teleport to="body">
3
7
  <Transition name="fullscreen-fade">
@@ -1,3 +1,11 @@
1
+ /**
2
+ * vitepress/components/CodeBlockFullscreen/index.ts
3
+ *
4
+ * 代码块全屏功能的组合式函数
5
+ * 负责在代码块上添加全屏和复制按钮,处理相关事件
6
+ * 使用 Vue 3 的 Composition API 实现,增强用户体验
7
+ */
8
+
1
9
  import { createApp, onMounted, onUnmounted } from 'vue'
2
10
 
3
11
  import CodeBlockFullscreen from './CodeBlockFullscreen.vue'
@@ -1,3 +1,7 @@
1
+ /*
2
+ vitepress/components/CodeBlockFullscreen/styles.css
3
+ */
4
+
1
5
  /* 代码块操作按钮样式 */
2
6
  div[class*='language-'] {
3
7
  position: relative;
@@ -1,3 +1,7 @@
1
+ <!--
2
+ vitepress/components/Discussions/Discussions.vue
3
+ -->
4
+
1
5
  <script setup lang="ts">
2
6
  import { useData } from 'vitepress/client'
3
7
  import { onMounted, onUnmounted, watch, computed } from 'vue'
@@ -1,3 +1,7 @@
1
+ <!--
2
+ vitepress/components/EnWordList/EnWordList.vue
3
+ -->
4
+
1
5
  <script setup>
2
6
  import { marked } from 'marked'
3
7
  import { computed, ref, onMounted, onUnmounted, nextTick } from 'vue'
@@ -1,3 +1,7 @@
1
+ <!--
2
+ vitepress/components/EnWordList/RightClickMenu.vue
3
+ -->
4
+
1
5
  <template>
2
6
  <div
3
7
  v-if="show"
@@ -1,3 +1,7 @@
1
+ <!--
2
+ vitepress/components/Footprints/Footprints.vue
3
+ -->
4
+
1
5
  <script setup>
2
6
  import { ref, onMounted, onBeforeUnmount, computed, nextTick } from 'vue'
3
7
 
@@ -1,3 +1,7 @@
1
+ <!--
2
+ vitepress/components/Layout/AboutModal.vue
3
+ -->
4
+
1
5
  <template>
2
6
  <!-- 使用 teleport 将 modal 放到 body 之下(避免父容器样式影响) -->
3
7
  <teleport to="body">
@@ -1,3 +1,7 @@
1
+ <!--
2
+ vitepress/components/Layout/AboutPanel.vue
3
+ -->
4
+
1
5
  <template>
2
6
  <div class="timeModalContent">
3
7
  <!-- 笔记编号(仅笔记页显示) -->
@@ -1,3 +1,7 @@
1
+ <!--
2
+ vitepress/components/Layout/ContentCollapse.vue
3
+ -->
4
+
1
5
  <template>
2
6
  <div></div>
3
7
  </template>
@@ -1,3 +1,7 @@
1
+ <!--
2
+ vitepress/components/Layout/CustomSidebar.vue
3
+ -->
4
+
1
5
  <template>
2
6
  <div class="custom-sidebar-wrapper">
3
7
  <nav class="nav" ref="navRef">
@@ -1,3 +1,7 @@
1
+ <!--
2
+ vitepress/components/Layout/DocBeforeControls.vue
3
+ -->
4
+
1
5
  <template>
2
6
  <div class="docBeforeContainer">
3
7
  <div class="leftArea">
@@ -1,3 +1,7 @@
1
+ <!--
2
+ vitepress/components/Layout/DocFooter.vue
3
+ -->
4
+
1
5
  <template>
2
6
  <nav class="custom-doc-footer" v-if="prev || next">
3
7
  <div class="container">
@@ -1,3 +1,7 @@
1
+ <!--
2
+ vitepress/components/Layout/ImagePreview.vue
3
+ -->
4
+
1
5
  <template>
2
6
  <!-- #region img preview -->
3
7
  <div