principles-disciple 1.72.0 → 1.74.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 (319) hide show
  1. package/INSTALL.md +1 -3
  2. package/openclaw.plugin.json +10 -5
  3. package/package.json +17 -19
  4. package/scripts/acceptance-test.mjs +16 -73
  5. package/scripts/sync-plugin.mjs +382 -77
  6. package/src/commands/archive-impl.ts +2 -1
  7. package/src/commands/capabilities.ts +2 -2
  8. package/src/commands/context.ts +2 -2
  9. package/src/commands/disable-impl.ts +2 -1
  10. package/src/commands/evolution-status.ts +16 -16
  11. package/src/commands/export.ts +12 -67
  12. package/src/commands/pain.ts +91 -1
  13. package/src/commands/principle-rollback.ts +2 -1
  14. package/src/commands/promote-impl.ts +7 -43
  15. package/src/commands/rollback-impl.ts +2 -1
  16. package/src/commands/rollback.ts +2 -1
  17. package/src/commands/samples.ts +2 -1
  18. package/src/commands/thinking-os.ts +2 -1
  19. package/src/config/errors.ts +18 -2
  20. package/src/constants/diagnostician.ts +2 -2
  21. package/src/constants/tools.ts +2 -1
  22. package/src/core/__tests__/focus-history.test.ts +210 -0
  23. package/src/core/config.ts +1 -1
  24. package/src/core/correction-cue-learner.ts +2 -136
  25. package/src/core/correction-types.ts +16 -88
  26. package/src/core/dictionary.ts +19 -20
  27. package/src/core/empathy-keyword-matcher.ts +17 -289
  28. package/src/core/empathy-types.ts +18 -229
  29. package/src/core/event-log.ts +29 -132
  30. package/src/core/evolution-reducer.ts +21 -2
  31. package/src/core/evolution-types.ts +76 -464
  32. package/src/core/file-store.ts +80 -0
  33. package/src/core/focus-history.ts +228 -955
  34. package/src/core/local-worker-routing.ts +34 -314
  35. package/src/core/merge-gate-audit.ts +0 -195
  36. package/src/core/migration.ts +0 -1
  37. package/src/core/pain-diagnostic-gate.ts +154 -0
  38. package/src/core/pain-signal.ts +21 -138
  39. package/src/core/pain.ts +15 -88
  40. package/src/core/path-resolver.ts +0 -1
  41. package/src/core/paths.ts +0 -1
  42. package/src/core/pd-task-reconciler.ts +26 -115
  43. package/src/core/pd-task-service.ts +9 -9
  44. package/src/core/pd-task-types.ts +23 -127
  45. package/src/core/principle-compiler/__tests__/compiler-replay-gate.test.ts +174 -0
  46. package/src/core/principle-compiler/code-validator.ts +15 -42
  47. package/src/core/principle-compiler/compiler.ts +100 -15
  48. package/src/core/principle-compiler/index.ts +5 -2
  49. package/src/core/principle-compiler/template-generator.ts +4 -104
  50. package/src/core/principle-injection.ts +10 -202
  51. package/src/core/principle-internalization/filesystem-lifecycle-datasource.ts +42 -0
  52. package/src/core/principle-internalization/lifecycle-read-model.ts +39 -242
  53. package/src/core/principle-internalization/principle-lifecycle-service.ts +12 -10
  54. package/src/core/principle-tree-ledger-adapter.ts +145 -0
  55. package/src/core/principle-tree-ledger.ts +8 -6
  56. package/src/core/reflection/reflection-context.ts +14 -109
  57. package/src/core/replay-engine.ts +8 -500
  58. package/src/core/rule-host-helpers.ts +5 -35
  59. package/src/core/rule-host-types.ts +10 -82
  60. package/src/core/rule-host.ts +6 -63
  61. package/src/core/runtime-v2-prompt-activation-reader.ts +231 -0
  62. package/src/core/session-tracker.ts +87 -101
  63. package/src/core/shadow-observation-registry.ts +19 -48
  64. package/src/core/trajectory.ts +3 -1
  65. package/src/core/workflow-funnel-loader.ts +62 -68
  66. package/src/core/workspace-context.ts +46 -0
  67. package/src/core/workspace-dir-service.ts +1 -1
  68. package/src/core/workspace-dir-validation.ts +18 -9
  69. package/src/hooks/AGENTS.md +1 -1
  70. package/src/hooks/gate-block-helper.ts +71 -64
  71. package/src/hooks/gate.ts +183 -31
  72. package/src/hooks/lifecycle.ts +30 -32
  73. package/src/hooks/llm.ts +60 -32
  74. package/src/hooks/pain.ts +297 -103
  75. package/src/hooks/prompt.ts +400 -440
  76. package/src/hooks/subagent.ts +2 -29
  77. package/src/i18n/commands.ts +2 -10
  78. package/src/index.ts +95 -85
  79. package/src/openclaw-sdk.ts +311 -0
  80. package/src/service/central-database.ts +8 -4
  81. package/src/service/evolution-queue-migration.ts +2 -1
  82. package/src/service/evolution-worker.ts +163 -1786
  83. package/src/service/internalization-trigger-adapter.ts +302 -0
  84. package/src/service/keyword-optimization-service.ts +4 -4
  85. package/src/service/monitoring-query-service.ts +1 -215
  86. package/src/service/queue-io.ts +60 -331
  87. package/src/service/runtime-summary-service.ts +59 -16
  88. package/src/service/subagent-workflow/index.ts +0 -41
  89. package/src/service/subagent-workflow/types.ts +9 -120
  90. package/src/service/subagent-workflow/workflow-store.ts +2 -119
  91. package/src/service/workflow-watchdog.ts +0 -43
  92. package/src/types/event-payload.ts +16 -74
  93. package/src/types/event-types.ts +38 -547
  94. package/src/types/hygiene-types.ts +7 -30
  95. package/src/types/principle-tree-schema.ts +20 -222
  96. package/src/types/queue.ts +15 -70
  97. package/src/types/runtime-summary.ts +5 -49
  98. package/src/utils/io.ts +8 -20
  99. package/src/utils/retry.ts +1 -1
  100. package/src/utils/shadow-fingerprint.ts +2 -2
  101. package/src/utils/workspace-resolver.ts +50 -0
  102. package/templates/langs/en/core/AGENTS.md +7 -7
  103. package/templates/langs/en/core/BOOT.md +1 -1
  104. package/templates/langs/en/core/HEARTBEAT.md +2 -2
  105. package/templates/langs/en/principles/THINKING_OS.md +3 -2
  106. package/templates/langs/en/skills/ai-sprint-orchestration/references/agent-registry.json +1 -72
  107. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +6 -6
  108. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +6 -6
  109. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +2 -12
  110. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +2 -12
  111. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/run.mjs +51 -15
  112. package/templates/langs/en/skills/evolve-task/SKILL.md +3 -3
  113. package/templates/langs/en/skills/pd-cli-operator/SKILL.md +67 -0
  114. package/templates/langs/en/skills/pd-diagnostician/SKILL.md +1 -1
  115. package/templates/langs/en/skills/pd-mentor/SKILL.md +2 -3
  116. package/templates/langs/en/skills/pd-pain-signal/SKILL.md +17 -39
  117. package/templates/langs/en/skills/pd-runtime-v2/SKILL.md +61 -0
  118. package/templates/langs/zh/core/AGENTS.md +7 -7
  119. package/templates/langs/zh/core/BOOT.md +1 -1
  120. package/templates/langs/zh/core/HEARTBEAT.md +2 -2
  121. package/templates/langs/zh/principles/THINKING_OS.md +3 -2
  122. package/templates/langs/zh/skills/ai-sprint-orchestration/references/agent-registry.json +1 -72
  123. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +6 -6
  124. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +6 -6
  125. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/nocturnal-trinity-quality-enhancement.json +8 -8
  126. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +2 -12
  127. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +2 -12
  128. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +51 -15
  129. package/templates/langs/zh/skills/ai-sprint-orchestration/test/run.test.mjs +21 -5
  130. package/templates/langs/zh/skills/evolve-task/SKILL.md +4 -4
  131. package/templates/langs/zh/skills/pd-cli-operator/SKILL.md +67 -0
  132. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +1 -1
  133. package/templates/langs/zh/skills/pd-mentor/SKILL.md +2 -3
  134. package/templates/langs/zh/skills/pd-pain-signal/SKILL.md +17 -38
  135. package/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +61 -0
  136. package/tests/build-artifacts.test.ts +1 -3
  137. package/tests/commands/evolution-status.test.ts +0 -118
  138. package/tests/core/bootstrap-rules.test.ts +1 -1
  139. package/tests/core/config.test.ts +1 -1
  140. package/tests/core/event-log.test.ts +35 -0
  141. package/tests/core/evolution-engine.test.ts +610 -0
  142. package/tests/core/file-store.test.ts +102 -0
  143. package/tests/core/focus-history.test.ts +203 -11
  144. package/tests/core/merge-gate-audit.test.ts +2 -169
  145. package/tests/core/migration.test.ts +7 -7
  146. package/tests/core/model-deployment-registry.test.ts +7 -1
  147. package/tests/core/model-training-registry.test.ts +19 -0
  148. package/tests/core/observability.test.ts +0 -1
  149. package/tests/core/pain-diagnostic-gate.test.ts +498 -0
  150. package/tests/core/pain.test.ts +0 -1
  151. package/tests/core/path-resolver.test.ts +1 -1
  152. package/tests/core/paths-refactor.test.ts +0 -22
  153. package/tests/core/principle-internalization/deprecated-readiness.test.ts +2 -2
  154. package/tests/core/principle-internalization/lifecycle-metrics.test.ts +2 -2
  155. package/tests/core/principle-internalization/{internalization-routing-policy.test.ts → lifecycle-routing-policy.test.ts} +6 -6
  156. package/tests/core/principle-internalization/lineage-source-retired.test.ts +56 -0
  157. package/tests/core/principle-internalization/principle-lifecycle-service.test.ts +1 -23
  158. package/tests/core/principle-tree-ledger-adapter.test.ts +253 -0
  159. package/tests/core/reflection-context.test.ts +0 -14
  160. package/tests/core/replay-engine.test.ts +127 -215
  161. package/tests/core/rule-host-helpers.test.ts +2 -2
  162. package/tests/core/rule-implementation-runtime.test.ts +0 -27
  163. package/tests/core/workflow-funnel-loader.test.ts +162 -0
  164. package/tests/core/workspace-context.test.ts +2 -2
  165. package/tests/core/workspace-dir-validation.test.ts +8 -1
  166. package/tests/core-anti-growth.test.ts +191 -0
  167. package/tests/hook-workspace-nextaction-contract.test.ts +42 -0
  168. package/tests/hooks/confirm-first-removal.test.ts +188 -0
  169. package/tests/hooks/gate-auto-correct-shadow.test.ts +310 -0
  170. package/tests/hooks/gate-auto-correct.test.ts +665 -0
  171. package/tests/hooks/gate-no-path-write-tool.test.ts +172 -0
  172. package/tests/hooks/gate-rule-host-pipeline.test.ts +2 -1
  173. package/tests/hooks/pain.test.ts +269 -12
  174. package/tests/hooks/prompt-characterization.test.ts +500 -0
  175. package/tests/hooks/prompt-size-guard.test.ts +32 -17
  176. package/tests/hooks/runtime-v2-prompt-activation.test.ts +869 -0
  177. package/tests/index.test.ts +94 -1
  178. package/tests/integration/auto-entry-gate.test.ts +248 -0
  179. package/tests/integration/internalization-trigger-guard.test.ts +69 -0
  180. package/tests/integration/m8-legacy-paths.test.ts +63 -0
  181. package/tests/integration/runtime-v2-pain-guard.test.ts +125 -0
  182. package/tests/plugin-config-resolution-cutover.test.ts +359 -0
  183. package/tests/runtime-v2-discovery-guard.test.ts +154 -0
  184. package/tests/service/central-database.test.ts +457 -0
  185. package/tests/service/evolution-worker.correction-observer.test.ts +173 -0
  186. package/tests/service/evolution-worker.timeout.test.ts +11 -129
  187. package/tests/service/internalization-trigger-adapter.test.ts +251 -0
  188. package/tests/service/monitoring-query-service.test.ts +1 -47
  189. package/tests/service/queue-io.test.ts +1 -62
  190. package/tests/service/runtime-summary-service.test.ts +3 -1
  191. package/tests/service/workflow-watchdog.test.ts +0 -91
  192. package/tests/utils/file-lock.test.ts +5 -3
  193. package/tests/utils/session-key.test.ts +52 -0
  194. package/tests/utils/subagent-probe.test.ts +48 -1
  195. package/vitest.config.ts +4 -11
  196. package/.planning/codebase/ARCHITECTURE.md +0 -157
  197. package/.planning/codebase/CONCERNS.md +0 -145
  198. package/.planning/codebase/CONVENTIONS.md +0 -148
  199. package/.planning/codebase/INTEGRATIONS.md +0 -81
  200. package/.planning/codebase/STACK.md +0 -87
  201. package/.planning/codebase/STRUCTURE.md +0 -193
  202. package/.planning/codebase/TESTING.md +0 -243
  203. package/.planning/phases/01-basic-visualization/01-GAP-CLOSURE-VERIFICATION.md +0 -113
  204. package/docs/COMMAND_REFERENCE.md +0 -76
  205. package/docs/COMMAND_REFERENCE_EN.md +0 -79
  206. package/scripts/build-web.mjs +0 -46
  207. package/scripts/diagnose-nocturnal.mjs +0 -537
  208. package/scripts/seed-nocturnal-scenarios.mjs +0 -384
  209. package/src/commands/nocturnal-review.ts +0 -322
  210. package/src/commands/nocturnal-rollout.ts +0 -790
  211. package/src/commands/nocturnal-train.ts +0 -986
  212. package/src/commands/pd-reflect.ts +0 -88
  213. package/src/core/adaptive-thresholds.ts +0 -478
  214. package/src/core/diagnostician-task-store.ts +0 -192
  215. package/src/core/nocturnal-arbiter.ts +0 -715
  216. package/src/core/nocturnal-artifact-lineage.ts +0 -116
  217. package/src/core/nocturnal-artificer.ts +0 -257
  218. package/src/core/nocturnal-candidate-scoring.ts +0 -530
  219. package/src/core/nocturnal-compliance.ts +0 -1146
  220. package/src/core/nocturnal-dataset.ts +0 -763
  221. package/src/core/nocturnal-executability.ts +0 -428
  222. package/src/core/nocturnal-export.ts +0 -499
  223. package/src/core/nocturnal-paths.ts +0 -240
  224. package/src/core/nocturnal-reasoning-deriver.ts +0 -343
  225. package/src/core/nocturnal-rule-implementation-validator.ts +0 -246
  226. package/src/core/nocturnal-snapshot-contract.ts +0 -99
  227. package/src/core/nocturnal-trajectory-extractor.ts +0 -512
  228. package/src/core/nocturnal-trinity-types.ts +0 -218
  229. package/src/core/nocturnal-trinity.ts +0 -2680
  230. package/src/core/principle-internalization/deprecated-readiness.ts +0 -93
  231. package/src/core/principle-internalization/internalization-routing-policy.ts +0 -208
  232. package/src/core/principle-internalization/lifecycle-metrics.ts +0 -152
  233. package/src/http/principles-console-route.ts +0 -709
  234. package/src/service/central-health-service.ts +0 -49
  235. package/src/service/central-overview-service.ts +0 -138
  236. package/src/service/control-ui-query-service.ts +0 -900
  237. package/src/service/cooldown-strategy.ts +0 -97
  238. package/src/service/evolution-pain-context.ts +0 -79
  239. package/src/service/evolution-query-service.ts +0 -407
  240. package/src/service/health-query-service.ts +0 -1038
  241. package/src/service/nocturnal-config.ts +0 -214
  242. package/src/service/nocturnal-runtime.ts +0 -734
  243. package/src/service/nocturnal-service.ts +0 -1605
  244. package/src/service/nocturnal-target-selector.ts +0 -545
  245. package/src/service/sleep-cycle.ts +0 -157
  246. package/src/service/startup-reconciler.ts +0 -112
  247. package/src/service/subagent-workflow/correction-observer-types.ts +0 -82
  248. package/src/service/subagent-workflow/correction-observer-workflow-manager.ts +0 -250
  249. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +0 -1
  250. package/src/service/subagent-workflow/dynamic-timeout.ts +0 -30
  251. package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +0 -268
  252. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +0 -795
  253. package/src/service/subagent-workflow/runtime-direct-driver.ts +0 -268
  254. package/src/service/subagent-workflow/workflow-manager-base.ts +0 -580
  255. package/src/tools/write-pain-flag.ts +0 -215
  256. package/templates/langs/en/skills/plan-script/SKILL.md +0 -32
  257. package/templates/langs/zh/skills/plan-script/SKILL.md +0 -32
  258. package/tests/commands/nocturnal-review.test.ts +0 -448
  259. package/tests/commands/nocturnal-train.test.ts +0 -97
  260. package/tests/commands/pd-reflect.test.ts +0 -49
  261. package/tests/core/adaptive-thresholds.test.ts +0 -261
  262. package/tests/core/nocturnal-arbiter.test.ts +0 -559
  263. package/tests/core/nocturnal-artifact-lineage.test.ts +0 -53
  264. package/tests/core/nocturnal-artificer.test.ts +0 -241
  265. package/tests/core/nocturnal-candidate-scoring.test.ts +0 -532
  266. package/tests/core/nocturnal-compliance-p-principles.test.ts +0 -133
  267. package/tests/core/nocturnal-compliance.test.ts +0 -646
  268. package/tests/core/nocturnal-dataset.test.ts +0 -892
  269. package/tests/core/nocturnal-e2e.test.ts +0 -234
  270. package/tests/core/nocturnal-executability.test.ts +0 -357
  271. package/tests/core/nocturnal-export.test.ts +0 -517
  272. package/tests/core/nocturnal-reasoning-deriver.test.ts +0 -372
  273. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +0 -428
  274. package/tests/core/nocturnal-rule-implementation-validator.test.ts +0 -127
  275. package/tests/core/nocturnal-snapshot-contract.test.ts +0 -121
  276. package/tests/core/nocturnal-trajectory-extractor.test.ts +0 -634
  277. package/tests/core/nocturnal-trinity.test.ts +0 -2053
  278. package/tests/core/pain-auto-repair.test.ts +0 -96
  279. package/tests/core/pain-integration.test.ts +0 -510
  280. package/tests/fixtures/nocturnal-reviewed-subset.json +0 -183
  281. package/tests/http/principles-console-route.test.ts +0 -162
  282. package/tests/integration/chaos-resilience.test.ts +0 -348
  283. package/tests/integration/empathy-workflow-integration.test.ts +0 -626
  284. package/tests/integration/pain-diagnostician-loop.e2e.test.ts +0 -380
  285. package/tests/service/control-ui-query-service.test.ts +0 -121
  286. package/tests/service/cooldown-strategy.test.ts +0 -164
  287. package/tests/service/data-endpoints-regression.test.ts +0 -834
  288. package/tests/service/empathy-observer-workflow-manager.test.ts +0 -175
  289. package/tests/service/evolution-worker.nocturnal.test.ts +0 -601
  290. package/tests/service/nocturnal-runtime-hardening.test.ts +0 -118
  291. package/tests/service/nocturnal-runtime.test.ts +0 -473
  292. package/tests/service/nocturnal-service-code-candidate.test.ts +0 -330
  293. package/tests/service/nocturnal-target-selector.test.ts +0 -615
  294. package/tests/service/startup-reconciler.test.ts +0 -148
  295. package/tests/tools/write-pain-flag.test.ts +0 -358
  296. package/ui/src/App.tsx +0 -45
  297. package/ui/src/api.ts +0 -220
  298. package/ui/src/charts.tsx +0 -955
  299. package/ui/src/components/ErrorState.tsx +0 -6
  300. package/ui/src/components/Loading.tsx +0 -13
  301. package/ui/src/components/ProtectedRoute.tsx +0 -12
  302. package/ui/src/components/Shell.tsx +0 -91
  303. package/ui/src/components/WorkspaceConfig.tsx +0 -178
  304. package/ui/src/components/index.ts +0 -5
  305. package/ui/src/context/auth.tsx +0 -80
  306. package/ui/src/context/theme.tsx +0 -66
  307. package/ui/src/hooks/useAutoRefresh.ts +0 -39
  308. package/ui/src/i18n/ui.ts +0 -473
  309. package/ui/src/main.tsx +0 -16
  310. package/ui/src/pages/EvolutionPage.tsx +0 -333
  311. package/ui/src/pages/FeedbackPage.tsx +0 -138
  312. package/ui/src/pages/GateMonitorPage.tsx +0 -136
  313. package/ui/src/pages/LoginPage.tsx +0 -89
  314. package/ui/src/pages/OverviewPage.tsx +0 -599
  315. package/ui/src/pages/SamplesPage.tsx +0 -174
  316. package/ui/src/pages/ThinkingModelsPage.tsx +0 -702
  317. package/ui/src/styles.css +0 -2020
  318. package/ui/src/types.ts +0 -384
  319. package/ui/src/utils/format.ts +0 -15
