principles-disciple 1.8.0 → 1.8.2

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 (460) hide show
  1. package/ADVANCED_CONFIG_ZH.md +97 -0
  2. package/AGENT_INSTALL.md +173 -0
  3. package/AGENT_INSTALL_EN.md +173 -0
  4. package/INSTALL.md +256 -0
  5. package/SKILL.md +63 -0
  6. package/docs/COMMAND_REFERENCE.md +76 -0
  7. package/docs/COMMAND_REFERENCE_EN.md +79 -0
  8. package/esbuild.config.js +75 -0
  9. package/openclaw.plugin.json +6 -1
  10. package/package.json +13 -15
  11. package/scripts/build-web.mjs +46 -0
  12. package/scripts/install-dependencies.cjs +47 -0
  13. package/scripts/sync-plugin.mjs +802 -0
  14. package/scripts/verify-build.mjs +109 -0
  15. package/src/agents/nocturnal-dreamer.md +152 -0
  16. package/src/agents/nocturnal-philosopher.md +138 -0
  17. package/src/agents/nocturnal-reflector.md +126 -0
  18. package/src/agents/nocturnal-scribe.md +164 -0
  19. package/src/commands/capabilities.ts +85 -0
  20. package/{dist/commands/context.js → src/commands/context.ts} +78 -38
  21. package/src/commands/evolution-status.ts +146 -0
  22. package/src/commands/export.ts +111 -0
  23. package/src/commands/focus.ts +533 -0
  24. package/src/commands/nocturnal-review.ts +311 -0
  25. package/src/commands/nocturnal-rollout.ts +763 -0
  26. package/src/commands/nocturnal-train.ts +1002 -0
  27. package/{dist/commands/pain.js → src/commands/pain.ts} +68 -49
  28. package/src/commands/principle-rollback.ts +27 -0
  29. package/{dist/commands/rollback.js → src/commands/rollback.ts} +44 -12
  30. package/src/commands/samples.ts +60 -0
  31. package/src/commands/strategy.ts +38 -0
  32. package/{dist/commands/thinking-os.js → src/commands/thinking-os.ts} +59 -36
  33. package/src/commands/workflow-debug.ts +128 -0
  34. package/{dist/config/defaults/runtime.js → src/config/defaults/runtime.ts} +12 -5
  35. package/src/config/errors.ts +163 -0
  36. package/{dist/config/index.d.ts → src/config/index.ts} +2 -1
  37. package/src/constants/diagnostician.ts +66 -0
  38. package/src/constants/tools.ts +62 -0
  39. package/src/core/adaptive-thresholds.ts +476 -0
  40. package/{dist/core/config-service.js → src/core/config-service.ts} +7 -4
  41. package/{dist/core/config.js → src/core/config.ts} +158 -46
  42. package/src/core/control-ui-db.ts +435 -0
  43. package/{dist/core/detection-funnel.js → src/core/detection-funnel.ts} +36 -21
  44. package/{dist/core/detection-service.js → src/core/detection-service.ts} +7 -4
  45. package/{dist/core/dictionary-service.js → src/core/dictionary-service.ts} +7 -4
  46. package/{dist/core/dictionary.js → src/core/dictionary.ts} +57 -34
  47. package/src/core/empathy-keyword-matcher.ts +327 -0
  48. package/src/core/empathy-types.ts +218 -0
  49. package/src/core/event-log.ts +544 -0
  50. package/src/core/evolution-engine.ts +612 -0
  51. package/src/core/evolution-logger.ts +353 -0
  52. package/src/core/evolution-migration.ts +77 -0
  53. package/src/core/evolution-reducer.ts +731 -0
  54. package/src/core/evolution-types.ts +456 -0
  55. package/src/core/external-training-contract.ts +527 -0
  56. package/src/core/focus-history.ts +1458 -0
  57. package/src/core/hygiene/tracker.ts +117 -0
  58. package/{dist/core/init.js → src/core/init.ts} +39 -26
  59. package/src/core/local-worker-routing.ts +617 -0
  60. package/{dist/core/migration.js → src/core/migration.ts} +18 -11
  61. package/src/core/model-deployment-registry.ts +722 -0
  62. package/src/core/model-training-registry.ts +813 -0
  63. package/src/core/nocturnal-arbiter.ts +706 -0
  64. package/src/core/nocturnal-candidate-scoring.ts +392 -0
  65. package/src/core/nocturnal-compliance.ts +1075 -0
  66. package/src/core/nocturnal-dataset.ts +668 -0
  67. package/src/core/nocturnal-executability.ts +428 -0
  68. package/src/core/nocturnal-export.ts +390 -0
  69. package/{dist/core/nocturnal-paths.js → src/core/nocturnal-paths.ts} +49 -23
  70. package/src/core/nocturnal-trajectory-extractor.ts +484 -0
  71. package/src/core/nocturnal-trinity.ts +1384 -0
  72. package/src/core/pain.ts +122 -0
  73. package/{dist/core/path-resolver.js → src/core/path-resolver.ts} +157 -36
  74. package/{dist/core/paths.js → src/core/paths.ts} +13 -4
  75. package/src/core/principle-training-state.ts +450 -0
  76. package/src/core/profile.ts +226 -0
  77. package/src/core/promotion-gate.ts +822 -0
  78. package/{dist/core/risk-calculator.js → src/core/risk-calculator.ts} +42 -16
  79. package/{dist/core/session-tracker.js → src/core/session-tracker.ts} +185 -63
  80. package/src/core/shadow-observation-registry.ts +534 -0
  81. package/{dist/core/system-logger.js → src/core/system-logger.ts} +9 -5
  82. package/src/core/thinking-models.ts +217 -0
  83. package/src/core/training-program.ts +630 -0
  84. package/src/core/trajectory-types.ts +243 -0
  85. package/src/core/trajectory.ts +1673 -0
  86. package/{dist/core/workspace-context.js → src/core/workspace-context.ts} +57 -32
  87. package/src/hooks/bash-risk.ts +171 -0
  88. package/src/hooks/edit-verification.ts +295 -0
  89. package/src/hooks/gate-block-helper.ts +160 -0
  90. package/src/hooks/gate.ts +210 -0
  91. package/src/hooks/gfi-gate.ts +177 -0
  92. package/src/hooks/lifecycle.ts +326 -0
  93. package/{dist/hooks/llm.js → src/hooks/llm.ts} +166 -139
  94. package/src/hooks/message-sanitize.ts +45 -0
  95. package/src/hooks/pain.ts +384 -0
  96. package/src/hooks/progressive-trust-gate.ts +174 -0
  97. package/src/hooks/prompt.ts +920 -0
  98. package/src/hooks/subagent.ts +207 -0
  99. package/src/hooks/thinking-checkpoint.ts +73 -0
  100. package/src/hooks/trajectory-collector.ts +290 -0
  101. package/src/http/principles-console-route.ts +716 -0
  102. package/src/i18n/commands.ts +117 -0
  103. package/src/index.ts +694 -0
  104. package/src/service/central-database.ts +831 -0
  105. package/src/service/control-ui-query-service.ts +888 -0
  106. package/src/service/evolution-query-service.ts +405 -0
  107. package/src/service/evolution-worker.ts +1646 -0
  108. package/src/service/health-query-service.ts +836 -0
  109. package/{dist/service/nocturnal-runtime.js → src/service/nocturnal-runtime.ts} +263 -36
  110. package/src/service/nocturnal-service.ts +1015 -0
  111. package/src/service/nocturnal-target-selector.ts +532 -0
  112. package/src/service/phase3-input-filter.ts +237 -0
  113. package/src/service/runtime-summary-service.ts +757 -0
  114. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +513 -0
  115. package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +603 -0
  116. package/src/service/subagent-workflow/index.ts +51 -0
  117. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +856 -0
  118. package/src/service/subagent-workflow/runtime-direct-driver.ts +166 -0
  119. package/src/service/subagent-workflow/types.ts +378 -0
  120. package/src/service/subagent-workflow/workflow-store.ts +328 -0
  121. package/src/service/trajectory-service.ts +15 -0
  122. package/{dist/tools/critique-prompt.js → src/tools/critique-prompt.ts} +25 -8
  123. package/src/tools/deep-reflect.ts +349 -0
  124. package/{dist/tools/model-index.js → src/tools/model-index.ts} +33 -17
  125. package/src/types/event-types.ts +453 -0
  126. package/src/types/hygiene-types.ts +31 -0
  127. package/src/types/principle-tree-schema.ts +244 -0
  128. package/src/types/runtime-summary.ts +49 -0
  129. package/src/types.ts +74 -0
  130. package/src/utils/file-lock.ts +391 -0
  131. package/{dist/utils/glob-match.js → src/utils/glob-match.ts} +21 -20
  132. package/{dist/utils/hashing.js → src/utils/hashing.ts} +6 -4
  133. package/src/utils/io.ts +110 -0
  134. package/{dist/utils/nlp.js → src/utils/nlp.ts} +19 -12
  135. package/{dist/utils/plugin-logger.js → src/utils/plugin-logger.ts} +33 -8
  136. package/src/utils/subagent-probe.ts +94 -0
  137. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +70 -1
  138. package/templates/pain_settings.json +2 -1
  139. package/tests/README.md +120 -0
  140. package/tests/build-artifacts.test.ts +111 -0
  141. package/tests/commands/evolution-status.test.ts +222 -0
  142. package/tests/commands/evolver.test.ts +22 -0
  143. package/tests/commands/export.test.ts +78 -0
  144. package/tests/commands/nocturnal-review.test.ts +448 -0
  145. package/tests/commands/nocturnal-train.test.ts +97 -0
  146. package/tests/commands/pain.test.ts +108 -0
  147. package/tests/commands/samples.test.ts +65 -0
  148. package/tests/commands/strategy.test.ts +34 -0
  149. package/tests/commands/thinking-os.test.ts +88 -0
  150. package/tests/core/adaptive-thresholds.test.ts +261 -0
  151. package/tests/core/config-service.test.ts +89 -0
  152. package/tests/core/config.test.ts +90 -0
  153. package/tests/core/control-ui-db.test.ts +75 -0
  154. package/tests/core/core-template-guidance.test.ts +21 -0
  155. package/tests/core/detection-funnel.test.ts +63 -0
  156. package/tests/core/detection-service.test.ts +50 -0
  157. package/tests/core/dictionary-service.test.ts +116 -0
  158. package/tests/core/dictionary.test.ts +168 -0
  159. package/tests/core/empathy-keyword-matcher.test.ts +209 -0
  160. package/tests/core/event-log.test.ts +181 -0
  161. package/tests/core/evolution-e2e.test.ts +58 -0
  162. package/tests/core/evolution-engine-gate-integration.test.ts +543 -0
  163. package/tests/core/evolution-engine.test.ts +562 -0
  164. package/tests/core/evolution-logger.test.ts +148 -0
  165. package/tests/core/evolution-migration.test.ts +50 -0
  166. package/tests/core/evolution-paths.test.ts +21 -0
  167. package/tests/core/evolution-reducer.detector-metadata.test.ts +602 -0
  168. package/tests/core/evolution-reducer.test.ts +180 -0
  169. package/tests/core/evolution-types-loop.test.ts +48 -0
  170. package/tests/core/evolution-user-stories.e2e.test.ts +249 -0
  171. package/tests/core/external-training-contract.test.ts +463 -0
  172. package/tests/core/focus-history.test.ts +682 -0
  173. package/tests/core/init-flatten.test.ts +69 -0
  174. package/tests/core/init-refactor.test.ts +87 -0
  175. package/tests/core/init-v1.3.test.ts +46 -0
  176. package/tests/core/init.test.ts +190 -0
  177. package/tests/core/local-worker-routing.test.ts +757 -0
  178. package/tests/core/migration.test.ts +84 -0
  179. package/tests/core/model-deployment-registry.test.ts +845 -0
  180. package/tests/core/model-training-registry.test.ts +889 -0
  181. package/tests/core/nocturnal-arbiter.test.ts +494 -0
  182. package/tests/core/nocturnal-candidate-scoring.test.ts +400 -0
  183. package/tests/core/nocturnal-compliance.test.ts +646 -0
  184. package/tests/core/nocturnal-dataset.test.ts +892 -0
  185. package/tests/core/nocturnal-executability.test.ts +357 -0
  186. package/tests/core/nocturnal-export.test.ts +462 -0
  187. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +428 -0
  188. package/tests/core/nocturnal-trajectory-extractor.test.ts +634 -0
  189. package/tests/core/nocturnal-trinity.test.ts +953 -0
  190. package/tests/core/pain.test.ts +33 -0
  191. package/tests/core/path-resolver.test.ts +57 -0
  192. package/tests/core/paths-refactor.test.ts +42 -0
  193. package/tests/core/phase7-rollout-integration.test.ts +477 -0
  194. package/tests/core/principle-training-state.test.ts +712 -0
  195. package/tests/core/profile.test.ts +56 -0
  196. package/tests/core/promotion-gate.test.ts +556 -0
  197. package/tests/core/risk-calculator.test.ts +168 -0
  198. package/tests/core/session-tracker.test.ts +191 -0
  199. package/tests/core/training-program.test.ts +472 -0
  200. package/tests/core/trajectory.test.ts +265 -0
  201. package/tests/core/workspace-context-factory.test.ts +18 -0
  202. package/tests/core/workspace-context.test.ts +134 -0
  203. package/tests/fixtures/nocturnal-reviewed-subset.json +183 -0
  204. package/tests/fixtures/production-compatibility.test.ts +147 -0
  205. package/tests/fixtures/production-mock-generator.ts +282 -0
  206. package/tests/hooks/bash-risk-integration.test.ts +137 -0
  207. package/tests/hooks/bash-risk.test.ts +81 -0
  208. package/tests/hooks/edit-verification.test.ts +678 -0
  209. package/tests/hooks/gate-edit-verification-p1.test.ts +632 -0
  210. package/tests/hooks/gate-edit-verification.test.ts +435 -0
  211. package/tests/hooks/gate-pipeline-integration.test.ts +404 -0
  212. package/tests/hooks/gate.test.ts +271 -0
  213. package/tests/hooks/gfi-gate-unit.test.ts +422 -0
  214. package/tests/hooks/gfi-gate.test.ts +669 -0
  215. package/tests/hooks/lifecycle.test.ts +248 -0
  216. package/tests/hooks/llm.test.ts +308 -0
  217. package/tests/hooks/message-sanitize.test.ts +36 -0
  218. package/tests/hooks/pain.test.ts +141 -0
  219. package/tests/hooks/progressive-trust-gate.test.ts +277 -0
  220. package/tests/hooks/prompt.test.ts +1411 -0
  221. package/tests/hooks/subagent.test.ts +467 -0
  222. package/tests/hooks/thinking-gate.test.ts +313 -0
  223. package/tests/http/principles-console-route.test.ts +140 -0
  224. package/tests/hygiene-tracker.test.ts +77 -0
  225. package/tests/index.integration.test.ts +179 -0
  226. package/tests/index.shadow-routing.integration.test.ts +140 -0
  227. package/tests/index.test.ts +9 -0
  228. package/tests/integration/empathy-workflow-integration.test.ts +627 -0
  229. package/tests/service/control-ui-query-service.test.ts +121 -0
  230. package/tests/service/empathy-observer-workflow-manager.test.ts +176 -0
  231. package/tests/service/evolution-worker.test.ts +585 -0
  232. package/tests/service/nocturnal-runtime.test.ts +470 -0
  233. package/tests/service/nocturnal-service.test.ts +577 -0
  234. package/tests/service/nocturnal-target-selector.test.ts +615 -0
  235. package/tests/service/nocturnal-workflow-manager.test.ts +439 -0
  236. package/tests/service/phase3-input-filter.test.ts +289 -0
  237. package/tests/service/runtime-summary-service.test.ts +919 -0
  238. package/tests/task-compliance.test.ts +166 -0
  239. package/tests/test-utils.ts +48 -0
  240. package/tests/tools/critique-prompt.test.ts +260 -0
  241. package/tests/tools/deep-reflect.test.ts +232 -0
  242. package/tests/tools/model-index.test.ts +246 -0
  243. package/tests/ui/app.test.tsx +114 -0
  244. package/tests/utils/file-lock.test.ts +407 -0
  245. package/tests/utils/hashing.test.ts +32 -0
  246. package/tests/utils/io.test.ts +39 -0
  247. package/tests/utils/nlp.test.ts +53 -0
  248. package/tests/utils/plugin-logger.test.ts +156 -0
  249. package/tsconfig.json +16 -0
  250. package/tsconfig.tsbuildinfo +1 -0
  251. package/ui/src/App.tsx +45 -0
  252. package/ui/src/api.ts +216 -0
  253. package/ui/src/charts.tsx +586 -0
  254. package/ui/src/components/ErrorState.tsx +6 -0
  255. package/ui/src/components/Loading.tsx +13 -0
  256. package/ui/src/components/ProtectedRoute.tsx +12 -0
  257. package/ui/src/components/Shell.tsx +91 -0
  258. package/ui/src/components/WorkspaceConfig.tsx +146 -0
  259. package/ui/src/components/index.ts +5 -0
  260. package/ui/src/context/auth.tsx +80 -0
  261. package/ui/src/context/theme.tsx +66 -0
  262. package/ui/src/hooks/useAutoRefresh.ts +39 -0
  263. package/ui/src/i18n/ui.ts +363 -0
  264. package/ui/src/main.tsx +16 -0
  265. package/ui/src/pages/EvolutionPage.tsx +352 -0
  266. package/ui/src/pages/FeedbackPage.tsx +140 -0
  267. package/ui/src/pages/GateMonitorPage.tsx +136 -0
  268. package/ui/src/pages/LoginPage.tsx +88 -0
  269. package/ui/src/pages/OverviewPage.tsx +238 -0
  270. package/ui/src/pages/SamplesPage.tsx +174 -0
  271. package/ui/src/pages/ThinkingModelsPage.tsx +127 -0
  272. package/ui/src/styles.css +1661 -0
  273. package/ui/src/types.ts +368 -0
  274. package/ui/src/utils/format.ts +15 -0
  275. package/vitest.config.ts +23 -0
  276. package/dist/commands/capabilities.d.ts +0 -3
  277. package/dist/commands/capabilities.js +0 -73
  278. package/dist/commands/context.d.ts +0 -5
  279. package/dist/commands/evolution-status.d.ts +0 -4
  280. package/dist/commands/evolution-status.js +0 -117
  281. package/dist/commands/evolver.d.ts +0 -9
  282. package/dist/commands/evolver.js +0 -26
  283. package/dist/commands/export.d.ts +0 -2
  284. package/dist/commands/export.js +0 -98
  285. package/dist/commands/focus.d.ts +0 -14
  286. package/dist/commands/focus.js +0 -457
  287. package/dist/commands/nocturnal-review.d.ts +0 -24
  288. package/dist/commands/nocturnal-review.js +0 -265
  289. package/dist/commands/nocturnal-rollout.d.ts +0 -27
  290. package/dist/commands/nocturnal-rollout.js +0 -671
  291. package/dist/commands/nocturnal-train.d.ts +0 -25
  292. package/dist/commands/nocturnal-train.js +0 -919
  293. package/dist/commands/pain.d.ts +0 -5
  294. package/dist/commands/principle-rollback.d.ts +0 -4
  295. package/dist/commands/principle-rollback.js +0 -22
  296. package/dist/commands/rollback.d.ts +0 -19
  297. package/dist/commands/samples.d.ts +0 -2
  298. package/dist/commands/samples.js +0 -55
  299. package/dist/commands/strategy.d.ts +0 -3
  300. package/dist/commands/strategy.js +0 -29
  301. package/dist/commands/thinking-os.d.ts +0 -2
  302. package/dist/config/defaults/runtime.d.ts +0 -40
  303. package/dist/config/errors.d.ts +0 -84
  304. package/dist/config/errors.js +0 -94
  305. package/dist/config/index.js +0 -7
  306. package/dist/constants/diagnostician.d.ts +0 -12
  307. package/dist/constants/diagnostician.js +0 -56
  308. package/dist/constants/tools.d.ts +0 -17
  309. package/dist/constants/tools.js +0 -54
  310. package/dist/core/adaptive-thresholds.d.ts +0 -186
  311. package/dist/core/adaptive-thresholds.js +0 -300
  312. package/dist/core/config-service.d.ts +0 -15
  313. package/dist/core/config.d.ts +0 -127
  314. package/dist/core/control-ui-db.d.ts +0 -95
  315. package/dist/core/control-ui-db.js +0 -292
  316. package/dist/core/detection-funnel.d.ts +0 -33
  317. package/dist/core/detection-service.d.ts +0 -15
  318. package/dist/core/dictionary-service.d.ts +0 -15
  319. package/dist/core/dictionary.d.ts +0 -38
  320. package/dist/core/event-log.d.ts +0 -82
  321. package/dist/core/event-log.js +0 -463
  322. package/dist/core/evolution-engine.d.ts +0 -118
  323. package/dist/core/evolution-engine.js +0 -464
  324. package/dist/core/evolution-logger.d.ts +0 -137
  325. package/dist/core/evolution-logger.js +0 -256
  326. package/dist/core/evolution-migration.d.ts +0 -5
  327. package/dist/core/evolution-migration.js +0 -65
  328. package/dist/core/evolution-reducer.d.ts +0 -98
  329. package/dist/core/evolution-reducer.js +0 -465
  330. package/dist/core/evolution-types.d.ts +0 -287
  331. package/dist/core/evolution-types.js +0 -78
  332. package/dist/core/external-training-contract.d.ts +0 -276
  333. package/dist/core/external-training-contract.js +0 -269
  334. package/dist/core/focus-history.d.ts +0 -210
  335. package/dist/core/focus-history.js +0 -1185
  336. package/dist/core/hygiene/tracker.d.ts +0 -22
  337. package/dist/core/hygiene/tracker.js +0 -106
  338. package/dist/core/init.d.ts +0 -12
  339. package/dist/core/local-worker-routing.d.ts +0 -175
  340. package/dist/core/local-worker-routing.js +0 -525
  341. package/dist/core/migration.d.ts +0 -6
  342. package/dist/core/model-deployment-registry.d.ts +0 -218
  343. package/dist/core/model-deployment-registry.js +0 -503
  344. package/dist/core/model-training-registry.d.ts +0 -295
  345. package/dist/core/model-training-registry.js +0 -475
  346. package/dist/core/nocturnal-arbiter.d.ts +0 -159
  347. package/dist/core/nocturnal-arbiter.js +0 -534
  348. package/dist/core/nocturnal-candidate-scoring.d.ts +0 -137
  349. package/dist/core/nocturnal-candidate-scoring.js +0 -266
  350. package/dist/core/nocturnal-compliance.d.ts +0 -175
  351. package/dist/core/nocturnal-compliance.js +0 -824
  352. package/dist/core/nocturnal-dataset.d.ts +0 -224
  353. package/dist/core/nocturnal-dataset.js +0 -443
  354. package/dist/core/nocturnal-executability.d.ts +0 -85
  355. package/dist/core/nocturnal-executability.js +0 -331
  356. package/dist/core/nocturnal-export.d.ts +0 -124
  357. package/dist/core/nocturnal-export.js +0 -275
  358. package/dist/core/nocturnal-paths.d.ts +0 -124
  359. package/dist/core/nocturnal-trajectory-extractor.d.ts +0 -242
  360. package/dist/core/nocturnal-trajectory-extractor.js +0 -307
  361. package/dist/core/nocturnal-trinity.d.ts +0 -311
  362. package/dist/core/nocturnal-trinity.js +0 -880
  363. package/dist/core/pain.d.ts +0 -4
  364. package/dist/core/pain.js +0 -70
  365. package/dist/core/path-resolver.d.ts +0 -46
  366. package/dist/core/paths.d.ts +0 -65
  367. package/dist/core/principle-training-state.d.ts +0 -121
  368. package/dist/core/principle-training-state.js +0 -321
  369. package/dist/core/profile.d.ts +0 -62
  370. package/dist/core/profile.js +0 -210
  371. package/dist/core/promotion-gate.d.ts +0 -238
  372. package/dist/core/promotion-gate.js +0 -529
  373. package/dist/core/risk-calculator.d.ts +0 -22
  374. package/dist/core/session-tracker.d.ts +0 -99
  375. package/dist/core/shadow-observation-registry.d.ts +0 -217
  376. package/dist/core/shadow-observation-registry.js +0 -308
  377. package/dist/core/system-logger.d.ts +0 -8
  378. package/dist/core/thinking-models.d.ts +0 -38
  379. package/dist/core/thinking-models.js +0 -170
  380. package/dist/core/training-program.d.ts +0 -233
  381. package/dist/core/training-program.js +0 -433
  382. package/dist/core/trajectory.d.ts +0 -411
  383. package/dist/core/trajectory.js +0 -1307
  384. package/dist/core/workspace-context.d.ts +0 -71
  385. package/dist/hooks/bash-risk.d.ts +0 -57
  386. package/dist/hooks/bash-risk.js +0 -137
  387. package/dist/hooks/edit-verification.d.ts +0 -62
  388. package/dist/hooks/edit-verification.js +0 -256
  389. package/dist/hooks/gate-block-helper.d.ts +0 -44
  390. package/dist/hooks/gate-block-helper.js +0 -119
  391. package/dist/hooks/gate.d.ts +0 -24
  392. package/dist/hooks/gate.js +0 -173
  393. package/dist/hooks/gfi-gate.d.ts +0 -40
  394. package/dist/hooks/gfi-gate.js +0 -113
  395. package/dist/hooks/lifecycle.d.ts +0 -5
  396. package/dist/hooks/lifecycle.js +0 -284
  397. package/dist/hooks/llm.d.ts +0 -12
  398. package/dist/hooks/message-sanitize.d.ts +0 -3
  399. package/dist/hooks/message-sanitize.js +0 -37
  400. package/dist/hooks/pain.d.ts +0 -5
  401. package/dist/hooks/pain.js +0 -301
  402. package/dist/hooks/progressive-trust-gate.d.ts +0 -51
  403. package/dist/hooks/progressive-trust-gate.js +0 -89
  404. package/dist/hooks/prompt.d.ts +0 -47
  405. package/dist/hooks/prompt.js +0 -884
  406. package/dist/hooks/subagent.d.ts +0 -10
  407. package/dist/hooks/subagent.js +0 -387
  408. package/dist/hooks/thinking-checkpoint.d.ts +0 -37
  409. package/dist/hooks/thinking-checkpoint.js +0 -51
  410. package/dist/hooks/trajectory-collector.d.ts +0 -32
  411. package/dist/hooks/trajectory-collector.js +0 -256
  412. package/dist/http/principles-console-route.d.ts +0 -9
  413. package/dist/http/principles-console-route.js +0 -567
  414. package/dist/i18n/commands.d.ts +0 -26
  415. package/dist/i18n/commands.js +0 -116
  416. package/dist/index.d.ts +0 -7
  417. package/dist/index.js +0 -581
  418. package/dist/service/central-database.d.ts +0 -104
  419. package/dist/service/central-database.js +0 -649
  420. package/dist/service/control-ui-query-service.d.ts +0 -221
  421. package/dist/service/control-ui-query-service.js +0 -543
  422. package/dist/service/empathy-observer-manager.d.ts +0 -52
  423. package/dist/service/empathy-observer-manager.js +0 -229
  424. package/dist/service/evolution-query-service.d.ts +0 -155
  425. package/dist/service/evolution-query-service.js +0 -258
  426. package/dist/service/evolution-worker.d.ts +0 -101
  427. package/dist/service/evolution-worker.js +0 -974
  428. package/dist/service/nocturnal-runtime.d.ts +0 -183
  429. package/dist/service/nocturnal-service.d.ts +0 -163
  430. package/dist/service/nocturnal-service.js +0 -787
  431. package/dist/service/nocturnal-target-selector.d.ts +0 -145
  432. package/dist/service/nocturnal-target-selector.js +0 -315
  433. package/dist/service/phase3-input-filter.d.ts +0 -73
  434. package/dist/service/phase3-input-filter.js +0 -172
  435. package/dist/service/runtime-summary-service.d.ts +0 -122
  436. package/dist/service/runtime-summary-service.js +0 -485
  437. package/dist/service/trajectory-service.d.ts +0 -2
  438. package/dist/service/trajectory-service.js +0 -15
  439. package/dist/tools/critique-prompt.d.ts +0 -14
  440. package/dist/tools/deep-reflect.d.ts +0 -39
  441. package/dist/tools/deep-reflect.js +0 -350
  442. package/dist/tools/model-index.d.ts +0 -9
  443. package/dist/types/event-types.d.ts +0 -306
  444. package/dist/types/event-types.js +0 -106
  445. package/dist/types/hygiene-types.d.ts +0 -20
  446. package/dist/types/hygiene-types.js +0 -12
  447. package/dist/types/runtime-summary.d.ts +0 -47
  448. package/dist/types/runtime-summary.js +0 -1
  449. package/dist/types.d.ts +0 -50
  450. package/dist/types.js +0 -22
  451. package/dist/utils/file-lock.d.ts +0 -71
  452. package/dist/utils/file-lock.js +0 -309
  453. package/dist/utils/glob-match.d.ts +0 -28
  454. package/dist/utils/hashing.d.ts +0 -9
  455. package/dist/utils/io.d.ts +0 -6
  456. package/dist/utils/io.js +0 -106
  457. package/dist/utils/nlp.d.ts +0 -9
  458. package/dist/utils/plugin-logger.d.ts +0 -39
  459. package/dist/utils/subagent-probe.d.ts +0 -34
  460. package/dist/utils/subagent-probe.js +0 -81
