@unbrained/pm-cli 2026.3.12 → 2026.5.1-2

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 (285) hide show
  1. package/.agents/pm/extensions/.managed-extensions.json +42 -0
  2. package/.agents/pm/extensions/beads/index.js +109 -0
  3. package/.agents/pm/extensions/beads/manifest.json +7 -0
  4. package/{dist/cli/commands/beads.js → .agents/pm/extensions/beads/runtime.js} +31 -21
  5. package/.agents/pm/extensions/beads/runtime.ts +702 -0
  6. package/.agents/pm/extensions/todos/index.js +126 -0
  7. package/.agents/pm/extensions/todos/manifest.json +7 -0
  8. package/{dist/extensions/builtins/todos/import-export.js → .agents/pm/extensions/todos/runtime.js} +39 -29
  9. package/.agents/pm/extensions/todos/runtime.ts +568 -0
  10. package/AGENTS.md +196 -92
  11. package/CHANGELOG.md +404 -0
  12. package/CODE_OF_CONDUCT.md +42 -0
  13. package/CONTRIBUTING.md +144 -0
  14. package/PRD.md +512 -164
  15. package/README.md +1053 -2
  16. package/SECURITY.md +51 -0
  17. package/dist/cli/commands/activity.d.ts +5 -0
  18. package/dist/cli/commands/activity.js +66 -3
  19. package/dist/cli/commands/activity.js.map +1 -1
  20. package/dist/cli/commands/aggregate.d.ts +54 -0
  21. package/dist/cli/commands/aggregate.js +181 -0
  22. package/dist/cli/commands/aggregate.js.map +1 -0
  23. package/dist/cli/commands/append.js +4 -1
  24. package/dist/cli/commands/append.js.map +1 -1
  25. package/dist/cli/commands/calendar.d.ts +109 -0
  26. package/dist/cli/commands/calendar.js +797 -0
  27. package/dist/cli/commands/calendar.js.map +1 -0
  28. package/dist/cli/commands/claim.d.ts +5 -1
  29. package/dist/cli/commands/claim.js +42 -21
  30. package/dist/cli/commands/claim.js.map +1 -1
  31. package/dist/cli/commands/close.d.ts +1 -0
  32. package/dist/cli/commands/close.js +54 -5
  33. package/dist/cli/commands/close.js.map +1 -1
  34. package/dist/cli/commands/comments-audit.d.ts +91 -0
  35. package/dist/cli/commands/comments-audit.js +195 -0
  36. package/dist/cli/commands/comments-audit.js.map +1 -0
  37. package/dist/cli/commands/comments.d.ts +1 -0
  38. package/dist/cli/commands/comments.js +70 -21
  39. package/dist/cli/commands/comments.js.map +1 -1
  40. package/dist/cli/commands/completion.d.ts +10 -4
  41. package/dist/cli/commands/completion.js +1184 -137
  42. package/dist/cli/commands/completion.js.map +1 -1
  43. package/dist/cli/commands/config.d.ts +35 -3
  44. package/dist/cli/commands/config.js +968 -13
  45. package/dist/cli/commands/config.js.map +1 -1
  46. package/dist/cli/commands/context.d.ts +86 -0
  47. package/dist/cli/commands/context.js +299 -0
  48. package/dist/cli/commands/context.js.map +1 -0
  49. package/dist/cli/commands/contracts.d.ts +78 -0
  50. package/dist/cli/commands/contracts.js +920 -0
  51. package/dist/cli/commands/contracts.js.map +1 -0
  52. package/dist/cli/commands/create.d.ts +48 -14
  53. package/dist/cli/commands/create.js +1331 -160
  54. package/dist/cli/commands/create.js.map +1 -1
  55. package/dist/cli/commands/dedupe-audit.d.ts +81 -0
  56. package/dist/cli/commands/dedupe-audit.js +330 -0
  57. package/dist/cli/commands/dedupe-audit.js.map +1 -0
  58. package/dist/cli/commands/deps.d.ts +52 -0
  59. package/dist/cli/commands/deps.js +204 -0
  60. package/dist/cli/commands/deps.js.map +1 -0
  61. package/dist/cli/commands/docs.d.ts +19 -0
  62. package/dist/cli/commands/docs.js +212 -13
  63. package/dist/cli/commands/docs.js.map +1 -1
  64. package/dist/cli/commands/extension.d.ts +122 -0
  65. package/dist/cli/commands/extension.js +1850 -0
  66. package/dist/cli/commands/extension.js.map +1 -0
  67. package/dist/cli/commands/files.d.ts +52 -1
  68. package/dist/cli/commands/files.js +455 -13
  69. package/dist/cli/commands/files.js.map +1 -1
  70. package/dist/cli/commands/gc.d.ts +11 -1
  71. package/dist/cli/commands/gc.js +89 -11
  72. package/dist/cli/commands/gc.js.map +1 -1
  73. package/dist/cli/commands/get.d.ts +13 -0
  74. package/dist/cli/commands/get.js +35 -3
  75. package/dist/cli/commands/get.js.map +1 -1
  76. package/dist/cli/commands/health.d.ts +10 -2
  77. package/dist/cli/commands/health.js +774 -23
  78. package/dist/cli/commands/health.js.map +1 -1
  79. package/dist/cli/commands/history.d.ts +20 -0
  80. package/dist/cli/commands/history.js +152 -6
  81. package/dist/cli/commands/history.js.map +1 -1
  82. package/dist/cli/commands/index.d.ts +16 -3
  83. package/dist/cli/commands/index.js +16 -3
  84. package/dist/cli/commands/index.js.map +1 -1
  85. package/dist/cli/commands/init.d.ts +7 -2
  86. package/dist/cli/commands/init.js +137 -5
  87. package/dist/cli/commands/init.js.map +1 -1
  88. package/dist/cli/commands/learnings.d.ts +17 -0
  89. package/dist/cli/commands/learnings.js +129 -0
  90. package/dist/cli/commands/learnings.js.map +1 -0
  91. package/dist/cli/commands/list.d.ts +29 -1
  92. package/dist/cli/commands/list.js +289 -53
  93. package/dist/cli/commands/list.js.map +1 -1
  94. package/dist/cli/commands/normalize.d.ts +51 -0
  95. package/dist/cli/commands/normalize.js +298 -0
  96. package/dist/cli/commands/normalize.js.map +1 -0
  97. package/dist/cli/commands/notes.d.ts +17 -0
  98. package/dist/cli/commands/notes.js +129 -0
  99. package/dist/cli/commands/notes.js.map +1 -0
  100. package/dist/cli/commands/reindex.d.ts +1 -0
  101. package/dist/cli/commands/reindex.js +208 -32
  102. package/dist/cli/commands/reindex.js.map +1 -1
  103. package/dist/cli/commands/restore.js +164 -30
  104. package/dist/cli/commands/restore.js.map +1 -1
  105. package/dist/cli/commands/search.d.ts +14 -1
  106. package/dist/cli/commands/search.js +475 -81
  107. package/dist/cli/commands/search.js.map +1 -1
  108. package/dist/cli/commands/stats.js +26 -10
  109. package/dist/cli/commands/stats.js.map +1 -1
  110. package/dist/cli/commands/templates.d.ts +26 -0
  111. package/dist/cli/commands/templates.js +179 -0
  112. package/dist/cli/commands/templates.js.map +1 -0
  113. package/dist/cli/commands/test-all.d.ts +19 -1
  114. package/dist/cli/commands/test-all.js +161 -13
  115. package/dist/cli/commands/test-all.js.map +1 -1
  116. package/dist/cli/commands/test-runs.d.ts +63 -0
  117. package/dist/cli/commands/test-runs.js +179 -0
  118. package/dist/cli/commands/test-runs.js.map +1 -0
  119. package/dist/cli/commands/test.d.ts +75 -1
  120. package/dist/cli/commands/test.js +1360 -41
  121. package/dist/cli/commands/test.js.map +1 -1
  122. package/dist/cli/commands/update-many.d.ts +57 -0
  123. package/dist/cli/commands/update-many.js +631 -0
  124. package/dist/cli/commands/update-many.js.map +1 -0
  125. package/dist/cli/commands/update.d.ts +30 -0
  126. package/dist/cli/commands/update.js +1393 -84
  127. package/dist/cli/commands/update.js.map +1 -1
  128. package/dist/cli/commands/validate.d.ts +30 -0
  129. package/dist/cli/commands/validate.js +1151 -0
  130. package/dist/cli/commands/validate.js.map +1 -0
  131. package/dist/cli/error-guidance.d.ts +33 -0
  132. package/dist/cli/error-guidance.js +337 -0
  133. package/dist/cli/error-guidance.js.map +1 -0
  134. package/dist/cli/extension-command-options.d.ts +1 -0
  135. package/dist/cli/extension-command-options.js +92 -0
  136. package/dist/cli/extension-command-options.js.map +1 -1
  137. package/dist/cli/help-content.d.ts +20 -0
  138. package/dist/cli/help-content.js +543 -0
  139. package/dist/cli/help-content.js.map +1 -0
  140. package/dist/cli/main.js +3625 -445
  141. package/dist/cli/main.js.map +1 -1
  142. package/dist/core/extensions/index.d.ts +13 -1
  143. package/dist/core/extensions/index.js +108 -1
  144. package/dist/core/extensions/index.js.map +1 -1
  145. package/dist/core/extensions/item-fields.d.ts +2 -0
  146. package/dist/core/extensions/item-fields.js +79 -0
  147. package/dist/core/extensions/item-fields.js.map +1 -0
  148. package/dist/core/extensions/loader.d.ts +322 -9
  149. package/dist/core/extensions/loader.js +911 -20
  150. package/dist/core/extensions/loader.js.map +1 -1
  151. package/dist/core/extensions/runtime-registrations.d.ts +5 -0
  152. package/dist/core/extensions/runtime-registrations.js +51 -0
  153. package/dist/core/extensions/runtime-registrations.js.map +1 -0
  154. package/dist/core/history/history-stream-policy.d.ts +20 -0
  155. package/dist/core/history/history-stream-policy.js +53 -0
  156. package/dist/core/history/history-stream-policy.js.map +1 -0
  157. package/dist/core/history/history.js +90 -1
  158. package/dist/core/history/history.js.map +1 -1
  159. package/dist/core/item/id.js +4 -1
  160. package/dist/core/item/id.js.map +1 -1
  161. package/dist/core/item/index.d.ts +1 -0
  162. package/dist/core/item/index.js +1 -0
  163. package/dist/core/item/index.js.map +1 -1
  164. package/dist/core/item/item-format.d.ts +11 -5
  165. package/dist/core/item/item-format.js +507 -24
  166. package/dist/core/item/item-format.js.map +1 -1
  167. package/dist/core/item/parent-reference-policy.d.ts +6 -0
  168. package/dist/core/item/parent-reference-policy.js +32 -0
  169. package/dist/core/item/parent-reference-policy.js.map +1 -0
  170. package/dist/core/item/parse.d.ts +5 -0
  171. package/dist/core/item/parse.js +216 -19
  172. package/dist/core/item/parse.js.map +1 -1
  173. package/dist/core/item/sprint-release-format.d.ts +6 -0
  174. package/dist/core/item/sprint-release-format.js +33 -0
  175. package/dist/core/item/sprint-release-format.js.map +1 -0
  176. package/dist/core/item/status.d.ts +3 -0
  177. package/dist/core/item/status.js +24 -0
  178. package/dist/core/item/status.js.map +1 -0
  179. package/dist/core/item/type-registry.d.ts +37 -0
  180. package/dist/core/item/type-registry.js +706 -0
  181. package/dist/core/item/type-registry.js.map +1 -0
  182. package/dist/core/lock/lock.d.ts +1 -1
  183. package/dist/core/lock/lock.js +101 -12
  184. package/dist/core/lock/lock.js.map +1 -1
  185. package/dist/core/output/command-aware.d.ts +1 -0
  186. package/dist/core/output/command-aware.js +394 -0
  187. package/dist/core/output/command-aware.js.map +1 -0
  188. package/dist/core/output/output.d.ts +3 -0
  189. package/dist/core/output/output.js +124 -6
  190. package/dist/core/output/output.js.map +1 -1
  191. package/dist/core/schema/runtime-field-filters.d.ts +3 -0
  192. package/dist/core/schema/runtime-field-filters.js +39 -0
  193. package/dist/core/schema/runtime-field-filters.js.map +1 -0
  194. package/dist/core/schema/runtime-field-values.d.ts +8 -0
  195. package/dist/core/schema/runtime-field-values.js +154 -0
  196. package/dist/core/schema/runtime-field-values.js.map +1 -0
  197. package/dist/core/schema/runtime-schema.d.ts +68 -0
  198. package/dist/core/schema/runtime-schema.js +554 -0
  199. package/dist/core/schema/runtime-schema.js.map +1 -0
  200. package/dist/core/search/cache.d.ts +13 -1
  201. package/dist/core/search/cache.js +123 -14
  202. package/dist/core/search/cache.js.map +1 -1
  203. package/dist/core/search/semantic-defaults.d.ts +6 -0
  204. package/dist/core/search/semantic-defaults.js +120 -0
  205. package/dist/core/search/semantic-defaults.js.map +1 -0
  206. package/dist/core/search/vector-stores.js +3 -1
  207. package/dist/core/search/vector-stores.js.map +1 -1
  208. package/dist/core/shared/command-types.d.ts +2 -0
  209. package/dist/core/shared/conflict-markers.d.ts +7 -0
  210. package/dist/core/shared/conflict-markers.js +27 -0
  211. package/dist/core/shared/conflict-markers.js.map +1 -0
  212. package/dist/core/shared/constants.d.ts +15 -4
  213. package/dist/core/shared/constants.js +141 -1
  214. package/dist/core/shared/constants.js.map +1 -1
  215. package/dist/core/shared/errors.d.ts +10 -1
  216. package/dist/core/shared/errors.js +3 -1
  217. package/dist/core/shared/errors.js.map +1 -1
  218. package/dist/core/shared/text-normalization.d.ts +4 -0
  219. package/dist/core/shared/text-normalization.js +33 -0
  220. package/dist/core/shared/text-normalization.js.map +1 -0
  221. package/dist/core/shared/time.d.ts +1 -2
  222. package/dist/core/shared/time.js +98 -11
  223. package/dist/core/shared/time.js.map +1 -1
  224. package/dist/core/store/index.d.ts +1 -0
  225. package/dist/core/store/index.js +1 -0
  226. package/dist/core/store/index.js.map +1 -1
  227. package/dist/core/store/item-format-migration.d.ts +9 -0
  228. package/dist/core/store/item-format-migration.js +87 -0
  229. package/dist/core/store/item-format-migration.js.map +1 -0
  230. package/dist/core/store/item-store.d.ts +13 -4
  231. package/dist/core/store/item-store.js +238 -51
  232. package/dist/core/store/item-store.js.map +1 -1
  233. package/dist/core/store/paths.d.ts +21 -3
  234. package/dist/core/store/paths.js +59 -4
  235. package/dist/core/store/paths.js.map +1 -1
  236. package/dist/core/store/settings.d.ts +14 -1
  237. package/dist/core/store/settings.js +463 -7
  238. package/dist/core/store/settings.js.map +1 -1
  239. package/dist/core/telemetry/consent.d.ts +2 -0
  240. package/dist/core/telemetry/consent.js +79 -0
  241. package/dist/core/telemetry/consent.js.map +1 -0
  242. package/dist/core/telemetry/runtime.d.ts +38 -0
  243. package/dist/core/telemetry/runtime.js +733 -0
  244. package/dist/core/telemetry/runtime.js.map +1 -0
  245. package/dist/core/test/background-runs.d.ts +117 -0
  246. package/dist/core/test/background-runs.js +760 -0
  247. package/dist/core/test/background-runs.js.map +1 -0
  248. package/dist/core/test/item-test-run-tracking.d.ts +9 -0
  249. package/dist/core/test/item-test-run-tracking.js +50 -0
  250. package/dist/core/test/item-test-run-tracking.js.map +1 -0
  251. package/dist/sdk/cli-contracts.d.ts +92 -0
  252. package/dist/sdk/cli-contracts.js +2357 -0
  253. package/dist/sdk/cli-contracts.js.map +1 -0
  254. package/dist/sdk/index.d.ts +34 -0
  255. package/dist/sdk/index.js +23 -0
  256. package/dist/sdk/index.js.map +1 -0
  257. package/dist/types.d.ts +197 -3
  258. package/dist/types.js +48 -1
  259. package/dist/types.js.map +1 -1
  260. package/docs/ARCHITECTURE.md +368 -39
  261. package/docs/EXTENSIONS.md +454 -49
  262. package/docs/RELEASING.md +70 -19
  263. package/docs/SDK.md +123 -0
  264. package/docs/examples/starter-extension/README.md +48 -0
  265. package/docs/examples/starter-extension/index.js +191 -0
  266. package/docs/examples/starter-extension/manifest.json +17 -0
  267. package/docs/examples/starter-extension/package.json +10 -0
  268. package/package.json +41 -14
  269. package/.pi/extensions/pm-cli/index.ts +0 -778
  270. package/dist/cli/commands/beads.d.ts +0 -16
  271. package/dist/cli/commands/beads.js.map +0 -1
  272. package/dist/cli/commands/install.d.ts +0 -18
  273. package/dist/cli/commands/install.js +0 -87
  274. package/dist/cli/commands/install.js.map +0 -1
  275. package/dist/core/extensions/builtins.d.ts +0 -3
  276. package/dist/core/extensions/builtins.js +0 -47
  277. package/dist/core/extensions/builtins.js.map +0 -1
  278. package/dist/extensions/builtins/beads/index.d.ts +0 -8
  279. package/dist/extensions/builtins/beads/index.js +0 -33
  280. package/dist/extensions/builtins/beads/index.js.map +0 -1
  281. package/dist/extensions/builtins/todos/import-export.d.ts +0 -26
  282. package/dist/extensions/builtins/todos/import-export.js.map +0 -1
  283. package/dist/extensions/builtins/todos/index.d.ts +0 -8
  284. package/dist/extensions/builtins/todos/index.js +0 -38
  285. package/dist/extensions/builtins/todos/index.js.map +0 -1
