@justyork/repo-mind 0.7.0 → 0.7.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.
- package/dist/ui/draft-api.js +33 -1
- package/dist/ui/fs-operations.d.ts +13 -0
- package/dist/ui/fs-operations.js +139 -0
- package/dist/ui/fs-tree.d.ts +6 -1
- package/dist/ui/fs-tree.js +62 -36
- package/package.json +3 -1
- package/ui/dist/assets/{arc-DufwQU06.js → arc-B9D1Pvqi.js} +1 -1
- package/ui/dist/assets/{architectureDiagram-3BPJPVTR-CI2fjjSo.js → architectureDiagram-3BPJPVTR-Bvug0Ca5.js} +1 -1
- package/ui/dist/assets/{blockDiagram-GPEHLZMM-DVBIs-Z6.js → blockDiagram-GPEHLZMM-Ckmilsu4.js} +1 -1
- package/ui/dist/assets/{c4Diagram-AAUBKEIU-rhAX_HrB.js → c4Diagram-AAUBKEIU-BT9pbmn0.js} +1 -1
- package/ui/dist/assets/channel-TAOLyHdK.js +1 -0
- package/ui/dist/assets/{chunk-2J33WTMH-CxWSQi5S.js → chunk-2J33WTMH-dgxq-Xfu.js} +1 -1
- package/ui/dist/assets/{chunk-4BX2VUAB-BEM-vVbU.js → chunk-4BX2VUAB-DmM9cIh_.js} +1 -1
- package/ui/dist/assets/{chunk-55IACEB6-TcrLDHYx.js → chunk-55IACEB6-DsB88bPS.js} +1 -1
- package/ui/dist/assets/{chunk-727SXJPM-D8g4OcIW.js → chunk-727SXJPM-BYuDClxC.js} +1 -1
- package/ui/dist/assets/{chunk-AQP2D5EJ-CSvrR8rQ.js → chunk-AQP2D5EJ-RO0Jvaof.js} +1 -1
- package/ui/dist/assets/{chunk-FMBD7UC4-C14JNc29.js → chunk-FMBD7UC4-DqY1unJF.js} +1 -1
- package/ui/dist/assets/{chunk-ND2GUHAM-Cnb0VFKm.js → chunk-ND2GUHAM-BAURH6-3.js} +1 -1
- package/ui/dist/assets/{chunk-QZHKN3VN-D2pqmAXN.js → chunk-QZHKN3VN-BiCWufLo.js} +1 -1
- package/ui/dist/assets/classDiagram-4FO5ZUOK-0RJZpoIN.js +1 -0
- package/ui/dist/assets/classDiagram-v2-Q7XG4LA2-0RJZpoIN.js +1 -0
- package/ui/dist/assets/{cose-bilkent-S5V4N54A-Cli2Sbvt.js → cose-bilkent-S5V4N54A-Bol8tJZ0.js} +1 -1
- package/ui/dist/assets/{dagre-BM42HDAG-gUsVuy4s.js → dagre-BM42HDAG-ziNCIqra.js} +1 -1
- package/ui/dist/assets/{diagram-2AECGRRQ-DTKi_1b6.js → diagram-2AECGRRQ-Dh2G8IOg.js} +1 -1
- package/ui/dist/assets/{diagram-5GNKFQAL-8Bj0k_-k.js → diagram-5GNKFQAL-C_26Fq9O.js} +1 -1
- package/ui/dist/assets/{diagram-KO2AKTUF-CKOX2fpv.js → diagram-KO2AKTUF-CPS1B4bk.js} +1 -1
- package/ui/dist/assets/{diagram-LMA3HP47-B12JvpF3.js → diagram-LMA3HP47-DoL5Nx28.js} +1 -1
- package/ui/dist/assets/{diagram-OG6HWLK6-DKeTI9IH.js → diagram-OG6HWLK6-DOy-TY5D.js} +1 -1
- package/ui/dist/assets/editor-CTtDusro.js +211 -0
- package/ui/dist/assets/{erDiagram-TEJ5UH35-oDb31edH.js → erDiagram-TEJ5UH35-C2whsoWw.js} +1 -1
- package/ui/dist/assets/{flowDiagram-I6XJVG4X-SPf3KLS-.js → flowDiagram-I6XJVG4X-D7-1XdVh.js} +1 -1
- package/ui/dist/assets/{ganttDiagram-6RSMTGT7-D8oPEcrt.js → ganttDiagram-6RSMTGT7-Dduumk4v.js} +1 -1
- package/ui/dist/assets/{gitGraphDiagram-PVQCEYII-eI9Yp7d7.js → gitGraphDiagram-PVQCEYII-CJfZihUe.js} +1 -1
- package/ui/dist/assets/{graph-DqCH9VKs.js → graph-CFkZObJQ.js} +1 -1
- package/ui/dist/assets/{infoDiagram-5YYISTIA-CQ6dtyj3.js → infoDiagram-5YYISTIA-B8IsGW31.js} +1 -1
- package/ui/dist/assets/{ishikawaDiagram-YF4QCWOH-BHnOZ8-9.js → ishikawaDiagram-YF4QCWOH-CwaI1VjO.js} +1 -1
- package/ui/dist/assets/{journeyDiagram-JHISSGLW-0t985reH.js → journeyDiagram-JHISSGLW-jo8e3Vri.js} +1 -1
- package/ui/dist/assets/{kanban-definition-UN3LZRKU-vPlhgwPS.js → kanban-definition-UN3LZRKU-DsFcvv5g.js} +1 -1
- package/ui/dist/assets/main-DEdNYNxf.js +274 -0
- package/ui/dist/assets/{mermaid.core-C2wn2wM5.js → mermaid.core-CIyMeT5H.js} +4 -4
- package/ui/dist/assets/{mindmap-definition-RKZ34NQL-COKv8bQN.js → mindmap-definition-RKZ34NQL-Bl3ML0fg.js} +1 -1
- package/ui/dist/assets/{pieDiagram-4H26LBE5-CgVeawD6.js → pieDiagram-4H26LBE5-rCj5-rCc.js} +1 -1
- package/ui/dist/assets/{quadrantDiagram-W4KKPZXB-Bwpr8PxN.js → quadrantDiagram-W4KKPZXB-tF5l8Pj1.js} +1 -1
- package/ui/dist/assets/{requirementDiagram-4Y6WPE33-Cc8HFBxl.js → requirementDiagram-4Y6WPE33-CtAsbYzh.js} +1 -1
- package/ui/dist/assets/{sankeyDiagram-5OEKKPKP-B_1nSAK5.js → sankeyDiagram-5OEKKPKP-CYgylTyv.js} +1 -1
- package/ui/dist/assets/{sequenceDiagram-3UESZ5HK-hsYrUJza.js → sequenceDiagram-3UESZ5HK-D2FeAk8O.js} +1 -1
- package/ui/dist/assets/{stateDiagram-AJRCARHV-BMf4FL5O.js → stateDiagram-AJRCARHV-BhNt372S.js} +1 -1
- package/ui/dist/assets/stateDiagram-v2-BHNVJYJU-hesflu-P.js +1 -0
- package/ui/dist/assets/theme-CgUWrIXo.css +1 -0
- package/ui/dist/assets/theme-DBoBdw62.js +1 -0
- package/ui/dist/assets/{timeline-definition-PNZ67QCA-Cf3u1h2_.js → timeline-definition-PNZ67QCA-DYrj-JqE.js} +1 -1
- package/ui/dist/assets/{vennDiagram-CIIHVFJN-2uKO3x22.js → vennDiagram-CIIHVFJN-DAdImqHv.js} +1 -1
- package/ui/dist/assets/visual-editor-BHZk1CI4.js +220 -0
- package/ui/dist/assets/{wardley-L42UT6IY-BjLaoVtm.js → wardley-L42UT6IY-BfiflBRy.js} +1 -1
- package/ui/dist/assets/{wardleyDiagram-YWT4CUSO-DlrUKeJk.js → wardleyDiagram-YWT4CUSO-5HZM-go9.js} +1 -1
- package/ui/dist/assets/{xychartDiagram-2RQKCTM6-Bzbb3cqD.js → xychartDiagram-2RQKCTM6-ozNCw5n2.js} +1 -1
- package/ui/dist/graph.html +3 -3
- package/ui/dist/index.html +4 -4
- package/ui/dist/assets/channel-Q_-BqwUT.js +0 -1
- package/ui/dist/assets/classDiagram-4FO5ZUOK-CPrZx4R4.js +0 -1
- package/ui/dist/assets/classDiagram-v2-Q7XG4LA2-CPrZx4R4.js +0 -1
- package/ui/dist/assets/editor-DZbRkvnr.js +0 -211
- package/ui/dist/assets/main-Io6jccwi.js +0 -232
- package/ui/dist/assets/stateDiagram-v2-BHNVJYJU-BpaPdu-O.js +0 -1
- package/ui/dist/assets/theme-Dl8H1UuW.js +0 -1
- package/ui/dist/assets/theme-PE9lQ4bz.css +0 -1
- package/ui/dist/assets/visual-editor-D1uYYGOW.js +0 -47
package/dist/ui/draft-api.js
CHANGED
|
@@ -2,7 +2,7 @@ import { runExport } from '../commands/export.js';
|
|
|
2
2
|
import { isValidSlug } from '../index/slug.js';
|
|
3
3
|
import { DOC_TYPES, isDocStatus, isDocType } from '../index/types.js';
|
|
4
4
|
import { writeCatalogEmoji } from './catalog-meta.js';
|
|
5
|
-
import { createFolder, createPageFile, deleteFolder, deletePageFile, movePageFile, renamePageFile } from './fs-operations.js';
|
|
5
|
+
import { createFolder, createPageFile, deleteFolder, deletePageFile, moveFolder, movePageFile, promotePageToFolder, renamePageFile } from './fs-operations.js';
|
|
6
6
|
import { prepareDocFile, prepareAllDocs } from '../prepare/prepare-docs.js';
|
|
7
7
|
import { syncAllDocLinks } from '../prepare/auto-links.js';
|
|
8
8
|
import { getDoc } from '../tools/get-doc.js';
|
|
@@ -102,6 +102,7 @@ export function handleDraftApi(index, db, method, pathname, bodyRaw) {
|
|
|
102
102
|
body: doc.body ?? '',
|
|
103
103
|
tags,
|
|
104
104
|
related,
|
|
105
|
+
forked_from: page.slug,
|
|
105
106
|
target_path: page.relativePath,
|
|
106
107
|
});
|
|
107
108
|
return { status: 201, body: { page, draft } };
|
|
@@ -111,6 +112,21 @@ export function handleDraftApi(index, db, method, pathname, bodyRaw) {
|
|
|
111
112
|
return jsonError(400, message);
|
|
112
113
|
}
|
|
113
114
|
}
|
|
115
|
+
if (pathname === '/api/fs/promote-page' && method === 'POST') {
|
|
116
|
+
const body = parseJsonBody(bodyRaw);
|
|
117
|
+
if (body === null) {
|
|
118
|
+
return jsonError(400, 'invalid JSON body');
|
|
119
|
+
}
|
|
120
|
+
const pagePath = typeof body.pagePath === 'string' ? body.pagePath : '';
|
|
121
|
+
try {
|
|
122
|
+
const result = promotePageToFolder(index, pagePath);
|
|
123
|
+
return { status: 200, body: { result } };
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
127
|
+
return jsonError(400, message);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
114
130
|
if (pathname === '/api/fs/move' && method === 'POST') {
|
|
115
131
|
const body = parseJsonBody(bodyRaw);
|
|
116
132
|
if (body === null) {
|
|
@@ -127,6 +143,22 @@ export function handleDraftApi(index, db, method, pathname, bodyRaw) {
|
|
|
127
143
|
return jsonError(400, message);
|
|
128
144
|
}
|
|
129
145
|
}
|
|
146
|
+
if (pathname === '/api/fs/move-folder' && method === 'POST') {
|
|
147
|
+
const body = parseJsonBody(bodyRaw);
|
|
148
|
+
if (body === null) {
|
|
149
|
+
return jsonError(400, 'invalid JSON body');
|
|
150
|
+
}
|
|
151
|
+
const fromPath = typeof body.fromPath === 'string' ? body.fromPath : '';
|
|
152
|
+
const toParentDir = typeof body.toParentDir === 'string' ? body.toParentDir : '';
|
|
153
|
+
try {
|
|
154
|
+
const result = moveFolder(index, fromPath, toParentDir);
|
|
155
|
+
return { status: 200, body: { result } };
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
159
|
+
return jsonError(400, message);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
130
162
|
if (pathname === '/api/fs/rename' && method === 'POST') {
|
|
131
163
|
const body = parseJsonBody(bodyRaw);
|
|
132
164
|
if (body === null) {
|
|
@@ -44,9 +44,22 @@ export interface CreatePageOptions {
|
|
|
44
44
|
title?: string;
|
|
45
45
|
templateId?: string;
|
|
46
46
|
}
|
|
47
|
+
export interface PromotePageResult extends FsPageMutationResult {
|
|
48
|
+
folderPath: string;
|
|
49
|
+
}
|
|
47
50
|
export declare function createFolder(index: DocIndex, parentPath: string, name: string): CreateFolderResult;
|
|
48
51
|
export declare function createPageFile(index: DocIndex, parentPath: string, name: string, options?: CreatePageOptions): CreatePageResult;
|
|
52
|
+
/** Creates sibling folder `{parent}/{basename}/` for a leaf page (Confluence-style); page file stays in place. */
|
|
53
|
+
export declare function promotePageToFolder(index: DocIndex, pagePath: string): PromotePageResult;
|
|
49
54
|
export declare function movePageFile(index: DocIndex, fromPath: string, toDir: string): FsPageMutationResult;
|
|
50
55
|
export declare function renamePageFile(index: DocIndex, pagePath: string, newName: string): FsPageMutationResult;
|
|
56
|
+
export interface FsMoveFolderResult {
|
|
57
|
+
relativePath: string;
|
|
58
|
+
previousPath: string;
|
|
59
|
+
siblingPagePath?: string;
|
|
60
|
+
cascadeUpdated: string[];
|
|
61
|
+
}
|
|
62
|
+
/** Moves a folder and its Confluence sibling page file when present. */
|
|
63
|
+
export declare function moveFolder(index: DocIndex, fromPath: string, toParentDir: string): FsMoveFolderResult;
|
|
51
64
|
export declare function deletePageFile(index: DocIndex, pagePath: string): FsDeletePageResult;
|
|
52
65
|
export declare function deleteFolder(index: DocIndex, folderPath: string): FsDeleteFolderResult;
|
package/dist/ui/fs-operations.js
CHANGED
|
@@ -115,6 +115,58 @@ function rewritePageFrontmatter(absolutePath, newRelativePath) {
|
|
|
115
115
|
fs.writeFileSync(absolutePath, matter.stringify(parsed.content, nextData), 'utf8');
|
|
116
116
|
return { newSlug, newType };
|
|
117
117
|
}
|
|
118
|
+
/** Creates sibling folder `{parent}/{basename}/` for a leaf page (Confluence-style); page file stays in place. */
|
|
119
|
+
export function promotePageToFolder(index, pagePath) {
|
|
120
|
+
const knowledgeRoot = index.getKnowledgeRoot();
|
|
121
|
+
if (!knowledgeRoot) {
|
|
122
|
+
throw new Error('no docs/ directory found');
|
|
123
|
+
}
|
|
124
|
+
const normalizedFrom = normalizeRelativePath(pagePath);
|
|
125
|
+
if (normalizedFrom === 'README.md') {
|
|
126
|
+
throw new Error('cannot promote docs root index');
|
|
127
|
+
}
|
|
128
|
+
const fileName = path.posix.basename(normalizedFrom);
|
|
129
|
+
if (fileName.toLowerCase() === 'readme.md') {
|
|
130
|
+
throw new Error('page is already inside a folder');
|
|
131
|
+
}
|
|
132
|
+
const sourceAbsolute = resolveRelativeMdPath(knowledgeRoot, normalizedFrom);
|
|
133
|
+
if (!sourceAbsolute || !fs.existsSync(sourceAbsolute)) {
|
|
134
|
+
throw new Error(`page not found: ${pagePath}`);
|
|
135
|
+
}
|
|
136
|
+
const parentPath = parentRelativePath(normalizedFrom);
|
|
137
|
+
const baseName = knowledgeFileDisplayName(fileName);
|
|
138
|
+
if (!isValidFsName(baseName)) {
|
|
139
|
+
throw new Error(`invalid page name: ${baseName}`);
|
|
140
|
+
}
|
|
141
|
+
const folderRelative = joinRelativePath(parentPath, baseName);
|
|
142
|
+
const folderAbsolute = resolveUnderKnowledgeRoot(knowledgeRoot, folderRelative);
|
|
143
|
+
if (!folderAbsolute) {
|
|
144
|
+
throw new Error('path escapes docs/');
|
|
145
|
+
}
|
|
146
|
+
if (fs.existsSync(folderAbsolute)) {
|
|
147
|
+
if (!fs.statSync(folderAbsolute).isDirectory()) {
|
|
148
|
+
throw new Error(`already exists: ${folderRelative}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
fs.mkdirSync(folderAbsolute, { recursive: true });
|
|
153
|
+
}
|
|
154
|
+
const previousSlug = readPageSlug(sourceAbsolute);
|
|
155
|
+
index.refresh();
|
|
156
|
+
return {
|
|
157
|
+
relativePath: normalizedFrom,
|
|
158
|
+
absolutePath: sourceAbsolute,
|
|
159
|
+
slug: previousSlug,
|
|
160
|
+
previousSlug,
|
|
161
|
+
slugChanged: false,
|
|
162
|
+
inboundWarnings: [],
|
|
163
|
+
cascadeUpdated: [],
|
|
164
|
+
folderPath: normalizeRelativePath(folderRelative),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function knowledgeFileDisplayName(fileName) {
|
|
168
|
+
return fileName.replace(/\.(md|ya?ml|json)$/i, '');
|
|
169
|
+
}
|
|
118
170
|
export function movePageFile(index, fromPath, toDir) {
|
|
119
171
|
const knowledgeRoot = index.getKnowledgeRoot();
|
|
120
172
|
if (!knowledgeRoot) {
|
|
@@ -244,6 +296,93 @@ function mergeInboundWarnings(lists) {
|
|
|
244
296
|
}
|
|
245
297
|
return merged;
|
|
246
298
|
}
|
|
299
|
+
function isDescendantOrEqual(ancestor, candidate) {
|
|
300
|
+
const a = normalizeRelativePath(ancestor);
|
|
301
|
+
const c = normalizeRelativePath(candidate);
|
|
302
|
+
if (!a) {
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
return c === a || c.startsWith(`${a}/`);
|
|
306
|
+
}
|
|
307
|
+
function absoluteToDocsRelative(knowledgeRoot, absolutePath) {
|
|
308
|
+
return normalizeRelativePath(path.relative(knowledgeRoot, absolutePath));
|
|
309
|
+
}
|
|
310
|
+
/** Moves a folder and its Confluence sibling page file when present. */
|
|
311
|
+
export function moveFolder(index, fromPath, toParentDir) {
|
|
312
|
+
const knowledgeRoot = index.getKnowledgeRoot();
|
|
313
|
+
if (!knowledgeRoot) {
|
|
314
|
+
throw new Error('no docs/ directory found');
|
|
315
|
+
}
|
|
316
|
+
const normalizedFrom = normalizeRelativePath(fromPath);
|
|
317
|
+
if (!normalizedFrom) {
|
|
318
|
+
throw new Error('cannot move docs root');
|
|
319
|
+
}
|
|
320
|
+
const sourceAbsolute = resolveUnderKnowledgeRoot(knowledgeRoot, normalizedFrom);
|
|
321
|
+
if (!sourceAbsolute || !fs.existsSync(sourceAbsolute)) {
|
|
322
|
+
throw new Error(`folder not found: ${fromPath}`);
|
|
323
|
+
}
|
|
324
|
+
if (!fs.statSync(sourceAbsolute).isDirectory()) {
|
|
325
|
+
throw new Error(`not a folder: ${fromPath}`);
|
|
326
|
+
}
|
|
327
|
+
const destParent = normalizeRelativePath(toParentDir);
|
|
328
|
+
if (isDescendantOrEqual(normalizedFrom, destParent)) {
|
|
329
|
+
throw new Error('cannot move folder into itself');
|
|
330
|
+
}
|
|
331
|
+
const folderName = path.posix.basename(normalizedFrom);
|
|
332
|
+
const destRelative = joinRelativePath(destParent, folderName);
|
|
333
|
+
const destAbsolute = resolveUnderKnowledgeRoot(knowledgeRoot, destRelative);
|
|
334
|
+
if (!destAbsolute) {
|
|
335
|
+
throw new Error('path escapes docs/');
|
|
336
|
+
}
|
|
337
|
+
if (fs.existsSync(destAbsolute)) {
|
|
338
|
+
throw new Error(`already exists: ${destRelative}`);
|
|
339
|
+
}
|
|
340
|
+
const fromParent = parentRelativePath(normalizedFrom);
|
|
341
|
+
const siblingRelative = joinRelativePath(fromParent, `${folderName}.md`);
|
|
342
|
+
const siblingAbsolute = resolveRelativeMdPath(knowledgeRoot, siblingRelative);
|
|
343
|
+
let siblingDestRelative;
|
|
344
|
+
if (siblingAbsolute && fs.existsSync(siblingAbsolute)) {
|
|
345
|
+
siblingDestRelative = joinRelativePath(destParent, `${folderName}.md`);
|
|
346
|
+
const siblingDestAbsolute = resolveRelativeMdPath(knowledgeRoot, siblingDestRelative);
|
|
347
|
+
if (!siblingDestAbsolute) {
|
|
348
|
+
throw new Error('path escapes docs/');
|
|
349
|
+
}
|
|
350
|
+
if (fs.existsSync(siblingDestAbsolute)) {
|
|
351
|
+
throw new Error(`already exists: ${siblingDestRelative}`);
|
|
352
|
+
}
|
|
353
|
+
fs.renameSync(siblingAbsolute, siblingDestAbsolute);
|
|
354
|
+
}
|
|
355
|
+
fs.renameSync(sourceAbsolute, destAbsolute);
|
|
356
|
+
const movedMarkdownAbsolutes = [];
|
|
357
|
+
if (siblingDestRelative) {
|
|
358
|
+
const siblingDestAbsolute = resolveRelativeMdPath(knowledgeRoot, siblingDestRelative);
|
|
359
|
+
if (siblingDestAbsolute) {
|
|
360
|
+
movedMarkdownAbsolutes.push(siblingDestAbsolute);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
movedMarkdownAbsolutes.push(...listMarkdownFilesRecursive(destAbsolute));
|
|
364
|
+
const cascadeUpdated = new Set();
|
|
365
|
+
for (const absolutePath of movedMarkdownAbsolutes) {
|
|
366
|
+
const relativePath = absoluteToDocsRelative(knowledgeRoot, absolutePath);
|
|
367
|
+
const previousSlug = readPageSlug(absolutePath);
|
|
368
|
+
const { newSlug } = rewritePageFrontmatter(absolutePath, relativePath);
|
|
369
|
+
if (newSlug === previousSlug) {
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
for (const updatedPath of cascadeSlugRename(knowledgeRoot, previousSlug, newSlug, {
|
|
373
|
+
excludeAbsolutePath: absolutePath,
|
|
374
|
+
})) {
|
|
375
|
+
cascadeUpdated.add(updatedPath);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
index.refresh();
|
|
379
|
+
return {
|
|
380
|
+
relativePath: destRelative,
|
|
381
|
+
previousPath: normalizedFrom,
|
|
382
|
+
siblingPagePath: siblingDestRelative,
|
|
383
|
+
cascadeUpdated: toRelativePaths(knowledgeRoot, [...cascadeUpdated]),
|
|
384
|
+
};
|
|
385
|
+
}
|
|
247
386
|
export function deletePageFile(index, pagePath) {
|
|
248
387
|
const knowledgeRoot = index.getKnowledgeRoot();
|
|
249
388
|
if (!knowledgeRoot) {
|
package/dist/ui/fs-tree.d.ts
CHANGED
|
@@ -9,6 +9,9 @@ export interface TreePageNode {
|
|
|
9
9
|
status: string;
|
|
10
10
|
type: string;
|
|
11
11
|
contentKind: 'markdown' | 'yaml' | 'json';
|
|
12
|
+
/** Sibling folder `{parent}/{name}/` when Confluence-style page+folder pair exists. */
|
|
13
|
+
childFolderPath?: string;
|
|
14
|
+
children?: TreeNode[];
|
|
12
15
|
}
|
|
13
16
|
export interface TreeFolderNode {
|
|
14
17
|
kind: 'folder';
|
|
@@ -17,6 +20,8 @@ export interface TreeFolderNode {
|
|
|
17
20
|
emoji: string | null;
|
|
18
21
|
/** Slug of README.md index page for this folder. */
|
|
19
22
|
indexPageSlug: string | null;
|
|
23
|
+
indexPageType: string | null;
|
|
24
|
+
indexPageContentKind: 'markdown' | 'yaml' | 'json' | null;
|
|
20
25
|
children: TreeNode[];
|
|
21
26
|
}
|
|
22
27
|
export type TreeNode = TreePageNode | TreeFolderNode;
|
|
@@ -25,4 +30,4 @@ export declare function readmeIndexRelativePath(folderRelativePath: string): str
|
|
|
25
30
|
export declare function folderDisplayName(relativePath: string): string;
|
|
26
31
|
export declare function buildDocsTree(index: DocIndex): TreeFolderNode | null;
|
|
27
32
|
export declare function findTreePageSlug(node: TreeFolderNode, relativePath: string): string | null;
|
|
28
|
-
export declare function collectParentOfEdges(
|
|
33
|
+
export declare function collectParentOfEdges(_tree: TreeFolderNode | null): LinkEdge[];
|
package/dist/ui/fs-tree.js
CHANGED
|
@@ -8,6 +8,20 @@ const IGNORED_DIRS = new Set(['.repo-mind', '.worktrees']);
|
|
|
8
8
|
function knowledgeFileDisplayName(fileName) {
|
|
9
9
|
return fileName.replace(/\.(md|ya?ml|json)$/i, '');
|
|
10
10
|
}
|
|
11
|
+
function findSiblingDirName(dirNames, fileName) {
|
|
12
|
+
const base = knowledgeFileDisplayName(fileName);
|
|
13
|
+
const exact = dirNames.find((name) => name === base);
|
|
14
|
+
if (exact) {
|
|
15
|
+
return exact;
|
|
16
|
+
}
|
|
17
|
+
const lower = base.toLowerCase();
|
|
18
|
+
return dirNames.find((name) => name.toLowerCase() === lower) ?? null;
|
|
19
|
+
}
|
|
20
|
+
function hasSiblingKnowledgePage(entries, dirName) {
|
|
21
|
+
return entries.some((entry) => !entry.isDirectory &&
|
|
22
|
+
isKnowledgeFileName(entry.name) &&
|
|
23
|
+
knowledgeFileDisplayName(entry.name).toLowerCase() === dirName.toLowerCase());
|
|
24
|
+
}
|
|
11
25
|
function listDirEntries(dirPath) {
|
|
12
26
|
if (!fs.existsSync(dirPath)) {
|
|
13
27
|
return [];
|
|
@@ -38,17 +52,25 @@ export function folderDisplayName(relativePath) {
|
|
|
38
52
|
function buildFolder(relativePath, absPath, ctx) {
|
|
39
53
|
const entries = listDirEntries(absPath);
|
|
40
54
|
const children = [];
|
|
55
|
+
const dirNames = entries.filter((entry) => entry.isDirectory).map((entry) => entry.name);
|
|
41
56
|
const readmeRel = readmeIndexRelativePath(relativePath);
|
|
42
57
|
let indexPageSlug = null;
|
|
58
|
+
let indexPageType = null;
|
|
59
|
+
let indexPageContentKind = null;
|
|
43
60
|
const readmeDoc = ctx.docsByRelative.get(readmeRel);
|
|
44
61
|
if (readmeDoc) {
|
|
45
62
|
indexPageSlug = readmeDoc.slug;
|
|
63
|
+
indexPageType = readmeDoc.type;
|
|
64
|
+
indexPageContentKind = readmeDoc.contentKind;
|
|
46
65
|
}
|
|
47
66
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
48
67
|
if (entry.isDirectory) {
|
|
49
68
|
if (IGNORED_DIRS.has(entry.name)) {
|
|
50
69
|
continue;
|
|
51
70
|
}
|
|
71
|
+
if (hasSiblingKnowledgePage(entries, entry.name)) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
52
74
|
const childRel = joinRelativePath(relativePath, entry.name);
|
|
53
75
|
children.push(buildFolder(childRel, path.join(absPath, entry.name), ctx));
|
|
54
76
|
continue;
|
|
@@ -57,13 +79,28 @@ function buildFolder(relativePath, absPath, ctx) {
|
|
|
57
79
|
continue;
|
|
58
80
|
}
|
|
59
81
|
const fileRel = joinRelativePath(relativePath, entry.name);
|
|
60
|
-
if (fileRel === readmeRel && indexPageSlug) {
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
82
|
const doc = ctx.docsByRelative.get(fileRel);
|
|
64
83
|
if (!doc) {
|
|
65
84
|
continue;
|
|
66
85
|
}
|
|
86
|
+
const siblingDir = findSiblingDirName(dirNames, entry.name);
|
|
87
|
+
if (siblingDir) {
|
|
88
|
+
const childFolderRel = joinRelativePath(relativePath, siblingDir);
|
|
89
|
+
const nested = buildFolder(childFolderRel, path.join(absPath, siblingDir), ctx);
|
|
90
|
+
children.push({
|
|
91
|
+
kind: 'page',
|
|
92
|
+
name: knowledgeFileDisplayName(entry.name),
|
|
93
|
+
relativePath: fileRel,
|
|
94
|
+
slug: doc.slug,
|
|
95
|
+
title: doc.title,
|
|
96
|
+
status: doc.status,
|
|
97
|
+
type: doc.type,
|
|
98
|
+
contentKind: doc.contentKind,
|
|
99
|
+
childFolderPath: childFolderRel,
|
|
100
|
+
children: nested.children,
|
|
101
|
+
});
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
67
104
|
children.push({
|
|
68
105
|
kind: 'page',
|
|
69
106
|
name: knowledgeFileDisplayName(entry.name),
|
|
@@ -81,6 +118,8 @@ function buildFolder(relativePath, absPath, ctx) {
|
|
|
81
118
|
relativePath,
|
|
82
119
|
emoji: catalogEmoji(ctx.meta, relativePath),
|
|
83
120
|
indexPageSlug,
|
|
121
|
+
indexPageType,
|
|
122
|
+
indexPageContentKind,
|
|
84
123
|
children,
|
|
85
124
|
};
|
|
86
125
|
}
|
|
@@ -107,42 +146,29 @@ export function buildDocsTree(index) {
|
|
|
107
146
|
}
|
|
108
147
|
export function findTreePageSlug(node, relativePath) {
|
|
109
148
|
const normalized = normalizeRelativePath(relativePath);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const found = findTreePageSlug(child, normalized);
|
|
116
|
-
if (found) {
|
|
117
|
-
return found;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
export function collectParentOfEdges(tree) {
|
|
124
|
-
if (!tree) {
|
|
125
|
-
return [];
|
|
126
|
-
}
|
|
127
|
-
const edges = [];
|
|
128
|
-
function walk(folder) {
|
|
129
|
-
if (folder.indexPageSlug) {
|
|
130
|
-
for (const child of folder.children ?? []) {
|
|
131
|
-
if (child.kind === 'page' && child.slug !== folder.indexPageSlug) {
|
|
132
|
-
edges.push({
|
|
133
|
-
from: folder.indexPageSlug,
|
|
134
|
-
to: child.slug,
|
|
135
|
-
kind: 'parent_of',
|
|
136
|
-
});
|
|
149
|
+
function search(nodes) {
|
|
150
|
+
for (const child of nodes) {
|
|
151
|
+
if (child.kind === 'page') {
|
|
152
|
+
if (child.relativePath === normalized) {
|
|
153
|
+
return child.slug;
|
|
137
154
|
}
|
|
155
|
+
if (child.children) {
|
|
156
|
+
const nested = search(child.children);
|
|
157
|
+
if (nested) {
|
|
158
|
+
return nested;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
continue;
|
|
138
162
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
walk(child);
|
|
163
|
+
const nested = findTreePageSlug(child, normalized);
|
|
164
|
+
if (nested) {
|
|
165
|
+
return nested;
|
|
143
166
|
}
|
|
144
167
|
}
|
|
168
|
+
return null;
|
|
145
169
|
}
|
|
146
|
-
|
|
147
|
-
|
|
170
|
+
return search(node.children);
|
|
171
|
+
}
|
|
172
|
+
export function collectParentOfEdges(_tree) {
|
|
173
|
+
return [];
|
|
148
174
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justyork/repo-mind",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Unified docs/ workspace for humans (UI) and AI agents (MCP) — Confluence in your repo",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
40
|
+
"@tiptap/extension-bubble-menu": "^2.27.2",
|
|
40
41
|
"better-sqlite3": "^12.11.1",
|
|
41
42
|
"chokidar": "^4.0.3",
|
|
42
43
|
"fast-glob": "^3.3.3",
|
|
@@ -61,6 +62,7 @@
|
|
|
61
62
|
"@types/better-sqlite3": "^7.6.13",
|
|
62
63
|
"@types/node": "^22.15.21",
|
|
63
64
|
"d3": "^7.9.0",
|
|
65
|
+
"lucide": "^1.21.0",
|
|
64
66
|
"marked": "^15.0.12",
|
|
65
67
|
"typescript": "^5.8.3",
|
|
66
68
|
"vite": "^6.3.5",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{$ as ln,a0 as an,a1 as G,a2 as q,a3 as z,a4 as un,a5 as y,a6 as tn,a7 as K,a8 as _,a9 as rn,aa as o,ab as on,ac as sn,ad as fn}from"./mermaid.core-
|
|
1
|
+
import{$ as ln,a0 as an,a1 as G,a2 as q,a3 as z,a4 as un,a5 as y,a6 as tn,a7 as K,a8 as _,a9 as rn,aa as o,ab as on,ac as sn,ad as fn}from"./mermaid.core-CIyMeT5H.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,B,a){var O=I-l,i=D-h,n=B-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function V(l,h,I,D,v,A,B){var a=l-I,O=h-D,i=(B?A:-A)/K(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,C=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*K(on(0,T*T*R-P*P)),$=(P*g-m*S)/R,j=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=$-C,e=j-t,r=w-C,F=p-t;return x*x+e*e>r*r+F*F&&($=w,j=p),{cx:$,cy:j,x01:-n,y01:-d,x11:$*(v/T-1),y11:j*(v/T-1)}}function hn(){var l=cn,h=yn,I=z(0),D=null,v=gn,A=dn,B=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,C=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(C>tn-y)a.moveTo(s*G(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*G(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=C,S=C,$=B.apply(this,arguments)/2,j=$>y&&(D?+D.apply(this,arguments):K(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if(j>y){var F=sn(j/u*q($)),L=sn(j/s*q($));(P-=F*2)>y?(F*=t?1:-1,R+=F,T-=F):(P=0,R=T=(f+c)/2),(S-=L*2)>y?(L*=t?1:-1,m+=L,g-=L):(S=0,m=g=(f+c)/2)}var H=s*G(m),J=s*q(m),M=u*G(T),N=u*q(T);if(w>y){var Q=s*G(g),U=s*q(g),W=u*G(R),X=u*q(R),E;if(C<an)if(E=pn(H,J,W,X,Q,U,M,N)){var Y=H-E[0],Z=J-E[1],b=Q-E[0],k=U-E[1],nn=1/q(fn((Y*b+Z*k)/(K(Y*Y+Z*Z)*K(b*b+k*k)))/2),en=K(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=V(W,X,H,J,s,x,t),r=V(Q,U,M,N,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(H,J),a.arc(0,0,s,m,g,!t)):a.moveTo(H,J),!(u>y)||!(P>y)?a.lineTo(M,N):p>y?(e=V(M,N,Q,U,u,-p,t),r=V(H,J,W,X,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[G(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:z(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:z(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:z(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:z(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:z(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:z(+n),i):A},i.padAngle=function(n){return arguments.length?(B=typeof n=="function"?n:z(+n),i):B},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
|