@valkyrianlabs/payload-markdown-docs 0.1.0-canary.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 +195 -0
- package/dist/admin/DocsSetManager.d.ts +2 -0
- package/dist/admin/DocsSetManager.js +298 -0
- package/dist/admin/DocsSetManager.js.map +1 -0
- package/dist/admin/docsSetManagerData.d.ts +25 -0
- package/dist/admin/docsSetManagerData.js +266 -0
- package/dist/admin/docsSetManagerData.js.map +1 -0
- package/dist/admin/docsSetManagerTypes.d.ts +103 -0
- package/dist/admin/docsSetManagerTypes.js +3 -0
- package/dist/admin/docsSetManagerTypes.js.map +1 -0
- package/dist/admin/index.d.ts +3 -0
- package/dist/admin/index.js +4 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/cli/commands/install.d.ts +2 -0
- package/dist/cli/commands/install.js +211 -0
- package/dist/cli/commands/install.js.map +1 -0
- package/dist/cli/commands/keygen.d.ts +2 -0
- package/dist/cli/commands/keygen.js +89 -0
- package/dist/cli/commands/keygen.js.map +1 -0
- package/dist/cli/commands/manifest.d.ts +2 -0
- package/dist/cli/commands/manifest.js +50 -0
- package/dist/cli/commands/manifest.js.map +1 -0
- package/dist/cli/commands/plan.d.ts +2 -0
- package/dist/cli/commands/plan.js +110 -0
- package/dist/cli/commands/plan.js.map +1 -0
- package/dist/cli/commands/push.d.ts +3 -0
- package/dist/cli/commands/push.js +308 -0
- package/dist/cli/commands/push.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +3 -0
- package/dist/cli/commands/validate.js +109 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/filesystem.d.ts +20 -0
- package/dist/cli/filesystem.js +96 -0
- package/dist/cli/filesystem.js.map +1 -0
- package/dist/cli/format.d.ts +35 -0
- package/dist/cli/format.js +76 -0
- package/dist/cli/format.js.map +1 -0
- package/dist/cli/http.d.ts +19 -0
- package/dist/cli/http.js +39 -0
- package/dist/cli/http.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +214 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/parseArgs.d.ts +5 -0
- package/dist/cli/parseArgs.js +219 -0
- package/dist/cli/parseArgs.js.map +1 -0
- package/dist/cli/types.d.ts +51 -0
- package/dist/cli/types.js +3 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/collections/docs.d.ts +9 -0
- package/dist/collections/docs.js +168 -0
- package/dist/collections/docs.js.map +1 -0
- package/dist/collections/docsGroups.d.ts +5 -0
- package/dist/collections/docsGroups.js +57 -0
- package/dist/collections/docsGroups.js.map +1 -0
- package/dist/collections/docsSets.d.ts +8 -0
- package/dist/collections/docsSets.js +158 -0
- package/dist/collections/docsSets.js.map +1 -0
- package/dist/collections/index.d.ts +10 -0
- package/dist/collections/index.js +7 -0
- package/dist/collections/index.js.map +1 -0
- package/dist/collections/nonces.d.ts +6 -0
- package/dist/collections/nonces.js +57 -0
- package/dist/collections/nonces.js.map +1 -0
- package/dist/collections/syncRuns.d.ts +5 -0
- package/dist/collections/syncRuns.js +139 -0
- package/dist/collections/syncRuns.js.map +1 -0
- package/dist/constants.d.ts +21 -0
- package/dist/constants.js +23 -0
- package/dist/constants.js.map +1 -0
- package/dist/endpoints/index.d.ts +2 -0
- package/dist/endpoints/index.js +3 -0
- package/dist/endpoints/index.js.map +1 -0
- package/dist/endpoints/sync.d.ts +47 -0
- package/dist/endpoints/sync.js +616 -0
- package/dist/endpoints/sync.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/next/PayloadMarkdownDocsPage.d.ts +7 -0
- package/dist/next/PayloadMarkdownDocsPage.js +142 -0
- package/dist/next/PayloadMarkdownDocsPage.js.map +1 -0
- package/dist/next/index.d.ts +9 -0
- package/dist/next/index.js +7 -0
- package/dist/next/index.js.map +1 -0
- package/dist/next/markdown.d.ts +14 -0
- package/dist/next/markdown.js +232 -0
- package/dist/next/markdown.js.map +1 -0
- package/dist/next/metadata.d.ts +3 -0
- package/dist/next/metadata.js +33 -0
- package/dist/next/metadata.js.map +1 -0
- package/dist/next/records.d.ts +14 -0
- package/dist/next/records.js +146 -0
- package/dist/next/records.js.map +1 -0
- package/dist/next/route.d.ts +6 -0
- package/dist/next/route.js +271 -0
- package/dist/next/route.js.map +1 -0
- package/dist/next/sidebar.d.ts +15 -0
- package/dist/next/sidebar.js +137 -0
- package/dist/next/sidebar.js.map +1 -0
- package/dist/next/types.d.ts +117 -0
- package/dist/next/types.js +3 -0
- package/dist/next/types.js.map +1 -0
- package/dist/payload/applyDocsSync.d.ts +54 -0
- package/dist/payload/applyDocsSync.js +176 -0
- package/dist/payload/applyDocsSync.js.map +1 -0
- package/dist/payload/docsConflicts.d.ts +12 -0
- package/dist/payload/docsConflicts.js +34 -0
- package/dist/payload/docsConflicts.js.map +1 -0
- package/dist/payload/docsData.d.ts +23 -0
- package/dist/payload/docsData.js +59 -0
- package/dist/payload/docsData.js.map +1 -0
- package/dist/payload/docsSets.d.ts +38 -0
- package/dist/payload/docsSets.js +57 -0
- package/dist/payload/docsSets.js.map +1 -0
- package/dist/payload/existingDocs.d.ts +43 -0
- package/dist/payload/existingDocs.js +97 -0
- package/dist/payload/existingDocs.js.map +1 -0
- package/dist/payload/index.d.ts +15 -0
- package/dist/payload/index.js +10 -0
- package/dist/payload/index.js.map +1 -0
- package/dist/payload/routeCollisions.d.ts +31 -0
- package/dist/payload/routeCollisions.js +104 -0
- package/dist/payload/routeCollisions.js.map +1 -0
- package/dist/payload/syncRuns.d.ts +60 -0
- package/dist/payload/syncRuns.js +53 -0
- package/dist/payload/syncRuns.js.map +1 -0
- package/dist/plugin.d.ts +3 -0
- package/dist/plugin.js +165 -0
- package/dist/plugin.js.map +1 -0
- package/dist/routing/index.d.ts +3 -0
- package/dist/routing/index.js +4 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/routing/paths.d.ts +7 -0
- package/dist/routing/paths.js +23 -0
- package/dist/routing/paths.js.map +1 -0
- package/dist/routing/reservations.d.ts +37 -0
- package/dist/routing/reservations.js +79 -0
- package/dist/routing/reservations.js.map +1 -0
- package/dist/security/canonical.d.ts +12 -0
- package/dist/security/canonical.js +24 -0
- package/dist/security/canonical.js.map +1 -0
- package/dist/security/githubOidc.d.ts +45 -0
- package/dist/security/githubOidc.js +177 -0
- package/dist/security/githubOidc.js.map +1 -0
- package/dist/security/headers.d.ts +22 -0
- package/dist/security/headers.js +44 -0
- package/dist/security/headers.js.map +1 -0
- package/dist/security/index.d.ts +15 -0
- package/dist/security/index.js +9 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/jwks.d.ts +20 -0
- package/dist/security/jwks.js +40 -0
- package/dist/security/jwks.js.map +1 -0
- package/dist/security/jwt.d.ts +10 -0
- package/dist/security/jwt.js +42 -0
- package/dist/security/jwt.js.map +1 -0
- package/dist/security/nonce.d.ts +34 -0
- package/dist/security/nonce.js +43 -0
- package/dist/security/nonce.js.map +1 -0
- package/dist/security/sign.d.ts +13 -0
- package/dist/security/sign.js +39 -0
- package/dist/security/sign.js.map +1 -0
- package/dist/security/verify.d.ts +28 -0
- package/dist/security/verify.js +54 -0
- package/dist/security/verify.js.map +1 -0
- package/dist/skills/codex/SKILL.md +173 -0
- package/dist/skills/codex/examples/docs-page.md +42 -0
- package/dist/skills/codex/examples/github-actions.md +64 -0
- package/dist/skills/codex/reference/admin.md +28 -0
- package/dist/skills/codex/reference/frontmatter.md +39 -0
- package/dist/skills/codex/reference/payload-markdown-directives.md +77 -0
- package/dist/skills/codex/reference/routing.md +35 -0
- package/dist/skills/codex/reference/sync.md +35 -0
- package/dist/skills/codex/reference/troubleshooting.md +53 -0
- package/dist/skills/codex/reference/workflow.md +39 -0
- package/dist/sync/aiExportManifest.d.ts +58 -0
- package/dist/sync/aiExportManifest.js +430 -0
- package/dist/sync/aiExportManifest.js.map +1 -0
- package/dist/sync/frontmatter.d.ts +28 -0
- package/dist/sync/frontmatter.js +210 -0
- package/dist/sync/frontmatter.js.map +1 -0
- package/dist/sync/hash.d.ts +1 -0
- package/dist/sync/hash.js +8 -0
- package/dist/sync/hash.js.map +1 -0
- package/dist/sync/index.d.ts +12 -0
- package/dist/sync/index.js +9 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/manifest.d.ts +58 -0
- package/dist/sync/manifest.js +21 -0
- package/dist/sync/manifest.js.map +1 -0
- package/dist/sync/paths.d.ts +16 -0
- package/dist/sync/paths.js +116 -0
- package/dist/sync/paths.js.map +1 -0
- package/dist/sync/plan.d.ts +29 -0
- package/dist/sync/plan.js +72 -0
- package/dist/sync/plan.js.map +1 -0
- package/dist/sync/validate.d.ts +26 -0
- package/dist/sync/validate.js +308 -0
- package/dist/sync/validate.js.map +1 -0
- package/dist/types.d.ts +84 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +143 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { DEFAULT_DOCS_COLLECTION_SLUG, DEFAULT_DOCS_SETS_COLLECTION_SLUG } from '../constants.js';
|
|
2
|
+
const isRecord = (value)=>typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3
|
+
const getRecordId = (doc)=>{
|
|
4
|
+
if (!isRecord(doc)) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
if (typeof doc.id === 'string' || typeof doc.id === 'number') {
|
|
8
|
+
return String(doc.id);
|
|
9
|
+
}
|
|
10
|
+
return undefined;
|
|
11
|
+
};
|
|
12
|
+
const getRelationshipId = (value)=>{
|
|
13
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
14
|
+
return String(value);
|
|
15
|
+
}
|
|
16
|
+
return getRecordId(value);
|
|
17
|
+
};
|
|
18
|
+
const normalizeAdminRoute = (adminRoute = '/admin')=>{
|
|
19
|
+
const trimmed = adminRoute.trim();
|
|
20
|
+
if (!trimmed || trimmed === '/') {
|
|
21
|
+
return '/admin';
|
|
22
|
+
}
|
|
23
|
+
return `/${trimmed}`.replace(/\/+/g, '/').replace(/\/+$/g, '');
|
|
24
|
+
};
|
|
25
|
+
export const getGeneratedDocAdminURL = ({ id, adminRoute, docsCollectionSlug })=>`${normalizeAdminRoute(adminRoute)}/collections/${docsCollectionSlug}/${encodeURIComponent(id)}`;
|
|
26
|
+
const hasText = (value)=>typeof value === 'string' && value.trim().length > 0;
|
|
27
|
+
const getOverrideSummary = (overrides)=>{
|
|
28
|
+
if (!overrides || !isRecord(overrides)) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
const summary = [];
|
|
32
|
+
if (hasText(overrides.navTitle)) {
|
|
33
|
+
summary.push('Nav title override');
|
|
34
|
+
}
|
|
35
|
+
if (overrides.hideFromNav === true) {
|
|
36
|
+
summary.push('Hidden from nav');
|
|
37
|
+
}
|
|
38
|
+
if (hasText(overrides.theme)) {
|
|
39
|
+
summary.push('Theme override');
|
|
40
|
+
}
|
|
41
|
+
if (hasText(overrides.heroEyebrow) || hasText(overrides.heroTitle) || hasText(overrides.heroDescription)) {
|
|
42
|
+
summary.push('Hero override');
|
|
43
|
+
}
|
|
44
|
+
if (hasText(overrides.seoTitle) || hasText(overrides.seoDescription)) {
|
|
45
|
+
summary.push('SEO override');
|
|
46
|
+
}
|
|
47
|
+
return summary;
|
|
48
|
+
};
|
|
49
|
+
const getDocStatus = (doc)=>{
|
|
50
|
+
if (doc.sync?.archived === true) {
|
|
51
|
+
return 'archived';
|
|
52
|
+
}
|
|
53
|
+
if (doc._status === 'draft') {
|
|
54
|
+
return 'draft';
|
|
55
|
+
}
|
|
56
|
+
if (doc._status === 'published') {
|
|
57
|
+
return 'published';
|
|
58
|
+
}
|
|
59
|
+
return 'synced';
|
|
60
|
+
};
|
|
61
|
+
const getSourcePathSegments = (sourcePath)=>{
|
|
62
|
+
const withoutExtension = sourcePath.replace(/\.md$/i, '');
|
|
63
|
+
const segments = withoutExtension.split('/').filter(Boolean);
|
|
64
|
+
if (segments.at(-1) === 'index') {
|
|
65
|
+
return segments.slice(0, -1);
|
|
66
|
+
}
|
|
67
|
+
return segments;
|
|
68
|
+
};
|
|
69
|
+
const titleCaseSegment = (segment)=>segment.split(/[-_]+/).filter(Boolean).map((part)=>`${part.charAt(0).toUpperCase()}${part.slice(1)}`).join(' ');
|
|
70
|
+
const compareDocItems = (first, second)=>{
|
|
71
|
+
if (first.order !== second.order) {
|
|
72
|
+
return first.order - second.order;
|
|
73
|
+
}
|
|
74
|
+
if (first.sourcePath !== second.sourcePath) {
|
|
75
|
+
return first.sourcePath.localeCompare(second.sourcePath);
|
|
76
|
+
}
|
|
77
|
+
return first.route.localeCompare(second.route);
|
|
78
|
+
};
|
|
79
|
+
const getOrCreateFolder = ({ items, order, segment, sourcePath })=>{
|
|
80
|
+
const existing = items.find((item)=>item.kind === 'folder' && item.sourcePath === sourcePath);
|
|
81
|
+
if (existing) {
|
|
82
|
+
existing.order = Math.min(existing.order, order);
|
|
83
|
+
return existing;
|
|
84
|
+
}
|
|
85
|
+
const folder = {
|
|
86
|
+
id: `folder:${sourcePath}`,
|
|
87
|
+
children: [],
|
|
88
|
+
kind: 'folder',
|
|
89
|
+
order,
|
|
90
|
+
overrideSummary: [],
|
|
91
|
+
route: '',
|
|
92
|
+
sourcePath,
|
|
93
|
+
status: 'synced',
|
|
94
|
+
title: titleCaseSegment(segment)
|
|
95
|
+
};
|
|
96
|
+
items.push(folder);
|
|
97
|
+
return folder;
|
|
98
|
+
};
|
|
99
|
+
const insertIntoTree = ({ item, tree })=>{
|
|
100
|
+
const segments = getSourcePathSegments(item.sourcePath);
|
|
101
|
+
if (segments.length <= 1) {
|
|
102
|
+
tree.push(item);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
let currentItems = tree;
|
|
106
|
+
for (const [index, segment] of segments.slice(0, -1).entries()){
|
|
107
|
+
const sourcePath = segments.slice(0, index + 1).join('/');
|
|
108
|
+
const folder = getOrCreateFolder({
|
|
109
|
+
items: currentItems,
|
|
110
|
+
order: item.order,
|
|
111
|
+
segment,
|
|
112
|
+
sourcePath
|
|
113
|
+
});
|
|
114
|
+
folder.children ??= [];
|
|
115
|
+
currentItems = folder.children;
|
|
116
|
+
}
|
|
117
|
+
currentItems.push(item);
|
|
118
|
+
};
|
|
119
|
+
const sortTree = (items)=>{
|
|
120
|
+
items.sort(compareDocItems);
|
|
121
|
+
for (const item of items){
|
|
122
|
+
if (item.children) {
|
|
123
|
+
sortTree(item.children);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const toDocItem = ({ adminRoute, doc, docsCollectionSlug, index, warnings })=>{
|
|
128
|
+
const id = getRecordId(doc) ?? `unknown-${index}`;
|
|
129
|
+
const route = hasText(doc.route) ? doc.route : '';
|
|
130
|
+
const sourcePath = hasText(doc.sourcePath) ? doc.sourcePath : `missing-source-path-${id}`;
|
|
131
|
+
const title = hasText(doc.title) ? doc.title : sourcePath;
|
|
132
|
+
const status = getDocStatus(doc);
|
|
133
|
+
const overrideSummary = getOverrideSummary(doc.overrides);
|
|
134
|
+
if (!hasText(doc.route)) {
|
|
135
|
+
warnings.push({
|
|
136
|
+
docId: id,
|
|
137
|
+
message: 'Generated doc is missing a route.',
|
|
138
|
+
sourcePath
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
if (!hasText(doc.sourcePath)) {
|
|
142
|
+
warnings.push({
|
|
143
|
+
docId: id,
|
|
144
|
+
message: 'Generated doc is missing a source path.'
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (!hasText(doc.title)) {
|
|
148
|
+
warnings.push({
|
|
149
|
+
docId: id,
|
|
150
|
+
message: 'Generated doc is missing a title.',
|
|
151
|
+
sourcePath
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
id,
|
|
156
|
+
...adminRoute ? {
|
|
157
|
+
adminURL: getGeneratedDocAdminURL({
|
|
158
|
+
id,
|
|
159
|
+
adminRoute,
|
|
160
|
+
docsCollectionSlug
|
|
161
|
+
})
|
|
162
|
+
} : {},
|
|
163
|
+
archived: status === 'archived',
|
|
164
|
+
draft: status === 'draft',
|
|
165
|
+
hiddenFromNav: doc.overrides?.hideFromNav === true,
|
|
166
|
+
kind: 'doc',
|
|
167
|
+
order: typeof doc.order === 'number' ? doc.order : 0,
|
|
168
|
+
overrideSummary,
|
|
169
|
+
published: status === 'published',
|
|
170
|
+
route,
|
|
171
|
+
sourcePath,
|
|
172
|
+
status,
|
|
173
|
+
title
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
export const buildDocsSetManagerData = ({ adminRoute, docs, docsCollectionSlug = DEFAULT_DOCS_COLLECTION_SLUG, docsSet })=>{
|
|
177
|
+
const warnings = [];
|
|
178
|
+
const docsSetId = getRecordId(docsSet) ?? 'unknown';
|
|
179
|
+
const sortedDocs = docs.map((doc, index)=>toDocItem({
|
|
180
|
+
adminRoute,
|
|
181
|
+
doc,
|
|
182
|
+
docsCollectionSlug,
|
|
183
|
+
index,
|
|
184
|
+
warnings
|
|
185
|
+
})).sort(compareDocItems);
|
|
186
|
+
const tree = [];
|
|
187
|
+
for (const item of sortedDocs){
|
|
188
|
+
insertIntoTree({
|
|
189
|
+
item,
|
|
190
|
+
tree
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
sortTree(tree);
|
|
194
|
+
return {
|
|
195
|
+
docs: sortedDocs,
|
|
196
|
+
docsSet: {
|
|
197
|
+
id: docsSetId,
|
|
198
|
+
routeBase: docsSet.routeBase ?? '',
|
|
199
|
+
sourceId: docsSet.sourceId ?? '',
|
|
200
|
+
title: docsSet.title ?? docsSetId
|
|
201
|
+
},
|
|
202
|
+
summary: {
|
|
203
|
+
archived: sortedDocs.filter((doc)=>doc.archived).length,
|
|
204
|
+
drafts: sortedDocs.filter((doc)=>doc.draft).length,
|
|
205
|
+
hiddenFromNav: sortedDocs.filter((doc)=>doc.hiddenFromNav).length,
|
|
206
|
+
published: sortedDocs.filter((doc)=>doc.published).length,
|
|
207
|
+
total: sortedDocs.length,
|
|
208
|
+
withOverrides: sortedDocs.filter((doc)=>doc.overrideSummary.length > 0).length
|
|
209
|
+
},
|
|
210
|
+
sync: docsSet.sync ? {
|
|
211
|
+
docsCount: typeof docsSet.sync.docsCount === 'number' ? docsSet.sync.docsCount : undefined,
|
|
212
|
+
lastStatus: docsSet.sync.lastStatus ?? undefined,
|
|
213
|
+
lastSyncedAt: docsSet.sync.lastSyncedAt ?? undefined
|
|
214
|
+
} : undefined,
|
|
215
|
+
tree,
|
|
216
|
+
warnings
|
|
217
|
+
};
|
|
218
|
+
};
|
|
219
|
+
export const isDocsRecordForDocsSet = ({ doc, docsSetId, sourceId })=>{
|
|
220
|
+
const docDocsSetId = getRelationshipId(doc.docsSet);
|
|
221
|
+
if (docDocsSetId) {
|
|
222
|
+
return docDocsSetId === docsSetId;
|
|
223
|
+
}
|
|
224
|
+
return doc.sync?.sourceId === sourceId;
|
|
225
|
+
};
|
|
226
|
+
export const getDocsSetManagerData = async ({ adminRoute, docsCollectionSlug = DEFAULT_DOCS_COLLECTION_SLUG, docsSetId, docsSetsCollectionSlug = DEFAULT_DOCS_SETS_COLLECTION_SLUG, overrideAccess = true, payload })=>{
|
|
227
|
+
const docsSet = await payload.findByID({
|
|
228
|
+
id: docsSetId,
|
|
229
|
+
collection: docsSetsCollectionSlug,
|
|
230
|
+
depth: 0,
|
|
231
|
+
overrideAccess
|
|
232
|
+
});
|
|
233
|
+
const docsResult = await payload.find({
|
|
234
|
+
collection: docsCollectionSlug,
|
|
235
|
+
depth: 0,
|
|
236
|
+
limit: 1000,
|
|
237
|
+
overrideAccess,
|
|
238
|
+
where: {
|
|
239
|
+
or: [
|
|
240
|
+
{
|
|
241
|
+
docsSet: {
|
|
242
|
+
equals: docsSetId
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
'sync.sourceId': {
|
|
247
|
+
equals: docsSet.sourceId
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
const docs = docsResult.docs.filter(isRecord).map((doc)=>doc).filter((doc)=>isDocsRecordForDocsSet({
|
|
254
|
+
doc,
|
|
255
|
+
docsSetId,
|
|
256
|
+
sourceId: docsSet.sourceId ?? ''
|
|
257
|
+
}));
|
|
258
|
+
return buildDocsSetManagerData({
|
|
259
|
+
adminRoute,
|
|
260
|
+
docs,
|
|
261
|
+
docsCollectionSlug,
|
|
262
|
+
docsSet
|
|
263
|
+
});
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
//# sourceMappingURL=docsSetManagerData.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/admin/docsSetManagerData.ts"],"sourcesContent":["import type {\n DocsSetManagerData,\n DocsSetManagerDocItem,\n DocsSetManagerPayloadOperations,\n DocsSetManagerWarning,\n RawDocsRecord,\n RawDocsSetRecord,\n} from './docsSetManagerTypes.js'\n\nimport {\n DEFAULT_DOCS_COLLECTION_SLUG,\n DEFAULT_DOCS_SETS_COLLECTION_SLUG,\n} from '../constants.js'\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst getRecordId = (doc: unknown): string | undefined => {\n if (!isRecord(doc)) {\n return undefined\n }\n\n if (typeof doc.id === 'string' || typeof doc.id === 'number') {\n return String(doc.id)\n }\n\n return undefined\n}\n\nconst getRelationshipId = (value: unknown): string | undefined => {\n if (typeof value === 'string' || typeof value === 'number') {\n return String(value)\n }\n\n return getRecordId(value)\n}\n\nconst normalizeAdminRoute = (adminRoute = '/admin'): string => {\n const trimmed = adminRoute.trim()\n\n if (!trimmed || trimmed === '/') {\n return '/admin'\n }\n\n return `/${trimmed}`.replace(/\\/+/g, '/').replace(/\\/+$/g, '')\n}\n\nexport const getGeneratedDocAdminURL = ({\n id,\n adminRoute,\n docsCollectionSlug,\n}: {\n adminRoute?: string\n docsCollectionSlug: string\n id: string\n}): string =>\n `${normalizeAdminRoute(adminRoute)}/collections/${docsCollectionSlug}/${encodeURIComponent(id)}`\n\nconst hasText = (value: null | string | undefined): value is string =>\n typeof value === 'string' && value.trim().length > 0\n\nconst getOverrideSummary = (overrides: RawDocsRecord['overrides']): string[] => {\n if (!overrides || !isRecord(overrides)) {\n return []\n }\n\n const summary: string[] = []\n\n if (hasText(overrides.navTitle)) {\n summary.push('Nav title override')\n }\n\n if (overrides.hideFromNav === true) {\n summary.push('Hidden from nav')\n }\n\n if (hasText(overrides.theme)) {\n summary.push('Theme override')\n }\n\n if (\n hasText(overrides.heroEyebrow) ||\n hasText(overrides.heroTitle) ||\n hasText(overrides.heroDescription)\n ) {\n summary.push('Hero override')\n }\n\n if (hasText(overrides.seoTitle) || hasText(overrides.seoDescription)) {\n summary.push('SEO override')\n }\n\n return summary\n}\n\nconst getDocStatus = (\n doc: RawDocsRecord,\n): DocsSetManagerDocItem['status'] => {\n if (doc.sync?.archived === true) {\n return 'archived'\n }\n\n if (doc._status === 'draft') {\n return 'draft'\n }\n\n if (doc._status === 'published') {\n return 'published'\n }\n\n return 'synced'\n}\n\nconst getSourcePathSegments = (sourcePath: string): string[] => {\n const withoutExtension = sourcePath.replace(/\\.md$/i, '')\n const segments = withoutExtension.split('/').filter(Boolean)\n\n if (segments.at(-1) === 'index') {\n return segments.slice(0, -1)\n }\n\n return segments\n}\n\nconst titleCaseSegment = (segment: string): string =>\n segment\n .split(/[-_]+/)\n .filter(Boolean)\n .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)\n .join(' ')\n\nconst compareDocItems = (\n first: DocsSetManagerDocItem,\n second: DocsSetManagerDocItem,\n): number => {\n if (first.order !== second.order) {\n return first.order - second.order\n }\n\n if (first.sourcePath !== second.sourcePath) {\n return first.sourcePath.localeCompare(second.sourcePath)\n }\n\n return first.route.localeCompare(second.route)\n}\n\nconst getOrCreateFolder = ({\n items,\n order,\n segment,\n sourcePath,\n}: {\n items: DocsSetManagerDocItem[]\n order: number\n segment: string\n sourcePath: string\n}): DocsSetManagerDocItem => {\n const existing = items.find(\n (item) => item.kind === 'folder' && item.sourcePath === sourcePath,\n )\n\n if (existing) {\n existing.order = Math.min(existing.order, order)\n return existing\n }\n\n const folder: DocsSetManagerDocItem = {\n id: `folder:${sourcePath}`,\n children: [],\n kind: 'folder',\n order,\n overrideSummary: [],\n route: '',\n sourcePath,\n status: 'synced',\n title: titleCaseSegment(segment),\n }\n\n items.push(folder)\n\n return folder\n}\n\nconst insertIntoTree = ({\n item,\n tree,\n}: {\n item: DocsSetManagerDocItem\n tree: DocsSetManagerDocItem[]\n}) => {\n const segments = getSourcePathSegments(item.sourcePath)\n\n if (segments.length <= 1) {\n tree.push(item)\n return\n }\n\n let currentItems = tree\n\n for (const [index, segment] of segments.slice(0, -1).entries()) {\n const sourcePath = segments.slice(0, index + 1).join('/')\n const folder = getOrCreateFolder({\n items: currentItems,\n order: item.order,\n segment,\n sourcePath,\n })\n\n folder.children ??= []\n currentItems = folder.children\n }\n\n currentItems.push(item)\n}\n\nconst sortTree = (items: DocsSetManagerDocItem[]) => {\n items.sort(compareDocItems)\n\n for (const item of items) {\n if (item.children) {\n sortTree(item.children)\n }\n }\n}\n\nconst toDocItem = ({\n adminRoute,\n doc,\n docsCollectionSlug,\n index,\n warnings,\n}: {\n adminRoute?: string\n doc: RawDocsRecord\n docsCollectionSlug: string\n index: number\n warnings: DocsSetManagerWarning[]\n}): DocsSetManagerDocItem => {\n const id = getRecordId(doc) ?? `unknown-${index}`\n const route = hasText(doc.route) ? doc.route : ''\n const sourcePath = hasText(doc.sourcePath)\n ? doc.sourcePath\n : `missing-source-path-${id}`\n const title = hasText(doc.title) ? doc.title : sourcePath\n const status = getDocStatus(doc)\n const overrideSummary = getOverrideSummary(doc.overrides)\n\n if (!hasText(doc.route)) {\n warnings.push({\n docId: id,\n message: 'Generated doc is missing a route.',\n sourcePath,\n })\n }\n\n if (!hasText(doc.sourcePath)) {\n warnings.push({\n docId: id,\n message: 'Generated doc is missing a source path.',\n })\n }\n\n if (!hasText(doc.title)) {\n warnings.push({\n docId: id,\n message: 'Generated doc is missing a title.',\n sourcePath,\n })\n }\n\n return {\n id,\n ...(adminRoute\n ? {\n adminURL: getGeneratedDocAdminURL({\n id,\n adminRoute,\n docsCollectionSlug,\n }),\n }\n : {}),\n archived: status === 'archived',\n draft: status === 'draft',\n hiddenFromNav: doc.overrides?.hideFromNav === true,\n kind: 'doc',\n order: typeof doc.order === 'number' ? doc.order : 0,\n overrideSummary,\n published: status === 'published',\n route,\n sourcePath,\n status,\n title,\n }\n}\n\nexport const buildDocsSetManagerData = ({\n adminRoute,\n docs,\n docsCollectionSlug = DEFAULT_DOCS_COLLECTION_SLUG,\n docsSet,\n}: {\n adminRoute?: string\n docs: RawDocsRecord[]\n docsCollectionSlug?: string\n docsSet: RawDocsSetRecord\n}): DocsSetManagerData => {\n const warnings: DocsSetManagerWarning[] = []\n const docsSetId = getRecordId(docsSet) ?? 'unknown'\n const sortedDocs = docs\n .map((doc, index) =>\n toDocItem({\n adminRoute,\n doc,\n docsCollectionSlug,\n index,\n warnings,\n }),\n )\n .sort(compareDocItems)\n const tree: DocsSetManagerDocItem[] = []\n\n for (const item of sortedDocs) {\n insertIntoTree({\n item,\n tree,\n })\n }\n\n sortTree(tree)\n\n return {\n docs: sortedDocs,\n docsSet: {\n id: docsSetId,\n routeBase: docsSet.routeBase ?? '',\n sourceId: docsSet.sourceId ?? '',\n title: docsSet.title ?? docsSetId,\n },\n summary: {\n archived: sortedDocs.filter((doc) => doc.archived).length,\n drafts: sortedDocs.filter((doc) => doc.draft).length,\n hiddenFromNav: sortedDocs.filter((doc) => doc.hiddenFromNav).length,\n published: sortedDocs.filter((doc) => doc.published).length,\n total: sortedDocs.length,\n withOverrides: sortedDocs.filter((doc) => doc.overrideSummary.length > 0)\n .length,\n },\n sync: docsSet.sync\n ? {\n docsCount:\n typeof docsSet.sync.docsCount === 'number'\n ? docsSet.sync.docsCount\n : undefined,\n lastStatus: docsSet.sync.lastStatus ?? undefined,\n lastSyncedAt: docsSet.sync.lastSyncedAt ?? undefined,\n }\n : undefined,\n tree,\n warnings,\n }\n}\n\nexport const isDocsRecordForDocsSet = ({\n doc,\n docsSetId,\n sourceId,\n}: {\n doc: RawDocsRecord\n docsSetId: string\n sourceId: string\n}): boolean => {\n const docDocsSetId = getRelationshipId(doc.docsSet)\n\n if (docDocsSetId) {\n return docDocsSetId === docsSetId\n }\n\n return doc.sync?.sourceId === sourceId\n}\n\nexport const getDocsSetManagerData = async ({\n adminRoute,\n docsCollectionSlug = DEFAULT_DOCS_COLLECTION_SLUG,\n docsSetId,\n docsSetsCollectionSlug = DEFAULT_DOCS_SETS_COLLECTION_SLUG,\n overrideAccess = true,\n payload,\n}: {\n adminRoute?: string\n docsCollectionSlug?: string\n docsSetId: string\n docsSetsCollectionSlug?: string\n overrideAccess?: boolean\n payload: DocsSetManagerPayloadOperations\n}): Promise<DocsSetManagerData> => {\n const docsSet = (await payload.findByID({\n id: docsSetId,\n collection: docsSetsCollectionSlug,\n depth: 0,\n overrideAccess,\n })) as RawDocsSetRecord\n\n const docsResult = await payload.find({\n collection: docsCollectionSlug,\n depth: 0,\n limit: 1000,\n overrideAccess,\n where: {\n or: [\n {\n docsSet: {\n equals: docsSetId,\n },\n },\n {\n 'sync.sourceId': {\n equals: docsSet.sourceId,\n },\n },\n ],\n },\n })\n const docs = docsResult.docs\n .filter(isRecord)\n .map((doc) => doc as RawDocsRecord)\n .filter((doc) =>\n isDocsRecordForDocsSet({\n doc,\n docsSetId,\n sourceId: docsSet.sourceId ?? '',\n }),\n )\n\n return buildDocsSetManagerData({\n adminRoute,\n docs,\n docsCollectionSlug,\n docsSet,\n })\n}\n"],"names":["DEFAULT_DOCS_COLLECTION_SLUG","DEFAULT_DOCS_SETS_COLLECTION_SLUG","isRecord","value","Array","isArray","getRecordId","doc","undefined","id","String","getRelationshipId","normalizeAdminRoute","adminRoute","trimmed","trim","replace","getGeneratedDocAdminURL","docsCollectionSlug","encodeURIComponent","hasText","length","getOverrideSummary","overrides","summary","navTitle","push","hideFromNav","theme","heroEyebrow","heroTitle","heroDescription","seoTitle","seoDescription","getDocStatus","sync","archived","_status","getSourcePathSegments","sourcePath","withoutExtension","segments","split","filter","Boolean","at","slice","titleCaseSegment","segment","map","part","charAt","toUpperCase","join","compareDocItems","first","second","order","localeCompare","route","getOrCreateFolder","items","existing","find","item","kind","Math","min","folder","children","overrideSummary","status","title","insertIntoTree","tree","currentItems","index","entries","sortTree","sort","toDocItem","warnings","docId","message","adminURL","draft","hiddenFromNav","published","buildDocsSetManagerData","docs","docsSet","docsSetId","sortedDocs","routeBase","sourceId","drafts","total","withOverrides","docsCount","lastStatus","lastSyncedAt","isDocsRecordForDocsSet","docDocsSetId","getDocsSetManagerData","docsSetsCollectionSlug","overrideAccess","payload","findByID","collection","depth","docsResult","limit","where","or","equals"],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
export type RawDocsSetRecord = {
|
|
2
|
+
id?: number | string;
|
|
3
|
+
routeBase?: string;
|
|
4
|
+
sourceId?: string;
|
|
5
|
+
sync?: {
|
|
6
|
+
docsCount?: null | number;
|
|
7
|
+
lastStatus?: 'failed' | 'pending' | 'success' | null;
|
|
8
|
+
lastSyncedAt?: null | string;
|
|
9
|
+
};
|
|
10
|
+
title?: string;
|
|
11
|
+
};
|
|
12
|
+
export type RawDocsRecord = {
|
|
13
|
+
_status?: 'draft' | 'published';
|
|
14
|
+
description?: null | string;
|
|
15
|
+
docsSet?: {
|
|
16
|
+
id?: number | string;
|
|
17
|
+
} | null | number | string;
|
|
18
|
+
id?: number | string;
|
|
19
|
+
navTitle?: null | string;
|
|
20
|
+
order?: null | number;
|
|
21
|
+
overrides?: {
|
|
22
|
+
heroDescription?: null | string;
|
|
23
|
+
heroEyebrow?: null | string;
|
|
24
|
+
heroTitle?: null | string;
|
|
25
|
+
hideFromNav?: boolean | null;
|
|
26
|
+
navTitle?: null | string;
|
|
27
|
+
seoDescription?: null | string;
|
|
28
|
+
seoTitle?: null | string;
|
|
29
|
+
theme?: null | string;
|
|
30
|
+
};
|
|
31
|
+
route?: null | string;
|
|
32
|
+
sourcePath?: null | string;
|
|
33
|
+
sync?: {
|
|
34
|
+
archived?: boolean | null;
|
|
35
|
+
archivedAt?: null | string;
|
|
36
|
+
lastSyncedAt?: null | string;
|
|
37
|
+
sourceId?: null | string;
|
|
38
|
+
};
|
|
39
|
+
title?: null | string;
|
|
40
|
+
};
|
|
41
|
+
export type DocsSetManagerWarning = {
|
|
42
|
+
docId?: string;
|
|
43
|
+
message: string;
|
|
44
|
+
sourcePath?: string;
|
|
45
|
+
};
|
|
46
|
+
export type DocsSetManagerDocStatus = 'archived' | 'draft' | 'published' | 'synced';
|
|
47
|
+
export type DocsSetManagerDocItem = {
|
|
48
|
+
adminURL?: string;
|
|
49
|
+
archived?: boolean;
|
|
50
|
+
children?: DocsSetManagerDocItem[];
|
|
51
|
+
draft?: boolean;
|
|
52
|
+
hiddenFromNav?: boolean;
|
|
53
|
+
id: string;
|
|
54
|
+
kind: 'doc' | 'folder';
|
|
55
|
+
order: number;
|
|
56
|
+
overrideSummary: string[];
|
|
57
|
+
published?: boolean;
|
|
58
|
+
route: string;
|
|
59
|
+
sourcePath: string;
|
|
60
|
+
status: DocsSetManagerDocStatus;
|
|
61
|
+
title: string;
|
|
62
|
+
};
|
|
63
|
+
export type DocsSetManagerData = {
|
|
64
|
+
docs: DocsSetManagerDocItem[];
|
|
65
|
+
docsSet: {
|
|
66
|
+
id: string;
|
|
67
|
+
routeBase: string;
|
|
68
|
+
sourceId: string;
|
|
69
|
+
title: string;
|
|
70
|
+
};
|
|
71
|
+
summary: {
|
|
72
|
+
archived: number;
|
|
73
|
+
drafts: number;
|
|
74
|
+
hiddenFromNav: number;
|
|
75
|
+
published: number;
|
|
76
|
+
total: number;
|
|
77
|
+
withOverrides: number;
|
|
78
|
+
};
|
|
79
|
+
sync?: {
|
|
80
|
+
docsCount?: number;
|
|
81
|
+
lastStatus?: 'failed' | 'pending' | 'success';
|
|
82
|
+
lastSyncedAt?: string;
|
|
83
|
+
};
|
|
84
|
+
tree: DocsSetManagerDocItem[];
|
|
85
|
+
warnings: DocsSetManagerWarning[];
|
|
86
|
+
};
|
|
87
|
+
export type DocsSetManagerPayloadOperations = {
|
|
88
|
+
find: (args: {
|
|
89
|
+
collection: string;
|
|
90
|
+
depth?: number;
|
|
91
|
+
limit?: number;
|
|
92
|
+
overrideAccess?: boolean;
|
|
93
|
+
where?: unknown;
|
|
94
|
+
}) => Promise<{
|
|
95
|
+
docs: unknown[];
|
|
96
|
+
}>;
|
|
97
|
+
findByID: (args: {
|
|
98
|
+
collection: string;
|
|
99
|
+
depth?: number;
|
|
100
|
+
id: number | string;
|
|
101
|
+
overrideAccess?: boolean;
|
|
102
|
+
}) => Promise<unknown>;
|
|
103
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/admin/docsSetManagerTypes.ts"],"sourcesContent":["export type RawDocsSetRecord = {\n id?: number | string\n routeBase?: string\n sourceId?: string\n sync?: {\n docsCount?: null | number\n lastStatus?: 'failed' | 'pending' | 'success' | null\n lastSyncedAt?: null | string\n }\n title?: string\n}\n\nexport type RawDocsRecord = {\n _status?: 'draft' | 'published'\n description?: null | string\n docsSet?: { id?: number | string } | null | number | string\n id?: number | string\n navTitle?: null | string\n order?: null | number\n overrides?: {\n heroDescription?: null | string\n heroEyebrow?: null | string\n heroTitle?: null | string\n hideFromNav?: boolean | null\n navTitle?: null | string\n seoDescription?: null | string\n seoTitle?: null | string\n theme?: null | string\n }\n route?: null | string\n sourcePath?: null | string\n sync?: {\n archived?: boolean | null\n archivedAt?: null | string\n lastSyncedAt?: null | string\n sourceId?: null | string\n }\n title?: null | string\n}\n\nexport type DocsSetManagerWarning = {\n docId?: string\n message: string\n sourcePath?: string\n}\n\nexport type DocsSetManagerDocStatus =\n | 'archived'\n | 'draft'\n | 'published'\n | 'synced'\n\nexport type DocsSetManagerDocItem = {\n adminURL?: string\n archived?: boolean\n children?: DocsSetManagerDocItem[]\n draft?: boolean\n hiddenFromNav?: boolean\n id: string\n kind: 'doc' | 'folder'\n order: number\n overrideSummary: string[]\n published?: boolean\n route: string\n sourcePath: string\n status: DocsSetManagerDocStatus\n title: string\n}\n\nexport type DocsSetManagerData = {\n docs: DocsSetManagerDocItem[]\n docsSet: {\n id: string\n routeBase: string\n sourceId: string\n title: string\n }\n summary: {\n archived: number\n drafts: number\n hiddenFromNav: number\n published: number\n total: number\n withOverrides: number\n }\n sync?: {\n docsCount?: number\n lastStatus?: 'failed' | 'pending' | 'success'\n lastSyncedAt?: string\n }\n tree: DocsSetManagerDocItem[]\n warnings: DocsSetManagerWarning[]\n}\n\nexport type DocsSetManagerPayloadOperations = {\n find: (args: {\n collection: string\n depth?: number\n limit?: number\n overrideAccess?: boolean\n where?: unknown\n }) => Promise<{\n docs: unknown[]\n }>\n findByID: (args: {\n collection: string\n depth?: number\n id: number | string\n overrideAccess?: boolean\n }) => Promise<unknown>\n}\n"],"names":[],"mappings":"AA8FA,WAgBC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { DocsSetManager } from './DocsSetManager.js';
|
|
2
|
+
export { buildDocsSetManagerData, getDocsSetManagerData, getGeneratedDocAdminURL, isDocsRecordForDocsSet, } from './docsSetManagerData.js';
|
|
3
|
+
export type { DocsSetManagerData, DocsSetManagerDocItem, DocsSetManagerDocStatus, DocsSetManagerPayloadOperations, DocsSetManagerWarning, RawDocsRecord, RawDocsSetRecord, } from './docsSetManagerTypes.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/admin/index.ts"],"sourcesContent":["export { DocsSetManager } from './DocsSetManager.js'\nexport {\n buildDocsSetManagerData,\n getDocsSetManagerData,\n getGeneratedDocAdminURL,\n isDocsRecordForDocsSet,\n} from './docsSetManagerData.js'\nexport type {\n DocsSetManagerData,\n DocsSetManagerDocItem,\n DocsSetManagerDocStatus,\n DocsSetManagerPayloadOperations,\n DocsSetManagerWarning,\n RawDocsRecord,\n RawDocsSetRecord,\n} from './docsSetManagerTypes.js'\n"],"names":["DocsSetManager","buildDocsSetManagerData","getDocsSetManagerData","getGeneratedDocAdminURL","isDocsRecordForDocsSet"],"mappings":"AAAA,SAASA,cAAc,QAAQ,sBAAqB;AACpD,SACEC,uBAAuB,EACvBC,qBAAqB,EACrBC,uBAAuB,EACvBC,sBAAsB,QACjB,0BAAyB"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { access, mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { getFlagBoolean, getFlagString } from '../parseArgs.js';
|
|
4
|
+
const packageManagers = new Set([
|
|
5
|
+
'bun',
|
|
6
|
+
'npm',
|
|
7
|
+
'pnpm',
|
|
8
|
+
'yarn'
|
|
9
|
+
]);
|
|
10
|
+
const supportedInstallTargets = new Set([
|
|
11
|
+
'ai-skill',
|
|
12
|
+
'skill'
|
|
13
|
+
]);
|
|
14
|
+
const defaultSkillOutputPath = '.agents/skills/payload-markdown-docs';
|
|
15
|
+
const skillTemplateRoot = new URL('../../skills/codex/', import.meta.url);
|
|
16
|
+
const fileExists = async (filePath)=>{
|
|
17
|
+
try {
|
|
18
|
+
await access(filePath);
|
|
19
|
+
return true;
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const detectPackageManager = async (cwd = process.cwd())=>{
|
|
25
|
+
const lockfiles = [
|
|
26
|
+
[
|
|
27
|
+
'pnpm-lock.yaml',
|
|
28
|
+
'pnpm'
|
|
29
|
+
],
|
|
30
|
+
[
|
|
31
|
+
'package-lock.json',
|
|
32
|
+
'npm'
|
|
33
|
+
],
|
|
34
|
+
[
|
|
35
|
+
'yarn.lock',
|
|
36
|
+
'yarn'
|
|
37
|
+
],
|
|
38
|
+
[
|
|
39
|
+
'bun.lockb',
|
|
40
|
+
'bun'
|
|
41
|
+
]
|
|
42
|
+
];
|
|
43
|
+
for (const [file, packageManager] of lockfiles){
|
|
44
|
+
if (await fileExists(path.join(cwd, file))) {
|
|
45
|
+
return packageManager;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return 'pnpm';
|
|
49
|
+
};
|
|
50
|
+
const readTemplateFiles = async (directoryUrl = skillTemplateRoot, basePath = '')=>{
|
|
51
|
+
const entries = await readdir(directoryUrl, {
|
|
52
|
+
withFileTypes: true
|
|
53
|
+
});
|
|
54
|
+
const files = [];
|
|
55
|
+
for (const entry of entries){
|
|
56
|
+
if (entry.isSymbolicLink()) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const relativePath = path.posix.join(basePath, entry.name);
|
|
60
|
+
const entryUrl = new URL(`${entry.name}${entry.isDirectory() ? '/' : ''}`, directoryUrl);
|
|
61
|
+
if (entry.isDirectory()) {
|
|
62
|
+
files.push(...await readTemplateFiles(entryUrl, relativePath));
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (!entry.isFile()) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
files.push({
|
|
69
|
+
content: await readFile(entryUrl, 'utf8'),
|
|
70
|
+
relativePath
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return files.sort((left, right)=>left.relativePath.localeCompare(right.relativePath));
|
|
74
|
+
};
|
|
75
|
+
const applyTemplateValues = ({ content, docsRoot, packageManager })=>content.replaceAll('{{docsRoot}}', docsRoot).replaceAll('{{packageManager}}', packageManager);
|
|
76
|
+
const assertSafeRelativePath = (relativePath)=>{
|
|
77
|
+
const normalized = path.posix.normalize(relativePath);
|
|
78
|
+
if (normalized.startsWith('../') || normalized === '..' || path.isAbsolute(relativePath) || relativePath.includes('\\')) {
|
|
79
|
+
return {
|
|
80
|
+
exitCode: 1,
|
|
81
|
+
stderr: `Unsafe bundled skill path "${relativePath}".\n`
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
};
|
|
86
|
+
const createPlannedFiles = async ({ docsRoot, outDir, packageManager })=>{
|
|
87
|
+
const absoluteOutDir = path.resolve(outDir);
|
|
88
|
+
const templates = await readTemplateFiles();
|
|
89
|
+
const plannedFiles = [];
|
|
90
|
+
for (const template of templates){
|
|
91
|
+
const unsafe = assertSafeRelativePath(template.relativePath);
|
|
92
|
+
if (unsafe) {
|
|
93
|
+
return unsafe;
|
|
94
|
+
}
|
|
95
|
+
const outputPath = path.resolve(absoluteOutDir, template.relativePath);
|
|
96
|
+
if (outputPath !== absoluteOutDir && !outputPath.startsWith(`${absoluteOutDir}${path.sep}`)) {
|
|
97
|
+
return {
|
|
98
|
+
exitCode: 1,
|
|
99
|
+
stderr: `Refusing to write outside target directory: ${template.relativePath}\n`
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
plannedFiles.push({
|
|
103
|
+
content: applyTemplateValues({
|
|
104
|
+
content: template.content,
|
|
105
|
+
docsRoot,
|
|
106
|
+
packageManager
|
|
107
|
+
}),
|
|
108
|
+
path: outputPath,
|
|
109
|
+
relativePath: template.relativePath
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return plannedFiles;
|
|
113
|
+
};
|
|
114
|
+
const getInstallSkillOptions = async (args)=>{
|
|
115
|
+
const [target] = args.positionals;
|
|
116
|
+
if (!target || !supportedInstallTargets.has(target)) {
|
|
117
|
+
return {
|
|
118
|
+
exitCode: 1,
|
|
119
|
+
stderr: 'Install requires target "skill" or "ai-skill".\n'
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const agentFlag = getFlagString(args, 'agent');
|
|
123
|
+
const codex = getFlagBoolean(args, 'codex');
|
|
124
|
+
if (agentFlag && agentFlag !== 'codex') {
|
|
125
|
+
return {
|
|
126
|
+
exitCode: 1,
|
|
127
|
+
stderr: '--agent currently supports only "codex".\n'
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (!codex && agentFlag !== 'codex') {
|
|
131
|
+
return {
|
|
132
|
+
exitCode: 1,
|
|
133
|
+
stderr: 'Install skill requires --codex or --agent codex.\n'
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
const packageManagerFlag = getFlagString(args, 'package-manager');
|
|
137
|
+
if (packageManagerFlag !== undefined && !packageManagers.has(packageManagerFlag)) {
|
|
138
|
+
return {
|
|
139
|
+
exitCode: 1,
|
|
140
|
+
stderr: '--package-manager must be pnpm, npm, yarn, or bun.\n'
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
agent: 'codex',
|
|
145
|
+
docsRoot: getFlagString(args, 'docs-root') ?? './docs',
|
|
146
|
+
dryRun: getFlagBoolean(args, 'dry-run'),
|
|
147
|
+
force: getFlagBoolean(args, 'force'),
|
|
148
|
+
outDir: getFlagString(args, 'out') ?? defaultSkillOutputPath,
|
|
149
|
+
packageManager: packageManagerFlag ?? await detectPackageManager()
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
const formatPlannedFiles = ({ dryRun, files, outDir })=>{
|
|
153
|
+
const lines = [
|
|
154
|
+
dryRun ? 'payload-markdown-docs install skill dry-run' : 'payload-markdown-docs install skill',
|
|
155
|
+
'',
|
|
156
|
+
`Target: ${path.resolve(outDir)}`,
|
|
157
|
+
'Files:',
|
|
158
|
+
...files.map((file)=>`- ${file.relativePath}`)
|
|
159
|
+
];
|
|
160
|
+
return `${lines.join('\n')}\n`;
|
|
161
|
+
};
|
|
162
|
+
export const runInstallCommand = async (args)=>{
|
|
163
|
+
const options = await getInstallSkillOptions(args);
|
|
164
|
+
if ('exitCode' in options) {
|
|
165
|
+
return options;
|
|
166
|
+
}
|
|
167
|
+
const plannedFiles = await createPlannedFiles(options);
|
|
168
|
+
if ('exitCode' in plannedFiles) {
|
|
169
|
+
return plannedFiles;
|
|
170
|
+
}
|
|
171
|
+
if (!options.force) {
|
|
172
|
+
const existingFiles = [];
|
|
173
|
+
for (const file of plannedFiles){
|
|
174
|
+
if (await fileExists(file.path)) {
|
|
175
|
+
existingFiles.push(file.relativePath);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (existingFiles.length > 0) {
|
|
179
|
+
return {
|
|
180
|
+
exitCode: 1,
|
|
181
|
+
stderr: `Skill files already exist. Use --force to overwrite:\n${existingFiles.map((file)=>`- ${file}`).join('\n')}\n`
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (options.dryRun) {
|
|
186
|
+
return {
|
|
187
|
+
exitCode: 0,
|
|
188
|
+
stdout: formatPlannedFiles({
|
|
189
|
+
dryRun: true,
|
|
190
|
+
files: plannedFiles,
|
|
191
|
+
outDir: options.outDir
|
|
192
|
+
})
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
for (const file of plannedFiles){
|
|
196
|
+
await mkdir(path.dirname(file.path), {
|
|
197
|
+
recursive: true
|
|
198
|
+
});
|
|
199
|
+
await writeFile(file.path, file.content, 'utf8');
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
exitCode: 0,
|
|
203
|
+
stdout: formatPlannedFiles({
|
|
204
|
+
dryRun: false,
|
|
205
|
+
files: plannedFiles,
|
|
206
|
+
outDir: options.outDir
|
|
207
|
+
})
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
//# sourceMappingURL=install.js.map
|