@@ -1,537 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Nocturnal Pipeline Diagnostic Script
5
- * ======================================
6
- * Checks every link in the Nocturnal reflection chain:
7
- * Heartbeat → Idle Detection → Queue → Snapshot → Workflow → Trinity → Arbiter → Persistence
8
- *
9
- * Usage:
10
- * node scripts/diagnose-nocturnal.mjs [--workspace /path/to/workspace]
11
- *
12
- * Output: Structured report with pass/fail for each checkpoint.
13
- */
14
-
15
- import { existsSync, readFileSync, readdirSync, statSync, writeFileSync, rmSync } from 'fs';
16
- import { join, dirname } from 'path';
17
- import { fileURLToPath } from 'url';
18
- import { execSync, execFileSync } from 'child_process';
19
-
20
- const __filename = fileURLToPath(import.meta.url);
21
- const __dirname = dirname(__filename);
22
- const PLUGIN_DIR = join(__dirname, '..');
23
-
24
- // ─── Argument parsing ───
25
- function parseArgs() {
26
- let workspaceDir = null;
27
- const argv = process.argv.slice(2);
28
- for (let i = 0; i < argv.length; i++) {
29
- if (argv[i] === '--workspace' && argv[i + 1]) {
30
- workspaceDir = argv[++i];
31
- }
32
- }
33
- // Auto-detect workspace from current git working directory
34
- if (!workspaceDir) {
35
- try {
36
- const gitRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }).trim();
37
- workspaceDir = gitRoot;
38
- } catch {
39
- workspaceDir = process.cwd();
40
- }
41
- }
42
- return { workspaceDir };
43
- }
44
-
45
- // ─── Report helpers ───
46
- const results = [];
47
- let checksPassed = 0;
48
- let checksFailed = 0;
49
- let checksWarned = 0;
50
-
51
- function check(name, fn) {
52
- try {
53
- const result = fn();
54
- if (result && result.status === 'warn') {
55
- checksWarned++;
56
- results.push({ name, status: 'warn', detail: result.detail || '' });
57
- } else {
58
- checksPassed++;
59
- results.push({ name, status: 'pass', detail: typeof result === 'string' ? result : '' });
60
- }
61
- } catch (err) {
62
- checksFailed++;
63
- results.push({ name, status: 'fail', detail: err.message || String(err) });
64
- }
65
- }
66
-
67
- function printReport() {
68
- console.log('\n' + '='.repeat(60));
69
- console.log(' NOCTURNAL PIPELINE DIAGNOSTIC REPORT');
70
- console.log(' ' + new Date().toISOString());
71
- console.log('='.repeat(60));
72
-
73
- for (const r of results) {
74
- const icon = r.status === 'pass' ? '✅' : r.status === 'warn' ? '⚠️ ' : '❌';
75
- console.log(`\n${icon} ${r.name}`);
76
- if (r.detail) {
77
- console.log(` ${r.detail}`);
78
- }
79
- }
80
-
81
- console.log('\n' + '-'.repeat(60));
82
- console.log(` Summary: ${checksPassed} passed, ${checksWarned} warnings, ${checksFailed} failed`);
83
- console.log('-'.repeat(60) + '\n');
84
-
85
- if (checksFailed > 0) {
86
- process.exitCode = 1;
87
- }
88
- }
89
-
90
- // ─── Main ───
91
- function main() {
92
- const { workspaceDir } = parseArgs();
93
- const stateDir = join(workspaceDir, '.state');
94
-
95
- console.log(`\n🔍 Diagnosing Nocturnal pipeline for workspace: ${workspaceDir}`);
96
-
97
- // ─────────────────────────────────────────────────────────
98
- // CHECKPOINT 1: State directory structure
99
- // ─────────────────────────────────────────────────────────
100
- check('1. State directory structure', () => {
101
- // All state dirs are inside .state/
102
- const required = ['sessions', 'logs', 'nocturnal', 'nocturnal/samples'];
103
- const missing = [];
104
- for (const rel of required) {
105
- if (!existsSync(join(stateDir, rel))) missing.push(rel);
106
- }
107
- if (missing.length > 0) throw new Error(`Missing directories: ${missing.join(', ')}`);
108
- return 'All required directories present';
109
- });
110
-
111
- // ─────────────────────────────────────────────────────────
112
- // CHECKPOINT 2: Session tracker persistence
113
- // ─────────────────────────────────────────────────────────
114
- check('2. Session tracker persistence', () => {
115
- const sessionsDir = join(stateDir, 'sessions');
116
- if (!existsSync(sessionsDir)) throw new Error('sessions/ directory missing');
117
- const files = readdirSync(sessionsDir).filter(f => f.endsWith('.json'));
118
- if (files.length === 0) {
119
- return { status: 'warn', detail: 'No session files found — idle check will report idle immediately' };
120
- }
121
- // Verify at least one session file is valid JSON
122
- let validSessions = 0;
123
- for (const f of files) {
124
- try {
125
- const data = JSON.parse(readFileSync(join(sessionsDir, f), 'utf-8'));
126
- if (data.sessionId && data.lastActivityAt) validSessions++;
127
- } catch { /* corrupted, skip */ }
128
- }
129
- if (validSessions === 0) {
130
- return { status: 'warn', detail: `${files.length} session file(s) found but none are valid JSON — idle check will likely report idle immediately` };
131
- }
132
- return `${files.length} session files, ${validSessions} valid with sessionId+lastActivityAt`;
133
- });
134
-
135
- // ─────────────────────────────────────────────────────────
136
- // CHECKPOINT 3: Idle detection logic
137
- // ─────────────────────────────────────────────────────────
138
- check('3. Idle detection (checkWorkspaceIdle)', () => {
139
- // Functions are minified — check for unique string markers instead.
140
- const bundlePath = join(PLUGIN_DIR, 'dist', 'bundle.js');
141
- const content = readFileSync(bundlePath, 'utf-8');
142
-
143
- // Stable markers: log messages, object fields, event strings that survive minification.
144
- const markers = [
145
- { name: 'Workspace not idle', reason: 'preflight idle check log message' },
146
- { name: 'trigger', reason: 'system session detection (checks trigger field)' },
147
- { name: 'abandonedSessionIds', reason: 'IdleCheckResult field (preserved in object literal)' },
148
- { name: 'trajectoryGuardrailConfirmsIdle', reason: 'IdleCheckResult field' },
149
- ];
150
- const missing = markers.filter(m => !content.includes(m.name));
151
- if (missing.length > 0) {
152
- throw new Error(`Idle detection markers missing: ${missing.map(m => m.name).join(', ')}`);
153
- }
154
-
155
- // Check PR #256 fix: legacy session temporal guard
156
- // The fix adds `lastActivityAt` comparison before treating sessions as system sessions.
157
- // In minified code this appears as a comparison involving `lastActivityAt`.
158
- if (!content.includes('lastActivityAt')) {
159
- return { status: 'warn', detail: 'lastActivityAt reference not found — temporal guard for legacy sessions may be missing' };
160
- }
161
- return 'Idle detection functions present (verified via stable string markers)';
162
- });
163
-
164
- // ─────────────────────────────────────────────────────────
165
- // CHECKPOINT 4: Evolution queue
166
- // ─────────────────────────────────────────────────────────
167
- check('4. Evolution queue', () => {
168
- const queuePath = join(stateDir, 'evolution_queue.json');
169
- if (!existsSync(queuePath)) {
170
- return { status: 'warn', detail: 'No evolution queue — idle check has not yet enqueued a task' };
171
- }
172
- const queue = JSON.parse(readFileSync(queuePath, 'utf-8'));
173
- const sleepTasks = queue.filter(t => t.taskKind === 'sleep_reflection');
174
- const pending = sleepTasks.filter(t => t.status === 'pending' || t.status === 'in_progress');
175
- const completed = sleepTasks.filter(t => t.status === 'completed');
176
- const failed = sleepTasks.filter(t => t.status === 'failed');
177
-
178
- if (pending.length > 0) return `${pending.length} pending sleep_reflection task(s) awaiting processing`;
179
- if (completed.length > 0) return `${completed.length} completed, ${failed.length} failed (total ${sleepTasks.length} tasks)`;
180
- return { status: 'warn', detail: `Queue exists with ${queue.length} items but no sleep_reflection tasks` };
181
- });
182
-
183
- // ─────────────────────────────────────────────────────────
184
- // CHECKPOINT 5: Nocturnal samples (artifacts)
185
- // ─────────────────────────────────────────────────────────
186
- check('5. Nocturnal artifact persistence', () => {
187
- const samplesDir = join(stateDir, 'nocturnal', 'samples');
188
- if (!existsSync(samplesDir)) {
189
- return { status: 'warn', detail: 'No samples directory — no reflections have been persisted yet' };
190
- }
191
- const files = readdirSync(samplesDir).filter(f => f.endsWith('.json'));
192
- if (files.length === 0) return { status: 'warn', detail: 'samples/ directory exists but is empty' };
193
-
194
- // Validate most recent artifact
195
- const sorted = files
196
- .map(f => ({ name: f, mtime: statSync(join(samplesDir, f)).mtimeMs }))
197
- .sort((a, b) => b.mtime - a.mtime);
198
- const latest = sorted[0].name;
199
- const artifact = JSON.parse(readFileSync(join(samplesDir, latest), 'utf-8'));
200
- const hasRequired = artifact.artifactId && artifact.badDecision && artifact.betterDecision && artifact.rationale;
201
- if (!hasRequired) {
202
- return { status: 'warn', detail: `Latest artifact ${latest} is missing required fields` };
203
- }
204
- return `${files.length} artifact(s), latest: ${latest} (${artifact.principleId || 'unknown principle'})`;
205
- });
206
-
207
- // ─────────────────────────────────────────────────────────
208
- // CHECKPOINT 6: Workflow store
209
- // ─────────────────────────────────────────────────────────
210
- check('6. Nocturnal workflow store', () => {
211
- const workflowsPath = join(stateDir, 'nocturnal', 'workflows.json');
212
- if (!existsSync(workflowsPath)) {
213
- return { status: 'warn', detail: 'No workflows.json — no nocturnal workflows have been started' };
214
- }
215
- const workflows = JSON.parse(readFileSync(workflowsPath, 'utf-8'));
216
- if (!Array.isArray(workflows) || workflows.length === 0) {
217
- return { status: 'warn', detail: 'workflows.json is empty — no workflows recorded' };
218
- }
219
- const active = workflows.filter(w => w.state === 'active');
220
- const completed = workflows.filter(w => w.state === 'completed');
221
- const errored = workflows.filter(w => w.state === 'terminal_error');
222
- const expired = workflows.filter(w => w.state === 'expired');
223
-
224
- if (active.length > 0) {
225
- return { status: 'warn', detail: `${active.length} workflow(s) still active — may be in progress or stuck. IDs: ${active.map(w => w.workflow_id).join(', ')}` };
226
- }
227
- return `${workflows.length} total: ${completed.length} completed, ${errored.length} errored, ${expired.length} expired`;
228
- });
229
-
230
- // ─────────────────────────────────────────────────────────
231
- // CHECKPOINT 7: Nocturnal runtime state (cooldown/quota)
232
- // ─────────────────────────────────────────────────────────
233
- check('7. Nocturnal runtime state (cooldown/quota)', () => {
234
- const runtimePath = join(stateDir, 'nocturnal-runtime.json');
235
- if (!existsSync(runtimePath)) {
236
- return 'No runtime state — no cooldown or quota restrictions';
237
- }
238
- const state = JSON.parse(readFileSync(runtimePath, 'utf-8'));
239
- const issues = [];
240
-
241
- if (state.globalCooldownUntil) {
242
- const cooldownEnd = new Date(state.globalCooldownUntil).getTime();
243
- if (cooldownEnd > Date.now()) {
244
- const remainingMin = Math.round((cooldownEnd - Date.now()) / 60000);
245
- issues.push(`global cooldown active (${remainingMin}min remaining)`);
246
- }
247
- }
248
-
249
- if (state.recentRunTimestamps) {
250
- const windowStart = Date.now() - 24 * 60 * 60 * 1000;
251
- const recentRuns = state.recentRunTimestamps
252
- .map(ts => new Date(ts).getTime())
253
- .filter(ts => ts > windowStart);
254
- if (recentRuns.length >= 3) {
255
- issues.push(`quota exhausted (${recentRuns.length}/3 runs used in 24h)`);
256
- }
257
- }
258
-
259
- if (issues.length > 0) {
260
- return { status: 'warn', detail: issues.join('; ') };
261
- }
262
- return 'No active cooldown or quota restrictions';
263
- });
264
-
265
- // ─────────────────────────────────────────────────────────
266
- // CHECKPOINT 8: Bundle health
267
- // ─────────────────────────────────────────────────────────
268
- check('8. Plugin bundle health', () => {
269
- const bundlePath = join(PLUGIN_DIR, 'dist', 'bundle.js');
270
- if (!existsSync(bundlePath)) throw new Error('dist/bundle.js missing — run build first');
271
-
272
- const content = readFileSync(bundlePath, 'utf-8');
273
-
274
- // Use a mix of exported symbols and stable string markers.
275
- // Class names and exported symbols survive minification; internal function names don't.
276
- const markers = [
277
- 'EvolutionWorkerService', // exported class
278
- 'checkPainFlag', // exported function
279
- 'processEvolutionQueue', // function reference
280
- 'NocturnalWorkflowManager', // exported class
281
- 'executeNocturnalReflectionAsync', // used in log messages
282
- 'nocturnal_started', // event type string
283
- 'nocturnal_completed', // event type string
284
- 'nocturnal_failed', // event type string
285
- 'nocturnal_expired', // event type string
286
- ];
287
- const missing = markers.filter(m => !content.includes(m));
288
- if (missing.length > 0) throw new Error(`Missing critical symbols in bundle: ${missing.join(', ')}`);
289
-
290
- return `Bundle OK (${Math.round(content.length / 1024)}KB), all ${markers.length} critical markers present`;
291
- });
292
-
293
- // ─────────────────────────────────────────────────────────
294
- // CHECKPOINT 9: Git state — uncommitted changes that could break pipeline
295
- // ─────────────────────────────────────────────────────────
296
- check('9. Git state (uncommitted changes)', () => {
297
- try {
298
- const status = execSync('git status --porcelain', { encoding: 'utf-8', timeout: 5000, cwd: PLUGIN_DIR }).trim();
299
- if (!status) return 'Working tree clean';
300
- const changedFiles = status.split('\n').length;
301
- return { status: 'warn', detail: `${changedFiles} uncommitted change(s) in plugin directory` };
302
- } catch {
303
- return { status: 'warn', detail: 'Could not check git status' };
304
- }
305
- });
306
-
307
- // ─────────────────────────────────────────────────────────
308
- // CHECKPOINT 10: Pain flag state
309
- // ─────────────────────────────────────────────────────────
310
- check('10. Pain flag state', () => {
311
- const painFlagPath = join(stateDir, '.pain_flag');
312
- if (!existsSync(painFlagPath)) {
313
- return 'No active pain flag';
314
- }
315
- const content = readFileSync(painFlagPath, 'utf-8');
316
-
317
- // Self-healing: fix [object Object] corruption caused by bash heredoc/toString
318
- if (content.includes('[object Object]')) {
319
- // Try to extract and parse JSON object from anywhere in the content
320
- // The corruption might be at any position, not just the beginning
321
- try {
322
- // Attempt 1: Extract JSON object using regex (handles {...} anywhere)
323
- const jsonMatch = content.match(/\{[\s\S]*\}/);
324
- if (jsonMatch) {
325
- const json = JSON.parse(jsonMatch[0]);
326
- // If we got a valid object, rewrite it properly as KV format
327
- const kv = Object.entries(json)
328
- .map(([k, v]) => `${k}: ${v === undefined ? '' : v}`)
329
- .join('\n');
330
- writeFileSync(painFlagPath, kv, 'utf-8');
331
- return `Pain flag was corrupted ([object Object]), auto-repaired from JSON backup`;
332
- }
333
- // Attempt 2: Try parsing the whole content after removing common prefixes
334
- const cleaned = content.replace(/^(active:\s*|source:\s*)/, '').trim();
335
- if (cleaned.startsWith('{')) {
336
- const json = JSON.parse(cleaned);
337
- const kv = Object.entries(json)
338
- .map(([k, v]) => `${k}: ${v === undefined ? '' : v}`)
339
- .join('\n');
340
- writeFileSync(painFlagPath, kv, 'utf-8');
341
- return `Pain flag was corrupted ([object Object]), auto-repaired from JSON backup`;
342
- }
343
- throw new Error('No valid JSON found');
344
- } catch {
345
- // If not JSON, delete the corrupted file to unblock the system
346
- try {
347
- rmSync(painFlagPath);
348
- return `Pain flag was corrupted ([object Object]), deleted invalid file to unblock system`;
349
- } catch {
350
- return { status: 'warn', detail: 'Pain flag corrupted ([object Object]), could not auto-repair' };
351
- }
352
- }
353
- }
354
-
355
- const lines = content.split('\n');
356
- const fields = {};
357
- for (const line of lines) {
358
- const colonIdx = line.indexOf(':');
359
- if (colonIdx > 0) {
360
- fields[line.substring(0, colonIdx).trim()] = line.substring(colonIdx + 1).trim();
361
- }
362
- }
363
- // Accept either the legacy contract (fields.score + fields.reason)
364
- // or the current contract (active.source.score)
365
- const legacy = fields.score && fields.reason;
366
- const current = fields.active && fields.source && fields.score;
367
- if (!legacy && !current) {
368
- return { status: 'warn', detail: 'Pain flag exists but is missing required fields (need score + reason, or active.source.score)' };
369
- }
370
- return `Pain flag active (score: ${fields.score}, source: ${fields.source || fields.active?.source || 'unknown'}, session: ${fields.session_id || 'none'})`;
371
- });
372
-
373
- // ─────────────────────────────────────────────────────────
374
- // CHECKPOINT 11: Trajectory data
375
- // ─────────────────────────────────────────────────────────
376
- check('11. Trajectory data availability', () => {
377
- const trajectoryPath = join(stateDir, 'trajectory.json');
378
- const trajectoryDir = join(stateDir, 'trajectory');
379
- const trajectoryDb = join(stateDir, 'trajectory.db');
380
- if (!existsSync(trajectoryPath) && !existsSync(trajectoryDir) && !existsSync(trajectoryDb)) {
381
- return { status: 'warn', detail: 'No trajectory data — snapshot extraction will use pain context fallback or fail' };
382
- }
383
- if (existsSync(trajectoryDb)) {
384
- const stat = statSync(trajectoryDb);
385
- return `Trajectory SQLite database present (${Math.round(stat.size / 1024)}KB)`;
386
- }
387
- // Check trajectory content
388
- if (existsSync(trajectoryPath)) {
389
- try {
390
- const data = JSON.parse(readFileSync(trajectoryPath, 'utf-8'));
391
- const entryCount = Array.isArray(data) ? data.length : Object.keys(data).length;
392
- return `${entryCount} trajectory entries available`;
393
- } catch {
394
- return { status: 'warn', detail: 'trajectory.json exists but is corrupted' };
395
- }
396
- }
397
- if (existsSync(trajectoryDir)) {
398
- const files = readdirSync(trajectoryDir).filter(f => f.endsWith('.json'));
399
- return `${files.length} trajectory file(s) available`;
400
- }
401
- return { status: 'warn', detail: 'Trajectory storage not found in expected locations' };
402
- });
403
-
404
- // ─────────────────────────────────────────────────────────
405
- // CHECKPOINT 12: Principle training state
406
- // ─────────────────────────────────────────────────────────
407
- check('12. Principle training state', () => {
408
- // Check multiple possible locations
409
- const candidates = [
410
- join(stateDir, 'nocturnal', 'training_store.json'),
411
- join(stateDir, 'principle_training_state.json'),
412
- ];
413
- let trainingPath = null;
414
- for (const c of candidates) {
415
- if (existsSync(c)) { trainingPath = c; break; }
416
- }
417
- if (!trainingPath) {
418
- return { status: 'warn', detail: 'No training_store.json or principle_training_state.json — NocturnalTargetSelector may not find evaluable principles' };
419
- }
420
- try {
421
- const store = JSON.parse(readFileSync(trainingPath, 'utf-8'));
422
- const principles = Object.keys(store.principles || store);
423
- if (principles.length === 0) {
424
- return { status: 'warn', detail: 'Training store exists but has no principles' };
425
- }
426
- const evaluable = principles.filter(p => {
427
- const pr = store.principles ? store.principles[p] : store[p];
428
- return pr && pr.evaluability !== 'manual_only';
429
- });
430
- return `${principles.length} principle(s) in training store, ${evaluable.length} evaluable`;
431
- } catch {
432
- return { status: 'warn', detail: 'Training store exists but is corrupted' };
433
- }
434
- });
435
-
436
- // ─────────────────────────────────────────────────────────
437
- // CHECKPOINT 13: Correction samples (Phase 2b/3b)
438
- // ─────────────────────────────────────────────────────────
439
- check('13. Correction samples availability', () => {
440
- // Read from trajectory.db using sqlite3 CLI
441
- try {
442
- const dbPath = join(stateDir, 'trajectory.db');
443
- if (!existsSync(dbPath)) {
444
- return { status: 'warn', detail: 'trajectory.db not found' };
445
- }
446
- let result;
447
- try {
448
- result = execFileSync('sqlite3', [dbPath, 'SELECT review_status, COUNT(*), AVG(quality_score) FROM correction_samples GROUP BY review_status;'], { encoding: 'utf-8', timeout: 5000 }).trim();
449
- } catch {
450
- return { status: 'warn', detail: 'Could not query correction samples' };
451
- }
452
- if (!result) {
453
- return { status: 'warn', detail: 'Could not query correction samples' };
454
- }
455
- const pendingMatch = result.match(/pending\|(\d+)/);
456
- const approvedMatch = result.match(/approved\|(\d+)/);
457
- const rejectedMatch = result.match(/rejected\|(\d+)/);
458
- const pending = pendingMatch ? parseInt(pendingMatch[1]) : 0;
459
- const approved = approvedMatch ? parseInt(approvedMatch[1]) : 0;
460
- const rejected = rejectedMatch ? parseInt(rejectedMatch[1]) : 0;
461
- if (pending > 0) {
462
- return { status: 'warn', detail: `${pending} pending review, ${approved} approved, ${rejected} rejected` };
463
- }
464
- if (approved === 0 && rejected === 0) return { status: 'warn', detail: 'No correction samples exist — no user corrections detected yet' };
465
- return `${approved} approved, ${rejected} rejected, ${pending} pending`;
466
- } catch {
467
- return { status: 'warn', detail: 'Could not query trajectory.db' };
468
- }
469
- });
470
-
471
- // ─────────────────────────────────────────────────────────
472
- // CHECKPOINT 14: Signal diversity (Phase 3b)
473
- // ─────────────────────────────────────────────────────────
474
- check('14. Pain signal diversity', () => {
475
- try {
476
- const dbPath = join(stateDir, 'trajectory.db');
477
- if (!existsSync(dbPath)) {
478
- return { status: 'warn', detail: 'trajectory.db not found' };
479
- }
480
- let result;
481
- try {
482
- result = execFileSync('sqlite3', [dbPath, 'SELECT source, COUNT(*), ROUND(AVG(score),1) FROM pain_events GROUP BY source ORDER BY COUNT(*) DESC;'], { encoding: 'utf-8', timeout: 5000 }).trim();
483
- } catch {
484
- return { status: 'warn', detail: 'Could not query pain events' };
485
- }
486
- if (!result) {
487
- return { status: 'warn', detail: 'Could not query pain events' };
488
- }
489
- const sources = result.split('\n').filter(Boolean);
490
- if (sources.length < 2) {
491
- return { status: 'warn', detail: `Only ${sources.length} pain signal source(s) — low diversity. Expected: tool_failure, user_empathy, correction_rejected, gate_blocked` };
492
- }
493
- const summary = sources.map(s => {
494
- const parts = s.split('|');
495
- return `${parts[0]} (${parts[1]}, avg ${parts[2]})`;
496
- }).join(', ');
497
- return `${sources.length} sources: ${summary}`;
498
- } catch {
499
- return { status: 'warn', detail: 'Could not query trajectory.db' };
500
- }
501
- });
502
-
503
- // ─────────────────────────────────────────────────────────
504
- // CHECKPOINT 15: Artifact quality (Phase 3)
505
- // ─────────────────────────────────────────────────────────
506
- check('15. Nocturnal artifact quality', () => {
507
- const samplesDir = join(stateDir, 'nocturnal', 'samples');
508
- if (!existsSync(samplesDir)) {
509
- return { status: 'warn', detail: 'No samples directory' };
510
- }
511
- const files = readdirSync(samplesDir).filter(f => f.endsWith('.json'));
512
- if (files.length === 0) return { status: 'warn', detail: 'No artifacts produced yet' };
513
-
514
- // Check uniqueness of badDecision across recent artifacts
515
- const recentFiles = files
516
- .map(f => ({ name: f, mtime: statSync(join(samplesDir, f)).mtimeMs }))
517
- .sort((a, b) => b.mtime - a.mtime)
518
- .slice(0, 5);
519
-
520
- const decisions = new Set();
521
- for (const f of recentFiles) {
522
- try {
523
- const artifact = JSON.parse(readFileSync(join(samplesDir, f.name), 'utf-8'));
524
- if (artifact.badDecision) decisions.add(artifact.badDecision);
525
- } catch { /* skip */ }
526
- }
527
-
528
- if (decisions.size < recentFiles.length) {
529
- return { status: 'warn', detail: `${recentFiles.length - decisions.size} duplicate decision(s) in last ${recentFiles.length} artifacts — stub reflector may not be content-aware` };
530
- }
531
- return `${files.length} total, last ${recentFiles.length} all unique decisions`;
532
- });
533
-
534
- printReport();
535
- }
536
-
537
- main();