@@ -1,919 +0,0 @@
1
- /**
2
- * Nocturnal Training Command Handler
3
- * ==================================
4
- *
5
- * Plugin command handler for nocturnal training operations.
6
- * Provides commands for:
7
- * - create-experiment: Create a new training experiment
8
- * - show-experiment: Show experiment details
9
- * - import-result: Import trainer result
10
- * - attach-eval: Attach benchmark eval to checkpoint
11
- * - show-lineage: Show checkpoint lineage
12
- * - list-experiments: List all experiments
13
- * - list-checkpoints: List all checkpoints
14
- *
15
- * Usage:
16
- * /nocturnal-train create-experiment --backend=peft-trl-orpo --family=<model-family> [--hyperparams=...]
17
- * /nocturnal-train show-experiment <experimentId>
18
- * /nocturnal-train import-result <experimentId> --result=<path-or-json>
19
- * /nocturnal-train attach-eval <checkpointId> --benchmark-id=<id> --delta=<number> --verdict=<pass|fail>
20
- * /nocturnal-train show-lineage <checkpointId>
21
- * /nocturnal-train list-experiments
22
- * /nocturnal-train list-checkpoints
23
- */
24
- import * as path from 'path';
25
- import * as fs from 'fs';
26
- import { execFileSync, spawn } from 'child_process';
27
- import { fileURLToPath } from 'url';
28
- import { TrainingProgram, } from '../core/training-program.js';
29
- import { listTrainingRuns, getTrainingRun, listCheckpoints, getCheckpoint, getCheckpointLineage, getTrainingRegistryStats, } from '../core/model-training-registry.js';
30
- import { getDeployment } from '../core/model-deployment-registry.js';
31
- function isZh(ctx) {
32
- return String(ctx.config?.language || 'en').startsWith('zh');
33
- }
34
- function zh(cond) {
35
- return cond;
36
- }
37
- const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
38
- const REPO_ROOT = path.resolve(MODULE_DIR, '..', '..', '..', '..');
39
- const TRAINER_SCRIPTS_DIR = path.join(REPO_ROOT, 'scripts', 'nocturnal', 'trainer');
40
- const BENCHMARK_SCRIPT_PATH = path.join(REPO_ROOT, 'scripts', 'nocturnal', 'run-benchmark.ts');
41
- /**
42
- * Parse backend from argument string.
43
- */
44
- function parseBackend(arg) {
45
- if (!arg)
46
- return 'peft-trl-orpo';
47
- const valid = ['peft-trl-orpo', 'unsloth-orpo', 'dry-run'];
48
- if (valid.includes(arg)) {
49
- return arg;
50
- }
51
- return 'peft-trl-orpo';
52
- }
53
- /**
54
- * Parse hardware tier from argument string.
55
- */
56
- function parseHardwareTier(arg) {
57
- if (!arg)
58
- return 'consumer-gpu';
59
- const valid = ['consumer-gpu', 'small-gpu', 'cpu-experimental'];
60
- if (valid.includes(arg)) {
61
- return arg;
62
- }
63
- return 'consumer-gpu';
64
- }
65
- /**
66
- * Format training run for display.
67
- */
68
- function formatTrainingRun(run, zh) {
69
- if (!run)
70
- return zh ? '未找到' : 'Not found';
71
- const lines = [
72
- `ID: ${run.trainRunId.substring(0, 8)}...`,
73
- `Family: ${run.targetModelFamily}`,
74
- `Status: ${run.status}`,
75
- `Dataset FP: ${run.datasetFingerprint.substring(0, 12)}...`,
76
- `Created: ${new Date(run.createdAt).toLocaleString()}`,
77
- ];
78
- if (run.completedAt)
79
- lines.push(`Completed: ${new Date(run.completedAt).toLocaleString()}`);
80
- if (run.failureReason)
81
- lines.push(`Failure: ${run.failureReason}`);
82
- if (run.checkpointIds.length > 0) {
83
- lines.push(`Checkpoints: ${run.checkpointIds.length}`);
84
- }
85
- return lines.join('\n ');
86
- }
87
- /**
88
- * Format checkpoint for display.
89
- */
90
- function formatCheckpoint(cp, zh) {
91
- if (!cp)
92
- return zh ? '未找到' : 'Not found';
93
- const lines = [
94
- `ID: ${cp.checkpointId.substring(0, 8)}...`,
95
- `Family: ${cp.targetModelFamily}`,
96
- `Artifact: ${cp.artifactPath}`,
97
- `Deployable: ${cp.deployable ? (zh ? '是' : 'Yes') : (zh ? '否' : 'No')}`,
98
- `Created: ${new Date(cp.createdAt).toLocaleString()}`,
99
- ];
100
- if (cp.lastEvalSummaryRef) {
101
- lines.push(`Eval: ${cp.lastEvalSummaryRef.substring(0, 12)}...`);
102
- }
103
- return lines.join('\n ');
104
- }
105
- export async function handleNocturnalTrainCommand(ctx) {
106
- const workspaceDir = ctx.config?.workspaceDir || process.cwd();
107
- const zh = isZh(ctx);
108
- const args = (ctx.args || '').trim();
109
- const parts = args.split(/\s+/).filter(Boolean);
110
- const [subcommand = 'help'] = parts;
111
- const backendArg = parts.find((p) => p.startsWith('--backend='))?.split('=')[1];
112
- const familyArg = parts.find((p) => p.startsWith('--family='))?.split('=')[1];
113
- const hardwareTierArg = parts.find((p) => p.startsWith('--tier='))?.split('=')[1];
114
- const datasetExportIdArg = parts.find((p) => p.startsWith('--dataset='))?.split('=')[1];
115
- const benchmarkExportIdArg = parts.find((p) => p.startsWith('--benchmark='))?.split('=')[1];
116
- const resultArg = parts.find((p) => p.startsWith('--result='))?.split('=')[1];
117
- const checkpointIdArg = parts.find((p) => p.startsWith('--checkpoint-id='))?.split('=')[1];
118
- const benchmarkIdArg = parts.find((p) => p.startsWith('--benchmark-id='))?.split('=')[1];
119
- const deltaArg = parts.find((p) => p.startsWith('--delta='))?.split('=')[1];
120
- const verdictArg = parts.find((p) => p.startsWith('--verdict='))?.split('=')[1];
121
- const modeArg = parts.find((p) => p.startsWith('--mode='))?.split('=')[1];
122
- const baselineScoreArg = parts.find((p) => p.startsWith('--baseline='))?.split('=')[1];
123
- const candidateScoreArg = parts.find((p) => p.startsWith('--candidate='))?.split('=')[1];
124
- try {
125
- // ── Help ────────────────────────────────────────────────────────────────
126
- if (subcommand === 'help' || subcommand === '--help') {
127
- return {
128
- text: zh
129
- ? ` nocturnal-train 命令帮助
130
-
131
- 用法:
132
- /nocturnal-train create-experiment --backend=<backend> --family=<model-family> [--dataset=<export-id>] [--benchmark=<export-id>] [--run]
133
- /nocturnal-train show-experiment <experimentId>
134
- /nocturnal-train import-result <experimentId> --result=<path-or-json>
135
- /nocturnal-train attach-eval <checkpointId> --benchmark-id=<id> [--baseline-ref=<checkpointId>] [--delta=<number>] [--verdict=<pass|fail>] [--run-benchmark]
136
- /nocturnal-train show-lineage <checkpointId>
137
- /nocturnal-train list-experiments
138
- /nocturnal-train list-checkpoints [--family=<model-family>]
139
-
140
- 示例:
141
- /nocturnal-train create-experiment --backend=peft-trl-orpo --family=qwen2.5-7b-reader --dataset=export-123 --benchmark=bench-456 --run
142
- /nocturnal-train show-experiment exp-abc123
143
- /nocturnal-train import-result exp-abc123 --result=.state/nocturnal/evals/result-exp-abc123.json
144
- /nocturnal-train attach-eval ckpt-xyz --benchmark-id=bench-001 --delta=0.08 --verdict=pass --run-benchmark
145
- /nocturnal-train show-lineage ckpt-xyz
146
- /nocturnal-train list-checkpoints --family=qwen2.5-7b-reader
147
-
148
- 后端选项:
149
- peft-trl-orpo - PEFT + TRL ORPO (生产用)
150
- unsloth-orpo - Unsloth 加速 ORPO
151
- dry-run - 仅验证,不实际训练
152
-
153
- 硬件层级:
154
- consumer-gpu - RTX 4090 24GB (默认)
155
- small-gpu - 8-16GB VRAM
156
- cpu-experimental - 仅 dry-run`
157
- : ` nocturnal-train command help
158
-
159
- Usage:
160
- /nocturnal-train create-experiment --backend=<backend> --family=<model-family> [--dataset=<export-id>] [--benchmark=<export-id>]
161
- /nocturnal-train show-experiment <experimentId>
162
- /nocturnal-train import-result <experimentId> --result=<path-or-json>
163
- /nocturnal-train attach-eval <checkpointId> --benchmark-id=<id> --delta=<number> --verdict=<pass|fail> [--baseline=<score>] [--candidate=<score>]
164
- /nocturnal-train show-lineage <checkpointId>
165
- /nocturnal-train list-experiments
166
- /nocturnal-train list-checkpoints [--family=<model-family>]
167
-
168
- Examples:
169
- /nocturnal-train create-experiment --backend=peft-trl-orpo --family=qwen2.5-7b-reader --dataset=export-123 --benchmark=bench-456
170
- /nocturnal-train show-experiment exp-abc123
171
- /nocturnal-train import-result exp-abc123 --result=.state/nocturnal/evals/result-exp-abc123.json
172
- /nocturnal-train attach-eval ckpt-xyz --benchmark-id=bench-001 --delta=0.08 --verdict=pass
173
- /nocturnal-train show-lineage ckpt-xyz
174
- /nocturnal-train list-checkpoints --family=qwen2.5-7b-reader
175
-
176
- Backend options:
177
- peft-trl-orpo - PEFT + TRL ORPO (production)
178
- unsloth-orpo - Unsloth accelerated ORPO
179
- dry-run - Validation only, no real training
180
-
181
- Hardware tiers:
182
- consumer-gpu - RTX 4090 24GB (default)
183
- small-gpu - 8-16GB VRAM
184
- cpu-experimental - dry-run only`,
185
- };
186
- }
187
- // ── Create Experiment ─────────────────────────────────────────────────
188
- if (subcommand === 'create-experiment') {
189
- if (!familyArg) {
190
- return { text: zh ? '错误: 需要 --family 参数' : 'Error: --family is required' };
191
- }
192
- const backend = parseBackend(backendArg);
193
- const hardwareTier = parseHardwareTier(hardwareTierArg);
194
- const runNow = args.includes('--run');
195
- // Find ORPO export if dataset not specified
196
- let datasetExportId = datasetExportIdArg;
197
- let datasetExportPath = '';
198
- if (!datasetExportId) {
199
- // Try to find latest ORPO export
200
- const exportsDir = path.join(workspaceDir, '.state', 'exports', 'orpo');
201
- if (fs.existsSync(exportsDir)) {
202
- const files = fs.readdirSync(exportsDir).filter((f) => f.endsWith('-manifest.json'));
203
- if (files.length > 0) {
204
- const manifest = JSON.parse(fs.readFileSync(path.join(exportsDir, files[0]), 'utf-8'));
205
- datasetExportId = manifest.exportId;
206
- datasetExportPath = manifest.exportPath;
207
- }
208
- }
209
- if (!datasetExportId) {
210
- return {
211
- text: zh
212
- ? '错误: 未找到 ORPO 导出。请先运行 /pd-nocturnal-review 导出数据。'
213
- : 'Error: No ORPO export found. Run /pd-nocturnal-review to export data first.',
214
- };
215
- }
216
- }
217
- else {
218
- datasetExportPath = path.join(workspaceDir, '.state', 'exports', 'orpo', `${datasetExportId}.jsonl`);
219
- }
220
- // Get dataset fingerprint
221
- let datasetFingerprint = 'unknown';
222
- const manifestPath = path.join(workspaceDir, '.state', 'exports', 'orpo', `${datasetExportId}-manifest.json`);
223
- if (fs.existsSync(manifestPath)) {
224
- const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
225
- if (!manifest.datasetFingerprint) {
226
- return {
227
- text: zh
228
- ? `错误: manifest 文件缺少 datasetFingerprint: ${manifestPath}`
229
- : `Error: manifest missing datasetFingerprint: ${manifestPath}`,
230
- };
231
- }
232
- datasetFingerprint = manifest.datasetFingerprint;
233
- }
234
- const benchmarkExportId = benchmarkExportIdArg || datasetExportId || 'benchmark-default';
235
- const outputDir = path.join(workspaceDir, '.state', 'nocturnal', 'checkpoints');
236
- const program = new TrainingProgram(workspaceDir);
237
- const createResult = program.createExperiment({
238
- backend,
239
- targetWorkerProfile: 'local-reader', // Phase 7 only
240
- targetModelFamily: familyArg,
241
- hardwareTier,
242
- datasetExportId,
243
- datasetExportPath,
244
- datasetFingerprint,
245
- benchmarkExportId,
246
- outputDir,
247
- });
248
- // --- Write spec files for the manual chain ---
249
- // The trainer reads spec from scripts/nocturnal/trainer/experiment-<id>.json.
250
- // import-result reads spec from .state/nocturnal/checkpoints/experiment-<id>.json.
251
- // Both must be written so the manual create-experiment -> trainer -> import-result chain works.
252
- const spec = createResult.spec;
253
- const trainerSpecPath = path.join(TRAINER_SCRIPTS_DIR, `experiment-${spec.experimentId}.json`);
254
- const workspaceSpecPath = path.join(workspaceDir, '.state', 'nocturnal', 'checkpoints', `experiment-${spec.experimentId}.json`);
255
- const trainerSpecDir = path.dirname(trainerSpecPath);
256
- const workspaceCheckpointsDir = path.dirname(workspaceSpecPath);
257
- if (!fs.existsSync(trainerSpecDir)) {
258
- fs.mkdirSync(trainerSpecDir, { recursive: true });
259
- }
260
- if (!fs.existsSync(workspaceCheckpointsDir)) {
261
- fs.mkdirSync(workspaceCheckpointsDir, { recursive: true });
262
- }
263
- fs.writeFileSync(trainerSpecPath, JSON.stringify(spec, null, 2), 'utf-8');
264
- fs.writeFileSync(workspaceSpecPath, JSON.stringify(spec, null, 2), 'utf-8');
265
- // --- Auto-run mode: execute trainer immediately ---
266
- // This closes the gap in the create-experiment -> trainer -> import-result chain.
267
- // NOTE: This blocks until training completes (could be minutes).
268
- if (runNow) {
269
- const spec = createResult.spec;
270
- const baseDir = TRAINER_SCRIPTS_DIR;
271
- const scriptPath = path.join(baseDir, 'main.py');
272
- const specPath = path.join(baseDir, `experiment-${spec.experimentId}.json`);
273
- const outputDir = spec.outputDir;
274
- const resultFilePath = path.join(outputDir, `result-${spec.experimentId}.json`);
275
- // Write spec file
276
- const specDir = path.dirname(specPath);
277
- if (!fs.existsSync(specDir)) {
278
- fs.mkdirSync(specDir, { recursive: true });
279
- }
280
- fs.writeFileSync(specPath, JSON.stringify(spec, null, 2), 'utf-8');
281
- let trainerResult;
282
- try {
283
- if (spec.backend === 'dry-run') {
284
- trainerResult = {
285
- experimentId: spec.experimentId,
286
- backend: 'dry-run',
287
- status: 'dry_run',
288
- targetWorkerProfile: spec.targetWorkerProfile,
289
- targetModelFamily: spec.targetModelFamily,
290
- datasetFingerprint: spec.datasetFingerprint,
291
- configFingerprint: spec.configFingerprint,
292
- codeHash: spec.codeHash,
293
- createdAt: new Date().toISOString(),
294
- };
295
- }
296
- else {
297
- // Execute trainer using spawn (streaming, no full log buffering).
298
- // stdout is collected into a fixed-size buffer (1MB) to avoid OOM.
299
- // stderr is piped directly to parent stderr to avoid memory accumulation.
300
- const timeoutMs = (spec.budget.maxWallClockMinutes * 60 * 1000) + 30000;
301
- const pythonExe = process.platform === 'win32' ? 'python' : 'python3';
302
- const MAX_STDOUT_BUFFER = 1 * 1024 * 1024; // 1MB cap
303
- trainerResult = await new Promise((resolve, reject) => {
304
- const proc = spawn(pythonExe, [scriptPath, '--spec', specPath, '--output-dir', outputDir], {
305
- timeout: timeoutMs,
306
- });
307
- // Collect stdout with size cap to prevent OOM
308
- const stdoutChunks = [];
309
- let stdoutSize = 0;
310
- proc.stdout.on('data', (chunk) => {
311
- const remaining = MAX_STDOUT_BUFFER - stdoutSize;
312
- if (remaining > 0) {
313
- stdoutChunks.push(chunk.slice(0, remaining));
314
- stdoutSize += Math.min(chunk.length, remaining);
315
- }
316
- });
317
- // Pipe stderr directly — training logs can be large, don't buffer
318
- proc.stderr.pipe(process.stderr);
319
- const timer = setTimeout(() => {
320
- proc.kill();
321
- reject(new Error(`Trainer timed out after ${timeoutMs}ms`));
322
- }, timeoutMs);
323
- proc.on('close', (code) => {
324
- clearTimeout(timer);
325
- if (code === 0) {
326
- const stdout = Buffer.concat(stdoutChunks).toString('utf-8');
327
- const trimmed = stdout.trim();
328
- if (trimmed) {
329
- try {
330
- resolve(JSON.parse(trimmed));
331
- return;
332
- }
333
- catch {
334
- // fall through to result file
335
- }
336
- }
337
- // Fallback to result file
338
- if (fs.existsSync(resultFilePath)) {
339
- try {
340
- resolve(JSON.parse(fs.readFileSync(resultFilePath, 'utf-8')));
341
- return;
342
- }
343
- catch {
344
- reject(new Error(`Trainer stdout was not valid JSON and result file also invalid: ${resultFilePath}`));
345
- return;
346
- }
347
- }
348
- reject(new Error(`Trainer produced no parseable stdout and no result file found at: ${resultFilePath}`));
349
- }
350
- else {
351
- // Non-zero exit: try result file as last resort
352
- if (fs.existsSync(resultFilePath)) {
353
- try {
354
- resolve(JSON.parse(fs.readFileSync(resultFilePath, 'utf-8')));
355
- }
356
- catch {
357
- reject(new Error(`Trainer exited with code ${code} and result file was invalid`));
358
- }
359
- }
360
- else {
361
- reject(new Error(`Trainer exited with code ${code} and no result file found`));
362
- }
363
- }
364
- });
365
- proc.on('error', (err) => {
366
- clearTimeout(timer);
367
- reject(new Error(`Trainer spawn failed: ${err.message}`));
368
- });
369
- });
370
- }
371
- }
372
- catch (err) {
373
- return {
374
- text: zh
375
- ? `❌ 训练执行失败: ${err.message}\n\n训练 Run ID: ${createResult.trainRunId}\n请检查 trainer 输出或使用 dry-run 后端重试。`
376
- : `❌ Trainer execution failed: ${err.message}\n\nTraining Run ID: ${createResult.trainRunId}\nCheck trainer output or retry with --backend=dry-run.`,
377
- };
378
- }
379
- finally {
380
- // Clean up spec file
381
- if (fs.existsSync(specPath)) {
382
- fs.unlinkSync(specPath);
383
- }
384
- }
385
- // Process trainer result (register checkpoint)
386
- // dry_run returns null (no checkpoint); other statuses throw on error
387
- let processed;
388
- try {
389
- processed = program.processResult({
390
- spec: createResult.spec,
391
- trainRunId: createResult.trainRunId,
392
- result: trainerResult,
393
- });
394
- }
395
- catch (err) {
396
- return {
397
- text: zh
398
- ? `❌ 结果导入失败: ${err.message}`
399
- : `❌ Result import failed: ${err.message}`,
400
- };
401
- }
402
- if (processed === null) {
403
- // dry_run completed with no checkpoint — this is a non-error outcome
404
- return {
405
- text: zh
406
- ? `✅ Dry-run 完成(未产生 checkpoint)
407
- 实验 ID: ${createResult.spec.experimentId}
408
- 训练 Run ID: ${createResult.trainRunId}
409
- 状态: ${trainerResult.status}
410
-
411
- 下一步:
412
- 若需产生可部署的 checkpoint,请使用 --backend=peft-trl-orpo 或 --backend=unsloth-orpo 重试。`
413
- : `✅ Dry-run complete (no checkpoint produced)
414
- Experiment ID: ${createResult.spec.experimentId}
415
- Training Run ID: ${createResult.trainRunId}
416
- Status: ${trainerResult.status}
417
-
418
- Next steps:
419
- To produce a deployable checkpoint, retry with --backend=peft-trl-orpo or --backend=unsloth-orpo.`,
420
- };
421
- }
422
- return {
423
- text: zh
424
- ? `✅ 训练完成
425
- 实验 ID: ${createResult.spec.experimentId}
426
- 训练 Run ID: ${createResult.trainRunId}
427
- Checkpoint ID: ${processed.checkpointId}
428
- 状态: ${trainerResult.status}
429
- ${trainerResult.failureReason ? `失败原因: ${trainerResult.failureReason}` : ''}
430
-
431
- 下一步:
432
- 1. 运行评估: /nocturnal-train attach-eval ${processed.checkpointId} --benchmark-id=<id> --delta=<number> --verdict=<pass|fail> --run-benchmark
433
- 2. 查看检查点: /nocturnal-train show-lineage ${processed.checkpointId}`
434
- : `✅ Training complete
435
- Experiment ID: ${createResult.spec.experimentId}
436
- Training Run ID: ${createResult.trainRunId}
437
- Checkpoint ID: ${processed.checkpointId}
438
- Status: ${trainerResult.status}
439
- ${trainerResult.failureReason ? `Failure: ${trainerResult.failureReason}` : ''}
440
-
441
- Next steps:
442
- 1. Run eval: /nocturnal-train attach-eval ${processed.checkpointId} --benchmark-id=<id> --delta=<number> --verdict=<pass|fail> --run-benchmark
443
- 2. View checkpoint: /nocturnal-train show-lineage ${processed.checkpointId}`,
444
- };
445
- }
446
- return {
447
- text: zh
448
- ? `✅ 实验已创建
449
- 实验 ID: ${createResult.spec.experimentId}
450
- 后端: ${createResult.spec.backend}
451
- 模型家族: ${createResult.spec.targetModelFamily}
452
- 硬件层级: ${createResult.spec.hardwareTier}
453
- 数据集: ${createResult.spec.datasetExportId}
454
- 输出目录: ${createResult.spec.outputDir}
455
- 训练 Run ID: ${createResult.trainRunId}
456
-
457
- 下一步:
458
- 1. 运行外部训练器: python "${path.join(TRAINER_SCRIPTS_DIR, 'main.py')}" --spec "${trainerSpecPath}" --output-dir ${outputDir}
459
- 2. 导入结果: /nocturnal-train import-result ${createResult.spec.experimentId} --result=<path>
460
- 3. 附加评估: /nocturnal-train attach-eval <checkpointId> --benchmark-id=<id> --delta=<number> --verdict=<pass|fail>
461
- 4. 手动链路 spec 已写入:
462
- - ${trainerSpecPath}
463
- - ${workspaceSpecPath}`
464
- : `✅ Experiment created
465
- Experiment ID: ${createResult.spec.experimentId}
466
- Backend: ${createResult.spec.backend}
467
- Model Family: ${createResult.spec.targetModelFamily}
468
- Hardware Tier: ${createResult.spec.hardwareTier}
469
- Dataset: ${createResult.spec.datasetExportId}
470
- Output Dir: ${createResult.spec.outputDir}
471
- Training Run ID: ${createResult.trainRunId}
472
-
473
- Next steps:
474
- 1. Run external trainer: python "${path.join(TRAINER_SCRIPTS_DIR, 'main.py')}" --spec "${trainerSpecPath}" --output-dir ${outputDir}
475
- 2. Import result: /nocturnal-train import-result ${createResult.spec.experimentId} --result=<path>
476
- 3. Attach eval: /nocturnal-train attach-eval <checkpointId> --benchmark-id=<id> --delta=<number> --verdict=<pass|fail>
477
- 4. Durable spec files written to:
478
- - ${trainerSpecPath}
479
- - ${workspaceSpecPath}`,
480
- };
481
- }
482
- // ── Show Experiment ───────────────────────────────────────────────────
483
- if (subcommand === 'show-experiment') {
484
- const experimentId = parts[1];
485
- if (!experimentId) {
486
- return { text: zh ? '错误: 需要实验 ID' : 'Error: experiment ID required' };
487
- }
488
- const runs = listTrainingRuns(workspaceDir, { targetModelFamily: undefined });
489
- const run = runs.find((r) => r.trainRunId.startsWith(experimentId) || r.trainRunId === experimentId);
490
- if (!run) {
491
- return { text: zh ? `未找到实验: ${experimentId}` : `Experiment not found: ${experimentId}` };
492
- }
493
- return { text: formatTrainingRun(run, zh) };
494
- }
495
- // ── Import Result ─────────────────────────────────────────────────────
496
- if (subcommand === 'import-result') {
497
- const experimentId = parts[1];
498
- if (!experimentId) {
499
- return { text: zh ? '错误: 需要实验 ID' : 'Error: experiment ID required' };
500
- }
501
- // Get result from argument or file
502
- let resultJson = resultArg;
503
- if (resultJson && fs.existsSync(resultJson)) {
504
- resultJson = fs.readFileSync(resultJson, 'utf-8');
505
- }
506
- if (!resultJson) {
507
- // Try to find result file
508
- const resultPath = path.join(workspaceDir, '.state', 'nocturnal', 'checkpoints', `result-${experimentId}.json`);
509
- if (fs.existsSync(resultPath)) {
510
- resultJson = fs.readFileSync(resultPath, 'utf-8');
511
- }
512
- else {
513
- return {
514
- text: zh
515
- ? `错误: 未找到结果文件。请使用 --result 参数指定路径或 JSON 内容。`
516
- : `Error: Result not found. Use --result to specify path or JSON content.`,
517
- };
518
- }
519
- }
520
- let result;
521
- try {
522
- result = JSON.parse(resultJson);
523
- }
524
- catch {
525
- return { text: zh ? '错误: 无效的 JSON 格式' : 'Error: Invalid JSON format' };
526
- }
527
- // Find the training run
528
- const runs = listTrainingRuns(workspaceDir);
529
- const run = runs.find((r) => r.trainRunId === result.trainRunId || r.trainRunId.startsWith(experimentId));
530
- if (!run) {
531
- return { text: zh ? `错误: 未找到训练 Run: ${result.trainRunId}` : `Error: Training run not found: ${result.trainRunId}` };
532
- }
533
- // Validate spec exists
534
- const specPath = path.join(workspaceDir, '.state', 'nocturnal', 'checkpoints', `experiment-${experimentId}.json`);
535
- if (!fs.existsSync(specPath)) {
536
- return {
537
- text: zh
538
- ? `错误: 未找到实验 spec 文件: ${specPath}`
539
- : `Error: Experiment spec not found: ${specPath}`,
540
- };
541
- }
542
- const spec = JSON.parse(fs.readFileSync(specPath, 'utf-8'));
543
- // Process the result
544
- const program = new TrainingProgram(workspaceDir);
545
- let processed;
546
- try {
547
- processed = program.processResult({
548
- spec,
549
- trainRunId: run.trainRunId,
550
- result,
551
- });
552
- }
553
- catch (err) {
554
- return {
555
- text: zh
556
- ? `❌ 导入失败: ${err.message}`
557
- : `❌ Import failed: ${err.message}`,
558
- };
559
- }
560
- if (processed === null) {
561
- // dry_run: non-error outcome with no checkpoint
562
- return {
563
- text: zh
564
- ? `✅ Dry-run 结果已导入(无 checkpoint)
565
- Status: ${result.status}
566
- 训练 Run: ${run.trainRunId}
567
-
568
- 若需产生可部署的 checkpoint,请使用 --backend=peft-trl-orpo 或 --backend=unsloth-orpo 重试。`
569
- : `✅ Dry-run result imported (no checkpoint)
570
- Status: ${result.status}
571
- Training Run: ${run.trainRunId}
572
-
573
- To produce a deployable checkpoint, retry with --backend=peft-trl-orpo or --backend=unsloth-orpo.`,
574
- };
575
- }
576
- return {
577
- text: zh
578
- ? `✅ 结果已导入
579
- Status: ${result.status}
580
- Checkpoint ID: ${processed.checkpointId}
581
- Checkpoint Ref: ${processed.checkpointRef}
582
- ${result.artifact ? `Artifact: ${result.artifact.artifactPath}` : ''}
583
- ${result.metrics ? `Wall Time: ${result.metrics.wallClockMinutes} min` : ''}
584
- ${result.failureReason ? `Failure: ${result.failureReason}` : ''}
585
-
586
- 下一步:
587
- 1. 运行评估: /nocturnal-train attach-eval ${processed.checkpointId} --benchmark-id=<id> --delta=<number> --verdict=<pass|fail>
588
- 2. 查看详情: /nocturnal-train show-lineage ${processed.checkpointId}`
589
- : `✅ Result imported
590
- Status: ${result.status}
591
- Checkpoint ID: ${processed.checkpointId}
592
- Checkpoint Ref: ${processed.checkpointRef}
593
- ${result.artifact ? `Artifact: ${result.artifact.artifactPath}` : ''}
594
- ${result.metrics ? `Wall Time: ${result.metrics.wallClockMinutes} min` : ''}
595
- ${result.failureReason ? `Failure: ${result.failureReason}` : ''}
596
-
597
- Next steps:
598
- 1. Run eval: /nocturnal-train attach-eval ${processed.checkpointId} --benchmark-id=<id> --delta=<number> --verdict=<pass|fail>
599
- 2. View details: /nocturnal-train show-lineage ${processed.checkpointId}`,
600
- };
601
- }
602
- // ── Attach Eval ──────────────────────────────────────────────────────
603
- if (subcommand === 'attach-eval') {
604
- const checkpointId = parts[1] || checkpointIdArg;
605
- if (!checkpointId) {
606
- return { text: zh ? '错误: 需要 checkpointId' : 'Error: checkpointId required' };
607
- }
608
- const runBenchmark = args.includes('--run-benchmark');
609
- const baselineRefArg = parts.find((p) => p.startsWith('--baseline-ref='))?.split('=')[1];
610
- const program = new TrainingProgram(workspaceDir);
611
- const checkpoint = getCheckpoint(workspaceDir, checkpointId);
612
- if (!checkpoint) {
613
- return { text: zh ? `错误: Checkpoint 未找到: ${checkpointId}` : `Error: Checkpoint not found: ${checkpointId}` };
614
- }
615
- let benchmarkId = benchmarkIdArg || `bench-${Date.now()}`;
616
- let delta = deltaArg ? parseFloat(deltaArg) : NaN;
617
- let verdict = verdictArg === 'pass' || verdictArg === 'fail' || verdictArg === 'compare_only'
618
- ? verdictArg
619
- : 'compare_only';
620
- let baselineScore = baselineScoreArg ? parseFloat(baselineScoreArg) : 0.5;
621
- let candidateScore = candidateScoreArg ? parseFloat(candidateScoreArg) : 0.5;
622
- const mode = (modeArg === 'prompt_assisted' ? 'prompt_assisted' : 'reduced_prompt');
623
- // --- Run benchmark mode: execute real benchmark to get scores ---
624
- // This closes the gap in the attach-eval command chain.
625
- if (runBenchmark) {
626
- // Determine baseline checkpoint ref
627
- let baselineRef = baselineRefArg;
628
- if (!baselineRef) {
629
- // Try to auto-detect from deployment registry: use the currently active checkpoint as baseline
630
- const deployment = getDeployment(workspaceDir, 'local-reader');
631
- if (deployment?.activeCheckpointId && deployment.activeCheckpointId !== checkpointId) {
632
- baselineRef = deployment.activeCheckpointId;
633
- }
634
- }
635
- if (!baselineRef) {
636
- return {
637
- text: zh
638
- ? `错误: --run-benchmark 需要 --baseline-ref 参数指定基线检查点,或当前需要有已启用的 local-reader 部署。`
639
- : `Error: --run-benchmark requires --baseline-ref to specify the baseline checkpoint, or an active local-reader deployment must exist.`,
640
- };
641
- }
642
- // Resolve both checkpoint refs to artifact paths for the scorer.
643
- // The scorer (resolveCheckpointPath) expects filesystem paths to PEFT adapters,
644
- // not checkpoint registry IDs. Look them up from the registry.
645
- const baselineCheckpoint = getCheckpoint(workspaceDir, baselineRef);
646
- if (!baselineCheckpoint) {
647
- return {
648
- text: zh
649
- ? `错误: Baseline 检查点未找到: ${baselineRef}`
650
- : `Error: Baseline checkpoint not found: ${baselineRef}`,
651
- };
652
- }
653
- // Candidate checkpoint was already validated above (line 550)
654
- // Find the export ID from the parent training run
655
- let exportId = checkpointId;
656
- if (checkpoint.trainRunId) {
657
- const run = getTrainingRun(workspaceDir, checkpoint.trainRunId);
658
- if (run?.exportId) {
659
- exportId = run.exportId;
660
- }
661
- }
662
- const scorerType = 'local-model'; // Use real model scorer
663
- // Run benchmark via ts-node subprocess
664
- const benchmarkScript = BENCHMARK_SCRIPT_PATH;
665
- const outputDir = path.join(workspaceDir, '.state', 'nocturnal', 'evals');
666
- // Build the compare command - pass ARTIFACT PATHS as separate arguments
667
- // to avoid shell injection when paths contain special characters.
668
- // Use execFileSync to pass arguments as an array (no shell interpolation).
669
- const cmdArgs = [
670
- '--yes',
671
- 'ts-node',
672
- benchmarkScript,
673
- 'compare',
674
- `--export-id=${exportId}`,
675
- `--baseline=${baselineCheckpoint.artifactPath}`,
676
- `--candidate=${checkpoint.artifactPath}`,
677
- `--mode=${mode}`,
678
- `--scorer=${scorerType}`,
679
- `--output-dir=${outputDir}`,
680
- ];
681
- let benchmarkResult = null;
682
- let benchmarkError = '';
683
- try {
684
- // Use execFileSync to avoid shell injection — paths are passed as args, not interpolated
685
- const stdout = execFileSync('npx', cmdArgs, {
686
- cwd: process.cwd(),
687
- timeout: 300000, // 5 min timeout
688
- encoding: 'utf-8',
689
- });
690
- // stdout is the JSON result from run-benchmark
691
- try {
692
- benchmarkResult = JSON.parse(stdout.trim());
693
- }
694
- catch {
695
- benchmarkError = `Failed to parse benchmark output: ${stdout.substring(0, 200)}`;
696
- }
697
- }
698
- catch (err) {
699
- // execSync throws on non-zero exit code; stdout may contain partial data
700
- const stdout = err.stdout ?? '';
701
- try {
702
- benchmarkResult = JSON.parse(stdout.trim());
703
- }
704
- catch {
705
- benchmarkError = `Benchmark failed: ${err.message}. stdout: ${stdout.substring(0, 200)}`;
706
- }
707
- }
708
- if (benchmarkError || !benchmarkResult) {
709
- return {
710
- text: zh
711
- ? `❌ Benchmark 执行失败: ${benchmarkError || '无法解析结果'}`
712
- : `❌ Benchmark execution failed: ${benchmarkError || 'Could not parse result'}`,
713
- };
714
- }
715
- delta = benchmarkResult.delta.delta;
716
- baselineScore = benchmarkResult.delta.baselineScore;
717
- candidateScore = benchmarkResult.delta.candidateScore;
718
- benchmarkId = benchmarkResult.benchmarkId;
719
- verdict = benchmarkResult.verdict;
720
- }
721
- else {
722
- // Manual mode: require explicit delta and verdict
723
- if (!deltaArg || !verdictArg) {
724
- return {
725
- text: zh
726
- ? '错误: 需要 --benchmark-id, --delta, --verdict 参数(或使用 --run-benchmark 自动运行)'
727
- : 'Error: --benchmark-id, --delta, --verdict are required (or use --run-benchmark to auto-run)',
728
- };
729
- }
730
- if (isNaN(delta)) {
731
- return { text: zh ? '错误: delta 必须是数字' : 'Error: delta must be a number' };
732
- }
733
- }
734
- const evalSummary = {
735
- evalId: `eval-${Date.now()}`,
736
- checkpointId,
737
- benchmarkId,
738
- targetModelFamily: checkpoint.targetModelFamily,
739
- mode,
740
- baselineScore,
741
- candidateScore,
742
- delta,
743
- verdict,
744
- };
745
- try {
746
- program.attachEvalAndMarkDeployable(checkpointId, evalSummary);
747
- const deployable = verdict === 'pass' || verdict === 'compare_only';
748
- return {
749
- text: zh
750
- ? `✅ 评估已附加${runBenchmark ? '(自动 Benchmark)' : ''}
751
- Checkpoint: ${checkpointId.substring(0, 8)}...
752
- Benchmark: ${benchmarkId}
753
- 基线分数: ${baselineScore.toFixed(4)}
754
- 候选分数: ${candidateScore.toFixed(4)}
755
- Delta: ${delta >= 0 ? '+' : ''}${delta.toFixed(4)}
756
- Verdict: ${verdict}
757
- Mode: ${mode}
758
- Deployable: ${deployable ? 'Yes' : 'No'}
759
-
760
- 下一步:
761
- 1. 评估晋升: /nocturnal-rollout evaluate-promotion ${checkpointId}
762
- 2. 绑定部署: /nocturnal-rollout bind ${checkpointId} --profile=local-reader`
763
- : `✅ Eval attached${runBenchmark ? ' (auto benchmark)' : ''}
764
- Checkpoint: ${checkpointId.substring(0, 8)}...
765
- Benchmark: ${benchmarkId}
766
- Baseline Score: ${baselineScore.toFixed(4)}
767
- Candidate Score: ${candidateScore.toFixed(4)}
768
- Delta: ${delta >= 0 ? '+' : ''}${delta.toFixed(4)}
769
- Verdict: ${verdict}
770
- Mode: ${mode}
771
- Deployable: ${deployable ? 'Yes' : 'No'}
772
-
773
- Next steps:
774
- 1. Evaluate promotion: /nocturnal-rollout evaluate-promotion ${checkpointId}
775
- 2. Bind deployment: /nocturnal-rollout bind ${checkpointId} --profile=local-reader`,
776
- };
777
- }
778
- catch (err) {
779
- return {
780
- text: zh
781
- ? `❌ 附加评估失败: ${err.message}`
782
- : `❌ Attach eval failed: ${err.message}`,
783
- };
784
- }
785
- }
786
- // ── Show Lineage ─────────────────────────────────────────────────────
787
- if (subcommand === 'show-lineage') {
788
- const checkpointId = parts[1];
789
- if (!checkpointId) {
790
- return { text: zh ? '错误: 需要 checkpointId' : 'Error: checkpointId required' };
791
- }
792
- const lineage = getCheckpointLineage(workspaceDir, checkpointId);
793
- if (!lineage) {
794
- return { text: zh ? `未找到 lineage: ${checkpointId}` : `Lineage not found: ${checkpointId}` };
795
- }
796
- const { run, checkpoint, eval: eval_ } = lineage;
797
- let text = zh
798
- ? `=== Checkpoint Lineage ===
799
- Checkpoint: ${checkpoint.checkpointId}
800
- Family: ${checkpoint.targetModelFamily}
801
- Deployable: ${checkpoint.deployable}
802
- Artifact: ${checkpoint.artifactPath}
803
-
804
- --- Training Run ---
805
- ${formatTrainingRun(run, zh)}
806
-
807
- --- Eval Summary ---`
808
- : `=== Checkpoint Lineage ===
809
- Checkpoint: ${checkpoint.checkpointId}
810
- Family: ${checkpoint.targetModelFamily}
811
- Deployable: ${checkpoint.deployable}
812
- Artifact: ${checkpoint.artifactPath}
813
-
814
- --- Training Run ---
815
- ${formatTrainingRun(run, zh)}
816
-
817
- --- Eval Summary ---`;
818
- if (eval_) {
819
- text += `
820
- ID: ${eval_.evalId}
821
- Mode: ${eval_.mode}
822
- Delta: ${eval_.delta >= 0 ? '+' : ''}${eval_.delta.toFixed(4)}
823
- Baseline: ${eval_.baselineScore.toFixed(3)}
824
- Candidate: ${eval_.candidateScore.toFixed(3)}
825
- Verdict: ${eval_.verdict}`;
826
- }
827
- else {
828
- text += zh ? '\n(无)' : '\n(None)';
829
- }
830
- return { text };
831
- }
832
- // ── List Experiments ──────────────────────────────────────────────────
833
- if (subcommand === 'list-experiments') {
834
- const runs = listTrainingRuns(workspaceDir);
835
- if (runs.length === 0) {
836
- return { text: zh ? '没有训练实验' : 'No training experiments' };
837
- }
838
- const lines = runs.slice(0, 20).map((run) => {
839
- const date = new Date(run.createdAt).toLocaleDateString();
840
- return `${run.trainRunId.substring(0, 8)}... | ${run.status} | ${run.targetModelFamily} | ${date} | ${run.checkpointIds.length} ckpts`;
841
- });
842
- return {
843
- text: zh
844
- ? `训练实验 (${runs.length}):
845
- ${lines.join('\n')}`
846
- : `Training experiments (${runs.length}):
847
- ${lines.join('\n')}`,
848
- };
849
- }
850
- // ── List Checkpoints ─────────────────────────────────────────────────
851
- if (subcommand === 'list-checkpoints') {
852
- const checkpoints = listCheckpoints(workspaceDir);
853
- if (checkpoints.length === 0) {
854
- return { text: zh ? '没有 Checkpoint' : 'No checkpoints' };
855
- }
856
- const filtered = familyArg
857
- ? checkpoints.filter((cp) => cp.targetModelFamily.includes(familyArg))
858
- : checkpoints;
859
- if (filtered.length === 0) {
860
- return { text: zh ? '没有匹配的 Checkpoint' : 'No matching checkpoints' };
861
- }
862
- const lines = filtered.slice(0, 20).map((cp) => {
863
- const date = new Date(cp.createdAt).toLocaleDateString();
864
- return `${cp.checkpointId.substring(0, 8)}... | ${cp.deployable ? 'deployable' : 'not-deployable'} | ${cp.targetModelFamily} | ${date}`;
865
- });
866
- return {
867
- text: zh
868
- ? `Checkpoints (${filtered.length}):
869
- ${lines.join('\n')}`
870
- : `Checkpoints (${filtered.length}):
871
- ${lines.join('\n')}`,
872
- };
873
- }
874
- // ── Stats ────────────────────────────────────────────────────────────
875
- if (subcommand === 'stats') {
876
- const stats = getTrainingRegistryStats(workspaceDir);
877
- return {
878
- text: zh
879
- ? `=== 训练注册统计 ===
880
- 总实验数: ${stats.totalRuns}
881
- 完成: ${stats.completedRuns}
882
- 失败: ${stats.failedRuns}
883
- 进行中: ${stats.pendingRuns + stats.runningRuns}
884
-
885
- 总 Checkpoint: ${stats.totalCheckpoints}
886
- 可部署: ${stats.deployableCheckpoints}
887
-
888
- 总评估: ${stats.totalEvals}
889
- 通过: ${stats.passingEvals}
890
- 失败: ${stats.failingEvals}`
891
- : `=== Training Registry Stats ===
892
- Total runs: ${stats.totalRuns}
893
- Completed: ${stats.completedRuns}
894
- Failed: ${stats.failedRuns}
895
- In progress: ${stats.pendingRuns + stats.runningRuns}
896
-
897
- Total checkpoints: ${stats.totalCheckpoints}
898
- Deployable: ${stats.deployableCheckpoints}
899
-
900
- Total evals: ${stats.totalEvals}
901
- Passing: ${stats.passingEvals}
902
- Failing: ${stats.failingEvals}`,
903
- };
904
- }
905
- // Unknown subcommand
906
- return {
907
- text: zh
908
- ? `未知子命令: ${subcommand}。运行 /nocturnal-train help 查看帮助。`
909
- : `Unknown subcommand: ${subcommand}. Run /nocturnal-train help for usage.`,
910
- };
911
- }
912
- catch (err) {
913
- return {
914
- text: zh
915
- ? `❌ 命令失败: ${err.message}`
916
- : `❌ Command failed: ${err.message}`,
917
- };
918
- }
919
- }