create-thally-docs 0.8.0 → 0.9.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 +11 -4
- package/dist/{chunk-5GIGIHI5.js → chunk-BW7J7DJV.js} +259 -334
- package/dist/chunk-JNDRCCJV.js +232 -0
- package/dist/chunk-PJW4JJIT.js +31 -0
- package/dist/{chunk-PZBQS5ZR.js → chunk-YWNWLSZ2.js} +1 -1
- package/dist/customize.d.ts +93 -0
- package/dist/customize.js +37 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +90 -19
- package/dist/migrate/index.d.ts +35 -0
- package/dist/migrate/index.js +4 -2
- package/dist/release.d.ts +58 -0
- package/dist/release.js +9 -0
- package/dist/scaffold.d.ts +38 -0
- package/dist/scaffold.js +16 -3
- package/package.json +11 -4
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
patchApiReferenceGuard,
|
|
4
|
+
patchGitignore,
|
|
5
|
+
patchOpenApiFetch,
|
|
6
|
+
patchPackageJson,
|
|
7
|
+
patchTopBarNavigation,
|
|
8
|
+
updateEnvExample,
|
|
9
|
+
updateSiteConfig,
|
|
10
|
+
writeCloudflareRuntimeConfig,
|
|
11
|
+
writeStarterAgentGuide,
|
|
12
|
+
writeStarterContent,
|
|
13
|
+
writeStarterReadme
|
|
14
|
+
} from "./chunk-BW7J7DJV.js";
|
|
15
|
+
import {
|
|
16
|
+
STABLE_SCAFFOLD_RELEASE
|
|
17
|
+
} from "./chunk-PJW4JJIT.js";
|
|
18
|
+
|
|
19
|
+
// src/scaffold.ts
|
|
20
|
+
import { existsSync, mkdirSync, readdirSync } from "fs";
|
|
21
|
+
import { resolve } from "path";
|
|
22
|
+
|
|
23
|
+
// src/download.ts
|
|
24
|
+
import { Readable, pipeline } from "stream";
|
|
25
|
+
import { promisify } from "util";
|
|
26
|
+
import { extract } from "tar";
|
|
27
|
+
var pipelineAsync = promisify(pipeline);
|
|
28
|
+
var TEMPLATE_REPOSITORY = STABLE_SCAFFOLD_RELEASE.source.repository;
|
|
29
|
+
var TEMPLATE_COMMIT_SHA = STABLE_SCAFFOLD_RELEASE.source.commitSha;
|
|
30
|
+
var TARBALL_URL = STABLE_SCAFFOLD_RELEASE.source.archiveUrl;
|
|
31
|
+
var EXCLUDE_PATHS = [
|
|
32
|
+
// Match both the directory entry itself and every nested file. Tar invokes
|
|
33
|
+
// the filter for `.../node_modules` before descendants, without a trailing `/`.
|
|
34
|
+
"/node_modules",
|
|
35
|
+
// The canonical docs repository may temporarily retain package sources while
|
|
36
|
+
// runtime work is being upstreamed. A scaffold consumes the published
|
|
37
|
+
// packages declared in package.json; it must never inherit those sources.
|
|
38
|
+
"/packages",
|
|
39
|
+
"/.git/",
|
|
40
|
+
"/.next/",
|
|
41
|
+
"/.data/",
|
|
42
|
+
"/.thally/",
|
|
43
|
+
// The first-party docs deployment pins its own canonical origin.
|
|
44
|
+
"/.env.production",
|
|
45
|
+
"/thally-track.yml",
|
|
46
|
+
"/CODEOWNERS",
|
|
47
|
+
"/CLAUDE.md",
|
|
48
|
+
"/notes/",
|
|
49
|
+
"/public/images/",
|
|
50
|
+
"/src/public/",
|
|
51
|
+
"/snippets/",
|
|
52
|
+
"/.github/ISSUE_TEMPLATE/",
|
|
53
|
+
"/.github/PULL_REQUEST_TEMPLATE.md",
|
|
54
|
+
"/README.md"
|
|
55
|
+
];
|
|
56
|
+
function shouldInclude(path) {
|
|
57
|
+
for (const excluded of EXCLUDE_PATHS) {
|
|
58
|
+
if (path.includes(excluded)) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
async function downloadTemplate(targetDir, siteName) {
|
|
65
|
+
console.log("");
|
|
66
|
+
console.log(` \u23F3 Creating ${siteName?.trim() || "your docs site"}...`);
|
|
67
|
+
const response = await fetch(TARBALL_URL);
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
throw new Error(`Failed to download template: ${response.status} ${response.statusText}`);
|
|
70
|
+
}
|
|
71
|
+
if (!response.body) {
|
|
72
|
+
throw new Error("Response body is empty");
|
|
73
|
+
}
|
|
74
|
+
const nodeStream = Readable.fromWeb(response.body);
|
|
75
|
+
await pipelineAsync(
|
|
76
|
+
nodeStream,
|
|
77
|
+
extract({ cwd: targetDir, strip: 1, filter: shouldInclude })
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/docs-json.ts
|
|
82
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
83
|
+
import { join } from "path";
|
|
84
|
+
function readDocsJson(projectDir) {
|
|
85
|
+
const docsPath = join(projectDir, "docs.json");
|
|
86
|
+
const raw = readFileSync(docsPath, "utf8");
|
|
87
|
+
return JSON.parse(raw);
|
|
88
|
+
}
|
|
89
|
+
function writeDocsJson(projectDir, config) {
|
|
90
|
+
const docsPath = join(projectDir, "docs.json");
|
|
91
|
+
writeFileSync(docsPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
92
|
+
}
|
|
93
|
+
function resetTrackingConfig(projectDir) {
|
|
94
|
+
const config = readDocsJson(projectDir);
|
|
95
|
+
if (config.tracking) {
|
|
96
|
+
delete config.tracking;
|
|
97
|
+
writeDocsJson(projectDir, config);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function writeTrackingConfig(projectDir, repos) {
|
|
101
|
+
if (repos.length === 0) return;
|
|
102
|
+
const config = readDocsJson(projectDir);
|
|
103
|
+
config.tracking = { repos: repos.map((r) => ({ owner: r.owner, repo: r.repo, branch: "main" })) };
|
|
104
|
+
writeDocsJson(projectDir, config);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/utils.ts
|
|
108
|
+
import { execSync } from "child_process";
|
|
109
|
+
import { basename } from "path";
|
|
110
|
+
function slugify(name) {
|
|
111
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
112
|
+
}
|
|
113
|
+
function run(cmd, cwd) {
|
|
114
|
+
execSync(cmd, { cwd, stdio: "inherit" });
|
|
115
|
+
}
|
|
116
|
+
function initGit(targetDir) {
|
|
117
|
+
try {
|
|
118
|
+
run("git init", targetDir);
|
|
119
|
+
run("git add -A", targetDir);
|
|
120
|
+
run('git commit -m "Initial commit from create-thally-docs"', targetDir);
|
|
121
|
+
} catch {
|
|
122
|
+
console.log(" \u26A0\uFE0F Could not initialize git (you can do this manually).");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function installDeps(targetDir) {
|
|
126
|
+
console.log("");
|
|
127
|
+
console.log(" \u{1F4E6} Installing dependencies...");
|
|
128
|
+
console.log("");
|
|
129
|
+
run("npm install --prefer-offline --no-audit --no-fund --progress=false", targetDir);
|
|
130
|
+
}
|
|
131
|
+
function logo() {
|
|
132
|
+
console.log("");
|
|
133
|
+
console.log(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
|
|
134
|
+
console.log(" \u2551 \u2551");
|
|
135
|
+
console.log(" \u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2551");
|
|
136
|
+
console.log(" \u2551 \u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D \u2551");
|
|
137
|
+
console.log(" \u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2554\u255D \u2551");
|
|
138
|
+
console.log(" \u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2554\u255D \u2551");
|
|
139
|
+
console.log(" \u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2551");
|
|
140
|
+
console.log(" \u2551 \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u2551");
|
|
141
|
+
console.log(" \u2551 \u2551");
|
|
142
|
+
console.log(" \u2551Give your product and docs first-class agent visibility.\u2551");
|
|
143
|
+
console.log(" \u2551 \u2551");
|
|
144
|
+
console.log(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
|
|
145
|
+
console.log("");
|
|
146
|
+
}
|
|
147
|
+
function success(projectDir, projectName, dependenciesInstalled) {
|
|
148
|
+
console.log("");
|
|
149
|
+
console.log(" \u2705 Your Thally project is ready!");
|
|
150
|
+
console.log("");
|
|
151
|
+
console.log(` \u{1F4C2} ${projectDir}`);
|
|
152
|
+
console.log("");
|
|
153
|
+
console.log(" Next steps:");
|
|
154
|
+
console.log("");
|
|
155
|
+
console.log(` cd ${basename(projectDir)}`);
|
|
156
|
+
if (!dependenciesInstalled) {
|
|
157
|
+
console.log(" npm install");
|
|
158
|
+
}
|
|
159
|
+
console.log(" npm run dev");
|
|
160
|
+
console.log("");
|
|
161
|
+
console.log(` Your terminal will print the local URL for your ${projectName} docs.`);
|
|
162
|
+
console.log("");
|
|
163
|
+
console.log(" \u{1F4DD} Key files to edit:");
|
|
164
|
+
console.log(" \u2022 src/data/site.ts \u2014 name, links, branding");
|
|
165
|
+
console.log(" \u2022 docs.json \u2014 navigation structure");
|
|
166
|
+
console.log(" \u2022 src/content/*.mdx \u2014 your documentation");
|
|
167
|
+
console.log(" \u2022 openapi.yaml \u2014 API spec (optional)");
|
|
168
|
+
console.log("");
|
|
169
|
+
console.log(" Happy documenting! \u{1F680}");
|
|
170
|
+
console.log("");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// src/scaffold.ts
|
|
174
|
+
async function scaffold(options) {
|
|
175
|
+
const {
|
|
176
|
+
projectDir,
|
|
177
|
+
projectName,
|
|
178
|
+
description,
|
|
179
|
+
brandPreset,
|
|
180
|
+
repoUrl,
|
|
181
|
+
doInstall,
|
|
182
|
+
enableAiChat = true,
|
|
183
|
+
i18nLocales,
|
|
184
|
+
trackRepos
|
|
185
|
+
} = options;
|
|
186
|
+
const targetDir = resolve(projectDir);
|
|
187
|
+
if (existsSync(targetDir) && readdirSync(targetDir).length > 0) {
|
|
188
|
+
throw new Error(`Directory "${targetDir}" already exists and is not empty.`);
|
|
189
|
+
}
|
|
190
|
+
mkdirSync(targetDir, { recursive: true });
|
|
191
|
+
const slug = slugify(projectName);
|
|
192
|
+
await downloadTemplate(targetDir, projectName);
|
|
193
|
+
resetTrackingConfig(targetDir);
|
|
194
|
+
if (trackRepos?.length) {
|
|
195
|
+
writeTrackingConfig(targetDir, trackRepos);
|
|
196
|
+
const list = trackRepos.map((r) => `${r.owner}/${r.repo}`).join(", ");
|
|
197
|
+
console.log(` \u2713 Thally Track enabled \u2014 watching ${list} (branch main, all files; refine in docs.json).`);
|
|
198
|
+
console.log(" To finish wiring it: `thally track setup` (pick a trigger) + `thally agent init`,");
|
|
199
|
+
console.log(" then add your ANTHROPIC_API_KEY. See /guides/thally-track.");
|
|
200
|
+
}
|
|
201
|
+
writeStarterContent(targetDir, projectName, enableAiChat, repoUrl, i18nLocales);
|
|
202
|
+
writeStarterReadme(targetDir, projectName);
|
|
203
|
+
writeStarterAgentGuide(targetDir, projectName);
|
|
204
|
+
updateSiteConfig(targetDir, projectName, description, brandPreset, repoUrl);
|
|
205
|
+
patchApiReferenceGuard(targetDir);
|
|
206
|
+
patchTopBarNavigation(targetDir);
|
|
207
|
+
patchOpenApiFetch(targetDir);
|
|
208
|
+
patchPackageJson(targetDir, slug);
|
|
209
|
+
writeCloudflareRuntimeConfig(targetDir, slug);
|
|
210
|
+
patchGitignore(targetDir);
|
|
211
|
+
updateEnvExample(targetDir);
|
|
212
|
+
if (doInstall) {
|
|
213
|
+
installDeps(targetDir);
|
|
214
|
+
}
|
|
215
|
+
initGit(targetDir);
|
|
216
|
+
return { projectDir: targetDir };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export {
|
|
220
|
+
slugify,
|
|
221
|
+
initGit,
|
|
222
|
+
installDeps,
|
|
223
|
+
logo,
|
|
224
|
+
success,
|
|
225
|
+
TEMPLATE_REPOSITORY,
|
|
226
|
+
TEMPLATE_COMMIT_SHA,
|
|
227
|
+
EXCLUDE_PATHS,
|
|
228
|
+
shouldInclude,
|
|
229
|
+
readDocsJson,
|
|
230
|
+
writeDocsJson,
|
|
231
|
+
scaffold
|
|
232
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/release.ts
|
|
4
|
+
var STABLE_SCAFFOLD_RELEASE = {
|
|
5
|
+
schemaVersion: 1,
|
|
6
|
+
id: "2026-08-04.b0094de4.e36d2bcf",
|
|
7
|
+
source: {
|
|
8
|
+
repository: "thallylabs/docs",
|
|
9
|
+
commitSha: "b0094de4fea84567eb12c39c6783fdae6820bb98",
|
|
10
|
+
treeSha: "ffd0a6fda07341ddd1ba164cb40acef796f89e2d",
|
|
11
|
+
archiveUrl: "https://codeload.github.com/thallylabs/docs/tar.gz/b0094de4fea84567eb12c39c6783fdae6820bb98"
|
|
12
|
+
},
|
|
13
|
+
runtime: {
|
|
14
|
+
repository: "thallylabs/thally",
|
|
15
|
+
commitSha: "e36d2bcff38f7638a77369e12773a7cab4d5d9ce",
|
|
16
|
+
treeSha: "1c8b0358d78d8caa14ed039bff6ab47c98b685d8",
|
|
17
|
+
contentSource: "assets",
|
|
18
|
+
identityContractVersion: 1
|
|
19
|
+
},
|
|
20
|
+
starterVersion: 1
|
|
21
|
+
};
|
|
22
|
+
function isStableScaffoldRelease(value) {
|
|
23
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
24
|
+
const candidate = value;
|
|
25
|
+
return candidate.schemaVersion === STABLE_SCAFFOLD_RELEASE.schemaVersion && candidate.id === STABLE_SCAFFOLD_RELEASE.id && candidate.starterVersion === STABLE_SCAFFOLD_RELEASE.starterVersion && candidate.source?.repository === STABLE_SCAFFOLD_RELEASE.source.repository && candidate.source?.commitSha === STABLE_SCAFFOLD_RELEASE.source.commitSha && candidate.source?.treeSha === STABLE_SCAFFOLD_RELEASE.source.treeSha && candidate.source?.archiveUrl === STABLE_SCAFFOLD_RELEASE.source.archiveUrl && candidate.runtime?.repository === STABLE_SCAFFOLD_RELEASE.runtime.repository && candidate.runtime?.commitSha === STABLE_SCAFFOLD_RELEASE.runtime.commitSha && candidate.runtime?.treeSha === STABLE_SCAFFOLD_RELEASE.runtime.treeSha && candidate.runtime?.contentSource === STABLE_SCAFFOLD_RELEASE.runtime.contentSource && candidate.runtime?.identityContractVersion === STABLE_SCAFFOLD_RELEASE.runtime.identityContractVersion;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
STABLE_SCAFFOLD_RELEASE,
|
|
30
|
+
isStableScaffoldRelease
|
|
31
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lowest `@thallylabs/cli` release a scaffold may declare.
|
|
3
|
+
*
|
|
4
|
+
* The managed builder depends on the Cloudflare-aware CLI contract, so a site
|
|
5
|
+
* scaffolded from an older or locally-vendored template must not keep a
|
|
6
|
+
* pre-Workers pin. This is a FLOOR, never an override: the canonical template
|
|
7
|
+
* tracks the newest published CLI, and overwriting its pin with a constant that
|
|
8
|
+
* has since aged past it silently downgrades every generated site. Raise it
|
|
9
|
+
* only alongside a released CLI — `scaffold-hygiene.test.ts` fails if it ever
|
|
10
|
+
* climbs above the version this monorepo publishes.
|
|
11
|
+
*/
|
|
12
|
+
declare const MIN_CLI_VERSION = "0.7.0";
|
|
13
|
+
/**
|
|
14
|
+
* Lowest `@thallylabs/mcp` release a scaffold may declare. Same floor semantics
|
|
15
|
+
* as {@link MIN_CLI_VERSION}; it also stands in for the unresolvable `*` range
|
|
16
|
+
* that older workspace-based templates used.
|
|
17
|
+
*/
|
|
18
|
+
declare const MIN_MCP_VERSION = "0.9.0";
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a dependency pin to at least `floor`, preferring what the template
|
|
21
|
+
* already ships. An absent, unresolvable, or demonstrably older pin becomes the
|
|
22
|
+
* floor; anything newer — or anything the comparison cannot rank — survives.
|
|
23
|
+
*/
|
|
24
|
+
declare function raisePinToFloor(current: string | undefined, floor: string): string;
|
|
25
|
+
interface StarterLocale {
|
|
26
|
+
code: string;
|
|
27
|
+
label: string;
|
|
28
|
+
}
|
|
29
|
+
interface StarterFile {
|
|
30
|
+
path: string;
|
|
31
|
+
content: string;
|
|
32
|
+
}
|
|
33
|
+
interface BuildStarterFilesOptions {
|
|
34
|
+
projectName: string;
|
|
35
|
+
enableAiChat?: boolean;
|
|
36
|
+
repoUrl?: string;
|
|
37
|
+
i18nLocales?: Array<StarterLocale>;
|
|
38
|
+
}
|
|
39
|
+
declare function buildStarterDocsJson({ enableAiChat, repoUrl, i18nLocales, }: {
|
|
40
|
+
enableAiChat: boolean;
|
|
41
|
+
repoUrl?: string;
|
|
42
|
+
i18nLocales?: Array<{
|
|
43
|
+
code: string;
|
|
44
|
+
label: string;
|
|
45
|
+
}>;
|
|
46
|
+
}): string;
|
|
47
|
+
/**
|
|
48
|
+
* Render the complete site-owned starter layer without reading or writing the
|
|
49
|
+
* filesystem. CLI, MCP, and Thally Cloud consume these exact bytes so a new
|
|
50
|
+
* site cannot vary by which creation entry point the user chose.
|
|
51
|
+
*/
|
|
52
|
+
declare function buildStarterFiles({ projectName, enableAiChat, repoUrl, i18nLocales, }: BuildStarterFilesOptions): Array<StarterFile>;
|
|
53
|
+
declare function writeStarterContent(targetDir: string, projectName: string, enableAiChat?: boolean, repoUrl?: string, i18nLocales?: Array<{
|
|
54
|
+
code: string;
|
|
55
|
+
label: string;
|
|
56
|
+
}>): void;
|
|
57
|
+
declare function writeStarterAgentGuide(targetDir: string, projectName: string): void;
|
|
58
|
+
declare function writeStarterReadme(targetDir: string, projectName: string): void;
|
|
59
|
+
/**
|
|
60
|
+
* Write provider-portable Cloudflare Workers configuration into every scaffold.
|
|
61
|
+
*
|
|
62
|
+
* The files contain no account, route, bucket, or token identifiers. Thally
|
|
63
|
+
* Cloud supplies those operational values while self-hosters can deploy the
|
|
64
|
+
* same source tree to their own account without editing application internals.
|
|
65
|
+
*/
|
|
66
|
+
declare function writeCloudflareRuntimeConfig(targetDir: string, slug: string): void;
|
|
67
|
+
declare function updateSiteConfig(targetDir: string, projectName: string, description: string, brandPreset: string, repoUrl: string): void;
|
|
68
|
+
declare function patchApiReferenceGuard(targetDir: string): void;
|
|
69
|
+
declare function patchTopBarNavigation(targetDir: string): void;
|
|
70
|
+
declare function patchOpenApiFetch(targetDir: string): void;
|
|
71
|
+
declare function updateEnvExample(targetDir: string): void;
|
|
72
|
+
/**
|
|
73
|
+
* Normalize the canonical docs package for a newly named standalone site.
|
|
74
|
+
* `thallylabs/docs` is already standalone, while this defensive cleanup also
|
|
75
|
+
* keeps local or older monorepo-based sources safe to scaffold:
|
|
76
|
+
*
|
|
77
|
+
* - `workspaces` points at a directory that doesn't exist in scaffolds.
|
|
78
|
+
* - `prebuild`/`pretest` invoke `packages:build`, which builds those absent
|
|
79
|
+
* workspaces. Runtime sources and embeddings stay in `prebuild`: both run
|
|
80
|
+
* standalone and supply request-time data in filesystem-free Workers.
|
|
81
|
+
* - The copied `package-lock.json` still resolves the monorepo's workspace
|
|
82
|
+
* graph; deleting it lets the scaffold's own `npm install` write a clean
|
|
83
|
+
* lockfile. Workspace-linked deps (e.g. @thallylabs/core) resolve from the
|
|
84
|
+
* npm registry instead, which is why the template must depend on published
|
|
85
|
+
* versions, never `workspace:*` specs.
|
|
86
|
+
*
|
|
87
|
+
* Also names the package after the site so `npm ls`/lockfiles read correctly.
|
|
88
|
+
*/
|
|
89
|
+
declare function patchPackageJson(targetDir: string, slug: string): void;
|
|
90
|
+
/** Ensure dependency folders are ignored at any depth in generated sites. */
|
|
91
|
+
declare function patchGitignore(targetDir: string): void;
|
|
92
|
+
|
|
93
|
+
export { type BuildStarterFilesOptions, MIN_CLI_VERSION, MIN_MCP_VERSION, type StarterFile, type StarterLocale, buildStarterDocsJson, buildStarterFiles, patchApiReferenceGuard, patchGitignore, patchOpenApiFetch, patchPackageJson, patchTopBarNavigation, raisePinToFloor, updateEnvExample, updateSiteConfig, writeCloudflareRuntimeConfig, writeStarterAgentGuide, writeStarterContent, writeStarterReadme };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
MIN_CLI_VERSION,
|
|
4
|
+
MIN_MCP_VERSION,
|
|
5
|
+
buildStarterDocsJson,
|
|
6
|
+
buildStarterFiles,
|
|
7
|
+
patchApiReferenceGuard,
|
|
8
|
+
patchGitignore,
|
|
9
|
+
patchOpenApiFetch,
|
|
10
|
+
patchPackageJson,
|
|
11
|
+
patchTopBarNavigation,
|
|
12
|
+
raisePinToFloor,
|
|
13
|
+
updateEnvExample,
|
|
14
|
+
updateSiteConfig,
|
|
15
|
+
writeCloudflareRuntimeConfig,
|
|
16
|
+
writeStarterAgentGuide,
|
|
17
|
+
writeStarterContent,
|
|
18
|
+
writeStarterReadme
|
|
19
|
+
} from "./chunk-BW7J7DJV.js";
|
|
20
|
+
export {
|
|
21
|
+
MIN_CLI_VERSION,
|
|
22
|
+
MIN_MCP_VERSION,
|
|
23
|
+
buildStarterDocsJson,
|
|
24
|
+
buildStarterFiles,
|
|
25
|
+
patchApiReferenceGuard,
|
|
26
|
+
patchGitignore,
|
|
27
|
+
patchOpenApiFetch,
|
|
28
|
+
patchPackageJson,
|
|
29
|
+
patchTopBarNavigation,
|
|
30
|
+
raisePinToFloor,
|
|
31
|
+
updateEnvExample,
|
|
32
|
+
updateSiteConfig,
|
|
33
|
+
writeCloudflareRuntimeConfig,
|
|
34
|
+
writeStarterAgentGuide,
|
|
35
|
+
writeStarterContent,
|
|
36
|
+
writeStarterReadme
|
|
37
|
+
};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
migrateDocs
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-YWNWLSZ2.js";
|
|
5
5
|
import {
|
|
6
6
|
logo,
|
|
7
7
|
readDocsJson,
|
|
@@ -9,15 +9,20 @@ import {
|
|
|
9
9
|
slugify,
|
|
10
10
|
success,
|
|
11
11
|
writeDocsJson
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-JNDRCCJV.js";
|
|
13
|
+
import "./chunk-BW7J7DJV.js";
|
|
14
|
+
import "./chunk-PJW4JJIT.js";
|
|
13
15
|
|
|
14
16
|
// src/index.ts
|
|
15
17
|
import { existsSync as existsSync3, readdirSync as readdirSync2 } from "fs";
|
|
16
18
|
import { resolve as resolve2 } from "path";
|
|
17
19
|
|
|
18
20
|
// src/prompts.ts
|
|
19
|
-
import { input, select } from "@inquirer/prompts";
|
|
21
|
+
import { confirm, input, select } from "@inquirer/prompts";
|
|
20
22
|
import { basename, resolve } from "path";
|
|
23
|
+
import {
|
|
24
|
+
parseGitHubRepositoryUrl
|
|
25
|
+
} from "@thallylabs/migrate";
|
|
21
26
|
function parseMigrationPlatform(value) {
|
|
22
27
|
if (!value || value === "auto") return void 0;
|
|
23
28
|
if (value === "mintlify" || value === "docusaurus") return value;
|
|
@@ -36,6 +41,54 @@ async function gatherMigrationPlatform(value, useDefaults) {
|
|
|
36
41
|
default: "mintlify"
|
|
37
42
|
});
|
|
38
43
|
}
|
|
44
|
+
var LIVE_URL_MIGRATION_WARNING = "Live website migration reconstructs documentation from public output and may need manual alignment. A source GitHub repository produces a more accurate migration. Use the Thally MCP afterward if the generated project needs refinement.";
|
|
45
|
+
function validateGitHubRepositorySource(value) {
|
|
46
|
+
try {
|
|
47
|
+
parseGitHubRepositoryUrl(value);
|
|
48
|
+
return true;
|
|
49
|
+
} catch (error) {
|
|
50
|
+
return error instanceof Error ? error.message : "Enter a valid public GitHub repository URL.";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function resolveAutoDetectedMigrationSource(sourceUrl, shouldPrompt) {
|
|
54
|
+
const source = new URL(sourceUrl);
|
|
55
|
+
if (source.hostname.toLowerCase() === "github.com") return sourceUrl;
|
|
56
|
+
console.warn(`
|
|
57
|
+
\u26A0 ${LIVE_URL_MIGRATION_WARNING}`);
|
|
58
|
+
if (!shouldPrompt) return sourceUrl;
|
|
59
|
+
const sourcePreference = await select({
|
|
60
|
+
message: " Which source should Thally migrate?",
|
|
61
|
+
choices: [
|
|
62
|
+
{
|
|
63
|
+
name: "Source GitHub repository (recommended)",
|
|
64
|
+
value: "github"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "Continue with the live website URL",
|
|
68
|
+
value: "website"
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
default: "github"
|
|
72
|
+
});
|
|
73
|
+
if (sourcePreference === "github") {
|
|
74
|
+
const repositoryUrl = await input({
|
|
75
|
+
message: " GitHub repository URL:",
|
|
76
|
+
validate: validateGitHubRepositorySource
|
|
77
|
+
});
|
|
78
|
+
parseGitHubRepositoryUrl(repositoryUrl);
|
|
79
|
+
return repositoryUrl;
|
|
80
|
+
}
|
|
81
|
+
const hasAcceptedAlignment = await confirm({
|
|
82
|
+
message: " Continue knowing the migration may need manual alignment, using the Thally MCP afterward if needed?",
|
|
83
|
+
default: false
|
|
84
|
+
});
|
|
85
|
+
if (!hasAcceptedAlignment) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
"Migration cancelled. Re-run with the source GitHub repository for the most accurate result."
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
return sourceUrl;
|
|
91
|
+
}
|
|
39
92
|
async function gatherAnswers(dirArg, useDefaults, installPreference) {
|
|
40
93
|
let projectDir;
|
|
41
94
|
if (dirArg) {
|
|
@@ -98,13 +151,13 @@ async function gatherAnswers(dirArg, useDefaults, installPreference) {
|
|
|
98
151
|
let i18nLocales;
|
|
99
152
|
if (!useDefaults) {
|
|
100
153
|
const enableI18n = await input({
|
|
101
|
-
message: "
|
|
154
|
+
message: " Add languages beyond English and Spanish? (y/N):",
|
|
102
155
|
default: "N"
|
|
103
156
|
});
|
|
104
157
|
if (enableI18n.toLowerCase() === "y") {
|
|
105
158
|
const localesInput = await input({
|
|
106
|
-
message: " Which locales? (comma-separated codes, e.g.
|
|
107
|
-
default: "
|
|
159
|
+
message: " Which additional locales? (comma-separated codes, e.g. fr,de,ja):",
|
|
160
|
+
default: "fr"
|
|
108
161
|
});
|
|
109
162
|
const LOCALE_LABELS = {
|
|
110
163
|
en: "English",
|
|
@@ -131,13 +184,26 @@ async function gatherAnswers(dirArg, useDefaults, installPreference) {
|
|
|
131
184
|
}
|
|
132
185
|
|
|
133
186
|
// src/index.ts
|
|
134
|
-
import { parseGitHubRepositoryUrl } from "@thallylabs/migrate";
|
|
187
|
+
import { parseGitHubRepositoryUrl as parseGitHubRepositoryUrl2 } from "@thallylabs/migrate";
|
|
135
188
|
|
|
136
189
|
// src/check.ts
|
|
137
190
|
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
138
191
|
import { join, extname, relative } from "path";
|
|
139
192
|
import { execFileSync } from "child_process";
|
|
193
|
+
|
|
194
|
+
// src/frontmatter.ts
|
|
140
195
|
import matter from "gray-matter";
|
|
196
|
+
var FRONTMATTER_OPTIONS = {
|
|
197
|
+
engines: {
|
|
198
|
+
javascript: () => ({}),
|
|
199
|
+
js: () => ({})
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
function parseFrontmatter(raw) {
|
|
203
|
+
return matter(raw, FRONTMATTER_OPTIONS);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// src/check.ts
|
|
141
207
|
import { parse as parseYaml } from "yaml";
|
|
142
208
|
function gitLocal(projectDir, args2) {
|
|
143
209
|
try {
|
|
@@ -373,7 +439,7 @@ async function runCheck(projectDir, options) {
|
|
|
373
439
|
let lineOffset = 0;
|
|
374
440
|
try {
|
|
375
441
|
const raw = readFileSync(filePath, "utf8");
|
|
376
|
-
const parsed =
|
|
442
|
+
const parsed = parseFrontmatter(raw);
|
|
377
443
|
data = parsed.data;
|
|
378
444
|
content = parsed.content;
|
|
379
445
|
lineOffset = raw.slice(0, raw.indexOf(content)).split("\n").length - 1;
|
|
@@ -474,7 +540,6 @@ thally check: ${errors.length} error(s), ${warnings.length} warning(s)`);
|
|
|
474
540
|
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
|
|
475
541
|
import { join as join2, dirname } from "path";
|
|
476
542
|
import { input as input2 } from "@inquirer/prompts";
|
|
477
|
-
import matter2 from "gray-matter";
|
|
478
543
|
import Anthropic from "@anthropic-ai/sdk";
|
|
479
544
|
import pLimit from "p-limit";
|
|
480
545
|
function readDocsJson2(projectDir) {
|
|
@@ -654,11 +719,11 @@ async function runTranslateCommand(locale, pages, force, apiKey, model, yes, pro
|
|
|
654
719
|
}
|
|
655
720
|
console.log("");
|
|
656
721
|
if (!yes) {
|
|
657
|
-
const
|
|
722
|
+
const confirm2 = await input2({
|
|
658
723
|
message: " Proceed? (Y/n):",
|
|
659
724
|
default: "Y"
|
|
660
725
|
});
|
|
661
|
-
if (
|
|
726
|
+
if (confirm2.toLowerCase() === "n") {
|
|
662
727
|
console.log("\n Aborted.");
|
|
663
728
|
return;
|
|
664
729
|
}
|
|
@@ -672,7 +737,7 @@ async function runTranslateCommand(locale, pages, force, apiKey, model, yes, pro
|
|
|
672
737
|
({ pageId, sourceFile, targetFile }) => limit(async () => {
|
|
673
738
|
try {
|
|
674
739
|
const sourceContent = readFileSync2(sourceFile, "utf8");
|
|
675
|
-
const parsed =
|
|
740
|
+
const parsed = parseFrontmatter(sourceContent);
|
|
676
741
|
if (!parsed.data.title) {
|
|
677
742
|
console.warn(` \u26A0 ${pageId}: missing title in frontmatter \u2014 translating anyway`);
|
|
678
743
|
}
|
|
@@ -732,7 +797,7 @@ function getFlagValue(flag) {
|
|
|
732
797
|
return void 0;
|
|
733
798
|
}
|
|
734
799
|
async function runMigrateCommand() {
|
|
735
|
-
|
|
800
|
+
let sourceUrl = positional[1];
|
|
736
801
|
if (!sourceUrl) {
|
|
737
802
|
console.error("\n \u274C Source URL is required.");
|
|
738
803
|
console.error(" Usage: create-thally-docs migrate <github-or-docs-url> [output-dir] [options]");
|
|
@@ -743,12 +808,22 @@ async function runMigrateCommand() {
|
|
|
743
808
|
try {
|
|
744
809
|
source = new URL(sourceUrl);
|
|
745
810
|
if (!["http:", "https:"].includes(source.protocol)) throw new Error("Only HTTP and HTTPS sources are supported.");
|
|
746
|
-
if (source.hostname.toLowerCase() === "github.com")
|
|
811
|
+
if (source.hostname.toLowerCase() === "github.com") parseGitHubRepositoryUrl2(sourceUrl);
|
|
747
812
|
} catch (err) {
|
|
748
813
|
console.error(`
|
|
749
814
|
\u274C ${err instanceof Error ? err.message : err}`);
|
|
750
815
|
process.exit(1);
|
|
751
816
|
}
|
|
817
|
+
const branch = getFlagValue("--branch");
|
|
818
|
+
const docsDir = getFlagValue("--docs-dir");
|
|
819
|
+
const yes = flags.includes("--yes") || flags.includes("-y");
|
|
820
|
+
const platformFlag = getFlagValue("--platform");
|
|
821
|
+
const platform = await gatherMigrationPlatform(platformFlag, yes);
|
|
822
|
+
if (platform === void 0) {
|
|
823
|
+
const shouldPromptForSource = platformFlag === void 0 && !yes;
|
|
824
|
+
sourceUrl = await resolveAutoDetectedMigrationSource(sourceUrl, shouldPromptForSource);
|
|
825
|
+
source = new URL(sourceUrl);
|
|
826
|
+
}
|
|
752
827
|
const apiKey = getFlagValue("--api-key") ?? process.env.ANTHROPIC_API_KEY;
|
|
753
828
|
const intoDir = getFlagValue("--into");
|
|
754
829
|
const isInto = Boolean(intoDir);
|
|
@@ -758,13 +833,9 @@ async function runMigrateCommand() {
|
|
|
758
833
|
} else if (positional[2]) {
|
|
759
834
|
projectDir = resolve2(positional[2]);
|
|
760
835
|
} else {
|
|
761
|
-
const sourceName = source.hostname.toLowerCase() === "github.com" ?
|
|
836
|
+
const sourceName = source.hostname.toLowerCase() === "github.com" ? parseGitHubRepositoryUrl2(sourceUrl).repo : source.pathname.split("/").filter(Boolean).at(-1) ?? source.hostname.split(".")[0];
|
|
762
837
|
projectDir = resolve2(`${slugify(sourceName)}-docs`);
|
|
763
838
|
}
|
|
764
|
-
const branch = getFlagValue("--branch");
|
|
765
|
-
const docsDir = getFlagValue("--docs-dir");
|
|
766
|
-
const yes = flags.includes("--yes") || flags.includes("-y");
|
|
767
|
-
const platform = await gatherMigrationPlatform(getFlagValue("--platform"), yes);
|
|
768
839
|
const maxPagesValue = getFlagValue("--max-pages");
|
|
769
840
|
const maxPages = maxPagesValue ? Number(maxPagesValue) : void 0;
|
|
770
841
|
if (maxPages !== void 0 && (!Number.isInteger(maxPages) || maxPages < 1 || maxPages > 1e3)) {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { MigrationPlatform, MigrationFetcher, MigrationBundle, MigrationWarning } from '@thallylabs/migrate';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CLI materializer for the shared Thally migration engine. Discovery completes
|
|
5
|
+
* before scaffolding or writing, and every generated path is proven to remain
|
|
6
|
+
* inside the selected project directory.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
interface MigrateOptions {
|
|
10
|
+
sourceUrl: string;
|
|
11
|
+
projectDir: string;
|
|
12
|
+
into: boolean;
|
|
13
|
+
/** Retained for CLI compatibility; Markdown/MDX imports do not require a key. */
|
|
14
|
+
apiKey?: string;
|
|
15
|
+
branch?: string;
|
|
16
|
+
docsDir?: string;
|
|
17
|
+
projectName?: string;
|
|
18
|
+
yes: boolean;
|
|
19
|
+
maxPages?: number;
|
|
20
|
+
/** Explicit source platform selected by an interactive or automated caller. */
|
|
21
|
+
platform?: MigrationPlatform;
|
|
22
|
+
/** Optional host fetch boundary; used by Thally Cloud adapters and tests. */
|
|
23
|
+
fetcher?: MigrationFetcher;
|
|
24
|
+
}
|
|
25
|
+
interface MigrateResult {
|
|
26
|
+
pagesWritten: number;
|
|
27
|
+
assetsWritten: number;
|
|
28
|
+
projectDir: string;
|
|
29
|
+
platform: MigrationBundle['platform'];
|
|
30
|
+
warnings: Array<MigrationWarning>;
|
|
31
|
+
}
|
|
32
|
+
/** Import a GitHub docs repository or public docs URL into a Thally project. */
|
|
33
|
+
declare function migrateDocs(options: MigrateOptions): Promise<MigrateResult>;
|
|
34
|
+
|
|
35
|
+
export { type MigrateOptions, type MigrateResult, migrateDocs };
|
package/dist/migrate/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
migrateDocs
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-YWNWLSZ2.js";
|
|
5
|
+
import "../chunk-JNDRCCJV.js";
|
|
6
|
+
import "../chunk-BW7J7DJV.js";
|
|
7
|
+
import "../chunk-PJW4JJIT.js";
|
|
6
8
|
export {
|
|
7
9
|
migrateDocs
|
|
8
10
|
};
|