@justyork/repo-mind 0.4.0 → 0.7.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/README.md +5 -2
- package/dist/ab-demo/compute-pass.d.ts +24 -0
- package/dist/ab-demo/compute-pass.js +80 -0
- package/dist/ab-demo/live-answer.d.ts +6 -0
- package/dist/ab-demo/live-answer.js +89 -0
- package/dist/ab-demo/live-eval.d.ts +19 -0
- package/dist/ab-demo/live-eval.js +192 -0
- package/dist/ab-demo/paths.d.ts +1 -0
- package/dist/ab-demo/paths.js +3 -0
- package/dist/ab-demo/record-transcript.d.ts +9 -0
- package/dist/ab-demo/record-transcript.js +97 -0
- package/dist/ab-demo/types.d.ts +57 -0
- package/dist/ab-demo/validate-questions.d.ts +5 -0
- package/dist/ab-demo/validate-questions.js +32 -0
- package/dist/agent-write-gate.d.ts +7 -0
- package/dist/agent-write-gate.js +33 -0
- package/dist/cli.js +102 -0
- package/dist/commands/ab-eval.d.ts +11 -0
- package/dist/commands/ab-eval.js +103 -0
- package/dist/commands/publish.d.ts +11 -0
- package/dist/commands/publish.js +91 -0
- package/dist/git/git-exec.d.ts +19 -0
- package/dist/git/git-exec.js +89 -0
- package/dist/git/publish-pr.d.ts +33 -0
- package/dist/git/publish-pr.js +121 -0
- package/dist/index/slug.d.ts +2 -0
- package/dist/index/slug.js +15 -0
- package/dist/mcp/server.js +40 -0
- package/dist/publish/batch-publish.d.ts +29 -0
- package/dist/publish/batch-publish.js +106 -0
- package/dist/tools/create-draft.d.ts +32 -0
- package/dist/tools/create-draft.js +163 -0
- package/package.json +7 -1
- package/ui/dist/assets/{arc-C6B0IXf5.js → arc-DufwQU06.js} +1 -1
- package/ui/dist/assets/{architectureDiagram-3BPJPVTR-BwcC0zwn.js → architectureDiagram-3BPJPVTR-CI2fjjSo.js} +1 -1
- package/ui/dist/assets/{blockDiagram-GPEHLZMM-DIhdWMA6.js → blockDiagram-GPEHLZMM-DVBIs-Z6.js} +1 -1
- package/ui/dist/assets/{c4Diagram-AAUBKEIU-DAe6bsUB.js → c4Diagram-AAUBKEIU-rhAX_HrB.js} +1 -1
- package/ui/dist/assets/channel-Q_-BqwUT.js +1 -0
- package/ui/dist/assets/{chunk-2J33WTMH-Cy3md3pb.js → chunk-2J33WTMH-CxWSQi5S.js} +1 -1
- package/ui/dist/assets/{chunk-4BX2VUAB-CzL8eUDD.js → chunk-4BX2VUAB-BEM-vVbU.js} +1 -1
- package/ui/dist/assets/{chunk-55IACEB6-CbthXzDA.js → chunk-55IACEB6-TcrLDHYx.js} +1 -1
- package/ui/dist/assets/{chunk-727SXJPM-B7ZW-l9j.js → chunk-727SXJPM-D8g4OcIW.js} +1 -1
- package/ui/dist/assets/{chunk-AQP2D5EJ-Vaux-7Ld.js → chunk-AQP2D5EJ-CSvrR8rQ.js} +1 -1
- package/ui/dist/assets/{chunk-FMBD7UC4-C6P2YSWU.js → chunk-FMBD7UC4-C14JNc29.js} +1 -1
- package/ui/dist/assets/{chunk-ND2GUHAM-gSNqdDAn.js → chunk-ND2GUHAM-Cnb0VFKm.js} +1 -1
- package/ui/dist/assets/{chunk-QZHKN3VN-DPPMoZqF.js → chunk-QZHKN3VN-D2pqmAXN.js} +1 -1
- package/ui/dist/assets/classDiagram-4FO5ZUOK-CPrZx4R4.js +1 -0
- package/ui/dist/assets/classDiagram-v2-Q7XG4LA2-CPrZx4R4.js +1 -0
- package/ui/dist/assets/{cose-bilkent-S5V4N54A-Ca4nXCOA.js → cose-bilkent-S5V4N54A-Cli2Sbvt.js} +1 -1
- package/ui/dist/assets/{dagre-BM42HDAG-C-4Y4Jyn.js → dagre-BM42HDAG-gUsVuy4s.js} +1 -1
- package/ui/dist/assets/{diagram-2AECGRRQ-CNv_WVZk.js → diagram-2AECGRRQ-DTKi_1b6.js} +1 -1
- package/ui/dist/assets/{diagram-5GNKFQAL-CNwYGvCw.js → diagram-5GNKFQAL-8Bj0k_-k.js} +1 -1
- package/ui/dist/assets/{diagram-KO2AKTUF-CEULTL49.js → diagram-KO2AKTUF-CKOX2fpv.js} +1 -1
- package/ui/dist/assets/{diagram-LMA3HP47-sGQpPW5i.js → diagram-LMA3HP47-B12JvpF3.js} +1 -1
- package/ui/dist/assets/{diagram-OG6HWLK6-BBEtEBkh.js → diagram-OG6HWLK6-DKeTI9IH.js} +1 -1
- package/ui/dist/assets/editor-DZbRkvnr.js +211 -0
- package/ui/dist/assets/{erDiagram-TEJ5UH35-B4mEdVPJ.js → erDiagram-TEJ5UH35-oDb31edH.js} +1 -1
- package/ui/dist/assets/{flowDiagram-I6XJVG4X-7-OngwLn.js → flowDiagram-I6XJVG4X-SPf3KLS-.js} +1 -1
- package/ui/dist/assets/{ganttDiagram-6RSMTGT7-Bq3z_Nvr.js → ganttDiagram-6RSMTGT7-D8oPEcrt.js} +1 -1
- package/ui/dist/assets/{gitGraphDiagram-PVQCEYII-BjMdjnGR.js → gitGraphDiagram-PVQCEYII-eI9Yp7d7.js} +1 -1
- package/ui/dist/assets/{graph-CwHQTpjf.js → graph-DqCH9VKs.js} +1 -1
- package/ui/dist/assets/{infoDiagram-5YYISTIA-ByORmROU.js → infoDiagram-5YYISTIA-CQ6dtyj3.js} +1 -1
- package/ui/dist/assets/{ishikawaDiagram-YF4QCWOH-B7yRHlcY.js → ishikawaDiagram-YF4QCWOH-BHnOZ8-9.js} +1 -1
- package/ui/dist/assets/{journeyDiagram-JHISSGLW-J5mLr9YH.js → journeyDiagram-JHISSGLW-0t985reH.js} +1 -1
- package/ui/dist/assets/{kanban-definition-UN3LZRKU-B3GyGD8X.js → kanban-definition-UN3LZRKU-vPlhgwPS.js} +1 -1
- package/ui/dist/assets/main-Io6jccwi.js +232 -0
- package/ui/dist/assets/{mermaid.core-C57NVZG0.js → mermaid.core-C2wn2wM5.js} +4 -4
- package/ui/dist/assets/{mindmap-definition-RKZ34NQL-CkcXt9tU.js → mindmap-definition-RKZ34NQL-COKv8bQN.js} +1 -1
- package/ui/dist/assets/{pieDiagram-4H26LBE5-Y7B3kCyQ.js → pieDiagram-4H26LBE5-CgVeawD6.js} +1 -1
- package/ui/dist/assets/{quadrantDiagram-W4KKPZXB-CXKUOw1G.js → quadrantDiagram-W4KKPZXB-Bwpr8PxN.js} +1 -1
- package/ui/dist/assets/{requirementDiagram-4Y6WPE33-DBmmmiXs.js → requirementDiagram-4Y6WPE33-Cc8HFBxl.js} +1 -1
- package/ui/dist/assets/{sankeyDiagram-5OEKKPKP-BNADiaE4.js → sankeyDiagram-5OEKKPKP-B_1nSAK5.js} +1 -1
- package/ui/dist/assets/{sequenceDiagram-3UESZ5HK-CctElOC5.js → sequenceDiagram-3UESZ5HK-hsYrUJza.js} +1 -1
- package/ui/dist/assets/{stateDiagram-AJRCARHV-D40_7g7Y.js → stateDiagram-AJRCARHV-BMf4FL5O.js} +1 -1
- package/ui/dist/assets/stateDiagram-v2-BHNVJYJU-BpaPdu-O.js +1 -0
- package/ui/dist/assets/{theme-DxqwV6dp.js → theme-Dl8H1UuW.js} +1 -1
- package/ui/dist/assets/theme-PE9lQ4bz.css +1 -0
- package/ui/dist/assets/{timeline-definition-PNZ67QCA-DMVhUcek.js → timeline-definition-PNZ67QCA-Cf3u1h2_.js} +1 -1
- package/ui/dist/assets/{vennDiagram-CIIHVFJN-Ci0RqPuV.js → vennDiagram-CIIHVFJN-2uKO3x22.js} +1 -1
- package/ui/dist/assets/visual-editor-D1uYYGOW.js +47 -0
- package/ui/dist/assets/{wardley-L42UT6IY-Chn0BKir.js → wardley-L42UT6IY-BjLaoVtm.js} +1 -1
- package/ui/dist/assets/{wardleyDiagram-YWT4CUSO-BLdXlrC5.js → wardleyDiagram-YWT4CUSO-DlrUKeJk.js} +1 -1
- package/ui/dist/assets/{xychartDiagram-2RQKCTM6-C4gOVVe1.js → xychartDiagram-2RQKCTM6-Bzbb3cqD.js} +1 -1
- package/ui/dist/graph.html +3 -3
- package/ui/dist/index.html +4 -4
- package/ui/dist/assets/channel-C8Q7-wTd.js +0 -1
- package/ui/dist/assets/classDiagram-4FO5ZUOK-pYCdSDhT.js +0 -1
- package/ui/dist/assets/classDiagram-v2-Q7XG4LA2-pYCdSDhT.js +0 -1
- package/ui/dist/assets/editor-BcAuZsp8.js +0 -211
- package/ui/dist/assets/main-Du7fLv5Y.js +0 -244
- package/ui/dist/assets/stateDiagram-v2-BHNVJYJU-DSc6L6rE.js +0 -1
- package/ui/dist/assets/theme-BJgORXba.css +0 -1
- package/ui/dist/assets/visual-editor-UWcMGp6p.js +0 -39
package/dist/index/slug.js
CHANGED
|
@@ -3,6 +3,21 @@ export const SLUG_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
|
|
|
3
3
|
export function isValidSlug(slug) {
|
|
4
4
|
return SLUG_PATTERN.test(slug);
|
|
5
5
|
}
|
|
6
|
+
/** Derives a kebab-case slug from a human title. */
|
|
7
|
+
export function slugFromTitle(title) {
|
|
8
|
+
const normalized = title
|
|
9
|
+
.trim()
|
|
10
|
+
.toLowerCase()
|
|
11
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
12
|
+
.replace(/-+/g, '-')
|
|
13
|
+
.replace(/^-|-$/g, '');
|
|
14
|
+
if (isValidSlug(normalized)) {
|
|
15
|
+
return normalized;
|
|
16
|
+
}
|
|
17
|
+
const fallback = normalized ? `draft-${normalized}` : 'draft';
|
|
18
|
+
const trimmed = fallback.slice(0, 80).replace(/-+$/g, '');
|
|
19
|
+
return isValidSlug(trimmed) ? trimmed : 'draft';
|
|
20
|
+
}
|
|
6
21
|
/** Builds a stable slug from a path relative to the docs root. */
|
|
7
22
|
export function slugFromRelativePath(relativePath) {
|
|
8
23
|
const normalized = relativePath
|
package/dist/mcp/server.js
CHANGED
|
@@ -5,6 +5,7 @@ import { getPackageVersion } from '../package-version.js';
|
|
|
5
5
|
import { DocIndex } from '../index/doc-index.js';
|
|
6
6
|
import { DOC_TYPES, DOC_STATUSES, DOC_DOMAINS } from '../index/types.js';
|
|
7
7
|
import { exploreGraph } from '../tools/explore-graph.js';
|
|
8
|
+
import { createDraft } from '../tools/create-draft.js';
|
|
8
9
|
import { getDoc } from '../tools/get-doc.js';
|
|
9
10
|
import { getGlossaryTerm } from '../tools/get-glossary-term.js';
|
|
10
11
|
import { listDocs } from '../tools/list-docs.js';
|
|
@@ -15,6 +16,7 @@ const TOOL_NAMES = [
|
|
|
15
16
|
'get_doc',
|
|
16
17
|
'get_glossary_term',
|
|
17
18
|
'explore_graph',
|
|
19
|
+
'create_draft',
|
|
18
20
|
];
|
|
19
21
|
function isToolName(name) {
|
|
20
22
|
return TOOL_NAMES.includes(name);
|
|
@@ -85,6 +87,23 @@ export async function startMcpServer() {
|
|
|
85
87
|
required: ['slug'],
|
|
86
88
|
},
|
|
87
89
|
},
|
|
90
|
+
{
|
|
91
|
+
name: 'create_draft',
|
|
92
|
+
description: 'Create a SQLite-backed draft for human review in repo-mind UI (gated on ab-demo kill-switch or REPOMIND_AGENT_WRITE=1).',
|
|
93
|
+
inputSchema: {
|
|
94
|
+
type: 'object',
|
|
95
|
+
properties: {
|
|
96
|
+
type: { type: 'string', enum: [...DOC_TYPES] },
|
|
97
|
+
title: { type: 'string' },
|
|
98
|
+
body: { type: 'string' },
|
|
99
|
+
slug: { type: 'string' },
|
|
100
|
+
related: { type: 'array', items: { type: 'string' } },
|
|
101
|
+
tags: { type: 'array', items: { type: 'string' } },
|
|
102
|
+
forked_from: { type: 'string' },
|
|
103
|
+
},
|
|
104
|
+
required: ['type', 'title', 'body'],
|
|
105
|
+
},
|
|
106
|
+
},
|
|
88
107
|
],
|
|
89
108
|
}));
|
|
90
109
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
@@ -125,6 +144,21 @@ export async function startMcpServer() {
|
|
|
125
144
|
slug: typeof args.slug === 'string' ? args.slug : '',
|
|
126
145
|
depth: typeof args.depth === 'number' ? args.depth : undefined,
|
|
127
146
|
}));
|
|
147
|
+
case 'create_draft': {
|
|
148
|
+
const result = createDraft(index, {
|
|
149
|
+
type: typeof args.type === 'string' ? args.type : '',
|
|
150
|
+
title: typeof args.title === 'string' ? args.title : '',
|
|
151
|
+
body: typeof args.body === 'string' ? args.body : '',
|
|
152
|
+
slug: typeof args.slug === 'string' ? args.slug : undefined,
|
|
153
|
+
related: Array.isArray(args.related) ? args.related : undefined,
|
|
154
|
+
tags: Array.isArray(args.tags) ? args.tags : undefined,
|
|
155
|
+
forked_from: typeof args.forked_from === 'string' ? args.forked_from : undefined,
|
|
156
|
+
});
|
|
157
|
+
if (!result.ok) {
|
|
158
|
+
return toolError(result.error);
|
|
159
|
+
}
|
|
160
|
+
return toolResult(result.data);
|
|
161
|
+
}
|
|
128
162
|
default: {
|
|
129
163
|
const unknownTool = toolName;
|
|
130
164
|
throw new Error(`Unknown tool: ${unknownTool}`);
|
|
@@ -153,3 +187,9 @@ function toolResult(payload) {
|
|
|
153
187
|
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
154
188
|
};
|
|
155
189
|
}
|
|
190
|
+
function toolError(error) {
|
|
191
|
+
return {
|
|
192
|
+
content: [{ type: 'text', text: JSON.stringify({ error }) }],
|
|
193
|
+
isError: true,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { DocIndex } from '../index/doc-index.js';
|
|
2
|
+
import type { DraftsDb } from '../ui/db/drafts-db.js';
|
|
3
|
+
export interface PublishedDraft {
|
|
4
|
+
draftId: string;
|
|
5
|
+
slug: string;
|
|
6
|
+
title: string;
|
|
7
|
+
path: string;
|
|
8
|
+
}
|
|
9
|
+
export interface BatchPublishFailure {
|
|
10
|
+
draftId: string;
|
|
11
|
+
slug: string;
|
|
12
|
+
code: string;
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
15
|
+
export interface BatchPublishResult {
|
|
16
|
+
published: PublishedDraft[];
|
|
17
|
+
failures: BatchPublishFailure[];
|
|
18
|
+
}
|
|
19
|
+
export interface BatchPublishOptions {
|
|
20
|
+
draftIds?: string[];
|
|
21
|
+
dryRun?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function batchPublishDrafts(index: DocIndex, db: DraftsDb, options?: BatchPublishOptions): BatchPublishResult;
|
|
24
|
+
export declare function defaultCommitMessage(published: PublishedDraft[]): string;
|
|
25
|
+
export declare function defaultPrTitle(published: PublishedDraft[]): string;
|
|
26
|
+
export declare function defaultPrBody(published: PublishedDraft[]): string;
|
|
27
|
+
export declare function buildPublishBranchName(published: PublishedDraft[]): string;
|
|
28
|
+
export declare function resolveUniqueBranchName(repoRoot: string, preferred: string): string;
|
|
29
|
+
export declare function relativeDocsPaths(repoRoot: string, absolutePaths: string[]): string[];
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { branchExists } from '../git/git-exec.js';
|
|
3
|
+
import { publishDraft, resolvePublishTargetPath, validateDraftForPublish } from '../ui/publish.js';
|
|
4
|
+
function selectDrafts(db, draftIds) {
|
|
5
|
+
const active = db.listActive();
|
|
6
|
+
if (!draftIds || draftIds.length === 0) {
|
|
7
|
+
return active;
|
|
8
|
+
}
|
|
9
|
+
const byId = new Map(active.map((draft) => [draft.id, draft]));
|
|
10
|
+
return draftIds.map((id) => byId.get(id) ?? null).filter((draft) => draft !== null);
|
|
11
|
+
}
|
|
12
|
+
export function batchPublishDrafts(index, db, options = {}) {
|
|
13
|
+
const drafts = selectDrafts(db, options.draftIds);
|
|
14
|
+
const failures = [];
|
|
15
|
+
const validated = [];
|
|
16
|
+
for (const draft of drafts) {
|
|
17
|
+
const validation = validateDraftForPublish(index, draft);
|
|
18
|
+
if (validation) {
|
|
19
|
+
failures.push({
|
|
20
|
+
draftId: draft.id,
|
|
21
|
+
slug: draft.slug,
|
|
22
|
+
code: validation.code,
|
|
23
|
+
message: validation.message,
|
|
24
|
+
});
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
validated.push(draft);
|
|
28
|
+
}
|
|
29
|
+
if (failures.length > 0) {
|
|
30
|
+
return { published: [], failures };
|
|
31
|
+
}
|
|
32
|
+
if (options.dryRun) {
|
|
33
|
+
return {
|
|
34
|
+
published: validated.map((draft) => ({
|
|
35
|
+
draftId: draft.id,
|
|
36
|
+
slug: draft.slug,
|
|
37
|
+
title: draft.title,
|
|
38
|
+
path: resolvePublishTargetPath(index, draft) ?? '(unresolved)',
|
|
39
|
+
})),
|
|
40
|
+
failures: [],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const published = [];
|
|
44
|
+
for (const draft of validated) {
|
|
45
|
+
const result = publishDraft(index, draft);
|
|
46
|
+
db.markPublished(draft.id, result.path);
|
|
47
|
+
published.push({
|
|
48
|
+
draftId: draft.id,
|
|
49
|
+
slug: draft.slug,
|
|
50
|
+
title: draft.title,
|
|
51
|
+
path: result.path,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return { published, failures: [] };
|
|
55
|
+
}
|
|
56
|
+
export function defaultCommitMessage(published) {
|
|
57
|
+
const lines = ['docs: publish via repo-mind', ''];
|
|
58
|
+
for (const item of published) {
|
|
59
|
+
lines.push(`- ${item.slug} (${item.title})`);
|
|
60
|
+
}
|
|
61
|
+
return lines.join('\n').trim();
|
|
62
|
+
}
|
|
63
|
+
export function defaultPrTitle(published) {
|
|
64
|
+
if (published.length === 1) {
|
|
65
|
+
return `docs: publish ${published[0].slug}`;
|
|
66
|
+
}
|
|
67
|
+
return `docs: publish ${published.length} pages via repo-mind`;
|
|
68
|
+
}
|
|
69
|
+
export function defaultPrBody(published) {
|
|
70
|
+
const lines = [
|
|
71
|
+
'## Summary',
|
|
72
|
+
'',
|
|
73
|
+
'Published knowledge pages from repo-mind drafts:',
|
|
74
|
+
'',
|
|
75
|
+
];
|
|
76
|
+
for (const item of published) {
|
|
77
|
+
lines.push(`- \`${item.slug}\` — ${item.title}`);
|
|
78
|
+
}
|
|
79
|
+
lines.push('', '## Test plan', '', '- [ ] `repo-mind check` passes', '- [ ] Pages render in repo-mind UI');
|
|
80
|
+
return lines.join('\n');
|
|
81
|
+
}
|
|
82
|
+
export function buildPublishBranchName(published) {
|
|
83
|
+
const slugPart = published
|
|
84
|
+
.map((item) => item.slug)
|
|
85
|
+
.slice(0, 2)
|
|
86
|
+
.join('-')
|
|
87
|
+
.slice(0, 40);
|
|
88
|
+
const stamp = new Date().toISOString().replace(/[-:]/g, '').slice(0, 13);
|
|
89
|
+
const suffix = slugPart ? `${slugPart}-${stamp}` : stamp;
|
|
90
|
+
return `repo-mind/publish/${suffix}`;
|
|
91
|
+
}
|
|
92
|
+
export function resolveUniqueBranchName(repoRoot, preferred) {
|
|
93
|
+
if (!branchExists(repoRoot, preferred)) {
|
|
94
|
+
return preferred;
|
|
95
|
+
}
|
|
96
|
+
for (let index = 2; index <= 9; index += 1) {
|
|
97
|
+
const candidate = `${preferred}-${index}`;
|
|
98
|
+
if (!branchExists(repoRoot, candidate)) {
|
|
99
|
+
return candidate;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return `${preferred}-${Date.now().toString(36)}`;
|
|
103
|
+
}
|
|
104
|
+
export function relativeDocsPaths(repoRoot, absolutePaths) {
|
|
105
|
+
return absolutePaths.map((absolutePath) => path.relative(repoRoot, absolutePath).replace(/\\/g, '/'));
|
|
106
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { DocIndex } from '../index/doc-index.js';
|
|
2
|
+
export type CreateDraftErrorCode = 'AGENT_WRITE_DISABLED' | 'BAD_TYPE' | 'BAD_SLUG' | 'BAD_TITLE' | 'DRAFT_EXISTS' | 'DOC_NOT_FOUND' | 'NO_KNOWLEDGE_ROOT' | 'SLUG_CONFLICT' | 'WRITE_CONFLICT';
|
|
3
|
+
export interface CreateDraftError {
|
|
4
|
+
code: CreateDraftErrorCode;
|
|
5
|
+
message: string;
|
|
6
|
+
hint?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface CreateDraftSuccess {
|
|
9
|
+
draftId: string;
|
|
10
|
+
slug: string;
|
|
11
|
+
title: string;
|
|
12
|
+
type: string;
|
|
13
|
+
editUrl: string;
|
|
14
|
+
editHint: string;
|
|
15
|
+
}
|
|
16
|
+
export type CreateDraftResult = {
|
|
17
|
+
ok: true;
|
|
18
|
+
data: CreateDraftSuccess;
|
|
19
|
+
} | {
|
|
20
|
+
ok: false;
|
|
21
|
+
error: CreateDraftError;
|
|
22
|
+
};
|
|
23
|
+
export interface CreateDraftInput {
|
|
24
|
+
type: string;
|
|
25
|
+
title: string;
|
|
26
|
+
body: string;
|
|
27
|
+
slug?: string;
|
|
28
|
+
related?: string[];
|
|
29
|
+
tags?: string[];
|
|
30
|
+
forked_from?: string;
|
|
31
|
+
}
|
|
32
|
+
export declare function createDraft(index: DocIndex, rawInput: CreateDraftInput, cwd?: string): CreateDraftResult;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { isValidSlug, slugFromTitle } from '../index/slug.js';
|
|
2
|
+
import { DOC_TYPES, isDocType } from '../index/types.js';
|
|
3
|
+
import { getAgentWriteGate } from '../agent-write-gate.js';
|
|
4
|
+
import { getDoc } from './get-doc.js';
|
|
5
|
+
import { openDraftsDb } from '../ui/db/drafts-db.js';
|
|
6
|
+
function stringArray(value) {
|
|
7
|
+
if (!Array.isArray(value)) {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
return value.filter((item) => typeof item === 'string');
|
|
11
|
+
}
|
|
12
|
+
function normalizeInput(raw) {
|
|
13
|
+
return {
|
|
14
|
+
type: raw.type.trim(),
|
|
15
|
+
title: raw.title.trim(),
|
|
16
|
+
body: raw.body,
|
|
17
|
+
slug: typeof raw.slug === 'string' && raw.slug.trim() ? raw.slug.trim() : undefined,
|
|
18
|
+
related: stringArray(raw.related),
|
|
19
|
+
tags: stringArray(raw.tags),
|
|
20
|
+
forked_from: typeof raw.forked_from === 'string' && raw.forked_from.trim()
|
|
21
|
+
? raw.forked_from.trim()
|
|
22
|
+
: undefined,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function fail(code, message, hint) {
|
|
26
|
+
return { ok: false, error: { code, message, hint } };
|
|
27
|
+
}
|
|
28
|
+
function success(draft) {
|
|
29
|
+
const editUrl = `/?draft=${encodeURIComponent(draft.id)}`;
|
|
30
|
+
return {
|
|
31
|
+
ok: true,
|
|
32
|
+
data: {
|
|
33
|
+
draftId: draft.id,
|
|
34
|
+
slug: draft.slug,
|
|
35
|
+
title: draft.title,
|
|
36
|
+
type: draft.type,
|
|
37
|
+
editUrl,
|
|
38
|
+
editHint: `Run \`repo-mind ui\` and open draft "${draft.title}" in the sidebar (${editUrl}).`,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function slugTaken(index, slug, allowExistingDoc) {
|
|
43
|
+
if (index.getDocBySlug(slug) && !allowExistingDoc) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
function resolveAvailableSlug(index, db, base, options) {
|
|
49
|
+
if (!isValidSlug(base)) {
|
|
50
|
+
return { code: 'BAD_SLUG', message: `invalid slug: ${base}` };
|
|
51
|
+
}
|
|
52
|
+
const isFree = (slug) => !db.getActiveBySlug(slug) && !slugTaken(index, slug, options.allowExistingDoc);
|
|
53
|
+
if (isFree(base)) {
|
|
54
|
+
return base;
|
|
55
|
+
}
|
|
56
|
+
if (!options.autoSuffix) {
|
|
57
|
+
if (db.getActiveBySlug(base)) {
|
|
58
|
+
return {
|
|
59
|
+
code: 'DRAFT_EXISTS',
|
|
60
|
+
message: `active draft already exists for slug: ${base}`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
code: 'SLUG_CONFLICT',
|
|
65
|
+
message: `published document already exists for slug: ${base}`,
|
|
66
|
+
hint: 'Use forked_from to edit an existing page, or omit slug to auto-assign a suffix.',
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
for (let suffix = 2; suffix <= 9; suffix += 1) {
|
|
70
|
+
const candidate = `${base}-${suffix}`;
|
|
71
|
+
if (isValidSlug(candidate) && isFree(candidate)) {
|
|
72
|
+
return candidate;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
code: 'WRITE_CONFLICT',
|
|
77
|
+
message: `could not allocate slug for base: ${base}`,
|
|
78
|
+
hint: 'All slug suffixes -2 through -9 are taken.',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function createDraft(index, rawInput, cwd = process.cwd()) {
|
|
82
|
+
const gate = getAgentWriteGate(cwd);
|
|
83
|
+
if (!gate.enabled) {
|
|
84
|
+
return fail('AGENT_WRITE_DISABLED', gate.reason, 'Set REPOMIND_AGENT_WRITE=1 for local override.');
|
|
85
|
+
}
|
|
86
|
+
const knowledgeRoot = index.getKnowledgeRoot();
|
|
87
|
+
if (!knowledgeRoot) {
|
|
88
|
+
return fail('NO_KNOWLEDGE_ROOT', 'no docs/ knowledge root found');
|
|
89
|
+
}
|
|
90
|
+
const input = normalizeInput(rawInput);
|
|
91
|
+
const db = openDraftsDb(knowledgeRoot);
|
|
92
|
+
try {
|
|
93
|
+
if (input.forked_from) {
|
|
94
|
+
if (!isValidSlug(input.forked_from)) {
|
|
95
|
+
return fail('BAD_SLUG', `invalid forked_from slug: ${input.forked_from}`);
|
|
96
|
+
}
|
|
97
|
+
const existing = db.getActiveBySlug(input.forked_from);
|
|
98
|
+
if (existing) {
|
|
99
|
+
return fail('DRAFT_EXISTS', `active draft already exists for slug: ${input.forked_from}`);
|
|
100
|
+
}
|
|
101
|
+
const doc = getDoc(index, input.forked_from);
|
|
102
|
+
if (!doc.found || !doc.slug || !doc.frontmatter) {
|
|
103
|
+
return fail('DOC_NOT_FOUND', `document not found: ${input.forked_from}`);
|
|
104
|
+
}
|
|
105
|
+
const docRecord = index.getDocBySlug(input.forked_from);
|
|
106
|
+
try {
|
|
107
|
+
const draft = db.create({
|
|
108
|
+
slug: doc.slug,
|
|
109
|
+
type: doc.frontmatter.type,
|
|
110
|
+
title: input.title || doc.frontmatter.title || doc.slug,
|
|
111
|
+
body: input.body || doc.body || '',
|
|
112
|
+
tags: (input.tags ?? []).length > 0 ? input.tags ?? [] : (doc.frontmatter.tags ?? []),
|
|
113
|
+
related: (input.related ?? []).length > 0 ? input.related ?? [] : (doc.frontmatter.related ?? []),
|
|
114
|
+
forked_from: doc.slug,
|
|
115
|
+
target_path: docRecord?.relativePath ?? null,
|
|
116
|
+
});
|
|
117
|
+
return success(draft);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
121
|
+
if (message.includes('already exists')) {
|
|
122
|
+
return fail('DRAFT_EXISTS', message);
|
|
123
|
+
}
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (!input.title) {
|
|
128
|
+
return fail('BAD_TITLE', 'title is required');
|
|
129
|
+
}
|
|
130
|
+
if (!isDocType(input.type)) {
|
|
131
|
+
return fail('BAD_TYPE', `invalid type — expected one of: ${DOC_TYPES.join(', ')}`);
|
|
132
|
+
}
|
|
133
|
+
const baseSlug = input.slug ?? slugFromTitle(input.title);
|
|
134
|
+
const resolved = resolveAvailableSlug(index, db, baseSlug, {
|
|
135
|
+
autoSuffix: !input.slug,
|
|
136
|
+
allowExistingDoc: false,
|
|
137
|
+
});
|
|
138
|
+
if (typeof resolved !== 'string') {
|
|
139
|
+
return { ok: false, error: resolved };
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
const draft = db.create({
|
|
143
|
+
slug: resolved,
|
|
144
|
+
type: input.type,
|
|
145
|
+
title: input.title,
|
|
146
|
+
body: input.body,
|
|
147
|
+
tags: input.tags,
|
|
148
|
+
related: input.related,
|
|
149
|
+
});
|
|
150
|
+
return success(draft);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
154
|
+
if (message.includes('already exists')) {
|
|
155
|
+
return fail('DRAFT_EXISTS', message);
|
|
156
|
+
}
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
finally {
|
|
161
|
+
db.close();
|
|
162
|
+
}
|
|
163
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justyork/repo-mind",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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": {
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"test:watch": "vitest",
|
|
19
19
|
"ab-demo": "npm run build --silent && node dist/ab-demo/run-ab.js --dry-run",
|
|
20
20
|
"ab-demo:run": "npm run build --silent && node dist/ab-demo/run-ab.js",
|
|
21
|
+
"ab-eval:live": "npm run build --silent && node dist/cli.js ab-eval",
|
|
21
22
|
"prepublishOnly": "npm run build"
|
|
22
23
|
},
|
|
23
24
|
"engines": {
|
|
@@ -45,9 +46,14 @@
|
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@tiptap/core": "^2.27.2",
|
|
49
|
+
"@tiptap/extension-code-block": "^2.27.2",
|
|
48
50
|
"@tiptap/extension-image": "^2.27.2",
|
|
49
51
|
"@tiptap/extension-link": "^2.27.2",
|
|
50
52
|
"@tiptap/extension-placeholder": "^2.27.2",
|
|
53
|
+
"@tiptap/extension-table": "^2.27.2",
|
|
54
|
+
"@tiptap/extension-table-cell": "^2.27.2",
|
|
55
|
+
"@tiptap/extension-table-header": "^2.27.2",
|
|
56
|
+
"@tiptap/extension-table-row": "^2.27.2",
|
|
51
57
|
"@tiptap/extension-task-item": "^2.27.2",
|
|
52
58
|
"@tiptap/extension-task-list": "^2.27.2",
|
|
53
59
|
"@tiptap/pm": "^2.27.2",
|
|
@@ -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-C2wn2wM5.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};
|