@@ -1,23 +1,438 @@
1
1
  import { pathExists } from "../../core/fs/fs-utils.js";
2
- import { parseOptionalNumber, parseTags } from "../../core/item/parse.js";
2
+ import { canonicalizeCommandOptionKey, commandOptionFlagLabel, resolveItemTypeRegistry, resolveCommandOptionPolicyState, resolveTypeDefinition, resolveTypeName, validateTypeOptions, } from "../../core/item/type-registry.js";
3
+ import { normalizeItemId } from "../../core/item/id.js";
4
+ import { normalizeParentReferenceValue, validateMissingParentReference, } from "../../core/item/parent-reference-policy.js";
5
+ import { validateSprintOrReleaseValue } from "../../core/item/sprint-release-format.js";
6
+ import { createStdinTokenResolver, parseCsvKv, parseOptionalNumber, parseTags } from "../../core/item/parse.js";
7
+ import { normalizeStatusInput } from "../../core/item/status.js";
8
+ import { collectRuntimeUpdateFieldValues } from "../../core/schema/runtime-field-values.js";
9
+ import { resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, } from "../../core/schema/runtime-schema.js";
3
10
  import { EXIT_CODE } from "../../core/shared/constants.js";
4
11
  import { PmCliError } from "../../core/shared/errors.js";
5
- import { isNoneToken, resolveIsoOrRelative } from "../../core/shared/time.js";
6
- import { mutateItem } from "../../core/store/item-store.js";
12
+ import { resolveIsoOrRelative } from "../../core/shared/time.js";
13
+ import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
14
+ import { applyRegisteredItemFieldDefaultsAndValidation } from "../../core/extensions/item-fields.js";
15
+ import { locateItem, mutateItem } from "../../core/store/item-store.js";
7
16
  import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
8
17
  import { readSettings } from "../../core/store/settings.js";
9
- import { CONFIDENCE_TEXT_VALUES, ISSUE_SEVERITY_VALUES, ITEM_TYPE_VALUES, RISK_VALUES, STATUS_VALUES } from "../../types/index.js";
18
+ import { CONFIDENCE_TEXT_VALUES, DEPENDENCY_KIND_VALUES, ISSUE_SEVERITY_VALUES, RECURRENCE_FREQUENCY_VALUES, RECURRENCE_WEEKDAY_VALUES, RISK_VALUES, } from "../../types/index.js";
19
+ import { parseDocs, parseFiles, parseLogSeed, parseTests } from "./create.js";
20
+ const LEGACY_NONE_TOKENS = new Set(["none", "null"]);
21
+ const UPDATE_UNSET_FIELD_DEFINITIONS = [
22
+ { canonical: "tags", aliases: ["tags"], optionKey: "tags", frontMatterKey: "tags" },
23
+ { canonical: "close-reason", aliases: ["close_reason", "close-reason"], optionKey: "closeReason", frontMatterKey: "close_reason" },
24
+ { canonical: "deadline", aliases: ["deadline"], optionKey: "deadline", frontMatterKey: "deadline" },
25
+ {
26
+ canonical: "estimate",
27
+ aliases: ["estimate", "estimated_minutes", "estimated-minutes"],
28
+ optionKey: "estimatedMinutes",
29
+ frontMatterKey: "estimated_minutes",
30
+ },
31
+ {
32
+ canonical: "acceptance-criteria",
33
+ aliases: ["acceptance_criteria", "acceptance-criteria", "ac"],
34
+ optionKey: "acceptanceCriteria",
35
+ frontMatterKey: "acceptance_criteria",
36
+ },
37
+ {
38
+ canonical: "definition-of-ready",
39
+ aliases: ["definition_of_ready", "definition-of-ready"],
40
+ optionKey: "definitionOfReady",
41
+ frontMatterKey: "definition_of_ready",
42
+ },
43
+ { canonical: "order", aliases: ["order", "rank"], optionKey: "order", frontMatterKey: "order" },
44
+ { canonical: "goal", aliases: ["goal"], optionKey: "goal", frontMatterKey: "goal" },
45
+ { canonical: "objective", aliases: ["objective"], optionKey: "objective", frontMatterKey: "objective" },
46
+ { canonical: "value", aliases: ["value"], optionKey: "value", frontMatterKey: "value" },
47
+ { canonical: "impact", aliases: ["impact"], optionKey: "impact", frontMatterKey: "impact" },
48
+ { canonical: "outcome", aliases: ["outcome"], optionKey: "outcome", frontMatterKey: "outcome" },
49
+ { canonical: "why-now", aliases: ["why_now", "why-now"], optionKey: "whyNow", frontMatterKey: "why_now" },
50
+ { canonical: "assignee", aliases: ["assignee"], optionKey: "assignee", frontMatterKey: "assignee" },
51
+ { canonical: "parent", aliases: ["parent"], optionKey: "parent", frontMatterKey: "parent" },
52
+ { canonical: "reviewer", aliases: ["reviewer"], optionKey: "reviewer", frontMatterKey: "reviewer" },
53
+ { canonical: "risk", aliases: ["risk"], optionKey: "risk", frontMatterKey: "risk" },
54
+ { canonical: "confidence", aliases: ["confidence"], optionKey: "confidence", frontMatterKey: "confidence" },
55
+ { canonical: "sprint", aliases: ["sprint"], optionKey: "sprint", frontMatterKey: "sprint" },
56
+ { canonical: "release", aliases: ["release"], optionKey: "release", frontMatterKey: "release" },
57
+ {
58
+ canonical: "blocked-by",
59
+ aliases: ["blocked_by", "blocked-by"],
60
+ optionKey: "blockedBy",
61
+ frontMatterKey: "blocked_by",
62
+ },
63
+ {
64
+ canonical: "blocked-reason",
65
+ aliases: ["blocked_reason", "blocked-reason"],
66
+ optionKey: "blockedReason",
67
+ frontMatterKey: "blocked_reason",
68
+ },
69
+ {
70
+ canonical: "unblock-note",
71
+ aliases: ["unblock_note", "unblock-note"],
72
+ optionKey: "unblockNote",
73
+ frontMatterKey: "unblock_note",
74
+ },
75
+ { canonical: "reporter", aliases: ["reporter"], optionKey: "reporter", frontMatterKey: "reporter" },
76
+ { canonical: "severity", aliases: ["severity"], optionKey: "severity", frontMatterKey: "severity" },
77
+ {
78
+ canonical: "environment",
79
+ aliases: ["environment"],
80
+ optionKey: "environment",
81
+ frontMatterKey: "environment",
82
+ },
83
+ {
84
+ canonical: "repro-steps",
85
+ aliases: ["repro_steps", "repro-steps"],
86
+ optionKey: "reproSteps",
87
+ frontMatterKey: "repro_steps",
88
+ },
89
+ {
90
+ canonical: "resolution",
91
+ aliases: ["resolution"],
92
+ optionKey: "resolution",
93
+ frontMatterKey: "resolution",
94
+ },
95
+ {
96
+ canonical: "expected-result",
97
+ aliases: ["expected_result", "expected-result"],
98
+ optionKey: "expectedResult",
99
+ frontMatterKey: "expected_result",
100
+ },
101
+ {
102
+ canonical: "actual-result",
103
+ aliases: ["actual_result", "actual-result"],
104
+ optionKey: "actualResult",
105
+ frontMatterKey: "actual_result",
106
+ },
107
+ {
108
+ canonical: "affected-version",
109
+ aliases: ["affected_version", "affected-version"],
110
+ optionKey: "affectedVersion",
111
+ frontMatterKey: "affected_version",
112
+ },
113
+ {
114
+ canonical: "fixed-version",
115
+ aliases: ["fixed_version", "fixed-version"],
116
+ optionKey: "fixedVersion",
117
+ frontMatterKey: "fixed_version",
118
+ },
119
+ { canonical: "component", aliases: ["component"], optionKey: "component", frontMatterKey: "component" },
120
+ { canonical: "regression", aliases: ["regression"], optionKey: "regression", frontMatterKey: "regression" },
121
+ {
122
+ canonical: "customer-impact",
123
+ aliases: ["customer_impact", "customer-impact"],
124
+ optionKey: "customerImpact",
125
+ frontMatterKey: "customer_impact",
126
+ },
127
+ ];
128
+ const UPDATE_UNSET_ALIAS_MAP = (() => {
129
+ const map = new Map();
130
+ for (const definition of UPDATE_UNSET_FIELD_DEFINITIONS) {
131
+ for (const alias of definition.aliases) {
132
+ map.set(alias, {
133
+ optionKey: definition.optionKey,
134
+ frontMatterKey: definition.frontMatterKey,
135
+ });
136
+ }
137
+ }
138
+ return map;
139
+ })();
140
+ const UPDATE_OPTION_KEY_TO_UNSET_CANONICAL = new Map(UPDATE_UNSET_FIELD_DEFINITIONS.map((definition) => [definition.optionKey, definition.canonical]));
141
+ const UPDATE_UNSET_SUPPORTED_CANONICAL_FIELDS = UPDATE_UNSET_FIELD_DEFINITIONS.map((definition) => definition.canonical)
142
+ .sort((left, right) => left.localeCompare(right))
143
+ .join(", ");
144
+ const AUDIT_UPDATE_DISALLOWED_UNSET_FRONT_MATTER_KEYS = new Set([
145
+ "close_reason",
146
+ "assignee",
147
+ "parent",
148
+ "blocked_by",
149
+ "blocked_reason",
150
+ "unblock_note",
151
+ "dependencies",
152
+ "comments",
153
+ "notes",
154
+ "learnings",
155
+ "files",
156
+ "tests",
157
+ "docs",
158
+ "reminders",
159
+ "events",
160
+ ]);
10
161
  function toAuthor(candidate, defaultAuthor) {
11
162
  const resolved = candidate ?? process.env.PM_AUTHOR ?? defaultAuthor;
12
163
  const trimmed = resolved.trim();
13
164
  return trimmed || "unknown";
14
165
  }
