@unbrained/pm-cli 2026.9.21 → 2026.9.22

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 (250) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +21 -1
  3. package/dist/cli/commander-usage.d.ts +5 -1
  4. package/dist/cli/commander-usage.js +2 -2
  5. package/dist/cli/commands/annotations/comments.d.ts +2 -0
  6. package/dist/cli/commands/{comments.js → annotations/comments.js} +1 -1
  7. package/dist/cli/commands/{docs.d.ts → annotations/docs.d.ts} +2 -2
  8. package/dist/cli/commands/{docs.js → annotations/docs.js} +1 -1
  9. package/dist/cli/commands/{files.d.ts → annotations/files.d.ts} +2 -2
  10. package/dist/cli/commands/{files.js → annotations/files.js} +1 -1
  11. package/dist/cli/commands/annotations/learnings.d.ts +2 -0
  12. package/dist/cli/commands/{learnings.js → annotations/learnings.js} +1 -1
  13. package/dist/cli/commands/annotations/notes.d.ts +2 -0
  14. package/dist/cli/commands/{notes.js → annotations/notes.js} +1 -1
  15. package/dist/cli/commands/extension/extension.d.ts +6 -0
  16. package/dist/cli/commands/{extension.js → extension/extension.js} +1 -1
  17. package/dist/cli/commands/{gc.d.ts → governance/gc.d.ts} +2 -2
  18. package/dist/cli/commands/{gc.js → governance/gc.js} +1 -1
  19. package/dist/cli/commands/governance/health.d.ts +6 -0
  20. package/dist/cli/commands/{deps.js → governance/health.js} +2 -2
  21. package/dist/cli/commands/governance/telemetry.d.ts +6 -0
  22. package/dist/cli/commands/{telemetry.js → governance/telemetry.js} +1 -1
  23. package/dist/cli/commands/governance/validate.d.ts +9 -0
  24. package/dist/cli/commands/governance/validate.js +2 -0
  25. package/dist/cli/commands/history/activity.d.ts +6 -0
  26. package/dist/cli/commands/{activity.js → history/activity.js} +1 -1
  27. package/dist/cli/commands/history/history-compact.d.ts +7 -0
  28. package/dist/cli/commands/{history-compact.js → history/history-compact.js} +1 -1
  29. package/dist/cli/commands/{history-redact.d.ts → history/history-redact.d.ts} +2 -2
  30. package/dist/cli/commands/history/history-redact.js +2 -0
  31. package/dist/cli/commands/{history-repair.d.ts → history/history-repair.d.ts} +2 -2
  32. package/dist/cli/commands/{history-repair.js → history/history-repair.js} +1 -1
  33. package/dist/cli/commands/history/history.d.ts +2 -0
  34. package/dist/cli/commands/{history.js → history/history.js} +1 -1
  35. package/dist/cli/commands/history/restore.d.ts +6 -0
  36. package/dist/cli/commands/history/restore.js +2 -0
  37. package/dist/cli/commands/lifecycle/append.d.ts +2 -0
  38. package/dist/cli/commands/{append.js → lifecycle/append.js} +1 -1
  39. package/dist/cli/commands/lifecycle/claim.d.ts +2 -0
  40. package/dist/cli/commands/{claim.js → lifecycle/claim.js} +1 -1
  41. package/dist/cli/commands/lifecycle/close-many.d.ts +2 -0
  42. package/dist/cli/commands/{close-many.js → lifecycle/close-many.js} +1 -1
  43. package/dist/cli/commands/lifecycle/close.d.ts +6 -0
  44. package/dist/cli/commands/lifecycle/close.js +2 -0
  45. package/dist/cli/commands/lifecycle/copy.d.ts +6 -0
  46. package/dist/cli/commands/lifecycle/copy.js +2 -0
  47. package/dist/cli/commands/lifecycle/create.d.ts +6 -0
  48. package/dist/cli/commands/{create.js → lifecycle/create.js} +1 -1
  49. package/dist/cli/commands/lifecycle/delete.d.ts +6 -0
  50. package/dist/cli/commands/{delete.js → lifecycle/delete.js} +1 -1
  51. package/dist/cli/commands/lifecycle/focus.d.ts +6 -0
  52. package/dist/cli/commands/lifecycle/focus.js +2 -0
  53. package/dist/cli/commands/lifecycle/plan.d.ts +6 -0
  54. package/dist/cli/commands/{plan.js → lifecycle/plan.js} +1 -1
  55. package/dist/cli/commands/lifecycle/update-many.d.ts +2 -0
  56. package/dist/cli/commands/lifecycle/update-many.js +2 -0
  57. package/dist/cli/commands/lifecycle/update.d.ts +6 -0
  58. package/dist/cli/commands/{copy.js → lifecycle/update.js} +2 -2
  59. package/dist/cli/commands/query/aggregate.d.ts +2 -0
  60. package/dist/cli/commands/{aggregate.js → query/aggregate.js} +1 -1
  61. package/dist/cli/commands/query/context.d.ts +6 -0
  62. package/dist/cli/commands/{focus.js → query/context.js} +2 -2
  63. package/dist/cli/commands/{deps.d.ts → query/deps.d.ts} +2 -2
  64. package/dist/cli/commands/query/deps.js +2 -0
  65. package/dist/cli/commands/query/duplicates.d.ts +6 -0
  66. package/dist/cli/commands/{duplicates.js → query/duplicates.js} +1 -1
  67. package/dist/cli/commands/{eval.d.ts → query/eval.d.ts} +2 -2
  68. package/dist/cli/commands/{eval.js → query/eval.js} +1 -1
  69. package/dist/cli/commands/query/get.d.ts +6 -0
  70. package/dist/cli/commands/{get.js → query/get.js} +1 -1
  71. package/dist/cli/commands/{graph.d.ts → query/graph.d.ts} +2 -2
  72. package/dist/cli/commands/{graph.js → query/graph.js} +1 -1
  73. package/dist/cli/commands/{list.d.ts → query/list.d.ts} +2 -2
  74. package/dist/cli/commands/{list.js → query/list.js} +1 -1
  75. package/dist/cli/commands/{next.d.ts → query/next.d.ts} +2 -2
  76. package/dist/cli/commands/{next.js → query/next.js} +1 -1
  77. package/dist/cli/commands/query/search.d.ts +6 -0
  78. package/dist/cli/commands/{search.js → query/search.js} +1 -1
  79. package/dist/cli/commands/query/stats.d.ts +6 -0
  80. package/dist/cli/commands/{stats.js → query/stats.js} +1 -1
  81. package/dist/cli/commands/{test-all.d.ts → test/test-all.d.ts} +2 -2
  82. package/dist/cli/commands/{test-all.js → test/test-all.js} +1 -1
  83. package/dist/cli/commands/{test-runs.d.ts → test/test-runs.d.ts} +2 -2
  84. package/dist/cli/commands/{test-runs.js → test/test-runs.js} +1 -1
  85. package/dist/cli/commands/{test.d.ts → test/test.d.ts} +2 -2
  86. package/dist/cli/commands/{test.js → test/test.js} +1 -1
  87. package/dist/cli/commands/{config.d.ts → workspace/config.d.ts} +2 -2
  88. package/dist/cli/commands/{config.js → workspace/config.js} +1 -1
  89. package/dist/cli/commands/workspace/contracts.d.ts +2 -0
  90. package/dist/cli/commands/{contracts.js → workspace/contracts.js} +1 -1
  91. package/dist/cli/commands/{init.d.ts → workspace/init.d.ts} +2 -2
  92. package/dist/cli/commands/{update.js → workspace/init.js} +2 -2
  93. package/dist/cli/commands/workspace/merge.d.ts +8 -0
  94. package/dist/cli/commands/workspace/merge.js +2 -0
  95. package/dist/cli/commands/{profile.d.ts → workspace/profile.d.ts} +2 -2
  96. package/dist/cli/commands/{profile.js → workspace/profile.js} +1 -1
  97. package/dist/cli/commands/workspace/schema.d.ts +7 -0
  98. package/dist/cli/commands/workspace/schema.js +2 -0
  99. package/dist/cli/commands/workspace/upgrade.d.ts +2 -0
  100. package/dist/cli/commands/{update-many.js → workspace/upgrade.js} +2 -2
  101. package/dist/cli/register-annotations.js +1 -1
  102. package/dist/cli/register-history-activity.js +1 -1
  103. package/dist/cli/register-history-maintenance.js +1 -1
  104. package/dist/cli/register-list-query.js +1 -1
  105. package/dist/cli/register-mutation.js +1 -1
  106. package/dist/cli/register-operations.js +1 -1
  107. package/dist/cli/register-setup.js +1 -1
  108. package/dist/cli/schema/registration.js +1 -1
  109. package/dist/cli/stats-analytics-json.d.ts +1 -1
  110. package/dist/cli/stats-analytics-json.js +1 -1
  111. package/dist/cli-bundle/bundle-manifest.json +154 -154
  112. package/dist/cli-bundle/chunks/{chunk-GRHSNUQO.js → chunk-3OFFMS2N.js} +2 -2
  113. package/dist/cli-bundle/chunks/{chunk-QZTS23BV.js → chunk-4XOV7Q5R.js} +2 -2
  114. package/dist/cli-bundle/chunks/{chunk-2QLXN6HZ.js → chunk-AVWHZUNC.js} +26 -26
  115. package/dist/cli-bundle/chunks/{chunk-2UNYUB4A.js → chunk-BJBBOUYQ.js} +2 -2
  116. package/dist/cli-bundle/chunks/{chunk-JBJUOOJI.js → chunk-CM57QHVK.js} +5 -5
  117. package/dist/cli-bundle/chunks/{chunk-NHRB3L5T.js → chunk-D2OV2UBV.js} +2 -2
  118. package/dist/cli-bundle/chunks/{chunk-4SI67A2F.js → chunk-GFTN5OS4.js} +2 -2
  119. package/dist/cli-bundle/chunks/{chunk-HAFSMFJK.js → chunk-JSW33Q6R.js} +3 -3
  120. package/dist/cli-bundle/chunks/{chunk-FBWAECBI.js → chunk-ML42DLI3.js} +3 -3
  121. package/dist/cli-bundle/chunks/{chunk-SDLBF4PY.js → chunk-SBTT42A4.js} +2 -2
  122. package/dist/cli-bundle/chunks/chunk-SGFQQXFD.js +2 -0
  123. package/dist/cli-bundle/chunks/{chunk-7YUYLYJQ.js → chunk-UDNYAMCM.js} +6 -6
  124. package/dist/cli-bundle/chunks/{chunk-K7RWRJLT.js → chunk-ZSPZJOMK.js} +2 -2
  125. package/dist/cli-bundle/chunks/{register-list-query-5V43MYPN.js → register-list-query-VOS5CBX4.js} +2 -2
  126. package/dist/cli-bundle/chunks/register-mutation-LWZH6UFJ.js +20 -0
  127. package/dist/cli-bundle/chunks/{register-operations-LJU5H2CU.js → register-operations-YJK4DNFZ.js} +2 -2
  128. package/dist/cli-bundle/chunks/{register-setup-HJUNGYBB.js → register-setup-Q3CYF67Q.js} +2 -2
  129. package/dist/cli-bundle/focused-chunks/{chunk-L6L4XCLY.js → chunk-AO5FR7PN.js} +2 -2
  130. package/dist/cli-bundle/focused-chunks/{chunk-K5ZCBC6Y.js → chunk-CASXNCNQ.js} +2 -2
  131. package/dist/cli-bundle/focused-chunks/{chunk-FXAZPSU6.js → chunk-FKYUTTFL.js} +2 -2
  132. package/dist/cli-bundle/focused-chunks/{chunk-DPBTIFW7.js → chunk-IOL25GKH.js} +2 -2
  133. package/dist/cli-bundle/focused-chunks/{chunk-N6KI3LWF.js → chunk-JCD5YESL.js} +2 -2
  134. package/dist/cli-bundle/focused-chunks/{chunk-6MNKQKT6.js → chunk-LH24XUPJ.js} +2 -2
  135. package/dist/cli-bundle/focused-chunks/{chunk-IA5CCSBB.js → chunk-MXESHALQ.js} +2 -2
  136. package/dist/cli-bundle/focused-chunks/{chunk-3XPBKIV6.js → chunk-PRMQTT7X.js} +12 -12
  137. package/dist/cli-bundle/focused-chunks/{chunk-ISEOBALS.js → chunk-QFEDRPPI.js} +2 -2
  138. package/dist/cli-bundle/focused-chunks/{chunk-UIS5FVHH.js → chunk-QYN77MQP.js} +49 -49
  139. package/dist/cli-bundle/focused-chunks/{chunk-5BLRMUMK.js → chunk-TSI73EEM.js} +3 -3
  140. package/dist/cli-bundle/focused-chunks/{chunk-PC6ZZVNP.js → chunk-UAU4DJSR.js} +3 -3
  141. package/dist/cli-bundle/focused-chunks/{chunk-RQL5WLNZ.js → chunk-URH727T5.js} +2 -2
  142. package/dist/cli-bundle/focused-chunks/{chunk-U2SB2BMM.js → chunk-UT7VS4X2.js} +2 -2
  143. package/dist/cli-bundle/focused-chunks/{chunk-HYPK5OPA.js → chunk-V2NARGRH.js} +2 -2
  144. package/dist/cli-bundle/focused-chunks/{chunk-DRNXMOSV.js → chunk-XR5EBU3B.js} +2 -2
  145. package/dist/cli-bundle/main.js +18 -18
  146. package/dist/cli-bundle/sdk-authoring.js +1 -1
  147. package/dist/cli-bundle/sdk-contracts.js +1 -1
  148. package/dist/cli-bundle/sdk-core.js +3 -3
  149. package/dist/cli-bundle/sdk-governance.js +1 -1
  150. package/dist/cli-bundle/sdk-graph.js +1 -1
  151. package/dist/cli-bundle/sdk-merge.js +38 -38
  152. package/dist/cli-bundle/sdk-query.js +1 -1
  153. package/dist/cli-bundle/sdk-runtime.js +1 -1
  154. package/dist/cli-bundle/sdk-testing.js +1 -1
  155. package/dist/cli-bundle/sdk.js +1 -1
  156. package/dist/core/config/positional-value.d.ts +0 -2
  157. package/dist/core/config/positional-value.js +1 -1
  158. package/dist/core/history/history-diff.js +1 -1
  159. package/dist/core/schema/type-workflows.d.ts +1 -1
  160. package/dist/core/schema/type-workflows.js +1 -1
  161. package/dist/core/search/eval.d.ts +1 -1
  162. package/dist/core/search/eval.js +1 -1
  163. package/dist/core/shared/item-metadata-contract.d.ts +0 -4
  164. package/dist/core/shared/item-metadata-contract.js +1 -1
  165. package/dist/sdk/extension/shared.d.ts +2 -2
  166. package/dist/sdk/extension/shared.js +1 -1
  167. package/dist/sdk/governance/upgrade.d.ts +2 -0
  168. package/dist/sdk/governance/upgrade.js +2 -2
  169. package/dist/sdk/public-surface.json +1 -1
  170. package/dist/sdk/query/search-contracts.d.ts +0 -1
  171. package/dist/sdk/query/search-contracts.js +1 -1
  172. package/dist/sdk/schema.d.ts +8 -4
  173. package/dist/sdk/schema.js +1 -1
  174. package/docs/ARCHITECTURE.md +31 -4
  175. package/docs/BUILD_AND_RELEASE_ACCEPTANCE.md +50 -1
  176. package/docs/COMMANDS.md +1 -1
  177. package/docs/EXTENSIONS.md +1 -1
  178. package/docs/READ_OUTPUT_CONTRACTS.md +1 -1
  179. package/docs/RELEASING.md +7 -1
  180. package/docs/SDK_CONTEXT_INTEGRITY_PRIMITIVES.md +1 -1
  181. package/marketplace.json +2 -2
  182. package/package.json +6 -4
  183. package/packages/pm-beads/package.json +1 -1
  184. package/packages/pm-calendar/package.json +1 -1
  185. package/packages/pm-command-kit/package.json +1 -1
  186. package/packages/pm-digital-twin/package.json +1 -1
  187. package/packages/pm-governance-audit/package.json +1 -1
  188. package/packages/pm-guide-shell/package.json +1 -1
  189. package/packages/pm-kanban/package.json +1 -1
  190. package/packages/pm-lifecycle-hooks/package.json +1 -1
  191. package/packages/pm-linked-test-adapters/package.json +1 -1
  192. package/packages/pm-search-advanced/package.json +1 -1
  193. package/packages/pm-templates/package.json +1 -1
  194. package/packages/pm-todos/package.json +1 -1
  195. package/packages/pm-vcs/package.json +1 -1
  196. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  197. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  198. package/scripts/build-lease.mjs +27 -0
  199. package/dist/cli/commands/activity.d.ts +0 -6
  200. package/dist/cli/commands/aggregate.d.ts +0 -2
  201. package/dist/cli/commands/append.d.ts +0 -2
  202. package/dist/cli/commands/claim.d.ts +0 -2
  203. package/dist/cli/commands/close-many.d.ts +0 -2
  204. package/dist/cli/commands/close.d.ts +0 -6
  205. package/dist/cli/commands/close.js +0 -2
  206. package/dist/cli/commands/comments.d.ts +0 -2
  207. package/dist/cli/commands/context.d.ts +0 -6
  208. package/dist/cli/commands/context.js +0 -2
  209. package/dist/cli/commands/contracts.d.ts +0 -2
  210. package/dist/cli/commands/copy.d.ts +0 -6
  211. package/dist/cli/commands/create.d.ts +0 -6
  212. package/dist/cli/commands/delete.d.ts +0 -6
  213. package/dist/cli/commands/duplicates.d.ts +0 -6
  214. package/dist/cli/commands/extension.d.ts +0 -6
  215. package/dist/cli/commands/focus.d.ts +0 -6
  216. package/dist/cli/commands/get.d.ts +0 -6
  217. package/dist/cli/commands/health.d.ts +0 -6
  218. package/dist/cli/commands/health.js +0 -2
  219. package/dist/cli/commands/history-compact.d.ts +0 -7
  220. package/dist/cli/commands/history-redact.js +0 -2
  221. package/dist/cli/commands/history.d.ts +0 -2
  222. package/dist/cli/commands/index.d.ts +0 -55
  223. package/dist/cli/commands/index.js +0 -2
  224. package/dist/cli/commands/init-agent-guidance.d.ts +0 -6
  225. package/dist/cli/commands/init-agent-guidance.js +0 -2
  226. package/dist/cli/commands/init.js +0 -2
  227. package/dist/cli/commands/learnings.d.ts +0 -2
  228. package/dist/cli/commands/lifecycle-transitions.d.ts +0 -2
  229. package/dist/cli/commands/lifecycle-transitions.js +0 -2
  230. package/dist/cli/commands/merge.d.ts +0 -8
  231. package/dist/cli/commands/merge.js +0 -2
  232. package/dist/cli/commands/notes.d.ts +0 -2
  233. package/dist/cli/commands/plan.d.ts +0 -6
  234. package/dist/cli/commands/restore.d.ts +0 -6
  235. package/dist/cli/commands/restore.js +0 -2
  236. package/dist/cli/commands/scheduling-shortcuts.d.ts +0 -6
  237. package/dist/cli/commands/scheduling-shortcuts.js +0 -2
  238. package/dist/cli/commands/schema.d.ts +0 -7
  239. package/dist/cli/commands/schema.js +0 -2
  240. package/dist/cli/commands/search.d.ts +0 -6
  241. package/dist/cli/commands/stats.d.ts +0 -6
  242. package/dist/cli/commands/telemetry.d.ts +0 -6
  243. package/dist/cli/commands/update-many.d.ts +0 -2
  244. package/dist/cli/commands/update.d.ts +0 -6
  245. package/dist/cli/commands/upgrade.d.ts +0 -2
  246. package/dist/cli/commands/upgrade.js +0 -2
  247. package/dist/cli/commands/validate.d.ts +0 -9
  248. package/dist/cli/commands/validate.js +0 -2
  249. package/dist/cli-bundle/chunks/chunk-T3AMFUCN.js +0 -2
  250. package/dist/cli-bundle/chunks/register-mutation-DXES37MA.js +0 -20
