czon 0.7.6 → 0.7.8

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/dist/cli.js CHANGED
@@ -1,197 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
- if (k2 === undefined) k2 = k;
5
- var desc = Object.getOwnPropertyDescriptor(m, k);
6
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
- desc = { enumerable: true, get: function() { return m[k]; } };
8
- }
9
- Object.defineProperty(o, k2, desc);
10
- }) : (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- o[k2] = m[k];
13
- }));
14
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
- Object.defineProperty(o, "default", { enumerable: true, value: v });
16
- }) : function(o, v) {
17
- o["default"] = v;
18
- });
19
- var __importStar = (this && this.__importStar) || (function () {
20
- var ownKeys = function(o) {
21
- ownKeys = Object.getOwnPropertyNames || function (o) {
22
- var ar = [];
23
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
- return ar;
25
- };
26
- return ownKeys(o);
27
- };
28
- return function (mod) {
29
- if (mod && mod.__esModule) return mod;
30
- var result = {};
31
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
- __setModuleDefault(result, mod);
33
- return result;
34
- };
35
- })();
36
3
  Object.defineProperty(exports, "__esModule", { value: true });
37
4
  const clipanion_1 = require("clipanion");
38
5
  const dotenv_1 = require("dotenv");
39
- const fs = __importStar(require("fs/promises"));
40
- const path = __importStar(require("path"));
41
- const pipeline_1 = require("./build/pipeline");
42
- const findEntries_1 = require("./findEntries");
43
- const summary_1 = require("./process/summary");
44
- const writeFile_1 = require("./utils/writeFile");
6
+ const commands_1 = require("./commands");
45
7
  const version_1 = require("./version");
46
8
  // 加载 .env 文件中的环境变量
47
9
  (0, dotenv_1.config)();
