@kurajs/cli 0.0.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 +24 -0
- package/dist/cli.js +91 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @kurajs/cli
|
|
2
|
+
|
|
3
|
+
The `kura` command-line tool.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
kura index [--out app/_index.bin] [--model Xenova/bge-m3]
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
**`kura index`** builds the search index for a Kura docs app: it reads the June-frozen
|
|
10
|
+
`app/_content.ts`, embeds every doc with bge-m3 (local, via `@kurajs/transformers`), and
|
|
11
|
+
writes a compact index (`app/_index.bin`) that the app loads at runtime — so search never
|
|
12
|
+
embeds the corpus on the request thread.
|
|
13
|
+
|
|
14
|
+
Typical use in a docs app's `package.json`:
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{ "scripts": { "gen": "june gen && kura index", "build": "june build && kura index" } }
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Run `june gen` first (it generates `app/_content.ts`), then `kura index`.
|
|
21
|
+
|
|
22
|
+
## License
|
|
23
|
+
|
|
24
|
+
MIT
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Kura CLI.
|
|
3
|
+
// kura index [--out app/_index.bin] [--model Xenova/bge-m3]
|
|
4
|
+
// Build the search index for the current Kura docs app: embed every doc from the
|
|
5
|
+
// June-frozen app/_content.ts and write a compact index the app loads at runtime.
|
|
6
|
+
import { buildIndex } from "@kurajs/docs/search";
|
|
7
|
+
import { transformers } from "@kurajs/transformers";
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { pathToFileURL } from "node:url";
|
|
11
|
+
function arg(name, def) {
|
|
12
|
+
const i = process.argv.indexOf(`--${name}`);
|
|
13
|
+
return i >= 0 ? process.argv[i + 1] : def;
|
|
14
|
+
}
|
|
15
|
+
async function cmdIndex() {
|
|
16
|
+
const cwd = process.cwd();
|
|
17
|
+
const contentPath = path.join(cwd, "app", "_content.ts");
|
|
18
|
+
if (!fs.existsSync(contentPath)) {
|
|
19
|
+
console.error("kura index: app/_content.ts not found — run `june gen` first (in a Kura docs app).");
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const out = arg("out", path.join("app", "_index.bin"));
|
|
23
|
+
const model = arg("model", "Xenova/bge-m3");
|
|
24
|
+
const mod = (await import(pathToFileURL(contentPath).href));
|
|
25
|
+
const DOCS = mod.DOCS ?? [];
|
|
26
|
+
if (!DOCS.length) {
|
|
27
|
+
console.error("kura index: no docs found in app/_content.ts");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
// Discover locales from content/<col>/<locale>/ subdirs, then collect each locale's actual
|
|
31
|
+
// variants (entry.locale === locale; fallbacks stay in the default set). Both the search
|
|
32
|
+
// index and the MDX precompile cover default + every variant → cross-lingual by construction.
|
|
33
|
+
const LOCALE_DIR = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;
|
|
34
|
+
const contentRoot = path.join(cwd, "content");
|
|
35
|
+
const locales = new Set();
|
|
36
|
+
if (mod.docs && fs.existsSync(contentRoot)) {
|
|
37
|
+
for (const col of fs.readdirSync(contentRoot, { withFileTypes: true })) {
|
|
38
|
+
if (!col.isDirectory())
|
|
39
|
+
continue;
|
|
40
|
+
for (const sub of fs.readdirSync(path.join(contentRoot, col.name), { withFileTypes: true })) {
|
|
41
|
+
if (sub.isDirectory() && LOCALE_DIR.test(sub.name))
|
|
42
|
+
locales.add(sub.name);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const variants = [];
|
|
47
|
+
for (const locale of locales)
|
|
48
|
+
for (const e of mod.docs(locale))
|
|
49
|
+
if (e.locale === locale)
|
|
50
|
+
variants.push(e);
|
|
51
|
+
const allEntries = [...DOCS, ...variants];
|
|
52
|
+
const localeTag = locales.size ? ` (+${variants.length} variants across ${locales.size} locales)` : "";
|
|
53
|
+
console.log(`kura index: embedding ${DOCS.length} docs${localeTag} (model ${model})…`);
|
|
54
|
+
const t0 = Date.now();
|
|
55
|
+
const bytes = await buildIndex({ entries: allEntries, embedder: transformers({ model }) });
|
|
56
|
+
fs.mkdirSync(path.dirname(out), { recursive: true });
|
|
57
|
+
fs.writeFileSync(out, bytes);
|
|
58
|
+
console.log(`kura index: wrote ${out} (${(fs.statSync(out).size / 1024).toFixed(0)}KB) in ${((Date.now() - t0) / 1000).toFixed(1)}s`);
|
|
59
|
+
// Precompile MDX -> static HTML with curated components (build-time; Workers-safe at
|
|
60
|
+
// runtime). Bucketed by locale: "default" for the flat (default-locale) files, plus one
|
|
61
|
+
// bucket per variant locale. The app picks the bucket per entry.
|
|
62
|
+
const { mdxToHtml } = await import("@kurajs/docs/mdx");
|
|
63
|
+
const mdxOut = path.join(cwd, "app", "_mdx.json");
|
|
64
|
+
const map = { default: {} };
|
|
65
|
+
let ok = 0;
|
|
66
|
+
const render = async (bucket, e) => {
|
|
67
|
+
try {
|
|
68
|
+
(map[bucket] ??= {})[e.slug] = await mdxToHtml(e.body);
|
|
69
|
+
ok++;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
/* leave out → the app falls back to the plain markdown html */
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
for (const d of DOCS)
|
|
76
|
+
await render("default", d);
|
|
77
|
+
for (const e of variants)
|
|
78
|
+
await render(e.locale, e);
|
|
79
|
+
fs.writeFileSync(mdxOut, JSON.stringify(map));
|
|
80
|
+
const total = Object.values(map).reduce((n, b) => n + Object.keys(b).length, 0);
|
|
81
|
+
const tag = locales.size ? ` across ${locales.size + 1} locales` : "";
|
|
82
|
+
console.log(`kura index: rendered ${ok}/${total} docs via MDX${tag} -> ${path.relative(cwd, mdxOut)}`);
|
|
83
|
+
}
|
|
84
|
+
const cmd = process.argv[2];
|
|
85
|
+
if (cmd === "index") {
|
|
86
|
+
await cmdIndex();
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.log("Kura CLI\n kura index [--out app/_index.bin] [--model <hf-model>] build the docs search index");
|
|
90
|
+
process.exit(cmd ? 1 : 0);
|
|
91
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kurajs/cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Kura CLI — build the docs search index (kura index).",
|
|
6
|
+
"bin": {
|
|
7
|
+
"kura": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc -p tsconfig.json"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@kurajs/core": "^0.0.1",
|
|
18
|
+
"@kurajs/docs": "^0.0.1",
|
|
19
|
+
"@kurajs/transformers": "^0.0.1"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@huggingface/transformers": ">=3"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@huggingface/transformers": "3.8.1",
|
|
26
|
+
"typescript": "^5.7.0"
|
|
27
|
+
},
|
|
28
|
+
"author": "Yi-Ru Lin",
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://kura.build",
|
|
33
|
+
"keywords": [
|
|
34
|
+
"kura",
|
|
35
|
+
"june",
|
|
36
|
+
"cli",
|
|
37
|
+
"docs",
|
|
38
|
+
"search",
|
|
39
|
+
"index",
|
|
40
|
+
"mcp"
|
|
41
|
+
]
|
|
42
|
+
}
|