@@ -1,7 +1,6 @@
1
1
  import type { RuntimeFieldRegistry } from "../../core/schema/runtime-schema.js";
2
2
  import type { SharedItemFilterOptions } from "./item-filter-options.js";
3
3
  import type { SearchMode } from "./search-rendering.js";
4
- export { DEFAULT_COMPACT_SEARCH_FIELDS, SEARCH_HIT_FIELD_KEYS, SEARCH_ITEM_FIELD_KEYS, listSearchProjectionFields, } from "./projection-contracts.js";
5
4
  /** Documents the search options payload exchanged by command, SDK, and package integrations. */
6
5
  export interface SearchOptions extends SharedItemFilterOptions {
7
6
  /** Value that configures or reports mode for this contract. */
@@ -1,2 +1,2 @@
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]="255d7c53-5905-51f7-8f5a-3580cf340648")}catch(e2){}})();import{coerceNumberInRange}from"../../core/shared/primitives.js";import{resolveIsoOrRelative}from"../../core/shared/time.js";import{renderPmCommand}from"../command-line.js";import{EXIT_CODE,PmCliError}from"../runtime-primitives.js";import{DEFAULT_COMPACT_SEARCH_FIELDS,listSearchProjectionFields}from"./projection-contracts.js";import{DEFAULT_COMPACT_SEARCH_FIELDS as DEFAULT_COMPACT_SEARCH_FIELDS2,SEARCH_HIT_FIELD_KEYS,SEARCH_ITEM_FIELD_KEYS,listSearchProjectionFields as listSearchProjectionFields2}from"./projection-contracts.js";function parseSearchMode(raw){if(raw===void 0)return"keyword";const normalized=raw.trim().toLowerCase();if(normalized!=="keyword"&&normalized!=="semantic"&&normalized!=="hybrid"){throw new PmCliError("Search mode must be one of keyword|semantic|hybrid",EXIT_CODE.USAGE)}return normalized}function parseSearchBoolean(raw){return raw===true}function parseSemanticWeightOverride(raw){return coerceNumberInRange(raw,0,1)??void 0}function parseSearchMatchMode(raw){if(raw===void 0)return"or";const normalized=raw.trim().toLowerCase();if(normalized!=="and"&&normalized!=="or"&&normalized!=="exact"){throw new PmCliError("Search --match-mode must be one of and|or|exact",EXIT_CODE.USAGE)}return normalized}function parseMinScoreOverride(raw){if(raw===void 0||raw===null||raw==="")return void 0;const parsed=typeof raw==="number"?raw:Number(String(raw).trim());if(!Number.isFinite(parsed)||parsed<0){throw new PmCliError("Search --min-score must be a finite number >= 0",EXIT_CODE.USAGE)}return parsed}function parseTimestampWindow(raw,fieldLabel){if(raw==null)return void 0;const value=String(raw).trim();if(value.length===0)return void 0;return resolveIsoOrRelative(value,new Date,fieldLabel)}function normalizeSearchPhrase(value){return value.toLowerCase().replace(/\s+/g," ").trim()}function parseSearchDeadline(raw,fieldLabel){if(raw===void 0)return void 0;return resolveIsoOrRelative(raw,new Date,fieldLabel)}function parseFieldSelectors(raw){if(raw===void 0)return void 0;const selectors=raw.split(",").map(entry=>entry.trim()).filter(entry=>entry.length>0);if(selectors.length===0){throw new PmCliError("Search --fields requires a comma-separated list of field names",EXIT_CODE.USAGE)}return[...new Set(selectors)]}function parseSearchProjection(options,query="<query>"){const compactRequested=options.compact===true;const fullRequested=options.full===true;const fieldSelectors=parseFieldSelectors(options.fields);const enabledModes=Number(compactRequested)+Number(fullRequested)+Number(fieldSelectors!==void 0);if(enabledModes>1){throw new PmCliError("Search projection options are mutually exclusive. Use one of --compact, --full, or --fields.",EXIT_CODE.USAGE,{code:"projection_options_mutually_exclusive",recovery:{suggested_retry:renderPmCommand(["search",query,"--full"]),suggested_retry_args:["search",query,"--full"]}})}if(compactRequested){return{mode:"compact",fields:[...DEFAULT_COMPACT_SEARCH_FIELDS]}}if(fullRequested)return{mode:"full",fields:[]};if(fieldSelectors)return{mode:"fields",fields:fieldSelectors};return{mode:"full",fields:[]}}function validateSearchProjectionFields(projection,runtimeFieldRegistry,query="<query>"){if(projection.mode!=="fields")return;const allowedValues=listSearchProjectionFields(runtimeFieldRegistry.definitions.flatMap(field=>[field.key,field.metadata_key]));const allowed=new Set(allowedValues);const unknown=projection.fields.filter(field=>{const normalized=field.trim();return!allowed.has(normalized)});if(unknown.length>0){const suggestedRetryArguments=["search",query,"--fields","id,title,status,score"];throw new PmCliError(`Unknown search --fields value(s): ${unknown.join(", ")}`,EXIT_CODE.USAGE,{code:"unknown_field_projection",examples:["pm search <query> --fields id,title,status,score","pm search <query> --fields id,title,item.description,matched_fields"],nextSteps:["Use item.<field> for explicit item metadata fields, or run pm search --help for projection examples."],recovery:{allowed_values:allowedValues,suggested_retry:renderPmCommand(suggestedRetryArguments),suggested_retry_args:suggestedRetryArguments}})}}function parseSearchTokens(query){const normalized=normalizeSearchPhrase(query);if(!normalized){throw new PmCliError("Search query must not be empty",EXIT_CODE.USAGE)}return normalized.split(/\s+/u).filter(Boolean)}function resolveSearchMaxResults(settings){const candidate=settings.search?.max_results;if(typeof candidate==="number"&&Number.isFinite(candidate)&&candidate>0){return Math.floor(candidate)}return 50}const SEARCH_DEFAULT_MODE_VALUES=["auto","keyword","semantic","hybrid"];function resolveSearchDefaultModeSetting(settings){const candidate=settings.search?.default_mode;if(typeof candidate!=="string"){return"auto"}const normalized=candidate.trim().toLowerCase();return SEARCH_DEFAULT_MODE_VALUES.includes(normalized)?normalized:"auto"}function resolveEffectiveSearchMode(params){if(typeof params.requested==="string"&&params.requested.trim().length>0){return{mode:parseSearchMode(params.requested),source:"explicit"}}const declared=resolveSearchDefaultModeSetting(params.settings);if(declared!=="auto"){return{mode:declared,source:"settings"}}return{mode:params.semanticRunnable?"hybrid":"keyword",source:"auto"}}function resolveSearchScoreThreshold(settings){const candidate=settings.search?.score_threshold;return typeof candidate==="number"&&Number.isFinite(candidate)?candidate:0}function resolveHybridSemanticWeight(settings){const candidate=settings.search?.hybrid_semantic_weight;if(typeof candidate==="number"&&Number.isFinite(candidate)&&candidate>=0&&candidate<=1){return candidate}return .7}function resolveSearchTuning(settings){const defaults={title_exact_bonus:10,title_weight:48,description_weight:5,tags_weight:6,status_weight:2,body_weight:1,comments_weight:1,notes_weight:1,learnings_weight:1,reminders_weight:2,events_weight:2,dependencies_weight:3,linked_content_weight:1};const tuning=settings.search?.tuning;if(!tuning)return defaults;const resolveWeight=(candidate,fallback)=>typeof candidate==="number"&&Number.isFinite(candidate)&&candidate>=0?candidate:fallback;return{title_exact_bonus:resolveWeight(tuning.title_exact_bonus,defaults.title_exact_bonus),title_weight:resolveWeight(tuning.title_weight,defaults.title_weight),description_weight:resolveWeight(tuning.description_weight,defaults.description_weight),tags_weight:resolveWeight(tuning.tags_weight,defaults.tags_weight),status_weight:resolveWeight(tuning.status_weight,defaults.status_weight),body_weight:resolveWeight(tuning.body_weight,defaults.body_weight),comments_weight:resolveWeight(tuning.comments_weight,defaults.comments_weight),notes_weight:resolveWeight(tuning.notes_weight,defaults.notes_weight),learnings_weight:resolveWeight(tuning.learnings_weight,defaults.learnings_weight),reminders_weight:resolveWeight(tuning.reminders_weight,defaults.reminders_weight),events_weight:resolveWeight(tuning.events_weight,defaults.events_weight),dependencies_weight:resolveWeight(tuning.dependencies_weight,defaults.dependencies_weight),linked_content_weight:resolveWeight(tuning.linked_content_weight,defaults.linked_content_weight)}}export{DEFAULT_COMPACT_SEARCH_FIELDS2 as DEFAULT_COMPACT_SEARCH_FIELDS,SEARCH_DEFAULT_MODE_VALUES,SEARCH_HIT_FIELD_KEYS,SEARCH_ITEM_FIELD_KEYS,listSearchProjectionFields2 as listSearchProjectionFields,normalizeSearchPhrase,parseMinScoreOverride,parseSearchBoolean,parseSearchDeadline,parseSearchMatchMode,parseSearchMode,parseSearchProjection,parseSearchTokens,parseSemanticWeightOverride,parseTimestampWindow,resolveEffectiveSearchMode,resolveHybridSemanticWeight,resolveSearchDefaultModeSetting,resolveSearchMaxResults,resolveSearchScoreThreshold,resolveSearchTuning,validateSearchProjectionFields};
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]="6a84083a-153e-590f-bb9b-cde96ed09a74")}catch(e2){}})();import{coerceNumberInRange}from"../../core/shared/primitives.js";import{resolveIsoOrRelative}from"../../core/shared/time.js";import{renderPmCommand}from"../command-line.js";import{EXIT_CODE,PmCliError}from"../runtime-primitives.js";import{DEFAULT_COMPACT_SEARCH_FIELDS,listSearchProjectionFields}from"./projection-contracts.js";function parseSearchMode(raw){if(raw===void 0)return"keyword";const normalized=raw.trim().toLowerCase();if(normalized!=="keyword"&&normalized!=="semantic"&&normalized!=="hybrid"){throw new PmCliError("Search mode must be one of keyword|semantic|hybrid",EXIT_CODE.USAGE)}return normalized}function parseSearchBoolean(raw){return raw===true}function parseSemanticWeightOverride(raw){return coerceNumberInRange(raw,0,1)??void 0}function parseSearchMatchMode(raw){if(raw===void 0)return"or";const normalized=raw.trim().toLowerCase();if(normalized!=="and"&&normalized!=="or"&&normalized!=="exact"){throw new PmCliError("Search --match-mode must be one of and|or|exact",EXIT_CODE.USAGE)}return normalized}function parseMinScoreOverride(raw){if(raw===void 0||raw===null||raw==="")return void 0;const parsed=typeof raw==="number"?raw:Number(String(raw).trim());if(!Number.isFinite(parsed)||parsed<0){throw new PmCliError("Search --min-score must be a finite number >= 0",EXIT_CODE.USAGE)}return parsed}function parseTimestampWindow(raw,fieldLabel){if(raw==null)return void 0;const value=String(raw).trim();if(value.length===0)return void 0;return resolveIsoOrRelative(value,new Date,fieldLabel)}function normalizeSearchPhrase(value){return value.toLowerCase().replace(/\s+/g," ").trim()}function parseSearchDeadline(raw,fieldLabel){if(raw===void 0)return void 0;return resolveIsoOrRelative(raw,new Date,fieldLabel)}function parseFieldSelectors(raw){if(raw===void 0)return void 0;const selectors=raw.split(",").map(entry=>entry.trim()).filter(entry=>entry.length>0);if(selectors.length===0){throw new PmCliError("Search --fields requires a comma-separated list of field names",EXIT_CODE.USAGE)}return[...new Set(selectors)]}function parseSearchProjection(options,query="<query>"){const compactRequested=options.compact===true;const fullRequested=options.full===true;const fieldSelectors=parseFieldSelectors(options.fields);const enabledModes=Number(compactRequested)+Number(fullRequested)+Number(fieldSelectors!==void 0);if(enabledModes>1){throw new PmCliError("Search projection options are mutually exclusive. Use one of --compact, --full, or --fields.",EXIT_CODE.USAGE,{code:"projection_options_mutually_exclusive",recovery:{suggested_retry:renderPmCommand(["search",query,"--full"]),suggested_retry_args:["search",query,"--full"]}})}if(compactRequested){return{mode:"compact",fields:[...DEFAULT_COMPACT_SEARCH_FIELDS]}}if(fullRequested)return{mode:"full",fields:[]};if(fieldSelectors)return{mode:"fields",fields:fieldSelectors};return{mode:"full",fields:[]}}function validateSearchProjectionFields(projection,runtimeFieldRegistry,query="<query>"){if(projection.mode!=="fields")return;const allowedValues=listSearchProjectionFields(runtimeFieldRegistry.definitions.flatMap(field=>[field.key,field.metadata_key]));const allowed=new Set(allowedValues);const unknown=projection.fields.filter(field=>{const normalized=field.trim();return!allowed.has(normalized)});if(unknown.length>0){const suggestedRetryArguments=["search",query,"--fields","id,title,status,score"];throw new PmCliError(`Unknown search --fields value(s): ${unknown.join(", ")}`,EXIT_CODE.USAGE,{code:"unknown_field_projection",examples:["pm search <query> --fields id,title,status,score","pm search <query> --fields id,title,item.description,matched_fields"],nextSteps:["Use item.<field> for explicit item metadata fields, or run pm search --help for projection examples."],recovery:{allowed_values:allowedValues,suggested_retry:renderPmCommand(suggestedRetryArguments),suggested_retry_args:suggestedRetryArguments}})}}function parseSearchTokens(query){const normalized=normalizeSearchPhrase(query);if(!normalized){throw new PmCliError("Search query must not be empty",EXIT_CODE.USAGE)}return normalized.split(/\s+/u).filter(Boolean)}function resolveSearchMaxResults(settings){const candidate=settings.search?.max_results;if(typeof candidate==="number"&&Number.isFinite(candidate)&&candidate>0){return Math.floor(candidate)}return 50}const SEARCH_DEFAULT_MODE_VALUES=["auto","keyword","semantic","hybrid"];function resolveSearchDefaultModeSetting(settings){const candidate=settings.search?.default_mode;if(typeof candidate!=="string"){return"auto"}const normalized=candidate.trim().toLowerCase();return SEARCH_DEFAULT_MODE_VALUES.includes(normalized)?normalized:"auto"}function resolveEffectiveSearchMode(params){if(typeof params.requested==="string"&&params.requested.trim().length>0){return{mode:parseSearchMode(params.requested),source:"explicit"}}const declared=resolveSearchDefaultModeSetting(params.settings);if(declared!=="auto"){return{mode:declared,source:"settings"}}return{mode:params.semanticRunnable?"hybrid":"keyword",source:"auto"}}function resolveSearchScoreThreshold(settings){const candidate=settings.search?.score_threshold;return typeof candidate==="number"&&Number.isFinite(candidate)?candidate:0}function resolveHybridSemanticWeight(settings){const candidate=settings.search?.hybrid_semantic_weight;if(typeof candidate==="number"&&Number.isFinite(candidate)&&candidate>=0&&candidate<=1){return candidate}return .7}function resolveSearchTuning(settings){const defaults={title_exact_bonus:10,title_weight:48,description_weight:5,tags_weight:6,status_weight:2,body_weight:1,comments_weight:1,notes_weight:1,learnings_weight:1,reminders_weight:2,events_weight:2,dependencies_weight:3,linked_content_weight:1};const tuning=settings.search?.tuning;if(!tuning)return defaults;const resolveWeight=(candidate,fallback)=>typeof candidate==="number"&&Number.isFinite(candidate)&&candidate>=0?candidate:fallback;return{title_exact_bonus:resolveWeight(tuning.title_exact_bonus,defaults.title_exact_bonus),title_weight:resolveWeight(tuning.title_weight,defaults.title_weight),description_weight:resolveWeight(tuning.description_weight,defaults.description_weight),tags_weight:resolveWeight(tuning.tags_weight,defaults.tags_weight),status_weight:resolveWeight(tuning.status_weight,defaults.status_weight),body_weight:resolveWeight(tuning.body_weight,defaults.body_weight),comments_weight:resolveWeight(tuning.comments_weight,defaults.comments_weight),notes_weight:resolveWeight(tuning.notes_weight,defaults.notes_weight),learnings_weight:resolveWeight(tuning.learnings_weight,defaults.learnings_weight),reminders_weight:resolveWeight(tuning.reminders_weight,defaults.reminders_weight),events_weight:resolveWeight(tuning.events_weight,defaults.events_weight),dependencies_weight:resolveWeight(tuning.dependencies_weight,defaults.dependencies_weight),linked_content_weight:resolveWeight(tuning.linked_content_weight,defaults.linked_content_weight)}}export{SEARCH_DEFAULT_MODE_VALUES,normalizeSearchPhrase,parseMinScoreOverride,parseSearchBoolean,parseSearchDeadline,parseSearchMatchMode,parseSearchMode,parseSearchProjection,parseSearchTokens,parseSemanticWeightOverride,parseTimestampWindow,resolveEffectiveSearchMode,resolveHybridSemanticWeight,resolveSearchDefaultModeSetting,resolveSearchMaxResults,resolveSearchScoreThreshold,resolveSearchTuning,validateSearchProjectionFields};
2
2
  //# sourceMappingURL=search-contracts.js.map
