@unbrained/pm-cli 2026.9.7 → 2026.9.9

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 (746) hide show
  1. package/.agents/skills/pm-developer/SKILL.md +12 -4
  2. package/.agents/skills/pm-developer/references/MULTI_AGENT_MERGE.md +19 -10
  3. package/.agents/skills/pm-extensions/SKILL.md +6 -0
  4. package/.agents/skills/pm-sdk/SKILL.md +11 -2
  5. package/.agents/skills/pm-user/SKILL.md +7 -2
  6. package/.agents/skills/pm-user/references/ECOSYSTEM_PLANNING.md +95 -0
  7. package/.claude-plugin/marketplace.json +2 -2
  8. package/CHANGELOG.md +231 -182
  9. package/dist/cli/after-command-context-usage.js +1 -48
  10. package/dist/cli/argv-utils.js +1 -40
  11. package/dist/cli/bootstrap-args.js +1 -9
  12. package/dist/cli/bundle-integrity.js +2 -110
  13. package/dist/cli/commander-usage.js +11 -771
  14. package/dist/cli/commands/activity.js +1 -9
  15. package/dist/cli/commands/aggregate.js +1 -5
  16. package/dist/cli/commands/append.js +1 -5
  17. package/dist/cli/commands/claim.js +1 -5
  18. package/dist/cli/commands/close-many.js +1 -5
  19. package/dist/cli/commands/close.js +1 -9
  20. package/dist/cli/commands/comments.js +1 -5
  21. package/dist/cli/commands/config.js +1 -9
  22. package/dist/cli/commands/context.js +1 -9
  23. package/dist/cli/commands/contracts.js +1 -5
  24. package/dist/cli/commands/copy.js +1 -9
  25. package/dist/cli/commands/create.js +1 -9
  26. package/dist/cli/commands/delete.js +1 -9
  27. package/dist/cli/commands/deps.js +1 -9
  28. package/dist/cli/commands/docs.js +1 -9
  29. package/dist/cli/commands/duplicates.js +1 -9
  30. package/dist/cli/commands/eval.js +1 -9
  31. package/dist/cli/commands/extension/describe.js +1 -5
  32. package/dist/cli/commands/extension/scaffold.js +1 -5
  33. package/dist/cli/commands/extension/shared.js +1 -5
  34. package/dist/cli/commands/extension.js +1 -9
  35. package/dist/cli/commands/files.js +1 -9
  36. package/dist/cli/commands/focus.js +1 -9
  37. package/dist/cli/commands/gc.js +1 -9
  38. package/dist/cli/commands/get.js +1 -9
  39. package/dist/cli/commands/graph.js +1 -10
  40. package/dist/cli/commands/health.js +1 -9
  41. package/dist/cli/commands/history-compact.js +1 -10
  42. package/dist/cli/commands/history-redact.js +1 -11
  43. package/dist/cli/commands/history-repair.js +1 -10
  44. package/dist/cli/commands/history.js +1 -5
  45. package/dist/cli/commands/index.js +1 -58
  46. package/dist/cli/commands/init-agent-guidance.js +1 -9
  47. package/dist/cli/commands/init.js +1 -9
  48. package/dist/cli/commands/learnings.js +1 -5
  49. package/dist/cli/commands/lifecycle-transitions.js +1 -5
  50. package/dist/cli/commands/list.js +1 -9
  51. package/dist/cli/commands/merge.js +1 -11
  52. package/dist/cli/commands/next.js +1 -9
  53. package/dist/cli/commands/notes.js +1 -5
  54. package/dist/cli/commands/plan.js +1 -9
  55. package/dist/cli/commands/profile.js +1 -9
  56. package/dist/cli/commands/restore.js +1 -9
  57. package/dist/cli/commands/scheduling-shortcuts.js +1 -9
  58. package/dist/cli/commands/schema.js +1 -10
  59. package/dist/cli/commands/search.js +1 -9
  60. package/dist/cli/commands/stats.js +1 -9
  61. package/dist/cli/commands/telemetry.js +1 -9
  62. package/dist/cli/commands/test-all.js +1 -9
  63. package/dist/cli/commands/test-runs.js +1 -9
  64. package/dist/cli/commands/test.js +1 -9
  65. package/dist/cli/commands/update-many.js +1 -5
  66. package/dist/cli/commands/update.js +1 -9
  67. package/dist/cli/commands/upgrade.js +1 -5
  68. package/dist/cli/commands/validate.js +1 -15
  69. package/dist/cli/context-intent-invocation.js +1 -20
  70. package/dist/cli/description-stdin.js +1 -17
  71. package/dist/cli/error-guidance.js +1 -1353
  72. package/dist/cli/extension-command-help.js +5 -636
  73. package/dist/cli/extension-command-options.js +1 -427
  74. package/dist/cli/extension-recovery.js +1 -126
  75. package/dist/cli/help-content.js +2 -1001
  76. package/dist/cli/help-json-payload.js +4 -570
  77. package/dist/cli/main.d.ts +4 -0
  78. package/dist/cli/main.js +5 -2573
  79. package/dist/cli/migration-gates.js +1 -289
  80. package/dist/cli/public.js +1 -20
  81. package/dist/cli/register-annotations.js +1 -270
  82. package/dist/cli/register-assurance.js +1 -62
  83. package/dist/cli/register-files-lookup.js +1 -56
  84. package/dist/cli/register-history-activity.d.ts +8 -0
  85. package/dist/cli/register-history-activity.js +2 -0
  86. package/dist/cli/register-history-author.js +1 -38
  87. package/dist/cli/register-history-maintenance.d.ts +9 -0
  88. package/dist/cli/register-history-maintenance.js +2 -0
  89. package/dist/cli/register-list-query.js +10 -943
  90. package/dist/cli/register-mutation-options.js +1 -9
  91. package/dist/cli/register-mutation.d.ts +0 -5
  92. package/dist/cli/register-mutation.js +19 -1893
  93. package/dist/cli/register-operations.js +1 -920
  94. package/dist/cli/register-setup.js +1 -716
  95. package/dist/cli/register-structured-mutation.js +1 -196
  96. package/dist/cli/registration-helpers.js +1 -5
  97. package/dist/cli/runtime-compatibility-boundary.js +4 -42
  98. package/dist/cli/schema-registration-helpers.js +1 -73
  99. package/dist/cli/search-refresh.js +1 -13
  100. package/dist/cli/stats-analytics-json.js +1 -68
  101. package/dist/cli/telemetry-flush.js +1 -10
  102. package/dist/cli-bundle/bundle-manifest.json +164 -156
  103. package/dist/cli-bundle/chunks/{chunk-NPN5I67J.js → chunk-3IPRM75M.js} +3 -3
  104. package/dist/cli-bundle/chunks/chunk-4VL5P22L.js +2 -0
  105. package/dist/cli-bundle/chunks/chunk-AAFBV3U3.js +29 -0
  106. package/dist/cli-bundle/chunks/chunk-D3YVILJJ.js +20 -0
  107. package/dist/cli-bundle/chunks/{chunk-WYRZZ5ZE.js → chunk-DEZPZOQ7.js} +2 -2
  108. package/dist/cli-bundle/chunks/chunk-ECBLPN7B.js +3 -0
  109. package/dist/cli-bundle/chunks/chunk-J6ERHBV2.js +235 -0
  110. package/dist/cli-bundle/chunks/chunk-JUNJ5EKI.js +2 -0
  111. package/dist/cli-bundle/chunks/chunk-L5RCDKQ2.js +2 -0
  112. package/dist/cli-bundle/chunks/chunk-NSAPNEYH.js +2 -0
  113. package/dist/cli-bundle/chunks/chunk-OHNLSGGV.js +79 -0
  114. package/dist/cli-bundle/chunks/chunk-WQKMSFBV.js +5 -0
  115. package/dist/cli-bundle/chunks/{chunk-BAX2BYUW.js → chunk-XZ6T7YPP.js} +256 -150
  116. package/dist/cli-bundle/chunks/{chunk-JT6XF6GE.js → chunk-Z3XVXUVF.js} +4 -4
  117. package/dist/cli-bundle/chunks/register-list-query-UIHRCS6D.js +11 -0
  118. package/dist/cli-bundle/chunks/register-mutation-WHWMGRVX.js +20 -0
  119. package/dist/cli-bundle/chunks/register-operations-64YZYTC5.js +2 -0
  120. package/dist/cli-bundle/chunks/register-setup-PERI45EM.js +2 -0
  121. package/dist/cli-bundle/focused-chunks/chunk-2W4XIYOB.js +2 -0
  122. package/dist/cli-bundle/focused-chunks/chunk-2WSBXIGF.js +12 -0
  123. package/dist/cli-bundle/focused-chunks/chunk-5FHTCOHS.js +3 -0
  124. package/dist/cli-bundle/focused-chunks/chunk-7N6DOREF.js +26 -0
  125. package/dist/cli-bundle/focused-chunks/{chunk-3BZEOXLT.js → chunk-7PC4R5QB.js} +2 -2
  126. package/dist/cli-bundle/focused-chunks/chunk-BUCJUZVG.js +6 -0
  127. package/dist/cli-bundle/focused-chunks/chunk-FE3BABLJ.js +2 -0
  128. package/dist/cli-bundle/focused-chunks/chunk-IWITF53W.js +2 -0
  129. package/dist/cli-bundle/focused-chunks/chunk-OQUGRHKV.js +10 -0
  130. package/dist/cli-bundle/focused-chunks/{chunk-M6PBRFSH.js → chunk-PNKIANFZ.js} +2 -2
  131. package/dist/cli-bundle/focused-chunks/{chunk-LIJIA4TY.js → chunk-QQQ4SAUO.js} +3 -3
  132. package/dist/cli-bundle/focused-chunks/chunk-TTYXF5YD.js +177 -0
  133. package/dist/cli-bundle/focused-chunks/chunk-XNR3DM6J.js +2 -0
  134. package/dist/cli-bundle/focused-chunks/chunk-XSS3APUF.js +9 -0
  135. package/dist/cli-bundle/focused-chunks/chunk-YCDQ2N23.js +8 -0
  136. package/dist/cli-bundle/focused-chunks/chunk-YJUXGS57.js +20 -0
  137. package/dist/cli-bundle/focused-chunks/chunk-ZTCE4UO6.js +58 -0
  138. package/dist/cli-bundle/main.js +20 -20
  139. package/dist/cli-bundle/sdk-authoring.js +1 -1
  140. package/dist/cli-bundle/sdk-contracts.js +2 -2
  141. package/dist/cli-bundle/sdk-core.js +37 -37
  142. package/dist/cli-bundle/sdk-governance.js +1 -1
  143. package/dist/cli-bundle/sdk-graph.js +1 -1
  144. package/dist/cli-bundle/sdk-merge.js +42 -42
  145. package/dist/cli-bundle/sdk-query.js +1 -1
  146. package/dist/cli-bundle/sdk-runtime.js +1 -1
  147. package/dist/cli-bundle/sdk-testing.js +1 -1
  148. package/dist/cli-bundle/sdk.js +11 -11
  149. package/dist/cli.js +1 -104
  150. package/dist/core/checkpoint/checkpoint-gc.js +1 -169
  151. package/dist/core/checkpoint/mutation-checkpoint.js +2 -133
  152. package/dist/core/config/nested-settings.js +1 -534
  153. package/dist/core/config/positional-value.js +1 -109
  154. package/dist/core/diagnostics/remediation.js +1 -506
  155. package/dist/core/extensions/activation-summary-markdown.js +2 -145
  156. package/dist/core/extensions/activation-summary.js +1 -92
  157. package/dist/core/extensions/activation-transaction.js +1 -46
  158. package/dist/core/extensions/capability-usage.js +1 -173
  159. package/dist/core/extensions/command-hook-context.js +1 -13
  160. package/dist/core/extensions/command-metadata-contract.js +1 -22
  161. package/dist/core/extensions/command-visibility-tier.js +1 -29
  162. package/dist/core/extensions/contribution-inventory.js +1 -173
  163. package/dist/core/extensions/exporter-output-contract.js +1 -66
  164. package/dist/core/extensions/extension-candidate.js +1 -18
  165. package/dist/core/extensions/extension-capability-aliases.js +1 -158
  166. package/dist/core/extensions/extension-hook-runtime.js +1 -699
  167. package/dist/core/extensions/extension-policy.js +1 -599
  168. package/dist/core/extensions/extension-registries.js +1 -62
  169. package/dist/core/extensions/extension-runtime-helpers.js +1 -33
  170. package/dist/core/extensions/extension-types.js +1 -102
  171. package/dist/core/extensions/flag-definition-validation.js +1 -52
  172. package/dist/core/extensions/flag-value-types.js +1 -64
  173. package/dist/core/extensions/index.js +1 -526
  174. package/dist/core/extensions/item-field-types.js +1 -39
  175. package/dist/core/extensions/item-fields.js +1 -261
  176. package/dist/core/extensions/loader.js +1 -2223
  177. package/dist/core/extensions/manifest-schema.js +1 -69
  178. package/dist/core/extensions/module-graph-snapshot.js +1 -33
  179. package/dist/core/extensions/preflight-ownership.js +1 -41
  180. package/dist/core/extensions/registration-validation.js +1 -82
  181. package/dist/core/extensions/registration-values.js +1 -209
  182. package/dist/core/extensions/reserved-host-flags.js +1 -36
  183. package/dist/core/extensions/runtime-registrations.js +1 -67
  184. package/dist/core/extensions/service-ownership.js +1 -19
  185. package/dist/core/extensions/version-compat.js +1 -216
  186. package/dist/core/fs/fs-utils.js +2 -158
  187. package/dist/core/fs/host-environment-errors.js +1 -141
  188. package/dist/core/fs/index.js +1 -9
  189. package/dist/core/fs/path-utils.js +1 -17
  190. package/dist/core/governance/content-fields.js +1 -160
  191. package/dist/core/governance/issue-codes.js +1 -151
  192. package/dist/core/governance/metadata-coverage.js +1 -358
  193. package/dist/core/history/drift-cache.js +3 -72
  194. package/dist/core/history/drift-scan.js +1 -342
  195. package/dist/core/history/event-classification.js +1 -109
  196. package/dist/core/history/event-index.js +8 -784
  197. package/dist/core/history/history-compact-bulk.js +1 -104
  198. package/dist/core/history/history-diff.js +1 -158
  199. package/dist/core/history/history-rewrite.d.ts +6 -1
  200. package/dist/core/history/history-rewrite.js +1 -107
  201. package/dist/core/history/history-storage-stats.js +1 -102
  202. package/dist/core/history/history-stream-policy.js +1 -62
  203. package/dist/core/history/history.js +2 -617
  204. package/dist/core/history/identity.js +1 -30
  205. package/dist/core/history/index.js +1 -9
  206. package/dist/core/history/projection.js +1 -196
  207. package/dist/core/history/read.d.ts +9 -0
  208. package/dist/core/history/read.js +1 -57
  209. package/dist/core/history/replay.js +2 -439
  210. package/dist/core/history/version-address.js +1 -32
  211. package/dist/core/history/workspace-history.js +2 -433
  212. package/dist/core/io/body-file.js +1 -62
  213. package/dist/core/io/bulk-ids-input.js +1 -112
  214. package/dist/core/item/actionability.js +1 -327
  215. package/dist/core/item/dependency-reference.js +1 -20
  216. package/dist/core/item/id.js +1 -112
  217. package/dist/core/item/index.js +1 -12
  218. package/dist/core/item/item-format-version.js +1 -78
  219. package/dist/core/item/item-format.js +5 -1473
  220. package/dist/core/item/item-record.js +1 -23
  221. package/dist/core/item/item-type-definition.js +1 -133
  222. package/dist/core/item/parent-reference-policy.js +1 -57
  223. package/dist/core/item/parse.js +2 -603
  224. package/dist/core/item/plan-lifecycle.js +1 -19
  225. package/dist/core/item/priority.js +1 -61
  226. package/dist/core/item/sprint-release-format.js +1 -38
  227. package/dist/core/item/status-filter.js +1 -115
  228. package/dist/core/item/status.js +1 -43
  229. package/dist/core/item/toon-decode.js +1 -29
  230. package/dist/core/item/type-registry.js +1 -715
  231. package/dist/core/item/type-synonyms.js +1 -38
  232. package/dist/core/lock/index.js +1 -9
  233. package/dist/core/lock/lock-gc.js +1 -240
  234. package/dist/core/lock/lock.js +3 -590
  235. package/dist/core/output/mutation-projection.js +1 -217
  236. package/dist/core/output/output-control.js +1 -25
  237. package/dist/core/output/output.js +11 -494
  238. package/dist/core/output/query-summary.js +1 -58
  239. package/dist/core/output/tabular.js +1 -77
  240. package/dist/core/packages/manifest.js +1 -244
  241. package/dist/core/packages/root.js +1 -84
  242. package/dist/core/policy/workflow-policy-schema.d.ts +312 -0
  243. package/dist/core/policy/workflow-policy-schema.js +2 -0
  244. package/dist/core/policy/workflow-policy-store.d.ts +24 -0
  245. package/dist/core/policy/workflow-policy-store.js +2 -0
  246. package/dist/core/policy/workflow-policy.d.ts +139 -0
  247. package/dist/core/policy/workflow-policy.js +2 -0
  248. package/dist/core/profile/profile-describe.js +1 -83
  249. package/dist/core/profile/profile-lint.js +1 -415
  250. package/dist/core/profile/profile-plan.js +0 -0
  251. package/dist/core/profile/profile-presets.js +1 -370
  252. package/dist/core/reproducibility/context.js +1 -82
  253. package/dist/core/schema/fields-file.js +2 -288
  254. package/dist/core/schema/item-types-file.js +2 -296
  255. package/dist/core/schema/runtime-field-filters.js +1 -49
  256. package/dist/core/schema/runtime-field-values.js +1 -313
  257. package/dist/core/schema/runtime-schema.js +2 -826
  258. package/dist/core/schema/status-defs-file.js +2 -227
  259. package/dist/core/schema/status-token.js +1 -31
  260. package/dist/core/schema/type-inference.js +1 -95
  261. package/dist/core/schema/type-presets.js +1 -87
  262. package/dist/core/schema/type-workflows.js +1 -104
  263. package/dist/core/search/background-refresh.js +2 -286
  264. package/dist/core/search/bm25.js +1 -146
  265. package/dist/core/search/cache.js +2 -534
  266. package/dist/core/search/corpus.js +1 -311
  267. package/dist/core/search/embedding-batches.js +1 -163
  268. package/dist/core/search/eval.js +1 -225
  269. package/dist/core/search/http-client.js +1 -75
  270. package/dist/core/search/providers.js +1 -242
  271. package/dist/core/search/relevance.js +1 -244
  272. package/dist/core/search/semantic-defaults.js +1 -199
  273. package/dist/core/search/staleness.js +1 -30
  274. package/dist/core/search/vector-stores.js +2 -664
  275. package/dist/core/search/vectorization-metadata.js +1 -81
  276. package/dist/core/sentry/helpers.js +1 -272
  277. package/dist/core/sentry/instrument.js +1 -387
  278. package/dist/core/session/session-state.js +1 -260
  279. package/dist/core/shared/agent-session-context.js +1 -133
  280. package/dist/core/shared/author.js +1 -1172
  281. package/dist/core/shared/command-types.js +1 -4
  282. package/dist/core/shared/conflict-markers.js +1 -31
  283. package/dist/core/shared/constants.js +1 -405
  284. package/dist/core/shared/errors.js +1 -20
  285. package/dist/core/shared/html-entity-decode.js +1 -131
  286. package/dist/core/shared/index.js +1 -12
  287. package/dist/core/shared/item-metadata-contract.js +1 -89
  288. package/dist/core/shared/lazy-module.js +1 -16
  289. package/dist/core/shared/levenshtein.js +1 -61
  290. package/dist/core/shared/memo.js +1 -19
  291. package/dist/core/shared/numeric-parsers.js +1 -20
  292. package/dist/core/shared/option-alias-visibility.js +1 -67
  293. package/dist/core/shared/primitives.js +1 -127
  294. package/dist/core/shared/serial-queue.js +1 -79
  295. package/dist/core/shared/serialization.js +1 -210
  296. package/dist/core/shared/split-comma-list.js +1 -30
  297. package/dist/core/shared/text-normalization.js +1 -38
  298. package/dist/core/shared/time.js +1 -306
  299. package/dist/core/store/index.js +1 -12
  300. package/dist/core/store/item-format-migration.js +1 -125
  301. package/dist/core/store/item-metadata-cache.js +1 -1116
  302. package/dist/core/store/item-metadata-query-index.js +9 -394
  303. package/dist/core/store/item-metadata-read-work.js +1 -43
  304. package/dist/core/store/item-store.js +1 -693
  305. package/dist/core/store/paths.d.ts +1 -1
  306. package/dist/core/store/paths.js +1 -214
  307. package/dist/core/store/settings-read-cache.js +1 -85
  308. package/dist/core/store/settings-validator.d.ts +1 -0
  309. package/dist/core/store/settings-validator.js +1 -421
  310. package/dist/core/store/settings.js +3 -1309
  311. package/dist/core/store/tracker-preflight.js +1 -141
  312. package/dist/core/telemetry/consent.js +5 -108
  313. package/dist/core/telemetry/observability.js +1 -246
  314. package/dist/core/telemetry/runtime.js +4 -1988
  315. package/dist/core/test/background-runs.js +4 -945
  316. package/dist/core/test/item-test-run-tracking.js +1 -63
  317. package/dist/core/test/run-selectors.js +1 -120
  318. package/dist/core/validate/estimate-defaults.js +1 -89
  319. package/dist/core/validate/fix-planning.js +1 -189
  320. package/dist/core/validate/linked-artifact-reference.js +1 -36
  321. package/dist/core/validate/missing-by-type.js +1 -34
  322. package/dist/core/validate/missing-link-owners.js +1 -95
  323. package/dist/core/validate/stale-file-classification.js +1 -82
  324. package/dist/mcp/http-server.js +5 -448
  325. package/dist/mcp/legacy-adapter.js +1 -77
  326. package/dist/mcp/runtime-capabilities.js +1 -200
  327. package/dist/mcp/server.js +4 -1233
  328. package/dist/mcp/tool-definitions.js +1 -804
  329. package/dist/sdk/actionability.js +1 -13
  330. package/dist/sdk/agent/closed-domain-contracts.js +1 -161
  331. package/dist/sdk/agent/command-recovery.js +1 -59
  332. package/dist/sdk/agent/command-suggestions.js +1 -66
  333. package/dist/sdk/agent/create-option-policy.js +1 -31
  334. package/dist/sdk/agent/identity-config.js +1 -106
  335. package/dist/sdk/agent/item-addressing.js +1 -207
  336. package/dist/sdk/agent/refusal-closure-census.js +1 -151
  337. package/dist/sdk/agent/refusal-closure.js +1 -133
  338. package/dist/sdk/agent/refusal-corpus-contracts.js +1 -193
  339. package/dist/sdk/agent/refusal-reachability.js +1 -593
  340. package/dist/sdk/agent/subcommand-recovery.js +1 -83
  341. package/dist/sdk/agent/task-transcript-contracts.js +1 -197
  342. package/dist/sdk/agent/tracker-preflight-contracts.js +1 -126
  343. package/dist/sdk/agent-capability-contracts.js +1 -428
  344. package/dist/sdk/agent-session-context.js +1 -9
  345. package/dist/sdk/annotations.js +1 -448
  346. package/dist/sdk/author-attribution.js +1 -468
  347. package/dist/sdk/authoring.js +1 -20
  348. package/dist/sdk/cli-bootstrap.js +1 -838
  349. package/dist/sdk/cli-contracts/agent-output-contracts.d.ts +1 -1
  350. package/dist/sdk/cli-contracts/agent-output-contracts.js +4 -476
  351. package/dist/sdk/cli-contracts/bootstrap-command-scanner.js +1 -79
  352. package/dist/sdk/cli-contracts/command-aliases.d.ts +4 -0
  353. package/dist/sdk/cli-contracts/command-aliases.js +1 -107
  354. package/dist/sdk/cli-contracts/command-exit-contracts.js +1 -151
  355. package/dist/sdk/cli-contracts/commander-mutation-options.js +1 -1081
  356. package/dist/sdk/cli-contracts/commander-types.js +1 -159
  357. package/dist/sdk/cli-contracts/completeness.js +1 -393
  358. package/dist/sdk/cli-contracts/enum-contracts.d.ts +1 -1
  359. package/dist/sdk/cli-contracts/enum-contracts.js +1 -222
  360. package/dist/sdk/cli-contracts/flag-contracts.js +1 -1947
  361. package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +1 -347
  362. package/dist/sdk/cli-contracts/grammar-contracts.js +1 -986
  363. package/dist/sdk/cli-contracts/registration-helpers.js +7 -990
  364. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +5 -0
  365. package/dist/sdk/cli-contracts/runtime-contracts.js +1 -2090
  366. package/dist/sdk/cli-contracts/schemas/assurance-definition.js +1 -324
  367. package/dist/sdk/cli-contracts/string-lists.js +1 -16
  368. package/dist/sdk/cli-contracts/tool-option-contracts.js +1 -461
  369. package/dist/sdk/cli-contracts/tool-parameter-tables.js +1 -2167
  370. package/dist/sdk/cli-contracts/tool-schema.d.ts +3 -1
  371. package/dist/sdk/cli-contracts/tool-schema.js +1 -1664
  372. package/dist/sdk/cli-contracts/typed-action-inputs.js +1 -4
  373. package/dist/sdk/cli-contracts.d.ts +1 -1
  374. package/dist/sdk/cli-contracts.js +1 -17
  375. package/dist/sdk/cli-program.js +1 -49
  376. package/dist/sdk/command-line.d.ts +2 -5
  377. package/dist/sdk/command-line.js +1 -78
  378. package/dist/sdk/comments.js +1 -133
  379. package/dist/sdk/compile-cache.js +1 -73
  380. package/dist/sdk/completion.js +174 -839
  381. package/dist/sdk/compose.js +1 -1090
  382. package/dist/sdk/config.js +1 -1204
  383. package/dist/sdk/context/recency.js +1 -33
  384. package/dist/sdk/context/semantic-session-attribution.js +1 -82
  385. package/dist/sdk/context/usage-egress.js +1 -29
  386. package/dist/sdk/context/usage-ledger.js +3 -185
  387. package/dist/sdk/context-intent-contracts.js +1 -709
  388. package/dist/sdk/context-intent-runtime.js +1 -115
  389. package/dist/sdk/context-packing.js +1 -218
  390. package/dist/sdk/context-relevance.js +1 -503
  391. package/dist/sdk/context-signal-store.js +2 -426
  392. package/dist/sdk/context-usage.js +1 -367
  393. package/dist/sdk/contracts.js +1 -23
  394. package/dist/sdk/core-governance.js +1 -14
  395. package/dist/sdk/core.js +1 -14
  396. package/dist/sdk/corpus-shape.js +1 -401
  397. package/dist/sdk/define.js +1 -220
  398. package/dist/sdk/dependencies.js +1 -718
  399. package/dist/sdk/dependency-flag-validation.js +1 -156
  400. package/dist/sdk/dependency-provenance.js +1 -135
  401. package/dist/sdk/docs.js +1 -14
  402. package/dist/sdk/duplicates.js +1 -40
  403. package/dist/sdk/environment/agent-environment.js +1 -466
  404. package/dist/sdk/environment/host-environment-errors.js +1 -8
  405. package/dist/sdk/environment/project-runtime-compatibility.js +1 -481
  406. package/dist/sdk/environment/source-context.js +1 -28
  407. package/dist/sdk/environment/tracker-preflight.js +1 -9
  408. package/dist/sdk/error-code-catalog.js +1 -153
  409. package/dist/sdk/error-runtime.js +1 -58
  410. package/dist/sdk/errors.js +1 -58
  411. package/dist/sdk/eval.js +1 -190
  412. package/dist/sdk/extension/author-manifest.js +1 -92
  413. package/dist/sdk/extension/bundled-catalog.js +1 -332
  414. package/dist/sdk/extension/concurrency.js +1 -25
  415. package/dist/sdk/extension/copy-scope.d.ts +2 -0
  416. package/dist/sdk/extension/copy-scope.js +2 -0
  417. package/dist/sdk/extension/custom-field-collisions.js +1 -30
  418. package/dist/sdk/extension/describe.js +3 -189
  419. package/dist/sdk/extension/doctor.js +1 -606
  420. package/dist/sdk/extension/install-plan.d.ts +69 -0
  421. package/dist/sdk/extension/install-plan.js +2 -0
  422. package/dist/sdk/extension/install-receipts.d.ts +7 -0
  423. package/dist/sdk/extension/install-receipts.js +2 -0
  424. package/dist/sdk/extension/install-runtime.js +3 -313
  425. package/dist/sdk/extension/install-snapshot.js +1 -66
  426. package/dist/sdk/extension/install-sources.js +5 -1057
  427. package/dist/sdk/extension/managed-state.js +2 -252
  428. package/dist/sdk/extension/migrations.js +2 -174
  429. package/dist/sdk/extension/output-ownership.js +1 -25
  430. package/dist/sdk/extension/runtime-summary.js +1 -18
  431. package/dist/sdk/extension/scaffold.js +4 -2308
  432. package/dist/sdk/extension/shared.js +1 -147
  433. package/dist/sdk/extension/source-resolution.js +1 -65
  434. package/dist/sdk/extension/update-check.js +1 -67
  435. package/dist/sdk/extension-command-context.js +1 -44
  436. package/dist/sdk/extension-contracts.js +1 -73
  437. package/dist/sdk/extension.d.ts +7 -2
  438. package/dist/sdk/extension.js +1 -2196
  439. package/dist/sdk/files.js +1 -535
  440. package/dist/sdk/flag-invocation-contracts.d.ts +0 -5
  441. package/dist/sdk/flag-invocation-contracts.js +1 -344
  442. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1 -2224
  443. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -2236
  444. package/dist/sdk/generated-error-code-catalog.js +1 -16
  445. package/dist/sdk/governance/assurance-action-contracts.js +1 -4
  446. package/dist/sdk/governance/assurance-action.js +1 -411
  447. package/dist/sdk/governance/assurance-limits.js +1 -10
  448. package/dist/sdk/governance/assurance-mutation-error.js +1 -81
  449. package/dist/sdk/governance/assurance-presets.js +1 -135
  450. package/dist/sdk/governance/assurance-runtime.js +1 -238
  451. package/dist/sdk/governance/assurance.js +4 -1182
  452. package/dist/sdk/governance/boundary-fixtures.js +1 -200
  453. package/dist/sdk/governance/coverage-assurance.js +1 -60
  454. package/dist/sdk/governance/defect-recurrence-coverage.js +1 -188
  455. package/dist/sdk/governance/defect-recurrence-graph.js +1 -120
  456. package/dist/sdk/governance/defect-recurrence-signals.js +1 -24
  457. package/dist/sdk/governance/defect-recurrence.js +1 -623
  458. package/dist/sdk/governance/extension-host-version.js +1 -115
  459. package/dist/sdk/governance/gc.js +1 -368
  460. package/dist/sdk/governance/health.js +1 -2367
  461. package/dist/sdk/governance/hierarchy-validation.js +1 -108
  462. package/dist/sdk/governance/linked-file-report.js +1 -71
  463. package/dist/sdk/governance/merge-receipt-history.js +1 -206
  464. package/dist/sdk/governance/provenance-health.js +1 -282
  465. package/dist/sdk/governance/reindex.js +4 -761
  466. package/dist/sdk/governance/stale-work.js +1 -82
  467. package/dist/sdk/governance/status-role-diagnostics.js +1 -35
  468. package/dist/sdk/governance/storage-integrity.js +1 -280
  469. package/dist/sdk/governance/tracked-runtime-cache.js +1 -106
  470. package/dist/sdk/governance/upgrade.js +2 -327
  471. package/dist/sdk/governance/validate-history-drift.js +1 -81
  472. package/dist/sdk/governance/validate-item-reader.js +1 -17
  473. package/dist/sdk/governance/validate-normalization.js +1 -36
  474. package/dist/sdk/governance/validate.d.ts +3 -1
  475. package/dist/sdk/governance/validate.js +1 -2261
  476. package/dist/sdk/governance/workflow-completeness.d.ts +32 -0
  477. package/dist/sdk/governance/workflow-completeness.js +2 -0
  478. package/dist/sdk/governance/workflow-policy.d.ts +47 -0
  479. package/dist/sdk/governance/workflow-policy.js +4 -0
  480. package/dist/sdk/governance/workspace-position.js +1 -163
  481. package/dist/sdk/governance.d.ts +2 -0
  482. package/dist/sdk/governance.js +1 -31
  483. package/dist/sdk/graph/adapter.js +1 -181
  484. package/dist/sdk/graph/analytics.js +1 -474
  485. package/dist/sdk/graph/assembly.js +1 -377
  486. package/dist/sdk/graph/cache.js +1 -160
  487. package/dist/sdk/graph/centrality.js +1 -258
  488. package/dist/sdk/graph/conformance.js +1 -130
  489. package/dist/sdk/graph/deadline-scheduling.d.ts +90 -0
  490. package/dist/sdk/graph/deadline-scheduling.js +2 -0
  491. package/dist/sdk/graph/durable-cache.d.ts +1 -1
  492. package/dist/sdk/graph/durable-cache.js +1 -361
  493. package/dist/sdk/graph/governance-contracts.js +1 -34
  494. package/dist/sdk/graph/governance.d.ts +13 -1
  495. package/dist/sdk/graph/governance.js +1 -735
  496. package/dist/sdk/graph/hierarchy-integrity.js +1 -310
  497. package/dist/sdk/graph/index.d.ts +3 -2
  498. package/dist/sdk/graph/index.js +1 -26
  499. package/dist/sdk/graph/lifecycle-coverage.d.ts +32 -0
  500. package/dist/sdk/graph/lifecycle-coverage.js +2 -0
  501. package/dist/sdk/graph/mutation-advisory.js +1 -176
  502. package/dist/sdk/graph/remediation.js +1 -197
  503. package/dist/sdk/graph/run.d.ts +15 -1
  504. package/dist/sdk/graph/run.js +1 -768
  505. package/dist/sdk/graph/scheduling.js +1 -124
  506. package/dist/sdk/graph/traversal.js +1 -284
  507. package/dist/sdk/graph/workspace-relationship-kind-registry.js +1 -27
  508. package/dist/sdk/graph.js +1 -15
  509. package/dist/sdk/guide-topics.js +1 -707
  510. package/dist/sdk/guide.js +1 -279
  511. package/dist/sdk/history/maintenance.d.ts +71 -0
  512. package/dist/sdk/history/maintenance.js +2 -0
  513. package/dist/sdk/history/salvage.js +2 -247
  514. package/dist/sdk/history/subject.d.ts +19 -0
  515. package/dist/sdk/history/subject.js +2 -0
  516. package/dist/sdk/history-analytics.js +1 -282
  517. package/dist/sdk/history-compact.js +1 -527
  518. package/dist/sdk/history-mcp.js +1 -68
  519. package/dist/sdk/history-provenance.js +1 -182
  520. package/dist/sdk/history-read.js +1 -96
  521. package/dist/sdk/history-redact.d.ts +1 -14
  522. package/dist/sdk/history-redact.js +1 -643
  523. package/dist/sdk/history-repair.d.ts +5 -0
  524. package/dist/sdk/history-repair.js +1 -657
  525. package/dist/sdk/improvement-ledger-validation.js +1 -62
  526. package/dist/sdk/improvement-ledger.js +2 -257
  527. package/dist/sdk/index.d.ts +4 -1
  528. package/dist/sdk/index.js +1 -183
  529. package/dist/sdk/init-agent-guidance.js +2 -496
  530. package/dist/sdk/init.js +2 -820
  531. package/dist/sdk/invocation-author.js +1 -39
  532. package/dist/sdk/item-children.js +1 -90
  533. package/dist/sdk/item-metadata-index.js +1 -15
  534. package/dist/sdk/item-schedule.js +1 -27
  535. package/dist/sdk/item-transaction.js +1 -396
  536. package/dist/sdk/learnings.js +1 -29
  537. package/dist/sdk/lifecycle/append.js +2 -53
  538. package/dist/sdk/lifecycle/claim.d.ts +2 -0
  539. package/dist/sdk/lifecycle/claim.js +1 -242
  540. package/dist/sdk/lifecycle/close-many.js +1 -438
  541. package/dist/sdk/lifecycle/close.js +1 -468
  542. package/dist/sdk/lifecycle/copy.js +1 -212
  543. package/dist/sdk/lifecycle/create.js +1 -1949
  544. package/dist/sdk/lifecycle/delete.js +1 -45
  545. package/dist/sdk/lifecycle/event-validation-messages.js +1 -91
  546. package/dist/sdk/lifecycle/focus.js +1 -91
  547. package/dist/sdk/lifecycle/hierarchy-mutation-lock.js +1 -24
  548. package/dist/sdk/lifecycle/legacy-none-tokens.js +1 -149
  549. package/dist/sdk/lifecycle/lifecycle-transitions.js +1 -40
  550. package/dist/sdk/lifecycle/mcp-actions.d.ts +2 -0
  551. package/dist/sdk/lifecycle/mcp-actions.js +1 -51
  552. package/dist/sdk/lifecycle/metadata-normalizers.js +1 -46
  553. package/dist/sdk/lifecycle/mutation-command-options.js +1 -9
  554. package/dist/sdk/lifecycle/plan.js +1 -1606
  555. package/dist/sdk/lifecycle/recurrence-parsers.d.ts +1 -1
  556. package/dist/sdk/lifecycle/recurrence-parsers.js +1 -147
  557. package/dist/sdk/lifecycle/reopen.js +1 -68
  558. package/dist/sdk/lifecycle/repeatable-metadata-parsers.js +1 -143
  559. package/dist/sdk/lifecycle/restore.d.ts +1 -0
  560. package/dist/sdk/lifecycle/restore.js +1 -330
  561. package/dist/sdk/lifecycle/shared-unset-fields.js +1 -295
  562. package/dist/sdk/lifecycle/update-many.js +1 -861
  563. package/dist/sdk/lifecycle/update.js +1 -2136
  564. package/dist/sdk/lifecycle-completion.js +1 -92
  565. package/dist/sdk/lifecycle-policy.js +1 -120
  566. package/dist/sdk/linked-artifacts.js +1 -530
  567. package/dist/sdk/mcp/apps.js +4 -133
  568. package/dist/sdk/mcp/authorization.js +1 -404
  569. package/dist/sdk/mcp/discovery.js +1 -494
  570. package/dist/sdk/mcp/interactions.js +1 -336
  571. package/dist/sdk/mcp/protocol.d.ts +7 -0
  572. package/dist/sdk/mcp/protocol.js +1 -184
  573. package/dist/sdk/mcp/skills.js +1 -389
  574. package/dist/sdk/mcp/subscriptions.js +1 -211
  575. package/dist/sdk/mcp/tasks.js +2 -430
  576. package/dist/sdk/mcp/transport.js +1 -260
  577. package/dist/sdk/merge/abandoned-receipts.js +1 -46
  578. package/dist/sdk/merge/driver.js +1 -212
  579. package/dist/sdk/merge/index.js +1 -16
  580. package/dist/sdk/merge/install.js +3 -561
  581. package/dist/sdk/merge/receipt-file-boundary.js +1 -46
  582. package/dist/sdk/merge/receipt-operation.js +1 -96
  583. package/dist/sdk/merge/receipt-schema.js +1 -397
  584. package/dist/sdk/merge/receipts.js +4 -525
  585. package/dist/sdk/merge/reconcile.js +1 -352
  586. package/dist/sdk/merge/three-way.js +3 -775
  587. package/dist/sdk/merge.js +1 -10
  588. package/dist/sdk/mutation-events.js +1 -292
  589. package/dist/sdk/mutation-guard.js +1 -216
  590. package/dist/sdk/notes.js +1 -139
  591. package/dist/sdk/output-contracts.js +1 -172
  592. package/dist/sdk/output-projection.js +1 -430
  593. package/dist/sdk/output-token-accounting.js +1 -140
  594. package/dist/sdk/output.js +1 -64
  595. package/dist/sdk/ownership-source.js +1 -21
  596. package/dist/sdk/package-import-adapters.js +1 -442
  597. package/dist/sdk/package-migrations.js +1 -20
  598. package/dist/sdk/package-runtime-options.js +1 -80
  599. package/dist/sdk/pagination.js +1 -162
  600. package/dist/sdk/profile.js +1 -454
  601. package/dist/sdk/provenance.js +1 -258
  602. package/dist/sdk/public-surface.json +1 -1
  603. package/dist/sdk/query/activity.js +1 -401
  604. package/dist/sdk/query/aggregate.d.ts +16 -0
  605. package/dist/sdk/query/aggregate.js +1 -390
  606. package/dist/sdk/query/calendar.js +1 -964
  607. package/dist/sdk/query/complete-list.js +1 -215
  608. package/dist/sdk/query/context.js +1 -1702
  609. package/dist/sdk/query/duplicate-candidates.js +1 -70
  610. package/dist/sdk/query/get.js +1 -450
  611. package/dist/sdk/query/history.js +1 -186
  612. package/dist/sdk/query/item-filter-options.js +1 -9
  613. package/dist/sdk/query/light-metadata.js +1 -18
  614. package/dist/sdk/query/list-filter-shared.js +1 -81
  615. package/dist/sdk/query/list.js +1 -1304
  616. package/dist/sdk/query/multi-value-filters.js +1 -78
  617. package/dist/sdk/query/next.js +1 -513
  618. package/dist/sdk/query/parsers.js +1 -44
  619. package/dist/sdk/query/projection-contracts.js +1 -184
  620. package/dist/sdk/query/search-contracts.d.ts +27 -0
  621. package/dist/sdk/query/search-contracts.js +1 -230
  622. package/dist/sdk/query/search-pagination.js +1 -35
  623. package/dist/sdk/query/search-rendering.js +1 -105
  624. package/dist/sdk/query/search.d.ts +6 -4
  625. package/dist/sdk/query/search.js +2 -1987
  626. package/dist/sdk/query.js +1 -35
  627. package/dist/sdk/read-output/continuation.js +1 -194
  628. package/dist/sdk/read-output-budget.js +1 -135
  629. package/dist/sdk/read-output-contracts.d.ts +1 -1
  630. package/dist/sdk/read-output-contracts.js +1 -1225
  631. package/dist/sdk/read-output-rows.js +1 -186
  632. package/dist/sdk/read-output-session.js +1 -208
  633. package/dist/sdk/relationship-analytics.js +1 -410
  634. package/dist/sdk/relationship-context.js +1 -284
  635. package/dist/sdk/relationship-history.js +4 -519
  636. package/dist/sdk/relationship-kinds/contract.js +1 -22
  637. package/dist/sdk/relationship-migration.js +1 -77
  638. package/dist/sdk/relationships.js +1 -579
  639. package/dist/sdk/reproducibility/process.js +1 -87
  640. package/dist/sdk/runtime-action-aliases.js +1 -59
  641. package/dist/sdk/runtime-extended-actions.js +1 -177
  642. package/dist/sdk/runtime-input.js +1 -614
  643. package/dist/sdk/runtime-primitives.js +1 -84
  644. package/dist/sdk/runtime-public-contracts.d.ts +2 -1
  645. package/dist/sdk/runtime-public-contracts.js +1 -4
  646. package/dist/sdk/runtime-stats-options.js +1 -38
  647. package/dist/sdk/runtime.d.ts +4 -0
  648. package/dist/sdk/runtime.js +1 -1928
  649. package/dist/sdk/scheduling-shortcuts.js +1 -63
  650. package/dist/sdk/schema-migration.js +3 -856
  651. package/dist/sdk/schema.d.ts +2 -1
  652. package/dist/sdk/schema.js +1 -1376
  653. package/dist/sdk/search-refresh-worker.js +1 -18
  654. package/dist/sdk/similarity-scoring.js +1 -53
  655. package/dist/sdk/similarity.js +1 -326
  656. package/dist/sdk/start-task-status.js +1 -14
  657. package/dist/sdk/stats.js +1 -270
  658. package/dist/sdk/structured-mutations.js +1 -580
  659. package/dist/sdk/telemetry-flush.js +1 -13
  660. package/dist/sdk/telemetry.js +1 -405
  661. package/dist/sdk/templates.js +2 -292
  662. package/dist/sdk/test/batch.js +2 -509
  663. package/dist/sdk/test/entry.js +1 -70
  664. package/dist/sdk/test/execution.js +6 -2211
  665. package/dist/sdk/test/linked-command-detection.js +1 -546
  666. package/dist/sdk/test/measurements.js +1 -91
  667. package/dist/sdk/test/parsers.js +1 -545
  668. package/dist/sdk/test/runs.js +1 -193
  669. package/dist/sdk/test/trust.js +2 -206
  670. package/dist/sdk/testing.js +4 -1391
  671. package/dist/sdk/traceability/runtime-files-lookup.js +1 -32
  672. package/dist/sdk/traceability/source-traceability.js +1 -292
  673. package/dist/sdk/tracker-root-discovery.js +1 -9
  674. package/dist/sdk/workspace-contracts-cache.js +1 -28
  675. package/dist/sdk/workspace-contracts.js +1 -33
  676. package/dist/sdk/workspace-memory.js +2 -318
  677. package/dist/sdk/workspace-recipe.js +1 -71
  678. package/dist/sdk/workspace-snapshot.js +4 -613
  679. package/dist/sdk/workspace-transaction-gc.js +1 -149
  680. package/dist/sdk/workspace-transaction.js +2 -363
  681. package/dist/sdk/workspace.js +3 -127
  682. package/dist/types/index.js +1 -9
  683. package/dist/types.d.ts +4 -0
  684. package/dist/types.js +1 -245
  685. package/docs/AGENT_GUIDE.md +1 -1
  686. package/docs/COMMANDS.md +10 -0
  687. package/docs/CONFIGURATION.md +12 -1
  688. package/docs/CONTEXT_ALGORITHM_PORTFOLIO.md +167 -0
  689. package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +9 -3
  690. package/docs/EXTENSIONS.md +1 -0
  691. package/docs/HISTORY_MAINTENANCE.md +125 -0
  692. package/docs/MCP_2026_07_28_CONFORMANCE.md +20 -10
  693. package/docs/PACKAGE_EVIDENCE.md +92 -0
  694. package/docs/PLANNING_MEASUREMENTS.md +183 -0
  695. package/docs/README.md +4 -0
  696. package/docs/READ_OUTPUT_CONTRACTS.md +5 -0
  697. package/docs/SCRIPTING.md +21 -0
  698. package/docs/TESTING.md +33 -0
  699. package/docs/WORKFLOW_POLICIES.md +129 -0
  700. package/docs/generated/FLAG_LEXICON_BUDGETS.md +7 -7
  701. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +11 -5
  702. package/marketplace.json +2 -2
  703. package/package.json +5 -5
  704. package/packages/pm-beads/package.json +1 -1
  705. package/packages/pm-calendar/package.json +1 -1
  706. package/packages/pm-command-kit/package.json +1 -1
  707. package/packages/pm-digital-twin/package.json +1 -1
  708. package/packages/pm-governance-audit/package.json +1 -1
  709. package/packages/pm-guide-shell/package.json +1 -1
  710. package/packages/pm-kanban/package.json +1 -1
  711. package/packages/pm-lifecycle-hooks/package.json +1 -1
  712. package/packages/pm-linked-test-adapters/package.json +1 -1
  713. package/packages/pm-search-advanced/package.json +1 -1
  714. package/packages/pm-templates/package.json +1 -1
  715. package/packages/pm-todos/package.json +1 -1
  716. package/packages/pm-vcs/package.json +1 -1
  717. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  718. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  719. package/scripts/finalize-build.mjs +45 -3
  720. package/dist/cli-bundle/chunks/chunk-AZDFJGH6.js +0 -9
  721. package/dist/cli-bundle/chunks/chunk-CKOL5U7J.js +0 -77
  722. package/dist/cli-bundle/chunks/chunk-JX4DH4WC.js +0 -3
  723. package/dist/cli-bundle/chunks/chunk-OF76PSDQ.js +0 -5
  724. package/dist/cli-bundle/chunks/chunk-QUWFABDM.js +0 -232
  725. package/dist/cli-bundle/chunks/chunk-QWRRFYK3.js +0 -2
  726. package/dist/cli-bundle/chunks/chunk-RWWBOWJ5.js +0 -2
  727. package/dist/cli-bundle/chunks/chunk-WGAOYSYH.js +0 -40
  728. package/dist/cli-bundle/chunks/chunk-WI2AYPA7.js +0 -2
  729. package/dist/cli-bundle/chunks/register-list-query-5JL52D33.js +0 -11
  730. package/dist/cli-bundle/chunks/register-mutation-ZPG7KMVP.js +0 -20
  731. package/dist/cli-bundle/chunks/register-operations-I5W3KMGB.js +0 -2
  732. package/dist/cli-bundle/chunks/register-setup-H4SVAVX7.js +0 -2
  733. package/dist/cli-bundle/focused-chunks/chunk-AL5ON6K6.js +0 -2
  734. package/dist/cli-bundle/focused-chunks/chunk-CHC2IDXA.js +0 -6
  735. package/dist/cli-bundle/focused-chunks/chunk-CK6QFAPZ.js +0 -20
  736. package/dist/cli-bundle/focused-chunks/chunk-EZR3GHFE.js +0 -2
  737. package/dist/cli-bundle/focused-chunks/chunk-H2WJWK7L.js +0 -56
  738. package/dist/cli-bundle/focused-chunks/chunk-NTPY5GSO.js +0 -3
  739. package/dist/cli-bundle/focused-chunks/chunk-P5O7MP5Y.js +0 -2
  740. package/dist/cli-bundle/focused-chunks/chunk-PDMW2E36.js +0 -177
  741. package/dist/cli-bundle/focused-chunks/chunk-PEFABF7E.js +0 -26
  742. package/dist/cli-bundle/focused-chunks/chunk-QTVCLMSZ.js +0 -6
  743. package/dist/cli-bundle/focused-chunks/chunk-QTZRBUYA.js +0 -8
  744. package/dist/cli-bundle/focused-chunks/chunk-SGQST3PQ.js +0 -12
  745. package/dist/cli-bundle/focused-chunks/chunk-UKHASMMP.js +0 -10
  746. package/dist/cli-bundle/focused-chunks/chunk-ZPEKQHOC.js +0 -2
