@principles/pd-cli 1.152.12 → 1.152.13

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 (296) hide show
  1. package/package.json +13 -7
  2. package/CHANGELOG.md +0 -23
  3. package/dist/commands/__tests__/intent-flag-wiring.test.d.ts +0 -9
  4. package/dist/commands/__tests__/intent-flag-wiring.test.d.ts.map +0 -1
  5. package/dist/commands/__tests__/intent-flag-wiring.test.js +0 -237
  6. package/dist/commands/__tests__/intent-flag-wiring.test.js.map +0 -1
  7. package/dist/commands/__tests__/legacy-cleanup.test.d.ts +0 -18
  8. package/dist/commands/__tests__/legacy-cleanup.test.d.ts.map +0 -1
  9. package/dist/commands/__tests__/legacy-cleanup.test.js +0 -467
  10. package/dist/commands/__tests__/legacy-cleanup.test.js.map +0 -1
  11. package/dist/commands/__tests__/mvp-smoke.test.d.ts +0 -15
  12. package/dist/commands/__tests__/mvp-smoke.test.d.ts.map +0 -1
  13. package/dist/commands/__tests__/mvp-smoke.test.js +0 -262
  14. package/dist/commands/__tests__/mvp-smoke.test.js.map +0 -1
  15. package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.d.ts +0 -2
  16. package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.d.ts.map +0 -1
  17. package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.js +0 -60
  18. package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.js.map +0 -1
  19. package/dist/commands/__tests__/rulecode-flag-wiring.test.d.ts +0 -21
  20. package/dist/commands/__tests__/rulecode-flag-wiring.test.d.ts.map +0 -1
  21. package/dist/commands/__tests__/rulecode-flag-wiring.test.js +0 -186
  22. package/dist/commands/__tests__/rulecode-flag-wiring.test.js.map +0 -1
  23. package/dist/commands/__tests__/rulecode-handler.test.d.ts +0 -16
  24. package/dist/commands/__tests__/rulecode-handler.test.d.ts.map +0 -1
  25. package/dist/commands/__tests__/rulecode-handler.test.js +0 -285
  26. package/dist/commands/__tests__/rulecode-handler.test.js.map +0 -1
  27. package/dist/commands/__tests__/run-rulehost-flag-wiring.test.d.ts +0 -24
  28. package/dist/commands/__tests__/run-rulehost-flag-wiring.test.d.ts.map +0 -1
  29. package/dist/commands/__tests__/run-rulehost-flag-wiring.test.js +0 -232
  30. package/dist/commands/__tests__/run-rulehost-flag-wiring.test.js.map +0 -1
  31. package/dist/commands/__tests__/runtime-activation-nextaction.test.d.ts +0 -15
  32. package/dist/commands/__tests__/runtime-activation-nextaction.test.d.ts.map +0 -1
  33. package/dist/commands/__tests__/runtime-activation-nextaction.test.js +0 -73
  34. package/dist/commands/__tests__/runtime-activation-nextaction.test.js.map +0 -1
  35. package/dist/commands/__tests__/runtime-probe-config.test.d.ts +0 -20
  36. package/dist/commands/__tests__/runtime-probe-config.test.d.ts.map +0 -1
  37. package/dist/commands/__tests__/runtime-probe-config.test.js +0 -389
  38. package/dist/commands/__tests__/runtime-probe-config.test.js.map +0 -1
  39. package/dist/commands/__tests__/telemetry-flag-wiring.test.d.ts +0 -9
  40. package/dist/commands/__tests__/telemetry-flag-wiring.test.d.ts.map +0 -1
  41. package/dist/commands/__tests__/telemetry-flag-wiring.test.js +0 -76
  42. package/dist/commands/__tests__/telemetry-flag-wiring.test.js.map +0 -1
  43. package/dist/commands/__tests__/version.test.d.ts +0 -2
  44. package/dist/commands/__tests__/version.test.d.ts.map +0 -1
  45. package/dist/commands/__tests__/version.test.js +0 -238
  46. package/dist/commands/__tests__/version.test.js.map +0 -1
  47. package/dist/commands/runtime-uat.guard.test.d.ts +0 -2
  48. package/dist/commands/runtime-uat.guard.test.d.ts.map +0 -1
  49. package/dist/commands/runtime-uat.guard.test.js +0 -153
  50. package/dist/commands/runtime-uat.guard.test.js.map +0 -1
  51. package/dist/services/__tests__/cli-output.test.d.ts +0 -18
  52. package/dist/services/__tests__/cli-output.test.d.ts.map +0 -1
  53. package/dist/services/__tests__/cli-output.test.js +0 -103
  54. package/dist/services/__tests__/cli-output.test.js.map +0 -1
  55. package/dist/services/__tests__/evaluator-runner-deps.test.d.ts +0 -2
  56. package/dist/services/__tests__/evaluator-runner-deps.test.d.ts.map +0 -1
  57. package/dist/services/__tests__/evaluator-runner-deps.test.js +0 -343
  58. package/dist/services/__tests__/evaluator-runner-deps.test.js.map +0 -1
  59. package/dist/services/__tests__/rulehost-readiness.test.d.ts +0 -2
  60. package/dist/services/__tests__/rulehost-readiness.test.d.ts.map +0 -1
  61. package/dist/services/__tests__/rulehost-readiness.test.js +0 -311
  62. package/dist/services/__tests__/rulehost-readiness.test.js.map +0 -1
  63. package/dist/services/__tests__/runtime-adapter-resolver.test.d.ts +0 -18
  64. package/dist/services/__tests__/runtime-adapter-resolver.test.d.ts.map +0 -1
  65. package/dist/services/__tests__/runtime-adapter-resolver.test.js +0 -673
  66. package/dist/services/__tests__/runtime-adapter-resolver.test.js.map +0 -1
  67. package/dist/utils/production-workspace-guard.test.d.ts +0 -2
  68. package/dist/utils/production-workspace-guard.test.d.ts.map +0 -1
  69. package/dist/utils/production-workspace-guard.test.js +0 -137
  70. package/dist/utils/production-workspace-guard.test.js.map +0 -1
  71. package/scripts/llm-dogfood.ts +0 -456
  72. package/scripts/migrate-illegal-expected-decision.ts +0 -252
  73. package/src/commands/__tests__/intent-flag-wiring.test.ts +0 -282
  74. package/src/commands/__tests__/legacy-cleanup.test.ts +0 -602
  75. package/src/commands/__tests__/mvp-smoke.test.ts +0 -300
  76. package/src/commands/__tests__/pain-retry-maxTokens-flag.test.ts +0 -73
  77. package/src/commands/__tests__/rulecode-flag-wiring.test.ts +0 -237
  78. package/src/commands/__tests__/rulecode-handler.test.ts +0 -369
  79. package/src/commands/__tests__/run-rulehost-flag-wiring.test.ts +0 -292
  80. package/src/commands/__tests__/runtime-activation-nextaction.test.ts +0 -81
  81. package/src/commands/__tests__/runtime-probe-config.test.ts +0 -432
  82. package/src/commands/__tests__/telemetry-flag-wiring.test.ts +0 -84
  83. package/src/commands/__tests__/version.test.ts +0 -251
  84. package/src/commands/admission-gate.ts +0 -30
  85. package/src/commands/artifact.ts +0 -82
  86. package/src/commands/build-trajectory-evidence.ts +0 -298
  87. package/src/commands/candidate.ts +0 -1250
  88. package/src/commands/codex-ingest-catchup.ts +0 -114
  89. package/src/commands/codex-ingest-quarantine.ts +0 -127
  90. package/src/commands/codex-reconcile.ts +0 -84
  91. package/src/commands/codex-setup.ts +0 -476
  92. package/src/commands/codex-worker.ts +0 -185
  93. package/src/commands/command-helpers.ts +0 -24
  94. package/src/commands/config-doctor.ts +0 -193
  95. package/src/commands/console.ts +0 -797
  96. package/src/commands/context.ts +0 -72
  97. package/src/commands/demo-story-a.ts +0 -241
  98. package/src/commands/diagnose.ts +0 -756
  99. package/src/commands/errors-list.ts +0 -441
  100. package/src/commands/evolution-tasks-list.ts +0 -48
  101. package/src/commands/evolution-tasks-show.ts +0 -62
  102. package/src/commands/flow.ts +0 -60
  103. package/src/commands/health-codex.ts +0 -576
  104. package/src/commands/health.ts +0 -315
  105. package/src/commands/history.ts +0 -63
  106. package/src/commands/intent.ts +0 -457
  107. package/src/commands/legacy-cleanup.ts +0 -531
  108. package/src/commands/legacy-import.ts +0 -104
  109. package/src/commands/mvp-smoke.ts +0 -160
  110. package/src/commands/pain-evidence.ts +0 -226
  111. package/src/commands/pain-list.ts +0 -239
  112. package/src/commands/pain-record.ts +0 -612
  113. package/src/commands/pain-retry.ts +0 -916
  114. package/src/commands/principles-stats.ts +0 -700
  115. package/src/commands/proven-channel-baseline.ts +0 -115
  116. package/src/commands/quality-scorecard.ts +0 -272
  117. package/src/commands/remediation-output.ts +0 -66
  118. package/src/commands/rulecode.ts +0 -465
  119. package/src/commands/run.ts +0 -89
  120. package/src/commands/runtime-activation.ts +0 -1629
  121. package/src/commands/runtime-artifact-repair.ts +0 -524
  122. package/src/commands/runtime-canary.ts +0 -395
  123. package/src/commands/runtime-compatibility-scan.ts +0 -105
  124. package/src/commands/runtime-diagnostics-export.ts +0 -229
  125. package/src/commands/runtime-features.ts +0 -153
  126. package/src/commands/runtime-gfi-snapshot.ts +0 -135
  127. package/src/commands/runtime-health-snapshot.ts +0 -108
  128. package/src/commands/runtime-init.ts +0 -429
  129. package/src/commands/runtime-internalization-enqueue-successors.ts +0 -530
  130. package/src/commands/runtime-internalization-integrity-repair.ts +0 -79
  131. package/src/commands/runtime-internalization-integrity.ts +0 -107
  132. package/src/commands/runtime-internalization-queue.ts +0 -135
  133. package/src/commands/runtime-internalization-retry.ts +0 -191
  134. package/src/commands/runtime-internalization-run-once.ts +0 -791
  135. package/src/commands/runtime-internalization-run-rulehost.ts +0 -749
  136. package/src/commands/runtime-internalization-wake-once.ts +0 -87
  137. package/src/commands/runtime-pain-flood-simulation.ts +0 -121
  138. package/src/commands/runtime-pruning.ts +0 -438
  139. package/src/commands/runtime-recovery-failed-tasks.ts +0 -258
  140. package/src/commands/runtime-recovery.ts +0 -109
  141. package/src/commands/runtime-synthetic-baseline.ts +0 -70
  142. package/src/commands/runtime-uat.guard.test.ts +0 -175
  143. package/src/commands/runtime-uat.ts +0 -380
  144. package/src/commands/runtime.ts +0 -473
  145. package/src/commands/samples-list.ts +0 -39
  146. package/src/commands/samples-review.ts +0 -36
  147. package/src/commands/task.ts +0 -271
  148. package/src/commands/telemetry.ts +0 -349
  149. package/src/commands/trace.ts +0 -174
  150. package/src/commands/trajectory-db-unavailable.ts +0 -19
  151. package/src/commands/trajectory.ts +0 -64
  152. package/src/commands/version.ts +0 -49
  153. package/src/config-reader.ts +0 -122
  154. package/src/index.ts +0 -1276
  155. package/src/legacy/legacy-import.ts +0 -179
  156. package/src/legacy/session-history-import.ts +0 -203
  157. package/src/resolve-workspace.ts +0 -106
  158. package/src/services/__tests__/cli-output.test.ts +0 -130
  159. package/src/services/__tests__/evaluator-runner-deps.test.ts +0 -382
  160. package/src/services/__tests__/rulehost-readiness.test.ts +0 -363
  161. package/src/services/__tests__/runtime-adapter-resolver.test.ts +0 -793
  162. package/src/services/cli-output.ts +0 -95
  163. package/src/services/config-doctor.ts +0 -697
  164. package/src/services/console-launcher.ts +0 -537
  165. package/src/services/demo-rule-compiler.ts +0 -40
  166. package/src/services/demo-story-a-runner.ts +0 -471
  167. package/src/services/mainline-snapshot-assembler.ts +0 -579
  168. package/src/services/pain-flood-simulation-runner.ts +0 -462
  169. package/src/services/pd-config-loader.ts +0 -433
  170. package/src/services/proven-channel-baseline-runner.ts +0 -157
  171. package/src/services/quality-scorecard/data-extractor.ts +0 -150
  172. package/src/services/quality-scorecard/local-evaluator.ts +0 -142
  173. package/src/services/quality-scorecard/strong-model-gate.ts +0 -202
  174. package/src/services/resolve-runtime-from-pd-config.ts +0 -230
  175. package/src/services/rulehost-pipeline-runner.ts +0 -1214
  176. package/src/services/rulehost-readiness.ts +0 -326
  177. package/src/services/runtime-adapter-resolver.ts +0 -364
  178. package/src/services/synthetic-baseline-runner.ts +0 -400
  179. package/src/services/version-report.ts +0 -253
  180. package/src/services/workspace-tool-semantics.ts +0 -26
  181. package/src/utils/path-security.ts +0 -96
  182. package/src/utils/production-workspace-guard.test.ts +0 -157
  183. package/src/utils/production-workspace-guard.ts +0 -210
  184. package/tests/bdd/cli-contract.steps.ts +0 -346
  185. package/tests/bdd/principles-stats.steps.ts +0 -211
  186. package/tests/bdd/support/gherkin-loader.ts +0 -147
  187. package/tests/bdd/support/repo-root.ts +0 -62
  188. package/tests/bdd/support/vitest-bdd.ts +0 -179
  189. package/tests/commands/admission-gate-coverage.test.ts +0 -79
  190. package/tests/commands/build-trajectory-evidence.test.ts +0 -508
  191. package/tests/commands/candidate-audit-repair.test.ts +0 -421
  192. package/tests/commands/candidate-intake.test.ts +0 -732
  193. package/tests/commands/candidate-internalization-backfill.test.ts +0 -548
  194. package/tests/commands/candidate-internalize-lineage.test.ts +0 -628
  195. package/tests/commands/candidate-internalize.test.ts +0 -299
  196. package/tests/commands/candidate-route.test.ts +0 -329
  197. package/tests/commands/candidate-show.test.ts +0 -95
  198. package/tests/commands/cli-command-tree.test.ts +0 -144
  199. package/tests/commands/cli-help-snapshot.test.ts +0 -155
  200. package/tests/commands/cli-skill-contract.test.ts +0 -121
  201. package/tests/commands/codex-consent-reversibility.steps.test.ts +0 -299
  202. package/tests/commands/codex-ingest-quarantine.test.ts +0 -136
  203. package/tests/commands/codex-setup.test.ts +0 -297
  204. package/tests/commands/codex-worker-daemon.test.ts +0 -95
  205. package/tests/commands/codex-worker-registration.test.ts +0 -207
  206. package/tests/commands/config-doctor.test.ts +0 -336
  207. package/tests/commands/console-launcher-edge-cases.test.ts +0 -388
  208. package/tests/commands/console-open.test.ts +0 -1381
  209. package/tests/commands/context.test.ts +0 -114
  210. package/tests/commands/demo-story-a.test.ts +0 -318
  211. package/tests/commands/diagnose.test.ts +0 -1803
  212. package/tests/commands/errors-list.test.ts +0 -679
  213. package/tests/commands/evolution-tasks-list.test.ts +0 -41
  214. package/tests/commands/evolution-tasks-show.test.ts +0 -46
  215. package/tests/commands/health-codex.test.ts +0 -349
  216. package/tests/commands/health-host-wiring.test.ts +0 -76
  217. package/tests/commands/health-reliability.test.ts +0 -99
  218. package/tests/commands/health.test.ts +0 -413
  219. package/tests/commands/intent.test.ts +0 -321
  220. package/tests/commands/legacy-cleanup.test.ts +0 -148
  221. package/tests/commands/pain-evidence.test.ts +0 -518
  222. package/tests/commands/pain-list.test.ts +0 -219
  223. package/tests/commands/pain-record-async.test.ts +0 -335
  224. package/tests/commands/pain-record-session-parser.test.ts +0 -228
  225. package/tests/commands/pain-record.test.ts +0 -851
  226. package/tests/commands/pain-retry.test.ts +0 -1121
  227. package/tests/commands/plugin-config-resolution-cutover.test.ts +0 -229
  228. package/tests/commands/pri-393-runtime-config-unification.test.ts +0 -443
  229. package/tests/commands/principles-stats-wiring.test.ts +0 -135
  230. package/tests/commands/principles-stats.test.ts +0 -274
  231. package/tests/commands/product-path-regression.test.ts +0 -86
  232. package/tests/commands/proven-channel-baseline.test.ts +0 -441
  233. package/tests/commands/rulecode.test.ts +0 -177
  234. package/tests/commands/run-rulehost-handler.test.ts +0 -908
  235. package/tests/commands/runtime-activation-approve-flag-wiring.test.ts +0 -227
  236. package/tests/commands/runtime-activation-deactivate-flag-wiring.test.ts +0 -167
  237. package/tests/commands/runtime-activation-dispatch-flag-wiring.test.ts +0 -262
  238. package/tests/commands/runtime-activation-governance-audit.test.ts +0 -95
  239. package/tests/commands/runtime-activation-list-flag-wiring.test.ts +0 -193
  240. package/tests/commands/runtime-activation-promote-flag-wiring.test.ts +0 -248
  241. package/tests/commands/runtime-activation-shadow-telemetry.test.ts +0 -130
  242. package/tests/commands/runtime-activation.test.ts +0 -2052
  243. package/tests/commands/runtime-artifact-repair-registration.test.ts +0 -74
  244. package/tests/commands/runtime-artifact-repair.test.ts +0 -404
  245. package/tests/commands/runtime-canary.test.ts +0 -430
  246. package/tests/commands/runtime-compatibility-scan.test.ts +0 -146
  247. package/tests/commands/runtime-diagnostics-export.test.ts +0 -175
  248. package/tests/commands/runtime-features.test.ts +0 -249
  249. package/tests/commands/runtime-health-snapshot.test.ts +0 -358
  250. package/tests/commands/runtime-init-empty-workspace.test.ts +0 -252
  251. package/tests/commands/runtime-init.test.ts +0 -420
  252. package/tests/commands/runtime-internalization-enqueue-successors.test.ts +0 -782
  253. package/tests/commands/runtime-internalization-integrity-repair.test.ts +0 -239
  254. package/tests/commands/runtime-internalization-integrity.test.ts +0 -140
  255. package/tests/commands/runtime-internalization-queue.test.ts +0 -380
  256. package/tests/commands/runtime-internalization-retry-owner-authority.test.ts +0 -431
  257. package/tests/commands/runtime-internalization-run-once-evaluator-parity.test.ts +0 -269
  258. package/tests/commands/runtime-internalization-run-once-language.test.ts +0 -303
  259. package/tests/commands/runtime-internalization-run-once-real-config.test.ts +0 -237
  260. package/tests/commands/runtime-internalization-run-once-rollout-parity.test.ts +0 -706
  261. package/tests/commands/runtime-internalization-run-once.test.ts +0 -1791
  262. package/tests/commands/runtime-internalization-wake-once.test.ts +0 -171
  263. package/tests/commands/runtime-internalization.test.ts +0 -53
  264. package/tests/commands/runtime-pain-flood-simulation.test.ts +0 -418
  265. package/tests/commands/runtime-pruning.test.ts +0 -694
  266. package/tests/commands/runtime-recovery-failed-tasks.test.ts +0 -328
  267. package/tests/commands/runtime-recovery.test.ts +0 -120
  268. package/tests/commands/runtime-synthetic-baseline.test.ts +0 -249
  269. package/tests/commands/runtime-uat.test.ts +0 -397
  270. package/tests/commands/runtime.test.ts +0 -392
  271. package/tests/commands/samples-list.test.ts +0 -43
  272. package/tests/commands/samples-review.test.ts +0 -41
  273. package/tests/commands/task.test.ts +0 -153
  274. package/tests/commands/telemetry.test.ts +0 -190
  275. package/tests/commands/trace.test.ts +0 -316
  276. package/tests/config-reader.test.ts +0 -143
  277. package/tests/e2e/candidate-intake-e2e.test.ts +0 -338
  278. package/tests/e2e/cli-full-flow.test.ts +0 -233
  279. package/tests/e2e/cross-package-acceptance.test.ts +0 -635
  280. package/tests/helpers/pd-cli-path.ts +0 -5
  281. package/tests/pd-cli-smoke.test.ts +0 -13
  282. package/tests/resolve-workspace.test.ts +0 -196
  283. package/tests/services/config-doctor-signal-health.test.ts +0 -109
  284. package/tests/services/console-launcher.test.ts +0 -114
  285. package/tests/services/demo-rule-compiler.test.ts +0 -242
  286. package/tests/services/mainline-snapshot-assembler.test.ts +0 -572
  287. package/tests/services/pd-config-loader.test.ts +0 -505
  288. package/tests/services/proven-channel-baseline-runner.test.ts +0 -30
  289. package/tests/services/quality-scorecard/strong-model-gate.test.ts +0 -133
  290. package/tests/services/resolve-runtime-from-pd-config.test.ts +0 -485
  291. package/tests/services/rulehost-pipeline-e2e.test.ts +0 -538
  292. package/tests/services/rulehost-pipeline-runner.test.ts +0 -1242
  293. package/tests/services/workspace-tool-semantics.test.ts +0 -76
  294. package/tests/utils/path-security.test.ts +0 -180
  295. package/tsconfig.json +0 -26
  296. package/vitest.config.ts +0 -10
