@tnotesjs/core 0.1.0 → 0.1.1

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.

Potentially problematic release.


This version of @tnotesjs/core might be problematic. Click here for more details.

package/dist/cli/index.js CHANGED
@@ -1,44 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- CONSTANTS,
4
3
  ConfigManager,
5
- EN_WORDS_DIR,
6
- EOL,
7
- Logger,
8
- NOTES_DIR_PATH,
9
- NOTES_PATH,
10
- NoteManager,
11
- REPO_NOTES_URL,
12
- ROOT_CONFIG_PATH,
13
- ROOT_DIR_PATH,
14
- ROOT_README_PATH,
15
- TNOTES_BASE_DIR,
16
- TNOTES_CORE_DIR,
17
- VP_SIDEBAR_PATH,
18
- buildNoteLineMarkdown,
19
- createAddNumberToTitle,
20
- createError,
21
- createLogger,
22
- ensureDirectory,
23
- genHierarchicalSidebar,
24
- generateToc,
25
- getChangedIds,
26
- getTargetDirs,
27
- handleError,
28
- isPortInUse,
29
- killPortProcess,
30
- logger,
31
- parseArgs,
32
- parseNoteLine,
33
- parseReadmeCompletedNotes,
34
- processEmptyLines,
35
- pullAllRepos,
36
- pushAllRepos,
37
- runCommand,
38
- syncAllRepos,
39
- validateNoteTitle,
40
- waitForPort
41
- } from "../chunk-K3X5OP3N.js";
4
+ getConfigManager
5
+ } from "../chunk-NYLJBCWL.js";
42
6
 
43
7
  // commands/models.ts
