dsh-thesis 1.0.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.
Files changed (188) hide show
  1. package/DESIGN.md +390 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE.md +10 -0
  4. package/README.md +253 -0
  5. package/cordis.patch.yml +17 -0
  6. package/docs/host-api.md +640 -0
  7. package/lib/codewalk/commands.d.ts +23 -0
  8. package/lib/codewalk/commands.js +168 -0
  9. package/lib/codewalk/engine.d.ts +108 -0
  10. package/lib/codewalk/engine.js +449 -0
  11. package/lib/codewalk/errors.d.ts +31 -0
  12. package/lib/codewalk/errors.js +20 -0
  13. package/lib/codewalk/fs-types.d.ts +34 -0
  14. package/lib/codewalk/fs-types.js +10 -0
  15. package/lib/codewalk/gate.d.ts +30 -0
  16. package/lib/codewalk/gate.js +60 -0
  17. package/lib/codewalk/host-types.d.ts +198 -0
  18. package/lib/codewalk/host-types.js +11 -0
  19. package/lib/codewalk/prestep.d.ts +17 -0
  20. package/lib/codewalk/prestep.js +62 -0
  21. package/lib/codewalk/register.d.ts +23 -0
  22. package/lib/codewalk/register.js +31 -0
  23. package/lib/codewalk/skill.d.ts +15 -0
  24. package/lib/codewalk/skill.js +57 -0
  25. package/lib/codewalk/tools.d.ts +18 -0
  26. package/lib/codewalk/tools.js +314 -0
  27. package/lib/codewalk/types.d.ts +151 -0
  28. package/lib/codewalk/types.js +9 -0
  29. package/lib/commands.d.ts +33 -0
  30. package/lib/commands.js +60 -0
  31. package/lib/config.d.ts +125 -0
  32. package/lib/config.js +139 -0
  33. package/lib/dedup/commands.d.ts +21 -0
  34. package/lib/dedup/commands.js +93 -0
  35. package/lib/dedup/index.d.ts +75 -0
  36. package/lib/dedup/index.js +331 -0
  37. package/lib/dedup/normalize.d.ts +125 -0
  38. package/lib/dedup/normalize.js +329 -0
  39. package/lib/dedup/report.d.ts +114 -0
  40. package/lib/dedup/report.js +309 -0
  41. package/lib/dedup/rewrite.d.ts +71 -0
  42. package/lib/dedup/rewrite.js +228 -0
  43. package/lib/dedup/similarity.d.ts +169 -0
  44. package/lib/dedup/similarity.js +323 -0
  45. package/lib/gates/dangerous.d.ts +22 -0
  46. package/lib/gates/dangerous.js +47 -0
  47. package/lib/gates/detect.d.ts +54 -0
  48. package/lib/gates/detect.js +106 -0
  49. package/lib/gates/messages.d.ts +39 -0
  50. package/lib/gates/messages.js +74 -0
  51. package/lib/gates/prompt.d.ts +21 -0
  52. package/lib/gates/prompt.js +56 -0
  53. package/lib/gates/writing-intent.d.ts +49 -0
  54. package/lib/gates/writing-intent.js +68 -0
  55. package/lib/index.d.ts +36 -0
  56. package/lib/index.js +76 -0
  57. package/lib/ingest/code.d.ts +71 -0
  58. package/lib/ingest/code.js +356 -0
  59. package/lib/ingest/commands.d.ts +23 -0
  60. package/lib/ingest/commands.js +74 -0
  61. package/lib/ingest/docx.d.ts +29 -0
  62. package/lib/ingest/docx.js +92 -0
  63. package/lib/ingest/index.d.ts +179 -0
  64. package/lib/ingest/index.js +640 -0
  65. package/lib/ingest/ooxml.d.ts +58 -0
  66. package/lib/ingest/ooxml.js +393 -0
  67. package/lib/ingest/pdf.d.ts +86 -0
  68. package/lib/ingest/pdf.js +1016 -0
  69. package/lib/ingest/pptx.d.ts +32 -0
  70. package/lib/ingest/pptx.js +116 -0
  71. package/lib/ingest/text.d.ts +25 -0
  72. package/lib/ingest/text.js +180 -0
  73. package/lib/ingest/types.d.ts +48 -0
  74. package/lib/ingest/types.js +47 -0
  75. package/lib/ingest/xlsx.d.ts +72 -0
  76. package/lib/ingest/xlsx.js +411 -0
  77. package/lib/ingest/zip.d.ts +76 -0
  78. package/lib/ingest/zip.js +393 -0
  79. package/lib/intake/definitions.d.ts +65 -0
  80. package/lib/intake/definitions.js +42 -0
  81. package/lib/intake/gate-rules.d.ts +57 -0
  82. package/lib/intake/gate-rules.js +118 -0
  83. package/lib/intake/gate.d.ts +24 -0
  84. package/lib/intake/gate.js +86 -0
  85. package/lib/intake/index.d.ts +76 -0
  86. package/lib/intake/index.js +468 -0
  87. package/lib/intake/questions.d.ts +169 -0
  88. package/lib/intake/questions.js +720 -0
  89. package/lib/intake/spec.d.ts +66 -0
  90. package/lib/intake/spec.js +221 -0
  91. package/lib/intake/state.d.ts +192 -0
  92. package/lib/intake/state.js +420 -0
  93. package/lib/memory/recall.d.ts +69 -0
  94. package/lib/memory/recall.js +177 -0
  95. package/lib/memory/register.d.ts +37 -0
  96. package/lib/memory/register.js +52 -0
  97. package/lib/memory/service.d.ts +39 -0
  98. package/lib/memory/service.js +39 -0
  99. package/lib/memory/store.d.ts +45 -0
  100. package/lib/memory/store.js +123 -0
  101. package/lib/memory/tools.d.ts +19 -0
  102. package/lib/memory/tools.js +195 -0
  103. package/lib/memory/types.d.ts +55 -0
  104. package/lib/memory/types.js +6 -0
  105. package/lib/paper/commands.d.ts +13 -0
  106. package/lib/paper/commands.js +84 -0
  107. package/lib/paper/lib/aicheck.d.ts +38 -0
  108. package/lib/paper/lib/aicheck.js +241 -0
  109. package/lib/paper/lib/bibtex.d.ts +21 -0
  110. package/lib/paper/lib/bibtex.js +114 -0
  111. package/lib/paper/lib/check.d.ts +32 -0
  112. package/lib/paper/lib/check.js +215 -0
  113. package/lib/paper/lib/defense.d.ts +48 -0
  114. package/lib/paper/lib/defense.js +220 -0
  115. package/lib/paper/lib/docx.d.ts +35 -0
  116. package/lib/paper/lib/docx.js +213 -0
  117. package/lib/paper/lib/layout.d.ts +41 -0
  118. package/lib/paper/lib/layout.js +572 -0
  119. package/lib/paper/lib/ledger.d.ts +112 -0
  120. package/lib/paper/lib/ledger.js +349 -0
  121. package/lib/paper/lib/lit-api.d.ts +59 -0
  122. package/lib/paper/lib/lit-api.js +296 -0
  123. package/lib/paper/lib/lit-cache.d.ts +32 -0
  124. package/lib/paper/lib/lit-cache.js +91 -0
  125. package/lib/paper/lib/project.d.ts +29 -0
  126. package/lib/paper/lib/project.js +93 -0
  127. package/lib/paper/lib/review.d.ts +37 -0
  128. package/lib/paper/lib/review.js +194 -0
  129. package/lib/paper/lib/zip.d.ts +14 -0
  130. package/lib/paper/lib/zip.js +124 -0
  131. package/lib/paper/register.d.ts +20 -0
  132. package/lib/paper/register.js +183 -0
  133. package/lib/paper/tools/aicheck.d.ts +6 -0
  134. package/lib/paper/tools/aicheck.js +38 -0
  135. package/lib/paper/tools/build.d.ts +27 -0
  136. package/lib/paper/tools/build.js +166 -0
  137. package/lib/paper/tools/check.d.ts +7 -0
  138. package/lib/paper/tools/check.js +79 -0
  139. package/lib/paper/tools/decision.d.ts +13 -0
  140. package/lib/paper/tools/decision.js +53 -0
  141. package/lib/paper/tools/defense.d.ts +11 -0
  142. package/lib/paper/tools/defense.js +74 -0
  143. package/lib/paper/tools/init.d.ts +23 -0
  144. package/lib/paper/tools/init.js +99 -0
  145. package/lib/paper/tools/lit.d.ts +27 -0
  146. package/lib/paper/tools/lit.js +236 -0
  147. package/lib/paper/tools/progress.d.ts +18 -0
  148. package/lib/paper/tools/progress.js +77 -0
  149. package/lib/paper/tools/review.d.ts +11 -0
  150. package/lib/paper/tools/review.js +41 -0
  151. package/lib/ppt/actions.d.ts +97 -0
  152. package/lib/ppt/actions.js +263 -0
  153. package/lib/ppt/check.d.ts +64 -0
  154. package/lib/ppt/check.js +185 -0
  155. package/lib/ppt/commands.d.ts +28 -0
  156. package/lib/ppt/commands.js +71 -0
  157. package/lib/ppt/convert.d.ts +146 -0
  158. package/lib/ppt/convert.js +423 -0
  159. package/lib/ppt/index.d.ts +45 -0
  160. package/lib/ppt/index.js +57 -0
  161. package/lib/ppt/marp.d.ts +74 -0
  162. package/lib/ppt/marp.js +165 -0
  163. package/lib/ppt/outline.d.ts +206 -0
  164. package/lib/ppt/outline.js +695 -0
  165. package/lib/shared/define-tool.d.ts +77 -0
  166. package/lib/shared/define-tool.js +235 -0
  167. package/lib/shared/fs-errors.d.ts +50 -0
  168. package/lib/shared/fs-errors.js +90 -0
  169. package/lib/shared/index.d.ts +31 -0
  170. package/lib/shared/index.js +32 -0
  171. package/lib/shared/spawn.d.ts +38 -0
  172. package/lib/shared/spawn.js +50 -0
  173. package/lib/shared/text.d.ts +14 -0
  174. package/lib/shared/text.js +26 -0
  175. package/package.json +82 -0
  176. package/skills/code-walkthrough/SKILL.md +94 -0
  177. package/skills/code-walkthrough/references/examples.md +129 -0
  178. package/skills/paper-dedup/SKILL.md +58 -0
  179. package/skills/paper-intake/SKILL.md +64 -0
  180. package/skills/thesis-citation/SKILL.md +67 -0
  181. package/skills/thesis-defense/SKILL.md +87 -0
  182. package/skills/thesis-eng-design/SKILL.md +97 -0
  183. package/skills/thesis-inquiry/SKILL.md +55 -0
  184. package/skills/thesis-inquiry/references/intent-spec-template.md +39 -0
  185. package/skills/thesis-literature/SKILL.md +56 -0
  186. package/skills/thesis-opener/SKILL.md +77 -0
  187. package/skills/thesis-pipeline/SKILL.md +121 -0
  188. package/skills/thesis-writing/SKILL.md +86 -0
