@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,147 +0,0 @@
1
- import { AstBuilder, GherkinClassicTokenMatcher, Parser } from '@cucumber/gherkin';
2
- import * as messages from '@cucumber/messages';
3
-
4
- export interface ParsedStep {
5
- keyword: 'Given' | 'When' | 'Then' | 'And' | 'But';
6
- text: string;
7
- }
8
-
9
- export interface ParsedScenario {
10
- featureName: string;
11
- featureTags: string[];
12
- scenarioName: string;
13
- scenarioTags: string[];
14
- background?: ParsedStep[];
15
- steps: ParsedStep[];
16
- }
17
-
18
- // 步骤关键词归一化表。英文关键词由 @cucumber/gherkin 以带尾空格的形式返回
19
- // (如 "Given "),中文关键词无尾空格 (如 "假如")。trim 后用此表映射到规范形式。
20
- // 中文条目用于带 # language: zh-CN 指令的文件 (parser 原生返回中文关键词)。
21
- const KEYWORD_MAP: Record<string, ParsedStep['keyword']> = {
22
- Given: 'Given',
23
- When: 'When',
24
- Then: 'Then',
25
- And: 'And',
26
- But: 'But',
27
- // 中文关键词 (@cucumber/gherkin zh-CN 方言)
28
- 假如: 'Given',
29
- 假设: 'Given',
30
- 假定: 'Given',
31
- 当: 'When',
32
- 那么: 'Then',
33
- 而且: 'And',
34
- 并且: 'And',
35
- 同时: 'And',
36
- 但是: 'But',
37
- };
38
-
39
- function normalizeKeyword(keyword: string): ParsedStep['keyword'] {
40
- const trimmed = keyword.trim();
41
- const mapped = KEYWORD_MAP[trimmed];
42
- if (!mapped) {
43
- // rc-9: 不静默回退到 'Given',未知关键词 fail loud。
44
- // @cucumber/gherkin parser 理论上只产生已知关键词,这里防御 parser 升级或异常输入。
45
- throw new Error(`normalizeKeyword: unknown step keyword "${trimmed}"`);
46
- }
47
- return mapped;
48
- }
49
-
50
- // 行首中文步骤关键词 → 英文。用于无 # language 指令的混合写法
51
- // (英文 Feature/Scenario + 中文步骤),这是 PD .feature 文件的常见写法。
52
- // 要求关键词后跟空白,避免误伤描述文本里的中文字符。
53
- const CHINESE_STEP_KEYWORD_PATTERNS: ReadonlyArray<readonly [RegExp, string]> = [
54
- [/^(\s*)(假如|假设|假定)(\s+)/gm, '$1Given$3'],
55
- [/^(\s*)(当)(\s+)/gm, '$1When$3'],
56
- [/^(\s*)(那么)(\s+)/gm, '$1Then$3'],
57
- [/^(\s*)(而且|并且|同时)(\s+)/gm, '$1And$3'],
58
- [/^(\s*)(但是)(\s+)/gm, '$1But$3'],
59
- ];
60
-
61
- function hasLanguageDirective(featureText: string): boolean {
62
- return /^\s*#\s*language\s*:/m.test(featureText);
63
- }
64
-
65
- function normalizeChineseStepKeywords(featureText: string): string {
66
- let result = featureText;
67
- for (const [pattern, replacement] of CHINESE_STEP_KEYWORD_PATTERNS) {
68
- result = result.replace(pattern, replacement);
69
- }
70
- return result;
71
- }
72
-
73
- /**
74
- * 解析 .feature 文本为 ParsedScenario[]。
75
- *
76
- * 纯逻辑,无 I/O。失败时 fail loud (rc-3),抛错带原因。
77
- *
78
- * 中文支持策略:
79
- * - 有 `# language:` 指令 → 交给 @cucumber/gherkin 原生处理方言,KEYWORD_MAP 兜底归一化。
80
- * - 无指令但含中文步骤关键词 → 行首归一化为英文后用默认英文方言解析
81
- * (支持英文 Feature/Scenario + 中文步骤的混合写法)。
82
- */
83
- export function parseFeature(featureText: string): ParsedScenario[] {
84
- if (!featureText || featureText.trim().length === 0) {
85
- throw new Error('parseFeature: empty feature text');
86
- }
87
-
88
- const source = hasLanguageDirective(featureText)
89
- ? featureText
90
- : normalizeChineseStepKeywords(featureText);
91
-
92
- let gherkinDocument: messages.GherkinDocument;
93
- try {
94
- const newId = messages.IdGenerator.uuid();
95
- const parser = new Parser(new AstBuilder(newId), new GherkinClassicTokenMatcher());
96
- gherkinDocument = parser.parse(source);
97
- } catch (e) {
98
- throw new Error(
99
- `parseFeature: malformed feature file: ${e instanceof Error ? e.message : String(e)}`
100
- );
101
- }
102
-
103
- if (!gherkinDocument.feature) {
104
- throw new Error('parseFeature: feature file has no Feature section');
105
- }
106
-
107
- const feature = gherkinDocument.feature;
108
- const featureTags = (feature.tags || []).map((t) => t.name);
109
-
110
- // 提取 Background (一个 Feature 至多一个 Background,适用于全部 scenario)
111
- let background: ParsedStep[] | undefined;
112
- for (const child of feature.children || []) {
113
- if (child.background) {
114
- background = (child.background.steps || []).map((step) => ({
115
- keyword: normalizeKeyword(step.keyword),
116
- text: step.text,
117
- }));
118
- break;
119
- }
120
- }
121
-
122
- // 提取 Scenario 列表
123
- const scenarios: ParsedScenario[] = [];
124
- for (const child of feature.children || []) {
125
- if (!child.scenario) continue;
126
- const scenario = child.scenario;
127
- const scenarioTags = (scenario.tags || []).map((t) => t.name);
128
- const steps: ParsedStep[] = (scenario.steps || []).map((step) => ({
129
- keyword: normalizeKeyword(step.keyword),
130
- text: step.text,
131
- }));
132
- scenarios.push({
133
- featureName: feature.name || '(unnamed feature)',
134
- featureTags,
135
- scenarioName: scenario.name || '(unnamed scenario)',
136
- scenarioTags,
137
- background,
138
- steps,
139
- });
140
- }
141
-
142
- if (scenarios.length === 0) {
143
- throw new Error('parseFeature: feature file has no Scenario');
144
- }
145
-
146
- return scenarios;
147
- }
@@ -1,62 +0,0 @@
1
- import { fileURLToPath } from 'node:url';
2
- import { dirname, join, resolve, isAbsolute } from 'node:path';
3
- import { readFileSync, existsSync } from 'node:fs';
4
-
5
- /**
6
- * 解析仓库根路径。优先用 PD_REPO_ROOT 环境变量,否则从 import.meta.url 向上查找
7
- * 含 "principles-disciple-monorepo" 的 package.json。
8
- *
9
- * 不依赖 process.cwd(),避免在 package 目录下运行测试时路径错误。
10
- */
11
- export function resolveRepoRoot(): string {
12
- // 优先使用环境变量 (CI 显式注入)
13
- const envRoot = process.env.PD_REPO_ROOT;
14
- if (envRoot && existsSync(join(envRoot, 'package.json'))) {
15
- try {
16
- const pkg = JSON.parse(readFileSync(join(envRoot, 'package.json'), 'utf8'));
17
- if (pkg.name === 'principles-disciple-monorepo') {
18
- return envRoot;
19
- }
20
- } catch {
21
- // fallthrough to import.meta.url strategy
22
- }
23
- }
24
-
25
- // 从 import.meta.url 向上查找
26
- const thisFileDir = dirname(fileURLToPath(import.meta.url));
27
- let current: string = thisFileDir;
28
- for (let i = 0; i < 20; i++) {
29
- const pkgPath = join(current, 'package.json');
30
- if (existsSync(pkgPath)) {
31
- try {
32
- const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
33
- if (pkg.name === 'principles-disciple-monorepo') {
34
- return current;
35
- }
36
- } catch {
37
- // continue upward
38
- }
39
- }
40
- const parent = dirname(current);
41
- if (parent === current) {
42
- break;
43
- }
44
- current = parent;
45
- }
46
-
47
- throw new Error(
48
- `resolveRepoRoot: cannot find principles-disciple-monorepo from ${thisFileDir}. ` +
49
- `Set PD_REPO_ROOT env var or run from within the repo. Searched: ${thisFileDir} and 20 ancestors.`
50
- );
51
- }
52
-
53
- /**
54
- * 把相对仓库根的路径解析为绝对路径。
55
- * 如果传入的已经是绝对路径,直接返回(若存在)。
56
- */
57
- export function resolveFeaturePath(relativePath: string): string {
58
- if (isAbsolute(relativePath)) {
59
- return relativePath;
60
- }
61
- return resolve(resolveRepoRoot(), relativePath);
62
- }
@@ -1,179 +0,0 @@
1
- import { describe, it } from 'vitest';
2
- import { parseFeature, type ParsedStep } from './gherkin-loader.js';
3
-
4
- export interface StepContext {
5
- state: Record<string, unknown>;
6
- redactable: Record<string, unknown>;
7
- attachments: Array<{ name: string; body: string }>;
8
- }
9
-
10
- export type StepFn = (ctx: StepContext, ...args: unknown[]) => void | Promise<void>;
11
-
12
- export interface StepMatch {
13
- fn: StepFn;
14
- args: unknown[];
15
- }
16
-
17
- export interface StepRegistry {
18
- given(pattern: string | RegExp, fn: StepFn): void;
19
- when(pattern: string | RegExp, fn: StepFn): void;
20
- then(pattern: string | RegExp, fn: StepFn): void;
21
- match(step: ParsedStep): StepMatch | null;
22
- /** 返回已注册步骤的描述列表,用于 fail-loud 诊断 (rc-3)。 */
23
- list(): ReadonlyArray<{ keyword: 'Given' | 'When' | 'Then'; pattern: string }>;
24
- }
25
-
26
- interface RegisteredStep {
27
- keyword: 'Given' | 'When' | 'Then';
28
- pattern: string | RegExp;
29
- fn: StepFn;
30
- }
31
-
32
- /**
33
- * defineFeature 使用的测试注册钩子。可选注入,便于单元测试验证
34
- * @disabled 与正常注册路径调用了正确的钩子 (vitest 4.x 不允许在 it 内调 describe)。
35
- */
36
- export interface DefineFeatureHooks {
37
- describe: (name: string, fn: () => void) => void;
38
- it: (name: string, fn: () => void | Promise<void>) => void;
39
- itSkip: (name: string, fn: () => void) => void;
40
- }
41
-
42
- export function createStepRegistry(): StepRegistry {
43
- const steps: RegisteredStep[] = [];
44
-
45
- function register(keyword: RegisteredStep['keyword']) {
46
- return (pattern: string | RegExp, fn: StepFn) => {
47
- steps.push({ keyword, pattern, fn });
48
- };
49
- }
50
-
51
- function match(step: ParsedStep): StepMatch | null {
52
- for (const registered of steps) {
53
- // keyword 匹配:And/But 匹配任何 registered keyword (gherkin 语义)
54
- const keywordMatch =
55
- step.keyword === registered.keyword ||
56
- step.keyword === 'And' ||
57
- step.keyword === 'But';
58
- if (!keywordMatch) continue;
59
-
60
- if (typeof registered.pattern === 'string') {
61
- if (registered.pattern === step.text) {
62
- return { fn: registered.fn, args: [] };
63
- }
64
- } else {
65
- const m = registered.pattern.exec(step.text);
66
- if (m) {
67
- return { fn: registered.fn, args: m.slice(1) };
68
- }
69
- }
70
- }
71
- return null;
72
- }
73
-
74
- return {
75
- given: register('Given'),
76
- when: register('When'),
77
- then: register('Then'),
78
- match,
79
- list: () => steps.map((s) => ({ keyword: s.keyword, pattern: String(s.pattern) })),
80
- };
81
- }
82
-
83
- function parseDisabledTag(tags: string[]): { reason: string; owner: string; date: string } | null {
84
- for (const tag of tags) {
85
- if (tag.startsWith('@disabled')) {
86
- // 格式: @disabled(reason="...",owner="...",date="...")
87
- // rc-3/rc-9: 三字段必填,缺失即 fail loud,不允许静默 skip。
88
- const reasonMatch = tag.match(/reason="([^"]+)"/);
89
- const ownerMatch = tag.match(/owner="([^"]+)"/);
90
- const dateMatch = tag.match(/date="([^"]+)"/);
91
- if (!reasonMatch || !ownerMatch || !dateMatch) {
92
- throw new Error(
93
- `Malformed @disabled tag: reason, owner, date are all required. ` +
94
- `Expected: @disabled(reason="...",owner="...",date="..."). Got: ${tag}`
95
- );
96
- }
97
- return {
98
- reason: reasonMatch[1],
99
- owner: ownerMatch[1],
100
- date: dateMatch[1],
101
- };
102
- }
103
- }
104
- return null;
105
- }
106
-
107
- function createStepContext(): StepContext {
108
- return {
109
- state: {},
110
- redactable: {},
111
- attachments: [],
112
- };
113
- }
114
-
115
- /**
116
- * 把 .feature 文本注册为 vitest describe/it。
117
- *
118
- * 关键行为:
119
- * - @disabled 标签的 scenario 走 it.skip,并打印显式 skip 报告 (rc-9)
120
- * - step 未匹配时 fail loud (rc-3)
121
- * - 每个场景独立 StepContext (rc-7)
122
- *
123
- * hooks 可选注入,默认使用 vitest 的 describe/it/it.skip。测试时传 spy
124
- * 可避免在 it 内调 describe 触发 vitest "suite inside test" 错误。
125
- */
126
- export function defineFeature(
127
- featureText: string,
128
- registry: StepRegistry,
129
- hooks?: Partial<DefineFeatureHooks>
130
- ): void {
131
- const h: DefineFeatureHooks = {
132
- describe,
133
- it,
134
- itSkip: (name, fn) => it.skip(name, fn),
135
- ...hooks,
136
- };
137
- const scenarios = parseFeature(featureText);
138
-
139
- h.describe(scenarios[0]?.featureName ?? '(feature)', () => {
140
- for (const scenario of scenarios) {
141
- const disabledInfo = parseDisabledTag(scenario.scenarioTags);
142
-
143
- if (disabledInfo) {
144
- // 显式 skip 报告 (rc-9: no silent fallback)
145
- h.itSkip(`${scenario.scenarioName} [SKIP: ${disabledInfo.reason}; owner=${disabledInfo.owner}; date=${disabledInfo.date}]`, () => {});
146
- continue;
147
- }
148
-
149
- h.it(scenario.scenarioName, async () => {
150
- const ctx = createStepContext();
151
- const allSteps = [...(scenario.background ?? []), ...scenario.steps];
152
-
153
- for (const step of allSteps) {
154
- const match = registry.match(step);
155
- if (!match) {
156
- // fail loud (rc-3): 列出已注册 steps 帮助诊断
157
- const registeredList = registry.list().length > 0
158
- ? registry.list().map((s) => ` ${s.keyword} ${s.pattern}`).join('\n')
159
- : ' (no steps registered)';
160
- throw new Error(
161
- `Step not matched: ${step.keyword} ${step.text}\n` +
162
- `Scenario: ${scenario.scenarioName}\n` +
163
- `Registered steps:\n${registeredList}`
164
- );
165
- }
166
-
167
- try {
168
- await match.fn(ctx, ...match.args);
169
- } catch (e) {
170
- // 增强 error 信息:附加 step 文本和场景名
171
- const enhanced = e instanceof Error ? e : new Error(String(e));
172
- enhanced.message = `Step failed: ${step.keyword} ${step.text}\nScenario: ${scenario.scenarioName}\n${enhanced.message}`;
173
- throw enhanced;
174
- }
175
- }
176
- });
177
- }
178
- });
179
- }
@@ -1,79 +0,0 @@
1
- /**
2
- * PRI-503 regression: admission gate must be checked before intakeService.intake()
3
- * in every CLI command that calls it. This static source-text scan prevents future
4
- * commands (or refactors) from re-introducing the bypass that PR #1134 missed in
5
- * pain-retry.ts and diagnose.ts (ERR-089 sibling-branch defect).
6
- *
7
- * Why static scan: runtime mocking of the full CLI command path is heavy and
8
- * brittle. A source-text check is deterministic, fast, and directly asserts the
9
- * invariant ("gate call appears before intake call in the same file").
10
- */
11
- import { describe, it, expect } from 'vitest';
12
- import * as fs from 'fs';
13
- import * as path from 'path';
14
-
15
- const PD_CLI_COMMANDS_DIR = path.resolve(__dirname, '..', '..', 'src', 'commands');
16
-
17
- function readSource(fileName: string): string {
18
- return fs.readFileSync(path.join(PD_CLI_COMMANDS_DIR, fileName), 'utf-8');
19
- }
20
-
21
- describe('PRI-503: admission gate coverage (static source scan)', () => {
22
- describe('shared helper exists', () => {
23
- it('admission-gate.ts exists and exports checkAdmissionGate', () => {
24
- const content = readSource('admission-gate.ts');
25
- expect(content).toContain('export function checkAdmissionGate');
26
- expect(content).toContain('evaluateCandidateAdmissionFromRecord');
27
- });
28
- });
29
-
30
- describe('candidate.ts uses shared helper (no local definition)', () => {
31
- it('candidate.ts imports checkAdmissionGate from ./admission-gate.js', () => {
32
- const content = readSource('candidate.ts');
33
- expect(content).toContain("from './admission-gate.js'");
34
- expect(content).toContain('checkAdmissionGate');
35
- });
36
-
37
- it('candidate.ts no longer defines a local function checkAdmissionGate', () => {
38
- const content = readSource('candidate.ts');
39
- // Local definition would be `function checkAdmissionGate(` at top level
40
- expect(content).not.toMatch(/function\s+checkAdmissionGate\s*\(/);
41
- });
42
- });
43
-
44
- describe('pain-retry.ts checks admission gate before intake', () => {
45
- it('pain-retry.ts imports checkAdmissionGate from ./admission-gate.js', () => {
46
- const content = readSource('pain-retry.ts');
47
- expect(content).toContain("from './admission-gate.js'");
48
- expect(content).toContain('checkAdmissionGate');
49
- });
50
-
51
- it('pain-retry.ts calls checkAdmissionGate before intakeService.intake', () => {
52
- const content = readSource('pain-retry.ts');
53
- const gateIdx = content.indexOf('checkAdmissionGate(');
54
- const intakeIdx = content.indexOf('intakeService.intake(');
55
- expect(gateIdx).toBeGreaterThan(-1);
56
- expect(intakeIdx).toBeGreaterThan(-1);
57
- // Gate MUST appear before intake in source order
58
- expect(gateIdx).toBeLessThan(intakeIdx);
59
- });
60
- });
61
-
62
- describe('diagnose.ts checks admission gate before intake', () => {
63
- it('diagnose.ts imports checkAdmissionGate from ./admission-gate.js', () => {
64
- const content = readSource('diagnose.ts');
65
- expect(content).toContain("from './admission-gate.js'");
66
- expect(content).toContain('checkAdmissionGate');
67
- });
68
-
69
- it('diagnose.ts calls checkAdmissionGate before intakeService.intake', () => {
70
- const content = readSource('diagnose.ts');
71
- const gateIdx = content.indexOf('checkAdmissionGate(');
72
- const intakeIdx = content.indexOf('intakeService.intake(');
73
- expect(gateIdx).toBeGreaterThan(-1);
74
- expect(intakeIdx).toBeGreaterThan(-1);
75
- // Gate MUST appear before intake in source order
76
- expect(gateIdx).toBeLessThan(intakeIdx);
77
- });
78
- });
79
- });