@@ -1,4 +1,4 @@
1
- import { buildInvalidTypeHint, type ItemTypeDefinition } from "../core/schema/item-types-file.js";
1
+ import { type ItemTypeDefinition } from "../core/schema/item-types-file.js";
2
2
  import { type RuntimeStatusDefinition } from "../core/schema/status-defs-file.js";
3
3
  import { type RuntimeFieldDefinition } from "../core/schema/fields-file.js";
4
4
  import { type TypePresetName } from "../core/schema/type-presets.js";
@@ -10,7 +10,13 @@ export * from "./governance/workflow-policy.js";
10
10
  export declare const SCHEMA_SUBCOMMANDS: readonly ["policies", "policy-put", "policy-remove", "policy-mode", "policy-check", "policy-approve", "policy-presets", "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"];
11
11
  /** Restricts schema subcommand values accepted by command, SDK, and storage contracts. */
12
12
  export type SchemaSubcommand = (typeof SCHEMA_SUBCOMMANDS)[number];
13
- export { formatSchemaEvolutionMigrationHuman, planSchemaEvolutionMigration, runSchemaEvolutionMigration, type PlanSchemaEvolutionMigrationOptions, type RunSchemaEvolutionMigrationOptions, type SchemaEvolutionFieldChange, type SchemaEvolutionItemPlan, type SchemaEvolutionMigrationPlan, type SchemaEvolutionMigrationRequest, type SchemaEvolutionMigrationResult, } from "./schema-migration.js";
13
+ export { formatSchemaEvolutionMigrationHuman, runSchemaEvolutionMigration, type RunSchemaEvolutionMigrationOptions, type SchemaEvolutionMigrationRequest, type SchemaEvolutionMigrationResult, } from "./schema-migration.js";
14
+ /**
15
+ * Planning-only migration contracts exposed by the published SDK for package
16
+ * authors. The CLI executes migrations but does not consume these exports.
17
+ * @public
18
+ */
19
+ export { planSchemaEvolutionMigration, type PlanSchemaEvolutionMigrationOptions, type SchemaEvolutionFieldChange, type SchemaEvolutionItemPlan, type SchemaEvolutionMigrationPlan, } from "./schema-migration.js";
14
20
  /** Documents the schema add type command options payload exchanged by command, SDK, and package integrations. */
