@principles/pd-cli 1.73.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 (298) hide show
  1. package/README.md +90 -0
  2. package/dist/commands/artifact.d.ts +14 -0
  3. package/dist/commands/artifact.d.ts.map +1 -0
  4. package/dist/commands/artifact.js +67 -0
  5. package/dist/commands/artifact.js.map +1 -0
  6. package/dist/commands/candidate.d.ts +83 -0
  7. package/dist/commands/candidate.d.ts.map +1 -0
  8. package/dist/commands/candidate.js +891 -0
  9. package/dist/commands/candidate.js.map +1 -0
  10. package/dist/commands/central-sync.d.ts +10 -0
  11. package/dist/commands/central-sync.d.ts.map +1 -0
  12. package/dist/commands/central-sync.js +32 -0
  13. package/dist/commands/central-sync.js.map +1 -0
  14. package/dist/commands/console.d.ts +9 -0
  15. package/dist/commands/console.d.ts.map +1 -0
  16. package/dist/commands/console.js +114 -0
  17. package/dist/commands/console.js.map +1 -0
  18. package/dist/commands/context.d.ts +7 -0
  19. package/dist/commands/context.d.ts.map +1 -0
  20. package/dist/commands/context.js +55 -0
  21. package/dist/commands/context.js.map +1 -0
  22. package/dist/commands/demo-story-a.d.ts +12 -0
  23. package/dist/commands/demo-story-a.d.ts.map +1 -0
  24. package/dist/commands/demo-story-a.js +175 -0
  25. package/dist/commands/demo-story-a.js.map +1 -0
  26. package/dist/commands/diagnose.d.ts +35 -0
  27. package/dist/commands/diagnose.d.ts.map +1 -0
  28. package/dist/commands/diagnose.js +390 -0
  29. package/dist/commands/diagnose.js.map +1 -0
  30. package/dist/commands/evolution-tasks-list.d.ts +15 -0
  31. package/dist/commands/evolution-tasks-list.d.ts.map +1 -0
  32. package/dist/commands/evolution-tasks-list.js +34 -0
  33. package/dist/commands/evolution-tasks-list.js.map +1 -0
  34. package/dist/commands/evolution-tasks-show.d.ts +14 -0
  35. package/dist/commands/evolution-tasks-show.d.ts.map +1 -0
  36. package/dist/commands/evolution-tasks-show.js +52 -0
  37. package/dist/commands/evolution-tasks-show.js.map +1 -0
  38. package/dist/commands/flow.d.ts +7 -0
  39. package/dist/commands/flow.d.ts.map +1 -0
  40. package/dist/commands/flow.js +57 -0
  41. package/dist/commands/flow.js.map +1 -0
  42. package/dist/commands/health.d.ts +16 -0
  43. package/dist/commands/health.d.ts.map +1 -0
  44. package/dist/commands/health.js +150 -0
  45. package/dist/commands/health.js.map +1 -0
  46. package/dist/commands/history.d.ts +11 -0
  47. package/dist/commands/history.d.ts.map +1 -0
  48. package/dist/commands/history.js +50 -0
  49. package/dist/commands/history.js.map +1 -0
  50. package/dist/commands/legacy-cleanup.d.ts +27 -0
  51. package/dist/commands/legacy-cleanup.d.ts.map +1 -0
  52. package/dist/commands/legacy-cleanup.js +171 -0
  53. package/dist/commands/legacy-cleanup.js.map +1 -0
  54. package/dist/commands/legacy-import.d.ts +7 -0
  55. package/dist/commands/legacy-import.d.ts.map +1 -0
  56. package/dist/commands/legacy-import.js +86 -0
  57. package/dist/commands/legacy-import.js.map +1 -0
  58. package/dist/commands/pain-record.d.ts +10 -0
  59. package/dist/commands/pain-record.d.ts.map +1 -0
  60. package/dist/commands/pain-record.js +162 -0
  61. package/dist/commands/pain-record.js.map +1 -0
  62. package/dist/commands/proven-channel-baseline.d.ts +12 -0
  63. package/dist/commands/proven-channel-baseline.d.ts.map +1 -0
  64. package/dist/commands/proven-channel-baseline.js +97 -0
  65. package/dist/commands/proven-channel-baseline.js.map +1 -0
  66. package/dist/commands/remediation-output.d.ts +40 -0
  67. package/dist/commands/remediation-output.d.ts.map +1 -0
  68. package/dist/commands/remediation-output.js +23 -0
  69. package/dist/commands/remediation-output.js.map +1 -0
  70. package/dist/commands/run.d.ts +10 -0
  71. package/dist/commands/run.d.ts.map +1 -0
  72. package/dist/commands/run.js +68 -0
  73. package/dist/commands/run.js.map +1 -0
  74. package/dist/commands/runtime-activation.d.ts +11 -0
  75. package/dist/commands/runtime-activation.d.ts.map +1 -0
  76. package/dist/commands/runtime-activation.js +150 -0
  77. package/dist/commands/runtime-activation.js.map +1 -0
  78. package/dist/commands/runtime-canary.d.ts +30 -0
  79. package/dist/commands/runtime-canary.d.ts.map +1 -0
  80. package/dist/commands/runtime-canary.js +343 -0
  81. package/dist/commands/runtime-canary.js.map +1 -0
  82. package/dist/commands/runtime-diagnostics-export.d.ts +20 -0
  83. package/dist/commands/runtime-diagnostics-export.d.ts.map +1 -0
  84. package/dist/commands/runtime-diagnostics-export.js +177 -0
  85. package/dist/commands/runtime-diagnostics-export.js.map +1 -0
  86. package/dist/commands/runtime-features.d.ts +26 -0
  87. package/dist/commands/runtime-features.d.ts.map +1 -0
  88. package/dist/commands/runtime-features.js +70 -0
  89. package/dist/commands/runtime-features.js.map +1 -0
  90. package/dist/commands/runtime-gfi-snapshot.d.ts +7 -0
  91. package/dist/commands/runtime-gfi-snapshot.d.ts.map +1 -0
  92. package/dist/commands/runtime-gfi-snapshot.js +101 -0
  93. package/dist/commands/runtime-gfi-snapshot.js.map +1 -0
  94. package/dist/commands/runtime-health-snapshot.d.ts +7 -0
  95. package/dist/commands/runtime-health-snapshot.d.ts.map +1 -0
  96. package/dist/commands/runtime-health-snapshot.js +93 -0
  97. package/dist/commands/runtime-health-snapshot.js.map +1 -0
  98. package/dist/commands/runtime-idle-trigger.d.ts +12 -0
  99. package/dist/commands/runtime-idle-trigger.d.ts.map +1 -0
  100. package/dist/commands/runtime-idle-trigger.js +102 -0
  101. package/dist/commands/runtime-idle-trigger.js.map +1 -0
  102. package/dist/commands/runtime-internalization-enqueue-successors.d.ts +9 -0
  103. package/dist/commands/runtime-internalization-enqueue-successors.d.ts.map +1 -0
  104. package/dist/commands/runtime-internalization-enqueue-successors.js +393 -0
  105. package/dist/commands/runtime-internalization-enqueue-successors.js.map +1 -0
  106. package/dist/commands/runtime-internalization-integrity-repair.d.ts +9 -0
  107. package/dist/commands/runtime-internalization-integrity-repair.d.ts.map +1 -0
  108. package/dist/commands/runtime-internalization-integrity-repair.js +54 -0
  109. package/dist/commands/runtime-internalization-integrity-repair.js.map +1 -0
  110. package/dist/commands/runtime-internalization-integrity.d.ts +7 -0
  111. package/dist/commands/runtime-internalization-integrity.d.ts.map +1 -0
  112. package/dist/commands/runtime-internalization-integrity.js +53 -0
  113. package/dist/commands/runtime-internalization-integrity.js.map +1 -0
  114. package/dist/commands/runtime-internalization-queue.d.ts +7 -0
  115. package/dist/commands/runtime-internalization-queue.d.ts.map +1 -0
  116. package/dist/commands/runtime-internalization-queue.js +85 -0
  117. package/dist/commands/runtime-internalization-queue.js.map +1 -0
  118. package/dist/commands/runtime-internalization-run-once.d.ts +12 -0
  119. package/dist/commands/runtime-internalization-run-once.d.ts.map +1 -0
  120. package/dist/commands/runtime-internalization-run-once.js +546 -0
  121. package/dist/commands/runtime-internalization-run-once.js.map +1 -0
  122. package/dist/commands/runtime-internalization-wake-once.d.ts +8 -0
  123. package/dist/commands/runtime-internalization-wake-once.d.ts.map +1 -0
  124. package/dist/commands/runtime-internalization-wake-once.js +72 -0
  125. package/dist/commands/runtime-internalization-wake-once.js.map +1 -0
  126. package/dist/commands/runtime-pain-flood-simulation.d.ts +10 -0
  127. package/dist/commands/runtime-pain-flood-simulation.d.ts.map +1 -0
  128. package/dist/commands/runtime-pain-flood-simulation.js +104 -0
  129. package/dist/commands/runtime-pain-flood-simulation.js.map +1 -0
  130. package/dist/commands/runtime-pruning.d.ts +45 -0
  131. package/dist/commands/runtime-pruning.d.ts.map +1 -0
  132. package/dist/commands/runtime-pruning.js +355 -0
  133. package/dist/commands/runtime-pruning.js.map +1 -0
  134. package/dist/commands/runtime-recovery.d.ts +9 -0
  135. package/dist/commands/runtime-recovery.d.ts.map +1 -0
  136. package/dist/commands/runtime-recovery.js +94 -0
  137. package/dist/commands/runtime-recovery.js.map +1 -0
  138. package/dist/commands/runtime-synthetic-baseline.d.ts +7 -0
  139. package/dist/commands/runtime-synthetic-baseline.d.ts.map +1 -0
  140. package/dist/commands/runtime-synthetic-baseline.js +59 -0
  141. package/dist/commands/runtime-synthetic-baseline.js.map +1 -0
  142. package/dist/commands/runtime-uat.d.ts +52 -0
  143. package/dist/commands/runtime-uat.d.ts.map +1 -0
  144. package/dist/commands/runtime-uat.js +274 -0
  145. package/dist/commands/runtime-uat.js.map +1 -0
  146. package/dist/commands/runtime.d.ts +20 -0
  147. package/dist/commands/runtime.d.ts.map +1 -0
  148. package/dist/commands/runtime.js +256 -0
  149. package/dist/commands/runtime.js.map +1 -0
  150. package/dist/commands/samples-list.d.ts +11 -0
  151. package/dist/commands/samples-list.d.ts.map +1 -0
  152. package/dist/commands/samples-list.js +37 -0
  153. package/dist/commands/samples-list.js.map +1 -0
  154. package/dist/commands/samples-review.d.ts +14 -0
  155. package/dist/commands/samples-review.d.ts.map +1 -0
  156. package/dist/commands/samples-review.js +22 -0
  157. package/dist/commands/samples-review.js.map +1 -0
  158. package/dist/commands/task.d.ts +14 -0
  159. package/dist/commands/task.d.ts.map +1 -0
  160. package/dist/commands/task.js +92 -0
  161. package/dist/commands/task.js.map +1 -0
  162. package/dist/commands/trace.d.ts +19 -0
  163. package/dist/commands/trace.d.ts.map +1 -0
  164. package/dist/commands/trace.js +154 -0
  165. package/dist/commands/trace.js.map +1 -0
  166. package/dist/commands/trajectory.d.ts +11 -0
  167. package/dist/commands/trajectory.d.ts.map +1 -0
  168. package/dist/commands/trajectory.js +47 -0
  169. package/dist/commands/trajectory.js.map +1 -0
  170. package/dist/index.d.ts +9 -0
  171. package/dist/index.d.ts.map +1 -0
  172. package/dist/index.js +736 -0
  173. package/dist/index.js.map +1 -0
  174. package/dist/legacy/legacy-import.d.ts +15 -0
  175. package/dist/legacy/legacy-import.d.ts.map +1 -0
  176. package/dist/legacy/legacy-import.js +141 -0
  177. package/dist/legacy/legacy-import.js.map +1 -0
  178. package/dist/legacy/session-history-import.d.ts +26 -0
  179. package/dist/legacy/session-history-import.d.ts.map +1 -0
  180. package/dist/legacy/session-history-import.js +151 -0
  181. package/dist/legacy/session-history-import.js.map +1 -0
  182. package/dist/principle-tree-ledger-adapter.d.ts +12 -0
  183. package/dist/principle-tree-ledger-adapter.d.ts.map +1 -0
  184. package/dist/principle-tree-ledger-adapter.js +12 -0
  185. package/dist/principle-tree-ledger-adapter.js.map +1 -0
  186. package/dist/resolve-workspace.d.ts +12 -0
  187. package/dist/resolve-workspace.d.ts.map +1 -0
  188. package/dist/resolve-workspace.js +20 -0
  189. package/dist/resolve-workspace.js.map +1 -0
  190. package/dist/services/demo-story-a-runner.d.ts +8 -0
  191. package/dist/services/demo-story-a-runner.d.ts.map +1 -0
  192. package/dist/services/demo-story-a-runner.js +369 -0
  193. package/dist/services/demo-story-a-runner.js.map +1 -0
  194. package/dist/services/feature-flag-loader.d.ts +6 -0
  195. package/dist/services/feature-flag-loader.d.ts.map +1 -0
  196. package/dist/services/feature-flag-loader.js +54 -0
  197. package/dist/services/feature-flag-loader.js.map +1 -0
  198. package/dist/services/pain-flood-simulation-runner.d.ts +10 -0
  199. package/dist/services/pain-flood-simulation-runner.d.ts.map +1 -0
  200. package/dist/services/pain-flood-simulation-runner.js +289 -0
  201. package/dist/services/pain-flood-simulation-runner.js.map +1 -0
  202. package/dist/services/proven-channel-baseline-runner.d.ts +12 -0
  203. package/dist/services/proven-channel-baseline-runner.d.ts.map +1 -0
  204. package/dist/services/proven-channel-baseline-runner.js +114 -0
  205. package/dist/services/proven-channel-baseline-runner.js.map +1 -0
  206. package/dist/services/synthetic-baseline-runner.d.ts +8 -0
  207. package/dist/services/synthetic-baseline-runner.d.ts.map +1 -0
  208. package/dist/services/synthetic-baseline-runner.js +251 -0
  209. package/dist/services/synthetic-baseline-runner.js.map +1 -0
  210. package/package.json +35 -0
  211. package/src/commands/artifact.ts +82 -0
  212. package/src/commands/candidate.ts +1117 -0
  213. package/src/commands/central-sync.ts +44 -0
  214. package/src/commands/console.ts +121 -0
  215. package/src/commands/context.ts +72 -0
  216. package/src/commands/demo-story-a.ts +195 -0
  217. package/src/commands/diagnose.ts +452 -0
  218. package/src/commands/evolution-tasks-list.ts +44 -0
  219. package/src/commands/evolution-tasks-show.ts +60 -0
  220. package/src/commands/flow.ts +60 -0
  221. package/src/commands/health.ts +189 -0
  222. package/src/commands/history.ts +63 -0
  223. package/src/commands/legacy-cleanup.ts +206 -0
  224. package/src/commands/legacy-import.ts +104 -0
  225. package/src/commands/pain-record.ts +167 -0
  226. package/src/commands/proven-channel-baseline.ts +113 -0
  227. package/src/commands/remediation-output.ts +66 -0
  228. package/src/commands/run.ts +89 -0
  229. package/src/commands/runtime-activation.ts +176 -0
  230. package/src/commands/runtime-canary.ts +371 -0
  231. package/src/commands/runtime-diagnostics-export.ts +229 -0
  232. package/src/commands/runtime-features.ts +103 -0
  233. package/src/commands/runtime-gfi-snapshot.ts +135 -0
  234. package/src/commands/runtime-health-snapshot.ts +106 -0
  235. package/src/commands/runtime-internalization-enqueue-successors.ts +479 -0
  236. package/src/commands/runtime-internalization-integrity-repair.ts +69 -0
  237. package/src/commands/runtime-internalization-integrity.ts +63 -0
  238. package/src/commands/runtime-internalization-queue.ts +106 -0
  239. package/src/commands/runtime-internalization-run-once.ts +658 -0
  240. package/src/commands/runtime-internalization-wake-once.ts +87 -0
  241. package/src/commands/runtime-pain-flood-simulation.ts +121 -0
  242. package/src/commands/runtime-pruning.ts +438 -0
  243. package/src/commands/runtime-recovery.ts +107 -0
  244. package/src/commands/runtime-synthetic-baseline.ts +70 -0
  245. package/src/commands/runtime-uat.ts +339 -0
  246. package/src/commands/runtime.ts +281 -0
  247. package/src/commands/samples-list.ts +43 -0
  248. package/src/commands/samples-review.ts +32 -0
  249. package/src/commands/task.ts +130 -0
  250. package/src/commands/trace.ts +174 -0
  251. package/src/commands/trajectory.ts +64 -0
  252. package/src/index.ts +829 -0
  253. package/src/legacy/legacy-import.ts +179 -0
  254. package/src/legacy/session-history-import.ts +231 -0
  255. package/src/principle-tree-ledger-adapter.ts +13 -0
  256. package/src/resolve-workspace.ts +20 -0
  257. package/src/services/demo-story-a-runner.ts +472 -0
  258. package/src/services/feature-flag-loader.ts +73 -0
  259. package/src/services/pain-flood-simulation-runner.ts +354 -0
  260. package/src/services/proven-channel-baseline-runner.ts +150 -0
  261. package/src/services/synthetic-baseline-runner.ts +291 -0
  262. package/tests/commands/candidate-audit-repair.test.ts +338 -0
  263. package/tests/commands/candidate-intake.test.ts +589 -0
  264. package/tests/commands/candidate-internalization-backfill.test.ts +480 -0
  265. package/tests/commands/candidate-internalize.test.ts +272 -0
  266. package/tests/commands/candidate-route.test.ts +328 -0
  267. package/tests/commands/candidate-show.test.ts +95 -0
  268. package/tests/commands/cli-command-tree.test.ts +64 -0
  269. package/tests/commands/context.test.ts +114 -0
  270. package/tests/commands/demo-story-a.test.ts +255 -0
  271. package/tests/commands/diagnose.test.ts +792 -0
  272. package/tests/commands/health.test.ts +330 -0
  273. package/tests/commands/pain-record.test.ts +316 -0
  274. package/tests/commands/plugin-config-resolution-cutover.test.ts +220 -0
  275. package/tests/commands/proven-channel-baseline.test.ts +441 -0
  276. package/tests/commands/runtime-activation.test.ts +168 -0
  277. package/tests/commands/runtime-canary.test.ts +369 -0
  278. package/tests/commands/runtime-diagnostics-export.test.ts +170 -0
  279. package/tests/commands/runtime-features.test.ts +114 -0
  280. package/tests/commands/runtime-health-snapshot.test.ts +357 -0
  281. package/tests/commands/runtime-internalization-enqueue-successors.test.ts +803 -0
  282. package/tests/commands/runtime-internalization-integrity-repair.test.ts +169 -0
  283. package/tests/commands/runtime-internalization-integrity.test.ts +102 -0
  284. package/tests/commands/runtime-internalization-queue.test.ts +252 -0
  285. package/tests/commands/runtime-internalization-run-once.test.ts +1318 -0
  286. package/tests/commands/runtime-internalization-wake-once.test.ts +170 -0
  287. package/tests/commands/runtime-internalization.test.ts +52 -0
  288. package/tests/commands/runtime-pain-flood-simulation.test.ts +418 -0
  289. package/tests/commands/runtime-pruning.test.ts +693 -0
  290. package/tests/commands/runtime-recovery.test.ts +96 -0
  291. package/tests/commands/runtime-synthetic-baseline.test.ts +249 -0
  292. package/tests/commands/runtime-uat.test.ts +397 -0
  293. package/tests/commands/runtime.test.ts +262 -0
  294. package/tests/commands/trace.test.ts +314 -0
  295. package/tests/e2e/candidate-intake-e2e.test.ts +316 -0
  296. package/tests/services/feature-flag-loader.test.ts +207 -0
  297. package/tests/services/proven-channel-baseline-runner.test.ts +30 -0
  298. package/tsconfig.json +26 -0
