novelws 1.2.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 (320) hide show
  1. package/CHANGELOG.md +161 -0
  2. package/LICENSE +22 -0
  3. package/README.md +372 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +50 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/check.d.ts +6 -0
  9. package/dist/commands/check.d.ts.map +1 -0
  10. package/dist/commands/check.js +32 -0
  11. package/dist/commands/check.js.map +1 -0
  12. package/dist/commands/init.d.ts +6 -0
  13. package/dist/commands/init.d.ts.map +1 -0
  14. package/dist/commands/init.js +160 -0
  15. package/dist/commands/init.js.map +1 -0
  16. package/dist/commands/plugin.d.ts +6 -0
  17. package/dist/commands/plugin.d.ts.map +1 -0
  18. package/dist/commands/plugin.js +135 -0
  19. package/dist/commands/plugin.js.map +1 -0
  20. package/dist/commands/upgrade.d.ts +6 -0
  21. package/dist/commands/upgrade.d.ts.map +1 -0
  22. package/dist/commands/upgrade.js +92 -0
  23. package/dist/commands/upgrade.js.map +1 -0
  24. package/dist/core/config.d.ts +72 -0
  25. package/dist/core/config.d.ts.map +1 -0
  26. package/dist/core/config.js +136 -0
  27. package/dist/core/config.js.map +1 -0
  28. package/dist/core/errors.d.ts +59 -0
  29. package/dist/core/errors.d.ts.map +1 -0
  30. package/dist/core/errors.js +125 -0
  31. package/dist/core/errors.js.map +1 -0
  32. package/dist/core/platform.d.ts +27 -0
  33. package/dist/core/platform.d.ts.map +1 -0
  34. package/dist/core/platform.js +75 -0
  35. package/dist/core/platform.js.map +1 -0
  36. package/dist/core/template.d.ts +35 -0
  37. package/dist/core/template.d.ts.map +1 -0
  38. package/dist/core/template.js +94 -0
  39. package/dist/core/template.js.map +1 -0
  40. package/dist/plugins/identifier.d.ts +13 -0
  41. package/dist/plugins/identifier.d.ts.map +1 -0
  42. package/dist/plugins/identifier.js +72 -0
  43. package/dist/plugins/identifier.js.map +1 -0
  44. package/dist/plugins/installers/base.d.ts +27 -0
  45. package/dist/plugins/installers/base.d.ts.map +1 -0
  46. package/dist/plugins/installers/base.js +30 -0
  47. package/dist/plugins/installers/base.js.map +1 -0
  48. package/dist/plugins/installers/github.d.ts +22 -0
  49. package/dist/plugins/installers/github.d.ts.map +1 -0
  50. package/dist/plugins/installers/github.js +133 -0
  51. package/dist/plugins/installers/github.js.map +1 -0
  52. package/dist/plugins/installers/local.d.ts +16 -0
  53. package/dist/plugins/installers/local.d.ts.map +1 -0
  54. package/dist/plugins/installers/local.js +69 -0
  55. package/dist/plugins/installers/local.js.map +1 -0
  56. package/dist/plugins/installers/npm.d.ts +20 -0
  57. package/dist/plugins/installers/npm.d.ts.map +1 -0
  58. package/dist/plugins/installers/npm.js +99 -0
  59. package/dist/plugins/installers/npm.js.map +1 -0
  60. package/dist/plugins/manager.d.ts +77 -0
  61. package/dist/plugins/manager.d.ts.map +1 -0
  62. package/dist/plugins/manager.js +349 -0
  63. package/dist/plugins/manager.js.map +1 -0
  64. package/dist/plugins/registry.d.ts +48 -0
  65. package/dist/plugins/registry.d.ts.map +1 -0
  66. package/dist/plugins/registry.js +111 -0
  67. package/dist/plugins/registry.js.map +1 -0
  68. package/dist/plugins/types.d.ts +66 -0
  69. package/dist/plugins/types.d.ts.map +1 -0
  70. package/dist/plugins/types.js +2 -0
  71. package/dist/plugins/types.js.map +1 -0
  72. package/dist/plugins/validator.d.ts +19 -0
  73. package/dist/plugins/validator.d.ts.map +1 -0
  74. package/dist/plugins/validator.js +164 -0
  75. package/dist/plugins/validator.js.map +1 -0
  76. package/dist/utils/logger.d.ts +13 -0
  77. package/dist/utils/logger.d.ts.map +1 -0
  78. package/dist/utils/logger.js +48 -0
  79. package/dist/utils/logger.js.map +1 -0
  80. package/dist/utils/project.d.ts +24 -0
  81. package/dist/utils/project.d.ts.map +1 -0
  82. package/dist/utils/project.js +61 -0
  83. package/dist/utils/project.js.map +1 -0
  84. package/dist/version.d.ts +3 -0
  85. package/dist/version.d.ts.map +1 -0
  86. package/dist/version.js +21 -0
  87. package/dist/version.js.map +1 -0
  88. package/package.json +76 -0
  89. package/plugins/authentic-voice/README.md +31 -0
  90. package/plugins/authentic-voice/commands/authentic-voice.md +73 -0
  91. package/plugins/authentic-voice/commands/authenticity-audit.md +37 -0
  92. package/plugins/authentic-voice/config.yaml +30 -0
  93. package/plugins/authentic-voice/experts/authentic-editor.md +27 -0
  94. package/plugins/export/README.md +319 -0
  95. package/plugins/export/commands/export.md +460 -0
  96. package/plugins/export/commands/generate-cover.md +256 -0
  97. package/plugins/export/commands/metadata.md +309 -0
  98. package/plugins/export/config.yaml +47 -0
  99. package/plugins/export/experts/publishing-expert.md +171 -0
  100. package/plugins/export/templates/epub/chapter-template.html +13 -0
  101. package/plugins/export/templates/epub/cover-template.html +14 -0
  102. package/plugins/export/templates/epub/stylesheet.css +200 -0
  103. package/plugins/export/templates/pdf/ebook-style.css +137 -0
  104. package/plugins/export/templates/pdf/print-style.css +179 -0
  105. package/plugins/export/templates/platforms/jinjiang-format.md +101 -0
  106. package/plugins/export/templates/platforms/qidian-format.md +108 -0
  107. package/plugins/export/templates/platforms/tomato-format.md +95 -0
  108. package/plugins/translate/README.md +265 -0
  109. package/plugins/translate/commands/glossary.md +731 -0
  110. package/plugins/translate/commands/translate-preview.md +543 -0
  111. package/plugins/translate/commands/translate.md +649 -0
  112. package/plugins/translate/config.yaml +43 -0
  113. package/plugins/translate/experts/literary-translator.md +605 -0
  114. package/templates/commands/analyze.md +1485 -0
  115. package/templates/commands/checklist.md +434 -0
  116. package/templates/commands/clarify.md +257 -0
  117. package/templates/commands/constitution.md +257 -0
  118. package/templates/commands/expert.md +136 -0
  119. package/templates/commands/plan.md +749 -0
  120. package/templates/commands/recap.md +613 -0
  121. package/templates/commands/relations.md +96 -0
  122. package/templates/commands/revise.md +341 -0
  123. package/templates/commands/specify.md +682 -0
  124. package/templates/commands/tasks.md +142 -0
  125. package/templates/commands/timeline.md +73 -0
  126. package/templates/commands/track-init.md +137 -0
  127. package/templates/commands/track.md +463 -0
  128. package/templates/commands/write.md +1264 -0
  129. package/templates/config/keyword-mappings.json +106 -0
  130. package/templates/knowledge/audit-config.json +26 -0
  131. package/templates/knowledge/character-profiles.md +152 -0
  132. package/templates/knowledge/character-voices.md +137 -0
  133. package/templates/knowledge/locations.md +184 -0
  134. package/templates/knowledge/world-setting.md +121 -0
  135. package/templates/knowledge-base/README.md +285 -0
  136. package/templates/knowledge-base/character-archetypes/01-hero.md +233 -0
  137. package/templates/knowledge-base/character-archetypes/02-mentor.md +177 -0
  138. package/templates/knowledge-base/character-archetypes/03-shadow.md +221 -0
  139. package/templates/knowledge-base/character-archetypes/04-ally.md +178 -0
  140. package/templates/knowledge-base/character-archetypes/05-shapeshifter.md +177 -0
  141. package/templates/knowledge-base/character-archetypes/06-trickster.md +181 -0
  142. package/templates/knowledge-base/character-archetypes/07-threshold-guardian.md +177 -0
  143. package/templates/knowledge-base/character-archetypes/08-herald.md +180 -0
  144. package/templates/knowledge-base/character-archetypes/09-father.md +249 -0
  145. package/templates/knowledge-base/character-archetypes/10-mother.md +202 -0
  146. package/templates/knowledge-base/character-archetypes/11-child.md +183 -0
  147. package/templates/knowledge-base/character-archetypes/12-sage.md +202 -0
  148. package/templates/knowledge-base/character-archetypes/README.md +60 -0
  149. package/templates/knowledge-base/character-archetypes/application-guide.md +222 -0
  150. package/templates/knowledge-base/character-archetypes/archetype-combinations.md +242 -0
  151. package/templates/knowledge-base/character-archetypes/config.yaml +28 -0
  152. package/templates/knowledge-base/character-archetypes/examples-analysis.md +223 -0
  153. package/templates/knowledge-base/craft/character-arc.md +1153 -0
  154. package/templates/knowledge-base/craft/dialogue.md +1170 -0
  155. package/templates/knowledge-base/craft/pacing.md +1200 -0
  156. package/templates/knowledge-base/craft/scene-structure.md +1136 -0
  157. package/templates/knowledge-base/craft/show-not-tell.md +1012 -0
  158. package/templates/knowledge-base/emotional-beats/01-first-meeting.md +145 -0
  159. package/templates/knowledge-base/emotional-beats/02-bonding-moment.md +226 -0
  160. package/templates/knowledge-base/emotional-beats/03-declaration.md +284 -0
  161. package/templates/knowledge-base/emotional-beats/04-triumph.md +240 -0
  162. package/templates/knowledge-base/emotional-beats/05-reunion.md +396 -0
  163. package/templates/knowledge-base/emotional-beats/06-forgiveness.md +204 -0
  164. package/templates/knowledge-base/emotional-beats/07-betrayal.md +204 -0
  165. package/templates/knowledge-base/emotional-beats/08-loss.md +214 -0
  166. package/templates/knowledge-base/emotional-beats/09-rejection.md +254 -0
  167. package/templates/knowledge-base/emotional-beats/10-failure.md +244 -0
  168. package/templates/knowledge-base/emotional-beats/11-misunderstanding.md +205 -0
  169. package/templates/knowledge-base/emotional-beats/12-farewell.md +283 -0
  170. package/templates/knowledge-base/emotional-beats/13-revelation.md +242 -0
  171. package/templates/knowledge-base/emotional-beats/14-point-of-no-return.md +215 -0
  172. package/templates/knowledge-base/emotional-beats/15-dark-night.md +244 -0
  173. package/templates/knowledge-base/emotional-beats/16-sacrifice.md +246 -0
  174. package/templates/knowledge-base/emotional-beats/17-awakening.md +246 -0
  175. package/templates/knowledge-base/emotional-beats/18-confrontation.md +217 -0
  176. package/templates/knowledge-base/emotional-beats/19-bittersweet-goodbye.md +368 -0
  177. package/templates/knowledge-base/emotional-beats/20-moral-dilemma.md +248 -0
  178. package/templates/knowledge-base/emotional-beats/21-temptation.md +240 -0
  179. package/templates/knowledge-base/emotional-beats/22-redemption.md +210 -0
  180. package/templates/knowledge-base/emotional-beats/README.md +104 -0
  181. package/templates/knowledge-base/emotional-beats/beat-sequences.md +276 -0
  182. package/templates/knowledge-base/emotional-beats/config.yaml +30 -0
  183. package/templates/knowledge-base/emotional-beats/pacing-guide.md +390 -0
  184. package/templates/knowledge-base/genres/historical.md +1127 -0
  185. package/templates/knowledge-base/genres/mystery.md +1123 -0
  186. package/templates/knowledge-base/genres/revenge.md +846 -0
  187. package/templates/knowledge-base/genres/romance.md +948 -0
  188. package/templates/knowledge-base/genres/sci-fi.md +156 -0
  189. package/templates/knowledge-base/genres/thriller.md +166 -0
  190. package/templates/knowledge-base/genres/wuxia.md +143 -0
  191. package/templates/knowledge-base/references/README.md +96 -0
  192. package/templates/knowledge-base/references/china-1920s/culture.md +423 -0
  193. package/templates/knowledge-base/references/china-1920s/daily-life.md +616 -0
  194. package/templates/knowledge-base/references/china-1920s/overview.md +298 -0
  195. package/templates/knowledge-base/references/china-1920s/society.md +703 -0
  196. package/templates/knowledge-base/references/china-1920s/warlords.md +427 -0
  197. package/templates/knowledge-base/references/cultivation-world/daily-life.md +108 -0
  198. package/templates/knowledge-base/references/cultivation-world/overview.md +64 -0
  199. package/templates/knowledge-base/references/cultivation-world/power-system.md +108 -0
  200. package/templates/knowledge-base/references/cultivation-world/sects.md +104 -0
  201. package/templates/knowledge-base/references/cultivation-world/world-setting.md +108 -0
  202. package/templates/knowledge-base/references/modern-workplace/corporate.md +115 -0
  203. package/templates/knowledge-base/references/modern-workplace/daily-life.md +129 -0
  204. package/templates/knowledge-base/references/modern-workplace/overview.md +73 -0
  205. package/templates/knowledge-base/references/modern-workplace/relationships.md +107 -0
  206. package/templates/knowledge-base/references/modern-workplace/tech-industry.md +131 -0
  207. package/templates/knowledge-base/references/tang-dynasty/culture.md +135 -0
  208. package/templates/knowledge-base/references/tang-dynasty/daily-life.md +139 -0
  209. package/templates/knowledge-base/references/tang-dynasty/overview.md +76 -0
  210. package/templates/knowledge-base/references/tang-dynasty/politics.md +121 -0
  211. package/templates/knowledge-base/references/tang-dynasty/society.md +126 -0
  212. package/templates/knowledge-base/requirements/README.md +240 -0
  213. package/templates/knowledge-base/requirements/anti-ai-v3.md +46 -0
  214. package/templates/knowledge-base/requirements/anti-ai-v4.md +430 -0
  215. package/templates/knowledge-base/requirements/fast-paced.md +552 -0
  216. package/templates/knowledge-base/requirements/no-poison.md +60 -0
  217. package/templates/knowledge-base/requirements/romance-angst.md +102 -0
  218. package/templates/knowledge-base/requirements/romance-sweet.md +63 -0
  219. package/templates/knowledge-base/requirements/serious-literature.md +45 -0
  220. package/templates/knowledge-base/requirements/strong-emotion.md +60 -0
  221. package/templates/knowledge-base/styles/README.md +302 -0
  222. package/templates/knowledge-base/styles/ancient-style.md +579 -0
  223. package/templates/knowledge-base/styles/literary.md +439 -0
  224. package/templates/knowledge-base/styles/minimal.md +472 -0
  225. package/templates/knowledge-base/styles/natural-voice.md +930 -0
  226. package/templates/knowledge-base/styles/web-novel.md +525 -0
  227. package/templates/memory/constitution.md +140 -0
  228. package/templates/memory/personal-voice.md +113 -0
  229. package/templates/scripts/README.md +187 -0
  230. package/templates/scripts/bash/analyze-story.sh +170 -0
  231. package/templates/scripts/bash/check-consistency.sh +463 -0
  232. package/templates/scripts/bash/check-plot.sh +374 -0
  233. package/templates/scripts/bash/check-timeline.sh +346 -0
  234. package/templates/scripts/bash/check-world.sh +395 -0
  235. package/templates/scripts/bash/check-writing-state.sh +854 -0
  236. package/templates/scripts/bash/clarify-story.sh +117 -0
  237. package/templates/scripts/bash/common.sh +151 -0
  238. package/templates/scripts/bash/constitution.sh +114 -0
  239. package/templates/scripts/bash/generate-tasks.sh +65 -0
  240. package/templates/scripts/bash/init-tracking.sh +183 -0
  241. package/templates/scripts/bash/manage-relations.sh +174 -0
  242. package/templates/scripts/bash/plan-story.sh +100 -0
  243. package/templates/scripts/bash/specify-story.sh +93 -0
  244. package/templates/scripts/bash/tasks-story.sh +96 -0
  245. package/templates/scripts/bash/test-word-count.sh +182 -0
  246. package/templates/scripts/bash/tests/bench-preload-cache.sh +100 -0
  247. package/templates/scripts/bash/tests/run-all-benchmarks.sh +16 -0
  248. package/templates/scripts/bash/tests/test-cache-semantics.sh +199 -0
  249. package/templates/scripts/bash/tests/test-cross-platform.sh +35 -0
  250. package/templates/scripts/bash/tests/test-edge-cases-bash.sh +60 -0
  251. package/templates/scripts/bash/tests/test-phase1-bash.sh +28 -0
  252. package/templates/scripts/bash/tests/test-preload-cache.sh +123 -0
  253. package/templates/scripts/bash/tests/test-regex-precompile.sh +89 -0
  254. package/templates/scripts/bash/tests/test-regression-bash.sh +42 -0
  255. package/templates/scripts/bash/tests/test-task6-verification.sh +200 -0
  256. package/templates/scripts/bash/text-audit.sh +144 -0
  257. package/templates/scripts/bash/track-progress.sh +194 -0
  258. package/templates/scripts/powershell/analyze-story.ps1 +171 -0
  259. package/templates/scripts/powershell/check-analyze-stage.ps1 +110 -0
  260. package/templates/scripts/powershell/check-consistency.ps1 +138 -0
  261. package/templates/scripts/powershell/check-plot.ps1 +139 -0
  262. package/templates/scripts/powershell/check-timeline.ps1 +112 -0
  263. package/templates/scripts/powershell/check-writing-state.ps1 +490 -0
  264. package/templates/scripts/powershell/check-writing-state.ps1.backup +135 -0
  265. package/templates/scripts/powershell/clarify-story.ps1 +107 -0
  266. package/templates/scripts/powershell/common.ps1 +36 -0
  267. package/templates/scripts/powershell/constitution.ps1 +142 -0
  268. package/templates/scripts/powershell/generate-tasks.ps1 +75 -0
  269. package/templates/scripts/powershell/init-tracking.ps1 +98 -0
  270. package/templates/scripts/powershell/manage-relations.ps1 +134 -0
  271. package/templates/scripts/powershell/plan-story.ps1 +96 -0
  272. package/templates/scripts/powershell/specify-story.ps1 +82 -0
  273. package/templates/scripts/powershell/tests/bench-ps-cache.ps1 +80 -0
  274. package/templates/scripts/powershell/tests/test-cross-platform.ps1 +27 -0
  275. package/templates/scripts/powershell/tests/test-edge-cases-ps.ps1 +29 -0
  276. package/templates/scripts/powershell/tests/test-phase1-ps.ps1 +28 -0
  277. package/templates/scripts/powershell/tests/test-ps-cache.ps1 +73 -0
  278. package/templates/scripts/powershell/tests/test-regression-ps.ps1 +40 -0
  279. package/templates/scripts/powershell/text-audit.ps1 +100 -0
  280. package/templates/scripts/powershell/track-progress.ps1 +105 -0
  281. package/templates/skills/genre-knowledge/fantasy/SKILL.md +355 -0
  282. package/templates/skills/genre-knowledge/mystery/SKILL.md +337 -0
  283. package/templates/skills/genre-knowledge/romance/SKILL.md +228 -0
  284. package/templates/skills/genre-knowledge/sci-fi/SKILL.md +65 -0
  285. package/templates/skills/genre-knowledge/thriller/SKILL.md +95 -0
  286. package/templates/skills/quality-assurance/consistency-checker/SKILL.md +341 -0
  287. package/templates/skills/quality-assurance/continuity-tracker/SKILL.md +157 -0
  288. package/templates/skills/quality-assurance/forgotten-elements/SKILL.md +147 -0
  289. package/templates/skills/quality-assurance/getting-started/SKILL.md +224 -0
  290. package/templates/skills/quality-assurance/pacing-monitor/SKILL.md +143 -0
  291. package/templates/skills/quality-assurance/pov-validator/SKILL.md +135 -0
  292. package/templates/skills/quality-assurance/pre-write-checklist/SKILL.md +583 -0
  293. package/templates/skills/quality-assurance/requirement-detector/CONFLICT_RESOLUTION.md +119 -0
  294. package/templates/skills/quality-assurance/requirement-detector/EXAMPLES.md +146 -0
  295. package/templates/skills/quality-assurance/requirement-detector/KEYWORDS.md +160 -0
  296. package/templates/skills/quality-assurance/requirement-detector/SKILL.md +149 -0
  297. package/templates/skills/quality-assurance/setting-detector/SKILL.md +611 -0
  298. package/templates/skills/quality-assurance/style-detector/CONFLICT_RESOLUTION.md +126 -0
  299. package/templates/skills/quality-assurance/style-detector/EXAMPLES.md +206 -0
  300. package/templates/skills/quality-assurance/style-detector/KEYWORDS.md +207 -0
  301. package/templates/skills/quality-assurance/style-detector/SKILL.md +126 -0
  302. package/templates/skills/quality-assurance/workflow-guide/SKILL.md +381 -0
  303. package/templates/skills/writing-techniques/character-arc/SKILL.md +267 -0
  304. package/templates/skills/writing-techniques/dialogue-techniques/SKILL.md +366 -0
  305. package/templates/skills/writing-techniques/multi-thread-narrative/SKILL.md +553 -0
  306. package/templates/skills/writing-techniques/multi-thread-narrative/experts/thread-analyst.md +226 -0
  307. package/templates/skills/writing-techniques/pacing-control/SKILL.md +377 -0
  308. package/templates/skills/writing-techniques/reader-expectation/SKILL.md +578 -0
  309. package/templates/skills/writing-techniques/reader-expectation/experts/expectation-analyst.md +209 -0
  310. package/templates/skills/writing-techniques/revision-polish/SKILL.md +496 -0
  311. package/templates/skills/writing-techniques/revision-polish/experts/revision-editor.md +221 -0
  312. package/templates/skills/writing-techniques/scene-structure/SKILL.md +361 -0
  313. package/templates/skills/writing-techniques/style-learning/SKILL.md +436 -0
  314. package/templates/specification-example.md +146 -0
  315. package/templates/tracking/character-state.json +78 -0
  316. package/templates/tracking/plot-tracker.json +62 -0
  317. package/templates/tracking/relationships.json +70 -0
  318. package/templates/tracking/timeline.json +49 -0
  319. package/templates/tracking/tracking-log.md +110 -0
  320. package/templates/tracking/validation-rules.json +128 -0