15
21
  export interface SchemaAddTypeCommandOptions {
16
22
  /** Value that configures or reports description for this contract. */
@@ -499,8 +505,6 @@ export declare function formatSchemaShowFieldHuman(result: SchemaShowFieldResult
499
505
  export declare function formatSchemaApplyPresetHuman(result: SchemaApplyPresetResult): string;
500
506
  /** Implements format schema infer types human for the public runtime surface of this module. */
501
507
  export declare function formatSchemaInferTypesHuman(result: SchemaAddTypeInferResult): string;
502
- /** Re-export so register-mutation can surface the hint in usage examples without importing the core module directly. */
503
- export { buildInvalidTypeHint };
504
508
  export type { RuntimeFieldDefinition, RuntimeFieldValueSchema, } from "../core/schema/fields-file.js";
505
509
  /** Public contract for test only schema command, shared by SDK and presentation-layer consumers. */
506
510
  export declare const _testOnlySchemaCommand: {
@@ -1,2 +1,2 @@
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};
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]="1805dfab-5dc5-5be4-ad32-cbd8b3e37f8c")}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,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,runSchemaEvolutionMigration}from"./schema-migration.js";import{planSchemaEvolutionMigration}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,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};
2
2
  //# sourceMappingURL=schema.js.map
@@ -46,6 +46,14 @@ src/
46
46
  schema/