166
+ function isLegacyNoneToken(value) {
167
+ if (value === undefined) {
168
+ return false;
169
+ }
170
+ return LEGACY_NONE_TOKENS.has(value.trim().toLowerCase());
171
+ }
172
+ function assertNoLegacyNoneToken(value, flag, replacementHint) {
173
+ if (!isLegacyNoneToken(value)) {
174
+ return;
175
+ }
176
+ const suffix = replacementHint ? ` ${replacementHint}` : "";
177
+ throw new PmCliError(`${flag} no longer accepts "none" or "null".${suffix}`.trim(), EXIT_CODE.USAGE);
178
+ }
179
+ function assertNoLegacyNoneTokens(values, flag, replacementHint) {
180
+ if (!values || values.length === 0) {
181
+ return;
182
+ }
183
+ const hasLegacyToken = values.some((value) => isLegacyNoneToken(value));
184
+ if (!hasLegacyToken) {
185
+ return;
186
+ }
187
+ const suffix = replacementHint ? ` ${replacementHint}` : "";
188
+ throw new PmCliError(`${flag} no longer accepts "none" or "null".${suffix}`.trim(), EXIT_CODE.USAGE);
189
+ }
190
+ function resolveRuntimeUnsetDefinition(token, runtimeFieldRegistry) {
191
+ if (!runtimeFieldRegistry) {
192
+ return undefined;
193
+ }
194
+ for (const definition of runtimeFieldRegistry.definitions) {
195
+ if (definition.allow_unset === false) {
196
+ continue;
197
+ }
198
+ const candidates = new Set([
199
+ definition.key,
200
+ definition.front_matter_key,
201
+ definition.cli_flag.replaceAll("-", "_"),
202
+ definition.cli_flag,
203
+ ...definition.cli_aliases.map((alias) => alias.replaceAll("-", "_")),
204
+ ...definition.cli_aliases,
205
+ ]);
206
+ if (!candidates.has(token)) {
207
+ continue;
208
+ }
209
+ return {
210
+ optionKey: definition.key,
211
+ frontMatterKey: definition.front_matter_key,
212
+ };
213
+ }
214
+ return undefined;
215
+ }
216
+ function parseUpdateUnsetTargets(raw, runtimeFieldRegistry) {
217
+ const frontMatterKeys = new Set();
218
+ const optionKeys = new Set();
219
+ if (!raw || raw.length === 0) {
220
+ return { frontMatterKeys, optionKeys };
221
+ }
222
+ for (const entry of raw) {
223
+ const trimmed = entry.trim().toLowerCase();
224
+ if (!trimmed) {
225
+ throw new PmCliError("--unset values must not be empty", EXIT_CODE.USAGE);
226
+ }
227
+ if (isLegacyNoneToken(trimmed)) {
228
+ throw new PmCliError('--unset no longer accepts "none" or "null". Specify concrete field names such as --unset deadline', EXIT_CODE.USAGE);
229
+ }
230
+ const definition = UPDATE_UNSET_ALIAS_MAP.get(trimmed) ?? resolveRuntimeUnsetDefinition(trimmed, runtimeFieldRegistry);
231
+ if (!definition) {
232
+ throw new PmCliError(`Unsupported --unset field "${entry}". Supported fields: ${UPDATE_UNSET_SUPPORTED_CANONICAL_FIELDS}`, EXIT_CODE.USAGE);
233
+ }
234
+ frontMatterKeys.add(definition.frontMatterKey);
235
+ optionKeys.add(definition.optionKey);
236
+ }
237
+ return { frontMatterKeys, optionKeys };
238
+ }
239
+ function enforceAllowAuditUpdateScope(options, clearFrontMatterKeys) {
240
+ const allowAuditUpdate = options.allowAuditUpdate === true;
241
+ const allowAuditDepUpdate = options.allowAuditDepUpdate === true;
242
+ if (!allowAuditUpdate && !allowAuditDepUpdate) {
243
+ return;
244
+ }
245
+ if (allowAuditUpdate && allowAuditDepUpdate) {
246
+ throw new PmCliError("Choose either --allow-audit-update or --allow-audit-dep-update; these override modes are mutually exclusive.", EXIT_CODE.USAGE);
247
+ }
248
+ const pushIf = (condition, flag, list) => {
249
+ if (condition) {
250
+ list.push(flag);
251
+ }
252
+ };
253
+ if (allowAuditDepUpdate) {
254
+ const disallowedFlags = [];
255
+ pushIf(options.title !== undefined, "--title", disallowedFlags);
256
+ pushIf(options.description !== undefined, "--description", disallowedFlags);
257
+ pushIf(options.body !== undefined, "--body", disallowedFlags);
258
+ pushIf(options.status !== undefined, "--status", disallowedFlags);
259
+ pushIf(options.closeReason !== undefined, "--close-reason", disallowedFlags);
260
+ pushIf(options.priority !== undefined, "--priority", disallowedFlags);
261
+ pushIf(options.type !== undefined, "--type", disallowedFlags);
262
+ pushIf(options.tags !== undefined, "--tags", disallowedFlags);
263
+ pushIf(options.deadline !== undefined, "--deadline", disallowedFlags);
264
+ pushIf(options.estimatedMinutes !== undefined, "--estimate", disallowedFlags);
265
+ pushIf(options.acceptanceCriteria !== undefined, "--acceptance-criteria", disallowedFlags);
266
+ pushIf(options.definitionOfReady !== undefined, "--definition-of-ready", disallowedFlags);
267
+ pushIf(options.order !== undefined || options.rank !== undefined, "--order/--rank", disallowedFlags);
268
+ pushIf(options.goal !== undefined, "--goal", disallowedFlags);
269
+ pushIf(options.objective !== undefined, "--objective", disallowedFlags);
270
+ pushIf(options.value !== undefined, "--value", disallowedFlags);
271
+ pushIf(options.impact !== undefined, "--impact", disallowedFlags);
272
+ pushIf(options.outcome !== undefined, "--outcome", disallowedFlags);
273
+ pushIf(options.whyNow !== undefined, "--why-now", disallowedFlags);
274
+ pushIf(options.assignee !== undefined, "--assignee", disallowedFlags);
275
+ pushIf(options.parent !== undefined, "--parent", disallowedFlags);
276
+ pushIf(options.reviewer !== undefined, "--reviewer", disallowedFlags);
277
+ pushIf(options.risk !== undefined, "--risk", disallowedFlags);
278
+ pushIf(options.confidence !== undefined, "--confidence", disallowedFlags);
279
+ pushIf(options.sprint !== undefined, "--sprint", disallowedFlags);
280
+ pushIf(options.release !== undefined, "--release", disallowedFlags);
281
+ pushIf(options.blockedBy !== undefined, "--blocked-by", disallowedFlags);
282
+ pushIf(options.blockedReason !== undefined, "--blocked-reason", disallowedFlags);
283
+ pushIf(options.unblockNote !== undefined, "--unblock-note", disallowedFlags);
284
+ pushIf(options.reporter !== undefined, "--reporter", disallowedFlags);
285
+ pushIf(options.severity !== undefined, "--severity", disallowedFlags);
286
+ pushIf(options.environment !== undefined, "--environment", disallowedFlags);
287
+ pushIf(options.reproSteps !== undefined, "--repro-steps", disallowedFlags);
288
+ pushIf(options.resolution !== undefined, "--resolution", disallowedFlags);
289
+ pushIf(options.expectedResult !== undefined, "--expected-result", disallowedFlags);
290
+ pushIf(options.actualResult !== undefined, "--actual-result", disallowedFlags);
291
+ pushIf(options.affectedVersion !== undefined, "--affected-version", disallowedFlags);
292
+ pushIf(options.fixedVersion !== undefined, "--fixed-version", disallowedFlags);
293
+ pushIf(options.component !== undefined, "--component", disallowedFlags);
294
+ pushIf(options.regression !== undefined, "--regression", disallowedFlags);
295
+ pushIf(options.customerImpact !== undefined, "--customer-impact", disallowedFlags);
296
+ pushIf(options.depRemove !== undefined, "--dep-remove", disallowedFlags);
297
+ pushIf(options.replaceDeps === true, "--replace-deps", disallowedFlags);
298
+ pushIf(options.replaceTests === true, "--replace-tests", disallowedFlags);
299
+ pushIf(options.comment !== undefined, "--comment", disallowedFlags);
300
+ pushIf(options.note !== undefined, "--note", disallowedFlags);
301
+ pushIf(options.learning !== undefined, "--learning", disallowedFlags);
302
+ pushIf(options.file !== undefined, "--file", disallowedFlags);
303
+ pushIf(options.test !== undefined, "--test", disallowedFlags);
304
+ pushIf(options.doc !== undefined, "--doc", disallowedFlags);
305
+ pushIf(options.reminder !== undefined, "--reminder", disallowedFlags);
306
+ pushIf(options.event !== undefined, "--event", disallowedFlags);
307
+ pushIf(options.typeOption !== undefined, "--type-option", disallowedFlags);
308
+ pushIf(options.clearDeps === true, "--clear-deps", disallowedFlags);
309
+ pushIf(options.clearComments === true, "--clear-comments", disallowedFlags);
310
+ pushIf(options.clearNotes === true, "--clear-notes", disallowedFlags);
311
+ pushIf(options.clearLearnings === true, "--clear-learnings", disallowedFlags);
312
+ pushIf(options.clearFiles === true, "--clear-files", disallowedFlags);
313
+ pushIf(options.clearTests === true, "--clear-tests", disallowedFlags);
314
+ pushIf(options.clearDocs === true, "--clear-docs", disallowedFlags);
315
+ pushIf(options.clearReminders === true, "--clear-reminders", disallowedFlags);
316
+ pushIf(options.clearEvents === true, "--clear-events", disallowedFlags);
317
+ pushIf(options.clearTypeOptions === true, "--clear-type-options", disallowedFlags);
318
+ pushIf(options.force === true, "--force", disallowedFlags);
319
+ pushIf(clearFrontMatterKeys.size > 0, "--unset", disallowedFlags);
320
+ if (options.dep === undefined || options.dep.length === 0) {
321
+ throw new PmCliError("--allow-audit-dep-update requires at least one --dep value", EXIT_CODE.USAGE);
322
+ }
323
+ if (disallowedFlags.length > 0) {
324
+ throw new PmCliError(`--allow-audit-dep-update supports append-only dependency additions via --dep. Remove restricted options: ${disallowedFlags.join(", ")}`, EXIT_CODE.USAGE);
325
+ }
326
+ return;
327
+ }
328
+ const disallowedFlags = [];
329
+ if (options.status !== undefined) {
330
+ disallowedFlags.push("--status");
331
+ }
332
+ if (options.closeReason !== undefined) {
333
+ disallowedFlags.push("--close-reason");
334
+ }
335
+ if (options.assignee !== undefined) {
336
+ disallowedFlags.push("--assignee");
337
+ }
338
+ if (options.parent !== undefined) {
339
+ disallowedFlags.push("--parent");
340
+ }
341
+ if (options.blockedBy !== undefined) {
342
+ disallowedFlags.push("--blocked-by");
343
+ }
344
+ if (options.blockedReason !== undefined) {
345
+ disallowedFlags.push("--blocked-reason");
346
+ }
347
+ if (options.unblockNote !== undefined) {
348
+ disallowedFlags.push("--unblock-note");
349
+ }
350
+ if (options.dep !== undefined) {
351
+ disallowedFlags.push("--dep");
352
+ }
353
+ if (options.depRemove !== undefined) {
354
+ disallowedFlags.push("--dep-remove");
355
+ }
356
+ if (options.replaceDeps === true) {
357
+ disallowedFlags.push("--replace-deps");
358
+ }
359
+ if (options.replaceTests === true) {
360
+ disallowedFlags.push("--replace-tests");
361
+ }
362
+ if (options.comment !== undefined) {
363
+ disallowedFlags.push("--comment");
364
+ }
365
+ if (options.note !== undefined) {
366
+ disallowedFlags.push("--note");
367
+ }
368
+ if (options.learning !== undefined) {
369
+ disallowedFlags.push("--learning");
370
+ }
371
+ if (options.file !== undefined) {
372
+ disallowedFlags.push("--file");
373
+ }
374
+ if (options.test !== undefined) {
375
+ disallowedFlags.push("--test");
376
+ }
377
+ if (options.doc !== undefined) {
378
+ disallowedFlags.push("--doc");
379
+ }
380
+ if (options.reminder !== undefined) {
381
+ disallowedFlags.push("--reminder");
382
+ }
383
+ if (options.event !== undefined) {
384
+ disallowedFlags.push("--event");
385
+ }
386
+ if (options.clearDeps === true) {
387
+ disallowedFlags.push("--clear-deps");
388
+ }
389
+ if (options.clearComments === true) {
390
+ disallowedFlags.push("--clear-comments");
391
+ }
392
+ if (options.clearNotes === true) {
393
+ disallowedFlags.push("--clear-notes");
394
+ }
395
+ if (options.clearLearnings === true) {
396
+ disallowedFlags.push("--clear-learnings");
397
+ }
398
+ if (options.clearFiles === true) {
399
+ disallowedFlags.push("--clear-files");
400
+ }
401
+ if (options.clearTests === true) {
402
+ disallowedFlags.push("--clear-tests");
403
+ }
404
+ if (options.clearDocs === true) {
405
+ disallowedFlags.push("--clear-docs");
406
+ }
407
+ if (options.clearReminders === true) {
408
+ disallowedFlags.push("--clear-reminders");
409
+ }
410
+ if (options.clearEvents === true) {
411
+ disallowedFlags.push("--clear-events");
412
+ }
413
+ const disallowedUnset = [...clearFrontMatterKeys]
414
+ .filter((field) => AUDIT_UPDATE_DISALLOWED_UNSET_FRONT_MATTER_KEYS.has(field))
415
+ .sort((left, right) => left.localeCompare(right))
416
+ .map((field) => `--unset ${field.replaceAll("_", "-")}`);
417
+ disallowedFlags.push(...disallowedUnset);
418
+ if (disallowedFlags.length > 0) {
419
+ throw new PmCliError(`--allow-audit-update only supports non-lifecycle metadata fields. Remove restricted options: ${disallowedFlags.join(", ")}`, EXIT_CODE.USAGE);
420
+ }
421
+ }
15
422
  function ensureEnum(value, allowed, label) {
16
423
  if (!allowed.includes(value)) {
17
424
  throw new PmCliError(`Invalid ${label} value "${value}"`, EXIT_CODE.USAGE);
18
425
  }
19
426
  return value;
20
427
  }