@@ -0,0 +1,189 @@
1
+ /**
2
+ * pd health command implementation — Runtime V2 edition.
3
+ *
4
+ * Usage: pd health [--workspace <path>] [--json]
5
+ *
6
+ * Reads workspace/.pd/state.db and workspace/.state/principle_training_state.json
7
+ * to provide Runtime V2 health diagnostics.
8
+ * Uses read models from @principles/core/runtime-v2 (no direct ledger access).
9
+ */
10
+
11
+ import * as fs from 'fs';
12
+ import * as path from 'path';
13
+ import Database from 'better-sqlite3';
14
+ import { resolveWorkspaceDir } from '../resolve-workspace.js';
15
+ import { PruningReadModel, PainChainReadModel, auditCandidateLedgerConsistency, getLedgerFilePathPublic } from '@principles/core/runtime-v2';
16
+ import type { PainChainTrace } from '@principles/core/runtime-v2';
17
+
18
+ interface LastSuccessfulChain {
19
+ painId?: string;
20
+ taskId: string;
21
+ runId: string;
22
+ artifactId: string;
23
+ candidateIds: string[];
24
+ ledgerEntryIds: string[];
25
+ latencyMs?: { totalMs?: number };
26
+ failureCategory: string | null;
27
+ checkedAt: string;
28
+ }
29
+
30
+ interface WorkspaceHealth {
31
+ generatedAt: string;
32
+ workspace: string;
33
+ partialHealth?: boolean;
34
+ pdStateDb: { path: string; exists: boolean };
35
+ ledger: { path: string; exists: boolean; totalPrinciples: number; byStatus: Record<string, number> };
36
+ candidates: { total: number; consumed: number; pending: number };
37
+ tasks: { total: number; byStatus: Record<string, number> };
38
+ candidateLedgerConsistency: { status: 'ok' | 'degraded'; missing: number };
39
+ lastSuccessfulChain?: LastSuccessfulChain;
40
+ }
41
+
42
+ interface HealthOptions {
43
+ workspace?: string;
44
+ json?: boolean;
45
+ }
46
+
47
+ function painChainTraceToLastSuccessfulChain(trace: PainChainTrace): LastSuccessfulChain {
48
+ const totalMs = (trace.latencyMs.painToTask ?? 0)
49
+ + (trace.latencyMs.taskToRun ?? 0)
50
+ + (trace.latencyMs.runToArtifact ?? 0);
51
+
52
+ return {
53
+ painId: trace.painId,
54
+ taskId: trace.taskId,
55
+ runId: trace.runId ?? '',
56
+ artifactId: trace.artifactId ?? '',
57
+ candidateIds: trace.candidateIds,
58
+ ledgerEntryIds: trace.ledgerEntryIds,
59
+ latencyMs: { totalMs: totalMs > 0 ? totalMs : undefined },
60
+ failureCategory: trace.failureCategory,
61
+ checkedAt: trace.checkedAt,
62
+ };
63
+ }
64
+
65
+ export async function handleHealth(opts: HealthOptions = {}): Promise<void> {
66
+ const workspaceDir = opts.workspace
67
+ ? path.resolve(opts.workspace)
68
+ : resolveWorkspaceDir();
69
+
70
+ const generatedAt = new Date().toISOString();
71
+ const pdDbPath = path.join(workspaceDir, '.pd', 'state.db');
72
+ const ledgerStateDir = path.join(workspaceDir, '.state');
73
+ const ledgerPath = getLedgerFilePathPublic(ledgerStateDir);
74
+
75
+ const pruningModel = new PruningReadModel({ workspaceDir });
76
+ const healthSummary = pruningModel.getHealthSummary();
77
+ const ledgerByStatus = healthSummary.byStatus;
78
+
79
+ const { missingLedgerCount } = await auditCandidateLedgerConsistency(workspaceDir);
80
+
81
+ let candidatesTotal = 0, candidatesConsumed = 0, candidatesPending = 0;
82
+ let tasksTotal = 0;
83
+ const tasksByStatus: Record<string, number> = {};
84
+ let pdDbExists = false;
85
+ let lastSuccessfulChain: LastSuccessfulChain | undefined = undefined;
86
+ let partialHealth = false;
87
+
88
+ function buildHealth(): WorkspaceHealth {
89
+ return {
90
+ generatedAt,
91
+ workspace: workspaceDir,
92
+ partialHealth,
93
+ pdStateDb: { path: pdDbPath, exists: pdDbExists },
94
+ ledger: {
95
+ path: ledgerPath,
96
+ exists: fs.existsSync(ledgerPath),
97
+ totalPrinciples: healthSummary.totalPrinciples,
98
+ byStatus: ledgerByStatus,
99
+ },
100
+ candidates: { total: candidatesTotal, consumed: candidatesConsumed, pending: candidatesPending },
101
+ tasks: { total: tasksTotal, byStatus: tasksByStatus },
102
+ candidateLedgerConsistency: {
103
+ status: missingLedgerCount === 0 ? 'ok' : 'degraded',
104
+ missing: missingLedgerCount,
105
+ },
106
+ lastSuccessfulChain,
107
+ };
108
+ }
109
+
110
+ function writeHealth(): void {
111
+ const health = buildHealth();
112
+
113
+ if (opts.json) {
114
+ console.log(JSON.stringify(health, null, 2));
115
+ if (health.candidateLedgerConsistency.status === 'degraded') process.exit(1);
116
+ return;
117
+ }
118
+
119
+ console.log(`generatedAt: ${health.generatedAt}`);
120
+ console.log(`workspace: ${health.workspace}`);
121
+ console.log(`pdStateDb.exists: ${health.pdStateDb.exists}`);
122
+ console.log(`pdStateDb.path: ${health.pdStateDb.path}`);
123
+ console.log(`ledger.exists: ${health.ledger.exists}`);
124
+ console.log(`ledger.path: ${health.ledger.path}`);
125
+ console.log(`ledger.totalPrinciples: ${health.ledger.totalPrinciples}`);
126
+ console.log(`ledger.byStatus: ${JSON.stringify(health.ledger.byStatus)}`);
127
+ console.log(`candidates.total: ${health.candidates.total}`);
128
+ console.log(`candidates.consumed: ${health.candidates.consumed}`);
129
+ console.log(`candidates.pending: ${health.candidates.pending}`);
130
+ console.log(`tasks.total: ${health.tasks.total}`);
131
+ console.log(`tasks.byStatus: ${JSON.stringify(health.tasks.byStatus)}`);
132
+ console.log(`candidateLedgerConsistency.status: ${health.candidateLedgerConsistency.status}`);
133
+ console.log(`candidateLedgerConsistency.missing: ${health.candidateLedgerConsistency.missing}`);
134
+ if (health.lastSuccessfulChain) {
135
+ console.log('lastSuccessfulChain:');
136
+ console.log(` taskId: ${health.lastSuccessfulChain.taskId}`);
137
+ console.log(` runId: ${health.lastSuccessfulChain.runId}`);
138
+ console.log(` artifactId: ${health.lastSuccessfulChain.artifactId}`);
139
+ console.log(` candidateIds: ${health.lastSuccessfulChain.candidateIds.join(', ')}`);
140
+ console.log(` ledgerEntries: ${health.lastSuccessfulChain.ledgerEntryIds.join(', ')}`);
141
+ }
142
+ console.log('');
143
+
144
+ if (health.candidateLedgerConsistency.status === 'degraded') {
145
+ console.warn('⚠️ Candidate/ledger consistency is DEGRADED. Run: pd candidate audit --workspace "' + workspaceDir + '" --json');
146
+ console.warn(' To repair missing entries: pd candidate repair --candidate-id <id> --workspace "' + workspaceDir + '" --json');
147
+ process.exit(1);
148
+ }
149
+ }
150
+
151
+ if (fs.existsSync(pdDbPath)) {
152
+ pdDbExists = true;
153
+ const db = Database(pdDbPath, { readonly: true });
154
+ try {
155
+ const cRow = db.prepare('SELECT COUNT(*) as total, status FROM principle_candidates GROUP BY status').all() as { total: number; status: string }[];
156
+ for (const r of cRow) {
157
+ candidatesTotal += r.total;
158
+ if (r.status === 'consumed') candidatesConsumed = r.total;
159
+ if (r.status === 'pending') candidatesPending = r.total;
160
+ }
161
+
162
+ const tRows = db.prepare('SELECT COUNT(*) as total, status FROM tasks GROUP BY status').all() as { total: number; status: string }[];
163
+ for (const r of tRows) {
164
+ tasksTotal += r.total;
165
+ tasksByStatus[r.status] = r.total;
166
+ }
167
+
168
+ const painChainModel = new PainChainReadModel({ workspaceDir });
169
+ try {
170
+ const chain = await painChainModel.getLastSuccessfulChain();
171
+ if (chain) {
172
+ lastSuccessfulChain = painChainTraceToLastSuccessfulChain(chain);
173
+ }
174
+ } catch {
175
+ partialHealth = true;
176
+ } finally {
177
+ await painChainModel.close();
178
+ }
179
+ } catch (err) {
180
+ const msg = err instanceof Error ? err.message : String(err);
181
+ console.warn(`Warning: could not read full state.db metrics — partial health data: ${msg}`);
182
+ partialHealth = true;
183
+ } finally {
184
+ db.close();
185
+ }
186
+ }
187
+
188
+ writeHealth();
189
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * pd history query — Query run history for a task with pagination.
3
+ *
4
+ * Usage:
5
+ * pd history query <taskId> [--limit N] [--cursor <cursor>]
6
+ * pd history query <taskId> --from <date> --to <date>
7
+ */
8
+ import { SqliteConnection, SqliteHistoryQuery } from '@principles/core';
9
+ import { resolveWorkspaceDir } from '../resolve-workspace.js';
10
+
11
+ interface HistoryQueryOptions {
12
+ limit?: number;
13
+ cursor?: string;
14
+ from?: string;
15
+ to?: string;
16
+ json?: boolean;
17
+ workspace?: string;
18
+ }
19
+
20
+ export async function handleHistoryQuery(taskId: string, opts: HistoryQueryOptions): Promise<void> {
21
+ const workspaceDir = resolveWorkspaceDir(opts.workspace);
22
+ const connection = new SqliteConnection(workspaceDir);
23
+
24
+ try {
25
+ const historyQuery = new SqliteHistoryQuery(connection);
26
+
27
+ const queryOpts = opts.limit || opts.from || opts.to
28
+ ? {
29
+ limit: opts.limit,
30
+ timeWindowStart: opts.from,
31
+ timeWindowEnd: opts.to,
32
+ }
33
+ : undefined;
34
+ const result = await historyQuery.query(taskId, opts.cursor, queryOpts);
35
+
36
+ if (opts.json) {
37
+ console.log(JSON.stringify(result, null, 2));
38
+ return;
39
+ }
40
+
41
+ if (result.entries.length === 0) {
42
+ console.log('No history entries found.');
43
+ return;
44
+ }
45
+
46
+ console.log(`\nHistory for ${taskId} (${result.entries.length} entries${result.truncated ? ', truncated' : ''}):\n`);
47
+ for (const entry of result.entries) {
48
+ const text = entry.text ? (entry.text.length > 60 ? entry.text.substring(0, 57) + '...' : entry.text) : '<empty>';
49
+ console.log(' [%s] %-8s %s', entry.ts.substring(11, 19), entry.role, text);
50
+ }
51
+
52
+ if (result.nextCursor) {
53
+ console.log(`\n nextCursor: ${result.nextCursor}`);
54
+ }
55
+ console.log('');
56
+ } catch (error) {
57
+ const message = error instanceof Error ? error.message : String(error);
58
+ console.error(`Error: ${message}`);
59
+ process.exit(1);
60
+ } finally {
61
+ connection.close();
62
+ }
63
+ }
@@ -0,0 +1,206 @@
1
+ /**
2
+ * pd legacy cleanup
3
+ *
4
+ * Cleans legacy artifacts from workspaces:
5
+ * - .state/pd_tasks.json (removes empathy-optimizer entries)
6
+ * - .state/sessions/*.json (archives sessions with cron:pd-empathy-optimizer)
7
+ * - .state/diagnostician_tasks.json (archives)
8
+ * - .state/.evolution_complete_* (archives)
9
+ * - .state/.diagnostician_report_* (archives)
10
+ * - ~/.openclaw/cron/jobs.json (removes pd-empathy-optimizer cron jobs)
11
+ *
12
+ * Usage:
13
+ * pd legacy cleanup --workspace <path> --dry-run
14
+ * pd legacy cleanup --workspace <path> --apply
15
+ */
16
+
17
+ import * as fs from 'fs';
18
+ import * as path from 'path';
19
+ import * as os from 'os';
20
+
21
+ interface CleanupTarget {
22
+ path: string;
23
+ action: 'remove' | 'archive';
24
+ reason: string;
25
+ archivePath?: string;
26
+ }
27
+
28
+ interface CronJobRecord {
29
+ id?: string;
30
+ name?: string;
31
+ [key: string]: unknown;
32
+ }
33
+
34
+ interface _CronStore {
35
+ jobs: CronJobRecord[];
36
+ }
37
+
38
+ interface TaskRecord {
39
+ id?: string;
40
+ name?: string;
41
+ [key: string]: unknown;
42
+ }
43
+
44
+ function glob(pattern: string): string[] {
45
+ const results: string[] = [];
46
+ const baseDir = path.dirname(pattern);
47
+ const filePattern = path.basename(pattern).replace(/\*/g, '');
48
+
49
+ if (!fs.existsSync(baseDir)) return [];
50
+
51
+ for (const file of fs.readdirSync(baseDir)) {
52
+ if (file.startsWith(filePattern) || filePattern === '') {
53
+ const fullPath = path.join(baseDir, file);
54
+ const stat = fs.statSync(fullPath);
55
+ if (stat.isFile()) results.push(fullPath);
56
+ }
57
+ }
58
+ return results;
59
+ }
60
+
61
+ function findLegacyTargets(workspacePath: string): CleanupTarget[] {
62
+ const targets: CleanupTarget[] = [];
63
+ const stateDir = path.join(workspacePath, '.state');
64
+ const archiveTimestamp = new Date().toISOString().replace(/[:.]/g, '-');
65
+ const archiveDir = path.join(stateDir, 'legacy-archive', archiveTimestamp);
66
+
67
+ // 1. pd_tasks.json — remove empathy-optimizer entries
68
+ const pdTasksPath = path.join(stateDir, 'pd_tasks.json');
69
+ if (fs.existsSync(pdTasksPath)) {
70
+ try {
71
+ const content = fs.readFileSync(pdTasksPath, 'utf-8');
72
+ const tasks = JSON.parse(content);
73
+ const filtered = tasks.filter((t: TaskRecord) =>
74
+ !t.id?.includes('empathy-optimizer') && !t.name?.includes('Empathy Optimizer')
75
+ );
76
+ if (filtered.length !== tasks.length) {
77
+ targets.push({
78
+ path: pdTasksPath,
79
+ action: 'archive',
80
+ reason: 'Removed empathy-optimizer entries from pd_tasks.json',
81
+ archivePath: path.join(archiveDir, 'pd_tasks.json.backup'),
82
+ });
83
+ }
84
+ } catch { /* skip invalid JSON */ }
85
+ }
86
+
87
+ // 2. sessions/*.json — archive empathy cron sessions
88
+ const sessionsDir = path.join(stateDir, 'sessions');
89
+ if (fs.existsSync(sessionsDir)) {
90
+ for (const file of fs.readdirSync(sessionsDir)) {
91
+ if (!file.endsWith('.json')) continue;
92
+ const filePath = path.join(sessionsDir, file);
93
+ try {
94
+ const content = fs.readFileSync(filePath, 'utf-8');
95
+ const session = JSON.parse(content);
96
+ if (session.sessionKey?.includes('cron:pd-empathy-optimizer') ||
97
+ session.sessionKey?.includes('cron:empathy-optimizer')) {
98
+ targets.push({
99
+ path: filePath,
100
+ action: 'archive',
101
+ reason: `Legacy empathy cron session: ${session.sessionKey}`,
102
+ archivePath: path.join(archiveDir, 'sessions', file),
103
+ });
104
+ }
105
+ } catch { /* skip */ }
106
+ }
107
+ }
108
+
109
+ // 3. diagnostician_tasks.json
110
+ const diagPath = path.join(stateDir, 'diagnostician_tasks.json');
111
+ if (fs.existsSync(diagPath)) {
112
+ targets.push({
113
+ path: diagPath,
114
+ action: 'archive',
115
+ reason: 'Legacy diagnostician task store',
116
+ archivePath: path.join(archiveDir, 'diagnostician_tasks.json'),
117
+ });
118
+ }
119
+
120
+ // 4. .evolution_complete_* markers
121
+ for (const marker of glob(path.join(stateDir, '.evolution_complete_*'))) {
122
+ targets.push({
123
+ path: marker,
124
+ action: 'archive',
125
+ reason: 'Legacy evolution marker',
126
+ archivePath: path.join(archiveDir, path.basename(marker)),
127
+ });
128
+ }
129
+
130
+ // 5. .diagnostician_report_* markers
131
+ for (const marker of glob(path.join(stateDir, '.diagnostician_report_*'))) {
132
+ targets.push({
133
+ path: marker,
134
+ action: 'archive',
135
+ reason: 'Legacy diagnostician report marker',
136
+ archivePath: path.join(archiveDir, path.basename(marker)),
137
+ });
138
+ }
139
+
140
+ // 6. OpenClaw cron jobs.json
141
+ const cronPath = path.join(os.homedir(), '.openclaw', 'cron', 'jobs.json');
142
+ if (fs.existsSync(cronPath)) {
143
+ try {
144
+ const content = fs.readFileSync(cronPath, 'utf-8');
145
+ const store = JSON.parse(content) as _CronStore;
146
+ const filtered = store.jobs.filter((j: CronJobRecord) =>
147
+ !j.id?.includes('pd-empathy-optimizer') && !j.name?.includes('Empathy Optimizer')
148
+ );
149
+ if (filtered.length !== store.jobs.length) {
150
+ targets.push({
151
+ path: cronPath,
152
+ action: 'archive',
153
+ reason: 'Removed pd-empathy-optimizer cron jobs',
154
+ archivePath: path.join(os.homedir(), '.openclaw', 'cron', `jobs.json.backup-${archiveTimestamp}`),
155
+ });
156
+ }
157
+ } catch { /* skip */ }
158
+ }
159
+
160
+ return targets;
161
+ }
162
+
163
+ export async function handleLegacyCleanup(
164
+ workspacePath: string,
165
+ dryRun: boolean
166
+ ): Promise<{ targets: CleanupTarget[]; applied: number }> {
167
+ const targets = findLegacyTargets(workspacePath);
168
+ let applied = 0;
169
+
170
+ if (dryRun) {
171
+ console.log(`\n=== DRY RUN: Would process ${targets.length} target(s) ===`);
172
+ for (const t of targets) {
173
+ console.log(` ${t.action}: ${t.path}`);
174
+ console.log(` Reason: ${t.reason}`);
175
+ if (t.archivePath) {
176
+ console.log(` Archive: ${t.archivePath}`);
177
+ }
178
+ }
179
+ if (targets.length === 0) {
180
+ console.log(' No legacy artifacts found.');
181
+ }
182
+ } else {
183
+ console.log(`\n=== Applying ${targets.length} cleanup(s) ===`);
184
+ for (const t of targets) {
185
+ try {
186
+ if (t.action === 'archive' && t.archivePath) {
187
+ const archiveDir = path.dirname(t.archivePath);
188
+ if (!fs.existsSync(archiveDir)) {
189
+ fs.mkdirSync(archiveDir, { recursive: true });
190
+ }
191
+ fs.copyFileSync(t.path, t.archivePath);
192
+ fs.unlinkSync(t.path);
193
+ console.log(` Archived: ${t.path} -> ${t.archivePath}`);
194
+ } else {
195
+ fs.unlinkSync(t.path);
196
+ console.log(` Removed: ${t.path}`);
197
+ }
198
+ applied++;
199
+ } catch (err) {
200
+ console.error(` ERROR processing ${t.path}: ${String(err)}`);
201
+ }
202
+ }
203
+ }
204
+
205
+ return { targets, applied };
206
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * pd legacy import openclaw — Import OpenClaw legacy data into PD runtime-v2 store.
3
+ *
4
+ * Usage:
5
+ * pd legacy import openclaw --workspace <path>
6
+ *
7
+ * This command is the formal operator path for migrating OpenClaw workspace data
8
+ * into PD runtime-v2 SQLite. It must be run before trajectory/history/context commands
9
+ * can return results on a workspace that only has OpenClaw legacy data.
10
+ *
11
+ * Two import stages:
12
+ * 1. Task/Run metadata from .state/diagnostician_tasks.json
13
+ * 2. Session history from .state/trajectory.db (assistant_turns, user_turns, tool_calls)
14
+ */
15
+ import { SqliteConnection } from '@principles/core';
16
+ import { syncOpenClawWorkspace } from '../legacy/legacy-import.js';
17
+ import { importSessionHistory } from '../legacy/session-history-import.js';
18
+ import { resolveWorkspaceDir } from '../resolve-workspace.js';
19
+
20
+ interface LegacyImportOptions {
21
+ workspace?: string;
22
+ json?: boolean;
23
+ }
24
+
25
+ export async function handleLegacyImportOpenClaw(opts: LegacyImportOptions): Promise<void> {
26
+ const workspaceDir = resolveWorkspaceDir(opts.workspace);
27
+ const connection = new SqliteConnection(workspaceDir);
28
+
29
+ try {
30
+ const openclawWorkspace = workspaceDir; // same workspace for now
31
+
32
+ // Stage 1: Task/Run metadata import
33
+ if (opts.json) {
34
+ console.log(JSON.stringify({ stage: 1, source: '.state/diagnostician_tasks.json' }));
35
+ } else {
36
+ console.log('Stage 1: Importing diagnostician tasks and runs...');
37
+ }
38
+ const syncResult = await syncOpenClawWorkspace(workspaceDir, connection);
39
+
40
+ if (opts.json) {
41
+ console.log(
42
+ JSON.stringify({
43
+ stage: 1,
44
+ tasksImported: syncResult.tasksSynced,
45
+ runsImported: syncResult.runsSynced,
46
+ }),
47
+ );
48
+ } else {
49
+ console.log(` → ${syncResult.tasksSynced} tasks, ${syncResult.runsSynced} runs synced`);
50
+ }
51
+
52
+ // Stage 2: Session history import (if better-sqlite3 is available)
53
+ try {
54
+ if (opts.json) {
55
+ console.log(JSON.stringify({ stage: 2, source: '.state/trajectory.db' }));
56
+ } else {
57
+ console.log('Stage 2: Importing session history from trajectory.db...');
58
+ }
59
+
60
+
61
+ const historyResult = await importSessionHistory(
62
+ openclawWorkspace,
63
+ workspaceDir,
64
+ () => connection.getDb(),
65
+ );
66
+
67
+ if (opts.json) {
68
+ console.log(
69
+ JSON.stringify({
70
+ stage: 2,
71
+ sessionsProcessed: historyResult.sessionsProcessed,
72
+ entriesImported: historyResult.entriesImported,
73
+ }),
74
+ );
75
+ } else {
76
+ console.log(
77
+ ` → ${historyResult.sessionsProcessed} sessions, ${historyResult.entriesImported} entries imported`,
78
+ );
79
+ }
80
+ } catch (historyError) {
81
+ const msg = historyError instanceof Error ? historyError.message : String(historyError);
82
+ if (opts.json) {
83
+ console.log(
84
+ JSON.stringify({
85
+ stage: 2,
86
+ skipped: true,
87
+ reason: `better-sqlite3 not available: ${msg}`,
88
+ }),
89
+ );
90
+ } else {
91
+ console.log(` → Stage 2 skipped (better-sqlite3 not available: ${msg})`);
92
+ }
93
+ }
94
+
95
+ if (!opts.json) {
96
+ console.log('\nImport complete. You can now run:');
97
+ console.log(' pd trajectory locate --task <id> --workspace <path>');
98
+ console.log(' pd history query <id> --workspace <path>');
99
+ console.log(' pd context build <id> --workspace <path>');
100
+ }
101
+ } finally {
102
+ connection.close();
103
+ }
104
+ }