48
- // LsFiles 命令
49
- class LsFilesCommand extends clipanion_1.Command {
50
- async execute() {
51
- try {
52
- const files = await (0, findEntries_1.findMarkdownEntries)(process.cwd());
53
- if (files.length === 0) {
54
- this.context.stdout.write('No markdown files found.\n');
55
- }
56
- else {
57
- files.forEach(file => {
58
- this.context.stdout.write(`${file}\n`);
59
- });
60
- }
61
- return 0;
62
- }
63
- catch (error) {
64
- this.context.stderr.write(`❌ Failed to list files: ${error}\n`);
65
- return 1;
66
- }
67
- }
68
- }
69
- LsFilesCommand.paths = [['ls-files']];
70
- LsFilesCommand.usage = clipanion_1.Command.Usage({
71
- description: 'List all markdown files in the current directory',
72
- details: `
73
- This command lists all markdown files in the current directory using git.
74
- It uses the same logic as the internal findMarkdownEntries function.
75
-
76
- Examples:
77
- $ czon ls-files
78
- `,
79
- });
80
- // Summary 命令
81
- class SummaryCommand extends clipanion_1.Command {
82
- constructor() {
83
- super(...arguments);
84
- this.model = clipanion_1.Option.String('--model', 'opencode/big-pickle', {
85
- description: 'OpenCode model to use for summarization',
86
- });
87
- }
88
- async execute() {
89
- try {
90
- await (0, summary_1.processSummary)(this.model);
91
- return 0;
92
- }
93
- catch (error) {
94
- this.context.stderr.write(`❌ Summary generation failed: ${error}\n`);
95
- return 1;
96
- }
97
- }
98
- }
99
- SummaryCommand.paths = [['summary']];
100
- SummaryCommand.usage = clipanion_1.Command.Usage({
101
- description: 'Generate comprehensive multi-style summaries of all markdown files',
102
- details: `
103
- This command generates 10 different styles of AI-powered summaries for all markdown files
104
- in the current repository. The summaries are saved to the SUMMARY directory.
105
-
106
- Generated summary styles include:
107
- - Objective analysis
108
- - Critical perspective
109
- - Positive encouragement
110
- - Popular science explanation
111
- - Artistic interpretation
112
- - Philosophical analysis
113
- - Psychological analysis (MBTI)
114
- - Historical timeline
115
- - Community discussion
116
- - Structured debate
117
-
118
- Examples:
119
- $ czon summary
120
- $ czon summary --model opencode/gpt-4o
121
- `,
122
- });
123
- // ConfigGithub 命令
124
- class ConfigGithubCommand extends clipanion_1.Command {
125
- async execute() {
126
- try {
127
- const targetDir = process.cwd();
128
- const templatePath = path.join(__dirname, '..', 'templates', 'pages.yml');
129
- const targetPath = path.join(targetDir, '.github', 'workflows', 'pages.yml');
130
- // 检查模板文件是否存在
131
- try {
132
- await fs.access(templatePath);
133
- }
134
- catch {
135
- this.context.stderr.write(`❌ Template file not found: ${templatePath}\n`);
136
- return 1;
137
- }
138
- // 读取模板文件
139
- const content = await fs.readFile(templatePath, 'utf-8');
140
- // 确保目标目录存在并写入文件
141
- await (0, writeFile_1.writeFile)(targetPath, content);
142
- this.context.stdout.write(`✅ GitHub Actions workflow copied to ${targetPath}\n`);
143
- return 0;
144
- }
145
- catch (error) {
146
- this.context.stderr.write(`❌ Failed to copy workflow template: ${error}\n`);
147
- return 1;
148
- }
149
- }
150
- }
151
- ConfigGithubCommand.paths = [['config', 'github']];
152
- ConfigGithubCommand.usage = clipanion_1.Command.Usage({
153
- description: 'Copy GitHub Pages deployment workflow template to .github/workflows/pages.yml',
154
- details: `
155
- This command copies the GitHub Pages deployment workflow template (templates/pages.yml)
156
- to the current directory's .github/workflows/pages.yml location.
157
-
158
- Examples:
159
- $ czon config github
160
- `,
161
- });
162
- // Build 命令
163
- class BuildCommand extends clipanion_1.Command {
164
- constructor() {
165
- super(...arguments);
166
- this.lang = clipanion_1.Option.Array('--lang', {
167
- description: 'Target languages for translation (e.g., en-US, ja-JP)',
168
- });
169
- }
170
- async execute() {
171
- try {
172
- await (0, pipeline_1.buildSite)({
173
- langs: this.lang,
174
- });
175
- return 0;
176
- }
177
- catch (error) {
178
- this.context.stderr.write(`❌ Build failed: ${error}\n`);
179
- return 1;
180
- }
181
- }
182
- }
183
- BuildCommand.paths = [['build']];
184
- BuildCommand.usage = clipanion_1.Command.Usage({
185
- description: 'Build documentation site from Markdown files in current directory',
186
- details: `
187
- This command builds a documentation site from Markdown files in the current directory.
188
- The output will be placed in the .czon/dist directory.
189
-
190
- Examples:
191
- $ czon build
192
- $ czon build --lang en-US --lang ja-JP (translate to English and Japanese)
193
- `,
194
- });
195
10
  // 创建 CLI 应用