@@ -1,433 +0,0 @@
1
- /**
2
- * PD Config Loader — PRI-305
3
- *
4
- * I/O boundary: reads `.pd/config.yaml`, validates via core, computes effective config.
5
- * This replaces the old `feature-flag-loader.ts` and `workflows.yaml` reading
6
- * for CLI production paths.
7
- *
8
- * ADR-0016: PD owns exactly one user config file.
9
- * - Missing config → defaults with nextAction
10
- * - Malformed config → fail loud with errors and nextAction
11
- * - No secrets in output
12
- */
13
-
14
- import * as fs from 'fs';
15
- import * as path from 'path';
16
- import * as os from 'os';
17
- import * as yaml from 'js-yaml';
18
- import { canonicalPath, isPathInside } from '../utils/path-security.js';
19
- import {
20
- validatePdConfig,
21
- computeEffectivePdConfig,
22
- computeFeatureFlagsFromConfig,
23
- isFeatureEnabled,
24
- redactPdConfig,
25
- } from '@principles/core/runtime-v2';
26
- import type {
27
- EffectivePdConfig,
28
- PdConfigValidationResult,
29
- RedactedPdConfigSummary,
30
- FeatureFlagsResult,
31
- } from '@principles/core/runtime-v2';
32
-
33
- // ── Constants ────────────────────────────────────────────────────────────────
34
-
35
- export const PD_CONFIG_DIR = '.pd';
36
- export const PD_CONFIG_FILENAME = 'config.yaml';
37
-
38
- // ── Types ────────────────────────────────────────────────────────────────────
39
-
40
- export type ConfigSource = 'defaults' | 'user_config' | 'malformed';
41
-
42
- export interface PdConfigLoadResultOk {
43
- ok: true;
44
- effective: EffectivePdConfig;
45
- source: ConfigSource;
46
- configPath: string;
47
- /** Warnings from config resolution (not errors) */
48
- warnings: string[];
49
- /** If legacy files were detected */
50
- legacyFilesDetected: string[];
51
- /** PRI-404: Next actions for removing legacy files (empty if none detected) */
52
- legacyFileNextActions: string[];
53
- }
54
-
55
- export interface PdConfigLoadResultErr {
56
- ok: false;
57
- source: 'malformed';
58
- configPath: string;
59
- errors: { path: string; reason: string; nextAction: string }[];
60
- /** Fallback defaults are still available */
61
- defaults: EffectivePdConfig;
62
- /** Warnings from config resolution */
63
- warnings: string[];
64
- legacyFilesDetected: string[];
65
- /** PRI-404: Next actions for removing legacy files (empty if none detected) */
66
- legacyFileNextActions: string[];
67
- }
68
-
69
- export type PdConfigLoadResult = PdConfigLoadResultOk | PdConfigLoadResultErr;
70
-
71
- // ── Config Path ──────────────────────────────────────────────────────────────
72
-
73
- export function getPdConfigPath(workspaceDir: string): string {
74
- return path.join(workspaceDir, PD_CONFIG_DIR, PD_CONFIG_FILENAME);
75
- }
76
-
77
- // ── Legacy File Detection ────────────────────────────────────────────────────
78
-
79
- function detectLegacyFiles(workspaceDir: string): string[] {
80
- const detected: string[] = [];
81
- const legacyPaths = [
82
- path.join(workspaceDir, PD_CONFIG_DIR, 'feature-flags.yaml'),
83
- path.join(workspaceDir, '.state', 'workflows.yaml'),
84
- ];
85
- for (const p of legacyPaths) {
86
- if (fs.existsSync(p)) {
87
- detected.push(p);
88
- }
89
- }
90
- return detected;
91
- }
92
-
93
- /** PRI-404: Generate nextAction suggestions for removing legacy files. */
94
- function buildLegacyFileNextActions(legacyFiles: string[]): string[] {
95
- return legacyFiles.map(f => {
96
- return `Run 'rm ${f}' to remove legacy config`;
97
- });
98
- }
99
-
100
- // ── Load PD Config ───────────────────────────────────────────────────────────
101
-
102
- /**
103
- * Load and validate `.pd/config.yaml` from the workspace.
104
- *
105
- * - Missing file → returns defaults with source='defaults'
106
- * - Malformed file → returns error result with defaults fallback
107
- * - Valid file → returns effective config with source='user_config'
108
- *
109
- * Never throws on malformed input. Always provides a usable fallback.
110
- */
111
- export function loadPdConfig(workspaceDir: string): PdConfigLoadResult {
112
- const configPath = getPdConfigPath(workspaceDir);
113
- const legacyFilesDetected = detectLegacyFiles(workspaceDir);
114
- const legacyFileNextActions = buildLegacyFileNextActions(legacyFilesDetected);
115
-
116
- // 1) Config file missing → use defaults
117
- if (!fs.existsSync(configPath)) {
118
- const effective = computeEffectivePdConfig(null);
119
- return {
120
- ok: true,
121
- effective,
122
- source: 'defaults',
123
- configPath,
124
- warnings: [
125
- ...effective.warnings,
126
- ...(legacyFilesDetected.length > 0
127
- ? [`Legacy config files detected (${legacyFilesDetected.length}): ${legacyFilesDetected.join(', ')}. PD now uses .pd/config.yaml.`]
128
- : []),
129
- ],
130
- legacyFilesDetected,
131
- legacyFileNextActions,
132
- };
133
- }
134
-
135
- // 2) Read the file
136
- let raw: string;
137
- try {
138
- raw = fs.readFileSync(configPath, 'utf8');
139
- } catch (err) {
140
- const message = err instanceof Error ? err.message : String(err);
141
- const effective = computeEffectivePdConfig(null);
142
- return {
143
- ok: false,
144
- source: 'malformed',
145
- configPath,
146
- errors: [{ path: '', reason: `Failed to read .pd/config.yaml: ${message}`, nextAction: 'Check file permissions for .pd/config.yaml' }],
147
- warnings: [],
148
- defaults: effective,
149
- legacyFilesDetected,
150
- legacyFileNextActions,
151
- };
152
- }
153
-
154
- // 3) Parse YAML — treat as unknown (ERR-001)
155
- let parsed: unknown;
156
- try {
157
- parsed = yaml.load(raw, { schema: yaml.JSON_SCHEMA });
158
- } catch (err) {
159
- const message = err instanceof Error ? err.message : String(err);
160
- const effective = computeEffectivePdConfig(null);
161
- return {
162
- ok: false,
163
- source: 'malformed',
164
- configPath,
165
- errors: [{ path: '', reason: `YAML parse error in .pd/config.yaml: ${message}`, nextAction: 'Fix YAML syntax in .pd/config.yaml' }],
166
- warnings: [],
167
- defaults: effective,
168
- legacyFilesDetected,
169
- legacyFileNextActions,
170
- };
171
- }
172
-
173
- // 4) Validate via core (ERR-001, ERR-005: no `as` bypasses)
174
- const validationResult: PdConfigValidationResult = validatePdConfig(parsed);
175
-
176
- if (!validationResult.ok) {
177
- const effective = computeEffectivePdConfig(null);
178
- return {
179
- ok: false,
180
- source: 'malformed',
181
- configPath,
182
- errors: validationResult.errors.map(e => ({
183
- path: e.path,
184
- reason: e.reason,
185
- nextAction: e.nextAction,
186
- })),
187
- warnings: [],
188
- defaults: effective,
189
- legacyFilesDetected,
190
- legacyFileNextActions,
191
- };
192
- }
193
-
194
- // 5) Compute effective config
195
- const effective = computeEffectivePdConfig(validationResult.value);
196
-
197
- return {
198
- ok: true,
199
- effective,
200
- source: 'user_config',
201
- configPath,
202
- warnings: [
203
- ...effective.warnings,
204
- ...validationResult.warnings,
205
- ...(legacyFilesDetected.length > 0
206
- ? [`Legacy config files detected (${legacyFilesDetected.length}): ${legacyFilesDetected.join(', ')}. PD now uses .pd/config.yaml.`]
207
- : []),
208
- ],
209
- legacyFilesDetected,
210
- legacyFileNextActions,
211
- };
212
- }
213
-
214
- // ── Feature Flags from Config ────────────────────────────────────────────────
215
-
216
- /**
217
- * Flags whose production gate FAILS CLOSED when the workspace config cannot
218
- * be loaded: the gate cannot know the flag state, so the gated capability is
219
- * suspended (OpenClaw `buildRuleContextIfEnabled` returns undefined context on
220
- * config failure → v2 rules skip). Status derivation must mirror that posture
221
- * or the CLI would display "active" for rules that are actually not
222
- * enforcing (PRI-780 review B3).
223
- */
224
- const CONFIG_FAILURE_FAIL_CLOSED_FLAGS: ReadonlySet<string> = new Set(['rulecode_context_v2']);
225
-
226
- /**
227
- * Compute feature flags from the loaded PD config.
228
- * Works with both ok and error results (uses defaults for errors).
229
- *
230
- * On a failed load, flags whose gate fail-closes on config errors are forced
231
- * disabled with an observable warning — the registry default (ON for a
232
- * graduated flag) must never be displayed as enforcing when the workspace
233
- * config is unreadable.
234
- */
235
- export function computeFlagsFromLoadResult(result: PdConfigLoadResult): FeatureFlagsResult {
236
- const effective = result.ok ? result.effective : result.defaults;
237
- const flags = computeFeatureFlagsFromConfig(effective);
238
- if (!result.ok) {
239
- for (const flagId of CONFIG_FAILURE_FAIL_CLOSED_FLAGS) {
240
- const flag = flags.flags[flagId];
241
- if (flag?.enabled) {
242
- flags.flags[flagId] = { ...flag, enabled: false };
243
- flags.warnings.push(`${flagId}: config load failed — flag treated as disabled (fail-closed, matches the gate's config-failure suspension)`);
244
- }
245
- }
246
- }
247
- return flags;
248
- }
249
-
250
- /**
251
- * PRI-720: resolve the seed-time full-chain override for prompt/defer_archive
252
- * internalization chains from the `prompt_full_pipeline` feature flag
253
- * (Owner switch: Console settings toggle or `.pd/config.yaml` features).
254
- * Returns undefined (= standard channel-aware topology) when the flag is off
255
- * or the config is unreadable — absence is the legacy-compatible default.
256
- * Resolve ONCE per command invocation and pass the value to every seed call.
257
- */
258
- export function resolvePromptFullPipelineSeedMode(workspaceDir: string): 'full_chain' | undefined {
259
- const flags = computeFlagsFromLoadResult(loadPdConfig(workspaceDir));
260
- return isFeatureEnabled(flags, 'prompt_full_pipeline') ? 'full_chain' : undefined;
261
- }
262
-
263
- // ── Redacted Summary from Config ─────────────────────────────────────────────
264
-
265
- /**
266
- * Produce a redacted summary of the PD config for CLI/Console display.
267
- * Never includes token/API key values or raw provider objects.
268
- */
269
- export function redactLoadResult(result: PdConfigLoadResult): RedactedPdConfigSummary {
270
- const effective = result.ok ? result.effective : result.defaults;
271
- return redactPdConfig(effective);
272
- }
273
-
274
- // ── Workspace Discovery ──────────────────────────────────────────────────────
275
-
276
- /** Result of workspace.default discovery from config files. */
277
- export interface WorkspaceDiscoveryResult {
278
- /** The extracted workspace.default path. */
279
- workspaceDefault: string;
280
- /** Path to the config file that provided workspace.default. */
281
- configPath: string;
282
- /** How the config location was found. */
283
- source: 'env_var' | 'openclaw_default' | 'openclaw_plugin_config';
284
- }
285
-
286
- function isRecord(value: unknown): value is Record<string, unknown> {
287
- return value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value);
288
- }
289
-
290
- /** Check if a path is absolute (Windows or POSIX). */
291
- function isAbsolutePath(p: string): boolean {
292
- return /^[A-Za-z]:[\\/]/.test(p) || p.startsWith('\\\\') || p.startsWith('/');
293
- }
294
-
295
- /**
296
- * Lightweight extraction of workspace.default from a config file.
297
- * Does NOT run full validation — just parses YAML and reads the field.
298
- * Rejects relative paths to prevent PD from writing to unpredictable locations.
299
- */
300
- function extractWorkspaceDefault(configPath: string): string | null {
301
- try {
302
- const raw = fs.readFileSync(configPath, 'utf8');
303
- const parsed: unknown = yaml.load(raw, { schema: yaml.JSON_SCHEMA });
304
- if (
305
- isRecord(parsed) &&
306
- isRecord(parsed.workspace) &&
307
- typeof parsed.workspace.default === 'string' &&
308
- parsed.workspace.default.length > 0 &&
309
- isAbsolutePath(parsed.workspace.default)
310
- ) {
311
- return parsed.workspace.default;
312
- }
313
- } catch (err) {
314
- // Graceful degradation with observability: log but don't throw
315
- process.stderr.write(
316
- `[PD:workspace] WARN: Failed to parse workspace config at ${configPath}: ${err instanceof Error ? err.message : String(err)}\n`,
317
- );
318
- }
319
- return null;
320
- }
321
-
322
- /**
323
- * Read the OpenClaw plugin config file for workspace field.
324
- * Reuses the same search locations as PathResolver.
325
- * Returns null if no valid config is found (graceful degradation).
326
- */
327
- function loadOpenClawPluginConfig(): { workspace?: string } | null {
328
- const configLocations = [
329
- path.join(process.cwd(), 'principles-disciple.json'),
330
- path.join(os.homedir(), '.openclaw', 'principles-disciple.json'),
331
- path.join(os.homedir(), '.principles', 'principles-disciple.json'),
332
- ];
333
- for (const loc of configLocations) {
334
- if (fs.existsSync(loc)) {
335
- try {
336
- const content = fs.readFileSync(loc, 'utf8');
337
- const parsed: unknown = JSON.parse(content);
338
- // Runtime type guard: validate workspace is a non-empty string
339
- if (
340
- parsed !== null &&
341
- typeof parsed === 'object' &&
342
- !Array.isArray(parsed) &&
343
- Object.hasOwn(parsed, 'workspace') &&
344
- typeof (parsed as Record<string, unknown>).workspace === 'string' &&
345
- ((parsed as Record<string, unknown>).workspace as string).length > 0
346
- ) {
347
- return { workspace: (parsed as Record<string, unknown>).workspace as string };
348
- }
349
- } catch (err) {
350
- // Graceful degradation with observability: log but continue to next location
351
- process.stderr.write(
352
- `[PD:workspace] WARN: Failed to parse plugin config at ${loc}: ${err instanceof Error ? err.message : String(err)}\n`,
353
- );
354
- }
355
- }
356
- }
357
- return null;
358
- }
359
-
360
- /**
361
- * Validate a candidate config directory before it is joined into a config
362
- * path for filesystem reads. Candidate dirs are operator-supplied
363
- * (PD_WORKSPACE_DIR / plugin config / home default), so we normalize with
364
- * `path.normalize` (pure string, no filesystem access), then reject empty,
365
- * parent-traversal, or root paths. This keeps the subsequent
366
- * `path.join(dir, PD_CONFIG_DIR, ...)` inside the intended directory
367
- * boundary (CWE-22 mitigation).
368
- *
369
- * Platform note: no `path.isAbsolute` check — absolute-ness is
370
- * platform-dependent (a Windows-style path is not absolute on POSIX
371
- * runners) and relative dirs resolve inside cwd without traversal risk.
372
- */
373
- function assertConfigDirBoundary(dir: string, source: string): void {
374
- if (!dir || dir.trim().length === 0) {
375
- throw new Error(`Invalid config search dir (${source}): path is empty`);
376
- }
377
- const normalized = path.normalize(dir);
378
- if (normalized.split(/[\\/]/).includes('..')) {
379
- throw new Error(`Invalid config search dir (${source}): "${dir}" contains parent traversal`);
380
- }
381
- if (normalized === path.parse(normalized).root) {
382
- throw new Error(`Invalid config search dir (${source}): "${dir}" resolves to filesystem root`);
383
- }
384
- }
385
-
386
- /**
387
- * Search known locations for a .pd/config.yaml that contains a workspace.default field.
388
- * This runs BEFORE workspace resolution and does NOT require knowing the workspace dir.
389
- *
390
- * Returns the extracted workspace.default path, or null if not found.
391
- */
392
- export function discoverWorkspaceDefault(): WorkspaceDiscoveryResult | null {
393
- const candidates: { dir: string; source: 'env_var' | 'openclaw_default' | 'openclaw_plugin_config' }[] = [];
394
-
395
- // 1. If PD_WORKSPACE_DIR is set, check there first
396
- const envWorkspace = process.env.PD_WORKSPACE_DIR?.trim();
397
- if (envWorkspace) {
398
- candidates.push({ dir: envWorkspace, source: 'env_var' });
399
- }
400
-
401
- // 2. OpenClaw default workspace
402
- const homeDir = os.homedir();
403
- candidates.push({
404
- dir: path.join(homeDir, '.openclaw', 'workspace'),
405
- source: 'openclaw_default',
406
- });
407
-
408
- // 3. OpenClaw plugin config (principles-disciple.json) may have workspace field
409
- const pluginConfig = loadOpenClawPluginConfig();
410
- if (pluginConfig?.workspace) {
411
- candidates.push({ dir: pluginConfig.workspace, source: 'openclaw_plugin_config' });
412
- }
413
-
414
- // Search each candidate for .pd/config.yaml with workspace.default
415
- for (const { dir, source } of candidates) {
416
- assertConfigDirBoundary(dir, source);
417
- // CWE-22: resolve the candidate root once, then verify the joined config
418
- // path stays inside that root before any filesystem access.
419
- const candidateRoot = canonicalPath(dir);
420
- const configPath = path.resolve(candidateRoot, PD_CONFIG_DIR, PD_CONFIG_FILENAME);
421
- if (!isPathInside(candidateRoot, configPath)) {
422
- throw new Error(`Invalid config search dir (${source}): "${dir}" escapes its boundary`);
423
- }
424
- if (fs.existsSync(configPath)) {
425
- const workspaceDefault = extractWorkspaceDefault(configPath);
426
- if (workspaceDefault) {
427
- return { workspaceDefault, configPath, source };
428
- }
429
- }
430
- }
431
-
432
- return null;
433
- }
@@ -1,157 +0,0 @@
1
- import * as path from 'path';
2
- import * as os from 'os';
3
- import {
4
- runPromptFixture,
5
- runRuleHostFixture,
6
- runDeferArchiveFixture,
7
- computeProvenChannelStatus,
8
- generateContinuityMatrix,
9
- recommendProvenChannelNextIssue,
10
- isMvpChannel,
11
- MVP_CHANNELS,
12
- } from '@principles/core/runtime-v2';
13
- import type {
14
- ChannelFixtureResult,
15
- ProvenChannelBaselineSummary,
16
- MvpChannel,
17
- } from '@principles/core/runtime-v2';
18
-
19
- export interface ProvenChannelBaselineRunnerOptions {
20
- workspaceDir: string;
21
- workspaceMode: 'temp' | 'explicit_workspace';
22
- channels?: MvpChannel[];
23
- unknownChannels?: string[];
24
- emptyChannelInput?: boolean;
25
- }
26
-
27
- function isProductionWorkspace(workspaceDir: string): boolean {
28
- const normalized = path.resolve(workspaceDir).toLowerCase();
29
- const productionPrefixes: string[] = [
30
- path.resolve(path.join(os.homedir(), '.openclaw', 'workspace')).toLowerCase(),
31
- ];
32
- // Allow operator to declare additional production paths (cross-platform).
33
- // Use path.delimiter (; on Windows, : on Unix) to separate multiple paths.
34
- const extra = process.env.PD_PRODUCTION_WORKSPACE;
35
- if (extra) {
36
- for (const p of extra.split(path.delimiter)) {
37
- const trimmed = p.trim();
38
- if (trimmed) productionPrefixes.push(path.resolve(trimmed).toLowerCase());
39
- }
40
- }
41
- for (const prefix of productionPrefixes) {
42
- if (normalized === prefix || normalized.startsWith(prefix + path.sep)) {
43
- return true;
44
- }
45
- }
46
- return false;
47
- }
48
-
49
- export async function runProvenChannelBaseline(
50
- opts: ProvenChannelBaselineRunnerOptions,
51
- ): Promise<ProvenChannelBaselineSummary> {
52
- const { workspaceDir, workspaceMode } = opts;
53
- const channels = opts.channels ?? [...MVP_CHANNELS];
54
- const unknownChannels = opts.unknownChannels ?? [];
55
- const emptyChannelInput = opts.emptyChannelInput ?? false;
56
- const generatedAt = new Date().toISOString();
57
-
58
- if (emptyChannelInput) {
59
- return {
60
- status: 'failed',
61
- generatedAt,
62
- workspaceMode,
63
- channels: [],
64
- inputValidationFailure: {
65
- reason: 'empty_channel_input',
66
- message: '--channels was provided but contained no valid channel names',
67
- nextAction: 'Provide at least one valid MVP channel: prompt, code_tool_hook, defer_archive',
68
- },
69
- continuityMatrix: generateContinuityMatrix(),
70
- recommendedNextIssue: 'PRI-240: --channels input was empty — no fixtures were executed',
71
- };
72
- }
73
-
74
- if (unknownChannels.length > 0) {
75
- return {
76
- status: 'failed',
77
- generatedAt,
78
- workspaceMode,
79
- channels: [],
80
- inputValidationFailure: {
81
- reason: 'unknown_channels',
82
- message: `Unknown channels: ${unknownChannels.join(', ')}. Valid channels: prompt, code_tool_hook, defer_archive`,
83
- nextAction: 'Use only valid MVP channels: prompt, code_tool_hook, defer_archive',
84
- unknownChannels,
85
- },
86
- continuityMatrix: generateContinuityMatrix(),
87
- recommendedNextIssue: `PRI-240: Unknown channels provided: ${unknownChannels.join(', ')}`,
88
- };
89
- }
90
-
91
- if (isProductionWorkspace(workspaceDir)) {
92
- return {
93
- status: 'failed',
94
- generatedAt,
95
- workspaceMode,
96
- channels: [],
97
- inputValidationFailure: {
98
- reason: 'production_workspace_blocked',
99
- message: 'Baseline must not write to production workspace',
100
- nextAction: 'Use a temp workspace or explicit non-production directory',
101
- },
102
- continuityMatrix: generateContinuityMatrix(),
103
- recommendedNextIssue: 'PRI-240: Production workspace blocked — use temp workspace',
104
- };
105
- }
106
-
107
- const results: ChannelFixtureResult[] = [];
108
-
109
- for (const channel of channels) {
110
- if (!isMvpChannel(channel)) {
111
- continue;
112
- }
113
-
114
- let result: ChannelFixtureResult = {
115
- channel,
116
- status: 'failed',
117
- canActivateResult: { ok: false, reason: 'unsupported_channel', riskLevel: 'low' },
118
- activationDecision: { decision: 'refused', reason: 'unsupported_channel', channel },
119
- evidence: {},
120
- failureReason: `Channel ${channel} is not an MVP channel`,
121
- nextAction: 'Use one of: prompt, code_tool_hook, defer_archive',
122
- dependsOnLegacy: false,
123
- evidenceSource: 'channel_validation',
124
- };
125
-
126
- switch (channel) {
127
- case 'prompt':
128
- result = await runPromptFixture();
129
- break;
130
- case 'code_tool_hook':
131
- result = await runRuleHostFixture();
132
- break;
133
- case 'defer_archive':
134
- result = await runDeferArchiveFixture();
135
- break;
136
- default: {
137
- const _exhaustive: never = channel;
138
- }
139
- }
140
-
141
- results.push(result);
142
- }
143
-
144
- const status = computeProvenChannelStatus(results);
145
- const continuityMatrix = generateContinuityMatrix();
146
-
147
- return {
148
- status,
149
- generatedAt,
150
- workspaceMode,
151
- channels: results,
152
- continuityMatrix,
153
- recommendedNextIssue: recommendProvenChannelNextIssue(results),
154
- };
155
- }
156
-
157
- export { isProductionWorkspace };