47
47
  registration.ts
48
48
  commands/
49
+ annotations/
50
+ history/
51
+ lifecycle/
52
+ query/
53
+ workspace/
54
+ governance/
55
+ test/
56
+ extension/
49
57
  help-content.ts
50
58
  error-guidance.ts
51
59
  extension-command-options.ts
@@ -273,10 +281,10 @@ applies:
273
281
  1. **Commander registration** — register the command/flag in the relevant
274
282
  `src/cli/register-*.ts` family module (`register-setup`, `register-list-query`,
275
283
  `register-mutation`, `register-operations`).
276
- 2. **Command module** — implement the handler under `src/cli/commands/` and add
277
- it to the `src/cli/commands/index.ts` barrel. The static orphan-modules gate
278
- fails on a command module that only the dynamic dispatcher imports, so the
279
- barrel export is mandatory.
284
+ 2. **SDK operation** — implement domain behavior in `src/sdk/` and expose it
285
+ through the appropriate published SDK entrypoint. Register the CLI adapter
286
+ directly in its command family. Private command barrels are unnecessary;
287
+ executable consumers and published entrypoints establish module reachability.
280
288
  3. **Flag contracts** — declare flags in `src/sdk/cli-contracts.ts` (the
281
289
  `*_FLAG_CONTRACTS` registries). Use `list: true` only for comma-list