196
11
  const cli = new clipanion_1.Cli({
197
12
  binaryName: 'czon',
@@ -199,10 +14,10 @@ const cli = new clipanion_1.Cli({
199
14
  binaryVersion: version_1.CZON_VERSION,
200
15
  });
201
16
  // 注册命令
202
- cli.register(BuildCommand);
203
- cli.register(LsFilesCommand);
204
- cli.register(SummaryCommand);
205
- cli.register(ConfigGithubCommand);
17
+ cli.register(commands_1.BuildCommand);
18
+ cli.register(commands_1.LsFilesCommand);
19
+ cli.register(commands_1.SummaryCommand);
20
+ cli.register(commands_1.ConfigGithubCommand);
206
21
  // 运行 CLI
207
22
  cli.runExit(process.argv.slice(2), {
208
23
  ...clipanion_1.Cli.defaultContext,
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BuildCommand = void 0;
4
+ const clipanion_1 = require("clipanion");
5
+ const pipeline_1 = require("../build/pipeline");
6
+ class BuildCommand extends clipanion_1.Command {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.lang = clipanion_1.Option.Array('--lang', {
10
+ description: 'Target languages for translation (e.g., en-US, ja-JP)',
11
+ });
12
+ }
13
+ async execute() {
14
+ try {
15
+ await (0, pipeline_1.buildSite)({
16
+ langs: this.lang,
17
+ });
18
+ return 0;
19
+ }
20
+ catch (error) {
21
+ this.context.stderr.write(`Build failed: ${error}\n`);
22
+ return 1;
23
+ }
24
+ }
25
+ }
26
+ exports.BuildCommand = BuildCommand;
27
+ BuildCommand.paths = [['build']];
28
+ BuildCommand.usage = clipanion_1.Command.Usage({
29
+ description: 'Build documentation site from Markdown files in current directory',
30
+ details: `
31
+ This command builds a documentation site from Markdown files in the current directory.
32
+ The output will be placed in the .czon/dist directory.
33
+
34
+ Examples:
35
+ $ czon build
36
+ $ czon build --lang en-US --lang ja-JP (translate to English and Japanese)
37
+ `,
38
+ });
39
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ConfigGithubCommand = void 0;
37
+ const clipanion_1 = require("clipanion");
38
+ const fs = __importStar(require("fs/promises"));
39
+ const path = __importStar(require("path"));
40
+ const writeFile_1 = require("../utils/writeFile");
41
+ class ConfigGithubCommand extends clipanion_1.Command {
42
+ async execute() {
43
+ try {
44
+ const targetDir = process.cwd();
45
+ const templatePath = path.join(__dirname, '..', '..', 'templates', 'pages.yml');
46
+ const targetPath = path.join(targetDir, '.github', 'workflows', 'pages.yml');
47
+ // 检查模板文件是否存在
48
+ try {
49
+ await fs.access(templatePath);
50
+ }
51
+ catch {
52
+ this.context.stderr.write(`Template file not found: ${templatePath}\n`);
53
+ return 1;
54
+ }
55
+ // 读取模板文件
56
+ const content = await fs.readFile(templatePath, 'utf-8');
57
+ // 确保目标目录存在并写入文件
58
+ await (0, writeFile_1.writeFile)(targetPath, content);
59
+ this.context.stdout.write(`GitHub Actions workflow copied to ${targetPath}\n`);
60
+ return 0;
61
+ }
62
+ catch (error) {
63
+ this.context.stderr.write(`Failed to copy workflow template: ${error}\n`);
64
+ return 1;
65
+ }
66
+ }
67
+ }
68
+ exports.ConfigGithubCommand = ConfigGithubCommand;
69
+ ConfigGithubCommand.paths = [['config', 'github']];
70
+ ConfigGithubCommand.usage = clipanion_1.Command.Usage({
71
+ description: 'Copy GitHub Pages deployment workflow template to .github/workflows/pages.yml',
72
+ details: `
73
+ This command copies the GitHub Pages deployment workflow template (templates/pages.yml)
74
+ to the current directory's .github/workflows/pages.yml location.
75
+
76
+ Examples:
77
+ $ czon config github
78
+ `,
79
+ });
80
+ //# sourceMappingURL=config-github.js.map
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SummaryCommand = exports.LsFilesCommand = exports.ConfigGithubCommand = exports.BuildCommand = void 0;
4
+ var build_1 = require("./build");
5
+ Object.defineProperty(exports, "BuildCommand", { enumerable: true, get: function () { return build_1.BuildCommand; } });
6
+ var config_github_1 = require("./config-github");
7
+ Object.defineProperty(exports, "ConfigGithubCommand", { enumerable: true, get: function () { return config_github_1.ConfigGithubCommand; } });
8
+ var ls_files_1 = require("./ls-files");
9
+ Object.defineProperty(exports, "LsFilesCommand", { enumerable: true, get: function () { return ls_files_1.LsFilesCommand; } });
10
+ var summary_1 = require("./summary");
11
+ Object.defineProperty(exports, "SummaryCommand", { enumerable: true, get: function () { return summary_1.SummaryCommand; } });
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LsFilesCommand = void 0;
4
+ const clipanion_1 = require("clipanion");
5
+ const findEntries_1 = require("../findEntries");
6
+ class LsFilesCommand extends clipanion_1.Command {
7
+ async execute() {
8
+ try {
9
+ const files = await (0, findEntries_1.findMarkdownEntries)(process.cwd());
10
+ if (files.length === 0) {
11
+ this.context.stdout.write('No markdown files found.\n');
12
+ }
13
+ else {
14
+ files.forEach(file => {
15
+ this.context.stdout.write(`${file}\n`);
16
+ });
17
+ }
18
+ return 0;
19
+ }
20
+ catch (error) {
21
+ this.context.stderr.write(`Failed to list files: ${error}\n`);
22
+ return 1;
23
+ }
24
+ }
25
+ }
26
+ exports.LsFilesCommand = LsFilesCommand;
27
+ LsFilesCommand.paths = [['ls-files']];
28
+ LsFilesCommand.usage = clipanion_1.Command.Usage({
29
+ description: 'List all markdown files in the current directory',
30
+ details: `
31
+ This command lists all markdown files in the current directory using git.
32
+ It uses the same logic as the internal findMarkdownEntries function.
33
+
34
+ Examples:
35
+ $ czon ls-files
36
+ `,
37
+ });
38
+ //# sourceMappingURL=ls-files.js.map
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SummaryCommand = void 0;
4
+ const clipanion_1 = require("clipanion");
5
+ const summary_1 = require("../process/summary");
6
+ class SummaryCommand extends clipanion_1.Command {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.model = clipanion_1.Option.String('--model', 'opencode/big-pickle', {
10
+ description: 'OpenCode model to use for summarization',
11
+ });
12
+ }
13
+ async execute() {
14
+ try {
15
+ await (0, summary_1.processSummary)(this.model);
16
+ return 0;
17
+ }
18
+ catch (error) {
19
+ this.context.stderr.write(`Summary generation failed: ${error}\n`);
20
+ return 1;
21
+ }
22
+ }
23
+ }
24
+ exports.SummaryCommand = SummaryCommand;
25
+ SummaryCommand.paths = [['summary']];
26
+ SummaryCommand.usage = clipanion_1.Command.Usage({
27
+ description: 'Generate comprehensive multi-style summaries of all markdown files',
28
+ details: `
29
+ This command generates 10 different styles of AI-powered summaries for all markdown files
30
+ in the current repository. The summaries are saved to the SUMMARY directory.
31
+
32
+ Generated summary styles include:
33
+ - Objective analysis
34
+ - Critical perspective
35
+ - Positive encouragement
36
+ - Popular science explanation
37
+ - Artistic interpretation
38
+ - Philosophical analysis
39
+ - Psychological analysis (MBTI)
40
+ - Historical timeline
41
+ - Community discussion
42
+ - Structured debate
43
+
44
+ Examples:
45
+ $ czon summary
46
+ $ czon summary --model opencode/gpt-4o
47
+ `,
48
+ });
49
+ //# sourceMappingURL=summary.js.map
package/dist/paths.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LOCAL_OPENCODE_AGENT_DIR = exports.GLOBAL_OPENCODE_AGENT_DIR = exports.CZON_META_PATH = exports.CZON_SRC_DIR = exports.CZON_DIST_RAW_CONTENT_DIR = exports.CZON_DIST_DIR = exports.CZON_DIR = exports.INPUT_DIR = void 0;
3
+ exports.LOCAL_OPENCODE_AGENT_DIR = exports.GLOBAL_OPENCODE_AGENT_DIR = exports.CZON_DIST_CUSTOM_STYLE_PATH = exports.CZON_CUSTOM_STYLE_PATH = exports.CZON_META_PATH = exports.CZON_SRC_DIR = exports.CZON_DIST_RAW_CONTENT_DIR = exports.CZON_DIST_DIR = exports.CZON_DIR = exports.INPUT_DIR = void 0;
4
4
  const os_1 = require("os");
5
5
  const path_1 = require("path");
6
6
  exports.INPUT_DIR = process.cwd();
@@ -9,6 +9,8 @@ exports.CZON_DIST_DIR = (0, path_1.join)(exports.CZON_DIR, 'dist');
9
9
  exports.CZON_DIST_RAW_CONTENT_DIR = (0, path_1.join)(exports.CZON_DIST_DIR, '__raw__');
10
10
  exports.CZON_SRC_DIR = (0, path_1.join)(exports.CZON_DIR, 'src');
11
11
  exports.CZON_META_PATH = (0, path_1.join)(exports.CZON_DIR, 'meta.json');
12
+ exports.CZON_CUSTOM_STYLE_PATH = (0, path_1.join)(exports.CZON_DIR, 'style.css');
13
+ exports.CZON_DIST_CUSTOM_STYLE_PATH = (0, path_1.join)(exports.CZON_DIST_DIR, 'style.css');
12
14
  /**
13
15
  * ~/.config/opencode/agents/
14
16
  */
@@ -65,13 +65,24 @@ const copyFavicon = async () => {
65
65
  await fs.copyFile(defaultFaviconSource, faviconTarget);
66
66
  console.info(`📄 Copied default favicon to: ${faviconTarget}`);
67
67
  };
68
+ /**
69
+ * 检测并复制自定义样式文件
70
+ * @returns 是否存在自定义样式
71
+ */
72
+ const copyCustomStyle = async () => {
73
+ if (await (0, isExists_1.isExists)(paths_1.CZON_CUSTOM_STYLE_PATH)) {
74
+ await fs.mkdir(path.dirname(paths_1.CZON_DIST_CUSTOM_STYLE_PATH), { recursive: true });
75
+ await fs.copyFile(paths_1.CZON_CUSTOM_STYLE_PATH, paths_1.CZON_DIST_CUSTOM_STYLE_PATH);
76
+ console.info(`🎨 Copied custom style from ${paths_1.CZON_CUSTOM_STYLE_PATH} to: ${paths_1.CZON_DIST_CUSTOM_STYLE_PATH}`);
77
+ return true;
78
+ }
79
+ return false;
80
+ };
68
81
  /**
69
82
  * 使用简单的爬虫抓取生成的站点页面
70
83
  */
71
84
  const spiderStaticSiteGenerator = async () => {
72
85
  (0, sitemap_1.clearSitemapCollection)();
73
- // 复制 favicon 图标
74
- await copyFavicon();
75
86
  const queue = ['/index.html', '/404.html'];
76
87
  // 将每个语言的首页加入队列
77
88
  for (const lang of metadata_1.MetaData.options.langs || []) {
@@ -79,6 +90,12 @@ const spiderStaticSiteGenerator = async () => {
79
90
  }
80
91
  const isVisited = new Set();
81
92
  const contents = [];
93
+ // 检测并复制自定义样式
94
+ const hasCustomStyle = await copyCustomStyle();
95
+ isVisited.add('/style.css'); // 标记自定义样式为已访问
96
+ // 复制 favicon 图标
97
+ await copyFavicon();
98
+ isVisited.add('/favicon.ico'); // 标记 favicon 为已访问
82
99
  // 预加载所有 Markdown 内容,因为 React 内部异步渲染比较麻烦
83
100
  for (const file of metadata_1.MetaData.files) {
84
101
  if (!file.path.endsWith('.md'))
@@ -107,6 +124,7 @@ const spiderStaticSiteGenerator = async () => {
107
124
  path: currentPath,
108
125
  site: metadata_1.MetaData,
109
126
  contents,
127
+ hasCustomStyle,
110
128
  });
111
129
  console.info(`🕷️ Crawled ${currentPath}`);
112
130
  // 收集 URL 用于 sitemap
@@ -137,9 +155,9 @@ const spiderStaticSiteGenerator = async () => {
137
155
  const resolvedPath = path.resolve('/', path.dirname(currentPath), link);
138
156
  if (resolvedPath.startsWith('/__raw__/'))
139
157
  continue; // 跳过原始内容目录
140
- if (resolvedPath === '/favicon.ico')
141
- continue; // 跳过 favicon.ico
142
- console.info(` ➕ Found link: ${link} -> ${resolvedPath} (${isVisited.has(resolvedPath) ? 'visited' : 'new'})`);
158
+ // console.info(
159
+ // ` ➕ Found link: ${link} -> ${resolvedPath} (${isVisited.has(resolvedPath) ? 'visited' : 'new'})`
160
+ // );
143
161
  if (!isVisited.has(resolvedPath)) {
144
162
  queue.push(resolvedPath);
145
163
  }
@@ -27,6 +27,7 @@ const ContentPage = props => {
27
27
  const thisPath = (0, node_path_1.resolve)('/', props.file.path);
28
28
  const referencedFiles = props.ctx.site.files.filter(f => f.links.some(link => (0, node_path_1.resolve)('/', (0, node_path_1.dirname)(f.path), link) === thisPath));
29
29
  const faviconUrl = (0, resourceMap_1.getFaviconUrlFrom)(props.ctx.path);
30
+ const customStyleUrl = props.ctx.hasCustomStyle ? (0, resourceMap_1.getCustomStyleUrlFrom)(props.ctx.path) : null;
30
31
  return (react_1.default.createElement("html", { lang: props.lang },
31
32
  react_1.default.createElement("head", null,
32
33
  react_1.default.createElement("meta", { charSet: "UTF-8" }),
@@ -37,6 +38,7 @@ const ContentPage = props => {
37
38
  react_1.default.createElement(Analytics_1.Analytics, { ctx: props.ctx }),
38
39
  react_1.default.createElement("script", { src: (0, resourceMap_1.getResourceUrlFrom)(props.ctx.path, 'tailwindcss.js') }),
39
40
  react_1.default.createElement("style", null, style_1.style),
41
+ customStyleUrl && react_1.default.createElement("link", { rel: "stylesheet", href: customStyleUrl }),
40
42
  react_1.default.createElement("script", { dangerouslySetInnerHTML: {
41
43
  __html: `
42
44
  (function() {
@@ -23,6 +23,7 @@ const IndexPage = props => {
23
23
  ]);
24
24
  const allCategories = Array.from(new Set([undefined].concat(props.ctx.site.files.map(f => f.category))));
25
25
  const faviconUrl = (0, resourceMap_1.getFaviconUrlFrom)(props.ctx.path);
26
+ const customStyleUrl = props.ctx.hasCustomStyle ? (0, resourceMap_1.getCustomStyleUrlFrom)(props.ctx.path) : null;
26
27
  return (react_1.default.createElement("html", null,
27
28
  react_1.default.createElement("head", null,
28
29
  react_1.default.createElement("meta", { charSet: "UTF-8" }),
@@ -33,6 +34,7 @@ const IndexPage = props => {
33
34
  react_1.default.createElement(Analytics_1.Analytics, { ctx: props.ctx }),
34
35
  react_1.default.createElement("script", { src: (0, resourceMap_1.getResourceUrlFrom)(props.ctx.path, 'tailwindcss.js') }),
35
36
  react_1.default.createElement("style", null, style_1.style),
37
+ customStyleUrl && react_1.default.createElement("link", { rel: "stylesheet", href: customStyleUrl }),
36
38
  react_1.default.createElement("script", { dangerouslySetInnerHTML: {
37
39
  __html: `
38
40
  (function() {
@@ -21,6 +21,7 @@ const RootPage = props => {
21
21
  }
22
22
  }
23
23
  const faviconUrl = (0, resourceMap_1.getFaviconUrlFrom)(props.ctx.path);
24
+ const customStyleUrl = props.ctx.hasCustomStyle ? (0, resourceMap_1.getCustomStyleUrlFrom)(props.ctx.path) : null;
24
25
  return (react_1.default.createElement("html", { lang: "en" },
25
26
  react_1.default.createElement("head", null,
26
27
  react_1.default.createElement("meta", { charSet: "UTF-8" }),
@@ -28,6 +29,7 @@ const RootPage = props => {
28
29
  react_1.default.createElement("title", null, "CZON Multilingual Site Navigator"),
29
30
  react_1.default.createElement("link", { rel: "icon", href: faviconUrl, type: "image/x-icon" }),
30
31
  react_1.default.createElement("meta", { name: "description", content: "Select your preferred language to explore our content." }),
32
+ customStyleUrl && react_1.default.createElement("link", { rel: "stylesheet", href: customStyleUrl }),
31
33
  react_1.default.createElement(Analytics_1.Analytics, { ctx: props.ctx }),
32
34
  props.ctx.site.options.langs.map(lang => (react_1.default.createElement("link", { key: lang, rel: "alternate", hrefLang: lang, href: `${lang}/index.html` }))),
33
35
  react_1.default.createElement("link", { rel: "alternate", hrefLang: "x-default", href: `${props.ctx.site.options.langs[0]}/index.html` }),
@@ -57,18 +59,19 @@ const RootPage = props => {
57
59
  // 自动重定向到用户浏览器语言对应的首页
58
60
  (function() {
59
61
  const mapUserLangToSupported = ${JSON.stringify(mapUserLangToSupported)};
62
+ const home = '${props.ctx.site.options.site?.home ?? 'index.html'}';
60
63
  for (const lang of navigator.languages) {
61
64
  if (mapUserLangToSupported[lang]) {
62
- window.location.href = mapUserLangToSupported[lang] + '/index.html';
65
+ window.location.href = mapUserLangToSupported[lang] + '/' + home;
63
66
  return;
64
67
  }
65
68
  const shortLang = lang.split('-')[0];
66
69
  if (mapUserLangToSupported[shortLang]) {
67
- window.location.href = mapUserLangToSupported[shortLang] + '/index.html';
70
+ window.location.href = mapUserLangToSupported[shortLang] + '/' + home;
68
71
  return;
69
72
  }
70
73
  }
71
- window.location.href = '${props.ctx.site.options.langs[0]}/index.html'; // 默认语言
74
+ window.location.href = '${props.ctx.site.options.langs[0]}/' + home; // 默认语言
72
75
  })();
73
76
 
74
77
  `))));
@@ -11,11 +11,12 @@ const NavLinks_1 = require("./NavLinks");
11
11
  const CZONHeader = props => {
12
12
  const navLinks = props.ctx.site.options.site?.navLinks;
13
13
  const hasNavLinks = navLinks && navLinks.length > 0;
14
+ const home = props.ctx.site.options.site?.home ?? 'index.html';
14
15
  return (react_1.default.createElement("header", { className: "czon-header py-4 border-b flex justify-between items-center px-6" },
15
16
  react_1.default.createElement("div", { className: "flex items-center gap-4" },
16
17
  hasNavLinks && react_1.default.createElement(NavLinks_1.NavLinksMobile, { navLinks: navLinks }),
17
18
  react_1.default.createElement("h1", { className: "text-2xl font-bold" },
18
- react_1.default.createElement("a", { href: "index.html" }, props.ctx.site.options.site?.title ?? 'CZON')),
19
+ react_1.default.createElement("a", { href: home }, props.ctx.site.options.site?.title ?? 'CZON')),
19
20
  hasNavLinks && react_1.default.createElement(NavLinks_1.NavLinksDesktop, { navLinks: navLinks })),
20
21
  react_1.default.createElement("div", { className: "flex items-center gap-4" },
21
22
  react_1.default.createElement(DarkModeSwitch_1.DarkModeSwitch, null),
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getFaviconUrlFrom = exports.getResourceUrlFrom = exports.EXTERNAL_RESOURCES = void 0;
3
+ exports.getCustomStyleUrlFrom = exports.getFaviconUrlFrom = exports.getResourceUrlFrom = exports.EXTERNAL_RESOURCES = void 0;
4
4
  const path_1 = require("path");
5
5
  exports.EXTERNAL_RESOURCES = [
6
6
  {
@@ -28,4 +28,12 @@ const getFaviconUrlFrom = (path) => {
28
28
  return (0, path_1.relative)((0, path_1.dirname)(path), '/favicon.ico');
29
29
  };
30
30
  exports.getFaviconUrlFrom = getFaviconUrlFrom;
31
+ /**
32
+ * 获取自定义样式的相对引用 URL
33
+ * @param path - 当前文件路径 (e.g. `/en-US/index.html`)
34
+ */
35
+ const getCustomStyleUrlFrom = (path) => {
36
+ return (0, path_1.relative)((0, path_1.dirname)(path), '/style.css');
37
+ };
38
+ exports.getCustomStyleUrlFrom = getCustomStyleUrlFrom;
31
39
  //# sourceMappingURL=resourceMap.js.map
package/package.json CHANGED
@@ -1,17 +1,16 @@
1
1
  {
2
2
  "name": "czon",
3
- "version": "0.7.6",
3
+ "version": "0.7.8",
4
4
  "description": "CZON - AI enhanced Markdown content engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "bin": "dist/cli.js",
8
8
  "scripts": {
9
9
  "build": "npx rimraf dist && tsc",
10
- "dev": "ts-node src/cli.ts",
11
- "build:doc": "npm run build && node dist/cli.js build",
12
- "test": "npm run build && node --test dist/**/*.test.js",
10
+ "dev": "tsx src/cli.ts",
11
+ "build:doc": "tsx src/cli.ts build",
12
+ "test": "tsx --test src/**/*.test.ts",
13
13
  "test:types": "tsc --noEmit",
14
- "test:build": "npm run build && test -f dist/index.js && test -f dist/cli.js",
15
14
  "test:cli": "node -e \"const pkg = require('./package.json'); console.log('Package:', pkg.name, 'v' + pkg.version)\"",
16
15
  "format": "prettier --write \"**/*.{ts,js,json,md}\"",
17
16
  "format:check": "prettier --check \"**/*.{ts,js,json,md}\"",
@@ -47,7 +46,7 @@
47
46
  "husky": "^9.1.7",
48
47
  "lint-staged": "^16.2.7",
49
48
  "prettier": "^3.7.4",
50
- "ts-node": "^10.9.2",
49
+ "tsx": "^4.19.4",
51
50
  "typescript": "^5.9.3"
52
51
  },
53
52
  "dependencies": {