@justyork/repo-mind 0.7.2 → 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/.cursor/skills/repomind-docs/SKILL.md +160 -0
- package/.cursor/skills/repomind-docs/examples.md +429 -0
- package/.cursor/skills/repomind-docs/reference.md +209 -0
- package/.cursor/skills/repomind-docs/structure.md +132 -0
- package/dist/cli.js +17 -0
- package/dist/commands/install-skill.d.ts +9 -0
- package/dist/commands/install-skill.js +35 -0
- package/dist/commands/ui.js +5 -1
- package/dist/ui/auth.d.ts +21 -0
- package/dist/ui/auth.js +117 -0
- package/dist/ui/fs-operations.d.ts +1 -1
- package/dist/ui/fs-operations.js +36 -4
- package/dist/ui/fs-tree.d.ts +5 -4
- package/dist/ui/fs-tree.js +60 -56
- package/dist/ui/server.d.ts +2 -0
- package/dist/ui/server.js +63 -2
- package/package.json +3 -2
- package/ui/dist/assets/{arc-C1R_fyW-.js → arc-D8hdO1rw.js} +1 -1
- package/ui/dist/assets/{architectureDiagram-3BPJPVTR-CcuF3FYc.js → architectureDiagram-3BPJPVTR-DD8y2xkc.js} +1 -1
- package/ui/dist/assets/{blockDiagram-GPEHLZMM-BZJKe3Ei.js → blockDiagram-GPEHLZMM-CC_b0LTp.js} +1 -1
- package/ui/dist/assets/{c4Diagram-AAUBKEIU-D_0fRNGS.js → c4Diagram-AAUBKEIU-D0xWINWL.js} +1 -1
- package/ui/dist/assets/channel-BlZV_pp1.js +1 -0
- package/ui/dist/assets/{chunk-2J33WTMH-0LcH4vIA.js → chunk-2J33WTMH-BU6b81sJ.js} +1 -1
- package/ui/dist/assets/{chunk-4BX2VUAB-DU1h67AD.js → chunk-4BX2VUAB-DZAlHkZW.js} +1 -1
- package/ui/dist/assets/{chunk-55IACEB6-BCx7dyYV.js → chunk-55IACEB6-AiC0yewf.js} +1 -1
- package/ui/dist/assets/{chunk-727SXJPM-CRO5yOrB.js → chunk-727SXJPM-DThb082L.js} +1 -1
- package/ui/dist/assets/{chunk-AQP2D5EJ-BayHdr67.js → chunk-AQP2D5EJ-BPfxgjqM.js} +1 -1
- package/ui/dist/assets/{chunk-FMBD7UC4-CJemLien.js → chunk-FMBD7UC4-BPN8p0X8.js} +1 -1
- package/ui/dist/assets/{chunk-ND2GUHAM-B_z-tw44.js → chunk-ND2GUHAM-Fg3EXATp.js} +1 -1
- package/ui/dist/assets/{chunk-QZHKN3VN-D40rAh_S.js → chunk-QZHKN3VN-BfNeOxQX.js} +1 -1
- package/ui/dist/assets/classDiagram-4FO5ZUOK-DeRilEwX.js +1 -0
- package/ui/dist/assets/classDiagram-v2-Q7XG4LA2-DeRilEwX.js +1 -0
- package/ui/dist/assets/{cose-bilkent-S5V4N54A-Cqthtrrq.js → cose-bilkent-S5V4N54A-BajfXpNb.js} +1 -1
- package/ui/dist/assets/{dagre-BM42HDAG-CrxsyXEa.js → dagre-BM42HDAG-BOr2m0CZ.js} +1 -1
- package/ui/dist/assets/{diagram-2AECGRRQ-DTYA7Rrn.js → diagram-2AECGRRQ-0NMPI4vh.js} +1 -1
- package/ui/dist/assets/{diagram-5GNKFQAL-CXs7RV13.js → diagram-5GNKFQAL-CTuUvbHc.js} +1 -1
- package/ui/dist/assets/{diagram-KO2AKTUF-Bf8EeV_S.js → diagram-KO2AKTUF-BQMPycKH.js} +1 -1
- package/ui/dist/assets/{diagram-LMA3HP47-C2XWB0cI.js → diagram-LMA3HP47-0EqSTR8-.js} +1 -1
- package/ui/dist/assets/{diagram-OG6HWLK6-BNMXob9h.js → diagram-OG6HWLK6-Cn7vgxcz.js} +1 -1
- package/ui/dist/assets/{erDiagram-TEJ5UH35-CnSczOvb.js → erDiagram-TEJ5UH35-DCHJaPi9.js} +1 -1
- package/ui/dist/assets/{flowDiagram-I6XJVG4X-DwZBJ2fr.js → flowDiagram-I6XJVG4X-GcCMnaHc.js} +1 -1
- package/ui/dist/assets/{ganttDiagram-6RSMTGT7-rxwvD8xn.js → ganttDiagram-6RSMTGT7-4NzDSonj.js} +1 -1
- package/ui/dist/assets/{gitGraphDiagram-PVQCEYII-DjJPiQ2K.js → gitGraphDiagram-PVQCEYII-BXLfDhC_.js} +1 -1
- package/ui/dist/assets/graph-CxZcS9dt.js +2 -0
- package/ui/dist/assets/{infoDiagram-5YYISTIA-BHgtQpBK.js → infoDiagram-5YYISTIA-DLHHvQ1b.js} +1 -1
- package/ui/dist/assets/{ishikawaDiagram-YF4QCWOH-BZ38ndde.js → ishikawaDiagram-YF4QCWOH-BtqY11Uk.js} +1 -1
- package/ui/dist/assets/{journeyDiagram-JHISSGLW-CNaZf5VN.js → journeyDiagram-JHISSGLW-lBwhxW7E.js} +1 -1
- package/ui/dist/assets/{kanban-definition-UN3LZRKU-4h1Jmt_X.js → kanban-definition-UN3LZRKU-C4Q8frPQ.js} +1 -1
- package/ui/dist/assets/main-BuVawP8Y.js +269 -0
- package/ui/dist/assets/{mermaid.core-BZZdRyuR.js → mermaid.core-DdiilVI8.js} +4 -4
- package/ui/dist/assets/{mindmap-definition-RKZ34NQL-DG_NciLX.js → mindmap-definition-RKZ34NQL-CzSxcpUz.js} +1 -1
- package/ui/dist/assets/{pieDiagram-4H26LBE5-B9FyPCLY.js → pieDiagram-4H26LBE5-VQ1Y2aMu.js} +1 -1
- package/ui/dist/assets/{quadrantDiagram-W4KKPZXB-B89WFfQu.js → quadrantDiagram-W4KKPZXB-DHxOr_Bb.js} +1 -1
- package/ui/dist/assets/{requirementDiagram-4Y6WPE33-BYHKePgB.js → requirementDiagram-4Y6WPE33-IruBFJXP.js} +1 -1
- package/ui/dist/assets/{sankeyDiagram-5OEKKPKP-BW6YuBQM.js → sankeyDiagram-5OEKKPKP-J4usxNW5.js} +1 -1
- package/ui/dist/assets/{sequenceDiagram-3UESZ5HK-BnojqKwf.js → sequenceDiagram-3UESZ5HK-C6C-kFaI.js} +1 -1
- package/ui/dist/assets/{stateDiagram-AJRCARHV-C_x9t2o6.js → stateDiagram-AJRCARHV-CJsdQK0K.js} +1 -1
- package/ui/dist/assets/stateDiagram-v2-BHNVJYJU-CnDT2Btz.js +1 -0
- package/ui/dist/assets/theme-BoL8lq0C.css +1 -0
- package/ui/dist/assets/theme-PLJ1jPdr.js +21 -0
- package/ui/dist/assets/{timeline-definition-PNZ67QCA-CI8Ngfzv.js → timeline-definition-PNZ67QCA-DR-akfNv.js} +1 -1
- package/ui/dist/assets/{vennDiagram-CIIHVFJN-CPRKGc2P.js → vennDiagram-CIIHVFJN-HohIp6U7.js} +1 -1
- package/ui/dist/assets/{visual-editor-DUVPRlY3.js → visual-editor-DeCtedTT.js} +12 -12
- package/ui/dist/assets/{wardley-L42UT6IY-CZY42jFT.js → wardley-L42UT6IY-DI0ohKT0.js} +1 -1
- package/ui/dist/assets/{wardleyDiagram-YWT4CUSO-CGKyWKnw.js → wardleyDiagram-YWT4CUSO-C1s7Fzl1.js} +1 -1
- package/ui/dist/assets/{xychartDiagram-2RQKCTM6-Cq-onAc3.js → xychartDiagram-2RQKCTM6-BbPEPR4c.js} +1 -1
- package/ui/dist/graph.html +3 -3
- package/ui/dist/index.html +3 -3
- package/ui/dist/assets/channel-BlWnHbuq.js +0 -1
- package/ui/dist/assets/classDiagram-4FO5ZUOK-D3OdfPqd.js +0 -1
- package/ui/dist/assets/classDiagram-v2-Q7XG4LA2-D3OdfPqd.js +0 -1
- package/ui/dist/assets/graph-D_tIaE_I.js +0 -2
- package/ui/dist/assets/main-BeHrzLrS.js +0 -273
- package/ui/dist/assets/stateDiagram-v2-BHNVJYJU-CBZx8gKT.js +0 -1
- package/ui/dist/assets/theme-CFHWfrn1.css +0 -1
- package/ui/dist/assets/theme-DS1fBM5L.js +0 -1
package/dist/ui/fs-operations.js
CHANGED
|
@@ -8,6 +8,7 @@ import { buildLinkIndexForDocs } from '../tools/explore-graph.js';
|
|
|
8
8
|
import { readPageTemplate } from './templates.js';
|
|
9
9
|
import { isValidFsName, joinRelativePath, normalizeRelativePath, parentRelativePath, resolveRelativeMdPath, resolveUnderKnowledgeRoot, } from './safe-path.js';
|
|
10
10
|
import { cascadeSlugDelete, cascadeSlugRename, toRelativePaths } from './link-cascade.js';
|
|
11
|
+
import { readmeIndexRelativePath, siblingPageIndexRelativePath } from './fs-tree.js';
|
|
11
12
|
function inferTypeFromParent(parentPath) {
|
|
12
13
|
return inferTypeFromRelative(`${parentPath}/page.md`);
|
|
13
14
|
}
|
|
@@ -115,7 +116,7 @@ function rewritePageFrontmatter(absolutePath, newRelativePath) {
|
|
|
115
116
|
fs.writeFileSync(absolutePath, matter.stringify(parsed.content, nextData), 'utf8');
|
|
116
117
|
return { newSlug, newType };
|
|
117
118
|
}
|
|
118
|
-
/** Creates
|
|
119
|
+
/** Creates `{parent}/{basename}/README.md` from a leaf page file. */
|
|
119
120
|
export function promotePageToFolder(index, pagePath) {
|
|
120
121
|
const knowledgeRoot = index.getKnowledgeRoot();
|
|
121
122
|
if (!knowledgeRoot) {
|
|
@@ -151,11 +152,34 @@ export function promotePageToFolder(index, pagePath) {
|
|
|
151
152
|
else {
|
|
152
153
|
fs.mkdirSync(folderAbsolute, { recursive: true });
|
|
153
154
|
}
|
|
154
|
-
const
|
|
155
|
+
const readmeRelative = readmeIndexRelativePath(folderRelative);
|
|
156
|
+
const readmeAbsolute = resolveRelativeMdPath(knowledgeRoot, readmeRelative);
|
|
157
|
+
if (!readmeAbsolute) {
|
|
158
|
+
throw new Error('path escapes docs/');
|
|
159
|
+
}
|
|
160
|
+
if (fs.existsSync(readmeAbsolute)) {
|
|
161
|
+
if (sourceAbsolute === readmeAbsolute) {
|
|
162
|
+
index.refresh();
|
|
163
|
+
const previousSlug = readPageSlug(readmeAbsolute);
|
|
164
|
+
return {
|
|
165
|
+
relativePath: readmeRelative,
|
|
166
|
+
absolutePath: readmeAbsolute,
|
|
167
|
+
slug: previousSlug,
|
|
168
|
+
previousSlug,
|
|
169
|
+
slugChanged: false,
|
|
170
|
+
inboundWarnings: [],
|
|
171
|
+
cascadeUpdated: [],
|
|
172
|
+
folderPath: normalizeRelativePath(folderRelative),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
throw new Error(`folder index already exists: ${readmeRelative}`);
|
|
176
|
+
}
|
|
177
|
+
fs.renameSync(sourceAbsolute, readmeAbsolute);
|
|
178
|
+
const previousSlug = readPageSlug(readmeAbsolute);
|
|
155
179
|
index.refresh();
|
|
156
180
|
return {
|
|
157
|
-
relativePath:
|
|
158
|
-
absolutePath:
|
|
181
|
+
relativePath: readmeRelative,
|
|
182
|
+
absolutePath: readmeAbsolute,
|
|
159
183
|
slug: previousSlug,
|
|
160
184
|
previousSlug,
|
|
161
185
|
slugChanged: false,
|
|
@@ -422,7 +446,12 @@ export function deleteFolder(index, folderPath) {
|
|
|
422
446
|
throw new Error(`not a folder: ${folderPath}`);
|
|
423
447
|
}
|
|
424
448
|
const markdownFiles = listMarkdownFilesRecursive(absolutePath);
|
|
449
|
+
const siblingRelative = siblingPageIndexRelativePath(normalized);
|
|
450
|
+
const siblingAbsolute = siblingRelative === null ? null : resolveRelativeMdPath(knowledgeRoot, siblingRelative);
|
|
425
451
|
const deletedSlugs = markdownFiles.map((filePath) => readPageSlug(filePath));
|
|
452
|
+
if (siblingAbsolute && fs.existsSync(siblingAbsolute)) {
|
|
453
|
+
deletedSlugs.push(readPageSlug(siblingAbsolute));
|
|
454
|
+
}
|
|
426
455
|
const inboundWarnings = mergeInboundWarnings(deletedSlugs.map((slug) => collectInboundWarnings(index, slug)));
|
|
427
456
|
const cascadeUpdated = new Set();
|
|
428
457
|
for (const deletedSlug of deletedSlugs) {
|
|
@@ -433,6 +462,9 @@ export function deleteFolder(index, folderPath) {
|
|
|
433
462
|
}
|
|
434
463
|
}
|
|
435
464
|
fs.rmSync(absolutePath, { recursive: true, force: true });
|
|
465
|
+
if (siblingAbsolute && fs.existsSync(siblingAbsolute)) {
|
|
466
|
+
fs.unlinkSync(siblingAbsolute);
|
|
467
|
+
}
|
|
436
468
|
index.refresh();
|
|
437
469
|
return {
|
|
438
470
|
relativePath: normalized,
|
package/dist/ui/fs-tree.d.ts
CHANGED
|
@@ -9,23 +9,24 @@ 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[];
|
|
15
12
|
}
|
|
16
13
|
export interface TreeFolderNode {
|
|
17
14
|
kind: 'folder';
|
|
18
15
|
name: string;
|
|
19
16
|
relativePath: string;
|
|
20
17
|
emoji: string | null;
|
|
21
|
-
/** Slug of README.md
|
|
18
|
+
/** Slug of the folder index page (README.md or legacy sibling page). */
|
|
22
19
|
indexPageSlug: string | null;
|
|
20
|
+
indexPageTitle: string | null;
|
|
21
|
+
indexPageRelativePath: string | null;
|
|
23
22
|
indexPageType: string | null;
|
|
24
23
|
indexPageContentKind: 'markdown' | 'yaml' | 'json' | null;
|
|
25
24
|
children: TreeNode[];
|
|
26
25
|
}
|
|
27
26
|
export type TreeNode = TreePageNode | TreeFolderNode;
|
|
28
27
|
export declare function readmeIndexRelativePath(folderRelativePath: string): string;
|
|
28
|
+
/** Legacy index path: `{parent}/{folderName}.md` next to `{folderName}/`. */
|
|
29
|
+
export declare function siblingPageIndexRelativePath(folderRelativePath: string): string | null;
|
|
29
30
|
/** Human label for domain folders at `docs/{domain}/`; otherwise basename. */
|
|
30
31
|
export declare function folderDisplayName(relativePath: string): string;
|
|
31
32
|
export declare function buildDocsTree(index: DocIndex): TreeFolderNode | null;
|
package/dist/ui/fs-tree.js
CHANGED
|
@@ -3,25 +3,11 @@ import path from 'node:path';
|
|
|
3
3
|
import { isKnowledgeFileName } from '../index/knowledge-file.js';
|
|
4
4
|
import { DOC_DOMAINS, DOMAIN_LABELS } from '../index/types.js';
|
|
5
5
|
import { catalogEmoji, readCatalogMeta } from './catalog-meta.js';
|
|
6
|
-
import { joinRelativePath, normalizeRelativePath } from './safe-path.js';
|
|
6
|
+
import { joinRelativePath, normalizeRelativePath, parentRelativePath } from './safe-path.js';
|
|
7
7
|
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
|
-
}
|
|
25
11
|
function listDirEntries(dirPath) {
|
|
26
12
|
if (!fs.existsSync(dirPath)) {
|
|
27
13
|
return [];
|
|
@@ -35,6 +21,50 @@ export function readmeIndexRelativePath(folderRelativePath) {
|
|
|
35
21
|
const base = normalizeRelativePath(folderRelativePath);
|
|
36
22
|
return base ? `${base}/README.md` : 'README.md';
|
|
37
23
|
}
|
|
24
|
+
/** Legacy index path: `{parent}/{folderName}.md` next to `{folderName}/`. */
|
|
25
|
+
export function siblingPageIndexRelativePath(folderRelativePath) {
|
|
26
|
+
const base = normalizeRelativePath(folderRelativePath);
|
|
27
|
+
if (!base) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const folderName = path.basename(base);
|
|
31
|
+
return joinRelativePath(parentRelativePath(base), `${folderName}.md`);
|
|
32
|
+
}
|
|
33
|
+
function resolveFolderIndex(relativePath, ctx) {
|
|
34
|
+
const empty = {
|
|
35
|
+
indexPageSlug: null,
|
|
36
|
+
indexPageTitle: null,
|
|
37
|
+
indexPageRelativePath: null,
|
|
38
|
+
indexPageType: null,
|
|
39
|
+
indexPageContentKind: null,
|
|
40
|
+
};
|
|
41
|
+
const readmeRel = readmeIndexRelativePath(relativePath);
|
|
42
|
+
const readmeDoc = ctx.docsByRelative.get(readmeRel);
|
|
43
|
+
if (readmeDoc) {
|
|
44
|
+
return {
|
|
45
|
+
indexPageSlug: readmeDoc.slug,
|
|
46
|
+
indexPageTitle: readmeDoc.title,
|
|
47
|
+
indexPageRelativePath: readmeRel,
|
|
48
|
+
indexPageType: readmeDoc.type,
|
|
49
|
+
indexPageContentKind: readmeDoc.contentKind,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const siblingRel = siblingPageIndexRelativePath(relativePath);
|
|
53
|
+
if (!siblingRel) {
|
|
54
|
+
return empty;
|
|
55
|
+
}
|
|
56
|
+
const siblingDoc = ctx.docsByRelative.get(siblingRel);
|
|
57
|
+
if (!siblingDoc) {
|
|
58
|
+
return empty;
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
indexPageSlug: siblingDoc.slug,
|
|
62
|
+
indexPageTitle: siblingDoc.title,
|
|
63
|
+
indexPageRelativePath: siblingRel,
|
|
64
|
+
indexPageType: siblingDoc.type,
|
|
65
|
+
indexPageContentKind: siblingDoc.contentKind,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
38
68
|
function isDocDomain(name) {
|
|
39
69
|
return DOC_DOMAINS.includes(name);
|
|
40
70
|
}
|
|
@@ -52,25 +82,12 @@ export function folderDisplayName(relativePath) {
|
|
|
52
82
|
function buildFolder(relativePath, absPath, ctx) {
|
|
53
83
|
const entries = listDirEntries(absPath);
|
|
54
84
|
const children = [];
|
|
55
|
-
const
|
|
56
|
-
const readmeRel = readmeIndexRelativePath(relativePath);
|
|
57
|
-
let indexPageSlug = null;
|
|
58
|
-
let indexPageType = null;
|
|
59
|
-
let indexPageContentKind = null;
|
|
60
|
-
const readmeDoc = ctx.docsByRelative.get(readmeRel);
|
|
61
|
-
if (readmeDoc) {
|
|
62
|
-
indexPageSlug = readmeDoc.slug;
|
|
63
|
-
indexPageType = readmeDoc.type;
|
|
64
|
-
indexPageContentKind = readmeDoc.contentKind;
|
|
65
|
-
}
|
|
85
|
+
const folderIndex = resolveFolderIndex(relativePath, ctx);
|
|
66
86
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
67
87
|
if (entry.isDirectory) {
|
|
68
88
|
if (IGNORED_DIRS.has(entry.name)) {
|
|
69
89
|
continue;
|
|
70
90
|
}
|
|
71
|
-
if (hasSiblingKnowledgePage(entries, entry.name)) {
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
91
|
const childRel = joinRelativePath(relativePath, entry.name);
|
|
75
92
|
children.push(buildFolder(childRel, path.join(absPath, entry.name), ctx));
|
|
76
93
|
continue;
|
|
@@ -79,26 +96,11 @@ function buildFolder(relativePath, absPath, ctx) {
|
|
|
79
96
|
continue;
|
|
80
97
|
}
|
|
81
98
|
const fileRel = joinRelativePath(relativePath, entry.name);
|
|
82
|
-
|
|
83
|
-
if (!doc) {
|
|
99
|
+
if (fileRel === folderIndex.indexPageRelativePath) {
|
|
84
100
|
continue;
|
|
85
101
|
}
|
|
86
|
-
const
|
|
87
|
-
if (
|
|
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
|
+
const doc = ctx.docsByRelative.get(fileRel);
|
|
103
|
+
if (!doc) {
|
|
102
104
|
continue;
|
|
103
105
|
}
|
|
104
106
|
children.push({
|
|
@@ -117,9 +119,11 @@ function buildFolder(relativePath, absPath, ctx) {
|
|
|
117
119
|
name: folderDisplayName(relativePath),
|
|
118
120
|
relativePath,
|
|
119
121
|
emoji: catalogEmoji(ctx.meta, relativePath),
|
|
120
|
-
indexPageSlug,
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
indexPageSlug: folderIndex.indexPageSlug,
|
|
123
|
+
indexPageTitle: folderIndex.indexPageTitle,
|
|
124
|
+
indexPageRelativePath: folderIndex.indexPageRelativePath,
|
|
125
|
+
indexPageType: folderIndex.indexPageType,
|
|
126
|
+
indexPageContentKind: folderIndex.indexPageContentKind,
|
|
123
127
|
children,
|
|
124
128
|
};
|
|
125
129
|
}
|
|
@@ -152,14 +156,11 @@ export function findTreePageSlug(node, relativePath) {
|
|
|
152
156
|
if (child.relativePath === normalized) {
|
|
153
157
|
return child.slug;
|
|
154
158
|
}
|
|
155
|
-
if (child.children) {
|
|
156
|
-
const nested = search(child.children);
|
|
157
|
-
if (nested) {
|
|
158
|
-
return nested;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
159
|
continue;
|
|
162
160
|
}
|
|
161
|
+
if (child.indexPageRelativePath === normalized && child.indexPageSlug) {
|
|
162
|
+
return child.indexPageSlug;
|
|
163
|
+
}
|
|
163
164
|
const nested = findTreePageSlug(child, normalized);
|
|
164
165
|
if (nested) {
|
|
165
166
|
return nested;
|
|
@@ -167,6 +168,9 @@ export function findTreePageSlug(node, relativePath) {
|
|
|
167
168
|
}
|
|
168
169
|
return null;
|
|
169
170
|
}
|
|
171
|
+
if (node.indexPageRelativePath === normalized && node.indexPageSlug) {
|
|
172
|
+
return node.indexPageSlug;
|
|
173
|
+
}
|
|
170
174
|
return search(node.children);
|
|
171
175
|
}
|
|
172
176
|
export function collectParentOfEdges(_tree) {
|
package/dist/ui/server.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import http from 'node:http';
|
|
2
2
|
import type { DocIndex } from '../index/doc-index.js';
|
|
3
|
+
import type { UiAuth } from './auth.js';
|
|
3
4
|
import type { DocsWatcher } from './docs-watcher.js';
|
|
4
5
|
import type { DraftsDb } from './db/drafts-db.js';
|
|
5
6
|
export interface UiServerOptions {
|
|
@@ -9,6 +10,7 @@ export interface UiServerOptions {
|
|
|
9
10
|
staticDir: string;
|
|
10
11
|
draftsDb?: DraftsDb;
|
|
11
12
|
docsWatcher?: DocsWatcher;
|
|
13
|
+
auth?: UiAuth | null;
|
|
12
14
|
}
|
|
13
15
|
export declare function createUiServer(options: UiServerOptions): http.Server;
|
|
14
16
|
export declare function resolveUiStaticDir(): string;
|
package/dist/ui/server.js
CHANGED
|
@@ -3,6 +3,7 @@ import http from 'node:http';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { routeApi, handleDocsEvents } from './api-handlers.js';
|
|
6
|
+
import { handleAuthApi } from './auth.js';
|
|
6
7
|
import { handleDraftApi } from './draft-api.js';
|
|
7
8
|
import { serveKnowledgeAsset } from './serve-asset.js';
|
|
8
9
|
import { handleAssetUpload, MAX_ASSET_UPLOAD_BYTES } from './upload-asset.js';
|
|
@@ -44,14 +45,25 @@ function resolveStaticPath(staticDir, requestPath) {
|
|
|
44
45
|
}
|
|
45
46
|
return resolvedFile;
|
|
46
47
|
}
|
|
47
|
-
function sendJson(res, status, body) {
|
|
48
|
+
function sendJson(res, status, body, extraHeaders = {}) {
|
|
48
49
|
const payload = JSON.stringify(body);
|
|
49
50
|
res.writeHead(status, {
|
|
50
51
|
'Content-Type': 'application/json; charset=utf-8',
|
|
51
52
|
'Content-Length': Buffer.byteLength(payload),
|
|
53
|
+
...extraHeaders,
|
|
52
54
|
});
|
|
53
55
|
res.end(payload);
|
|
54
56
|
}
|
|
57
|
+
function sendAuthJson(res, auth, response) {
|
|
58
|
+
const headers = {};
|
|
59
|
+
if (response.setCookie) {
|
|
60
|
+
headers['Set-Cookie'] = response.setCookie;
|
|
61
|
+
}
|
|
62
|
+
else if (response.clearCookie) {
|
|
63
|
+
headers['Set-Cookie'] = auth.clearSessionCookie();
|
|
64
|
+
}
|
|
65
|
+
sendJson(res, response.status, response.body, headers);
|
|
66
|
+
}
|
|
55
67
|
function readBody(req) {
|
|
56
68
|
return new Promise((resolve, reject) => {
|
|
57
69
|
const chunks = [];
|
|
@@ -94,11 +106,60 @@ function serveStatic(res, staticDir, requestPath) {
|
|
|
94
106
|
}
|
|
95
107
|
export function createUiServer(options) {
|
|
96
108
|
const host = options.host ?? '127.0.0.1';
|
|
97
|
-
const { staticDir, index, draftsDb, docsWatcher } = options;
|
|
109
|
+
const { staticDir, index, draftsDb, docsWatcher, auth = null } = options;
|
|
98
110
|
return http.createServer((req, res) => {
|
|
99
111
|
void (async () => {
|
|
100
112
|
const method = req.method ?? 'GET';
|
|
101
113
|
const urlPath = new URL(req.url ?? '/', `http://${host}`).pathname;
|
|
114
|
+
if (urlPath.startsWith('/api/auth/')) {
|
|
115
|
+
if (!auth) {
|
|
116
|
+
if (urlPath === '/api/auth/session' && method === 'GET') {
|
|
117
|
+
sendJson(res, 200, { authenticated: true, required: false });
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
sendJson(res, 404, { error: 'not found' });
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
let bodyRaw = '';
|
|
124
|
+
if (method === 'POST') {
|
|
125
|
+
try {
|
|
126
|
+
bodyRaw = await readBody(req);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
const message = error instanceof Error ? error.message : 'bad request';
|
|
130
|
+
sendJson(res, 400, { error: message });
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const authResponse = handleAuthApi(auth, method, urlPath, bodyRaw, req.headers);
|
|
135
|
+
if (authResponse) {
|
|
136
|
+
sendAuthJson(res, auth, authResponse);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
sendJson(res, 404, { error: 'not found' });
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (auth && !auth.isAuthenticated(req.headers)) {
|
|
143
|
+
if (urlPath.startsWith('/api/')) {
|
|
144
|
+
sendJson(res, 401, { error: 'authentication required' });
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (method !== 'GET' && method !== 'HEAD') {
|
|
148
|
+
sendJson(res, 401, { error: 'authentication required' });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (method === 'HEAD') {
|
|
152
|
+
res.writeHead(401);
|
|
153
|
+
res.end();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (!serveStatic(res, staticDir, urlPath)) {
|
|
157
|
+
sendJson(res, 503, {
|
|
158
|
+
error: 'UI assets not found — run `npm run build:ui` in the repo-mind package',
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
102
163
|
if (urlPath.startsWith('/api/')) {
|
|
103
164
|
if (urlPath === '/api/assets/upload' && method === 'POST') {
|
|
104
165
|
const knowledgeRoot = index.getKnowledgeRoot();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justyork/repo-mind",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Unified docs/ workspace for humans (UI) and AI agents (MCP) — Confluence in your repo",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
11
|
"ui/dist",
|
|
12
|
-
"templates"
|
|
12
|
+
"templates",
|
|
13
|
+
".cursor/skills/repomind-docs"
|
|
13
14
|
],
|
|
14
15
|
"scripts": {
|
|
15
16
|
"build": "tsc && npm run build:ui",
|
|
@@ -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-DdiilVI8.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};
|