Files
ClassIsland Prompt Kit 22c1784bab feat: ClassIsland / ClassHelper 灵动岛提示词套件
- 重构版主提示词(14 parts,面向 ClassHelper 灵动岛重构)
- ClassIsland 全量规格提示词(20 parts,含分卷与逐章版本)
- 投喂指南、分卷、逐节文件
- 调研记录、一致性基线、生成与质检脚本
2026-11-12 21:59:58 +08:00

97 lines
4.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* 汇总 parts/00-preamble.md + parts/NN-*.md 为最终提示词文件。
* 用法:node scripts/assemble.mjs [--split]
* 输出:ClassIsland-给ChatGPT的完整提示词.md(工作区根目录);--split 额外输出 out/ 下的分卷。
*/
import { readdirSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
const partsDir = join(root, 'parts');
const outFile = join(root, 'ClassIsland-给ChatGPT的完整提示词.md');
const files = readdirSync(partsDir)
.filter((f) => /^\d{2}-.+\.md$/.test(f))
.sort((a, b) => a.localeCompare(b, 'en'));
if (!files.some((f) => f.startsWith('00-'))) throw new Error('缺少 parts/00-preamble.md');
if (files.length !== 20) console.warn(`警告:part 数量为 ${files.length},预期 20`);
const sections = [];
const toc = [];
const stats = [];
let preamble = '';
for (const file of files) {
const content = readFileSync(join(partsDir, file), 'utf8').replace(/\r\n/g, '\n').trimEnd();
if (file.startsWith('00-')) {
preamble = content;
for (const line of content.split('\n')) {
if (/^## /.test(line)) toc.push(`- ${line.replace(/^##\s+/, '').trim()}`);
}
continue;
}
for (const line of content.split('\n')) {
if (/^## /.test(line)) toc.push(`- ${line.replace(/^##\s+/, '').trim()}`);
else if (/^### /.test(line)) toc.push(` - ${line.replace(/^###\s+/, '').trim()}`);
}
const chars = [...content.replace(/\s/g, '')].length;
const cjk = (content.match(/[\u4e00-\u9fff]/g) || []).length;
stats.push({ file, chars, cjk, lines: content.split('\n').length });
sections.push(content);
}
if (!preamble.includes('<!-- TOC -->')) throw new Error('preamble 缺少 <!-- TOC --> 占位符');
const tocBlock = ['## 目录', '', ...toc, ''].join('\n');
const body = [preamble.replace('<!-- TOC -->', tocBlock), ...sections].join('\n\n---\n\n');
writeFileSync(outFile, body + '\n', 'utf8');
const totalChars = [...body.replace(/\s/g, '')].length;
const totalCjk = (body.match(/[\u4e00-\u9fff]/g) || []).length;
const lines = body.split('\n').length;
console.log(`输出:${outFile}`);
console.log(`总字符(去空白):${totalChars};汉字:${totalCjk};行数:${lines}`);
console.log(`粗略 token 估算:${Math.round(totalCjk * 0.9 + (totalChars - totalCjk) * 0.3)}(仅参考)`);
console.log('各 part:');
for (const s of stats) console.log(` ${s.file.padEnd(28)} ${String(s.chars).padStart(7)} 字符 ${String(s.cjk).padStart(6)} 汉字`);
console.log(` 00-preamble.md ${String([...preamble.replace(/\s/g, '')].length).padStart(7)} 字符 ${String((preamble.match(/[\u4e00-\u9fff]/g) || []).length).padStart(6)} 汉字`);
if (process.argv.includes('--split')) {
const outDir = join(root, 'out');
const sectionsDir = join(outDir, 'sections');
mkdirSync(sectionsDir, { recursive: true });
const volumes = [
{ name: 'vol1-总纲与技术栈(00-02)', nums: [0, 1, 2] },
{ name: 'vol2-设计系统与主界面组件(03-05)', nums: [3, 4, 5] },
{ name: 'vol3-课表提醒自动化(06-08)', nums: [6, 7, 8] },
{ name: 'vol4-主题设置窗口系统与数据(09-13)', nums: [9, 10, 11, 12, 13] },
{ name: 'vol5-动画资源验收与结语(14-19)', nums: [14, 15, 16, 17, 18, 19] },
];
for (const v of volumes) {
const chunks = [];
if (v.nums.includes(0)) chunks.push(preamble.replace('<!-- TOC -->', tocBlock));
for (const n of v.nums) {
if (n === 0) continue;
const f = files.find((x) => Number(x.slice(0, 2)) === n);
if (f) chunks.push(readFileSync(join(partsDir, f), 'utf8').replace(/\r\n/g, '\n').trimEnd());
else console.warn(`警告:缺少 part ${n}`);
}
const p = join(outDir, `${v.name}.md`);
writeFileSync(p, chunks.join('\n\n---\n\n') + '\n', 'utf8');
const c = readFileSync(p, 'utf8');
console.log(`分卷:${p}(${[...c.replace(/\s/g, '')].length} 字符,${(c.match(/[\u4e00-\u9fff]/g) || []).length} 汉字)`);
}
// 逐节文件(适合按章节投喂)
let copied = 0;
for (const f of files) {
if (f.startsWith('00-')) continue;
copyFileSync(join(partsDir, f), join(sectionsDir, f));
copied += 1;
}
copyFileSync(join(partsDir, '00-preamble.md'), join(sectionsDir, '00-preamble.md'));
console.log(`逐节文件:${sectionsDir}(${copied + 1} 个)`);
}