mosage 0.2.0 → 0.8.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 +16 -15
- package/bin.js +2 -0
- package/dist/build-C7NW_3Pk.js +14 -0
- package/dist/check-CP4873Wx.js +41 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +228 -0
- package/dist/config-DPm1BBAb.js +2619 -0
- package/dist/config-TlTe7Ona.d.ts +24 -0
- package/dist/context-BqsdSrAQ.js +1084 -0
- package/dist/dev-Biz42qlu.js +17 -0
- package/dist/diagram-xlVDekYk.js +763 -0
- package/dist/export-Bi6nuxjT.js +31 -0
- package/dist/import-D2jNB07F.js +25 -0
- package/dist/index.d.ts +455 -0
- package/dist/index.js +693 -0
- package/dist/{cli.js → init-Bbtj2pxF.js} +34 -68
- package/dist/preview-CLm51aRt.js +19 -0
- package/dist/sdk-DjpX6mCv.js +51 -0
- package/dist/vite/index.d.ts +25 -0
- package/dist/vite/index.js +2 -0
- package/env.d.ts +83 -0
- package/package.json +59 -12
- package/{template/.agents/skills → skills}/create-doc/SKILL.md +1 -1
- package/{template/.agents/skills → skills}/create-theme/SKILL.md +1 -1
- package/{template/.agents/skills → skills}/doc-authoring/SKILL.md +8 -9
- package/{template/.agents/skills → skills}/doc-authoring/references/assets.md +1 -1
- package/{template/.agents/skills → skills}/doc-authoring/references/design-system.md +1 -1
- package/{template/.agents/skills → skills}/doc-authoring/references/long-form.md +4 -4
- package/{template/.agents/skills → skills}/doc-authoring/references/pagination.md +1 -1
- package/src/app/app.tsx +42 -0
- package/src/app/components/data-table.tsx +196 -0
- package/src/app/components/design-panel/design-panel.tsx +318 -0
- package/src/app/components/design-panel/design-provider.tsx +121 -0
- package/src/app/components/design-panel/use-design.ts +85 -0
- package/src/app/components/diagram.tsx +76 -0
- package/src/app/components/doc-assets.tsx +129 -0
- package/src/app/components/doc-search.tsx +248 -0
- package/src/app/components/doc-sidebar.tsx +162 -0
- package/src/app/components/flow-page.tsx +93 -0
- package/src/app/components/footnote.tsx +204 -0
- package/src/app/components/image-placeholder.tsx +50 -0
- package/src/app/components/inspector/inspector.tsx +518 -0
- package/src/app/components/numbering.tsx +224 -0
- package/src/app/components/page-frame.tsx +70 -0
- package/src/app/components/sidebar/folder-item.tsx +212 -0
- package/src/app/components/sidebar/icon-picker.tsx +99 -0
- package/src/app/components/sidebar/sidebar.tsx +252 -0
- package/src/app/components/table-of-contents.tsx +93 -0
- package/src/app/components/theme-toggle.tsx +50 -0
- package/src/app/components/themes/markdown.tsx +249 -0
- package/src/app/components/themes/theme-preview.tsx +74 -0
- package/src/app/components/ui/menu.tsx +143 -0
- package/src/app/index.html +12 -0
- package/src/app/lib/agent-bridge.ts +140 -0
- package/src/app/lib/assets.ts +151 -0
- package/src/app/lib/design-presets.ts +109 -0
- package/src/app/lib/design.ts +88 -0
- package/src/app/lib/diagnostics.ts +282 -0
- package/src/app/lib/doc-preview.tsx +29 -0
- package/src/app/lib/docs.ts +26 -0
- package/src/app/lib/docx/extract.ts +1623 -0
- package/src/app/lib/docx/fonts.test.ts +136 -0
- package/src/app/lib/docx/fonts.ts +166 -0
- package/src/app/lib/docx/media.ts +102 -0
- package/src/app/lib/docx/model.ts +206 -0
- package/src/app/lib/docx/paragraph.test.ts +92 -0
- package/src/app/lib/docx/paragraph.ts +107 -0
- package/src/app/lib/docx/props.ts +187 -0
- package/src/app/lib/docx/styles.ts +306 -0
- package/src/app/lib/docx/units.ts +35 -0
- package/src/app/lib/docx/write.test.ts +507 -0
- package/src/app/lib/docx/write.ts +581 -0
- package/src/app/lib/docx/xml.ts +39 -0
- package/src/app/lib/export-docx.ts +289 -0
- package/src/app/lib/export-dom.ts +318 -0
- package/src/app/lib/export-html.ts +156 -0
- package/src/app/lib/export-image.ts +70 -0
- package/src/app/lib/export-pdf.ts +165 -0
- package/src/app/lib/flow-measure.test.ts +31 -0
- package/src/app/lib/flow-measure.ts +183 -0
- package/src/app/lib/flow.test.ts +110 -0
- package/src/app/lib/flow.ts +136 -0
- package/src/app/lib/folders.ts +192 -0
- package/src/app/lib/footnotes.test.tsx +102 -0
- package/src/app/lib/footnotes.ts +94 -0
- package/src/app/lib/inspector/fiber.ts +99 -0
- package/src/app/lib/labels.test.ts +18 -0
- package/src/app/lib/labels.ts +181 -0
- package/src/app/lib/outline.ts +118 -0
- package/src/app/lib/page-context.tsx +43 -0
- package/src/app/lib/page-range.test.ts +95 -0
- package/src/app/lib/page-range.ts +90 -0
- package/src/app/lib/print-ready.ts +69 -0
- package/src/app/lib/rasterize.ts +173 -0
- package/src/app/lib/scan.ts +26 -0
- package/src/app/lib/sdk.test.ts +32 -0
- package/src/app/lib/sdk.ts +115 -0
- package/src/app/lib/themes.ts +31 -0
- package/src/app/lib/use-doc-module.ts +53 -0
- package/src/app/lib/use-doc-pages.ts +147 -0
- package/src/app/lib/utils.ts +6 -0
- package/src/app/lib/view-mode.test.ts +91 -0
- package/src/app/lib/view-mode.ts +104 -0
- package/src/app/main.tsx +14 -0
- package/src/app/routes/assets.tsx +257 -0
- package/src/app/routes/doc.tsx +877 -0
- package/src/app/routes/home-shell.tsx +203 -0
- package/src/app/routes/home.tsx +269 -0
- package/src/app/routes/themes.tsx +121 -0
- package/src/app/styles.css +97 -0
- package/src/app/virtual.d.ts +30 -0
- package/template/AGENTS.md +1 -1
- package/template/README.md +24 -52
- package/template/docs/getting-started/index.tsx +2 -2
- package/template/mosage.config.ts +1 -1
- package/template/package.json +1 -1
- package/template/tsconfig.json +1 -1
- package/README.zh-TW.md +0 -28
- /package/{template/.agents/skills → skills}/apply-comments/SKILL.md +0 -0
- /package/{template/.agents/skills → skills}/current-doc/SKILL.md +0 -0
- /package/{template/.agents/skills → skills}/doc-authoring/references/tables-and-charts.md +0 -0
package/README.md
CHANGED
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
# mosage
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Scaffold an [MoSage](https://github.com/nickchen1998/MoSage) workspace — documents as React, one component per printed page.
|
|
3
|
+
讓 AI coding agent 幫你做出要印出來、要交出去的文件:報告、企劃書、白皮書、手冊。
|
|
4
|
+
Agent 把內容寫成頁面,MoSage 負責紙張尺寸、分頁、目錄與頁碼,並匯出 PDF、可編輯的 Word 或 HTML。
|
|
6
5
|
|
|
7
6
|
```bash
|
|
8
7
|
npx mosage init my-docs
|
|
9
8
|
cd my-docs
|
|
10
|
-
|
|
9
|
+
npm run dev # http://localhost:5273
|
|
11
10
|
```
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
接著在同一個資料夾開啟 Claude Code 或 Codex,描述你要的文件即可。
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
## 這個套件包含
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
- **CLI**:`mosage init`(建立專案)、`dev`、`check`(版面檢查)、`export`(PDF/Word/HTML/PNG)、`import`(Markdown 轉文件)、`build`、`preview`、`sync:skills`
|
|
17
|
+
- **檢視器**:真實尺寸的頁面、縮圖與大綱、單頁/雙頁/格狀檢視、Inspect(直接改字或留言給 AI)、Design 面板
|
|
18
|
+
- **文件元件**:`flow()` 自動分頁、`TableOfContents`、`Footnote`、`Figure`/`Ref` 編號與交互參照、`DataTable`(讀 CSV)、頁碼 hooks
|
|
19
|
+
- **AI skills**:`create-doc`、`doc-authoring`、`current-doc`、`apply-comments`、`create-theme`
|
|
18
20
|
|
|
21
|
+
`mosage check` 與 `mosage export` 會用無頭 Chromium 渲染,第一次使用前請安裝 Playwright:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm i -D playwright && npx playwright install chromium
|
|
19
25
|
```
|
|
20
|
-
mosage init [dir]
|
|
21
|
-
-f, --force overwrite a non-empty target directory
|
|
22
|
-
-n, --name <name> package name (defaults to the folder name)
|
|
23
|
-
--use-pnpm (or --use-npm / --use-yarn / --use-bun)
|
|
24
|
-
--no-install skip dependency installation
|
|
25
|
-
--no-git skip git init and the initial commit
|
|
26
|
-
```
|
|
27
26
|
|
|
28
|
-
|
|
27
|
+
完整說明與範例:<https://github.com/nickchen1998/MoSage>
|
|
28
|
+
|
|
29
|
+
MoSage 以 [open-doc](https://github.com/simonliu-ai-product/open-doc)(Simon Liu,MIT)為基礎開發。授權:MIT。
|
package/bin.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { t as createViteConfig } from "./config-DPm1BBAb.js";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { build as build$1, mergeConfig } from "vite";
|
|
4
|
+
//#region src/cli/build.ts
|
|
5
|
+
async function build(opts = {}) {
|
|
6
|
+
const base = await createViteConfig({
|
|
7
|
+
userCwd: process.cwd(),
|
|
8
|
+
mode: "build"
|
|
9
|
+
});
|
|
10
|
+
const config = mergeConfig(base, { build: { ...opts.outDir !== void 0 ? { outDir: path.resolve(process.cwd(), opts.outDir) } : {} } });
|
|
11
|
+
await build$1(config);
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { build };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { i as listDocIds } from "./config-DPm1BBAb.js";
|
|
2
|
+
import { n as checkLayout, r as closeRenderSession, t as cliContext } from "./context-BqsdSrAQ.js";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
//#region src/cli/check.ts
|
|
5
|
+
function line(finding) {
|
|
6
|
+
const where = finding.page > 0 ? `p.${finding.page}` : "doc";
|
|
7
|
+
const mark = finding.severity === "error" ? chalk.red("✗") : chalk.yellow("!");
|
|
8
|
+
const detail = [finding.element, finding.loc && chalk.dim(`@ ${finding.loc}`)].filter(Boolean).join(" ");
|
|
9
|
+
return ` ${mark} ${chalk.dim(where.padEnd(5))} ${finding.message}${detail ? `\n ${chalk.dim(detail)}` : ""}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Renders every sheet at true page size and reports the layout faults an agent
|
|
13
|
+
* writing React cannot see: content clipped by the page edge, an empty sheet, a
|
|
14
|
+
* heading stranded at the foot of a page, type too small to print.
|
|
15
|
+
*
|
|
16
|
+
* Exits non-zero when anything is an error, so it works as a CI gate.
|
|
17
|
+
*/
|
|
18
|
+
async function checkDocs(docIds, opts = {}) {
|
|
19
|
+
const ctx = await cliContext();
|
|
20
|
+
const targets = docIds.length > 0 ? docIds : await listDocIds(ctx);
|
|
21
|
+
if (targets.length === 0) throw new Error("No documents found under docs/.");
|
|
22
|
+
let errors = 0;
|
|
23
|
+
const reports = [];
|
|
24
|
+
try {
|
|
25
|
+
for (const docId of targets) {
|
|
26
|
+
const report = await checkLayout(ctx, docId);
|
|
27
|
+
reports.push(report);
|
|
28
|
+
errors += report.errors;
|
|
29
|
+
if (opts.json) continue;
|
|
30
|
+
const summary = report.errors === 0 && report.warnings === 0 ? chalk.green("clean") : [report.errors > 0 ? chalk.red(`${report.errors} error(s)`) : "", report.warnings > 0 ? chalk.yellow(`${report.warnings} warning(s)`) : ""].filter(Boolean).join(", ");
|
|
31
|
+
process.stdout.write(`${chalk.bold(docId)} ${chalk.dim(`${report.pageCount} pages`)} — ${summary}\n`);
|
|
32
|
+
for (const finding of report.findings) process.stdout.write(`${line(finding)}\n`);
|
|
33
|
+
}
|
|
34
|
+
} finally {
|
|
35
|
+
await closeRenderSession();
|
|
36
|
+
}
|
|
37
|
+
if (opts.json) process.stdout.write(`${JSON.stringify(reports, null, 2)}\n`);
|
|
38
|
+
if (errors > 0) process.exitCode = 1;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { checkDocs };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/dist/cli/bin.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { a as PAGE_SIZE_NAMES, r as ORIENTATIONS } from "../sdk-DjpX6mCv.js";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import * as readline from "node:readline/promises";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { Command, Option } from "commander";
|
|
8
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import fs, { readFile } from "node:fs/promises";
|
|
10
|
+
//#region \0rolldown/runtime.js
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __exportAll = (all, no_symbols) => {
|
|
13
|
+
let target = {};
|
|
14
|
+
for (var name in all) __defProp(target, name, {
|
|
15
|
+
get: all[name],
|
|
16
|
+
enumerable: true
|
|
17
|
+
});
|
|
18
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
19
|
+
return target;
|
|
20
|
+
};
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/ops/formats.ts
|
|
23
|
+
/** Kept apart from `layout.ts`, so the CLI can list the choices without loading the renderer. */
|
|
24
|
+
const EXPORT_FORMATS = [
|
|
25
|
+
"pdf",
|
|
26
|
+
"html",
|
|
27
|
+
"docx",
|
|
28
|
+
"png"
|
|
29
|
+
];
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/cli/package-version.ts
|
|
32
|
+
const PACKAGE_NAME = "mosage";
|
|
33
|
+
/**
|
|
34
|
+
* This package's root folder (the one holding its own `package.json`, the
|
|
35
|
+
* `template/` and `skills/`). Walks up instead of assuming a fixed depth: the
|
|
36
|
+
* bundler decides which chunk a module lands in, so `../../` is right from
|
|
37
|
+
* `dist/cli/` and wrong from `dist/`.
|
|
38
|
+
*/
|
|
39
|
+
function packageRoot() {
|
|
40
|
+
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
41
|
+
for (let up = 0; up < 6; up += 1) {
|
|
42
|
+
const file = path.join(dir, "package.json");
|
|
43
|
+
if (existsSync(file)) try {
|
|
44
|
+
if (JSON.parse(readFileSync(file, "utf8")).name === PACKAGE_NAME) return dir;
|
|
45
|
+
} catch {}
|
|
46
|
+
const parent = path.dirname(dir);
|
|
47
|
+
if (parent === dir) break;
|
|
48
|
+
dir = parent;
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
/** Getting the root wrong is silent — it reports `0.0.0` rather than failing. */
|
|
53
|
+
async function readCoreVersion() {
|
|
54
|
+
const root = packageRoot();
|
|
55
|
+
if (!root) return "0.0.0";
|
|
56
|
+
try {
|
|
57
|
+
return JSON.parse(await readFile(path.join(root, "package.json"), "utf8")).version ?? "0.0.0";
|
|
58
|
+
} catch {
|
|
59
|
+
return "0.0.0";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/cli/sync.ts
|
|
64
|
+
var sync_exports = /* @__PURE__ */ __exportAll({
|
|
65
|
+
detectSkillsDrift: () => detectSkillsDrift,
|
|
66
|
+
syncSkills: () => syncSkills
|
|
67
|
+
});
|
|
68
|
+
const SKILL_TARGET_DIRS = [".agents/skills", ".claude/skills"];
|
|
69
|
+
async function listFiles(dir) {
|
|
70
|
+
const out = [];
|
|
71
|
+
const walk = async (current) => {
|
|
72
|
+
const entries = await fs.readdir(current, { withFileTypes: true });
|
|
73
|
+
for (const entry of entries) {
|
|
74
|
+
const abs = path.join(current, entry.name);
|
|
75
|
+
if (entry.isDirectory()) await walk(abs);
|
|
76
|
+
else out.push(path.relative(dir, abs));
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
await walk(dir);
|
|
80
|
+
return out.sort();
|
|
81
|
+
}
|
|
82
|
+
async function sameTree(src, dst) {
|
|
83
|
+
if (!existsSync(dst)) return false;
|
|
84
|
+
const [srcFiles, dstFiles] = await Promise.all([listFiles(src), listFiles(dst)]);
|
|
85
|
+
if (srcFiles.length !== dstFiles.length) return false;
|
|
86
|
+
if (srcFiles.some((f, i) => f !== dstFiles[i])) return false;
|
|
87
|
+
for (const rel of srcFiles) {
|
|
88
|
+
const [a, b] = await Promise.all([fs.readFile(path.join(src, rel), "utf8"), fs.readFile(path.join(dst, rel), "utf8")]);
|
|
89
|
+
if (a !== b) return false;
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
async function skillNames(builtinDir) {
|
|
94
|
+
if (!existsSync(builtinDir)) return [];
|
|
95
|
+
return (await fs.readdir(builtinDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
96
|
+
}
|
|
97
|
+
async function detectSkillsDrift(builtinDir, userCwd = process.cwd()) {
|
|
98
|
+
const names = await skillNames(builtinDir);
|
|
99
|
+
const primaryTarget = path.join(userCwd, SKILL_TARGET_DIRS[0]);
|
|
100
|
+
const drift = [];
|
|
101
|
+
for (const name of names) {
|
|
102
|
+
const src = path.join(builtinDir, name);
|
|
103
|
+
const dst = path.join(primaryTarget, name);
|
|
104
|
+
if (!existsSync(dst)) drift.push({
|
|
105
|
+
name,
|
|
106
|
+
status: "added"
|
|
107
|
+
});
|
|
108
|
+
else if (!await sameTree(src, dst)) drift.push({
|
|
109
|
+
name,
|
|
110
|
+
status: "updated"
|
|
111
|
+
});
|
|
112
|
+
else drift.push({
|
|
113
|
+
name,
|
|
114
|
+
status: "unchanged"
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return drift;
|
|
118
|
+
}
|
|
119
|
+
async function syncSkills(builtinDir, opts = {}, userCwd = process.cwd()) {
|
|
120
|
+
const stale = (await detectSkillsDrift(builtinDir, userCwd)).filter((d) => d.status !== "unchanged");
|
|
121
|
+
if (stale.length === 0) {
|
|
122
|
+
if (!opts.quiet) process.stdout.write(`${chalk.green("✔")} Skills already up to date.\n`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
for (const { name, status } of stale) {
|
|
126
|
+
if (opts.dryRun) {
|
|
127
|
+
process.stdout.write(`${chalk.yellow("~")} ${name} ${chalk.dim(`(${status})`)}\n`);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
for (const targetDir of SKILL_TARGET_DIRS) {
|
|
131
|
+
const dst = path.join(userCwd, targetDir, name);
|
|
132
|
+
await fs.rm(dst, {
|
|
133
|
+
recursive: true,
|
|
134
|
+
force: true
|
|
135
|
+
});
|
|
136
|
+
await fs.mkdir(path.dirname(dst), { recursive: true });
|
|
137
|
+
await fs.cp(path.join(builtinDir, name), dst, { recursive: true });
|
|
138
|
+
}
|
|
139
|
+
if (!opts.quiet) process.stdout.write(`${chalk.green("✔")} ${name} ${chalk.dim(`(${status})`)}\n`);
|
|
140
|
+
}
|
|
141
|
+
if (opts.dryRun) process.stdout.write(chalk.dim("\nDry run — nothing written.\n"));
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
//#region src/cli/run.ts
|
|
145
|
+
function parsePort(value) {
|
|
146
|
+
const n = Number(value);
|
|
147
|
+
if (!Number.isInteger(n) || n < 0 || n > 65535) throw new Error(`Invalid port: ${value}`);
|
|
148
|
+
return n;
|
|
149
|
+
}
|
|
150
|
+
function resolveBuiltinSkillsDir() {
|
|
151
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
152
|
+
return path.resolve(here, "..", "..", "skills");
|
|
153
|
+
}
|
|
154
|
+
async function runSkillsDriftCheck(skillsDir) {
|
|
155
|
+
if (process.env.OPEN_DOC_SKIP_SKILLS_CHECK === "1") return;
|
|
156
|
+
let drift;
|
|
157
|
+
try {
|
|
158
|
+
drift = await detectSkillsDrift(skillsDir);
|
|
159
|
+
} catch {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const stale = drift.filter((d) => d.status !== "unchanged");
|
|
163
|
+
if (stale.length === 0) return;
|
|
164
|
+
const names = stale.map((d) => d.name).join(", ");
|
|
165
|
+
if (!Boolean(process.stdin.isTTY && process.stdout.isTTY)) {
|
|
166
|
+
process.stderr.write(`${chalk.yellow("!")} Skills out of date (${names}). Run \`mosage sync:skills\` to update.\n`);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const rl = readline.createInterface({
|
|
170
|
+
input: process.stdin,
|
|
171
|
+
output: process.stdout
|
|
172
|
+
});
|
|
173
|
+
try {
|
|
174
|
+
const answer = (await rl.question(`${chalk.yellow("!")} Skills out of date: ${chalk.bold(names)}. Sync now? ${chalk.dim("(Y/n) ")}`)).trim().toLowerCase();
|
|
175
|
+
if (answer === "" || answer === "y" || answer === "yes") await syncSkills(skillsDir);
|
|
176
|
+
else process.stdout.write(chalk.dim("Skipped. Run `mosage sync:skills` later to update.\n"));
|
|
177
|
+
} finally {
|
|
178
|
+
rl.close();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
async function run(argv) {
|
|
182
|
+
const version = await readCoreVersion();
|
|
183
|
+
const program = new Command();
|
|
184
|
+
program.name("mosage").description("Author documents — we handle the Vite/React stack, pagination, and export.").version(version, "-v, --version", "print version").helpOption("-h, --help", "show help").showHelpAfterError(chalk.dim("(run `mosage --help` for usage)"));
|
|
185
|
+
program.command("init").description("Create a new MoSage workspace").argument("[dir]", "target directory", void 0).option("-f, --force", "overwrite non-empty target directory", false).option("-n, --name <name>", "override package name (defaults to folder name)").option("--use-npm", "use npm to install dependencies").option("--use-pnpm", "use pnpm to install dependencies").option("--use-yarn", "use yarn to install dependencies").option("--use-bun", "use bun to install dependencies").option("--no-install", "skip dependency installation").option("--no-git", "skip git init and initial commit").action(async (dir, flags) => {
|
|
186
|
+
const { runInit } = await import("../init-Bbtj2pxF.js");
|
|
187
|
+
await runInit(dir, flags);
|
|
188
|
+
});
|
|
189
|
+
program.command("dev").description("Start the dev server").addOption(new Option("-p, --port <port>", "port to listen on").argParser(parsePort)).addOption(new Option("--host [host]", "expose on the network (optional host)")).option("--open", "open the browser on start").option("--no-skills-check", "skip the built-in skills drift check").action(async (flags) => {
|
|
190
|
+
if (flags.skillsCheck !== false) await runSkillsDriftCheck(resolveBuiltinSkillsDir());
|
|
191
|
+
const { dev } = await import("../dev-Biz42qlu.js");
|
|
192
|
+
await dev(flags);
|
|
193
|
+
});
|
|
194
|
+
program.command("build").description("Build a static site").option("--out-dir <dir>", "output directory (defaults to `dist`)").action(async (flags) => {
|
|
195
|
+
const { build } = await import("../build-C7NW_3Pk.js");
|
|
196
|
+
await build(flags);
|
|
197
|
+
});
|
|
198
|
+
program.command("preview").description("Preview the production build").addOption(new Option("-p, --port <port>", "port to listen on").argParser(parsePort)).addOption(new Option("--host [host]", "expose on the network (optional host)")).option("--open", "open the browser on start").action(async (flags) => {
|
|
199
|
+
const { preview } = await import("../preview-CLm51aRt.js");
|
|
200
|
+
await preview(flags);
|
|
201
|
+
});
|
|
202
|
+
program.command("export [docIds...]").description("Render documents headlessly to PDF, HTML, DOCX, or PNG").addOption(new Option("-f, --format <format>", "output format").choices(EXPORT_FORMATS)).option("-o, --out-dir <dir>", "directory to write into (defaults to `out`)").option("--all", "export every document under docs/").action(async (docIds, flags) => {
|
|
203
|
+
const { exportDocs } = await import("../export-Bi6nuxjT.js");
|
|
204
|
+
await exportDocs(docIds, flags);
|
|
205
|
+
});
|
|
206
|
+
program.command("check [docIds...]").description("Report layout faults — clipped content, blank sheets, stranded headings").option("--json", "print the full report as JSON").action(async (docIds, flags) => {
|
|
207
|
+
const { checkDocs } = await import("../check-CP4873Wx.js");
|
|
208
|
+
await checkDocs(docIds, flags);
|
|
209
|
+
});
|
|
210
|
+
program.command("import <file>").description("Turn a Markdown file into a document under docs/").option("--id <id>", "document id (defaults to a slug of the title)").option("--title <title>", "override the title").option("--subtitle <subtitle>", "subtitle, also used as the cover eyebrow").option("--author <author>", "author line on the cover").option("--theme <theme>", "theme id to back-link from meta.theme").addOption(new Option("--page-size <size>", "page size").choices(PAGE_SIZE_NAMES)).addOption(new Option("--orientation <orientation>", "page orientation").choices(ORIENTATIONS)).option("--no-cover", "skip the title page").option("--contents", "add a self-filling contents page").action(async (file, flags) => {
|
|
211
|
+
const { importDoc } = await import("../import-D2jNB07F.js");
|
|
212
|
+
await importDoc(file, flags);
|
|
213
|
+
});
|
|
214
|
+
program.command("sync:skills").description("Sync built-in skills from mosage into this workspace").option("--dry-run", "show what would change without writing").action(async (flags) => {
|
|
215
|
+
const { syncSkills } = await Promise.resolve().then(() => sync_exports);
|
|
216
|
+
await syncSkills(resolveBuiltinSkillsDir(), flags);
|
|
217
|
+
});
|
|
218
|
+
await program.parseAsync(argv, { from: "user" });
|
|
219
|
+
}
|
|
220
|
+
//#endregion
|
|
221
|
+
//#region src/cli/bin.ts
|
|
222
|
+
run(process.argv.slice(2)).catch((err) => {
|
|
223
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
224
|
+
process.stderr.write(`${chalk.red("error:")} ${message}\n`);
|
|
225
|
+
process.exit(1);
|
|
226
|
+
});
|
|
227
|
+
//#endregion
|
|
228
|
+
export { EXPORT_FORMATS as i, packageRoot as n, readCoreVersion as r, syncSkills as t };
|