@@ -0,0 +1,213 @@
1
+ /**
2
+ * 零依赖 .docx 生成:Markdown-lite → WordprocessingML。
3
+ *
4
+ * 覆盖论文写作实际用到的 Markdown 子集:
5
+ * - 标题 # / ## / ###(H1 每章另起一页)
6
+ * - 段落、粗体 **text**、行内代码 `code`、链接 [text](url)
7
+ * - 无序列表 - item、表格 | a | b |
8
+ * - G2 清单 - [ ] / - [x] 保持为列表项文本
9
+ *
10
+ * 中文排版:正文宋体 + Times New Roman、1.5 倍行距;标题黑体。
11
+ * 这是内置过渡引擎;机器装有 pandoc 时 thesis_build 优先走 pandoc。
12
+ */
13
+ import { buildZip } from "./zip.js";
14
+ const encoder = new TextEncoder();
15
+ export function parseMarkdownBlocks(markdown) {
16
+ const blocks = [];
17
+ const lines = markdown.split('\n');
18
+ let i = 0;
19
+ while (i < lines.length) {
20
+ const line = lines[i];
21
+ const trimmed = line.trim();
22
+ if (trimmed === '' || /^-{3,}$/.test(trimmed)) {
23
+ i += 1;
24
+ continue;
25
+ }
26
+ // 表格:连续的 | 行(跳过分隔行)
27
+ if (trimmed.startsWith('|') && trimmed.endsWith('|')) {
28
+ const rows = [];
29
+ while (i < lines.length) {
30
+ const candidate = lines[i].trim();
31
+ if (!(candidate.startsWith('|') && candidate.endsWith('|')))
32
+ break;
33
+ const cells = candidate.slice(1, -1).split('|').map(c => c.trim());
34
+ const isSeparator = cells.every(c => /^:?-{2,}:?$/.test(c));
35
+ if (!isSeparator && cells.some(c => c !== ''))
36
+ rows.push(cells);
37
+ i += 1;
38
+ }
39
+ if (rows.length > 0)
40
+ blocks.push({ kind: 'table', rows });
41
+ continue;
42
+ }
43
+ const h = /^(#{1,3})\s+(.*)$/.exec(line);
44
+ if (h !== null) {
45
+ const level = h[1].length;
46
+ const kind = level === 1 ? 'h1' : level === 2 ? 'h2' : 'h3';
47
+ blocks.push({ kind, text: h[2].trim() });
48
+ i += 1;
49
+ continue;
50
+ }
51
+ if (/^[-*]\s+/.test(trimmed)) {
52
+ blocks.push({ kind: 'bullet', text: trimmed.replace(/^[-*]\s+/, '') });
53
+ i += 1;
54
+ continue;
55
+ }
56
+ blocks.push({ kind: 'p', text: trimmed.replace(/^>\s?/, '') });
57
+ i += 1;
58
+ }
59
+ return blocks;
60
+ }
61
+ // ---------------------------------------------------------------------------
62
+ // 行内解析与 XML
63
+ // ---------------------------------------------------------------------------
64
+ function escapeXml(text) {
65
+ return text
66
+ .replaceAll('&', '&amp;')
67
+ .replaceAll('<', '&lt;')
68
+ .replaceAll('>', '&gt;')
69
+ .replaceAll('"', '&quot;');
70
+ }
71
+ function parseInline(text) {
72
+ const runs = [];
73
+ // 先还原链接为文字
74
+ const noLinks = text.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1');
75
+ const parts = noLinks.split(/(\*\*[^*]+\*\*|`[^`]+`)/g);
76
+ for (const part of parts) {
77
+ if (part === '' || part === undefined)
78
+ continue;
79
+ if (part.startsWith('**') && part.endsWith('**') && part.length > 4) {
80
+ runs.push({ text: part.slice(2, -2), bold: true });
81
+ }
82
+ else if (part.startsWith('`') && part.endsWith('`') && part.length > 1) {
83
+ runs.push({ text: part.slice(1, -1), bold: false });
84
+ }
85
+ else {
86
+ runs.push({ text: part, bold: false });
87
+ }
88
+ }
89
+ return runs;
90
+ }
91
+ function runsXml(runs) {
92
+ return runs.map(run => `<w:r><w:rPr>${run.bold ? '<w:b/>' : ''}</w:rPr><w:t xml:space="preserve">${escapeXml(run.text)}</w:t></w:r>`).join('');
93
+ }
94
+ function paragraphXml(text, styleId, pageBreakBefore = false) {
95
+ const pPr = styleId !== undefined || pageBreakBefore
96
+ ? `<w:pPr>${styleId !== undefined ? `<w:pStyle w:val="${styleId}"/>` : ''}${pageBreakBefore ? '<w:pageBreakBefore/>' : ''}</w:pPr>`
97
+ : '';
98
+ return `<w:p>${pPr}${runsXml(parseInline(text))}</w:p>`;
99
+ }
100
+ function blockXml(block) {
101
+ switch (block.kind) {
102
+ case 'h1': return paragraphXml(block.text, 'Heading1', true);
103
+ case 'h2': return paragraphXml(block.text, 'Heading2');
104
+ case 'h3': return paragraphXml(block.text, 'Heading3');
105
+ case 'p': return paragraphXml(block.text);
106
+ case 'bullet': return paragraphXml(`• ${block.text}`, 'ListBullet');
107
+ case 'table': {
108
+ const rows = block.rows.map(row => {
109
+ const cells = row.map(cell => `<w:tc><w:p>${runsXml(parseInline(cell))}</w:p></w:tc>`).join('');
110
+ return `<w:tr>${cells}</w:tr>`;
111
+ }).join('');
112
+ return `<w:tbl><w:tblPr><w:tblStyle w:val="TableGrid"/><w:tblW w:w="0" w:type="auto"/></w:tblPr>${rows}</w:tbl>`;
113
+ }
114
+ }
115
+ }
116
+ // ---------------------------------------------------------------------------
117
+ // 文档装配
118
+ // ---------------------------------------------------------------------------
119
+ const CONTENT_TYPES = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
120
+ <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
121
+ <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
122
+ <Default Extension="xml" ContentType="application/xml"/>
123
+ <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
124
+ <Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>
125
+ </Types>
126
+ `;
127
+ const ROOT_RELS = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
128
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
129
+ <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
130
+ </Relationships>
131
+ `;
132
+ const DOCUMENT_RELS = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
133
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"/>
134
+ `;
135
+ const STYLES = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
136
+ <w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
137
+ <w:docDefaults>
138
+ <w:rPrDefault><w:rPr>
139
+ <w:rFonts w:ascii="Times New Roman" w:eastAsia="宋体" w:hAnsi="Times New Roman"/>
140
+ <w:sz w:val="24"/><w:szCs w:val="24"/>
141
+ </w:rPr></w:rPrDefault>
142
+ <w:pPrDefault><w:pPr><w:spacing w:line="360" w:lineRule="auto"/></w:pPr></w:pPrDefault>
143
+ </w:docDefaults>
144
+ <w:style w:type="paragraph" w:styleId="Normal"><w:name w:val="Normal"/></w:style>
145
+ <w:style w:type="paragraph" w:styleId="TitlePage">
146
+ <w:name w:val="Title Page"/>
147
+ <w:pPr><w:jc w:val="center"/><w:spacing w:before="1200" w:after="240"/></w:pPr>
148
+ <w:rPr><w:rFonts w:eastAsia="黑体"/><w:b/><w:sz w:val="44"/><w:szCs w:val="44"/></w:rPr>
149
+ </w:style>
150
+ <w:style w:type="paragraph" w:styleId="Subtitle">
151
+ <w:name w:val="Subtitle"/>
152
+ <w:pPr><w:jc w:val="center"/><w:spacing w:after="240"/></w:pPr>
153
+ <w:rPr><w:sz w:val="28"/><w:szCs w:val="28"/></w:rPr>
154
+ </w:style>
155
+ <w:style w:type="paragraph" w:styleId="Heading1">
156
+ <w:name w:val="heading 1"/>
157
+ <w:pPr><w:spacing w:before="240" w:after="120"/></w:pPr>
158
+ <w:rPr><w:rFonts w:eastAsia="黑体"/><w:b/><w:sz w:val="32"/><w:szCs w:val="32"/></w:rPr>
159
+ </w:style>
160
+ <w:style w:type="paragraph" w:styleId="Heading2">
161
+ <w:name w:val="heading 2"/>
162
+ <w:pPr><w:spacing w:before="200" w:after="100"/></w:pPr>
163
+ <w:rPr><w:rFonts w:eastAsia="黑体"/><w:b/><w:sz w:val="28"/><w:szCs w:val="28"/></w:rPr>
164
+ </w:style>
165
+ <w:style w:type="paragraph" w:styleId="Heading3">
166
+ <w:name w:val="heading 3"/>
167
+ <w:pPr><w:spacing w:before="160" w:after="80"/></w:pPr>
168
+ <w:rPr><w:rFonts w:eastAsia="黑体"/><w:b/><w:sz w:val="26"/><w:szCs w:val="26"/></w:rPr>
169
+ </w:style>
170
+ <w:style w:type="paragraph" w:styleId="ListBullet"><w:name w:val="List Bullet"/></w:style>
171
+ <w:style w:type="table" w:styleId="TableGrid">
172
+ <w:name w:val="Table Grid"/>
173
+ <w:tblPr>
174
+ <w:tblBorders>
175
+ <w:top w:val="single" w:sz="4" w:color="000000"/>
176
+ <w:left w:val="single" w:sz="4" w:color="000000"/>
177
+ <w:bottom w:val="single" w:sz="4" w:color="000000"/>
178
+ <w:right w:val="single" w:sz="4" w:color="000000"/>
179
+ <w:insideH w:val="single" w:sz="4" w:color="000000"/>
180
+ <w:insideV w:val="single" w:sz="4" w:color="000000"/>
181
+ </w:tblBorders>
182
+ </w:tblPr>
183
+ </w:style>
184
+ </w:styles>
185
+ `;
186
+ /**
187
+ * 生成完整 .docx 字节。title 渲染为封面页;markdown 为正文(章节合并内容)。
188
+ */
189
+ export function buildDocx(opts) {
190
+ const blocks = parseMarkdownBlocks(opts.markdown);
191
+ const body = [];
192
+ body.push(paragraphXml(opts.title, 'TitlePage'));
193
+ body.push(paragraphXml('本科毕业论文(设计)', 'Subtitle'));
194
+ body.push('<w:p/>');
195
+ for (const block of blocks)
196
+ body.push(blockXml(block));
197
+ const document = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
198
+ <w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
199
+ <w:body>
200
+ ${body.join('')}
201
+ <w:sectPr><w:pgSz w:w="11906" w:h="16838"/><w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440"/></w:sectPr>
202
+ </w:body>
203
+ </w:document>
204
+ `;
205
+ const entries = [
206
+ { name: '[Content_Types].xml', data: encoder.encode(CONTENT_TYPES) },
207
+ { name: '_rels/.rels', data: encoder.encode(ROOT_RELS) },
208
+ { name: 'word/document.xml', data: encoder.encode(document) },
209
+ { name: 'word/styles.xml', data: encoder.encode(STYLES) },
210
+ { name: 'word/_rels/document.xml.rels', data: encoder.encode(DOCUMENT_RELS) },
211
+ ];
212
+ return buildZip(entries);
213
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * 论文工作区布局与全部模板文件内容(DESIGN.md §5 的落地)。
3
+ *
4
+ * thesis_init 按此生成目录树;模板内容与技能包(plugin/skills/)保持一致。
5
+ * 本模块只依赖 Node 内置能力。
6
+ */
7
+ export interface LayoutFile {
8
+ /** 相对论文仓库根的路径(POSIX 分隔符)。 */
9
+ readonly path: string;
10
+ readonly content: string;
11
+ }
12
+ export interface LayoutOptions {
13
+ readonly title: string;
14
+ readonly date: string;
15
+ }
16
+ export declare function buildLayout(opts: LayoutOptions): LayoutFile[];
17
+ export interface ChapterMeta {
18
+ readonly file: string;
19
+ readonly title: string;
20
+ readonly outline: readonly string[];
21
+ readonly words: string;
22
+ /** 该章专属的 G2 验收要点。 */
23
+ readonly checklist: readonly string[];
24
+ }
25
+ export declare const CHAPTER_META: readonly ChapterMeta[];
26
+ export declare function chapterTemplate(n: number, meta: ChapterMeta): string;
27
+ /** 章节文件列表(供工具与测试使用)。 */
28
+ export declare const CHAPTER_FILES: readonly string[];
29
+ /** 按文件名(带或不带 .md 后缀)查找章节元数据。 */
30
+ export declare function chapterMetaFor(file: string): {
31
+ meta: ChapterMeta;
32
+ chapterNo: number;
33
+ } | undefined;
34
+ /**
35
+ * 章节"已撰写"判定(确定性):
36
+ * - 勾选过至少一项 G2 清单(- [x]),或
37
+ * - 正文 CJK 字数比模板脚手架多 100 字以上(模板只含大纲与写作要求)。
38
+ * 供 thesis_build / thesis_check / thesis_stylecheck 共用,
39
+ * 避免把未动笔的脚手架当正文处理。
40
+ */
41
+ export declare function isWrittenChapter(text: string, metaNo: number, meta: ChapterMeta): boolean;