282
290
  accumulation flags, never for Commander `collect` repeatable flags. Flags that
@@ -300,6 +308,25 @@ applies:
300
308
  Verify the end-to-end surface with `pm contracts --command <name> --json`,
301
309
  `pm help <name> --json`, and the matching MCP tool listing.
302
310
 
311
+ ## Private Export and Directory Boundaries
312
+
313
+ Command adapters and their specs are grouped by domain under
314
+ `src/cli/commands/` and `tests/unit/commands/`. Registration stays in the
315
+ CLI family modules; domain behavior stays in the SDK. The removed private
316
+ command barrel is not a package entrypoint.
317
+
318
+ `pnpm quality:exports` runs Knip with zero allowed unused values or types,
319
+ then executes an isolated negative control that introduces both kinds of dead
320
+ export. The configured entrypoints are published SDK/bin sources, package
321
+ activation modules, executable examples, and the invoked static-gate module.
322
+ Only externally consumed entrypoint exports and declarations used inside their
323
+ own module are retained without an internal importer. There is no directory-wide
324
+ SDK ignore rule. Explicit public migration re-exports remain available to
325
+ package authors; the SDK surface snapshot separately guards their signatures.
326
+
327
+ Tracked by [pm-f4yn](../.agents/pm/tasks/pm-f4yn.toon) and
328
+ [pm-kb5h](../.agents/pm/chores/pm-kb5h.toon).
329
+
303
330
  ## SDK-First Boundary
304
331
 
305
332
  The target layering is: `src/core` remains private implementation detail,
@@ -1,7 +1,10 @@
1
1
  # Build generations and registry acceptance
2
2
 
3
3
  Tracked by [pm-cxc4jc](../.agents/pm/tasks/pm-cxc4jc.toon) and