428
+ function parseStatus(value, statusRegistry) {
429
+ const normalized = normalizeStatusInput(value, statusRegistry);
430
+ if (!normalized) {
431
+ const allowedStatuses = statusRegistry.definitions.map((definition) => definition.id);
432
+ throw new PmCliError(`Invalid --status value "${value}". Allowed: ${allowedStatuses.join(", ")}`, EXIT_CODE.USAGE);
433
+ }
434
+ return normalized;
435
+ }
21
436
  function normalizeRiskInput(value) {
22
437
  const trimmed = value.trim();
23
438
  return trimmed.toLowerCase() === "med" ? "medium" : trimmed;
@@ -50,6 +465,278 @@ function parseRegressionInput(value) {
50
465
  }
51
466
  throw new PmCliError("Regression must be one of true|false|1|0", EXIT_CODE.USAGE);
52
467
  }
468
+ function weekdayOrderIndex(value) {
469
+ return RECURRENCE_WEEKDAY_VALUES.indexOf(value);
470
+ }
471
+ function parseReminderEntries(raw, nowValue) {
472
+ return raw.map((entry) => {
473
+ const kv = parseCsvKv(entry, "--reminder");
474
+ const atRaw = kv.at?.trim();
475
+ const textRaw = kv.text?.trim();
476
+ if (!atRaw || !textRaw) {
477
+ throw new PmCliError("--reminder requires at=<iso|relative> and text=<value>", EXIT_CODE.USAGE);
478
+ }
479
+ return {
480
+ at: resolveIsoOrRelative(atRaw, nowValue, "reminder.at"),
481
+ text: textRaw,
482
+ };
483
+ });
484
+ }
485
+ function parseEventBoolean(value, flag) {
486
+ const normalized = value.trim().toLowerCase();
487
+ if (normalized === "true" || normalized === "1" || normalized === "yes") {
488
+ return true;
489
+ }
490
+ if (normalized === "false" || normalized === "0" || normalized === "no") {
491
+ return false;
492
+ }
493
+ throw new PmCliError(`${flag} must be one of true|false|1|0|yes|no`, EXIT_CODE.USAGE);
494
+ }
495
+ function parseDelimitedList(raw) {
496
+ if (!raw) {
497
+ return [];
498
+ }
499
+ return raw
500
+ .split("|")
501
+ .map((value) => value.trim())
502
+ .filter((value) => value.length > 0);
503
+ }
504
+ function parseRecurrenceRule(kv, startAt, nowValue) {
505
+ const freqRaw = kv.recur_freq?.trim();
506
+ const intervalRaw = kv.recur_interval?.trim();
507
+ const countRaw = kv.recur_count?.trim();
508
+ const untilRaw = kv.recur_until?.trim();
509
+ const byWeekdayRaw = kv.recur_by_weekday?.trim();
510
+ const byMonthDayRaw = kv.recur_by_month_day?.trim();
511
+ const exdatesRaw = kv.recur_exdates?.trim();
512
+ const recurrenceInputsProvided = [freqRaw, intervalRaw, countRaw, untilRaw, byWeekdayRaw, byMonthDayRaw, exdatesRaw].some((value) => value !== undefined);
513
+ if (!recurrenceInputsProvided) {
514
+ return undefined;
515
+ }
516
+ if (!freqRaw) {
517
+ throw new PmCliError("--event recurrence fields require recur_freq=<daily|weekly|monthly|yearly>", EXIT_CODE.USAGE);
518
+ }
519
+ const freq = ensureEnum(freqRaw.toLowerCase(), RECURRENCE_FREQUENCY_VALUES, "event recurrence frequency");
520
+ const interval = intervalRaw ? parseOptionalNumber(intervalRaw, "event recur_interval") : undefined;
521
+ if (interval !== undefined && (!Number.isInteger(interval) || interval < 1)) {
522
+ throw new PmCliError("--event recur_interval must be an integer >= 1", EXIT_CODE.USAGE);
523
+ }
524
+ const count = countRaw ? parseOptionalNumber(countRaw, "event recur_count") : undefined;
525
+ if (count !== undefined && (!Number.isInteger(count) || count < 1)) {
526
+ throw new PmCliError("--event recur_count must be an integer >= 1", EXIT_CODE.USAGE);
527
+ }
528
+ const until = untilRaw ? resolveIsoOrRelative(untilRaw, nowValue, "event.recur_until") : undefined;
529
+ if (until && until < startAt) {
530
+ throw new PmCliError("--event recur_until must be at or after start", EXIT_CODE.USAGE);
531
+ }
532
+ const byWeekday = Array.from(new Set(parseDelimitedList(byWeekdayRaw)
533
+ .map((value) => ensureEnum(value.toLowerCase(), RECURRENCE_WEEKDAY_VALUES, "event weekday")))).sort((left, right) => weekdayOrderIndex(left) -
534
+ weekdayOrderIndex(right));
535
+ const byMonthDay = Array.from(new Set(parseDelimitedList(byMonthDayRaw)
536
+ .map((value) => {
537
+ const day = parseOptionalNumber(value, "event recur_by_month_day");
538
+ if (!Number.isInteger(day) || day < 1 || day > 31) {
539
+ throw new PmCliError("--event recur_by_month_day values must be integers 1..31", EXIT_CODE.USAGE);
540
+ }
541
+ return day;
542
+ }))).sort((left, right) => left - right);
543
+ const exdates = Array.from(new Set(parseDelimitedList(exdatesRaw).map((value) => resolveIsoOrRelative(value, nowValue, "event.recur_exdates")))).sort((left, right) => left.localeCompare(right));
544
+ return {
545
+ freq,
546
+ interval,
547
+ count,
548
+ until,
549
+ by_weekday: byWeekday.length > 0 ? byWeekday : undefined,
550
+ by_month_day: byMonthDay.length > 0 ? byMonthDay : undefined,
551
+ exdates: exdates.length > 0 ? exdates : undefined,
552
+ };
553
+ }
554
+ function parseEventEntries(raw, nowValue) {
555
+ return raw.map((entry) => {
556
+ const kv = parseCsvKv(entry, "--event");
557
+ const startRaw = kv.start?.trim();
558
+ if (!startRaw) {
559
+ throw new PmCliError("--event requires start=<iso|relative>", EXIT_CODE.USAGE);
560
+ }
561
+ const startAt = resolveIsoOrRelative(startRaw, nowValue, "event.start");
562
+ const endRaw = kv.end?.trim();
563
+ const endAt = endRaw ? resolveIsoOrRelative(endRaw, nowValue, "event.end") : undefined;
564
+ if (endAt && endAt <= startAt) {
565
+ throw new PmCliError("--event end must be after start", EXIT_CODE.USAGE);
566
+ }
567
+ const titleRaw = kv.title;
568
+ const descriptionRaw = kv.description;
569
+ const locationRaw = kv.location;
570
+ const timezoneRaw = kv.timezone;
571
+ const title = titleRaw?.trim();
572
+ const description = descriptionRaw?.trim();
573
+ const location = locationRaw?.trim();
574
+ const timezone = timezoneRaw?.trim();
575
+ if (titleRaw !== undefined && !title) {
576
+ throw new PmCliError("--event title must not be empty", EXIT_CODE.USAGE);
577
+ }
578
+ if (descriptionRaw !== undefined && !description) {
579
+ throw new PmCliError("--event description must not be empty", EXIT_CODE.USAGE);
580
+ }
581
+ if (locationRaw !== undefined && !location) {
582
+ throw new PmCliError("--event location must not be empty", EXIT_CODE.USAGE);
583
+ }
584
+ if (timezoneRaw !== undefined && !timezone) {
585
+ throw new PmCliError("--event timezone must not be empty", EXIT_CODE.USAGE);
586
+ }
587
+ const allDayRaw = kv.all_day?.trim();
588
+ const recurrence = parseRecurrenceRule(kv, startAt, nowValue);
589
+ return {
590
+ start_at: startAt,
591
+ end_at: endAt,
592
+ title,
593
+ description,
594
+ location,
595
+ all_day: allDayRaw ? parseEventBoolean(allDayRaw, "--event all_day") : undefined,
596
+ timezone,
597
+ recurrence,
598
+ };
599
+ });
600
+ }
601
+ function parseTypeOptionEntries(raw) {
602
+ const values = {};
603
+ for (const entry of raw) {
604
+ const trimmedEntry = entry.trim();
605
+ if (trimmedEntry.length === 0) {
606
+ throw new PmCliError("--type-option values must not be empty", EXIT_CODE.USAGE);
607
+ }
608
+ let key;
609
+ let value;
610
+ const prefersStructuredKv = trimmedEntry.includes(",") ||
611
+ trimmedEntry.includes("\n") ||
612
+ trimmedEntry.startsWith("```") ||
613
+ /^(?:[-*+]\s+)?(?:key|value)\s*[:=]/i.test(trimmedEntry);
614
+ if (prefersStructuredKv) {
615
+ const kv = parseCsvKv(trimmedEntry, "--type-option");
616
+ key = kv.key?.trim();
617
+ value = kv.value?.trim();
618
+ }
619
+ else {
620
+ const equalsIndex = trimmedEntry.indexOf("=");
621
+ const colonIndex = trimmedEntry.indexOf(":");
622
+ let separatorIndex = equalsIndex;
623
+ if (equalsIndex <= 0 && colonIndex > 0) {
624
+ separatorIndex = colonIndex;
625
+ }
626
+ if (separatorIndex <= 0 || separatorIndex === trimmedEntry.length - 1) {
627
+ throw new PmCliError("--type-option requires key=value or key=<name>,value=<value> entries", EXIT_CODE.USAGE);
628
+ }
629
+ key = trimmedEntry.slice(0, separatorIndex).trim();
630
+ value = trimmedEntry.slice(separatorIndex + 1).trim();
631
+ }
632
+ if (!key || !value) {
633
+ throw new PmCliError("--type-option requires key and value", EXIT_CODE.USAGE);
634
+ }
635
+ values[key] = value;
636
+ }
637
+ return Object.fromEntries(Object.entries(values).sort((left, right) => left[0].localeCompare(right[0])));
638
+ }
639
+ function parseDependencyCreatedAt(value, currentIso) {
640
+ if (!value || value.trim() === "" || value.trim().toLowerCase() === "now") {
641
+ return currentIso;
642
+ }
643
+ const parsed = Date.parse(value);
644
+ if (!Number.isFinite(parsed)) {
645
+ throw new PmCliError(`Invalid dependency created_at timestamp "${value}"`, EXIT_CODE.USAGE);
646
+ }
647
+ return new Date(parsed).toISOString();
648
+ }
649
+ function parseOptionalDependencyString(value) {
650
+ if (value === undefined)
651
+ return undefined;
652
+ const trimmed = value.trim();
653
+ return trimmed.length > 0 ? trimmed : undefined;
654
+ }
655
+ function parseDependencyAdditions(raw, prefix, nowIso) {
656
+ if (!raw) {
657
+ return { additions: [] };
658
+ }
659
+ assertNoLegacyNoneTokens(raw, "--dep", "Use --clear-deps to clear dependencies.");
660
+ const additions = raw.map((entry) => {
661
+ const kv = parseCsvKv(entry, "--dep");
662
+ const id = kv.id?.trim();
663
+ const kind = kv.kind?.trim();
664
+ if (!id || !kind) {
665
+ throw new PmCliError("--dep requires id and kind", EXIT_CODE.USAGE);
666
+ }
667
+ if (id.toLowerCase() === "undefined") {
668
+ throw new PmCliError(`--dep id must not use placeholder token "${id}". Use --clear-deps to clear dependencies.`, EXIT_CODE.USAGE);
669
+ }
670
+ const sourceKind = parseOptionalDependencyString(kv.source_kind);
671
+ return {
672
+ id: normalizeItemId(id, prefix),
673
+ kind: ensureEnum(kind, DEPENDENCY_KIND_VALUES, "dependency kind"),
674
+ created_at: parseDependencyCreatedAt(kv.created_at, nowIso),
675
+ author: parseOptionalDependencyString(kv.author),
676
+ source_kind: sourceKind,
677
+ };
678
+ });
679
+ return { additions };
680
+ }
681
+ function parseDependencyRemovals(raw, prefix) {
682
+ if (!raw) {
683
+ return [];
684
+ }
685
+ assertNoLegacyNoneTokens(raw, "--dep-remove");
686
+ return raw.map((entry) => {
687
+ const trimmed = entry.trim();
688
+ if (!trimmed) {
689
+ throw new PmCliError("--dep-remove requires id or key/value selectors", EXIT_CODE.USAGE);
690
+ }
691
+ if (trimmed.includes("=") || /^(?:[-*+]\s+)?(?:id|kind|source_kind)\s*[:=]/i.test(trimmed) || trimmed.startsWith("```")) {
692
+ const kv = parseCsvKv(trimmed, "--dep-remove");
693
+ const idRaw = kv.id?.trim();
694
+ if (!idRaw) {
695
+ throw new PmCliError("--dep-remove key/value form requires id=<value>", EXIT_CODE.USAGE);
696
+ }
697
+ if (idRaw.toLowerCase() === "undefined") {
698
+ throw new PmCliError(`--dep-remove id must not use placeholder token "${idRaw}"`, EXIT_CODE.USAGE);
699
+ }
700
+ const kindRaw = parseOptionalDependencyString(kv.kind);
701
+ const sourceKind = parseOptionalDependencyString(kv.source_kind);
702
+ return {
703
+ id: normalizeItemId(idRaw, prefix),
704
+ kind: kindRaw ? ensureEnum(kindRaw, DEPENDENCY_KIND_VALUES, "dependency kind") : undefined,
705
+ source_kind: sourceKind,
706
+ };
707
+ }
708
+ if (trimmed.toLowerCase() === "undefined") {
709
+ throw new PmCliError(`--dep-remove id must not use placeholder token "${trimmed}"`, EXIT_CODE.USAGE);
710
+ }
711
+ return {
712
+ id: normalizeItemId(trimmed, prefix),
713
+ };
714
+ });
715
+ }
716
+ function dependencyKey(value) {
717
+ return `${value.id}::${value.kind}::${value.source_kind ?? ""}`;
718
+ }
719
+ function fileKey(value) {
720
+ return `${value.path}::${value.scope}`;
721
+ }
722
+ function docKey(value) {
723
+ return `${value.path}::${value.scope}`;
724
+ }
725
+ function testKey(value) {
726
+ return `${value.command}::${value.path ?? ""}::${value.scope}::${value.pm_context_mode ?? ""}`;
727
+ }
728
+ function matchesDependencySelector(value, selector) {
729
+ if (value.id !== selector.id) {
730
+ return false;
731
+ }
732
+ if (selector.kind && value.kind !== selector.kind) {
733
+ return false;
734
+ }
735
+ if (selector.source_kind !== undefined && (value.source_kind ?? undefined) !== selector.source_kind) {
736
+ return false;
737
+ }
738
+ return true;
739
+ }
53
740
  function ensurePriority(raw) {
54
741
  const parsed = parseOptionalNumber(raw, "priority");
55
742
  if (![0, 1, 2, 3, 4].includes(parsed)) {
@@ -57,17 +744,368 @@ function ensurePriority(raw) {
57
744
  }
58
745
  return parsed;
59
746
  }
747
+ function normalizeUpdatePolicyOptionKey(raw, typeName) {
748
+ const canonical = canonicalizeCommandOptionKey("update", raw);
749
+ if (!canonical) {
750
+ throw new PmCliError(`Unsupported command_option_policies option "${raw}" for update command on type "${typeName}"`, EXIT_CODE.CONFLICT);
751
+ }
752
+ return canonical;
753
+ }
754
+ function collectProvidedUpdatePolicyOptions(options) {
755
+ const provided = new Set();
756
+ const mark = (optionKey, isProvided) => {
757
+ if (isProvided) {
758
+ provided.add(optionKey);
759
+ }
760
+ };
761
+ mark("title", options.title !== undefined);
762
+ mark("description", options.description !== undefined);
763
+ mark("body", options.body !== undefined);
764
+ mark("status", options.status !== undefined);
765
+ mark("closeReason", options.closeReason !== undefined);
766
+ mark("priority", options.priority !== undefined);
767
+ mark("type", options.type !== undefined);
768
+ mark("tags", options.tags !== undefined);
769
+ mark("deadline", options.deadline !== undefined);
770
+ mark("estimatedMinutes", options.estimatedMinutes !== undefined);
771
+ mark("acceptanceCriteria", options.acceptanceCriteria !== undefined);
772
+ mark("definitionOfReady", options.definitionOfReady !== undefined);
773
+ mark("order", options.order !== undefined || options.rank !== undefined);
774
+ mark("goal", options.goal !== undefined);
775
+ mark("objective", options.objective !== undefined);
776
+ mark("value", options.value !== undefined);
777
+ mark("impact", options.impact !== undefined);
778
+ mark("outcome", options.outcome !== undefined);
779
+ mark("whyNow", options.whyNow !== undefined);
780
+ mark("author", options.author !== undefined);
781
+ mark("message", options.message !== undefined);
782
+ mark("assignee", options.assignee !== undefined);
783
+ mark("parent", options.parent !== undefined);
784
+ mark("reviewer", options.reviewer !== undefined);
785
+ mark("risk", options.risk !== undefined);
786
+ mark("confidence", options.confidence !== undefined);
787
+ mark("sprint", options.sprint !== undefined);
788
+ mark("release", options.release !== undefined);
789
+ mark("blockedBy", options.blockedBy !== undefined);
790
+ mark("blockedReason", options.blockedReason !== undefined);
791
+ mark("unblockNote", options.unblockNote !== undefined);
792
+ mark("reporter", options.reporter !== undefined);
793
+ mark("severity", options.severity !== undefined);
794
+ mark("environment", options.environment !== undefined);
795
+ mark("reproSteps", options.reproSteps !== undefined);
796
+ mark("resolution", options.resolution !== undefined);
797
+ mark("expectedResult", options.expectedResult !== undefined);
798
+ mark("actualResult", options.actualResult !== undefined);
799
+ mark("affectedVersion", options.affectedVersion !== undefined);
800
+ mark("fixedVersion", options.fixedVersion !== undefined);
801
+ mark("component", options.component !== undefined);
802
+ mark("regression", options.regression !== undefined);
803
+ mark("customerImpact", options.customerImpact !== undefined);
804
+ mark("dep", options.dep !== undefined);
805
+ mark("depRemove", options.depRemove !== undefined);
806
+ mark("dep", options.replaceDeps === true);
807
+ mark("comment", options.comment !== undefined);
808
+ mark("note", options.note !== undefined);
809
+ mark("learning", options.learning !== undefined);
810
+ mark("file", options.file !== undefined);
811
+ mark("test", options.test !== undefined);
812
+ mark("test", options.replaceTests === true);
813
+ mark("doc", options.doc !== undefined);
814
+ mark("reminder", options.reminder !== undefined);
815
+ mark("event", options.event !== undefined);
816
+ mark("typeOption", options.typeOption !== undefined);
817
+ mark("force", options.force === true);
818
+ mark("allowAuditUpdate", options.allowAuditUpdate === true);
819
+ mark("dep", options.clearDeps === true);
820
+ mark("comment", options.clearComments === true);
821
+ mark("note", options.clearNotes === true);
822
+ mark("learning", options.clearLearnings === true);
823
+ mark("file", options.clearFiles === true);
824
+ mark("test", options.clearTests === true);
825
+ mark("doc", options.clearDocs === true);
826
+ mark("reminder", options.clearReminders === true);
827
+ mark("event", options.clearEvents === true);
828
+ mark("typeOption", options.clearTypeOptions === true);
829
+ if (options.unset && options.unset.length > 0) {
830
+ const unsetTargets = parseUpdateUnsetTargets(options.unset);
831
+ for (const optionKey of unsetTargets.optionKeys) {
832
+ mark(optionKey, true);
833
+ }
834
+ }
835
+ return provided;
836
+ }
837
+ function enforceUpdateOptionsByType(typeName, options, typeRegistry) {
838
+ const typeDefinition = resolveTypeDefinition(typeName, typeRegistry);
839
+ if (!typeDefinition) {
840
+ throw new PmCliError(`Invalid type value "${typeName}"`, EXIT_CODE.USAGE);
841
+ }
842
+ const policyState = resolveCommandOptionPolicyState(typeDefinition, "update", []);
843
+ if (policyState.errors.length > 0) {
844
+ throw new PmCliError(policyState.errors.join("; "), EXIT_CODE.CONFLICT);
845
+ }
846
+ const provided = collectProvidedUpdatePolicyOptions(options);
847
+ for (const disabled of policyState.disabled) {
848
+ if (provided.has(normalizeUpdatePolicyOptionKey(disabled, typeName))) {
849
+ throw new PmCliError(`Option ${commandOptionFlagLabel("update", disabled)} is disabled for type "${typeName}" by command_option_policies`, EXIT_CODE.USAGE);
850
+ }
851
+ }
852
+ for (const required of policyState.required) {
853
+ if (!provided.has(normalizeUpdatePolicyOptionKey(required, typeName))) {
854
+ throw new PmCliError(`Missing required option ${commandOptionFlagLabel("update", required)} for type "${typeName}"`, EXIT_CODE.USAGE);
855
+ }
856
+ }
857
+ }
60
858
  export async function runUpdate(id, options, global) {
859
+ const stdinResolver = createStdinTokenResolver();
860
+ options = {
861
+ ...options,
862
+ body: await stdinResolver.resolveValue(options.body, "--body"),
863
+ dep: await stdinResolver.resolveList(options.dep, "--dep"),
864
+ depRemove: await stdinResolver.resolveList(options.depRemove, "--dep-remove"),
865
+ comment: await stdinResolver.resolveList(options.comment, "--comment"),
866
+ note: await stdinResolver.resolveList(options.note, "--note"),
867
+ learning: await stdinResolver.resolveList(options.learning, "--learning"),
868
+ file: await stdinResolver.resolveList(options.file, "--file"),
869
+ test: await stdinResolver.resolveList(options.test, "--test"),
870
+ doc: await stdinResolver.resolveList(options.doc, "--doc"),
871
+ reminder: await stdinResolver.resolveList(options.reminder, "--reminder"),
872
+ event: await stdinResolver.resolveList(options.event, "--event"),
873
+ typeOption: await stdinResolver.resolveList(options.typeOption, "--type-option"),
874
+ };
61
875
  const pmRoot = resolvePmRoot(process.cwd(), global.path);
62
876
  if (!(await pathExists(getSettingsPath(pmRoot)))) {
63
877
  throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
64
878
  }
65
879
  const settings = await readSettings(pmRoot);
880
+ const statusRegistry = resolveRuntimeStatusRegistry(settings.schema);
881
+ const runtimeFieldRegistry = resolveRuntimeFieldRegistry(settings.schema);
882
+ const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
883
+ const parentReferencePolicy = settings.validation.parent_reference;
884
+ const sprintReleasePolicy = settings.validation.sprint_release_format;
885
+ const unsetTargets = parseUpdateUnsetTargets(options.unset, runtimeFieldRegistry);
886
+ const clearOptionKeys = new Set(unsetTargets.optionKeys);
887
+ const clearFrontMatterKeys = new Set(unsetTargets.frontMatterKeys);
888
+ const clearCollectionDefinitions = [
889
+ {
890
+ enabled: options.clearDeps || options.replaceDeps,
891
+ optionKey: "dep",
892
+ clearFlag: "--clear-deps",
893
+ valueFlag: "--dep",
894
+ values: options.dep,
895
+ frontMatterKey: "dependencies",
896
+ },
897
+ {
898
+ enabled: options.clearComments,
899
+ optionKey: "comment",
900
+ clearFlag: "--clear-comments",
901
+ valueFlag: "--comment",
902
+ values: options.comment,
903
+ frontMatterKey: "comments",
904
+ },
905
+ {
906
+ enabled: options.clearNotes,
907
+ optionKey: "note",
908
+ clearFlag: "--clear-notes",
909
+ valueFlag: "--note",
910
+ values: options.note,
911
+ frontMatterKey: "notes",
912
+ },
913
+ {
914
+ enabled: options.clearLearnings,
915
+ optionKey: "learning",
916
+ clearFlag: "--clear-learnings",
917
+ valueFlag: "--learning",
918
+ values: options.learning,
919
+ frontMatterKey: "learnings",
920
+ },
921
+ {
922
+ enabled: options.clearFiles,
923
+ optionKey: "file",
924
+ clearFlag: "--clear-files",
925
+ valueFlag: "--file",
926
+ values: options.file,
927
+ frontMatterKey: "files",
928
+ },
929
+ {
930
+ enabled: options.clearTests || options.replaceTests,
931
+ optionKey: "test",
932
+ clearFlag: "--clear-tests",
933
+ valueFlag: "--test",
934
+ values: options.test,
935
+ frontMatterKey: "tests",
936
+ },
937
+ {
938
+ enabled: options.clearDocs,
939
+ optionKey: "doc",
940
+ clearFlag: "--clear-docs",
941
+ valueFlag: "--doc",
942
+ values: options.doc,
943
+ frontMatterKey: "docs",
944
+ },
945
+ {
946
+ enabled: options.clearReminders,
947
+ optionKey: "reminder",
948
+ clearFlag: "--clear-reminders",
949
+ valueFlag: "--reminder",
950
+ values: options.reminder,
951
+ frontMatterKey: "reminders",
952
+ },
953
+ {
954
+ enabled: options.clearEvents,
955
+ optionKey: "event",
956
+ clearFlag: "--clear-events",
957
+ valueFlag: "--event",
958
+ values: options.event,
959
+ frontMatterKey: "events",
960
+ },
961
+ {
962
+ enabled: options.clearTypeOptions,
963
+ optionKey: "typeOption",
964
+ clearFlag: "--clear-type-options",
965
+ valueFlag: "--type-option",
966
+ values: options.typeOption,
967
+ frontMatterKey: "type_options",
968
+ },
969
+ ];
970
+ if (options.replaceDeps === true && (options.dep === undefined || options.dep.length === 0)) {
971
+ throw new PmCliError("--replace-deps requires at least one --dep entry", EXIT_CODE.USAGE);
972
+ }
973
+ if (options.replaceDeps === true && options.depRemove !== undefined && options.depRemove.length > 0) {
974
+ throw new PmCliError("--replace-deps cannot be combined with --dep-remove", EXIT_CODE.USAGE);
975
+ }
976
+ if (options.replaceTests === true && (options.test === undefined || options.test.length === 0)) {
977
+ throw new PmCliError("--replace-tests requires at least one --test entry", EXIT_CODE.USAGE);
978
+ }
979
+ if (options.replaceTests === true && options.clearTests === true) {
980
+ throw new PmCliError("--replace-tests cannot be combined with --clear-tests", EXIT_CODE.USAGE);
981
+ }
982
+ for (const definition of clearCollectionDefinitions) {
983
+ if (!definition.enabled) {
984
+ continue;
985
+ }
986
+ if (definition.values &&
987
+ definition.values.length > 0 &&
988
+ !((definition.optionKey === "dep" && options.replaceDeps === true) ||
989
+ (definition.optionKey === "test" && options.replaceTests === true))) {
990
+ throw new PmCliError(`Cannot combine ${definition.clearFlag} with ${definition.valueFlag}`, EXIT_CODE.USAGE);
991
+ }
992
+ clearOptionKeys.add(definition.optionKey);
993
+ clearFrontMatterKeys.add(definition.frontMatterKey);
994
+ }
995
+ enforceAllowAuditUpdateScope(options, clearFrontMatterKeys);
996
+ const scalarOptionPresence = {
997
+ tags: options.tags !== undefined,
998
+ closeReason: options.closeReason !== undefined,
999
+ deadline: options.deadline !== undefined,
1000
+ estimatedMinutes: options.estimatedMinutes !== undefined,
1001
+ acceptanceCriteria: options.acceptanceCriteria !== undefined,
1002
+ definitionOfReady: options.definitionOfReady !== undefined,
1003
+ order: options.order !== undefined || options.rank !== undefined,
1004
+ goal: options.goal !== undefined,
1005
+ objective: options.objective !== undefined,
1006
+ value: options.value !== undefined,
1007
+ impact: options.impact !== undefined,
1008
+ outcome: options.outcome !== undefined,
1009
+ whyNow: options.whyNow !== undefined,
1010
+ assignee: options.assignee !== undefined,
1011
+ parent: options.parent !== undefined,
1012
+ reviewer: options.reviewer !== undefined,
1013
+ risk: options.risk !== undefined,
1014
+ confidence: options.confidence !== undefined,
1015
+ sprint: options.sprint !== undefined,
1016
+ release: options.release !== undefined,
1017
+ blockedBy: options.blockedBy !== undefined,
1018
+ blockedReason: options.blockedReason !== undefined,
1019
+ unblockNote: options.unblockNote !== undefined,
1020
+ reporter: options.reporter !== undefined,
1021
+ severity: options.severity !== undefined,
1022
+ environment: options.environment !== undefined,
1023
+ reproSteps: options.reproSteps !== undefined,
1024
+ resolution: options.resolution !== undefined,
1025
+ expectedResult: options.expectedResult !== undefined,
1026
+ actualResult: options.actualResult !== undefined,
1027
+ affectedVersion: options.affectedVersion !== undefined,
1028
+ fixedVersion: options.fixedVersion !== undefined,
1029
+ component: options.component !== undefined,
1030
+ regression: options.regression !== undefined,
1031
+ customerImpact: options.customerImpact !== undefined,
1032
+ };
1033
+ for (const [optionKey, hasValue] of Object.entries(scalarOptionPresence)) {
1034
+ if (!hasValue || !unsetTargets.optionKeys.has(optionKey)) {
1035
+ continue;
1036
+ }
1037
+ const unsetField = UPDATE_OPTION_KEY_TO_UNSET_CANONICAL.get(optionKey) ?? optionKey;
1038
+ throw new PmCliError(`Cannot combine --unset ${unsetField} with ${commandOptionFlagLabel("update", optionKey)}`, EXIT_CODE.USAGE);
1039
+ }
1040
+ const assertNoLegacyScalarToken = (value, optionKey) => {
1041
+ const unsetField = UPDATE_OPTION_KEY_TO_UNSET_CANONICAL.get(optionKey);
1042
+ const hint = unsetField ? `Use --unset ${unsetField} to clear this field.` : undefined;
1043
+ assertNoLegacyNoneToken(value, commandOptionFlagLabel("update", optionKey), hint);
1044
+ };
1045
+ assertNoLegacyScalarToken(options.tags, "tags");
1046
+ assertNoLegacyScalarToken(options.closeReason, "closeReason");
1047
+ assertNoLegacyScalarToken(options.deadline, "deadline");
1048
+ assertNoLegacyScalarToken(options.estimatedMinutes, "estimatedMinutes");
1049
+ assertNoLegacyScalarToken(options.acceptanceCriteria, "acceptanceCriteria");
1050
+ assertNoLegacyScalarToken(options.definitionOfReady, "definitionOfReady");
1051
+ assertNoLegacyScalarToken(options.order ?? options.rank, "order");
1052
+ assertNoLegacyScalarToken(options.goal, "goal");
1053
+ assertNoLegacyScalarToken(options.objective, "objective");
1054
+ assertNoLegacyScalarToken(options.value, "value");
1055
+ assertNoLegacyScalarToken(options.impact, "impact");
1056
+ assertNoLegacyScalarToken(options.outcome, "outcome");
1057
+ assertNoLegacyScalarToken(options.whyNow, "whyNow");
1058
+ assertNoLegacyScalarToken(options.assignee, "assignee");
1059
+ assertNoLegacyScalarToken(options.parent, "parent");
1060
+ assertNoLegacyScalarToken(options.reviewer, "reviewer");
1061
+ assertNoLegacyScalarToken(options.risk, "risk");
1062
+ assertNoLegacyScalarToken(options.confidence, "confidence");
1063
+ assertNoLegacyScalarToken(options.sprint, "sprint");
1064
+ assertNoLegacyScalarToken(options.release, "release");
1065
+ assertNoLegacyScalarToken(options.blockedBy, "blockedBy");
1066
+ assertNoLegacyScalarToken(options.blockedReason, "blockedReason");
1067
+ assertNoLegacyScalarToken(options.unblockNote, "unblockNote");
1068
+ assertNoLegacyScalarToken(options.reporter, "reporter");
1069
+ assertNoLegacyScalarToken(options.severity, "severity");
1070
+ assertNoLegacyScalarToken(options.environment, "environment");
1071
+ assertNoLegacyScalarToken(options.reproSteps, "reproSteps");
1072
+ assertNoLegacyScalarToken(options.resolution, "resolution");
1073
+ assertNoLegacyScalarToken(options.expectedResult, "expectedResult");
1074
+ assertNoLegacyScalarToken(options.actualResult, "actualResult");
1075
+ assertNoLegacyScalarToken(options.affectedVersion, "affectedVersion");
1076
+ assertNoLegacyScalarToken(options.fixedVersion, "fixedVersion");
1077
+ assertNoLegacyScalarToken(options.component, "component");
1078
+ assertNoLegacyScalarToken(options.regression, "regression");
1079
+ assertNoLegacyScalarToken(options.customerImpact, "customerImpact");
1080
+ assertNoLegacyNoneTokens(options.reminder, "--reminder", "Use --clear-reminders to clear reminders.");
1081
+ assertNoLegacyNoneTokens(options.event, "--event", "Use --clear-events to clear linked events.");
66
1082
  const author = toAuthor(options.author, settings.author_default);
1083
+ const nowValue = new Date();
1084
+ const nowIso = nowValue.toISOString();
1085
+ const dependencyUpdates = parseDependencyAdditions(options.dep, settings.id_prefix, nowIso);
1086
+ const dependencyRemovals = parseDependencyRemovals(options.depRemove, settings.id_prefix);
1087
+ const commentUpdates = parseLogSeed("--comment", options.comment, nowIso, author);
1088
+ const noteUpdates = parseLogSeed("--note", options.note, nowIso, author);
1089
+ const learningUpdates = parseLogSeed("--learning", options.learning, nowIso, author);
1090
+ const fileUpdates = parseFiles(options.file);
1091
+ const testUpdates = parseTests(options.test);
1092
+ const docUpdates = parseDocs(options.doc);
1093
+ const parentReferenceWarnings = [];
1094
+ let resolvedParentValue;
1095
+ if (options.parent !== undefined && !unsetTargets.frontMatterKeys.has("parent")) {
1096
+ resolvedParentValue = normalizeParentReferenceValue(options.parent);
1097
+ const parentLocated = await locateItem(pmRoot, resolvedParentValue, settings.id_prefix, settings.item_format, typeRegistry.type_to_folder);
1098
+ if (!parentLocated) {
1099
+ const normalizedParentId = normalizeItemId(resolvedParentValue, settings.id_prefix);
1100
+ parentReferenceWarnings.push(...validateMissingParentReference(normalizedParentId, parentReferencePolicy).warnings);
1101
+ }
1102
+ }
67
1103
  const changedFlags = [
68
1104
  options.title !== undefined,
69
1105
  options.description !== undefined,
1106
+ options.body !== undefined,
70
1107
  options.status !== undefined,
1108
+ options.closeReason !== undefined,
71
1109
  options.priority !== undefined,
72
1110
  options.type !== undefined,
73
1111
  options.tags !== undefined,
@@ -105,6 +1143,30 @@ export async function runUpdate(id, options, global) {
105
1143
  options.component !== undefined,
106
1144
  options.regression !== undefined,
107
1145
  options.customerImpact !== undefined,
1146
+ options.dep !== undefined,
1147
+ options.depRemove !== undefined,
1148
+ options.replaceDeps === true,
1149
+ options.comment !== undefined,
1150
+ options.note !== undefined,
1151
+ options.learning !== undefined,
1152
+ options.file !== undefined,
1153
+ options.test !== undefined,
1154
+ options.replaceTests === true,
1155
+ options.doc !== undefined,
1156
+ options.reminder !== undefined,
1157
+ options.event !== undefined,
1158
+ options.typeOption !== undefined,
1159
+ options.unset !== undefined && options.unset.length > 0,
1160
+ options.clearDeps === true,
1161
+ options.clearComments === true,
1162
+ options.clearNotes === true,
1163
+ options.clearLearnings === true,
1164
+ options.clearFiles === true,
1165
+ options.clearTests === true,
1166
+ options.clearDocs === true,
1167
+ options.clearReminders === true,
1168
+ options.clearEvents === true,
1169
+ options.clearTypeOptions === true,
108
1170
  ].some(Boolean);
109
1171
  if (!changedFlags) {
110
1172
  throw new PmCliError("No update flags provided", EXIT_CODE.USAGE);
@@ -115,13 +1177,17 @@ export async function runUpdate(id, options, global) {
115
1177
  const result = await mutateItem({
116
1178
  pmRoot,
117
1179
  settings,
1180
+ typeToFolder: typeRegistry.type_to_folder,
118
1181
  id,
119
- op: "update",
1182
+ op: options.allowAuditUpdate === true || options.allowAuditDepUpdate === true ? "update_audit" : "update",
120
1183
  author,
121
1184
  message: options.message,
122
1185
  force: options.force,
1186
+ bypassAssigneeConflict: options.allowAuditUpdate === true || options.allowAuditDepUpdate === true,
123
1187
  mutate(document) {
124
1188
  const changedFields = [];
1189
+ const warnings = [];
1190
+ let activeTypeName = resolveTypeName(document.front_matter.type, typeRegistry) ?? document.front_matter.type;
125
1191
  if (options.title !== undefined) {
126
1192
  document.front_matter.title = options.title;
127
1193
  changedFields.push("title");
@@ -130,40 +1196,230 @@ export async function runUpdate(id, options, global) {
130
1196
  document.front_matter.description = options.description;
131
1197
  changedFields.push("description");
132
1198
  }
1199
+ if (options.body !== undefined) {
1200
+ document.body = options.body;
1201
+ changedFields.push("body");
1202
+ }
1203
+ const previousStatus = document.front_matter.status;
1204
+ const previousStatusNormalized = normalizeStatusInput(previousStatus, statusRegistry) ?? previousStatus;
133
1205
  if (options.status !== undefined) {
134
- const status = ensureEnum(options.status, STATUS_VALUES, "status");
135
- if (status === "closed") {
136
- throw new PmCliError('Invalid --status value "closed". Use "pm close <ID> <TEXT>" to close an item.', EXIT_CODE.USAGE);
1206
+ const status = parseStatus(options.status, statusRegistry);
1207
+ if (status === statusRegistry.close_status) {
1208
+ throw new PmCliError(`Invalid --status value "${statusRegistry.close_status}". Use "pm close <ID> <TEXT>" to close an item.`, EXIT_CODE.USAGE, {
1209
+ code: "close_through_update",
1210
+ why: "Closing requires a close reason and optional validation checks that pm update cannot enforce. Use pm close for auditable close workflows.",
1211
+ examples: [
1212
+ `pm close ${id} "All acceptance criteria met" --author "${author}" --message "Close: verified"`,
1213
+ `pm close ${id} "Resolved" --validate-close warn --author "${author}"`,
1214
+ ],
1215
+ nextSteps: [
1216
+ 'Use "pm close <ID> <reason>" to close with required close reason and optional --validate-close.',
1217
+ 'To cancel instead, use "pm update <ID> --status canceled".',
1218
+ ],
1219
+ });
137
1220
  }
138
1221
  document.front_matter.status = status;
139
- if (status === "canceled") {
1222
+ if (status === statusRegistry.canceled_status) {
140
1223
  delete document.front_matter.assignee;
141
1224
  }
142
1225
  changedFields.push("status");
143
1226
  }
1227
+ if (options.closeReason !== undefined || clearFrontMatterKeys.has("close_reason")) {
1228
+ if (clearFrontMatterKeys.has("close_reason")) {
1229
+ delete document.front_matter.close_reason;
1230
+ }
1231
+ else {
1232
+ const closeReason = options.closeReason.trim();
1233
+ if (closeReason.length === 0) {
1234
+ throw new PmCliError("--close-reason must not be empty", EXIT_CODE.USAGE);
1235
+ }
1236
+ document.front_matter.close_reason = closeReason;
1237
+ }
1238
+ changedFields.push("close_reason");
1239
+ }
1240
+ else if (options.status !== undefined &&
1241
+ previousStatusNormalized === statusRegistry.close_status &&
1242
+ document.front_matter.status !== statusRegistry.canceled_status &&
1243
+ document.front_matter.close_reason !== undefined) {
1244
+ delete document.front_matter.close_reason;
1245
+ changedFields.push("close_reason");
1246
+ }
144
1247
  if (options.priority !== undefined) {
145
1248
  document.front_matter.priority = ensurePriority(options.priority);
146
1249
  changedFields.push("priority");
147
1250
  }
148
1251
  if (options.type !== undefined) {
149
- document.front_matter.type = ensureEnum(options.type, ITEM_TYPE_VALUES, "type");
1252
+ const resolvedTypeName = resolveTypeName(options.type, typeRegistry);
1253
+ if (!resolvedTypeName) {
1254
+ throw new PmCliError(`Invalid type value "${options.type}". Allowed: ${typeRegistry.types.join(", ")}`, EXIT_CODE.USAGE);
1255
+ }
1256
+ document.front_matter.type = resolvedTypeName;
1257
+ activeTypeName = resolvedTypeName;
150
1258
  changedFields.push("type");
151
1259
  }
152
- if (options.tags !== undefined) {
153
- document.front_matter.tags = parseTags(options.tags);
1260
+ enforceUpdateOptionsByType(activeTypeName, options, typeRegistry);
1261
+ if (options.typeOption !== undefined || clearFrontMatterKeys.has("type_options")) {
1262
+ if (clearFrontMatterKeys.has("type_options")) {
1263
+ delete document.front_matter.type_options;
1264
+ }
1265
+ else {
1266
+ const parsedTypeOptions = parseTypeOptionEntries(options.typeOption);
1267
+ const validation = validateTypeOptions(activeTypeName, parsedTypeOptions, typeRegistry);
1268
+ if (validation.errors.length > 0) {
1269
+ throw new PmCliError(validation.errors.join("; "), EXIT_CODE.USAGE);
1270
+ }
1271
+ document.front_matter.type_options = validation.normalized;
1272
+ }
1273
+ changedFields.push("type_options");
1274
+ }
1275
+ else if (options.type !== undefined && document.front_matter.type_options !== undefined) {
1276
+ const validation = validateTypeOptions(activeTypeName, document.front_matter.type_options, typeRegistry);
1277
+ if (validation.errors.length > 0) {
1278
+ throw new PmCliError(`Current type options are incompatible with type "${activeTypeName}". ${validation.errors.join("; ")}. Use --clear-type-options to clear them.`, EXIT_CODE.USAGE);
1279
+ }
1280
+ document.front_matter.type_options = validation.normalized;
1281
+ }
1282
+ if (options.dep !== undefined || options.depRemove !== undefined || clearFrontMatterKeys.has("dependencies")) {
1283
+ let nextDependencies = clearFrontMatterKeys.has("dependencies") ? [] : [...(document.front_matter.dependencies ?? [])];
1284
+ if (dependencyUpdates.additions.length > 0) {
1285
+ const seen = new Set(nextDependencies.map((entry) => dependencyKey(entry)));
1286
+ for (const addition of dependencyUpdates.additions) {
1287
+ const key = dependencyKey(addition);
1288
+ if (seen.has(key)) {
1289
+ continue;
1290
+ }
1291
+ nextDependencies.push(addition);
1292
+ seen.add(key);
1293
+ }
1294
+ }
1295
+ if (dependencyRemovals.length > 0) {
1296
+ nextDependencies = nextDependencies.filter((entry) => !dependencyRemovals.some((selector) => matchesDependencySelector(entry, selector)));
1297
+ }
1298
+ if (nextDependencies.length === 0) {
1299
+ delete document.front_matter.dependencies;
1300
+ }
1301
+ else {
1302
+ document.front_matter.dependencies = nextDependencies;
1303
+ }
1304
+ changedFields.push("dependencies");
1305
+ }
1306
+ if (options.comment !== undefined || clearFrontMatterKeys.has("comments")) {
1307
+ if (clearFrontMatterKeys.has("comments") || !commentUpdates.values || commentUpdates.values.length === 0) {
1308
+ delete document.front_matter.comments;
1309
+ }
1310
+ else {
1311
+ document.front_matter.comments = [...(document.front_matter.comments ?? []), ...commentUpdates.values];
1312
+ }
1313
+ changedFields.push("comments");
1314
+ }
1315
+ if (options.note !== undefined || clearFrontMatterKeys.has("notes")) {
1316
+ if (clearFrontMatterKeys.has("notes") || !noteUpdates.values || noteUpdates.values.length === 0) {
1317
+ delete document.front_matter.notes;
1318
+ }
1319
+ else {
1320
+ document.front_matter.notes = [...(document.front_matter.notes ?? []), ...noteUpdates.values];
1321
+ }
1322
+ changedFields.push("notes");
1323
+ }
1324
+ if (options.learning !== undefined || clearFrontMatterKeys.has("learnings")) {
1325
+ if (clearFrontMatterKeys.has("learnings") || !learningUpdates.values || learningUpdates.values.length === 0) {
1326
+ delete document.front_matter.learnings;
1327
+ }
1328
+ else {
1329
+ document.front_matter.learnings = [...(document.front_matter.learnings ?? []), ...learningUpdates.values];
1330
+ }
1331
+ changedFields.push("learnings");
1332
+ }
1333
+ if (options.file !== undefined || clearFrontMatterKeys.has("files")) {
1334
+ if (clearFrontMatterKeys.has("files") || !fileUpdates.values || fileUpdates.values.length === 0) {
1335
+ delete document.front_matter.files;
1336
+ }
1337
+ else {
1338
+ const nextFiles = [...(document.front_matter.files ?? [])];
1339
+ const seen = new Set(nextFiles.map((entry) => fileKey(entry)));
1340
+ for (const entry of fileUpdates.values) {
1341
+ const key = fileKey(entry);
1342
+ if (seen.has(key)) {
1343
+ continue;
1344
+ }
1345
+ nextFiles.push(entry);
1346
+ seen.add(key);
1347
+ }
1348
+ document.front_matter.files = nextFiles;
1349
+ }
1350
+ changedFields.push("files");
1351
+ }
1352
+ if (options.test !== undefined || clearFrontMatterKeys.has("tests")) {
1353
+ if (clearFrontMatterKeys.has("tests") && options.replaceTests === true) {
1354
+ if (!testUpdates.values || testUpdates.values.length === 0) {
1355
+ delete document.front_matter.tests;
1356
+ }
1357
+ else {
1358
+ const replacementTests = [];
1359
+ const seen = new Set();
1360
+ for (const entry of testUpdates.values) {
1361
+ const key = testKey(entry);
1362
+ if (seen.has(key)) {
1363
+ continue;
1364
+ }
1365
+ replacementTests.push(entry);
1366
+ seen.add(key);
1367
+ }
1368
+ document.front_matter.tests = replacementTests;
1369
+ }
1370
+ }
1371
+ else if (clearFrontMatterKeys.has("tests") || !testUpdates.values || testUpdates.values.length === 0) {
1372
+ delete document.front_matter.tests;
1373
+ }
1374
+ else {
1375
+ const nextTests = [...(document.front_matter.tests ?? [])];
1376
+ const seen = new Set(nextTests.map((entry) => testKey(entry)));
1377
+ for (const entry of testUpdates.values) {
1378
+ const key = testKey(entry);
1379
+ if (seen.has(key)) {
1380
+ continue;
1381
+ }
1382
+ nextTests.push(entry);
1383
+ seen.add(key);
1384
+ }
1385
+ document.front_matter.tests = nextTests;
1386
+ }
1387
+ changedFields.push("tests");
1388
+ }
1389
+ if (options.doc !== undefined || clearFrontMatterKeys.has("docs")) {
1390
+ if (clearFrontMatterKeys.has("docs") || !docUpdates.values || docUpdates.values.length === 0) {
1391
+ delete document.front_matter.docs;
1392
+ }
1393
+ else {
1394
+ const nextDocs = [...(document.front_matter.docs ?? [])];
1395
+ const seen = new Set(nextDocs.map((entry) => docKey(entry)));
1396
+ for (const entry of docUpdates.values) {
1397
+ const key = docKey(entry);
1398
+ if (seen.has(key)) {
1399
+ continue;
1400
+ }
1401
+ nextDocs.push(entry);
1402
+ seen.add(key);
1403
+ }
1404
+ document.front_matter.docs = nextDocs;
1405
+ }
1406
+ changedFields.push("docs");
1407
+ }
1408
+ if (options.tags !== undefined || clearFrontMatterKeys.has("tags")) {
1409
+ document.front_matter.tags = clearFrontMatterKeys.has("tags") ? [] : parseTags(options.tags);
154
1410
  changedFields.push("tags");
155
1411
  }
156
- if (options.deadline !== undefined) {
157
- if (isNoneToken(options.deadline)) {
1412
+ if (options.deadline !== undefined || clearFrontMatterKeys.has("deadline")) {
1413
+ if (clearFrontMatterKeys.has("deadline")) {
158
1414
  delete document.front_matter.deadline;
159
1415
  }
160
1416
  else {
161
- document.front_matter.deadline = resolveIsoOrRelative(options.deadline);
1417
+ document.front_matter.deadline = resolveIsoOrRelative(options.deadline, new Date(), "deadline");
162
1418
  }
163
1419
  changedFields.push("deadline");
164
1420
  }
165
- if (options.estimatedMinutes !== undefined) {
166
- if (isNoneToken(options.estimatedMinutes)) {
1421
+ if (options.estimatedMinutes !== undefined || clearFrontMatterKeys.has("estimated_minutes")) {
1422
+ if (clearFrontMatterKeys.has("estimated_minutes")) {
167
1423
  delete document.front_matter.estimated_minutes;
168
1424
  }
169
1425
  else {
@@ -171,8 +1427,8 @@ export async function runUpdate(id, options, global) {
171
1427
  }
172
1428
  changedFields.push("estimated_minutes");
173
1429
  }
174
- if (options.acceptanceCriteria !== undefined) {
175
- if (isNoneToken(options.acceptanceCriteria)) {
1430
+ if (options.acceptanceCriteria !== undefined || clearFrontMatterKeys.has("acceptance_criteria")) {
1431
+ if (clearFrontMatterKeys.has("acceptance_criteria")) {
176
1432
  delete document.front_matter.acceptance_criteria;
177
1433
  }
178
1434
  else {
@@ -180,8 +1436,8 @@ export async function runUpdate(id, options, global) {
180
1436
  }
181
1437
  changedFields.push("acceptance_criteria");
182
1438
  }
183
- if (options.definitionOfReady !== undefined) {
184
- if (isNoneToken(options.definitionOfReady)) {
1439
+ if (options.definitionOfReady !== undefined || clearFrontMatterKeys.has("definition_of_ready")) {
1440
+ if (clearFrontMatterKeys.has("definition_of_ready")) {
185
1441
  delete document.front_matter.definition_of_ready;
186
1442
  }
187
1443
  else {
@@ -190,8 +1446,8 @@ export async function runUpdate(id, options, global) {
190
1446
  changedFields.push("definition_of_ready");
191
1447
  }
192
1448
  const orderRaw = options.order ?? options.rank;
193
- if (orderRaw !== undefined) {
194
- if (isNoneToken(orderRaw)) {
1449
+ if (orderRaw !== undefined || clearFrontMatterKeys.has("order")) {
1450
+ if (clearFrontMatterKeys.has("order")) {
195
1451
  delete document.front_matter.order;
196
1452
  }
197
1453
  else {
@@ -203,8 +1459,8 @@ export async function runUpdate(id, options, global) {
203
1459
  }
204
1460
  changedFields.push("order");
205
1461
  }
206
- if (options.goal !== undefined) {
207
- if (isNoneToken(options.goal)) {
1462
+ if (options.goal !== undefined || clearFrontMatterKeys.has("goal")) {
1463
+ if (clearFrontMatterKeys.has("goal")) {
208
1464
  delete document.front_matter.goal;
209
1465
  }
210
1466
  else {
@@ -212,8 +1468,8 @@ export async function runUpdate(id, options, global) {
212
1468
  }
213
1469
  changedFields.push("goal");
214
1470
  }
215
- if (options.objective !== undefined) {
216
- if (isNoneToken(options.objective)) {
1471
+ if (options.objective !== undefined || clearFrontMatterKeys.has("objective")) {
1472
+ if (clearFrontMatterKeys.has("objective")) {
217
1473
  delete document.front_matter.objective;
218
1474
  }
219
1475
  else {
@@ -221,8 +1477,8 @@ export async function runUpdate(id, options, global) {
221
1477
  }
222
1478
  changedFields.push("objective");
223
1479
  }
224
- if (options.value !== undefined) {
225
- if (isNoneToken(options.value)) {
1480
+ if (options.value !== undefined || clearFrontMatterKeys.has("value")) {
1481
+ if (clearFrontMatterKeys.has("value")) {
226
1482
  delete document.front_matter.value;
227
1483
  }
228
1484
  else {
@@ -230,8 +1486,8 @@ export async function runUpdate(id, options, global) {
230
1486
  }
231
1487
  changedFields.push("value");
232
1488
  }
233
- if (options.impact !== undefined) {
234
- if (isNoneToken(options.impact)) {
1489
+ if (options.impact !== undefined || clearFrontMatterKeys.has("impact")) {
1490
+ if (clearFrontMatterKeys.has("impact")) {
235
1491
  delete document.front_matter.impact;
236
1492
  }
237
1493
  else {
@@ -239,8 +1495,8 @@ export async function runUpdate(id, options, global) {
239
1495
  }
240
1496
  changedFields.push("impact");
241
1497
  }
242
- if (options.outcome !== undefined) {
243
- if (isNoneToken(options.outcome)) {
1498
+ if (options.outcome !== undefined || clearFrontMatterKeys.has("outcome")) {
1499
+ if (clearFrontMatterKeys.has("outcome")) {
244
1500
  delete document.front_matter.outcome;
245
1501
  }
246
1502
  else {
@@ -248,8 +1504,8 @@ export async function runUpdate(id, options, global) {
248
1504
  }
249
1505
  changedFields.push("outcome");
250
1506
  }
251
- if (options.whyNow !== undefined) {
252
- if (isNoneToken(options.whyNow)) {
1507
+ if (options.whyNow !== undefined || clearFrontMatterKeys.has("why_now")) {
1508
+ if (clearFrontMatterKeys.has("why_now")) {
253
1509
  delete document.front_matter.why_now;
254
1510
  }
255
1511
  else {
@@ -257,26 +1513,29 @@ export async function runUpdate(id, options, global) {
257
1513
  }
258
1514
  changedFields.push("why_now");
259
1515
  }
260
- if (options.assignee !== undefined) {
261
- if (isNoneToken(options.assignee) || options.assignee.trim() === "") {
1516
+ if (options.assignee !== undefined || clearFrontMatterKeys.has("assignee")) {
1517
+ if (clearFrontMatterKeys.has("assignee")) {
262
1518
  delete document.front_matter.assignee;
263
1519
  }
264
1520
  else {
1521
+ if (options.assignee.trim() === "") {
1522
+ throw new PmCliError("--assignee must not be empty. Use --unset assignee to clear it.", EXIT_CODE.USAGE);
1523
+ }
265
1524
  document.front_matter.assignee = options.assignee.trim();
266
1525
  }
267
1526
  changedFields.push("assignee");
268
1527
  }
269
- if (options.parent !== undefined) {
270
- if (isNoneToken(options.parent)) {
1528
+ if (options.parent !== undefined || clearFrontMatterKeys.has("parent")) {
1529
+ if (clearFrontMatterKeys.has("parent")) {
271
1530
  delete document.front_matter.parent;
272
1531
  }
273
1532
  else {
274
- document.front_matter.parent = options.parent.trim();
1533
+ document.front_matter.parent = resolvedParentValue;
275
1534
  }
276
1535
  changedFields.push("parent");
277
1536
  }
278
- if (options.reviewer !== undefined) {
279
- if (isNoneToken(options.reviewer)) {
1537
+ if (options.reviewer !== undefined || clearFrontMatterKeys.has("reviewer")) {
1538
+ if (clearFrontMatterKeys.has("reviewer")) {
280
1539
  delete document.front_matter.reviewer;
281
1540
  }
282
1541
  else {
@@ -284,8 +1543,8 @@ export async function runUpdate(id, options, global) {
284
1543
  }
285
1544
  changedFields.push("reviewer");
286
1545
  }
287
- if (options.risk !== undefined) {
288
- if (isNoneToken(options.risk)) {
1546
+ if (options.risk !== undefined || clearFrontMatterKeys.has("risk")) {
1547
+ if (clearFrontMatterKeys.has("risk")) {
289
1548
  delete document.front_matter.risk;
290
1549
  }
291
1550
  else {
@@ -293,8 +1552,8 @@ export async function runUpdate(id, options, global) {
293
1552
  }
294
1553
  changedFields.push("risk");
295
1554
  }
296
- if (options.confidence !== undefined) {
297
- if (isNoneToken(options.confidence)) {
1555
+ if (options.confidence !== undefined || clearFrontMatterKeys.has("confidence")) {
1556
+ if (clearFrontMatterKeys.has("confidence")) {
298
1557
  delete document.front_matter.confidence;
299
1558
  }
300
1559
  else {
@@ -302,26 +1561,30 @@ export async function runUpdate(id, options, global) {
302
1561
  }
303
1562
  changedFields.push("confidence");
304
1563
  }
305
- if (options.sprint !== undefined) {
306
- if (isNoneToken(options.sprint)) {
1564
+ if (options.sprint !== undefined || clearFrontMatterKeys.has("sprint")) {
1565
+ if (clearFrontMatterKeys.has("sprint")) {
307
1566
  delete document.front_matter.sprint;
308
1567
  }
309
1568
  else {
310
- document.front_matter.sprint = options.sprint.trim();
1569
+ const sprintValidation = validateSprintOrReleaseValue("sprint", options.sprint, sprintReleasePolicy);
1570
+ document.front_matter.sprint = sprintValidation.value;
1571
+ warnings.push(...sprintValidation.warnings);
311
1572
  }
312
1573
  changedFields.push("sprint");
313
1574
  }
314
- if (options.release !== undefined) {
315
- if (isNoneToken(options.release)) {
1575
+ if (options.release !== undefined || clearFrontMatterKeys.has("release")) {
1576
+ if (clearFrontMatterKeys.has("release")) {
316
1577
  delete document.front_matter.release;
317
1578
  }
318
1579
  else {
319
- document.front_matter.release = options.release.trim();
1580
+ const releaseValidation = validateSprintOrReleaseValue("release", options.release, sprintReleasePolicy);
1581
+ document.front_matter.release = releaseValidation.value;
1582
+ warnings.push(...releaseValidation.warnings);
320
1583
  }
321
1584
  changedFields.push("release");
322
1585
  }
323
- if (options.blockedBy !== undefined) {
324
- if (isNoneToken(options.blockedBy)) {
1586
+ if (options.blockedBy !== undefined || clearFrontMatterKeys.has("blocked_by")) {
1587
+ if (clearFrontMatterKeys.has("blocked_by")) {
325
1588
  delete document.front_matter.blocked_by;
326
1589
  }
327
1590
  else {
@@ -329,8 +1592,8 @@ export async function runUpdate(id, options, global) {
329
1592
  }
330
1593
  changedFields.push("blocked_by");
331
1594
  }
332
- if (options.blockedReason !== undefined) {
333
- if (isNoneToken(options.blockedReason)) {
1595
+ if (options.blockedReason !== undefined || clearFrontMatterKeys.has("blocked_reason")) {
1596
+ if (clearFrontMatterKeys.has("blocked_reason")) {
334
1597
  delete document.front_matter.blocked_reason;
335
1598
  }
336
1599
  else {
@@ -338,8 +1601,8 @@ export async function runUpdate(id, options, global) {
338
1601
  }
339
1602
  changedFields.push("blocked_reason");
340
1603
  }
341
- if (options.unblockNote !== undefined) {
342
- if (isNoneToken(options.unblockNote)) {
1604
+ if (options.unblockNote !== undefined || clearFrontMatterKeys.has("unblock_note")) {
1605
+ if (clearFrontMatterKeys.has("unblock_note")) {
343
1606
  delete document.front_matter.unblock_note;
344
1607
  }
345
1608
  else {
@@ -347,8 +1610,8 @@ export async function runUpdate(id, options, global) {
347
1610
  }
348
1611
  changedFields.push("unblock_note");
349
1612
  }
350
- if (options.reporter !== undefined) {
351
- if (isNoneToken(options.reporter)) {
1613
+ if (options.reporter !== undefined || clearFrontMatterKeys.has("reporter")) {
1614
+ if (clearFrontMatterKeys.has("reporter")) {
352
1615
  delete document.front_matter.reporter;
353
1616
  }
354
1617
  else {
@@ -356,8 +1619,8 @@ export async function runUpdate(id, options, global) {
356
1619
  }
357
1620
  changedFields.push("reporter");
358
1621
  }
359
- if (options.severity !== undefined) {
360
- if (isNoneToken(options.severity)) {
1622
+ if (options.severity !== undefined || clearFrontMatterKeys.has("severity")) {
1623
+ if (clearFrontMatterKeys.has("severity")) {
361
1624
  delete document.front_matter.severity;
362
1625
  }
363
1626
  else {
@@ -365,8 +1628,8 @@ export async function runUpdate(id, options, global) {
365
1628
  }
366
1629
  changedFields.push("severity");
367
1630
  }
368
- if (options.environment !== undefined) {
369
- if (isNoneToken(options.environment)) {
1631
+ if (options.environment !== undefined || clearFrontMatterKeys.has("environment")) {
1632
+ if (clearFrontMatterKeys.has("environment")) {
370
1633
  delete document.front_matter.environment;
371
1634
  }
372
1635
  else {
@@ -374,8 +1637,8 @@ export async function runUpdate(id, options, global) {
374
1637
  }
375
1638
  changedFields.push("environment");
376
1639
  }
377
- if (options.reproSteps !== undefined) {
378
- if (isNoneToken(options.reproSteps)) {
1640
+ if (options.reproSteps !== undefined || clearFrontMatterKeys.has("repro_steps")) {
1641
+ if (clearFrontMatterKeys.has("repro_steps")) {
379
1642
  delete document.front_matter.repro_steps;
380
1643
  }
381
1644
  else {
@@ -383,8 +1646,8 @@ export async function runUpdate(id, options, global) {
383
1646
  }
384
1647
  changedFields.push("repro_steps");
385
1648
  }
386
- if (options.resolution !== undefined) {
387
- if (isNoneToken(options.resolution)) {
1649
+ if (options.resolution !== undefined || clearFrontMatterKeys.has("resolution")) {
1650
+ if (clearFrontMatterKeys.has("resolution")) {
388
1651
  delete document.front_matter.resolution;
389
1652
  }
390
1653
  else {
@@ -392,8 +1655,8 @@ export async function runUpdate(id, options, global) {
392
1655
  }
393
1656
  changedFields.push("resolution");
394
1657
  }
395
- if (options.expectedResult !== undefined) {
396
- if (isNoneToken(options.expectedResult)) {
1658
+ if (options.expectedResult !== undefined || clearFrontMatterKeys.has("expected_result")) {
1659
+ if (clearFrontMatterKeys.has("expected_result")) {
397
1660
  delete document.front_matter.expected_result;
398
1661
  }
399
1662
  else {
@@ -401,8 +1664,8 @@ export async function runUpdate(id, options, global) {
401
1664
  }
402
1665
  changedFields.push("expected_result");
403
1666
  }
404
- if (options.actualResult !== undefined) {
405
- if (isNoneToken(options.actualResult)) {
1667
+ if (options.actualResult !== undefined || clearFrontMatterKeys.has("actual_result")) {
1668
+ if (clearFrontMatterKeys.has("actual_result")) {
406
1669
  delete document.front_matter.actual_result;
407
1670
  }
408
1671
  else {
@@ -410,8 +1673,8 @@ export async function runUpdate(id, options, global) {
410
1673
  }
411
1674
  changedFields.push("actual_result");
412
1675
  }
413
- if (options.affectedVersion !== undefined) {
414
- if (isNoneToken(options.affectedVersion)) {
1676
+ if (options.affectedVersion !== undefined || clearFrontMatterKeys.has("affected_version")) {
1677
+ if (clearFrontMatterKeys.has("affected_version")) {
415
1678
  delete document.front_matter.affected_version;
416
1679
  }
417
1680
  else {
@@ -419,8 +1682,8 @@ export async function runUpdate(id, options, global) {
419
1682
  }
420
1683
  changedFields.push("affected_version");
421
1684
  }
422
- if (options.fixedVersion !== undefined) {
423
- if (isNoneToken(options.fixedVersion)) {
1685
+ if (options.fixedVersion !== undefined || clearFrontMatterKeys.has("fixed_version")) {
1686
+ if (clearFrontMatterKeys.has("fixed_version")) {
424
1687
  delete document.front_matter.fixed_version;
425
1688
  }
426
1689
  else {
@@ -428,8 +1691,8 @@ export async function runUpdate(id, options, global) {
428
1691
  }
429
1692
  changedFields.push("fixed_version");
430
1693
  }
431
- if (options.component !== undefined) {
432
- if (isNoneToken(options.component)) {
1694
+ if (options.component !== undefined || clearFrontMatterKeys.has("component")) {
1695
+ if (clearFrontMatterKeys.has("component")) {
433
1696
  delete document.front_matter.component;
434
1697
  }
435
1698
  else {
@@ -437,8 +1700,8 @@ export async function runUpdate(id, options, global) {
437
1700
  }
438
1701
  changedFields.push("component");
439
1702
  }
440
- if (options.regression !== undefined) {
441
- if (isNoneToken(options.regression)) {
1703
+ if (options.regression !== undefined || clearFrontMatterKeys.has("regression")) {
1704
+ if (clearFrontMatterKeys.has("regression")) {
442
1705
  delete document.front_matter.regression;
443
1706
  }
444
1707
  else {
@@ -446,8 +1709,8 @@ export async function runUpdate(id, options, global) {
446
1709
  }
447
1710
  changedFields.push("regression");
448
1711
  }
449
- if (options.customerImpact !== undefined) {
450
- if (isNoneToken(options.customerImpact)) {
1712
+ if (options.customerImpact !== undefined || clearFrontMatterKeys.has("customer_impact")) {
1713
+ if (clearFrontMatterKeys.has("customer_impact")) {
451
1714
  delete document.front_matter.customer_impact;
452
1715
  }
453
1716
  else {
@@ -455,13 +1718,59 @@ export async function runUpdate(id, options, global) {
455
1718
  }
456
1719
  changedFields.push("customer_impact");
457
1720
  }
458
- return { changedFields };
1721
+ if (options.reminder !== undefined || clearFrontMatterKeys.has("reminders")) {
1722
+ if (clearFrontMatterKeys.has("reminders")) {
1723
+ delete document.front_matter.reminders;
1724
+ }
1725
+ else {
1726
+ document.front_matter.reminders = parseReminderEntries(options.reminder, nowValue);
1727
+ }
1728
+ changedFields.push("reminders");
1729
+ }
1730
+ if (options.event !== undefined || clearFrontMatterKeys.has("events")) {
1731
+ if (clearFrontMatterKeys.has("events")) {
1732
+ delete document.front_matter.events;
1733
+ }
1734
+ else {
1735
+ document.front_matter.events = parseEventEntries(options.event, nowValue);
1736
+ }
1737
+ changedFields.push("events");
1738
+ }
1739
+ for (const definition of runtimeFieldRegistry.definitions) {
1740
+ if (!clearFrontMatterKeys.has(definition.front_matter_key)) {
1741
+ continue;
1742
+ }
1743
+ if (document.front_matter[definition.front_matter_key] === undefined) {
1744
+ continue;
1745
+ }
1746
+ delete document.front_matter[definition.front_matter_key];
1747
+ changedFields.push(definition.front_matter_key);
1748
+ }
1749
+ const runtimeFieldUpdates = collectRuntimeUpdateFieldValues(options, runtimeFieldRegistry);
1750
+ for (const [fieldKey, fieldValue] of Object.entries(runtimeFieldUpdates)) {
1751
+ if (clearFrontMatterKeys.has(fieldKey)) {
1752
+ continue;
1753
+ }
1754
+ if (JSON.stringify(document.front_matter[fieldKey]) === JSON.stringify(fieldValue)) {
1755
+ continue;
1756
+ }
1757
+ document.front_matter[fieldKey] = fieldValue;
1758
+ changedFields.push(fieldKey);
1759
+ }
1760
+ try {
1761
+ applyRegisteredItemFieldDefaultsAndValidation(document.front_matter, getActiveExtensionRegistrations());
1762
+ }
1763
+ catch (error) {
1764
+ throw new PmCliError(error instanceof Error ? error.message : "Invalid extension item field values", EXIT_CODE.USAGE);
1765
+ }
1766
+ return { changedFields, warnings };
459
1767
  },
460
1768
  });
461
1769
  return {
462
1770
  item: result.item,
463
1771
  changed_fields: result.changedFields,
464
- warnings: result.warnings,
1772
+ warnings: [...parentReferenceWarnings, ...result.warnings],
1773
+ ...(options.allowAuditUpdate === true || options.allowAuditDepUpdate === true ? { audit_update: true } : {}),
465
1774
  };
466
1775
  }
467
1776
  //# sourceMappingURL=update.js.map