@tnotesjs/core 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/BaseCommand.ts +58 -0
- package/commands/build/BuildCommand.ts +25 -0
- package/commands/build/PreviewCommand.ts +29 -0
- package/commands/build/index.ts +8 -0
- package/commands/dev/DevCommand.ts +75 -0
- package/commands/dev/index.ts +7 -0
- package/commands/git/PullCommand.ts +25 -0
- package/commands/git/PushCommand.ts +64 -0
- package/commands/git/index.ts +8 -0
- package/commands/index.ts +11 -0
- package/commands/init-sub-repo/InitSubRepoCommand.ts +206 -0
- package/commands/init-sub-repo/index.ts +1 -0
- package/commands/misc/HelpCommand.ts +104 -0
- package/commands/misc/index.ts +7 -0
- package/commands/models.ts +87 -0
- package/commands/note/CreateNoteCommand.ts +160 -0
- package/commands/note/RenameNoteCommand.ts +147 -0
- package/commands/note/UpdateNoteConfigCommand.ts +78 -0
- package/commands/note/index.ts +9 -0
- package/commands/registry.ts +47 -0
- package/commands/update/UpdateCommand.ts +219 -0
- package/commands/update/index.ts +7 -0
- package/commands/update-completed-count/UpdateCompletedCountCommand.ts +208 -0
- package/commands/update-completed-count/index.ts +5 -0
- package/config/templates.ts +0 -5
- package/dist/{chunk-5F5RJ2HV.cjs → chunk-7FEANCT6.cjs} +16 -7
- package/dist/chunk-AGVER5MX.cjs +1746 -0
- package/dist/{chunk-TJ4527KA.cjs → chunk-BL22KD4V.cjs} +324 -950
- package/dist/{chunk-56PKXCOX.js → chunk-GWG75A5M.js} +13 -4
- package/dist/{chunk-DUTS75WQ.js → chunk-XNO3PCEH.js} +374 -1000
- package/dist/chunk-ZEQS64PE.js +1746 -0
- package/dist/cli/index.cjs +76 -155
- package/dist/cli/index.js +10 -89
- package/dist/markdown/index.cjs +8 -12
- package/dist/markdown/index.d.cts +1 -1
- package/dist/markdown/index.d.ts +1 -1
- package/dist/markdown/index.js +7 -11
- package/dist/{types-CwBWwNVv.d.ts → types-C_d0fFeD.d.ts} +8 -1
- package/dist/{types-CpsEy8lA.d.cts → types-MRBGgJTX.d.cts} +8 -1
- package/dist/vitepress/config/index.cjs +402 -178
- package/dist/vitepress/config/index.js +392 -168
- package/dist/workspace/index.cjs +4 -1202
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.ts +2 -2
- package/dist/workspace/index.js +4 -1202
- package/markdown/components.ts +86 -0
- package/markdown/index.ts +17 -0
- package/markdown/noteFormatter.test.ts +44 -0
- package/markdown/noteFormatter.ts +237 -0
- package/package.json +7 -3
- package/services/file-watcher/folderChangeHandler.ts +19 -15
- package/services/file-watcher/globalUpdateCoordinator.ts +21 -27
- package/services/file-watcher/service.ts +1 -6
- package/services/index.ts +0 -1
- package/services/note/service.ts +4 -6
- package/services/readme/service.ts +11 -18
- package/services/reconcileToc.ts +20 -0
- package/utils/index.ts +0 -9
- package/{services/toc → utils}/moveTocInside.test.ts +1 -1
- package/vitepress/components/BilibiliOutsidePlayer/BilibiliOutsidePlayer.vue +9 -18
- package/vitepress/components/EnWordList/EnWordList.vue +16 -662
- package/vitepress/components/Footprints/Footprints.vue +15 -537
- package/vitepress/components/Mermaid/Mermaid.vue +13 -588
- package/vitepress/components/MindmapPreview/MindmapPreview.vue +12 -434
- package/vitepress/components/MindmapPreview/markdown.ts +1 -1
- package/vitepress/components/NotesTable/NotesTable.vue +11 -130
- package/vitepress/components/constants.ts +2 -2
- package/vitepress/components/sidebar.data.ts +8 -5
- package/vitepress/configs/markdown.config.ts +170 -26
- package/vitepress/plugins/sidebarStructurePlugin.ts +242 -145
- package/vitepress/theme/index.ts +9 -13
- package/vitepress/theme/styles/base.scss +15 -0
- package/workspace/atomic.ts +113 -0
- package/workspace/errors.ts +27 -0
- package/workspace/index.ts +40 -0
- package/workspace/mutationQueue.ts +28 -0
- package/workspace/paths.ts +64 -0
- package/workspace/reconcile.test.ts +300 -0
- package/workspace/reconcile.ts +95 -0
- package/workspace/scanner.ts +292 -0
- package/workspace/types.ts +224 -0
- package/workspace/workspace.test.ts +333 -0
- package/workspace/workspace.ts +1020 -0
- package/dist/chunk-3R7QSABB.cjs +0 -502
- package/dist/chunk-CZXRQPFJ.js +0 -11
- package/dist/chunk-HXED7KVT.cjs +0 -11
- package/dist/chunk-U6IBLREL.js +0 -502
- package/services/toc/index.ts +0 -5
- package/services/toc/service.ts +0 -759
- package/utils/migrateReadmeToToc.test.ts +0 -111
- package/utils/migrateReadmeToToc.ts +0 -135
- package/vitepress/components/EnWordList/RightClickMenu.vue +0 -93
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
import fs from 'node:fs/promises'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
buildSidebarFromTocTree,
|
|
7
|
+
parseTocToTree,
|
|
8
|
+
} from '../utils/tocHelpers'
|
|
9
|
+
|
|
10
|
+
import type { WorkspacePaths } from './paths'
|
|
11
|
+
import type {
|
|
12
|
+
KnowledgeBaseSnapshot,
|
|
13
|
+
WorkspaceDiagnostic,
|
|
14
|
+
WorkspaceKnowledgeBaseConfig,
|
|
15
|
+
WorkspaceNoteConfig,
|
|
16
|
+
WorkspaceNoteSummary,
|
|
17
|
+
} from './types'
|
|
18
|
+
import type { NoteInfo } from '../types/note'
|
|
19
|
+
|
|
20
|
+
const NOTE_DIRECTORY_PATTERN = /^(\d{4})\.\s*(.+)$/
|
|
21
|
+
const CURRENT_SCHEMA_VERSION = 1
|
|
22
|
+
|
|
23
|
+
function digest(...values: Array<string | Buffer>): string {
|
|
24
|
+
const hash = createHash('sha256')
|
|
25
|
+
for (const value of values) {
|
|
26
|
+
hash.update(value)
|
|
27
|
+
hash.update('\0')
|
|
28
|
+
}
|
|
29
|
+
return hash.digest('hex')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function readText(filePath: string): Promise<string | null> {
|
|
33
|
+
try {
|
|
34
|
+
return await fs.readFile(filePath, 'utf8')
|
|
35
|
+
} catch {
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function parseJsonObject<T extends Record<string, unknown>>(
|
|
41
|
+
content: string,
|
|
42
|
+
): T | null {
|
|
43
|
+
try {
|
|
44
|
+
const value = JSON.parse(content) as unknown
|
|
45
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
46
|
+
? (value as T)
|
|
47
|
+
: null
|
|
48
|
+
} catch {
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function noteInfoFromSummary(note: WorkspaceNoteSummary): NoteInfo {
|
|
54
|
+
return {
|
|
55
|
+
index: note.index,
|
|
56
|
+
path: note.directoryPath,
|
|
57
|
+
dirName: note.dirName,
|
|
58
|
+
readmePath: note.readmePath,
|
|
59
|
+
configPath: note.configPath,
|
|
60
|
+
config: note.config,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ScannedWorkspace {
|
|
65
|
+
snapshot: KnowledgeBaseSnapshot
|
|
66
|
+
configText: string | null
|
|
67
|
+
tocText: string | null
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function scanWorkspace(
|
|
71
|
+
paths: WorkspacePaths,
|
|
72
|
+
): Promise<ScannedWorkspace> {
|
|
73
|
+
const diagnostics: WorkspaceDiagnostic[] = []
|
|
74
|
+
let rootIsDirectory = false
|
|
75
|
+
try {
|
|
76
|
+
rootIsDirectory = (await fs.stat(paths.root)).isDirectory()
|
|
77
|
+
} catch {
|
|
78
|
+
// Handled as a diagnostic below.
|
|
79
|
+
}
|
|
80
|
+
if (!rootIsDirectory) {
|
|
81
|
+
diagnostics.push({
|
|
82
|
+
code: 'ROOT_NOT_DIRECTORY',
|
|
83
|
+
message: '知识库根目录不存在或不是目录',
|
|
84
|
+
severity: 'error',
|
|
85
|
+
path: paths.root,
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const configText = await readText(paths.config)
|
|
90
|
+
let config: WorkspaceKnowledgeBaseConfig | null = null
|
|
91
|
+
if (configText === null) {
|
|
92
|
+
diagnostics.push({
|
|
93
|
+
code: 'CONFIG_MISSING',
|
|
94
|
+
message: '缺少知识库配置 .tnotes.json',
|
|
95
|
+
severity: 'error',
|
|
96
|
+
path: paths.config,
|
|
97
|
+
})
|
|
98
|
+
} else {
|
|
99
|
+
config = parseJsonObject<WorkspaceKnowledgeBaseConfig>(configText)
|
|
100
|
+
if (!config) {
|
|
101
|
+
diagnostics.push({
|
|
102
|
+
code: 'CONFIG_INVALID_JSON',
|
|
103
|
+
message: '知识库配置不是有效的 JSON 对象',
|
|
104
|
+
severity: 'error',
|
|
105
|
+
path: paths.config,
|
|
106
|
+
})
|
|
107
|
+
} else {
|
|
108
|
+
if (typeof config.id !== 'string' || !config.id.trim()) {
|
|
109
|
+
diagnostics.push({
|
|
110
|
+
code: 'CONFIG_ID_MISSING',
|
|
111
|
+
message: '知识库配置缺少稳定的 id',
|
|
112
|
+
severity: 'error',
|
|
113
|
+
path: paths.config,
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
if (typeof config.repoName !== 'string' || !config.repoName.trim()) {
|
|
117
|
+
diagnostics.push({
|
|
118
|
+
code: 'CONFIG_REPO_NAME_MISSING',
|
|
119
|
+
message: '知识库配置缺少 repoName',
|
|
120
|
+
severity: 'error',
|
|
121
|
+
path: paths.config,
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let notesDirectoryExists = false
|
|
128
|
+
try {
|
|
129
|
+
notesDirectoryExists = (await fs.stat(paths.notes)).isDirectory()
|
|
130
|
+
} catch {
|
|
131
|
+
// Handled below.
|
|
132
|
+
}
|
|
133
|
+
if (!notesDirectoryExists) {
|
|
134
|
+
diagnostics.push({
|
|
135
|
+
code: 'NOTES_DIRECTORY_MISSING',
|
|
136
|
+
message: '缺少 notes 目录',
|
|
137
|
+
severity: 'error',
|
|
138
|
+
path: paths.notes,
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const tocText = await readText(paths.toc)
|
|
143
|
+
if (tocText === null) {
|
|
144
|
+
diagnostics.push({
|
|
145
|
+
code: 'TOC_MISSING',
|
|
146
|
+
message: '缺少目录真相源 TOC.md',
|
|
147
|
+
severity: 'error',
|
|
148
|
+
path: paths.toc,
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const notes: WorkspaceNoteSummary[] = []
|
|
153
|
+
const usedIndexes = new Map<string, string>()
|
|
154
|
+
const usedIds = new Map<string, string>()
|
|
155
|
+
if (notesDirectoryExists) {
|
|
156
|
+
const entries = await fs.readdir(paths.notes, { withFileTypes: true })
|
|
157
|
+
entries.sort((left, right) => left.name.localeCompare(right.name))
|
|
158
|
+
for (const entry of entries) {
|
|
159
|
+
if (!entry.isDirectory() || entry.name.startsWith('.')) continue
|
|
160
|
+
const match = NOTE_DIRECTORY_PATTERN.exec(entry.name)
|
|
161
|
+
if (!match) continue
|
|
162
|
+
|
|
163
|
+
const [, index, rawTitle] = match
|
|
164
|
+
const title = rawTitle.trim()
|
|
165
|
+
const directoryPath = path.join(paths.notes, entry.name)
|
|
166
|
+
const readmePath = path.join(directoryPath, 'README.md')
|
|
167
|
+
const configPath = path.join(directoryPath, '.tnotes.json')
|
|
168
|
+
const readme = await readText(readmePath)
|
|
169
|
+
const noteConfigText = await readText(configPath)
|
|
170
|
+
|
|
171
|
+
if (readme === null) {
|
|
172
|
+
diagnostics.push({
|
|
173
|
+
code: 'NOTE_README_MISSING',
|
|
174
|
+
message: `笔记 ${entry.name} 缺少 README.md`,
|
|
175
|
+
severity: 'error',
|
|
176
|
+
path: readmePath,
|
|
177
|
+
})
|
|
178
|
+
continue
|
|
179
|
+
}
|
|
180
|
+
if (noteConfigText === null) {
|
|
181
|
+
diagnostics.push({
|
|
182
|
+
code: 'NOTE_CONFIG_MISSING',
|
|
183
|
+
message: `笔记 ${entry.name} 缺少 .tnotes.json`,
|
|
184
|
+
severity: 'error',
|
|
185
|
+
path: configPath,
|
|
186
|
+
})
|
|
187
|
+
continue
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const noteConfig = parseJsonObject<WorkspaceNoteConfig>(noteConfigText)
|
|
191
|
+
if (!noteConfig || typeof noteConfig.id !== 'string' || !noteConfig.id) {
|
|
192
|
+
diagnostics.push({
|
|
193
|
+
code: 'NOTE_CONFIG_INVALID',
|
|
194
|
+
message: `笔记 ${entry.name} 的配置无法解析或缺少 id`,
|
|
195
|
+
severity: 'error',
|
|
196
|
+
path: configPath,
|
|
197
|
+
})
|
|
198
|
+
continue
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const existingIndex = usedIndexes.get(index)
|
|
202
|
+
if (existingIndex) {
|
|
203
|
+
diagnostics.push({
|
|
204
|
+
code: 'NOTE_INDEX_DUPLICATE',
|
|
205
|
+
message: `笔记编号 ${index} 重复:${existingIndex}、${entry.name}`,
|
|
206
|
+
severity: 'error',
|
|
207
|
+
path: directoryPath,
|
|
208
|
+
})
|
|
209
|
+
} else {
|
|
210
|
+
usedIndexes.set(index, entry.name)
|
|
211
|
+
}
|
|
212
|
+
const existingId = usedIds.get(noteConfig.id)
|
|
213
|
+
if (existingId) {
|
|
214
|
+
diagnostics.push({
|
|
215
|
+
code: 'NOTE_ID_DUPLICATE',
|
|
216
|
+
message: `笔记 id ${noteConfig.id} 重复:${existingId}、${entry.name}`,
|
|
217
|
+
severity: 'error',
|
|
218
|
+
path: configPath,
|
|
219
|
+
})
|
|
220
|
+
} else {
|
|
221
|
+
usedIds.set(noteConfig.id, entry.name)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
notes.push({
|
|
225
|
+
uuid: noteConfig.id,
|
|
226
|
+
index,
|
|
227
|
+
title,
|
|
228
|
+
dirName: entry.name,
|
|
229
|
+
directoryPath,
|
|
230
|
+
readmePath,
|
|
231
|
+
configPath,
|
|
232
|
+
config: noteConfig,
|
|
233
|
+
revision: digest(entry.name, readme, noteConfigText),
|
|
234
|
+
})
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const noteInfos = notes.map(noteInfoFromSummary)
|
|
239
|
+
const toc = tocText ? parseTocToTree(tocText.split('\n'), noteInfos) : []
|
|
240
|
+
const sidebar = buildSidebarFromTocTree(toc, noteInfos, {
|
|
241
|
+
sidebarShowNoteId: config?.sidebarShowNoteId ?? true,
|
|
242
|
+
sidebarIsCollapsed: true,
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
const schemaVersion = config?.schemaVersion
|
|
246
|
+
const futureSchema =
|
|
247
|
+
typeof schemaVersion === 'number' && schemaVersion > CURRENT_SCHEMA_VERSION
|
|
248
|
+
if (futureSchema) {
|
|
249
|
+
diagnostics.push({
|
|
250
|
+
code: 'FUTURE_SCHEMA',
|
|
251
|
+
message: `知识库 schemaVersion ${schemaVersion} 高于当前支持版本 ${CURRENT_SCHEMA_VERSION}`,
|
|
252
|
+
severity: 'error',
|
|
253
|
+
path: paths.config,
|
|
254
|
+
})
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const health = futureSchema
|
|
258
|
+
? { status: 'future-schema' as const, diagnostics }
|
|
259
|
+
: diagnostics.some((diagnostic) => diagnostic.severity === 'error')
|
|
260
|
+
? { status: 'invalid' as const, diagnostics }
|
|
261
|
+
: { status: 'ready' as const, diagnostics }
|
|
262
|
+
|
|
263
|
+
const id =
|
|
264
|
+
config && typeof config.id === 'string' && config.id.trim()
|
|
265
|
+
? config.id
|
|
266
|
+
: `path-${digest(paths.root).slice(0, 24)}`
|
|
267
|
+
const revision = digest(
|
|
268
|
+
paths.root,
|
|
269
|
+
configText ?? '',
|
|
270
|
+
tocText ?? '',
|
|
271
|
+
...notes.map((note) => `${note.uuid}:${note.revision}`),
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
return {
|
|
275
|
+
snapshot: {
|
|
276
|
+
id,
|
|
277
|
+
rootPath: paths.root,
|
|
278
|
+
config,
|
|
279
|
+
health,
|
|
280
|
+
toc,
|
|
281
|
+
sidebar,
|
|
282
|
+
notes,
|
|
283
|
+
revision,
|
|
284
|
+
},
|
|
285
|
+
configText,
|
|
286
|
+
tocText,
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export function toNoteInfo(note: WorkspaceNoteSummary): NoteInfo {
|
|
291
|
+
return noteInfoFromSummary(note)
|
|
292
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import type { TNotesConfig } from '../types/config'
|
|
2
|
+
import type { NoteConfig } from '../types/note'
|
|
3
|
+
import type { TocTreeNode, TocSidebarItem } from '../utils/tocHelpers'
|
|
4
|
+
|
|
5
|
+
export type WorkspaceDiagnosticSeverity = 'error' | 'warning' | 'info'
|
|
6
|
+
|
|
7
|
+
export interface WorkspaceDiagnostic {
|
|
8
|
+
code: string
|
|
9
|
+
message: string
|
|
10
|
+
severity: WorkspaceDiagnosticSeverity
|
|
11
|
+
path?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type WorkspaceHealth =
|
|
15
|
+
| { status: 'ready'; diagnostics: WorkspaceDiagnostic[] }
|
|
16
|
+
| { status: 'invalid'; diagnostics: WorkspaceDiagnostic[] }
|
|
17
|
+
| { status: 'future-schema'; diagnostics: WorkspaceDiagnostic[] }
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Core only edits known fields, but it must retain fields introduced by a
|
|
21
|
+
* knowledge base or by a newer Core release.
|
|
22
|
+
*/
|
|
23
|
+
export type WorkspaceNoteConfig = NoteConfig & Record<string, unknown>
|
|
24
|
+
export type WorkspaceKnowledgeBaseConfig = TNotesConfig &
|
|
25
|
+
Record<string, unknown>
|
|
26
|
+
|
|
27
|
+
export interface WorkspaceNoteSummary {
|
|
28
|
+
uuid: string
|
|
29
|
+
index: string
|
|
30
|
+
title: string
|
|
31
|
+
dirName: string
|
|
32
|
+
directoryPath: string
|
|
33
|
+
readmePath: string
|
|
34
|
+
configPath: string
|
|
35
|
+
config: WorkspaceNoteConfig
|
|
36
|
+
revision: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface KnowledgeBaseSnapshot {
|
|
40
|
+
id: string
|
|
41
|
+
rootPath: string
|
|
42
|
+
config: WorkspaceKnowledgeBaseConfig | null
|
|
43
|
+
health: WorkspaceHealth
|
|
44
|
+
toc: TocTreeNode[]
|
|
45
|
+
sidebar: TocSidebarItem[]
|
|
46
|
+
notes: WorkspaceNoteSummary[]
|
|
47
|
+
revision: string
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface NoteDocument extends WorkspaceNoteSummary {
|
|
51
|
+
content: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface ChangedFile {
|
|
55
|
+
path: string
|
|
56
|
+
kind: 'created' | 'updated' | 'deleted' | 'renamed' | 'trashed'
|
|
57
|
+
previousPath?: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface MutationResult<T> {
|
|
61
|
+
value: T
|
|
62
|
+
changedFiles: ChangedFile[]
|
|
63
|
+
snapshotRevision: string
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface WorkspaceLogger {
|
|
67
|
+
debug?(message: string, details?: unknown): void
|
|
68
|
+
info?(message: string, details?: unknown): void
|
|
69
|
+
warn?(message: string, details?: unknown): void
|
|
70
|
+
error?(message: string, details?: unknown): void
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface CreateWorkspaceOptions {
|
|
74
|
+
rootPath: string
|
|
75
|
+
logger?: WorkspaceLogger
|
|
76
|
+
format?: {
|
|
77
|
+
prettier?: boolean
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface SaveNoteInput {
|
|
82
|
+
noteUuid: string
|
|
83
|
+
content: string
|
|
84
|
+
expectedRevision: string
|
|
85
|
+
prettier?: boolean
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type NotePlacement =
|
|
89
|
+
| { type: 'root'; placement?: 'start' | 'end' }
|
|
90
|
+
| {
|
|
91
|
+
type: 'note'
|
|
92
|
+
targetNoteUuid: string
|
|
93
|
+
placement: 'before' | 'after' | 'inside'
|
|
94
|
+
}
|
|
95
|
+
| {
|
|
96
|
+
type: 'folder'
|
|
97
|
+
folderPath: string[]
|
|
98
|
+
placement: 'before' | 'after' | 'inside'
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface CreateNoteInput {
|
|
102
|
+
title: string
|
|
103
|
+
placement?: NotePlacement
|
|
104
|
+
config?: Partial<Pick<WorkspaceNoteConfig, 'description' | 'enableDiscussions'>>
|
|
105
|
+
expectedSnapshotRevision?: string
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface RenameNoteInput {
|
|
109
|
+
noteUuid: string
|
|
110
|
+
title: string
|
|
111
|
+
expectedRevision: string
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface UpdateNoteConfigInput {
|
|
115
|
+
noteUuid: string
|
|
116
|
+
updates: Partial<
|
|
117
|
+
Pick<
|
|
118
|
+
WorkspaceNoteConfig,
|
|
119
|
+
'done' | 'description' | 'enableDiscussions'
|
|
120
|
+
>
|
|
121
|
+
>
|
|
122
|
+
expectedRevision: string
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export type TocEntryRef =
|
|
126
|
+
| { type: 'note'; noteUuid: string }
|
|
127
|
+
| { type: 'folder'; folderPath: string[] }
|
|
128
|
+
| { type: 'line'; tocLineIndex: number }
|
|
129
|
+
|
|
130
|
+
export interface MoveTocEntryInput {
|
|
131
|
+
source: TocEntryRef
|
|
132
|
+
target: TocEntryRef
|
|
133
|
+
placement: 'before' | 'after' | 'inside'
|
|
134
|
+
expectedSnapshotRevision: string
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface CreateTocGroupInput {
|
|
138
|
+
title: string
|
|
139
|
+
placement?: NotePlacement
|
|
140
|
+
expectedSnapshotRevision: string
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface RenameTocGroupInput {
|
|
144
|
+
folderPath: string[]
|
|
145
|
+
title: string
|
|
146
|
+
expectedSnapshotRevision: string
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface DeletePreviewItem {
|
|
150
|
+
noteUuid: string
|
|
151
|
+
index: string
|
|
152
|
+
title: string
|
|
153
|
+
directoryPath: string
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface DeleteTocEntryPreview {
|
|
157
|
+
entry: TocEntryRef
|
|
158
|
+
notes: DeletePreviewItem[]
|
|
159
|
+
filePaths: string[]
|
|
160
|
+
directoryPaths: string[]
|
|
161
|
+
snapshotRevision: string
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface DeleteTocEntryInput {
|
|
165
|
+
entry: TocEntryRef
|
|
166
|
+
expectedSnapshotRevision: string
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface WriteAttachmentInput {
|
|
170
|
+
noteUuid: string
|
|
171
|
+
fileName: string
|
|
172
|
+
data: Uint8Array
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export interface AttachmentResult {
|
|
176
|
+
absolutePath: string
|
|
177
|
+
markdownPath: string
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export interface TNotesWorkspace {
|
|
181
|
+
inspect(): Promise<KnowledgeBaseSnapshot>
|
|
182
|
+
refresh(): Promise<KnowledgeBaseSnapshot>
|
|
183
|
+
reconcileTocCompletion(): Promise<MutationResult<KnowledgeBaseSnapshot>>
|
|
184
|
+
|
|
185
|
+
notes: {
|
|
186
|
+
read(noteUuid: string): Promise<NoteDocument>
|
|
187
|
+
save(input: SaveNoteInput): Promise<MutationResult<NoteDocument>>
|
|
188
|
+
create(input: CreateNoteInput): Promise<MutationResult<NoteDocument>>
|
|
189
|
+
rename(input: RenameNoteInput): Promise<MutationResult<NoteDocument>>
|
|
190
|
+
updateConfig(
|
|
191
|
+
input: UpdateNoteConfigInput,
|
|
192
|
+
): Promise<MutationResult<NoteDocument>>
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
toc: {
|
|
196
|
+
move(input: MoveTocEntryInput): Promise<MutationResult<KnowledgeBaseSnapshot>>
|
|
197
|
+
createGroup(
|
|
198
|
+
input: CreateTocGroupInput,
|
|
199
|
+
): Promise<MutationResult<KnowledgeBaseSnapshot>>
|
|
200
|
+
renameGroup(
|
|
201
|
+
input: RenameTocGroupInput,
|
|
202
|
+
): Promise<MutationResult<KnowledgeBaseSnapshot>>
|
|
203
|
+
previewDelete(entry: TocEntryRef): Promise<DeleteTocEntryPreview>
|
|
204
|
+
deleteEntry(
|
|
205
|
+
input: DeleteTocEntryInput,
|
|
206
|
+
): Promise<MutationResult<KnowledgeBaseSnapshot>>
|
|
207
|
+
setDone(input: UpdateNoteConfigInput): Promise<MutationResult<NoteDocument>>
|
|
208
|
+
/**
|
|
209
|
+
* Align TOC.md + sidebar.json with the filesystem truth (files-first).
|
|
210
|
+
* Valid notes missing from the TOC are appended (root level, by index);
|
|
211
|
+
* note dirs with a missing/invalid config are soft-deleted to
|
|
212
|
+
* notes/.trash/. Idempotent: no changes -> changedFiles = [].
|
|
213
|
+
*/
|
|
214
|
+
reconcileFromFiles(): Promise<MutationResult<KnowledgeBaseSnapshot>>
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
attachments: {
|
|
218
|
+
writeLocal(
|
|
219
|
+
input: WriteAttachmentInput,
|
|
220
|
+
): Promise<MutationResult<AttachmentResult>>
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
dispose(): Promise<void>
|
|
224
|
+
}
|