4
- [pm-ygli86](../.agents/pm/tasks/pm-ygli86.toon).
4
+ [pm-ygli86](../.agents/pm/tasks/pm-ygli86.toon). Ownership recovery and temporary
5
+ workspace lifecycle follow-ups are
6
+ [pm-63i8nr](../.agents/pm/tasks/pm-63i8nr.toon) and
7
+ [pm-p5u6](../.agents/pm/chores/pm-p5u6.toon).
5
8
 
6
9
  ## Complete build ownership
7
10
 
@@ -18,6 +21,12 @@ other test workers consume them would violate the generation boundary. Fixtures
18
21
  that exercise the build orchestrator must use independent temporary workspaces.
19
22
 
20
23
  The lease never expires based on its age and is never automatically stolen.
24
+ While waiting, the runner probes the recorded owner's process identifier. If
25
+ the process is definitively absent and a second read confirms the same owner,
26
+ it fails promptly with the receipt path and recovery instructions. Missing,
27
+ malformed, changing, and permission-ambiguous receipts remain protected and use
28
+ the ordinary acquisition timeout. PID reuse can make a departed owner appear
29
+ live; the probe is a conservative diagnostic, not proof of process identity.
21
30
  After an interrupted process, inspect the owner and its children before removing
22
31
  an abandoned lease. A failed build leaves `.cache/build-incomplete`; prebuilt
23
32
  tests refuse that generation until a successful `pnpm build` clears the marker.
@@ -25,6 +34,46 @@ Direct invocations of individual build stages or arbitrary reads of `dist` do
25
34
  not participate in this protocol. Use the build and test entrypoints for
26
35
  concurrent validation.
27
36
 
37
+ ## Owned temporary workspaces
38
+
39
+ Package smoke, external-package smoke, package-first dogfood, contract snapshots,
40
+ plugin MCP smoke, and the sandboxed test runner register their temporary roots
41
+ with the shared lifecycle helper. Release preparation, installed-agent and
42
+ published-package verification, compatibility checks, isolated regression
43
+ controls, context evaluation, intent calibration, refusal probes, and the point
44
+ and context read benchmarks also register their owned roots. Normal completion
45
+ releases the registration after cleanup. Synchronous
46
+ workspaces also clean on process exit, including uncaught failure. SIGINT and
47
+ SIGTERM run registered cleanup before returning exit codes 130 and 143.
48
+
49
+ An asynchronous producer must provide bounded shutdown. The plugin harness
50
+ waits for its MCP child to close before removing its workspace; shutdown failure
51
+ retains the directory and reports its path. An abrupt exit cannot await that
52
+ shutdown, so it also retains asynchronous workspaces. Explicit keep-temp modes
53
+ do not register cleanup. No cleanup scans or deletes unrelated temporary roots.
54
+
55
+ The test runner stops its active build or test child on interruption, closes
56
+ admission to later stages, and waits up to five seconds for the runner to settle.
57
+ That wait includes release of its build lease and ordinary cleanup. If the child
58
+ does not stop, the workspace is retained and its location is reported. A signal
59
+ must never remove files still being used by a test process. Real subprocess
60
+ regressions exercise both build-enabled and prebuilt execution, alongside
61
+ installer failures that call `process.exit` and therefore bypass `finally`.
62
+
63
+ Package-first dogfood disables telemetry for its synthetic child commands so
64
+ detached flush workers cannot recreate the workspace after cleanup. Dedicated
65
+ telemetry acceptance and the live Sentry/telemetry gate verify delivery.
66
+
67
+ Release-note integration fixtures own their changelog, generator location, and
68
+ Git lookup directory. Both a dated-only changelog and an Unreleased section are
69
+ tested against the same real over-budget tracker. Release preparation can
70
+ therefore regenerate the checkout changelog without changing test inputs.
71
+
72
+ These handlers cannot run after SIGKILL, power loss, or Windows forced process
73
+ termination. Native signal acceptance runs on Unix; callback and normal-exit
74
+ contracts also run on Windows. The remaining script-wide migration stays tracked
75
+ by pm-p5u6 rather than treating these covered entrypoints as complete adoption.
76
+
28
77
  ## Published candidate and control
29
78
 
30
79
  The Release workflow publishes npm artifacts once, verifies executors, and
package/docs/COMMANDS.md CHANGED
@@ -550,7 +550,7 @@ and all clear/replace operations stay restricted or use their dedicated commands
550
550
  ```bash
551
551
  pm update <id> \
552
552
  --comment "Audit evidence: reproduced in staging" \
553
- --file "path=src/cli/commands/update.ts,scope=project,note=audit evidence" \
553
+ --file "path=src/cli/commands/lifecycle/update.ts,scope=project,note=audit evidence" \
554
554
  --doc "path=docs/COMMANDS.md,scope=project,note=user-facing behavior" \
555
555
  --message "Append audit evidence"
556
556
  ```
@@ -398,7 +398,7 @@ pm package upgrade todos --dry-run
398
398
  pm package upgrade --cli-only --repair
399
399
  ```
400
400
 
401
- CLI/SDK upgrades use `npm install -g @unbrained/pm-cli@<tag>`. Managed package upgrades reuse the source recorded at install time, including registry, GitHub, local, and first-party package sources.
401
+ CLI/SDK upgrades use `npm install -g @unbrained/pm-cli@<tag>`. Managed package upgrades reuse the source recorded at install time, including registry, GitHub, local, and first-party package sources. Canonical CLI upgrade receipts include `cli.migration_guidance`, including dry-run plans. Scheduling lives in the optional calendar package: install it with `pm package install calendar --project`, then use `pm calendar meet`, `pm calendar event`, or `pm calendar remind`. Legacy `meet`, `event`, and `remind` shortcuts remain usable after installation; before installation, both text and JSON errors identify the owning package and the install command. An upgrade does not install optional workflows automatically. Tracked by [pm-o3fh](../.agents/pm/tasks/pm-o3fh.toon).
402
402
 
403
403
  ## Automation Patterns
404
404
 
@@ -298,5 +298,5 @@ The full runtime contract reports every surface and all four dimensions. Strict
298
298
  pnpm contracts:check
299
299
  node scripts/run-tests.mjs test -- tests/unit/sdk/read-output-contracts.spec.ts
300
300
  node scripts/run-tests.mjs test -- tests/unit/sdk/read-output-migration-hints.spec.ts
301
- node scripts/run-tests.mjs test -- tests/unit/commands/completion-command.spec.ts
301
+ node scripts/run-tests.mjs test -- tests/unit/commands/workspace/completion-command.spec.ts
302
302
  ```
package/docs/RELEASING.md CHANGED
@@ -387,7 +387,13 @@ git push origin v<version>
387
387
  `sentry-injected` packlist budget over the exact publishable bytes, and only
388
388
  then optional Sentry release metadata/upload/finalization and the npx tarball
389
389
  smoke test
390
- - generated release notes from changelog plus sanitized tracker metadata
390
+ - generated release notes from changelog plus sanitized tracker metadata. The
391
+ tracker read projects only release-relevant fields and explicitly removes row
392
+ and token limits. The generator validates the completeness receipt before
393
+ summarizing; partial, unreadable, or malformed input produces a visible warning
394
+ instead of claiming no items closed. The regression suite exercises a real
395
+ workspace exceeding the default JSON budget. Tracked by
396
+ [pm-svxdsx](../.agents/pm/issues/pm-svxdsx.toon).
391
397
  - artifact uploads
392
398
  - `npm publish --access public --provenance --tag latest`, skipped on retry