44
8
  var COMMAND_NAMES = {
@@ -67,7 +31,7 @@ var COMMAND_DESCRIPTIONS = {
67
31
  [COMMAND_NAMES.PUSH]: "\u5C06\u77E5\u8BC6\u5E93\u63A8\u9001\u5230 GitHub (\u4F7F\u7528 --all \u63A8\u9001\u6240\u6709\u77E5\u8BC6\u5E93)",
68
32
  [COMMAND_NAMES.PULL]: "\u5C06 GitHub \u7684\u77E5\u8BC6\u5E93\u62C9\u4E0B\u6765 (\u4F7F\u7528 --all \u62C9\u53D6\u6240\u6709\u77E5\u8BC6\u5E93)",
69
33
  [COMMAND_NAMES.SYNC]: "\u540C\u6B65\u672C\u5730\u548C\u8FDC\u7A0B\u7684\u77E5\u8BC6\u5E93\u72B6\u6001 (\u4F7F\u7528 --all \u540C\u6B65\u6240\u6709\u77E5\u8BC6\u5E93)",
70
- [COMMAND_NAMES.SYNC_CORE]: "\u540C\u6B65\u6240\u6709\u5144\u5F1F\u77E5\u8BC6\u5E93\u7684 TNotes.core \u5230\u6700\u65B0\u7248\u672C",
34
+ [COMMAND_NAMES.SYNC_CORE]: "\u540C\u6B65\u6240\u6709\u5144\u5F1F\u77E5\u8BC6\u5E93\u7684 tnotesjs/core \u5230\u6700\u65B0\u7248\u672C",
71
35
  [COMMAND_NAMES.FIX_TIMESTAMPS]: "\u4FEE\u590D\u6240\u6709\u7B14\u8BB0\u7684\u65F6\u95F4\u6233\uFF08\u57FA\u4E8E git \u5386\u53F2\uFF09",
72
36
  [COMMAND_NAMES.UPDATE_NOTE_CONFIG]: "\u66F4\u65B0\u7B14\u8BB0\u914D\u7F6E\u6587\u4EF6",
73
37
  [COMMAND_NAMES.RENAME_NOTE]: "\u91CD\u547D\u540D\u7B14\u8BB0",
@@ -79,13 +43,1302 @@ var COMMAND_OPTIONS = {
79
43
  FORCE: "force"
80
44
  };
81
45
 
46
+ // utils/errorHandler.ts
47
+ var TNotesError = class _TNotesError extends Error {
48
+ constructor(message, code = "UNKNOWN" /* UNKNOWN */, context) {
49
+ super(message);
50
+ this.code = code;
51
+ this.context = context;
52
+ this.name = "TNotesError";
53
+ if (Error.captureStackTrace) {
54
+ Error.captureStackTrace(this, _TNotesError);
55
+ }
56
+ }
57
+ };
58
+ function handleError(error, exitOnError = false) {
59
+ if (error instanceof TNotesError) {
60
+ console.error(`\u274C TNotesError`);
61
+ console.error(`\u9519\u8BEF\u7801\uFF1A${error.code}`);
62
+ console.error(`\u9519\u8BEF\u4FE1\u606F\uFF1A${error.message}`);
63
+ if (error.context && Object.keys(error.context).length > 0) {
64
+ console.error("\u9519\u8BEF\u4E0A\u4E0B\u6587\u4FE1\u606F\uFF1A", error.context);
65
+ }
66
+ if (error.stack && process.env.DEBUG) {
67
+ console.error("\u9519\u8BEF\u5806\u6808\u4FE1\u606F\uFF1A", error.stack);
68
+ }
69
+ } else if (error instanceof Error) {
70
+ console.error(`\u274C Error`);
71
+ console.error(`\u9519\u8BEF\u4FE1\u606F\uFF1A${error.message}`);
72
+ if (error.stack && process.env.DEBUG) {
73
+ console.error("\u9519\u8BEF\u5806\u6808\u4FE1\u606F\uFF1A", error.stack);
74
+ }
75
+ } else {
76
+ console.error("\u274C \u672A\u77E5\u9519\u8BEF\uFF1A", error);
77
+ }
78
+ if (exitOnError) {
79
+ process.exit(1);
80
+ }
81
+ }
82
+ var createError = {
83
+ fileNotFound: (path2) => new TNotesError(`\u6587\u4EF6\u672A\u627E\u5230\uFF1A${path2}`, "FILE_NOT_FOUND" /* FILE_NOT_FOUND */, {
84
+ path: path2
85
+ }),
86
+ fileReadError: (path2, originalError) => new TNotesError(`\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25\uFF1A${path2}`, "FILE_READ_ERROR" /* FILE_READ_ERROR */, {
87
+ path: path2,
88
+ originalError: originalError?.message
89
+ }),
90
+ fileWriteError: (path2, originalError) => new TNotesError(`\u5199\u5165\u6587\u4EF6\u5931\u8D25\uFF1A${path2}`, "FILE_WRITE_ERROR" /* FILE_WRITE_ERROR */, {
91
+ path: path2,
92
+ originalError: originalError?.message
93
+ }),
94
+ gitNotRepo: (dir) => new TNotesError(`\u4E0D\u662F\u4E00\u4E2A Git \u4ED3\u5E93\uFF1A${dir}`, "GIT_NOT_REPO" /* GIT_NOT_REPO */, {
95
+ dir
96
+ }),
97
+ gitCommandFailed: (command, dir, originalError) => new TNotesError(`Git \u547D\u4EE4\u5931\u8D25\uFF1A${command}`, "GIT_COMMAND_FAILED" /* GIT_COMMAND_FAILED */, {
98
+ command,
99
+ dir,
100
+ originalError: originalError?.message
101
+ }),
102
+ noteIndexInvalid: (noteIndex) => new TNotesError(
103
+ `\u65E0\u6548\u7684\u7B14\u8BB0\u7D22\u5F15\uFF1A${noteIndex}`,
104
+ "NOTE_INDEX_INVALID" /* NOTE_INDEX_INVALID */,
105
+ {
106
+ noteIndex
107
+ }
108
+ ),
109
+ noteConfigInvalid: (notePath, reason) => new TNotesError(
110
+ `\u65E0\u6548\u7684\u7B14\u8BB0\u914D\u7F6E\uFF1A${notePath}`,
111
+ "NOTE_CONFIG_INVALID" /* NOTE_CONFIG_INVALID */,
112
+ { notePath, reason }
113
+ ),
114
+ configInvalid: (field, reason) => new TNotesError(`\u65E0\u6548\u7684\u914D\u7F6E\u5B57\u6BB5\uFF1A${field}`, "CONFIG_INVALID" /* CONFIG_INVALID */, {
115
+ field,
116
+ reason
117
+ }),
118
+ commandNotFound: (commandName) => new TNotesError(`\u672A\u627E\u5230\u547D\u4EE4\uFF1A${commandName}`, "COMMAND_NOT_FOUND" /* COMMAND_NOT_FOUND */, {
119
+ commandName
120
+ }),
121
+ commandFailed: (commandName, exitCode, originalError) => new TNotesError(`\u547D\u4EE4\u6267\u884C\u5931\u8D25\uFF1A${commandName}`, "COMMAND_FAILED" /* COMMAND_FAILED */, {
122
+ commandName,
123
+ exitCode,
124
+ originalError: originalError?.message
125
+ }),
126
+ serverStartFailed: (port2, originalError) => new TNotesError(
127
+ `\u542F\u52A8\u670D\u52A1\u5668\u5931\u8D25\uFF1A\u7AEF\u53E3 ${port2}`,
128
+ "SERVER_START_FAILED" /* SERVER_START_FAILED */,
129
+ { port: port2, originalError: originalError?.message }
130
+ ),
131
+ portInUse: (port2) => new TNotesError(`\u7AEF\u53E3 ${port2} \u5DF2\u88AB\u5360\u7528`, "PORT_IN_USE" /* PORT_IN_USE */, {
132
+ port: port2
133
+ })
134
+ };
135
+
136
+ // utils/file.ts
137
+ import fs from "fs";
138
+ async function ensureDirectory(dir) {
139
+ if (!fs.existsSync(dir)) {
140
+ await fs.promises.mkdir(dir, { recursive: true });
141
+ }
142
+ }
143
+
144
+ // utils/generateAnchor.ts
145
+ import GithubSlugger from "github-slugger";
146
+ var slugger = new GithubSlugger();
147
+ var generateAnchor = (label) => {
148
+ slugger.reset();
149
+ return slugger.slug(label);
150
+ };
151
+
152
+ // utils/genHierarchicalSidebar.ts
153
+ var genHierarchicalSidebar = (itemList, titles, titlesNotesCount, sidebarIsCollapsed) => {
154
+ const stack = [];
155
+ const root = [];
156
+ titles.forEach((title, i) => {
157
+ const match = title.match(/^#+/);
158
+ if (!match) return;
159
+ const level = match[0].length;
160
+ const text = title.replace(/^#+\s*/, "");
161
+ const noteItems = itemList.splice(0, titlesNotesCount[i]);
162
+ const node = {
163
+ text,
164
+ collapsed: sidebarIsCollapsed,
165
+ items: noteItems.length > 0 ? noteItems : []
166
+ };
167
+ if (i === 0 && level === 1) return;
168
+ while (stack.length > 0 && stack[stack.length - 1].level >= level) {
169
+ stack.pop();
170
+ }
171
+ if (stack.length === 0) {
172
+ root.push(node);
173
+ } else {
174
+ const parent = stack[stack.length - 1].node;
175
+ if (!parent.items) parent.items = [];
176
+ parent.items.push(node);
177
+ }
178
+ stack.push({ level, node });
179
+ });
180
+ return root;
181
+ };
182
+
183
+ // utils/getChangedIds.ts
184
+ import path from "path";
185
+ import { execSync } from "child_process";
186
+ function getChangedIds() {
187
+ const changedFiles = execSync(
188
+ `git diff --name-only HEAD -- "notes/[0-9][0-9][0-9][0-9]*/README.md"`
189
+ // 根据当前仓库状态和最近一次提交之间的比较
190
+ ).toString().split(/\r?\n/).filter(Boolean).map((fp) => fp.replace(/^"|"$/g, "")).map((fp) => fp.split("/").join(path.sep));
191
+ const changedIds = changedFiles.map((fp) => {
192
+ const parts = fp.split(path.sep);
193
+ const dirName = parts.find((p, i) => parts[i - 1] === "notes");
194
+ return dirName?.slice(0, 4);
195
+ }).filter((id) => Boolean(id));
196
+ return new Set(changedIds);
197
+ }
198
+
199
+ // utils/getTargetDirs.ts
200
+ import { readdirSync } from "fs";
201
+ import { join } from "path";
202
+ var getTargetDirs = (baseDir, prefix, excludeDirs = []) => {
203
+ try {
204
+ const entries = readdirSync(baseDir, { withFileTypes: true });
205
+ const targetDirs = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(prefix)).map((entry) => join(baseDir, entry.name)).filter((dir) => !excludeDirs.includes(dir));
206
+ return targetDirs;
207
+ } catch (error) {
208
+ const errorMessage = error instanceof Error ? error.message : String(error);
209
+ console.error(`\u8BFB\u53D6\u76EE\u5F55 ${baseDir} \u65F6\u51FA\u9519\uFF1A${errorMessage}`);
210
+ return [];
211
+ }
212
+ };
213
+
214
+ // utils/logger.ts
215
+ var Logger = class _Logger {
216
+ level;
217
+ prefix;
218
+ timestamp;
219
+ colors;
220
+ constructor(config2 = {}) {
221
+ this.level = config2.level ?? 1 /* INFO */;
222
+ this.prefix = config2.prefix ?? "";
223
+ this.timestamp = config2.timestamp ?? false;
224
+ this.colors = config2.colors ?? true;
225
+ }
226
+ /**
227
+ * 设置日志级别
228
+ */
229
+ setLevel(level) {
230
+ this.level = level;
231
+ }
232
+ /**
233
+ * 获取当前时间戳(精确到毫秒)
234
+ */
235
+ getTimestamp() {
236
+ if (!this.timestamp) return "";
237
+ const now = /* @__PURE__ */ new Date();
238
+ const hours = String(now.getHours()).padStart(2, "0");
239
+ const minutes = String(now.getMinutes()).padStart(2, "0");
240
+ const seconds = String(now.getSeconds()).padStart(2, "0");
241
+ const milliseconds = String(now.getMilliseconds()).padStart(3, "0");
242
+ return `[${hours}:${minutes}:${seconds}.${milliseconds}] `;
243
+ }
244
+ /**
245
+ * 格式化日志消息
246
+ */
247
+ formatMessage(message) {
248
+ const timestamp = this.getTimestamp();
249
+ const prefix = this.prefix ? `[${this.prefix}] ` : "";
250
+ return `${timestamp}${prefix}${message}`;
251
+ }
252
+ /**
253
+ * DEBUG 级别日志
254
+ */
255
+ debug(message, ...args) {
256
+ if (this.level <= 0 /* DEBUG */) {
257
+ console.log(`\u{1F41B} ${this.formatMessage(message)}`, ...args);
258
+ }
259
+ }
260
+ /**
261
+ * INFO 级别日志
262
+ */
263
+ info(message, ...args) {
264
+ if (this.level <= 1 /* INFO */) {
265
+ console.log(`\u2139\uFE0F ${this.formatMessage(message)}`, ...args);
266
+ }
267
+ }
268
+ /**
269
+ * 成功日志(特殊的 INFO 级别)
270
+ */
271
+ success(message, ...args) {
272
+ if (this.level <= 1 /* INFO */) {
273
+ console.log(`\u2705 ${this.formatMessage(message)}`, ...args);
274
+ }
275
+ }
276
+ /**
277
+ * 警告日志
278
+ */
279
+ warn(message, ...args) {
280
+ if (this.level <= 2 /* WARN */) {
281
+ console.warn(`\u26A0\uFE0F ${this.formatMessage(message)}`, ...args);
282
+ }
283
+ }
284
+ /**
285
+ * 错误日志
286
+ */
287
+ error(message, ...args) {
288
+ if (this.level <= 3 /* ERROR */) {
289
+ console.error(`\u274C ${this.formatMessage(message)}`, ...args);
290
+ }
291
+ }
292
+ /**
293
+ * 进度日志
294
+ */
295
+ progress(message, ...args) {
296
+ if (this.level <= 1 /* INFO */) {
297
+ console.log(`\u23F3 ${this.formatMessage(message)}`, ...args);
298
+ }
299
+ }
300
+ /**
301
+ * 启动日志
302
+ */
303
+ start(message, ...args) {
304
+ if (this.level <= 1 /* INFO */) {
305
+ console.log(`\u{1F680} ${this.formatMessage(message)}`, ...args);
306
+ }
307
+ }
308
+ /**
309
+ * 停止日志
310
+ */
311
+ stop(message, ...args) {
312
+ if (this.level <= 1 /* INFO */) {
313
+ console.log(`\u{1F6D1} ${this.formatMessage(message)}`, ...args);
314
+ }
315
+ }
316
+ /**
317
+ * 完成日志
318
+ */
319
+ done(message, duration, ...args) {
320
+ if (this.level <= 1 /* INFO */) {
321
+ const durationStr = duration ? ` (${duration}ms)` : "";
322
+ console.log(`\u2728 ${this.formatMessage(message)}${durationStr}`, ...args);
323
+ }
324
+ }
325
+ /**
326
+ * 链接日志
327
+ */
328
+ link(message, url, ...args) {
329
+ if (this.level <= 1 /* INFO */) {
330
+ console.log(`\u{1F517} ${this.formatMessage(message)} ${url}`, ...args);
331
+ }
332
+ }
333
+ /**
334
+ * 文件操作日志
335
+ */
336
+ file(action, path2, ...args) {
337
+ if (this.level <= 1 /* INFO */) {
338
+ console.log(`\u{1F4C4} ${this.formatMessage(`${action}: ${path2}`)}`, ...args);
339
+ }
340
+ }
341
+ /**
342
+ * Git 操作日志
343
+ */
344
+ git(message, ...args) {
345
+ if (this.level <= 1 /* INFO */) {
346
+ console.log(`\u{1F4E6} ${this.formatMessage(message)}`, ...args);
347
+ }
348
+ }
349
+ /**
350
+ * 创建子 Logger
351
+ */
352
+ child(prefix) {
353
+ return new _Logger({
354
+ level: this.level,
355
+ prefix: this.prefix ? `${this.prefix}:${prefix}` : prefix,
356
+ timestamp: this.timestamp,
357
+ colors: this.colors
358
+ });
359
+ }
360
+ /**
361
+ * 执行函数并记录耗时
362
+ */
363
+ async time(label, fn) {
364
+ this.progress(`${label}...`);
365
+ const startTime = Date.now();
366
+ try {
367
+ const result = await fn();
368
+ const duration = Date.now() - startTime;
369
+ this.done(label, duration);
370
+ return result;
371
+ } catch (error) {
372
+ const duration = Date.now() - startTime;
373
+ this.error(`${label} failed after ${duration}ms`);
374
+ throw error;
375
+ }
376
+ }
377
+ };
378
+ var logger = new Logger({
379
+ level: process.env.DEBUG ? 0 /* DEBUG */ : 1 /* INFO */,
380
+ timestamp: true,
381
+ // 启用时间戳(精确到毫秒)
382
+ colors: true
383
+ });
384
+ function createLogger(prefix, config2) {
385
+ return new Logger({
386
+ ...config2,
387
+ prefix
388
+ });
389
+ }
390
+
391
+ // utils/markdown.ts
392
+ function createAddNumberToTitle() {
393
+ const titleNumbers = Array(7).fill(0);
394
+ return function addNumberToTitle(title) {
395
+ const match = title.match(
396
+ /^(\#+)\s*((\d+(\.\d*)?(\.\d*)?(\.\d*)?(\.\d*)?(\.\d*)?)\.\s*)?(.*)/
397
+ );
398
+ const plainTitle = match ? match[9].trim() : title.trim();
399
+ const level = title.indexOf(" ");
400
+ const baseLevel = 2;
401
+ if (level === 1) return [title, plainTitle];
402
+ for (let i = level + 1; i < titleNumbers.length; i++) titleNumbers[i] = 0;
403
+ titleNumbers[level] += 1;
404
+ const newNumber = titleNumbers.slice(baseLevel, level + 1).join(".");
405
+ const headerSymbol = title.slice(0, level).trim();
406
+ const newTitle = `${headerSymbol} ${newNumber}. ${plainTitle}`;
407
+ return [newTitle, plainTitle];
408
+ };
409
+ }
410
+ function generateToc(titles, baseLevel = 2, eol = "\n") {
411
+ const toc = titles.map((title) => {
412
+ const level = title.indexOf(" ");
413
+ const text = title.slice(level).trim();
414
+ const anchor = generateAnchor(text);
415
+ const indent = Math.max(0, (level - baseLevel) * 2);
416
+ return " ".repeat(indent) + `- [${text}](#${anchor})`;
417
+ }).join(eol);
418
+ return `${eol}${toc}${eol}`;
419
+ }
420
+
421
+ // utils/parseArgs.ts
422
+ function parseArgs(args) {
423
+ const result = { _: [] };
424
+ for (let i = 0; i < args.length; i++) {
425
+ const arg = args[i];
426
+ if (arg.startsWith("--") && arg.includes("=")) {
427
+ const eqIndex = arg.indexOf("=");
428
+ const key = arg.slice(2, eqIndex);
429
+ const value = arg.slice(eqIndex + 1);
430
+ result[key] = value;
431
+ continue;
432
+ }
433
+ if (arg.startsWith("--no-")) {
434
+ const key = arg.slice(5);
435
+ result[key] = false;
436
+ continue;
437
+ }
438
+ if (arg.startsWith("--")) {
439
+ const key = arg.slice(2);
440
+ const next = args[i + 1];
441
+ if (next !== void 0 && !next.startsWith("-")) {
442
+ if (next === "true") {
443
+ result[key] = true;
444
+ i++;
445
+ } else if (next === "false") {
446
+ result[key] = false;
447
+ i++;
448
+ } else {
449
+ result[key] = true;
450
+ }
451
+ } else {
452
+ result[key] = true;
453
+ }
454
+ continue;
455
+ }
456
+ if (arg.startsWith("-") && arg.length > 1 && !arg.startsWith("--")) {
457
+ const flags = arg.slice(1);
458
+ for (const flag of flags) {
459
+ result[flag] = true;
460
+ }
461
+ continue;
462
+ }
463
+ result._.push(arg);
464
+ }
465
+ return result;
466
+ }
467
+
468
+ // utils/parseReadmeCompletedNotes.ts
469
+ function parseReadmeCompletedNotes(content) {
470
+ const lines = content.split("\n");
471
+ const noteMap = /* @__PURE__ */ new Map();
472
+ const noteIndexRegex = /\[(\d{4})\./;
473
+ for (const line of lines) {
474
+ const match = line.match(noteIndexRegex);
475
+ if (!match) continue;
476
+ const noteIndex = match[1];
477
+ let completed;
478
+ if (line.includes("\u274C")) {
479
+ completed = false;
480
+ } else if (line.includes("\u23F0")) {
481
+ completed = false;
482
+ } else if (line.includes("\u2705")) {
483
+ completed = true;
484
+ } else if (line.trim().startsWith("- [ ]")) {
485
+ completed = false;
486
+ } else if (line.trim().startsWith("- [x]")) {
487
+ completed = true;
488
+ } else {
489
+ continue;
490
+ }
491
+ if (noteMap.has(noteIndex)) {
492
+ const existing = noteMap.get(noteIndex);
493
+ if (existing.completed !== completed) {
494
+ throw new Error(
495
+ `\u53D1\u73B0\u76F8\u540C\u7F16\u53F7 ${noteIndex} \u7684\u7B14\u8BB0\u6709\u4E0D\u540C\u7684\u5B8C\u6210\u72B6\u6001:
496
+ \u7B2C\u4E00\u6B21\u51FA\u73B0: ${existing.line}
497
+ \u7B2C\u4E8C\u6B21\u51FA\u73B0: ${line}`
498
+ );
499
+ }
500
+ continue;
501
+ }
502
+ noteMap.set(noteIndex, {
503
+ noteIndex,
504
+ completed,
505
+ line: line.trim()
506
+ });
507
+ }
508
+ const notes = Array.from(noteMap.values());
509
+ const completedCount = notes.filter((note) => note.completed).length;
510
+ const totalCount = notes.length;
511
+ return {
512
+ completedCount,
513
+ totalCount,
514
+ notes
515
+ };
516
+ }
517
+
518
+ // utils/portUtils.ts
519
+ import { execSync as execSync2 } from "child_process";
520
+ function isPortInUse(port2) {
521
+ try {
522
+ if (process.platform === "win32") {
523
+ const output = execSync2(
524
+ `netstat -ano | findstr :${port2} | findstr LISTENING`,
525
+ { encoding: "utf-8", stdio: "pipe" }
526
+ );
527
+ return output.trim().length > 0;
528
+ } else {
529
+ const output = execSync2(`lsof -i :${port2}`, {
530
+ encoding: "utf-8",
531
+ stdio: "pipe"
532
+ });
533
+ return output.trim().length > 0;
534
+ }
535
+ } catch (error) {
536
+ return false;
537
+ }
538
+ }
539
+ function getPortPid(port2) {
540
+ try {
541
+ if (process.platform === "win32") {
542
+ const output = execSync2(`netstat -ano | findstr :${port2}`, {
543
+ encoding: "utf-8",
544
+ stdio: "pipe"
545
+ });
546
+ const lines = output.trim().split("\n");
547
+ if (lines.length > 0) {
548
+ const match = lines[0].match(/\s+(\d+)\s*$/);
549
+ if (match) {
550
+ return parseInt(match[1]);
551
+ }
552
+ }
553
+ } else {
554
+ const output = execSync2(`lsof -t -i :${port2}`, {
555
+ encoding: "utf-8",
556
+ stdio: "pipe"
557
+ });
558
+ const pid = parseInt(output.trim());
559
+ if (!isNaN(pid)) {
560
+ return pid;
561
+ }
562
+ }
563
+ } catch (error) {
564
+ }
565
+ return null;
566
+ }
567
+ function killPortProcess(port2) {
568
+ const pid = getPortPid(port2);
569
+ if (!pid) {
570
+ return false;
571
+ }
572
+ try {
573
+ if (process.platform === "win32") {
574
+ execSync2(`taskkill /F /PID ${pid}`, { stdio: "pipe" });
575
+ } else {
576
+ execSync2(`kill -9 ${pid}`, { stdio: "pipe" });
577
+ }
578
+ logger.info(`\u5DF2\u7EC8\u6B62\u5360\u7528\u7AEF\u53E3 ${port2} \u7684\u8FDB\u7A0B (PID: ${pid})`);
579
+ return true;
580
+ } catch (error) {
581
+ logger.error(
582
+ `\u7EC8\u6B62\u8FDB\u7A0B\u5931\u8D25 (PID: ${pid}): ${error instanceof Error ? error.message : String(error)}`
583
+ );
584
+ return false;
585
+ }
586
+ }
587
+ async function waitForPort(port2, timeout = 5e3) {
588
+ const startTime = Date.now();
589
+ while (Date.now() - startTime < timeout) {
590
+ if (!isPortInUse(port2)) {
591
+ return true;
592
+ }
593
+ await new Promise((resolve4) => setTimeout(resolve4, 100));
594
+ }
595
+ return false;
596
+ }
597
+
598
+ // core/NoteManager.ts
599
+ import { existsSync, readFileSync, readdirSync as readdirSync2, writeFileSync } from "fs";
600
+ import { join as join2 } from "path";
601
+
602
+ // config/constants.ts
603
+ import { resolve } from "path";
604
+ var configManager = getConfigManager();
605
+ var config = configManager.getAll();
606
+ var {
607
+ author,
608
+ ignore_dirs,
609
+ menuItems,
610
+ port,
611
+ repoName,
612
+ sidebarShowNoteId,
613
+ socialLinks,
614
+ root_item
615
+ } = config;
616
+ var rootPath = configManager.getRootPath();
617
+ var TNOTES_BASE_DIR = resolve(rootPath, "..");
618
+ var TNOTES_CORE_DIR = resolve(TNOTES_BASE_DIR, "TNotes.core");
619
+ var EN_WORDS_DIR = resolve(TNOTES_BASE_DIR, "TNotes.en-words");
620
+ var ROOT_DIR_PATH = rootPath;
621
+ var ROOT_README_PATH = resolve(ROOT_DIR_PATH, "README.md");
622
+ var ROOT_CONFIG_PATH = resolve(ROOT_DIR_PATH, ".tnotes.json");
623
+ var NOTES_DIR_PATH = resolve(ROOT_DIR_PATH, "notes");
624
+ var VP_DIR_PATH = resolve(ROOT_DIR_PATH, ".vitepress");
625
+ var PUBLIC_PATH = resolve(ROOT_DIR_PATH, "public");
626
+ var GITHUB_DIR_PATH = resolve(ROOT_DIR_PATH, ".github");
627
+ var GITHUB_DEPLOY_YML_PATH = resolve(
628
+ GITHUB_DIR_PATH,
629
+ "workflows",
630
+ "deploy.yml"
631
+ );
632
+ var VP_SIDEBAR_PATH = resolve(ROOT_DIR_PATH, "sidebar.json");
633
+ var ROOT_PKG_PATH = resolve(ROOT_DIR_PATH, "package.json");
634
+ var VSCODE_SETTINGS_PATH = resolve(
635
+ ROOT_DIR_PATH,
636
+ ".vscode",
637
+ "settings.json"
638
+ );
639
+ var VSCODE_TASKS_PATH = resolve(ROOT_DIR_PATH, ".vscode", "tasks.json");
640
+ var EOL = "\n";
641
+ var CONSTANTS = {
642
+ // 端口配置
643
+ DEFAULT_PORT: 5173,
644
+ // 笔记索引配置(文件夹前缀的 4 位数字)
645
+ NOTE_INDEX_LENGTH: 4,
646
+ NOTE_INDEX_PATTERN: /^\d{4}\./,
647
+ NOTE_INDEX_PREFIX_PATTERN: /^\d{4}/,
648
+ // Git 配置
649
+ DEFAULT_BRANCH: "main",
650
+ // 缓存配置
651
+ CACHE_TTL: 5e3,
652
+ // 终端输出颜色
653
+ COLORS: {
654
+ RESET: "\x1B[0m",
655
+ BRIGHT: "\x1B[1m",
656
+ DIM: "\x1B[2m",
657
+ RED: "\x1B[31m",
658
+ GREEN: "\x1B[32m",
659
+ YELLOW: "\x1B[33m",
660
+ BLUE: "\x1B[34m",
661
+ MAGENTA: "\x1B[35m",
662
+ CYAN: "\x1B[36m"
663
+ },
664
+ // Emoji
665
+ EMOJI: {
666
+ SUCCESS: "\u2705",
667
+ ERROR: "\u274C",
668
+ WARNING: "\u26A0\uFE0F",
669
+ INFO: "\u2139\uFE0F",
670
+ PROGRESS: "\u23F3",
671
+ ROCKET: "\u{1F680}",
672
+ STOP: "\u{1F6D1}",
673
+ SPARKLES: "\u2728",
674
+ LINK: "\u{1F517}",
675
+ FILE: "\u{1F4C4}",
676
+ GIT: "\u{1F4E6}",
677
+ DEBUG: "\u{1F41B}"
678
+ }
679
+ };
680
+ var NOTES_PATH = NOTES_DIR_PATH;
681
+ var REPO_NOTES_URL = `https://github.com/${author}/${repoName}/tree/main/notes`;
682
+
683
+ // core/NoteManager.ts
684
+ var NoteManager = class _NoteManager {
685
+ static instance;
686
+ /** 笔记索引正则:4 位数字开头,后接小数点 */
687
+ static NOTE_INDEX_REGEX = /^(\d{4})\./;
688
+ constructor() {
689
+ }
690
+ /**
691
+ * 从文件夹名称或文本中提取笔记索引
692
+ *
693
+ * @param text - 要解析的文本(通常是文件夹名称)
694
+ * @returns 笔记索引(4 位数字字符串)或 null
695
+ *
696
+ * @example
697
+ * NoteManager.extractNoteIndex('0001. TNotes 简介') // '0001'
698
+ * NoteManager.extractNoteIndex('invalid-folder') // null
699
+ */
700
+ static extractNoteIndex(text) {
701
+ const match = text.match(_NoteManager.NOTE_INDEX_REGEX);
702
+ return match ? match[1] : null;
703
+ }
704
+ /**
705
+ * 输出无效笔记名称的警告日志
706
+ *
707
+ * @param name - 无效的笔记名称
708
+ */
709
+ static warnInvalidNoteIndex(name) {
710
+ logger.warn(`\u65E0\u6548\u7684\u7B14\u8BB0\u540D: ${name}`);
711
+ logger.warn("\u7B14\u8BB0\u540D\u5FC5\u987B\u4EE5 4 \u4E2A\u6570\u5B57\u5F00\u5934");
712
+ logger.warn("\u8303\u56F4\uFF1A0001-9999");
713
+ }
714
+ static getInstance() {
715
+ if (!_NoteManager.instance) {
716
+ _NoteManager.instance = new _NoteManager();
717
+ }
718
+ return _NoteManager.instance;
719
+ }
720
+ /**
721
+ * 获取 notes 目录下所有合法的笔记目录名(已排序)
722
+ * 合法条件:是目录、不以 . 开头、以 4 位数字 + . 开头
723
+ */
724
+ getNoteDirs() {
725
+ if (!existsSync(NOTES_PATH)) return [];
726
+ return readdirSync2(NOTES_PATH, { withFileTypes: true }).filter(
727
+ (entry) => entry.isDirectory() && !entry.name.startsWith(".") && _NoteManager.NOTE_INDEX_REGEX.test(entry.name)
728
+ ).map((entry) => entry.name).sort();
729
+ }
730
+ /**
731
+ * 根据目录名构建单条 NoteInfo
732
+ * @returns NoteInfo 或 undefined(README 不存在时)
733
+ */
734
+ buildNoteInfo(dirName) {
735
+ const notePath = join2(NOTES_PATH, dirName);
736
+ const readmePath = join2(notePath, "README.md");
737
+ const configPath = join2(notePath, ".tnotes.json");
738
+ if (!existsSync(readmePath)) {
739
+ logger.warn(`README not found in note: ${dirName}`);
740
+ return void 0;
741
+ }
742
+ let config2;
743
+ if (existsSync(configPath)) {
744
+ config2 = this.validateAndFixConfig(configPath) || void 0;
745
+ }
746
+ return {
747
+ index: _NoteManager.extractNoteIndex(dirName),
748
+ path: notePath,
749
+ dirName,
750
+ readmePath,
751
+ configPath,
752
+ config: config2
753
+ };
754
+ }
755
+ /**
756
+ * 扫描所有笔记并校验数据完整性
757
+ *
758
+ * @returns 笔记信息数组
759
+ */
760
+ scanNotes() {
761
+ const noteDirs = this.getNoteDirs();
762
+ if (noteDirs.length === 0) {
763
+ logger.warn(`${NOTES_PATH} \u672A\u68C0\u6D4B\u5230\u7B14\u8BB0\u76EE\u5F55`);
764
+ return [];
765
+ }
766
+ const notes = [];
767
+ for (const dirName of noteDirs) {
768
+ const note = this.buildNoteInfo(dirName);
769
+ if (note) notes.push(note);
770
+ }
771
+ this.validateNotes(notes);
772
+ return notes;
773
+ }
774
+ /**
775
+ * 校验笔记数据完整性
776
+ *
777
+ * - 检查 noteIndex 冲突 + config id 缺失/重复
778
+ * - 任一检查失败则终止进程
779
+ */
780
+ validateNotes(notes) {
781
+ const errors = [];
782
+ const L1 = " ".repeat(3);
783
+ const L2 = " ".repeat(6);
784
+ const indexMap = this.buildNoteIndexMap(notes.map((n) => n.dirName));
785
+ for (const [index, dirNames] of indexMap.entries()) {
786
+ if (dirNames.length > 1) {
787
+ errors.push(`\u26A0\uFE0F \u68C0\u6D4B\u5230\u91CD\u590D\u7684\u7B14\u8BB0\u7F16\u53F7\uFF1A`);
788
+ errors.push(`${L1}\u7D22\u5F15 ${index} \u88AB\u4EE5\u4E0B\u7B14\u8BB0\u91CD\u590D\u4F7F\u7528\uFF1A`);
789
+ dirNames.forEach((dirName) => errors.push(`${L2}- ${dirName}`));
790
+ }
791
+ }
792
+ const missingConfigId = [];
793
+ for (const note of notes) {
794
+ if (!note.config || !note.config.id) {
795
+ missingConfigId.push(note.dirName);
796
+ }
797
+ }
798
+ if (missingConfigId.length > 0) {
799
+ errors.push(`\u26A0\uFE0F \u68C0\u6D4B\u5230\u7B14\u8BB0\u914D\u7F6E ID \u7F3A\u5931\uFF1A`);
800
+ missingConfigId.forEach((dirName) => errors.push(`${L2}- ${dirName}`));
801
+ }
802
+ const configIdMap = /* @__PURE__ */ new Map();
803
+ for (const note of notes) {
804
+ if (note.config?.id) {
805
+ if (!configIdMap.has(note.config.id))
806
+ configIdMap.set(note.config.id, []);
807
+ configIdMap.get(note.config.id).push(note.dirName);
808
+ }
809
+ }
810
+ for (const [configId, dirNames] of configIdMap.entries()) {
811
+ if (dirNames.length > 1) {
812
+ errors.push(`\u26A0\uFE0F \u68C0\u6D4B\u5230\u91CD\u590D\u7684\u7B14\u8BB0\u914D\u7F6E ID\uFF1A`);
813
+ errors.push(`${L1}\u914D\u7F6E ID ${configId} \u88AB\u4EE5\u4E0B\u7B14\u8BB0\u91CD\u590D\u4F7F\u7528\uFF1A`);
814
+ dirNames.forEach((dirName) => errors.push(`${L2}- ${dirName}`));
815
+ }
816
+ }
817
+ if (errors.length > 0) {
818
+ for (const line of errors) {
819
+ logger.error(line);
820
+ }
821
+ logger.error("\n\n\u8BF7\u4FEE\u590D\u4E0A\u8FF0\u95EE\u9898\u540E\u91CD\u65B0\u542F\u52A8\u670D\u52A1\u3002\n\n");
822
+ process.exit(1);
823
+ }
824
+ }
825
+ /**
826
+ * 按 4 位数字编号对目录名分组
827
+ * @param dirNames - 目录名数组
828
+ * @returns 编号 -> 目录名数组 的映射
829
+ */
830
+ buildNoteIndexMap(dirNames) {
831
+ const indexMap = /* @__PURE__ */ new Map();
832
+ for (const name of dirNames) {
833
+ const index = _NoteManager.extractNoteIndex(name);
834
+ if (!indexMap.has(index)) indexMap.set(index, []);
835
+ indexMap.get(index).push(name);
836
+ }
837
+ return indexMap;
838
+ }
839
+ /** 配置字段顺序 */
840
+ static FIELD_ORDER = [
841
+ "bilibili",
842
+ "tnotes",
843
+ "yuque",
844
+ "done",
845
+ "category",
846
+ "enableDiscussions",
847
+ "description",
848
+ "id",
849
+ "created_at",
850
+ "updated_at"
851
+ ];
852
+ /** 默认配置字段 */
853
+ static DEFAULT_CONFIG_FIELDS = {
854
+ bilibili: [],
855
+ tnotes: [],
856
+ yuque: [],
857
+ done: false,
858
+ enableDiscussions: false,
859
+ description: ""
860
+ };
861
+ /** 必需字段(不能缺失) */
862
+ static REQUIRED_FIELDS = ["id"];
863
+ /**
864
+ * 验证并修复配置文件
865
+ * @param configPath - 配置文件路径
866
+ * @returns 修复后的配置对象,失败时返回 null
867
+ */
868
+ validateAndFixConfig(configPath) {
869
+ const configContent = readFileSync(configPath, "utf-8");
870
+ let config2;
871
+ try {
872
+ config2 = JSON.parse(configContent);
873
+ } catch (error) {
874
+ logger.error(`\u914D\u7F6E\u6587\u4EF6 JSON \u89E3\u6790\u5931\u8D25: ${configPath}`, error);
875
+ return null;
876
+ }
877
+ let needsUpdate = false;
878
+ for (const field of _NoteManager.REQUIRED_FIELDS) {
879
+ if (!config2[field]) {
880
+ return null;
881
+ }
882
+ }
883
+ for (const [key, defaultValue] of Object.entries(
884
+ _NoteManager.DEFAULT_CONFIG_FIELDS
885
+ )) {
886
+ if (!(key in config2)) {
887
+ ;
888
+ config2[key] = defaultValue;
889
+ needsUpdate = true;
890
+ logger.info(`\u8865\u5145\u7F3A\u5931\u5B57\u6BB5 "${key}": ${configPath}`);
891
+ }
892
+ }
893
+ const now = Date.now();
894
+ if (!config2.created_at) {
895
+ config2.created_at = now;
896
+ needsUpdate = true;
897
+ logger.info(
898
+ `\u68C0\u6D4B\u5230 ${configPath} \u7F3A\u5931 created_at \u5B57\u6BB5\uFF0C\u8BF7\u6267\u884C tn:fix-timestamps \u6821\u51C6\u4E3A\u7B14\u8BB0\u9996\u6B21 git commit \u7684\u65F6\u95F4\uFF09`
899
+ );
900
+ }
901
+ if (!config2.updated_at) {
902
+ config2.updated_at = now;
903
+ needsUpdate = true;
904
+ logger.info(
905
+ `\u68C0\u6D4B\u5230 ${configPath} \u7F3A\u5931 updated_at \u5B57\u6BB5\uFF0C\u8BF7\u6267\u884C tn:fix-timestamps \u6821\u51C6\u4E3A\u7B14\u8BB0\u6700\u540E\u4E00\u6B21 git commit \u7684\u65F6\u95F4\uFF09`
906
+ );
907
+ }
908
+ const sortedConfig = this.sortConfigKeys(config2);
909
+ if (needsUpdate) {
910
+ this.writeNoteConfig(configPath, sortedConfig);
911
+ logger.info(`\u914D\u7F6E\u6587\u4EF6\u5DF2\u4FEE\u590D: ${configPath}`);
912
+ }
913
+ return sortedConfig;
914
+ }
915
+ /**
916
+ * 按指定顺序排序配置对象的键
917
+ */
918
+ sortConfigKeys(config2) {
919
+ const configRecord = config2;
920
+ const sorted = {};
921
+ for (const key of _NoteManager.FIELD_ORDER) {
922
+ if (key in config2) {
923
+ sorted[key] = configRecord[key];
924
+ }
925
+ }
926
+ for (const key of Object.keys(config2)) {
927
+ if (!(key in sorted)) {
928
+ sorted[key] = configRecord[key];
929
+ }
930
+ }
931
+ return sorted;
932
+ }
933
+ /**
934
+ * 序列化 NoteConfig 为格式化的 JSON 字符串
935
+ * 保持字段顺序,使用 2 空格缩进,末尾含换行符
936
+ */
937
+ serializeNoteConfig(config2) {
938
+ const sorted = this.sortConfigKeys(config2);
939
+ return JSON.stringify(sorted, null, 2) + "\n";
940
+ }
941
+ /**
942
+ * 统一写入笔记配置文件
943
+ * @param configPath - 配置文件路径
944
+ * @param config - 笔记配置
945
+ */
946
+ writeNoteConfig(configPath, config2) {
947
+ writeFileSync(configPath, this.serializeNoteConfig(config2), "utf-8");
948
+ }
949
+ /**
950
+ * 验证笔记配置对象的结构合法性
951
+ * @param config - 笔记配置
952
+ * @returns 是否有效
953
+ */
954
+ validateConfig(config2) {
955
+ if (!config2.id) {
956
+ logger.error("Note config missing id");
957
+ return false;
958
+ }
959
+ if (!Array.isArray(config2.bilibili)) {
960
+ logger.error(`Invalid bilibili config in note: ${config2.id}`);
961
+ return false;
962
+ }
963
+ if (!Array.isArray(config2.tnotes)) {
964
+ logger.error(`Invalid tnotes config in note: ${config2.id}`);
965
+ return false;
966
+ }
967
+ if (!Array.isArray(config2.yuque)) {
968
+ logger.error(`Invalid yuque config in note: ${config2.id}`);
969
+ return false;
970
+ }
971
+ if (typeof config2.done !== "boolean") {
972
+ logger.error(`Invalid done status in note: ${config2.id}`);
973
+ return false;
974
+ }
975
+ if (typeof config2.enableDiscussions !== "boolean") {
976
+ logger.error(`Invalid enableDiscussions status in note: ${config2.id}`);
977
+ return false;
978
+ }
979
+ return true;
980
+ }
981
+ /**
982
+ * 更新笔记配置
983
+ * @param noteInfo - 笔记信息
984
+ * @param config - 新的配置
985
+ */
986
+ updateNoteConfig(noteInfo, config2) {
987
+ if (!this.validateConfig(config2)) {
988
+ throw new Error(`Invalid config for note: ${noteInfo.dirName}`);
989
+ }
990
+ config2.updated_at = Date.now();
991
+ this.writeNoteConfig(noteInfo.configPath, config2);
992
+ logger.info(`Updated config for note: ${noteInfo.dirName}`);
993
+ }
994
+ /**
995
+ * 获取笔记信息(通过索引)- 直接查找不扫描所有笔记
996
+ * @param noteIndex - 笔记索引
997
+ * @returns 笔记信息,未找到时返回 undefined
998
+ */
999
+ getNoteByIndex(noteIndex) {
1000
+ const noteDirs = this.getNoteDirs();
1001
+ for (const dirName of noteDirs) {
1002
+ if (_NoteManager.extractNoteIndex(dirName) === noteIndex) {
1003
+ return this.buildNoteInfo(dirName);
1004
+ }
1005
+ }
1006
+ return void 0;
1007
+ }
1008
+ };
1009
+
1010
+ // utils/readmeHelpers.ts
1011
+ var NOTE_LINE_REGEX = /^( *)- \[.\] \[(\d{4}\. .+?)\]/;
1012
+ function parseNoteLine(line) {
1013
+ const noteMatch = line.match(NOTE_LINE_REGEX);
1014
+ if (!noteMatch) {
1015
+ return {
1016
+ isMatch: false,
1017
+ noteIndex: null
1018
+ };
1019
+ }
1020
+ const [, , text] = noteMatch;
1021
+ const noteIndex = NoteManager.extractNoteIndex(text);
1022
+ return {
1023
+ isMatch: true,
1024
+ noteIndex
1025
+ };
1026
+ }
1027
+ function buildNoteLink(note, repoOwner, repoName2) {
1028
+ const encodedDirName = encodeURIComponent(note.dirName);
1029
+ return `https://github.com/${repoOwner}/${repoName2}/tree/main/notes/${encodedDirName}/README.md`;
1030
+ }
1031
+ function updateNoteStatus(note) {
1032
+ let status = " ";
1033
+ let deprecatedMark = "";
1034
+ if (note.config) {
1035
+ if (note.config.done) {
1036
+ status = "x";
1037
+ }
1038
+ }
1039
+ return { status, deprecatedMark };
1040
+ }
1041
+ function buildNoteLineMarkdown(note, repoOwner, repoName2) {
1042
+ const url = buildNoteLink(note, repoOwner, repoName2);
1043
+ const { status, deprecatedMark } = updateNoteStatus(note);
1044
+ return `- [${status}] [${note.dirName}](${url})${deprecatedMark}`;
1045
+ }
1046
+ function isNoteLine(line) {
1047
+ return NOTE_LINE_REGEX.test(line);
1048
+ }
1049
+ function mergeConsecutiveEmptyLines(lines) {
1050
+ const result = [];
1051
+ let previousLineIsEmpty = false;
1052
+ for (const line of lines) {
1053
+ const isCurrentLineEmpty = line === "";
1054
+ if (isCurrentLineEmpty) {
1055
+ if (!previousLineIsEmpty) {
1056
+ result.push(line);
1057
+ previousLineIsEmpty = true;
1058
+ }
1059
+ } else {
1060
+ result.push(line);
1061
+ previousLineIsEmpty = false;
1062
+ }
1063
+ }
1064
+ return result;
1065
+ }
1066
+ function removeEmptyLinesBetweenNotes(lines) {
1067
+ const result = [];
1068
+ for (let i = 0; i < lines.length; i++) {
1069
+ const currentLine = lines[i];
1070
+ const prevLine = i > 0 ? lines[i - 1] : null;
1071
+ const nextLine = i < lines.length - 1 ? lines[i + 1] : null;
1072
+ if (currentLine === "" && prevLine && nextLine) {
1073
+ const isPrevLineNote = isNoteLine(prevLine);
1074
+ const isNextLineNote = isNoteLine(nextLine);
1075
+ if (isPrevLineNote && isNextLineNote) {
1076
+ continue;
1077
+ }
1078
+ }
1079
+ result.push(currentLine);
1080
+ }
1081
+ return result;
1082
+ }
1083
+ function processEmptyLines(lines) {
1084
+ const stepOne = mergeConsecutiveEmptyLines(lines);
1085
+ const stepTwo = removeEmptyLinesBetweenNotes(stepOne);
1086
+ return stepTwo;
1087
+ }
1088
+
1089
+ // utils/runCommand.ts
1090
+ import { exec } from "child_process";
1091
+ async function runCommand(command, dir) {
1092
+ return new Promise((resolve4, reject) => {
1093
+ exec(command, { cwd: dir }, (error, stdout, stderr) => {
1094
+ if (error) {
1095
+ console.error(`\u5904\u7406 ${dir} \u65F6\u51FA\u9519\uFF1A${stderr}`);
1096
+ reject(error);
1097
+ } else {
1098
+ resolve4(stdout.trim());
1099
+ }
1100
+ });
1101
+ });
1102
+ }
1103
+
1104
+ // utils/syncRepo.ts
1105
+ async function pushAllRepos(options) {
1106
+ const {
1107
+ parallel = true,
1108
+ continueOnError = true,
1109
+ force = false
1110
+ } = options || {};
1111
+ const targetDirs = getTargetDirs(TNOTES_BASE_DIR, "TNotes.", [EN_WORDS_DIR, TNOTES_CORE_DIR]);
1112
+ logger.info(`\u6B63\u5728\u63A8\u9001 ${targetDirs.length} \u4E2A\u4ED3\u5E93...`);
1113
+ if (force) {
1114
+ logger.warn("\u4F7F\u7528\u5F3A\u5236\u63A8\u9001\u6A21\u5F0F");
1115
+ }
1116
+ const results = [];
1117
+ const pushCmd = force ? "pnpm tn:push --force" : "pnpm tn:push";
1118
+ if (parallel) {
1119
+ const promises = targetDirs.map(async (dir, index) => {
1120
+ try {
1121
+ await runCommand(pushCmd, dir);
1122
+ process.stdout.write(`\r \u8FDB\u5EA6: ~${index + 1}/${targetDirs.length}`);
1123
+ return { dir, success: true };
1124
+ } catch (error) {
1125
+ const errorMessage = error instanceof Error ? error.message : String(error);
1126
+ return { dir, success: false, error: errorMessage };
1127
+ }
1128
+ });
1129
+ results.push(...await Promise.all(promises));
1130
+ console.log();
1131
+ } else {
1132
+ for (let i = 0; i < targetDirs.length; i++) {
1133
+ const dir = targetDirs[i];
1134
+ try {
1135
+ await runCommand(pushCmd, dir);
1136
+ process.stdout.write(`\r \u8FDB\u5EA6: ${i + 1}/${targetDirs.length}`);
1137
+ results.push({ dir, success: true });
1138
+ } catch (error) {
1139
+ process.stdout.write(`\r \u8FDB\u5EA6: ${i + 1}/${targetDirs.length}`);
1140
+ const errorMessage = error instanceof Error ? error.message : String(error);
1141
+ results.push({ dir, success: false, error: errorMessage });
1142
+ if (!continueOnError) {
1143
+ console.log();
1144
+ throw error;
1145
+ }
1146
+ }
1147
+ }
1148
+ console.log();
1149
+ }
1150
+ const successCount = results.filter((r) => r.success).length;
1151
+ const failCount = results.length - successCount;
1152
+ if (failCount === 0) {
1153
+ logger.success(`\u63A8\u9001\u5B8C\u6210: ${successCount}/${results.length} \u4E2A\u4ED3\u5E93\u6210\u529F`);
1154
+ } else {
1155
+ logger.warn(
1156
+ `\u63A8\u9001\u5B8C\u6210: ${successCount} \u6210\u529F, ${failCount} \u5931\u8D25 (\u5171 ${results.length} \u4E2A)`
1157
+ );
1158
+ console.log("\n\u5931\u8D25\u7684\u4ED3\u5E93:");
1159
+ results.filter((r) => !r.success).forEach((r, index) => {
1160
+ const repoName2 = r.dir.split("\\").pop() || r.dir;
1161
+ console.log(` ${index + 1}. ${repoName2}`);
1162
+ console.log(` \u9519\u8BEF: ${r.error}`);
1163
+ });
1164
+ }
1165
+ }
1166
+ async function pullAllRepos(options) {
1167
+ const { parallel = true, continueOnError = true } = options || {};
1168
+ const targetDirs = getTargetDirs(TNOTES_BASE_DIR, "TNotes.", [EN_WORDS_DIR, TNOTES_CORE_DIR]);
1169
+ logger.info(`\u6B63\u5728\u62C9\u53D6 ${targetDirs.length} \u4E2A\u4ED3\u5E93...`);
1170
+ const results = [];
1171
+ if (parallel) {
1172
+ const promises = targetDirs.map(async (dir, index) => {
1173
+ try {
1174
+ await runCommand("pnpm tn:pull", dir);
1175
+ process.stdout.write(`\r \u8FDB\u5EA6: ~${index + 1}/${targetDirs.length}`);
1176
+ return { dir, success: true };
1177
+ } catch (error) {
1178
+ const errorMessage = error instanceof Error ? error.message : String(error);
1179
+ return { dir, success: false, error: errorMessage };
1180
+ }
1181
+ });
1182
+ results.push(...await Promise.all(promises));
1183
+ console.log();
1184
+ } else {
1185
+ for (let i = 0; i < targetDirs.length; i++) {
1186
+ const dir = targetDirs[i];
1187
+ try {
1188
+ await runCommand("pnpm tn:pull", dir);
1189
+ process.stdout.write(`\r \u8FDB\u5EA6: ${i + 1}/${targetDirs.length}`);
1190
+ results.push({ dir, success: true });
1191
+ } catch (error) {
1192
+ process.stdout.write(`\r \u8FDB\u5EA6: ${i + 1}/${targetDirs.length}`);
1193
+ const errorMessage = error instanceof Error ? error.message : String(error);
1194
+ results.push({ dir, success: false, error: errorMessage });
1195
+ if (!continueOnError) {
1196
+ console.log();
1197
+ throw error;
1198
+ }
1199
+ }
1200
+ }
1201
+ console.log();
1202
+ }
1203
+ const successCount = results.filter((r) => r.success).length;
1204
+ const failCount = results.length - successCount;
1205
+ if (failCount === 0) {
1206
+ logger.success(`\u62C9\u53D6\u5B8C\u6210: ${successCount}/${results.length} \u4E2A\u4ED3\u5E93\u6210\u529F`);
1207
+ } else {
1208
+ logger.warn(
1209
+ `\u62C9\u53D6\u5B8C\u6210: ${successCount} \u6210\u529F, ${failCount} \u5931\u8D25 (\u5171 ${results.length} \u4E2A)`
1210
+ );
1211
+ console.log("\n\u5931\u8D25\u7684\u4ED3\u5E93:");
1212
+ results.filter((r) => !r.success).forEach((r, index) => {
1213
+ const repoName2 = r.dir.split("\\").pop() || r.dir;
1214
+ console.log(` ${index + 1}. ${repoName2}`);
1215
+ console.log(` \u9519\u8BEF: ${r.error}`);
1216
+ });
1217
+ }
1218
+ }
1219
+ async function syncAllRepos(options) {
1220
+ const { parallel = true, continueOnError = true } = options || {};
1221
+ const targetDirs = getTargetDirs(TNOTES_BASE_DIR, "TNotes.", [EN_WORDS_DIR, TNOTES_CORE_DIR]);
1222
+ logger.info(`\u6B63\u5728\u540C\u6B65 ${targetDirs.length} \u4E2A\u4ED3\u5E93...`);
1223
+ const results = [];
1224
+ if (parallel) {
1225
+ const promises = targetDirs.map(async (dir, index) => {
1226
+ try {
1227
+ await runCommand("pnpm tn:sync", dir);
1228
+ process.stdout.write(`\r \u8FDB\u5EA6: ~${index + 1}/${targetDirs.length}`);
1229
+ return { dir, success: true };
1230
+ } catch (error) {
1231
+ const errorMessage = error instanceof Error ? error.message : String(error);
1232
+ return { dir, success: false, error: errorMessage };
1233
+ }
1234
+ });
1235
+ results.push(...await Promise.all(promises));
1236
+ } else {
1237
+ for (let i = 0; i < targetDirs.length; i++) {
1238
+ const dir = targetDirs[i];
1239
+ try {
1240
+ await runCommand("pnpm tn:sync", dir);
1241
+ process.stdout.write(`\r \u8FDB\u5EA6: ${i + 1}/${targetDirs.length}`);
1242
+ results.push({ dir, success: true });
1243
+ } catch (error) {
1244
+ process.stdout.write(`\r \u8FDB\u5EA6: ${i + 1}/${targetDirs.length}`);
1245
+ const errorMessage = error instanceof Error ? error.message : String(error);
1246
+ results.push({ dir, success: false, error: errorMessage });
1247
+ if (!continueOnError) {
1248
+ throw error;
1249
+ }
1250
+ }
1251
+ }
1252
+ }
1253
+ console.log();
1254
+ const successCount = results.filter((r) => r.success).length;
1255
+ const failCount = results.length - successCount;
1256
+ if (failCount === 0) {
1257
+ logger.success(`\u540C\u6B65\u5B8C\u6210: ${successCount}/${results.length} \u4E2A\u4ED3\u5E93\u6210\u529F`);
1258
+ } else {
1259
+ logger.warn(
1260
+ `\u540C\u6B65\u5B8C\u6210: ${successCount} \u6210\u529F, ${failCount} \u5931\u8D25 (\u5171 ${results.length} \u4E2A)`
1261
+ );
1262
+ console.log("\n\u5931\u8D25\u7684\u4ED3\u5E93:");
1263
+ results.filter((r) => !r.success).forEach((r, index) => {
1264
+ const repoName2 = r.dir.split("\\").pop() || r.dir;
1265
+ console.log(` ${index + 1}. ${repoName2}`);
1266
+ console.log(` \u9519\u8BEF: ${r.error}`);
1267
+ });
1268
+ }
1269
+ }
1270
+
1271
+ // utils/validators.ts
1272
+ var INVALID_FILENAME_CHARS = /[<>:"/\\|?*\x00-\x1F]/;
1273
+ var WINDOWS_RESERVED_NAMES = /* @__PURE__ */ new Set([
1274
+ "CON",
1275
+ "PRN",
1276
+ "AUX",
1277
+ "NUL",
1278
+ "COM1",
1279
+ "COM2",
1280
+ "COM3",
1281
+ "COM4",
1282
+ "COM5",
1283
+ "COM6",
1284
+ "COM7",
1285
+ "COM8",
1286
+ "COM9",
1287
+ "LPT1",
1288
+ "LPT2",
1289
+ "LPT3",
1290
+ "LPT4",
1291
+ "LPT5",
1292
+ "LPT6",
1293
+ "LPT7",
1294
+ "LPT8",
1295
+ "LPT9"
1296
+ ]);
1297
+ function validateNoteTitle(title) {
1298
+ if (!title || title.trim().length === 0) {
1299
+ return { valid: false, error: "\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A" };
1300
+ }
1301
+ const trimmedTitle = title.trim();
1302
+ if (trimmedTitle.length > 200) {
1303
+ return { valid: false, error: "\u6807\u9898\u8FC7\u957F(\u6700\u591A200\u4E2A\u5B57\u7B26)" };
1304
+ }
1305
+ if (INVALID_FILENAME_CHARS.test(trimmedTitle)) {
1306
+ return {
1307
+ valid: false,
1308
+ error: '\u6807\u9898\u5305\u542B\u975E\u6CD5\u5B57\u7B26(\u4E0D\u5141\u8BB8: < > : " / \\ | ? *)'
1309
+ };
1310
+ }
1311
+ if (/^[.\s]|[.\s]$/.test(trimmedTitle)) {
1312
+ return {
1313
+ valid: false,
1314
+ error: "\u6807\u9898\u4E0D\u80FD\u4EE5\u70B9\u6216\u7A7A\u683C\u5F00\u5934/\u7ED3\u5C3E"
1315
+ };
1316
+ }
1317
+ const upperTitle = trimmedTitle.toUpperCase();
1318
+ if (WINDOWS_RESERVED_NAMES.has(upperTitle)) {
1319
+ return {
1320
+ valid: false,
1321
+ error: `"${trimmedTitle}" \u662F Windows \u7CFB\u7EDF\u4FDD\u7559\u540D\u79F0`
1322
+ };
1323
+ }
1324
+ const baseName = trimmedTitle.split(".")[0].toUpperCase();
1325
+ if (WINDOWS_RESERVED_NAMES.has(baseName)) {
1326
+ return {
1327
+ valid: false,
1328
+ error: `"${trimmedTitle}" \u5305\u542B Windows \u7CFB\u7EDF\u4FDD\u7559\u540D\u79F0`
1329
+ };
1330
+ }
1331
+ return { valid: true };
1332
+ }
1333
+
82
1334
  // commands/BaseCommand.ts
83
1335
  var BaseCommand = class {
84
1336
  constructor(name) {
85
1337
  this.name = name;
86
- this.options = {};
87
1338
  this.logger = logger.child(name);
88
1339
  }
1340
+ logger;
1341
+ options = {};
89
1342
  /** 命令描述(从静态配置读取) */
90
1343
  get description() {
91
1344
  return COMMAND_DESCRIPTIONS[this.name];
@@ -129,19 +1382,19 @@ async function safeExecute(label, fn, logger2) {
129
1382
  }
130
1383
 
131
1384
  // services/file-watcher/watchState.ts
132
- import { existsSync, readFileSync, readdirSync, statSync } from "fs";
1385
+ import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync as readdirSync3, statSync } from "fs";
133
1386
  import { createHash } from "crypto";
134
- import { join } from "path";
1387
+ import { join as join3 } from "path";
135
1388
  var WatchState = class {
136
- constructor(config) {
137
- this.config = config;
138
- /** 文件哈希缓存 */
139
- this.fileHashes = /* @__PURE__ */ new Map();
140
- /** 笔记目录缓存 */
141
- this.noteDirCache = /* @__PURE__ */ new Set();
142
- /** 笔记配置缓存 */
143
- this.configCache = /* @__PURE__ */ new Map();
144
- }
1389
+ constructor(config2) {
1390
+ this.config = config2;
1391
+ }
1392
+ /** 文件哈希缓存 */
1393
+ fileHashes = /* @__PURE__ */ new Map();
1394
+ /** 笔记目录缓存 */
1395
+ noteDirCache = /* @__PURE__ */ new Set();
1396
+ /** 笔记配置缓存 */
1397
+ configCache = /* @__PURE__ */ new Map();
145
1398
  /**
146
1399
  * 获取指定文件的 MD5 哈希值,若文件不存在或读取失败返回 null
147
1400
  *
@@ -150,8 +1403,8 @@ var WatchState = class {
150
1403
  */
151
1404
  getFileHash(filePath) {
152
1405
  try {
153
- if (!existsSync(filePath)) return null;
154
- const content = readFileSync(filePath, "utf-8");
1406
+ if (!existsSync2(filePath)) return null;
1407
+ const content = readFileSync2(filePath, "utf-8");
155
1408
  if (content.length === 0) return null;
156
1409
  return createHash("md5").update(content).digest("hex");
157
1410
  } catch {
@@ -211,8 +1464,8 @@ var WatchState = class {
211
1464
  * @param noteDirName 笔记目录名称
212
1465
  */
213
1466
  clearNoteCaches(noteDirName) {
214
- const readmePath = join(this.config.notesDir, noteDirName, "README.md");
215
- const configPath = join(this.config.notesDir, noteDirName, ".tnotes.json");
1467
+ const readmePath = join3(this.config.notesDir, noteDirName, "README.md");
1468
+ const configPath = join3(this.config.notesDir, noteDirName, ".tnotes.json");
216
1469
  this.fileHashes.delete(readmePath);
217
1470
  this.fileHashes.delete(configPath);
218
1471
  this.configCache.delete(configPath);
@@ -245,13 +1498,13 @@ var WatchState = class {
245
1498
  */
246
1499
  readConfigSnapshot(configPath) {
247
1500
  try {
248
- if (!existsSync(configPath)) return null;
249
- const content = readFileSync(configPath, "utf-8");
250
- const config = JSON.parse(content);
1501
+ if (!existsSync2(configPath)) return null;
1502
+ const content = readFileSync2(configPath, "utf-8");
1503
+ const config2 = JSON.parse(content);
251
1504
  return {
252
- done: Boolean(config.done),
253
- enableDiscussions: Boolean(config.enableDiscussions),
254
- description: config.description || ""
1505
+ done: Boolean(config2.done),
1506
+ enableDiscussions: Boolean(config2.enableDiscussions),
1507
+ description: config2.description || ""
255
1508
  };
256
1509
  } catch (error) {
257
1510
  this.config.logger.error(`[\u8BFB\u53D6\u914D\u7F6E\u5FEB\u7167] ${error}`);
@@ -265,16 +1518,16 @@ var WatchState = class {
265
1518
  */
266
1519
  initializeFromDisk() {
267
1520
  try {
268
- const noteDirs = readdirSync(this.config.notesDir);
1521
+ const noteDirs = readdirSync3(this.config.notesDir);
269
1522
  this.clearAll();
270
1523
  for (const noteDir of noteDirs) {
271
- const noteDirPath = join(this.config.notesDir, noteDir);
1524
+ const noteDirPath = join3(this.config.notesDir, noteDir);
272
1525
  if (!statSync(noteDirPath).isDirectory()) continue;
273
1526
  this.noteDirCache.add(noteDir);
274
- const readmePath = join(noteDirPath, "README.md");
1527
+ const readmePath = join3(noteDirPath, "README.md");
275
1528
  const readmeHash = this.getFileHash(readmePath);
276
1529
  if (readmeHash) this.fileHashes.set(readmePath, readmeHash);
277
- const configPath = join(noteDirPath, ".tnotes.json");
1530
+ const configPath = join3(noteDirPath, ".tnotes.json");
278
1531
  const configHash = this.getFileHash(configPath);
279
1532
  if (configHash) {
280
1533
  this.fileHashes.set(configPath, configHash);
@@ -296,23 +1549,27 @@ var DEFAULT_BATCH_WINDOW_MS = 1e3;
296
1549
  var DEFAULT_BATCH_THRESHOLD = 3;
297
1550
  var DEFAULT_BATCH_BUFFER_MS = 2e3;
298
1551
  var EventScheduler = class {
299
- constructor(config) {
300
- this.config = config;
301
- /** 待处理的文件变更事件队列 */
302
- this.pendingEvents = /* @__PURE__ */ new Map();
303
- /** 防抖定时器 */
304
- this.updateTimer = null;
305
- /** 批量更新恢复定时器 */
306
- this.batchResumeTimer = null;
307
- /** 记录最近的变更时间戳 */
308
- this.recentChanges = [];
309
- /** 标记是否正在更新,避免循环触发 - 类似一把更新行为锁 */
310
- this.isUpdating = false;
311
- this.debounceMs = config.debounceMs ?? DEFAULT_DEBOUNCE_MS;
312
- this.batchWindowMs = config.batchWindowMs ?? DEFAULT_BATCH_WINDOW_MS;
313
- this.batchThreshold = config.batchThreshold ?? DEFAULT_BATCH_THRESHOLD;
314
- this.batchBufferMs = config.batchBufferMs ?? DEFAULT_BATCH_BUFFER_MS;
315
- }
1552
+ constructor(config2) {
1553
+ this.config = config2;
1554
+ this.debounceMs = config2.debounceMs ?? DEFAULT_DEBOUNCE_MS;
1555
+ this.batchWindowMs = config2.batchWindowMs ?? DEFAULT_BATCH_WINDOW_MS;
1556
+ this.batchThreshold = config2.batchThreshold ?? DEFAULT_BATCH_THRESHOLD;
1557
+ this.batchBufferMs = config2.batchBufferMs ?? DEFAULT_BATCH_BUFFER_MS;
1558
+ }
1559
+ /** 待处理的文件变更事件队列 */
1560
+ pendingEvents = /* @__PURE__ */ new Map();
1561
+ /** 防抖定时器 */
1562
+ updateTimer = null;
1563
+ /** 批量更新恢复定时器 */
1564
+ batchResumeTimer = null;
1565
+ /** 记录最近的变更时间戳 */
1566
+ recentChanges = [];
1567
+ /** 标记是否正在更新,避免循环触发 - 类似一把更新行为锁 */
1568
+ isUpdating = false;
1569
+ debounceMs;
1570
+ batchWindowMs;
1571
+ batchThreshold;
1572
+ batchBufferMs;
316
1573
  /**
317
1574
  * 设置更新状态锁,用于防止在执行耗时更新操作时被新的文件变更事件打断
318
1575
  *
@@ -409,21 +1666,21 @@ var EventScheduler = class {
409
1666
  };
410
1667
 
411
1668
  // services/file-watcher/renameDetector.ts
412
- import { existsSync as existsSync2 } from "fs";
413
- import { join as join2 } from "path";
1669
+ import { existsSync as existsSync3 } from "fs";
1670
+ import { join as join4 } from "path";
414
1671
  var FOLDER_RENAME_DETECT_WINDOW_MS = 500;
415
1672
  var RenameDetector = class {
416
- constructor(config) {
417
- this.config = config;
418
- /** 待处理的文件夹重命名 */
419
- this.pendingFolderRename = null;
420
- /** 文件夹重命名检测定时器 */
421
- this.folderRenameTimer = null;
1673
+ constructor(config2) {
1674
+ this.config = config2;
422
1675
  }
1676
+ /** 待处理的文件夹重命名 */
1677
+ pendingFolderRename = null;
1678
+ /** 文件夹重命名检测定时器 */
1679
+ folderRenameTimer = null;
423
1680
  handleFsRename(folderName) {
424
1681
  const { notesDir, dirCache, logger: logger2, onDelete, onRename } = this.config;
425
- const folderPath = join2(notesDir, folderName);
426
- const folderExists = existsSync2(folderPath);
1682
+ const folderPath = join4(notesDir, folderName);
1683
+ const folderExists = existsSync3(folderPath);
427
1684
  const noteIndex = NoteManager.extractNoteIndex(folderName);
428
1685
  if (!noteIndex) {
429
1686
  logger2.warn(`\u65E0\u6CD5\u4ECE\u6587\u4EF6\u5939\u540D\u79F0\u63D0\u53D6\u7B14\u8BB0\u7D22\u5F15: ${folderName}`);
@@ -479,8 +1736,8 @@ var RenameDetector = class {
479
1736
 
480
1737
  // services/file-watcher/configChangeHandler.ts
481
1738
  var ConfigChangeHandler = class {
482
- constructor(config) {
483
- this.config = config;
1739
+ constructor(config2) {
1740
+ this.config = config2;
484
1741
  }
485
1742
  async handle(events) {
486
1743
  if (events.length === 0) return [];
@@ -512,8 +1769,8 @@ var ConfigChangeHandler = class {
512
1769
 
513
1770
  // services/file-watcher/readmeChangeHandler.ts
514
1771
  var ReadmeChangeHandler = class {
515
- constructor(config) {
516
- this.config = config;
1772
+ constructor(config2) {
1773
+ this.config = config2;
517
1774
  }
518
1775
  async handle(events) {
519
1776
  if (events.length === 0) return;
@@ -529,8 +1786,8 @@ var ReadmeChangeHandler = class {
529
1786
 
530
1787
  // services/file-watcher/globalUpdateCoordinator.ts
531
1788
  var GlobalUpdateCoordinator = class {
532
- constructor(config) {
533
- this.config = config;
1789
+ constructor(config2) {
1790
+ this.config = config2;
534
1791
  }
535
1792
  async applyConfigUpdates(changedNoteIndexes) {
536
1793
  if (changedNoteIndexes.length === 0) return;
@@ -560,17 +1817,17 @@ var GlobalUpdateCoordinator = class {
560
1817
  };
561
1818
 
562
1819
  // services/file-watcher/folderChangeHandler.ts
563
- import { existsSync as existsSync3, promises as fsPromises } from "fs";
564
- import { join as join3 } from "path";
1820
+ import { existsSync as existsSync4, promises as fsPromises } from "fs";
1821
+ import { join as join5 } from "path";
565
1822
  var RENAME_REVERT_DELAY_MS = 2e3;
566
1823
  var DELETE_REINIT_DELAY_MS = 1e3;
567
1824
  var UPDATE_UNLOCK_DELAY_MS = 500;
568
1825
  var FolderChangeHandler = class {
569
- constructor(config) {
570
- this.config = config;
571
- /** 活跃的定时器 ID 集合,用于统一清理 */
572
- this.activeTimers = /* @__PURE__ */ new Set();
1826
+ constructor(config2) {
1827
+ this.config = config2;
573
1828
  }
1829
+ /** 活跃的定时器 ID 集合,用于统一清理 */
1830
+ activeTimers = /* @__PURE__ */ new Set();
574
1831
  /**
575
1832
  * 清理所有活跃定时器,释放资源
576
1833
  *
@@ -695,9 +1952,9 @@ var FolderChangeHandler = class {
695
1952
  async revertFolderRename(oldName, newName) {
696
1953
  const { notesDir, scheduler, watchState, logger: logger2 } = this.config;
697
1954
  try {
698
- const oldPath = join3(notesDir, oldName);
699
- const newPath = join3(notesDir, newName);
700
- if (existsSync3(newPath)) {
1955
+ const oldPath = join5(notesDir, oldName);
1956
+ const newPath = join5(notesDir, newName);
1957
+ if (existsSync4(newPath)) {
701
1958
  scheduler.setUpdating(true);
702
1959
  await fsPromises.rename(newPath, oldPath);
703
1960
  logger2.warn(`\u6587\u4EF6\u5939\u5DF2\u56DE\u9000: ${newName} \u2192 ${oldName}`);
@@ -722,13 +1979,13 @@ var FolderChangeHandler = class {
722
1979
 
723
1980
  // services/file-watcher/fsWatcherAdapter.ts
724
1981
  import { watch } from "fs";
725
- import { basename, dirname, join as join4, sep } from "path";
1982
+ import { basename, dirname, join as join6, sep } from "path";
726
1983
  var FsWatcherAdapter = class {
727
- constructor(config) {
728
- this.config = config;
729
- /** 文件系统监听器实例 */
730
- this.watcher = null;
1984
+ constructor(config2) {
1985
+ this.config = config2;
731
1986
  }
1987
+ /** 文件系统监听器实例 */
1988
+ watcher = null;
732
1989
  start() {
733
1990
  const { logger: logger2 } = this.config;
734
1991
  if (this.watcher) {
@@ -765,7 +2022,7 @@ var FsWatcherAdapter = class {
765
2022
  if (baseFilename !== "README.md" && baseFilename !== ".tnotes.json") {
766
2023
  return;
767
2024
  }
768
- const fullPath = join4(this.config.notesDir, filename);
2025
+ const fullPath = join6(this.config.notesDir, filename);
769
2026
  const event = this.buildWatchEvent(fullPath, filename);
770
2027
  if (!event) {
771
2028
  return;
@@ -791,7 +2048,7 @@ var FsWatcherAdapter = class {
791
2048
  };
792
2049
 
793
2050
  // core/ReadmeGenerator.ts
794
- import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync4 } from "fs";
2051
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync5 } from "fs";
795
2052
 
796
2053
  // core/TocGenerator.ts
797
2054
  var BILIBILI_VIDEO_BASE_URL = "https://www.bilibili.com/video/";
@@ -806,7 +2063,7 @@ var TocGenerator = class {
806
2063
  * @param noteConfig - 笔记配置
807
2064
  * @param repoName - 仓库名称
808
2065
  */
809
- updateNoteToc(noteIndex, lines, noteConfig, repoName) {
2066
+ updateNoteToc(noteIndex, lines, noteConfig, repoName2) {
810
2067
  let startLineIdx = -1, endLineIdx = -1;
811
2068
  lines.forEach((line, idx) => {
812
2069
  if (line.startsWith(NOTES_TOC_START_TAG)) startLineIdx = idx;
@@ -866,7 +2123,7 @@ var TocGenerator = class {
866
2123
  if (noteConfig.bilibili.length > 0) {
867
2124
  noteConfig.bilibili.forEach((bvid, i) => {
868
2125
  bilibiliTOCItems.push(
869
- ` - [bilibili.${repoName}.${noteIndex}.${i + 1}](${BILIBILI_VIDEO_BASE_URL + bvid})`
2126
+ ` - [bilibili.${repoName2}.${noteIndex}.${i + 1}](${BILIBILI_VIDEO_BASE_URL + bvid})`
870
2127
  );
871
2128
  });
872
2129
  }
@@ -874,16 +2131,16 @@ var TocGenerator = class {
874
2131
  tnotesTOCItems.push(
875
2132
  `- [\u{1F4D2} TNotes\uFF08\u76F8\u5173\u77E5\u8BC6\u5E93\uFF09](https://tnotesjs.github.io/TNotes/)`
876
2133
  );
877
- noteConfig.tnotes.forEach((repoName2) => {
2134
+ noteConfig.tnotes.forEach((repoName3) => {
878
2135
  tnotesTOCItems.push(
879
- ` - [TNotes.${repoName2}](https://tnotesjs.github.io/TNotes.${repoName2}/)`
2136
+ ` - [TNotes.${repoName3}](https://tnotesjs.github.io/TNotes.${repoName3}/)`
880
2137
  );
881
2138
  });
882
2139
  }
883
2140
  if (noteConfig.yuque.length > 0) {
884
2141
  noteConfig.yuque.forEach((slug, i) => {
885
2142
  yuqueTOCItems.push(
886
- ` - [TNotes.yuque.${repoName.replace(
2143
+ ` - [TNotes.yuque.${repoName2.replace(
887
2144
  "TNotes.",
888
2145
  ""
889
2146
  )}.${noteIndex}](${TNOTES_YUQUE_BASE_URL + slug})`
@@ -944,6 +2201,8 @@ var TocGenerator = class {
944
2201
 
945
2202
  // core/ReadmeGenerator.ts
946
2203
  var ReadmeGenerator = class {
2204
+ tocGenerator;
2205
+ configManager;
947
2206
  constructor() {
948
2207
  this.tocGenerator = new TocGenerator();
949
2208
  this.configManager = ConfigManager.getInstance();
@@ -957,18 +2216,18 @@ var ReadmeGenerator = class {
957
2216
  logger.warn(`\u7B14\u8BB0 ${noteInfo.dirName} \u7F3A\u5C11\u914D\u7F6E\u6587\u4EF6`);
958
2217
  return;
959
2218
  }
960
- const content = readFileSync2(noteInfo.readmePath, "utf-8");
2219
+ const content = readFileSync3(noteInfo.readmePath, "utf-8");
961
2220
  if (content.length === 0) return;
962
2221
  const lines = content.split(EOL);
963
- const repoName = this.configManager.get("repoName");
2222
+ const repoName2 = this.configManager.get("repoName");
964
2223
  this.tocGenerator.updateNoteToc(
965
2224
  noteInfo.index,
966
2225
  lines,
967
2226
  noteInfo.config,
968
- repoName
2227
+ repoName2
969
2228
  );
970
2229
  const updatedContent = lines.join(EOL);
971
- writeFileSync(noteInfo.readmePath, updatedContent, "utf-8");
2230
+ writeFileSync2(noteInfo.readmePath, updatedContent, "utf-8");
972
2231
  }
973
2232
  /**
974
2233
  * 更新首页 README
@@ -977,18 +2236,18 @@ var ReadmeGenerator = class {
977
2236
  * @param homeReadmePath - 首页 README 路径
978
2237
  */
979
2238
  updateHomeReadme(notes, homeReadmePath) {
980
- if (!existsSync4(homeReadmePath)) {
2239
+ if (!existsSync5(homeReadmePath)) {
981
2240
  logger.error(`\u6839\u76EE\u5F55\u4E0B\u7684 README.md \u6587\u4EF6\u672A\u627E\u5230\uFF1A${homeReadmePath}`);
982
2241
  return;
983
2242
  }
984
- const content = readFileSync2(homeReadmePath, "utf-8");
2243
+ const content = readFileSync3(homeReadmePath, "utf-8");
985
2244
  const lines = content.split(EOL);
986
2245
  const noteByIndexMap = /* @__PURE__ */ new Map();
987
2246
  for (const note of notes) {
988
2247
  noteByIndexMap.set(note.index, note);
989
2248
  }
990
2249
  const repoOwner = this.configManager.get("author");
991
- const repoName = this.configManager.get("repoName");
2250
+ const repoName2 = this.configManager.get("repoName");
992
2251
  const existingNoteIndexes = /* @__PURE__ */ new Set();
993
2252
  const linesToRemove = /* @__PURE__ */ new Set();
994
2253
  const titles = [];
@@ -1019,7 +2278,7 @@ var ReadmeGenerator = class {
1019
2278
  continue;
1020
2279
  }
1021
2280
  existingNoteIndexes.add(parsed.noteIndex);
1022
- lines[i] = buildNoteLineMarkdown(note, repoOwner, repoName);
2281
+ lines[i] = buildNoteLineMarkdown(note, repoOwner, repoName2);
1023
2282
  currentNoteCount++;
1024
2283
  continue;
1025
2284
  }
@@ -1062,7 +2321,7 @@ var ReadmeGenerator = class {
1062
2321
  logger.info(`\u6DFB\u52A0 ${missingNotes.length} \u7BC7\u7F3A\u5931\u7684\u7B14\u8BB0\u5230 README`);
1063
2322
  missingNotes.sort((a, b) => a.index.localeCompare(b.index));
1064
2323
  for (const note of missingNotes) {
1065
- const noteLine = buildNoteLineMarkdown(note, repoOwner, repoName);
2324
+ const noteLine = buildNoteLineMarkdown(note, repoOwner, repoName2);
1066
2325
  lines.push(noteLine);
1067
2326
  currentNoteCount++;
1068
2327
  }
@@ -1073,24 +2332,22 @@ var ReadmeGenerator = class {
1073
2332
  this.tocGenerator.updateHomeToc(lines, titles, titlesNotesCount);
1074
2333
  const processedLines = processEmptyLines(lines);
1075
2334
  const updatedContent = processedLines.join(EOL);
1076
- writeFileSync(homeReadmePath, updatedContent, "utf-8");
2335
+ writeFileSync2(homeReadmePath, updatedContent, "utf-8");
1077
2336
  logger.info("\u5DF2\u66F4\u65B0\u9996\u9875 README");
1078
2337
  }
1079
2338
  };
1080
2339
 
1081
2340
  // core/NoteIndexCache.ts
1082
- import { join as join5 } from "path";
2341
+ import { join as join7 } from "path";
1083
2342
  var NoteIndexCache = class _NoteIndexCache {
2343
+ static instance = null;
2344
+ /** noteIndex -> NoteIndexItem 的映射 */
2345
+ byNoteIndex = /* @__PURE__ */ new Map();
2346
+ /** configId (UUID) -> noteIndex 的映射,用于快速反向查询 */
2347
+ byConfigId = /* @__PURE__ */ new Map();
2348
+ /** 是否已完成初始化 */
2349
+ _initialized = false;
1084
2350
  constructor() {
1085
- /** noteIndex -> NoteIndexItem 的映射 */
1086
- this.byNoteIndex = /* @__PURE__ */ new Map();
1087
- /** configId (UUID) -> noteIndex 的映射,用于快速反向查询 */
1088
- this.byConfigId = /* @__PURE__ */ new Map();
1089
- /** 是否已完成初始化 */
1090
- this._initialized = false;
1091
- }
1092
- static {
1093
- this.instance = null;
1094
2351
  }
1095
2352
  /**
1096
2353
  * 获取单例实例
@@ -1132,13 +2389,13 @@ var NoteIndexCache = class _NoteIndexCache {
1132
2389
  toNoteInfoList() {
1133
2390
  const result = [];
1134
2391
  for (const item of this.byNoteIndex.values()) {
1135
- const notePath = join5(NOTES_PATH, item.folderName);
2392
+ const notePath = join7(NOTES_PATH, item.folderName);
1136
2393
  result.push({
1137
2394
  index: item.noteIndex,
1138
2395
  path: notePath,
1139
2396
  dirName: item.folderName,
1140
- readmePath: join5(notePath, "README.md"),
1141
- configPath: join5(notePath, ".tnotes.json"),
2397
+ readmePath: join7(notePath, "README.md"),
2398
+ configPath: join7(notePath, ".tnotes.json"),
1142
2399
  config: item.noteConfig
1143
2400
  });
1144
2401
  }
@@ -1224,12 +2481,17 @@ var NoteIndexCache = class _NoteIndexCache {
1224
2481
 
1225
2482
  // services/readme/service.ts
1226
2483
  import {
1227
- existsSync as existsSync5,
1228
- readFileSync as readFileSync3,
1229
- writeFileSync as writeFileSync2,
2484
+ existsSync as existsSync6,
2485
+ readFileSync as readFileSync4,
2486
+ writeFileSync as writeFileSync3,
1230
2487
  promises as fsPromises2
1231
2488
  } from "fs";
1232
2489
  var ReadmeService = class _ReadmeService {
2490
+ static instance;
2491
+ noteManager;
2492
+ readmeGenerator;
2493
+ configManager;
2494
+ noteIndexCache;
1233
2495
  constructor() {
1234
2496
  this.noteManager = NoteManager.getInstance();
1235
2497
  this.readmeGenerator = new ReadmeGenerator();
@@ -1354,11 +2616,11 @@ var ReadmeService = class _ReadmeService {
1354
2616
  * @param notes - 笔记信息数组
1355
2617
  */
1356
2618
  async updateSidebar(notes) {
1357
- if (!existsSync5(ROOT_README_PATH)) {
2619
+ if (!existsSync6(ROOT_README_PATH)) {
1358
2620
  logger.error("\u672A\u627E\u5230\u9996\u9875 README\uFF0C\u65E0\u6CD5\u751F\u6210\u4FA7\u8FB9\u680F");
1359
2621
  return;
1360
2622
  }
1361
- const content = readFileSync3(ROOT_README_PATH, "utf-8");
2623
+ const content = readFileSync4(ROOT_README_PATH, "utf-8");
1362
2624
  const lines = content.split("\n");
1363
2625
  const itemList = [];
1364
2626
  const titles = [];
@@ -1390,9 +2652,9 @@ var ReadmeService = class _ReadmeService {
1390
2652
  statusEmoji = "\u2705 ";
1391
2653
  }
1392
2654
  }
1393
- const sidebarShowNoteId = this.configManager.get("sidebarShowNoteId");
2655
+ const sidebarShowNoteId2 = this.configManager.get("sidebarShowNoteId");
1394
2656
  let displayText = note.dirName;
1395
- if (!sidebarShowNoteId) {
2657
+ if (!sidebarShowNoteId2) {
1396
2658
  displayText = note.dirName.replace(/^\d{4}\.\s/, "");
1397
2659
  }
1398
2660
  itemList.push({
@@ -1421,7 +2683,7 @@ var ReadmeService = class _ReadmeService {
1421
2683
  titlesNotesCount,
1422
2684
  sidebarIsCollapsed
1423
2685
  );
1424
- writeFileSync2(
2686
+ writeFileSync3(
1425
2687
  VP_SIDEBAR_PATH,
1426
2688
  JSON.stringify(hierarchicalSidebar, null, 2),
1427
2689
  "utf-8"
@@ -1449,7 +2711,7 @@ var ReadmeService = class _ReadmeService {
1449
2711
  const content = await fsPromises2.readFile(ROOT_README_PATH, "utf-8");
1450
2712
  const lines = content.split("\n");
1451
2713
  const repoOwner = this.configManager.get("author");
1452
- const repoName = this.configManager.get("repoName");
2714
+ const repoName2 = this.configManager.get("repoName");
1453
2715
  const mergedConfig = { ...item.noteConfig, ...updates };
1454
2716
  const tempNoteInfo = {
1455
2717
  index: noteIndex,
@@ -1463,7 +2725,7 @@ var ReadmeService = class _ReadmeService {
1463
2725
  for (let i = 0; i < lines.length; i++) {
1464
2726
  const parsed = parseNoteLine(lines[i]);
1465
2727
  if (parsed.noteIndex === noteIndex) {
1466
- lines[i] = buildNoteLineMarkdown(tempNoteInfo, repoOwner, repoName);
2728
+ lines[i] = buildNoteLineMarkdown(tempNoteInfo, repoOwner, repoName2);
1467
2729
  updated = true;
1468
2730
  }
1469
2731
  }
@@ -1513,7 +2775,7 @@ var ReadmeService = class _ReadmeService {
1513
2775
  const content = await fsPromises2.readFile(ROOT_README_PATH, "utf-8");
1514
2776
  const lines = content.split("\n");
1515
2777
  const repoOwner = this.configManager.get("author");
1516
- const repoName = this.configManager.get("repoName");
2778
+ const repoName2 = this.configManager.get("repoName");
1517
2779
  const tempNoteInfo = {
1518
2780
  index: noteIndex,
1519
2781
  dirName: item.folderName,
@@ -1522,7 +2784,7 @@ var ReadmeService = class _ReadmeService {
1522
2784
  configPath: "",
1523
2785
  config: item.noteConfig
1524
2786
  };
1525
- const noteLine = buildNoteLineMarkdown(tempNoteInfo, repoOwner, repoName);
2787
+ const noteLine = buildNoteLineMarkdown(tempNoteInfo, repoOwner, repoName2);
1526
2788
  lines.push(noteLine);
1527
2789
  await fsPromises2.writeFile(ROOT_README_PATH, lines.join("\n"), "utf-8");
1528
2790
  logger.info(`\u5728 README.md \u672B\u5C3E\u6DFB\u52A0\u7B14\u8BB0: ${noteIndex}`);
@@ -1539,8 +2801,8 @@ var ReadmeService = class _ReadmeService {
1539
2801
  };
1540
2802
 
1541
2803
  // services/note/service.ts
1542
- import { writeFileSync as writeFileSync3, readFileSync as readFileSync4 } from "fs";
1543
- import { join as join6 } from "path";
2804
+ import { writeFileSync as writeFileSync4, readFileSync as readFileSync5 } from "fs";
2805
+ import { join as join8 } from "path";
1544
2806
  import { v4 as uuidv4 } from "uuid";
1545
2807
 
1546
2808
  // config/templates.ts
@@ -1568,8 +2830,11 @@ var NEW_NOTES_README_MD_TEMPLATE = `
1568
2830
  - todo
1569
2831
  `;
1570
2832
  var NoteService = class _NoteService {
2833
+ static instance;
2834
+ noteManager;
2835
+ noteIndexCache;
2836
+ ignoredConfigPaths = /* @__PURE__ */ new Set();
1571
2837
  constructor() {
1572
- this.ignoredConfigPaths = /* @__PURE__ */ new Set();
1573
2838
  this.noteManager = NoteManager.getInstance();
1574
2839
  this.noteIndexCache = NoteIndexCache.getInstance();
1575
2840
  }
@@ -1632,15 +2897,15 @@ var NoteService = class _NoteService {
1632
2897
  } = options;
1633
2898
  const noteIndex = this.generateNextNoteIndex(usedIndexes);
1634
2899
  const dirName = `${noteIndex}. ${title}`;
1635
- const notePath = join6(NOTES_PATH, dirName);
2900
+ const notePath = join8(NOTES_PATH, dirName);
1636
2901
  await ensureDirectory(notePath);
1637
- const readmePath = join6(notePath, "README.md");
2902
+ const readmePath = join8(notePath, "README.md");
1638
2903
  const noteTitle = generateNoteTitle(noteIndex, title, REPO_NOTES_URL);
1639
2904
  const readmeContent = noteTitle + "\n" + NEW_NOTES_README_MD_TEMPLATE;
1640
- writeFileSync3(readmePath, readmeContent, "utf-8");
1641
- const configPath = join6(notePath, ".tnotes.json");
2905
+ writeFileSync4(readmePath, readmeContent, "utf-8");
2906
+ const configPath = join8(notePath, ".tnotes.json");
1642
2907
  const now = Date.now();
1643
- const config = {
2908
+ const config2 = {
1644
2909
  id: configId || uuidv4(),
1645
2910
  // 配置 ID 使用 UUID(跨知识库唯一)
1646
2911
  bilibili: [],
@@ -1652,7 +2917,7 @@ var NoteService = class _NoteService {
1652
2917
  created_at: now,
1653
2918
  updated_at: now
1654
2919
  };
1655
- this.noteManager.writeNoteConfig(configPath, config);
2920
+ this.noteManager.writeNoteConfig(configPath, config2);
1656
2921
  logger.info(`Created new note: ${dirName}`);
1657
2922
  return {
1658
2923
  index: noteIndex,
@@ -1661,7 +2926,7 @@ var NoteService = class _NoteService {
1661
2926
  dirName,
1662
2927
  readmePath,
1663
2928
  configPath,
1664
- config
2929
+ config: config2
1665
2930
  };
1666
2931
  }
1667
2932
  /**
@@ -1745,7 +3010,7 @@ var NoteService = class _NoteService {
1745
3010
  */
1746
3011
  async fixNoteTitle(noteInfo) {
1747
3012
  try {
1748
- const readmeContent = readFileSync4(noteInfo.readmePath, "utf-8");
3013
+ const readmeContent = readFileSync5(noteInfo.readmePath, "utf-8");
1749
3014
  if (readmeContent.length === 0) return false;
1750
3015
  const lines = readmeContent.split("\n");
1751
3016
  const match = noteInfo.dirName.match(/^\d{4}\.\s+(.+)$/);
@@ -1762,13 +3027,13 @@ var NoteService = class _NoteService {
1762
3027
  const firstLine = lines[0].trim();
1763
3028
  if (!firstLine.startsWith("# ")) {
1764
3029
  lines.unshift(expectedH1);
1765
- writeFileSync3(noteInfo.readmePath, lines.join("\n"), "utf-8");
3030
+ writeFileSync4(noteInfo.readmePath, lines.join("\n"), "utf-8");
1766
3031
  logger.info(`Added title to: ${noteInfo.dirName}`);
1767
3032
  return true;
1768
3033
  }
1769
3034
  if (firstLine !== expectedH1) {
1770
3035
  lines[0] = expectedH1;
1771
- writeFileSync3(noteInfo.readmePath, lines.join("\n"), "utf-8");
3036
+ writeFileSync4(noteInfo.readmePath, lines.join("\n"), "utf-8");
1772
3037
  logger.info(`Fixed title for: ${noteInfo.dirName}`);
1773
3038
  return true;
1774
3039
  }
@@ -1805,12 +3070,23 @@ var UPDATE_UNLOCK_DELAY_MS2 = 500;
1805
3070
  var FileWatcherService = class {
1806
3071
  constructor(notesDir = NOTES_DIR_PATH) {
1807
3072
  this.notesDir = notesDir;
1808
- this.unlockTimer = null;
1809
3073
  if (!this.notesDir) {
1810
3074
  throw new Error(NOTES_DIR_NOT_SET_ERROR);
1811
3075
  }
1812
3076
  this.init();
1813
3077
  }
3078
+ watchState;
3079
+ scheduler;
3080
+ renameDetector;
3081
+ configHandler;
3082
+ readmeHandler;
3083
+ coordinator;
3084
+ folderHandler;
3085
+ adapter;
3086
+ noteService;
3087
+ readmeService;
3088
+ noteIndexCache;
3089
+ unlockTimer = null;
1814
3090
  init() {
1815
3091
  this.noteService = NoteService.getInstance();
1816
3092
  this.readmeService = ReadmeService.getInstance();
@@ -1962,9 +3238,11 @@ var FileWatcherService = class {
1962
3238
  };
1963
3239
 
1964
3240
  // core/GitManager.ts
1965
- import { resolve } from "path";
1966
- import { existsSync as existsSync6 } from "fs";
3241
+ import { resolve as resolve2 } from "path";
3242
+ import { existsSync as existsSync7 } from "fs";
1967
3243
  var GitManager = class {
3244
+ logger;
3245
+ dir;
1968
3246
  constructor(dir, logger2) {
1969
3247
  this.dir = dir;
1970
3248
  this.logger = logger2?.child("git") || new Logger({ prefix: "git" });
@@ -2003,8 +3281,8 @@ var GitManager = class {
2003
3281
  const lines = statusOutput.trim().split("\n").filter((line) => line);
2004
3282
  const files = lines.map((line) => {
2005
3283
  const statusCode = line.substring(0, 2);
2006
- let path = line.substring(3);
2007
- path = path.replace(/^"(.*)"$/, "$1");
3284
+ let path2 = line.substring(3);
3285
+ path2 = path2.replace(/^"(.*)"$/, "$1");
2008
3286
  let status = "modified";
2009
3287
  if (line.startsWith("??")) {
2010
3288
  status = "untracked";
@@ -2013,7 +3291,7 @@ var GitManager = class {
2013
3291
  } else if (/^.[MD]/.test(statusCode)) {
2014
3292
  status = "unstaged";
2015
3293
  }
2016
- return { path, status, statusCode };
3294
+ return { path: path2, status, statusCode };
2017
3295
  });
2018
3296
  const staged = files.filter((f) => f.status === "staged").length;
2019
3297
  const unstaged = files.filter((f) => f.status === "unstaged").length;
@@ -2278,7 +3556,7 @@ var GitManager = class {
2278
3556
  * 检查仓库是否包含 submodule
2279
3557
  */
2280
3558
  hasSubmodules() {
2281
- return existsSync6(resolve(this.dir, ".gitmodules"));
3559
+ return existsSync7(resolve2(this.dir, ".gitmodules"));
2282
3560
  }
2283
3561
  /**
2284
3562
  * 获取所有 submodule 的路径
@@ -2302,7 +3580,7 @@ var GitManager = class {
2302
3580
  const paths = await this.getSubmodulePaths();
2303
3581
  if (paths.length === 0) return;
2304
3582
  for (const subPath of paths) {
2305
- const absPath = resolve(this.dir, subPath);
3583
+ const absPath = resolve2(this.dir, subPath);
2306
3584
  let hasChanges = false;
2307
3585
  try {
2308
3586
  const status = await runCommand("git status --porcelain", absPath);
@@ -2406,8 +3684,9 @@ var GitManager = class {
2406
3684
  // core/ProcessManager.ts
2407
3685
  import { spawn } from "child_process";
2408
3686
  var ProcessManager = class {
3687
+ processes = /* @__PURE__ */ new Map();
3688
+ logger;
2409
3689
  constructor() {
2410
- this.processes = /* @__PURE__ */ new Map();
2411
3690
  this.logger = new Logger({ prefix: "process" });
2412
3691
  process.on("exit", () => {
2413
3692
  this.killAll();
@@ -2528,6 +3807,7 @@ var ProcessManager = class {
2528
3807
 
2529
3808
  // services/git/service.ts
2530
3809
  var GitService = class {
3810
+ gitManager;
2531
3811
  constructor() {
2532
3812
  this.gitManager = new GitManager(ROOT_DIR_PATH);
2533
3813
  }
@@ -2603,26 +3883,26 @@ var GitService = class {
2603
3883
  };
2604
3884
 
2605
3885
  // services/sync-core/service.ts
2606
- import { existsSync as existsSync7 } from "fs";
2607
- import { join as join7, basename as basename2 } from "path";
3886
+ import { existsSync as existsSync8 } from "fs";
3887
+ import { join as join9, basename as basename2 } from "path";
2608
3888
  var SyncCoreService = class {
2609
3889
  /**
2610
3890
  * 同步单个仓库的 submodule 到最新版本
2611
3891
  */
2612
3892
  async syncSingleRepo(targetDir) {
2613
- const repoName = basename2(targetDir);
2614
- const submodulePath = join7(targetDir, ".vitepress", "tnotes");
3893
+ const repoName2 = basename2(targetDir);
3894
+ const submodulePath = join9(targetDir, ".vitepress", "tnotes");
2615
3895
  try {
2616
- if (!existsSync7(join7(targetDir, ".gitmodules"))) {
3896
+ if (!existsSync8(join9(targetDir, ".gitmodules"))) {
2617
3897
  return {
2618
3898
  dir: targetDir,
2619
- repoName,
3899
+ repoName: repoName2,
2620
3900
  success: false,
2621
3901
  updated: false,
2622
3902
  error: "\u672A\u627E\u5230 .gitmodules\uFF0C\u8BE5\u4ED3\u5E93\u672A\u914D\u7F6E submodule"
2623
3903
  };
2624
3904
  }
2625
- if (!existsSync7(submodulePath)) {
3905
+ if (!existsSync8(submodulePath)) {
2626
3906
  await runCommand("git submodule update --init", targetDir);
2627
3907
  }
2628
3908
  const beforeHash = (await runCommand("git rev-parse HEAD", submodulePath)).trim();
@@ -2634,11 +3914,14 @@ var SyncCoreService = class {
2634
3914
  const updated = beforeHash !== afterHash;
2635
3915
  if (updated) {
2636
3916
  await runCommand("git add .vitepress/tnotes", targetDir);
2637
- await runCommand('git commit -m "chore: update TNotes.core"', targetDir);
3917
+ await runCommand(
3918
+ 'git commit -m "chore: update tnotesjs/core"',
3919
+ targetDir
3920
+ );
2638
3921
  }
2639
3922
  return {
2640
3923
  dir: targetDir,
2641
- repoName,
3924
+ repoName: repoName2,
2642
3925
  success: true,
2643
3926
  updated,
2644
3927
  beforeHash: beforeHash.substring(0, 7),
@@ -2650,7 +3933,7 @@ var SyncCoreService = class {
2650
3933
  const errorMessage = error instanceof Error ? error.message : String(error);
2651
3934
  return {
2652
3935
  dir: targetDir,
2653
- repoName,
3936
+ repoName: repoName2,
2654
3937
  success: false,
2655
3938
  updated: false,
2656
3939
  error: errorMessage
@@ -2658,7 +3941,7 @@ var SyncCoreService = class {
2658
3941
  }
2659
3942
  }
2660
3943
  /**
2661
- * 同步所有兄弟仓库的 TNotes.core 到最新版本
3944
+ * 同步所有兄弟仓库的 tnotesjs/core 到最新版本
2662
3945
  */
2663
3946
  async syncToAllRepos() {
2664
3947
  try {
@@ -2671,13 +3954,13 @@ var SyncCoreService = class {
2671
3954
  logger.warn("\u672A\u627E\u5230\u7B26\u5408\u6761\u4EF6\u7684\u76EE\u6807\u76EE\u5F55");
2672
3955
  return;
2673
3956
  }
2674
- logger.info(`\u6B63\u5728\u540C\u6B65 ${targetDirs.length} \u4E2A\u4ED3\u5E93\u7684 TNotes.core...`);
3957
+ logger.info(`\u6B63\u5728\u540C\u6B65 ${targetDirs.length} \u4E2A\u4ED3\u5E93\u7684 tnotesjs/core...`);
2675
3958
  console.log();
2676
3959
  const results = [];
2677
3960
  for (let i = 0; i < targetDirs.length; i++) {
2678
3961
  const dir = targetDirs[i];
2679
- const repoName = basename2(dir);
2680
- logger.info(`[${i + 1}/${targetDirs.length}] ${repoName}`);
3962
+ const repoName2 = basename2(dir);
3963
+ logger.info(`[${i + 1}/${targetDirs.length}] ${repoName2}`);
2681
3964
  const result = await this.syncSingleRepo(dir);
2682
3965
  results.push(result);
2683
3966
  if (result.success) {
@@ -2717,7 +4000,7 @@ var SyncCoreService = class {
2717
4000
  }
2718
4001
  } catch (error) {
2719
4002
  const errorMessage = error instanceof Error ? error.message : String(error);
2720
- logger.error(`TNotes.core \u540C\u6B65\u5931\u8D25: ${errorMessage}`);
4003
+ logger.error(`tnotesjs/core \u540C\u6B65\u5931\u8D25: ${errorMessage}`);
2721
4004
  throw error;
2722
4005
  }
2723
4006
  }
@@ -2725,16 +4008,17 @@ var SyncCoreService = class {
2725
4008
 
2726
4009
  // services/timestamp/service.ts
2727
4010
  import {
2728
- existsSync as existsSync8,
2729
- readFileSync as readFileSync5,
2730
- writeFileSync as writeFileSync4,
2731
- readdirSync as readdirSync2,
4011
+ existsSync as existsSync9,
4012
+ readFileSync as readFileSync6,
4013
+ writeFileSync as writeFileSync5,
4014
+ readdirSync as readdirSync4,
2732
4015
  statSync as statSync2
2733
4016
  } from "fs";
2734
- import { join as join8 } from "path";
2735
- import { execSync } from "child_process";
4017
+ import { join as join10 } from "path";
4018
+ import { execSync as execSync3 } from "child_process";
2736
4019
  var BIRTH_DATE = (/* @__PURE__ */ new Date("1999-06-29T00:00:00+08:00")).getTime();
2737
4020
  var TimestampService = class {
4021
+ noteManager;
2738
4022
  constructor() {
2739
4023
  this.noteManager = NoteManager.getInstance();
2740
4024
  }
@@ -2745,8 +4029,8 @@ var TimestampService = class {
2745
4029
  */
2746
4030
  getGitTimestamps(noteDirPath) {
2747
4031
  try {
2748
- const readmePath = join8(noteDirPath, "README.md");
2749
- const createdAtOutput = execSync(
4032
+ const readmePath = join10(noteDirPath, "README.md");
4033
+ const createdAtOutput = execSync3(
2750
4034
  `git log --diff-filter=A --follow --format=%ct -- "${readmePath}"`,
2751
4035
  {
2752
4036
  cwd: ROOT_DIR_PATH,
@@ -2754,7 +4038,7 @@ var TimestampService = class {
2754
4038
  stdio: ["pipe", "pipe", "ignore"]
2755
4039
  }
2756
4040
  ).split(/\r?\n/).filter(Boolean).pop();
2757
- const updatedAtOutput = execSync(
4041
+ const updatedAtOutput = execSync3(
2758
4042
  `git log -1 --format=%ct -- "${readmePath}"`,
2759
4043
  {
2760
4044
  cwd: ROOT_DIR_PATH,
@@ -2782,39 +4066,39 @@ var TimestampService = class {
2782
4066
  * @returns 是否进行了修复
2783
4067
  */
2784
4068
  fixNoteTimestamps(noteDir, forceUpdate = false) {
2785
- const configPath = join8(NOTES_DIR_PATH, noteDir, ".tnotes.json");
2786
- if (!existsSync8(configPath)) {
4069
+ const configPath = join10(NOTES_DIR_PATH, noteDir, ".tnotes.json");
4070
+ if (!existsSync9(configPath)) {
2787
4071
  return false;
2788
4072
  }
2789
4073
  try {
2790
- const configContent = readFileSync5(configPath, "utf-8");
2791
- const config = JSON.parse(configContent);
2792
- const noteDirPath = join8(NOTES_DIR_PATH, noteDir);
4074
+ const configContent = readFileSync6(configPath, "utf-8");
4075
+ const config2 = JSON.parse(configContent);
4076
+ const noteDirPath = join10(NOTES_DIR_PATH, noteDir);
2793
4077
  const timestamps = this.getGitTimestamps(noteDirPath);
2794
4078
  if (!timestamps) {
2795
4079
  return false;
2796
4080
  }
2797
4081
  let modified = false;
2798
- if (forceUpdate || !config.created_at || config.created_at !== timestamps.created_at) {
2799
- config.created_at = timestamps.created_at;
4082
+ if (forceUpdate || !config2.created_at || config2.created_at !== timestamps.created_at) {
4083
+ config2.created_at = timestamps.created_at;
2800
4084
  modified = true;
2801
4085
  }
2802
4086
  if (forceUpdate) {
2803
- if (config.updated_at !== timestamps.updated_at) {
2804
- config.updated_at = timestamps.updated_at;
4087
+ if (config2.updated_at !== timestamps.updated_at) {
4088
+ config2.updated_at = timestamps.updated_at;
2805
4089
  modified = true;
2806
4090
  }
2807
4091
  } else {
2808
- if (!config.updated_at) {
2809
- config.updated_at = timestamps.updated_at;
4092
+ if (!config2.updated_at) {
4093
+ config2.updated_at = timestamps.updated_at;
2810
4094
  modified = true;
2811
- } else if (timestamps.updated_at > config.updated_at) {
2812
- config.updated_at = timestamps.updated_at;
4095
+ } else if (timestamps.updated_at > config2.updated_at) {
4096
+ config2.updated_at = timestamps.updated_at;
2813
4097
  modified = true;
2814
4098
  }
2815
4099
  }
2816
4100
  if (modified) {
2817
- this.noteManager.writeNoteConfig(configPath, config);
4101
+ this.noteManager.writeNoteConfig(configPath, config2);
2818
4102
  return true;
2819
4103
  }
2820
4104
  return false;
@@ -2830,14 +4114,14 @@ var TimestampService = class {
2830
4114
  */
2831
4115
  fixRootConfigTimestamps(forceUpdate = false) {
2832
4116
  try {
2833
- const configContent = readFileSync5(ROOT_CONFIG_PATH, "utf-8");
2834
- const config = JSON.parse(configContent);
2835
- const createdAtOutput = execSync("git log --reverse --format=%ct", {
4117
+ const configContent = readFileSync6(ROOT_CONFIG_PATH, "utf-8");
4118
+ const config2 = JSON.parse(configContent);
4119
+ const createdAtOutput = execSync3("git log --reverse --format=%ct", {
2836
4120
  cwd: ROOT_DIR_PATH,
2837
4121
  encoding: "utf-8",
2838
4122
  stdio: ["pipe", "pipe", "ignore"]
2839
4123
  }).trim();
2840
- const updatedAtOutput = execSync("git log -1 --format=%ct", {
4124
+ const updatedAtOutput = execSync3("git log -1 --format=%ct", {
2841
4125
  cwd: ROOT_DIR_PATH,
2842
4126
  encoding: "utf-8",
2843
4127
  stdio: ["pipe", "pipe", "ignore"]
@@ -2849,20 +4133,20 @@ var TimestampService = class {
2849
4133
  const createdAt = parseInt(firstTimestamp) * 1e3;
2850
4134
  const updatedAt = parseInt(updatedAtOutput) * 1e3;
2851
4135
  let modified = false;
2852
- if (forceUpdate || !config.root_item.created_at || config.root_item.created_at !== createdAt) {
2853
- config.root_item.created_at = createdAt;
4136
+ if (forceUpdate || !config2.root_item.created_at || config2.root_item.created_at !== createdAt) {
4137
+ config2.root_item.created_at = createdAt;
2854
4138
  modified = true;
2855
4139
  }
2856
- if (forceUpdate || !config.root_item.updated_at || config.root_item.updated_at !== updatedAt) {
2857
- config.root_item.updated_at = updatedAt;
4140
+ if (forceUpdate || !config2.root_item.updated_at || config2.root_item.updated_at !== updatedAt) {
4141
+ config2.root_item.updated_at = updatedAt;
2858
4142
  modified = true;
2859
4143
  }
2860
4144
  if (modified) {
2861
4145
  const daysSinceBirth = Math.floor((updatedAt - BIRTH_DATE) / (1e3 * 60 * 60 * 24)) + 1;
2862
- config.root_item.days_since_birth = daysSinceBirth;
2863
- writeFileSync4(
4146
+ config2.root_item.days_since_birth = daysSinceBirth;
4147
+ writeFileSync5(
2864
4148
  ROOT_CONFIG_PATH,
2865
- JSON.stringify(config, null, 2) + "\n",
4149
+ JSON.stringify(config2, null, 2) + "\n",
2866
4150
  "utf-8"
2867
4151
  );
2868
4152
  return true;
@@ -2888,12 +4172,12 @@ var TimestampService = class {
2888
4172
  if (rootConfigFixed) {
2889
4173
  logger.success("\u2705 \u6839\u914D\u7F6E\u6587\u4EF6\u65F6\u95F4\u6233\u5DF2\u4FEE\u590D");
2890
4174
  }
2891
- if (!existsSync8(NOTES_DIR_PATH)) {
4175
+ if (!existsSync9(NOTES_DIR_PATH)) {
2892
4176
  logger.error("notes \u76EE\u5F55\u4E0D\u5B58\u5728");
2893
4177
  return { fixed: 0, skipped: 0, total: 0, rootConfigFixed };
2894
4178
  }
2895
- const noteDirs = readdirSync2(NOTES_DIR_PATH).filter((name) => {
2896
- const fullPath = join8(NOTES_DIR_PATH, name);
4179
+ const noteDirs = readdirSync4(NOTES_DIR_PATH).filter((name) => {
4180
+ const fullPath = join10(NOTES_DIR_PATH, name);
2897
4181
  return statSync2(fullPath).isDirectory() && /^\d{4}\./.test(name);
2898
4182
  }).sort();
2899
4183
  let fixedCount = 0;
@@ -2930,15 +4214,15 @@ var TimestampService = class {
2930
4214
  const now = Date.now();
2931
4215
  let updatedCount = 0;
2932
4216
  for (const noteDir of noteDirNames) {
2933
- const configPath = join8(NOTES_DIR_PATH, noteDir, ".tnotes.json");
2934
- if (!existsSync8(configPath)) {
4217
+ const configPath = join10(NOTES_DIR_PATH, noteDir, ".tnotes.json");
4218
+ if (!existsSync9(configPath)) {
2935
4219
  continue;
2936
4220
  }
2937
4221
  try {
2938
- const configContent = readFileSync5(configPath, "utf-8");
2939
- const config = JSON.parse(configContent);
2940
- config.updated_at = now;
2941
- this.noteManager.writeNoteConfig(configPath, config);
4222
+ const configContent = readFileSync6(configPath, "utf-8");
4223
+ const config2 = JSON.parse(configContent);
4224
+ config2.updated_at = now;
4225
+ this.noteManager.writeNoteConfig(configPath, config2);
2942
4226
  updatedCount++;
2943
4227
  } catch (error) {
2944
4228
  logger.error(`\u66F4\u65B0\u65F6\u95F4\u6233\u5931\u8D25: ${noteDir}`, error);
@@ -2967,42 +4251,26 @@ var TimestampService = class {
2967
4251
  // services/vitepress/service.ts
2968
4252
  import { spawn as spawn2 } from "child_process";
2969
4253
  var VitepressService = class _VitepressService {
2970
- static {
2971
- /** VitePress 开发服务器默认端口 */
2972
- this.DEFAULT_DEV_PORT = 5173;
2973
- }
2974
- static {
2975
- /** VitePress 预览服务器默认端口 */
2976
- this.DEFAULT_PREVIEW_PORT = 4173;
2977
- }
2978
- static {
2979
- /** 开发服务器进程 ID 后缀 */
2980
- this.PROCESS_ID_DEV_SUFFIX = "vitepress-dev";
2981
- }
2982
- static {
2983
- /** 预览服务器进程 ID 后缀 */
2984
- this.PROCESS_ID_PREVIEW_SUFFIX = "vitepress-preview";
2985
- }
2986
- static {
2987
- /** 服务启动超时时间(毫秒) */
2988
- this.SERVER_STARTUP_TIMEOUT = 6e4;
2989
- }
2990
- static {
2991
- /** 端口释放等待超时时间(毫秒) */
2992
- this.PORT_RELEASE_TIMEOUT = 3e3;
2993
- }
2994
- static {
2995
- /** 进程清理等待时间(毫秒) */
2996
- this.PROCESS_CLEANUP_DELAY = 3e3;
2997
- }
2998
- static {
2999
- /** 显示启动服务状态行间隔(毫秒) */
3000
- this.SERVER_STATUS_LINE_INTERVAL = 1e3;
3001
- }
3002
- static {
3003
- /** 默认包管理器 */
3004
- this.DEFAULT_PACKAGE_MANAGER = "pnpm";
3005
- }
4254
+ /** VitePress 开发服务器默认端口 */
4255
+ static DEFAULT_DEV_PORT = 5173;
4256
+ /** VitePress 预览服务器默认端口 */
4257
+ static DEFAULT_PREVIEW_PORT = 4173;
4258
+ /** 开发服务器进程 ID 后缀 */
4259
+ static PROCESS_ID_DEV_SUFFIX = "vitepress-dev";
4260
+ /** 预览服务器进程 ID 后缀 */
4261
+ static PROCESS_ID_PREVIEW_SUFFIX = "vitepress-preview";
4262
+ /** 服务启动超时时间(毫秒) */
4263
+ static SERVER_STARTUP_TIMEOUT = 6e4;
4264
+ /** 端口释放等待超时时间(毫秒) */
4265
+ static PORT_RELEASE_TIMEOUT = 3e3;
4266
+ /** 进程清理等待时间(毫秒) */
4267
+ static PROCESS_CLEANUP_DELAY = 3e3;
4268
+ /** 显示启动服务状态行间隔(毫秒) */
4269
+ static SERVER_STATUS_LINE_INTERVAL = 1e3;
4270
+ /** 默认包管理器 */
4271
+ static DEFAULT_PACKAGE_MANAGER = "pnpm";
4272
+ processManager;
4273
+ configManager;
3006
4274
  constructor() {
3007
4275
  this.processManager = new ProcessManager();
3008
4276
  this.configManager = ConfigManager.getInstance();
@@ -3012,32 +4280,32 @@ var VitepressService = class _VitepressService {
3012
4280
  * @returns 启动结果(服务就绪后返回),失败时返回 undefined
3013
4281
  */
3014
4282
  async startServer() {
3015
- const port = this.configManager.get("port") || _VitepressService.DEFAULT_DEV_PORT;
3016
- const repoName = this.configManager.get("repoName");
3017
- const processId = `${repoName}-${_VitepressService.PROCESS_ID_DEV_SUFFIX}`;
4283
+ const port2 = this.configManager.get("port") || _VitepressService.DEFAULT_DEV_PORT;
4284
+ const repoName2 = this.configManager.get("repoName");
4285
+ const processId = `${repoName2}-${_VitepressService.PROCESS_ID_DEV_SUFFIX}`;
3018
4286
  if (this.processManager.has(processId) && this.processManager.isRunning(processId)) {
3019
4287
  this.processManager.kill(processId);
3020
4288
  await new Promise(
3021
- (resolve3) => setTimeout(resolve3, _VitepressService.PROCESS_CLEANUP_DELAY)
4289
+ (resolve4) => setTimeout(resolve4, _VitepressService.PROCESS_CLEANUP_DELAY)
3022
4290
  );
3023
4291
  }
3024
- if (isPortInUse(port)) {
3025
- logger.warn(`\u7AEF\u53E3 ${port} \u88AB\u5360\u7528\uFF0C\u6B63\u5728\u6E05\u7406...`);
3026
- killPortProcess(port);
4292
+ if (isPortInUse(port2)) {
4293
+ logger.warn(`\u7AEF\u53E3 ${port2} \u88AB\u5360\u7528\uFF0C\u6B63\u5728\u6E05\u7406...`);
4294
+ killPortProcess(port2);
3027
4295
  const available = await waitForPort(
3028
- port,
4296
+ port2,
3029
4297
  _VitepressService.PORT_RELEASE_TIMEOUT
3030
4298
  );
3031
4299
  if (available) {
3032
- logger.info(`\u7AEF\u53E3 ${port} \u5DF2\u91CA\u653E\uFF0C\u7EE7\u7EED\u542F\u52A8\u670D\u52A1`);
4300
+ logger.info(`\u7AEF\u53E3 ${port2} \u5DF2\u91CA\u653E\uFF0C\u7EE7\u7EED\u542F\u52A8\u670D\u52A1`);
3033
4301
  } else {
3034
4302
  logger.warn(
3035
- `\u7AEF\u53E3 ${port} \u672A\u786E\u8BA4\u91CA\u653E\uFF0C\u4ECD\u5C06\u5C1D\u8BD5\u542F\u52A8\uFF1B\u5982\u542F\u52A8\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u6E05\u7406\u8BE5\u7AEF\u53E3`
4303
+ `\u7AEF\u53E3 ${port2} \u672A\u786E\u8BA4\u91CA\u653E\uFF0C\u4ECD\u5C06\u5C1D\u8BD5\u542F\u52A8\uFF1B\u5982\u542F\u52A8\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u6E05\u7406\u8BE5\u7AEF\u53E3`
3036
4304
  );
3037
4305
  }
3038
4306
  }
3039
4307
  const pm = this.configManager.get("packageManager") || _VitepressService.DEFAULT_PACKAGE_MANAGER;
3040
- const args = ["vitepress", "dev", "--port", port.toString()];
4308
+ const args = ["vitepress", "dev", "--port", port2.toString()];
3041
4309
  const processInfo = this.processManager.spawn(processId, pm, args, {
3042
4310
  cwd: ROOT_DIR_PATH,
3043
4311
  stdio: ["inherit", "pipe", "pipe"]
@@ -3056,7 +4324,7 @@ var VitepressService = class _VitepressService {
3056
4324
  * @param childProcess - 子进程
3057
4325
  */
3058
4326
  waitForServerReady(childProcess) {
3059
- return new Promise((resolve3) => {
4327
+ return new Promise((resolve4) => {
3060
4328
  const startTime = Date.now();
3061
4329
  let serverReady = false;
3062
4330
  let version = "";
@@ -3083,7 +4351,7 @@ var VitepressService = class _VitepressService {
3083
4351
  process.stderr.clearLine?.(0);
3084
4352
  process.stderr.cursorTo?.(0);
3085
4353
  const elapsed = Date.now() - startTime;
3086
- setTimeout(() => resolve3({ version, elapsed }), 200);
4354
+ setTimeout(() => resolve4({ version, elapsed }), 200);
3087
4355
  return;
3088
4356
  }
3089
4357
  if (!serverReady) {
@@ -3109,7 +4377,7 @@ var VitepressService = class _VitepressService {
3109
4377
  process.stderr.clearLine?.(0);
3110
4378
  process.stderr.cursorTo?.(0);
3111
4379
  logger.warn("\u542F\u52A8\u8D85\u65F6\uFF0C\u8BF7\u68C0\u67E5 VitePress \u8F93\u51FA");
3112
- resolve3({ version, elapsed: _VitepressService.SERVER_STARTUP_TIMEOUT });
4380
+ resolve4({ version, elapsed: _VitepressService.SERVER_STARTUP_TIMEOUT });
3113
4381
  }
3114
4382
  }, _VitepressService.SERVER_STARTUP_TIMEOUT);
3115
4383
  });
@@ -3118,7 +4386,7 @@ var VitepressService = class _VitepressService {
3118
4386
  * 构建生产版本
3119
4387
  */
3120
4388
  build() {
3121
- return new Promise((resolve3, reject) => {
4389
+ return new Promise((resolve4, reject) => {
3122
4390
  const pm = this.configManager.get("packageManager") || _VitepressService.DEFAULT_PACKAGE_MANAGER;
3123
4391
  const child = spawn2(pm, ["vitepress", "build"], {
3124
4392
  cwd: ROOT_DIR_PATH,
@@ -3142,7 +4410,7 @@ var VitepressService = class _VitepressService {
3142
4410
  });
3143
4411
  child.on("close", (code) => {
3144
4412
  if (code === 0) {
3145
- resolve3();
4413
+ resolve4();
3146
4414
  } else {
3147
4415
  reject(new Error(`Command failed with code ${code}`));
3148
4416
  }
@@ -3153,8 +4421,8 @@ var VitepressService = class _VitepressService {
3153
4421
  * 预览构建后的站点
3154
4422
  */
3155
4423
  async preview() {
3156
- const repoName = this.configManager.get("repoName");
3157
- const processId = `${repoName}-${_VitepressService.PROCESS_ID_PREVIEW_SUFFIX}`;
4424
+ const repoName2 = this.configManager.get("repoName");
4425
+ const processId = `${repoName2}-${_VitepressService.PROCESS_ID_PREVIEW_SUFFIX}`;
3158
4426
  const pm = this.configManager.get("packageManager") || _VitepressService.DEFAULT_PACKAGE_MANAGER;
3159
4427
  const args = ["vitepress", "preview"];
3160
4428
  const previewPort = _VitepressService.DEFAULT_PREVIEW_PORT;
@@ -3187,13 +4455,15 @@ var VitepressService = class _VitepressService {
3187
4455
  };
3188
4456
 
3189
4457
  // commands/update/UpdateCommand.ts
3190
- import { existsSync as existsSync9, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
3191
- import { resolve as resolve2 } from "path";
4458
+ import { existsSync as existsSync10, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
4459
+ import { resolve as resolve3 } from "path";
3192
4460
  var UpdateCommand = class extends BaseCommand {
4461
+ readmeService;
4462
+ noteService;
4463
+ quiet = false;
4464
+ updateAll = false;
3193
4465
  constructor() {
3194
4466
  super("update");
3195
- this.quiet = false;
3196
- this.updateAll = false;
3197
4467
  this.readmeService = ReadmeService.getInstance();
3198
4468
  this.noteService = NoteService.getInstance();
3199
4469
  }
@@ -3263,10 +4533,10 @@ var UpdateCommand = class extends BaseCommand {
3263
4533
  let failCount = 0;
3264
4534
  for (let i = 0; i < targetDirs.length; i++) {
3265
4535
  const dir = targetDirs[i];
3266
- const repoName = dir.split("/").pop() || dir;
4536
+ const repoName2 = dir.split("/").pop() || dir;
3267
4537
  try {
3268
4538
  process.stdout.write(
3269
- `\r [${i + 1}/${targetDirs.length}] \u6B63\u5728\u66F4\u65B0: ${repoName}...`
4539
+ `\r [${i + 1}/${targetDirs.length}] \u6B63\u5728\u66F4\u65B0: ${repoName2}...`
3270
4540
  );
3271
4541
  await runCommand("pnpm tn:update --quiet", dir);
3272
4542
  successCount++;
@@ -3274,7 +4544,7 @@ var UpdateCommand = class extends BaseCommand {
3274
4544
  failCount++;
3275
4545
  console.log();
3276
4546
  this.logger.error(
3277
- `\u66F4\u65B0\u5931\u8D25: ${repoName} - ${error instanceof Error ? error.message : String(error)}`
4547
+ `\u66F4\u65B0\u5931\u8D25: ${repoName2} - ${error instanceof Error ? error.message : String(error)}`
3278
4548
  );
3279
4549
  }
3280
4550
  }
@@ -3301,30 +4571,30 @@ var UpdateCommand = class extends BaseCommand {
3301
4571
  */
3302
4572
  async updateRootItem() {
3303
4573
  try {
3304
- const configContent = readFileSync6(ROOT_CONFIG_PATH, "utf-8");
3305
- const config = JSON.parse(configContent);
3306
- const readmePath = resolve2(ROOT_DIR_PATH, "README.md");
3307
- if (!existsSync9(readmePath)) {
4574
+ const configContent = readFileSync7(ROOT_CONFIG_PATH, "utf-8");
4575
+ const config2 = JSON.parse(configContent);
4576
+ const readmePath = resolve3(ROOT_DIR_PATH, "README.md");
4577
+ if (!existsSync10(readmePath)) {
3308
4578
  throw new Error("\u6839\u76EE\u5F55 README.md \u4E0D\u5B58\u5728");
3309
4579
  }
3310
- const readmeContent = readFileSync6(readmePath, "utf-8");
4580
+ const readmeContent = readFileSync7(readmePath, "utf-8");
3311
4581
  const { completedCount } = parseReadmeCompletedNotes(readmeContent);
3312
4582
  const now = /* @__PURE__ */ new Date();
3313
4583
  const yearShort = String(now.getFullYear()).slice(-2);
3314
4584
  const monthStr = String(now.getMonth() + 1).padStart(2, "0");
3315
4585
  const currentKey = `${yearShort}.${monthStr}`;
3316
4586
  const completedNotesCount = {
3317
- ...config.root_item.completed_notes_count || {},
4587
+ ...config2.root_item.completed_notes_count || {},
3318
4588
  [currentKey]: completedCount
3319
4589
  };
3320
4590
  const updatedAt = Date.now();
3321
- config.root_item = {
3322
- ...config.root_item,
4591
+ config2.root_item = {
4592
+ ...config2.root_item,
3323
4593
  completed_notes_count: completedNotesCount,
3324
4594
  updated_at: updatedAt
3325
4595
  };
3326
- delete config.root_item.completed_notes_count_last_month;
3327
- writeFileSync5(ROOT_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
4596
+ delete config2.root_item.completed_notes_count_last_month;
4597
+ writeFileSync6(ROOT_CONFIG_PATH, JSON.stringify(config2, null, 2), "utf-8");
3328
4598
  if (!this.quiet) {
3329
4599
  this.logger.success(
3330
4600
  `root_item \u914D\u7F6E\u5DF2\u66F4\u65B0: ${currentKey} \u6708\u5B8C\u6210 ${completedCount} \u7BC7\u7B14\u8BB0`
@@ -3342,12 +4612,12 @@ var UpdateCommand = class extends BaseCommand {
3342
4612
  };
3343
4613
 
3344
4614
  // commands/update-completed-count/UpdateCompletedCountCommand.ts
3345
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
3346
- import { execSync as execSync2 } from "child_process";
4615
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
4616
+ import { execSync as execSync4 } from "child_process";
3347
4617
  var UpdateCompletedCountCommand = class extends BaseCommand {
4618
+ updateAll = false;
3348
4619
  constructor() {
3349
4620
  super("update-completed-count");
3350
- this.updateAll = false;
3351
4621
  }
3352
4622
  /**
3353
4623
  * 设置是否更新所有知识库
@@ -3368,16 +4638,16 @@ var UpdateCompletedCountCommand = class extends BaseCommand {
3368
4638
  async updateCurrentRepo() {
3369
4639
  const startTime = Date.now();
3370
4640
  try {
3371
- const configContent = readFileSync7(ROOT_CONFIG_PATH, "utf-8");
3372
- const config = JSON.parse(configContent);
4641
+ const configContent = readFileSync8(ROOT_CONFIG_PATH, "utf-8");
4642
+ const config2 = JSON.parse(configContent);
3373
4643
  this.logger.info("\u5F00\u59CB\u66F4\u65B0\u5B8C\u6210\u7B14\u8BB0\u6570\u91CF\u5386\u53F2\u8BB0\u5F55...");
3374
- const completedNotesCountHistory = await this.getCompletedNotesCountHistory(config.root_item.created_at);
3375
- config.root_item = {
3376
- ...config.root_item,
4644
+ const completedNotesCountHistory = await this.getCompletedNotesCountHistory(config2.root_item.created_at);
4645
+ config2.root_item = {
4646
+ ...config2.root_item,
3377
4647
  completed_notes_count: completedNotesCountHistory,
3378
4648
  updated_at: Date.now()
3379
4649
  };
3380
- writeFileSync6(ROOT_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
4650
+ writeFileSync7(ROOT_CONFIG_PATH, JSON.stringify(config2, null, 2), "utf-8");
3381
4651
  const duration = Date.now() - startTime;
3382
4652
  const monthKeys = Object.keys(completedNotesCountHistory);
3383
4653
  const currentKey = monthKeys[monthKeys.length - 1];
@@ -3412,10 +4682,10 @@ var UpdateCompletedCountCommand = class extends BaseCommand {
3412
4682
  let failCount = 0;
3413
4683
  for (let i = 0; i < targetDirs.length; i++) {
3414
4684
  const dir = targetDirs[i];
3415
- const repoName = dir.split("/").pop() || dir;
4685
+ const repoName2 = dir.split("/").pop() || dir;
3416
4686
  try {
3417
4687
  process.stdout.write(
3418
- `\r [${i + 1}/${targetDirs.length}] \u6B63\u5728\u66F4\u65B0: ${repoName}...`
4688
+ `\r [${i + 1}/${targetDirs.length}] \u6B63\u5728\u66F4\u65B0: ${repoName2}...`
3419
4689
  );
3420
4690
  await runCommand("pnpm tn:update-completed-count", dir);
3421
4691
  successCount++;
@@ -3423,7 +4693,7 @@ var UpdateCompletedCountCommand = class extends BaseCommand {
3423
4693
  failCount++;
3424
4694
  console.log();
3425
4695
  this.logger.error(
3426
- `\u66F4\u65B0\u5931\u8D25: ${repoName} - ${error instanceof Error ? error.message : String(error)}`
4696
+ `\u66F4\u65B0\u5931\u8D25: ${repoName2} - ${error instanceof Error ? error.message : String(error)}`
3427
4697
  );
3428
4698
  }
3429
4699
  }
@@ -3518,7 +4788,7 @@ var UpdateCompletedCountCommand = class extends BaseCommand {
3518
4788
  const monthStr = String(lastDayOfMonth.getMonth() + 1).padStart(2, "0");
3519
4789
  const dayStr = String(lastDayOfMonth.getDate()).padStart(2, "0");
3520
4790
  const untilDate = `${yearStr}-${monthStr}-${dayStr} 23:59:59 +0800`;
3521
- const commitHash = execSync2(
4791
+ const commitHash = execSync4(
3522
4792
  `git log --until="${untilDate}" --format=%H -1 -- README.md`,
3523
4793
  {
3524
4794
  cwd: ROOT_DIR_PATH,
@@ -3530,7 +4800,7 @@ var UpdateCompletedCountCommand = class extends BaseCommand {
3530
4800
  }
3531
4801
  let readmeContent;
3532
4802
  try {
3533
- readmeContent = execSync2(`git show ${commitHash}:README.md`, {
4803
+ readmeContent = execSync4(`git show ${commitHash}:README.md`, {
3534
4804
  cwd: ROOT_DIR_PATH,
3535
4805
  encoding: "utf-8"
3536
4806
  });
@@ -3544,9 +4814,11 @@ var UpdateCompletedCountCommand = class extends BaseCommand {
3544
4814
 
3545
4815
  // commands/git/PushCommand.ts
3546
4816
  var PushCommand = class extends BaseCommand {
4817
+ gitService;
4818
+ timestampService;
4819
+ pushAll = false;
3547
4820
  constructor() {
3548
4821
  super("push");
3549
- this.pushAll = false;
3550
4822
  this.gitService = new GitService();
3551
4823
  this.timestampService = new TimestampService();
3552
4824
  }
@@ -3610,9 +4882,10 @@ var PushCommand = class extends BaseCommand {
3610
4882
 
3611
4883
  // commands/git/PullCommand.ts
3612
4884
  var PullCommand = class extends BaseCommand {
4885
+ gitService;
4886
+ pullAll = false;
3613
4887
  constructor() {
3614
4888
  super("pull");
3615
- this.pullAll = false;
3616
4889
  this.gitService = new GitService();
3617
4890
  }
3618
4891
  /**
@@ -3638,9 +4911,10 @@ var PullCommand = class extends BaseCommand {
3638
4911
 
3639
4912
  // commands/git/SyncCommand.ts
3640
4913
  var SyncCommand = class extends BaseCommand {
4914
+ gitService;
4915
+ syncAll = false;
3641
4916
  constructor() {
3642
4917
  super("sync");
3643
- this.syncAll = false;
3644
4918
  this.gitService = new GitService();
3645
4919
  }
3646
4920
  /**
@@ -3668,6 +4942,11 @@ var SyncCommand = class extends BaseCommand {
3668
4942
 
3669
4943
  // commands/dev/DevCommand.ts
3670
4944
  var DevCommand = class extends BaseCommand {
4945
+ fileWatcherService;
4946
+ vitepressService;
4947
+ noteManager;
4948
+ noteIndexCache;
4949
+ configManager;
3671
4950
  constructor() {
3672
4951
  super("dev");
3673
4952
  this.fileWatcherService = new FileWatcherService();
@@ -3690,10 +4969,10 @@ var DevCommand = class extends BaseCommand {
3690
4969
  this.fileWatcherService.start();
3691
4970
  const watcherElapsed = Date.now() - watcherStart;
3692
4971
  this.logger.success(`\u6587\u4EF6\u76D1\u542C\u670D\u52A1\u5DF2\u5C31\u7EEA\uFF0C\u8017\u65F6\uFF1A${watcherElapsed} ms`);
3693
- const port = this.configManager.get("port") || VitepressService.DEFAULT_DEV_PORT;
3694
- const repoName = this.configManager.get("repoName");
4972
+ const port2 = this.configManager.get("port") || VitepressService.DEFAULT_DEV_PORT;
4973
+ const repoName2 = this.configManager.get("repoName");
3695
4974
  this.logger.info(
3696
- `\u672C\u5730\u5F00\u53D1\u670D\u52A1\u5730\u5740\uFF1Ahttp://localhost:${port}/${repoName}/`
4975
+ `\u672C\u5730\u5F00\u53D1\u670D\u52A1\u5730\u5740\uFF1Ahttp://localhost:${port2}/${repoName2}/`
3697
4976
  );
3698
4977
  } else {
3699
4978
  this.logger.error("\u542F\u52A8\u670D\u52A1\u5668\u5931\u8D25");
@@ -3703,6 +4982,7 @@ var DevCommand = class extends BaseCommand {
3703
4982
 
3704
4983
  // commands/build/BuildCommand.ts
3705
4984
  var BuildCommand = class extends BaseCommand {
4985
+ vitepressService;
3706
4986
  constructor() {
3707
4987
  super("build");
3708
4988
  this.vitepressService = new VitepressService();
@@ -3716,6 +4996,7 @@ var BuildCommand = class extends BaseCommand {
3716
4996
 
3717
4997
  // commands/build/PreviewCommand.ts
3718
4998
  var PreviewCommand = class extends BaseCommand {
4999
+ vitepressService;
3719
5000
  constructor() {
3720
5001
  super("preview");
3721
5002
  this.vitepressService = new VitepressService();
@@ -3735,6 +5016,8 @@ var PreviewCommand = class extends BaseCommand {
3735
5016
  import { createInterface } from "readline";
3736
5017
  import { v4 as uuidv42 } from "uuid";
3737
5018
  var CreateNoteCommand = class extends BaseCommand {
5019
+ noteService;
5020
+ readmeService;
3738
5021
  constructor() {
3739
5022
  super("create-notes");
3740
5023
  this.noteService = NoteService.getInstance();
@@ -3811,23 +5094,23 @@ var CreateNoteCommand = class extends BaseCommand {
3811
5094
  input: process.stdin,
3812
5095
  output: process.stdout
3813
5096
  });
3814
- return new Promise((resolve3) => {
5097
+ return new Promise((resolve4) => {
3815
5098
  rl.question("\n\u{1F4DD} \u8BF7\u8F93\u5165\u8981\u521B\u5EFA\u7684\u7B14\u8BB0\u6570\u91CF\uFF08\u9ED8\u8BA4\u4E3A 1\uFF09: ", (answer) => {
3816
5099
  rl.close();
3817
5100
  const trimmed = answer.trim();
3818
5101
  if (!trimmed) {
3819
5102
  this.logger.info("\u4F7F\u7528\u9ED8\u8BA4\u6570\u91CF: 1");
3820
- resolve3(1);
5103
+ resolve4(1);
3821
5104
  return;
3822
5105
  }
3823
5106
  const num = parseInt(trimmed, 10);
3824
5107
  if (isNaN(num) || num < 1 || !Number.isInteger(num)) {
3825
5108
  this.logger.warn(`\u8F93\u5165 "${trimmed}" \u4E0D\u662F\u6709\u6548\u7684\u6B63\u6574\u6570\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u503C: 1`);
3826
- resolve3(1);
5109
+ resolve4(1);
3827
5110
  return;
3828
5111
  }
3829
5112
  this.logger.info(`\u5C06\u521B\u5EFA ${num} \u7BC7\u7B14\u8BB0`);
3830
- resolve3(num);
5113
+ resolve4(num);
3831
5114
  });
3832
5115
  });
3833
5116
  }
@@ -3839,10 +5122,10 @@ var CreateNoteCommand = class extends BaseCommand {
3839
5122
  input: process.stdin,
3840
5123
  output: process.stdout
3841
5124
  });
3842
- return new Promise((resolve3) => {
5125
+ return new Promise((resolve4) => {
3843
5126
  rl.question("\u8BF7\u8F93\u5165\u7B14\u8BB0\u6807\u9898: ", (answer) => {
3844
5127
  rl.close();
3845
- resolve3(answer.trim());
5128
+ resolve4(answer.trim());
3846
5129
  });
3847
5130
  });
3848
5131
  }
@@ -3850,6 +5133,7 @@ var CreateNoteCommand = class extends BaseCommand {
3850
5133
 
3851
5134
  // commands/note/UpdateNoteConfigCommand.ts
3852
5135
  var UpdateNoteConfigCommand = class extends BaseCommand {
5136
+ noteService;
3853
5137
  constructor() {
3854
5138
  super("update-note-config");
3855
5139
  this.noteService = NoteService.getInstance();
@@ -3881,26 +5165,28 @@ var UpdateNoteConfigCommand = class extends BaseCommand {
3881
5165
  * 更新笔记配置(可被外部调用)
3882
5166
  */
3883
5167
  async updateConfig(params) {
3884
- const { noteIndex, config } = params;
5168
+ const { noteIndex, config: config2 } = params;
3885
5169
  const note = this.noteService.getNoteByIndex(noteIndex);
3886
5170
  if (!note) {
3887
5171
  throw new Error(`\u7B14\u8BB0\u672A\u627E\u5230: ${noteIndex}`);
3888
5172
  }
3889
- await this.noteService.updateNoteConfig(noteIndex, config);
5173
+ await this.noteService.updateNoteConfig(noteIndex, config2);
3890
5174
  this.logger.info(`\u2705 \u7B14\u8BB0 ${noteIndex} \u914D\u7F6E\u5DF2\u66F4\u65B0:`);
3891
- if (config.done !== void 0)
3892
- this.logger.info(` - \u5B8C\u6210\u72B6\u6001: ${config.done}`);
3893
- if (config.enableDiscussions !== void 0)
3894
- this.logger.info(` - \u8BC4\u8BBA\u72B6\u6001: ${config.enableDiscussions}`);
3895
- if (config.description !== void 0)
3896
- this.logger.info(` - \u7B14\u8BB0\u7B80\u4ECB: ${config.description || "(\u7A7A)"}`);
5175
+ if (config2.done !== void 0)
5176
+ this.logger.info(` - \u5B8C\u6210\u72B6\u6001: ${config2.done}`);
5177
+ if (config2.enableDiscussions !== void 0)
5178
+ this.logger.info(` - \u8BC4\u8BBA\u72B6\u6001: ${config2.enableDiscussions}`);
5179
+ if (config2.description !== void 0)
5180
+ this.logger.info(` - \u7B14\u8BB0\u7B80\u4ECB: ${config2.description || "(\u7A7A)"}`);
3897
5181
  }
3898
5182
  };
3899
5183
 
3900
5184
  // commands/note/RenameNoteCommand.ts
3901
- import { existsSync as existsSync10, renameSync, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
3902
- import { join as join9 } from "path";
5185
+ import { existsSync as existsSync11, renameSync, readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "fs";
5186
+ import { join as join11 } from "path";
3903
5187
  var RenameNoteCommand = class extends BaseCommand {
5188
+ noteService;
5189
+ readmeService;
3904
5190
  constructor() {
3905
5191
  super("rename-note");
3906
5192
  this.noteService = NoteService.getInstance();
@@ -3934,8 +5220,8 @@ var RenameNoteCommand = class extends BaseCommand {
3934
5220
  throw new Error(validation.error || "\u6807\u9898\u683C\u5F0F\u65E0\u6548");
3935
5221
  }
3936
5222
  const newDirName = `${noteIndex}. ${newTitle.trim()}`;
3937
- const newPath = join9(NOTES_PATH, newDirName);
3938
- if (existsSync10(newPath)) {
5223
+ const newPath = join11(NOTES_PATH, newDirName);
5224
+ if (existsSync11(newPath)) {
3939
5225
  throw new Error(`\u76EE\u6807\u6587\u4EF6\u5939\u5DF2\u5B58\u5728: ${newDirName}`);
3940
5226
  }
3941
5227
  try {
@@ -3950,9 +5236,9 @@ var RenameNoteCommand = class extends BaseCommand {
3950
5236
  }
3951
5237
  try {
3952
5238
  this.logger.info("\u6B63\u5728\u66F4\u65B0\u7B14\u8BB0\u5185\u90E8\u6807\u9898...");
3953
- const readmePath = join9(newPath, "README.md");
3954
- if (existsSync10(readmePath)) {
3955
- const content = readFileSync8(readmePath, "utf-8");
5239
+ const readmePath = join11(newPath, "README.md");
5240
+ if (existsSync11(readmePath)) {
5241
+ const content = readFileSync9(readmePath, "utf-8");
3956
5242
  const lines = content.split("\n");
3957
5243
  let h1Index = -1;
3958
5244
  for (let i = 0; i < lines.length; i++) {
@@ -3968,7 +5254,7 @@ var RenameNoteCommand = class extends BaseCommand {
3968
5254
  REPO_NOTES_URL
3969
5255
  );
3970
5256
  lines[h1Index] = newH1;
3971
- writeFileSync7(readmePath, lines.join("\n"), "utf-8");
5257
+ writeFileSync8(readmePath, lines.join("\n"), "utf-8");
3972
5258
  this.logger.success("\u2705 \u7B14\u8BB0\u6807\u9898\u5DF2\u66F4\u65B0");
3973
5259
  } else {
3974
5260
  this.logger.warn(
@@ -3991,6 +5277,7 @@ var RenameNoteCommand = class extends BaseCommand {
3991
5277
 
3992
5278
  // commands/maintenance/SyncCoreCommand.ts
3993
5279
  var SyncCoreCommand = class extends BaseCommand {
5280
+ syncCoreService;
3994
5281
  constructor() {
3995
5282
  super("sync-core");
3996
5283
  this.syncCoreService = new SyncCoreService();
@@ -4002,6 +5289,7 @@ var SyncCoreCommand = class extends BaseCommand {
4002
5289
 
4003
5290
  // commands/maintenance/FixTimestampsCommand.ts
4004
5291
  var FixTimestampsCommand = class extends BaseCommand {
5292
+ timestampService;
4005
5293
  constructor() {
4006
5294
  super("fix-timestamps");
4007
5295
  this.timestampService = new TimestampService();