@@ -1,1377 +1,2 @@
1
- /**
2
- * @module sdk/schema
3
- *
4
- * Owns typed schema customization primitives shared by SDK, CLI, and MCP consumers.
5
- */
6
-
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="264088a5-09d1-52ed-8b12-af00392e1a5f")}catch(e){}}();
8
- import { assertInitializedTracker } from "./environment/tracker-preflight.js";
9
- import path from "node:path";
10
- import { mkdir } from "node:fs/promises";
11
- import { resolveAuthor } from "../core/shared/author.js";
12
- import { pathExists, readFileIfExists } from "../core/fs/fs-utils.js";
13
- import { writeWorkspaceJsonWithHistory } from "../core/history/workspace-history.js";
14
- import { acquireLock } from "../core/lock/lock.js";
15
- import { refreshMergeAttributeFenceIfInstalled } from "./merge/install.js";
16
- import { assertAliasesAvailable, assertTypeFolderAvailable, buildInvalidTypeHint, escapeForDoubleQuotes, normalizeAddTypeInput, parseItemTypesFile, removeItemType, serializeItemTypesFile, upsertItemType, } from "../core/schema/item-types-file.js";
17
- import { assertStatusTokensAvailable, BUILTIN_STATUS_IDS, normalizeAddStatusInput, normalizeStatusToken, parseStatusDefsFile, removeStatusDef, serializeStatusDefsFile, upsertStatusDef, } from "../core/schema/status-defs-file.js";
18
- import { normalizeAddFieldInput, normalizeFieldKey, parseFieldsFile, removeField, serializeFieldsFile, upsertField, } from "../core/schema/fields-file.js";
19
- import { normalizeTypePresetName, resolveTypePresetDefinitions, TYPE_PRESET_NAMES, } from "../core/schema/type-presets.js";
20
- import { inferTypesFromTitles, } from "../core/schema/type-inference.js";
21
- import { DEFAULT_RUNTIME_SCHEMA_FILE_PATHS, filePathForSchemaSection, normalizeRuntimeSchemaSettings, resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, } from "../core/schema/runtime-schema.js";
22
- import { normalizeItemTypeFolder, resolveItemTypeRegistry, toDefaultFolder, } from "../core/item/type-registry.js";
23
- import { listAllItemMetadataLight } from "../core/store/item-store.js";
24
- import { EXIT_CODE } from "../core/shared/constants.js";
25
- import { PmCliError } from "../core/shared/errors.js";
26
- import { nowIso } from "../core/shared/time.js";
27
- import { getActiveExtensionRegistrations, runActiveOnWriteHooks, } from "../core/extensions/index.js";
28
- import { resolvePmRoot } from "../core/store/paths.js";
29
- import { readSettings, resolveGovernanceKnobs, } from "../core/store/settings.js";
30
- import { resolvePmToolCustomFieldCollision } from "./cli-contracts/tool-schema.js";
31
- /** Public contract for schema subcommands, shared by SDK and presentation-layer consumers. */
32
- export const SCHEMA_SUBCOMMANDS = [
33
- "add-type",
34
- "remove-type",
35
- "add-status",
36
- "remove-status",
37
- "add-field",
38
- "remove-field",
39
- "list-fields",
40
- "show-field",
41
- "apply-preset",
42
- "list",
43
- "show",
44
- "show-status",
45
- "rename-type",
46
- "rename-field",
47
- "remap-status",
48
- ];
49
- export { formatSchemaEvolutionMigrationHuman, planSchemaEvolutionMigration, runSchemaEvolutionMigration, } from "./schema-migration.js";
50
- const SCHEMA_TYPES_LOCK_ID = "schema-types";
51
- const SCHEMA_STATUSES_LOCK_ID = "schema-statuses";
52
- const SCHEMA_FIELDS_LOCK_ID = "schema-fields";
53
- function writeAuditedSchemaFile(params) {
54
- return writeWorkspaceJsonWithHistory({
55
- pmRoot: params.pmRoot,
56
- filePath: params.filePath,
57
- raw: params.raw,
58
- op: params.op,
59
- author: params.author,
60
- lockTtlSeconds: params.settings.locks.ttl_seconds,
61
- lockWaitMs: params.settings.locks.wait_ms,
62
- });
63
- }
64
- /* c8 ignore start -- schema command mutation/inspection branches are covered by broader schema integration workflows. */
65
- /** Implements run schema add type for the public runtime surface of this module. */
66
- export async function runSchemaAddType(name, options, global) {
67
- const pmRoot = resolvePmRoot(process.cwd(), global.path);
68
- await ensureInitialized(pmRoot);
69
- let normalized;
70
- try {
71
- normalized = normalizeAddTypeInput({
72
- name,
73
- description: options.description,
74
- defaultStatus: options.defaultStatus,
75
- folder: options.folder,
76
- aliases: options.alias,
77
- });
78
- }
79
- catch (error) {
80
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.USAGE);
81
- }
82
- const settings = await readSettings(pmRoot);
83
- const schema = normalizeRuntimeSchemaSettings(settings.schema);
84
- const typesPath = filePathForSchemaSection(pmRoot, schema.files.types, DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types);
85
- const warnings = [];
86
- const author = resolveAuthor(options.author, settings.author_default);
87
- const governance = resolveGovernanceKnobs(settings);
88
- const releaseLock = await acquireLock(pmRoot, SCHEMA_TYPES_LOCK_ID, settings.locks.ttl_seconds, author, Boolean(options.force), governance.force_required_for_stale_lock, settings.locks.wait_ms);
89
- let upsert;
90
- try {
91
- const previousRaw = await readFileIfExists(typesPath);
92
- let parsed;
93
- try {
94
- parsed = parseItemTypesFile(previousRaw);
95
- }
96
- catch (error) {
97
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.GENERIC_FAILURE);
98
- }
99
- try {
100
- assertAliasesAvailable(normalized, parsed);
101
- // GH-248: reject distinct type names that would slug to the same storage
102
- // folder (e.g. "Spike"/"Spikes") so item files never silently share a
103
- // directory. Same-named upserts (recase/idempotent re-runs) are exempt.
104
- // reservedFolders covers built-in + extension + settings-resolved custom
105
- // folders so a slug like "Tasks" can't collide with the built-in Task.
106
- const reservedFolders = new Map();
107
- const resolvedRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
108
- for (const [typeName, folder] of Object.entries(resolvedRegistry.type_to_folder)) {
109
- const folderKey = folder.trim().toLowerCase();
110
- if (folderKey.length > 0 && !reservedFolders.has(folderKey)) {
111
- reservedFolders.set(folderKey, typeName);
112
- }
113
- }
114
- assertTypeFolderAvailable(normalized, parsed, reservedFolders);
115
- }
116
- catch (error) {
117
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.USAGE);
118
- }
119
- upsert = upsertItemType(parsed, normalized);
120
- // GH-248: an upsert that only differs in case from the existing canonical
121
- // name silently renames the stored type (e.g. registering "spike" over
122
- // "Spike"). Surface it as a non-blocking warning so the operator knows the
123
- // existing definition was replaced rather than a new type created.
124
- if (upsert.replaced &&
125
- upsert.previousName !== undefined &&
126
- upsert.previousName !== upsert.definition.name) {
127
- warnings.push(`type_recased:${upsert.previousName}->${upsert.definition.name}`);
128
- }
129
- // writeFileAtomic writes to a temp file then renames, so a failure leaves the
130
- // existing types.json untouched; no manual rollback is needed.
131
- await writeAuditedSchemaFile({
132
- pmRoot,
133
- filePath: typesPath,
134
- raw: serializeItemTypesFile(upsert.file),
135
- op: "schema:add-type",
136
- author,
137
- settings,
138
- });
139
- await ensureTypeFolderScaffold(pmRoot, [upsert.definition], warnings, "schema:add-type-folder");
140
- warnings.push(...(await runActiveOnWriteHooks({
141
- path: typesPath,
142
- scope: "project",
143
- op: "schema:add-type",
144
- })));
145
- }
146
- finally {
147
- await releaseLock();
148
- }
149
- await appendMergeFenceWarnings(pmRoot, warnings);
150
- return {
151
- action: "add-type",
152
- registered: true,
153
- replaced: upsert.replaced,
154
- type: upsert.definition,
155
- file: {
156
- path: typesPath,
157
- definitions: upsert.file.definitions.length,
158
- },
159
- warnings: finalizeWarnings(warnings),
160
- generated_at: nowIso(),
161
- };
162
- }
163
- async function ensureInitialized(pmRoot) {
164
- await assertInitializedTracker(pmRoot);
165
- }
166
- /**
167
- * Reconcile the committed merge-driver fence with the type folders that exist
168
- * after a schema type mutation. When `pm merge install` already ran the fence
169
- * is rewritten in place (`merge_fence_refreshed`); when the repository has a
170
- * tracker inside git but never installed the fence, an actionable hint warning
171
- * is emitted instead — new type folders would otherwise merge under git's
172
- * default text driver and reintroduce whole-file item conflicts (pm-i4fx).
173
- */
174
- async function appendMergeFenceWarnings(pmRoot, warnings) {
175
- try {
176
- const fence = await refreshMergeAttributeFenceIfInstalled(pmRoot);
177
- if (fence.status === "refreshed") {
178
- warnings.push("merge_fence_refreshed");
179
- }
180
- else if (fence.status === "not_installed") {
181
- warnings.push('merge_fence_not_installed:type folders lack git merge drivers; run "pm merge install"');
182
- }
183
- }
184
- catch {
185
- warnings.push('merge_fence_refresh_failed:run "pm merge install" to reconcile');
186
- }
187
- }
188
- /** Deduplicates schema mutation warnings and returns their stable locale-aware order. */
189
- function finalizeWarnings(warnings) {
190
- return [...new Set(warnings)].sort((left, right) => left.localeCompare(right));
191
- }
192
- /** Counts items whose resolved type matches `typeName` (case-insensitive). Uses the lightest existing read path (listAllItemMetadataLight skips the heavy collections cache). All items are counted — not just open ones — so the advisory warning surfaces every item the removed definition would orphan; the count is non-blocking. The caller passes its already-loaded `settings` so we never re-read settings.json from disk here. */
193
- async function countItemsUsingType(pmRoot, settings, schema, typeName) {
194
- const registry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
195
- const lowerName = typeName.trim().toLowerCase();
196
- const items = await listAllItemMetadataLight(pmRoot, settings.item_format, registry.type_to_folder, [], schema);
197
- return items.filter((item) => typeof item.type === "string" && item.type.toLowerCase() === lowerName).length;
198
- }
199
- /** Counts items currently set to the status whose id/aliases resolve to `statusId`. Uses listAllItemMetadataLight (the lightest read path). All items are counted regardless of lifecycle phase; the count is advisory only. The caller passes its already-loaded `settings` so we never re-read from disk. */
200
- async function countItemsUsingStatus(pmRoot, settings, schema, statusId) {
201
- const registry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
202
- const statusRegistry = resolveRuntimeStatusRegistry(schema);
203
- const normalizedId = normalizeStatusToken(statusId);
204
- const items = await listAllItemMetadataLight(pmRoot, settings.item_format, registry.type_to_folder, [], schema);
205
- return items.filter((item) => {
206
- const itemStatus = typeof item.status === "string" ? item.status : "";
207
- const resolved = statusRegistry.alias_to_id.get(normalizeStatusToken(itemStatus)) ??
208
- normalizeStatusToken(itemStatus);
209
- return resolved === normalizedId;
210
- }).length;
211
- }
212
- /** Adds non-blocking usage and workflow diagnostics for a removed custom status. */
213
- async function appendRemovedStatusWarnings(warnings, pmRoot, settings, schema, removedId) {
214
- if (removedId.length === 0 || BUILTIN_STATUS_IDS.has(removedId)) {
215
- return;
216
- }
217
- const usingStatus = await countItemsUsingStatus(pmRoot, settings, schema, removedId);
218
- if (usingStatus > 0) {
219
- warnings.push(`items_using_status:${usingStatus}`);
220
- }
221
- const referencingSlots = workflowSlotsReferencing(schema.workflow, removedId);
222
- if (referencingSlots.length > 0) {
223
- warnings.push(`status_referenced_by_workflow:${referencingSlots.join(",")}`);
224
- }
225
- }
226
- /** Returns the workflow role-slot names (open_status, close_status, ...) that currently point at `statusId` (normalized). Used to warn before removing a status that a workflow default still references. */
227
- function workflowSlotsReferencing(workflow, statusId) {
228
- const slots = [
229
- ["draft_status", workflow.draft_status],
230
- ["open_status", workflow.open_status],
231
- ["in_progress_status", workflow.in_progress_status],
232
- ["blocked_status", workflow.blocked_status],
233
- ["close_status", workflow.close_status],
234
- ["canceled_status", workflow.canceled_status],
235
- ];
236
- return slots
237
- .filter(([, value]) => value !== undefined && normalizeStatusToken(value) === statusId)
238
- .map(([slot]) => slot);
239
- }
240
- /** Implements run schema remove type for the public runtime surface of this module. */
241
- export async function runSchemaRemoveType(name, options, global) {
242
- const pmRoot = resolvePmRoot(process.cwd(), global.path);
243
- await ensureInitialized(pmRoot);
244
- const settings = await readSettings(pmRoot);
245
- const schema = normalizeRuntimeSchemaSettings(settings.schema);
246
- const typesPath = filePathForSchemaSection(pmRoot, schema.files.types, DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types);
247
- const warnings = [];
248
- const author = resolveAuthor(options.author, settings.author_default);
249
- const governance = resolveGovernanceKnobs(settings);
250
- const releaseLock = await acquireLock(pmRoot, SCHEMA_TYPES_LOCK_ID, settings.locks.ttl_seconds, author, Boolean(options.force), governance.force_required_for_stale_lock, settings.locks.wait_ms);
251
- let removal;
252
- try {
253
- const previousRaw = await readFileIfExists(typesPath);
254
- let parsed;
255
- try {
256
- parsed = parseItemTypesFile(previousRaw);
257
- }
258
- catch (error) {
259
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.GENERIC_FAILURE);
260
- }
261
- try {
262
- removal = removeItemType(parsed, name);
263
- }
264
- catch (error) {
265
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.USAGE);
266
- }
267
- if (removal.removed) {
268
- // Only emit the advisory orphan-count warning once a removable custom
269
- // definition was actually removed; a no-op/unknown removal would otherwise
270
- // surface a misleading items_using_type:* warning. The count is
271
- // non-blocking and reuses the already-loaded settings (no disk re-read).
272
- const removedName = (removal.definition?.name ?? name ?? "").trim();
273
- if (removedName.length > 0) {
274
- const usingType = await countItemsUsingType(pmRoot, settings, schema, removedName);
275
- if (usingType > 0) {
276
- warnings.push(`items_using_type:${usingType}`);
277
- }
278
- }
279
- // writeFileAtomic writes to a temp file then renames, so a failure leaves
280
- // the existing types.json untouched; no manual rollback is needed.
281
- await writeAuditedSchemaFile({
282
- pmRoot,
283
- filePath: typesPath,
284
- raw: serializeItemTypesFile(removal.file),
285
- op: "schema:remove-type",
286
- author,
287
- settings,
288
- });
289
- warnings.push(...(await runActiveOnWriteHooks({
290
- path: typesPath,
291
- scope: "project",
292
- op: "schema:remove-type",
293
- })));
294
- }
295
- }
296
- finally {
297
- await releaseLock();
298
- }
299
- if (removal.removed) {
300
- await appendMergeFenceWarnings(pmRoot, warnings);
301
- }
302
- return {
303
- action: "remove-type",
304
- removed: removal.removed,
305
- ...(removal.definition ? { type: removal.definition } : {}),
306
- file: {
307
- path: typesPath,
308
- definitions: removal.file.definitions.length,
309
- },
310
- warnings: finalizeWarnings(warnings),
311
- generated_at: nowIso(),
312
- };
313
- }
314
- function statusesPathFor(pmRoot, schema) {
315
- return filePathForSchemaSection(pmRoot, schema.files.statuses, DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.statuses);
316
- }
317
- function fieldsPathFor(pmRoot, schema) {
318
- return filePathForSchemaSection(pmRoot, schema.files.fields, DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.fields);
319
- }
320
- function typesPathFor(pmRoot, schema) {
321
- return filePathForSchemaSection(pmRoot, schema.files.types, DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types);
322
- }
323
- /** Creates the storage folder for each item-type definition (resolving the default folder when unset) and runs on-write hooks for newly created folders. Shared with `pm profile apply` so profile-staged types scaffold identically to `pm schema add-type`. Existing folders are skipped, keeping the call idempotent. */
324
- export async function ensureTypeFolderScaffold(pmRoot, definitions, warnings, op) {
325
- for (const definition of definitions) {
326
- const folder = normalizeItemTypeFolder(definition.folder ?? toDefaultFolder(definition.name));
327
- const target = path.join(pmRoot, folder);
328
- if (await pathExists(target)) {
329
- continue;
330
- }
331
- await mkdir(target, { recursive: true });
332
- warnings.push(...(await runActiveOnWriteHooks({
333
- path: target,
334
- scope: "project",
335
- op,
336
- })));
337
- }
338
- }
339
- function toSchemaFieldSummary(field) {
340
- return {
341
- key: field.key,
342
- type: field.type,
343
- commands: [...field.commands],
344
- cli_flag: `--${field.cli_flag}`,
345
- cli_aliases: field.cli_aliases.map((alias) => `--${alias}`),
346
- ...(field.description ? { description: field.description } : {}),
347
- required: field.required,
348
- required_on_create: field.required_on_create,
349
- allow_unset: field.allow_unset,
350
- required_types: [...field.required_types],
351
- };
352
- }
353
- function toExistingStatusDefinition(resolvedExisting) {
354
- if (!resolvedExisting) {
355
- return undefined;
356
- }
357
- return {
358
- id: resolvedExisting.id,
359
- ...(resolvedExisting.roles.length > 0
360
- ? { roles: [...resolvedExisting.roles] }
361
- : {}),
362
- ...(resolvedExisting.aliases.length > 0
363
- ? { aliases: [...resolvedExisting.aliases] }
364
- : {}),
365
- ...(resolvedExisting.description
366
- ? { description: resolvedExisting.description }
367
- : {}),
368
- ...(typeof resolvedExisting.order === "number"
369
- ? { order: resolvedExisting.order }
370
- : {}),
371
- };
372
- }
373
- function buildStatusFileAliasMap(statuses) {
374
- const fileAliasToId = new Map();
375
- for (const definition of statuses) {
376
- const defId = normalizeStatusToken(definition.id);
377
- if (defId.length === 0) {
378
- continue;
379
- }
380
- fileAliasToId.set(defId, defId);
381
- for (const alias of Array.isArray(definition.aliases)
382
- ? definition.aliases
383
- : []) {
384
- const aliasToken = normalizeStatusToken(alias);
385
- if (aliasToken.length > 0 && !fileAliasToId.has(aliasToken)) {
386
- fileAliasToId.set(aliasToken, defId);
387
- }
388
- }
389
- }
390
- return fileAliasToId;
391
- }
392
- /** Implements run schema add status for the public runtime surface of this module. */
393
- export async function runSchemaAddStatus(id, options, global) {
394
- const pmRoot = resolvePmRoot(process.cwd(), global.path);
395
- await ensureInitialized(pmRoot);
396
- let normalized;
397
- try {
398
- normalized = normalizeAddStatusInput({
399
- id,
400
- roles: options.role,
401
- aliases: options.alias,
402
- description: options.description,
403
- order: options.order,
404
- });
405
- }
406
- catch (error) {
407
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.USAGE);
408
- }
409
- const settings = await readSettings(pmRoot);
410
- const schema = normalizeRuntimeSchemaSettings(settings.schema);
411
- const statusesPath = statusesPathFor(pmRoot, schema);
412
- const statusRegistry = resolveRuntimeStatusRegistry(schema);
413
- // Reject id/alias collisions with a DIFFERENT existing status so a custom
414
- // status can never shadow a built-in lifecycle token (e.g. --alias open).
415
- try {
416
- assertStatusTokensAvailable(normalized, statusRegistry.alias_to_id);
417
- }
418
- catch (error) {
419
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.USAGE);
420
- }
421
- // Seed the upsert from the resolved (settings-or-file) definition so omitting
422
- // --role/--alias preserves metadata defined in settings.schema.statuses, not
423
- // only what is already in statuses.json.
424
- const baseDefinition = toExistingStatusDefinition(statusRegistry.by_id.get(normalized.id));
425
- const effectiveRoles = normalized.roles ?? baseDefinition?.roles ?? [];
426
- if (effectiveRoles.length === 0) {
427
- throw new PmCliError(`Status "${normalized.id}" requires at least one lifecycle role. Re-run with --role active, --role blocked, --role draft, or an appropriate terminal/default role.`, EXIT_CODE.USAGE, {
428
- code: "status_lifecycle_role_required",
429
- examples: [
430
- `pm schema add-status "${escapeForDoubleQuotes(normalized.id)}" --role active`,
431
- `pm schema add-status "${escapeForDoubleQuotes(normalized.id)}" --role blocked`,
432
- ],
433
- });
434
- }
435
- const warnings = [];
436
- const author = resolveAuthor(options.author, settings.author_default);
437
- const governance = resolveGovernanceKnobs(settings);
438
- const releaseLock = await acquireLock(pmRoot, SCHEMA_STATUSES_LOCK_ID, settings.locks.ttl_seconds, author, Boolean(options.force), governance.force_required_for_stale_lock, settings.locks.wait_ms);
439
- let upsert;
440
- try {
441
- const previousRaw = await readFileIfExists(statusesPath);
442
- let parsed;
443
- try {
444
- parsed = parseStatusDefsFile(previousRaw);
445
- }
446
- catch (error) {
447
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.GENERIC_FAILURE);
448
- }
449
- // Re-check collisions against the CURRENT file under the lock: the pre-lock
450
- // check used the registry loaded before acquiring schema-statuses, so a
451
- // concurrent add-status could have written a colliding id/alias in between.
452
- // The lock serializes writes; this serializes the collision decision too.
453
- const fileAliasToId = buildStatusFileAliasMap(parsed.statuses);
454
- try {
455
- assertStatusTokensAvailable(normalized, fileAliasToId);
456
- }
457
- catch (error) {
458
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.USAGE);
459
- }
460
- upsert = upsertStatusDef(parsed, normalized, baseDefinition);
461
- // writeFileAtomic writes to a temp file then renames, so a failure leaves
462
- // the existing statuses.json untouched; no manual rollback is needed.
463
- await writeAuditedSchemaFile({
464
- pmRoot,
465
- filePath: statusesPath,
466
- raw: serializeStatusDefsFile(upsert.file),
467
- op: "schema:add-status",
468
- author,
469
- settings,
470
- });
471
- warnings.push(...(await runActiveOnWriteHooks({
472
- path: statusesPath,
473
- scope: "project",
474
- op: "schema:add-status",
475
- })));
476
- }
477
- finally {
478
- await releaseLock();
479
- }
480
- return {
481
- action: "add-status",
482
- registered: true,
483
- replaced: upsert.replaced,
484
- status: upsert.definition,
485
- file: {
486
- path: statusesPath,
487
- statuses: upsert.file.statuses.length,
488
- },
489
- warnings: finalizeWarnings(warnings),
490
- generated_at: nowIso(),
491
- };
492
- }
493
- /** Implements run schema remove status for the public runtime surface of this module. */
494
- export async function runSchemaRemoveStatus(id, options, global) {
495
- const pmRoot = resolvePmRoot(process.cwd(), global.path);
496
- await ensureInitialized(pmRoot);
497
- const settings = await readSettings(pmRoot);
498
- const schema = normalizeRuntimeSchemaSettings(settings.schema);
499
- const statusesPath = statusesPathFor(pmRoot, schema);
500
- const warnings = [];
501
- const author = resolveAuthor(options.author, settings.author_default);
502
- const governance = resolveGovernanceKnobs(settings);
503
- const releaseLock = await acquireLock(pmRoot, SCHEMA_STATUSES_LOCK_ID, settings.locks.ttl_seconds, author, Boolean(options.force), governance.force_required_for_stale_lock, settings.locks.wait_ms);
504
- let removal;
505
- try {
506
- const previousRaw = await readFileIfExists(statusesPath);
507
- let parsed;
508
- try {
509
- parsed = parseStatusDefsFile(previousRaw);
510
- }
511
- catch (error) {
512
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.GENERIC_FAILURE);
513
- }
514
- try {
515
- removal = removeStatusDef(parsed, id);
516
- }
517
- catch (error) {
518
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.USAGE);
519
- }
520
- if (removal.removed) {
521
- // Only emit the advisory orphan-count warning once a removable custom
522
- // status was actually removed; a no-op/unknown removal would otherwise
523
- // surface a misleading items_using_status:* warning. The count reuses the
524
- // already-loaded settings (no disk re-read) and is non-blocking.
525
- const removedId = normalizeStatusToken(removal.definition?.id ?? id);
526
- // Removing a status that a workflow default still points at would leave
527
- // pm close / default pm create resolving to an unregistered status. Warn
528
- // (non-blocking, consistent with remove-type) so the operator re-points
529
- // the workflow slot via schema/workflows.json or pm config.
530
- await appendRemovedStatusWarnings(warnings, pmRoot, settings, schema, removedId);
531
- await writeAuditedSchemaFile({
532
- pmRoot,
533
- filePath: statusesPath,
534
- raw: serializeStatusDefsFile(removal.file),
535
- op: "schema:remove-status",
536
- author,
537
- settings,
538
- });
539
- warnings.push(...(await runActiveOnWriteHooks({
540
- path: statusesPath,
541
- scope: "project",
542
- op: "schema:remove-status",
543
- })));
544
- }
545
- }
546
- finally {
547
- await releaseLock();
548
- }
549
- return {
550
- action: "remove-status",
551
- removed: removal.removed,
552
- ...(removal.definition ? { status: removal.definition } : {}),
553
- file: {
554
- path: statusesPath,
555
- statuses: removal.file.statuses.length,
556
- },
557
- warnings: finalizeWarnings(warnings),
558
- generated_at: nowIso(),
559
- };
560
- }
561
- function toSchemaTypeSummary(definition) {
562
- return {
563
- name: definition.name,
564
- folder: definition.folder,
565
- aliases: Array.isArray(definition.aliases) ? [...definition.aliases] : [],
566
- ...(definition.default_status
567
- ? { default_status: definition.default_status }
568
- : {}),
569
- ...(definition.description ? { description: definition.description } : {}),
570
- };
571
- }
572
- function toSchemaTypeDefinition(definition, source, extensionProvenance) {
573
- return {
574
- ...toSchemaTypeSummary(definition),
575
- source,
576
- ...(extensionProvenance ? { extension: extensionProvenance } : {}),
577
- required_create_fields: [...definition.required_create_fields],
578
- required_create_repeatables: [...definition.required_create_repeatables],
579
- options: structuredClone(definition.options),
580
- command_option_policies: structuredClone(definition.command_option_policies),
581
- };
582
- }
583
- function toSchemaStatusSummary(definition) {
584
- return {
585
- id: definition.id,
586
- source: BUILTIN_STATUS_IDS.has(definition.id) ? "builtin" : "custom",
587
- roles: Array.isArray(definition.roles) ? [...definition.roles] : [],
588
- aliases: Array.isArray(definition.aliases) ? [...definition.aliases] : [],
589
- ...(definition.description ? { description: definition.description } : {}),
590
- ...(typeof definition.order === "number"
591
- ? { order: definition.order }
592
- : {}),
593
- };
594
- }
595
- function classifyTypeSource(name, customNames, extensionNames) {
596
- const lowerName = name.toLowerCase();
597
- if (extensionNames.has(lowerName)) {
598
- return "extension";
599
- }
600
- if (customNames.has(lowerName)) {
601
- return "custom";
602
- }
603
- return "builtin";
604
- }
605
- function collectExtensionTypeProvenance() {
606
- const provenance = new Map();
607
- const registrations = getActiveExtensionRegistrations();
608
- for (const registration of registrations?.item_types ?? []) {
609
- const rawTypes = registration.types;
610
- if (!Array.isArray(rawTypes)) {
611
- continue;
612
- }
613
- for (const rawType of rawTypes) {
614
- if (typeof rawType !== "object" ||
615
- rawType === null ||
616
- Array.isArray(rawType)) {
617
- continue;
618
- }
619
- const name = rawType.name;
620
- if (typeof name === "string" && name.trim().length > 0) {
621
- provenance.set(name.trim().toLowerCase(), {
622
- layer: registration.layer,
623
- name: registration.name,
624
- });
625
- }
626
- }
627
- }
628
- return provenance;
629
- }
630
- function buildSchemaStatusSummaries(schema) {
631
- const registry = resolveRuntimeStatusRegistry(schema);
632
- const builtin = [];
633
- const custom = [];
634
- for (const definition of registry.definitions) {
635
- const summary = toSchemaStatusSummary(definition);
636
- if (summary.source === "builtin") {
637
- builtin.push(summary);
638
- }
639
- else {
640
- custom.push(summary);
641
- }
642
- }
643
- return { builtin, custom };
644
- }
645
- async function loadSchemaInspectionContext(global) {
646
- const pmRoot = resolvePmRoot(process.cwd(), global.path);
647
- await ensureInitialized(pmRoot);
648
- const settings = await readSettings(pmRoot);
649
- const schema = normalizeRuntimeSchemaSettings(settings.schema);
650
- const typesPath = filePathForSchemaSection(pmRoot, schema.files.types, DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types);
651
- const statusesPath = statusesPathFor(pmRoot, schema);
652
- const registry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
653
- const extensionProvenance = collectExtensionTypeProvenance();
654
- const customNames = new Set((settings.item_types?.definitions ?? [])
655
- .map((definition) => definition.name.trim().toLowerCase())
656
- .filter((name) => name.length > 0 && !extensionProvenance.has(name)));
657
- return {
658
- pmRoot,
659
- typesPath,
660
- statusesPath,
661
- byType: registry.by_type,
662
- customNames,
663
- extensionProvenance,
664
- schema,
665
- };
666
- }
667
- /** Implements run schema list for the public runtime surface of this module. */
668
- export async function runSchemaList(global) {
669
- const context = await loadSchemaInspectionContext(global);
670
- const builtin = [];
671
- const custom = [];
672
- const extension = [];
673
- for (const definition of Object.values(context.byType).sort((left, right) => left.name.localeCompare(right.name))) {
674
- const source = classifyTypeSource(definition.name, context.customNames, new Set(context.extensionProvenance.keys()));
675
- const summary = toSchemaTypeSummary(definition);
676
- if (source === "extension") {
677
- extension.push(summary);
678
- }
679
- else if (source === "custom") {
680
- custom.push(summary);
681
- }
682
- else {
683
- builtin.push(summary);
684
- }
685
- }
686
- const statusSummaries = buildSchemaStatusSummaries(context.schema);
687
- const fieldSummaries = resolveRuntimeFieldRegistry(context.schema).definitions.map(toSchemaFieldSummary);
688
- return {
689
- action: "list",
690
- builtin,
691
- custom,
692
- extension,
693
- counts: {
694
- builtin: builtin.length,
695
- custom: custom.length,
696
- extension: extension.length,
697
- total: builtin.length + custom.length + extension.length,
698
- },
699
- statuses: {
700
- builtin: statusSummaries.builtin,
701
- custom: statusSummaries.custom,
702
- counts: {
703
- builtin: statusSummaries.builtin.length,
704
- custom: statusSummaries.custom.length,
705
- total: statusSummaries.builtin.length + statusSummaries.custom.length,
706
- },
707
- },
708
- fields: {
709
- custom: fieldSummaries,
710
- counts: {
711
- total: fieldSummaries.length,
712
- },
713
- },
714
- file: {
715
- path: context.typesPath,
716
- },
717
- generated_at: nowIso(),
718
- };
719
- }
720
- /** Implements run schema show for the public runtime surface of this module. */
721
- export async function runSchemaShow(name, global) {
722
- const typeName = (name ?? "").trim();
723
- if (typeName.length === 0) {
724
- throw new PmCliError("Type name must not be empty.", EXIT_CODE.USAGE);
725
- }
726
- const context = await loadSchemaInspectionContext(global);
727
- const match = Object.values(context.byType).find((definition) => definition.name.toLowerCase() === typeName.toLowerCase() ||
728
- definition.aliases.some((alias) => alias.toLowerCase() === typeName.toLowerCase()));
729
- if (!match) {
730
- throw new PmCliError(`Unknown item type "${typeName}". Run pm schema list to inspect registered types, or pm schema add-type "${escapeForDoubleQuotes(typeName)}" to register it.`, EXIT_CODE.NOT_FOUND, { code: "unknown_item_type" });
731
- }
732
- return {
733
- action: "show",
734
- type: toSchemaTypeDefinition(match, classifyTypeSource(match.name, context.customNames, new Set(context.extensionProvenance.keys())), context.extensionProvenance.get(match.name.toLowerCase())),
735
- file: {
736
- path: context.typesPath,
737
- },
738
- generated_at: nowIso(),
739
- };
740
- }
741
- /** Implements run schema show status for the public runtime surface of this module. */
742
- export async function runSchemaShowStatus(id, global) {
743
- const statusToken = normalizeStatusToken(id);
744
- if (statusToken.length === 0) {
745
- throw new PmCliError("Status id must not be empty.", EXIT_CODE.USAGE);
746
- }
747
- const context = await loadSchemaInspectionContext(global);
748
- const statusRegistry = resolveRuntimeStatusRegistry(context.schema);
749
- const resolvedId = statusRegistry.alias_to_id.get(statusToken) ?? statusToken;
750
- const match = statusRegistry.by_id.get(resolvedId);
751
- if (!match) {
752
- throw new PmCliError(`Unknown status "${id}". Run pm schema list to inspect registered statuses, or pm schema add-status "${escapeForDoubleQuotes(id ?? "")}" to register it.`, EXIT_CODE.NOT_FOUND, { code: "unknown_status" });
753
- }
754
- return {
755
- action: "show-status",
756
- status: toSchemaStatusSummary(match),
757
- file: {
758
- path: context.statusesPath,
759
- },
760
- generated_at: nowIso(),
761
- };
762
- }
763
- /** Implements run schema add field for the public runtime surface of this module. */
764
- export async function runSchemaAddField(key, options, global) {
765
- const pmRoot = resolvePmRoot(process.cwd(), global.path);
766
- await ensureInitialized(pmRoot);
767
- let normalized;
768
- try {
769
- normalized = normalizeAddFieldInput({
770
- key,
771
- type: options.type,
772
- commands: options.commands,
773
- description: options.description,
774
- cliFlag: options.cliFlag,
775
- aliases: options.alias,
776
- required: options.required,
777
- requiredOnCreate: options.requiredOnCreate,
778
- allowUnset: options.allowUnset,
779
- requiredTypes: options.requiredTypes,
780
- });
781
- }
782
- catch (error) {
783
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.USAGE);
784
- }
785
- const settings = await readSettings(pmRoot);
786
- const schema = normalizeRuntimeSchemaSettings(settings.schema);
787
- const fieldsPath = fieldsPathFor(pmRoot, schema);
788
- const warnings = [];
789
- const mcpCollision = resolvePmToolCustomFieldCollision(normalized.key);
790
- if (mcpCollision) {
791
- warnings.push(`custom_field_mcp_input_collision:${mcpCollision.field}:${mcpCollision.property}:${mcpCollision.owner}:use=${mcpCollision.nested_path}`);
792
- }
793
- const author = resolveAuthor(options.author, settings.author_default);
794
- const governance = resolveGovernanceKnobs(settings);
795
- const releaseLock = await acquireLock(pmRoot, SCHEMA_FIELDS_LOCK_ID, settings.locks.ttl_seconds, author, Boolean(options.force), governance.force_required_for_stale_lock, settings.locks.wait_ms);
796
- let upsert;
797
- try {
798
- const previousRaw = await readFileIfExists(fieldsPath);
799
- let parsed;
800
- try {
801
- parsed = parseFieldsFile(previousRaw);
802
- }
803
- catch (error) {
804
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.GENERIC_FAILURE);
805
- }
806
- upsert = upsertField(parsed, normalized);
807
- await writeAuditedSchemaFile({
808
- pmRoot,
809
- filePath: fieldsPath,
810
- raw: serializeFieldsFile(upsert.file),
811
- op: "schema:add-field",
812
- author,
813
- settings,
814
- });
815
- warnings.push(...(await runActiveOnWriteHooks({
816
- path: fieldsPath,
817
- scope: "project",
818
- op: "schema:add-field",
819
- })));
820
- }
821
- finally {
822
- await releaseLock();
823
- }
824
- return {
825
- action: "add-field",
826
- registered: true,
827
- replaced: upsert.replaced,
828
- field: upsert.definition,
829
- file: {
830
- path: fieldsPath,
831
- fields: upsert.file.fields.length,
832
- },
833
- warnings: finalizeWarnings(warnings),
834
- generated_at: nowIso(),
835
- };
836
- }
837
- /** Counts items carrying a non-empty value for the custom field's metadata key. Advisory only (non-blocking) so remove-field can surface how many items would lose a managed column. Reuses the already-loaded settings (no disk re-read). */
838
- async function countItemsUsingField(pmRoot, settings, schema, metadataKey) {
839
- const registry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
840
- const items = await listAllItemMetadataLight(pmRoot, settings.item_format, registry.type_to_folder, [], schema);
841
- return items.filter((item) => {
842
- const value = item[metadataKey];
843
- if (value === undefined || value === null) {
844
- return false;
845
- }
846
- if (Array.isArray(value)) {
847
- return value.length > 0;
848
- }
849
- if (typeof value === "string") {
850
- return value.trim().length > 0;
851
- }
852
- return true;
853
- }).length;
854
- }
855
- /** Implements run schema remove field for the public runtime surface of this module. */
856
- export async function runSchemaRemoveField(key, options, global) {
857
- const pmRoot = resolvePmRoot(process.cwd(), global.path);
858
- await ensureInitialized(pmRoot);
859
- const settings = await readSettings(pmRoot);
860
- const schema = normalizeRuntimeSchemaSettings(settings.schema);
861
- const fieldsPath = fieldsPathFor(pmRoot, schema);
862
- const warnings = [];
863
- const author = resolveAuthor(options.author, settings.author_default);
864
- const governance = resolveGovernanceKnobs(settings);
865
- const releaseLock = await acquireLock(pmRoot, SCHEMA_FIELDS_LOCK_ID, settings.locks.ttl_seconds, author, Boolean(options.force), governance.force_required_for_stale_lock, settings.locks.wait_ms);
866
- let removal;
867
- try {
868
- const previousRaw = await readFileIfExists(fieldsPath);
869
- let parsed;
870
- try {
871
- parsed = parseFieldsFile(previousRaw);
872
- }
873
- catch (error) {
874
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.GENERIC_FAILURE);
875
- }
876
- try {
877
- removal = removeField(parsed, key);
878
- }
879
- catch (error) {
880
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.USAGE);
881
- }
882
- if (removal.removed) {
883
- const removedKey = normalizeFieldKey(removal.definition?.key ?? key);
884
- const metadataKey = normalizeFieldKey(removal.definition?.metadata_key ??
885
- removal.definition?.front_matter_key ??
886
- removedKey);
887
- if (metadataKey.length > 0) {
888
- const usingField = await countItemsUsingField(pmRoot, settings, schema, metadataKey);
889
- if (usingField > 0) {
890
- warnings.push(`items_using_field:${usingField}`);
891
- }
892
- }
893
- await writeAuditedSchemaFile({
894
- pmRoot,
895
- filePath: fieldsPath,
896
- raw: serializeFieldsFile(removal.file),
897
- op: "schema:remove-field",
898
- author,
899
- settings,
900
- });
901
- warnings.push(...(await runActiveOnWriteHooks({
902
- path: fieldsPath,
903
- scope: "project",
904
- op: "schema:remove-field",
905
- })));
906
- }
907
- }
908
- finally {
909
- await releaseLock();
910
- }
911
- return {
912
- action: "remove-field",
913
- removed: removal.removed,
914
- ...(removal.definition ? { field: removal.definition } : {}),
915
- file: {
916
- path: fieldsPath,
917
- fields: removal.file.fields.length,
918
- },
919
- warnings: finalizeWarnings(warnings),
920
- generated_at: nowIso(),
921
- };
922
- }
923
- /** Implements run schema list fields for the public runtime surface of this module. */
924
- export async function runSchemaListFields(global) {
925
- const context = await loadSchemaInspectionContext(global);
926
- const fields = resolveRuntimeFieldRegistry(context.schema).definitions.map(toSchemaFieldSummary);
927
- return {
928
- action: "list-fields",
929
- fields,
930
- counts: {
931
- total: fields.length,
932
- },
933
- file: {
934
- path: fieldsPathFor(context.pmRoot, context.schema),
935
- },
936
- generated_at: nowIso(),
937
- };
938
- }
939
- /** Implements run schema show field for the public runtime surface of this module. */
940
- export async function runSchemaShowField(key, global) {
941
- const fieldKey = normalizeFieldKey(key);
942
- if (fieldKey.length === 0) {
943
- throw new PmCliError("Field key must not be empty.", EXIT_CODE.USAGE);
944
- }
945
- const context = await loadSchemaInspectionContext(global);
946
- const match = resolveRuntimeFieldRegistry(context.schema).by_key.get(fieldKey);
947
- if (!match) {
948
- throw new PmCliError(`Unknown custom field "${key}". Run pm schema list-fields to inspect registered fields, or pm schema add-field "${escapeForDoubleQuotes(key ?? "")}" to register it.`, EXIT_CODE.NOT_FOUND, { code: "unknown_field" });
949
- }
950
- return {
951
- action: "show-field",
952
- field: toSchemaFieldSummary(match),
953
- file: {
954
- path: fieldsPathFor(context.pmRoot, context.schema),
955
- },
956
- generated_at: nowIso(),
957
- };
958
- }
959
- /** Implements run schema apply preset for the public runtime surface of this module. */
960
- export async function runSchemaApplyPreset(preset, options, global) {
961
- const pmRoot = resolvePmRoot(process.cwd(), global.path);
962
- await ensureInitialized(pmRoot);
963
- let presetName;
964
- try {
965
- const normalized = normalizeTypePresetName(preset);
966
- if (normalized === undefined) {
967
- throw new Error(`Type preset name is required. Allowed: ${TYPE_PRESET_NAMES.join(", ")}.`);
968
- }
969
- presetName = normalized;
970
- }
971
- catch (error) {
972
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.USAGE);
973
- }
974
- const settings = await readSettings(pmRoot);
975
- const schema = normalizeRuntimeSchemaSettings(settings.schema);
976
- const typesPath = typesPathFor(pmRoot, schema);
977
- const warnings = [];
978
- const author = resolveAuthor(options.author, settings.author_default);
979
- const governance = resolveGovernanceKnobs(settings);
980
- const registered = [];
981
- const replaced = [];
982
- let definitionsCount;
983
- const releaseLock = await acquireLock(pmRoot, SCHEMA_TYPES_LOCK_ID, settings.locks.ttl_seconds, author, Boolean(options.force), governance.force_required_for_stale_lock, settings.locks.wait_ms);
984
- try {
985
- const previousRaw = await readFileIfExists(typesPath);
986
- let parsed;
987
- try {
988
- parsed = parseItemTypesFile(previousRaw);
989
- }
990
- catch (error) {
991
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.GENERIC_FAILURE);
992
- }
993
- let nextFile = parsed;
994
- for (const normalized of resolveTypePresetDefinitions(presetName)) {
995
- const upsert = upsertItemType(nextFile, normalized);
996
- nextFile = upsert.file;
997
- (upsert.replaced ? replaced : registered).push(upsert.definition.name);
998
- }
999
- definitionsCount = nextFile.definitions.length;
1000
- await writeAuditedSchemaFile({
1001
- pmRoot,
1002
- filePath: typesPath,
1003
- raw: serializeItemTypesFile(nextFile),
1004
- op: "schema:apply-preset",
1005
- author,
1006
- settings,
1007
- });
1008
- await ensureTypeFolderScaffold(pmRoot, resolveTypePresetDefinitions(presetName), warnings, "schema:apply-preset-folder");
1009
- warnings.push(...(await runActiveOnWriteHooks({
1010
- path: typesPath,
1011
- scope: "project",
1012
- op: "schema:apply-preset",
1013
- })));
1014
- }
1015
- finally {
1016
- await releaseLock();
1017
- }
1018
- return {
1019
- action: "apply-preset",
1020
- preset: presetName,
1021
- registered,
1022
- replaced,
1023
- file: {
1024
- path: typesPath,
1025
- definitions: definitionsCount,
1026
- },
1027
- warnings: finalizeWarnings(warnings),
1028
- generated_at: nowIso(),
1029
- };
1030
- }
1031
- /** Validates the positive inference threshold while preserving the command default. */
1032
- function resolveSchemaInferenceMinCount(value) {
1033
- if (value === undefined) {
1034
- return 10;
1035
- }
1036
- if (!Number.isInteger(value) || value < 1) {
1037
- throw new PmCliError("--min-count must be a positive integer (>= 1).", EXIT_CODE.USAGE);
1038
- }
1039
- return value;
1040
- }
1041
- /** Implements run schema infer types for the public runtime surface of this module. */
1042
- export async function runSchemaInferTypes(options, global) {
1043
- const pmRoot = resolvePmRoot(process.cwd(), global.path);
1044
- await ensureInitialized(pmRoot);
1045
- const settings = await readSettings(pmRoot);
1046
- const schema = normalizeRuntimeSchemaSettings(settings.schema);
1047
- const typesPath = typesPathFor(pmRoot, schema);
1048
- const minCount = resolveSchemaInferenceMinCount(options.minCount);
1049
- const registry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
1050
- const items = await listAllItemMetadataLight(pmRoot, settings.item_format, registry.type_to_folder, [], schema);
1051
- const titles = items.map((item) => typeof item.title === "string" ? item.title : "");
1052
- const candidates = inferTypesFromTitles(titles, { minCount });
1053
- const warnings = [];
1054
- const registered = [];
1055
- const replaced = [];
1056
- const skipped = [];
1057
- let definitionsCount;
1058
- // Dry-run preview by default: only --apply mutates schema/types.json.
1059
- if (!options.apply) {
1060
- let parsed;
1061
- try {
1062
- parsed = parseItemTypesFile(await readFileIfExists(typesPath));
1063
- }
1064
- catch (error) {
1065
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.GENERIC_FAILURE);
1066
- }
1067
- definitionsCount = parsed.definitions.length;
1068
- return {
1069
- action: "infer-types",
1070
- applied: false,
1071
- min_count: minCount,
1072
- candidates,
1073
- registered,
1074
- replaced,
1075
- skipped,
1076
- file: {
1077
- path: typesPath,
1078
- definitions: definitionsCount,
1079
- },
1080
- warnings,
1081
- generated_at: nowIso(),
1082
- };
1083
- }
1084
- const author = resolveAuthor(options.author, settings.author_default);
1085
- const governance = resolveGovernanceKnobs(settings);
1086
- const releaseLock = await acquireLock(pmRoot, SCHEMA_TYPES_LOCK_ID, settings.locks.ttl_seconds, author, Boolean(options.force), governance.force_required_for_stale_lock, settings.locks.wait_ms);
1087
- try {
1088
- const previousRaw = await readFileIfExists(typesPath);
1089
- let parsed;
1090
- try {
1091
- parsed = parseItemTypesFile(previousRaw);
1092
- }
1093
- catch (error) {
1094
- throw new PmCliError(error instanceof Error ? error.message : String(error), EXIT_CODE.GENERIC_FAILURE);
1095
- }
1096
- let nextFile = parsed;
1097
- for (const candidate of candidates) {
1098
- if (candidate.shadows_builtin) {
1099
- skipped.push({ name: candidate.name, reason: "shadows_builtin" });
1100
- continue;
1101
- }
1102
- let normalized;
1103
- try {
1104
- normalized = normalizeAddTypeInput({ name: candidate.name });
1105
- }
1106
- catch {
1107
- // A title prefix that does not normalize to a valid type token (rare,
1108
- // given the inference pattern) is skipped rather than aborting the batch.
1109
- skipped.push({ name: candidate.name, reason: "invalid_type_token" });
1110
- continue;
1111
- }
1112
- const upsert = upsertItemType(nextFile, normalized);
1113
- nextFile = upsert.file;
1114
- (upsert.replaced ? replaced : registered).push(upsert.definition.name);
1115
- }
1116
- definitionsCount = nextFile.definitions.length;
1117
- await writeAuditedSchemaFile({
1118
- pmRoot,
1119
- filePath: typesPath,
1120
- raw: serializeItemTypesFile(nextFile),
1121
- op: "schema:infer-types",
1122
- author,
1123
- settings,
1124
- });
1125
- await ensureTypeFolderScaffold(pmRoot, nextFile.definitions.filter((definition) => registered.includes(definition.name) ||
1126
- replaced.includes(definition.name)), warnings, "schema:infer-types-folder");
1127
- warnings.push(...(await runActiveOnWriteHooks({
1128
- path: typesPath,
1129
- scope: "project",
1130
- op: "schema:infer-types",
1131
- })));
1132
- }
1133
- finally {
1134
- await releaseLock();
1135
- }
1136
- return {
1137
- action: "infer-types",
1138
- applied: true,
1139
- min_count: minCount,
1140
- candidates,
1141
- registered,
1142
- replaced,
1143
- skipped,
1144
- file: {
1145
- path: typesPath,
1146
- definitions: definitionsCount,
1147
- },
1148
- warnings: finalizeWarnings(warnings),
1149
- generated_at: nowIso(),
1150
- };
1151
- }
1152
- /** Implements format schema add type human for the public runtime surface of this module. */
1153
- export function formatSchemaAddTypeHuman(result) {
1154
- const verb = result.replaced ? "Updated" : "Registered";
1155
- const aliasSuffix = result.type.aliases && result.type.aliases.length > 0
1156
- ? ` (aliases: ${result.type.aliases.join(", ")})`
1157
- : "";
1158
- return `${verb} custom item type "${result.type.name}"${aliasSuffix} in ${result.file.path}. Run: pm create "${escapeForDoubleQuotes(result.type.name)}" "<title>"`;
1159
- }
1160
- /** Implements format schema remove type human for the public runtime surface of this module. */
1161
- export function formatSchemaRemoveTypeHuman(result) {
1162
- if (!result.removed) {
1163
- return `No custom item type matched; nothing removed from ${result.file.path}.`;
1164
- }
1165
- const name = result.type?.name ?? "(unknown)";
1166
- return `Removed custom item type "${name}" from ${result.file.path}.`;
1167
- }
1168
- /** Implements format schema add status human for the public runtime surface of this module. */
1169
- export function formatSchemaAddStatusHuman(result) {
1170
- const verb = result.replaced ? "Updated" : "Registered";
1171
- const roleSuffix = result.status.roles && result.status.roles.length > 0
1172
- ? ` (roles: ${result.status.roles.join(", ")})`
1173
- : "";
1174
- const aliasSuffix = result.status.aliases && result.status.aliases.length > 0
1175
- ? ` (aliases: ${result.status.aliases.join(", ")})`
1176
- : "";
1177
- return `${verb} status "${result.status.id}"${roleSuffix}${aliasSuffix} in ${result.file.path}.`;
1178
- }
1179
- /** Implements format schema remove status human for the public runtime surface of this module. */
1180
- export function formatSchemaRemoveStatusHuman(result) {
1181
- if (!result.removed) {
1182
- return `No custom status matched; nothing removed from ${result.file.path}.`;
1183
- }
1184
- const id = result.status?.id ?? "(unknown)";
1185
- return `Removed custom status "${id}" from ${result.file.path}.`;
1186
- }
1187
- /** Implements format schema list human for the public runtime surface of this module. */
1188
- export function formatSchemaListHuman(result) {
1189
- const lines = [
1190
- `Schema types: ${result.counts.total} total (${result.counts.builtin} builtin, ${result.counts.custom} custom, ${result.counts.extension} extension)`,
1191
- ];
1192
- for (const [label, entries] of [
1193
- ["builtin", result.builtin],
1194
- ["custom", result.custom],
1195
- ["extension", result.extension],
1196
- ]) {
1197
- if (entries.length === 0) {
1198
- continue;
1199
- }
1200
- lines.push(`${label}: ${entries.map((entry) => entry.name).join(", ")}`);
1201
- }
1202
- lines.push(`statuses: ${result.statuses.counts.total} total (${result.statuses.counts.builtin} builtin, ${result.statuses.counts.custom} custom)`);
1203
- for (const [label, entries] of [
1204
- ["builtin statuses", result.statuses.builtin],
1205
- ["custom statuses", result.statuses.custom],
1206
- ]) {
1207
- if (entries.length === 0) {
1208
- continue;
1209
- }
1210
- lines.push(`${label}: ${entries.map((entry) => entry.id).join(", ")}`);
1211
- }
1212
- lines.push(`custom fields: ${result.fields.counts.total} total`);
1213
- if (result.fields.custom.length > 0) {
1214
- lines.push(`fields: ${result.fields.custom.map((field) => `${field.key} (${field.type}, ${field.cli_flag})`).join(", ")}`);
1215
- }
1216
- lines.push(`Inspect one: pm schema show <Type>`);
1217
- lines.push(`Inspect one status: pm schema show-status <status>`);
1218
- lines.push(`Inspect one field: pm schema show-field <key>`);
1219
- return lines.join("\n");
1220
- }
1221
- /** Implements format schema show human for the public runtime surface of this module. */
1222
- export function formatSchemaShowHuman(result) {
1223
- const parts = [
1224
- `type: ${result.type.name}`,
1225
- `source: ${result.type.source}`,
1226
- `folder: ${result.type.folder}`,
1227
- ];
1228
- if (result.type.default_status) {
1229
- parts.push(`default_status: ${result.type.default_status}`);
1230
- }
1231
- if (result.type.aliases.length > 0) {
1232
- parts.push(`aliases: ${result.type.aliases.join(", ")}`);
1233
- }
1234
- if (result.type.description) {
1235
- parts.push(`description: ${result.type.description}`);
1236
- }
1237
- if (result.type.options.length > 0) {
1238
- parts.push(`options: ${result.type.options.map((option) => option.key).join(", ")}`);
1239
- }
1240
- return parts.join("\n");
1241
- }
1242
- /** Implements format schema show status human for the public runtime surface of this module. */
1243
- export function formatSchemaShowStatusHuman(result) {
1244
- const parts = [
1245
- `status: ${result.status.id}`,
1246
- `source: ${result.status.source}`,
1247
- ];
1248
- if (result.status.roles.length > 0) {
1249
- parts.push(`roles: ${result.status.roles.join(", ")}`);
1250
- }
1251
- if (result.status.aliases.length > 0) {
1252
- parts.push(`aliases: ${result.status.aliases.join(", ")}`);
1253
- }
1254
- if (result.status.description) {
1255
- parts.push(`description: ${result.status.description}`);
1256
- }
1257
- if (typeof result.status.order === "number") {
1258
- parts.push(`order: ${result.status.order}`);
1259
- }
1260
- return parts.join("\n");
1261
- }
1262
- function formatFieldSummaryLine(field) {
1263
- const flags = [];
1264
- if (field.required) {
1265
- flags.push("required");
1266
- }
1267
- if (field.required_on_create) {
1268
- flags.push("required_on_create");
1269
- }
1270
- if (!field.allow_unset) {
1271
- flags.push("no_unset");
1272
- }
1273
- const flagSuffix = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
1274
- return `${field.key} (${field.type}) ${field.cli_flag} commands=${field.commands.join("/")}${flagSuffix}`;
1275
- }
1276
- /** Implements format schema add field human for the public runtime surface of this module. */
1277
- export function formatSchemaAddFieldHuman(result) {
1278
- const verb = result.replaced ? "Updated" : "Registered";
1279
- return `${verb} custom field "${result.field.key}" in ${result.file.path}. Use it: pm create "<title>" --${(result.field.cli_flag ?? result.field.key).replaceAll("_", "-")} <value>`;
1280
- }
1281
- /** Implements format schema remove field human for the public runtime surface of this module. */
1282
- export function formatSchemaRemoveFieldHuman(result) {
1283
- if (!result.removed) {
1284
- return `No custom field matched; nothing removed from ${result.file.path}.`;
1285
- }
1286
- const key = result.field?.key ?? "(unknown)";
1287
- return `Removed custom field "${key}" from ${result.file.path}.`;
1288
- }
1289
- /** Implements format schema list fields human for the public runtime surface of this module. */
1290
- export function formatSchemaListFieldsHuman(result) {
1291
- const lines = [`Custom fields: ${result.counts.total} total`];
1292
- for (const field of result.fields) {
1293
- lines.push(` ${formatFieldSummaryLine(field)}`);
1294
- }
1295
- lines.push(`Inspect one: pm schema show-field <key>`);
1296
- return lines.join("\n");
1297
- }
1298
- /** Implements format schema show field human for the public runtime surface of this module. */
1299
- export function formatSchemaShowFieldHuman(result) {
1300
- const field = result.field;
1301
- const parts = [
1302
- `field: ${field.key}`,
1303
- `type: ${field.type}`,
1304
- `cli_flag: ${field.cli_flag}`,
1305
- `commands: ${field.commands.join(", ")}`,
1306
- ];
1307
- if (field.cli_aliases.length > 0) {
1308
- parts.push(`cli_aliases: ${field.cli_aliases.join(", ")}`);
1309
- }
1310
- if (field.description) {
1311
- parts.push(`description: ${field.description}`);
1312
- }
1313
- if (field.required) {
1314
- parts.push(`required: true`);
1315
- }
1316
- if (field.required_on_create) {
1317
- parts.push(`required_on_create: true`);
1318
- }
1319
- if (!field.allow_unset) {
1320
- parts.push(`allow_unset: false`);
1321
- }
1322
- if (field.required_types.length > 0) {
1323
- parts.push(`required_types: ${field.required_types.join(", ")}`);
1324
- }
1325
- return parts.join("\n");
1326
- }
1327
- /** Implements format schema apply preset human for the public runtime surface of this module. */
1328
- export function formatSchemaApplyPresetHuman(result) {
1329
- const registered = result.registered.length > 0
1330
- ? `registered: ${result.registered.join(", ")}`
1331
- : "";
1332
- const replaced = result.replaced.length > 0 ? `updated: ${result.replaced.join(", ")}` : "";
1333
- const detail = [registered, replaced]
1334
- .filter((part) => part.length > 0)
1335
- .join("; ");
1336
- return `Applied "${result.preset}" type preset to ${result.file.path}${detail.length > 0 ? ` (${detail})` : ""}.`;
1337
- }
1338
- /** Implements format schema infer types human for the public runtime surface of this module. */
1339
- export function formatSchemaInferTypesHuman(result) {
1340
- if (result.candidates.length === 0) {
1341
- return `No title-prefix conventions found with at least ${result.min_count} items. Lower the threshold with --min-count <n>.`;
1342
- }
1343
- const lines = result.applied
1344
- ? [
1345
- `Inferred and registered custom types from title prefixes (min-count ${result.min_count}):`,
1346
- ]
1347
- : [
1348
- `Inferred custom type candidates from title prefixes (min-count ${result.min_count}, dry-run):`,
1349
- ];
1350
- for (const candidate of result.candidates) {
1351
- const note = candidate.shadows_builtin
1352
- ? " [shadows built-in, skipped]"
1353
- : "";
1354
- lines.push(` ${candidate.name} <- "${candidate.prefix}" (${candidate.count} items)${note}`);
1355
- }
1356
- if (!result.applied) {
1357
- lines.push(`Re-run with --apply to register the non-shadowing candidates.`);
1358
- }
1359
- else {
1360
- if (result.registered.length > 0) {
1361
- lines.push(`registered: ${result.registered.join(", ")}`);
1362
- }
1363
- if (result.replaced.length > 0) {
1364
- lines.push(`updated: ${result.replaced.join(", ")}`);
1365
- }
1366
- }
1367
- return lines.join("\n");
1368
- }
1369
- /* c8 ignore stop */
1370
- /** Re-export so register-mutation can surface the hint in usage examples without importing the core module directly. */
1371
- export { buildInvalidTypeHint };
1372
- /** Public contract for test only schema command, shared by SDK and presentation-layer consumers. */
1373
- export const _testOnlySchemaCommand = {
1374
- workflowSlotsReferencing,
1375
- };
1
+ !(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3b47d4d5-a224-5e46-8f91-9988c353c26b")}catch(e2){}})();import{assertInitializedTracker}from"./environment/tracker-preflight.js";import path from"node:path";import{mkdir}from"node:fs/promises";import{resolveAuthor}from"../core/shared/author.js";import{pathExists,readFileIfExists}from"../core/fs/fs-utils.js";import{writeWorkspaceJsonWithHistory}from"../core/history/workspace-history.js";import{acquireLock}from"../core/lock/lock.js";import{refreshMergeAttributeFenceIfInstalled}from"./merge/install.js";import{assertAliasesAvailable,assertTypeFolderAvailable,buildInvalidTypeHint,escapeForDoubleQuotes,normalizeAddTypeInput,parseItemTypesFile,removeItemType,serializeItemTypesFile,upsertItemType}from"../core/schema/item-types-file.js";import{assertStatusTokensAvailable,BUILTIN_STATUS_IDS,normalizeAddStatusInput,normalizeStatusToken,parseStatusDefsFile,removeStatusDef,serializeStatusDefsFile,upsertStatusDef}from"../core/schema/status-defs-file.js";import{normalizeAddFieldInput,normalizeFieldKey,parseFieldsFile,removeField,serializeFieldsFile,upsertField}from"../core/schema/fields-file.js";import{normalizeTypePresetName,resolveTypePresetDefinitions,TYPE_PRESET_NAMES}from"../core/schema/type-presets.js";import{inferTypesFromTitles}from"../core/schema/type-inference.js";import{DEFAULT_RUNTIME_SCHEMA_FILE_PATHS,filePathForSchemaSection,normalizeRuntimeSchemaSettings,resolveRuntimeFieldRegistry,resolveRuntimeStatusRegistry}from"../core/schema/runtime-schema.js";import{normalizeItemTypeFolder,resolveItemTypeRegistry,toDefaultFolder}from"../core/item/type-registry.js";import{listAllItemMetadataLight}from"../core/store/item-store.js";import{EXIT_CODE}from"../core/shared/constants.js";import{PmCliError}from"../core/shared/errors.js";import{nowIso}from"../core/shared/time.js";import{getActiveExtensionRegistrations,runActiveOnWriteHooks}from"../core/extensions/index.js";import{resolvePmRoot}from"../core/store/paths.js";import{readSettings,resolveGovernanceKnobs}from"../core/store/settings.js";import{resolvePmToolCustomFieldCollision}from"./cli-contracts/tool-schema.js";import{WORKFLOW_POLICY_ACTIONS}from"./governance/workflow-policy.js";export*from"./governance/workflow-policy.js";const SCHEMA_SUBCOMMANDS=[...WORKFLOW_POLICY_ACTIONS,"add-type","remove-type","add-status","remove-status","add-field","remove-field","list-fields","show-field","apply-preset","list","show","show-status","rename-type","rename-field","remap-status"];import{formatSchemaEvolutionMigrationHuman,planSchemaEvolutionMigration,runSchemaEvolutionMigration}from"./schema-migration.js";const SCHEMA_TYPES_LOCK_ID="schema-types";const SCHEMA_STATUSES_LOCK_ID="schema-statuses";const SCHEMA_FIELDS_LOCK_ID="schema-fields";function writeAuditedSchemaFile(params){return writeWorkspaceJsonWithHistory({pmRoot:params.pmRoot,filePath:params.filePath,raw:params.raw,op:params.op,author:params.author,lockTtlSeconds:params.settings.locks.ttl_seconds,lockWaitMs:params.settings.locks.wait_ms})}async function runSchemaAddType(name,options,global2){const pmRoot=resolvePmRoot(process.cwd(),global2.path);await ensureInitialized(pmRoot);let normalized;try{normalized=normalizeAddTypeInput({name,description:options.description,defaultStatus:options.defaultStatus,folder:options.folder,aliases:options.alias})}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.USAGE)}const settings=await readSettings(pmRoot);const schema=normalizeRuntimeSchemaSettings(settings.schema);const typesPath=filePathForSchemaSection(pmRoot,schema.files.types,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types);const warnings=[];const author=resolveAuthor(options.author,settings.author_default);const governance=resolveGovernanceKnobs(settings);const releaseLock=await acquireLock(pmRoot,SCHEMA_TYPES_LOCK_ID,settings.locks.ttl_seconds,author,Boolean(options.force),governance.force_required_for_stale_lock,settings.locks.wait_ms);let upsert;try{const previousRaw=await readFileIfExists(typesPath);let parsed;try{parsed=parseItemTypesFile(previousRaw)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.GENERIC_FAILURE)}try{assertAliasesAvailable(normalized,parsed);const reservedFolders=new Map;const resolvedRegistry=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations());for(const[typeName,folder]of Object.entries(resolvedRegistry.type_to_folder)){const folderKey=folder.trim().toLowerCase();if(folderKey.length>0&&!reservedFolders.has(folderKey)){reservedFolders.set(folderKey,typeName)}}assertTypeFolderAvailable(normalized,parsed,reservedFolders)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.USAGE)}upsert=upsertItemType(parsed,normalized);if(upsert.replaced&&upsert.previousName!==void 0&&upsert.previousName!==upsert.definition.name){warnings.push(`type_recased:${upsert.previousName}->${upsert.definition.name}`)}await writeAuditedSchemaFile({pmRoot,filePath:typesPath,raw:serializeItemTypesFile(upsert.file),op:"schema:add-type",author,settings});await ensureTypeFolderScaffold(pmRoot,[upsert.definition],warnings,"schema:add-type-folder");warnings.push(...await runActiveOnWriteHooks({path:typesPath,scope:"project",op:"schema:add-type"}))}finally{await releaseLock()}await appendMergeFenceWarnings(pmRoot,warnings);return{action:"add-type",registered:true,replaced:upsert.replaced,type:upsert.definition,file:{path:typesPath,definitions:upsert.file.definitions.length},warnings:finalizeWarnings(warnings),generated_at:nowIso()}}async function ensureInitialized(pmRoot){await assertInitializedTracker(pmRoot)}async function appendMergeFenceWarnings(pmRoot,warnings){try{const fence=await refreshMergeAttributeFenceIfInstalled(pmRoot);if(fence.status==="refreshed"){warnings.push("merge_fence_refreshed")}else if(fence.status==="not_installed"){warnings.push('merge_fence_not_installed:type folders lack git merge drivers; run "pm merge install"')}}catch{warnings.push('merge_fence_refresh_failed:run "pm merge install" to reconcile')}}function finalizeWarnings(warnings){return[...new Set(warnings)].sort((left,right)=>left.localeCompare(right))}async function countItemsUsingType(pmRoot,settings,schema,typeName){const registry=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations());const lowerName=typeName.trim().toLowerCase();const items=await listAllItemMetadataLight(pmRoot,settings.item_format,registry.type_to_folder,[],schema);return items.filter(item=>typeof item.type==="string"&&item.type.toLowerCase()===lowerName).length}async function countItemsUsingStatus(pmRoot,settings,schema,statusId){const registry=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations());const statusRegistry=resolveRuntimeStatusRegistry(schema);const normalizedId=normalizeStatusToken(statusId);const items=await listAllItemMetadataLight(pmRoot,settings.item_format,registry.type_to_folder,[],schema);return items.filter(item=>{const itemStatus=typeof item.status==="string"?item.status:"";const resolved=statusRegistry.alias_to_id.get(normalizeStatusToken(itemStatus))??normalizeStatusToken(itemStatus);return resolved===normalizedId}).length}async function appendRemovedStatusWarnings(warnings,pmRoot,settings,schema,removedId){if(removedId.length===0||BUILTIN_STATUS_IDS.has(removedId)){return}const usingStatus=await countItemsUsingStatus(pmRoot,settings,schema,removedId);if(usingStatus>0){warnings.push(`items_using_status:${usingStatus}`)}const referencingSlots=workflowSlotsReferencing(schema.workflow,removedId);if(referencingSlots.length>0){warnings.push(`status_referenced_by_workflow:${referencingSlots.join(",")}`)}}function workflowSlotsReferencing(workflow,statusId){const slots=[["draft_status",workflow.draft_status],["open_status",workflow.open_status],["in_progress_status",workflow.in_progress_status],["blocked_status",workflow.blocked_status],["close_status",workflow.close_status],["canceled_status",workflow.canceled_status]];return slots.filter(([,value])=>value!==void 0&&normalizeStatusToken(value)===statusId).map(([slot])=>slot)}async function runSchemaRemoveType(name,options,global2){const pmRoot=resolvePmRoot(process.cwd(),global2.path);await ensureInitialized(pmRoot);const settings=await readSettings(pmRoot);const schema=normalizeRuntimeSchemaSettings(settings.schema);const typesPath=filePathForSchemaSection(pmRoot,schema.files.types,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types);const warnings=[];const author=resolveAuthor(options.author,settings.author_default);const governance=resolveGovernanceKnobs(settings);const releaseLock=await acquireLock(pmRoot,SCHEMA_TYPES_LOCK_ID,settings.locks.ttl_seconds,author,Boolean(options.force),governance.force_required_for_stale_lock,settings.locks.wait_ms);let removal;try{const previousRaw=await readFileIfExists(typesPath);let parsed;try{parsed=parseItemTypesFile(previousRaw)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.GENERIC_FAILURE)}try{removal=removeItemType(parsed,name)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.USAGE)}if(removal.removed){const removedName=(removal.definition?.name??name??"").trim();if(removedName.length>0){const usingType=await countItemsUsingType(pmRoot,settings,schema,removedName);if(usingType>0){warnings.push(`items_using_type:${usingType}`)}}await writeAuditedSchemaFile({pmRoot,filePath:typesPath,raw:serializeItemTypesFile(removal.file),op:"schema:remove-type",author,settings});warnings.push(...await runActiveOnWriteHooks({path:typesPath,scope:"project",op:"schema:remove-type"}))}}finally{await releaseLock()}if(removal.removed){await appendMergeFenceWarnings(pmRoot,warnings)}return{action:"remove-type",removed:removal.removed,...removal.definition?{type:removal.definition}:{},file:{path:typesPath,definitions:removal.file.definitions.length},warnings:finalizeWarnings(warnings),generated_at:nowIso()}}function statusesPathFor(pmRoot,schema){return filePathForSchemaSection(pmRoot,schema.files.statuses,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.statuses)}function fieldsPathFor(pmRoot,schema){return filePathForSchemaSection(pmRoot,schema.files.fields,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.fields)}function typesPathFor(pmRoot,schema){return filePathForSchemaSection(pmRoot,schema.files.types,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types)}async function ensureTypeFolderScaffold(pmRoot,definitions,warnings,op){for(const definition of definitions){const folder=normalizeItemTypeFolder(definition.folder??toDefaultFolder(definition.name));const target=path.join(pmRoot,folder);if(await pathExists(target)){continue}await mkdir(target,{recursive:true});warnings.push(...await runActiveOnWriteHooks({path:target,scope:"project",op}))}}function toSchemaFieldSummary(field){return{key:field.key,type:field.type,commands:[...field.commands],cli_flag:`--${field.cli_flag}`,cli_aliases:field.cli_aliases.map(alias=>`--${alias}`),...field.description?{description:field.description}:{},required:field.required,required_on_create:field.required_on_create,allow_unset:field.allow_unset,required_types:[...field.required_types]}}function toExistingStatusDefinition(resolvedExisting){if(!resolvedExisting){return void 0}return{id:resolvedExisting.id,...resolvedExisting.roles.length>0?{roles:[...resolvedExisting.roles]}:{},...resolvedExisting.aliases.length>0?{aliases:[...resolvedExisting.aliases]}:{},...resolvedExisting.description?{description:resolvedExisting.description}:{},...typeof resolvedExisting.order==="number"?{order:resolvedExisting.order}:{}}}function buildStatusFileAliasMap(statuses){const fileAliasToId=new Map;for(const definition of statuses){const defId=normalizeStatusToken(definition.id);if(defId.length===0){continue}fileAliasToId.set(defId,defId);for(const alias of Array.isArray(definition.aliases)?definition.aliases:[]){const aliasToken=normalizeStatusToken(alias);if(aliasToken.length>0&&!fileAliasToId.has(aliasToken)){fileAliasToId.set(aliasToken,defId)}}}return fileAliasToId}async function runSchemaAddStatus(id,options,global2){const pmRoot=resolvePmRoot(process.cwd(),global2.path);await ensureInitialized(pmRoot);let normalized;try{normalized=normalizeAddStatusInput({id,roles:options.role,aliases:options.alias,description:options.description,order:options.order})}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.USAGE)}const settings=await readSettings(pmRoot);const schema=normalizeRuntimeSchemaSettings(settings.schema);const statusesPath=statusesPathFor(pmRoot,schema);const statusRegistry=resolveRuntimeStatusRegistry(schema);try{assertStatusTokensAvailable(normalized,statusRegistry.alias_to_id)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.USAGE)}const baseDefinition=toExistingStatusDefinition(statusRegistry.by_id.get(normalized.id));const effectiveRoles=normalized.roles??baseDefinition?.roles??[];if(effectiveRoles.length===0){throw new PmCliError(`Status "${normalized.id}" requires at least one lifecycle role. Re-run with --role active, --role blocked, --role draft, or an appropriate terminal/default role.`,EXIT_CODE.USAGE,{code:"status_lifecycle_role_required",examples:[`pm schema add-status "${escapeForDoubleQuotes(normalized.id)}" --role active`,`pm schema add-status "${escapeForDoubleQuotes(normalized.id)}" --role blocked`]})}const warnings=[];const author=resolveAuthor(options.author,settings.author_default);const governance=resolveGovernanceKnobs(settings);const releaseLock=await acquireLock(pmRoot,SCHEMA_STATUSES_LOCK_ID,settings.locks.ttl_seconds,author,Boolean(options.force),governance.force_required_for_stale_lock,settings.locks.wait_ms);let upsert;try{const previousRaw=await readFileIfExists(statusesPath);let parsed;try{parsed=parseStatusDefsFile(previousRaw)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.GENERIC_FAILURE)}const fileAliasToId=buildStatusFileAliasMap(parsed.statuses);try{assertStatusTokensAvailable(normalized,fileAliasToId)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.USAGE)}upsert=upsertStatusDef(parsed,normalized,baseDefinition);await writeAuditedSchemaFile({pmRoot,filePath:statusesPath,raw:serializeStatusDefsFile(upsert.file),op:"schema:add-status",author,settings});warnings.push(...await runActiveOnWriteHooks({path:statusesPath,scope:"project",op:"schema:add-status"}))}finally{await releaseLock()}return{action:"add-status",registered:true,replaced:upsert.replaced,status:upsert.definition,file:{path:statusesPath,statuses:upsert.file.statuses.length},warnings:finalizeWarnings(warnings),generated_at:nowIso()}}async function runSchemaRemoveStatus(id,options,global2){const pmRoot=resolvePmRoot(process.cwd(),global2.path);await ensureInitialized(pmRoot);const settings=await readSettings(pmRoot);const schema=normalizeRuntimeSchemaSettings(settings.schema);const statusesPath=statusesPathFor(pmRoot,schema);const warnings=[];const author=resolveAuthor(options.author,settings.author_default);const governance=resolveGovernanceKnobs(settings);const releaseLock=await acquireLock(pmRoot,SCHEMA_STATUSES_LOCK_ID,settings.locks.ttl_seconds,author,Boolean(options.force),governance.force_required_for_stale_lock,settings.locks.wait_ms);let removal;try{const previousRaw=await readFileIfExists(statusesPath);let parsed;try{parsed=parseStatusDefsFile(previousRaw)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.GENERIC_FAILURE)}try{removal=removeStatusDef(parsed,id)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.USAGE)}if(removal.removed){const removedId=normalizeStatusToken(removal.definition?.id??id);await appendRemovedStatusWarnings(warnings,pmRoot,settings,schema,removedId);await writeAuditedSchemaFile({pmRoot,filePath:statusesPath,raw:serializeStatusDefsFile(removal.file),op:"schema:remove-status",author,settings});warnings.push(...await runActiveOnWriteHooks({path:statusesPath,scope:"project",op:"schema:remove-status"}))}}finally{await releaseLock()}return{action:"remove-status",removed:removal.removed,...removal.definition?{status:removal.definition}:{},file:{path:statusesPath,statuses:removal.file.statuses.length},warnings:finalizeWarnings(warnings),generated_at:nowIso()}}function toSchemaTypeSummary(definition){return{name:definition.name,folder:definition.folder,aliases:Array.isArray(definition.aliases)?[...definition.aliases]:[],...definition.default_status?{default_status:definition.default_status}:{},...definition.description?{description:definition.description}:{}}}function toSchemaTypeDefinition(definition,source,extensionProvenance){return{...toSchemaTypeSummary(definition),source,...extensionProvenance?{extension:extensionProvenance}:{},required_create_fields:[...definition.required_create_fields],required_create_repeatables:[...definition.required_create_repeatables],options:structuredClone(definition.options),command_option_policies:structuredClone(definition.command_option_policies)}}function toSchemaStatusSummary(definition){return{id:definition.id,source:BUILTIN_STATUS_IDS.has(definition.id)?"builtin":"custom",roles:Array.isArray(definition.roles)?[...definition.roles]:[],aliases:Array.isArray(definition.aliases)?[...definition.aliases]:[],...definition.description?{description:definition.description}:{},...typeof definition.order==="number"?{order:definition.order}:{}}}function classifyTypeSource(name,customNames,extensionNames){const lowerName=name.toLowerCase();if(extensionNames.has(lowerName)){return"extension"}if(customNames.has(lowerName)){return"custom"}return"builtin"}function collectExtensionTypeProvenance(){const provenance=new Map;const registrations=getActiveExtensionRegistrations();for(const registration of registrations?.item_types??[]){const rawTypes=registration.types;if(!Array.isArray(rawTypes)){continue}for(const rawType of rawTypes){if(typeof rawType!=="object"||rawType===null||Array.isArray(rawType)){continue}const name=rawType.name;if(typeof name==="string"&&name.trim().length>0){provenance.set(name.trim().toLowerCase(),{layer:registration.layer,name:registration.name})}}}return provenance}function buildSchemaStatusSummaries(schema){const registry=resolveRuntimeStatusRegistry(schema);const builtin=[];const custom=[];for(const definition of registry.definitions){const summary=toSchemaStatusSummary(definition);if(summary.source==="builtin"){builtin.push(summary)}else{custom.push(summary)}}return{builtin,custom}}async function loadSchemaInspectionContext(global2){const pmRoot=resolvePmRoot(process.cwd(),global2.path);await ensureInitialized(pmRoot);const settings=await readSettings(pmRoot);const schema=normalizeRuntimeSchemaSettings(settings.schema);const typesPath=filePathForSchemaSection(pmRoot,schema.files.types,DEFAULT_RUNTIME_SCHEMA_FILE_PATHS.types);const statusesPath=statusesPathFor(pmRoot,schema);const registry=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations());const extensionProvenance=collectExtensionTypeProvenance();const customNames=new Set((settings.item_types?.definitions??[]).map(definition=>definition.name.trim().toLowerCase()).filter(name=>name.length>0&&!extensionProvenance.has(name)));return{pmRoot,typesPath,statusesPath,byType:registry.by_type,customNames,extensionProvenance,schema}}async function runSchemaList(global2){const context=await loadSchemaInspectionContext(global2);const builtin=[];const custom=[];const extension=[];for(const definition of Object.values(context.byType).sort((left,right)=>left.name.localeCompare(right.name))){const source=classifyTypeSource(definition.name,context.customNames,new Set(context.extensionProvenance.keys()));const summary=toSchemaTypeSummary(definition);if(source==="extension"){extension.push(summary)}else if(source==="custom"){custom.push(summary)}else{builtin.push(summary)}}const statusSummaries=buildSchemaStatusSummaries(context.schema);const fieldSummaries=resolveRuntimeFieldRegistry(context.schema).definitions.map(toSchemaFieldSummary);return{action:"list",builtin,custom,extension,counts:{builtin:builtin.length,custom:custom.length,extension:extension.length,total:builtin.length+custom.length+extension.length},statuses:{builtin:statusSummaries.builtin,custom:statusSummaries.custom,counts:{builtin:statusSummaries.builtin.length,custom:statusSummaries.custom.length,total:statusSummaries.builtin.length+statusSummaries.custom.length}},fields:{custom:fieldSummaries,counts:{total:fieldSummaries.length}},file:{path:context.typesPath},generated_at:nowIso()}}async function runSchemaShow(name,global2){const typeName=(name??"").trim();if(typeName.length===0){throw new PmCliError("Type name must not be empty.",EXIT_CODE.USAGE)}const context=await loadSchemaInspectionContext(global2);const match=Object.values(context.byType).find(definition=>definition.name.toLowerCase()===typeName.toLowerCase()||definition.aliases.some(alias=>alias.toLowerCase()===typeName.toLowerCase()));if(!match){throw new PmCliError(`Unknown item type "${typeName}". Run pm schema list to inspect registered types, or pm schema add-type "${escapeForDoubleQuotes(typeName)}" to register it.`,EXIT_CODE.NOT_FOUND,{code:"unknown_item_type"})}return{action:"show",type:toSchemaTypeDefinition(match,classifyTypeSource(match.name,context.customNames,new Set(context.extensionProvenance.keys())),context.extensionProvenance.get(match.name.toLowerCase())),file:{path:context.typesPath},generated_at:nowIso()}}async function runSchemaShowStatus(id,global2){const statusToken=normalizeStatusToken(id);if(statusToken.length===0){throw new PmCliError("Status id must not be empty.",EXIT_CODE.USAGE)}const context=await loadSchemaInspectionContext(global2);const statusRegistry=resolveRuntimeStatusRegistry(context.schema);const resolvedId=statusRegistry.alias_to_id.get(statusToken)??statusToken;const match=statusRegistry.by_id.get(resolvedId);if(!match){throw new PmCliError(`Unknown status "${id}". Run pm schema list to inspect registered statuses, or pm schema add-status "${escapeForDoubleQuotes(id??"")}" to register it.`,EXIT_CODE.NOT_FOUND,{code:"unknown_status"})}return{action:"show-status",status:toSchemaStatusSummary(match),file:{path:context.statusesPath},generated_at:nowIso()}}async function runSchemaAddField(key,options,global2){const pmRoot=resolvePmRoot(process.cwd(),global2.path);await ensureInitialized(pmRoot);let normalized;try{normalized=normalizeAddFieldInput({key,type:options.type,commands:options.commands,description:options.description,cliFlag:options.cliFlag,aliases:options.alias,required:options.required,requiredOnCreate:options.requiredOnCreate,allowUnset:options.allowUnset,requiredTypes:options.requiredTypes})}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.USAGE)}const settings=await readSettings(pmRoot);const schema=normalizeRuntimeSchemaSettings(settings.schema);const fieldsPath=fieldsPathFor(pmRoot,schema);const warnings=[];const mcpCollision=resolvePmToolCustomFieldCollision(normalized.key);if(mcpCollision){warnings.push(`custom_field_mcp_input_collision:${mcpCollision.field}:${mcpCollision.property}:${mcpCollision.owner}:use=${mcpCollision.nested_path}`)}const author=resolveAuthor(options.author,settings.author_default);const governance=resolveGovernanceKnobs(settings);const releaseLock=await acquireLock(pmRoot,SCHEMA_FIELDS_LOCK_ID,settings.locks.ttl_seconds,author,Boolean(options.force),governance.force_required_for_stale_lock,settings.locks.wait_ms);let upsert;try{const previousRaw=await readFileIfExists(fieldsPath);let parsed;try{parsed=parseFieldsFile(previousRaw)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.GENERIC_FAILURE)}upsert=upsertField(parsed,normalized);await writeAuditedSchemaFile({pmRoot,filePath:fieldsPath,raw:serializeFieldsFile(upsert.file),op:"schema:add-field",author,settings});warnings.push(...await runActiveOnWriteHooks({path:fieldsPath,scope:"project",op:"schema:add-field"}))}finally{await releaseLock()}return{action:"add-field",registered:true,replaced:upsert.replaced,field:upsert.definition,file:{path:fieldsPath,fields:upsert.file.fields.length},warnings:finalizeWarnings(warnings),generated_at:nowIso()}}async function countItemsUsingField(pmRoot,settings,schema,metadataKey){const registry=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations());const items=await listAllItemMetadataLight(pmRoot,settings.item_format,registry.type_to_folder,[],schema);return items.filter(item=>{const value=item[metadataKey];if(value===void 0||value===null){return false}if(Array.isArray(value)){return value.length>0}if(typeof value==="string"){return value.trim().length>0}return true}).length}async function runSchemaRemoveField(key,options,global2){const pmRoot=resolvePmRoot(process.cwd(),global2.path);await ensureInitialized(pmRoot);const settings=await readSettings(pmRoot);const schema=normalizeRuntimeSchemaSettings(settings.schema);const fieldsPath=fieldsPathFor(pmRoot,schema);const warnings=[];const author=resolveAuthor(options.author,settings.author_default);const governance=resolveGovernanceKnobs(settings);const releaseLock=await acquireLock(pmRoot,SCHEMA_FIELDS_LOCK_ID,settings.locks.ttl_seconds,author,Boolean(options.force),governance.force_required_for_stale_lock,settings.locks.wait_ms);let removal;try{const previousRaw=await readFileIfExists(fieldsPath);let parsed;try{parsed=parseFieldsFile(previousRaw)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.GENERIC_FAILURE)}try{removal=removeField(parsed,key)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.USAGE)}if(removal.removed){const removedKey=normalizeFieldKey(removal.definition?.key??key);const metadataKey=normalizeFieldKey(removal.definition?.metadata_key??removal.definition?.front_matter_key??removedKey);if(metadataKey.length>0){const usingField=await countItemsUsingField(pmRoot,settings,schema,metadataKey);if(usingField>0){warnings.push(`items_using_field:${usingField}`)}}await writeAuditedSchemaFile({pmRoot,filePath:fieldsPath,raw:serializeFieldsFile(removal.file),op:"schema:remove-field",author,settings});warnings.push(...await runActiveOnWriteHooks({path:fieldsPath,scope:"project",op:"schema:remove-field"}))}}finally{await releaseLock()}return{action:"remove-field",removed:removal.removed,...removal.definition?{field:removal.definition}:{},file:{path:fieldsPath,fields:removal.file.fields.length},warnings:finalizeWarnings(warnings),generated_at:nowIso()}}async function runSchemaListFields(global2){const context=await loadSchemaInspectionContext(global2);const fields=resolveRuntimeFieldRegistry(context.schema).definitions.map(toSchemaFieldSummary);return{action:"list-fields",fields,counts:{total:fields.length},file:{path:fieldsPathFor(context.pmRoot,context.schema)},generated_at:nowIso()}}async function runSchemaShowField(key,global2){const fieldKey=normalizeFieldKey(key);if(fieldKey.length===0){throw new PmCliError("Field key must not be empty.",EXIT_CODE.USAGE)}const context=await loadSchemaInspectionContext(global2);const match=resolveRuntimeFieldRegistry(context.schema).by_key.get(fieldKey);if(!match){throw new PmCliError(`Unknown custom field "${key}". Run pm schema list-fields to inspect registered fields, or pm schema add-field "${escapeForDoubleQuotes(key??"")}" to register it.`,EXIT_CODE.NOT_FOUND,{code:"unknown_field"})}return{action:"show-field",field:toSchemaFieldSummary(match),file:{path:fieldsPathFor(context.pmRoot,context.schema)},generated_at:nowIso()}}async function runSchemaApplyPreset(preset,options,global2){const pmRoot=resolvePmRoot(process.cwd(),global2.path);await ensureInitialized(pmRoot);let presetName;try{const normalized=normalizeTypePresetName(preset);if(normalized===void 0){throw new Error(`Type preset name is required. Allowed: ${TYPE_PRESET_NAMES.join(", ")}.`)}presetName=normalized}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.USAGE)}const settings=await readSettings(pmRoot);const schema=normalizeRuntimeSchemaSettings(settings.schema);const typesPath=typesPathFor(pmRoot,schema);const warnings=[];const author=resolveAuthor(options.author,settings.author_default);const governance=resolveGovernanceKnobs(settings);const registered=[];const replaced=[];let definitionsCount;const releaseLock=await acquireLock(pmRoot,SCHEMA_TYPES_LOCK_ID,settings.locks.ttl_seconds,author,Boolean(options.force),governance.force_required_for_stale_lock,settings.locks.wait_ms);try{const previousRaw=await readFileIfExists(typesPath);let parsed;try{parsed=parseItemTypesFile(previousRaw)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.GENERIC_FAILURE)}let nextFile=parsed;for(const normalized of resolveTypePresetDefinitions(presetName)){const upsert=upsertItemType(nextFile,normalized);nextFile=upsert.file;(upsert.replaced?replaced:registered).push(upsert.definition.name)}definitionsCount=nextFile.definitions.length;await writeAuditedSchemaFile({pmRoot,filePath:typesPath,raw:serializeItemTypesFile(nextFile),op:"schema:apply-preset",author,settings});await ensureTypeFolderScaffold(pmRoot,resolveTypePresetDefinitions(presetName),warnings,"schema:apply-preset-folder");warnings.push(...await runActiveOnWriteHooks({path:typesPath,scope:"project",op:"schema:apply-preset"}))}finally{await releaseLock()}return{action:"apply-preset",preset:presetName,registered,replaced,file:{path:typesPath,definitions:definitionsCount},warnings:finalizeWarnings(warnings),generated_at:nowIso()}}function resolveSchemaInferenceMinCount(value){if(value===void 0){return 10}if(!Number.isInteger(value)||value<1){throw new PmCliError("--min-count must be a positive integer (>= 1).",EXIT_CODE.USAGE)}return value}async function runSchemaInferTypes(options,global2){const pmRoot=resolvePmRoot(process.cwd(),global2.path);await ensureInitialized(pmRoot);const settings=await readSettings(pmRoot);const schema=normalizeRuntimeSchemaSettings(settings.schema);const typesPath=typesPathFor(pmRoot,schema);const minCount=resolveSchemaInferenceMinCount(options.minCount);const registry=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations());const items=await listAllItemMetadataLight(pmRoot,settings.item_format,registry.type_to_folder,[],schema);const titles=items.map(item=>typeof item.title==="string"?item.title:"");const candidates=inferTypesFromTitles(titles,{minCount});const warnings=[];const registered=[];const replaced=[];const skipped=[];let definitionsCount;if(!options.apply){let parsed;try{parsed=parseItemTypesFile(await readFileIfExists(typesPath))}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.GENERIC_FAILURE)}definitionsCount=parsed.definitions.length;return{action:"infer-types",applied:false,min_count:minCount,candidates,registered,replaced,skipped,file:{path:typesPath,definitions:definitionsCount},warnings,generated_at:nowIso()}}const author=resolveAuthor(options.author,settings.author_default);const governance=resolveGovernanceKnobs(settings);const releaseLock=await acquireLock(pmRoot,SCHEMA_TYPES_LOCK_ID,settings.locks.ttl_seconds,author,Boolean(options.force),governance.force_required_for_stale_lock,settings.locks.wait_ms);try{const previousRaw=await readFileIfExists(typesPath);let parsed;try{parsed=parseItemTypesFile(previousRaw)}catch(error){throw new PmCliError(error instanceof Error?error.message:String(error),EXIT_CODE.GENERIC_FAILURE)}let nextFile=parsed;for(const candidate of candidates){if(candidate.shadows_builtin){skipped.push({name:candidate.name,reason:"shadows_builtin"});continue}let normalized;try{normalized=normalizeAddTypeInput({name:candidate.name})}catch{skipped.push({name:candidate.name,reason:"invalid_type_token"});continue}const upsert=upsertItemType(nextFile,normalized);nextFile=upsert.file;(upsert.replaced?replaced:registered).push(upsert.definition.name)}definitionsCount=nextFile.definitions.length;await writeAuditedSchemaFile({pmRoot,filePath:typesPath,raw:serializeItemTypesFile(nextFile),op:"schema:infer-types",author,settings});await ensureTypeFolderScaffold(pmRoot,nextFile.definitions.filter(definition=>registered.includes(definition.name)||replaced.includes(definition.name)),warnings,"schema:infer-types-folder");warnings.push(...await runActiveOnWriteHooks({path:typesPath,scope:"project",op:"schema:infer-types"}))}finally{await releaseLock()}return{action:"infer-types",applied:true,min_count:minCount,candidates,registered,replaced,skipped,file:{path:typesPath,definitions:definitionsCount},warnings:finalizeWarnings(warnings),generated_at:nowIso()}}function formatSchemaAddTypeHuman(result){const verb=result.replaced?"Updated":"Registered";const aliasSuffix=result.type.aliases&&result.type.aliases.length>0?` (aliases: ${result.type.aliases.join(", ")})`:"";return`${verb} custom item type "${result.type.name}"${aliasSuffix} in ${result.file.path}. Run: pm create "${escapeForDoubleQuotes(result.type.name)}" "<title>"`}function formatSchemaRemoveTypeHuman(result){if(!result.removed){return`No custom item type matched; nothing removed from ${result.file.path}.`}const name=result.type?.name??"(unknown)";return`Removed custom item type "${name}" from ${result.file.path}.`}function formatSchemaAddStatusHuman(result){const verb=result.replaced?"Updated":"Registered";const roleSuffix=result.status.roles&&result.status.roles.length>0?` (roles: ${result.status.roles.join(", ")})`:"";const aliasSuffix=result.status.aliases&&result.status.aliases.length>0?` (aliases: ${result.status.aliases.join(", ")})`:"";return`${verb} status "${result.status.id}"${roleSuffix}${aliasSuffix} in ${result.file.path}.`}function formatSchemaRemoveStatusHuman(result){if(!result.removed){return`No custom status matched; nothing removed from ${result.file.path}.`}const id=result.status?.id??"(unknown)";return`Removed custom status "${id}" from ${result.file.path}.`}function formatSchemaListHuman(result){const lines=[`Schema types: ${result.counts.total} total (${result.counts.builtin} builtin, ${result.counts.custom} custom, ${result.counts.extension} extension)`];for(const[label,entries]of[["builtin",result.builtin],["custom",result.custom],["extension",result.extension]]){if(entries.length===0){continue}lines.push(`${label}: ${entries.map(entry=>entry.name).join(", ")}`)}lines.push(`statuses: ${result.statuses.counts.total} total (${result.statuses.counts.builtin} builtin, ${result.statuses.counts.custom} custom)`);for(const[label,entries]of[["builtin statuses",result.statuses.builtin],["custom statuses",result.statuses.custom]]){if(entries.length===0){continue}lines.push(`${label}: ${entries.map(entry=>entry.id).join(", ")}`)}lines.push(`custom fields: ${result.fields.counts.total} total`);if(result.fields.custom.length>0){lines.push(`fields: ${result.fields.custom.map(field=>`${field.key} (${field.type}, ${field.cli_flag})`).join(", ")}`)}lines.push(`Inspect one: pm schema show <Type>`);lines.push(`Inspect one status: pm schema show-status <status>`);lines.push(`Inspect one field: pm schema show-field <key>`);return lines.join("\n")}function formatSchemaShowHuman(result){const parts=[`type: ${result.type.name}`,`source: ${result.type.source}`,`folder: ${result.type.folder}`];if(result.type.default_status){parts.push(`default_status: ${result.type.default_status}`)}if(result.type.aliases.length>0){parts.push(`aliases: ${result.type.aliases.join(", ")}`)}if(result.type.description){parts.push(`description: ${result.type.description}`)}if(result.type.options.length>0){parts.push(`options: ${result.type.options.map(option=>option.key).join(", ")}`)}return parts.join("\n")}function formatSchemaShowStatusHuman(result){const parts=[`status: ${result.status.id}`,`source: ${result.status.source}`];if(result.status.roles.length>0){parts.push(`roles: ${result.status.roles.join(", ")}`)}if(result.status.aliases.length>0){parts.push(`aliases: ${result.status.aliases.join(", ")}`)}if(result.status.description){parts.push(`description: ${result.status.description}`)}if(typeof result.status.order==="number"){parts.push(`order: ${result.status.order}`)}return parts.join("\n")}function formatFieldSummaryLine(field){const flags=[];if(field.required){flags.push("required")}if(field.required_on_create){flags.push("required_on_create")}if(!field.allow_unset){flags.push("no_unset")}const flagSuffix=flags.length>0?` [${flags.join(", ")}]`:"";return`${field.key} (${field.type}) ${field.cli_flag} commands=${field.commands.join("/")}${flagSuffix}`}function formatSchemaAddFieldHuman(result){const verb=result.replaced?"Updated":"Registered";return`${verb} custom field "${result.field.key}" in ${result.file.path}. Use it: pm create "<title>" --${(result.field.cli_flag??result.field.key).replaceAll("_","-")} <value>`}function formatSchemaRemoveFieldHuman(result){if(!result.removed){return`No custom field matched; nothing removed from ${result.file.path}.`}const key=result.field?.key??"(unknown)";return`Removed custom field "${key}" from ${result.file.path}.`}function formatSchemaListFieldsHuman(result){const lines=[`Custom fields: ${result.counts.total} total`];for(const field of result.fields){lines.push(` ${formatFieldSummaryLine(field)}`)}lines.push(`Inspect one: pm schema show-field <key>`);return lines.join("\n")}function formatSchemaShowFieldHuman(result){const field=result.field;const parts=[`field: ${field.key}`,`type: ${field.type}`,`cli_flag: ${field.cli_flag}`,`commands: ${field.commands.join(", ")}`];if(field.cli_aliases.length>0){parts.push(`cli_aliases: ${field.cli_aliases.join(", ")}`)}if(field.description){parts.push(`description: ${field.description}`)}if(field.required){parts.push(`required: true`)}if(field.required_on_create){parts.push(`required_on_create: true`)}if(!field.allow_unset){parts.push(`allow_unset: false`)}if(field.required_types.length>0){parts.push(`required_types: ${field.required_types.join(", ")}`)}return parts.join("\n")}function formatSchemaApplyPresetHuman(result){const registered=result.registered.length>0?`registered: ${result.registered.join(", ")}`:"";const replaced=result.replaced.length>0?`updated: ${result.replaced.join(", ")}`:"";const detail=[registered,replaced].filter(part=>part.length>0).join("; ");return`Applied "${result.preset}" type preset to ${result.file.path}${detail.length>0?` (${detail})`:""}.`}function formatSchemaInferTypesHuman(result){if(result.candidates.length===0){return`No title-prefix conventions found with at least ${result.min_count} items. Lower the threshold with --min-count <n>.`}const lines=result.applied?[`Inferred and registered custom types from title prefixes (min-count ${result.min_count}):`]:[`Inferred custom type candidates from title prefixes (min-count ${result.min_count}, dry-run):`];for(const candidate of result.candidates){const note=candidate.shadows_builtin?" [shadows built-in, skipped]":"";lines.push(` ${candidate.name} <- "${candidate.prefix}" (${candidate.count} items)${note}`)}if(!result.applied){lines.push(`Re-run with --apply to register the non-shadowing candidates.`)}else{if(result.registered.length>0){lines.push(`registered: ${result.registered.join(", ")}`)}if(result.replaced.length>0){lines.push(`updated: ${result.replaced.join(", ")}`)}}return lines.join("\n")}const _testOnlySchemaCommand={workflowSlotsReferencing};export{SCHEMA_SUBCOMMANDS,_testOnlySchemaCommand,buildInvalidTypeHint,ensureTypeFolderScaffold,formatSchemaAddFieldHuman,formatSchemaAddStatusHuman,formatSchemaAddTypeHuman,formatSchemaApplyPresetHuman,formatSchemaEvolutionMigrationHuman,formatSchemaInferTypesHuman,formatSchemaListFieldsHuman,formatSchemaListHuman,formatSchemaRemoveFieldHuman,formatSchemaRemoveStatusHuman,formatSchemaRemoveTypeHuman,formatSchemaShowFieldHuman,formatSchemaShowHuman,formatSchemaShowStatusHuman,planSchemaEvolutionMigration,runSchemaAddField,runSchemaAddStatus,runSchemaAddType,runSchemaApplyPreset,runSchemaEvolutionMigration,runSchemaInferTypes,runSchemaList,runSchemaListFields,runSchemaRemoveField,runSchemaRemoveStatus,runSchemaRemoveType,runSchemaShow,runSchemaShowField,runSchemaShowStatus};
1376
2
  //# sourceMappingURL=schema.js.map
1377
- //# debugId=264088a5-09d1-52ed-8b12-af00392e1a5f