@@ -0,0 +1,164 @@
1
+ /**
2
+ * 插件验证器
3
+ *
4
+ * 验证插件目录结构和 config.yaml 内容。
5
+ * 增强:schema 校验、运行时类型检查、文件名合法性验证。
6
+ */
7
+ import fs from 'fs-extra';
8
+ import path from 'path';
9
+ import yaml from 'js-yaml';
10
+ /** 合法的插件类型 */
11
+ const VALID_PLUGIN_TYPES = ['feature', 'expert', 'workflow'];
12
+ /** 检查 ID 是否为合法文件名 */
13
+ function isValidId(id) {
14
+ return /^[\w-]+$/.test(id);
15
+ }
16
+ export class PluginValidator {
17
+ /**
18
+ * 验证插件目录
19
+ */
20
+ static async validate(pluginPath) {
21
+ const result = {
22
+ valid: true,
23
+ errors: [],
24
+ warnings: [],
25
+ };
26
+ // 1. 检查 config.yaml 存在
27
+ const configPath = path.join(pluginPath, 'config.yaml');
28
+ if (!await fs.pathExists(configPath)) {
29
+ result.valid = false;
30
+ result.errors.push('config.yaml 未找到');
31
+ return result;
32
+ }
33
+ // 2. 解析 YAML
34
+ let rawConfig;
35
+ try {
36
+ const content = await fs.readFile(configPath, 'utf-8');
37
+ rawConfig = yaml.load(content);
38
+ }
39
+ catch {
40
+ result.valid = false;
41
+ result.errors.push('config.yaml 不是有效的 YAML 格式');
42
+ return result;
43
+ }
44
+ if (!rawConfig || typeof rawConfig !== 'object') {
45
+ result.valid = false;
46
+ result.errors.push('config.yaml 内容为空或无效');
47
+ return result;
48
+ }
49
+ const config = rawConfig;
50
+ // 3. 验证必填字段
51
+ if (!config.name || typeof config.name !== 'string') {
52
+ result.valid = false;
53
+ result.errors.push('config.yaml 缺少必填字段: name');
54
+ }
55
+ if (!config.version || typeof config.version !== 'string') {
56
+ result.warnings.push('config.yaml 缺少 version 字段');
57
+ }
58
+ if (!config.description || typeof config.description !== 'string') {
59
+ result.warnings.push('config.yaml 缺少 description 字段');
60
+ }
61
+ // 4. 验证 type 字段
62
+ if (config.type) {
63
+ if (typeof config.type !== 'string' || !VALID_PLUGIN_TYPES.includes(config.type)) {
64
+ result.warnings.push(`config.yaml 的 type 字段无效: "${config.type}",有效值: ${VALID_PLUGIN_TYPES.join(', ')}`);
65
+ }
66
+ }
67
+ // 5. 验证命令声明
68
+ if (config.commands) {
69
+ if (!Array.isArray(config.commands)) {
70
+ result.valid = false;
71
+ result.errors.push('config.yaml 的 commands 字段必须是数组');
72
+ }
73
+ else {
74
+ for (const cmd of config.commands) {
75
+ if (!cmd || typeof cmd !== 'object') {
76
+ result.errors.push('commands 数组中包含无效条目');
77
+ result.valid = false;
78
+ continue;
79
+ }
80
+ const cmdObj = cmd;
81
+ if (!cmdObj.id || typeof cmdObj.id !== 'string') {
82
+ result.errors.push('命令缺少 id 字段');
83
+ result.valid = false;
84
+ }
85
+ else if (!isValidId(cmdObj.id)) {
86
+ result.errors.push(`命令 ID 不合法: "${cmdObj.id}"(只允许字母、数字、下划线、连字符)`);
87
+ result.valid = false;
88
+ }
89
+ // 检查命令文件是否存在
90
+ const cmdFile = cmdObj.file || `${cmdObj.id || 'unknown'}.md`;
91
+ const cmdPath = path.join(pluginPath, cmdFile);
92
+ if (!await fs.pathExists(cmdPath)) {
93
+ result.warnings.push(`声明的命令文件不存在: ${cmdFile}`);
94
+ }
95
+ }
96
+ }
97
+ }
98
+ // 6. 验证 Skills 声明
99
+ if (config.skills) {
100
+ if (!Array.isArray(config.skills)) {
101
+ result.valid = false;
102
+ result.errors.push('config.yaml 的 skills 字段必须是数组');
103
+ }
104
+ else {
105
+ for (const skill of config.skills) {
106
+ if (!skill || typeof skill !== 'object') {
107
+ result.errors.push('skills 数组中包含无效条目');
108
+ result.valid = false;
109
+ continue;
110
+ }
111
+ const skillObj = skill;
112
+ if (!skillObj.id || typeof skillObj.id !== 'string') {
113
+ result.errors.push('Skill 缺少 id 字段');
114
+ result.valid = false;
115
+ }
116
+ else if (!isValidId(skillObj.id)) {
117
+ result.errors.push(`Skill ID 不合法: "${skillObj.id}"(只允许字母、数字、下划线、连字符)`);
118
+ result.valid = false;
119
+ }
120
+ // 检查 Skill 文件是否存在
121
+ const skillFile = skillObj.file || path.join('skills', String(skillObj.id || 'unknown'), 'SKILL.md');
122
+ const skillPath = path.join(pluginPath, skillFile);
123
+ if (!await fs.pathExists(skillPath)) {
124
+ result.warnings.push(`声明的 Skill 文件不存在: ${skillFile}`);
125
+ }
126
+ }
127
+ }
128
+ }
129
+ return result;
130
+ }
131
+ /**
132
+ * 安全解析 config.yaml 为 PluginConfig
133
+ * 返回 null 表示解析失败
134
+ */
135
+ static async parseConfig(configPath) {
136
+ try {
137
+ const content = await fs.readFile(configPath, 'utf-8');
138
+ const raw = yaml.load(content);
139
+ if (!raw || typeof raw !== 'object') {
140
+ return null;
141
+ }
142
+ const config = raw;
143
+ if (!config.name || typeof config.name !== 'string') {
144
+ return null;
145
+ }
146
+ return {
147
+ name: config.name,
148
+ version: typeof config.version === 'string' ? config.version : '0.0.0',
149
+ description: typeof config.description === 'string' ? config.description : '',
150
+ type: VALID_PLUGIN_TYPES.includes(config.type)
151
+ ? config.type
152
+ : 'feature',
153
+ commands: Array.isArray(config.commands) ? config.commands : undefined,
154
+ skills: Array.isArray(config.skills) ? config.skills : undefined,
155
+ dependencies: config.dependencies,
156
+ installation: config.installation,
157
+ };
158
+ }
159
+ catch {
160
+ return null;
161
+ }
162
+ }
163
+ }
164
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/plugins/validator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,IAAI,MAAM,SAAS,CAAC;AAG3B,cAAc;AACd,MAAM,kBAAkB,GAAG,CAAC,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;AAE7D,qBAAqB;AACrB,SAAS,SAAS,CAAC,EAAU;IAC3B,OAAO,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,OAAO,eAAe;IAC1B;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAkB;QACtC,MAAM,MAAM,GAAqB;YAC/B,KAAK,EAAE,IAAI;YACX,MAAM,EAAE,EAAE;YACV,QAAQ,EAAE,EAAE;SACb,CAAC;QAEF,uBAAuB;QACvB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;QACxD,IAAI,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YACrC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;YACrB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YACtC,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,aAAa;QACb,IAAI,SAAkB,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACvD,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;YACrB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;YAChD,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,IAAI,CAAC,SAAS,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;YAChD,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;YACrB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YAC1C,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,MAAM,GAAG,SAAoC,CAAC;QAEpD,YAAY;QACZ,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACpD,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;YACrB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACjD,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC1D,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QACpD,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;YAClE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QACxD,CAAC;QAED,gBAAgB;QAChB,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjF,MAAM,CAAC,QAAQ,CAAC,IAAI,CAClB,6BAA6B,MAAM,CAAC,IAAI,UAAU,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAClF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,YAAY;QACZ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACpB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;gBACrB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;YACvD,CAAC;iBAAM,CAAC;gBACN,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;oBAClC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;wBACpC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;wBACzC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;wBACrB,SAAS;oBACX,CAAC;oBAED,MAAM,MAAM,GAAG,GAA8B,CAAC;oBAE9C,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;wBAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;wBACjC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;oBACvB,CAAC;yBAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;wBACjC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,MAAM,CAAC,EAAE,qBAAqB,CAAC,CAAC;wBAClE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;oBACvB,CAAC;oBAED,aAAa;oBACb,MAAM,OAAO,GAAI,MAAM,CAAC,IAAe,IAAI,GAAG,MAAM,CAAC,EAAE,IAAI,SAAS,KAAK,CAAC;oBAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;oBAC/C,IAAI,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;wBAClC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC;oBACjD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,kBAAkB;QAClB,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;gBACrB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;YACrD,CAAC;iBAAM,CAAC;gBACN,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAClC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;wBACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;wBACvC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;wBACrB,SAAS;oBACX,CAAC;oBAED,MAAM,QAAQ,GAAG,KAAgC,CAAC;oBAElD,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,OAAO,QAAQ,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;wBACpD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;wBACrC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;oBACvB,CAAC;yBAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;wBACnC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,QAAQ,CAAC,EAAE,qBAAqB,CAAC,CAAC;wBACvE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;oBACvB,CAAC;oBAED,kBAAkB;oBAClB,MAAM,SAAS,GAAI,QAAQ,CAAC,IAAe,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,SAAS,CAAC,EAAE,UAAU,CAAC,CAAC;oBACjH,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;oBACnD,IAAI,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;wBACpC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,oBAAoB,SAAS,EAAE,CAAC,CAAC;oBACxD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,UAAkB;QACzC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE/B,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACpC,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,MAAM,GAAG,GAA8B,CAAC;YAE9C,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACpD,OAAO,IAAI,CAAC;YACd,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,OAAO,EAAE,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO;gBACtE,WAAW,EAAE,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;gBAC7E,IAAI,EAAE,kBAAkB,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAc,CAAC;oBACtD,CAAC,CAAE,MAAM,CAAC,IAA6B;oBACvC,CAAC,CAAC,SAAS;gBACb,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAoC,CAAC,CAAC,CAAC,SAAS;gBAClG,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAgC,CAAC,CAAC,CAAC,SAAS;gBAC1F,YAAY,EAAE,MAAM,CAAC,YAA4C;gBACjE,YAAY,EAAE,MAAM,CAAC,YAA4C;aAClE,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
2
+ export declare const logger: {
3
+ /** 设置日志级别 */
4
+ setLevel(level: LogLevel): void;
5
+ /** 获取当前日志级别 */
6
+ getLevel(): LogLevel;
7
+ info: (message: string, ...args: any[]) => void;
8
+ success: (message: string, ...args: any[]) => void;
9
+ warn: (message: string, ...args: any[]) => void;
10
+ error: (message: string, ...args: any[]) => void;
11
+ debug: (message: string, ...args: any[]) => void;
12
+ };
13
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AAgBtE,eAAO,MAAM,MAAM;IACjB,aAAa;oBACG,QAAQ,GAAG,IAAI;IAI/B,eAAe;gBACH,QAAQ;oBAIJ,MAAM,WAAW,GAAG,EAAE;uBAMnB,MAAM,WAAW,GAAG,EAAE;oBAMzB,MAAM,WAAW,GAAG,EAAE;qBAMrB,MAAM,WAAW,GAAG,EAAE;qBAMtB,MAAM,WAAW,GAAG,EAAE;CAKxC,CAAC"}
@@ -0,0 +1,48 @@
1
+ import chalk from 'chalk';
2
+ const LEVEL_PRIORITY = {
3
+ debug: 0,
4
+ info: 1,
5
+ warn: 2,
6
+ error: 3,
7
+ silent: 4,
8
+ };
9
+ let _currentLevel = 'info';
10
+ function shouldLog(level) {
11
+ return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[_currentLevel];
12
+ }
13
+ export const logger = {
14
+ /** 设置日志级别 */
15
+ setLevel(level) {
16
+ _currentLevel = level;
17
+ },
18
+ /** 获取当前日志级别 */
19
+ getLevel() {
20
+ return _currentLevel;
21
+ },
22
+ info: (message, ...args) => {
23
+ if (shouldLog('info')) {
24
+ console.log(chalk.blue('ℹ'), message, ...args);
25
+ }
26
+ },
27
+ success: (message, ...args) => {
28
+ if (shouldLog('info')) {
29
+ console.log(chalk.green('✓'), message, ...args);
30
+ }
31
+ },
32
+ warn: (message, ...args) => {
33
+ if (shouldLog('warn')) {
34
+ console.log(chalk.yellow('⚠'), message, ...args);
35
+ }
36
+ },
37
+ error: (message, ...args) => {
38
+ if (shouldLog('error')) {
39
+ console.log(chalk.red('✗'), message, ...args);
40
+ }
41
+ },
42
+ debug: (message, ...args) => {
43
+ if (shouldLog('debug') && process.env.DEBUG) {
44
+ console.log(chalk.gray('🐛'), message, ...args);
45
+ }
46
+ },
47
+ };
48
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,cAAc,GAA6B;IAC/C,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC;CACV,CAAC;AAEF,IAAI,aAAa,GAAa,MAAM,CAAC;AAErC,SAAS,SAAS,CAAC,KAAe;IAChC,OAAO,cAAc,CAAC,KAAK,CAAC,IAAI,cAAc,CAAC,aAAa,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,aAAa;IACb,QAAQ,CAAC,KAAe;QACtB,aAAa,GAAG,KAAK,CAAC;IACxB,CAAC;IAED,eAAe;IACf,QAAQ;QACN,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,IAAI,EAAE,CAAC,OAAe,EAAE,GAAG,IAAW,EAAE,EAAE;QACxC,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAED,OAAO,EAAE,CAAC,OAAe,EAAE,GAAG,IAAW,EAAE,EAAE;QAC3C,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,IAAI,EAAE,CAAC,OAAe,EAAE,GAAG,IAAW,EAAE,EAAE;QACxC,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,KAAK,EAAE,CAAC,OAAe,EAAE,GAAG,IAAW,EAAE,EAAE;QACzC,IAAI,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,KAAK,EAAE,CAAC,OAAe,EAAE,GAAG,IAAW,EAAE,EAAE;QACzC,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,24 @@
1
+ export interface ProjectInfo {
2
+ name: string;
3
+ version: string;
4
+ hasClaudeDir: boolean;
5
+ hasSpecifyDir: boolean;
6
+ hasStoriesDir: boolean;
7
+ }
8
+ /**
9
+ * 检测当前目录是否是 novel-writer-skills 项目
10
+ */
11
+ export declare function isProjectRoot(dir: string): Promise<boolean>;
12
+ /**
13
+ * 向上查找项目根目录
14
+ */
15
+ export declare function findProjectRoot(startDir?: string): Promise<string | null>;
16
+ /**
17
+ * 确保在项目根目录,否则抛出错误
18
+ */
19
+ export declare function ensureProjectRoot(): Promise<string>;
20
+ /**
21
+ * 获取项目信息
22
+ */
23
+ export declare function getProjectInfo(projectPath: string): Promise<ProjectInfo | null>;
24
+ //# sourceMappingURL=project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/utils/project.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGjE;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiB9F;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAQzD;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAoBrF"}
@@ -0,0 +1,61 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { DIRS, FILES } from '../core/config.js';
4
+ import { ProjectNotFoundError } from '../core/errors.js';
5
+ /**
6
+ * 检测当前目录是否是 novel-writer-skills 项目
7
+ */
8
+ export async function isProjectRoot(dir) {
9
+ const configPath = path.join(dir, DIRS.SPECIFY, FILES.CONFIG);
10
+ return await fs.pathExists(configPath);
11
+ }
12
+ /**
13
+ * 向上查找项目根目录
14
+ */
15
+ export async function findProjectRoot(startDir = process.cwd()) {
16
+ let currentDir = startDir;
17
+ while (true) {
18
+ if (await isProjectRoot(currentDir)) {
19
+ return currentDir;
20
+ }
21
+ const parentDir = path.dirname(currentDir);
22
+ // 已到达文件系统根目录
23
+ if (parentDir === currentDir) {
24
+ return null;
25
+ }
26
+ currentDir = parentDir;
27
+ }
28
+ }
29
+ /**
30
+ * 确保在项目根目录,否则抛出错误
31
+ */
32
+ export async function ensureProjectRoot() {
33
+ const projectRoot = await findProjectRoot();
34
+ if (!projectRoot) {
35
+ throw new ProjectNotFoundError();
36
+ }
37
+ return projectRoot;
38
+ }
39
+ /**
40
+ * 获取项目信息
41
+ */
42
+ export async function getProjectInfo(projectPath) {
43
+ try {
44
+ const configPath = path.join(projectPath, DIRS.SPECIFY, FILES.CONFIG);
45
+ if (!await fs.pathExists(configPath)) {
46
+ return null;
47
+ }
48
+ const config = await fs.readJson(configPath);
49
+ return {
50
+ name: config.name || path.basename(projectPath),
51
+ version: config.version || 'unknown',
52
+ hasClaudeDir: await fs.pathExists(path.join(projectPath, DIRS.CLAUDE)),
53
+ hasSpecifyDir: await fs.pathExists(path.join(projectPath, DIRS.SPECIFY)),
54
+ hasStoriesDir: await fs.pathExists(path.join(projectPath, DIRS.STORIES)),
55
+ };
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
61
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/utils/project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAUzD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW;IAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9D,OAAO,MAAM,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;IACpE,IAAI,UAAU,GAAG,QAAQ,CAAC;IAE1B,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,MAAM,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;YACpC,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAE3C,aAAa;QACb,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,UAAU,GAAG,SAAS,CAAC;IACzB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,WAAW,GAAG,MAAM,eAAe,EAAE,CAAC;IAE5C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,oBAAoB,EAAE,CAAC;IACnC,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,WAAmB;IACtD,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAEtE,IAAI,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAE7C,OAAO;YACL,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;YAC/C,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,SAAS;YACpC,YAAY,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACtE,aAAa,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACxE,aAAa,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;SACzE,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function getVersion(): string;
2
+ export declare function getVersionInfo(): string;
3
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAMA,wBAAgB,UAAU,IAAI,MAAM,CAWnC;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC"}
@@ -0,0 +1,21 @@
1
+ import { readFileSync } from 'fs';
2
+ import path from 'path';
3
+ import { getPackageRoot } from './core/config.js';
4
+ let _cachedVersion = null;
5
+ export function getVersion() {
6
+ if (_cachedVersion)
7
+ return _cachedVersion;
8
+ try {
9
+ const packagePath = path.join(getPackageRoot(), 'package.json');
10
+ const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'));
11
+ _cachedVersion = packageJson.version;
12
+ return _cachedVersion;
13
+ }
14
+ catch {
15
+ return '1.0.0';
16
+ }
17
+ }
18
+ export function getVersionInfo() {
19
+ return `v${getVersion()}`;
20
+ }
21
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,IAAI,cAAc,GAAkB,IAAI,CAAC;AAEzC,MAAM,UAAU,UAAU;IACxB,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC;IAE1C,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,cAAc,CAAC,CAAC;QAChE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;QACnE,cAAc,GAAG,WAAW,CAAC,OAAO,CAAC;QACrC,OAAO,cAAe,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,IAAI,UAAU,EAAE,EAAE,CAAC;AAC5B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "novelws",
3
+ "version": "1.2.0",
4
+ "type": "module",
5
+ "description": "Claude Code 专用的 AI 小说创作工具 - 深度集成 Slash Commands 和 Agent Skills",
6
+ "keywords": [
7
+ "novel",
8
+ "writer",
9
+ "chinese",
10
+ "ai",
11
+ "creative-writing",
12
+ "claude",
13
+ "claude-code",
14
+ "agent-skills",
15
+ "小说",
16
+ "创作",
17
+ "写作"
18
+ ],
19
+ "author": "Novel Writer Team",
20
+ "license": "MIT",
21
+ "main": "dist/cli.js",
22
+ "bin": {
23
+ "novelws": "dist/cli.js"
24
+ },
25
+ "scripts": {
26
+ "build": "tsc",
27
+ "postbuild": "node -e \"try{require('fs').chmodSync('dist/cli.js',0o755)}catch{}\"",
28
+ "dev": "tsx src/cli.ts",
29
+ "start": "node dist/cli.js",
30
+ "clean": "rm -rf dist",
31
+ "prepare": "npm run build",
32
+ "test": "jest --config jest.config.cjs",
33
+ "test:watch": "jest --config jest.config.cjs --watch",
34
+ "test:coverage": "jest --config jest.config.cjs --coverage",
35
+ "test:unit": "jest --config jest.config.cjs tests/unit",
36
+ "test:integration": "jest --config jest.config.cjs tests/integration"
37
+ },
38
+ "dependencies": {
39
+ "@commander-js/extra-typings": "^12.0.0",
40
+ "chalk": "^5.3.0",
41
+ "fs-extra": "^11.2.0",
42
+ "inquirer": "^9.2.12",
43
+ "js-yaml": "^4.1.0",
44
+ "ora": "^8.0.1"
45
+ },
46
+ "devDependencies": {
47
+ "@types/fs-extra": "^11.0.4",
48
+ "@types/inquirer": "^9.0.9",
49
+ "@types/jest": "^30.0.0",
50
+ "@types/js-yaml": "^4.0.9",
51
+ "@types/node": "^20.10.0",
52
+ "jest": "^30.2.0",
53
+ "ts-jest": "^29.4.6",
54
+ "tsx": "^4.7.0",
55
+ "typescript": "^5.3.3"
56
+ },
57
+ "files": [
58
+ "dist",
59
+ "templates",
60
+ "plugins",
61
+ "README.md",
62
+ "LICENSE",
63
+ "CHANGELOG.md"
64
+ ],
65
+ "engines": {
66
+ "node": ">=18.0.0"
67
+ },
68
+ "repository": {
69
+ "type": "git",
70
+ "url": "git+https://github.com/binlee1990/novel-writer-skills.git"
71
+ },
72
+ "homepage": "https://github.com/binlee1990/novel-writer-skills#readme",
73
+ "bugs": {
74
+ "url": "https://github.com/binlee1990/novel-writer-skills/issues"
75
+ }
76
+ }
@@ -0,0 +1,31 @@
1
+ # Authentic Voice 插件
2
+
3
+ 让文字更像你自己写的:强调生活细节、口语节奏与个体词库的一致性。该插件聚焦“提升原创度与自然度”,不涉及也不用于任何检测规避场景
4
+
5
+ ## 安装
6
+
7
+ ```
8
+ novel plugins add authentic-voice
9
+ ```
10
+
11
+ ## 准备个人语料
12
+
13
+ 在 `.specify/memory/personal-voice.md` 中补全:
14
+ - 口头禅与常用表达
15
+ - 固定句式与节奏偏好
16
+ - 生活经历清单与行业/地域词汇
17
+ - 写作忌口与避讳
18
+ - 比喻口味与意象库
19
+
20
+ ## 常用命令
21
+
22
+ - `/authentic-voice` 启动真实人声写作,自动读取个人语料并在输出前给出“取材卡”
23
+ - `/authenticity-audit` 对既有文本做人味自查与改写建议
24
+ - `/expert authentic-editor` 召唤真实人声编辑专家,进行更细致的行级改写
25
+
26
+ ## 适用场景
27
+
28
+ - 正稿创作:需要稳态的个人风格与节奏
29
+ - 二次打磨:避免空话、模板化与节奏单一
30
+ - 长线项目:逐步沉淀个人词库与意象,形成稳定“作者指纹”
31
+
@@ -0,0 +1,73 @@
1
+ ---
2
+ title: 真实人声写作模式 - /authentic-voice
3
+ description: 以更贴近生活与个人表达的方式进行创作,强调具体细节、口语节奏与个体词汇
4
+ ---
5
+
6
+ # 真实人声写作模式
7
+
8
+ 目标:基于作者的生活经验与个人用语,输出自然、有细节、有温度的文字;避免模板化句式与空泛表达,保持叙述的节奏变化与真实思考过程
9
+
10
+ ## 使用方法
11
+
12
+ ```
13
+ /authentic-voice [可选参数]
14
+ ```
15
+
16
+ - `--tone <自由/克制/热烈/冷静>` 设定整体语气偏好,默认自由
17
+ - `--pace <慢/适中/快>` 控制叙述节奏,默认适中
18
+ - `--persona <file>` 指定个人语料文件,默认读取 `.specify/memory/personal-voice.md`
19
+
20
+ ## 输入准备
21
+
22
+ - 若存在 `.specify/memory/personal-voice.md`,在创作前读取该文件的要点:
23
+ - 口头禅与常用表达
24
+ - 固定句式与偏好节奏
25
+ - 生活经历清单与行业/地域词汇
26
+ - 写作忌口与避讳
27
+ - 比喻口味与意象库
28
+
29
+ 如果文件为空或缺失,以当前对话中提供的个人信息为准,并在输出开头提示需要完善个人语料
30
+
31
+ ## 写作要则
32
+
33
+ 请按以下方式组织创作:
34
+
35
+ - 具体细节优先:尽量用可感知的场景与动作替代抽象总结
36
+ - 节奏有起伏:段落长短交替,长段推进,短句落锤
37
+ - 真实思路:允许小范围犹疑、转折与补充,而不是一口气给出完美结构
38
+ - 口语混搭:语气词与书面语并存,但不要过度修饰
39
+ - 个体词库:自然使用作者在 personal-voice.md 中记录的用语与意象
40
+ - 避免空话:少用“众所周知、在某种程度、某种意义”这类虚化表达
41
+
42
+ ## 结构建议(可弹性使用)
43
+
44
+ ### 开头
45
+ - 由具体画面/细节入手,不讲大道理,先把人和事摆出来
46
+
47
+ ### 展开
48
+ - 以“一个细节→一个联想→一个判断”的节拍推进,可在熟悉话题里加入个人角度
49
+
50
+ ### 深入
51
+ - 说出自己真实的矛盾与拿不准之处,再给出现阶段可行的做法或更谨慎的表述
52
+
53
+ ### 收束
54
+ - 回到生活层面的落点,用一句朴素的话作结,留一点余味
55
+
56
+ ## 语言提示
57
+
58
+ - 混用长短句,口语为骨,书面为皮
59
+ - 对话尽量自然,保留个体口头禅,但避免滥用
60
+ - 少用模板连接词;根据语义自然转折
61
+ - 允许小瑕疵,但避免语义不清
62
+
63
+ ## 输出要求
64
+
65
+ - 先给出一小段“写作取材卡”,用 3-6 行列出:将要使用的个人词汇、生活细节与意象
66
+ - 之后输出正文,不插入执行过程解释
67
+
68
+ ## 若用户提供标题或主题
69
+
70
+ 当收到 `标题:...` 或明确主题时:
71
+ - 用“标题拆解→生活联想→叙述落点”三步在内部完成构思,再按上文要则直接写正文
72
+ - 若无个人语料,先尝试向用户询问一到两个能落地的小细节
73
+
@@ -0,0 +1,37 @@
1
+ ---
2
+ title: 人味自查与改写 - /authenticity-audit
3
+ description: 对现有文本做“人味”体检,给出可执行的微调与改写建议,提升自然度与个体风格一致性
4
+ ---
5
+
6
+ # 人味自查与改写
7
+
8
+ 目标:帮助作者发现文本中的模板化痕迹、空话与节奏单一的问题,并提供面向行/段落的微调建议。强调“更像你写的”,而非追求任何形式的检测规避
9
+
10
+ ## 使用方法
11
+
12
+ ```
13
+ /authenticity-audit
14
+
15
+ [粘贴需要检查的文本]
16
+ ```
17
+
18
+ ## 检查维度(给出计数与示例)
19
+
20
+ 若存在 `spec/knowledge/audit-config.json`,以其中的连接词、空话清单、句长阈值为准;否则使用内置默认规则
21
+
22
+ - 模板连接词密度:如“首先、其次、再者、总而言之”等的出现次数与替换建议
23
+ - 空泛表达:如“在某种程度、众所周知、众多领域”等,给出更具体的改写
24
+ - 句长方差:统计平均句长与方差,标记“连续长句”或“连续短句”的片段,并给出节奏打断/合并建议
25
+ - 陈词滥调:识别可替换的套话,提供两到三种更贴近内容的改写版本
26
+ - 抽象过载:提示哪些段落抽象名词密度过高,并建议补充可感知的细节
27
+ - 人设一致性:对比 `.specify/memory/personal-voice.md` 中的口头禅/词汇,标记缺失的“个体信号”并建议自然融入点
28
+
29
+ ## 改写输出
30
+
31
+ - 分段输出:原句 → 问题简述 → 微调版 → 更大胆的个人化版本
32
+ - 控制幅度:优先微调,尽量保留原意;仅在必要时提供更大幅度的改写
33
+ - 体例保持:不改变原文的文体与叙述角度,除非用户明确请求
34
+
35
+ ## 末尾建议卡片
36
+
37
+ - 给出 5-8 条“下次写作时可直接使用”的个体化提示,来源于本次文本暴露的问题
@@ -0,0 +1,30 @@
1
+ name: authentic-voice
2
+ version: 1.0.0
3
+ description: 真实人声写作插件——提升原创度、生活质感与个体声音一致性
4
+ type: feature
5
+ author: Novel Writer Community
6
+ commands:
7
+ - id: authentic-voice
8
+ file: commands/authentic-voice.md
9
+ description: 启动真实人声写作模式(基于个人语料与生活细节)
10
+ - id: authenticity-audit
11
+ file: commands/authenticity-audit.md
12
+ description: 对现有文本进行“人味”自查与改写建议
13
+ experts:
14
+ - id: authentic-editor
15
+ file: experts/authentic-editor.md
16
+ title: 真实人声编辑
17
+ description: 擅长将文本改写为更自然、更具生活细节的表达
18
+ dependencies:
19
+ core: ">=0.5.0"
20
+ installation:
21
+ message: |
22
+ ✅ 真实人声写作插件安装成功
23
+
24
+ 用法建议:
25
+ 1. 在 .specify/memory/personal-voice.md 中填写你的口头禅、常用句式、生活经历与行业词汇
26
+ 2. 在 AI 助手中使用 /authentic-voice 进入真实人声写作模式
27
+ 3. 对既有文本运行 /authenticity-audit 获取自查清单与修改建议
28
+
29
+ 目标:提升原创度、生活质感和你的个人表达一致性,帮助构建可信的人设与稳定文风
30
+
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: 真实人声编辑 - expert:authentic-editor
3
+ description: 将作者文本改得更自然、更具生活细节与个人表达一致性
4
+ ---
5
+
6
+ 作为“真实人声编辑”,你的职责是:
7
+
8
+ - 尊重作者意图与叙述视角,优先做微调
9
+ - 在不改变事实与逻辑的前提下,提高具体度与画面感
10
+ - 维持段落节奏的起伏,避免“一股脑儿”地规整
11
+ - 自然地融入个人语料中的词汇与口头禅
12
+ - 用可执行的行级建议帮助作者迭代
13
+
14
+ 工作流程:
15
+
16
+ 1. 读取 `.specify/memory/personal-voice.md`(如果存在)
17
+ 2. 对全文做一次“人味自查”,标记问题集中区
18
+ 3. 分段提出最小可行改动(保持原意)
19
+ 4. 对关键段落额外给出一个“更大胆”的改写版本供参考
20
+
21
+ 输出格式:
22
+
23
+ - 问题清单(带计数与示例)
24
+ - 行/段落级微调建议
25
+ - 关键段落改写对照
26
+ - 下一次写作提醒清单(5-8条)
27
+