czon 0.5.4 → 0.5.6

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
@@ -4,8 +4,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const clipanion_1 = require("clipanion");
5
5
  const dotenv_1 = require("dotenv");
6
6
  const pipeline_1 = require("./build/pipeline");
7
- const version_1 = require("./version");
8
7
  const findEntries_1 = require("./findEntries");
8
+ const summary_1 = require("./process/summary");
9
+ const version_1 = require("./version");
9
10
  // 加载 .env 文件中的环境变量
10
11
  (0, dotenv_1.config)();
11
12
  // LsFiles 命令
@@ -40,6 +41,54 @@ LsFilesCommand.usage = clipanion_1.Command.Usage({
40
41
  $ czon ls-files
41
42
  `,
42
43
  });
44
+ // Summary 命令
45
+ class SummaryCommand extends clipanion_1.Command {
46
+ constructor() {
47
+ super(...arguments);
48
+ this.model = clipanion_1.Option.String('--model', 'opencode/big-pickle', {
49
+ description: 'OpenCode model to use for summarization',
50
+ });
51
+ this.verbose = clipanion_1.Option.Boolean('-v,--verbose');
52
+ }
53
+ async execute() {
54
+ try {
55
+ if (this.verbose) {
56
+ process.env.VERBOSE = 'true';
57
+ }
58
+ await (0, summary_1.processSummary)(this.model);
59
+ return 0;
60
+ }
61
+ catch (error) {
62
+ this.context.stderr.write(`❌ Summary generation failed: ${error}\n`);
63
+ return 1;
64
+ }
65
+ }
66
+ }
67
+ SummaryCommand.paths = [['summary']];
68
+ SummaryCommand.usage = clipanion_1.Command.Usage({
69
+ description: 'Generate comprehensive multi-style summaries of all markdown files',
70
+ details: `
71
+ This command generates 10 different styles of AI-powered summaries for all markdown files
72
+ in the current repository. The summaries are saved to the SUMMARY directory.
73
+
74
+ Generated summary styles include:
75
+ - Objective analysis
76
+ - Critical perspective
77
+ - Positive encouragement
78
+ - Popular science explanation
79
+ - Artistic interpretation
80
+ - Philosophical analysis
81
+ - Psychological analysis (MBTI)
82
+ - Historical timeline
83
+ - Community discussion
84
+ - Structured debate
85
+
86
+ Examples:
87
+ $ czon summary
88
+ $ czon summary --model opencode/gpt-4o
89
+ $ czon summary --verbose
90
+ `,
91
+ });
43
92
  // Build 命令
44
93
  class BuildCommand extends clipanion_1.Command {
45
94
  constructor() {
@@ -89,6 +138,7 @@ const cli = new clipanion_1.Cli({
89
138
  // 注册命令
90
139
  cli.register(BuildCommand);
91
140
  cli.register(LsFilesCommand);
141
+ cli.register(SummaryCommand);
92
142
  // 运行 CLI
93
143
  cli.runExit(process.argv.slice(2), {
94
144
  ...clipanion_1.Cli.defaultContext,
@@ -13,27 +13,19 @@ const execAsync = (0, util_1.promisify)(child_process_1.exec);
13
13
  * @returns Promise<string[]> 返回Markdown文件的相对路径数组
14
14
  */
15
15
  const findMarkdownEntries = async (dirPath) => {
16
- try {
17
- // 使用git命令获取所有文件(包括已跟踪和未跟踪的文件)
18
- // 在指定的目录下执行git命令
19
- // 使用 -z 选项以空字符分隔文件名,方便处理文件名中包含特殊字符 (UTF-8) 的情况
20
- const { stdout } = await execAsync('git ls-files --others --cached --exclude-standard -z', {
21
- cwd: dirPath,
22
- });
23
- // 按行分割并过滤
24
- const files = stdout
25
- .split('\0') // 按空字符分割文件名
26
- .filter(line => line.trim() !== '') // 移除空行
27
- .filter(file => !file.startsWith('.')) // 过滤掉隐藏目录下的文件
28
- .filter(file => file.endsWith('.md')); // 只保留.md文件
29
- return files;
30
- }
31
- catch (error) {
32
- console.error('Error finding markdown entries:', error);
33
- // 如果git命令失败,返回空数组
34
- // 这可以处理没有git仓库或git不可用的情况
35
- return [];
36
- }
16
+ // 使用git命令获取所有文件(包括已跟踪和未跟踪的文件)
17
+ // 在指定的目录下执行git命令
18
+ // 使用 -z 选项以空字符分隔文件名,方便处理文件名中包含特殊字符 (UTF-8) 的情况
19
+ const { stdout } = await execAsync('git ls-files --others --cached --exclude-standard -z', {
20
+ cwd: dirPath,
21
+ });
22
+ // 按行分割并过滤
23
+ const files = stdout
24
+ .split('\0') // 按空字符分割文件名
25
+ .filter(line => line.trim() !== '') // 移除空行
26
+ .filter(file => !file.startsWith('.')) // 过滤掉隐藏目录下的文件
27
+ .filter(file => file.endsWith('.md')); // 只保留.md文件
28
+ return files;
37
29
  };
38
30
  exports.findMarkdownEntries = findMarkdownEntries;
39
31
  //# sourceMappingURL=findEntries.js.map
@@ -40,13 +40,13 @@ const processExtractCategory = async () => {
40
40
  '每个文档只能有一个类别标签。',
41
41
  '请确保类别标签之间没有重复,并且涵盖所有文档的主题。',
42
42
  '然后,为每个文档生成一个映射,指明该文档对应的类别标签。',
43
- '请检查每个分类中的文档数量不能过少(例如少于 2 个),如果有,请考虑合并到其他相关类别中。',
44
43
  '确保每个输入的文档都能在输出的类别标签中找到对应的类别。',
44
+ '优先考虑已有的类别标签,但也可以根据需要创建新的类别标签。',
45
45
  // ISSUE: 有时候 AI 会忽略部分文件的分类,需要强调至少要处理还未分类的文件
46
46
  '请优先考虑尚未被分类的文件。',
47
47
  '请以 JSON 格式返回类别标签列表。',
48
48
  '示例输出格式:',
49
- '{ "categories": ["tag1", "tag2", "tag3"], "mappings": { "hash1": "tag1", "hash2": "tag2" } }',
49
+ '{ "mappings": { "hash1": "tag1", "hash2": "tag2" } }',
50
50
  ].join('\n'),
51
51
  },
52
52
  {
@@ -60,11 +60,6 @@ const processExtractCategory = async () => {
60
60
  .map(f => formatFileForCategoryExtraction(f))
61
61
  .join('\n\n'),
62
62
  '',
63
- `已经分类的文件有:`,
64
- markdownFiles
65
- .filter(f => f.category)
66
- .map(f => formatFileForCategoryExtraction(f))
67
- .join('\n\n'),
68
63
  ].join('\n'),
69
64
  },
70
65
  ], { response_format: { type: 'json_object' }, task_id: 'extract-categories' });
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processSummary = void 0;
4
+ const opencode_1 = require("../services/opencode");
5
+ const processSummary = async (model) => {
6
+ const prompt = [
7
+ `
8
+ 先清空 SUMMARY 目录,因为这是历史分析,已经过时。
9
+
10
+ 通过命令列出目标 Markdown 文件:
11
+ npx czon@latest ls-files
12
+
13
+ 然后,阅读所有 markdown 文件,除了 .czon 中的。对内容进行多方面的总结。
14
+
15
+ 请从以下几个风格进行总结分析,生成对应的 markdown 文件:
16
+
17
+ 1. 客观中立风格 (1-objective.md)
18
+
19
+ 以客观中立的角度介绍内容,避免主观评价和情感色彩。 强调事实和数据,确保信息的准确性和可靠性。
20
+
21
+ 目的是为了让读者全面了解内容的基本信息和核心观点,帮助他们形成自己的看法和判断。
22
+
23
+ 注意,不要加入情感表达,不要进行推测,保持中立和客观。
24
+
25
+ 基于事实,保持简洁,使用简历和履历格式。
26
+
27
+ 2. 客观批判风格 (2-critical.md)
28
+
29
+ 基于事实,对内容进行客观的批判性分析,指出其优点和缺点。
30
+
31
+ 目的是为了帮助读者更全面地理解内容,识别其优缺点,从而做出更明智的判断和决策。同时促进内容的改进和提升。
32
+
33
+ 注意,批判并不意味着否定或贬低,而是以建设性的态度提出意见和建议,促进内容的改进和提升。
34
+
35
+ 3. 赞扬鼓励风格 (3-positive.md)
36
+
37
+ 以积极正面的角度介绍内容,强调其优点和亮点,鼓励读者去尝试和体验。
38
+
39
+ 目的是为了激发读者的兴趣和热情,增强他们对内容的认可和好感。同时鼓励内容创作者继续努力,提升内容质量。
40
+
41
+ 注意,不是盲目吹捧,不要谄媚表达,要有事实依据
42
+
43
+ 4. 科普介绍风格 (4-popular.md)
44
+
45
+ 以通俗易懂的语言,向普通人介绍内容,降低理解难度。
46
+
47
+ 目的是为了让读者在轻松愉快的氛围中理解内容,增加阅读的趣味性和吸引力。
48
+
49
+ 基于事实,使用简单的语言和例子,避免专业术语和复杂概念。
50
+
51
+ 5. 文艺感性风格 (5-artistic.md)
52
+
53
+ 通过细腻的描写和情感表达,营造出一种身临其境的感觉,让读者能够感受到内容中的情感和氛围。
54
+
55
+ 使用生动的语言和形象的比喻,帮助读者在脑海中构建出内容的画面,增强内容的感染力。
56
+
57
+ 通过讲述故事和情节的发展,引导读者进入内容的情境中,激发他们的共鸣和情感反应。
58
+
59
+ 6. 哲学思辨风格 (6-philosophical.md)
60
+
61
+ 以哲学的视角,对内容进行深度思考和分析,探讨其背后的意义和价值。
62
+
63
+ 目的是为了引发读者的思考和反思,帮助他们从更深层次理解内容,提升他们的认知水平和思维能力。
64
+
65
+ 基于逻辑推理和哲学理论,提出有深度的问题和观点,促进读者的思辨能力。
66
+
67
+ 7. 心理分析风格 (7-psychological.md)
68
+
69
+ 进行深度的心理分析,探讨内容背后的心理动机和行为模式。
70
+
71
+ 基于内容,进行 MBTI 分析,分析内容创作者的性格倾向和行为特征,必须给出每个倾向维度的证据。
72
+
73
+ 基于内容,进行价值观分析,探讨内容所反映的核心价值观和信念体系,给出价值观的排序和具体例子。
74
+
75
+ 基于内容,进行精神分析 (包括心理防御机制、潜意识动机等),必须为每个评价标签给出置信度,给出具体例子,解释其作用和影响。
76
+
77
+ 基于内容,分析人物关系,探讨内容中不同人物之间的互动和关系动态,揭示其背后的心理机制。
78
+
79
+ 8. 历史时间跨度风格 (8-history.md)
80
+
81
+ 梳理时间线,以历史发展的视角看待内容的变化。
82
+
83
+ 基于时间顺序,分析内容在不同时间点上的演变和发展,揭示其背后的历史脉络和趋势。
84
+
85
+ 目的是为了帮助读者理解内容的历史背景和发展过程,提供更全面的视角。
86
+
87
+ 基于现有内容,合理推测未来的发展方向和趋势,提供前瞻性的见解。
88
+
89
+ 9. 社区评论风格 (9-discussion.md)
90
+
91
+ 模拟多位网友,以评论区的形式对内容进行讨论,展现多样化的观点和看法。
92
+
93
+ 每位网友应有独立的网名,不要起太过于刻板印象的网名(不真实感太强烈)。
94
+
95
+ 网友的身份可以多样化,涵盖不同年龄、性别、职业、兴趣等背景,以体现社区的多元性。
96
+
97
+ 多位网友之间要有互动和回应,形成一个活跃的讨论氛围。
98
+
99
+ 根据文章内容的量级,生成大约 20 到 300 条评论,每条评论控制在 150 字之内。
100
+
101
+ 注意,评论内容必须基于事实,不能脱离内容本身进行无根据的猜测和评论。
102
+
103
+ 目的是为了呈现不同视角和关注点下的内容理解,降低读者的认知负担。
104
+
105
+ 10. 辩论风格 (10-debate.md)
106
+
107
+ 模拟两位辩手围绕内容展开辩论,展现不同的观点和立场。
108
+
109
+ 从原始内容中,挑选有代表性的观点,进行正反两方面的辩论。
110
+
111
+ 每位辩手应有独立的身份背景,可以是不同的职业、学术背景或社会角色,以体现观点的多样性。
112
+
113
+ 正反双方可以各派出 5 位辩手,围绕核心观点展开深入讨论。
114
+
115
+ 辩论过程中,双方应针对对方的观点进行回应和反驳,形成一个有逻辑、有深度的讨论。
116
+
117
+ 进行 5 轮辩论,每轮辩论后进行简短的总结陈词。每轮发言控制在 1000 字之内。
118
+
119
+ 每轮结束后,主持人进行简短总结陈词,概括双方的主要观点和争议点。然后由观众投票选出本轮的胜者。
120
+
121
+ 注意,辩论内容必须基于事实,不能脱离内容本身进行无根据的猜测和评论。
122
+
123
+ 目的是为了通过对立观点的碰撞,激发读者的思考和理解,提供更全面的视角。
124
+
125
+
126
+ 请遵循如下规则:
127
+ 1. 切记,以事实内容为依据,不得出现脱离事实的情况。
128
+ 2. 内容生成到 SUMMARY 目录中,生成不同的 markdown 文件。
129
+ 3. 引用原文链接时,保证链接有效,不要链接一个目录,永远链接到一个具体的 Markdown 文件。并且链接的文本应当是对应的标题,而不是文件名。注意,由于生成到 SUMMARY 目录,引用 Markdown 文件时注意 .. 开头才是项目根目录(相对文件所在的位置)。
130
+ 4. 在开头添加 AI 分析的时间日期。注明是 AI 生成,内容仅供参考。
131
+ 5. 考虑时间跨度,给予最近的文章更高的权重。
132
+
133
+ `,
134
+ ]
135
+ .join('\n')
136
+ .trim();
137
+ await (0, opencode_1.runOpenCode)(prompt, { model });
138
+ };
139
+ exports.processSummary = processSummary;
140
+ //# sourceMappingURL=summary.js.map
@@ -51,8 +51,11 @@ const runOpenCode = (prompt, options) => {
51
51
  '--format',
52
52
  'json',
53
53
  ], {
54
- stdio: ['ignore', 'pipe', 'pipe'],
54
+ stdio: ['ignore', 'pipe', 'inherit'],
55
55
  cwd,
56
+ env: Object.assign({
57
+ OPENCODE_PERMISSION: JSON.stringify({ bash: 'allow', read: 'allow', write: 'allow' }),
58
+ }, process.env),
56
59
  });
57
60
  let output = '';
58
61
  proc.stdout.on('data', data => {
@@ -62,9 +65,6 @@ const runOpenCode = (prompt, options) => {
62
65
  console.info('OpenCode stdout chunk:', chunk);
63
66
  }
64
67
  });
65
- proc.stderr.on('data', data => {
66
- console.error('OpenCode stderr:', data.toString());
67
- });
68
68
  proc.on('error', err => {
69
69
  reject(new Error(`Failed to start OpenCode process: ${err.message}`));
70
70
  });
package/dist/ssg/style.js CHANGED
@@ -174,6 +174,14 @@ html:not(.dark) body {
174
174
  margin: 1rem 0;
175
175
  }
176
176
 
177
+ .content-body ul {
178
+ list-style: disc outside;
179
+ }
180
+
181
+ .content-body ol {
182
+ list-style: decimal outside;
183
+ }
184
+
177
185
  .content-body ul,
178
186
  .content-body ol {
179
187
  margin: 1rem 0 1rem 2rem;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "czon",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "CZone - AI enhanced Markdown content engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",