create-thally-docs 0.7.9 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# create-thally-docs
|
|
2
2
|
|
|
3
|
-
Scaffold
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Scaffold the first customer-facing knowledge surface in a
|
|
4
|
+
[Thally](https://github.com/thallylabs/thally) product-knowledge pipeline. The
|
|
5
|
+
result is an open documentation site that serves every page to humans as
|
|
6
|
+
polished HTML and to agents as structured JSON, JSON-LD, and Markdown from the
|
|
7
|
+
same URL.
|
|
6
8
|
|
|
7
9
|
## Quick start
|
|
8
10
|
|
|
@@ -44,6 +46,16 @@ interactive question explicitly.
|
|
|
44
46
|
| `create-thally-docs check [dir] [--fix]` | Lint content for orphan pages and missing frontmatter |
|
|
45
47
|
| `create-thally-docs translate --locale <code>` | Translate content into another locale |
|
|
46
48
|
|
|
49
|
+
Interactive migrations ask whether the source is Mintlify, Docusaurus, or
|
|
50
|
+
another auto-detected platform. When automatic detection receives a live
|
|
51
|
+
website URL, the CLI recommends its source GitHub repository and requires
|
|
52
|
+
confirmation before continuing with the less precise website crawl. For
|
|
53
|
+
scripts and CI, pass
|
|
54
|
+
`--platform mintlify`, `--platform docusaurus`, or `--platform auto`; `--yes`
|
|
55
|
+
keeps backward-compatible auto-detection when no platform flag is supplied.
|
|
56
|
+
Explicit `--platform auto` and `--yes` runs print the live-site limitation
|
|
57
|
+
without introducing an interactive prompt.
|
|
58
|
+
|
|
47
59
|
Prefer a single binary? Install [`@thallylabs/cli`](https://www.npmjs.com/package/@thallylabs/cli)
|
|
48
60
|
and use `thally init`, which delegates here.
|
|
49
61
|
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
initGit,
|
|
4
4
|
installDeps,
|
|
5
5
|
scaffold
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-RS6U2GSX.js";
|
|
7
7
|
|
|
8
8
|
// src/migrate/index.ts
|
|
9
9
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
@@ -41,7 +41,12 @@ async function discoverMigration(options) {
|
|
|
41
41
|
const url = new URL(options.sourceUrl);
|
|
42
42
|
if (url.hostname.toLowerCase() !== "github.com") {
|
|
43
43
|
console.log(` \u{1F310} Discovering public docs at ${url.origin}${url.pathname}...`);
|
|
44
|
-
return migrateUrl({
|
|
44
|
+
return migrateUrl({
|
|
45
|
+
sourceUrl: options.sourceUrl,
|
|
46
|
+
platform: options.platform,
|
|
47
|
+
maxPages: options.maxPages,
|
|
48
|
+
fetcher: options.fetcher
|
|
49
|
+
});
|
|
45
50
|
}
|
|
46
51
|
const source = parseGitHubRepositoryUrl(options.sourceUrl);
|
|
47
52
|
if (options.branch) source.branch = options.branch;
|
|
@@ -53,7 +58,8 @@ async function discoverMigration(options) {
|
|
|
53
58
|
return migrateRepository({
|
|
54
59
|
repositoryDir: cloneDir,
|
|
55
60
|
sourceUrl: options.sourceUrl,
|
|
56
|
-
docsDir: options.docsDir ?? (source.docsDir || void 0)
|
|
61
|
+
docsDir: options.docsDir ?? (source.docsDir || void 0),
|
|
62
|
+
platform: options.platform
|
|
57
63
|
});
|
|
58
64
|
} finally {
|
|
59
65
|
rmSync(temporaryRoot, { recursive: true, force: true });
|
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-SDZZYPSN.js";
|
|
5
5
|
import {
|
|
6
6
|
logo,
|
|
7
7
|
readDocsJson,
|
|
@@ -9,16 +9,84 @@ import {
|
|
|
9
9
|
slugify,
|
|
10
10
|
success,
|
|
11
11
|
writeDocsJson
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-RS6U2GSX.js";
|
|
13
13
|
|
|
14
14
|
// src/index.ts
|
|
15
15
|
import { existsSync as existsSync3, readdirSync as readdirSync2 } from "fs";
|
|
16
16
|
import { resolve as resolve2 } from "path";
|
|
17
17
|
|
|
18
18
|
// src/prompts.ts
|
|
19
|
-
import { input, select } from "@inquirer/prompts";
|
|
20
|
-
import { basename } from "path";
|
|
21
|
-
import {
|
|
19
|
+
import { confirm, input, select } from "@inquirer/prompts";
|
|
20
|
+
import { basename, resolve } from "path";
|
|
21
|
+
import {
|
|
22
|
+
parseGitHubRepositoryUrl
|
|
23
|
+
} from "@thallylabs/migrate";
|
|
24
|
+
function parseMigrationPlatform(value) {
|
|
25
|
+
if (!value || value === "auto") return void 0;
|
|
26
|
+
if (value === "mintlify" || value === "docusaurus") return value;
|
|
27
|
+
throw new Error("--platform must be mintlify, docusaurus, or auto.");
|
|
28
|
+
}
|
|
29
|
+
async function gatherMigrationPlatform(value, useDefaults) {
|
|
30
|
+
const configured = parseMigrationPlatform(value);
|
|
31
|
+
if (configured || value === "auto" || useDefaults) return configured;
|
|
32
|
+
return select({
|
|
33
|
+
message: " Which platform currently hosts these docs?",
|
|
34
|
+
choices: [
|
|
35
|
+
{ name: "Mintlify", value: "mintlify" },
|
|
36
|
+
{ name: "Docusaurus", value: "docusaurus" },
|
|
37
|
+
{ name: "Other / detect automatically", value: void 0 }
|
|
38
|
+
],
|
|
39
|
+
default: "mintlify"
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
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.";
|
|
43
|
+
function validateGitHubRepositorySource(value) {
|
|
44
|
+
try {
|
|
45
|
+
parseGitHubRepositoryUrl(value);
|
|
46
|
+
return true;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
return error instanceof Error ? error.message : "Enter a valid public GitHub repository URL.";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function resolveAutoDetectedMigrationSource(sourceUrl, shouldPrompt) {
|
|
52
|
+
const source = new URL(sourceUrl);
|
|
53
|
+
if (source.hostname.toLowerCase() === "github.com") return sourceUrl;
|
|
54
|
+
console.warn(`
|
|
55
|
+
\u26A0 ${LIVE_URL_MIGRATION_WARNING}`);
|
|
56
|
+
if (!shouldPrompt) return sourceUrl;
|
|
57
|
+
const sourcePreference = await select({
|
|
58
|
+
message: " Which source should Thally migrate?",
|
|
59
|
+
choices: [
|
|
60
|
+
{
|
|
61
|
+
name: "Source GitHub repository (recommended)",
|
|
62
|
+
value: "github"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: "Continue with the live website URL",
|
|
66
|
+
value: "website"
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
default: "github"
|
|
70
|
+
});
|
|
71
|
+
if (sourcePreference === "github") {
|
|
72
|
+
const repositoryUrl = await input({
|
|
73
|
+
message: " GitHub repository URL:",
|
|
74
|
+
validate: validateGitHubRepositorySource
|
|
75
|
+
});
|
|
76
|
+
parseGitHubRepositoryUrl(repositoryUrl);
|
|
77
|
+
return repositoryUrl;
|
|
78
|
+
}
|
|
79
|
+
const hasAcceptedAlignment = await confirm({
|
|
80
|
+
message: " Continue knowing the migration may need manual alignment, using the Thally MCP afterward if needed?",
|
|
81
|
+
default: false
|
|
82
|
+
});
|
|
83
|
+
if (!hasAcceptedAlignment) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
"Migration cancelled. Re-run with the source GitHub repository for the most accurate result."
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
return sourceUrl;
|
|
89
|
+
}
|
|
22
90
|
async function gatherAnswers(dirArg, useDefaults, installPreference) {
|
|
23
91
|
let projectDir;
|
|
24
92
|
if (dirArg) {
|
|
@@ -114,13 +182,26 @@ async function gatherAnswers(dirArg, useDefaults, installPreference) {
|
|
|
114
182
|
}
|
|
115
183
|
|
|
116
184
|
// src/index.ts
|
|
117
|
-
import { parseGitHubRepositoryUrl } from "@thallylabs/migrate";
|
|
185
|
+
import { parseGitHubRepositoryUrl as parseGitHubRepositoryUrl2 } from "@thallylabs/migrate";
|
|
118
186
|
|
|
119
187
|
// src/check.ts
|
|
120
188
|
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
121
189
|
import { join, extname, relative } from "path";
|
|
122
190
|
import { execFileSync } from "child_process";
|
|
191
|
+
|
|
192
|
+
// src/frontmatter.ts
|
|
123
193
|
import matter from "gray-matter";
|
|
194
|
+
var FRONTMATTER_OPTIONS = {
|
|
195
|
+
engines: {
|
|
196
|
+
javascript: () => ({}),
|
|
197
|
+
js: () => ({})
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
function parseFrontmatter(raw) {
|
|
201
|
+
return matter(raw, FRONTMATTER_OPTIONS);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// src/check.ts
|
|
124
205
|
import { parse as parseYaml } from "yaml";
|
|
125
206
|
function gitLocal(projectDir, args2) {
|
|
126
207
|
try {
|
|
@@ -356,7 +437,7 @@ async function runCheck(projectDir, options) {
|
|
|
356
437
|
let lineOffset = 0;
|
|
357
438
|
try {
|
|
358
439
|
const raw = readFileSync(filePath, "utf8");
|
|
359
|
-
const parsed =
|
|
440
|
+
const parsed = parseFrontmatter(raw);
|
|
360
441
|
data = parsed.data;
|
|
361
442
|
content = parsed.content;
|
|
362
443
|
lineOffset = raw.slice(0, raw.indexOf(content)).split("\n").length - 1;
|
|
@@ -457,7 +538,6 @@ thally check: ${errors.length} error(s), ${warnings.length} warning(s)`);
|
|
|
457
538
|
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
|
|
458
539
|
import { join as join2, dirname } from "path";
|
|
459
540
|
import { input as input2 } from "@inquirer/prompts";
|
|
460
|
-
import matter2 from "gray-matter";
|
|
461
541
|
import Anthropic from "@anthropic-ai/sdk";
|
|
462
542
|
import pLimit from "p-limit";
|
|
463
543
|
function readDocsJson2(projectDir) {
|
|
@@ -637,11 +717,11 @@ async function runTranslateCommand(locale, pages, force, apiKey, model, yes, pro
|
|
|
637
717
|
}
|
|
638
718
|
console.log("");
|
|
639
719
|
if (!yes) {
|
|
640
|
-
const
|
|
720
|
+
const confirm2 = await input2({
|
|
641
721
|
message: " Proceed? (Y/n):",
|
|
642
722
|
default: "Y"
|
|
643
723
|
});
|
|
644
|
-
if (
|
|
724
|
+
if (confirm2.toLowerCase() === "n") {
|
|
645
725
|
console.log("\n Aborted.");
|
|
646
726
|
return;
|
|
647
727
|
}
|
|
@@ -655,7 +735,7 @@ async function runTranslateCommand(locale, pages, force, apiKey, model, yes, pro
|
|
|
655
735
|
({ pageId, sourceFile, targetFile }) => limit(async () => {
|
|
656
736
|
try {
|
|
657
737
|
const sourceContent = readFileSync2(sourceFile, "utf8");
|
|
658
|
-
const parsed =
|
|
738
|
+
const parsed = parseFrontmatter(sourceContent);
|
|
659
739
|
if (!parsed.data.title) {
|
|
660
740
|
console.warn(` \u26A0 ${pageId}: missing title in frontmatter \u2014 translating anyway`);
|
|
661
741
|
}
|
|
@@ -692,8 +772,10 @@ var valueFlags = /* @__PURE__ */ new Set([
|
|
|
692
772
|
"--docs-dir",
|
|
693
773
|
"--into",
|
|
694
774
|
"--locale",
|
|
775
|
+
"--max-pages",
|
|
695
776
|
"--model",
|
|
696
|
-
"--pages"
|
|
777
|
+
"--pages",
|
|
778
|
+
"--platform"
|
|
697
779
|
]);
|
|
698
780
|
var positional = [];
|
|
699
781
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -713,7 +795,7 @@ function getFlagValue(flag) {
|
|
|
713
795
|
return void 0;
|
|
714
796
|
}
|
|
715
797
|
async function runMigrateCommand() {
|
|
716
|
-
|
|
798
|
+
let sourceUrl = positional[1];
|
|
717
799
|
if (!sourceUrl) {
|
|
718
800
|
console.error("\n \u274C Source URL is required.");
|
|
719
801
|
console.error(" Usage: create-thally-docs migrate <github-or-docs-url> [output-dir] [options]");
|
|
@@ -724,12 +806,22 @@ async function runMigrateCommand() {
|
|
|
724
806
|
try {
|
|
725
807
|
source = new URL(sourceUrl);
|
|
726
808
|
if (!["http:", "https:"].includes(source.protocol)) throw new Error("Only HTTP and HTTPS sources are supported.");
|
|
727
|
-
if (source.hostname.toLowerCase() === "github.com")
|
|
809
|
+
if (source.hostname.toLowerCase() === "github.com") parseGitHubRepositoryUrl2(sourceUrl);
|
|
728
810
|
} catch (err) {
|
|
729
811
|
console.error(`
|
|
730
812
|
\u274C ${err instanceof Error ? err.message : err}`);
|
|
731
813
|
process.exit(1);
|
|
732
814
|
}
|
|
815
|
+
const branch = getFlagValue("--branch");
|
|
816
|
+
const docsDir = getFlagValue("--docs-dir");
|
|
817
|
+
const yes = flags.includes("--yes") || flags.includes("-y");
|
|
818
|
+
const platformFlag = getFlagValue("--platform");
|
|
819
|
+
const platform = await gatherMigrationPlatform(platformFlag, yes);
|
|
820
|
+
if (platform === void 0) {
|
|
821
|
+
const shouldPromptForSource = platformFlag === void 0 && !yes;
|
|
822
|
+
sourceUrl = await resolveAutoDetectedMigrationSource(sourceUrl, shouldPromptForSource);
|
|
823
|
+
source = new URL(sourceUrl);
|
|
824
|
+
}
|
|
733
825
|
const apiKey = getFlagValue("--api-key") ?? process.env.ANTHROPIC_API_KEY;
|
|
734
826
|
const intoDir = getFlagValue("--into");
|
|
735
827
|
const isInto = Boolean(intoDir);
|
|
@@ -739,18 +831,15 @@ async function runMigrateCommand() {
|
|
|
739
831
|
} else if (positional[2]) {
|
|
740
832
|
projectDir = resolve2(positional[2]);
|
|
741
833
|
} else {
|
|
742
|
-
const sourceName = source.hostname.toLowerCase() === "github.com" ?
|
|
834
|
+
const sourceName = source.hostname.toLowerCase() === "github.com" ? parseGitHubRepositoryUrl2(sourceUrl).repo : source.pathname.split("/").filter(Boolean).at(-1) ?? source.hostname.split(".")[0];
|
|
743
835
|
projectDir = resolve2(`${slugify(sourceName)}-docs`);
|
|
744
836
|
}
|
|
745
|
-
const branch = getFlagValue("--branch");
|
|
746
|
-
const docsDir = getFlagValue("--docs-dir");
|
|
747
837
|
const maxPagesValue = getFlagValue("--max-pages");
|
|
748
838
|
const maxPages = maxPagesValue ? Number(maxPagesValue) : void 0;
|
|
749
839
|
if (maxPages !== void 0 && (!Number.isInteger(maxPages) || maxPages < 1 || maxPages > 1e3)) {
|
|
750
840
|
console.error("\n \u274C --max-pages must be an integer between 1 and 1000.");
|
|
751
841
|
process.exit(1);
|
|
752
842
|
}
|
|
753
|
-
const yes = flags.includes("--yes") || flags.includes("-y");
|
|
754
843
|
logo();
|
|
755
844
|
console.log(" \u{1F680} Thally Migrate");
|
|
756
845
|
console.log("");
|
|
@@ -758,6 +847,7 @@ async function runMigrateCommand() {
|
|
|
758
847
|
console.log(` Target: ${projectDir}`);
|
|
759
848
|
if (branch) console.log(` Branch: ${branch}`);
|
|
760
849
|
if (docsDir) console.log(` Docs dir: ${docsDir}`);
|
|
850
|
+
console.log(` Platform: ${platform ?? "auto-detect"}`);
|
|
761
851
|
console.log("");
|
|
762
852
|
await migrateDocs({
|
|
763
853
|
sourceUrl,
|
|
@@ -767,6 +857,7 @@ async function runMigrateCommand() {
|
|
|
767
857
|
branch,
|
|
768
858
|
docsDir,
|
|
769
859
|
maxPages,
|
|
860
|
+
platform,
|
|
770
861
|
yes
|
|
771
862
|
});
|
|
772
863
|
}
|
package/dist/migrate/index.js
CHANGED
package/dist/scaffold.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-thally-docs",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Scaffold a
|
|
3
|
+
"version": "0.8.1",
|
|
4
|
+
"description": "Scaffold the first documentation surface in a Thally product-knowledge pipeline.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=18"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@anthropic-ai/sdk": "^0.36.0",
|
|
30
30
|
"@inquirer/prompts": "^7.0.0",
|
|
31
|
-
"@thallylabs/migrate": "0.
|
|
31
|
+
"@thallylabs/migrate": "0.2.0",
|
|
32
32
|
"gray-matter": "^4.0.3",
|
|
33
33
|
"p-limit": "^6.1.0",
|
|
34
34
|
"tar": "^6.2.0",
|