393
399
  only when the exact version is anonymously visible from a fresh npm cache.
@@ -87,7 +87,7 @@ artifact in a fresh temporary project:
87
87
 
88
88
  ```bash
89
89
  pnpm build
90
- node scripts/run-tests.mjs test -- tests/unit/commands/test-command.spec.ts
90
+ node scripts/run-tests.mjs test -- tests/unit/commands/test/test-command.spec.ts
91
91
  ```
92
92
 
93
93
  ## Workspace relocation diagnostics
package/marketplace.json CHANGED
@@ -6,14 +6,14 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Official marketplace for pm CLI — native git-based project management for Claude Code and AI coding agents.",
9
- "version": "2026.9.21"
9
+ "version": "2026.9.22"
10
10
  },
11
11
  "plugins": [
12
12
  {
13
13
  "name": "pm-claude",
14
14
  "source": "./plugins/pm-claude",
15
15
  "description": "Native pm CLI integration for Claude Code — 28 MCP tools, 5 workflow skills, 14 slash commands, 4 subagents, hybrid TUI task tracking, session context injection, and coordination subagents for git-based project management without leaving Claude Code.",
16
- "version": "2026.9.21",
16
+ "version": "2026.9.22",
17
17
  "author": {
18
18
  "name": "unbrained",
19
19
  "url": "https://github.com/unbraind/pm-cli"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unbrained/pm-cli",
3
- "version": "2026.9.21",
3
+ "version": "2026.9.22",
4
4
  "description": "Git-native project management CLI for humans and agents.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@11.10.0",
@@ -123,7 +123,8 @@
123
123
  "lint:complexity:baseline": "eslint . --suppress-rule complexity --suppress-rule sonarjs/cognitive-complexity",
124
124
  "lint:duplicates": "jscpd --config .jscpd.json && jscpd --config .jscpd.source.json && jscpd --config .jscpd.tables.json",
125
125
  "lint:codefactor": "pnpm quality:static",
126
- "quality:static": "pnpm lint:eslint && pnpm lint:duplicates && pnpm build && node scripts/contracts-snapshot.mjs --check && node scripts/generate-agent-capability-surfaces.mjs --check && node scripts/generate-error-code-catalog.mjs --check && node scripts/release/repository-assurance.mjs repository-static-quality --trigger ci --json && node scripts/release/audit-package-boundary.mjs && node scripts/release/package-sdk-contract-parity.mjs && node scripts/release/surface-replication-gate.mjs && node scripts/release/command-grammar-gate.mjs && node scripts/release/flag-invocation-parity.mjs && node scripts/release/flag-lexicon-gate.mjs && node scripts/release/refusal-closure-gate.mjs && node scripts/release/agent-task-token-gate.mjs && pnpm quality:mcp-deprecations && node dist/cli.js assurance run tracker-context-quality --trigger ci --dry-run --json --output-budget unbounded && node scripts/release/gate-registry.mjs && node scripts/sdk-surface-snapshot.mjs --check && node scripts/bench/sdk-entrypoint-costs.mjs --check && node scripts/bench/cli-transport-floor.mjs --check && node dist/cli.js assurance run graph-composition --trigger ci --dry-run --json --output-budget unbounded && node dist/cli.js assurance run record-integrity --trigger ci --dry-run --json --output-budget unbounded",
126
+ "quality:static": "pnpm quality:exports && pnpm lint:eslint && pnpm lint:duplicates && pnpm build && node scripts/contracts-snapshot.mjs --check && node scripts/generate-agent-capability-surfaces.mjs --check && node scripts/generate-error-code-catalog.mjs --check && node scripts/release/repository-assurance.mjs repository-static-quality --trigger ci --json && node scripts/release/audit-package-boundary.mjs && node scripts/release/package-sdk-contract-parity.mjs && node scripts/release/surface-replication-gate.mjs && node scripts/release/command-grammar-gate.mjs && node scripts/release/flag-invocation-parity.mjs && node scripts/release/flag-lexicon-gate.mjs && node scripts/release/refusal-closure-gate.mjs && node scripts/release/agent-task-token-gate.mjs && pnpm quality:mcp-deprecations && node dist/cli.js assurance run tracker-context-quality --trigger ci --dry-run --json --output-budget unbounded && node scripts/release/gate-registry.mjs && node scripts/sdk-surface-snapshot.mjs --check && node scripts/bench/sdk-entrypoint-costs.mjs --check && node scripts/bench/cli-transport-floor.mjs --check && node dist/cli.js assurance run graph-composition --trigger ci --dry-run --json --output-budget unbounded && node dist/cli.js assurance run record-integrity --trigger ci --dry-run --json --output-budget unbounded",
127
+ "quality:exports": "knip --no-config-hints && node scripts/run-tests.mjs test -- tests/unit/scripts/release/dead-exports.spec.ts",
127
128
  "quality:command-grammar": "pnpm build && node scripts/release/command-grammar-gate.mjs && node scripts/release/flag-invocation-parity.mjs && node scripts/release/flag-lexicon-gate.mjs",
128
129
  "quality:recovery-closure": "pnpm build && node scripts/release/refusal-closure-gate.mjs",
129
130
  "quality:token-budget": "node scripts/release/token-budget-gate.mjs",
@@ -229,13 +230,14 @@
229
230
  "eslint": "^10.11.0",
230
231
  "eslint-plugin-sonarjs": "^4.2.1",
231
232
  "eslint-plugin-unicorn": "76.0.0",
232
- "fast-check": "^4.10.1",
233
+ "fast-check": "^4.10.2",
233
234
  "github-slugger": "2.0.0",
234
235
  "greptile": "^3.5.3",
235
236
  "jscpd": "^5.3.0",
237
+ "knip": "^6.37.0",
236
238
  "marked": "18.0.13",
237
239
  "parse5": "8.0.1",
238
- "tsx": "^4.23.13",
240
+ "tsx": "^4.23.15",
239
241
  "typescript": "^6.0.3",
240
242
  "typescript-eslint": "^8.70.0",
241
243
  "vitest": "^4.1.11"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unbrained/pm-beads",
3
- "version": "2026.9.21",
3
+ "version": "2026.9.22",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "First-party pm package for importing Beads JSONL records.",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unbrained/pm-calendar",
3
- "version": "2026.9.21",
3
+ "version": "2026.9.22",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "First-party pm package for calendar and agenda views.",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unbrained/pm-command-kit",
3
- "version": "2026.9.21",
3
+ "version": "2026.9.22",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "First-party pm exemplar package for the commands capability: registerCommand, registerFlags, and registerParser.",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unbrained/pm-digital-twin",
3
- "version": "2026.9.21",
3
+ "version": "2026.9.22",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "Beyond-PM exemplar: a temporal production-facility digital twin built entirely on public pm SDK and extension primitives.",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unbrained/pm-governance-audit",
3
- "version": "2026.9.21",
3
+ "version": "2026.9.22",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "First-party pm package for governance audit and normalization workflows.",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unbrained/pm-guide-shell",
3
- "version": "2026.9.21",
3
+ "version": "2026.9.22",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "First-party pm package for guide and shell completion workflows.",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unbrained/pm-kanban",
3
- "version": "2026.9.21",
3
+ "version": "2026.9.22",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "First-party pm archetype package: a complete Kanban continuous-flow profile built on public SDK primitives.",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unbrained/pm-lifecycle-hooks",
3
- "version": "2026.9.21",
3
+ "version": "2026.9.22",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "First-party pm package demonstrating safe lifecycle hook registration.",